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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Tönne <lukas.toenne@gmail.com>2016-10-31 15:38:28 +0300
committerLukas Tönne <lukas.toenne@gmail.com>2016-10-31 15:38:28 +0300
commitd6ecf8efcd2453b55a1961713c67f10565d56ad5 (patch)
treea4fc7b4069eb25968af2e1e3e8d5e524aa315993
parent75976a24d7dd7e8463d477de6dd30b9a1a0edb87 (diff)
parentce785868a56a1446750f5af1779f7623ca462ec2 (diff)
Merge branch 'master' into openvdb
-rw-r--r--.gitignore6
-rw-r--r--.gitmodules4
-rw-r--r--CMakeLists.txt1721
-rw-r--r--GNUmakefile98
-rwxr-xr-xbuild_files/build_environment/install_deps.sh334
-rw-r--r--build_files/buildbot/master.cfg2
-rw-r--r--build_files/buildbot/slave_compile.py29
-rw-r--r--build_files/buildbot/slave_pack.py2
-rw-r--r--build_files/cmake/Modules/FindAlembic.cmake70
-rw-r--r--build_files/cmake/Modules/FindHDF5.cmake69
-rw-r--r--build_files/cmake/Modules/FindJack.cmake12
-rw-r--r--build_files/cmake/Modules/GTestTesting.cmake2
-rw-r--r--build_files/cmake/buildinfo.cmake21
-rw-r--r--build_files/cmake/clang_array_check.py4
-rwxr-xr-xbuild_files/cmake/cmake_consistency_check.py10
-rw-r--r--build_files/cmake/cmake_consistency_check_config.py2
-rwxr-xr-xbuild_files/cmake/cmake_netbeans_project.py26
-rwxr-xr-xbuild_files/cmake/cmake_qtcreator_project.py68
-rw-r--r--build_files/cmake/cmake_static_check_clang_array.py4
-rw-r--r--build_files/cmake/cmake_static_check_cppcheck.py4
-rw-r--r--build_files/cmake/cmake_static_check_smatch.py4
-rw-r--r--build_files/cmake/cmake_static_check_sparse.py4
-rw-r--r--build_files/cmake/cmake_static_check_splint.py4
-rw-r--r--build_files/cmake/config/blender_full.cmake2
-rw-r--r--build_files/cmake/config/blender_lite.cmake3
-rw-r--r--build_files/cmake/config/blender_release.cmake79
-rw-r--r--build_files/cmake/config/bpy_module.cmake1
-rwxr-xr-xbuild_files/cmake/example_scripts/make_quicky.py2
-rw-r--r--build_files/cmake/macros.cmake162
-rw-r--r--build_files/cmake/packaging.cmake18
-rw-r--r--build_files/cmake/platform/platform_apple.cmake465
-rw-r--r--build_files/cmake/platform/platform_unix.cmake427
-rw-r--r--build_files/cmake/platform/platform_win32.cmake87
-rw-r--r--build_files/cmake/platform/platform_win32_mingw.cmake302
-rw-r--r--build_files/cmake/platform/platform_win32_msvc.cmake487
-rwxr-xr-xbuild_files/cmake/project_info.py9
-rw-r--r--build_files/cmake/project_source_info.py2
-rwxr-xr-xbuild_files/package_spec/build_archive.py2
-rw-r--r--build_files/package_spec/pacman/PKGBUILD10
-rwxr-xr-xbuild_files/utils/build_tgz.sh8
-rw-r--r--doc/blender_file_format/mystery_of_the_blend.html2
-rw-r--r--doc/doxygen/Doxyfile8
-rwxr-xr-xdoc/manpage/blender.1.py2
-rw-r--r--doc/python_api/epy/IDProp.py132
-rw-r--r--doc/python_api/examples/bge.texture.2.py237
-rw-r--r--doc/python_api/examples/bpy.app.handlers.1.py2
-rw-r--r--doc/python_api/examples/bpy.app.translations.py8
-rw-r--r--doc/python_api/examples/bpy.types.AddonPreferences.1.py12
-rw-r--r--doc/python_api/examples/bpy.types.Menu.2.py6
-rw-r--r--doc/python_api/examples/bpy.types.PropertyGroup.py2
-rw-r--r--doc/python_api/examples/mathutils.Vector.py2
-rw-r--r--doc/python_api/rst/bge.constraints.rst4
-rw-r--r--doc/python_api/rst/bge.events.rst94
-rw-r--r--doc/python_api/rst/bge.logic.rst22
-rw-r--r--doc/python_api/rst/bge.render.rst61
-rw-r--r--doc/python_api/rst/bge.texture.rst748
-rw-r--r--doc/python_api/rst/bge_types/bge.types.BL_Shader.rst10
-rw-r--r--doc/python_api/rst/bge_types/bge.types.KX_LightObject.rst12
-rw-r--r--doc/python_api/rst/bge_types/bge.types.SCA_PythonJoystick.rst10
-rw-r--r--doc/python_api/rst/bgl.rst304
-rw-r--r--doc/python_api/rst/include__bmesh.rst18
-rw-r--r--doc/python_api/rst/info_best_practice.rst4
-rw-r--r--doc/python_api/rst/info_gotcha.rst11
-rw-r--r--doc/python_api/rst/info_overview.rst17
-rw-r--r--doc/python_api/rst/info_quickstart.rst13
-rw-r--r--doc/python_api/rst/info_tips_and_tricks.rst4
-rw-r--r--doc/python_api/rst/info_tutorial_addon.rst138
-rw-r--r--doc/python_api/rst_from_bmesh_opdefines.py2
-rw-r--r--doc/python_api/sphinx_changelog_gen.py117
-rw-r--r--doc/python_api/sphinx_doc_gen.py423
-rwxr-xr-xdoc/python_api/sphinx_doc_gen.sh66
-rwxr-xr-xdoc/python_api/sphinx_doc_update.py183
-rw-r--r--extern/CMakeLists.txt9
-rw-r--r--extern/Eigen3/README.blender6
-rw-r--r--extern/binreloc/README.blender6
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp10
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp4
-rw-r--r--extern/carve/README.blender4
-rw-r--r--extern/ceres/README.blender4
-rw-r--r--extern/clew/README.blender5
-rw-r--r--extern/clew/src/clew.c23
-rw-r--r--extern/cuew/README2
-rw-r--r--extern/cuew/README.blender5
-rw-r--r--extern/cuew/include/cuew.h164
-rw-r--r--extern/curve_fit_nd/CMakeLists.txt6
-rw-r--r--extern/curve_fit_nd/README.blender5
-rw-r--r--extern/curve_fit_nd/curve_fit_nd.h41
-rw-r--r--extern/curve_fit_nd/intern/curve_fit_cubic.c339
-rw-r--r--extern/curve_fit_nd/intern/curve_fit_cubic_refit.c1443
-rw-r--r--extern/curve_fit_nd/intern/curve_fit_inline.h22
-rw-r--r--extern/curve_fit_nd/intern/generic_alloc_impl.h220
-rw-r--r--extern/curve_fit_nd/intern/generic_heap.c278
-rw-r--r--extern/curve_fit_nd/intern/generic_heap.h54
-rw-r--r--extern/gflags/README.blender (renamed from extern/gflags/README.libmv)6
-rw-r--r--extern/glog/README.blender (renamed from extern/glog/README.libmv)2
-rw-r--r--extern/gmock/CMakeLists.txt66
-rw-r--r--extern/gmock/LICENSE28
-rw-r--r--extern/gmock/README.blender (renamed from extern/gtest/README)4
-rw-r--r--extern/gmock/README.md333
-rw-r--r--extern/gmock/include/gmock/gmock-actions.h1205
-rw-r--r--extern/gmock/include/gmock/gmock-cardinalities.h147
-rw-r--r--extern/gmock/include/gmock/gmock-generated-actions.h2377
-rw-r--r--extern/gmock/include/gmock/gmock-generated-function-mockers.h1095
-rw-r--r--extern/gmock/include/gmock/gmock-generated-matchers.h2179
-rw-r--r--extern/gmock/include/gmock/gmock-generated-nice-strict.h397
-rw-r--r--extern/gmock/include/gmock/gmock-matchers.h4399
-rw-r--r--extern/gmock/include/gmock/gmock-more-actions.h246
-rw-r--r--extern/gmock/include/gmock/gmock-more-matchers.h58
-rw-r--r--extern/gmock/include/gmock/gmock-spec-builders.h1847
-rw-r--r--extern/gmock/include/gmock/gmock.h94
-rw-r--r--extern/gmock/include/gmock/internal/custom/gmock-generated-actions.h8
-rw-r--r--extern/gmock/include/gmock/internal/custom/gmock-matchers.h39
-rw-r--r--extern/gmock/include/gmock/internal/custom/gmock-port.h46
-rw-r--r--extern/gmock/include/gmock/internal/gmock-generated-internal-utils.h279
-rw-r--r--extern/gmock/include/gmock/internal/gmock-internal-utils.h511
-rw-r--r--extern/gmock/include/gmock/internal/gmock-port.h91
-rw-r--r--extern/gmock/src/gmock-all.cc47
-rw-r--r--extern/gmock/src/gmock-cardinalities.cc156
-rw-r--r--extern/gmock/src/gmock-internal-utils.cc174
-rw-r--r--extern/gmock/src/gmock-matchers.cc498
-rw-r--r--extern/gmock/src/gmock-spec-builders.cc823
-rw-r--r--extern/gmock/src/gmock.cc183
-rw-r--r--extern/gmock/src/gmock_main.cc54
-rw-r--r--extern/gtest/README.blender7
-rw-r--r--extern/gtest/include/gtest/gtest-param-test.h47
-rw-r--r--extern/gtest/include/gtest/gtest-printers.h244
-rw-r--r--extern/gtest/include/gtest/gtest-typed-test.h8
-rw-r--r--extern/gtest/include/gtest/gtest.h401
-rw-r--r--extern/gtest/include/gtest/internal/custom/gtest-port.h69
-rw-r--r--extern/gtest/include/gtest/internal/custom/gtest-printers.h42
-rw-r--r--extern/gtest/include/gtest/internal/custom/gtest.h41
-rw-r--r--extern/gtest/include/gtest/internal/gtest-internal.h192
-rw-r--r--extern/gtest/include/gtest/internal/gtest-linked_ptr.h14
-rw-r--r--extern/gtest/include/gtest/internal/gtest-param-util-generated.h83
-rw-r--r--extern/gtest/include/gtest/internal/gtest-param-util.h152
-rw-r--r--extern/gtest/include/gtest/internal/gtest-port-arch.h93
-rw-r--r--extern/gtest/include/gtest/internal/gtest-port.h986
-rw-r--r--extern/gtest/include/gtest/internal/gtest-tuple.h8
-rw-r--r--extern/gtest/src/gtest-death-test.cc44
-rw-r--r--extern/gtest/src/gtest-filepath.cc13
-rw-r--r--extern/gtest/src/gtest-internal-inl.h55
-rw-r--r--extern/gtest/src/gtest-port.cc576
-rw-r--r--extern/gtest/src/gtest-printers.cc12
-rw-r--r--extern/gtest/src/gtest-test-part.cc6
-rw-r--r--extern/gtest/src/gtest-typed-test.cc40
-rw-r--r--extern/gtest/src/gtest.cc739
-rw-r--r--extern/libopenjpeg/README.blender5
-rw-r--r--extern/rangetree/CMakeLists.txt6
-rw-r--r--extern/rangetree/README.blender5
-rw-r--r--extern/rangetree/README.org13
-rw-r--r--extern/rangetree/intern/generic_alloc_impl.h215
-rw-r--r--extern/rangetree/intern/range_tree.c873
-rw-r--r--extern/rangetree/range_tree.h48
-rw-r--r--extern/rangetree/range_tree.hh251
-rw-r--r--extern/rangetree/range_tree_c_api.cc92
-rw-r--r--extern/rangetree/range_tree_c_api.h62
-rw-r--r--extern/recastnavigation/CMakeLists.txt60
-rw-r--r--extern/sdlew/README.blender5
-rw-r--r--extern/wcwidth/README.blender5
-rw-r--r--extern/xdnd/README.blender8
-rw-r--r--intern/CMakeLists.txt6
-rw-r--r--intern/atomic/atomic_ops.h2
-rw-r--r--intern/atomic/intern/atomic_ops_msvc.h5
-rw-r--r--intern/atomic/intern/atomic_ops_unix.h21
-rw-r--r--intern/atomic/intern/atomic_ops_utils.h4
-rw-r--r--intern/audaspace/Python/AUD_PyAPI.cpp4
-rw-r--r--intern/audaspace/intern/AUD_C-API.cpp6
-rw-r--r--intern/audaspace/intern/AUD_C-API.h2
-rw-r--r--intern/audaspace/intern/AUD_Mixer.cpp15
-rw-r--r--intern/audaspace/intern/AUD_Mixer.h2
-rw-r--r--intern/audaspace/intern/AUD_SoftwareDevice.cpp10
-rw-r--r--intern/audaspace/intern/AUD_SoftwareDevice.h1
-rw-r--r--intern/audaspace/jack/AUD_JackDevice.h8
-rw-r--r--intern/audaspace/jack/AUD_JackLibrary.cpp15
-rw-r--r--intern/audaspace/jack/AUD_JackLibrary.h2
-rw-r--r--intern/cycles/CMakeLists.txt13
-rw-r--r--intern/cycles/app/CMakeLists.txt9
-rw-r--r--intern/cycles/app/cycles_standalone.cpp2
-rw-r--r--intern/cycles/app/cycles_xml.cpp932
-rw-r--r--intern/cycles/blender/CMakeLists.txt1
-rw-r--r--intern/cycles/blender/addon/engine.py3
-rw-r--r--intern/cycles/blender/addon/osl.py6
-rw-r--r--intern/cycles/blender/addon/properties.py64
-rw-r--r--intern/cycles/blender/addon/ui.py218
-rw-r--r--intern/cycles/blender/addon/version_update.py1
-rw-r--r--intern/cycles/blender/blender_camera.cpp23
-rw-r--r--intern/cycles/blender/blender_curves.cpp90
-rw-r--r--intern/cycles/blender/blender_mesh.cpp450
-rw-r--r--intern/cycles/blender/blender_object.cpp65
-rw-r--r--intern/cycles/blender/blender_particles.cpp4
-rw-r--r--intern/cycles/blender/blender_python.cpp7
-rw-r--r--intern/cycles/blender/blender_session.cpp5
-rw-r--r--intern/cycles/blender/blender_shader.cpp317
-rw-r--r--intern/cycles/blender/blender_sync.cpp70
-rw-r--r--intern/cycles/blender/blender_sync.h10
-rw-r--r--intern/cycles/blender/blender_util.h96
-rw-r--r--intern/cycles/bvh/CMakeLists.txt3
-rw-r--r--intern/cycles/bvh/bvh.cpp703
-rw-r--r--intern/cycles/bvh/bvh.h62
-rw-r--r--intern/cycles/bvh/bvh_binning.cpp72
-rw-r--r--intern/cycles/bvh/bvh_binning.h39
-rw-r--r--intern/cycles/bvh/bvh_build.cpp301
-rw-r--r--intern/cycles/bvh/bvh_build.h27
-rw-r--r--intern/cycles/bvh/bvh_node.cpp70
-rw-r--r--intern/cycles/bvh/bvh_node.h49
-rw-r--r--intern/cycles/bvh/bvh_params.h18
-rw-r--r--intern/cycles/bvh/bvh_sort.cpp47
-rw-r--r--intern/cycles/bvh/bvh_sort.h10
-rw-r--r--intern/cycles/bvh/bvh_split.cpp136
-rw-r--r--intern/cycles/bvh/bvh_split.h82
-rw-r--r--intern/cycles/bvh/bvh_unaligned.cpp178
-rw-r--r--intern/cycles/bvh/bvh_unaligned.h81
-rw-r--r--intern/cycles/device/CMakeLists.txt12
-rw-r--r--intern/cycles/device/device.cpp16
-rw-r--r--intern/cycles/device/device.h15
-rw-r--r--intern/cycles/device/device_cpu.cpp52
-rw-r--r--intern/cycles/device/device_cuda.cpp608
-rw-r--r--intern/cycles/device/device_memory.h5
-rw-r--r--intern/cycles/device/device_multi.cpp19
-rw-r--r--intern/cycles/device/device_network.cpp4
-rw-r--r--intern/cycles/device/device_network.h2
-rw-r--r--intern/cycles/device/device_opencl.cpp3223
-rw-r--r--intern/cycles/device/device_task.h2
-rw-r--r--intern/cycles/device/opencl/opencl.h403
-rw-r--r--intern/cycles/device/opencl/opencl_base.cpp741
-rw-r--r--intern/cycles/device/opencl/opencl_mega.cpp150
-rw-r--r--intern/cycles/device/opencl/opencl_split.cpp1307
-rw-r--r--intern/cycles/device/opencl/opencl_util.cpp793
-rw-r--r--intern/cycles/graph/CMakeLists.txt24
-rw-r--r--intern/cycles/graph/node.cpp407
-rw-r--r--intern/cycles/graph/node.h96
-rw-r--r--intern/cycles/graph/node_enum.h48
-rw-r--r--intern/cycles/graph/node_type.cpp220
-rw-r--r--intern/cycles/graph/node_type.h265
-rw-r--r--intern/cycles/graph/node_xml.cpp462
-rw-r--r--intern/cycles/graph/node_xml.h35
-rw-r--r--intern/cycles/kernel/CMakeLists.txt67
-rw-r--r--intern/cycles/kernel/bvh/bvh.h (renamed from intern/cycles/kernel/geom/geom_bvh.h)182
-rw-r--r--intern/cycles/kernel/bvh/bvh_nodes.h656
-rw-r--r--intern/cycles/kernel/bvh/bvh_shadow_all.h (renamed from intern/cycles/kernel/geom/geom_bvh_shadow.h)271
-rw-r--r--intern/cycles/kernel/bvh/bvh_subsurface.h (renamed from intern/cycles/kernel/geom/geom_bvh_subsurface.h)194
-rw-r--r--intern/cycles/kernel/bvh/bvh_traversal.h466
-rw-r--r--intern/cycles/kernel/bvh/bvh_types.h72
-rw-r--r--intern/cycles/kernel/bvh/bvh_volume.h (renamed from intern/cycles/kernel/geom/geom_bvh_volume.h)234
-rw-r--r--intern/cycles/kernel/bvh/bvh_volume_all.h (renamed from intern/cycles/kernel/geom/geom_bvh_volume_all.h)241
-rw-r--r--intern/cycles/kernel/bvh/qbvh_nodes.h465
-rw-r--r--intern/cycles/kernel/bvh/qbvh_shadow_all.h480
-rw-r--r--intern/cycles/kernel/bvh/qbvh_subsurface.h (renamed from intern/cycles/kernel/geom/geom_qbvh_subsurface.h)206
-rw-r--r--intern/cycles/kernel/bvh/qbvh_traversal.h501
-rw-r--r--intern/cycles/kernel/bvh/qbvh_volume.h (renamed from intern/cycles/kernel/geom/geom_qbvh_volume.h)282
-rw-r--r--intern/cycles/kernel/bvh/qbvh_volume_all.h (renamed from intern/cycles/kernel/geom/geom_qbvh_volume_all.h)291
-rw-r--r--intern/cycles/kernel/closure/alloc.h90
-rw-r--r--intern/cycles/kernel/closure/bsdf.h123
-rw-r--r--intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h60
-rw-r--r--intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h35
-rw-r--r--intern/cycles/kernel/closure/bsdf_diffuse.h33
-rw-r--r--intern/cycles/kernel/closure/bsdf_diffuse_ramp.h35
-rw-r--r--intern/cycles/kernel/closure/bsdf_hair.h71
-rw-r--r--intern/cycles/kernel/closure/bsdf_microfacet.h259
-rw-r--r--intern/cycles/kernel/closure/bsdf_microfacet_multi.h557
-rw-r--r--intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h233
-rw-r--r--intern/cycles/kernel/closure/bsdf_oren_nayar.h45
-rw-r--r--intern/cycles/kernel/closure/bsdf_phong_ramp.h56
-rw-r--r--intern/cycles/kernel/closure/bsdf_reflection.h7
-rw-r--r--intern/cycles/kernel/closure/bsdf_refraction.h9
-rw-r--r--intern/cycles/kernel/closure/bsdf_toon.h78
-rw-r--r--intern/cycles/kernel/closure/bsdf_util.h6
-rw-r--r--intern/cycles/kernel/closure/bssrdf.h117
-rw-r--r--intern/cycles/kernel/closure/volume.h26
-rw-r--r--intern/cycles/kernel/geom/geom.h29
-rw-r--r--intern/cycles/kernel/geom/geom_attribute.h65
-rw-r--r--intern/cycles/kernel/geom/geom_bvh_traversal.h449
-rw-r--r--intern/cycles/kernel/geom/geom_curve.h34
-rw-r--r--intern/cycles/kernel/geom/geom_motion_triangle.h41
-rw-r--r--intern/cycles/kernel/geom/geom_object.h60
-rw-r--r--intern/cycles/kernel/geom/geom_patch.h343
-rw-r--r--intern/cycles/kernel/geom/geom_primitive.h72
-rw-r--r--intern/cycles/kernel/geom/geom_qbvh.h147
-rw-r--r--intern/cycles/kernel/geom/geom_qbvh_shadow.h403
-rw-r--r--intern/cycles/kernel/geom/geom_qbvh_traversal.h425
-rw-r--r--intern/cycles/kernel/geom/geom_subd_triangle.h355
-rw-r--r--intern/cycles/kernel/geom/geom_triangle.h94
-rw-r--r--intern/cycles/kernel/geom/geom_triangle_intersect.h212
-rw-r--r--intern/cycles/kernel/geom/geom_volume.h55
-rw-r--r--intern/cycles/kernel/kernel_accumulate.h78
-rw-r--r--intern/cycles/kernel/kernel_bake.h74
-rw-r--r--intern/cycles/kernel/kernel_camera.h230
-rw-r--r--intern/cycles/kernel/kernel_compat_cpu.h52
-rw-r--r--intern/cycles/kernel/kernel_compat_cuda.h36
-rw-r--r--intern/cycles/kernel/kernel_compat_opencl.h3
-rw-r--r--intern/cycles/kernel/kernel_emission.h60
-rw-r--r--intern/cycles/kernel/kernel_globals.h19
-rw-r--r--intern/cycles/kernel/kernel_image_opencl.h231
-rw-r--r--intern/cycles/kernel/kernel_light.h91
-rw-r--r--intern/cycles/kernel/kernel_path.h126
-rw-r--r--intern/cycles/kernel/kernel_path_branched.h75
-rw-r--r--intern/cycles/kernel/kernel_path_state.h16
-rw-r--r--intern/cycles/kernel/kernel_path_surface.h102
-rw-r--r--intern/cycles/kernel/kernel_path_volume.h112
-rw-r--r--intern/cycles/kernel/kernel_projection.h64
-rw-r--r--intern/cycles/kernel/kernel_random.h22
-rw-r--r--intern/cycles/kernel/kernel_shader.h205
-rw-r--r--intern/cycles/kernel/kernel_shadow.h86
-rw-r--r--intern/cycles/kernel/kernel_subsurface.h60
-rw-r--r--intern/cycles/kernel/kernel_textures.h84
-rw-r--r--intern/cycles/kernel/kernel_types.h307
-rw-r--r--intern/cycles/kernel/kernel_volume.h131
-rw-r--r--intern/cycles/kernel/kernels/cpu/kernel.cpp72
-rw-r--r--intern/cycles/kernel/kernels/cpu/kernel_avx.cpp1
-rw-r--r--intern/cycles/kernel/kernels/cpu/kernel_avx2.cpp1
-rw-r--r--intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h78
-rw-r--r--intern/cycles/kernel/kernels/cpu/kernel_cpu_impl.h3
-rw-r--r--intern/cycles/kernel/kernels/cuda/kernel.cu6
-rw-r--r--intern/cycles/kernel/kernels/opencl/kernel.cl2
-rw-r--r--intern/cycles/kernel/osl/CMakeLists.txt2
-rw-r--r--intern/cycles/kernel/osl/background.cpp20
-rw-r--r--intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp46
-rw-r--r--intern/cycles/kernel/osl/bsdf_phong_ramp.cpp48
-rw-r--r--intern/cycles/kernel/osl/emissive.cpp23
-rw-r--r--intern/cycles/kernel/osl/osl_bssrdf.cpp102
-rw-r--r--intern/cycles/kernel/osl/osl_bssrdf.h61
-rw-r--r--intern/cycles/kernel/osl/osl_closures.cpp260
-rw-r--r--intern/cycles/kernel/osl/osl_closures.h116
-rw-r--r--intern/cycles/kernel/osl/osl_globals.h4
-rw-r--r--intern/cycles/kernel/osl/osl_services.cpp55
-rw-r--r--intern/cycles/kernel/osl/osl_services.h1
-rw-r--r--intern/cycles/kernel/osl/osl_shader.cpp338
-rw-r--r--intern/cycles/kernel/osl/osl_shader.h12
-rw-r--r--intern/cycles/kernel/shaders/CMakeLists.txt1
-rw-r--r--intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl6
-rw-r--r--intern/cycles/kernel/shaders/node_brick_texture.osl31
-rw-r--r--intern/cycles/kernel/shaders/node_bump.osl25
-rw-r--r--intern/cycles/kernel/shaders/node_convert_from_color.osl24
-rw-r--r--intern/cycles/kernel/shaders/node_convert_from_float.osl24
-rw-r--r--intern/cycles/kernel/shaders/node_convert_from_int.osl26
-rw-r--r--intern/cycles/kernel/shaders/node_convert_from_normal.osl24
-rw-r--r--intern/cycles/kernel/shaders/node_convert_from_point.osl24
-rw-r--r--intern/cycles/kernel/shaders/node_convert_from_string.osl14
-rw-r--r--intern/cycles/kernel/shaders/node_convert_from_vector.osl24
-rw-r--r--intern/cycles/kernel/shaders/node_environment_texture.osl4
-rw-r--r--intern/cycles/kernel/shaders/node_glass_bsdf.osl8
-rw-r--r--intern/cycles/kernel/shaders/node_glossy_bsdf.osl6
-rw-r--r--intern/cycles/kernel/shaders/node_gradient_texture.osl18
-rw-r--r--intern/cycles/kernel/shaders/node_hair_bsdf.osl47
-rw-r--r--intern/cycles/kernel/shaders/node_image_texture.osl28
-rw-r--r--intern/cycles/kernel/shaders/node_magic_texture.osl4
-rw-r--r--intern/cycles/kernel/shaders/node_math.osl44
-rw-r--r--intern/cycles/kernel/shaders/node_mix.osl42
-rw-r--r--intern/cycles/kernel/shaders/node_musgrave_texture.osl12
-rw-r--r--intern/cycles/kernel/shaders/node_normal.osl4
-rw-r--r--intern/cycles/kernel/shaders/node_normal_map.osl28
-rw-r--r--intern/cycles/kernel/shaders/node_output_displacement.osl4
-rw-r--r--intern/cycles/kernel/shaders/node_ramp_util.h89
-rw-r--r--intern/cycles/kernel/shaders/node_refraction_bsdf.osl6
-rw-r--r--intern/cycles/kernel/shaders/node_rgb_curves.osl47
-rw-r--r--intern/cycles/kernel/shaders/node_rgb_ramp.osl25
-rw-r--r--intern/cycles/kernel/shaders/node_rgb_to_bw.osl25
-rw-r--r--intern/cycles/kernel/shaders/node_sky_texture.osl4
-rw-r--r--intern/cycles/kernel/shaders/node_subsurface_scattering.osl6
-rw-r--r--intern/cycles/kernel/shaders/node_tangent.osl12
-rw-r--r--intern/cycles/kernel/shaders/node_toon_bsdf.osl6
-rw-r--r--intern/cycles/kernel/shaders/node_uv_map.osl6
-rw-r--r--intern/cycles/kernel/shaders/node_vector_curves.osl47
-rw-r--r--intern/cycles/kernel/shaders/node_vector_math.osl14
-rw-r--r--intern/cycles/kernel/shaders/node_vector_transform.osl8
-rw-r--r--intern/cycles/kernel/shaders/node_voronoi_texture.osl4
-rw-r--r--intern/cycles/kernel/shaders/node_wave_texture.osl12
-rw-r--r--intern/cycles/kernel/shaders/oslutil.h3
-rw-r--r--intern/cycles/kernel/shaders/stdosl.h3
-rw-r--r--intern/cycles/kernel/split/kernel_background_buffer_update.h7
-rw-r--r--intern/cycles/kernel/split/kernel_data_init.h4
-rw-r--r--intern/cycles/kernel/split/kernel_direct_lighting.h41
-rw-r--r--intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h3
-rw-r--r--intern/cycles/kernel/split/kernel_lamp_emission.h2
-rw-r--r--intern/cycles/kernel/split/kernel_next_iteration_setup.h2
-rw-r--r--intern/cycles/kernel/split/kernel_scene_intersect.h4
-rw-r--r--intern/cycles/kernel/split/kernel_shader_eval.h2
-rw-r--r--intern/cycles/kernel/split/kernel_shadow_blocked.h1
-rw-r--r--intern/cycles/kernel/split/kernel_split_common.h2
-rw-r--r--intern/cycles/kernel/svm/svm.h16
-rw-r--r--intern/cycles/kernel/svm/svm_attribute.h116
-rw-r--r--intern/cycles/kernel/svm/svm_brick.h32
-rw-r--r--intern/cycles/kernel/svm/svm_brightness.h7
-rw-r--r--intern/cycles/kernel/svm/svm_bump.h54
-rw-r--r--intern/cycles/kernel/svm/svm_closure.h501
-rw-r--r--intern/cycles/kernel/svm/svm_color_util.h306
-rw-r--r--intern/cycles/kernel/svm/svm_displace.h36
-rw-r--r--intern/cycles/kernel/svm/svm_geometry.h18
-rw-r--r--intern/cycles/kernel/svm/svm_image.h204
-rw-r--r--intern/cycles/kernel/svm/svm_math_util.h13
-rw-r--r--intern/cycles/kernel/svm/svm_mix.h274
-rw-r--r--intern/cycles/kernel/svm/svm_ramp.h68
-rw-r--r--intern/cycles/kernel/svm/svm_ramp_util.h99
-rw-r--r--intern/cycles/kernel/svm/svm_tex_coord.h81
-rw-r--r--intern/cycles/kernel/svm/svm_types.h33
-rw-r--r--intern/cycles/kernel/svm/svm_voxel.h21
-rw-r--r--intern/cycles/kernel/svm/svm_wireframe.h10
-rw-r--r--intern/cycles/render/CMakeLists.txt4
-rw-r--r--intern/cycles/render/attribute.cpp134
-rw-r--r--intern/cycles/render/attribute.h25
-rw-r--r--intern/cycles/render/background.cpp47
-rw-r--r--intern/cycles/render/background.h9
-rw-r--r--intern/cycles/render/bake.cpp2
-rw-r--r--intern/cycles/render/buffers.cpp18
-rw-r--r--intern/cycles/render/buffers.h4
-rw-r--r--intern/cycles/render/camera.cpp190
-rw-r--r--intern/cycles/render/camera.h11
-rw-r--r--intern/cycles/render/constant_fold.cpp384
-rw-r--r--intern/cycles/render/constant_fold.h71
-rw-r--r--intern/cycles/render/curves.h34
-rw-r--r--intern/cycles/render/film.cpp70
-rw-r--r--intern/cycles/render/film.h16
-rw-r--r--intern/cycles/render/graph.cpp415
-rw-r--r--intern/cycles/render/graph.h132
-rw-r--r--intern/cycles/render/image.cpp840
-rw-r--r--intern/cycles/render/image.h26
-rw-r--r--intern/cycles/render/integrator.cpp130
-rw-r--r--intern/cycles/render/integrator.h7
-rw-r--r--intern/cycles/render/light.cpp296
-rw-r--r--intern/cycles/render/light.h18
-rw-r--r--intern/cycles/render/mesh.cpp1083
-rw-r--r--intern/cycles/render/mesh.h180
-rw-r--r--intern/cycles/render/mesh_displace.cpp180
-rw-r--r--intern/cycles/render/mesh_subdivision.cpp612
-rw-r--r--intern/cycles/render/nodes.cpp3228
-rw-r--r--intern/cycles/render/nodes.h622
-rw-r--r--intern/cycles/render/object.cpp150
-rw-r--r--intern/cycles/render/object.h14
-rw-r--r--intern/cycles/render/osl.cpp469
-rw-r--r--intern/cycles/render/osl.h17
-rw-r--r--intern/cycles/render/particles.cpp11
-rw-r--r--intern/cycles/render/particles.h2
-rw-r--r--intern/cycles/render/scene.cpp17
-rw-r--r--intern/cycles/render/scene.h32
-rw-r--r--intern/cycles/render/session.cpp19
-rw-r--r--intern/cycles/render/session.h2
-rw-r--r--intern/cycles/render/shader.cpp180
-rw-r--r--intern/cycles/render/shader.h26
-rw-r--r--intern/cycles/render/svm.cpp273
-rw-r--r--intern/cycles/render/svm.h26
-rw-r--r--intern/cycles/subd/CMakeLists.txt11
-rw-r--r--intern/cycles/subd/subd_dice.cpp187
-rw-r--r--intern/cycles/subd/subd_dice.h54
-rw-r--r--intern/cycles/subd/subd_mesh.cpp419
-rw-r--r--intern/cycles/subd/subd_mesh.h78
-rw-r--r--intern/cycles/subd/subd_patch.cpp26
-rw-r--r--intern/cycles/subd/subd_patch.h18
-rw-r--r--intern/cycles/subd/subd_patch_table.cpp297
-rw-r--r--intern/cycles/subd/subd_patch_table.h63
-rw-r--r--intern/cycles/subd/subd_split.cpp199
-rw-r--r--intern/cycles/subd/subd_split.h10
-rw-r--r--intern/cycles/test/CMakeLists.txt40
-rw-r--r--intern/cycles/test/render_graph_finalize_test.cpp1680
-rw-r--r--intern/cycles/util/CMakeLists.txt8
-rw-r--r--intern/cycles/util/util_avxf.h185
-rw-r--r--intern/cycles/util/util_boundbox.h2
-rw-r--r--intern/cycles/util/util_debug.h6
-rw-r--r--intern/cycles/util/util_guarded_allocator.cpp2
-rw-r--r--intern/cycles/util/util_half.h33
-rw-r--r--intern/cycles/util/util_math.h291
-rw-r--r--intern/cycles/util/util_math_fast.h3
-rw-r--r--intern/cycles/util/util_path.cpp71
-rw-r--r--intern/cycles/util/util_path.h5
-rw-r--r--intern/cycles/util/util_progress.h12
-rw-r--r--intern/cycles/util/util_simd.h3
-rw-r--r--intern/cycles/util/util_sky_model.cpp2
-rw-r--r--intern/cycles/util/util_static_assert.h68
-rw-r--r--intern/cycles/util/util_stats.h3
-rw-r--r--intern/cycles/util/util_string.cpp53
-rw-r--r--intern/cycles/util/util_string.h10
-rw-r--r--intern/cycles/util/util_system.cpp52
-rw-r--r--intern/cycles/util/util_system.h8
-rw-r--r--intern/cycles/util/util_task.cpp24
-rw-r--r--intern/cycles/util/util_task.h2
-rw-r--r--intern/cycles/util/util_texture.h66
-rw-r--r--intern/cycles/util/util_thread.cpp66
-rw-r--r--intern/cycles/util/util_thread.h38
-rw-r--r--intern/cycles/util/util_time.h2
-rw-r--r--intern/cycles/util/util_transform.cpp2
-rw-r--r--intern/cycles/util/util_transform.h60
-rw-r--r--intern/cycles/util/util_types.h18
-rw-r--r--intern/cycles/util/util_vector.h90
-rw-r--r--intern/cycles/util/util_view.cpp2
-rw-r--r--intern/cycles/util/util_windows.cpp88
-rw-r--r--intern/cycles/util/util_windows.h19
-rw-r--r--intern/decklink/CMakeLists.txt58
-rw-r--r--intern/decklink/DeckLinkAPI.cpp50
-rw-r--r--intern/decklink/DeckLinkAPI.h56
-rw-r--r--intern/decklink/linux/DeckLinkAPI.h767
-rw-r--r--intern/decklink/linux/DeckLinkAPIConfiguration.h192
-rw-r--r--intern/decklink/linux/DeckLinkAPIDeckControl.h215
-rw-r--r--intern/decklink/linux/DeckLinkAPIDiscovery.h71
-rw-r--r--intern/decklink/linux/DeckLinkAPIDispatch.cpp148
-rw-r--r--intern/decklink/linux/DeckLinkAPIModes.h191
-rw-r--r--intern/decklink/linux/DeckLinkAPITypes.h110
-rw-r--r--intern/decklink/linux/DeckLinkAPIVersion.h37
-rw-r--r--intern/decklink/linux/LinuxCOM.h100
-rw-r--r--intern/decklink/win/DeckLinkAPI_h.h13323
-rw-r--r--intern/decklink/win/DeckLinkAPI_i.c343
-rw-r--r--intern/elbeem/intern/controlparticles.cpp3
-rw-r--r--intern/elbeem/intern/isosurface.h6
-rw-r--r--intern/elbeem/intern/solver_class.h2
-rw-r--r--intern/elbeem/intern/solver_main.cpp42
-rw-r--r--intern/ghost/CMakeLists.txt4
-rw-r--r--intern/ghost/GHOST_C-api.h2
-rw-r--r--intern/ghost/GHOST_ISystem.h4
-rw-r--r--intern/ghost/GHOST_Types.h9
-rw-r--r--intern/ghost/doc/ghost_interface.cfg626
-rw-r--r--intern/ghost/intern/GHOST_C-api.cpp3
-rw-r--r--intern/ghost/intern/GHOST_ContextCGL.h2
-rw-r--r--intern/ghost/intern/GHOST_ContextCGL.mm87
-rw-r--r--intern/ghost/intern/GHOST_ContextGLX.cpp51
-rw-r--r--intern/ghost/intern/GHOST_ContextGLX.h3
-rw-r--r--intern/ghost/intern/GHOST_ContextSDL.cpp2
-rw-r--r--intern/ghost/intern/GHOST_ContextWGL.cpp75
-rw-r--r--intern/ghost/intern/GHOST_ContextWGL.h4
-rw-r--r--intern/ghost/intern/GHOST_DropTargetWin32.cpp17
-rw-r--r--intern/ghost/intern/GHOST_EventManager.cpp12
-rw-r--r--intern/ghost/intern/GHOST_EventNDOF.h5
-rw-r--r--intern/ghost/intern/GHOST_ISystem.cpp6
-rw-r--r--intern/ghost/intern/GHOST_ISystemPaths.cpp9
-rw-r--r--intern/ghost/intern/GHOST_ImeWin32.cpp2
-rw-r--r--intern/ghost/intern/GHOST_NDOFManager.cpp13
-rw-r--r--intern/ghost/intern/GHOST_NDOFManager.h13
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerCocoa.h4
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerCocoa.mm21
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerUnix.cpp10
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerUnix.h3
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerWin32.cpp4
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerWin32.h4
-rw-r--r--intern/ghost/intern/GHOST_System.cpp56
-rw-r--r--intern/ghost/intern/GHOST_System.h10
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.mm508
-rw-r--r--intern/ghost/intern/GHOST_SystemPathsWin32.cpp6
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp70
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.h7
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp210
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.h20
-rw-r--r--intern/ghost/intern/GHOST_Window.h2
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.h4
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.mm11
-rw-r--r--intern/ghost/intern/GHOST_WindowManager.cpp8
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.cpp87
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.h3
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.cpp240
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.h11
-rw-r--r--intern/gpudirect/CMakeLists.txt41
-rw-r--r--intern/gpudirect/dvpapi.cpp147
-rw-r--r--intern/gpudirect/dvpapi.h667
-rw-r--r--intern/guardedalloc/test/simpletest/memtest.c1
-rw-r--r--intern/itasc/ConstraintSet.cpp26
-rw-r--r--intern/itasc/Scene.cpp20
-rw-r--r--intern/itasc/WSDLSSolver.cpp8
-rw-r--r--intern/libmv/intern/autotrack.cc8
-rw-r--r--intern/libmv/libmv/multiview/projection.h2
-rw-r--r--intern/libmv/libmv/numeric/numeric.cc2
-rw-r--r--intern/libmv/libmv/numeric/numeric.h2
-rw-r--r--intern/mikktspace/mikktspace.c12
-rw-r--r--intern/moto/include/MT_Matrix4x4.h10
-rw-r--r--intern/opencolorio/gpu_shader_display_transform.glsl2
-rw-r--r--intern/opensubdiv/CMakeLists.txt6
-rw-r--r--intern/opensubdiv/gpu_shader_opensubdiv_fragment.glsl (renamed from intern/opensubdiv/gpu_shader_opensubd_display.glsl)176
-rw-r--r--intern/opensubdiv/gpu_shader_opensubdiv_geometry.glsl165
-rw-r--r--intern/opensubdiv/gpu_shader_opensubdiv_vertex.glsl53
-rw-r--r--intern/opensubdiv/opensubdiv_capi.cc89
-rw-r--r--intern/opensubdiv/opensubdiv_capi.h11
-rw-r--r--intern/opensubdiv/opensubdiv_converter.cc112
-rw-r--r--intern/opensubdiv/opensubdiv_converter_capi.h16
-rw-r--r--intern/opensubdiv/opensubdiv_gpu_capi.cc444
-rw-r--r--intern/opensubdiv/opensubdiv_topology_refiner.h41
-rw-r--r--intern/smoke/intern/FLUID_3D.cpp141
-rw-r--r--intern/smoke/intern/FLUID_3D.h5
-rw-r--r--make.bat258
-rwxr-xr-xrelease/bin/blender-thumbnailer.py2
-rw-r--r--release/datafiles/LICENSE-droidsans.ttf.txt2
-rw-r--r--release/datafiles/blender_icons.svg6060
-rw-r--r--release/datafiles/blender_icons16/icon16_restrict_color_off.datbin0 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_restrict_color_on.datbin0 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_restrict_color_off.datbin0 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_restrict_color_on.datbin0 -> 4120 bytes
-rw-r--r--release/datafiles/colormanagement/config.ocio1
-rw-r--r--release/datafiles/colormanagement/luts/srgb_inv.spi1d65567
-rwxr-xr-xrelease/datafiles/ctodata.py2
-rw-r--r--release/datafiles/fonts/droidsans.ttf.gzbin2485497 -> 2485539 bytes
m---------release/datafiles/locale0
-rw-r--r--release/datafiles/prvicons.pngbin15781 -> 16912 bytes
-rw-r--r--release/datafiles/prvicons.svg3799
-rw-r--r--release/datafiles/splash.pngbin230768 -> 283527 bytes
-rw-r--r--release/datafiles/splash_2x.pngbin812837 -> 988186 bytes
-rwxr-xr-xrelease/datafiles/splash_scale.sh18
-rw-r--r--release/datafiles/splash_template.xcfbin1274820 -> 1267126 bytes
m---------release/scripts/addons0
m---------release/scripts/addons_contrib0
-rw-r--r--release/scripts/freestyle/modules/parameter_editor.py15
-rw-r--r--release/scripts/modules/addon_utils.py4
-rw-r--r--release/scripts/modules/bl_i18n_utils/bl_extract_messages.py30
-rw-r--r--release/scripts/modules/bl_i18n_utils/settings.py6
-rw-r--r--release/scripts/modules/bl_i18n_utils/utils_spell_check.py23
-rw-r--r--release/scripts/modules/bl_previews_utils/bl_previews_render.py42
-rwxr-xr-xrelease/scripts/modules/blend_render_info.py6
-rw-r--r--release/scripts/modules/bpy/__init__.py12
-rw-r--r--release/scripts/modules/bpy/path.py32
-rw-r--r--release/scripts/modules/bpy/utils/__init__.py35
-rw-r--r--release/scripts/modules/bpy/utils/previews.py2
-rw-r--r--release/scripts/modules/bpy_extras/anim_utils.py7
-rw-r--r--release/scripts/modules/bpy_extras/keyconfig_utils.py39
-rw-r--r--release/scripts/modules/bpy_extras/object_utils.py12
-rw-r--r--release/scripts/modules/bpy_extras/view3d_utils.py6
-rw-r--r--release/scripts/modules/bpy_restrict_state.py2
-rw-r--r--release/scripts/modules/bpy_types.py15
-rw-r--r--release/scripts/modules/console/complete_import.py10
-rw-r--r--release/scripts/modules/console/complete_namespace.py4
-rw-r--r--release/scripts/modules/console/intellisense.py14
-rw-r--r--release/scripts/modules/console_python.py18
-rw-r--r--release/scripts/modules/keyingsets_utils.py52
-rw-r--r--release/scripts/modules/progress_report.py3
-rw-r--r--release/scripts/modules/rna_info.py40
-rw-r--r--release/scripts/modules/rna_xml.py5
-rw-r--r--release/scripts/modules/sys_info.py350
-rw-r--r--release/scripts/presets/ffmpeg/DV.py14
-rw-r--r--release/scripts/presets/ffmpeg/DVD (note_colon_ this changes render resolution).py (renamed from release/scripts/presets/ffmpeg/DVD.py)0
-rw-r--r--release/scripts/presets/ffmpeg/SVCD.py24
-rw-r--r--release/scripts/presets/ffmpeg/VCD.py24
-rw-r--r--release/scripts/presets/ffmpeg/h264 in MP4.py18
-rw-r--r--release/scripts/presets/ffmpeg/h264 in Matroska for scrubbing.py14
-rw-r--r--release/scripts/presets/ffmpeg/h264 in Matroska.py (renamed from release/scripts/presets/ffmpeg/h264.py)2
-rw-r--r--release/scripts/presets/ffmpeg/ogg_theora.py (renamed from release/scripts/presets/ffmpeg/theora.py)1
-rw-r--r--release/scripts/presets/ffmpeg/xvid.py4
-rw-r--r--release/scripts/presets/interface_theme/back_to_black.xml13
-rw-r--r--release/scripts/presets/interface_theme/blender_24x.xml17
-rw-r--r--release/scripts/presets/interface_theme/elsyiun.xml13
-rw-r--r--release/scripts/presets/interface_theme/flatty_light.xml13
-rw-r--r--release/scripts/presets/interface_theme/graph.xml13
-rw-r--r--release/scripts/presets/interface_theme/hexagon.xml13
-rw-r--r--release/scripts/presets/interface_theme/rtheme.xml13
-rw-r--r--release/scripts/presets/interface_theme/science_lab.xml13
-rw-r--r--release/scripts/presets/interface_theme/softimage.xml13
-rw-r--r--release/scripts/presets/interface_theme/ubuntu_ambiance.xml13
-rw-r--r--release/scripts/presets/keyconfig/maya.py2
-rw-r--r--release/scripts/startup/bl_operators/add_mesh_torus.py40
-rw-r--r--release/scripts/startup/bl_operators/anim.py2
-rw-r--r--release/scripts/startup/bl_operators/file.py20
-rw-r--r--release/scripts/startup/bl_operators/object.py85
-rw-r--r--release/scripts/startup/bl_operators/object_align.py10
-rw-r--r--release/scripts/startup/bl_operators/uvcalc_lightmap.py3
-rw-r--r--release/scripts/startup/bl_operators/wm.py82
-rw-r--r--release/scripts/startup/bl_ui/__init__.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_constraint.py16
-rw-r--r--release/scripts/startup/bl_ui/properties_data_armature.py6
-rw-r--r--release/scripts/startup/bl_ui/properties_data_bone.py101
-rw-r--r--release/scripts/startup/bl_ui/properties_data_camera.py10
-rw-r--r--release/scripts/startup/bl_ui/properties_data_curve.py9
-rw-r--r--release/scripts/startup/bl_ui/properties_data_modifier.py78
-rw-r--r--release/scripts/startup/bl_ui/properties_game.py29
-rw-r--r--release/scripts/startup/bl_ui/properties_grease_pencil_common.py604
-rw-r--r--release/scripts/startup/bl_ui/properties_particle.py6
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_cloth.py53
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_common.py3
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py27
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_field.py8
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_fluid.py12
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_rigidbody.py9
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py3
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_smoke.py67
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_softbody.py11
-rw-r--r--release/scripts/startup/bl_ui/properties_render.py49
-rw-r--r--release/scripts/startup/bl_ui/properties_world.py4
-rw-r--r--release/scripts/startup/bl_ui/space_clip.py125
-rw-r--r--release/scripts/startup/bl_ui/space_console.py4
-rw-r--r--release/scripts/startup/bl_ui/space_dopesheet.py8
-rw-r--r--release/scripts/startup/bl_ui/space_graph.py6
-rw-r--r--release/scripts/startup/bl_ui/space_image.py34
-rw-r--r--release/scripts/startup/bl_ui/space_info.py37
-rw-r--r--release/scripts/startup/bl_ui/space_logic.py4
-rw-r--r--release/scripts/startup/bl_ui/space_nla.py5
-rw-r--r--release/scripts/startup/bl_ui/space_node.py32
-rw-r--r--release/scripts/startup/bl_ui/space_outliner.py4
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py20
-rw-r--r--release/scripts/startup/bl_ui/space_text.py4
-rw-r--r--release/scripts/startup/bl_ui/space_time.py4
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py23
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py117
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py31
-rw-r--r--release/scripts/startup/keyingsets_builtins.py68
-rw-r--r--release/scripts/startup/nodeitems_builtins.py1
-rw-r--r--release/scripts/templates_py/external_script_stub.py (renamed from release/scripts/templates_py/script_stub.py)0
-rw-r--r--source/blender/CMakeLists.txt4
-rw-r--r--source/blender/alembic/ABC_alembic.h119
-rw-r--r--source/blender/alembic/CMakeLists.txt85
-rw-r--r--source/blender/alembic/intern/abc_archive.cc175
-rw-r--r--source/blender/alembic/intern/abc_archive.h66
-rw-r--r--source/blender/alembic/intern/abc_camera.cc160
-rw-r--r--source/blender/alembic/intern/abc_camera.h61
-rw-r--r--source/blender/alembic/intern/abc_curves.cc407
-rw-r--r--source/blender/alembic/intern/abc_curves.h66
-rw-r--r--source/blender/alembic/intern/abc_customdata.cc379
-rw-r--r--source/blender/alembic/intern/abc_customdata.h102
-rw-r--r--source/blender/alembic/intern/abc_exporter.cc584
-rw-r--r--source/blender/alembic/intern/abc_exporter.h118
-rw-r--r--source/blender/alembic/intern/abc_hair.cc290
-rw-r--r--source/blender/alembic/intern/abc_hair.h66
-rw-r--r--source/blender/alembic/intern/abc_mesh.cc1303
-rw-r--r--source/blender/alembic/intern/abc_mesh.h147
-rw-r--r--source/blender/alembic/intern/abc_nurbs.cc367
-rw-r--r--source/blender/alembic/intern/abc_nurbs.h63
-rw-r--r--source/blender/alembic/intern/abc_object.cc325
-rw-r--r--source/blender/alembic/intern/abc_object.h191
-rw-r--r--source/blender/alembic/intern/abc_points.cc219
-rw-r--r--source/blender/alembic/intern/abc_points.h72
-rw-r--r--source/blender/alembic/intern/abc_transform.cc152
-rw-r--r--source/blender/alembic/intern/abc_transform.h73
-rw-r--r--source/blender/alembic/intern/abc_util.cc526
-rw-r--r--source/blender/alembic/intern/abc_util.h149
-rw-r--r--source/blender/alembic/intern/alembic_capi.cc887
-rw-r--r--source/blender/blenfont/intern/blf_font.c8
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c14
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h15
-rw-r--r--source/blender/blenkernel/BKE_action.h14
-rw-r--r--source/blender/blenkernel/BKE_animsys.h8
-rw-r--r--source/blender/blenkernel/BKE_armature.h6
-rw-r--r--source/blender/blenkernel/BKE_blender.h5
-rw-r--r--source/blender/blenkernel/BKE_blender_copybuffer.h1
-rw-r--r--source/blender/blenkernel/BKE_blender_undo.h2
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/BKE_brush.h4
-rw-r--r--source/blender/blenkernel/BKE_bvhutils.h54
-rw-r--r--source/blender/blenkernel/BKE_cachefile.h72
-rw-r--r--source/blender/blenkernel/BKE_camera.h4
-rw-r--r--source/blender/blenkernel/BKE_cloth.h1
-rw-r--r--source/blender/blenkernel/BKE_collision.h4
-rw-r--r--source/blender/blenkernel/BKE_colortools.h2
-rw-r--r--source/blender/blenkernel/BKE_context.h9
-rw-r--r--source/blender/blenkernel/BKE_curve.h15
-rw-r--r--source/blender/blenkernel/BKE_customdata.h4
-rw-r--r--source/blender/blenkernel/BKE_displist.h14
-rw-r--r--source/blender/blenkernel/BKE_dynamicpaint.h2
-rw-r--r--source/blender/blenkernel/BKE_effect.h2
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h6
-rw-r--r--source/blender/blenkernel/BKE_font.h2
-rw-r--r--source/blender/blenkernel/BKE_freestyle.h3
-rw-r--r--source/blender/blenkernel/BKE_global.h1
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h72
-rw-r--r--source/blender/blenkernel/BKE_group.h4
-rw-r--r--source/blender/blenkernel/BKE_icons.h5
-rw-r--r--source/blender/blenkernel/BKE_idcode.h2
-rw-r--r--source/blender/blenkernel/BKE_image.h2
-rw-r--r--source/blender/blenkernel/BKE_key.h4
-rw-r--r--source/blender/blenkernel/BKE_lamp.h4
-rw-r--r--source/blender/blenkernel/BKE_lattice.h4
-rw-r--r--source/blender/blenkernel/BKE_library.h35
-rw-r--r--source/blender/blenkernel/BKE_library_idmap.h50
-rw-r--r--source/blender/blenkernel/BKE_library_query.h17
-rw-r--r--source/blender/blenkernel/BKE_library_remap.h80
-rw-r--r--source/blender/blenkernel/BKE_linestyle.h12
-rw-r--r--source/blender/blenkernel/BKE_main.h5
-rw-r--r--source/blender/blenkernel/BKE_mask.h7
-rw-r--r--source/blender/blenkernel/BKE_material.h26
-rw-r--r--source/blender/blenkernel/BKE_mball.h5
-rw-r--r--source/blender/blenkernel/BKE_mesh.h15
-rw-r--r--source/blender/blenkernel/BKE_mesh_mapping.h20
-rw-r--r--source/blender/blenkernel/BKE_modifier.h3
-rw-r--r--source/blender/blenkernel/BKE_movieclip.h4
-rw-r--r--source/blender/blenkernel/BKE_node.h6
-rw-r--r--source/blender/blenkernel/BKE_object.h7
-rw-r--r--source/blender/blenkernel/BKE_paint.h4
-rw-r--r--source/blender/blenkernel/BKE_particle.h26
-rw-r--r--source/blender/blenkernel/BKE_pointcache.h2
-rw-r--r--source/blender/blenkernel/BKE_sca.h7
-rw-r--r--source/blender/blenkernel/BKE_scene.h8
-rw-r--r--source/blender/blenkernel/BKE_screen.h7
-rw-r--r--source/blender/blenkernel/BKE_sequencer.h2
-rw-r--r--source/blender/blenkernel/BKE_sound.h4
-rw-r--r--source/blender/blenkernel/BKE_speaker.h4
-rw-r--r--source/blender/blenkernel/BKE_text.h2
-rw-r--r--source/blender/blenkernel/BKE_texture.h4
-rw-r--r--source/blender/blenkernel/BKE_tracking.h5
-rw-r--r--source/blender/blenkernel/BKE_world.h5
-rw-r--r--source/blender/blenkernel/CMakeLists.txt16
-rw-r--r--source/blender/blenkernel/depsgraph_private.h10
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.c4
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.h4
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_intern.h7
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c15
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c244
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_util.c2
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c209
-rw-r--r--source/blender/blenkernel/intern/action.c174
-rw-r--r--source/blender/blenkernel/intern/anim.c10
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c419
-rw-r--r--source/blender/blenkernel/intern/armature.c321
-rw-r--r--source/blender/blenkernel/intern/armature_update.c16
-rw-r--r--source/blender/blenkernel/intern/autoexec.c5
-rw-r--r--source/blender/blenkernel/intern/blender.c55
-rw-r--r--source/blender/blenkernel/intern/blender_copybuffer.c25
-rw-r--r--source/blender/blenkernel/intern/blender_undo.c14
-rw-r--r--source/blender/blenkernel/intern/blendfile.c22
-rw-r--r--source/blender/blenkernel/intern/bpath.c9
-rw-r--r--source/blender/blenkernel/intern/brush.c113
-rw-r--r--source/blender/blenkernel/intern/bvhutils.c211
-rw-r--r--source/blender/blenkernel/intern/cachefile.c239
-rw-r--r--source/blender/blenkernel/intern/camera.c63
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c81
-rw-r--r--source/blender/blenkernel/intern/cloth.c36
-rw-r--r--source/blender/blenkernel/intern/collision.c27
-rw-r--r--source/blender/blenkernel/intern/colortools.c389
-rw-r--r--source/blender/blenkernel/intern/constraint.c163
-rw-r--r--source/blender/blenkernel/intern/context.c22
-rw-r--r--source/blender/blenkernel/intern/crazyspace.c9
-rw-r--r--source/blender/blenkernel/intern/curve.c200
-rw-r--r--source/blender/blenkernel/intern/customdata.c56
-rw-r--r--source/blender/blenkernel/intern/data_transfer.c2
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c157
-rw-r--r--source/blender/blenkernel/intern/displist.c14
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c4953
-rw-r--r--source/blender/blenkernel/intern/editderivedmesh.c45
-rw-r--r--source/blender/blenkernel/intern/effect.c40
-rw-r--r--source/blender/blenkernel/intern/fcurve.c103
-rw-r--r--source/blender/blenkernel/intern/font.c83
-rw-r--r--source/blender/blenkernel/intern/freestyle.c22
-rw-r--r--source/blender/blenkernel/intern/gpencil.c847
-rw-r--r--source/blender/blenkernel/intern/group.c79
-rw-r--r--source/blender/blenkernel/intern/icons.c95
-rw-r--r--source/blender/blenkernel/intern/idcode.c72
-rw-r--r--source/blender/blenkernel/intern/idprop.c11
-rw-r--r--source/blender/blenkernel/intern/image.c321
-rw-r--r--source/blender/blenkernel/intern/key.c34
-rw-r--r--source/blender/blenkernel/intern/lamp.c75
-rw-r--r--source/blender/blenkernel/intern/lattice.c85
-rw-r--r--source/blender/blenkernel/intern/library.c962
-rw-r--r--source/blender/blenkernel/intern/library_idmap.c176
-rw-r--r--source/blender/blenkernel/intern/library_query.c523
-rw-r--r--source/blender/blenkernel/intern/library_remap.c926
-rw-r--r--source/blender/blenkernel/intern/linestyle.c85
-rw-r--r--source/blender/blenkernel/intern/mask.c82
-rw-r--r--source/blender/blenkernel/intern/material.c326
-rw-r--r--source/blender/blenkernel/intern/mball.c88
-rw-r--r--source/blender/blenkernel/intern/mball_tessellate.c4
-rw-r--r--source/blender/blenkernel/intern/mesh.c246
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c15
-rw-r--r--source/blender/blenkernel/intern/mesh_mapping.c230
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.c4
-rw-r--r--source/blender/blenkernel/intern/modifier.c2
-rw-r--r--source/blender/blenkernel/intern/modifiers_bmesh.c8
-rw-r--r--source/blender/blenkernel/intern/movieclip.c88
-rw-r--r--source/blender/blenkernel/intern/nla.c4
-rw-r--r--source/blender/blenkernel/intern/node.c139
-rw-r--r--source/blender/blenkernel/intern/object.c635
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c19
-rw-r--r--source/blender/blenkernel/intern/object_update.c8
-rw-r--r--source/blender/blenkernel/intern/ocean.c16
-rw-r--r--source/blender/blenkernel/intern/packedFile.c6
-rw-r--r--source/blender/blenkernel/intern/paint.c49
-rw-r--r--source/blender/blenkernel/intern/particle.c190
-rw-r--r--source/blender/blenkernel/intern/particle_child.c2
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c44
-rw-r--r--source/blender/blenkernel/intern/particle_system.c89
-rw-r--r--source/blender/blenkernel/intern/pbvh.c42
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c497
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h10
-rw-r--r--source/blender/blenkernel/intern/pointcache.c29
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c6
-rw-r--r--source/blender/blenkernel/intern/sca.c208
-rw-r--r--source/blender/blenkernel/intern/scene.c175
-rw-r--r--source/blender/blenkernel/intern/screen.c17
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c44
-rw-r--r--source/blender/blenkernel/intern/sequencer.c97
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c523
-rw-r--r--source/blender/blenkernel/intern/smoke.c67
-rw-r--r--source/blender/blenkernel/intern/softbody.c161
-rw-r--r--source/blender/blenkernel/intern/sound.c22
-rw-r--r--source/blender/blenkernel/intern/speaker.c73
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c243
-rw-r--r--source/blender/blenkernel/intern/text.c201
-rw-r--r--source/blender/blenkernel/intern/texture.c244
-rw-r--r--source/blender/blenkernel/intern/tracking.c154
-rw-r--r--source/blender/blenkernel/intern/tracking_auto.c32
-rw-r--r--source/blender/blenkernel/intern/tracking_stabilize.c1641
-rw-r--r--source/blender/blenkernel/intern/tracking_util.c8
-rw-r--r--source/blender/blenkernel/intern/world.c92
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c81
-rw-r--r--source/blender/blenlib/BLI_array_store.h66
-rw-r--r--source/blender/blenlib/BLI_array_store_utils.h50
-rw-r--r--source/blender/blenlib/BLI_array_utils.h4
-rw-r--r--source/blender/blenlib/BLI_bitmap_draw_2d.h37
-rw-r--r--source/blender/blenlib/BLI_kdopbvh.h13
-rw-r--r--source/blender/blenlib/BLI_listbase.h1
-rw-r--r--source/blender/blenlib/BLI_math_base.h10
-rw-r--r--source/blender/blenlib/BLI_math_geom.h16
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h11
-rw-r--r--source/blender/blenlib/BLI_math_vector.h36
-rw-r--r--source/blender/blenlib/BLI_quadric.h7
-rw-r--r--source/blender/blenlib/BLI_rand.h1
-rw-r--r--source/blender/blenlib/BLI_stackdefines.h12
-rw-r--r--source/blender/blenlib/BLI_system.h5
-rw-r--r--source/blender/blenlib/BLI_task.h26
-rw-r--r--source/blender/blenlib/BLI_threads.h2
-rw-r--r--source/blender/blenlib/BLI_utildefines.h2
-rw-r--r--source/blender/blenlib/CMakeLists.txt6
-rw-r--r--source/blender/blenlib/intern/BLI_filelist.c4
-rw-r--r--source/blender/blenlib/intern/BLI_ghash.c4
-rw-r--r--source/blender/blenlib/intern/BLI_heap.c129
-rw-r--r--source/blender/blenlib/intern/BLI_kdopbvh.c418
-rw-r--r--source/blender/blenlib/intern/BLI_mempool.c42
-rw-r--r--source/blender/blenlib/intern/array_store.c1811
-rw-r--r--source/blender/blenlib/intern/array_store_utils.c103
-rw-r--r--source/blender/blenlib/intern/array_utils.c20
-rw-r--r--source/blender/blenlib/intern/astar.c2
-rw-r--r--source/blender/blenlib/intern/bitmap_draw_2d.c331
-rw-r--r--source/blender/blenlib/intern/hash_md5.c2
-rw-r--r--source/blender/blenlib/intern/listbase.c38
-rw-r--r--source/blender/blenlib/intern/math_base.c2
-rw-r--r--source/blender/blenlib/intern/math_color_inline.c6
-rw-r--r--source/blender/blenlib/intern/math_geom.c235
-rw-r--r--source/blender/blenlib/intern/math_interp.c32
-rw-r--r--source/blender/blenlib/intern/math_matrix.c32
-rw-r--r--source/blender/blenlib/intern/math_rotation.c3
-rw-r--r--source/blender/blenlib/intern/math_vector.c159
-rw-r--r--source/blender/blenlib/intern/math_vector_inline.c56
-rw-r--r--source/blender/blenlib/intern/noise.c4
-rw-r--r--source/blender/blenlib/intern/path_util.c4
-rw-r--r--source/blender/blenlib/intern/polyfill2d_beautify.c5
-rw-r--r--source/blender/blenlib/intern/quadric.c86
-rw-r--r--source/blender/blenlib/intern/rand.c40
-rw-r--r--source/blender/blenlib/intern/scanfill_utils.c2
-rw-r--r--source/blender/blenlib/intern/smallhash.c2
-rw-r--r--source/blender/blenlib/intern/storage.c2
-rw-r--r--source/blender/blenlib/intern/system.c3
-rw-r--r--source/blender/blenlib/intern/task.c235
-rw-r--r--source/blender/blenloader/BLO_readfile.h3
-rw-r--r--source/blender/blenloader/CMakeLists.txt14
-rw-r--r--source/blender/blenloader/intern/readblenentry.c9
-rw-r--r--source/blender/blenloader/intern/readfile.c782
-rw-r--r--source/blender/blenloader/intern/readfile.h10
-rw-r--r--source/blender/blenloader/intern/undofile.c16
-rw-r--r--source/blender/blenloader/intern/versioning_250.c2
-rw-r--r--source/blender/blenloader/intern/versioning_270.c306
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c11
-rw-r--r--source/blender/blenloader/intern/writefile.c3336
-rw-r--r--source/blender/blentranslation/BLT_translation.h2
-rw-r--r--source/blender/bmesh/bmesh_class.h47
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.c4
-rw-r--r--source/blender/bmesh/intern/bmesh_core.c37
-rw-r--r--source/blender/bmesh/intern/bmesh_delete.c34
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators.c37
-rw-r--r--source/blender/bmesh/intern/bmesh_log.c2
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.c4
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.c333
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.h21
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_conv.c8
-rw-r--r--source/blender/bmesh/intern/bmesh_opdefines.c3
-rw-r--r--source/blender/bmesh/intern/bmesh_operator_api.h77
-rw-r--r--source/blender/bmesh/intern/bmesh_operator_api_inline.h10
-rw-r--r--source/blender/bmesh/intern/bmesh_operators.c128
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.c466
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.h9
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon_edgenet.c221
-rw-r--r--source/blender/bmesh/intern/bmesh_private.h3
-rw-r--r--source/blender/bmesh/intern/bmesh_queries.c2
-rw-r--r--source/blender/bmesh/intern/bmesh_queries_inline.h7
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers.h1
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers_impl.c87
-rw-r--r--source/blender/bmesh/operators/bmo_beautify.c6
-rw-r--r--source/blender/bmesh/operators/bmo_bridge.c12
-rw-r--r--source/blender/bmesh/operators/bmo_connect.c28
-rw-r--r--source/blender/bmesh/operators/bmo_connect_concave.c19
-rw-r--r--source/blender/bmesh/operators/bmo_connect_nonplanar.c24
-rw-r--r--source/blender/bmesh/operators/bmo_connect_pair.c37
-rw-r--r--source/blender/bmesh/operators/bmo_create.c29
-rw-r--r--source/blender/bmesh/operators/bmo_dissolve.c96
-rw-r--r--source/blender/bmesh/operators/bmo_dupe.c52
-rw-r--r--source/blender/bmesh/operators/bmo_edgenet.c14
-rw-r--r--source/blender/bmesh/operators/bmo_extrude.c84
-rw-r--r--source/blender/bmesh/operators/bmo_fill_edgeloop.c16
-rw-r--r--source/blender/bmesh/operators/bmo_fill_grid.c4
-rw-r--r--source/blender/bmesh/operators/bmo_hull.c79
-rw-r--r--source/blender/bmesh/operators/bmo_inset.c4
-rw-r--r--source/blender/bmesh/operators/bmo_join_triangles.c12
-rw-r--r--source/blender/bmesh/operators/bmo_normals.c22
-rw-r--r--source/blender/bmesh/operators/bmo_offset_edgeloops.c10
-rw-r--r--source/blender/bmesh/operators/bmo_planar_faces.c14
-rw-r--r--source/blender/bmesh/operators/bmo_poke.c4
-rw-r--r--source/blender/bmesh/operators/bmo_primitive.c760
-rw-r--r--source/blender/bmesh/operators/bmo_removedoubles.c73
-rw-r--r--source/blender/bmesh/operators/bmo_similar.c68
-rw-r--r--source/blender/bmesh/operators/bmo_subdivide.c63
-rw-r--r--source/blender/bmesh/operators/bmo_subdivide_edgering.c59
-rw-r--r--source/blender/bmesh/operators/bmo_triangulate.c50
-rw-r--r--source/blender/bmesh/operators/bmo_utils.c80
-rw-r--r--source/blender/bmesh/tools/bmesh_beautify.c10
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c509
-rw-r--r--source/blender/bmesh/tools/bmesh_bisect_plane.c18
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_collapse.c276
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_dissolve.c2
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c4
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect.c158
-rw-r--r--source/blender/collada/ArmatureExporter.cpp54
-rw-r--r--source/blender/collada/ArmatureExporter.h2
-rw-r--r--source/blender/collada/ArmatureImporter.cpp352
-rw-r--r--source/blender/collada/ArmatureImporter.h38
-rw-r--r--source/blender/collada/DocumentImporter.cpp42
-rw-r--r--source/blender/collada/EffectExporter.cpp7
-rw-r--r--source/blender/collada/ErrorHandler.cpp2
-rw-r--r--source/blender/collada/ExportSettings.h1
-rw-r--r--source/blender/collada/ExtraTags.cpp23
-rw-r--r--source/blender/collada/ExtraTags.h11
-rw-r--r--source/blender/collada/ImportSettings.h1
-rw-r--r--source/blender/collada/MeshImporter.cpp83
-rw-r--r--source/blender/collada/MeshImporter.h2
-rw-r--r--source/blender/collada/SkinInfo.cpp1
-rw-r--r--source/blender/collada/TransformWriter.cpp1
-rw-r--r--source/blender/collada/collada.cpp8
-rw-r--r--source/blender/collada/collada.h2
-rw-r--r--source/blender/collada/collada_utils.cpp250
-rw-r--r--source/blender/collada/collada_utils.h70
-rw-r--r--source/blender/compositor/intern/COM_OpenCLDevice.h6
-rw-r--r--source/blender/compositor/intern/COM_WorkScheduler.cpp4
-rw-r--r--source/blender/compositor/nodes/COM_FilterNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_MovieClipNode.cpp2
-rw-r--r--source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp7
-rw-r--r--source/blender/compositor/operations/COM_ImageOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_MaskOperation.cpp3
-rw-r--r--source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_SunBeamsOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_TextureOperation.cpp14
-rw-r--r--source/blender/depsgraph/CMakeLists.txt57
-rw-r--r--source/blender/depsgraph/DEG_depsgraph.h12
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_build.h14
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_debug.h3
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_query.h143
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.cc129
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.h46
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cycle.cc (renamed from source/blender/depsgraph/util/depsgraph_util_cycle.cc)42
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cycle.h (renamed from source/blender/depsgraph/util/depsgraph_util_cycle.h)11
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc (renamed from source/blender/depsgraph/intern/depsgraph_build_nodes.cc)83
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.h155
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc (renamed from source/blender/depsgraph/util/depsgraph_util_pchanmap.cc)28
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h (renamed from source/blender/depsgraph/util/depsgraph_util_pchanmap.h)15
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc (renamed from source/blender/depsgraph/intern/depsgraph_build_relations.cc)252
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h (renamed from source/blender/depsgraph/intern/depsgraph_build.h)181
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_transitive.cc (renamed from source/blender/depsgraph/util/depsgraph_util_transitive.cc)58
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_transitive.h (renamed from source/blender/depsgraph/util/depsgraph_util_transitive.h)10
-rw-r--r--source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc590
-rw-r--r--source/blender/depsgraph/intern/depsgraph.cc115
-rw-r--r--source/blender/depsgraph/intern/depsgraph.h49
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc383
-rw-r--r--source/blender/depsgraph/intern/depsgraph_debug.cc1054
-rw-r--r--source/blender/depsgraph/intern/depsgraph_eval.cc391
-rw-r--r--source/blender/depsgraph/intern/depsgraph_intern.h95
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query.cc159
-rw-r--r--source/blender/depsgraph/intern/depsgraph_queue.cc177
-rw-r--r--source/blender/depsgraph/intern/depsgraph_queue.h91
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc212
-rw-r--r--source/blender/depsgraph/intern/depsgraph_type_defines.cc123
-rw-r--r--source/blender/depsgraph/intern/depsgraph_types.h257
-rw-r--r--source/blender/depsgraph/intern/depsnode_opcodes.h145
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.cc409
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.h52
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_debug.cc249
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_debug.h (renamed from source/blender/depsgraph/intern/depsgraph_debug.h)28
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.cc227
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.h49
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node.cc (renamed from source/blender/depsgraph/intern/depsnode.cc)165
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node.h (renamed from source/blender/depsgraph/intern/depsnode.h)45
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_component.cc (renamed from source/blender/depsgraph/intern/depsnode_component.cc)226
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_component.h (renamed from source/blender/depsgraph/intern/depsnode_component.h)98
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_operation.cc (renamed from source/blender/depsgraph/intern/depsnode_operation.cc)33
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_operation.h (renamed from source/blender/depsgraph/intern/depsnode_operation.h)44
-rw-r--r--source/blender/depsgraph/util/deg_util_foreach.h68
-rw-r--r--source/blender/depsgraph/util/deg_util_function.h (renamed from source/blender/depsgraph/util/depsgraph_util_function.h)8
-rw-r--r--source/blender/depsgraph/util/deg_util_hash.h (renamed from source/blender/depsgraph/util/depsgraph_util_set.h)43
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_hash.h72
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_map.h67
-rw-r--r--source/blender/editors/CMakeLists.txt4
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c273
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c34
-rw-r--r--source/blender/editors/animation/anim_deps.c8
-rw-r--r--source/blender/editors/animation/anim_draw.c15
-rw-r--r--source/blender/editors/animation/anim_filter.c352
-rw-r--r--source/blender/editors/animation/anim_ipo_utils.c2
-rw-r--r--source/blender/editors/animation/anim_markers.c10
-rw-r--r--source/blender/editors/animation/drivers.c15
-rw-r--r--source/blender/editors/animation/keyframes_draw.c203
-rw-r--r--source/blender/editors/animation/keyframes_edit.c84
-rw-r--r--source/blender/editors/animation/keyframing.c56
-rw-r--r--source/blender/editors/animation/keyingsets.c18
-rw-r--r--source/blender/editors/armature/armature_add.c40
-rw-r--r--source/blender/editors/armature/armature_edit.c6
-rw-r--r--source/blender/editors/armature/armature_intern.h6
-rw-r--r--source/blender/editors/armature/armature_ops.c1
-rw-r--r--source/blender/editors/armature/armature_utils.c44
-rw-r--r--source/blender/editors/armature/editarmature_retarget.c9
-rw-r--r--source/blender/editors/armature/editarmature_sketch.c19
-rw-r--r--source/blender/editors/armature/pose_edit.c2
-rw-r--r--source/blender/editors/armature/pose_group.c58
-rw-r--r--source/blender/editors/armature/pose_lib.c106
-rw-r--r--source/blender/editors/armature/pose_slide.c27
-rw-r--r--source/blender/editors/armature/pose_transform.c161
-rw-r--r--source/blender/editors/armature/pose_utils.c25
-rw-r--r--source/blender/editors/curve/CMakeLists.txt1
-rw-r--r--source/blender/editors/curve/editcurve.c14
-rw-r--r--source/blender/editors/curve/editcurve_paint.c97
-rw-r--r--source/blender/editors/curve/editcurve_select.c19
-rw-r--r--source/blender/editors/curve/editfont.c62
-rw-r--r--source/blender/editors/curve/editfont_undo.c311
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c599
-rw-r--r--source/blender/editors/gpencil/editaction_gpencil.c42
-rw-r--r--source/blender/editors/gpencil/gpencil_brush.c417
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c55
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c1424
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c1708
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h160
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c159
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c654
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c176
-rw-r--r--source/blender/editors/gpencil/gpencil_undo.c60
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c442
-rw-r--r--source/blender/editors/include/BIF_glutil.h1
-rw-r--r--source/blender/editors/include/ED_anim_api.h24
-rw-r--r--source/blender/editors/include/ED_armature.h5
-rw-r--r--source/blender/editors/include/ED_buttons.h2
-rw-r--r--source/blender/editors/include/ED_curve.h6
-rw-r--r--source/blender/editors/include/ED_fileselect.h5
-rw-r--r--source/blender/editors/include/ED_gpencil.h47
-rw-r--r--source/blender/editors/include/ED_keyframes_draw.h29
-rw-r--r--source/blender/editors/include/ED_keyframes_edit.h34
-rw-r--r--source/blender/editors/include/ED_keyframing.h9
-rw-r--r--source/blender/editors/include/ED_mask.h2
-rw-r--r--source/blender/editors/include/ED_node.h2
-rw-r--r--source/blender/editors/include/ED_numinput.h2
-rw-r--r--source/blender/editors/include/ED_outliner.h6
-rw-r--r--source/blender/editors/include/ED_physics.h8
-rw-r--r--source/blender/editors/include/ED_screen_types.h1
-rw-r--r--source/blender/editors/include/ED_transform.h13
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h21
-rw-r--r--source/blender/editors/include/ED_util.h5
-rw-r--r--source/blender/editors/include/ED_view3d.h14
-rw-r--r--source/blender/editors/include/UI_icons.h27
-rw-r--r--source/blender/editors/include/UI_interface.h25
-rw-r--r--source/blender/editors/include/UI_resources.h7
-rw-r--r--source/blender/editors/interface/interface.c37
-rw-r--r--source/blender/editors/interface/interface_anim.c44
-rw-r--r--source/blender/editors/interface/interface_draw.c78
-rw-r--r--source/blender/editors/interface/interface_eyedropper.c76
-rw-r--r--source/blender/editors/interface/interface_handlers.c498
-rw-r--r--source/blender/editors/interface/interface_icons.c128
-rw-r--r--source/blender/editors/interface/interface_intern.h13
-rw-r--r--source/blender/editors/interface/interface_layout.c31
-rw-r--r--source/blender/editors/interface/interface_ops.c62
-rw-r--r--source/blender/editors/interface/interface_panel.c78
-rw-r--r--source/blender/editors/interface/interface_regions.c116
-rw-r--r--source/blender/editors/interface/interface_style.c12
-rw-r--r--source/blender/editors/interface/interface_templates.c131
-rw-r--r--source/blender/editors/interface/interface_widgets.c30
-rw-r--r--source/blender/editors/interface/resources.c73
-rw-r--r--source/blender/editors/interface/view2d_ops.c9
-rw-r--r--source/blender/editors/io/CMakeLists.txt14
-rw-r--r--source/blender/editors/io/io_alembic.c528
-rw-r--r--source/blender/editors/io/io_alembic.h37
-rw-r--r--source/blender/editors/io/io_cache.c165
-rw-r--r--source/blender/editors/io/io_cache.h37
-rw-r--r--source/blender/editors/io/io_collada.c37
-rw-r--r--source/blender/editors/io/io_ops.c16
-rw-r--r--source/blender/editors/mask/mask_draw.c18
-rw-r--r--source/blender/editors/mask/mask_editaction.c30
-rw-r--r--source/blender/editors/mesh/CMakeLists.txt1
-rw-r--r--source/blender/editors/mesh/editface.c3
-rw-r--r--source/blender/editors/mesh/editmesh_add.c9
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c245
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c3
-rw-r--r--source/blender/editors/mesh/editmesh_inset.c8
-rw-r--r--source/blender/editors/mesh/editmesh_intersect.c4
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c2
-rw-r--r--source/blender/editors/mesh/editmesh_loopcut.c4
-rw-r--r--source/blender/editors/mesh/editmesh_path.c15
-rw-r--r--source/blender/editors/mesh/editmesh_rip.c17
-rw-r--r--source/blender/editors/mesh/editmesh_select.c9
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c230
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c667
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c171
-rw-r--r--source/blender/editors/mesh/mesh_data.c6
-rw-r--r--source/blender/editors/mesh/mesh_intern.h1
-rw-r--r--source/blender/editors/mesh/mesh_ops.c1
-rw-r--r--source/blender/editors/mesh/meshtools.c27
-rw-r--r--source/blender/editors/object/object_add.c111
-rw-r--r--source/blender/editors/object/object_constraint.c85
-rw-r--r--source/blender/editors/object/object_data_transfer.c6
-rw-r--r--source/blender/editors/object/object_edit.c15
-rw-r--r--source/blender/editors/object/object_group.c6
-rw-r--r--source/blender/editors/object/object_modifier.c4
-rw-r--r--source/blender/editors/object/object_ops.c18
-rw-r--r--source/blender/editors/object/object_relations.c115
-rw-r--r--source/blender/editors/object/object_select.c1
-rw-r--r--source/blender/editors/object/object_shapekey.c9
-rw-r--r--source/blender/editors/object/object_transform.c134
-rw-r--r--source/blender/editors/object/object_vgroup.c62
-rw-r--r--source/blender/editors/physics/dynamicpaint_ops.c8
-rw-r--r--source/blender/editors/physics/particle_edit.c10
-rw-r--r--source/blender/editors/physics/particle_object.c69
-rw-r--r--source/blender/editors/physics/physics_intern.h1
-rw-r--r--source/blender/editors/physics/physics_ops.c1
-rw-r--r--source/blender/editors/physics/rigidbody_constraint.c15
-rw-r--r--source/blender/editors/physics/rigidbody_object.c21
-rw-r--r--source/blender/editors/render/render_internal.c2
-rw-r--r--source/blender/editors/render/render_opengl.c377
-rw-r--r--source/blender/editors/render/render_preview.c40
-rw-r--r--source/blender/editors/render/render_shading.c74
-rw-r--r--source/blender/editors/screen/area.c16
-rw-r--r--source/blender/editors/screen/glutil.c13
-rw-r--r--source/blender/editors/screen/screen_context.c64
-rw-r--r--source/blender/editors/screen/screen_edit.c17
-rw-r--r--source/blender/editors/screen/screen_ops.c127
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c23
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c4
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c59
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h4
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c3
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c242
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c48
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c67
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c171
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c4
-rw-r--r--source/blender/editors/sound/sound_ops.c79
-rw-r--r--source/blender/editors/space_action/action_buttons.c2
-rw-r--r--source/blender/editors/space_action/action_data.c6
-rw-r--r--source/blender/editors/space_action/action_draw.c64
-rw-r--r--source/blender/editors/space_action/action_edit.c19
-rw-r--r--source/blender/editors/space_action/action_intern.h2
-rw-r--r--source/blender/editors/space_action/action_ops.c12
-rw-r--r--source/blender/editors/space_action/action_select.c277
-rw-r--r--source/blender/editors/space_action/space_action.c17
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c32
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c58
-rw-r--r--source/blender/editors/space_clip/clip_draw.c52
-rw-r--r--source/blender/editors/space_clip/clip_editor.c2
-rw-r--r--source/blender/editors/space_clip/clip_intern.h7
-rw-r--r--source/blender/editors/space_clip/clip_ops.c8
-rw-r--r--source/blender/editors/space_clip/clip_toolbar.c2
-rw-r--r--source/blender/editors/space_clip/clip_utils.c12
-rw-r--r--source/blender/editors/space_clip/space_clip.c51
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c25
-rw-r--r--source/blender/editors/space_clip/tracking_ops_stabilize.c141
-rw-r--r--source/blender/editors/space_console/space_console.c4
-rw-r--r--source/blender/editors/space_file/file_ops.c108
-rw-r--r--source/blender/editors/space_file/file_utils.c3
-rw-r--r--source/blender/editors/space_file/filelist.c67
-rw-r--r--source/blender/editors/space_file/filelist.h1
-rw-r--r--source/blender/editors/space_file/filesel.c10
-rw-r--r--source/blender/editors/space_file/fsmenu.c11
-rw-r--r--source/blender/editors/space_file/space_file.c1
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c7
-rw-r--r--source/blender/editors/space_graph/graph_draw.c22
-rw-r--r--source/blender/editors/space_graph/graph_edit.c9
-rw-r--r--source/blender/editors/space_graph/graph_ops.c9
-rw-r--r--source/blender/editors/space_graph/graph_select.c83
-rw-r--r--source/blender/editors/space_graph/space_graph.c210
-rw-r--r--source/blender/editors/space_image/image_buttons.c73
-rw-r--r--source/blender/editors/space_image/image_draw.c13
-rw-r--r--source/blender/editors/space_image/image_intern.h2
-rw-r--r--source/blender/editors/space_image/image_ops.c235
-rw-r--r--source/blender/editors/space_image/space_image.c34
-rw-r--r--source/blender/editors/space_logic/logic_buttons.c2
-rw-r--r--source/blender/editors/space_logic/logic_ops.c6
-rw-r--r--source/blender/editors/space_logic/space_logic.c23
-rw-r--r--source/blender/editors/space_nla/nla_buttons.c3
-rw-r--r--source/blender/editors/space_nla/nla_channels.c3
-rw-r--r--source/blender/editors/space_nla/nla_draw.c62
-rw-r--r--source/blender/editors/space_nla/nla_edit.c10
-rw-r--r--source/blender/editors/space_nla/nla_ops.c2
-rw-r--r--source/blender/editors/space_nla/space_nla.c17
-rw-r--r--source/blender/editors/space_node/drawnode.c2
-rw-r--r--source/blender/editors/space_node/node_add.c4
-rw-r--r--source/blender/editors/space_node/node_buttons.c2
-rw-r--r--source/blender/editors/space_node/node_draw.c6
-rw-r--r--source/blender/editors/space_node/node_edit.c28
-rw-r--r--source/blender/editors/space_node/node_group.c47
-rw-r--r--source/blender/editors/space_node/node_ops.c2
-rw-r--r--source/blender/editors/space_node/node_relationships.c23
-rw-r--r--source/blender/editors/space_node/node_templates.c24
-rw-r--r--source/blender/editors/space_node/space_node.c37
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c275
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c572
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h78
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.c4
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c8
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c322
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c36
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c37
-rw-r--r--source/blender/editors/space_sequencer/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c5
-rw-r--r--source/blender/editors/space_sequencer/sequencer_buttons.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c31
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c9
-rw-r--r--source/blender/editors/space_sequencer/sequencer_ops.c4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_scopes.c117
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c111
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c19
-rw-r--r--source/blender/editors/space_text/space_text.c18
-rw-r--r--source/blender/editors/space_text/text_autocomplete.c6
-rw-r--r--source/blender/editors/space_text/text_header.c2
-rw-r--r--source/blender/editors/space_text/text_ops.c21
-rw-r--r--source/blender/editors/space_time/space_time.c70
-rw-r--r--source/blender/editors/space_time/time_ops.c2
-rw-r--r--source/blender/editors/space_view3d/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_view3d/drawanimviz.c2
-rw-r--r--source/blender/editors/space_view3d/drawarmature.c127
-rw-r--r--source/blender/editors/space_view3d/drawmesh.c106
-rw-r--r--source/blender/editors/space_view3d/drawobject.c274
-rw-r--r--source/blender/editors/space_view3d/drawvolume.c507
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c65
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c220
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c58
-rw-r--r--source/blender/editors/space_view3d/view3d_fly.c37
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h17
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c17
-rw-r--r--source/blender/editors/space_view3d/view3d_project.c74
-rw-r--r--source/blender/editors/space_view3d/view3d_ruler.c102
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c7
-rw-r--r--source/blender/editors/space_view3d/view3d_snap.c68
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c58
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c46
-rw-r--r--source/blender/editors/transform/transform.c445
-rw-r--r--source/blender/editors/transform/transform.h18
-rw-r--r--source/blender/editors/transform/transform_constraints.c15
-rw-r--r--source/blender/editors/transform/transform_conversions.c156
-rw-r--r--source/blender/editors/transform/transform_generics.c67
-rw-r--r--source/blender/editors/transform/transform_manipulator.c61
-rw-r--r--source/blender/editors/transform/transform_ops.c7
-rw-r--r--source/blender/editors/transform/transform_orientations.c4
-rw-r--r--source/blender/editors/transform/transform_snap.c82
-rw-r--r--source/blender/editors/transform/transform_snap_object.c1823
-rw-r--r--source/blender/editors/util/ed_util.c21
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c53
-rw-r--r--source/blender/editors/uvedit/uvedit_parametrizer.c16
-rw-r--r--source/blender/editors/uvedit/uvedit_smart_stitch.c17
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c9
-rw-r--r--source/blender/freestyle/FRS_freestyle.h3
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp1
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp2
-rw-r--r--source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp22
-rw-r--r--source/blender/freestyle/intern/geometry/normal_cycle.h14
-rw-r--r--source/blender/freestyle/intern/python/BPy_FrsNoise.cpp2
-rw-r--r--source/blender/freestyle/intern/python/BPy_ViewShape.cpp14
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp2
-rw-r--r--source/blender/freestyle/intern/scene_graph/FrsMaterial.h6
-rw-r--r--source/blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.h10
-rw-r--r--source/blender/freestyle/intern/scene_graph/Rep.h18
-rw-r--r--source/blender/freestyle/intern/stroke/AdvancedPredicates1D.h4
-rw-r--r--source/blender/freestyle/intern/stroke/BasicStrokeShaders.h6
-rw-r--r--source/blender/freestyle/intern/stroke/Curve.cpp2
-rw-r--r--source/blender/freestyle/intern/stroke/Stroke.h14
-rw-r--r--source/blender/freestyle/intern/stroke/StrokeRep.cpp14
-rw-r--r--source/blender/freestyle/intern/system/PseudoNoise.cpp2
-rw-r--r--source/blender/freestyle/intern/system/PythonInterpreter.h3
-rw-r--r--source/blender/freestyle/intern/view_map/BoxGrid.cpp10
-rw-r--r--source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp2
-rw-r--r--source/blender/freestyle/intern/view_map/Functions0D.h12
-rw-r--r--source/blender/freestyle/intern/view_map/Functions1D.cpp2
-rw-r--r--source/blender/freestyle/intern/view_map/Silhouette.h21
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMap.h8
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp3
-rw-r--r--source/blender/freestyle/intern/winged_edge/Curvature.cpp32
-rw-r--r--source/blender/freestyle/intern/winged_edge/WEdge.cpp1
-rw-r--r--source/blender/freestyle/intern/winged_edge/WEdge.h13
-rw-r--r--source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp1
-rw-r--r--source/blender/gpu/CMakeLists.txt2
-rw-r--r--source/blender/gpu/GPU_basic_shader.h37
-rw-r--r--source/blender/gpu/GPU_buffers.h19
-rw-r--r--source/blender/gpu/GPU_debug.h4
-rw-r--r--source/blender/gpu/GPU_draw.h25
-rw-r--r--source/blender/gpu/GPU_extensions.h1
-rw-r--r--source/blender/gpu/GPU_material.h3
-rw-r--r--source/blender/gpu/GPU_shader.h1
-rw-r--r--source/blender/gpu/intern/gpu_basic_shader.c101
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c167
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c37
-rw-r--r--source/blender/gpu/intern/gpu_codegen.h1
-rw-r--r--source/blender/gpu/intern/gpu_compositing.c5
-rw-r--r--source/blender/gpu/intern/gpu_debug.c125
-rw-r--r--source/blender/gpu/intern/gpu_draw.c178
-rw-r--r--source/blender/gpu/intern/gpu_extensions.c17
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer.c16
-rw-r--r--source/blender/gpu/intern/gpu_init_exit.c4
-rw-r--r--source/blender/gpu/intern/gpu_material.c81
-rw-r--r--source/blender/gpu/intern/gpu_shader.c14
-rw-r--r--source/blender/gpu/intern/gpu_texture.c17
-rw-r--r--source/blender/gpu/shaders/gpu_shader_basic_frag.glsl196
-rw-r--r--source/blender/gpu/shaders/gpu_shader_basic_geom.glsl130
-rw-r--r--source/blender/gpu/shaders/gpu_shader_basic_vert.glsl12
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fire_frag.glsl17
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl10
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl8
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl5
-rw-r--r--source/blender/gpu/shaders/gpu_shader_geometry.glsl17
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl1951
-rw-r--r--source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl14
-rw-r--r--source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl4
-rw-r--r--source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl12
-rw-r--r--source/blender/gpu/shaders/gpu_shader_vertex.glsl70
-rw-r--r--source/blender/gpu/shaders/gpu_shader_vertex_world.glsl68
-rw-r--r--source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl2
-rw-r--r--source/blender/ikplugin/intern/iksolver_plugin.c31
-rw-r--r--source/blender/ikplugin/intern/iksolver_plugin.h2
-rw-r--r--source/blender/ikplugin/intern/itasc_plugin.cpp4
-rw-r--r--source/blender/ikplugin/intern/itasc_plugin.h2
-rw-r--r--source/blender/imbuf/intern/IMB_anim.h8
-rw-r--r--source/blender/imbuf/intern/anim_movie.c6
-rw-r--r--source/blender/imbuf/intern/cineon/logImageCore.c7
-rw-r--r--source/blender/imbuf/intern/colormanagement.c11
-rw-r--r--source/blender/imbuf/intern/filter.c2
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp4
-rw-r--r--source/blender/imbuf/intern/stereoimbuf.c4
-rw-r--r--source/blender/imbuf/intern/thumbs.c4
-rw-r--r--source/blender/makesdna/DNA_ID.h141
-rw-r--r--source/blender/makesdna/DNA_action_types.h53
-rw-r--r--source/blender/makesdna/DNA_anim_types.h16
-rw-r--r--source/blender/makesdna/DNA_armature_types.h14
-rw-r--r--source/blender/makesdna/DNA_brush_types.h9
-rw-r--r--source/blender/makesdna/DNA_cachefile_types.h85
-rw-r--r--source/blender/makesdna/DNA_camera_types.h9
-rw-r--r--source/blender/makesdna/DNA_cloth_types.h4
-rw-r--r--source/blender/makesdna/DNA_color_types.h6
-rw-r--r--source/blender/makesdna/DNA_constraint_types.h12
-rw-r--r--source/blender/makesdna/DNA_curve_types.h21
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h6
-rw-r--r--source/blender/makesdna/DNA_genfile.h28
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h143
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h52
-rw-r--r--source/blender/makesdna/DNA_movieclip_types.h1
-rw-r--r--source/blender/makesdna/DNA_node_types.h3
-rw-r--r--source/blender/makesdna/DNA_object_force.h2
-rw-r--r--source/blender/makesdna/DNA_object_types.h2
-rw-r--r--source/blender/makesdna/DNA_particle_types.h1
-rw-r--r--source/blender/makesdna/DNA_scene_types.h87
-rw-r--r--source/blender/makesdna/DNA_screen_types.h17
-rw-r--r--source/blender/makesdna/DNA_sdna_types.h14
-rw-r--r--source/blender/makesdna/DNA_smoke_types.h35
-rw-r--r--source/blender/makesdna/DNA_space_types.h17
-rw-r--r--source/blender/makesdna/DNA_tracking_types.h27
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h9
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h9
-rw-r--r--source/blender/makesdna/intern/CMakeLists.txt23
-rw-r--r--source/blender/makesdna/intern/dna_genfile.c403
-rw-r--r--source/blender/makesdna/intern/makesdna.c55
-rw-r--r--source/blender/makesrna/RNA_access.h14
-rw-r--r--source/blender/makesrna/RNA_enum_types.h3
-rw-r--r--source/blender/makesrna/RNA_types.h15
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt15
-rw-r--r--source/blender/makesrna/intern/makesrna.c9
-rw-r--r--source/blender/makesrna/intern/rna_ID.c69
-rw-r--r--source/blender/makesrna/intern/rna_access.c192
-rw-r--r--source/blender/makesrna/intern/rna_action.c15
-rw-r--r--source/blender/makesrna/intern/rna_animation.c31
-rw-r--r--source/blender/makesrna/intern/rna_armature.c78
-rw-r--r--source/blender/makesrna/intern/rna_brush.c8
-rw-r--r--source/blender/makesrna/intern/rna_cachefile.c192
-rw-r--r--source/blender/makesrna/intern/rna_camera.c28
-rw-r--r--source/blender/makesrna/intern/rna_cloth.c53
-rw-r--r--source/blender/makesrna/intern/rna_color.c6
-rw-r--r--source/blender/makesrna/intern/rna_constraint.c102
-rw-r--r--source/blender/makesrna/intern/rna_curve.c56
-rw-r--r--source/blender/makesrna/intern/rna_define.c8
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c15
-rw-r--r--source/blender/makesrna/intern/rna_fluidsim.c24
-rw-r--r--source/blender/makesrna/intern/rna_gpencil.c863
-rw-r--r--source/blender/makesrna/intern/rna_internal.h5
-rw-r--r--source/blender/makesrna/intern/rna_internal_types.h6
-rw-r--r--source/blender/makesrna/intern/rna_key.c2
-rw-r--r--source/blender/makesrna/intern/rna_lamp.c2
-rw-r--r--source/blender/makesrna/intern/rna_lattice.c2
-rw-r--r--source/blender/makesrna/intern/rna_linestyle.c10
-rw-r--r--source/blender/makesrna/intern/rna_main.c78
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c477
-rw-r--r--source/blender/makesrna/intern/rna_mask.c4
-rw-r--r--source/blender/makesrna/intern/rna_material.c4
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c6
-rw-r--r--source/blender/makesrna/intern/rna_meta.c2
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c161
-rw-r--r--source/blender/makesrna/intern/rna_movieclip.c2
-rw-r--r--source/blender/makesrna/intern/rna_nla.c2
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c47
-rw-r--r--source/blender/makesrna/intern/rna_object.c14
-rw-r--r--source/blender/makesrna/intern/rna_object_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_object_force.c14
-rw-r--r--source/blender/makesrna/intern/rna_particle.c30
-rw-r--r--source/blender/makesrna/intern/rna_pose.c95
-rw-r--r--source/blender/makesrna/intern/rna_scene.c497
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c130
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c56
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c3
-rw-r--r--source/blender/makesrna/intern/rna_smoke.c102
-rw-r--r--source/blender/makesrna/intern/rna_space.c74
-rw-r--r--source/blender/makesrna/intern/rna_tracking.c173
-rw-r--r--source/blender/makesrna/intern/rna_ui_api.c11
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c96
-rw-r--r--source/blender/makesrna/intern/rna_vfont.c2
-rw-r--r--source/blender/makesrna/intern/rna_wm.c20
-rw-r--r--source/blender/makesrna/intern/rna_wm_api.c26
-rw-r--r--source/blender/makesrna/intern/rna_world.c25
-rw-r--r--source/blender/modifiers/CMakeLists.txt8
-rw-r--r--source/blender/modifiers/MOD_modifiertypes.h1
-rw-r--r--source/blender/modifiers/intern/MOD_armature.c1
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.c36
-rw-r--r--source/blender/modifiers/intern/MOD_cast.c1
-rw-r--r--source/blender/modifiers/intern/MOD_cloth.c30
-rw-r--r--source/blender/modifiers/intern/MOD_collision.c17
-rw-r--r--source/blender/modifiers/intern/MOD_correctivesmooth.c52
-rw-r--r--source/blender/modifiers/intern/MOD_curve.c1
-rw-r--r--source/blender/modifiers/intern/MOD_displace.c60
-rw-r--r--source/blender/modifiers/intern/MOD_dynamicpaint.c32
-rw-r--r--source/blender/modifiers/intern/MOD_fluidsim_util.c2
-rw-r--r--source/blender/modifiers/intern/MOD_hook.c1
-rw-r--r--source/blender/modifiers/intern/MOD_lattice.c1
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache.c1
-rw-r--r--source/blender/modifiers/intern/MOD_meshdeform.c1
-rw-r--r--source/blender/modifiers/intern/MOD_meshsequencecache.c210
-rw-r--r--source/blender/modifiers/intern/MOD_normal_edit.c102
-rw-r--r--source/blender/modifiers/intern/MOD_ocean.c2
-rw-r--r--source/blender/modifiers/intern/MOD_particlesystem.c6
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c2
-rw-r--r--source/blender/modifiers/intern/MOD_shapekey.c1
-rw-r--r--source/blender/modifiers/intern/MOD_shrinkwrap.c1
-rw-r--r--source/blender/modifiers/intern/MOD_simpledeform.c1
-rw-r--r--source/blender/modifiers/intern/MOD_skin.c4
-rw-r--r--source/blender/modifiers/intern/MOD_smoke.c207
-rw-r--r--source/blender/modifiers/intern/MOD_softbody.c34
-rw-r--r--source/blender/modifiers/intern/MOD_solidify.c6
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.c3
-rw-r--r--source/blender/modifiers/intern/MOD_util.c1
-rw-r--r--source/blender/modifiers/intern/MOD_warp.c1
-rw-r--r--source/blender/modifiers/intern/MOD_wave.c1
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgmix.c2
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgproximity.c3
-rw-r--r--source/blender/modifiers/intern/MOD_wireframe.c38
-rw-r--r--source/blender/nodes/NOD_static_types.h2
-rw-r--r--source/blender/nodes/intern/node_common.c2
-rw-r--r--source/blender/nodes/shader/node_shader_tree.c282
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_attribute.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_brightness.c3
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bump.c13
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_camera.c10
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_fresnel.c6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_gamma.c3
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_geom.c11
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_lamp.c7
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_material.c59
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_normal_map.c80
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_brick.c20
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_checker.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_gradient.c8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_image.c36
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_magic.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c9
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_noise.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c9
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_wave.c10
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_texture.c19
-rw-r--r--source/blender/physics/intern/BPH_mass_spring.cpp8
-rw-r--r--source/blender/physics/intern/hair_volume.cpp4
-rw-r--r--source/blender/physics/intern/implicit_blender.c7
-rw-r--r--source/blender/python/BPY_extern.h3
-rw-r--r--source/blender/python/bmesh/bmesh_py_api.c31
-rw-r--r--source/blender/python/bmesh/bmesh_py_ops_call.c14
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.c80
-rw-r--r--source/blender/python/generic/bgl.c2
-rw-r--r--source/blender/python/generic/idprop_py_api.c144
-rw-r--r--source/blender/python/generic/py_capi_utils.c43
-rw-r--r--source/blender/python/generic/py_capi_utils.h1
-rw-r--r--source/blender/python/intern/CMakeLists.txt13
-rw-r--r--source/blender/python/intern/bpy_app.c23
-rw-r--r--source/blender/python/intern/bpy_app_alembic.c113
-rw-r--r--source/blender/python/intern/bpy_app_alembic.h38
-rw-r--r--source/blender/python/intern/bpy_app_build_options.c7
-rw-r--r--source/blender/python/intern/bpy_app_handlers.c8
-rw-r--r--source/blender/python/intern/bpy_app_translations.c2
-rw-r--r--source/blender/python/intern/bpy_driver.c80
-rw-r--r--source/blender/python/intern/bpy_driver.h3
-rw-r--r--source/blender/python/intern/bpy_interface.c8
-rw-r--r--source/blender/python/intern/bpy_intern_string.c6
-rw-r--r--source/blender/python/intern/bpy_intern_string.h2
-rw-r--r--source/blender/python/intern/bpy_library_load.c64
-rw-r--r--source/blender/python/intern/bpy_library_write.c2
-rw-r--r--source/blender/python/intern/bpy_operator.c16
-rw-r--r--source/blender/python/intern/bpy_props.c33
-rw-r--r--source/blender/python/intern/bpy_rna.c186
-rw-r--r--source/blender/python/intern/bpy_rna.h2
-rw-r--r--source/blender/python/intern/bpy_rna_anim.c2
-rw-r--r--source/blender/python/intern/bpy_rna_driver.c21
-rw-r--r--source/blender/python/intern/bpy_rna_driver.h4
-rw-r--r--source/blender/python/intern/bpy_rna_id_collection.c34
-rw-r--r--source/blender/python/intern/bpy_util.c2
-rw-r--r--source/blender/python/intern/gpu.c7
-rw-r--r--source/blender/python/mathutils/mathutils.c10
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.c12
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.h2
-rw-r--r--source/blender/python/mathutils/mathutils_Quaternion.c8
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.c790
-rw-r--r--source/blender/quicktime/apple/qtkit_import.m2
-rw-r--r--source/blender/render/extern/include/RE_pipeline.h40
-rw-r--r--source/blender/render/extern/include/RE_shader_ext.h1
-rw-r--r--source/blender/render/intern/include/pixelblending.h2
-rw-r--r--source/blender/render/intern/include/rayintersection.h5
-rw-r--r--source/blender/render/intern/include/render_result.h3
-rw-r--r--source/blender/render/intern/include/render_types.h1
-rw-r--r--source/blender/render/intern/include/rendercore.h2
-rw-r--r--source/blender/render/intern/raytrace/rayobject.cpp215
-rw-r--r--source/blender/render/intern/raytrace/rayobject_instance.cpp6
-rw-r--r--source/blender/render/intern/raytrace/rayobject_rtbuild.cpp12
-rw-r--r--source/blender/render/intern/source/bake_api.c24
-rw-r--r--source/blender/render/intern/source/convertblender.c28
-rw-r--r--source/blender/render/intern/source/envmap.c28
-rw-r--r--source/blender/render/intern/source/multires_bake.c3
-rw-r--r--source/blender/render/intern/source/occlusion.c11
-rw-r--r--source/blender/render/intern/source/pipeline.c198
-rw-r--r--source/blender/render/intern/source/pixelblending.c16
-rw-r--r--source/blender/render/intern/source/pointdensity.c13
-rw-r--r--source/blender/render/intern/source/rayshade.c14
-rw-r--r--source/blender/render/intern/source/render_result.c162
-rw-r--r--source/blender/render/intern/source/render_texture.c24
-rw-r--r--source/blender/render/intern/source/renderdatabase.c4
-rw-r--r--source/blender/render/intern/source/shadeinput.c1
-rw-r--r--source/blender/render/intern/source/sss.c14
-rw-r--r--source/blender/render/intern/source/zbuf.c9
-rw-r--r--source/blender/windowmanager/CMakeLists.txt4
-rw-r--r--source/blender/windowmanager/WM_api.h22
-rw-r--r--source/blender/windowmanager/WM_types.h2
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c12
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c49
-rw-r--r--source/blender/windowmanager/intern/wm_files.c13
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c460
-rw-r--r--source/blender/windowmanager/intern/wm_gesture.c36
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c23
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c20
-rw-r--r--source/blender/windowmanager/intern/wm_operator_props.c2
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c110
-rw-r--r--source/blender/windowmanager/intern/wm_stereo.c14
-rw-r--r--source/blender/windowmanager/intern/wm_subwindow.c144
-rw-r--r--source/blender/windowmanager/intern/wm_window.c28
-rw-r--r--source/blender/windowmanager/wm_event_types.h30
-rw-r--r--source/blender/windowmanager/wm_files.h3
-rw-r--r--source/blender/windowmanager/wm_subwindow.h2
-rw-r--r--source/blenderplayer/CMakeLists.txt17
-rw-r--r--source/blenderplayer/bad_level_call_stubs/CMakeLists.txt4
-rw-r--r--source/blenderplayer/bad_level_call_stubs/stubs.c36
-rw-r--r--source/creator/CMakeLists.txt109
-rw-r--r--source/creator/creator.c64
-rw-r--r--source/creator/creator_args.c50
-rw-r--r--source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp15
-rw-r--r--source/gameengine/Converter/BL_ArmatureObject.cpp8
-rw-r--r--source/gameengine/Converter/BL_BlenderDataConversion.cpp5
-rw-r--r--source/gameengine/Converter/BL_ShapeDeformer.cpp6
-rw-r--r--source/gameengine/Converter/KX_BlenderSceneConverter.cpp6
-rw-r--r--source/gameengine/Converter/KX_ConvertActuators.cpp3
-rw-r--r--source/gameengine/Expressions/EXP_PyObjectPlus.h18
-rw-r--r--source/gameengine/Expressions/intern/IntValue.cpp22
-rw-r--r--source/gameengine/GameLogic/SCA_PropertySensor.cpp4
-rw-r--r--source/gameengine/GameLogic/SCA_PythonController.cpp4
-rw-r--r--source/gameengine/GameLogic/SCA_PythonKeyboard.cpp26
-rw-r--r--source/gameengine/GameLogic/SCA_PythonMouse.cpp31
-rw-r--r--source/gameengine/GamePlayer/ghost/CMakeLists.txt4
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_Application.cpp25
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_Application.h6
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_ghost.cpp31
-rw-r--r--source/gameengine/Ketsji/BL_Action.cpp2
-rw-r--r--source/gameengine/Ketsji/BL_Shader.cpp156
-rw-r--r--source/gameengine/Ketsji/BL_Shader.h4
-rw-r--r--source/gameengine/Ketsji/BL_Texture.cpp9
-rw-r--r--source/gameengine/Ketsji/KX_Dome.cpp4
-rw-r--r--source/gameengine/Ketsji/KX_GameObject.cpp6
-rw-r--r--source/gameengine/Ketsji/KX_KetsjiEngine.cpp32
-rw-r--r--source/gameengine/Ketsji/KX_KetsjiEngine.h20
-rw-r--r--source/gameengine/Ketsji/KX_Light.cpp2
-rw-r--r--source/gameengine/Ketsji/KX_NavMeshObject.cpp7
-rw-r--r--source/gameengine/Ketsji/KX_PythonInit.cpp178
-rw-r--r--source/gameengine/Ketsji/KX_Scene.cpp5
-rw-r--r--source/gameengine/Ketsji/KX_Scene.h7
-rw-r--r--source/gameengine/Ketsji/KX_SoundActuator.cpp15
-rw-r--r--source/gameengine/Ketsji/KX_TrackToActuator.cpp2
-rw-r--r--source/gameengine/Ketsji/KX_VehicleWrapper.cpp8
-rw-r--r--source/gameengine/Physics/Bullet/CcdPhysicsController.h12
-rw-r--r--source/gameengine/Physics/common/PHY_ICharacter.h2
-rw-r--r--source/gameengine/Physics/common/PHY_IController.h2
-rw-r--r--source/gameengine/Physics/common/PHY_IMotionState.h2
-rw-r--r--source/gameengine/Physics/common/PHY_IPhysicsController.h2
-rw-r--r--source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h2
-rw-r--r--source/gameengine/Physics/common/PHY_IVehicle.h2
-rw-r--r--source/gameengine/Rasterizer/CMakeLists.txt2
-rw-r--r--source/gameengine/Rasterizer/RAS_IOffScreen.h84
-rw-r--r--source/gameengine/Rasterizer/RAS_IRasterizer.h16
-rw-r--r--source/gameengine/Rasterizer/RAS_ISync.h48
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt4
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp2
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp347
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.h65
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp43
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h11
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp82
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.h50
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp2
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h2
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp3
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h2
-rw-r--r--source/gameengine/VideoTexture/CMakeLists.txt13
-rw-r--r--source/gameengine/VideoTexture/Common.h3
-rw-r--r--source/gameengine/VideoTexture/DeckLink.cpp813
-rw-r--r--source/gameengine/VideoTexture/DeckLink.h86
-rw-r--r--source/gameengine/VideoTexture/Exception.cpp15
-rw-r--r--source/gameengine/VideoTexture/Exception.h18
-rw-r--r--source/gameengine/VideoTexture/FilterBase.h7
-rw-r--r--source/gameengine/VideoTexture/FilterSource.h24
-rw-r--r--source/gameengine/VideoTexture/ImageBase.cpp99
-rw-r--r--source/gameengine/VideoTexture/ImageBase.h10
-rw-r--r--source/gameengine/VideoTexture/ImageMix.cpp2
-rw-r--r--source/gameengine/VideoTexture/ImageRender.cpp200
-rw-r--r--source/gameengine/VideoTexture/ImageRender.h28
-rw-r--r--source/gameengine/VideoTexture/ImageViewport.cpp99
-rw-r--r--source/gameengine/VideoTexture/ImageViewport.h11
-rw-r--r--source/gameengine/VideoTexture/Texture.cpp7
-rw-r--r--source/gameengine/VideoTexture/VideoBase.cpp47
-rw-r--r--source/gameengine/VideoTexture/VideoBase.h2
-rw-r--r--source/gameengine/VideoTexture/VideoDeckLink.cpp1228
-rw-r--r--source/gameengine/VideoTexture/VideoDeckLink.h256
-rw-r--r--source/gameengine/VideoTexture/VideoFFmpeg.cpp4
-rw-r--r--source/gameengine/VideoTexture/blendVideoTex.cpp15
m---------source/tools0
-rw-r--r--tests/gtests/blenlib/BLI_array_store_test.cc806
-rw-r--r--tests/gtests/blenlib/BLI_array_utils_test.cc82
-rw-r--r--tests/gtests/blenlib/BLI_ghash_performance_test.cc111
-rw-r--r--tests/gtests/blenlib/CMakeLists.txt1
-rw-r--r--tests/gtests/bmesh/bmesh_core_test.cc4
-rw-r--r--tests/gtests/testing/mock_log.h162
-rwxr-xr-xtests/python/cycles_render_tests.py19
-rw-r--r--tests/python/pep8.py13
1735 files changed, 214688 insertions, 51104 deletions
diff --git a/.gitignore b/.gitignore
index 7acac981ed7..977fd9c2627 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,3 +33,9 @@ Desktop.ini
/doc/python_api/sphinx-in-tmp/
/doc/python_api/sphinx-in/
/doc/python_api/sphinx-out/
+/doc/python_api/rst/bmesh.ops.rst
+/doc/python_api/rst/in_menu.png
+/doc/python_api/rst/menu_id.png
+/doc/python_api/rst/op_prop.png
+/doc/python_api/rst/run_script.png
+/doc/python_api/rst/spacebar.png
diff --git a/.gitmodules b/.gitmodules
index 132f6cffada..0b8228e3f14 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -10,3 +10,7 @@
path = release/datafiles/locale
url = ../blender-translations.git
ignore = all
+[submodule "source/tools"]
+ path = source/tools
+ url = ../blender-dev-tools.git
+ ignore = all
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 57936fe2cf4..351768c5425 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -55,6 +55,7 @@ endif()
# this starts out unset
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/build_files/cmake/Modules")
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/build_files/cmake/platform")
# avoid having empty buildtype
set(CMAKE_BUILD_TYPE_INIT "Release")
@@ -154,6 +155,7 @@ option_defaults_init(
_init_BUILDINFO
_init_CODEC_FFMPEG
_init_CYCLES_OSL
+ _init_CYCLES_OPENSUBDIV
_init_IMAGE_OPENEXR
_init_INPUT_NDOF
_init_JACK
@@ -171,8 +173,8 @@ if(UNIX AND NOT APPLE)
# disable less important dependencies by default
set(_init_CODEC_FFMPEG OFF)
set(_init_CYCLES_OSL OFF)
+ set(_init_CYCLES_OPENSUBDIV OFF)
set(_init_IMAGE_OPENEXR OFF)
- set(_init_INPUT_NDOF OFF)
set(_init_JACK OFF)
set(_init_OPENCOLLADA OFF)
set(_init_OPENCOLORIO OFF)
@@ -220,6 +222,8 @@ if(${CMAKE_VERSION} VERSION_LESS 2.8.8)
endif()
set(BUILDINFO_OVERRIDE_DATE "" CACHE STRING "Use instead of the current date for reproducable builds (empty string disables this option)")
set(BUILDINFO_OVERRIDE_TIME "" CACHE STRING "Use instead of the current time for reproducable builds (empty string disables this option)")
+set(CPACK_OVERRIDE_PACKAGENAME "" CACHE STRING "Use instead of the standard packagename (empty string disables this option)")
+mark_as_advanced(CPACK_OVERRIDE_PACKAGENAME)
mark_as_advanced(BUILDINFO_OVERRIDE_DATE)
mark_as_advanced(BUILDINFO_OVERRIDE_TIME)
@@ -230,6 +234,11 @@ option(WITH_BULLET "Enable Bullet (Physics Engine)" ON)
option(WITH_SYSTEM_BULLET "Use the systems bullet library (currently unsupported due to missing features in upstream!)" )
mark_as_advanced(WITH_SYSTEM_BULLET)
option(WITH_GAMEENGINE "Enable Game Engine" ${_init_GAMEENGINE})
+if(APPLE)
+ set(WITH_GAMEENGINE_DECKLINK OFF)
+else()
+ option(WITH_GAMEENGINE_DECKLINK "Support BlackMagicDesign DeckLink cards in the Game Engine" ON)
+endif()
option(WITH_PLAYER "Build Player" OFF)
option(WITH_OPENCOLORIO "Enable OpenColorIO color management" ${_init_OPENCOLORIO})
@@ -274,6 +283,7 @@ endif()
if(WITH_X11)
option(WITH_X11_XINPUT "Enable X11 Xinput (tablet support and unicode input)" ON)
option(WITH_X11_XF86VMODE "Enable X11 video mode switching" ON)
+ option(WITH_X11_ALPHA "Enable X11 transparent background" ON)
endif()
if(UNIX AND NOT APPLE)
@@ -318,6 +328,10 @@ option(WITH_CODEC_AVI "Enable Blenders own AVI file support (raw/jpeg)
option(WITH_CODEC_FFMPEG "Enable FFMPeg Support (http://ffmpeg.org)" ${_init_CODEC_FFMPEG})
option(WITH_CODEC_SNDFILE "Enable libsndfile Support (http://www.mega-nerd.com/libsndfile)" OFF)
+# Alembic support
+option(WITH_ALEMBIC "Enable Alembic Support" OFF)
+option(WITH_ALEMBIC_HDF5 "Enable Legacy Alembic Support (not officially supported)" OFF)
+
if(APPLE)
option(WITH_CODEC_QUICKTIME "Enable Quicktime Support" ON)
endif()
@@ -329,9 +343,9 @@ option(WITH_OPENCOLLADA "Enable OpenCollada Support (http://www.opencollada.or
# Sound output
option(WITH_SDL "Enable SDL for sound and joystick support" ${_init_SDL})
option(WITH_OPENAL "Enable OpenAL Support (http://www.openal.org)" ON)
-option(WITH_JACK "Enable Jack Support (http://www.jackaudio.org)" ${_init_JACK})
+option(WITH_JACK "Enable JACK Support (http://www.jackaudio.org)" ${_init_JACK})
if(UNIX AND NOT APPLE)
- option(WITH_JACK_DYNLOAD "Enable runtime dynamic Jack libraries loading" OFF)
+ option(WITH_JACK_DYNLOAD "Enable runtime dynamic JACK libraries loading" OFF)
endif()
if(UNIX AND NOT APPLE)
option(WITH_SDL_DYNLOAD "Enable runtime dynamic SDL libraries loading" OFF)
@@ -388,8 +402,9 @@ option(WITH_CYCLES "Enable Cycles Render Engine" ON)
option(WITH_CYCLES_STANDALONE "Build Cycles standalone application" OFF)
option(WITH_CYCLES_STANDALONE_GUI "Build Cycles standalone with GUI" OFF)
option(WITH_CYCLES_OSL "Build Cycles with OSL support" ${_init_CYCLES_OSL})
+option(WITH_CYCLES_OPENSUBDIV "Build Cycles with OpenSubdiv support" ${_init_CYCLES_OPENSUBDIV})
option(WITH_CYCLES_CUDA_BINARIES "Build Cycles CUDA binaries" OFF)
-set(CYCLES_CUDA_BINARIES_ARCH sm_20 sm_21 sm_30 sm_35 sm_37 sm_50 sm_52 CACHE STRING "CUDA architectures to build binaries for")
+set(CYCLES_CUDA_BINARIES_ARCH sm_20 sm_21 sm_30 sm_35 sm_37 sm_50 sm_52 sm_60 sm_61 CACHE STRING "CUDA architectures to build binaries for")
mark_as_advanced(CYCLES_CUDA_BINARIES_ARCH)
unset(PLATFORM_DEFAULT)
option(WITH_CYCLES_LOGGING "Build Cycles with logging support" ON)
@@ -478,15 +493,38 @@ if(WIN32)
endif()
# Experimental support of C11 and C++11
-option(WITH_C11 "Build with C11 standard enabled, for development use only!" OFF)
+#
+# We default options to whatever default standard in the current compiler.
+if(CMAKE_COMPILER_IS_GNUCC AND (NOT "${CMAKE_C_COMPILER_VERSION}" VERSION_LESS "6.0") AND (NOT WITH_CXX11))
+ set(_c11_init ON)
+ set(_cxx11_init ON)
+else()
+ set(_c11_init OFF)
+ set(_cxx11_init OFF)
+endif()
+
+option(WITH_C11 "Build with C11 standard enabled, for development use only!" ${_c11_init})
mark_as_advanced(WITH_C11)
-option(WITH_CXX11 "Build with C++11 standard enabled, for development use only!" OFF)
+option(WITH_CXX11 "Build with C++11 standard enabled, for development use only!" ${_cxx11_init})
mark_as_advanced(WITH_CXX11)
# Dependency graph
option(WITH_LEGACY_DEPSGRAPH "Build Blender with legacy dependency graph" ON)
mark_as_advanced(WITH_LEGACY_DEPSGRAPH)
+# Use hardcoded paths or find_package to find externals
+option(WITH_WINDOWS_FIND_MODULES "Use find_package to locate libraries" OFF)
+mark_as_advanced(WITH_WINDOWS_FIND_MODULES)
+
+option(WITH_WINDOWS_CODESIGN "Use signtool to sign the final binary." OFF)
+mark_as_advanced(WITH_WINDOWS_CODESIGN)
+
+set(WINDOWS_CODESIGN_PFX CACHE FILEPATH "Path to pfx file to use for codesigning.")
+mark_as_advanced(WINDOWS_CODESIGN_PFX)
+
+set(WINDOWS_CODESIGN_PFX_PASSWORD CACHE STRING "password for pfx file used for codesigning.")
+mark_as_advanced(WINDOWS_CODESIGN_PFX_PASSWORD)
+
# avoid using again
option_defaults_clear()
@@ -519,8 +557,8 @@ if(APPLE)
if(NOT CMAKE_OSX_ARCHITECTURES)
set(CMAKE_OSX_ARCHITECTURES x86_64 CACHE STRING
- "Choose the architecture you want to build Blender for: i386, x86_64 or ppc"
- FORCE)
+ "Choose the architecture you want to build Blender for: i386, x86_64 or ppc"
+ FORCE)
endif()
if(NOT DEFINED OSX_SYSTEM)
@@ -530,15 +568,20 @@ if(APPLE)
OUTPUT_STRIP_TRAILING_WHITESPACE)
endif()
- # workaround for incorrect cmake xcode lookup for developer previews - XCODE_VERSION does not take xcode-select path into accout
- # but would always look into /Applications/Xcode.app while dev versions are named Xcode<version>-DP<preview_number>
- execute_process(COMMAND xcode-select --print-path OUTPUT_VARIABLE XCODE_CHECK OUTPUT_STRIP_TRAILING_WHITESPACE)
+ # workaround for incorrect cmake xcode lookup for developer previews - XCODE_VERSION does not
+ # take xcode-select path into account but would always look into /Applications/Xcode.app
+ # while dev versions are named Xcode<version>-DP<preview_number>
+ execute_process(
+ COMMAND xcode-select --print-path
+ OUTPUT_VARIABLE XCODE_CHECK OUTPUT_STRIP_TRAILING_WHITESPACE)
string(REPLACE "/Contents/Developer" "" XCODE_BUNDLE ${XCODE_CHECK}) # truncate to bundlepath in any case
if(${CMAKE_GENERATOR} MATCHES "Xcode")
- if(${XCODE_VERSION} VERSION_GREATER 4.2) # earlier xcode has no bundled developer dir, no sense in getting xcode path from
- string(SUBSTRING "${XCODE_CHECK}" 14 6 DP_NAME) # reduce to XCode name without dp extension
+ # earlier xcode has no bundled developer dir, no sense in getting xcode path from
+ if(${XCODE_VERSION} VERSION_GREATER 4.2)
+ # reduce to XCode name without dp extension
+ string(SUBSTRING "${XCODE_CHECK}" 14 6 DP_NAME)
if(${DP_NAME} MATCHES Xcode5)
set(XCODE_VERSION 5)
endif()
@@ -565,25 +608,42 @@ if(APPLE)
message(STATUS "Detected OS X ${OSX_SYSTEM} and Xcode ${XCODE_VERSION} at ${XCODE_BUNDLE}")
if(${XCODE_VERSION} VERSION_LESS 4.3)
- set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX${OSX_SYSTEM}.sdk CACHE PATH "" FORCE) # use guaranteed existing sdk
+ # use guaranteed existing sdk
+ set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX${OSX_SYSTEM}.sdk CACHE PATH "" FORCE)
else()
- # note: xcode-select path could be ambigous, cause /Applications/Xcode.app/Contents/Developer or /Applications/Xcode.app would be allowed
+ # note: xcode-select path could be ambigous,
+ # cause /Applications/Xcode.app/Contents/Developer or /Applications/Xcode.app would be allowed
# so i use a selfcomposed bundlepath here
set(OSX_SYSROOT_PREFIX ${XCODE_BUNDLE}/Contents/Developer/Platforms/MacOSX.platform)
message(STATUS "OSX_SYSROOT_PREFIX: " ${OSX_SYSROOT_PREFIX})
set(OSX_DEVELOPER_PREFIX /Developer/SDKs/MacOSX${OSX_SYSTEM}.sdk) # use guaranteed existing sdk
set(CMAKE_OSX_SYSROOT ${OSX_SYSROOT_PREFIX}/${OSX_DEVELOPER_PREFIX} CACHE PATH "" FORCE)
if(${CMAKE_GENERATOR} MATCHES "Xcode")
- set(CMAKE_XCODE_ATTRIBUTE_SDKROOT macosx${OSX_SYSTEM}) # to silence sdk not found warning, just overrides CMAKE_OSX_SYSROOT
+ # to silence sdk not found warning, just overrides CMAKE_OSX_SYSROOT
+ set(CMAKE_XCODE_ATTRIBUTE_SDKROOT macosx${OSX_SYSTEM})
endif()
endif()
if(OSX_SYSTEM MATCHES 10.9)
- set(CMAKE_FIND_ROOT_PATH ${CMAKE_OSX_SYSROOT}) # make sure syslibs and headers are looked up in sdk ( expecially for 10.9 openGL atm. )
+ # make sure syslibs and headers are looked up in sdk ( expecially for 10.9 openGL atm. )
+ set(CMAKE_FIND_ROOT_PATH ${CMAKE_OSX_SYSROOT})
endif()
- if(NOT CMAKE_OSX_DEPLOYMENT_TARGET)
- set(CMAKE_OSX_DEPLOYMENT_TARGET "10.6" CACHE STRING "" FORCE) # 10.6 is our min. target, if you use higher sdk, weak linking happens
+ if(WITH_CXX11)
+ # 10.9 is our min. target, if you use higher sdk, weak linking happens
+ if(CMAKE_OSX_DEPLOYMENT_TARGET)
+ if(${CMAKE_OSX_DEPLOYMENT_TARGET} VERSION_LESS 10.9)
+ message(STATUS "Setting deployment target to 10.9, lower versions are incompatible with WITH_CXX11")
+ set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9" CACHE STRING "" FORCE)
+ endif()
+ else()
+ set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9" CACHE STRING "" FORCE)
+ endif()
+ else()
+ if(NOT CMAKE_OSX_DEPLOYMENT_TARGET)
+ # 10.6 is our min. target, if you use higher sdk, weak linking happens
+ set(CMAKE_OSX_DEPLOYMENT_TARGET "10.6" CACHE STRING "" FORCE)
+ endif()
endif()
if(NOT ${CMAKE_GENERATOR} MATCHES "Xcode")
@@ -592,8 +652,6 @@ if(APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}")
add_definitions("-DMACOSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}")
endif()
-
- option(WITH_LIBS10.5 "Use 10.5 libs (needed for 64bit builds)" OFF)
endif()
@@ -601,7 +659,10 @@ endif()
# Check for conflicting/unsupported configurations
if(NOT WITH_BLENDER AND NOT WITH_PLAYER AND NOT WITH_CYCLES_STANDALONE)
- message(FATAL_ERROR "At least one of WITH_BLENDER or WITH_PLAYER or WITH_CYCLES_STANDALONE must be enabled, nothing to do!")
+ message(FATAL_ERROR
+ "At least one of WITH_BLENDER or WITH_PLAYER or "
+ "WITH_CYCLES_STANDALONE must be enabled, nothing to do!"
+ )
endif()
if(NOT WITH_GAMEENGINE AND WITH_PLAYER)
@@ -665,7 +726,8 @@ if(NOT WITH_BOOST)
set_and_warn(WITH_OPENAL OFF) # depends on AUDASPACE
set_and_warn(WITH_GAMEENGINE OFF) # depends on AUDASPACE
set_and_warn(WITH_PLAYER OFF) # depends on GAMEENGINE
-elseif(WITH_CYCLES OR WITH_OPENIMAGEIO OR WITH_AUDASPACE OR WITH_INTERNATIONAL OR WITH_OPENVDB OR WITH_OPENCOLORIO OR WITH_MOD_BOOLEAN)
+elseif(WITH_CYCLES OR WITH_OPENIMAGEIO OR WITH_AUDASPACE OR WITH_INTERNATIONAL OR
+ WITH_OPENVDB OR WITH_OPENCOLORIO OR WITH_MOD_BOOLEAN)
# Keep enabled
else()
# New dependency graph needs either Boost or C++11 for function bindings.
@@ -693,6 +755,11 @@ if(WITH_OPENIMAGEIO)
set(WITH_IMAGE_TIFF ON)
endif()
+# auto enable alembic linking dependencies
+if(WITH_ALEMBIC)
+ set(WITH_IMAGE_OPENEXR ON)
+endif()
+
# don't store paths to libs for portable distribution
if(WITH_INSTALL_PORTABLE)
set(CMAKE_SKIP_BUILD_RPATH TRUE)
@@ -702,6 +769,7 @@ if(WITH_GHOST_SDL OR WITH_HEADLESS)
set(WITH_X11 OFF)
set(WITH_X11_XINPUT OFF)
set(WITH_X11_XF86VMODE OFF)
+ set(WITH_X11_ALPHA OFF)
set(WITH_GHOST_XDND OFF)
set(WITH_INPUT_IME OFF)
endif()
@@ -762,18 +830,22 @@ endif()
if(WITH_INTERNATIONAL)
if(NOT EXISTS "${CMAKE_SOURCE_DIR}/release/datafiles/locale/languages")
- message(WARNING "Translation path '${CMAKE_SOURCE_DIR}/release/datafiles/locale' is missing, "
- "This is a 'git submodule', which are known not to work with bridges to other version "
- "control systems, disabling 'WITH_INTERNATIONAL'.")
+ message(WARNING
+ "Translation path '${CMAKE_SOURCE_DIR}/release/datafiles/locale' is missing, "
+ "This is a 'git submodule', which are known not to work with bridges to other version "
+ "control systems, disabling 'WITH_INTERNATIONAL'."
+ )
set(WITH_INTERNATIONAL OFF)
endif()
endif()
if(WITH_PYTHON)
if(NOT EXISTS "${CMAKE_SOURCE_DIR}/release/scripts/addons/modules")
- message(WARNING "Addons path '${CMAKE_SOURCE_DIR}/release/scripts/addons' is missing, "
- "This is a 'git submodule', which are known not to work with bridges to other version "
- "control systems: * CONTINUING WITHOUT ADDONS *")
+ message(WARNING
+ "Addons path '${CMAKE_SOURCE_DIR}/release/scripts/addons' is missing, "
+ "This is a 'git submodule', which are known not to work with bridges to other version "
+ "control systems: * CONTINUING WITHOUT ADDONS *"
+ )
endif()
endif()
@@ -807,21 +879,6 @@ set(PLATFORM_LINKFLAGS "")
set(PLATFORM_LINKFLAGS_DEBUG "")
-# For alternate Python locations the commandline can be used to override detected/default cache settings, e.g:
-# On Unix:
-# cmake ../blender \
-# -D PYTHON_VERSION=3.5 \
-# -D PYTHON_INCLUDE_DIR=/opt/py35/include/python3.5d \
-# -D PYTHON_LIBRARY=/opt/py35/lib/libpython3.5d.so
-#
-# On Macs:
-# cmake ../blender \
-# -D PYTHON_INCLUDE_DIR=/System/Library/Frameworks/Python.framework/Versions/3.5/include/python3.5 \
-# -D PYTHON_LIBPATH=/System/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/config \
-# -G Xcode
-#
-# When changing any of this remember to update the notes in doc/build_systems/cmake.txt
-
#-----------------------------------------------------------------------------
#Platform specifics
@@ -852,6 +909,16 @@ if(WITH_X11)
endif()
endif()
+ if(WITH_X11_ALPHA)
+ find_library(X11_Xrender_LIB Xrender ${X11_LIB_SEARCH_PATH})
+ mark_as_advanced(X11_Xrender_LIB)
+ if (X11_Xrender_LIB)
+ list(APPEND PLATFORM_LINKLIBS ${X11_Xrender_LIB})
+ else()
+ set(WITH_X11_ALPHA OFF)
+ endif()
+ endif()
+
endif()
@@ -863,1472 +930,11 @@ endif()
# - APPLE
if(UNIX AND NOT APPLE)
- macro(find_package_wrapper)
- if(WITH_STATIC_LIBS)
- find_package_static(${ARGV})
- else()
- find_package(${ARGV})
- endif()
- endmacro()
-
- find_package_wrapper(JPEG REQUIRED)
- find_package_wrapper(PNG REQUIRED)
- find_package_wrapper(ZLIB REQUIRED)
- find_package_wrapper(Freetype REQUIRED)
-
- if(WITH_LZO AND WITH_SYSTEM_LZO)
- find_package_wrapper(LZO)
- if(NOT LZO_FOUND)
- message(FATAL_ERROR "Failed finding system LZO version!")
- endif()
- endif()
-
- if(WITH_SYSTEM_EIGEN3)
- find_package_wrapper(Eigen3)
- if(NOT EIGEN3_FOUND)
- message(FATAL_ERROR "Failed finding system Eigen3 version!")
- endif()
- endif()
- # else values are set below for all platforms
-
- if(WITH_PYTHON)
- # No way to set py35, remove for now.
- # find_package(PythonLibs)
-
- # Use our own instead, since without py is such a rare case,
- # require this package
- # XXX Linking errors with debian static python :/
-# find_package_wrapper(PythonLibsUnix REQUIRED)
- find_package(PythonLibsUnix REQUIRED)
- endif()
-
- if(WITH_IMAGE_OPENEXR)
- find_package_wrapper(OpenEXR) # our own module
- if(NOT OPENEXR_FOUND)
- set(WITH_IMAGE_OPENEXR OFF)
- endif()
- endif()
-
- if(WITH_IMAGE_OPENJPEG)
- find_package_wrapper(OpenJPEG)
- if(NOT OPENJPEG_FOUND)
- set(WITH_IMAGE_OPENJPEG OFF)
- endif()
- endif()
-
- if(WITH_IMAGE_TIFF)
- # XXX Linking errors with debian static tiff :/
-# find_package_wrapper(TIFF)
- find_package(TIFF)
- if(NOT TIFF_FOUND)
- set(WITH_IMAGE_TIFF OFF)
- endif()
- endif()
-
- # Audio IO
- if(WITH_SYSTEM_AUDASPACE)
- find_package_wrapper(Audaspace)
- if(NOT AUDASPACE_FOUND OR NOT AUDASPACE_C_FOUND)
- message(FATAL_ERROR "Audaspace external library not found!")
- endif()
- endif()
-
- if(WITH_OPENAL)
- find_package_wrapper(OpenAL)
- if(NOT OPENAL_FOUND)
- set(WITH_OPENAL OFF)
- endif()
- endif()
-
- if(WITH_SDL)
- if(WITH_SDL_DYNLOAD)
- set(SDL_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/extern/sdlew/include/SDL2")
- set(SDL_LIBRARY)
- else()
- find_package_wrapper(SDL2)
- if(SDL2_FOUND)
- # Use same names for both versions of SDL until we move to 2.x.
- set(SDL_INCLUDE_DIR "${SDL2_INCLUDE_DIR}")
- set(SDL_LIBRARY "${SDL2_LIBRARY}")
- set(SDL_FOUND "${SDL2_FOUND}")
- else()
- find_package_wrapper(SDL)
- endif()
- mark_as_advanced(
- SDL_INCLUDE_DIR
- SDL_LIBRARY
- )
- # unset(SDLMAIN_LIBRARY CACHE)
- if(NOT SDL_FOUND)
- set(WITH_SDL OFF)
- endif()
- endif()
- endif()
-
- if(WITH_JACK)
- find_package_wrapper(Jack)
- if(NOT JACK_FOUND)
- set(WITH_JACK OFF)
- endif()
- endif()
-
- # Codecs
- if(WITH_CODEC_SNDFILE)
- find_package_wrapper(SndFile)
- if(NOT SNDFILE_FOUND)
- set(WITH_CODEC_SNDFILE OFF)
- endif()
- endif()
-
- if(WITH_CODEC_FFMPEG)
- set(FFMPEG /usr CACHE PATH "FFMPEG Directory")
- set(FFMPEG_LIBRARIES avformat avcodec avutil avdevice swscale CACHE STRING "FFMPEG Libraries")
-
- mark_as_advanced(FFMPEG)
-
- # lame, but until we have proper find module for ffmpeg
- set(FFMPEG_INCLUDE_DIRS ${FFMPEG}/include)
- if(EXISTS "${FFMPEG}/include/ffmpeg/")
- list(APPEND FFMPEG_INCLUDE_DIRS "${FFMPEG}/include/ffmpeg")
- endif()
- # end lameness
-
- mark_as_advanced(FFMPEG_LIBRARIES)
- set(FFMPEG_LIBPATH ${FFMPEG}/lib)
- endif()
-
- if(WITH_FFTW3)
- find_package_wrapper(Fftw3)
- if(NOT FFTW3_FOUND)
- set(WITH_FFTW3 OFF)
- endif()
- endif()
-
- if(WITH_OPENCOLLADA)
- find_package_wrapper(OpenCOLLADA)
- if(OPENCOLLADA_FOUND)
- find_package_wrapper(XML2)
- find_package_wrapper(PCRE)
- else()
- set(WITH_OPENCOLLADA OFF)
- endif()
- endif()
-
- if(WITH_MEM_JEMALLOC)
- find_package_wrapper(JeMalloc)
- if(NOT JEMALLOC_FOUND)
- set(WITH_MEM_JEMALLOC OFF)
- endif()
- endif()
-
- if(WITH_INPUT_NDOF)
- find_package_wrapper(Spacenav)
- if(NOT SPACENAV_FOUND)
- set(WITH_INPUT_NDOF OFF)
- endif()
-
- # use generic names within blenders buildsystem.
- if(SPACENAV_FOUND)
- set(NDOF_INCLUDE_DIRS ${SPACENAV_INCLUDE_DIRS})
- set(NDOF_LIBRARIES ${SPACENAV_LIBRARIES})
- endif()
- endif()
-
- if(WITH_CYCLES_OSL)
- set(CYCLES_OSL ${LIBDIR}/osl CACHE PATH "Path to OpenShadingLanguage installation")
- if(NOT OSL_ROOT)
- set(OSL_ROOT ${CYCLES_OSL})
- endif()
- find_package_wrapper(OpenShadingLanguage)
- if(OSL_FOUND)
- if(${OSL_LIBRARY_VERSION_MAJOR} EQUAL "1" AND ${OSL_LIBRARY_VERSION_MINOR} LESS "6")
- # Note: --whole-archive is needed to force loading of all symbols in liboslexec,
- # otherwise LLVM is missing the osl_allocate_closure_component function
- set(OSL_LIBRARIES ${OSL_OSLCOMP_LIBRARY} -Wl,--whole-archive ${OSL_OSLEXEC_LIBRARY} -Wl,--no-whole-archive ${OSL_OSLQUERY_LIBRARY})
- endif()
- else()
- message(STATUS "OSL not found, disabling it from Cycles")
- set(WITH_CYCLES_OSL OFF)
- endif()
- endif()
-
- if(WITH_OPENVDB)
- find_package_wrapper(OpenVDB)
- find_package_wrapper(TBB)
- if(NOT OPENVDB_FOUND OR NOT TBB_FOUND)
- set(WITH_OPENVDB OFF)
- set(WITH_OPENVDB_BLOSC OFF)
- message(STATUS "OpenVDB not found, disabling it")
- endif()
- endif()
-
- if(WITH_BOOST)
- # uses in build instructions to override include and library variables
- if(NOT BOOST_CUSTOM)
- if(WITH_STATIC_LIBS)
- set(Boost_USE_STATIC_LIBS ON)
- endif()
- set(Boost_USE_MULTITHREADED ON)
- set(__boost_packages filesystem regex system thread date_time)
- if(WITH_CYCLES_OSL)
- if(NOT (${OSL_LIBRARY_VERSION_MAJOR} EQUAL "1" AND ${OSL_LIBRARY_VERSION_MINOR} LESS "6"))
- list(APPEND __boost_packages wave)
- else()
- endif()
- endif()
- if(WITH_INTERNATIONAL)
- list(APPEND __boost_packages locale)
- endif()
- if(WITH_CYCLES_NETWORK)
- list(APPEND __boost_packages serialization)
- endif()
- if(WITH_OPENVDB)
- list(APPEND __boost_packages iostreams)
- endif()
- find_package(Boost 1.48 COMPONENTS ${__boost_packages})
- if(NOT Boost_FOUND)
- # try to find non-multithreaded if -mt not found, this flag
- # doesn't matter for us, it has nothing to do with thread
- # safety, but keep it to not disturb build setups
- set(Boost_USE_MULTITHREADED OFF)
- find_package(Boost 1.48 COMPONENTS ${__boost_packages})
- endif()
- unset(__boost_packages)
- if(Boost_USE_STATIC_LIBS AND WITH_BOOST_ICU)
- find_package(IcuLinux)
- endif()
- mark_as_advanced(Boost_DIR) # why doesnt boost do this?
- endif()
-
- set(BOOST_INCLUDE_DIR ${Boost_INCLUDE_DIRS})
- set(BOOST_LIBRARIES ${Boost_LIBRARIES})
- set(BOOST_LIBPATH ${Boost_LIBRARY_DIRS})
- set(BOOST_DEFINITIONS "-DBOOST_ALL_NO_LIB")
- endif()
-
- if(WITH_OPENIMAGEIO)
- find_package_wrapper(OpenImageIO)
- if(NOT OPENIMAGEIO_PUGIXML_FOUND AND WITH_CYCLES_STANDALONE)
- find_package_wrapper(PugiXML)
- else()
- set(PUGIXML_INCLUDE_DIR "${OPENIMAGEIO_INCLUDE_DIR/OpenImageIO}")
- set(PUGIXML_LIBRARIES "")
- endif()
-
- set(OPENIMAGEIO_LIBRARIES ${OPENIMAGEIO_LIBRARIES} ${PNG_LIBRARIES} ${JPEG_LIBRARIES} ${ZLIB_LIBRARIES} ${BOOST_LIBRARIES})
- set(OPENIMAGEIO_LIBPATH) # TODO, remove and reference the absolute path everywhere
- set(OPENIMAGEIO_DEFINITIONS "")
-
- if(WITH_IMAGE_TIFF)
- list(APPEND OPENIMAGEIO_LIBRARIES "${TIFF_LIBRARY}")
- endif()
- if(WITH_IMAGE_OPENEXR)
- list(APPEND OPENIMAGEIO_LIBRARIES "${OPENEXR_LIBRARIES}")
- endif()
-
- if(NOT OPENIMAGEIO_FOUND)
- set(WITH_OPENIMAGEIO OFF)
- message(STATUS "OpenImageIO not found, disabling WITH_CYCLES")
- endif()
- endif()
-
- if(WITH_OPENCOLORIO)
- find_package_wrapper(OpenColorIO)
-
- set(OPENCOLORIO_LIBRARIES ${OPENCOLORIO_LIBRARIES})
- set(OPENCOLORIO_LIBPATH) # TODO, remove and reference the absolute path everywhere
- set(OPENCOLORIO_DEFINITIONS)
-
- if(NOT OPENCOLORIO_FOUND)
- set(WITH_OPENCOLORIO OFF)
- message(STATUS "OpenColorIO not found")
- endif()
- endif()
-
- if(WITH_LLVM)
- find_package_wrapper(LLVM)
-
- if(NOT LLVM_FOUND)
- set(WITH_LLVM OFF)
- message(STATUS "LLVM not found")
- endif()
- endif()
-
- if(WITH_LLVM OR WITH_SDL_DYNLOAD)
- # Fix for conflict with Mesa llvmpipe
- set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -Wl,--version-script='${CMAKE_SOURCE_DIR}/source/creator/blender.map'")
- endif()
-
- if(WITH_OPENSUBDIV)
- find_package_wrapper(OpenSubdiv)
-
- set(OPENSUBDIV_LIBRARIES ${OPENSUBDIV_LIBRARIES})
- set(OPENSUBDIV_LIBPATH) # TODO, remove and reference the absolute path everywhere
-
- if(NOT OPENSUBDIV_FOUND)
- set(WITH_OPENSUBDIV OFF)
- message(STATUS "OpenSubdiv not found")
- endif()
- endif()
-
- # OpenSuse needs lutil, ArchLinux not, for now keep, can avoid by using --as-needed
- list(APPEND PLATFORM_LINKLIBS -lutil -lc -lm)
-
- find_package(Threads REQUIRED)
- list(APPEND PLATFORM_LINKLIBS ${CMAKE_THREAD_LIBS_INIT})
- # used by other platforms
- set(PTHREADS_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
-
- if(CMAKE_DL_LIBS)
- list(APPEND PLATFORM_LINKLIBS ${CMAKE_DL_LIBS})
- endif()
-
- if(CMAKE_SYSTEM_NAME MATCHES "Linux")
- if(NOT WITH_PYTHON_MODULE)
- # binreloc is linux only
- set(BINRELOC_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/extern/binreloc/include)
- set(WITH_BINRELOC ON)
- endif()
- endif()
-
- # lfs on glibc, all compilers should use
- add_definitions(-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE)
-
- # GNU Compiler
- if(CMAKE_COMPILER_IS_GNUCC)
- set(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing")
-
- # use ld.gold linker if available, could make optional
- execute_process(
- COMMAND ${CMAKE_C_COMPILER} -fuse-ld=gold -Wl,--version
- ERROR_QUIET OUTPUT_VARIABLE LD_VERSION)
- if("${LD_VERSION}" MATCHES "GNU gold")
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fuse-ld=gold")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-ld=gold")
- else()
- message(STATUS "GNU gold linker isn't available, using the default system linker.")
- endif()
- unset(LD_VERSION)
-
- # CLang is the same as GCC for now.
- elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")
- set(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing")
- # Solaris CC
- elseif(CMAKE_C_COMPILER_ID MATCHES "SunPro")
- set(PLATFORM_CFLAGS "-pipe -features=extensions -fPIC -D__FUNCTION__=__func__")
-
- # Intel C++ Compiler
- elseif(CMAKE_C_COMPILER_ID MATCHES "Intel")
- # think these next two are broken
- find_program(XIAR xiar)
- if(XIAR)
- set(CMAKE_AR "${XIAR}")
- endif()
- mark_as_advanced(XIAR)
-
- find_program(XILD xild)
- if(XILD)
- set(CMAKE_LINKER "${XILD}")
- endif()
- mark_as_advanced(XILD)
-
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fp-model precise -prec_div -parallel")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fp-model precise -prec_div -parallel")
-
- # set(PLATFORM_CFLAGS "${PLATFORM_CFLAGS} -diag-enable sc3")
- set(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing")
- set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -static-intel")
- endif()
-
+ include(platform_unix)
elseif(WIN32)
-
- add_definitions(-DWIN32)
-
- if(MSVC)
- # Minimum MSVC Version
- set(_min_ver "18.0.31101")
- if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${_min_ver})
- message(FATAL_ERROR
- "Visual Studio 2013 (Update 4, ${_min_ver}) required, "
- "found (${CMAKE_CXX_COMPILER_VERSION})")
- endif()
- unset(_min_ver)
-
- # needed for some MSVC installations
- set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO")
- set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SAFESEH:NO")
- set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /SAFESEH:NO")
-
- list(APPEND PLATFORM_LINKLIBS ws2_32 vfw32 winmm kernel32 user32 gdi32 comdlg32 advapi32 shfolder shell32 ole32 oleaut32 uuid psapi Dbghelp)
-
- if(WITH_INPUT_IME)
- list(APPEND PLATFORM_LINKLIBS imm32)
- endif()
-
- add_definitions(
- -D_CRT_NONSTDC_NO_DEPRECATE
- -D_CRT_SECURE_NO_DEPRECATE
- -D_SCL_SECURE_NO_DEPRECATE
- -D_CONSOLE
- -D_LIB
- )
-
- # MSVC11 needs _ALLOW_KEYWORD_MACROS to build
- add_definitions(-D_ALLOW_KEYWORD_MACROS)
-
- if(CMAKE_CL_64)
- # We want to support Vista level ABI for x64
- add_definitions(-D_WIN32_WINNT=0x600)
- endif()
-
- # Make cmake find the msvc redistributables
- set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP TRUE)
- include(InstallRequiredSystemLibraries)
-
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /nologo /J /Gd /MP /EHsc")
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /nologo /J /Gd /MP")
-
- set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
- set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd")
- set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
- set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT")
- set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} /MT")
- set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} /MT")
- set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /MT")
- set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} /MT")
-
- set(PLATFORM_LINKFLAGS "/SUBSYSTEM:CONSOLE /STACK:2097152 /INCREMENTAL:NO /NODEFAULTLIB:msvcrt.lib /NODEFAULTLIB:msvcmrt.lib /NODEFAULTLIB:msvcurt.lib /NODEFAULTLIB:msvcrtd.lib")
-
- # Ignore meaningless for us linker warnings.
- set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} /ignore:4049 /ignore:4217 /ignore:4221")
- set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4221")
-
- # MSVC only, Mingw doesnt need
- if(CMAKE_CL_64)
- set(PLATFORM_LINKFLAGS "/MACHINE:X64 /OPT:NOREF ${PLATFORM_LINKFLAGS}")
- else()
- set(PLATFORM_LINKFLAGS "/MACHINE:IX86 /LARGEADDRESSAWARE ${PLATFORM_LINKFLAGS}")
- endif()
-
- set(PLATFORM_LINKFLAGS_DEBUG "/IGNORE:4099 /NODEFAULTLIB:libcmt.lib /NODEFAULTLIB:libc.lib")
-
- # Use dynamic loading for OpenMP
- if(WITH_OPENMP)
- if(MSVC_VERSION EQUAL 1800)
- set(OPENMP_DLL_NAME "vcomp120")
- else()
- set(OPENMP_DLL_NAME "vcomp140")
- endif()
- set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} /DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib")
- set(PLATFORM_LINKFLAGS_DEBUG "${PLATFORM_LINKFLAGS_DEBUG} /DELAYLOAD:${OPENMP_DLL_NAME}d.dll delayimp.lib")
- endif()
-
- if(NOT DEFINED LIBDIR)
-
- # Setup 64bit and 64bit windows systems
- if(CMAKE_CL_64)
- message(STATUS "64 bit compiler detected.")
- set(LIBDIR_BASE "win64")
- else()
- message(STATUS "32 bit compiler detected.")
- set(LIBDIR_BASE "windows")
- endif()
-
- if(MSVC_VERSION EQUAL 1900)
- message(STATUS "Visual Studio 2015 detected.")
- set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc14)
- else()
- message(STATUS "Visual Studio 2013 detected.")
- set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc12)
- endif()
- else()
- message(STATUS "Using pre-compiled LIBDIR: ${LIBDIR}")
- endif()
- if(NOT EXISTS "${LIBDIR}/")
- message(FATAL_ERROR "Windows requires pre-compiled libs at: '${LIBDIR}'")
- endif()
-
- # Add each of our libraries to our cmake_prefix_path so find_package() could work
- file(GLOB children RELATIVE ${LIBDIR} ${LIBDIR}/*)
- foreach(child ${children})
- if(IS_DIRECTORY ${LIBDIR}/${child})
- list(APPEND CMAKE_PREFIX_PATH ${LIBDIR}/${child})
- endif()
- endforeach()
-
- set(ZLIB_INCLUDE_DIRS ${LIBDIR}/zlib/include)
- set(ZLIB_LIBRARIES ${LIBDIR}/zlib/lib/libz_st.lib)
- set(ZLIB_INCLUDE_DIR ${LIBDIR}/zlib/include)
- set(ZLIB_LIBRARY ${LIBDIR}/zlib/lib/libz_st.lib)
- set(ZLIB_DIR ${LIBDIR}/zlib)
- #find_package(zlib) # we want to find before finding things that depend on it like png
-
-
- find_package(png)
- if(NOT PNG_FOUND)
- message(WARNING "Using HARDCODED libpng locations")
- set(PNG_PNG_INCLUDE_DIR ${LIBDIR}/png/include)
- set(PNG_LIBRARIES libpng)
- set(PNG "${LIBDIR}/png")
- set(PNG_INCLUDE_DIRS "${PNG}/include")
- set(PNG_LIBPATH ${PNG}/lib) # not cmake defined
- endif()
-
- set(JPEG_NAMES ${JPEG_NAMES} libjpeg)
- find_package(jpeg REQUIRED)
-
- set(PTHREADS_INCLUDE_DIRS ${LIBDIR}/pthreads/include)
- set(PTHREADS_LIBRARIES ${LIBDIR}/pthreads/lib/pthreadVC2.lib)
-
- set(FREETYPE ${LIBDIR}/freetype)
- set(FREETYPE_INCLUDE_DIRS
- ${LIBDIR}/freetype/include
- ${LIBDIR}/freetype/include/freetype2
- )
- set(FREETYPE_LIBRARY ${LIBDIR}/freetype/lib/freetype2ST.lib)
- find_package(freetype REQUIRED)
-
- if(WITH_FFTW3)
- set(FFTW3 ${LIBDIR}/fftw3)
- set(FFTW3_LIBRARIES libfftw)
- set(FFTW3_INCLUDE_DIRS ${FFTW3}/include)
- set(FFTW3_LIBPATH ${FFTW3}/lib)
- endif()
-
- if(WITH_OPENCOLLADA)
- set(OPENCOLLADA ${LIBDIR}/opencollada)
-
- set(OPENCOLLADA_INCLUDE_DIRS
- ${OPENCOLLADA}/include/opencollada/COLLADAStreamWriter
- ${OPENCOLLADA}/include/opencollada/COLLADABaseUtils
- ${OPENCOLLADA}/include/opencollada/COLLADAFramework
- ${OPENCOLLADA}/include/opencollada/COLLADASaxFrameworkLoader
- ${OPENCOLLADA}/include/opencollada/GeneratedSaxParser
- )
-
- set(OPENCOLLADA_LIBRARIES
- ${OPENCOLLADA}/lib/opencollada/OpenCOLLADASaxFrameworkLoader.lib
- ${OPENCOLLADA}/lib/opencollada/OpenCOLLADAFramework.lib
- ${OPENCOLLADA}/lib/opencollada/OpenCOLLADABaseUtils.lib
- ${OPENCOLLADA}/lib/opencollada/OpenCOLLADAStreamWriter.lib
- ${OPENCOLLADA}/lib/opencollada/MathMLSolver.lib
- ${OPENCOLLADA}/lib/opencollada/GeneratedSaxParser.lib
- ${OPENCOLLADA}/lib/opencollada/xml.lib
- ${OPENCOLLADA}/lib/opencollada/buffer.lib
- ${OPENCOLLADA}/lib/opencollada/ftoa.lib
- )
-
- if(NOT WITH_LLVM)
- list(APPEND OPENCOLLADA_LIBRARIES ${OPENCOLLADA}/lib/opencollada/UTF.lib)
- endif()
-
- set(PCRE_LIBRARIES
- ${OPENCOLLADA}/lib/opencollada/pcre.lib
- )
- endif()
-
- if(WITH_CODEC_FFMPEG)
- set(FFMPEG_INCLUDE_DIRS
- ${LIBDIR}/ffmpeg/include
- ${LIBDIR}/ffmpeg/include/msvc
- )
- find_package(FFMPEG)
- if(NOT FFMPEG_FOUND)
- message(WARNING "Using HARDCODED ffmpeg locations")
- set(FFMPEG_LIBRARY_VERSION 55)
- set(FFMPEG_LIBRARY_VERSION_AVU 52)
- set(FFMPEG_LIBRARIES
- ${LIBDIR}/ffmpeg/lib/avcodec-${FFMPEG_LIBRARY_VERSION}.lib
- ${LIBDIR}/ffmpeg/lib/avformat-${FFMPEG_LIBRARY_VERSION}.lib
- ${LIBDIR}/ffmpeg/lib/avdevice-${FFMPEG_LIBRARY_VERSION}.lib
- ${LIBDIR}/ffmpeg/lib/avutil-${FFMPEG_LIBRARY_VERSION_AVU}.lib
- ${LIBDIR}/ffmpeg/lib/swscale-2.lib
- )
- endif()
- endif()
-
- if(WITH_IMAGE_OPENEXR)
- set(OPENEXR_ROOT_DIR ${LIBDIR}/openexr)
- set(OPENEXR_VERSION "2.1")
- find_package(OPENEXR REQUIRED)
- if(NOT OPENEXR_FOUND)
- message(WARNING "Using HARDCODED OpenEXR locations")
- set(OPENEXR ${LIBDIR}/openexr)
- set(OPENEXR_INCLUDE_DIR ${OPENEXR}/include)
- set(OPENEXR_INCLUDE_DIRS ${OPENEXR_INCLUDE_DIR} ${OPENEXR}/include/OpenEXR)
- set(OPENEXR_LIBPATH ${OPENEXR}/lib)
- set(OPENEXR_LIBRARIES
- optimized ${OPENEXR_LIBPATH}/Iex-2_2.lib debug ${OPENEXR_LIBPATH}/Iex-2_2_d.lib
- optimized ${OPENEXR_LIBPATH}/Half.lib debug ${OPENEXR_LIBPATH}/Half_d.lib
- optimized ${OPENEXR_LIBPATH}/IlmImf-2_2.lib debug ${OPENEXR_LIBPATH}/IlmImf-2_2_d.lib
- optimized ${OPENEXR_LIBPATH}/Imath-2_2.lib debug ${OPENEXR_LIBPATH}/Imath-2_2_d.lib
- optimized ${OPENEXR_LIBPATH}/IlmThread-2_2.lib debug ${OPENEXR_LIBPATH}/IlmThread-2_2_d.lib
- )
- endif()
- endif()
-
- if(WITH_IMAGE_TIFF)
- # Try to find tiff first then complain and set static and maybe wrong paths
- find_package(TIFF)
- if(NOT TIFF_FOUND)
- message(WARNING "Using HARDCODED libtiff locations")
- set(TIFF_LIBRARY ${LIBDIR}/tiff/lib/libtiff.lib)
- set(TIFF_INCLUDE_DIR ${LIBDIR}/tiff/include)
- endif()
- endif()
-
- if(WITH_JACK)
- set(JACK_INCLUDE_DIRS
- ${LIBDIR}/jack/include/jack
- ${LIBDIR}/jack/include
- )
- set(JACK_LIBRARIES optimized ${LIBDIR}/jack/lib/libjack.lib debug ${LIBDIR}/jack/lib/libjack_d.lib)
- endif()
-
- if(WITH_PYTHON)
- set(PYTHON_VERSION 3.5) # CACHE STRING)
-
- string(REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${PYTHON_VERSION})
- # Use shared libs for vc2008 and vc2010 until we actually have vc2010 libs
- set(PYTHON_LIBRARY ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}.lib)
- unset(_PYTHON_VERSION_NO_DOTS)
-
- # Shared includes for both vc2008 and vc2010
- set(PYTHON_INCLUDE_DIR ${LIBDIR}/python/include/python${PYTHON_VERSION})
-
- # uncached vars
- set(PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIR}")
- set(PYTHON_LIBRARIES "${PYTHON_LIBRARY}")
- endif()
-
- if(WITH_BOOST)
- if(WITH_CYCLES_OSL)
- set(boost_extra_libs wave)
- endif()
- if(WITH_INTERNATIONAL)
- list(APPEND boost_extra_libs locale)
- endif()
- if(WITH_OPENVDB)
- list(APPEND boost_extra_libs iostreams)
- endif()
- set(Boost_USE_STATIC_RUNTIME ON) # prefix lib
- set(Boost_USE_MULTITHREADED ON) # suffix -mt
- set(Boost_USE_STATIC_LIBS ON) # suffix -s
- find_package(Boost COMPONENTS date_time filesystem thread regex system ${boost_extra_libs})
- if(NOT Boost_FOUND)
- message(WARNING "USING HARDCODED boost locations")
- set(BOOST ${LIBDIR}/boost)
- set(BOOST_INCLUDE_DIR ${BOOST}/include)
- if(MSVC12)
- set(BOOST_LIBPATH ${BOOST}/lib)
- set(BOOST_POSTFIX "vc120-mt-s-1_60.lib")
- set(BOOST_DEBUG_POSTFIX "vc120-mt-sgd-1_60.lib")
- else()
- set(BOOST_LIBPATH ${BOOST}/lib)
- set(BOOST_POSTFIX "vc140-mt-s-1_60.lib")
- set(BOOST_DEBUG_POSTFIX "vc140-mt-sgd-1_60.lib")
- endif()
- set(BOOST_LIBRARIES
- optimized libboost_date_time-${BOOST_POSTFIX} optimized libboost_filesystem-${BOOST_POSTFIX}
- optimized libboost_regex-${BOOST_POSTFIX}
- optimized libboost_system-${BOOST_POSTFIX} optimized libboost_thread-${BOOST_POSTFIX}
- debug libboost_date_time-${BOOST_DEBUG_POSTFIX} debug libboost_filesystem-${BOOST_DEBUG_POSTFIX}
- debug libboost_regex-${BOOST_DEBUG_POSTFIX}
- debug libboost_system-${BOOST_DEBUG_POSTFIX} debug libboost_thread-${BOOST_DEBUG_POSTFIX})
- if(WITH_CYCLES_OSL)
- set(BOOST_LIBRARIES ${BOOST_LIBRARIES}
- optimized libboost_wave-${BOOST_POSTFIX}
- debug libboost_wave-${BOOST_DEBUG_POSTFIX})
- endif()
- if(WITH_INTERNATIONAL)
- set(BOOST_LIBRARIES ${BOOST_LIBRARIES}
- optimized libboost_locale-${BOOST_POSTFIX}
- debug libboost_locale-${BOOST_DEBUG_POSTFIX})
- endif()
- else() # we found boost using find_package
- set(BOOST_INCLUDE_DIR ${Boost_INCLUDE_DIRS})
- set(BOOST_LIBRARIES ${Boost_LIBRARIES})
- set(BOOST_LIBPATH ${Boost_LIBRARY_DIRS})
- endif()
- set(BOOST_DEFINITIONS "-DBOOST_ALL_NO_LIB")
- endif()
-
- if(WITH_OPENIMAGEIO)
- find_package(OpenImageIO)
- set(OPENIMAGEIO ${LIBDIR}/openimageio)
- set(OPENIMAGEIO_INCLUDE_DIRS ${OPENIMAGEIO}/include)
- set(OIIO_OPTIMIZED optimized OpenImageIO optimized OpenImageIO_Util)
- set(OIIO_DEBUG debug OpenImageIO_d debug OpenImageIO_Util_d)
- set(OPENIMAGEIO_LIBRARIES ${OIIO_OPTIMIZED} ${OIIO_DEBUG})
- set(OPENIMAGEIO_LIBPATH ${OPENIMAGEIO}/lib)
- set(OPENIMAGEIO_DEFINITIONS "-DUSE_TBB=0")
- set(OPENCOLORIO_DEFINITIONS "-DOCIO_STATIC_BUILD")
- set(OPENIMAGEIO_IDIFF "${OPENIMAGEIO}/bin/idiff.exe")
- add_definitions(-DOIIO_STATIC_BUILD)
- endif()
-
- if(WITH_LLVM)
- set(LLVM_ROOT_DIR ${LIBDIR}/llvm CACHE PATH "Path to the LLVM installation")
- file(GLOB LLVM_LIBRARY_OPTIMIZED ${LLVM_ROOT_DIR}/lib/*.lib)
-
- if(EXISTS ${LLVM_ROOT_DIR}/debug/lib)
- foreach(LLVM_OPTIMIZED_LIB ${LLVM_LIBRARY_OPTIMIZED})
- get_filename_component(LIBNAME ${LLVM_OPTIMIZED_LIB} ABSOLUTE)
- list(APPEND LLVM_LIBS optimized ${LIBNAME})
- endforeach(LLVM_OPTIMIZED_LIB)
-
- file(GLOB LLVM_LIBRARY_DEBUG ${LLVM_ROOT_DIR}/debug/lib/*.lib)
-
- foreach(LLVM_DEBUG_LIB ${LLVM_LIBRARY_DEBUG})
- get_filename_component(LIBNAME ${LLVM_DEBUG_LIB} ABSOLUTE)
- list(APPEND LLVM_LIBS debug ${LIBNAME})
- endforeach(LLVM_DEBUG_LIB)
-
- set(LLVM_LIBRARY ${LLVM_LIBS})
- else()
- message(WARNING "LLVM debug libs not present on this system. Using release libs for debug builds.")
- set(LLVM_LIBRARY ${LLVM_LIBRARY_OPTIMIZED})
- endif()
-
- endif()
-
- if(WITH_OPENCOLORIO)
- set(OPENCOLORIO ${LIBDIR}/opencolorio)
- set(OPENCOLORIO_INCLUDE_DIRS ${OPENCOLORIO}/include)
- set(OPENCOLORIO_LIBRARIES OpenColorIO)
- set(OPENCOLORIO_LIBPATH ${LIBDIR}/opencolorio/lib)
- set(OPENCOLORIO_DEFINITIONS)
- endif()
-
- if(WITH_OPENVDB)
- set(BLOSC_LIBRARIES optimized ${LIBDIR}/blosc/lib/libblosc.lib debug ${LIBDIR}/blosc/lib/libblosc_d.lib)
- set(TBB_LIBRARIES optimized ${LIBDIR}/tbb/lib/tbb.lib debug ${LIBDIR}/tbb/lib/tbb_debug.lib)
- set(TBB_INCLUDE_DIR ${LIBDIR}/tbb/include)
- set(OPENVDB ${LIBDIR}/openvdb)
- set(OPENVDB_INCLUDE_DIRS ${OPENVDB}/include ${TBB_INCLUDE_DIR})
- set(OPENVDB_LIBRARIES optimized openvdb debug openvdb_d ${TBB_LIBRARIES} ${BLOSC_LIBRARIES})
- set(OPENVDB_LIBPATH ${LIBDIR}/openvdb/lib)
- endif()
-
- if(WITH_MOD_CLOTH_ELTOPO)
- set(LAPACK ${LIBDIR}/lapack)
- # set(LAPACK_INCLUDE_DIR ${LAPACK}/include)
- set(LAPACK_LIBPATH ${LAPACK}/lib)
- set(LAPACK_LIBRARIES
- ${LIBDIR}/lapack/lib/libf2c.lib
- ${LIBDIR}/lapack/lib/clapack_nowrap.lib
- ${LIBDIR}/lapack/lib/BLAS_nowrap.lib
- )
- endif()
-
- if(WITH_OPENSUBDIV)
- set(OPENSUBDIV_INCLUDE_DIR ${LIBDIR}/opensubdiv/include)
- set(OPENSUBDIV_LIBPATH ${LIBDIR}/opensubdiv/lib)
- set(OPENSUBDIV_LIBRARIES ${OPENSUBDIV_LIBPATH}/osdCPU.lib ${OPENSUBDIV_LIBPATH}/osdGPU.lib)
- find_package(OpenSubdiv)
- endif()
-
- if(WITH_SDL)
- set(SDL ${LIBDIR}/sdl)
- set(SDL_INCLUDE_DIR ${SDL}/include)
- set(SDL_LIBPATH ${SDL}/lib)
- # MinGW TODO: Update MinGW to SDL2
- if(NOT CMAKE_COMPILER_IS_GNUCC)
- set(SDL_LIBRARY SDL2)
- else()
- set(SDL_LIBRARY SDL)
- endif()
- endif()
-
- # Audio IO
- if(WITH_SYSTEM_AUDASPACE)
- set(AUDASPACE_INCLUDE_DIRS ${LIBDIR}/audaspace/include/audaspace)
- set(AUDASPACE_LIBRARIES ${LIBDIR}/audaspace/lib/audaspace.lib)
- set(AUDASPACE_C_INCLUDE_DIRS ${LIBDIR}/audaspace/include/audaspace)
- set(AUDASPACE_C_LIBRARIES ${LIBDIR}/audaspace/lib/audaspace-c.lib)
- set(AUDASPACE_PY_INCLUDE_DIRS ${LIBDIR}/audaspace/include/audaspace)
- set(AUDASPACE_PY_LIBRARIES ${LIBDIR}/audaspace/lib/audaspace-py.lib)
- endif()
-
- # used in many places so include globally, like OpenGL
- blender_include_dirs_sys("${PTHREADS_INCLUDE_DIRS}")
-
- elseif(CMAKE_COMPILER_IS_GNUCC)
- # keep GCC specific stuff here
- include(CheckCSourceCompiles)
- # Setup 64bit and 64bit windows systems
- CHECK_C_SOURCE_COMPILES("
- #ifndef __MINGW64__
- #error
- #endif
- int main(void) { return 0; }
- "
- WITH_MINGW64)
-
- if(NOT DEFINED LIBDIR)
- if(WITH_MINGW64)
- message(STATUS "Compiling for 64 bit with MinGW-w64.")
- set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/mingw64)
- else()
- message(STATUS "Compiling for 32 bit with MinGW-w32.")
- set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/mingw32)
-
- if(WITH_RAYOPTIMIZATION)
- message(WARNING "MinGW-w32 is known to be unstable with 'WITH_RAYOPTIMIZATION' option enabled.")
- endif()
- endif()
- else()
- message(STATUS "Using pre-compiled LIBDIR: ${LIBDIR}")
- endif()
- if(NOT EXISTS "${LIBDIR}/")
- message(FATAL_ERROR "Windows requires pre-compiled libs at: '${LIBDIR}'")
- endif()
-
- list(APPEND PLATFORM_LINKLIBS -lshell32 -lshfolder -lgdi32 -lmsvcrt -lwinmm -lmingw32 -lm -lws2_32 -lz -lstdc++ -lole32 -luuid -lwsock32 -lpsapi -ldbghelp)
-
- if(WITH_INPUT_IME)
- list(APPEND PLATFORM_LINKLIBS -limm32)
- endif()
-
- set(PLATFORM_CFLAGS "-pipe -funsigned-char -fno-strict-aliasing")
-
- if(WITH_MINGW64)
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive")
- list(APPEND PLATFORM_LINKLIBS -lpthread)
-
- add_definitions(-DFREE_WINDOWS64 -DMS_WIN64)
- endif()
-
- add_definitions(-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE)
-
- add_definitions(-DFREE_WINDOWS)
-
- set(PNG "${LIBDIR}/png")
- set(PNG_INCLUDE_DIRS "${PNG}/include")
- set(PNG_LIBPATH ${PNG}/lib) # not cmake defined
-
- if(WITH_MINGW64)
- set(JPEG_LIBRARIES jpeg)
- else()
- set(JPEG_LIBRARIES libjpeg)
- endif()
- set(PNG_LIBRARIES png)
-
- set(ZLIB ${LIBDIR}/zlib)
- set(ZLIB_INCLUDE_DIRS ${ZLIB}/include)
- set(ZLIB_LIBPATH ${ZLIB}/lib)
- set(ZLIB_LIBRARIES z)
-
- set(JPEG "${LIBDIR}/jpeg")
- set(JPEG_INCLUDE_DIR "${JPEG}/include")
- set(JPEG_LIBPATH ${JPEG}/lib) # not cmake defined
-
- # comes with own pthread library
- if(NOT WITH_MINGW64)
- set(PTHREADS ${LIBDIR}/pthreads)
- #set(PTHREADS_INCLUDE_DIRS ${PTHREADS}/include)
- set(PTHREADS_LIBPATH ${PTHREADS}/lib)
- set(PTHREADS_LIBRARIES pthreadGC2)
- endif()
-
- set(FREETYPE ${LIBDIR}/freetype)
- set(FREETYPE_INCLUDE_DIRS ${FREETYPE}/include ${FREETYPE}/include/freetype2)
- set(FREETYPE_LIBPATH ${FREETYPE}/lib)
- set(FREETYPE_LIBRARY freetype)
-
- if(WITH_FFTW3)
- set(FFTW3 ${LIBDIR}/fftw3)
- set(FFTW3_LIBRARIES fftw3)
- set(FFTW3_INCLUDE_DIRS ${FFTW3}/include)
- set(FFTW3_LIBPATH ${FFTW3}/lib)
- endif()
-
- if(WITH_OPENCOLLADA)
- set(OPENCOLLADA ${LIBDIR}/opencollada)
- set(OPENCOLLADA_INCLUDE_DIRS
- ${OPENCOLLADA}/include/opencollada/COLLADAStreamWriter
- ${OPENCOLLADA}/include/opencollada/COLLADABaseUtils
- ${OPENCOLLADA}/include/opencollada/COLLADAFramework
- ${OPENCOLLADA}/include/opencollada/COLLADASaxFrameworkLoader
- ${OPENCOLLADA}/include/opencollada/GeneratedSaxParser
- )
- set(OPENCOLLADA_LIBPATH ${OPENCOLLADA}/lib/opencollada)
- set(OPENCOLLADA_LIBRARIES OpenCOLLADAStreamWriter OpenCOLLADASaxFrameworkLoader OpenCOLLADAFramework OpenCOLLADABaseUtils GeneratedSaxParser UTF MathMLSolver buffer ftoa xml)
- set(PCRE_LIBRARIES pcre)
- endif()
-
- if(WITH_CODEC_FFMPEG)
- set(FFMPEG ${LIBDIR}/ffmpeg)
- set(FFMPEG_INCLUDE_DIRS ${FFMPEG}/include)
- if(WITH_MINGW64)
- set(FFMPEG_LIBRARIES avcodec.dll avformat.dll avdevice.dll avutil.dll swscale.dll swresample.dll)
- else()
- set(FFMPEG_LIBRARIES avcodec-55 avformat-55 avdevice-55 avutil-52 swscale-2)
- endif()
- set(FFMPEG_LIBPATH ${FFMPEG}/lib)
- endif()
-
- if(WITH_IMAGE_OPENEXR)
- set(OPENEXR ${LIBDIR}/openexr)
- set(OPENEXR_INCLUDE_DIR ${OPENEXR}/include)
- set(OPENEXR_INCLUDE_DIRS ${OPENEXR}/include/OpenEXR)
- set(OPENEXR_LIBRARIES Half IlmImf Imath IlmThread Iex)
- set(OPENEXR_LIBPATH ${OPENEXR}/lib)
- endif()
-
- if(WITH_IMAGE_TIFF)
- set(TIFF ${LIBDIR}/tiff)
- set(TIFF_LIBRARY tiff)
- set(TIFF_INCLUDE_DIR ${TIFF}/include)
- set(TIFF_LIBPATH ${TIFF}/lib)
- endif()
-
- if(WITH_JACK)
- set(JACK ${LIBDIR}/jack)
- set(JACK_INCLUDE_DIRS ${JACK}/include/jack ${JACK}/include)
- set(JACK_LIBRARIES jack)
- set(JACK_LIBPATH ${JACK}/lib)
-
- # TODO, gives linking errors, force off
- set(WITH_JACK OFF)
- endif()
-
- if(WITH_PYTHON)
- # normally cached but not since we include them with blender
- set(PYTHON_VERSION 3.5) # CACHE STRING)
- string(REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${PYTHON_VERSION})
- set(PYTHON_INCLUDE_DIR "${LIBDIR}/python/include/python${PYTHON_VERSION}") # CACHE PATH)
- set(PYTHON_LIBRARY "${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}mw.lib") # CACHE FILEPATH)
- unset(_PYTHON_VERSION_NO_DOTS)
-
- # uncached vars
- set(PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIR}")
- set(PYTHON_LIBRARIES "${PYTHON_LIBRARY}")
- endif()
-
- if(WITH_BOOST)
- set(BOOST ${LIBDIR}/boost)
- set(BOOST_INCLUDE_DIR ${BOOST}/include)
- if(WITH_MINGW64)
- set(BOOST_POSTFIX "mgw47-mt-s-1_49")
- set(BOOST_DEBUG_POSTFIX "mgw47-mt-sd-1_49")
- else()
- set(BOOST_POSTFIX "mgw46-mt-s-1_49")
- set(BOOST_DEBUG_POSTFIX "mgw46-mt-sd-1_49")
- endif()
- set(BOOST_LIBRARIES
- optimized boost_date_time-${BOOST_POSTFIX} boost_filesystem-${BOOST_POSTFIX}
- boost_regex-${BOOST_POSTFIX}
- boost_system-${BOOST_POSTFIX} boost_thread-${BOOST_POSTFIX}
- debug boost_date_time-${BOOST_DEBUG_POSTFIX} boost_filesystem-${BOOST_DEBUG_POSTFIX}
- boost_regex-${BOOST_DEBUG_POSTFIX}
- boost_system-${BOOST_DEBUG_POSTFIX} boost_thread-${BOOST_DEBUG_POSTFIX})
- if(WITH_INTERNATIONAL)
- set(BOOST_LIBRARIES ${BOOST_LIBRARIES}
- optimized boost_locale-${BOOST_POSTFIX}
- debug boost_locale-${BOOST_DEBUG_POSTFIX})
- endif()
- if(WITH_CYCLES_OSL)
- set(BOOST_LIBRARIES ${BOOST_LIBRARIES}
- optimized boost_wave-${BOOST_POSTFIX}
- debug boost_wave-${BOOST_DEBUG_POSTFIX})
- endif()
- set(BOOST_LIBPATH ${BOOST}/lib)
- set(BOOST_DEFINITIONS "-DBOOST_ALL_NO_LIB -DBOOST_THREAD_USE_LIB ")
- endif()
-
- if(WITH_OPENIMAGEIO)
- set(OPENIMAGEIO ${LIBDIR}/openimageio)
- set(OPENIMAGEIO_INCLUDE_DIRS ${OPENIMAGEIO}/include)
- set(OPENIMAGEIO_LIBRARIES OpenImageIO)
- set(OPENIMAGEIO_LIBPATH ${OPENIMAGEIO}/lib)
- set(OPENIMAGEIO_DEFINITIONS "")
- set(OPENIMAGEIO_IDIFF "${OPENIMAGEIO}/bin/idiff.exe")
- endif()
-
- if(WITH_LLVM)
- set(LLVM_ROOT_DIR ${LIBDIR}/llvm CACHE PATH "Path to the LLVM installation")
- set(LLVM_LIBPATH ${LLVM_ROOT_DIR}/lib)
- # Explicitly set llvm lib order.
- #---- WARNING ON GCC ORDER OF LIBS IS IMPORTANT, DO NOT CHANGE! ---------
- set(LLVM_LIBRARY LLVMSelectionDAG LLVMCodeGen LLVMScalarOpts LLVMAnalysis LLVMArchive
- LLVMAsmParser LLVMAsmPrinter
- LLVMBitReader LLVMBitWriter
- LLVMDebugInfo LLVMExecutionEngine
- LLVMInstCombine LLVMInstrumentation
- LLVMInterpreter LLVMJIT
- LLVMLinker LLVMMC
- LLVMMCDisassembler LLVMMCJIT
- LLVMMCParser LLVMObject
- LLVMRuntimeDyld
- LLVMSupport
- LLVMTableGen LLVMTarget
- LLVMTransformUtils LLVMVectorize
- LLVMX86AsmParser LLVMX86AsmPrinter
- LLVMX86CodeGen LLVMX86Desc
- LLVMX86Disassembler LLVMX86Info
- LLVMX86Utils LLVMipa
- LLVMipo LLVMCore)
- # imagehelp is needed by LLVM 3.1 on MinGW, check lib\Support\Windows\Signals.inc
- list(APPEND PLATFORM_LINKLIBS -limagehlp)
- endif()
-
- if(WITH_OPENCOLORIO)
- set(OPENCOLORIO ${LIBDIR}/opencolorio)
- set(OPENCOLORIO_INCLUDE_DIRS ${OPENCOLORIO}/include)
- set(OPENCOLORIO_LIBRARIES OpenColorIO)
- set(OPENCOLORIO_LIBPATH ${OPENCOLORIO}/lib)
- set(OPENCOLORIO_DEFINITIONS)
- endif()
-
- if(WITH_SDL)
- set(SDL ${LIBDIR}/sdl)
- set(SDL_INCLUDE_DIR ${SDL}/include)
- set(SDL_LIBRARY SDL)
- set(SDL_LIBPATH ${SDL}/lib)
- endif()
-
- if(WITH_OPENVDB)
- set(OPENVDB ${LIBDIR}/openvdb)
- set(OPENVDB_INCLUDE_DIRS ${OPENVDB}/include)
- set(OPENVDB_LIBRARIES openvdb ${TBB_LIBRARIES})
- set(OPENVDB_LIBPATH ${LIBDIR}/openvdb/lib)
- set(OPENVDB_DEFINITIONS)
- endif()
-
- set(PLATFORM_LINKFLAGS "-Xlinker --stack=2097152")
-
- ## DISABLE - causes linking errors
- ## for re-distribution, so users dont need mingw installed
- # set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -static-libgcc -static-libstdc++")
-
- endif()
-
- # Things common to both mingw and MSVC should go here
-
- set(WINTAB_INC ${LIBDIR}/wintab/include)
-
- if(WITH_OPENAL)
- set(OPENAL ${LIBDIR}/openal)
- set(OPENALDIR ${LIBDIR}/openal)
- set(OPENAL_INCLUDE_DIR ${OPENAL}/include)
- if(MSVC12)
- set(OPENAL_LIBRARY openal32)
- else()
- set(OPENAL_LIBRARY wrap_oal)
- endif()
- set(OPENAL_LIBPATH ${OPENAL}/lib)
- endif()
-
- if(WITH_CODEC_SNDFILE)
- set(SNDFILE ${LIBDIR}/sndfile)
- set(SNDFILE_INCLUDE_DIRS ${SNDFILE}/include)
- set(SNDFILE_LIBRARIES libsndfile-1)
- set(SNDFILE_LIBPATH ${SNDFILE}/lib) # TODO, deprecate
- endif()
-
- if(WITH_RAYOPTIMIZATION AND SUPPORT_SSE_BUILD)
- add_definitions(-D__SSE__ -D__MMX__)
- endif()
-
- if(WITH_CYCLES_OSL)
- set(CYCLES_OSL ${LIBDIR}/osl CACHE PATH "Path to OpenShadingLanguage installation")
-
- find_library(OSL_LIB_EXEC NAMES oslexec PATHS ${CYCLES_OSL}/lib)
- find_library(OSL_LIB_COMP NAMES oslcomp PATHS ${CYCLES_OSL}/lib)
- find_library(OSL_LIB_QUERY NAMES oslquery PATHS ${CYCLES_OSL}/lib)
- find_library(OSL_LIB_EXEC_DEBUG NAMES oslexec_d PATHS ${CYCLES_OSL}/lib)
- find_library(OSL_LIB_COMP_DEBUG NAMES oslcomp_d PATHS ${CYCLES_OSL}/lib)
- find_library(OSL_LIB_QUERY_DEBUG NAMES oslquery_d PATHS ${CYCLES_OSL}/lib)
- list(APPEND OSL_LIBRARIES optimized ${OSL_LIB_COMP} optimized ${OSL_LIB_EXEC} optimized ${OSL_LIB_QUERY} debug ${OSL_LIB_EXEC_DEBUG} debug ${OSL_LIB_COMP_DEBUG} debug ${OSL_LIB_QUERY_DEBUG})
- find_path(OSL_INCLUDE_DIR OSL/oslclosure.h PATHS ${CYCLES_OSL}/include)
- find_program(OSL_COMPILER NAMES oslc PATHS ${CYCLES_OSL}/bin)
-
- if(OSL_INCLUDE_DIR AND OSL_LIBRARIES AND OSL_COMPILER)
- set(OSL_FOUND TRUE)
- else()
- message(STATUS "OSL not found")
- set(WITH_CYCLES_OSL OFF)
- endif()
- endif()
-
+ include(platform_win32)
elseif(APPLE)
-
- if(${CMAKE_OSX_DEPLOYMENT_TARGET} STREQUAL "10.5" OR ${CMAKE_OSX_DEPLOYMENT_TARGET} STRGREATER "10.5")
- set(WITH_LIBS10.5 ON CACHE BOOL "Use 10.5 libs" FORCE) # valid also for 10.6/7/8/9
- endif()
-
- if(NOT DEFINED LIBDIR)
- if(WITH_LIBS10.5)
- set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/darwin-9.x.universal)
- else()
- if(CMAKE_OSX_ARCHITECTURES MATCHES i386)
- set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/darwin-8.x.i386)
- else()
- set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/darwin-8.0.0-powerpc)
- endif()
- endif()
- else()
- message(STATUS "Using pre-compiled LIBDIR: ${LIBDIR}")
- endif()
- if(NOT EXISTS "${LIBDIR}/")
- message(FATAL_ERROR "Mac OSX requires pre-compiled libs at: '${LIBDIR}'")
- endif()
-
- if(WITH_OPENAL)
- find_package(OpenAL)
- if(OPENAL_FOUND)
- set(WITH_OPENAL ON)
- set(OPENAL_INCLUDE_DIR "${LIBDIR}/openal/include")
- else()
- set(WITH_OPENAL OFF)
- endif()
- endif()
-
- if(WITH_OPENSUBDIV)
- set(OPENSUBDIV ${LIBDIR}/opensubdiv)
- set(OPENSUBDIV_LIBPATH ${OPENSUBDIV}/lib)
- find_library(OSL_LIB_UTIL NAMES osdutil PATHS ${OPENSUBDIV_LIBPATH})
- find_library(OSL_LIB_CPU NAMES osdCPU PATHS ${OPENSUBDIV_LIBPATH})
- find_library(OSL_LIB_GPU NAMES osdGPU PATHS ${OPENSUBDIV_LIBPATH})
- set(OPENSUBDIV_INCLUDE_DIR ${OPENSUBDIV}/include)
- set(OPENSUBDIV_INCLUDE_DIRS ${OPENSUBDIV_INCLUDE_DIR})
- list(APPEND OPENSUBDIV_LIBRARIES ${OSL_LIB_UTIL} ${OSL_LIB_CPU} ${OSL_LIB_GPU})
- endif()
-
- if(WITH_JACK)
- find_library(JACK_FRAMEWORK
- NAMES jackmp
- )
- set(JACK_INCLUDE_DIRS ${JACK_FRAMEWORK}/headers)
- if(NOT JACK_FRAMEWORK)
- set(WITH_JACK OFF)
- endif()
- endif()
-
- if(WITH_CODEC_SNDFILE)
- set(SNDFILE ${LIBDIR}/sndfile)
- set(SNDFILE_INCLUDE_DIRS ${SNDFILE}/include)
- set(SNDFILE_LIBRARIES sndfile FLAC ogg vorbis vorbisenc)
- set(SNDFILE_LIBPATH ${SNDFILE}/lib ${FFMPEG}/lib) # TODO, deprecate
- endif()
-
- if(WITH_PYTHON)
- # we use precompiled libraries for py 3.5 and up by default
- set(PYTHON_VERSION 3.5)
- if(NOT WITH_PYTHON_MODULE AND NOT WITH_PYTHON_FRAMEWORK)
- # normally cached but not since we include them with blender
- set(PYTHON_INCLUDE_DIR "${LIBDIR}/python/include/python${PYTHON_VERSION}m")
- set(PYTHON_EXECUTABLE "${LIBDIR}/python/bin/python${PYTHON_VERSION}m")
- set(PYTHON_LIBRARY python${PYTHON_VERSION}m)
- set(PYTHON_LIBPATH "${LIBDIR}/python/lib/python${PYTHON_VERSION}")
- # set(PYTHON_LINKFLAGS "-u _PyMac_Error") # won't build with this enabled
- else()
- # module must be compiled against Python framework
- set(PYTHON_INCLUDE_DIR "/Library/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/include/python${PYTHON_VERSION}m")
- set(PYTHON_EXECUTABLE "/Library/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/bin/python${PYTHON_VERSION}m")
- #set(PYTHON_LIBRARY python${PYTHON_VERSION})
- set(PYTHON_LIBPATH "/Library/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/lib/python${PYTHON_VERSION}/config-${PYTHON_VERSION}m")
- #set(PYTHON_LINKFLAGS "-u _PyMac_Error -framework Python") # won't build with this enabled
- endif()
-
- # uncached vars
- set(PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIR}")
- set(PYTHON_LIBRARIES "${PYTHON_LIBRARY}")
-
- if(NOT EXISTS "${PYTHON_EXECUTABLE}")
- message(FATAL_ERROR "Python executable missing: ${PYTHON_EXECUTABLE}")
- endif()
- endif()
-
- if(WITH_FFTW3)
- set(FFTW3 ${LIBDIR}/fftw3)
- set(FFTW3_INCLUDE_DIRS ${FFTW3}/include)
- set(FFTW3_LIBRARIES fftw3)
- set(FFTW3_LIBPATH ${FFTW3}/lib)
- endif()
-
- set(PNG_LIBRARIES png)
- set(JPEG_LIBRARIES jpeg)
-
- set(ZLIB /usr)
- set(ZLIB_INCLUDE_DIRS "${ZLIB}/include")
- set(ZLIB_LIBRARIES z bz2)
-
- set(FREETYPE ${LIBDIR}/freetype)
- set(FREETYPE_INCLUDE_DIRS ${FREETYPE}/include ${FREETYPE}/include/freetype2)
- set(FREETYPE_LIBPATH ${FREETYPE}/lib)
- set(FREETYPE_LIBRARY freetype)
-
- if(WITH_IMAGE_OPENEXR)
- set(OPENEXR ${LIBDIR}/openexr)
- set(OPENEXR_INCLUDE_DIR ${OPENEXR}/include)
- set(OPENEXR_INCLUDE_DIRS ${OPENEXR_INCLUDE_DIR} ${OPENEXR}/include/OpenEXR)
- set(OPENEXR_LIBRARIES Iex Half IlmImf Imath IlmThread)
- set(OPENEXR_LIBPATH ${OPENEXR}/lib)
- endif()
-
- if(WITH_CODEC_FFMPEG)
- set(FFMPEG ${LIBDIR}/ffmpeg)
- set(FFMPEG_INCLUDE_DIRS ${FFMPEG}/include)
- set(FFMPEG_LIBRARIES avcodec avdevice avformat avutil mp3lame swscale x264 xvidcore theora theoradec theoraenc vorbis vorbisenc vorbisfile ogg)
- set(FFMPEG_LIBPATH ${FFMPEG}/lib)
- endif()
-
- find_library(SYSTEMSTUBS_LIBRARY
- NAMES
- SystemStubs
- PATHS
- )
- mark_as_advanced(SYSTEMSTUBS_LIBRARY)
- if(SYSTEMSTUBS_LIBRARY)
- list(APPEND PLATFORM_LINKLIBS stdc++ SystemStubs)
- else()
- list(APPEND PLATFORM_LINKLIBS stdc++)
- endif()
-
- set(PLATFORM_CFLAGS "-pipe -funsigned-char")
- set(PLATFORM_LINKFLAGS "-fexceptions -framework CoreServices -framework Foundation -framework IOKit -framework AppKit -framework Cocoa -framework Carbon -framework AudioUnit -framework AudioToolbox -framework CoreAudio")
- if(WITH_CODEC_QUICKTIME)
- set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -framework QTKit")
- if(CMAKE_OSX_ARCHITECTURES MATCHES i386)
- set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -framework QuickTime")
- # libSDL still needs 32bit carbon quicktime
- endif()
- endif()
-
- # XXX - SOME MAC DEV PLEASE TEST WITH THE SDK INSTALLED!
- # ALSO SHOULD BE MOVED INTO OWN MODULE WHEN FUNCTIONAL
- if(WITH_INPUT_NDOF)
- # This thread it *should* work and check the framework - campbell
- # http://www.cmake.org/pipermail/cmake/2005-December/007740.html
- find_library(3DCONNEXION_CLIENT_FRAMEWORK
- NAMES 3DconnexionClient
- )
- if(NOT 3DCONNEXION_CLIENT_FRAMEWORK)
- set(WITH_INPUT_NDOF OFF)
- endif()
-
- if(WITH_INPUT_NDOF)
- set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -F/Library/Frameworks -weak_framework 3DconnexionClient")
- set(NDOF_INCLUDE_DIRS /Library/Frameworks/3DconnexionClient.framework/Headers )
- endif()
- endif()
-
- if(WITH_JACK)
- set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -F/Library/Frameworks -weak_framework jackmp")
- endif()
-
- if(WITH_PYTHON_MODULE OR WITH_PYTHON_FRAMEWORK)
- set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} /Library/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/Python")# force cmake to link right framework
- endif()
-
- if(WITH_OPENCOLLADA)
- set(OPENCOLLADA ${LIBDIR}/opencollada)
-
- set(OPENCOLLADA_INCLUDE_DIRS
- ${LIBDIR}/opencollada/include/COLLADAStreamWriter
- ${LIBDIR}/opencollada/include/COLLADABaseUtils
- ${LIBDIR}/opencollada/include/COLLADAFramework
- ${LIBDIR}/opencollada/include/COLLADASaxFrameworkLoader
- ${LIBDIR}/opencollada/include/GeneratedSaxParser
- )
-
- set(OPENCOLLADA_LIBPATH ${OPENCOLLADA}/lib)
- set(OPENCOLLADA_LIBRARIES "OpenCOLLADASaxFrameworkLoader -lOpenCOLLADAFramework -lOpenCOLLADABaseUtils -lOpenCOLLADAStreamWriter -lMathMLSolver -lGeneratedSaxParser -lxml2 -lbuffer -lftoa")
- # Use UTF functions from collada if LLVM is not enabled
- if(NOT WITH_LLVM)
- set(OPENCOLLADA_LIBRARIES "${OPENCOLLADA_LIBRARIES} -lUTF")
- endif()
- # pcre is bundled with openCollada
- #set(PCRE ${LIBDIR}/pcre)
- #set(PCRE_LIBPATH ${PCRE}/lib)
- set(PCRE_LIBRARIES pcre)
- #libxml2 is used
- #set(EXPAT ${LIBDIR}/expat)
- #set(EXPAT_LIBPATH ${EXPAT}/lib)
- set(EXPAT_LIB)
- endif()
-
- if(WITH_SDL)
- set(SDL ${LIBDIR}/sdl)
- set(SDL_INCLUDE_DIR ${SDL}/include)
- set(SDL_LIBRARY SDL2)
- set(SDL_LIBPATH ${SDL}/lib)
- set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -lazy_framework ForceFeedback")
- endif()
-
- set(PNG "${LIBDIR}/png")
- set(PNG_INCLUDE_DIRS "${PNG}/include")
- set(PNG_LIBPATH ${PNG}/lib)
-
- set(JPEG "${LIBDIR}/jpeg")
- set(JPEG_INCLUDE_DIR "${JPEG}/include")
- set(JPEG_LIBPATH ${JPEG}/lib)
-
- if(WITH_IMAGE_TIFF)
- set(TIFF ${LIBDIR}/tiff)
- set(TIFF_INCLUDE_DIR ${TIFF}/include)
- set(TIFF_LIBRARY tiff)
- set(TIFF_LIBPATH ${TIFF}/lib)
- endif()
-
- if(WITH_INPUT_NDOF)
- # linker needs "-weak_framework 3DconnexionClient"
- endif()
-
- if(WITH_BOOST)
- set(BOOST ${LIBDIR}/boost)
- set(BOOST_INCLUDE_DIR ${BOOST}/include)
- set(BOOST_LIBRARIES boost_date_time-mt boost_filesystem-mt boost_regex-mt boost_system-mt boost_thread-mt boost_wave-mt)
- if(WITH_INTERNATIONAL)
- list(APPEND BOOST_LIBRARIES boost_locale-mt)
- endif()
- if(WITH_CYCLES_NETWORK)
- list(APPEND BOOST_LIBRARIES boost_serialization-mt)
- endif()
- if(WITH_OPENVDB)
- list(APPEND BOOST_LIBRARIES boost_iostreams-mt)
- endif()
- set(BOOST_LIBPATH ${BOOST}/lib)
- set(BOOST_DEFINITIONS)
- endif()
-
- if(WITH_INTERNATIONAL OR WITH_CODEC_FFMPEG)
- set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -liconv") # boost_locale and ffmpeg needs it !
- endif()
-
- if(WITH_OPENIMAGEIO)
- set(OPENIMAGEIO ${LIBDIR}/openimageio)
- set(OPENIMAGEIO_INCLUDE_DIRS ${OPENIMAGEIO}/include)
- set(OPENIMAGEIO_LIBRARIES ${OPENIMAGEIO}/lib/libOpenImageIO.a ${PNG_LIBRARIES} ${JPEG_LIBRARIES} ${TIFF_LIBRARY} ${OPENEXR_LIBRARIES} ${ZLIB_LIBRARIES})
- set(OPENIMAGEIO_LIBPATH ${OPENIMAGEIO}/lib ${JPEG_LIBPATH} ${PNG_LIBPATH} ${TIFF_LIBPATH} ${OPENEXR_LIBPATH} ${ZLIB_LIBPATH})
- set(OPENIMAGEIO_DEFINITIONS "-DOIIO_STATIC_BUILD")
- set(OPENIMAGEIO_IDIFF "${LIBDIR}/openimageio/bin/idiff")
- endif()
-
- if(WITH_OPENCOLORIO)
- set(OPENCOLORIO ${LIBDIR}/opencolorio)
- set(OPENCOLORIO_INCLUDE_DIRS ${OPENCOLORIO}/include)
- set(OPENCOLORIO_LIBRARIES OpenColorIO tinyxml yaml-cpp)
- set(OPENCOLORIO_LIBPATH ${OPENCOLORIO}/lib)
- endif()
-
- if(WITH_OPENVDB)
- set(OPENVDB ${LIBDIR}/openvdb)
- set(OPENVDB_INCLUDE_DIRS ${OPENVDB}/include)
- set(TBB_INCLUDE_DIRS ${LIBDIR}/tbb/include)
- set(TBB_LIBRARIES ${LIBDIR}/tbb/lib/libtbb.a)
- set(OPENVDB_LIBRARIES openvdb blosc ${TBB_LIBRARIES})
- set(OPENVDB_LIBPATH ${LIBDIR}/openvdb/lib)
- set(OPENVDB_DEFINITIONS)
- endif()
-
- if(WITH_LLVM)
- set(LLVM_ROOT_DIR ${LIBDIR}/llvm CACHE PATH "Path to the LLVM installation")
- set(LLVM_VERSION "3.4" CACHE STRING "Version of LLVM to use")
- if(EXISTS "${LLVM_ROOT_DIR}/bin/llvm-config")
- set(LLVM_CONFIG "${LLVM_ROOT_DIR}/bin/llvm-config")
- else()
- set(LLVM_CONFIG llvm-config)
- endif()
- execute_process(COMMAND ${LLVM_CONFIG} --version
- OUTPUT_VARIABLE LLVM_VERSION
- OUTPUT_STRIP_TRAILING_WHITESPACE)
- execute_process(COMMAND ${LLVM_CONFIG} --prefix
- OUTPUT_VARIABLE LLVM_ROOT_DIR
- OUTPUT_STRIP_TRAILING_WHITESPACE)
- execute_process(COMMAND ${LLVM_CONFIG} --libdir
- OUTPUT_VARIABLE LLVM_LIBPATH
- OUTPUT_STRIP_TRAILING_WHITESPACE)
- find_library(LLVM_LIBRARY
- NAMES LLVMAnalysis # first of a whole bunch of libs to get
- PATHS ${LLVM_LIBPATH})
-
- if(LLVM_LIBRARY AND LLVM_ROOT_DIR AND LLVM_LIBPATH)
- if(LLVM_STATIC)
- # if static LLVM libraries were requested, use llvm-config to generate
- # the list of what libraries we need, and substitute that in the right
- # way for LLVM_LIBRARY.
- execute_process(COMMAND ${LLVM_CONFIG} --libfiles
- OUTPUT_VARIABLE LLVM_LIBRARY
- OUTPUT_STRIP_TRAILING_WHITESPACE)
- string(REPLACE " " ";" LLVM_LIBRARY ${LLVM_LIBRARY})
- else()
- set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -lLLVM-3.4")
- endif()
- else()
- message(FATAL_ERROR "LLVM not found.")
- endif()
- endif()
-
- if(WITH_CYCLES_OSL)
- set(CYCLES_OSL ${LIBDIR}/osl CACHE PATH "Path to OpenShadingLanguage installation")
-
- find_library(OSL_LIB_EXEC NAMES oslexec PATHS ${CYCLES_OSL}/lib)
- find_library(OSL_LIB_COMP NAMES oslcomp PATHS ${CYCLES_OSL}/lib)
- find_library(OSL_LIB_QUERY NAMES oslquery PATHS ${CYCLES_OSL}/lib)
- # WARNING! depends on correct order of OSL libs linking
- list(APPEND OSL_LIBRARIES ${OSL_LIB_COMP} -force_load ${OSL_LIB_EXEC} ${OSL_LIB_QUERY})
- find_path(OSL_INCLUDE_DIR OSL/oslclosure.h PATHS ${CYCLES_OSL}/include)
- find_program(OSL_COMPILER NAMES oslc PATHS ${CYCLES_OSL}/bin)
-
- if(OSL_INCLUDE_DIR AND OSL_LIBRARIES AND OSL_COMPILER)
- set(OSL_FOUND TRUE)
- else()
- message(STATUS "OSL not found")
- set(WITH_CYCLES_OSL OFF)
- endif()
- endif()
-
- if(WITH_OPENMP)
- execute_process(COMMAND ${CMAKE_C_COMPILER} --version OUTPUT_VARIABLE COMPILER_VENDOR)
- string(SUBSTRING "${COMPILER_VENDOR}" 0 5 VENDOR_NAME) # truncate output
- if(${VENDOR_NAME} MATCHES "Apple") # Apple does not support OpenMP reliable with gcc and not with clang
- set(WITH_OPENMP OFF)
- else() # vanilla gcc or clang_omp support OpenMP
- message(STATUS "Using special OpenMP enabled compiler !") # letting find_package(OpenMP) module work for gcc
- if(CMAKE_C_COMPILER_ID MATCHES "Clang") # clang-omp in darwin libs
- set(OPENMP_FOUND ON)
- set(OpenMP_C_FLAGS "-fopenmp" CACHE STRING "C compiler flags for OpenMP parallization" FORCE)
- set(OpenMP_CXX_FLAGS "-fopenmp" CACHE STRING "C++ compiler flags for OpenMP parallization" FORCE)
- include_directories(${LIBDIR}/openmp/include)
- link_directories(${LIBDIR}/openmp/lib)
- # This is a workaround for our helperbinaries ( datatoc, masgfmt, ... ),
- # They are linked also to omp lib, so we need it in builddir for runtime exexcution, TODO: remove all unneeded dependencies from these
- execute_process(COMMAND ditto -arch ${CMAKE_OSX_ARCHITECTURES} ${LIBDIR}/openmp/lib/libiomp5.dylib ${CMAKE_BINARY_DIR}/Resources/lib/libiomp5.dylib) # for intermediate binaries, in respect to lib ID
- endif()
- endif()
- endif()
-
- set(EXETYPE MACOSX_BUNDLE)
-
- set(CMAKE_C_FLAGS_DEBUG "-fno-strict-aliasing -g")
- set(CMAKE_CXX_FLAGS_DEBUG "-fno-strict-aliasing -g")
- if(CMAKE_OSX_ARCHITECTURES MATCHES "x86_64" OR CMAKE_OSX_ARCHITECTURES MATCHES "i386")
- set(CMAKE_CXX_FLAGS_RELEASE "-O2 -mdynamic-no-pic -msse -msse2 -msse3 -mssse3")
- set(CMAKE_C_FLAGS_RELEASE "-O2 -mdynamic-no-pic -msse -msse2 -msse3 -mssse3")
- if(NOT CMAKE_C_COMPILER_ID MATCHES "Clang")
- set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -ftree-vectorize -fvariable-expansion-in-unroller")
- set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -ftree-vectorize -fvariable-expansion-in-unroller")
- endif()
- else()
- set(CMAKE_C_FLAGS_RELEASE "-mdynamic-no-pic -fno-strict-aliasing")
- set(CMAKE_CXX_FLAGS_RELEASE "-mdynamic-no-pic -fno-strict-aliasing")
- endif()
-
- if(${XCODE_VERSION} VERSION_EQUAL 5 OR ${XCODE_VERSION} VERSION_GREATER 5)
- # Xcode 5 is always using CLANG, which has too low template depth of 128 for libmv
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftemplate-depth=1024")
- endif()
- # Get rid of eventually clashes, we export some symbols explicite as local
- set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -Xlinker -unexported_symbols_list -Xlinker ${CMAKE_SOURCE_DIR}/source/creator/osx_locals.map")
-
- # Suppress ranlib "has no symbols" warnings (workaround for T48250)
- set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>")
- set(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>")
- set(CMAKE_C_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
- set(CMAKE_CXX_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
+ include(platform_apple)
endif()
#-----------------------------------------------------------------------------
@@ -2340,22 +946,34 @@ endif()
if(WITH_CYCLES)
if(NOT WITH_OPENIMAGEIO)
- message(FATAL_ERROR "Cycles requires WITH_OPENIMAGEIO, the library may not have been found. Configure OIIO or disable WITH_CYCLES")
+ message(FATAL_ERROR
+ "Cycles requires WITH_OPENIMAGEIO, the library may not have been found. "
+ "Configure OIIO or disable WITH_CYCLES"
+ )
endif()
if(NOT WITH_BOOST)
- message(FATAL_ERROR "Cycles requires WITH_BOOST, the library may not have been found. Configure BOOST or disable WITH_CYCLES")
+ message(FATAL_ERROR
+ "Cycles requires WITH_BOOST, the library may not have been found. "
+ "Configure BOOST or disable WITH_CYCLES"
+ )
endif()
if(WITH_CYCLES_OSL)
if(NOT WITH_LLVM)
- message(FATAL_ERROR "Cycles OSL requires WITH_LLVM, the library may not have been found. Configure LLVM or disable WITH_CYCLES_OSL")
+ message(FATAL_ERROR
+ "Cycles OSL requires WITH_LLVM, the library may not have been found. "
+ "Configure LLVM or disable WITH_CYCLES_OSL"
+ )
endif()
endif()
endif()
if(WITH_INTERNATIONAL)
if(NOT WITH_BOOST)
- message(FATAL_ERROR "Internationalization requires WITH_BOOST, the library may not have been found. Configure BOOST or disable WITH_INTERNATIONAL")
+ message(FATAL_ERROR
+ "Internationalization requires WITH_BOOST, the library may not have been found. "
+ "Configure BOOST or disable WITH_INTERNATIONAL"
+ )
endif()
endif()
@@ -2368,7 +986,7 @@ if(SUPPORT_SSE_BUILD)
add_definitions(-D__SSE__ -D__MMX__)
endif()
if(SUPPORT_SSE2_BUILD)
- set(PLATFORM_CFLAGS " ${COMPILER_SSE2_FLAG} ${PLATFORM_CFLAGS}")
+ set(PLATFORM_CFLAGS " ${PLATFORM_CFLAGS} ${COMPILER_SSE2_FLAG}")
add_definitions(-D__SSE2__)
if(NOT SUPPORT_SSE_BUILD) # dont double up
add_definitions(-D__MMX__)
@@ -2400,8 +1018,6 @@ else()
endif()
unset(_SYSTEM_BIG_ENDIAN)
endif()
-
-
if(WITH_IMAGE_OPENJPEG)
if(WITH_SYSTEM_OPENJPEG)
# dealt with above
@@ -2441,7 +1057,10 @@ if(WITH_GL_PROFILE_COMPAT OR WITH_GL_PROFILE_CORE)
elseif(WITH_GL_PROFILE_ES20)
if(WITH_SYSTEM_GLES)
if(NOT OPENGLES_LIBRARY)
- message(FATAL_ERROR "Unable to find OpenGL ES libraries. Install them or disable WITH_SYSTEM_GLES.")
+ message(FATAL_ERROR
+ "Unable to find OpenGL ES libraries. "
+ "Install them or disable WITH_SYSTEM_GLES."
+ )
endif()
list(APPEND BLENDER_GL_LIBRARIES OPENGLES_LIBRARY)
@@ -2453,7 +1072,10 @@ elseif(WITH_GL_PROFILE_ES20)
list(APPEND BLENDER_GL_LIBRARIES "${OPENGLES_LIBRARY}")
if(NOT OPENGLES_LIBRARY)
- message(FATAL_ERROR "To compile WITH_GL_EGL you need to set OPENGLES_LIBRARY to the file path of an OpenGL ES 2.0 library.")
+ message(FATAL_ERROR
+ "To compile WITH_GL_EGL you need to set OPENGLES_LIBRARY "
+ "to the file path of an OpenGL ES 2.0 library."
+ )
endif()
endif()
@@ -2465,7 +1087,10 @@ elseif(WITH_GL_PROFILE_ES20)
mark_as_advanced(OPENGLES_DLL)
if(NOT OPENGLES_DLL)
- message(FATAL_ERROR "To compile WITH_GL_PROFILE_ES20 you need to set OPENGLES_DLL to the file path of an OpenGL ES 2.0 runtime dynamic link library (DLL).")
+ message(FATAL_ERROR
+ "To compile WITH_GL_PROFILE_ES20 you need to set OPENGLES_DLL to the file "
+ "path of an OpenGL ES 2.0 runtime dynamic link library (DLL)."
+ )
endif()
if(WITH_GL_ANGLE)
@@ -2479,7 +1104,10 @@ elseif(WITH_GL_PROFILE_ES20)
mark_as_advanced(D3DCOMPILER_DLL)
if(D3DCOMPILER_DLL STREQUAL "")
- message(FATAL_ERROR "To compile WITH_GL_ANGLE you need to set D3DCOMPILER_DLL to the file path of a copy of the DirectX redistributable DLL file: D3DCompiler_46.dll")
+ message(FATAL_ERROR
+ "To compile WITH_GL_ANGLE you need to set D3DCOMPILER_DLL to the file "
+ "path of a copy of the DirectX redistributable DLL file: D3DCompiler_46.dll"
+ )
endif()
endif()
@@ -2493,7 +1121,10 @@ if(WITH_GL_EGL)
if(WITH_SYSTEM_GLES)
if(NOT OPENGLES_EGL_LIBRARY)
- message(FATAL_ERROR "Unable to find OpenGL ES libraries. Install them or disable WITH_SYSTEM_GLES.")
+ message(FATAL_ERROR
+ "Unable to find OpenGL ES libraries. "
+ "Install them or disable WITH_SYSTEM_GLES."
+ )
endif()
list(APPEND BLENDER_GL_LIBRARIES OPENGLES_EGL_LIBRARY)
@@ -2505,7 +1136,10 @@ if(WITH_GL_EGL)
list(APPEND BLENDER_GL_LIBRARIES "${OPENGLES_LIBRARY}" "${OPENGLES_EGL_LIBRARY}")
if(NOT OPENGLES_EGL_LIBRARY)
- message(FATAL_ERROR "To compile WITH_GL_EGL you need to set OPENGLES_EGL_LIBRARY to the file path of an EGL library.")
+ message(FATAL_ERROR
+ "To compile WITH_GL_EGL you need to set OPENGLES_EGL_LIBRARY "
+ "to the file path of an EGL library."
+ )
endif()
endif()
@@ -2517,7 +1151,10 @@ if(WITH_GL_EGL)
mark_as_advanced(OPENGLES_EGL_DLL)
if(NOT OPENGLES_EGL_DLL)
- message(FATAL_ERROR "To compile WITH_GL_EGL you need to set OPENGLES_EGL_DLL to the file path of an EGL runtime dynamic link library (DLL).")
+ message(FATAL_ERROR
+ "To compile WITH_GL_EGL you need to set OPENGLES_EGL_DLL "
+ "to the file path of an EGL runtime dynamic link library (DLL)."
+ )
endif()
endif()
@@ -2682,7 +1319,9 @@ endif()
if(WITH_LIBMV)
set(CERES_DEFINES)
- if(SHARED_PTR_FOUND)
+ if(WITH_CXX11)
+ # nothing to be done
+ elseif(SHARED_PTR_FOUND)
if(SHARED_PTR_TR1_MEMORY_HEADER)
list(APPEND CERES_DEFINES -DCERES_TR1_MEMORY_HEADER)
endif()
@@ -2693,7 +1332,9 @@ if(WITH_LIBMV)
message(FATAL_ERROR "Ceres: Unable to find shared_ptr.")
endif()
- if(HAVE_STD_UNORDERED_MAP_HEADER)
+ if(WITH_CXX11)
+ list(APPEND CERES_DEFINES -DCERES_STD_UNORDERED_MAP)
+ elseif(HAVE_STD_UNORDERED_MAP_HEADER)
if(HAVE_UNORDERED_MAP_IN_STD_NAMESPACE)
list(APPEND CERES_DEFINES -DCERES_STD_UNORDERED_MAP)
else()
@@ -2895,10 +1536,12 @@ endif()
# be most problematic.
if(WITH_PYTHON)
if(NOT EXISTS "${PYTHON_INCLUDE_DIR}/Python.h")
- message(FATAL_ERROR "Missing: \"${PYTHON_INCLUDE_DIR}/Python.h\",\n"
- "Set the cache entry 'PYTHON_INCLUDE_DIR' to point "
- "to a valid python include path. Containing "
- "Python.h for python version \"${PYTHON_VERSION}\"")
+ message(FATAL_ERROR
+ "Missing: \"${PYTHON_INCLUDE_DIR}/Python.h\",\n"
+ "Set the cache entry 'PYTHON_INCLUDE_DIR' to point "
+ "to a valid python include path. Containing "
+ "Python.h for python version \"${PYTHON_VERSION}\""
+ )
endif()
if(WIN32 OR APPLE)
@@ -2916,12 +1559,22 @@ endif()
if(WITH_CXX11)
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
+ # TODO(sergey): Do we want c++11 or gnu-c++11 here?
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(MSVC12)
# Nothing special is needed, C++11 features are available by default.
else()
message(FATAL_ERROR "Compiler ${CMAKE_C_COMPILER_ID} is not supported for C++11 build yet")
endif()
+else()
+ # GCC-6 switched to C++11 by default, which would break linking with existing libraries
+ # by default. So we explicitly disable C++11 for a new GCC so no linking issues happens.
+ if(CMAKE_COMPILER_IS_GNUCC AND (NOT "${CMAKE_C_COMPILER_VERSION}" VERSION_LESS "6.0"))
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++98")
+ # We also disable any of C++11 ABI from usage, so we wouldn't even try to
+ # link to stuff from std::__cxx11 namespace.
+ add_definitions("-D_GLIBCXX_USE_CXX11_ABI=0")
+ endif()
endif()
# Visual Studio has all standards it supports available by default
@@ -3020,6 +1673,14 @@ add_subdirectory(tests)
# CPack for generating packages
include(build_files/cmake/packaging.cmake)
+#-----------------------------------------------------------------------------
+# Use dynamic loading for OpenMP
+if(WITH_BLENDER)
+ openmp_delayload(blender)
+endif(WITH_BLENDER)
+if(WITH_PLAYER)
+ openmp_delayload(blenderplayer)
+endif(WITH_PLAYER)
#-----------------------------------------------------------------------------
# Print Final Configuration
@@ -3036,7 +1697,7 @@ if(FIRST_RUN)
string(LENGTH "${_msg}" _len)
while("32" GREATER "${_len}")
set(_msg "${_msg} ")
- math(EXPR _len "${_len} + 1")
+ math(EXPR _len "${_len} + 1")
endwhile()
set(_config_msg "${_config_msg}\n${_msg}${${_setting}}" PARENT_SCOPE)
@@ -3066,6 +1727,7 @@ if(FIRST_RUN)
info_cfg_option(WITH_FREESTYLE)
info_cfg_option(WITH_OPENCOLORIO)
info_cfg_option(WITH_OPENVDB)
+ info_cfg_option(WITH_ALEMBIC)
info_cfg_text("Compiler Options:")
info_cfg_option(WITH_BUILDINFO)
@@ -3074,6 +1736,7 @@ if(FIRST_RUN)
info_cfg_text("System Options:")
info_cfg_option(WITH_INSTALL_PORTABLE)
+ info_cfg_option(WITH_X11_ALPHA)
info_cfg_option(WITH_X11_XF86VMODE)
info_cfg_option(WITH_X11_XINPUT)
info_cfg_option(WITH_MEM_JEMALLOC)
diff --git a/GNUmakefile b/GNUmakefile
index df2d7051326..1fda1a25a92 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -120,7 +120,7 @@ endif
# -----------------------------------------------------------------------------
# Build Blender
-all: FORCE
+all: .FORCE
@echo
@echo Configuring Blender in \"$(BUILD_DIR)\" ...
@@ -149,13 +149,13 @@ bpy: all
# -----------------------------------------------------------------------------
# Configuration (save some cd'ing around)
-config: FORCE
+config: .FORCE
$(CMAKE_CONFIG_TOOL) "$(BUILD_DIR)"
# -----------------------------------------------------------------------------
# Help for build targets
-help: FORCE
+help: .FORCE
@echo ""
@echo "Convenience targets provided for building blender, (multiple at once can be used)"
@echo " * debug - build a debug binary"
@@ -182,14 +182,20 @@ help: FORCE
@echo " * package_archive - build an archive package"
@echo ""
@echo "Testing Targets (not associated with building blender)"
- @echo " * test - run ctest, currently tests import/export, operator execution and that python modules load"
- @echo " * test_cmake - runs our own cmake file checker which detects errors in the cmake file list definitions"
- @echo " * test_pep8 - checks all python script are pep8 which are tagged to use the stricter formatting"
+ @echo " * test - run ctest, currently tests import/export,"
+ @echo " operator execution and that python modules load"
+ @echo " * test_cmake - runs our own cmake file checker"
+ @echo " which detects errors in the cmake file list definitions"
+ @echo " * test_pep8 - checks all python script are pep8"
+ @echo " which are tagged to use the stricter formatting"
@echo " * test_deprecated - checks for deprecation tags in our code which may need to be removed"
- @echo " * test_style_c - checks C/C++ conforms with blenders style guide: http://wiki.blender.org/index.php/Dev:Doc/CodeStyle"
+ @echo " * test_style_c - checks C/C++ conforms with blenders style guide:"
+ @echo " http://wiki.blender.org/index.php/Dev:Doc/CodeStyle"
@echo " * test_style_c_qtc - same as test_style but outputs QtCreator tasks format"
- @echo " * test_style_osl - checks OpenShadingLanguage conforms with blenders style guide: http://wiki.blender.org/index.php/Dev:Doc/CodeStyle"
- @echo " * test_style_osl_qtc - checks OpenShadingLanguage conforms with blenders style guide: http://wiki.blender.org/index.php/Dev:Doc/CodeStyle"
+ @echo " * test_style_osl - checks OpenShadingLanguage conforms with blenders style guide:"
+ @echo " http://wiki.blender.org/index.php/Dev:Doc/CodeStyle"
+ @echo " * test_style_osl_qtc - checks OpenShadingLanguage conforms with blenders style guide:"
+ @echo " http://wiki.blender.org/index.php/Dev:Doc/CodeStyle"
@echo ""
@echo "Static Source Code Checking (not associated with building blender)"
@echo " * check_cppcheck - run blender source through cppcheck (C & C++)"
@@ -228,13 +234,13 @@ help: FORCE
# -----------------------------------------------------------------------------
# Packages
#
-package_debian: FORCE
+package_debian: .FORCE
cd build_files/package_spec ; DEB_BUILD_OPTIONS="parallel=$(NPROCS)" sh ./build_debian.sh
-package_pacman: FORCE
+package_pacman: .FORCE
cd build_files/package_spec/pacman ; MAKEFLAGS="-j$(NPROCS)" makepkg
-package_archive: FORCE
+package_archive: .FORCE
make -C "$(BUILD_DIR)" -s package_archive
@echo archive in "$(BUILD_DIR)/release"
@@ -242,24 +248,24 @@ package_archive: FORCE
# -----------------------------------------------------------------------------
# Tests
#
-test: FORCE
+test: .FORCE
cd $(BUILD_DIR) ; ctest . --output-on-failure
# run pep8 check check on scripts we distribute.
-test_pep8: FORCE
+test_pep8: .FORCE
$(PYTHON) tests/python/pep8.py > test_pep8.log 2>&1
@echo "written: test_pep8.log"
# run some checks on our cmakefiles.
-test_cmake: FORCE
+test_cmake: .FORCE
$(PYTHON) build_files/cmake/cmake_consistency_check.py > test_cmake_consistency.log 2>&1
@echo "written: test_cmake_consistency.log"
# run deprecation tests, see if we have anything to remove.
-test_deprecated: FORCE
+test_deprecated: .FORCE
$(PYTHON) tests/check_deprecated.py
-test_style_c: FORCE
+test_style_c: .FORCE
# run our own checks on C/C++ style
PYTHONIOENCODING=utf_8 $(PYTHON) \
"$(BLENDER_DIR)/source/tools/check_source/check_style_c.py" \
@@ -267,7 +273,7 @@ test_style_c: FORCE
"$(BLENDER_DIR)/source/creator" \
--no-length-check
-test_style_c_qtc: FORCE
+test_style_c_qtc: .FORCE
# run our own checks on C/C++ style
USE_QTC_TASK=1 \
PYTHONIOENCODING=utf_8 $(PYTHON) \
@@ -280,7 +286,7 @@ test_style_c_qtc: FORCE
@echo "written: test_style.tasks"
-test_style_osl: FORCE
+test_style_osl: .FORCE
# run our own checks on C/C++ style
PYTHONIOENCODING=utf_8 $(PYTHON) \
"$(BLENDER_DIR)/source/tools/check_source/check_style_c.py" \
@@ -288,7 +294,7 @@ test_style_osl: FORCE
"$(BLENDER_DIR)/release/scripts/templates_osl"
-test_style_osl_qtc: FORCE
+test_style_osl_qtc: .FORCE
# run our own checks on C/C++ style
USE_QTC_TASK=1 \
PYTHONIOENCODING=utf_8 $(PYTHON) \
@@ -303,13 +309,13 @@ test_style_osl_qtc: FORCE
# Project Files
#
-project_qtcreator: FORCE
+project_qtcreator: .FORCE
$(PYTHON) build_files/cmake/cmake_qtcreator_project.py "$(BUILD_DIR)"
-project_netbeans: FORCE
+project_netbeans: .FORCE
$(PYTHON) build_files/cmake/cmake_netbeans_project.py "$(BUILD_DIR)"
-project_eclipse: FORCE
+project_eclipse: .FORCE
cmake -G"Eclipse CDT4 - Unix Makefiles" -H"$(BLENDER_DIR)" -B"$(BUILD_DIR)"
@@ -317,40 +323,40 @@ project_eclipse: FORCE
# Static Checking
#
-check_cppcheck: FORCE
+check_cppcheck: .FORCE
$(CMAKE_CONFIG)
cd "$(BUILD_DIR)" ; \
$(PYTHON) "$(BLENDER_DIR)/build_files/cmake/cmake_static_check_cppcheck.py" 2> \
"$(BLENDER_DIR)/check_cppcheck.txt"
@echo "written: check_cppcheck.txt"
-check_clang_array: FORCE
+check_clang_array: .FORCE
$(CMAKE_CONFIG)
cd "$(BUILD_DIR)" ; \
$(PYTHON) "$(BLENDER_DIR)/build_files/cmake/cmake_static_check_clang_array.py"
-check_splint: FORCE
+check_splint: .FORCE
$(CMAKE_CONFIG)
cd "$(BUILD_DIR)" ; \
$(PYTHON) "$(BLENDER_DIR)/build_files/cmake/cmake_static_check_splint.py"
-check_sparse: FORCE
+check_sparse: .FORCE
$(CMAKE_CONFIG)
cd "$(BUILD_DIR)" ; \
$(PYTHON) "$(BLENDER_DIR)/build_files/cmake/cmake_static_check_sparse.py"
-check_smatch: FORCE
+check_smatch: .FORCE
$(CMAKE_CONFIG)
cd "$(BUILD_DIR)" ; \
$(PYTHON) "$(BLENDER_DIR)/build_files/cmake/cmake_static_check_smatch.py"
-check_spelling_py: FORCE
+check_spelling_py: .FORCE
cd "$(BUILD_DIR)" ; \
PYTHONIOENCODING=utf_8 $(PYTHON) \
"$(BLENDER_DIR)/source/tools/check_source/check_spelling.py" \
"$(BLENDER_DIR)/release/scripts"
-check_spelling_c: FORCE
+check_spelling_c: .FORCE
cd "$(BUILD_DIR)" ; \
PYTHONIOENCODING=utf_8 $(PYTHON) \
"$(BLENDER_DIR)/source/tools/check_source/check_spelling.py" \
@@ -359,7 +365,7 @@ check_spelling_c: FORCE
"$(BLENDER_DIR)/intern/guardedalloc" \
"$(BLENDER_DIR)/intern/ghost" \
-check_spelling_c_qtc: FORCE
+check_spelling_c_qtc: .FORCE
cd "$(BUILD_DIR)" ; USE_QTC_TASK=1 \
PYTHONIOENCODING=utf_8 $(PYTHON) \
"$(BLENDER_DIR)/source/tools/check_source/check_spelling.py" \
@@ -370,13 +376,13 @@ check_spelling_c_qtc: FORCE
> \
"$(BLENDER_DIR)/check_spelling_c.tasks"
-check_spelling_osl: FORCE
+check_spelling_osl: .FORCE
cd "$(BUILD_DIR)" ;\
PYTHONIOENCODING=utf_8 $(PYTHON) \
"$(BLENDER_DIR)/source/tools/check_source/check_spelling.py" \
"$(BLENDER_DIR)/intern/cycles/kernel/shaders"
-check_descriptions: FORCE
+check_descriptions: .FORCE
"$(BUILD_DIR)/bin/blender" --background -noaudio --factory-startup --python \
"$(BLENDER_DIR)/source/tools/check_source/check_descriptions.py"
@@ -384,14 +390,14 @@ check_descriptions: FORCE
# Utilities
#
-tgz: FORCE
+tgz: .FORCE
./build_files/utils/build_tgz.sh
-icons: FORCE
+icons: .FORCE
"$(BLENDER_DIR)/release/datafiles/blender_icons_update.py"
"$(BLENDER_DIR)/release/datafiles/prvicons_update.py"
-update: FORCE
+update: .FORCE
if [ -d "../lib" ]; then \
svn update ../lib/* ; \
fi
@@ -404,23 +410,25 @@ update: FORCE
#
# Simple version of ./doc/python_api/sphinx_doc_gen.sh with no PDF generation.
-doc_py: FORCE
- "$(BUILD_DIR)/bin/blender" --background -noaudio --factory-startup --python doc/python_api/sphinx_doc_gen.py
+doc_py: .FORCE
+ "$(BUILD_DIR)/bin/blender" --background -noaudio --factory-startup \
+ --python doc/python_api/sphinx_doc_gen.py
cd doc/python_api ; sphinx-build -b html sphinx-in sphinx-out
@echo "docs written into: '$(BLENDER_DIR)/doc/python_api/sphinx-out/contents.html'"
-doc_doxy: FORCE
+doc_doxy: .FORCE
cd doc/doxygen; doxygen Doxyfile
@echo "docs written into: '$(BLENDER_DIR)/doc/doxygen/html/index.html'"
-doc_dna: FORCE
- "$(BUILD_DIR)/bin/blender" --background -noaudio --factory-startup --python doc/blender_file_format/BlendFileDnaExporter_25.py
+doc_dna: .FORCE
+ "$(BUILD_DIR)/bin/blender" --background -noaudio --factory-startup \
+ --python doc/blender_file_format/BlendFileDnaExporter_25.py
@echo "docs written into: '$(BLENDER_DIR)/doc/blender_file_format/dna.html'"
-doc_man: FORCE
+doc_man: .FORCE
$(PYTHON) doc/manpage/blender.1.py "$(BUILD_DIR)/bin/blender"
-help_features: FORCE
+help_features: .FORCE
@$(PYTHON) -c \
"import re; \
print('\n'.join([ \
@@ -431,9 +439,9 @@ help_features: FORCE
if w.startswith('WITH_')]))" | uniq
-clean: FORCE
+clean: .FORCE
$(MAKE) -C "$(BUILD_DIR)" clean
.PHONY: all
-FORCE:
+.FORCE:
diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh
index 6b9ac8f00fc..d6ea7d99f04 100755
--- a/build_files/build_environment/install_deps.sh
+++ b/build_files/build_environment/install_deps.sh
@@ -25,17 +25,18 @@
ARGS=$( \
getopt \
-o s:i:t:h \
---long source:,install:,tmp:,info:,threads:,help,show-deps,no-sudo,no-confirm,with-all,with-opencollada,\
+--long source:,install:,tmp:,info:,threads:,help,show-deps,no-sudo,no-build,no-confirm,use-cxx11,\
+with-all,with-opencollada,\
ver-ocio:,ver-oiio:,ver-llvm:,ver-osl:,ver-osd:,ver-openvdb:,\
force-all,force-python,force-numpy,force-boost,\
force-ocio,force-openexr,force-oiio,force-llvm,force-osl,force-osd,force-openvdb,\
-force-ffmpeg,force-opencollada,\
+force-ffmpeg,force-opencollada,force-alembic,\
build-all,build-python,build-numpy,build-boost,\
build-ocio,build-openexr,build-oiio,build-llvm,build-osl,build-osd,build-openvdb,\
-build-ffmpeg,build-opencollada,\
+build-ffmpeg,build-opencollada,build-alembic,\
skip-python,skip-numpy,skip-boost,\
skip-ocio,skip-openexr,skip-oiio,skip-llvm,skip-osl,skip-osd,skip-openvdb,\
-skip-ffmpeg,skip-opencollada \
+skip-ffmpeg,skip-opencollada,skip-alembic \
-- "$@" \
)
@@ -97,9 +98,17 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
--no-sudo
Disable use of sudo (this script won't be able to do much though, will just print needed packages...).
+ --no-build
+ Do not build (compile) anything, dependencies not installable with the package manager will remain missing.
+
--no-confirm
Disable any interaction with user (suitable for automated run).
+ --use-cxx11
+ Build all libraries in cpp11 'mode' (will be mandatory soon in blender2.8 branch).
+ NOTE: If your compiler is gcc-6.0 or above, you probably *want* to enable this option (since it's default
+ standard starting from this version).
+
--with-all
By default, a number of optional and not-so-often needed libraries are not installed.
This option will try to install them, at the cost of potential conflicts (depending on
@@ -164,6 +173,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
--build-openvdb
Force the build of OpenVDB.
+ --build-alembic
+ Force the build of Alembic.
+
--build-opencollada
Force the build of OpenCOLLADA.
@@ -213,6 +225,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
--force-openvdb
Force the rebuild of OpenVDB.
+ --force-alembic
+ Force the rebuild of Alembic.
+
--force-opencollada
Force the rebuild of OpenCOLLADA.
@@ -255,6 +270,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
--skip-openvdb
Unconditionally skip OpenVDB installation/building.
+ --skip-alembic
+ Unconditionally skip Alembic installation/building.
+
--skip-opencollada
Unconditionally skip OpenCOLLADA installation/building.
@@ -267,7 +285,9 @@ DO_SHOW_DEPS=false
SUDO="sudo"
+NO_BUILD=false
NO_CONFIRM=false
+USE_CXX11=false
PYTHON_VERSION="3.5.1"
PYTHON_VERSION_MIN="3.5"
@@ -317,14 +337,14 @@ LLVM_FORCE_REBUILD=false
LLVM_SKIP=false
# OSL needs to be compiled for now!
-OSL_VERSION="1.7.1"
+OSL_VERSION="1.7.3"
OSL_VERSION_MIN=$OSL_VERSION
OSL_FORCE_BUILD=false
OSL_FORCE_REBUILD=false
OSL_SKIP=false
# OpenSubdiv needs to be compiled for now
-OSD_VERSION="3.0.2"
+OSD_VERSION="3.0.5"
OSD_VERSION_MIN=$OSD_VERSION
OSD_FORCE_BUILD=false
OSD_FORCE_REBUILD=false
@@ -339,6 +359,13 @@ OPENVDB_FORCE_BUILD=false
OPENVDB_FORCE_REBUILD=false
OPENVDB_SKIP=false
+# Alembic needs to be compiled for now
+ALEMBIC_VERSION="1.6.0"
+ALEMBIC_VERSION_MIN=$ALEMBIC_VERSION
+ALEMBIC_FORCE_BUILD=false
+ALEMBIC_FORCE_REBUILD=false
+ALEMBIC_SKIP=false
+
# Version??
OPENCOLLADA_VERSION="1.3"
OPENCOLLADA_FORCE_BUILD=false
@@ -463,9 +490,18 @@ while true; do
PRINT ""
SUDO=""; shift; continue
;;
+ --no-build)
+ PRINT ""
+ WARNING "--no-build enabled, this script will not be able to install all dependencies..."
+ PRINT ""
+ NO_BUILD=true; shift; continue
+ ;;
--no-confirm)
NO_CONFIRM=true; shift; continue
;;
+ --use-cxx11)
+ USE_CXX11=true; shift; continue
+ ;;
--with-all)
WITH_ALL=true; shift; continue
;;
@@ -515,6 +551,7 @@ while true; do
OPENVDB_FORCE_BUILD=true
OPENCOLLADA_FORCE_BUILD=true
FFMPEG_FORCE_BUILD=true
+ ALEMBIC_FORCE_BUILD=true
shift; continue
;;
--build-python)
@@ -557,6 +594,9 @@ while true; do
--build-ffmpeg)
FFMPEG_FORCE_BUILD=true; shift; continue
;;
+ --build-alembic)
+ ALEMBIC_FORCE_BUILD=true; shift; continue
+ ;;
--force-all)
PYTHON_FORCE_REBUILD=true
NUMPY_FORCE_REBUILD=true
@@ -570,6 +610,7 @@ while true; do
OPENVDB_FORCE_REBUILD=true
OPENCOLLADA_FORCE_REBUILD=true
FFMPEG_FORCE_REBUILD=true
+ ALEMBIC_FORCE_REBUILD=true
shift; continue
;;
--force-python)
@@ -610,6 +651,9 @@ while true; do
--force-ffmpeg)
FFMPEG_FORCE_REBUILD=true; shift; continue
;;
+ --force-alembic)
+ ALEMBIC_FORCE_REBUILD=true; shift; continue
+ ;;
--skip-python)
PYTHON_SKIP=true; shift; continue
;;
@@ -646,6 +690,9 @@ while true; do
--skip-ffmpeg)
FFMPEG_SKIP=true; shift; continue
;;
+ --skip-alembic)
+ ALEMBIC_SKIP=true; shift; continue
+ ;;
--)
# no more arguments to parse
break
@@ -673,7 +720,7 @@ NUMPY_SOURCE=( "http://sourceforge.net/projects/numpy/files/NumPy/$NUMPY_VERSION
_boost_version_nodots=`echo "$BOOST_VERSION" | sed -r 's/\./_/g'`
BOOST_SOURCE=( "http://sourceforge.net/projects/boost/files/boost/$BOOST_VERSION/boost_$_boost_version_nodots.tar.bz2/download" )
-BOOST_BUILD_MODULES="--with-system --with-filesystem --with-thread --with-regex --with-locale --with-date_time --with-wave --with-iostreams"
+BOOST_BUILD_MODULES="--with-system --with-filesystem --with-thread --with-regex --with-locale --with-date_time --with-wave --with-iostreams --with-python --with-program_options"
OCIO_SOURCE=( "https://github.com/imageworks/OpenColorIO/tarball/v$OCIO_VERSION" )
@@ -702,7 +749,7 @@ OSL_SOURCE_REPO=( "https://github.com/Nazg-Gul/OpenShadingLanguage.git" )
OSL_SOURCE_REPO_UID="7d40ff5fe8e47b030042afb92d0e955f5aa96f48"
OSL_SOURCE_REPO_BRANCH="blender-fixes"
-OSD_USE_REPO=true
+OSD_USE_REPO=false
# Script foo to make the version string compliant with the archive name:
# ${Varname//SearchForThisChar/ReplaceWithThisChar}
OSD_SOURCE=( "https://github.com/PixarAnimationStudios/OpenSubdiv/archive/v${OSD_VERSION//./_}.tar.gz" )
@@ -717,13 +764,30 @@ OPENVDB_SOURCE=( "https://github.com/dreamworksanimation/openvdb/archive/v${OPEN
#~ OPENVDB_SOURCE_REPO_UID="404659fffa659da075d1c9416e4fc939139a84ee"
#~ OPENVDB_SOURCE_REPO_BRANCH="dev"
+ALEMBIC_USE_REPO=false
+ALEMBIC_SOURCE=( "https://github.com/alembic/alembic/archive/${ALEMBIC_VERSION}.tar.gz" )
+# ALEMBIC_SOURCE_REPO=( "https://github.com/alembic/alembic.git" )
+# ALEMBIC_SOURCE_REPO_UID="e6c90d4faa32c4550adeaaf3f556dad4b73a92bb"
+# ALEMBIC_SOURCE_REPO_BRANCH="master"
+
OPENCOLLADA_SOURCE=( "https://github.com/KhronosGroup/OpenCOLLADA.git" )
OPENCOLLADA_REPO_UID="3335ac164e68b2512a40914b14c74db260e6ff7d"
OPENCOLLADA_REPO_BRANCH="master"
FFMPEG_SOURCE=( "http://ffmpeg.org/releases/ffmpeg-$FFMPEG_VERSION.tar.bz2" )
-
+CXXFLAGS_BACK=$CXXFLAGS
+if [ "$USE_CXX11" = true ]; then
+ WARNING "You are trying to use c++11, this *should* go smoothely with any very recent distribution
+However, if you are experiencing linking errors (also when building Blender itself), please try the following:
+ * Re-run this script with `--build-all --force-all` options.
+ * Ensure your gcc version is at the very least 4.8, if possible you should really rather use gcc-5.1 or above.
+
+Please note that until the transition to C++11-built libraries if completed in your distribution, situation will
+remain fuzzy and incompatibilities may happen..."
+ CXXFLAGS="$CXXFLAGS -std=c++11"
+ export CXXFLAGS
+fi
#### Show Dependencies ####
@@ -736,7 +800,7 @@ Those libraries should be available as packages in all recent distributions (opt
* libjpeg, libpng, libtiff, [libopenjpeg], [libopenal].
* libx11, libxcursor, libxi, libxrandr, libxinerama (and other libx... as needed).
* libsqlite3, libbz2, libssl, libfftw3, libxml2, libtinyxml, yasm, libyaml-cpp.
- * libsdl1.2, libglew, libglewmx.\""
+ * libsdl1.2, libglew, [libglewmx].\""
DEPS_SPECIFIC_INFO="\"BUILDABLE DEPENDENCIES:
@@ -757,7 +821,8 @@ You may also want to build them yourself (optional ones are [between brackets]):
* [OpenShadingLanguage $OSL_VERSION_MIN] (from $OSL_SOURCE_REPO, branch $OSL_SOURCE_REPO_BRANCH, commit $OSL_SOURCE_REPO_UID).
* [OpenSubDiv $OSD_VERSION_MIN] (from $OSD_SOURCE_REPO, branch $OSD_SOURCE_REPO_BRANCH, commit $OSD_SOURCE_REPO_UID).
* [OpenVDB $OPENVDB_VERSION_MIN] (from $OPENVDB_SOURCE), [Blosc $OPENVDB_BLOSC_VERSION] (from $OPENVDB_BLOSC_SOURCE).
- * [OpenCollada] (from $OPENCOLLADA_SOURCE, branch $OPENCOLLADA_REPO_BRANCH, commit $OPENCOLLADA_REPO_UID).\""
+ * [OpenCollada] (from $OPENCOLLADA_SOURCE, branch $OPENCOLLADA_REPO_BRANCH, commit $OPENCOLLADA_REPO_UID).
+ * [Alembic $ALEMBIC_VERSION] (from $ALEMBIC_SOURCE).\""
if [ "$DO_SHOW_DEPS" = true ]; then
PRINT ""
@@ -909,7 +974,7 @@ prepare_opt() {
# Check whether the current package needs to be recompiled, based on a dummy file containing a magic number in its name...
magic_compile_check() {
- if [ -f $INST/.$1-magiccheck-$2 ]; then
+ if [ -f $INST/.$1-magiccheck-$2-$USE_CXX11 ]; then
return 0
else
return 1
@@ -918,7 +983,7 @@ magic_compile_check() {
magic_compile_set() {
rm -f $INST/.$1-magiccheck-*
- touch $INST/.$1-magiccheck-$2
+ touch $INST/.$1-magiccheck-$2-$USE_CXX11
}
# Note: should clean nicely in $INST, but not in $SRC, when we switch to a new version of a lib...
@@ -967,6 +1032,11 @@ clean_Python() {
}
compile_Python() {
+ if [ "$NO_BUILD" = true ]; then
+ WARNING "--no-build enabled, Python will not be compiled!"
+ return
+ fi
+
# To be changed each time we make edits that would modify the compiled result!
py_magic=1
_init_python
@@ -1032,6 +1102,11 @@ clean_Numpy() {
}
compile_Numpy() {
+ if [ "$NO_BUILD" = true ]; then
+ WARNING "--no-build enabled, Numpy will not be compiled!"
+ return
+ fi
+
# To be changed each time we make edits that would modify the compiled result!
numpy_magic=0
_init_numpy
@@ -1092,8 +1167,13 @@ clean_Boost() {
}
compile_Boost() {
+ if [ "$NO_BUILD" = true ]; then
+ WARNING "--no-build enabled, Boost will not be compiled!"
+ return
+ fi
+
# To be changed each time we make edits that would modify the compiled result!
- boost_magic=10
+ boost_magic=11
_init_boost
@@ -1165,6 +1245,11 @@ clean_OCIO() {
}
compile_OCIO() {
+ if [ "$NO_BUILD" = true ]; then
+ WARNING "--no-build enabled, OpenColorIO will not be compiled!"
+ return
+ fi
+
# To be changed each time we make edits that would modify the compiled result!
ocio_magic=1
_init_ocio
@@ -1256,6 +1341,11 @@ clean_ILMBASE() {
}
compile_ILMBASE() {
+ if [ "$NO_BUILD" = true ]; then
+ WARNING "--no-build enabled, ILMBase will not be compiled!"
+ return
+ fi
+
# To be changed each time we make edits that would modify the compiled result!
ilmbase_magic=10
_init_ilmbase
@@ -1343,6 +1433,11 @@ clean_OPENEXR() {
}
compile_OPENEXR() {
+ if [ "$NO_BUILD" = true ]; then
+ WARNING "--no-build enabled, OpenEXR will not be compiled!"
+ return
+ fi
+
# To be changed each time we make edits that would modify the compiled result!
openexr_magic=14
@@ -1458,6 +1553,11 @@ clean_OIIO() {
}
compile_OIIO() {
+ if [ "$NO_BUILD" = true ]; then
+ WARNING "--no-build enabled, OpenImageIO will not be compiled!"
+ return
+ fi
+
# To be changed each time we make edits that would modify the compiled result!
oiio_magic=16
_init_oiio
@@ -1543,6 +1643,10 @@ compile_OIIO() {
# fi
cmake_d="$cmake_d -D USE_OCIO=OFF"
+ if [ "$USE_CXX11" = true ]; then
+ cmake_d="$cmake_d -D OIIO_BUILD_CPP11=ON"
+ fi
+
if file /bin/cp | grep -q '32-bit'; then
cflags="-fPIC -m32 -march=i686"
else
@@ -1589,6 +1693,11 @@ clean_LLVM() {
}
compile_LLVM() {
+ if [ "$NO_BUILD" = true ]; then
+ WARNING "--no-build enabled, LLVM will not be compiled!"
+ return
+ fi
+
# To be changed each time we make edits that would modify the compiled result!
llvm_magic=3
_init_llvm
@@ -1686,8 +1795,13 @@ clean_OSL() {
}
compile_OSL() {
+ if [ "$NO_BUILD" = true ]; then
+ WARNING "--no-build enabled, OpenShadingLanguage will not be compiled!"
+ return
+ fi
+
# To be changed each time we make edits that would modify the compiled result!
- osl_magic=20
+ osl_magic=21
_init_osl
# Clean install if needed!
@@ -1812,8 +1926,13 @@ clean_OSD() {
}
compile_OSD() {
+ if [ "$NO_BUILD" = true ]; then
+ WARNING "--no-build enabled, OpenSubdiv will not be compiled!"
+ return
+ fi
+
# To be changed each time we make edits that would modify the compiled result!
- osd_magic=1
+ osd_magic=2
_init_osd
# Clean install if needed!
@@ -1904,6 +2023,11 @@ clean_BLOSC() {
}
compile_BLOSC() {
+ if [ "$NO_BUILD" = true ]; then
+ WARNING "--no-build enabled, Blosc will not be compiled!"
+ return
+ fi
+
# To be changed each time we make edits that would modify the compiled result!
blosc_magic=0
_init_blosc
@@ -1986,6 +2110,11 @@ clean_OPENVDB() {
}
compile_OPENVDB() {
+ if [ "$NO_BUILD" = true ]; then
+ WARNING "--no-build enabled, OpenVDB will not be compiled!"
+ return
+ fi
+
compile_BLOSC
PRINT ""
@@ -2068,6 +2197,102 @@ compile_OPENVDB() {
run_ldconfig "openvdb"
}
+#### Build Alembic ####
+_init_alembic() {
+ _src=$SRC/alembic-$ALEMBIC_VERSION
+ _git=false
+ _inst=$INST/alembic-$ALEMBIC_VERSION
+ _inst_shortcut=$INST/alembic
+}
+
+clean_ALEMBIC() {
+ _init_alembic
+ _clean
+}
+
+compile_ALEMBIC() {
+ if [ "$NO_BUILD" = true ]; then
+ WARNING "--no-build enabled, Alembic will not be compiled!"
+ return
+ fi
+
+ compile_HDF5
+ PRINT ""
+
+ # To be changed each time we make edits that would modify the compiled result!
+ alembic_magic=2
+ _init_alembic
+
+ # Clean install if needed!
+ magic_compile_check alembic-$ALEMBIC_VERSION $alembic_magic
+ if [ $? -eq 1 -o "$ALEMBIC_FORCE_REBUILD" = true ]; then
+ clean_ALEMBIC
+ fi
+
+ if [ ! -d $_inst ]; then
+ INFO "Building Alembic-$ALEMBIC_VERSION"
+
+ prepare_opt
+
+ if [ ! -d $_src -o true ]; then
+ mkdir -p $SRC
+ download ALEMBIC_SOURCE[@] "$_src.tar.gz"
+
+ INFO "Unpacking Alembic-$ALEMBIC_VERSION"
+ tar -C $SRC -xf $_src.tar.gz
+ fi
+
+ cd $_src
+
+ cmake_d="-D CMAKE_INSTALL_PREFIX=$_inst"
+
+ if [ -d $INST/boost ]; then
+ cmake_d="$cmake_d -D BOOST_ROOT=$INST/boost"
+ cmake_d="$cmake_d -D USE_STATIC_BOOST=ON"
+ else
+ cmake_d="$cmake_d -D USE_STATIC_BOOST=OFF"
+ fi
+
+ if [ "$_with_built_openexr" = true ]; then
+ cmake_d="$cmake_d -D ILMBASE_ROOT=$INST/openexr"
+ cmake_d="$cmake_d -D USE_ARNOLD=OFF"
+ cmake_d="$cmake_d -D USE_BINARIES=OFF"
+ cmake_d="$cmake_d -D USE_EXAMPLES=OFF"
+ cmake_d="$cmake_d -D USE_HDF5=OFF"
+ cmake_d="$cmake_d -D USE_MAYA=OFF"
+ cmake_d="$cmake_d -D USE_PRMAN=OFF"
+ cmake_d="$cmake_d -D USE_PYALEMBIC=OFF"
+ cmake_d="$cmake_d -D USE_STATIC_HDF5=OFF"
+ cmake_d="$cmake_d -D ALEMBIC_ILMBASE_LINK_STATIC=OFF"
+ cmake_d="$cmake_d -D ALEMBIC_SHARED_LIBS=OFF"
+ cmake_d="$cmake_d -D ALEMBIC_LIB_USES_BOOST=ON"
+ cmake_d="$cmake_d -D ALEMBIC_LIB_USES_TR1=OFF"
+ INFO "ILMBASE_ROOT=$INST/openexr"
+ fi
+
+ cmake $cmake_d ./
+ make -j$THREADS install
+ make clean
+
+ if [ -d $_inst ]; then
+ _create_inst_shortcut
+ else
+ ERROR "Alembic-$ALEMBIC_VERSION failed to compile, exiting"
+ exit 1
+ fi
+
+ magic_compile_set alembic-$ALEMBIC_VERSION $alembic_magic
+
+ cd $CWD
+ INFO "Done compiling Alembic-$ALEMBIC_VERSION!"
+ else
+ INFO "Own Alembic-$ALEMBIC_VERSION is up to date, nothing to do!"
+ INFO "If you want to force rebuild of this lib, use the --force-alembic option."
+ fi
+
+ run_ldconfig "alembic"
+}
+
#### Build OpenCOLLADA ####
_init_opencollada() {
_src=$SRC/OpenCOLLADA-$OPENCOLLADA_VERSION
@@ -2082,6 +2307,11 @@ clean_OpenCOLLADA() {
}
compile_OpenCOLLADA() {
+ if [ "$NO_BUILD" = true ]; then
+ WARNING "--no-build enabled, OpenCOLLADA will not be compiled!"
+ return
+ fi
+
# To be changed each time we make edits that would modify the compiled results!
opencollada_magic=9
_init_opencollada
@@ -2161,6 +2391,11 @@ clean_FFmpeg() {
}
compile_FFmpeg() {
+ if [ "$NO_BUILD" = true ]; then
+ WARNING "--no-build enabled, ffmpeg will not be compiled!"
+ return
+ fi
+
# To be changed each time we make edits that would modify the compiled result!
ffmpeg_magic=5
_init_ffmpeg
@@ -2352,8 +2587,9 @@ install_DEB() {
git libfreetype6-dev libx11-dev flex bison libtbb-dev libxxf86vm-dev \
libxcursor-dev libxi-dev wget libsqlite3-dev libxrandr-dev libxinerama-dev \
libbz2-dev libncurses5-dev libssl-dev liblzma-dev libreadline-dev $OPENJPEG_DEV \
- libopenal-dev libglew-dev libglewmx-dev yasm $THEORA_DEV $VORBIS_DEV $OGG_DEV \
+ libopenal-dev libglew-dev yasm $THEORA_DEV $VORBIS_DEV $OGG_DEV \
libsdl1.2-dev libfftw3-dev patch bzip2 libxml2-dev libtinyxml-dev libjemalloc-dev"
+ # libglewmx-dev (broken in deb testing currently...)
OPENJPEG_USE=true
VORBIS_USE=true
@@ -2666,6 +2902,17 @@ install_DEB() {
fi
fi
+ PRINT ""
+ if [ "$ALEMBIC_SKIP" = true ]; then
+ WARNING "Skipping Alembic installation, as requested..."
+ elif [ "$ALEMBIC_FORCE_BUILD" = true ]; then
+ INFO "Forced Alembic building, as requested..."
+ compile_ALEMBIC
+ else
+ # No package currently, only HDF5!
+ compile_ALEMBIC
+ fi
+
if [ "$WITH_OPENCOLLADA" = true ]; then
_do_compile_collada=false
@@ -3203,6 +3450,17 @@ install_RPM() {
compile_OPENVDB
fi
+ PRINT ""
+ if [ "$ALEMBIC_SKIP" = true ]; then
+ WARNING "Skipping Alembic installation, as requested..."
+ elif [ "$ALEMBIC_FORCE_BUILD" = true ]; then
+ INFO "Forced Alembic building, as requested..."
+ compile_ALEMBIC
+ else
+ # No package currently!
+ compile_ALEMBIC
+ fi
+
if [ "$WITH_OPENCOLLADA" = true ]; then
PRINT ""
@@ -3342,7 +3600,15 @@ install_ARCH() {
OGG_DEV="libogg"
THEORA_DEV="libtheora"
- _packages="base-devel git cmake \
+ BASE_DEVEL="base-devel"
+
+ # Avoid conflicts when gcc-multilib is installed
+ pacman -Qi gcc-multilib &>/dev/null
+ if [ $? -eq 0 ]; then
+ BASE_DEVEL=`pacman -Sgq base-devel | sed -e 's/^gcc$/gcc-multilib/g' | paste -s -d' '`
+ fi
+
+ _packages="$BASE_DEVEL git cmake \
libxi libxcursor libxrandr libxinerama glew libpng libtiff wget openal \
$OPENJPEG_DEV $VORBIS_DEV $OGG_DEV $THEORA_DEV yasm sdl fftw intel-tbb \
libxml2 yaml-cpp tinyxml python-requests jemalloc"
@@ -3605,6 +3871,16 @@ install_ARCH() {
fi
fi
+ PRINT ""
+ if [ "$ALEMBIC_SKIP" = true ]; then
+ WARNING "Skipping Alembic installation, as requested..."
+ elif [ "$ALEMBIC_FORCE_BUILD" = true ]; then
+ INFO "Forced Alembic building, as requested..."
+ compile_ALEMBIC
+ else
+ compile_ALEMBIC
+ fi
+
if [ "$WITH_OPENCOLLADA" = true ]; then
PRINT ""
@@ -3912,7 +4188,13 @@ print_info() {
_buildargs="-U *SNDFILE* -U *PYTHON* -U *BOOST* -U *Boost*"
_buildargs="$_buildargs -U *OPENCOLORIO* -U *OPENEXR* -U *OPENIMAGEIO* -U *LLVM* -U *CYCLES*"
- _buildargs="$_buildargs -U *OPENSUBDIV* -U *OPENVDB* -U *COLLADA* -U *FFMPEG*"
+ _buildargs="$_buildargs -U *OPENSUBDIV* -U *OPENVDB* -U *COLLADA* -U *FFMPEG* -U *ALEMBIC*"
+
+ if [ "$USE_CXX11" = true ]; then
+ _1="-D WITH_CXX11=ON"
+ PRINT " $_1"
+ _buildargs="$_buildargs $_1"
+ fi
_1="-D WITH_CODEC_SNDFILE=ON"
PRINT " $_1"
@@ -4018,6 +4300,17 @@ print_info() {
_buildargs="$_buildargs $_1"
fi
+ if [ "$ALEMBIC_SKIP" = false ]; then
+ _1="-D WITH_ALEMBIC=ON"
+ PRINT " $_1"
+ _buildargs="$_buildargs $_1"
+ if [ -d $INST/alembic ]; then
+ _1="-D ALEMBIC_ROOT_DIR=$INST/alembic"
+ PRINT " $_1"
+ _buildargs="$_buildargs $_1"
+ fi
+ fi
+
if [ "$NO_SYSTEM_GLEW" = true ]; then
_1="-D WITH_SYSTEM_GLEW=OFF"
PRINT " $_1"
@@ -4066,3 +4359,6 @@ PRINT ""
# Switch back to user language.
LANG=LANG_BACK
export LANG
+
+CXXFLAGS=$CXXFLAGS_BACK
+export CXXFLAGS
diff --git a/build_files/buildbot/master.cfg b/build_files/buildbot/master.cfg
index 70dcbfbc1df..8bd23357fc6 100644
--- a/build_files/buildbot/master.cfg
+++ b/build_files/buildbot/master.cfg
@@ -285,7 +285,7 @@ def generic_builder(id, libdir='', branch='', rsync=False):
maxsize=150 * 1024 * 1024,
workdir='install'))
f.addStep(MasterShellCommand(name='unpack',
- command=['python', unpack_script, filename],
+ command=['python2.7', unpack_script, filename],
description='unpacking',
descriptionDone='unpacked'))
return f
diff --git a/build_files/buildbot/slave_compile.py b/build_files/buildbot/slave_compile.py
index 5e25d9f3f04..c2bfd882fde 100644
--- a/build_files/buildbot/slave_compile.py
+++ b/build_files/buildbot/slave_compile.py
@@ -72,14 +72,28 @@ if 'cmake' in builder:
# Set up OSX architecture
if builder.endswith('x86_64_10_6_cmake'):
cmake_extra_options.append('-DCMAKE_OSX_ARCHITECTURES:STRING=x86_64')
- cmake_extra_options.append('-DCUDA_NVCC_EXECUTABLE=/usr/local/cuda-hack/bin/nvcc')
+ cmake_extra_options.append('-DCUDA_NVCC_EXECUTABLE=/usr/local/cuda8-hack/bin/nvcc')
+ cmake_extra_options.append('-DWITH_CODEC_QUICKTIME=OFF')
+ cmake_extra_options.append('-DCMAKE_OSX_DEPLOYMENT_TARGET=10.6')
+ build_cubins = False
+
elif builder.startswith('win'):
- if builder.startswith('win64'):
- cmake_options.append(['-G', '"Visual Studio 12 2013 Win64"'])
- elif builder.startswith('win32'):
- bits = 32
- cmake_options.append(['-G', '"Visual Studio 12 2013"'])
+ if builder.endswith('_vc2015'):
+ if builder.startswith('win64'):
+ cmake_options.extend(['-G', 'Visual Studio 14 2015 Win64'])
+ elif builder.startswith('win32'):
+ bits = 32
+ cmake_options.extend(['-G', 'Visual Studio 14 2015'])
+ cmake_extra_options.append('-DCUDA_NVCC_FLAGS=--cl-version;2013;' +
+ '--compiler-bindir;C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\bin')
+ else:
+ if builder.startswith('win64'):
+ cmake_options.extend(['-G', 'Visual Studio 12 2013 Win64'])
+ elif builder.startswith('win32'):
+ bits = 32
+ cmake_options.extend(['-G', 'Visual Studio 12 2013'])
+ cmake_extra_options.append('-DCUDA_NVCC_EXECUTABLE:FILEPATH=C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v8.0/bin/nvcc.exe')
elif builder.startswith('linux'):
tokens = builder.split("_")
@@ -99,10 +113,13 @@ if 'cmake' in builder:
cuda_chroot_name = 'buildbot_' + deb_name + '_x86_64'
targets = ['player', 'blender', 'cuda']
+ cmake_extra_options.append('-DCUDA_NVCC_EXECUTABLE=/usr/local/cuda-8.0/bin/nvcc')
+
cmake_options.append("-C" + os.path.join(blender_dir, cmake_config_file))
# Prepare CMake options needed to configure cuda binaries compilation.
cuda_cmake_options.append("-DWITH_CYCLES_CUDA_BINARIES=%s" % ('ON' if build_cubins else 'OFF'))
+ cuda_cmake_options.append("-DCYCLES_CUDA_BINARIES_ARCH=sm_20;sm_21;sm_30;sm_35;sm_37;sm_50;sm_52;sm_60;sm_61")
if build_cubins or 'cuda' in targets:
if bits == 32:
cuda_cmake_options.append("-DCUDA_64_BIT_DEVICE_CODE=OFF")
diff --git a/build_files/buildbot/slave_pack.py b/build_files/buildbot/slave_pack.py
index b27017568cb..490f0456045 100644
--- a/build_files/buildbot/slave_pack.py
+++ b/build_files/buildbot/slave_pack.py
@@ -108,6 +108,8 @@ if builder.find('cmake') != -1:
platform += 'i386'
elif builder.endswith('ppc_10_6_cmake'):
platform += 'ppc'
+ if builder.endswith('vc2015'):
+ platform += "-vc14"
builderified_name = 'blender-{}-{}-{}'.format(blender_full_version, git_hash, platform)
if branch != '':
builderified_name = branch + "-" + builderified_name
diff --git a/build_files/cmake/Modules/FindAlembic.cmake b/build_files/cmake/Modules/FindAlembic.cmake
new file mode 100644
index 00000000000..1f61b5ef462
--- /dev/null
+++ b/build_files/cmake/Modules/FindAlembic.cmake
@@ -0,0 +1,70 @@
+# - Find Alembic library
+# Find the native Alembic includes and libraries
+# This module defines
+# ALEMBIC_INCLUDE_DIRS, where to find Alembic headers, Set when
+# ALEMBIC_INCLUDE_DIR is found.
+# ALEMBIC_LIBRARIES, libraries to link against to use Alembic.
+# ALEMBIC_ROOT_DIR, The base directory to search for Alembic.
+# This can also be an environment variable.
+# ALEMBIC_FOUND, If false, do not try to use Alembic.
+#
+
+#=============================================================================
+# Copyright 2016 Blender Foundation.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+
+# If ALEMBIC_ROOT_DIR was defined in the environment, use it.
+IF(NOT ALEMBIC_ROOT_DIR AND NOT $ENV{ALEMBIC_ROOT_DIR} STREQUAL "")
+ SET(ALEMBIC_ROOT_DIR $ENV{ALEMBIC_ROOT_DIR})
+ENDIF()
+
+SET(_alembic_SEARCH_DIRS
+ ${ALEMBIC_ROOT_DIR}
+ /usr/local
+ /sw # Fink
+ /opt/local # DarwinPorts
+ /opt/csw # Blastwave
+ /opt/lib/alembic
+)
+
+FIND_PATH(ALEMBIC_INCLUDE_DIR
+ NAMES
+ Alembic/Abc/All.h
+ HINTS
+ ${_alembic_SEARCH_DIRS}
+ PATH_SUFFIXES
+ include
+)
+
+FIND_LIBRARY(ALEMBIC_LIBRARY
+ NAMES
+ Alembic
+ HINTS
+ ${_alembic_SEARCH_DIRS}
+ PATH_SUFFIXES
+ lib64 lib lib/static
+)
+
+# handle the QUIETLY and REQUIRED arguments and set ALEMBIC_FOUND to TRUE if
+# all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(ALEMBIC DEFAULT_MSG ALEMBIC_LIBRARY ALEMBIC_INCLUDE_DIR)
+
+IF(ALEMBIC_FOUND)
+ SET(ALEMBIC_LIBRARIES ${ALEMBIC_LIBRARY})
+ SET(ALEMBIC_INCLUDE_DIRS ${ALEMBIC_INCLUDE_DIR})
+ENDIF(ALEMBIC_FOUND)
+
+MARK_AS_ADVANCED(
+ ALEMBIC_INCLUDE_DIR
+ ALEMBIC_LIBRARY
+)
+
+UNSET(_alembic_SEARCH_DIRS)
diff --git a/build_files/cmake/Modules/FindHDF5.cmake b/build_files/cmake/Modules/FindHDF5.cmake
new file mode 100644
index 00000000000..56ceda8fb5e
--- /dev/null
+++ b/build_files/cmake/Modules/FindHDF5.cmake
@@ -0,0 +1,69 @@
+# - Find HDF5 library
+# Find the native HDF5 includes and libraries
+# This module defines
+# HDF5_INCLUDE_DIRS, where to find hdf5.h, Set when HDF5_INCLUDE_DIR is found.
+# HDF5_LIBRARIES, libraries to link against to use HDF5.
+# HDF5_ROOT_DIR, The base directory to search for HDF5.
+# This can also be an environment variable.
+# HDF5_FOUND, If false, do not try to use HDF5.
+#
+
+#=============================================================================
+# Copyright 2016 Blender Foundation.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+
+# If HDF5_ROOT_DIR was defined in the environment, use it.
+IF(NOT HDF5_ROOT_DIR AND NOT $ENV{HDF5_ROOT_DIR} STREQUAL "")
+ SET(HDF5_ROOT_DIR $ENV{HDF5_ROOT_DIR})
+ENDIF()
+
+SET(_hdf5_SEARCH_DIRS
+ ${HDF5_ROOT_DIR}
+ /usr/local
+ /sw # Fink
+ /opt/local # DarwinPorts
+ /opt/csw # Blastwave
+ /opt/lib/hdf5
+)
+
+FIND_LIBRARY(HDF5_LIBRARY
+ NAMES
+ hdf5
+ HINTS
+ ${_hdf5_SEARCH_DIRS}
+ PATH_SUFFIXES
+ lib64 lib
+)
+
+FIND_PATH(HDF5_INCLUDE_DIR
+ NAMES
+ hdf5.h
+ HINTS
+ ${_hdf5_SEARCH_DIRS}
+ PATH_SUFFIXES
+ include
+)
+
+# handle the QUIETLY and REQUIRED arguments and set HDF5_FOUND to TRUE if
+# all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(HDF5 DEFAULT_MSG HDF5_LIBRARY HDF5_INCLUDE_DIR)
+
+IF(HDF5_FOUND)
+ SET(HDF5_LIBRARIES ${HDF5_LIBRARY})
+ SET(HDF5_INCLUDE_DIRS ${HDF5_INCLUDE_DIR})
+ENDIF(HDF5_FOUND)
+
+MARK_AS_ADVANCED(
+ HDF5_INCLUDE_DIR
+ HDF5_LIBRARY
+)
+
+UNSET(_hdf5_SEARCH_DIRS)
diff --git a/build_files/cmake/Modules/FindJack.cmake b/build_files/cmake/Modules/FindJack.cmake
index 9a847fabf70..caafa3c34a1 100644
--- a/build_files/cmake/Modules/FindJack.cmake
+++ b/build_files/cmake/Modules/FindJack.cmake
@@ -1,15 +1,15 @@
-# - Find Jack library
-# Find the native Jack includes and library
+# - Find JACK library
+# Find the native JACK includes and library
# This module defines
# JACK_INCLUDE_DIRS, where to find jack.h, Set when
# JACK_INCLUDE_DIR is found.
-# JACK_LIBRARIES, libraries to link against to use Jack.
-# JACK_ROOT_DIR, The base directory to search for Jack.
+# JACK_LIBRARIES, libraries to link against to use JACK.
+# JACK_ROOT_DIR, The base directory to search for JACK.
# This can also be an environment variable.
-# JACK_FOUND, If false, do not try to use Jack.
+# JACK_FOUND, If false, do not try to use JACK.
#
# also defined, but not for general use are
-# JACK_LIBRARY, where to find the Jack library.
+# JACK_LIBRARY, where to find the JACK library.
#=============================================================================
# Copyright 2011 Blender Foundation.
diff --git a/build_files/cmake/Modules/GTestTesting.cmake b/build_files/cmake/Modules/GTestTesting.cmake
index 3ccca1f199c..96c06ef8eb5 100644
--- a/build_files/cmake/Modules/GTestTesting.cmake
+++ b/build_files/cmake/Modules/GTestTesting.cmake
@@ -23,6 +23,7 @@ macro(BLENDER_SRC_GTEST_EX NAME SRC EXTRA_LIBS DO_ADD_TEST)
${CMAKE_SOURCE_DIR}/extern/glog/src
${CMAKE_SOURCE_DIR}/extern/gflags/src
${CMAKE_SOURCE_DIR}/extern/gtest/include
+ ${CMAKE_SOURCE_DIR}/extern/gmock/include
)
unset(_current_include_directories)
@@ -33,6 +34,7 @@ macro(BLENDER_SRC_GTEST_EX NAME SRC EXTRA_LIBS DO_ADD_TEST)
bf_testing_main
bf_intern_guardedalloc
extern_gtest
+ extern_gmock
# needed for glog
${PTHREADS_LIBRARIES}
extern_glog
diff --git a/build_files/cmake/buildinfo.cmake b/build_files/cmake/buildinfo.cmake
index af0ccd250e8..1f0a283ba0e 100644
--- a/build_files/cmake/buildinfo.cmake
+++ b/build_files/cmake/buildinfo.cmake
@@ -27,13 +27,12 @@ if(EXISTS ${SOURCE_DIR}/.git)
OUTPUT_VARIABLE MY_WC_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE)
- execute_process(COMMAND git branch --list master --contains ${MY_WC_HASH}
+ execute_process(COMMAND git branch --list master blender-v* --contains ${MY_WC_HASH}
WORKING_DIRECTORY ${SOURCE_DIR}
OUTPUT_VARIABLE _git_contains_check
OUTPUT_STRIP_TRAILING_WHITESPACE)
- STRING(REGEX REPLACE "^[ \t]+" "" _git_contains_check "${_git_contains_check}")
- if(_git_contains_check STREQUAL "master")
+ if(NOT _git_contains_check STREQUAL "")
set(MY_WC_BRANCH "master")
else()
execute_process(COMMAND git show-ref --tags -d
@@ -48,6 +47,22 @@ if(EXISTS ${SOURCE_DIR}/.git)
if(_git_tag_hashes MATCHES "${_git_head_hash}")
set(MY_WC_BRANCH "master")
+ else()
+ execute_process(COMMAND git branch --contains ${MY_WC_HASH}
+ WORKING_DIRECTORY ${SOURCE_DIR}
+ OUTPUT_VARIABLE _git_contains_branches
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ string(REGEX REPLACE "^\\*[ \t]+" "" _git_contains_branches "${_git_contains_branches}")
+ string(REGEX REPLACE "[\r\n]+" ";" _git_contains_branches "${_git_contains_branches}")
+ string(REGEX REPLACE ";[ \t]+" ";" _git_contains_branches "${_git_contains_branches}")
+ foreach(_branch ${_git_contains_branches})
+ if (NOT "${_branch}" MATCHES "\\(HEAD.*")
+ set(MY_WC_BRANCH "${_branch}")
+ break()
+ endif()
+ endforeach()
+ unset(_branch)
+ unset(_git_contains_branches)
endif()
unset(_git_tag_hashes)
diff --git a/build_files/cmake/clang_array_check.py b/build_files/cmake/clang_array_check.py
index 9f22a9c43c1..6eaaebce52f 100644
--- a/build_files/cmake/clang_array_check.py
+++ b/build_files/cmake/clang_array_check.py
@@ -239,8 +239,8 @@ def file_check_arg_sizes(tu):
if 0:
print("---",
" <~> ".join(
- [" ".join([t.spelling for t in C.get_tokens()])
- for C in node.get_children()]
+ [" ".join([t.spelling for t in C.get_tokens()])
+ for C in node.get_children()]
))
# print(node.location)
diff --git a/build_files/cmake/cmake_consistency_check.py b/build_files/cmake/cmake_consistency_check.py
index 6cd66b7640c..3d06790758a 100755
--- a/build_files/cmake/cmake_consistency_check.py
+++ b/build_files/cmake/cmake_consistency_check.py
@@ -29,11 +29,11 @@ if not sys.version.startswith("3"):
sys.exit(1)
from cmake_consistency_check_config import (
- IGNORE,
- UTF8_CHECK,
- SOURCE_DIR,
- BUILD_DIR,
- )
+ IGNORE,
+ UTF8_CHECK,
+ SOURCE_DIR,
+ BUILD_DIR,
+)
import os
diff --git a/build_files/cmake/cmake_consistency_check_config.py b/build_files/cmake/cmake_consistency_check_config.py
index 7e7cd40dbea..9ec1c095a9c 100644
--- a/build_files/cmake/cmake_consistency_check_config.py
+++ b/build_files/cmake/cmake_consistency_check_config.py
@@ -31,7 +31,7 @@ IGNORE = (
"extern/carve/patches/files/random.h",
"intern/audaspace/SRC/AUD_SRCResampleFactory.h",
"intern/audaspace/SRC/AUD_SRCResampleReader.h",
- )
+)
UTF8_CHECK = True
diff --git a/build_files/cmake/cmake_netbeans_project.py b/build_files/cmake/cmake_netbeans_project.py
index 8d66c101c6a..5b074b6975a 100755
--- a/build_files/cmake/cmake_netbeans_project.py
+++ b/build_files/cmake/cmake_netbeans_project.py
@@ -37,19 +37,19 @@ if not project_info.init(sys.argv[-1]):
sys.exit(1)
from project_info import (
- SIMPLE_PROJECTFILE,
- SOURCE_DIR,
- CMAKE_DIR,
- PROJECT_DIR,
- source_list,
- is_project_file,
- is_c_header,
- # is_py,
- cmake_advanced_info,
- cmake_compiler_defines,
- cmake_cache_var,
- project_name_get,
- )
+ SIMPLE_PROJECTFILE,
+ SOURCE_DIR,
+ CMAKE_DIR,
+ PROJECT_DIR,
+ source_list,
+ is_project_file,
+ is_c_header,
+ # is_py,
+ cmake_advanced_info,
+ cmake_compiler_defines,
+ cmake_cache_var,
+ project_name_get,
+)
import os
diff --git a/build_files/cmake/cmake_qtcreator_project.py b/build_files/cmake/cmake_qtcreator_project.py
index 9c0a02a7a0c..231784df588 100755
--- a/build_files/cmake/cmake_qtcreator_project.py
+++ b/build_files/cmake/cmake_qtcreator_project.py
@@ -43,17 +43,17 @@ def quote_define(define):
def create_qtc_project_main(name):
from project_info import (
- SIMPLE_PROJECTFILE,
- SOURCE_DIR,
- # CMAKE_DIR,
- PROJECT_DIR,
- source_list,
- is_project_file,
- is_c_header,
- cmake_advanced_info,
- cmake_compiler_defines,
- project_name_get,
- )
+ SIMPLE_PROJECTFILE,
+ SOURCE_DIR,
+ # CMAKE_DIR,
+ PROJECT_DIR,
+ source_list,
+ is_project_file,
+ is_c_header,
+ cmake_advanced_info,
+ cmake_compiler_defines,
+ project_name_get,
+ )
files = list(source_list(SOURCE_DIR, filename_check=is_project_file))
files_rel = [os.path.relpath(f, start=PROJECT_DIR) for f in files]
@@ -69,7 +69,7 @@ def create_qtc_project_main(name):
with open(os.path.join(PROJECT_DIR, "%s.includes" % FILE_NAME), 'w') as f:
f.write("\n".join(sorted(list(set(os.path.dirname(f)
- for f in files_rel if is_c_header(f))))))
+ for f in files_rel if is_c_header(f))))))
qtc_prj = os.path.join(PROJECT_DIR, "%s.creator" % FILE_NAME)
with open(qtc_prj, 'w') as f:
@@ -87,7 +87,7 @@ def create_qtc_project_main(name):
# for some reason it doesnt give all internal includes
includes = list(set(includes) | set(os.path.dirname(f)
- for f in files_rel if is_c_header(f)))
+ for f in files_rel if is_c_header(f)))
includes.sort()
# be tricky, get the project name from CMake if we can!
@@ -125,13 +125,13 @@ def create_qtc_project_main(name):
def create_qtc_project_python(name):
from project_info import (
- SOURCE_DIR,
- # CMAKE_DIR,
- PROJECT_DIR,
- source_list,
- is_py,
- project_name_get,
- )
+ SOURCE_DIR,
+ # CMAKE_DIR,
+ PROJECT_DIR,
+ source_list,
+ is_py,
+ project_name_get,
+ )
files = list(source_list(SOURCE_DIR, filename_check=is_py))
files_rel = [os.path.relpath(f, start=PROJECT_DIR) for f in files]
@@ -161,24 +161,24 @@ def argparse_create():
import argparse
parser = argparse.ArgumentParser(
- description="This script generates Qt Creator project files for Blender",
- )
+ description="This script generates Qt Creator project files for Blender",
+ )
parser.add_argument(
- "-n", "--name",
- dest="name",
- metavar='NAME', type=str,
- help="Override default project name (\"Blender\")",
- required=False,
- )
+ "-n", "--name",
+ dest="name",
+ metavar='NAME', type=str,
+ help="Override default project name (\"Blender\")",
+ required=False,
+ )
parser.add_argument(
- "-b", "--build-dir",
- dest="build_dir",
- metavar='BUILD_DIR', type=str,
- help="Specify the build path (or fallback to the $PWD)",
- required=False,
- )
+ "-b", "--build-dir",
+ dest="build_dir",
+ metavar='BUILD_DIR', type=str,
+ help="Specify the build path (or fallback to the $PWD)",
+ required=False,
+ )
return parser
diff --git a/build_files/cmake/cmake_static_check_clang_array.py b/build_files/cmake/cmake_static_check_clang_array.py
index 597d1d2b980..7b3b73985fa 100644
--- a/build_files/cmake/cmake_static_check_clang_array.py
+++ b/build_files/cmake/cmake_static_check_clang_array.py
@@ -32,7 +32,7 @@ USE_QUIET = (os.environ.get("QUIET", None) is not None)
CHECKER_IGNORE_PREFIX = [
"extern",
"intern/moto",
- ]
+]
CHECKER_BIN = "python2"
@@ -42,7 +42,7 @@ CHECKER_ARGS = [
"-I" + os.path.join(project_source_info.SOURCE_DIR, "extern", "glew", "include"),
# stupid but needed
"-Dbool=char"
- ]
+]
def main():
diff --git a/build_files/cmake/cmake_static_check_cppcheck.py b/build_files/cmake/cmake_static_check_cppcheck.py
index 3504b005adc..ef4ee71dec2 100644
--- a/build_files/cmake/cmake_static_check_cppcheck.py
+++ b/build_files/cmake/cmake_static_check_cppcheck.py
@@ -32,7 +32,7 @@ USE_QUIET = (os.environ.get("QUIET", None) is not None)
CHECKER_IGNORE_PREFIX = [
"extern",
"intern/moto",
- ]
+]
CHECKER_BIN = "cppcheck"
@@ -43,7 +43,7 @@ CHECKER_ARGS = [
"--max-configs=1", # speeds up execution
# "--check-config", # when includes are missing
"--enable=all", # if you want sixty hundred pedantic suggestions
- ]
+]
if USE_QUIET:
CHECKER_ARGS.append("--quiet")
diff --git a/build_files/cmake/cmake_static_check_smatch.py b/build_files/cmake/cmake_static_check_smatch.py
index f525187e22c..29afdb79819 100644
--- a/build_files/cmake/cmake_static_check_smatch.py
+++ b/build_files/cmake/cmake_static_check_smatch.py
@@ -25,13 +25,13 @@
CHECKER_IGNORE_PREFIX = [
"extern",
"intern/moto",
- ]
+]
CHECKER_BIN = "smatch"
CHECKER_ARGS = [
"--full-path",
"--two-passes",
- ]
+]
import project_source_info
import subprocess
diff --git a/build_files/cmake/cmake_static_check_sparse.py b/build_files/cmake/cmake_static_check_sparse.py
index 6d1c4e3d6a2..600370cca25 100644
--- a/build_files/cmake/cmake_static_check_sparse.py
+++ b/build_files/cmake/cmake_static_check_sparse.py
@@ -25,11 +25,11 @@
CHECKER_IGNORE_PREFIX = [
"extern",
"intern/moto",
- ]
+]
CHECKER_BIN = "sparse"
CHECKER_ARGS = [
- ]
+]
import project_source_info
import subprocess
diff --git a/build_files/cmake/cmake_static_check_splint.py b/build_files/cmake/cmake_static_check_splint.py
index 46d8808e89d..069d1b7ff25 100644
--- a/build_files/cmake/cmake_static_check_splint.py
+++ b/build_files/cmake/cmake_static_check_splint.py
@@ -25,7 +25,7 @@
CHECKER_IGNORE_PREFIX = [
"extern",
"intern/moto",
- ]
+]
CHECKER_BIN = "splint"
@@ -61,7 +61,7 @@ CHECKER_ARGS = [
# dummy, witjout this splint complains with:
# /usr/include/bits/confname.h:31:27: *** Internal Bug at cscannerHelp.c:2428: Unexpanded macro not function or constant: int _PC_MAX_CANON
"-D_PC_MAX_CANON=0",
- ]
+]
import project_source_info
diff --git a/build_files/cmake/config/blender_full.cmake b/build_files/cmake/config/blender_full.cmake
index b50b42416fb..cb18500c7ca 100644
--- a/build_files/cmake/config/blender_full.cmake
+++ b/build_files/cmake/config/blender_full.cmake
@@ -4,6 +4,7 @@
# cmake -C../blender/build_files/cmake/config/blender_full.cmake ../blender
#
+set(WITH_ALEMBIC ON CACHE BOOL "" FORCE)
set(WITH_BUILDINFO ON CACHE BOOL "" FORCE)
set(WITH_BULLET ON CACHE BOOL "" FORCE)
set(WITH_CODEC_AVI ON CACHE BOOL "" FORCE)
@@ -11,6 +12,7 @@ set(WITH_CODEC_FFMPEG ON CACHE BOOL "" FORCE)
set(WITH_CODEC_SNDFILE ON CACHE BOOL "" FORCE)
set(WITH_CYCLES ON CACHE BOOL "" FORCE)
set(WITH_CYCLES_OSL ON CACHE BOOL "" FORCE)
+set(WITH_CYCLES_OPENSUBDIV ON CACHE BOOL "" FORCE)
set(WITH_FFTW3 ON CACHE BOOL "" FORCE)
set(WITH_LIBMV ON CACHE BOOL "" FORCE)
set(WITH_LIBMV_SCHUR_SPECIALIZATIONS ON CACHE BOOL "" FORCE)
diff --git a/build_files/cmake/config/blender_lite.cmake b/build_files/cmake/config/blender_lite.cmake
index 3c53ee7ae23..537134eb357 100644
--- a/build_files/cmake/config/blender_lite.cmake
+++ b/build_files/cmake/config/blender_lite.cmake
@@ -8,6 +8,7 @@
set(WITH_INSTALL_PORTABLE ON CACHE BOOL "" FORCE)
set(WITH_SYSTEM_GLEW ON CACHE BOOL "" FORCE)
+set(WITH_ALEMBIC OFF CACHE BOOL "" FORCE)
set(WITH_BUILDINFO OFF CACHE BOOL "" FORCE)
set(WITH_BULLET OFF CACHE BOOL "" FORCE)
set(WITH_CODEC_AVI OFF CACHE BOOL "" FORCE)
@@ -15,6 +16,7 @@ set(WITH_CODEC_FFMPEG OFF CACHE BOOL "" FORCE)
set(WITH_CODEC_SNDFILE OFF CACHE BOOL "" FORCE)
set(WITH_CYCLES OFF CACHE BOOL "" FORCE)
set(WITH_CYCLES_OSL OFF CACHE BOOL "" FORCE)
+set(WITH_CYCLES_OPENSUBDIV OFF CACHE BOOL "" FORCE)
set(WITH_FFTW3 OFF CACHE BOOL "" FORCE)
set(WITH_LIBMV OFF CACHE BOOL "" FORCE)
set(WITH_LLVM OFF CACHE BOOL "" FORCE)
@@ -47,6 +49,7 @@ set(WITH_OPENCOLLADA OFF CACHE BOOL "" FORCE)
set(WITH_OPENCOLORIO OFF CACHE BOOL "" FORCE)
set(WITH_OPENIMAGEIO OFF CACHE BOOL "" FORCE)
set(WITH_OPENMP OFF CACHE BOOL "" FORCE)
+set(WITH_OPENSUBDIV OFF CACHE BOOL "" FORCE)
set(WITH_OPENVDB OFF CACHE BOOL "" FORCE)
set(WITH_RAYOPTIMIZATION OFF CACHE BOOL "" FORCE)
set(WITH_SDL OFF CACHE BOOL "" FORCE)
diff --git a/build_files/cmake/config/blender_release.cmake b/build_files/cmake/config/blender_release.cmake
new file mode 100644
index 00000000000..050db91e75e
--- /dev/null
+++ b/build_files/cmake/config/blender_release.cmake
@@ -0,0 +1,79 @@
+# Turn everything ON thats expected for an official release builds.
+#
+# Example usage:
+# cmake -C../blender/build_files/cmake/config/blender_release.cmake ../blender
+#
+
+set(WITH_ALEMBIC ON CACHE BOOL "" FORCE)
+set(WITH_BUILDINFO ON CACHE BOOL "" FORCE)
+set(WITH_BULLET ON CACHE BOOL "" FORCE)
+set(WITH_CODEC_AVI ON CACHE BOOL "" FORCE)
+set(WITH_CODEC_FFMPEG ON CACHE BOOL "" FORCE)
+set(WITH_CODEC_SNDFILE ON CACHE BOOL "" FORCE)
+set(WITH_CYCLES ON CACHE BOOL "" FORCE)
+set(WITH_CYCLES_OSL ON CACHE BOOL "" FORCE)
+set(WITH_CYCLES_OPENSUBDIV ON CACHE BOOL "" FORCE)
+set(WITH_FFTW3 ON CACHE BOOL "" FORCE)
+set(WITH_LIBMV ON CACHE BOOL "" FORCE)
+set(WITH_LIBMV_SCHUR_SPECIALIZATIONS ON CACHE BOOL "" FORCE)
+set(WITH_GAMEENGINE ON CACHE BOOL "" FORCE)
+set(WITH_COMPOSITOR ON CACHE BOOL "" FORCE)
+set(WITH_FREESTYLE ON CACHE BOOL "" FORCE)
+set(WITH_GHOST_XDND ON CACHE BOOL "" FORCE)
+set(WITH_IK_SOLVER ON CACHE BOOL "" FORCE)
+set(WITH_IK_ITASC ON CACHE BOOL "" FORCE)
+set(WITH_IMAGE_CINEON ON CACHE BOOL "" FORCE)
+set(WITH_IMAGE_DDS ON CACHE BOOL "" FORCE)
+set(WITH_IMAGE_FRAMESERVER ON CACHE BOOL "" FORCE)
+set(WITH_IMAGE_HDR ON CACHE BOOL "" FORCE)
+set(WITH_IMAGE_OPENEXR ON CACHE BOOL "" FORCE)
+set(WITH_IMAGE_OPENJPEG ON CACHE BOOL "" FORCE)
+set(WITH_IMAGE_TIFF ON CACHE BOOL "" FORCE)
+set(WITH_INPUT_NDOF ON CACHE BOOL "" FORCE)
+set(WITH_INTERNATIONAL ON CACHE BOOL "" FORCE)
+set(WITH_JACK ON CACHE BOOL "" FORCE)
+set(WITH_LZMA ON CACHE BOOL "" FORCE)
+set(WITH_LZO ON CACHE BOOL "" FORCE)
+set(WITH_MOD_BOOLEAN ON CACHE BOOL "" FORCE)
+set(WITH_MOD_FLUID ON CACHE BOOL "" FORCE)
+set(WITH_MOD_REMESH ON CACHE BOOL "" FORCE)
+set(WITH_MOD_SMOKE ON CACHE BOOL "" FORCE)
+set(WITH_MOD_OCEANSIM ON CACHE BOOL "" FORCE)
+set(WITH_AUDASPACE ON CACHE BOOL "" FORCE)
+set(WITH_OPENAL ON CACHE BOOL "" FORCE)
+set(WITH_OPENCOLLADA ON CACHE BOOL "" FORCE)
+set(WITH_OPENCOLORIO ON CACHE BOOL "" FORCE)
+set(WITH_OPENMP ON CACHE BOOL "" FORCE)
+set(WITH_OPENVDB ON CACHE BOOL "" FORCE)
+set(WITH_OPENVDB_BLOSC ON CACHE BOOL "" FORCE)
+set(WITH_PYTHON_INSTALL ON CACHE BOOL "" FORCE)
+set(WITH_RAYOPTIMIZATION ON CACHE BOOL "" FORCE)
+set(WITH_SDL ON CACHE BOOL "" FORCE)
+set(WITH_X11_XINPUT ON CACHE BOOL "" FORCE)
+set(WITH_X11_XF86VMODE ON CACHE BOOL "" FORCE)
+
+set(WITH_PLAYER ON CACHE BOOL "" FORCE)
+set(WITH_MEM_JEMALLOC ON CACHE BOOL "" FORCE)
+set(WITH_CYCLES_CUDA_BINARIES ON CACHE BOOL "" FORCE)
+set(CYCLES_CUDA_BINARIES_ARCH sm_20;sm_21;sm_30;sm_35;sm_37;sm_50;sm_52;sm_60;sm_61 CACHE STRING "" FORCE)
+
+# platform dependent options
+if(UNIX AND NOT APPLE)
+ set(WITH_JACK ON CACHE BOOL "" FORCE)
+ set(WITH_DOC_MANPAGE ON CACHE BOOL "" FORCE)
+ set(WITH_OPENSUBDIV ON CACHE BOOL "" FORCE)
+elseif(WIN32)
+ set(WITH_JACK OFF CACHE BOOL "" FORCE)
+ if(NOT CMAKE_COMPILER_IS_GNUCC)
+ set(WITH_OPENSUBDIV ON CACHE BOOL "" FORCE)
+ else()
+ # MinGW exceptions
+ set(WITH_OPENSUBDIV OFF CACHE BOOL "" FORCE)
+ set(WITH_CODEC_SNDFILE OFF CACHE BOOL "" FORCE)
+ set(WITH_CYCLES_OSL OFF CACHE BOOL "" FORCE)
+ endif()
+elseif(APPLE)
+ set(WITH_JACK ON CACHE BOOL "" FORCE)
+ set(WITH_CODEC_QUICKTIME ON CACHE BOOL "" FORCE)
+ set(WITH_OPENSUBDIV OFF CACHE BOOL "" FORCE)
+endif()
diff --git a/build_files/cmake/config/bpy_module.cmake b/build_files/cmake/config/bpy_module.cmake
index 41140151f04..854d6e49370 100644
--- a/build_files/cmake/config/bpy_module.cmake
+++ b/build_files/cmake/config/bpy_module.cmake
@@ -32,3 +32,4 @@ set(WITH_OPENCOLLADA OFF CACHE BOOL "" FORCE)
set(WITH_INTERNATIONAL OFF CACHE BOOL "" FORCE)
set(WITH_BULLET OFF CACHE BOOL "" FORCE)
set(WITH_OPENVDB OFF CACHE BOOL "" FORCE)
+set(WITH_ALEMBIC OFF CACHE BOOL "" FORCE)
diff --git a/build_files/cmake/example_scripts/make_quicky.py b/build_files/cmake/example_scripts/make_quicky.py
index 76d4df32f86..49c284e354d 100755
--- a/build_files/cmake/example_scripts/make_quicky.py
+++ b/build_files/cmake/example_scripts/make_quicky.py
@@ -74,7 +74,7 @@ def main():
"rebuild_cache",
"depend",
"cmake_check_build_system",
- ])
+ ])
targets -= set(bad)
diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake
index 7f19e22c39e..2e3a1907063 100644
--- a/build_files/cmake/macros.cmake
+++ b/build_files/cmake/macros.cmake
@@ -196,8 +196,33 @@ function(blender_source_group
endfunction()
+# Support per-target CMake flags
+# Read from: CMAKE_C_FLAGS_**** (made upper case) when set.
+#
+# 'name' should alway match the target name,
+# use this macro before add_library or add_executable.
+#
+# Optionally takes an arg passed to set(), eg PARENT_SCOPE.
+macro(add_cc_flags_custom_test
+ name
+ )
+
+ string(TOUPPER ${name} _name_upper)
+ if(DEFINED CMAKE_C_FLAGS_${_name_upper})
+ message(STATUS "Using custom CFLAGS: CMAKE_C_FLAGS_${_name_upper} in \"${CMAKE_CURRENT_SOURCE_DIR}\"")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${_name_upper}}" ${ARGV1})
+ endif()
+ if(DEFINED CMAKE_CXX_FLAGS_${_name_upper})
+ message(STATUS "Using custom CXXFLAGS: CMAKE_CXX_FLAGS_${_name_upper} in \"${CMAKE_CURRENT_SOURCE_DIR}\"")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${_name_upper}}" ${ARGV1})
+ endif()
+ unset(_name_upper)
+
+endmacro()
+
+
# only MSVC uses SOURCE_GROUP
-function(blender_add_lib_nolist
+function(blender_add_lib__impl
name
sources
includes
@@ -225,6 +250,18 @@ function(blender_add_lib_nolist
endfunction()
+function(blender_add_lib_nolist
+ name
+ sources
+ includes
+ includes_sys
+ )
+
+ add_cc_flags_custom_test(${name} PARENT_SCOPE)
+
+ blender_add_lib__impl(${name} "${sources}" "${includes}" "${includes_sys}")
+endfunction()
+
function(blender_add_lib
name
sources
@@ -232,7 +269,9 @@ function(blender_add_lib
includes_sys
)
- blender_add_lib_nolist(${name} "${sources}" "${includes}" "${includes_sys}")
+ add_cc_flags_custom_test(${name} PARENT_SCOPE)
+
+ blender_add_lib__impl(${name} "${sources}" "${includes}" "${includes_sys}")
set_property(GLOBAL APPEND PROPERTY BLENDER_LINK_LIBS ${name})
endfunction()
@@ -294,6 +333,11 @@ function(SETUP_LIBDIRS)
link_directories(${LLVM_LIBPATH})
endif()
+ if(WITH_ALEMBIC)
+ link_directories(${ALEMBIC_LIBPATH})
+ link_directories(${HDF5_LIBPATH})
+ endif()
+
if(WIN32 AND NOT UNIX)
link_directories(${PTHREADS_LIBPATH})
endif()
@@ -315,7 +359,6 @@ function(setup_liblinks
target_link_libraries(
${target}
${PNG_LIBRARIES}
- ${ZLIB_LIBRARIES}
${FREETYPE_LIBRARY}
)
@@ -372,7 +415,7 @@ function(setup_liblinks
if(WITH_OPENCOLORIO)
target_link_libraries(${target} ${OPENCOLORIO_LIBRARIES})
endif()
- if(WITH_OPENSUBDIV)
+ if(WITH_OPENSUBDIV OR WITH_CYCLES_OPENSUBDIV)
if(WIN32 AND NOT UNIX)
file_list_suffix(OPENSUBDIV_LIBRARIES_DEBUG "${OPENSUBDIV_LIBRARIES}" "_d")
target_link_libraries_debug(${target} "${OPENSUBDIV_LIBRARIES_DEBUG}")
@@ -395,6 +438,9 @@ function(setup_liblinks
endif()
endif()
target_link_libraries(${target} ${JPEG_LIBRARIES})
+ if(WITH_ALEMBIC)
+ target_link_libraries(${target} ${ALEMBIC_LIBRARIES} ${HDF5_LIBRARIES})
+ endif()
if(WITH_IMAGE_OPENEXR)
target_link_libraries(${target} ${OPENEXR_LIBRARIES})
endif()
@@ -435,9 +481,6 @@ function(setup_liblinks
if(WITH_MEM_JEMALLOC)
target_link_libraries(${target} ${JEMALLOC_LIBRARIES})
endif()
- if(WITH_INPUT_NDOF)
- target_link_libraries(${target} ${NDOF_LIBRARIES})
- endif()
if(WITH_MOD_CLOTH_ELTOPO)
target_link_libraries(${target} ${LAPACK_LIBRARIES})
endif()
@@ -451,6 +494,9 @@ function(setup_liblinks
if(WITH_OPENMP_STATIC)
target_link_libraries(${target} ${OpenMP_LIBRARIES})
endif()
+ if(WITH_INPUT_NDOF)
+ target_link_libraries(${target} ${NDOF_LIBRARIES})
+ endif()
endif()
# We put CLEW and CUEW here because OPENSUBDIV_LIBRARIES dpeends on them..
@@ -463,11 +509,17 @@ function(setup_liblinks
endif()
endif()
+ target_link_libraries(
+ ${target}
+ ${ZLIB_LIBRARIES}
+ )
+
#system libraries with no dependencies such as platform link libs or opengl should go last
target_link_libraries(${target}
${BLENDER_GL_LIBRARIES})
- target_link_libraries(${target} ${PLATFORM_LINKLIBS} ${CMAKE_DL_LIBS})
+ #target_link_libraries(${target} ${PLATFORM_LINKLIBS} ${CMAKE_DL_LIBS})
+ target_link_libraries(${target} ${PLATFORM_LINKLIBS})
endfunction()
@@ -487,6 +539,7 @@ function(SETUP_BLENDER_SORTED_LIBS)
if(WITH_CYCLES)
list(APPEND BLENDER_LINK_LIBS
cycles_render
+ cycles_graph
cycles_bvh
cycles_device
cycles_kernel
@@ -551,11 +604,11 @@ function(SETUP_BLENDER_SORTED_LIBS)
bf_modifiers
bf_bmesh
bf_gpu
+ bf_blenloader
bf_blenkernel
bf_physics
bf_nodes
bf_rna
- bf_blenloader
bf_imbuf
bf_blenlib
bf_depsgraph
@@ -567,6 +620,7 @@ function(SETUP_BLENDER_SORTED_LIBS)
bf_imbuf_openimageio
bf_imbuf_dds
bf_collada
+ bf_alembic
bf_intern_elbeem
bf_intern_memutil
bf_intern_guardedalloc
@@ -600,6 +654,7 @@ function(SETUP_BLENDER_SORTED_LIBS)
bf_intern_dualcon
bf_intern_cycles
cycles_render
+ cycles_graph
cycles_bvh
cycles_device
cycles_kernel
@@ -659,10 +714,6 @@ function(SETUP_BLENDER_SORTED_LIBS)
list(APPEND BLENDER_SORTED_LIBS bf_quicktime)
endif()
- if(WITH_INPUT_NDOF)
- list(APPEND BLENDER_SORTED_LIBS bf_intern_ghostndof3dconnexion)
- endif()
-
if(WITH_MOD_BOOLEAN)
list(APPEND BLENDER_SORTED_LIBS extern_carve)
endif()
@@ -687,7 +738,15 @@ function(SETUP_BLENDER_SORTED_LIBS)
list_insert_after(BLENDER_SORTED_LIBS "ge_logic_ngnetwork" "extern_bullet")
endif()
- if(WITH_OPENSUBDIV)
+ if(WITH_GAMEENGINE_DECKLINK)
+ list(APPEND BLENDER_SORTED_LIBS bf_intern_decklink)
+ endif()
+
+ if(WIN32)
+ list(APPEND BLENDER_SORTED_LIBS bf_intern_gpudirect)
+ endif()
+
+ if(WITH_OPENSUBDIV OR WITH_CYCLES_OPENSUBDIV)
list(APPEND BLENDER_SORTED_LIBS bf_intern_opensubdiv)
endif()
@@ -803,7 +862,15 @@ macro(TEST_UNORDERED_MAP_SUPPORT)
# UNORDERED_MAP_NAMESPACE, namespace for unordered_map, if found
include(CheckIncludeFileCXX)
- CHECK_INCLUDE_FILE_CXX("unordered_map" HAVE_STD_UNORDERED_MAP_HEADER)
+
+ # Workaround for newer GCC (6.x+) where C++11 was enabled by default, which lead us
+ # to a situation when there is <unordered_map> include but which can't be used uless
+ # C++11 is enabled.
+ if(CMAKE_COMPILER_IS_GNUCC AND (NOT "${CMAKE_C_COMPILER_VERSION}" VERSION_LESS "6.0") AND (NOT WITH_CXX11))
+ set(HAVE_STD_UNORDERED_MAP_HEADER False)
+ else()
+ CHECK_INCLUDE_FILE_CXX("unordered_map" HAVE_STD_UNORDERED_MAP_HEADER)
+ endif()
if(HAVE_STD_UNORDERED_MAP_HEADER)
# Even so we've found unordered_map header file it doesn't
# mean unordered_map and unordered_set will be declared in
@@ -873,8 +940,16 @@ macro(TEST_SHARED_PTR_SUPPORT)
# otherwise it's assumed to be defined in std namespace.
include(CheckIncludeFileCXX)
+ include(CheckCXXSourceCompiles)
set(SHARED_PTR_FOUND FALSE)
- CHECK_INCLUDE_FILE_CXX(memory HAVE_STD_MEMORY_HEADER)
+ # Workaround for newer GCC (6.x+) where C++11 was enabled by default, which lead us
+ # to a situation when there is <unordered_map> include but which can't be used uless
+ # C++11 is enabled.
+ if(CMAKE_COMPILER_IS_GNUCC AND (NOT "${CMAKE_C_COMPILER_VERSION}" VERSION_LESS "6.0") AND (NOT WITH_CXX11))
+ set(HAVE_STD_MEMORY_HEADER False)
+ else()
+ CHECK_INCLUDE_FILE_CXX(memory HAVE_STD_MEMORY_HEADER)
+ endif()
if(HAVE_STD_MEMORY_HEADER)
# Finding the memory header doesn't mean that shared_ptr is in std
# namespace.
@@ -882,7 +957,6 @@ macro(TEST_SHARED_PTR_SUPPORT)
# In particular, MSVC 2008 has shared_ptr declared in std::tr1. In
# order to support this, we do an extra check to see which namespace
# should be used.
- include(CheckCXXSourceCompiles)
CHECK_CXX_SOURCE_COMPILES("#include <memory>
int main() {
std::shared_ptr<int> int_ptr;
@@ -1050,6 +1124,19 @@ macro(remove_strict_flags_file
endmacro()
+# External libs may need 'signed char' to be default.
+macro(remove_cc_flag_unsigned_char)
+ if(CMAKE_C_COMPILER_ID MATCHES "^(GNU|Clang|Intel)$")
+ remove_cc_flag("-funsigned-char")
+ elseif(MSVC)
+ remove_cc_flag("/J")
+ else()
+ message(WARNING
+ "Compiler '${CMAKE_C_COMPILER_ID}' failed to disable 'unsigned char' flag."
+ "Build files need updating."
+ )
+ endif()
+endmacro()
function(ADD_CHECK_C_COMPILER_FLAG
_CFLAGS
@@ -1474,3 +1561,44 @@ function(print_all_vars)
message("${_var}=${${_var}}")
endforeach()
endfunction()
+
+macro(openmp_delayload
+ projectname
+ )
+ if(MSVC)
+ if(WITH_OPENMP)
+ if(MSVC_VERSION EQUAL 1800)
+ set(OPENMP_DLL_NAME "vcomp120")
+ else()
+ set(OPENMP_DLL_NAME "vcomp140")
+ endif()
+ SET_TARGET_PROPERTIES(${projectname} PROPERTIES LINK_FLAGS_RELEASE "/DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib")
+ SET_TARGET_PROPERTIES(${projectname} PROPERTIES LINK_FLAGS_DEBUG "/DELAYLOAD:${OPENMP_DLL_NAME}d.dll delayimp.lib")
+ SET_TARGET_PROPERTIES(${projectname} PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib")
+ SET_TARGET_PROPERTIES(${projectname} PROPERTIES LINK_FLAGS_MINSIZEREL "/DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib")
+ endif(WITH_OPENMP)
+ endif(MSVC)
+endmacro()
+
+MACRO(WINDOWS_SIGN_TARGET target)
+ if (WITH_WINDOWS_CODESIGN)
+ if (!SIGNTOOL_EXE)
+ error("Codesigning is enabled, but signtool is not found")
+ else()
+ if (WINDOWS_CODESIGN_PFX_PASSWORD)
+ set(CODESIGNPASSWORD /p ${WINDOWS_CODESIGN_PFX_PASSWORD})
+ else()
+ if ($ENV{PFXPASSWORD})
+ set(CODESIGNPASSWORD /p $ENV{PFXPASSWORD})
+ else()
+ message( FATAL_ERROR "WITH_WINDOWS_CODESIGN is on but WINDOWS_CODESIGN_PFX_PASSWORD not set, and environment variable PFXPASSWORD not found, unable to sign code.")
+ endif()
+ endif()
+ add_custom_command(TARGET ${target}
+ POST_BUILD
+ COMMAND ${SIGNTOOL_EXE} sign /f ${WINDOWS_CODESIGN_PFX} ${CODESIGNPASSWORD} $<TARGET_FILE:${target}>
+ VERBATIM
+ )
+ endif()
+ endif()
+ENDMACRO()
diff --git a/build_files/cmake/packaging.cmake b/build_files/cmake/packaging.cmake
index afdbc644b4e..c7063ed6772 100644
--- a/build_files/cmake/packaging.cmake
+++ b/build_files/cmake/packaging.cmake
@@ -38,7 +38,21 @@ unset(MY_WC_HASH)
# Force Package Name
execute_process(COMMAND date "+%Y%m%d" OUTPUT_VARIABLE CPACK_DATE OUTPUT_STRIP_TRAILING_WHITESPACE)
string(TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWER)
-set(CPACK_PACKAGE_FILE_NAME ${PROJECT_NAME_LOWER}-${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}-git${CPACK_DATE}.${BUILD_REV}-${CMAKE_SYSTEM_PROCESSOR})
+if (MSVC)
+ if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
+ set(PACKAGE_ARCH windows64)
+ else()
+ set(PACKAGE_ARCH windows32)
+ endif()
+else(MSVC)
+ set(PACKAGE_ARCH ${CMAKE_SYSTEM_PROCESSOR})
+endif()
+
+if (CPACK_OVERRIDE_PACKAGENAME)
+ set(CPACK_PACKAGE_FILE_NAME ${CPACK_OVERRIDE_PACKAGENAME}-${PACKAGE_ARCH})
+else()
+ set(CPACK_PACKAGE_FILE_NAME ${PROJECT_NAME_LOWER}-${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}-git${CPACK_DATE}.${BUILD_REV}-${PACKAGE_ARCH})
+endif()
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
# RPM packages
@@ -83,6 +97,8 @@ if(WIN32)
endif()
set(CPACK_PACKAGE_EXECUTABLES "blender" "blender")
+set(CPACK_CREATE_DESKTOP_LINKS "blender" "blender")
+
include(CPack)
# Target for build_archive.py script, to automatically pass along
diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake
new file mode 100644
index 00000000000..129969ad16c
--- /dev/null
+++ b/build_files/cmake/platform/platform_apple.cmake
@@ -0,0 +1,465 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2016, Blender Foundation
+# All rights reserved.
+#
+# Contributor(s): Sergey Sharybin.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+# Libraries configuration for Apple.
+
+if(NOT DEFINED LIBDIR)
+ if(WITH_CXX11)
+ set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/darwin)
+ else()
+ set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/darwin-9.x.universal)
+ endif()
+else()
+ message(STATUS "Using pre-compiled LIBDIR: ${LIBDIR}")
+endif()
+if(NOT EXISTS "${LIBDIR}/")
+ message(FATAL_ERROR "Mac OSX requires pre-compiled libs at: '${LIBDIR}'")
+endif()
+
+if(WITH_OPENAL)
+ find_package(OpenAL)
+ if(OPENAL_FOUND)
+ set(WITH_OPENAL ON)
+ set(OPENAL_INCLUDE_DIR "${LIBDIR}/openal/include")
+ else()
+ set(WITH_OPENAL OFF)
+ endif()
+endif()
+
+if(WITH_ALEMBIC)
+ set(ALEMBIC ${LIBDIR}/alembic)
+ set(ALEMBIC_INCLUDE_DIR ${ALEMBIC}/include)
+ set(ALEMBIC_INCLUDE_DIRS ${ALEMBIC_INCLUDE_DIR})
+ set(ALEMBIC_LIBPATH ${ALEMBIC}/lib)
+ set(ALEMBIC_LIBRARIES Alembic)
+endif()
+
+if(WITH_OPENSUBDIV OR WITH_CYCLES_OPENSUBDIV)
+ set(OPENSUBDIV ${LIBDIR}/opensubdiv)
+ set(OPENSUBDIV_LIBPATH ${OPENSUBDIV}/lib)
+ find_library(OSD_LIB_CPU NAMES osdCPU PATHS ${OPENSUBDIV_LIBPATH})
+ find_library(OSD_LIB_GPU NAMES osdGPU PATHS ${OPENSUBDIV_LIBPATH})
+ set(OPENSUBDIV_INCLUDE_DIR ${OPENSUBDIV}/include)
+ set(OPENSUBDIV_INCLUDE_DIRS ${OPENSUBDIV_INCLUDE_DIR})
+ list(APPEND OPENSUBDIV_LIBRARIES ${OSD_LIB_CPU} ${OSD_LIB_GPU})
+endif()
+
+if(WITH_JACK)
+ find_library(JACK_FRAMEWORK
+ NAMES jackmp
+ )
+ set(JACK_INCLUDE_DIRS ${JACK_FRAMEWORK}/headers)
+ if(NOT JACK_FRAMEWORK)
+ set(WITH_JACK OFF)
+ endif()
+endif()
+
+if(WITH_CODEC_SNDFILE)
+ set(SNDFILE ${LIBDIR}/sndfile)
+ set(SNDFILE_INCLUDE_DIRS ${SNDFILE}/include)
+ set(SNDFILE_LIBRARIES sndfile FLAC ogg vorbis vorbisenc)
+ set(SNDFILE_LIBPATH ${SNDFILE}/lib ${LIBDIR}/ffmpeg/lib) # TODO, deprecate
+endif()
+
+if(WITH_PYTHON)
+ # we use precompiled libraries for py 3.5 and up by default
+ set(PYTHON_VERSION 3.5)
+ if(NOT WITH_PYTHON_MODULE AND NOT WITH_PYTHON_FRAMEWORK)
+ # normally cached but not since we include them with blender
+ set(PYTHON_INCLUDE_DIR "${LIBDIR}/python/include/python${PYTHON_VERSION}m")
+ set(PYTHON_EXECUTABLE "${LIBDIR}/python/bin/python${PYTHON_VERSION}m")
+ set(PYTHON_LIBRARY python${PYTHON_VERSION}m)
+ set(PYTHON_LIBPATH "${LIBDIR}/python/lib/python${PYTHON_VERSION}")
+ # set(PYTHON_LINKFLAGS "-u _PyMac_Error") # won't build with this enabled
+ else()
+ # module must be compiled against Python framework
+ set(_py_framework "/Library/Frameworks/Python.framework/Versions/${PYTHON_VERSION}")
+
+ set(PYTHON_INCLUDE_DIR "${_py_framework}/include/python${PYTHON_VERSION}m")
+ set(PYTHON_EXECUTABLE "${_py_framework}/bin/python${PYTHON_VERSION}m")
+ set(PYTHON_LIBPATH "${_py_framework}/lib/python${PYTHON_VERSION}/config-${PYTHON_VERSION}m")
+ #set(PYTHON_LIBRARY python${PYTHON_VERSION})
+ #set(PYTHON_LINKFLAGS "-u _PyMac_Error -framework Python") # won't build with this enabled
+
+ unset(_py_framework)
+ endif()
+
+ # uncached vars
+ set(PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIR}")
+ set(PYTHON_LIBRARIES "${PYTHON_LIBRARY}")
+
+ if(NOT EXISTS "${PYTHON_EXECUTABLE}")
+ message(FATAL_ERROR "Python executable missing: ${PYTHON_EXECUTABLE}")
+ endif()
+endif()
+
+if(WITH_FFTW3)
+ set(FFTW3 ${LIBDIR}/fftw3)
+ set(FFTW3_INCLUDE_DIRS ${FFTW3}/include)
+ set(FFTW3_LIBRARIES fftw3)
+ set(FFTW3_LIBPATH ${FFTW3}/lib)
+endif()
+
+set(PNG_LIBRARIES png)
+set(JPEG_LIBRARIES jpeg)
+
+set(ZLIB /usr)
+set(ZLIB_INCLUDE_DIRS "${ZLIB}/include")
+set(ZLIB_LIBRARIES z bz2)
+
+set(FREETYPE ${LIBDIR}/freetype)
+set(FREETYPE_INCLUDE_DIRS ${FREETYPE}/include ${FREETYPE}/include/freetype2)
+set(FREETYPE_LIBPATH ${FREETYPE}/lib)
+set(FREETYPE_LIBRARY freetype)
+
+if(WITH_IMAGE_OPENEXR)
+ set(OPENEXR ${LIBDIR}/openexr)
+ set(OPENEXR_INCLUDE_DIR ${OPENEXR}/include)
+ set(OPENEXR_INCLUDE_DIRS ${OPENEXR_INCLUDE_DIR} ${OPENEXR}/include/OpenEXR)
+ if(WITH_CXX11)
+ set(OPENEXR_POSTFIX -2_2)
+ else()
+ set(OPENEXR_POSTFIX)
+ endif()
+ set(OPENEXR_LIBRARIES
+ Iex${OPENEXR_POSTFIX}
+ Half
+ IlmImf${OPENEXR_POSTFIX}
+ Imath${OPENEXR_POSTFIX}
+ IlmThread${OPENEXR_POSTFIX})
+ set(OPENEXR_LIBPATH ${OPENEXR}/lib)
+endif()
+
+if(WITH_CODEC_FFMPEG)
+ set(FFMPEG ${LIBDIR}/ffmpeg)
+ set(FFMPEG_INCLUDE_DIRS ${FFMPEG}/include)
+ set(FFMPEG_LIBRARIES
+ avcodec avdevice avformat avutil
+ mp3lame swscale x264 xvidcore theora theoradec theoraenc vorbis vorbisenc vorbisfile ogg
+ )
+ if(WITH_CXX11)
+ set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} schroedinger orc vpx)
+ endif()
+ set(FFMPEG_LIBPATH ${FFMPEG}/lib)
+endif()
+
+if(WITH_OPENJPEG OR WITH_CODEC_FFMPEG)
+ # use openjpeg from libdir that is linked into ffmpeg
+ if(WITH_CXX11)
+ set(OPENJPEG ${LIBDIR}/openjpeg)
+ set(WITH_SYSTEM_OPENJPEG ON)
+ set(OPENJPEG_INCLUDE_DIRS ${OPENJPEG}/include)
+ set(OPENJPEG_LIBRARIES ${OPENJPEG}/lib/libopenjpeg.a)
+ endif()
+endif()
+
+find_library(SYSTEMSTUBS_LIBRARY
+ NAMES
+ SystemStubs
+ PATHS
+)
+mark_as_advanced(SYSTEMSTUBS_LIBRARY)
+if(SYSTEMSTUBS_LIBRARY)
+ list(APPEND PLATFORM_LINKLIBS SystemStubs)
+endif()
+
+set(PLATFORM_CFLAGS "-pipe -funsigned-char")
+set(PLATFORM_LINKFLAGS
+ "-fexceptions -framework CoreServices -framework Foundation -framework IOKit -framework AppKit -framework Cocoa -framework Carbon -framework AudioUnit -framework AudioToolbox -framework CoreAudio"
+)
+if(WITH_CODEC_QUICKTIME)
+ set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -framework QTKit")
+ if(CMAKE_OSX_ARCHITECTURES MATCHES i386)
+ set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -framework QuickTime")
+ # libSDL still needs 32bit carbon quicktime
+ endif()
+endif()
+
+if(WITH_CXX11)
+ list(APPEND PLATFORM_LINKLIBS c++)
+else()
+ list(APPEND PLATFORM_LINKLIBS stdc++)
+endif()
+
+if(WITH_JACK)
+ set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -F/Library/Frameworks -weak_framework jackmp")
+endif()
+
+if(WITH_PYTHON_MODULE OR WITH_PYTHON_FRAMEWORK)
+ # force cmake to link right framework
+ set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} /Library/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/Python")
+endif()
+
+if(WITH_OPENCOLLADA)
+ set(OPENCOLLADA ${LIBDIR}/opencollada)
+
+ set(OPENCOLLADA_INCLUDE_DIRS
+ ${LIBDIR}/opencollada/include/COLLADAStreamWriter
+ ${LIBDIR}/opencollada/include/COLLADABaseUtils
+ ${LIBDIR}/opencollada/include/COLLADAFramework
+ ${LIBDIR}/opencollada/include/COLLADASaxFrameworkLoader
+ ${LIBDIR}/opencollada/include/GeneratedSaxParser
+ )
+
+ set(OPENCOLLADA_LIBPATH ${OPENCOLLADA}/lib)
+ set(OPENCOLLADA_LIBRARIES
+ OpenCOLLADASaxFrameworkLoader
+ -lOpenCOLLADAFramework
+ -lOpenCOLLADABaseUtils
+ -lOpenCOLLADAStreamWriter
+ -lMathMLSolver
+ -lGeneratedSaxParser
+ -lxml2 -lbuffer -lftoa
+ )
+ # Use UTF functions from collada if LLVM is not enabled
+ if(NOT WITH_LLVM)
+ list(APPEND OPENCOLLADA_LIBRARIES -lUTF)
+ endif()
+ # pcre is bundled with openCollada
+ #set(PCRE ${LIBDIR}/pcre)
+ #set(PCRE_LIBPATH ${PCRE}/lib)
+ set(PCRE_LIBRARIES pcre)
+ #libxml2 is used
+ #set(EXPAT ${LIBDIR}/expat)
+ #set(EXPAT_LIBPATH ${EXPAT}/lib)
+ set(EXPAT_LIB)
+endif()
+
+if(WITH_SDL)
+ set(SDL ${LIBDIR}/sdl)
+ set(SDL_INCLUDE_DIR ${SDL}/include)
+ set(SDL_LIBRARY SDL2)
+ set(SDL_LIBPATH ${SDL}/lib)
+ if(WITH_CXX11)
+ set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -framework ForceFeedback")
+ else()
+ set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -lazy_framework ForceFeedback")
+ endif()
+endif()
+
+set(PNG "${LIBDIR}/png")
+set(PNG_INCLUDE_DIRS "${PNG}/include")
+set(PNG_LIBPATH ${PNG}/lib)
+
+set(JPEG "${LIBDIR}/jpeg")
+set(JPEG_INCLUDE_DIR "${JPEG}/include")
+set(JPEG_LIBPATH ${JPEG}/lib)
+
+if(WITH_IMAGE_TIFF)
+ set(TIFF ${LIBDIR}/tiff)
+ set(TIFF_INCLUDE_DIR ${TIFF}/include)
+ set(TIFF_LIBRARY tiff)
+ set(TIFF_LIBPATH ${TIFF}/lib)
+endif()
+
+if(WITH_BOOST)
+ set(BOOST ${LIBDIR}/boost)
+ set(BOOST_INCLUDE_DIR ${BOOST}/include)
+ if(WITH_CXX11)
+ set(BOOST_POSTFIX)
+ else()
+ set(BOOST_POSTFIX -mt)
+ endif()
+ set(BOOST_LIBRARIES
+ boost_date_time${BOOST_POSTFIX}
+ boost_filesystem${BOOST_POSTFIX}
+ boost_regex${BOOST_POSTFIX}
+ boost_system${BOOST_POSTFIX}
+ boost_thread${BOOST_POSTFIX}
+ boost_wave${BOOST_POSTFIX}
+ )
+ if(WITH_INTERNATIONAL)
+ list(APPEND BOOST_LIBRARIES boost_locale${BOOST_POSTFIX})
+ endif()
+ if(WITH_CYCLES_NETWORK)
+ list(APPEND BOOST_LIBRARIES boost_serialization${BOOST_POSTFIX})
+ endif()
+ if(WITH_OPENVDB)
+ list(APPEND BOOST_LIBRARIES boost_iostreams${BOOST_POSTFIX})
+ endif()
+ set(BOOST_LIBPATH ${BOOST}/lib)
+ set(BOOST_DEFINITIONS)
+endif()
+
+if(WITH_INTERNATIONAL OR WITH_CODEC_FFMPEG)
+ set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -liconv") # boost_locale and ffmpeg needs it !
+endif()
+
+if(WITH_OPENIMAGEIO)
+ set(OPENIMAGEIO ${LIBDIR}/openimageio)
+ set(OPENIMAGEIO_INCLUDE_DIRS ${OPENIMAGEIO}/include)
+ set(OPENIMAGEIO_LIBRARIES
+ ${OPENIMAGEIO}/lib/libOpenImageIO.a
+ ${PNG_LIBRARIES}
+ ${JPEG_LIBRARIES}
+ ${TIFF_LIBRARY}
+ ${OPENEXR_LIBRARIES}
+ ${ZLIB_LIBRARIES}
+ )
+ set(OPENIMAGEIO_LIBPATH
+ ${OPENIMAGEIO}/lib
+ ${JPEG_LIBPATH}
+ ${PNG_LIBPATH}
+ ${TIFF_LIBPATH}
+ ${OPENEXR_LIBPATH}
+ ${ZLIB_LIBPATH}
+ )
+ set(OPENIMAGEIO_DEFINITIONS "-DOIIO_STATIC_BUILD")
+ set(OPENIMAGEIO_IDIFF "${LIBDIR}/openimageio/bin/idiff")
+endif()
+
+if(WITH_OPENCOLORIO)
+ set(OPENCOLORIO ${LIBDIR}/opencolorio)
+ set(OPENCOLORIO_INCLUDE_DIRS ${OPENCOLORIO}/include)
+ set(OPENCOLORIO_LIBRARIES OpenColorIO tinyxml yaml-cpp)
+ set(OPENCOLORIO_LIBPATH ${OPENCOLORIO}/lib)
+endif()
+
+if(WITH_OPENVDB)
+ set(OPENVDB ${LIBDIR}/openvdb)
+ set(OPENVDB_INCLUDE_DIRS ${OPENVDB}/include)
+ set(TBB_INCLUDE_DIRS ${LIBDIR}/tbb/include)
+ set(TBB_LIBRARIES ${LIBDIR}/tbb/lib/libtbb.a)
+ set(OPENVDB_LIBRARIES openvdb blosc ${TBB_LIBRARIES})
+ set(OPENVDB_LIBPATH ${LIBDIR}/openvdb/lib)
+ set(OPENVDB_DEFINITIONS)
+endif()
+
+if(WITH_LLVM)
+ set(LLVM_ROOT_DIR ${LIBDIR}/llvm CACHE PATH "Path to the LLVM installation")
+ set(LLVM_VERSION "3.4" CACHE STRING "Version of LLVM to use")
+ if(EXISTS "${LLVM_ROOT_DIR}/bin/llvm-config")
+ set(LLVM_CONFIG "${LLVM_ROOT_DIR}/bin/llvm-config")
+ else()
+ set(LLVM_CONFIG llvm-config)
+ endif()
+ execute_process(COMMAND ${LLVM_CONFIG} --version
+ OUTPUT_VARIABLE LLVM_VERSION
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ execute_process(COMMAND ${LLVM_CONFIG} --prefix
+ OUTPUT_VARIABLE LLVM_ROOT_DIR
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ execute_process(COMMAND ${LLVM_CONFIG} --libdir
+ OUTPUT_VARIABLE LLVM_LIBPATH
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ find_library(LLVM_LIBRARY
+ NAMES LLVMAnalysis # first of a whole bunch of libs to get
+ PATHS ${LLVM_LIBPATH})
+
+ if(LLVM_LIBRARY AND LLVM_ROOT_DIR AND LLVM_LIBPATH)
+ if(LLVM_STATIC)
+ # if static LLVM libraries were requested, use llvm-config to generate
+ # the list of what libraries we need, and substitute that in the right
+ # way for LLVM_LIBRARY.
+ execute_process(COMMAND ${LLVM_CONFIG} --libfiles
+ OUTPUT_VARIABLE LLVM_LIBRARY
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ string(REPLACE " " ";" LLVM_LIBRARY ${LLVM_LIBRARY})
+ else()
+ set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -lLLVM-3.4")
+ endif()
+ else()
+ message(FATAL_ERROR "LLVM not found.")
+ endif()
+endif()
+
+if(WITH_CYCLES_OSL)
+ set(CYCLES_OSL ${LIBDIR}/osl CACHE PATH "Path to OpenShadingLanguage installation")
+
+ find_library(OSL_LIB_EXEC NAMES oslexec PATHS ${CYCLES_OSL}/lib)
+ find_library(OSL_LIB_COMP NAMES oslcomp PATHS ${CYCLES_OSL}/lib)
+ find_library(OSL_LIB_QUERY NAMES oslquery PATHS ${CYCLES_OSL}/lib)
+ # WARNING! depends on correct order of OSL libs linking
+ list(APPEND OSL_LIBRARIES ${OSL_LIB_COMP} -force_load ${OSL_LIB_EXEC} ${OSL_LIB_QUERY})
+ find_path(OSL_INCLUDE_DIR OSL/oslclosure.h PATHS ${CYCLES_OSL}/include)
+ find_program(OSL_COMPILER NAMES oslc PATHS ${CYCLES_OSL}/bin)
+
+ if(OSL_INCLUDE_DIR AND OSL_LIBRARIES AND OSL_COMPILER)
+ set(OSL_FOUND TRUE)
+ else()
+ message(STATUS "OSL not found")
+ set(WITH_CYCLES_OSL OFF)
+ endif()
+endif()
+
+if(WITH_OPENMP)
+ execute_process(COMMAND ${CMAKE_C_COMPILER} --version OUTPUT_VARIABLE COMPILER_VENDOR)
+ string(SUBSTRING "${COMPILER_VENDOR}" 0 5 VENDOR_NAME) # truncate output
+ if(${VENDOR_NAME} MATCHES "Apple") # Apple does not support OpenMP reliable with gcc and not with clang
+ set(WITH_OPENMP OFF)
+ else() # vanilla gcc or clang_omp support OpenMP
+ message(STATUS "Using special OpenMP enabled compiler !") # letting find_package(OpenMP) module work for gcc
+ if(CMAKE_C_COMPILER_ID MATCHES "Clang") # clang-omp in darwin libs
+ set(OPENMP_FOUND ON)
+ set(OpenMP_C_FLAGS "-fopenmp" CACHE STRING "C compiler flags for OpenMP parallization" FORCE)
+ set(OpenMP_CXX_FLAGS "-fopenmp" CACHE STRING "C++ compiler flags for OpenMP parallization" FORCE)
+ include_directories(${LIBDIR}/openmp/include)
+ link_directories(${LIBDIR}/openmp/lib)
+ # This is a workaround for our helperbinaries ( datatoc, masgfmt, ... ),
+ # They are linked also to omp lib, so we need it in builddir for runtime exexcution,
+ # TODO: remove all unneeded dependencies from these
+
+ # for intermediate binaries, in respect to lib ID
+ execute_process(
+ COMMAND ditto -arch ${CMAKE_OSX_ARCHITECTURES}
+ ${LIBDIR}/openmp/lib/libiomp5.dylib
+ ${CMAKE_BINARY_DIR}/Resources/lib/libiomp5.dylib)
+ endif()
+ endif()
+endif()
+
+set(EXETYPE MACOSX_BUNDLE)
+
+set(CMAKE_C_FLAGS_DEBUG "-fno-strict-aliasing -g")
+set(CMAKE_CXX_FLAGS_DEBUG "-fno-strict-aliasing -g")
+if(CMAKE_OSX_ARCHITECTURES MATCHES "x86_64" OR CMAKE_OSX_ARCHITECTURES MATCHES "i386")
+ set(CMAKE_CXX_FLAGS_RELEASE "-O2 -mdynamic-no-pic -msse -msse2 -msse3 -mssse3")
+ set(CMAKE_C_FLAGS_RELEASE "-O2 -mdynamic-no-pic -msse -msse2 -msse3 -mssse3")
+ if(NOT CMAKE_C_COMPILER_ID MATCHES "Clang")
+ set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -ftree-vectorize -fvariable-expansion-in-unroller")
+ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -ftree-vectorize -fvariable-expansion-in-unroller")
+ endif()
+else()
+ set(CMAKE_C_FLAGS_RELEASE "-mdynamic-no-pic -fno-strict-aliasing")
+ set(CMAKE_CXX_FLAGS_RELEASE "-mdynamic-no-pic -fno-strict-aliasing")
+endif()
+
+if(${XCODE_VERSION} VERSION_EQUAL 5 OR ${XCODE_VERSION} VERSION_GREATER 5)
+ # Xcode 5 is always using CLANG, which has too low template depth of 128 for libmv
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftemplate-depth=1024")
+endif()
+# Get rid of eventually clashes, we export some symbols explicite as local
+set(PLATFORM_LINKFLAGS
+ "${PLATFORM_LINKFLAGS} -Xlinker -unexported_symbols_list -Xlinker ${CMAKE_SOURCE_DIR}/source/creator/osx_locals.map"
+)
+
+if(WITH_CXX11)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
+ set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -stdlib=libc++")
+endif()
+
+# Suppress ranlib "has no symbols" warnings (workaround for T48250)
+set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>")
+set(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>")
+set(CMAKE_C_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
+set(CMAKE_CXX_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake
new file mode 100644
index 00000000000..e33141f8012
--- /dev/null
+++ b/build_files/cmake/platform/platform_unix.cmake
@@ -0,0 +1,427 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2016, Blender Foundation
+# All rights reserved.
+#
+# Contributor(s): Sergey Sharybin.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+# Libraries configuration for any *nix system including Linux and Unix.
+
+macro(find_package_wrapper)
+ if(WITH_STATIC_LIBS)
+ find_package_static(${ARGV})
+ else()
+ find_package(${ARGV})
+ endif()
+endmacro()
+
+find_package_wrapper(JPEG REQUIRED)
+find_package_wrapper(PNG REQUIRED)
+find_package_wrapper(ZLIB REQUIRED)
+find_package_wrapper(Freetype REQUIRED)
+
+if(WITH_LZO AND WITH_SYSTEM_LZO)
+ find_package_wrapper(LZO)
+ if(NOT LZO_FOUND)
+ message(FATAL_ERROR "Failed finding system LZO version!")
+ endif()
+endif()
+
+if(WITH_SYSTEM_EIGEN3)
+ find_package_wrapper(Eigen3)
+ if(NOT EIGEN3_FOUND)
+ message(FATAL_ERROR "Failed finding system Eigen3 version!")
+ endif()
+endif()
+# else values are set below for all platforms
+
+if(WITH_PYTHON)
+ # No way to set py35, remove for now.
+ # find_package(PythonLibs)
+
+ # Use our own instead, since without py is such a rare case,
+ # require this package
+ # XXX Linking errors with debian static python :/
+# find_package_wrapper(PythonLibsUnix REQUIRED)
+ find_package(PythonLibsUnix REQUIRED)
+endif()
+
+if(WITH_IMAGE_OPENEXR)
+ find_package_wrapper(OpenEXR) # our own module
+ if(NOT OPENEXR_FOUND)
+ set(WITH_IMAGE_OPENEXR OFF)
+ endif()
+endif()
+
+if(WITH_IMAGE_OPENJPEG)
+ find_package_wrapper(OpenJPEG)
+ if(NOT OPENJPEG_FOUND)
+ set(WITH_IMAGE_OPENJPEG OFF)
+ endif()
+endif()
+
+if(WITH_IMAGE_TIFF)
+ # XXX Linking errors with debian static tiff :/
+# find_package_wrapper(TIFF)
+ find_package(TIFF)
+ if(NOT TIFF_FOUND)
+ set(WITH_IMAGE_TIFF OFF)
+ endif()
+endif()
+
+# Audio IO
+if(WITH_SYSTEM_AUDASPACE)
+ find_package_wrapper(Audaspace)
+ if(NOT AUDASPACE_FOUND OR NOT AUDASPACE_C_FOUND)
+ message(FATAL_ERROR "Audaspace external library not found!")
+ endif()
+endif()
+
+if(WITH_OPENAL)
+ find_package_wrapper(OpenAL)
+ if(NOT OPENAL_FOUND)
+ set(WITH_OPENAL OFF)
+ endif()
+endif()
+
+if(WITH_SDL)
+ if(WITH_SDL_DYNLOAD)
+ set(SDL_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/extern/sdlew/include/SDL2")
+ set(SDL_LIBRARY)
+ else()
+ find_package_wrapper(SDL2)
+ if(SDL2_FOUND)
+ # Use same names for both versions of SDL until we move to 2.x.
+ set(SDL_INCLUDE_DIR "${SDL2_INCLUDE_DIR}")
+ set(SDL_LIBRARY "${SDL2_LIBRARY}")
+ set(SDL_FOUND "${SDL2_FOUND}")
+ else()
+ find_package_wrapper(SDL)
+ endif()
+ mark_as_advanced(
+ SDL_INCLUDE_DIR
+ SDL_LIBRARY
+ )
+ # unset(SDLMAIN_LIBRARY CACHE)
+ if(NOT SDL_FOUND)
+ set(WITH_SDL OFF)
+ endif()
+ endif()
+endif()
+
+if(WITH_JACK)
+ find_package_wrapper(Jack)
+ if(NOT JACK_FOUND)
+ set(WITH_JACK OFF)
+ endif()
+endif()
+
+# Codecs
+if(WITH_CODEC_SNDFILE)
+ find_package_wrapper(SndFile)
+ if(NOT SNDFILE_FOUND)
+ set(WITH_CODEC_SNDFILE OFF)
+ endif()
+endif()
+
+if(WITH_CODEC_FFMPEG)
+ set(FFMPEG /usr CACHE PATH "FFMPEG Directory")
+ set(FFMPEG_LIBRARIES avformat avcodec avutil avdevice swscale CACHE STRING "FFMPEG Libraries")
+
+ mark_as_advanced(FFMPEG)
+
+ # lame, but until we have proper find module for ffmpeg
+ set(FFMPEG_INCLUDE_DIRS ${FFMPEG}/include)
+ if(EXISTS "${FFMPEG}/include/ffmpeg/")
+ list(APPEND FFMPEG_INCLUDE_DIRS "${FFMPEG}/include/ffmpeg")
+ endif()
+ # end lameness
+
+ mark_as_advanced(FFMPEG_LIBRARIES)
+ set(FFMPEG_LIBPATH ${FFMPEG}/lib)
+endif()
+
+if(WITH_FFTW3)
+ find_package_wrapper(Fftw3)
+ if(NOT FFTW3_FOUND)
+ set(WITH_FFTW3 OFF)
+ endif()
+endif()
+
+if(WITH_OPENCOLLADA)
+ find_package_wrapper(OpenCOLLADA)
+ if(OPENCOLLADA_FOUND)
+ find_package_wrapper(XML2)
+ find_package_wrapper(PCRE)
+ else()
+ set(WITH_OPENCOLLADA OFF)
+ endif()
+endif()
+
+if(WITH_MEM_JEMALLOC)
+ find_package_wrapper(JeMalloc)
+ if(NOT JEMALLOC_FOUND)
+ set(WITH_MEM_JEMALLOC OFF)
+ endif()
+endif()
+
+if(WITH_INPUT_NDOF)
+ find_package_wrapper(Spacenav)
+ if(SPACENAV_FOUND)
+ # use generic names within blenders buildsystem.
+ set(NDOF_INCLUDE_DIRS ${SPACENAV_INCLUDE_DIRS})
+ set(NDOF_LIBRARIES ${SPACENAV_LIBRARIES})
+ else()
+ set(WITH_INPUT_NDOF OFF)
+ endif()
+endif()
+
+if(WITH_CYCLES_OSL)
+ set(CYCLES_OSL ${LIBDIR}/osl CACHE PATH "Path to OpenShadingLanguage installation")
+ if(NOT OSL_ROOT)
+ set(OSL_ROOT ${CYCLES_OSL})
+ endif()
+ find_package_wrapper(OpenShadingLanguage)
+ if(OSL_FOUND)
+ if(${OSL_LIBRARY_VERSION_MAJOR} EQUAL "1" AND ${OSL_LIBRARY_VERSION_MINOR} LESS "6")
+ # Note: --whole-archive is needed to force loading of all symbols in liboslexec,
+ # otherwise LLVM is missing the osl_allocate_closure_component function
+ set(OSL_LIBRARIES
+ ${OSL_OSLCOMP_LIBRARY}
+ -Wl,--whole-archive ${OSL_OSLEXEC_LIBRARY}
+ -Wl,--no-whole-archive ${OSL_OSLQUERY_LIBRARY}
+ )
+ endif()
+ else()
+ message(STATUS "OSL not found, disabling it from Cycles")
+ set(WITH_CYCLES_OSL OFF)
+ endif()
+endif()
+
+if(WITH_OPENVDB)
+ find_package_wrapper(OpenVDB)
+ find_package_wrapper(TBB)
+ if(NOT OPENVDB_FOUND OR NOT TBB_FOUND)
+ set(WITH_OPENVDB OFF)
+ set(WITH_OPENVDB_BLOSC OFF)
+ message(STATUS "OpenVDB not found, disabling it")
+ endif()
+endif()
+
+if(WITH_ALEMBIC)
+ find_package_wrapper(Alembic)
+
+ if(WITH_ALEMBIC_HDF5)
+ set(HDF5_ROOT_DIR ${LIBDIR}/hdf5)
+ find_package_wrapper(HDF5)
+ endif()
+
+ if(NOT ALEMBIC_FOUND OR (WITH_ALEMBIC_HDF5 AND NOT HDF5_FOUND))
+ set(WITH_ALEMBIC OFF)
+ set(WITH_ALEMBIC_HDF5 OFF)
+ endif()
+endif()
+
+if(WITH_BOOST)
+ # uses in build instructions to override include and library variables
+ if(NOT BOOST_CUSTOM)
+ if(WITH_STATIC_LIBS)
+ set(Boost_USE_STATIC_LIBS ON)
+ endif()
+ set(Boost_USE_MULTITHREADED ON)
+ set(__boost_packages filesystem regex thread date_time)
+ if(WITH_CYCLES_OSL)
+ if(NOT (${OSL_LIBRARY_VERSION_MAJOR} EQUAL "1" AND ${OSL_LIBRARY_VERSION_MINOR} LESS "6"))
+ list(APPEND __boost_packages wave)
+ else()
+ endif()
+ endif()
+ if(WITH_INTERNATIONAL)
+ list(APPEND __boost_packages locale)
+ endif()
+ if(WITH_CYCLES_NETWORK)
+ list(APPEND __boost_packages serialization)
+ endif()
+ if(WITH_OPENVDB)
+ list(APPEND __boost_packages iostreams)
+ endif()
+ list(APPEND __boost_packages system)
+ find_package(Boost 1.48 COMPONENTS ${__boost_packages})
+ if(NOT Boost_FOUND)
+ # try to find non-multithreaded if -mt not found, this flag
+ # doesn't matter for us, it has nothing to do with thread
+ # safety, but keep it to not disturb build setups
+ set(Boost_USE_MULTITHREADED OFF)
+ find_package(Boost 1.48 COMPONENTS ${__boost_packages})
+ endif()
+ unset(__boost_packages)
+ if(Boost_USE_STATIC_LIBS AND WITH_BOOST_ICU)
+ find_package(IcuLinux)
+ endif()
+ mark_as_advanced(Boost_DIR) # why doesnt boost do this?
+ endif()
+
+ set(BOOST_INCLUDE_DIR ${Boost_INCLUDE_DIRS})
+ set(BOOST_LIBRARIES ${Boost_LIBRARIES})
+ set(BOOST_LIBPATH ${Boost_LIBRARY_DIRS})
+ set(BOOST_DEFINITIONS "-DBOOST_ALL_NO_LIB")
+endif()
+
+if(WITH_OPENIMAGEIO)
+ find_package_wrapper(OpenImageIO)
+ if(NOT OPENIMAGEIO_PUGIXML_FOUND AND WITH_CYCLES_STANDALONE)
+ find_package_wrapper(PugiXML)
+ else()
+ set(PUGIXML_INCLUDE_DIR "${OPENIMAGEIO_INCLUDE_DIR/OpenImageIO}")
+ set(PUGIXML_LIBRARIES "")
+ endif()
+
+ set(OPENIMAGEIO_LIBRARIES
+ ${OPENIMAGEIO_LIBRARIES}
+ ${PNG_LIBRARIES}
+ ${JPEG_LIBRARIES}
+ ${ZLIB_LIBRARIES}
+ ${BOOST_LIBRARIES}
+ )
+ set(OPENIMAGEIO_LIBPATH) # TODO, remove and reference the absolute path everywhere
+ set(OPENIMAGEIO_DEFINITIONS "")
+
+ if(WITH_IMAGE_TIFF)
+ list(APPEND OPENIMAGEIO_LIBRARIES "${TIFF_LIBRARY}")
+ endif()
+ if(WITH_IMAGE_OPENEXR)
+ list(APPEND OPENIMAGEIO_LIBRARIES "${OPENEXR_LIBRARIES}")
+ endif()
+
+ if(NOT OPENIMAGEIO_FOUND)
+ set(WITH_OPENIMAGEIO OFF)
+ message(STATUS "OpenImageIO not found, disabling WITH_CYCLES")
+ endif()
+endif()
+
+if(WITH_OPENCOLORIO)
+ find_package_wrapper(OpenColorIO)
+
+ set(OPENCOLORIO_LIBRARIES ${OPENCOLORIO_LIBRARIES})
+ set(OPENCOLORIO_LIBPATH) # TODO, remove and reference the absolute path everywhere
+ set(OPENCOLORIO_DEFINITIONS)
+
+ if(NOT OPENCOLORIO_FOUND)
+ set(WITH_OPENCOLORIO OFF)
+ message(STATUS "OpenColorIO not found")
+ endif()
+endif()
+
+if(WITH_LLVM)
+ find_package_wrapper(LLVM)
+
+ if(NOT LLVM_FOUND)
+ set(WITH_LLVM OFF)
+ message(STATUS "LLVM not found")
+ endif()
+endif()
+
+if(WITH_LLVM OR WITH_SDL_DYNLOAD)
+ # Fix for conflict with Mesa llvmpipe
+ set(PLATFORM_LINKFLAGS
+ "${PLATFORM_LINKFLAGS} -Wl,--version-script='${CMAKE_SOURCE_DIR}/source/creator/blender.map'"
+ )
+endif()
+
+if(WITH_OPENSUBDIV OR WITH_CYCLES_OPENSUBDIV)
+ find_package_wrapper(OpenSubdiv)
+
+ set(OPENSUBDIV_LIBRARIES ${OPENSUBDIV_LIBRARIES})
+ set(OPENSUBDIV_LIBPATH) # TODO, remove and reference the absolute path everywhere
+
+ if(NOT OPENSUBDIV_FOUND)
+ set(WITH_OPENSUBDIV OFF)
+ set(WITH_CYCLES_OPENSUBDIV OFF)
+ message(STATUS "OpenSubdiv not found")
+ endif()
+endif()
+
+# OpenSuse needs lutil, ArchLinux not, for now keep, can avoid by using --as-needed
+list(APPEND PLATFORM_LINKLIBS -lutil -lc -lm)
+
+find_package(Threads REQUIRED)
+list(APPEND PLATFORM_LINKLIBS ${CMAKE_THREAD_LIBS_INIT})
+# used by other platforms
+set(PTHREADS_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
+
+if(CMAKE_DL_LIBS)
+ list(APPEND PLATFORM_LINKLIBS ${CMAKE_DL_LIBS})
+endif()
+
+if(CMAKE_SYSTEM_NAME MATCHES "Linux")
+ if(NOT WITH_PYTHON_MODULE)
+ # binreloc is linux only
+ set(BINRELOC_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/extern/binreloc/include)
+ set(WITH_BINRELOC ON)
+ endif()
+endif()
+
+# lfs on glibc, all compilers should use
+add_definitions(-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE)
+
+# GNU Compiler
+if(CMAKE_COMPILER_IS_GNUCC)
+ set(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing")
+
+ # use ld.gold linker if available, could make optional
+ execute_process(
+ COMMAND ${CMAKE_C_COMPILER} -fuse-ld=gold -Wl,--version
+ ERROR_QUIET OUTPUT_VARIABLE LD_VERSION)
+ if("${LD_VERSION}" MATCHES "GNU gold")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fuse-ld=gold")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-ld=gold")
+ else()
+ message(STATUS "GNU gold linker isn't available, using the default system linker.")
+ endif()
+ unset(LD_VERSION)
+
+# CLang is the same as GCC for now.
+elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")
+ set(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing")
+# Solaris CC
+elseif(CMAKE_C_COMPILER_ID MATCHES "SunPro")
+ set(PLATFORM_CFLAGS "-pipe -features=extensions -fPIC -D__FUNCTION__=__func__")
+
+# Intel C++ Compiler
+elseif(CMAKE_C_COMPILER_ID MATCHES "Intel")
+ # think these next two are broken
+ find_program(XIAR xiar)
+ if(XIAR)
+ set(CMAKE_AR "${XIAR}")
+ endif()
+ mark_as_advanced(XIAR)
+
+ find_program(XILD xild)
+ if(XILD)
+ set(CMAKE_LINKER "${XILD}")
+ endif()
+ mark_as_advanced(XILD)
+
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fp-model precise -prec_div -parallel")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fp-model precise -prec_div -parallel")
+
+ # set(PLATFORM_CFLAGS "${PLATFORM_CFLAGS} -diag-enable sc3")
+ set(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing")
+ set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -static-intel")
+endif()
diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake
new file mode 100644
index 00000000000..631973b758b
--- /dev/null
+++ b/build_files/cmake/platform/platform_win32.cmake
@@ -0,0 +1,87 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2016, Blender Foundation
+# All rights reserved.
+#
+# Contributor(s): Sergey Sharybin.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+# Libraries configuration for Windows.
+
+add_definitions(-DWIN32)
+
+if(MSVC)
+ include(platform_win32_msvc)
+elseif(CMAKE_COMPILER_IS_GNUCC)
+ include(platform_win32_mingw)
+endif()
+
+# Things common to both mingw and MSVC should go here
+
+set(WINTAB_INC ${LIBDIR}/wintab/include)
+
+if(WITH_OPENAL)
+ set(OPENAL ${LIBDIR}/openal)
+ set(OPENALDIR ${LIBDIR}/openal)
+ set(OPENAL_INCLUDE_DIR ${OPENAL}/include)
+ if(MSVC)
+ set(OPENAL_LIBRARY openal32)
+ else()
+ set(OPENAL_LIBRARY wrap_oal)
+ endif()
+ set(OPENAL_LIBPATH ${OPENAL}/lib)
+endif()
+
+if(WITH_CODEC_SNDFILE)
+ set(SNDFILE ${LIBDIR}/sndfile)
+ set(SNDFILE_INCLUDE_DIRS ${SNDFILE}/include)
+ set(SNDFILE_LIBRARIES libsndfile-1)
+ set(SNDFILE_LIBPATH ${SNDFILE}/lib) # TODO, deprecate
+endif()
+
+if(WITH_RAYOPTIMIZATION AND SUPPORT_SSE_BUILD)
+ add_definitions(-D__SSE__ -D__MMX__)
+endif()
+
+if(WITH_CYCLES_OSL)
+ set(CYCLES_OSL ${LIBDIR}/osl CACHE PATH "Path to OpenShadingLanguage installation")
+
+ find_library(OSL_LIB_EXEC NAMES oslexec PATHS ${CYCLES_OSL}/lib)
+ find_library(OSL_LIB_COMP NAMES oslcomp PATHS ${CYCLES_OSL}/lib)
+ find_library(OSL_LIB_QUERY NAMES oslquery PATHS ${CYCLES_OSL}/lib)
+ find_library(OSL_LIB_EXEC_DEBUG NAMES oslexec_d PATHS ${CYCLES_OSL}/lib)
+ find_library(OSL_LIB_COMP_DEBUG NAMES oslcomp_d PATHS ${CYCLES_OSL}/lib)
+ find_library(OSL_LIB_QUERY_DEBUG NAMES oslquery_d PATHS ${CYCLES_OSL}/lib)
+ list(APPEND OSL_LIBRARIES
+ optimized ${OSL_LIB_COMP}
+ optimized ${OSL_LIB_EXEC}
+ optimized ${OSL_LIB_QUERY}
+ debug ${OSL_LIB_EXEC_DEBUG}
+ debug ${OSL_LIB_COMP_DEBUG}
+ debug ${OSL_LIB_QUERY_DEBUG}
+ )
+ find_path(OSL_INCLUDE_DIR OSL/oslclosure.h PATHS ${CYCLES_OSL}/include)
+ find_program(OSL_COMPILER NAMES oslc PATHS ${CYCLES_OSL}/bin)
+
+ if(OSL_INCLUDE_DIR AND OSL_LIBRARIES AND OSL_COMPILER)
+ set(OSL_FOUND TRUE)
+ else()
+ message(STATUS "OSL not found")
+ set(WITH_CYCLES_OSL OFF)
+ endif()
+endif()
diff --git a/build_files/cmake/platform/platform_win32_mingw.cmake b/build_files/cmake/platform/platform_win32_mingw.cmake
new file mode 100644
index 00000000000..216568bd069
--- /dev/null
+++ b/build_files/cmake/platform/platform_win32_mingw.cmake
@@ -0,0 +1,302 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2016, Blender Foundation
+# All rights reserved.
+#
+# Contributor(s): Sergey Sharybin.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+# Libraries configuration for Windows when compiling with MinGW.
+
+# keep GCC specific stuff here
+include(CheckCSourceCompiles)
+# Setup 64bit and 64bit windows systems
+CHECK_C_SOURCE_COMPILES("
+ #ifndef __MINGW64__
+ #error
+ #endif
+ int main(void) { return 0; }
+ "
+ WITH_MINGW64
+)
+
+if(NOT DEFINED LIBDIR)
+ if(WITH_MINGW64)
+ message(STATUS "Compiling for 64 bit with MinGW-w64.")
+ set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/mingw64)
+ else()
+ message(STATUS "Compiling for 32 bit with MinGW-w32.")
+ set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/mingw32)
+
+ if(WITH_RAYOPTIMIZATION)
+ message(WARNING "MinGW-w32 is known to be unstable with 'WITH_RAYOPTIMIZATION' option enabled.")
+ endif()
+ endif()
+else()
+ message(STATUS "Using pre-compiled LIBDIR: ${LIBDIR}")
+endif()
+if(NOT EXISTS "${LIBDIR}/")
+ message(FATAL_ERROR "Windows requires pre-compiled libs at: '${LIBDIR}'")
+endif()
+
+list(APPEND PLATFORM_LINKLIBS
+ -lshell32 -lshfolder -lgdi32 -lmsvcrt -lwinmm -lmingw32 -lm -lws2_32
+ -lz -lstdc++ -lole32 -luuid -lwsock32 -lpsapi -ldbghelp
+)
+
+if(WITH_INPUT_IME)
+ list(APPEND PLATFORM_LINKLIBS -limm32)
+endif()
+
+set(PLATFORM_CFLAGS "-pipe -funsigned-char -fno-strict-aliasing")
+
+if(WITH_MINGW64)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive")
+ list(APPEND PLATFORM_LINKLIBS -lpthread)
+
+ add_definitions(-DFREE_WINDOWS64 -DMS_WIN64)
+endif()
+
+add_definitions(-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE)
+
+add_definitions(-DFREE_WINDOWS)
+
+set(PNG "${LIBDIR}/png")
+set(PNG_INCLUDE_DIRS "${PNG}/include")
+set(PNG_LIBPATH ${PNG}/lib) # not cmake defined
+
+if(WITH_MINGW64)
+ set(JPEG_LIBRARIES jpeg)
+else()
+ set(JPEG_LIBRARIES libjpeg)
+endif()
+set(PNG_LIBRARIES png)
+
+set(ZLIB ${LIBDIR}/zlib)
+set(ZLIB_INCLUDE_DIRS ${ZLIB}/include)
+set(ZLIB_LIBPATH ${ZLIB}/lib)
+set(ZLIB_LIBRARIES z)
+
+set(JPEG "${LIBDIR}/jpeg")
+set(JPEG_INCLUDE_DIR "${JPEG}/include")
+set(JPEG_LIBPATH ${JPEG}/lib) # not cmake defined
+
+# comes with own pthread library
+if(NOT WITH_MINGW64)
+ set(PTHREADS ${LIBDIR}/pthreads)
+ #set(PTHREADS_INCLUDE_DIRS ${PTHREADS}/include)
+ set(PTHREADS_LIBPATH ${PTHREADS}/lib)
+ set(PTHREADS_LIBRARIES pthreadGC2)
+endif()
+
+set(FREETYPE ${LIBDIR}/freetype)
+set(FREETYPE_INCLUDE_DIRS ${FREETYPE}/include ${FREETYPE}/include/freetype2)
+set(FREETYPE_LIBPATH ${FREETYPE}/lib)
+set(FREETYPE_LIBRARY freetype)
+
+if(WITH_FFTW3)
+ set(FFTW3 ${LIBDIR}/fftw3)
+ set(FFTW3_LIBRARIES fftw3)
+ set(FFTW3_INCLUDE_DIRS ${FFTW3}/include)
+ set(FFTW3_LIBPATH ${FFTW3}/lib)
+endif()
+
+if(WITH_OPENCOLLADA)
+ set(OPENCOLLADA ${LIBDIR}/opencollada)
+ set(OPENCOLLADA_INCLUDE_DIRS
+ ${OPENCOLLADA}/include/opencollada/COLLADAStreamWriter
+ ${OPENCOLLADA}/include/opencollada/COLLADABaseUtils
+ ${OPENCOLLADA}/include/opencollada/COLLADAFramework
+ ${OPENCOLLADA}/include/opencollada/COLLADASaxFrameworkLoader
+ ${OPENCOLLADA}/include/opencollada/GeneratedSaxParser
+ )
+ set(OPENCOLLADA_LIBPATH ${OPENCOLLADA}/lib/opencollada)
+ set(OPENCOLLADA_LIBRARIES
+ OpenCOLLADAStreamWriter
+ OpenCOLLADASaxFrameworkLoader
+ OpenCOLLADAFramework
+ OpenCOLLADABaseUtils
+ GeneratedSaxParser
+ UTF MathMLSolver buffer ftoa xml
+ )
+ set(PCRE_LIBRARIES pcre)
+endif()
+
+if(WITH_CODEC_FFMPEG)
+ set(FFMPEG ${LIBDIR}/ffmpeg)
+ set(FFMPEG_INCLUDE_DIRS ${FFMPEG}/include)
+ if(WITH_MINGW64)
+ set(FFMPEG_LIBRARIES avcodec.dll avformat.dll avdevice.dll avutil.dll swscale.dll swresample.dll)
+ else()
+ set(FFMPEG_LIBRARIES avcodec-55 avformat-55 avdevice-55 avutil-52 swscale-2)
+ endif()
+ set(FFMPEG_LIBPATH ${FFMPEG}/lib)
+endif()
+
+if(WITH_IMAGE_OPENEXR)
+ set(OPENEXR ${LIBDIR}/openexr)
+ set(OPENEXR_INCLUDE_DIR ${OPENEXR}/include)
+ set(OPENEXR_INCLUDE_DIRS ${OPENEXR}/include/OpenEXR)
+ set(OPENEXR_LIBRARIES Half IlmImf Imath IlmThread Iex)
+ set(OPENEXR_LIBPATH ${OPENEXR}/lib)
+endif()
+
+if(WITH_IMAGE_TIFF)
+ set(TIFF ${LIBDIR}/tiff)
+ set(TIFF_LIBRARY tiff)
+ set(TIFF_INCLUDE_DIR ${TIFF}/include)
+ set(TIFF_LIBPATH ${TIFF}/lib)
+endif()
+
+if(WITH_JACK)
+ set(JACK ${LIBDIR}/jack)
+ set(JACK_INCLUDE_DIRS ${JACK}/include/jack ${JACK}/include)
+ set(JACK_LIBRARIES jack)
+ set(JACK_LIBPATH ${JACK}/lib)
+
+ # TODO, gives linking errors, force off
+ set(WITH_JACK OFF)
+endif()
+
+if(WITH_PYTHON)
+ # normally cached but not since we include them with blender
+ set(PYTHON_VERSION 3.5) # CACHE STRING)
+ string(REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${PYTHON_VERSION})
+ set(PYTHON_INCLUDE_DIR "${LIBDIR}/python/include/python${PYTHON_VERSION}") # CACHE PATH)
+ set(PYTHON_LIBRARY "${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}mw.lib") # CACHE FILEPATH)
+ unset(_PYTHON_VERSION_NO_DOTS)
+
+ # uncached vars
+ set(PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIR}")
+ set(PYTHON_LIBRARIES "${PYTHON_LIBRARY}")
+endif()
+
+if(WITH_BOOST)
+ set(BOOST ${LIBDIR}/boost)
+ set(BOOST_INCLUDE_DIR ${BOOST}/include)
+ if(WITH_MINGW64)
+ set(BOOST_POSTFIX "mgw47-mt-s-1_49")
+ set(BOOST_DEBUG_POSTFIX "mgw47-mt-sd-1_49")
+ else()
+ set(BOOST_POSTFIX "mgw46-mt-s-1_49")
+ set(BOOST_DEBUG_POSTFIX "mgw46-mt-sd-1_49")
+ endif()
+ set(BOOST_LIBRARIES
+ optimized boost_date_time-${BOOST_POSTFIX} boost_filesystem-${BOOST_POSTFIX}
+ boost_regex-${BOOST_POSTFIX}
+ boost_system-${BOOST_POSTFIX} boost_thread-${BOOST_POSTFIX}
+ debug boost_date_time-${BOOST_DEBUG_POSTFIX} boost_filesystem-${BOOST_DEBUG_POSTFIX}
+ boost_regex-${BOOST_DEBUG_POSTFIX}
+ boost_system-${BOOST_DEBUG_POSTFIX} boost_thread-${BOOST_DEBUG_POSTFIX})
+ if(WITH_INTERNATIONAL)
+ set(BOOST_LIBRARIES ${BOOST_LIBRARIES}
+ optimized boost_locale-${BOOST_POSTFIX}
+ debug boost_locale-${BOOST_DEBUG_POSTFIX}
+ )
+ endif()
+ if(WITH_CYCLES_OSL)
+ set(BOOST_LIBRARIES ${BOOST_LIBRARIES}
+ optimized boost_wave-${BOOST_POSTFIX}
+ debug boost_wave-${BOOST_DEBUG_POSTFIX}
+ )
+ endif()
+ set(BOOST_LIBPATH ${BOOST}/lib)
+ set(BOOST_DEFINITIONS "-DBOOST_ALL_NO_LIB -DBOOST_THREAD_USE_LIB ")
+endif()
+
+if(WITH_OPENIMAGEIO)
+ set(OPENIMAGEIO ${LIBDIR}/openimageio)
+ set(OPENIMAGEIO_INCLUDE_DIRS ${OPENIMAGEIO}/include)
+ set(OPENIMAGEIO_LIBRARIES OpenImageIO)
+ set(OPENIMAGEIO_LIBPATH ${OPENIMAGEIO}/lib)
+ set(OPENIMAGEIO_DEFINITIONS "")
+ set(OPENIMAGEIO_IDIFF "${OPENIMAGEIO}/bin/idiff.exe")
+endif()
+
+if(WITH_LLVM)
+ set(LLVM_ROOT_DIR ${LIBDIR}/llvm CACHE PATH "Path to the LLVM installation")
+ set(LLVM_LIBPATH ${LLVM_ROOT_DIR}/lib)
+ # Explicitly set llvm lib order.
+ #---- WARNING ON GCC ORDER OF LIBS IS IMPORTANT, DO NOT CHANGE! ---------
+ set(LLVM_LIBRARY LLVMSelectionDAG LLVMCodeGen LLVMScalarOpts LLVMAnalysis LLVMArchive
+ LLVMAsmParser LLVMAsmPrinter
+ LLVMBitReader LLVMBitWriter
+ LLVMDebugInfo LLVMExecutionEngine
+ LLVMInstCombine LLVMInstrumentation
+ LLVMInterpreter LLVMJIT
+ LLVMLinker LLVMMC
+ LLVMMCDisassembler LLVMMCJIT
+ LLVMMCParser LLVMObject
+ LLVMRuntimeDyld
+ LLVMSupport
+ LLVMTableGen LLVMTarget
+ LLVMTransformUtils LLVMVectorize
+ LLVMX86AsmParser LLVMX86AsmPrinter
+ LLVMX86CodeGen LLVMX86Desc
+ LLVMX86Disassembler LLVMX86Info
+ LLVMX86Utils LLVMipa
+ LLVMipo LLVMCore)
+ # imagehelp is needed by LLVM 3.1 on MinGW, check lib\Support\Windows\Signals.inc
+ list(APPEND PLATFORM_LINKLIBS -limagehlp)
+endif()
+
+if(WITH_OPENCOLORIO)
+ set(OPENCOLORIO ${LIBDIR}/opencolorio)
+ set(OPENCOLORIO_INCLUDE_DIRS ${OPENCOLORIO}/include)
+ set(OPENCOLORIO_LIBRARIES OpenColorIO)
+ set(OPENCOLORIO_LIBPATH ${OPENCOLORIO}/lib)
+ set(OPENCOLORIO_DEFINITIONS)
+endif()
+
+if(WITH_SDL)
+ set(SDL ${LIBDIR}/sdl)
+ set(SDL_INCLUDE_DIR ${SDL}/include)
+ set(SDL_LIBRARY SDL)
+ set(SDL_LIBPATH ${SDL}/lib)
+endif()
+
+if(WITH_OPENVDB)
+ set(OPENVDB ${LIBDIR}/openvdb)
+ set(OPENVDB_INCLUDE_DIRS ${OPENVDB}/include)
+ set(OPENVDB_LIBRARIES openvdb ${TBB_LIBRARIES})
+ set(OPENVDB_LIBPATH ${LIBDIR}/openvdb/lib)
+ set(OPENVDB_DEFINITIONS)
+endif()
+
+if(WITH_ALEMBIC)
+ # TODO(sergey): For until someone drops by and compiles libraries for
+ # MinGW we allow users to compile their own Alembic library and use
+ # that via find_package(),
+ #
+ # Once precompiled libraries are there we'll use hardcoded locations.
+ find_package_wrapper(Alembic)
+ if(WITH_ALEMBIC_HDF5)
+ set(HDF5_ROOT_DIR ${LIBDIR}/hdf5)
+ find_package_wrapper(HDF5)
+ endif()
+ if(NOT ALEMBIC_FOUND OR (WITH_ALEMBIC_HDF5 AND NOT HDF5_FOUND))
+ set(WITH_ALEMBIC OFF)
+ set(WITH_ALEMBIC_HDF5 OFF)
+ endif()
+endif()
+
+set(PLATFORM_LINKFLAGS "-Xlinker --stack=2097152")
+
+## DISABLE - causes linking errors
+## for re-distribution, so users dont need mingw installed
+# set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -static-libgcc -static-libstdc++")
diff --git a/build_files/cmake/platform/platform_win32_msvc.cmake b/build_files/cmake/platform/platform_win32_msvc.cmake
new file mode 100644
index 00000000000..5efda52b2c5
--- /dev/null
+++ b/build_files/cmake/platform/platform_win32_msvc.cmake
@@ -0,0 +1,487 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2016, Blender Foundation
+# All rights reserved.
+#
+# Contributor(s): Sergey Sharybin.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+# Libraries configuration for Windows when compiling with MSVC.
+
+macro(warn_hardcoded_paths package_name
+ )
+ if(WITH_WINDOWS_FIND_MODULES)
+ message(WARNING "Using HARDCODED ${package_name} locations")
+ endif(WITH_WINDOWS_FIND_MODULES)
+endmacro()
+
+macro(windows_find_package package_name
+ )
+ if(WITH_WINDOWS_FIND_MODULES)
+ find_package( ${package_name})
+ endif(WITH_WINDOWS_FIND_MODULES)
+endmacro()
+
+add_definitions(-DWIN32)
+# Minimum MSVC Version
+if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
+ if(MSVC_VERSION EQUAL 1800)
+ set(_min_ver "18.0.31101")
+ if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${_min_ver})
+ message(FATAL_ERROR
+ "Visual Studio 2013 (Update 4, ${_min_ver}) required, "
+ "found (${CMAKE_CXX_COMPILER_VERSION})")
+ endif()
+ endif()
+ if(MSVC_VERSION EQUAL 1900)
+ set(_min_ver "19.0.24210")
+ if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${_min_ver})
+ message(FATAL_ERROR
+ "Visual Studio 2015 (Update 3, ${_min_ver}) required, "
+ "found (${CMAKE_CXX_COMPILER_VERSION})")
+ endif()
+ endif()
+endif()
+unset(_min_ver)
+
+# needed for some MSVC installations
+set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO")
+set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SAFESEH:NO")
+set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /SAFESEH:NO")
+
+list(APPEND PLATFORM_LINKLIBS
+ ws2_32 vfw32 winmm kernel32 user32 gdi32 comdlg32
+ advapi32 shfolder shell32 ole32 oleaut32 uuid psapi Dbghelp
+)
+
+if(WITH_INPUT_IME)
+ list(APPEND PLATFORM_LINKLIBS imm32)
+endif()
+
+add_definitions(
+ -D_CRT_NONSTDC_NO_DEPRECATE
+ -D_CRT_SECURE_NO_DEPRECATE
+ -D_SCL_SECURE_NO_DEPRECATE
+ -D_CONSOLE
+ -D_LIB
+)
+
+# MSVC11 needs _ALLOW_KEYWORD_MACROS to build
+add_definitions(-D_ALLOW_KEYWORD_MACROS)
+
+# We want to support Vista level ABI
+add_definitions(-D_WIN32_WINNT=0x600)
+
+# Make cmake find the msvc redistributables
+set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP TRUE)
+include(InstallRequiredSystemLibraries)
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /nologo /J /Gd /MP /EHsc")
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /nologo /J /Gd /MP")
+
+set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
+set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd")
+set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
+set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT")
+set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} /MT")
+set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} /MT")
+set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /MT")
+set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} /MT")
+
+set(PLATFORM_LINKFLAGS "/SUBSYSTEM:CONSOLE /STACK:2097152 /INCREMENTAL:NO ")
+set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} /NODEFAULTLIB:msvcrt.lib /NODEFAULTLIB:msvcmrt.lib /NODEFAULTLIB:msvcurt.lib /NODEFAULTLIB:msvcrtd.lib ")
+
+# Ignore meaningless for us linker warnings.
+set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} /ignore:4049 /ignore:4217 /ignore:4221")
+set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4221")
+
+# MSVC only, Mingw doesnt need
+if(CMAKE_CL_64)
+ set(PLATFORM_LINKFLAGS "/MACHINE:X64 /OPT:NOREF ${PLATFORM_LINKFLAGS}")
+else()
+ set(PLATFORM_LINKFLAGS "/MACHINE:IX86 /LARGEADDRESSAWARE ${PLATFORM_LINKFLAGS}")
+endif()
+
+set(PLATFORM_LINKFLAGS_DEBUG "/IGNORE:4099 /NODEFAULTLIB:libcmt.lib /NODEFAULTLIB:libc.lib")
+
+if(NOT DEFINED LIBDIR)
+
+ # Setup 64bit and 64bit windows systems
+ if(CMAKE_CL_64)
+ message(STATUS "64 bit compiler detected.")
+ set(LIBDIR_BASE "win64")
+ else()
+ message(STATUS "32 bit compiler detected.")
+ set(LIBDIR_BASE "windows")
+ endif()
+
+ if(MSVC_VERSION EQUAL 1900)
+ message(STATUS "Visual Studio 2015 detected.")
+ set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc14)
+ else()
+ message(STATUS "Visual Studio 2013 detected.")
+ set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc12)
+ endif()
+else()
+ message(STATUS "Using pre-compiled LIBDIR: ${LIBDIR}")
+endif()
+if(NOT EXISTS "${LIBDIR}/")
+ message(FATAL_ERROR "Windows requires pre-compiled libs at: '${LIBDIR}'")
+endif()
+
+# Add each of our libraries to our cmake_prefix_path so find_package() could work
+file(GLOB children RELATIVE ${LIBDIR} ${LIBDIR}/*)
+foreach(child ${children})
+ if(IS_DIRECTORY ${LIBDIR}/${child})
+ list(APPEND CMAKE_PREFIX_PATH ${LIBDIR}/${child})
+ endif()
+endforeach()
+
+set(ZLIB_INCLUDE_DIRS ${LIBDIR}/zlib/include)
+set(ZLIB_LIBRARIES ${LIBDIR}/zlib/lib/libz_st.lib)
+set(ZLIB_INCLUDE_DIR ${LIBDIR}/zlib/include)
+set(ZLIB_LIBRARY ${LIBDIR}/zlib/lib/libz_st.lib)
+set(ZLIB_DIR ${LIBDIR}/zlib)
+
+windows_find_package(zlib) # we want to find before finding things that depend on it like png
+windows_find_package(png)
+
+if(NOT PNG_FOUND)
+ warn_hardcoded_paths(libpng)
+ set(PNG_PNG_INCLUDE_DIR ${LIBDIR}/png/include)
+ set(PNG_LIBRARIES libpng)
+ set(PNG "${LIBDIR}/png")
+ set(PNG_INCLUDE_DIRS "${PNG}/include")
+ set(PNG_LIBPATH ${PNG}/lib) # not cmake defined
+endif()
+
+set(JPEG_NAMES ${JPEG_NAMES} libjpeg)
+windows_find_package(jpeg REQUIRED)
+if(NOT JPEG_FOUND)
+ warn_hardcoded_paths(jpeg)
+ set(JPEG_INCLUDE_DIR ${LIBDIR}/jpeg/include)
+ set(JPEG_LIBRARIES ${LIBDIR}/jpeg/lib/libjpeg.lib)
+endif()
+
+set(PTHREADS_INCLUDE_DIRS ${LIBDIR}/pthreads/include)
+set(PTHREADS_LIBRARIES ${LIBDIR}/pthreads/lib/pthreadVC2.lib)
+
+set(FREETYPE ${LIBDIR}/freetype)
+set(FREETYPE_INCLUDE_DIRS
+ ${LIBDIR}/freetype/include
+ ${LIBDIR}/freetype/include/freetype2
+)
+set(FREETYPE_LIBRARY ${LIBDIR}/freetype/lib/freetype2ST.lib)
+windows_find_package(freetype REQUIRED)
+
+if(WITH_FFTW3)
+ set(FFTW3 ${LIBDIR}/fftw3)
+ set(FFTW3_LIBRARIES libfftw)
+ set(FFTW3_INCLUDE_DIRS ${FFTW3}/include)
+ set(FFTW3_LIBPATH ${FFTW3}/lib)
+endif()
+
+if(WITH_OPENCOLLADA)
+ set(OPENCOLLADA ${LIBDIR}/opencollada)
+
+ set(OPENCOLLADA_INCLUDE_DIRS
+ ${OPENCOLLADA}/include/opencollada/COLLADAStreamWriter
+ ${OPENCOLLADA}/include/opencollada/COLLADABaseUtils
+ ${OPENCOLLADA}/include/opencollada/COLLADAFramework
+ ${OPENCOLLADA}/include/opencollada/COLLADASaxFrameworkLoader
+ ${OPENCOLLADA}/include/opencollada/GeneratedSaxParser
+ )
+
+ set(OPENCOLLADA_LIBRARIES
+ ${OPENCOLLADA}/lib/opencollada/OpenCOLLADASaxFrameworkLoader.lib
+ ${OPENCOLLADA}/lib/opencollada/OpenCOLLADAFramework.lib
+ ${OPENCOLLADA}/lib/opencollada/OpenCOLLADABaseUtils.lib
+ ${OPENCOLLADA}/lib/opencollada/OpenCOLLADAStreamWriter.lib
+ ${OPENCOLLADA}/lib/opencollada/MathMLSolver.lib
+ ${OPENCOLLADA}/lib/opencollada/GeneratedSaxParser.lib
+ ${OPENCOLLADA}/lib/opencollada/xml.lib
+ ${OPENCOLLADA}/lib/opencollada/buffer.lib
+ ${OPENCOLLADA}/lib/opencollada/ftoa.lib
+ )
+
+ if(NOT WITH_LLVM)
+ list(APPEND OPENCOLLADA_LIBRARIES ${OPENCOLLADA}/lib/opencollada/UTF.lib)
+ endif()
+
+ set(PCRE_LIBRARIES
+ ${OPENCOLLADA}/lib/opencollada/pcre.lib
+ )
+endif()
+
+if(WITH_CODEC_FFMPEG)
+ set(FFMPEG_INCLUDE_DIRS
+ ${LIBDIR}/ffmpeg/include
+ ${LIBDIR}/ffmpeg/include/msvc
+ )
+ windows_find_package(FFMPEG)
+ if(NOT FFMPEG_FOUND)
+ warn_hardcoded_paths(ffmpeg)
+ set(FFMPEG_LIBRARY_VERSION 55)
+ set(FFMPEG_LIBRARY_VERSION_AVU 52)
+ set(FFMPEG_LIBRARIES
+ ${LIBDIR}/ffmpeg/lib/avcodec-${FFMPEG_LIBRARY_VERSION}.lib
+ ${LIBDIR}/ffmpeg/lib/avformat-${FFMPEG_LIBRARY_VERSION}.lib
+ ${LIBDIR}/ffmpeg/lib/avdevice-${FFMPEG_LIBRARY_VERSION}.lib
+ ${LIBDIR}/ffmpeg/lib/avutil-${FFMPEG_LIBRARY_VERSION_AVU}.lib
+ ${LIBDIR}/ffmpeg/lib/swscale-2.lib
+ )
+ endif()
+endif()
+
+if(WITH_IMAGE_OPENEXR)
+ set(OPENEXR_ROOT_DIR ${LIBDIR}/openexr)
+ set(OPENEXR_VERSION "2.1")
+ windows_find_package(OPENEXR REQUIRED)
+ if(NOT OPENEXR_FOUND)
+ warn_hardcoded_paths(OpenEXR)
+ set(OPENEXR ${LIBDIR}/openexr)
+ set(OPENEXR_INCLUDE_DIR ${OPENEXR}/include)
+ set(OPENEXR_INCLUDE_DIRS ${OPENEXR_INCLUDE_DIR} ${OPENEXR}/include/OpenEXR)
+ set(OPENEXR_LIBPATH ${OPENEXR}/lib)
+ set(OPENEXR_LIBRARIES
+ optimized ${OPENEXR_LIBPATH}/Iex-2_2.lib
+ optimized ${OPENEXR_LIBPATH}/Half.lib
+ optimized ${OPENEXR_LIBPATH}/IlmImf-2_2.lib
+ optimized ${OPENEXR_LIBPATH}/Imath-2_2.lib
+ optimized ${OPENEXR_LIBPATH}/IlmThread-2_2.lib
+ debug ${OPENEXR_LIBPATH}/Iex-2_2_d.lib
+ debug ${OPENEXR_LIBPATH}/Half_d.lib
+ debug ${OPENEXR_LIBPATH}/IlmImf-2_2_d.lib
+ debug ${OPENEXR_LIBPATH}/Imath-2_2_d.lib
+ debug ${OPENEXR_LIBPATH}/IlmThread-2_2_d.lib
+ )
+ endif()
+endif()
+
+if(WITH_IMAGE_TIFF)
+ # Try to find tiff first then complain and set static and maybe wrong paths
+ windows_find_package(TIFF)
+ if(NOT TIFF_FOUND)
+ warn_hardcoded_paths(libtiff)
+ set(TIFF_LIBRARY ${LIBDIR}/tiff/lib/libtiff.lib)
+ set(TIFF_INCLUDE_DIR ${LIBDIR}/tiff/include)
+ endif()
+endif()
+
+if(WITH_JACK)
+ set(JACK_INCLUDE_DIRS
+ ${LIBDIR}/jack/include/jack
+ ${LIBDIR}/jack/include
+ )
+ set(JACK_LIBRARIES optimized ${LIBDIR}/jack/lib/libjack.lib debug ${LIBDIR}/jack/lib/libjack_d.lib)
+endif()
+
+if(WITH_PYTHON)
+ set(PYTHON_VERSION 3.5) # CACHE STRING)
+
+ string(REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${PYTHON_VERSION})
+ # Use shared libs for vc2008 and vc2010 until we actually have vc2010 libs
+ set(PYTHON_LIBRARY ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}.lib)
+ unset(_PYTHON_VERSION_NO_DOTS)
+
+ # Shared includes for both vc2008 and vc2010
+ set(PYTHON_INCLUDE_DIR ${LIBDIR}/python/include/python${PYTHON_VERSION})
+
+ # uncached vars
+ set(PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIR}")
+ set(PYTHON_LIBRARIES "${PYTHON_LIBRARY}")
+endif()
+
+if(WITH_BOOST)
+ if(WITH_CYCLES_OSL)
+ set(boost_extra_libs wave)
+ endif()
+ if(WITH_INTERNATIONAL)
+ list(APPEND boost_extra_libs locale)
+ endif()
+ if(WITH_OPENVDB)
+ list(APPEND boost_extra_libs iostreams)
+ endif()
+ set(Boost_USE_STATIC_RUNTIME ON) # prefix lib
+ set(Boost_USE_MULTITHREADED ON) # suffix -mt
+ set(Boost_USE_STATIC_LIBS ON) # suffix -s
+ if (WITH_WINDOWS_FIND_MODULES)
+ find_package(Boost COMPONENTS date_time filesystem thread regex system ${boost_extra_libs})
+ endif (WITH_WINDOWS_FIND_MODULES)
+ if(NOT Boost_FOUND)
+ warn_hardcoded_paths(BOOST)
+ set(BOOST ${LIBDIR}/boost)
+ set(BOOST_INCLUDE_DIR ${BOOST}/include)
+ if(MSVC12)
+ set(BOOST_LIBPATH ${BOOST}/lib)
+ set(BOOST_POSTFIX "vc120-mt-s-1_60.lib")
+ set(BOOST_DEBUG_POSTFIX "vc120-mt-sgd-1_60.lib")
+ else()
+ set(BOOST_LIBPATH ${BOOST}/lib)
+ set(BOOST_POSTFIX "vc140-mt-s-1_60.lib")
+ set(BOOST_DEBUG_POSTFIX "vc140-mt-sgd-1_60.lib")
+ endif()
+ set(BOOST_LIBRARIES
+ optimized libboost_date_time-${BOOST_POSTFIX}
+ optimized libboost_filesystem-${BOOST_POSTFIX}
+ optimized libboost_regex-${BOOST_POSTFIX}
+ optimized libboost_system-${BOOST_POSTFIX}
+ optimized libboost_thread-${BOOST_POSTFIX}
+ debug libboost_date_time-${BOOST_DEBUG_POSTFIX}
+ debug libboost_filesystem-${BOOST_DEBUG_POSTFIX}
+ debug libboost_regex-${BOOST_DEBUG_POSTFIX}
+ debug libboost_system-${BOOST_DEBUG_POSTFIX}
+ debug libboost_thread-${BOOST_DEBUG_POSTFIX}
+ )
+ if(WITH_CYCLES_OSL)
+ set(BOOST_LIBRARIES ${BOOST_LIBRARIES}
+ optimized libboost_wave-${BOOST_POSTFIX}
+ debug libboost_wave-${BOOST_DEBUG_POSTFIX})
+ endif()
+ if(WITH_INTERNATIONAL)
+ set(BOOST_LIBRARIES ${BOOST_LIBRARIES}
+ optimized libboost_locale-${BOOST_POSTFIX}
+ debug libboost_locale-${BOOST_DEBUG_POSTFIX})
+ endif()
+ else() # we found boost using find_package
+ set(BOOST_INCLUDE_DIR ${Boost_INCLUDE_DIRS})
+ set(BOOST_LIBRARIES ${Boost_LIBRARIES})
+ set(BOOST_LIBPATH ${Boost_LIBRARY_DIRS})
+ endif()
+ set(BOOST_DEFINITIONS "-DBOOST_ALL_NO_LIB")
+endif()
+
+if(WITH_OPENIMAGEIO)
+ windows_find_package(OpenImageIO)
+ set(OPENIMAGEIO ${LIBDIR}/openimageio)
+ set(OPENIMAGEIO_INCLUDE_DIRS ${OPENIMAGEIO}/include)
+ set(OIIO_OPTIMIZED optimized OpenImageIO optimized OpenImageIO_Util)
+ set(OIIO_DEBUG debug OpenImageIO_d debug OpenImageIO_Util_d)
+ set(OPENIMAGEIO_LIBRARIES ${OIIO_OPTIMIZED} ${OIIO_DEBUG})
+ set(OPENIMAGEIO_LIBPATH ${OPENIMAGEIO}/lib)
+ set(OPENIMAGEIO_DEFINITIONS "-DUSE_TBB=0")
+ set(OPENCOLORIO_DEFINITIONS "-DOCIO_STATIC_BUILD")
+ set(OPENIMAGEIO_IDIFF "${OPENIMAGEIO}/bin/idiff.exe")
+ add_definitions(-DOIIO_STATIC_BUILD)
+endif()
+
+if(WITH_LLVM)
+ set(LLVM_ROOT_DIR ${LIBDIR}/llvm CACHE PATH "Path to the LLVM installation")
+ file(GLOB LLVM_LIBRARY_OPTIMIZED ${LLVM_ROOT_DIR}/lib/*.lib)
+
+ if(EXISTS ${LLVM_ROOT_DIR}/debug/lib)
+ foreach(LLVM_OPTIMIZED_LIB ${LLVM_LIBRARY_OPTIMIZED})
+ get_filename_component(LIBNAME ${LLVM_OPTIMIZED_LIB} ABSOLUTE)
+ list(APPEND LLVM_LIBS optimized ${LIBNAME})
+ endforeach(LLVM_OPTIMIZED_LIB)
+
+ file(GLOB LLVM_LIBRARY_DEBUG ${LLVM_ROOT_DIR}/debug/lib/*.lib)
+
+ foreach(LLVM_DEBUG_LIB ${LLVM_LIBRARY_DEBUG})
+ get_filename_component(LIBNAME ${LLVM_DEBUG_LIB} ABSOLUTE)
+ list(APPEND LLVM_LIBS debug ${LIBNAME})
+ endforeach(LLVM_DEBUG_LIB)
+
+ set(LLVM_LIBRARY ${LLVM_LIBS})
+ else()
+ message(WARNING "LLVM debug libs not present on this system. Using release libs for debug builds.")
+ set(LLVM_LIBRARY ${LLVM_LIBRARY_OPTIMIZED})
+ endif()
+
+endif()
+
+if(WITH_OPENCOLORIO)
+ set(OPENCOLORIO ${LIBDIR}/opencolorio)
+ set(OPENCOLORIO_INCLUDE_DIRS ${OPENCOLORIO}/include)
+ set(OPENCOLORIO_LIBRARIES OpenColorIO)
+ set(OPENCOLORIO_LIBPATH ${LIBDIR}/opencolorio/lib)
+ set(OPENCOLORIO_DEFINITIONS)
+endif()
+
+if(WITH_OPENVDB)
+ set(BLOSC_LIBRARIES optimized ${LIBDIR}/blosc/lib/libblosc.lib debug ${LIBDIR}/blosc/lib/libblosc_d.lib)
+ set(TBB_LIBRARIES optimized ${LIBDIR}/tbb/lib/tbb.lib debug ${LIBDIR}/tbb/lib/tbb_debug.lib)
+ set(TBB_INCLUDE_DIR ${LIBDIR}/tbb/include)
+ set(OPENVDB ${LIBDIR}/openvdb)
+ set(OPENVDB_INCLUDE_DIRS ${OPENVDB}/include ${TBB_INCLUDE_DIR})
+ set(OPENVDB_LIBRARIES optimized openvdb debug openvdb_d ${TBB_LIBRARIES} ${BLOSC_LIBRARIES})
+ set(OPENVDB_LIBPATH ${LIBDIR}/openvdb/lib)
+endif()
+
+if(WITH_ALEMBIC)
+ set(ALEMBIC ${LIBDIR}/alembic)
+ set(ALEMBIC_INCLUDE_DIR ${ALEMBIC}/include)
+ set(ALEMBIC_INCLUDE_DIRS ${ALEMBIC_INCLUDE_DIR})
+ set(ALEMBIC_LIBPATH ${ALEMBIC}/lib)
+ set(ALEMBIC_LIBRARIES optimized alembic debug alembic_d)
+endif()
+
+if(WITH_MOD_CLOTH_ELTOPO)
+ set(LAPACK ${LIBDIR}/lapack)
+ # set(LAPACK_INCLUDE_DIR ${LAPACK}/include)
+ set(LAPACK_LIBPATH ${LAPACK}/lib)
+ set(LAPACK_LIBRARIES
+ ${LIBDIR}/lapack/lib/libf2c.lib
+ ${LIBDIR}/lapack/lib/clapack_nowrap.lib
+ ${LIBDIR}/lapack/lib/BLAS_nowrap.lib
+ )
+endif()
+
+if(WITH_OPENSUBDIV OR WITH_CYCLES_OPENSUBDIV)
+ set(OPENSUBDIV_INCLUDE_DIR ${LIBDIR}/opensubdiv/include)
+ set(OPENSUBDIV_LIBPATH ${LIBDIR}/opensubdiv/lib)
+ set(OPENSUBDIV_LIBRARIES ${OPENSUBDIV_LIBPATH}/osdCPU.lib ${OPENSUBDIV_LIBPATH}/osdGPU.lib)
+ find_package(OpenSubdiv)
+endif()
+
+if(WITH_SDL)
+ set(SDL ${LIBDIR}/sdl)
+ set(SDL_INCLUDE_DIR ${SDL}/include)
+ set(SDL_LIBPATH ${SDL}/lib)
+ # MinGW TODO: Update MinGW to SDL2
+ if(NOT CMAKE_COMPILER_IS_GNUCC)
+ set(SDL_LIBRARY SDL2)
+ else()
+ set(SDL_LIBRARY SDL)
+ endif()
+endif()
+
+# Audio IO
+if(WITH_SYSTEM_AUDASPACE)
+ set(AUDASPACE_INCLUDE_DIRS ${LIBDIR}/audaspace/include/audaspace)
+ set(AUDASPACE_LIBRARIES ${LIBDIR}/audaspace/lib/audaspace.lib)
+ set(AUDASPACE_C_INCLUDE_DIRS ${LIBDIR}/audaspace/include/audaspace)
+ set(AUDASPACE_C_LIBRARIES ${LIBDIR}/audaspace/lib/audaspace-c.lib)
+ set(AUDASPACE_PY_INCLUDE_DIRS ${LIBDIR}/audaspace/include/audaspace)
+ set(AUDASPACE_PY_LIBRARIES ${LIBDIR}/audaspace/lib/audaspace-py.lib)
+endif()
+
+# used in many places so include globally, like OpenGL
+blender_include_dirs_sys("${PTHREADS_INCLUDE_DIRS}")
+
+#find signtool
+SET(ProgramFilesX86_NAME "ProgramFiles(x86)") #env dislikes the ( )
+find_program(SIGNTOOL_EXE signtool
+HINTS
+ "$ENV{${ProgramFilesX86_NAME}}/Windows Kits/10/bin/x86/"
+ "$ENV{ProgramFiles}/Windows Kits/10/bin/x86/"
+ "$ENV{${ProgramFilesX86_NAME}}/Windows Kits/8.1/bin/x86/"
+ "$ENV{ProgramFiles}/Windows Kits/8.1/bin/x86/"
+ "$ENV{${ProgramFilesX86_NAME}}/Windows Kits/8.0/bin/x86/"
+ "$ENV{ProgramFiles}/Windows Kits/8.0/bin/x86/"
+)
diff --git a/build_files/cmake/project_info.py b/build_files/cmake/project_info.py
index cfcd9df65c8..deea844034c 100755
--- a/build_files/cmake/project_info.py
+++ b/build_files/cmake/project_info.py
@@ -39,7 +39,7 @@ __all__ = (
"is_py",
"cmake_advanced_info",
"cmake_compiler_defines",
- "project_name_get"
+ "project_name_get",
"init",
)
@@ -214,7 +214,12 @@ def cmake_advanced_info():
def cmake_cache_var(var):
cache_file = open(join(CMAKE_DIR, "CMakeCache.txt"), encoding='utf-8')
- lines = [l_strip for l in cache_file for l_strip in (l.strip(),) if l_strip if not l_strip.startswith("//") if not l_strip.startswith("#")]
+ lines = [
+ l_strip for l in cache_file
+ for l_strip in (l.strip(),)
+ if l_strip
+ if not l_strip.startswith(("//", "#"))
+ ]
cache_file.close()
for l in lines:
diff --git a/build_files/cmake/project_source_info.py b/build_files/cmake/project_source_info.py
index 45d732c2422..3ba26513491 100644
--- a/build_files/cmake/project_source_info.py
+++ b/build_files/cmake/project_source_info.py
@@ -23,7 +23,7 @@
__all__ = (
"build_info",
"SOURCE_DIR",
- )
+)
import sys
diff --git a/build_files/package_spec/build_archive.py b/build_files/package_spec/build_archive.py
index 6a7ec8a0faa..bd00984c74b 100755
--- a/build_files/package_spec/build_archive.py
+++ b/build_files/package_spec/build_archive.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# <pep8 compliant>
diff --git a/build_files/package_spec/pacman/PKGBUILD b/build_files/package_spec/pacman/PKGBUILD
index 961e35578b9..aea5acd13e4 100644
--- a/build_files/package_spec/pacman/PKGBUILD
+++ b/build_files/package_spec/pacman/PKGBUILD
@@ -2,11 +2,9 @@
# custom blender vars
blender_srcdir=$(dirname $startdir)"/../.."
-# value may be formatted: 35042:35051M
-blender_revision=$(svnversion $blender_srcdir | cut -d: -f2 | awk '{print $3}')
-blender_version=$(grep "BLENDER_VERSION\s" $blender_srcdir/source/blender/blenkernel/BKE_blender.h | awk '{print $3}')
+blender_version=$(grep "BLENDER_VERSION\s" $blender_srcdir/source/blender/blenkernel/BKE_blender_version.h | awk '{print $3}')
blender_version=$(expr $blender_version / 100).$(expr $blender_version % 100) # 256 -> 2.56
-blender_version_char=$(sed -ne 's/.*BLENDER_VERSION_CHAR.*\([a-z]\)$/\1/p' $blender_srcdir/source/blender/blenkernel/BKE_blender.h)
+blender_version_char=$(sed -ne 's/.*BLENDER_VERSION_CHAR.*\([a-z]\)$/\1/p' $blender_srcdir/source/blender/blenkernel/BKE_blender_version.h)
# blender_subversion=$(grep BLENDER_SUBVERSION $blender_srcdir/source/blender/blenkernel/BKE_blender.h | awk '{print $3}')
# map the version a -> 1
@@ -27,7 +25,9 @@ arch=('i686' 'x86_64')
url="www.blender.org"
license=('GPL')
groups=()
-depends=('libjpeg' 'libpng' 'openjpeg' 'libtiff' 'openexr' 'python>=3.4' 'gettext' 'libxi' 'libxmu' 'mesa' 'freetype2' 'openal' 'sdl' 'libsndfile' 'ffmpeg')
+depends=('libjpeg' 'libpng' 'openjpeg' 'libtiff' 'openexr' 'python>=3.5'
+ 'gettext' 'libxi' 'libxmu' 'mesa' 'freetype2' 'openal' 'sdl'
+ 'libsndfile' 'ffmpeg')
makedepends=('cmake' 'git')
optdepends=()
provides=()
diff --git a/build_files/utils/build_tgz.sh b/build_files/utils/build_tgz.sh
index 3c921081c29..865df277605 100755
--- a/build_files/utils/build_tgz.sh
+++ b/build_files/utils/build_tgz.sh
@@ -6,10 +6,10 @@
BASE_DIR="$PWD"
blender_srcdir=$(dirname -- $0)/../..
-blender_version=$(grep "BLENDER_VERSION\s" "$blender_srcdir/source/blender/blenkernel/BKE_blender.h" | awk '{print $3}')
-blender_version_char=$(grep "BLENDER_VERSION_CHAR\s" "$blender_srcdir/source/blender/blenkernel/BKE_blender.h" | awk '{print $3}')
-blender_version_cycle=$(grep "BLENDER_VERSION_CYCLE\s" "$blender_srcdir/source/blender/blenkernel/BKE_blender.h" | awk '{print $3}')
-blender_subversion=$(grep "BLENDER_SUBVERSION\s" "$blender_srcdir/source/blender/blenkernel/BKE_blender.h" | awk '{print $3}')
+blender_version=$(grep "BLENDER_VERSION\s" "$blender_srcdir/source/blender/blenkernel/BKE_blender_version.h" | awk '{print $3}')
+blender_version_char=$(grep "BLENDER_VERSION_CHAR\s" "$blender_srcdir/source/blender/blenkernel/BKE_blender_version.h" | awk '{print $3}')
+blender_version_cycle=$(grep "BLENDER_VERSION_CYCLE\s" "$blender_srcdir/source/blender/blenkernel/BKE_blender_version.h" | awk '{print $3}')
+blender_subversion=$(grep "BLENDER_SUBVERSION\s" "$blender_srcdir/source/blender/blenkernel/BKE_blender_version.h" | awk '{print $3}')
if [ "$blender_version_cycle" = "release" ] ; then
VERSION=$(expr $blender_version / 100).$(expr $blender_version % 100)$blender_version_char
diff --git a/doc/blender_file_format/mystery_of_the_blend.html b/doc/blender_file_format/mystery_of_the_blend.html
index b34493ffa3e..599cb4a05bc 100644
--- a/doc/blender_file_format/mystery_of_the_blend.html
+++ b/doc/blender_file_format/mystery_of_the_blend.html
@@ -187,7 +187,7 @@ The next table describes the information in the file-header.
</table>
<p>
-<a href="http://en.wikipedia.org/wiki/Endianness">Endianness</a> addresses the way values are ordered in a sequence of bytes(see the <a href="#example-endianess">example</a> below):
+<a href="https://en.wikipedia.org/wiki/Endianness">Endianness</a> addresses the way values are ordered in a sequence of bytes(see the <a href="#example-endianess">example</a> below):
</p>
<ul>
diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile
index b34d4dfe6f1..8b3a97816ba 100644
--- a/doc/doxygen/Doxyfile
+++ b/doc/doxygen/Doxyfile
@@ -38,7 +38,7 @@ PROJECT_NAME = Blender
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = "V2.7x"
+PROJECT_NUMBER = "V2.8x"
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
@@ -699,7 +699,7 @@ LAYOUT_FILE =
# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
# the reference definitions. This must be a list of .bib files. The .bib
# extension is automatically appended if omitted. This requires the bibtex tool
-# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
# For LaTeX the style of the bibliography can be controlled using
# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
# search path. See also \cite for info how to create references.
@@ -1145,7 +1145,7 @@ HTML_EXTRA_FILES =
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
# will adjust the colors in the style sheet and background images according to
# this color. Hue is specified as an angle on a colorwheel, see
-# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
# purple, and 360 is red again.
# Minimum value: 0, maximum value: 359, default value: 220.
@@ -1752,7 +1752,7 @@ LATEX_SOURCE_CODE = NO
# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
# bibliography, e.g. plainnat, or ieeetr. See
-# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
# The default value is: plain.
# This tag requires that the tag GENERATE_LATEX is set to YES.
diff --git a/doc/manpage/blender.1.py b/doc/manpage/blender.1.py
index cdd2d7ca2df..52856717b4a 100755
--- a/doc/manpage/blender.1.py
+++ b/doc/manpage/blender.1.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# ##### BEGIN GPL LICENSE BLOCK #####
#
diff --git a/doc/python_api/epy/IDProp.py b/doc/python_api/epy/IDProp.py
deleted file mode 100644
index 1fc26d7f65b..00000000000
--- a/doc/python_api/epy/IDProp.py
+++ /dev/null
@@ -1,132 +0,0 @@
-class IDGroup:
- """
- The IDGroup Type
- ================
- This type supports both iteration and the []
- operator to get child ID properties.
-
- You can also add new properties using the [] operator.
- For example::
-
- group['a float!'] = 0.0
- group['an int!'] = 0
- group['a string!'] = "hi!"
- group['an array!'] = [0, 0, 1.0, 0]
-
- group['a subgroup!] = {"float": 0.0, "an int": 1.0, "an array": [1, 2],
- "another subgroup": {"a": 0.0, "str": "bleh"}}
-
- Note that for arrays, the array type defaults to int unless a float is found
- while scanning the template list; if any floats are found, then the whole
- array is float. Note that double-precision floating point numbers are used for
- python-created float ID properties and arrays (though the internal C api does
- support single-precision floats, and the python code will read them).
-
- You can also delete properties with the del operator. For example:
-
- del group['property']
-
- To get the type of a property, use the type() operator, for example::
-
- if type(group['bleh']) == str: pass
-
- To tell if the property is a group or array type, import the Blender.Types module and test
- against IDGroupType and IDArrayType, like so::
-
- from Blender.Types import IDGroupType, IDArrayType.
-
- if type(group['bleghr']) == IDGroupType:
- (do something)
-
- @ivar name: The name of the property
- @type name: string
- """
-
- def pop(item):
- """
- Pop an item from the group property.
- @type item: string
- @param item: The item name.
- @rtype: can be dict, list, int, float or string.
- @return: The removed property.
- """
-
- def update(updatedict):
- """
- Updates items in the dict, similar to normal python
- dictionary method .update().
- @type updatedict: dict
- @param updatedict: A dict of simple types to derive updated/new IDProperties from.
- @rtype: None
- @return: None
- """
-
- def keys():
- """
- Returns a list of the keys in this property group.
- @rtype: list of strings.
- @return: a list of the keys in this property group.
- """
-
- def values():
- """
- Returns a list of the values in this property group.
-
- Note that unless a value is itself a property group or an array, you
- cannot change it by changing the values in this list, you must change them
- in the parent property group.
-
- For example,
-
- group['some_property'] = new_value
-
- . . .is correct, while,
-
- values = group.values()
- values[0] = new_value
-
- . . .is wrong.
-
- @rtype: list of strings.
- @return: a list of the values in this property group.
- """
-
- def iteritems():
- """
- Implements the python dictionary iteritmes method.
-
- For example::
-
- for k, v in group.iteritems():
- print "Property name: " + k
- print "Property value: " + str(v)
-
- @rtype: an iterator that spits out items of the form [key, value]
- @return: an iterator.
- """
-
- def convert_to_pyobject():
- """
- Converts the entire property group to a purely python form.
-
- @rtype: dict
- @return: A python dictionary representing the property group
- """
-
-class IDArray:
- """
- The IDArray Type
- ================
-
- @ivar type: returns the type of the array, can be either IDP_Int or IDP_Float
- """
-
- def __getitem__(index):
- pass
-
- def __setitem__(index, value):
- pass
-
- def __len__():
- pass
-
diff --git a/doc/python_api/examples/bge.texture.2.py b/doc/python_api/examples/bge.texture.2.py
new file mode 100644
index 00000000000..96619007fba
--- /dev/null
+++ b/doc/python_api/examples/bge.texture.2.py
@@ -0,0 +1,237 @@
+"""
+Video Capture with DeckLink
++++++++++++++++++++++++++++
+Video frames captured with DeckLink cards have pixel formats that are generally not directly
+usable by OpenGL, they must be processed by a shader. The three shaders presented here should
+cover all common video capture cases.
+
+This file reflects the current video transfer method implemented in the Decklink module:
+whenever possible the video images are transferred as float texture because this is more
+compatible with GPUs. Of course, only the pixel formats that have a correspondant GL format
+can be transferred as float. Look for fg_shaders in this file for an exhaustive list.
+
+Other pixel formats will be transferred as 32 bits integer red-channel texture but this
+won't work with certain GPU (Intel GMA); the corresponding shaders are not shown here.
+However, it should not be necessary to use any of them as the list below covers all practical
+cases of video capture with all types of Decklink product.
+
+In other words, only use one of the pixel format below and you will be fine. Note that depending
+on the video stream, only certain pixel formats will be allowed (others will throw an exception).
+For example, to capture a PAL video stream, you must use one of the YUV formats.
+
+To find which pixel format is suitable for a particular video stream, use the 'Media Express'
+utility that comes with the Decklink software : if you see the video in the 'Log and Capture'
+Window, you have selected the right pixel format and you can use the same in Blender.
+
+Notes: * these shaders only decode the RGB channel and set the alpha channel to a fixed
+value (look for color.a = ). It's up to you to add postprocessing to the color.
+ * these shaders are compatible with 2D and 3D video stream
+"""
+import bge
+from bge import logic
+from bge import texture as vt
+
+# The default vertex shader, because we need one
+#
+VertexShader = """
+#version 130
+ void main()
+ {
+ gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
+ gl_TexCoord[0] = gl_MultiTexCoord0;
+ }
+
+"""
+
+# For use with RGB video stream: the pixel is directly usable
+#
+FragmentShader_R10l = """
+ #version 130
+ uniform sampler2D tex;
+ // stereo = 1.0 if 2D image, =0.5 if 3D (left eye below, right eye above)
+ uniform float stereo;
+ // eye = 0.0 for the left eye, 0.5 for the right eye
+ uniform float eye;
+
+ void main(void)
+ {
+ vec4 color;
+ float tx, ty;
+ tx = gl_TexCoord[0].x;
+ ty = eye+gl_TexCoord[0].y*stereo;
+ color = texture(tex, vec2(tx,ty));
+ color.a = 0.7;
+ gl_FragColor = color;
+ }
+"""
+
+# For use with YUV video stream
+#
+FragmentShader_2vuy = """
+ #version 130
+ uniform sampler2D tex;
+ // stereo = 1.0 if 2D image, =0.5 if 3D (left eye below, right eye above)
+ uniform float stereo;
+ // eye = 0.0 for the left eye, 0.5 for the right eye
+ uniform float eye;
+
+ void main(void)
+ {
+ vec4 color;
+ float tx, ty, width, Y, Cb, Cr;
+ int px;
+ tx = gl_TexCoord[0].x;
+ ty = eye+gl_TexCoord[0].y*stereo;
+ width = float(textureSize(tex, 0).x);
+ color = texture(tex, vec2(tx, ty));
+ px = int(floor(fract(tx*width)*2.0));
+ switch (px) {
+ case 0:
+ Y = color.g;
+ break;
+ case 1:
+ Y = color.a;
+ break;
+ }
+ Y = (Y - 0.0625) * 1.168949772;
+ Cb = (color.b - 0.0625) * 1.142857143 - 0.5;
+ Cr = (color.r - 0.0625) * 1.142857143 - 0.5;
+ color.r = Y + 1.5748 * Cr;
+ color.g = Y - 0.1873 * Cb - 0.4681 * Cr;
+ color.b = Y + 1.8556 * Cb;
+ color.a = 0.7;
+ gl_FragColor = color;
+ }
+"""
+
+# For use with high resolution YUV
+#
+FragmentShader_v210 = """
+ #version 130
+ uniform sampler2D tex;
+ // stereo = 1.0 if 2D image, =0.5 if 3D (left eye below, right eye above)
+ uniform float stereo;
+ // eye = 0.0 for the left eye, 0.5 for the right eye
+ uniform float eye;
+
+ void main(void)
+ {
+ vec4 color, color1, color2, color3;
+ int px;
+ float tx, ty, width, sx, dx, bx, Y, Cb, Cr;
+ tx = gl_TexCoord[0].x;
+ ty = eye+gl_TexCoord[0].y*stereo;
+ width = float(textureSize(tex, 0).x);
+ // to sample macro pixels (6 pixels in 4 words)
+ sx = tx*width*0.25+0.01;
+ // index of display pixel in the macro pixel 0..5
+ px = int(floor(fract(sx)*6.0));
+ // increment as we sample the macro pixel
+ dx = 1.0/width;
+ // base x coord of macro pixel
+ bx = (floor(sx)+0.01)*dx*4.0;
+ color = texture(tex, vec2(bx, ty));
+ color1 = texture(tex, vec2(bx+dx, ty));
+ color2 = texture(tex, vec2(bx+dx*2.0, ty));
+ color3 = texture(tex, vec2(bx+dx*3.0, ty));
+ switch (px) {
+ case 0:
+ case 1:
+ Cb = color.b;
+ Cr = color.r;
+ break;
+ case 2:
+ case 3:
+ Cb = color1.g;
+ Cr = color2.b;
+ break;
+ default:
+ Cb = color2.r;
+ Cr = color3.g;
+ break;
+ }
+ switch (px) {
+ case 0:
+ Y = color.g;
+ break;
+ case 1:
+ Y = color1.b;
+ break;
+ case 2:
+ Y = color1.r;
+ break;
+ case 3:
+ Y = color2.g;
+ break;
+ case 4:
+ Y = color3.b;
+ break;
+ default:
+ Y = color3.r;
+ break;
+ }
+ Y = (Y - 0.0625) * 1.168949772;
+ Cb = (Cb - 0.0625) * 1.142857143 - 0.5;
+ Cr = (Cr - 0.0625) * 1.142857143 - 0.5;
+ color.r = Y + 1.5748 * Cr;
+ color.g = Y - 0.1873 * Cb - 0.4681 * Cr;
+ color.b = Y + 1.8556 * Cb;
+ color.a = 0.7;
+ gl_FragColor = color;
+ }
+"""
+
+# The exhausitve list of pixel formats that are transferred as float texture
+# Only use those for greater efficiency and compatiblity.
+#
+fg_shaders = {
+ '2vuy' :FragmentShader_2vuy,
+ '8BitYUV' :FragmentShader_2vuy,
+ 'v210' :FragmentShader_v210,
+ '10BitYUV' :FragmentShader_v210,
+ '8BitBGRA' :FragmentShader_R10l,
+ 'BGRA' :FragmentShader_R10l,
+ '8BitARGB' :FragmentShader_R10l,
+ '10BitRGBXLE':FragmentShader_R10l,
+ 'R10l' :FragmentShader_R10l
+ }
+
+
+#
+# Helper function to attach a pixel shader to the material that receives the video frame.
+#
+
+def config_video(obj, format, pixel, is3D=False, mat=0, card=0):
+ if pixel not in fg_shaders:
+ raise('Unsuported shader')
+ shader = obj.meshes[0].materials[mat].getShader()
+ if shader is not None and not shader.isValid():
+ shader.setSource(VertexShader, fg_shaders[pixel], True)
+ shader.setSampler('tex', 0)
+ shader.setUniformEyef("eye")
+ shader.setUniform1f("stereo", 0.5 if is3D else 1.0)
+ tex = vt.Texture(obj, mat)
+ tex.source = vt.VideoDeckLink(format + "/" + pixel + ("/3D" if is3D else ""), card)
+ print("frame rate: ", tex.source.framerate)
+ tex.source.play()
+ obj["video"] = tex
+
+#
+# Attach this function to an object that has a material with texture
+# and call it once to initialize the object
+#
+def init(cont):
+ # config_video(cont.owner, 'HD720p5994', '8BitBGRA')
+ # config_video(cont.owner, 'HD720p5994', '8BitYUV')
+ # config_video(cont.owner, 'pal ', '10BitYUV')
+ config_video(cont.owner, 'pal ', '8BitYUV')
+
+
+#
+# To be called on every frame
+#
+def play(cont):
+ obj = cont.owner
+ video = obj.get("video")
+ if video is not None:
+ video.refresh(True)
diff --git a/doc/python_api/examples/bpy.app.handlers.1.py b/doc/python_api/examples/bpy.app.handlers.1.py
index 48fdb95d793..245ac199d58 100644
--- a/doc/python_api/examples/bpy.app.handlers.1.py
+++ b/doc/python_api/examples/bpy.app.handlers.1.py
@@ -4,7 +4,7 @@ Persistent Handler Example
By default handlers are freed when loading new files, in some cases you may
wan't the handler stay running across multiple files (when the handler is
-part of an addon for example).
+part of an add-on for example).
For this the :data:`bpy.app.handlers.persistent` decorator needs to be used.
"""
diff --git a/doc/python_api/examples/bpy.app.translations.py b/doc/python_api/examples/bpy.app.translations.py
index 6ea749c7e1e..e41623d2885 100644
--- a/doc/python_api/examples/bpy.app.translations.py
+++ b/doc/python_api/examples/bpy.app.translations.py
@@ -5,7 +5,7 @@ Intro
.. warning::
Most of this object should only be useful if you actually manipulate i18n stuff from Python.
- If you are a regular addon, you should only bother about :const:`contexts` member,
+ If you are a regular add-on, you should only bother about :const:`contexts` member,
and the :func:`register`/:func:`unregister` functions! The :func:`pgettext` family of functions
should only be used in rare, specific cases (like e.g. complex "composited" UI strings...).
@@ -21,11 +21,11 @@ Intro
Then, call ``bpy.app.translations.register(__name__, your_dict)`` in your ``register()`` function, and
``bpy.app.translations.unregister(__name__)`` in your ``unregister()`` one.
-The ``Manage UI translations`` addon has several functions to help you collect strings to translate, and
+The ``Manage UI translations`` add-on has several functions to help you collect strings to translate, and
generate the needed python code (the translation dictionary), as well as optional intermediary po files
if you want some... See
-`How to Translate Blender <http://wiki.blender.org/index.php/Dev:Doc/Process/Translate_Blender>`_ and
-`Using i18n in Blender Code <http://wiki.blender.org/index.php/Dev:Source/Interface/Internationalization>`_
+`How to Translate Blender <https://wiki.blender.org/index.php/Dev:Doc/Process/Translate_Blender>`_ and
+`Using i18n in Blender Code <https://wiki.blender.org/index.php/Dev:Source/Interface/Internationalization>`_
for more info.
Module References
diff --git a/doc/python_api/examples/bpy.types.AddonPreferences.1.py b/doc/python_api/examples/bpy.types.AddonPreferences.1.py
index 7a065dbf6a5..e478ba9b19a 100644
--- a/doc/python_api/examples/bpy.types.AddonPreferences.1.py
+++ b/doc/python_api/examples/bpy.types.AddonPreferences.1.py
@@ -1,10 +1,10 @@
bl_info = {
- "name": "Example Addon Preferences",
+ "name": "Example Add-on Preferences",
"author": "Your Name Here",
"version": (1, 0),
"blender": (2, 65, 0),
- "location": "SpaceBar Search -> Addon Preferences Example",
- "description": "Example Addon",
+ "location": "SpaceBar Search -> Add-on Preferences Example",
+ "description": "Example Add-on",
"warning": "",
"wiki_url": "",
"tracker_url": "",
@@ -18,7 +18,7 @@ from bpy.props import StringProperty, IntProperty, BoolProperty
class ExampleAddonPreferences(AddonPreferences):
- # this must match the addon name, use '__package__'
+ # this must match the add-on name, use '__package__'
# when defining this in a submodule of a python package.
bl_idname = __name__
@@ -37,7 +37,7 @@ class ExampleAddonPreferences(AddonPreferences):
def draw(self, context):
layout = self.layout
- layout.label(text="This is a preferences view for our addon")
+ layout.label(text="This is a preferences view for our add-on")
layout.prop(self, "filepath")
layout.prop(self, "number")
layout.prop(self, "boolean")
@@ -46,7 +46,7 @@ class ExampleAddonPreferences(AddonPreferences):
class OBJECT_OT_addon_prefs_example(Operator):
"""Display example preferences"""
bl_idname = "object.addon_prefs_example"
- bl_label = "Addon Preferences Example"
+ bl_label = "Add-on Preferences Example"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
diff --git a/doc/python_api/examples/bpy.types.Menu.2.py b/doc/python_api/examples/bpy.types.Menu.2.py
index 86288b5b1c5..50460f65b3d 100644
--- a/doc/python_api/examples/bpy.types.Menu.2.py
+++ b/doc/python_api/examples/bpy.types.Menu.2.py
@@ -2,9 +2,9 @@
Extending Menus
+++++++++++++++
-When creating menus for addons you can't reference menus in Blender's default
-scripts.
-Instead, the addon can add menu items to existing menus.
+When creating menus for add-ons you can't reference menus
+in Blender's default scripts.
+Instead, the add-on can add menu items to existing menus.
The function menu_draw acts like :class:`Menu.draw`.
"""
diff --git a/doc/python_api/examples/bpy.types.PropertyGroup.py b/doc/python_api/examples/bpy.types.PropertyGroup.py
index d5260bf94bb..2c2aa6d9b11 100644
--- a/doc/python_api/examples/bpy.types.PropertyGroup.py
+++ b/doc/python_api/examples/bpy.types.PropertyGroup.py
@@ -13,7 +13,7 @@ be animated, accessed from the user interface and from python.
definitions are not, this means whenever you load blender the class needs
to be registered too.
- This is best done by creating an addon which loads on startup and registers
+ This is best done by creating an add-on which loads on startup and registers
your properties.
.. note::
diff --git a/doc/python_api/examples/mathutils.Vector.py b/doc/python_api/examples/mathutils.Vector.py
index 3f79fdebff1..a8db4aa6691 100644
--- a/doc/python_api/examples/mathutils.Vector.py
+++ b/doc/python_api/examples/mathutils.Vector.py
@@ -49,7 +49,7 @@ vec2d[:] = vec3d[:2]
# Vectors support 'swizzle' operations
-# See http://en.wikipedia.org/wiki/Swizzling_(computer_graphics)
+# See https://en.wikipedia.org/wiki/Swizzling_(computer_graphics)
vec.xyz = vec.zyx
vec.xy = vec4d.zw
vec.xyz = vec4d.wzz
diff --git a/doc/python_api/rst/bge.constraints.rst b/doc/python_api/rst/bge.constraints.rst
index bf015057dcb..ed965c3dfc1 100644
--- a/doc/python_api/rst/bge.constraints.rst
+++ b/doc/python_api/rst/bge.constraints.rst
@@ -8,11 +8,11 @@ Physics Constraints (bge.constraints)
Examples
--------
-.. include:: ../examples/bge.constraints.py
+.. include:: __/examples/bge.constraints.py
:start-line: 1
:end-line: 4
-.. literalinclude:: ../examples/bge.constraints.py
+.. literalinclude:: __/examples/bge.constraints.py
:lines: 6-
diff --git a/doc/python_api/rst/bge.events.rst b/doc/python_api/rst/bge.events.rst
index 8dbded6a3fe..42135926fda 100644
--- a/doc/python_api/rst/bge.events.rst
+++ b/doc/python_api/rst/bge.events.rst
@@ -12,53 +12,53 @@ This module holds key constants for the SCA_KeyboardSensor.
.. code-block:: python
- # Set a connected keyboard sensor to accept F1
- import bge
-
- co = bge.logic.getCurrentController()
- # 'Keyboard' is a keyboard sensor
- sensor = co.sensors["Keyboard"]
- sensor.key = bge.events.F1KEY
-
-.. code-block:: python
-
- # Do the all keys thing
- import bge
-
- co = bge.logic.getCurrentController()
- # 'Keyboard' is a keyboard sensor
- sensor = co.sensors["Keyboard"]
-
- for key,status in sensor.events:
- # key[0] == bge.events.keycode, key[1] = status
- if status == bge.logic.KX_INPUT_JUST_ACTIVATED:
- if key == bge.events.WKEY:
- # Activate Forward!
- if key == bge.events.SKEY:
- # Activate Backward!
- if key == bge.events.AKEY:
- # Activate Left!
- if key == bge.events.DKEY:
- # Activate Right!
-
-.. code-block:: python
-
- # The all keys thing without a keyboard sensor (but you will
- # need an always sensor with pulse mode on)
- import bge
-
- # Just shortening names here
- keyboard = bge.logic.keyboard
- JUST_ACTIVATED = bge.logic.KX_INPUT_JUST_ACTIVATED
-
- if keyboard.events[bge.events.WKEY] == JUST_ACTIVATED:
- print("Activate Forward!")
- if keyboard.events[bge.events.SKEY] == JUST_ACTIVATED:
- print("Activate Backward!")
- if keyboard.events[bge.events.AKEY] == JUST_ACTIVATED:
- print("Activate Left!")
- if keyboard.events[bge.events.DKEY] == JUST_ACTIVATED:
- print("Activate Right!")
+ # Set a connected keyboard sensor to accept F1
+ import bge
+
+ co = bge.logic.getCurrentController()
+ # 'Keyboard' is a keyboard sensor
+ sensor = co.sensors["Keyboard"]
+ sensor.key = bge.events.F1KEY
+
+ code-block:: python
+
+ # Do the all keys thing
+ import bge
+
+ co = bge.logic.getCurrentController()
+ # 'Keyboard' is a keyboard sensor
+ sensor = co.sensors["Keyboard"]
+
+ for key,status in sensor.events:
+ # key[0] == bge.events.keycode, key[1] = status
+ if status == bge.logic.KX_INPUT_JUST_ACTIVATED:
+ if key == bge.events.WKEY:
+ # Activate Forward!
+ if key == bge.events.SKEY:
+ # Activate Backward!
+ if key == bge.events.AKEY:
+ # Activate Left!
+ if key == bge.events.DKEY:
+ # Activate Right!
+
+ code-block:: python
+
+ # The all keys thing without a keyboard sensor (but you will
+ # need an always sensor with pulse mode on)
+ import bge
+
+ # Just shortening names here
+ keyboard = bge.logic.keyboard
+ JUST_ACTIVATED = bge.logic.KX_INPUT_JUST_ACTIVATED
+
+ if keyboard.events[bge.events.WKEY] == JUST_ACTIVATED:
+ print("Activate Forward!")
+ if keyboard.events[bge.events.SKEY] == JUST_ACTIVATED:
+ print("Activate Backward!")
+ if keyboard.events[bge.events.AKEY] == JUST_ACTIVATED:
+ print("Activate Left!")
+ if keyboard.events[bge.events.DKEY] == JUST_ACTIVATED:
+ print("Activate Right!")
*********
diff --git a/doc/python_api/rst/bge.logic.rst b/doc/python_api/rst/bge.logic.rst
index 3f35901234a..5cdb8ebfee9 100644
--- a/doc/python_api/rst/bge.logic.rst
+++ b/doc/python_api/rst/bge.logic.rst
@@ -378,6 +378,28 @@ General functions
Render next frame (if Python has control)
+.. function:: setRender(render)
+
+ Sets the global flag that controls the render of the scene.
+ If True, the render is done after the logic frame.
+ If False, the render is skipped and another logic frame starts immediately.
+
+ .. note::
+
+ GPU VSync no longer limits the number of frame per second when render is off,
+ but the *Use Frame Rate* option still regulates the fps. To run as many frames
+ as possible, untick this option (Render Properties, System panel).
+
+ :arg render: the render flag
+ :type render: bool
+
+.. function:: getRender()
+
+ Get the current value of the global render flag
+
+ :return: The flag value
+ :rtype: bool
+
**********************
Time related functions
**********************
diff --git a/doc/python_api/rst/bge.render.rst b/doc/python_api/rst/bge.render.rst
index 3b565e294dd..02c3beef672 100644
--- a/doc/python_api/rst/bge.render.rst
+++ b/doc/python_api/rst/bge.render.rst
@@ -90,6 +90,48 @@ Constants
Right eye being used during stereoscopic rendering.
+.. data:: RAS_OFS_RENDER_BUFFER
+
+ The pixel buffer for offscreen render is a RenderBuffer. Argument to :func:`offScreenCreate`
+
+.. data:: RAS_OFS_RENDER_TEXTURE
+
+ The pixel buffer for offscreen render is a Texture. Argument to :func:`offScreenCreate`
+
+
+*****
+Types
+*****
+
+.. class:: RASOffScreen
+
+ An off-screen render buffer object.
+
+ Use :func:`offScreenCreate` to create it.
+ Currently it can only be used in the :class:`bge.texture.ImageRender`
+ constructor to render on a FBO rather than the default viewport.
+
+ .. attribute:: width
+
+ The width in pixel of the FBO
+
+ :type: integer
+
+ .. attribute:: height
+
+ The height in pixel of the FBO
+
+ :type: integer
+
+ .. attribute:: color
+
+ The underlying OpenGL bind code of the texture object that holds
+ the rendered image, 0 if the FBO is using RenderBuffer.
+ The choice between RenderBuffer and Texture is determined
+ by the target argument of :func:`offScreenCreate`.
+
+ :type: integer
+
*********
Functions
@@ -362,3 +404,22 @@ Functions
Get the current vsync value
:rtype: One of VSYNC_OFF, VSYNC_ON, VSYNC_ADAPTIVE
+
+.. function:: offScreenCreate(width,height[,samples=0][,target=bge.render.RAS_OFS_RENDER_BUFFER])
+
+ Create a Off-screen render buffer object.
+
+ :arg width: the width of the buffer in pixels
+ :type width: integer
+ :arg height: the height of the buffer in pixels
+ :type height: integer
+ :arg samples: the number of multisample for anti-aliasing (MSAA), 0 to disable MSAA
+ :type samples: integer
+ :arg target: the pixel storage: :data:`RAS_OFS_RENDER_BUFFER` to render on RenderBuffers (the default),
+ :data:`RAS_OFS_RENDER_TEXTURE` to render on texture.
+ The later is interesting if you want to access the texture directly (see :attr:`RASOffScreen.color`).
+ Otherwise the default is preferable as it's more widely supported by GPUs and more efficient.
+ If the GPU does not support MSAA+Texture (e.g. Intel HD GPU), MSAA will be disabled.
+ :type target: integer
+ :rtype: :class:`RASOffScreen`
+
diff --git a/doc/python_api/rst/bge.texture.rst b/doc/python_api/rst/bge.texture.rst
index 4588a3e1800..49f6c4469a4 100644
--- a/doc/python_api/rst/bge.texture.rst
+++ b/doc/python_api/rst/bge.texture.rst
@@ -8,13 +8,16 @@ Introduction
The bge.texture module allows you to manipulate textures during the game.
-Several sources for texture are possible: video files, image files, video capture, memory buffer, camera render or a mix of that.
+Several sources for texture are possible: video files, image files, video capture, memory buffer,
+camera render or a mix of that.
The video and image files can be loaded from the internet using an URL instead of a file name.
-In addition, you can apply filters on the images before sending them to the GPU, allowing video effect: blue screen, color band, gray, normal map.
+In addition, you can apply filters on the images before sending them to the GPU, allowing video effect:
+blue screen, color band, gray, normal map.
-bge.texture uses FFmpeg to load images and videos. All the formats and codecs that FFmpeg supports are supported by this module, including but not limited to:
+bge.texture uses FFmpeg to load images and videos.
+All the formats and codecs that FFmpeg supports are supported by this module, including but not limited to:
* AVI
* Ogg
@@ -36,21 +39,29 @@ When the texture object is deleted, the new texture is deleted and the old textu
.. module:: bge.texture
-.. include:: ../examples/bge.texture.py
+.. include:: __/examples/bge.texture.py
:start-line: 1
:end-line: 5
-
-.. literalinclude:: ../examples/bge.texture.py
+
+.. literalinclude:: __/examples/bge.texture.py
:lines: 7-
-.. include:: ../examples/bge.texture.1.py
+.. include:: __/examples/bge.texture.1.py
+ :start-line: 1
+ :end-line: 6
+
+.. literalinclude:: __/examples/bge.texture.1.py
+ :lines: 8-
+
+
+.. include:: __/examples/bge.texture.2.py
:start-line: 1
:end-line: 6
-
-.. literalinclude:: ../examples/bge.texture.1.py
+
+.. literalinclude:: __/examples/bge.texture.2.py
:lines: 8-
-
-
+
+
*************
Video classes
*************
@@ -58,7 +69,7 @@ Video classes
.. class:: VideoFFmpeg(file, capture=-1, rate=25.0, width=0, height=0)
FFmpeg video source.
-
+
:arg file: Path to the video to load; if capture >= 0 on Windows, this parameter will not be used.
:type file: str
:arg capture: Capture device number; if >= 0, the corresponding webcam will be used. (optional)
@@ -73,14 +84,14 @@ Video classes
.. attribute:: status
Video status. (readonly)
-
+
:type: int
:value: see `FFmpeg Video and Image Status`_.
.. attribute:: range
Replay range.
-
+
:type: sequence of two floats
.. attribute:: repeat
@@ -104,33 +115,33 @@ Video classes
.. attribute:: image
Image data. (readonly)
-
+
:type: :class:`~bgl.Buffer` or None
.. attribute:: size
Image size. (readonly)
-
+
:type: tuple of two ints
.. attribute:: scale
Fast scale of image (near neighbour).
-
+
:type: bool
.. attribute:: flip
Flip image vertically.
-
+
:type: bool
.. attribute:: filter
Pixel filter.
-
+
:type: one of...
-
+
* :class:`FilterBGR24`
* :class:`FilterBlueScreen`
* :class:`FilterColor`
@@ -155,32 +166,41 @@ Video classes
.. method:: play()
Play (restart) video.
-
+
:return: Whether the video was ready or stopped.
:rtype: bool
.. method:: pause()
Pause video.
-
+
:return: Whether the video was playing.
:rtype: bool
.. method:: stop()
Stop video (play will replay it from start).
-
+
:return: Whether the video was playing.
:rtype: bool
- .. method:: refresh()
+ .. method:: refresh(buffer=None, format="RGBA", timestamp=-1.0)
- Refresh video - get its status.
-
- :value: see `FFmpeg Video and Image Status`_.
+ Refresh video - get its status and optionally copy the frame to an external buffer.
+ :arg buffer: An optional object that implements the buffer protocol.
+ If specified, the image is copied to the buffer, which must be big enough or an exception is thrown.
+ :type buffer: any buffer type
+ :arg format: An optional image format specifier for the image that will be copied to the buffer.
+ Only valid values are "RGBA" or "BGRA"
+ :type format: str
+ :arg timestamp: An optional timestamp (in seconds from the start of the movie)
+ of the frame to be copied to the buffer.
+ :type timestamp: float
+ :return: see `FFmpeg Video and Image Status`_.
:rtype: int
+
*************
Image classes
*************
@@ -188,14 +208,14 @@ Image classes
.. class:: ImageFFmpeg(file)
FFmpeg image source.
-
+
:arg file: Path to the image to load.
:type file: str
.. attribute:: status
Image status. (readonly)
-
+
:type: int
:value: see `FFmpeg Video and Image Status`_.
@@ -208,33 +228,33 @@ Image classes
.. attribute:: image
Image data. (readonly)
-
+
:type: :class:`~bgl.Buffer` or None
.. attribute:: size
Image size. (readonly)
-
+
:type: tuple of two ints
.. attribute:: scale
Fast scale of image (near neighbour).
-
+
:type: bool
.. attribute:: flip
Flip image vertically.
-
+
:type: bool
.. attribute:: filter
Pixel filter.
-
+
:type: one of...
-
+
* :class:`FilterBGR24`
* :class:`FilterBlueScreen`
* :class:`FilterColor`
@@ -244,25 +264,30 @@ Image classes
* :class:`FilterRGB24`
* :class:`FilterRGBA32`
- .. method:: refresh()
+ .. method:: refresh(buffer=None, format="RGBA")
- Refresh image, i.e. load it.
-
- :value: see `FFmpeg Video and Image Status`_.
+ Refresh image, get its status and optionally copy the frame to an external buffer.
+ :arg buffer: An optional object that implements the buffer protocol.
+ If specified, the image is copied to the buffer, which must be big enough or an exception is thrown.
+ :type buffer: any buffer type
+ :arg format: An optional image format specifier for the image that will be copied to the buffer.
+ Only valid values are "RGBA" or "BGRA"
+ :type format: str
+ :return: see `FFmpeg Video and Image Status`_.
:rtype: int
.. method:: reload(newname=None)
Reload image, i.e. reopen it.
-
+
:arg newname: Path to a new image. (optional)
:type newname: str
.. class:: ImageBuff(width, height, color=0, scale=False)
Image source from image buffer.
-
+
:arg width: Width of the image.
:type width: int
:arg height: Height of the image.
@@ -276,9 +301,9 @@ Image classes
.. attribute:: filter
Pixel filter.
-
+
:type: one of...
-
+
* :class:`FilterBGR24`
* :class:`FilterBlueScreen`
* :class:`FilterColor`
@@ -291,19 +316,19 @@ Image classes
.. attribute:: flip
Flip image vertically.
-
+
:type: bool
.. attribute:: image
Image data. (readonly)
-
+
:type: :class:`~bgl.Buffer` or None
.. method:: load(imageBuffer, width, height)
Load image from buffer.
-
+
:arg imageBuffer: Buffer to load the image from.
:type imageBuffer: :class:`~bgl.Buffer` or Python object implementing the buffer protocol (f.ex. bytes)
:arg width: Width of the image to load.
@@ -314,9 +339,10 @@ Image classes
.. method:: plot(imageBuffer, width, height, positionX, positionY, mode=IMB_BLEND_COPY)
Update image buffer.
-
+
:arg imageBuffer: Buffer to load the new data from.
- :type imageBuffer: :class:`~bgl.Buffer`, :class:`ImageBuff` or Python object implementing the buffer protocol (f.ex. bytes)
+ :type imageBuffer: :class:`~bgl.Buffer`, :class:`ImageBuff`
+ or Python object implementing the buffer protocol (f.ex. bytes)
:arg width: Width of the data to load.
:type width: int
:arg height: Height of the data to load.
@@ -327,18 +353,18 @@ Image classes
:type positionY: int
:arg mode: Drawing mode, see `Image Blending Modes`_.
:type mode: int
-
+
.. attribute:: scale
Fast scale of image (near neighbour).
-
+
:type: bool
.. attribute:: size
Image size. (readonly)
-
+
:type: tuple of two ints
.. attribute:: valid
@@ -350,10 +376,11 @@ Image classes
.. class:: ImageMirror(scene, observer, mirror, material=0)
Image source from mirror.
-
+
:arg scene: Scene in which the image has to be taken.
:type scene: :class:`~bge.types.KX_Scene`
- :arg observer: Reference object for the mirror (the object from which the mirror has to be looked at, for example a camera).
+ :arg observer: Reference object for the mirror
+ (the object from which the mirror has to be looked at, for example a camera).
:type observer: :class:`~bge.types.KX_GameObject`
:arg mirror: Object holding the mirror.
:type mirror: :class:`~bge.types.KX_GameObject`
@@ -363,33 +390,33 @@ Image classes
.. attribute:: alpha
Use alpha in texture.
-
+
:type: bool
.. attribute:: background
Background color.
-
+
:type: int or float list [r, g, b, a] in [0.0, 255.0]
.. attribute:: capsize
Size of render area.
-
+
:type: sequence of two ints
.. attribute:: clip
Clipping distance.
-
+
:type: float in [0.01, 5000.0]
.. attribute:: filter
Pixel filter.
-
+
:type: one of...
-
+
* :class:`FilterBGR24`
* :class:`FilterBlueScreen`
* :class:`FilterColor`
@@ -402,29 +429,38 @@ Image classes
.. attribute:: flip
Flip image vertically.
-
+
:type: bool
.. attribute:: image
Image data. (readonly)
-
+
:type: :class:`~bgl.Buffer` or None
- .. method:: refresh()
+ .. method:: refresh(buffer=None, format="RGBA")
+
+ Refresh image - render and copy the image to an external buffer (optional)
+ then invalidate its current content.
- Refresh image - invalidate its current content.
+ :arg buffer: An optional object that implements the buffer protocol.
+ If specified, the image is rendered and copied to the buffer,
+ which must be big enough or an exception is thrown.
+ :type buffer: any buffer type
+ :arg format: An optional image format specifier for the image that will be copied to the buffer.
+ Only valid values are "RGBA" or "BGRA"
+ :type format: str
.. attribute:: scale
Fast scale of image (near neighbour).
-
+
:type: bool
.. attribute:: size
Image size (readonly).
-
+
:type: tuple of two ints
.. attribute:: valid
@@ -436,7 +472,7 @@ Image classes
.. attribute:: whole
Use whole viewport to render.
-
+
:type: bool
.. class:: ImageMix
@@ -446,9 +482,9 @@ Image classes
.. attribute:: filter
Pixel filter.
-
+
:type: one of...
-
+
* :class:`FilterBGR24`
* :class:`FilterBlueScreen`
* :class:`FilterColor`
@@ -461,19 +497,19 @@ Image classes
.. attribute:: flip
Flip image vertically.
-
+
:type: bool
.. method:: getSource(id)
Get image source.
-
+
:arg id: Identifier of the source to get.
:type id: str
-
+
:return: Image source.
:rtype: one of...
-
+
* :class:`VideoFFmpeg`
* :class:`ImageFFmpeg`
* :class:`ImageBuff`
@@ -485,43 +521,52 @@ Image classes
.. method:: getWeight(id)
Get image source weight.
-
+
:arg id: Identifier of the source.
:type id: str
-
+
:return: Weight of the source.
:rtype: int
.. attribute:: image
Image data. (readonly)
-
+
:type: :class:`~bgl.Buffer` or None
- .. method:: refresh()
+ .. method:: refresh(buffer=None, format="RGBA")
- Refresh image - invalidate its current content.
+ Refresh image - calculate and copy the image to an external buffer (optional)
+ then invalidate its current content.
+
+ :arg buffer: An optional object that implements the buffer protocol.
+ If specified, the image is calculated and copied to the buffer,
+ which must be big enough or an exception is thrown.
+ :type buffer: any buffer type
+ :arg format: An optional image format specifier for the image that will be copied to the buffer.
+ Only valid values are "RGBA" or "BGRA"
+ :type format: str
.. attribute:: scale
Fast scale of image (near neighbour).
-
+
:type: bool
-
+
.. attribute:: size
Image size. (readonly)
-
+
:type: tuple of two ints
.. method:: setSource(id, image)
Set image source - all sources must have the same size.
-
+
:arg id: Identifier of the source to set.
:type id: str
:arg image: Image source of type...
-
+
* :class:`VideoFFmpeg`
* :class:`ImageFFmpeg`
* :class:`ImageBuff`
@@ -533,7 +578,7 @@ Image classes
.. method:: setWeight(id, weight)
Set image source weight - the sum of the weights should be 256 to get full color intensity in the output.
-
+
:arg id: Identifier of the source.
:type id: str
:arg weight: Weight of the source.
@@ -548,36 +593,40 @@ Image classes
.. class:: ImageRender(scene, camera)
Image source from render.
-
+ The render is done on a custom framebuffer object if fbo is specified,
+ otherwise on the default framebuffer.
+
:arg scene: Scene in which the image has to be taken.
:type scene: :class:`~bge.types.KX_Scene`
:arg camera: Camera from which the image has to be taken.
:type camera: :class:`~bge.types.KX_Camera`
+ :arg fbo: Off-screen render buffer object (optional)
+ :type fbo: :class:`~bge.render.RASOffScreen`
.. attribute:: alpha
Use alpha in texture.
-
+
:type: bool
.. attribute:: background
Background color.
-
+
:type: int or float list [r, g, b, a] in [0.0, 255.0]
.. attribute:: capsize
Size of render area.
-
+
:type: sequence of two ints
.. attribute:: filter
Pixel filter.
-
+
:type: one of...
-
+
* :class:`FilterBGR24`
* :class:`FilterBlueScreen`
* :class:`FilterColor`
@@ -590,29 +639,25 @@ Image classes
.. attribute:: flip
Flip image vertically.
-
+
:type: bool
.. attribute:: image
Image data. (readonly)
-
- :type: :class:`~bgl.Buffer` or None
-
- .. method:: refresh()
- Refresh image - invalidate its current content.
+ :type: :class:`~bgl.Buffer` or None
.. attribute:: scale
Fast scale of image (near neighbour).
-
+
:type: bool
.. attribute:: size
Image size. (readonly)
-
+
:type: tuple of two ints
.. attribute:: valid
@@ -624,22 +669,58 @@ Image classes
.. attribute:: whole
Use whole viewport to render.
-
+
:type: bool
.. attribute:: depth
Use depth component of render as array of float - not suitable for texture source,
should only be used with bge.texture.imageToArray(mode='F').
-
+
:type: bool
.. attribute:: zbuff
Use depth component of render as grey scale color - suitable for texture source.
-
+
:type: bool
+ .. method:: render()
+
+ Render the scene but do not extract the pixels yet.
+ The function returns as soon as the render commands have been send to the GPU.
+ The render will proceed asynchronously in the GPU while the host can perform other tasks.
+ To complete the render, you can either call :func:`refresh`
+ directly of refresh the texture of which this object is the source.
+ This method is useful to implement asynchronous render for optimal performance: call render()
+ on frame n and refresh() on frame n+1 to give as much as time as possible to the GPU
+ to render the frame while the game engine can perform other tasks.
+
+ :return: True if the render was initiated, False if the render cannot be performed (e.g. the camera is active)
+ :rtype: bool
+
+ .. method:: refresh()
+ .. method:: refresh(buffer, format="RGBA")
+
+ Refresh video - render and optionally copy the image to an external buffer then invalidate its current content.
+ The render may have been started earlier with the :func:`render` method,
+ in which case this function simply waits for the render operations to complete.
+ When called without argument, the pixels are not extracted but the render is guaranteed
+ to be completed when the function returns.
+ This only makes sense with offscreen render on texture target (see :func:`~bge.render.offScreenCreate`).
+
+ :arg buffer: An object that implements the buffer protocol.
+ If specified, the image is copied to the buffer, which must be big enough or an exception is thrown.
+ The transfer to the buffer is optimal if no processing of the image is needed.
+ This is the case if ``flip=False, alpha=True, scale=False, whole=True, depth=False, zbuff=False``
+ and no filter is set.
+ :type buffer: any buffer type of sufficient size
+ :arg format: An optional image format specifier for the image that will be copied to the buffer.
+ Only valid values are "RGBA" or "BGRA"
+ :type format: str
+ :return: True if the render is complete, False if the render cannot be performed (e.g. the camera is active)
+ :rtype: bool
+
.. class:: ImageViewport
Image source from viewport.
@@ -647,21 +728,21 @@ Image classes
.. attribute:: alpha
Use alpha in texture.
-
+
:type: bool
.. attribute:: capsize
Size of viewport area being captured.
-
+
:type: sequence of two ints
.. attribute:: filter
Pixel filter.
-
+
:type: one of...
-
+
* :class:`FilterBGR24`
* :class:`FilterBlueScreen`
* :class:`FilterColor`
@@ -674,35 +755,45 @@ Image classes
.. attribute:: flip
Flip image vertically.
-
+
:type: bool
.. attribute:: image
Image data. (readonly)
-
+
:type: :class:`~bgl.Buffer` or None
.. attribute:: position
Upper left corner of the captured area.
-
+
:type: sequence of two ints
- .. method:: refresh()
+ .. method:: refresh(buffer=None, format="RGBA")
+
+ Refresh video - copy the viewport to an external buffer (optional) then invalidate its current content.
- Refresh image - invalidate its current content.
+ :arg buffer: An optional object that implements the buffer protocol.
+ If specified, the image is copied to the buffer, which must be big enough or an exception is thrown.
+ The transfer to the buffer is optimal if no processing of the image is needed.
+ This is the case if ``flip=False, alpha=True, scale=False, whole=True, depth=False, zbuff=False``
+ and no filter is set.
+ :type buffer: any buffer type
+ :arg format: An optional image format specifier for the image that will be copied to the buffer.
+ Only valid values are "RGBA" or "BGRA"
+ :type format: str
.. attribute:: scale
Fast scale of image (near neighbour).
-
+
:type: bool
.. attribute:: size
Image size. (readonly)
-
+
:type: tuple of two ints
.. attribute:: valid
@@ -714,23 +805,201 @@ Image classes
.. attribute:: whole
Use whole viewport to capture.
-
+
:type: bool
.. attribute:: depth
Use depth component of viewport as array of float - not suitable for texture source,
- should only be used with bge.texture.imageToArray(mode='F').
-
+ should only be used with ``bge.texture.imageToArray(mode='F')``.
+
:type: bool
.. attribute:: zbuff
- Use depth component of viewport as grey scale color - suitable for texture source.
-
+ Use depth component of viewport as grey scale color - suitable for texture source.
+
:type: bool
-
+.. class:: VideoDeckLink(format, capture=0)
+
+ Image source from an external video stream captured with a DeckLink video card from
+ Black Magic Design.
+ Before this source can be used, a DeckLink hardware device must be installed, it can be a PCIe card
+ or a USB device, and the 'Desktop Video' software package (version 10.4 or above must be installed)
+ on the host as described in the DeckLink documentation.
+ If in addition you have a recent nVideo Quadro card, you can benefit from the 'GPUDirect' technology
+ to push the captured video frame very efficiently to the GPU. For this you need to install the
+ 'DeckLink SDK' version 10.4 or above and copy the 'dvp.dll' runtime library to Blender's
+ installation directory or to any other place where Blender can load a DLL from.
+
+ :arg format: string describing the video format to be captured.
+ :type format: str
+ :arg capture: Card number from which the input video must be captured.
+ :type capture: int
+
+ The format argument must be written as ``<displayMode>/<pixelFormat>[/3D][:<cacheSize>]`` where ``<displayMode>``
+ describes the frame size and rate and <pixelFormat> the encoding of the pixels.
+ The optional ``/3D`` suffix is to be used if the video stream is stereo with a left and right eye feed.
+ The optional ``:<cacheSize>`` suffix determines the number of the video frames kept in cache, by default 8.
+ Some DeckLink cards won't work below a certain cache size.
+ The default value 8 should be sufficient for all cards.
+ You may try to reduce the cache size to reduce the memory footprint. For example the The 4K Extreme is known
+ to work with 3 frames only, the Extreme 2 needs 4 frames and the Intensity Shuttle needs 6 frames, etc.
+ Reducing the cache size may be useful when Decklink is used in conjunction with GPUDirect:
+ all frames must be locked in memory in that case and that puts a lot of pressure on memory.
+ If you reduce the cache size too much,
+ you'll get no error but no video feed either.
+
+ The valid ``<displayMode>`` values are copied from the ``BMDDisplayMode`` enum in the DeckLink API
+ without the 'bmdMode' prefix. In case a mode that is not in this list is added in a later version
+ of the SDK, it is also possible to specify the 4 letters of the internal code for that mode.
+ You will find the internal code in the ``DeckLinkAPIModes.h`` file that is part of the SDK.
+ Here is for reference the full list of supported display modes with their equivalent internal code:
+
+ Internal Codes
+ - NTSC 'ntsc'
+ - NTSC2398 'nt23'
+ - PAL 'pal '
+ - NTSCp 'ntsp'
+ - PALp 'palp'
+ HD 1080 Modes
+ - HD1080p2398 '23ps'
+ - HD1080p24 '24ps'
+ - HD1080p25 'Hp25'
+ - HD1080p2997 'Hp29'
+ - HD1080p30 'Hp30'
+ - HD1080i50 'Hi50'
+ - HD1080i5994 'Hi59'
+ - HD1080i6000 'Hi60'
+ - HD1080p50 'Hp50'
+ - HD1080p5994 'Hp59'
+ - HD1080p6000 'Hp60'
+ HD 720 Modes
+ - HD720p50 'hp50'
+ - HD720p5994 'hp59'
+ - HD720p60 'hp60'
+ 2k Modes
+ - 2k2398 '2k23'
+ - 2k24 '2k24'
+ - 2k25 '2k25'
+ 4k Modes
+ - 4K2160p2398 '4k23'
+ - 4K2160p24 '4k24'
+ - 4K2160p25 '4k25'
+ - 4K2160p2997 '4k29'
+ - 4K2160p30 '4k30'
+ - 4K2160p50 '4k50'
+ - 4K2160p5994 '4k59'
+ - 4K2160p60 '4k60'
+
+ Most of names are self explanatory. If necessary refer to the DeckLink API documentation for more information.
+
+ Similarly, <pixelFormat> is copied from the BMDPixelFormat enum.
+
+ Here is for reference the full list of supported pixel format and their equivalent internal code:
+
+ Pixel Formats
+ - 8BitYUV '2vuy'
+ - 10BitYUV 'v210'
+ - 8BitARGB * no equivalent code *
+ - 8BitBGRA 'BGRA'
+ - 10BitRGB 'r210'
+ - 12BitRGB 'R12B'
+ - 12BitRGBLE 'R12L'
+ - 10BitRGBXLE 'R10l'
+ - 10BitRGBX 'R10b'
+
+ Refer to the DeckLink SDK documentation for a full description of these pixel format.
+ It is important to understand them as the decoding of the pixels is NOT done in VideoTexture
+ for performance reason. Instead a specific shader must be used to decode the pixel in the GPU.
+ Only the '8BitARGB', '8BitBGRA' and '10BitRGBXLE' pixel formats are mapped directly to OpenGL RGB float textures.
+ The '8BitYUV' and '10BitYUV' pixel formats are mapped to openGL RGB float texture but require a shader to decode.
+ The other pixel formats are sent as a ``GL_RED_INTEGER`` texture (i.e. a texture with only the
+ red channel coded as an unsigned 32 bit integer) and are not recommended for use.
+
+ Example: ``HD1080p24/10BitYUV/3D:4`` is equivalent to ``24ps/v210/3D:4``
+ and represents a full HD stereo feed at 24 frame per second and 4 frames cache size.
+
+ Although video format auto detection is possible with certain DeckLink devices, the corresponding
+ API is NOT implemented in the BGE. Therefore it is important to specify the format string that
+ matches exactly the video feed. If the format is wrong, no frame will be captured.
+ It should be noted that the pixel format that you need to specify is not necessarily the actual
+ format in the video feed. For example, the 4K Extreme card delivers 8bit RGBs pixels in the
+ '10BitRGBXLE' format. Use the 'Media Express' application included in 'Desktop Video' to discover
+ which pixel format works for a particular video stream.
+
+ .. attribute:: status
+
+ Status of the capture: 1=ready to use, 2=capturing, 3=stopped
+
+ :type: int
+
+ .. attribute:: framerate
+
+ Capture frame rate as computed from the video format.
+
+ :type: float
+
+ .. attribute:: valid
+
+ Tells if the image attribute can be used to retrieve the image.
+ Always False in this implementation (the image is not available at python level)
+
+ :type: bool
+
+ .. attribute:: image
+
+ The image data. Always None in this implementation.
+
+ :type: :class:`~bgl.Buffer` or None
+
+ .. attribute:: size
+
+ The size of the frame in pixel.
+ Stereo frames have double the height of the video frame, i.e. 3D is delivered to the GPU
+ as a single image in top-bottom order, left eye on top.
+
+ :type: (int,int)
+
+ .. attribute:: scale
+
+ Not used in this object.
+
+ :type: bool
+
+ .. attribute:: flip
+
+ Not used in this object.
+
+ :type: bool
+
+ .. attribute:: filter
+
+ Not used in this object.
+
+ .. method:: play()
+
+ Kick-off the capture after creation of the object.
+
+ :return: True if the capture could be started, False otherwise.
+ :rtype: bool
+
+ .. method:: pause()
+
+ Temporary stops the capture. Use play() to restart it.
+
+ :return: True if the capture could be paused, False otherwise.
+ :rtype: bool
+
+ .. method:: stop()
+
+ Stops the capture.
+
+ :return: True if the capture could be stopped, False otherwise.
+ :rtype: bool
+
+
***************
Texture classes
***************
@@ -738,7 +1007,7 @@ Texture classes
.. class:: Texture(gameObj, materialID=0, textureID=0, textureObj=None)
Texture object.
-
+
:arg gameObj: Game object to be created a video texture on.
:type gameObj: :class:`~bge.types.KX_GameObject`
:arg materialID: Material ID. (optional)
@@ -751,7 +1020,7 @@ Texture classes
.. attribute:: bindId
OpenGL Bind Name. (readonly)
-
+
:type: int
.. method:: close()
@@ -761,27 +1030,28 @@ Texture classes
.. attribute:: mipmap
Mipmap texture.
-
+
:type: bool
- .. method:: refresh(refresh_source=True, ts=-1.0)
+ .. method:: refresh(refresh_source, timestamp=-1.0)
Refresh texture from source.
-
+
:arg refresh_source: Whether to also refresh the image source of the texture.
:type refresh_source: bool
- :arg ts: If the texture controls a VideoFFmpeg object:
- timestamp (in seconds from the start of the movie) of the frame to be loaded; this can be
- used for video-sound synchonization by passing :attr:`~bge.types.KX_SoundActuator.time` to it. (optional)
- :type ts: float
+ :arg timestamp: If the texture controls a VideoFFmpeg object:
+ timestamp (in seconds from the start of the movie) of the frame to be loaded; this can be
+ used for video-sound synchonization by passing :attr:`~bge.types.KX_SoundActuator.time` to it. (optional)
+ :type timestamp: float
.. attribute:: source
Source of texture.
-
+
:type: one of...
-
+
* :class:`VideoFFmpeg`
+ * :class:`VideoDeckLink`
* :class:`ImageFFmpeg`
* :class:`ImageBuff`
* :class:`ImageMirror`
@@ -789,47 +1059,168 @@ Texture classes
* :class:`ImageRender`
* :class:`ImageViewport`
-
+.. class:: DeckLink(cardIdx=0, format="")
+
+ Certain DeckLink devices can be used to playback video: the host sends video frames regularly
+ for immediate or scheduled playback. The video feed is outputted on HDMI or SDI interfaces.
+ This class supports the immediate playback mode: it has a source attribute that is assigned
+ one of the source object in the bge.texture module. Refreshing the DeckLink object causes
+ the image source to be computed and sent to the DeckLink device for immediate transmission
+ on the output interfaces. Keying is supported: it allows to composite the frame with an
+ input video feed that transits through the DeckLink card.
+
+ :arg cardIdx: Number of the card to be used for output (0=first card).
+ It should be noted that DeckLink devices are usually half duplex:
+ they can either be used for capture or playback but not both at the same time.
+ :type cardIdx: int
+ :arg format: String representing the display mode of the output feed.
+ :type format: str
+
+ The default value of the format argument is reserved for auto detection but it is currently
+ not supported (it will generate a runtime error) and thus the video format must be explicitly
+ specified. If keying is the goal (see keying attributes), the format must match exactly the
+ input video feed, otherwise it can be any format supported by the device (there will be a
+ runtime error if not).
+ The format of the string is ``<displayMode>[/3D]``.
+
+ Refer to :class:`VideoDeckLink` to get the list of acceptable ``<displayMode>``.
+ The optional ``/3D`` suffix is used to create a stereo 3D feed.
+ In that case the 'right' attribute must also be set to specify the image source for the right eye.
+
+ Note: The pixel format is not specified here because it is always BGRA. The alpha channel is
+ used in keying to mix the source with the input video feed, otherwise it is not used.
+ If a conversion is needed to match the native video format, it is done inside the DeckLink driver
+ or device.
+
+ .. attribute:: source
+
+ This attribute must be set to one of the image source. If the image size does not fit exactly
+ the frame size, the extend attribute determines what to do.
+
+ For best performance, the source image should match exactly the size of the output frame.
+ A further optimization is achieved if the image source object is ImageViewport or ImageRender
+ set for whole viewport, flip disabled and no filter: the GL frame buffer is copied directly
+ to the image buffer and directly from there to the DeckLink card (hence no buffer to buffer
+ copy inside VideoTexture).
+
+ :type: one of...
+ - :class:`VideoFFmpeg`
+ - :class:`VideoDeckLink`
+ - :class:`ImageFFmpeg`
+ - :class:`ImageBuff`
+ - :class:`ImageMirror`
+ - :class:`ImageMix`
+ - :class:`ImageRender`
+ - :class:`ImageViewport`
+
+ .. attribute:: right
+
+ If the video format is stereo 3D, this attribute should be set to an image source object
+ that will produce the right eye images. If the goal is to render the BGE scene in 3D,
+ it can be achieved with 2 cameras, one for each eye, used by 2 ImageRender with an offscreen
+ render buffer that is just the size of the video frame.
+
+ :type: one of...
+ - :class:`VideoFFmpeg`
+ - :class:`VideoDeckLink`
+ - :class:`ImageFFmpeg`
+ - :class:`ImageBuff`
+ - :class:`ImageMirror`
+ - :class:`ImageMix`
+ - :class:`ImageRender`
+ - :class:`ImageViewport`
+
+ .. attribute:: keying
+
+ Specify if keying is enabled. False (default): the output frame is sent unmodified on
+ the output interface (in that case no input video is required). True: the output frame
+ is mixed with the input video, using the alpha channel to blend the two images and the
+ combination is sent on the output interface.
+
+ :type: bool
+
+ .. attribute:: level
+
+ If keying is enabled, sets the keying level from 0 to 255. This value is a global alpha value
+ that multiplies the alpha channel of the image source. Use 255 (the default) to keep the alpha
+ channel unmodified, 0 to make the output frame totally transparent.
+
+ :type: int
+
+ .. attribute:: extend
+
+ Determines how the image source should be mapped if the size does not fit the video frame size.
+ * False (the default): map the image pixel by pixel.
+ If the image size is smaller than the frame size, extra space around the image is filled with
+ 0-alpha black. If it is larger, the image is cropped to fit the frame size.
+ * True: the image is scaled by the nearest neighbor algorithm to fit the frame size.
+ The scaling is fast but poor quality. For best results, always adjust the image source to
+ match the size of the output video.
+
+ :type: bool
+
+ .. method:: close()
+
+ Close the DeckLink device and release all resources. After calling this method,
+ the object cannot be reactivated, it must be destroyed and a new DeckLink object
+ created from fresh to restart the output.
+
+ .. method:: refresh(refresh_source,ts)
+
+ This method must be called frequently to update the output frame in the DeckLink device.
+
+ :arg refresh_source: True if the source objects image buffer should be invalidated after being
+ used to compute the output frame. This triggers the recomputing of the
+ source image on next refresh, which is normally the desired effect.
+ False if the image source buffer should stay valid and reused on next refresh.
+ Note that the DeckLink device stores the output frame and replays until a
+ new frame is sent from the host. Thus, it is not necessary to refresh the
+ DeckLink object if it is known that the image source has not changed.
+ :type refresh_source: bool
+ :arg ts: The timestamp value passed to the image source object to compute the image.
+ If unspecified, the BGE clock is used.
+ :type ts: float
+
+
**************
Filter classes
**************
-
.. class:: FilterBGR24
Source filter BGR24.
.. class:: FilterBlueScreen
- Filter for Blue Screen. The RGB channels of the color are left unchanged, while the output alpha is obtained as follows:
-
- * if the square of the euclidian distance between the RGB color and the filter's reference color is smaller than the filter's lower limit,
+ Filter for Blue Screen.
+ The RGB channels of the color are left unchanged, while the output alpha is obtained as follows:
+
+ - if the square of the euclidian distance between the RGB color
+ and the filter's reference color is smaller than the filter's lower limit,
the output alpha is set to 0;
-
- * if that square is bigger than the filter's upper limit, the output alpha is set to 255;
-
- * otherwise the output alpha is linarly extrapoled between 0 and 255 in the interval of the limits.
+ - if that square is bigger than the filter's upper limit, the output alpha is set to 255;
+ - otherwise the output alpha is linarly extrapoled between 0 and 255 in the interval of the limits.
.. attribute:: color
Reference color.
-
+
:type: sequence of three ints
:default: (0, 0, 255)
.. attribute:: limits
Reference color limits.
-
+
:type: sequence of two ints
:default: (64, 64)
.. attribute:: previous
Previous pixel filter.
-
+
:type: one of...
-
+
* :class:`FilterBGR24`
* :class:`FilterBlueScreen`
* :class:`FilterColor`
@@ -841,22 +1232,23 @@ Filter classes
.. class:: FilterColor
- Filter for color calculations. The output color is obtained by multiplying the reduced 4x4 matrix with the input color
+ Filter for color calculations.
+ The output color is obtained by multiplying the reduced 4x4 matrix with the input color
and adding the remaining column to the result.
.. attribute:: matrix
Matrix [4][5] for color calculation.
-
+
:type: sequence of four sequences of five ints
:default: ((256, 0, 0, 0, 0), (0, 256, 0, 0, 0), (0, 0, 256, 0, 0), (0, 0, 0, 256, 0))
.. attribute:: previous
Previous pixel filter.
-
+
:type: one of...
-
+
* :class:`FilterBGR24`
* :class:`FilterBlueScreen`
* :class:`FilterColor`
@@ -868,14 +1260,15 @@ Filter classes
.. class:: FilterGray
- Filter for gray scale effect. Proportions of R, G and B contributions in the output gray scale are 28:151:77.
+ Filter for gray scale effect.
+ Proportions of R, G and B contributions in the output gray scale are 28:151:77.
.. attribute:: previous
Previous pixel filter.
-
+
:type: one of...
-
+
* :class:`FilterBGR24`
* :class:`FilterBlueScreen`
* :class:`FilterColor`
@@ -888,26 +1281,26 @@ Filter classes
.. class:: FilterLevel
Filter for levels calculations. Each output color component is obtained as follows:
-
+
* if it is smaller than its corresponding min value, it is set to 0;
-
+
* if it is bigger than its corresponding max value, it is set to 255;
-
+
* Otherwise it is linearly extrapoled between 0 and 255 in the (min, max) interval.
.. attribute:: levels
Levels matrix [4] (min, max).
-
+
:type: sequence of four sequences of two ints
:default: ((0, 255), (0, 255), (0, 255), (0, 255))
.. attribute:: previous
Previous pixel filter.
-
+
:type: one of...
-
+
* :class:`FilterBGR24`
* :class:`FilterBlueScreen`
* :class:`FilterColor`
@@ -924,23 +1317,23 @@ Filter classes
.. attribute:: colorIdx
Index of color used to calculate normal (0 - red, 1 - green, 2 - blue, 3 - alpha).
-
+
:type: int in [0, 3]
:default: 0
.. attribute:: depth
Depth of relief.
-
+
:type: float
:default: 4.0
.. attribute:: previous
Previous pixel filter.
-
+
:type: one of...
-
+
* :class:`FilterBGR24`
* :class:`FilterBlueScreen`
* :class:`FilterColor`
@@ -984,25 +1377,29 @@ Functions
* :class:`ImageMix`
* :class:`ImageRender`
* :class:`ImageViewport`
-
+
:arg mode: Optional argument representing the pixel format.
-
- * You can use the characters R, G, B for the 3 color channels, A for the alpha channel,
+
+ - You can use the characters R, G, B for the 3 color channels, A for the alpha channel,
0 to force a fixed 0 color channel and 1 to force a fixed 255 color channel.
-
+
Examples:
- * "BGR" will return 3 bytes per pixel with the Blue, Green and Red channels in that order.
- * "RGB1" will return 4 bytes per pixel with the Red, Green, Blue channels in that order and the alpha channel forced to 255.
-
- * A special mode "F" allows to return the image as an array of float. This mode should only be used to retrieve
- the depth buffer of the class:`ImageViewport` and :class:`ImageRender` objects.
+
+ - "BGR" will return 3 bytes per pixel with the
+ Blue, Green and Red channels in that order.
+ - "RGB1" will return 4 bytes per pixel with the
+ Red, Green, Blue channels in that order and the alpha channel forced to 255.
+
+ - A special mode "F" allows to return the image as an array of float.
+ This mode should only be used to retrieve the depth buffer of the
+ class:`ImageViewport` and :class:`ImageRender` objects.
The default mode is "RGBA".
-
+
:type mode: str
-
+
:return: An object representing the image as one dimensional array of bytes of size (pixel_size*width*height),
- line by line starting from the bottom of the image. The pixel size and format is determined by the mode
- parameter. For mode 'F', the array is a one dimensional array of float of size (width*height).
+ line by line starting from the bottom of the image. The pixel size and format is determined by the mode
+ parameter. For mode 'F', the array is a one dimensional array of float of size (width*height).
:rtype: :class:`~bgl.Buffer`
.. function:: materialID(object, name)
@@ -1017,7 +1414,8 @@ Functions
the texture by material. In that case the material must have a texture channel in first
position.
- If the object has no material that matches name, it generates a runtime error. Use try/except to catch the exception.
+ If the object has no material that matches name, it generates a runtime error.
+ Use try/except to catch the exception.
Ex: ``bge.texture.materialID(obj, 'IMvideo.png')``
@@ -1025,7 +1423,7 @@ Functions
:type object: :class:`~bge.types.KX_GameObject`
:arg name: Name of the texture/material you want to make dynamic.
:type name: str
-
+
:return: The internal material number.
:rtype: int
@@ -1037,11 +1435,11 @@ Functions
:arg filename: Name of the error log file.
:type filename: str
-
+
:return: -1 if the parameter name is invalid (not of type string), else 0.
:rtype: int
-
+
*********
Constants
*********
diff --git a/doc/python_api/rst/bge_types/bge.types.BL_Shader.rst b/doc/python_api/rst/bge_types/bge.types.BL_Shader.rst
index f4f5c0d62ba..a389f68ee04 100644
--- a/doc/python_api/rst/bge_types/bge.types.BL_Shader.rst
+++ b/doc/python_api/rst/bge_types/bge.types.BL_Shader.rst
@@ -214,6 +214,16 @@ base class --- :class:`PyObjectPlus`
:arg iList: a list (2, 3 or 4 elements) of integer values
:type iList: list[integer]
+ .. method:: setUniformEyef(name)
+
+ Set a uniform with a float value that reflects the eye being render in stereo mode:
+ 0.0 for the left eye, 0.5 for the right eye. In non stereo mode, the value of the uniform
+ is fixed to 0.0. The typical use of this uniform is in stereo mode to sample stereo textures
+ containing the left and right eye images in a top-bottom order.
+
+ :arg name: the uniform name
+ :type name: string
+
.. method:: validate()
Validate the shader object.
diff --git a/doc/python_api/rst/bge_types/bge.types.KX_LightObject.rst b/doc/python_api/rst/bge_types/bge.types.KX_LightObject.rst
index 5ba7f3b8e34..6748df13873 100644
--- a/doc/python_api/rst/bge_types/bge.types.KX_LightObject.rst
+++ b/doc/python_api/rst/bge_types/bge.types.KX_LightObject.rst
@@ -60,37 +60,37 @@ base class --- :class:`KX_GameObject`
:type: float (read only)
- ..attribute:: shadowFrustumSize
+ .. attribute:: shadowFrustumSize
Size of the frustum used for creating the shadowmap.
:type: float (read only)
- ..attribute:: shadowBindId
+ .. attribute:: shadowBindId
The OpenGL shadow texture bind number/id.
:type: int (read only)
- ..attribute:: shadowMapType
+ .. attribute:: shadowMapType
The shadow shadow map type (0 -> Simple; 1 -> Variance)
:type: int (read only)
- ..attribute:: shadowBias
+ .. attribute:: shadowBias
The shadow buffer sampling bias.
:type: float (read only)
- ..attribute:: shadowBleedBias
+ .. attribute:: shadowBleedBias
The bias for reducing light-bleed on variance shadow maps.
:type: float (read only)
- ..attribute:: useShadow
+ .. attribute:: useShadow
Returns True if the light has Shadow option activated, else returns False.
diff --git a/doc/python_api/rst/bge_types/bge.types.SCA_PythonJoystick.rst b/doc/python_api/rst/bge_types/bge.types.SCA_PythonJoystick.rst
index 2b97b5939e2..bcec751929d 100644
--- a/doc/python_api/rst/bge_types/bge.types.SCA_PythonJoystick.rst
+++ b/doc/python_api/rst/bge_types/bge.types.SCA_PythonJoystick.rst
@@ -12,13 +12,13 @@ base class --- :class:`PyObjectPlus`
.. attribute:: name
The name assigned to the joystick by the operating system. (read-only)
-
+
:type: string
.. attribute:: activeButtons
A list of active button values. (read-only)
-
+
:type: list
.. attribute:: axisValues
@@ -27,8 +27,10 @@ base class --- :class:`PyObjectPlus`
:type: list of ints.
- Each specifying the value of an axis between -1.0 and 1.0 depending on how far the axis is pushed, 0 for nothing.
- The first 2 values are used by most joysticks and gamepads for directional control. 3rd and 4th values are only on some joysticks and can be used for arbitary controls.
+ Each specifying the value of an axis between -1.0 and 1.0
+ depending on how far the axis is pushed, 0 for nothing.
+ The first 2 values are used by most joysticks and gamepads for directional control.
+ 3rd and 4th values are only on some joysticks and can be used for arbitary controls.
* left:[-1.0, 0.0, ...]
* right:[1.0, 0.0, ...]
diff --git a/doc/python_api/rst/bgl.rst b/doc/python_api/rst/bgl.rst
index 36e07a17cdc..99f481ce998 100644
--- a/doc/python_api/rst/bgl.rst
+++ b/doc/python_api/rst/bgl.rst
@@ -12,10 +12,10 @@ contents: dir(bgl). A simple search on the web can point to more
than enough material to teach OpenGL programming, from books to many
collections of tutorials.
-Here is a comprehensive `list of books <http://www.opengl.org/documentation/books/>`__ (non free).
-The `arcsynthesis tutorials <http://www.arcsynthesis.org/gltut/>`__
+Here is a comprehensive `list of books <https://www.opengl.org/documentation/books/>`__ (non free).
+The `arcsynthesis tutorials <https://web.archive.org/web/20150225192611/http://www.arcsynthesis.org/gltut/index.html>`__
is one of the best resources to learn modern OpenGL and
-`g-truc <http://www.g-truc.net/post-tech-content-sample.html>`__
+`g-truc <http://www.g-truc.net/post-opengl-samples.html#menu>`__
offers a set of extensive examples, including advanced features.
@@ -30,7 +30,7 @@ offers a set of extensive examples, including advanced features.
Operate on the accumulation buffer.
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glAccum.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glAccum.xml>`__
:type op: Enumerated constant
:arg op: The accumulation buffer operation.
@@ -42,7 +42,7 @@ offers a set of extensive examples, including advanced features.
Specify the alpha test function.
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glAlphaFunc.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glAlphaFunc.xml>`__
:type func: Enumerated constant
:arg func: Specifies the alpha comparison function.
@@ -55,7 +55,7 @@ offers a set of extensive examples, including advanced features.
Determine if textures are loaded in texture memory
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glAreTexturesResident.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glAreTexturesResident.xml>`__
:type n: int
:arg n: Specifies the number of textures to be queried.
@@ -71,7 +71,7 @@ offers a set of extensive examples, including advanced features.
Delimit the vertices of a primitive or a group of like primatives
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glBegin.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glBegin.xml>`__
:type mode: Enumerated constant
:arg mode: Specifies the primitive that will be create from vertices between
@@ -82,7 +82,7 @@ offers a set of extensive examples, including advanced features.
Bind a named texture to a texturing target
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glBindTexture.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glBindTexture.xml>`__
:type target: Enumerated constant
:arg target: Specifies the target to which the texture is bound.
@@ -94,7 +94,7 @@ offers a set of extensive examples, including advanced features.
Draw a bitmap
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glBitmap.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glBitmap.xml>`__
:type width, height: int
:arg width, height: Specify the pixel width and height of the bitmap image.
@@ -112,7 +112,7 @@ offers a set of extensive examples, including advanced features.
Specify pixel arithmetic
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glBlendFunc.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glBlendFunc.xml>`__
:type sfactor: Enumerated constant
:arg sfactor: Specifies how the red, green, blue, and alpha source blending factors are
@@ -126,7 +126,7 @@ offers a set of extensive examples, including advanced features.
Execute a display list
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glCallList.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glCallList.xml>`__
:type list: unsigned int
:arg list: Specifies the integer name of the display list to be executed.
@@ -136,7 +136,7 @@ offers a set of extensive examples, including advanced features.
Execute a list of display lists
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glCallLists.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glCallLists.xml>`__
:type n: int
:arg n: Specifies the number of display lists to be executed.
@@ -152,7 +152,7 @@ offers a set of extensive examples, including advanced features.
Clear buffers to preset values
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glClear.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glClear.xml>`__
:type mask: Enumerated constant(s)
:arg mask: Bitwise OR of masks that indicate the buffers to be cleared.
@@ -162,7 +162,7 @@ offers a set of extensive examples, including advanced features.
Specify clear values for the accumulation buffer
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glClearAccum.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glClearAccum.xml>`__
:type red, green, blue, alpha: float
:arg red, green, blue, alpha: Specify the red, green, blue, and alpha values used when the
@@ -173,7 +173,7 @@ offers a set of extensive examples, including advanced features.
Specify clear values for the color buffers
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glClearColor.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glClearColor.xml>`__
:type red, green, blue, alpha: float
:arg red, green, blue, alpha: Specify the red, green, blue, and alpha values used when the
@@ -184,7 +184,7 @@ offers a set of extensive examples, including advanced features.
Specify the clear value for the depth buffer
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glClearDepth.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glClearDepth.xml>`__
:type depth: int
:arg depth: Specifies the depth value used when the depth buffer is cleared.
@@ -195,7 +195,7 @@ offers a set of extensive examples, including advanced features.
Specify the clear value for the color index buffers
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glClearIndex.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glClearIndex.xml>`__
:type c: float
:arg c: Specifies the index used when the color index buffers are cleared.
@@ -206,7 +206,7 @@ offers a set of extensive examples, including advanced features.
Specify the clear value for the stencil buffer
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glClearStencil.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glClearStencil.xml>`__
:type s: int
:arg s: Specifies the index used when the stencil buffer is cleared. The initial value is 0.
@@ -216,7 +216,7 @@ offers a set of extensive examples, including advanced features.
Specify a plane against which all geometry is clipped
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glClipPlane.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glClipPlane.xml>`__
:type plane: Enumerated constant
:arg plane: Specifies which clipping plane is being positioned.
@@ -235,7 +235,7 @@ offers a set of extensive examples, including advanced features.
Set a new color.
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glColor.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glColor.xml>`__
:type red, green, blue, alpha: Depends on function prototype.
:arg red, green, blue: Specify new red, green, and blue values for the current color.
@@ -247,7 +247,7 @@ offers a set of extensive examples, including advanced features.
Enable and disable writing of frame buffer color components
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glColorMask.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glColorMask.xml>`__
:type red, green, blue, alpha: int (boolean)
:arg red, green, blue, alpha: Specify whether red, green, blue, and alpha can or cannot be
@@ -259,7 +259,7 @@ offers a set of extensive examples, including advanced features.
Cause a material color to track the current color
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glColorMaterial.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glColorMaterial.xml>`__
:type face: Enumerated constant
:arg face: Specifies whether front, back, or both front and back material parameters should
@@ -272,7 +272,7 @@ offers a set of extensive examples, including advanced features.
Copy pixels in the frame buffer
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glCopyPixels.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glCopyPixels.xml>`__
:type x, y: int
:arg x, y: Specify the window coordinates of the lower left corner of the rectangular
@@ -288,7 +288,7 @@ offers a set of extensive examples, including advanced features.
Copy pixels into a 2D texture image
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glCopyTexImage2D.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glCopyTexImage2D.xml>`__
:type target: Enumerated constant
:arg target: Specifies the target texture.
@@ -317,7 +317,7 @@ offers a set of extensive examples, including advanced features.
Specify whether front- or back-facing facets can be culled
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glCullFace.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glCullFace.xml>`__
:type mode: Enumerated constant
:arg mode: Specifies whether front- or back-facing facets are candidates for culling.
@@ -327,7 +327,7 @@ offers a set of extensive examples, including advanced features.
Delete a contiguous group of display lists
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glDeleteLists.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glDeleteLists.xml>`__
:type list: unsigned int
:arg list: Specifies the integer name of the first display list to delete
@@ -339,7 +339,7 @@ offers a set of extensive examples, including advanced features.
Delete named textures
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glDeleteTextures.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glDeleteTextures.xml>`__
:type n: int
:arg n: Specifies the number of textures to be deleted
@@ -351,7 +351,7 @@ offers a set of extensive examples, including advanced features.
Specify the value used for depth buffer comparisons
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glDepthFunc.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glDepthFunc.xml>`__
:type func: Enumerated constant
:arg func: Specifies the depth comparison function.
@@ -361,7 +361,7 @@ offers a set of extensive examples, including advanced features.
Enable or disable writing into the depth buffer
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glDepthMask.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glDepthMask.xml>`__
:type flag: int (boolean)
:arg flag: Specifies whether the depth buffer is enabled for writing. If flag is GL_FALSE,
@@ -373,7 +373,7 @@ offers a set of extensive examples, including advanced features.
Specify mapping of depth values from normalized device coordinates to window coordinates
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glDepthRange.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glDepthRange.xml>`__
:type zNear: int
:arg zNear: Specifies the mapping of the near clipping plane to window coordinates.
@@ -387,7 +387,7 @@ offers a set of extensive examples, including advanced features.
Disable server-side GL capabilities
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glEnable.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glEnable.xml>`__
:type cap: Enumerated constant
:arg cap: Specifies a symbolic constant indicating a GL capability.
@@ -397,7 +397,7 @@ offers a set of extensive examples, including advanced features.
Specify which color buffers are to be drawn into
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glDrawBuffer.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glDrawBuffer.xml>`__
:type mode: Enumerated constant
:arg mode: Specifies up to four color buffers to be drawn into.
@@ -407,7 +407,7 @@ offers a set of extensive examples, including advanced features.
Write a block of pixels to the frame buffer
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glDrawPixels.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glDrawPixels.xml>`__
:type width, height: int
:arg width, height: Specify the dimensions of the pixel rectangle to be
@@ -426,7 +426,7 @@ offers a set of extensive examples, including advanced features.
Flag edges as either boundary or non-boundary
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glEdgeFlag.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glEdgeFlag.xml>`__
:type flag: Depends of function prototype
:arg flag: Specifies the current edge flag value.The initial value is GL_TRUE.
@@ -436,7 +436,7 @@ offers a set of extensive examples, including advanced features.
Enable server-side GL capabilities
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glEnable.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glEnable.xml>`__
:type cap: Enumerated constant
:arg cap: Specifies a symbolic constant indicating a GL capability.
@@ -446,14 +446,14 @@ offers a set of extensive examples, including advanced features.
Delimit the vertices of a primitive or group of like primitives
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glBegin.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glBegin.xml>`__
.. function:: glEndList():
Create or replace a display list
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glNewList.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glNewList.xml>`__
.. function:: glEvalCoord (u,v):
@@ -463,7 +463,7 @@ offers a set of extensive examples, including advanced features.
Evaluate enabled one- and two-dimensional maps
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glEvalCoord.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glEvalCoord.xml>`__
:type u: Depends on function prototype.
:arg u: Specifies a value that is the domain coordinate u to the basis function defined
@@ -481,7 +481,7 @@ offers a set of extensive examples, including advanced features.
Compute a one- or two-dimensional grid of points or lines
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glEvalMesh.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glEvalMesh.xml>`__
:type mode: Enumerated constant
:arg mode: In glEvalMesh1, specifies whether to compute a one-dimensional
@@ -496,7 +496,7 @@ offers a set of extensive examples, including advanced features.
Generate and evaluate a single point in a mesh
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glEvalPoint.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glEvalPoint.xml>`__
:type i: int
:arg i: Specifies the integer value for grid domain variable i.
@@ -508,7 +508,7 @@ offers a set of extensive examples, including advanced features.
Controls feedback mode
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glFeedbackBuffer.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glFeedbackBuffer.xml>`__
:type size: int
:arg size: Specifies the maximum number of values that can be written into buffer.
@@ -523,14 +523,14 @@ offers a set of extensive examples, including advanced features.
Block until all GL execution is complete
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glFinish.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glFinish.xml>`__
.. function:: glFlush():
Force Execution of GL commands in finite time
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glFlush.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glFlush.xml>`__
.. function:: glFog (pname, param):
@@ -539,7 +539,7 @@ offers a set of extensive examples, including advanced features.
Specify fog parameters
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glFog.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glFog.xml>`__
:type pname: Enumerated constant
:arg pname: Specifies a single-valued fog parameter. If the function prototype
@@ -554,7 +554,7 @@ offers a set of extensive examples, including advanced features.
Define front- and back-facing polygons
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glFrontFace.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glFrontFace.xml>`__
:type mode: Enumerated constant
:arg mode: Specifies the orientation of front-facing polygons.
@@ -564,7 +564,7 @@ offers a set of extensive examples, including advanced features.
Multiply the current matrix by a perspective matrix
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glFrustum.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glFrustum.xml>`__
:type left, right: double (float)
:arg left, right: Specify the coordinates for the left and right vertical
@@ -581,7 +581,7 @@ offers a set of extensive examples, including advanced features.
Generate a contiguous set of empty display lists
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glGenLists.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glGenLists.xml>`__
:type range: int
:arg range: Specifies the number of contiguous empty display lists to be generated.
@@ -591,7 +591,7 @@ offers a set of extensive examples, including advanced features.
Generate texture names
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glGenTextures.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glGenTextures.xml>`__
:type n: int
:arg n: Specifies the number of textures name to be generated.
@@ -605,7 +605,7 @@ offers a set of extensive examples, including advanced features.
Return the value or values of a selected parameter
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glGet.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glGet.xml>`__
:type pname: Enumerated constant
:arg pname: Specifies the parameter value to be returned.
@@ -617,7 +617,7 @@ offers a set of extensive examples, including advanced features.
Return the coefficients of the specified clipping plane
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glGetClipPlane.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glGetClipPlane.xml>`__
:type plane: Enumerated constant
:arg plane: Specifies a clipping plane. The number of clipping planes depends on the
@@ -632,7 +632,7 @@ offers a set of extensive examples, including advanced features.
Return error information
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glGetError.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glGetError.xml>`__
.. function:: glGetLight (light, pname, params):
@@ -641,7 +641,7 @@ offers a set of extensive examples, including advanced features.
Return light source parameter values
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glGetLight.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glGetLight.xml>`__
:type light: Enumerated constant
:arg light: Specifies a light source. The number of possible lights depends on the
@@ -659,7 +659,7 @@ offers a set of extensive examples, including advanced features.
Return evaluator parameters
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glGetMap.xml>`_
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glGetMap.xml>`_
:type target: Enumerated constant
:arg target: Specifies the symbolic name of a map.
@@ -675,7 +675,7 @@ offers a set of extensive examples, including advanced features.
Return material parameters
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glGetMaterial.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glGetMaterial.xml>`__
:type face: Enumerated constant
:arg face: Specifies which of the two materials is being queried.
@@ -692,7 +692,7 @@ offers a set of extensive examples, including advanced features.
Return the specified pixel map
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glGetPixelMap.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glGetPixelMap.xml>`__
:type map: Enumerated constant
:arg map: Specifies the name of the pixel map to return.
@@ -704,7 +704,7 @@ offers a set of extensive examples, including advanced features.
Return the polygon stipple pattern
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glGetPolygonStipple.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glGetPolygonStipple.xml>`__
:type mask: :class:`bgl.Buffer` object I{type GL_BYTE}
:arg mask: Returns the stipple pattern. The initial value is all 1's.
@@ -714,7 +714,7 @@ offers a set of extensive examples, including advanced features.
Return a string describing the current GL connection
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glGetString.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glGetString.xml>`__
:type name: Enumerated constant
:arg name: Specifies a symbolic constant.
@@ -727,7 +727,7 @@ offers a set of extensive examples, including advanced features.
Return texture environment parameters
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glGetTexEnv.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glGetTexEnv.xml>`__
:type target: Enumerated constant
:arg target: Specifies a texture environment. Must be GL_TEXTURE_ENV.
@@ -743,7 +743,7 @@ offers a set of extensive examples, including advanced features.
Return texture coordinate generation parameters
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glGetTexGen.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glGetTexGen.xml>`__
:type coord: Enumerated constant
:arg coord: Specifies a texture coordinate.
@@ -757,7 +757,7 @@ offers a set of extensive examples, including advanced features.
Return a texture image
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glGetTexImage.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glGetTexImage.xml>`__
:type target: Enumerated constant
:arg target: Specifies which texture is to be obtained.
@@ -779,7 +779,7 @@ offers a set of extensive examples, including advanced features.
return texture parameter values for a specific level of detail
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glGetTexLevelParameter.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glGetTexLevelParameter.xml>`__
:type target: Enumerated constant
:arg target: Specifies the symbolic name of the target texture.
@@ -798,7 +798,7 @@ offers a set of extensive examples, including advanced features.
Return texture parameter values
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glGetTexParameter.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glGetTexParameter.xml>`__
:type target: Enumerated constant
:arg target: Specifies the symbolic name of the target texture.
@@ -812,7 +812,7 @@ offers a set of extensive examples, including advanced features.
Specify implementation-specific hints
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glHint.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glHint.xml>`__
:type target: Enumerated constant
:arg target: Specifies a symbolic constant indicating the behavior to be
@@ -827,7 +827,7 @@ offers a set of extensive examples, including advanced features.
Set the current color index
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glIndex.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glIndex.xml>`__
:type c: :class:`bgl.Buffer` object. Depends on function prototype.
:arg c: Specifies a pointer to a one element array that contains the new value for
@@ -838,7 +838,7 @@ offers a set of extensive examples, including advanced features.
Control the writing of individual bits in the color index buffers
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glIndexMask.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glIndexMask.xml>`__
:type mask: int
:arg mask: Specifies a bit mask to enable and disable the writing of individual bits
@@ -850,14 +850,14 @@ offers a set of extensive examples, including advanced features.
Initialize the name stack
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glInitNames.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glInitNames.xml>`__
.. function:: glIsEnabled(cap):
Test whether a capability is enabled
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glIsEnabled.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glIsEnabled.xml>`__
:type cap: Enumerated constant
:arg cap: Specifies a constant representing a GL capability.
@@ -867,7 +867,7 @@ offers a set of extensive examples, including advanced features.
Determine if a name corresponds to a display-list
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glIsList.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glIsList.xml>`__
:type list: unsigned int
:arg list: Specifies a potential display-list name.
@@ -877,7 +877,7 @@ offers a set of extensive examples, including advanced features.
Determine if a name corresponds to a texture
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glIsTexture.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glIsTexture.xml>`__
:type texture: unsigned int
:arg texture: Specifies a value that may be the name of a texture.
@@ -889,7 +889,7 @@ offers a set of extensive examples, including advanced features.
Set the light source parameters
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glLight.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glLight.xml>`__
:type light: Enumerated constant
:arg light: Specifies a light. The number of lights depends on the implementation,
@@ -909,7 +909,7 @@ offers a set of extensive examples, including advanced features.
Set the lighting model parameters
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glLightModel.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glLightModel.xml>`__
:type pname: Enumerated constant
:arg pname: Specifies a single-value light model parameter.
@@ -922,7 +922,7 @@ offers a set of extensive examples, including advanced features.
Specify the line stipple pattern
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glLineStipple.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glLineStipple.xml>`__
:type factor: int
:arg factor: Specifies a multiplier for each bit in the line stipple pattern.
@@ -939,7 +939,7 @@ offers a set of extensive examples, including advanced features.
Specify the width of rasterized lines.
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glLineWidth.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glLineWidth.xml>`__
:type width: float
:arg width: Specifies the width of rasterized lines. The initial value is 1.
@@ -949,7 +949,7 @@ offers a set of extensive examples, including advanced features.
Set the display-list base for glCallLists
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glListBase.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glListBase.xml>`__
:type base: unsigned int
:arg base: Specifies an integer offset that will be added to glCallLists
@@ -960,7 +960,7 @@ offers a set of extensive examples, including advanced features.
Replace the current matrix with the identity matrix
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glLoadIdentity.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glLoadIdentity.xml>`__
.. function:: glLoadMatrix (m):
@@ -969,7 +969,7 @@ offers a set of extensive examples, including advanced features.
Replace the current matrix with the specified matrix
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glLoadMatrix.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glLoadMatrix.xml>`__
:type m: :class:`bgl.Buffer` object. Depends on function prototype.
:arg m: Specifies a pointer to 16 consecutive values, which are used as the elements
@@ -980,7 +980,7 @@ offers a set of extensive examples, including advanced features.
Load a name onto the name stack.
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glLoadName.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glLoadName.xml>`__
:type name: unsigned int
:arg name: Specifies a name that will replace the top value on the name stack.
@@ -990,7 +990,7 @@ offers a set of extensive examples, including advanced features.
Specify a logical pixel operation for color index rendering
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glLogicOp.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glLogicOp.xml>`__
:type opcode: Enumerated constant
:arg opcode: Specifies a symbolic constant that selects a logical operation.
@@ -1002,7 +1002,7 @@ offers a set of extensive examples, including advanced features.
Define a one-dimensional evaluator
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glMap1.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glMap1.xml>`__
:type target: Enumerated constant
:arg target: Specifies the kind of values that are generated by the evaluator.
@@ -1027,7 +1027,7 @@ offers a set of extensive examples, including advanced features.
Define a two-dimensional evaluator
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glMap2.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glMap2.xml>`__
:type target: Enumerated constant
:arg target: Specifies the kind of values that are generated by the evaluator.
@@ -1068,7 +1068,7 @@ offers a set of extensive examples, including advanced features.
Define a one- or two-dimensional mesh
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glMapGrid.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glMapGrid.xml>`__
:type un: int
:arg un: Specifies the number of partitions in the grid range interval
@@ -1087,7 +1087,7 @@ offers a set of extensive examples, including advanced features.
Specify material parameters for the lighting model.
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glMaterial.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glMaterial.xml>`__
:type face: Enumerated constant
:arg face: Specifies which face or faces are being updated. Must be one of:
@@ -1104,7 +1104,7 @@ offers a set of extensive examples, including advanced features.
Specify which matrix is the current matrix.
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glMatrixMode.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glMatrixMode.xml>`__
:type mode: Enumerated constant
:arg mode: Specifies which matrix stack is the target for subsequent matrix operations.
@@ -1116,7 +1116,7 @@ offers a set of extensive examples, including advanced features.
Multiply the current matrix with the specified matrix
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glMultMatrix.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glMultMatrix.xml>`__
:type m: :class:`bgl.Buffer` object. Depends on function prototype.
:arg m: Points to 16 consecutive values that are used as the elements of a 4x4 column
@@ -1127,7 +1127,7 @@ offers a set of extensive examples, including advanced features.
Create or replace a display list
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glNewList.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glNewList.xml>`__
:type list: unsigned int
:arg list: Specifies the display list name
@@ -1142,7 +1142,7 @@ offers a set of extensive examples, including advanced features.
Set the current normal vector
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glNormal.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glNormal.xml>`__
:type nx, ny, nz: Depends on function prototype. (non - 'v' prototypes only)
:arg nx, ny, nz: Specify the x, y, and z coordinates of the new current normal.
@@ -1156,7 +1156,7 @@ offers a set of extensive examples, including advanced features.
Multiply the current matrix with an orthographic matrix
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glOrtho.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glOrtho.xml>`__
:type left, right: double (float)
:arg left, right: Specify the coordinates for the left and
@@ -1173,7 +1173,7 @@ offers a set of extensive examples, including advanced features.
Place a marker in the feedback buffer
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glPassThrough.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glPassThrough.xml>`__
:type token: float
:arg token: Specifies a marker value to be placed in the feedback
@@ -1186,7 +1186,7 @@ offers a set of extensive examples, including advanced features.
Set up pixel transfer maps
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glPixelMap.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glPixelMap.xml>`__
:type map: Enumerated constant
:arg map: Specifies a symbolic map name.
@@ -1202,7 +1202,7 @@ offers a set of extensive examples, including advanced features.
Set pixel storage modes
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glPixelStore.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glPixelStore.xml>`__
:type pname: Enumerated constant
:arg pname: Specifies the symbolic name of the parameter to be set.
@@ -1218,7 +1218,7 @@ offers a set of extensive examples, including advanced features.
Set pixel transfer modes
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glPixelTransfer.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glPixelTransfer.xml>`__
:type pname: Enumerated constant
:arg pname: Specifies the symbolic name of the pixel transfer parameter to be set.
@@ -1230,7 +1230,7 @@ offers a set of extensive examples, including advanced features.
Specify the pixel zoom factors
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glPixelZoom.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glPixelZoom.xml>`__
:type xfactor, yfactor: float
:arg xfactor, yfactor: Specify the x and y zoom factors for pixel write operations.
@@ -1240,7 +1240,7 @@ offers a set of extensive examples, including advanced features.
Specify the diameter of rasterized points
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glPointSize.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glPointSize.xml>`__
:type size: float
:arg size: Specifies the diameter of rasterized points. The initial value is 1.
@@ -1250,7 +1250,7 @@ offers a set of extensive examples, including advanced features.
Select a polygon rasterization mode
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glPolygonMode.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glPolygonMode.xml>`__
:type face: Enumerated constant
:arg face: Specifies the polygons that mode applies to.
@@ -1265,7 +1265,7 @@ offers a set of extensive examples, including advanced features.
Set the scale and units used to calculate depth values
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glPolygonOffset.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glPolygonOffset.xml>`__
:type factor: float
:arg factor: Specifies a scale factor that is used to create a variable depth
@@ -1279,7 +1279,7 @@ offers a set of extensive examples, including advanced features.
Set the polygon stippling pattern
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glPolygonStipple.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glPolygonStipple.xml>`__
:type mask: :class:`bgl.Buffer` object I{type GL_BYTE}
:arg mask: Specifies a pointer to a 32x32 stipple pattern that will be unpacked
@@ -1290,35 +1290,35 @@ offers a set of extensive examples, including advanced features.
Pop the server attribute stack
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glPopAttrib.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glPopAttrib.xml>`__
.. function:: glPopClientAttrib():
Pop the client attribute stack
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glPopClientAttrib.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glPopClientAttrib.xml>`__
.. function:: glPopMatrix():
Pop the current matrix stack
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glPopMatrix.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glPopMatrix.xml>`__
.. function:: glPopName():
Pop the name stack
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glPopName.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glPopName.xml>`__
.. function:: glPrioritizeTextures(n, textures, priorities):
Set texture residence priority
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glPrioritizeTextures.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glPrioritizeTextures.xml>`__
:type n: int
:arg n: Specifies the number of textures to be prioritized.
@@ -1334,7 +1334,7 @@ offers a set of extensive examples, including advanced features.
Push the server attribute stack
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glPushAttrib.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glPushAttrib.xml>`__
:type mask: Enumerated constant(s)
:arg mask: Specifies a mask that indicates which attributes to save.
@@ -1344,7 +1344,7 @@ offers a set of extensive examples, including advanced features.
Push the client attribute stack
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glPushClientAttrib.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glPushClientAttrib.xml>`__
:type mask: Enumerated constant(s)
:arg mask: Specifies a mask that indicates which attributes to save.
@@ -1354,14 +1354,14 @@ offers a set of extensive examples, including advanced features.
Push the current matrix stack
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glPushMatrix.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glPushMatrix.xml>`__
.. function:: glPushName(name):
Push the name stack
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glPushName.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glPushName.xml>`__
:type name: unsigned int
:arg name: Specifies a name that will be pushed onto the name stack.
@@ -1377,7 +1377,7 @@ offers a set of extensive examples, including advanced features.
Specify the raster position for pixel operations
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glRasterPos.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glRasterPos.xml>`__
:type x, y, z, w: Depends on function prototype. (z and w for '3' and '4' prototypes only)
:arg x, y, z, w: Specify the x,y,z, and w object coordinates (if present) for the
@@ -1409,7 +1409,7 @@ offers a set of extensive examples, including advanced features.
Select a color buffer source for pixels.
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glReadBuffer.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glReadBuffer.xml>`__
:type mode: Enumerated constant
:arg mode: Specifies a color buffer.
@@ -1419,7 +1419,7 @@ offers a set of extensive examples, including advanced features.
Read a block of pixels from the frame buffer
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glReadPixels.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glReadPixels.xml>`__
:type x, y: int
:arg x, y: Specify the window coordinates of the first pixel that is read
@@ -1442,7 +1442,7 @@ offers a set of extensive examples, including advanced features.
Draw a rectangle
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glRect.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glRect.xml>`__
:type x1, y1: Depends on function prototype. (for non 'v' prototypes only)
:arg x1, y1: Specify one vertex of a rectangle
@@ -1457,7 +1457,7 @@ offers a set of extensive examples, including advanced features.
Set rasterization mode
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glRenderMode.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glRenderMode.xml>`__
:type mode: Enumerated constant
:arg mode: Specifies the rasterization mode.
@@ -1469,7 +1469,7 @@ offers a set of extensive examples, including advanced features.
Multiply the current matrix by a rotation matrix
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glRotate.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glRotate.xml>`__
:type angle: Depends on function prototype.
:arg angle: Specifies the angle of rotation in degrees.
@@ -1483,7 +1483,7 @@ offers a set of extensive examples, including advanced features.
Multiply the current matrix by a general scaling matrix
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glScale.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glScale.xml>`__
:type x, y, z: Depends on function prototype.
:arg x, y, z: Specify scale factors along the x, y, and z axes, respectively.
@@ -1493,7 +1493,7 @@ offers a set of extensive examples, including advanced features.
Define the scissor box
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glScissor.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glScissor.xml>`__
:type x, y: int
:arg x, y: Specify the lower left corner of the scissor box. Initially (0, 0).
@@ -1507,7 +1507,7 @@ offers a set of extensive examples, including advanced features.
Establish a buffer for selection mode values
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glSelectBuffer.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glSelectBuffer.xml>`__
:type size: int
:arg size: Specifies the size of buffer
@@ -1519,7 +1519,7 @@ offers a set of extensive examples, including advanced features.
Select flat or smooth shading
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glShadeModel.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glShadeModel.xml>`__
:type mode: Enumerated constant
:arg mode: Specifies a symbolic value representing a shading technique.
@@ -1529,7 +1529,7 @@ offers a set of extensive examples, including advanced features.
Set function and reference value for stencil testing
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glStencilFuc.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man/docbook4/xhtml/glStencilFunc.xml>`__
:type func: Enumerated constant
:arg func: Specifies the test function.
@@ -1546,7 +1546,7 @@ offers a set of extensive examples, including advanced features.
Control the writing of individual bits in the stencil planes
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glStencilMask.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glStencilMask.xml>`__
:type mask: unsigned int
:arg mask: Specifies a bit mask to enable and disable writing of individual bits
@@ -1557,7 +1557,7 @@ offers a set of extensive examples, including advanced features.
Set stencil test actions
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glStencilOp.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glStencilOp.xml>`__
:type fail: Enumerated constant
:arg fail: Specifies the action to take when the stencil test fails.
@@ -1585,7 +1585,7 @@ offers a set of extensive examples, including advanced features.
Set the current texture coordinates
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glTexCoord.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glTexCoord.xml>`__
:type s, t, r, q: Depends on function prototype. (r and q for '3' and '4' prototypes only)
:arg s, t, r, q: Specify s, t, r, and q texture coordinates. Not all parameters are
@@ -1601,7 +1601,7 @@ offers a set of extensive examples, including advanced features.
Set texture environment parameters
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glTexEnv.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glTexEnv.xml>`__
:type target: Enumerated constant
:arg target: Specifies a texture environment. Must be GL_TEXTURE_ENV.
@@ -1620,7 +1620,7 @@ offers a set of extensive examples, including advanced features.
Control the generation of texture coordinates
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glTexGen.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glTexGen.xml>`__
:type coord: Enumerated constant
:arg coord: Specifies a texture coordinate.
@@ -1638,7 +1638,7 @@ offers a set of extensive examples, including advanced features.
Specify a one-dimensional texture image
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glTexImage1D.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glTexImage1D.xml>`__
:type target: Enumerated constant
:arg target: Specifies the target texture.
@@ -1665,7 +1665,7 @@ offers a set of extensive examples, including advanced features.
Specify a two-dimensional texture image
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glTexImage2D.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glTexImage2D.xml>`__
:type target: Enumerated constant
:arg target: Specifies the target texture.
@@ -1698,7 +1698,7 @@ offers a set of extensive examples, including advanced features.
Set texture parameters
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glTexParameter.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glTexParameter.xml>`__
:type target: Enumerated constant
:arg target: Specifies the target texture.
@@ -1715,7 +1715,7 @@ offers a set of extensive examples, including advanced features.
Multiply the current matrix by a translation matrix
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glTranslate.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glTranslate.xml>`__
:type x, y, z: Depends on function prototype.
:arg x, y, z: Specify the x, y, and z coordinates of a translation vector.
@@ -1730,7 +1730,7 @@ offers a set of extensive examples, including advanced features.
Specify a vertex
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glVertex.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glVertex.xml>`__
:type x, y, z, w: Depends on function prototype (z and w for '3' and '4' prototypes only)
:arg x, y, z, w: Specify x, y, z, and w coordinates of a vertex. Not all parameters
@@ -1746,7 +1746,7 @@ offers a set of extensive examples, including advanced features.
Set the viewport
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glViewport.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glViewport.xml>`__
:type x, y: int
:arg x, y: Specify the lower left corner of the viewport rectangle,
@@ -1761,7 +1761,7 @@ offers a set of extensive examples, including advanced features.
Set up a perspective projection matrix.
- .. seealso:: U{http://biology.ncsa.uiuc.edu/cgi-bin/infosrch.cgi?cmd=getdoc&coll=0650&db=bks&fname=/SGI_Developer/OpenGL_RM/ch06.html#id5577288}
+ .. seealso:: https://www.opengl.org/sdk/docs/man2/xhtml/gluPerspective.xml
:type fovY: double
:arg fovY: Specifies the field of view angle, in degrees, in the y direction.
@@ -1778,7 +1778,7 @@ offers a set of extensive examples, including advanced features.
Define a viewing transformation.
- .. seealso:: U{http://biology.ncsa.uiuc.edu/cgi-bin/infosrch.cgi?cmd=getdoc&coll=0650&db=bks&fname=/SGI_Developer/OpenGL_RM/ch06.html#id5573042}
+ .. seealso:: https://www.opengl.org/sdk/docs/man2/xhtml/gluLookAt.xml
:type eyex, eyey, eyez: double
:arg eyex, eyey, eyez: Specifies the position of the eye point.
@@ -1792,7 +1792,7 @@ offers a set of extensive examples, including advanced features.
Define a 2-D orthographic projection matrix.
- .. seealso:: U{http://biology.ncsa.uiuc.edu/cgi-bin/infosrch.cgi?cmd=getdoc&coll=0650&db=bks&fname=/SGI_Developer/OpenGL_RM/ch06.html#id5578074}
+ .. seealso:: https://www.opengl.org/sdk/docs/man2/xhtml/gluOrtho2D.xml
:type left, right: double
:arg left, right: Specify the coordinates for the left and right vertical clipping planes.
@@ -1804,7 +1804,7 @@ offers a set of extensive examples, including advanced features.
Define a picking region.
- .. seealso:: U{http://biology.ncsa.uiuc.edu/cgi-bin/infosrch.cgi?cmd=getdoc&coll=0650&db=bks&fname=/SGI_Developer/OpenGL_RM/ch06.html#id5578074}
+ .. seealso:: https://www.opengl.org/sdk/docs/man2/xhtml/gluPickMatrix.xml
:type x, y: double
:arg x, y: Specify the center of a picking region in window coordinates.
@@ -1818,7 +1818,7 @@ offers a set of extensive examples, including advanced features.
Map object coordinates to window coordinates.
- .. seealso:: U{http://biology.ncsa.uiuc.edu/cgi-bin/infosrch.cgi?cmd=getdoc&coll=0650&db=bks&fname=/SGI_Developer/OpenGL_RM/ch06.html#id5578074}
+ .. seealso:: https://www.opengl.org/sdk/docs/man2/xhtml/gluProject.xml
:type objx, objy, objz: double
:arg objx, objy, objz: Specify the object coordinates.
@@ -1836,7 +1836,7 @@ offers a set of extensive examples, including advanced features.
Map object coordinates to window coordinates.
- .. seealso:: U{http://biology.ncsa.uiuc.edu/cgi-bin/infosrch.cgi?cmd=getdoc&coll=0650&db=bks&fname=/SGI_Developer/OpenGL_RM/ch06.html#id5582204}
+ .. seealso:: https://www.opengl.org/sdk/docs/man2/xhtml/gluUnProject.xml
:type winx, winy, winz: double
:arg winx, winy, winz: Specify the window coordinates to be mapped.
@@ -1854,7 +1854,7 @@ offers a set of extensive examples, including advanced features.
Installs a program object as part of current rendering state
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glUseProgram.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glUseProgram.xml>`__
:type program: int
:arg program: Specifies the handle of the program object whose executables are to be used as part of current rendering state.
@@ -1864,7 +1864,7 @@ offers a set of extensive examples, including advanced features.
Validates a program object
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glValidateProgram.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glValidateProgram.xml>`__
:type program: int
:arg program: Specifies the handle of the program object to be validated.
@@ -1874,7 +1874,7 @@ offers a set of extensive examples, including advanced features.
Links a program object.
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glLinkProgram.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glLinkProgram.xml>`__
:type program: int
:arg program: Specifies the handle of the program object to be linked.
@@ -1884,7 +1884,7 @@ offers a set of extensive examples, including advanced features.
Select active texture unit.
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glActiveTexture.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glActiveTexture.xml>`__
:type texture: int
:arg texture: Constant in ``GL_TEXTURE0`` 0 - 8
@@ -1894,7 +1894,7 @@ offers a set of extensive examples, including advanced features.
Attaches a shader object to a program object.
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glAttachShader.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glAttachShader.xml>`__
:type program: int
:arg program: Specifies the program object to which a shader object will be attached.
@@ -1906,7 +1906,7 @@ offers a set of extensive examples, including advanced features.
Compiles a shader object.
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glCompileShader.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glCompileShader.xml>`__
:type shader: int
:arg shader: Specifies the shader object to be compiled.
@@ -1916,7 +1916,7 @@ offers a set of extensive examples, including advanced features.
Creates a program object
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glCreateProgram.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glCreateProgram.xml>`__
:rtype: int
:return: The new program or zero if an error occurs.
@@ -1926,7 +1926,7 @@ offers a set of extensive examples, including advanced features.
Creates a shader object.
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glCreateShader.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glCreateShader.xml>`__
:type shaderType: Specifies the type of shader to be created.
Must be one of ``GL_VERTEX_SHADER``,
@@ -1943,7 +1943,7 @@ offers a set of extensive examples, including advanced features.
Deletes a program object.
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glDeleteProgram.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glDeleteProgram.xml>`__
:type program: int
:arg program: Specifies the program object to be deleted.
@@ -1953,7 +1953,7 @@ offers a set of extensive examples, including advanced features.
Deletes a shader object.
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glDeleteShader.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glDeleteShader.xml>`__
:type shader: int
:arg shader: Specifies the shader object to be deleted.
@@ -1963,7 +1963,7 @@ offers a set of extensive examples, including advanced features.
Detaches a shader object from a program object to which it is attached.
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glDetachShader.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glDetachShader.xml>`__
:type program: int
:arg program: Specifies the program object from which to detach the shader object.
@@ -1975,7 +1975,7 @@ offers a set of extensive examples, including advanced features.
Returns the handles of the shader objects attached to a program object.
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glGetAttachedShaders.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glGetAttachedShaders.xml>`__
:type program: int
:arg program: Specifies the program object to be queried.
@@ -1991,7 +1991,7 @@ offers a set of extensive examples, including advanced features.
Returns the information log for a program object.
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glGetProgramInfoLog.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glGetProgramInfoLog.xml>`__
:type program: int
:arg program: Specifies the program object whose information log is to be queried.
@@ -2007,7 +2007,7 @@ offers a set of extensive examples, including advanced features.
Returns the information log for a shader object.
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glGetShaderInfoLog.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glGetShaderInfoLog.xml>`__
:type shader: int
:arg shader: Specifies the shader object whose information log is to be queried.
@@ -2023,7 +2023,7 @@ offers a set of extensive examples, including advanced features.
Returns a parameter from a program object.
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glGetProgram.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glGetProgram.xml>`__
:type program: int
:arg program: Specifies the program object to be queried.
@@ -2037,7 +2037,7 @@ offers a set of extensive examples, including advanced features.
Determines if a name corresponds to a shader object.
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glIsShader.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glIsShader.xml>`__
:type shader: int
:arg shader: Specifies a potential shader object.
@@ -2047,7 +2047,7 @@ offers a set of extensive examples, including advanced features.
Determines if a name corresponds to a program object
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glIsProgram.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glIsProgram.xml>`__
:type program: int
:arg program: Specifies a potential program object.
@@ -2057,7 +2057,7 @@ offers a set of extensive examples, including advanced features.
Returns the source code string from a shader object
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man2/xhtml/glGetShaderSource.xml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man2/xhtml/glGetShaderSource.xml>`__
:type shader: int
:arg shader: Specifies the shader object to be queried.
@@ -2073,7 +2073,7 @@ offers a set of extensive examples, including advanced features.
Replaces the source code in a shader object.
- .. seealso:: `OpenGL Docs <http://www.opengl.org/sdk/docs/man/html/glShaderSource.xhtml>`__
+ .. seealso:: `OpenGL Docs <https://www.opengl.org/sdk/docs/man/html/glShaderSource.xhtml>`__
:type shader: int
:arg shader: Specifies the handle of the shader object whose source code is to be replaced.
diff --git a/doc/python_api/rst/include__bmesh.rst b/doc/python_api/rst/include__bmesh.rst
index 070dc34c964..83e3e73cea4 100644
--- a/doc/python_api/rst/include__bmesh.rst
+++ b/doc/python_api/rst/include__bmesh.rst
@@ -1,7 +1,8 @@
..
This document is appended to the auto generated bmesh api doc to avoid clogging up the C files with details.
to test this run:
- ./blender.bin -b -noaudio -P doc/python_api/sphinx_doc_gen.py -- --partial bmesh* ; cd doc/python_api ; sphinx-build sphinx-in sphinx-out ; cd ../../
+ ./blender.bin -b -noaudio -P doc/python_api/sphinx_doc_gen.py -- \
+ --partial bmesh* ; cd doc/python_api ; sphinx-build sphinx-in sphinx-out ; cd ../../
Submodules:
@@ -22,7 +23,7 @@ The features exposed closely follow the C API,
giving python access to the functions used by blenders own mesh editing tools.
For an overview of BMesh data types and how they reference each other see:
-`BMesh Design Document <http://wiki.blender.org/index.php/Dev:2.6/Source/Modeling/BMesh/Design>`_ .
+`BMesh Design Document <https://wiki.blender.org/index.php/Dev:Source/Modeling/BMesh/Design>`_ .
.. note::
@@ -30,17 +31,16 @@ For an overview of BMesh data types and how they reference each other see:
**Disk** and **Radial** data is not exposed by the python api since this is for internal use only.
-.. warning::
-
- TODO items are...
+.. warning:: TODO items are...
* add access to BMesh **walkers**
* add custom-data manipulation functions add/remove/rename.
+
Example Script
--------------
-.. literalinclude:: ../../../release/scripts/templates_py/bmesh_simple.py
+.. literalinclude:: __/__/__/release/scripts/templates_py/bmesh_simple.py
Stand-Alone Module
@@ -59,9 +59,9 @@ There are 2 ways to access BMesh data, you can create a new BMesh by converting
:class:`bpy.types.BlendData.meshes` or by accessing the current edit mode mesh.
see: :class:`bmesh.types.BMesh.from_mesh` and :mod:`bmesh.from_edit_mesh` respectively.
-When explicitly converting from mesh data python **owns** the data, that is to say - that the mesh only exists while
-python holds a reference to it, and the script is responsible for putting it back into a mesh data-block when the edits
-are done.
+When explicitly converting from mesh data python **owns** the data, that is to say -
+that the mesh only exists while python holds a reference to it,
+and the script is responsible for putting it back into a mesh data-block when the edits are done.
Note that unlike :mod:`bpy`, a BMesh does not necessarily correspond to data in the currently open blend file,
a BMesh can be created, edited and freed without the user ever seeing or having access to it.
diff --git a/doc/python_api/rst/info_best_practice.rst b/doc/python_api/rst/info_best_practice.rst
index 9b95ada2b2c..418f636030c 100644
--- a/doc/python_api/rst/info_best_practice.rst
+++ b/doc/python_api/rst/info_best_practice.rst
@@ -18,7 +18,7 @@ amongst our own scripts and make it easier to use python scripts from other proj
Using our style guide for your own scripts makes it easier if you eventually want to contribute them to blender.
-This style guide is known as pep8 and can be found `here <http://www.python.org/dev/peps/pep-0008>`_
+This style guide is known as pep8 and can be found `here <https://www.python.org/dev/peps/pep-0008/>`_
A brief listing of pep8 criteria.
@@ -316,7 +316,7 @@ use to join a list of strings (the list may be temporary). In the following exam
Join is fastest on many strings,
-`string formatting <http://docs.python.org/py3k/library/string.html#string-formatting>`__
+`string formatting <https://wiki.blender.org/index.php/Dev:Source/Modeling/BMesh/Design>`__
is quite fast too (better for converting data types). String arithmetic is slowest.
diff --git a/doc/python_api/rst/info_gotcha.rst b/doc/python_api/rst/info_gotcha.rst
index 430a862cf7b..2b361d476da 100644
--- a/doc/python_api/rst/info_gotcha.rst
+++ b/doc/python_api/rst/info_gotcha.rst
@@ -1,3 +1,4 @@
+
*******
Gotchas
*******
@@ -38,7 +39,6 @@ but some operators are more picky about when they run.
In most cases you can figure out what context an operator needs
simply be seeing how it's used in Blender and thinking about what it does.
-
Unfortunately if you're still stuck - the only way to **really** know
whats going on is to read the source code for the poll function and see what its checking.
@@ -82,7 +82,6 @@ it should be reported to the bug tracker.
Stale Data
==========
-
No updates after setting values
-------------------------------
@@ -174,8 +173,8 @@ In this situation you can...
.. _info_gotcha_mesh_faces:
-NGons and Tessellation Faces
-============================
+N-Gons and Tessellation Faces
+=============================
Since 2.63 NGons are supported, this adds some complexity
since in some cases you need to access triangles/quads still (some exporters for example).
@@ -509,7 +508,7 @@ Unicode Problems
Python supports many different encodings so there is nothing stopping you from
writing a script in ``latin1`` or ``iso-8859-15``.
-See `pep-0263 <http://www.python.org/dev/peps/pep-0263/>`_
+See `pep-0263 <https://www.python.org/dev/peps/pep-0263/>`_
However this complicates matters for Blender's Python API because ``.blend`` files don't have an explicit encoding.
@@ -657,7 +656,7 @@ Here are some general hints to avoid running into these problems.
.. note::
To find the line of your script that crashes you can use the ``faulthandler`` module.
- See `faulthandler docs <http://docs.python.org/dev/library/faulthandler.html>`_.
+ See the `faulthandler docs <https://docs.python.org/dev/library/faulthandler.html>`_.
While the crash may be in Blenders C/C++ code,
this can help a lot to track down the area of the script that causes the crash.
diff --git a/doc/python_api/rst/info_overview.rst b/doc/python_api/rst/info_overview.rst
index 960dd07ecf1..b4ae906277d 100644
--- a/doc/python_api/rst/info_overview.rst
+++ b/doc/python_api/rst/info_overview.rst
@@ -43,8 +43,7 @@ scene manipulation, automation, defining your own toolset and customization.
On startup Blender scans the ``scripts/startup/`` directory for Python modules and imports them.
The exact location of this directory depends on your installation.
-`See the directory layout docs
-<https://www.blender.org/manual/getting_started/installing_blender/directorylayout.html>`__
+See the :ref:`directory layout docs <blender_manual:getting-started_installing-config-directories>`.
Script Loading
@@ -77,22 +76,22 @@ To run as modules:
- The obvious way, ``import some_module`` command from the text window or interactive console.
- Open as a text block and tick "Register" option, this will load with the blend file.
- copy into one of the directories ``scripts/startup``, where they will be automatically imported on startup.
-- define as an addon, enabling the addon will load it as a Python module.
+- define as an add-on, enabling the add-on will load it as a Python module.
-Addons
+Add-ons
------
Some of Blenders functionality is best kept optional,
-alongside scripts loaded at startup we have addons which are kept in their own directory ``scripts/addons``,
+alongside scripts loaded at startup we have add-ons which are kept in their own directory ``scripts/addons``,
and only load on startup if selected from the user preferences.
-The only difference between addons and built-in Python modules is that addons must contain a ``bl_info``
+The only difference between add-ons and built-in Python modules is that add-ons must contain a ``bl_info``
variable which Blender uses to read metadata such as name, author, category and URL.
-The user preferences addon listing uses **bl_info** to display information about each addon.
+The User Preferences add-on listing uses **bl_info** to display information about each add-on.
-`See Addons <http://wiki.blender.org/index.php/Dev:2.5/Py/Scripts/Guidelines/Addons>`__
+`See Add-ons <https://wiki.blender.org/index.php/Dev:Py/Scripts/Guidelines/Addons>`__
for details on the ``bl_info`` dictionary.
@@ -223,7 +222,7 @@ These functions usually appear at the bottom of the script containing class regi
You can also use them for internal purposes setting up data for your own tools but take care
since register won't re-run when a new blend file is loaded.
-The register/unregister calls are used so it's possible to toggle addons and reload scripts while Blender runs.
+The register/unregister calls are used so it's possible to toggle add-ons and reload scripts while Blender runs.
If the register calls were placed in the body of the script, registration would be called on import,
meaning there would be no distinction between importing a module or loading its classes into Blender.
diff --git a/doc/python_api/rst/info_quickstart.rst b/doc/python_api/rst/info_quickstart.rst
index 164196c0ac2..7a899e040a6 100644
--- a/doc/python_api/rst/info_quickstart.rst
+++ b/doc/python_api/rst/info_quickstart.rst
@@ -51,8 +51,7 @@ A quick list of helpful things to know before starting:
| ``scripts/startup/bl_operators`` for operators.
Exact location depends on platform, see:
- `Configuration and Data Paths
- <https://www.blender.org/manual/getting_started/installing_blender/directorylayout.html>`__.
+ :ref:`Configuration and Data Paths <blender_manual:getting-started_installing-config-directories>`.
Running Scripts
@@ -151,7 +150,7 @@ Data Creation/Removal
^^^^^^^^^^^^^^^^^^^^^
Those of you familiar with other Python API's may be surprised that
-new datablocks in the bpy API can't be created by calling the class:
+new data-blocks in the bpy API can't be created by calling the class:
>>> bpy.types.Mesh()
Traceback (most recent call last):
@@ -305,7 +304,7 @@ In Python, this is done by defining a class, which is a subclass of an existing
Example Operator
----------------
-.. literalinclude:: ../../../release/scripts/templates_py/operator_simple.py
+.. literalinclude:: __/__/__/release/scripts/templates_py/operator_simple.py
Once this script runs, ``SimpleOperator`` is registered with Blender
and can be called from the operator search popup or added to the toolbar.
@@ -336,7 +335,7 @@ Example Panel
Panels register themselves as a class, like an operator.
Notice the extra ``bl_`` variables used to set the context they display in.
-.. literalinclude:: ../../../release/scripts/templates_py/ui_panel_simple.py
+.. literalinclude:: __/__/__/release/scripts/templates_py/ui_panel_simple.py
To run the script:
@@ -393,11 +392,11 @@ so these are accessed as normal Python types.
Internal Types
--------------
-Used for Blender datablocks and collections: :class:`bpy.types.bpy_struct`
+Used for Blender data-blocks and collections: :class:`bpy.types.bpy_struct`
For data that contains its own attributes groups/meshes/bones/scenes... etc.
-There are 2 main types that wrap Blenders data, one for datablocks
+There are 2 main types that wrap Blenders data, one for data-blocks
(known internally as ``bpy_struct``), another for properties.
>>> bpy.context.object
diff --git a/doc/python_api/rst/info_tips_and_tricks.rst b/doc/python_api/rst/info_tips_and_tricks.rst
index e8928e07671..97bc682894a 100644
--- a/doc/python_api/rst/info_tips_and_tricks.rst
+++ b/doc/python_api/rst/info_tips_and_tricks.rst
@@ -27,7 +27,7 @@ There are 3 main uses for the terminal, these are:
.. note::
- For Linux and OSX users this means starting the terminal first, then running Blender from within it.
+ For Linux and macOS users this means starting the terminal first, then running Blender from within it.
On Windows the terminal can be enabled from the help menu.
@@ -306,7 +306,7 @@ Advantages include:
This is marked advanced because to run Blender as a Python module requires a special build option.
For instructions on building see
-`Building Blender as a Python module <http://wiki.blender.org/index.php/User:Ideasman42/BlenderAsPyModule>`_
+`Building Blender as a Python module <https://wiki.blender.org/index.php/User:Ideasman42/BlenderAsPyModule>`_
Python Safety (Build Option)
diff --git a/doc/python_api/rst/info_tutorial_addon.rst b/doc/python_api/rst/info_tutorial_addon.rst
index 239c28859a3..92fbf9b8787 100644
--- a/doc/python_api/rst/info_tutorial_addon.rst
+++ b/doc/python_api/rst/info_tutorial_addon.rst
@@ -1,6 +1,6 @@
-Addon Tutorial
-##############
+Add-on Tutorial
+###############
************
Introduction
@@ -36,6 +36,7 @@ Suggested reading before starting this tutorial.
To best troubleshoot any error message Python prints while writing scripts you run blender with from a terminal,
see :ref:`Use The Terminal <use_the_terminal>`.
+
Documentation Links
===================
@@ -46,51 +47,48 @@ While going through the tutorial you may want to look into our reference documen
- :mod:`bpy.context` api reference. -
*Handy to have a list of available items your script may operate on.*
- :class:`bpy.types.Operator`. -
- *The following addons define operators, these docs give details and more examples of operators.*
-
+ *The following add-ons define operators, these docs give details and more examples of operators.*
-******
-Addons
-******
+*******
+Add-ons
+*******
-What is an Addon?
-=================
+What is an Add-on?
+==================
-An addon is simply a Python module with some additional requirements so Blender can display it in a list with useful
+An add-on is simply a Python module with some additional requirements so Blender can display it in a list with useful
information.
-To give an example, here is the simplest possible addon.
-
+To give an example, here is the simplest possible add-on.
.. code-block:: python
- bl_info = {"name": "My Test Addon", "category": "Object"}
+ bl_info = {"name": "My Test Add-on", "category": "Object"}
def register():
print("Hello World")
def unregister():
print("Goodbye World")
-- ``bl_info`` is a dictionary containing addon meta-data such as the title, version and author to be displayed in the
- user preferences addon list.
-- ``register`` is a function which only runs when enabling the addon, this means the module can be loaded without
- activating the addon.
-- ``unregister`` is a function to unload anything setup by ``register``, this is called when the addon is disabled.
+- ``bl_info`` is a dictionary containing add-on metadata such as the title,
+ version and author to be displayed in the user preferences add-on list.
+- ``register`` is a function which only runs when enabling the add-on,
+ this means the module can be loaded without activating the add-on.
+- ``unregister`` is a function to unload anything setup by ``register``, this is called when the add-on is disabled.
+Notice this add-on does not do anything related to Blender, (the :mod:`bpy` module is not imported for example).
-Notice this addon does not do anything related to Blender, (the :mod:`bpy` module is not imported for example).
+This is a contrived example of an add-on that serves to illustrate the point
+that the base requirements of an add-on are simple.
-This is a contrived example of an addon that serves to illustrate the point
-that the base requirements of an addon are simple.
-
-An addon will typically register operators, panels, menu items etc, but its worth noting that _any_ script can do this,
+An add-on will typically register operators, panels, menu items etc, but its worth noting that _any_ script can do this,
when executed from the text editor or even the interactive console - there is nothing inherently different about an
-addon that allows it to integrate with Blender, such functionality is just provided by the :mod:`bpy` module for any
+add-on that allows it to integrate with Blender, such functionality is just provided by the :mod:`bpy` module for any
script to access.
-So an addon is just a way to encapsulate a Python module in a way a user can easily utilize.
+So an add-on is just a way to encapsulate a Python module in a way a user can easily utilize.
.. note::
@@ -99,14 +97,14 @@ So an addon is just a way to encapsulate a Python module in a way a user can eas
Messages will be printed when enabling and disabling.
-Your First Addon
-================
+Your First Add-on
+=================
-The simplest possible addon above was useful as an example but not much else.
-This next addon is simple but shows how to integrate a script into Blender using an ``Operator``
+The simplest possible add-on above is useful as an example but not much else.
+This next add-on is simple but shows how to integrate a script into Blender using an ``Operator``
which is the typical way to define a tool accessed from menus, buttons and keyboard shortcuts.
-For the first example we'll make a script that simply moves all objects in a scene.
+For the first example we will make a script that simply moves all objects in a scene.
Write The Script
@@ -123,20 +121,14 @@ Add the following script to the text editor in Blender.
obj.location.x += 1.0
-.. image:: run_script.png
- :width: 924px
- :align: center
- :height: 574px
- :alt: Run Script button
-
-Click the Run Script button, all objects in the active scene are moved by 1.0 Blender unit.
-Next we'll make this script into an addon.
+Click the :ref:`Run Script button <blender_manual:editors-text-run-script>`,
+all objects in the active scene are moved by 1.0 Blender unit.
-Write the Addon (Simple)
-------------------------
+Write the Add-on (Simple)
+-------------------------
-This addon takes the body of the script above, and adds them to an operator's ``execute()`` function.
+This add-on takes the body of the script above, and adds them to an operator's ``execute()`` function.
.. code-block:: python
@@ -173,7 +165,7 @@ This addon takes the body of the script above, and adds them to an operator's ``
# This allows you to run the script directly from blenders text editor
- # to test the addon without having to install it.
+ # to test the add-on without having to install it.
if __name__ == "__main__":
register()
@@ -206,33 +198,33 @@ Do this by pressing :kbd:`Spacebar` to bring up the operator search dialog and t
The objects should move as before.
-*Keep this addon open in Blender for the next step - Installing.*
+*Keep this add-on open in Blender for the next step - Installing.*
-Install The Addon
------------------
+Install The Add-on
+------------------
-Once you have your addon within in Blender's text editor,
+Once you have your add-on within in Blender's text editor,
you will want to be able to install it so it can be enabled in the user preferences to load on startup.
-Even though the addon above is a test, lets go through the steps anyway so you know how to do it for later.
+Even though the add-on above is a test, lets go through the steps anyway so you know how to do it for later.
-To install the Blender text as an addon you will first have to save it to disk, take care to obey the naming
+To install the Blender text as an add-on you will first have to save it to disk, take care to obey the naming
restrictions that apply to Python modules and end with a ``.py`` extension.
-Once the file is on disk, you can install it as you would for an addon downloaded online.
+Once the file is on disk, you can install it as you would for an add-on downloaded online.
-Open the user :menuselection:`File -> User Preferences`,
-Select the *Addon* section, press *Install Addon...* and select the file.
+Open the user :menuselection:`File --> User Preferences`,
+Select the *Add-on* section, press *Install Add-on...* and select the file.
-Now the addon will be listed and you can enable it by pressing the check-box,
+Now the add-on will be listed and you can enable it by pressing the check-box,
if you want it to be enabled on restart, press *Save as Default*.
.. note::
- The destination of the addon depends on your Blender configuration.
- When installing an addon the source and destination path are printed in the console.
- You can also find addon path locations by running this in the Python console.
+ The destination of the add-on depends on your Blender configuration.
+ When installing an add-on the source and destination path are printed in the console.
+ You can also find add-on path locations by running this in the Python console.
.. code-block:: python
@@ -240,20 +232,20 @@ if you want it to be enabled on restart, press *Save as Default*.
print(addon_utils.paths())
More is written on this topic here:
- `Directory Layout <https://www.blender.org/manual/getting_started/installing_blender/directorylayout.html>`_
+ :ref:`Directory Layout <blender_manual:getting-started_installing-config-directories>`.
-Your Second Addon
-=================
+Your Second Add-on
+==================
-For our second addon, we will focus on object instancing - this is - to make linked copies of an object in a
+For our second add-on, we will focus on object instancing - this is - to make linked copies of an object in a
similar way to what you may have seen with the array modifier.
Write The Script
----------------
-As before, first we will start with a script, develop it, then convert into an addon.
+As before, first we will start with a script, develop it, then convert into an add-on.
.. code-block:: python
@@ -324,17 +316,17 @@ allows vectors to be multiplied by numbers and matrices.
If you are interested in this area, read into :class:`mathutils.Vector` - there are many handy utility functions
such as getting the angle between vectors, cross product, dot products
-as well as more advanced functions in :mod:`mathutils.geometry` such as bezier spline interpolation and
+as well as more advanced functions in :mod:`mathutils.geometry` such as Bézier Spline interpolation and
ray-triangle intersection.
-For now we'll focus on making this script an addon, but its good to know that this 3D math module is available and
+For now we will focus on making this script an add-on, but its good to know that this 3D math module is available and
can help you with more advanced functionality later on.
-Write the Addon
----------------
+Write the Add-on
+----------------
-The first step is to convert the script as-is into an addon.
+The first step is to convert the script as-is into an add-on.
.. code-block:: python
@@ -381,7 +373,7 @@ The first step is to convert the script as-is into an addon.
register()
-Everything here has been covered in the previous steps, you may want to try run the addon still
+Everything here has been covered in the previous steps, you may want to try run the add-on still
and consider what could be done to make it more useful.
@@ -434,7 +426,7 @@ however the link above includes examples of more advanced property usage.
Menu Item
^^^^^^^^^
-Addons can add to the user interface of existing panels, headers and menus defined in Python.
+Add-ons can add to the user interface of existing panels, headers and menus defined in Python.
For this example we'll add to an existing menu.
@@ -464,7 +456,7 @@ For docs on extending menus see: :doc:`bpy.types.Menu`.
Keymap
^^^^^^
-In Blender addons have their own key-maps so as not to interfere with Blenders built in key-maps.
+In Blender, add-ons have their own keymaps so as not to interfere with Blenders built in key-maps.
In the example below, a new object-mode :class:`bpy.types.KeyMap` is added,
then a :class:`bpy.types.KeyMapItem` is added to the key-map which references our newly added operator,
@@ -502,7 +494,7 @@ this allows you to have multiple keys accessing the same operator with different
.. note::
- While :kbd:`Ctrl-Shift-Space` isn't a default Blender key shortcut, its hard to make sure addons won't
+ While :kbd:`Ctrl-Shift-Space` isn't a default Blender key shortcut, its hard to make sure add-ons won't
overwrite each others keymaps, At least take care when assigning keys that they don't
conflict with important functionality within Blender.
@@ -606,14 +598,14 @@ After selecting it from the menu, you can choose how many instance of the cube y
.. note::
Directly executing the script multiple times will add the menu each time too.
- While not useful behavior, theres nothing to worry about since addons won't register them selves multiple
+ While not useful behavior, theres nothing to worry about since add-ons won't register them selves multiple
times when enabled through the user preferences.
Conclusions
===========
-Addons can encapsulate certain functionality neatly for writing tools to improve your work-flow or for writing utilities
+Add-ons can encapsulate certain functionality neatly for writing tools to improve your work-flow or for writing utilities
for others to use.
While there are limits to what Python can do within Blender, there is certainly a lot that can be achieved without
@@ -636,8 +628,8 @@ Here are some sites you might like to check on after completing this tutorial.
*For more background details on Blender/Python integration.*
- `How to Think Like a Computer Scientist <http://interactivepython.org/courselib/static/thinkcspy/index.html>`_ -
*Great info for those who are still learning Python.*
-- `Blender Development (Wiki) <http://wiki.blender.org/index.php/Dev:Contents>`_ -
+- `Blender Development (Wiki) <https://wiki.blender.org/index.php/Dev:Contents>`_ -
*Blender Development, general information and helpful links.*
-- `Blender Artists (Coding Section) <http://blenderartists.org/forum/forumdisplay.php?47-Coding>`_ -
+- `Blender Artists (Coding Section) <https://blenderartists.org/forum/forumdisplay.php?47-Coding>`_ -
*forum where people ask Python development questions*
diff --git a/doc/python_api/rst_from_bmesh_opdefines.py b/doc/python_api/rst_from_bmesh_opdefines.py
index ebcedbf71f1..cdbed88cc88 100644
--- a/doc/python_api/rst_from_bmesh_opdefines.py
+++ b/doc/python_api/rst_from_bmesh_opdefines.py
@@ -57,7 +57,7 @@ Operator Example
++++++++++++++++
This script shows how operators can be used to model a link of a chain.
-.. literalinclude:: ../examples/bmesh.ops.1.py
+.. literalinclude:: __/examples/bmesh.ops.1.py
"""
diff --git a/doc/python_api/sphinx_changelog_gen.py b/doc/python_api/sphinx_changelog_gen.py
index 0b083c31c58..8758590dbae 100644
--- a/doc/python_api/sphinx_changelog_gen.py
+++ b/doc/python_api/sphinx_changelog_gen.py
@@ -27,7 +27,7 @@ output from this tool should be added into "doc/python_api/rst/change_log.rst"
blender --background --python doc/python_api/sphinx_changelog_gen.py -- --dump
# create changelog
-blender --background --python doc/python_api/sphinx_changelog_gen.py -- \
+blender --background --factory-startup --python doc/python_api/sphinx_changelog_gen.py -- \
--api_from blender_2_63_0.py \
--api_to blender_2_64_0.py \
--api_out changes.rst
@@ -48,7 +48,8 @@ python doc/python_api/sphinx_changelog_gen.py -- \
'''
{"module.name":
{"parent.class":
- {"basic_type", "member_name": ("Name", type, range, length, default, descr, f_args, f_arg_types, f_ret_types)}, ...
+ {"basic_type", "member_name":
+ ("Name", type, range, length, default, descr, f_args, f_arg_types, f_ret_types)}, ...
}, ...
}
'''
@@ -99,34 +100,34 @@ def api_dump():
prop_range = None
dump_class[prop_id] = (
- "prop_rna", # basic_type
- prop.name, # name
- prop_type, # type
- prop_range, # range
- prop_length, # length
- prop.default, # default
- prop.description, # descr
- Ellipsis, # f_args
- Ellipsis, # f_arg_types
- Ellipsis, # f_ret_types
- )
+ "prop_rna", # basic_type
+ prop.name, # name
+ prop_type, # type
+ prop_range, # range
+ prop_length, # length
+ prop.default, # default
+ prop.description, # descr
+ Ellipsis, # f_args
+ Ellipsis, # f_arg_types
+ Ellipsis, # f_ret_types
+ )
del props
# python props, tricky since we dont know much about them.
for prop_id, attr in struct_info.get_py_properties():
dump_class[prop_id] = (
- "prop_py", # basic_type
- Ellipsis, # name
- Ellipsis, # type
- Ellipsis, # range
- Ellipsis, # length
- Ellipsis, # default
- attr.__doc__, # descr
- Ellipsis, # f_args
- Ellipsis, # f_arg_types
- Ellipsis, # f_ret_types
- )
+ "prop_py", # basic_type
+ Ellipsis, # name
+ Ellipsis, # type
+ Ellipsis, # range
+ Ellipsis, # length
+ Ellipsis, # default
+ attr.__doc__, # descr
+ Ellipsis, # f_args
+ Ellipsis, # f_arg_types
+ Ellipsis, # f_ret_types
+ )
# kludge func -> props
funcs = [(func.identifier, func) for func in struct_info.functions]
@@ -137,17 +138,17 @@ def api_dump():
func_args_type = tuple([prop.type for prop in func.args])
dump_class[func_id] = (
- "func_rna", # basic_type
- Ellipsis, # name
- Ellipsis, # type
- Ellipsis, # range
- Ellipsis, # length
- Ellipsis, # default
- func.description, # descr
- func_args_ids, # f_args
- func_args_type, # f_arg_types
- func_ret_types, # f_ret_types
- )
+ "func_rna", # basic_type
+ Ellipsis, # name
+ Ellipsis, # type
+ Ellipsis, # range
+ Ellipsis, # length
+ Ellipsis, # default
+ func.description, # descr
+ func_args_ids, # f_args
+ func_args_type, # f_arg_types
+ func_ret_types, # f_ret_types
+ )
del funcs
# kludge func -> props
@@ -158,17 +159,17 @@ def api_dump():
func_args_ids = tuple(inspect.getargspec(attr).args)
dump_class[func_id] = (
- "func_py", # basic_type
- Ellipsis, # name
- Ellipsis, # type
- Ellipsis, # range
- Ellipsis, # length
- Ellipsis, # default
- attr.__doc__, # descr
- func_args_ids, # f_args
- Ellipsis, # f_arg_types
- Ellipsis, # f_ret_types
- )
+ "func_py", # basic_type
+ Ellipsis, # name
+ Ellipsis, # type
+ Ellipsis, # range
+ Ellipsis, # length
+ Ellipsis, # default
+ attr.__doc__, # descr
+ func_args_ids, # f_args
+ Ellipsis, # f_arg_types
+ Ellipsis, # f_ret_types
+ )
del funcs
import pprint
@@ -330,21 +331,25 @@ def main():
# When --help or no args are given, print this help
usage_text = "Run blender in background mode with this script: "
- "blender --background --python %s -- [options]" % os.path.basename(__file__)
+ "blender --background --factory-startup --python %s -- [options]" % os.path.basename(__file__)
epilog = "Run this before releases"
parser = argparse.ArgumentParser(description=usage_text, epilog=epilog)
- parser.add_argument("--dump", dest="dump", action='store_true',
- help="When set the api will be dumped into blender_version.py")
-
- parser.add_argument("--api_from", dest="api_from", metavar='FILE',
- help="File to compare from (previous version)")
- parser.add_argument("--api_to", dest="api_to", metavar='FILE',
- help="File to compare from (current)")
- parser.add_argument("--api_out", dest="api_out", metavar='FILE',
- help="Output sphinx changelog")
+ parser.add_argument(
+ "--dump", dest="dump", action='store_true',
+ help="When set the api will be dumped into blender_version.py")
+
+ parser.add_argument(
+ "--api_from", dest="api_from", metavar='FILE',
+ help="File to compare from (previous version)")
+ parser.add_argument(
+ "--api_to", dest="api_to", metavar='FILE',
+ help="File to compare from (current)")
+ parser.add_argument(
+ "--api_out", dest="api_out", metavar='FILE',
+ help="Output sphinx changelog")
args = parser.parse_args(argv) # In this example we wont use the args
diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py
index 9d0d358305b..432cceece1c 100644
--- a/doc/python_api/sphinx_doc_gen.py
+++ b/doc/python_api/sphinx_doc_gen.py
@@ -24,18 +24,18 @@ SCRIPT_HELP_MSG = """
API dump in RST files
---------------------
- Run this script from blenders root path once you have compiled blender
+ Run this script from Blender's root path once you have compiled Blender
- ./blender.bin --background -noaudio --python doc/python_api/sphinx_doc_gen.py
+ blender --background --factory-startup -noaudio --python doc/python_api/sphinx_doc_gen.py
This will generate python files in doc/python_api/sphinx-in/
- providing ./blender.bin is or links to the blender executable
+ providing ./blender is or links to the blender executable
To choose sphinx-in directory:
- ./blender.bin --background --python doc/python_api/sphinx_doc_gen.py -- --output ../python_api
+ blender --background --factory-startup --python doc/python_api/sphinx_doc_gen.py -- --output ../python_api
For quick builds:
- ./blender.bin --background --python doc/python_api/sphinx_doc_gen.py -- --partial bmesh.*
+ blender --background --factory-startup --python doc/python_api/sphinx_doc_gen.py -- --partial bmesh.*
Sphinx: HTML generation
@@ -46,8 +46,6 @@ Sphinx: HTML generation
cd doc/python_api
sphinx-build sphinx-in sphinx-out
- This requires sphinx 1.0.7 to be installed.
-
Sphinx: PDF generation
----------------------
@@ -61,14 +59,14 @@ Sphinx: PDF generation
"""
try:
- import bpy # blender module
+ import bpy # Blender module
except ImportError:
print("\nERROR: this script must run from inside Blender")
print(SCRIPT_HELP_MSG)
import sys
sys.exit()
-import rna_info # blender module
+import rna_info # Blender module
def rna_info_BuildRNAInfo_cache():
@@ -86,7 +84,7 @@ import shutil
import logging
from platform import platform
-PLATFORM = platform().split('-')[0].lower() # 'linux', 'darwin', 'windows'
+PLATFORM = platform().split('-')[0].lower() # 'linux', 'darwin', 'windows'
SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))
@@ -181,15 +179,13 @@ def handle_args():
dest="log",
default=False,
action='store_true',
- help=(
- "Log the output of the api dump and sphinx|latex "
- "warnings and errors (default=False).\n"
- "If given, save logs in:\n"
- "* OUTPUT_DIR/.bpy.log\n"
- "* OUTPUT_DIR/.sphinx-build.log\n"
- "* OUTPUT_DIR/.sphinx-build_pdf.log\n"
- "* OUTPUT_DIR/.latex_make.log",
- ),
+ help="Log the output of the api dump and sphinx|latex "
+ "warnings and errors (default=False).\n"
+ "If given, save logs in:\n"
+ "* OUTPUT_DIR/.bpy.log\n"
+ "* OUTPUT_DIR/.sphinx-build.log\n"
+ "* OUTPUT_DIR/.sphinx-build_pdf.log\n"
+ "* OUTPUT_DIR/.latex_make.log",
required=False)
# parse only the args passed after '--'
@@ -210,12 +206,12 @@ BPY_LOGGER.setLevel(logging.DEBUG)
"""
# for quick rebuilds
rm -rf /b/doc/python_api/sphinx-* && \
-./blender.bin -b -noaudio --factory-startup -P doc/python_api/sphinx_doc_gen.py && \
+./blender -b -noaudio --factory-startup -P doc/python_api/sphinx_doc_gen.py && \
sphinx-build doc/python_api/sphinx-in doc/python_api/sphinx-out
or
-./blender.bin -b -noaudio --factory-startup -P doc/python_api/sphinx_doc_gen.py -- -f -B
+./blender -b -noaudio --factory-startup -P doc/python_api/sphinx_doc_gen.py -- -f -B
"""
# Switch for quick testing so doc-builds don't take so long
@@ -224,12 +220,12 @@ if not ARGS.partial:
FILTER_BPY_OPS = None
FILTER_BPY_TYPES = None
EXCLUDE_INFO_DOCS = False
- EXCLUDE_MODULES = ()
+ EXCLUDE_MODULES = []
else:
# can manually edit this too:
- #FILTER_BPY_OPS = ("import.scene", ) # allow
- #FILTER_BPY_TYPES = ("bpy_struct", "Operator", "ID") # allow
+ # FILTER_BPY_OPS = ("import.scene", ) # allow
+ # FILTER_BPY_TYPES = ("bpy_struct", "Operator", "ID") # allow
EXCLUDE_INFO_DOCS = True
EXCLUDE_MODULES = [
"aud",
@@ -262,6 +258,7 @@ else:
"bpy_extras",
"gpu",
"gpu.offscreen",
+ "idprop.types",
"mathutils",
"mathutils.bvhtree",
"mathutils.geometry",
@@ -275,7 +272,7 @@ else:
"freestyle.shaders",
"freestyle.types",
"freestyle.utils",
- ]
+ ]
# ------
# Filter
@@ -301,7 +298,9 @@ else:
del m
del fnmatch
- BPY_LOGGER.debug("Partial Doc Build, Skipping: %s\n" % "\n ".join(sorted(EXCLUDE_MODULES)))
+ BPY_LOGGER.debug(
+ "Partial Doc Build, Skipping: %s\n" %
+ "\n ".join(sorted(EXCLUDE_MODULES)))
#
# done filtering
@@ -311,19 +310,39 @@ try:
__import__("aud")
except ImportError:
BPY_LOGGER.debug("Warning: Built without 'aud' module, docs incomplete...")
- EXCLUDE_MODULES = list(EXCLUDE_MODULES) + ["aud"]
+ EXCLUDE_MODULES.append("aud")
try:
__import__("freestyle")
except ImportError:
BPY_LOGGER.debug("Warning: Built without 'freestyle' module, docs incomplete...")
- EXCLUDE_MODULES = list(EXCLUDE_MODULES) + ["freestyle",
- "freestyle.chainingiterators",
- "freestyle.functions",
- "freestyle.predicates",
- "freestyle.shaders",
- "freestyle.types",
- "freestyle.utils"]
+ EXCLUDE_MODULES.extend([
+ "freestyle",
+ "freestyle.chainingiterators",
+ "freestyle.functions",
+ "freestyle.predicates",
+ "freestyle.shaders",
+ "freestyle.types",
+ "freestyle.utils",
+ ])
+
+# Source files we use, and need to copy to the OUTPUT_DIR
+# to have working out-of-source builds.
+# Note that ".." is replaced by "__" in the RST files,
+# to avoid having to match Blender's source tree.
+EXTRA_SOURCE_FILES = (
+ "../../../release/scripts/templates_py/bmesh_simple.py",
+ "../../../release/scripts/templates_py/operator_simple.py",
+ "../../../release/scripts/templates_py/ui_panel_simple.py",
+ "../../../release/scripts/templates_py/ui_previews_custom_icon.py",
+ "../examples/bge.constraints.py",
+ "../examples/bge.texture.1.py",
+ "../examples/bge.texture.2.py",
+ "../examples/bge.texture.py",
+ "../examples/bmesh.ops.1.py",
+ "../examples/bpy.app.translations.py",
+)
+
# examples
EXAMPLES_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, "examples"))
@@ -339,52 +358,59 @@ RST_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, "rst"))
# extra info, not api reference docs
# stored in ./rst/info_*
INFO_DOCS = (
- ("info_quickstart.rst", "Blender/Python Quickstart: new to blender/scripting and want to get your feet wet?"),
- ("info_overview.rst", "Blender/Python API Overview: a more complete explanation of python integration"),
- ("info_tutorial_addon.rst", "Blender/Python Addon Tutorial: a step by step guide on how to write an addon from scratch"),
- ("info_api_reference.rst", "Blender/Python API Reference Usage: examples of how to use the API reference docs"),
- ("info_best_practice.rst", "Best Practice: Conventions to follow for writing good scripts"),
- ("info_tips_and_tricks.rst", "Tips and Tricks: Hints to help you while writing scripts for blender"),
- ("info_gotcha.rst", "Gotcha's: some of the problems you may come up against when writing scripts"),
- )
+ ("info_quickstart.rst",
+ "Blender/Python Quickstart: new to Blender/scripting and want to get your feet wet?"),
+ ("info_overview.rst",
+ "Blender/Python API Overview: a more complete explanation of Python integration"),
+ ("info_tutorial_addon.rst",
+ "Blender/Python Add-on Tutorial: a step by step guide on how to write an add-on from scratch"),
+ ("info_api_reference.rst",
+ "Blender/Python API Reference Usage: examples of how to use the API reference docs"),
+ ("info_best_practice.rst",
+ "Best Practice: Conventions to follow for writing good scripts"),
+ ("info_tips_and_tricks.rst",
+ "Tips and Tricks: Hints to help you while writing scripts for Blender"),
+ ("info_gotcha.rst",
+ "Gotcha's: some of the problems you may come up against when writing scripts"),
+)
# only support for properties atm.
RNA_BLACKLIST = {
# XXX messes up PDF!, really a bug but for now just workaround.
"UserPreferencesSystem": {"language", }
- }
+}
MODULE_GROUPING = {
"bmesh.types": (
- ("Base Mesh Type", '-'),
- "BMesh",
- ("Mesh Elements", '-'),
- "BMVert",
- "BMEdge",
- "BMFace",
- "BMLoop",
- ("Sequence Accessors", '-'),
- "BMElemSeq",
- "BMVertSeq",
- "BMEdgeSeq",
- "BMFaceSeq",
- "BMLoopSeq",
- "BMIter",
- ("Selection History", '-'),
- "BMEditSelSeq",
- "BMEditSelIter",
- ("Custom-Data Layer Access", '-'),
- "BMLayerAccessVert",
- "BMLayerAccessEdge",
- "BMLayerAccessFace",
- "BMLayerAccessLoop",
- "BMLayerCollection",
- "BMLayerItem",
- ("Custom-Data Layer Types", '-'),
- "BMLoopUV",
- "BMDeformVert"
- )
- }
+ ("Base Mesh Type", '-'),
+ "BMesh",
+ ("Mesh Elements", '-'),
+ "BMVert",
+ "BMEdge",
+ "BMFace",
+ "BMLoop",
+ ("Sequence Accessors", '-'),
+ "BMElemSeq",
+ "BMVertSeq",
+ "BMEdgeSeq",
+ "BMFaceSeq",
+ "BMLoopSeq",
+ "BMIter",
+ ("Selection History", '-'),
+ "BMEditSelSeq",
+ "BMEditSelIter",
+ ("Custom-Data Layer Access", '-'),
+ "BMLayerAccessVert",
+ "BMLayerAccessEdge",
+ "BMLayerAccessFace",
+ "BMLayerAccessLoop",
+ "BMLayerCollection",
+ "BMLayerItem",
+ ("Custom-Data Layer Types", '-'),
+ "BMLoopUV",
+ "BMDeformVert"
+ )
+}
# --------------------configure compile time options----------------------------
@@ -392,7 +418,7 @@ MODULE_GROUPING = {
blender_version_strings = [str(v) for v in bpy.app.version]
-# converting bytes to strings, due to #30154
+# converting bytes to strings, due to T30154
BLENDER_REVISION = str(bpy.app.build_hash, 'utf_8')
BLENDER_DATE = str(bpy.app.build_date, 'utf_8')
@@ -460,10 +486,10 @@ MethodDescriptorType = type(dict.get)
GetSetDescriptorType = type(int.real)
StaticMethodType = type(staticmethod(lambda: None))
from types import (
- MemberDescriptorType,
- MethodType,
- FunctionType,
- )
+ MemberDescriptorType,
+ MethodType,
+ FunctionType,
+)
_BPY_STRUCT_FAKE = "bpy_struct"
_BPY_PROP_COLLECTION_FAKE = "bpy_prop_collection"
@@ -483,7 +509,7 @@ escape_rst.trans = str.maketrans({
"|": "\\|",
"*": "\\*",
"\\": "\\\\",
- })
+})
def is_struct_seq(value):
@@ -728,7 +754,7 @@ def py_c_func2sphinx(ident, fw, module_name, type_name, identifier, py_func, is_
def pyprop2sphinx(ident, fw, identifier, py_prop):
'''
- python property to sphinx
+ Python property to sphinx
'''
# readonly properties use "data" directive, variables use "attribute" directive
if py_prop.fset is None:
@@ -828,7 +854,8 @@ def pymodule2sphinx(basepath, module_name, module, title):
# naughty, we also add getset's into PyStructs, this is not typical py but also not incorrect.
# type_name is only used for examples and messages
- type_name = str(type(module)).strip("<>").split(" ", 1)[-1][1:-1] # "<class 'bpy.app.handlers'>" --> bpy.app.handlers
+ # "<class 'bpy.app.handlers'>" --> bpy.app.handlers
+ type_name = str(type(module)).strip("<>").split(" ", 1)[-1][1:-1]
if type(descr) == types.GetSetDescriptorType:
py_descr2sphinx("", fw, descr, module_name, type_name, key)
attribute_set.add(key)
@@ -889,7 +916,8 @@ def pymodule2sphinx(basepath, module_name, module, title):
for attribute, value, value_type in module_dir_value_type:
if value_type == FunctionType:
pyfunc2sphinx("", fw, module_name, None, attribute, value, is_class=False)
- elif value_type in {types.BuiltinMethodType, types.BuiltinFunctionType}: # both the same at the moment but to be future proof
+ # both the same at the moment but to be future proof
+ elif value_type in {types.BuiltinMethodType, types.BuiltinFunctionType}:
# note: can't get args from these, so dump the string as is
# this means any module used like this must have fully formatted docstrings.
py_c_func2sphinx("", fw, module_name, None, attribute, value, is_class=False)
@@ -955,7 +983,7 @@ def pymodule2sphinx(basepath, module_name, module, title):
if type(descr) == ClassMethodDescriptorType:
py_descr2sphinx(" ", fw, descr, module_name, type_name, key)
- # needed for pure python classes
+ # needed for pure Python classes
for key, descr in descr_items:
if type(descr) == FunctionType:
pyfunc2sphinx(" ", fw, module_name, type_name, key, descr, is_class=True)
@@ -978,12 +1006,15 @@ def pymodule2sphinx(basepath, module_name, module, title):
file.close()
-# Changes in blender will force errors here
+# Changes in Blender will force errors here
context_type_map = {
"active_base": ("ObjectBase", False),
"active_bone": ("EditBone", False),
"active_gpencil_frame": ("GreasePencilLayer", True),
"active_gpencil_layer": ("GPencilLayer", True),
+ "active_gpencil_brush": ("GPencilSculptBrush", False),
+ "active_gpencil_palette": ("GPencilPalette", True),
+ "active_gpencil_palettecolor": ("GPencilPaletteColor", True),
"active_node": ("Node", False),
"active_object": ("Object", False),
"active_operator": ("Operator", False),
@@ -1066,9 +1097,10 @@ def pycontext2sphinx(basepath):
fw(title_string("Context Access (bpy.context)", "="))
fw(".. module:: bpy.context\n")
fw("\n")
- fw("The context members available depend on the area of blender which is currently being accessed.\n")
+ fw("The context members available depend on the area of Blender which is currently being accessed.\n")
fw("\n")
- fw("Note that all context values are readonly, but may be modified through the data api or by running operators\n\n")
+ fw("Note that all context values are readonly,\n")
+ fw("but may be modified through the data api or by running operators\n\n")
def write_contex_cls():
@@ -1091,7 +1123,8 @@ def pycontext2sphinx(basepath):
if prop.identifier in struct_blacklist:
continue
- type_descr = prop.get_type_description(class_fmt=":class:`bpy.types.%s`", collection_id=_BPY_PROP_COLLECTION_ID)
+ type_descr = prop.get_type_description(
+ class_fmt=":class:`bpy.types.%s`", collection_id=_BPY_PROP_COLLECTION_ID)
fw(".. data:: %s\n\n" % prop.identifier)
if prop.description:
fw(" %s\n\n" % prop.description)
@@ -1111,7 +1144,7 @@ def pycontext2sphinx(basepath):
del write_contex_cls
# end
- # nasty, get strings directly from blender because there is no other way to get it
+ # nasty, get strings directly from Blender because there is no other way to get it
import ctypes
context_strings = (
@@ -1147,7 +1180,9 @@ def pycontext2sphinx(basepath):
# for member in sorted(unique):
# print(' "%s": ("", False),' % member)
if len(context_type_map) > len(unique):
- raise Exception("Some types are not used: %s" % str([member for member in context_type_map if member not in unique]))
+ raise Exception(
+ "Some types are not used: %s" %
+ str([member for member in context_type_map if member not in unique]))
else:
pass # will have raised an error above
@@ -1226,11 +1261,11 @@ def pyrna2sphinx(basepath):
fw(ident + ":%s%s: %s\n" % (id_type, identifier, type_descr))
def write_struct(struct):
- #if not struct.identifier.startswith("Sc") and not struct.identifier.startswith("I"):
- # return
+ # if not struct.identifier.startswith("Sc") and not struct.identifier.startswith("I"):
+ # return
- #if not struct.identifier == "Object":
- # return
+ # if not struct.identifier == "Object":
+ # return
filepath = os.path.join(basepath, "bpy.types.%s.rst" % struct.identifier)
file = open(filepath, "w", encoding="utf-8")
@@ -1271,7 +1306,11 @@ def pyrna2sphinx(basepath):
fw(", ".join((":class:`%s`" % base_id) for base_id in base_ids))
fw("\n\n")
- subclass_ids = [s.identifier for s in structs.values() if s.base is struct if not rna_info.rna_id_ignore(s.identifier)]
+ subclass_ids = [
+ s.identifier for s in structs.values()
+ if s.base is struct
+ if not rna_info.rna_id_ignore(s.identifier)
+ ]
subclass_ids.sort()
if subclass_ids:
fw("subclasses --- \n" + ", ".join((":class:`%s`" % s) for s in subclass_ids) + "\n\n")
@@ -1322,7 +1361,7 @@ def pyrna2sphinx(basepath):
fw(" :type: %s\n\n" % type_descr)
- # python attributes
+ # Python attributes
py_properties = struct.get_py_properties()
py_prop = None
for identifier, py_prop in py_properties:
@@ -1332,7 +1371,8 @@ def pyrna2sphinx(basepath):
for func in struct.functions:
args_str = ", ".join(prop.get_arg_default(force=False) for prop in func.args)
- fw(" .. %s:: %s(%s)\n\n" % ("classmethod" if func.is_classmethod else "method", func.identifier, args_str))
+ fw(" .. %s:: %s(%s)\n\n" %
+ ("classmethod" if func.is_classmethod else "method", func.identifier, args_str))
fw(" %s\n\n" % func.description)
for prop in func.args:
@@ -1343,8 +1383,10 @@ def pyrna2sphinx(basepath):
elif func.return_values: # multiple return values
fw(" :return (%s):\n" % ", ".join(prop.identifier for prop in func.return_values))
for prop in func.return_values:
- # TODO, pyrna_enum2sphinx for multiple return values... actually dont think we even use this but still!!!
- type_descr = prop.get_type_description(as_ret=True, class_fmt=":class:`%s`", collection_id=_BPY_PROP_COLLECTION_ID)
+ # TODO, pyrna_enum2sphinx for multiple return values... actually dont
+ # think we even use this but still!!!
+ type_descr = prop.get_type_description(
+ as_ret=True, class_fmt=":class:`%s`", collection_id=_BPY_PROP_COLLECTION_ID)
descr = prop.description
if not descr:
descr = prop.name
@@ -1357,7 +1399,7 @@ def pyrna2sphinx(basepath):
fw("\n")
- # python methods
+ # Python methods
py_funcs = struct.get_py_functions()
py_func = None
@@ -1380,7 +1422,10 @@ def pyrna2sphinx(basepath):
del lines[:]
if _BPY_STRUCT_FAKE:
- descr_items = [(key, descr) for key, descr in sorted(bpy.types.Struct.__bases__[0].__dict__.items()) if not key.startswith("__")]
+ descr_items = [
+ (key, descr) for key, descr in sorted(bpy.types.Struct.__bases__[0].__dict__.items())
+ if not key.startswith("__")
+ ]
if _BPY_STRUCT_FAKE:
for key, descr in descr_items:
@@ -1476,19 +1521,28 @@ def pyrna2sphinx(basepath):
fw("\n")
if use_subclasses:
- subclass_ids = [s.identifier for s in structs.values() if s.base is None if not rna_info.rna_id_ignore(s.identifier)]
+ subclass_ids = [
+ s.identifier for s in structs.values()
+ if s.base is None
+ if not rna_info.rna_id_ignore(s.identifier)
+ ]
if subclass_ids:
fw("subclasses --- \n" + ", ".join((":class:`%s`" % s) for s in sorted(subclass_ids)) + "\n\n")
fw(".. class:: %s\n\n" % class_name)
fw(" %s\n\n" % descr_str)
fw(" .. note::\n\n")
- fw(" Note that bpy.types.%s is not actually available from within blender, it only exists for the purpose of documentation.\n\n" % class_name)
+ fw(" Note that bpy.types.%s is not actually available from within Blender,\n"
+ " it only exists for the purpose of documentation.\n\n" % class_name)
- descr_items = [(key, descr) for key, descr in sorted(class_value.__dict__.items()) if not key.startswith("__")]
+ descr_items = [
+ (key, descr) for key, descr in sorted(class_value.__dict__.items())
+ if not key.startswith("__")
+ ]
for key, descr in descr_items:
- if type(descr) == MethodDescriptorType: # GetSetDescriptorType, GetSetDescriptorType's are not documented yet
+ # GetSetDescriptorType, GetSetDescriptorType's are not documented yet
+ if type(descr) == MethodDescriptorType:
py_descr2sphinx(" ", fw, descr, "bpy.types", class_name, key)
for key, descr in descr_items:
@@ -1499,17 +1553,21 @@ def pyrna2sphinx(basepath):
# write fake classes
if _BPY_STRUCT_FAKE:
class_value = bpy.types.Struct.__bases__[0]
- fake_bpy_type(class_value, _BPY_STRUCT_FAKE, "built-in base class for all classes in bpy.types.", use_subclasses=True)
+ fake_bpy_type(
+ class_value, _BPY_STRUCT_FAKE,
+ "built-in base class for all classes in bpy.types.", use_subclasses=True)
if _BPY_PROP_COLLECTION_FAKE:
class_value = bpy.data.objects.__class__
- fake_bpy_type(class_value, _BPY_PROP_COLLECTION_FAKE, "built-in class used for all collections.", use_subclasses=False)
+ fake_bpy_type(
+ class_value, _BPY_PROP_COLLECTION_FAKE,
+ "built-in class used for all collections.", use_subclasses=False)
# operators
def write_ops():
- API_BASEURL = "http://svn.blender.org/svnroot/bf-blender/trunk/blender/release/scripts"
- API_BASEURL_ADDON = "http://svn.blender.org/svnroot/bf-extensions/trunk/py/scripts"
- API_BASEURL_ADDON_CONTRIB = "http://svn.blender.org/svnroot/bf-extensions/contrib/py/scripts"
+ API_BASEURL = "https://developer.blender.org/diffusion/B/browse/master/release/scripts/ "
+ API_BASEURL_ADDON = "https://developer.blender.org/diffusion/BA/"
+ API_BASEURL_ADDON_CONTRIB = "https://developer.blender.org/diffusion/BAC/"
op_modules = {}
for op in ops.values():
@@ -1574,6 +1632,13 @@ def write_sphinx_conf_py(basepath):
file = open(filepath, "w", encoding="utf-8")
fw = file.write
+ fw("import sys, os\n")
+ fw("\n")
+ fw("extensions = ['sphinx.ext.intersphinx']\n")
+ fw("\n")
+ fw("intersphinx_mapping = {'blender_manual': ('https://www.blender.org/manual/', None)}\n")
+ fw("\n")
+
fw("project = 'Blender'\n")
# fw("master_doc = 'index'\n")
fw("copyright = u'Blender Foundation'\n")
@@ -1585,11 +1650,12 @@ def write_sphinx_conf_py(basepath):
if ARGS.sphinx_theme == "blender-org":
fw("html_theme_path = ['../']\n")
- # copied with the theme, exclude else we get an error [#28873]
+ # copied with the theme, exclude else we get an error [T28873]
fw("html_favicon = 'favicon.ico'\n") # in <theme>/static/
# not helpful since the source is generated, adds to upload size.
fw("html_copy_source = False\n")
+ fw("html_split_index = True\n")
fw("\n")
# needed for latex, pdf gen
@@ -1615,11 +1681,13 @@ def write_rst_contents(basepath):
fw(title_string("Blender Documentation Contents", "%", double=True))
fw("\n")
- fw("Welcome, this document is an API reference for Blender %s, built %s.\n" % (BLENDER_VERSION_DOTS, BLENDER_DATE))
+ fw("Welcome, this document is an API reference for Blender %s, built %s.\n" %
+ (BLENDER_VERSION_DOTS, BLENDER_DATE))
fw("\n")
# fw("`A PDF version of this document is also available <%s>`_\n" % BLENDER_PDF_FILENAME)
- fw("This site can be downloaded for offline use `Download the full Documentation (zipped HTML files) <%s>`_\n" % BLENDER_ZIP_FILENAME)
+ fw("This site can be downloaded for offline use `Download the full Documentation (zipped HTML files) <%s>`_\n" %
+ BLENDER_ZIP_FILENAME)
fw("\n")
@@ -1652,7 +1720,7 @@ def write_rst_contents(basepath):
# C modules
"bpy.props",
- )
+ )
for mod in app_modules:
if mod not in EXCLUDE_MODULES:
@@ -1673,9 +1741,10 @@ def write_rst_contents(basepath):
"freestyle", "bgl", "blf",
"gpu", "gpu.offscreen",
"aud", "bpy_extras",
+ "idprop.types",
# bmesh, submodules are in own page
"bmesh",
- )
+ )
for mod in standalone_modules:
if mod not in EXCLUDE_MODULES:
@@ -1713,7 +1782,8 @@ def write_rst_contents(basepath):
fw(" * mesh creation and editing functions\n")
fw(" \n")
fw(" These parts of the API are relatively stable and are unlikely to change significantly\n")
- fw(" * data API, access to attributes of blender data such as mesh verts, material color, timeline frames and scene objects\n")
+ fw(" * data API, access to attributes of Blender data such as mesh verts, material color,\n")
+ fw(" timeline frames and scene objects\n")
fw(" * user interface functions for defining buttons, creation of menus, headers, panels\n")
fw(" * render engine integration\n")
fw(" * modules: bgl, mathutils & game engine.\n")
@@ -1785,11 +1855,11 @@ def write_rst_data(basepath):
fw(title_string("Data Access (bpy.data)", "="))
fw(".. module:: bpy\n")
fw("\n")
- fw("This module is used for all blender/python access.\n")
+ fw("This module is used for all Blender/Python access.\n")
fw("\n")
fw(".. data:: data\n")
fw("\n")
- fw(" Access to blenders internal data\n")
+ fw(" Access to Blender's internal data\n")
fw("\n")
fw(" :type: :class:`bpy.types.BlendData`\n")
fw("\n")
@@ -1804,37 +1874,38 @@ def write_rst_importable_modules(basepath):
Write the rst files of importable modules
'''
importable_modules = {
- # python_modules
- "bpy.path" : "Path Utilities",
- "bpy.utils" : "Utilities",
- "bpy_extras" : "Extra Utilities",
+ # Python_modules
+ "bpy.path": "Path Utilities",
+ "bpy.utils": "Utilities",
+ "bpy_extras": "Extra Utilities",
# C_modules
- "aud" : "Audio System",
- "blf" : "Font Drawing",
- "gpu.offscreen" : "GPU Off-Screen Buffer",
- "bmesh" : "BMesh Module",
- "bmesh.types" : "BMesh Types",
- "bmesh.utils" : "BMesh Utilities",
- "bmesh.geometry" : "BMesh Geometry Utilities",
- "bpy.app" : "Application Data",
- "bpy.app.handlers" : "Application Handlers",
- "bpy.app.translations" : "Application Translations",
- "bpy.props" : "Property Definitions",
- "mathutils" : "Math Types & Utilities",
- "mathutils.geometry" : "Geometry Utilities",
- "mathutils.bvhtree" : "BVHTree Utilities",
- "mathutils.kdtree" : "KDTree Utilities",
+ "aud": "Audio System",
+ "blf": "Font Drawing",
+ "gpu.offscreen": "GPU Off-Screen Buffer",
+ "bmesh": "BMesh Module",
+ "bmesh.types": "BMesh Types",
+ "bmesh.utils": "BMesh Utilities",
+ "bmesh.geometry": "BMesh Geometry Utilities",
+ "bpy.app": "Application Data",
+ "bpy.app.handlers": "Application Handlers",
+ "bpy.app.translations": "Application Translations",
+ "bpy.props": "Property Definitions",
+ "idprop.types": "ID Property Access",
+ "mathutils": "Math Types & Utilities",
+ "mathutils.geometry": "Geometry Utilities",
+ "mathutils.bvhtree": "BVHTree Utilities",
+ "mathutils.kdtree": "KDTree Utilities",
"mathutils.interpolate": "Interpolation Utilities",
- "mathutils.noise" : "Noise Utilities",
- "freestyle" : "Freestyle Module",
- "freestyle.types" : "Freestyle Types",
- "freestyle.predicates" : "Freestyle Predicates",
- "freestyle.functions" : "Freestyle Functions",
- "freestyle.chainingiterators" : "Freestyle Chaining Iterators",
- "freestyle.shaders" : "Freestyle Shaders",
- "freestyle.utils" : "Freestyle Utilities",
- }
+ "mathutils.noise": "Noise Utilities",
+ "freestyle": "Freestyle Module",
+ "freestyle.types": "Freestyle Types",
+ "freestyle.predicates": "Freestyle Predicates",
+ "freestyle.functions": "Freestyle Functions",
+ "freestyle.chainingiterators": "Freestyle Chaining Iterators",
+ "freestyle.shaders": "Freestyle Shaders",
+ "freestyle.utils": "Freestyle Utilities",
+ }
for mod_name, mod_descr in importable_modules.items():
if mod_name not in EXCLUDE_MODULES:
module = __import__(mod_name,
@@ -1849,7 +1920,7 @@ def copy_handwritten_rsts(basepath):
for info, info_desc in INFO_DOCS:
shutil.copy2(os.path.join(RST_DIR, info), basepath)
- # TODO put this docs in blender's code and use import as per modules above
+ # TODO put this docs in Blender's code and use import as per modules above
handwritten_modules = [
"bge.logic",
"bge.render",
@@ -1890,6 +1961,21 @@ def copy_handwritten_rsts(basepath):
shutil.copy2(os.path.join(RST_DIR, f), basepath)
+def copy_handwritten_extra(basepath):
+ for f_src in EXTRA_SOURCE_FILES:
+ if os.sep != "/":
+ f_src = os.sep.join(f_src.split("/"))
+
+ f_dst = f_src.replace("..", "__")
+
+ f_src = os.path.join(RST_DIR, f_src)
+ f_dst = os.path.join(basepath, f_dst)
+
+ os.makedirs(os.path.dirname(f_dst), exist_ok=True)
+
+ shutil.copy2(f_src, f_dst)
+
+
def rna2sphinx(basepath):
try:
@@ -1921,35 +2007,48 @@ def rna2sphinx(basepath):
# copy the other rsts
copy_handwritten_rsts(basepath)
+ # copy source files referenced
+ copy_handwritten_extra(basepath)
-def align_sphinx_in_to_sphinx_in_tmp():
+
+def align_sphinx_in_to_sphinx_in_tmp(dir_src, dir_dst):
'''
Move changed files from SPHINX_IN_TMP to SPHINX_IN
'''
import filecmp
- sphinx_in_files = set(os.listdir(SPHINX_IN))
- sphinx_in_tmp_files = set(os.listdir(SPHINX_IN_TMP))
+ # possible the dir doesn't exist when running recursively
+ os.makedirs(dir_dst, exist_ok=True)
+
+ sphinx_dst_files = set(os.listdir(dir_dst))
+ sphinx_src_files = set(os.listdir(dir_src))
# remove deprecated files that have been removed
- for f in sorted(sphinx_in_files):
- if f not in sphinx_in_tmp_files:
+ for f in sorted(sphinx_dst_files):
+ if f not in sphinx_src_files:
BPY_LOGGER.debug("\tdeprecated: %s" % f)
- os.remove(os.path.join(SPHINX_IN, f))
+ f_dst = os.path.join(dir_dst, f)
+ if os.path.isdir(f_dst):
+ shutil.rmtree(f_dst, True)
+ else:
+ os.remove(f_dst)
# freshen with new files.
- for f in sorted(sphinx_in_tmp_files):
- f_from = os.path.join(SPHINX_IN_TMP, f)
- f_to = os.path.join(SPHINX_IN, f)
+ for f in sorted(sphinx_src_files):
+ f_src = os.path.join(dir_src, f)
+ f_dst = os.path.join(dir_dst, f)
- do_copy = True
- if f in sphinx_in_files:
- if filecmp.cmp(f_from, f_to):
- do_copy = False
+ if os.path.isdir(f_src):
+ align_sphinx_in_to_sphinx_in_tmp(f_src, f_dst)
+ else:
+ do_copy = True
+ if f in sphinx_dst_files:
+ if filecmp.cmp(f_src, f_dst):
+ do_copy = False
- if do_copy:
- BPY_LOGGER.debug("\tupdating: %s" % f)
- shutil.copy(f_from, f_to)
+ if do_copy:
+ BPY_LOGGER.debug("\tupdating: %s" % f)
+ shutil.copy(f_src, f_dst)
def refactor_sphinx_log(sphinx_logfile):
@@ -2036,7 +2135,7 @@ def main():
shutil.rmtree(SPHINX_OUT_PDF, True)
else:
# move changed files in SPHINX_IN
- align_sphinx_in_to_sphinx_in_tmp()
+ align_sphinx_in_to_sphinx_in_tmp(SPHINX_IN_TMP, SPHINX_IN)
# report which example files weren't used
EXAMPLE_SET_UNUSED = EXAMPLE_SET - EXAMPLE_SET_USED
diff --git a/doc/python_api/sphinx_doc_gen.sh b/doc/python_api/sphinx_doc_gen.sh
index 7095808f251..b3bdd386f8c 100755
--- a/doc/python_api/sphinx_doc_gen.sh
+++ b/doc/python_api/sphinx_doc_gen.sh
@@ -3,11 +3,6 @@
# bash doc/python_api/sphinx_doc_gen.sh
# ssh upload means you need an account on the server
-if [ "$1" == "" ] ; then
- echo "Expected a single argument for the username on blender.org, aborting"
- exit 1
-fi
-
# ----------------------------------------------------------------------------
# Upload vars
@@ -22,9 +17,15 @@ if [ -z $BLENDER_BIN ] ; then
BLENDER_BIN="./blender.bin"
fi
-SSH_USER=$1
-SSH_HOST=$SSH_USER"@blender.org"
-SSH_UPLOAD="/data/www/vhosts/www.blender.org/api" # blender_python_api_VERSION, added after
+if [ "$1" == "" ] ; then
+ echo "Expected a single argument for the username on blender.org, skipping upload step!"
+ DO_UPLOAD=false
+else
+ SSH_USER=$1
+ SSH_HOST=$SSH_USER"@blender.org"
+ SSH_UPLOAD="/data/www/vhosts/www.blender.org/api" # blender_python_api_VERSION, added after
+fi
+
# ----------------------------------------------------------------------------
# Blender Version & Info
@@ -33,10 +34,12 @@ SSH_UPLOAD="/data/www/vhosts/www.blender.org/api" # blender_python_api_VERSION,
# "_".join(str(v) for v in bpy.app.version)
# custom blender vars
blender_srcdir=$(dirname -- $0)/../..
-blender_version=$(grep "BLENDER_VERSION\s" "$blender_srcdir/source/blender/blenkernel/BKE_blender_version.h" | awk '{print $3}')
-blender_version_char=$(grep "BLENDER_VERSION_CHAR\s" "$blender_srcdir/source/blender/blenkernel/BKE_blender_version.h" | awk '{print $3}')
-blender_version_cycle=$(grep "BLENDER_VERSION_CYCLE\s" "$blender_srcdir/source/blender/blenkernel/BKE_blender_version.h" | awk '{print $3}')
-blender_subversion=$(grep "BLENDER_SUBVERSION\s" "$blender_srcdir/source/blender/blenkernel/BKE_blender_version.h" | awk '{print $3}')
+blender_version_header="$blender_srcdir/source/blender/blenkernel/BKE_blender_version.h"
+blender_version=$(grep "BLENDER_VERSION\s" "$blender_version_header" | awk '{print $3}')
+blender_version_char=$(grep "BLENDER_VERSION_CHAR\s" "$blender_version_header" | awk '{print $3}')
+blender_version_cycle=$(grep "BLENDER_VERSION_CYCLE\s" "$blender_version_header" | awk '{print $3}')
+blender_subversion=$(grep "BLENDER_SUBVERSION\s" "$blender_version_header" | awk '{print $3}')
+unset blender_version_header
if [ "$blender_version_cycle" = "release" ] ; then
BLENDER_VERSION=$(expr $blender_version / 100)_$(expr $blender_version % 100)$blender_version_char"_release"
@@ -48,6 +51,8 @@ SSH_UPLOAD_FULL=$SSH_UPLOAD/"blender_python_api_"$BLENDER_VERSION
SPHINXBASE=doc/python_api
+SPHINX_WORKDIR="$(mktemp --directory --suffix=.sphinx)"
+
# ----------------------------------------------------------------------------
# Generate reStructuredText (blender/python only)
@@ -59,23 +64,25 @@ if $DO_EXE_BLENDER ; then
-noaudio \
--factory-startup \
--python-exit-code 1 \
- --python $SPHINXBASE/sphinx_doc_gen.py
+ --python $SPHINXBASE/sphinx_doc_gen.py \
+ -- \
+ --output=$SPHINX_WORKDIR
+
- if (($? == 1)) ; then
+ if (($? != 0)) ; then
echo "Generating documentation failed, aborting"
exit 1
fi
fi
-
# ----------------------------------------------------------------------------
# Generate HTML (sphinx)
if $DO_OUT_HTML ; then
- # sphinx-build -n -b html $SPHINXBASE/sphinx-in $SPHINXBASE/sphinx-out
+ # sphinx-build -n -b html $SPHINX_WORKDIR/sphinx-in $SPHINX_WORKDIR/sphinx-out
# annoying bug in sphinx makes it very slow unless we do this. should report.
- cd $SPHINXBASE
+ cd $SPHINX_WORKDIR
sphinx-build -b html sphinx-in sphinx-out
# XXX, saves space on upload and zip, should move HTML outside
@@ -103,20 +110,21 @@ fi
# Generate PDF (sphinx/laytex)
if $DO_OUT_PDF ; then
- sphinx-build -n -b latex $SPHINXBASE/sphinx-in $SPHINXBASE/sphinx-out
- make -C $SPHINXBASE/sphinx-out
- mv $SPHINXBASE/sphinx-out/contents.pdf $SPHINXBASE/sphinx-out/blender_python_reference_$BLENDER_VERSION.pdf
+ cd $SPHINX_WORKDIR
+ sphinx-build -n -b latex $SPHINX_WORKDIR/sphinx-in $SPHINX_WORKDIR/sphinx-out
+ make -C $SPHINX_WORKDIR/sphinx-out
+ mv $SPHINX_WORKDIR/sphinx-out/contents.pdf \
+ $SPHINX_WORKDIR/sphinx-out/blender_python_reference_$BLENDER_VERSION.pdf
fi
-
# ----------------------------------------------------------------------------
# Upload to blender servers, comment this section for testing
if $DO_UPLOAD ; then
- cp $SPHINXBASE/sphinx-out/contents.html $SPHINXBASE/sphinx-out/index.html
+ cp $SPHINX_WORKDIR/sphinx-out/contents.html $SPHINX_WORKDIR/sphinx-out/index.html
ssh $SSH_USER@blender.org 'rm -rf '$SSH_UPLOAD_FULL'/*'
- rsync --progress -ave "ssh -p 22" $SPHINXBASE/sphinx-out/* $SSH_HOST:$SSH_UPLOAD_FULL/
+ rsync --progress -ave "ssh -p 22" $SPHINX_WORKDIR/sphinx-out/* $SSH_HOST:$SSH_UPLOAD_FULL/
## symlink the dir to a static URL
#ssh $SSH_USER@blender.org 'rm '$SSH_UPLOAD'/250PythonDoc && ln -s '$SSH_UPLOAD_FULL' '$SSH_UPLOAD'/250PythonDoc'
@@ -134,11 +142,15 @@ if $DO_UPLOAD ; then
if $DO_OUT_PDF ; then
# rename so local PDF has matching name.
- rsync --progress -ave "ssh -p 22" $SPHINXBASE/sphinx-out/blender_python_reference_$BLENDER_VERSION.pdf $SSH_HOST:$SSH_UPLOAD_FULL/blender_python_reference_$BLENDER_VERSION.pdf
+ rsync --progress -ave "ssh -p 22" \
+ $SPHINX_WORKDIR/sphinx-out/blender_python_reference_$BLENDER_VERSION.pdf \
+ $SSH_HOST:$SSH_UPLOAD_FULL/blender_python_reference_$BLENDER_VERSION.pdf
fi
if $DO_OUT_HTML_ZIP ; then
- rsync --progress -ave "ssh -p 22" $SPHINXBASE/blender_python_reference_$BLENDER_VERSION.zip $SSH_HOST:$SSH_UPLOAD_FULL/blender_python_reference_$BLENDER_VERSION.zip
+ rsync --progress -ave "ssh -p 22" \
+ $SPHINX_WORKDIR/blender_python_reference_$BLENDER_VERSION.zip \
+ $SSH_HOST:$SSH_UPLOAD_FULL/blender_python_reference_$BLENDER_VERSION.zip
fi
fi
@@ -149,5 +161,5 @@ fi
echo ""
echo "Finished! view the docs from: "
-if $DO_OUT_HTML ; then echo " html:" $SPHINXBASE/sphinx-out/contents.html ; fi
-if $DO_OUT_PDF ; then echo " pdf:" $SPHINXBASE/sphinx-out/blender_python_reference_$BLENDER_VERSION.pdf ; fi
+if $DO_OUT_HTML ; then echo " html:" $SPHINX_WORKDIR/sphinx-out/contents.html ; fi
+if $DO_OUT_PDF ; then echo " pdf:" $SPHINX_WORKDIR/sphinx-out/blender_python_reference_$BLENDER_VERSION.pdf ; fi
diff --git a/doc/python_api/sphinx_doc_update.py b/doc/python_api/sphinx_doc_update.py
new file mode 100755
index 00000000000..5301f39b2e3
--- /dev/null
+++ b/doc/python_api/sphinx_doc_update.py
@@ -0,0 +1,183 @@
+#!/usr/bin/env 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.
+#
+# Contributor(s): Bastien Montagne
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+"""
+This is a helper script to generate Blender Python API documentation (using Sphinx), and update server data using rsync.
+
+You'll need to specify your user login and password, obviously.
+
+Example usage:
+
+ ./sphinx_doc_update.py --mirror ../../../docs/remote_api_backup/ --source ../.. --blender ../../../build_cmake/bin/blender --user foobar --password barfoo
+
+"""
+
+import os
+import shutil
+import subprocess
+import sys
+import tempfile
+import zipfile
+
+
+DEFAULT_RSYNC_SERVER = "www.blender.org"
+DEFAULT_RSYNC_ROOT = "/api/"
+DEFAULT_SYMLINK_ROOT = "/data/www/vhosts/www.blender.org/api"
+
+
+def argparse_create():
+ import argparse
+ global __doc__
+
+ # When --help or no args are given, print this help
+ usage_text = __doc__
+
+ parser = argparse.ArgumentParser(description=usage_text,
+ formatter_class=argparse.RawDescriptionHelpFormatter)
+
+ parser.add_argument(
+ "--mirror", dest="mirror_dir",
+ metavar='PATH', required=True,
+ help="Path to local rsync mirror of api doc server")
+ parser.add_argument(
+ "--source", dest="source_dir",
+ metavar='PATH', required=True,
+ help="Path to Blender git repository")
+ parser.add_argument(
+ "--blender", dest="blender",
+ metavar='PATH', required=True,
+ help="Path to Blender executable")
+ parser.add_argument(
+ "--rsync-server", dest="rsync_server", default=DEFAULT_RSYNC_SERVER,
+ metavar='RSYNCSERVER', type=str, required=False,
+ help=("rsync server address"))
+ parser.add_argument(
+ "--rsync-root", dest="rsync_root", default=DEFAULT_RSYNC_ROOT,
+ metavar='RSYNCROOT', type=str, required=False,
+ help=("Root path of API doc on rsync server"))
+ parser.add_argument(
+ "--user", dest="user",
+ metavar='USER', type=str, required=True,
+ help=("User to login on rsync server"))
+ parser.add_argument(
+ "--password", dest="password",
+ metavar='PASSWORD', type=str, required=True,
+ help=("Password to login on rsync server"))
+
+ return parser
+
+
+def main():
+ # ----------
+ # Parse Args
+
+ args = argparse_create().parse_args()
+
+ rsync_base = "rsync://%s@%s:%s" % (args.user, args.rsync_server, args.rsync_root)
+
+ # I) Update local mirror using rsync.
+ rsync_mirror_cmd = ("rsync", "--delete-after", "-avzz", rsync_base, args.mirror_dir)
+ subprocess.run(rsync_mirror_cmd, env=dict(os.environ, RSYNC_PASSWORD=args.password))
+
+ with tempfile.TemporaryDirectory() as tmp_dir:
+ # II) Generate doc source in temp dir.
+ doc_gen_cmd = (args.blender, "--background", "-noaudio", "--factory-startup", "--python-exit-code", "1",
+ "--python", "%s/doc/python_api/sphinx_doc_gen.py" % args.source_dir, "--",
+ "--output", tmp_dir)
+ subprocess.run(doc_gen_cmd)
+
+ # III) Get Blender version info.
+ blenver = blenver_zip = ""
+ getver_file = os.path.join(tmp_dir, "blendver.txt")
+ getver_script = (""
+ "import sys, bpy\n"
+ "with open(sys.argv[-1], 'w') as f:\n"
+ " f.write('%d_%d%s_release\\n' % (bpy.app.version[0], bpy.app.version[1], bpy.app.version_char)\n"
+ " if bpy.app.version_cycle in {'rc', 'release'} else '%d_%d_%d\\n' % bpy.app.version)\n"
+ " f.write('%d_%d_%d' % bpy.app.version)\n")
+ get_ver_cmd = (args.blender, "--background", "-noaudio", "--factory-startup", "--python-exit-code", "1",
+ "--python-expr", getver_script, "--", getver_file)
+ subprocess.run(get_ver_cmd)
+ with open(getver_file) as f:
+ blenver, blenver_zip = f.read().split("\n")
+ os.remove(getver_file)
+
+ # IV) Build doc.
+ curr_dir = os.getcwd()
+ os.chdir(tmp_dir)
+ sphinx_cmd = ("sphinx-build", "-b", "html", "sphinx-in", "sphinx-out")
+ subprocess.run(sphinx_cmd)
+ shutil.rmtree(os.path.join("sphinx-out", ".doctrees"))
+ os.chdir(curr_dir)
+
+ # V) Cleanup existing matching dir in server mirror (if any), and copy new doc.
+ api_name = "blender_python_api_%s" % blenver
+ api_dir = os.path.join(args.mirror_dir, api_name)
+ if os.path.exists(api_dir):
+ shutil.rmtree(api_dir)
+ os.rename(os.path.join(tmp_dir, "sphinx-out"), api_dir)
+
+ # VI) Create zip archive.
+ zip_name = "blender_python_reference_%s" % blenver_zip # We can't use 'release' postfix here...
+ zip_path = os.path.join(args.mirror_dir, zip_name)
+ with zipfile.ZipFile(zip_path, 'w') as zf:
+ for de in os.scandir(api_dir):
+ zf.write(de.path, arcname=os.path.join(zip_name, de.name))
+ os.rename(zip_path, os.path.join(api_dir, "%s.zip" % zip_name))
+
+ # VII) Create symlinks and html redirects.
+ #~ os.symlink(os.path.join(DEFAULT_SYMLINK_ROOT, api_name, "contents.html"), os.path.join(api_dir, "index.html"))
+ os.symlink("./contents.html", os.path.join(api_dir, "index.html"))
+ if blenver.endswith("release"):
+ symlink = os.path.join(args.mirror_dir, "blender_python_api_current")
+ os.remove(symlink)
+ os.symlink("./%s" % api_name, symlink)
+ with open(os.path.join(args.mirror_dir, "250PythonDoc/index.html"), 'w') as f:
+ f.write("<html><head><title>Redirecting...</title><meta http-equiv=\"REFRESH\""
+ "content=\"0;url=../%s/\"></head><body>Redirecting...</body></html>" % api_name)
+ else:
+ symlink = os.path.join(args.mirror_dir, "blender_python_api_master")
+ os.remove(symlink)
+ os.symlink("./%s" % api_name, symlink)
+ with open(os.path.join(args.mirror_dir, "blender_python_api/index.html"), 'w') as f:
+ f.write("<html><head><title>Redirecting...</title><meta http-equiv=\"REFRESH\""
+ "content=\"0;url=../%s/\"></head><body>Redirecting...</body></html>" % api_name)
+
+ # VIII) Upload (first do a dry-run so user can ensure everything is OK).
+ print("Doc generated in local mirror %s, please check it before uploading "
+ "(hit [Enter] to continue, [Ctrl-C] to exit):" % api_dir)
+ sys.stdin.read(1)
+
+ rsync_mirror_cmd = ("rsync", "--dry-run", "--delete-after", "-avzz", args.mirror_dir, rsync_base)
+ subprocess.run(rsync_mirror_cmd, env=dict(os.environ, RSYNC_PASSWORD=args.password))
+
+ print("Rsync upload simulated, please check every thing is OK (hit [Enter] to continue, [Ctrl-C] to exit):")
+ sys.stdin.read(1)
+
+ rsync_mirror_cmd = ("rsync", "--delete-after", "-avzz", args.mirror_dir, rsync_base)
+ subprocess.run(rsync_mirror_cmd, env=dict(os.environ, RSYNC_PASSWORD=args.password))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt
index 58e0c68148b..45aa4a9d94d 100644
--- a/extern/CMakeLists.txt
+++ b/extern/CMakeLists.txt
@@ -29,6 +29,14 @@ add_subdirectory(curve_fit_nd)
# Otherwise we get warnings here that we cant fix in external projects
remove_strict_flags()
+# Not a strict flag, but noisy for code we don't maintain
+if(CMAKE_COMPILER_IS_GNUCC)
+ remove_cc_flag(
+ "-Wmisleading-indentation"
+ )
+endif()
+
+
add_subdirectory(rangetree)
add_subdirectory(wcwidth)
@@ -97,6 +105,7 @@ endif()
if(WITH_GTESTS)
add_subdirectory(gtest)
+ add_subdirectory(gmock)
endif()
if(WITH_SDL AND WITH_SDL_DYNLOAD)
diff --git a/extern/Eigen3/README.blender b/extern/Eigen3/README.blender
new file mode 100644
index 00000000000..8ccc46ac344
--- /dev/null
+++ b/extern/Eigen3/README.blender
@@ -0,0 +1,6 @@
+Project: Eigen, template library for linear algebra: matrices, vectors, numerical solvers, and related algorithms
+URL: http://eigen.tuxfamily.org/index.php?title=Main_Page
+License: GPLv3+
+Upstream version: 3.2.7
+Local modifications:
+- OpenMP fix for MSVC2015, see http://eigen.tuxfamily.org/bz/show_bug.cgi?id=1131
diff --git a/extern/binreloc/README.blender b/extern/binreloc/README.blender
new file mode 100644
index 00000000000..a90b44216a4
--- /dev/null
+++ b/extern/binreloc/README.blender
@@ -0,0 +1,6 @@
+Project: AutoPackage
+URL: http://autopackage.org/docs/binreloc (original, defunct)
+ http://alien.cern.ch/cache/autopackage-1.0/site/docs/binreloc/ (cache)
+License: Public Domain
+Upstream version: Unknown (Last Release)
+Local modifications: None
diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp b/extern/bullet2/src/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp
index 2c362778210..c1da9f36cfb 100644
--- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp
+++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp
@@ -151,8 +151,8 @@ static btScalar EdgeSeparation(const btBox2dShape* poly1, const btTransform& xf1
int index = 0;
btScalar minDot = BT_LARGE_FLOAT;
- if( count2 > 0 )
- index = (int) normal1.minDot( vertices2, count2, minDot);
+ if( count2 > 0 )
+ index = (int) normal1.minDot( vertices2, count2, minDot);
btVector3 v1 = b2Mul(xf1, vertices1[edge1]);
btVector3 v2 = b2Mul(xf2, vertices2[index]);
@@ -174,9 +174,9 @@ static btScalar FindMaxSeparation(int* edgeIndex,
// Find edge normal on poly1 that has the largest projection onto d.
int edge = 0;
- btScalar maxDot;
- if( count1 > 0 )
- edge = (int) dLocal1.maxDot( normals1, count1, maxDot);
+ btScalar maxDot;
+ if( count1 > 0 )
+ edge = (int) dLocal1.maxDot( normals1, count1, maxDot);
// Get the separation for the edge normal.
btScalar s = EdgeSeparation(poly1, xf1, edge, poly2, xf2);
diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp
index a80c438d12a..589a7f55f2b 100644
--- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp
+++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp
@@ -232,8 +232,8 @@ void btCompoundCollisionAlgorithm::processCollision (const btCollisionObjectWrap
m_compoundShapeRevision = compoundShape->getUpdateRevision();
}
- if (m_childCollisionAlgorithms.size()==0)
- return;
+ if (m_childCollisionAlgorithms.size()==0)
+ return;
const btDbvt* tree = compoundShape->getDynamicAabbTree();
//use a dynamic aabb tree to cull potential child-overlaps
diff --git a/extern/carve/README.blender b/extern/carve/README.blender
new file mode 100644
index 00000000000..80be40ae558
--- /dev/null
+++ b/extern/carve/README.blender
@@ -0,0 +1,4 @@
+Project: Carve, CSG library
+URL: https://code.google.com/archive/p/carve/
+Upstream version 9a85d733a43d
+Local modifications: See patches/ folder
diff --git a/extern/ceres/README.blender b/extern/ceres/README.blender
new file mode 100644
index 00000000000..44c389a42d9
--- /dev/null
+++ b/extern/ceres/README.blender
@@ -0,0 +1,4 @@
+Project: Ceres Solver
+URL: http://ceres-solver.org/
+Upstream version 1.11 (aef9c9563b08d5f39eee1576af133a84749d1b48)
+Local modifications: None
diff --git a/extern/clew/README.blender b/extern/clew/README.blender
new file mode 100644
index 00000000000..8355a96db8e
--- /dev/null
+++ b/extern/clew/README.blender
@@ -0,0 +1,5 @@
+Project: OpenCL Wrangler
+URL: https://github.com/OpenCLWrangler/clew
+License: Apache 2.0
+Upstream version: 309a653
+Local modifications: None
diff --git a/extern/clew/src/clew.c b/extern/clew/src/clew.c
index e3adabd829c..3717c74f1a0 100644
--- a/extern/clew/src/clew.c
+++ b/extern/clew/src/clew.c
@@ -137,6 +137,17 @@ PFNCLCREATEFROMGLTEXTURE3D __clewCreateFromGLTexture3D = NULL;
#endif
PFNCLGETGLCONTEXTINFOKHR __clewGetGLContextInfoKHR = NULL;
+static CLEW_DYNLIB_HANDLE dynamic_library_open_find(const char **paths) {
+ int i = 0;
+ while (paths[i] != NULL) {
+ CLEW_DYNLIB_HANDLE lib = CLEW_DYNLIB_OPEN(paths[i]);
+ if (lib != NULL) {
+ return lib;
+ }
+ ++i;
+ }
+ return NULL;
+}
static void clewExit(void)
{
@@ -151,11 +162,15 @@ static void clewExit(void)
int clewInit()
{
#ifdef _WIN32
- const char *path = "OpenCL.dll";
+ const char *paths[] = {"OpenCL.dll", NULL};
#elif defined(__APPLE__)
- const char *path = "/Library/Frameworks/OpenCL.framework/OpenCL";
+ const char *paths[] = {"/Library/Frameworks/OpenCL.framework/OpenCL", NULL};
#else
- const char *path = "libOpenCL.so";
+ const char *paths[] = {"libOpenCL.so",
+ "libOpenCL.so.0",
+ "libOpenCL.so.1",
+ "libOpenCL.so.2",
+ NULL};
#endif
int error = 0;
@@ -167,7 +182,7 @@ int clewInit()
}
// Load library
- module = CLEW_DYNLIB_OPEN(path);
+ module = dynamic_library_open_find(paths);
// Check for errors
if (module == NULL)
diff --git a/extern/cuew/README b/extern/cuew/README
index 3c43b7278d9..2fab76015e6 100644
--- a/extern/cuew/README
+++ b/extern/cuew/README
@@ -4,7 +4,7 @@ for determining which CUDA functions and extensions extensions are supported
on the target platform.
CUDA core and extension functionality is exposed in a single header file.
-GUEW has been tested on a variety of operating systems, including Windows,
+CUEW has been tested on a variety of operating systems, including Windows,
Linux, Mac OS X.
LICENSE
diff --git a/extern/cuew/README.blender b/extern/cuew/README.blender
new file mode 100644
index 00000000000..7b77935d750
--- /dev/null
+++ b/extern/cuew/README.blender
@@ -0,0 +1,5 @@
+Project: Cuda Wrangler
+URL: https://github.com/CudaWrangler/cuew
+License: Apache 2.0
+Upstream version: 63d2a0f
+Local modifications: None
diff --git a/extern/cuew/include/cuew.h b/extern/cuew/include/cuew.h
index 47b19b4b3a5..19087117667 100644
--- a/extern/cuew/include/cuew.h
+++ b/extern/cuew/include/cuew.h
@@ -131,8 +131,8 @@ typedef struct CUsurfref_st* CUsurfref;
typedef struct CUevent_st* CUevent;
typedef struct CUstream_st* CUstream;
typedef struct CUgraphicsResource_st* CUgraphicsResource;
-typedef unsigned CUtexObject;
-typedef unsigned CUsurfObject;
+typedef unsigned long long CUtexObject;
+typedef unsigned long long CUsurfObject;
typedef struct CUuuid_st {
char bytes[16];
@@ -603,7 +603,7 @@ typedef struct CUDA_ARRAY_DESCRIPTOR_st {
size_t Width;
size_t Height;
CUarray_format Format;
- unsigned NumChannels;
+ unsigned int NumChannels;
} CUDA_ARRAY_DESCRIPTOR;
typedef struct CUDA_ARRAY3D_DESCRIPTOR_st {
@@ -611,8 +611,8 @@ typedef struct CUDA_ARRAY3D_DESCRIPTOR_st {
size_t Height;
size_t Depth;
CUarray_format Format;
- unsigned NumChannels;
- unsigned Flags;
+ unsigned int NumChannels;
+ unsigned int Flags;
} CUDA_ARRAY3D_DESCRIPTOR;
typedef struct CUDA_RESOURCE_DESC_st {
@@ -627,13 +627,13 @@ typedef struct CUDA_RESOURCE_DESC_st {
struct {
CUdeviceptr devPtr;
CUarray_format format;
- unsigned numChannels;
+ unsigned int numChannels;
size_t sizeInBytes;
} linear;
struct {
CUdeviceptr devPtr;
CUarray_format format;
- unsigned numChannels;
+ unsigned int numChannels;
size_t width;
size_t height;
size_t pitchInBytes;
@@ -642,14 +642,14 @@ typedef struct CUDA_RESOURCE_DESC_st {
int reserved[32];
} reserved;
} res;
- unsigned flags;
+ unsigned int flags;
} CUDA_RESOURCE_DESC;
typedef struct CUDA_TEXTURE_DESC_st {
CUaddress_mode addressMode[3];
CUfilter_mode filterMode;
- unsigned flags;
- unsigned maxAnisotropy;
+ unsigned int flags;
+ unsigned int maxAnisotropy;
CUfilter_mode mipmapFilterMode;
float mipmapLevelBias;
float minMipmapLevelClamp;
@@ -700,19 +700,19 @@ typedef struct CUDA_RESOURCE_VIEW_DESC_st {
size_t width;
size_t height;
size_t depth;
- unsigned firstMipmapLevel;
- unsigned lastMipmapLevel;
- unsigned firstLayer;
- unsigned lastLayer;
- unsigned reserved[16];
+ unsigned int firstMipmapLevel;
+ unsigned int lastMipmapLevel;
+ unsigned int firstLayer;
+ unsigned int lastLayer;
+ unsigned int reserved[16];
} CUDA_RESOURCE_VIEW_DESC;
typedef struct CUDA_POINTER_ATTRIBUTE_P2P_TOKENS_st {
- unsigned p2pToken;
- unsigned vaSpaceToken;
+ unsigned long long p2pToken;
+ unsigned int vaSpaceToken;
} CUDA_POINTER_ATTRIBUTE_P2P_TOKENS;
-typedef unsigned GLenum;
-typedef unsigned GLuint;
+typedef unsigned int GLenum;
+typedef unsigned int GLuint;
typedef int GLint;
typedef enum CUGLDeviceList_enum {
@@ -751,7 +751,7 @@ typedef struct _nvrtcProgram* nvrtcProgram;
/* Function types. */
typedef CUresult CUDAAPI tcuGetErrorString(CUresult error, const char* pStr);
typedef CUresult CUDAAPI tcuGetErrorName(CUresult error, const char* pStr);
-typedef CUresult CUDAAPI tcuInit(unsigned Flags);
+typedef CUresult CUDAAPI tcuInit(unsigned int Flags);
typedef CUresult CUDAAPI tcuDriverGetVersion(int* driverVersion);
typedef CUresult CUDAAPI tcuDeviceGet(CUdevice* device, int ordinal);
typedef CUresult CUDAAPI tcuDeviceGetCount(int* count);
@@ -762,17 +762,17 @@ typedef CUresult CUDAAPI tcuDeviceGetProperties(CUdevprop* prop, CUdevice dev);
typedef CUresult CUDAAPI tcuDeviceComputeCapability(int* major, int* minor, CUdevice dev);
typedef CUresult CUDAAPI tcuDevicePrimaryCtxRetain(CUcontext* pctx, CUdevice dev);
typedef CUresult CUDAAPI tcuDevicePrimaryCtxRelease(CUdevice dev);
-typedef CUresult CUDAAPI tcuDevicePrimaryCtxSetFlags(CUdevice dev, unsigned flags);
-typedef CUresult CUDAAPI tcuDevicePrimaryCtxGetState(CUdevice dev, unsigned* flags, int* active);
+typedef CUresult CUDAAPI tcuDevicePrimaryCtxSetFlags(CUdevice dev, unsigned int flags);
+typedef CUresult CUDAAPI tcuDevicePrimaryCtxGetState(CUdevice dev, unsigned int* flags, int* active);
typedef CUresult CUDAAPI tcuDevicePrimaryCtxReset(CUdevice dev);
-typedef CUresult CUDAAPI tcuCtxCreate_v2(CUcontext* pctx, unsigned flags, CUdevice dev);
+typedef CUresult CUDAAPI tcuCtxCreate_v2(CUcontext* pctx, unsigned int flags, CUdevice dev);
typedef CUresult CUDAAPI tcuCtxDestroy_v2(CUcontext ctx);
typedef CUresult CUDAAPI tcuCtxPushCurrent_v2(CUcontext ctx);
typedef CUresult CUDAAPI tcuCtxPopCurrent_v2(CUcontext* pctx);
typedef CUresult CUDAAPI tcuCtxSetCurrent(CUcontext ctx);
typedef CUresult CUDAAPI tcuCtxGetCurrent(CUcontext* pctx);
typedef CUresult CUDAAPI tcuCtxGetDevice(CUdevice* device);
-typedef CUresult CUDAAPI tcuCtxGetFlags(unsigned* flags);
+typedef CUresult CUDAAPI tcuCtxGetFlags(unsigned int* flags);
typedef CUresult CUDAAPI tcuCtxSynchronize(void);
typedef CUresult CUDAAPI tcuCtxSetLimit(CUlimit limit, size_t value);
typedef CUresult CUDAAPI tcuCtxGetLimit(size_t* pvalue, CUlimit limit);
@@ -780,43 +780,43 @@ typedef CUresult CUDAAPI tcuCtxGetCacheConfig(CUfunc_cache* pconfig);
typedef CUresult CUDAAPI tcuCtxSetCacheConfig(CUfunc_cache config);
typedef CUresult CUDAAPI tcuCtxGetSharedMemConfig(CUsharedconfig* pConfig);
typedef CUresult CUDAAPI tcuCtxSetSharedMemConfig(CUsharedconfig config);
-typedef CUresult CUDAAPI tcuCtxGetApiVersion(CUcontext ctx, unsigned* version);
+typedef CUresult CUDAAPI tcuCtxGetApiVersion(CUcontext ctx, unsigned int* version);
typedef CUresult CUDAAPI tcuCtxGetStreamPriorityRange(int* leastPriority, int* greatestPriority);
-typedef CUresult CUDAAPI tcuCtxAttach(CUcontext* pctx, unsigned flags);
+typedef CUresult CUDAAPI tcuCtxAttach(CUcontext* pctx, unsigned int flags);
typedef CUresult CUDAAPI tcuCtxDetach(CUcontext ctx);
typedef CUresult CUDAAPI tcuModuleLoad(CUmodule* module, const char* fname);
typedef CUresult CUDAAPI tcuModuleLoadData(CUmodule* module, const void* image);
-typedef CUresult CUDAAPI tcuModuleLoadDataEx(CUmodule* module, const void* image, unsigned numOptions, CUjit_option* options, void* optionValues);
+typedef CUresult CUDAAPI tcuModuleLoadDataEx(CUmodule* module, const void* image, unsigned int numOptions, CUjit_option* options, void* optionValues);
typedef CUresult CUDAAPI tcuModuleLoadFatBinary(CUmodule* module, const void* fatCubin);
typedef CUresult CUDAAPI tcuModuleUnload(CUmodule hmod);
typedef CUresult CUDAAPI tcuModuleGetFunction(CUfunction* hfunc, CUmodule hmod, const char* name);
typedef CUresult CUDAAPI tcuModuleGetGlobal_v2(CUdeviceptr* dptr, size_t* bytes, CUmodule hmod, const char* name);
typedef CUresult CUDAAPI tcuModuleGetTexRef(CUtexref* pTexRef, CUmodule hmod, const char* name);
typedef CUresult CUDAAPI tcuModuleGetSurfRef(CUsurfref* pSurfRef, CUmodule hmod, const char* name);
-typedef CUresult CUDAAPI tcuLinkCreate_v2(unsigned numOptions, CUjit_option* options, void* optionValues, CUlinkState* stateOut);
-typedef CUresult CUDAAPI tcuLinkAddData_v2(CUlinkState state, CUjitInputType type, void* data, size_t size, const char* name, unsigned numOptions, CUjit_option* options, void* optionValues);
-typedef CUresult CUDAAPI tcuLinkAddFile_v2(CUlinkState state, CUjitInputType type, const char* path, unsigned numOptions, CUjit_option* options, void* optionValues);
+typedef CUresult CUDAAPI tcuLinkCreate_v2(unsigned int numOptions, CUjit_option* options, void* optionValues, CUlinkState* stateOut);
+typedef CUresult CUDAAPI tcuLinkAddData_v2(CUlinkState state, CUjitInputType type, void* data, size_t size, const char* name, unsigned int numOptions, CUjit_option* options, void* optionValues);
+typedef CUresult CUDAAPI tcuLinkAddFile_v2(CUlinkState state, CUjitInputType type, const char* path, unsigned int numOptions, CUjit_option* options, void* optionValues);
typedef CUresult CUDAAPI tcuLinkComplete(CUlinkState state, void* cubinOut, size_t* sizeOut);
typedef CUresult CUDAAPI tcuLinkDestroy(CUlinkState state);
typedef CUresult CUDAAPI tcuMemGetInfo_v2(size_t* free, size_t* total);
typedef CUresult CUDAAPI tcuMemAlloc_v2(CUdeviceptr* dptr, size_t bytesize);
-typedef CUresult CUDAAPI tcuMemAllocPitch_v2(CUdeviceptr* dptr, size_t* pPitch, size_t WidthInBytes, size_t Height, unsigned ElementSizeBytes);
+typedef CUresult CUDAAPI tcuMemAllocPitch_v2(CUdeviceptr* dptr, size_t* pPitch, size_t WidthInBytes, size_t Height, unsigned int ElementSizeBytes);
typedef CUresult CUDAAPI tcuMemFree_v2(CUdeviceptr dptr);
typedef CUresult CUDAAPI tcuMemGetAddressRange_v2(CUdeviceptr* pbase, size_t* psize, CUdeviceptr dptr);
typedef CUresult CUDAAPI tcuMemAllocHost_v2(void* pp, size_t bytesize);
typedef CUresult CUDAAPI tcuMemFreeHost(void* p);
-typedef CUresult CUDAAPI tcuMemHostAlloc(void* pp, size_t bytesize, unsigned Flags);
-typedef CUresult CUDAAPI tcuMemHostGetDevicePointer_v2(CUdeviceptr* pdptr, void* p, unsigned Flags);
-typedef CUresult CUDAAPI tcuMemHostGetFlags(unsigned* pFlags, void* p);
-typedef CUresult CUDAAPI tcuMemAllocManaged(CUdeviceptr* dptr, size_t bytesize, unsigned flags);
+typedef CUresult CUDAAPI tcuMemHostAlloc(void* pp, size_t bytesize, unsigned int Flags);
+typedef CUresult CUDAAPI tcuMemHostGetDevicePointer_v2(CUdeviceptr* pdptr, void* p, unsigned int Flags);
+typedef CUresult CUDAAPI tcuMemHostGetFlags(unsigned int* pFlags, void* p);
+typedef CUresult CUDAAPI tcuMemAllocManaged(CUdeviceptr* dptr, size_t bytesize, unsigned int flags);
typedef CUresult CUDAAPI tcuDeviceGetByPCIBusId(CUdevice* dev, const char* pciBusId);
typedef CUresult CUDAAPI tcuDeviceGetPCIBusId(char* pciBusId, int len, CUdevice dev);
typedef CUresult CUDAAPI tcuIpcGetEventHandle(CUipcEventHandle* pHandle, CUevent event);
typedef CUresult CUDAAPI tcuIpcOpenEventHandle(CUevent* phEvent, CUipcEventHandle handle);
typedef CUresult CUDAAPI tcuIpcGetMemHandle(CUipcMemHandle* pHandle, CUdeviceptr dptr);
-typedef CUresult CUDAAPI tcuIpcOpenMemHandle(CUdeviceptr* pdptr, CUipcMemHandle handle, unsigned Flags);
+typedef CUresult CUDAAPI tcuIpcOpenMemHandle(CUdeviceptr* pdptr, CUipcMemHandle handle, unsigned int Flags);
typedef CUresult CUDAAPI tcuIpcCloseMemHandle(CUdeviceptr dptr);
-typedef CUresult CUDAAPI tcuMemHostRegister_v2(void* p, size_t bytesize, unsigned Flags);
+typedef CUresult CUDAAPI tcuMemHostRegister_v2(void* p, size_t bytesize, unsigned int Flags);
typedef CUresult CUDAAPI tcuMemHostUnregister(void* p);
typedef CUresult CUDAAPI tcuMemcpy(CUdeviceptr dst, CUdeviceptr src, size_t ByteCount);
typedef CUresult CUDAAPI tcuMemcpyPeer(CUdeviceptr dstDevice, CUcontext dstContext, CUdeviceptr srcDevice, CUcontext srcContext, size_t ByteCount);
@@ -842,40 +842,40 @@ typedef CUresult CUDAAPI tcuMemcpyAtoHAsync_v2(void* dstHost, CUarray srcArray,
typedef CUresult CUDAAPI tcuMemcpy2DAsync_v2(const CUDA_MEMCPY2D* pCopy, CUstream hStream);
typedef CUresult CUDAAPI tcuMemcpy3DAsync_v2(const CUDA_MEMCPY3D* pCopy, CUstream hStream);
typedef CUresult CUDAAPI tcuMemcpy3DPeerAsync(const CUDA_MEMCPY3D_PEER* pCopy, CUstream hStream);
-typedef CUresult CUDAAPI tcuMemsetD8_v2(CUdeviceptr dstDevice, unsigned uc, size_t N);
-typedef CUresult CUDAAPI tcuMemsetD16_v2(CUdeviceptr dstDevice, unsigned us, size_t N);
-typedef CUresult CUDAAPI tcuMemsetD32_v2(CUdeviceptr dstDevice, unsigned ui, size_t N);
-typedef CUresult CUDAAPI tcuMemsetD2D8_v2(CUdeviceptr dstDevice, size_t dstPitch, unsigned uc, size_t Width, size_t Height);
-typedef CUresult CUDAAPI tcuMemsetD2D16_v2(CUdeviceptr dstDevice, size_t dstPitch, unsigned us, size_t Width, size_t Height);
-typedef CUresult CUDAAPI tcuMemsetD2D32_v2(CUdeviceptr dstDevice, size_t dstPitch, unsigned ui, size_t Width, size_t Height);
-typedef CUresult CUDAAPI tcuMemsetD8Async(CUdeviceptr dstDevice, unsigned uc, size_t N, CUstream hStream);
-typedef CUresult CUDAAPI tcuMemsetD16Async(CUdeviceptr dstDevice, unsigned us, size_t N, CUstream hStream);
-typedef CUresult CUDAAPI tcuMemsetD32Async(CUdeviceptr dstDevice, unsigned ui, size_t N, CUstream hStream);
-typedef CUresult CUDAAPI tcuMemsetD2D8Async(CUdeviceptr dstDevice, size_t dstPitch, unsigned uc, size_t Width, size_t Height, CUstream hStream);
-typedef CUresult CUDAAPI tcuMemsetD2D16Async(CUdeviceptr dstDevice, size_t dstPitch, unsigned us, size_t Width, size_t Height, CUstream hStream);
-typedef CUresult CUDAAPI tcuMemsetD2D32Async(CUdeviceptr dstDevice, size_t dstPitch, unsigned ui, size_t Width, size_t Height, CUstream hStream);
+typedef CUresult CUDAAPI tcuMemsetD8_v2(CUdeviceptr dstDevice, unsigned char uc, size_t N);
+typedef CUresult CUDAAPI tcuMemsetD16_v2(CUdeviceptr dstDevice, unsigned short us, size_t N);
+typedef CUresult CUDAAPI tcuMemsetD32_v2(CUdeviceptr dstDevice, unsigned int ui, size_t N);
+typedef CUresult CUDAAPI tcuMemsetD2D8_v2(CUdeviceptr dstDevice, size_t dstPitch, unsigned char uc, size_t Width, size_t Height);
+typedef CUresult CUDAAPI tcuMemsetD2D16_v2(CUdeviceptr dstDevice, size_t dstPitch, unsigned short us, size_t Width, size_t Height);
+typedef CUresult CUDAAPI tcuMemsetD2D32_v2(CUdeviceptr dstDevice, size_t dstPitch, unsigned int ui, size_t Width, size_t Height);
+typedef CUresult CUDAAPI tcuMemsetD8Async(CUdeviceptr dstDevice, unsigned char uc, size_t N, CUstream hStream);
+typedef CUresult CUDAAPI tcuMemsetD16Async(CUdeviceptr dstDevice, unsigned short us, size_t N, CUstream hStream);
+typedef CUresult CUDAAPI tcuMemsetD32Async(CUdeviceptr dstDevice, unsigned int ui, size_t N, CUstream hStream);
+typedef CUresult CUDAAPI tcuMemsetD2D8Async(CUdeviceptr dstDevice, size_t dstPitch, unsigned char uc, size_t Width, size_t Height, CUstream hStream);
+typedef CUresult CUDAAPI tcuMemsetD2D16Async(CUdeviceptr dstDevice, size_t dstPitch, unsigned short us, size_t Width, size_t Height, CUstream hStream);
+typedef CUresult CUDAAPI tcuMemsetD2D32Async(CUdeviceptr dstDevice, size_t dstPitch, unsigned int ui, size_t Width, size_t Height, CUstream hStream);
typedef CUresult CUDAAPI tcuArrayCreate_v2(CUarray* pHandle, const CUDA_ARRAY_DESCRIPTOR* pAllocateArray);
typedef CUresult CUDAAPI tcuArrayGetDescriptor_v2(CUDA_ARRAY_DESCRIPTOR* pArrayDescriptor, CUarray hArray);
typedef CUresult CUDAAPI tcuArrayDestroy(CUarray hArray);
typedef CUresult CUDAAPI tcuArray3DCreate_v2(CUarray* pHandle, const CUDA_ARRAY3D_DESCRIPTOR* pAllocateArray);
typedef CUresult CUDAAPI tcuArray3DGetDescriptor_v2(CUDA_ARRAY3D_DESCRIPTOR* pArrayDescriptor, CUarray hArray);
-typedef CUresult CUDAAPI tcuMipmappedArrayCreate(CUmipmappedArray* pHandle, const CUDA_ARRAY3D_DESCRIPTOR* pMipmappedArrayDesc, unsigned numMipmapLevels);
-typedef CUresult CUDAAPI tcuMipmappedArrayGetLevel(CUarray* pLevelArray, CUmipmappedArray hMipmappedArray, unsigned level);
+typedef CUresult CUDAAPI tcuMipmappedArrayCreate(CUmipmappedArray* pHandle, const CUDA_ARRAY3D_DESCRIPTOR* pMipmappedArrayDesc, unsigned int numMipmapLevels);
+typedef CUresult CUDAAPI tcuMipmappedArrayGetLevel(CUarray* pLevelArray, CUmipmappedArray hMipmappedArray, unsigned int level);
typedef CUresult CUDAAPI tcuMipmappedArrayDestroy(CUmipmappedArray hMipmappedArray);
typedef CUresult CUDAAPI tcuPointerGetAttribute(void* data, CUpointer_attribute attribute, CUdeviceptr ptr);
typedef CUresult CUDAAPI tcuPointerSetAttribute(const void* value, CUpointer_attribute attribute, CUdeviceptr ptr);
-typedef CUresult CUDAAPI tcuPointerGetAttributes(unsigned numAttributes, CUpointer_attribute* attributes, void* data, CUdeviceptr ptr);
-typedef CUresult CUDAAPI tcuStreamCreate(CUstream* phStream, unsigned Flags);
-typedef CUresult CUDAAPI tcuStreamCreateWithPriority(CUstream* phStream, unsigned flags, int priority);
+typedef CUresult CUDAAPI tcuPointerGetAttributes(unsigned int numAttributes, CUpointer_attribute* attributes, void* data, CUdeviceptr ptr);
+typedef CUresult CUDAAPI tcuStreamCreate(CUstream* phStream, unsigned int Flags);
+typedef CUresult CUDAAPI tcuStreamCreateWithPriority(CUstream* phStream, unsigned int flags, int priority);
typedef CUresult CUDAAPI tcuStreamGetPriority(CUstream hStream, int* priority);
-typedef CUresult CUDAAPI tcuStreamGetFlags(CUstream hStream, unsigned* flags);
-typedef CUresult CUDAAPI tcuStreamWaitEvent(CUstream hStream, CUevent hEvent, unsigned Flags);
-typedef CUresult CUDAAPI tcuStreamAddCallback(CUstream hStream, CUstreamCallback callback, void* userData, unsigned flags);
-typedef CUresult CUDAAPI tcuStreamAttachMemAsync(CUstream hStream, CUdeviceptr dptr, size_t length, unsigned flags);
+typedef CUresult CUDAAPI tcuStreamGetFlags(CUstream hStream, unsigned int* flags);
+typedef CUresult CUDAAPI tcuStreamWaitEvent(CUstream hStream, CUevent hEvent, unsigned int Flags);
+typedef CUresult CUDAAPI tcuStreamAddCallback(CUstream hStream, CUstreamCallback callback, void* userData, unsigned int flags);
+typedef CUresult CUDAAPI tcuStreamAttachMemAsync(CUstream hStream, CUdeviceptr dptr, size_t length, unsigned int flags);
typedef CUresult CUDAAPI tcuStreamQuery(CUstream hStream);
typedef CUresult CUDAAPI tcuStreamSynchronize(CUstream hStream);
typedef CUresult CUDAAPI tcuStreamDestroy_v2(CUstream hStream);
-typedef CUresult CUDAAPI tcuEventCreate(CUevent* phEvent, unsigned Flags);
+typedef CUresult CUDAAPI tcuEventCreate(CUevent* phEvent, unsigned int Flags);
typedef CUresult CUDAAPI tcuEventRecord(CUevent hEvent, CUstream hStream);
typedef CUresult CUDAAPI tcuEventQuery(CUevent hEvent);
typedef CUresult CUDAAPI tcuEventSynchronize(CUevent hEvent);
@@ -884,23 +884,23 @@ typedef CUresult CUDAAPI tcuEventElapsedTime(float* pMilliseconds, CUevent hStar
typedef CUresult CUDAAPI tcuFuncGetAttribute(int* pi, CUfunction_attribute attrib, CUfunction hfunc);
typedef CUresult CUDAAPI tcuFuncSetCacheConfig(CUfunction hfunc, CUfunc_cache config);
typedef CUresult CUDAAPI tcuFuncSetSharedMemConfig(CUfunction hfunc, CUsharedconfig config);
-typedef CUresult CUDAAPI tcuLaunchKernel(CUfunction f, unsigned gridDimX, unsigned gridDimY, unsigned gridDimZ, unsigned blockDimX, unsigned blockDimY, unsigned blockDimZ, unsigned sharedMemBytes, CUstream hStream, void* kernelParams, void* extra);
+typedef CUresult CUDAAPI tcuLaunchKernel(CUfunction f, unsigned int gridDimX, unsigned int gridDimY, unsigned int gridDimZ, unsigned int blockDimX, unsigned int blockDimY, unsigned int blockDimZ, unsigned int sharedMemBytes, CUstream hStream, void* kernelParams, void* extra);
typedef CUresult CUDAAPI tcuFuncSetBlockShape(CUfunction hfunc, int x, int y, int z);
-typedef CUresult CUDAAPI tcuFuncSetSharedSize(CUfunction hfunc, unsigned bytes);
-typedef CUresult CUDAAPI tcuParamSetSize(CUfunction hfunc, unsigned numbytes);
-typedef CUresult CUDAAPI tcuParamSeti(CUfunction hfunc, int offset, unsigned value);
+typedef CUresult CUDAAPI tcuFuncSetSharedSize(CUfunction hfunc, unsigned int bytes);
+typedef CUresult CUDAAPI tcuParamSetSize(CUfunction hfunc, unsigned int numbytes);
+typedef CUresult CUDAAPI tcuParamSeti(CUfunction hfunc, int offset, unsigned int value);
typedef CUresult CUDAAPI tcuParamSetf(CUfunction hfunc, int offset, float value);
-typedef CUresult CUDAAPI tcuParamSetv(CUfunction hfunc, int offset, void* ptr, unsigned numbytes);
+typedef CUresult CUDAAPI tcuParamSetv(CUfunction hfunc, int offset, void* ptr, unsigned int numbytes);
typedef CUresult CUDAAPI tcuLaunch(CUfunction f);
typedef CUresult CUDAAPI tcuLaunchGrid(CUfunction f, int grid_width, int grid_height);
typedef CUresult CUDAAPI tcuLaunchGridAsync(CUfunction f, int grid_width, int grid_height, CUstream hStream);
typedef CUresult CUDAAPI tcuParamSetTexRef(CUfunction hfunc, int texunit, CUtexref hTexRef);
typedef CUresult CUDAAPI tcuOccupancyMaxActiveBlocksPerMultiprocessor(int* numBlocks, CUfunction func, int blockSize, size_t dynamicSMemSize);
-typedef CUresult CUDAAPI tcuOccupancyMaxActiveBlocksPerMultiprocessorWithFlags(int* numBlocks, CUfunction func, int blockSize, size_t dynamicSMemSize, unsigned flags);
+typedef CUresult CUDAAPI tcuOccupancyMaxActiveBlocksPerMultiprocessorWithFlags(int* numBlocks, CUfunction func, int blockSize, size_t dynamicSMemSize, unsigned int flags);
typedef CUresult CUDAAPI tcuOccupancyMaxPotentialBlockSize(int* minGridSize, int* blockSize, CUfunction func, CUoccupancyB2DSize blockSizeToDynamicSMemSize, size_t dynamicSMemSize, int blockSizeLimit);
-typedef CUresult CUDAAPI tcuOccupancyMaxPotentialBlockSizeWithFlags(int* minGridSize, int* blockSize, CUfunction func, CUoccupancyB2DSize blockSizeToDynamicSMemSize, size_t dynamicSMemSize, int blockSizeLimit, unsigned flags);
-typedef CUresult CUDAAPI tcuTexRefSetArray(CUtexref hTexRef, CUarray hArray, unsigned Flags);
-typedef CUresult CUDAAPI tcuTexRefSetMipmappedArray(CUtexref hTexRef, CUmipmappedArray hMipmappedArray, unsigned Flags);
+typedef CUresult CUDAAPI tcuOccupancyMaxPotentialBlockSizeWithFlags(int* minGridSize, int* blockSize, CUfunction func, CUoccupancyB2DSize blockSizeToDynamicSMemSize, size_t dynamicSMemSize, int blockSizeLimit, unsigned int flags);
+typedef CUresult CUDAAPI tcuTexRefSetArray(CUtexref hTexRef, CUarray hArray, unsigned int Flags);
+typedef CUresult CUDAAPI tcuTexRefSetMipmappedArray(CUtexref hTexRef, CUmipmappedArray hMipmappedArray, unsigned int Flags);
typedef CUresult CUDAAPI tcuTexRefSetAddress_v2(size_t* ByteOffset, CUtexref hTexRef, CUdeviceptr dptr, size_t bytes);
typedef CUresult CUDAAPI tcuTexRefSetAddress2D_v3(CUtexref hTexRef, const CUDA_ARRAY_DESCRIPTOR* desc, CUdeviceptr dptr, size_t Pitch);
typedef CUresult CUDAAPI tcuTexRefSetFormat(CUtexref hTexRef, CUarray_format fmt, int NumPackedComponents);
@@ -909,8 +909,8 @@ typedef CUresult CUDAAPI tcuTexRefSetFilterMode(CUtexref hTexRef, CUfilter_mode
typedef CUresult CUDAAPI tcuTexRefSetMipmapFilterMode(CUtexref hTexRef, CUfilter_mode fm);
typedef CUresult CUDAAPI tcuTexRefSetMipmapLevelBias(CUtexref hTexRef, float bias);
typedef CUresult CUDAAPI tcuTexRefSetMipmapLevelClamp(CUtexref hTexRef, float minMipmapLevelClamp, float maxMipmapLevelClamp);
-typedef CUresult CUDAAPI tcuTexRefSetMaxAnisotropy(CUtexref hTexRef, unsigned maxAniso);
-typedef CUresult CUDAAPI tcuTexRefSetFlags(CUtexref hTexRef, unsigned Flags);
+typedef CUresult CUDAAPI tcuTexRefSetMaxAnisotropy(CUtexref hTexRef, unsigned int maxAniso);
+typedef CUresult CUDAAPI tcuTexRefSetFlags(CUtexref hTexRef, unsigned int Flags);
typedef CUresult CUDAAPI tcuTexRefGetAddress_v2(CUdeviceptr* pdptr, CUtexref hTexRef);
typedef CUresult CUDAAPI tcuTexRefGetArray(CUarray* phArray, CUtexref hTexRef);
typedef CUresult CUDAAPI tcuTexRefGetMipmappedArray(CUmipmappedArray* phMipmappedArray, CUtexref hTexRef);
@@ -921,10 +921,10 @@ typedef CUresult CUDAAPI tcuTexRefGetMipmapFilterMode(CUfilter_mode* pfm, CUtexr
typedef CUresult CUDAAPI tcuTexRefGetMipmapLevelBias(float* pbias, CUtexref hTexRef);
typedef CUresult CUDAAPI tcuTexRefGetMipmapLevelClamp(float* pminMipmapLevelClamp, float* pmaxMipmapLevelClamp, CUtexref hTexRef);
typedef CUresult CUDAAPI tcuTexRefGetMaxAnisotropy(int* pmaxAniso, CUtexref hTexRef);
-typedef CUresult CUDAAPI tcuTexRefGetFlags(unsigned* pFlags, CUtexref hTexRef);
+typedef CUresult CUDAAPI tcuTexRefGetFlags(unsigned int* pFlags, CUtexref hTexRef);
typedef CUresult CUDAAPI tcuTexRefCreate(CUtexref* pTexRef);
typedef CUresult CUDAAPI tcuTexRefDestroy(CUtexref hTexRef);
-typedef CUresult CUDAAPI tcuSurfRefSetArray(CUsurfref hSurfRef, CUarray hArray, unsigned Flags);
+typedef CUresult CUDAAPI tcuSurfRefSetArray(CUsurfref hSurfRef, CUarray hArray, unsigned int Flags);
typedef CUresult CUDAAPI tcuSurfRefGetArray(CUarray* phArray, CUsurfref hSurfRef);
typedef CUresult CUDAAPI tcuTexObjectCreate(CUtexObject* pTexObject, const CUDA_RESOURCE_DESC* pResDesc, const CUDA_TEXTURE_DESC* pTexDesc, const CUDA_RESOURCE_VIEW_DESC* pResViewDesc);
typedef CUresult CUDAAPI tcuTexObjectDestroy(CUtexObject texObject);
@@ -935,27 +935,27 @@ typedef CUresult CUDAAPI tcuSurfObjectCreate(CUsurfObject* pSurfObject, const CU
typedef CUresult CUDAAPI tcuSurfObjectDestroy(CUsurfObject surfObject);
typedef CUresult CUDAAPI tcuSurfObjectGetResourceDesc(CUDA_RESOURCE_DESC* pResDesc, CUsurfObject surfObject);
typedef CUresult CUDAAPI tcuDeviceCanAccessPeer(int* canAccessPeer, CUdevice dev, CUdevice peerDev);
-typedef CUresult CUDAAPI tcuCtxEnablePeerAccess(CUcontext peerContext, unsigned Flags);
+typedef CUresult CUDAAPI tcuCtxEnablePeerAccess(CUcontext peerContext, unsigned int Flags);
typedef CUresult CUDAAPI tcuCtxDisablePeerAccess(CUcontext peerContext);
typedef CUresult CUDAAPI tcuGraphicsUnregisterResource(CUgraphicsResource resource);
-typedef CUresult CUDAAPI tcuGraphicsSubResourceGetMappedArray(CUarray* pArray, CUgraphicsResource resource, unsigned arrayIndex, unsigned mipLevel);
+typedef CUresult CUDAAPI tcuGraphicsSubResourceGetMappedArray(CUarray* pArray, CUgraphicsResource resource, unsigned int arrayIndex, unsigned int mipLevel);
typedef CUresult CUDAAPI tcuGraphicsResourceGetMappedMipmappedArray(CUmipmappedArray* pMipmappedArray, CUgraphicsResource resource);
typedef CUresult CUDAAPI tcuGraphicsResourceGetMappedPointer_v2(CUdeviceptr* pDevPtr, size_t* pSize, CUgraphicsResource resource);
-typedef CUresult CUDAAPI tcuGraphicsResourceSetMapFlags_v2(CUgraphicsResource resource, unsigned flags);
-typedef CUresult CUDAAPI tcuGraphicsMapResources(unsigned count, CUgraphicsResource* resources, CUstream hStream);
-typedef CUresult CUDAAPI tcuGraphicsUnmapResources(unsigned count, CUgraphicsResource* resources, CUstream hStream);
+typedef CUresult CUDAAPI tcuGraphicsResourceSetMapFlags_v2(CUgraphicsResource resource, unsigned int flags);
+typedef CUresult CUDAAPI tcuGraphicsMapResources(unsigned int count, CUgraphicsResource* resources, CUstream hStream);
+typedef CUresult CUDAAPI tcuGraphicsUnmapResources(unsigned int count, CUgraphicsResource* resources, CUstream hStream);
typedef CUresult CUDAAPI tcuGetExportTable(const void* ppExportTable, const CUuuid* pExportTableId);
-typedef CUresult CUDAAPI tcuGraphicsGLRegisterBuffer(CUgraphicsResource* pCudaResource, GLuint buffer, unsigned Flags);
-typedef CUresult CUDAAPI tcuGraphicsGLRegisterImage(CUgraphicsResource* pCudaResource, GLuint image, GLenum target, unsigned Flags);
-typedef CUresult CUDAAPI tcuGLGetDevices_v2(unsigned* pCudaDeviceCount, CUdevice* pCudaDevices, unsigned cudaDeviceCount, CUGLDeviceList deviceList);
-typedef CUresult CUDAAPI tcuGLCtxCreate_v2(CUcontext* pCtx, unsigned Flags, CUdevice device);
+typedef CUresult CUDAAPI tcuGraphicsGLRegisterBuffer(CUgraphicsResource* pCudaResource, GLuint buffer, unsigned int Flags);
+typedef CUresult CUDAAPI tcuGraphicsGLRegisterImage(CUgraphicsResource* pCudaResource, GLuint image, GLenum target, unsigned int Flags);
+typedef CUresult CUDAAPI tcuGLGetDevices_v2(unsigned int* pCudaDeviceCount, CUdevice* pCudaDevices, unsigned int cudaDeviceCount, CUGLDeviceList deviceList);
+typedef CUresult CUDAAPI tcuGLCtxCreate_v2(CUcontext* pCtx, unsigned int Flags, CUdevice device);
typedef CUresult CUDAAPI tcuGLInit(void);
typedef CUresult CUDAAPI tcuGLRegisterBufferObject(GLuint buffer);
typedef CUresult CUDAAPI tcuGLMapBufferObject_v2(CUdeviceptr* dptr, size_t* size, GLuint buffer);
typedef CUresult CUDAAPI tcuGLUnmapBufferObject(GLuint buffer);
typedef CUresult CUDAAPI tcuGLUnregisterBufferObject(GLuint buffer);
-typedef CUresult CUDAAPI tcuGLSetBufferObjectMapFlags(GLuint buffer, unsigned Flags);
+typedef CUresult CUDAAPI tcuGLSetBufferObjectMapFlags(GLuint buffer, unsigned int Flags);
typedef CUresult CUDAAPI tcuGLMapBufferObjectAsync_v2(CUdeviceptr* dptr, size_t* size, GLuint buffer, CUstream hStream);
typedef CUresult CUDAAPI tcuGLUnmapBufferObjectAsync(GLuint buffer, CUstream hStream);
diff --git a/extern/curve_fit_nd/CMakeLists.txt b/extern/curve_fit_nd/CMakeLists.txt
index 6669971aa2d..cc9efe1c470 100644
--- a/extern/curve_fit_nd/CMakeLists.txt
+++ b/extern/curve_fit_nd/CMakeLists.txt
@@ -26,10 +26,14 @@ set(INC_SYS
set(SRC
intern/curve_fit_cubic.c
+ intern/curve_fit_cubic_refit.c
intern/curve_fit_corners_detect.c
- intern/curve_fit_inline.h
curve_fit_nd.h
+ intern/curve_fit_inline.h
+ intern/generic_alloc_impl.h
+ intern/generic_heap.c
+ intern/generic_heap.h
)
blender_add_lib(extern_curve_fit_nd "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/extern/curve_fit_nd/README.blender b/extern/curve_fit_nd/README.blender
new file mode 100644
index 00000000000..db520ea524e
--- /dev/null
+++ b/extern/curve_fit_nd/README.blender
@@ -0,0 +1,5 @@
+Project: Curve-Fit-nD
+URL: https://github.com/ideasman42/curve-fit-nd
+License: BSD 3-Clause
+Upstream version: Unknown (Last Release)
+Local modifications: None
diff --git a/extern/curve_fit_nd/curve_fit_nd.h b/extern/curve_fit_nd/curve_fit_nd.h
index ff6b9513a9b..cfb1881fe00 100644
--- a/extern/curve_fit_nd/curve_fit_nd.h
+++ b/extern/curve_fit_nd/curve_fit_nd.h
@@ -60,6 +60,7 @@ int curve_fit_cubic_to_points_db(
const unsigned int points_len,
const unsigned int dims,
const double error_threshold,
+ const unsigned int calc_flag,
const unsigned int *corners,
unsigned int corners_len,
@@ -72,6 +73,7 @@ int curve_fit_cubic_to_points_fl(
const unsigned int points_len,
const unsigned int dims,
const float error_threshold,
+ const unsigned int calc_flag,
const unsigned int *corners,
const unsigned int corners_len,
@@ -84,6 +86,7 @@ int curve_fit_cubic_to_points_fl(
*
* \param points, points_len: The array of points to calculate a cubics from.
* \param dims: The number of dimensions for for each element in \a points.
+ * \param points_length_cache: Optional pre-calculated lengths between points.
* \param error_threshold: the error threshold to allow for,
* \param tan_l, tan_r: Normalized tangents the handles will be aligned to.
* Note that tangents must both point along the direction of the \a points,
@@ -96,6 +99,7 @@ int curve_fit_cubic_to_points_fl(
int curve_fit_cubic_to_points_single_db(
const double *points,
const unsigned int points_len,
+ const double *points_length_cache,
const unsigned int dims,
const double error_threshold,
const double tan_l[],
@@ -108,6 +112,7 @@ int curve_fit_cubic_to_points_single_db(
int curve_fit_cubic_to_points_single_fl(
const float *points,
const unsigned int points_len,
+ const float *points_length_cache,
const unsigned int dims,
const float error_threshold,
const float tan_l[],
@@ -117,6 +122,42 @@ int curve_fit_cubic_to_points_single_fl(
float r_handle_r[],
float *r_error_sq);
+enum {
+ CURVE_FIT_CALC_HIGH_QUALIY = (1 << 0),
+ CURVE_FIT_CALC_CYCLIC = (1 << 1),
+};
+
+
+/* curve_fit_cubic_refit.c */
+
+int curve_fit_cubic_to_points_refit_db(
+ const double *points,
+ const unsigned int points_len,
+ const unsigned int dims,
+ const double error_threshold,
+ const unsigned int calc_flag,
+ const unsigned int *corners,
+ unsigned int corners_len,
+ const double corner_angle,
+
+ double **r_cubic_array, unsigned int *r_cubic_array_len,
+ unsigned int **r_cubic_orig_index,
+ unsigned int **r_corner_index_array, unsigned int *r_corner_index_len);
+
+int curve_fit_cubic_to_points_refit_fl(
+ const float *points,
+ const unsigned int points_len,
+ const unsigned int dims,
+ const float error_threshold,
+ const unsigned int calc_flag,
+ const unsigned int *corners,
+ unsigned int corners_len,
+ const float corner_angle,
+
+ float **r_cubic_array, unsigned int *r_cubic_array_len,
+ unsigned int **r_cubic_orig_index,
+ unsigned int **r_corner_index_array, unsigned int *r_corner_index_len);
+
/* curve_fit_corners_detect.c */
/**
diff --git a/extern/curve_fit_nd/intern/curve_fit_cubic.c b/extern/curve_fit_nd/intern/curve_fit_cubic.c
index b97763460a3..0a32f1e796a 100644
--- a/extern/curve_fit_nd/intern/curve_fit_cubic.c
+++ b/extern/curve_fit_nd/intern/curve_fit_cubic.c
@@ -46,6 +46,12 @@
/* Take curvature into account when calculating the least square solution isn't usable. */
#define USE_CIRCULAR_FALLBACK
+/* Use the maximum distance of any points from the direct line between 2 points
+ * to calculate how long the handles need to be.
+ * Can do a 'perfect' reversal of subdivision when for curve has symmetrical handles and doesn't change direction
+ * (as with an 'S' shape). */
+#define USE_OFFSET_FALLBACK
+
/* avoid re-calculating lengths multiple times */
#define USE_LENGTH_CACHE
@@ -249,7 +255,7 @@ static void cubic_list_clear(CubicList *clist)
/** \name Cubic Evaluation
* \{ */
-static void cubic_evaluate(
+static void cubic_calc_point(
const Cubic *cubic, const double t, const uint dims,
double r_v[])
{
@@ -265,18 +271,6 @@ static void cubic_evaluate(
}
}
-static void cubic_calc_point(
- const Cubic *cubic, const double t, const uint dims,
- double r_v[])
-{
- CUBIC_VARS_CONST(cubic, dims, p0, p1, p2, p3);
- const double s = 1.0 - t;
- for (uint j = 0; j < dims; j++) {
- r_v[j] = p0[j] * s * s * s +
- 3.0 * t * s * (s * p1[j] + t * p2[j]) + t * t * t * p3[j];
- }
-}
-
static void cubic_calc_speed(
const Cubic *cubic, const double t, const uint dims,
double r_v[])
@@ -326,7 +320,7 @@ static double cubic_calc_error(
#endif
for (uint i = 1; i < points_offset_len - 1; i++, pt_real += dims) {
- cubic_evaluate(cubic, u[i], dims, pt_eval);
+ cubic_calc_point(cubic, u[i], dims, pt_eval);
const double err_sq = len_squared_vnvn(pt_real, pt_eval, dims);
if (err_sq >= error_max_sq) {
@@ -339,6 +333,44 @@ static double cubic_calc_error(
return error_max_sq;
}
+#ifdef USE_OFFSET_FALLBACK
+/**
+ * A version #cubic_calc_error where we don't need the split-index and can exit early when over the limit.
+ */
+static double cubic_calc_error_simple(
+ const Cubic *cubic,
+ const double *points_offset,
+ const uint points_offset_len,
+ const double *u,
+ const double error_threshold_sq,
+ const uint dims)
+
+{
+ double error_max_sq = 0.0;
+
+ const double *pt_real = points_offset + dims;
+#ifdef USE_VLA
+ double pt_eval[dims];
+#else
+ double *pt_eval = alloca(sizeof(double) * dims);
+#endif
+
+ for (uint i = 1; i < points_offset_len - 1; i++, pt_real += dims) {
+ cubic_calc_point(cubic, u[i], dims, pt_eval);
+
+ const double err_sq = len_squared_vnvn(pt_real, pt_eval, dims);
+ if (err_sq >= error_threshold_sq) {
+ return error_threshold_sq;
+ }
+ else if (err_sq >= error_max_sq) {
+ error_max_sq = err_sq;
+ }
+ }
+
+ return error_max_sq;
+}
+#endif
+
/**
* Bezier multipliers
*/
@@ -429,14 +461,45 @@ static double points_calc_circumference_factor(
* (tangents that point away from each other).
* We could try support this but will likely cause extreme >1 scales which could cause other issues. */
// assert(angle >= len_tangent);
- double factor = (angle / len_tangent) / (M_PI / 2);
- factor = 1.0 - pow(1.0 - factor, 1.75);
- assert(factor < 1.0 + DBL_EPSILON);
+ double factor = (angle / len_tangent);
+ assert(factor < (M_PI / 2) + (DBL_EPSILON * 10));
return factor;
}
else {
/* tangents are exactly aligned (think two opposite sides of a circle). */
- return 1.0;
+ return (M_PI / 2);
+ }
+}
+
+/**
+ * Return the value which the distance between points will need to be scaled by,
+ * to define a handle, given both points are on a perfect circle.
+ *
+ * \note the return value will need to be multiplied by 1.3... for correct results.
+ */
+static double points_calc_circle_tangent_factor(
+ const double tan_l[],
+ const double tan_r[],
+ const uint dims)
+{
+ const double eps = 1e-8;
+ const double tan_dot = dot_vnvn(tan_l, tan_r, dims);
+ if (tan_dot > 1.0 - eps) {
+ /* no angle difference (use fallback, length wont make any difference) */
+ return (1.0 / 3.0) * 0.75;
+ }
+ else if (tan_dot < -1.0 + eps) {
+ /* parallel tangents (half-circle) */
+ return (1.0 / 2.0);
+ }
+ else {
+ /* non-aligned tangents, calculate handle length */
+ const double angle = acos(tan_dot) / 2.0;
+
+ /* could also use 'angle_sin = len_vnvn(tan_l, tan_r, dims) / 2.0' */
+ const double angle_sin = sin(angle);
+ const double angle_cos = cos(angle);
+ return ((1.0 - angle_cos) / (angle_sin * 2.0)) / angle_sin;
}
}
@@ -451,9 +514,20 @@ static double points_calc_cubic_scale(
const double coords_length, uint dims)
{
const double len_direct = len_vnvn(v_l, v_r, dims);
- const double len_circle_factor = points_calc_circumference_factor(tan_l, tan_r, dims) * 1.75;
- const double len_points = min(coords_length, len_circle_factor * len_direct);
- return (len_direct + ((len_points - len_direct) * len_circle_factor)) / 3.0;
+ const double len_circle_factor = points_calc_circle_tangent_factor(tan_l, tan_r, dims);
+
+ /* if this curve is a circle, this value doesn't need modification */
+ const double len_circle_handle = (len_direct * (len_circle_factor / 0.75));
+
+ /* scale by the difference from the circumference distance */
+ const double len_circle = len_direct * points_calc_circumference_factor(tan_l, tan_r, dims);
+ double scale_handle = (coords_length / len_circle);
+
+ /* Could investigate an accurate calculation here,
+ * though this gives close results */
+ scale_handle = ((scale_handle - 1.0) * 1.75) + 1.0;
+
+ return len_circle_handle * scale_handle;
}
static void cubic_from_points_fallback(
@@ -488,6 +562,85 @@ static void cubic_from_points_fallback(
}
#endif /* USE_CIRCULAR_FALLBACK */
+
+#ifdef USE_OFFSET_FALLBACK
+
+static void cubic_from_points_offset_fallback(
+ const double *points_offset,
+ const uint points_offset_len,
+ const double tan_l[],
+ const double tan_r[],
+ const uint dims,
+
+ Cubic *r_cubic)
+{
+ const double *p0 = &points_offset[0];
+ const double *p3 = &points_offset[(points_offset_len - 1) * dims];
+
+#ifdef USE_VLA
+ double dir_unit[dims];
+ double a[2][dims];
+ double tmp[dims];
+#else
+ double *dir_unit = alloca(sizeof(double) * dims);
+ double *a[2] = {
+ alloca(sizeof(double) * dims),
+ alloca(sizeof(double) * dims),
+ };
+ double *tmp = alloca(sizeof(double) * dims);
+#endif
+
+ const double dir_dist = normalize_vn_vnvn(dir_unit, p3, p0, dims);
+ project_plane_vn_vnvn_normalized(a[0], tan_l, dir_unit, dims);
+ project_plane_vn_vnvn_normalized(a[1], tan_r, dir_unit, dims);
+
+ /* only for better accuracy, not essential */
+ normalize_vn(a[0], dims);
+ normalize_vn(a[1], dims);
+
+ mul_vnvn_fl(a[1], a[1], -1, dims);
+
+ double dists[2] = {0, 0};
+
+ const double *pt = &points_offset[dims];
+ for (uint i = 1; i < points_offset_len - 1; i++, pt += dims) {
+ for (uint k = 0; k < 2; k++) {
+ sub_vn_vnvn(tmp, p0, pt, dims);
+ project_vn_vnvn_normalized(tmp, tmp, a[k], dims);
+ dists[k] = max(dists[k], dot_vnvn(tmp, a[k], dims));
+ }
+ }
+
+ double alpha_l = (dists[0] / 0.75) / fabs(dot_vnvn(tan_l, a[0], dims));
+ double alpha_r = (dists[1] / 0.75) / fabs(dot_vnvn(tan_r, a[1], dims));
+
+ if (!(alpha_l > 0.0)) {
+ alpha_l = dir_dist / 3.0;
+ }
+ if (!(alpha_r > 0.0)) {
+ alpha_r = dir_dist / 3.0;
+ }
+
+ double *p1 = CUBIC_PT(r_cubic, 1, dims);
+ double *p2 = CUBIC_PT(r_cubic, 2, dims);
+
+ copy_vnvn(CUBIC_PT(r_cubic, 0, dims), p0, dims);
+ copy_vnvn(CUBIC_PT(r_cubic, 3, dims), p3, dims);
+
+#ifdef USE_ORIG_INDEX_DATA
+ r_cubic->orig_span = (points_offset_len - 1);
+#endif
+
+ /* p1 = p0 - (tan_l * alpha_l);
+ * p2 = p3 + (tan_r * alpha_r);
+ */
+ msub_vn_vnvn_fl(p1, p0, tan_l, alpha_l, dims);
+ madd_vn_vnvn_fl(p2, p3, tan_r, alpha_r, dims);
+}
+
+#endif /* USE_OFFSET_FALLBACK */
+
+
/**
* Use least-squares method to find Bezier control points for region.
*/
@@ -512,13 +665,11 @@ static void cubic_from_points(
double alpha_l, alpha_r;
#ifdef USE_VLA
double a[2][dims];
- double tmp[dims];
#else
double *a[2] = {
alloca(sizeof(double) * dims),
alloca(sizeof(double) * dims),
};
- double *tmp = alloca(sizeof(double) * dims);
#endif
{
@@ -529,22 +680,22 @@ static void cubic_from_points(
mul_vnvn_fl(a[0], tan_l, B1(u_prime[i]), dims);
mul_vnvn_fl(a[1], tan_r, B2(u_prime[i]), dims);
- c[0][0] += dot_vnvn(a[0], a[0], dims);
- c[0][1] += dot_vnvn(a[0], a[1], dims);
- c[1][1] += dot_vnvn(a[1], a[1], dims);
+ const double b0_plus_b1 = B0plusB1(u_prime[i]);
+ const double b2_plus_b3 = B2plusB3(u_prime[i]);
- c[1][0] = c[0][1];
+ /* inline dot product */
+ for (uint j = 0; j < dims; j++) {
+ const double tmp = (pt[j] - (p0[j] * b0_plus_b1)) + (p3[j] * b2_plus_b3);
- {
- const double b0_plus_b1 = B0plusB1(u_prime[i]);
- const double b2_plus_b3 = B2plusB3(u_prime[i]);
- for (uint j = 0; j < dims; j++) {
- tmp[j] = (pt[j] - (p0[j] * b0_plus_b1)) + (p3[j] * b2_plus_b3);
- }
+ x[0] += a[0][j] * tmp;
+ x[1] += a[1][j] * tmp;
- x[0] += dot_vnvn(a[0], tmp, dims);
- x[1] += dot_vnvn(a[1], tmp, dims);
+ c[0][0] += a[0][j] * a[0][j];
+ c[0][1] += a[0][j] * a[1][j];
+ c[1][1] += a[1][j] * a[1][j];
}
+
+ c[1][0] = c[0][1];
}
double det_C0_C1 = c[0][0] * c[1][1] - c[0][1] * c[1][0];
@@ -577,7 +728,11 @@ static void cubic_from_points(
!(alpha_r >= 0.0))
{
#ifdef USE_CIRCULAR_FALLBACK
- alpha_l = alpha_r = points_calc_cubic_scale(p0, p3, tan_l, tan_r, points_offset_coords_length, dims);
+ double alpha_test = points_calc_cubic_scale(p0, p3, tan_l, tan_r, points_offset_coords_length, dims);
+ if (!isfinite(alpha_test)) {
+ alpha_test = len_vnvn(p0, p3, dims) / 3.0;
+ }
+ alpha_l = alpha_r = alpha_test;
#else
alpha_l = alpha_r = len_vnvn(p0, p3, dims) / 3.0;
#endif
@@ -639,7 +794,11 @@ static void cubic_from_points(
p2_dist_sq > dist_sq_max)
{
#ifdef USE_CIRCULAR_FALLBACK
- alpha_l = alpha_r = points_calc_cubic_scale(p0, p3, tan_l, tan_r, points_offset_coords_length, dims);
+ double alpha_test = points_calc_cubic_scale(p0, p3, tan_l, tan_r, points_offset_coords_length, dims);
+ if (!isfinite(alpha_test)) {
+ alpha_test = len_vnvn(p0, p3, dims) / 3.0;
+ }
+ alpha_l = alpha_r = alpha_test;
#else
alpha_l = alpha_r = len_vnvn(p0, p3, dims) / 3.0;
#endif
@@ -711,7 +870,6 @@ static double points_calc_coord_length(
#ifdef USE_LENGTH_CACHE
length = points_length_cache[i];
-
assert(len_vnvn(pt, pt_prev, dims) == points_length_cache[i]);
#else
length = len_vnvn(pt, pt_prev, dims);
@@ -724,7 +882,7 @@ static double points_calc_coord_length(
}
assert(!is_almost_zero(r_u[points_offset_len - 1]));
const double w = r_u[points_offset_len - 1];
- for (uint i = 0; i < points_offset_len; i++) {
+ for (uint i = 1; i < points_offset_len; i++) {
r_u[i] /= w;
}
return w;
@@ -876,6 +1034,8 @@ static bool fit_cubic_to_points(
Cubic *cubic_test = alloca(cubic_alloc_size(dims));
+ /* Run this so we use the non-circular calculation when the circular-fallback
+ * in 'cubic_from_points' failed to give a close enough result. */
#ifdef USE_CIRCULAR_FALLBACK
if (!(error_max_sq < error_threshold_sq)) {
/* Don't use the cubic calculated above, instead calculate a new fallback cubic,
@@ -898,14 +1058,28 @@ static bool fit_cubic_to_points(
}
#endif
+ /* Test the offset fallback */
+#ifdef USE_OFFSET_FALLBACK
+ if (!(error_max_sq < error_threshold_sq)) {
+ /* Using the offset from the curve to calculate cubic handle length may give better results
+ * try this as a second fallback. */
+ cubic_from_points_offset_fallback(
+ points_offset, points_offset_len,
+ tan_l, tan_r, dims, cubic_test);
+ const double error_max_sq_test = cubic_calc_error_simple(
+ cubic_test, points_offset, points_offset_len, u, error_max_sq, dims);
+
+ if (error_max_sq > error_max_sq_test) {
+ error_max_sq = error_max_sq_test;
+ cubic_copy(r_cubic, cubic_test, dims);
+ }
+ }
+#endif
+
*r_error_max_sq = error_max_sq;
*r_split_index = split_index;
- if (error_max_sq < error_threshold_sq) {
- free(u);
- return true;
- }
- else {
+ if (!(error_max_sq < error_threshold_sq)) {
cubic_copy(cubic_test, r_cubic, dims);
/* If error not too large, try some reparameterization and iteration */
@@ -923,25 +1097,28 @@ static bool fit_cubic_to_points(
points_offset_coords_length,
#endif
u_prime, tan_l, tan_r, dims, cubic_test);
- error_max_sq = cubic_calc_error(
+
+ const double error_max_sq_test = cubic_calc_error(
cubic_test, points_offset, points_offset_len, u_prime, dims,
&split_index);
- if (error_max_sq < error_threshold_sq) {
- free(u_prime);
- free(u);
-
- cubic_copy(r_cubic, cubic_test, dims);
- *r_error_max_sq = error_max_sq;
- *r_split_index = split_index;
- return true;
- }
- else if (error_max_sq < *r_error_max_sq) {
+ if (error_max_sq > error_max_sq_test) {
+ error_max_sq = error_max_sq_test;
cubic_copy(r_cubic, cubic_test, dims);
*r_error_max_sq = error_max_sq;
*r_split_index = split_index;
}
+ if (!(error_max_sq < error_threshold_sq)) {
+ /* continue */
+ }
+ else {
+ assert((error_max_sq < error_threshold_sq));
+ free(u_prime);
+ free(u);
+ return true;
+ }
+
SWAP(double *, u, u_prime);
}
free(u_prime);
@@ -949,6 +1126,10 @@ static bool fit_cubic_to_points(
return false;
}
+ else {
+ free(u);
+ return true;
+ }
}
static void fit_cubic_to_points_recursive(
@@ -960,6 +1141,7 @@ static void fit_cubic_to_points_recursive(
const double tan_l[],
const double tan_r[],
const double error_threshold_sq,
+ const uint calc_flag,
const uint dims,
/* fill in the list */
CubicList *clist)
@@ -973,8 +1155,11 @@ static void fit_cubic_to_points_recursive(
#ifdef USE_LENGTH_CACHE
points_length_cache,
#endif
- tan_l, tan_r, error_threshold_sq, dims,
- cubic, &error_max_sq, &split_index))
+ tan_l, tan_r,
+ (calc_flag & CURVE_FIT_CALC_HIGH_QUALIY) ? DBL_EPSILON : error_threshold_sq,
+ dims,
+ cubic, &error_max_sq, &split_index) ||
+ (error_max_sq < error_threshold_sq))
{
cubic_list_prepend(clist, cubic);
return;
@@ -1026,13 +1211,13 @@ static void fit_cubic_to_points_recursive(
#ifdef USE_LENGTH_CACHE
points_length_cache,
#endif
- tan_l, tan_center, error_threshold_sq, dims, clist);
+ tan_l, tan_center, error_threshold_sq, calc_flag, dims, clist);
fit_cubic_to_points_recursive(
&points_offset[split_index * dims], points_offset_len - split_index,
#ifdef USE_LENGTH_CACHE
points_length_cache + split_index,
#endif
- tan_center, tan_r, error_threshold_sq, dims, clist);
+ tan_center, tan_r, error_threshold_sq, calc_flag, dims, clist);
}
@@ -1055,6 +1240,7 @@ int curve_fit_cubic_to_points_db(
const uint points_len,
const uint dims,
const double error_threshold,
+ const uint calc_flag,
const uint *corners,
uint corners_len,
@@ -1130,7 +1316,7 @@ int curve_fit_cubic_to_points_db(
#ifdef USE_LENGTH_CACHE
points_length_cache,
#endif
- tan_l, tan_r, error_threshold_sq, dims, &clist);
+ tan_l, tan_r, error_threshold_sq, calc_flag, dims, &clist);
}
else if (points_len == 1) {
assert(points_offset_len == 1);
@@ -1197,6 +1383,7 @@ int curve_fit_cubic_to_points_fl(
const uint points_len,
const uint dims,
const float error_threshold,
+ const uint calc_flag,
const uint *corners,
const uint corners_len,
@@ -1214,7 +1401,7 @@ int curve_fit_cubic_to_points_fl(
uint cubic_array_len = 0;
int result = curve_fit_cubic_to_points_db(
- points_db, points_len, dims, error_threshold, corners, corners_len,
+ points_db, points_len, dims, error_threshold, calc_flag, corners, corners_len,
&cubic_array_db, &cubic_array_len,
r_cubic_orig_index,
r_corner_index_array, r_corner_index_len);
@@ -1241,6 +1428,7 @@ int curve_fit_cubic_to_points_fl(
int curve_fit_cubic_to_points_single_db(
const double *points,
const uint points_len,
+ const double *points_length_cache,
const uint dims,
const double error_threshold,
const double tan_l[],
@@ -1257,10 +1445,14 @@ int curve_fit_cubic_to_points_single_db(
/* in this instance theres no advantage in using length cache,
* since we're not recursively calculating values. */
#ifdef USE_LENGTH_CACHE
- double *points_length_cache = malloc(sizeof(double) * points_len);
- points_calc_coord_length_cache(
- points, points_len, dims,
- points_length_cache);
+ double *points_length_cache_alloc = NULL;
+ if (points_length_cache == NULL) {
+ points_length_cache_alloc = malloc(sizeof(double) * points_len);
+ points_calc_coord_length_cache(
+ points, points_len, dims,
+ points_length_cache_alloc);
+ points_length_cache = points_length_cache_alloc;
+ }
#endif
fit_cubic_to_points(
@@ -1273,7 +1465,9 @@ int curve_fit_cubic_to_points_single_db(
cubic, r_error_max_sq, &split_index);
#ifdef USE_LENGTH_CACHE
- free(points_length_cache);
+ if (points_length_cache_alloc) {
+ free(points_length_cache_alloc);
+ }
#endif
copy_vnvn(r_handle_l, CUBIC_PT(cubic, 1, dims), dims);
@@ -1285,6 +1479,7 @@ int curve_fit_cubic_to_points_single_db(
int curve_fit_cubic_to_points_single_fl(
const float *points,
const uint points_len,
+ const float *points_length_cache,
const uint dims,
const float error_threshold,
const float tan_l[],
@@ -1296,9 +1491,15 @@ int curve_fit_cubic_to_points_single_fl(
{
const uint points_flat_len = points_len * dims;
double *points_db = malloc(sizeof(double) * points_flat_len);
+ double *points_length_cache_db = NULL;
copy_vndb_vnfl(points_db, points, points_flat_len);
+ if (points_length_cache) {
+ points_length_cache_db = malloc(sizeof(double) * points_len);
+ copy_vndb_vnfl(points_length_cache_db, points_length_cache, points_len);
+ }
+
#ifdef USE_VLA
double tan_l_db[dims];
double tan_r_db[dims];
@@ -1316,7 +1517,7 @@ int curve_fit_cubic_to_points_single_fl(
copy_vndb_vnfl(tan_r_db, tan_r, dims);
int result = curve_fit_cubic_to_points_single_db(
- points_db, points_len, dims,
+ points_db, points_len, points_length_cache_db, dims,
(double)error_threshold,
tan_l_db, tan_r_db,
r_handle_l_db, r_handle_r_db,
@@ -1324,6 +1525,10 @@ int curve_fit_cubic_to_points_single_fl(
free(points_db);
+ if (points_length_cache_db) {
+ free(points_length_cache_db);
+ }
+
copy_vnfl_vndb(r_handle_l, r_handle_l_db, dims);
copy_vnfl_vndb(r_handle_r, r_handle_r_db, dims);
*r_error_sq = (float)r_error_sq_db;
diff --git a/extern/curve_fit_nd/intern/curve_fit_cubic_refit.c b/extern/curve_fit_nd/intern/curve_fit_cubic_refit.c
new file mode 100644
index 00000000000..bf1ab99995f
--- /dev/null
+++ b/extern/curve_fit_nd/intern/curve_fit_cubic_refit.c
@@ -0,0 +1,1443 @@
+/*
+ * Copyright (c) 2016, Campbell Barton.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the <organization> nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Curve Re-fitting Method
+ * =======================
+ *
+ * This is a more processor intensive method of fitting,
+ * compared to #curve_fit_cubic_to_points_db, and works as follows:
+ *
+ * - First iteratively remove all points under the error threshold.
+ * - If corner calculation is enabled:
+ * - Find adjacent knots that exceed the angle limit
+ * - Find a 'split' point between the knots (could include the knots)
+ * - If copying the tangents to this split point doesn't exceed the error threshold:
+ * - Assign the tangents of the two knots to the split point, define it as a corner.
+ * (after this, we have many points which are too close).
+ * - Run a re-fit pass, where knots are re-positioned between their adjacent knots
+ * when their re-fit position has a lower 'error'.
+ * While re-fitting, remove knots that fall below the error threshold.
+ */
+
+#ifdef _MSC_VER
+# define _USE_MATH_DEFINES
+#endif
+
+#include <math.h>
+#include <float.h>
+#include <stdbool.h>
+#include <assert.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+typedef unsigned int uint;
+
+#include "curve_fit_inline.h"
+#include "../curve_fit_nd.h"
+
+#include "generic_heap.h"
+
+#ifdef _MSC_VER
+# define alloca(size) _alloca(size)
+#endif
+
+#if !defined(_MSC_VER)
+# define USE_VLA
+#endif
+
+#ifdef USE_VLA
+# ifdef __GNUC__
+# pragma GCC diagnostic ignored "-Wvla"
+# endif
+#else
+# ifdef __GNUC__
+# pragma GCC diagnostic error "-Wvla"
+# endif
+#endif
+
+/* adjust the knots after simplifying */
+#define USE_KNOT_REFIT
+/* remove knots under the error threshold while re-fitting */
+#define USE_KNOT_REFIT_REMOVE
+/* detect corners over an angle threshold */
+#define USE_CORNER_DETECT
+/* avoid re-calculating lengths multiple times */
+#define USE_LENGTH_CACHE
+/* use pool allocator */
+#define USE_TPOOL
+
+
+#define SPLIT_POINT_INVALID ((uint)-1)
+
+#define MAX2(x, y) ((x) > (y) ? (x) : (y))
+
+#define SQUARE(a) ((a) * (a))
+
+#ifdef __GNUC__
+# define UNLIKELY(x) __builtin_expect(!!(x), 0)
+#else
+# define UNLIKELY(x) (x)
+#endif
+
+struct PointData {
+ const double *points;
+ uint points_len;
+#ifdef USE_LENGTH_CACHE
+ const double *points_length_cache;
+#endif
+};
+
+struct Knot {
+ struct Knot *next, *prev;
+
+ HeapNode *heap_node;
+
+ /**
+ * Currently the same, access as different for now
+ * since we may want to support different point/knot indices
+ */
+ uint index;
+
+ uint can_remove : 1;
+ uint is_removed : 1;
+ uint is_corner : 1;
+
+ double handles[2];
+ /**
+ * Store the error value, to see if we can improve on it
+ * (without having to re-calculate each time)
+ *
+ * This is the error between this knot and the next */
+ double error_sq_next;
+
+ /* Initially point to contiguous memory, however we may re-assign */
+ double *tan[2];
+} Knot;
+
+
+struct KnotRemoveState {
+ uint index;
+ /* Handles for prev/next knots */
+ double handles[2];
+};
+
+#ifdef USE_TPOOL
+/* rstate_* pool allocator */
+#define TPOOL_IMPL_PREFIX rstate
+#define TPOOL_ALLOC_TYPE struct KnotRemoveState
+#define TPOOL_STRUCT ElemPool_KnotRemoveState
+#include "generic_alloc_impl.h"
+#undef TPOOL_IMPL_PREFIX
+#undef TPOOL_ALLOC_TYPE
+#undef TPOOL_STRUCT
+#endif /* USE_TPOOL */
+
+#ifdef USE_KNOT_REFIT
+struct KnotRefitState {
+ uint index;
+ /** When SPLIT_POINT_INVALID - remove this item */
+ uint index_refit;
+ /** Handles for prev/next knots */
+ double handles_prev[2], handles_next[2];
+ double error_sq[2];
+};
+
+#ifdef USE_TPOOL
+/* refit_* pool allocator */
+#define TPOOL_IMPL_PREFIX refit
+#define TPOOL_ALLOC_TYPE struct KnotRefitState
+#define TPOOL_STRUCT ElemPool_KnotRefitState
+#include "generic_alloc_impl.h"
+#undef TPOOL_IMPL_PREFIX
+#undef TPOOL_ALLOC_TYPE
+#undef TPOOL_STRUCT
+#endif /* USE_TPOOL */
+#endif /* USE_KNOT_REFIT */
+
+
+#ifdef USE_CORNER_DETECT
+/** Result of collapsing a corner. */
+struct KnotCornerState {
+ uint index;
+ /* Merge adjacent handles into this one (may be shared with the 'index') */
+ uint index_adjacent[2];
+
+ /* Handles for prev/next knots */
+ double handles_prev[2], handles_next[2];
+ double error_sq[2];
+};
+
+/* refit_* pool allocator */
+#ifdef USE_TPOOL
+#define TPOOL_IMPL_PREFIX corner
+#define TPOOL_ALLOC_TYPE struct KnotCornerState
+#define TPOOL_STRUCT ElemPool_KnotCornerState
+#include "generic_alloc_impl.h"
+#undef TPOOL_IMPL_PREFIX
+#undef TPOOL_ALLOC_TYPE
+#undef TPOOL_STRUCT
+#endif /* USE_TPOOL */
+#endif /* USE_CORNER_DETECT */
+
+
+/* Utility functions */
+
+#ifdef USE_KNOT_REFIT
+/**
+ * Find the most distant point between the 2 knots.
+ */
+static uint knot_find_split_point(
+ const struct PointData *pd,
+ const struct Knot *knot_l, const struct Knot *knot_r,
+ const uint knots_len,
+ const uint dims)
+{
+ uint split_point = SPLIT_POINT_INVALID;
+ double split_point_dist_best = -DBL_MAX;
+
+ const double *offset = &pd->points[knot_l->index * dims];
+
+#ifdef USE_VLA
+ double v_plane[dims];
+ double v_proj[dims];
+ double v_offset[dims];
+#else
+ double *v_plane = alloca(sizeof(double) * dims);
+ double *v_proj = alloca(sizeof(double) * dims);
+ double *v_offset = alloca(sizeof(double) * dims);
+#endif
+
+ sub_vn_vnvn(
+ v_plane,
+ &pd->points[knot_l->index * dims],
+ &pd->points[knot_r->index * dims],
+ dims);
+
+ normalize_vn(v_plane, dims);
+
+ const uint knots_end = knots_len - 1;
+ const struct Knot *k_step = knot_l;
+ do {
+ if (k_step->index != knots_end) {
+ k_step += 1;
+ }
+ else {
+ /* wrap around */
+ k_step = k_step - knots_end;
+ }
+
+ if (k_step != knot_r) {
+ sub_vn_vnvn(v_offset, &pd->points[k_step->index * dims], offset, dims);
+ project_plane_vn_vnvn_normalized(v_proj, v_offset, v_plane, dims);
+
+ double split_point_dist_test = len_squared_vn(v_proj, dims);
+ if (split_point_dist_test > split_point_dist_best) {
+ split_point_dist_best = split_point_dist_test;
+ split_point = k_step->index;
+ }
+ }
+ else {
+ break;
+ }
+
+ } while (true);
+
+ return split_point;
+}
+#endif /* USE_KNOT_REFIT */
+
+
+#ifdef USE_CORNER_DETECT
+/**
+ * Find the knot furthest from the line between \a knot_l & \a knot_r.
+ * This is to be used as a split point.
+ */
+static uint knot_find_split_point_on_axis(
+ const struct PointData *pd,
+ const struct Knot *knot_l, const struct Knot *knot_r,
+ const uint knots_len,
+ const double *plane_no,
+ const uint dims)
+{
+ uint split_point = SPLIT_POINT_INVALID;
+ double split_point_dist_best = -DBL_MAX;
+
+ const uint knots_end = knots_len - 1;
+ const struct Knot *k_step = knot_l;
+ do {
+ if (k_step->index != knots_end) {
+ k_step += 1;
+ }
+ else {
+ /* wrap around */
+ k_step = k_step - knots_end;
+ }
+
+ if (k_step != knot_r) {
+ double split_point_dist_test = dot_vnvn(plane_no, &pd->points[k_step->index * dims], dims);
+ if (split_point_dist_test > split_point_dist_best) {
+ split_point_dist_best = split_point_dist_test;
+ split_point = k_step->index;
+ }
+ }
+ else {
+ break;
+ }
+
+ } while (true);
+
+ return split_point;
+}
+#endif /* USE_CORNER_DETECT */
+
+
+static double knot_remove_error_value(
+ const double *tan_l, const double *tan_r,
+ const double *points_offset, const uint points_offset_len,
+ const double *points_offset_length_cache,
+ const uint dims,
+ /* Avoid having to re-calculate again */
+ double r_handle_factors[2])
+{
+ double error_sq = FLT_MAX;
+
+#ifdef USE_VLA
+ double handle_factor_l[dims];
+ double handle_factor_r[dims];
+#else
+ double *handle_factor_l = alloca(sizeof(double) * dims);
+ double *handle_factor_r = alloca(sizeof(double) * dims);
+#endif
+
+ curve_fit_cubic_to_points_single_db(
+ points_offset, points_offset_len, points_offset_length_cache, dims, 0.0,
+ tan_l, tan_r,
+ handle_factor_l, handle_factor_r,
+ &error_sq);
+
+ assert(error_sq != FLT_MAX);
+
+ isub_vnvn(handle_factor_l, points_offset, dims);
+ r_handle_factors[0] = dot_vnvn(tan_l, handle_factor_l, dims);
+
+ isub_vnvn(handle_factor_r, &points_offset[(points_offset_len - 1) * dims], dims);
+ r_handle_factors[1] = dot_vnvn(tan_r, handle_factor_r, dims);
+
+ return error_sq;
+}
+
+static double knot_calc_curve_error_value(
+ const struct PointData *pd,
+ const struct Knot *knot_l, const struct Knot *knot_r,
+ const double *tan_l, const double *tan_r,
+ const uint dims,
+ double r_handle_factors[2])
+{
+ const uint points_offset_len = ((knot_l->index < knot_r->index) ?
+ (knot_r->index - knot_l->index) :
+ ((knot_r->index + pd->points_len) - knot_l->index)) + 1;
+
+ if (points_offset_len != 2) {
+ return knot_remove_error_value(
+ tan_l, tan_r,
+ &pd->points[knot_l->index * dims], points_offset_len,
+#ifdef USE_LENGTH_CACHE
+ &pd->points_length_cache[knot_l->index],
+#else
+ NULL,
+#endif
+ dims,
+ r_handle_factors);
+ }
+ else {
+ /* No points between, use 1/3 handle length with no error as a fallback. */
+ assert(points_offset_len == 2);
+#ifdef USE_LENGTH_CACHE
+ r_handle_factors[0] = r_handle_factors[1] = pd->points_length_cache[knot_l->index] / 3.0;
+#else
+ r_handle_factors[0] = r_handle_factors[1] = len_vnvn(
+ &pd->points[(knot_l->index + 0) * dims],
+ &pd->points[(knot_l->index + 1) * dims], dims) / 3.0;
+#endif
+ return 0.0;
+ }
+}
+
+struct KnotRemove_Params {
+ Heap *heap;
+ const struct PointData *pd;
+#ifdef USE_TPOOL
+ struct ElemPool_KnotRemoveState *epool;
+#endif
+};
+
+static void knot_remove_error_recalculate(
+ struct KnotRemove_Params *p,
+ struct Knot *k, const double error_sq_max,
+ const uint dims)
+{
+ assert(k->can_remove);
+ double handles[2];
+
+ const double cost_sq = knot_calc_curve_error_value(
+ p->pd, k->prev, k->next,
+ k->prev->tan[1], k->next->tan[0],
+ dims,
+ handles);
+
+ if (cost_sq < error_sq_max) {
+ struct KnotRemoveState *r;
+ if (k->heap_node) {
+ r = HEAP_node_ptr(k->heap_node);
+ HEAP_remove(p->heap, k->heap_node);
+ }
+ else {
+#ifdef USE_TPOOL
+ r = rstate_pool_elem_alloc(p->epool);
+#else
+ r = malloc(sizeof(*r));
+#endif
+
+ r->index = k->index;
+ }
+
+ r->handles[0] = handles[0];
+ r->handles[1] = handles[1];
+
+ k->heap_node = HEAP_insert(p->heap, cost_sq, r);
+ }
+ else {
+ if (k->heap_node) {
+ struct KnotRemoveState *r;
+ r = HEAP_node_ptr(k->heap_node);
+ HEAP_remove(p->heap, k->heap_node);
+
+#ifdef USE_TPOOL
+ rstate_pool_elem_free(p->epool, r);
+#else
+ free(r);
+#endif
+
+ k->heap_node = NULL;
+ }
+ }
+}
+
+/**
+ * Return length after being reduced.
+ */
+static uint curve_incremental_simplify(
+ const struct PointData *pd,
+ struct Knot *knots, const uint knots_len, uint knots_len_remaining,
+ double error_sq_max, const uint dims)
+{
+
+#ifdef USE_TPOOL
+ struct ElemPool_KnotRemoveState epool;
+
+ rstate_pool_create(&epool, 0);
+#endif
+
+ Heap *heap = HEAP_new(knots_len_remaining);
+
+ struct KnotRemove_Params params = {
+ .pd = pd,
+ .heap = heap,
+#ifdef USE_TPOOL
+ .epool = &epool,
+#endif
+ };
+
+ for (uint i = 0; i < knots_len; i++) {
+ struct Knot *k = &knots[i];
+ if (k->can_remove && (k->is_removed == false) && (k->is_corner == false)) {
+ knot_remove_error_recalculate(&params, k, error_sq_max, dims);
+ }
+ }
+
+ while (HEAP_is_empty(heap) == false) {
+ struct Knot *k;
+
+ {
+ const double error_sq = HEAP_top_value(heap);
+ struct KnotRemoveState *r = HEAP_popmin(heap);
+ k = &knots[r->index];
+ k->heap_node = NULL;
+ k->prev->handles[1] = r->handles[0];
+ k->next->handles[0] = r->handles[1];
+
+ k->prev->error_sq_next = error_sq;
+
+#ifdef USE_TPOOL
+ rstate_pool_elem_free(&epool, r);
+#else
+ free(r);
+#endif
+ }
+
+ if (UNLIKELY(knots_len_remaining <= 2)) {
+ continue;
+ }
+
+ struct Knot *k_prev = k->prev;
+ struct Knot *k_next = k->next;
+
+ /* Remove ourselves */
+ k_next->prev = k_prev;
+ k_prev->next = k_next;
+
+ k->next = NULL;
+ k->prev = NULL;
+ k->is_removed = true;
+
+ if (k_prev->can_remove && (k_prev->is_corner == false) && (k_prev->prev && k_prev->next)) {
+ knot_remove_error_recalculate(&params, k_prev, error_sq_max, dims);
+ }
+
+ if (k_next->can_remove && (k_next->is_corner == false) && (k_next->prev && k_next->next)) {
+ knot_remove_error_recalculate(&params, k_next, error_sq_max, dims);
+ }
+
+ knots_len_remaining -= 1;
+ }
+
+#ifdef USE_TPOOL
+ rstate_pool_destroy(&epool);
+#endif
+
+ HEAP_free(heap, free);
+
+ return knots_len_remaining;
+}
+
+
+#ifdef USE_KNOT_REFIT
+
+struct KnotRefit_Params {
+ Heap *heap;
+ const struct PointData *pd;
+#ifdef USE_TPOOL
+ struct ElemPool_KnotRefitState *epool;
+#endif
+};
+
+static void knot_refit_error_recalculate(
+ struct KnotRefit_Params *p,
+ struct Knot *knots, const uint knots_len,
+ struct Knot *k,
+ const double error_sq_max,
+ const uint dims)
+{
+ assert(k->can_remove);
+
+#ifdef USE_KNOT_REFIT_REMOVE
+ {
+ double handles[2];
+
+ /* First check if we can remove, this allows to refit and remove as we go. */
+ const double cost_sq = knot_calc_curve_error_value(
+ p->pd, k->prev, k->next,
+ k->prev->tan[1], k->next->tan[0],
+ dims,
+ handles);
+
+ if (cost_sq < error_sq_max) {
+ struct KnotRefitState *r;
+ if (k->heap_node) {
+ r = HEAP_node_ptr(k->heap_node);
+ HEAP_remove(p->heap, k->heap_node);
+ }
+ else {
+#ifdef USE_TPOOL
+ r = refit_pool_elem_alloc(p->epool);
+#else
+ r = malloc(sizeof(*r));
+#endif
+ r->index = k->index;
+ }
+
+ r->index_refit = SPLIT_POINT_INVALID;
+
+ r->handles_prev[0] = handles[0];
+ r->handles_prev[1] = 0.0; /* unused */
+ r->handles_next[0] = 0.0; /* unused */
+ r->handles_next[1] = handles[1];
+
+ r->error_sq[0] = r->error_sq[1] = cost_sq;
+
+ /* Always perform removal before refitting, (make a negative number) */
+ k->heap_node = HEAP_insert(p->heap, cost_sq - error_sq_max, r);
+
+ return;
+ }
+ }
+#else
+ (void)error_sq_max;
+#endif /* USE_KNOT_REFIT_REMOVE */
+
+ const uint refit_index = knot_find_split_point(
+ p->pd, k->prev, k->next,
+ knots_len,
+ dims);
+
+ if ((refit_index == SPLIT_POINT_INVALID) ||
+ (refit_index == k->index))
+ {
+ goto remove;
+ }
+
+ struct Knot *k_refit = &knots[refit_index];
+
+ const double cost_sq_src_max = MAX2(k->prev->error_sq_next, k->error_sq_next);
+ assert(cost_sq_src_max <= error_sq_max);
+
+ double cost_sq_dst[2];
+ double handles_prev[2], handles_next[2];
+
+ if ((((cost_sq_dst[0] = knot_calc_curve_error_value(
+ p->pd, k->prev, k_refit,
+ k->prev->tan[1], k_refit->tan[0],
+ dims,
+ handles_prev)) < cost_sq_src_max) &&
+ ((cost_sq_dst[1] = knot_calc_curve_error_value(
+ p->pd, k_refit, k->next,
+ k_refit->tan[1], k->next->tan[0],
+ dims,
+ handles_next)) < cost_sq_src_max)))
+ {
+ {
+ struct KnotRefitState *r;
+ if (k->heap_node) {
+ r = HEAP_node_ptr(k->heap_node);
+ HEAP_remove(p->heap, k->heap_node);
+ }
+ else {
+#ifdef USE_TPOOL
+ r = refit_pool_elem_alloc(p->epool);
+#else
+ r = malloc(sizeof(*r));
+#endif
+ r->index = k->index;
+ }
+
+ r->index_refit = refit_index;
+
+ r->handles_prev[0] = handles_prev[0];
+ r->handles_prev[1] = handles_prev[1];
+
+ r->handles_next[0] = handles_next[0];
+ r->handles_next[1] = handles_next[1];
+
+ r->error_sq[0] = cost_sq_dst[0];
+ r->error_sq[1] = cost_sq_dst[1];
+
+ const double cost_sq_dst_max = MAX2(cost_sq_dst[0], cost_sq_dst[1]);
+
+ assert(cost_sq_dst_max < cost_sq_src_max);
+
+ /* Weight for the greatest improvement */
+ k->heap_node = HEAP_insert(p->heap, cost_sq_src_max - cost_sq_dst_max, r);
+ }
+ }
+ else {
+remove:
+ if (k->heap_node) {
+ struct KnotRefitState *r;
+ r = HEAP_node_ptr(k->heap_node);
+ HEAP_remove(p->heap, k->heap_node);
+
+#ifdef USE_TPOOL
+ refit_pool_elem_free(p->epool, r);
+#else
+ free(r);
+#endif
+
+ k->heap_node = NULL;
+ }
+ }
+}
+
+/**
+ * Re-adjust the curves by re-fitting points.
+ * test the error from moving using points between the adjacent.
+ */
+static uint curve_incremental_simplify_refit(
+ const struct PointData *pd,
+ struct Knot *knots, const uint knots_len, uint knots_len_remaining,
+ const double error_sq_max,
+ const uint dims)
+{
+#ifdef USE_TPOOL
+ struct ElemPool_KnotRefitState epool;
+
+ refit_pool_create(&epool, 0);
+#endif
+
+ Heap *heap = HEAP_new(knots_len_remaining);
+
+ struct KnotRefit_Params params = {
+ .pd = pd,
+ .heap = heap,
+#ifdef USE_TPOOL
+ .epool = &epool,
+#endif
+ };
+
+ for (uint i = 0; i < knots_len; i++) {
+ struct Knot *k = &knots[i];
+ if (k->can_remove &&
+ (k->is_removed == false) &&
+ (k->is_corner == false) &&
+ (k->prev && k->next))
+ {
+ knot_refit_error_recalculate(&params, knots, knots_len, k, error_sq_max, dims);
+ }
+ }
+
+ while (HEAP_is_empty(heap) == false) {
+ struct Knot *k_old, *k_refit;
+
+ {
+ struct KnotRefitState *r = HEAP_popmin(heap);
+ k_old = &knots[r->index];
+ k_old->heap_node = NULL;
+
+#ifdef USE_KNOT_REFIT_REMOVE
+ if (r->index_refit == SPLIT_POINT_INVALID) {
+ k_refit = NULL;
+ }
+ else
+#endif
+ {
+ k_refit = &knots[r->index_refit];
+ k_refit->handles[0] = r->handles_prev[1];
+ k_refit->handles[1] = r->handles_next[0];
+ }
+
+ k_old->prev->handles[1] = r->handles_prev[0];
+ k_old->next->handles[0] = r->handles_next[1];
+
+#ifdef USE_TPOOL
+ refit_pool_elem_free(&epool, r);
+#else
+ free(r);
+#endif
+ }
+
+ if (UNLIKELY(knots_len_remaining <= 2)) {
+ continue;
+ }
+
+ struct Knot *k_prev = k_old->prev;
+ struct Knot *k_next = k_old->next;
+
+ k_old->next = NULL;
+ k_old->prev = NULL;
+ k_old->is_removed = true;
+
+#ifdef USE_KNOT_REFIT_REMOVE
+ if (k_refit == NULL) {
+ k_next->prev = k_prev;
+ k_prev->next = k_next;
+
+ knots_len_remaining -= 1;
+ }
+ else
+#endif
+ {
+ /* Remove ourselves */
+ k_next->prev = k_refit;
+ k_prev->next = k_refit;
+
+ k_refit->prev = k_prev;
+ k_refit->next = k_next;
+ k_refit->is_removed = false;
+ }
+
+ if (k_prev->can_remove && (k_prev->is_corner == false) && (k_prev->prev && k_prev->next)) {
+ knot_refit_error_recalculate(&params, knots, knots_len, k_prev, error_sq_max, dims);
+ }
+
+ if (k_next->can_remove && (k_next->is_corner == false) && (k_next->prev && k_next->next)) {
+ knot_refit_error_recalculate(&params, knots, knots_len, k_next, error_sq_max, dims);
+ }
+ }
+
+#ifdef USE_TPOOL
+ refit_pool_destroy(&epool);
+#endif
+
+ HEAP_free(heap, free);
+
+ return knots_len_remaining;
+}
+
+#endif /* USE_KNOT_REFIT */
+
+
+#ifdef USE_CORNER_DETECT
+
+struct KnotCorner_Params {
+ Heap *heap;
+ const struct PointData *pd;
+#ifdef USE_TPOOL
+ struct ElemPool_KnotCornerState *epool;
+#endif
+};
+
+/**
+ * (Re)calculate the error incurred from turning this into a corner.
+ */
+static void knot_corner_error_recalculate(
+ struct KnotCorner_Params *p,
+ struct Knot *k_split,
+ struct Knot *k_prev, struct Knot *k_next,
+ const double error_sq_max,
+ const uint dims)
+{
+ assert(k_prev->can_remove && k_next->can_remove);
+
+ double handles_prev[2], handles_next[2];
+ /* Test skipping 'k_prev' by using points (k_prev->prev to k_split) */
+ double cost_sq_dst[2];
+
+ if (((cost_sq_dst[0] = knot_calc_curve_error_value(
+ p->pd, k_prev, k_split,
+ k_prev->tan[1], k_prev->tan[1],
+ dims,
+ handles_prev)) < error_sq_max) &&
+ ((cost_sq_dst[1] = knot_calc_curve_error_value(
+ p->pd, k_split, k_next,
+ k_next->tan[0], k_next->tan[0],
+ dims,
+ handles_next)) < error_sq_max))
+ {
+ struct KnotCornerState *c;
+ if (k_split->heap_node) {
+ c = HEAP_node_ptr(k_split->heap_node);
+ HEAP_remove(p->heap, k_split->heap_node);
+ }
+ else {
+#ifdef USE_TPOOL
+ c = corner_pool_elem_alloc(p->epool);
+#else
+ c = malloc(sizeof(*c));
+#endif
+ c->index = k_split->index;
+ }
+
+ c->index_adjacent[0] = k_prev->index;
+ c->index_adjacent[1] = k_next->index;
+
+ /* Need to store handle lengths for both sides */
+ c->handles_prev[0] = handles_prev[0];
+ c->handles_prev[1] = handles_prev[1];
+
+ c->handles_next[0] = handles_next[0];
+ c->handles_next[1] = handles_next[1];
+
+ c->error_sq[0] = cost_sq_dst[0];
+ c->error_sq[1] = cost_sq_dst[1];
+
+ const double cost_max_sq = MAX2(cost_sq_dst[0], cost_sq_dst[1]);
+ k_split->heap_node = HEAP_insert(p->heap, cost_max_sq, c);
+ }
+ else {
+ if (k_split->heap_node) {
+ struct KnotCornerState *c;
+ c = HEAP_node_ptr(k_split->heap_node);
+ HEAP_remove(p->heap, k_split->heap_node);
+#ifdef USE_TPOOL
+ corner_pool_elem_free(p->epool, c);
+#else
+ free(c);
+#endif
+ k_split->heap_node = NULL;
+ }
+ }
+}
+
+
+/**
+ * Attempt to collapse close knots into corners,
+ * as long as they fall below the error threshold.
+ */
+static uint curve_incremental_simplify_corners(
+ const struct PointData *pd,
+ struct Knot *knots, const uint knots_len, uint knots_len_remaining,
+ const double error_sq_max, const double error_sq_collapse_max,
+ const double corner_angle,
+ const uint dims,
+ uint *r_corner_index_len)
+{
+#ifdef USE_TPOOL
+ struct ElemPool_KnotCornerState epool;
+
+ corner_pool_create(&epool, 0);
+#endif
+
+ Heap *heap = HEAP_new(0);
+
+ struct KnotCorner_Params params = {
+ .pd = pd,
+ .heap = heap,
+#ifdef USE_TPOOL
+ .epool = &epool,
+#endif
+ };
+
+#ifdef USE_VLA
+ double plane_no[dims];
+ double k_proj_ref[dims];
+ double k_proj_split[dims];
+#else
+ double *plane_no = alloca(sizeof(double) * dims);
+ double *k_proj_ref = alloca(sizeof(double) * dims);
+ double *k_proj_split = alloca(sizeof(double) * dims);
+#endif
+
+ const double corner_angle_cos = cos(corner_angle);
+
+ uint corner_index_len = 0;
+
+ for (uint i = 0; i < knots_len; i++) {
+ if ((knots[i].is_removed == false) &&
+ (knots[i].can_remove == true) &&
+ (knots[i].next && knots[i].next->can_remove))
+ {
+ struct Knot *k_prev = &knots[i];
+ struct Knot *k_next = k_prev->next;
+
+ /* Angle outside threshold */
+ if (dot_vnvn(k_prev->tan[0], k_next->tan[1], dims) < corner_angle_cos) {
+ /* Measure distance projected onto a plane,
+ * since the points may be offset along their own tangents. */
+ sub_vn_vnvn(plane_no, k_next->tan[0], k_prev->tan[1], dims);
+
+ /* Compare 2x so as to allow both to be changed by maximum of error_sq_max */
+ const uint split_index = knot_find_split_point_on_axis(
+ pd, k_prev, k_next,
+ knots_len,
+ plane_no,
+ dims);
+
+ if (split_index != SPLIT_POINT_INVALID) {
+ const double *co_prev = &params.pd->points[k_prev->index * dims];
+ const double *co_next = &params.pd->points[k_next->index * dims];
+ const double *co_split = &params.pd->points[split_index * dims];
+
+ project_vn_vnvn_normalized(k_proj_ref, co_prev, k_prev->tan[1], dims);
+ project_vn_vnvn_normalized(k_proj_split, co_split, k_prev->tan[1], dims);
+
+ if (len_squared_vnvn(k_proj_ref, k_proj_split, dims) < error_sq_collapse_max) {
+
+ project_vn_vnvn_normalized(k_proj_ref, co_next, k_next->tan[0], dims);
+ project_vn_vnvn_normalized(k_proj_split, co_split, k_next->tan[0], dims);
+
+ if (len_squared_vnvn(k_proj_ref, k_proj_split, dims) < error_sq_collapse_max) {
+
+ struct Knot *k_split = &knots[split_index];
+
+ knot_corner_error_recalculate(
+ &params,
+ k_split, k_prev, k_next,
+ error_sq_max,
+ dims);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ while (HEAP_is_empty(heap) == false) {
+ struct KnotCornerState *c = HEAP_popmin(heap);
+
+ struct Knot *k_split = &knots[c->index];
+
+ /* Remove while collapsing */
+ struct Knot *k_prev = &knots[c->index_adjacent[0]];
+ struct Knot *k_next = &knots[c->index_adjacent[1]];
+
+ /* Insert */
+ k_split->is_removed = false;
+ k_split->prev = k_prev;
+ k_split->next = k_next;
+ k_prev->next = k_split;
+ k_next->prev = k_split;
+
+ /* Update tangents */
+ k_split->tan[0] = k_prev->tan[1];
+ k_split->tan[1] = k_next->tan[0];
+
+ /* Own handles */
+ k_prev->handles[1] = c->handles_prev[0];
+ k_split->handles[0] = c->handles_prev[1];
+ k_split->handles[1] = c->handles_next[0];
+ k_next->handles[0] = c->handles_next[1];
+
+ k_prev->error_sq_next = c->error_sq[0];
+ k_split->error_sq_next = c->error_sq[1];
+
+ k_split->heap_node = NULL;
+
+#ifdef USE_TPOOL
+ corner_pool_elem_free(&epool, c);
+#else
+ free(c);
+#endif
+
+ k_split->is_corner = true;
+
+ knots_len_remaining++;
+
+ corner_index_len++;
+ }
+
+#ifdef USE_TPOOL
+ corner_pool_destroy(&epool);
+#endif
+
+ HEAP_free(heap, free);
+
+ *r_corner_index_len = corner_index_len;
+
+ return knots_len_remaining;
+}
+
+#endif /* USE_CORNER_DETECT */
+
+int curve_fit_cubic_to_points_refit_db(
+ const double *points,
+ const uint points_len,
+ const uint dims,
+ const double error_threshold,
+ const uint calc_flag,
+ const uint *corners,
+ const uint corners_len,
+ const double corner_angle,
+
+ double **r_cubic_array, uint *r_cubic_array_len,
+ uint **r_cubic_orig_index,
+ uint **r_corner_index_array, uint *r_corner_index_len)
+{
+ const uint knots_len = points_len;
+ struct Knot *knots = malloc(sizeof(Knot) * knots_len);
+
+#ifndef USE_CORNER_DETECT
+ (void)r_corner_index_array;
+ (void)r_corner_index_len;
+#endif
+
+(void)corners;
+(void)corners_len;
+
+ const bool is_cyclic = (calc_flag & CURVE_FIT_CALC_CYCLIC) != 0 && (points_len > 2);
+#ifdef USE_CORNER_DETECT
+ const bool use_corner = (corner_angle < M_PI);
+#else
+ (void)corner_angle;
+#endif
+
+ /* Over alloc the list x2 for cyclic curves,
+ * so we can evaluate across the start/end */
+ double *points_alloc = NULL;
+ if (is_cyclic) {
+ points_alloc = malloc((sizeof(double) * points_len * dims) * 2);
+ memcpy(points_alloc, points, sizeof(double) * points_len * dims);
+ memcpy(points_alloc + (points_len * dims), points_alloc, sizeof(double) * points_len * dims);
+ points = points_alloc;
+ }
+
+ double *tangents = malloc(sizeof(double) * knots_len * 2 * dims);
+
+ {
+ double *t_step = tangents;
+ for (uint i = 0; i < knots_len; i++) {
+ knots[i].next = (knots + i) + 1;
+ knots[i].prev = (knots + i) - 1;
+
+ knots[i].heap_node = NULL;
+ knots[i].index = i;
+ knots[i].can_remove = true;
+ knots[i].is_removed = false;
+ knots[i].is_corner = false;
+ knots[i].error_sq_next = 0.0;
+ knots[i].tan[0] = t_step; t_step += dims;
+ knots[i].tan[1] = t_step; t_step += dims;
+ }
+ assert(t_step == &tangents[knots_len * 2 * dims]);
+ }
+
+ if (is_cyclic) {
+ knots[0].prev = &knots[knots_len - 1];
+ knots[knots_len - 1].next = &knots[0];
+ }
+ else {
+ knots[0].prev = NULL;
+ knots[knots_len - 1].next = NULL;
+
+ /* always keep end-points */
+ knots[0].can_remove = false;
+ knots[knots_len - 1].can_remove = false;
+ }
+
+#ifdef USE_LENGTH_CACHE
+ double *points_length_cache = malloc(sizeof(double) * points_len * (is_cyclic ? 2 : 1));
+#endif
+
+ /* Initialize tangents,
+ * also set the values for knot handles since some may not collapse. */
+ {
+#ifdef USE_VLA
+ double tan_prev[dims];
+ double tan_next[dims];
+#else
+ double *tan_prev = alloca(sizeof(double) * dims);
+ double *tan_next = alloca(sizeof(double) * dims);
+#endif
+ double len_prev, len_next;
+
+#if 0
+ /* 2x normalize calculations, but correct */
+
+ for (uint i = 0; i < knots_len; i++) {
+ Knot *k = &knots[i];
+
+ if (k->prev) {
+ sub_vn_vnvn(tan_prev, &points[k->prev->index * dims], &points[k->index * dims], dims);
+#ifdef USE_LENGTH_CACHE
+ points_length_cache[i] =
+#endif
+ len_prev = normalize_vn(tan_prev, dims);
+ }
+ else {
+ zero_vn(tan_prev, dims);
+ len_prev = 0.0;
+ }
+
+ if (k->next) {
+ sub_vn_vnvn(tan_next, &points[k->index * dims], &points[k->next->index * dims], dims);
+ len_next = normalize_vn(tan_next, dims);
+ }
+ else {
+ zero_vn(tan_next, dims);
+ len_next = 0.0;
+ }
+
+ add_vn_vnvn(k->tan[0], tan_prev, tan_next, dims);
+ normalize_vn(k->tan[0], dims);
+ copy_vnvn(k->tan[1], k->tan[0], dims);
+ k->handles[0] = len_prev / 3;
+ k->handles[1] = len_next / -3;
+ }
+#else
+ if (knots_len < 2) {
+ /* NOP, set dummy values */
+ for (uint i = 0; i < knots_len; i++) {
+ struct Knot *k = &knots[i];
+ zero_vn(k->tan[0], dims);
+ zero_vn(k->tan[1], dims);
+ k->handles[0] = 0.0;
+ k->handles[1] = 0.0;
+#ifdef USE_LENGTH_CACHE
+ points_length_cache[i] = 0.0;
+#endif
+ }
+ }
+ else if (is_cyclic) {
+ len_prev = normalize_vn_vnvn(
+ tan_prev, &points[(knots_len - 2) * dims], &points[(knots_len - 1) * dims], dims);
+ for (uint i_curr = knots_len - 1, i_next = 0; i_next < knots_len; i_curr = i_next++) {
+ struct Knot *k = &knots[i_curr];
+#ifdef USE_LENGTH_CACHE
+ points_length_cache[i_next] =
+#endif
+ len_next = normalize_vn_vnvn(tan_next, &points[i_curr * dims], &points[i_next * dims], dims);
+
+ add_vn_vnvn(k->tan[0], tan_prev, tan_next, dims);
+ normalize_vn(k->tan[0], dims);
+ copy_vnvn(k->tan[1], k->tan[0], dims);
+ k->handles[0] = len_prev / 3;
+ k->handles[1] = len_next / -3;
+
+ copy_vnvn(tan_prev, tan_next, dims);
+ len_prev = len_next;
+ }
+ }
+ else {
+#ifdef USE_LENGTH_CACHE
+ points_length_cache[0] = 0.0;
+ points_length_cache[1] =
+#endif
+ len_prev = normalize_vn_vnvn(
+ tan_prev, &points[0 * dims], &points[1 * dims], dims);
+ copy_vnvn(knots[0].tan[0], tan_prev, dims);
+ copy_vnvn(knots[0].tan[1], tan_prev, dims);
+ knots[0].handles[0] = len_prev / 3;
+ knots[0].handles[1] = len_prev / -3;
+
+ for (uint i_curr = 1, i_next = 2; i_next < knots_len; i_curr = i_next++) {
+ struct Knot *k = &knots[i_curr];
+
+#ifdef USE_LENGTH_CACHE
+ points_length_cache[i_next] =
+#endif
+ len_next = normalize_vn_vnvn(tan_next, &points[i_curr * dims], &points[i_next * dims], dims);
+
+ add_vn_vnvn(k->tan[0], tan_prev, tan_next, dims);
+ normalize_vn(k->tan[0], dims);
+ copy_vnvn(k->tan[1], k->tan[0], dims);
+ k->handles[0] = len_prev / 3;
+ k->handles[1] = len_next / -3;
+
+ copy_vnvn(tan_prev, tan_next, dims);
+ len_prev = len_next;
+ }
+ copy_vnvn(knots[knots_len - 1].tan[0], tan_next, dims);
+ copy_vnvn(knots[knots_len - 1].tan[1], tan_next, dims);
+
+ knots[knots_len - 1].handles[0] = len_next / 3;
+ knots[knots_len - 1].handles[1] = len_next / -3;
+ }
+#endif
+ }
+
+#ifdef USE_LENGTH_CACHE
+ if (is_cyclic) {
+ memcpy(&points_length_cache[points_len], points_length_cache, sizeof(double) * points_len);
+ }
+#endif
+
+
+#if 0
+ for (uint i = 0; i < knots_len; i++) {
+ Knot *k = &knots[i];
+ printf("TAN %.8f %.8f %.8f %.8f\n", k->tan[0][0], k->tan[0][1], k->tan[1][0], k->tan[0][1]);
+ }
+#endif
+
+ const struct PointData pd = {
+ .points = points,
+ .points_len = points_len,
+#ifdef USE_LENGTH_CACHE
+ .points_length_cache = points_length_cache,
+#endif
+ };
+
+ uint knots_len_remaining = knots_len;
+
+ /* 'curve_incremental_simplify_refit' can be called here, but its very slow
+ * just remove all within the threshold first. */
+ knots_len_remaining = curve_incremental_simplify(
+ &pd, knots, knots_len, knots_len_remaining,
+ SQUARE(error_threshold), dims);
+
+#ifdef USE_CORNER_DETECT
+ if (use_corner) {
+
+#ifdef DEBUG
+ for (uint i = 0; i < knots_len; i++) {
+ assert(knots[i].heap_node == NULL);
+ }
+#endif
+
+ knots_len_remaining = curve_incremental_simplify_corners(
+ &pd, knots, knots_len, knots_len_remaining,
+ SQUARE(error_threshold), SQUARE(error_threshold * 3),
+ corner_angle,
+ dims,
+ r_corner_index_len);
+ }
+#endif /* USE_CORNER_DETECT */
+
+#ifdef USE_KNOT_REFIT
+ knots_len_remaining = curve_incremental_simplify_refit(
+ &pd, knots, knots_len, knots_len_remaining,
+ SQUARE(error_threshold),
+ dims);
+#endif /* USE_KNOT_REFIT */
+
+
+#ifdef USE_CORNER_DETECT
+ if (use_corner) {
+ if (is_cyclic == false) {
+ *r_corner_index_len += 2;
+ }
+
+ uint *corner_index_array = malloc(sizeof(uint) * (*r_corner_index_len));
+ uint k_index = 0, c_index = 0;
+ uint i = 0;
+
+ if (is_cyclic == false) {
+ corner_index_array[c_index++] = k_index;
+ k_index++;
+ i++;
+ }
+
+ for (; i < knots_len; i++) {
+ if (knots[i].is_removed == false) {
+ if (knots[i].is_corner == true) {
+ corner_index_array[c_index++] = k_index;
+ }
+ k_index++;
+ }
+ }
+
+ if (is_cyclic == false) {
+ corner_index_array[c_index++] = k_index;
+ k_index++;
+ }
+
+ assert(c_index == *r_corner_index_len);
+ *r_corner_index_array = corner_index_array;
+ }
+#endif /* USE_CORNER_DETECT */
+
+#ifdef USE_LENGTH_CACHE
+ free(points_length_cache);
+#endif
+
+ uint *cubic_orig_index = NULL;
+
+ if (r_cubic_orig_index) {
+ cubic_orig_index = malloc(sizeof(uint) * knots_len_remaining);
+ }
+
+ struct Knot *knots_first = NULL;
+ {
+ struct Knot *k;
+ for (uint i = 0; i < knots_len; i++) {
+ if (knots[i].is_removed == false) {
+ knots_first = &knots[i];
+ break;
+ }
+ }
+
+ if (cubic_orig_index) {
+ k = knots_first;
+ for (uint i = 0; i < knots_len_remaining; i++, k = k->next) {
+ cubic_orig_index[i] = k->index;
+ }
+ }
+ }
+
+ /* Correct unused handle endpoints - not essential, but nice behavior */
+ if (is_cyclic == false) {
+ struct Knot *knots_last = knots_first;
+ while (knots_last->next) {
+ knots_last = knots_last->next;
+ }
+ knots_first->handles[0] = -knots_first->handles[1];
+ knots_last->handles[1] = -knots_last->handles[0];
+ }
+
+ /* 3x for one knot and two handles */
+ double *cubic_array = malloc(sizeof(double) * knots_len_remaining * 3 * dims);
+
+ {
+ double *c_step = cubic_array;
+ struct Knot *k = knots_first;
+ for (uint i = 0; i < knots_len_remaining; i++, k = k->next) {
+ const double *p = &points[k->index * dims];
+
+ madd_vn_vnvn_fl(c_step, p, k->tan[0], k->handles[0], dims);
+ c_step += dims;
+ copy_vnvn(c_step, p, dims);
+ c_step += dims;
+ madd_vn_vnvn_fl(c_step, p, k->tan[1], k->handles[1], dims);
+ c_step += dims;
+ }
+ assert(c_step == &cubic_array[knots_len_remaining * 3 * dims]);
+ }
+
+ if (points_alloc) {
+ free(points_alloc);
+ points_alloc = NULL;
+ }
+
+ free(knots);
+ free(tangents);
+
+ if (r_cubic_orig_index) {
+ *r_cubic_orig_index = cubic_orig_index;
+ }
+
+ *r_cubic_array = cubic_array;
+ *r_cubic_array_len = knots_len_remaining;
+
+ return 0;
+}
+
+
+int curve_fit_cubic_to_points_refit_fl(
+ const float *points,
+ const unsigned int points_len,
+ const unsigned int dims,
+ const float error_threshold,
+ const unsigned int calc_flag,
+ const unsigned int *corners,
+ unsigned int corners_len,
+ const float corner_angle,
+
+ float **r_cubic_array, unsigned int *r_cubic_array_len,
+ unsigned int **r_cubic_orig_index,
+ unsigned int **r_corner_index_array, unsigned int *r_corner_index_len)
+{
+ const uint points_flat_len = points_len * dims;
+ double *points_db = malloc(sizeof(double) * points_flat_len);
+
+ copy_vndb_vnfl(points_db, points, points_flat_len);
+
+ double *cubic_array_db = NULL;
+ float *cubic_array_fl = NULL;
+ uint cubic_array_len = 0;
+
+ int result = curve_fit_cubic_to_points_refit_db(
+ points_db, points_len, dims, error_threshold, calc_flag, corners, corners_len,
+ corner_angle,
+ &cubic_array_db, &cubic_array_len,
+ r_cubic_orig_index,
+ r_corner_index_array, r_corner_index_len);
+ free(points_db);
+
+ if (!result) {
+ uint cubic_array_flat_len = cubic_array_len * 3 * dims;
+ cubic_array_fl = malloc(sizeof(float) * cubic_array_flat_len);
+ for (uint i = 0; i < cubic_array_flat_len; i++) {
+ cubic_array_fl[i] = (float)cubic_array_db[i];
+ }
+ free(cubic_array_db);
+ }
+
+ *r_cubic_array = cubic_array_fl;
+ *r_cubic_array_len = cubic_array_len;
+
+ return result;
+}
+
diff --git a/extern/curve_fit_nd/intern/curve_fit_inline.h b/extern/curve_fit_nd/intern/curve_fit_inline.h
index f6656c0f9e9..f9eaa4c647c 100644
--- a/extern/curve_fit_nd/intern/curve_fit_inline.h
+++ b/extern/curve_fit_nd/intern/curve_fit_inline.h
@@ -290,4 +290,26 @@ MINLINE bool equals_vnvn(
return true;
}
+MINLINE void project_vn_vnvn(
+ double v_out[], const double p[], const double v_proj[], const uint dims)
+{
+ const double mul = dot_vnvn(p, v_proj, dims) / dot_vnvn(v_proj, v_proj, dims);
+ mul_vnvn_fl(v_out, v_proj, mul, dims);
+}
+
+MINLINE void project_vn_vnvn_normalized(
+ double v_out[], const double p[], const double v_proj[], const uint dims)
+{
+ const double mul = dot_vnvn(p, v_proj, dims);
+ mul_vnvn_fl(v_out, v_proj, mul, dims);
+}
+
+MINLINE void project_plane_vn_vnvn_normalized(
+ double v_out[], const double v[], const double v_plane[], const uint dims)
+{
+ assert(v != v_out);
+ project_vn_vnvn_normalized(v_out, v, v_plane, dims);
+ sub_vn_vnvn(v_out, v, v_out, dims);
+}
+
/** \} */
diff --git a/extern/curve_fit_nd/intern/generic_alloc_impl.h b/extern/curve_fit_nd/intern/generic_alloc_impl.h
new file mode 100644
index 00000000000..687c154f14a
--- /dev/null
+++ b/extern/curve_fit_nd/intern/generic_alloc_impl.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2016, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the <organization> nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file generic_alloc_impl.c
+ * \ingroup curve_fit
+ *
+ * Simple Memory Chunking Allocator
+ * ================================
+ *
+ * Defines need to be set:
+ * - #TPOOL_IMPL_PREFIX: Prefix to use for the API.
+ * - #TPOOL_ALLOC_TYPE: Struct type this pool handles.
+ * - #TPOOL_STRUCT: Name for pool struct name.
+ * - #TPOOL_CHUNK_SIZE: Chunk size (optional), use 64kb when not defined.
+ *
+ * \note #TPOOL_ALLOC_TYPE must be at least ``sizeof(void *)``.
+ *
+ * Defines the API, uses #TPOOL_IMPL_PREFIX to prefix each function.
+ *
+ * - *_pool_create()
+ * - *_pool_destroy()
+ * - *_pool_clear()
+ *
+ * - *_pool_elem_alloc()
+ * - *_pool_elem_calloc()
+ * - *_pool_elem_free()
+ */
+
+/* check we're not building directly */
+#if !defined(TPOOL_IMPL_PREFIX) || \
+ !defined(TPOOL_ALLOC_TYPE) || \
+ !defined(TPOOL_STRUCT)
+# error "This file can't be compiled directly, include in another source file"
+#endif
+
+#define _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) MACRO_ARG1 ## MACRO_ARG2
+#define _CONCAT(MACRO_ARG1, MACRO_ARG2) _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2)
+#define _TPOOL_PREFIX(id) _CONCAT(TPOOL_IMPL_PREFIX, _##id)
+
+/* local identifiers */
+#define pool_create _TPOOL_PREFIX(pool_create)
+#define pool_destroy _TPOOL_PREFIX(pool_destroy)
+#define pool_clear _TPOOL_PREFIX(pool_clear)
+
+#define pool_elem_alloc _TPOOL_PREFIX(pool_elem_alloc)
+#define pool_elem_calloc _TPOOL_PREFIX(pool_elem_calloc)
+#define pool_elem_free _TPOOL_PREFIX(pool_elem_free)
+
+/* private identifiers (only for this file, undefine after) */
+#define pool_alloc_chunk _TPOOL_PREFIX(pool_alloc_chunk)
+#define TPoolChunk _TPOOL_PREFIX(TPoolChunk)
+#define TPoolChunkElemFree _TPOOL_PREFIX(TPoolChunkElemFree)
+
+#ifndef TPOOL_CHUNK_SIZE
+#define TPOOL_CHUNK_SIZE (1 << 16) /* 64kb */
+#define _TPOOL_CHUNK_SIZE_UNDEF
+#endif
+
+#ifndef UNLIKELY
+# ifdef __GNUC__
+# define UNLIKELY(x) __builtin_expect(!!(x), 0)
+# else
+# define UNLIKELY(x) (x)
+# endif
+#endif
+
+#ifdef __GNUC__
+# define MAYBE_UNUSED __attribute__((unused))
+#else
+# define MAYBE_UNUSED
+#endif
+
+
+struct TPoolChunk {
+ struct TPoolChunk *prev;
+ unsigned int size;
+ unsigned int bufsize;
+ TPOOL_ALLOC_TYPE buf[0];
+};
+
+struct TPoolChunkElemFree {
+ struct TPoolChunkElemFree *next;
+};
+
+struct TPOOL_STRUCT {
+ /* Always keep at least one chunk (never NULL) */
+ struct TPoolChunk *chunk;
+ /* when NULL, allocate a new chunk */
+ struct TPoolChunkElemFree *free;
+};
+
+/**
+ * Number of elems to include per #TPoolChunk when no reserved size is passed,
+ * or we allocate past the reserved number.
+ *
+ * \note Optimize number for 64kb allocs.
+ */
+#define _TPOOL_CHUNK_DEFAULT_NUM \
+ (((1 << 16) - sizeof(struct TPoolChunk)) / sizeof(TPOOL_ALLOC_TYPE))
+
+
+/** \name Internal Memory Management
+ * \{ */
+
+static struct TPoolChunk *pool_alloc_chunk(
+ unsigned int tot_elems, struct TPoolChunk *chunk_prev)
+{
+ struct TPoolChunk *chunk = malloc(
+ sizeof(struct TPoolChunk) + (sizeof(TPOOL_ALLOC_TYPE) * tot_elems));
+ chunk->prev = chunk_prev;
+ chunk->bufsize = tot_elems;
+ chunk->size = 0;
+ return chunk;
+}
+
+static TPOOL_ALLOC_TYPE *pool_elem_alloc(struct TPOOL_STRUCT *pool)
+{
+ TPOOL_ALLOC_TYPE *elem;
+
+ if (pool->free) {
+ elem = (TPOOL_ALLOC_TYPE *)pool->free;
+ pool->free = pool->free->next;
+ }
+ else {
+ struct TPoolChunk *chunk = pool->chunk;
+ if (UNLIKELY(chunk->size == chunk->bufsize)) {
+ chunk = pool->chunk = pool_alloc_chunk(_TPOOL_CHUNK_DEFAULT_NUM, chunk);
+ }
+ elem = &chunk->buf[chunk->size++];
+ }
+
+ return elem;
+}
+
+MAYBE_UNUSED
+static TPOOL_ALLOC_TYPE *pool_elem_calloc(struct TPOOL_STRUCT *pool)
+{
+ TPOOL_ALLOC_TYPE *elem = pool_elem_alloc(pool);
+ memset(elem, 0, sizeof(*elem));
+ return elem;
+}
+
+static void pool_elem_free(struct TPOOL_STRUCT *pool, TPOOL_ALLOC_TYPE *elem)
+{
+ struct TPoolChunkElemFree *elem_free = (struct TPoolChunkElemFree *)elem;
+ elem_free->next = pool->free;
+ pool->free = elem_free;
+}
+
+static void pool_create(struct TPOOL_STRUCT *pool, unsigned int tot_reserve)
+{
+ pool->chunk = pool_alloc_chunk((tot_reserve > 1) ? tot_reserve : _TPOOL_CHUNK_DEFAULT_NUM, NULL);
+ pool->free = NULL;
+}
+
+MAYBE_UNUSED
+static void pool_clear(struct TPOOL_STRUCT *pool)
+{
+ /* Remove all except the last chunk */
+ while (pool->chunk->prev) {
+ struct TPoolChunk *chunk_prev = pool->chunk->prev;
+ free(pool->chunk);
+ pool->chunk = chunk_prev;
+ }
+ pool->chunk->size = 0;
+ pool->free = NULL;
+}
+
+static void pool_destroy(struct TPOOL_STRUCT *pool)
+{
+ struct TPoolChunk *chunk = pool->chunk;
+ do {
+ struct TPoolChunk *chunk_prev;
+ chunk_prev = chunk->prev;
+ free(chunk);
+ chunk = chunk_prev;
+ } while (chunk);
+
+ pool->chunk = NULL;
+ pool->free = NULL;
+}
+
+/** \} */
+
+#undef _TPOOL_CHUNK_DEFAULT_NUM
+#undef _CONCAT_AUX
+#undef _CONCAT
+#undef _TPOOL_PREFIX
+
+#undef TPoolChunk
+#undef TPoolChunkElemFree
+
+#ifdef _TPOOL_CHUNK_SIZE_UNDEF
+# undef TPOOL_CHUNK_SIZE
+# undef _TPOOL_CHUNK_SIZE_UNDEF
+#endif
diff --git a/extern/curve_fit_nd/intern/generic_heap.c b/extern/curve_fit_nd/intern/generic_heap.c
new file mode 100644
index 00000000000..1e2efa5b43d
--- /dev/null
+++ b/extern/curve_fit_nd/intern/generic_heap.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2016, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the <organization> nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file generic_heap.c
+ * \ingroup curve_fit
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <assert.h>
+
+#include "generic_heap.h"
+
+/* swap with a temp value */
+#define SWAP_TVAL(tval, a, b) { \
+ (tval) = (a); \
+ (a) = (b); \
+ (b) = (tval); \
+} (void)0
+
+#ifdef __GNUC__
+# define UNLIKELY(x) __builtin_expect(!!(x), 0)
+#else
+# define UNLIKELY(x) (x)
+#endif
+
+
+/***/
+
+struct HeapNode {
+ void *ptr;
+ double value;
+ unsigned int index;
+};
+
+/* heap_* pool allocator */
+#define TPOOL_IMPL_PREFIX heap
+#define TPOOL_ALLOC_TYPE HeapNode
+#define TPOOL_STRUCT HeapMemPool
+#include "generic_alloc_impl.h"
+#undef TPOOL_IMPL_PREFIX
+#undef TPOOL_ALLOC_TYPE
+#undef TPOOL_STRUCT
+
+struct Heap {
+ unsigned int size;
+ unsigned int bufsize;
+ HeapNode **tree;
+
+ struct HeapMemPool pool;
+};
+
+/** \name Internal Functions
+ * \{ */
+
+#define HEAP_PARENT(i) (((i) - 1) >> 1)
+#define HEAP_LEFT(i) (((i) << 1) + 1)
+#define HEAP_RIGHT(i) (((i) << 1) + 2)
+#define HEAP_COMPARE(a, b) ((a)->value < (b)->value)
+
+#if 0 /* UNUSED */
+#define HEAP_EQUALS(a, b) ((a)->value == (b)->value)
+#endif
+
+static void heap_swap(Heap *heap, const unsigned int i, const unsigned int j)
+{
+
+#if 0
+ SWAP(unsigned int, heap->tree[i]->index, heap->tree[j]->index);
+ SWAP(HeapNode *, heap->tree[i], heap->tree[j]);
+#else
+ HeapNode **tree = heap->tree;
+ union {
+ unsigned int index;
+ HeapNode *node;
+ } tmp;
+ SWAP_TVAL(tmp.index, tree[i]->index, tree[j]->index);
+ SWAP_TVAL(tmp.node, tree[i], tree[j]);
+#endif
+}
+
+static void heap_down(Heap *heap, unsigned int i)
+{
+ /* size won't change in the loop */
+ const unsigned int size = heap->size;
+
+ while (1) {
+ const unsigned int l = HEAP_LEFT(i);
+ const unsigned int r = HEAP_RIGHT(i);
+ unsigned int smallest;
+
+ smallest = ((l < size) && HEAP_COMPARE(heap->tree[l], heap->tree[i])) ? l : i;
+
+ if ((r < size) && HEAP_COMPARE(heap->tree[r], heap->tree[smallest])) {
+ smallest = r;
+ }
+
+ if (smallest == i) {
+ break;
+ }
+
+ heap_swap(heap, i, smallest);
+ i = smallest;
+ }
+}
+
+static void heap_up(Heap *heap, unsigned int i)
+{
+ while (i > 0) {
+ const unsigned int p = HEAP_PARENT(i);
+
+ if (HEAP_COMPARE(heap->tree[p], heap->tree[i])) {
+ break;
+ }
+ heap_swap(heap, p, i);
+ i = p;
+ }
+}
+
+/** \} */
+
+
+/** \name Public Heap API
+ * \{ */
+
+/* use when the size of the heap is known in advance */
+Heap *HEAP_new(unsigned int tot_reserve)
+{
+ Heap *heap = malloc(sizeof(Heap));
+ /* ensure we have at least one so we can keep doubling it */
+ heap->size = 0;
+ heap->bufsize = tot_reserve ? tot_reserve : 1;
+ heap->tree = malloc(heap->bufsize * sizeof(HeapNode *));
+
+ heap_pool_create(&heap->pool, tot_reserve);
+
+ return heap;
+}
+
+void HEAP_free(Heap *heap, HeapFreeFP ptrfreefp)
+{
+ if (ptrfreefp) {
+ unsigned int i;
+
+ for (i = 0; i < heap->size; i++) {
+ ptrfreefp(heap->tree[i]->ptr);
+ }
+ }
+
+ heap_pool_destroy(&heap->pool);
+
+ free(heap->tree);
+ free(heap);
+}
+
+void HEAP_clear(Heap *heap, HeapFreeFP ptrfreefp)
+{
+ if (ptrfreefp) {
+ unsigned int i;
+
+ for (i = 0; i < heap->size; i++) {
+ ptrfreefp(heap->tree[i]->ptr);
+ }
+ }
+ heap->size = 0;
+
+ heap_pool_clear(&heap->pool);
+}
+
+HeapNode *HEAP_insert(Heap *heap, double value, void *ptr)
+{
+ HeapNode *node;
+
+ if (UNLIKELY(heap->size >= heap->bufsize)) {
+ heap->bufsize *= 2;
+ heap->tree = realloc(heap->tree, heap->bufsize * sizeof(*heap->tree));
+ }
+
+ node = heap_pool_elem_alloc(&heap->pool);
+
+ node->ptr = ptr;
+ node->value = value;
+ node->index = heap->size;
+
+ heap->tree[node->index] = node;
+
+ heap->size++;
+
+ heap_up(heap, node->index);
+
+ return node;
+}
+
+bool HEAP_is_empty(Heap *heap)
+{
+ return (heap->size == 0);
+}
+
+unsigned int HEAP_size(Heap *heap)
+{
+ return heap->size;
+}
+
+HeapNode *HEAP_top(Heap *heap)
+{
+ return heap->tree[0];
+}
+
+double HEAP_top_value(Heap *heap)
+{
+ return heap->tree[0]->value;
+}
+
+void *HEAP_popmin(Heap *heap)
+{
+ void *ptr = heap->tree[0]->ptr;
+
+ assert(heap->size != 0);
+
+ heap_pool_elem_free(&heap->pool, heap->tree[0]);
+
+ if (--heap->size) {
+ heap_swap(heap, 0, heap->size);
+ heap_down(heap, 0);
+ }
+
+ return ptr;
+}
+
+void HEAP_remove(Heap *heap, HeapNode *node)
+{
+ unsigned int i = node->index;
+
+ assert(heap->size != 0);
+
+ while (i > 0) {
+ unsigned int p = HEAP_PARENT(i);
+
+ heap_swap(heap, p, i);
+ i = p;
+ }
+
+ HEAP_popmin(heap);
+}
+
+double HEAP_node_value(HeapNode *node)
+{
+ return node->value;
+}
+
+void *HEAP_node_ptr(HeapNode *node)
+{
+ return node->ptr;
+}
diff --git a/extern/curve_fit_nd/intern/generic_heap.h b/extern/curve_fit_nd/intern/generic_heap.h
new file mode 100644
index 00000000000..e39344cf076
--- /dev/null
+++ b/extern/curve_fit_nd/intern/generic_heap.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2016, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the <organization> nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __GENERIC_HEAP_H__
+#define __GENERIC_HEAP_H__
+
+/** \file generic_heap.h
+ * \ingroup curve_fit
+ */
+
+struct Heap;
+struct HeapNode;
+typedef struct Heap Heap;
+typedef struct HeapNode HeapNode;
+
+typedef void (*HeapFreeFP)(void *ptr);
+
+Heap *HEAP_new(unsigned int tot_reserve);
+bool HEAP_is_empty(Heap *heap);
+void HEAP_free(Heap *heap, HeapFreeFP ptrfreefp);
+void *HEAP_node_ptr(HeapNode *node);
+void HEAP_remove(Heap *heap, HeapNode *node);
+HeapNode *HEAP_insert(Heap *heap, double value, void *ptr);
+void *HEAP_popmin(Heap *heap);
+void HEAP_clear(Heap *heap, HeapFreeFP ptrfreefp);
+unsigned int HEAP_size(Heap *heap);
+HeapNode *HEAP_top(Heap *heap);
+double HEAP_top_value(Heap *heap);
+double HEAP_node_value(HeapNode *node);
+
+#endif /* __GENERIC_HEAP_IMPL_H__ */
diff --git a/extern/gflags/README.libmv b/extern/gflags/README.blender
index bf58ccb5fd2..0c8ea9a2be3 100644
--- a/extern/gflags/README.libmv
+++ b/extern/gflags/README.blender
@@ -1,5 +1,5 @@
Project: Google Flags
-URL: http://code.google.com/p/google-gflags/
+URL: https://github.com/gflags/gflags
License: New BSD
Upstream version: 2.2.0 (9db82895)
Local modifications:
@@ -17,3 +17,7 @@ Local modifications:
- Applied some modifications from fork https://github.com/Nazg-Gul/gflags.git
(see https://github.com/gflags/gflags/pull/129)
+
+- Avoid attemot of acquiring mutex lock in FlagRegistry::GlobalRegistry when
+ doing static flags initialization. See d81dd2d in Blender repository.
+
diff --git a/extern/glog/README.libmv b/extern/glog/README.blender
index 6e82cbbacdf..288e78b3259 100644
--- a/extern/glog/README.libmv
+++ b/extern/glog/README.blender
@@ -1,5 +1,5 @@
Project: Google Logging
-URL: http://code.google.com/p/google-glog/
+URL: https://github.com/google/glog
License: New BSD
Upstream version: 0.3.4, 4d391fe
Local modifications:
diff --git a/extern/gmock/CMakeLists.txt b/extern/gmock/CMakeLists.txt
new file mode 100644
index 00000000000..c0c87009328
--- /dev/null
+++ b/extern/gmock/CMakeLists.txt
@@ -0,0 +1,66 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2014, Blender Foundation
+# All rights reserved.
+#
+# Contributor(s): Sergey Sharybin
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ include
+)
+
+set(INC_SYS
+ ../gtest/include
+)
+
+set(SRC
+ # src/gmock-all.cc
+
+ src/gmock-cardinalities.cc
+ src/gmock.cc
+ src/gmock-internal-utils.cc
+ src/gmock_main.cc
+ src/gmock-matchers.cc
+ src/gmock-spec-builders.cc
+)
+
+set(SRC_HEADERS
+ include/gmock/gmock-actions.h
+ include/gmock/gmock-cardinalities.h
+ include/gmock/gmock-generated-actions.h
+ include/gmock/gmock-generated-function-mockers.h
+ include/gmock/gmock-generated-matchers.h
+ include/gmock/gmock-generated-nice-strict.h
+ include/gmock/gmock.h
+ include/gmock/gmock-matchers.h
+ include/gmock/gmock-more-actions.h
+ include/gmock/gmock-more-matchers.h
+ include/gmock/gmock-spec-builders.h
+ include/gmock/internal/custom/gmock-generated-actions.h
+ include/gmock/internal/custom/gmock-matchers.h
+ include/gmock/internal/custom/gmock-port.h
+ include/gmock/internal/gmock-generated-internal-utils.h
+ include/gmock/internal/gmock-internal-utils.h
+ include/gmock/internal/gmock-port.h
+)
+
+include_directories(${INC})
+include_directories(SYSTEM ${INC_SYS})
+add_library(extern_gmock ${SRC} ${SRC_HEADERS})
diff --git a/extern/gmock/LICENSE b/extern/gmock/LICENSE
new file mode 100644
index 00000000000..1941a11f8ce
--- /dev/null
+++ b/extern/gmock/LICENSE
@@ -0,0 +1,28 @@
+Copyright 2008, Google Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/extern/gtest/README b/extern/gmock/README.blender
index 27e4eff92c9..41dda92c19c 100644
--- a/extern/gtest/README
+++ b/extern/gmock/README.blender
@@ -1,7 +1,7 @@
Project: Google C++ Testing Framework
-URL: http://code.google.com/p/googletest
+URL: https://github.com/google/googletest
License: New BSD
-Upstream version: 1.7.0
+Upstream version: 1.7.0 (ec44c6c)
Local modifications:
None.
diff --git a/extern/gmock/README.md b/extern/gmock/README.md
new file mode 100644
index 00000000000..332beab3881
--- /dev/null
+++ b/extern/gmock/README.md
@@ -0,0 +1,333 @@
+## Google Mock ##
+
+The Google C++ mocking framework.
+
+### Overview ###
+
+Google's framework for writing and using C++ mock classes.
+It can help you derive better designs of your system and write better tests.
+
+It is inspired by:
+
+ * [jMock](http://www.jmock.org/),
+ * [EasyMock](http://www.easymock.org/), and
+ * [Hamcrest](http://code.google.com/p/hamcrest/),
+
+and designed with C++'s specifics in mind.
+
+Google mock:
+
+ * lets you create mock classes trivially using simple macros.
+ * supports a rich set of matchers and actions.
+ * handles unordered, partially ordered, or completely ordered expectations.
+ * is extensible by users.
+
+We hope you find it useful!
+
+### Features ###
+
+ * Provides a declarative syntax for defining mocks.
+ * Can easily define partial (hybrid) mocks, which are a cross of real
+ and mock objects.
+ * Handles functions of arbitrary types and overloaded functions.
+ * Comes with a rich set of matchers for validating function arguments.
+ * Uses an intuitive syntax for controlling the behavior of a mock.
+ * Does automatic verification of expectations (no record-and-replay needed).
+ * Allows arbitrary (partial) ordering constraints on
+ function calls to be expressed,.
+ * Lets a user extend it by defining new matchers and actions.
+ * Does not use exceptions.
+ * Is easy to learn and use.
+
+Please see the project page above for more information as well as the
+mailing list for questions, discussions, and development. There is
+also an IRC channel on OFTC (irc.oftc.net) #gtest available. Please
+join us!
+
+Please note that code under [scripts/generator](scripts/generator/) is
+from [cppclean](http://code.google.com/p/cppclean/) and released under
+the Apache License, which is different from Google Mock's license.
+
+## Getting Started ##
+
+If you are new to the project, we suggest that you read the user
+documentation in the following order:
+
+ * Learn the [basics](../googletest/docs/Primer.md) of
+ Google Test, if you choose to use Google Mock with it (recommended).
+ * Read [Google Mock for Dummies](docs/ForDummies.md).
+ * Read the instructions below on how to build Google Mock.
+
+You can also watch Zhanyong's [talk](http://www.youtube.com/watch?v=sYpCyLI47rM) on Google Mock's usage and implementation.
+
+Once you understand the basics, check out the rest of the docs:
+
+ * [CheatSheet](docs/CheatSheet.md) - all the commonly used stuff
+ at a glance.
+ * [CookBook](docs/CookBook.md) - recipes for getting things done,
+ including advanced techniques.
+
+If you need help, please check the
+[KnownIssues](docs/KnownIssues.md) and
+[FrequentlyAskedQuestions](docs/FrequentlyAskedQuestions.md) before
+posting a question on the
+[discussion group](http://groups.google.com/group/googlemock).
+
+
+### Using Google Mock Without Google Test ###
+
+Google Mock is not a testing framework itself. Instead, it needs a
+testing framework for writing tests. Google Mock works seamlessly
+with [Google Test](http://code.google.com/p/googletest/), but
+you can also use it with [any C++ testing framework](googlemock/ForDummies.md#Using_Google_Mock_with_Any_Testing_Framework).
+
+### Requirements for End Users ###
+
+Google Mock is implemented on top of [Google Test](
+http://github.com/google/googletest/), and depends on it.
+You must use the bundled version of Google Test when using Google Mock.
+
+You can also easily configure Google Mock to work with another testing
+framework, although it will still need Google Test. Please read
+["Using_Google_Mock_with_Any_Testing_Framework"](
+ docs/ForDummies.md#Using_Google_Mock_with_Any_Testing_Framework)
+for instructions.
+
+Google Mock depends on advanced C++ features and thus requires a more
+modern compiler. The following are needed to use Google Mock:
+
+#### Linux Requirements ####
+
+ * GNU-compatible Make or "gmake"
+ * POSIX-standard shell
+ * POSIX(-2) Regular Expressions (regex.h)
+ * C++98-standard-compliant compiler (e.g. GCC 3.4 or newer)
+
+#### Windows Requirements ####
+
+ * Microsoft Visual C++ 8.0 SP1 or newer
+
+#### Mac OS X Requirements ####
+
+ * Mac OS X 10.4 Tiger or newer
+ * Developer Tools Installed
+
+### Requirements for Contributors ###
+
+We welcome patches. If you plan to contribute a patch, you need to
+build Google Mock and its tests, which has further requirements:
+
+ * Automake version 1.9 or newer
+ * Autoconf version 2.59 or newer
+ * Libtool / Libtoolize
+ * Python version 2.3 or newer (for running some of the tests and
+ re-generating certain source files from templates)
+
+### Building Google Mock ###
+
+#### Preparing to Build (Unix only) ####
+
+If you are using a Unix system and plan to use the GNU Autotools build
+system to build Google Mock (described below), you'll need to
+configure it now.
+
+To prepare the Autotools build system:
+
+ cd googlemock
+ autoreconf -fvi
+
+To build Google Mock and your tests that use it, you need to tell your
+build system where to find its headers and source files. The exact
+way to do it depends on which build system you use, and is usually
+straightforward.
+
+This section shows how you can integrate Google Mock into your
+existing build system.
+
+Suppose you put Google Mock in directory `${GMOCK_DIR}` and Google Test
+in `${GTEST_DIR}` (the latter is `${GMOCK_DIR}/gtest` by default). To
+build Google Mock, create a library build target (or a project as
+called by Visual Studio and Xcode) to compile
+
+ ${GTEST_DIR}/src/gtest-all.cc and ${GMOCK_DIR}/src/gmock-all.cc
+
+with
+
+ ${GTEST_DIR}/include and ${GMOCK_DIR}/include
+
+in the system header search path, and
+
+ ${GTEST_DIR} and ${GMOCK_DIR}
+
+in the normal header search path. Assuming a Linux-like system and gcc,
+something like the following will do:
+
+ g++ -isystem ${GTEST_DIR}/include -I${GTEST_DIR} \
+ -isystem ${GMOCK_DIR}/include -I${GMOCK_DIR} \
+ -pthread -c ${GTEST_DIR}/src/gtest-all.cc
+ g++ -isystem ${GTEST_DIR}/include -I${GTEST_DIR} \
+ -isystem ${GMOCK_DIR}/include -I${GMOCK_DIR} \
+ -pthread -c ${GMOCK_DIR}/src/gmock-all.cc
+ ar -rv libgmock.a gtest-all.o gmock-all.o
+
+(We need -pthread as Google Test and Google Mock use threads.)
+
+Next, you should compile your test source file with
+${GTEST\_DIR}/include and ${GMOCK\_DIR}/include in the header search
+path, and link it with gmock and any other necessary libraries:
+
+ g++ -isystem ${GTEST_DIR}/include -isystem ${GMOCK_DIR}/include \
+ -pthread path/to/your_test.cc libgmock.a -o your_test
+
+As an example, the make/ directory contains a Makefile that you can
+use to build Google Mock on systems where GNU make is available
+(e.g. Linux, Mac OS X, and Cygwin). It doesn't try to build Google
+Mock's own tests. Instead, it just builds the Google Mock library and
+a sample test. You can use it as a starting point for your own build
+script.
+
+If the default settings are correct for your environment, the
+following commands should succeed:
+
+ cd ${GMOCK_DIR}/make
+ make
+ ./gmock_test
+
+If you see errors, try to tweak the contents of
+[make/Makefile](make/Makefile) to make them go away.
+
+### Windows ###
+
+The msvc/2005 directory contains VC++ 2005 projects and the msvc/2010
+directory contains VC++ 2010 projects for building Google Mock and
+selected tests.
+
+Change to the appropriate directory and run "msbuild gmock.sln" to
+build the library and tests (or open the gmock.sln in the MSVC IDE).
+If you want to create your own project to use with Google Mock, you'll
+have to configure it to use the `gmock_config` propety sheet. For that:
+
+ * Open the Property Manager window (View | Other Windows | Property Manager)
+ * Right-click on your project and select "Add Existing Property Sheet..."
+ * Navigate to `gmock_config.vsprops` or `gmock_config.props` and select it.
+ * In Project Properties | Configuration Properties | General | Additional
+ Include Directories, type <path to Google Mock>/include.
+
+### Tweaking Google Mock ###
+
+Google Mock can be used in diverse environments. The default
+configuration may not work (or may not work well) out of the box in
+some environments. However, you can easily tweak Google Mock by
+defining control macros on the compiler command line. Generally,
+these macros are named like `GTEST_XYZ` and you define them to either 1
+or 0 to enable or disable a certain feature.
+
+We list the most frequently used macros below. For a complete list,
+see file [${GTEST\_DIR}/include/gtest/internal/gtest-port.h](
+../googletest/include/gtest/internal/gtest-port.h).
+
+### Choosing a TR1 Tuple Library ###
+
+Google Mock uses the C++ Technical Report 1 (TR1) tuple library
+heavily. Unfortunately TR1 tuple is not yet widely available with all
+compilers. The good news is that Google Test 1.4.0+ implements a
+subset of TR1 tuple that's enough for Google Mock's need. Google Mock
+will automatically use that implementation when the compiler doesn't
+provide TR1 tuple.
+
+Usually you don't need to care about which tuple library Google Test
+and Google Mock use. However, if your project already uses TR1 tuple,
+you need to tell Google Test and Google Mock to use the same TR1 tuple
+library the rest of your project uses, or the two tuple
+implementations will clash. To do that, add
+
+ -DGTEST_USE_OWN_TR1_TUPLE=0
+
+to the compiler flags while compiling Google Test, Google Mock, and
+your tests. If you want to force Google Test and Google Mock to use
+their own tuple library, just add
+
+ -DGTEST_USE_OWN_TR1_TUPLE=1
+
+to the compiler flags instead.
+
+If you want to use Boost's TR1 tuple library with Google Mock, please
+refer to the Boost website (http://www.boost.org/) for how to obtain
+it and set it up.
+
+### As a Shared Library (DLL) ###
+
+Google Mock is compact, so most users can build and link it as a static
+library for the simplicity. Google Mock can be used as a DLL, but the
+same DLL must contain Google Test as well. See
+[Google Test's README][gtest_readme]
+for instructions on how to set up necessary compiler settings.
+
+### Tweaking Google Mock ###
+
+Most of Google Test's control macros apply to Google Mock as well.
+Please see [Google Test's README][gtest_readme] for how to tweak them.
+
+### Upgrading from an Earlier Version ###
+
+We strive to keep Google Mock releases backward compatible.
+Sometimes, though, we have to make some breaking changes for the
+users' long-term benefits. This section describes what you'll need to
+do if you are upgrading from an earlier version of Google Mock.
+
+#### Upgrading from 1.1.0 or Earlier ####
+
+You may need to explicitly enable or disable Google Test's own TR1
+tuple library. See the instructions in section "[Choosing a TR1 Tuple
+Library](../googletest/#choosing-a-tr1-tuple-library)".
+
+#### Upgrading from 1.4.0 or Earlier ####
+
+On platforms where the pthread library is available, Google Test and
+Google Mock use it in order to be thread-safe. For this to work, you
+may need to tweak your compiler and/or linker flags. Please see the
+"[Multi-threaded Tests](../googletest#multi-threaded-tests
+)" section in file Google Test's README for what you may need to do.
+
+If you have custom matchers defined using `MatcherInterface` or
+`MakePolymorphicMatcher()`, you'll need to update their definitions to
+use the new matcher API (
+[monomorphic](http://code.google.com/p/googlemock/wiki/CookBook#Writing_New_Monomorphic_Matchers),
+[polymorphic](http://code.google.com/p/googlemock/wiki/CookBook#Writing_New_Polymorphic_Matchers)).
+Matchers defined using `MATCHER()` or `MATCHER_P*()` aren't affected.
+
+### Developing Google Mock ###
+
+This section discusses how to make your own changes to Google Mock.
+
+#### Testing Google Mock Itself ####
+
+To make sure your changes work as intended and don't break existing
+functionality, you'll want to compile and run Google Test's own tests.
+For that you'll need Autotools. First, make sure you have followed
+the instructions above to configure Google Mock.
+Then, create a build output directory and enter it. Next,
+
+ ${GMOCK_DIR}/configure # try --help for more info
+
+Once you have successfully configured Google Mock, the build steps are
+standard for GNU-style OSS packages.
+
+ make # Standard makefile following GNU conventions
+ make check # Builds and runs all tests - all should pass.
+
+Note that when building your project against Google Mock, you are building
+against Google Test as well. There is no need to configure Google Test
+separately.
+
+#### Contributing a Patch ####
+
+We welcome patches.
+Please read the [Developer's Guide](docs/DevGuide.md)
+for how you can contribute. In particular, make sure you have signed
+the Contributor License Agreement, or we won't be able to accept the
+patch.
+
+Happy testing!
+
+[gtest_readme]: ../googletest/README.md "googletest"
diff --git a/extern/gmock/include/gmock/gmock-actions.h b/extern/gmock/include/gmock/gmock-actions.h
new file mode 100644
index 00000000000..b3f654af348
--- /dev/null
+++ b/extern/gmock/include/gmock/gmock-actions.h
@@ -0,0 +1,1205 @@
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Google Mock - a framework for writing C++ mock classes.
+//
+// This file implements some commonly used actions.
+
+#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_
+#define GMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_
+
+#ifndef _WIN32_WCE
+# include <errno.h>
+#endif
+
+#include <algorithm>
+#include <string>
+
+#include "gmock/internal/gmock-internal-utils.h"
+#include "gmock/internal/gmock-port.h"
+
+#if GTEST_HAS_STD_TYPE_TRAITS_ // Defined by gtest-port.h via gmock-port.h.
+#include <type_traits>
+#endif
+
+namespace testing {
+
+// To implement an action Foo, define:
+// 1. a class FooAction that implements the ActionInterface interface, and
+// 2. a factory function that creates an Action object from a
+// const FooAction*.
+//
+// The two-level delegation design follows that of Matcher, providing
+// consistency for extension developers. It also eases ownership
+// management as Action objects can now be copied like plain values.
+
+namespace internal {
+
+template <typename F1, typename F2>
+class ActionAdaptor;
+
+// BuiltInDefaultValueGetter<T, true>::Get() returns a
+// default-constructed T value. BuiltInDefaultValueGetter<T,
+// false>::Get() crashes with an error.
+//
+// This primary template is used when kDefaultConstructible is true.
+template <typename T, bool kDefaultConstructible>
+struct BuiltInDefaultValueGetter {
+ static T Get() { return T(); }
+};
+template <typename T>
+struct BuiltInDefaultValueGetter<T, false> {
+ static T Get() {
+ Assert(false, __FILE__, __LINE__,
+ "Default action undefined for the function return type.");
+ return internal::Invalid<T>();
+ // The above statement will never be reached, but is required in
+ // order for this function to compile.
+ }
+};
+
+// BuiltInDefaultValue<T>::Get() returns the "built-in" default value
+// for type T, which is NULL when T is a raw pointer type, 0 when T is
+// a numeric type, false when T is bool, or "" when T is string or
+// std::string. In addition, in C++11 and above, it turns a
+// default-constructed T value if T is default constructible. For any
+// other type T, the built-in default T value is undefined, and the
+// function will abort the process.
+template <typename T>
+class BuiltInDefaultValue {
+ public:
+#if GTEST_HAS_STD_TYPE_TRAITS_
+ // This function returns true iff type T has a built-in default value.
+ static bool Exists() {
+ return ::std::is_default_constructible<T>::value;
+ }
+
+ static T Get() {
+ return BuiltInDefaultValueGetter<
+ T, ::std::is_default_constructible<T>::value>::Get();
+ }
+
+#else // GTEST_HAS_STD_TYPE_TRAITS_
+ // This function returns true iff type T has a built-in default value.
+ static bool Exists() {
+ return false;
+ }
+
+ static T Get() {
+ return BuiltInDefaultValueGetter<T, false>::Get();
+ }
+
+#endif // GTEST_HAS_STD_TYPE_TRAITS_
+};
+
+// This partial specialization says that we use the same built-in
+// default value for T and const T.
+template <typename T>
+class BuiltInDefaultValue<const T> {
+ public:
+ static bool Exists() { return BuiltInDefaultValue<T>::Exists(); }
+ static T Get() { return BuiltInDefaultValue<T>::Get(); }
+};
+
+// This partial specialization defines the default values for pointer
+// types.
+template <typename T>
+class BuiltInDefaultValue<T*> {
+ public:
+ static bool Exists() { return true; }
+ static T* Get() { return NULL; }
+};
+
+// The following specializations define the default values for
+// specific types we care about.
+#define GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(type, value) \
+ template <> \
+ class BuiltInDefaultValue<type> { \
+ public: \
+ static bool Exists() { return true; } \
+ static type Get() { return value; } \
+ }
+
+GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(void, ); // NOLINT
+#if GTEST_HAS_GLOBAL_STRING
+GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(::string, "");
+#endif // GTEST_HAS_GLOBAL_STRING
+GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(::std::string, "");
+GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(bool, false);
+GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned char, '\0');
+GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed char, '\0');
+GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(char, '\0');
+
+// There's no need for a default action for signed wchar_t, as that
+// type is the same as wchar_t for gcc, and invalid for MSVC.
+//
+// There's also no need for a default action for unsigned wchar_t, as
+// that type is the same as unsigned int for gcc, and invalid for
+// MSVC.
+#if GMOCK_WCHAR_T_IS_NATIVE_
+GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(wchar_t, 0U); // NOLINT
+#endif
+
+GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned short, 0U); // NOLINT
+GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed short, 0); // NOLINT
+GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned int, 0U);
+GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed int, 0);
+GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned long, 0UL); // NOLINT
+GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed long, 0L); // NOLINT
+GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(UInt64, 0);
+GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(Int64, 0);
+GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(float, 0);
+GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(double, 0);
+
+#undef GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_
+
+} // namespace internal
+
+// When an unexpected function call is encountered, Google Mock will
+// let it return a default value if the user has specified one for its
+// return type, or if the return type has a built-in default value;
+// otherwise Google Mock won't know what value to return and will have
+// to abort the process.
+//
+// The DefaultValue<T> class allows a user to specify the
+// default value for a type T that is both copyable and publicly
+// destructible (i.e. anything that can be used as a function return
+// type). The usage is:
+//
+// // Sets the default value for type T to be foo.
+// DefaultValue<T>::Set(foo);
+template <typename T>
+class DefaultValue {
+ public:
+ // Sets the default value for type T; requires T to be
+ // copy-constructable and have a public destructor.
+ static void Set(T x) {
+ delete producer_;
+ producer_ = new FixedValueProducer(x);
+ }
+
+ // Provides a factory function to be called to generate the default value.
+ // This method can be used even if T is only move-constructible, but it is not
+ // limited to that case.
+ typedef T (*FactoryFunction)();
+ static void SetFactory(FactoryFunction factory) {
+ delete producer_;
+ producer_ = new FactoryValueProducer(factory);
+ }
+
+ // Unsets the default value for type T.
+ static void Clear() {
+ delete producer_;
+ producer_ = NULL;
+ }
+
+ // Returns true iff the user has set the default value for type T.
+ static bool IsSet() { return producer_ != NULL; }
+
+ // Returns true if T has a default return value set by the user or there
+ // exists a built-in default value.
+ static bool Exists() {
+ return IsSet() || internal::BuiltInDefaultValue<T>::Exists();
+ }
+
+ // Returns the default value for type T if the user has set one;
+ // otherwise returns the built-in default value. Requires that Exists()
+ // is true, which ensures that the return value is well-defined.
+ static T Get() {
+ return producer_ == NULL ?
+ internal::BuiltInDefaultValue<T>::Get() : producer_->Produce();
+ }
+
+ private:
+ class ValueProducer {
+ public:
+ virtual ~ValueProducer() {}
+ virtual T Produce() = 0;
+ };
+
+ class FixedValueProducer : public ValueProducer {
+ public:
+ explicit FixedValueProducer(T value) : value_(value) {}
+ virtual T Produce() { return value_; }
+
+ private:
+ const T value_;
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(FixedValueProducer);
+ };
+
+ class FactoryValueProducer : public ValueProducer {
+ public:
+ explicit FactoryValueProducer(FactoryFunction factory)
+ : factory_(factory) {}
+ virtual T Produce() { return factory_(); }
+
+ private:
+ const FactoryFunction factory_;
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(FactoryValueProducer);
+ };
+
+ static ValueProducer* producer_;
+};
+
+// This partial specialization allows a user to set default values for
+// reference types.
+template <typename T>
+class DefaultValue<T&> {
+ public:
+ // Sets the default value for type T&.
+ static void Set(T& x) { // NOLINT
+ address_ = &x;
+ }
+
+ // Unsets the default value for type T&.
+ static void Clear() {
+ address_ = NULL;
+ }
+
+ // Returns true iff the user has set the default value for type T&.
+ static bool IsSet() { return address_ != NULL; }
+
+ // Returns true if T has a default return value set by the user or there
+ // exists a built-in default value.
+ static bool Exists() {
+ return IsSet() || internal::BuiltInDefaultValue<T&>::Exists();
+ }
+
+ // Returns the default value for type T& if the user has set one;
+ // otherwise returns the built-in default value if there is one;
+ // otherwise aborts the process.
+ static T& Get() {
+ return address_ == NULL ?
+ internal::BuiltInDefaultValue<T&>::Get() : *address_;
+ }
+
+ private:
+ static T* address_;
+};
+
+// This specialization allows DefaultValue<void>::Get() to
+// compile.
+template <>
+class DefaultValue<void> {
+ public:
+ static bool Exists() { return true; }
+ static void Get() {}
+};
+
+// Points to the user-set default value for type T.
+template <typename T>
+typename DefaultValue<T>::ValueProducer* DefaultValue<T>::producer_ = NULL;
+
+// Points to the user-set default value for type T&.
+template <typename T>
+T* DefaultValue<T&>::address_ = NULL;
+
+// Implement this interface to define an action for function type F.
+template <typename F>
+class ActionInterface {
+ public:
+ typedef typename internal::Function<F>::Result Result;
+ typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
+
+ ActionInterface() {}
+ virtual ~ActionInterface() {}
+
+ // Performs the action. This method is not const, as in general an
+ // action can have side effects and be stateful. For example, a
+ // get-the-next-element-from-the-collection action will need to
+ // remember the current element.
+ virtual Result Perform(const ArgumentTuple& args) = 0;
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ActionInterface);
+};
+
+// An Action<F> is a copyable and IMMUTABLE (except by assignment)
+// object that represents an action to be taken when a mock function
+// of type F is called. The implementation of Action<T> is just a
+// linked_ptr to const ActionInterface<T>, so copying is fairly cheap.
+// Don't inherit from Action!
+//
+// You can view an object implementing ActionInterface<F> as a
+// concrete action (including its current state), and an Action<F>
+// object as a handle to it.
+template <typename F>
+class Action {
+ public:
+ typedef typename internal::Function<F>::Result Result;
+ typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
+
+ // Constructs a null Action. Needed for storing Action objects in
+ // STL containers.
+ Action() : impl_(NULL) {}
+
+ // Constructs an Action from its implementation. A NULL impl is
+ // used to represent the "do-default" action.
+ explicit Action(ActionInterface<F>* impl) : impl_(impl) {}
+
+ // Copy constructor.
+ Action(const Action& action) : impl_(action.impl_) {}
+
+ // This constructor allows us to turn an Action<Func> object into an
+ // Action<F>, as long as F's arguments can be implicitly converted
+ // to Func's and Func's return type can be implicitly converted to
+ // F's.
+ template <typename Func>
+ explicit Action(const Action<Func>& action);
+
+ // Returns true iff this is the DoDefault() action.
+ bool IsDoDefault() const { return impl_.get() == NULL; }
+
+ // Performs the action. Note that this method is const even though
+ // the corresponding method in ActionInterface is not. The reason
+ // is that a const Action<F> means that it cannot be re-bound to
+ // another concrete action, not that the concrete action it binds to
+ // cannot change state. (Think of the difference between a const
+ // pointer and a pointer to const.)
+ Result Perform(const ArgumentTuple& args) const {
+ internal::Assert(
+ !IsDoDefault(), __FILE__, __LINE__,
+ "You are using DoDefault() inside a composite action like "
+ "DoAll() or WithArgs(). This is not supported for technical "
+ "reasons. Please instead spell out the default action, or "
+ "assign the default action to an Action variable and use "
+ "the variable in various places.");
+ return impl_->Perform(args);
+ }
+
+ private:
+ template <typename F1, typename F2>
+ friend class internal::ActionAdaptor;
+
+ internal::linked_ptr<ActionInterface<F> > impl_;
+};
+
+// The PolymorphicAction class template makes it easy to implement a
+// polymorphic action (i.e. an action that can be used in mock
+// functions of than one type, e.g. Return()).
+//
+// To define a polymorphic action, a user first provides a COPYABLE
+// implementation class that has a Perform() method template:
+//
+// class FooAction {
+// public:
+// template <typename Result, typename ArgumentTuple>
+// Result Perform(const ArgumentTuple& args) const {
+// // Processes the arguments and returns a result, using
+// // tr1::get<N>(args) to get the N-th (0-based) argument in the tuple.
+// }
+// ...
+// };
+//
+// Then the user creates the polymorphic action using
+// MakePolymorphicAction(object) where object has type FooAction. See
+// the definition of Return(void) and SetArgumentPointee<N>(value) for
+// complete examples.
+template <typename Impl>
+class PolymorphicAction {
+ public:
+ explicit PolymorphicAction(const Impl& impl) : impl_(impl) {}
+
+ template <typename F>
+ operator Action<F>() const {
+ return Action<F>(new MonomorphicImpl<F>(impl_));
+ }
+
+ private:
+ template <typename F>
+ class MonomorphicImpl : public ActionInterface<F> {
+ public:
+ typedef typename internal::Function<F>::Result Result;
+ typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
+
+ explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {}
+
+ virtual Result Perform(const ArgumentTuple& args) {
+ return impl_.template Perform<Result>(args);
+ }
+
+ private:
+ Impl impl_;
+
+ GTEST_DISALLOW_ASSIGN_(MonomorphicImpl);
+ };
+
+ Impl impl_;
+
+ GTEST_DISALLOW_ASSIGN_(PolymorphicAction);
+};
+
+// Creates an Action from its implementation and returns it. The
+// created Action object owns the implementation.
+template <typename F>
+Action<F> MakeAction(ActionInterface<F>* impl) {
+ return Action<F>(impl);
+}
+
+// Creates a polymorphic action from its implementation. This is
+// easier to use than the PolymorphicAction<Impl> constructor as it
+// doesn't require you to explicitly write the template argument, e.g.
+//
+// MakePolymorphicAction(foo);
+// vs
+// PolymorphicAction<TypeOfFoo>(foo);
+template <typename Impl>
+inline PolymorphicAction<Impl> MakePolymorphicAction(const Impl& impl) {
+ return PolymorphicAction<Impl>(impl);
+}
+
+namespace internal {
+
+// Allows an Action<F2> object to pose as an Action<F1>, as long as F2
+// and F1 are compatible.
+template <typename F1, typename F2>
+class ActionAdaptor : public ActionInterface<F1> {
+ public:
+ typedef typename internal::Function<F1>::Result Result;
+ typedef typename internal::Function<F1>::ArgumentTuple ArgumentTuple;
+
+ explicit ActionAdaptor(const Action<F2>& from) : impl_(from.impl_) {}
+
+ virtual Result Perform(const ArgumentTuple& args) {
+ return impl_->Perform(args);
+ }
+
+ private:
+ const internal::linked_ptr<ActionInterface<F2> > impl_;
+
+ GTEST_DISALLOW_ASSIGN_(ActionAdaptor);
+};
+
+// Helper struct to specialize ReturnAction to execute a move instead of a copy
+// on return. Useful for move-only types, but could be used on any type.
+template <typename T>
+struct ByMoveWrapper {
+ explicit ByMoveWrapper(T value) : payload(internal::move(value)) {}
+ T payload;
+};
+
+// Implements the polymorphic Return(x) action, which can be used in
+// any function that returns the type of x, regardless of the argument
+// types.
+//
+// Note: The value passed into Return must be converted into
+// Function<F>::Result when this action is cast to Action<F> rather than
+// when that action is performed. This is important in scenarios like
+//
+// MOCK_METHOD1(Method, T(U));
+// ...
+// {
+// Foo foo;
+// X x(&foo);
+// EXPECT_CALL(mock, Method(_)).WillOnce(Return(x));
+// }
+//
+// In the example above the variable x holds reference to foo which leaves
+// scope and gets destroyed. If copying X just copies a reference to foo,
+// that copy will be left with a hanging reference. If conversion to T
+// makes a copy of foo, the above code is safe. To support that scenario, we
+// need to make sure that the type conversion happens inside the EXPECT_CALL
+// statement, and conversion of the result of Return to Action<T(U)> is a
+// good place for that.
+//
+template <typename R>
+class ReturnAction {
+ public:
+ // Constructs a ReturnAction object from the value to be returned.
+ // 'value' is passed by value instead of by const reference in order
+ // to allow Return("string literal") to compile.
+ explicit ReturnAction(R value) : value_(new R(internal::move(value))) {}
+
+ // This template type conversion operator allows Return(x) to be
+ // used in ANY function that returns x's type.
+ template <typename F>
+ operator Action<F>() const {
+ // Assert statement belongs here because this is the best place to verify
+ // conditions on F. It produces the clearest error messages
+ // in most compilers.
+ // Impl really belongs in this scope as a local class but can't
+ // because MSVC produces duplicate symbols in different translation units
+ // in this case. Until MS fixes that bug we put Impl into the class scope
+ // and put the typedef both here (for use in assert statement) and
+ // in the Impl class. But both definitions must be the same.
+ typedef typename Function<F>::Result Result;
+ GTEST_COMPILE_ASSERT_(
+ !is_reference<Result>::value,
+ use_ReturnRef_instead_of_Return_to_return_a_reference);
+ return Action<F>(new Impl<R, F>(value_));
+ }
+
+ private:
+ // Implements the Return(x) action for a particular function type F.
+ template <typename R_, typename F>
+ class Impl : public ActionInterface<F> {
+ public:
+ typedef typename Function<F>::Result Result;
+ typedef typename Function<F>::ArgumentTuple ArgumentTuple;
+
+ // The implicit cast is necessary when Result has more than one
+ // single-argument constructor (e.g. Result is std::vector<int>) and R
+ // has a type conversion operator template. In that case, value_(value)
+ // won't compile as the compiler doesn't known which constructor of
+ // Result to call. ImplicitCast_ forces the compiler to convert R to
+ // Result without considering explicit constructors, thus resolving the
+ // ambiguity. value_ is then initialized using its copy constructor.
+ explicit Impl(const linked_ptr<R>& value)
+ : value_before_cast_(*value),
+ value_(ImplicitCast_<Result>(value_before_cast_)) {}
+
+ virtual Result Perform(const ArgumentTuple&) { return value_; }
+
+ private:
+ GTEST_COMPILE_ASSERT_(!is_reference<Result>::value,
+ Result_cannot_be_a_reference_type);
+ // We save the value before casting just in case it is being cast to a
+ // wrapper type.
+ R value_before_cast_;
+ Result value_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(Impl);
+ };
+
+ // Partially specialize for ByMoveWrapper. This version of ReturnAction will
+ // move its contents instead.
+ template <typename R_, typename F>
+ class Impl<ByMoveWrapper<R_>, F> : public ActionInterface<F> {
+ public:
+ typedef typename Function<F>::Result Result;
+ typedef typename Function<F>::ArgumentTuple ArgumentTuple;
+
+ explicit Impl(const linked_ptr<R>& wrapper)
+ : performed_(false), wrapper_(wrapper) {}
+
+ virtual Result Perform(const ArgumentTuple&) {
+ GTEST_CHECK_(!performed_)
+ << "A ByMove() action should only be performed once.";
+ performed_ = true;
+ return internal::move(wrapper_->payload);
+ }
+
+ private:
+ bool performed_;
+ const linked_ptr<R> wrapper_;
+
+ GTEST_DISALLOW_ASSIGN_(Impl);
+ };
+
+ const linked_ptr<R> value_;
+
+ GTEST_DISALLOW_ASSIGN_(ReturnAction);
+};
+
+// Implements the ReturnNull() action.
+class ReturnNullAction {
+ public:
+ // Allows ReturnNull() to be used in any pointer-returning function. In C++11
+ // this is enforced by returning nullptr, and in non-C++11 by asserting a
+ // pointer type on compile time.
+ template <typename Result, typename ArgumentTuple>
+ static Result Perform(const ArgumentTuple&) {
+#if GTEST_LANG_CXX11
+ return nullptr;
+#else
+ GTEST_COMPILE_ASSERT_(internal::is_pointer<Result>::value,
+ ReturnNull_can_be_used_to_return_a_pointer_only);
+ return NULL;
+#endif // GTEST_LANG_CXX11
+ }
+};
+
+// Implements the Return() action.
+class ReturnVoidAction {
+ public:
+ // Allows Return() to be used in any void-returning function.
+ template <typename Result, typename ArgumentTuple>
+ static void Perform(const ArgumentTuple&) {
+ CompileAssertTypesEqual<void, Result>();
+ }
+};
+
+// Implements the polymorphic ReturnRef(x) action, which can be used
+// in any function that returns a reference to the type of x,
+// regardless of the argument types.
+template <typename T>
+class ReturnRefAction {
+ public:
+ // Constructs a ReturnRefAction object from the reference to be returned.
+ explicit ReturnRefAction(T& ref) : ref_(ref) {} // NOLINT
+
+ // This template type conversion operator allows ReturnRef(x) to be
+ // used in ANY function that returns a reference to x's type.
+ template <typename F>
+ operator Action<F>() const {
+ typedef typename Function<F>::Result Result;
+ // Asserts that the function return type is a reference. This
+ // catches the user error of using ReturnRef(x) when Return(x)
+ // should be used, and generates some helpful error message.
+ GTEST_COMPILE_ASSERT_(internal::is_reference<Result>::value,
+ use_Return_instead_of_ReturnRef_to_return_a_value);
+ return Action<F>(new Impl<F>(ref_));
+ }
+
+ private:
+ // Implements the ReturnRef(x) action for a particular function type F.
+ template <typename F>
+ class Impl : public ActionInterface<F> {
+ public:
+ typedef typename Function<F>::Result Result;
+ typedef typename Function<F>::ArgumentTuple ArgumentTuple;
+
+ explicit Impl(T& ref) : ref_(ref) {} // NOLINT
+
+ virtual Result Perform(const ArgumentTuple&) {
+ return ref_;
+ }
+
+ private:
+ T& ref_;
+
+ GTEST_DISALLOW_ASSIGN_(Impl);
+ };
+
+ T& ref_;
+
+ GTEST_DISALLOW_ASSIGN_(ReturnRefAction);
+};
+
+// Implements the polymorphic ReturnRefOfCopy(x) action, which can be
+// used in any function that returns a reference to the type of x,
+// regardless of the argument types.
+template <typename T>
+class ReturnRefOfCopyAction {
+ public:
+ // Constructs a ReturnRefOfCopyAction object from the reference to
+ // be returned.
+ explicit ReturnRefOfCopyAction(const T& value) : value_(value) {} // NOLINT
+
+ // This template type conversion operator allows ReturnRefOfCopy(x) to be
+ // used in ANY function that returns a reference to x's type.
+ template <typename F>
+ operator Action<F>() const {
+ typedef typename Function<F>::Result Result;
+ // Asserts that the function return type is a reference. This
+ // catches the user error of using ReturnRefOfCopy(x) when Return(x)
+ // should be used, and generates some helpful error message.
+ GTEST_COMPILE_ASSERT_(
+ internal::is_reference<Result>::value,
+ use_Return_instead_of_ReturnRefOfCopy_to_return_a_value);
+ return Action<F>(new Impl<F>(value_));
+ }
+
+ private:
+ // Implements the ReturnRefOfCopy(x) action for a particular function type F.
+ template <typename F>
+ class Impl : public ActionInterface<F> {
+ public:
+ typedef typename Function<F>::Result Result;
+ typedef typename Function<F>::ArgumentTuple ArgumentTuple;
+
+ explicit Impl(const T& value) : value_(value) {} // NOLINT
+
+ virtual Result Perform(const ArgumentTuple&) {
+ return value_;
+ }
+
+ private:
+ T value_;
+
+ GTEST_DISALLOW_ASSIGN_(Impl);
+ };
+
+ const T value_;
+
+ GTEST_DISALLOW_ASSIGN_(ReturnRefOfCopyAction);
+};
+
+// Implements the polymorphic DoDefault() action.
+class DoDefaultAction {
+ public:
+ // This template type conversion operator allows DoDefault() to be
+ // used in any function.
+ template <typename F>
+ operator Action<F>() const { return Action<F>(NULL); }
+};
+
+// Implements the Assign action to set a given pointer referent to a
+// particular value.
+template <typename T1, typename T2>
+class AssignAction {
+ public:
+ AssignAction(T1* ptr, T2 value) : ptr_(ptr), value_(value) {}
+
+ template <typename Result, typename ArgumentTuple>
+ void Perform(const ArgumentTuple& /* args */) const {
+ *ptr_ = value_;
+ }
+
+ private:
+ T1* const ptr_;
+ const T2 value_;
+
+ GTEST_DISALLOW_ASSIGN_(AssignAction);
+};
+
+#if !GTEST_OS_WINDOWS_MOBILE
+
+// Implements the SetErrnoAndReturn action to simulate return from
+// various system calls and libc functions.
+template <typename T>
+class SetErrnoAndReturnAction {
+ public:
+ SetErrnoAndReturnAction(int errno_value, T result)
+ : errno_(errno_value),
+ result_(result) {}
+ template <typename Result, typename ArgumentTuple>
+ Result Perform(const ArgumentTuple& /* args */) const {
+ errno = errno_;
+ return result_;
+ }
+
+ private:
+ const int errno_;
+ const T result_;
+
+ GTEST_DISALLOW_ASSIGN_(SetErrnoAndReturnAction);
+};
+
+#endif // !GTEST_OS_WINDOWS_MOBILE
+
+// Implements the SetArgumentPointee<N>(x) action for any function
+// whose N-th argument (0-based) is a pointer to x's type. The
+// template parameter kIsProto is true iff type A is ProtocolMessage,
+// proto2::Message, or a sub-class of those.
+template <size_t N, typename A, bool kIsProto>
+class SetArgumentPointeeAction {
+ public:
+ // Constructs an action that sets the variable pointed to by the
+ // N-th function argument to 'value'.
+ explicit SetArgumentPointeeAction(const A& value) : value_(value) {}
+
+ template <typename Result, typename ArgumentTuple>
+ void Perform(const ArgumentTuple& args) const {
+ CompileAssertTypesEqual<void, Result>();
+ *::testing::get<N>(args) = value_;
+ }
+
+ private:
+ const A value_;
+
+ GTEST_DISALLOW_ASSIGN_(SetArgumentPointeeAction);
+};
+
+template <size_t N, typename Proto>
+class SetArgumentPointeeAction<N, Proto, true> {
+ public:
+ // Constructs an action that sets the variable pointed to by the
+ // N-th function argument to 'proto'. Both ProtocolMessage and
+ // proto2::Message have the CopyFrom() method, so the same
+ // implementation works for both.
+ explicit SetArgumentPointeeAction(const Proto& proto) : proto_(new Proto) {
+ proto_->CopyFrom(proto);
+ }
+
+ template <typename Result, typename ArgumentTuple>
+ void Perform(const ArgumentTuple& args) const {
+ CompileAssertTypesEqual<void, Result>();
+ ::testing::get<N>(args)->CopyFrom(*proto_);
+ }
+
+ private:
+ const internal::linked_ptr<Proto> proto_;
+
+ GTEST_DISALLOW_ASSIGN_(SetArgumentPointeeAction);
+};
+
+// Implements the InvokeWithoutArgs(f) action. The template argument
+// FunctionImpl is the implementation type of f, which can be either a
+// function pointer or a functor. InvokeWithoutArgs(f) can be used as an
+// Action<F> as long as f's type is compatible with F (i.e. f can be
+// assigned to a tr1::function<F>).
+template <typename FunctionImpl>
+class InvokeWithoutArgsAction {
+ public:
+ // The c'tor makes a copy of function_impl (either a function
+ // pointer or a functor).
+ explicit InvokeWithoutArgsAction(FunctionImpl function_impl)
+ : function_impl_(function_impl) {}
+
+ // Allows InvokeWithoutArgs(f) to be used as any action whose type is
+ // compatible with f.
+ template <typename Result, typename ArgumentTuple>
+ Result Perform(const ArgumentTuple&) { return function_impl_(); }
+
+ private:
+ FunctionImpl function_impl_;
+
+ GTEST_DISALLOW_ASSIGN_(InvokeWithoutArgsAction);
+};
+
+// Implements the InvokeWithoutArgs(object_ptr, &Class::Method) action.
+template <class Class, typename MethodPtr>
+class InvokeMethodWithoutArgsAction {
+ public:
+ InvokeMethodWithoutArgsAction(Class* obj_ptr, MethodPtr method_ptr)
+ : obj_ptr_(obj_ptr), method_ptr_(method_ptr) {}
+
+ template <typename Result, typename ArgumentTuple>
+ Result Perform(const ArgumentTuple&) const {
+ return (obj_ptr_->*method_ptr_)();
+ }
+
+ private:
+ Class* const obj_ptr_;
+ const MethodPtr method_ptr_;
+
+ GTEST_DISALLOW_ASSIGN_(InvokeMethodWithoutArgsAction);
+};
+
+// Implements the IgnoreResult(action) action.
+template <typename A>
+class IgnoreResultAction {
+ public:
+ explicit IgnoreResultAction(const A& action) : action_(action) {}
+
+ template <typename F>
+ operator Action<F>() const {
+ // Assert statement belongs here because this is the best place to verify
+ // conditions on F. It produces the clearest error messages
+ // in most compilers.
+ // Impl really belongs in this scope as a local class but can't
+ // because MSVC produces duplicate symbols in different translation units
+ // in this case. Until MS fixes that bug we put Impl into the class scope
+ // and put the typedef both here (for use in assert statement) and
+ // in the Impl class. But both definitions must be the same.
+ typedef typename internal::Function<F>::Result Result;
+
+ // Asserts at compile time that F returns void.
+ CompileAssertTypesEqual<void, Result>();
+
+ return Action<F>(new Impl<F>(action_));
+ }
+
+ private:
+ template <typename F>
+ class Impl : public ActionInterface<F> {
+ public:
+ typedef typename internal::Function<F>::Result Result;
+ typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
+
+ explicit Impl(const A& action) : action_(action) {}
+
+ virtual void Perform(const ArgumentTuple& args) {
+ // Performs the action and ignores its result.
+ action_.Perform(args);
+ }
+
+ private:
+ // Type OriginalFunction is the same as F except that its return
+ // type is IgnoredValue.
+ typedef typename internal::Function<F>::MakeResultIgnoredValue
+ OriginalFunction;
+
+ const Action<OriginalFunction> action_;
+
+ GTEST_DISALLOW_ASSIGN_(Impl);
+ };
+
+ const A action_;
+
+ GTEST_DISALLOW_ASSIGN_(IgnoreResultAction);
+};
+
+// A ReferenceWrapper<T> object represents a reference to type T,
+// which can be either const or not. It can be explicitly converted
+// from, and implicitly converted to, a T&. Unlike a reference,
+// ReferenceWrapper<T> can be copied and can survive template type
+// inference. This is used to support by-reference arguments in the
+// InvokeArgument<N>(...) action. The idea was from "reference
+// wrappers" in tr1, which we don't have in our source tree yet.
+template <typename T>
+class ReferenceWrapper {
+ public:
+ // Constructs a ReferenceWrapper<T> object from a T&.
+ explicit ReferenceWrapper(T& l_value) : pointer_(&l_value) {} // NOLINT
+
+ // Allows a ReferenceWrapper<T> object to be implicitly converted to
+ // a T&.
+ operator T&() const { return *pointer_; }
+ private:
+ T* pointer_;
+};
+
+// Allows the expression ByRef(x) to be printed as a reference to x.
+template <typename T>
+void PrintTo(const ReferenceWrapper<T>& ref, ::std::ostream* os) {
+ T& value = ref;
+ UniversalPrinter<T&>::Print(value, os);
+}
+
+// Does two actions sequentially. Used for implementing the DoAll(a1,
+// a2, ...) action.
+template <typename Action1, typename Action2>
+class DoBothAction {
+ public:
+ DoBothAction(Action1 action1, Action2 action2)
+ : action1_(action1), action2_(action2) {}
+
+ // This template type conversion operator allows DoAll(a1, ..., a_n)
+ // to be used in ANY function of compatible type.
+ template <typename F>
+ operator Action<F>() const {
+ return Action<F>(new Impl<F>(action1_, action2_));
+ }
+
+ private:
+ // Implements the DoAll(...) action for a particular function type F.
+ template <typename F>
+ class Impl : public ActionInterface<F> {
+ public:
+ typedef typename Function<F>::Result Result;
+ typedef typename Function<F>::ArgumentTuple ArgumentTuple;
+ typedef typename Function<F>::MakeResultVoid VoidResult;
+
+ Impl(const Action<VoidResult>& action1, const Action<F>& action2)
+ : action1_(action1), action2_(action2) {}
+
+ virtual Result Perform(const ArgumentTuple& args) {
+ action1_.Perform(args);
+ return action2_.Perform(args);
+ }
+
+ private:
+ const Action<VoidResult> action1_;
+ const Action<F> action2_;
+
+ GTEST_DISALLOW_ASSIGN_(Impl);
+ };
+
+ Action1 action1_;
+ Action2 action2_;
+
+ GTEST_DISALLOW_ASSIGN_(DoBothAction);
+};
+
+} // namespace internal
+
+// An Unused object can be implicitly constructed from ANY value.
+// This is handy when defining actions that ignore some or all of the
+// mock function arguments. For example, given
+//
+// MOCK_METHOD3(Foo, double(const string& label, double x, double y));
+// MOCK_METHOD3(Bar, double(int index, double x, double y));
+//
+// instead of
+//
+// double DistanceToOriginWithLabel(const string& label, double x, double y) {
+// return sqrt(x*x + y*y);
+// }
+// double DistanceToOriginWithIndex(int index, double x, double y) {
+// return sqrt(x*x + y*y);
+// }
+// ...
+// EXEPCT_CALL(mock, Foo("abc", _, _))
+// .WillOnce(Invoke(DistanceToOriginWithLabel));
+// EXEPCT_CALL(mock, Bar(5, _, _))
+// .WillOnce(Invoke(DistanceToOriginWithIndex));
+//
+// you could write
+//
+// // We can declare any uninteresting argument as Unused.
+// double DistanceToOrigin(Unused, double x, double y) {
+// return sqrt(x*x + y*y);
+// }
+// ...
+// EXEPCT_CALL(mock, Foo("abc", _, _)).WillOnce(Invoke(DistanceToOrigin));
+// EXEPCT_CALL(mock, Bar(5, _, _)).WillOnce(Invoke(DistanceToOrigin));
+typedef internal::IgnoredValue Unused;
+
+// This constructor allows us to turn an Action<From> object into an
+// Action<To>, as long as To's arguments can be implicitly converted
+// to From's and From's return type cann be implicitly converted to
+// To's.
+template <typename To>
+template <typename From>
+Action<To>::Action(const Action<From>& from)
+ : impl_(new internal::ActionAdaptor<To, From>(from)) {}
+
+// Creates an action that returns 'value'. 'value' is passed by value
+// instead of const reference - otherwise Return("string literal")
+// will trigger a compiler error about using array as initializer.
+template <typename R>
+internal::ReturnAction<R> Return(R value) {
+ return internal::ReturnAction<R>(internal::move(value));
+}
+
+// Creates an action that returns NULL.
+inline PolymorphicAction<internal::ReturnNullAction> ReturnNull() {
+ return MakePolymorphicAction(internal::ReturnNullAction());
+}
+
+// Creates an action that returns from a void function.
+inline PolymorphicAction<internal::ReturnVoidAction> Return() {
+ return MakePolymorphicAction(internal::ReturnVoidAction());
+}
+
+// Creates an action that returns the reference to a variable.
+template <typename R>
+inline internal::ReturnRefAction<R> ReturnRef(R& x) { // NOLINT
+ return internal::ReturnRefAction<R>(x);
+}
+
+// Creates an action that returns the reference to a copy of the
+// argument. The copy is created when the action is constructed and
+// lives as long as the action.
+template <typename R>
+inline internal::ReturnRefOfCopyAction<R> ReturnRefOfCopy(const R& x) {
+ return internal::ReturnRefOfCopyAction<R>(x);
+}
+
+// Modifies the parent action (a Return() action) to perform a move of the
+// argument instead of a copy.
+// Return(ByMove()) actions can only be executed once and will assert this
+// invariant.
+template <typename R>
+internal::ByMoveWrapper<R> ByMove(R x) {
+ return internal::ByMoveWrapper<R>(internal::move(x));
+}
+
+// Creates an action that does the default action for the give mock function.
+inline internal::DoDefaultAction DoDefault() {
+ return internal::DoDefaultAction();
+}
+
+// Creates an action that sets the variable pointed by the N-th
+// (0-based) function argument to 'value'.
+template <size_t N, typename T>
+PolymorphicAction<
+ internal::SetArgumentPointeeAction<
+ N, T, internal::IsAProtocolMessage<T>::value> >
+SetArgPointee(const T& x) {
+ return MakePolymorphicAction(internal::SetArgumentPointeeAction<
+ N, T, internal::IsAProtocolMessage<T>::value>(x));
+}
+
+#if !((GTEST_GCC_VER_ && GTEST_GCC_VER_ < 40000) || GTEST_OS_SYMBIAN)
+// This overload allows SetArgPointee() to accept a string literal.
+// GCC prior to the version 4.0 and Symbian C++ compiler cannot distinguish
+// this overload from the templated version and emit a compile error.
+template <size_t N>
+PolymorphicAction<
+ internal::SetArgumentPointeeAction<N, const char*, false> >
+SetArgPointee(const char* p) {
+ return MakePolymorphicAction(internal::SetArgumentPointeeAction<
+ N, const char*, false>(p));
+}
+
+template <size_t N>
+PolymorphicAction<
+ internal::SetArgumentPointeeAction<N, const wchar_t*, false> >
+SetArgPointee(const wchar_t* p) {
+ return MakePolymorphicAction(internal::SetArgumentPointeeAction<
+ N, const wchar_t*, false>(p));
+}
+#endif
+
+// The following version is DEPRECATED.
+template <size_t N, typename T>
+PolymorphicAction<
+ internal::SetArgumentPointeeAction<
+ N, T, internal::IsAProtocolMessage<T>::value> >
+SetArgumentPointee(const T& x) {
+ return MakePolymorphicAction(internal::SetArgumentPointeeAction<
+ N, T, internal::IsAProtocolMessage<T>::value>(x));
+}
+
+// Creates an action that sets a pointer referent to a given value.
+template <typename T1, typename T2>
+PolymorphicAction<internal::AssignAction<T1, T2> > Assign(T1* ptr, T2 val) {
+ return MakePolymorphicAction(internal::AssignAction<T1, T2>(ptr, val));
+}
+
+#if !GTEST_OS_WINDOWS_MOBILE
+
+// Creates an action that sets errno and returns the appropriate error.
+template <typename T>
+PolymorphicAction<internal::SetErrnoAndReturnAction<T> >
+SetErrnoAndReturn(int errval, T result) {
+ return MakePolymorphicAction(
+ internal::SetErrnoAndReturnAction<T>(errval, result));
+}
+
+#endif // !GTEST_OS_WINDOWS_MOBILE
+
+// Various overloads for InvokeWithoutArgs().
+
+// Creates an action that invokes 'function_impl' with no argument.
+template <typename FunctionImpl>
+PolymorphicAction<internal::InvokeWithoutArgsAction<FunctionImpl> >
+InvokeWithoutArgs(FunctionImpl function_impl) {
+ return MakePolymorphicAction(
+ internal::InvokeWithoutArgsAction<FunctionImpl>(function_impl));
+}
+
+// Creates an action that invokes the given method on the given object
+// with no argument.
+template <class Class, typename MethodPtr>
+PolymorphicAction<internal::InvokeMethodWithoutArgsAction<Class, MethodPtr> >
+InvokeWithoutArgs(Class* obj_ptr, MethodPtr method_ptr) {
+ return MakePolymorphicAction(
+ internal::InvokeMethodWithoutArgsAction<Class, MethodPtr>(
+ obj_ptr, method_ptr));
+}
+
+// Creates an action that performs an_action and throws away its
+// result. In other words, it changes the return type of an_action to
+// void. an_action MUST NOT return void, or the code won't compile.
+template <typename A>
+inline internal::IgnoreResultAction<A> IgnoreResult(const A& an_action) {
+ return internal::IgnoreResultAction<A>(an_action);
+}
+
+// Creates a reference wrapper for the given L-value. If necessary,
+// you can explicitly specify the type of the reference. For example,
+// suppose 'derived' is an object of type Derived, ByRef(derived)
+// would wrap a Derived&. If you want to wrap a const Base& instead,
+// where Base is a base class of Derived, just write:
+//
+// ByRef<const Base>(derived)
+template <typename T>
+inline internal::ReferenceWrapper<T> ByRef(T& l_value) { // NOLINT
+ return internal::ReferenceWrapper<T>(l_value);
+}
+
+} // namespace testing
+
+#endif // GMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_
diff --git a/extern/gmock/include/gmock/gmock-cardinalities.h b/extern/gmock/include/gmock/gmock-cardinalities.h
new file mode 100644
index 00000000000..fc315f92ab5
--- /dev/null
+++ b/extern/gmock/include/gmock/gmock-cardinalities.h
@@ -0,0 +1,147 @@
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Google Mock - a framework for writing C++ mock classes.
+//
+// This file implements some commonly used cardinalities. More
+// cardinalities can be defined by the user implementing the
+// CardinalityInterface interface if necessary.
+
+#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_
+#define GMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_
+
+#include <limits.h>
+#include <ostream> // NOLINT
+#include "gmock/internal/gmock-port.h"
+#include "gtest/gtest.h"
+
+namespace testing {
+
+// To implement a cardinality Foo, define:
+// 1. a class FooCardinality that implements the
+// CardinalityInterface interface, and
+// 2. a factory function that creates a Cardinality object from a
+// const FooCardinality*.
+//
+// The two-level delegation design follows that of Matcher, providing
+// consistency for extension developers. It also eases ownership
+// management as Cardinality objects can now be copied like plain values.
+
+// The implementation of a cardinality.
+class CardinalityInterface {
+ public:
+ virtual ~CardinalityInterface() {}
+
+ // Conservative estimate on the lower/upper bound of the number of
+ // calls allowed.
+ virtual int ConservativeLowerBound() const { return 0; }
+ virtual int ConservativeUpperBound() const { return INT_MAX; }
+
+ // Returns true iff call_count calls will satisfy this cardinality.
+ virtual bool IsSatisfiedByCallCount(int call_count) const = 0;
+
+ // Returns true iff call_count calls will saturate this cardinality.
+ virtual bool IsSaturatedByCallCount(int call_count) const = 0;
+
+ // Describes self to an ostream.
+ virtual void DescribeTo(::std::ostream* os) const = 0;
+};
+
+// A Cardinality is a copyable and IMMUTABLE (except by assignment)
+// object that specifies how many times a mock function is expected to
+// be called. The implementation of Cardinality is just a linked_ptr
+// to const CardinalityInterface, so copying is fairly cheap.
+// Don't inherit from Cardinality!
+class GTEST_API_ Cardinality {
+ public:
+ // Constructs a null cardinality. Needed for storing Cardinality
+ // objects in STL containers.
+ Cardinality() {}
+
+ // Constructs a Cardinality from its implementation.
+ explicit Cardinality(const CardinalityInterface* impl) : impl_(impl) {}
+
+ // Conservative estimate on the lower/upper bound of the number of
+ // calls allowed.
+ int ConservativeLowerBound() const { return impl_->ConservativeLowerBound(); }
+ int ConservativeUpperBound() const { return impl_->ConservativeUpperBound(); }
+
+ // Returns true iff call_count calls will satisfy this cardinality.
+ bool IsSatisfiedByCallCount(int call_count) const {
+ return impl_->IsSatisfiedByCallCount(call_count);
+ }
+
+ // Returns true iff call_count calls will saturate this cardinality.
+ bool IsSaturatedByCallCount(int call_count) const {
+ return impl_->IsSaturatedByCallCount(call_count);
+ }
+
+ // Returns true iff call_count calls will over-saturate this
+ // cardinality, i.e. exceed the maximum number of allowed calls.
+ bool IsOverSaturatedByCallCount(int call_count) const {
+ return impl_->IsSaturatedByCallCount(call_count) &&
+ !impl_->IsSatisfiedByCallCount(call_count);
+ }
+
+ // Describes self to an ostream
+ void DescribeTo(::std::ostream* os) const { impl_->DescribeTo(os); }
+
+ // Describes the given actual call count to an ostream.
+ static void DescribeActualCallCountTo(int actual_call_count,
+ ::std::ostream* os);
+
+ private:
+ internal::linked_ptr<const CardinalityInterface> impl_;
+};
+
+// Creates a cardinality that allows at least n calls.
+GTEST_API_ Cardinality AtLeast(int n);
+
+// Creates a cardinality that allows at most n calls.
+GTEST_API_ Cardinality AtMost(int n);
+
+// Creates a cardinality that allows any number of calls.
+GTEST_API_ Cardinality AnyNumber();
+
+// Creates a cardinality that allows between min and max calls.
+GTEST_API_ Cardinality Between(int min, int max);
+
+// Creates a cardinality that allows exactly n calls.
+GTEST_API_ Cardinality Exactly(int n);
+
+// Creates a cardinality from its implementation.
+inline Cardinality MakeCardinality(const CardinalityInterface* c) {
+ return Cardinality(c);
+}
+
+} // namespace testing
+
+#endif // GMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_
diff --git a/extern/gmock/include/gmock/gmock-generated-actions.h b/extern/gmock/include/gmock/gmock-generated-actions.h
new file mode 100644
index 00000000000..b5a889c0c3a
--- /dev/null
+++ b/extern/gmock/include/gmock/gmock-generated-actions.h
@@ -0,0 +1,2377 @@
+// This file was GENERATED by a script. DO NOT EDIT BY HAND!!!
+
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Google Mock - a framework for writing C++ mock classes.
+//
+// This file implements some commonly used variadic actions.
+
+#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_
+#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_
+
+#include "gmock/gmock-actions.h"
+#include "gmock/internal/gmock-port.h"
+
+namespace testing {
+namespace internal {
+
+// InvokeHelper<F> knows how to unpack an N-tuple and invoke an N-ary
+// function or method with the unpacked values, where F is a function
+// type that takes N arguments.
+template <typename Result, typename ArgumentTuple>
+class InvokeHelper;
+
+template <typename R>
+class InvokeHelper<R, ::testing::tuple<> > {
+ public:
+ template <typename Function>
+ static R Invoke(Function function, const ::testing::tuple<>&) {
+ return function();
+ }
+
+ template <class Class, typename MethodPtr>
+ static R InvokeMethod(Class* obj_ptr,
+ MethodPtr method_ptr,
+ const ::testing::tuple<>&) {
+ return (obj_ptr->*method_ptr)();
+ }
+};
+
+template <typename R, typename A1>
+class InvokeHelper<R, ::testing::tuple<A1> > {
+ public:
+ template <typename Function>
+ static R Invoke(Function function, const ::testing::tuple<A1>& args) {
+ return function(get<0>(args));
+ }
+
+ template <class Class, typename MethodPtr>
+ static R InvokeMethod(Class* obj_ptr,
+ MethodPtr method_ptr,
+ const ::testing::tuple<A1>& args) {
+ return (obj_ptr->*method_ptr)(get<0>(args));
+ }
+};
+
+template <typename R, typename A1, typename A2>
+class InvokeHelper<R, ::testing::tuple<A1, A2> > {
+ public:
+ template <typename Function>
+ static R Invoke(Function function, const ::testing::tuple<A1, A2>& args) {
+ return function(get<0>(args), get<1>(args));
+ }
+
+ template <class Class, typename MethodPtr>
+ static R InvokeMethod(Class* obj_ptr,
+ MethodPtr method_ptr,
+ const ::testing::tuple<A1, A2>& args) {
+ return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args));
+ }
+};
+
+template <typename R, typename A1, typename A2, typename A3>
+class InvokeHelper<R, ::testing::tuple<A1, A2, A3> > {
+ public:
+ template <typename Function>
+ static R Invoke(Function function, const ::testing::tuple<A1, A2, A3>& args) {
+ return function(get<0>(args), get<1>(args), get<2>(args));
+ }
+
+ template <class Class, typename MethodPtr>
+ static R InvokeMethod(Class* obj_ptr,
+ MethodPtr method_ptr,
+ const ::testing::tuple<A1, A2, A3>& args) {
+ return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args),
+ get<2>(args));
+ }
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4>
+class InvokeHelper<R, ::testing::tuple<A1, A2, A3, A4> > {
+ public:
+ template <typename Function>
+ static R Invoke(Function function, const ::testing::tuple<A1, A2, A3,
+ A4>& args) {
+ return function(get<0>(args), get<1>(args), get<2>(args),
+ get<3>(args));
+ }
+
+ template <class Class, typename MethodPtr>
+ static R InvokeMethod(Class* obj_ptr,
+ MethodPtr method_ptr,
+ const ::testing::tuple<A1, A2, A3, A4>& args) {
+ return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args),
+ get<2>(args), get<3>(args));
+ }
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5>
+class InvokeHelper<R, ::testing::tuple<A1, A2, A3, A4, A5> > {
+ public:
+ template <typename Function>
+ static R Invoke(Function function, const ::testing::tuple<A1, A2, A3, A4,
+ A5>& args) {
+ return function(get<0>(args), get<1>(args), get<2>(args),
+ get<3>(args), get<4>(args));
+ }
+
+ template <class Class, typename MethodPtr>
+ static R InvokeMethod(Class* obj_ptr,
+ MethodPtr method_ptr,
+ const ::testing::tuple<A1, A2, A3, A4, A5>& args) {
+ return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args),
+ get<2>(args), get<3>(args), get<4>(args));
+ }
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6>
+class InvokeHelper<R, ::testing::tuple<A1, A2, A3, A4, A5, A6> > {
+ public:
+ template <typename Function>
+ static R Invoke(Function function, const ::testing::tuple<A1, A2, A3, A4, A5,
+ A6>& args) {
+ return function(get<0>(args), get<1>(args), get<2>(args),
+ get<3>(args), get<4>(args), get<5>(args));
+ }
+
+ template <class Class, typename MethodPtr>
+ static R InvokeMethod(Class* obj_ptr,
+ MethodPtr method_ptr,
+ const ::testing::tuple<A1, A2, A3, A4, A5, A6>& args) {
+ return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args),
+ get<2>(args), get<3>(args), get<4>(args), get<5>(args));
+ }
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6, typename A7>
+class InvokeHelper<R, ::testing::tuple<A1, A2, A3, A4, A5, A6, A7> > {
+ public:
+ template <typename Function>
+ static R Invoke(Function function, const ::testing::tuple<A1, A2, A3, A4, A5,
+ A6, A7>& args) {
+ return function(get<0>(args), get<1>(args), get<2>(args),
+ get<3>(args), get<4>(args), get<5>(args), get<6>(args));
+ }
+
+ template <class Class, typename MethodPtr>
+ static R InvokeMethod(Class* obj_ptr,
+ MethodPtr method_ptr,
+ const ::testing::tuple<A1, A2, A3, A4, A5, A6,
+ A7>& args) {
+ return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args),
+ get<2>(args), get<3>(args), get<4>(args), get<5>(args),
+ get<6>(args));
+ }
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6, typename A7, typename A8>
+class InvokeHelper<R, ::testing::tuple<A1, A2, A3, A4, A5, A6, A7, A8> > {
+ public:
+ template <typename Function>
+ static R Invoke(Function function, const ::testing::tuple<A1, A2, A3, A4, A5,
+ A6, A7, A8>& args) {
+ return function(get<0>(args), get<1>(args), get<2>(args),
+ get<3>(args), get<4>(args), get<5>(args), get<6>(args),
+ get<7>(args));
+ }
+
+ template <class Class, typename MethodPtr>
+ static R InvokeMethod(Class* obj_ptr,
+ MethodPtr method_ptr,
+ const ::testing::tuple<A1, A2, A3, A4, A5, A6, A7,
+ A8>& args) {
+ return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args),
+ get<2>(args), get<3>(args), get<4>(args), get<5>(args),
+ get<6>(args), get<7>(args));
+ }
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6, typename A7, typename A8, typename A9>
+class InvokeHelper<R, ::testing::tuple<A1, A2, A3, A4, A5, A6, A7, A8, A9> > {
+ public:
+ template <typename Function>
+ static R Invoke(Function function, const ::testing::tuple<A1, A2, A3, A4, A5,
+ A6, A7, A8, A9>& args) {
+ return function(get<0>(args), get<1>(args), get<2>(args),
+ get<3>(args), get<4>(args), get<5>(args), get<6>(args),
+ get<7>(args), get<8>(args));
+ }
+
+ template <class Class, typename MethodPtr>
+ static R InvokeMethod(Class* obj_ptr,
+ MethodPtr method_ptr,
+ const ::testing::tuple<A1, A2, A3, A4, A5, A6, A7, A8,
+ A9>& args) {
+ return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args),
+ get<2>(args), get<3>(args), get<4>(args), get<5>(args),
+ get<6>(args), get<7>(args), get<8>(args));
+ }
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6, typename A7, typename A8, typename A9,
+ typename A10>
+class InvokeHelper<R, ::testing::tuple<A1, A2, A3, A4, A5, A6, A7, A8, A9,
+ A10> > {
+ public:
+ template <typename Function>
+ static R Invoke(Function function, const ::testing::tuple<A1, A2, A3, A4, A5,
+ A6, A7, A8, A9, A10>& args) {
+ return function(get<0>(args), get<1>(args), get<2>(args),
+ get<3>(args), get<4>(args), get<5>(args), get<6>(args),
+ get<7>(args), get<8>(args), get<9>(args));
+ }
+
+ template <class Class, typename MethodPtr>
+ static R InvokeMethod(Class* obj_ptr,
+ MethodPtr method_ptr,
+ const ::testing::tuple<A1, A2, A3, A4, A5, A6, A7, A8,
+ A9, A10>& args) {
+ return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args),
+ get<2>(args), get<3>(args), get<4>(args), get<5>(args),
+ get<6>(args), get<7>(args), get<8>(args), get<9>(args));
+ }
+};
+
+// An INTERNAL macro for extracting the type of a tuple field. It's
+// subject to change without notice - DO NOT USE IN USER CODE!
+#define GMOCK_FIELD_(Tuple, N) \
+ typename ::testing::tuple_element<N, Tuple>::type
+
+// SelectArgs<Result, ArgumentTuple, k1, k2, ..., k_n>::type is the
+// type of an n-ary function whose i-th (1-based) argument type is the
+// k{i}-th (0-based) field of ArgumentTuple, which must be a tuple
+// type, and whose return type is Result. For example,
+// SelectArgs<int, ::testing::tuple<bool, char, double, long>, 0, 3>::type
+// is int(bool, long).
+//
+// SelectArgs<Result, ArgumentTuple, k1, k2, ..., k_n>::Select(args)
+// returns the selected fields (k1, k2, ..., k_n) of args as a tuple.
+// For example,
+// SelectArgs<int, tuple<bool, char, double>, 2, 0>::Select(
+// ::testing::make_tuple(true, 'a', 2.5))
+// returns tuple (2.5, true).
+//
+// The numbers in list k1, k2, ..., k_n must be >= 0, where n can be
+// in the range [0, 10]. Duplicates are allowed and they don't have
+// to be in an ascending or descending order.
+
+template <typename Result, typename ArgumentTuple, int k1, int k2, int k3,
+ int k4, int k5, int k6, int k7, int k8, int k9, int k10>
+class SelectArgs {
+ public:
+ typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1),
+ GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3),
+ GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5),
+ GMOCK_FIELD_(ArgumentTuple, k6), GMOCK_FIELD_(ArgumentTuple, k7),
+ GMOCK_FIELD_(ArgumentTuple, k8), GMOCK_FIELD_(ArgumentTuple, k9),
+ GMOCK_FIELD_(ArgumentTuple, k10));
+ typedef typename Function<type>::ArgumentTuple SelectedArgs;
+ static SelectedArgs Select(const ArgumentTuple& args) {
+ return SelectedArgs(get<k1>(args), get<k2>(args), get<k3>(args),
+ get<k4>(args), get<k5>(args), get<k6>(args), get<k7>(args),
+ get<k8>(args), get<k9>(args), get<k10>(args));
+ }
+};
+
+template <typename Result, typename ArgumentTuple>
+class SelectArgs<Result, ArgumentTuple,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1> {
+ public:
+ typedef Result type();
+ typedef typename Function<type>::ArgumentTuple SelectedArgs;
+ static SelectedArgs Select(const ArgumentTuple& /* args */) {
+ return SelectedArgs();
+ }
+};
+
+template <typename Result, typename ArgumentTuple, int k1>
+class SelectArgs<Result, ArgumentTuple,
+ k1, -1, -1, -1, -1, -1, -1, -1, -1, -1> {
+ public:
+ typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1));
+ typedef typename Function<type>::ArgumentTuple SelectedArgs;
+ static SelectedArgs Select(const ArgumentTuple& args) {
+ return SelectedArgs(get<k1>(args));
+ }
+};
+
+template <typename Result, typename ArgumentTuple, int k1, int k2>
+class SelectArgs<Result, ArgumentTuple,
+ k1, k2, -1, -1, -1, -1, -1, -1, -1, -1> {
+ public:
+ typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1),
+ GMOCK_FIELD_(ArgumentTuple, k2));
+ typedef typename Function<type>::ArgumentTuple SelectedArgs;
+ static SelectedArgs Select(const ArgumentTuple& args) {
+ return SelectedArgs(get<k1>(args), get<k2>(args));
+ }
+};
+
+template <typename Result, typename ArgumentTuple, int k1, int k2, int k3>
+class SelectArgs<Result, ArgumentTuple,
+ k1, k2, k3, -1, -1, -1, -1, -1, -1, -1> {
+ public:
+ typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1),
+ GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3));
+ typedef typename Function<type>::ArgumentTuple SelectedArgs;
+ static SelectedArgs Select(const ArgumentTuple& args) {
+ return SelectedArgs(get<k1>(args), get<k2>(args), get<k3>(args));
+ }
+};
+
+template <typename Result, typename ArgumentTuple, int k1, int k2, int k3,
+ int k4>
+class SelectArgs<Result, ArgumentTuple,
+ k1, k2, k3, k4, -1, -1, -1, -1, -1, -1> {
+ public:
+ typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1),
+ GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3),
+ GMOCK_FIELD_(ArgumentTuple, k4));
+ typedef typename Function<type>::ArgumentTuple SelectedArgs;
+ static SelectedArgs Select(const ArgumentTuple& args) {
+ return SelectedArgs(get<k1>(args), get<k2>(args), get<k3>(args),
+ get<k4>(args));
+ }
+};
+
+template <typename Result, typename ArgumentTuple, int k1, int k2, int k3,
+ int k4, int k5>
+class SelectArgs<Result, ArgumentTuple,
+ k1, k2, k3, k4, k5, -1, -1, -1, -1, -1> {
+ public:
+ typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1),
+ GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3),
+ GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5));
+ typedef typename Function<type>::ArgumentTuple SelectedArgs;
+ static SelectedArgs Select(const ArgumentTuple& args) {
+ return SelectedArgs(get<k1>(args), get<k2>(args), get<k3>(args),
+ get<k4>(args), get<k5>(args));
+ }
+};
+
+template <typename Result, typename ArgumentTuple, int k1, int k2, int k3,
+ int k4, int k5, int k6>
+class SelectArgs<Result, ArgumentTuple,
+ k1, k2, k3, k4, k5, k6, -1, -1, -1, -1> {
+ public:
+ typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1),
+ GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3),
+ GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5),
+ GMOCK_FIELD_(ArgumentTuple, k6));
+ typedef typename Function<type>::ArgumentTuple SelectedArgs;
+ static SelectedArgs Select(const ArgumentTuple& args) {
+ return SelectedArgs(get<k1>(args), get<k2>(args), get<k3>(args),
+ get<k4>(args), get<k5>(args), get<k6>(args));
+ }
+};
+
+template <typename Result, typename ArgumentTuple, int k1, int k2, int k3,
+ int k4, int k5, int k6, int k7>
+class SelectArgs<Result, ArgumentTuple,
+ k1, k2, k3, k4, k5, k6, k7, -1, -1, -1> {
+ public:
+ typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1),
+ GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3),
+ GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5),
+ GMOCK_FIELD_(ArgumentTuple, k6), GMOCK_FIELD_(ArgumentTuple, k7));
+ typedef typename Function<type>::ArgumentTuple SelectedArgs;
+ static SelectedArgs Select(const ArgumentTuple& args) {
+ return SelectedArgs(get<k1>(args), get<k2>(args), get<k3>(args),
+ get<k4>(args), get<k5>(args), get<k6>(args), get<k7>(args));
+ }
+};
+
+template <typename Result, typename ArgumentTuple, int k1, int k2, int k3,
+ int k4, int k5, int k6, int k7, int k8>
+class SelectArgs<Result, ArgumentTuple,
+ k1, k2, k3, k4, k5, k6, k7, k8, -1, -1> {
+ public:
+ typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1),
+ GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3),
+ GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5),
+ GMOCK_FIELD_(ArgumentTuple, k6), GMOCK_FIELD_(ArgumentTuple, k7),
+ GMOCK_FIELD_(ArgumentTuple, k8));
+ typedef typename Function<type>::ArgumentTuple SelectedArgs;
+ static SelectedArgs Select(const ArgumentTuple& args) {
+ return SelectedArgs(get<k1>(args), get<k2>(args), get<k3>(args),
+ get<k4>(args), get<k5>(args), get<k6>(args), get<k7>(args),
+ get<k8>(args));
+ }
+};
+
+template <typename Result, typename ArgumentTuple, int k1, int k2, int k3,
+ int k4, int k5, int k6, int k7, int k8, int k9>
+class SelectArgs<Result, ArgumentTuple,
+ k1, k2, k3, k4, k5, k6, k7, k8, k9, -1> {
+ public:
+ typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1),
+ GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3),
+ GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5),
+ GMOCK_FIELD_(ArgumentTuple, k6), GMOCK_FIELD_(ArgumentTuple, k7),
+ GMOCK_FIELD_(ArgumentTuple, k8), GMOCK_FIELD_(ArgumentTuple, k9));
+ typedef typename Function<type>::ArgumentTuple SelectedArgs;
+ static SelectedArgs Select(const ArgumentTuple& args) {
+ return SelectedArgs(get<k1>(args), get<k2>(args), get<k3>(args),
+ get<k4>(args), get<k5>(args), get<k6>(args), get<k7>(args),
+ get<k8>(args), get<k9>(args));
+ }
+};
+
+#undef GMOCK_FIELD_
+
+// Implements the WithArgs action.
+template <typename InnerAction, int k1 = -1, int k2 = -1, int k3 = -1,
+ int k4 = -1, int k5 = -1, int k6 = -1, int k7 = -1, int k8 = -1,
+ int k9 = -1, int k10 = -1>
+class WithArgsAction {
+ public:
+ explicit WithArgsAction(const InnerAction& action) : action_(action) {}
+
+ template <typename F>
+ operator Action<F>() const { return MakeAction(new Impl<F>(action_)); }
+
+ private:
+ template <typename F>
+ class Impl : public ActionInterface<F> {
+ public:
+ typedef typename Function<F>::Result Result;
+ typedef typename Function<F>::ArgumentTuple ArgumentTuple;
+
+ explicit Impl(const InnerAction& action) : action_(action) {}
+
+ virtual Result Perform(const ArgumentTuple& args) {
+ return action_.Perform(SelectArgs<Result, ArgumentTuple, k1, k2, k3, k4,
+ k5, k6, k7, k8, k9, k10>::Select(args));
+ }
+
+ private:
+ typedef typename SelectArgs<Result, ArgumentTuple,
+ k1, k2, k3, k4, k5, k6, k7, k8, k9, k10>::type InnerFunctionType;
+
+ Action<InnerFunctionType> action_;
+ };
+
+ const InnerAction action_;
+
+ GTEST_DISALLOW_ASSIGN_(WithArgsAction);
+};
+
+// A macro from the ACTION* family (defined later in this file)
+// defines an action that can be used in a mock function. Typically,
+// these actions only care about a subset of the arguments of the mock
+// function. For example, if such an action only uses the second
+// argument, it can be used in any mock function that takes >= 2
+// arguments where the type of the second argument is compatible.
+//
+// Therefore, the action implementation must be prepared to take more
+// arguments than it needs. The ExcessiveArg type is used to
+// represent those excessive arguments. In order to keep the compiler
+// error messages tractable, we define it in the testing namespace
+// instead of testing::internal. However, this is an INTERNAL TYPE
+// and subject to change without notice, so a user MUST NOT USE THIS
+// TYPE DIRECTLY.
+struct ExcessiveArg {};
+
+// A helper class needed for implementing the ACTION* macros.
+template <typename Result, class Impl>
+class ActionHelper {
+ public:
+ static Result Perform(Impl* impl, const ::testing::tuple<>& args) {
+ return impl->template gmock_PerformImpl<>(args, ExcessiveArg(),
+ ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(),
+ ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(),
+ ExcessiveArg());
+ }
+
+ template <typename A0>
+ static Result Perform(Impl* impl, const ::testing::tuple<A0>& args) {
+ return impl->template gmock_PerformImpl<A0>(args, get<0>(args),
+ ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(),
+ ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(),
+ ExcessiveArg());
+ }
+
+ template <typename A0, typename A1>
+ static Result Perform(Impl* impl, const ::testing::tuple<A0, A1>& args) {
+ return impl->template gmock_PerformImpl<A0, A1>(args, get<0>(args),
+ get<1>(args), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(),
+ ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(),
+ ExcessiveArg());
+ }
+
+ template <typename A0, typename A1, typename A2>
+ static Result Perform(Impl* impl, const ::testing::tuple<A0, A1, A2>& args) {
+ return impl->template gmock_PerformImpl<A0, A1, A2>(args, get<0>(args),
+ get<1>(args), get<2>(args), ExcessiveArg(), ExcessiveArg(),
+ ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(),
+ ExcessiveArg());
+ }
+
+ template <typename A0, typename A1, typename A2, typename A3>
+ static Result Perform(Impl* impl, const ::testing::tuple<A0, A1, A2,
+ A3>& args) {
+ return impl->template gmock_PerformImpl<A0, A1, A2, A3>(args, get<0>(args),
+ get<1>(args), get<2>(args), get<3>(args), ExcessiveArg(),
+ ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(),
+ ExcessiveArg());
+ }
+
+ template <typename A0, typename A1, typename A2, typename A3, typename A4>
+ static Result Perform(Impl* impl, const ::testing::tuple<A0, A1, A2, A3,
+ A4>& args) {
+ return impl->template gmock_PerformImpl<A0, A1, A2, A3, A4>(args,
+ get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args),
+ ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(),
+ ExcessiveArg());
+ }
+
+ template <typename A0, typename A1, typename A2, typename A3, typename A4,
+ typename A5>
+ static Result Perform(Impl* impl, const ::testing::tuple<A0, A1, A2, A3, A4,
+ A5>& args) {
+ return impl->template gmock_PerformImpl<A0, A1, A2, A3, A4, A5>(args,
+ get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args),
+ get<5>(args), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(),
+ ExcessiveArg());
+ }
+
+ template <typename A0, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6>
+ static Result Perform(Impl* impl, const ::testing::tuple<A0, A1, A2, A3, A4,
+ A5, A6>& args) {
+ return impl->template gmock_PerformImpl<A0, A1, A2, A3, A4, A5, A6>(args,
+ get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args),
+ get<5>(args), get<6>(args), ExcessiveArg(), ExcessiveArg(),
+ ExcessiveArg());
+ }
+
+ template <typename A0, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6, typename A7>
+ static Result Perform(Impl* impl, const ::testing::tuple<A0, A1, A2, A3, A4,
+ A5, A6, A7>& args) {
+ return impl->template gmock_PerformImpl<A0, A1, A2, A3, A4, A5, A6,
+ A7>(args, get<0>(args), get<1>(args), get<2>(args), get<3>(args),
+ get<4>(args), get<5>(args), get<6>(args), get<7>(args), ExcessiveArg(),
+ ExcessiveArg());
+ }
+
+ template <typename A0, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6, typename A7, typename A8>
+ static Result Perform(Impl* impl, const ::testing::tuple<A0, A1, A2, A3, A4,
+ A5, A6, A7, A8>& args) {
+ return impl->template gmock_PerformImpl<A0, A1, A2, A3, A4, A5, A6, A7,
+ A8>(args, get<0>(args), get<1>(args), get<2>(args), get<3>(args),
+ get<4>(args), get<5>(args), get<6>(args), get<7>(args), get<8>(args),
+ ExcessiveArg());
+ }
+
+ template <typename A0, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6, typename A7, typename A8, typename A9>
+ static Result Perform(Impl* impl, const ::testing::tuple<A0, A1, A2, A3, A4,
+ A5, A6, A7, A8, A9>& args) {
+ return impl->template gmock_PerformImpl<A0, A1, A2, A3, A4, A5, A6, A7, A8,
+ A9>(args, get<0>(args), get<1>(args), get<2>(args), get<3>(args),
+ get<4>(args), get<5>(args), get<6>(args), get<7>(args), get<8>(args),
+ get<9>(args));
+ }
+};
+
+} // namespace internal
+
+// Various overloads for Invoke().
+
+// WithArgs<N1, N2, ..., Nk>(an_action) creates an action that passes
+// the selected arguments of the mock function to an_action and
+// performs it. It serves as an adaptor between actions with
+// different argument lists. C++ doesn't support default arguments for
+// function templates, so we have to overload it.
+template <int k1, typename InnerAction>
+inline internal::WithArgsAction<InnerAction, k1>
+WithArgs(const InnerAction& action) {
+ return internal::WithArgsAction<InnerAction, k1>(action);
+}
+
+template <int k1, int k2, typename InnerAction>
+inline internal::WithArgsAction<InnerAction, k1, k2>
+WithArgs(const InnerAction& action) {
+ return internal::WithArgsAction<InnerAction, k1, k2>(action);
+}
+
+template <int k1, int k2, int k3, typename InnerAction>
+inline internal::WithArgsAction<InnerAction, k1, k2, k3>
+WithArgs(const InnerAction& action) {
+ return internal::WithArgsAction<InnerAction, k1, k2, k3>(action);
+}
+
+template <int k1, int k2, int k3, int k4, typename InnerAction>
+inline internal::WithArgsAction<InnerAction, k1, k2, k3, k4>
+WithArgs(const InnerAction& action) {
+ return internal::WithArgsAction<InnerAction, k1, k2, k3, k4>(action);
+}
+
+template <int k1, int k2, int k3, int k4, int k5, typename InnerAction>
+inline internal::WithArgsAction<InnerAction, k1, k2, k3, k4, k5>
+WithArgs(const InnerAction& action) {
+ return internal::WithArgsAction<InnerAction, k1, k2, k3, k4, k5>(action);
+}
+
+template <int k1, int k2, int k3, int k4, int k5, int k6, typename InnerAction>
+inline internal::WithArgsAction<InnerAction, k1, k2, k3, k4, k5, k6>
+WithArgs(const InnerAction& action) {
+ return internal::WithArgsAction<InnerAction, k1, k2, k3, k4, k5, k6>(action);
+}
+
+template <int k1, int k2, int k3, int k4, int k5, int k6, int k7,
+ typename InnerAction>
+inline internal::WithArgsAction<InnerAction, k1, k2, k3, k4, k5, k6, k7>
+WithArgs(const InnerAction& action) {
+ return internal::WithArgsAction<InnerAction, k1, k2, k3, k4, k5, k6,
+ k7>(action);
+}
+
+template <int k1, int k2, int k3, int k4, int k5, int k6, int k7, int k8,
+ typename InnerAction>
+inline internal::WithArgsAction<InnerAction, k1, k2, k3, k4, k5, k6, k7, k8>
+WithArgs(const InnerAction& action) {
+ return internal::WithArgsAction<InnerAction, k1, k2, k3, k4, k5, k6, k7,
+ k8>(action);
+}
+
+template <int k1, int k2, int k3, int k4, int k5, int k6, int k7, int k8,
+ int k9, typename InnerAction>
+inline internal::WithArgsAction<InnerAction, k1, k2, k3, k4, k5, k6, k7, k8, k9>
+WithArgs(const InnerAction& action) {
+ return internal::WithArgsAction<InnerAction, k1, k2, k3, k4, k5, k6, k7, k8,
+ k9>(action);
+}
+
+template <int k1, int k2, int k3, int k4, int k5, int k6, int k7, int k8,
+ int k9, int k10, typename InnerAction>
+inline internal::WithArgsAction<InnerAction, k1, k2, k3, k4, k5, k6, k7, k8,
+ k9, k10>
+WithArgs(const InnerAction& action) {
+ return internal::WithArgsAction<InnerAction, k1, k2, k3, k4, k5, k6, k7, k8,
+ k9, k10>(action);
+}
+
+// Creates an action that does actions a1, a2, ..., sequentially in
+// each invocation.
+template <typename Action1, typename Action2>
+inline internal::DoBothAction<Action1, Action2>
+DoAll(Action1 a1, Action2 a2) {
+ return internal::DoBothAction<Action1, Action2>(a1, a2);
+}
+
+template <typename Action1, typename Action2, typename Action3>
+inline internal::DoBothAction<Action1, internal::DoBothAction<Action2,
+ Action3> >
+DoAll(Action1 a1, Action2 a2, Action3 a3) {
+ return DoAll(a1, DoAll(a2, a3));
+}
+
+template <typename Action1, typename Action2, typename Action3,
+ typename Action4>
+inline internal::DoBothAction<Action1, internal::DoBothAction<Action2,
+ internal::DoBothAction<Action3, Action4> > >
+DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4) {
+ return DoAll(a1, DoAll(a2, a3, a4));
+}
+
+template <typename Action1, typename Action2, typename Action3,
+ typename Action4, typename Action5>
+inline internal::DoBothAction<Action1, internal::DoBothAction<Action2,
+ internal::DoBothAction<Action3, internal::DoBothAction<Action4,
+ Action5> > > >
+DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5) {
+ return DoAll(a1, DoAll(a2, a3, a4, a5));
+}
+
+template <typename Action1, typename Action2, typename Action3,
+ typename Action4, typename Action5, typename Action6>
+inline internal::DoBothAction<Action1, internal::DoBothAction<Action2,
+ internal::DoBothAction<Action3, internal::DoBothAction<Action4,
+ internal::DoBothAction<Action5, Action6> > > > >
+DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6) {
+ return DoAll(a1, DoAll(a2, a3, a4, a5, a6));
+}
+
+template <typename Action1, typename Action2, typename Action3,
+ typename Action4, typename Action5, typename Action6, typename Action7>
+inline internal::DoBothAction<Action1, internal::DoBothAction<Action2,
+ internal::DoBothAction<Action3, internal::DoBothAction<Action4,
+ internal::DoBothAction<Action5, internal::DoBothAction<Action6,
+ Action7> > > > > >
+DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
+ Action7 a7) {
+ return DoAll(a1, DoAll(a2, a3, a4, a5, a6, a7));
+}
+
+template <typename Action1, typename Action2, typename Action3,
+ typename Action4, typename Action5, typename Action6, typename Action7,
+ typename Action8>
+inline internal::DoBothAction<Action1, internal::DoBothAction<Action2,
+ internal::DoBothAction<Action3, internal::DoBothAction<Action4,
+ internal::DoBothAction<Action5, internal::DoBothAction<Action6,
+ internal::DoBothAction<Action7, Action8> > > > > > >
+DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
+ Action7 a7, Action8 a8) {
+ return DoAll(a1, DoAll(a2, a3, a4, a5, a6, a7, a8));
+}
+
+template <typename Action1, typename Action2, typename Action3,
+ typename Action4, typename Action5, typename Action6, typename Action7,
+ typename Action8, typename Action9>
+inline internal::DoBothAction<Action1, internal::DoBothAction<Action2,
+ internal::DoBothAction<Action3, internal::DoBothAction<Action4,
+ internal::DoBothAction<Action5, internal::DoBothAction<Action6,
+ internal::DoBothAction<Action7, internal::DoBothAction<Action8,
+ Action9> > > > > > > >
+DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
+ Action7 a7, Action8 a8, Action9 a9) {
+ return DoAll(a1, DoAll(a2, a3, a4, a5, a6, a7, a8, a9));
+}
+
+template <typename Action1, typename Action2, typename Action3,
+ typename Action4, typename Action5, typename Action6, typename Action7,
+ typename Action8, typename Action9, typename Action10>
+inline internal::DoBothAction<Action1, internal::DoBothAction<Action2,
+ internal::DoBothAction<Action3, internal::DoBothAction<Action4,
+ internal::DoBothAction<Action5, internal::DoBothAction<Action6,
+ internal::DoBothAction<Action7, internal::DoBothAction<Action8,
+ internal::DoBothAction<Action9, Action10> > > > > > > > >
+DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
+ Action7 a7, Action8 a8, Action9 a9, Action10 a10) {
+ return DoAll(a1, DoAll(a2, a3, a4, a5, a6, a7, a8, a9, a10));
+}
+
+} // namespace testing
+
+// The ACTION* family of macros can be used in a namespace scope to
+// define custom actions easily. The syntax:
+//
+// ACTION(name) { statements; }
+//
+// will define an action with the given name that executes the
+// statements. The value returned by the statements will be used as
+// the return value of the action. Inside the statements, you can
+// refer to the K-th (0-based) argument of the mock function by
+// 'argK', and refer to its type by 'argK_type'. For example:
+//
+// ACTION(IncrementArg1) {
+// arg1_type temp = arg1;
+// return ++(*temp);
+// }
+//
+// allows you to write
+//
+// ...WillOnce(IncrementArg1());
+//
+// You can also refer to the entire argument tuple and its type by
+// 'args' and 'args_type', and refer to the mock function type and its
+// return type by 'function_type' and 'return_type'.
+//
+// Note that you don't need to specify the types of the mock function
+// arguments. However rest assured that your code is still type-safe:
+// you'll get a compiler error if *arg1 doesn't support the ++
+// operator, or if the type of ++(*arg1) isn't compatible with the
+// mock function's return type, for example.
+//
+// Sometimes you'll want to parameterize the action. For that you can use
+// another macro:
+//
+// ACTION_P(name, param_name) { statements; }
+//
+// For example:
+//
+// ACTION_P(Add, n) { return arg0 + n; }
+//
+// will allow you to write:
+//
+// ...WillOnce(Add(5));
+//
+// Note that you don't need to provide the type of the parameter
+// either. If you need to reference the type of a parameter named
+// 'foo', you can write 'foo_type'. For example, in the body of
+// ACTION_P(Add, n) above, you can write 'n_type' to refer to the type
+// of 'n'.
+//
+// We also provide ACTION_P2, ACTION_P3, ..., up to ACTION_P10 to support
+// multi-parameter actions.
+//
+// For the purpose of typing, you can view
+//
+// ACTION_Pk(Foo, p1, ..., pk) { ... }
+//
+// as shorthand for
+//
+// template <typename p1_type, ..., typename pk_type>
+// FooActionPk<p1_type, ..., pk_type> Foo(p1_type p1, ..., pk_type pk) { ... }
+//
+// In particular, you can provide the template type arguments
+// explicitly when invoking Foo(), as in Foo<long, bool>(5, false);
+// although usually you can rely on the compiler to infer the types
+// for you automatically. You can assign the result of expression
+// Foo(p1, ..., pk) to a variable of type FooActionPk<p1_type, ...,
+// pk_type>. This can be useful when composing actions.
+//
+// You can also overload actions with different numbers of parameters:
+//
+// ACTION_P(Plus, a) { ... }
+// ACTION_P2(Plus, a, b) { ... }
+//
+// While it's tempting to always use the ACTION* macros when defining
+// a new action, you should also consider implementing ActionInterface
+// or using MakePolymorphicAction() instead, especially if you need to
+// use the action a lot. While these approaches require more work,
+// they give you more control on the types of the mock function
+// arguments and the action parameters, which in general leads to
+// better compiler error messages that pay off in the long run. They
+// also allow overloading actions based on parameter types (as opposed
+// to just based on the number of parameters).
+//
+// CAVEAT:
+//
+// ACTION*() can only be used in a namespace scope. The reason is
+// that C++ doesn't yet allow function-local types to be used to
+// instantiate templates. The up-coming C++0x standard will fix this.
+// Once that's done, we'll consider supporting using ACTION*() inside
+// a function.
+//
+// MORE INFORMATION:
+//
+// To learn more about using these macros, please search for 'ACTION'
+// on http://code.google.com/p/googlemock/wiki/CookBook.
+
+// An internal macro needed for implementing ACTION*().
+#define GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_\
+ const args_type& args GTEST_ATTRIBUTE_UNUSED_, \
+ arg0_type arg0 GTEST_ATTRIBUTE_UNUSED_, \
+ arg1_type arg1 GTEST_ATTRIBUTE_UNUSED_, \
+ arg2_type arg2 GTEST_ATTRIBUTE_UNUSED_, \
+ arg3_type arg3 GTEST_ATTRIBUTE_UNUSED_, \
+ arg4_type arg4 GTEST_ATTRIBUTE_UNUSED_, \
+ arg5_type arg5 GTEST_ATTRIBUTE_UNUSED_, \
+ arg6_type arg6 GTEST_ATTRIBUTE_UNUSED_, \
+ arg7_type arg7 GTEST_ATTRIBUTE_UNUSED_, \
+ arg8_type arg8 GTEST_ATTRIBUTE_UNUSED_, \
+ arg9_type arg9 GTEST_ATTRIBUTE_UNUSED_
+
+// Sometimes you want to give an action explicit template parameters
+// that cannot be inferred from its value parameters. ACTION() and
+// ACTION_P*() don't support that. ACTION_TEMPLATE() remedies that
+// and can be viewed as an extension to ACTION() and ACTION_P*().
+//
+// The syntax:
+//
+// ACTION_TEMPLATE(ActionName,
+// HAS_m_TEMPLATE_PARAMS(kind1, name1, ..., kind_m, name_m),
+// AND_n_VALUE_PARAMS(p1, ..., p_n)) { statements; }
+//
+// defines an action template that takes m explicit template
+// parameters and n value parameters. name_i is the name of the i-th
+// template parameter, and kind_i specifies whether it's a typename,
+// an integral constant, or a template. p_i is the name of the i-th
+// value parameter.
+//
+// Example:
+//
+// // DuplicateArg<k, T>(output) converts the k-th argument of the mock
+// // function to type T and copies it to *output.
+// ACTION_TEMPLATE(DuplicateArg,
+// HAS_2_TEMPLATE_PARAMS(int, k, typename, T),
+// AND_1_VALUE_PARAMS(output)) {
+// *output = T(::testing::get<k>(args));
+// }
+// ...
+// int n;
+// EXPECT_CALL(mock, Foo(_, _))
+// .WillOnce(DuplicateArg<1, unsigned char>(&n));
+//
+// To create an instance of an action template, write:
+//
+// ActionName<t1, ..., t_m>(v1, ..., v_n)
+//
+// where the ts are the template arguments and the vs are the value
+// arguments. The value argument types are inferred by the compiler.
+// If you want to explicitly specify the value argument types, you can
+// provide additional template arguments:
+//
+// ActionName<t1, ..., t_m, u1, ..., u_k>(v1, ..., v_n)
+//
+// where u_i is the desired type of v_i.
+//
+// ACTION_TEMPLATE and ACTION/ACTION_P* can be overloaded on the
+// number of value parameters, but not on the number of template
+// parameters. Without the restriction, the meaning of the following
+// is unclear:
+//
+// OverloadedAction<int, bool>(x);
+//
+// Are we using a single-template-parameter action where 'bool' refers
+// to the type of x, or are we using a two-template-parameter action
+// where the compiler is asked to infer the type of x?
+//
+// Implementation notes:
+//
+// GMOCK_INTERNAL_*_HAS_m_TEMPLATE_PARAMS and
+// GMOCK_INTERNAL_*_AND_n_VALUE_PARAMS are internal macros for
+// implementing ACTION_TEMPLATE. The main trick we use is to create
+// new macro invocations when expanding a macro. For example, we have
+//
+// #define ACTION_TEMPLATE(name, template_params, value_params)
+// ... GMOCK_INTERNAL_DECL_##template_params ...
+//
+// which causes ACTION_TEMPLATE(..., HAS_1_TEMPLATE_PARAMS(typename, T), ...)
+// to expand to
+//
+// ... GMOCK_INTERNAL_DECL_HAS_1_TEMPLATE_PARAMS(typename, T) ...
+//
+// Since GMOCK_INTERNAL_DECL_HAS_1_TEMPLATE_PARAMS is a macro, the
+// preprocessor will continue to expand it to
+//
+// ... typename T ...
+//
+// This technique conforms to the C++ standard and is portable. It
+// allows us to implement action templates using O(N) code, where N is
+// the maximum number of template/value parameters supported. Without
+// using it, we'd have to devote O(N^2) amount of code to implement all
+// combinations of m and n.
+
+// Declares the template parameters.
+#define GMOCK_INTERNAL_DECL_HAS_1_TEMPLATE_PARAMS(kind0, name0) kind0 name0
+#define GMOCK_INTERNAL_DECL_HAS_2_TEMPLATE_PARAMS(kind0, name0, kind1, \
+ name1) kind0 name0, kind1 name1
+#define GMOCK_INTERNAL_DECL_HAS_3_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \
+ kind2, name2) kind0 name0, kind1 name1, kind2 name2
+#define GMOCK_INTERNAL_DECL_HAS_4_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \
+ kind2, name2, kind3, name3) kind0 name0, kind1 name1, kind2 name2, \
+ kind3 name3
+#define GMOCK_INTERNAL_DECL_HAS_5_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \
+ kind2, name2, kind3, name3, kind4, name4) kind0 name0, kind1 name1, \
+ kind2 name2, kind3 name3, kind4 name4
+#define GMOCK_INTERNAL_DECL_HAS_6_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \
+ kind2, name2, kind3, name3, kind4, name4, kind5, name5) kind0 name0, \
+ kind1 name1, kind2 name2, kind3 name3, kind4 name4, kind5 name5
+#define GMOCK_INTERNAL_DECL_HAS_7_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \
+ kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, \
+ name6) kind0 name0, kind1 name1, kind2 name2, kind3 name3, kind4 name4, \
+ kind5 name5, kind6 name6
+#define GMOCK_INTERNAL_DECL_HAS_8_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \
+ kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, name6, \
+ kind7, name7) kind0 name0, kind1 name1, kind2 name2, kind3 name3, \
+ kind4 name4, kind5 name5, kind6 name6, kind7 name7
+#define GMOCK_INTERNAL_DECL_HAS_9_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \
+ kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, name6, \
+ kind7, name7, kind8, name8) kind0 name0, kind1 name1, kind2 name2, \
+ kind3 name3, kind4 name4, kind5 name5, kind6 name6, kind7 name7, \
+ kind8 name8
+#define GMOCK_INTERNAL_DECL_HAS_10_TEMPLATE_PARAMS(kind0, name0, kind1, \
+ name1, kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, \
+ name6, kind7, name7, kind8, name8, kind9, name9) kind0 name0, \
+ kind1 name1, kind2 name2, kind3 name3, kind4 name4, kind5 name5, \
+ kind6 name6, kind7 name7, kind8 name8, kind9 name9
+
+// Lists the template parameters.
+#define GMOCK_INTERNAL_LIST_HAS_1_TEMPLATE_PARAMS(kind0, name0) name0
+#define GMOCK_INTERNAL_LIST_HAS_2_TEMPLATE_PARAMS(kind0, name0, kind1, \
+ name1) name0, name1
+#define GMOCK_INTERNAL_LIST_HAS_3_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \
+ kind2, name2) name0, name1, name2
+#define GMOCK_INTERNAL_LIST_HAS_4_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \
+ kind2, name2, kind3, name3) name0, name1, name2, name3
+#define GMOCK_INTERNAL_LIST_HAS_5_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \
+ kind2, name2, kind3, name3, kind4, name4) name0, name1, name2, name3, \
+ name4
+#define GMOCK_INTERNAL_LIST_HAS_6_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \
+ kind2, name2, kind3, name3, kind4, name4, kind5, name5) name0, name1, \
+ name2, name3, name4, name5
+#define GMOCK_INTERNAL_LIST_HAS_7_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \
+ kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, \
+ name6) name0, name1, name2, name3, name4, name5, name6
+#define GMOCK_INTERNAL_LIST_HAS_8_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \
+ kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, name6, \
+ kind7, name7) name0, name1, name2, name3, name4, name5, name6, name7
+#define GMOCK_INTERNAL_LIST_HAS_9_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \
+ kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, name6, \
+ kind7, name7, kind8, name8) name0, name1, name2, name3, name4, name5, \
+ name6, name7, name8
+#define GMOCK_INTERNAL_LIST_HAS_10_TEMPLATE_PARAMS(kind0, name0, kind1, \
+ name1, kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, \
+ name6, kind7, name7, kind8, name8, kind9, name9) name0, name1, name2, \
+ name3, name4, name5, name6, name7, name8, name9
+
+// Declares the types of value parameters.
+#define GMOCK_INTERNAL_DECL_TYPE_AND_0_VALUE_PARAMS()
+#define GMOCK_INTERNAL_DECL_TYPE_AND_1_VALUE_PARAMS(p0) , typename p0##_type
+#define GMOCK_INTERNAL_DECL_TYPE_AND_2_VALUE_PARAMS(p0, p1) , \
+ typename p0##_type, typename p1##_type
+#define GMOCK_INTERNAL_DECL_TYPE_AND_3_VALUE_PARAMS(p0, p1, p2) , \
+ typename p0##_type, typename p1##_type, typename p2##_type
+#define GMOCK_INTERNAL_DECL_TYPE_AND_4_VALUE_PARAMS(p0, p1, p2, p3) , \
+ typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type
+#define GMOCK_INTERNAL_DECL_TYPE_AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4) , \
+ typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type
+#define GMOCK_INTERNAL_DECL_TYPE_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5) , \
+ typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type
+#define GMOCK_INTERNAL_DECL_TYPE_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \
+ p6) , typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type, \
+ typename p6##_type
+#define GMOCK_INTERNAL_DECL_TYPE_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \
+ p6, p7) , typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type, \
+ typename p6##_type, typename p7##_type
+#define GMOCK_INTERNAL_DECL_TYPE_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \
+ p6, p7, p8) , typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type, \
+ typename p6##_type, typename p7##_type, typename p8##_type
+#define GMOCK_INTERNAL_DECL_TYPE_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \
+ p6, p7, p8, p9) , typename p0##_type, typename p1##_type, \
+ typename p2##_type, typename p3##_type, typename p4##_type, \
+ typename p5##_type, typename p6##_type, typename p7##_type, \
+ typename p8##_type, typename p9##_type
+
+// Initializes the value parameters.
+#define GMOCK_INTERNAL_INIT_AND_0_VALUE_PARAMS()\
+ ()
+#define GMOCK_INTERNAL_INIT_AND_1_VALUE_PARAMS(p0)\
+ (p0##_type gmock_p0) : p0(gmock_p0)
+#define GMOCK_INTERNAL_INIT_AND_2_VALUE_PARAMS(p0, p1)\
+ (p0##_type gmock_p0, p1##_type gmock_p1) : p0(gmock_p0), p1(gmock_p1)
+#define GMOCK_INTERNAL_INIT_AND_3_VALUE_PARAMS(p0, p1, p2)\
+ (p0##_type gmock_p0, p1##_type gmock_p1, \
+ p2##_type gmock_p2) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2)
+#define GMOCK_INTERNAL_INIT_AND_4_VALUE_PARAMS(p0, p1, p2, p3)\
+ (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
+ p3##_type gmock_p3) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
+ p3(gmock_p3)
+#define GMOCK_INTERNAL_INIT_AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4)\
+ (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
+ p3##_type gmock_p3, p4##_type gmock_p4) : p0(gmock_p0), p1(gmock_p1), \
+ p2(gmock_p2), p3(gmock_p3), p4(gmock_p4)
+#define GMOCK_INTERNAL_INIT_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5)\
+ (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
+ p3##_type gmock_p3, p4##_type gmock_p4, \
+ p5##_type gmock_p5) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
+ p3(gmock_p3), p4(gmock_p4), p5(gmock_p5)
+#define GMOCK_INTERNAL_INIT_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6)\
+ (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
+ p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
+ p6##_type gmock_p6) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
+ p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6)
+#define GMOCK_INTERNAL_INIT_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7)\
+ (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
+ p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
+ p6##_type gmock_p6, p7##_type gmock_p7) : p0(gmock_p0), p1(gmock_p1), \
+ p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \
+ p7(gmock_p7)
+#define GMOCK_INTERNAL_INIT_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \
+ p7, p8)\
+ (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
+ p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
+ p6##_type gmock_p6, p7##_type gmock_p7, \
+ p8##_type gmock_p8) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
+ p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \
+ p8(gmock_p8)
+#define GMOCK_INTERNAL_INIT_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \
+ p7, p8, p9)\
+ (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
+ p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
+ p6##_type gmock_p6, p7##_type gmock_p7, p8##_type gmock_p8, \
+ p9##_type gmock_p9) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
+ p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \
+ p8(gmock_p8), p9(gmock_p9)
+
+// Declares the fields for storing the value parameters.
+#define GMOCK_INTERNAL_DEFN_AND_0_VALUE_PARAMS()
+#define GMOCK_INTERNAL_DEFN_AND_1_VALUE_PARAMS(p0) p0##_type p0;
+#define GMOCK_INTERNAL_DEFN_AND_2_VALUE_PARAMS(p0, p1) p0##_type p0; \
+ p1##_type p1;
+#define GMOCK_INTERNAL_DEFN_AND_3_VALUE_PARAMS(p0, p1, p2) p0##_type p0; \
+ p1##_type p1; p2##_type p2;
+#define GMOCK_INTERNAL_DEFN_AND_4_VALUE_PARAMS(p0, p1, p2, p3) p0##_type p0; \
+ p1##_type p1; p2##_type p2; p3##_type p3;
+#define GMOCK_INTERNAL_DEFN_AND_5_VALUE_PARAMS(p0, p1, p2, p3, \
+ p4) p0##_type p0; p1##_type p1; p2##_type p2; p3##_type p3; p4##_type p4;
+#define GMOCK_INTERNAL_DEFN_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, \
+ p5) p0##_type p0; p1##_type p1; p2##_type p2; p3##_type p3; p4##_type p4; \
+ p5##_type p5;
+#define GMOCK_INTERNAL_DEFN_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \
+ p6) p0##_type p0; p1##_type p1; p2##_type p2; p3##_type p3; p4##_type p4; \
+ p5##_type p5; p6##_type p6;
+#define GMOCK_INTERNAL_DEFN_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \
+ p7) p0##_type p0; p1##_type p1; p2##_type p2; p3##_type p3; p4##_type p4; \
+ p5##_type p5; p6##_type p6; p7##_type p7;
+#define GMOCK_INTERNAL_DEFN_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \
+ p7, p8) p0##_type p0; p1##_type p1; p2##_type p2; p3##_type p3; \
+ p4##_type p4; p5##_type p5; p6##_type p6; p7##_type p7; p8##_type p8;
+#define GMOCK_INTERNAL_DEFN_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \
+ p7, p8, p9) p0##_type p0; p1##_type p1; p2##_type p2; p3##_type p3; \
+ p4##_type p4; p5##_type p5; p6##_type p6; p7##_type p7; p8##_type p8; \
+ p9##_type p9;
+
+// Lists the value parameters.
+#define GMOCK_INTERNAL_LIST_AND_0_VALUE_PARAMS()
+#define GMOCK_INTERNAL_LIST_AND_1_VALUE_PARAMS(p0) p0
+#define GMOCK_INTERNAL_LIST_AND_2_VALUE_PARAMS(p0, p1) p0, p1
+#define GMOCK_INTERNAL_LIST_AND_3_VALUE_PARAMS(p0, p1, p2) p0, p1, p2
+#define GMOCK_INTERNAL_LIST_AND_4_VALUE_PARAMS(p0, p1, p2, p3) p0, p1, p2, p3
+#define GMOCK_INTERNAL_LIST_AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4) p0, p1, \
+ p2, p3, p4
+#define GMOCK_INTERNAL_LIST_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5) p0, \
+ p1, p2, p3, p4, p5
+#define GMOCK_INTERNAL_LIST_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \
+ p6) p0, p1, p2, p3, p4, p5, p6
+#define GMOCK_INTERNAL_LIST_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \
+ p7) p0, p1, p2, p3, p4, p5, p6, p7
+#define GMOCK_INTERNAL_LIST_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \
+ p7, p8) p0, p1, p2, p3, p4, p5, p6, p7, p8
+#define GMOCK_INTERNAL_LIST_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \
+ p7, p8, p9) p0, p1, p2, p3, p4, p5, p6, p7, p8, p9
+
+// Lists the value parameter types.
+#define GMOCK_INTERNAL_LIST_TYPE_AND_0_VALUE_PARAMS()
+#define GMOCK_INTERNAL_LIST_TYPE_AND_1_VALUE_PARAMS(p0) , p0##_type
+#define GMOCK_INTERNAL_LIST_TYPE_AND_2_VALUE_PARAMS(p0, p1) , p0##_type, \
+ p1##_type
+#define GMOCK_INTERNAL_LIST_TYPE_AND_3_VALUE_PARAMS(p0, p1, p2) , p0##_type, \
+ p1##_type, p2##_type
+#define GMOCK_INTERNAL_LIST_TYPE_AND_4_VALUE_PARAMS(p0, p1, p2, p3) , \
+ p0##_type, p1##_type, p2##_type, p3##_type
+#define GMOCK_INTERNAL_LIST_TYPE_AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4) , \
+ p0##_type, p1##_type, p2##_type, p3##_type, p4##_type
+#define GMOCK_INTERNAL_LIST_TYPE_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5) , \
+ p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, p5##_type
+#define GMOCK_INTERNAL_LIST_TYPE_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \
+ p6) , p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, p5##_type, \
+ p6##_type
+#define GMOCK_INTERNAL_LIST_TYPE_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \
+ p6, p7) , p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \
+ p5##_type, p6##_type, p7##_type
+#define GMOCK_INTERNAL_LIST_TYPE_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \
+ p6, p7, p8) , p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \
+ p5##_type, p6##_type, p7##_type, p8##_type
+#define GMOCK_INTERNAL_LIST_TYPE_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \
+ p6, p7, p8, p9) , p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \
+ p5##_type, p6##_type, p7##_type, p8##_type, p9##_type
+
+// Declares the value parameters.
+#define GMOCK_INTERNAL_DECL_AND_0_VALUE_PARAMS()
+#define GMOCK_INTERNAL_DECL_AND_1_VALUE_PARAMS(p0) p0##_type p0
+#define GMOCK_INTERNAL_DECL_AND_2_VALUE_PARAMS(p0, p1) p0##_type p0, \
+ p1##_type p1
+#define GMOCK_INTERNAL_DECL_AND_3_VALUE_PARAMS(p0, p1, p2) p0##_type p0, \
+ p1##_type p1, p2##_type p2
+#define GMOCK_INTERNAL_DECL_AND_4_VALUE_PARAMS(p0, p1, p2, p3) p0##_type p0, \
+ p1##_type p1, p2##_type p2, p3##_type p3
+#define GMOCK_INTERNAL_DECL_AND_5_VALUE_PARAMS(p0, p1, p2, p3, \
+ p4) p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4
+#define GMOCK_INTERNAL_DECL_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, \
+ p5) p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4, \
+ p5##_type p5
+#define GMOCK_INTERNAL_DECL_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \
+ p6) p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4, \
+ p5##_type p5, p6##_type p6
+#define GMOCK_INTERNAL_DECL_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \
+ p7) p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4, \
+ p5##_type p5, p6##_type p6, p7##_type p7
+#define GMOCK_INTERNAL_DECL_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \
+ p7, p8) p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \
+ p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, p8##_type p8
+#define GMOCK_INTERNAL_DECL_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \
+ p7, p8, p9) p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \
+ p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, p8##_type p8, \
+ p9##_type p9
+
+// The suffix of the class template implementing the action template.
+#define GMOCK_INTERNAL_COUNT_AND_0_VALUE_PARAMS()
+#define GMOCK_INTERNAL_COUNT_AND_1_VALUE_PARAMS(p0) P
+#define GMOCK_INTERNAL_COUNT_AND_2_VALUE_PARAMS(p0, p1) P2
+#define GMOCK_INTERNAL_COUNT_AND_3_VALUE_PARAMS(p0, p1, p2) P3
+#define GMOCK_INTERNAL_COUNT_AND_4_VALUE_PARAMS(p0, p1, p2, p3) P4
+#define GMOCK_INTERNAL_COUNT_AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4) P5
+#define GMOCK_INTERNAL_COUNT_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5) P6
+#define GMOCK_INTERNAL_COUNT_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6) P7
+#define GMOCK_INTERNAL_COUNT_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \
+ p7) P8
+#define GMOCK_INTERNAL_COUNT_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \
+ p7, p8) P9
+#define GMOCK_INTERNAL_COUNT_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \
+ p7, p8, p9) P10
+
+// The name of the class template implementing the action template.
+#define GMOCK_ACTION_CLASS_(name, value_params)\
+ GTEST_CONCAT_TOKEN_(name##Action, GMOCK_INTERNAL_COUNT_##value_params)
+
+#define ACTION_TEMPLATE(name, template_params, value_params)\
+ template <GMOCK_INTERNAL_DECL_##template_params\
+ GMOCK_INTERNAL_DECL_TYPE_##value_params>\
+ class GMOCK_ACTION_CLASS_(name, value_params) {\
+ public:\
+ explicit GMOCK_ACTION_CLASS_(name, value_params)\
+ GMOCK_INTERNAL_INIT_##value_params {}\
+ template <typename F>\
+ class gmock_Impl : public ::testing::ActionInterface<F> {\
+ public:\
+ typedef F function_type;\
+ typedef typename ::testing::internal::Function<F>::Result return_type;\
+ typedef typename ::testing::internal::Function<F>::ArgumentTuple\
+ args_type;\
+ explicit gmock_Impl GMOCK_INTERNAL_INIT_##value_params {}\
+ virtual return_type Perform(const args_type& args) {\
+ return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
+ Perform(this, args);\
+ }\
+ template <typename arg0_type, typename arg1_type, typename arg2_type, \
+ typename arg3_type, typename arg4_type, typename arg5_type, \
+ typename arg6_type, typename arg7_type, typename arg8_type, \
+ typename arg9_type>\
+ return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
+ arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
+ arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
+ arg9_type arg9) const;\
+ GMOCK_INTERNAL_DEFN_##value_params\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
+ };\
+ template <typename F> operator ::testing::Action<F>() const {\
+ return ::testing::Action<F>(\
+ new gmock_Impl<F>(GMOCK_INTERNAL_LIST_##value_params));\
+ }\
+ GMOCK_INTERNAL_DEFN_##value_params\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(GMOCK_ACTION_CLASS_(name, value_params));\
+ };\
+ template <GMOCK_INTERNAL_DECL_##template_params\
+ GMOCK_INTERNAL_DECL_TYPE_##value_params>\
+ inline GMOCK_ACTION_CLASS_(name, value_params)<\
+ GMOCK_INTERNAL_LIST_##template_params\
+ GMOCK_INTERNAL_LIST_TYPE_##value_params> name(\
+ GMOCK_INTERNAL_DECL_##value_params) {\
+ return GMOCK_ACTION_CLASS_(name, value_params)<\
+ GMOCK_INTERNAL_LIST_##template_params\
+ GMOCK_INTERNAL_LIST_TYPE_##value_params>(\
+ GMOCK_INTERNAL_LIST_##value_params);\
+ }\
+ template <GMOCK_INTERNAL_DECL_##template_params\
+ GMOCK_INTERNAL_DECL_TYPE_##value_params>\
+ template <typename F>\
+ template <typename arg0_type, typename arg1_type, typename arg2_type, \
+ typename arg3_type, typename arg4_type, typename arg5_type, \
+ typename arg6_type, typename arg7_type, typename arg8_type, \
+ typename arg9_type>\
+ typename ::testing::internal::Function<F>::Result\
+ GMOCK_ACTION_CLASS_(name, value_params)<\
+ GMOCK_INTERNAL_LIST_##template_params\
+ GMOCK_INTERNAL_LIST_TYPE_##value_params>::gmock_Impl<F>::\
+ gmock_PerformImpl(\
+ GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const
+
+#define ACTION(name)\
+ class name##Action {\
+ public:\
+ name##Action() {}\
+ template <typename F>\
+ class gmock_Impl : public ::testing::ActionInterface<F> {\
+ public:\
+ typedef F function_type;\
+ typedef typename ::testing::internal::Function<F>::Result return_type;\
+ typedef typename ::testing::internal::Function<F>::ArgumentTuple\
+ args_type;\
+ gmock_Impl() {}\
+ virtual return_type Perform(const args_type& args) {\
+ return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
+ Perform(this, args);\
+ }\
+ template <typename arg0_type, typename arg1_type, typename arg2_type, \
+ typename arg3_type, typename arg4_type, typename arg5_type, \
+ typename arg6_type, typename arg7_type, typename arg8_type, \
+ typename arg9_type>\
+ return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
+ arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
+ arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
+ arg9_type arg9) const;\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
+ };\
+ template <typename F> operator ::testing::Action<F>() const {\
+ return ::testing::Action<F>(new gmock_Impl<F>());\
+ }\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(name##Action);\
+ };\
+ inline name##Action name() {\
+ return name##Action();\
+ }\
+ template <typename F>\
+ template <typename arg0_type, typename arg1_type, typename arg2_type, \
+ typename arg3_type, typename arg4_type, typename arg5_type, \
+ typename arg6_type, typename arg7_type, typename arg8_type, \
+ typename arg9_type>\
+ typename ::testing::internal::Function<F>::Result\
+ name##Action::gmock_Impl<F>::gmock_PerformImpl(\
+ GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const
+
+#define ACTION_P(name, p0)\
+ template <typename p0##_type>\
+ class name##ActionP {\
+ public:\
+ explicit name##ActionP(p0##_type gmock_p0) : p0(gmock_p0) {}\
+ template <typename F>\
+ class gmock_Impl : public ::testing::ActionInterface<F> {\
+ public:\
+ typedef F function_type;\
+ typedef typename ::testing::internal::Function<F>::Result return_type;\
+ typedef typename ::testing::internal::Function<F>::ArgumentTuple\
+ args_type;\
+ explicit gmock_Impl(p0##_type gmock_p0) : p0(gmock_p0) {}\
+ virtual return_type Perform(const args_type& args) {\
+ return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
+ Perform(this, args);\
+ }\
+ template <typename arg0_type, typename arg1_type, typename arg2_type, \
+ typename arg3_type, typename arg4_type, typename arg5_type, \
+ typename arg6_type, typename arg7_type, typename arg8_type, \
+ typename arg9_type>\
+ return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
+ arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
+ arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
+ arg9_type arg9) const;\
+ p0##_type p0;\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
+ };\
+ template <typename F> operator ::testing::Action<F>() const {\
+ return ::testing::Action<F>(new gmock_Impl<F>(p0));\
+ }\
+ p0##_type p0;\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(name##ActionP);\
+ };\
+ template <typename p0##_type>\
+ inline name##ActionP<p0##_type> name(p0##_type p0) {\
+ return name##ActionP<p0##_type>(p0);\
+ }\
+ template <typename p0##_type>\
+ template <typename F>\
+ template <typename arg0_type, typename arg1_type, typename arg2_type, \
+ typename arg3_type, typename arg4_type, typename arg5_type, \
+ typename arg6_type, typename arg7_type, typename arg8_type, \
+ typename arg9_type>\
+ typename ::testing::internal::Function<F>::Result\
+ name##ActionP<p0##_type>::gmock_Impl<F>::gmock_PerformImpl(\
+ GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const
+
+#define ACTION_P2(name, p0, p1)\
+ template <typename p0##_type, typename p1##_type>\
+ class name##ActionP2 {\
+ public:\
+ name##ActionP2(p0##_type gmock_p0, p1##_type gmock_p1) : p0(gmock_p0), \
+ p1(gmock_p1) {}\
+ template <typename F>\
+ class gmock_Impl : public ::testing::ActionInterface<F> {\
+ public:\
+ typedef F function_type;\
+ typedef typename ::testing::internal::Function<F>::Result return_type;\
+ typedef typename ::testing::internal::Function<F>::ArgumentTuple\
+ args_type;\
+ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1) : p0(gmock_p0), \
+ p1(gmock_p1) {}\
+ virtual return_type Perform(const args_type& args) {\
+ return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
+ Perform(this, args);\
+ }\
+ template <typename arg0_type, typename arg1_type, typename arg2_type, \
+ typename arg3_type, typename arg4_type, typename arg5_type, \
+ typename arg6_type, typename arg7_type, typename arg8_type, \
+ typename arg9_type>\
+ return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
+ arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
+ arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
+ arg9_type arg9) const;\
+ p0##_type p0;\
+ p1##_type p1;\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
+ };\
+ template <typename F> operator ::testing::Action<F>() const {\
+ return ::testing::Action<F>(new gmock_Impl<F>(p0, p1));\
+ }\
+ p0##_type p0;\
+ p1##_type p1;\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(name##ActionP2);\
+ };\
+ template <typename p0##_type, typename p1##_type>\
+ inline name##ActionP2<p0##_type, p1##_type> name(p0##_type p0, \
+ p1##_type p1) {\
+ return name##ActionP2<p0##_type, p1##_type>(p0, p1);\
+ }\
+ template <typename p0##_type, typename p1##_type>\
+ template <typename F>\
+ template <typename arg0_type, typename arg1_type, typename arg2_type, \
+ typename arg3_type, typename arg4_type, typename arg5_type, \
+ typename arg6_type, typename arg7_type, typename arg8_type, \
+ typename arg9_type>\
+ typename ::testing::internal::Function<F>::Result\
+ name##ActionP2<p0##_type, p1##_type>::gmock_Impl<F>::gmock_PerformImpl(\
+ GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const
+
+#define ACTION_P3(name, p0, p1, p2)\
+ template <typename p0##_type, typename p1##_type, typename p2##_type>\
+ class name##ActionP3 {\
+ public:\
+ name##ActionP3(p0##_type gmock_p0, p1##_type gmock_p1, \
+ p2##_type gmock_p2) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2) {}\
+ template <typename F>\
+ class gmock_Impl : public ::testing::ActionInterface<F> {\
+ public:\
+ typedef F function_type;\
+ typedef typename ::testing::internal::Function<F>::Result return_type;\
+ typedef typename ::testing::internal::Function<F>::ArgumentTuple\
+ args_type;\
+ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, \
+ p2##_type gmock_p2) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2) {}\
+ virtual return_type Perform(const args_type& args) {\
+ return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
+ Perform(this, args);\
+ }\
+ template <typename arg0_type, typename arg1_type, typename arg2_type, \
+ typename arg3_type, typename arg4_type, typename arg5_type, \
+ typename arg6_type, typename arg7_type, typename arg8_type, \
+ typename arg9_type>\
+ return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
+ arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
+ arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
+ arg9_type arg9) const;\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
+ };\
+ template <typename F> operator ::testing::Action<F>() const {\
+ return ::testing::Action<F>(new gmock_Impl<F>(p0, p1, p2));\
+ }\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(name##ActionP3);\
+ };\
+ template <typename p0##_type, typename p1##_type, typename p2##_type>\
+ inline name##ActionP3<p0##_type, p1##_type, p2##_type> name(p0##_type p0, \
+ p1##_type p1, p2##_type p2) {\
+ return name##ActionP3<p0##_type, p1##_type, p2##_type>(p0, p1, p2);\
+ }\
+ template <typename p0##_type, typename p1##_type, typename p2##_type>\
+ template <typename F>\
+ template <typename arg0_type, typename arg1_type, typename arg2_type, \
+ typename arg3_type, typename arg4_type, typename arg5_type, \
+ typename arg6_type, typename arg7_type, typename arg8_type, \
+ typename arg9_type>\
+ typename ::testing::internal::Function<F>::Result\
+ name##ActionP3<p0##_type, p1##_type, \
+ p2##_type>::gmock_Impl<F>::gmock_PerformImpl(\
+ GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const
+
+#define ACTION_P4(name, p0, p1, p2, p3)\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type>\
+ class name##ActionP4 {\
+ public:\
+ name##ActionP4(p0##_type gmock_p0, p1##_type gmock_p1, \
+ p2##_type gmock_p2, p3##_type gmock_p3) : p0(gmock_p0), p1(gmock_p1), \
+ p2(gmock_p2), p3(gmock_p3) {}\
+ template <typename F>\
+ class gmock_Impl : public ::testing::ActionInterface<F> {\
+ public:\
+ typedef F function_type;\
+ typedef typename ::testing::internal::Function<F>::Result return_type;\
+ typedef typename ::testing::internal::Function<F>::ArgumentTuple\
+ args_type;\
+ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
+ p3##_type gmock_p3) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
+ p3(gmock_p3) {}\
+ virtual return_type Perform(const args_type& args) {\
+ return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
+ Perform(this, args);\
+ }\
+ template <typename arg0_type, typename arg1_type, typename arg2_type, \
+ typename arg3_type, typename arg4_type, typename arg5_type, \
+ typename arg6_type, typename arg7_type, typename arg8_type, \
+ typename arg9_type>\
+ return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
+ arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
+ arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
+ arg9_type arg9) const;\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ p3##_type p3;\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
+ };\
+ template <typename F> operator ::testing::Action<F>() const {\
+ return ::testing::Action<F>(new gmock_Impl<F>(p0, p1, p2, p3));\
+ }\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ p3##_type p3;\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(name##ActionP4);\
+ };\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type>\
+ inline name##ActionP4<p0##_type, p1##_type, p2##_type, \
+ p3##_type> name(p0##_type p0, p1##_type p1, p2##_type p2, \
+ p3##_type p3) {\
+ return name##ActionP4<p0##_type, p1##_type, p2##_type, p3##_type>(p0, p1, \
+ p2, p3);\
+ }\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type>\
+ template <typename F>\
+ template <typename arg0_type, typename arg1_type, typename arg2_type, \
+ typename arg3_type, typename arg4_type, typename arg5_type, \
+ typename arg6_type, typename arg7_type, typename arg8_type, \
+ typename arg9_type>\
+ typename ::testing::internal::Function<F>::Result\
+ name##ActionP4<p0##_type, p1##_type, p2##_type, \
+ p3##_type>::gmock_Impl<F>::gmock_PerformImpl(\
+ GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const
+
+#define ACTION_P5(name, p0, p1, p2, p3, p4)\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type>\
+ class name##ActionP5 {\
+ public:\
+ name##ActionP5(p0##_type gmock_p0, p1##_type gmock_p1, \
+ p2##_type gmock_p2, p3##_type gmock_p3, \
+ p4##_type gmock_p4) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
+ p3(gmock_p3), p4(gmock_p4) {}\
+ template <typename F>\
+ class gmock_Impl : public ::testing::ActionInterface<F> {\
+ public:\
+ typedef F function_type;\
+ typedef typename ::testing::internal::Function<F>::Result return_type;\
+ typedef typename ::testing::internal::Function<F>::ArgumentTuple\
+ args_type;\
+ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
+ p3##_type gmock_p3, p4##_type gmock_p4) : p0(gmock_p0), \
+ p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), p4(gmock_p4) {}\
+ virtual return_type Perform(const args_type& args) {\
+ return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
+ Perform(this, args);\
+ }\
+ template <typename arg0_type, typename arg1_type, typename arg2_type, \
+ typename arg3_type, typename arg4_type, typename arg5_type, \
+ typename arg6_type, typename arg7_type, typename arg8_type, \
+ typename arg9_type>\
+ return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
+ arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
+ arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
+ arg9_type arg9) const;\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ p3##_type p3;\
+ p4##_type p4;\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
+ };\
+ template <typename F> operator ::testing::Action<F>() const {\
+ return ::testing::Action<F>(new gmock_Impl<F>(p0, p1, p2, p3, p4));\
+ }\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ p3##_type p3;\
+ p4##_type p4;\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(name##ActionP5);\
+ };\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type>\
+ inline name##ActionP5<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type> name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \
+ p4##_type p4) {\
+ return name##ActionP5<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type>(p0, p1, p2, p3, p4);\
+ }\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type>\
+ template <typename F>\
+ template <typename arg0_type, typename arg1_type, typename arg2_type, \
+ typename arg3_type, typename arg4_type, typename arg5_type, \
+ typename arg6_type, typename arg7_type, typename arg8_type, \
+ typename arg9_type>\
+ typename ::testing::internal::Function<F>::Result\
+ name##ActionP5<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type>::gmock_Impl<F>::gmock_PerformImpl(\
+ GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const
+
+#define ACTION_P6(name, p0, p1, p2, p3, p4, p5)\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type>\
+ class name##ActionP6 {\
+ public:\
+ name##ActionP6(p0##_type gmock_p0, p1##_type gmock_p1, \
+ p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \
+ p5##_type gmock_p5) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
+ p3(gmock_p3), p4(gmock_p4), p5(gmock_p5) {}\
+ template <typename F>\
+ class gmock_Impl : public ::testing::ActionInterface<F> {\
+ public:\
+ typedef F function_type;\
+ typedef typename ::testing::internal::Function<F>::Result return_type;\
+ typedef typename ::testing::internal::Function<F>::ArgumentTuple\
+ args_type;\
+ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
+ p3##_type gmock_p3, p4##_type gmock_p4, \
+ p5##_type gmock_p5) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
+ p3(gmock_p3), p4(gmock_p4), p5(gmock_p5) {}\
+ virtual return_type Perform(const args_type& args) {\
+ return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
+ Perform(this, args);\
+ }\
+ template <typename arg0_type, typename arg1_type, typename arg2_type, \
+ typename arg3_type, typename arg4_type, typename arg5_type, \
+ typename arg6_type, typename arg7_type, typename arg8_type, \
+ typename arg9_type>\
+ return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
+ arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
+ arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
+ arg9_type arg9) const;\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ p3##_type p3;\
+ p4##_type p4;\
+ p5##_type p5;\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
+ };\
+ template <typename F> operator ::testing::Action<F>() const {\
+ return ::testing::Action<F>(new gmock_Impl<F>(p0, p1, p2, p3, p4, p5));\
+ }\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ p3##_type p3;\
+ p4##_type p4;\
+ p5##_type p5;\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(name##ActionP6);\
+ };\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type>\
+ inline name##ActionP6<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type, p5##_type> name(p0##_type p0, p1##_type p1, p2##_type p2, \
+ p3##_type p3, p4##_type p4, p5##_type p5) {\
+ return name##ActionP6<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type, p5##_type>(p0, p1, p2, p3, p4, p5);\
+ }\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type>\
+ template <typename F>\
+ template <typename arg0_type, typename arg1_type, typename arg2_type, \
+ typename arg3_type, typename arg4_type, typename arg5_type, \
+ typename arg6_type, typename arg7_type, typename arg8_type, \
+ typename arg9_type>\
+ typename ::testing::internal::Function<F>::Result\
+ name##ActionP6<p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \
+ p5##_type>::gmock_Impl<F>::gmock_PerformImpl(\
+ GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const
+
+#define ACTION_P7(name, p0, p1, p2, p3, p4, p5, p6)\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type, \
+ typename p6##_type>\
+ class name##ActionP7 {\
+ public:\
+ name##ActionP7(p0##_type gmock_p0, p1##_type gmock_p1, \
+ p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \
+ p5##_type gmock_p5, p6##_type gmock_p6) : p0(gmock_p0), p1(gmock_p1), \
+ p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), \
+ p6(gmock_p6) {}\
+ template <typename F>\
+ class gmock_Impl : public ::testing::ActionInterface<F> {\
+ public:\
+ typedef F function_type;\
+ typedef typename ::testing::internal::Function<F>::Result return_type;\
+ typedef typename ::testing::internal::Function<F>::ArgumentTuple\
+ args_type;\
+ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
+ p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
+ p6##_type gmock_p6) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
+ p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6) {}\
+ virtual return_type Perform(const args_type& args) {\
+ return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
+ Perform(this, args);\
+ }\
+ template <typename arg0_type, typename arg1_type, typename arg2_type, \
+ typename arg3_type, typename arg4_type, typename arg5_type, \
+ typename arg6_type, typename arg7_type, typename arg8_type, \
+ typename arg9_type>\
+ return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
+ arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
+ arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
+ arg9_type arg9) const;\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ p3##_type p3;\
+ p4##_type p4;\
+ p5##_type p5;\
+ p6##_type p6;\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
+ };\
+ template <typename F> operator ::testing::Action<F>() const {\
+ return ::testing::Action<F>(new gmock_Impl<F>(p0, p1, p2, p3, p4, p5, \
+ p6));\
+ }\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ p3##_type p3;\
+ p4##_type p4;\
+ p5##_type p5;\
+ p6##_type p6;\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(name##ActionP7);\
+ };\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type, \
+ typename p6##_type>\
+ inline name##ActionP7<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type, p5##_type, p6##_type> name(p0##_type p0, p1##_type p1, \
+ p2##_type p2, p3##_type p3, p4##_type p4, p5##_type p5, \
+ p6##_type p6) {\
+ return name##ActionP7<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type, p5##_type, p6##_type>(p0, p1, p2, p3, p4, p5, p6);\
+ }\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type, \
+ typename p6##_type>\
+ template <typename F>\
+ template <typename arg0_type, typename arg1_type, typename arg2_type, \
+ typename arg3_type, typename arg4_type, typename arg5_type, \
+ typename arg6_type, typename arg7_type, typename arg8_type, \
+ typename arg9_type>\
+ typename ::testing::internal::Function<F>::Result\
+ name##ActionP7<p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \
+ p5##_type, p6##_type>::gmock_Impl<F>::gmock_PerformImpl(\
+ GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const
+
+#define ACTION_P8(name, p0, p1, p2, p3, p4, p5, p6, p7)\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type, \
+ typename p6##_type, typename p7##_type>\
+ class name##ActionP8 {\
+ public:\
+ name##ActionP8(p0##_type gmock_p0, p1##_type gmock_p1, \
+ p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \
+ p5##_type gmock_p5, p6##_type gmock_p6, \
+ p7##_type gmock_p7) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
+ p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \
+ p7(gmock_p7) {}\
+ template <typename F>\
+ class gmock_Impl : public ::testing::ActionInterface<F> {\
+ public:\
+ typedef F function_type;\
+ typedef typename ::testing::internal::Function<F>::Result return_type;\
+ typedef typename ::testing::internal::Function<F>::ArgumentTuple\
+ args_type;\
+ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
+ p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
+ p6##_type gmock_p6, p7##_type gmock_p7) : p0(gmock_p0), \
+ p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), \
+ p5(gmock_p5), p6(gmock_p6), p7(gmock_p7) {}\
+ virtual return_type Perform(const args_type& args) {\
+ return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
+ Perform(this, args);\
+ }\
+ template <typename arg0_type, typename arg1_type, typename arg2_type, \
+ typename arg3_type, typename arg4_type, typename arg5_type, \
+ typename arg6_type, typename arg7_type, typename arg8_type, \
+ typename arg9_type>\
+ return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
+ arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
+ arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
+ arg9_type arg9) const;\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ p3##_type p3;\
+ p4##_type p4;\
+ p5##_type p5;\
+ p6##_type p6;\
+ p7##_type p7;\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
+ };\
+ template <typename F> operator ::testing::Action<F>() const {\
+ return ::testing::Action<F>(new gmock_Impl<F>(p0, p1, p2, p3, p4, p5, \
+ p6, p7));\
+ }\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ p3##_type p3;\
+ p4##_type p4;\
+ p5##_type p5;\
+ p6##_type p6;\
+ p7##_type p7;\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(name##ActionP8);\
+ };\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type, \
+ typename p6##_type, typename p7##_type>\
+ inline name##ActionP8<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type, p5##_type, p6##_type, p7##_type> name(p0##_type p0, \
+ p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4, p5##_type p5, \
+ p6##_type p6, p7##_type p7) {\
+ return name##ActionP8<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type, p5##_type, p6##_type, p7##_type>(p0, p1, p2, p3, p4, p5, \
+ p6, p7);\
+ }\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type, \
+ typename p6##_type, typename p7##_type>\
+ template <typename F>\
+ template <typename arg0_type, typename arg1_type, typename arg2_type, \
+ typename arg3_type, typename arg4_type, typename arg5_type, \
+ typename arg6_type, typename arg7_type, typename arg8_type, \
+ typename arg9_type>\
+ typename ::testing::internal::Function<F>::Result\
+ name##ActionP8<p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \
+ p5##_type, p6##_type, \
+ p7##_type>::gmock_Impl<F>::gmock_PerformImpl(\
+ GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const
+
+#define ACTION_P9(name, p0, p1, p2, p3, p4, p5, p6, p7, p8)\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type, \
+ typename p6##_type, typename p7##_type, typename p8##_type>\
+ class name##ActionP9 {\
+ public:\
+ name##ActionP9(p0##_type gmock_p0, p1##_type gmock_p1, \
+ p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \
+ p5##_type gmock_p5, p6##_type gmock_p6, p7##_type gmock_p7, \
+ p8##_type gmock_p8) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
+ p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \
+ p8(gmock_p8) {}\
+ template <typename F>\
+ class gmock_Impl : public ::testing::ActionInterface<F> {\
+ public:\
+ typedef F function_type;\
+ typedef typename ::testing::internal::Function<F>::Result return_type;\
+ typedef typename ::testing::internal::Function<F>::ArgumentTuple\
+ args_type;\
+ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
+ p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
+ p6##_type gmock_p6, p7##_type gmock_p7, \
+ p8##_type gmock_p8) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
+ p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \
+ p7(gmock_p7), p8(gmock_p8) {}\
+ virtual return_type Perform(const args_type& args) {\
+ return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
+ Perform(this, args);\
+ }\
+ template <typename arg0_type, typename arg1_type, typename arg2_type, \
+ typename arg3_type, typename arg4_type, typename arg5_type, \
+ typename arg6_type, typename arg7_type, typename arg8_type, \
+ typename arg9_type>\
+ return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
+ arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
+ arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
+ arg9_type arg9) const;\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ p3##_type p3;\
+ p4##_type p4;\
+ p5##_type p5;\
+ p6##_type p6;\
+ p7##_type p7;\
+ p8##_type p8;\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
+ };\
+ template <typename F> operator ::testing::Action<F>() const {\
+ return ::testing::Action<F>(new gmock_Impl<F>(p0, p1, p2, p3, p4, p5, \
+ p6, p7, p8));\
+ }\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ p3##_type p3;\
+ p4##_type p4;\
+ p5##_type p5;\
+ p6##_type p6;\
+ p7##_type p7;\
+ p8##_type p8;\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(name##ActionP9);\
+ };\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type, \
+ typename p6##_type, typename p7##_type, typename p8##_type>\
+ inline name##ActionP9<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type, p5##_type, p6##_type, p7##_type, \
+ p8##_type> name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \
+ p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, \
+ p8##_type p8) {\
+ return name##ActionP9<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type, p5##_type, p6##_type, p7##_type, p8##_type>(p0, p1, p2, \
+ p3, p4, p5, p6, p7, p8);\
+ }\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type, \
+ typename p6##_type, typename p7##_type, typename p8##_type>\
+ template <typename F>\
+ template <typename arg0_type, typename arg1_type, typename arg2_type, \
+ typename arg3_type, typename arg4_type, typename arg5_type, \
+ typename arg6_type, typename arg7_type, typename arg8_type, \
+ typename arg9_type>\
+ typename ::testing::internal::Function<F>::Result\
+ name##ActionP9<p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \
+ p5##_type, p6##_type, p7##_type, \
+ p8##_type>::gmock_Impl<F>::gmock_PerformImpl(\
+ GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const
+
+#define ACTION_P10(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type, \
+ typename p6##_type, typename p7##_type, typename p8##_type, \
+ typename p9##_type>\
+ class name##ActionP10 {\
+ public:\
+ name##ActionP10(p0##_type gmock_p0, p1##_type gmock_p1, \
+ p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \
+ p5##_type gmock_p5, p6##_type gmock_p6, p7##_type gmock_p7, \
+ p8##_type gmock_p8, p9##_type gmock_p9) : p0(gmock_p0), p1(gmock_p1), \
+ p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \
+ p7(gmock_p7), p8(gmock_p8), p9(gmock_p9) {}\
+ template <typename F>\
+ class gmock_Impl : public ::testing::ActionInterface<F> {\
+ public:\
+ typedef F function_type;\
+ typedef typename ::testing::internal::Function<F>::Result return_type;\
+ typedef typename ::testing::internal::Function<F>::ArgumentTuple\
+ args_type;\
+ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
+ p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
+ p6##_type gmock_p6, p7##_type gmock_p7, p8##_type gmock_p8, \
+ p9##_type gmock_p9) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
+ p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \
+ p7(gmock_p7), p8(gmock_p8), p9(gmock_p9) {}\
+ virtual return_type Perform(const args_type& args) {\
+ return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
+ Perform(this, args);\
+ }\
+ template <typename arg0_type, typename arg1_type, typename arg2_type, \
+ typename arg3_type, typename arg4_type, typename arg5_type, \
+ typename arg6_type, typename arg7_type, typename arg8_type, \
+ typename arg9_type>\
+ return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
+ arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
+ arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
+ arg9_type arg9) const;\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ p3##_type p3;\
+ p4##_type p4;\
+ p5##_type p5;\
+ p6##_type p6;\
+ p7##_type p7;\
+ p8##_type p8;\
+ p9##_type p9;\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
+ };\
+ template <typename F> operator ::testing::Action<F>() const {\
+ return ::testing::Action<F>(new gmock_Impl<F>(p0, p1, p2, p3, p4, p5, \
+ p6, p7, p8, p9));\
+ }\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ p3##_type p3;\
+ p4##_type p4;\
+ p5##_type p5;\
+ p6##_type p6;\
+ p7##_type p7;\
+ p8##_type p8;\
+ p9##_type p9;\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(name##ActionP10);\
+ };\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type, \
+ typename p6##_type, typename p7##_type, typename p8##_type, \
+ typename p9##_type>\
+ inline name##ActionP10<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type, p5##_type, p6##_type, p7##_type, p8##_type, \
+ p9##_type> name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \
+ p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, p8##_type p8, \
+ p9##_type p9) {\
+ return name##ActionP10<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type, p5##_type, p6##_type, p7##_type, p8##_type, p9##_type>(p0, \
+ p1, p2, p3, p4, p5, p6, p7, p8, p9);\
+ }\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type, \
+ typename p6##_type, typename p7##_type, typename p8##_type, \
+ typename p9##_type>\
+ template <typename F>\
+ template <typename arg0_type, typename arg1_type, typename arg2_type, \
+ typename arg3_type, typename arg4_type, typename arg5_type, \
+ typename arg6_type, typename arg7_type, typename arg8_type, \
+ typename arg9_type>\
+ typename ::testing::internal::Function<F>::Result\
+ name##ActionP10<p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \
+ p5##_type, p6##_type, p7##_type, p8##_type, \
+ p9##_type>::gmock_Impl<F>::gmock_PerformImpl(\
+ GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const
+
+namespace testing {
+
+
+// The ACTION*() macros trigger warning C4100 (unreferenced formal
+// parameter) in MSVC with -W4. Unfortunately they cannot be fixed in
+// the macro definition, as the warnings are generated when the macro
+// is expanded and macro expansion cannot contain #pragma. Therefore
+// we suppress them here.
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable:4100)
+#endif
+
+// Various overloads for InvokeArgument<N>().
+//
+// The InvokeArgument<N>(a1, a2, ..., a_k) action invokes the N-th
+// (0-based) argument, which must be a k-ary callable, of the mock
+// function, with arguments a1, a2, ..., a_k.
+//
+// Notes:
+//
+// 1. The arguments are passed by value by default. If you need to
+// pass an argument by reference, wrap it inside ByRef(). For
+// example,
+//
+// InvokeArgument<1>(5, string("Hello"), ByRef(foo))
+//
+// passes 5 and string("Hello") by value, and passes foo by
+// reference.
+//
+// 2. If the callable takes an argument by reference but ByRef() is
+// not used, it will receive the reference to a copy of the value,
+// instead of the original value. For example, when the 0-th
+// argument of the mock function takes a const string&, the action
+//
+// InvokeArgument<0>(string("Hello"))
+//
+// makes a copy of the temporary string("Hello") object and passes a
+// reference of the copy, instead of the original temporary object,
+// to the callable. This makes it easy for a user to define an
+// InvokeArgument action from temporary values and have it performed
+// later.
+
+namespace internal {
+namespace invoke_argument {
+
+// Appears in InvokeArgumentAdl's argument list to help avoid
+// accidental calls to user functions of the same name.
+struct AdlTag {};
+
+// InvokeArgumentAdl - a helper for InvokeArgument.
+// The basic overloads are provided here for generic functors.
+// Overloads for other custom-callables are provided in the
+// internal/custom/callback-actions.h header.
+
+template <typename R, typename F>
+R InvokeArgumentAdl(AdlTag, F f) {
+ return f();
+}
+template <typename R, typename F, typename A1>
+R InvokeArgumentAdl(AdlTag, F f, A1 a1) {
+ return f(a1);
+}
+template <typename R, typename F, typename A1, typename A2>
+R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2) {
+ return f(a1, a2);
+}
+template <typename R, typename F, typename A1, typename A2, typename A3>
+R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3) {
+ return f(a1, a2, a3);
+}
+template <typename R, typename F, typename A1, typename A2, typename A3,
+ typename A4>
+R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4) {
+ return f(a1, a2, a3, a4);
+}
+template <typename R, typename F, typename A1, typename A2, typename A3,
+ typename A4, typename A5>
+R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) {
+ return f(a1, a2, a3, a4, a5);
+}
+template <typename R, typename F, typename A1, typename A2, typename A3,
+ typename A4, typename A5, typename A6>
+R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) {
+ return f(a1, a2, a3, a4, a5, a6);
+}
+template <typename R, typename F, typename A1, typename A2, typename A3,
+ typename A4, typename A5, typename A6, typename A7>
+R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6,
+ A7 a7) {
+ return f(a1, a2, a3, a4, a5, a6, a7);
+}
+template <typename R, typename F, typename A1, typename A2, typename A3,
+ typename A4, typename A5, typename A6, typename A7, typename A8>
+R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6,
+ A7 a7, A8 a8) {
+ return f(a1, a2, a3, a4, a5, a6, a7, a8);
+}
+template <typename R, typename F, typename A1, typename A2, typename A3,
+ typename A4, typename A5, typename A6, typename A7, typename A8,
+ typename A9>
+R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6,
+ A7 a7, A8 a8, A9 a9) {
+ return f(a1, a2, a3, a4, a5, a6, a7, a8, a9);
+}
+template <typename R, typename F, typename A1, typename A2, typename A3,
+ typename A4, typename A5, typename A6, typename A7, typename A8,
+ typename A9, typename A10>
+R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6,
+ A7 a7, A8 a8, A9 a9, A10 a10) {
+ return f(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
+}
+} // namespace invoke_argument
+} // namespace internal
+
+ACTION_TEMPLATE(InvokeArgument,
+ HAS_1_TEMPLATE_PARAMS(int, k),
+ AND_0_VALUE_PARAMS()) {
+ using internal::invoke_argument::InvokeArgumentAdl;
+ return InvokeArgumentAdl<return_type>(
+ internal::invoke_argument::AdlTag(),
+ ::testing::get<k>(args));
+}
+
+ACTION_TEMPLATE(InvokeArgument,
+ HAS_1_TEMPLATE_PARAMS(int, k),
+ AND_1_VALUE_PARAMS(p0)) {
+ using internal::invoke_argument::InvokeArgumentAdl;
+ return InvokeArgumentAdl<return_type>(
+ internal::invoke_argument::AdlTag(),
+ ::testing::get<k>(args), p0);
+}
+
+ACTION_TEMPLATE(InvokeArgument,
+ HAS_1_TEMPLATE_PARAMS(int, k),
+ AND_2_VALUE_PARAMS(p0, p1)) {
+ using internal::invoke_argument::InvokeArgumentAdl;
+ return InvokeArgumentAdl<return_type>(
+ internal::invoke_argument::AdlTag(),
+ ::testing::get<k>(args), p0, p1);
+}
+
+ACTION_TEMPLATE(InvokeArgument,
+ HAS_1_TEMPLATE_PARAMS(int, k),
+ AND_3_VALUE_PARAMS(p0, p1, p2)) {
+ using internal::invoke_argument::InvokeArgumentAdl;
+ return InvokeArgumentAdl<return_type>(
+ internal::invoke_argument::AdlTag(),
+ ::testing::get<k>(args), p0, p1, p2);
+}
+
+ACTION_TEMPLATE(InvokeArgument,
+ HAS_1_TEMPLATE_PARAMS(int, k),
+ AND_4_VALUE_PARAMS(p0, p1, p2, p3)) {
+ using internal::invoke_argument::InvokeArgumentAdl;
+ return InvokeArgumentAdl<return_type>(
+ internal::invoke_argument::AdlTag(),
+ ::testing::get<k>(args), p0, p1, p2, p3);
+}
+
+ACTION_TEMPLATE(InvokeArgument,
+ HAS_1_TEMPLATE_PARAMS(int, k),
+ AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4)) {
+ using internal::invoke_argument::InvokeArgumentAdl;
+ return InvokeArgumentAdl<return_type>(
+ internal::invoke_argument::AdlTag(),
+ ::testing::get<k>(args), p0, p1, p2, p3, p4);
+}
+
+ACTION_TEMPLATE(InvokeArgument,
+ HAS_1_TEMPLATE_PARAMS(int, k),
+ AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5)) {
+ using internal::invoke_argument::InvokeArgumentAdl;
+ return InvokeArgumentAdl<return_type>(
+ internal::invoke_argument::AdlTag(),
+ ::testing::get<k>(args), p0, p1, p2, p3, p4, p5);
+}
+
+ACTION_TEMPLATE(InvokeArgument,
+ HAS_1_TEMPLATE_PARAMS(int, k),
+ AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6)) {
+ using internal::invoke_argument::InvokeArgumentAdl;
+ return InvokeArgumentAdl<return_type>(
+ internal::invoke_argument::AdlTag(),
+ ::testing::get<k>(args), p0, p1, p2, p3, p4, p5, p6);
+}
+
+ACTION_TEMPLATE(InvokeArgument,
+ HAS_1_TEMPLATE_PARAMS(int, k),
+ AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7)) {
+ using internal::invoke_argument::InvokeArgumentAdl;
+ return InvokeArgumentAdl<return_type>(
+ internal::invoke_argument::AdlTag(),
+ ::testing::get<k>(args), p0, p1, p2, p3, p4, p5, p6, p7);
+}
+
+ACTION_TEMPLATE(InvokeArgument,
+ HAS_1_TEMPLATE_PARAMS(int, k),
+ AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7, p8)) {
+ using internal::invoke_argument::InvokeArgumentAdl;
+ return InvokeArgumentAdl<return_type>(
+ internal::invoke_argument::AdlTag(),
+ ::testing::get<k>(args), p0, p1, p2, p3, p4, p5, p6, p7, p8);
+}
+
+ACTION_TEMPLATE(InvokeArgument,
+ HAS_1_TEMPLATE_PARAMS(int, k),
+ AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)) {
+ using internal::invoke_argument::InvokeArgumentAdl;
+ return InvokeArgumentAdl<return_type>(
+ internal::invoke_argument::AdlTag(),
+ ::testing::get<k>(args), p0, p1, p2, p3, p4, p5, p6, p7, p8, p9);
+}
+
+// Various overloads for ReturnNew<T>().
+//
+// The ReturnNew<T>(a1, a2, ..., a_k) action returns a pointer to a new
+// instance of type T, constructed on the heap with constructor arguments
+// a1, a2, ..., and a_k. The caller assumes ownership of the returned value.
+ACTION_TEMPLATE(ReturnNew,
+ HAS_1_TEMPLATE_PARAMS(typename, T),
+ AND_0_VALUE_PARAMS()) {
+ return new T();
+}
+
+ACTION_TEMPLATE(ReturnNew,
+ HAS_1_TEMPLATE_PARAMS(typename, T),
+ AND_1_VALUE_PARAMS(p0)) {
+ return new T(p0);
+}
+
+ACTION_TEMPLATE(ReturnNew,
+ HAS_1_TEMPLATE_PARAMS(typename, T),
+ AND_2_VALUE_PARAMS(p0, p1)) {
+ return new T(p0, p1);
+}
+
+ACTION_TEMPLATE(ReturnNew,
+ HAS_1_TEMPLATE_PARAMS(typename, T),
+ AND_3_VALUE_PARAMS(p0, p1, p2)) {
+ return new T(p0, p1, p2);
+}
+
+ACTION_TEMPLATE(ReturnNew,
+ HAS_1_TEMPLATE_PARAMS(typename, T),
+ AND_4_VALUE_PARAMS(p0, p1, p2, p3)) {
+ return new T(p0, p1, p2, p3);
+}
+
+ACTION_TEMPLATE(ReturnNew,
+ HAS_1_TEMPLATE_PARAMS(typename, T),
+ AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4)) {
+ return new T(p0, p1, p2, p3, p4);
+}
+
+ACTION_TEMPLATE(ReturnNew,
+ HAS_1_TEMPLATE_PARAMS(typename, T),
+ AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5)) {
+ return new T(p0, p1, p2, p3, p4, p5);
+}
+
+ACTION_TEMPLATE(ReturnNew,
+ HAS_1_TEMPLATE_PARAMS(typename, T),
+ AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6)) {
+ return new T(p0, p1, p2, p3, p4, p5, p6);
+}
+
+ACTION_TEMPLATE(ReturnNew,
+ HAS_1_TEMPLATE_PARAMS(typename, T),
+ AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7)) {
+ return new T(p0, p1, p2, p3, p4, p5, p6, p7);
+}
+
+ACTION_TEMPLATE(ReturnNew,
+ HAS_1_TEMPLATE_PARAMS(typename, T),
+ AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7, p8)) {
+ return new T(p0, p1, p2, p3, p4, p5, p6, p7, p8);
+}
+
+ACTION_TEMPLATE(ReturnNew,
+ HAS_1_TEMPLATE_PARAMS(typename, T),
+ AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)) {
+ return new T(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9);
+}
+
+#ifdef _MSC_VER
+# pragma warning(pop)
+#endif
+
+} // namespace testing
+
+// Include any custom actions added by the local installation.
+// We must include this header at the end to make sure it can use the
+// declarations from this file.
+#include "gmock/internal/custom/gmock-generated-actions.h"
+
+#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_
diff --git a/extern/gmock/include/gmock/gmock-generated-function-mockers.h b/extern/gmock/include/gmock/gmock-generated-function-mockers.h
new file mode 100644
index 00000000000..4fa5ca94849
--- /dev/null
+++ b/extern/gmock/include/gmock/gmock-generated-function-mockers.h
@@ -0,0 +1,1095 @@
+// This file was GENERATED by command:
+// pump.py gmock-generated-function-mockers.h.pump
+// DO NOT EDIT BY HAND!!!
+
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Google Mock - a framework for writing C++ mock classes.
+//
+// This file implements function mockers of various arities.
+
+#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_
+#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_
+
+#include "gmock/gmock-spec-builders.h"
+#include "gmock/internal/gmock-internal-utils.h"
+
+#if GTEST_HAS_STD_FUNCTION_
+# include <functional>
+#endif
+
+namespace testing {
+namespace internal {
+
+template <typename F>
+class FunctionMockerBase;
+
+// Note: class FunctionMocker really belongs to the ::testing
+// namespace. However if we define it in ::testing, MSVC will
+// complain when classes in ::testing::internal declare it as a
+// friend class template. To workaround this compiler bug, we define
+// FunctionMocker in ::testing::internal and import it into ::testing.
+template <typename F>
+class FunctionMocker;
+
+template <typename R>
+class FunctionMocker<R()> : public
+ internal::FunctionMockerBase<R()> {
+ public:
+ typedef R F();
+ typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
+
+ MockSpec<F>& With() {
+ return this->current_spec();
+ }
+
+ R Invoke() {
+ // Even though gcc and MSVC don't enforce it, 'this->' is required
+ // by the C++ standard [14.6.4] here, as the base class type is
+ // dependent on the template argument (and thus shouldn't be
+ // looked into when resolving InvokeWith).
+ return this->InvokeWith(ArgumentTuple());
+ }
+};
+
+template <typename R, typename A1>
+class FunctionMocker<R(A1)> : public
+ internal::FunctionMockerBase<R(A1)> {
+ public:
+ typedef R F(A1);
+ typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
+
+ MockSpec<F>& With(const Matcher<A1>& m1) {
+ this->current_spec().SetMatchers(::testing::make_tuple(m1));
+ return this->current_spec();
+ }
+
+ R Invoke(A1 a1) {
+ // Even though gcc and MSVC don't enforce it, 'this->' is required
+ // by the C++ standard [14.6.4] here, as the base class type is
+ // dependent on the template argument (and thus shouldn't be
+ // looked into when resolving InvokeWith).
+ return this->InvokeWith(ArgumentTuple(a1));
+ }
+};
+
+template <typename R, typename A1, typename A2>
+class FunctionMocker<R(A1, A2)> : public
+ internal::FunctionMockerBase<R(A1, A2)> {
+ public:
+ typedef R F(A1, A2);
+ typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
+
+ MockSpec<F>& With(const Matcher<A1>& m1, const Matcher<A2>& m2) {
+ this->current_spec().SetMatchers(::testing::make_tuple(m1, m2));
+ return this->current_spec();
+ }
+
+ R Invoke(A1 a1, A2 a2) {
+ // Even though gcc and MSVC don't enforce it, 'this->' is required
+ // by the C++ standard [14.6.4] here, as the base class type is
+ // dependent on the template argument (and thus shouldn't be
+ // looked into when resolving InvokeWith).
+ return this->InvokeWith(ArgumentTuple(a1, a2));
+ }
+};
+
+template <typename R, typename A1, typename A2, typename A3>
+class FunctionMocker<R(A1, A2, A3)> : public
+ internal::FunctionMockerBase<R(A1, A2, A3)> {
+ public:
+ typedef R F(A1, A2, A3);
+ typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
+
+ MockSpec<F>& With(const Matcher<A1>& m1, const Matcher<A2>& m2,
+ const Matcher<A3>& m3) {
+ this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3));
+ return this->current_spec();
+ }
+
+ R Invoke(A1 a1, A2 a2, A3 a3) {
+ // Even though gcc and MSVC don't enforce it, 'this->' is required
+ // by the C++ standard [14.6.4] here, as the base class type is
+ // dependent on the template argument (and thus shouldn't be
+ // looked into when resolving InvokeWith).
+ return this->InvokeWith(ArgumentTuple(a1, a2, a3));
+ }
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4>
+class FunctionMocker<R(A1, A2, A3, A4)> : public
+ internal::FunctionMockerBase<R(A1, A2, A3, A4)> {
+ public:
+ typedef R F(A1, A2, A3, A4);
+ typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
+
+ MockSpec<F>& With(const Matcher<A1>& m1, const Matcher<A2>& m2,
+ const Matcher<A3>& m3, const Matcher<A4>& m4) {
+ this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4));
+ return this->current_spec();
+ }
+
+ R Invoke(A1 a1, A2 a2, A3 a3, A4 a4) {
+ // Even though gcc and MSVC don't enforce it, 'this->' is required
+ // by the C++ standard [14.6.4] here, as the base class type is
+ // dependent on the template argument (and thus shouldn't be
+ // looked into when resolving InvokeWith).
+ return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4));
+ }
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5>
+class FunctionMocker<R(A1, A2, A3, A4, A5)> : public
+ internal::FunctionMockerBase<R(A1, A2, A3, A4, A5)> {
+ public:
+ typedef R F(A1, A2, A3, A4, A5);
+ typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
+
+ MockSpec<F>& With(const Matcher<A1>& m1, const Matcher<A2>& m2,
+ const Matcher<A3>& m3, const Matcher<A4>& m4, const Matcher<A5>& m5) {
+ this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4, m5));
+ return this->current_spec();
+ }
+
+ R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) {
+ // Even though gcc and MSVC don't enforce it, 'this->' is required
+ // by the C++ standard [14.6.4] here, as the base class type is
+ // dependent on the template argument (and thus shouldn't be
+ // looked into when resolving InvokeWith).
+ return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5));
+ }
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6>
+class FunctionMocker<R(A1, A2, A3, A4, A5, A6)> : public
+ internal::FunctionMockerBase<R(A1, A2, A3, A4, A5, A6)> {
+ public:
+ typedef R F(A1, A2, A3, A4, A5, A6);
+ typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
+
+ MockSpec<F>& With(const Matcher<A1>& m1, const Matcher<A2>& m2,
+ const Matcher<A3>& m3, const Matcher<A4>& m4, const Matcher<A5>& m5,
+ const Matcher<A6>& m6) {
+ this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4, m5,
+ m6));
+ return this->current_spec();
+ }
+
+ R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) {
+ // Even though gcc and MSVC don't enforce it, 'this->' is required
+ // by the C++ standard [14.6.4] here, as the base class type is
+ // dependent on the template argument (and thus shouldn't be
+ // looked into when resolving InvokeWith).
+ return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6));
+ }
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6, typename A7>
+class FunctionMocker<R(A1, A2, A3, A4, A5, A6, A7)> : public
+ internal::FunctionMockerBase<R(A1, A2, A3, A4, A5, A6, A7)> {
+ public:
+ typedef R F(A1, A2, A3, A4, A5, A6, A7);
+ typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
+
+ MockSpec<F>& With(const Matcher<A1>& m1, const Matcher<A2>& m2,
+ const Matcher<A3>& m3, const Matcher<A4>& m4, const Matcher<A5>& m5,
+ const Matcher<A6>& m6, const Matcher<A7>& m7) {
+ this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4, m5,
+ m6, m7));
+ return this->current_spec();
+ }
+
+ R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) {
+ // Even though gcc and MSVC don't enforce it, 'this->' is required
+ // by the C++ standard [14.6.4] here, as the base class type is
+ // dependent on the template argument (and thus shouldn't be
+ // looked into when resolving InvokeWith).
+ return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6, a7));
+ }
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6, typename A7, typename A8>
+class FunctionMocker<R(A1, A2, A3, A4, A5, A6, A7, A8)> : public
+ internal::FunctionMockerBase<R(A1, A2, A3, A4, A5, A6, A7, A8)> {
+ public:
+ typedef R F(A1, A2, A3, A4, A5, A6, A7, A8);
+ typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
+
+ MockSpec<F>& With(const Matcher<A1>& m1, const Matcher<A2>& m2,
+ const Matcher<A3>& m3, const Matcher<A4>& m4, const Matcher<A5>& m5,
+ const Matcher<A6>& m6, const Matcher<A7>& m7, const Matcher<A8>& m8) {
+ this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4, m5,
+ m6, m7, m8));
+ return this->current_spec();
+ }
+
+ R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) {
+ // Even though gcc and MSVC don't enforce it, 'this->' is required
+ // by the C++ standard [14.6.4] here, as the base class type is
+ // dependent on the template argument (and thus shouldn't be
+ // looked into when resolving InvokeWith).
+ return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6, a7, a8));
+ }
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6, typename A7, typename A8, typename A9>
+class FunctionMocker<R(A1, A2, A3, A4, A5, A6, A7, A8, A9)> : public
+ internal::FunctionMockerBase<R(A1, A2, A3, A4, A5, A6, A7, A8, A9)> {
+ public:
+ typedef R F(A1, A2, A3, A4, A5, A6, A7, A8, A9);
+ typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
+
+ MockSpec<F>& With(const Matcher<A1>& m1, const Matcher<A2>& m2,
+ const Matcher<A3>& m3, const Matcher<A4>& m4, const Matcher<A5>& m5,
+ const Matcher<A6>& m6, const Matcher<A7>& m7, const Matcher<A8>& m8,
+ const Matcher<A9>& m9) {
+ this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4, m5,
+ m6, m7, m8, m9));
+ return this->current_spec();
+ }
+
+ R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) {
+ // Even though gcc and MSVC don't enforce it, 'this->' is required
+ // by the C++ standard [14.6.4] here, as the base class type is
+ // dependent on the template argument (and thus shouldn't be
+ // looked into when resolving InvokeWith).
+ return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6, a7, a8, a9));
+ }
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6, typename A7, typename A8, typename A9,
+ typename A10>
+class FunctionMocker<R(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)> : public
+ internal::FunctionMockerBase<R(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)> {
+ public:
+ typedef R F(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10);
+ typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
+
+ MockSpec<F>& With(const Matcher<A1>& m1, const Matcher<A2>& m2,
+ const Matcher<A3>& m3, const Matcher<A4>& m4, const Matcher<A5>& m5,
+ const Matcher<A6>& m6, const Matcher<A7>& m7, const Matcher<A8>& m8,
+ const Matcher<A9>& m9, const Matcher<A10>& m10) {
+ this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4, m5,
+ m6, m7, m8, m9, m10));
+ return this->current_spec();
+ }
+
+ R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9,
+ A10 a10) {
+ // Even though gcc and MSVC don't enforce it, 'this->' is required
+ // by the C++ standard [14.6.4] here, as the base class type is
+ // dependent on the template argument (and thus shouldn't be
+ // looked into when resolving InvokeWith).
+ return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6, a7, a8, a9,
+ a10));
+ }
+};
+
+} // namespace internal
+
+// The style guide prohibits "using" statements in a namespace scope
+// inside a header file. However, the FunctionMocker class template
+// is meant to be defined in the ::testing namespace. The following
+// line is just a trick for working around a bug in MSVC 8.0, which
+// cannot handle it if we define FunctionMocker in ::testing.
+using internal::FunctionMocker;
+
+// GMOCK_RESULT_(tn, F) expands to the result type of function type F.
+// We define this as a variadic macro in case F contains unprotected
+// commas (the same reason that we use variadic macros in other places
+// in this file).
+// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
+#define GMOCK_RESULT_(tn, ...) \
+ tn ::testing::internal::Function<__VA_ARGS__>::Result
+
+// The type of argument N of the given function type.
+// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
+#define GMOCK_ARG_(tn, N, ...) \
+ tn ::testing::internal::Function<__VA_ARGS__>::Argument##N
+
+// The matcher type for argument N of the given function type.
+// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
+#define GMOCK_MATCHER_(tn, N, ...) \
+ const ::testing::Matcher<GMOCK_ARG_(tn, N, __VA_ARGS__)>&
+
+// The variable for mocking the given method.
+// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
+#define GMOCK_MOCKER_(arity, constness, Method) \
+ GTEST_CONCAT_TOKEN_(gmock##constness##arity##_##Method##_, __LINE__)
+
+// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
+#define GMOCK_METHOD0_(tn, constness, ct, Method, ...) \
+ GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
+ ) constness { \
+ GTEST_COMPILE_ASSERT_((::testing::tuple_size< \
+ tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \
+ == 0), \
+ this_method_does_not_take_0_arguments); \
+ GMOCK_MOCKER_(0, constness, Method).SetOwnerAndName(this, #Method); \
+ return GMOCK_MOCKER_(0, constness, Method).Invoke(); \
+ } \
+ ::testing::MockSpec<__VA_ARGS__>& \
+ gmock_##Method() constness { \
+ GMOCK_MOCKER_(0, constness, Method).RegisterOwner(this); \
+ return GMOCK_MOCKER_(0, constness, Method).With(); \
+ } \
+ mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(0, constness, \
+ Method)
+
+// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
+#define GMOCK_METHOD1_(tn, constness, ct, Method, ...) \
+ GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
+ GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1) constness { \
+ GTEST_COMPILE_ASSERT_((::testing::tuple_size< \
+ tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \
+ == 1), \
+ this_method_does_not_take_1_argument); \
+ GMOCK_MOCKER_(1, constness, Method).SetOwnerAndName(this, #Method); \
+ return GMOCK_MOCKER_(1, constness, Method).Invoke(gmock_a1); \
+ } \
+ ::testing::MockSpec<__VA_ARGS__>& \
+ gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1) constness { \
+ GMOCK_MOCKER_(1, constness, Method).RegisterOwner(this); \
+ return GMOCK_MOCKER_(1, constness, Method).With(gmock_a1); \
+ } \
+ mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(1, constness, \
+ Method)
+
+// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
+#define GMOCK_METHOD2_(tn, constness, ct, Method, ...) \
+ GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
+ GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \
+ GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2) constness { \
+ GTEST_COMPILE_ASSERT_((::testing::tuple_size< \
+ tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \
+ == 2), \
+ this_method_does_not_take_2_arguments); \
+ GMOCK_MOCKER_(2, constness, Method).SetOwnerAndName(this, #Method); \
+ return GMOCK_MOCKER_(2, constness, Method).Invoke(gmock_a1, gmock_a2); \
+ } \
+ ::testing::MockSpec<__VA_ARGS__>& \
+ gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
+ GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2) constness { \
+ GMOCK_MOCKER_(2, constness, Method).RegisterOwner(this); \
+ return GMOCK_MOCKER_(2, constness, Method).With(gmock_a1, gmock_a2); \
+ } \
+ mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(2, constness, \
+ Method)
+
+// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
+#define GMOCK_METHOD3_(tn, constness, ct, Method, ...) \
+ GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
+ GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \
+ GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \
+ GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3) constness { \
+ GTEST_COMPILE_ASSERT_((::testing::tuple_size< \
+ tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \
+ == 3), \
+ this_method_does_not_take_3_arguments); \
+ GMOCK_MOCKER_(3, constness, Method).SetOwnerAndName(this, #Method); \
+ return GMOCK_MOCKER_(3, constness, Method).Invoke(gmock_a1, gmock_a2, \
+ gmock_a3); \
+ } \
+ ::testing::MockSpec<__VA_ARGS__>& \
+ gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
+ GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
+ GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3) constness { \
+ GMOCK_MOCKER_(3, constness, Method).RegisterOwner(this); \
+ return GMOCK_MOCKER_(3, constness, Method).With(gmock_a1, gmock_a2, \
+ gmock_a3); \
+ } \
+ mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(3, constness, \
+ Method)
+
+// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
+#define GMOCK_METHOD4_(tn, constness, ct, Method, ...) \
+ GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
+ GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \
+ GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \
+ GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
+ GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4) constness { \
+ GTEST_COMPILE_ASSERT_((::testing::tuple_size< \
+ tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \
+ == 4), \
+ this_method_does_not_take_4_arguments); \
+ GMOCK_MOCKER_(4, constness, Method).SetOwnerAndName(this, #Method); \
+ return GMOCK_MOCKER_(4, constness, Method).Invoke(gmock_a1, gmock_a2, \
+ gmock_a3, gmock_a4); \
+ } \
+ ::testing::MockSpec<__VA_ARGS__>& \
+ gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
+ GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
+ GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \
+ GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4) constness { \
+ GMOCK_MOCKER_(4, constness, Method).RegisterOwner(this); \
+ return GMOCK_MOCKER_(4, constness, Method).With(gmock_a1, gmock_a2, \
+ gmock_a3, gmock_a4); \
+ } \
+ mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(4, constness, \
+ Method)
+
+// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
+#define GMOCK_METHOD5_(tn, constness, ct, Method, ...) \
+ GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
+ GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \
+ GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \
+ GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
+ GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \
+ GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5) constness { \
+ GTEST_COMPILE_ASSERT_((::testing::tuple_size< \
+ tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \
+ == 5), \
+ this_method_does_not_take_5_arguments); \
+ GMOCK_MOCKER_(5, constness, Method).SetOwnerAndName(this, #Method); \
+ return GMOCK_MOCKER_(5, constness, Method).Invoke(gmock_a1, gmock_a2, \
+ gmock_a3, gmock_a4, gmock_a5); \
+ } \
+ ::testing::MockSpec<__VA_ARGS__>& \
+ gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
+ GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
+ GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \
+ GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \
+ GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5) constness { \
+ GMOCK_MOCKER_(5, constness, Method).RegisterOwner(this); \
+ return GMOCK_MOCKER_(5, constness, Method).With(gmock_a1, gmock_a2, \
+ gmock_a3, gmock_a4, gmock_a5); \
+ } \
+ mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(5, constness, \
+ Method)
+
+// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
+#define GMOCK_METHOD6_(tn, constness, ct, Method, ...) \
+ GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
+ GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \
+ GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \
+ GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
+ GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \
+ GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5, \
+ GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6) constness { \
+ GTEST_COMPILE_ASSERT_((::testing::tuple_size< \
+ tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \
+ == 6), \
+ this_method_does_not_take_6_arguments); \
+ GMOCK_MOCKER_(6, constness, Method).SetOwnerAndName(this, #Method); \
+ return GMOCK_MOCKER_(6, constness, Method).Invoke(gmock_a1, gmock_a2, \
+ gmock_a3, gmock_a4, gmock_a5, gmock_a6); \
+ } \
+ ::testing::MockSpec<__VA_ARGS__>& \
+ gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
+ GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
+ GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \
+ GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \
+ GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \
+ GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6) constness { \
+ GMOCK_MOCKER_(6, constness, Method).RegisterOwner(this); \
+ return GMOCK_MOCKER_(6, constness, Method).With(gmock_a1, gmock_a2, \
+ gmock_a3, gmock_a4, gmock_a5, gmock_a6); \
+ } \
+ mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(6, constness, \
+ Method)
+
+// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
+#define GMOCK_METHOD7_(tn, constness, ct, Method, ...) \
+ GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
+ GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \
+ GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \
+ GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
+ GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \
+ GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5, \
+ GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \
+ GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7) constness { \
+ GTEST_COMPILE_ASSERT_((::testing::tuple_size< \
+ tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \
+ == 7), \
+ this_method_does_not_take_7_arguments); \
+ GMOCK_MOCKER_(7, constness, Method).SetOwnerAndName(this, #Method); \
+ return GMOCK_MOCKER_(7, constness, Method).Invoke(gmock_a1, gmock_a2, \
+ gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7); \
+ } \
+ ::testing::MockSpec<__VA_ARGS__>& \
+ gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
+ GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
+ GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \
+ GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \
+ GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \
+ GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6, \
+ GMOCK_MATCHER_(tn, 7, __VA_ARGS__) gmock_a7) constness { \
+ GMOCK_MOCKER_(7, constness, Method).RegisterOwner(this); \
+ return GMOCK_MOCKER_(7, constness, Method).With(gmock_a1, gmock_a2, \
+ gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7); \
+ } \
+ mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(7, constness, \
+ Method)
+
+// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
+#define GMOCK_METHOD8_(tn, constness, ct, Method, ...) \
+ GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
+ GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \
+ GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \
+ GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
+ GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \
+ GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5, \
+ GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \
+ GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7, \
+ GMOCK_ARG_(tn, 8, __VA_ARGS__) gmock_a8) constness { \
+ GTEST_COMPILE_ASSERT_((::testing::tuple_size< \
+ tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \
+ == 8), \
+ this_method_does_not_take_8_arguments); \
+ GMOCK_MOCKER_(8, constness, Method).SetOwnerAndName(this, #Method); \
+ return GMOCK_MOCKER_(8, constness, Method).Invoke(gmock_a1, gmock_a2, \
+ gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8); \
+ } \
+ ::testing::MockSpec<__VA_ARGS__>& \
+ gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
+ GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
+ GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \
+ GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \
+ GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \
+ GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6, \
+ GMOCK_MATCHER_(tn, 7, __VA_ARGS__) gmock_a7, \
+ GMOCK_MATCHER_(tn, 8, __VA_ARGS__) gmock_a8) constness { \
+ GMOCK_MOCKER_(8, constness, Method).RegisterOwner(this); \
+ return GMOCK_MOCKER_(8, constness, Method).With(gmock_a1, gmock_a2, \
+ gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8); \
+ } \
+ mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(8, constness, \
+ Method)
+
+// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
+#define GMOCK_METHOD9_(tn, constness, ct, Method, ...) \
+ GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
+ GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \
+ GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \
+ GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
+ GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \
+ GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5, \
+ GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \
+ GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7, \
+ GMOCK_ARG_(tn, 8, __VA_ARGS__) gmock_a8, \
+ GMOCK_ARG_(tn, 9, __VA_ARGS__) gmock_a9) constness { \
+ GTEST_COMPILE_ASSERT_((::testing::tuple_size< \
+ tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \
+ == 9), \
+ this_method_does_not_take_9_arguments); \
+ GMOCK_MOCKER_(9, constness, Method).SetOwnerAndName(this, #Method); \
+ return GMOCK_MOCKER_(9, constness, Method).Invoke(gmock_a1, gmock_a2, \
+ gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, \
+ gmock_a9); \
+ } \
+ ::testing::MockSpec<__VA_ARGS__>& \
+ gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
+ GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
+ GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \
+ GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \
+ GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \
+ GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6, \
+ GMOCK_MATCHER_(tn, 7, __VA_ARGS__) gmock_a7, \
+ GMOCK_MATCHER_(tn, 8, __VA_ARGS__) gmock_a8, \
+ GMOCK_MATCHER_(tn, 9, __VA_ARGS__) gmock_a9) constness { \
+ GMOCK_MOCKER_(9, constness, Method).RegisterOwner(this); \
+ return GMOCK_MOCKER_(9, constness, Method).With(gmock_a1, gmock_a2, \
+ gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, \
+ gmock_a9); \
+ } \
+ mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(9, constness, \
+ Method)
+
+// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
+#define GMOCK_METHOD10_(tn, constness, ct, Method, ...) \
+ GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
+ GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \
+ GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \
+ GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
+ GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \
+ GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5, \
+ GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \
+ GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7, \
+ GMOCK_ARG_(tn, 8, __VA_ARGS__) gmock_a8, \
+ GMOCK_ARG_(tn, 9, __VA_ARGS__) gmock_a9, \
+ GMOCK_ARG_(tn, 10, __VA_ARGS__) gmock_a10) constness { \
+ GTEST_COMPILE_ASSERT_((::testing::tuple_size< \
+ tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \
+ == 10), \
+ this_method_does_not_take_10_arguments); \
+ GMOCK_MOCKER_(10, constness, Method).SetOwnerAndName(this, #Method); \
+ return GMOCK_MOCKER_(10, constness, Method).Invoke(gmock_a1, gmock_a2, \
+ gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, gmock_a9, \
+ gmock_a10); \
+ } \
+ ::testing::MockSpec<__VA_ARGS__>& \
+ gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
+ GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
+ GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \
+ GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \
+ GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \
+ GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6, \
+ GMOCK_MATCHER_(tn, 7, __VA_ARGS__) gmock_a7, \
+ GMOCK_MATCHER_(tn, 8, __VA_ARGS__) gmock_a8, \
+ GMOCK_MATCHER_(tn, 9, __VA_ARGS__) gmock_a9, \
+ GMOCK_MATCHER_(tn, 10, \
+ __VA_ARGS__) gmock_a10) constness { \
+ GMOCK_MOCKER_(10, constness, Method).RegisterOwner(this); \
+ return GMOCK_MOCKER_(10, constness, Method).With(gmock_a1, gmock_a2, \
+ gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, gmock_a9, \
+ gmock_a10); \
+ } \
+ mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(10, constness, \
+ Method)
+
+#define MOCK_METHOD0(m, ...) GMOCK_METHOD0_(, , , m, __VA_ARGS__)
+#define MOCK_METHOD1(m, ...) GMOCK_METHOD1_(, , , m, __VA_ARGS__)
+#define MOCK_METHOD2(m, ...) GMOCK_METHOD2_(, , , m, __VA_ARGS__)
+#define MOCK_METHOD3(m, ...) GMOCK_METHOD3_(, , , m, __VA_ARGS__)
+#define MOCK_METHOD4(m, ...) GMOCK_METHOD4_(, , , m, __VA_ARGS__)
+#define MOCK_METHOD5(m, ...) GMOCK_METHOD5_(, , , m, __VA_ARGS__)
+#define MOCK_METHOD6(m, ...) GMOCK_METHOD6_(, , , m, __VA_ARGS__)
+#define MOCK_METHOD7(m, ...) GMOCK_METHOD7_(, , , m, __VA_ARGS__)
+#define MOCK_METHOD8(m, ...) GMOCK_METHOD8_(, , , m, __VA_ARGS__)
+#define MOCK_METHOD9(m, ...) GMOCK_METHOD9_(, , , m, __VA_ARGS__)
+#define MOCK_METHOD10(m, ...) GMOCK_METHOD10_(, , , m, __VA_ARGS__)
+
+#define MOCK_CONST_METHOD0(m, ...) GMOCK_METHOD0_(, const, , m, __VA_ARGS__)
+#define MOCK_CONST_METHOD1(m, ...) GMOCK_METHOD1_(, const, , m, __VA_ARGS__)
+#define MOCK_CONST_METHOD2(m, ...) GMOCK_METHOD2_(, const, , m, __VA_ARGS__)
+#define MOCK_CONST_METHOD3(m, ...) GMOCK_METHOD3_(, const, , m, __VA_ARGS__)
+#define MOCK_CONST_METHOD4(m, ...) GMOCK_METHOD4_(, const, , m, __VA_ARGS__)
+#define MOCK_CONST_METHOD5(m, ...) GMOCK_METHOD5_(, const, , m, __VA_ARGS__)
+#define MOCK_CONST_METHOD6(m, ...) GMOCK_METHOD6_(, const, , m, __VA_ARGS__)
+#define MOCK_CONST_METHOD7(m, ...) GMOCK_METHOD7_(, const, , m, __VA_ARGS__)
+#define MOCK_CONST_METHOD8(m, ...) GMOCK_METHOD8_(, const, , m, __VA_ARGS__)
+#define MOCK_CONST_METHOD9(m, ...) GMOCK_METHOD9_(, const, , m, __VA_ARGS__)
+#define MOCK_CONST_METHOD10(m, ...) GMOCK_METHOD10_(, const, , m, __VA_ARGS__)
+
+#define MOCK_METHOD0_T(m, ...) GMOCK_METHOD0_(typename, , , m, __VA_ARGS__)
+#define MOCK_METHOD1_T(m, ...) GMOCK_METHOD1_(typename, , , m, __VA_ARGS__)
+#define MOCK_METHOD2_T(m, ...) GMOCK_METHOD2_(typename, , , m, __VA_ARGS__)
+#define MOCK_METHOD3_T(m, ...) GMOCK_METHOD3_(typename, , , m, __VA_ARGS__)
+#define MOCK_METHOD4_T(m, ...) GMOCK_METHOD4_(typename, , , m, __VA_ARGS__)
+#define MOCK_METHOD5_T(m, ...) GMOCK_METHOD5_(typename, , , m, __VA_ARGS__)
+#define MOCK_METHOD6_T(m, ...) GMOCK_METHOD6_(typename, , , m, __VA_ARGS__)
+#define MOCK_METHOD7_T(m, ...) GMOCK_METHOD7_(typename, , , m, __VA_ARGS__)
+#define MOCK_METHOD8_T(m, ...) GMOCK_METHOD8_(typename, , , m, __VA_ARGS__)
+#define MOCK_METHOD9_T(m, ...) GMOCK_METHOD9_(typename, , , m, __VA_ARGS__)
+#define MOCK_METHOD10_T(m, ...) GMOCK_METHOD10_(typename, , , m, __VA_ARGS__)
+
+#define MOCK_CONST_METHOD0_T(m, ...) \
+ GMOCK_METHOD0_(typename, const, , m, __VA_ARGS__)
+#define MOCK_CONST_METHOD1_T(m, ...) \
+ GMOCK_METHOD1_(typename, const, , m, __VA_ARGS__)
+#define MOCK_CONST_METHOD2_T(m, ...) \
+ GMOCK_METHOD2_(typename, const, , m, __VA_ARGS__)
+#define MOCK_CONST_METHOD3_T(m, ...) \
+ GMOCK_METHOD3_(typename, const, , m, __VA_ARGS__)
+#define MOCK_CONST_METHOD4_T(m, ...) \
+ GMOCK_METHOD4_(typename, const, , m, __VA_ARGS__)
+#define MOCK_CONST_METHOD5_T(m, ...) \
+ GMOCK_METHOD5_(typename, const, , m, __VA_ARGS__)
+#define MOCK_CONST_METHOD6_T(m, ...) \
+ GMOCK_METHOD6_(typename, const, , m, __VA_ARGS__)
+#define MOCK_CONST_METHOD7_T(m, ...) \
+ GMOCK_METHOD7_(typename, const, , m, __VA_ARGS__)
+#define MOCK_CONST_METHOD8_T(m, ...) \
+ GMOCK_METHOD8_(typename, const, , m, __VA_ARGS__)
+#define MOCK_CONST_METHOD9_T(m, ...) \
+ GMOCK_METHOD9_(typename, const, , m, __VA_ARGS__)
+#define MOCK_CONST_METHOD10_T(m, ...) \
+ GMOCK_METHOD10_(typename, const, , m, __VA_ARGS__)
+
+#define MOCK_METHOD0_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD0_(, , ct, m, __VA_ARGS__)
+#define MOCK_METHOD1_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD1_(, , ct, m, __VA_ARGS__)
+#define MOCK_METHOD2_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD2_(, , ct, m, __VA_ARGS__)
+#define MOCK_METHOD3_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD3_(, , ct, m, __VA_ARGS__)
+#define MOCK_METHOD4_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD4_(, , ct, m, __VA_ARGS__)
+#define MOCK_METHOD5_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD5_(, , ct, m, __VA_ARGS__)
+#define MOCK_METHOD6_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD6_(, , ct, m, __VA_ARGS__)
+#define MOCK_METHOD7_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD7_(, , ct, m, __VA_ARGS__)
+#define MOCK_METHOD8_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD8_(, , ct, m, __VA_ARGS__)
+#define MOCK_METHOD9_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD9_(, , ct, m, __VA_ARGS__)
+#define MOCK_METHOD10_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD10_(, , ct, m, __VA_ARGS__)
+
+#define MOCK_CONST_METHOD0_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD0_(, const, ct, m, __VA_ARGS__)
+#define MOCK_CONST_METHOD1_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD1_(, const, ct, m, __VA_ARGS__)
+#define MOCK_CONST_METHOD2_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD2_(, const, ct, m, __VA_ARGS__)
+#define MOCK_CONST_METHOD3_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD3_(, const, ct, m, __VA_ARGS__)
+#define MOCK_CONST_METHOD4_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD4_(, const, ct, m, __VA_ARGS__)
+#define MOCK_CONST_METHOD5_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD5_(, const, ct, m, __VA_ARGS__)
+#define MOCK_CONST_METHOD6_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD6_(, const, ct, m, __VA_ARGS__)
+#define MOCK_CONST_METHOD7_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD7_(, const, ct, m, __VA_ARGS__)
+#define MOCK_CONST_METHOD8_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD8_(, const, ct, m, __VA_ARGS__)
+#define MOCK_CONST_METHOD9_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD9_(, const, ct, m, __VA_ARGS__)
+#define MOCK_CONST_METHOD10_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD10_(, const, ct, m, __VA_ARGS__)
+
+#define MOCK_METHOD0_T_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD0_(typename, , ct, m, __VA_ARGS__)
+#define MOCK_METHOD1_T_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD1_(typename, , ct, m, __VA_ARGS__)
+#define MOCK_METHOD2_T_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD2_(typename, , ct, m, __VA_ARGS__)
+#define MOCK_METHOD3_T_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD3_(typename, , ct, m, __VA_ARGS__)
+#define MOCK_METHOD4_T_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD4_(typename, , ct, m, __VA_ARGS__)
+#define MOCK_METHOD5_T_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD5_(typename, , ct, m, __VA_ARGS__)
+#define MOCK_METHOD6_T_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD6_(typename, , ct, m, __VA_ARGS__)
+#define MOCK_METHOD7_T_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD7_(typename, , ct, m, __VA_ARGS__)
+#define MOCK_METHOD8_T_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD8_(typename, , ct, m, __VA_ARGS__)
+#define MOCK_METHOD9_T_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD9_(typename, , ct, m, __VA_ARGS__)
+#define MOCK_METHOD10_T_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD10_(typename, , ct, m, __VA_ARGS__)
+
+#define MOCK_CONST_METHOD0_T_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD0_(typename, const, ct, m, __VA_ARGS__)
+#define MOCK_CONST_METHOD1_T_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD1_(typename, const, ct, m, __VA_ARGS__)
+#define MOCK_CONST_METHOD2_T_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD2_(typename, const, ct, m, __VA_ARGS__)
+#define MOCK_CONST_METHOD3_T_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD3_(typename, const, ct, m, __VA_ARGS__)
+#define MOCK_CONST_METHOD4_T_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD4_(typename, const, ct, m, __VA_ARGS__)
+#define MOCK_CONST_METHOD5_T_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD5_(typename, const, ct, m, __VA_ARGS__)
+#define MOCK_CONST_METHOD6_T_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD6_(typename, const, ct, m, __VA_ARGS__)
+#define MOCK_CONST_METHOD7_T_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD7_(typename, const, ct, m, __VA_ARGS__)
+#define MOCK_CONST_METHOD8_T_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD8_(typename, const, ct, m, __VA_ARGS__)
+#define MOCK_CONST_METHOD9_T_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD9_(typename, const, ct, m, __VA_ARGS__)
+#define MOCK_CONST_METHOD10_T_WITH_CALLTYPE(ct, m, ...) \
+ GMOCK_METHOD10_(typename, const, ct, m, __VA_ARGS__)
+
+// A MockFunction<F> class has one mock method whose type is F. It is
+// useful when you just want your test code to emit some messages and
+// have Google Mock verify the right messages are sent (and perhaps at
+// the right times). For example, if you are exercising code:
+//
+// Foo(1);
+// Foo(2);
+// Foo(3);
+//
+// and want to verify that Foo(1) and Foo(3) both invoke
+// mock.Bar("a"), but Foo(2) doesn't invoke anything, you can write:
+//
+// TEST(FooTest, InvokesBarCorrectly) {
+// MyMock mock;
+// MockFunction<void(string check_point_name)> check;
+// {
+// InSequence s;
+//
+// EXPECT_CALL(mock, Bar("a"));
+// EXPECT_CALL(check, Call("1"));
+// EXPECT_CALL(check, Call("2"));
+// EXPECT_CALL(mock, Bar("a"));
+// }
+// Foo(1);
+// check.Call("1");
+// Foo(2);
+// check.Call("2");
+// Foo(3);
+// }
+//
+// The expectation spec says that the first Bar("a") must happen
+// before check point "1", the second Bar("a") must happen after check
+// point "2", and nothing should happen between the two check
+// points. The explicit check points make it easy to tell which
+// Bar("a") is called by which call to Foo().
+//
+// MockFunction<F> can also be used to exercise code that accepts
+// std::function<F> callbacks. To do so, use AsStdFunction() method
+// to create std::function proxy forwarding to original object's Call.
+// Example:
+//
+// TEST(FooTest, RunsCallbackWithBarArgument) {
+// MockFunction<int(string)> callback;
+// EXPECT_CALL(callback, Call("bar")).WillOnce(Return(1));
+// Foo(callback.AsStdFunction());
+// }
+template <typename F>
+class MockFunction;
+
+template <typename R>
+class MockFunction<R()> {
+ public:
+ MockFunction() {}
+
+ MOCK_METHOD0_T(Call, R());
+
+#if GTEST_HAS_STD_FUNCTION_
+ std::function<R()> AsStdFunction() {
+ return [this]() -> R {
+ return this->Call();
+ };
+ }
+#endif // GTEST_HAS_STD_FUNCTION_
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction);
+};
+
+template <typename R, typename A0>
+class MockFunction<R(A0)> {
+ public:
+ MockFunction() {}
+
+ MOCK_METHOD1_T(Call, R(A0));
+
+#if GTEST_HAS_STD_FUNCTION_
+ std::function<R(A0)> AsStdFunction() {
+ return [this](A0 a0) -> R {
+ return this->Call(a0);
+ };
+ }
+#endif // GTEST_HAS_STD_FUNCTION_
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction);
+};
+
+template <typename R, typename A0, typename A1>
+class MockFunction<R(A0, A1)> {
+ public:
+ MockFunction() {}
+
+ MOCK_METHOD2_T(Call, R(A0, A1));
+
+#if GTEST_HAS_STD_FUNCTION_
+ std::function<R(A0, A1)> AsStdFunction() {
+ return [this](A0 a0, A1 a1) -> R {
+ return this->Call(a0, a1);
+ };
+ }
+#endif // GTEST_HAS_STD_FUNCTION_
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction);
+};
+
+template <typename R, typename A0, typename A1, typename A2>
+class MockFunction<R(A0, A1, A2)> {
+ public:
+ MockFunction() {}
+
+ MOCK_METHOD3_T(Call, R(A0, A1, A2));
+
+#if GTEST_HAS_STD_FUNCTION_
+ std::function<R(A0, A1, A2)> AsStdFunction() {
+ return [this](A0 a0, A1 a1, A2 a2) -> R {
+ return this->Call(a0, a1, a2);
+ };
+ }
+#endif // GTEST_HAS_STD_FUNCTION_
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction);
+};
+
+template <typename R, typename A0, typename A1, typename A2, typename A3>
+class MockFunction<R(A0, A1, A2, A3)> {
+ public:
+ MockFunction() {}
+
+ MOCK_METHOD4_T(Call, R(A0, A1, A2, A3));
+
+#if GTEST_HAS_STD_FUNCTION_
+ std::function<R(A0, A1, A2, A3)> AsStdFunction() {
+ return [this](A0 a0, A1 a1, A2 a2, A3 a3) -> R {
+ return this->Call(a0, a1, a2, a3);
+ };
+ }
+#endif // GTEST_HAS_STD_FUNCTION_
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction);
+};
+
+template <typename R, typename A0, typename A1, typename A2, typename A3,
+ typename A4>
+class MockFunction<R(A0, A1, A2, A3, A4)> {
+ public:
+ MockFunction() {}
+
+ MOCK_METHOD5_T(Call, R(A0, A1, A2, A3, A4));
+
+#if GTEST_HAS_STD_FUNCTION_
+ std::function<R(A0, A1, A2, A3, A4)> AsStdFunction() {
+ return [this](A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) -> R {
+ return this->Call(a0, a1, a2, a3, a4);
+ };
+ }
+#endif // GTEST_HAS_STD_FUNCTION_
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction);
+};
+
+template <typename R, typename A0, typename A1, typename A2, typename A3,
+ typename A4, typename A5>
+class MockFunction<R(A0, A1, A2, A3, A4, A5)> {
+ public:
+ MockFunction() {}
+
+ MOCK_METHOD6_T(Call, R(A0, A1, A2, A3, A4, A5));
+
+#if GTEST_HAS_STD_FUNCTION_
+ std::function<R(A0, A1, A2, A3, A4, A5)> AsStdFunction() {
+ return [this](A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) -> R {
+ return this->Call(a0, a1, a2, a3, a4, a5);
+ };
+ }
+#endif // GTEST_HAS_STD_FUNCTION_
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction);
+};
+
+template <typename R, typename A0, typename A1, typename A2, typename A3,
+ typename A4, typename A5, typename A6>
+class MockFunction<R(A0, A1, A2, A3, A4, A5, A6)> {
+ public:
+ MockFunction() {}
+
+ MOCK_METHOD7_T(Call, R(A0, A1, A2, A3, A4, A5, A6));
+
+#if GTEST_HAS_STD_FUNCTION_
+ std::function<R(A0, A1, A2, A3, A4, A5, A6)> AsStdFunction() {
+ return [this](A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) -> R {
+ return this->Call(a0, a1, a2, a3, a4, a5, a6);
+ };
+ }
+#endif // GTEST_HAS_STD_FUNCTION_
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction);
+};
+
+template <typename R, typename A0, typename A1, typename A2, typename A3,
+ typename A4, typename A5, typename A6, typename A7>
+class MockFunction<R(A0, A1, A2, A3, A4, A5, A6, A7)> {
+ public:
+ MockFunction() {}
+
+ MOCK_METHOD8_T(Call, R(A0, A1, A2, A3, A4, A5, A6, A7));
+
+#if GTEST_HAS_STD_FUNCTION_
+ std::function<R(A0, A1, A2, A3, A4, A5, A6, A7)> AsStdFunction() {
+ return [this](A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) -> R {
+ return this->Call(a0, a1, a2, a3, a4, a5, a6, a7);
+ };
+ }
+#endif // GTEST_HAS_STD_FUNCTION_
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction);
+};
+
+template <typename R, typename A0, typename A1, typename A2, typename A3,
+ typename A4, typename A5, typename A6, typename A7, typename A8>
+class MockFunction<R(A0, A1, A2, A3, A4, A5, A6, A7, A8)> {
+ public:
+ MockFunction() {}
+
+ MOCK_METHOD9_T(Call, R(A0, A1, A2, A3, A4, A5, A6, A7, A8));
+
+#if GTEST_HAS_STD_FUNCTION_
+ std::function<R(A0, A1, A2, A3, A4, A5, A6, A7, A8)> AsStdFunction() {
+ return [this](A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7,
+ A8 a8) -> R {
+ return this->Call(a0, a1, a2, a3, a4, a5, a6, a7, a8);
+ };
+ }
+#endif // GTEST_HAS_STD_FUNCTION_
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction);
+};
+
+template <typename R, typename A0, typename A1, typename A2, typename A3,
+ typename A4, typename A5, typename A6, typename A7, typename A8,
+ typename A9>
+class MockFunction<R(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9)> {
+ public:
+ MockFunction() {}
+
+ MOCK_METHOD10_T(Call, R(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9));
+
+#if GTEST_HAS_STD_FUNCTION_
+ std::function<R(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9)> AsStdFunction() {
+ return [this](A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7,
+ A8 a8, A9 a9) -> R {
+ return this->Call(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+ };
+ }
+#endif // GTEST_HAS_STD_FUNCTION_
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction);
+};
+
+} // namespace testing
+
+#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_
diff --git a/extern/gmock/include/gmock/gmock-generated-matchers.h b/extern/gmock/include/gmock/gmock-generated-matchers.h
new file mode 100644
index 00000000000..57056fd91d2
--- /dev/null
+++ b/extern/gmock/include/gmock/gmock-generated-matchers.h
@@ -0,0 +1,2179 @@
+// This file was GENERATED by command:
+// pump.py gmock-generated-matchers.h.pump
+// DO NOT EDIT BY HAND!!!
+
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Google Mock - a framework for writing C++ mock classes.
+//
+// This file implements some commonly used variadic matchers.
+
+#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_
+#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_
+
+#include <iterator>
+#include <sstream>
+#include <string>
+#include <vector>
+#include "gmock/gmock-matchers.h"
+
+namespace testing {
+namespace internal {
+
+// The type of the i-th (0-based) field of Tuple.
+#define GMOCK_FIELD_TYPE_(Tuple, i) \
+ typename ::testing::tuple_element<i, Tuple>::type
+
+// TupleFields<Tuple, k0, ..., kn> is for selecting fields from a
+// tuple of type Tuple. It has two members:
+//
+// type: a tuple type whose i-th field is the ki-th field of Tuple.
+// GetSelectedFields(t): returns fields k0, ..., and kn of t as a tuple.
+//
+// For example, in class TupleFields<tuple<bool, char, int>, 2, 0>, we have:
+//
+// type is tuple<int, bool>, and
+// GetSelectedFields(make_tuple(true, 'a', 42)) is (42, true).
+
+template <class Tuple, int k0 = -1, int k1 = -1, int k2 = -1, int k3 = -1,
+ int k4 = -1, int k5 = -1, int k6 = -1, int k7 = -1, int k8 = -1,
+ int k9 = -1>
+class TupleFields;
+
+// This generic version is used when there are 10 selectors.
+template <class Tuple, int k0, int k1, int k2, int k3, int k4, int k5, int k6,
+ int k7, int k8, int k9>
+class TupleFields {
+ public:
+ typedef ::testing::tuple<GMOCK_FIELD_TYPE_(Tuple, k0),
+ GMOCK_FIELD_TYPE_(Tuple, k1), GMOCK_FIELD_TYPE_(Tuple, k2),
+ GMOCK_FIELD_TYPE_(Tuple, k3), GMOCK_FIELD_TYPE_(Tuple, k4),
+ GMOCK_FIELD_TYPE_(Tuple, k5), GMOCK_FIELD_TYPE_(Tuple, k6),
+ GMOCK_FIELD_TYPE_(Tuple, k7), GMOCK_FIELD_TYPE_(Tuple, k8),
+ GMOCK_FIELD_TYPE_(Tuple, k9)> type;
+ static type GetSelectedFields(const Tuple& t) {
+ return type(get<k0>(t), get<k1>(t), get<k2>(t), get<k3>(t), get<k4>(t),
+ get<k5>(t), get<k6>(t), get<k7>(t), get<k8>(t), get<k9>(t));
+ }
+};
+
+// The following specialization is used for 0 ~ 9 selectors.
+
+template <class Tuple>
+class TupleFields<Tuple, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1> {
+ public:
+ typedef ::testing::tuple<> type;
+ static type GetSelectedFields(const Tuple& /* t */) {
+ return type();
+ }
+};
+
+template <class Tuple, int k0>
+class TupleFields<Tuple, k0, -1, -1, -1, -1, -1, -1, -1, -1, -1> {
+ public:
+ typedef ::testing::tuple<GMOCK_FIELD_TYPE_(Tuple, k0)> type;
+ static type GetSelectedFields(const Tuple& t) {
+ return type(get<k0>(t));
+ }
+};
+
+template <class Tuple, int k0, int k1>
+class TupleFields<Tuple, k0, k1, -1, -1, -1, -1, -1, -1, -1, -1> {
+ public:
+ typedef ::testing::tuple<GMOCK_FIELD_TYPE_(Tuple, k0),
+ GMOCK_FIELD_TYPE_(Tuple, k1)> type;
+ static type GetSelectedFields(const Tuple& t) {
+ return type(get<k0>(t), get<k1>(t));
+ }
+};
+
+template <class Tuple, int k0, int k1, int k2>
+class TupleFields<Tuple, k0, k1, k2, -1, -1, -1, -1, -1, -1, -1> {
+ public:
+ typedef ::testing::tuple<GMOCK_FIELD_TYPE_(Tuple, k0),
+ GMOCK_FIELD_TYPE_(Tuple, k1), GMOCK_FIELD_TYPE_(Tuple, k2)> type;
+ static type GetSelectedFields(const Tuple& t) {
+ return type(get<k0>(t), get<k1>(t), get<k2>(t));
+ }
+};
+
+template <class Tuple, int k0, int k1, int k2, int k3>
+class TupleFields<Tuple, k0, k1, k2, k3, -1, -1, -1, -1, -1, -1> {
+ public:
+ typedef ::testing::tuple<GMOCK_FIELD_TYPE_(Tuple, k0),
+ GMOCK_FIELD_TYPE_(Tuple, k1), GMOCK_FIELD_TYPE_(Tuple, k2),
+ GMOCK_FIELD_TYPE_(Tuple, k3)> type;
+ static type GetSelectedFields(const Tuple& t) {
+ return type(get<k0>(t), get<k1>(t), get<k2>(t), get<k3>(t));
+ }
+};
+
+template <class Tuple, int k0, int k1, int k2, int k3, int k4>
+class TupleFields<Tuple, k0, k1, k2, k3, k4, -1, -1, -1, -1, -1> {
+ public:
+ typedef ::testing::tuple<GMOCK_FIELD_TYPE_(Tuple, k0),
+ GMOCK_FIELD_TYPE_(Tuple, k1), GMOCK_FIELD_TYPE_(Tuple, k2),
+ GMOCK_FIELD_TYPE_(Tuple, k3), GMOCK_FIELD_TYPE_(Tuple, k4)> type;
+ static type GetSelectedFields(const Tuple& t) {
+ return type(get<k0>(t), get<k1>(t), get<k2>(t), get<k3>(t), get<k4>(t));
+ }
+};
+
+template <class Tuple, int k0, int k1, int k2, int k3, int k4, int k5>
+class TupleFields<Tuple, k0, k1, k2, k3, k4, k5, -1, -1, -1, -1> {
+ public:
+ typedef ::testing::tuple<GMOCK_FIELD_TYPE_(Tuple, k0),
+ GMOCK_FIELD_TYPE_(Tuple, k1), GMOCK_FIELD_TYPE_(Tuple, k2),
+ GMOCK_FIELD_TYPE_(Tuple, k3), GMOCK_FIELD_TYPE_(Tuple, k4),
+ GMOCK_FIELD_TYPE_(Tuple, k5)> type;
+ static type GetSelectedFields(const Tuple& t) {
+ return type(get<k0>(t), get<k1>(t), get<k2>(t), get<k3>(t), get<k4>(t),
+ get<k5>(t));
+ }
+};
+
+template <class Tuple, int k0, int k1, int k2, int k3, int k4, int k5, int k6>
+class TupleFields<Tuple, k0, k1, k2, k3, k4, k5, k6, -1, -1, -1> {
+ public:
+ typedef ::testing::tuple<GMOCK_FIELD_TYPE_(Tuple, k0),
+ GMOCK_FIELD_TYPE_(Tuple, k1), GMOCK_FIELD_TYPE_(Tuple, k2),
+ GMOCK_FIELD_TYPE_(Tuple, k3), GMOCK_FIELD_TYPE_(Tuple, k4),
+ GMOCK_FIELD_TYPE_(Tuple, k5), GMOCK_FIELD_TYPE_(Tuple, k6)> type;
+ static type GetSelectedFields(const Tuple& t) {
+ return type(get<k0>(t), get<k1>(t), get<k2>(t), get<k3>(t), get<k4>(t),
+ get<k5>(t), get<k6>(t));
+ }
+};
+
+template <class Tuple, int k0, int k1, int k2, int k3, int k4, int k5, int k6,
+ int k7>
+class TupleFields<Tuple, k0, k1, k2, k3, k4, k5, k6, k7, -1, -1> {
+ public:
+ typedef ::testing::tuple<GMOCK_FIELD_TYPE_(Tuple, k0),
+ GMOCK_FIELD_TYPE_(Tuple, k1), GMOCK_FIELD_TYPE_(Tuple, k2),
+ GMOCK_FIELD_TYPE_(Tuple, k3), GMOCK_FIELD_TYPE_(Tuple, k4),
+ GMOCK_FIELD_TYPE_(Tuple, k5), GMOCK_FIELD_TYPE_(Tuple, k6),
+ GMOCK_FIELD_TYPE_(Tuple, k7)> type;
+ static type GetSelectedFields(const Tuple& t) {
+ return type(get<k0>(t), get<k1>(t), get<k2>(t), get<k3>(t), get<k4>(t),
+ get<k5>(t), get<k6>(t), get<k7>(t));
+ }
+};
+
+template <class Tuple, int k0, int k1, int k2, int k3, int k4, int k5, int k6,
+ int k7, int k8>
+class TupleFields<Tuple, k0, k1, k2, k3, k4, k5, k6, k7, k8, -1> {
+ public:
+ typedef ::testing::tuple<GMOCK_FIELD_TYPE_(Tuple, k0),
+ GMOCK_FIELD_TYPE_(Tuple, k1), GMOCK_FIELD_TYPE_(Tuple, k2),
+ GMOCK_FIELD_TYPE_(Tuple, k3), GMOCK_FIELD_TYPE_(Tuple, k4),
+ GMOCK_FIELD_TYPE_(Tuple, k5), GMOCK_FIELD_TYPE_(Tuple, k6),
+ GMOCK_FIELD_TYPE_(Tuple, k7), GMOCK_FIELD_TYPE_(Tuple, k8)> type;
+ static type GetSelectedFields(const Tuple& t) {
+ return type(get<k0>(t), get<k1>(t), get<k2>(t), get<k3>(t), get<k4>(t),
+ get<k5>(t), get<k6>(t), get<k7>(t), get<k8>(t));
+ }
+};
+
+#undef GMOCK_FIELD_TYPE_
+
+// Implements the Args() matcher.
+template <class ArgsTuple, int k0 = -1, int k1 = -1, int k2 = -1, int k3 = -1,
+ int k4 = -1, int k5 = -1, int k6 = -1, int k7 = -1, int k8 = -1,
+ int k9 = -1>
+class ArgsMatcherImpl : public MatcherInterface<ArgsTuple> {
+ public:
+ // ArgsTuple may have top-level const or reference modifiers.
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(ArgsTuple) RawArgsTuple;
+ typedef typename internal::TupleFields<RawArgsTuple, k0, k1, k2, k3, k4, k5,
+ k6, k7, k8, k9>::type SelectedArgs;
+ typedef Matcher<const SelectedArgs&> MonomorphicInnerMatcher;
+
+ template <typename InnerMatcher>
+ explicit ArgsMatcherImpl(const InnerMatcher& inner_matcher)
+ : inner_matcher_(SafeMatcherCast<const SelectedArgs&>(inner_matcher)) {}
+
+ virtual bool MatchAndExplain(ArgsTuple args,
+ MatchResultListener* listener) const {
+ const SelectedArgs& selected_args = GetSelectedArgs(args);
+ if (!listener->IsInterested())
+ return inner_matcher_.Matches(selected_args);
+
+ PrintIndices(listener->stream());
+ *listener << "are " << PrintToString(selected_args);
+
+ StringMatchResultListener inner_listener;
+ const bool match = inner_matcher_.MatchAndExplain(selected_args,
+ &inner_listener);
+ PrintIfNotEmpty(inner_listener.str(), listener->stream());
+ return match;
+ }
+
+ virtual void DescribeTo(::std::ostream* os) const {
+ *os << "are a tuple ";
+ PrintIndices(os);
+ inner_matcher_.DescribeTo(os);
+ }
+
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ *os << "are a tuple ";
+ PrintIndices(os);
+ inner_matcher_.DescribeNegationTo(os);
+ }
+
+ private:
+ static SelectedArgs GetSelectedArgs(ArgsTuple args) {
+ return TupleFields<RawArgsTuple, k0, k1, k2, k3, k4, k5, k6, k7, k8,
+ k9>::GetSelectedFields(args);
+ }
+
+ // Prints the indices of the selected fields.
+ static void PrintIndices(::std::ostream* os) {
+ *os << "whose fields (";
+ const int indices[10] = { k0, k1, k2, k3, k4, k5, k6, k7, k8, k9 };
+ for (int i = 0; i < 10; i++) {
+ if (indices[i] < 0)
+ break;
+
+ if (i >= 1)
+ *os << ", ";
+
+ *os << "#" << indices[i];
+ }
+ *os << ") ";
+ }
+
+ const MonomorphicInnerMatcher inner_matcher_;
+
+ GTEST_DISALLOW_ASSIGN_(ArgsMatcherImpl);
+};
+
+template <class InnerMatcher, int k0 = -1, int k1 = -1, int k2 = -1,
+ int k3 = -1, int k4 = -1, int k5 = -1, int k6 = -1, int k7 = -1,
+ int k8 = -1, int k9 = -1>
+class ArgsMatcher {
+ public:
+ explicit ArgsMatcher(const InnerMatcher& inner_matcher)
+ : inner_matcher_(inner_matcher) {}
+
+ template <typename ArgsTuple>
+ operator Matcher<ArgsTuple>() const {
+ return MakeMatcher(new ArgsMatcherImpl<ArgsTuple, k0, k1, k2, k3, k4, k5,
+ k6, k7, k8, k9>(inner_matcher_));
+ }
+
+ private:
+ const InnerMatcher inner_matcher_;
+
+ GTEST_DISALLOW_ASSIGN_(ArgsMatcher);
+};
+
+// A set of metafunctions for computing the result type of AllOf.
+// AllOf(m1, ..., mN) returns
+// AllOfResultN<decltype(m1), ..., decltype(mN)>::type.
+
+// Although AllOf isn't defined for one argument, AllOfResult1 is defined
+// to simplify the implementation.
+template <typename M1>
+struct AllOfResult1 {
+ typedef M1 type;
+};
+
+template <typename M1, typename M2>
+struct AllOfResult2 {
+ typedef BothOfMatcher<
+ typename AllOfResult1<M1>::type,
+ typename AllOfResult1<M2>::type
+ > type;
+};
+
+template <typename M1, typename M2, typename M3>
+struct AllOfResult3 {
+ typedef BothOfMatcher<
+ typename AllOfResult1<M1>::type,
+ typename AllOfResult2<M2, M3>::type
+ > type;
+};
+
+template <typename M1, typename M2, typename M3, typename M4>
+struct AllOfResult4 {
+ typedef BothOfMatcher<
+ typename AllOfResult2<M1, M2>::type,
+ typename AllOfResult2<M3, M4>::type
+ > type;
+};
+
+template <typename M1, typename M2, typename M3, typename M4, typename M5>
+struct AllOfResult5 {
+ typedef BothOfMatcher<
+ typename AllOfResult2<M1, M2>::type,
+ typename AllOfResult3<M3, M4, M5>::type
+ > type;
+};
+
+template <typename M1, typename M2, typename M3, typename M4, typename M5,
+ typename M6>
+struct AllOfResult6 {
+ typedef BothOfMatcher<
+ typename AllOfResult3<M1, M2, M3>::type,
+ typename AllOfResult3<M4, M5, M6>::type
+ > type;
+};
+
+template <typename M1, typename M2, typename M3, typename M4, typename M5,
+ typename M6, typename M7>
+struct AllOfResult7 {
+ typedef BothOfMatcher<
+ typename AllOfResult3<M1, M2, M3>::type,
+ typename AllOfResult4<M4, M5, M6, M7>::type
+ > type;
+};
+
+template <typename M1, typename M2, typename M3, typename M4, typename M5,
+ typename M6, typename M7, typename M8>
+struct AllOfResult8 {
+ typedef BothOfMatcher<
+ typename AllOfResult4<M1, M2, M3, M4>::type,
+ typename AllOfResult4<M5, M6, M7, M8>::type
+ > type;
+};
+
+template <typename M1, typename M2, typename M3, typename M4, typename M5,
+ typename M6, typename M7, typename M8, typename M9>
+struct AllOfResult9 {
+ typedef BothOfMatcher<
+ typename AllOfResult4<M1, M2, M3, M4>::type,
+ typename AllOfResult5<M5, M6, M7, M8, M9>::type
+ > type;
+};
+
+template <typename M1, typename M2, typename M3, typename M4, typename M5,
+ typename M6, typename M7, typename M8, typename M9, typename M10>
+struct AllOfResult10 {
+ typedef BothOfMatcher<
+ typename AllOfResult5<M1, M2, M3, M4, M5>::type,
+ typename AllOfResult5<M6, M7, M8, M9, M10>::type
+ > type;
+};
+
+// A set of metafunctions for computing the result type of AnyOf.
+// AnyOf(m1, ..., mN) returns
+// AnyOfResultN<decltype(m1), ..., decltype(mN)>::type.
+
+// Although AnyOf isn't defined for one argument, AnyOfResult1 is defined
+// to simplify the implementation.
+template <typename M1>
+struct AnyOfResult1 {
+ typedef M1 type;
+};
+
+template <typename M1, typename M2>
+struct AnyOfResult2 {
+ typedef EitherOfMatcher<
+ typename AnyOfResult1<M1>::type,
+ typename AnyOfResult1<M2>::type
+ > type;
+};
+
+template <typename M1, typename M2, typename M3>
+struct AnyOfResult3 {
+ typedef EitherOfMatcher<
+ typename AnyOfResult1<M1>::type,
+ typename AnyOfResult2<M2, M3>::type
+ > type;
+};
+
+template <typename M1, typename M2, typename M3, typename M4>
+struct AnyOfResult4 {
+ typedef EitherOfMatcher<
+ typename AnyOfResult2<M1, M2>::type,
+ typename AnyOfResult2<M3, M4>::type
+ > type;
+};
+
+template <typename M1, typename M2, typename M3, typename M4, typename M5>
+struct AnyOfResult5 {
+ typedef EitherOfMatcher<
+ typename AnyOfResult2<M1, M2>::type,
+ typename AnyOfResult3<M3, M4, M5>::type
+ > type;
+};
+
+template <typename M1, typename M2, typename M3, typename M4, typename M5,
+ typename M6>
+struct AnyOfResult6 {
+ typedef EitherOfMatcher<
+ typename AnyOfResult3<M1, M2, M3>::type,
+ typename AnyOfResult3<M4, M5, M6>::type
+ > type;
+};
+
+template <typename M1, typename M2, typename M3, typename M4, typename M5,
+ typename M6, typename M7>
+struct AnyOfResult7 {
+ typedef EitherOfMatcher<
+ typename AnyOfResult3<M1, M2, M3>::type,
+ typename AnyOfResult4<M4, M5, M6, M7>::type
+ > type;
+};
+
+template <typename M1, typename M2, typename M3, typename M4, typename M5,
+ typename M6, typename M7, typename M8>
+struct AnyOfResult8 {
+ typedef EitherOfMatcher<
+ typename AnyOfResult4<M1, M2, M3, M4>::type,
+ typename AnyOfResult4<M5, M6, M7, M8>::type
+ > type;
+};
+
+template <typename M1, typename M2, typename M3, typename M4, typename M5,
+ typename M6, typename M7, typename M8, typename M9>
+struct AnyOfResult9 {
+ typedef EitherOfMatcher<
+ typename AnyOfResult4<M1, M2, M3, M4>::type,
+ typename AnyOfResult5<M5, M6, M7, M8, M9>::type
+ > type;
+};
+
+template <typename M1, typename M2, typename M3, typename M4, typename M5,
+ typename M6, typename M7, typename M8, typename M9, typename M10>
+struct AnyOfResult10 {
+ typedef EitherOfMatcher<
+ typename AnyOfResult5<M1, M2, M3, M4, M5>::type,
+ typename AnyOfResult5<M6, M7, M8, M9, M10>::type
+ > type;
+};
+
+} // namespace internal
+
+// Args<N1, N2, ..., Nk>(a_matcher) matches a tuple if the selected
+// fields of it matches a_matcher. C++ doesn't support default
+// arguments for function templates, so we have to overload it.
+template <typename InnerMatcher>
+inline internal::ArgsMatcher<InnerMatcher>
+Args(const InnerMatcher& matcher) {
+ return internal::ArgsMatcher<InnerMatcher>(matcher);
+}
+
+template <int k1, typename InnerMatcher>
+inline internal::ArgsMatcher<InnerMatcher, k1>
+Args(const InnerMatcher& matcher) {
+ return internal::ArgsMatcher<InnerMatcher, k1>(matcher);
+}
+
+template <int k1, int k2, typename InnerMatcher>
+inline internal::ArgsMatcher<InnerMatcher, k1, k2>
+Args(const InnerMatcher& matcher) {
+ return internal::ArgsMatcher<InnerMatcher, k1, k2>(matcher);
+}
+
+template <int k1, int k2, int k3, typename InnerMatcher>
+inline internal::ArgsMatcher<InnerMatcher, k1, k2, k3>
+Args(const InnerMatcher& matcher) {
+ return internal::ArgsMatcher<InnerMatcher, k1, k2, k3>(matcher);
+}
+
+template <int k1, int k2, int k3, int k4, typename InnerMatcher>
+inline internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4>
+Args(const InnerMatcher& matcher) {
+ return internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4>(matcher);
+}
+
+template <int k1, int k2, int k3, int k4, int k5, typename InnerMatcher>
+inline internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5>
+Args(const InnerMatcher& matcher) {
+ return internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5>(matcher);
+}
+
+template <int k1, int k2, int k3, int k4, int k5, int k6, typename InnerMatcher>
+inline internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5, k6>
+Args(const InnerMatcher& matcher) {
+ return internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5, k6>(matcher);
+}
+
+template <int k1, int k2, int k3, int k4, int k5, int k6, int k7,
+ typename InnerMatcher>
+inline internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5, k6, k7>
+Args(const InnerMatcher& matcher) {
+ return internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5, k6,
+ k7>(matcher);
+}
+
+template <int k1, int k2, int k3, int k4, int k5, int k6, int k7, int k8,
+ typename InnerMatcher>
+inline internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5, k6, k7, k8>
+Args(const InnerMatcher& matcher) {
+ return internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5, k6, k7,
+ k8>(matcher);
+}
+
+template <int k1, int k2, int k3, int k4, int k5, int k6, int k7, int k8,
+ int k9, typename InnerMatcher>
+inline internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5, k6, k7, k8, k9>
+Args(const InnerMatcher& matcher) {
+ return internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5, k6, k7, k8,
+ k9>(matcher);
+}
+
+template <int k1, int k2, int k3, int k4, int k5, int k6, int k7, int k8,
+ int k9, int k10, typename InnerMatcher>
+inline internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5, k6, k7, k8, k9,
+ k10>
+Args(const InnerMatcher& matcher) {
+ return internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5, k6, k7, k8,
+ k9, k10>(matcher);
+}
+
+// ElementsAre(e_1, e_2, ... e_n) matches an STL-style container with
+// n elements, where the i-th element in the container must
+// match the i-th argument in the list. Each argument of
+// ElementsAre() can be either a value or a matcher. We support up to
+// 10 arguments.
+//
+// The use of DecayArray in the implementation allows ElementsAre()
+// to accept string literals, whose type is const char[N], but we
+// want to treat them as const char*.
+//
+// NOTE: Since ElementsAre() cares about the order of the elements, it
+// must not be used with containers whose elements's order is
+// undefined (e.g. hash_map).
+
+inline internal::ElementsAreMatcher<
+ ::testing::tuple<> >
+ElementsAre() {
+ typedef ::testing::tuple<> Args;
+ return internal::ElementsAreMatcher<Args>(Args());
+}
+
+template <typename T1>
+inline internal::ElementsAreMatcher<
+ ::testing::tuple<
+ typename internal::DecayArray<T1>::type> >
+ElementsAre(const T1& e1) {
+ typedef ::testing::tuple<
+ typename internal::DecayArray<T1>::type> Args;
+ return internal::ElementsAreMatcher<Args>(Args(e1));
+}
+
+template <typename T1, typename T2>
+inline internal::ElementsAreMatcher<
+ ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type> >
+ElementsAre(const T1& e1, const T2& e2) {
+ typedef ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type> Args;
+ return internal::ElementsAreMatcher<Args>(Args(e1, e2));
+}
+
+template <typename T1, typename T2, typename T3>
+inline internal::ElementsAreMatcher<
+ ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type> >
+ElementsAre(const T1& e1, const T2& e2, const T3& e3) {
+ typedef ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type> Args;
+ return internal::ElementsAreMatcher<Args>(Args(e1, e2, e3));
+}
+
+template <typename T1, typename T2, typename T3, typename T4>
+inline internal::ElementsAreMatcher<
+ ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type,
+ typename internal::DecayArray<T4>::type> >
+ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4) {
+ typedef ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type,
+ typename internal::DecayArray<T4>::type> Args;
+ return internal::ElementsAreMatcher<Args>(Args(e1, e2, e3, e4));
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+inline internal::ElementsAreMatcher<
+ ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type,
+ typename internal::DecayArray<T4>::type,
+ typename internal::DecayArray<T5>::type> >
+ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4,
+ const T5& e5) {
+ typedef ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type,
+ typename internal::DecayArray<T4>::type,
+ typename internal::DecayArray<T5>::type> Args;
+ return internal::ElementsAreMatcher<Args>(Args(e1, e2, e3, e4, e5));
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6>
+inline internal::ElementsAreMatcher<
+ ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type,
+ typename internal::DecayArray<T4>::type,
+ typename internal::DecayArray<T5>::type,
+ typename internal::DecayArray<T6>::type> >
+ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4,
+ const T5& e5, const T6& e6) {
+ typedef ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type,
+ typename internal::DecayArray<T4>::type,
+ typename internal::DecayArray<T5>::type,
+ typename internal::DecayArray<T6>::type> Args;
+ return internal::ElementsAreMatcher<Args>(Args(e1, e2, e3, e4, e5, e6));
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+inline internal::ElementsAreMatcher<
+ ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type,
+ typename internal::DecayArray<T4>::type,
+ typename internal::DecayArray<T5>::type,
+ typename internal::DecayArray<T6>::type,
+ typename internal::DecayArray<T7>::type> >
+ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4,
+ const T5& e5, const T6& e6, const T7& e7) {
+ typedef ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type,
+ typename internal::DecayArray<T4>::type,
+ typename internal::DecayArray<T5>::type,
+ typename internal::DecayArray<T6>::type,
+ typename internal::DecayArray<T7>::type> Args;
+ return internal::ElementsAreMatcher<Args>(Args(e1, e2, e3, e4, e5, e6, e7));
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+inline internal::ElementsAreMatcher<
+ ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type,
+ typename internal::DecayArray<T4>::type,
+ typename internal::DecayArray<T5>::type,
+ typename internal::DecayArray<T6>::type,
+ typename internal::DecayArray<T7>::type,
+ typename internal::DecayArray<T8>::type> >
+ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4,
+ const T5& e5, const T6& e6, const T7& e7, const T8& e8) {
+ typedef ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type,
+ typename internal::DecayArray<T4>::type,
+ typename internal::DecayArray<T5>::type,
+ typename internal::DecayArray<T6>::type,
+ typename internal::DecayArray<T7>::type,
+ typename internal::DecayArray<T8>::type> Args;
+ return internal::ElementsAreMatcher<Args>(Args(e1, e2, e3, e4, e5, e6, e7,
+ e8));
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+inline internal::ElementsAreMatcher<
+ ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type,
+ typename internal::DecayArray<T4>::type,
+ typename internal::DecayArray<T5>::type,
+ typename internal::DecayArray<T6>::type,
+ typename internal::DecayArray<T7>::type,
+ typename internal::DecayArray<T8>::type,
+ typename internal::DecayArray<T9>::type> >
+ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4,
+ const T5& e5, const T6& e6, const T7& e7, const T8& e8, const T9& e9) {
+ typedef ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type,
+ typename internal::DecayArray<T4>::type,
+ typename internal::DecayArray<T5>::type,
+ typename internal::DecayArray<T6>::type,
+ typename internal::DecayArray<T7>::type,
+ typename internal::DecayArray<T8>::type,
+ typename internal::DecayArray<T9>::type> Args;
+ return internal::ElementsAreMatcher<Args>(Args(e1, e2, e3, e4, e5, e6, e7,
+ e8, e9));
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+inline internal::ElementsAreMatcher<
+ ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type,
+ typename internal::DecayArray<T4>::type,
+ typename internal::DecayArray<T5>::type,
+ typename internal::DecayArray<T6>::type,
+ typename internal::DecayArray<T7>::type,
+ typename internal::DecayArray<T8>::type,
+ typename internal::DecayArray<T9>::type,
+ typename internal::DecayArray<T10>::type> >
+ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4,
+ const T5& e5, const T6& e6, const T7& e7, const T8& e8, const T9& e9,
+ const T10& e10) {
+ typedef ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type,
+ typename internal::DecayArray<T4>::type,
+ typename internal::DecayArray<T5>::type,
+ typename internal::DecayArray<T6>::type,
+ typename internal::DecayArray<T7>::type,
+ typename internal::DecayArray<T8>::type,
+ typename internal::DecayArray<T9>::type,
+ typename internal::DecayArray<T10>::type> Args;
+ return internal::ElementsAreMatcher<Args>(Args(e1, e2, e3, e4, e5, e6, e7,
+ e8, e9, e10));
+}
+
+// UnorderedElementsAre(e_1, e_2, ..., e_n) is an ElementsAre extension
+// that matches n elements in any order. We support up to n=10 arguments.
+
+inline internal::UnorderedElementsAreMatcher<
+ ::testing::tuple<> >
+UnorderedElementsAre() {
+ typedef ::testing::tuple<> Args;
+ return internal::UnorderedElementsAreMatcher<Args>(Args());
+}
+
+template <typename T1>
+inline internal::UnorderedElementsAreMatcher<
+ ::testing::tuple<
+ typename internal::DecayArray<T1>::type> >
+UnorderedElementsAre(const T1& e1) {
+ typedef ::testing::tuple<
+ typename internal::DecayArray<T1>::type> Args;
+ return internal::UnorderedElementsAreMatcher<Args>(Args(e1));
+}
+
+template <typename T1, typename T2>
+inline internal::UnorderedElementsAreMatcher<
+ ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type> >
+UnorderedElementsAre(const T1& e1, const T2& e2) {
+ typedef ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type> Args;
+ return internal::UnorderedElementsAreMatcher<Args>(Args(e1, e2));
+}
+
+template <typename T1, typename T2, typename T3>
+inline internal::UnorderedElementsAreMatcher<
+ ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type> >
+UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3) {
+ typedef ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type> Args;
+ return internal::UnorderedElementsAreMatcher<Args>(Args(e1, e2, e3));
+}
+
+template <typename T1, typename T2, typename T3, typename T4>
+inline internal::UnorderedElementsAreMatcher<
+ ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type,
+ typename internal::DecayArray<T4>::type> >
+UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4) {
+ typedef ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type,
+ typename internal::DecayArray<T4>::type> Args;
+ return internal::UnorderedElementsAreMatcher<Args>(Args(e1, e2, e3, e4));
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+inline internal::UnorderedElementsAreMatcher<
+ ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type,
+ typename internal::DecayArray<T4>::type,
+ typename internal::DecayArray<T5>::type> >
+UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4,
+ const T5& e5) {
+ typedef ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type,
+ typename internal::DecayArray<T4>::type,
+ typename internal::DecayArray<T5>::type> Args;
+ return internal::UnorderedElementsAreMatcher<Args>(Args(e1, e2, e3, e4, e5));
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6>
+inline internal::UnorderedElementsAreMatcher<
+ ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type,
+ typename internal::DecayArray<T4>::type,
+ typename internal::DecayArray<T5>::type,
+ typename internal::DecayArray<T6>::type> >
+UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4,
+ const T5& e5, const T6& e6) {
+ typedef ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type,
+ typename internal::DecayArray<T4>::type,
+ typename internal::DecayArray<T5>::type,
+ typename internal::DecayArray<T6>::type> Args;
+ return internal::UnorderedElementsAreMatcher<Args>(Args(e1, e2, e3, e4, e5,
+ e6));
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+inline internal::UnorderedElementsAreMatcher<
+ ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type,
+ typename internal::DecayArray<T4>::type,
+ typename internal::DecayArray<T5>::type,
+ typename internal::DecayArray<T6>::type,
+ typename internal::DecayArray<T7>::type> >
+UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4,
+ const T5& e5, const T6& e6, const T7& e7) {
+ typedef ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type,
+ typename internal::DecayArray<T4>::type,
+ typename internal::DecayArray<T5>::type,
+ typename internal::DecayArray<T6>::type,
+ typename internal::DecayArray<T7>::type> Args;
+ return internal::UnorderedElementsAreMatcher<Args>(Args(e1, e2, e3, e4, e5,
+ e6, e7));
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+inline internal::UnorderedElementsAreMatcher<
+ ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type,
+ typename internal::DecayArray<T4>::type,
+ typename internal::DecayArray<T5>::type,
+ typename internal::DecayArray<T6>::type,
+ typename internal::DecayArray<T7>::type,
+ typename internal::DecayArray<T8>::type> >
+UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4,
+ const T5& e5, const T6& e6, const T7& e7, const T8& e8) {
+ typedef ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type,
+ typename internal::DecayArray<T4>::type,
+ typename internal::DecayArray<T5>::type,
+ typename internal::DecayArray<T6>::type,
+ typename internal::DecayArray<T7>::type,
+ typename internal::DecayArray<T8>::type> Args;
+ return internal::UnorderedElementsAreMatcher<Args>(Args(e1, e2, e3, e4, e5,
+ e6, e7, e8));
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+inline internal::UnorderedElementsAreMatcher<
+ ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type,
+ typename internal::DecayArray<T4>::type,
+ typename internal::DecayArray<T5>::type,
+ typename internal::DecayArray<T6>::type,
+ typename internal::DecayArray<T7>::type,
+ typename internal::DecayArray<T8>::type,
+ typename internal::DecayArray<T9>::type> >
+UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4,
+ const T5& e5, const T6& e6, const T7& e7, const T8& e8, const T9& e9) {
+ typedef ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type,
+ typename internal::DecayArray<T4>::type,
+ typename internal::DecayArray<T5>::type,
+ typename internal::DecayArray<T6>::type,
+ typename internal::DecayArray<T7>::type,
+ typename internal::DecayArray<T8>::type,
+ typename internal::DecayArray<T9>::type> Args;
+ return internal::UnorderedElementsAreMatcher<Args>(Args(e1, e2, e3, e4, e5,
+ e6, e7, e8, e9));
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+inline internal::UnorderedElementsAreMatcher<
+ ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type,
+ typename internal::DecayArray<T4>::type,
+ typename internal::DecayArray<T5>::type,
+ typename internal::DecayArray<T6>::type,
+ typename internal::DecayArray<T7>::type,
+ typename internal::DecayArray<T8>::type,
+ typename internal::DecayArray<T9>::type,
+ typename internal::DecayArray<T10>::type> >
+UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4,
+ const T5& e5, const T6& e6, const T7& e7, const T8& e8, const T9& e9,
+ const T10& e10) {
+ typedef ::testing::tuple<
+ typename internal::DecayArray<T1>::type,
+ typename internal::DecayArray<T2>::type,
+ typename internal::DecayArray<T3>::type,
+ typename internal::DecayArray<T4>::type,
+ typename internal::DecayArray<T5>::type,
+ typename internal::DecayArray<T6>::type,
+ typename internal::DecayArray<T7>::type,
+ typename internal::DecayArray<T8>::type,
+ typename internal::DecayArray<T9>::type,
+ typename internal::DecayArray<T10>::type> Args;
+ return internal::UnorderedElementsAreMatcher<Args>(Args(e1, e2, e3, e4, e5,
+ e6, e7, e8, e9, e10));
+}
+
+// AllOf(m1, m2, ..., mk) matches any value that matches all of the given
+// sub-matchers. AllOf is called fully qualified to prevent ADL from firing.
+
+template <typename M1, typename M2>
+inline typename internal::AllOfResult2<M1, M2>::type
+AllOf(M1 m1, M2 m2) {
+ return typename internal::AllOfResult2<M1, M2>::type(
+ m1,
+ m2);
+}
+
+template <typename M1, typename M2, typename M3>
+inline typename internal::AllOfResult3<M1, M2, M3>::type
+AllOf(M1 m1, M2 m2, M3 m3) {
+ return typename internal::AllOfResult3<M1, M2, M3>::type(
+ m1,
+ ::testing::AllOf(m2, m3));
+}
+
+template <typename M1, typename M2, typename M3, typename M4>
+inline typename internal::AllOfResult4<M1, M2, M3, M4>::type
+AllOf(M1 m1, M2 m2, M3 m3, M4 m4) {
+ return typename internal::AllOfResult4<M1, M2, M3, M4>::type(
+ ::testing::AllOf(m1, m2),
+ ::testing::AllOf(m3, m4));
+}
+
+template <typename M1, typename M2, typename M3, typename M4, typename M5>
+inline typename internal::AllOfResult5<M1, M2, M3, M4, M5>::type
+AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5) {
+ return typename internal::AllOfResult5<M1, M2, M3, M4, M5>::type(
+ ::testing::AllOf(m1, m2),
+ ::testing::AllOf(m3, m4, m5));
+}
+
+template <typename M1, typename M2, typename M3, typename M4, typename M5,
+ typename M6>
+inline typename internal::AllOfResult6<M1, M2, M3, M4, M5, M6>::type
+AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6) {
+ return typename internal::AllOfResult6<M1, M2, M3, M4, M5, M6>::type(
+ ::testing::AllOf(m1, m2, m3),
+ ::testing::AllOf(m4, m5, m6));
+}
+
+template <typename M1, typename M2, typename M3, typename M4, typename M5,
+ typename M6, typename M7>
+inline typename internal::AllOfResult7<M1, M2, M3, M4, M5, M6, M7>::type
+AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7) {
+ return typename internal::AllOfResult7<M1, M2, M3, M4, M5, M6, M7>::type(
+ ::testing::AllOf(m1, m2, m3),
+ ::testing::AllOf(m4, m5, m6, m7));
+}
+
+template <typename M1, typename M2, typename M3, typename M4, typename M5,
+ typename M6, typename M7, typename M8>
+inline typename internal::AllOfResult8<M1, M2, M3, M4, M5, M6, M7, M8>::type
+AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8) {
+ return typename internal::AllOfResult8<M1, M2, M3, M4, M5, M6, M7, M8>::type(
+ ::testing::AllOf(m1, m2, m3, m4),
+ ::testing::AllOf(m5, m6, m7, m8));
+}
+
+template <typename M1, typename M2, typename M3, typename M4, typename M5,
+ typename M6, typename M7, typename M8, typename M9>
+inline typename internal::AllOfResult9<M1, M2, M3, M4, M5, M6, M7, M8, M9>::type
+AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9) {
+ return typename internal::AllOfResult9<M1, M2, M3, M4, M5, M6, M7, M8,
+ M9>::type(
+ ::testing::AllOf(m1, m2, m3, m4),
+ ::testing::AllOf(m5, m6, m7, m8, m9));
+}
+
+template <typename M1, typename M2, typename M3, typename M4, typename M5,
+ typename M6, typename M7, typename M8, typename M9, typename M10>
+inline typename internal::AllOfResult10<M1, M2, M3, M4, M5, M6, M7, M8, M9,
+ M10>::type
+AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
+ return typename internal::AllOfResult10<M1, M2, M3, M4, M5, M6, M7, M8, M9,
+ M10>::type(
+ ::testing::AllOf(m1, m2, m3, m4, m5),
+ ::testing::AllOf(m6, m7, m8, m9, m10));
+}
+
+// AnyOf(m1, m2, ..., mk) matches any value that matches any of the given
+// sub-matchers. AnyOf is called fully qualified to prevent ADL from firing.
+
+template <typename M1, typename M2>
+inline typename internal::AnyOfResult2<M1, M2>::type
+AnyOf(M1 m1, M2 m2) {
+ return typename internal::AnyOfResult2<M1, M2>::type(
+ m1,
+ m2);
+}
+
+template <typename M1, typename M2, typename M3>
+inline typename internal::AnyOfResult3<M1, M2, M3>::type
+AnyOf(M1 m1, M2 m2, M3 m3) {
+ return typename internal::AnyOfResult3<M1, M2, M3>::type(
+ m1,
+ ::testing::AnyOf(m2, m3));
+}
+
+template <typename M1, typename M2, typename M3, typename M4>
+inline typename internal::AnyOfResult4<M1, M2, M3, M4>::type
+AnyOf(M1 m1, M2 m2, M3 m3, M4 m4) {
+ return typename internal::AnyOfResult4<M1, M2, M3, M4>::type(
+ ::testing::AnyOf(m1, m2),
+ ::testing::AnyOf(m3, m4));
+}
+
+template <typename M1, typename M2, typename M3, typename M4, typename M5>
+inline typename internal::AnyOfResult5<M1, M2, M3, M4, M5>::type
+AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5) {
+ return typename internal::AnyOfResult5<M1, M2, M3, M4, M5>::type(
+ ::testing::AnyOf(m1, m2),
+ ::testing::AnyOf(m3, m4, m5));
+}
+
+template <typename M1, typename M2, typename M3, typename M4, typename M5,
+ typename M6>
+inline typename internal::AnyOfResult6<M1, M2, M3, M4, M5, M6>::type
+AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6) {
+ return typename internal::AnyOfResult6<M1, M2, M3, M4, M5, M6>::type(
+ ::testing::AnyOf(m1, m2, m3),
+ ::testing::AnyOf(m4, m5, m6));
+}
+
+template <typename M1, typename M2, typename M3, typename M4, typename M5,
+ typename M6, typename M7>
+inline typename internal::AnyOfResult7<M1, M2, M3, M4, M5, M6, M7>::type
+AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7) {
+ return typename internal::AnyOfResult7<M1, M2, M3, M4, M5, M6, M7>::type(
+ ::testing::AnyOf(m1, m2, m3),
+ ::testing::AnyOf(m4, m5, m6, m7));
+}
+
+template <typename M1, typename M2, typename M3, typename M4, typename M5,
+ typename M6, typename M7, typename M8>
+inline typename internal::AnyOfResult8<M1, M2, M3, M4, M5, M6, M7, M8>::type
+AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8) {
+ return typename internal::AnyOfResult8<M1, M2, M3, M4, M5, M6, M7, M8>::type(
+ ::testing::AnyOf(m1, m2, m3, m4),
+ ::testing::AnyOf(m5, m6, m7, m8));
+}
+
+template <typename M1, typename M2, typename M3, typename M4, typename M5,
+ typename M6, typename M7, typename M8, typename M9>
+inline typename internal::AnyOfResult9<M1, M2, M3, M4, M5, M6, M7, M8, M9>::type
+AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9) {
+ return typename internal::AnyOfResult9<M1, M2, M3, M4, M5, M6, M7, M8,
+ M9>::type(
+ ::testing::AnyOf(m1, m2, m3, m4),
+ ::testing::AnyOf(m5, m6, m7, m8, m9));
+}
+
+template <typename M1, typename M2, typename M3, typename M4, typename M5,
+ typename M6, typename M7, typename M8, typename M9, typename M10>
+inline typename internal::AnyOfResult10<M1, M2, M3, M4, M5, M6, M7, M8, M9,
+ M10>::type
+AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
+ return typename internal::AnyOfResult10<M1, M2, M3, M4, M5, M6, M7, M8, M9,
+ M10>::type(
+ ::testing::AnyOf(m1, m2, m3, m4, m5),
+ ::testing::AnyOf(m6, m7, m8, m9, m10));
+}
+
+} // namespace testing
+
+
+// The MATCHER* family of macros can be used in a namespace scope to
+// define custom matchers easily.
+//
+// Basic Usage
+// ===========
+//
+// The syntax
+//
+// MATCHER(name, description_string) { statements; }
+//
+// defines a matcher with the given name that executes the statements,
+// which must return a bool to indicate if the match succeeds. Inside
+// the statements, you can refer to the value being matched by 'arg',
+// and refer to its type by 'arg_type'.
+//
+// The description string documents what the matcher does, and is used
+// to generate the failure message when the match fails. Since a
+// MATCHER() is usually defined in a header file shared by multiple
+// C++ source files, we require the description to be a C-string
+// literal to avoid possible side effects. It can be empty, in which
+// case we'll use the sequence of words in the matcher name as the
+// description.
+//
+// For example:
+//
+// MATCHER(IsEven, "") { return (arg % 2) == 0; }
+//
+// allows you to write
+//
+// // Expects mock_foo.Bar(n) to be called where n is even.
+// EXPECT_CALL(mock_foo, Bar(IsEven()));
+//
+// or,
+//
+// // Verifies that the value of some_expression is even.
+// EXPECT_THAT(some_expression, IsEven());
+//
+// If the above assertion fails, it will print something like:
+//
+// Value of: some_expression
+// Expected: is even
+// Actual: 7
+//
+// where the description "is even" is automatically calculated from the
+// matcher name IsEven.
+//
+// Argument Type
+// =============
+//
+// Note that the type of the value being matched (arg_type) is
+// determined by the context in which you use the matcher and is
+// supplied to you by the compiler, so you don't need to worry about
+// declaring it (nor can you). This allows the matcher to be
+// polymorphic. For example, IsEven() can be used to match any type
+// where the value of "(arg % 2) == 0" can be implicitly converted to
+// a bool. In the "Bar(IsEven())" example above, if method Bar()
+// takes an int, 'arg_type' will be int; if it takes an unsigned long,
+// 'arg_type' will be unsigned long; and so on.
+//
+// Parameterizing Matchers
+// =======================
+//
+// Sometimes you'll want to parameterize the matcher. For that you
+// can use another macro:
+//
+// MATCHER_P(name, param_name, description_string) { statements; }
+//
+// For example:
+//
+// MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; }
+//
+// will allow you to write:
+//
+// EXPECT_THAT(Blah("a"), HasAbsoluteValue(n));
+//
+// which may lead to this message (assuming n is 10):
+//
+// Value of: Blah("a")
+// Expected: has absolute value 10
+// Actual: -9
+//
+// Note that both the matcher description and its parameter are
+// printed, making the message human-friendly.
+//
+// In the matcher definition body, you can write 'foo_type' to
+// reference the type of a parameter named 'foo'. For example, in the
+// body of MATCHER_P(HasAbsoluteValue, value) above, you can write
+// 'value_type' to refer to the type of 'value'.
+//
+// We also provide MATCHER_P2, MATCHER_P3, ..., up to MATCHER_P10 to
+// support multi-parameter matchers.
+//
+// Describing Parameterized Matchers
+// =================================
+//
+// The last argument to MATCHER*() is a string-typed expression. The
+// expression can reference all of the matcher's parameters and a
+// special bool-typed variable named 'negation'. When 'negation' is
+// false, the expression should evaluate to the matcher's description;
+// otherwise it should evaluate to the description of the negation of
+// the matcher. For example,
+//
+// using testing::PrintToString;
+//
+// MATCHER_P2(InClosedRange, low, hi,
+// string(negation ? "is not" : "is") + " in range [" +
+// PrintToString(low) + ", " + PrintToString(hi) + "]") {
+// return low <= arg && arg <= hi;
+// }
+// ...
+// EXPECT_THAT(3, InClosedRange(4, 6));
+// EXPECT_THAT(3, Not(InClosedRange(2, 4)));
+//
+// would generate two failures that contain the text:
+//
+// Expected: is in range [4, 6]
+// ...
+// Expected: is not in range [2, 4]
+//
+// If you specify "" as the description, the failure message will
+// contain the sequence of words in the matcher name followed by the
+// parameter values printed as a tuple. For example,
+//
+// MATCHER_P2(InClosedRange, low, hi, "") { ... }
+// ...
+// EXPECT_THAT(3, InClosedRange(4, 6));
+// EXPECT_THAT(3, Not(InClosedRange(2, 4)));
+//
+// would generate two failures that contain the text:
+//
+// Expected: in closed range (4, 6)
+// ...
+// Expected: not (in closed range (2, 4))
+//
+// Types of Matcher Parameters
+// ===========================
+//
+// For the purpose of typing, you can view
+//
+// MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... }
+//
+// as shorthand for
+//
+// template <typename p1_type, ..., typename pk_type>
+// FooMatcherPk<p1_type, ..., pk_type>
+// Foo(p1_type p1, ..., pk_type pk) { ... }
+//
+// When you write Foo(v1, ..., vk), the compiler infers the types of
+// the parameters v1, ..., and vk for you. If you are not happy with
+// the result of the type inference, you can specify the types by
+// explicitly instantiating the template, as in Foo<long, bool>(5,
+// false). As said earlier, you don't get to (or need to) specify
+// 'arg_type' as that's determined by the context in which the matcher
+// is used. You can assign the result of expression Foo(p1, ..., pk)
+// to a variable of type FooMatcherPk<p1_type, ..., pk_type>. This
+// can be useful when composing matchers.
+//
+// While you can instantiate a matcher template with reference types,
+// passing the parameters by pointer usually makes your code more
+// readable. If, however, you still want to pass a parameter by
+// reference, be aware that in the failure message generated by the
+// matcher you will see the value of the referenced object but not its
+// address.
+//
+// Explaining Match Results
+// ========================
+//
+// Sometimes the matcher description alone isn't enough to explain why
+// the match has failed or succeeded. For example, when expecting a
+// long string, it can be very helpful to also print the diff between
+// the expected string and the actual one. To achieve that, you can
+// optionally stream additional information to a special variable
+// named result_listener, whose type is a pointer to class
+// MatchResultListener:
+//
+// MATCHER_P(EqualsLongString, str, "") {
+// if (arg == str) return true;
+//
+// *result_listener << "the difference: "
+/// << DiffStrings(str, arg);
+// return false;
+// }
+//
+// Overloading Matchers
+// ====================
+//
+// You can overload matchers with different numbers of parameters:
+//
+// MATCHER_P(Blah, a, description_string1) { ... }
+// MATCHER_P2(Blah, a, b, description_string2) { ... }
+//
+// Caveats
+// =======
+//
+// When defining a new matcher, you should also consider implementing
+// MatcherInterface or using MakePolymorphicMatcher(). These
+// approaches require more work than the MATCHER* macros, but also
+// give you more control on the types of the value being matched and
+// the matcher parameters, which may leads to better compiler error
+// messages when the matcher is used wrong. They also allow
+// overloading matchers based on parameter types (as opposed to just
+// based on the number of parameters).
+//
+// MATCHER*() can only be used in a namespace scope. The reason is
+// that C++ doesn't yet allow function-local types to be used to
+// instantiate templates. The up-coming C++0x standard will fix this.
+// Once that's done, we'll consider supporting using MATCHER*() inside
+// a function.
+//
+// More Information
+// ================
+//
+// To learn more about using these macros, please search for 'MATCHER'
+// on http://code.google.com/p/googlemock/wiki/CookBook.
+
+#define MATCHER(name, description)\
+ class name##Matcher {\
+ public:\
+ template <typename arg_type>\
+ class gmock_Impl : public ::testing::MatcherInterface<arg_type> {\
+ public:\
+ gmock_Impl()\
+ {}\
+ virtual bool MatchAndExplain(\
+ arg_type arg, ::testing::MatchResultListener* result_listener) const;\
+ virtual void DescribeTo(::std::ostream* gmock_os) const {\
+ *gmock_os << FormatDescription(false);\
+ }\
+ virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
+ *gmock_os << FormatDescription(true);\
+ }\
+ private:\
+ ::testing::internal::string FormatDescription(bool negation) const {\
+ const ::testing::internal::string gmock_description = (description);\
+ if (!gmock_description.empty())\
+ return gmock_description;\
+ return ::testing::internal::FormatMatcherDescription(\
+ negation, #name, \
+ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
+ ::testing::tuple<>()));\
+ }\
+ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
+ };\
+ template <typename arg_type>\
+ operator ::testing::Matcher<arg_type>() const {\
+ return ::testing::Matcher<arg_type>(\
+ new gmock_Impl<arg_type>());\
+ }\
+ name##Matcher() {\
+ }\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(name##Matcher);\
+ };\
+ inline name##Matcher name() {\
+ return name##Matcher();\
+ }\
+ template <typename arg_type>\
+ bool name##Matcher::gmock_Impl<arg_type>::MatchAndExplain(\
+ arg_type arg, \
+ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
+ const
+
+#define MATCHER_P(name, p0, description)\
+ template <typename p0##_type>\
+ class name##MatcherP {\
+ public:\
+ template <typename arg_type>\
+ class gmock_Impl : public ::testing::MatcherInterface<arg_type> {\
+ public:\
+ explicit gmock_Impl(p0##_type gmock_p0)\
+ : p0(gmock_p0) {}\
+ virtual bool MatchAndExplain(\
+ arg_type arg, ::testing::MatchResultListener* result_listener) const;\
+ virtual void DescribeTo(::std::ostream* gmock_os) const {\
+ *gmock_os << FormatDescription(false);\
+ }\
+ virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
+ *gmock_os << FormatDescription(true);\
+ }\
+ p0##_type p0;\
+ private:\
+ ::testing::internal::string FormatDescription(bool negation) const {\
+ const ::testing::internal::string gmock_description = (description);\
+ if (!gmock_description.empty())\
+ return gmock_description;\
+ return ::testing::internal::FormatMatcherDescription(\
+ negation, #name, \
+ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
+ ::testing::tuple<p0##_type>(p0)));\
+ }\
+ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
+ };\
+ template <typename arg_type>\
+ operator ::testing::Matcher<arg_type>() const {\
+ return ::testing::Matcher<arg_type>(\
+ new gmock_Impl<arg_type>(p0));\
+ }\
+ explicit name##MatcherP(p0##_type gmock_p0) : p0(gmock_p0) {\
+ }\
+ p0##_type p0;\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(name##MatcherP);\
+ };\
+ template <typename p0##_type>\
+ inline name##MatcherP<p0##_type> name(p0##_type p0) {\
+ return name##MatcherP<p0##_type>(p0);\
+ }\
+ template <typename p0##_type>\
+ template <typename arg_type>\
+ bool name##MatcherP<p0##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
+ arg_type arg, \
+ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
+ const
+
+#define MATCHER_P2(name, p0, p1, description)\
+ template <typename p0##_type, typename p1##_type>\
+ class name##MatcherP2 {\
+ public:\
+ template <typename arg_type>\
+ class gmock_Impl : public ::testing::MatcherInterface<arg_type> {\
+ public:\
+ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1)\
+ : p0(gmock_p0), p1(gmock_p1) {}\
+ virtual bool MatchAndExplain(\
+ arg_type arg, ::testing::MatchResultListener* result_listener) const;\
+ virtual void DescribeTo(::std::ostream* gmock_os) const {\
+ *gmock_os << FormatDescription(false);\
+ }\
+ virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
+ *gmock_os << FormatDescription(true);\
+ }\
+ p0##_type p0;\
+ p1##_type p1;\
+ private:\
+ ::testing::internal::string FormatDescription(bool negation) const {\
+ const ::testing::internal::string gmock_description = (description);\
+ if (!gmock_description.empty())\
+ return gmock_description;\
+ return ::testing::internal::FormatMatcherDescription(\
+ negation, #name, \
+ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
+ ::testing::tuple<p0##_type, p1##_type>(p0, p1)));\
+ }\
+ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
+ };\
+ template <typename arg_type>\
+ operator ::testing::Matcher<arg_type>() const {\
+ return ::testing::Matcher<arg_type>(\
+ new gmock_Impl<arg_type>(p0, p1));\
+ }\
+ name##MatcherP2(p0##_type gmock_p0, p1##_type gmock_p1) : p0(gmock_p0), \
+ p1(gmock_p1) {\
+ }\
+ p0##_type p0;\
+ p1##_type p1;\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(name##MatcherP2);\
+ };\
+ template <typename p0##_type, typename p1##_type>\
+ inline name##MatcherP2<p0##_type, p1##_type> name(p0##_type p0, \
+ p1##_type p1) {\
+ return name##MatcherP2<p0##_type, p1##_type>(p0, p1);\
+ }\
+ template <typename p0##_type, typename p1##_type>\
+ template <typename arg_type>\
+ bool name##MatcherP2<p0##_type, \
+ p1##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
+ arg_type arg, \
+ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
+ const
+
+#define MATCHER_P3(name, p0, p1, p2, description)\
+ template <typename p0##_type, typename p1##_type, typename p2##_type>\
+ class name##MatcherP3 {\
+ public:\
+ template <typename arg_type>\
+ class gmock_Impl : public ::testing::MatcherInterface<arg_type> {\
+ public:\
+ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2)\
+ : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2) {}\
+ virtual bool MatchAndExplain(\
+ arg_type arg, ::testing::MatchResultListener* result_listener) const;\
+ virtual void DescribeTo(::std::ostream* gmock_os) const {\
+ *gmock_os << FormatDescription(false);\
+ }\
+ virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
+ *gmock_os << FormatDescription(true);\
+ }\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ private:\
+ ::testing::internal::string FormatDescription(bool negation) const {\
+ const ::testing::internal::string gmock_description = (description);\
+ if (!gmock_description.empty())\
+ return gmock_description;\
+ return ::testing::internal::FormatMatcherDescription(\
+ negation, #name, \
+ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
+ ::testing::tuple<p0##_type, p1##_type, p2##_type>(p0, p1, \
+ p2)));\
+ }\
+ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
+ };\
+ template <typename arg_type>\
+ operator ::testing::Matcher<arg_type>() const {\
+ return ::testing::Matcher<arg_type>(\
+ new gmock_Impl<arg_type>(p0, p1, p2));\
+ }\
+ name##MatcherP3(p0##_type gmock_p0, p1##_type gmock_p1, \
+ p2##_type gmock_p2) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2) {\
+ }\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(name##MatcherP3);\
+ };\
+ template <typename p0##_type, typename p1##_type, typename p2##_type>\
+ inline name##MatcherP3<p0##_type, p1##_type, p2##_type> name(p0##_type p0, \
+ p1##_type p1, p2##_type p2) {\
+ return name##MatcherP3<p0##_type, p1##_type, p2##_type>(p0, p1, p2);\
+ }\
+ template <typename p0##_type, typename p1##_type, typename p2##_type>\
+ template <typename arg_type>\
+ bool name##MatcherP3<p0##_type, p1##_type, \
+ p2##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
+ arg_type arg, \
+ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
+ const
+
+#define MATCHER_P4(name, p0, p1, p2, p3, description)\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type>\
+ class name##MatcherP4 {\
+ public:\
+ template <typename arg_type>\
+ class gmock_Impl : public ::testing::MatcherInterface<arg_type> {\
+ public:\
+ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
+ p3##_type gmock_p3)\
+ : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3) {}\
+ virtual bool MatchAndExplain(\
+ arg_type arg, ::testing::MatchResultListener* result_listener) const;\
+ virtual void DescribeTo(::std::ostream* gmock_os) const {\
+ *gmock_os << FormatDescription(false);\
+ }\
+ virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
+ *gmock_os << FormatDescription(true);\
+ }\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ p3##_type p3;\
+ private:\
+ ::testing::internal::string FormatDescription(bool negation) const {\
+ const ::testing::internal::string gmock_description = (description);\
+ if (!gmock_description.empty())\
+ return gmock_description;\
+ return ::testing::internal::FormatMatcherDescription(\
+ negation, #name, \
+ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
+ ::testing::tuple<p0##_type, p1##_type, p2##_type, \
+ p3##_type>(p0, p1, p2, p3)));\
+ }\
+ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
+ };\
+ template <typename arg_type>\
+ operator ::testing::Matcher<arg_type>() const {\
+ return ::testing::Matcher<arg_type>(\
+ new gmock_Impl<arg_type>(p0, p1, p2, p3));\
+ }\
+ name##MatcherP4(p0##_type gmock_p0, p1##_type gmock_p1, \
+ p2##_type gmock_p2, p3##_type gmock_p3) : p0(gmock_p0), p1(gmock_p1), \
+ p2(gmock_p2), p3(gmock_p3) {\
+ }\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ p3##_type p3;\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(name##MatcherP4);\
+ };\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type>\
+ inline name##MatcherP4<p0##_type, p1##_type, p2##_type, \
+ p3##_type> name(p0##_type p0, p1##_type p1, p2##_type p2, \
+ p3##_type p3) {\
+ return name##MatcherP4<p0##_type, p1##_type, p2##_type, p3##_type>(p0, \
+ p1, p2, p3);\
+ }\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type>\
+ template <typename arg_type>\
+ bool name##MatcherP4<p0##_type, p1##_type, p2##_type, \
+ p3##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
+ arg_type arg, \
+ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
+ const
+
+#define MATCHER_P5(name, p0, p1, p2, p3, p4, description)\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type>\
+ class name##MatcherP5 {\
+ public:\
+ template <typename arg_type>\
+ class gmock_Impl : public ::testing::MatcherInterface<arg_type> {\
+ public:\
+ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
+ p3##_type gmock_p3, p4##_type gmock_p4)\
+ : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \
+ p4(gmock_p4) {}\
+ virtual bool MatchAndExplain(\
+ arg_type arg, ::testing::MatchResultListener* result_listener) const;\
+ virtual void DescribeTo(::std::ostream* gmock_os) const {\
+ *gmock_os << FormatDescription(false);\
+ }\
+ virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
+ *gmock_os << FormatDescription(true);\
+ }\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ p3##_type p3;\
+ p4##_type p4;\
+ private:\
+ ::testing::internal::string FormatDescription(bool negation) const {\
+ const ::testing::internal::string gmock_description = (description);\
+ if (!gmock_description.empty())\
+ return gmock_description;\
+ return ::testing::internal::FormatMatcherDescription(\
+ negation, #name, \
+ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
+ ::testing::tuple<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type>(p0, p1, p2, p3, p4)));\
+ }\
+ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
+ };\
+ template <typename arg_type>\
+ operator ::testing::Matcher<arg_type>() const {\
+ return ::testing::Matcher<arg_type>(\
+ new gmock_Impl<arg_type>(p0, p1, p2, p3, p4));\
+ }\
+ name##MatcherP5(p0##_type gmock_p0, p1##_type gmock_p1, \
+ p2##_type gmock_p2, p3##_type gmock_p3, \
+ p4##_type gmock_p4) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
+ p3(gmock_p3), p4(gmock_p4) {\
+ }\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ p3##_type p3;\
+ p4##_type p4;\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(name##MatcherP5);\
+ };\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type>\
+ inline name##MatcherP5<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type> name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \
+ p4##_type p4) {\
+ return name##MatcherP5<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type>(p0, p1, p2, p3, p4);\
+ }\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type>\
+ template <typename arg_type>\
+ bool name##MatcherP5<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
+ arg_type arg, \
+ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
+ const
+
+#define MATCHER_P6(name, p0, p1, p2, p3, p4, p5, description)\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type>\
+ class name##MatcherP6 {\
+ public:\
+ template <typename arg_type>\
+ class gmock_Impl : public ::testing::MatcherInterface<arg_type> {\
+ public:\
+ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
+ p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5)\
+ : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \
+ p4(gmock_p4), p5(gmock_p5) {}\
+ virtual bool MatchAndExplain(\
+ arg_type arg, ::testing::MatchResultListener* result_listener) const;\
+ virtual void DescribeTo(::std::ostream* gmock_os) const {\
+ *gmock_os << FormatDescription(false);\
+ }\
+ virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
+ *gmock_os << FormatDescription(true);\
+ }\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ p3##_type p3;\
+ p4##_type p4;\
+ p5##_type p5;\
+ private:\
+ ::testing::internal::string FormatDescription(bool negation) const {\
+ const ::testing::internal::string gmock_description = (description);\
+ if (!gmock_description.empty())\
+ return gmock_description;\
+ return ::testing::internal::FormatMatcherDescription(\
+ negation, #name, \
+ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
+ ::testing::tuple<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type, p5##_type>(p0, p1, p2, p3, p4, p5)));\
+ }\
+ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
+ };\
+ template <typename arg_type>\
+ operator ::testing::Matcher<arg_type>() const {\
+ return ::testing::Matcher<arg_type>(\
+ new gmock_Impl<arg_type>(p0, p1, p2, p3, p4, p5));\
+ }\
+ name##MatcherP6(p0##_type gmock_p0, p1##_type gmock_p1, \
+ p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \
+ p5##_type gmock_p5) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
+ p3(gmock_p3), p4(gmock_p4), p5(gmock_p5) {\
+ }\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ p3##_type p3;\
+ p4##_type p4;\
+ p5##_type p5;\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(name##MatcherP6);\
+ };\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type>\
+ inline name##MatcherP6<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type, p5##_type> name(p0##_type p0, p1##_type p1, p2##_type p2, \
+ p3##_type p3, p4##_type p4, p5##_type p5) {\
+ return name##MatcherP6<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type, p5##_type>(p0, p1, p2, p3, p4, p5);\
+ }\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type>\
+ template <typename arg_type>\
+ bool name##MatcherP6<p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \
+ p5##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
+ arg_type arg, \
+ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
+ const
+
+#define MATCHER_P7(name, p0, p1, p2, p3, p4, p5, p6, description)\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type, \
+ typename p6##_type>\
+ class name##MatcherP7 {\
+ public:\
+ template <typename arg_type>\
+ class gmock_Impl : public ::testing::MatcherInterface<arg_type> {\
+ public:\
+ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
+ p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
+ p6##_type gmock_p6)\
+ : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \
+ p4(gmock_p4), p5(gmock_p5), p6(gmock_p6) {}\
+ virtual bool MatchAndExplain(\
+ arg_type arg, ::testing::MatchResultListener* result_listener) const;\
+ virtual void DescribeTo(::std::ostream* gmock_os) const {\
+ *gmock_os << FormatDescription(false);\
+ }\
+ virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
+ *gmock_os << FormatDescription(true);\
+ }\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ p3##_type p3;\
+ p4##_type p4;\
+ p5##_type p5;\
+ p6##_type p6;\
+ private:\
+ ::testing::internal::string FormatDescription(bool negation) const {\
+ const ::testing::internal::string gmock_description = (description);\
+ if (!gmock_description.empty())\
+ return gmock_description;\
+ return ::testing::internal::FormatMatcherDescription(\
+ negation, #name, \
+ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
+ ::testing::tuple<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type, p5##_type, p6##_type>(p0, p1, p2, p3, p4, p5, \
+ p6)));\
+ }\
+ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
+ };\
+ template <typename arg_type>\
+ operator ::testing::Matcher<arg_type>() const {\
+ return ::testing::Matcher<arg_type>(\
+ new gmock_Impl<arg_type>(p0, p1, p2, p3, p4, p5, p6));\
+ }\
+ name##MatcherP7(p0##_type gmock_p0, p1##_type gmock_p1, \
+ p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \
+ p5##_type gmock_p5, p6##_type gmock_p6) : p0(gmock_p0), p1(gmock_p1), \
+ p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), \
+ p6(gmock_p6) {\
+ }\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ p3##_type p3;\
+ p4##_type p4;\
+ p5##_type p5;\
+ p6##_type p6;\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(name##MatcherP7);\
+ };\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type, \
+ typename p6##_type>\
+ inline name##MatcherP7<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type, p5##_type, p6##_type> name(p0##_type p0, p1##_type p1, \
+ p2##_type p2, p3##_type p3, p4##_type p4, p5##_type p5, \
+ p6##_type p6) {\
+ return name##MatcherP7<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type, p5##_type, p6##_type>(p0, p1, p2, p3, p4, p5, p6);\
+ }\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type, \
+ typename p6##_type>\
+ template <typename arg_type>\
+ bool name##MatcherP7<p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \
+ p5##_type, p6##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
+ arg_type arg, \
+ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
+ const
+
+#define MATCHER_P8(name, p0, p1, p2, p3, p4, p5, p6, p7, description)\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type, \
+ typename p6##_type, typename p7##_type>\
+ class name##MatcherP8 {\
+ public:\
+ template <typename arg_type>\
+ class gmock_Impl : public ::testing::MatcherInterface<arg_type> {\
+ public:\
+ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
+ p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
+ p6##_type gmock_p6, p7##_type gmock_p7)\
+ : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \
+ p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7) {}\
+ virtual bool MatchAndExplain(\
+ arg_type arg, ::testing::MatchResultListener* result_listener) const;\
+ virtual void DescribeTo(::std::ostream* gmock_os) const {\
+ *gmock_os << FormatDescription(false);\
+ }\
+ virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
+ *gmock_os << FormatDescription(true);\
+ }\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ p3##_type p3;\
+ p4##_type p4;\
+ p5##_type p5;\
+ p6##_type p6;\
+ p7##_type p7;\
+ private:\
+ ::testing::internal::string FormatDescription(bool negation) const {\
+ const ::testing::internal::string gmock_description = (description);\
+ if (!gmock_description.empty())\
+ return gmock_description;\
+ return ::testing::internal::FormatMatcherDescription(\
+ negation, #name, \
+ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
+ ::testing::tuple<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type, p5##_type, p6##_type, p7##_type>(p0, p1, p2, \
+ p3, p4, p5, p6, p7)));\
+ }\
+ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
+ };\
+ template <typename arg_type>\
+ operator ::testing::Matcher<arg_type>() const {\
+ return ::testing::Matcher<arg_type>(\
+ new gmock_Impl<arg_type>(p0, p1, p2, p3, p4, p5, p6, p7));\
+ }\
+ name##MatcherP8(p0##_type gmock_p0, p1##_type gmock_p1, \
+ p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \
+ p5##_type gmock_p5, p6##_type gmock_p6, \
+ p7##_type gmock_p7) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
+ p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \
+ p7(gmock_p7) {\
+ }\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ p3##_type p3;\
+ p4##_type p4;\
+ p5##_type p5;\
+ p6##_type p6;\
+ p7##_type p7;\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(name##MatcherP8);\
+ };\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type, \
+ typename p6##_type, typename p7##_type>\
+ inline name##MatcherP8<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type, p5##_type, p6##_type, p7##_type> name(p0##_type p0, \
+ p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4, p5##_type p5, \
+ p6##_type p6, p7##_type p7) {\
+ return name##MatcherP8<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type, p5##_type, p6##_type, p7##_type>(p0, p1, p2, p3, p4, p5, \
+ p6, p7);\
+ }\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type, \
+ typename p6##_type, typename p7##_type>\
+ template <typename arg_type>\
+ bool name##MatcherP8<p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \
+ p5##_type, p6##_type, \
+ p7##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
+ arg_type arg, \
+ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
+ const
+
+#define MATCHER_P9(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, description)\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type, \
+ typename p6##_type, typename p7##_type, typename p8##_type>\
+ class name##MatcherP9 {\
+ public:\
+ template <typename arg_type>\
+ class gmock_Impl : public ::testing::MatcherInterface<arg_type> {\
+ public:\
+ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
+ p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
+ p6##_type gmock_p6, p7##_type gmock_p7, p8##_type gmock_p8)\
+ : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \
+ p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \
+ p8(gmock_p8) {}\
+ virtual bool MatchAndExplain(\
+ arg_type arg, ::testing::MatchResultListener* result_listener) const;\
+ virtual void DescribeTo(::std::ostream* gmock_os) const {\
+ *gmock_os << FormatDescription(false);\
+ }\
+ virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
+ *gmock_os << FormatDescription(true);\
+ }\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ p3##_type p3;\
+ p4##_type p4;\
+ p5##_type p5;\
+ p6##_type p6;\
+ p7##_type p7;\
+ p8##_type p8;\
+ private:\
+ ::testing::internal::string FormatDescription(bool negation) const {\
+ const ::testing::internal::string gmock_description = (description);\
+ if (!gmock_description.empty())\
+ return gmock_description;\
+ return ::testing::internal::FormatMatcherDescription(\
+ negation, #name, \
+ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
+ ::testing::tuple<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type, p5##_type, p6##_type, p7##_type, \
+ p8##_type>(p0, p1, p2, p3, p4, p5, p6, p7, p8)));\
+ }\
+ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
+ };\
+ template <typename arg_type>\
+ operator ::testing::Matcher<arg_type>() const {\
+ return ::testing::Matcher<arg_type>(\
+ new gmock_Impl<arg_type>(p0, p1, p2, p3, p4, p5, p6, p7, p8));\
+ }\
+ name##MatcherP9(p0##_type gmock_p0, p1##_type gmock_p1, \
+ p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \
+ p5##_type gmock_p5, p6##_type gmock_p6, p7##_type gmock_p7, \
+ p8##_type gmock_p8) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
+ p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \
+ p8(gmock_p8) {\
+ }\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ p3##_type p3;\
+ p4##_type p4;\
+ p5##_type p5;\
+ p6##_type p6;\
+ p7##_type p7;\
+ p8##_type p8;\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(name##MatcherP9);\
+ };\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type, \
+ typename p6##_type, typename p7##_type, typename p8##_type>\
+ inline name##MatcherP9<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type, p5##_type, p6##_type, p7##_type, \
+ p8##_type> name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \
+ p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, \
+ p8##_type p8) {\
+ return name##MatcherP9<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type, p5##_type, p6##_type, p7##_type, p8##_type>(p0, p1, p2, \
+ p3, p4, p5, p6, p7, p8);\
+ }\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type, \
+ typename p6##_type, typename p7##_type, typename p8##_type>\
+ template <typename arg_type>\
+ bool name##MatcherP9<p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \
+ p5##_type, p6##_type, p7##_type, \
+ p8##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
+ arg_type arg, \
+ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
+ const
+
+#define MATCHER_P10(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, description)\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type, \
+ typename p6##_type, typename p7##_type, typename p8##_type, \
+ typename p9##_type>\
+ class name##MatcherP10 {\
+ public:\
+ template <typename arg_type>\
+ class gmock_Impl : public ::testing::MatcherInterface<arg_type> {\
+ public:\
+ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
+ p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
+ p6##_type gmock_p6, p7##_type gmock_p7, p8##_type gmock_p8, \
+ p9##_type gmock_p9)\
+ : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \
+ p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \
+ p8(gmock_p8), p9(gmock_p9) {}\
+ virtual bool MatchAndExplain(\
+ arg_type arg, ::testing::MatchResultListener* result_listener) const;\
+ virtual void DescribeTo(::std::ostream* gmock_os) const {\
+ *gmock_os << FormatDescription(false);\
+ }\
+ virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
+ *gmock_os << FormatDescription(true);\
+ }\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ p3##_type p3;\
+ p4##_type p4;\
+ p5##_type p5;\
+ p6##_type p6;\
+ p7##_type p7;\
+ p8##_type p8;\
+ p9##_type p9;\
+ private:\
+ ::testing::internal::string FormatDescription(bool negation) const {\
+ const ::testing::internal::string gmock_description = (description);\
+ if (!gmock_description.empty())\
+ return gmock_description;\
+ return ::testing::internal::FormatMatcherDescription(\
+ negation, #name, \
+ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
+ ::testing::tuple<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type, p5##_type, p6##_type, p7##_type, p8##_type, \
+ p9##_type>(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)));\
+ }\
+ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
+ };\
+ template <typename arg_type>\
+ operator ::testing::Matcher<arg_type>() const {\
+ return ::testing::Matcher<arg_type>(\
+ new gmock_Impl<arg_type>(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9));\
+ }\
+ name##MatcherP10(p0##_type gmock_p0, p1##_type gmock_p1, \
+ p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \
+ p5##_type gmock_p5, p6##_type gmock_p6, p7##_type gmock_p7, \
+ p8##_type gmock_p8, p9##_type gmock_p9) : p0(gmock_p0), p1(gmock_p1), \
+ p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \
+ p7(gmock_p7), p8(gmock_p8), p9(gmock_p9) {\
+ }\
+ p0##_type p0;\
+ p1##_type p1;\
+ p2##_type p2;\
+ p3##_type p3;\
+ p4##_type p4;\
+ p5##_type p5;\
+ p6##_type p6;\
+ p7##_type p7;\
+ p8##_type p8;\
+ p9##_type p9;\
+ private:\
+ GTEST_DISALLOW_ASSIGN_(name##MatcherP10);\
+ };\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type, \
+ typename p6##_type, typename p7##_type, typename p8##_type, \
+ typename p9##_type>\
+ inline name##MatcherP10<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type, p5##_type, p6##_type, p7##_type, p8##_type, \
+ p9##_type> name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \
+ p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, p8##_type p8, \
+ p9##_type p9) {\
+ return name##MatcherP10<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type, p5##_type, p6##_type, p7##_type, p8##_type, p9##_type>(p0, \
+ p1, p2, p3, p4, p5, p6, p7, p8, p9);\
+ }\
+ template <typename p0##_type, typename p1##_type, typename p2##_type, \
+ typename p3##_type, typename p4##_type, typename p5##_type, \
+ typename p6##_type, typename p7##_type, typename p8##_type, \
+ typename p9##_type>\
+ template <typename arg_type>\
+ bool name##MatcherP10<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type, p5##_type, p6##_type, p7##_type, p8##_type, \
+ p9##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
+ arg_type arg, \
+ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
+ const
+
+#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_
diff --git a/extern/gmock/include/gmock/gmock-generated-nice-strict.h b/extern/gmock/include/gmock/gmock-generated-nice-strict.h
new file mode 100644
index 00000000000..4095f4d5bc7
--- /dev/null
+++ b/extern/gmock/include/gmock/gmock-generated-nice-strict.h
@@ -0,0 +1,397 @@
+// This file was GENERATED by command:
+// pump.py gmock-generated-nice-strict.h.pump
+// DO NOT EDIT BY HAND!!!
+
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Implements class templates NiceMock, NaggyMock, and StrictMock.
+//
+// Given a mock class MockFoo that is created using Google Mock,
+// NiceMock<MockFoo> is a subclass of MockFoo that allows
+// uninteresting calls (i.e. calls to mock methods that have no
+// EXPECT_CALL specs), NaggyMock<MockFoo> is a subclass of MockFoo
+// that prints a warning when an uninteresting call occurs, and
+// StrictMock<MockFoo> is a subclass of MockFoo that treats all
+// uninteresting calls as errors.
+//
+// Currently a mock is naggy by default, so MockFoo and
+// NaggyMock<MockFoo> behave like the same. However, we will soon
+// switch the default behavior of mocks to be nice, as that in general
+// leads to more maintainable tests. When that happens, MockFoo will
+// stop behaving like NaggyMock<MockFoo> and start behaving like
+// NiceMock<MockFoo>.
+//
+// NiceMock, NaggyMock, and StrictMock "inherit" the constructors of
+// their respective base class, with up-to 10 arguments. Therefore
+// you can write NiceMock<MockFoo>(5, "a") to construct a nice mock
+// where MockFoo has a constructor that accepts (int, const char*),
+// for example.
+//
+// A known limitation is that NiceMock<MockFoo>, NaggyMock<MockFoo>,
+// and StrictMock<MockFoo> only works for mock methods defined using
+// the MOCK_METHOD* family of macros DIRECTLY in the MockFoo class.
+// If a mock method is defined in a base class of MockFoo, the "nice"
+// or "strict" modifier may not affect it, depending on the compiler.
+// In particular, nesting NiceMock, NaggyMock, and StrictMock is NOT
+// supported.
+//
+// Another known limitation is that the constructors of the base mock
+// cannot have arguments passed by non-const reference, which are
+// banned by the Google C++ style guide anyway.
+
+#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_
+#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_
+
+#include "gmock/gmock-spec-builders.h"
+#include "gmock/internal/gmock-port.h"
+
+namespace testing {
+
+template <class MockClass>
+class NiceMock : public MockClass {
+ public:
+ // We don't factor out the constructor body to a common method, as
+ // we have to avoid a possible clash with members of MockClass.
+ NiceMock() {
+ ::testing::Mock::AllowUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ // C++ doesn't (yet) allow inheritance of constructors, so we have
+ // to define it for each arity.
+ template <typename A1>
+ explicit NiceMock(const A1& a1) : MockClass(a1) {
+ ::testing::Mock::AllowUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+ template <typename A1, typename A2>
+ NiceMock(const A1& a1, const A2& a2) : MockClass(a1, a2) {
+ ::testing::Mock::AllowUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ template <typename A1, typename A2, typename A3>
+ NiceMock(const A1& a1, const A2& a2, const A3& a3) : MockClass(a1, a2, a3) {
+ ::testing::Mock::AllowUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ template <typename A1, typename A2, typename A3, typename A4>
+ NiceMock(const A1& a1, const A2& a2, const A3& a3,
+ const A4& a4) : MockClass(a1, a2, a3, a4) {
+ ::testing::Mock::AllowUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ template <typename A1, typename A2, typename A3, typename A4, typename A5>
+ NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
+ const A5& a5) : MockClass(a1, a2, a3, a4, a5) {
+ ::testing::Mock::AllowUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ template <typename A1, typename A2, typename A3, typename A4, typename A5,
+ typename A6>
+ NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
+ const A5& a5, const A6& a6) : MockClass(a1, a2, a3, a4, a5, a6) {
+ ::testing::Mock::AllowUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ template <typename A1, typename A2, typename A3, typename A4, typename A5,
+ typename A6, typename A7>
+ NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
+ const A5& a5, const A6& a6, const A7& a7) : MockClass(a1, a2, a3, a4, a5,
+ a6, a7) {
+ ::testing::Mock::AllowUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ template <typename A1, typename A2, typename A3, typename A4, typename A5,
+ typename A6, typename A7, typename A8>
+ NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
+ const A5& a5, const A6& a6, const A7& a7, const A8& a8) : MockClass(a1,
+ a2, a3, a4, a5, a6, a7, a8) {
+ ::testing::Mock::AllowUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ template <typename A1, typename A2, typename A3, typename A4, typename A5,
+ typename A6, typename A7, typename A8, typename A9>
+ NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
+ const A5& a5, const A6& a6, const A7& a7, const A8& a8,
+ const A9& a9) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9) {
+ ::testing::Mock::AllowUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ template <typename A1, typename A2, typename A3, typename A4, typename A5,
+ typename A6, typename A7, typename A8, typename A9, typename A10>
+ NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
+ const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9,
+ const A10& a10) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) {
+ ::testing::Mock::AllowUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ virtual ~NiceMock() {
+ ::testing::Mock::UnregisterCallReaction(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(NiceMock);
+};
+
+template <class MockClass>
+class NaggyMock : public MockClass {
+ public:
+ // We don't factor out the constructor body to a common method, as
+ // we have to avoid a possible clash with members of MockClass.
+ NaggyMock() {
+ ::testing::Mock::WarnUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ // C++ doesn't (yet) allow inheritance of constructors, so we have
+ // to define it for each arity.
+ template <typename A1>
+ explicit NaggyMock(const A1& a1) : MockClass(a1) {
+ ::testing::Mock::WarnUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+ template <typename A1, typename A2>
+ NaggyMock(const A1& a1, const A2& a2) : MockClass(a1, a2) {
+ ::testing::Mock::WarnUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ template <typename A1, typename A2, typename A3>
+ NaggyMock(const A1& a1, const A2& a2, const A3& a3) : MockClass(a1, a2, a3) {
+ ::testing::Mock::WarnUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ template <typename A1, typename A2, typename A3, typename A4>
+ NaggyMock(const A1& a1, const A2& a2, const A3& a3,
+ const A4& a4) : MockClass(a1, a2, a3, a4) {
+ ::testing::Mock::WarnUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ template <typename A1, typename A2, typename A3, typename A4, typename A5>
+ NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
+ const A5& a5) : MockClass(a1, a2, a3, a4, a5) {
+ ::testing::Mock::WarnUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ template <typename A1, typename A2, typename A3, typename A4, typename A5,
+ typename A6>
+ NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
+ const A5& a5, const A6& a6) : MockClass(a1, a2, a3, a4, a5, a6) {
+ ::testing::Mock::WarnUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ template <typename A1, typename A2, typename A3, typename A4, typename A5,
+ typename A6, typename A7>
+ NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
+ const A5& a5, const A6& a6, const A7& a7) : MockClass(a1, a2, a3, a4, a5,
+ a6, a7) {
+ ::testing::Mock::WarnUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ template <typename A1, typename A2, typename A3, typename A4, typename A5,
+ typename A6, typename A7, typename A8>
+ NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
+ const A5& a5, const A6& a6, const A7& a7, const A8& a8) : MockClass(a1,
+ a2, a3, a4, a5, a6, a7, a8) {
+ ::testing::Mock::WarnUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ template <typename A1, typename A2, typename A3, typename A4, typename A5,
+ typename A6, typename A7, typename A8, typename A9>
+ NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
+ const A5& a5, const A6& a6, const A7& a7, const A8& a8,
+ const A9& a9) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9) {
+ ::testing::Mock::WarnUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ template <typename A1, typename A2, typename A3, typename A4, typename A5,
+ typename A6, typename A7, typename A8, typename A9, typename A10>
+ NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
+ const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9,
+ const A10& a10) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) {
+ ::testing::Mock::WarnUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ virtual ~NaggyMock() {
+ ::testing::Mock::UnregisterCallReaction(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(NaggyMock);
+};
+
+template <class MockClass>
+class StrictMock : public MockClass {
+ public:
+ // We don't factor out the constructor body to a common method, as
+ // we have to avoid a possible clash with members of MockClass.
+ StrictMock() {
+ ::testing::Mock::FailUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ // C++ doesn't (yet) allow inheritance of constructors, so we have
+ // to define it for each arity.
+ template <typename A1>
+ explicit StrictMock(const A1& a1) : MockClass(a1) {
+ ::testing::Mock::FailUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+ template <typename A1, typename A2>
+ StrictMock(const A1& a1, const A2& a2) : MockClass(a1, a2) {
+ ::testing::Mock::FailUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ template <typename A1, typename A2, typename A3>
+ StrictMock(const A1& a1, const A2& a2, const A3& a3) : MockClass(a1, a2, a3) {
+ ::testing::Mock::FailUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ template <typename A1, typename A2, typename A3, typename A4>
+ StrictMock(const A1& a1, const A2& a2, const A3& a3,
+ const A4& a4) : MockClass(a1, a2, a3, a4) {
+ ::testing::Mock::FailUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ template <typename A1, typename A2, typename A3, typename A4, typename A5>
+ StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
+ const A5& a5) : MockClass(a1, a2, a3, a4, a5) {
+ ::testing::Mock::FailUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ template <typename A1, typename A2, typename A3, typename A4, typename A5,
+ typename A6>
+ StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
+ const A5& a5, const A6& a6) : MockClass(a1, a2, a3, a4, a5, a6) {
+ ::testing::Mock::FailUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ template <typename A1, typename A2, typename A3, typename A4, typename A5,
+ typename A6, typename A7>
+ StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
+ const A5& a5, const A6& a6, const A7& a7) : MockClass(a1, a2, a3, a4, a5,
+ a6, a7) {
+ ::testing::Mock::FailUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ template <typename A1, typename A2, typename A3, typename A4, typename A5,
+ typename A6, typename A7, typename A8>
+ StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
+ const A5& a5, const A6& a6, const A7& a7, const A8& a8) : MockClass(a1,
+ a2, a3, a4, a5, a6, a7, a8) {
+ ::testing::Mock::FailUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ template <typename A1, typename A2, typename A3, typename A4, typename A5,
+ typename A6, typename A7, typename A8, typename A9>
+ StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
+ const A5& a5, const A6& a6, const A7& a7, const A8& a8,
+ const A9& a9) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9) {
+ ::testing::Mock::FailUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ template <typename A1, typename A2, typename A3, typename A4, typename A5,
+ typename A6, typename A7, typename A8, typename A9, typename A10>
+ StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
+ const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9,
+ const A10& a10) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) {
+ ::testing::Mock::FailUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ virtual ~StrictMock() {
+ ::testing::Mock::UnregisterCallReaction(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(StrictMock);
+};
+
+// The following specializations catch some (relatively more common)
+// user errors of nesting nice and strict mocks. They do NOT catch
+// all possible errors.
+
+// These specializations are declared but not defined, as NiceMock,
+// NaggyMock, and StrictMock cannot be nested.
+
+template <typename MockClass>
+class NiceMock<NiceMock<MockClass> >;
+template <typename MockClass>
+class NiceMock<NaggyMock<MockClass> >;
+template <typename MockClass>
+class NiceMock<StrictMock<MockClass> >;
+
+template <typename MockClass>
+class NaggyMock<NiceMock<MockClass> >;
+template <typename MockClass>
+class NaggyMock<NaggyMock<MockClass> >;
+template <typename MockClass>
+class NaggyMock<StrictMock<MockClass> >;
+
+template <typename MockClass>
+class StrictMock<NiceMock<MockClass> >;
+template <typename MockClass>
+class StrictMock<NaggyMock<MockClass> >;
+template <typename MockClass>
+class StrictMock<StrictMock<MockClass> >;
+
+} // namespace testing
+
+#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_
diff --git a/extern/gmock/include/gmock/gmock-matchers.h b/extern/gmock/include/gmock/gmock-matchers.h
new file mode 100644
index 00000000000..33b37a7a5d6
--- /dev/null
+++ b/extern/gmock/include/gmock/gmock-matchers.h
@@ -0,0 +1,4399 @@
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Google Mock - a framework for writing C++ mock classes.
+//
+// This file implements some commonly used argument matchers. More
+// matchers can be defined by the user implementing the
+// MatcherInterface<T> interface if necessary.
+
+#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_
+#define GMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_
+
+#include <math.h>
+#include <algorithm>
+#include <iterator>
+#include <limits>
+#include <ostream> // NOLINT
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "gmock/internal/gmock-internal-utils.h"
+#include "gmock/internal/gmock-port.h"
+#include "gtest/gtest.h"
+
+#if GTEST_HAS_STD_INITIALIZER_LIST_
+# include <initializer_list> // NOLINT -- must be after gtest.h
+#endif
+
+namespace testing {
+
+// To implement a matcher Foo for type T, define:
+// 1. a class FooMatcherImpl that implements the
+// MatcherInterface<T> interface, and
+// 2. a factory function that creates a Matcher<T> object from a
+// FooMatcherImpl*.
+//
+// The two-level delegation design makes it possible to allow a user
+// to write "v" instead of "Eq(v)" where a Matcher is expected, which
+// is impossible if we pass matchers by pointers. It also eases
+// ownership management as Matcher objects can now be copied like
+// plain values.
+
+// MatchResultListener is an abstract class. Its << operator can be
+// used by a matcher to explain why a value matches or doesn't match.
+//
+// TODO(wan@google.com): add method
+// bool InterestedInWhy(bool result) const;
+// to indicate whether the listener is interested in why the match
+// result is 'result'.
+class MatchResultListener {
+ public:
+ // Creates a listener object with the given underlying ostream. The
+ // listener does not own the ostream, and does not dereference it
+ // in the constructor or destructor.
+ explicit MatchResultListener(::std::ostream* os) : stream_(os) {}
+ virtual ~MatchResultListener() = 0; // Makes this class abstract.
+
+ // Streams x to the underlying ostream; does nothing if the ostream
+ // is NULL.
+ template <typename T>
+ MatchResultListener& operator<<(const T& x) {
+ if (stream_ != NULL)
+ *stream_ << x;
+ return *this;
+ }
+
+ // Returns the underlying ostream.
+ ::std::ostream* stream() { return stream_; }
+
+ // Returns true iff the listener is interested in an explanation of
+ // the match result. A matcher's MatchAndExplain() method can use
+ // this information to avoid generating the explanation when no one
+ // intends to hear it.
+ bool IsInterested() const { return stream_ != NULL; }
+
+ private:
+ ::std::ostream* const stream_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(MatchResultListener);
+};
+
+inline MatchResultListener::~MatchResultListener() {
+}
+
+// An instance of a subclass of this knows how to describe itself as a
+// matcher.
+class MatcherDescriberInterface {
+ public:
+ virtual ~MatcherDescriberInterface() {}
+
+ // Describes this matcher to an ostream. The function should print
+ // a verb phrase that describes the property a value matching this
+ // matcher should have. The subject of the verb phrase is the value
+ // being matched. For example, the DescribeTo() method of the Gt(7)
+ // matcher prints "is greater than 7".
+ virtual void DescribeTo(::std::ostream* os) const = 0;
+
+ // Describes the negation of this matcher to an ostream. For
+ // example, if the description of this matcher is "is greater than
+ // 7", the negated description could be "is not greater than 7".
+ // You are not required to override this when implementing
+ // MatcherInterface, but it is highly advised so that your matcher
+ // can produce good error messages.
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ *os << "not (";
+ DescribeTo(os);
+ *os << ")";
+ }
+};
+
+// The implementation of a matcher.
+template <typename T>
+class MatcherInterface : public MatcherDescriberInterface {
+ public:
+ // Returns true iff the matcher matches x; also explains the match
+ // result to 'listener' if necessary (see the next paragraph), in
+ // the form of a non-restrictive relative clause ("which ...",
+ // "whose ...", etc) that describes x. For example, the
+ // MatchAndExplain() method of the Pointee(...) matcher should
+ // generate an explanation like "which points to ...".
+ //
+ // Implementations of MatchAndExplain() should add an explanation of
+ // the match result *if and only if* they can provide additional
+ // information that's not already present (or not obvious) in the
+ // print-out of x and the matcher's description. Whether the match
+ // succeeds is not a factor in deciding whether an explanation is
+ // needed, as sometimes the caller needs to print a failure message
+ // when the match succeeds (e.g. when the matcher is used inside
+ // Not()).
+ //
+ // For example, a "has at least 10 elements" matcher should explain
+ // what the actual element count is, regardless of the match result,
+ // as it is useful information to the reader; on the other hand, an
+ // "is empty" matcher probably only needs to explain what the actual
+ // size is when the match fails, as it's redundant to say that the
+ // size is 0 when the value is already known to be empty.
+ //
+ // You should override this method when defining a new matcher.
+ //
+ // It's the responsibility of the caller (Google Mock) to guarantee
+ // that 'listener' is not NULL. This helps to simplify a matcher's
+ // implementation when it doesn't care about the performance, as it
+ // can talk to 'listener' without checking its validity first.
+ // However, in order to implement dummy listeners efficiently,
+ // listener->stream() may be NULL.
+ virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0;
+
+ // Inherits these methods from MatcherDescriberInterface:
+ // virtual void DescribeTo(::std::ostream* os) const = 0;
+ // virtual void DescribeNegationTo(::std::ostream* os) const;
+};
+
+// A match result listener that stores the explanation in a string.
+class StringMatchResultListener : public MatchResultListener {
+ public:
+ StringMatchResultListener() : MatchResultListener(&ss_) {}
+
+ // Returns the explanation accumulated so far.
+ internal::string str() const { return ss_.str(); }
+
+ // Clears the explanation accumulated so far.
+ void Clear() { ss_.str(""); }
+
+ private:
+ ::std::stringstream ss_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(StringMatchResultListener);
+};
+
+namespace internal {
+
+struct AnyEq {
+ template <typename A, typename B>
+ bool operator()(const A& a, const B& b) const { return a == b; }
+};
+struct AnyNe {
+ template <typename A, typename B>
+ bool operator()(const A& a, const B& b) const { return a != b; }
+};
+struct AnyLt {
+ template <typename A, typename B>
+ bool operator()(const A& a, const B& b) const { return a < b; }
+};
+struct AnyGt {
+ template <typename A, typename B>
+ bool operator()(const A& a, const B& b) const { return a > b; }
+};
+struct AnyLe {
+ template <typename A, typename B>
+ bool operator()(const A& a, const B& b) const { return a <= b; }
+};
+struct AnyGe {
+ template <typename A, typename B>
+ bool operator()(const A& a, const B& b) const { return a >= b; }
+};
+
+// A match result listener that ignores the explanation.
+class DummyMatchResultListener : public MatchResultListener {
+ public:
+ DummyMatchResultListener() : MatchResultListener(NULL) {}
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(DummyMatchResultListener);
+};
+
+// A match result listener that forwards the explanation to a given
+// ostream. The difference between this and MatchResultListener is
+// that the former is concrete.
+class StreamMatchResultListener : public MatchResultListener {
+ public:
+ explicit StreamMatchResultListener(::std::ostream* os)
+ : MatchResultListener(os) {}
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamMatchResultListener);
+};
+
+// An internal class for implementing Matcher<T>, which will derive
+// from it. We put functionalities common to all Matcher<T>
+// specializations here to avoid code duplication.
+template <typename T>
+class MatcherBase {
+ public:
+ // Returns true iff the matcher matches x; also explains the match
+ // result to 'listener'.
+ bool MatchAndExplain(T x, MatchResultListener* listener) const {
+ return impl_->MatchAndExplain(x, listener);
+ }
+
+ // Returns true iff this matcher matches x.
+ bool Matches(T x) const {
+ DummyMatchResultListener dummy;
+ return MatchAndExplain(x, &dummy);
+ }
+
+ // Describes this matcher to an ostream.
+ void DescribeTo(::std::ostream* os) const { impl_->DescribeTo(os); }
+
+ // Describes the negation of this matcher to an ostream.
+ void DescribeNegationTo(::std::ostream* os) const {
+ impl_->DescribeNegationTo(os);
+ }
+
+ // Explains why x matches, or doesn't match, the matcher.
+ void ExplainMatchResultTo(T x, ::std::ostream* os) const {
+ StreamMatchResultListener listener(os);
+ MatchAndExplain(x, &listener);
+ }
+
+ // Returns the describer for this matcher object; retains ownership
+ // of the describer, which is only guaranteed to be alive when
+ // this matcher object is alive.
+ const MatcherDescriberInterface* GetDescriber() const {
+ return impl_.get();
+ }
+
+ protected:
+ MatcherBase() {}
+
+ // Constructs a matcher from its implementation.
+ explicit MatcherBase(const MatcherInterface<T>* impl)
+ : impl_(impl) {}
+
+ virtual ~MatcherBase() {}
+
+ private:
+ // shared_ptr (util/gtl/shared_ptr.h) and linked_ptr have similar
+ // interfaces. The former dynamically allocates a chunk of memory
+ // to hold the reference count, while the latter tracks all
+ // references using a circular linked list without allocating
+ // memory. It has been observed that linked_ptr performs better in
+ // typical scenarios. However, shared_ptr can out-perform
+ // linked_ptr when there are many more uses of the copy constructor
+ // than the default constructor.
+ //
+ // If performance becomes a problem, we should see if using
+ // shared_ptr helps.
+ ::testing::internal::linked_ptr<const MatcherInterface<T> > impl_;
+};
+
+} // namespace internal
+
+// A Matcher<T> is a copyable and IMMUTABLE (except by assignment)
+// object that can check whether a value of type T matches. The
+// implementation of Matcher<T> is just a linked_ptr to const
+// MatcherInterface<T>, so copying is fairly cheap. Don't inherit
+// from Matcher!
+template <typename T>
+class Matcher : public internal::MatcherBase<T> {
+ public:
+ // Constructs a null matcher. Needed for storing Matcher objects in STL
+ // containers. A default-constructed matcher is not yet initialized. You
+ // cannot use it until a valid value has been assigned to it.
+ explicit Matcher() {} // NOLINT
+
+ // Constructs a matcher from its implementation.
+ explicit Matcher(const MatcherInterface<T>* impl)
+ : internal::MatcherBase<T>(impl) {}
+
+ // Implicit constructor here allows people to write
+ // EXPECT_CALL(foo, Bar(5)) instead of EXPECT_CALL(foo, Bar(Eq(5))) sometimes
+ Matcher(T value); // NOLINT
+};
+
+// The following two specializations allow the user to write str
+// instead of Eq(str) and "foo" instead of Eq("foo") when a string
+// matcher is expected.
+template <>
+class GTEST_API_ Matcher<const internal::string&>
+ : public internal::MatcherBase<const internal::string&> {
+ public:
+ Matcher() {}
+
+ explicit Matcher(const MatcherInterface<const internal::string&>* impl)
+ : internal::MatcherBase<const internal::string&>(impl) {}
+
+ // Allows the user to write str instead of Eq(str) sometimes, where
+ // str is a string object.
+ Matcher(const internal::string& s); // NOLINT
+
+ // Allows the user to write "foo" instead of Eq("foo") sometimes.
+ Matcher(const char* s); // NOLINT
+};
+
+template <>
+class GTEST_API_ Matcher<internal::string>
+ : public internal::MatcherBase<internal::string> {
+ public:
+ Matcher() {}
+
+ explicit Matcher(const MatcherInterface<internal::string>* impl)
+ : internal::MatcherBase<internal::string>(impl) {}
+
+ // Allows the user to write str instead of Eq(str) sometimes, where
+ // str is a string object.
+ Matcher(const internal::string& s); // NOLINT
+
+ // Allows the user to write "foo" instead of Eq("foo") sometimes.
+ Matcher(const char* s); // NOLINT
+};
+
+#if GTEST_HAS_STRING_PIECE_
+// The following two specializations allow the user to write str
+// instead of Eq(str) and "foo" instead of Eq("foo") when a StringPiece
+// matcher is expected.
+template <>
+class GTEST_API_ Matcher<const StringPiece&>
+ : public internal::MatcherBase<const StringPiece&> {
+ public:
+ Matcher() {}
+
+ explicit Matcher(const MatcherInterface<const StringPiece&>* impl)
+ : internal::MatcherBase<const StringPiece&>(impl) {}
+
+ // Allows the user to write str instead of Eq(str) sometimes, where
+ // str is a string object.
+ Matcher(const internal::string& s); // NOLINT
+
+ // Allows the user to write "foo" instead of Eq("foo") sometimes.
+ Matcher(const char* s); // NOLINT
+
+ // Allows the user to pass StringPieces directly.
+ Matcher(StringPiece s); // NOLINT
+};
+
+template <>
+class GTEST_API_ Matcher<StringPiece>
+ : public internal::MatcherBase<StringPiece> {
+ public:
+ Matcher() {}
+
+ explicit Matcher(const MatcherInterface<StringPiece>* impl)
+ : internal::MatcherBase<StringPiece>(impl) {}
+
+ // Allows the user to write str instead of Eq(str) sometimes, where
+ // str is a string object.
+ Matcher(const internal::string& s); // NOLINT
+
+ // Allows the user to write "foo" instead of Eq("foo") sometimes.
+ Matcher(const char* s); // NOLINT
+
+ // Allows the user to pass StringPieces directly.
+ Matcher(StringPiece s); // NOLINT
+};
+#endif // GTEST_HAS_STRING_PIECE_
+
+// The PolymorphicMatcher class template makes it easy to implement a
+// polymorphic matcher (i.e. a matcher that can match values of more
+// than one type, e.g. Eq(n) and NotNull()).
+//
+// To define a polymorphic matcher, a user should provide an Impl
+// class that has a DescribeTo() method and a DescribeNegationTo()
+// method, and define a member function (or member function template)
+//
+// bool MatchAndExplain(const Value& value,
+// MatchResultListener* listener) const;
+//
+// See the definition of NotNull() for a complete example.
+template <class Impl>
+class PolymorphicMatcher {
+ public:
+ explicit PolymorphicMatcher(const Impl& an_impl) : impl_(an_impl) {}
+
+ // Returns a mutable reference to the underlying matcher
+ // implementation object.
+ Impl& mutable_impl() { return impl_; }
+
+ // Returns an immutable reference to the underlying matcher
+ // implementation object.
+ const Impl& impl() const { return impl_; }
+
+ template <typename T>
+ operator Matcher<T>() const {
+ return Matcher<T>(new MonomorphicImpl<T>(impl_));
+ }
+
+ private:
+ template <typename T>
+ class MonomorphicImpl : public MatcherInterface<T> {
+ public:
+ explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {}
+
+ virtual void DescribeTo(::std::ostream* os) const {
+ impl_.DescribeTo(os);
+ }
+
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ impl_.DescribeNegationTo(os);
+ }
+
+ virtual bool MatchAndExplain(T x, MatchResultListener* listener) const {
+ return impl_.MatchAndExplain(x, listener);
+ }
+
+ private:
+ const Impl impl_;
+
+ GTEST_DISALLOW_ASSIGN_(MonomorphicImpl);
+ };
+
+ Impl impl_;
+
+ GTEST_DISALLOW_ASSIGN_(PolymorphicMatcher);
+};
+
+// Creates a matcher from its implementation. This is easier to use
+// than the Matcher<T> constructor as it doesn't require you to
+// explicitly write the template argument, e.g.
+//
+// MakeMatcher(foo);
+// vs
+// Matcher<const string&>(foo);
+template <typename T>
+inline Matcher<T> MakeMatcher(const MatcherInterface<T>* impl) {
+ return Matcher<T>(impl);
+}
+
+// Creates a polymorphic matcher from its implementation. This is
+// easier to use than the PolymorphicMatcher<Impl> constructor as it
+// doesn't require you to explicitly write the template argument, e.g.
+//
+// MakePolymorphicMatcher(foo);
+// vs
+// PolymorphicMatcher<TypeOfFoo>(foo);
+template <class Impl>
+inline PolymorphicMatcher<Impl> MakePolymorphicMatcher(const Impl& impl) {
+ return PolymorphicMatcher<Impl>(impl);
+}
+
+// Anything inside the 'internal' namespace IS INTERNAL IMPLEMENTATION
+// and MUST NOT BE USED IN USER CODE!!!
+namespace internal {
+
+// The MatcherCastImpl class template is a helper for implementing
+// MatcherCast(). We need this helper in order to partially
+// specialize the implementation of MatcherCast() (C++ allows
+// class/struct templates to be partially specialized, but not
+// function templates.).
+
+// This general version is used when MatcherCast()'s argument is a
+// polymorphic matcher (i.e. something that can be converted to a
+// Matcher but is not one yet; for example, Eq(value)) or a value (for
+// example, "hello").
+template <typename T, typename M>
+class MatcherCastImpl {
+ public:
+ static Matcher<T> Cast(const M& polymorphic_matcher_or_value) {
+ // M can be a polymorhic matcher, in which case we want to use
+ // its conversion operator to create Matcher<T>. Or it can be a value
+ // that should be passed to the Matcher<T>'s constructor.
+ //
+ // We can't call Matcher<T>(polymorphic_matcher_or_value) when M is a
+ // polymorphic matcher because it'll be ambiguous if T has an implicit
+ // constructor from M (this usually happens when T has an implicit
+ // constructor from any type).
+ //
+ // It won't work to unconditionally implict_cast
+ // polymorphic_matcher_or_value to Matcher<T> because it won't trigger
+ // a user-defined conversion from M to T if one exists (assuming M is
+ // a value).
+ return CastImpl(
+ polymorphic_matcher_or_value,
+ BooleanConstant<
+ internal::ImplicitlyConvertible<M, Matcher<T> >::value>());
+ }
+
+ private:
+ static Matcher<T> CastImpl(const M& value, BooleanConstant<false>) {
+ // M can't be implicitly converted to Matcher<T>, so M isn't a polymorphic
+ // matcher. It must be a value then. Use direct initialization to create
+ // a matcher.
+ return Matcher<T>(ImplicitCast_<T>(value));
+ }
+
+ static Matcher<T> CastImpl(const M& polymorphic_matcher_or_value,
+ BooleanConstant<true>) {
+ // M is implicitly convertible to Matcher<T>, which means that either
+ // M is a polymorhpic matcher or Matcher<T> has an implicit constructor
+ // from M. In both cases using the implicit conversion will produce a
+ // matcher.
+ //
+ // Even if T has an implicit constructor from M, it won't be called because
+ // creating Matcher<T> would require a chain of two user-defined conversions
+ // (first to create T from M and then to create Matcher<T> from T).
+ return polymorphic_matcher_or_value;
+ }
+};
+
+// This more specialized version is used when MatcherCast()'s argument
+// is already a Matcher. This only compiles when type T can be
+// statically converted to type U.
+template <typename T, typename U>
+class MatcherCastImpl<T, Matcher<U> > {
+ public:
+ static Matcher<T> Cast(const Matcher<U>& source_matcher) {
+ return Matcher<T>(new Impl(source_matcher));
+ }
+
+ private:
+ class Impl : public MatcherInterface<T> {
+ public:
+ explicit Impl(const Matcher<U>& source_matcher)
+ : source_matcher_(source_matcher) {}
+
+ // We delegate the matching logic to the source matcher.
+ virtual bool MatchAndExplain(T x, MatchResultListener* listener) const {
+ return source_matcher_.MatchAndExplain(static_cast<U>(x), listener);
+ }
+
+ virtual void DescribeTo(::std::ostream* os) const {
+ source_matcher_.DescribeTo(os);
+ }
+
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ source_matcher_.DescribeNegationTo(os);
+ }
+
+ private:
+ const Matcher<U> source_matcher_;
+
+ GTEST_DISALLOW_ASSIGN_(Impl);
+ };
+};
+
+// This even more specialized version is used for efficiently casting
+// a matcher to its own type.
+template <typename T>
+class MatcherCastImpl<T, Matcher<T> > {
+ public:
+ static Matcher<T> Cast(const Matcher<T>& matcher) { return matcher; }
+};
+
+} // namespace internal
+
+// In order to be safe and clear, casting between different matcher
+// types is done explicitly via MatcherCast<T>(m), which takes a
+// matcher m and returns a Matcher<T>. It compiles only when T can be
+// statically converted to the argument type of m.
+template <typename T, typename M>
+inline Matcher<T> MatcherCast(const M& matcher) {
+ return internal::MatcherCastImpl<T, M>::Cast(matcher);
+}
+
+// Implements SafeMatcherCast().
+//
+// We use an intermediate class to do the actual safe casting as Nokia's
+// Symbian compiler cannot decide between
+// template <T, M> ... (M) and
+// template <T, U> ... (const Matcher<U>&)
+// for function templates but can for member function templates.
+template <typename T>
+class SafeMatcherCastImpl {
+ public:
+ // This overload handles polymorphic matchers and values only since
+ // monomorphic matchers are handled by the next one.
+ template <typename M>
+ static inline Matcher<T> Cast(const M& polymorphic_matcher_or_value) {
+ return internal::MatcherCastImpl<T, M>::Cast(polymorphic_matcher_or_value);
+ }
+
+ // This overload handles monomorphic matchers.
+ //
+ // In general, if type T can be implicitly converted to type U, we can
+ // safely convert a Matcher<U> to a Matcher<T> (i.e. Matcher is
+ // contravariant): just keep a copy of the original Matcher<U>, convert the
+ // argument from type T to U, and then pass it to the underlying Matcher<U>.
+ // The only exception is when U is a reference and T is not, as the
+ // underlying Matcher<U> may be interested in the argument's address, which
+ // is not preserved in the conversion from T to U.
+ template <typename U>
+ static inline Matcher<T> Cast(const Matcher<U>& matcher) {
+ // Enforce that T can be implicitly converted to U.
+ GTEST_COMPILE_ASSERT_((internal::ImplicitlyConvertible<T, U>::value),
+ T_must_be_implicitly_convertible_to_U);
+ // Enforce that we are not converting a non-reference type T to a reference
+ // type U.
+ GTEST_COMPILE_ASSERT_(
+ internal::is_reference<T>::value || !internal::is_reference<U>::value,
+ cannot_convert_non_referentce_arg_to_reference);
+ // In case both T and U are arithmetic types, enforce that the
+ // conversion is not lossy.
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(T) RawT;
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(U) RawU;
+ const bool kTIsOther = GMOCK_KIND_OF_(RawT) == internal::kOther;
+ const bool kUIsOther = GMOCK_KIND_OF_(RawU) == internal::kOther;
+ GTEST_COMPILE_ASSERT_(
+ kTIsOther || kUIsOther ||
+ (internal::LosslessArithmeticConvertible<RawT, RawU>::value),
+ conversion_of_arithmetic_types_must_be_lossless);
+ return MatcherCast<T>(matcher);
+ }
+};
+
+template <typename T, typename M>
+inline Matcher<T> SafeMatcherCast(const M& polymorphic_matcher) {
+ return SafeMatcherCastImpl<T>::Cast(polymorphic_matcher);
+}
+
+// A<T>() returns a matcher that matches any value of type T.
+template <typename T>
+Matcher<T> A();
+
+// Anything inside the 'internal' namespace IS INTERNAL IMPLEMENTATION
+// and MUST NOT BE USED IN USER CODE!!!
+namespace internal {
+
+// If the explanation is not empty, prints it to the ostream.
+inline void PrintIfNotEmpty(const internal::string& explanation,
+ ::std::ostream* os) {
+ if (explanation != "" && os != NULL) {
+ *os << ", " << explanation;
+ }
+}
+
+// Returns true if the given type name is easy to read by a human.
+// This is used to decide whether printing the type of a value might
+// be helpful.
+inline bool IsReadableTypeName(const string& type_name) {
+ // We consider a type name readable if it's short or doesn't contain
+ // a template or function type.
+ return (type_name.length() <= 20 ||
+ type_name.find_first_of("<(") == string::npos);
+}
+
+// Matches the value against the given matcher, prints the value and explains
+// the match result to the listener. Returns the match result.
+// 'listener' must not be NULL.
+// Value cannot be passed by const reference, because some matchers take a
+// non-const argument.
+template <typename Value, typename T>
+bool MatchPrintAndExplain(Value& value, const Matcher<T>& matcher,
+ MatchResultListener* listener) {
+ if (!listener->IsInterested()) {
+ // If the listener is not interested, we do not need to construct the
+ // inner explanation.
+ return matcher.Matches(value);
+ }
+
+ StringMatchResultListener inner_listener;
+ const bool match = matcher.MatchAndExplain(value, &inner_listener);
+
+ UniversalPrint(value, listener->stream());
+#if GTEST_HAS_RTTI
+ const string& type_name = GetTypeName<Value>();
+ if (IsReadableTypeName(type_name))
+ *listener->stream() << " (of type " << type_name << ")";
+#endif
+ PrintIfNotEmpty(inner_listener.str(), listener->stream());
+
+ return match;
+}
+
+// An internal helper class for doing compile-time loop on a tuple's
+// fields.
+template <size_t N>
+class TuplePrefix {
+ public:
+ // TuplePrefix<N>::Matches(matcher_tuple, value_tuple) returns true
+ // iff the first N fields of matcher_tuple matches the first N
+ // fields of value_tuple, respectively.
+ template <typename MatcherTuple, typename ValueTuple>
+ static bool Matches(const MatcherTuple& matcher_tuple,
+ const ValueTuple& value_tuple) {
+ return TuplePrefix<N - 1>::Matches(matcher_tuple, value_tuple)
+ && get<N - 1>(matcher_tuple).Matches(get<N - 1>(value_tuple));
+ }
+
+ // TuplePrefix<N>::ExplainMatchFailuresTo(matchers, values, os)
+ // describes failures in matching the first N fields of matchers
+ // against the first N fields of values. If there is no failure,
+ // nothing will be streamed to os.
+ template <typename MatcherTuple, typename ValueTuple>
+ static void ExplainMatchFailuresTo(const MatcherTuple& matchers,
+ const ValueTuple& values,
+ ::std::ostream* os) {
+ // First, describes failures in the first N - 1 fields.
+ TuplePrefix<N - 1>::ExplainMatchFailuresTo(matchers, values, os);
+
+ // Then describes the failure (if any) in the (N - 1)-th (0-based)
+ // field.
+ typename tuple_element<N - 1, MatcherTuple>::type matcher =
+ get<N - 1>(matchers);
+ typedef typename tuple_element<N - 1, ValueTuple>::type Value;
+ Value value = get<N - 1>(values);
+ StringMatchResultListener listener;
+ if (!matcher.MatchAndExplain(value, &listener)) {
+ // TODO(wan): include in the message the name of the parameter
+ // as used in MOCK_METHOD*() when possible.
+ *os << " Expected arg #" << N - 1 << ": ";
+ get<N - 1>(matchers).DescribeTo(os);
+ *os << "\n Actual: ";
+ // We remove the reference in type Value to prevent the
+ // universal printer from printing the address of value, which
+ // isn't interesting to the user most of the time. The
+ // matcher's MatchAndExplain() method handles the case when
+ // the address is interesting.
+ internal::UniversalPrint(value, os);
+ PrintIfNotEmpty(listener.str(), os);
+ *os << "\n";
+ }
+ }
+};
+
+// The base case.
+template <>
+class TuplePrefix<0> {
+ public:
+ template <typename MatcherTuple, typename ValueTuple>
+ static bool Matches(const MatcherTuple& /* matcher_tuple */,
+ const ValueTuple& /* value_tuple */) {
+ return true;
+ }
+
+ template <typename MatcherTuple, typename ValueTuple>
+ static void ExplainMatchFailuresTo(const MatcherTuple& /* matchers */,
+ const ValueTuple& /* values */,
+ ::std::ostream* /* os */) {}
+};
+
+// TupleMatches(matcher_tuple, value_tuple) returns true iff all
+// matchers in matcher_tuple match the corresponding fields in
+// value_tuple. It is a compiler error if matcher_tuple and
+// value_tuple have different number of fields or incompatible field
+// types.
+template <typename MatcherTuple, typename ValueTuple>
+bool TupleMatches(const MatcherTuple& matcher_tuple,
+ const ValueTuple& value_tuple) {
+ // Makes sure that matcher_tuple and value_tuple have the same
+ // number of fields.
+ GTEST_COMPILE_ASSERT_(tuple_size<MatcherTuple>::value ==
+ tuple_size<ValueTuple>::value,
+ matcher_and_value_have_different_numbers_of_fields);
+ return TuplePrefix<tuple_size<ValueTuple>::value>::
+ Matches(matcher_tuple, value_tuple);
+}
+
+// Describes failures in matching matchers against values. If there
+// is no failure, nothing will be streamed to os.
+template <typename MatcherTuple, typename ValueTuple>
+void ExplainMatchFailureTupleTo(const MatcherTuple& matchers,
+ const ValueTuple& values,
+ ::std::ostream* os) {
+ TuplePrefix<tuple_size<MatcherTuple>::value>::ExplainMatchFailuresTo(
+ matchers, values, os);
+}
+
+// TransformTupleValues and its helper.
+//
+// TransformTupleValuesHelper hides the internal machinery that
+// TransformTupleValues uses to implement a tuple traversal.
+template <typename Tuple, typename Func, typename OutIter>
+class TransformTupleValuesHelper {
+ private:
+ typedef ::testing::tuple_size<Tuple> TupleSize;
+
+ public:
+ // For each member of tuple 't', taken in order, evaluates '*out++ = f(t)'.
+ // Returns the final value of 'out' in case the caller needs it.
+ static OutIter Run(Func f, const Tuple& t, OutIter out) {
+ return IterateOverTuple<Tuple, TupleSize::value>()(f, t, out);
+ }
+
+ private:
+ template <typename Tup, size_t kRemainingSize>
+ struct IterateOverTuple {
+ OutIter operator() (Func f, const Tup& t, OutIter out) const {
+ *out++ = f(::testing::get<TupleSize::value - kRemainingSize>(t));
+ return IterateOverTuple<Tup, kRemainingSize - 1>()(f, t, out);
+ }
+ };
+ template <typename Tup>
+ struct IterateOverTuple<Tup, 0> {
+ OutIter operator() (Func /* f */, const Tup& /* t */, OutIter out) const {
+ return out;
+ }
+ };
+};
+
+// Successively invokes 'f(element)' on each element of the tuple 't',
+// appending each result to the 'out' iterator. Returns the final value
+// of 'out'.
+template <typename Tuple, typename Func, typename OutIter>
+OutIter TransformTupleValues(Func f, const Tuple& t, OutIter out) {
+ return TransformTupleValuesHelper<Tuple, Func, OutIter>::Run(f, t, out);
+}
+
+// Implements A<T>().
+template <typename T>
+class AnyMatcherImpl : public MatcherInterface<T> {
+ public:
+ virtual bool MatchAndExplain(
+ T /* x */, MatchResultListener* /* listener */) const { return true; }
+ virtual void DescribeTo(::std::ostream* os) const { *os << "is anything"; }
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ // This is mostly for completeness' safe, as it's not very useful
+ // to write Not(A<bool>()). However we cannot completely rule out
+ // such a possibility, and it doesn't hurt to be prepared.
+ *os << "never matches";
+ }
+};
+
+// Implements _, a matcher that matches any value of any
+// type. This is a polymorphic matcher, so we need a template type
+// conversion operator to make it appearing as a Matcher<T> for any
+// type T.
+class AnythingMatcher {
+ public:
+ template <typename T>
+ operator Matcher<T>() const { return A<T>(); }
+};
+
+// Implements a matcher that compares a given value with a
+// pre-supplied value using one of the ==, <=, <, etc, operators. The
+// two values being compared don't have to have the same type.
+//
+// The matcher defined here is polymorphic (for example, Eq(5) can be
+// used to match an int, a short, a double, etc). Therefore we use
+// a template type conversion operator in the implementation.
+//
+// The following template definition assumes that the Rhs parameter is
+// a "bare" type (i.e. neither 'const T' nor 'T&').
+template <typename D, typename Rhs, typename Op>
+class ComparisonBase {
+ public:
+ explicit ComparisonBase(const Rhs& rhs) : rhs_(rhs) {}
+ template <typename Lhs>
+ operator Matcher<Lhs>() const {
+ return MakeMatcher(new Impl<Lhs>(rhs_));
+ }
+
+ private:
+ template <typename Lhs>
+ class Impl : public MatcherInterface<Lhs> {
+ public:
+ explicit Impl(const Rhs& rhs) : rhs_(rhs) {}
+ virtual bool MatchAndExplain(
+ Lhs lhs, MatchResultListener* /* listener */) const {
+ return Op()(lhs, rhs_);
+ }
+ virtual void DescribeTo(::std::ostream* os) const {
+ *os << D::Desc() << " ";
+ UniversalPrint(rhs_, os);
+ }
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ *os << D::NegatedDesc() << " ";
+ UniversalPrint(rhs_, os);
+ }
+ private:
+ Rhs rhs_;
+ GTEST_DISALLOW_ASSIGN_(Impl);
+ };
+ Rhs rhs_;
+ GTEST_DISALLOW_ASSIGN_(ComparisonBase);
+};
+
+template <typename Rhs>
+class EqMatcher : public ComparisonBase<EqMatcher<Rhs>, Rhs, AnyEq> {
+ public:
+ explicit EqMatcher(const Rhs& rhs)
+ : ComparisonBase<EqMatcher<Rhs>, Rhs, AnyEq>(rhs) { }
+ static const char* Desc() { return "is equal to"; }
+ static const char* NegatedDesc() { return "isn't equal to"; }
+};
+template <typename Rhs>
+class NeMatcher : public ComparisonBase<NeMatcher<Rhs>, Rhs, AnyNe> {
+ public:
+ explicit NeMatcher(const Rhs& rhs)
+ : ComparisonBase<NeMatcher<Rhs>, Rhs, AnyNe>(rhs) { }
+ static const char* Desc() { return "isn't equal to"; }
+ static const char* NegatedDesc() { return "is equal to"; }
+};
+template <typename Rhs>
+class LtMatcher : public ComparisonBase<LtMatcher<Rhs>, Rhs, AnyLt> {
+ public:
+ explicit LtMatcher(const Rhs& rhs)
+ : ComparisonBase<LtMatcher<Rhs>, Rhs, AnyLt>(rhs) { }
+ static const char* Desc() { return "is <"; }
+ static const char* NegatedDesc() { return "isn't <"; }
+};
+template <typename Rhs>
+class GtMatcher : public ComparisonBase<GtMatcher<Rhs>, Rhs, AnyGt> {
+ public:
+ explicit GtMatcher(const Rhs& rhs)
+ : ComparisonBase<GtMatcher<Rhs>, Rhs, AnyGt>(rhs) { }
+ static const char* Desc() { return "is >"; }
+ static const char* NegatedDesc() { return "isn't >"; }
+};
+template <typename Rhs>
+class LeMatcher : public ComparisonBase<LeMatcher<Rhs>, Rhs, AnyLe> {
+ public:
+ explicit LeMatcher(const Rhs& rhs)
+ : ComparisonBase<LeMatcher<Rhs>, Rhs, AnyLe>(rhs) { }
+ static const char* Desc() { return "is <="; }
+ static const char* NegatedDesc() { return "isn't <="; }
+};
+template <typename Rhs>
+class GeMatcher : public ComparisonBase<GeMatcher<Rhs>, Rhs, AnyGe> {
+ public:
+ explicit GeMatcher(const Rhs& rhs)
+ : ComparisonBase<GeMatcher<Rhs>, Rhs, AnyGe>(rhs) { }
+ static const char* Desc() { return "is >="; }
+ static const char* NegatedDesc() { return "isn't >="; }
+};
+
+// Implements the polymorphic IsNull() matcher, which matches any raw or smart
+// pointer that is NULL.
+class IsNullMatcher {
+ public:
+ template <typename Pointer>
+ bool MatchAndExplain(const Pointer& p,
+ MatchResultListener* /* listener */) const {
+#if GTEST_LANG_CXX11
+ return p == nullptr;
+#else // GTEST_LANG_CXX11
+ return GetRawPointer(p) == NULL;
+#endif // GTEST_LANG_CXX11
+ }
+
+ void DescribeTo(::std::ostream* os) const { *os << "is NULL"; }
+ void DescribeNegationTo(::std::ostream* os) const {
+ *os << "isn't NULL";
+ }
+};
+
+// Implements the polymorphic NotNull() matcher, which matches any raw or smart
+// pointer that is not NULL.
+class NotNullMatcher {
+ public:
+ template <typename Pointer>
+ bool MatchAndExplain(const Pointer& p,
+ MatchResultListener* /* listener */) const {
+#if GTEST_LANG_CXX11
+ return p != nullptr;
+#else // GTEST_LANG_CXX11
+ return GetRawPointer(p) != NULL;
+#endif // GTEST_LANG_CXX11
+ }
+
+ void DescribeTo(::std::ostream* os) const { *os << "isn't NULL"; }
+ void DescribeNegationTo(::std::ostream* os) const {
+ *os << "is NULL";
+ }
+};
+
+// Ref(variable) matches any argument that is a reference to
+// 'variable'. This matcher is polymorphic as it can match any
+// super type of the type of 'variable'.
+//
+// The RefMatcher template class implements Ref(variable). It can
+// only be instantiated with a reference type. This prevents a user
+// from mistakenly using Ref(x) to match a non-reference function
+// argument. For example, the following will righteously cause a
+// compiler error:
+//
+// int n;
+// Matcher<int> m1 = Ref(n); // This won't compile.
+// Matcher<int&> m2 = Ref(n); // This will compile.
+template <typename T>
+class RefMatcher;
+
+template <typename T>
+class RefMatcher<T&> {
+ // Google Mock is a generic framework and thus needs to support
+ // mocking any function types, including those that take non-const
+ // reference arguments. Therefore the template parameter T (and
+ // Super below) can be instantiated to either a const type or a
+ // non-const type.
+ public:
+ // RefMatcher() takes a T& instead of const T&, as we want the
+ // compiler to catch using Ref(const_value) as a matcher for a
+ // non-const reference.
+ explicit RefMatcher(T& x) : object_(x) {} // NOLINT
+
+ template <typename Super>
+ operator Matcher<Super&>() const {
+ // By passing object_ (type T&) to Impl(), which expects a Super&,
+ // we make sure that Super is a super type of T. In particular,
+ // this catches using Ref(const_value) as a matcher for a
+ // non-const reference, as you cannot implicitly convert a const
+ // reference to a non-const reference.
+ return MakeMatcher(new Impl<Super>(object_));
+ }
+
+ private:
+ template <typename Super>
+ class Impl : public MatcherInterface<Super&> {
+ public:
+ explicit Impl(Super& x) : object_(x) {} // NOLINT
+
+ // MatchAndExplain() takes a Super& (as opposed to const Super&)
+ // in order to match the interface MatcherInterface<Super&>.
+ virtual bool MatchAndExplain(
+ Super& x, MatchResultListener* listener) const {
+ *listener << "which is located @" << static_cast<const void*>(&x);
+ return &x == &object_;
+ }
+
+ virtual void DescribeTo(::std::ostream* os) const {
+ *os << "references the variable ";
+ UniversalPrinter<Super&>::Print(object_, os);
+ }
+
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ *os << "does not reference the variable ";
+ UniversalPrinter<Super&>::Print(object_, os);
+ }
+
+ private:
+ const Super& object_;
+
+ GTEST_DISALLOW_ASSIGN_(Impl);
+ };
+
+ T& object_;
+
+ GTEST_DISALLOW_ASSIGN_(RefMatcher);
+};
+
+// Polymorphic helper functions for narrow and wide string matchers.
+inline bool CaseInsensitiveCStringEquals(const char* lhs, const char* rhs) {
+ return String::CaseInsensitiveCStringEquals(lhs, rhs);
+}
+
+inline bool CaseInsensitiveCStringEquals(const wchar_t* lhs,
+ const wchar_t* rhs) {
+ return String::CaseInsensitiveWideCStringEquals(lhs, rhs);
+}
+
+// String comparison for narrow or wide strings that can have embedded NUL
+// characters.
+template <typename StringType>
+bool CaseInsensitiveStringEquals(const StringType& s1,
+ const StringType& s2) {
+ // Are the heads equal?
+ if (!CaseInsensitiveCStringEquals(s1.c_str(), s2.c_str())) {
+ return false;
+ }
+
+ // Skip the equal heads.
+ const typename StringType::value_type nul = 0;
+ const size_t i1 = s1.find(nul), i2 = s2.find(nul);
+
+ // Are we at the end of either s1 or s2?
+ if (i1 == StringType::npos || i2 == StringType::npos) {
+ return i1 == i2;
+ }
+
+ // Are the tails equal?
+ return CaseInsensitiveStringEquals(s1.substr(i1 + 1), s2.substr(i2 + 1));
+}
+
+// String matchers.
+
+// Implements equality-based string matchers like StrEq, StrCaseNe, and etc.
+template <typename StringType>
+class StrEqualityMatcher {
+ public:
+ StrEqualityMatcher(const StringType& str, bool expect_eq,
+ bool case_sensitive)
+ : string_(str), expect_eq_(expect_eq), case_sensitive_(case_sensitive) {}
+
+ // Accepts pointer types, particularly:
+ // const char*
+ // char*
+ // const wchar_t*
+ // wchar_t*
+ template <typename CharType>
+ bool MatchAndExplain(CharType* s, MatchResultListener* listener) const {
+ if (s == NULL) {
+ return !expect_eq_;
+ }
+ return MatchAndExplain(StringType(s), listener);
+ }
+
+ // Matches anything that can convert to StringType.
+ //
+ // This is a template, not just a plain function with const StringType&,
+ // because StringPiece has some interfering non-explicit constructors.
+ template <typename MatcheeStringType>
+ bool MatchAndExplain(const MatcheeStringType& s,
+ MatchResultListener* /* listener */) const {
+ const StringType& s2(s);
+ const bool eq = case_sensitive_ ? s2 == string_ :
+ CaseInsensitiveStringEquals(s2, string_);
+ return expect_eq_ == eq;
+ }
+
+ void DescribeTo(::std::ostream* os) const {
+ DescribeToHelper(expect_eq_, os);
+ }
+
+ void DescribeNegationTo(::std::ostream* os) const {
+ DescribeToHelper(!expect_eq_, os);
+ }
+
+ private:
+ void DescribeToHelper(bool expect_eq, ::std::ostream* os) const {
+ *os << (expect_eq ? "is " : "isn't ");
+ *os << "equal to ";
+ if (!case_sensitive_) {
+ *os << "(ignoring case) ";
+ }
+ UniversalPrint(string_, os);
+ }
+
+ const StringType string_;
+ const bool expect_eq_;
+ const bool case_sensitive_;
+
+ GTEST_DISALLOW_ASSIGN_(StrEqualityMatcher);
+};
+
+// Implements the polymorphic HasSubstr(substring) matcher, which
+// can be used as a Matcher<T> as long as T can be converted to a
+// string.
+template <typename StringType>
+class HasSubstrMatcher {
+ public:
+ explicit HasSubstrMatcher(const StringType& substring)
+ : substring_(substring) {}
+
+ // Accepts pointer types, particularly:
+ // const char*
+ // char*
+ // const wchar_t*
+ // wchar_t*
+ template <typename CharType>
+ bool MatchAndExplain(CharType* s, MatchResultListener* listener) const {
+ return s != NULL && MatchAndExplain(StringType(s), listener);
+ }
+
+ // Matches anything that can convert to StringType.
+ //
+ // This is a template, not just a plain function with const StringType&,
+ // because StringPiece has some interfering non-explicit constructors.
+ template <typename MatcheeStringType>
+ bool MatchAndExplain(const MatcheeStringType& s,
+ MatchResultListener* /* listener */) const {
+ const StringType& s2(s);
+ return s2.find(substring_) != StringType::npos;
+ }
+
+ // Describes what this matcher matches.
+ void DescribeTo(::std::ostream* os) const {
+ *os << "has substring ";
+ UniversalPrint(substring_, os);
+ }
+
+ void DescribeNegationTo(::std::ostream* os) const {
+ *os << "has no substring ";
+ UniversalPrint(substring_, os);
+ }
+
+ private:
+ const StringType substring_;
+
+ GTEST_DISALLOW_ASSIGN_(HasSubstrMatcher);
+};
+
+// Implements the polymorphic StartsWith(substring) matcher, which
+// can be used as a Matcher<T> as long as T can be converted to a
+// string.
+template <typename StringType>
+class StartsWithMatcher {
+ public:
+ explicit StartsWithMatcher(const StringType& prefix) : prefix_(prefix) {
+ }
+
+ // Accepts pointer types, particularly:
+ // const char*
+ // char*
+ // const wchar_t*
+ // wchar_t*
+ template <typename CharType>
+ bool MatchAndExplain(CharType* s, MatchResultListener* listener) const {
+ return s != NULL && MatchAndExplain(StringType(s), listener);
+ }
+
+ // Matches anything that can convert to StringType.
+ //
+ // This is a template, not just a plain function with const StringType&,
+ // because StringPiece has some interfering non-explicit constructors.
+ template <typename MatcheeStringType>
+ bool MatchAndExplain(const MatcheeStringType& s,
+ MatchResultListener* /* listener */) const {
+ const StringType& s2(s);
+ return s2.length() >= prefix_.length() &&
+ s2.substr(0, prefix_.length()) == prefix_;
+ }
+
+ void DescribeTo(::std::ostream* os) const {
+ *os << "starts with ";
+ UniversalPrint(prefix_, os);
+ }
+
+ void DescribeNegationTo(::std::ostream* os) const {
+ *os << "doesn't start with ";
+ UniversalPrint(prefix_, os);
+ }
+
+ private:
+ const StringType prefix_;
+
+ GTEST_DISALLOW_ASSIGN_(StartsWithMatcher);
+};
+
+// Implements the polymorphic EndsWith(substring) matcher, which
+// can be used as a Matcher<T> as long as T can be converted to a
+// string.
+template <typename StringType>
+class EndsWithMatcher {
+ public:
+ explicit EndsWithMatcher(const StringType& suffix) : suffix_(suffix) {}
+
+ // Accepts pointer types, particularly:
+ // const char*
+ // char*
+ // const wchar_t*
+ // wchar_t*
+ template <typename CharType>
+ bool MatchAndExplain(CharType* s, MatchResultListener* listener) const {
+ return s != NULL && MatchAndExplain(StringType(s), listener);
+ }
+
+ // Matches anything that can convert to StringType.
+ //
+ // This is a template, not just a plain function with const StringType&,
+ // because StringPiece has some interfering non-explicit constructors.
+ template <typename MatcheeStringType>
+ bool MatchAndExplain(const MatcheeStringType& s,
+ MatchResultListener* /* listener */) const {
+ const StringType& s2(s);
+ return s2.length() >= suffix_.length() &&
+ s2.substr(s2.length() - suffix_.length()) == suffix_;
+ }
+
+ void DescribeTo(::std::ostream* os) const {
+ *os << "ends with ";
+ UniversalPrint(suffix_, os);
+ }
+
+ void DescribeNegationTo(::std::ostream* os) const {
+ *os << "doesn't end with ";
+ UniversalPrint(suffix_, os);
+ }
+
+ private:
+ const StringType suffix_;
+
+ GTEST_DISALLOW_ASSIGN_(EndsWithMatcher);
+};
+
+// Implements polymorphic matchers MatchesRegex(regex) and
+// ContainsRegex(regex), which can be used as a Matcher<T> as long as
+// T can be converted to a string.
+class MatchesRegexMatcher {
+ public:
+ MatchesRegexMatcher(const RE* regex, bool full_match)
+ : regex_(regex), full_match_(full_match) {}
+
+ // Accepts pointer types, particularly:
+ // const char*
+ // char*
+ // const wchar_t*
+ // wchar_t*
+ template <typename CharType>
+ bool MatchAndExplain(CharType* s, MatchResultListener* listener) const {
+ return s != NULL && MatchAndExplain(internal::string(s), listener);
+ }
+
+ // Matches anything that can convert to internal::string.
+ //
+ // This is a template, not just a plain function with const internal::string&,
+ // because StringPiece has some interfering non-explicit constructors.
+ template <class MatcheeStringType>
+ bool MatchAndExplain(const MatcheeStringType& s,
+ MatchResultListener* /* listener */) const {
+ const internal::string& s2(s);
+ return full_match_ ? RE::FullMatch(s2, *regex_) :
+ RE::PartialMatch(s2, *regex_);
+ }
+
+ void DescribeTo(::std::ostream* os) const {
+ *os << (full_match_ ? "matches" : "contains")
+ << " regular expression ";
+ UniversalPrinter<internal::string>::Print(regex_->pattern(), os);
+ }
+
+ void DescribeNegationTo(::std::ostream* os) const {
+ *os << "doesn't " << (full_match_ ? "match" : "contain")
+ << " regular expression ";
+ UniversalPrinter<internal::string>::Print(regex_->pattern(), os);
+ }
+
+ private:
+ const internal::linked_ptr<const RE> regex_;
+ const bool full_match_;
+
+ GTEST_DISALLOW_ASSIGN_(MatchesRegexMatcher);
+};
+
+// Implements a matcher that compares the two fields of a 2-tuple
+// using one of the ==, <=, <, etc, operators. The two fields being
+// compared don't have to have the same type.
+//
+// The matcher defined here is polymorphic (for example, Eq() can be
+// used to match a tuple<int, short>, a tuple<const long&, double>,
+// etc). Therefore we use a template type conversion operator in the
+// implementation.
+template <typename D, typename Op>
+class PairMatchBase {
+ public:
+ template <typename T1, typename T2>
+ operator Matcher< ::testing::tuple<T1, T2> >() const {
+ return MakeMatcher(new Impl< ::testing::tuple<T1, T2> >);
+ }
+ template <typename T1, typename T2>
+ operator Matcher<const ::testing::tuple<T1, T2>&>() const {
+ return MakeMatcher(new Impl<const ::testing::tuple<T1, T2>&>);
+ }
+
+ private:
+ static ::std::ostream& GetDesc(::std::ostream& os) { // NOLINT
+ return os << D::Desc();
+ }
+
+ template <typename Tuple>
+ class Impl : public MatcherInterface<Tuple> {
+ public:
+ virtual bool MatchAndExplain(
+ Tuple args,
+ MatchResultListener* /* listener */) const {
+ return Op()(::testing::get<0>(args), ::testing::get<1>(args));
+ }
+ virtual void DescribeTo(::std::ostream* os) const {
+ *os << "are " << GetDesc;
+ }
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ *os << "aren't " << GetDesc;
+ }
+ };
+};
+
+class Eq2Matcher : public PairMatchBase<Eq2Matcher, AnyEq> {
+ public:
+ static const char* Desc() { return "an equal pair"; }
+};
+class Ne2Matcher : public PairMatchBase<Ne2Matcher, AnyNe> {
+ public:
+ static const char* Desc() { return "an unequal pair"; }
+};
+class Lt2Matcher : public PairMatchBase<Lt2Matcher, AnyLt> {
+ public:
+ static const char* Desc() { return "a pair where the first < the second"; }
+};
+class Gt2Matcher : public PairMatchBase<Gt2Matcher, AnyGt> {
+ public:
+ static const char* Desc() { return "a pair where the first > the second"; }
+};
+class Le2Matcher : public PairMatchBase<Le2Matcher, AnyLe> {
+ public:
+ static const char* Desc() { return "a pair where the first <= the second"; }
+};
+class Ge2Matcher : public PairMatchBase<Ge2Matcher, AnyGe> {
+ public:
+ static const char* Desc() { return "a pair where the first >= the second"; }
+};
+
+// Implements the Not(...) matcher for a particular argument type T.
+// We do not nest it inside the NotMatcher class template, as that
+// will prevent different instantiations of NotMatcher from sharing
+// the same NotMatcherImpl<T> class.
+template <typename T>
+class NotMatcherImpl : public MatcherInterface<T> {
+ public:
+ explicit NotMatcherImpl(const Matcher<T>& matcher)
+ : matcher_(matcher) {}
+
+ virtual bool MatchAndExplain(T x, MatchResultListener* listener) const {
+ return !matcher_.MatchAndExplain(x, listener);
+ }
+
+ virtual void DescribeTo(::std::ostream* os) const {
+ matcher_.DescribeNegationTo(os);
+ }
+
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ matcher_.DescribeTo(os);
+ }
+
+ private:
+ const Matcher<T> matcher_;
+
+ GTEST_DISALLOW_ASSIGN_(NotMatcherImpl);
+};
+
+// Implements the Not(m) matcher, which matches a value that doesn't
+// match matcher m.
+template <typename InnerMatcher>
+class NotMatcher {
+ public:
+ explicit NotMatcher(InnerMatcher matcher) : matcher_(matcher) {}
+
+ // This template type conversion operator allows Not(m) to be used
+ // to match any type m can match.
+ template <typename T>
+ operator Matcher<T>() const {
+ return Matcher<T>(new NotMatcherImpl<T>(SafeMatcherCast<T>(matcher_)));
+ }
+
+ private:
+ InnerMatcher matcher_;
+
+ GTEST_DISALLOW_ASSIGN_(NotMatcher);
+};
+
+// Implements the AllOf(m1, m2) matcher for a particular argument type
+// T. We do not nest it inside the BothOfMatcher class template, as
+// that will prevent different instantiations of BothOfMatcher from
+// sharing the same BothOfMatcherImpl<T> class.
+template <typename T>
+class BothOfMatcherImpl : public MatcherInterface<T> {
+ public:
+ BothOfMatcherImpl(const Matcher<T>& matcher1, const Matcher<T>& matcher2)
+ : matcher1_(matcher1), matcher2_(matcher2) {}
+
+ virtual void DescribeTo(::std::ostream* os) const {
+ *os << "(";
+ matcher1_.DescribeTo(os);
+ *os << ") and (";
+ matcher2_.DescribeTo(os);
+ *os << ")";
+ }
+
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ *os << "(";
+ matcher1_.DescribeNegationTo(os);
+ *os << ") or (";
+ matcher2_.DescribeNegationTo(os);
+ *os << ")";
+ }
+
+ virtual bool MatchAndExplain(T x, MatchResultListener* listener) const {
+ // If either matcher1_ or matcher2_ doesn't match x, we only need
+ // to explain why one of them fails.
+ StringMatchResultListener listener1;
+ if (!matcher1_.MatchAndExplain(x, &listener1)) {
+ *listener << listener1.str();
+ return false;
+ }
+
+ StringMatchResultListener listener2;
+ if (!matcher2_.MatchAndExplain(x, &listener2)) {
+ *listener << listener2.str();
+ return false;
+ }
+
+ // Otherwise we need to explain why *both* of them match.
+ const internal::string s1 = listener1.str();
+ const internal::string s2 = listener2.str();
+
+ if (s1 == "") {
+ *listener << s2;
+ } else {
+ *listener << s1;
+ if (s2 != "") {
+ *listener << ", and " << s2;
+ }
+ }
+ return true;
+ }
+
+ private:
+ const Matcher<T> matcher1_;
+ const Matcher<T> matcher2_;
+
+ GTEST_DISALLOW_ASSIGN_(BothOfMatcherImpl);
+};
+
+#if GTEST_LANG_CXX11
+// MatcherList provides mechanisms for storing a variable number of matchers in
+// a list structure (ListType) and creating a combining matcher from such a
+// list.
+// The template is defined recursively using the following template paramters:
+// * kSize is the length of the MatcherList.
+// * Head is the type of the first matcher of the list.
+// * Tail denotes the types of the remaining matchers of the list.
+template <int kSize, typename Head, typename... Tail>
+struct MatcherList {
+ typedef MatcherList<kSize - 1, Tail...> MatcherListTail;
+ typedef ::std::pair<Head, typename MatcherListTail::ListType> ListType;
+
+ // BuildList stores variadic type values in a nested pair structure.
+ // Example:
+ // MatcherList<3, int, string, float>::BuildList(5, "foo", 2.0) will return
+ // the corresponding result of type pair<int, pair<string, float>>.
+ static ListType BuildList(const Head& matcher, const Tail&... tail) {
+ return ListType(matcher, MatcherListTail::BuildList(tail...));
+ }
+
+ // CreateMatcher<T> creates a Matcher<T> from a given list of matchers (built
+ // by BuildList()). CombiningMatcher<T> is used to combine the matchers of the
+ // list. CombiningMatcher<T> must implement MatcherInterface<T> and have a
+ // constructor taking two Matcher<T>s as input.
+ template <typename T, template <typename /* T */> class CombiningMatcher>
+ static Matcher<T> CreateMatcher(const ListType& matchers) {
+ return Matcher<T>(new CombiningMatcher<T>(
+ SafeMatcherCast<T>(matchers.first),
+ MatcherListTail::template CreateMatcher<T, CombiningMatcher>(
+ matchers.second)));
+ }
+};
+
+// The following defines the base case for the recursive definition of
+// MatcherList.
+template <typename Matcher1, typename Matcher2>
+struct MatcherList<2, Matcher1, Matcher2> {
+ typedef ::std::pair<Matcher1, Matcher2> ListType;
+
+ static ListType BuildList(const Matcher1& matcher1,
+ const Matcher2& matcher2) {
+ return ::std::pair<Matcher1, Matcher2>(matcher1, matcher2);
+ }
+
+ template <typename T, template <typename /* T */> class CombiningMatcher>
+ static Matcher<T> CreateMatcher(const ListType& matchers) {
+ return Matcher<T>(new CombiningMatcher<T>(
+ SafeMatcherCast<T>(matchers.first),
+ SafeMatcherCast<T>(matchers.second)));
+ }
+};
+
+// VariadicMatcher is used for the variadic implementation of
+// AllOf(m_1, m_2, ...) and AnyOf(m_1, m_2, ...).
+// CombiningMatcher<T> is used to recursively combine the provided matchers
+// (of type Args...).
+template <template <typename T> class CombiningMatcher, typename... Args>
+class VariadicMatcher {
+ public:
+ VariadicMatcher(const Args&... matchers) // NOLINT
+ : matchers_(MatcherListType::BuildList(matchers...)) {}
+
+ // This template type conversion operator allows an
+ // VariadicMatcher<Matcher1, Matcher2...> object to match any type that
+ // all of the provided matchers (Matcher1, Matcher2, ...) can match.
+ template <typename T>
+ operator Matcher<T>() const {
+ return MatcherListType::template CreateMatcher<T, CombiningMatcher>(
+ matchers_);
+ }
+
+ private:
+ typedef MatcherList<sizeof...(Args), Args...> MatcherListType;
+
+ const typename MatcherListType::ListType matchers_;
+
+ GTEST_DISALLOW_ASSIGN_(VariadicMatcher);
+};
+
+template <typename... Args>
+using AllOfMatcher = VariadicMatcher<BothOfMatcherImpl, Args...>;
+
+#endif // GTEST_LANG_CXX11
+
+// Used for implementing the AllOf(m_1, ..., m_n) matcher, which
+// matches a value that matches all of the matchers m_1, ..., and m_n.
+template <typename Matcher1, typename Matcher2>
+class BothOfMatcher {
+ public:
+ BothOfMatcher(Matcher1 matcher1, Matcher2 matcher2)
+ : matcher1_(matcher1), matcher2_(matcher2) {}
+
+ // This template type conversion operator allows a
+ // BothOfMatcher<Matcher1, Matcher2> object to match any type that
+ // both Matcher1 and Matcher2 can match.
+ template <typename T>
+ operator Matcher<T>() const {
+ return Matcher<T>(new BothOfMatcherImpl<T>(SafeMatcherCast<T>(matcher1_),
+ SafeMatcherCast<T>(matcher2_)));
+ }
+
+ private:
+ Matcher1 matcher1_;
+ Matcher2 matcher2_;
+
+ GTEST_DISALLOW_ASSIGN_(BothOfMatcher);
+};
+
+// Implements the AnyOf(m1, m2) matcher for a particular argument type
+// T. We do not nest it inside the AnyOfMatcher class template, as
+// that will prevent different instantiations of AnyOfMatcher from
+// sharing the same EitherOfMatcherImpl<T> class.
+template <typename T>
+class EitherOfMatcherImpl : public MatcherInterface<T> {
+ public:
+ EitherOfMatcherImpl(const Matcher<T>& matcher1, const Matcher<T>& matcher2)
+ : matcher1_(matcher1), matcher2_(matcher2) {}
+
+ virtual void DescribeTo(::std::ostream* os) const {
+ *os << "(";
+ matcher1_.DescribeTo(os);
+ *os << ") or (";
+ matcher2_.DescribeTo(os);
+ *os << ")";
+ }
+
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ *os << "(";
+ matcher1_.DescribeNegationTo(os);
+ *os << ") and (";
+ matcher2_.DescribeNegationTo(os);
+ *os << ")";
+ }
+
+ virtual bool MatchAndExplain(T x, MatchResultListener* listener) const {
+ // If either matcher1_ or matcher2_ matches x, we just need to
+ // explain why *one* of them matches.
+ StringMatchResultListener listener1;
+ if (matcher1_.MatchAndExplain(x, &listener1)) {
+ *listener << listener1.str();
+ return true;
+ }
+
+ StringMatchResultListener listener2;
+ if (matcher2_.MatchAndExplain(x, &listener2)) {
+ *listener << listener2.str();
+ return true;
+ }
+
+ // Otherwise we need to explain why *both* of them fail.
+ const internal::string s1 = listener1.str();
+ const internal::string s2 = listener2.str();
+
+ if (s1 == "") {
+ *listener << s2;
+ } else {
+ *listener << s1;
+ if (s2 != "") {
+ *listener << ", and " << s2;
+ }
+ }
+ return false;
+ }
+
+ private:
+ const Matcher<T> matcher1_;
+ const Matcher<T> matcher2_;
+
+ GTEST_DISALLOW_ASSIGN_(EitherOfMatcherImpl);
+};
+
+#if GTEST_LANG_CXX11
+// AnyOfMatcher is used for the variadic implementation of AnyOf(m_1, m_2, ...).
+template <typename... Args>
+using AnyOfMatcher = VariadicMatcher<EitherOfMatcherImpl, Args...>;
+
+#endif // GTEST_LANG_CXX11
+
+// Used for implementing the AnyOf(m_1, ..., m_n) matcher, which
+// matches a value that matches at least one of the matchers m_1, ...,
+// and m_n.
+template <typename Matcher1, typename Matcher2>
+class EitherOfMatcher {
+ public:
+ EitherOfMatcher(Matcher1 matcher1, Matcher2 matcher2)
+ : matcher1_(matcher1), matcher2_(matcher2) {}
+
+ // This template type conversion operator allows a
+ // EitherOfMatcher<Matcher1, Matcher2> object to match any type that
+ // both Matcher1 and Matcher2 can match.
+ template <typename T>
+ operator Matcher<T>() const {
+ return Matcher<T>(new EitherOfMatcherImpl<T>(
+ SafeMatcherCast<T>(matcher1_), SafeMatcherCast<T>(matcher2_)));
+ }
+
+ private:
+ Matcher1 matcher1_;
+ Matcher2 matcher2_;
+
+ GTEST_DISALLOW_ASSIGN_(EitherOfMatcher);
+};
+
+// Used for implementing Truly(pred), which turns a predicate into a
+// matcher.
+template <typename Predicate>
+class TrulyMatcher {
+ public:
+ explicit TrulyMatcher(Predicate pred) : predicate_(pred) {}
+
+ // This method template allows Truly(pred) to be used as a matcher
+ // for type T where T is the argument type of predicate 'pred'. The
+ // argument is passed by reference as the predicate may be
+ // interested in the address of the argument.
+ template <typename T>
+ bool MatchAndExplain(T& x, // NOLINT
+ MatchResultListener* /* listener */) const {
+ // Without the if-statement, MSVC sometimes warns about converting
+ // a value to bool (warning 4800).
+ //
+ // We cannot write 'return !!predicate_(x);' as that doesn't work
+ // when predicate_(x) returns a class convertible to bool but
+ // having no operator!().
+ if (predicate_(x))
+ return true;
+ return false;
+ }
+
+ void DescribeTo(::std::ostream* os) const {
+ *os << "satisfies the given predicate";
+ }
+
+ void DescribeNegationTo(::std::ostream* os) const {
+ *os << "doesn't satisfy the given predicate";
+ }
+
+ private:
+ Predicate predicate_;
+
+ GTEST_DISALLOW_ASSIGN_(TrulyMatcher);
+};
+
+// Used for implementing Matches(matcher), which turns a matcher into
+// a predicate.
+template <typename M>
+class MatcherAsPredicate {
+ public:
+ explicit MatcherAsPredicate(M matcher) : matcher_(matcher) {}
+
+ // This template operator() allows Matches(m) to be used as a
+ // predicate on type T where m is a matcher on type T.
+ //
+ // The argument x is passed by reference instead of by value, as
+ // some matcher may be interested in its address (e.g. as in
+ // Matches(Ref(n))(x)).
+ template <typename T>
+ bool operator()(const T& x) const {
+ // We let matcher_ commit to a particular type here instead of
+ // when the MatcherAsPredicate object was constructed. This
+ // allows us to write Matches(m) where m is a polymorphic matcher
+ // (e.g. Eq(5)).
+ //
+ // If we write Matcher<T>(matcher_).Matches(x) here, it won't
+ // compile when matcher_ has type Matcher<const T&>; if we write
+ // Matcher<const T&>(matcher_).Matches(x) here, it won't compile
+ // when matcher_ has type Matcher<T>; if we just write
+ // matcher_.Matches(x), it won't compile when matcher_ is
+ // polymorphic, e.g. Eq(5).
+ //
+ // MatcherCast<const T&>() is necessary for making the code work
+ // in all of the above situations.
+ return MatcherCast<const T&>(matcher_).Matches(x);
+ }
+
+ private:
+ M matcher_;
+
+ GTEST_DISALLOW_ASSIGN_(MatcherAsPredicate);
+};
+
+// For implementing ASSERT_THAT() and EXPECT_THAT(). The template
+// argument M must be a type that can be converted to a matcher.
+template <typename M>
+class PredicateFormatterFromMatcher {
+ public:
+ explicit PredicateFormatterFromMatcher(M m) : matcher_(internal::move(m)) {}
+
+ // This template () operator allows a PredicateFormatterFromMatcher
+ // object to act as a predicate-formatter suitable for using with
+ // Google Test's EXPECT_PRED_FORMAT1() macro.
+ template <typename T>
+ AssertionResult operator()(const char* value_text, const T& x) const {
+ // We convert matcher_ to a Matcher<const T&> *now* instead of
+ // when the PredicateFormatterFromMatcher object was constructed,
+ // as matcher_ may be polymorphic (e.g. NotNull()) and we won't
+ // know which type to instantiate it to until we actually see the
+ // type of x here.
+ //
+ // We write SafeMatcherCast<const T&>(matcher_) instead of
+ // Matcher<const T&>(matcher_), as the latter won't compile when
+ // matcher_ has type Matcher<T> (e.g. An<int>()).
+ // We don't write MatcherCast<const T&> either, as that allows
+ // potentially unsafe downcasting of the matcher argument.
+ const Matcher<const T&> matcher = SafeMatcherCast<const T&>(matcher_);
+ StringMatchResultListener listener;
+ if (MatchPrintAndExplain(x, matcher, &listener))
+ return AssertionSuccess();
+
+ ::std::stringstream ss;
+ ss << "Value of: " << value_text << "\n"
+ << "Expected: ";
+ matcher.DescribeTo(&ss);
+ ss << "\n Actual: " << listener.str();
+ return AssertionFailure() << ss.str();
+ }
+
+ private:
+ const M matcher_;
+
+ GTEST_DISALLOW_ASSIGN_(PredicateFormatterFromMatcher);
+};
+
+// A helper function for converting a matcher to a predicate-formatter
+// without the user needing to explicitly write the type. This is
+// used for implementing ASSERT_THAT() and EXPECT_THAT().
+// Implementation detail: 'matcher' is received by-value to force decaying.
+template <typename M>
+inline PredicateFormatterFromMatcher<M>
+MakePredicateFormatterFromMatcher(M matcher) {
+ return PredicateFormatterFromMatcher<M>(internal::move(matcher));
+}
+
+// Implements the polymorphic floating point equality matcher, which matches
+// two float values using ULP-based approximation or, optionally, a
+// user-specified epsilon. The template is meant to be instantiated with
+// FloatType being either float or double.
+template <typename FloatType>
+class FloatingEqMatcher {
+ public:
+ // Constructor for FloatingEqMatcher.
+ // The matcher's input will be compared with expected. The matcher treats two
+ // NANs as equal if nan_eq_nan is true. Otherwise, under IEEE standards,
+ // equality comparisons between NANs will always return false. We specify a
+ // negative max_abs_error_ term to indicate that ULP-based approximation will
+ // be used for comparison.
+ FloatingEqMatcher(FloatType expected, bool nan_eq_nan) :
+ expected_(expected), nan_eq_nan_(nan_eq_nan), max_abs_error_(-1) {
+ }
+
+ // Constructor that supports a user-specified max_abs_error that will be used
+ // for comparison instead of ULP-based approximation. The max absolute
+ // should be non-negative.
+ FloatingEqMatcher(FloatType expected, bool nan_eq_nan,
+ FloatType max_abs_error)
+ : expected_(expected),
+ nan_eq_nan_(nan_eq_nan),
+ max_abs_error_(max_abs_error) {
+ GTEST_CHECK_(max_abs_error >= 0)
+ << ", where max_abs_error is" << max_abs_error;
+ }
+
+ // Implements floating point equality matcher as a Matcher<T>.
+ template <typename T>
+ class Impl : public MatcherInterface<T> {
+ public:
+ Impl(FloatType expected, bool nan_eq_nan, FloatType max_abs_error)
+ : expected_(expected),
+ nan_eq_nan_(nan_eq_nan),
+ max_abs_error_(max_abs_error) {}
+
+ virtual bool MatchAndExplain(T value,
+ MatchResultListener* listener) const {
+ const FloatingPoint<FloatType> actual(value), expected(expected_);
+
+ // Compares NaNs first, if nan_eq_nan_ is true.
+ if (actual.is_nan() || expected.is_nan()) {
+ if (actual.is_nan() && expected.is_nan()) {
+ return nan_eq_nan_;
+ }
+ // One is nan; the other is not nan.
+ return false;
+ }
+ if (HasMaxAbsError()) {
+ // We perform an equality check so that inf will match inf, regardless
+ // of error bounds. If the result of value - expected_ would result in
+ // overflow or if either value is inf, the default result is infinity,
+ // which should only match if max_abs_error_ is also infinity.
+ if (value == expected_) {
+ return true;
+ }
+
+ const FloatType diff = value - expected_;
+ if (fabs(diff) <= max_abs_error_) {
+ return true;
+ }
+
+ if (listener->IsInterested()) {
+ *listener << "which is " << diff << " from " << expected_;
+ }
+ return false;
+ } else {
+ return actual.AlmostEquals(expected);
+ }
+ }
+
+ virtual void DescribeTo(::std::ostream* os) const {
+ // os->precision() returns the previously set precision, which we
+ // store to restore the ostream to its original configuration
+ // after outputting.
+ const ::std::streamsize old_precision = os->precision(
+ ::std::numeric_limits<FloatType>::digits10 + 2);
+ if (FloatingPoint<FloatType>(expected_).is_nan()) {
+ if (nan_eq_nan_) {
+ *os << "is NaN";
+ } else {
+ *os << "never matches";
+ }
+ } else {
+ *os << "is approximately " << expected_;
+ if (HasMaxAbsError()) {
+ *os << " (absolute error <= " << max_abs_error_ << ")";
+ }
+ }
+ os->precision(old_precision);
+ }
+
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ // As before, get original precision.
+ const ::std::streamsize old_precision = os->precision(
+ ::std::numeric_limits<FloatType>::digits10 + 2);
+ if (FloatingPoint<FloatType>(expected_).is_nan()) {
+ if (nan_eq_nan_) {
+ *os << "isn't NaN";
+ } else {
+ *os << "is anything";
+ }
+ } else {
+ *os << "isn't approximately " << expected_;
+ if (HasMaxAbsError()) {
+ *os << " (absolute error > " << max_abs_error_ << ")";
+ }
+ }
+ // Restore original precision.
+ os->precision(old_precision);
+ }
+
+ private:
+ bool HasMaxAbsError() const {
+ return max_abs_error_ >= 0;
+ }
+
+ const FloatType expected_;
+ const bool nan_eq_nan_;
+ // max_abs_error will be used for value comparison when >= 0.
+ const FloatType max_abs_error_;
+
+ GTEST_DISALLOW_ASSIGN_(Impl);
+ };
+
+ // The following 3 type conversion operators allow FloatEq(expected) and
+ // NanSensitiveFloatEq(expected) to be used as a Matcher<float>, a
+ // Matcher<const float&>, or a Matcher<float&>, but nothing else.
+ // (While Google's C++ coding style doesn't allow arguments passed
+ // by non-const reference, we may see them in code not conforming to
+ // the style. Therefore Google Mock needs to support them.)
+ operator Matcher<FloatType>() const {
+ return MakeMatcher(
+ new Impl<FloatType>(expected_, nan_eq_nan_, max_abs_error_));
+ }
+
+ operator Matcher<const FloatType&>() const {
+ return MakeMatcher(
+ new Impl<const FloatType&>(expected_, nan_eq_nan_, max_abs_error_));
+ }
+
+ operator Matcher<FloatType&>() const {
+ return MakeMatcher(
+ new Impl<FloatType&>(expected_, nan_eq_nan_, max_abs_error_));
+ }
+
+ private:
+ const FloatType expected_;
+ const bool nan_eq_nan_;
+ // max_abs_error will be used for value comparison when >= 0.
+ const FloatType max_abs_error_;
+
+ GTEST_DISALLOW_ASSIGN_(FloatingEqMatcher);
+};
+
+// Implements the Pointee(m) matcher for matching a pointer whose
+// pointee matches matcher m. The pointer can be either raw or smart.
+template <typename InnerMatcher>
+class PointeeMatcher {
+ public:
+ explicit PointeeMatcher(const InnerMatcher& matcher) : matcher_(matcher) {}
+
+ // This type conversion operator template allows Pointee(m) to be
+ // used as a matcher for any pointer type whose pointee type is
+ // compatible with the inner matcher, where type Pointer can be
+ // either a raw pointer or a smart pointer.
+ //
+ // The reason we do this instead of relying on
+ // MakePolymorphicMatcher() is that the latter is not flexible
+ // enough for implementing the DescribeTo() method of Pointee().
+ template <typename Pointer>
+ operator Matcher<Pointer>() const {
+ return MakeMatcher(new Impl<Pointer>(matcher_));
+ }
+
+ private:
+ // The monomorphic implementation that works for a particular pointer type.
+ template <typename Pointer>
+ class Impl : public MatcherInterface<Pointer> {
+ public:
+ typedef typename PointeeOf<GTEST_REMOVE_CONST_( // NOLINT
+ GTEST_REMOVE_REFERENCE_(Pointer))>::type Pointee;
+
+ explicit Impl(const InnerMatcher& matcher)
+ : matcher_(MatcherCast<const Pointee&>(matcher)) {}
+
+ virtual void DescribeTo(::std::ostream* os) const {
+ *os << "points to a value that ";
+ matcher_.DescribeTo(os);
+ }
+
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ *os << "does not point to a value that ";
+ matcher_.DescribeTo(os);
+ }
+
+ virtual bool MatchAndExplain(Pointer pointer,
+ MatchResultListener* listener) const {
+ if (GetRawPointer(pointer) == NULL)
+ return false;
+
+ *listener << "which points to ";
+ return MatchPrintAndExplain(*pointer, matcher_, listener);
+ }
+
+ private:
+ const Matcher<const Pointee&> matcher_;
+
+ GTEST_DISALLOW_ASSIGN_(Impl);
+ };
+
+ const InnerMatcher matcher_;
+
+ GTEST_DISALLOW_ASSIGN_(PointeeMatcher);
+};
+
+// Implements the WhenDynamicCastTo<T>(m) matcher that matches a pointer or
+// reference that matches inner_matcher when dynamic_cast<T> is applied.
+// The result of dynamic_cast<To> is forwarded to the inner matcher.
+// If To is a pointer and the cast fails, the inner matcher will receive NULL.
+// If To is a reference and the cast fails, this matcher returns false
+// immediately.
+template <typename To>
+class WhenDynamicCastToMatcherBase {
+ public:
+ explicit WhenDynamicCastToMatcherBase(const Matcher<To>& matcher)
+ : matcher_(matcher) {}
+
+ void DescribeTo(::std::ostream* os) const {
+ GetCastTypeDescription(os);
+ matcher_.DescribeTo(os);
+ }
+
+ void DescribeNegationTo(::std::ostream* os) const {
+ GetCastTypeDescription(os);
+ matcher_.DescribeNegationTo(os);
+ }
+
+ protected:
+ const Matcher<To> matcher_;
+
+ static string GetToName() {
+#if GTEST_HAS_RTTI
+ return GetTypeName<To>();
+#else // GTEST_HAS_RTTI
+ return "the target type";
+#endif // GTEST_HAS_RTTI
+ }
+
+ private:
+ static void GetCastTypeDescription(::std::ostream* os) {
+ *os << "when dynamic_cast to " << GetToName() << ", ";
+ }
+
+ GTEST_DISALLOW_ASSIGN_(WhenDynamicCastToMatcherBase);
+};
+
+// Primary template.
+// To is a pointer. Cast and forward the result.
+template <typename To>
+class WhenDynamicCastToMatcher : public WhenDynamicCastToMatcherBase<To> {
+ public:
+ explicit WhenDynamicCastToMatcher(const Matcher<To>& matcher)
+ : WhenDynamicCastToMatcherBase<To>(matcher) {}
+
+ template <typename From>
+ bool MatchAndExplain(From from, MatchResultListener* listener) const {
+ // TODO(sbenza): Add more detail on failures. ie did the dyn_cast fail?
+ To to = dynamic_cast<To>(from);
+ return MatchPrintAndExplain(to, this->matcher_, listener);
+ }
+};
+
+// Specialize for references.
+// In this case we return false if the dynamic_cast fails.
+template <typename To>
+class WhenDynamicCastToMatcher<To&> : public WhenDynamicCastToMatcherBase<To&> {
+ public:
+ explicit WhenDynamicCastToMatcher(const Matcher<To&>& matcher)
+ : WhenDynamicCastToMatcherBase<To&>(matcher) {}
+
+ template <typename From>
+ bool MatchAndExplain(From& from, MatchResultListener* listener) const {
+ // We don't want an std::bad_cast here, so do the cast with pointers.
+ To* to = dynamic_cast<To*>(&from);
+ if (to == NULL) {
+ *listener << "which cannot be dynamic_cast to " << this->GetToName();
+ return false;
+ }
+ return MatchPrintAndExplain(*to, this->matcher_, listener);
+ }
+};
+
+// Implements the Field() matcher for matching a field (i.e. member
+// variable) of an object.
+template <typename Class, typename FieldType>
+class FieldMatcher {
+ public:
+ FieldMatcher(FieldType Class::*field,
+ const Matcher<const FieldType&>& matcher)
+ : field_(field), matcher_(matcher) {}
+
+ void DescribeTo(::std::ostream* os) const {
+ *os << "is an object whose given field ";
+ matcher_.DescribeTo(os);
+ }
+
+ void DescribeNegationTo(::std::ostream* os) const {
+ *os << "is an object whose given field ";
+ matcher_.DescribeNegationTo(os);
+ }
+
+ template <typename T>
+ bool MatchAndExplain(const T& value, MatchResultListener* listener) const {
+ return MatchAndExplainImpl(
+ typename ::testing::internal::
+ is_pointer<GTEST_REMOVE_CONST_(T)>::type(),
+ value, listener);
+ }
+
+ private:
+ // The first argument of MatchAndExplainImpl() is needed to help
+ // Symbian's C++ compiler choose which overload to use. Its type is
+ // true_type iff the Field() matcher is used to match a pointer.
+ bool MatchAndExplainImpl(false_type /* is_not_pointer */, const Class& obj,
+ MatchResultListener* listener) const {
+ *listener << "whose given field is ";
+ return MatchPrintAndExplain(obj.*field_, matcher_, listener);
+ }
+
+ bool MatchAndExplainImpl(true_type /* is_pointer */, const Class* p,
+ MatchResultListener* listener) const {
+ if (p == NULL)
+ return false;
+
+ *listener << "which points to an object ";
+ // Since *p has a field, it must be a class/struct/union type and
+ // thus cannot be a pointer. Therefore we pass false_type() as
+ // the first argument.
+ return MatchAndExplainImpl(false_type(), *p, listener);
+ }
+
+ const FieldType Class::*field_;
+ const Matcher<const FieldType&> matcher_;
+
+ GTEST_DISALLOW_ASSIGN_(FieldMatcher);
+};
+
+// Implements the Property() matcher for matching a property
+// (i.e. return value of a getter method) of an object.
+template <typename Class, typename PropertyType>
+class PropertyMatcher {
+ public:
+ // The property may have a reference type, so 'const PropertyType&'
+ // may cause double references and fail to compile. That's why we
+ // need GTEST_REFERENCE_TO_CONST, which works regardless of
+ // PropertyType being a reference or not.
+ typedef GTEST_REFERENCE_TO_CONST_(PropertyType) RefToConstProperty;
+
+ PropertyMatcher(PropertyType (Class::*property)() const,
+ const Matcher<RefToConstProperty>& matcher)
+ : property_(property), matcher_(matcher) {}
+
+ void DescribeTo(::std::ostream* os) const {
+ *os << "is an object whose given property ";
+ matcher_.DescribeTo(os);
+ }
+
+ void DescribeNegationTo(::std::ostream* os) const {
+ *os << "is an object whose given property ";
+ matcher_.DescribeNegationTo(os);
+ }
+
+ template <typename T>
+ bool MatchAndExplain(const T&value, MatchResultListener* listener) const {
+ return MatchAndExplainImpl(
+ typename ::testing::internal::
+ is_pointer<GTEST_REMOVE_CONST_(T)>::type(),
+ value, listener);
+ }
+
+ private:
+ // The first argument of MatchAndExplainImpl() is needed to help
+ // Symbian's C++ compiler choose which overload to use. Its type is
+ // true_type iff the Property() matcher is used to match a pointer.
+ bool MatchAndExplainImpl(false_type /* is_not_pointer */, const Class& obj,
+ MatchResultListener* listener) const {
+ *listener << "whose given property is ";
+ // Cannot pass the return value (for example, int) to MatchPrintAndExplain,
+ // which takes a non-const reference as argument.
+#if defined(_PREFAST_ ) && _MSC_VER == 1800
+ // Workaround bug in VC++ 2013's /analyze parser.
+ // https://connect.microsoft.com/VisualStudio/feedback/details/1106363/internal-compiler-error-with-analyze-due-to-failure-to-infer-move
+ posix::Abort(); // To make sure it is never run.
+ return false;
+#else
+ RefToConstProperty result = (obj.*property_)();
+ return MatchPrintAndExplain(result, matcher_, listener);
+#endif
+ }
+
+ bool MatchAndExplainImpl(true_type /* is_pointer */, const Class* p,
+ MatchResultListener* listener) const {
+ if (p == NULL)
+ return false;
+
+ *listener << "which points to an object ";
+ // Since *p has a property method, it must be a class/struct/union
+ // type and thus cannot be a pointer. Therefore we pass
+ // false_type() as the first argument.
+ return MatchAndExplainImpl(false_type(), *p, listener);
+ }
+
+ PropertyType (Class::*property_)() const;
+ const Matcher<RefToConstProperty> matcher_;
+
+ GTEST_DISALLOW_ASSIGN_(PropertyMatcher);
+};
+
+// Type traits specifying various features of different functors for ResultOf.
+// The default template specifies features for functor objects.
+// Functor classes have to typedef argument_type and result_type
+// to be compatible with ResultOf.
+template <typename Functor>
+struct CallableTraits {
+ typedef typename Functor::result_type ResultType;
+ typedef Functor StorageType;
+
+ static void CheckIsValid(Functor /* functor */) {}
+ template <typename T>
+ static ResultType Invoke(Functor f, T arg) { return f(arg); }
+};
+
+// Specialization for function pointers.
+template <typename ArgType, typename ResType>
+struct CallableTraits<ResType(*)(ArgType)> {
+ typedef ResType ResultType;
+ typedef ResType(*StorageType)(ArgType);
+
+ static void CheckIsValid(ResType(*f)(ArgType)) {
+ GTEST_CHECK_(f != NULL)
+ << "NULL function pointer is passed into ResultOf().";
+ }
+ template <typename T>
+ static ResType Invoke(ResType(*f)(ArgType), T arg) {
+ return (*f)(arg);
+ }
+};
+
+// Implements the ResultOf() matcher for matching a return value of a
+// unary function of an object.
+template <typename Callable>
+class ResultOfMatcher {
+ public:
+ typedef typename CallableTraits<Callable>::ResultType ResultType;
+
+ ResultOfMatcher(Callable callable, const Matcher<ResultType>& matcher)
+ : callable_(callable), matcher_(matcher) {
+ CallableTraits<Callable>::CheckIsValid(callable_);
+ }
+
+ template <typename T>
+ operator Matcher<T>() const {
+ return Matcher<T>(new Impl<T>(callable_, matcher_));
+ }
+
+ private:
+ typedef typename CallableTraits<Callable>::StorageType CallableStorageType;
+
+ template <typename T>
+ class Impl : public MatcherInterface<T> {
+ public:
+ Impl(CallableStorageType callable, const Matcher<ResultType>& matcher)
+ : callable_(callable), matcher_(matcher) {}
+
+ virtual void DescribeTo(::std::ostream* os) const {
+ *os << "is mapped by the given callable to a value that ";
+ matcher_.DescribeTo(os);
+ }
+
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ *os << "is mapped by the given callable to a value that ";
+ matcher_.DescribeNegationTo(os);
+ }
+
+ virtual bool MatchAndExplain(T obj, MatchResultListener* listener) const {
+ *listener << "which is mapped by the given callable to ";
+ // Cannot pass the return value (for example, int) to
+ // MatchPrintAndExplain, which takes a non-const reference as argument.
+ ResultType result =
+ CallableTraits<Callable>::template Invoke<T>(callable_, obj);
+ return MatchPrintAndExplain(result, matcher_, listener);
+ }
+
+ private:
+ // Functors often define operator() as non-const method even though
+ // they are actualy stateless. But we need to use them even when
+ // 'this' is a const pointer. It's the user's responsibility not to
+ // use stateful callables with ResultOf(), which does't guarantee
+ // how many times the callable will be invoked.
+ mutable CallableStorageType callable_;
+ const Matcher<ResultType> matcher_;
+
+ GTEST_DISALLOW_ASSIGN_(Impl);
+ }; // class Impl
+
+ const CallableStorageType callable_;
+ const Matcher<ResultType> matcher_;
+
+ GTEST_DISALLOW_ASSIGN_(ResultOfMatcher);
+};
+
+// Implements a matcher that checks the size of an STL-style container.
+template <typename SizeMatcher>
+class SizeIsMatcher {
+ public:
+ explicit SizeIsMatcher(const SizeMatcher& size_matcher)
+ : size_matcher_(size_matcher) {
+ }
+
+ template <typename Container>
+ operator Matcher<Container>() const {
+ return MakeMatcher(new Impl<Container>(size_matcher_));
+ }
+
+ template <typename Container>
+ class Impl : public MatcherInterface<Container> {
+ public:
+ typedef internal::StlContainerView<
+ GTEST_REMOVE_REFERENCE_AND_CONST_(Container)> ContainerView;
+ typedef typename ContainerView::type::size_type SizeType;
+ explicit Impl(const SizeMatcher& size_matcher)
+ : size_matcher_(MatcherCast<SizeType>(size_matcher)) {}
+
+ virtual void DescribeTo(::std::ostream* os) const {
+ *os << "size ";
+ size_matcher_.DescribeTo(os);
+ }
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ *os << "size ";
+ size_matcher_.DescribeNegationTo(os);
+ }
+
+ virtual bool MatchAndExplain(Container container,
+ MatchResultListener* listener) const {
+ SizeType size = container.size();
+ StringMatchResultListener size_listener;
+ const bool result = size_matcher_.MatchAndExplain(size, &size_listener);
+ *listener
+ << "whose size " << size << (result ? " matches" : " doesn't match");
+ PrintIfNotEmpty(size_listener.str(), listener->stream());
+ return result;
+ }
+
+ private:
+ const Matcher<SizeType> size_matcher_;
+ GTEST_DISALLOW_ASSIGN_(Impl);
+ };
+
+ private:
+ const SizeMatcher size_matcher_;
+ GTEST_DISALLOW_ASSIGN_(SizeIsMatcher);
+};
+
+// Implements a matcher that checks the begin()..end() distance of an STL-style
+// container.
+template <typename DistanceMatcher>
+class BeginEndDistanceIsMatcher {
+ public:
+ explicit BeginEndDistanceIsMatcher(const DistanceMatcher& distance_matcher)
+ : distance_matcher_(distance_matcher) {}
+
+ template <typename Container>
+ operator Matcher<Container>() const {
+ return MakeMatcher(new Impl<Container>(distance_matcher_));
+ }
+
+ template <typename Container>
+ class Impl : public MatcherInterface<Container> {
+ public:
+ typedef internal::StlContainerView<
+ GTEST_REMOVE_REFERENCE_AND_CONST_(Container)> ContainerView;
+ typedef typename std::iterator_traits<
+ typename ContainerView::type::const_iterator>::difference_type
+ DistanceType;
+ explicit Impl(const DistanceMatcher& distance_matcher)
+ : distance_matcher_(MatcherCast<DistanceType>(distance_matcher)) {}
+
+ virtual void DescribeTo(::std::ostream* os) const {
+ *os << "distance between begin() and end() ";
+ distance_matcher_.DescribeTo(os);
+ }
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ *os << "distance between begin() and end() ";
+ distance_matcher_.DescribeNegationTo(os);
+ }
+
+ virtual bool MatchAndExplain(Container container,
+ MatchResultListener* listener) const {
+#if GTEST_HAS_STD_BEGIN_AND_END_
+ using std::begin;
+ using std::end;
+ DistanceType distance = std::distance(begin(container), end(container));
+#else
+ DistanceType distance = std::distance(container.begin(), container.end());
+#endif
+ StringMatchResultListener distance_listener;
+ const bool result =
+ distance_matcher_.MatchAndExplain(distance, &distance_listener);
+ *listener << "whose distance between begin() and end() " << distance
+ << (result ? " matches" : " doesn't match");
+ PrintIfNotEmpty(distance_listener.str(), listener->stream());
+ return result;
+ }
+
+ private:
+ const Matcher<DistanceType> distance_matcher_;
+ GTEST_DISALLOW_ASSIGN_(Impl);
+ };
+
+ private:
+ const DistanceMatcher distance_matcher_;
+ GTEST_DISALLOW_ASSIGN_(BeginEndDistanceIsMatcher);
+};
+
+// Implements an equality matcher for any STL-style container whose elements
+// support ==. This matcher is like Eq(), but its failure explanations provide
+// more detailed information that is useful when the container is used as a set.
+// The failure message reports elements that are in one of the operands but not
+// the other. The failure messages do not report duplicate or out-of-order
+// elements in the containers (which don't properly matter to sets, but can
+// occur if the containers are vectors or lists, for example).
+//
+// Uses the container's const_iterator, value_type, operator ==,
+// begin(), and end().
+template <typename Container>
+class ContainerEqMatcher {
+ public:
+ typedef internal::StlContainerView<Container> View;
+ typedef typename View::type StlContainer;
+ typedef typename View::const_reference StlContainerReference;
+
+ // We make a copy of expected in case the elements in it are modified
+ // after this matcher is created.
+ explicit ContainerEqMatcher(const Container& expected)
+ : expected_(View::Copy(expected)) {
+ // Makes sure the user doesn't instantiate this class template
+ // with a const or reference type.
+ (void)testing::StaticAssertTypeEq<Container,
+ GTEST_REMOVE_REFERENCE_AND_CONST_(Container)>();
+ }
+
+ void DescribeTo(::std::ostream* os) const {
+ *os << "equals ";
+ UniversalPrint(expected_, os);
+ }
+ void DescribeNegationTo(::std::ostream* os) const {
+ *os << "does not equal ";
+ UniversalPrint(expected_, os);
+ }
+
+ template <typename LhsContainer>
+ bool MatchAndExplain(const LhsContainer& lhs,
+ MatchResultListener* listener) const {
+ // GTEST_REMOVE_CONST_() is needed to work around an MSVC 8.0 bug
+ // that causes LhsContainer to be a const type sometimes.
+ typedef internal::StlContainerView<GTEST_REMOVE_CONST_(LhsContainer)>
+ LhsView;
+ typedef typename LhsView::type LhsStlContainer;
+ StlContainerReference lhs_stl_container = LhsView::ConstReference(lhs);
+ if (lhs_stl_container == expected_)
+ return true;
+
+ ::std::ostream* const os = listener->stream();
+ if (os != NULL) {
+ // Something is different. Check for extra values first.
+ bool printed_header = false;
+ for (typename LhsStlContainer::const_iterator it =
+ lhs_stl_container.begin();
+ it != lhs_stl_container.end(); ++it) {
+ if (internal::ArrayAwareFind(expected_.begin(), expected_.end(), *it) ==
+ expected_.end()) {
+ if (printed_header) {
+ *os << ", ";
+ } else {
+ *os << "which has these unexpected elements: ";
+ printed_header = true;
+ }
+ UniversalPrint(*it, os);
+ }
+ }
+
+ // Now check for missing values.
+ bool printed_header2 = false;
+ for (typename StlContainer::const_iterator it = expected_.begin();
+ it != expected_.end(); ++it) {
+ if (internal::ArrayAwareFind(
+ lhs_stl_container.begin(), lhs_stl_container.end(), *it) ==
+ lhs_stl_container.end()) {
+ if (printed_header2) {
+ *os << ", ";
+ } else {
+ *os << (printed_header ? ",\nand" : "which")
+ << " doesn't have these expected elements: ";
+ printed_header2 = true;
+ }
+ UniversalPrint(*it, os);
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private:
+ const StlContainer expected_;
+
+ GTEST_DISALLOW_ASSIGN_(ContainerEqMatcher);
+};
+
+// A comparator functor that uses the < operator to compare two values.
+struct LessComparator {
+ template <typename T, typename U>
+ bool operator()(const T& lhs, const U& rhs) const { return lhs < rhs; }
+};
+
+// Implements WhenSortedBy(comparator, container_matcher).
+template <typename Comparator, typename ContainerMatcher>
+class WhenSortedByMatcher {
+ public:
+ WhenSortedByMatcher(const Comparator& comparator,
+ const ContainerMatcher& matcher)
+ : comparator_(comparator), matcher_(matcher) {}
+
+ template <typename LhsContainer>
+ operator Matcher<LhsContainer>() const {
+ return MakeMatcher(new Impl<LhsContainer>(comparator_, matcher_));
+ }
+
+ template <typename LhsContainer>
+ class Impl : public MatcherInterface<LhsContainer> {
+ public:
+ typedef internal::StlContainerView<
+ GTEST_REMOVE_REFERENCE_AND_CONST_(LhsContainer)> LhsView;
+ typedef typename LhsView::type LhsStlContainer;
+ typedef typename LhsView::const_reference LhsStlContainerReference;
+ // Transforms std::pair<const Key, Value> into std::pair<Key, Value>
+ // so that we can match associative containers.
+ typedef typename RemoveConstFromKey<
+ typename LhsStlContainer::value_type>::type LhsValue;
+
+ Impl(const Comparator& comparator, const ContainerMatcher& matcher)
+ : comparator_(comparator), matcher_(matcher) {}
+
+ virtual void DescribeTo(::std::ostream* os) const {
+ *os << "(when sorted) ";
+ matcher_.DescribeTo(os);
+ }
+
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ *os << "(when sorted) ";
+ matcher_.DescribeNegationTo(os);
+ }
+
+ virtual bool MatchAndExplain(LhsContainer lhs,
+ MatchResultListener* listener) const {
+ LhsStlContainerReference lhs_stl_container = LhsView::ConstReference(lhs);
+ ::std::vector<LhsValue> sorted_container(lhs_stl_container.begin(),
+ lhs_stl_container.end());
+ ::std::sort(
+ sorted_container.begin(), sorted_container.end(), comparator_);
+
+ if (!listener->IsInterested()) {
+ // If the listener is not interested, we do not need to
+ // construct the inner explanation.
+ return matcher_.Matches(sorted_container);
+ }
+
+ *listener << "which is ";
+ UniversalPrint(sorted_container, listener->stream());
+ *listener << " when sorted";
+
+ StringMatchResultListener inner_listener;
+ const bool match = matcher_.MatchAndExplain(sorted_container,
+ &inner_listener);
+ PrintIfNotEmpty(inner_listener.str(), listener->stream());
+ return match;
+ }
+
+ private:
+ const Comparator comparator_;
+ const Matcher<const ::std::vector<LhsValue>&> matcher_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(Impl);
+ };
+
+ private:
+ const Comparator comparator_;
+ const ContainerMatcher matcher_;
+
+ GTEST_DISALLOW_ASSIGN_(WhenSortedByMatcher);
+};
+
+// Implements Pointwise(tuple_matcher, rhs_container). tuple_matcher
+// must be able to be safely cast to Matcher<tuple<const T1&, const
+// T2&> >, where T1 and T2 are the types of elements in the LHS
+// container and the RHS container respectively.
+template <typename TupleMatcher, typename RhsContainer>
+class PointwiseMatcher {
+ public:
+ typedef internal::StlContainerView<RhsContainer> RhsView;
+ typedef typename RhsView::type RhsStlContainer;
+ typedef typename RhsStlContainer::value_type RhsValue;
+
+ // Like ContainerEq, we make a copy of rhs in case the elements in
+ // it are modified after this matcher is created.
+ PointwiseMatcher(const TupleMatcher& tuple_matcher, const RhsContainer& rhs)
+ : tuple_matcher_(tuple_matcher), rhs_(RhsView::Copy(rhs)) {
+ // Makes sure the user doesn't instantiate this class template
+ // with a const or reference type.
+ (void)testing::StaticAssertTypeEq<RhsContainer,
+ GTEST_REMOVE_REFERENCE_AND_CONST_(RhsContainer)>();
+ }
+
+ template <typename LhsContainer>
+ operator Matcher<LhsContainer>() const {
+ return MakeMatcher(new Impl<LhsContainer>(tuple_matcher_, rhs_));
+ }
+
+ template <typename LhsContainer>
+ class Impl : public MatcherInterface<LhsContainer> {
+ public:
+ typedef internal::StlContainerView<
+ GTEST_REMOVE_REFERENCE_AND_CONST_(LhsContainer)> LhsView;
+ typedef typename LhsView::type LhsStlContainer;
+ typedef typename LhsView::const_reference LhsStlContainerReference;
+ typedef typename LhsStlContainer::value_type LhsValue;
+ // We pass the LHS value and the RHS value to the inner matcher by
+ // reference, as they may be expensive to copy. We must use tuple
+ // instead of pair here, as a pair cannot hold references (C++ 98,
+ // 20.2.2 [lib.pairs]).
+ typedef ::testing::tuple<const LhsValue&, const RhsValue&> InnerMatcherArg;
+
+ Impl(const TupleMatcher& tuple_matcher, const RhsStlContainer& rhs)
+ // mono_tuple_matcher_ holds a monomorphic version of the tuple matcher.
+ : mono_tuple_matcher_(SafeMatcherCast<InnerMatcherArg>(tuple_matcher)),
+ rhs_(rhs) {}
+
+ virtual void DescribeTo(::std::ostream* os) const {
+ *os << "contains " << rhs_.size()
+ << " values, where each value and its corresponding value in ";
+ UniversalPrinter<RhsStlContainer>::Print(rhs_, os);
+ *os << " ";
+ mono_tuple_matcher_.DescribeTo(os);
+ }
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ *os << "doesn't contain exactly " << rhs_.size()
+ << " values, or contains a value x at some index i"
+ << " where x and the i-th value of ";
+ UniversalPrint(rhs_, os);
+ *os << " ";
+ mono_tuple_matcher_.DescribeNegationTo(os);
+ }
+
+ virtual bool MatchAndExplain(LhsContainer lhs,
+ MatchResultListener* listener) const {
+ LhsStlContainerReference lhs_stl_container = LhsView::ConstReference(lhs);
+ const size_t actual_size = lhs_stl_container.size();
+ if (actual_size != rhs_.size()) {
+ *listener << "which contains " << actual_size << " values";
+ return false;
+ }
+
+ typename LhsStlContainer::const_iterator left = lhs_stl_container.begin();
+ typename RhsStlContainer::const_iterator right = rhs_.begin();
+ for (size_t i = 0; i != actual_size; ++i, ++left, ++right) {
+ const InnerMatcherArg value_pair(*left, *right);
+
+ if (listener->IsInterested()) {
+ StringMatchResultListener inner_listener;
+ if (!mono_tuple_matcher_.MatchAndExplain(
+ value_pair, &inner_listener)) {
+ *listener << "where the value pair (";
+ UniversalPrint(*left, listener->stream());
+ *listener << ", ";
+ UniversalPrint(*right, listener->stream());
+ *listener << ") at index #" << i << " don't match";
+ PrintIfNotEmpty(inner_listener.str(), listener->stream());
+ return false;
+ }
+ } else {
+ if (!mono_tuple_matcher_.Matches(value_pair))
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private:
+ const Matcher<InnerMatcherArg> mono_tuple_matcher_;
+ const RhsStlContainer rhs_;
+
+ GTEST_DISALLOW_ASSIGN_(Impl);
+ };
+
+ private:
+ const TupleMatcher tuple_matcher_;
+ const RhsStlContainer rhs_;
+
+ GTEST_DISALLOW_ASSIGN_(PointwiseMatcher);
+};
+
+// Holds the logic common to ContainsMatcherImpl and EachMatcherImpl.
+template <typename Container>
+class QuantifierMatcherImpl : public MatcherInterface<Container> {
+ public:
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer;
+ typedef StlContainerView<RawContainer> View;
+ typedef typename View::type StlContainer;
+ typedef typename View::const_reference StlContainerReference;
+ typedef typename StlContainer::value_type Element;
+
+ template <typename InnerMatcher>
+ explicit QuantifierMatcherImpl(InnerMatcher inner_matcher)
+ : inner_matcher_(
+ testing::SafeMatcherCast<const Element&>(inner_matcher)) {}
+
+ // Checks whether:
+ // * All elements in the container match, if all_elements_should_match.
+ // * Any element in the container matches, if !all_elements_should_match.
+ bool MatchAndExplainImpl(bool all_elements_should_match,
+ Container container,
+ MatchResultListener* listener) const {
+ StlContainerReference stl_container = View::ConstReference(container);
+ size_t i = 0;
+ for (typename StlContainer::const_iterator it = stl_container.begin();
+ it != stl_container.end(); ++it, ++i) {
+ StringMatchResultListener inner_listener;
+ const bool matches = inner_matcher_.MatchAndExplain(*it, &inner_listener);
+
+ if (matches != all_elements_should_match) {
+ *listener << "whose element #" << i
+ << (matches ? " matches" : " doesn't match");
+ PrintIfNotEmpty(inner_listener.str(), listener->stream());
+ return !all_elements_should_match;
+ }
+ }
+ return all_elements_should_match;
+ }
+
+ protected:
+ const Matcher<const Element&> inner_matcher_;
+
+ GTEST_DISALLOW_ASSIGN_(QuantifierMatcherImpl);
+};
+
+// Implements Contains(element_matcher) for the given argument type Container.
+// Symmetric to EachMatcherImpl.
+template <typename Container>
+class ContainsMatcherImpl : public QuantifierMatcherImpl<Container> {
+ public:
+ template <typename InnerMatcher>
+ explicit ContainsMatcherImpl(InnerMatcher inner_matcher)
+ : QuantifierMatcherImpl<Container>(inner_matcher) {}
+
+ // Describes what this matcher does.
+ virtual void DescribeTo(::std::ostream* os) const {
+ *os << "contains at least one element that ";
+ this->inner_matcher_.DescribeTo(os);
+ }
+
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ *os << "doesn't contain any element that ";
+ this->inner_matcher_.DescribeTo(os);
+ }
+
+ virtual bool MatchAndExplain(Container container,
+ MatchResultListener* listener) const {
+ return this->MatchAndExplainImpl(false, container, listener);
+ }
+
+ private:
+ GTEST_DISALLOW_ASSIGN_(ContainsMatcherImpl);
+};
+
+// Implements Each(element_matcher) for the given argument type Container.
+// Symmetric to ContainsMatcherImpl.
+template <typename Container>
+class EachMatcherImpl : public QuantifierMatcherImpl<Container> {
+ public:
+ template <typename InnerMatcher>
+ explicit EachMatcherImpl(InnerMatcher inner_matcher)
+ : QuantifierMatcherImpl<Container>(inner_matcher) {}
+
+ // Describes what this matcher does.
+ virtual void DescribeTo(::std::ostream* os) const {
+ *os << "only contains elements that ";
+ this->inner_matcher_.DescribeTo(os);
+ }
+
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ *os << "contains some element that ";
+ this->inner_matcher_.DescribeNegationTo(os);
+ }
+
+ virtual bool MatchAndExplain(Container container,
+ MatchResultListener* listener) const {
+ return this->MatchAndExplainImpl(true, container, listener);
+ }
+
+ private:
+ GTEST_DISALLOW_ASSIGN_(EachMatcherImpl);
+};
+
+// Implements polymorphic Contains(element_matcher).
+template <typename M>
+class ContainsMatcher {
+ public:
+ explicit ContainsMatcher(M m) : inner_matcher_(m) {}
+
+ template <typename Container>
+ operator Matcher<Container>() const {
+ return MakeMatcher(new ContainsMatcherImpl<Container>(inner_matcher_));
+ }
+
+ private:
+ const M inner_matcher_;
+
+ GTEST_DISALLOW_ASSIGN_(ContainsMatcher);
+};
+
+// Implements polymorphic Each(element_matcher).
+template <typename M>
+class EachMatcher {
+ public:
+ explicit EachMatcher(M m) : inner_matcher_(m) {}
+
+ template <typename Container>
+ operator Matcher<Container>() const {
+ return MakeMatcher(new EachMatcherImpl<Container>(inner_matcher_));
+ }
+
+ private:
+ const M inner_matcher_;
+
+ GTEST_DISALLOW_ASSIGN_(EachMatcher);
+};
+
+// Implements Key(inner_matcher) for the given argument pair type.
+// Key(inner_matcher) matches an std::pair whose 'first' field matches
+// inner_matcher. For example, Contains(Key(Ge(5))) can be used to match an
+// std::map that contains at least one element whose key is >= 5.
+template <typename PairType>
+class KeyMatcherImpl : public MatcherInterface<PairType> {
+ public:
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(PairType) RawPairType;
+ typedef typename RawPairType::first_type KeyType;
+
+ template <typename InnerMatcher>
+ explicit KeyMatcherImpl(InnerMatcher inner_matcher)
+ : inner_matcher_(
+ testing::SafeMatcherCast<const KeyType&>(inner_matcher)) {
+ }
+
+ // Returns true iff 'key_value.first' (the key) matches the inner matcher.
+ virtual bool MatchAndExplain(PairType key_value,
+ MatchResultListener* listener) const {
+ StringMatchResultListener inner_listener;
+ const bool match = inner_matcher_.MatchAndExplain(key_value.first,
+ &inner_listener);
+ const internal::string explanation = inner_listener.str();
+ if (explanation != "") {
+ *listener << "whose first field is a value " << explanation;
+ }
+ return match;
+ }
+
+ // Describes what this matcher does.
+ virtual void DescribeTo(::std::ostream* os) const {
+ *os << "has a key that ";
+ inner_matcher_.DescribeTo(os);
+ }
+
+ // Describes what the negation of this matcher does.
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ *os << "doesn't have a key that ";
+ inner_matcher_.DescribeTo(os);
+ }
+
+ private:
+ const Matcher<const KeyType&> inner_matcher_;
+
+ GTEST_DISALLOW_ASSIGN_(KeyMatcherImpl);
+};
+
+// Implements polymorphic Key(matcher_for_key).
+template <typename M>
+class KeyMatcher {
+ public:
+ explicit KeyMatcher(M m) : matcher_for_key_(m) {}
+
+ template <typename PairType>
+ operator Matcher<PairType>() const {
+ return MakeMatcher(new KeyMatcherImpl<PairType>(matcher_for_key_));
+ }
+
+ private:
+ const M matcher_for_key_;
+
+ GTEST_DISALLOW_ASSIGN_(KeyMatcher);
+};
+
+// Implements Pair(first_matcher, second_matcher) for the given argument pair
+// type with its two matchers. See Pair() function below.
+template <typename PairType>
+class PairMatcherImpl : public MatcherInterface<PairType> {
+ public:
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(PairType) RawPairType;
+ typedef typename RawPairType::first_type FirstType;
+ typedef typename RawPairType::second_type SecondType;
+
+ template <typename FirstMatcher, typename SecondMatcher>
+ PairMatcherImpl(FirstMatcher first_matcher, SecondMatcher second_matcher)
+ : first_matcher_(
+ testing::SafeMatcherCast<const FirstType&>(first_matcher)),
+ second_matcher_(
+ testing::SafeMatcherCast<const SecondType&>(second_matcher)) {
+ }
+
+ // Describes what this matcher does.
+ virtual void DescribeTo(::std::ostream* os) const {
+ *os << "has a first field that ";
+ first_matcher_.DescribeTo(os);
+ *os << ", and has a second field that ";
+ second_matcher_.DescribeTo(os);
+ }
+
+ // Describes what the negation of this matcher does.
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ *os << "has a first field that ";
+ first_matcher_.DescribeNegationTo(os);
+ *os << ", or has a second field that ";
+ second_matcher_.DescribeNegationTo(os);
+ }
+
+ // Returns true iff 'a_pair.first' matches first_matcher and 'a_pair.second'
+ // matches second_matcher.
+ virtual bool MatchAndExplain(PairType a_pair,
+ MatchResultListener* listener) const {
+ if (!listener->IsInterested()) {
+ // If the listener is not interested, we don't need to construct the
+ // explanation.
+ return first_matcher_.Matches(a_pair.first) &&
+ second_matcher_.Matches(a_pair.second);
+ }
+ StringMatchResultListener first_inner_listener;
+ if (!first_matcher_.MatchAndExplain(a_pair.first,
+ &first_inner_listener)) {
+ *listener << "whose first field does not match";
+ PrintIfNotEmpty(first_inner_listener.str(), listener->stream());
+ return false;
+ }
+ StringMatchResultListener second_inner_listener;
+ if (!second_matcher_.MatchAndExplain(a_pair.second,
+ &second_inner_listener)) {
+ *listener << "whose second field does not match";
+ PrintIfNotEmpty(second_inner_listener.str(), listener->stream());
+ return false;
+ }
+ ExplainSuccess(first_inner_listener.str(), second_inner_listener.str(),
+ listener);
+ return true;
+ }
+
+ private:
+ void ExplainSuccess(const internal::string& first_explanation,
+ const internal::string& second_explanation,
+ MatchResultListener* listener) const {
+ *listener << "whose both fields match";
+ if (first_explanation != "") {
+ *listener << ", where the first field is a value " << first_explanation;
+ }
+ if (second_explanation != "") {
+ *listener << ", ";
+ if (first_explanation != "") {
+ *listener << "and ";
+ } else {
+ *listener << "where ";
+ }
+ *listener << "the second field is a value " << second_explanation;
+ }
+ }
+
+ const Matcher<const FirstType&> first_matcher_;
+ const Matcher<const SecondType&> second_matcher_;
+
+ GTEST_DISALLOW_ASSIGN_(PairMatcherImpl);
+};
+
+// Implements polymorphic Pair(first_matcher, second_matcher).
+template <typename FirstMatcher, typename SecondMatcher>
+class PairMatcher {
+ public:
+ PairMatcher(FirstMatcher first_matcher, SecondMatcher second_matcher)
+ : first_matcher_(first_matcher), second_matcher_(second_matcher) {}
+
+ template <typename PairType>
+ operator Matcher<PairType> () const {
+ return MakeMatcher(
+ new PairMatcherImpl<PairType>(
+ first_matcher_, second_matcher_));
+ }
+
+ private:
+ const FirstMatcher first_matcher_;
+ const SecondMatcher second_matcher_;
+
+ GTEST_DISALLOW_ASSIGN_(PairMatcher);
+};
+
+// Implements ElementsAre() and ElementsAreArray().
+template <typename Container>
+class ElementsAreMatcherImpl : public MatcherInterface<Container> {
+ public:
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer;
+ typedef internal::StlContainerView<RawContainer> View;
+ typedef typename View::type StlContainer;
+ typedef typename View::const_reference StlContainerReference;
+ typedef typename StlContainer::value_type Element;
+
+ // Constructs the matcher from a sequence of element values or
+ // element matchers.
+ template <typename InputIter>
+ ElementsAreMatcherImpl(InputIter first, InputIter last) {
+ while (first != last) {
+ matchers_.push_back(MatcherCast<const Element&>(*first++));
+ }
+ }
+
+ // Describes what this matcher does.
+ virtual void DescribeTo(::std::ostream* os) const {
+ if (count() == 0) {
+ *os << "is empty";
+ } else if (count() == 1) {
+ *os << "has 1 element that ";
+ matchers_[0].DescribeTo(os);
+ } else {
+ *os << "has " << Elements(count()) << " where\n";
+ for (size_t i = 0; i != count(); ++i) {
+ *os << "element #" << i << " ";
+ matchers_[i].DescribeTo(os);
+ if (i + 1 < count()) {
+ *os << ",\n";
+ }
+ }
+ }
+ }
+
+ // Describes what the negation of this matcher does.
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ if (count() == 0) {
+ *os << "isn't empty";
+ return;
+ }
+
+ *os << "doesn't have " << Elements(count()) << ", or\n";
+ for (size_t i = 0; i != count(); ++i) {
+ *os << "element #" << i << " ";
+ matchers_[i].DescribeNegationTo(os);
+ if (i + 1 < count()) {
+ *os << ", or\n";
+ }
+ }
+ }
+
+ virtual bool MatchAndExplain(Container container,
+ MatchResultListener* listener) const {
+ // To work with stream-like "containers", we must only walk
+ // through the elements in one pass.
+
+ const bool listener_interested = listener->IsInterested();
+
+ // explanations[i] is the explanation of the element at index i.
+ ::std::vector<internal::string> explanations(count());
+ StlContainerReference stl_container = View::ConstReference(container);
+ typename StlContainer::const_iterator it = stl_container.begin();
+ size_t exam_pos = 0;
+ bool mismatch_found = false; // Have we found a mismatched element yet?
+
+ // Go through the elements and matchers in pairs, until we reach
+ // the end of either the elements or the matchers, or until we find a
+ // mismatch.
+ for (; it != stl_container.end() && exam_pos != count(); ++it, ++exam_pos) {
+ bool match; // Does the current element match the current matcher?
+ if (listener_interested) {
+ StringMatchResultListener s;
+ match = matchers_[exam_pos].MatchAndExplain(*it, &s);
+ explanations[exam_pos] = s.str();
+ } else {
+ match = matchers_[exam_pos].Matches(*it);
+ }
+
+ if (!match) {
+ mismatch_found = true;
+ break;
+ }
+ }
+ // If mismatch_found is true, 'exam_pos' is the index of the mismatch.
+
+ // Find how many elements the actual container has. We avoid
+ // calling size() s.t. this code works for stream-like "containers"
+ // that don't define size().
+ size_t actual_count = exam_pos;
+ for (; it != stl_container.end(); ++it) {
+ ++actual_count;
+ }
+
+ if (actual_count != count()) {
+ // The element count doesn't match. If the container is empty,
+ // there's no need to explain anything as Google Mock already
+ // prints the empty container. Otherwise we just need to show
+ // how many elements there actually are.
+ if (listener_interested && (actual_count != 0)) {
+ *listener << "which has " << Elements(actual_count);
+ }
+ return false;
+ }
+
+ if (mismatch_found) {
+ // The element count matches, but the exam_pos-th element doesn't match.
+ if (listener_interested) {
+ *listener << "whose element #" << exam_pos << " doesn't match";
+ PrintIfNotEmpty(explanations[exam_pos], listener->stream());
+ }
+ return false;
+ }
+
+ // Every element matches its expectation. We need to explain why
+ // (the obvious ones can be skipped).
+ if (listener_interested) {
+ bool reason_printed = false;
+ for (size_t i = 0; i != count(); ++i) {
+ const internal::string& s = explanations[i];
+ if (!s.empty()) {
+ if (reason_printed) {
+ *listener << ",\nand ";
+ }
+ *listener << "whose element #" << i << " matches, " << s;
+ reason_printed = true;
+ }
+ }
+ }
+ return true;
+ }
+
+ private:
+ static Message Elements(size_t count) {
+ return Message() << count << (count == 1 ? " element" : " elements");
+ }
+
+ size_t count() const { return matchers_.size(); }
+
+ ::std::vector<Matcher<const Element&> > matchers_;
+
+ GTEST_DISALLOW_ASSIGN_(ElementsAreMatcherImpl);
+};
+
+// Connectivity matrix of (elements X matchers), in element-major order.
+// Initially, there are no edges.
+// Use NextGraph() to iterate over all possible edge configurations.
+// Use Randomize() to generate a random edge configuration.
+class GTEST_API_ MatchMatrix {
+ public:
+ MatchMatrix(size_t num_elements, size_t num_matchers)
+ : num_elements_(num_elements),
+ num_matchers_(num_matchers),
+ matched_(num_elements_* num_matchers_, 0) {
+ }
+
+ size_t LhsSize() const { return num_elements_; }
+ size_t RhsSize() const { return num_matchers_; }
+ bool HasEdge(size_t ilhs, size_t irhs) const {
+ return matched_[SpaceIndex(ilhs, irhs)] == 1;
+ }
+ void SetEdge(size_t ilhs, size_t irhs, bool b) {
+ matched_[SpaceIndex(ilhs, irhs)] = b ? 1 : 0;
+ }
+
+ // Treating the connectivity matrix as a (LhsSize()*RhsSize())-bit number,
+ // adds 1 to that number; returns false if incrementing the graph left it
+ // empty.
+ bool NextGraph();
+
+ void Randomize();
+
+ string DebugString() const;
+
+ private:
+ size_t SpaceIndex(size_t ilhs, size_t irhs) const {
+ return ilhs * num_matchers_ + irhs;
+ }
+
+ size_t num_elements_;
+ size_t num_matchers_;
+
+ // Each element is a char interpreted as bool. They are stored as a
+ // flattened array in lhs-major order, use 'SpaceIndex()' to translate
+ // a (ilhs, irhs) matrix coordinate into an offset.
+ ::std::vector<char> matched_;
+};
+
+typedef ::std::pair<size_t, size_t> ElementMatcherPair;
+typedef ::std::vector<ElementMatcherPair> ElementMatcherPairs;
+
+// Returns a maximum bipartite matching for the specified graph 'g'.
+// The matching is represented as a vector of {element, matcher} pairs.
+GTEST_API_ ElementMatcherPairs
+FindMaxBipartiteMatching(const MatchMatrix& g);
+
+GTEST_API_ bool FindPairing(const MatchMatrix& matrix,
+ MatchResultListener* listener);
+
+// Untyped base class for implementing UnorderedElementsAre. By
+// putting logic that's not specific to the element type here, we
+// reduce binary bloat and increase compilation speed.
+class GTEST_API_ UnorderedElementsAreMatcherImplBase {
+ protected:
+ // A vector of matcher describers, one for each element matcher.
+ // Does not own the describers (and thus can be used only when the
+ // element matchers are alive).
+ typedef ::std::vector<const MatcherDescriberInterface*> MatcherDescriberVec;
+
+ // Describes this UnorderedElementsAre matcher.
+ void DescribeToImpl(::std::ostream* os) const;
+
+ // Describes the negation of this UnorderedElementsAre matcher.
+ void DescribeNegationToImpl(::std::ostream* os) const;
+
+ bool VerifyAllElementsAndMatchersAreMatched(
+ const ::std::vector<string>& element_printouts,
+ const MatchMatrix& matrix,
+ MatchResultListener* listener) const;
+
+ MatcherDescriberVec& matcher_describers() {
+ return matcher_describers_;
+ }
+
+ static Message Elements(size_t n) {
+ return Message() << n << " element" << (n == 1 ? "" : "s");
+ }
+
+ private:
+ MatcherDescriberVec matcher_describers_;
+
+ GTEST_DISALLOW_ASSIGN_(UnorderedElementsAreMatcherImplBase);
+};
+
+// Implements unordered ElementsAre and unordered ElementsAreArray.
+template <typename Container>
+class UnorderedElementsAreMatcherImpl
+ : public MatcherInterface<Container>,
+ public UnorderedElementsAreMatcherImplBase {
+ public:
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer;
+ typedef internal::StlContainerView<RawContainer> View;
+ typedef typename View::type StlContainer;
+ typedef typename View::const_reference StlContainerReference;
+ typedef typename StlContainer::const_iterator StlContainerConstIterator;
+ typedef typename StlContainer::value_type Element;
+
+ // Constructs the matcher from a sequence of element values or
+ // element matchers.
+ template <typename InputIter>
+ UnorderedElementsAreMatcherImpl(InputIter first, InputIter last) {
+ for (; first != last; ++first) {
+ matchers_.push_back(MatcherCast<const Element&>(*first));
+ matcher_describers().push_back(matchers_.back().GetDescriber());
+ }
+ }
+
+ // Describes what this matcher does.
+ virtual void DescribeTo(::std::ostream* os) const {
+ return UnorderedElementsAreMatcherImplBase::DescribeToImpl(os);
+ }
+
+ // Describes what the negation of this matcher does.
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ return UnorderedElementsAreMatcherImplBase::DescribeNegationToImpl(os);
+ }
+
+ virtual bool MatchAndExplain(Container container,
+ MatchResultListener* listener) const {
+ StlContainerReference stl_container = View::ConstReference(container);
+ ::std::vector<string> element_printouts;
+ MatchMatrix matrix = AnalyzeElements(stl_container.begin(),
+ stl_container.end(),
+ &element_printouts,
+ listener);
+
+ const size_t actual_count = matrix.LhsSize();
+ if (actual_count == 0 && matchers_.empty()) {
+ return true;
+ }
+ if (actual_count != matchers_.size()) {
+ // The element count doesn't match. If the container is empty,
+ // there's no need to explain anything as Google Mock already
+ // prints the empty container. Otherwise we just need to show
+ // how many elements there actually are.
+ if (actual_count != 0 && listener->IsInterested()) {
+ *listener << "which has " << Elements(actual_count);
+ }
+ return false;
+ }
+
+ return VerifyAllElementsAndMatchersAreMatched(element_printouts,
+ matrix, listener) &&
+ FindPairing(matrix, listener);
+ }
+
+ private:
+ typedef ::std::vector<Matcher<const Element&> > MatcherVec;
+
+ template <typename ElementIter>
+ MatchMatrix AnalyzeElements(ElementIter elem_first, ElementIter elem_last,
+ ::std::vector<string>* element_printouts,
+ MatchResultListener* listener) const {
+ element_printouts->clear();
+ ::std::vector<char> did_match;
+ size_t num_elements = 0;
+ for (; elem_first != elem_last; ++num_elements, ++elem_first) {
+ if (listener->IsInterested()) {
+ element_printouts->push_back(PrintToString(*elem_first));
+ }
+ for (size_t irhs = 0; irhs != matchers_.size(); ++irhs) {
+ did_match.push_back(Matches(matchers_[irhs])(*elem_first));
+ }
+ }
+
+ MatchMatrix matrix(num_elements, matchers_.size());
+ ::std::vector<char>::const_iterator did_match_iter = did_match.begin();
+ for (size_t ilhs = 0; ilhs != num_elements; ++ilhs) {
+ for (size_t irhs = 0; irhs != matchers_.size(); ++irhs) {
+ matrix.SetEdge(ilhs, irhs, *did_match_iter++ != 0);
+ }
+ }
+ return matrix;
+ }
+
+ MatcherVec matchers_;
+
+ GTEST_DISALLOW_ASSIGN_(UnorderedElementsAreMatcherImpl);
+};
+
+// Functor for use in TransformTuple.
+// Performs MatcherCast<Target> on an input argument of any type.
+template <typename Target>
+struct CastAndAppendTransform {
+ template <typename Arg>
+ Matcher<Target> operator()(const Arg& a) const {
+ return MatcherCast<Target>(a);
+ }
+};
+
+// Implements UnorderedElementsAre.
+template <typename MatcherTuple>
+class UnorderedElementsAreMatcher {
+ public:
+ explicit UnorderedElementsAreMatcher(const MatcherTuple& args)
+ : matchers_(args) {}
+
+ template <typename Container>
+ operator Matcher<Container>() const {
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer;
+ typedef typename internal::StlContainerView<RawContainer>::type View;
+ typedef typename View::value_type Element;
+ typedef ::std::vector<Matcher<const Element&> > MatcherVec;
+ MatcherVec matchers;
+ matchers.reserve(::testing::tuple_size<MatcherTuple>::value);
+ TransformTupleValues(CastAndAppendTransform<const Element&>(), matchers_,
+ ::std::back_inserter(matchers));
+ return MakeMatcher(new UnorderedElementsAreMatcherImpl<Container>(
+ matchers.begin(), matchers.end()));
+ }
+
+ private:
+ const MatcherTuple matchers_;
+ GTEST_DISALLOW_ASSIGN_(UnorderedElementsAreMatcher);
+};
+
+// Implements ElementsAre.
+template <typename MatcherTuple>
+class ElementsAreMatcher {
+ public:
+ explicit ElementsAreMatcher(const MatcherTuple& args) : matchers_(args) {}
+
+ template <typename Container>
+ operator Matcher<Container>() const {
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer;
+ typedef typename internal::StlContainerView<RawContainer>::type View;
+ typedef typename View::value_type Element;
+ typedef ::std::vector<Matcher<const Element&> > MatcherVec;
+ MatcherVec matchers;
+ matchers.reserve(::testing::tuple_size<MatcherTuple>::value);
+ TransformTupleValues(CastAndAppendTransform<const Element&>(), matchers_,
+ ::std::back_inserter(matchers));
+ return MakeMatcher(new ElementsAreMatcherImpl<Container>(
+ matchers.begin(), matchers.end()));
+ }
+
+ private:
+ const MatcherTuple matchers_;
+ GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher);
+};
+
+// Implements UnorderedElementsAreArray().
+template <typename T>
+class UnorderedElementsAreArrayMatcher {
+ public:
+ UnorderedElementsAreArrayMatcher() {}
+
+ template <typename Iter>
+ UnorderedElementsAreArrayMatcher(Iter first, Iter last)
+ : matchers_(first, last) {}
+
+ template <typename Container>
+ operator Matcher<Container>() const {
+ return MakeMatcher(
+ new UnorderedElementsAreMatcherImpl<Container>(matchers_.begin(),
+ matchers_.end()));
+ }
+
+ private:
+ ::std::vector<T> matchers_;
+
+ GTEST_DISALLOW_ASSIGN_(UnorderedElementsAreArrayMatcher);
+};
+
+// Implements ElementsAreArray().
+template <typename T>
+class ElementsAreArrayMatcher {
+ public:
+ template <typename Iter>
+ ElementsAreArrayMatcher(Iter first, Iter last) : matchers_(first, last) {}
+
+ template <typename Container>
+ operator Matcher<Container>() const {
+ return MakeMatcher(new ElementsAreMatcherImpl<Container>(
+ matchers_.begin(), matchers_.end()));
+ }
+
+ private:
+ const ::std::vector<T> matchers_;
+
+ GTEST_DISALLOW_ASSIGN_(ElementsAreArrayMatcher);
+};
+
+// Given a 2-tuple matcher tm of type Tuple2Matcher and a value second
+// of type Second, BoundSecondMatcher<Tuple2Matcher, Second>(tm,
+// second) is a polymorphic matcher that matches a value x iff tm
+// matches tuple (x, second). Useful for implementing
+// UnorderedPointwise() in terms of UnorderedElementsAreArray().
+//
+// BoundSecondMatcher is copyable and assignable, as we need to put
+// instances of this class in a vector when implementing
+// UnorderedPointwise().
+template <typename Tuple2Matcher, typename Second>
+class BoundSecondMatcher {
+ public:
+ BoundSecondMatcher(const Tuple2Matcher& tm, const Second& second)
+ : tuple2_matcher_(tm), second_value_(second) {}
+
+ template <typename T>
+ operator Matcher<T>() const {
+ return MakeMatcher(new Impl<T>(tuple2_matcher_, second_value_));
+ }
+
+ // We have to define this for UnorderedPointwise() to compile in
+ // C++98 mode, as it puts BoundSecondMatcher instances in a vector,
+ // which requires the elements to be assignable in C++98. The
+ // compiler cannot generate the operator= for us, as Tuple2Matcher
+ // and Second may not be assignable.
+ //
+ // However, this should never be called, so the implementation just
+ // need to assert.
+ void operator=(const BoundSecondMatcher& /*rhs*/) {
+ GTEST_LOG_(FATAL) << "BoundSecondMatcher should never be assigned.";
+ }
+
+ private:
+ template <typename T>
+ class Impl : public MatcherInterface<T> {
+ public:
+ typedef ::testing::tuple<T, Second> ArgTuple;
+
+ Impl(const Tuple2Matcher& tm, const Second& second)
+ : mono_tuple2_matcher_(SafeMatcherCast<const ArgTuple&>(tm)),
+ second_value_(second) {}
+
+ virtual void DescribeTo(::std::ostream* os) const {
+ *os << "and ";
+ UniversalPrint(second_value_, os);
+ *os << " ";
+ mono_tuple2_matcher_.DescribeTo(os);
+ }
+
+ virtual bool MatchAndExplain(T x, MatchResultListener* listener) const {
+ return mono_tuple2_matcher_.MatchAndExplain(ArgTuple(x, second_value_),
+ listener);
+ }
+
+ private:
+ const Matcher<const ArgTuple&> mono_tuple2_matcher_;
+ const Second second_value_;
+
+ GTEST_DISALLOW_ASSIGN_(Impl);
+ };
+
+ const Tuple2Matcher tuple2_matcher_;
+ const Second second_value_;
+};
+
+// Given a 2-tuple matcher tm and a value second,
+// MatcherBindSecond(tm, second) returns a matcher that matches a
+// value x iff tm matches tuple (x, second). Useful for implementing
+// UnorderedPointwise() in terms of UnorderedElementsAreArray().
+template <typename Tuple2Matcher, typename Second>
+BoundSecondMatcher<Tuple2Matcher, Second> MatcherBindSecond(
+ const Tuple2Matcher& tm, const Second& second) {
+ return BoundSecondMatcher<Tuple2Matcher, Second>(tm, second);
+}
+
+// Returns the description for a matcher defined using the MATCHER*()
+// macro where the user-supplied description string is "", if
+// 'negation' is false; otherwise returns the description of the
+// negation of the matcher. 'param_values' contains a list of strings
+// that are the print-out of the matcher's parameters.
+GTEST_API_ string FormatMatcherDescription(bool negation,
+ const char* matcher_name,
+ const Strings& param_values);
+
+} // namespace internal
+
+// ElementsAreArray(first, last)
+// ElementsAreArray(pointer, count)
+// ElementsAreArray(array)
+// ElementsAreArray(container)
+// ElementsAreArray({ e1, e2, ..., en })
+//
+// The ElementsAreArray() functions are like ElementsAre(...), except
+// that they are given a homogeneous sequence rather than taking each
+// element as a function argument. The sequence can be specified as an
+// array, a pointer and count, a vector, an initializer list, or an
+// STL iterator range. In each of these cases, the underlying sequence
+// can be either a sequence of values or a sequence of matchers.
+//
+// All forms of ElementsAreArray() make a copy of the input matcher sequence.
+
+template <typename Iter>
+inline internal::ElementsAreArrayMatcher<
+ typename ::std::iterator_traits<Iter>::value_type>
+ElementsAreArray(Iter first, Iter last) {
+ typedef typename ::std::iterator_traits<Iter>::value_type T;
+ return internal::ElementsAreArrayMatcher<T>(first, last);
+}
+
+template <typename T>
+inline internal::ElementsAreArrayMatcher<T> ElementsAreArray(
+ const T* pointer, size_t count) {
+ return ElementsAreArray(pointer, pointer + count);
+}
+
+template <typename T, size_t N>
+inline internal::ElementsAreArrayMatcher<T> ElementsAreArray(
+ const T (&array)[N]) {
+ return ElementsAreArray(array, N);
+}
+
+template <typename Container>
+inline internal::ElementsAreArrayMatcher<typename Container::value_type>
+ElementsAreArray(const Container& container) {
+ return ElementsAreArray(container.begin(), container.end());
+}
+
+#if GTEST_HAS_STD_INITIALIZER_LIST_
+template <typename T>
+inline internal::ElementsAreArrayMatcher<T>
+ElementsAreArray(::std::initializer_list<T> xs) {
+ return ElementsAreArray(xs.begin(), xs.end());
+}
+#endif
+
+// UnorderedElementsAreArray(first, last)
+// UnorderedElementsAreArray(pointer, count)
+// UnorderedElementsAreArray(array)
+// UnorderedElementsAreArray(container)
+// UnorderedElementsAreArray({ e1, e2, ..., en })
+//
+// The UnorderedElementsAreArray() functions are like
+// ElementsAreArray(...), but allow matching the elements in any order.
+template <typename Iter>
+inline internal::UnorderedElementsAreArrayMatcher<
+ typename ::std::iterator_traits<Iter>::value_type>
+UnorderedElementsAreArray(Iter first, Iter last) {
+ typedef typename ::std::iterator_traits<Iter>::value_type T;
+ return internal::UnorderedElementsAreArrayMatcher<T>(first, last);
+}
+
+template <typename T>
+inline internal::UnorderedElementsAreArrayMatcher<T>
+UnorderedElementsAreArray(const T* pointer, size_t count) {
+ return UnorderedElementsAreArray(pointer, pointer + count);
+}
+
+template <typename T, size_t N>
+inline internal::UnorderedElementsAreArrayMatcher<T>
+UnorderedElementsAreArray(const T (&array)[N]) {
+ return UnorderedElementsAreArray(array, N);
+}
+
+template <typename Container>
+inline internal::UnorderedElementsAreArrayMatcher<
+ typename Container::value_type>
+UnorderedElementsAreArray(const Container& container) {
+ return UnorderedElementsAreArray(container.begin(), container.end());
+}
+
+#if GTEST_HAS_STD_INITIALIZER_LIST_
+template <typename T>
+inline internal::UnorderedElementsAreArrayMatcher<T>
+UnorderedElementsAreArray(::std::initializer_list<T> xs) {
+ return UnorderedElementsAreArray(xs.begin(), xs.end());
+}
+#endif
+
+// _ is a matcher that matches anything of any type.
+//
+// This definition is fine as:
+//
+// 1. The C++ standard permits using the name _ in a namespace that
+// is not the global namespace or ::std.
+// 2. The AnythingMatcher class has no data member or constructor,
+// so it's OK to create global variables of this type.
+// 3. c-style has approved of using _ in this case.
+const internal::AnythingMatcher _ = {};
+// Creates a matcher that matches any value of the given type T.
+template <typename T>
+inline Matcher<T> A() { return MakeMatcher(new internal::AnyMatcherImpl<T>()); }
+
+// Creates a matcher that matches any value of the given type T.
+template <typename T>
+inline Matcher<T> An() { return A<T>(); }
+
+// Creates a polymorphic matcher that matches anything equal to x.
+// Note: if the parameter of Eq() were declared as const T&, Eq("foo")
+// wouldn't compile.
+template <typename T>
+inline internal::EqMatcher<T> Eq(T x) { return internal::EqMatcher<T>(x); }
+
+// Constructs a Matcher<T> from a 'value' of type T. The constructed
+// matcher matches any value that's equal to 'value'.
+template <typename T>
+Matcher<T>::Matcher(T value) { *this = Eq(value); }
+
+// Creates a monomorphic matcher that matches anything with type Lhs
+// and equal to rhs. A user may need to use this instead of Eq(...)
+// in order to resolve an overloading ambiguity.
+//
+// TypedEq<T>(x) is just a convenient short-hand for Matcher<T>(Eq(x))
+// or Matcher<T>(x), but more readable than the latter.
+//
+// We could define similar monomorphic matchers for other comparison
+// operations (e.g. TypedLt, TypedGe, and etc), but decided not to do
+// it yet as those are used much less than Eq() in practice. A user
+// can always write Matcher<T>(Lt(5)) to be explicit about the type,
+// for example.
+template <typename Lhs, typename Rhs>
+inline Matcher<Lhs> TypedEq(const Rhs& rhs) { return Eq(rhs); }
+
+// Creates a polymorphic matcher that matches anything >= x.
+template <typename Rhs>
+inline internal::GeMatcher<Rhs> Ge(Rhs x) {
+ return internal::GeMatcher<Rhs>(x);
+}
+
+// Creates a polymorphic matcher that matches anything > x.
+template <typename Rhs>
+inline internal::GtMatcher<Rhs> Gt(Rhs x) {
+ return internal::GtMatcher<Rhs>(x);
+}
+
+// Creates a polymorphic matcher that matches anything <= x.
+template <typename Rhs>
+inline internal::LeMatcher<Rhs> Le(Rhs x) {
+ return internal::LeMatcher<Rhs>(x);
+}
+
+// Creates a polymorphic matcher that matches anything < x.
+template <typename Rhs>
+inline internal::LtMatcher<Rhs> Lt(Rhs x) {
+ return internal::LtMatcher<Rhs>(x);
+}
+
+// Creates a polymorphic matcher that matches anything != x.
+template <typename Rhs>
+inline internal::NeMatcher<Rhs> Ne(Rhs x) {
+ return internal::NeMatcher<Rhs>(x);
+}
+
+// Creates a polymorphic matcher that matches any NULL pointer.
+inline PolymorphicMatcher<internal::IsNullMatcher > IsNull() {
+ return MakePolymorphicMatcher(internal::IsNullMatcher());
+}
+
+// Creates a polymorphic matcher that matches any non-NULL pointer.
+// This is convenient as Not(NULL) doesn't compile (the compiler
+// thinks that that expression is comparing a pointer with an integer).
+inline PolymorphicMatcher<internal::NotNullMatcher > NotNull() {
+ return MakePolymorphicMatcher(internal::NotNullMatcher());
+}
+
+// Creates a polymorphic matcher that matches any argument that
+// references variable x.
+template <typename T>
+inline internal::RefMatcher<T&> Ref(T& x) { // NOLINT
+ return internal::RefMatcher<T&>(x);
+}
+
+// Creates a matcher that matches any double argument approximately
+// equal to rhs, where two NANs are considered unequal.
+inline internal::FloatingEqMatcher<double> DoubleEq(double rhs) {
+ return internal::FloatingEqMatcher<double>(rhs, false);
+}
+
+// Creates a matcher that matches any double argument approximately
+// equal to rhs, including NaN values when rhs is NaN.
+inline internal::FloatingEqMatcher<double> NanSensitiveDoubleEq(double rhs) {
+ return internal::FloatingEqMatcher<double>(rhs, true);
+}
+
+// Creates a matcher that matches any double argument approximately equal to
+// rhs, up to the specified max absolute error bound, where two NANs are
+// considered unequal. The max absolute error bound must be non-negative.
+inline internal::FloatingEqMatcher<double> DoubleNear(
+ double rhs, double max_abs_error) {
+ return internal::FloatingEqMatcher<double>(rhs, false, max_abs_error);
+}
+
+// Creates a matcher that matches any double argument approximately equal to
+// rhs, up to the specified max absolute error bound, including NaN values when
+// rhs is NaN. The max absolute error bound must be non-negative.
+inline internal::FloatingEqMatcher<double> NanSensitiveDoubleNear(
+ double rhs, double max_abs_error) {
+ return internal::FloatingEqMatcher<double>(rhs, true, max_abs_error);
+}
+
+// Creates a matcher that matches any float argument approximately
+// equal to rhs, where two NANs are considered unequal.
+inline internal::FloatingEqMatcher<float> FloatEq(float rhs) {
+ return internal::FloatingEqMatcher<float>(rhs, false);
+}
+
+// Creates a matcher that matches any float argument approximately
+// equal to rhs, including NaN values when rhs is NaN.
+inline internal::FloatingEqMatcher<float> NanSensitiveFloatEq(float rhs) {
+ return internal::FloatingEqMatcher<float>(rhs, true);
+}
+
+// Creates a matcher that matches any float argument approximately equal to
+// rhs, up to the specified max absolute error bound, where two NANs are
+// considered unequal. The max absolute error bound must be non-negative.
+inline internal::FloatingEqMatcher<float> FloatNear(
+ float rhs, float max_abs_error) {
+ return internal::FloatingEqMatcher<float>(rhs, false, max_abs_error);
+}
+
+// Creates a matcher that matches any float argument approximately equal to
+// rhs, up to the specified max absolute error bound, including NaN values when
+// rhs is NaN. The max absolute error bound must be non-negative.
+inline internal::FloatingEqMatcher<float> NanSensitiveFloatNear(
+ float rhs, float max_abs_error) {
+ return internal::FloatingEqMatcher<float>(rhs, true, max_abs_error);
+}
+
+// Creates a matcher that matches a pointer (raw or smart) that points
+// to a value that matches inner_matcher.
+template <typename InnerMatcher>
+inline internal::PointeeMatcher<InnerMatcher> Pointee(
+ const InnerMatcher& inner_matcher) {
+ return internal::PointeeMatcher<InnerMatcher>(inner_matcher);
+}
+
+// Creates a matcher that matches a pointer or reference that matches
+// inner_matcher when dynamic_cast<To> is applied.
+// The result of dynamic_cast<To> is forwarded to the inner matcher.
+// If To is a pointer and the cast fails, the inner matcher will receive NULL.
+// If To is a reference and the cast fails, this matcher returns false
+// immediately.
+template <typename To>
+inline PolymorphicMatcher<internal::WhenDynamicCastToMatcher<To> >
+WhenDynamicCastTo(const Matcher<To>& inner_matcher) {
+ return MakePolymorphicMatcher(
+ internal::WhenDynamicCastToMatcher<To>(inner_matcher));
+}
+
+// Creates a matcher that matches an object whose given field matches
+// 'matcher'. For example,
+// Field(&Foo::number, Ge(5))
+// matches a Foo object x iff x.number >= 5.
+template <typename Class, typename FieldType, typename FieldMatcher>
+inline PolymorphicMatcher<
+ internal::FieldMatcher<Class, FieldType> > Field(
+ FieldType Class::*field, const FieldMatcher& matcher) {
+ return MakePolymorphicMatcher(
+ internal::FieldMatcher<Class, FieldType>(
+ field, MatcherCast<const FieldType&>(matcher)));
+ // The call to MatcherCast() is required for supporting inner
+ // matchers of compatible types. For example, it allows
+ // Field(&Foo::bar, m)
+ // to compile where bar is an int32 and m is a matcher for int64.
+}
+
+// Creates a matcher that matches an object whose given property
+// matches 'matcher'. For example,
+// Property(&Foo::str, StartsWith("hi"))
+// matches a Foo object x iff x.str() starts with "hi".
+template <typename Class, typename PropertyType, typename PropertyMatcher>
+inline PolymorphicMatcher<
+ internal::PropertyMatcher<Class, PropertyType> > Property(
+ PropertyType (Class::*property)() const, const PropertyMatcher& matcher) {
+ return MakePolymorphicMatcher(
+ internal::PropertyMatcher<Class, PropertyType>(
+ property,
+ MatcherCast<GTEST_REFERENCE_TO_CONST_(PropertyType)>(matcher)));
+ // The call to MatcherCast() is required for supporting inner
+ // matchers of compatible types. For example, it allows
+ // Property(&Foo::bar, m)
+ // to compile where bar() returns an int32 and m is a matcher for int64.
+}
+
+// Creates a matcher that matches an object iff the result of applying
+// a callable to x matches 'matcher'.
+// For example,
+// ResultOf(f, StartsWith("hi"))
+// matches a Foo object x iff f(x) starts with "hi".
+// callable parameter can be a function, function pointer, or a functor.
+// Callable has to satisfy the following conditions:
+// * It is required to keep no state affecting the results of
+// the calls on it and make no assumptions about how many calls
+// will be made. Any state it keeps must be protected from the
+// concurrent access.
+// * If it is a function object, it has to define type result_type.
+// We recommend deriving your functor classes from std::unary_function.
+template <typename Callable, typename ResultOfMatcher>
+internal::ResultOfMatcher<Callable> ResultOf(
+ Callable callable, const ResultOfMatcher& matcher) {
+ return internal::ResultOfMatcher<Callable>(
+ callable,
+ MatcherCast<typename internal::CallableTraits<Callable>::ResultType>(
+ matcher));
+ // The call to MatcherCast() is required for supporting inner
+ // matchers of compatible types. For example, it allows
+ // ResultOf(Function, m)
+ // to compile where Function() returns an int32 and m is a matcher for int64.
+}
+
+// String matchers.
+
+// Matches a string equal to str.
+inline PolymorphicMatcher<internal::StrEqualityMatcher<internal::string> >
+ StrEq(const internal::string& str) {
+ return MakePolymorphicMatcher(internal::StrEqualityMatcher<internal::string>(
+ str, true, true));
+}
+
+// Matches a string not equal to str.
+inline PolymorphicMatcher<internal::StrEqualityMatcher<internal::string> >
+ StrNe(const internal::string& str) {
+ return MakePolymorphicMatcher(internal::StrEqualityMatcher<internal::string>(
+ str, false, true));
+}
+
+// Matches a string equal to str, ignoring case.
+inline PolymorphicMatcher<internal::StrEqualityMatcher<internal::string> >
+ StrCaseEq(const internal::string& str) {
+ return MakePolymorphicMatcher(internal::StrEqualityMatcher<internal::string>(
+ str, true, false));
+}
+
+// Matches a string not equal to str, ignoring case.
+inline PolymorphicMatcher<internal::StrEqualityMatcher<internal::string> >
+ StrCaseNe(const internal::string& str) {
+ return MakePolymorphicMatcher(internal::StrEqualityMatcher<internal::string>(
+ str, false, false));
+}
+
+// Creates a matcher that matches any string, std::string, or C string
+// that contains the given substring.
+inline PolymorphicMatcher<internal::HasSubstrMatcher<internal::string> >
+ HasSubstr(const internal::string& substring) {
+ return MakePolymorphicMatcher(internal::HasSubstrMatcher<internal::string>(
+ substring));
+}
+
+// Matches a string that starts with 'prefix' (case-sensitive).
+inline PolymorphicMatcher<internal::StartsWithMatcher<internal::string> >
+ StartsWith(const internal::string& prefix) {
+ return MakePolymorphicMatcher(internal::StartsWithMatcher<internal::string>(
+ prefix));
+}
+
+// Matches a string that ends with 'suffix' (case-sensitive).
+inline PolymorphicMatcher<internal::EndsWithMatcher<internal::string> >
+ EndsWith(const internal::string& suffix) {
+ return MakePolymorphicMatcher(internal::EndsWithMatcher<internal::string>(
+ suffix));
+}
+
+// Matches a string that fully matches regular expression 'regex'.
+// The matcher takes ownership of 'regex'.
+inline PolymorphicMatcher<internal::MatchesRegexMatcher> MatchesRegex(
+ const internal::RE* regex) {
+ return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, true));
+}
+inline PolymorphicMatcher<internal::MatchesRegexMatcher> MatchesRegex(
+ const internal::string& regex) {
+ return MatchesRegex(new internal::RE(regex));
+}
+
+// Matches a string that contains regular expression 'regex'.
+// The matcher takes ownership of 'regex'.
+inline PolymorphicMatcher<internal::MatchesRegexMatcher> ContainsRegex(
+ const internal::RE* regex) {
+ return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, false));
+}
+inline PolymorphicMatcher<internal::MatchesRegexMatcher> ContainsRegex(
+ const internal::string& regex) {
+ return ContainsRegex(new internal::RE(regex));
+}
+
+#if GTEST_HAS_GLOBAL_WSTRING || GTEST_HAS_STD_WSTRING
+// Wide string matchers.
+
+// Matches a string equal to str.
+inline PolymorphicMatcher<internal::StrEqualityMatcher<internal::wstring> >
+ StrEq(const internal::wstring& str) {
+ return MakePolymorphicMatcher(internal::StrEqualityMatcher<internal::wstring>(
+ str, true, true));
+}
+
+// Matches a string not equal to str.
+inline PolymorphicMatcher<internal::StrEqualityMatcher<internal::wstring> >
+ StrNe(const internal::wstring& str) {
+ return MakePolymorphicMatcher(internal::StrEqualityMatcher<internal::wstring>(
+ str, false, true));
+}
+
+// Matches a string equal to str, ignoring case.
+inline PolymorphicMatcher<internal::StrEqualityMatcher<internal::wstring> >
+ StrCaseEq(const internal::wstring& str) {
+ return MakePolymorphicMatcher(internal::StrEqualityMatcher<internal::wstring>(
+ str, true, false));
+}
+
+// Matches a string not equal to str, ignoring case.
+inline PolymorphicMatcher<internal::StrEqualityMatcher<internal::wstring> >
+ StrCaseNe(const internal::wstring& str) {
+ return MakePolymorphicMatcher(internal::StrEqualityMatcher<internal::wstring>(
+ str, false, false));
+}
+
+// Creates a matcher that matches any wstring, std::wstring, or C wide string
+// that contains the given substring.
+inline PolymorphicMatcher<internal::HasSubstrMatcher<internal::wstring> >
+ HasSubstr(const internal::wstring& substring) {
+ return MakePolymorphicMatcher(internal::HasSubstrMatcher<internal::wstring>(
+ substring));
+}
+
+// Matches a string that starts with 'prefix' (case-sensitive).
+inline PolymorphicMatcher<internal::StartsWithMatcher<internal::wstring> >
+ StartsWith(const internal::wstring& prefix) {
+ return MakePolymorphicMatcher(internal::StartsWithMatcher<internal::wstring>(
+ prefix));
+}
+
+// Matches a string that ends with 'suffix' (case-sensitive).
+inline PolymorphicMatcher<internal::EndsWithMatcher<internal::wstring> >
+ EndsWith(const internal::wstring& suffix) {
+ return MakePolymorphicMatcher(internal::EndsWithMatcher<internal::wstring>(
+ suffix));
+}
+
+#endif // GTEST_HAS_GLOBAL_WSTRING || GTEST_HAS_STD_WSTRING
+
+// Creates a polymorphic matcher that matches a 2-tuple where the
+// first field == the second field.
+inline internal::Eq2Matcher Eq() { return internal::Eq2Matcher(); }
+
+// Creates a polymorphic matcher that matches a 2-tuple where the
+// first field >= the second field.
+inline internal::Ge2Matcher Ge() { return internal::Ge2Matcher(); }
+
+// Creates a polymorphic matcher that matches a 2-tuple where the
+// first field > the second field.
+inline internal::Gt2Matcher Gt() { return internal::Gt2Matcher(); }
+
+// Creates a polymorphic matcher that matches a 2-tuple where the
+// first field <= the second field.
+inline internal::Le2Matcher Le() { return internal::Le2Matcher(); }
+
+// Creates a polymorphic matcher that matches a 2-tuple where the
+// first field < the second field.
+inline internal::Lt2Matcher Lt() { return internal::Lt2Matcher(); }
+
+// Creates a polymorphic matcher that matches a 2-tuple where the
+// first field != the second field.
+inline internal::Ne2Matcher Ne() { return internal::Ne2Matcher(); }
+
+// Creates a matcher that matches any value of type T that m doesn't
+// match.
+template <typename InnerMatcher>
+inline internal::NotMatcher<InnerMatcher> Not(InnerMatcher m) {
+ return internal::NotMatcher<InnerMatcher>(m);
+}
+
+// Returns a matcher that matches anything that satisfies the given
+// predicate. The predicate can be any unary function or functor
+// whose return type can be implicitly converted to bool.
+template <typename Predicate>
+inline PolymorphicMatcher<internal::TrulyMatcher<Predicate> >
+Truly(Predicate pred) {
+ return MakePolymorphicMatcher(internal::TrulyMatcher<Predicate>(pred));
+}
+
+// Returns a matcher that matches the container size. The container must
+// support both size() and size_type which all STL-like containers provide.
+// Note that the parameter 'size' can be a value of type size_type as well as
+// matcher. For instance:
+// EXPECT_THAT(container, SizeIs(2)); // Checks container has 2 elements.
+// EXPECT_THAT(container, SizeIs(Le(2)); // Checks container has at most 2.
+template <typename SizeMatcher>
+inline internal::SizeIsMatcher<SizeMatcher>
+SizeIs(const SizeMatcher& size_matcher) {
+ return internal::SizeIsMatcher<SizeMatcher>(size_matcher);
+}
+
+// Returns a matcher that matches the distance between the container's begin()
+// iterator and its end() iterator, i.e. the size of the container. This matcher
+// can be used instead of SizeIs with containers such as std::forward_list which
+// do not implement size(). The container must provide const_iterator (with
+// valid iterator_traits), begin() and end().
+template <typename DistanceMatcher>
+inline internal::BeginEndDistanceIsMatcher<DistanceMatcher>
+BeginEndDistanceIs(const DistanceMatcher& distance_matcher) {
+ return internal::BeginEndDistanceIsMatcher<DistanceMatcher>(distance_matcher);
+}
+
+// Returns a matcher that matches an equal container.
+// This matcher behaves like Eq(), but in the event of mismatch lists the
+// values that are included in one container but not the other. (Duplicate
+// values and order differences are not explained.)
+template <typename Container>
+inline PolymorphicMatcher<internal::ContainerEqMatcher< // NOLINT
+ GTEST_REMOVE_CONST_(Container)> >
+ ContainerEq(const Container& rhs) {
+ // This following line is for working around a bug in MSVC 8.0,
+ // which causes Container to be a const type sometimes.
+ typedef GTEST_REMOVE_CONST_(Container) RawContainer;
+ return MakePolymorphicMatcher(
+ internal::ContainerEqMatcher<RawContainer>(rhs));
+}
+
+// Returns a matcher that matches a container that, when sorted using
+// the given comparator, matches container_matcher.
+template <typename Comparator, typename ContainerMatcher>
+inline internal::WhenSortedByMatcher<Comparator, ContainerMatcher>
+WhenSortedBy(const Comparator& comparator,
+ const ContainerMatcher& container_matcher) {
+ return internal::WhenSortedByMatcher<Comparator, ContainerMatcher>(
+ comparator, container_matcher);
+}
+
+// Returns a matcher that matches a container that, when sorted using
+// the < operator, matches container_matcher.
+template <typename ContainerMatcher>
+inline internal::WhenSortedByMatcher<internal::LessComparator, ContainerMatcher>
+WhenSorted(const ContainerMatcher& container_matcher) {
+ return
+ internal::WhenSortedByMatcher<internal::LessComparator, ContainerMatcher>(
+ internal::LessComparator(), container_matcher);
+}
+
+// Matches an STL-style container or a native array that contains the
+// same number of elements as in rhs, where its i-th element and rhs's
+// i-th element (as a pair) satisfy the given pair matcher, for all i.
+// TupleMatcher must be able to be safely cast to Matcher<tuple<const
+// T1&, const T2&> >, where T1 and T2 are the types of elements in the
+// LHS container and the RHS container respectively.
+template <typename TupleMatcher, typename Container>
+inline internal::PointwiseMatcher<TupleMatcher,
+ GTEST_REMOVE_CONST_(Container)>
+Pointwise(const TupleMatcher& tuple_matcher, const Container& rhs) {
+ // This following line is for working around a bug in MSVC 8.0,
+ // which causes Container to be a const type sometimes (e.g. when
+ // rhs is a const int[])..
+ typedef GTEST_REMOVE_CONST_(Container) RawContainer;
+ return internal::PointwiseMatcher<TupleMatcher, RawContainer>(
+ tuple_matcher, rhs);
+}
+
+#if GTEST_HAS_STD_INITIALIZER_LIST_
+
+// Supports the Pointwise(m, {a, b, c}) syntax.
+template <typename TupleMatcher, typename T>
+inline internal::PointwiseMatcher<TupleMatcher, std::vector<T> > Pointwise(
+ const TupleMatcher& tuple_matcher, std::initializer_list<T> rhs) {
+ return Pointwise(tuple_matcher, std::vector<T>(rhs));
+}
+
+#endif // GTEST_HAS_STD_INITIALIZER_LIST_
+
+// UnorderedPointwise(pair_matcher, rhs) matches an STL-style
+// container or a native array that contains the same number of
+// elements as in rhs, where in some permutation of the container, its
+// i-th element and rhs's i-th element (as a pair) satisfy the given
+// pair matcher, for all i. Tuple2Matcher must be able to be safely
+// cast to Matcher<tuple<const T1&, const T2&> >, where T1 and T2 are
+// the types of elements in the LHS container and the RHS container
+// respectively.
+//
+// This is like Pointwise(pair_matcher, rhs), except that the element
+// order doesn't matter.
+template <typename Tuple2Matcher, typename RhsContainer>
+inline internal::UnorderedElementsAreArrayMatcher<
+ typename internal::BoundSecondMatcher<
+ Tuple2Matcher, typename internal::StlContainerView<GTEST_REMOVE_CONST_(
+ RhsContainer)>::type::value_type> >
+UnorderedPointwise(const Tuple2Matcher& tuple2_matcher,
+ const RhsContainer& rhs_container) {
+ // This following line is for working around a bug in MSVC 8.0,
+ // which causes RhsContainer to be a const type sometimes (e.g. when
+ // rhs_container is a const int[]).
+ typedef GTEST_REMOVE_CONST_(RhsContainer) RawRhsContainer;
+
+ // RhsView allows the same code to handle RhsContainer being a
+ // STL-style container and it being a native C-style array.
+ typedef typename internal::StlContainerView<RawRhsContainer> RhsView;
+ typedef typename RhsView::type RhsStlContainer;
+ typedef typename RhsStlContainer::value_type Second;
+ const RhsStlContainer& rhs_stl_container =
+ RhsView::ConstReference(rhs_container);
+
+ // Create a matcher for each element in rhs_container.
+ ::std::vector<internal::BoundSecondMatcher<Tuple2Matcher, Second> > matchers;
+ for (typename RhsStlContainer::const_iterator it = rhs_stl_container.begin();
+ it != rhs_stl_container.end(); ++it) {
+ matchers.push_back(
+ internal::MatcherBindSecond(tuple2_matcher, *it));
+ }
+
+ // Delegate the work to UnorderedElementsAreArray().
+ return UnorderedElementsAreArray(matchers);
+}
+
+#if GTEST_HAS_STD_INITIALIZER_LIST_
+
+// Supports the UnorderedPointwise(m, {a, b, c}) syntax.
+template <typename Tuple2Matcher, typename T>
+inline internal::UnorderedElementsAreArrayMatcher<
+ typename internal::BoundSecondMatcher<Tuple2Matcher, T> >
+UnorderedPointwise(const Tuple2Matcher& tuple2_matcher,
+ std::initializer_list<T> rhs) {
+ return UnorderedPointwise(tuple2_matcher, std::vector<T>(rhs));
+}
+
+#endif // GTEST_HAS_STD_INITIALIZER_LIST_
+
+// Matches an STL-style container or a native array that contains at
+// least one element matching the given value or matcher.
+//
+// Examples:
+// ::std::set<int> page_ids;
+// page_ids.insert(3);
+// page_ids.insert(1);
+// EXPECT_THAT(page_ids, Contains(1));
+// EXPECT_THAT(page_ids, Contains(Gt(2)));
+// EXPECT_THAT(page_ids, Not(Contains(4)));
+//
+// ::std::map<int, size_t> page_lengths;
+// page_lengths[1] = 100;
+// EXPECT_THAT(page_lengths,
+// Contains(::std::pair<const int, size_t>(1, 100)));
+//
+// const char* user_ids[] = { "joe", "mike", "tom" };
+// EXPECT_THAT(user_ids, Contains(Eq(::std::string("tom"))));
+template <typename M>
+inline internal::ContainsMatcher<M> Contains(M matcher) {
+ return internal::ContainsMatcher<M>(matcher);
+}
+
+// Matches an STL-style container or a native array that contains only
+// elements matching the given value or matcher.
+//
+// Each(m) is semantically equivalent to Not(Contains(Not(m))). Only
+// the messages are different.
+//
+// Examples:
+// ::std::set<int> page_ids;
+// // Each(m) matches an empty container, regardless of what m is.
+// EXPECT_THAT(page_ids, Each(Eq(1)));
+// EXPECT_THAT(page_ids, Each(Eq(77)));
+//
+// page_ids.insert(3);
+// EXPECT_THAT(page_ids, Each(Gt(0)));
+// EXPECT_THAT(page_ids, Not(Each(Gt(4))));
+// page_ids.insert(1);
+// EXPECT_THAT(page_ids, Not(Each(Lt(2))));
+//
+// ::std::map<int, size_t> page_lengths;
+// page_lengths[1] = 100;
+// page_lengths[2] = 200;
+// page_lengths[3] = 300;
+// EXPECT_THAT(page_lengths, Not(Each(Pair(1, 100))));
+// EXPECT_THAT(page_lengths, Each(Key(Le(3))));
+//
+// const char* user_ids[] = { "joe", "mike", "tom" };
+// EXPECT_THAT(user_ids, Not(Each(Eq(::std::string("tom")))));
+template <typename M>
+inline internal::EachMatcher<M> Each(M matcher) {
+ return internal::EachMatcher<M>(matcher);
+}
+
+// Key(inner_matcher) matches an std::pair whose 'first' field matches
+// inner_matcher. For example, Contains(Key(Ge(5))) can be used to match an
+// std::map that contains at least one element whose key is >= 5.
+template <typename M>
+inline internal::KeyMatcher<M> Key(M inner_matcher) {
+ return internal::KeyMatcher<M>(inner_matcher);
+}
+
+// Pair(first_matcher, second_matcher) matches a std::pair whose 'first' field
+// matches first_matcher and whose 'second' field matches second_matcher. For
+// example, EXPECT_THAT(map_type, ElementsAre(Pair(Ge(5), "foo"))) can be used
+// to match a std::map<int, string> that contains exactly one element whose key
+// is >= 5 and whose value equals "foo".
+template <typename FirstMatcher, typename SecondMatcher>
+inline internal::PairMatcher<FirstMatcher, SecondMatcher>
+Pair(FirstMatcher first_matcher, SecondMatcher second_matcher) {
+ return internal::PairMatcher<FirstMatcher, SecondMatcher>(
+ first_matcher, second_matcher);
+}
+
+// Returns a predicate that is satisfied by anything that matches the
+// given matcher.
+template <typename M>
+inline internal::MatcherAsPredicate<M> Matches(M matcher) {
+ return internal::MatcherAsPredicate<M>(matcher);
+}
+
+// Returns true iff the value matches the matcher.
+template <typename T, typename M>
+inline bool Value(const T& value, M matcher) {
+ return testing::Matches(matcher)(value);
+}
+
+// Matches the value against the given matcher and explains the match
+// result to listener.
+template <typename T, typename M>
+inline bool ExplainMatchResult(
+ M matcher, const T& value, MatchResultListener* listener) {
+ return SafeMatcherCast<const T&>(matcher).MatchAndExplain(value, listener);
+}
+
+#if GTEST_LANG_CXX11
+// Define variadic matcher versions. They are overloaded in
+// gmock-generated-matchers.h for the cases supported by pre C++11 compilers.
+template <typename... Args>
+inline internal::AllOfMatcher<Args...> AllOf(const Args&... matchers) {
+ return internal::AllOfMatcher<Args...>(matchers...);
+}
+
+template <typename... Args>
+inline internal::AnyOfMatcher<Args...> AnyOf(const Args&... matchers) {
+ return internal::AnyOfMatcher<Args...>(matchers...);
+}
+
+#endif // GTEST_LANG_CXX11
+
+// AllArgs(m) is a synonym of m. This is useful in
+//
+// EXPECT_CALL(foo, Bar(_, _)).With(AllArgs(Eq()));
+//
+// which is easier to read than
+//
+// EXPECT_CALL(foo, Bar(_, _)).With(Eq());
+template <typename InnerMatcher>
+inline InnerMatcher AllArgs(const InnerMatcher& matcher) { return matcher; }
+
+// These macros allow using matchers to check values in Google Test
+// tests. ASSERT_THAT(value, matcher) and EXPECT_THAT(value, matcher)
+// succeed iff the value matches the matcher. If the assertion fails,
+// the value and the description of the matcher will be printed.
+#define ASSERT_THAT(value, matcher) ASSERT_PRED_FORMAT1(\
+ ::testing::internal::MakePredicateFormatterFromMatcher(matcher), value)
+#define EXPECT_THAT(value, matcher) EXPECT_PRED_FORMAT1(\
+ ::testing::internal::MakePredicateFormatterFromMatcher(matcher), value)
+
+} // namespace testing
+
+// Include any custom callback matchers added by the local installation.
+// We must include this header at the end to make sure it can use the
+// declarations from this file.
+#include "gmock/internal/custom/gmock-matchers.h"
+#endif // GMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_
diff --git a/extern/gmock/include/gmock/gmock-more-actions.h b/extern/gmock/include/gmock/gmock-more-actions.h
new file mode 100644
index 00000000000..3d387b6b7d7
--- /dev/null
+++ b/extern/gmock/include/gmock/gmock-more-actions.h
@@ -0,0 +1,246 @@
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Google Mock - a framework for writing C++ mock classes.
+//
+// This file implements some actions that depend on gmock-generated-actions.h.
+
+#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_MORE_ACTIONS_H_
+#define GMOCK_INCLUDE_GMOCK_GMOCK_MORE_ACTIONS_H_
+
+#include <algorithm>
+
+#include "gmock/gmock-generated-actions.h"
+
+namespace testing {
+namespace internal {
+
+// Implements the Invoke(f) action. The template argument
+// FunctionImpl is the implementation type of f, which can be either a
+// function pointer or a functor. Invoke(f) can be used as an
+// Action<F> as long as f's type is compatible with F (i.e. f can be
+// assigned to a tr1::function<F>).
+template <typename FunctionImpl>
+class InvokeAction {
+ public:
+ // The c'tor makes a copy of function_impl (either a function
+ // pointer or a functor).
+ explicit InvokeAction(FunctionImpl function_impl)
+ : function_impl_(function_impl) {}
+
+ template <typename Result, typename ArgumentTuple>
+ Result Perform(const ArgumentTuple& args) {
+ return InvokeHelper<Result, ArgumentTuple>::Invoke(function_impl_, args);
+ }
+
+ private:
+ FunctionImpl function_impl_;
+
+ GTEST_DISALLOW_ASSIGN_(InvokeAction);
+};
+
+// Implements the Invoke(object_ptr, &Class::Method) action.
+template <class Class, typename MethodPtr>
+class InvokeMethodAction {
+ public:
+ InvokeMethodAction(Class* obj_ptr, MethodPtr method_ptr)
+ : method_ptr_(method_ptr), obj_ptr_(obj_ptr) {}
+
+ template <typename Result, typename ArgumentTuple>
+ Result Perform(const ArgumentTuple& args) const {
+ return InvokeHelper<Result, ArgumentTuple>::InvokeMethod(
+ obj_ptr_, method_ptr_, args);
+ }
+
+ private:
+ // The order of these members matters. Reversing the order can trigger
+ // warning C4121 in MSVC (see
+ // http://computer-programming-forum.com/7-vc.net/6fbc30265f860ad1.htm ).
+ const MethodPtr method_ptr_;
+ Class* const obj_ptr_;
+
+ GTEST_DISALLOW_ASSIGN_(InvokeMethodAction);
+};
+
+// An internal replacement for std::copy which mimics its behavior. This is
+// necessary because Visual Studio deprecates ::std::copy, issuing warning 4996.
+// However Visual Studio 2010 and later do not honor #pragmas which disable that
+// warning.
+template<typename InputIterator, typename OutputIterator>
+inline OutputIterator CopyElements(InputIterator first,
+ InputIterator last,
+ OutputIterator output) {
+ for (; first != last; ++first, ++output) {
+ *output = *first;
+ }
+ return output;
+}
+
+} // namespace internal
+
+// Various overloads for Invoke().
+
+// Creates an action that invokes 'function_impl' with the mock
+// function's arguments.
+template <typename FunctionImpl>
+PolymorphicAction<internal::InvokeAction<FunctionImpl> > Invoke(
+ FunctionImpl function_impl) {
+ return MakePolymorphicAction(
+ internal::InvokeAction<FunctionImpl>(function_impl));
+}
+
+// Creates an action that invokes the given method on the given object
+// with the mock function's arguments.
+template <class Class, typename MethodPtr>
+PolymorphicAction<internal::InvokeMethodAction<Class, MethodPtr> > Invoke(
+ Class* obj_ptr, MethodPtr method_ptr) {
+ return MakePolymorphicAction(
+ internal::InvokeMethodAction<Class, MethodPtr>(obj_ptr, method_ptr));
+}
+
+// WithoutArgs(inner_action) can be used in a mock function with a
+// non-empty argument list to perform inner_action, which takes no
+// argument. In other words, it adapts an action accepting no
+// argument to one that accepts (and ignores) arguments.
+template <typename InnerAction>
+inline internal::WithArgsAction<InnerAction>
+WithoutArgs(const InnerAction& action) {
+ return internal::WithArgsAction<InnerAction>(action);
+}
+
+// WithArg<k>(an_action) creates an action that passes the k-th
+// (0-based) argument of the mock function to an_action and performs
+// it. It adapts an action accepting one argument to one that accepts
+// multiple arguments. For convenience, we also provide
+// WithArgs<k>(an_action) (defined below) as a synonym.
+template <int k, typename InnerAction>
+inline internal::WithArgsAction<InnerAction, k>
+WithArg(const InnerAction& action) {
+ return internal::WithArgsAction<InnerAction, k>(action);
+}
+
+// The ACTION*() macros trigger warning C4100 (unreferenced formal
+// parameter) in MSVC with -W4. Unfortunately they cannot be fixed in
+// the macro definition, as the warnings are generated when the macro
+// is expanded and macro expansion cannot contain #pragma. Therefore
+// we suppress them here.
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable:4100)
+#endif
+
+// Action ReturnArg<k>() returns the k-th argument of the mock function.
+ACTION_TEMPLATE(ReturnArg,
+ HAS_1_TEMPLATE_PARAMS(int, k),
+ AND_0_VALUE_PARAMS()) {
+ return ::testing::get<k>(args);
+}
+
+// Action SaveArg<k>(pointer) saves the k-th (0-based) argument of the
+// mock function to *pointer.
+ACTION_TEMPLATE(SaveArg,
+ HAS_1_TEMPLATE_PARAMS(int, k),
+ AND_1_VALUE_PARAMS(pointer)) {
+ *pointer = ::testing::get<k>(args);
+}
+
+// Action SaveArgPointee<k>(pointer) saves the value pointed to
+// by the k-th (0-based) argument of the mock function to *pointer.
+ACTION_TEMPLATE(SaveArgPointee,
+ HAS_1_TEMPLATE_PARAMS(int, k),
+ AND_1_VALUE_PARAMS(pointer)) {
+ *pointer = *::testing::get<k>(args);
+}
+
+// Action SetArgReferee<k>(value) assigns 'value' to the variable
+// referenced by the k-th (0-based) argument of the mock function.
+ACTION_TEMPLATE(SetArgReferee,
+ HAS_1_TEMPLATE_PARAMS(int, k),
+ AND_1_VALUE_PARAMS(value)) {
+ typedef typename ::testing::tuple_element<k, args_type>::type argk_type;
+ // Ensures that argument #k is a reference. If you get a compiler
+ // error on the next line, you are using SetArgReferee<k>(value) in
+ // a mock function whose k-th (0-based) argument is not a reference.
+ GTEST_COMPILE_ASSERT_(internal::is_reference<argk_type>::value,
+ SetArgReferee_must_be_used_with_a_reference_argument);
+ ::testing::get<k>(args) = value;
+}
+
+// Action SetArrayArgument<k>(first, last) copies the elements in
+// source range [first, last) to the array pointed to by the k-th
+// (0-based) argument, which can be either a pointer or an
+// iterator. The action does not take ownership of the elements in the
+// source range.
+ACTION_TEMPLATE(SetArrayArgument,
+ HAS_1_TEMPLATE_PARAMS(int, k),
+ AND_2_VALUE_PARAMS(first, last)) {
+ // Visual Studio deprecates ::std::copy, so we use our own copy in that case.
+#ifdef _MSC_VER
+ internal::CopyElements(first, last, ::testing::get<k>(args));
+#else
+ ::std::copy(first, last, ::testing::get<k>(args));
+#endif
+}
+
+// Action DeleteArg<k>() deletes the k-th (0-based) argument of the mock
+// function.
+ACTION_TEMPLATE(DeleteArg,
+ HAS_1_TEMPLATE_PARAMS(int, k),
+ AND_0_VALUE_PARAMS()) {
+ delete ::testing::get<k>(args);
+}
+
+// This action returns the value pointed to by 'pointer'.
+ACTION_P(ReturnPointee, pointer) { return *pointer; }
+
+// Action Throw(exception) can be used in a mock function of any type
+// to throw the given exception. Any copyable value can be thrown.
+#if GTEST_HAS_EXCEPTIONS
+
+// Suppresses the 'unreachable code' warning that VC generates in opt modes.
+# ifdef _MSC_VER
+# pragma warning(push) // Saves the current warning state.
+# pragma warning(disable:4702) // Temporarily disables warning 4702.
+# endif
+ACTION_P(Throw, exception) { throw exception; }
+# ifdef _MSC_VER
+# pragma warning(pop) // Restores the warning state.
+# endif
+
+#endif // GTEST_HAS_EXCEPTIONS
+
+#ifdef _MSC_VER
+# pragma warning(pop)
+#endif
+
+} // namespace testing
+
+#endif // GMOCK_INCLUDE_GMOCK_GMOCK_MORE_ACTIONS_H_
diff --git a/extern/gmock/include/gmock/gmock-more-matchers.h b/extern/gmock/include/gmock/gmock-more-matchers.h
new file mode 100644
index 00000000000..3db899f4297
--- /dev/null
+++ b/extern/gmock/include/gmock/gmock-more-matchers.h
@@ -0,0 +1,58 @@
+// Copyright 2013, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: marcus.boerger@google.com (Marcus Boerger)
+
+// Google Mock - a framework for writing C++ mock classes.
+//
+// This file implements some matchers that depend on gmock-generated-matchers.h.
+//
+// Note that tests are implemented in gmock-matchers_test.cc rather than
+// gmock-more-matchers-test.cc.
+
+#ifndef GMOCK_GMOCK_MORE_MATCHERS_H_
+#define GMOCK_GMOCK_MORE_MATCHERS_H_
+
+#include "gmock/gmock-generated-matchers.h"
+
+namespace testing {
+
+// Defines a matcher that matches an empty container. The container must
+// support both size() and empty(), which all STL-like containers provide.
+MATCHER(IsEmpty, negation ? "isn't empty" : "is empty") {
+ if (arg.empty()) {
+ return true;
+ }
+ *result_listener << "whose size is " << arg.size();
+ return false;
+}
+
+} // namespace testing
+
+#endif // GMOCK_GMOCK_MORE_MATCHERS_H_
diff --git a/extern/gmock/include/gmock/gmock-spec-builders.h b/extern/gmock/include/gmock/gmock-spec-builders.h
new file mode 100644
index 00000000000..fed7de66bc4
--- /dev/null
+++ b/extern/gmock/include/gmock/gmock-spec-builders.h
@@ -0,0 +1,1847 @@
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Google Mock - a framework for writing C++ mock classes.
+//
+// This file implements the ON_CALL() and EXPECT_CALL() macros.
+//
+// A user can use the ON_CALL() macro to specify the default action of
+// a mock method. The syntax is:
+//
+// ON_CALL(mock_object, Method(argument-matchers))
+// .With(multi-argument-matcher)
+// .WillByDefault(action);
+//
+// where the .With() clause is optional.
+//
+// A user can use the EXPECT_CALL() macro to specify an expectation on
+// a mock method. The syntax is:
+//
+// EXPECT_CALL(mock_object, Method(argument-matchers))
+// .With(multi-argument-matchers)
+// .Times(cardinality)
+// .InSequence(sequences)
+// .After(expectations)
+// .WillOnce(action)
+// .WillRepeatedly(action)
+// .RetiresOnSaturation();
+//
+// where all clauses are optional, and .InSequence()/.After()/
+// .WillOnce() can appear any number of times.
+
+#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_SPEC_BUILDERS_H_
+#define GMOCK_INCLUDE_GMOCK_GMOCK_SPEC_BUILDERS_H_
+
+#include <map>
+#include <set>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#if GTEST_HAS_EXCEPTIONS
+# include <stdexcept> // NOLINT
+#endif
+
+#include "gmock/gmock-actions.h"
+#include "gmock/gmock-cardinalities.h"
+#include "gmock/gmock-matchers.h"
+#include "gmock/internal/gmock-internal-utils.h"
+#include "gmock/internal/gmock-port.h"
+#include "gtest/gtest.h"
+
+namespace testing {
+
+// An abstract handle of an expectation.
+class Expectation;
+
+// A set of expectation handles.
+class ExpectationSet;
+
+// Anything inside the 'internal' namespace IS INTERNAL IMPLEMENTATION
+// and MUST NOT BE USED IN USER CODE!!!
+namespace internal {
+
+// Implements a mock function.
+template <typename F> class FunctionMocker;
+
+// Base class for expectations.
+class ExpectationBase;
+
+// Implements an expectation.
+template <typename F> class TypedExpectation;
+
+// Helper class for testing the Expectation class template.
+class ExpectationTester;
+
+// Base class for function mockers.
+template <typename F> class FunctionMockerBase;
+
+// Protects the mock object registry (in class Mock), all function
+// mockers, and all expectations.
+//
+// The reason we don't use more fine-grained protection is: when a
+// mock function Foo() is called, it needs to consult its expectations
+// to see which one should be picked. If another thread is allowed to
+// call a mock function (either Foo() or a different one) at the same
+// time, it could affect the "retired" attributes of Foo()'s
+// expectations when InSequence() is used, and thus affect which
+// expectation gets picked. Therefore, we sequence all mock function
+// calls to ensure the integrity of the mock objects' states.
+GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_gmock_mutex);
+
+// Untyped base class for ActionResultHolder<R>.
+class UntypedActionResultHolderBase;
+
+// Abstract base class of FunctionMockerBase. This is the
+// type-agnostic part of the function mocker interface. Its pure
+// virtual methods are implemented by FunctionMockerBase.
+class GTEST_API_ UntypedFunctionMockerBase {
+ public:
+ UntypedFunctionMockerBase();
+ virtual ~UntypedFunctionMockerBase();
+
+ // Verifies that all expectations on this mock function have been
+ // satisfied. Reports one or more Google Test non-fatal failures
+ // and returns false if not.
+ bool VerifyAndClearExpectationsLocked()
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex);
+
+ // Clears the ON_CALL()s set on this mock function.
+ virtual void ClearDefaultActionsLocked()
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) = 0;
+
+ // In all of the following Untyped* functions, it's the caller's
+ // responsibility to guarantee the correctness of the arguments'
+ // types.
+
+ // Performs the default action with the given arguments and returns
+ // the action's result. The call description string will be used in
+ // the error message to describe the call in the case the default
+ // action fails.
+ // L = *
+ virtual UntypedActionResultHolderBase* UntypedPerformDefaultAction(
+ const void* untyped_args,
+ const string& call_description) const = 0;
+
+ // Performs the given action with the given arguments and returns
+ // the action's result.
+ // L = *
+ virtual UntypedActionResultHolderBase* UntypedPerformAction(
+ const void* untyped_action,
+ const void* untyped_args) const = 0;
+
+ // Writes a message that the call is uninteresting (i.e. neither
+ // explicitly expected nor explicitly unexpected) to the given
+ // ostream.
+ virtual void UntypedDescribeUninterestingCall(
+ const void* untyped_args,
+ ::std::ostream* os) const
+ GTEST_LOCK_EXCLUDED_(g_gmock_mutex) = 0;
+
+ // Returns the expectation that matches the given function arguments
+ // (or NULL is there's no match); when a match is found,
+ // untyped_action is set to point to the action that should be
+ // performed (or NULL if the action is "do default"), and
+ // is_excessive is modified to indicate whether the call exceeds the
+ // expected number.
+ virtual const ExpectationBase* UntypedFindMatchingExpectation(
+ const void* untyped_args,
+ const void** untyped_action, bool* is_excessive,
+ ::std::ostream* what, ::std::ostream* why)
+ GTEST_LOCK_EXCLUDED_(g_gmock_mutex) = 0;
+
+ // Prints the given function arguments to the ostream.
+ virtual void UntypedPrintArgs(const void* untyped_args,
+ ::std::ostream* os) const = 0;
+
+ // Sets the mock object this mock method belongs to, and registers
+ // this information in the global mock registry. Will be called
+ // whenever an EXPECT_CALL() or ON_CALL() is executed on this mock
+ // method.
+ // TODO(wan@google.com): rename to SetAndRegisterOwner().
+ void RegisterOwner(const void* mock_obj)
+ GTEST_LOCK_EXCLUDED_(g_gmock_mutex);
+
+ // Sets the mock object this mock method belongs to, and sets the
+ // name of the mock function. Will be called upon each invocation
+ // of this mock function.
+ void SetOwnerAndName(const void* mock_obj, const char* name)
+ GTEST_LOCK_EXCLUDED_(g_gmock_mutex);
+
+ // Returns the mock object this mock method belongs to. Must be
+ // called after RegisterOwner() or SetOwnerAndName() has been
+ // called.
+ const void* MockObject() const
+ GTEST_LOCK_EXCLUDED_(g_gmock_mutex);
+
+ // Returns the name of this mock method. Must be called after
+ // SetOwnerAndName() has been called.
+ const char* Name() const
+ GTEST_LOCK_EXCLUDED_(g_gmock_mutex);
+
+ // Returns the result of invoking this mock function with the given
+ // arguments. This function can be safely called from multiple
+ // threads concurrently. The caller is responsible for deleting the
+ // result.
+ UntypedActionResultHolderBase* UntypedInvokeWith(
+ const void* untyped_args)
+ GTEST_LOCK_EXCLUDED_(g_gmock_mutex);
+
+ protected:
+ typedef std::vector<const void*> UntypedOnCallSpecs;
+
+ typedef std::vector<internal::linked_ptr<ExpectationBase> >
+ UntypedExpectations;
+
+ // Returns an Expectation object that references and co-owns exp,
+ // which must be an expectation on this mock function.
+ Expectation GetHandleOf(ExpectationBase* exp);
+
+ // Address of the mock object this mock method belongs to. Only
+ // valid after this mock method has been called or
+ // ON_CALL/EXPECT_CALL has been invoked on it.
+ const void* mock_obj_; // Protected by g_gmock_mutex.
+
+ // Name of the function being mocked. Only valid after this mock
+ // method has been called.
+ const char* name_; // Protected by g_gmock_mutex.
+
+ // All default action specs for this function mocker.
+ UntypedOnCallSpecs untyped_on_call_specs_;
+
+ // All expectations for this function mocker.
+ UntypedExpectations untyped_expectations_;
+}; // class UntypedFunctionMockerBase
+
+// Untyped base class for OnCallSpec<F>.
+class UntypedOnCallSpecBase {
+ public:
+ // The arguments are the location of the ON_CALL() statement.
+ UntypedOnCallSpecBase(const char* a_file, int a_line)
+ : file_(a_file), line_(a_line), last_clause_(kNone) {}
+
+ // Where in the source file was the default action spec defined?
+ const char* file() const { return file_; }
+ int line() const { return line_; }
+
+ protected:
+ // Gives each clause in the ON_CALL() statement a name.
+ enum Clause {
+ // Do not change the order of the enum members! The run-time
+ // syntax checking relies on it.
+ kNone,
+ kWith,
+ kWillByDefault
+ };
+
+ // Asserts that the ON_CALL() statement has a certain property.
+ void AssertSpecProperty(bool property, const string& failure_message) const {
+ Assert(property, file_, line_, failure_message);
+ }
+
+ // Expects that the ON_CALL() statement has a certain property.
+ void ExpectSpecProperty(bool property, const string& failure_message) const {
+ Expect(property, file_, line_, failure_message);
+ }
+
+ const char* file_;
+ int line_;
+
+ // The last clause in the ON_CALL() statement as seen so far.
+ // Initially kNone and changes as the statement is parsed.
+ Clause last_clause_;
+}; // class UntypedOnCallSpecBase
+
+// This template class implements an ON_CALL spec.
+template <typename F>
+class OnCallSpec : public UntypedOnCallSpecBase {
+ public:
+ typedef typename Function<F>::ArgumentTuple ArgumentTuple;
+ typedef typename Function<F>::ArgumentMatcherTuple ArgumentMatcherTuple;
+
+ // Constructs an OnCallSpec object from the information inside
+ // the parenthesis of an ON_CALL() statement.
+ OnCallSpec(const char* a_file, int a_line,
+ const ArgumentMatcherTuple& matchers)
+ : UntypedOnCallSpecBase(a_file, a_line),
+ matchers_(matchers),
+ // By default, extra_matcher_ should match anything. However,
+ // we cannot initialize it with _ as that triggers a compiler
+ // bug in Symbian's C++ compiler (cannot decide between two
+ // overloaded constructors of Matcher<const ArgumentTuple&>).
+ extra_matcher_(A<const ArgumentTuple&>()) {
+ }
+
+ // Implements the .With() clause.
+ OnCallSpec& With(const Matcher<const ArgumentTuple&>& m) {
+ // Makes sure this is called at most once.
+ ExpectSpecProperty(last_clause_ < kWith,
+ ".With() cannot appear "
+ "more than once in an ON_CALL().");
+ last_clause_ = kWith;
+
+ extra_matcher_ = m;
+ return *this;
+ }
+
+ // Implements the .WillByDefault() clause.
+ OnCallSpec& WillByDefault(const Action<F>& action) {
+ ExpectSpecProperty(last_clause_ < kWillByDefault,
+ ".WillByDefault() must appear "
+ "exactly once in an ON_CALL().");
+ last_clause_ = kWillByDefault;
+
+ ExpectSpecProperty(!action.IsDoDefault(),
+ "DoDefault() cannot be used in ON_CALL().");
+ action_ = action;
+ return *this;
+ }
+
+ // Returns true iff the given arguments match the matchers.
+ bool Matches(const ArgumentTuple& args) const {
+ return TupleMatches(matchers_, args) && extra_matcher_.Matches(args);
+ }
+
+ // Returns the action specified by the user.
+ const Action<F>& GetAction() const {
+ AssertSpecProperty(last_clause_ == kWillByDefault,
+ ".WillByDefault() must appear exactly "
+ "once in an ON_CALL().");
+ return action_;
+ }
+
+ private:
+ // The information in statement
+ //
+ // ON_CALL(mock_object, Method(matchers))
+ // .With(multi-argument-matcher)
+ // .WillByDefault(action);
+ //
+ // is recorded in the data members like this:
+ //
+ // source file that contains the statement => file_
+ // line number of the statement => line_
+ // matchers => matchers_
+ // multi-argument-matcher => extra_matcher_
+ // action => action_
+ ArgumentMatcherTuple matchers_;
+ Matcher<const ArgumentTuple&> extra_matcher_;
+ Action<F> action_;
+}; // class OnCallSpec
+
+// Possible reactions on uninteresting calls.
+enum CallReaction {
+ kAllow,
+ kWarn,
+ kFail,
+ kDefault = kWarn // By default, warn about uninteresting calls.
+};
+
+} // namespace internal
+
+// Utilities for manipulating mock objects.
+class GTEST_API_ Mock {
+ public:
+ // The following public methods can be called concurrently.
+
+ // Tells Google Mock to ignore mock_obj when checking for leaked
+ // mock objects.
+ static void AllowLeak(const void* mock_obj)
+ GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex);
+
+ // Verifies and clears all expectations on the given mock object.
+ // If the expectations aren't satisfied, generates one or more
+ // Google Test non-fatal failures and returns false.
+ static bool VerifyAndClearExpectations(void* mock_obj)
+ GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex);
+
+ // Verifies all expectations on the given mock object and clears its
+ // default actions and expectations. Returns true iff the
+ // verification was successful.
+ static bool VerifyAndClear(void* mock_obj)
+ GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex);
+
+ private:
+ friend class internal::UntypedFunctionMockerBase;
+
+ // Needed for a function mocker to register itself (so that we know
+ // how to clear a mock object).
+ template <typename F>
+ friend class internal::FunctionMockerBase;
+
+ template <typename M>
+ friend class NiceMock;
+
+ template <typename M>
+ friend class NaggyMock;
+
+ template <typename M>
+ friend class StrictMock;
+
+ // Tells Google Mock to allow uninteresting calls on the given mock
+ // object.
+ static void AllowUninterestingCalls(const void* mock_obj)
+ GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex);
+
+ // Tells Google Mock to warn the user about uninteresting calls on
+ // the given mock object.
+ static void WarnUninterestingCalls(const void* mock_obj)
+ GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex);
+
+ // Tells Google Mock to fail uninteresting calls on the given mock
+ // object.
+ static void FailUninterestingCalls(const void* mock_obj)
+ GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex);
+
+ // Tells Google Mock the given mock object is being destroyed and
+ // its entry in the call-reaction table should be removed.
+ static void UnregisterCallReaction(const void* mock_obj)
+ GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex);
+
+ // Returns the reaction Google Mock will have on uninteresting calls
+ // made on the given mock object.
+ static internal::CallReaction GetReactionOnUninterestingCalls(
+ const void* mock_obj)
+ GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex);
+
+ // Verifies that all expectations on the given mock object have been
+ // satisfied. Reports one or more Google Test non-fatal failures
+ // and returns false if not.
+ static bool VerifyAndClearExpectationsLocked(void* mock_obj)
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(internal::g_gmock_mutex);
+
+ // Clears all ON_CALL()s set on the given mock object.
+ static void ClearDefaultActionsLocked(void* mock_obj)
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(internal::g_gmock_mutex);
+
+ // Registers a mock object and a mock method it owns.
+ static void Register(
+ const void* mock_obj,
+ internal::UntypedFunctionMockerBase* mocker)
+ GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex);
+
+ // Tells Google Mock where in the source code mock_obj is used in an
+ // ON_CALL or EXPECT_CALL. In case mock_obj is leaked, this
+ // information helps the user identify which object it is.
+ static void RegisterUseByOnCallOrExpectCall(
+ const void* mock_obj, const char* file, int line)
+ GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex);
+
+ // Unregisters a mock method; removes the owning mock object from
+ // the registry when the last mock method associated with it has
+ // been unregistered. This is called only in the destructor of
+ // FunctionMockerBase.
+ static void UnregisterLocked(internal::UntypedFunctionMockerBase* mocker)
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(internal::g_gmock_mutex);
+}; // class Mock
+
+// An abstract handle of an expectation. Useful in the .After()
+// clause of EXPECT_CALL() for setting the (partial) order of
+// expectations. The syntax:
+//
+// Expectation e1 = EXPECT_CALL(...)...;
+// EXPECT_CALL(...).After(e1)...;
+//
+// sets two expectations where the latter can only be matched after
+// the former has been satisfied.
+//
+// Notes:
+// - This class is copyable and has value semantics.
+// - Constness is shallow: a const Expectation object itself cannot
+// be modified, but the mutable methods of the ExpectationBase
+// object it references can be called via expectation_base().
+// - The constructors and destructor are defined out-of-line because
+// the Symbian WINSCW compiler wants to otherwise instantiate them
+// when it sees this class definition, at which point it doesn't have
+// ExpectationBase available yet, leading to incorrect destruction
+// in the linked_ptr (or compilation errors if using a checking
+// linked_ptr).
+class GTEST_API_ Expectation {
+ public:
+ // Constructs a null object that doesn't reference any expectation.
+ Expectation();
+
+ ~Expectation();
+
+ // This single-argument ctor must not be explicit, in order to support the
+ // Expectation e = EXPECT_CALL(...);
+ // syntax.
+ //
+ // A TypedExpectation object stores its pre-requisites as
+ // Expectation objects, and needs to call the non-const Retire()
+ // method on the ExpectationBase objects they reference. Therefore
+ // Expectation must receive a *non-const* reference to the
+ // ExpectationBase object.
+ Expectation(internal::ExpectationBase& exp); // NOLINT
+
+ // The compiler-generated copy ctor and operator= work exactly as
+ // intended, so we don't need to define our own.
+
+ // Returns true iff rhs references the same expectation as this object does.
+ bool operator==(const Expectation& rhs) const {
+ return expectation_base_ == rhs.expectation_base_;
+ }
+
+ bool operator!=(const Expectation& rhs) const { return !(*this == rhs); }
+
+ private:
+ friend class ExpectationSet;
+ friend class Sequence;
+ friend class ::testing::internal::ExpectationBase;
+ friend class ::testing::internal::UntypedFunctionMockerBase;
+
+ template <typename F>
+ friend class ::testing::internal::FunctionMockerBase;
+
+ template <typename F>
+ friend class ::testing::internal::TypedExpectation;
+
+ // This comparator is needed for putting Expectation objects into a set.
+ class Less {
+ public:
+ bool operator()(const Expectation& lhs, const Expectation& rhs) const {
+ return lhs.expectation_base_.get() < rhs.expectation_base_.get();
+ }
+ };
+
+ typedef ::std::set<Expectation, Less> Set;
+
+ Expectation(
+ const internal::linked_ptr<internal::ExpectationBase>& expectation_base);
+
+ // Returns the expectation this object references.
+ const internal::linked_ptr<internal::ExpectationBase>&
+ expectation_base() const {
+ return expectation_base_;
+ }
+
+ // A linked_ptr that co-owns the expectation this handle references.
+ internal::linked_ptr<internal::ExpectationBase> expectation_base_;
+};
+
+// A set of expectation handles. Useful in the .After() clause of
+// EXPECT_CALL() for setting the (partial) order of expectations. The
+// syntax:
+//
+// ExpectationSet es;
+// es += EXPECT_CALL(...)...;
+// es += EXPECT_CALL(...)...;
+// EXPECT_CALL(...).After(es)...;
+//
+// sets three expectations where the last one can only be matched
+// after the first two have both been satisfied.
+//
+// This class is copyable and has value semantics.
+class ExpectationSet {
+ public:
+ // A bidirectional iterator that can read a const element in the set.
+ typedef Expectation::Set::const_iterator const_iterator;
+
+ // An object stored in the set. This is an alias of Expectation.
+ typedef Expectation::Set::value_type value_type;
+
+ // Constructs an empty set.
+ ExpectationSet() {}
+
+ // This single-argument ctor must not be explicit, in order to support the
+ // ExpectationSet es = EXPECT_CALL(...);
+ // syntax.
+ ExpectationSet(internal::ExpectationBase& exp) { // NOLINT
+ *this += Expectation(exp);
+ }
+
+ // This single-argument ctor implements implicit conversion from
+ // Expectation and thus must not be explicit. This allows either an
+ // Expectation or an ExpectationSet to be used in .After().
+ ExpectationSet(const Expectation& e) { // NOLINT
+ *this += e;
+ }
+
+ // The compiler-generator ctor and operator= works exactly as
+ // intended, so we don't need to define our own.
+
+ // Returns true iff rhs contains the same set of Expectation objects
+ // as this does.
+ bool operator==(const ExpectationSet& rhs) const {
+ return expectations_ == rhs.expectations_;
+ }
+
+ bool operator!=(const ExpectationSet& rhs) const { return !(*this == rhs); }
+
+ // Implements the syntax
+ // expectation_set += EXPECT_CALL(...);
+ ExpectationSet& operator+=(const Expectation& e) {
+ expectations_.insert(e);
+ return *this;
+ }
+
+ int size() const { return static_cast<int>(expectations_.size()); }
+
+ const_iterator begin() const { return expectations_.begin(); }
+ const_iterator end() const { return expectations_.end(); }
+
+ private:
+ Expectation::Set expectations_;
+};
+
+
+// Sequence objects are used by a user to specify the relative order
+// in which the expectations should match. They are copyable (we rely
+// on the compiler-defined copy constructor and assignment operator).
+class GTEST_API_ Sequence {
+ public:
+ // Constructs an empty sequence.
+ Sequence() : last_expectation_(new Expectation) {}
+
+ // Adds an expectation to this sequence. The caller must ensure
+ // that no other thread is accessing this Sequence object.
+ void AddExpectation(const Expectation& expectation) const;
+
+ private:
+ // The last expectation in this sequence. We use a linked_ptr here
+ // because Sequence objects are copyable and we want the copies to
+ // be aliases. The linked_ptr allows the copies to co-own and share
+ // the same Expectation object.
+ internal::linked_ptr<Expectation> last_expectation_;
+}; // class Sequence
+
+// An object of this type causes all EXPECT_CALL() statements
+// encountered in its scope to be put in an anonymous sequence. The
+// work is done in the constructor and destructor. You should only
+// create an InSequence object on the stack.
+//
+// The sole purpose for this class is to support easy definition of
+// sequential expectations, e.g.
+//
+// {
+// InSequence dummy; // The name of the object doesn't matter.
+//
+// // The following expectations must match in the order they appear.
+// EXPECT_CALL(a, Bar())...;
+// EXPECT_CALL(a, Baz())...;
+// ...
+// EXPECT_CALL(b, Xyz())...;
+// }
+//
+// You can create InSequence objects in multiple threads, as long as
+// they are used to affect different mock objects. The idea is that
+// each thread can create and set up its own mocks as if it's the only
+// thread. However, for clarity of your tests we recommend you to set
+// up mocks in the main thread unless you have a good reason not to do
+// so.
+class GTEST_API_ InSequence {
+ public:
+ InSequence();
+ ~InSequence();
+ private:
+ bool sequence_created_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(InSequence); // NOLINT
+} GTEST_ATTRIBUTE_UNUSED_;
+
+namespace internal {
+
+// Points to the implicit sequence introduced by a living InSequence
+// object (if any) in the current thread or NULL.
+GTEST_API_ extern ThreadLocal<Sequence*> g_gmock_implicit_sequence;
+
+// Base class for implementing expectations.
+//
+// There are two reasons for having a type-agnostic base class for
+// Expectation:
+//
+// 1. We need to store collections of expectations of different
+// types (e.g. all pre-requisites of a particular expectation, all
+// expectations in a sequence). Therefore these expectation objects
+// must share a common base class.
+//
+// 2. We can avoid binary code bloat by moving methods not depending
+// on the template argument of Expectation to the base class.
+//
+// This class is internal and mustn't be used by user code directly.
+class GTEST_API_ ExpectationBase {
+ public:
+ // source_text is the EXPECT_CALL(...) source that created this Expectation.
+ ExpectationBase(const char* file, int line, const string& source_text);
+
+ virtual ~ExpectationBase();
+
+ // Where in the source file was the expectation spec defined?
+ const char* file() const { return file_; }
+ int line() const { return line_; }
+ const char* source_text() const { return source_text_.c_str(); }
+ // Returns the cardinality specified in the expectation spec.
+ const Cardinality& cardinality() const { return cardinality_; }
+
+ // Describes the source file location of this expectation.
+ void DescribeLocationTo(::std::ostream* os) const {
+ *os << FormatFileLocation(file(), line()) << " ";
+ }
+
+ // Describes how many times a function call matching this
+ // expectation has occurred.
+ void DescribeCallCountTo(::std::ostream* os) const
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex);
+
+ // If this mock method has an extra matcher (i.e. .With(matcher)),
+ // describes it to the ostream.
+ virtual void MaybeDescribeExtraMatcherTo(::std::ostream* os) = 0;
+
+ protected:
+ friend class ::testing::Expectation;
+ friend class UntypedFunctionMockerBase;
+
+ enum Clause {
+ // Don't change the order of the enum members!
+ kNone,
+ kWith,
+ kTimes,
+ kInSequence,
+ kAfter,
+ kWillOnce,
+ kWillRepeatedly,
+ kRetiresOnSaturation
+ };
+
+ typedef std::vector<const void*> UntypedActions;
+
+ // Returns an Expectation object that references and co-owns this
+ // expectation.
+ virtual Expectation GetHandle() = 0;
+
+ // Asserts that the EXPECT_CALL() statement has the given property.
+ void AssertSpecProperty(bool property, const string& failure_message) const {
+ Assert(property, file_, line_, failure_message);
+ }
+
+ // Expects that the EXPECT_CALL() statement has the given property.
+ void ExpectSpecProperty(bool property, const string& failure_message) const {
+ Expect(property, file_, line_, failure_message);
+ }
+
+ // Explicitly specifies the cardinality of this expectation. Used
+ // by the subclasses to implement the .Times() clause.
+ void SpecifyCardinality(const Cardinality& cardinality);
+
+ // Returns true iff the user specified the cardinality explicitly
+ // using a .Times().
+ bool cardinality_specified() const { return cardinality_specified_; }
+
+ // Sets the cardinality of this expectation spec.
+ void set_cardinality(const Cardinality& a_cardinality) {
+ cardinality_ = a_cardinality;
+ }
+
+ // The following group of methods should only be called after the
+ // EXPECT_CALL() statement, and only when g_gmock_mutex is held by
+ // the current thread.
+
+ // Retires all pre-requisites of this expectation.
+ void RetireAllPreRequisites()
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex);
+
+ // Returns true iff this expectation is retired.
+ bool is_retired() const
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
+ g_gmock_mutex.AssertHeld();
+ return retired_;
+ }
+
+ // Retires this expectation.
+ void Retire()
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
+ g_gmock_mutex.AssertHeld();
+ retired_ = true;
+ }
+
+ // Returns true iff this expectation is satisfied.
+ bool IsSatisfied() const
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
+ g_gmock_mutex.AssertHeld();
+ return cardinality().IsSatisfiedByCallCount(call_count_);
+ }
+
+ // Returns true iff this expectation is saturated.
+ bool IsSaturated() const
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
+ g_gmock_mutex.AssertHeld();
+ return cardinality().IsSaturatedByCallCount(call_count_);
+ }
+
+ // Returns true iff this expectation is over-saturated.
+ bool IsOverSaturated() const
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
+ g_gmock_mutex.AssertHeld();
+ return cardinality().IsOverSaturatedByCallCount(call_count_);
+ }
+
+ // Returns true iff all pre-requisites of this expectation are satisfied.
+ bool AllPrerequisitesAreSatisfied() const
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex);
+
+ // Adds unsatisfied pre-requisites of this expectation to 'result'.
+ void FindUnsatisfiedPrerequisites(ExpectationSet* result) const
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex);
+
+ // Returns the number this expectation has been invoked.
+ int call_count() const
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
+ g_gmock_mutex.AssertHeld();
+ return call_count_;
+ }
+
+ // Increments the number this expectation has been invoked.
+ void IncrementCallCount()
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
+ g_gmock_mutex.AssertHeld();
+ call_count_++;
+ }
+
+ // Checks the action count (i.e. the number of WillOnce() and
+ // WillRepeatedly() clauses) against the cardinality if this hasn't
+ // been done before. Prints a warning if there are too many or too
+ // few actions.
+ void CheckActionCountIfNotDone() const
+ GTEST_LOCK_EXCLUDED_(mutex_);
+
+ friend class ::testing::Sequence;
+ friend class ::testing::internal::ExpectationTester;
+
+ template <typename Function>
+ friend class TypedExpectation;
+
+ // Implements the .Times() clause.
+ void UntypedTimes(const Cardinality& a_cardinality);
+
+ // This group of fields are part of the spec and won't change after
+ // an EXPECT_CALL() statement finishes.
+ const char* file_; // The file that contains the expectation.
+ int line_; // The line number of the expectation.
+ const string source_text_; // The EXPECT_CALL(...) source text.
+ // True iff the cardinality is specified explicitly.
+ bool cardinality_specified_;
+ Cardinality cardinality_; // The cardinality of the expectation.
+ // The immediate pre-requisites (i.e. expectations that must be
+ // satisfied before this expectation can be matched) of this
+ // expectation. We use linked_ptr in the set because we want an
+ // Expectation object to be co-owned by its FunctionMocker and its
+ // successors. This allows multiple mock objects to be deleted at
+ // different times.
+ ExpectationSet immediate_prerequisites_;
+
+ // This group of fields are the current state of the expectation,
+ // and can change as the mock function is called.
+ int call_count_; // How many times this expectation has been invoked.
+ bool retired_; // True iff this expectation has retired.
+ UntypedActions untyped_actions_;
+ bool extra_matcher_specified_;
+ bool repeated_action_specified_; // True if a WillRepeatedly() was specified.
+ bool retires_on_saturation_;
+ Clause last_clause_;
+ mutable bool action_count_checked_; // Under mutex_.
+ mutable Mutex mutex_; // Protects action_count_checked_.
+
+ GTEST_DISALLOW_ASSIGN_(ExpectationBase);
+}; // class ExpectationBase
+
+// Impements an expectation for the given function type.
+template <typename F>
+class TypedExpectation : public ExpectationBase {
+ public:
+ typedef typename Function<F>::ArgumentTuple ArgumentTuple;
+ typedef typename Function<F>::ArgumentMatcherTuple ArgumentMatcherTuple;
+ typedef typename Function<F>::Result Result;
+
+ TypedExpectation(FunctionMockerBase<F>* owner,
+ const char* a_file, int a_line, const string& a_source_text,
+ const ArgumentMatcherTuple& m)
+ : ExpectationBase(a_file, a_line, a_source_text),
+ owner_(owner),
+ matchers_(m),
+ // By default, extra_matcher_ should match anything. However,
+ // we cannot initialize it with _ as that triggers a compiler
+ // bug in Symbian's C++ compiler (cannot decide between two
+ // overloaded constructors of Matcher<const ArgumentTuple&>).
+ extra_matcher_(A<const ArgumentTuple&>()),
+ repeated_action_(DoDefault()) {}
+
+ virtual ~TypedExpectation() {
+ // Check the validity of the action count if it hasn't been done
+ // yet (for example, if the expectation was never used).
+ CheckActionCountIfNotDone();
+ for (UntypedActions::const_iterator it = untyped_actions_.begin();
+ it != untyped_actions_.end(); ++it) {
+ delete static_cast<const Action<F>*>(*it);
+ }
+ }
+
+ // Implements the .With() clause.
+ TypedExpectation& With(const Matcher<const ArgumentTuple&>& m) {
+ if (last_clause_ == kWith) {
+ ExpectSpecProperty(false,
+ ".With() cannot appear "
+ "more than once in an EXPECT_CALL().");
+ } else {
+ ExpectSpecProperty(last_clause_ < kWith,
+ ".With() must be the first "
+ "clause in an EXPECT_CALL().");
+ }
+ last_clause_ = kWith;
+
+ extra_matcher_ = m;
+ extra_matcher_specified_ = true;
+ return *this;
+ }
+
+ // Implements the .Times() clause.
+ TypedExpectation& Times(const Cardinality& a_cardinality) {
+ ExpectationBase::UntypedTimes(a_cardinality);
+ return *this;
+ }
+
+ // Implements the .Times() clause.
+ TypedExpectation& Times(int n) {
+ return Times(Exactly(n));
+ }
+
+ // Implements the .InSequence() clause.
+ TypedExpectation& InSequence(const Sequence& s) {
+ ExpectSpecProperty(last_clause_ <= kInSequence,
+ ".InSequence() cannot appear after .After(),"
+ " .WillOnce(), .WillRepeatedly(), or "
+ ".RetiresOnSaturation().");
+ last_clause_ = kInSequence;
+
+ s.AddExpectation(GetHandle());
+ return *this;
+ }
+ TypedExpectation& InSequence(const Sequence& s1, const Sequence& s2) {
+ return InSequence(s1).InSequence(s2);
+ }
+ TypedExpectation& InSequence(const Sequence& s1, const Sequence& s2,
+ const Sequence& s3) {
+ return InSequence(s1, s2).InSequence(s3);
+ }
+ TypedExpectation& InSequence(const Sequence& s1, const Sequence& s2,
+ const Sequence& s3, const Sequence& s4) {
+ return InSequence(s1, s2, s3).InSequence(s4);
+ }
+ TypedExpectation& InSequence(const Sequence& s1, const Sequence& s2,
+ const Sequence& s3, const Sequence& s4,
+ const Sequence& s5) {
+ return InSequence(s1, s2, s3, s4).InSequence(s5);
+ }
+
+ // Implements that .After() clause.
+ TypedExpectation& After(const ExpectationSet& s) {
+ ExpectSpecProperty(last_clause_ <= kAfter,
+ ".After() cannot appear after .WillOnce(),"
+ " .WillRepeatedly(), or "
+ ".RetiresOnSaturation().");
+ last_clause_ = kAfter;
+
+ for (ExpectationSet::const_iterator it = s.begin(); it != s.end(); ++it) {
+ immediate_prerequisites_ += *it;
+ }
+ return *this;
+ }
+ TypedExpectation& After(const ExpectationSet& s1, const ExpectationSet& s2) {
+ return After(s1).After(s2);
+ }
+ TypedExpectation& After(const ExpectationSet& s1, const ExpectationSet& s2,
+ const ExpectationSet& s3) {
+ return After(s1, s2).After(s3);
+ }
+ TypedExpectation& After(const ExpectationSet& s1, const ExpectationSet& s2,
+ const ExpectationSet& s3, const ExpectationSet& s4) {
+ return After(s1, s2, s3).After(s4);
+ }
+ TypedExpectation& After(const ExpectationSet& s1, const ExpectationSet& s2,
+ const ExpectationSet& s3, const ExpectationSet& s4,
+ const ExpectationSet& s5) {
+ return After(s1, s2, s3, s4).After(s5);
+ }
+
+ // Implements the .WillOnce() clause.
+ TypedExpectation& WillOnce(const Action<F>& action) {
+ ExpectSpecProperty(last_clause_ <= kWillOnce,
+ ".WillOnce() cannot appear after "
+ ".WillRepeatedly() or .RetiresOnSaturation().");
+ last_clause_ = kWillOnce;
+
+ untyped_actions_.push_back(new Action<F>(action));
+ if (!cardinality_specified()) {
+ set_cardinality(Exactly(static_cast<int>(untyped_actions_.size())));
+ }
+ return *this;
+ }
+
+ // Implements the .WillRepeatedly() clause.
+ TypedExpectation& WillRepeatedly(const Action<F>& action) {
+ if (last_clause_ == kWillRepeatedly) {
+ ExpectSpecProperty(false,
+ ".WillRepeatedly() cannot appear "
+ "more than once in an EXPECT_CALL().");
+ } else {
+ ExpectSpecProperty(last_clause_ < kWillRepeatedly,
+ ".WillRepeatedly() cannot appear "
+ "after .RetiresOnSaturation().");
+ }
+ last_clause_ = kWillRepeatedly;
+ repeated_action_specified_ = true;
+
+ repeated_action_ = action;
+ if (!cardinality_specified()) {
+ set_cardinality(AtLeast(static_cast<int>(untyped_actions_.size())));
+ }
+
+ // Now that no more action clauses can be specified, we check
+ // whether their count makes sense.
+ CheckActionCountIfNotDone();
+ return *this;
+ }
+
+ // Implements the .RetiresOnSaturation() clause.
+ TypedExpectation& RetiresOnSaturation() {
+ ExpectSpecProperty(last_clause_ < kRetiresOnSaturation,
+ ".RetiresOnSaturation() cannot appear "
+ "more than once.");
+ last_clause_ = kRetiresOnSaturation;
+ retires_on_saturation_ = true;
+
+ // Now that no more action clauses can be specified, we check
+ // whether their count makes sense.
+ CheckActionCountIfNotDone();
+ return *this;
+ }
+
+ // Returns the matchers for the arguments as specified inside the
+ // EXPECT_CALL() macro.
+ const ArgumentMatcherTuple& matchers() const {
+ return matchers_;
+ }
+
+ // Returns the matcher specified by the .With() clause.
+ const Matcher<const ArgumentTuple&>& extra_matcher() const {
+ return extra_matcher_;
+ }
+
+ // Returns the action specified by the .WillRepeatedly() clause.
+ const Action<F>& repeated_action() const { return repeated_action_; }
+
+ // If this mock method has an extra matcher (i.e. .With(matcher)),
+ // describes it to the ostream.
+ virtual void MaybeDescribeExtraMatcherTo(::std::ostream* os) {
+ if (extra_matcher_specified_) {
+ *os << " Expected args: ";
+ extra_matcher_.DescribeTo(os);
+ *os << "\n";
+ }
+ }
+
+ private:
+ template <typename Function>
+ friend class FunctionMockerBase;
+
+ // Returns an Expectation object that references and co-owns this
+ // expectation.
+ virtual Expectation GetHandle() {
+ return owner_->GetHandleOf(this);
+ }
+
+ // The following methods will be called only after the EXPECT_CALL()
+ // statement finishes and when the current thread holds
+ // g_gmock_mutex.
+
+ // Returns true iff this expectation matches the given arguments.
+ bool Matches(const ArgumentTuple& args) const
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
+ g_gmock_mutex.AssertHeld();
+ return TupleMatches(matchers_, args) && extra_matcher_.Matches(args);
+ }
+
+ // Returns true iff this expectation should handle the given arguments.
+ bool ShouldHandleArguments(const ArgumentTuple& args) const
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
+ g_gmock_mutex.AssertHeld();
+
+ // In case the action count wasn't checked when the expectation
+ // was defined (e.g. if this expectation has no WillRepeatedly()
+ // or RetiresOnSaturation() clause), we check it when the
+ // expectation is used for the first time.
+ CheckActionCountIfNotDone();
+ return !is_retired() && AllPrerequisitesAreSatisfied() && Matches(args);
+ }
+
+ // Describes the result of matching the arguments against this
+ // expectation to the given ostream.
+ void ExplainMatchResultTo(
+ const ArgumentTuple& args,
+ ::std::ostream* os) const
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
+ g_gmock_mutex.AssertHeld();
+
+ if (is_retired()) {
+ *os << " Expected: the expectation is active\n"
+ << " Actual: it is retired\n";
+ } else if (!Matches(args)) {
+ if (!TupleMatches(matchers_, args)) {
+ ExplainMatchFailureTupleTo(matchers_, args, os);
+ }
+ StringMatchResultListener listener;
+ if (!extra_matcher_.MatchAndExplain(args, &listener)) {
+ *os << " Expected args: ";
+ extra_matcher_.DescribeTo(os);
+ *os << "\n Actual: don't match";
+
+ internal::PrintIfNotEmpty(listener.str(), os);
+ *os << "\n";
+ }
+ } else if (!AllPrerequisitesAreSatisfied()) {
+ *os << " Expected: all pre-requisites are satisfied\n"
+ << " Actual: the following immediate pre-requisites "
+ << "are not satisfied:\n";
+ ExpectationSet unsatisfied_prereqs;
+ FindUnsatisfiedPrerequisites(&unsatisfied_prereqs);
+ int i = 0;
+ for (ExpectationSet::const_iterator it = unsatisfied_prereqs.begin();
+ it != unsatisfied_prereqs.end(); ++it) {
+ it->expectation_base()->DescribeLocationTo(os);
+ *os << "pre-requisite #" << i++ << "\n";
+ }
+ *os << " (end of pre-requisites)\n";
+ } else {
+ // This line is here just for completeness' sake. It will never
+ // be executed as currently the ExplainMatchResultTo() function
+ // is called only when the mock function call does NOT match the
+ // expectation.
+ *os << "The call matches the expectation.\n";
+ }
+ }
+
+ // Returns the action that should be taken for the current invocation.
+ const Action<F>& GetCurrentAction(
+ const FunctionMockerBase<F>* mocker,
+ const ArgumentTuple& args) const
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
+ g_gmock_mutex.AssertHeld();
+ const int count = call_count();
+ Assert(count >= 1, __FILE__, __LINE__,
+ "call_count() is <= 0 when GetCurrentAction() is "
+ "called - this should never happen.");
+
+ const int action_count = static_cast<int>(untyped_actions_.size());
+ if (action_count > 0 && !repeated_action_specified_ &&
+ count > action_count) {
+ // If there is at least one WillOnce() and no WillRepeatedly(),
+ // we warn the user when the WillOnce() clauses ran out.
+ ::std::stringstream ss;
+ DescribeLocationTo(&ss);
+ ss << "Actions ran out in " << source_text() << "...\n"
+ << "Called " << count << " times, but only "
+ << action_count << " WillOnce()"
+ << (action_count == 1 ? " is" : "s are") << " specified - ";
+ mocker->DescribeDefaultActionTo(args, &ss);
+ Log(kWarning, ss.str(), 1);
+ }
+
+ return count <= action_count ?
+ *static_cast<const Action<F>*>(untyped_actions_[count - 1]) :
+ repeated_action();
+ }
+
+ // Given the arguments of a mock function call, if the call will
+ // over-saturate this expectation, returns the default action;
+ // otherwise, returns the next action in this expectation. Also
+ // describes *what* happened to 'what', and explains *why* Google
+ // Mock does it to 'why'. This method is not const as it calls
+ // IncrementCallCount(). A return value of NULL means the default
+ // action.
+ const Action<F>* GetActionForArguments(
+ const FunctionMockerBase<F>* mocker,
+ const ArgumentTuple& args,
+ ::std::ostream* what,
+ ::std::ostream* why)
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
+ g_gmock_mutex.AssertHeld();
+ if (IsSaturated()) {
+ // We have an excessive call.
+ IncrementCallCount();
+ *what << "Mock function called more times than expected - ";
+ mocker->DescribeDefaultActionTo(args, what);
+ DescribeCallCountTo(why);
+
+ // TODO(wan@google.com): allow the user to control whether
+ // unexpected calls should fail immediately or continue using a
+ // flag --gmock_unexpected_calls_are_fatal.
+ return NULL;
+ }
+
+ IncrementCallCount();
+ RetireAllPreRequisites();
+
+ if (retires_on_saturation_ && IsSaturated()) {
+ Retire();
+ }
+
+ // Must be done after IncrementCount()!
+ *what << "Mock function call matches " << source_text() <<"...\n";
+ return &(GetCurrentAction(mocker, args));
+ }
+
+ // All the fields below won't change once the EXPECT_CALL()
+ // statement finishes.
+ FunctionMockerBase<F>* const owner_;
+ ArgumentMatcherTuple matchers_;
+ Matcher<const ArgumentTuple&> extra_matcher_;
+ Action<F> repeated_action_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TypedExpectation);
+}; // class TypedExpectation
+
+// A MockSpec object is used by ON_CALL() or EXPECT_CALL() for
+// specifying the default behavior of, or expectation on, a mock
+// function.
+
+// Note: class MockSpec really belongs to the ::testing namespace.
+// However if we define it in ::testing, MSVC will complain when
+// classes in ::testing::internal declare it as a friend class
+// template. To workaround this compiler bug, we define MockSpec in
+// ::testing::internal and import it into ::testing.
+
+// Logs a message including file and line number information.
+GTEST_API_ void LogWithLocation(testing::internal::LogSeverity severity,
+ const char* file, int line,
+ const string& message);
+
+template <typename F>
+class MockSpec {
+ public:
+ typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
+ typedef typename internal::Function<F>::ArgumentMatcherTuple
+ ArgumentMatcherTuple;
+
+ // Constructs a MockSpec object, given the function mocker object
+ // that the spec is associated with.
+ explicit MockSpec(internal::FunctionMockerBase<F>* function_mocker)
+ : function_mocker_(function_mocker) {}
+
+ // Adds a new default action spec to the function mocker and returns
+ // the newly created spec.
+ internal::OnCallSpec<F>& InternalDefaultActionSetAt(
+ const char* file, int line, const char* obj, const char* call) {
+ LogWithLocation(internal::kInfo, file, line,
+ string("ON_CALL(") + obj + ", " + call + ") invoked");
+ return function_mocker_->AddNewOnCallSpec(file, line, matchers_);
+ }
+
+ // Adds a new expectation spec to the function mocker and returns
+ // the newly created spec.
+ internal::TypedExpectation<F>& InternalExpectedAt(
+ const char* file, int line, const char* obj, const char* call) {
+ const string source_text(string("EXPECT_CALL(") + obj + ", " + call + ")");
+ LogWithLocation(internal::kInfo, file, line, source_text + " invoked");
+ return function_mocker_->AddNewExpectation(
+ file, line, source_text, matchers_);
+ }
+
+ private:
+ template <typename Function>
+ friend class internal::FunctionMocker;
+
+ void SetMatchers(const ArgumentMatcherTuple& matchers) {
+ matchers_ = matchers;
+ }
+
+ // The function mocker that owns this spec.
+ internal::FunctionMockerBase<F>* const function_mocker_;
+ // The argument matchers specified in the spec.
+ ArgumentMatcherTuple matchers_;
+
+ GTEST_DISALLOW_ASSIGN_(MockSpec);
+}; // class MockSpec
+
+// Wrapper type for generically holding an ordinary value or lvalue reference.
+// If T is not a reference type, it must be copyable or movable.
+// ReferenceOrValueWrapper<T> is movable, and will also be copyable unless
+// T is a move-only value type (which means that it will always be copyable
+// if the current platform does not support move semantics).
+//
+// The primary template defines handling for values, but function header
+// comments describe the contract for the whole template (including
+// specializations).
+template <typename T>
+class ReferenceOrValueWrapper {
+ public:
+ // Constructs a wrapper from the given value/reference.
+ explicit ReferenceOrValueWrapper(T value)
+ : value_(::testing::internal::move(value)) {
+ }
+
+ // Unwraps and returns the underlying value/reference, exactly as
+ // originally passed. The behavior of calling this more than once on
+ // the same object is unspecified.
+ T Unwrap() { return ::testing::internal::move(value_); }
+
+ // Provides nondestructive access to the underlying value/reference.
+ // Always returns a const reference (more precisely,
+ // const RemoveReference<T>&). The behavior of calling this after
+ // calling Unwrap on the same object is unspecified.
+ const T& Peek() const {
+ return value_;
+ }
+
+ private:
+ T value_;
+};
+
+// Specialization for lvalue reference types. See primary template
+// for documentation.
+template <typename T>
+class ReferenceOrValueWrapper<T&> {
+ public:
+ // Workaround for debatable pass-by-reference lint warning (c-library-team
+ // policy precludes NOLINT in this context)
+ typedef T& reference;
+ explicit ReferenceOrValueWrapper(reference ref)
+ : value_ptr_(&ref) {}
+ T& Unwrap() { return *value_ptr_; }
+ const T& Peek() const { return *value_ptr_; }
+
+ private:
+ T* value_ptr_;
+};
+
+// MSVC warns about using 'this' in base member initializer list, so
+// we need to temporarily disable the warning. We have to do it for
+// the entire class to suppress the warning, even though it's about
+// the constructor only.
+
+#ifdef _MSC_VER
+# pragma warning(push) // Saves the current warning state.
+# pragma warning(disable:4355) // Temporarily disables warning 4355.
+#endif // _MSV_VER
+
+// C++ treats the void type specially. For example, you cannot define
+// a void-typed variable or pass a void value to a function.
+// ActionResultHolder<T> holds a value of type T, where T must be a
+// copyable type or void (T doesn't need to be default-constructable).
+// It hides the syntactic difference between void and other types, and
+// is used to unify the code for invoking both void-returning and
+// non-void-returning mock functions.
+
+// Untyped base class for ActionResultHolder<T>.
+class UntypedActionResultHolderBase {
+ public:
+ virtual ~UntypedActionResultHolderBase() {}
+
+ // Prints the held value as an action's result to os.
+ virtual void PrintAsActionResult(::std::ostream* os) const = 0;
+};
+
+// This generic definition is used when T is not void.
+template <typename T>
+class ActionResultHolder : public UntypedActionResultHolderBase {
+ public:
+ // Returns the held value. Must not be called more than once.
+ T Unwrap() {
+ return result_.Unwrap();
+ }
+
+ // Prints the held value as an action's result to os.
+ virtual void PrintAsActionResult(::std::ostream* os) const {
+ *os << "\n Returns: ";
+ // T may be a reference type, so we don't use UniversalPrint().
+ UniversalPrinter<T>::Print(result_.Peek(), os);
+ }
+
+ // Performs the given mock function's default action and returns the
+ // result in a new-ed ActionResultHolder.
+ template <typename F>
+ static ActionResultHolder* PerformDefaultAction(
+ const FunctionMockerBase<F>* func_mocker,
+ const typename Function<F>::ArgumentTuple& args,
+ const string& call_description) {
+ return new ActionResultHolder(Wrapper(
+ func_mocker->PerformDefaultAction(args, call_description)));
+ }
+
+ // Performs the given action and returns the result in a new-ed
+ // ActionResultHolder.
+ template <typename F>
+ static ActionResultHolder*
+ PerformAction(const Action<F>& action,
+ const typename Function<F>::ArgumentTuple& args) {
+ return new ActionResultHolder(Wrapper(action.Perform(args)));
+ }
+
+ private:
+ typedef ReferenceOrValueWrapper<T> Wrapper;
+
+ explicit ActionResultHolder(Wrapper result)
+ : result_(::testing::internal::move(result)) {
+ }
+
+ Wrapper result_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ActionResultHolder);
+};
+
+// Specialization for T = void.
+template <>
+class ActionResultHolder<void> : public UntypedActionResultHolderBase {
+ public:
+ void Unwrap() { }
+
+ virtual void PrintAsActionResult(::std::ostream* /* os */) const {}
+
+ // Performs the given mock function's default action and returns ownership
+ // of an empty ActionResultHolder*.
+ template <typename F>
+ static ActionResultHolder* PerformDefaultAction(
+ const FunctionMockerBase<F>* func_mocker,
+ const typename Function<F>::ArgumentTuple& args,
+ const string& call_description) {
+ func_mocker->PerformDefaultAction(args, call_description);
+ return new ActionResultHolder;
+ }
+
+ // Performs the given action and returns ownership of an empty
+ // ActionResultHolder*.
+ template <typename F>
+ static ActionResultHolder* PerformAction(
+ const Action<F>& action,
+ const typename Function<F>::ArgumentTuple& args) {
+ action.Perform(args);
+ return new ActionResultHolder;
+ }
+
+ private:
+ ActionResultHolder() {}
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ActionResultHolder);
+};
+
+// The base of the function mocker class for the given function type.
+// We put the methods in this class instead of its child to avoid code
+// bloat.
+template <typename F>
+class FunctionMockerBase : public UntypedFunctionMockerBase {
+ public:
+ typedef typename Function<F>::Result Result;
+ typedef typename Function<F>::ArgumentTuple ArgumentTuple;
+ typedef typename Function<F>::ArgumentMatcherTuple ArgumentMatcherTuple;
+
+ FunctionMockerBase() : current_spec_(this) {}
+
+ // The destructor verifies that all expectations on this mock
+ // function have been satisfied. If not, it will report Google Test
+ // non-fatal failures for the violations.
+ virtual ~FunctionMockerBase()
+ GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
+ MutexLock l(&g_gmock_mutex);
+ VerifyAndClearExpectationsLocked();
+ Mock::UnregisterLocked(this);
+ ClearDefaultActionsLocked();
+ }
+
+ // Returns the ON_CALL spec that matches this mock function with the
+ // given arguments; returns NULL if no matching ON_CALL is found.
+ // L = *
+ const OnCallSpec<F>* FindOnCallSpec(
+ const ArgumentTuple& args) const {
+ for (UntypedOnCallSpecs::const_reverse_iterator it
+ = untyped_on_call_specs_.rbegin();
+ it != untyped_on_call_specs_.rend(); ++it) {
+ const OnCallSpec<F>* spec = static_cast<const OnCallSpec<F>*>(*it);
+ if (spec->Matches(args))
+ return spec;
+ }
+
+ return NULL;
+ }
+
+ // Performs the default action of this mock function on the given
+ // arguments and returns the result. Asserts (or throws if
+ // exceptions are enabled) with a helpful call descrption if there
+ // is no valid return value. This method doesn't depend on the
+ // mutable state of this object, and thus can be called concurrently
+ // without locking.
+ // L = *
+ Result PerformDefaultAction(const ArgumentTuple& args,
+ const string& call_description) const {
+ const OnCallSpec<F>* const spec =
+ this->FindOnCallSpec(args);
+ if (spec != NULL) {
+ return spec->GetAction().Perform(args);
+ }
+ const string message = call_description +
+ "\n The mock function has no default action "
+ "set, and its return type has no default value set.";
+#if GTEST_HAS_EXCEPTIONS
+ if (!DefaultValue<Result>::Exists()) {
+ throw std::runtime_error(message);
+ }
+#else
+ Assert(DefaultValue<Result>::Exists(), "", -1, message);
+#endif
+ return DefaultValue<Result>::Get();
+ }
+
+ // Performs the default action with the given arguments and returns
+ // the action's result. The call description string will be used in
+ // the error message to describe the call in the case the default
+ // action fails. The caller is responsible for deleting the result.
+ // L = *
+ virtual UntypedActionResultHolderBase* UntypedPerformDefaultAction(
+ const void* untyped_args, // must point to an ArgumentTuple
+ const string& call_description) const {
+ const ArgumentTuple& args =
+ *static_cast<const ArgumentTuple*>(untyped_args);
+ return ResultHolder::PerformDefaultAction(this, args, call_description);
+ }
+
+ // Performs the given action with the given arguments and returns
+ // the action's result. The caller is responsible for deleting the
+ // result.
+ // L = *
+ virtual UntypedActionResultHolderBase* UntypedPerformAction(
+ const void* untyped_action, const void* untyped_args) const {
+ // Make a copy of the action before performing it, in case the
+ // action deletes the mock object (and thus deletes itself).
+ const Action<F> action = *static_cast<const Action<F>*>(untyped_action);
+ const ArgumentTuple& args =
+ *static_cast<const ArgumentTuple*>(untyped_args);
+ return ResultHolder::PerformAction(action, args);
+ }
+
+ // Implements UntypedFunctionMockerBase::ClearDefaultActionsLocked():
+ // clears the ON_CALL()s set on this mock function.
+ virtual void ClearDefaultActionsLocked()
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
+ g_gmock_mutex.AssertHeld();
+
+ // Deleting our default actions may trigger other mock objects to be
+ // deleted, for example if an action contains a reference counted smart
+ // pointer to that mock object, and that is the last reference. So if we
+ // delete our actions within the context of the global mutex we may deadlock
+ // when this method is called again. Instead, make a copy of the set of
+ // actions to delete, clear our set within the mutex, and then delete the
+ // actions outside of the mutex.
+ UntypedOnCallSpecs specs_to_delete;
+ untyped_on_call_specs_.swap(specs_to_delete);
+
+ g_gmock_mutex.Unlock();
+ for (UntypedOnCallSpecs::const_iterator it =
+ specs_to_delete.begin();
+ it != specs_to_delete.end(); ++it) {
+ delete static_cast<const OnCallSpec<F>*>(*it);
+ }
+
+ // Lock the mutex again, since the caller expects it to be locked when we
+ // return.
+ g_gmock_mutex.Lock();
+ }
+
+ protected:
+ template <typename Function>
+ friend class MockSpec;
+
+ typedef ActionResultHolder<Result> ResultHolder;
+
+ // Returns the result of invoking this mock function with the given
+ // arguments. This function can be safely called from multiple
+ // threads concurrently.
+ Result InvokeWith(const ArgumentTuple& args)
+ GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
+ scoped_ptr<ResultHolder> holder(
+ DownCast_<ResultHolder*>(this->UntypedInvokeWith(&args)));
+ return holder->Unwrap();
+ }
+
+ // Adds and returns a default action spec for this mock function.
+ OnCallSpec<F>& AddNewOnCallSpec(
+ const char* file, int line,
+ const ArgumentMatcherTuple& m)
+ GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
+ Mock::RegisterUseByOnCallOrExpectCall(MockObject(), file, line);
+ OnCallSpec<F>* const on_call_spec = new OnCallSpec<F>(file, line, m);
+ untyped_on_call_specs_.push_back(on_call_spec);
+ return *on_call_spec;
+ }
+
+ // Adds and returns an expectation spec for this mock function.
+ TypedExpectation<F>& AddNewExpectation(
+ const char* file,
+ int line,
+ const string& source_text,
+ const ArgumentMatcherTuple& m)
+ GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
+ Mock::RegisterUseByOnCallOrExpectCall(MockObject(), file, line);
+ TypedExpectation<F>* const expectation =
+ new TypedExpectation<F>(this, file, line, source_text, m);
+ const linked_ptr<ExpectationBase> untyped_expectation(expectation);
+ untyped_expectations_.push_back(untyped_expectation);
+
+ // Adds this expectation into the implicit sequence if there is one.
+ Sequence* const implicit_sequence = g_gmock_implicit_sequence.get();
+ if (implicit_sequence != NULL) {
+ implicit_sequence->AddExpectation(Expectation(untyped_expectation));
+ }
+
+ return *expectation;
+ }
+
+ // The current spec (either default action spec or expectation spec)
+ // being described on this function mocker.
+ MockSpec<F>& current_spec() { return current_spec_; }
+
+ private:
+ template <typename Func> friend class TypedExpectation;
+
+ // Some utilities needed for implementing UntypedInvokeWith().
+
+ // Describes what default action will be performed for the given
+ // arguments.
+ // L = *
+ void DescribeDefaultActionTo(const ArgumentTuple& args,
+ ::std::ostream* os) const {
+ const OnCallSpec<F>* const spec = FindOnCallSpec(args);
+
+ if (spec == NULL) {
+ *os << (internal::type_equals<Result, void>::value ?
+ "returning directly.\n" :
+ "returning default value.\n");
+ } else {
+ *os << "taking default action specified at:\n"
+ << FormatFileLocation(spec->file(), spec->line()) << "\n";
+ }
+ }
+
+ // Writes a message that the call is uninteresting (i.e. neither
+ // explicitly expected nor explicitly unexpected) to the given
+ // ostream.
+ virtual void UntypedDescribeUninterestingCall(
+ const void* untyped_args,
+ ::std::ostream* os) const
+ GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
+ const ArgumentTuple& args =
+ *static_cast<const ArgumentTuple*>(untyped_args);
+ *os << "Uninteresting mock function call - ";
+ DescribeDefaultActionTo(args, os);
+ *os << " Function call: " << Name();
+ UniversalPrint(args, os);
+ }
+
+ // Returns the expectation that matches the given function arguments
+ // (or NULL is there's no match); when a match is found,
+ // untyped_action is set to point to the action that should be
+ // performed (or NULL if the action is "do default"), and
+ // is_excessive is modified to indicate whether the call exceeds the
+ // expected number.
+ //
+ // Critical section: We must find the matching expectation and the
+ // corresponding action that needs to be taken in an ATOMIC
+ // transaction. Otherwise another thread may call this mock
+ // method in the middle and mess up the state.
+ //
+ // However, performing the action has to be left out of the critical
+ // section. The reason is that we have no control on what the
+ // action does (it can invoke an arbitrary user function or even a
+ // mock function) and excessive locking could cause a dead lock.
+ virtual const ExpectationBase* UntypedFindMatchingExpectation(
+ const void* untyped_args,
+ const void** untyped_action, bool* is_excessive,
+ ::std::ostream* what, ::std::ostream* why)
+ GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
+ const ArgumentTuple& args =
+ *static_cast<const ArgumentTuple*>(untyped_args);
+ MutexLock l(&g_gmock_mutex);
+ TypedExpectation<F>* exp = this->FindMatchingExpectationLocked(args);
+ if (exp == NULL) { // A match wasn't found.
+ this->FormatUnexpectedCallMessageLocked(args, what, why);
+ return NULL;
+ }
+
+ // This line must be done before calling GetActionForArguments(),
+ // which will increment the call count for *exp and thus affect
+ // its saturation status.
+ *is_excessive = exp->IsSaturated();
+ const Action<F>* action = exp->GetActionForArguments(this, args, what, why);
+ if (action != NULL && action->IsDoDefault())
+ action = NULL; // Normalize "do default" to NULL.
+ *untyped_action = action;
+ return exp;
+ }
+
+ // Prints the given function arguments to the ostream.
+ virtual void UntypedPrintArgs(const void* untyped_args,
+ ::std::ostream* os) const {
+ const ArgumentTuple& args =
+ *static_cast<const ArgumentTuple*>(untyped_args);
+ UniversalPrint(args, os);
+ }
+
+ // Returns the expectation that matches the arguments, or NULL if no
+ // expectation matches them.
+ TypedExpectation<F>* FindMatchingExpectationLocked(
+ const ArgumentTuple& args) const
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
+ g_gmock_mutex.AssertHeld();
+ for (typename UntypedExpectations::const_reverse_iterator it =
+ untyped_expectations_.rbegin();
+ it != untyped_expectations_.rend(); ++it) {
+ TypedExpectation<F>* const exp =
+ static_cast<TypedExpectation<F>*>(it->get());
+ if (exp->ShouldHandleArguments(args)) {
+ return exp;
+ }
+ }
+ return NULL;
+ }
+
+ // Returns a message that the arguments don't match any expectation.
+ void FormatUnexpectedCallMessageLocked(
+ const ArgumentTuple& args,
+ ::std::ostream* os,
+ ::std::ostream* why) const
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
+ g_gmock_mutex.AssertHeld();
+ *os << "\nUnexpected mock function call - ";
+ DescribeDefaultActionTo(args, os);
+ PrintTriedExpectationsLocked(args, why);
+ }
+
+ // Prints a list of expectations that have been tried against the
+ // current mock function call.
+ void PrintTriedExpectationsLocked(
+ const ArgumentTuple& args,
+ ::std::ostream* why) const
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
+ g_gmock_mutex.AssertHeld();
+ const int count = static_cast<int>(untyped_expectations_.size());
+ *why << "Google Mock tried the following " << count << " "
+ << (count == 1 ? "expectation, but it didn't match" :
+ "expectations, but none matched")
+ << ":\n";
+ for (int i = 0; i < count; i++) {
+ TypedExpectation<F>* const expectation =
+ static_cast<TypedExpectation<F>*>(untyped_expectations_[i].get());
+ *why << "\n";
+ expectation->DescribeLocationTo(why);
+ if (count > 1) {
+ *why << "tried expectation #" << i << ": ";
+ }
+ *why << expectation->source_text() << "...\n";
+ expectation->ExplainMatchResultTo(args, why);
+ expectation->DescribeCallCountTo(why);
+ }
+ }
+
+ // The current spec (either default action spec or expectation spec)
+ // being described on this function mocker.
+ MockSpec<F> current_spec_;
+
+ // There is no generally useful and implementable semantics of
+ // copying a mock object, so copying a mock is usually a user error.
+ // Thus we disallow copying function mockers. If the user really
+ // wants to copy a mock object, he should implement his own copy
+ // operation, for example:
+ //
+ // class MockFoo : public Foo {
+ // public:
+ // // Defines a copy constructor explicitly.
+ // MockFoo(const MockFoo& src) {}
+ // ...
+ // };
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(FunctionMockerBase);
+}; // class FunctionMockerBase
+
+#ifdef _MSC_VER
+# pragma warning(pop) // Restores the warning state.
+#endif // _MSV_VER
+
+// Implements methods of FunctionMockerBase.
+
+// Verifies that all expectations on this mock function have been
+// satisfied. Reports one or more Google Test non-fatal failures and
+// returns false if not.
+
+// Reports an uninteresting call (whose description is in msg) in the
+// manner specified by 'reaction'.
+void ReportUninterestingCall(CallReaction reaction, const string& msg);
+
+} // namespace internal
+
+// The style guide prohibits "using" statements in a namespace scope
+// inside a header file. However, the MockSpec class template is
+// meant to be defined in the ::testing namespace. The following line
+// is just a trick for working around a bug in MSVC 8.0, which cannot
+// handle it if we define MockSpec in ::testing.
+using internal::MockSpec;
+
+// Const(x) is a convenient function for obtaining a const reference
+// to x. This is useful for setting expectations on an overloaded
+// const mock method, e.g.
+//
+// class MockFoo : public FooInterface {
+// public:
+// MOCK_METHOD0(Bar, int());
+// MOCK_CONST_METHOD0(Bar, int&());
+// };
+//
+// MockFoo foo;
+// // Expects a call to non-const MockFoo::Bar().
+// EXPECT_CALL(foo, Bar());
+// // Expects a call to const MockFoo::Bar().
+// EXPECT_CALL(Const(foo), Bar());
+template <typename T>
+inline const T& Const(const T& x) { return x; }
+
+// Constructs an Expectation object that references and co-owns exp.
+inline Expectation::Expectation(internal::ExpectationBase& exp) // NOLINT
+ : expectation_base_(exp.GetHandle().expectation_base()) {}
+
+} // namespace testing
+
+// A separate macro is required to avoid compile errors when the name
+// of the method used in call is a result of macro expansion.
+// See CompilesWithMethodNameExpandedFromMacro tests in
+// internal/gmock-spec-builders_test.cc for more details.
+#define GMOCK_ON_CALL_IMPL_(obj, call) \
+ ((obj).gmock_##call).InternalDefaultActionSetAt(__FILE__, __LINE__, \
+ #obj, #call)
+#define ON_CALL(obj, call) GMOCK_ON_CALL_IMPL_(obj, call)
+
+#define GMOCK_EXPECT_CALL_IMPL_(obj, call) \
+ ((obj).gmock_##call).InternalExpectedAt(__FILE__, __LINE__, #obj, #call)
+#define EXPECT_CALL(obj, call) GMOCK_EXPECT_CALL_IMPL_(obj, call)
+
+#endif // GMOCK_INCLUDE_GMOCK_GMOCK_SPEC_BUILDERS_H_
diff --git a/extern/gmock/include/gmock/gmock.h b/extern/gmock/include/gmock/gmock.h
new file mode 100644
index 00000000000..6735c71bf8a
--- /dev/null
+++ b/extern/gmock/include/gmock/gmock.h
@@ -0,0 +1,94 @@
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Google Mock - a framework for writing C++ mock classes.
+//
+// This is the main header file a user should include.
+
+#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_H_
+#define GMOCK_INCLUDE_GMOCK_GMOCK_H_
+
+// This file implements the following syntax:
+//
+// ON_CALL(mock_object.Method(...))
+// .With(...) ?
+// .WillByDefault(...);
+//
+// where With() is optional and WillByDefault() must appear exactly
+// once.
+//
+// EXPECT_CALL(mock_object.Method(...))
+// .With(...) ?
+// .Times(...) ?
+// .InSequence(...) *
+// .WillOnce(...) *
+// .WillRepeatedly(...) ?
+// .RetiresOnSaturation() ? ;
+//
+// where all clauses are optional and WillOnce() can be repeated.
+
+#include "gmock/gmock-actions.h"
+#include "gmock/gmock-cardinalities.h"
+#include "gmock/gmock-generated-actions.h"
+#include "gmock/gmock-generated-function-mockers.h"
+#include "gmock/gmock-generated-nice-strict.h"
+#include "gmock/gmock-generated-matchers.h"
+#include "gmock/gmock-matchers.h"
+#include "gmock/gmock-more-actions.h"
+#include "gmock/gmock-more-matchers.h"
+#include "gmock/internal/gmock-internal-utils.h"
+
+namespace testing {
+
+// Declares Google Mock flags that we want a user to use programmatically.
+GMOCK_DECLARE_bool_(catch_leaked_mocks);
+GMOCK_DECLARE_string_(verbose);
+
+// Initializes Google Mock. This must be called before running the
+// tests. In particular, it parses the command line for the flags
+// that Google Mock recognizes. Whenever a Google Mock flag is seen,
+// it is removed from argv, and *argc is decremented.
+//
+// No value is returned. Instead, the Google Mock flag variables are
+// updated.
+//
+// Since Google Test is needed for Google Mock to work, this function
+// also initializes Google Test and parses its flags, if that hasn't
+// been done.
+GTEST_API_ void InitGoogleMock(int* argc, char** argv);
+
+// This overloaded version can be used in Windows programs compiled in
+// UNICODE mode.
+GTEST_API_ void InitGoogleMock(int* argc, wchar_t** argv);
+
+} // namespace testing
+
+#endif // GMOCK_INCLUDE_GMOCK_GMOCK_H_
diff --git a/extern/gmock/include/gmock/internal/custom/gmock-generated-actions.h b/extern/gmock/include/gmock/internal/custom/gmock-generated-actions.h
new file mode 100644
index 00000000000..7dc3b1ad541
--- /dev/null
+++ b/extern/gmock/include/gmock/internal/custom/gmock-generated-actions.h
@@ -0,0 +1,8 @@
+// This file was GENERATED by command:
+// pump.py gmock-generated-actions.h.pump
+// DO NOT EDIT BY HAND!!!
+
+#ifndef GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_GENERATED_ACTIONS_H_
+#define GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_GENERATED_ACTIONS_H_
+
+#endif // GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_GENERATED_ACTIONS_H_
diff --git a/extern/gmock/include/gmock/internal/custom/gmock-matchers.h b/extern/gmock/include/gmock/internal/custom/gmock-matchers.h
new file mode 100644
index 00000000000..f2efef91dbe
--- /dev/null
+++ b/extern/gmock/include/gmock/internal/custom/gmock-matchers.h
@@ -0,0 +1,39 @@
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ============================================================
+// An installation-specific extension point for gmock-matchers.h.
+// ============================================================
+//
+// Adds google3 callback support to CallableTraits.
+//
+#ifndef GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_CALLBACK_MATCHERS_H_
+#define GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_CALLBACK_MATCHERS_H_
+
+#endif // GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_CALLBACK_MATCHERS_H_
diff --git a/extern/gmock/include/gmock/internal/custom/gmock-port.h b/extern/gmock/include/gmock/internal/custom/gmock-port.h
new file mode 100644
index 00000000000..9ce8bfe06bf
--- /dev/null
+++ b/extern/gmock/include/gmock/internal/custom/gmock-port.h
@@ -0,0 +1,46 @@
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Injection point for custom user configurations.
+// The following macros can be defined:
+//
+// Flag related macros:
+// GMOCK_DECLARE_bool_(name)
+// GMOCK_DECLARE_int32_(name)
+// GMOCK_DECLARE_string_(name)
+// GMOCK_DEFINE_bool_(name, default_val, doc)
+// GMOCK_DEFINE_int32_(name, default_val, doc)
+// GMOCK_DEFINE_string_(name, default_val, doc)
+//
+// ** Custom implementation starts here **
+
+#ifndef GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_PORT_H_
+#define GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_PORT_H_
+
+#endif // GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_PORT_H_
diff --git a/extern/gmock/include/gmock/internal/gmock-generated-internal-utils.h b/extern/gmock/include/gmock/internal/gmock-generated-internal-utils.h
new file mode 100644
index 00000000000..7811e43f87c
--- /dev/null
+++ b/extern/gmock/include/gmock/internal/gmock-generated-internal-utils.h
@@ -0,0 +1,279 @@
+// This file was GENERATED by command:
+// pump.py gmock-generated-internal-utils.h.pump
+// DO NOT EDIT BY HAND!!!
+
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Google Mock - a framework for writing C++ mock classes.
+//
+// This file contains template meta-programming utility classes needed
+// for implementing Google Mock.
+
+#ifndef GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_GENERATED_INTERNAL_UTILS_H_
+#define GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_GENERATED_INTERNAL_UTILS_H_
+
+#include "gmock/internal/gmock-port.h"
+
+namespace testing {
+
+template <typename T>
+class Matcher;
+
+namespace internal {
+
+// An IgnoredValue object can be implicitly constructed from ANY value.
+// This is used in implementing the IgnoreResult(a) action.
+class IgnoredValue {
+ public:
+ // This constructor template allows any value to be implicitly
+ // converted to IgnoredValue. The object has no data member and
+ // doesn't try to remember anything about the argument. We
+ // deliberately omit the 'explicit' keyword in order to allow the
+ // conversion to be implicit.
+ template <typename T>
+ IgnoredValue(const T& /* ignored */) {} // NOLINT(runtime/explicit)
+};
+
+// MatcherTuple<T>::type is a tuple type where each field is a Matcher
+// for the corresponding field in tuple type T.
+template <typename Tuple>
+struct MatcherTuple;
+
+template <>
+struct MatcherTuple< ::testing::tuple<> > {
+ typedef ::testing::tuple< > type;
+};
+
+template <typename A1>
+struct MatcherTuple< ::testing::tuple<A1> > {
+ typedef ::testing::tuple<Matcher<A1> > type;
+};
+
+template <typename A1, typename A2>
+struct MatcherTuple< ::testing::tuple<A1, A2> > {
+ typedef ::testing::tuple<Matcher<A1>, Matcher<A2> > type;
+};
+
+template <typename A1, typename A2, typename A3>
+struct MatcherTuple< ::testing::tuple<A1, A2, A3> > {
+ typedef ::testing::tuple<Matcher<A1>, Matcher<A2>, Matcher<A3> > type;
+};
+
+template <typename A1, typename A2, typename A3, typename A4>
+struct MatcherTuple< ::testing::tuple<A1, A2, A3, A4> > {
+ typedef ::testing::tuple<Matcher<A1>, Matcher<A2>, Matcher<A3>,
+ Matcher<A4> > type;
+};
+
+template <typename A1, typename A2, typename A3, typename A4, typename A5>
+struct MatcherTuple< ::testing::tuple<A1, A2, A3, A4, A5> > {
+ typedef ::testing::tuple<Matcher<A1>, Matcher<A2>, Matcher<A3>, Matcher<A4>,
+ Matcher<A5> > type;
+};
+
+template <typename A1, typename A2, typename A3, typename A4, typename A5,
+ typename A6>
+struct MatcherTuple< ::testing::tuple<A1, A2, A3, A4, A5, A6> > {
+ typedef ::testing::tuple<Matcher<A1>, Matcher<A2>, Matcher<A3>, Matcher<A4>,
+ Matcher<A5>, Matcher<A6> > type;
+};
+
+template <typename A1, typename A2, typename A3, typename A4, typename A5,
+ typename A6, typename A7>
+struct MatcherTuple< ::testing::tuple<A1, A2, A3, A4, A5, A6, A7> > {
+ typedef ::testing::tuple<Matcher<A1>, Matcher<A2>, Matcher<A3>, Matcher<A4>,
+ Matcher<A5>, Matcher<A6>, Matcher<A7> > type;
+};
+
+template <typename A1, typename A2, typename A3, typename A4, typename A5,
+ typename A6, typename A7, typename A8>
+struct MatcherTuple< ::testing::tuple<A1, A2, A3, A4, A5, A6, A7, A8> > {
+ typedef ::testing::tuple<Matcher<A1>, Matcher<A2>, Matcher<A3>, Matcher<A4>,
+ Matcher<A5>, Matcher<A6>, Matcher<A7>, Matcher<A8> > type;
+};
+
+template <typename A1, typename A2, typename A3, typename A4, typename A5,
+ typename A6, typename A7, typename A8, typename A9>
+struct MatcherTuple< ::testing::tuple<A1, A2, A3, A4, A5, A6, A7, A8, A9> > {
+ typedef ::testing::tuple<Matcher<A1>, Matcher<A2>, Matcher<A3>, Matcher<A4>,
+ Matcher<A5>, Matcher<A6>, Matcher<A7>, Matcher<A8>, Matcher<A9> > type;
+};
+
+template <typename A1, typename A2, typename A3, typename A4, typename A5,
+ typename A6, typename A7, typename A8, typename A9, typename A10>
+struct MatcherTuple< ::testing::tuple<A1, A2, A3, A4, A5, A6, A7, A8, A9,
+ A10> > {
+ typedef ::testing::tuple<Matcher<A1>, Matcher<A2>, Matcher<A3>, Matcher<A4>,
+ Matcher<A5>, Matcher<A6>, Matcher<A7>, Matcher<A8>, Matcher<A9>,
+ Matcher<A10> > type;
+};
+
+// Template struct Function<F>, where F must be a function type, contains
+// the following typedefs:
+//
+// Result: the function's return type.
+// ArgumentN: the type of the N-th argument, where N starts with 1.
+// ArgumentTuple: the tuple type consisting of all parameters of F.
+// ArgumentMatcherTuple: the tuple type consisting of Matchers for all
+// parameters of F.
+// MakeResultVoid: the function type obtained by substituting void
+// for the return type of F.
+// MakeResultIgnoredValue:
+// the function type obtained by substituting Something
+// for the return type of F.
+template <typename F>
+struct Function;
+
+template <typename R>
+struct Function<R()> {
+ typedef R Result;
+ typedef ::testing::tuple<> ArgumentTuple;
+ typedef typename MatcherTuple<ArgumentTuple>::type ArgumentMatcherTuple;
+ typedef void MakeResultVoid();
+ typedef IgnoredValue MakeResultIgnoredValue();
+};
+
+template <typename R, typename A1>
+struct Function<R(A1)>
+ : Function<R()> {
+ typedef A1 Argument1;
+ typedef ::testing::tuple<A1> ArgumentTuple;
+ typedef typename MatcherTuple<ArgumentTuple>::type ArgumentMatcherTuple;
+ typedef void MakeResultVoid(A1);
+ typedef IgnoredValue MakeResultIgnoredValue(A1);
+};
+
+template <typename R, typename A1, typename A2>
+struct Function<R(A1, A2)>
+ : Function<R(A1)> {
+ typedef A2 Argument2;
+ typedef ::testing::tuple<A1, A2> ArgumentTuple;
+ typedef typename MatcherTuple<ArgumentTuple>::type ArgumentMatcherTuple;
+ typedef void MakeResultVoid(A1, A2);
+ typedef IgnoredValue MakeResultIgnoredValue(A1, A2);
+};
+
+template <typename R, typename A1, typename A2, typename A3>
+struct Function<R(A1, A2, A3)>
+ : Function<R(A1, A2)> {
+ typedef A3 Argument3;
+ typedef ::testing::tuple<A1, A2, A3> ArgumentTuple;
+ typedef typename MatcherTuple<ArgumentTuple>::type ArgumentMatcherTuple;
+ typedef void MakeResultVoid(A1, A2, A3);
+ typedef IgnoredValue MakeResultIgnoredValue(A1, A2, A3);
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4>
+struct Function<R(A1, A2, A3, A4)>
+ : Function<R(A1, A2, A3)> {
+ typedef A4 Argument4;
+ typedef ::testing::tuple<A1, A2, A3, A4> ArgumentTuple;
+ typedef typename MatcherTuple<ArgumentTuple>::type ArgumentMatcherTuple;
+ typedef void MakeResultVoid(A1, A2, A3, A4);
+ typedef IgnoredValue MakeResultIgnoredValue(A1, A2, A3, A4);
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5>
+struct Function<R(A1, A2, A3, A4, A5)>
+ : Function<R(A1, A2, A3, A4)> {
+ typedef A5 Argument5;
+ typedef ::testing::tuple<A1, A2, A3, A4, A5> ArgumentTuple;
+ typedef typename MatcherTuple<ArgumentTuple>::type ArgumentMatcherTuple;
+ typedef void MakeResultVoid(A1, A2, A3, A4, A5);
+ typedef IgnoredValue MakeResultIgnoredValue(A1, A2, A3, A4, A5);
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6>
+struct Function<R(A1, A2, A3, A4, A5, A6)>
+ : Function<R(A1, A2, A3, A4, A5)> {
+ typedef A6 Argument6;
+ typedef ::testing::tuple<A1, A2, A3, A4, A5, A6> ArgumentTuple;
+ typedef typename MatcherTuple<ArgumentTuple>::type ArgumentMatcherTuple;
+ typedef void MakeResultVoid(A1, A2, A3, A4, A5, A6);
+ typedef IgnoredValue MakeResultIgnoredValue(A1, A2, A3, A4, A5, A6);
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6, typename A7>
+struct Function<R(A1, A2, A3, A4, A5, A6, A7)>
+ : Function<R(A1, A2, A3, A4, A5, A6)> {
+ typedef A7 Argument7;
+ typedef ::testing::tuple<A1, A2, A3, A4, A5, A6, A7> ArgumentTuple;
+ typedef typename MatcherTuple<ArgumentTuple>::type ArgumentMatcherTuple;
+ typedef void MakeResultVoid(A1, A2, A3, A4, A5, A6, A7);
+ typedef IgnoredValue MakeResultIgnoredValue(A1, A2, A3, A4, A5, A6, A7);
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6, typename A7, typename A8>
+struct Function<R(A1, A2, A3, A4, A5, A6, A7, A8)>
+ : Function<R(A1, A2, A3, A4, A5, A6, A7)> {
+ typedef A8 Argument8;
+ typedef ::testing::tuple<A1, A2, A3, A4, A5, A6, A7, A8> ArgumentTuple;
+ typedef typename MatcherTuple<ArgumentTuple>::type ArgumentMatcherTuple;
+ typedef void MakeResultVoid(A1, A2, A3, A4, A5, A6, A7, A8);
+ typedef IgnoredValue MakeResultIgnoredValue(A1, A2, A3, A4, A5, A6, A7, A8);
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6, typename A7, typename A8, typename A9>
+struct Function<R(A1, A2, A3, A4, A5, A6, A7, A8, A9)>
+ : Function<R(A1, A2, A3, A4, A5, A6, A7, A8)> {
+ typedef A9 Argument9;
+ typedef ::testing::tuple<A1, A2, A3, A4, A5, A6, A7, A8, A9> ArgumentTuple;
+ typedef typename MatcherTuple<ArgumentTuple>::type ArgumentMatcherTuple;
+ typedef void MakeResultVoid(A1, A2, A3, A4, A5, A6, A7, A8, A9);
+ typedef IgnoredValue MakeResultIgnoredValue(A1, A2, A3, A4, A5, A6, A7, A8,
+ A9);
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6, typename A7, typename A8, typename A9,
+ typename A10>
+struct Function<R(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)>
+ : Function<R(A1, A2, A3, A4, A5, A6, A7, A8, A9)> {
+ typedef A10 Argument10;
+ typedef ::testing::tuple<A1, A2, A3, A4, A5, A6, A7, A8, A9,
+ A10> ArgumentTuple;
+ typedef typename MatcherTuple<ArgumentTuple>::type ArgumentMatcherTuple;
+ typedef void MakeResultVoid(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10);
+ typedef IgnoredValue MakeResultIgnoredValue(A1, A2, A3, A4, A5, A6, A7, A8,
+ A9, A10);
+};
+
+} // namespace internal
+
+} // namespace testing
+
+#endif // GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_GENERATED_INTERNAL_UTILS_H_
diff --git a/extern/gmock/include/gmock/internal/gmock-internal-utils.h b/extern/gmock/include/gmock/internal/gmock-internal-utils.h
new file mode 100644
index 00000000000..e2ddb05c91d
--- /dev/null
+++ b/extern/gmock/include/gmock/internal/gmock-internal-utils.h
@@ -0,0 +1,511 @@
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Google Mock - a framework for writing C++ mock classes.
+//
+// This file defines some utilities useful for implementing Google
+// Mock. They are subject to change without notice, so please DO NOT
+// USE THEM IN USER CODE.
+
+#ifndef GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_INTERNAL_UTILS_H_
+#define GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_INTERNAL_UTILS_H_
+
+#include <stdio.h>
+#include <ostream> // NOLINT
+#include <string>
+
+#include "gmock/internal/gmock-generated-internal-utils.h"
+#include "gmock/internal/gmock-port.h"
+#include "gtest/gtest.h"
+
+namespace testing {
+namespace internal {
+
+// Converts an identifier name to a space-separated list of lower-case
+// words. Each maximum substring of the form [A-Za-z][a-z]*|\d+ is
+// treated as one word. For example, both "FooBar123" and
+// "foo_bar_123" are converted to "foo bar 123".
+GTEST_API_ string ConvertIdentifierNameToWords(const char* id_name);
+
+// PointeeOf<Pointer>::type is the type of a value pointed to by a
+// Pointer, which can be either a smart pointer or a raw pointer. The
+// following default implementation is for the case where Pointer is a
+// smart pointer.
+template <typename Pointer>
+struct PointeeOf {
+ // Smart pointer classes define type element_type as the type of
+ // their pointees.
+ typedef typename Pointer::element_type type;
+};
+// This specialization is for the raw pointer case.
+template <typename T>
+struct PointeeOf<T*> { typedef T type; }; // NOLINT
+
+// GetRawPointer(p) returns the raw pointer underlying p when p is a
+// smart pointer, or returns p itself when p is already a raw pointer.
+// The following default implementation is for the smart pointer case.
+template <typename Pointer>
+inline const typename Pointer::element_type* GetRawPointer(const Pointer& p) {
+ return p.get();
+}
+// This overloaded version is for the raw pointer case.
+template <typename Element>
+inline Element* GetRawPointer(Element* p) { return p; }
+
+// This comparator allows linked_ptr to be stored in sets.
+template <typename T>
+struct LinkedPtrLessThan {
+ bool operator()(const ::testing::internal::linked_ptr<T>& lhs,
+ const ::testing::internal::linked_ptr<T>& rhs) const {
+ return lhs.get() < rhs.get();
+ }
+};
+
+// Symbian compilation can be done with wchar_t being either a native
+// type or a typedef. Using Google Mock with OpenC without wchar_t
+// should require the definition of _STLP_NO_WCHAR_T.
+//
+// MSVC treats wchar_t as a native type usually, but treats it as the
+// same as unsigned short when the compiler option /Zc:wchar_t- is
+// specified. It defines _NATIVE_WCHAR_T_DEFINED symbol when wchar_t
+// is a native type.
+#if (GTEST_OS_SYMBIAN && defined(_STLP_NO_WCHAR_T)) || \
+ (defined(_MSC_VER) && !defined(_NATIVE_WCHAR_T_DEFINED))
+// wchar_t is a typedef.
+#else
+# define GMOCK_WCHAR_T_IS_NATIVE_ 1
+#endif
+
+// signed wchar_t and unsigned wchar_t are NOT in the C++ standard.
+// Using them is a bad practice and not portable. So DON'T use them.
+//
+// Still, Google Mock is designed to work even if the user uses signed
+// wchar_t or unsigned wchar_t (obviously, assuming the compiler
+// supports them).
+//
+// To gcc,
+// wchar_t == signed wchar_t != unsigned wchar_t == unsigned int
+#ifdef __GNUC__
+// signed/unsigned wchar_t are valid types.
+# define GMOCK_HAS_SIGNED_WCHAR_T_ 1
+#endif
+
+// In what follows, we use the term "kind" to indicate whether a type
+// is bool, an integer type (excluding bool), a floating-point type,
+// or none of them. This categorization is useful for determining
+// when a matcher argument type can be safely converted to another
+// type in the implementation of SafeMatcherCast.
+enum TypeKind {
+ kBool, kInteger, kFloatingPoint, kOther
+};
+
+// KindOf<T>::value is the kind of type T.
+template <typename T> struct KindOf {
+ enum { value = kOther }; // The default kind.
+};
+
+// This macro declares that the kind of 'type' is 'kind'.
+#define GMOCK_DECLARE_KIND_(type, kind) \
+ template <> struct KindOf<type> { enum { value = kind }; }
+
+GMOCK_DECLARE_KIND_(bool, kBool);
+
+// All standard integer types.
+GMOCK_DECLARE_KIND_(char, kInteger);
+GMOCK_DECLARE_KIND_(signed char, kInteger);
+GMOCK_DECLARE_KIND_(unsigned char, kInteger);
+GMOCK_DECLARE_KIND_(short, kInteger); // NOLINT
+GMOCK_DECLARE_KIND_(unsigned short, kInteger); // NOLINT
+GMOCK_DECLARE_KIND_(int, kInteger);
+GMOCK_DECLARE_KIND_(unsigned int, kInteger);
+GMOCK_DECLARE_KIND_(long, kInteger); // NOLINT
+GMOCK_DECLARE_KIND_(unsigned long, kInteger); // NOLINT
+
+#if GMOCK_WCHAR_T_IS_NATIVE_
+GMOCK_DECLARE_KIND_(wchar_t, kInteger);
+#endif
+
+// Non-standard integer types.
+GMOCK_DECLARE_KIND_(Int64, kInteger);
+GMOCK_DECLARE_KIND_(UInt64, kInteger);
+
+// All standard floating-point types.
+GMOCK_DECLARE_KIND_(float, kFloatingPoint);
+GMOCK_DECLARE_KIND_(double, kFloatingPoint);
+GMOCK_DECLARE_KIND_(long double, kFloatingPoint);
+
+#undef GMOCK_DECLARE_KIND_
+
+// Evaluates to the kind of 'type'.
+#define GMOCK_KIND_OF_(type) \
+ static_cast< ::testing::internal::TypeKind>( \
+ ::testing::internal::KindOf<type>::value)
+
+// Evaluates to true iff integer type T is signed.
+#define GMOCK_IS_SIGNED_(T) (static_cast<T>(-1) < 0)
+
+// LosslessArithmeticConvertibleImpl<kFromKind, From, kToKind, To>::value
+// is true iff arithmetic type From can be losslessly converted to
+// arithmetic type To.
+//
+// It's the user's responsibility to ensure that both From and To are
+// raw (i.e. has no CV modifier, is not a pointer, and is not a
+// reference) built-in arithmetic types, kFromKind is the kind of
+// From, and kToKind is the kind of To; the value is
+// implementation-defined when the above pre-condition is violated.
+template <TypeKind kFromKind, typename From, TypeKind kToKind, typename To>
+struct LosslessArithmeticConvertibleImpl : public false_type {};
+
+// Converting bool to bool is lossless.
+template <>
+struct LosslessArithmeticConvertibleImpl<kBool, bool, kBool, bool>
+ : public true_type {}; // NOLINT
+
+// Converting bool to any integer type is lossless.
+template <typename To>
+struct LosslessArithmeticConvertibleImpl<kBool, bool, kInteger, To>
+ : public true_type {}; // NOLINT
+
+// Converting bool to any floating-point type is lossless.
+template <typename To>
+struct LosslessArithmeticConvertibleImpl<kBool, bool, kFloatingPoint, To>
+ : public true_type {}; // NOLINT
+
+// Converting an integer to bool is lossy.
+template <typename From>
+struct LosslessArithmeticConvertibleImpl<kInteger, From, kBool, bool>
+ : public false_type {}; // NOLINT
+
+// Converting an integer to another non-bool integer is lossless iff
+// the target type's range encloses the source type's range.
+template <typename From, typename To>
+struct LosslessArithmeticConvertibleImpl<kInteger, From, kInteger, To>
+ : public bool_constant<
+ // When converting from a smaller size to a larger size, we are
+ // fine as long as we are not converting from signed to unsigned.
+ ((sizeof(From) < sizeof(To)) &&
+ (!GMOCK_IS_SIGNED_(From) || GMOCK_IS_SIGNED_(To))) ||
+ // When converting between the same size, the signedness must match.
+ ((sizeof(From) == sizeof(To)) &&
+ (GMOCK_IS_SIGNED_(From) == GMOCK_IS_SIGNED_(To)))> {}; // NOLINT
+
+#undef GMOCK_IS_SIGNED_
+
+// Converting an integer to a floating-point type may be lossy, since
+// the format of a floating-point number is implementation-defined.
+template <typename From, typename To>
+struct LosslessArithmeticConvertibleImpl<kInteger, From, kFloatingPoint, To>
+ : public false_type {}; // NOLINT
+
+// Converting a floating-point to bool is lossy.
+template <typename From>
+struct LosslessArithmeticConvertibleImpl<kFloatingPoint, From, kBool, bool>
+ : public false_type {}; // NOLINT
+
+// Converting a floating-point to an integer is lossy.
+template <typename From, typename To>
+struct LosslessArithmeticConvertibleImpl<kFloatingPoint, From, kInteger, To>
+ : public false_type {}; // NOLINT
+
+// Converting a floating-point to another floating-point is lossless
+// iff the target type is at least as big as the source type.
+template <typename From, typename To>
+struct LosslessArithmeticConvertibleImpl<
+ kFloatingPoint, From, kFloatingPoint, To>
+ : public bool_constant<sizeof(From) <= sizeof(To)> {}; // NOLINT
+
+// LosslessArithmeticConvertible<From, To>::value is true iff arithmetic
+// type From can be losslessly converted to arithmetic type To.
+//
+// It's the user's responsibility to ensure that both From and To are
+// raw (i.e. has no CV modifier, is not a pointer, and is not a
+// reference) built-in arithmetic types; the value is
+// implementation-defined when the above pre-condition is violated.
+template <typename From, typename To>
+struct LosslessArithmeticConvertible
+ : public LosslessArithmeticConvertibleImpl<
+ GMOCK_KIND_OF_(From), From, GMOCK_KIND_OF_(To), To> {}; // NOLINT
+
+// This interface knows how to report a Google Mock failure (either
+// non-fatal or fatal).
+class FailureReporterInterface {
+ public:
+ // The type of a failure (either non-fatal or fatal).
+ enum FailureType {
+ kNonfatal, kFatal
+ };
+
+ virtual ~FailureReporterInterface() {}
+
+ // Reports a failure that occurred at the given source file location.
+ virtual void ReportFailure(FailureType type, const char* file, int line,
+ const string& message) = 0;
+};
+
+// Returns the failure reporter used by Google Mock.
+GTEST_API_ FailureReporterInterface* GetFailureReporter();
+
+// Asserts that condition is true; aborts the process with the given
+// message if condition is false. We cannot use LOG(FATAL) or CHECK()
+// as Google Mock might be used to mock the log sink itself. We
+// inline this function to prevent it from showing up in the stack
+// trace.
+inline void Assert(bool condition, const char* file, int line,
+ const string& msg) {
+ if (!condition) {
+ GetFailureReporter()->ReportFailure(FailureReporterInterface::kFatal,
+ file, line, msg);
+ }
+}
+inline void Assert(bool condition, const char* file, int line) {
+ Assert(condition, file, line, "Assertion failed.");
+}
+
+// Verifies that condition is true; generates a non-fatal failure if
+// condition is false.
+inline void Expect(bool condition, const char* file, int line,
+ const string& msg) {
+ if (!condition) {
+ GetFailureReporter()->ReportFailure(FailureReporterInterface::kNonfatal,
+ file, line, msg);
+ }
+}
+inline void Expect(bool condition, const char* file, int line) {
+ Expect(condition, file, line, "Expectation failed.");
+}
+
+// Severity level of a log.
+enum LogSeverity {
+ kInfo = 0,
+ kWarning = 1
+};
+
+// Valid values for the --gmock_verbose flag.
+
+// All logs (informational and warnings) are printed.
+const char kInfoVerbosity[] = "info";
+// Only warnings are printed.
+const char kWarningVerbosity[] = "warning";
+// No logs are printed.
+const char kErrorVerbosity[] = "error";
+
+// Returns true iff a log with the given severity is visible according
+// to the --gmock_verbose flag.
+GTEST_API_ bool LogIsVisible(LogSeverity severity);
+
+// Prints the given message to stdout iff 'severity' >= the level
+// specified by the --gmock_verbose flag. If stack_frames_to_skip >=
+// 0, also prints the stack trace excluding the top
+// stack_frames_to_skip frames. In opt mode, any positive
+// stack_frames_to_skip is treated as 0, since we don't know which
+// function calls will be inlined by the compiler and need to be
+// conservative.
+GTEST_API_ void Log(LogSeverity severity,
+ const string& message,
+ int stack_frames_to_skip);
+
+// TODO(wan@google.com): group all type utilities together.
+
+// Type traits.
+
+// is_reference<T>::value is non-zero iff T is a reference type.
+template <typename T> struct is_reference : public false_type {};
+template <typename T> struct is_reference<T&> : public true_type {};
+
+// type_equals<T1, T2>::value is non-zero iff T1 and T2 are the same type.
+template <typename T1, typename T2> struct type_equals : public false_type {};
+template <typename T> struct type_equals<T, T> : public true_type {};
+
+// remove_reference<T>::type removes the reference from type T, if any.
+template <typename T> struct remove_reference { typedef T type; }; // NOLINT
+template <typename T> struct remove_reference<T&> { typedef T type; }; // NOLINT
+
+// DecayArray<T>::type turns an array type U[N] to const U* and preserves
+// other types. Useful for saving a copy of a function argument.
+template <typename T> struct DecayArray { typedef T type; }; // NOLINT
+template <typename T, size_t N> struct DecayArray<T[N]> {
+ typedef const T* type;
+};
+// Sometimes people use arrays whose size is not available at the use site
+// (e.g. extern const char kNamePrefix[]). This specialization covers that
+// case.
+template <typename T> struct DecayArray<T[]> {
+ typedef const T* type;
+};
+
+// Disable MSVC warnings for infinite recursion, since in this case the
+// the recursion is unreachable.
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable:4717)
+#endif
+
+// Invalid<T>() is usable as an expression of type T, but will terminate
+// the program with an assertion failure if actually run. This is useful
+// when a value of type T is needed for compilation, but the statement
+// will not really be executed (or we don't care if the statement
+// crashes).
+template <typename T>
+inline T Invalid() {
+ Assert(false, "", -1, "Internal error: attempt to return invalid value");
+ // This statement is unreachable, and would never terminate even if it
+ // could be reached. It is provided only to placate compiler warnings
+ // about missing return statements.
+ return Invalid<T>();
+}
+
+#ifdef _MSC_VER
+# pragma warning(pop)
+#endif
+
+// Given a raw type (i.e. having no top-level reference or const
+// modifier) RawContainer that's either an STL-style container or a
+// native array, class StlContainerView<RawContainer> has the
+// following members:
+//
+// - type is a type that provides an STL-style container view to
+// (i.e. implements the STL container concept for) RawContainer;
+// - const_reference is a type that provides a reference to a const
+// RawContainer;
+// - ConstReference(raw_container) returns a const reference to an STL-style
+// container view to raw_container, which is a RawContainer.
+// - Copy(raw_container) returns an STL-style container view of a
+// copy of raw_container, which is a RawContainer.
+//
+// This generic version is used when RawContainer itself is already an
+// STL-style container.
+template <class RawContainer>
+class StlContainerView {
+ public:
+ typedef RawContainer type;
+ typedef const type& const_reference;
+
+ static const_reference ConstReference(const RawContainer& container) {
+ // Ensures that RawContainer is not a const type.
+ testing::StaticAssertTypeEq<RawContainer,
+ GTEST_REMOVE_CONST_(RawContainer)>();
+ return container;
+ }
+ static type Copy(const RawContainer& container) { return container; }
+};
+
+// This specialization is used when RawContainer is a native array type.
+template <typename Element, size_t N>
+class StlContainerView<Element[N]> {
+ public:
+ typedef GTEST_REMOVE_CONST_(Element) RawElement;
+ typedef internal::NativeArray<RawElement> type;
+ // NativeArray<T> can represent a native array either by value or by
+ // reference (selected by a constructor argument), so 'const type'
+ // can be used to reference a const native array. We cannot
+ // 'typedef const type& const_reference' here, as that would mean
+ // ConstReference() has to return a reference to a local variable.
+ typedef const type const_reference;
+
+ static const_reference ConstReference(const Element (&array)[N]) {
+ // Ensures that Element is not a const type.
+ testing::StaticAssertTypeEq<Element, RawElement>();
+#if GTEST_OS_SYMBIAN
+ // The Nokia Symbian compiler confuses itself in template instantiation
+ // for this call without the cast to Element*:
+ // function call '[testing::internal::NativeArray<char *>].NativeArray(
+ // {lval} const char *[4], long, testing::internal::RelationToSource)'
+ // does not match
+ // 'testing::internal::NativeArray<char *>::NativeArray(
+ // char *const *, unsigned int, testing::internal::RelationToSource)'
+ // (instantiating: 'testing::internal::ContainsMatcherImpl
+ // <const char * (&)[4]>::Matches(const char * (&)[4]) const')
+ // (instantiating: 'testing::internal::StlContainerView<char *[4]>::
+ // ConstReference(const char * (&)[4])')
+ // (and though the N parameter type is mismatched in the above explicit
+ // conversion of it doesn't help - only the conversion of the array).
+ return type(const_cast<Element*>(&array[0]), N,
+ RelationToSourceReference());
+#else
+ return type(array, N, RelationToSourceReference());
+#endif // GTEST_OS_SYMBIAN
+ }
+ static type Copy(const Element (&array)[N]) {
+#if GTEST_OS_SYMBIAN
+ return type(const_cast<Element*>(&array[0]), N, RelationToSourceCopy());
+#else
+ return type(array, N, RelationToSourceCopy());
+#endif // GTEST_OS_SYMBIAN
+ }
+};
+
+// This specialization is used when RawContainer is a native array
+// represented as a (pointer, size) tuple.
+template <typename ElementPointer, typename Size>
+class StlContainerView< ::testing::tuple<ElementPointer, Size> > {
+ public:
+ typedef GTEST_REMOVE_CONST_(
+ typename internal::PointeeOf<ElementPointer>::type) RawElement;
+ typedef internal::NativeArray<RawElement> type;
+ typedef const type const_reference;
+
+ static const_reference ConstReference(
+ const ::testing::tuple<ElementPointer, Size>& array) {
+ return type(get<0>(array), get<1>(array), RelationToSourceReference());
+ }
+ static type Copy(const ::testing::tuple<ElementPointer, Size>& array) {
+ return type(get<0>(array), get<1>(array), RelationToSourceCopy());
+ }
+};
+
+// The following specialization prevents the user from instantiating
+// StlContainer with a reference type.
+template <typename T> class StlContainerView<T&>;
+
+// A type transform to remove constness from the first part of a pair.
+// Pairs like that are used as the value_type of associative containers,
+// and this transform produces a similar but assignable pair.
+template <typename T>
+struct RemoveConstFromKey {
+ typedef T type;
+};
+
+// Partially specialized to remove constness from std::pair<const K, V>.
+template <typename K, typename V>
+struct RemoveConstFromKey<std::pair<const K, V> > {
+ typedef std::pair<K, V> type;
+};
+
+// Mapping from booleans to types. Similar to boost::bool_<kValue> and
+// std::integral_constant<bool, kValue>.
+template <bool kValue>
+struct BooleanConstant {};
+
+} // namespace internal
+} // namespace testing
+
+#endif // GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_INTERNAL_UTILS_H_
+
diff --git a/extern/gmock/include/gmock/internal/gmock-port.h b/extern/gmock/include/gmock/internal/gmock-port.h
new file mode 100644
index 00000000000..63f4a6802e8
--- /dev/null
+++ b/extern/gmock/include/gmock/internal/gmock-port.h
@@ -0,0 +1,91 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vadimb@google.com (Vadim Berman)
+//
+// Low-level types and utilities for porting Google Mock to various
+// platforms. All macros ending with _ and symbols defined in an
+// internal namespace are subject to change without notice. Code
+// outside Google Mock MUST NOT USE THEM DIRECTLY. Macros that don't
+// end with _ are part of Google Mock's public API and can be used by
+// code outside Google Mock.
+
+#ifndef GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_PORT_H_
+#define GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_PORT_H_
+
+#include <assert.h>
+#include <stdlib.h>
+#include <iostream>
+
+// Most of the utilities needed for porting Google Mock are also
+// required for Google Test and are defined in gtest-port.h.
+//
+// Note to maintainers: to reduce code duplication, prefer adding
+// portability utilities to Google Test's gtest-port.h instead of
+// here, as Google Mock depends on Google Test. Only add a utility
+// here if it's truly specific to Google Mock.
+#include "gtest/internal/gtest-linked_ptr.h"
+#include "gtest/internal/gtest-port.h"
+#include "gmock/internal/custom/gmock-port.h"
+
+// To avoid conditional compilation everywhere, we make it
+// gmock-port.h's responsibility to #include the header implementing
+// tr1/tuple. gmock-port.h does this via gtest-port.h, which is
+// guaranteed to pull in the tuple header.
+
+// For MS Visual C++, check the compiler version. At least VS 2003 is
+// required to compile Google Mock.
+#if defined(_MSC_VER) && _MSC_VER < 1310
+# error "At least Visual C++ 2003 (7.1) is required to compile Google Mock."
+#endif
+
+// Macro for referencing flags. This is public as we want the user to
+// use this syntax to reference Google Mock flags.
+#define GMOCK_FLAG(name) FLAGS_gmock_##name
+
+#if !defined(GMOCK_DECLARE_bool_)
+
+// Macros for declaring flags.
+#define GMOCK_DECLARE_bool_(name) extern GTEST_API_ bool GMOCK_FLAG(name)
+#define GMOCK_DECLARE_int32_(name) \
+ extern GTEST_API_ ::testing::internal::Int32 GMOCK_FLAG(name)
+#define GMOCK_DECLARE_string_(name) \
+ extern GTEST_API_ ::std::string GMOCK_FLAG(name)
+
+// Macros for defining flags.
+#define GMOCK_DEFINE_bool_(name, default_val, doc) \
+ GTEST_API_ bool GMOCK_FLAG(name) = (default_val)
+#define GMOCK_DEFINE_int32_(name, default_val, doc) \
+ GTEST_API_ ::testing::internal::Int32 GMOCK_FLAG(name) = (default_val)
+#define GMOCK_DEFINE_string_(name, default_val, doc) \
+ GTEST_API_ ::std::string GMOCK_FLAG(name) = (default_val)
+
+#endif // !defined(GMOCK_DECLARE_bool_)
+
+#endif // GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_PORT_H_
diff --git a/extern/gmock/src/gmock-all.cc b/extern/gmock/src/gmock-all.cc
new file mode 100644
index 00000000000..7aebce7afef
--- /dev/null
+++ b/extern/gmock/src/gmock-all.cc
@@ -0,0 +1,47 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// Google C++ Mocking Framework (Google Mock)
+//
+// This file #includes all Google Mock implementation .cc files. The
+// purpose is to allow a user to build Google Mock by compiling this
+// file alone.
+
+// This line ensures that gmock.h can be compiled on its own, even
+// when it's fused.
+#include "gmock/gmock.h"
+
+// The following lines pull in the real gmock *.cc files.
+#include "src/gmock-cardinalities.cc"
+#include "src/gmock-internal-utils.cc"
+#include "src/gmock-matchers.cc"
+#include "src/gmock-spec-builders.cc"
+#include "src/gmock.cc"
diff --git a/extern/gmock/src/gmock-cardinalities.cc b/extern/gmock/src/gmock-cardinalities.cc
new file mode 100644
index 00000000000..50ec7286eeb
--- /dev/null
+++ b/extern/gmock/src/gmock-cardinalities.cc
@@ -0,0 +1,156 @@
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Google Mock - a framework for writing C++ mock classes.
+//
+// This file implements cardinalities.
+
+#include "gmock/gmock-cardinalities.h"
+
+#include <limits.h>
+#include <ostream> // NOLINT
+#include <sstream>
+#include <string>
+#include "gmock/internal/gmock-internal-utils.h"
+#include "gtest/gtest.h"
+
+namespace testing {
+
+namespace {
+
+// Implements the Between(m, n) cardinality.
+class BetweenCardinalityImpl : public CardinalityInterface {
+ public:
+ BetweenCardinalityImpl(int min, int max)
+ : min_(min >= 0 ? min : 0),
+ max_(max >= min_ ? max : min_) {
+ std::stringstream ss;
+ if (min < 0) {
+ ss << "The invocation lower bound must be >= 0, "
+ << "but is actually " << min << ".";
+ internal::Expect(false, __FILE__, __LINE__, ss.str());
+ } else if (max < 0) {
+ ss << "The invocation upper bound must be >= 0, "
+ << "but is actually " << max << ".";
+ internal::Expect(false, __FILE__, __LINE__, ss.str());
+ } else if (min > max) {
+ ss << "The invocation upper bound (" << max
+ << ") must be >= the invocation lower bound (" << min
+ << ").";
+ internal::Expect(false, __FILE__, __LINE__, ss.str());
+ }
+ }
+
+ // Conservative estimate on the lower/upper bound of the number of
+ // calls allowed.
+ virtual int ConservativeLowerBound() const { return min_; }
+ virtual int ConservativeUpperBound() const { return max_; }
+
+ virtual bool IsSatisfiedByCallCount(int call_count) const {
+ return min_ <= call_count && call_count <= max_;
+ }
+
+ virtual bool IsSaturatedByCallCount(int call_count) const {
+ return call_count >= max_;
+ }
+
+ virtual void DescribeTo(::std::ostream* os) const;
+
+ private:
+ const int min_;
+ const int max_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(BetweenCardinalityImpl);
+};
+
+// Formats "n times" in a human-friendly way.
+inline internal::string FormatTimes(int n) {
+ if (n == 1) {
+ return "once";
+ } else if (n == 2) {
+ return "twice";
+ } else {
+ std::stringstream ss;
+ ss << n << " times";
+ return ss.str();
+ }
+}
+
+// Describes the Between(m, n) cardinality in human-friendly text.
+void BetweenCardinalityImpl::DescribeTo(::std::ostream* os) const {
+ if (min_ == 0) {
+ if (max_ == 0) {
+ *os << "never called";
+ } else if (max_ == INT_MAX) {
+ *os << "called any number of times";
+ } else {
+ *os << "called at most " << FormatTimes(max_);
+ }
+ } else if (min_ == max_) {
+ *os << "called " << FormatTimes(min_);
+ } else if (max_ == INT_MAX) {
+ *os << "called at least " << FormatTimes(min_);
+ } else {
+ // 0 < min_ < max_ < INT_MAX
+ *os << "called between " << min_ << " and " << max_ << " times";
+ }
+}
+
+} // Unnamed namespace
+
+// Describes the given call count to an ostream.
+void Cardinality::DescribeActualCallCountTo(int actual_call_count,
+ ::std::ostream* os) {
+ if (actual_call_count > 0) {
+ *os << "called " << FormatTimes(actual_call_count);
+ } else {
+ *os << "never called";
+ }
+}
+
+// Creates a cardinality that allows at least n calls.
+GTEST_API_ Cardinality AtLeast(int n) { return Between(n, INT_MAX); }
+
+// Creates a cardinality that allows at most n calls.
+GTEST_API_ Cardinality AtMost(int n) { return Between(0, n); }
+
+// Creates a cardinality that allows any number of calls.
+GTEST_API_ Cardinality AnyNumber() { return AtLeast(0); }
+
+// Creates a cardinality that allows between min and max calls.
+GTEST_API_ Cardinality Between(int min, int max) {
+ return Cardinality(new BetweenCardinalityImpl(min, max));
+}
+
+// Creates a cardinality that allows exactly n calls.
+GTEST_API_ Cardinality Exactly(int n) { return Between(n, n); }
+
+} // namespace testing
diff --git a/extern/gmock/src/gmock-internal-utils.cc b/extern/gmock/src/gmock-internal-utils.cc
new file mode 100644
index 00000000000..fb5308018a7
--- /dev/null
+++ b/extern/gmock/src/gmock-internal-utils.cc
@@ -0,0 +1,174 @@
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Google Mock - a framework for writing C++ mock classes.
+//
+// This file defines some utilities useful for implementing Google
+// Mock. They are subject to change without notice, so please DO NOT
+// USE THEM IN USER CODE.
+
+#include "gmock/internal/gmock-internal-utils.h"
+
+#include <ctype.h>
+#include <ostream> // NOLINT
+#include <string>
+#include "gmock/gmock.h"
+#include "gmock/internal/gmock-port.h"
+#include "gtest/gtest.h"
+
+namespace testing {
+namespace internal {
+
+// Converts an identifier name to a space-separated list of lower-case
+// words. Each maximum substring of the form [A-Za-z][a-z]*|\d+ is
+// treated as one word. For example, both "FooBar123" and
+// "foo_bar_123" are converted to "foo bar 123".
+GTEST_API_ string ConvertIdentifierNameToWords(const char* id_name) {
+ string result;
+ char prev_char = '\0';
+ for (const char* p = id_name; *p != '\0'; prev_char = *(p++)) {
+ // We don't care about the current locale as the input is
+ // guaranteed to be a valid C++ identifier name.
+ const bool starts_new_word = IsUpper(*p) ||
+ (!IsAlpha(prev_char) && IsLower(*p)) ||
+ (!IsDigit(prev_char) && IsDigit(*p));
+
+ if (IsAlNum(*p)) {
+ if (starts_new_word && result != "")
+ result += ' ';
+ result += ToLower(*p);
+ }
+ }
+ return result;
+}
+
+// This class reports Google Mock failures as Google Test failures. A
+// user can define another class in a similar fashion if he intends to
+// use Google Mock with a testing framework other than Google Test.
+class GoogleTestFailureReporter : public FailureReporterInterface {
+ public:
+ virtual void ReportFailure(FailureType type, const char* file, int line,
+ const string& message) {
+ AssertHelper(type == kFatal ?
+ TestPartResult::kFatalFailure :
+ TestPartResult::kNonFatalFailure,
+ file,
+ line,
+ message.c_str()) = Message();
+ if (type == kFatal) {
+ posix::Abort();
+ }
+ }
+};
+
+// Returns the global failure reporter. Will create a
+// GoogleTestFailureReporter and return it the first time called.
+GTEST_API_ FailureReporterInterface* GetFailureReporter() {
+ // Points to the global failure reporter used by Google Mock. gcc
+ // guarantees that the following use of failure_reporter is
+ // thread-safe. We may need to add additional synchronization to
+ // protect failure_reporter if we port Google Mock to other
+ // compilers.
+ static FailureReporterInterface* const failure_reporter =
+ new GoogleTestFailureReporter();
+ return failure_reporter;
+}
+
+// Protects global resources (stdout in particular) used by Log().
+static GTEST_DEFINE_STATIC_MUTEX_(g_log_mutex);
+
+// Returns true iff a log with the given severity is visible according
+// to the --gmock_verbose flag.
+GTEST_API_ bool LogIsVisible(LogSeverity severity) {
+ if (GMOCK_FLAG(verbose) == kInfoVerbosity) {
+ // Always show the log if --gmock_verbose=info.
+ return true;
+ } else if (GMOCK_FLAG(verbose) == kErrorVerbosity) {
+ // Always hide it if --gmock_verbose=error.
+ return false;
+ } else {
+ // If --gmock_verbose is neither "info" nor "error", we treat it
+ // as "warning" (its default value).
+ return severity == kWarning;
+ }
+}
+
+// Prints the given message to stdout iff 'severity' >= the level
+// specified by the --gmock_verbose flag. If stack_frames_to_skip >=
+// 0, also prints the stack trace excluding the top
+// stack_frames_to_skip frames. In opt mode, any positive
+// stack_frames_to_skip is treated as 0, since we don't know which
+// function calls will be inlined by the compiler and need to be
+// conservative.
+GTEST_API_ void Log(LogSeverity severity,
+ const string& message,
+ int stack_frames_to_skip) {
+ if (!LogIsVisible(severity))
+ return;
+
+ // Ensures that logs from different threads don't interleave.
+ MutexLock l(&g_log_mutex);
+
+ // "using ::std::cout;" doesn't work with Symbian's STLport, where cout is a
+ // macro.
+
+ if (severity == kWarning) {
+ // Prints a GMOCK WARNING marker to make the warnings easily searchable.
+ std::cout << "\nGMOCK WARNING:";
+ }
+ // Pre-pends a new-line to message if it doesn't start with one.
+ if (message.empty() || message[0] != '\n') {
+ std::cout << "\n";
+ }
+ std::cout << message;
+ if (stack_frames_to_skip >= 0) {
+#ifdef NDEBUG
+ // In opt mode, we have to be conservative and skip no stack frame.
+ const int actual_to_skip = 0;
+#else
+ // In dbg mode, we can do what the caller tell us to do (plus one
+ // for skipping this function's stack frame).
+ const int actual_to_skip = stack_frames_to_skip + 1;
+#endif // NDEBUG
+
+ // Appends a new-line to message if it doesn't end with one.
+ if (!message.empty() && *message.rbegin() != '\n') {
+ std::cout << "\n";
+ }
+ std::cout << "Stack trace:\n"
+ << ::testing::internal::GetCurrentOsStackTraceExceptTop(
+ ::testing::UnitTest::GetInstance(), actual_to_skip);
+ }
+ std::cout << ::std::flush;
+}
+
+} // namespace internal
+} // namespace testing
diff --git a/extern/gmock/src/gmock-matchers.cc b/extern/gmock/src/gmock-matchers.cc
new file mode 100644
index 00000000000..e7424510fca
--- /dev/null
+++ b/extern/gmock/src/gmock-matchers.cc
@@ -0,0 +1,498 @@
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Google Mock - a framework for writing C++ mock classes.
+//
+// This file implements Matcher<const string&>, Matcher<string>, and
+// utilities for defining matchers.
+
+#include "gmock/gmock-matchers.h"
+#include "gmock/gmock-generated-matchers.h"
+
+#include <string.h>
+#include <sstream>
+#include <string>
+
+namespace testing {
+
+// Constructs a matcher that matches a const string& whose value is
+// equal to s.
+Matcher<const internal::string&>::Matcher(const internal::string& s) {
+ *this = Eq(s);
+}
+
+// Constructs a matcher that matches a const string& whose value is
+// equal to s.
+Matcher<const internal::string&>::Matcher(const char* s) {
+ *this = Eq(internal::string(s));
+}
+
+// Constructs a matcher that matches a string whose value is equal to s.
+Matcher<internal::string>::Matcher(const internal::string& s) { *this = Eq(s); }
+
+// Constructs a matcher that matches a string whose value is equal to s.
+Matcher<internal::string>::Matcher(const char* s) {
+ *this = Eq(internal::string(s));
+}
+
+#if GTEST_HAS_STRING_PIECE_
+// Constructs a matcher that matches a const StringPiece& whose value is
+// equal to s.
+Matcher<const StringPiece&>::Matcher(const internal::string& s) {
+ *this = Eq(s);
+}
+
+// Constructs a matcher that matches a const StringPiece& whose value is
+// equal to s.
+Matcher<const StringPiece&>::Matcher(const char* s) {
+ *this = Eq(internal::string(s));
+}
+
+// Constructs a matcher that matches a const StringPiece& whose value is
+// equal to s.
+Matcher<const StringPiece&>::Matcher(StringPiece s) {
+ *this = Eq(s.ToString());
+}
+
+// Constructs a matcher that matches a StringPiece whose value is equal to s.
+Matcher<StringPiece>::Matcher(const internal::string& s) {
+ *this = Eq(s);
+}
+
+// Constructs a matcher that matches a StringPiece whose value is equal to s.
+Matcher<StringPiece>::Matcher(const char* s) {
+ *this = Eq(internal::string(s));
+}
+
+// Constructs a matcher that matches a StringPiece whose value is equal to s.
+Matcher<StringPiece>::Matcher(StringPiece s) {
+ *this = Eq(s.ToString());
+}
+#endif // GTEST_HAS_STRING_PIECE_
+
+namespace internal {
+
+// Joins a vector of strings as if they are fields of a tuple; returns
+// the joined string.
+GTEST_API_ string JoinAsTuple(const Strings& fields) {
+ switch (fields.size()) {
+ case 0:
+ return "";
+ case 1:
+ return fields[0];
+ default:
+ string result = "(" + fields[0];
+ for (size_t i = 1; i < fields.size(); i++) {
+ result += ", ";
+ result += fields[i];
+ }
+ result += ")";
+ return result;
+ }
+}
+
+// Returns the description for a matcher defined using the MATCHER*()
+// macro where the user-supplied description string is "", if
+// 'negation' is false; otherwise returns the description of the
+// negation of the matcher. 'param_values' contains a list of strings
+// that are the print-out of the matcher's parameters.
+GTEST_API_ string FormatMatcherDescription(bool negation,
+ const char* matcher_name,
+ const Strings& param_values) {
+ string result = ConvertIdentifierNameToWords(matcher_name);
+ if (param_values.size() >= 1)
+ result += " " + JoinAsTuple(param_values);
+ return negation ? "not (" + result + ")" : result;
+}
+
+// FindMaxBipartiteMatching and its helper class.
+//
+// Uses the well-known Ford-Fulkerson max flow method to find a maximum
+// bipartite matching. Flow is considered to be from left to right.
+// There is an implicit source node that is connected to all of the left
+// nodes, and an implicit sink node that is connected to all of the
+// right nodes. All edges have unit capacity.
+//
+// Neither the flow graph nor the residual flow graph are represented
+// explicitly. Instead, they are implied by the information in 'graph' and
+// a vector<int> called 'left_' whose elements are initialized to the
+// value kUnused. This represents the initial state of the algorithm,
+// where the flow graph is empty, and the residual flow graph has the
+// following edges:
+// - An edge from source to each left_ node
+// - An edge from each right_ node to sink
+// - An edge from each left_ node to each right_ node, if the
+// corresponding edge exists in 'graph'.
+//
+// When the TryAugment() method adds a flow, it sets left_[l] = r for some
+// nodes l and r. This induces the following changes:
+// - The edges (source, l), (l, r), and (r, sink) are added to the
+// flow graph.
+// - The same three edges are removed from the residual flow graph.
+// - The reverse edges (l, source), (r, l), and (sink, r) are added
+// to the residual flow graph, which is a directional graph
+// representing unused flow capacity.
+//
+// When the method augments a flow (moving left_[l] from some r1 to some
+// other r2), this can be thought of as "undoing" the above steps with
+// respect to r1 and "redoing" them with respect to r2.
+//
+// It bears repeating that the flow graph and residual flow graph are
+// never represented explicitly, but can be derived by looking at the
+// information in 'graph' and in left_.
+//
+// As an optimization, there is a second vector<int> called right_ which
+// does not provide any new information. Instead, it enables more
+// efficient queries about edges entering or leaving the right-side nodes
+// of the flow or residual flow graphs. The following invariants are
+// maintained:
+//
+// left[l] == kUnused or right[left[l]] == l
+// right[r] == kUnused or left[right[r]] == r
+//
+// . [ source ] .
+// . ||| .
+// . ||| .
+// . ||\--> left[0]=1 ---\ right[0]=-1 ----\ .
+// . || | | .
+// . |\---> left[1]=-1 \--> right[1]=0 ---\| .
+// . | || .
+// . \----> left[2]=2 ------> right[2]=2 --\|| .
+// . ||| .
+// . elements matchers vvv .
+// . [ sink ] .
+//
+// See Also:
+// [1] Cormen, et al (2001). "Section 26.2: The Ford-Fulkerson method".
+// "Introduction to Algorithms (Second ed.)", pp. 651-664.
+// [2] "Ford-Fulkerson algorithm", Wikipedia,
+// 'http://en.wikipedia.org/wiki/Ford%E2%80%93Fulkerson_algorithm'
+class MaxBipartiteMatchState {
+ public:
+ explicit MaxBipartiteMatchState(const MatchMatrix& graph)
+ : graph_(&graph),
+ left_(graph_->LhsSize(), kUnused),
+ right_(graph_->RhsSize(), kUnused) {
+ }
+
+ // Returns the edges of a maximal match, each in the form {left, right}.
+ ElementMatcherPairs Compute() {
+ // 'seen' is used for path finding { 0: unseen, 1: seen }.
+ ::std::vector<char> seen;
+ // Searches the residual flow graph for a path from each left node to
+ // the sink in the residual flow graph, and if one is found, add flow
+ // to the graph. It's okay to search through the left nodes once. The
+ // edge from the implicit source node to each previously-visited left
+ // node will have flow if that left node has any path to the sink
+ // whatsoever. Subsequent augmentations can only add flow to the
+ // network, and cannot take away that previous flow unit from the source.
+ // Since the source-to-left edge can only carry one flow unit (or,
+ // each element can be matched to only one matcher), there is no need
+ // to visit the left nodes more than once looking for augmented paths.
+ // The flow is known to be possible or impossible by looking at the
+ // node once.
+ for (size_t ilhs = 0; ilhs < graph_->LhsSize(); ++ilhs) {
+ // Reset the path-marking vector and try to find a path from
+ // source to sink starting at the left_[ilhs] node.
+ GTEST_CHECK_(left_[ilhs] == kUnused)
+ << "ilhs: " << ilhs << ", left_[ilhs]: " << left_[ilhs];
+ // 'seen' initialized to 'graph_->RhsSize()' copies of 0.
+ seen.assign(graph_->RhsSize(), 0);
+ TryAugment(ilhs, &seen);
+ }
+ ElementMatcherPairs result;
+ for (size_t ilhs = 0; ilhs < left_.size(); ++ilhs) {
+ size_t irhs = left_[ilhs];
+ if (irhs == kUnused) continue;
+ result.push_back(ElementMatcherPair(ilhs, irhs));
+ }
+ return result;
+ }
+
+ private:
+ static const size_t kUnused = static_cast<size_t>(-1);
+
+ // Perform a depth-first search from left node ilhs to the sink. If a
+ // path is found, flow is added to the network by linking the left and
+ // right vector elements corresponding each segment of the path.
+ // Returns true if a path to sink was found, which means that a unit of
+ // flow was added to the network. The 'seen' vector elements correspond
+ // to right nodes and are marked to eliminate cycles from the search.
+ //
+ // Left nodes will only be explored at most once because they
+ // are accessible from at most one right node in the residual flow
+ // graph.
+ //
+ // Note that left_[ilhs] is the only element of left_ that TryAugment will
+ // potentially transition from kUnused to another value. Any other
+ // left_ element holding kUnused before TryAugment will be holding it
+ // when TryAugment returns.
+ //
+ bool TryAugment(size_t ilhs, ::std::vector<char>* seen) {
+ for (size_t irhs = 0; irhs < graph_->RhsSize(); ++irhs) {
+ if ((*seen)[irhs])
+ continue;
+ if (!graph_->HasEdge(ilhs, irhs))
+ continue;
+ // There's an available edge from ilhs to irhs.
+ (*seen)[irhs] = 1;
+ // Next a search is performed to determine whether
+ // this edge is a dead end or leads to the sink.
+ //
+ // right_[irhs] == kUnused means that there is residual flow from
+ // right node irhs to the sink, so we can use that to finish this
+ // flow path and return success.
+ //
+ // Otherwise there is residual flow to some ilhs. We push flow
+ // along that path and call ourselves recursively to see if this
+ // ultimately leads to sink.
+ if (right_[irhs] == kUnused || TryAugment(right_[irhs], seen)) {
+ // Add flow from left_[ilhs] to right_[irhs].
+ left_[ilhs] = irhs;
+ right_[irhs] = ilhs;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ const MatchMatrix* graph_; // not owned
+ // Each element of the left_ vector represents a left hand side node
+ // (i.e. an element) and each element of right_ is a right hand side
+ // node (i.e. a matcher). The values in the left_ vector indicate
+ // outflow from that node to a node on the the right_ side. The values
+ // in the right_ indicate inflow, and specify which left_ node is
+ // feeding that right_ node, if any. For example, left_[3] == 1 means
+ // there's a flow from element #3 to matcher #1. Such a flow would also
+ // be redundantly represented in the right_ vector as right_[1] == 3.
+ // Elements of left_ and right_ are either kUnused or mutually
+ // referent. Mutually referent means that left_[right_[i]] = i and
+ // right_[left_[i]] = i.
+ ::std::vector<size_t> left_;
+ ::std::vector<size_t> right_;
+
+ GTEST_DISALLOW_ASSIGN_(MaxBipartiteMatchState);
+};
+
+const size_t MaxBipartiteMatchState::kUnused;
+
+GTEST_API_ ElementMatcherPairs
+FindMaxBipartiteMatching(const MatchMatrix& g) {
+ return MaxBipartiteMatchState(g).Compute();
+}
+
+static void LogElementMatcherPairVec(const ElementMatcherPairs& pairs,
+ ::std::ostream* stream) {
+ typedef ElementMatcherPairs::const_iterator Iter;
+ ::std::ostream& os = *stream;
+ os << "{";
+ const char *sep = "";
+ for (Iter it = pairs.begin(); it != pairs.end(); ++it) {
+ os << sep << "\n ("
+ << "element #" << it->first << ", "
+ << "matcher #" << it->second << ")";
+ sep = ",";
+ }
+ os << "\n}";
+}
+
+// Tries to find a pairing, and explains the result.
+GTEST_API_ bool FindPairing(const MatchMatrix& matrix,
+ MatchResultListener* listener) {
+ ElementMatcherPairs matches = FindMaxBipartiteMatching(matrix);
+
+ size_t max_flow = matches.size();
+ bool result = (max_flow == matrix.RhsSize());
+
+ if (!result) {
+ if (listener->IsInterested()) {
+ *listener << "where no permutation of the elements can "
+ "satisfy all matchers, and the closest match is "
+ << max_flow << " of " << matrix.RhsSize()
+ << " matchers with the pairings:\n";
+ LogElementMatcherPairVec(matches, listener->stream());
+ }
+ return false;
+ }
+
+ if (matches.size() > 1) {
+ if (listener->IsInterested()) {
+ const char *sep = "where:\n";
+ for (size_t mi = 0; mi < matches.size(); ++mi) {
+ *listener << sep << " - element #" << matches[mi].first
+ << " is matched by matcher #" << matches[mi].second;
+ sep = ",\n";
+ }
+ }
+ }
+ return true;
+}
+
+bool MatchMatrix::NextGraph() {
+ for (size_t ilhs = 0; ilhs < LhsSize(); ++ilhs) {
+ for (size_t irhs = 0; irhs < RhsSize(); ++irhs) {
+ char& b = matched_[SpaceIndex(ilhs, irhs)];
+ if (!b) {
+ b = 1;
+ return true;
+ }
+ b = 0;
+ }
+ }
+ return false;
+}
+
+void MatchMatrix::Randomize() {
+ for (size_t ilhs = 0; ilhs < LhsSize(); ++ilhs) {
+ for (size_t irhs = 0; irhs < RhsSize(); ++irhs) {
+ char& b = matched_[SpaceIndex(ilhs, irhs)];
+ b = static_cast<char>(rand() & 1); // NOLINT
+ }
+ }
+}
+
+string MatchMatrix::DebugString() const {
+ ::std::stringstream ss;
+ const char *sep = "";
+ for (size_t i = 0; i < LhsSize(); ++i) {
+ ss << sep;
+ for (size_t j = 0; j < RhsSize(); ++j) {
+ ss << HasEdge(i, j);
+ }
+ sep = ";";
+ }
+ return ss.str();
+}
+
+void UnorderedElementsAreMatcherImplBase::DescribeToImpl(
+ ::std::ostream* os) const {
+ if (matcher_describers_.empty()) {
+ *os << "is empty";
+ return;
+ }
+ if (matcher_describers_.size() == 1) {
+ *os << "has " << Elements(1) << " and that element ";
+ matcher_describers_[0]->DescribeTo(os);
+ return;
+ }
+ *os << "has " << Elements(matcher_describers_.size())
+ << " and there exists some permutation of elements such that:\n";
+ const char* sep = "";
+ for (size_t i = 0; i != matcher_describers_.size(); ++i) {
+ *os << sep << " - element #" << i << " ";
+ matcher_describers_[i]->DescribeTo(os);
+ sep = ", and\n";
+ }
+}
+
+void UnorderedElementsAreMatcherImplBase::DescribeNegationToImpl(
+ ::std::ostream* os) const {
+ if (matcher_describers_.empty()) {
+ *os << "isn't empty";
+ return;
+ }
+ if (matcher_describers_.size() == 1) {
+ *os << "doesn't have " << Elements(1)
+ << ", or has " << Elements(1) << " that ";
+ matcher_describers_[0]->DescribeNegationTo(os);
+ return;
+ }
+ *os << "doesn't have " << Elements(matcher_describers_.size())
+ << ", or there exists no permutation of elements such that:\n";
+ const char* sep = "";
+ for (size_t i = 0; i != matcher_describers_.size(); ++i) {
+ *os << sep << " - element #" << i << " ";
+ matcher_describers_[i]->DescribeTo(os);
+ sep = ", and\n";
+ }
+}
+
+// Checks that all matchers match at least one element, and that all
+// elements match at least one matcher. This enables faster matching
+// and better error reporting.
+// Returns false, writing an explanation to 'listener', if and only
+// if the success criteria are not met.
+bool UnorderedElementsAreMatcherImplBase::
+VerifyAllElementsAndMatchersAreMatched(
+ const ::std::vector<string>& element_printouts,
+ const MatchMatrix& matrix,
+ MatchResultListener* listener) const {
+ bool result = true;
+ ::std::vector<char> element_matched(matrix.LhsSize(), 0);
+ ::std::vector<char> matcher_matched(matrix.RhsSize(), 0);
+
+ for (size_t ilhs = 0; ilhs < matrix.LhsSize(); ilhs++) {
+ for (size_t irhs = 0; irhs < matrix.RhsSize(); irhs++) {
+ char matched = matrix.HasEdge(ilhs, irhs);
+ element_matched[ilhs] |= matched;
+ matcher_matched[irhs] |= matched;
+ }
+ }
+
+ {
+ const char* sep =
+ "where the following matchers don't match any elements:\n";
+ for (size_t mi = 0; mi < matcher_matched.size(); ++mi) {
+ if (matcher_matched[mi])
+ continue;
+ result = false;
+ if (listener->IsInterested()) {
+ *listener << sep << "matcher #" << mi << ": ";
+ matcher_describers_[mi]->DescribeTo(listener->stream());
+ sep = ",\n";
+ }
+ }
+ }
+
+ {
+ const char* sep =
+ "where the following elements don't match any matchers:\n";
+ const char* outer_sep = "";
+ if (!result) {
+ outer_sep = "\nand ";
+ }
+ for (size_t ei = 0; ei < element_matched.size(); ++ei) {
+ if (element_matched[ei])
+ continue;
+ result = false;
+ if (listener->IsInterested()) {
+ *listener << outer_sep << sep << "element #" << ei << ": "
+ << element_printouts[ei];
+ sep = ",\n";
+ outer_sep = "";
+ }
+ }
+ }
+ return result;
+}
+
+} // namespace internal
+} // namespace testing
diff --git a/extern/gmock/src/gmock-spec-builders.cc b/extern/gmock/src/gmock-spec-builders.cc
new file mode 100644
index 00000000000..95513420707
--- /dev/null
+++ b/extern/gmock/src/gmock-spec-builders.cc
@@ -0,0 +1,823 @@
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Google Mock - a framework for writing C++ mock classes.
+//
+// This file implements the spec builder syntax (ON_CALL and
+// EXPECT_CALL).
+
+#include "gmock/gmock-spec-builders.h"
+
+#include <stdlib.h>
+#include <iostream> // NOLINT
+#include <map>
+#include <set>
+#include <string>
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#if GTEST_OS_CYGWIN || GTEST_OS_LINUX || GTEST_OS_MAC
+# include <unistd.h> // NOLINT
+#endif
+
+namespace testing {
+namespace internal {
+
+// Protects the mock object registry (in class Mock), all function
+// mockers, and all expectations.
+GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_gmock_mutex);
+
+// Logs a message including file and line number information.
+GTEST_API_ void LogWithLocation(testing::internal::LogSeverity severity,
+ const char* file, int line,
+ const string& message) {
+ ::std::ostringstream s;
+ s << file << ":" << line << ": " << message << ::std::endl;
+ Log(severity, s.str(), 0);
+}
+
+// Constructs an ExpectationBase object.
+ExpectationBase::ExpectationBase(const char* a_file,
+ int a_line,
+ const string& a_source_text)
+ : file_(a_file),
+ line_(a_line),
+ source_text_(a_source_text),
+ cardinality_specified_(false),
+ cardinality_(Exactly(1)),
+ call_count_(0),
+ retired_(false),
+ extra_matcher_specified_(false),
+ repeated_action_specified_(false),
+ retires_on_saturation_(false),
+ last_clause_(kNone),
+ action_count_checked_(false) {}
+
+// Destructs an ExpectationBase object.
+ExpectationBase::~ExpectationBase() {}
+
+// Explicitly specifies the cardinality of this expectation. Used by
+// the subclasses to implement the .Times() clause.
+void ExpectationBase::SpecifyCardinality(const Cardinality& a_cardinality) {
+ cardinality_specified_ = true;
+ cardinality_ = a_cardinality;
+}
+
+// Retires all pre-requisites of this expectation.
+void ExpectationBase::RetireAllPreRequisites()
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
+ if (is_retired()) {
+ // We can take this short-cut as we never retire an expectation
+ // until we have retired all its pre-requisites.
+ return;
+ }
+
+ for (ExpectationSet::const_iterator it = immediate_prerequisites_.begin();
+ it != immediate_prerequisites_.end(); ++it) {
+ ExpectationBase* const prerequisite = it->expectation_base().get();
+ if (!prerequisite->is_retired()) {
+ prerequisite->RetireAllPreRequisites();
+ prerequisite->Retire();
+ }
+ }
+}
+
+// Returns true iff all pre-requisites of this expectation have been
+// satisfied.
+bool ExpectationBase::AllPrerequisitesAreSatisfied() const
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
+ g_gmock_mutex.AssertHeld();
+ for (ExpectationSet::const_iterator it = immediate_prerequisites_.begin();
+ it != immediate_prerequisites_.end(); ++it) {
+ if (!(it->expectation_base()->IsSatisfied()) ||
+ !(it->expectation_base()->AllPrerequisitesAreSatisfied()))
+ return false;
+ }
+ return true;
+}
+
+// Adds unsatisfied pre-requisites of this expectation to 'result'.
+void ExpectationBase::FindUnsatisfiedPrerequisites(ExpectationSet* result) const
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
+ g_gmock_mutex.AssertHeld();
+ for (ExpectationSet::const_iterator it = immediate_prerequisites_.begin();
+ it != immediate_prerequisites_.end(); ++it) {
+ if (it->expectation_base()->IsSatisfied()) {
+ // If *it is satisfied and has a call count of 0, some of its
+ // pre-requisites may not be satisfied yet.
+ if (it->expectation_base()->call_count_ == 0) {
+ it->expectation_base()->FindUnsatisfiedPrerequisites(result);
+ }
+ } else {
+ // Now that we know *it is unsatisfied, we are not so interested
+ // in whether its pre-requisites are satisfied. Therefore we
+ // don't recursively call FindUnsatisfiedPrerequisites() here.
+ *result += *it;
+ }
+ }
+}
+
+// Describes how many times a function call matching this
+// expectation has occurred.
+void ExpectationBase::DescribeCallCountTo(::std::ostream* os) const
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
+ g_gmock_mutex.AssertHeld();
+
+ // Describes how many times the function is expected to be called.
+ *os << " Expected: to be ";
+ cardinality().DescribeTo(os);
+ *os << "\n Actual: ";
+ Cardinality::DescribeActualCallCountTo(call_count(), os);
+
+ // Describes the state of the expectation (e.g. is it satisfied?
+ // is it active?).
+ *os << " - " << (IsOverSaturated() ? "over-saturated" :
+ IsSaturated() ? "saturated" :
+ IsSatisfied() ? "satisfied" : "unsatisfied")
+ << " and "
+ << (is_retired() ? "retired" : "active");
+}
+
+// Checks the action count (i.e. the number of WillOnce() and
+// WillRepeatedly() clauses) against the cardinality if this hasn't
+// been done before. Prints a warning if there are too many or too
+// few actions.
+void ExpectationBase::CheckActionCountIfNotDone() const
+ GTEST_LOCK_EXCLUDED_(mutex_) {
+ bool should_check = false;
+ {
+ MutexLock l(&mutex_);
+ if (!action_count_checked_) {
+ action_count_checked_ = true;
+ should_check = true;
+ }
+ }
+
+ if (should_check) {
+ if (!cardinality_specified_) {
+ // The cardinality was inferred - no need to check the action
+ // count against it.
+ return;
+ }
+
+ // The cardinality was explicitly specified.
+ const int action_count = static_cast<int>(untyped_actions_.size());
+ const int upper_bound = cardinality().ConservativeUpperBound();
+ const int lower_bound = cardinality().ConservativeLowerBound();
+ bool too_many; // True if there are too many actions, or false
+ // if there are too few.
+ if (action_count > upper_bound ||
+ (action_count == upper_bound && repeated_action_specified_)) {
+ too_many = true;
+ } else if (0 < action_count && action_count < lower_bound &&
+ !repeated_action_specified_) {
+ too_many = false;
+ } else {
+ return;
+ }
+
+ ::std::stringstream ss;
+ DescribeLocationTo(&ss);
+ ss << "Too " << (too_many ? "many" : "few")
+ << " actions specified in " << source_text() << "...\n"
+ << "Expected to be ";
+ cardinality().DescribeTo(&ss);
+ ss << ", but has " << (too_many ? "" : "only ")
+ << action_count << " WillOnce()"
+ << (action_count == 1 ? "" : "s");
+ if (repeated_action_specified_) {
+ ss << " and a WillRepeatedly()";
+ }
+ ss << ".";
+ Log(kWarning, ss.str(), -1); // -1 means "don't print stack trace".
+ }
+}
+
+// Implements the .Times() clause.
+void ExpectationBase::UntypedTimes(const Cardinality& a_cardinality) {
+ if (last_clause_ == kTimes) {
+ ExpectSpecProperty(false,
+ ".Times() cannot appear "
+ "more than once in an EXPECT_CALL().");
+ } else {
+ ExpectSpecProperty(last_clause_ < kTimes,
+ ".Times() cannot appear after "
+ ".InSequence(), .WillOnce(), .WillRepeatedly(), "
+ "or .RetiresOnSaturation().");
+ }
+ last_clause_ = kTimes;
+
+ SpecifyCardinality(a_cardinality);
+}
+
+// Points to the implicit sequence introduced by a living InSequence
+// object (if any) in the current thread or NULL.
+GTEST_API_ ThreadLocal<Sequence*> g_gmock_implicit_sequence;
+
+// Reports an uninteresting call (whose description is in msg) in the
+// manner specified by 'reaction'.
+void ReportUninterestingCall(CallReaction reaction, const string& msg) {
+ // Include a stack trace only if --gmock_verbose=info is specified.
+ const int stack_frames_to_skip =
+ GMOCK_FLAG(verbose) == kInfoVerbosity ? 3 : -1;
+ switch (reaction) {
+ case kAllow:
+ Log(kInfo, msg, stack_frames_to_skip);
+ break;
+ case kWarn:
+ Log(kWarning,
+ msg +
+ "\nNOTE: You can safely ignore the above warning unless this "
+ "call should not happen. Do not suppress it by blindly adding "
+ "an EXPECT_CALL() if you don't mean to enforce the call. "
+ "See https://github.com/google/googletest/blob/master/googlemock/docs/CookBook.md#"
+ "knowing-when-to-expect for details.\n",
+ stack_frames_to_skip);
+ break;
+ default: // FAIL
+ Expect(false, NULL, -1, msg);
+ }
+}
+
+UntypedFunctionMockerBase::UntypedFunctionMockerBase()
+ : mock_obj_(NULL), name_("") {}
+
+UntypedFunctionMockerBase::~UntypedFunctionMockerBase() {}
+
+// Sets the mock object this mock method belongs to, and registers
+// this information in the global mock registry. Will be called
+// whenever an EXPECT_CALL() or ON_CALL() is executed on this mock
+// method.
+void UntypedFunctionMockerBase::RegisterOwner(const void* mock_obj)
+ GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
+ {
+ MutexLock l(&g_gmock_mutex);
+ mock_obj_ = mock_obj;
+ }
+ Mock::Register(mock_obj, this);
+}
+
+// Sets the mock object this mock method belongs to, and sets the name
+// of the mock function. Will be called upon each invocation of this
+// mock function.
+void UntypedFunctionMockerBase::SetOwnerAndName(const void* mock_obj,
+ const char* name)
+ GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
+ // We protect name_ under g_gmock_mutex in case this mock function
+ // is called from two threads concurrently.
+ MutexLock l(&g_gmock_mutex);
+ mock_obj_ = mock_obj;
+ name_ = name;
+}
+
+// Returns the name of the function being mocked. Must be called
+// after RegisterOwner() or SetOwnerAndName() has been called.
+const void* UntypedFunctionMockerBase::MockObject() const
+ GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
+ const void* mock_obj;
+ {
+ // We protect mock_obj_ under g_gmock_mutex in case this mock
+ // function is called from two threads concurrently.
+ MutexLock l(&g_gmock_mutex);
+ Assert(mock_obj_ != NULL, __FILE__, __LINE__,
+ "MockObject() must not be called before RegisterOwner() or "
+ "SetOwnerAndName() has been called.");
+ mock_obj = mock_obj_;
+ }
+ return mock_obj;
+}
+
+// Returns the name of this mock method. Must be called after
+// SetOwnerAndName() has been called.
+const char* UntypedFunctionMockerBase::Name() const
+ GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
+ const char* name;
+ {
+ // We protect name_ under g_gmock_mutex in case this mock
+ // function is called from two threads concurrently.
+ MutexLock l(&g_gmock_mutex);
+ Assert(name_ != NULL, __FILE__, __LINE__,
+ "Name() must not be called before SetOwnerAndName() has "
+ "been called.");
+ name = name_;
+ }
+ return name;
+}
+
+// Calculates the result of invoking this mock function with the given
+// arguments, prints it, and returns it. The caller is responsible
+// for deleting the result.
+UntypedActionResultHolderBase*
+UntypedFunctionMockerBase::UntypedInvokeWith(const void* const untyped_args)
+ GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
+ if (untyped_expectations_.size() == 0) {
+ // No expectation is set on this mock method - we have an
+ // uninteresting call.
+
+ // We must get Google Mock's reaction on uninteresting calls
+ // made on this mock object BEFORE performing the action,
+ // because the action may DELETE the mock object and make the
+ // following expression meaningless.
+ const CallReaction reaction =
+ Mock::GetReactionOnUninterestingCalls(MockObject());
+
+ // True iff we need to print this call's arguments and return
+ // value. This definition must be kept in sync with
+ // the behavior of ReportUninterestingCall().
+ const bool need_to_report_uninteresting_call =
+ // If the user allows this uninteresting call, we print it
+ // only when he wants informational messages.
+ reaction == kAllow ? LogIsVisible(kInfo) :
+ // If the user wants this to be a warning, we print it only
+ // when he wants to see warnings.
+ reaction == kWarn ? LogIsVisible(kWarning) :
+ // Otherwise, the user wants this to be an error, and we
+ // should always print detailed information in the error.
+ true;
+
+ if (!need_to_report_uninteresting_call) {
+ // Perform the action without printing the call information.
+ return this->UntypedPerformDefaultAction(untyped_args, "");
+ }
+
+ // Warns about the uninteresting call.
+ ::std::stringstream ss;
+ this->UntypedDescribeUninterestingCall(untyped_args, &ss);
+
+ // Calculates the function result.
+ UntypedActionResultHolderBase* const result =
+ this->UntypedPerformDefaultAction(untyped_args, ss.str());
+
+ // Prints the function result.
+ if (result != NULL)
+ result->PrintAsActionResult(&ss);
+
+ ReportUninterestingCall(reaction, ss.str());
+ return result;
+ }
+
+ bool is_excessive = false;
+ ::std::stringstream ss;
+ ::std::stringstream why;
+ ::std::stringstream loc;
+ const void* untyped_action = NULL;
+
+ // The UntypedFindMatchingExpectation() function acquires and
+ // releases g_gmock_mutex.
+ const ExpectationBase* const untyped_expectation =
+ this->UntypedFindMatchingExpectation(
+ untyped_args, &untyped_action, &is_excessive,
+ &ss, &why);
+ const bool found = untyped_expectation != NULL;
+
+ // True iff we need to print the call's arguments and return value.
+ // This definition must be kept in sync with the uses of Expect()
+ // and Log() in this function.
+ const bool need_to_report_call =
+ !found || is_excessive || LogIsVisible(kInfo);
+ if (!need_to_report_call) {
+ // Perform the action without printing the call information.
+ return
+ untyped_action == NULL ?
+ this->UntypedPerformDefaultAction(untyped_args, "") :
+ this->UntypedPerformAction(untyped_action, untyped_args);
+ }
+
+ ss << " Function call: " << Name();
+ this->UntypedPrintArgs(untyped_args, &ss);
+
+ // In case the action deletes a piece of the expectation, we
+ // generate the message beforehand.
+ if (found && !is_excessive) {
+ untyped_expectation->DescribeLocationTo(&loc);
+ }
+
+ UntypedActionResultHolderBase* const result =
+ untyped_action == NULL ?
+ this->UntypedPerformDefaultAction(untyped_args, ss.str()) :
+ this->UntypedPerformAction(untyped_action, untyped_args);
+ if (result != NULL)
+ result->PrintAsActionResult(&ss);
+ ss << "\n" << why.str();
+
+ if (!found) {
+ // No expectation matches this call - reports a failure.
+ Expect(false, NULL, -1, ss.str());
+ } else if (is_excessive) {
+ // We had an upper-bound violation and the failure message is in ss.
+ Expect(false, untyped_expectation->file(),
+ untyped_expectation->line(), ss.str());
+ } else {
+ // We had an expected call and the matching expectation is
+ // described in ss.
+ Log(kInfo, loc.str() + ss.str(), 2);
+ }
+
+ return result;
+}
+
+// Returns an Expectation object that references and co-owns exp,
+// which must be an expectation on this mock function.
+Expectation UntypedFunctionMockerBase::GetHandleOf(ExpectationBase* exp) {
+ for (UntypedExpectations::const_iterator it =
+ untyped_expectations_.begin();
+ it != untyped_expectations_.end(); ++it) {
+ if (it->get() == exp) {
+ return Expectation(*it);
+ }
+ }
+
+ Assert(false, __FILE__, __LINE__, "Cannot find expectation.");
+ return Expectation();
+ // The above statement is just to make the code compile, and will
+ // never be executed.
+}
+
+// Verifies that all expectations on this mock function have been
+// satisfied. Reports one or more Google Test non-fatal failures
+// and returns false if not.
+bool UntypedFunctionMockerBase::VerifyAndClearExpectationsLocked()
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
+ g_gmock_mutex.AssertHeld();
+ bool expectations_met = true;
+ for (UntypedExpectations::const_iterator it =
+ untyped_expectations_.begin();
+ it != untyped_expectations_.end(); ++it) {
+ ExpectationBase* const untyped_expectation = it->get();
+ if (untyped_expectation->IsOverSaturated()) {
+ // There was an upper-bound violation. Since the error was
+ // already reported when it occurred, there is no need to do
+ // anything here.
+ expectations_met = false;
+ } else if (!untyped_expectation->IsSatisfied()) {
+ expectations_met = false;
+ ::std::stringstream ss;
+ ss << "Actual function call count doesn't match "
+ << untyped_expectation->source_text() << "...\n";
+ // No need to show the source file location of the expectation
+ // in the description, as the Expect() call that follows already
+ // takes care of it.
+ untyped_expectation->MaybeDescribeExtraMatcherTo(&ss);
+ untyped_expectation->DescribeCallCountTo(&ss);
+ Expect(false, untyped_expectation->file(),
+ untyped_expectation->line(), ss.str());
+ }
+ }
+
+ // Deleting our expectations may trigger other mock objects to be deleted, for
+ // example if an action contains a reference counted smart pointer to that
+ // mock object, and that is the last reference. So if we delete our
+ // expectations within the context of the global mutex we may deadlock when
+ // this method is called again. Instead, make a copy of the set of
+ // expectations to delete, clear our set within the mutex, and then clear the
+ // copied set outside of it.
+ UntypedExpectations expectations_to_delete;
+ untyped_expectations_.swap(expectations_to_delete);
+
+ g_gmock_mutex.Unlock();
+ expectations_to_delete.clear();
+ g_gmock_mutex.Lock();
+
+ return expectations_met;
+}
+
+} // namespace internal
+
+// Class Mock.
+
+namespace {
+
+typedef std::set<internal::UntypedFunctionMockerBase*> FunctionMockers;
+
+// The current state of a mock object. Such information is needed for
+// detecting leaked mock objects and explicitly verifying a mock's
+// expectations.
+struct MockObjectState {
+ MockObjectState()
+ : first_used_file(NULL), first_used_line(-1), leakable(false) {}
+
+ // Where in the source file an ON_CALL or EXPECT_CALL is first
+ // invoked on this mock object.
+ const char* first_used_file;
+ int first_used_line;
+ ::std::string first_used_test_case;
+ ::std::string first_used_test;
+ bool leakable; // true iff it's OK to leak the object.
+ FunctionMockers function_mockers; // All registered methods of the object.
+};
+
+// A global registry holding the state of all mock objects that are
+// alive. A mock object is added to this registry the first time
+// Mock::AllowLeak(), ON_CALL(), or EXPECT_CALL() is called on it. It
+// is removed from the registry in the mock object's destructor.
+class MockObjectRegistry {
+ public:
+ // Maps a mock object (identified by its address) to its state.
+ typedef std::map<const void*, MockObjectState> StateMap;
+
+ // This destructor will be called when a program exits, after all
+ // tests in it have been run. By then, there should be no mock
+ // object alive. Therefore we report any living object as test
+ // failure, unless the user explicitly asked us to ignore it.
+ ~MockObjectRegistry() {
+ // "using ::std::cout;" doesn't work with Symbian's STLport, where cout is
+ // a macro.
+
+ if (!GMOCK_FLAG(catch_leaked_mocks))
+ return;
+
+ int leaked_count = 0;
+ for (StateMap::const_iterator it = states_.begin(); it != states_.end();
+ ++it) {
+ if (it->second.leakable) // The user said it's fine to leak this object.
+ continue;
+
+ // TODO(wan@google.com): Print the type of the leaked object.
+ // This can help the user identify the leaked object.
+ std::cout << "\n";
+ const MockObjectState& state = it->second;
+ std::cout << internal::FormatFileLocation(state.first_used_file,
+ state.first_used_line);
+ std::cout << " ERROR: this mock object";
+ if (state.first_used_test != "") {
+ std::cout << " (used in test " << state.first_used_test_case << "."
+ << state.first_used_test << ")";
+ }
+ std::cout << " should be deleted but never is. Its address is @"
+ << it->first << ".";
+ leaked_count++;
+ }
+ if (leaked_count > 0) {
+ std::cout << "\nERROR: " << leaked_count
+ << " leaked mock " << (leaked_count == 1 ? "object" : "objects")
+ << " found at program exit.\n";
+ std::cout.flush();
+ ::std::cerr.flush();
+ // RUN_ALL_TESTS() has already returned when this destructor is
+ // called. Therefore we cannot use the normal Google Test
+ // failure reporting mechanism.
+ _exit(1); // We cannot call exit() as it is not reentrant and
+ // may already have been called.
+ }
+ }
+
+ StateMap& states() { return states_; }
+
+ private:
+ StateMap states_;
+};
+
+// Protected by g_gmock_mutex.
+MockObjectRegistry g_mock_object_registry;
+
+// Maps a mock object to the reaction Google Mock should have when an
+// uninteresting method is called. Protected by g_gmock_mutex.
+std::map<const void*, internal::CallReaction> g_uninteresting_call_reaction;
+
+// Sets the reaction Google Mock should have when an uninteresting
+// method of the given mock object is called.
+void SetReactionOnUninterestingCalls(const void* mock_obj,
+ internal::CallReaction reaction)
+ GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
+ internal::MutexLock l(&internal::g_gmock_mutex);
+ g_uninteresting_call_reaction[mock_obj] = reaction;
+}
+
+} // namespace
+
+// Tells Google Mock to allow uninteresting calls on the given mock
+// object.
+void Mock::AllowUninterestingCalls(const void* mock_obj)
+ GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
+ SetReactionOnUninterestingCalls(mock_obj, internal::kAllow);
+}
+
+// Tells Google Mock to warn the user about uninteresting calls on the
+// given mock object.
+void Mock::WarnUninterestingCalls(const void* mock_obj)
+ GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
+ SetReactionOnUninterestingCalls(mock_obj, internal::kWarn);
+}
+
+// Tells Google Mock to fail uninteresting calls on the given mock
+// object.
+void Mock::FailUninterestingCalls(const void* mock_obj)
+ GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
+ SetReactionOnUninterestingCalls(mock_obj, internal::kFail);
+}
+
+// Tells Google Mock the given mock object is being destroyed and its
+// entry in the call-reaction table should be removed.
+void Mock::UnregisterCallReaction(const void* mock_obj)
+ GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
+ internal::MutexLock l(&internal::g_gmock_mutex);
+ g_uninteresting_call_reaction.erase(mock_obj);
+}
+
+// Returns the reaction Google Mock will have on uninteresting calls
+// made on the given mock object.
+internal::CallReaction Mock::GetReactionOnUninterestingCalls(
+ const void* mock_obj)
+ GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
+ internal::MutexLock l(&internal::g_gmock_mutex);
+ return (g_uninteresting_call_reaction.count(mock_obj) == 0) ?
+ internal::kDefault : g_uninteresting_call_reaction[mock_obj];
+}
+
+// Tells Google Mock to ignore mock_obj when checking for leaked mock
+// objects.
+void Mock::AllowLeak(const void* mock_obj)
+ GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
+ internal::MutexLock l(&internal::g_gmock_mutex);
+ g_mock_object_registry.states()[mock_obj].leakable = true;
+}
+
+// Verifies and clears all expectations on the given mock object. If
+// the expectations aren't satisfied, generates one or more Google
+// Test non-fatal failures and returns false.
+bool Mock::VerifyAndClearExpectations(void* mock_obj)
+ GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
+ internal::MutexLock l(&internal::g_gmock_mutex);
+ return VerifyAndClearExpectationsLocked(mock_obj);
+}
+
+// Verifies all expectations on the given mock object and clears its
+// default actions and expectations. Returns true iff the
+// verification was successful.
+bool Mock::VerifyAndClear(void* mock_obj)
+ GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
+ internal::MutexLock l(&internal::g_gmock_mutex);
+ ClearDefaultActionsLocked(mock_obj);
+ return VerifyAndClearExpectationsLocked(mock_obj);
+}
+
+// Verifies and clears all expectations on the given mock object. If
+// the expectations aren't satisfied, generates one or more Google
+// Test non-fatal failures and returns false.
+bool Mock::VerifyAndClearExpectationsLocked(void* mock_obj)
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(internal::g_gmock_mutex) {
+ internal::g_gmock_mutex.AssertHeld();
+ if (g_mock_object_registry.states().count(mock_obj) == 0) {
+ // No EXPECT_CALL() was set on the given mock object.
+ return true;
+ }
+
+ // Verifies and clears the expectations on each mock method in the
+ // given mock object.
+ bool expectations_met = true;
+ FunctionMockers& mockers =
+ g_mock_object_registry.states()[mock_obj].function_mockers;
+ for (FunctionMockers::const_iterator it = mockers.begin();
+ it != mockers.end(); ++it) {
+ if (!(*it)->VerifyAndClearExpectationsLocked()) {
+ expectations_met = false;
+ }
+ }
+
+ // We don't clear the content of mockers, as they may still be
+ // needed by ClearDefaultActionsLocked().
+ return expectations_met;
+}
+
+// Registers a mock object and a mock method it owns.
+void Mock::Register(const void* mock_obj,
+ internal::UntypedFunctionMockerBase* mocker)
+ GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
+ internal::MutexLock l(&internal::g_gmock_mutex);
+ g_mock_object_registry.states()[mock_obj].function_mockers.insert(mocker);
+}
+
+// Tells Google Mock where in the source code mock_obj is used in an
+// ON_CALL or EXPECT_CALL. In case mock_obj is leaked, this
+// information helps the user identify which object it is.
+void Mock::RegisterUseByOnCallOrExpectCall(const void* mock_obj,
+ const char* file, int line)
+ GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
+ internal::MutexLock l(&internal::g_gmock_mutex);
+ MockObjectState& state = g_mock_object_registry.states()[mock_obj];
+ if (state.first_used_file == NULL) {
+ state.first_used_file = file;
+ state.first_used_line = line;
+ const TestInfo* const test_info =
+ UnitTest::GetInstance()->current_test_info();
+ if (test_info != NULL) {
+ // TODO(wan@google.com): record the test case name when the
+ // ON_CALL or EXPECT_CALL is invoked from SetUpTestCase() or
+ // TearDownTestCase().
+ state.first_used_test_case = test_info->test_case_name();
+ state.first_used_test = test_info->name();
+ }
+ }
+}
+
+// Unregisters a mock method; removes the owning mock object from the
+// registry when the last mock method associated with it has been
+// unregistered. This is called only in the destructor of
+// FunctionMockerBase.
+void Mock::UnregisterLocked(internal::UntypedFunctionMockerBase* mocker)
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(internal::g_gmock_mutex) {
+ internal::g_gmock_mutex.AssertHeld();
+ for (MockObjectRegistry::StateMap::iterator it =
+ g_mock_object_registry.states().begin();
+ it != g_mock_object_registry.states().end(); ++it) {
+ FunctionMockers& mockers = it->second.function_mockers;
+ if (mockers.erase(mocker) > 0) {
+ // mocker was in mockers and has been just removed.
+ if (mockers.empty()) {
+ g_mock_object_registry.states().erase(it);
+ }
+ return;
+ }
+ }
+}
+
+// Clears all ON_CALL()s set on the given mock object.
+void Mock::ClearDefaultActionsLocked(void* mock_obj)
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(internal::g_gmock_mutex) {
+ internal::g_gmock_mutex.AssertHeld();
+
+ if (g_mock_object_registry.states().count(mock_obj) == 0) {
+ // No ON_CALL() was set on the given mock object.
+ return;
+ }
+
+ // Clears the default actions for each mock method in the given mock
+ // object.
+ FunctionMockers& mockers =
+ g_mock_object_registry.states()[mock_obj].function_mockers;
+ for (FunctionMockers::const_iterator it = mockers.begin();
+ it != mockers.end(); ++it) {
+ (*it)->ClearDefaultActionsLocked();
+ }
+
+ // We don't clear the content of mockers, as they may still be
+ // needed by VerifyAndClearExpectationsLocked().
+}
+
+Expectation::Expectation() {}
+
+Expectation::Expectation(
+ const internal::linked_ptr<internal::ExpectationBase>& an_expectation_base)
+ : expectation_base_(an_expectation_base) {}
+
+Expectation::~Expectation() {}
+
+// Adds an expectation to a sequence.
+void Sequence::AddExpectation(const Expectation& expectation) const {
+ if (*last_expectation_ != expectation) {
+ if (last_expectation_->expectation_base() != NULL) {
+ expectation.expectation_base()->immediate_prerequisites_
+ += *last_expectation_;
+ }
+ *last_expectation_ = expectation;
+ }
+}
+
+// Creates the implicit sequence if there isn't one.
+InSequence::InSequence() {
+ if (internal::g_gmock_implicit_sequence.get() == NULL) {
+ internal::g_gmock_implicit_sequence.set(new Sequence);
+ sequence_created_ = true;
+ } else {
+ sequence_created_ = false;
+ }
+}
+
+// Deletes the implicit sequence if it was created by the constructor
+// of this object.
+InSequence::~InSequence() {
+ if (sequence_created_) {
+ delete internal::g_gmock_implicit_sequence.get();
+ internal::g_gmock_implicit_sequence.set(NULL);
+ }
+}
+
+} // namespace testing
diff --git a/extern/gmock/src/gmock.cc b/extern/gmock/src/gmock.cc
new file mode 100644
index 00000000000..eac3d842ba0
--- /dev/null
+++ b/extern/gmock/src/gmock.cc
@@ -0,0 +1,183 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+#include "gmock/gmock.h"
+#include "gmock/internal/gmock-port.h"
+
+namespace testing {
+
+// TODO(wan@google.com): support using environment variables to
+// control the flag values, like what Google Test does.
+
+GMOCK_DEFINE_bool_(catch_leaked_mocks, true,
+ "true iff Google Mock should report leaked mock objects "
+ "as failures.");
+
+GMOCK_DEFINE_string_(verbose, internal::kWarningVerbosity,
+ "Controls how verbose Google Mock's output is."
+ " Valid values:\n"
+ " info - prints all messages.\n"
+ " warning - prints warnings and errors.\n"
+ " error - prints errors only.");
+
+namespace internal {
+
+// Parses a string as a command line flag. The string should have the
+// format "--gmock_flag=value". When def_optional is true, the
+// "=value" part can be omitted.
+//
+// Returns the value of the flag, or NULL if the parsing failed.
+static const char* ParseGoogleMockFlagValue(const char* str,
+ const char* flag,
+ bool def_optional) {
+ // str and flag must not be NULL.
+ if (str == NULL || flag == NULL) return NULL;
+
+ // The flag must start with "--gmock_".
+ const std::string flag_str = std::string("--gmock_") + flag;
+ const size_t flag_len = flag_str.length();
+ if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL;
+
+ // Skips the flag name.
+ const char* flag_end = str + flag_len;
+
+ // When def_optional is true, it's OK to not have a "=value" part.
+ if (def_optional && (flag_end[0] == '\0')) {
+ return flag_end;
+ }
+
+ // If def_optional is true and there are more characters after the
+ // flag name, or if def_optional is false, there must be a '=' after
+ // the flag name.
+ if (flag_end[0] != '=') return NULL;
+
+ // Returns the string after "=".
+ return flag_end + 1;
+}
+
+// Parses a string for a Google Mock bool flag, in the form of
+// "--gmock_flag=value".
+//
+// On success, stores the value of the flag in *value, and returns
+// true. On failure, returns false without changing *value.
+static bool ParseGoogleMockBoolFlag(const char* str, const char* flag,
+ bool* value) {
+ // Gets the value of the flag as a string.
+ const char* const value_str = ParseGoogleMockFlagValue(str, flag, true);
+
+ // Aborts if the parsing failed.
+ if (value_str == NULL) return false;
+
+ // Converts the string value to a bool.
+ *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F');
+ return true;
+}
+
+// Parses a string for a Google Mock string flag, in the form of
+// "--gmock_flag=value".
+//
+// On success, stores the value of the flag in *value, and returns
+// true. On failure, returns false without changing *value.
+template <typename String>
+static bool ParseGoogleMockStringFlag(const char* str, const char* flag,
+ String* value) {
+ // Gets the value of the flag as a string.
+ const char* const value_str = ParseGoogleMockFlagValue(str, flag, false);
+
+ // Aborts if the parsing failed.
+ if (value_str == NULL) return false;
+
+ // Sets *value to the value of the flag.
+ *value = value_str;
+ return true;
+}
+
+// The internal implementation of InitGoogleMock().
+//
+// The type parameter CharType can be instantiated to either char or
+// wchar_t.
+template <typename CharType>
+void InitGoogleMockImpl(int* argc, CharType** argv) {
+ // Makes sure Google Test is initialized. InitGoogleTest() is
+ // idempotent, so it's fine if the user has already called it.
+ InitGoogleTest(argc, argv);
+ if (*argc <= 0) return;
+
+ for (int i = 1; i != *argc; i++) {
+ const std::string arg_string = StreamableToString(argv[i]);
+ const char* const arg = arg_string.c_str();
+
+ // Do we see a Google Mock flag?
+ if (ParseGoogleMockBoolFlag(arg, "catch_leaked_mocks",
+ &GMOCK_FLAG(catch_leaked_mocks)) ||
+ ParseGoogleMockStringFlag(arg, "verbose", &GMOCK_FLAG(verbose))) {
+ // Yes. Shift the remainder of the argv list left by one. Note
+ // that argv has (*argc + 1) elements, the last one always being
+ // NULL. The following loop moves the trailing NULL element as
+ // well.
+ for (int j = i; j != *argc; j++) {
+ argv[j] = argv[j + 1];
+ }
+
+ // Decrements the argument count.
+ (*argc)--;
+
+ // We also need to decrement the iterator as we just removed
+ // an element.
+ i--;
+ }
+ }
+}
+
+} // namespace internal
+
+// Initializes Google Mock. This must be called before running the
+// tests. In particular, it parses a command line for the flags that
+// Google Mock recognizes. Whenever a Google Mock flag is seen, it is
+// removed from argv, and *argc is decremented.
+//
+// No value is returned. Instead, the Google Mock flag variables are
+// updated.
+//
+// Since Google Test is needed for Google Mock to work, this function
+// also initializes Google Test and parses its flags, if that hasn't
+// been done.
+GTEST_API_ void InitGoogleMock(int* argc, char** argv) {
+ internal::InitGoogleMockImpl(argc, argv);
+}
+
+// This overloaded version can be used in Windows programs compiled in
+// UNICODE mode.
+GTEST_API_ void InitGoogleMock(int* argc, wchar_t** argv) {
+ internal::InitGoogleMockImpl(argc, argv);
+}
+
+} // namespace testing
diff --git a/extern/gmock/src/gmock_main.cc b/extern/gmock/src/gmock_main.cc
new file mode 100644
index 00000000000..bd5be03be22
--- /dev/null
+++ b/extern/gmock/src/gmock_main.cc
@@ -0,0 +1,54 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+#include <iostream>
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+// MS C++ compiler/linker has a bug on Windows (not on Windows CE), which
+// causes a link error when _tmain is defined in a static library and UNICODE
+// is enabled. For this reason instead of _tmain, main function is used on
+// Windows. See the following link to track the current status of this bug:
+// http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=394464 // NOLINT
+#if GTEST_OS_WINDOWS_MOBILE
+# include <tchar.h> // NOLINT
+
+GTEST_API_ int _tmain(int argc, TCHAR** argv) {
+#else
+GTEST_API_ int main(int argc, char** argv) {
+#endif // GTEST_OS_WINDOWS_MOBILE
+ std::cout << "Running main() from gmock_main.cc\n";
+ // Since Google Mock depends on Google Test, InitGoogleMock() is
+ // also responsible for initializing Google Test. Therefore there's
+ // no need for calling testing::InitGoogleTest() separately.
+ testing::InitGoogleMock(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/extern/gtest/README.blender b/extern/gtest/README.blender
new file mode 100644
index 00000000000..41dda92c19c
--- /dev/null
+++ b/extern/gtest/README.blender
@@ -0,0 +1,7 @@
+Project: Google C++ Testing Framework
+URL: https://github.com/google/googletest
+License: New BSD
+Upstream version: 1.7.0 (ec44c6c)
+Local modifications:
+
+None.
diff --git a/extern/gtest/include/gtest/gtest-param-test.h b/extern/gtest/include/gtest/gtest-param-test.h
index d6702c8f162..038f9ba79eb 100644
--- a/extern/gtest/include/gtest/gtest-param-test.h
+++ b/extern/gtest/include/gtest/gtest-param-test.h
@@ -1387,14 +1387,17 @@ internal::CartesianProductHolder10<Generator1, Generator2, Generator3,
static int AddToRegistry() { \
::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
GetTestCasePatternHolder<test_case_name>(\
- #test_case_name, __FILE__, __LINE__)->AddTestPattern(\
- #test_case_name, \
- #test_name, \
- new ::testing::internal::TestMetaFactory< \
- GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \
+ #test_case_name, \
+ ::testing::internal::CodeLocation(\
+ __FILE__, __LINE__))->AddTestPattern(\
+ #test_case_name, \
+ #test_name, \
+ new ::testing::internal::TestMetaFactory< \
+ GTEST_TEST_CLASS_NAME_(\
+ test_case_name, test_name)>()); \
return 0; \
} \
- static int gtest_registering_dummy_; \
+ static int gtest_registering_dummy_ GTEST_ATTRIBUTE_UNUSED_; \
GTEST_DISALLOW_COPY_AND_ASSIGN_(\
GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \
}; \
@@ -1403,16 +1406,36 @@ internal::CartesianProductHolder10<Generator1, Generator2, Generator3,
GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \
void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
-# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \
+// The optional last argument to INSTANTIATE_TEST_CASE_P allows the user
+// to specify a function or functor that generates custom test name suffixes
+// based on the test parameters. The function should accept one argument of
+// type testing::TestParamInfo<class ParamType>, and return std::string.
+//
+// testing::PrintToStringParamName is a builtin test suffix generator that
+// returns the value of testing::PrintToString(GetParam()). It does not work
+// for std::string or C strings.
+//
+// Note: test names must be non-empty, unique, and may only contain ASCII
+// alphanumeric characters or underscore.
+
+# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator, ...) \
::testing::internal::ParamGenerator<test_case_name::ParamType> \
gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \
- int gtest_##prefix##test_case_name##_dummy_ = \
+ ::std::string gtest_##prefix##test_case_name##_EvalGenerateName_( \
+ const ::testing::TestParamInfo<test_case_name::ParamType>& info) { \
+ return ::testing::internal::GetParamNameGen<test_case_name::ParamType> \
+ (__VA_ARGS__)(info); \
+ } \
+ int gtest_##prefix##test_case_name##_dummy_ GTEST_ATTRIBUTE_UNUSED_ = \
::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
GetTestCasePatternHolder<test_case_name>(\
- #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\
- #prefix, \
- &gtest_##prefix##test_case_name##_EvalGenerator_, \
- __FILE__, __LINE__)
+ #test_case_name, \
+ ::testing::internal::CodeLocation(\
+ __FILE__, __LINE__))->AddTestCaseInstantiation(\
+ #prefix, \
+ &gtest_##prefix##test_case_name##_EvalGenerator_, \
+ &gtest_##prefix##test_case_name##_EvalGenerateName_, \
+ __FILE__, __LINE__)
} // namespace testing
diff --git a/extern/gtest/include/gtest/gtest-printers.h b/extern/gtest/include/gtest/gtest-printers.h
index 0639d9f5869..27a1edc3728 100644
--- a/extern/gtest/include/gtest/gtest-printers.h
+++ b/extern/gtest/include/gtest/gtest-printers.h
@@ -103,6 +103,10 @@
#include "gtest/internal/gtest-port.h"
#include "gtest/internal/gtest-internal.h"
+#if defined(GTEST_HAS_STD_TUPLE_) && GTEST_HAS_STD_TUPLE_
+# include <tuple>
+#endif
+
namespace testing {
// Definitions in the 'internal' and 'internal2' name spaces are
@@ -250,6 +254,103 @@ void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) {
namespace testing {
namespace internal {
+// FormatForComparison<ToPrint, OtherOperand>::Format(value) formats a
+// value of type ToPrint that is an operand of a comparison assertion
+// (e.g. ASSERT_EQ). OtherOperand is the type of the other operand in
+// the comparison, and is used to help determine the best way to
+// format the value. In particular, when the value is a C string
+// (char pointer) and the other operand is an STL string object, we
+// want to format the C string as a string, since we know it is
+// compared by value with the string object. If the value is a char
+// pointer but the other operand is not an STL string object, we don't
+// know whether the pointer is supposed to point to a NUL-terminated
+// string, and thus want to print it as a pointer to be safe.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+
+// The default case.
+template <typename ToPrint, typename OtherOperand>
+class FormatForComparison {
+ public:
+ static ::std::string Format(const ToPrint& value) {
+ return ::testing::PrintToString(value);
+ }
+};
+
+// Array.
+template <typename ToPrint, size_t N, typename OtherOperand>
+class FormatForComparison<ToPrint[N], OtherOperand> {
+ public:
+ static ::std::string Format(const ToPrint* value) {
+ return FormatForComparison<const ToPrint*, OtherOperand>::Format(value);
+ }
+};
+
+// By default, print C string as pointers to be safe, as we don't know
+// whether they actually point to a NUL-terminated string.
+
+#define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType) \
+ template <typename OtherOperand> \
+ class FormatForComparison<CharType*, OtherOperand> { \
+ public: \
+ static ::std::string Format(CharType* value) { \
+ return ::testing::PrintToString(static_cast<const void*>(value)); \
+ } \
+ }
+
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t);
+
+#undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_
+
+// If a C string is compared with an STL string object, we know it's meant
+// to point to a NUL-terminated string, and thus can print it as a string.
+
+#define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \
+ template <> \
+ class FormatForComparison<CharType*, OtherStringType> { \
+ public: \
+ static ::std::string Format(CharType* value) { \
+ return ::testing::PrintToString(value); \
+ } \
+ }
+
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string);
+
+#if GTEST_HAS_GLOBAL_STRING
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::string);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::string);
+#endif
+
+#if GTEST_HAS_GLOBAL_WSTRING
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::wstring);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::wstring);
+#endif
+
+#if GTEST_HAS_STD_WSTRING
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring);
+#endif
+
+#undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_
+
+// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc)
+// operand to be used in a failure message. The type (but not value)
+// of the other operand may affect the format. This allows us to
+// print a char* as a raw pointer when it is compared against another
+// char* or void*, and print it as a C string when it is compared
+// against an std::string object, for example.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+template <typename T1, typename T2>
+std::string FormatForComparisonFailureMessage(
+ const T1& value, const T2& /* other_operand */) {
+ return FormatForComparison<T1, T2>::Format(value);
+}
+
// UniversalPrinter<T>::Print(value, ostream_ptr) prints the given
// value to the given ostream. The caller must ensure that
// 'ostream_ptr' is not NULL, or the behavior is undefined.
@@ -480,14 +581,16 @@ inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) {
}
#endif // GTEST_HAS_STD_WSTRING
-#if GTEST_HAS_TR1_TUPLE
-// Overload for ::std::tr1::tuple. Needed for printing function arguments,
-// which are packed as tuples.
-
+#if GTEST_HAS_TR1_TUPLE || (defined(GTEST_HAS_STD_TUPLE_) && GTEST_HAS_STD_TUPLE_)
// Helper function for printing a tuple. T must be instantiated with
// a tuple type.
template <typename T>
void PrintTupleTo(const T& t, ::std::ostream* os);
+#endif // GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_
+
+#if GTEST_HAS_TR1_TUPLE
+// Overload for ::std::tr1::tuple. Needed for printing function arguments,
+// which are packed as tuples.
// Overloaded PrintTo() for tuples of various arities. We support
// tuples of up-to 10 fields. The following implementation works
@@ -561,6 +664,13 @@ void PrintTo(
}
#endif // GTEST_HAS_TR1_TUPLE
+#if defined(GTEST_HAS_STD_TUPLE_) && GTEST_HAS_STD_TUPLE_
+template <typename... Types>
+void PrintTo(const ::std::tuple<Types...>& t, ::std::ostream* os) {
+ PrintTupleTo(t, os);
+}
+#endif // GTEST_HAS_STD_TUPLE_
+
// Overload for std::pair.
template <typename T1, typename T2>
void PrintTo(const ::std::pair<T1, T2>& value, ::std::ostream* os) {
@@ -580,10 +690,7 @@ class UniversalPrinter {
public:
// MSVC warns about adding const to a function type, so we want to
// disable the warning.
-#ifdef _MSC_VER
-# pragma warning(push) // Saves the current warning state.
-# pragma warning(disable:4180) // Temporarily disables warning 4180.
-#endif // _MSC_VER
+ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180)
// Note: we deliberately don't call this PrintTo(), as that name
// conflicts with ::testing::internal::PrintTo in the body of the
@@ -600,9 +707,7 @@ class UniversalPrinter {
PrintTo(value, os);
}
-#ifdef _MSC_VER
-# pragma warning(pop) // Restores the warning state.
-#endif // _MSC_VER
+ GTEST_DISABLE_MSC_WARNINGS_POP_()
};
// UniversalPrintArray(begin, len, os) prints an array of 'len'
@@ -654,10 +759,7 @@ class UniversalPrinter<T&> {
public:
// MSVC warns about adding const to a function type, so we want to
// disable the warning.
-#ifdef _MSC_VER
-# pragma warning(push) // Saves the current warning state.
-# pragma warning(disable:4180) // Temporarily disables warning 4180.
-#endif // _MSC_VER
+ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180)
static void Print(const T& value, ::std::ostream* os) {
// Prints the address of the value. We use reinterpret_cast here
@@ -668,9 +770,7 @@ class UniversalPrinter<T&> {
UniversalPrint(value, os);
}
-#ifdef _MSC_VER
-# pragma warning(pop) // Restores the warning state.
-#endif // _MSC_VER
+ GTEST_DISABLE_MSC_WARNINGS_POP_()
};
// Prints a value tersely: for a reference type, the referenced value
@@ -756,16 +856,65 @@ void UniversalPrint(const T& value, ::std::ostream* os) {
UniversalPrinter<T1>::Print(value, os);
}
-#if GTEST_HAS_TR1_TUPLE
typedef ::std::vector<string> Strings;
+// TuplePolicy<TupleT> must provide:
+// - tuple_size
+// size of tuple TupleT.
+// - get<size_t I>(const TupleT& t)
+// static function extracting element I of tuple TupleT.
+// - tuple_element<size_t I>::type
+// type of element I of tuple TupleT.
+template <typename TupleT>
+struct TuplePolicy;
+
+#if GTEST_HAS_TR1_TUPLE
+template <typename TupleT>
+struct TuplePolicy {
+ typedef TupleT Tuple;
+ static const size_t tuple_size = ::std::tr1::tuple_size<Tuple>::value;
+
+ template <size_t I>
+ struct tuple_element : ::std::tr1::tuple_element<I, Tuple> {};
+
+ template <size_t I>
+ static typename AddReference<
+ const typename ::std::tr1::tuple_element<I, Tuple>::type>::type get(
+ const Tuple& tuple) {
+ return ::std::tr1::get<I>(tuple);
+ }
+};
+template <typename TupleT>
+const size_t TuplePolicy<TupleT>::tuple_size;
+#endif // GTEST_HAS_TR1_TUPLE
+
+#if defined(GTEST_HAS_STD_TUPLE_) && GTEST_HAS_STD_TUPLE_
+template <typename... Types>
+struct TuplePolicy< ::std::tuple<Types...> > {
+ typedef ::std::tuple<Types...> Tuple;
+ static const size_t tuple_size = ::std::tuple_size<Tuple>::value;
+
+ template <size_t I>
+ struct tuple_element : ::std::tuple_element<I, Tuple> {};
+
+ template <size_t I>
+ static const typename ::std::tuple_element<I, Tuple>::type& get(
+ const Tuple& tuple) {
+ return ::std::get<I>(tuple);
+ }
+};
+template <typename... Types>
+const size_t TuplePolicy< ::std::tuple<Types...> >::tuple_size;
+#endif // GTEST_HAS_STD_TUPLE_
+
+#if GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_
// This helper template allows PrintTo() for tuples and
// UniversalTersePrintTupleFieldsToStrings() to be defined by
// induction on the number of tuple fields. The idea is that
// TuplePrefixPrinter<N>::PrintPrefixTo(t, os) prints the first N
// fields in tuple t, and can be defined in terms of
// TuplePrefixPrinter<N - 1>.
-
+//
// The inductive case.
template <size_t N>
struct TuplePrefixPrinter {
@@ -773,9 +922,14 @@ struct TuplePrefixPrinter {
template <typename Tuple>
static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) {
TuplePrefixPrinter<N - 1>::PrintPrefixTo(t, os);
- *os << ", ";
- UniversalPrinter<typename ::std::tr1::tuple_element<N - 1, Tuple>::type>
- ::Print(::std::tr1::get<N - 1>(t), os);
+ GTEST_INTENTIONAL_CONST_COND_PUSH_()
+ if (N > 1) {
+ GTEST_INTENTIONAL_CONST_COND_POP_()
+ *os << ", ";
+ }
+ UniversalPrinter<
+ typename TuplePolicy<Tuple>::template tuple_element<N - 1>::type>
+ ::Print(TuplePolicy<Tuple>::template get<N - 1>(t), os);
}
// Tersely prints the first N fields of a tuple to a string vector,
@@ -784,12 +938,12 @@ struct TuplePrefixPrinter {
static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) {
TuplePrefixPrinter<N - 1>::TersePrintPrefixToStrings(t, strings);
::std::stringstream ss;
- UniversalTersePrint(::std::tr1::get<N - 1>(t), &ss);
+ UniversalTersePrint(TuplePolicy<Tuple>::template get<N - 1>(t), &ss);
strings->push_back(ss.str());
}
};
-// Base cases.
+// Base case.
template <>
struct TuplePrefixPrinter<0> {
template <typename Tuple>
@@ -798,34 +952,13 @@ struct TuplePrefixPrinter<0> {
template <typename Tuple>
static void TersePrintPrefixToStrings(const Tuple&, Strings*) {}
};
-// We have to specialize the entire TuplePrefixPrinter<> class
-// template here, even though the definition of
-// TersePrintPrefixToStrings() is the same as the generic version, as
-// Embarcadero (formerly CodeGear, formerly Borland) C++ doesn't
-// support specializing a method template of a class template.
-template <>
-struct TuplePrefixPrinter<1> {
- template <typename Tuple>
- static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) {
- UniversalPrinter<typename ::std::tr1::tuple_element<0, Tuple>::type>::
- Print(::std::tr1::get<0>(t), os);
- }
- template <typename Tuple>
- static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) {
- ::std::stringstream ss;
- UniversalTersePrint(::std::tr1::get<0>(t), &ss);
- strings->push_back(ss.str());
- }
-};
-
-// Helper function for printing a tuple. T must be instantiated with
-// a tuple type.
-template <typename T>
-void PrintTupleTo(const T& t, ::std::ostream* os) {
+// Helper function for printing a tuple.
+// Tuple must be either std::tr1::tuple or std::tuple type.
+template <typename Tuple>
+void PrintTupleTo(const Tuple& t, ::std::ostream* os) {
*os << "(";
- TuplePrefixPrinter< ::std::tr1::tuple_size<T>::value>::
- PrintPrefixTo(t, os);
+ TuplePrefixPrinter<TuplePolicy<Tuple>::tuple_size>::PrintPrefixTo(t, os);
*os << ")";
}
@@ -835,11 +968,11 @@ void PrintTupleTo(const T& t, ::std::ostream* os) {
template <typename Tuple>
Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) {
Strings result;
- TuplePrefixPrinter< ::std::tr1::tuple_size<Tuple>::value>::
+ TuplePrefixPrinter<TuplePolicy<Tuple>::tuple_size>::
TersePrintPrefixToStrings(value, &result);
return result;
}
-#endif // GTEST_HAS_TR1_TUPLE
+#endif // GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_
} // namespace internal
@@ -852,4 +985,9 @@ template <typename T>
} // namespace testing
+// Include any custom printer added by the local installation.
+// We must include this header at the end to make sure it can use the
+// declarations from this file.
+#include "gtest/internal/custom/gtest-printers.h"
+
#endif // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
diff --git a/extern/gtest/include/gtest/gtest-typed-test.h b/extern/gtest/include/gtest/gtest-typed-test.h
index fe1e83b274b..5f69d5678ea 100644
--- a/extern/gtest/include/gtest/gtest-typed-test.h
+++ b/extern/gtest/include/gtest/gtest-typed-test.h
@@ -181,7 +181,8 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);
::testing::internal::TemplateSel< \
GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \
GTEST_TYPE_PARAMS_(CaseName)>::Register(\
- "", #CaseName, #TestName, 0); \
+ "", ::testing::internal::CodeLocation(__FILE__, __LINE__), \
+ #CaseName, #TestName, 0); \
template <typename gtest_TypeParam_> \
void GTEST_TEST_CLASS_NAME_(CaseName, TestName)<gtest_TypeParam_>::TestBody()
@@ -252,7 +253,10 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);
::testing::internal::TypeParameterizedTestCase<CaseName, \
GTEST_CASE_NAMESPACE_(CaseName)::gtest_AllTests_, \
::testing::internal::TypeList< Types >::type>::Register(\
- #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName))
+ #Prefix, \
+ ::testing::internal::CodeLocation(__FILE__, __LINE__), \
+ &GTEST_TYPED_TEST_CASE_P_STATE_(CaseName), \
+ #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName))
#endif // GTEST_HAS_TYPED_TEST_P
diff --git a/extern/gtest/include/gtest/gtest.h b/extern/gtest/include/gtest/gtest.h
index 69a8e72da5f..18d3ed4b469 100644
--- a/extern/gtest/include/gtest/gtest.h
+++ b/extern/gtest/include/gtest/gtest.h
@@ -70,14 +70,14 @@
// class ::string, which has the same interface as ::std::string, but
// has a different implementation.
//
-// The user can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that
+// You can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that
// ::string is available AND is a distinct type to ::std::string, or
// define it to 0 to indicate otherwise.
//
-// If the user's ::std::string and ::string are the same class due to
-// aliasing, he should define GTEST_HAS_GLOBAL_STRING to 0.
+// If ::std::string and ::string are the same class on your platform
+// due to aliasing, you should define GTEST_HAS_GLOBAL_STRING to 0.
//
-// If the user doesn't define GTEST_HAS_GLOBAL_STRING, it is defined
+// If you do not define GTEST_HAS_GLOBAL_STRING, it is defined
// heuristically.
namespace testing {
@@ -258,8 +258,31 @@ class GTEST_API_ AssertionResult {
// Copy constructor.
// Used in EXPECT_TRUE/FALSE(assertion_result).
AssertionResult(const AssertionResult& other);
+
+ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 /* forcing value to bool */)
+
// Used in the EXPECT_TRUE/FALSE(bool_expression).
- explicit AssertionResult(bool success) : success_(success) {}
+ //
+ // T must be contextually convertible to bool.
+ //
+ // The second parameter prevents this overload from being considered if
+ // the argument is implicitly convertible to AssertionResult. In that case
+ // we want AssertionResult's copy constructor to be used.
+ template <typename T>
+ explicit AssertionResult(
+ const T& success,
+ typename internal::EnableIf<
+ !internal::ImplicitlyConvertible<T, AssertionResult>::value>::type*
+ /*enabler*/ = NULL)
+ : success_(success) {}
+
+ GTEST_DISABLE_MSC_WARNINGS_POP_()
+
+ // Assignment operator.
+ AssertionResult& operator=(AssertionResult other) {
+ swap(other);
+ return *this;
+ }
// Returns true iff the assertion succeeded.
operator bool() const { return success_; } // NOLINT
@@ -300,6 +323,9 @@ class GTEST_API_ AssertionResult {
message_->append(a_message.GetString().c_str());
}
+ // Swap the contents of this AssertionResult with other.
+ void swap(AssertionResult& other);
+
// Stores result of the assertion predicate.
bool success_;
// Stores the message describing the condition in case the expectation
@@ -307,8 +333,6 @@ class GTEST_API_ AssertionResult {
// Referenced via a pointer to avoid taking too much stack frame space
// with test assertions.
internal::scoped_ptr< ::std::string> message_;
-
- GTEST_DISALLOW_ASSIGN_(AssertionResult);
};
// Makes a successful assertion result.
@@ -335,8 +359,8 @@ GTEST_API_ AssertionResult AssertionFailure(const Message& msg);
//
// class FooTest : public testing::Test {
// protected:
-// virtual void SetUp() { ... }
-// virtual void TearDown() { ... }
+// void SetUp() override { ... }
+// void TearDown() override { ... }
// ...
// };
//
@@ -428,20 +452,19 @@ class GTEST_API_ Test {
// internal method to avoid clashing with names used in user TESTs.
void DeleteSelf_() { delete this; }
- // Uses a GTestFlagSaver to save and restore all Google Test flags.
- const internal::GTestFlagSaver* const gtest_flag_saver_;
+ const internal::scoped_ptr< GTEST_FLAG_SAVER_ > gtest_flag_saver_;
- // Often a user mis-spells SetUp() as Setup() and spends a long time
+ // Often a user misspells SetUp() as Setup() and spends a long time
// wondering why it is never called by Google Test. The declaration of
// the following method is solely for catching such an error at
// compile time:
//
// - The return type is deliberately chosen to be not void, so it
- // will be a conflict if a user declares void Setup() in his test
- // fixture.
+ // will be a conflict if void Setup() is declared in the user's
+ // test fixture.
//
// - This method is private, so it will be another compiler error
- // if a user calls it from his test fixture.
+ // if the method is called from the user's test fixture.
//
// DO NOT OVERRIDE THIS FUNCTION.
//
@@ -646,6 +669,12 @@ class GTEST_API_ TestInfo {
return NULL;
}
+ // Returns the file name where this test is defined.
+ const char* file() const { return location_.file.c_str(); }
+
+ // Returns the line where this test is defined.
+ int line() const { return location_.line; }
+
// Returns true if this test should run, that is if the test is not
// disabled (or it is disabled but the also_run_disabled_tests flag has
// been specified) and its full name matches the user-specified filter.
@@ -688,6 +717,7 @@ class GTEST_API_ TestInfo {
const char* name,
const char* type_param,
const char* value_param,
+ internal::CodeLocation code_location,
internal::TypeId fixture_class_id,
Test::SetUpTestCaseFunc set_up_tc,
Test::TearDownTestCaseFunc tear_down_tc,
@@ -699,6 +729,7 @@ class GTEST_API_ TestInfo {
const std::string& name,
const char* a_type_param, // NULL if not a type-parameterized test
const char* a_value_param, // NULL if not a value-parameterized test
+ internal::CodeLocation a_code_location,
internal::TypeId fixture_class_id,
internal::TestFactoryBase* factory);
@@ -725,6 +756,7 @@ class GTEST_API_ TestInfo {
// Text representation of the value parameter, or NULL if this is not a
// value-parameterized test.
const internal::scoped_ptr<const ::std::string> value_param_;
+ internal::CodeLocation location_;
const internal::TypeId fixture_class_id_; // ID of the test fixture class
bool should_run_; // True iff this test should run
bool is_disabled_; // True iff this test is disabled
@@ -924,7 +956,7 @@ class GTEST_API_ TestCase {
};
// An Environment object is capable of setting up and tearing down an
-// environment. The user should subclass this to define his own
+// environment. You should subclass this to define your own
// environment(s).
//
// An Environment object does the set-up and tear-down in virtual
@@ -1336,137 +1368,42 @@ GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv);
namespace internal {
-// FormatForComparison<ToPrint, OtherOperand>::Format(value) formats a
-// value of type ToPrint that is an operand of a comparison assertion
-// (e.g. ASSERT_EQ). OtherOperand is the type of the other operand in
-// the comparison, and is used to help determine the best way to
-// format the value. In particular, when the value is a C string
-// (char pointer) and the other operand is an STL string object, we
-// want to format the C string as a string, since we know it is
-// compared by value with the string object. If the value is a char
-// pointer but the other operand is not an STL string object, we don't
-// know whether the pointer is supposed to point to a NUL-terminated
-// string, and thus want to print it as a pointer to be safe.
-//
-// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
-
-// The default case.
-template <typename ToPrint, typename OtherOperand>
-class FormatForComparison {
- public:
- static ::std::string Format(const ToPrint& value) {
- return ::testing::PrintToString(value);
- }
-};
-
-// Array.
-template <typename ToPrint, size_t N, typename OtherOperand>
-class FormatForComparison<ToPrint[N], OtherOperand> {
- public:
- static ::std::string Format(const ToPrint* value) {
- return FormatForComparison<const ToPrint*, OtherOperand>::Format(value);
- }
-};
-
-// By default, print C string as pointers to be safe, as we don't know
-// whether they actually point to a NUL-terminated string.
-
-#define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType) \
- template <typename OtherOperand> \
- class FormatForComparison<CharType*, OtherOperand> { \
- public: \
- static ::std::string Format(CharType* value) { \
- return ::testing::PrintToString(static_cast<const void*>(value)); \
- } \
- }
-
-GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char);
-GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char);
-GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t);
-GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t);
-
-#undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_
-
-// If a C string is compared with an STL string object, we know it's meant
-// to point to a NUL-terminated string, and thus can print it as a string.
-
-#define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \
- template <> \
- class FormatForComparison<CharType*, OtherStringType> { \
- public: \
- static ::std::string Format(CharType* value) { \
- return ::testing::PrintToString(value); \
- } \
- }
-
-GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string);
-GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string);
-
-#if GTEST_HAS_GLOBAL_STRING
-GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::string);
-GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::string);
-#endif
-
-#if GTEST_HAS_GLOBAL_WSTRING
-GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::wstring);
-GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::wstring);
-#endif
-
-#if GTEST_HAS_STD_WSTRING
-GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring);
-GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring);
-#endif
-
-#undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_
-
-// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc)
-// operand to be used in a failure message. The type (but not value)
-// of the other operand may affect the format. This allows us to
-// print a char* as a raw pointer when it is compared against another
-// char* or void*, and print it as a C string when it is compared
-// against an std::string object, for example.
-//
-// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+// Separate the error generating code from the code path to reduce the stack
+// frame size of CmpHelperEQ. This helps reduce the overhead of some sanitizers
+// when calling EXPECT_* in a tight loop.
template <typename T1, typename T2>
-std::string FormatForComparisonFailureMessage(
- const T1& value, const T2& /* other_operand */) {
- return FormatForComparison<T1, T2>::Format(value);
+AssertionResult CmpHelperEQFailure(const char* lhs_expression,
+ const char* rhs_expression,
+ const T1& lhs, const T2& rhs) {
+ return EqFailure(lhs_expression,
+ rhs_expression,
+ FormatForComparisonFailureMessage(lhs, rhs),
+ FormatForComparisonFailureMessage(rhs, lhs),
+ false);
}
// The helper function for {ASSERT|EXPECT}_EQ.
template <typename T1, typename T2>
-AssertionResult CmpHelperEQ(const char* expected_expression,
- const char* actual_expression,
- const T1& expected,
- const T2& actual) {
-#ifdef _MSC_VER
-# pragma warning(push) // Saves the current warning state.
-# pragma warning(disable:4389) // Temporarily disables warning on
- // signed/unsigned mismatch.
-#endif
-
- if (expected == actual) {
+AssertionResult CmpHelperEQ(const char* lhs_expression,
+ const char* rhs_expression,
+ const T1& lhs,
+ const T2& rhs) {
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4389 /* signed/unsigned mismatch */)
+ if (lhs == rhs) {
return AssertionSuccess();
}
+GTEST_DISABLE_MSC_WARNINGS_POP_()
-#ifdef _MSC_VER
-# pragma warning(pop) // Restores the warning state.
-#endif
-
- return EqFailure(expected_expression,
- actual_expression,
- FormatForComparisonFailureMessage(expected, actual),
- FormatForComparisonFailureMessage(actual, expected),
- false);
+ return CmpHelperEQFailure(lhs_expression, rhs_expression, lhs, rhs);
}
// With this overloaded version, we allow anonymous enums to be used
// in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums
// can be implicitly cast to BiggestInt.
-GTEST_API_ AssertionResult CmpHelperEQ(const char* expected_expression,
- const char* actual_expression,
- BiggestInt expected,
- BiggestInt actual);
+GTEST_API_ AssertionResult CmpHelperEQ(const char* lhs_expression,
+ const char* rhs_expression,
+ BiggestInt lhs,
+ BiggestInt rhs);
// The helper class for {ASSERT|EXPECT}_EQ. The template argument
// lhs_is_null_literal is true iff the first argument to ASSERT_EQ()
@@ -1477,12 +1414,11 @@ class EqHelper {
public:
// This templatized version is for the general case.
template <typename T1, typename T2>
- static AssertionResult Compare(const char* expected_expression,
- const char* actual_expression,
- const T1& expected,
- const T2& actual) {
- return CmpHelperEQ(expected_expression, actual_expression, expected,
- actual);
+ static AssertionResult Compare(const char* lhs_expression,
+ const char* rhs_expression,
+ const T1& lhs,
+ const T2& rhs) {
+ return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs);
}
// With this overloaded version, we allow anonymous enums to be used
@@ -1491,12 +1427,11 @@ class EqHelper {
//
// Even though its body looks the same as the above version, we
// cannot merge the two, as it will make anonymous enums unhappy.
- static AssertionResult Compare(const char* expected_expression,
- const char* actual_expression,
- BiggestInt expected,
- BiggestInt actual) {
- return CmpHelperEQ(expected_expression, actual_expression, expected,
- actual);
+ static AssertionResult Compare(const char* lhs_expression,
+ const char* rhs_expression,
+ BiggestInt lhs,
+ BiggestInt rhs) {
+ return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs);
}
};
@@ -1511,40 +1446,52 @@ class EqHelper<true> {
// EXPECT_EQ(false, a_bool).
template <typename T1, typename T2>
static AssertionResult Compare(
- const char* expected_expression,
- const char* actual_expression,
- const T1& expected,
- const T2& actual,
+ const char* lhs_expression,
+ const char* rhs_expression,
+ const T1& lhs,
+ const T2& rhs,
// The following line prevents this overload from being considered if T2
// is not a pointer type. We need this because ASSERT_EQ(NULL, my_ptr)
// expands to Compare("", "", NULL, my_ptr), which requires a conversion
// to match the Secret* in the other overload, which would otherwise make
// this template match better.
typename EnableIf<!is_pointer<T2>::value>::type* = 0) {
- return CmpHelperEQ(expected_expression, actual_expression, expected,
- actual);
+ return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs);
}
// This version will be picked when the second argument to ASSERT_EQ() is a
// pointer, e.g. ASSERT_EQ(NULL, a_pointer).
template <typename T>
static AssertionResult Compare(
- const char* expected_expression,
- const char* actual_expression,
+ const char* lhs_expression,
+ const char* rhs_expression,
// We used to have a second template parameter instead of Secret*. That
// template parameter would deduce to 'long', making this a better match
// than the first overload even without the first overload's EnableIf.
// Unfortunately, gcc with -Wconversion-null warns when "passing NULL to
// non-pointer argument" (even a deduced integral argument), so the old
// implementation caused warnings in user code.
- Secret* /* expected (NULL) */,
- T* actual) {
- // We already know that 'expected' is a null pointer.
- return CmpHelperEQ(expected_expression, actual_expression,
- static_cast<T*>(NULL), actual);
+ Secret* /* lhs (NULL) */,
+ T* rhs) {
+ // We already know that 'lhs' is a null pointer.
+ return CmpHelperEQ(lhs_expression, rhs_expression,
+ static_cast<T*>(NULL), rhs);
}
};
+// Separate the error generating code from the code path to reduce the stack
+// frame size of CmpHelperOP. This helps reduce the overhead of some sanitizers
+// when calling EXPECT_OP in a tight loop.
+template <typename T1, typename T2>
+AssertionResult CmpHelperOpFailure(const char* expr1, const char* expr2,
+ const T1& val1, const T2& val2,
+ const char* op) {
+ return AssertionFailure()
+ << "Expected: (" << expr1 << ") " << op << " (" << expr2
+ << "), actual: " << FormatForComparisonFailureMessage(val1, val2)
+ << " vs " << FormatForComparisonFailureMessage(val2, val1);
+}
+
// A macro for implementing the helper functions needed to implement
// ASSERT_?? and EXPECT_??. It is here just to avoid copy-and-paste
// of similar code.
@@ -1555,6 +1502,7 @@ class EqHelper<true> {
// with gcc 4.
//
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+
#define GTEST_IMPL_CMP_HELPER_(op_name, op)\
template <typename T1, typename T2>\
AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \
@@ -1562,10 +1510,7 @@ AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \
if (val1 op val2) {\
return AssertionSuccess();\
} else {\
- return AssertionFailure() \
- << "Expected: (" << expr1 << ") " #op " (" << expr2\
- << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\
- << " vs " << FormatForComparisonFailureMessage(val2, val1);\
+ return CmpHelperOpFailure(expr1, expr2, val1, val2, #op);\
}\
}\
GTEST_API_ AssertionResult CmpHelper##op_name(\
@@ -1589,18 +1534,18 @@ GTEST_IMPL_CMP_HELPER_(GT, >);
// The helper function for {ASSERT|EXPECT}_STREQ.
//
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
-GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression,
- const char* actual_expression,
- const char* expected,
- const char* actual);
+GTEST_API_ AssertionResult CmpHelperSTREQ(const char* s1_expression,
+ const char* s2_expression,
+ const char* s1,
+ const char* s2);
// The helper function for {ASSERT|EXPECT}_STRCASEEQ.
//
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
-GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression,
- const char* actual_expression,
- const char* expected,
- const char* actual);
+GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* s1_expression,
+ const char* s2_expression,
+ const char* s1,
+ const char* s2);
// The helper function for {ASSERT|EXPECT}_STRNE.
//
@@ -1622,10 +1567,10 @@ GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression,
// Helper function for *_STREQ on wide strings.
//
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
-GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression,
- const char* actual_expression,
- const wchar_t* expected,
- const wchar_t* actual);
+GTEST_API_ AssertionResult CmpHelperSTREQ(const char* s1_expression,
+ const char* s2_expression,
+ const wchar_t* s1,
+ const wchar_t* s2);
// Helper function for *_STRNE on wide strings.
//
@@ -1683,28 +1628,28 @@ namespace internal {
//
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
template <typename RawType>
-AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression,
- const char* actual_expression,
- RawType expected,
- RawType actual) {
- const FloatingPoint<RawType> lhs(expected), rhs(actual);
+AssertionResult CmpHelperFloatingPointEQ(const char* lhs_expression,
+ const char* rhs_expression,
+ RawType lhs_value,
+ RawType rhs_value) {
+ const FloatingPoint<RawType> lhs(lhs_value), rhs(rhs_value);
if (lhs.AlmostEquals(rhs)) {
return AssertionSuccess();
}
- ::std::stringstream expected_ss;
- expected_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
- << expected;
+ ::std::stringstream lhs_ss;
+ lhs_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+ << lhs_value;
- ::std::stringstream actual_ss;
- actual_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
- << actual;
+ ::std::stringstream rhs_ss;
+ rhs_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+ << rhs_value;
- return EqFailure(expected_expression,
- actual_expression,
- StringStreamToString(&expected_ss),
- StringStreamToString(&actual_ss),
+ return EqFailure(lhs_expression,
+ rhs_expression,
+ StringStreamToString(&lhs_ss),
+ StringStreamToString(&rhs_ss),
false);
}
@@ -1912,13 +1857,13 @@ class TestWithParam : public Test, public WithParamInterface<T> {
// AssertionResult. For more information on how to use AssertionResult with
// these macros see comments on that class.
#define EXPECT_TRUE(condition) \
- GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \
+ GTEST_TEST_BOOLEAN_((condition), #condition, false, true, \
GTEST_NONFATAL_FAILURE_)
#define EXPECT_FALSE(condition) \
GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
GTEST_NONFATAL_FAILURE_)
#define ASSERT_TRUE(condition) \
- GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \
+ GTEST_TEST_BOOLEAN_((condition), #condition, false, true, \
GTEST_FATAL_FAILURE_)
#define ASSERT_FALSE(condition) \
GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
@@ -1930,12 +1875,12 @@ class TestWithParam : public Test, public WithParamInterface<T> {
// Macros for testing equalities and inequalities.
//
-// * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual
-// * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2
-// * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2
-// * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2
-// * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2
-// * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2
+// * {ASSERT|EXPECT}_EQ(v1, v2): Tests that v1 == v2
+// * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2
+// * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2
+// * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2
+// * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2
+// * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2
//
// When they are not, Google Test prints both the tested expressions and
// their actual values. The values must be compatible built-in types,
@@ -1957,8 +1902,8 @@ class TestWithParam : public Test, public WithParamInterface<T> {
// are related, not how their content is related. To compare two C
// strings by content, use {ASSERT|EXPECT}_STR*().
//
-// 3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to
-// {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you
+// 3. {ASSERT|EXPECT}_EQ(v1, v2) is preferred to
+// {ASSERT|EXPECT}_TRUE(v1 == v2), as the former tells you
// what the actual value is when it fails, and similarly for the
// other comparisons.
//
@@ -1974,12 +1919,12 @@ class TestWithParam : public Test, public WithParamInterface<T> {
// ASSERT_LT(i, array_size);
// ASSERT_GT(records.size(), 0) << "There is no record left.";
-#define EXPECT_EQ(expected, actual) \
+#define EXPECT_EQ(val1, val2) \
EXPECT_PRED_FORMAT2(::testing::internal:: \
- EqHelper<GTEST_IS_NULL_LITERAL_(expected)>::Compare, \
- expected, actual)
-#define EXPECT_NE(expected, actual) \
- EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual)
+ EqHelper<GTEST_IS_NULL_LITERAL_(val1)>::Compare, \
+ val1, val2)
+#define EXPECT_NE(val1, val2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2)
#define EXPECT_LE(val1, val2) \
EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2)
#define EXPECT_LT(val1, val2) \
@@ -1989,10 +1934,10 @@ class TestWithParam : public Test, public WithParamInterface<T> {
#define EXPECT_GT(val1, val2) \
EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2)
-#define GTEST_ASSERT_EQ(expected, actual) \
+#define GTEST_ASSERT_EQ(val1, val2) \
ASSERT_PRED_FORMAT2(::testing::internal:: \
- EqHelper<GTEST_IS_NULL_LITERAL_(expected)>::Compare, \
- expected, actual)
+ EqHelper<GTEST_IS_NULL_LITERAL_(val1)>::Compare, \
+ val1, val2)
#define GTEST_ASSERT_NE(val1, val2) \
ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2)
#define GTEST_ASSERT_LE(val1, val2) \
@@ -2047,29 +1992,29 @@ class TestWithParam : public Test, public WithParamInterface<T> {
//
// These macros evaluate their arguments exactly once.
-#define EXPECT_STREQ(expected, actual) \
- EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual)
+#define EXPECT_STREQ(s1, s2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, s1, s2)
#define EXPECT_STRNE(s1, s2) \
EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2)
-#define EXPECT_STRCASEEQ(expected, actual) \
- EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual)
+#define EXPECT_STRCASEEQ(s1, s2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, s1, s2)
#define EXPECT_STRCASENE(s1, s2)\
EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2)
-#define ASSERT_STREQ(expected, actual) \
- ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual)
+#define ASSERT_STREQ(s1, s2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, s1, s2)
#define ASSERT_STRNE(s1, s2) \
ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2)
-#define ASSERT_STRCASEEQ(expected, actual) \
- ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual)
+#define ASSERT_STRCASEEQ(s1, s2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, s1, s2)
#define ASSERT_STRCASENE(s1, s2)\
ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2)
// Macros for comparing floating-point numbers.
//
-// * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual):
+// * {ASSERT|EXPECT}_FLOAT_EQ(val1, val2):
// Tests that two float values are almost equal.
-// * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual):
+// * {ASSERT|EXPECT}_DOUBLE_EQ(val1, val2):
// Tests that two double values are almost equal.
// * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error):
// Tests that v1 and v2 are within the given distance to each other.
@@ -2079,21 +2024,21 @@ class TestWithParam : public Test, public WithParamInterface<T> {
// FloatingPoint template class in gtest-internal.h if you are
// interested in the implementation details.
-#define EXPECT_FLOAT_EQ(expected, actual)\
+#define EXPECT_FLOAT_EQ(val1, val2)\
EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<float>, \
- expected, actual)
+ val1, val2)
-#define EXPECT_DOUBLE_EQ(expected, actual)\
+#define EXPECT_DOUBLE_EQ(val1, val2)\
EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<double>, \
- expected, actual)
+ val1, val2)
-#define ASSERT_FLOAT_EQ(expected, actual)\
+#define ASSERT_FLOAT_EQ(val1, val2)\
ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<float>, \
- expected, actual)
+ val1, val2)
-#define ASSERT_DOUBLE_EQ(expected, actual)\
+#define ASSERT_DOUBLE_EQ(val1, val2)\
ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<double>, \
- expected, actual)
+ val1, val2)
#define EXPECT_NEAR(val1, val2, abs_error)\
EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \
@@ -2215,8 +2160,8 @@ bool StaticAssertTypeEq() {
// The convention is to end the test case name with "Test". For
// example, a test case for the Foo class can be named FooTest.
//
-// The user should put his test code between braces after using this
-// macro. Example:
+// Test code should appear between braces after an invocation of
+// this macro. Example:
//
// TEST(FooTest, InitializesCorrectly) {
// Foo foo;
diff --git a/extern/gtest/include/gtest/internal/custom/gtest-port.h b/extern/gtest/include/gtest/internal/custom/gtest-port.h
new file mode 100644
index 00000000000..7e744bd3bb3
--- /dev/null
+++ b/extern/gtest/include/gtest/internal/custom/gtest-port.h
@@ -0,0 +1,69 @@
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Injection point for custom user configurations.
+// The following macros can be defined:
+//
+// Flag related macros:
+// GTEST_FLAG(flag_name)
+// GTEST_USE_OWN_FLAGFILE_FLAG_ - Define to 0 when the system provides its
+// own flagfile flag parsing.
+// GTEST_DECLARE_bool_(name)
+// GTEST_DECLARE_int32_(name)
+// GTEST_DECLARE_string_(name)
+// GTEST_DEFINE_bool_(name, default_val, doc)
+// GTEST_DEFINE_int32_(name, default_val, doc)
+// GTEST_DEFINE_string_(name, default_val, doc)
+//
+// Test filtering:
+// GTEST_TEST_FILTER_ENV_VAR_ - The name of an environment variable that
+// will be used if --GTEST_FLAG(test_filter)
+// is not provided.
+//
+// Logging:
+// GTEST_LOG_(severity)
+// GTEST_CHECK_(condition)
+// Functions LogToStderr() and FlushInfoLog() have to be provided too.
+//
+// Threading:
+// GTEST_HAS_NOTIFICATION_ - Enabled if Notification is already provided.
+// GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ - Enabled if Mutex and ThreadLocal are
+// already provided.
+// Must also provide GTEST_DECLARE_STATIC_MUTEX_(mutex) and
+// GTEST_DEFINE_STATIC_MUTEX_(mutex)
+//
+// GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks)
+// GTEST_LOCK_EXCLUDED_(locks)
+//
+// ** Custom implementation starts here **
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
diff --git a/extern/gtest/include/gtest/internal/custom/gtest-printers.h b/extern/gtest/include/gtest/internal/custom/gtest-printers.h
new file mode 100644
index 00000000000..60c1ea050b6
--- /dev/null
+++ b/extern/gtest/include/gtest/internal/custom/gtest-printers.h
@@ -0,0 +1,42 @@
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// This file provides an injection point for custom printers in a local
+// installation of gTest.
+// It will be included from gtest-printers.h and the overrides in this file
+// will be visible to everyone.
+// See documentation at gtest/gtest-printers.h for details on how to define a
+// custom printer.
+//
+// ** Custom implementation starts here **
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
diff --git a/extern/gtest/include/gtest/internal/custom/gtest.h b/extern/gtest/include/gtest/internal/custom/gtest.h
new file mode 100644
index 00000000000..c27412a8981
--- /dev/null
+++ b/extern/gtest/include/gtest/internal/custom/gtest.h
@@ -0,0 +1,41 @@
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Injection point for custom user configurations.
+// The following macros can be defined:
+//
+// GTEST_OS_STACK_TRACE_GETTER_ - The name of an implementation of
+// OsStackTraceGetterInterface.
+//
+// ** Custom implementation starts here **
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_
diff --git a/extern/gtest/include/gtest/internal/gtest-internal.h b/extern/gtest/include/gtest/internal/gtest-internal.h
index 0dcc3a3194f..ebd1cf615de 100644
--- a/extern/gtest/include/gtest/internal/gtest-internal.h
+++ b/extern/gtest/include/gtest/internal/gtest-internal.h
@@ -55,7 +55,10 @@
#include <string.h>
#include <iomanip>
#include <limits>
+#include <map>
#include <set>
+#include <string>
+#include <vector>
#include "gtest/gtest-message.h"
#include "gtest/internal/gtest-string.h"
@@ -97,9 +100,6 @@ class ScopedTrace; // Implements scoped trace.
class TestInfoImpl; // Opaque implementation of TestInfo
class UnitTestImpl; // Opaque implementation of UnitTest
-// How many times InitGoogleTest() has been called.
-GTEST_API_ extern int g_init_gtest_count;
-
// The text used in failure messages to indicate the start of the
// stack trace.
GTEST_API_ extern const char kStackTraceMarker[];
@@ -171,6 +171,36 @@ class GTEST_API_ ScopedTrace {
// c'tor and d'tor. Therefore it doesn't
// need to be used otherwise.
+namespace edit_distance {
+// Returns the optimal edits to go from 'left' to 'right'.
+// All edits cost the same, with replace having lower priority than
+// add/remove.
+// Simple implementation of the Wagner–Fischer algorithm.
+// See http://en.wikipedia.org/wiki/Wagner-Fischer_algorithm
+enum EditType { kMatch, kAdd, kRemove, kReplace };
+GTEST_API_ std::vector<EditType> CalculateOptimalEdits(
+ const std::vector<size_t>& left, const std::vector<size_t>& right);
+
+// Same as above, but the input is represented as strings.
+GTEST_API_ std::vector<EditType> CalculateOptimalEdits(
+ const std::vector<std::string>& left,
+ const std::vector<std::string>& right);
+
+// Create a diff of the input strings in Unified diff format.
+GTEST_API_ std::string CreateUnifiedDiff(const std::vector<std::string>& left,
+ const std::vector<std::string>& right,
+ size_t context = 2);
+
+} // namespace edit_distance
+
+// Calculate the diff between 'left' and 'right' and return it in unified diff
+// format.
+// If not null, stores in 'total_line_count' the total number of lines found
+// in left + right.
+GTEST_API_ std::string DiffStrings(const std::string& left,
+ const std::string& right,
+ size_t* total_line_count);
+
// Constructs and returns the message for an equality assertion
// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure.
//
@@ -471,6 +501,13 @@ GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr,
typedef void (*SetUpTestCaseFunc)();
typedef void (*TearDownTestCaseFunc)();
+struct CodeLocation {
+ CodeLocation(const string& a_file, int a_line) : file(a_file), line(a_line) {}
+
+ string file;
+ int line;
+};
+
// Creates a new TestInfo object and registers it with Google Test;
// returns the created object.
//
@@ -482,6 +519,7 @@ typedef void (*TearDownTestCaseFunc)();
// this is not a typed or a type-parameterized test.
// value_param text representation of the test's value parameter,
// or NULL if this is not a type-parameterized test.
+// code_location: code location where the test is defined
// fixture_class_id: ID of the test fixture class
// set_up_tc: pointer to the function that sets up the test case
// tear_down_tc: pointer to the function that tears down the test case
@@ -493,6 +531,7 @@ GTEST_API_ TestInfo* MakeAndRegisterTestInfo(
const char* name,
const char* type_param,
const char* value_param,
+ CodeLocation code_location,
TypeId fixture_class_id,
SetUpTestCaseFunc set_up_tc,
TearDownTestCaseFunc tear_down_tc,
@@ -522,10 +561,21 @@ class GTEST_API_ TypedTestCasePState {
fflush(stderr);
posix::Abort();
}
- defined_test_names_.insert(test_name);
+ registered_tests_.insert(
+ ::std::make_pair(test_name, CodeLocation(file, line)));
return true;
}
+ bool TestExists(const std::string& test_name) const {
+ return registered_tests_.count(test_name) > 0;
+ }
+
+ const CodeLocation& GetCodeLocation(const std::string& test_name) const {
+ RegisteredTestsMap::const_iterator it = registered_tests_.find(test_name);
+ GTEST_CHECK_(it != registered_tests_.end());
+ return it->second;
+ }
+
// Verifies that registered_tests match the test names in
// defined_test_names_; returns registered_tests if successful, or
// aborts the program otherwise.
@@ -533,8 +583,10 @@ class GTEST_API_ TypedTestCasePState {
const char* file, int line, const char* registered_tests);
private:
+ typedef ::std::map<std::string, CodeLocation> RegisteredTestsMap;
+
bool registered_;
- ::std::set<const char*> defined_test_names_;
+ RegisteredTestsMap registered_tests_;
};
// Skips to the first non-space char after the first comma in 'str';
@@ -555,6 +607,11 @@ inline std::string GetPrefixUntilComma(const char* str) {
return comma == NULL ? str : std::string(str, comma);
}
+// Splits a given string on a given delimiter, populating a given
+// vector with the fields.
+void SplitString(const ::std::string& str, char delimiter,
+ ::std::vector< ::std::string>* dest);
+
// TypeParameterizedTest<Fixture, TestSel, Types>::Register()
// registers a list of type-parameterized tests with Google Test. The
// return value is insignificant - we just need to return something
@@ -569,8 +626,10 @@ class TypeParameterizedTest {
// specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase,
// Types). Valid values for 'index' are [0, N - 1] where N is the
// length of Types.
- static bool Register(const char* prefix, const char* case_name,
- const char* test_names, int index) {
+ static bool Register(const char* prefix,
+ CodeLocation code_location,
+ const char* case_name, const char* test_names,
+ int index) {
typedef typename Types::Head Type;
typedef Fixture<Type> FixtureClass;
typedef typename GTEST_BIND_(TestSel, Type) TestClass;
@@ -580,9 +639,10 @@ class TypeParameterizedTest {
MakeAndRegisterTestInfo(
(std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + "/"
+ StreamableToString(index)).c_str(),
- GetPrefixUntilComma(test_names).c_str(),
+ StripTrailingSpaces(GetPrefixUntilComma(test_names)).c_str(),
GetTypeName<Type>().c_str(),
NULL, // No value parameter.
+ code_location,
GetTypeId<FixtureClass>(),
TestClass::SetUpTestCase,
TestClass::TearDownTestCase,
@@ -590,7 +650,7 @@ class TypeParameterizedTest {
// Next, recurses (at compile time) with the tail of the type list.
return TypeParameterizedTest<Fixture, TestSel, typename Types::Tail>
- ::Register(prefix, case_name, test_names, index + 1);
+ ::Register(prefix, code_location, case_name, test_names, index + 1);
}
};
@@ -598,8 +658,9 @@ class TypeParameterizedTest {
template <GTEST_TEMPLATE_ Fixture, class TestSel>
class TypeParameterizedTest<Fixture, TestSel, Types0> {
public:
- static bool Register(const char* /*prefix*/, const char* /*case_name*/,
- const char* /*test_names*/, int /*index*/) {
+ static bool Register(const char* /*prefix*/, CodeLocation,
+ const char* /*case_name*/, const char* /*test_names*/,
+ int /*index*/) {
return true;
}
};
@@ -611,17 +672,31 @@ class TypeParameterizedTest<Fixture, TestSel, Types0> {
template <GTEST_TEMPLATE_ Fixture, typename Tests, typename Types>
class TypeParameterizedTestCase {
public:
- static bool Register(const char* prefix, const char* case_name,
- const char* test_names) {
+ static bool Register(const char* prefix, CodeLocation code_location,
+ const TypedTestCasePState* state,
+ const char* case_name, const char* test_names) {
+ std::string test_name = StripTrailingSpaces(
+ GetPrefixUntilComma(test_names));
+ if (!state->TestExists(test_name)) {
+ fprintf(stderr, "Failed to get code location for test %s.%s at %s.",
+ case_name, test_name.c_str(),
+ FormatFileLocation(code_location.file.c_str(),
+ code_location.line).c_str());
+ fflush(stderr);
+ posix::Abort();
+ }
+ const CodeLocation& test_location = state->GetCodeLocation(test_name);
+
typedef typename Tests::Head Head;
// First, register the first test in 'Test' for each type in 'Types'.
TypeParameterizedTest<Fixture, Head, Types>::Register(
- prefix, case_name, test_names, 0);
+ prefix, test_location, case_name, test_names, 0);
// Next, recurses (at compile time) with the tail of the test list.
return TypeParameterizedTestCase<Fixture, typename Tests::Tail, Types>
- ::Register(prefix, case_name, SkipComma(test_names));
+ ::Register(prefix, code_location, state,
+ case_name, SkipComma(test_names));
}
};
@@ -629,8 +704,9 @@ class TypeParameterizedTestCase {
template <GTEST_TEMPLATE_ Fixture, typename Types>
class TypeParameterizedTestCase<Fixture, Templates0, Types> {
public:
- static bool Register(const char* /*prefix*/, const char* /*case_name*/,
- const char* /*test_names*/) {
+ static bool Register(const char* /*prefix*/, CodeLocation,
+ const TypedTestCasePState* /*state*/,
+ const char* /*case_name*/, const char* /*test_names*/) {
return true;
}
};
@@ -784,7 +860,7 @@ class ImplicitlyConvertible {
// MakeFrom() is an expression whose type is From. We cannot simply
// use From(), as the type From may not have a public default
// constructor.
- static From MakeFrom();
+ static typename AddReference<From>::type MakeFrom();
// These two functions are overloaded. Given an expression
// Helper(x), the compiler will pick the first version if x can be
@@ -802,25 +878,20 @@ class ImplicitlyConvertible {
// We have to put the 'public' section after the 'private' section,
// or MSVC refuses to compile the code.
public:
- // MSVC warns about implicitly converting from double to int for
- // possible loss of data, so we need to temporarily disable the
- // warning.
-#ifdef _MSC_VER
-# pragma warning(push) // Saves the current warning state.
-# pragma warning(disable:4244) // Temporarily disables warning 4244.
-
- static const bool value =
- sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1;
-# pragma warning(pop) // Restores the warning state.
-#elif defined(__BORLANDC__)
+#if defined(__BORLANDC__)
// C++Builder cannot use member overload resolution during template
// instantiation. The simplest workaround is to use its C++0x type traits
// functions (C++Builder 2009 and above only).
static const bool value = __is_convertible(From, To);
#else
+ // MSVC warns about implicitly converting from double to int for
+ // possible loss of data, so we need to temporarily disable the
+ // warning.
+ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4244)
static const bool value =
sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1;
-#endif // _MSV_VER
+ GTEST_DISABLE_MSC_WARNINGS_POP_()
+#endif // __BORLANDC__
};
template <typename From, typename To>
const bool ImplicitlyConvertible<From, To>::value;
@@ -946,11 +1017,10 @@ void CopyArray(const T* from, size_t size, U* to) {
// The relation between an NativeArray object (see below) and the
// native array it represents.
-enum RelationToSource {
- kReference, // The NativeArray references the native array.
- kCopy // The NativeArray makes a copy of the native array and
- // owns the copy.
-};
+// We use 2 different structs to allow non-copyable types to be used, as long
+// as RelationToSourceReference() is passed.
+struct RelationToSourceReference {};
+struct RelationToSourceCopy {};
// Adapts a native array to a read-only STL-style container. Instead
// of the complete STL container concept, this adaptor only implements
@@ -968,22 +1038,23 @@ class NativeArray {
typedef Element* iterator;
typedef const Element* const_iterator;
- // Constructs from a native array.
- NativeArray(const Element* array, size_t count, RelationToSource relation) {
- Init(array, count, relation);
+ // Constructs from a native array. References the source.
+ NativeArray(const Element* array, size_t count, RelationToSourceReference) {
+ InitRef(array, count);
+ }
+
+ // Constructs from a native array. Copies the source.
+ NativeArray(const Element* array, size_t count, RelationToSourceCopy) {
+ InitCopy(array, count);
}
// Copy constructor.
NativeArray(const NativeArray& rhs) {
- Init(rhs.array_, rhs.size_, rhs.relation_to_source_);
+ (this->*rhs.clone_)(rhs.array_, rhs.size_);
}
~NativeArray() {
- // Ensures that the user doesn't instantiate NativeArray with a
- // const or reference type.
- static_cast<void>(StaticAssertTypeEqHelper<Element,
- GTEST_REMOVE_REFERENCE_AND_CONST_(Element)>());
- if (relation_to_source_ == kCopy)
+ if (clone_ != &NativeArray::InitRef)
delete[] array_;
}
@@ -997,23 +1068,30 @@ class NativeArray {
}
private:
- // Initializes this object; makes a copy of the input array if
- // 'relation' is kCopy.
- void Init(const Element* array, size_t a_size, RelationToSource relation) {
- if (relation == kReference) {
- array_ = array;
- } else {
- Element* const copy = new Element[a_size];
- CopyArray(array, a_size, copy);
- array_ = copy;
- }
+ enum {
+ kCheckTypeIsNotConstOrAReference = StaticAssertTypeEqHelper<
+ Element, GTEST_REMOVE_REFERENCE_AND_CONST_(Element)>::value,
+ };
+
+ // Initializes this object with a copy of the input.
+ void InitCopy(const Element* array, size_t a_size) {
+ Element* const copy = new Element[a_size];
+ CopyArray(array, a_size, copy);
+ array_ = copy;
size_ = a_size;
- relation_to_source_ = relation;
+ clone_ = &NativeArray::InitCopy;
+ }
+
+ // Initializes this object with a reference of the input.
+ void InitRef(const Element* array, size_t a_size) {
+ array_ = array;
+ size_ = a_size;
+ clone_ = &NativeArray::InitRef;
}
const Element* array_;
size_t size_;
- RelationToSource relation_to_source_;
+ void (NativeArray::*clone_)(const Element*, size_t);
GTEST_DISALLOW_ASSIGN_(NativeArray);
};
@@ -1148,6 +1226,7 @@ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\
::test_info_ =\
::testing::internal::MakeAndRegisterTestInfo(\
#test_case_name, #test_name, NULL, NULL, \
+ ::testing::internal::CodeLocation(__FILE__, __LINE__), \
(parent_id), \
parent_class::SetUpTestCase, \
parent_class::TearDownTestCase, \
@@ -1156,3 +1235,4 @@ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\
void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
+
diff --git a/extern/gtest/include/gtest/internal/gtest-linked_ptr.h b/extern/gtest/include/gtest/internal/gtest-linked_ptr.h
index b1362cd002c..36029422174 100644
--- a/extern/gtest/include/gtest/internal/gtest-linked_ptr.h
+++ b/extern/gtest/include/gtest/internal/gtest-linked_ptr.h
@@ -110,7 +110,12 @@ class linked_ptr_internal {
MutexLock lock(&g_linked_ptr_mutex);
linked_ptr_internal const* p = ptr;
- while (p->next_ != ptr) p = p->next_;
+ while (p->next_ != ptr) {
+ assert(p->next_ != this &&
+ "Trying to join() a linked ring we are already in. "
+ "Is GMock thread safety enabled?");
+ p = p->next_;
+ }
p->next_ = this;
next_ = ptr;
}
@@ -123,7 +128,12 @@ class linked_ptr_internal {
if (next_ == this) return true;
linked_ptr_internal const* p = next_;
- while (p->next_ != this) p = p->next_;
+ while (p->next_ != this) {
+ assert(p->next_ != next_ &&
+ "Trying to depart() a linked ring we are not in. "
+ "Is GMock thread safety enabled?");
+ p = p->next_;
+ }
p->next_ = next_;
return false;
}
diff --git a/extern/gtest/include/gtest/internal/gtest-param-util-generated.h b/extern/gtest/include/gtest/internal/gtest-param-util-generated.h
index e80548592c7..4d1d81d20ff 100644
--- a/extern/gtest/include/gtest/internal/gtest-param-util-generated.h
+++ b/extern/gtest/include/gtest/internal/gtest-param-util-generated.h
@@ -40,7 +40,7 @@
// and at most 10 arguments in Combine. Please contact
// googletestframework@googlegroups.com if you need more.
// Please note that the number of arguments to Combine is limited
-// by the maximum arity of the implementation of tr1::tuple which is
+// by the maximum arity of the implementation of tuple which is
// currently set at 10.
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
@@ -79,7 +79,10 @@ class ValueArray1 {
explicit ValueArray1(T1 v1) : v1_(v1) {}
template <typename T>
- operator ParamGenerator<T>() const { return ValuesIn(&v1_, &v1_ + 1); }
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_)};
+ return ValuesIn(array);
+ }
private:
// No implementation - assignment is unsupported.
@@ -3157,9 +3160,9 @@ class ValueArray50 {
//
template <typename T1, typename T2>
class CartesianProductGenerator2
- : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2> > {
+ : public ParamGeneratorInterface< ::testing::tuple<T1, T2> > {
public:
- typedef ::std::tr1::tuple<T1, T2> ParamType;
+ typedef ::testing::tuple<T1, T2> ParamType;
CartesianProductGenerator2(const ParamGenerator<T1>& g1,
const ParamGenerator<T2>& g2)
@@ -3272,9 +3275,9 @@ class CartesianProductGenerator2
template <typename T1, typename T2, typename T3>
class CartesianProductGenerator3
- : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3> > {
+ : public ParamGeneratorInterface< ::testing::tuple<T1, T2, T3> > {
public:
- typedef ::std::tr1::tuple<T1, T2, T3> ParamType;
+ typedef ::testing::tuple<T1, T2, T3> ParamType;
CartesianProductGenerator3(const ParamGenerator<T1>& g1,
const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3)
@@ -3404,9 +3407,9 @@ class CartesianProductGenerator3
template <typename T1, typename T2, typename T3, typename T4>
class CartesianProductGenerator4
- : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4> > {
+ : public ParamGeneratorInterface< ::testing::tuple<T1, T2, T3, T4> > {
public:
- typedef ::std::tr1::tuple<T1, T2, T3, T4> ParamType;
+ typedef ::testing::tuple<T1, T2, T3, T4> ParamType;
CartesianProductGenerator4(const ParamGenerator<T1>& g1,
const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
@@ -3555,9 +3558,9 @@ class CartesianProductGenerator4
template <typename T1, typename T2, typename T3, typename T4, typename T5>
class CartesianProductGenerator5
- : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5> > {
+ : public ParamGeneratorInterface< ::testing::tuple<T1, T2, T3, T4, T5> > {
public:
- typedef ::std::tr1::tuple<T1, T2, T3, T4, T5> ParamType;
+ typedef ::testing::tuple<T1, T2, T3, T4, T5> ParamType;
CartesianProductGenerator5(const ParamGenerator<T1>& g1,
const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
@@ -3723,10 +3726,10 @@ class CartesianProductGenerator5
template <typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6>
class CartesianProductGenerator6
- : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5,
+ : public ParamGeneratorInterface< ::testing::tuple<T1, T2, T3, T4, T5,
T6> > {
public:
- typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> ParamType;
+ typedef ::testing::tuple<T1, T2, T3, T4, T5, T6> ParamType;
CartesianProductGenerator6(const ParamGenerator<T1>& g1,
const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
@@ -3909,10 +3912,10 @@ class CartesianProductGenerator6
template <typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6, typename T7>
class CartesianProductGenerator7
- : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+ : public ParamGeneratorInterface< ::testing::tuple<T1, T2, T3, T4, T5, T6,
T7> > {
public:
- typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7> ParamType;
+ typedef ::testing::tuple<T1, T2, T3, T4, T5, T6, T7> ParamType;
CartesianProductGenerator7(const ParamGenerator<T1>& g1,
const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
@@ -4112,10 +4115,10 @@ class CartesianProductGenerator7
template <typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6, typename T7, typename T8>
class CartesianProductGenerator8
- : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+ : public ParamGeneratorInterface< ::testing::tuple<T1, T2, T3, T4, T5, T6,
T7, T8> > {
public:
- typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8> ParamType;
+ typedef ::testing::tuple<T1, T2, T3, T4, T5, T6, T7, T8> ParamType;
CartesianProductGenerator8(const ParamGenerator<T1>& g1,
const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
@@ -4334,10 +4337,10 @@ class CartesianProductGenerator8
template <typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6, typename T7, typename T8, typename T9>
class CartesianProductGenerator9
- : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+ : public ParamGeneratorInterface< ::testing::tuple<T1, T2, T3, T4, T5, T6,
T7, T8, T9> > {
public:
- typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9> ParamType;
+ typedef ::testing::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9> ParamType;
CartesianProductGenerator9(const ParamGenerator<T1>& g1,
const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
@@ -4573,10 +4576,10 @@ class CartesianProductGenerator9
template <typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6, typename T7, typename T8, typename T9, typename T10>
class CartesianProductGenerator10
- : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+ : public ParamGeneratorInterface< ::testing::tuple<T1, T2, T3, T4, T5, T6,
T7, T8, T9, T10> > {
public:
- typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> ParamType;
+ typedef ::testing::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> ParamType;
CartesianProductGenerator10(const ParamGenerator<T1>& g1,
const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
@@ -4838,8 +4841,8 @@ class CartesianProductHolder2 {
CartesianProductHolder2(const Generator1& g1, const Generator2& g2)
: g1_(g1), g2_(g2) {}
template <typename T1, typename T2>
- operator ParamGenerator< ::std::tr1::tuple<T1, T2> >() const {
- return ParamGenerator< ::std::tr1::tuple<T1, T2> >(
+ operator ParamGenerator< ::testing::tuple<T1, T2> >() const {
+ return ParamGenerator< ::testing::tuple<T1, T2> >(
new CartesianProductGenerator2<T1, T2>(
static_cast<ParamGenerator<T1> >(g1_),
static_cast<ParamGenerator<T2> >(g2_)));
@@ -4860,8 +4863,8 @@ CartesianProductHolder3(const Generator1& g1, const Generator2& g2,
const Generator3& g3)
: g1_(g1), g2_(g2), g3_(g3) {}
template <typename T1, typename T2, typename T3>
- operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3> >() const {
- return ParamGenerator< ::std::tr1::tuple<T1, T2, T3> >(
+ operator ParamGenerator< ::testing::tuple<T1, T2, T3> >() const {
+ return ParamGenerator< ::testing::tuple<T1, T2, T3> >(
new CartesianProductGenerator3<T1, T2, T3>(
static_cast<ParamGenerator<T1> >(g1_),
static_cast<ParamGenerator<T2> >(g2_),
@@ -4885,8 +4888,8 @@ CartesianProductHolder4(const Generator1& g1, const Generator2& g2,
const Generator3& g3, const Generator4& g4)
: g1_(g1), g2_(g2), g3_(g3), g4_(g4) {}
template <typename T1, typename T2, typename T3, typename T4>
- operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4> >() const {
- return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4> >(
+ operator ParamGenerator< ::testing::tuple<T1, T2, T3, T4> >() const {
+ return ParamGenerator< ::testing::tuple<T1, T2, T3, T4> >(
new CartesianProductGenerator4<T1, T2, T3, T4>(
static_cast<ParamGenerator<T1> >(g1_),
static_cast<ParamGenerator<T2> >(g2_),
@@ -4912,8 +4915,8 @@ CartesianProductHolder5(const Generator1& g1, const Generator2& g2,
const Generator3& g3, const Generator4& g4, const Generator5& g5)
: g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {}
template <typename T1, typename T2, typename T3, typename T4, typename T5>
- operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5> >() const {
- return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5> >(
+ operator ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5> >() const {
+ return ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5> >(
new CartesianProductGenerator5<T1, T2, T3, T4, T5>(
static_cast<ParamGenerator<T1> >(g1_),
static_cast<ParamGenerator<T2> >(g2_),
@@ -4943,8 +4946,8 @@ CartesianProductHolder6(const Generator1& g1, const Generator2& g2,
: g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {}
template <typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6>
- operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> >() const {
- return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> >(
+ operator ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5, T6> >() const {
+ return ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5, T6> >(
new CartesianProductGenerator6<T1, T2, T3, T4, T5, T6>(
static_cast<ParamGenerator<T1> >(g1_),
static_cast<ParamGenerator<T2> >(g2_),
@@ -4976,9 +4979,9 @@ CartesianProductHolder7(const Generator1& g1, const Generator2& g2,
: g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {}
template <typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6, typename T7>
- operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+ operator ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5, T6,
T7> >() const {
- return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7> >(
+ return ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5, T6, T7> >(
new CartesianProductGenerator7<T1, T2, T3, T4, T5, T6, T7>(
static_cast<ParamGenerator<T1> >(g1_),
static_cast<ParamGenerator<T2> >(g2_),
@@ -5014,9 +5017,9 @@ CartesianProductHolder8(const Generator1& g1, const Generator2& g2,
g8_(g8) {}
template <typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6, typename T7, typename T8>
- operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7,
+ operator ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5, T6, T7,
T8> >() const {
- return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8> >(
+ return ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5, T6, T7, T8> >(
new CartesianProductGenerator8<T1, T2, T3, T4, T5, T6, T7, T8>(
static_cast<ParamGenerator<T1> >(g1_),
static_cast<ParamGenerator<T2> >(g2_),
@@ -5055,9 +5058,9 @@ CartesianProductHolder9(const Generator1& g1, const Generator2& g2,
g9_(g9) {}
template <typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6, typename T7, typename T8, typename T9>
- operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+ operator ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
T9> >() const {
- return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+ return ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
T9> >(
new CartesianProductGenerator9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(
static_cast<ParamGenerator<T1> >(g1_),
@@ -5099,10 +5102,10 @@ CartesianProductHolder10(const Generator1& g1, const Generator2& g2,
g9_(g9), g10_(g10) {}
template <typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6, typename T7, typename T8, typename T9, typename T10>
- operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
- T9, T10> >() const {
- return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
- T9, T10> >(
+ operator ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9,
+ T10> >() const {
+ return ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9,
+ T10> >(
new CartesianProductGenerator10<T1, T2, T3, T4, T5, T6, T7, T8, T9,
T10>(
static_cast<ParamGenerator<T1> >(g1_),
diff --git a/extern/gtest/include/gtest/internal/gtest-param-util.h b/extern/gtest/include/gtest/internal/gtest-param-util.h
index d5e1028b0c1..82cab9b0201 100644
--- a/extern/gtest/include/gtest/internal/gtest-param-util.h
+++ b/extern/gtest/include/gtest/internal/gtest-param-util.h
@@ -34,7 +34,10 @@
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
+#include <ctype.h>
+
#include <iterator>
+#include <set>
#include <utility>
#include <vector>
@@ -49,6 +52,27 @@
#if GTEST_HAS_PARAM_TEST
namespace testing {
+
+// Input to a parameterized test name generator, describing a test parameter.
+// Consists of the parameter value and the integer parameter index.
+template <class ParamType>
+struct TestParamInfo {
+ TestParamInfo(const ParamType& a_param, size_t an_index) :
+ param(a_param),
+ index(an_index) {}
+ ParamType param;
+ size_t index;
+};
+
+// A builtin parameterized test name generator which returns the result of
+// testing::PrintToString.
+struct PrintToStringParamName {
+ template <class ParamType>
+ std::string operator()(const TestParamInfo<ParamType>& info) const {
+ return PrintToString(info.param);
+ }
+};
+
namespace internal {
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
@@ -58,7 +82,7 @@ namespace internal {
// TEST_P macro is used to define two tests with the same name
// but in different namespaces.
GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name,
- const char* file, int line);
+ CodeLocation code_location);
template <typename> class ParamGeneratorInterface;
template <typename> class ParamGenerator;
@@ -206,7 +230,7 @@ class RangeGenerator : public ParamGeneratorInterface<T> {
return base_;
}
virtual void Advance() {
- value_ = value_ + step_;
+ value_ = static_cast<T>(value_ + step_);
index_++;
}
virtual ParamIteratorInterface<T>* Clone() const {
@@ -243,7 +267,7 @@ class RangeGenerator : public ParamGeneratorInterface<T> {
const T& end,
const IncrementT& step) {
int end_index = 0;
- for (T i = begin; i < end; i = i + step)
+ for (T i = begin; i < end; i = static_cast<T>(i + step))
end_index++;
return end_index;
}
@@ -347,6 +371,37 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> {
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
//
+// Default parameterized test name generator, returns a string containing the
+// integer test parameter index.
+template <class ParamType>
+std::string DefaultParamName(const TestParamInfo<ParamType>& info) {
+ Message name_stream;
+ name_stream << info.index;
+ return name_stream.GetString();
+}
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Parameterized test name overload helpers, which help the
+// INSTANTIATE_TEST_CASE_P macro choose between the default parameterized
+// test name generator and user param name generator.
+template <class ParamType, class ParamNameGenFunctor>
+ParamNameGenFunctor GetParamNameGen(ParamNameGenFunctor func) {
+ return func;
+}
+
+template <class ParamType>
+struct ParamNameGenFunc {
+ typedef std::string Type(const TestParamInfo<ParamType>&);
+};
+
+template <class ParamType>
+typename ParamNameGenFunc<ParamType>::Type *GetParamNameGen() {
+ return DefaultParamName;
+}
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
// Stores a parameter value and later creates tests parameterized with that
// value.
template <class TestClass>
@@ -449,9 +504,11 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
typedef typename TestCase::ParamType ParamType;
// A function that returns an instance of appropriate generator type.
typedef ParamGenerator<ParamType>(GeneratorCreationFunc)();
+ typedef typename ParamNameGenFunc<ParamType>::Type ParamNameGeneratorFunc;
- explicit ParameterizedTestCaseInfo(const char* name)
- : test_case_name_(name) {}
+ explicit ParameterizedTestCaseInfo(
+ const char* name, CodeLocation code_location)
+ : test_case_name_(name), code_location_(code_location) {}
// Test case base name for display purposes.
virtual const string& GetTestCaseName() const { return test_case_name_; }
@@ -474,9 +531,11 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
// about a generator.
int AddTestCaseInstantiation(const string& instantiation_name,
GeneratorCreationFunc* func,
- const char* /* file */,
- int /* line */) {
- instantiations_.push_back(::std::make_pair(instantiation_name, func));
+ ParamNameGeneratorFunc* name_func,
+ const char* file,
+ int line) {
+ instantiations_.push_back(
+ InstantiationInfo(instantiation_name, func, name_func, file, line));
return 0; // Return value used only to run this method in namespace scope.
}
// UnitTest class invokes this method to register tests in this test case
@@ -491,25 +550,45 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
for (typename InstantiationContainer::iterator gen_it =
instantiations_.begin(); gen_it != instantiations_.end();
++gen_it) {
- const string& instantiation_name = gen_it->first;
- ParamGenerator<ParamType> generator((*gen_it->second)());
+ const string& instantiation_name = gen_it->name;
+ ParamGenerator<ParamType> generator((*gen_it->generator)());
+ ParamNameGeneratorFunc* name_func = gen_it->name_func;
+ const char* file = gen_it->file;
+ int line = gen_it->line;
string test_case_name;
if ( !instantiation_name.empty() )
test_case_name = instantiation_name + "/";
test_case_name += test_info->test_case_base_name;
- int i = 0;
+ size_t i = 0;
+ std::set<std::string> test_param_names;
for (typename ParamGenerator<ParamType>::iterator param_it =
generator.begin();
param_it != generator.end(); ++param_it, ++i) {
Message test_name_stream;
- test_name_stream << test_info->test_base_name << "/" << i;
+
+ std::string param_name = name_func(
+ TestParamInfo<ParamType>(*param_it, i));
+
+ GTEST_CHECK_(IsValidParamName(param_name))
+ << "Parameterized test name '" << param_name
+ << "' is invalid, in " << file
+ << " line " << line << std::endl;
+
+ GTEST_CHECK_(test_param_names.count(param_name) == 0)
+ << "Duplicate parameterized test name '" << param_name
+ << "', in " << file << " line " << line << std::endl;
+
+ test_param_names.insert(param_name);
+
+ test_name_stream << test_info->test_base_name << "/" << param_name;
MakeAndRegisterTestInfo(
test_case_name.c_str(),
test_name_stream.GetString().c_str(),
NULL, // No type parameter.
PrintToString(*param_it).c_str(),
+ code_location_,
GetTestCaseTypeId(),
TestCase::SetUpTestCase,
TestCase::TearDownTestCase,
@@ -535,12 +614,45 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
const scoped_ptr<TestMetaFactoryBase<ParamType> > test_meta_factory;
};
typedef ::std::vector<linked_ptr<TestInfo> > TestInfoContainer;
- // Keeps pairs of <Instantiation name, Sequence generator creation function>
- // received from INSTANTIATE_TEST_CASE_P macros.
- typedef ::std::vector<std::pair<string, GeneratorCreationFunc*> >
- InstantiationContainer;
+ // Records data received from INSTANTIATE_TEST_CASE_P macros:
+ // <Instantiation name, Sequence generator creation function,
+ // Name generator function, Source file, Source line>
+ struct InstantiationInfo {
+ InstantiationInfo(const std::string &name_in,
+ GeneratorCreationFunc* generator_in,
+ ParamNameGeneratorFunc* name_func_in,
+ const char* file_in,
+ int line_in)
+ : name(name_in),
+ generator(generator_in),
+ name_func(name_func_in),
+ file(file_in),
+ line(line_in) {}
+
+ std::string name;
+ GeneratorCreationFunc* generator;
+ ParamNameGeneratorFunc* name_func;
+ const char* file;
+ int line;
+ };
+ typedef ::std::vector<InstantiationInfo> InstantiationContainer;
+
+ static bool IsValidParamName(const std::string& name) {
+ // Check for empty string
+ if (name.empty())
+ return false;
+
+ // Check for invalid characters
+ for (std::string::size_type index = 0; index < name.size(); ++index) {
+ if (!isalnum(name[index]) && name[index] != '_')
+ return false;
+ }
+
+ return true;
+ }
const string test_case_name_;
+ CodeLocation code_location_;
TestInfoContainer tests_;
InstantiationContainer instantiations_;
@@ -568,8 +680,7 @@ class ParameterizedTestCaseRegistry {
template <class TestCase>
ParameterizedTestCaseInfo<TestCase>* GetTestCasePatternHolder(
const char* test_case_name,
- const char* file,
- int line) {
+ CodeLocation code_location) {
ParameterizedTestCaseInfo<TestCase>* typed_test_info = NULL;
for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
it != test_case_infos_.end(); ++it) {
@@ -578,7 +689,7 @@ class ParameterizedTestCaseRegistry {
// Complain about incorrect usage of Google Test facilities
// and terminate the program since we cannot guaranty correct
// test case setup and tear-down in this case.
- ReportInvalidTestCaseType(test_case_name, file, line);
+ ReportInvalidTestCaseType(test_case_name, code_location);
posix::Abort();
} else {
// At this point we are sure that the object we found is of the same
@@ -591,7 +702,8 @@ class ParameterizedTestCaseRegistry {
}
}
if (typed_test_info == NULL) {
- typed_test_info = new ParameterizedTestCaseInfo<TestCase>(test_case_name);
+ typed_test_info = new ParameterizedTestCaseInfo<TestCase>(
+ test_case_name, code_location);
test_case_infos_.push_back(typed_test_info);
}
return typed_test_info;
diff --git a/extern/gtest/include/gtest/internal/gtest-port-arch.h b/extern/gtest/include/gtest/internal/gtest-port-arch.h
new file mode 100644
index 00000000000..74ab949057c
--- /dev/null
+++ b/extern/gtest/include/gtest/internal/gtest-port-arch.h
@@ -0,0 +1,93 @@
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines the GTEST_OS_* macro.
+// It is separate from gtest-port.h so that custom/gtest-port.h can include it.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_
+
+// Determines the platform on which Google Test is compiled.
+#ifdef __CYGWIN__
+# define GTEST_OS_CYGWIN 1
+#elif defined __SYMBIAN32__
+# define GTEST_OS_SYMBIAN 1
+#elif defined _WIN32
+# define GTEST_OS_WINDOWS 1
+# ifdef _WIN32_WCE
+# define GTEST_OS_WINDOWS_MOBILE 1
+# elif defined(__MINGW__) || defined(__MINGW32__)
+# define GTEST_OS_WINDOWS_MINGW 1
+# elif defined(WINAPI_FAMILY)
+# include <winapifamily.h>
+# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+# define GTEST_OS_WINDOWS_DESKTOP 1
+# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
+# define GTEST_OS_WINDOWS_PHONE 1
+# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
+# define GTEST_OS_WINDOWS_RT 1
+# else
+ // WINAPI_FAMILY defined but no known partition matched.
+ // Default to desktop.
+# define GTEST_OS_WINDOWS_DESKTOP 1
+# endif
+# else
+# define GTEST_OS_WINDOWS_DESKTOP 1
+# endif // _WIN32_WCE
+#elif defined __APPLE__
+# define GTEST_OS_MAC 1
+# if TARGET_OS_IPHONE
+# define GTEST_OS_IOS 1
+# endif
+#elif defined __FreeBSD__
+# define GTEST_OS_FREEBSD 1
+#elif defined __linux__
+# define GTEST_OS_LINUX 1
+# if defined __ANDROID__
+# define GTEST_OS_LINUX_ANDROID 1
+# endif
+#elif defined __MVS__
+# define GTEST_OS_ZOS 1
+#elif defined(__sun) && defined(__SVR4)
+# define GTEST_OS_SOLARIS 1
+#elif defined(_AIX)
+# define GTEST_OS_AIX 1
+#elif defined(__hpux)
+# define GTEST_OS_HPUX 1
+#elif defined __native_client__
+# define GTEST_OS_NACL 1
+#elif defined __OpenBSD__
+# define GTEST_OS_OPENBSD 1
+#elif defined __QNX__
+# define GTEST_OS_QNX 1
+#endif // __CYGWIN__
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_
diff --git a/extern/gtest/include/gtest/internal/gtest-port.h b/extern/gtest/include/gtest/internal/gtest-port.h
index 5ff2c29ad43..ad2a43df17d 100644
--- a/extern/gtest/include/gtest/internal/gtest-port.h
+++ b/extern/gtest/include/gtest/internal/gtest-port.h
@@ -30,8 +30,11 @@
// Authors: wan@google.com (Zhanyong Wan)
//
// Low-level types and utilities for porting Google Test to various
-// platforms. They are subject to change without notice. DO NOT USE
-// THEM IN USER CODE.
+// platforms. All macros ending with _ and symbols defined in an
+// internal namespace are subject to change without notice. Code
+// outside Google Test MUST NOT USE THEM DIRECTLY. Macros that don't
+// end with _ are part of Google Test's public API and can be used by
+// code outside Google Test.
//
// This file is fundamental to Google Test. All other Google Test source
// files are expected to #include this. Therefore, it cannot #include
@@ -40,9 +43,30 @@
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
-// The user can define the following macros in the build script to
-// control Google Test's behavior. If the user doesn't define a macro
-// in this list, Google Test will define it.
+// Environment-describing macros
+// -----------------------------
+//
+// Google Test can be used in many different environments. Macros in
+// this section tell Google Test what kind of environment it is being
+// used in, such that Google Test can provide environment-specific
+// features and implementations.
+//
+// Google Test tries to automatically detect the properties of its
+// environment, so users usually don't need to worry about these
+// macros. However, the automatic detection is not perfect.
+// Sometimes it's necessary for a user to define some of the following
+// macros in the build script to override Google Test's decisions.
+//
+// If the user doesn't define a macro in the list, Google Test will
+// provide a default definition. After this header is #included, all
+// macros in this list will be defined to either 1 or 0.
+//
+// Notes to maintainers:
+// - Each macro here is a user-tweakable knob; do not grow the list
+// lightly.
+// - Use #if to key off these macros. Don't use #ifdef or "#if
+// defined(...)", which will not work as these macros are ALWAYS
+// defined.
//
// GTEST_HAS_CLONE - Define it to 1/0 to indicate that clone(2)
// is/isn't available.
@@ -86,18 +110,23 @@
// - Define to 1 when compiling Google Test itself
// as a shared library.
-// This header defines the following utilities:
+// Platform-indicating macros
+// --------------------------
+//
+// Macros indicating the platform on which Google Test is being used
+// (a macro is defined to 1 if compiled on the given platform;
+// otherwise UNDEFINED -- it's never defined to 0.). Google Test
+// defines these macros automatically. Code outside Google Test MUST
+// NOT define them.
//
-// Macros indicating the current platform (defined to 1 if compiled on
-// the given platform; otherwise undefined):
// GTEST_OS_AIX - IBM AIX
// GTEST_OS_CYGWIN - Cygwin
+// GTEST_OS_FREEBSD - FreeBSD
// GTEST_OS_HPUX - HP-UX
// GTEST_OS_LINUX - Linux
// GTEST_OS_LINUX_ANDROID - Google Android
// GTEST_OS_MAC - Mac OS X
// GTEST_OS_IOS - iOS
-// GTEST_OS_IOS_SIMULATOR - iOS simulator
// GTEST_OS_NACL - Google Native Client (NaCl)
// GTEST_OS_OPENBSD - OpenBSD
// GTEST_OS_QNX - QNX
@@ -107,6 +136,8 @@
// GTEST_OS_WINDOWS_DESKTOP - Windows Desktop
// GTEST_OS_WINDOWS_MINGW - MinGW
// GTEST_OS_WINDOWS_MOBILE - Windows Mobile
+// GTEST_OS_WINDOWS_PHONE - Windows Phone
+// GTEST_OS_WINDOWS_RT - Windows Store App/WinRT
// GTEST_OS_ZOS - z/OS
//
// Among the platforms, Cygwin, Linux, Max OS X, and Windows have the
@@ -116,22 +147,50 @@
// googletestframework@googlegroups.com (patches for fixing them are
// even more welcome!).
//
-// Note that it is possible that none of the GTEST_OS_* macros are defined.
+// It is possible that none of the GTEST_OS_* macros are defined.
+
+// Feature-indicating macros
+// -------------------------
+//
+// Macros indicating which Google Test features are available (a macro
+// is defined to 1 if the corresponding feature is supported;
+// otherwise UNDEFINED -- it's never defined to 0.). Google Test
+// defines these macros automatically. Code outside Google Test MUST
+// NOT define them.
+//
+// These macros are public so that portable tests can be written.
+// Such tests typically surround code using a feature with an #if
+// which controls that code. For example:
+//
+// #if GTEST_HAS_DEATH_TEST
+// EXPECT_DEATH(DoSomethingDeadly());
+// #endif
//
-// Macros indicating available Google Test features (defined to 1 if
-// the corresponding feature is supported; otherwise undefined):
// GTEST_HAS_COMBINE - the Combine() function (for value-parameterized
// tests)
// GTEST_HAS_DEATH_TEST - death tests
// GTEST_HAS_PARAM_TEST - value-parameterized tests
// GTEST_HAS_TYPED_TEST - typed tests
// GTEST_HAS_TYPED_TEST_P - type-parameterized tests
+// GTEST_IS_THREADSAFE - Google Test is thread-safe.
// GTEST_USES_POSIX_RE - enhanced POSIX regex is used. Do not confuse with
// GTEST_HAS_POSIX_RE (see above) which users can
// define themselves.
// GTEST_USES_SIMPLE_RE - our own simple regex is used;
// the above two are mutually exclusive.
// GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ().
+
+// Misc public macros
+// ------------------
+//
+// GTEST_FLAG(flag_name) - references the variable corresponding to
+// the given Google Test flag.
+
+// Internal utilities
+// ------------------
+//
+// The following macros and utilities are for Google Test's INTERNAL
+// use only. Code outside Google Test MUST NOT USE THEM DIRECTLY.
//
// Macros for basic C++ coding:
// GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning.
@@ -140,13 +199,18 @@
// GTEST_DISALLOW_ASSIGN_ - disables operator=.
// GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=.
// GTEST_MUST_USE_RESULT_ - declares that a function's result must be used.
+// GTEST_INTENTIONAL_CONST_COND_PUSH_ - start code section where MSVC C4127 is
+// suppressed (constant conditional).
+// GTEST_INTENTIONAL_CONST_COND_POP_ - finish code section where MSVC C4127
+// is suppressed.
+//
+// C++11 feature wrappers:
+//
+// testing::internal::move - portability wrapper for std::move.
//
// Synchronization:
// Mutex, MutexLock, ThreadLocal, GetThreadCount()
-// - synchronization primitives.
-// GTEST_IS_THREADSAFE - defined to 1 to indicate that the above
-// synchronization primitives have real implementations
-// and Google Test is thread-safe; or 0 otherwise.
+// - synchronization primitives.
//
// Template meta programming:
// is_pointer - as in TR1; needed on Symbian and IBM XL C/C++ only.
@@ -182,7 +246,6 @@
// BiggestInt - the biggest signed integer type.
//
// Command-line utilities:
-// GTEST_FLAG() - references a flag.
// GTEST_DECLARE_*() - declares a flag.
// GTEST_DEFINE_*() - defines a flag.
// GetInjectableArgvs() - returns the command line as a vector of strings.
@@ -208,16 +271,28 @@
# include <TargetConditionals.h>
#endif
+#include <algorithm> // NOLINT
#include <iostream> // NOLINT
#include <sstream> // NOLINT
#include <string> // NOLINT
+#include <utility>
+#include <vector> // NOLINT
-#define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com"
-#define GTEST_FLAG_PREFIX_ "gtest_"
-#define GTEST_FLAG_PREFIX_DASH_ "gtest-"
-#define GTEST_FLAG_PREFIX_UPPER_ "GTEST_"
-#define GTEST_NAME_ "Google Test"
-#define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/"
+#include "gtest/internal/gtest-port-arch.h"
+#include "gtest/internal/custom/gtest-port.h"
+
+#if !defined(GTEST_DEV_EMAIL_)
+# define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com"
+# define GTEST_FLAG_PREFIX_ "gtest_"
+# define GTEST_FLAG_PREFIX_DASH_ "gtest-"
+# define GTEST_FLAG_PREFIX_UPPER_ "GTEST_"
+# define GTEST_NAME_ "Google Test"
+# define GTEST_PROJECT_URL_ "https://github.com/google/googletest/"
+#endif // !defined(GTEST_DEV_EMAIL_)
+
+#if !defined(GTEST_INIT_GOOGLE_TEST_NAME_)
+# define GTEST_INIT_GOOGLE_TEST_NAME_ "testing::InitGoogleTest"
+#endif // !defined(GTEST_INIT_GOOGLE_TEST_NAME_)
// Determines the version of gcc that is used to compile this.
#ifdef __GNUC__
@@ -226,48 +301,22 @@
(__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__)
#endif // __GNUC__
-// Determines the platform on which Google Test is compiled.
-#ifdef __CYGWIN__
-# define GTEST_OS_CYGWIN 1
-#elif defined __SYMBIAN32__
-# define GTEST_OS_SYMBIAN 1
-#elif defined _WIN32
-# define GTEST_OS_WINDOWS 1
-# ifdef _WIN32_WCE
-# define GTEST_OS_WINDOWS_MOBILE 1
-# elif defined(__MINGW__) || defined(__MINGW32__)
-# define GTEST_OS_WINDOWS_MINGW 1
-# else
-# define GTEST_OS_WINDOWS_DESKTOP 1
-# endif // _WIN32_WCE
-#elif defined __APPLE__
-# define GTEST_OS_MAC 1
-# if TARGET_OS_IPHONE
-# define GTEST_OS_IOS 1
-# if TARGET_IPHONE_SIMULATOR
-# define GTEST_OS_IOS_SIMULATOR 1
-# endif
-# endif
-#elif defined __linux__
-# define GTEST_OS_LINUX 1
-# if defined __ANDROID__
-# define GTEST_OS_LINUX_ANDROID 1
-# endif
-#elif defined __MVS__
-# define GTEST_OS_ZOS 1
-#elif defined(__sun) && defined(__SVR4)
-# define GTEST_OS_SOLARIS 1
-#elif defined(_AIX)
-# define GTEST_OS_AIX 1
-#elif defined(__hpux)
-# define GTEST_OS_HPUX 1
-#elif defined __native_client__
-# define GTEST_OS_NACL 1
-#elif defined __OpenBSD__
-# define GTEST_OS_OPENBSD 1
-#elif defined __QNX__
-# define GTEST_OS_QNX 1
-#endif // __CYGWIN__
+// Macros for disabling Microsoft Visual C++ warnings.
+//
+// GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 4385)
+// /* code that triggers warnings C4800 and C4385 */
+// GTEST_DISABLE_MSC_WARNINGS_POP_()
+#if defined(_MSC_VER) && _MSC_VER >= 1500
+# define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) \
+ __pragma(warning(push)) \
+ __pragma(warning(disable: warnings))
+# define GTEST_DISABLE_MSC_WARNINGS_POP_() \
+ __pragma(warning(pop))
+#else
+// Older versions of MSVC don't have __pragma.
+# define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings)
+# define GTEST_DISABLE_MSC_WARNINGS_POP_()
+#endif
#ifndef GTEST_LANG_CXX11
// gcc and clang define __GXX_EXPERIMENTAL_CXX0X__ when
@@ -282,12 +331,77 @@
# endif
#endif
+// Distinct from C++11 language support, some environments don't provide
+// proper C++11 library support. Notably, it's possible to build in
+// C++11 mode when targeting Mac OS X 10.6, which has an old libstdc++
+// with no C++11 support.
+//
+// libstdc++ has sufficient C++11 support as of GCC 4.6.0, __GLIBCXX__
+// 20110325, but maintenance releases in the 4.4 and 4.5 series followed
+// this date, so check for those versions by their date stamps.
+// https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html#abi.versioning
+#if GTEST_LANG_CXX11 && \
+ (!defined(__GLIBCXX__) || ( \
+ __GLIBCXX__ >= 20110325ul && /* GCC >= 4.6.0 */ \
+ /* Blacklist of patch releases of older branches: */ \
+ __GLIBCXX__ != 20110416ul && /* GCC 4.4.6 */ \
+ __GLIBCXX__ != 20120313ul && /* GCC 4.4.7 */ \
+ __GLIBCXX__ != 20110428ul && /* GCC 4.5.3 */ \
+ __GLIBCXX__ != 20120702ul)) /* GCC 4.5.4 */
+# define GTEST_STDLIB_CXX11 1
+#endif
+
+// Only use C++11 library features if the library provides them.
+#if defined(GTEST_STDLIB_CXX11) && GTEST_STDLIB_CXX11
+# define GTEST_HAS_STD_BEGIN_AND_END_ 1
+# define GTEST_HAS_STD_FORWARD_LIST_ 1
+# define GTEST_HAS_STD_FUNCTION_ 1
+# define GTEST_HAS_STD_INITIALIZER_LIST_ 1
+# define GTEST_HAS_STD_MOVE_ 1
+# define GTEST_HAS_STD_SHARED_PTR_ 1
+# define GTEST_HAS_STD_TYPE_TRAITS_ 1
+# define GTEST_HAS_STD_UNIQUE_PTR_ 1
+#endif
+
+// C++11 specifies that <tuple> provides std::tuple.
+// Some platforms still might not have it, however.
+#if GTEST_LANG_CXX11
+# define GTEST_HAS_STD_TUPLE_ 1
+# if defined(__clang__)
+// Inspired by http://clang.llvm.org/docs/LanguageExtensions.html#__has_include
+# if defined(__has_include) && !__has_include(<tuple>)
+# undef GTEST_HAS_STD_TUPLE_
+# endif
+# elif defined(_MSC_VER)
+// Inspired by boost/config/stdlib/dinkumware.hpp
+# if defined(_CPPLIB_VER) && _CPPLIB_VER < 520
+# undef GTEST_HAS_STD_TUPLE_
+# endif
+# elif defined(__GLIBCXX__)
+// Inspired by boost/config/stdlib/libstdcpp3.hpp,
+// http://gcc.gnu.org/gcc-4.2/changes.html and
+// http://gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt01ch01.html#manual.intro.status.standard.200x
+# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2)
+# undef GTEST_HAS_STD_TUPLE_
+# endif
+# endif
+#endif
+
#ifndef GTEST_OS_WINDOWS
# define GTEST_OS_WINDOWS 0
#endif
+#ifndef GTEST_OS_WINDOWS_MINGW
+# define GTEST_OS_WINDOWS_MINGW 0
+#endif
+#ifndef GTEST_OS_WINDOWS_PHONE
+# define GTEST_OS_WINDOWS_PHONE 0
+#endif
#ifndef GTEST_OS_WINDOWS_MOBILE
# define GTEST_OS_WINDOWS_MOBILE 0
#endif
+#ifndef GTEST_OS_WINDOWS_RT
+# define GTEST_OS_WINDOWS_RT 0
+#endif
#ifndef GTEST_OS_LINUX_ANDROID
# define GTEST_OS_LINUX_ANDROID 0
#endif
@@ -307,16 +421,23 @@
// Brings in definitions for functions used in the testing::internal::posix
// namespace (read, write, close, chdir, isatty, stat). We do not currently
// use them on Windows Mobile.
-#if !GTEST_OS_WINDOWS
+#if GTEST_OS_WINDOWS
+# if !GTEST_OS_WINDOWS_MOBILE
+# include <direct.h>
+# include <io.h>
+# endif
+// In order to avoid having to include <windows.h>, use forward declaration
+// assuming CRITICAL_SECTION is a typedef of _RTL_CRITICAL_SECTION.
+// This assumption is verified by
+// WindowsTypesTest.CRITICAL_SECTIONIs_RTL_CRITICAL_SECTION.
+struct _RTL_CRITICAL_SECTION;
+#else
// This assumes that non-Windows OSes provide unistd.h. For OSes where this
// is not the case, we need to include headers that provide the functions
// mentioned above.
# include <unistd.h>
# include <strings.h>
-#elif !GTEST_OS_WINDOWS_MOBILE
-# include <direct.h>
-# include <io.h>
-#endif
+#endif // GTEST_OS_WINDOWS
#if GTEST_OS_LINUX_ANDROID
// Used to define __ANDROID_API__ matching the target NDK API level.
@@ -333,7 +454,10 @@
# endif
#endif
-#if GTEST_HAS_POSIX_RE
+#if defined(GTEST_USES_PCRE) && GTEST_USES_PCRE
+// The appropriate headers have already been included.
+
+#elif GTEST_HAS_POSIX_RE
// On some platforms, <regex.h> needs someone to define size_t, and
// won't compile otherwise. We can #include it here as we already
@@ -355,7 +479,7 @@
// simple regex implementation instead.
# define GTEST_USES_SIMPLE_RE 1
-#endif // GTEST_HAS_POSIX_RE
+#endif // GTEST_USES_PCRE
#ifndef GTEST_HAS_EXCEPTIONS
// The user didn't tell us whether exceptions are enabled, so we need
@@ -368,6 +492,15 @@
# define _HAS_EXCEPTIONS 1
# endif // _HAS_EXCEPTIONS
# define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS
+# elif defined(__clang__)
+// clang defines __EXCEPTIONS iff exceptions are enabled before clang 220714,
+// but iff cleanups are enabled after that. In Obj-C++ files, there can be
+// cleanups for ObjC exceptions which also need cleanups, even if C++ exceptions
+// are disabled. clang has __has_feature(cxx_exceptions) which checks for C++
+// exceptions starting at clang r206352, but which checked for cleanups prior to
+// that. To reliably check for C++ exception availability with clang, check for
+// __EXCEPTIONS && __has_feature(cxx_exceptions).
+# define GTEST_HAS_EXCEPTIONS (__EXCEPTIONS && __has_feature(cxx_exceptions))
# elif defined(__GNUC__) && __EXCEPTIONS
// gcc defines __EXCEPTIONS to 1 iff exceptions are enabled.
# define GTEST_HAS_EXCEPTIONS 1
@@ -493,13 +626,13 @@
// Determines whether Google Test can use the pthreads library.
#ifndef GTEST_HAS_PTHREAD
-// The user didn't tell us explicitly, so we assume pthreads support is
-// available on Linux and Mac.
+// The user didn't tell us explicitly, so we make reasonable assumptions about
+// which platforms have pthreads support.
//
// To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0
// to your compiler flags.
# define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX \
- || GTEST_OS_QNX)
+ || GTEST_OS_QNX || GTEST_OS_FREEBSD || GTEST_OS_NACL)
#endif // GTEST_HAS_PTHREAD
#if GTEST_HAS_PTHREAD
@@ -511,6 +644,15 @@
# include <time.h> // NOLINT
#endif
+// Determines if hash_map/hash_set are available.
+// Only used for testing against those containers.
+#if !defined(GTEST_HAS_HASH_MAP_)
+# if defined(_MSC_VER)
+# define GTEST_HAS_HASH_MAP_ 1 // Indicates that hash_map is available.
+# define GTEST_HAS_HASH_SET_ 1 // Indicates that hash_set is available.
+# endif // _MSC_VER
+#endif // !defined(GTEST_HAS_HASH_MAP_)
+
// Determines whether Google Test can use tr1/tuple. You can define
// this macro to 0 to prevent Google Test from using tuple (any
// feature depending on tuple with be disabled in this mode).
@@ -563,11 +705,21 @@
// To avoid conditional compilation everywhere, we make it
// gtest-port.h's responsibility to #include the header implementing
-// tr1/tuple.
+// tuple.
+#if defined(GTEST_HAS_STD_TUPLE_) && GTEST_HAS_STD_TUPLE_
+# include <tuple> // IWYU pragma: export
+# define GTEST_TUPLE_NAMESPACE_ ::std
+#endif // GTEST_HAS_STD_TUPLE_
+
+// We include tr1::tuple even if std::tuple is available to define printers for
+// them.
#if GTEST_HAS_TR1_TUPLE
+# ifndef GTEST_TUPLE_NAMESPACE_
+# define GTEST_TUPLE_NAMESPACE_ ::std::tr1
+# endif // GTEST_TUPLE_NAMESPACE_
# if GTEST_USE_OWN_TR1_TUPLE
-# include "gtest/internal/gtest-tuple.h"
+# include "gtest/internal/gtest-tuple.h" // IWYU pragma: export // NOLINT
# elif GTEST_ENV_HAS_STD_TUPLE_
# include <tuple>
// C++11 puts its tuple into the ::std namespace rather than
@@ -598,7 +750,7 @@ using ::std::tuple_size;
// This prevents <boost/tr1/detail/config.hpp>, which defines
// BOOST_HAS_TR1_TUPLE, from being #included by Boost's <tuple>.
# define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED
-# include <tuple>
+# include <tuple> // IWYU pragma: export // NOLINT
# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000)
// GCC 4.0+ implements tr1/tuple in the <tr1/tuple> header. This does
@@ -621,7 +773,7 @@ using ::std::tuple_size;
# else
// If the compiler is not GCC 4.0+, we assume the user is using a
// spec-conforming TR1 implementation.
-# include <tuple> // NOLINT
+# include <tuple> // IWYU pragma: export // NOLINT
# endif // GTEST_USE_OWN_TR1_TUPLE
#endif // GTEST_HAS_TR1_TUPLE
@@ -655,7 +807,8 @@ using ::std::tuple_size;
#ifndef GTEST_HAS_STREAM_REDIRECTION
// By default, we assume that stream redirection is supported on all
// platforms except known mobile ones.
-# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN
+# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || \
+ GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT
# define GTEST_HAS_STREAM_REDIRECTION 0
# else
# define GTEST_HAS_STREAM_REDIRECTION 1
@@ -667,12 +820,11 @@ using ::std::tuple_size;
// abort() in a VC 7.1 application compiled as GUI in debug config
// pops up a dialog window that cannot be suppressed programmatically.
#if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \
- (GTEST_OS_MAC && !GTEST_OS_IOS) || GTEST_OS_IOS_SIMULATOR || \
+ (GTEST_OS_MAC && !GTEST_OS_IOS) || \
(GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \
GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX || \
- GTEST_OS_OPENBSD || GTEST_OS_QNX)
+ GTEST_OS_OPENBSD || GTEST_OS_QNX || GTEST_OS_FREEBSD)
# define GTEST_HAS_DEATH_TEST 1
-# include <vector> // NOLINT
#endif
// We don't support MSVC 7.1 with exceptions disabled now. Therefore
@@ -736,7 +888,12 @@ using ::std::tuple_size;
// compiler the variable/parameter does not have to be used.
#if defined(__GNUC__) && !defined(COMPILER_ICC)
# define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused))
-#else
+#elif defined(__clang__)
+# if __has_attribute(unused)
+# define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused))
+# endif
+#endif
+#ifndef GTEST_ATTRIBUTE_UNUSED_
# define GTEST_ATTRIBUTE_UNUSED_
#endif
@@ -762,6 +919,19 @@ using ::std::tuple_size;
# define GTEST_MUST_USE_RESULT_
#endif // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC
+// MS C++ compiler emits warning when a conditional expression is compile time
+// constant. In some contexts this warning is false positive and needs to be
+// suppressed. Use the following two macros in such cases:
+//
+// GTEST_INTENTIONAL_CONST_COND_PUSH_()
+// while (true) {
+// GTEST_INTENTIONAL_CONST_COND_POP_()
+// }
+# define GTEST_INTENTIONAL_CONST_COND_PUSH_() \
+ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4127)
+# define GTEST_INTENTIONAL_CONST_COND_POP_() \
+ GTEST_DISABLE_MSC_WARNINGS_POP_()
+
// Determine whether the compiler supports Microsoft's Structured Exception
// Handling. This is supported by several Windows compilers but generally
// does not exist on any other system.
@@ -776,17 +946,22 @@ using ::std::tuple_size;
# define GTEST_HAS_SEH 0
# endif
+#define GTEST_IS_THREADSAFE \
+ ((defined(GTEST_HAS_MUTEX_AND_THREAD_LOCAL_) && GTEST_HAS_MUTEX_AND_THREAD_LOCAL_) \
+ || (GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT) \
+ || GTEST_HAS_PTHREAD)
+
#endif // GTEST_HAS_SEH
#ifdef _MSC_VER
-
# if GTEST_LINKED_AS_SHARED_LIBRARY
# define GTEST_API_ __declspec(dllimport)
# elif GTEST_CREATE_SHARED_LIBRARY
# define GTEST_API_ __declspec(dllexport)
# endif
-
-#endif // _MSC_VER
+#elif __GNUC__ >= 4 || defined(__clang__)
+# define GTEST_API_ __attribute__((visibility ("default")))
+#endif // _MSC_VER
#ifndef GTEST_API_
# define GTEST_API_
@@ -806,10 +981,58 @@ using ::std::tuple_size;
# define GTEST_HAS_CXXABI_H_ 0
#endif
+// A function level attribute to disable checking for use of uninitialized
+// memory when built with MemorySanitizer.
+#if defined(__clang__)
+# if __has_feature(memory_sanitizer)
+# define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ \
+ __attribute__((no_sanitize_memory))
+# else
+# define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
+# endif // __has_feature(memory_sanitizer)
+#else
+# define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
+#endif // __clang__
+
+// A function level attribute to disable AddressSanitizer instrumentation.
+#if defined(__clang__)
+# if __has_feature(address_sanitizer)
+# define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ \
+ __attribute__((no_sanitize_address))
+# else
+# define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+# endif // __has_feature(address_sanitizer)
+#else
+# define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+#endif // __clang__
+
+// A function level attribute to disable ThreadSanitizer instrumentation.
+#if defined(__clang__)
+# if __has_feature(thread_sanitizer)
+# define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ \
+ __attribute__((no_sanitize_thread))
+# else
+# define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
+# endif // __has_feature(thread_sanitizer)
+#else
+# define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
+#endif // __clang__
+
namespace testing {
class Message;
+#if defined(GTEST_TUPLE_NAMESPACE_)
+// Import tuple and friends into the ::testing namespace.
+// It is part of our interface, having them in ::testing allows us to change
+// their types as needed.
+using GTEST_TUPLE_NAMESPACE_::get;
+using GTEST_TUPLE_NAMESPACE_::make_tuple;
+using GTEST_TUPLE_NAMESPACE_::tuple;
+using GTEST_TUPLE_NAMESPACE_::tuple_size;
+using GTEST_TUPLE_NAMESPACE_::tuple_element;
+#endif // defined(GTEST_TUPLE_NAMESPACE_)
+
namespace internal {
// A secret type that Google Test users don't know about. It has no
@@ -821,8 +1044,8 @@ class Secret;
// expression is true. For example, you could use it to verify the
// size of a static array:
//
-// GTEST_COMPILE_ASSERT_(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES,
-// content_type_names_incorrect_size);
+// GTEST_COMPILE_ASSERT_(GTEST_ARRAY_SIZE_(names) == NUM_NAMES,
+// names_incorrect_size);
//
// or to make sure a struct is smaller than a certain size:
//
@@ -832,16 +1055,22 @@ class Secret;
// the expression is false, most compilers will issue a warning/error
// containing the name of the variable.
+#if GTEST_LANG_CXX11
+# define GTEST_COMPILE_ASSERT_(expr, msg) static_assert(expr, #msg)
+#else // !GTEST_LANG_CXX11
template <bool>
-struct CompileAssert {
+ struct CompileAssert {
};
-#define GTEST_COMPILE_ASSERT_(expr, msg) \
+# define GTEST_COMPILE_ASSERT_(expr, msg) \
typedef ::testing::internal::CompileAssert<(static_cast<bool>(expr))> \
msg[static_cast<bool>(expr) ? 1 : -1] GTEST_ATTRIBUTE_UNUSED_
+#endif // !GTEST_LANG_CXX11
// Implementation details of GTEST_COMPILE_ASSERT_:
//
+// (In C++11, we simply use static_assert instead of the following)
+//
// - GTEST_COMPILE_ASSERT_ works by defining an array type that has -1
// elements (and thus is invalid) when the expression is false.
//
@@ -888,7 +1117,12 @@ template <typename T1, typename T2>
struct StaticAssertTypeEqHelper;
template <typename T>
-struct StaticAssertTypeEqHelper<T, T> {};
+struct StaticAssertTypeEqHelper<T, T> {
+ enum { value = true };
+};
+
+// Evaluates to the number of elements in 'array'.
+#define GTEST_ARRAY_SIZE_(array) (sizeof(array) / sizeof(array[0]))
#if GTEST_HAS_GLOBAL_STRING
typedef ::string string;
@@ -937,6 +1171,11 @@ class scoped_ptr {
}
}
+ friend void swap(scoped_ptr& a, scoped_ptr& b) {
+ using std::swap;
+ swap(a.ptr_, b.ptr_);
+ }
+
private:
T* ptr_;
@@ -1060,13 +1299,18 @@ class GTEST_API_ GTestLog {
GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog);
};
-#define GTEST_LOG_(severity) \
+#if !defined(GTEST_LOG_)
+
+# define GTEST_LOG_(severity) \
::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \
__FILE__, __LINE__).GetStream()
inline void LogToStderr() {}
inline void FlushInfoLog() { fflush(NULL); }
+#endif // !defined(GTEST_LOG_)
+
+#if !defined(GTEST_CHECK_)
// INTERNAL IMPLEMENTATION - DO NOT USE.
//
// GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition
@@ -1081,12 +1325,13 @@ inline void FlushInfoLog() { fflush(NULL); }
// condition itself, plus additional message streamed into it, if any,
// and then it aborts the program. It aborts the program irrespective of
// whether it is built in the debug mode or not.
-#define GTEST_CHECK_(condition) \
+# define GTEST_CHECK_(condition) \
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
if (::testing::internal::IsTrue(condition)) \
; \
else \
GTEST_LOG_(FATAL) << "Condition " #condition " failed. "
+#endif // !defined(GTEST_CHECK_)
// An all-mode assert to verify that the given POSIX-style function
// call returns 0 (indicating success). Known limitation: this
@@ -1098,6 +1343,15 @@ inline void FlushInfoLog() { fflush(NULL); }
GTEST_LOG_(FATAL) << #posix_call << "failed with error " \
<< gtest_error
+#if defined(GTEST_HAS_STD_MOVE_) && GTEST_HAS_STD_MOVE_
+using std::move;
+#else // GTEST_HAS_STD_MOVE_
+template <typename T>
+const T& move(const T& t) {
+ return t;
+}
+#endif // GTEST_HAS_STD_MOVE_
+
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
//
// Use ImplicitCast_ as a safe version of static_cast for upcasting in
@@ -1148,7 +1402,9 @@ inline To DownCast_(From* f) { // so we only accept pointers
// for compile-time type checking, and has no overhead in an
// optimized build at run-time, as it will be optimized away
// completely.
+ GTEST_INTENTIONAL_CONST_COND_PUSH_()
if (false) {
+ GTEST_INTENTIONAL_CONST_COND_POP_()
const To to = NULL;
::testing::internal::ImplicitCast_<From*>(to);
}
@@ -1169,6 +1425,11 @@ template <class Derived, class Base>
Derived* CheckedDowncastToActualType(Base* base) {
#if GTEST_HAS_RTTI
GTEST_CHECK_(typeid(*base) == typeid(Derived));
+#endif
+
+#if defined(GTEST_HAS_DOWNCAST_) && GTEST_HAS_DOWNCAST_
+ return ::down_cast<Derived*>(base);
+#elif GTEST_HAS_RTTI
return dynamic_cast<Derived*>(base); // NOLINT
#else
return static_cast<Derived*>(base); // Poor man's downcast.
@@ -1190,6 +1451,17 @@ GTEST_API_ std::string GetCapturedStderr();
#endif // GTEST_HAS_STREAM_REDIRECTION
+// Returns a path to temporary directory.
+GTEST_API_ std::string TempDir();
+
+// Returns the size (in bytes) of a file.
+GTEST_API_ size_t GetFileSize(FILE* file);
+
+// Reads the entire content of a file as a string.
+GTEST_API_ std::string ReadEntireFile(FILE* file);
+
+// All command line arguments.
+GTEST_API_ const ::std::vector<testing::internal::string>& GetArgvs();
#if GTEST_HAS_DEATH_TEST
@@ -1197,18 +1469,15 @@ const ::std::vector<testing::internal::string>& GetInjectableArgvs();
void SetInjectableArgvs(const ::std::vector<testing::internal::string>*
new_argvs);
-// A copy of all command line arguments. Set by InitGoogleTest().
-extern ::std::vector<testing::internal::string> g_argvs;
#endif // GTEST_HAS_DEATH_TEST
// Defines synchronization primitives.
-
-#if GTEST_HAS_PTHREAD
-
-// Sleeps for (roughly) n milli-seconds. This function is only for
-// testing Google Test's own constructs. Don't use it in user tests,
-// either directly or indirectly.
+#if GTEST_IS_THREADSAFE
+# if GTEST_HAS_PTHREAD
+// Sleeps for (roughly) n milliseconds. This function is only for testing
+// Google Test's own constructs. Don't use it in user tests, either
+// directly or indirectly.
inline void SleepMilliseconds(int n) {
const timespec time = {
0, // 0 seconds.
@@ -1216,7 +1485,13 @@ inline void SleepMilliseconds(int n) {
};
nanosleep(&time, NULL);
}
+# endif // GTEST_HAS_PTHREAD
+
+# if defined(GTEST_HAS_NOTIFICATION_) && GTEST_HAS_NOTIFICATION_
+// Notification has already been imported into the namespace.
+// Nothing to do here.
+# elif GTEST_HAS_PTHREAD
// Allows a controller thread to pause execution of newly created
// threads until notified. Instances of this class must be created
// and destroyed in the controller thread.
@@ -1260,6 +1535,62 @@ class Notification {
GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification);
};
+# elif GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT
+
+GTEST_API_ void SleepMilliseconds(int n);
+
+// Provides leak-safe Windows kernel handle ownership.
+// Used in death tests and in threading support.
+class GTEST_API_ AutoHandle {
+ public:
+ // Assume that Win32 HANDLE type is equivalent to void*. Doing so allows us to
+ // avoid including <windows.h> in this header file. Including <windows.h> is
+ // undesirable because it defines a lot of symbols and macros that tend to
+ // conflict with client code. This assumption is verified by
+ // WindowsTypesTest.HANDLEIsVoidStar.
+ typedef void* Handle;
+ AutoHandle();
+ explicit AutoHandle(Handle handle);
+
+ ~AutoHandle();
+
+ Handle Get() const;
+ void Reset();
+ void Reset(Handle handle);
+
+ private:
+ // Returns true iff the handle is a valid handle object that can be closed.
+ bool IsCloseable() const;
+
+ Handle handle_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle);
+};
+
+// Allows a controller thread to pause execution of newly created
+// threads until notified. Instances of this class must be created
+// and destroyed in the controller thread.
+//
+// This class is only for testing Google Test's own constructs. Do not
+// use it in user tests, either directly or indirectly.
+class GTEST_API_ Notification {
+ public:
+ Notification();
+ void Notify();
+ void WaitForNotification();
+
+ private:
+ AutoHandle event_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification);
+};
+# endif // GTEST_HAS_NOTIFICATION_
+
+// On MinGW, we can have both GTEST_OS_WINDOWS and GTEST_HAS_PTHREAD
+// defined, but we don't want to use MinGW's pthreads implementation, which
+// has conformance problems with some versions of the POSIX standard.
+# if GTEST_HAS_PTHREAD && !GTEST_OS_WINDOWS_MINGW
+
// As a C-function, ThreadFuncWithCLinkage cannot be templated itself.
// Consequently, it cannot select a correct instantiation of ThreadWithParam
// in order to call its Run(). Introducing ThreadWithParamBase as a
@@ -1297,10 +1628,9 @@ extern "C" inline void* ThreadFuncWithCLinkage(void* thread) {
template <typename T>
class ThreadWithParam : public ThreadWithParamBase {
public:
- typedef void (*UserThreadFunc)(T);
+ typedef void UserThreadFunc(T);
- ThreadWithParam(
- UserThreadFunc func, T param, Notification* thread_can_start)
+ ThreadWithParam(UserThreadFunc* func, T param, Notification* thread_can_start)
: func_(func),
param_(param),
thread_can_start_(thread_can_start),
@@ -1327,7 +1657,7 @@ class ThreadWithParam : public ThreadWithParamBase {
}
private:
- const UserThreadFunc func_; // User-supplied thread function.
+ UserThreadFunc* const func_; // User-supplied thread function.
const T param_; // User-supplied parameter to the thread function.
// When non-NULL, used to block execution until the controller thread
// notifies.
@@ -1337,26 +1667,293 @@ class ThreadWithParam : public ThreadWithParamBase {
GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam);
};
+# endif // !GTEST_OS_WINDOWS && GTEST_HAS_PTHREAD ||
+ // GTEST_HAS_MUTEX_AND_THREAD_LOCAL_
+
+# if defined(GTEST_HAS_MUTEX_AND_THREAD_LOCAL_) && GTEST_HAS_MUTEX_AND_THREAD_LOCAL_
+// Mutex and ThreadLocal have already been imported into the namespace.
+// Nothing to do here.
+
+# elif GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT
-// MutexBase and Mutex implement mutex on pthreads-based platforms. They
-// are used in conjunction with class MutexLock:
+// Mutex implements mutex on Windows platforms. It is used in conjunction
+// with class MutexLock:
//
// Mutex mutex;
// ...
-// MutexLock lock(&mutex); // Acquires the mutex and releases it at the end
-// // of the current scope.
-//
-// MutexBase implements behavior for both statically and dynamically
-// allocated mutexes. Do not use MutexBase directly. Instead, write
-// the following to define a static mutex:
+// MutexLock lock(&mutex); // Acquires the mutex and releases it at the
+// // end of the current scope.
//
+// A static Mutex *must* be defined or declared using one of the following
+// macros:
// GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex);
+// GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex);
//
-// You can forward declare a static mutex like this:
+// (A non-static Mutex is defined/declared in the usual way).
+class GTEST_API_ Mutex {
+ public:
+ enum MutexType { kStatic = 0, kDynamic = 1 };
+ // We rely on kStaticMutex being 0 as it is to what the linker initializes
+ // type_ in static mutexes. critical_section_ will be initialized lazily
+ // in ThreadSafeLazyInit().
+ enum StaticConstructorSelector { kStaticMutex = 0 };
+
+ // This constructor intentionally does nothing. It relies on type_ being
+ // statically initialized to 0 (effectively setting it to kStatic) and on
+ // ThreadSafeLazyInit() to lazily initialize the rest of the members.
+ explicit Mutex(StaticConstructorSelector /*dummy*/) {}
+
+ Mutex();
+ ~Mutex();
+
+ void Lock();
+
+ void Unlock();
+
+ // Does nothing if the current thread holds the mutex. Otherwise, crashes
+ // with high probability.
+ void AssertHeld();
+
+ private:
+ // Initializes owner_thread_id_ and critical_section_ in static mutexes.
+ void ThreadSafeLazyInit();
+
+ // Per http://blogs.msdn.com/b/oldnewthing/archive/2004/02/23/78395.aspx,
+ // we assume that 0 is an invalid value for thread IDs.
+ unsigned int owner_thread_id_;
+
+ // For static mutexes, we rely on these members being initialized to zeros
+ // by the linker.
+ MutexType type_;
+ long critical_section_init_phase_; // NOLINT
+ _RTL_CRITICAL_SECTION* critical_section_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex);
+};
+
+# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \
+ extern ::testing::internal::Mutex mutex
+
+# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \
+ ::testing::internal::Mutex mutex(::testing::internal::Mutex::kStaticMutex)
+
+// We cannot name this class MutexLock because the ctor declaration would
+// conflict with a macro named MutexLock, which is defined on some
+// platforms. That macro is used as a defensive measure to prevent against
+// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than
+// "MutexLock l(&mu)". Hence the typedef trick below.
+class GTestMutexLock {
+ public:
+ explicit GTestMutexLock(Mutex* mutex)
+ : mutex_(mutex) { mutex_->Lock(); }
+
+ ~GTestMutexLock() { mutex_->Unlock(); }
+
+ private:
+ Mutex* const mutex_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock);
+};
+
+typedef GTestMutexLock MutexLock;
+
+// Base class for ValueHolder<T>. Allows a caller to hold and delete a value
+// without knowing its type.
+class ThreadLocalValueHolderBase {
+ public:
+ virtual ~ThreadLocalValueHolderBase() {}
+};
+
+// Provides a way for a thread to send notifications to a ThreadLocal
+// regardless of its parameter type.
+class ThreadLocalBase {
+ public:
+ // Creates a new ValueHolder<T> object holding a default value passed to
+ // this ThreadLocal<T>'s constructor and returns it. It is the caller's
+ // responsibility not to call this when the ThreadLocal<T> instance already
+ // has a value on the current thread.
+ virtual ThreadLocalValueHolderBase* NewValueForCurrentThread() const = 0;
+
+ protected:
+ ThreadLocalBase() {}
+ virtual ~ThreadLocalBase() {}
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocalBase);
+};
+
+// Maps a thread to a set of ThreadLocals that have values instantiated on that
+// thread and notifies them when the thread exits. A ThreadLocal instance is
+// expected to persist until all threads it has values on have terminated.
+class GTEST_API_ ThreadLocalRegistry {
+ public:
+ // Registers thread_local_instance as having value on the current thread.
+ // Returns a value that can be used to identify the thread from other threads.
+ static ThreadLocalValueHolderBase* GetValueOnCurrentThread(
+ const ThreadLocalBase* thread_local_instance);
+
+ // Invoked when a ThreadLocal instance is destroyed.
+ static void OnThreadLocalDestroyed(
+ const ThreadLocalBase* thread_local_instance);
+};
+
+class GTEST_API_ ThreadWithParamBase {
+ public:
+ void Join();
+
+ protected:
+ class Runnable {
+ public:
+ virtual ~Runnable() {}
+ virtual void Run() = 0;
+ };
+
+ ThreadWithParamBase(Runnable *runnable, Notification* thread_can_start);
+ virtual ~ThreadWithParamBase();
+
+ private:
+ AutoHandle thread_;
+};
+
+// Helper class for testing Google Test's multi-threading constructs.
+template <typename T>
+class ThreadWithParam : public ThreadWithParamBase {
+ public:
+ typedef void UserThreadFunc(T);
+
+ ThreadWithParam(UserThreadFunc* func, T param, Notification* thread_can_start)
+ : ThreadWithParamBase(new RunnableImpl(func, param), thread_can_start) {
+ }
+ virtual ~ThreadWithParam() {}
+
+ private:
+ class RunnableImpl : public Runnable {
+ public:
+ RunnableImpl(UserThreadFunc* func, T param)
+ : func_(func),
+ param_(param) {
+ }
+ virtual ~RunnableImpl() {}
+ virtual void Run() {
+ func_(param_);
+ }
+
+ private:
+ UserThreadFunc* const func_;
+ const T param_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(RunnableImpl);
+ };
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam);
+};
+
+// Implements thread-local storage on Windows systems.
//
-// GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex);
+// // Thread 1
+// ThreadLocal<int> tl(100); // 100 is the default value for each thread.
+//
+// // Thread 2
+// tl.set(150); // Changes the value for thread 2 only.
+// EXPECT_EQ(150, tl.get());
+//
+// // Thread 1
+// EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value.
+// tl.set(200);
+// EXPECT_EQ(200, tl.get());
+//
+// The template type argument T must have a public copy constructor.
+// In addition, the default ThreadLocal constructor requires T to have
+// a public default constructor.
+//
+// The users of a TheadLocal instance have to make sure that all but one
+// threads (including the main one) using that instance have exited before
+// destroying it. Otherwise, the per-thread objects managed for them by the
+// ThreadLocal instance are not guaranteed to be destroyed on all platforms.
//
-// To create a dynamic mutex, just define an object of type Mutex.
+// Google Test only uses global ThreadLocal objects. That means they
+// will die after main() has returned. Therefore, no per-thread
+// object managed by Google Test will be leaked as long as all threads
+// using Google Test have exited when main() returns.
+template <typename T>
+class ThreadLocal : public ThreadLocalBase {
+ public:
+ ThreadLocal() : default_factory_(new DefaultValueHolderFactory()) {}
+ explicit ThreadLocal(const T& value)
+ : default_factory_(new InstanceValueHolderFactory(value)) {}
+
+ ~ThreadLocal() { ThreadLocalRegistry::OnThreadLocalDestroyed(this); }
+
+ T* pointer() { return GetOrCreateValue(); }
+ const T* pointer() const { return GetOrCreateValue(); }
+ const T& get() const { return *pointer(); }
+ void set(const T& value) { *pointer() = value; }
+
+ private:
+ // Holds a value of T. Can be deleted via its base class without the caller
+ // knowing the type of T.
+ class ValueHolder : public ThreadLocalValueHolderBase {
+ public:
+ ValueHolder() : value_() {}
+ explicit ValueHolder(const T& value) : value_(value) {}
+
+ T* pointer() { return &value_; }
+
+ private:
+ T value_;
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder);
+ };
+
+
+ T* GetOrCreateValue() const {
+ return static_cast<ValueHolder*>(
+ ThreadLocalRegistry::GetValueOnCurrentThread(this))->pointer();
+ }
+
+ virtual ThreadLocalValueHolderBase* NewValueForCurrentThread() const {
+ return default_factory_->MakeNewHolder();
+ }
+
+ class ValueHolderFactory {
+ public:
+ ValueHolderFactory() {}
+ virtual ~ValueHolderFactory() {}
+ virtual ValueHolder* MakeNewHolder() const = 0;
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolderFactory);
+ };
+
+ class DefaultValueHolderFactory : public ValueHolderFactory {
+ public:
+ DefaultValueHolderFactory() {}
+ virtual ValueHolder* MakeNewHolder() const { return new ValueHolder(); }
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultValueHolderFactory);
+ };
+
+ class InstanceValueHolderFactory : public ValueHolderFactory {
+ public:
+ explicit InstanceValueHolderFactory(const T& value) : value_(value) {}
+ virtual ValueHolder* MakeNewHolder() const {
+ return new ValueHolder(value_);
+ }
+
+ private:
+ const T value_; // The value for each thread.
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(InstanceValueHolderFactory);
+ };
+
+ scoped_ptr<ValueHolderFactory> default_factory_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal);
+};
+
+# elif GTEST_HAS_PTHREAD
+
+// MutexBase and Mutex implement mutex on pthreads-based platforms.
class MutexBase {
public:
// Acquires this mutex.
@@ -1401,17 +1998,12 @@ class MutexBase {
};
// Forward-declares a static mutex.
-# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \
- extern ::testing::internal::MutexBase mutex
+# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \
+ extern ::testing::internal::MutexBase mutex
// Defines and statically (i.e. at link time) initializes a static mutex.
-// The initialization list here does not explicitly initialize each field,
-// instead relying on default initialization for the unspecified fields. In
-// particular, the owner_ field (a pthread_t) is not explicitly initialized.
-// This allows initialization to work whether pthread_t is a scalar or struct.
-// The flag -Wmissing-field-initializers must not be specified for this to work.
-# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \
- ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, false }
+# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \
+ ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, false, pthread_t() }
// The Mutex class can only be used for mutexes created at runtime. It
// shares its API with MutexBase otherwise.
@@ -1429,9 +2021,11 @@ class Mutex : public MutexBase {
GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex);
};
-// We cannot name this class MutexLock as the ctor declaration would
+// We cannot name this class MutexLock because the ctor declaration would
// conflict with a macro named MutexLock, which is defined on some
-// platforms. Hence the typedef trick below.
+// platforms. That macro is used as a defensive measure to prevent against
+// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than
+// "MutexLock l(&mu)". Hence the typedef trick below.
class GTestMutexLock {
public:
explicit GTestMutexLock(MutexBase* mutex)
@@ -1465,41 +2059,14 @@ extern "C" inline void DeleteThreadLocalValue(void* value_holder) {
}
// Implements thread-local storage on pthreads-based systems.
-//
-// // Thread 1
-// ThreadLocal<int> tl(100); // 100 is the default value for each thread.
-//
-// // Thread 2
-// tl.set(150); // Changes the value for thread 2 only.
-// EXPECT_EQ(150, tl.get());
-//
-// // Thread 1
-// EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value.
-// tl.set(200);
-// EXPECT_EQ(200, tl.get());
-//
-// The template type argument T must have a public copy constructor.
-// In addition, the default ThreadLocal constructor requires T to have
-// a public default constructor.
-//
-// An object managed for a thread by a ThreadLocal instance is deleted
-// when the thread exits. Or, if the ThreadLocal instance dies in
-// that thread, when the ThreadLocal dies. It's the user's
-// responsibility to ensure that all other threads using a ThreadLocal
-// have exited when it dies, or the per-thread objects for those
-// threads will not be deleted.
-//
-// Google Test only uses global ThreadLocal objects. That means they
-// will die after main() has returned. Therefore, no per-thread
-// object managed by Google Test will be leaked as long as all threads
-// using Google Test have exited when main() returns.
template <typename T>
class ThreadLocal {
public:
- ThreadLocal() : key_(CreateKey()),
- default_() {}
- explicit ThreadLocal(const T& value) : key_(CreateKey()),
- default_(value) {}
+ ThreadLocal()
+ : key_(CreateKey()), default_factory_(new DefaultValueHolderFactory()) {}
+ explicit ThreadLocal(const T& value)
+ : key_(CreateKey()),
+ default_factory_(new InstanceValueHolderFactory(value)) {}
~ThreadLocal() {
// Destroys the managed object for the current thread, if any.
@@ -1519,6 +2086,7 @@ class ThreadLocal {
// Holds a value of type T.
class ValueHolder : public ThreadLocalValueHolderBase {
public:
+ ValueHolder() : value_() {}
explicit ValueHolder(const T& value) : value_(value) {}
T* pointer() { return &value_; }
@@ -1544,22 +2112,54 @@ class ThreadLocal {
return CheckedDowncastToActualType<ValueHolder>(holder)->pointer();
}
- ValueHolder* const new_holder = new ValueHolder(default_);
+ ValueHolder* const new_holder = default_factory_->MakeNewHolder();
ThreadLocalValueHolderBase* const holder_base = new_holder;
GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base));
return new_holder->pointer();
}
+ class ValueHolderFactory {
+ public:
+ ValueHolderFactory() {}
+ virtual ~ValueHolderFactory() {}
+ virtual ValueHolder* MakeNewHolder() const = 0;
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolderFactory);
+ };
+
+ class DefaultValueHolderFactory : public ValueHolderFactory {
+ public:
+ DefaultValueHolderFactory() {}
+ virtual ValueHolder* MakeNewHolder() const { return new ValueHolder(); }
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultValueHolderFactory);
+ };
+
+ class InstanceValueHolderFactory : public ValueHolderFactory {
+ public:
+ explicit InstanceValueHolderFactory(const T& value) : value_(value) {}
+ virtual ValueHolder* MakeNewHolder() const {
+ return new ValueHolder(value_);
+ }
+
+ private:
+ const T value_; // The value for each thread.
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(InstanceValueHolderFactory);
+ };
+
// A key pthreads uses for looking up per-thread values.
const pthread_key_t key_;
- const T default_; // The default value for each thread.
+ scoped_ptr<ValueHolderFactory> default_factory_;
GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal);
};
-# define GTEST_IS_THREADSAFE 1
+# endif // GTEST_HAS_MUTEX_AND_THREAD_LOCAL_
-#else // GTEST_HAS_PTHREAD
+#else // GTEST_IS_THREADSAFE
// A dummy implementation of synchronization primitives (mutex, lock,
// and thread-local variable). Necessary for compiling Google Test where
@@ -1579,6 +2179,11 @@ class Mutex {
# define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex
+// We cannot name this class MutexLock because the ctor declaration would
+// conflict with a macro named MutexLock, which is defined on some
+// platforms. That macro is used as a defensive measure to prevent against
+// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than
+// "MutexLock l(&mu)". Hence the typedef trick below.
class GTestMutexLock {
public:
explicit GTestMutexLock(Mutex*) {} // NOLINT
@@ -1599,11 +2204,7 @@ class ThreadLocal {
T value_;
};
-// The above synchronization primitives have dummy implementations.
-// Therefore Google Test is not thread-safe.
-# define GTEST_IS_THREADSAFE 0
-
-#endif // GTEST_HAS_PTHREAD
+#endif // GTEST_IS_THREADSAFE
// Returns the number of threads running in the process, or 0 to indicate that
// we cannot detect it.
@@ -1713,6 +2314,13 @@ inline char ToUpper(char ch) {
return static_cast<char>(toupper(static_cast<unsigned char>(ch)));
}
+inline std::string StripTrailingSpaces(std::string str) {
+ std::string::iterator it = str.end();
+ while (it != str.begin() && IsSpace(*--it))
+ it = str.erase(it);
+ return str;
+}
+
// The testing::internal::posix namespace holds wrappers for common
// POSIX functions. These wrappers hide the differences between
// Windows/MSVC and POSIX systems. Since some compilers define these
@@ -1776,11 +2384,7 @@ inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); }
// Functions deprecated by MSVC 8.0.
-#ifdef _MSC_VER
-// Temporarily disable warning 4996 (deprecated function).
-# pragma warning(push)
-# pragma warning(disable:4996)
-#endif
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996 /* deprecated function */)
inline const char* StrNCpy(char* dest, const char* src, size_t n) {
return strncpy(dest, src, n);
@@ -1790,7 +2394,7 @@ inline const char* StrNCpy(char* dest, const char* src, size_t n) {
// StrError() aren't needed on Windows CE at this time and thus not
// defined there.
-#if !GTEST_OS_WINDOWS_MOBILE
+#if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT
inline int ChDir(const char* dir) { return chdir(dir); }
#endif
inline FILE* FOpen(const char* path, const char* mode) {
@@ -1814,8 +2418,9 @@ inline int Close(int fd) { return close(fd); }
inline const char* StrError(int errnum) { return strerror(errnum); }
#endif
inline const char* GetEnv(const char* name) {
-#if GTEST_OS_WINDOWS_MOBILE
+#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE | GTEST_OS_WINDOWS_RT
// We are on Windows CE, which has no environment variables.
+ static_cast<void>(name); // To prevent 'unused argument' warning.
return NULL;
#elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9)
// Environment variables which we programmatically clear will be set to the
@@ -1827,9 +2432,7 @@ inline const char* GetEnv(const char* name) {
#endif
}
-#ifdef _MSC_VER
-# pragma warning(pop) // Restores the warning state.
-#endif
+GTEST_DISABLE_MSC_WARNINGS_POP_()
#if GTEST_OS_WINDOWS_MOBILE
// Windows CE has no C library. The abort() function is used in
@@ -1930,11 +2533,20 @@ typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds.
// Utilities for command line flags and environment variables.
// Macro for referencing flags.
-#define GTEST_FLAG(name) FLAGS_gtest_##name
+#if !defined(GTEST_FLAG)
+# define GTEST_FLAG(name) FLAGS_gtest_##name
+#endif // !defined(GTEST_FLAG)
+
+#if !defined(GTEST_USE_OWN_FLAGFILE_FLAG_)
+# define GTEST_USE_OWN_FLAGFILE_FLAG_ 1
+#endif // !defined(GTEST_USE_OWN_FLAGFILE_FLAG_)
+
+#if !defined(GTEST_DECLARE_bool_)
+# define GTEST_FLAG_SAVER_ ::testing::internal::GTestFlagSaver
// Macros for declaring flags.
-#define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name)
-#define GTEST_DECLARE_int32_(name) \
+# define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name)
+# define GTEST_DECLARE_int32_(name) \
GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name)
#define GTEST_DECLARE_string_(name) \
GTEST_API_ extern ::std::string GTEST_FLAG(name)
@@ -1947,9 +2559,13 @@ typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds.
#define GTEST_DEFINE_string_(name, default_val, doc) \
GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val)
+#endif // !defined(GTEST_DECLARE_bool_)
+
// Thread annotations
-#define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks)
-#define GTEST_LOCK_EXCLUDED_(locks)
+#if !defined(GTEST_EXCLUSIVE_LOCK_REQUIRED_)
+# define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks)
+# define GTEST_LOCK_EXCLUDED_(locks)
+#endif // !defined(GTEST_EXCLUSIVE_LOCK_REQUIRED_)
// Parses 'str' for a 32-bit signed integer. If successful, writes the result
// to *value and returns true; otherwise leaves *value unchanged and returns
@@ -1963,7 +2579,7 @@ bool ParseInt32(const Message& src_text, const char* str, Int32* value);
// corresponding to the given Google Test flag.
bool BoolFromGTestEnv(const char* flag, bool default_val);
GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val);
-const char* StringFromGTestEnv(const char* flag, const char* default_val);
+std::string StringFromGTestEnv(const char* flag, const char* default_val);
} // namespace internal
} // namespace testing
diff --git a/extern/gtest/include/gtest/internal/gtest-tuple.h b/extern/gtest/include/gtest/internal/gtest-tuple.h
index 7b3dfc312dc..e9b405340a8 100644
--- a/extern/gtest/include/gtest/internal/gtest-tuple.h
+++ b/extern/gtest/include/gtest/internal/gtest-tuple.h
@@ -53,6 +53,14 @@
private:
#endif
+// Visual Studio 2010, 2012, and 2013 define symbols in std::tr1 that conflict
+// with our own definitions. Therefore using our own tuple does not work on
+// those compilers.
+#if defined(_MSC_VER) && _MSC_VER >= 1600 /* 1600 is Visual Studio 2010 */
+# error "gtest's tuple doesn't compile on Visual Studio 2010 or later. \
+GTEST_USE_OWN_TR1_TUPLE must be set to 0 on those compilers."
+#endif
+
// GTEST_n_TUPLE_(T) is the type of an n-tuple.
#define GTEST_0_TUPLE_(T) tuple<>
#define GTEST_1_TUPLE_(T) tuple<T##0, void, void, void, void, void, void, \
diff --git a/extern/gtest/src/gtest-death-test.cc b/extern/gtest/src/gtest-death-test.cc
index a6023fce4fa..a01a3698308 100644
--- a/extern/gtest/src/gtest-death-test.cc
+++ b/extern/gtest/src/gtest-death-test.cc
@@ -33,6 +33,7 @@
#include "gtest/gtest-death-test.h"
#include "gtest/internal/gtest-port.h"
+#include "gtest/internal/custom/gtest.h"
#if GTEST_HAS_DEATH_TEST
@@ -68,9 +69,9 @@
// Indicates that this translation unit is part of Google Test's
// implementation. It must come before gtest-internal-inl.h is
-// included, or there will be a compiler error. This trick is to
-// prevent a user from accidentally including gtest-internal-inl.h in
-// his code.
+// included, or there will be a compiler error. This trick exists to
+// prevent the accidental inclusion of gtest-internal-inl.h in the
+// user's code.
#define GTEST_IMPLEMENTATION_ 1
#include "src/gtest-internal-inl.h"
#undef GTEST_IMPLEMENTATION_
@@ -120,7 +121,9 @@ namespace internal {
// Valid only for fast death tests. Indicates the code is running in the
// child process of a fast style death test.
+# if !GTEST_OS_WINDOWS
static bool g_in_fast_death_test_child = false;
+# endif
// Returns a Boolean value indicating whether the caller is currently
// executing in the context of the death test child process. Tools such as
@@ -169,6 +172,14 @@ KilledBySignal::KilledBySignal(int signum) : signum_(signum) {
// KilledBySignal function-call operator.
bool KilledBySignal::operator()(int exit_status) const {
+# if defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_)
+ {
+ bool result;
+ if (GTEST_KILLED_BY_SIGNAL_OVERRIDE_(signum_, exit_status, &result)) {
+ return result;
+ }
+ }
+# endif // defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_)
return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_;
}
# endif // !GTEST_OS_WINDOWS
@@ -875,6 +886,11 @@ class ExecDeathTest : public ForkingDeathTest {
static ::std::vector<testing::internal::string>
GetArgvsForDeathTestChildProcess() {
::std::vector<testing::internal::string> args = GetInjectableArgvs();
+# if defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_)
+ ::std::vector<testing::internal::string> extra_args =
+ GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_();
+ args.insert(args.end(), extra_args.begin(), extra_args.end());
+# endif // defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_)
return args;
}
// The name of the file in which the death test is located.
@@ -985,6 +1001,8 @@ void StackLowerThanAddress(const void* ptr, bool* result) {
*result = (&dummy < ptr);
}
+// Make sure AddressSanitizer does not tamper with the stack here.
+GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
bool StackGrowsDown() {
int dummy;
bool result;
@@ -1202,26 +1220,6 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
return true;
}
-// Splits a given string on a given delimiter, populating a given
-// vector with the fields. GTEST_HAS_DEATH_TEST implies that we have
-// ::std::string, so we can use it here.
-static void SplitString(const ::std::string& str, char delimiter,
- ::std::vector< ::std::string>* dest) {
- ::std::vector< ::std::string> parsed;
- ::std::string::size_type pos = 0;
- while (::testing::internal::AlwaysTrue()) {
- const ::std::string::size_type colon = str.find(delimiter, pos);
- if (colon == ::std::string::npos) {
- parsed.push_back(str.substr(pos));
- break;
- } else {
- parsed.push_back(str.substr(pos, colon - pos));
- pos = colon + 1;
- }
- }
- dest->swap(parsed);
-}
-
# if GTEST_OS_WINDOWS
// Recreates the pipe and event handles from the provided parameters,
// signals the event, and returns a file descriptor wrapped around the pipe
diff --git a/extern/gtest/src/gtest-filepath.cc b/extern/gtest/src/gtest-filepath.cc
index 6be58b6fca2..0292dc11957 100644
--- a/extern/gtest/src/gtest-filepath.cc
+++ b/extern/gtest/src/gtest-filepath.cc
@@ -70,7 +70,6 @@ namespace internal {
// of them.
const char kPathSeparator = '\\';
const char kAlternatePathSeparator = '/';
-const char kPathSeparatorString[] = "\\";
const char kAlternatePathSeparatorString[] = "/";
# if GTEST_OS_WINDOWS_MOBILE
// Windows CE doesn't have a current directory. You should not use
@@ -84,7 +83,6 @@ const char kCurrentDirectoryString[] = ".\\";
# endif // GTEST_OS_WINDOWS_MOBILE
#else
const char kPathSeparator = '/';
-const char kPathSeparatorString[] = "/";
const char kCurrentDirectoryString[] = "./";
#endif // GTEST_OS_WINDOWS
@@ -99,7 +97,7 @@ static bool IsPathSeparator(char c) {
// Returns the current working directory, or "" if unsuccessful.
FilePath FilePath::GetCurrentDir() {
-#if GTEST_OS_WINDOWS_MOBILE
+#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT
// Windows CE doesn't have a current directory, so we just return
// something reasonable.
return FilePath(kCurrentDirectoryString);
@@ -108,7 +106,14 @@ FilePath FilePath::GetCurrentDir() {
return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
#else
char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
- return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
+ char* result = getcwd(cwd, sizeof(cwd));
+# if GTEST_OS_NACL
+ // getcwd will likely fail in NaCl due to the sandbox, so return something
+ // reasonable. The user may have provided a shim implementation for getcwd,
+ // however, so fallback only when failure is detected.
+ return FilePath(result == NULL ? kCurrentDirectoryString : cwd);
+# endif // GTEST_OS_NACL
+ return FilePath(result == NULL ? "" : cwd);
#endif // GTEST_OS_WINDOWS_MOBILE
}
diff --git a/extern/gtest/src/gtest-internal-inl.h b/extern/gtest/src/gtest-internal-inl.h
index 35df303cca6..ed8a682a964 100644
--- a/extern/gtest/src/gtest-internal-inl.h
+++ b/extern/gtest/src/gtest-internal-inl.h
@@ -40,7 +40,7 @@
// GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is
// part of Google Test's implementation; otherwise it's undefined.
#if !GTEST_IMPLEMENTATION_
-// A user is trying to include this from his code - just say no.
+// If this file is included from the user's code, just say no.
# error "gtest-internal-inl.h is part of Google Test's internal implementation."
# error "It must not be included except by Google Test itself."
#endif // GTEST_IMPLEMENTATION_
@@ -100,6 +100,7 @@ const char kShuffleFlag[] = "shuffle";
const char kStackTraceDepthFlag[] = "stack_trace_depth";
const char kStreamResultToFlag[] = "stream_result_to";
const char kThrowOnFailureFlag[] = "throw_on_failure";
+const char kFlagfileFlag[] = "flagfile";
// A valid random seed must be in [1, kMaxRandomSeed].
const int kMaxRandomSeed = 99999;
@@ -432,6 +433,10 @@ class OsStackTraceGetterInterface {
// CurrentStackTrace() will use to find and hide Google Test stack frames.
virtual void UponLeavingGTest() = 0;
+ // This string is inserted in place of stack frames that are part of
+ // Google Test's implementation.
+ static const char* const kElidedFramesMarker;
+
private:
GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface);
};
@@ -439,26 +444,12 @@ class OsStackTraceGetterInterface {
// A working implementation of the OsStackTraceGetterInterface interface.
class OsStackTraceGetter : public OsStackTraceGetterInterface {
public:
- OsStackTraceGetter() : caller_frame_(NULL) {}
-
- virtual string CurrentStackTrace(int max_depth, int skip_count)
- GTEST_LOCK_EXCLUDED_(mutex_);
+ OsStackTraceGetter() {}
- virtual void UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_);
-
- // This string is inserted in place of stack frames that are part of
- // Google Test's implementation.
- static const char* const kElidedFramesMarker;
+ virtual string CurrentStackTrace(int max_depth, int skip_count);
+ virtual void UponLeavingGTest();
private:
- Mutex mutex_; // protects all internal state
-
- // We save the stack frame below the frame that calls user code.
- // We do this because the address of the frame immediately below
- // the user code changes between the call to UponLeavingGTest()
- // and any calls to CurrentStackTrace() from within the user code.
- void* caller_frame_;
-
GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter);
};
@@ -968,32 +959,6 @@ GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv);
// platform.
GTEST_API_ std::string GetLastErrnoDescription();
-# if GTEST_OS_WINDOWS
-// Provides leak-safe Windows kernel handle ownership.
-class AutoHandle {
- public:
- AutoHandle() : handle_(INVALID_HANDLE_VALUE) {}
- explicit AutoHandle(HANDLE handle) : handle_(handle) {}
-
- ~AutoHandle() { Reset(); }
-
- HANDLE Get() const { return handle_; }
- void Reset() { Reset(INVALID_HANDLE_VALUE); }
- void Reset(HANDLE handle) {
- if (handle != handle_) {
- if (handle_ != INVALID_HANDLE_VALUE)
- ::CloseHandle(handle_);
- handle_ = handle;
- }
- }
-
- private:
- HANDLE handle_;
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle);
-};
-# endif // GTEST_OS_WINDOWS
-
// Attempts to parse a string into a positive integer pointed to by the
// number parameter. Returns true if that is possible.
// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use
@@ -1067,7 +1032,7 @@ class TestResultAccessor {
#if GTEST_CAN_STREAM_RESULTS_
// Streams test results to the given port on the given host machine.
-class StreamingListener : public EmptyTestEventListener {
+class GTEST_API_ StreamingListener : public EmptyTestEventListener {
public:
// Abstract base class for writing strings to a socket.
class AbstractSocketWriter {
diff --git a/extern/gtest/src/gtest-port.cc b/extern/gtest/src/gtest-port.cc
index 0c4df5f29a7..e5bf3dd2be4 100644
--- a/extern/gtest/src/gtest-port.cc
+++ b/extern/gtest/src/gtest-port.cc
@@ -35,15 +35,16 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <fstream>
-#if GTEST_OS_WINDOWS_MOBILE
-# include <windows.h> // For TerminateProcess()
-#elif GTEST_OS_WINDOWS
+#if GTEST_OS_WINDOWS
+# include <windows.h>
# include <io.h>
# include <sys/stat.h>
+# include <map> // Used in ThreadLocal.
#else
# include <unistd.h>
-#endif // GTEST_OS_WINDOWS_MOBILE
+#endif // GTEST_OS_WINDOWS
#if GTEST_OS_MAC
# include <mach/mach_init.h>
@@ -53,9 +54,15 @@
#if GTEST_OS_QNX
# include <devctl.h>
+# include <fcntl.h>
# include <sys/procfs.h>
#endif // GTEST_OS_QNX
+#if GTEST_OS_AIX
+# include <procinfo.h>
+# include <sys/types.h>
+#endif // GTEST_OS_AIX
+
#include "gtest/gtest-spi.h"
#include "gtest/gtest-message.h"
#include "gtest/internal/gtest-internal.h"
@@ -63,9 +70,9 @@
// Indicates that this translation unit is part of Google Test's
// implementation. It must come before gtest-internal-inl.h is
-// included, or there will be a compiler error. This trick is to
-// prevent a user from accidentally including gtest-internal-inl.h in
-// his code.
+// included, or there will be a compiler error. This trick exists to
+// prevent the accidental inclusion of gtest-internal-inl.h in the
+// user's code.
#define GTEST_IMPLEMENTATION_ 1
#include "src/gtest-internal-inl.h"
#undef GTEST_IMPLEMENTATION_
@@ -82,10 +89,31 @@ const int kStdOutFileno = STDOUT_FILENO;
const int kStdErrFileno = STDERR_FILENO;
#endif // _MSC_VER
-#if GTEST_OS_MAC
+#if GTEST_OS_LINUX
+
+namespace {
+template <typename T>
+T ReadProcFileField(const string& filename, int field) {
+ std::string dummy;
+ std::ifstream file(filename.c_str());
+ while (field-- > 0) {
+ file >> dummy;
+ }
+ T output = 0;
+ file >> output;
+ return output;
+}
+} // namespace
+
+// Returns the number of active threads, or 0 when there is an error.
+size_t GetThreadCount() {
+ const string filename =
+ (Message() << "/proc/" << getpid() << "/stat").GetString();
+ return ReadProcFileField<int>(filename, 19);
+}
+
+#elif GTEST_OS_MAC
-// Returns the number of threads running in the process, or 0 to indicate that
-// we cannot detect it.
size_t GetThreadCount() {
const task_t task = mach_task_self();
mach_msg_type_number_t thread_count;
@@ -123,6 +151,19 @@ size_t GetThreadCount() {
}
}
+#elif GTEST_OS_AIX
+
+size_t GetThreadCount() {
+ struct procentry64 entry;
+ pid_t pid = getpid();
+ int status = getprocs64(&entry, sizeof(entry), NULL, 0, &pid, 1);
+ if (status == 1) {
+ return entry.pi_thcount;
+ } else {
+ return 0;
+ }
+}
+
#else
size_t GetThreadCount() {
@@ -131,7 +172,390 @@ size_t GetThreadCount() {
return 0;
}
-#endif // GTEST_OS_MAC
+#endif // GTEST_OS_LINUX
+
+#if GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS
+
+void SleepMilliseconds(int n) {
+ ::Sleep(n);
+}
+
+AutoHandle::AutoHandle()
+ : handle_(INVALID_HANDLE_VALUE) {}
+
+AutoHandle::AutoHandle(Handle handle)
+ : handle_(handle) {}
+
+AutoHandle::~AutoHandle() {
+ Reset();
+}
+
+AutoHandle::Handle AutoHandle::Get() const {
+ return handle_;
+}
+
+void AutoHandle::Reset() {
+ Reset(INVALID_HANDLE_VALUE);
+}
+
+void AutoHandle::Reset(HANDLE handle) {
+ // Resetting with the same handle we already own is invalid.
+ if (handle_ != handle) {
+ if (IsCloseable()) {
+ ::CloseHandle(handle_);
+ }
+ handle_ = handle;
+ } else {
+ GTEST_CHECK_(!IsCloseable())
+ << "Resetting a valid handle to itself is likely a programmer error "
+ "and thus not allowed.";
+ }
+}
+
+bool AutoHandle::IsCloseable() const {
+ // Different Windows APIs may use either of these values to represent an
+ // invalid handle.
+ return handle_ != NULL && handle_ != INVALID_HANDLE_VALUE;
+}
+
+Notification::Notification()
+ : event_(::CreateEvent(NULL, // Default security attributes.
+ TRUE, // Do not reset automatically.
+ FALSE, // Initially unset.
+ NULL)) { // Anonymous event.
+ GTEST_CHECK_(event_.Get() != NULL);
+}
+
+void Notification::Notify() {
+ GTEST_CHECK_(::SetEvent(event_.Get()) != FALSE);
+}
+
+void Notification::WaitForNotification() {
+ GTEST_CHECK_(
+ ::WaitForSingleObject(event_.Get(), INFINITE) == WAIT_OBJECT_0);
+}
+
+Mutex::Mutex()
+ : owner_thread_id_(0),
+ type_(kDynamic),
+ critical_section_init_phase_(0),
+ critical_section_(new CRITICAL_SECTION) {
+ ::InitializeCriticalSection(critical_section_);
+}
+
+Mutex::~Mutex() {
+ // Static mutexes are leaked intentionally. It is not thread-safe to try
+ // to clean them up.
+ // TODO(yukawa): Switch to Slim Reader/Writer (SRW) Locks, which requires
+ // nothing to clean it up but is available only on Vista and later.
+ // http://msdn.microsoft.com/en-us/library/windows/desktop/aa904937.aspx
+ if (type_ == kDynamic) {
+ ::DeleteCriticalSection(critical_section_);
+ delete critical_section_;
+ critical_section_ = NULL;
+ }
+}
+
+void Mutex::Lock() {
+ ThreadSafeLazyInit();
+ ::EnterCriticalSection(critical_section_);
+ owner_thread_id_ = ::GetCurrentThreadId();
+}
+
+void Mutex::Unlock() {
+ ThreadSafeLazyInit();
+ // We don't protect writing to owner_thread_id_ here, as it's the
+ // caller's responsibility to ensure that the current thread holds the
+ // mutex when this is called.
+ owner_thread_id_ = 0;
+ ::LeaveCriticalSection(critical_section_);
+}
+
+// Does nothing if the current thread holds the mutex. Otherwise, crashes
+// with high probability.
+void Mutex::AssertHeld() {
+ ThreadSafeLazyInit();
+ GTEST_CHECK_(owner_thread_id_ == ::GetCurrentThreadId())
+ << "The current thread is not holding the mutex @" << this;
+}
+
+// Initializes owner_thread_id_ and critical_section_ in static mutexes.
+void Mutex::ThreadSafeLazyInit() {
+ // Dynamic mutexes are initialized in the constructor.
+ if (type_ == kStatic) {
+ switch (
+ ::InterlockedCompareExchange(&critical_section_init_phase_, 1L, 0L)) {
+ case 0:
+ // If critical_section_init_phase_ was 0 before the exchange, we
+ // are the first to test it and need to perform the initialization.
+ owner_thread_id_ = 0;
+ critical_section_ = new CRITICAL_SECTION;
+ ::InitializeCriticalSection(critical_section_);
+ // Updates the critical_section_init_phase_ to 2 to signal
+ // initialization complete.
+ GTEST_CHECK_(::InterlockedCompareExchange(
+ &critical_section_init_phase_, 2L, 1L) ==
+ 1L);
+ break;
+ case 1:
+ // Somebody else is already initializing the mutex; spin until they
+ // are done.
+ while (::InterlockedCompareExchange(&critical_section_init_phase_,
+ 2L,
+ 2L) != 2L) {
+ // Possibly yields the rest of the thread's time slice to other
+ // threads.
+ ::Sleep(0);
+ }
+ break;
+
+ case 2:
+ break; // The mutex is already initialized and ready for use.
+
+ default:
+ GTEST_CHECK_(false)
+ << "Unexpected value of critical_section_init_phase_ "
+ << "while initializing a static mutex.";
+ }
+ }
+}
+
+namespace {
+
+class ThreadWithParamSupport : public ThreadWithParamBase {
+ public:
+ static HANDLE CreateThread(Runnable* runnable,
+ Notification* thread_can_start) {
+ ThreadMainParam* param = new ThreadMainParam(runnable, thread_can_start);
+ DWORD thread_id;
+ // TODO(yukawa): Consider to use _beginthreadex instead.
+ HANDLE thread_handle = ::CreateThread(
+ NULL, // Default security.
+ 0, // Default stack size.
+ &ThreadWithParamSupport::ThreadMain,
+ param, // Parameter to ThreadMainStatic
+ 0x0, // Default creation flags.
+ &thread_id); // Need a valid pointer for the call to work under Win98.
+ GTEST_CHECK_(thread_handle != NULL) << "CreateThread failed with error "
+ << ::GetLastError() << ".";
+ if (thread_handle == NULL) {
+ delete param;
+ }
+ return thread_handle;
+ }
+
+ private:
+ struct ThreadMainParam {
+ ThreadMainParam(Runnable* runnable, Notification* thread_can_start)
+ : runnable_(runnable),
+ thread_can_start_(thread_can_start) {
+ }
+ scoped_ptr<Runnable> runnable_;
+ // Does not own.
+ Notification* thread_can_start_;
+ };
+
+ static DWORD WINAPI ThreadMain(void* ptr) {
+ // Transfers ownership.
+ scoped_ptr<ThreadMainParam> param(static_cast<ThreadMainParam*>(ptr));
+ if (param->thread_can_start_ != NULL)
+ param->thread_can_start_->WaitForNotification();
+ param->runnable_->Run();
+ return 0;
+ }
+
+ // Prohibit instantiation.
+ ThreadWithParamSupport();
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParamSupport);
+};
+
+} // namespace
+
+ThreadWithParamBase::ThreadWithParamBase(Runnable *runnable,
+ Notification* thread_can_start)
+ : thread_(ThreadWithParamSupport::CreateThread(runnable,
+ thread_can_start)) {
+}
+
+ThreadWithParamBase::~ThreadWithParamBase() {
+ Join();
+}
+
+void ThreadWithParamBase::Join() {
+ GTEST_CHECK_(::WaitForSingleObject(thread_.Get(), INFINITE) == WAIT_OBJECT_0)
+ << "Failed to join the thread with error " << ::GetLastError() << ".";
+}
+
+// Maps a thread to a set of ThreadIdToThreadLocals that have values
+// instantiated on that thread and notifies them when the thread exits. A
+// ThreadLocal instance is expected to persist until all threads it has
+// values on have terminated.
+class ThreadLocalRegistryImpl {
+ public:
+ // Registers thread_local_instance as having value on the current thread.
+ // Returns a value that can be used to identify the thread from other threads.
+ static ThreadLocalValueHolderBase* GetValueOnCurrentThread(
+ const ThreadLocalBase* thread_local_instance) {
+ DWORD current_thread = ::GetCurrentThreadId();
+ MutexLock lock(&mutex_);
+ ThreadIdToThreadLocals* const thread_to_thread_locals =
+ GetThreadLocalsMapLocked();
+ ThreadIdToThreadLocals::iterator thread_local_pos =
+ thread_to_thread_locals->find(current_thread);
+ if (thread_local_pos == thread_to_thread_locals->end()) {
+ thread_local_pos = thread_to_thread_locals->insert(
+ std::make_pair(current_thread, ThreadLocalValues())).first;
+ StartWatcherThreadFor(current_thread);
+ }
+ ThreadLocalValues& thread_local_values = thread_local_pos->second;
+ ThreadLocalValues::iterator value_pos =
+ thread_local_values.find(thread_local_instance);
+ if (value_pos == thread_local_values.end()) {
+ value_pos =
+ thread_local_values
+ .insert(std::make_pair(
+ thread_local_instance,
+ linked_ptr<ThreadLocalValueHolderBase>(
+ thread_local_instance->NewValueForCurrentThread())))
+ .first;
+ }
+ return value_pos->second.get();
+ }
+
+ static void OnThreadLocalDestroyed(
+ const ThreadLocalBase* thread_local_instance) {
+ std::vector<linked_ptr<ThreadLocalValueHolderBase> > value_holders;
+ // Clean up the ThreadLocalValues data structure while holding the lock, but
+ // defer the destruction of the ThreadLocalValueHolderBases.
+ {
+ MutexLock lock(&mutex_);
+ ThreadIdToThreadLocals* const thread_to_thread_locals =
+ GetThreadLocalsMapLocked();
+ for (ThreadIdToThreadLocals::iterator it =
+ thread_to_thread_locals->begin();
+ it != thread_to_thread_locals->end();
+ ++it) {
+ ThreadLocalValues& thread_local_values = it->second;
+ ThreadLocalValues::iterator value_pos =
+ thread_local_values.find(thread_local_instance);
+ if (value_pos != thread_local_values.end()) {
+ value_holders.push_back(value_pos->second);
+ thread_local_values.erase(value_pos);
+ // This 'if' can only be successful at most once, so theoretically we
+ // could break out of the loop here, but we don't bother doing so.
+ }
+ }
+ }
+ // Outside the lock, let the destructor for 'value_holders' deallocate the
+ // ThreadLocalValueHolderBases.
+ }
+
+ static void OnThreadExit(DWORD thread_id) {
+ GTEST_CHECK_(thread_id != 0) << ::GetLastError();
+ std::vector<linked_ptr<ThreadLocalValueHolderBase> > value_holders;
+ // Clean up the ThreadIdToThreadLocals data structure while holding the
+ // lock, but defer the destruction of the ThreadLocalValueHolderBases.
+ {
+ MutexLock lock(&mutex_);
+ ThreadIdToThreadLocals* const thread_to_thread_locals =
+ GetThreadLocalsMapLocked();
+ ThreadIdToThreadLocals::iterator thread_local_pos =
+ thread_to_thread_locals->find(thread_id);
+ if (thread_local_pos != thread_to_thread_locals->end()) {
+ ThreadLocalValues& thread_local_values = thread_local_pos->second;
+ for (ThreadLocalValues::iterator value_pos =
+ thread_local_values.begin();
+ value_pos != thread_local_values.end();
+ ++value_pos) {
+ value_holders.push_back(value_pos->second);
+ }
+ thread_to_thread_locals->erase(thread_local_pos);
+ }
+ }
+ // Outside the lock, let the destructor for 'value_holders' deallocate the
+ // ThreadLocalValueHolderBases.
+ }
+
+ private:
+ // In a particular thread, maps a ThreadLocal object to its value.
+ typedef std::map<const ThreadLocalBase*,
+ linked_ptr<ThreadLocalValueHolderBase> > ThreadLocalValues;
+ // Stores all ThreadIdToThreadLocals having values in a thread, indexed by
+ // thread's ID.
+ typedef std::map<DWORD, ThreadLocalValues> ThreadIdToThreadLocals;
+
+ // Holds the thread id and thread handle that we pass from
+ // StartWatcherThreadFor to WatcherThreadFunc.
+ typedef std::pair<DWORD, HANDLE> ThreadIdAndHandle;
+
+ static void StartWatcherThreadFor(DWORD thread_id) {
+ // The returned handle will be kept in thread_map and closed by
+ // watcher_thread in WatcherThreadFunc.
+ HANDLE thread = ::OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION,
+ FALSE,
+ thread_id);
+ GTEST_CHECK_(thread != NULL);
+ // We need to to pass a valid thread ID pointer into CreateThread for it
+ // to work correctly under Win98.
+ DWORD watcher_thread_id;
+ HANDLE watcher_thread = ::CreateThread(
+ NULL, // Default security.
+ 0, // Default stack size
+ &ThreadLocalRegistryImpl::WatcherThreadFunc,
+ reinterpret_cast<LPVOID>(new ThreadIdAndHandle(thread_id, thread)),
+ CREATE_SUSPENDED,
+ &watcher_thread_id);
+ GTEST_CHECK_(watcher_thread != NULL);
+ // Give the watcher thread the same priority as ours to avoid being
+ // blocked by it.
+ ::SetThreadPriority(watcher_thread,
+ ::GetThreadPriority(::GetCurrentThread()));
+ ::ResumeThread(watcher_thread);
+ ::CloseHandle(watcher_thread);
+ }
+
+ // Monitors exit from a given thread and notifies those
+ // ThreadIdToThreadLocals about thread termination.
+ static DWORD WINAPI WatcherThreadFunc(LPVOID param) {
+ const ThreadIdAndHandle* tah =
+ reinterpret_cast<const ThreadIdAndHandle*>(param);
+ GTEST_CHECK_(
+ ::WaitForSingleObject(tah->second, INFINITE) == WAIT_OBJECT_0);
+ OnThreadExit(tah->first);
+ ::CloseHandle(tah->second);
+ delete tah;
+ return 0;
+ }
+
+ // Returns map of thread local instances.
+ static ThreadIdToThreadLocals* GetThreadLocalsMapLocked() {
+ mutex_.AssertHeld();
+ static ThreadIdToThreadLocals* map = new ThreadIdToThreadLocals;
+ return map;
+ }
+
+ // Protects access to GetThreadLocalsMapLocked() and its return value.
+ static Mutex mutex_;
+ // Protects access to GetThreadMapLocked() and its return value.
+ static Mutex thread_map_mutex_;
+};
+
+Mutex ThreadLocalRegistryImpl::mutex_(Mutex::kStaticMutex);
+Mutex ThreadLocalRegistryImpl::thread_map_mutex_(Mutex::kStaticMutex);
+
+ThreadLocalValueHolderBase* ThreadLocalRegistry::GetValueOnCurrentThread(
+ const ThreadLocalBase* thread_local_instance) {
+ return ThreadLocalRegistryImpl::GetValueOnCurrentThread(
+ thread_local_instance);
+}
+
+void ThreadLocalRegistry::OnThreadLocalDestroyed(
+ const ThreadLocalBase* thread_local_instance) {
+ ThreadLocalRegistryImpl::OnThreadLocalDestroyed(thread_local_instance);
+}
+
+#endif // GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS
#if GTEST_USES_POSIX_RE
@@ -481,7 +905,6 @@ GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(
return file_name + ":" + StreamableToString(line);
}
-
GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line)
: severity_(severity) {
const char* const marker =
@@ -502,10 +925,7 @@ GTestLog::~GTestLog() {
}
// Disable Microsoft deprecation warnings for POSIX functions called from
// this class (creat, dup, dup2, and close)
-#ifdef _MSC_VER
-# pragma warning(push)
-# pragma warning(disable: 4996)
-#endif // _MSC_VER
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996)
#if GTEST_HAS_STREAM_REDIRECTION
@@ -581,12 +1001,6 @@ class CapturedStream {
}
private:
- // Reads the entire content of a file as an std::string.
- static std::string ReadEntireFile(FILE* file);
-
- // Returns the size (in bytes) of a file.
- static size_t GetFileSize(FILE* file);
-
const int fd_; // A stream to capture.
int uncaptured_fd_;
// Name of the temporary file holding the stderr output.
@@ -595,38 +1009,7 @@ class CapturedStream {
GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream);
};
-// Returns the size (in bytes) of a file.
-size_t CapturedStream::GetFileSize(FILE* file) {
- fseek(file, 0, SEEK_END);
- return static_cast<size_t>(ftell(file));
-}
-
-// Reads the entire content of a file as a string.
-std::string CapturedStream::ReadEntireFile(FILE* file) {
- const size_t file_size = GetFileSize(file);
- char* const buffer = new char[file_size];
-
- size_t bytes_last_read = 0; // # of bytes read in the last fread()
- size_t bytes_read = 0; // # of bytes read so far
-
- fseek(file, 0, SEEK_SET);
-
- // Keeps reading the file until we cannot read further or the
- // pre-determined file size is reached.
- do {
- bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file);
- bytes_read += bytes_last_read;
- } while (bytes_last_read > 0 && bytes_read < file_size);
-
- const std::string content(buffer, bytes_read);
- delete[] buffer;
-
- return content;
-}
-
-# ifdef _MSC_VER
-# pragma warning(pop)
-# endif // _MSC_VER
+GTEST_DISABLE_MSC_WARNINGS_POP_()
static CapturedStream* g_captured_stderr = NULL;
static CapturedStream* g_captured_stdout = NULL;
@@ -672,10 +1055,52 @@ std::string GetCapturedStderr() {
#endif // GTEST_HAS_STREAM_REDIRECTION
-#if GTEST_HAS_DEATH_TEST
+std::string TempDir() {
+#if GTEST_OS_WINDOWS_MOBILE
+ return "\\temp\\";
+#elif GTEST_OS_WINDOWS
+ const char* temp_dir = posix::GetEnv("TEMP");
+ if (temp_dir == NULL || temp_dir[0] == '\0')
+ return "\\temp\\";
+ else if (temp_dir[strlen(temp_dir) - 1] == '\\')
+ return temp_dir;
+ else
+ return std::string(temp_dir) + "\\";
+#elif GTEST_OS_LINUX_ANDROID
+ return "/sdcard/";
+#else
+ return "/tmp/";
+#endif // GTEST_OS_WINDOWS_MOBILE
+}
+
+size_t GetFileSize(FILE* file) {
+ fseek(file, 0, SEEK_END);
+ return static_cast<size_t>(ftell(file));
+}
+
+std::string ReadEntireFile(FILE* file) {
+ const size_t file_size = GetFileSize(file);
+ char* const buffer = new char[file_size];
+
+ size_t bytes_last_read = 0; // # of bytes read in the last fread()
+ size_t bytes_read = 0; // # of bytes read so far
+
+ fseek(file, 0, SEEK_SET);
+
+ // Keeps reading the file until we cannot read further or the
+ // pre-determined file size is reached.
+ do {
+ bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file);
+ bytes_read += bytes_last_read;
+ } while (bytes_last_read > 0 && bytes_read < file_size);
+
+ const std::string content(buffer, bytes_read);
+ delete[] buffer;
+
+ return content;
+}
-// A copy of all command line arguments. Set by InitGoogleTest().
-::std::vector<testing::internal::string> g_argvs;
+#if GTEST_HAS_DEATH_TEST
static const ::std::vector<testing::internal::string>* g_injected_test_argvs =
NULL; // Owned.
@@ -690,7 +1115,7 @@ const ::std::vector<testing::internal::string>& GetInjectableArgvs() {
if (g_injected_test_argvs != NULL) {
return *g_injected_test_argvs;
}
- return g_argvs;
+ return GetArgvs();
}
#endif // GTEST_HAS_DEATH_TEST
@@ -764,6 +1189,9 @@ bool ParseInt32(const Message& src_text, const char* str, Int32* value) {
//
// The value is considered true iff it's not "0".
bool BoolFromGTestEnv(const char* flag, bool default_value) {
+#if defined(GTEST_GET_BOOL_FROM_ENV_)
+ return GTEST_GET_BOOL_FROM_ENV_(flag, default_value);
+#endif // defined(GTEST_GET_BOOL_FROM_ENV_)
const std::string env_var = FlagToEnvVar(flag);
const char* const string_value = posix::GetEnv(env_var.c_str());
return string_value == NULL ?
@@ -774,6 +1202,9 @@ bool BoolFromGTestEnv(const char* flag, bool default_value) {
// variable corresponding to the given flag; if it isn't set or
// doesn't represent a valid 32-bit integer, returns default_value.
Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) {
+#if defined(GTEST_GET_INT32_FROM_ENV_)
+ return GTEST_GET_INT32_FROM_ENV_(flag, default_value);
+#endif // defined(GTEST_GET_INT32_FROM_ENV_)
const std::string env_var = FlagToEnvVar(flag);
const char* const string_value = posix::GetEnv(env_var.c_str());
if (string_value == NULL) {
@@ -795,10 +1226,33 @@ Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) {
// Reads and returns the string environment variable corresponding to
// the given flag; if it's not set, returns default_value.
-const char* StringFromGTestEnv(const char* flag, const char* default_value) {
+std::string StringFromGTestEnv(const char* flag, const char* default_value) {
+#if defined(GTEST_GET_STRING_FROM_ENV_)
+ return GTEST_GET_STRING_FROM_ENV_(flag, default_value);
+#endif // defined(GTEST_GET_STRING_FROM_ENV_)
const std::string env_var = FlagToEnvVar(flag);
- const char* const value = posix::GetEnv(env_var.c_str());
- return value == NULL ? default_value : value;
+ const char* value = posix::GetEnv(env_var.c_str());
+ if (value != NULL) {
+ return value;
+ }
+
+ // As a special case for the 'output' flag, if GTEST_OUTPUT is not
+ // set, we look for XML_OUTPUT_FILE, which is set by the Bazel build
+ // system. The value of XML_OUTPUT_FILE is a filename without the
+ // "xml:" prefix of GTEST_OUTPUT.
+ //
+ // The net priority order after flag processing is thus:
+ // --gtest_output command line flag
+ // GTEST_OUTPUT environment variable
+ // XML_OUTPUT_FILE environment variable
+ // 'default_value'
+ if (strcmp(flag, "output") == 0) {
+ value = posix::GetEnv("XML_OUTPUT_FILE");
+ if (value != NULL) {
+ return std::string("xml:") + value;
+ }
+ }
+ return default_value;
}
} // namespace internal
diff --git a/extern/gtest/src/gtest-printers.cc b/extern/gtest/src/gtest-printers.cc
index 75fa4081009..a2df412f8a2 100644
--- a/extern/gtest/src/gtest-printers.cc
+++ b/extern/gtest/src/gtest-printers.cc
@@ -45,6 +45,7 @@
#include "gtest/gtest-printers.h"
#include <ctype.h>
#include <stdio.h>
+#include <cwchar>
#include <ostream> // NOLINT
#include <string>
#include "gtest/internal/gtest-port.h"
@@ -56,6 +57,9 @@ namespace {
using ::std::ostream;
// Prints a segment of bytes in the given object.
+GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
+GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start,
size_t count, ostream* os) {
char text[5] = "";
@@ -252,6 +256,9 @@ void PrintTo(wchar_t wc, ostream* os) {
// The array starts at begin, the length is len, it may include '\0' characters
// and may not be NUL-terminated.
template <typename CharType>
+GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
+GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
static void PrintCharsAsStringTo(
const CharType* begin, size_t len, ostream* os) {
const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\"";
@@ -273,6 +280,9 @@ static void PrintCharsAsStringTo(
// Prints a (const) char/wchar_t array of 'len' elements, starting at address
// 'begin'. CharType must be either char or wchar_t.
template <typename CharType>
+GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
+GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
static void UniversalPrintCharArray(
const CharType* begin, size_t len, ostream* os) {
// The code
@@ -329,7 +339,7 @@ void PrintTo(const wchar_t* s, ostream* os) {
*os << "NULL";
} else {
*os << ImplicitCast_<const void*>(s) << " pointing to ";
- PrintCharsAsStringTo(s, wcslen(s), os);
+ PrintCharsAsStringTo(s, std::wcslen(s), os);
}
}
#endif // wchar_t is native
diff --git a/extern/gtest/src/gtest-test-part.cc b/extern/gtest/src/gtest-test-part.cc
index c60eef3ab35..fb0e35425e1 100644
--- a/extern/gtest/src/gtest-test-part.cc
+++ b/extern/gtest/src/gtest-test-part.cc
@@ -35,9 +35,9 @@
// Indicates that this translation unit is part of Google Test's
// implementation. It must come before gtest-internal-inl.h is
-// included, or there will be a compiler error. This trick is to
-// prevent a user from accidentally including gtest-internal-inl.h in
-// his code.
+// included, or there will be a compiler error. This trick exists to
+// prevent the accidental inclusion of gtest-internal-inl.h in the
+// user's code.
#define GTEST_IMPLEMENTATION_ 1
#include "src/gtest-internal-inl.h"
#undef GTEST_IMPLEMENTATION_
diff --git a/extern/gtest/src/gtest-typed-test.cc b/extern/gtest/src/gtest-typed-test.cc
index f0079f407c5..df1eef4754e 100644
--- a/extern/gtest/src/gtest-typed-test.cc
+++ b/extern/gtest/src/gtest-typed-test.cc
@@ -45,33 +45,41 @@ static const char* SkipSpaces(const char* str) {
return str;
}
+static std::vector<std::string> SplitIntoTestNames(const char* src) {
+ std::vector<std::string> name_vec;
+ src = SkipSpaces(src);
+ for (; src != NULL; src = SkipComma(src)) {
+ name_vec.push_back(StripTrailingSpaces(GetPrefixUntilComma(src)));
+ }
+ return name_vec;
+}
+
// Verifies that registered_tests match the test names in
-// defined_test_names_; returns registered_tests if successful, or
+// registered_tests_; returns registered_tests if successful, or
// aborts the program otherwise.
const char* TypedTestCasePState::VerifyRegisteredTestNames(
const char* file, int line, const char* registered_tests) {
- typedef ::std::set<const char*>::const_iterator DefinedTestIter;
+ typedef RegisteredTestsMap::const_iterator RegisteredTestIter;
registered_ = true;
- // Skip initial whitespace in registered_tests since some
- // preprocessors prefix stringizied literals with whitespace.
- registered_tests = SkipSpaces(registered_tests);
+ std::vector<std::string> name_vec = SplitIntoTestNames(registered_tests);
Message errors;
- ::std::set<std::string> tests;
- for (const char* names = registered_tests; names != NULL;
- names = SkipComma(names)) {
- const std::string name = GetPrefixUntilComma(names);
+
+ std::set<std::string> tests;
+ for (std::vector<std::string>::const_iterator name_it = name_vec.begin();
+ name_it != name_vec.end(); ++name_it) {
+ const std::string& name = *name_it;
if (tests.count(name) != 0) {
errors << "Test " << name << " is listed more than once.\n";
continue;
}
bool found = false;
- for (DefinedTestIter it = defined_test_names_.begin();
- it != defined_test_names_.end();
+ for (RegisteredTestIter it = registered_tests_.begin();
+ it != registered_tests_.end();
++it) {
- if (name == *it) {
+ if (name == it->first) {
found = true;
break;
}
@@ -85,11 +93,11 @@ const char* TypedTestCasePState::VerifyRegisteredTestNames(
}
}
- for (DefinedTestIter it = defined_test_names_.begin();
- it != defined_test_names_.end();
+ for (RegisteredTestIter it = registered_tests_.begin();
+ it != registered_tests_.end();
++it) {
- if (tests.count(*it) == 0) {
- errors << "You forgot to list test " << *it << ".\n";
+ if (tests.count(it->first) == 0) {
+ errors << "You forgot to list test " << it->first << ".\n";
}
}
diff --git a/extern/gtest/src/gtest.cc b/extern/gtest/src/gtest.cc
index 6de53dd0198..d882ab2e36a 100644
--- a/extern/gtest/src/gtest.cc
+++ b/extern/gtest/src/gtest.cc
@@ -32,6 +32,7 @@
// The Google C++ Testing Framework (Google Test)
#include "gtest/gtest.h"
+#include "gtest/internal/custom/gtest.h"
#include "gtest/gtest-spi.h"
#include <ctype.h>
@@ -46,6 +47,8 @@
#include <algorithm>
#include <iomanip>
#include <limits>
+#include <list>
+#include <map>
#include <ostream> // NOLINT
#include <sstream>
#include <vector>
@@ -80,6 +83,7 @@
#elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE.
# include <windows.h> // NOLINT
+# undef min
#elif GTEST_OS_WINDOWS // We are on Windows proper.
@@ -102,6 +106,7 @@
// cpplint thinks that the header is already included, so we want to
// silence it.
# include <windows.h> // NOLINT
+# undef min
#else
@@ -124,6 +129,8 @@
#if GTEST_CAN_STREAM_RESULTS_
# include <arpa/inet.h> // NOLINT
# include <netdb.h> // NOLINT
+# include <sys/socket.h> // NOLINT
+# include <sys/types.h> // NOLINT
#endif
// Indicates that this translation unit is part of Google Test's
@@ -183,6 +190,12 @@ bool g_help_flag = false;
} // namespace internal
static const char* GetDefaultFilter() {
+#ifdef GTEST_TEST_FILTER_ENV_VAR_
+ const char* const testbridge_test_only = getenv(GTEST_TEST_FILTER_ENV_VAR_);
+ if (testbridge_test_only != NULL) {
+ return testbridge_test_only;
+ }
+#endif // GTEST_TEST_FILTER_ENV_VAR_
return kUniversalFilter;
}
@@ -283,6 +296,13 @@ GTEST_DEFINE_bool_(
"if exceptions are enabled or exit the program with a non-zero code "
"otherwise.");
+#if GTEST_USE_OWN_FLAGFILE_FLAG_
+GTEST_DEFINE_string_(
+ flagfile,
+ internal::StringFromGTestEnv("flagfile", ""),
+ "This flag specifies the flagfile to read command-line flags from.");
+#endif // GTEST_USE_OWN_FLAGFILE_FLAG_
+
namespace internal {
// Generates a random number from [0, range), using a Linear
@@ -307,13 +327,7 @@ UInt32 Random::Generate(UInt32 range) {
// GTestIsInitialized() returns true iff the user has initialized
// Google Test. Useful for catching the user mistake of not initializing
// Google Test before calling RUN_ALL_TESTS().
-//
-// A user must call testing::InitGoogleTest() to initialize Google
-// Test. g_init_gtest_count is set to the number of times
-// InitGoogleTest() has been called. We don't protect this variable
-// under a mutex as it is only accessed in the main thread.
-GTEST_API_ int g_init_gtest_count = 0;
-static bool GTestIsInitialized() { return g_init_gtest_count != 0; }
+static bool GTestIsInitialized() { return GetArgvs().size() > 0; }
// Iterates over a vector of TestCases, keeping a running sum of the
// results of calling a given int-returning method on each.
@@ -369,8 +383,16 @@ void AssertHelper::operator=(const Message& message) const {
// Mutex for linked pointers.
GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex);
-// Application pathname gotten in InitGoogleTest.
-std::string g_executable_path;
+// A copy of all command line arguments. Set by InitGoogleTest().
+::std::vector<testing::internal::string> g_argvs;
+
+const ::std::vector<testing::internal::string>& GetArgvs() {
+#if defined(GTEST_CUSTOM_GET_ARGVS_)
+ return GTEST_CUSTOM_GET_ARGVS_();
+#else // defined(GTEST_CUSTOM_GET_ARGVS_)
+ return g_argvs;
+#endif // defined(GTEST_CUSTOM_GET_ARGVS_)
+}
// Returns the current application's name, removing directory path if that
// is present.
@@ -378,9 +400,9 @@ FilePath GetCurrentExecutableName() {
FilePath result;
#if GTEST_OS_WINDOWS
- result.Set(FilePath(g_executable_path).RemoveExtension("exe"));
+ result.Set(FilePath(GetArgvs()[0]).RemoveExtension("exe"));
#else
- result.Set(FilePath(g_executable_path));
+ result.Set(FilePath(GetArgvs()[0]));
#endif // GTEST_OS_WINDOWS
return result.RemoveDirectoryName();
@@ -772,8 +794,12 @@ int UnitTestImpl::test_to_run_count() const {
// CurrentOsStackTraceExceptTop(1), Foo() will be included in the
// trace but Bar() and CurrentOsStackTraceExceptTop() won't.
std::string UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) {
- (void)skip_count;
- return "";
+ return os_stack_trace_getter()->CurrentStackTrace(
+ static_cast<int>(GTEST_FLAG(stack_trace_depth)),
+ skip_count + 1
+ // Skips the user-specified number of frames plus this function
+ // itself.
+ ); // NOLINT
}
// Returns the current time in milliseconds.
@@ -802,21 +828,13 @@ TimeInMillis GetTimeInMillis() {
#elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_
__timeb64 now;
-# ifdef _MSC_VER
-
// MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996
// (deprecated function) there.
// TODO(kenton@google.com): Use GetTickCount()? Or use
// SystemTimeToFileTime()
-# pragma warning(push) // Saves the current warning state.
-# pragma warning(disable:4996) // Temporarily disables warning 4996.
- _ftime64(&now);
-# pragma warning(pop) // Restores the warning state.
-# else
-
+ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996)
_ftime64(&now);
-
-# endif // _MSC_VER
+ GTEST_DISABLE_MSC_WARNINGS_POP_()
return static_cast<TimeInMillis>(now.time) * 1000 + now.millitm;
#elif GTEST_HAS_GETTIMEOFDAY_
@@ -901,6 +919,23 @@ static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length,
#endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING
+void SplitString(const ::std::string& str, char delimiter,
+ ::std::vector< ::std::string>* dest) {
+ ::std::vector< ::std::string> parsed;
+ ::std::string::size_type pos = 0;
+ while (::testing::internal::AlwaysTrue()) {
+ const ::std::string::size_type colon = str.find(delimiter, pos);
+ if (colon == ::std::string::npos) {
+ parsed.push_back(str.substr(pos));
+ break;
+ } else {
+ parsed.push_back(str.substr(pos, colon - pos));
+ pos = colon + 1;
+ }
+ }
+ dest->swap(parsed);
+}
+
} // namespace internal
// Constructs an empty Message.
@@ -956,6 +991,13 @@ AssertionResult::AssertionResult(const AssertionResult& other)
static_cast< ::std::string*>(NULL)) {
}
+// Swaps two AssertionResults.
+void AssertionResult::swap(AssertionResult& other) {
+ using std::swap;
+ swap(success_, other.success_);
+ swap(message_, other.message_);
+}
+
// Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE.
AssertionResult AssertionResult::operator!() const {
AssertionResult negation(!success_);
@@ -982,6 +1024,276 @@ AssertionResult AssertionFailure(const Message& message) {
namespace internal {
+namespace edit_distance {
+std::vector<EditType> CalculateOptimalEdits(const std::vector<size_t>& left,
+ const std::vector<size_t>& right) {
+ std::vector<std::vector<double> > costs(
+ left.size() + 1, std::vector<double>(right.size() + 1));
+ std::vector<std::vector<EditType> > best_move(
+ left.size() + 1, std::vector<EditType>(right.size() + 1));
+
+ // Populate for empty right.
+ for (size_t l_i = 0; l_i < costs.size(); ++l_i) {
+ costs[l_i][0] = static_cast<double>(l_i);
+ best_move[l_i][0] = kRemove;
+ }
+ // Populate for empty left.
+ for (size_t r_i = 1; r_i < costs[0].size(); ++r_i) {
+ costs[0][r_i] = static_cast<double>(r_i);
+ best_move[0][r_i] = kAdd;
+ }
+
+ for (size_t l_i = 0; l_i < left.size(); ++l_i) {
+ for (size_t r_i = 0; r_i < right.size(); ++r_i) {
+ if (left[l_i] == right[r_i]) {
+ // Found a match. Consume it.
+ costs[l_i + 1][r_i + 1] = costs[l_i][r_i];
+ best_move[l_i + 1][r_i + 1] = kMatch;
+ continue;
+ }
+
+ const double add = costs[l_i + 1][r_i];
+ const double remove = costs[l_i][r_i + 1];
+ const double replace = costs[l_i][r_i];
+ if (add < remove && add < replace) {
+ costs[l_i + 1][r_i + 1] = add + 1;
+ best_move[l_i + 1][r_i + 1] = kAdd;
+ } else if (remove < add && remove < replace) {
+ costs[l_i + 1][r_i + 1] = remove + 1;
+ best_move[l_i + 1][r_i + 1] = kRemove;
+ } else {
+ // We make replace a little more expensive than add/remove to lower
+ // their priority.
+ costs[l_i + 1][r_i + 1] = replace + 1.00001;
+ best_move[l_i + 1][r_i + 1] = kReplace;
+ }
+ }
+ }
+
+ // Reconstruct the best path. We do it in reverse order.
+ std::vector<EditType> best_path;
+ for (size_t l_i = left.size(), r_i = right.size(); l_i > 0 || r_i > 0;) {
+ EditType move = best_move[l_i][r_i];
+ best_path.push_back(move);
+ l_i -= move != kAdd;
+ r_i -= move != kRemove;
+ }
+ std::reverse(best_path.begin(), best_path.end());
+ return best_path;
+}
+
+namespace {
+
+// Helper class to convert string into ids with deduplication.
+class InternalStrings {
+ public:
+ size_t GetId(const std::string& str) {
+ IdMap::iterator it = ids_.find(str);
+ if (it != ids_.end()) return it->second;
+ size_t id = ids_.size();
+ return ids_[str] = id;
+ }
+
+ private:
+ typedef std::map<std::string, size_t> IdMap;
+ IdMap ids_;
+};
+
+} // namespace
+
+std::vector<EditType> CalculateOptimalEdits(
+ const std::vector<std::string>& left,
+ const std::vector<std::string>& right) {
+ std::vector<size_t> left_ids, right_ids;
+ {
+ InternalStrings intern_table;
+ for (size_t i = 0; i < left.size(); ++i) {
+ left_ids.push_back(intern_table.GetId(left[i]));
+ }
+ for (size_t i = 0; i < right.size(); ++i) {
+ right_ids.push_back(intern_table.GetId(right[i]));
+ }
+ }
+ return CalculateOptimalEdits(left_ids, right_ids);
+}
+
+namespace {
+
+// Helper class that holds the state for one hunk and prints it out to the
+// stream.
+// It reorders adds/removes when possible to group all removes before all
+// adds. It also adds the hunk header before printint into the stream.
+class Hunk {
+ public:
+ Hunk(size_t left_start, size_t right_start)
+ : left_start_(left_start),
+ right_start_(right_start),
+ adds_(),
+ removes_(),
+ common_() {}
+
+ void PushLine(char edit, const char* line) {
+ switch (edit) {
+ case ' ':
+ ++common_;
+ FlushEdits();
+ hunk_.push_back(std::make_pair(' ', line));
+ break;
+ case '-':
+ ++removes_;
+ hunk_removes_.push_back(std::make_pair('-', line));
+ break;
+ case '+':
+ ++adds_;
+ hunk_adds_.push_back(std::make_pair('+', line));
+ break;
+ }
+ }
+
+ void PrintTo(std::ostream* os) {
+ PrintHeader(os);
+ FlushEdits();
+ for (std::list<std::pair<char, const char*> >::const_iterator it =
+ hunk_.begin();
+ it != hunk_.end(); ++it) {
+ *os << it->first << it->second << "\n";
+ }
+ }
+
+ bool has_edits() const { return adds_ || removes_; }
+
+ private:
+ void FlushEdits() {
+ hunk_.splice(hunk_.end(), hunk_removes_);
+ hunk_.splice(hunk_.end(), hunk_adds_);
+ }
+
+ // Print a unified diff header for one hunk.
+ // The format is
+ // "@@ -<left_start>,<left_length> +<right_start>,<right_length> @@"
+ // where the left/right parts are ommitted if unnecessary.
+ void PrintHeader(std::ostream* ss) const {
+ *ss << "@@ ";
+ if (removes_) {
+ *ss << "-" << left_start_ << "," << (removes_ + common_);
+ }
+ if (removes_ && adds_) {
+ *ss << " ";
+ }
+ if (adds_) {
+ *ss << "+" << right_start_ << "," << (adds_ + common_);
+ }
+ *ss << " @@\n";
+ }
+
+ size_t left_start_, right_start_;
+ size_t adds_, removes_, common_;
+ std::list<std::pair<char, const char*> > hunk_, hunk_adds_, hunk_removes_;
+};
+
+} // namespace
+
+// Create a list of diff hunks in Unified diff format.
+// Each hunk has a header generated by PrintHeader above plus a body with
+// lines prefixed with ' ' for no change, '-' for deletion and '+' for
+// addition.
+// 'context' represents the desired unchanged prefix/suffix around the diff.
+// If two hunks are close enough that their contexts overlap, then they are
+// joined into one hunk.
+std::string CreateUnifiedDiff(const std::vector<std::string>& left,
+ const std::vector<std::string>& right,
+ size_t context) {
+ const std::vector<EditType> edits = CalculateOptimalEdits(left, right);
+
+ size_t l_i = 0, r_i = 0, edit_i = 0;
+ std::stringstream ss;
+ while (edit_i < edits.size()) {
+ // Find first edit.
+ while (edit_i < edits.size() && edits[edit_i] == kMatch) {
+ ++l_i;
+ ++r_i;
+ ++edit_i;
+ }
+
+ // Find the first line to include in the hunk.
+ const size_t prefix_context = std::min(l_i, context);
+ Hunk hunk(l_i - prefix_context + 1, r_i - prefix_context + 1);
+ for (size_t i = prefix_context; i > 0; --i) {
+ hunk.PushLine(' ', left[l_i - i].c_str());
+ }
+
+ // Iterate the edits until we found enough suffix for the hunk or the input
+ // is over.
+ size_t n_suffix = 0;
+ for (; edit_i < edits.size(); ++edit_i) {
+ if (n_suffix >= context) {
+ // Continue only if the next hunk is very close.
+ std::vector<EditType>::const_iterator it = edits.begin() + edit_i;
+ while (it != edits.end() && *it == kMatch) ++it;
+ if (it == edits.end() || (it - edits.begin()) - edit_i >= context) {
+ // There is no next edit or it is too far away.
+ break;
+ }
+ }
+
+ EditType edit = edits[edit_i];
+ // Reset count when a non match is found.
+ n_suffix = edit == kMatch ? n_suffix + 1 : 0;
+
+ if (edit == kMatch || edit == kRemove || edit == kReplace) {
+ hunk.PushLine(edit == kMatch ? ' ' : '-', left[l_i].c_str());
+ }
+ if (edit == kAdd || edit == kReplace) {
+ hunk.PushLine('+', right[r_i].c_str());
+ }
+
+ // Advance indices, depending on edit type.
+ l_i += edit != kAdd;
+ r_i += edit != kRemove;
+ }
+
+ if (!hunk.has_edits()) {
+ // We are done. We don't want this hunk.
+ break;
+ }
+
+ hunk.PrintTo(&ss);
+ }
+ return ss.str();
+}
+
+} // namespace edit_distance
+
+namespace {
+
+// The string representation of the values received in EqFailure() are already
+// escaped. Split them on escaped '\n' boundaries. Leave all other escaped
+// characters the same.
+std::vector<std::string> SplitEscapedString(const std::string& str) {
+ std::vector<std::string> lines;
+ size_t start = 0, end = str.size();
+ if (end > 2 && str[0] == '"' && str[end - 1] == '"') {
+ ++start;
+ --end;
+ }
+ bool escaped = false;
+ for (size_t i = start; i + 1 < end; ++i) {
+ if (escaped) {
+ escaped = false;
+ if (str[i] == 'n') {
+ lines.push_back(str.substr(start, i - start - 1));
+ start = i + 1;
+ }
+ } else {
+ escaped = str[i] == '\\';
+ }
+ }
+ lines.push_back(str.substr(start, end - start));
+ return lines;
+}
+
+} // namespace
+
// Constructs and returns the message for an equality assertion
// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure.
//
@@ -989,31 +1301,42 @@ namespace internal {
// and their values, as strings. For example, for ASSERT_EQ(foo, bar)
// where foo is 5 and bar is 6, we have:
//
-// expected_expression: "foo"
-// actual_expression: "bar"
-// expected_value: "5"
-// actual_value: "6"
+// lhs_expression: "foo"
+// rhs_expression: "bar"
+// lhs_value: "5"
+// rhs_value: "6"
//
// The ignoring_case parameter is true iff the assertion is a
-// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will
+// *_STRCASEEQ*. When it's true, the string "Ignoring case" will
// be inserted into the message.
-AssertionResult EqFailure(const char* expected_expression,
- const char* actual_expression,
- const std::string& expected_value,
- const std::string& actual_value,
+AssertionResult EqFailure(const char* lhs_expression,
+ const char* rhs_expression,
+ const std::string& lhs_value,
+ const std::string& rhs_value,
bool ignoring_case) {
Message msg;
- msg << "Value of: " << actual_expression;
- if (actual_value != actual_expression) {
- msg << "\n Actual: " << actual_value;
+ msg << " Expected: " << lhs_expression;
+ if (lhs_value != lhs_expression) {
+ msg << "\n Which is: " << lhs_value;
+ }
+ msg << "\nTo be equal to: " << rhs_expression;
+ if (rhs_value != rhs_expression) {
+ msg << "\n Which is: " << rhs_value;
}
- msg << "\nExpected: " << expected_expression;
if (ignoring_case) {
- msg << " (ignoring case)";
+ msg << "\nIgnoring case";
}
- if (expected_value != expected_expression) {
- msg << "\nWhich is: " << expected_value;
+
+ if (!lhs_value.empty() && !rhs_value.empty()) {
+ const std::vector<std::string> lhs_lines =
+ SplitEscapedString(lhs_value);
+ const std::vector<std::string> rhs_lines =
+ SplitEscapedString(rhs_value);
+ if (lhs_lines.size() > 1 || rhs_lines.size() > 1) {
+ msg << "\nWith diff:\n"
+ << edit_distance::CreateUnifiedDiff(lhs_lines, rhs_lines);
+ }
}
return AssertionFailure() << msg;
@@ -1111,18 +1434,18 @@ namespace internal {
// The helper function for {ASSERT|EXPECT}_EQ with int or enum
// arguments.
-AssertionResult CmpHelperEQ(const char* expected_expression,
- const char* actual_expression,
- BiggestInt expected,
- BiggestInt actual) {
- if (expected == actual) {
+AssertionResult CmpHelperEQ(const char* lhs_expression,
+ const char* rhs_expression,
+ BiggestInt lhs,
+ BiggestInt rhs) {
+ if (lhs == rhs) {
return AssertionSuccess();
}
- return EqFailure(expected_expression,
- actual_expression,
- FormatForComparisonFailureMessage(expected, actual),
- FormatForComparisonFailureMessage(actual, expected),
+ return EqFailure(lhs_expression,
+ rhs_expression,
+ FormatForComparisonFailureMessage(lhs, rhs),
+ FormatForComparisonFailureMessage(rhs, lhs),
false);
}
@@ -1161,34 +1484,34 @@ GTEST_IMPL_CMP_HELPER_(GT, > )
#undef GTEST_IMPL_CMP_HELPER_
// The helper function for {ASSERT|EXPECT}_STREQ.
-AssertionResult CmpHelperSTREQ(const char* expected_expression,
- const char* actual_expression,
- const char* expected,
- const char* actual) {
- if (String::CStringEquals(expected, actual)) {
+AssertionResult CmpHelperSTREQ(const char* lhs_expression,
+ const char* rhs_expression,
+ const char* lhs,
+ const char* rhs) {
+ if (String::CStringEquals(lhs, rhs)) {
return AssertionSuccess();
}
- return EqFailure(expected_expression,
- actual_expression,
- PrintToString(expected),
- PrintToString(actual),
+ return EqFailure(lhs_expression,
+ rhs_expression,
+ PrintToString(lhs),
+ PrintToString(rhs),
false);
}
// The helper function for {ASSERT|EXPECT}_STRCASEEQ.
-AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression,
- const char* actual_expression,
- const char* expected,
- const char* actual) {
- if (String::CaseInsensitiveCStringEquals(expected, actual)) {
+AssertionResult CmpHelperSTRCASEEQ(const char* lhs_expression,
+ const char* rhs_expression,
+ const char* lhs,
+ const char* rhs) {
+ if (String::CaseInsensitiveCStringEquals(lhs, rhs)) {
return AssertionSuccess();
}
- return EqFailure(expected_expression,
- actual_expression,
- PrintToString(expected),
- PrintToString(actual),
+ return EqFailure(lhs_expression,
+ rhs_expression,
+ PrintToString(lhs),
+ PrintToString(rhs),
true);
}
@@ -1543,18 +1866,18 @@ bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) {
}
// Helper function for *_STREQ on wide strings.
-AssertionResult CmpHelperSTREQ(const char* expected_expression,
- const char* actual_expression,
- const wchar_t* expected,
- const wchar_t* actual) {
- if (String::WideCStringEquals(expected, actual)) {
+AssertionResult CmpHelperSTREQ(const char* lhs_expression,
+ const char* rhs_expression,
+ const wchar_t* lhs,
+ const wchar_t* rhs) {
+ if (String::WideCStringEquals(lhs, rhs)) {
return AssertionSuccess();
}
- return EqFailure(expected_expression,
- actual_expression,
- PrintToString(expected),
- PrintToString(actual),
+ return EqFailure(lhs_expression,
+ rhs_expression,
+ PrintToString(lhs),
+ PrintToString(rhs),
false);
}
@@ -1887,14 +2210,15 @@ int TestResult::test_property_count() const {
// Creates a Test object.
-// The c'tor saves the values of all Google Test flags.
+// The c'tor saves the states of all flags.
Test::Test()
- : gtest_flag_saver_(new internal::GTestFlagSaver) {
+ : gtest_flag_saver_(new GTEST_FLAG_SAVER_) {
}
-// The d'tor restores the values of all Google Test flags.
+// The d'tor restores the states of all flags. The actual work is
+// done by the d'tor of the gtest_flag_saver_ field, and thus not
+// visible here.
Test::~Test() {
- delete gtest_flag_saver_;
}
// Sets up the test fixture.
@@ -1963,8 +2287,8 @@ bool Test::HasSameFixtureClass() {
const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId();
if (first_is_TEST || this_is_TEST) {
- // The user mixed TEST and TEST_F in this test case - we'll tell
- // him/her how to fix it.
+ // Both TEST and TEST_F appear in same test case, which is incorrect.
+ // Tell the user how to fix this.
// Gets the name of the TEST and the name of the TEST_F. Note
// that first_is_TEST and this_is_TEST cannot both be true, as
@@ -1984,8 +2308,8 @@ bool Test::HasSameFixtureClass() {
<< "want to change the TEST to TEST_F or move it to another test\n"
<< "case.";
} else {
- // The user defined two fixture classes with the same name in
- // two namespaces - we'll tell him/her how to fix it.
+ // Two fixture classes with the same name appear in two different
+ // namespaces, which is not allowed. Tell the user how to fix this.
ADD_FAILURE()
<< "All tests in the same test case must use the same test fixture\n"
<< "class. However, in test case "
@@ -2178,12 +2502,14 @@ TestInfo::TestInfo(const std::string& a_test_case_name,
const std::string& a_name,
const char* a_type_param,
const char* a_value_param,
+ internal::CodeLocation a_code_location,
internal::TypeId fixture_class_id,
internal::TestFactoryBase* factory)
: test_case_name_(a_test_case_name),
name_(a_name),
type_param_(a_type_param ? new std::string(a_type_param) : NULL),
value_param_(a_value_param ? new std::string(a_value_param) : NULL),
+ location_(a_code_location),
fixture_class_id_(fixture_class_id),
should_run_(false),
is_disabled_(false),
@@ -2207,6 +2533,7 @@ namespace internal {
// this is not a typed or a type-parameterized test.
// value_param: text representation of the test's value parameter,
// or NULL if this is not a value-parameterized test.
+// code_location: code location where the test is defined
// fixture_class_id: ID of the test fixture class
// set_up_tc: pointer to the function that sets up the test case
// tear_down_tc: pointer to the function that tears down the test case
@@ -2218,20 +2545,21 @@ TestInfo* MakeAndRegisterTestInfo(
const char* name,
const char* type_param,
const char* value_param,
+ CodeLocation code_location,
TypeId fixture_class_id,
SetUpTestCaseFunc set_up_tc,
TearDownTestCaseFunc tear_down_tc,
TestFactoryBase* factory) {
TestInfo* const test_info =
new TestInfo(test_case_name, name, type_param, value_param,
- fixture_class_id, factory);
+ code_location, fixture_class_id, factory);
GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info);
return test_info;
}
#if GTEST_HAS_PARAM_TEST
void ReportInvalidTestCaseType(const char* test_case_name,
- const char* file, int line) {
+ CodeLocation code_location) {
Message errors;
errors
<< "Attempted redefinition of test case " << test_case_name << ".\n"
@@ -2243,7 +2571,9 @@ void ReportInvalidTestCaseType(const char* test_case_name,
<< "probably rename one of the classes to put the tests into different\n"
<< "test cases.";
- fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(),
+ fprintf(stderr, "%s %s",
+ FormatFileLocation(code_location.file.c_str(),
+ code_location.line).c_str(),
errors.GetString().c_str());
}
#endif // GTEST_HAS_PARAM_TEST
@@ -2554,7 +2884,8 @@ enum GTestColor {
COLOR_YELLOW
};
-#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \
+ !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT
// Returns the character attribute for the given color.
WORD GetColorAttribute(GTestColor color) {
@@ -2599,6 +2930,10 @@ bool ShouldUseColor(bool stdout_is_tty) {
String::CStringEquals(term, "xterm-256color") ||
String::CStringEquals(term, "screen") ||
String::CStringEquals(term, "screen-256color") ||
+ String::CStringEquals(term, "tmux") ||
+ String::CStringEquals(term, "tmux-256color") ||
+ String::CStringEquals(term, "rxvt-unicode") ||
+ String::CStringEquals(term, "rxvt-unicode-256color") ||
String::CStringEquals(term, "linux") ||
String::CStringEquals(term, "cygwin");
return stdout_is_tty && term_supports_color;
@@ -2622,8 +2957,9 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
-#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS || GTEST_OS_IOS
- const bool use_color = false;
+#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS || \
+ GTEST_OS_IOS || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT
+ const bool use_color = AlwaysFalse();
#else
static const bool in_color_mode =
ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0);
@@ -2637,7 +2973,8 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) {
return;
}
-#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \
+ !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT
const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
// Gets the current text color.
@@ -3212,34 +3549,39 @@ std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters(
// Formats the given time in milliseconds as seconds.
std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) {
::std::stringstream ss;
- ss << ms/1000.0;
+ ss << (static_cast<double>(ms) * 1e-3);
return ss.str();
}
-// Converts the given epoch time in milliseconds to a date string in the ISO
-// 8601 format, without the timezone information.
-std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) {
- // Using non-reentrant version as localtime_r is not portable.
- time_t seconds = static_cast<time_t>(ms / 1000);
-#ifdef _MSC_VER
-# pragma warning(push) // Saves the current warning state.
-# pragma warning(disable:4996) // Temporarily disables warning 4996
- // (function or variable may be unsafe).
- const struct tm* const time_struct = localtime(&seconds); // NOLINT
-# pragma warning(pop) // Restores the warning state again.
+static bool PortableLocaltime(time_t seconds, struct tm* out) {
+#if defined(_MSC_VER)
+ return localtime_s(out, &seconds) == 0;
+#elif defined(__MINGW32__) || defined(__MINGW64__)
+ // MINGW <time.h> provides neither localtime_r nor localtime_s, but uses
+ // Windows' localtime(), which has a thread-local tm buffer.
+ struct tm* tm_ptr = localtime(&seconds); // NOLINT
+ if (tm_ptr == NULL)
+ return false;
+ *out = *tm_ptr;
+ return true;
#else
- const struct tm* const time_struct = localtime(&seconds); // NOLINT
+ return localtime_r(&seconds, out) != NULL;
#endif
- if (time_struct == NULL)
- return ""; // Invalid ms value
+}
+// Converts the given epoch time in milliseconds to a date string in the ISO
+// 8601 format, without the timezone information.
+std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) {
+ struct tm time_struct;
+ if (!PortableLocaltime(static_cast<time_t>(ms / 1000), &time_struct))
+ return "";
// YYYY-MM-DDThh:mm:ss
- return StreamableToString(time_struct->tm_year + 1900) + "-" +
- String::FormatIntWidth2(time_struct->tm_mon + 1) + "-" +
- String::FormatIntWidth2(time_struct->tm_mday) + "T" +
- String::FormatIntWidth2(time_struct->tm_hour) + ":" +
- String::FormatIntWidth2(time_struct->tm_min) + ":" +
- String::FormatIntWidth2(time_struct->tm_sec);
+ return StreamableToString(time_struct.tm_year + 1900) + "-" +
+ String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" +
+ String::FormatIntWidth2(time_struct.tm_mday) + "T" +
+ String::FormatIntWidth2(time_struct.tm_hour) + ":" +
+ String::FormatIntWidth2(time_struct.tm_min) + ":" +
+ String::FormatIntWidth2(time_struct.tm_sec);
}
// Streams an XML CDATA section, escaping invalid CDATA sequences as needed.
@@ -3502,26 +3844,15 @@ ScopedTrace::~ScopedTrace()
// class OsStackTraceGetter
-// Returns the current OS stack trace as an std::string. Parameters:
-//
-// max_depth - the maximum number of stack frames to be included
-// in the trace.
-// skip_count - the number of top frames to be skipped; doesn't count
-// against max_depth.
-//
-string OsStackTraceGetter::CurrentStackTrace(int /* max_depth */,
- int /* skip_count */)
- GTEST_LOCK_EXCLUDED_(mutex_) {
- return "";
-}
+const char* const OsStackTraceGetterInterface::kElidedFramesMarker =
+ "... " GTEST_NAME_ " internal frames ...";
-void OsStackTraceGetter::UponLeavingGTest()
- GTEST_LOCK_EXCLUDED_(mutex_) {
+string OsStackTraceGetter::CurrentStackTrace(int /*max_depth*/,
+ int /*skip_count*/) {
+ return "";
}
-const char* const
-OsStackTraceGetter::kElidedFramesMarker =
- "... " GTEST_NAME_ " internal frames ...";
+void OsStackTraceGetter::UponLeavingGTest() {}
// A helper class that creates the premature-exit file in its
// constructor and deletes the file in its destructor.
@@ -3812,7 +4143,7 @@ void UnitTest::AddTestPartResult(
// with another testing framework) and specify the former on the
// command line for debugging.
if (GTEST_FLAG(break_on_failure)) {
-#if GTEST_OS_WINDOWS
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT
// Using DebugBreak on Windows allows gtest to still break into a debugger
// when a failure happens and both the --gtest_break_on_failure and
// the --gtest_catch_exceptions flags are specified.
@@ -3890,7 +4221,7 @@ int UnitTest::Run() {
// process. In either case the user does not want to see pop-up dialogs
// about crashes - they are expected.
if (impl()->catch_exceptions() || in_death_test_child_process) {
-# if !GTEST_OS_WINDOWS_MOBILE
+# if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT
// SetErrorMode doesn't exist on CE.
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT |
SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
@@ -3993,17 +4324,10 @@ namespace internal {
UnitTestImpl::UnitTestImpl(UnitTest* parent)
: parent_(parent),
-#ifdef _MSC_VER
-# pragma warning(push) // Saves the current warning state.
-# pragma warning(disable:4355) // Temporarily disables warning 4355
- // (using this in initializer).
+ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4355 /* using this in initializer */)
default_global_test_part_result_reporter_(this),
default_per_thread_test_part_result_reporter_(this),
-# pragma warning(pop) // Restores the warning state again.
-#else
- default_global_test_part_result_reporter_(this),
- default_per_thread_test_part_result_reporter_(this),
-#endif // _MSC_VER
+ GTEST_DISABLE_MSC_WARNINGS_POP_()
global_test_part_result_repoter_(
&default_global_test_part_result_reporter_),
per_thread_test_part_result_reporter_(
@@ -4114,6 +4438,11 @@ void UnitTestImpl::PostFlagParsingInit() {
if (!post_flag_parse_init_performed_) {
post_flag_parse_init_performed_ = true;
+#if defined(GTEST_CUSTOM_TEST_EVENT_LISTENER_)
+ // Register to send notifications about key process state changes.
+ listeners()->Append(new GTEST_CUSTOM_TEST_EVENT_LISTENER_());
+#endif // defined(GTEST_CUSTOM_TEST_EVENT_LISTENER_)
+
#if GTEST_HAS_DEATH_TEST
InitDeathTestSubprocessControlInfo();
SuppressTestEventsIfInSubprocess();
@@ -4247,6 +4576,11 @@ bool UnitTestImpl::RunAllTests() {
#if GTEST_HAS_DEATH_TEST
in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL);
+# if defined(GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_)
+ if (in_subprocess_for_death_test) {
+ GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_();
+ }
+# endif // defined(GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_)
#endif // GTEST_HAS_DEATH_TEST
const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex,
@@ -4583,7 +4917,11 @@ void UnitTestImpl::set_os_stack_trace_getter(
// getter, and returns it.
OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() {
if (os_stack_trace_getter_ == NULL) {
+#ifdef GTEST_OS_STACK_TRACE_GETTER_
+ os_stack_trace_getter_ = new GTEST_OS_STACK_TRACE_GETTER_;
+#else
os_stack_trace_getter_ = new OsStackTraceGetter;
+#endif // GTEST_OS_STACK_TRACE_GETTER_
}
return os_stack_trace_getter_;
@@ -4882,6 +5220,58 @@ static const char kColorEncodedHelpMessage[] =
"(not one in your own code or tests), please report it to\n"
"@G<" GTEST_DEV_EMAIL_ ">@D.\n";
+bool ParseGoogleTestFlag(const char* const arg) {
+ return ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag,
+ &GTEST_FLAG(also_run_disabled_tests)) ||
+ ParseBoolFlag(arg, kBreakOnFailureFlag,
+ &GTEST_FLAG(break_on_failure)) ||
+ ParseBoolFlag(arg, kCatchExceptionsFlag,
+ &GTEST_FLAG(catch_exceptions)) ||
+ ParseStringFlag(arg, kColorFlag, &GTEST_FLAG(color)) ||
+ ParseStringFlag(arg, kDeathTestStyleFlag,
+ &GTEST_FLAG(death_test_style)) ||
+ ParseBoolFlag(arg, kDeathTestUseFork,
+ &GTEST_FLAG(death_test_use_fork)) ||
+ ParseStringFlag(arg, kFilterFlag, &GTEST_FLAG(filter)) ||
+ ParseStringFlag(arg, kInternalRunDeathTestFlag,
+ &GTEST_FLAG(internal_run_death_test)) ||
+ ParseBoolFlag(arg, kListTestsFlag, &GTEST_FLAG(list_tests)) ||
+ ParseStringFlag(arg, kOutputFlag, &GTEST_FLAG(output)) ||
+ ParseBoolFlag(arg, kPrintTimeFlag, &GTEST_FLAG(print_time)) ||
+ ParseInt32Flag(arg, kRandomSeedFlag, &GTEST_FLAG(random_seed)) ||
+ ParseInt32Flag(arg, kRepeatFlag, &GTEST_FLAG(repeat)) ||
+ ParseBoolFlag(arg, kShuffleFlag, &GTEST_FLAG(shuffle)) ||
+ ParseInt32Flag(arg, kStackTraceDepthFlag,
+ &GTEST_FLAG(stack_trace_depth)) ||
+ ParseStringFlag(arg, kStreamResultToFlag,
+ &GTEST_FLAG(stream_result_to)) ||
+ ParseBoolFlag(arg, kThrowOnFailureFlag,
+ &GTEST_FLAG(throw_on_failure));
+}
+
+#if GTEST_USE_OWN_FLAGFILE_FLAG_
+void LoadFlagsFromFile(const std::string& path) {
+ FILE* flagfile = posix::FOpen(path.c_str(), "r");
+ if (!flagfile) {
+ fprintf(stderr,
+ "Unable to open file \"%s\"\n",
+ GTEST_FLAG(flagfile).c_str());
+ fflush(stderr);
+ exit(EXIT_FAILURE);
+ }
+ std::string contents(ReadEntireFile(flagfile));
+ posix::FClose(flagfile);
+ std::vector<std::string> lines;
+ SplitString(contents, '\n', &lines);
+ for (size_t i = 0; i < lines.size(); ++i) {
+ if (lines[i].empty())
+ continue;
+ if (!ParseGoogleTestFlag(lines[i].c_str()))
+ g_help_flag = true;
+ }
+}
+#endif // GTEST_USE_OWN_FLAGFILE_FLAG_
+
// Parses the command line for Google Test flags, without initializing
// other parts of Google Test. The type parameter CharType can be
// instantiated to either char or wchar_t.
@@ -4895,35 +5285,24 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) {
using internal::ParseInt32Flag;
using internal::ParseStringFlag;
- // Do we see a Google Test flag?
- if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag,
- &GTEST_FLAG(also_run_disabled_tests)) ||
- ParseBoolFlag(arg, kBreakOnFailureFlag,
- &GTEST_FLAG(break_on_failure)) ||
- ParseBoolFlag(arg, kCatchExceptionsFlag,
- &GTEST_FLAG(catch_exceptions)) ||
- ParseStringFlag(arg, kColorFlag, &GTEST_FLAG(color)) ||
- ParseStringFlag(arg, kDeathTestStyleFlag,
- &GTEST_FLAG(death_test_style)) ||
- ParseBoolFlag(arg, kDeathTestUseFork,
- &GTEST_FLAG(death_test_use_fork)) ||
- ParseStringFlag(arg, kFilterFlag, &GTEST_FLAG(filter)) ||
- ParseStringFlag(arg, kInternalRunDeathTestFlag,
- &GTEST_FLAG(internal_run_death_test)) ||
- ParseBoolFlag(arg, kListTestsFlag, &GTEST_FLAG(list_tests)) ||
- ParseStringFlag(arg, kOutputFlag, &GTEST_FLAG(output)) ||
- ParseBoolFlag(arg, kPrintTimeFlag, &GTEST_FLAG(print_time)) ||
- ParseInt32Flag(arg, kRandomSeedFlag, &GTEST_FLAG(random_seed)) ||
- ParseInt32Flag(arg, kRepeatFlag, &GTEST_FLAG(repeat)) ||
- ParseBoolFlag(arg, kShuffleFlag, &GTEST_FLAG(shuffle)) ||
- ParseInt32Flag(arg, kStackTraceDepthFlag,
- &GTEST_FLAG(stack_trace_depth)) ||
- ParseStringFlag(arg, kStreamResultToFlag,
- &GTEST_FLAG(stream_result_to)) ||
- ParseBoolFlag(arg, kThrowOnFailureFlag,
- &GTEST_FLAG(throw_on_failure))
- ) {
- // Yes. Shift the remainder of the argv list left by one. Note
+ bool remove_flag = false;
+ if (ParseGoogleTestFlag(arg)) {
+ remove_flag = true;
+#if GTEST_USE_OWN_FLAGFILE_FLAG_
+ } else if (ParseStringFlag(arg, kFlagfileFlag, &GTEST_FLAG(flagfile))) {
+ LoadFlagsFromFile(GTEST_FLAG(flagfile));
+ remove_flag = true;
+#endif // GTEST_USE_OWN_FLAGFILE_FLAG_
+ } else if (arg_string == "--help" || arg_string == "-h" ||
+ arg_string == "-?" || arg_string == "/?" ||
+ HasGoogleTestFlagPrefix(arg)) {
+ // Both help flag and unrecognized Google Test flags (excluding
+ // internal ones) trigger help display.
+ g_help_flag = true;
+ }
+
+ if (remove_flag) {
+ // Shift the remainder of the argv list left by one. Note
// that argv has (*argc + 1) elements, the last one always being
// NULL. The following loop moves the trailing NULL element as
// well.
@@ -4937,12 +5316,6 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) {
// We also need to decrement the iterator as we just removed
// an element.
i--;
- } else if (arg_string == "--help" || arg_string == "-h" ||
- arg_string == "-?" || arg_string == "/?" ||
- HasGoogleTestFlagPrefix(arg)) {
- // Both help flag and unrecognized Google Test flags (excluding
- // internal ones) trigger help display.
- g_help_flag = true;
}
}
@@ -4969,24 +5342,16 @@ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) {
// wchar_t.
template <typename CharType>
void InitGoogleTestImpl(int* argc, CharType** argv) {
- g_init_gtest_count++;
-
// We don't want to run the initialization code twice.
- if (g_init_gtest_count != 1) return;
+ if (GTestIsInitialized()) return;
if (*argc <= 0) return;
- internal::g_executable_path = internal::StreamableToString(argv[0]);
-
-#if GTEST_HAS_DEATH_TEST
-
g_argvs.clear();
for (int i = 0; i != *argc; i++) {
g_argvs.push_back(StreamableToString(argv[i]));
}
-#endif // GTEST_HAS_DEATH_TEST
-
ParseGoogleTestFlagsOnly(argc, argv);
GetUnitTestImpl()->PostFlagParsingInit();
}
@@ -5003,13 +5368,21 @@ void InitGoogleTestImpl(int* argc, CharType** argv) {
//
// Calling the function for the second time has no user-visible effect.
void InitGoogleTest(int* argc, char** argv) {
+#if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
+ GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(argc, argv);
+#else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
internal::InitGoogleTestImpl(argc, argv);
+#endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
}
// This overloaded version can be used in Windows programs compiled in
// UNICODE mode.
void InitGoogleTest(int* argc, wchar_t** argv) {
+#if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
+ GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(argc, argv);
+#else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
internal::InitGoogleTestImpl(argc, argv);
+#endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
}
} // namespace testing
diff --git a/extern/libopenjpeg/README.blender b/extern/libopenjpeg/README.blender
new file mode 100644
index 00000000000..5aa213c7707
--- /dev/null
+++ b/extern/libopenjpeg/README.blender
@@ -0,0 +1,5 @@
+Project: OpenJPEG
+URL: http://www.openjpeg.org
+License: BSD 2-Clause
+Upstream version: 1.5.2
+Local modifications:
diff --git a/extern/rangetree/CMakeLists.txt b/extern/rangetree/CMakeLists.txt
index ba682233381..e8e9b15f8b1 100644
--- a/extern/rangetree/CMakeLists.txt
+++ b/extern/rangetree/CMakeLists.txt
@@ -21,10 +21,10 @@ set(INC
)
set(SRC
- range_tree.hh
- range_tree_c_api.h
+ range_tree.h
+ intern/generic_alloc_impl.h
- range_tree_c_api.cc
+ intern/range_tree.c
)
blender_add_lib(extern_rangetree "${SRC}" "${INC}" "")
diff --git a/extern/rangetree/README.blender b/extern/rangetree/README.blender
new file mode 100644
index 00000000000..6a940c14d60
--- /dev/null
+++ b/extern/rangetree/README.blender
@@ -0,0 +1,5 @@
+Project: RangeTree
+URL: https://github.com/ideasman42/rangetree-c
+License: Apache 2.0
+Upstream version: 40ebed8aa209
+Local modifications: None
diff --git a/extern/rangetree/README.org b/extern/rangetree/README.org
deleted file mode 100644
index 46a4cedaf8f..00000000000
--- a/extern/rangetree/README.org
+++ /dev/null
@@ -1,13 +0,0 @@
-* Overview
- Basic class for storing non-overlapping scalar ranges. Underlying
- representation is a C++ STL set for fast lookups.
-
-* License
- GPL version 2 or later (see COPYING)
-
-* Author Note
- This implementation is intended for storing free unique IDs in a new
- undo system for BMesh in Blender, but could be useful elsewhere.
-
-* Website
- https://github.com/nicholasbishop/RangeTree
diff --git a/extern/rangetree/intern/generic_alloc_impl.h b/extern/rangetree/intern/generic_alloc_impl.h
new file mode 100644
index 00000000000..0f9f5184637
--- /dev/null
+++ b/extern/rangetree/intern/generic_alloc_impl.h
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2016, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "Apache License")
+ * with the following modification; you may not use this file except in
+ * compliance with the Apache License and the following modification to it:
+ * Section 6. Trademarks. is deleted and replaced with:
+ *
+ * 6. Trademarks. This License does not grant permission to use the trade
+ * names, trademarks, service marks, or product names of the Licensor
+ * and its affiliates, except as required to comply with Section 4(c) of
+ * the License and to reproduce the content of the NOTICE file.
+ *
+ * You may obtain a copy of the Apache License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Apache License with the above modification is
+ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the Apache License for the specific
+ * language governing permissions and limitations under the Apache License.
+ */
+
+/**
+ * Simple Memory Chunking Allocator
+ * ================================
+ *
+ * Defines need to be set:
+ * - #TPOOL_IMPL_PREFIX: Prefix to use for the API.
+ * - #TPOOL_ALLOC_TYPE: Struct type this pool handles.
+ * - #TPOOL_STRUCT: Name for pool struct name.
+ * - #TPOOL_CHUNK_SIZE: Chunk size (optional), use 64kb when not defined.
+ *
+ * \note #TPOOL_ALLOC_TYPE must be at least ``sizeof(void *)``.
+ *
+ * Defines the API, uses #TPOOL_IMPL_PREFIX to prefix each function.
+ *
+ * - *_pool_create()
+ * - *_pool_destroy()
+ * - *_pool_clear()
+ *
+ * - *_pool_elem_alloc()
+ * - *_pool_elem_calloc()
+ * - *_pool_elem_free()
+ */
+
+/* check we're not building directly */
+#if !defined(TPOOL_IMPL_PREFIX) || \
+ !defined(TPOOL_ALLOC_TYPE) || \
+ !defined(TPOOL_STRUCT)
+# error "This file can't be compiled directly, include in another source file"
+#endif
+
+#define _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) MACRO_ARG1 ## MACRO_ARG2
+#define _CONCAT(MACRO_ARG1, MACRO_ARG2) _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2)
+#define _TPOOL_PREFIX(id) _CONCAT(TPOOL_IMPL_PREFIX, _##id)
+
+/* local identifiers */
+#define pool_create _TPOOL_PREFIX(pool_create)
+#define pool_destroy _TPOOL_PREFIX(pool_destroy)
+#define pool_clear _TPOOL_PREFIX(pool_clear)
+
+#define pool_elem_alloc _TPOOL_PREFIX(pool_elem_alloc)
+#define pool_elem_calloc _TPOOL_PREFIX(pool_elem_calloc)
+#define pool_elem_free _TPOOL_PREFIX(pool_elem_free)
+
+/* private identifiers (only for this file, undefine after) */
+#define pool_alloc_chunk _TPOOL_PREFIX(pool_alloc_chunk)
+#define TPoolChunk _TPOOL_PREFIX(TPoolChunk)
+#define TPoolChunkElemFree _TPOOL_PREFIX(TPoolChunkElemFree)
+
+#ifndef TPOOL_CHUNK_SIZE
+#define TPOOL_CHUNK_SIZE (1 << 16) /* 64kb */
+#define _TPOOL_CHUNK_SIZE_UNDEF
+#endif
+
+#ifndef UNLIKELY
+# ifdef __GNUC__
+# define UNLIKELY(x) __builtin_expect(!!(x), 0)
+# else
+# define UNLIKELY(x) (x)
+# endif
+#endif
+
+#ifdef __GNUC__
+# define MAYBE_UNUSED __attribute__((unused))
+#else
+# define MAYBE_UNUSED
+#endif
+
+
+struct TPoolChunk {
+ struct TPoolChunk *prev;
+ unsigned int size;
+ unsigned int bufsize;
+ TPOOL_ALLOC_TYPE buf[0];
+};
+
+struct TPoolChunkElemFree {
+ struct TPoolChunkElemFree *next;
+};
+
+struct TPOOL_STRUCT {
+ /* Always keep at least one chunk (never NULL) */
+ struct TPoolChunk *chunk;
+ /* when NULL, allocate a new chunk */
+ struct TPoolChunkElemFree *free;
+};
+
+/**
+ * Number of elems to include per #TPoolChunk when no reserved size is passed,
+ * or we allocate past the reserved number.
+ *
+ * \note Optimize number for 64kb allocs.
+ */
+#define _TPOOL_CHUNK_DEFAULT_NUM \
+ (((1 << 16) - sizeof(struct TPoolChunk)) / sizeof(TPOOL_ALLOC_TYPE))
+
+
+/** \name Internal Memory Management
+ * \{ */
+
+static struct TPoolChunk *pool_alloc_chunk(
+ unsigned int tot_elems, struct TPoolChunk *chunk_prev)
+{
+ struct TPoolChunk *chunk = malloc(
+ sizeof(struct TPoolChunk) + (sizeof(TPOOL_ALLOC_TYPE) * tot_elems));
+ chunk->prev = chunk_prev;
+ chunk->bufsize = tot_elems;
+ chunk->size = 0;
+ return chunk;
+}
+
+static TPOOL_ALLOC_TYPE *pool_elem_alloc(struct TPOOL_STRUCT *pool)
+{
+ TPOOL_ALLOC_TYPE *elem;
+
+ if (pool->free) {
+ elem = (TPOOL_ALLOC_TYPE *)pool->free;
+ pool->free = pool->free->next;
+ }
+ else {
+ struct TPoolChunk *chunk = pool->chunk;
+ if (UNLIKELY(chunk->size == chunk->bufsize)) {
+ chunk = pool->chunk = pool_alloc_chunk(_TPOOL_CHUNK_DEFAULT_NUM, chunk);
+ }
+ elem = &chunk->buf[chunk->size++];
+ }
+
+ return elem;
+}
+
+MAYBE_UNUSED
+static TPOOL_ALLOC_TYPE *pool_elem_calloc(struct TPOOL_STRUCT *pool)
+{
+ TPOOL_ALLOC_TYPE *elem = pool_elem_alloc(pool);
+ memset(elem, 0, sizeof(*elem));
+ return elem;
+}
+
+static void pool_elem_free(struct TPOOL_STRUCT *pool, TPOOL_ALLOC_TYPE *elem)
+{
+ struct TPoolChunkElemFree *elem_free = (struct TPoolChunkElemFree *)elem;
+ elem_free->next = pool->free;
+ pool->free = elem_free;
+}
+
+static void pool_create(struct TPOOL_STRUCT *pool, unsigned int tot_reserve)
+{
+ pool->chunk = pool_alloc_chunk((tot_reserve > 1) ? tot_reserve : _TPOOL_CHUNK_DEFAULT_NUM, NULL);
+ pool->free = NULL;
+}
+
+MAYBE_UNUSED
+static void pool_clear(struct TPOOL_STRUCT *pool)
+{
+ /* Remove all except the last chunk */
+ while (pool->chunk->prev) {
+ struct TPoolChunk *chunk_prev = pool->chunk->prev;
+ free(pool->chunk);
+ pool->chunk = chunk_prev;
+ }
+ pool->chunk->size = 0;
+ pool->free = NULL;
+}
+
+static void pool_destroy(struct TPOOL_STRUCT *pool)
+{
+ struct TPoolChunk *chunk = pool->chunk;
+ do {
+ struct TPoolChunk *chunk_prev;
+ chunk_prev = chunk->prev;
+ free(chunk);
+ chunk = chunk_prev;
+ } while (chunk);
+
+ pool->chunk = NULL;
+ pool->free = NULL;
+}
+
+/** \} */
+
+#undef _TPOOL_CHUNK_DEFAULT_NUM
+#undef _CONCAT_AUX
+#undef _CONCAT
+#undef _TPOOL_PREFIX
+
+#undef TPoolChunk
+#undef TPoolChunkElemFree
+
+#ifdef _TPOOL_CHUNK_SIZE_UNDEF
+# undef TPOOL_CHUNK_SIZE
+# undef _TPOOL_CHUNK_SIZE_UNDEF
+#endif
diff --git a/extern/rangetree/intern/range_tree.c b/extern/rangetree/intern/range_tree.c
new file mode 100644
index 00000000000..4c81036dceb
--- /dev/null
+++ b/extern/rangetree/intern/range_tree.c
@@ -0,0 +1,873 @@
+/*
+ * Copyright (c) 2016, Campbell Barton.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "Apache License")
+ * with the following modification; you may not use this file except in
+ * compliance with the Apache License and the following modification to it:
+ * Section 6. Trademarks. is deleted and replaced with:
+ *
+ * 6. Trademarks. This License does not grant permission to use the trade
+ * names, trademarks, service marks, or product names of the Licensor
+ * and its affiliates, except as required to comply with Section 4(c) of
+ * the License and to reproduce the content of the NOTICE file.
+ *
+ * You may obtain a copy of the Apache License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Apache License with the above modification is
+ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the Apache License for the specific
+ * language governing permissions and limitations under the Apache License.
+ */
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <assert.h>
+
+#include "range_tree.h"
+
+typedef unsigned int uint;
+
+/* Use binary-tree for lookups, else fallback to full search */
+#define USE_BTREE
+/* Use memory pool for nodes, else do individual allocations */
+#define USE_TPOOL
+
+/* Node representing a range in the RangeTreeUInt. */
+typedef struct Node {
+ struct Node *next, *prev;
+
+ /* range (inclusive) */
+ uint min, max;
+
+#ifdef USE_BTREE
+ /* Left leaning red-black tree, for reference implementation see:
+ * https://gitlab.com/ideasman42/btree-mini-py */
+ struct Node *left, *right;
+ /* RED/BLACK */
+ bool color;
+#endif
+} Node;
+
+#ifdef USE_TPOOL
+/* rt_pool_* pool allocator */
+#define TPOOL_IMPL_PREFIX rt_node
+#define TPOOL_ALLOC_TYPE Node
+#define TPOOL_STRUCT ElemPool_Node
+#include "generic_alloc_impl.h"
+#undef TPOOL_IMPL_PREFIX
+#undef TPOOL_ALLOC_TYPE
+#undef TPOOL_STRUCT
+#endif /* USE_TPOOL */
+
+typedef struct LinkedList {
+ Node *first, *last;
+} LinkedList;
+
+typedef struct RangeTreeUInt {
+ uint range[2];
+ LinkedList list;
+#ifdef USE_BTREE
+ Node *root;
+#endif
+#ifdef USE_TPOOL
+ struct ElemPool_Node epool;
+#endif
+} RangeTreeUInt;
+
+/* ------------------------------------------------------------------------- */
+/* List API */
+
+static void list_push_front(LinkedList *list, Node *node)
+{
+ if (list->first != NULL) {
+ node->next = list->first;
+ node->next->prev = node;
+ node->prev = NULL;
+ }
+ else {
+ list->last = node;
+ }
+ list->first = node;
+}
+
+static void list_push_back(LinkedList *list, Node *node)
+{
+ if (list->first != NULL) {
+ node->prev = list->last;
+ node->prev->next = node;
+ node->next = NULL;
+ }
+ else {
+ list->first = node;
+ }
+ list->last = node;
+}
+
+static void list_push_after(LinkedList *list, Node *node_prev, Node *node_new)
+{
+ /* node_new before node_next */
+
+ /* empty list */
+ if (list->first == NULL) {
+ list->first = node_new;
+ list->last = node_new;
+ return;
+ }
+
+ /* insert at head of list */
+ if (node_prev == NULL) {
+ node_new->prev = NULL;
+ node_new->next = list->first;
+ node_new->next->prev = node_new;
+ list->first = node_new;
+ return;
+ }
+
+ /* at end of list */
+ if (list->last == node_prev) {
+ list->last = node_new;
+ }
+
+ node_new->next = node_prev->next;
+ node_new->prev = node_prev;
+ node_prev->next = node_new;
+ if (node_new->next) {
+ node_new->next->prev = node_new;
+ }
+}
+
+static void list_push_before(LinkedList *list, Node *node_next, Node *node_new)
+{
+ /* node_new before node_next */
+
+ /* empty list */
+ if (list->first == NULL) {
+ list->first = node_new;
+ list->last = node_new;
+ return;
+ }
+
+ /* insert at end of list */
+ if (node_next == NULL) {
+ node_new->prev = list->last;
+ node_new->next = NULL;
+ list->last->next = node_new;
+ list->last = node_new;
+ return;
+ }
+
+ /* at beginning of list */
+ if (list->first == node_next) {
+ list->first = node_new;
+ }
+
+ node_new->next = node_next;
+ node_new->prev = node_next->prev;
+ node_next->prev = node_new;
+ if (node_new->prev) {
+ node_new->prev->next = node_new;
+ }
+}
+
+static void list_remove(LinkedList *list, Node *node)
+{
+ if (node->next != NULL) {
+ node->next->prev = node->prev;
+ }
+ if (node->prev != NULL) {
+ node->prev->next = node->next;
+ }
+
+ if (list->last == node) {
+ list->last = node->prev;
+ }
+ if (list->first == node) {
+ list->first = node->next;
+ }
+}
+
+static void list_clear(LinkedList *list)
+{
+ list->first = NULL;
+ list->last = NULL;
+}
+
+/* end list API */
+
+
+/* forward declarations */
+static void rt_node_free(RangeTreeUInt *rt, Node *node);
+
+
+#ifdef USE_BTREE
+
+#ifdef DEBUG
+static bool rb_is_balanced_root(const Node *root);
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* Internal BTree API
+ *
+ * Left-leaning red-black tree.
+ */
+
+/* use minimum, could use max too since nodes never overlap */
+#define KEY(n) ((n)->min)
+
+enum {
+ RED = 0,
+ BLACK = 1,
+};
+
+
+static bool is_red(const Node *node)
+{
+ return (node && (node->color == RED));
+}
+
+static int key_cmp(uint key1, uint key2)
+{
+ return (key1 == key2) ? 0 : ((key1 < key2) ? -1 : 1);
+}
+
+/* removed from the tree */
+static void rb_node_invalidate(Node *node)
+{
+#ifdef DEBUG
+ node->left = NULL;
+ node->right = NULL;
+ node->color = false;
+#else
+ (void)node;
+#endif
+}
+
+static void rb_flip_color(Node *node)
+{
+ node->color ^= 1;
+ node->left->color ^= 1;
+ node->right->color ^= 1;
+}
+
+static Node *rb_rotate_left(Node *left)
+{
+ /* Make a right-leaning 3-node lean to the left. */
+ Node *right = left->right;
+ left->right = right->left;
+ right->left = left;
+ right->color = left->color;
+ left->color = RED;
+ return right;
+}
+
+static Node *rb_rotate_right(Node *right)
+{
+ /* Make a left-leaning 3-node lean to the right. */
+ Node *left = right->left;
+ right->left = left->right;
+ left->right = right;
+ left->color = right->color;
+ right->color = RED;
+ return left;
+}
+
+/* Fixup colors when insert happened */
+static Node *rb_fixup_insert(Node *node)
+{
+ if (is_red(node->right) && !is_red(node->left)) {
+ node = rb_rotate_left(node);
+ }
+ if (is_red(node->left) && is_red(node->left->left)) {
+ node = rb_rotate_right(node);
+ }
+
+ if (is_red(node->left) && is_red(node->right)) {
+ rb_flip_color(node);
+ }
+
+ return node;
+}
+
+static Node *rb_insert_recursive(Node *node, Node *node_to_insert)
+{
+ if (node == NULL) {
+ return node_to_insert;
+ }
+
+ const int cmp = key_cmp(KEY(node_to_insert), KEY(node));
+ if (cmp == 0) {
+ /* caller ensures no collisions */
+ assert(0);
+ }
+ else if (cmp == -1) {
+ node->left = rb_insert_recursive(node->left, node_to_insert);
+ }
+ else {
+ node->right = rb_insert_recursive(node->right, node_to_insert);
+ }
+
+ return rb_fixup_insert(node);
+}
+
+static Node *rb_insert_root(Node *root, Node *node_to_insert)
+{
+ root = rb_insert_recursive(root, node_to_insert);
+ root->color = BLACK;
+ return root;
+}
+
+static Node *rb_move_red_to_left(Node *node)
+{
+ /* Assuming that h is red and both h->left and h->left->left
+ * are black, make h->left or one of its children red.
+ */
+ rb_flip_color(node);
+ if (node->right && is_red(node->right->left)) {
+ node->right = rb_rotate_right(node->right);
+ node = rb_rotate_left(node);
+ rb_flip_color(node);
+ }
+ return node;
+}
+
+static Node *rb_move_red_to_right(Node *node)
+{
+ /* Assuming that h is red and both h->right and h->right->left
+ * are black, make h->right or one of its children red.
+ */
+ rb_flip_color(node);
+ if (node->left && is_red(node->left->left)) {
+ node = rb_rotate_right(node);
+ rb_flip_color(node);
+ }
+ return node;
+}
+
+/* Fixup colors when remove happened */
+static Node *rb_fixup_remove(Node *node)
+{
+ if (is_red(node->right)) {
+ node = rb_rotate_left(node);
+ }
+ if (is_red(node->left) && is_red(node->left->left)) {
+ node = rb_rotate_right(node);
+ }
+ if (is_red(node->left) && is_red(node->right)) {
+ rb_flip_color(node);
+ }
+ return node;
+}
+
+static Node *rb_pop_min_recursive(Node *node, Node **r_node_pop)
+{
+ if (node == NULL) {
+ return NULL;
+ }
+ if (node->left == NULL) {
+ rb_node_invalidate(node);
+ *r_node_pop = node;
+ return NULL;
+ }
+ if ((!is_red(node->left)) && (!is_red(node->left->left))) {
+ node = rb_move_red_to_left(node);
+ }
+ node->left = rb_pop_min_recursive(node->left, r_node_pop);
+ return rb_fixup_remove(node);
+}
+
+static Node *rb_remove_recursive(Node *node, const Node *node_to_remove)
+{
+ if (node == NULL) {
+ return NULL;
+ }
+ if (key_cmp(KEY(node_to_remove), KEY(node)) == -1) {
+ if (node->left != NULL) {
+ if ((!is_red(node->left)) && (!is_red(node->left->left))) {
+ node = rb_move_red_to_left(node);
+ }
+ }
+ node->left = rb_remove_recursive(node->left, node_to_remove);
+ }
+ else {
+ if (is_red(node->left)) {
+ node = rb_rotate_right(node);
+ }
+ if ((node == node_to_remove) && (node->right == NULL)) {
+ rb_node_invalidate(node);
+ return NULL;
+ }
+ assert(node->right != NULL);
+ if ((!is_red(node->right)) && (!is_red(node->right->left))) {
+ node = rb_move_red_to_right(node);
+ }
+
+ if (node == node_to_remove) {
+ /* minor improvement over original method:
+ * no need to double lookup min */
+ Node *node_free; /* will always be set */
+ node->right = rb_pop_min_recursive(node->right, &node_free);
+
+ node_free->left = node->left;
+ node_free->right = node->right;
+ node_free->color = node->color;
+
+ rb_node_invalidate(node);
+ node = node_free;
+ }
+ else {
+ node->right = rb_remove_recursive(node->right, node_to_remove);
+ }
+ }
+ return rb_fixup_remove(node);
+}
+
+static Node *rb_btree_remove(Node *root, const Node *node_to_remove)
+{
+ root = rb_remove_recursive(root, node_to_remove);
+ if (root != NULL) {
+ root->color = BLACK;
+ }
+ return root;
+}
+
+/*
+ * Returns the node closest to and including 'key',
+ * excluding anything below.
+ */
+static Node *rb_get_or_upper_recursive(Node *n, const uint key)
+{
+ if (n == NULL) {
+ return NULL;
+ }
+ const int cmp_upper = key_cmp(KEY(n), key);
+ if (cmp_upper == 0) {
+ return n; // exact match
+ }
+ else if (cmp_upper == 1) {
+ assert(KEY(n) >= key);
+ Node *n_test = rb_get_or_upper_recursive(n->left, key);
+ return n_test ? n_test : n;
+ }
+ else { // cmp_upper == -1
+ return rb_get_or_upper_recursive(n->right, key);
+ }
+}
+
+/*
+ * Returns the node closest to and including 'key',
+ * excluding anything above.
+ */
+static Node *rb_get_or_lower_recursive(Node *n, const uint key)
+{
+ if (n == NULL) {
+ return NULL;
+ }
+ const int cmp_lower = key_cmp(KEY(n), key);
+ if (cmp_lower == 0) {
+ return n; // exact match
+ }
+ else if (cmp_lower == -1) {
+ assert(KEY(n) <= key);
+ Node *n_test = rb_get_or_lower_recursive(n->right, key);
+ return n_test ? n_test : n;
+ }
+ else { // cmp_lower == 1
+ return rb_get_or_lower_recursive(n->left, key);
+ }
+}
+
+#ifdef DEBUG
+
+static bool rb_is_balanced_recursive(const Node *node, int black)
+{
+ // Does every path from the root to a leaf have the given number
+ // of black links?
+ if (node == NULL) {
+ return black == 0;
+ }
+ if (!is_red(node)) {
+ black--;
+ }
+ return rb_is_balanced_recursive(node->left, black) &&
+ rb_is_balanced_recursive(node->right, black);
+}
+
+static bool rb_is_balanced_root(const Node *root)
+{
+ // Do all paths from root to leaf have same number of black edges?
+ int black = 0; // number of black links on path from root to min
+ const Node *node = root;
+ while (node != NULL) {
+ if (!is_red(node)) {
+ black++;
+ }
+ node = node->left;
+ }
+ return rb_is_balanced_recursive(root, black);
+}
+
+#endif // DEBUG
+
+
+/* End BTree API */
+#endif // USE_BTREE
+
+
+/* ------------------------------------------------------------------------- */
+/* Internal RangeTreeUInt API */
+
+#ifdef _WIN32
+#define inline __inline
+#endif
+
+static inline Node *rt_node_alloc(RangeTreeUInt *rt)
+{
+#ifdef USE_TPOOL
+ return rt_node_pool_elem_alloc(&rt->epool);
+#else
+ (void)rt;
+ return malloc(sizeof(Node));
+#endif
+}
+
+static Node *rt_node_new(RangeTreeUInt *rt, uint min, uint max)
+{
+ Node *node = rt_node_alloc(rt);
+
+ assert(min <= max);
+ node->prev = NULL;
+ node->next = NULL;
+ node->min = min;
+ node->max = max;
+#ifdef USE_BTREE
+ node->left = NULL;
+ node->right = NULL;
+#endif
+ return node;
+}
+
+static void rt_node_free(RangeTreeUInt *rt, Node *node)
+{
+#ifdef USE_TPOOL
+ rt_node_pool_elem_free(&rt->epool, node);
+#else
+ (void)rt;
+ free(node);
+#endif
+}
+
+#ifdef USE_BTREE
+static void rt_btree_insert(RangeTreeUInt *rt, Node *node)
+{
+ node->color = RED;
+ node->left = NULL;
+ node->right = NULL;
+ rt->root = rb_insert_root(rt->root, node);
+}
+#endif
+
+static void rt_node_add_back(RangeTreeUInt *rt, Node *node)
+{
+ list_push_back(&rt->list, node);
+#ifdef USE_BTREE
+ rt_btree_insert(rt, node);
+#endif
+}
+static void rt_node_add_front(RangeTreeUInt *rt, Node *node)
+{
+ list_push_front(&rt->list, node);
+#ifdef USE_BTREE
+ rt_btree_insert(rt, node);
+#endif
+}
+static void rt_node_add_before(RangeTreeUInt *rt, Node *node_next, Node *node)
+{
+ list_push_before(&rt->list, node_next, node);
+#ifdef USE_BTREE
+ rt_btree_insert(rt, node);
+#endif
+}
+static void rt_node_add_after(RangeTreeUInt *rt, Node *node_prev, Node *node)
+{
+ list_push_after(&rt->list, node_prev, node);
+#ifdef USE_BTREE
+ rt_btree_insert(rt, node);
+#endif
+}
+
+static void rt_node_remove(RangeTreeUInt *rt, Node *node)
+{
+ list_remove(&rt->list, node);
+#ifdef USE_BTREE
+ rt->root = rb_btree_remove(rt->root, node);
+#endif
+ rt_node_free(rt, node);
+}
+
+static Node *rt_find_node_from_value(RangeTreeUInt *rt, const uint value)
+{
+#ifdef USE_BTREE
+ Node *node = rb_get_or_lower_recursive(rt->root, value);
+ if (node != NULL) {
+ if ((value >= node->min) && (value <= node->max)) {
+ return node;
+ }
+ }
+ return NULL;
+#else
+ for (Node *node = rt->list.first; node; node = node->next) {
+ if ((value >= node->min) && (value <= node->max)) {
+ return node;
+ }
+ }
+ return NULL;
+#endif // USE_BTREE
+}
+
+static void rt_find_node_pair_around_value(RangeTreeUInt *rt, const uint value,
+ Node **r_node_prev, Node **r_node_next)
+{
+ if (value < rt->list.first->min) {
+ *r_node_prev = NULL;
+ *r_node_next = rt->list.first;
+ return;
+ }
+ else if (value > rt->list.last->max) {
+ *r_node_prev = rt->list.last;
+ *r_node_next = NULL;
+ return;
+ }
+ else {
+#ifdef USE_BTREE
+ Node *node_next = rb_get_or_upper_recursive(rt->root, value);
+ if (node_next != NULL) {
+ Node *node_prev = node_next->prev;
+ if ((node_prev->max < value) && (value < node_next->min)) {
+ *r_node_prev = node_prev;
+ *r_node_next = node_next;
+ return;
+ }
+ }
+#else
+ Node *node_prev = rt->list.first;
+ Node *node_next;
+ while ((node_next = node_prev->next)) {
+ if ((node_prev->max < value) && (value < node_next->min)) {
+ *r_node_prev = node_prev;
+ *r_node_next = node_next;
+ return;
+ }
+ node_prev = node_next;
+ }
+#endif // USE_BTREE
+ }
+ *r_node_prev = NULL;
+ *r_node_next = NULL;
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* Public API */
+
+static RangeTreeUInt *rt_create_empty(uint min, uint max)
+{
+ RangeTreeUInt *rt = malloc(sizeof(*rt));
+ rt->range[0] = min;
+ rt->range[1] = max;
+
+ list_clear(&rt->list);
+
+#ifdef USE_BTREE
+ rt->root = NULL;
+#endif
+#ifdef USE_TPOOL
+ rt_node_pool_create(&rt->epool, 512);
+#endif
+
+ return rt;
+}
+
+RangeTreeUInt *range_tree_uint_alloc(uint min, uint max)
+{
+ RangeTreeUInt *rt = rt_create_empty(min, max);
+
+ Node *node = rt_node_new(rt, min, max);
+ rt_node_add_front(rt, node);
+ return rt;
+}
+
+void range_tree_uint_free(RangeTreeUInt *rt)
+{
+#ifdef DEBUG
+#ifdef USE_BTREE
+ assert(rb_is_balanced_root(rt->root));
+#endif
+#endif
+
+#ifdef USE_TPOOL
+
+ rt_node_pool_destroy(&rt->epool);
+#else
+ for (Node *node = rt->list.first, *node_next; node; node = node_next) {
+ node_next = node->next;
+ rt_node_free(rt, node);
+ }
+#endif
+
+ free(rt);
+}
+
+#ifdef USE_BTREE
+static Node *rt_copy_recursive(RangeTreeUInt *rt_dst, const Node *node_src)
+{
+ if (node_src == NULL) {
+ return NULL;
+ }
+
+ Node *node_dst = rt_node_alloc(rt_dst);
+
+ *node_dst = *node_src;
+ node_dst->left = rt_copy_recursive(rt_dst, node_dst->left);
+ list_push_back(&rt_dst->list, node_dst);
+ node_dst->right = rt_copy_recursive(rt_dst, node_dst->right);
+
+ return node_dst;
+}
+#endif // USE_BTREE
+
+RangeTreeUInt *range_tree_uint_copy(const RangeTreeUInt *rt_src)
+{
+ RangeTreeUInt *rt_dst = rt_create_empty(rt_src->range[0], rt_src->range[1]);
+#ifdef USE_BTREE
+ rt_dst->root = rt_copy_recursive(rt_dst, rt_src->root);
+#else
+ for (Node *node_src = rt_src->list.first; node_src; node_src = node_src->next) {
+ Node *node_dst = rt_node_alloc(rt_dst);
+ *node_dst = *node_src;
+ list_push_back(&rt_dst->list, node_dst);
+ }
+#endif
+ return rt_dst;
+}
+
+/**
+ * Return true if the tree has the value (not taken).
+ */
+bool range_tree_uint_has(RangeTreeUInt *rt, const uint value)
+{
+ assert(value >= rt->range[0] && value <= rt->range[1]);
+ Node *node = rt_find_node_from_value(rt, value);
+ return (node != NULL);
+}
+
+static void range_tree_uint_take_impl(RangeTreeUInt *rt, const uint value, Node *node)
+{
+ assert(node == rt_find_node_from_value(rt, value));
+ if (node->min == value) {
+ if (node->max != value) {
+ node->min += 1;
+ }
+ else {
+ assert(node->min == node->max);
+ rt_node_remove(rt, node);
+ }
+ }
+ else if (node->max == value) {
+ node->max -= 1;
+ }
+ else {
+ Node *node_next = rt_node_new(rt, value + 1, node->max);
+ node->max = value - 1;
+ rt_node_add_after(rt, node, node_next);
+ }
+}
+
+void range_tree_uint_take(RangeTreeUInt *rt, const uint value)
+{
+ Node *node = rt_find_node_from_value(rt, value);
+ assert(node != NULL);
+ range_tree_uint_take_impl(rt, value, node);
+}
+
+bool range_tree_uint_retake(RangeTreeUInt *rt, const uint value)
+{
+ Node *node = rt_find_node_from_value(rt, value);
+ if (node != NULL) {
+ range_tree_uint_take_impl(rt, value, node);
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+uint range_tree_uint_take_any(RangeTreeUInt *rt)
+{
+ Node *node = node = rt->list.first;
+ uint value = node->min;
+ if (value == node->max) {
+ rt_node_remove(rt, node);
+ }
+ else {
+ node->min += 1;
+ }
+ return value;
+}
+
+void range_tree_uint_release(RangeTreeUInt *rt, const uint value)
+{
+ bool touch_prev, touch_next;
+ Node *node_prev, *node_next;
+
+ if (rt->list.first != NULL) {
+ rt_find_node_pair_around_value(rt, value, &node_prev, &node_next);
+ /* the value must have been already taken */
+ assert(node_prev || node_next);
+
+ /* Cases:
+ * 1) fill the gap between prev & next (two spans into one span).
+ * 2) touching prev, (grow node_prev->max up one).
+ * 3) touching next, (grow node_next->min down one).
+ * 4) touching neither, add a new segment. */
+ touch_prev = (node_prev != NULL && node_prev->max + 1 == value);
+ touch_next = (node_next != NULL && node_next->min - 1 == value);
+ }
+ else {
+ // we could handle this case (4) inline,
+ // since its not a common case - use regular logic.
+ node_prev = node_next = NULL;
+ touch_prev = false;
+ touch_next = false;
+ }
+
+ if (touch_prev && touch_next) { // 1)
+ node_prev->max = node_next->max;
+ rt_node_remove(rt, node_next);
+ }
+ else if (touch_prev) { // 2)
+ assert(node_prev->max + 1 == value);
+ node_prev->max = value;
+ }
+ else if (touch_next) { // 3)
+ assert(node_next->min - 1 == value);
+ node_next->min = value;
+ }
+ else { // 4)
+ Node *node_new = rt_node_new(rt, value, value);
+ if (node_prev != NULL) {
+ rt_node_add_after(rt, node_prev, node_new);
+ }
+ else if (node_next != NULL) {
+ rt_node_add_before(rt, node_next, node_new);
+ }
+ else {
+ assert(rt->list.first == NULL);
+ rt_node_add_back(rt, node_new);
+ }
+ }
+}
diff --git a/extern/rangetree/range_tree.h b/extern/rangetree/range_tree.h
new file mode 100644
index 00000000000..b46832b5cdb
--- /dev/null
+++ b/extern/rangetree/range_tree.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2016, Campbell Barton.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "Apache License")
+ * with the following modification; you may not use this file except in
+ * compliance with the Apache License and the following modification to it:
+ * Section 6. Trademarks. is deleted and replaced with:
+ *
+ * 6. Trademarks. This License does not grant permission to use the trade
+ * names, trademarks, service marks, or product names of the Licensor
+ * and its affiliates, except as required to comply with Section 4(c) of
+ * the License and to reproduce the content of the NOTICE file.
+ *
+ * You may obtain a copy of the Apache License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Apache License with the above modification is
+ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the Apache License for the specific
+ * language governing permissions and limitations under the Apache License.
+ */
+
+#ifndef __RANGE_TREE_H__
+#define __RANGE_TREE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct RangeTreeUInt RangeTreeUInt;
+
+struct RangeTreeUInt *range_tree_uint_alloc(unsigned int min, unsigned int max);
+void range_tree_uint_free(struct RangeTreeUInt *rt);
+struct RangeTreeUInt *range_tree_uint_copy(const struct RangeTreeUInt *rt_src);
+
+bool range_tree_uint_has(struct RangeTreeUInt *rt, const unsigned int value);
+void range_tree_uint_take(struct RangeTreeUInt *rt, const unsigned int value);
+bool range_tree_uint_retake(struct RangeTreeUInt *rt, const unsigned int value);
+unsigned int range_tree_uint_take_any(struct RangeTreeUInt *rt);
+void range_tree_uint_release(struct RangeTreeUInt *rt, const unsigned int value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __RANGE_TREE_H__ */
diff --git a/extern/rangetree/range_tree.hh b/extern/rangetree/range_tree.hh
deleted file mode 100644
index b247a0c6a1e..00000000000
--- a/extern/rangetree/range_tree.hh
+++ /dev/null
@@ -1,251 +0,0 @@
-/* This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA.
-*/
-
-#include <cassert>
-#include <climits>
-#include <iostream>
-#include <set>
-
-#ifndef RANGE_TREE_DEBUG_PRINT_FUNCTION
-# define RANGE_TREE_DEBUG_PRINT_FUNCTION 0
-#endif
-
-template <typename T>
-struct RangeTree {
- struct Range {
- Range(T min_, T max_)
- : min(min_), max(max_), single(min_ == max_) {
- assert(min_ <= max_);
- }
-
- Range(T t)
- : min(t), max(t), single(true)
- {}
-
- Range& operator=(const Range& v) {
- *this = v;
- return *this;
- }
-
- bool operator<(const Range& v) const {
- return max < v.min;
- }
-
- const T min;
- const T max;
- const bool single;
- };
-
- typedef std::set<Range> Tree;
- typedef typename Tree::iterator TreeIter;
- typedef typename Tree::reverse_iterator TreeIterReverse;
- typedef typename Tree::const_iterator TreeIterConst;
-
- /* Initialize with a single range from 'min' to 'max', inclusive. */
- RangeTree(T min, T max) {
- tree.insert(Range(min, max));
- }
-
- /* Initialize with a single range from 0 to 'max', inclusive. */
- RangeTree(T max) {
- tree.insert(Range(0, max));
- }
-
- RangeTree(const RangeTree<T>& src) {
- tree = src.tree;
- }
-
- /* Remove 't' from the associated range in the tree. Precondition:
- a range including 't' must exist in the tree. */
- void take(T t) {
- #if RANGE_TREE_DEBUG_PRINT_FUNCTION
- std::cout << __func__ << "(" << t << ")\n";
- #endif
-
- /* Find the range that includes 't' and its neighbors */
- TreeIter iter = tree.find(Range(t));
- assert(iter != tree.end());
- Range cur = *iter;
-
- /* Remove the original range (note that this does not
- invalidate the prev/next iterators) */
- tree.erase(iter);
-
- /* Construct two new ranges that together cover the original
- range, except for 't' */
- if (t > cur.min)
- tree.insert(Range(cur.min, t - 1));
- if (t + 1 <= cur.max)
- tree.insert(Range(t + 1, cur.max));
- }
-
- /* clone of 'take' that checks if the item exists */
- bool retake(T t) {
- #if RANGE_TREE_DEBUG_PRINT_FUNCTION
- std::cout << __func__ << "(" << t << ")\n";
- #endif
-
- TreeIter iter = tree.find(Range(t));
- if (iter == tree.end()) {
- return false;
- }
-
- Range cur = *iter;
- tree.erase(iter);
- if (t > cur.min)
- tree.insert(Range(cur.min, t - 1));
- if (t + 1 <= cur.max)
- tree.insert(Range(t + 1, cur.max));
-
- return true;
- }
-
-
- /* Take the first element out of the first range in the
- tree. Precondition: tree must not be empty. */
- T take_any() {
- #if RANGE_TREE_DEBUG_PRINT_FUNCTION
- std::cout << __func__ << "()\n";
- #endif
-
- /* Find the first element */
- TreeIter iter = tree.begin();
- assert(iter != tree.end());
- T first = iter->min;
-
- /* Take the first element */
- take(first);
- return first;
- }
-
- /* Return 't' to the tree, either expanding/merging existing
- ranges or adding a range to cover it. Precondition: 't' cannot
- be in an existing range. */
- void release(T t) {
- #if RANGE_TREE_DEBUG_PRINT_FUNCTION
- std::cout << __func__ << "(" << t << ")\n";
- #endif
-
- /* TODO: these cases should be simplified/unified */
-
- TreeIter right = tree.upper_bound(t);
- if (right != tree.end()) {
- TreeIter left = right;
- if (left != tree.begin())
- --left;
-
- if (left == right) {
- /* 't' lies before any existing ranges */
- if (t + 1 == left->min) {
- /* 't' lies directly before the first range,
- resize and replace that range */
- const Range r(t, left->max);
- tree.erase(left);
- tree.insert(r);
- }
- else {
- /* There's a gap between 't' and the first range,
- add a new range */
- tree.insert(Range(t));
- }
- }
- else if ((left->max + 1 == t) &&
- (t + 1 == right->min)) {
- /* 't' fills a hole. Remove left and right, and insert a
- new range that covers both. */
- const Range r(left->min, right->max);
- tree.erase(left);
- tree.erase(right);
- tree.insert(r);
- }
- else if (left->max + 1 == t) {
- /* 't' lies directly after 'left' range, resize and
- replace that range */
- const Range r(left->min, t);
- tree.erase(left);
- tree.insert(r);
- }
- else if (t + 1 == right->min) {
- /* 't' lies directly before 'right' range, resize and
- replace that range */
- const Range r(t, right->max);
- tree.erase(right);
- tree.insert(r);
- }
- else {
- /* There's a gap between 't' and both adjacent ranges,
- add a new range */
- tree.insert(Range(t));
- }
- }
- else {
- /* 't' lies after any existing ranges */
- right = tree.end();
- right--;
- if (right->max + 1 == t) {
- /* 't' lies directly after last range, resize and
- replace that range */
- const Range r(right->min, t);
- tree.erase(right);
- tree.insert(r);
- }
- else {
- /* There's a gap between the last range and 't', add a
- new range */
- tree.insert(Range(t));
- }
- }
- }
-
- bool has(T t) const {
- TreeIterConst iter = tree.find(Range(t));
- return (iter != tree.end()) && (t <= iter->max);
- }
-
- bool has_range(T min, T max) const {
- TreeIterConst iter = tree.find(Range(min, max));
- return (iter != tree.end()) && (min == iter->min && max == iter->max);
- }
-
- bool empty() const {
- return tree.empty();
- }
-
- int size() const {
- return tree.size();
- }
-
- void print() const {
- std::cout << "RangeTree:\n";
- for (TreeIterConst iter = tree.begin(); iter != tree.end(); ++iter) {
- const Range& r = *iter;
- if (r.single)
- std::cout << " [" << r.min << "]\n";
- else
- std::cout << " [" << r.min << ", " << r.max << "]\n";
- }
- if (empty())
- std::cout << " <empty>";
- std::cout << "\n";
- }
-
- unsigned int allocation_lower_bound() const {
- return tree.size() * sizeof(Range);
- }
-
-private:
- Tree tree;
-};
diff --git a/extern/rangetree/range_tree_c_api.cc b/extern/rangetree/range_tree_c_api.cc
deleted file mode 100644
index f040b5eaeb6..00000000000
--- a/extern/rangetree/range_tree_c_api.cc
+++ /dev/null
@@ -1,92 +0,0 @@
-/* This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA.
-*/
-
-#include "range_tree.hh"
-
-/* Give RangeTreeUInt a real type rather than the opaque struct type
- defined for external use. */
-#define RANGE_TREE_C_API_INTERNAL
-typedef RangeTree<unsigned> RangeTreeUInt;
-
-#include "range_tree_c_api.h"
-
-RangeTreeUInt *range_tree_uint_alloc(unsigned min, unsigned max)
-{
- return new RangeTreeUInt(min, max);
-}
-
-RangeTreeUInt *range_tree_uint_copy(RangeTreeUInt *src)
-{
- return new RangeTreeUInt(*src);
-}
-
-void range_tree_uint_free(RangeTreeUInt *rt)
-{
- delete rt;
-}
-
-void range_tree_uint_take(RangeTreeUInt *rt, unsigned v)
-{
- rt->take(v);
-}
-
-bool range_tree_uint_retake(RangeTreeUInt *rt, unsigned v)
-{
- return rt->retake(v);
-}
-
-unsigned range_tree_uint_take_any(RangeTreeUInt *rt)
-{
- return rt->take_any();
-}
-
-void range_tree_uint_release(RangeTreeUInt *rt, unsigned v)
-{
- rt->release(v);
-}
-
-bool range_tree_uint_has(const RangeTreeUInt *rt, unsigned v)
-{
- return rt->has(v);
-}
-
-bool range_tree_uint_has_range(
- const RangeTreeUInt *rt,
- unsigned vmin,
- unsigned vmax)
-{
- return rt->has_range(vmin, vmax);
-}
-
-bool range_tree_uint_empty(const RangeTreeUInt *rt)
-{
- return rt->empty();
-}
-
-unsigned range_tree_uint_size(const RangeTreeUInt *rt)
-{
- return rt->size();
-}
-
-void range_tree_uint_print(const RangeTreeUInt *rt)
-{
- rt->print();
-}
-
-unsigned int range_tree_uint_allocation_lower_bound(const RangeTreeUInt *rt)
-{
- return rt->allocation_lower_bound();
-}
diff --git a/extern/rangetree/range_tree_c_api.h b/extern/rangetree/range_tree_c_api.h
deleted file mode 100644
index 6abfb6bd55e..00000000000
--- a/extern/rangetree/range_tree_c_api.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/* This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA.
-*/
-
-#ifndef __RANGE_TREE_C_API_H__
-#define __RANGE_TREE_C_API_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Simple C-accessible wrapper for RangeTree<unsigned> */
-
-#ifndef RANGE_TREE_C_API_INTERNAL
-typedef struct RangeTreeUInt RangeTreeUInt;
-#endif
-
-RangeTreeUInt *range_tree_uint_alloc(unsigned min, unsigned max);
-
-RangeTreeUInt *range_tree_uint_copy(RangeTreeUInt *src);
-
-void range_tree_uint_free(RangeTreeUInt *rt);
-
-void range_tree_uint_take(RangeTreeUInt *rt, unsigned v);
-
-bool range_tree_uint_retake(RangeTreeUInt *rt, unsigned v);
-
-unsigned range_tree_uint_take_any(RangeTreeUInt *rt);
-
-void range_tree_uint_release(RangeTreeUInt *rt, unsigned v);
-
-bool range_tree_uint_has(const RangeTreeUInt *rt, unsigned v);
-
-bool range_tree_uint_has_range(
- const RangeTreeUInt *rt,
- unsigned vmin, unsigned vmax);
-
-bool range_tree_uint_empty(const RangeTreeUInt *rt);
-
-unsigned range_tree_uint_size(const RangeTreeUInt *rt);
-
-void range_tree_uint_print(const RangeTreeUInt *rt);
-
-unsigned int range_tree_uint_allocation_lower_bound(const RangeTreeUInt *rt);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __RANGE_TREE_C_API_H__ */
diff --git a/extern/recastnavigation/CMakeLists.txt b/extern/recastnavigation/CMakeLists.txt
index d6c7fd357b1..19ac6e9dde8 100644
--- a/extern/recastnavigation/CMakeLists.txt
+++ b/extern/recastnavigation/CMakeLists.txt
@@ -23,9 +23,11 @@
#
# ***** END GPL LICENSE BLOCK *****
+remove_cc_flag_unsigned_char()
+
set(INC
- Recast/Include
- Detour/Include
+ Recast/Include
+ Detour/Include
)
set(INC_SYS
@@ -33,38 +35,38 @@ set(INC_SYS
)
set(SRC
- recast-capi.cpp
- recast-capi.h
+ recast-capi.cpp
+ recast-capi.h
- Detour/Source/DetourCommon.cpp
- Detour/Source/DetourNode.cpp
- Detour/Source/DetourStatNavMesh.cpp
- Detour/Source/DetourStatNavMeshBuilder.cpp
- Detour/Source/DetourTileNavMesh.cpp
- Detour/Source/DetourTileNavMeshBuilder.cpp
+ Detour/Source/DetourCommon.cpp
+ Detour/Source/DetourNode.cpp
+ Detour/Source/DetourStatNavMesh.cpp
+ Detour/Source/DetourStatNavMeshBuilder.cpp
+ Detour/Source/DetourTileNavMesh.cpp
+ Detour/Source/DetourTileNavMeshBuilder.cpp
- Detour/Include/DetourCommon.h
- Detour/Include/DetourNode.h
- Detour/Include/DetourStatNavMesh.h
- Detour/Include/DetourStatNavMeshBuilder.h
- Detour/Include/DetourTileNavMesh.h
- Detour/Include/DetourTileNavMeshBuilder.h
+ Detour/Include/DetourCommon.h
+ Detour/Include/DetourNode.h
+ Detour/Include/DetourStatNavMesh.h
+ Detour/Include/DetourStatNavMeshBuilder.h
+ Detour/Include/DetourTileNavMesh.h
+ Detour/Include/DetourTileNavMeshBuilder.h
- Recast/Source/Recast.cpp
- Recast/Source/RecastAlloc.cpp
- Recast/Source/RecastArea.cpp
- Recast/Source/RecastContour.cpp
- Recast/Source/RecastFilter.cpp
- Recast/Source/RecastLayers.cpp
- Recast/Source/RecastMesh.cpp
- Recast/Source/RecastMeshDetail.cpp
- Recast/Source/RecastRasterization.cpp
- Recast/Source/RecastRegion.cpp
+ Recast/Source/Recast.cpp
+ Recast/Source/RecastAlloc.cpp
+ Recast/Source/RecastArea.cpp
+ Recast/Source/RecastContour.cpp
+ Recast/Source/RecastFilter.cpp
+ Recast/Source/RecastLayers.cpp
+ Recast/Source/RecastMesh.cpp
+ Recast/Source/RecastMeshDetail.cpp
+ Recast/Source/RecastRasterization.cpp
+ Recast/Source/RecastRegion.cpp
- Recast/Include/Recast.h
- Recast/Include/RecastAlloc.h
- Recast/Include/RecastAssert.h
+ Recast/Include/Recast.h
+ Recast/Include/RecastAlloc.h
+ Recast/Include/RecastAssert.h
)
blender_add_lib(extern_recastnavigation "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/extern/sdlew/README.blender b/extern/sdlew/README.blender
new file mode 100644
index 00000000000..773f03737c7
--- /dev/null
+++ b/extern/sdlew/README.blender
@@ -0,0 +1,5 @@
+Project: SDL Extension Wrangler
+URL: https://github.com/SDLWrangler/sdlew
+License: Apache 2.0
+Upstream version: 15edf8e
+Local modifications: None
diff --git a/extern/wcwidth/README.blender b/extern/wcwidth/README.blender
new file mode 100644
index 00000000000..27c8574d1d7
--- /dev/null
+++ b/extern/wcwidth/README.blender
@@ -0,0 +1,5 @@
+Project: WC Width
+URL: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
+License: ICS
+Upstream version: 2007-05-26
+Local modifications: None
diff --git a/extern/xdnd/README.blender b/extern/xdnd/README.blender
new file mode 100644
index 00000000000..05afe566bba
--- /dev/null
+++ b/extern/xdnd/README.blender
@@ -0,0 +1,8 @@
+Project: X Drag and Drop
+URL: http://www.newplanetsoftware.com/xdnd/ (defunct)
+ https://freedesktop.org/wiki/Specifications/XDND/ (cache)
+License: GPLv2+
+Upstream version: 2000-08-08
+Local modifications:
+* Fix T33192
+ Opening Blender breaks drag-and-drop support on the KDE desktop.
diff --git a/intern/CMakeLists.txt b/intern/CMakeLists.txt
index 43e5b6bff3e..9a5476772ab 100644
--- a/intern/CMakeLists.txt
+++ b/intern/CMakeLists.txt
@@ -34,6 +34,10 @@ add_subdirectory(mikktspace)
add_subdirectory(glew-mx)
add_subdirectory(eigen)
+if (WITH_GAMEENGINE_DECKLINK)
+ add_subdirectory(decklink)
+endif()
+
if(WITH_AUDASPACE)
add_subdirectory(audaspace)
endif()
@@ -79,8 +83,10 @@ if(WITH_OPENSUBDIV)
endif()
# only windows needs utf16 converter
+# gpudirect is a runtime interface to the nVidia's DVP driver, only for windows
if(WIN32)
add_subdirectory(utfconv)
+ add_subdirectory(gpudirect)
endif()
if(WITH_OPENVDB)
diff --git a/intern/atomic/atomic_ops.h b/intern/atomic/atomic_ops.h
index e4e1bdc1c09..0bc7905aa07 100644
--- a/intern/atomic/atomic_ops.h
+++ b/intern/atomic/atomic_ops.h
@@ -86,6 +86,8 @@ ATOMIC_INLINE uint32_t atomic_add_uint32(uint32_t *p, uint32_t x);
ATOMIC_INLINE uint32_t atomic_sub_uint32(uint32_t *p, uint32_t x);
ATOMIC_INLINE uint32_t atomic_cas_uint32(uint32_t *v, uint32_t old, uint32_t _new);
+ATOMIC_INLINE uint32_t atomic_fetch_and_add_uint32(uint32_t *p, uint32_t x);
+
ATOMIC_INLINE uint8_t atomic_fetch_and_or_uint8(uint8_t *p, uint8_t b);
ATOMIC_INLINE uint8_t atomic_fetch_and_and_uint8(uint8_t *p, uint8_t b);
diff --git a/intern/atomic/intern/atomic_ops_msvc.h b/intern/atomic/intern/atomic_ops_msvc.h
index bd9186e7864..15ddda246d9 100644
--- a/intern/atomic/intern/atomic_ops_msvc.h
+++ b/intern/atomic/intern/atomic_ops_msvc.h
@@ -76,6 +76,11 @@ ATOMIC_INLINE uint32_t atomic_cas_uint32(uint32_t *v, uint32_t old, uint32_t _ne
return InterlockedCompareExchange((long *)v, _new, old);
}
+ATOMIC_INLINE uint32_t atomic_fetch_and_add_uint32(uint32_t *p, uint32_t x)
+{
+ return InterlockedExchangeAdd(p, x);
+}
+
/******************************************************************************/
/* 8-bit operations. */
diff --git a/intern/atomic/intern/atomic_ops_unix.h b/intern/atomic/intern/atomic_ops_unix.h
index 05d0fbf1856..55c00024244 100644
--- a/intern/atomic/intern/atomic_ops_unix.h
+++ b/intern/atomic/intern/atomic_ops_unix.h
@@ -129,23 +129,24 @@ ATOMIC_INLINE uint32_t atomic_cas_uint32(uint32_t *v, uint32_t old, uint32_t _ne
#elif (defined(__i386__) || defined(__amd64__) || defined(__x86_64__))
ATOMIC_INLINE uint32_t atomic_add_uint32(uint32_t *p, uint32_t x)
{
+ uint32_t ret = x;
asm volatile (
"lock; xaddl %0, %1;"
- : "+r" (x), "=m" (*p) /* Outputs. */
+ : "+r" (ret), "=m" (*p) /* Outputs. */
: "m" (*p) /* Inputs. */
);
- return x;
+ return ret+x;
}
ATOMIC_INLINE uint32_t atomic_sub_uint32(uint32_t *p, uint32_t x)
{
- x = (uint32_t)(-(int32_t)x);
+ ret = (uint32_t)(-(int32_t)x);
asm volatile (
"lock; xaddl %0, %1;"
- : "+r" (x), "=m" (*p) /* Outputs. */
+ : "+r" (ret), "=m" (*p) /* Outputs. */
: "m" (*p) /* Inputs. */
);
- return x;
+ return ret-x;
}
ATOMIC_INLINE uint32_t atomic_cas_uint32(uint32_t *v, uint32_t old, uint32_t _new)
@@ -162,6 +163,16 @@ ATOMIC_INLINE uint32_t atomic_cas_uint32(uint32_t *v, uint32_t old, uint32_t _ne
# error "Missing implementation for 32-bit atomic operations"
#endif
+#if (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_4))
+ATOMIC_INLINE uint32_t atomic_fetch_and_add_uint32(uint32_t *p, uint32_t x)
+{
+ return __sync_fetch_and_add(p, x);
+}
+
+#else
+# error "Missing implementation for 32-bit atomic operations"
+#endif
+
/******************************************************************************/
/* 8-bit operations. */
#if (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1) || defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_1))
diff --git a/intern/atomic/intern/atomic_ops_utils.h b/intern/atomic/intern/atomic_ops_utils.h
index fcbb2346243..bfec9918c16 100644
--- a/intern/atomic/intern/atomic_ops_utils.h
+++ b/intern/atomic/intern/atomic_ops_utils.h
@@ -81,7 +81,9 @@
# endif
#endif
-#ifdef UINTPTR_MAX
+#if defined(__SIZEOF_POINTER__)
+# define LG_SIZEOF_PTR __SIZEOF_POINTER__
+#elif defined(UINTPTR_MAX)
# if (UINTPTR_MAX == 0xFFFFFFFF)
# define LG_SIZEOF_PTR 4
# elif (UINTPTR_MAX == 0xFFFFFFFFFFFFFFFF)
diff --git a/intern/audaspace/Python/AUD_PyAPI.cpp b/intern/audaspace/Python/AUD_PyAPI.cpp
index 300fd55e23b..6d4939bf96c 100644
--- a/intern/audaspace/Python/AUD_PyAPI.cpp
+++ b/intern/audaspace/Python/AUD_PyAPI.cpp
@@ -861,7 +861,7 @@ Factory_filter(Factory* self, PyObject *args)
py_a_len= py_a ? PySequence_Size(py_a) : 0;
py_b_len= PySequence_Size(py_b);
- if(!py_b_len || ((py_a != NULL) && !py_b_len))
+ if(!py_b_len || ((py_a != NULL) && !py_a_len))
{
PyErr_SetString(PyExc_ValueError, "The sequence has to contain at least one value!");
return NULL;
@@ -2698,7 +2698,7 @@ Device_set_doppler_factor(Device *self, PyObject *args, void* nothing)
PyDoc_STRVAR(M_aud_Device_distance_model_doc,
"The distance model of the device.\n\n"
- ".. seealso:: http://connect.creativelabs.com/openal/Documentation/OpenAL%201.1%20Specification.htm#_Toc199835864");
+ ".. seealso:: `OpenAL documentation <https://www.openal.org/documentation>`");
static PyObject *
Device_get_distance_model(Device *self, void* nothing)
diff --git a/intern/audaspace/intern/AUD_C-API.cpp b/intern/audaspace/intern/AUD_C-API.cpp
index b326c9f4281..52cf256147f 100644
--- a/intern/audaspace/intern/AUD_C-API.cpp
+++ b/intern/audaspace/intern/AUD_C-API.cpp
@@ -155,18 +155,18 @@ AUD_Device* AUD_init(const char* device, AUD_DeviceSpecs specs, int buffersize,
}
#endif
#ifdef WITH_JACK
- else if(dname == "Jack")
+ else if(dname == "JACK")
{
#ifdef __APPLE__
struct stat st;
if (stat("/Library/Frameworks/Jackmp.framework", &st) != 0) {
- printf("Warning: Jack Framework not installed\n");
+ printf("Warning: JACK Framework not installed\n");
return NULL;
}
else
#endif
if (!AUD_jack_supported()) {
- printf("Warning: Jack cllient not installed\n");
+ printf("Warning: JACK cllient not installed\n");
return NULL;
}
else {
diff --git a/intern/audaspace/intern/AUD_C-API.h b/intern/audaspace/intern/AUD_C-API.h
index bdbe751b140..cc9059a8e09 100644
--- a/intern/audaspace/intern/AUD_C-API.h
+++ b/intern/audaspace/intern/AUD_C-API.h
@@ -61,7 +61,7 @@ typedef struct
#endif
/**
- * Initializes audio rutines (FFMPEG/Jack if it is enabled).
+ * Initializes audio routines (FFMPEG/JACK if it is enabled).
*/
extern void AUD_initOnce(void);
diff --git a/intern/audaspace/intern/AUD_Mixer.cpp b/intern/audaspace/intern/AUD_Mixer.cpp
index 380affa6bd1..78dfaddd27a 100644
--- a/intern/audaspace/intern/AUD_Mixer.cpp
+++ b/intern/audaspace/intern/AUD_Mixer.cpp
@@ -95,6 +95,21 @@ void AUD_Mixer::mix(sample_t* buffer, int start, int length, float volume)
out[i + start] += buffer[i] * volume;
}
+void AUD_Mixer::mix(sample_t* buffer, int start, int length, float volume_to, float volume_from)
+{
+ sample_t* out = m_buffer.getBuffer();
+
+ length = (std::min(m_length, length + start) - start);
+
+ for(int i = 0; i < length; i++)
+ {
+ float volume = volume_from * (1.0f - i / float(length)) + volume_to * (i / float(length));
+
+ for(int c = 0; c < m_specs.channels; c++)
+ out[(i + start) * m_specs.channels + c] += buffer[i * m_specs.channels + c] * volume;
+ }
+}
+
void AUD_Mixer::read(data_t* buffer, float volume)
{
sample_t* out = m_buffer.getBuffer();
diff --git a/intern/audaspace/intern/AUD_Mixer.h b/intern/audaspace/intern/AUD_Mixer.h
index 3dd03b0a3fe..0735fee715b 100644
--- a/intern/audaspace/intern/AUD_Mixer.h
+++ b/intern/audaspace/intern/AUD_Mixer.h
@@ -95,6 +95,8 @@ public:
*/
void mix(sample_t* buffer, int start, int length, float volume);
+ void mix(sample_t* buffer, int start, int length, float volume_to, float volume_from);
+
/**
* Writes the mixing buffer into an output buffer.
* \param buffer The target buffer for superposing.
diff --git a/intern/audaspace/intern/AUD_SoftwareDevice.cpp b/intern/audaspace/intern/AUD_SoftwareDevice.cpp
index c4277a6d02e..15594d340be 100644
--- a/intern/audaspace/intern/AUD_SoftwareDevice.cpp
+++ b/intern/audaspace/intern/AUD_SoftwareDevice.cpp
@@ -89,7 +89,7 @@ bool AUD_SoftwareDevice::AUD_SoftwareHandle::pause(bool keep)
}
AUD_SoftwareDevice::AUD_SoftwareHandle::AUD_SoftwareHandle(AUD_SoftwareDevice* device, boost::shared_ptr<AUD_IReader> reader, boost::shared_ptr<AUD_PitchReader> pitch, boost::shared_ptr<AUD_ResampleReader> resampler, boost::shared_ptr<AUD_ChannelMapperReader> mapper, bool keep) :
- m_reader(reader), m_pitch(pitch), m_resampler(resampler), m_mapper(mapper), m_keep(keep), m_user_pitch(1.0f), m_user_volume(1.0f), m_user_pan(0.0f), m_volume(1.0f), m_loopcount(0),
+ m_reader(reader), m_pitch(pitch), m_resampler(resampler), m_mapper(mapper), m_keep(keep), m_user_pitch(1.0f), m_user_volume(1.0f), m_user_pan(0.0f), m_volume(1.0f), m_old_volume(1.0f), m_loopcount(0),
m_relative(true), m_volume_max(1.0f), m_volume_min(0), m_distance_max(std::numeric_limits<float>::max()),
m_distance_reference(1.0f), m_attenuation(1.0f), m_cone_angle_outer(M_PI), m_cone_angle_inner(M_PI), m_cone_volume_outer(0),
m_flags(AUD_RENDER_CONE), m_stop(NULL), m_stop_data(NULL), m_status(AUD_STATUS_PLAYING), m_device(device)
@@ -100,6 +100,8 @@ void AUD_SoftwareDevice::AUD_SoftwareHandle::update()
{
int flags = 0;
+ m_old_volume = m_volume;
+
AUD_Vector3 SL;
if(m_relative)
SL = -m_location;
@@ -404,7 +406,7 @@ bool AUD_SoftwareDevice::AUD_SoftwareHandle::setVolume(float volume)
if(volume == 0)
{
- m_volume = volume;
+ m_old_volume = m_volume = volume;
m_flags |= AUD_RENDER_VOLUME;
}
else
@@ -772,7 +774,7 @@ void AUD_SoftwareDevice::mix(data_t* buffer, int length)
// in case of looping
while(pos + len < length && sound->m_loopcount && eos)
{
- m_mixer->mix(buf, pos, len, sound->m_volume);
+ m_mixer->mix(buf, pos, len, sound->m_volume, sound->m_old_volume);
pos += len;
@@ -789,7 +791,7 @@ void AUD_SoftwareDevice::mix(data_t* buffer, int length)
break;
}
- m_mixer->mix(buf, pos, len, sound->m_volume);
+ m_mixer->mix(buf, pos, len, sound->m_volume, sound->m_old_volume);
// in case the end of the sound is reached
if(eos && !sound->m_loopcount)
diff --git a/intern/audaspace/intern/AUD_SoftwareDevice.h b/intern/audaspace/intern/AUD_SoftwareDevice.h
index 3c8c1e438a3..54e49c87b27 100644
--- a/intern/audaspace/intern/AUD_SoftwareDevice.h
+++ b/intern/audaspace/intern/AUD_SoftwareDevice.h
@@ -84,6 +84,7 @@ protected:
/// The calculated final volume of the source.
float m_volume;
+ float m_old_volume;
/// The loop count of the source.
int m_loopcount;
diff --git a/intern/audaspace/jack/AUD_JackDevice.h b/intern/audaspace/jack/AUD_JackDevice.h
index a82a6bc5c38..ccf3bfd6341 100644
--- a/intern/audaspace/jack/AUD_JackDevice.h
+++ b/intern/audaspace/jack/AUD_JackDevice.h
@@ -41,7 +41,7 @@
typedef void (*AUD_syncFunction)(void*, int, float);
/**
- * This device plays back through Jack.
+ * This device plays back through JACK.
*/
class AUD_JackDevice : public AUD_SoftwareDevice
{
@@ -90,7 +90,7 @@ private:
static int jack_sync(jack_transport_state_t state, jack_position_t* pos, void* data);
/**
- * Next Jack Transport state (-1 if not expected to change).
+ * Next JACK Transport state (-1 if not expected to change).
*/
jack_transport_state_t m_nextState;
@@ -150,7 +150,7 @@ protected:
public:
/**
- * Creates a Jack client for audio output.
+ * Creates a JACK client for audio output.
* \param name The client name.
* \param specs The wanted audio specification, where only the channel count
* is important.
@@ -160,7 +160,7 @@ public:
AUD_JackDevice(std::string name, AUD_DeviceSpecs specs, int buffersize = AUD_DEFAULT_BUFFER_SIZE);
/**
- * Closes the Jack client.
+ * Closes the JACK client.
*/
virtual ~AUD_JackDevice();
diff --git a/intern/audaspace/jack/AUD_JackLibrary.cpp b/intern/audaspace/jack/AUD_JackLibrary.cpp
index 63306ee0b15..9ed6862bbb9 100644
--- a/intern/audaspace/jack/AUD_JackLibrary.cpp
+++ b/intern/audaspace/jack/AUD_JackLibrary.cpp
@@ -44,7 +44,20 @@ static bool jack_supported = false;
void AUD_jack_init(void)
{
#ifdef WITH_JACK_DYNLOAD
- jack_handle = dlopen("libjack.so", RTLD_LAZY);
+ const char *names[] = {"libjack.so",
+ "libjack.so.0",
+ "libjack.so.1",
+ "libjack.so.2",
+ NULL};
+ int index = 0;
+ while (names[index] != NULL) {
+ jack_handle = dlopen(names[index], RTLD_LAZY);
+ if (jack_handle != NULL) {
+ // Found existing library.
+ break;
+ }
+ ++index;
+ }
if (!jack_handle) {
return;
diff --git a/intern/audaspace/jack/AUD_JackLibrary.h b/intern/audaspace/jack/AUD_JackLibrary.h
index 2a737a1a4e2..d74d9ba8021 100644
--- a/intern/audaspace/jack/AUD_JackLibrary.h
+++ b/intern/audaspace/jack/AUD_JackLibrary.h
@@ -42,7 +42,7 @@
# define JACK_SYM extern
#endif
-/* All loadable Jack sumbols, prototypes from original jack.h */
+/* All loadable JACK sumbols, prototypes from original jack.h */
JACK_SYM jack_transport_state_t (*AUD_jack_transport_query) (
const jack_client_t *client,
diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt
index 0e04ca6db43..cf0248b7d15 100644
--- a/intern/cycles/CMakeLists.txt
+++ b/intern/cycles/CMakeLists.txt
@@ -146,6 +146,14 @@ if(WITH_CYCLES_OSL)
)
endif()
+if(WITH_CYCLES_OPENSUBDIV)
+ add_definitions(-DWITH_OPENSUBDIV)
+ include_directories(
+ SYSTEM
+ ${OPENSUBDIV_INCLUDE_DIR}
+ )
+endif()
+
if(WITH_OPENVDB)
add_definitions(-DWITH_OPENVDB)
add_definitions(-DDWREAL_IS_DOUBLE=0)
@@ -163,7 +171,9 @@ set(WITH_CYCLES_DEVICE_MULTI TRUE)
if(CYCLES_STANDALONE_REPOSITORY)
TEST_UNORDERED_MAP_SUPPORT()
endif()
-if(HAVE_STD_UNORDERED_MAP_HEADER)
+if(WITH_CXX11)
+ add_definitions(-DCYCLES_STD_UNORDERED_MAP)
+elseif(HAVE_STD_UNORDERED_MAP_HEADER)
if(HAVE_UNORDERED_MAP_IN_STD_NAMESPACE)
add_definitions(-DCYCLES_STD_UNORDERED_MAP)
else()
@@ -245,6 +255,7 @@ endif()
add_subdirectory(bvh)
add_subdirectory(device)
add_subdirectory(doc)
+add_subdirectory(graph)
add_subdirectory(kernel)
add_subdirectory(render)
add_subdirectory(subd)
diff --git a/intern/cycles/app/CMakeLists.txt b/intern/cycles/app/CMakeLists.txt
index d40a1a14f72..8cd499b7ca6 100644
--- a/intern/cycles/app/CMakeLists.txt
+++ b/intern/cycles/app/CMakeLists.txt
@@ -1,13 +1,14 @@
set(INC
.
+ ../bvh
../device
+ ../graph
../kernel
../kernel/svm
- ../bvh
- ../util
../render
../subd
+ ../util
)
set(INC_SYS
)
@@ -20,6 +21,7 @@ set(LIBRARIES
cycles_render
cycles_bvh
cycles_subd
+ cycles_graph
cycles_util
${BLENDER_GL_LIBRARIES}
${CYCLES_APP_GLEW_LIBRARY}
@@ -86,6 +88,9 @@ macro(cycles_target_link_libraries target)
if(WITH_CYCLES_OSL)
target_link_libraries(${target} ${OSL_LIBRARIES} ${LLVM_LIBRARIES})
endif()
+ if(WITH_CYCLES_OPENSUBDIV)
+ target_link_libraries(${target} ${OPENSUBDIV_LIBRARIES})
+ endif()
target_link_libraries(
${target}
${OPENIMAGEIO_LIBRARIES}
diff --git a/intern/cycles/app/cycles_standalone.cpp b/intern/cycles/app/cycles_standalone.cpp
index 726e9a51744..e8168bc15ff 100644
--- a/intern/cycles/app/cycles_standalone.cpp
+++ b/intern/cycles/app/cycles_standalone.cpp
@@ -375,6 +375,8 @@ static void options_parse(int argc, const char **argv)
"--threads %d", &options.session_params.threads, "CPU Rendering Threads",
"--width %d", &options.width, "Window width in pixel",
"--height %d", &options.height, "Window height in pixel",
+ "--tile-width %d", &options.session_params.tile_size.x, "Tile width in pixels",
+ "--tile-height %d", &options.session_params.tile_size.y, "Tile height in pixels",
"--list-devices", &list, "List information about all available devices",
#ifdef WITH_CYCLES_LOGGING
"--debug", &debug, "Enable debug logging",
diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp
index 878d7c23715..e2197a33e63 100644
--- a/intern/cycles/app/cycles_xml.cpp
+++ b/intern/cycles/app/cycles_xml.cpp
@@ -20,6 +20,8 @@
#include <algorithm>
#include <iterator>
+#include "node_xml.h"
+
#include "background.h"
#include "camera.h"
#include "film.h"
@@ -29,10 +31,10 @@
#include "mesh.h"
#include "nodes.h"
#include "object.h"
+#include "osl.h"
#include "shader.h"
#include "scene.h"
-#include "subd_mesh.h"
#include "subd_patch.h"
#include "subd_split.h"
@@ -48,21 +50,19 @@ CCL_NAMESPACE_BEGIN
/* XML reading state */
-struct XMLReadState {
+struct XMLReadState : public XMLReader {
Scene *scene; /* scene pointer */
Transform tfm; /* current transform state */
bool smooth; /* smooth normal state */
- int shader; /* current shader */
+ Shader *shader; /* current shader */
string base; /* base path to current file*/
float dicing_rate; /* current dicing rate */
- Mesh::DisplacementMethod displacement_method;
XMLReadState()
: scene(NULL),
smooth(false),
- shader(0),
- dicing_rate(0.0f),
- displacement_method(Mesh::DISPLACE_BUMP)
+ shader(NULL),
+ dicing_rate(1.0f)
{
tfm = transform_identity();
}
@@ -70,18 +70,6 @@ struct XMLReadState {
/* Attribute Reading */
-static bool xml_read_bool(bool *value, pugi::xml_node node, const char *name)
-{
- pugi::xml_attribute attr = node.attribute(name);
-
- if(attr) {
- *value = (string_iequals(attr.value(), "true")) || (atoi(attr.value()) != 0);
- return true;
- }
-
- return false;
-}
-
static bool xml_read_int(int *value, pugi::xml_node node, const char *name)
{
pugi::xml_attribute attr = node.attribute(name);
@@ -190,18 +178,6 @@ static bool xml_read_string(string *str, pugi::xml_node node, const char *name)
return false;
}
-static bool xml_read_ustring(ustring *str, pugi::xml_node node, const char *name)
-{
- pugi::xml_attribute attr = node.attribute(name);
-
- if(attr) {
- *str = ustring(attr.value());
- return true;
- }
-
- return false;
-}
-
static bool xml_equal_string(pugi::xml_node node, const char *name, const char *value)
{
pugi::xml_attribute attr = node.attribute(name);
@@ -212,159 +188,19 @@ static bool xml_equal_string(pugi::xml_node node, const char *name, const char *
return false;
}
-static bool xml_read_enum(ustring *str, ShaderEnum& enm, pugi::xml_node node, const char *name)
-{
- pugi::xml_attribute attr = node.attribute(name);
-
- if(attr) {
- ustring ustr(attr.value());
-
- if(enm.exists(ustr)) {
- *str = ustr;
- return true;
- }
- else
- fprintf(stderr, "Unknown value \"%s\" for attribute \"%s\".\n", ustr.c_str(), name);
- }
-
- return false;
-}
-
-static ShaderSocketType xml_read_socket_type(pugi::xml_node node, const char *name)
-{
- pugi::xml_attribute attr = node.attribute(name);
-
- if(attr) {
- string value = attr.value();
- if(string_iequals(value, "float"))
- return SHADER_SOCKET_FLOAT;
- else if(string_iequals(value, "int"))
- return SHADER_SOCKET_INT;
- else if(string_iequals(value, "color"))
- return SHADER_SOCKET_COLOR;
- else if(string_iequals(value, "vector"))
- return SHADER_SOCKET_VECTOR;
- else if(string_iequals(value, "point"))
- return SHADER_SOCKET_POINT;
- else if(string_iequals(value, "normal"))
- return SHADER_SOCKET_NORMAL;
- else if(string_iequals(value, "closure color"))
- return SHADER_SOCKET_CLOSURE;
- else if(string_iequals(value, "string"))
- return SHADER_SOCKET_STRING;
- else
- fprintf(stderr, "Unknown shader socket type \"%s\" for attribute \"%s\".\n", value.c_str(), name);
- }
-
- return SHADER_SOCKET_UNDEFINED;
-}
-
-/* Film */
-
-static void xml_read_film(const XMLReadState& state, pugi::xml_node node)
-{
- Film *film = state.scene->film;
-
- xml_read_float(&film->exposure, node, "exposure");
-
- /* ToDo: Filter Type */
- xml_read_float(&film->filter_width, node, "filter_width");
-}
-
-/* Integrator */
-
-static void xml_read_integrator(const XMLReadState& state, pugi::xml_node node)
-{
- Integrator *integrator = state.scene->integrator;
-
- /* Branched Path */
- bool branched = false;
- xml_read_bool(&branched, node, "branched");
-
- if(branched) {
- integrator->method = Integrator::BRANCHED_PATH;
-
- xml_read_int(&integrator->diffuse_samples, node, "diffuse_samples");
- xml_read_int(&integrator->glossy_samples, node, "glossy_samples");
- xml_read_int(&integrator->transmission_samples, node, "transmission_samples");
- xml_read_int(&integrator->ao_samples, node, "ao_samples");
- xml_read_int(&integrator->mesh_light_samples, node, "mesh_light_samples");
- xml_read_int(&integrator->subsurface_samples, node, "subsurface_samples");
- xml_read_int(&integrator->volume_samples, node, "volume_samples");
- xml_read_bool(&integrator->sample_all_lights_direct, node, "sample_all_lights_direct");
- xml_read_bool(&integrator->sample_all_lights_indirect, node, "sample_all_lights_indirect");
- }
-
- /* Bounces */
- xml_read_int(&integrator->min_bounce, node, "min_bounce");
- xml_read_int(&integrator->max_bounce, node, "max_bounce");
-
- xml_read_int(&integrator->max_diffuse_bounce, node, "max_diffuse_bounce");
- xml_read_int(&integrator->max_glossy_bounce, node, "max_glossy_bounce");
- xml_read_int(&integrator->max_transmission_bounce, node, "max_transmission_bounce");
- xml_read_int(&integrator->max_volume_bounce, node, "max_volume_bounce");
-
- /* Transparency */
- xml_read_int(&integrator->transparent_min_bounce, node, "transparent_min_bounce");
- xml_read_int(&integrator->transparent_max_bounce, node, "transparent_max_bounce");
- xml_read_bool(&integrator->transparent_shadows, node, "transparent_shadows");
-
- /* Volume */
- xml_read_float(&integrator->volume_step_size, node, "volume_step_size");
- xml_read_int(&integrator->volume_max_steps, node, "volume_max_steps");
-
- /* Various Settings */
- xml_read_bool(&integrator->caustics_reflective, node, "caustics_reflective");
- xml_read_bool(&integrator->caustics_refractive, node, "caustics_refractive");
- xml_read_float(&integrator->filter_glossy, node, "filter_glossy");
-
- xml_read_int(&integrator->seed, node, "seed");
- xml_read_float(&integrator->sample_clamp_direct, node, "sample_clamp_direct");
- xml_read_float(&integrator->sample_clamp_indirect, node, "sample_clamp_indirect");
-}
-
/* Camera */
-static void xml_read_camera(const XMLReadState& state, pugi::xml_node node)
+static void xml_read_camera(XMLReadState& state, pugi::xml_node node)
{
Camera *cam = state.scene->camera;
xml_read_int(&cam->width, node, "width");
xml_read_int(&cam->height, node, "height");
- if(xml_read_float(&cam->fov, node, "fov"))
- cam->fov = DEG2RADF(cam->fov);
-
- xml_read_float(&cam->nearclip, node, "nearclip");
- xml_read_float(&cam->farclip, node, "farclip");
- xml_read_float(&cam->aperturesize, node, "aperturesize"); // 0.5*focallength/fstop
- xml_read_float(&cam->focaldistance, node, "focaldistance");
- xml_read_float(&cam->shuttertime, node, "shuttertime");
- xml_read_float(&cam->aperture_ratio, node, "aperture_ratio");
-
- if(xml_equal_string(node, "type", "orthographic"))
- cam->type = CAMERA_ORTHOGRAPHIC;
- else if(xml_equal_string(node, "type", "perspective"))
- cam->type = CAMERA_PERSPECTIVE;
- else if(xml_equal_string(node, "type", "panorama"))
- cam->type = CAMERA_PANORAMA;
+ cam->full_width = cam->width;
+ cam->full_height = cam->height;
- if(xml_equal_string(node, "panorama_type", "equirectangular"))
- cam->panorama_type = PANORAMA_EQUIRECTANGULAR;
- else if(xml_equal_string(node, "panorama_type", "fisheye_equidistant"))
- cam->panorama_type = PANORAMA_FISHEYE_EQUIDISTANT;
- else if(xml_equal_string(node, "panorama_type", "fisheye_equisolid"))
- cam->panorama_type = PANORAMA_FISHEYE_EQUISOLID;
-
- xml_read_float(&cam->fisheye_fov, node, "fisheye_fov");
- xml_read_float(&cam->fisheye_lens, node, "fisheye_lens");
-
- xml_read_bool(&cam->use_spherical_stereo, node, "use_spherical_stereo");
- xml_read_float(&cam->interocular_distance, node, "interocular_distance");
- xml_read_float(&cam->convergence_distance, node, "convergence_distance");
-
- xml_read_float(&cam->sensorwidth, node, "sensorwidth");
- xml_read_float(&cam->sensorheight, node, "sensorheight");
+ xml_read_node(state, cam, node);
cam->matrix = state.tfm;
@@ -385,361 +221,20 @@ static string xml_socket_name(const char *name)
return sname;
}
-static void xml_read_shader_graph(const XMLReadState& state, Shader *shader, pugi::xml_node graph_node)
+static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml_node graph_node)
{
- ShaderGraph *graph = new ShaderGraph();
+ xml_read_node(state, shader, graph_node);
- map<string, ShaderNode*> nodemap;
+ ShaderGraph *graph = new ShaderGraph();
- nodemap["output"] = graph->output();
+ /* local state, shader nodes can't link to nodes outside the shader graph */
+ XMLReader graph_reader;
+ graph_reader.node_map[ustring("output")] = graph->output();
for(pugi::xml_node node = graph_node.first_child(); node; node = node.next_sibling()) {
- ShaderNode *snode = NULL;
-
- /* ToDo: Add missing nodes
- * RGBCurvesNode, VectorCurvesNode, RGBRampNode and ConvertNode (RGB -> BW).
- */
-
- if(string_iequals(node.name(), "image_texture")) {
- ImageTextureNode *img = new ImageTextureNode();
-
- xml_read_string(&img->filename, node, "src");
- img->filename = path_join(state.base, img->filename);
-
- xml_read_enum(&img->color_space, ImageTextureNode::color_space_enum, node, "color_space");
- xml_read_enum(&img->projection, ImageTextureNode::projection_enum, node, "projection");
- xml_read_float(&img->projection_blend, node, "projection_blend");
-
- /* ToDo: Interpolation */
-
- snode = img;
- }
- else if(string_iequals(node.name(), "environment_texture")) {
- EnvironmentTextureNode *env = new EnvironmentTextureNode();
-
- xml_read_string(&env->filename, node, "src");
- env->filename = path_join(state.base, env->filename);
-
- xml_read_enum(&env->color_space, EnvironmentTextureNode::color_space_enum, node, "color_space");
- xml_read_enum(&env->projection, EnvironmentTextureNode::projection_enum, node, "projection");
+ ustring node_name(node.name());
- snode = env;
- }
- else if(string_iequals(node.name(), "osl_shader")) {
- OSLScriptNode *osl = new OSLScriptNode();
-
- /* Source */
- xml_read_string(&osl->filepath, node, "src");
- if(path_is_relative(osl->filepath)) {
- osl->filepath = path_join(state.base, osl->filepath);
- }
-
- /* Generate inputs/outputs from node sockets
- *
- * Note: ShaderInput/ShaderOutput store shallow string copies only!
- * So we register them as ustring to ensure the pointer stays valid. */
- /* read input values */
- for(pugi::xml_node param = node.first_child(); param; param = param.next_sibling()) {
- if(string_iequals(param.name(), "input")) {
- string name;
- if(!xml_read_string(&name, param, "name"))
- continue;
-
- ShaderSocketType type = xml_read_socket_type(param, "type");
- if(type == SHADER_SOCKET_UNDEFINED)
- continue;
-
- osl->add_input(ustring(name).c_str(), type);
- }
- else if(string_iequals(param.name(), "output")) {
- string name;
- if(!xml_read_string(&name, param, "name"))
- continue;
-
- ShaderSocketType type = xml_read_socket_type(param, "type");
- if(type == SHADER_SOCKET_UNDEFINED)
- continue;
-
- osl->add_output(ustring(name).c_str(), type);
- }
- }
-
- snode = osl;
- }
- else if(string_iequals(node.name(), "sky_texture")) {
- SkyTextureNode *sky = new SkyTextureNode();
-
- xml_read_enum(&sky->type, SkyTextureNode::type_enum, node, "type");
- xml_read_float3(&sky->sun_direction, node, "sun_direction");
- xml_read_float(&sky->turbidity, node, "turbidity");
- xml_read_float(&sky->ground_albedo, node, "ground_albedo");
-
- snode = sky;
- }
- else if(string_iequals(node.name(), "noise_texture")) {
- snode = new NoiseTextureNode();
- }
- else if(string_iequals(node.name(), "checker_texture")) {
- snode = new CheckerTextureNode();
- }
- else if(string_iequals(node.name(), "brick_texture")) {
- BrickTextureNode *brick = new BrickTextureNode();
-
- xml_read_float(&brick->offset, node, "offset");
- xml_read_int(&brick->offset_frequency, node, "offset_frequency");
- xml_read_float(&brick->squash, node, "squash");
- xml_read_int(&brick->squash_frequency, node, "squash_frequency");
-
- snode = brick;
- }
- else if(string_iequals(node.name(), "gradient_texture")) {
- GradientTextureNode *blend = new GradientTextureNode();
- xml_read_enum(&blend->type, GradientTextureNode::type_enum, node, "type");
- snode = blend;
- }
- else if(string_iequals(node.name(), "voronoi_texture")) {
- VoronoiTextureNode *voronoi = new VoronoiTextureNode();
- xml_read_enum(&voronoi->coloring, VoronoiTextureNode::coloring_enum, node, "coloring");
- snode = voronoi;
- }
- else if(string_iequals(node.name(), "musgrave_texture")) {
- MusgraveTextureNode *musgrave = new MusgraveTextureNode();
- xml_read_enum(&musgrave->type, MusgraveTextureNode::type_enum, node, "type");
- snode = musgrave;
- }
- else if(string_iequals(node.name(), "magic_texture")) {
- MagicTextureNode *magic = new MagicTextureNode();
- xml_read_int(&magic->depth, node, "depth");
- snode = magic;
- }
- else if(string_iequals(node.name(), "wave_texture")) {
- WaveTextureNode *wave = new WaveTextureNode();
- xml_read_enum(&wave->type, WaveTextureNode::type_enum, node, "type");
- xml_read_enum(&wave->profile, WaveTextureNode::profile_enum, node, "profile");
- snode = wave;
- }
- else if(string_iequals(node.name(), "normal")) {
- NormalNode *normal = new NormalNode();
- xml_read_float3(&normal->direction, node, "direction");
- snode = normal;
- }
- else if(string_iequals(node.name(), "bump")) {
- BumpNode *bump = new BumpNode();
- xml_read_bool(&bump->invert, node, "invert");
- snode = bump;
- }
- else if(string_iequals(node.name(), "mapping")) {
- snode = new MappingNode();
- }
- else if(string_iequals(node.name(), "anisotropic_bsdf")) {
- AnisotropicBsdfNode *aniso = new AnisotropicBsdfNode();
- xml_read_enum(&aniso->distribution, AnisotropicBsdfNode::distribution_enum, node, "distribution");
- snode = aniso;
- }
- else if(string_iequals(node.name(), "diffuse_bsdf")) {
- snode = new DiffuseBsdfNode();
- }
- else if(string_iequals(node.name(), "translucent_bsdf")) {
- snode = new TranslucentBsdfNode();
- }
- else if(string_iequals(node.name(), "transparent_bsdf")) {
- snode = new TransparentBsdfNode();
- }
- else if(string_iequals(node.name(), "velvet_bsdf")) {
- snode = new VelvetBsdfNode();
- }
- else if(string_iequals(node.name(), "toon_bsdf")) {
- ToonBsdfNode *toon = new ToonBsdfNode();
- xml_read_enum(&toon->component, ToonBsdfNode::component_enum, node, "component");
- snode = toon;
- }
- else if(string_iequals(node.name(), "glossy_bsdf")) {
- GlossyBsdfNode *glossy = new GlossyBsdfNode();
- xml_read_enum(&glossy->distribution, GlossyBsdfNode::distribution_enum, node, "distribution");
- snode = glossy;
- }
- else if(string_iequals(node.name(), "glass_bsdf")) {
- GlassBsdfNode *diel = new GlassBsdfNode();
- xml_read_enum(&diel->distribution, GlassBsdfNode::distribution_enum, node, "distribution");
- snode = diel;
- }
- else if(string_iequals(node.name(), "refraction_bsdf")) {
- RefractionBsdfNode *diel = new RefractionBsdfNode();
- xml_read_enum(&diel->distribution, RefractionBsdfNode::distribution_enum, node, "distribution");
- snode = diel;
- }
- else if(string_iequals(node.name(), "hair_bsdf")) {
- HairBsdfNode *hair = new HairBsdfNode();
- xml_read_enum(&hair->component, HairBsdfNode::component_enum, node, "component");
- snode = hair;
- }
- else if(string_iequals(node.name(), "emission")) {
- snode = new EmissionNode();
- }
- else if(string_iequals(node.name(), "ambient_occlusion")) {
- snode = new AmbientOcclusionNode();
- }
- else if(string_iequals(node.name(), "background")) {
- snode = new BackgroundNode();
- }
- else if(string_iequals(node.name(), "holdout")) {
- snode = new HoldoutNode();
- }
- else if(string_iequals(node.name(), "absorption_volume")) {
- snode = new AbsorptionVolumeNode();
- }
- else if(string_iequals(node.name(), "scatter_volume")) {
- snode = new ScatterVolumeNode();
- }
- else if(string_iequals(node.name(), "subsurface_scattering")) {
- SubsurfaceScatteringNode *sss = new SubsurfaceScatteringNode();
-
- string falloff;
- xml_read_string(&falloff, node, "falloff");
- if(falloff == "cubic")
- sss->closure = CLOSURE_BSSRDF_CUBIC_ID;
- else if(falloff == "gaussian")
- sss->closure = CLOSURE_BSSRDF_GAUSSIAN_ID;
- else /*if(falloff == "burley")*/
- sss->closure = CLOSURE_BSSRDF_BURLEY_ID;
-
- snode = sss;
- }
- else if(string_iequals(node.name(), "geometry")) {
- snode = new GeometryNode();
- }
- else if(string_iequals(node.name(), "texture_coordinate")) {
- snode = new TextureCoordinateNode();
- }
- else if(string_iequals(node.name(), "light_path")) {
- snode = new LightPathNode();
- }
- else if(string_iequals(node.name(), "light_falloff")) {
- snode = new LightFalloffNode();
- }
- else if(string_iequals(node.name(), "object_info")) {
- snode = new ObjectInfoNode();
- }
- else if(string_iequals(node.name(), "particle_info")) {
- snode = new ParticleInfoNode();
- }
- else if(string_iequals(node.name(), "hair_info")) {
- snode = new HairInfoNode();
- }
- else if(string_iequals(node.name(), "value")) {
- ValueNode *value = new ValueNode();
- xml_read_float(&value->value, node, "value");
- snode = value;
- }
- else if(string_iequals(node.name(), "color")) {
- ColorNode *color = new ColorNode();
- xml_read_float3(&color->value, node, "value");
- snode = color;
- }
- else if(string_iequals(node.name(), "mix_closure")) {
- snode = new MixClosureNode();
- }
- else if(string_iequals(node.name(), "add_closure")) {
- snode = new AddClosureNode();
- }
- else if(string_iequals(node.name(), "invert")) {
- snode = new InvertNode();
- }
- else if(string_iequals(node.name(), "mix")) {
- /* ToDo: Tag Mix case for optimization */
- MixNode *mix = new MixNode();
- xml_read_enum(&mix->type, MixNode::type_enum, node, "type");
- xml_read_bool(&mix->use_clamp, node, "use_clamp");
- snode = mix;
- }
- else if(string_iequals(node.name(), "gamma")) {
- snode = new GammaNode();
- }
- else if(string_iequals(node.name(), "brightness")) {
- snode = new BrightContrastNode();
- }
- else if(string_iequals(node.name(), "combine_rgb")) {
- snode = new CombineRGBNode();
- }
- else if(string_iequals(node.name(), "separate_rgb")) {
- snode = new SeparateRGBNode();
- }
- else if(string_iequals(node.name(), "combine_hsv")) {
- snode = new CombineHSVNode();
- }
- else if(string_iequals(node.name(), "separate_hsv")) {
- snode = new SeparateHSVNode();
- }
- else if(string_iequals(node.name(), "combine_xyz")) {
- snode = new CombineXYZNode();
- }
- else if(string_iequals(node.name(), "separate_xyz")) {
- snode = new SeparateXYZNode();
- }
- else if(string_iequals(node.name(), "hsv")) {
- snode = new HSVNode();
- }
- else if(string_iequals(node.name(), "wavelength")) {
- snode = new WavelengthNode();
- }
- else if(string_iequals(node.name(), "blackbody")) {
- snode = new BlackbodyNode();
- }
- else if(string_iequals(node.name(), "attribute")) {
- AttributeNode *attr = new AttributeNode();
- xml_read_ustring(&attr->attribute, node, "attribute");
- snode = attr;
- }
- else if(string_iequals(node.name(), "uv_map")) {
- UVMapNode *uvm = new UVMapNode();
- xml_read_ustring(&uvm->attribute, node, "uv_map");
- snode = uvm;
- }
- else if(string_iequals(node.name(), "camera")) {
- snode = new CameraNode();
- }
- else if(string_iequals(node.name(), "fresnel")) {
- snode = new FresnelNode();
- }
- else if(string_iequals(node.name(), "layer_weight")) {
- snode = new LayerWeightNode();
- }
- else if(string_iequals(node.name(), "wireframe")) {
- WireframeNode *wire = new WireframeNode;
- xml_read_bool(&wire->use_pixel_size, node, "use_pixel_size");
- snode = wire;
- }
- else if(string_iequals(node.name(), "normal_map")) {
- NormalMapNode *nmap = new NormalMapNode;
- xml_read_ustring(&nmap->attribute, node, "attribute");
- xml_read_enum(&nmap->space, NormalMapNode::space_enum, node, "space");
- snode = nmap;
- }
- else if(string_iequals(node.name(), "tangent")) {
- TangentNode *tangent = new TangentNode;
- xml_read_ustring(&tangent->attribute, node, "attribute");
- xml_read_enum(&tangent->direction_type, TangentNode::direction_type_enum, node, "direction_type");
- xml_read_enum(&tangent->axis, TangentNode::axis_enum, node, "axis");
- snode = tangent;
- }
- else if(string_iequals(node.name(), "math")) {
- MathNode *math = new MathNode();
- xml_read_enum(&math->type, MathNode::type_enum, node, "type");
- xml_read_bool(&math->use_clamp, node, "use_clamp");
- snode = math;
- }
- else if(string_iequals(node.name(), "vector_math")) {
- VectorMathNode *vmath = new VectorMathNode();
- xml_read_enum(&vmath->type, VectorMathNode::type_enum, node, "type");
- snode = vmath;
- }
- else if(string_iequals(node.name(), "vector_transform")) {
- VectorTransformNode *vtransform = new VectorTransformNode();
- xml_read_enum(&vtransform->type, VectorTransformNode::type_enum, node, "type");
- xml_read_enum(&vtransform->convert_from, VectorTransformNode::convert_space_enum, node, "convert_from");
- xml_read_enum(&vtransform->convert_to, VectorTransformNode::convert_space_enum, node, "convert_to");
- snode = vtransform;
- }
+ if(node_name == "connect") {
else if(string_iequals(node.name(), "openvdb")) {
OpenVDBNode *vdbnode = new OpenVDBNode();
xml_read_string(&vdbnode->filename, node, "src");
@@ -747,7 +242,6 @@ static void xml_read_shader_graph(const XMLReadState& state, Shader *shader, pug
snode = vdbnode;
}
- else if(string_iequals(node.name(), "connect")) {
/* connect nodes */
vector<string> from_tokens, to_tokens;
@@ -755,35 +249,40 @@ static void xml_read_shader_graph(const XMLReadState& state, Shader *shader, pug
string_split(to_tokens, node.attribute("to").value());
if(from_tokens.size() == 2 && to_tokens.size() == 2) {
+ ustring from_node_name(from_tokens[0]);
+ ustring from_socket_name(from_tokens[1]);
+ ustring to_node_name(to_tokens[0]);
+ ustring to_socket_name(to_tokens[1]);
+
/* find nodes and sockets */
ShaderOutput *output = NULL;
ShaderInput *input = NULL;
- if(nodemap.find(from_tokens[0]) != nodemap.end()) {
- ShaderNode *fromnode = nodemap[from_tokens[0]];
+ if(graph_reader.node_map.find(from_node_name) != graph_reader.node_map.end()) {
+ ShaderNode *fromnode = (ShaderNode*)graph_reader.node_map[from_node_name];
foreach(ShaderOutput *out, fromnode->outputs)
- if(string_iequals(xml_socket_name(out->name), from_tokens[1]))
+ if(string_iequals(xml_socket_name(out->name().c_str()), from_socket_name.c_str()))
output = out;
if(!output)
- fprintf(stderr, "Unknown output socket name \"%s\" on \"%s\".\n", from_tokens[1].c_str(), from_tokens[0].c_str());
+ fprintf(stderr, "Unknown output socket name \"%s\" on \"%s\".\n", from_node_name.c_str(), from_socket_name.c_str());
}
else
- fprintf(stderr, "Unknown shader node name \"%s\".\n", from_tokens[0].c_str());
+ fprintf(stderr, "Unknown shader node name \"%s\".\n", from_node_name.c_str());
- if(nodemap.find(to_tokens[0]) != nodemap.end()) {
- ShaderNode *tonode = nodemap[to_tokens[0]];
+ if(graph_reader.node_map.find(to_node_name) != graph_reader.node_map.end()) {
+ ShaderNode *tonode = (ShaderNode*)graph_reader.node_map[to_node_name];
foreach(ShaderInput *in, tonode->inputs)
- if(string_iequals(xml_socket_name(in->name), to_tokens[1]))
+ if(string_iequals(xml_socket_name(in->name().c_str()), to_socket_name.c_str()))
input = in;
if(!input)
- fprintf(stderr, "Unknown input socket name \"%s\" on \"%s\".\n", to_tokens[1].c_str(), to_tokens[0].c_str());
+ fprintf(stderr, "Unknown input socket name \"%s\" on \"%s\".\n", to_socket_name.c_str(), to_node_name.c_str());
}
else
- fprintf(stderr, "Unknown shader node name \"%s\".\n", to_tokens[0].c_str());
+ fprintf(stderr, "Unknown shader node name \"%s\".\n", to_node_name.c_str());
/* connect */
if(output && input)
@@ -791,44 +290,76 @@ static void xml_read_shader_graph(const XMLReadState& state, Shader *shader, pug
}
else
fprintf(stderr, "Invalid from or to value for connect node.\n");
+
+ continue;
}
- else
- fprintf(stderr, "Unknown shader node \"%s\".\n", node.name());
- if(snode) {
- /* add to graph */
- graph->add(snode);
+ ShaderNode *snode = NULL;
+
+#ifdef WITH_OSL
+ if(node_name == "osl_shader") {
+ ShaderManager *manager = state.scene->shader_manager;
+
+ if(manager->use_osl()) {
+ std::string filepath;
- /* add to map for name lookups */
- string name = "";
- xml_read_string(&name, node, "name");
-
- nodemap[name] = snode;
-
- /* read input values */
- for(pugi::xml_attribute attr = node.first_attribute(); attr; attr = attr.next_attribute()) {
- foreach(ShaderInput *in, snode->inputs) {
- if(string_iequals(in->name, attr.name())) {
- switch(in->type) {
- case SHADER_SOCKET_FLOAT:
- case SHADER_SOCKET_INT:
- xml_read_float(&in->value.x, node, attr.name());
- break;
- case SHADER_SOCKET_COLOR:
- case SHADER_SOCKET_VECTOR:
- case SHADER_SOCKET_POINT:
- case SHADER_SOCKET_NORMAL:
- xml_read_float3(&in->value, node, attr.name());
- break;
- case SHADER_SOCKET_STRING:
- xml_read_ustring( &in->value_string, node, attr.name() );
- break;
- default:
- break;
- }
+ if(xml_read_string(&filepath, node, "src")) {
+ if(path_is_relative(filepath)) {
+ filepath = path_join(state.base, filepath);
+ }
+
+ snode = ((OSLShaderManager*)manager)->osl_node(filepath);
+
+ if(!snode) {
+ fprintf(stderr, "Failed to create OSL node from \"%s\".\n", filepath.c_str());
+ continue;
}
}
+ else {
+ fprintf(stderr, "OSL node missing \"src\" attribute.\n");
+ continue;
+ }
+ }
+ else {
+ fprintf(stderr, "OSL node without using --shadingsys osl.\n");
+ continue;
+ }
+ }
+ else
+#endif
+ {
+ /* exception for name collision */
+ if(node_name == "background")
+ node_name = "background_shader";
+
+ const NodeType *node_type = NodeType::find(node_name);
+
+ if(!node_type) {
+ fprintf(stderr, "Unknown shader node \"%s\".\n", node.name());
+ continue;
}
+ else if(node_type->type != NodeType::SHADER) {
+ fprintf(stderr, "Node type \"%s\" is not a shader node.\n", node_type->name.c_str());
+ continue;
+ }
+
+ snode = (ShaderNode*) node_type->create(node_type);
+ }
+
+ xml_read_node(graph_reader, snode, node);
+
+ if(node_name == "image_texture") {
+ ImageTextureNode *img = (ImageTextureNode*) snode;
+ img->filename = path_join(state.base, img->filename.string());
+ }
+ else if(node_name == "environment_texture") {
+ EnvironmentTextureNode *env = (EnvironmentTextureNode*) snode;
+ env->filename = path_join(state.base, env->filename.string());
+ }
+
+ if(snode) {
+ /* add to graph */
+ graph->add(snode);
}
}
@@ -836,54 +367,22 @@ static void xml_read_shader_graph(const XMLReadState& state, Shader *shader, pug
shader->tag_update(state.scene);
}
-static void xml_read_shader(const XMLReadState& state, pugi::xml_node node)
+static void xml_read_shader(XMLReadState& state, pugi::xml_node node)
{
Shader *shader = new Shader();
-
- xml_read_string(&shader->name, node, "name");
- xml_read_bool(&shader->use_mis, node, "use_mis");
- xml_read_bool(&shader->use_transparent_shadow, node, "use_transparent_shadow");
-
- /* Volume */
- xml_read_bool(&shader->heterogeneous_volume, node, "heterogeneous_volume");
- xml_read_int(&shader->volume_interpolation_method, node, "volume_interpolation_method");
-
- if(xml_equal_string(node, "volume_sampling_method", "distance"))
- shader->volume_sampling_method = VOLUME_SAMPLING_DISTANCE;
- else if(xml_equal_string(node, "volume_sampling_method", "equiangular"))
- shader->volume_sampling_method = VOLUME_SAMPLING_EQUIANGULAR;
- else if(xml_equal_string(node, "volume_sampling_method", "multiple_importance"))
- shader->volume_sampling_method = VOLUME_SAMPLING_MULTIPLE_IMPORTANCE;
-
xml_read_shader_graph(state, shader, node);
state.scene->shaders.push_back(shader);
}
/* Background */
-static void xml_read_background(const XMLReadState& state, pugi::xml_node node)
+static void xml_read_background(XMLReadState& state, pugi::xml_node node)
{
/* Background Settings */
- Background *bg = state.scene->background;
-
- xml_read_float(&bg->ao_distance, node, "ao_distance");
- xml_read_float(&bg->ao_factor, node, "ao_factor");
-
- xml_read_bool(&bg->transparent, node, "transparent");
+ xml_read_node(state, state.scene->background, node);
/* Background Shader */
- Shader *shader = state.scene->shaders[state.scene->default_background];
-
- xml_read_bool(&shader->heterogeneous_volume, node, "heterogeneous_volume");
- xml_read_int(&shader->volume_interpolation_method, node, "volume_interpolation_method");
-
- if(xml_equal_string(node, "volume_sampling_method", "distance"))
- shader->volume_sampling_method = VOLUME_SAMPLING_DISTANCE;
- else if(xml_equal_string(node, "volume_sampling_method", "equiangular"))
- shader->volume_sampling_method = VOLUME_SAMPLING_EQUIANGULAR;
- else if(xml_equal_string(node, "volume_sampling_method", "multiple_importance"))
- shader->volume_sampling_method = VOLUME_SAMPLING_MULTIPLE_IMPORTANCE;
-
+ Shader *shader = state.scene->default_background;
xml_read_shader_graph(state, shader, node);
}
@@ -911,11 +410,9 @@ static void xml_read_mesh(const XMLReadState& state, pugi::xml_node node)
mesh->used_shaders.push_back(state.shader);
/* read state */
- int shader = state.shader;
+ int shader = 0;
bool smooth = state.smooth;
- mesh->displacement_method = state.displacement_method;
-
/* read vertices and polygons, RIB style */
vector<float3> P;
vector<float> UV;
@@ -926,52 +423,21 @@ static void xml_read_mesh(const XMLReadState& state, pugi::xml_node node)
xml_read_int_array(nverts, node, "nverts");
if(xml_equal_string(node, "subdivision", "catmull-clark")) {
- /* create subd mesh */
- SubdMesh sdmesh;
-
- /* create subd vertices */
- for(size_t i = 0; i < P.size(); i++)
- sdmesh.add_vert(P[i]);
-
- /* create subd faces */
- int index_offset = 0;
-
- for(size_t i = 0; i < nverts.size(); i++) {
- if(nverts[i] == 4) {
- int v0 = verts[index_offset + 0];
- int v1 = verts[index_offset + 1];
- int v2 = verts[index_offset + 2];
- int v3 = verts[index_offset + 3];
-
- sdmesh.add_face(v0, v1, v2, v3);
- }
- else {
- for(int j = 0; j < nverts[i]-2; j++) {
- int v0 = verts[index_offset];
- int v1 = verts[index_offset + j + 1];
- int v2 = verts[index_offset + j + 2];
-
- sdmesh.add_face(v0, v1, v2);
- }
- }
-
- index_offset += nverts[i];
- }
-
- /* finalize subd mesh */
- sdmesh.finish();
-
- /* parameters */
- SubdParams sdparams(mesh, shader, smooth);
- xml_read_float(&sdparams.dicing_rate, node, "dicing_rate");
-
- DiagSplit dsplit(sdparams);
- sdmesh.tessellate(&dsplit);
+ mesh->subdivision_type = Mesh::SUBDIVISION_CATMULL_CLARK;
}
- else {
+ else if(xml_equal_string(node, "subdivision", "linear")) {
+ mesh->subdivision_type = Mesh::SUBDIVISION_LINEAR;
+ }
+
+ if(mesh->subdivision_type == Mesh::SUBDIVISION_NONE) {
/* create vertices */
mesh->verts = P;
+ size_t num_triangles = 0;
+ for(size_t i = 0; i < nverts.size(); i++)
+ num_triangles += nverts[i]-2;
+ mesh->reserve_mesh(mesh->verts.size(), num_triangles);
+
/* create triangles */
int index_offset = 0;
@@ -1000,9 +466,9 @@ static void xml_read_mesh(const XMLReadState& state, pugi::xml_node node)
index_offset = 0;
for(size_t i = 0; i < nverts.size(); i++) {
for(int j = 0; j < nverts[i]-2; j++) {
- int v0 = verts[index_offset];
- int v1 = verts[index_offset + j + 1];
- int v2 = verts[index_offset + j + 2];
+ int v0 = index_offset;
+ int v1 = index_offset + j + 1;
+ int v2 = index_offset + j + 2;
assert(v0*2+1 < (int)UV.size());
assert(v1*2+1 < (int)UV.size());
@@ -1018,115 +484,73 @@ static void xml_read_mesh(const XMLReadState& state, pugi::xml_node node)
}
}
}
+ else {
+ /* create vertices */
+ mesh->verts = P;
- /* temporary for test compatibility */
- mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
-}
-
-/* Patch */
+ size_t num_ngons = 0;
+ size_t num_corners = 0;
+ for(size_t i = 0; i < nverts.size(); i++) {
+ num_ngons += (nverts[i] == 4) ? 0 : 1;
+ num_corners += nverts[i];
+ }
+ mesh->reserve_subd_faces(nverts.size(), num_ngons, num_corners);
-static void xml_read_patch(const XMLReadState& state, pugi::xml_node node)
-{
- /* read patch */
- Patch *patch = NULL;
+ /* create subd_faces */
+ int index_offset = 0;
- vector<float3> P;
- xml_read_float3_array(P, node, "P");
+ for(size_t i = 0; i < nverts.size(); i++) {
+ mesh->add_subd_face(&verts[index_offset], nverts[i], shader, smooth);
+ index_offset += nverts[i];
+ }
- if(xml_equal_string(node, "type", "bilinear")) {
- /* bilinear patch */
- if(P.size() == 4) {
- LinearQuadPatch *bpatch = new LinearQuadPatch();
+ /* uv map */
+ if(xml_read_float_array(UV, node, "UV")) {
+ ustring name = ustring("UVMap");
+ Attribute *attr = mesh->subd_attributes.add(ATTR_STD_UV, name);
+ float3 *fdata = attr->data_float3();
- for(int i = 0; i < 4; i++)
- P[i] = transform_point(&state.tfm, P[i]);
- memcpy(bpatch->hull, &P[0], sizeof(bpatch->hull));
+#if 0
+ if(subdivide_uvs) {
+ attr->flags |= ATTR_SUBDIVIDED;
+ }
+#endif
- patch = bpatch;
+ index_offset = 0;
+ for(size_t i = 0; i < nverts.size(); i++) {
+ for(int j = 0; j < nverts[i]; j++) {
+ *(fdata++) = make_float3(UV[index_offset++]);
+ }
+ }
}
- else
- fprintf(stderr, "Invalid number of control points for bilinear patch.\n");
- }
- else if(xml_equal_string(node, "type", "bicubic")) {
- /* bicubic patch */
- if(P.size() == 16) {
- BicubicPatch *bpatch = new BicubicPatch();
-
- for(int i = 0; i < 16; i++)
- P[i] = transform_point(&state.tfm, P[i]);
- memcpy(bpatch->hull, &P[0], sizeof(bpatch->hull));
- patch = bpatch;
+ /* setup subd params */
+ if(!mesh->subd_params) {
+ mesh->subd_params = new SubdParams(mesh);
}
- else
- fprintf(stderr, "Invalid number of control points for bicubic patch.\n");
- }
- else
- fprintf(stderr, "Unknown patch type.\n");
+ SubdParams& sdparams = *mesh->subd_params;
- if(patch) {
- /* add mesh */
- Mesh *mesh = xml_add_mesh(state.scene, transform_identity());
-
- mesh->used_shaders.push_back(state.shader);
-
- /* split */
- SubdParams sdparams(mesh, state.shader, state.smooth);
+ sdparams.dicing_rate = state.dicing_rate;
xml_read_float(&sdparams.dicing_rate, node, "dicing_rate");
+ sdparams.dicing_rate = std::max(0.1f, sdparams.dicing_rate);
- DiagSplit dsplit(sdparams);
- dsplit.split_quad(patch);
-
- delete patch;
-
- /* temporary for test compatibility */
- mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
+ state.scene->camera->update();
+ sdparams.camera = state.scene->camera;
+ sdparams.objecttoworld = state.tfm;
}
+
+ /* temporary for test compatibility */
+ mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
}
/* Light */
-static void xml_read_light(const XMLReadState& state, pugi::xml_node node)
+static void xml_read_light(XMLReadState& state, pugi::xml_node node)
{
Light *light = new Light();
- light->shader = state.shader;
- /* Light Type
- * 0: Point, 1: Sun, 3: Area, 5: Spot */
- int type = 0;
- xml_read_int(&type, node, "type");
- light->type = (LightType)type;
-
- /* Spot Light */
- xml_read_float(&light->spot_angle, node, "spot_angle");
- xml_read_float(&light->spot_smooth, node, "spot_smooth");
-
- /* Area Light */
- xml_read_float(&light->sizeu, node, "sizeu");
- xml_read_float(&light->sizev, node, "sizev");
- xml_read_float3(&light->axisu, node, "axisu");
- xml_read_float3(&light->axisv, node, "axisv");
-
- /* Portal? (Area light only) */
- xml_read_bool(&light->is_portal, node, "is_portal");
-
- /* Generic */
- xml_read_float(&light->size, node, "size");
- xml_read_float3(&light->dir, node, "dir");
- xml_read_float3(&light->co, node, "P");
- light->co = transform_point(&state.tfm, light->co);
-
- /* Settings */
- xml_read_bool(&light->cast_shadow, node, "cast_shadow");
- xml_read_bool(&light->use_mis, node, "use_mis");
- xml_read_int(&light->samples, node, "samples");
- xml_read_int(&light->max_bounces, node, "max_bounces");
-
- /* Ray Visibility */
- xml_read_bool(&light->use_diffuse, node, "use_diffuse");
- xml_read_bool(&light->use_glossy, node, "use_glossy");
- xml_read_bool(&light->use_transmission, node, "use_transmission");
- xml_read_bool(&light->use_scatter, node, "use_scatter");
+ light->shader = state.shader;
+ xml_read_node(state, light, node);
state.scene->lights.push_back(light);
}
@@ -1168,17 +592,14 @@ static void xml_read_state(XMLReadState& state, pugi::xml_node node)
string shadername;
if(xml_read_string(&shadername, node, "shader")) {
- int i = 0;
bool found = false;
foreach(Shader *shader, state.scene->shaders) {
if(shader->name == shadername) {
- state.shader = i;
+ state.shader = shader;
found = true;
break;
}
-
- i++;
}
if(!found)
@@ -1192,28 +613,20 @@ static void xml_read_state(XMLReadState& state, pugi::xml_node node)
state.smooth = true;
else if(xml_equal_string(node, "interpolation", "flat"))
state.smooth = false;
-
- /* read displacement method */
- if(xml_equal_string(node, "displacement_method", "true"))
- state.displacement_method = Mesh::DISPLACE_TRUE;
- else if(xml_equal_string(node, "displacement_method", "bump"))
- state.displacement_method = Mesh::DISPLACE_BUMP;
- else if(xml_equal_string(node, "displacement_method", "both"))
- state.displacement_method = Mesh::DISPLACE_BOTH;
}
/* Scene */
-static void xml_read_include(const XMLReadState& state, const string& src);
+static void xml_read_include(XMLReadState& state, const string& src);
-static void xml_read_scene(const XMLReadState& state, pugi::xml_node scene_node)
+static void xml_read_scene(XMLReadState& state, pugi::xml_node scene_node)
{
for(pugi::xml_node node = scene_node.first_child(); node; node = node.next_sibling()) {
if(string_iequals(node.name(), "film")) {
- xml_read_film(state, node);
+ xml_read_node(state, state.scene->film, node);
}
else if(string_iequals(node.name(), "integrator")) {
- xml_read_integrator(state, node);
+ xml_read_node(state, state.scene->integrator, node);
}
else if(string_iequals(node.name(), "camera")) {
xml_read_camera(state, node);
@@ -1227,9 +640,6 @@ static void xml_read_scene(const XMLReadState& state, pugi::xml_node scene_node)
else if(string_iequals(node.name(), "mesh")) {
xml_read_mesh(state, node);
}
- else if(string_iequals(node.name(), "patch")) {
- xml_read_patch(state, node);
- }
else if(string_iequals(node.name(), "light")) {
xml_read_light(state, node);
}
@@ -1258,7 +668,7 @@ static void xml_read_scene(const XMLReadState& state, pugi::xml_node scene_node)
/* Include */
-static void xml_read_include(const XMLReadState& state, const string& src)
+static void xml_read_include(XMLReadState& state, const string& src)
{
/* open XML document */
pugi::xml_document doc;
@@ -1290,7 +700,7 @@ void xml_read_file(Scene *scene, const char *filepath)
state.tfm = transform_identity();
state.shader = scene->default_surface;
state.smooth = false;
- state.dicing_rate = 0.1f;
+ state.dicing_rate = 1.0f;
state.base = path_dirname(filepath);
xml_read_include(state, path_filename(filepath));
diff --git a/intern/cycles/blender/CMakeLists.txt b/intern/cycles/blender/CMakeLists.txt
index a8cc4907cbf..a79deca53e1 100644
--- a/intern/cycles/blender/CMakeLists.txt
+++ b/intern/cycles/blender/CMakeLists.txt
@@ -1,5 +1,6 @@
set(INC
+ ../graph
../render
../device
../kernel
diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py
index d4b7535b9ee..2c5365c9189 100644
--- a/intern/cycles/blender/addon/engine.py
+++ b/intern/cycles/blender/addon/engine.py
@@ -82,7 +82,6 @@ def init():
import bpy
import _cycles
import os.path
- import sys
# Workaround possibly buggy legacy drivers which crashes on the OpenCL
# device enumeration.
@@ -103,10 +102,12 @@ def init():
_cycles.init(path, user_path, bpy.app.background)
_parse_command_line()
+
def exit():
import _cycles
_cycles.exit()
+
def create(engine, data, scene, region=None, v3d=None, rv3d=None, preview_osl=False):
import bpy
import _cycles
diff --git a/intern/cycles/blender/addon/osl.py b/intern/cycles/blender/addon/osl.py
index f4aaaab5eab..19f2ecc9d1a 100644
--- a/intern/cycles/blender/addon/osl.py
+++ b/intern/cycles/blender/addon/osl.py
@@ -41,6 +41,8 @@ def update_script_node(node, report):
import shutil
import tempfile
+ oso_file_remove = False
+
if node.mode == 'EXTERNAL':
# compile external script file
script_path = bpy.path.abspath(node.filepath, library=node.id_data.library)
@@ -49,7 +51,6 @@ def update_script_node(node, report):
if script_ext == ".oso":
# it's a .oso file, no need to compile
ok, oso_path = True, script_path
- oso_file_remove = False
elif script_ext == ".osl":
# compile .osl file
ok, oso_path = osl_compile(script_path, report)
@@ -65,7 +66,6 @@ def update_script_node(node, report):
elif os.path.dirname(node.filepath) == "":
# module in search path
oso_path = node.filepath
- oso_file_remove = False
ok = True
else:
# unknown
@@ -88,12 +88,10 @@ def update_script_node(node, report):
osl_file.close()
ok, oso_path = osl_compile(osl_file.name, report)
- oso_file_remove = False
os.remove(osl_file.name)
else:
# compile text datablock from disk directly
ok, oso_path = osl_compile(osl_path, report)
- oso_file_remove = False
if ok:
# read bytecode
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index eed86a6e65a..977d7f75bb7 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -46,12 +46,6 @@ enum_displacement_methods = (
('BOTH', "Both", "Combination of displacement and bump mapping"),
)
-enum_subdivision_types = (
- ('NONE', "None", "No subdivision"),
- ('LINEAR', "Linear", "Use linear subdivision"),
- ('CATMULL_CLARK', "Catmull–Clark", "Use Catmull-Clark subdivision"),
- )
-
enum_bvh_types = (
('DYNAMIC_BVH', "Dynamic BVH", "Objects can be individually updated, at the cost of slower render time"),
('STATIC_BVH', "Static BVH", "Any object modification requires a complete BVH rebuild, but renders faster"),
@@ -359,7 +353,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
description="Distance between volume shader samples when rendering the volume "
"(lower values give more accurate and detailed results, but also increased render time)",
default=0.1,
- min=0.0000001, max=100000.0, soft_min=0.01, soft_max=1.0
+ min=0.0000001, max=100000.0, soft_min=0.01, soft_max=1.0, precision=4
)
cls.volume_max_steps = IntProperty(
@@ -373,14 +367,16 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
cls.dicing_rate = FloatProperty(
name="Dicing Rate",
description="Size of a micropolygon in pixels",
- min=0.1, max=1000.0,
+ min=0.1, max=1000.0, soft_min=0.5,
default=1.0,
+ subtype="PIXEL"
)
cls.preview_dicing_rate = FloatProperty(
name="Preview Dicing Rate",
description="Size of a micropolygon in pixels during preview render",
- min=0.1, max=1000.0,
+ min=0.1, max=1000.0, soft_min=0.5,
default=8.0,
+ subtype="PIXEL"
)
cls.max_subdivisions = IntProperty(
@@ -503,6 +499,11 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
description="Use BVH spatial splits: longer builder time, faster render",
default=False,
)
+ cls.debug_use_hair_bvh = BoolProperty(
+ name="Use Hair BVH",
+ description="Use special type BVH optimized for hair (uses more ram but renders faster)",
+ default=True,
+ )
cls.tile_order = EnumProperty(
name="Tile Order",
description="Tile order for rendering",
@@ -776,6 +777,13 @@ class CyclesMaterialSettings(bpy.types.PropertyGroup):
default='LINEAR',
)
+ cls.displacement_method = EnumProperty(
+ name="Displacement Method",
+ description="Method to use for the displacement",
+ items=enum_displacement_methods,
+ default='BUMP',
+ )
+
@classmethod
def unregister(cls):
del bpy.types.Material.cycles
@@ -953,25 +961,6 @@ class CyclesMeshSettings(bpy.types.PropertyGroup):
type=cls,
)
- cls.displacement_method = EnumProperty(
- name="Displacement Method",
- description="Method to use for the displacement",
- items=enum_displacement_methods,
- default='BUMP',
- )
- cls.subdivision_type = EnumProperty(
- name="Subdivision Type",
- description="Type of subdivision to use",
- items=enum_subdivision_types,
- default='NONE',
- )
- cls.dicing_rate = FloatProperty(
- name="Dicing Rate",
- description="Multiplier for scene dicing rate",
- min=0.1, max=1000.0,
- default=1.0,
- )
-
@classmethod
def unregister(cls):
del bpy.types.Mesh.cycles
@@ -979,11 +968,9 @@ class CyclesMeshSettings(bpy.types.PropertyGroup):
del bpy.types.MetaBall.cycles
-class CyclesObjectBlurSettings(bpy.types.PropertyGroup):
-
+class CyclesObjectSettings(bpy.types.PropertyGroup):
@classmethod
def register(cls):
-
bpy.types.Object.cycles = PointerProperty(
name="Cycles Object Settings",
description="Cycles object settings",
@@ -1015,6 +1002,19 @@ class CyclesObjectBlurSettings(bpy.types.PropertyGroup):
default=False,
)
+ cls.use_adaptive_subdivision = BoolProperty(
+ name="Use Adaptive Subdivision",
+ description="Use adaptive render time subdivision",
+ default=False,
+ )
+
+ cls.dicing_rate = FloatProperty(
+ name="Dicing Scale",
+ description="Multiplier for scene dicing rate (located in the Geometry Panel)",
+ min=0.1, max=1000.0, soft_min=0.5,
+ default=1.0,
+ )
+
@classmethod
def unregister(cls):
del bpy.types.Object.cycles
@@ -1131,6 +1131,7 @@ def register():
bpy.utils.register_class(CyclesWorldSettings)
bpy.utils.register_class(CyclesVisibilitySettings)
bpy.utils.register_class(CyclesMeshSettings)
+ bpy.utils.register_class(CyclesObjectSettings)
bpy.utils.register_class(CyclesCurveRenderSettings)
bpy.utils.register_class(CyclesCurveSettings)
@@ -1142,6 +1143,7 @@ def unregister():
bpy.utils.unregister_class(CyclesLampSettings)
bpy.utils.unregister_class(CyclesWorldSettings)
bpy.utils.unregister_class(CyclesMeshSettings)
+ bpy.utils.unregister_class(CyclesObjectSettings)
bpy.utils.unregister_class(CyclesVisibilitySettings)
bpy.utils.unregister_class(CyclesCurveRenderSettings)
bpy.utils.unregister_class(CyclesCurveSettings)
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index 023841a7a17..52872d2b83f 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -76,9 +76,8 @@ def use_cuda(context):
def use_branched_path(context):
cscene = context.scene.cycles
- device_type = context.user_preferences.system.compute_device_type
- return (cscene.progressive == 'BRANCHED_PATH' and device_type != 'OPENCL')
+ return (cscene.progressive == 'BRANCHED_PATH' and not use_opencl(context))
def use_sample_all_lights(context):
@@ -384,7 +383,6 @@ class CyclesRender_PT_performance(CyclesButtonsPanel, Panel):
sub.prop(cscene, "use_progressive_refine")
subsub = sub.column(align=True)
- subsub.enabled = not rd.use_border
subsub.prop(rd, "use_save_buffers")
col = split.column(align=True)
@@ -403,6 +401,7 @@ class CyclesRender_PT_performance(CyclesButtonsPanel, Panel):
col.label(text="Acceleration structure:")
col.prop(cscene, "debug_use_spatial_splits")
+ col.prop(cscene, "debug_use_hair_bvh")
class CyclesRender_PT_layer_options(CyclesButtonsPanel, Panel):
@@ -460,7 +459,9 @@ class CyclesRender_PT_layer_passes(CyclesButtonsPanel, Panel):
col.prop(rl, "use_pass_z")
col.prop(rl, "use_pass_mist")
col.prop(rl, "use_pass_normal")
- col.prop(rl, "use_pass_vector")
+ row = col.row()
+ row.prop(rl, "use_pass_vector")
+ row.active = not rd.use_motion_blur
col.prop(rl, "use_pass_uv")
col.prop(rl, "use_pass_object_index")
col.prop(rl, "use_pass_material_index")
@@ -673,48 +674,6 @@ class Cycles_PT_context_material(CyclesButtonsPanel, Panel):
split.separator()
-class Cycles_PT_mesh_displacement(CyclesButtonsPanel, Panel):
- bl_label = "Displacement"
- bl_context = "data"
-
- @classmethod
- def poll(cls, context):
- if CyclesButtonsPanel.poll(context):
- if context.mesh or context.curve or context.meta_ball:
- if context.scene.cycles.feature_set == 'EXPERIMENTAL':
- return True
-
- return False
-
- def draw(self, context):
- layout = self.layout
-
- mesh = context.mesh
- curve = context.curve
- mball = context.meta_ball
-
- if mesh:
- cdata = mesh.cycles
- elif curve:
- cdata = curve.cycles
- elif mball:
- cdata = mball.cycles
-
- split = layout.split()
-
- col = split.column()
- sub = col.column(align=True)
- sub.label(text="Displacment:")
- sub.prop(cdata, "displacement_method", text="")
-
- col = split.column()
- sub = col.column(align=True)
- sub.label(text="Subdivision:")
- sub.prop(cdata, "subdivision_type", text="")
-
- if cdata.subdivision_type != 'NONE':
- sub.prop(cdata, "dicing_rate")
-
class CyclesObject_PT_motion_blur(CyclesButtonsPanel, Panel):
bl_label = "Motion Blur"
bl_context = "object"
@@ -894,7 +853,7 @@ class CyclesLamp_PT_lamp(CyclesButtonsPanel, Panel):
lamp = context.lamp
clamp = lamp.cycles
- cscene = context.scene.cycles
+ # cscene = context.scene.cycles
layout.prop(lamp, "type", expand=True)
@@ -1114,7 +1073,7 @@ class CyclesWorld_PT_settings(CyclesButtonsPanel, Panel):
world = context.world
cworld = world.cycles
- cscene = context.scene.cycles
+ # cscene = context.scene.cycles
split = layout.split()
@@ -1226,6 +1185,11 @@ class CyclesMaterial_PT_settings(CyclesButtonsPanel, Panel):
col.prop(cmat, "sample_as_light", text="Multiple Importance")
col.prop(cmat, "use_transparent_shadow")
+ if context.scene.cycles.feature_set == 'EXPERIMENTAL':
+ col.separator()
+ col.label(text="Displacement:")
+ col.prop(cmat, "displacement_method", text="")
+
col = split.column()
col.label(text="Volume:")
sub = col.column()
@@ -1664,104 +1628,62 @@ def draw_pause(self, context):
def get_panels():
- types = bpy.types
- panels = [
- "RENDER_PT_render",
- "RENDER_PT_output",
- "RENDER_PT_encoding",
- "RENDER_PT_dimensions",
- "RENDER_PT_stamp",
- "RENDER_PT_freestyle",
- "RENDERLAYER_PT_layers",
- "RENDERLAYER_PT_freestyle",
- "RENDERLAYER_PT_freestyle_lineset",
- "RENDERLAYER_PT_freestyle_linestyle",
- "SCENE_PT_scene",
- "SCENE_PT_color_management",
- "SCENE_PT_custom_props",
- "SCENE_PT_audio",
- "SCENE_PT_unit",
- "SCENE_PT_keying_sets",
- "SCENE_PT_keying_set_paths",
- "SCENE_PT_physics",
- "WORLD_PT_context_world",
- "WORLD_PT_custom_props",
- "DATA_PT_context_mesh",
- "DATA_PT_context_camera",
- "DATA_PT_context_lamp",
- "DATA_PT_context_speaker",
- "DATA_PT_normals",
- "DATA_PT_texture_space",
- "DATA_PT_curve_texture_space",
- "DATA_PT_mball_texture_space",
- "DATA_PT_vertex_groups",
- "DATA_PT_shape_keys",
- "DATA_PT_uv_texture",
- "DATA_PT_vertex_colors",
- "DATA_PT_camera",
- "DATA_PT_camera_display",
- "DATA_PT_camera_stereoscopy",
- "DATA_PT_camera_safe_areas",
- "DATA_PT_lens",
- "DATA_PT_speaker",
- "DATA_PT_distance",
- "DATA_PT_cone",
- "DATA_PT_customdata",
- "DATA_PT_custom_props_mesh",
- "DATA_PT_custom_props_camera",
- "DATA_PT_custom_props_lamp",
- "DATA_PT_custom_props_speaker",
- "DATA_PT_custom_props_arm",
- "DATA_PT_custom_props_curve",
- "DATA_PT_custom_props_lattice",
- "DATA_PT_custom_props_metaball",
- "TEXTURE_PT_preview",
- "TEXTURE_PT_custom_props",
- "TEXTURE_PT_clouds",
- "TEXTURE_PT_wood",
- "TEXTURE_PT_marble",
- "TEXTURE_PT_magic",
- "TEXTURE_PT_blend",
- "TEXTURE_PT_stucci",
- "TEXTURE_PT_image",
- "TEXTURE_PT_image_sampling",
- "TEXTURE_PT_image_mapping",
- "TEXTURE_PT_musgrave",
- "TEXTURE_PT_voronoi",
- "TEXTURE_PT_distortednoise",
- "TEXTURE_PT_voxeldata",
- "TEXTURE_PT_pointdensity",
- "TEXTURE_PT_pointdensity_turbulence",
- "TEXTURE_PT_mapping",
- "TEXTURE_PT_ocean",
- "TEXTURE_PT_influence",
- "TEXTURE_PT_colors",
- "PARTICLE_PT_context_particles",
- "PARTICLE_PT_custom_props",
- "PARTICLE_PT_emission",
- "PARTICLE_PT_hair_dynamics",
- "PARTICLE_PT_cache",
- "PARTICLE_PT_velocity",
- "PARTICLE_PT_rotation",
- "PARTICLE_PT_physics",
- "SCENE_PT_rigid_body_world",
- "SCENE_PT_rigid_body_cache",
- "SCENE_PT_rigid_body_field_weights",
- "PARTICLE_PT_boidbrain",
- "PARTICLE_PT_render",
- "PARTICLE_PT_draw",
- "PARTICLE_PT_children",
- "PARTICLE_PT_field_weights",
- "PARTICLE_PT_force_fields",
- "PARTICLE_PT_vertexgroups",
- "MATERIAL_PT_custom_props",
- "MATERIAL_PT_freestyle_line",
- "BONE_PT_custom_props",
- "OBJECT_PT_custom_props",
- ]
-
- return [getattr(types, p) for p in panels if hasattr(types, p)]
-
+ exclude_panels = {
+ 'DATA_PT_area',
+ 'DATA_PT_camera_dof',
+ 'DATA_PT_falloff_curve',
+ 'DATA_PT_lamp',
+ 'DATA_PT_preview',
+ 'DATA_PT_shadow',
+ 'DATA_PT_spot',
+ 'DATA_PT_sunsky',
+ 'MATERIAL_PT_context_material',
+ 'MATERIAL_PT_diffuse',
+ 'MATERIAL_PT_flare',
+ 'MATERIAL_PT_halo',
+ 'MATERIAL_PT_mirror',
+ 'MATERIAL_PT_options',
+ 'MATERIAL_PT_pipeline',
+ 'MATERIAL_PT_preview',
+ 'MATERIAL_PT_shading',
+ 'MATERIAL_PT_shadow',
+ 'MATERIAL_PT_specular',
+ 'MATERIAL_PT_sss',
+ 'MATERIAL_PT_strand',
+ 'MATERIAL_PT_transp',
+ 'MATERIAL_PT_volume_density',
+ 'MATERIAL_PT_volume_integration',
+ 'MATERIAL_PT_volume_lighting',
+ 'MATERIAL_PT_volume_options',
+ 'MATERIAL_PT_volume_shading',
+ 'MATERIAL_PT_volume_transp',
+ 'RENDERLAYER_PT_layer_options',
+ 'RENDERLAYER_PT_layer_passes',
+ 'RENDERLAYER_PT_views',
+ 'RENDER_PT_antialiasing',
+ 'RENDER_PT_bake',
+ 'RENDER_PT_motion_blur',
+ 'RENDER_PT_performance',
+ 'RENDER_PT_post_processing',
+ 'RENDER_PT_shading',
+ 'SCENE_PT_simplify',
+ 'TEXTURE_PT_context_texture',
+ 'WORLD_PT_ambient_occlusion',
+ 'WORLD_PT_environment_lighting',
+ 'WORLD_PT_gather',
+ 'WORLD_PT_indirect_lighting',
+ 'WORLD_PT_mist',
+ 'WORLD_PT_preview',
+ 'WORLD_PT_world'
+ }
+
+ panels = []
+ for panel in bpy.types.Panel.__subclasses__():
+ if hasattr(panel, 'COMPAT_ENGINES') and 'BLENDER_RENDER' in panel.COMPAT_ENGINES:
+ if panel.__name__ not in exclude_panels:
+ panels.append(panel)
+
+ return panels
def register():
bpy.types.RENDER_PT_render.append(draw_device)
@@ -1770,10 +1692,10 @@ def register():
for panel in get_panels():
panel.COMPAT_ENGINES.add('CYCLES')
-
def unregister():
bpy.types.RENDER_PT_render.remove(draw_device)
bpy.types.VIEW3D_HT_header.remove(draw_pause)
for panel in get_panels():
- panel.COMPAT_ENGINES.remove('CYCLES')
+ if 'CYCLES' in panel.COMPAT_ENGINES:
+ panel.COMPAT_ENGINES.remove('CYCLES')
diff --git a/intern/cycles/blender/addon/version_update.py b/intern/cycles/blender/addon/version_update.py
index 221b1437128..830723d6149 100644
--- a/intern/cycles/blender/addon/version_update.py
+++ b/intern/cycles/blender/addon/version_update.py
@@ -104,7 +104,6 @@ def vector_curve_node_remap(node):
"""
Remap values of vector curve node from normalized to absolute values
"""
- from mathutils import Vector
if node.bl_idname == 'ShaderNodeVectorCurve':
node.mapping.use_clip = False
for curve in node.mapping.curves:
diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp
index 6b459ae575f..f02fc553908 100644
--- a/intern/cycles/blender/blender_camera.cpp
+++ b/intern/cycles/blender/blender_camera.cpp
@@ -37,7 +37,7 @@ struct BlenderCamera {
float lens;
float shuttertime;
Camera::MotionPosition motion_position;
- float shutter_curve[RAMP_TABLE_SIZE];
+ array<float> shutter_curve;
Camera::RollingShutterType rolling_shutter_type;
float rolling_shutter_duration;
@@ -65,6 +65,9 @@ struct BlenderCamera {
bool use_spherical_stereo;
float interocular_distance;
float convergence_distance;
+ bool use_pole_merge;
+ float pole_merge_angle_from;
+ float pole_merge_angle_to;
enum { AUTO, HORIZONTAL, VERTICAL } sensor_fit;
float sensor_width;
@@ -105,10 +108,6 @@ static void blender_camera_init(BlenderCamera *bcam,
/* render resolution */
bcam->full_width = render_resolution_x(b_render);
bcam->full_height = render_resolution_y(b_render);
-
- /* pixel aspect */
- bcam->pixelaspect.x = b_render.pixel_aspect_x();
- bcam->pixelaspect.y = b_render.pixel_aspect_y();
}
static float blender_camera_focal_distance(BL::RenderEngine& b_engine,
@@ -183,6 +182,10 @@ static void blender_camera_from_object(BlenderCamera *bcam,
}
bcam->use_spherical_stereo = b_engine.use_spherical_stereo(b_ob);
+ bcam->use_pole_merge = b_camera.stereo().use_pole_merge();
+ bcam->pole_merge_angle_from = b_camera.stereo().pole_merge_angle_from();
+ bcam->pole_merge_angle_to = b_camera.stereo().pole_merge_angle_to();
+
bcam->ortho_scale = b_camera.ortho_scale();
bcam->lens = b_camera.lens();
@@ -427,6 +430,10 @@ static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int
cam->stereo_eye = Camera::STEREO_NONE;
}
+ cam->use_pole_merge = bcam->use_pole_merge;
+ cam->pole_merge_angle_from = bcam->pole_merge_angle_from;
+ cam->pole_merge_angle_to = bcam->pole_merge_angle_to;
+
/* anamorphic lens bokeh */
cam->aperture_ratio = bcam->aperture_ratio;
@@ -453,7 +460,7 @@ static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int
cam->rolling_shutter_type = bcam->rolling_shutter_type;
cam->rolling_shutter_duration = bcam->rolling_shutter_duration;
- memcpy(cam->shutter_curve, bcam->shutter_curve, sizeof(cam->shutter_curve));
+ cam->shutter_curve = bcam->shutter_curve;
/* border */
cam->border = bcam->border;
@@ -552,6 +559,10 @@ void BlenderSync::sync_camera_motion(BL::RenderSettings& b_render,
float aspectratio, sensor_size;
blender_camera_init(&bcam, b_render);
+ /* TODO(sergey): Consider making it a part of blender_camera_init(). */
+ bcam.pixelaspect.x = b_render.pixel_aspect_x();
+ bcam.pixelaspect.y = b_render.pixel_aspect_y();
+
blender_camera_from_object(&bcam, b_engine, b_ob);
blender_camera_viewplane(&bcam,
width, height,
diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp
index 0178bfbe8d9..378ae67f0c7 100644
--- a/intern/cycles/blender/blender_curves.cpp
+++ b/intern/cycles/blender/blender_curves.cpp
@@ -138,8 +138,7 @@ bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Par
BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
if((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && (b_part.type() == BL::ParticleSettings::type_HAIR)) {
- int mi = clamp(b_part.material()-1, 0, mesh->used_shaders.size()-1);
- int shader = mesh->used_shaders[mi];
+ int shader = clamp(b_part.material()-1, 0, mesh->used_shaders.size()-1);
int draw_step = background ? b_part.render_step() : b_part.draw_step();
int totparts = b_psys.particles.length();
int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f);
@@ -157,16 +156,16 @@ bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Par
PointerRNA cpsys = RNA_pointer_get(&b_part.ptr, "cycles");
- CData->psys_firstcurve.push_back(curvenum);
- CData->psys_curvenum.push_back(totcurves);
- CData->psys_shader.push_back(shader);
+ CData->psys_firstcurve.push_back_slow(curvenum);
+ CData->psys_curvenum.push_back_slow(totcurves);
+ CData->psys_shader.push_back_slow(shader);
float radius = get_float(cpsys, "radius_scale") * 0.5f;
- CData->psys_rootradius.push_back(radius * get_float(cpsys, "root_width"));
- CData->psys_tipradius.push_back(radius * get_float(cpsys, "tip_width"));
- CData->psys_shape.push_back(get_float(cpsys, "shape"));
- CData->psys_closetip.push_back(get_boolean(cpsys, "use_closetip"));
+ CData->psys_rootradius.push_back_slow(radius * get_float(cpsys, "root_width"));
+ CData->psys_tipradius.push_back_slow(radius * get_float(cpsys, "tip_width"));
+ CData->psys_shape.push_back_slow(get_float(cpsys, "shape"));
+ CData->psys_closetip.push_back_slow(get_boolean(cpsys, "use_closetip"));
int pa_no = 0;
if(!(b_part.child_type() == 0) && totchild != 0)
@@ -181,7 +180,7 @@ bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Par
for(; pa_no < totparts+totchild; pa_no++) {
int keynum = 0;
- CData->curve_firstkey.push_back(keyno);
+ CData->curve_firstkey.push_back_slow(keyno);
float curve_length = 0.0f;
float3 pcKey;
@@ -196,15 +195,15 @@ bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Par
continue;
curve_length += step_length;
}
- CData->curvekey_co.push_back(cKey);
- CData->curvekey_time.push_back(curve_length);
+ CData->curvekey_co.push_back_slow(cKey);
+ CData->curvekey_time.push_back_slow(curve_length);
pcKey = cKey;
keynum++;
}
keyno += keynum;
- CData->curve_keynum.push_back(keynum);
- CData->curve_length.push_back(curve_length);
+ CData->curve_keynum.push_back_slow(keynum);
+ CData->curve_length.push_back_slow(curve_length);
curvenum++;
}
}
@@ -256,7 +255,7 @@ bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Parti
float3 uv = make_float3(0.0f, 0.0f, 0.0f);
if(b_mesh->tessface_uv_textures.length())
b_psys.uv_on_emitter(psmd, *b_pa, pa_no, uv_num, &uv.x);
- CData->curve_uv.push_back(uv);
+ CData->curve_uv.push_back_slow(uv);
if(pa_no < totparts && b_pa != b_psys.particles.end())
++b_pa;
@@ -310,7 +309,7 @@ bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Par
float3 vcol = make_float3(0.0f, 0.0f, 0.0f);
if(b_mesh->tessface_vertex_colors.length())
b_psys.mcol_on_emitter(psmd, *b_pa, pa_no, vcol_num, &vcol.x);
- CData->curve_vcol.push_back(vcol);
+ CData->curve_vcol.push_back_slow(vcol);
if(pa_no < totparts && b_pa != b_psys.particles.end())
++b_pa;
@@ -352,10 +351,7 @@ void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData,
}
}
- mesh->verts.reserve(mesh->verts.size() + numverts);
- mesh->triangles.reserve(mesh->triangles.size() + numtris);
- mesh->shader.reserve(mesh->shader.size() + numtris);
- mesh->smooth.reserve(mesh->smooth.size() + numtris);
+ mesh->reserve_mesh(mesh->verts.size() + numverts, mesh->num_triangles() + numtris);
/* actually export */
for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
@@ -375,8 +371,8 @@ void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData,
xbasis = normalize(cross(RotCam - ickey_loc, v1));
float3 ickey_loc_shfl = ickey_loc - radius * xbasis;
float3 ickey_loc_shfr = ickey_loc + radius * xbasis;
- mesh->verts.push_back(ickey_loc_shfl);
- mesh->verts.push_back(ickey_loc_shfr);
+ mesh->add_vertex(ickey_loc_shfl);
+ mesh->add_vertex(ickey_loc_shfr);
vertexindex += 2;
for(int curvekey = CData->curve_firstkey[curve] + 1; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; curvekey++) {
@@ -402,8 +398,8 @@ void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData,
xbasis = normalize(cross(RotCam - ickey_loc, v1));
float3 ickey_loc_shfl = ickey_loc - radius * xbasis;
float3 ickey_loc_shfr = ickey_loc + radius * xbasis;
- mesh->verts.push_back(ickey_loc_shfl);
- mesh->verts.push_back(ickey_loc_shfr);
+ mesh->add_vertex(ickey_loc_shfl);
+ mesh->add_vertex(ickey_loc_shfr);
mesh->add_triangle(vertexindex-2, vertexindex, vertexindex-1, CData->psys_shader[sys], true);
mesh->add_triangle(vertexindex+1, vertexindex-1, vertexindex, CData->psys_shader[sys], true);
vertexindex += 2;
@@ -411,7 +407,6 @@ void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData,
}
}
- mesh->reserve(mesh->verts.size(), mesh->triangles.size(), 0, 0);
mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
mesh->add_face_normals();
@@ -438,10 +433,7 @@ void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resol
}
}
- mesh->verts.reserve(mesh->verts.size() + numverts);
- mesh->triangles.reserve(mesh->triangles.size() + numtris);
- mesh->shader.reserve(mesh->shader.size() + numtris);
- mesh->smooth.reserve(mesh->smooth.size() + numtris);
+ mesh->reserve_mesh(mesh->verts.size() + numverts, mesh->num_triangles() + numtris);
/* actually export */
for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
@@ -530,7 +522,7 @@ void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resol
float angle = M_2PI_F / (float)resolution;
for(int section = 0; section < resolution; section++) {
float3 ickey_loc_shf = ickey_loc + radius * (cosf(angle * section) * xbasis + sinf(angle * section) * ybasis);
- mesh->verts.push_back(ickey_loc_shf);
+ mesh->add_vertex(ickey_loc_shf);
}
if(subv != 0) {
@@ -547,7 +539,6 @@ void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resol
}
}
- mesh->reserve(mesh->verts.size(), mesh->triangles.size(), 0, 0);
mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
mesh->add_face_normals();
@@ -562,7 +553,7 @@ void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData)
int num_keys = 0;
int num_curves = 0;
- if(!(mesh->curves.empty() && mesh->curve_keys.empty()))
+ if(mesh->num_curves())
return;
Attribute *attr_intercept = NULL;
@@ -585,8 +576,7 @@ void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData)
VLOG(1) << "Exporting curve segments for mesh " << mesh->name;
}
- mesh->curve_keys.reserve(mesh->curve_keys.size() + num_keys);
- mesh->curves.reserve(mesh->curves.size() + num_curves);
+ mesh->reserve_curves(mesh->num_curves() + num_curves, mesh->curve_keys.size() + num_keys);
num_keys = 0;
num_curves = 0;
@@ -614,18 +604,16 @@ void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData)
num_curve_keys++;
}
- mesh->add_curve(num_keys, num_curve_keys, CData->psys_shader[sys]);
+ mesh->add_curve(num_keys, CData->psys_shader[sys]);
num_keys += num_curve_keys;
num_curves++;
}
}
/* check allocation */
- if((mesh->curve_keys.size() != num_keys) || (mesh->curves.size() != num_curves)) {
+ if((mesh->curve_keys.size() != num_keys) || (mesh->num_curves() != num_curves)) {
VLOG(1) << "Allocation failed, clearing data";
- mesh->curve_keys.clear();
- mesh->curves.clear();
- mesh->curve_attributes.clear();
+ mesh->clear();
}
}
@@ -668,13 +656,16 @@ static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int
if(CData->psys_closetip[sys] && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1))
radius = 0.0f;
+ /* curve motion keys store both position and radius in float4 */
mP[i] = float3_to_float4(ickey_loc);
mP[i].w = radius;
/* unlike mesh coordinates, these tend to be slightly different
* between frames due to particle transforms into/out of object
* space, so we use an epsilon to detect actual changes */
- if(len_squared(mP[i] - mesh->curve_keys[i]) > 1e-5f*1e-5f)
+ float4 curve_key = float3_to_float4(mesh->curve_keys[i]);
+ curve_key.w = mesh->curve_radius[i];
+ if(len_squared(mP[i] - curve_key) > 1e-5f*1e-5f)
have_motion = true;
}
@@ -698,8 +689,10 @@ static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int
for(int step = 0; step < time_index; step++) {
float4 *mP = attr_mP->data_float4() + step*numkeys;
- for(int key = 0; key < numkeys; key++)
- mP[key] = mesh->curve_keys[key];
+ for(int key = 0; key < numkeys; key++) {
+ mP[key] = float3_to_float4(mesh->curve_keys[key]);
+ mP[key].w = mesh->curve_radius[key];
+ }
}
}
}
@@ -873,7 +866,9 @@ void BlenderSync::sync_curves(Mesh *mesh,
if(!motion) {
/* Clear stored curve data */
mesh->curve_keys.clear();
- mesh->curves.clear();
+ mesh->curve_radius.clear();
+ mesh->curve_first_key.clear();
+ mesh->curve_shader.clear();
mesh->curve_attributes.clear();
}
@@ -890,7 +885,7 @@ void BlenderSync::sync_curves(Mesh *mesh,
int triangle_method = scene->curve_system_manager->triangle_method;
int resolution = scene->curve_system_manager->resolution;
size_t vert_num = mesh->verts.size();
- size_t tri_num = mesh->triangles.size();
+ size_t tri_num = mesh->num_triangles();
int used_res = 1;
/* extract particle hair data - should be combined with connecting to mesh later*/
@@ -951,11 +946,10 @@ void BlenderSync::sync_curves(Mesh *mesh,
else {
Attribute *attr_generated = mesh->curve_attributes.add(ATTR_STD_GENERATED);
float3 *generated = attr_generated->data_float3();
- size_t i = 0;
- foreach(Mesh::Curve& curve, mesh->curves) {
- float3 co = float4_to_float3(mesh->curve_keys[curve.first_key]);
- generated[i++] = co*size - loc;
+ for(size_t i = 0; i < mesh->num_curves(); i++) {
+ float3 co = mesh->curve_keys[mesh->get_curve(i).first_key];
+ generated[i] = co*size - loc;
}
}
}
diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp
index 55ef913408f..fab03c7659b 100644
--- a/intern/cycles/blender/blender_mesh.cpp
+++ b/intern/cycles/blender/blender_mesh.cpp
@@ -24,7 +24,6 @@
#include "blender_session.h"
#include "blender_util.h"
-#include "subd_mesh.h"
#include "subd_patch.h"
#include "subd_split.h"
@@ -335,44 +334,71 @@ static void attr_create_vertex_color(Scene *scene,
Mesh *mesh,
BL::Mesh& b_mesh,
const vector<int>& nverts,
- const vector<int>& face_flags)
+ const vector<int>& face_flags,
+ bool subdivision)
{
- BL::Mesh::tessface_vertex_colors_iterator l;
- for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l) {
- if(!mesh->need_attribute(scene, ustring(l->name().c_str())))
- continue;
+ if(subdivision) {
+ BL::Mesh::vertex_colors_iterator l;
- Attribute *attr = mesh->attributes.add(
- ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER_BYTE);
+ for(b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l) {
+ if(!mesh->need_attribute(scene, ustring(l->name().c_str())))
+ continue;
- BL::MeshColorLayer::data_iterator c;
- uchar4 *cdata = attr->data_uchar4();
- size_t i = 0;
+ Attribute *attr = mesh->subd_attributes.add(ustring(l->name().c_str()),
+ TypeDesc::TypeColor,
+ ATTR_ELEMENT_CORNER_BYTE);
- for(l->data.begin(c); c != l->data.end(); ++c, ++i) {
- int tri_a[3], tri_b[3];
- face_split_tri_indices(nverts[i], face_flags[i], tri_a, tri_b);
+ BL::Mesh::polygons_iterator p;
+ uchar4 *cdata = attr->data_uchar4();
- uchar4 colors[4];
- colors[0] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color1())));
- colors[1] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color2())));
- colors[2] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color3())));
- if(nverts[i] == 4) {
- colors[3] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color4())));
+ for(b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) {
+ int n = p->loop_total();
+ for(int i = 0; i < n; i++) {
+ float3 color = get_float3(l->data[p->loop_start() + i].color());
+ *(cdata++) = color_float_to_byte(color_srgb_to_scene_linear(color));
+ }
}
+ }
+ }
+ else {
+ BL::Mesh::tessface_vertex_colors_iterator l;
+ for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l) {
+ if(!mesh->need_attribute(scene, ustring(l->name().c_str())))
+ continue;
+
+ Attribute *attr = mesh->attributes.add(ustring(l->name().c_str()),
+ TypeDesc::TypeColor,
+ ATTR_ELEMENT_CORNER_BYTE);
+
+ BL::MeshColorLayer::data_iterator c;
+ uchar4 *cdata = attr->data_uchar4();
+ size_t i = 0;
+
+ for(l->data.begin(c); c != l->data.end(); ++c, ++i) {
+ int tri_a[3], tri_b[3];
+ face_split_tri_indices(nverts[i], face_flags[i], tri_a, tri_b);
+
+ uchar4 colors[4];
+ colors[0] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color1())));
+ colors[1] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color2())));
+ colors[2] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color3())));
+ if(nverts[i] == 4) {
+ colors[3] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color4())));
+ }
- cdata[0] = colors[tri_a[0]];
- cdata[1] = colors[tri_a[1]];
- cdata[2] = colors[tri_a[2]];
+ cdata[0] = colors[tri_a[0]];
+ cdata[1] = colors[tri_a[1]];
+ cdata[2] = colors[tri_a[2]];
- if(nverts[i] == 4) {
- cdata[3] = colors[tri_b[0]];
- cdata[4] = colors[tri_b[1]];
- cdata[5] = colors[tri_b[2]];
- cdata += 6;
+ if(nverts[i] == 4) {
+ cdata[3] = colors[tri_b[0]];
+ cdata[4] = colors[tri_b[1]];
+ cdata[5] = colors[tri_b[2]];
+ cdata += 6;
+ }
+ else
+ cdata += 3;
}
- else
- cdata += 3;
}
}
}
@@ -382,9 +408,45 @@ static void attr_create_uv_map(Scene *scene,
Mesh *mesh,
BL::Mesh& b_mesh,
const vector<int>& nverts,
- const vector<int>& face_flags)
+ const vector<int>& face_flags,
+ bool subdivision,
+ bool subdivide_uvs)
{
- if(b_mesh.tessface_uv_textures.length() != 0) {
+ if(subdivision) {
+ BL::Mesh::uv_layers_iterator l;
+ int i = 0;
+
+ for(b_mesh.uv_layers.begin(l); l != b_mesh.uv_layers.end(); ++l, ++i) {
+ bool active_render = b_mesh.uv_textures[i].active_render();
+ AttributeStandard std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE;
+ ustring name = ustring(l->name().c_str());
+
+ /* UV map */
+ if(mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)) {
+ Attribute *attr;
+
+ if(active_render)
+ attr = mesh->subd_attributes.add(std, name);
+ else
+ attr = mesh->subd_attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER);
+
+ if(subdivide_uvs) {
+ attr->flags |= ATTR_SUBDIVIDED;
+ }
+
+ BL::Mesh::polygons_iterator p;
+ float3 *fdata = attr->data_float3();
+
+ for(b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) {
+ int n = p->loop_total();
+ for(int j = 0; j < n; j++) {
+ *(fdata++) = get_float3(l->data[p->loop_start() + j].uv());
+ }
+ }
+ }
+ }
+ }
+ else if(b_mesh.tessface_uv_textures.length() != 0) {
BL::Mesh::tessface_uv_textures_iterator l;
for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l) {
@@ -465,11 +527,13 @@ static void attr_create_uv_map(Scene *scene,
/* Create vertex pointiness attributes. */
static void attr_create_pointiness(Scene *scene,
Mesh *mesh,
- BL::Mesh& b_mesh)
+ BL::Mesh& b_mesh,
+ bool subdivision)
{
if(mesh->need_attribute(scene, ATTR_STD_POINTINESS)) {
const int numverts = b_mesh.vertices.length();
- Attribute *attr = mesh->attributes.add(ATTR_STD_POINTINESS);
+ AttributeSet& attributes = (subdivision)? mesh->subd_attributes: mesh->attributes;
+ Attribute *attr = attributes.add(ATTR_STD_POINTINESS);
float *data = attr->data_float();
int *counter = new int[numverts];
float *raw_data = new float[numverts];
@@ -532,31 +596,45 @@ static void attr_create_pointiness(Scene *scene,
static void create_mesh(Scene *scene,
Mesh *mesh,
BL::Mesh& b_mesh,
- const vector<uint>& used_shaders)
+ const vector<Shader*>& used_shaders,
+ bool subdivision=false,
+ bool subdivide_uvs=true)
{
/* count vertices and faces */
int numverts = b_mesh.vertices.length();
- int numfaces = b_mesh.tessfaces.length();
+ int numfaces = (!subdivision) ? b_mesh.tessfaces.length() : b_mesh.polygons.length();
int numtris = 0;
- bool use_loop_normals = b_mesh.use_auto_smooth();
+ int numcorners = 0;
+ int numngons = 0;
+ bool use_loop_normals = b_mesh.use_auto_smooth() && (mesh->subdivision_type != Mesh::SUBDIVISION_CATMULL_CLARK);
BL::Mesh::vertices_iterator v;
BL::Mesh::tessfaces_iterator f;
+ BL::Mesh::polygons_iterator p;
- for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f) {
- int4 vi = get_int4(f->vertices_raw());
- numtris += (vi[3] == 0)? 1: 2;
+ if(!subdivision) {
+ for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f) {
+ int4 vi = get_int4(f->vertices_raw());
+ numtris += (vi[3] == 0)? 1: 2;
+ }
+ }
+ else {
+ for(b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) {
+ numngons += (p->loop_total() == 4)? 0: 1;
+ numcorners += p->loop_total();
+ }
}
- /* reserve memory */
- mesh->reserve(numverts, numtris, 0, 0);
+ /* allocate memory */
+ mesh->reserve_mesh(numverts, numtris);
+ mesh->reserve_subd_faces(numfaces, numngons, numcorners);
/* create vertex coordinates and normals */
- int i = 0;
- for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++i)
- mesh->verts[i] = get_float3(v->co());
+ for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
+ mesh->add_vertex(get_float3(v->co()));
- Attribute *attr_N = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL);
+ AttributeSet& attributes = (subdivision)? mesh->subd_attributes: mesh->attributes;
+ Attribute *attr_N = attributes.add(ATTR_STD_VERTEX_NORMAL);
float3 *N = attr_N->data_float3();
for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++N)
@@ -565,7 +643,8 @@ static void create_mesh(Scene *scene,
/* create generated coordinates from undeformed coordinates */
if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
- Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED);
+ Attribute *attr = attributes.add(ATTR_STD_GENERATED);
+ attr->flags |= ATTR_SUBDIVIDED;
float3 loc, size;
mesh_texture_space(b_mesh, loc, size);
@@ -578,68 +657,103 @@ static void create_mesh(Scene *scene,
}
/* Create needed vertex attributes. */
- attr_create_pointiness(scene, mesh, b_mesh);
+ attr_create_pointiness(scene, mesh, b_mesh, subdivision);
/* create faces */
vector<int> nverts(numfaces);
vector<int> face_flags(numfaces, FACE_FLAG_NONE);
- int fi = 0, ti = 0;
-
- for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f, ++fi) {
- int4 vi = get_int4(f->vertices_raw());
- int n = (vi[3] == 0)? 3: 4;
- int mi = clamp(f->material_index(), 0, used_shaders.size()-1);
- int shader = used_shaders[mi];
- bool smooth = f->use_smooth() || use_loop_normals;
-
- /* split vertices if normal is different
- *
- * note all vertex attributes must have been set here so we can split
- * and copy attributes in split_vertex without remapping later */
- if(use_loop_normals) {
- BL::Array<float, 12> loop_normals = f->split_normals();
-
- for(int i = 0; i < n; i++) {
- float3 loop_N = make_float3(loop_normals[i * 3], loop_normals[i * 3 + 1], loop_normals[i * 3 + 2]);
-
- if(N[vi[i]] != loop_N) {
- int new_vi = mesh->split_vertex(vi[i]);
-
- /* set new normal and vertex index */
- N = attr_N->data_float3();
- N[new_vi] = loop_N;
- vi[i] = new_vi;
+ int fi = 0;
+
+ if(!subdivision) {
+ for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f, ++fi) {
+ int4 vi = get_int4(f->vertices_raw());
+ int n = (vi[3] == 0)? 3: 4;
+ int shader = clamp(f->material_index(), 0, used_shaders.size()-1);
+ bool smooth = f->use_smooth() || use_loop_normals;
+
+ /* split vertices if normal is different
+ *
+ * note all vertex attributes must have been set here so we can split
+ * and copy attributes in split_vertex without remapping later */
+ if(use_loop_normals) {
+ BL::Array<float, 12> loop_normals = f->split_normals();
+
+ for(int i = 0; i < n; i++) {
+ float3 loop_N = make_float3(loop_normals[i * 3], loop_normals[i * 3 + 1], loop_normals[i * 3 + 2]);
+
+ if(N[vi[i]] != loop_N) {
+ int new_vi = mesh->split_vertex(vi[i]);
+
+ /* set new normal and vertex index */
+ N = attr_N->data_float3();
+ N[new_vi] = loop_N;
+ vi[i] = new_vi;
+ }
}
}
- }
- /* create triangles */
- if(n == 4) {
- if(is_zero(cross(mesh->verts[vi[1]] - mesh->verts[vi[0]], mesh->verts[vi[2]] - mesh->verts[vi[0]])) ||
- is_zero(cross(mesh->verts[vi[2]] - mesh->verts[vi[0]], mesh->verts[vi[3]] - mesh->verts[vi[0]])))
- {
- // TODO(mai): order here is probably wrong
- mesh->set_triangle(ti++, vi[0], vi[1], vi[3], shader, smooth, true);
- mesh->set_triangle(ti++, vi[2], vi[3], vi[1], shader, smooth, true);
- face_flags[fi] |= FACE_FLAG_DIVIDE_24;
+ /* create triangles */
+ if(n == 4) {
+ if(is_zero(cross(mesh->verts[vi[1]] - mesh->verts[vi[0]], mesh->verts[vi[2]] - mesh->verts[vi[0]])) ||
+ is_zero(cross(mesh->verts[vi[2]] - mesh->verts[vi[0]], mesh->verts[vi[3]] - mesh->verts[vi[0]])))
+ {
+ mesh->add_triangle(vi[0], vi[1], vi[3], shader, smooth);
+ mesh->add_triangle(vi[2], vi[3], vi[1], shader, smooth);
+ face_flags[fi] |= FACE_FLAG_DIVIDE_24;
+ }
+ else {
+ mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth);
+ mesh->add_triangle(vi[0], vi[2], vi[3], shader, smooth);
+ face_flags[fi] |= FACE_FLAG_DIVIDE_13;
+ }
}
else {
- mesh->set_triangle(ti++, vi[0], vi[1], vi[2], shader, smooth, true);
- mesh->set_triangle(ti++, vi[0], vi[2], vi[3], shader, smooth, true);
- face_flags[fi] |= FACE_FLAG_DIVIDE_13;
+ mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth);
}
+
+ nverts[fi] = n;
}
- else
- mesh->set_triangle(ti++, vi[0], vi[1], vi[2], shader, smooth, false);
+ }
+ else {
+ vector<int> vi;
- nverts[fi] = n;
+ for(b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) {
+ int n = p->loop_total();
+ int shader = clamp(p->material_index(), 0, used_shaders.size()-1);
+ bool smooth = p->use_smooth() || use_loop_normals;
+
+ vi.reserve(n);
+ for(int i = 0; i < n; i++) {
+ vi[i] = b_mesh.loops[p->loop_start() + i].vertex_index();
+
+ /* split vertices if normal is different
+ *
+ * note all vertex attributes must have been set here so we can split
+ * and copy attributes in split_vertex without remapping later */
+ if(use_loop_normals) {
+ float3 loop_N = get_float3(b_mesh.loops[p->loop_start() + i].normal());
+
+ if(N[vi[i]] != loop_N) {
+ int new_vi = mesh->split_vertex(vi[i]);
+
+ /* set new normal and vertex index */
+ N = attr_N->data_float3();
+ N[new_vi] = loop_N;
+ vi[i] = new_vi;
+ }
+ }
+ }
+
+ /* create subd faces */
+ mesh->add_subd_face(&vi[0], n, shader, smooth);
+ }
}
/* Create all needed attributes.
* The calculate functions will check whether they're needed or not.
*/
- attr_create_vertex_color(scene, mesh, b_mesh, nverts, face_flags);
- attr_create_uv_map(scene, mesh, b_mesh, nverts, face_flags);
+ attr_create_vertex_color(scene, mesh, b_mesh, nverts, face_flags, subdivision);
+ attr_create_uv_map(scene, mesh, b_mesh, nverts, face_flags, subdivision, subdivide_uvs);
/* for volume objects, create a matrix to transform from object space to
* mesh texture space. this does not work with deformations but that can
@@ -659,29 +773,93 @@ static void create_subd_mesh(Scene *scene,
Mesh *mesh,
BL::Object& b_ob,
BL::Mesh& b_mesh,
- PointerRNA *cmesh,
- const vector<uint>& used_shaders,
+ const vector<Shader*>& used_shaders,
float dicing_rate,
int max_subdivisions)
{
- Mesh basemesh;
- create_mesh(scene, &basemesh, b_mesh, used_shaders);
+ BL::SubsurfModifier subsurf_mod(b_ob.modifiers[b_ob.modifiers.length()-1]);
+ bool subdivide_uvs = subsurf_mod.use_subsurf_uv();
+
+ create_mesh(scene, mesh, b_mesh, used_shaders, true, subdivide_uvs);
+
+ /* export creases */
+ size_t num_creases = 0;
+ BL::Mesh::edges_iterator e;
+
+ for(b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e) {
+ if(e->crease() != 0.0f) {
+ num_creases++;
+ }
+ }
+
+ mesh->subd_creases.resize(num_creases);
- SubdParams sdparams(mesh, used_shaders[0], true, false);
- sdparams.dicing_rate = max(0.1f, RNA_float_get(cmesh, "dicing_rate") * dicing_rate);
+ Mesh::SubdEdgeCrease* crease = mesh->subd_creases.data();
+ for(b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e) {
+ if(e->crease() != 0.0f) {
+ crease->v[0] = e->vertices()[0];
+ crease->v[1] = e->vertices()[1];
+ crease->crease = e->crease();
+
+ crease++;
+ }
+ }
+
+ /* set subd params */
+ if(!mesh->subd_params) {
+ mesh->subd_params = new SubdParams(mesh);
+ }
+ SubdParams& sdparams = *mesh->subd_params;
+
+ PointerRNA cobj = RNA_pointer_get(&b_ob.ptr, "cycles");
+
+ sdparams.dicing_rate = max(0.1f, RNA_float_get(&cobj, "dicing_rate") * dicing_rate);
sdparams.max_level = max_subdivisions;
scene->camera->update();
sdparams.camera = scene->camera;
sdparams.objecttoworld = get_transform(b_ob.matrix_world());
-
- /* tesselate */
- DiagSplit dsplit(sdparams);
- basemesh.tessellate(&dsplit);
}
/* Sync */
+static void sync_mesh_fluid_motion(BL::Object& b_ob, Scene *scene, Mesh *mesh)
+{
+ if(scene->need_motion() == Scene::MOTION_NONE)
+ return;
+
+ BL::DomainFluidSettings b_fluid_domain = object_fluid_domain_find(b_ob);
+
+ if(!b_fluid_domain)
+ return;
+
+ /* If the mesh has modifiers following the fluid domain we can't export motion. */
+ if(b_fluid_domain.fluid_mesh_vertices.length() != mesh->verts.size())
+ return;
+
+ /* Find or add attribute */
+ float3 *P = &mesh->verts[0];
+ Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+
+ if(!attr_mP) {
+ attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
+ }
+
+ /* Only export previous and next frame, we don't have any in between data. */
+ float motion_times[2] = {-1.0f, 1.0f};
+ for(int step = 0; step < 2; step++) {
+ float relative_time = motion_times[step] * scene->motion_shutter_time() * 0.5f;
+ float3 *mP = attr_mP->data_float3() + step*mesh->verts.size();
+
+ BL::DomainFluidSettings::fluid_mesh_vertices_iterator fvi;
+ int i = 0;
+
+ for(b_fluid_domain.fluid_mesh_vertices.begin(fvi); fvi != b_fluid_domain.fluid_mesh_vertices.end(); ++fvi, ++i) {
+ mP[i] = P[i] + get_float3(fvi->velocity()) * relative_time;
+ }
+ }
+}
+
Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
bool object_updated,
bool hide_tris)
@@ -700,7 +878,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
BL::Material material_override = render_layer.material_override;
/* find shader indices */
- vector<uint> used_shaders;
+ vector<Shader*> used_shaders;
BL::Object::material_slots_iterator slot;
for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) {
@@ -742,8 +920,8 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
* because the shader needs different mesh attributes */
bool attribute_recalc = false;
- foreach(uint shader, mesh->used_shaders)
- if(scene->shaders[shader]->need_update_attributes)
+ foreach(Shader *shader, mesh->used_shaders)
+ if(shader->need_update_attributes)
attribute_recalc = true;
if(!attribute_recalc)
@@ -758,13 +936,12 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
mesh_synced.insert(mesh);
/* create derived mesh */
- PointerRNA cmesh = RNA_pointer_get(&b_ob_data.ptr, "cycles");
-
- vector<Mesh::Triangle> oldtriangle = mesh->triangles;
+ array<int> oldtriangle = mesh->triangles;
/* compares curve_keys rather than strands in order to handle quick hair
* adjustments in dynamic BVH - other methods could probably do this better*/
- vector<float4> oldcurve_keys = mesh->curve_keys;
+ array<float3> oldcurve_keys = mesh->curve_keys;
+ array<float> oldcurve_radius = mesh->curve_radius;
mesh->clear();
mesh->used_shaders = used_shaders;
@@ -781,20 +958,23 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
b_ob.update_from_editmode();
bool need_undeformed = mesh->need_attribute(scene, ATTR_STD_GENERATED);
- BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, need_undeformed);
+
+ mesh->subdivision_type = object_subdivision_type(b_ob, preview, experimental);
+
+ BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, need_undeformed, mesh->subdivision_type);
if(b_mesh) {
if(render_layer.use_surfaces && !hide_tris) {
- if(cmesh.data && experimental && RNA_enum_get(&cmesh, "subdivision_type"))
- create_subd_mesh(scene, mesh, b_ob, b_mesh, &cmesh, used_shaders,
+ if(mesh->subdivision_type != Mesh::SUBDIVISION_NONE)
+ create_subd_mesh(scene, mesh, b_ob, b_mesh, used_shaders,
dicing_rate, max_subdivisions);
else
- create_mesh(scene, mesh, b_mesh, used_shaders);
+ create_mesh(scene, mesh, b_mesh, used_shaders, false);
create_mesh_volume_attributes(scene, b_ob, mesh, b_scene.frame_current());
}
- if(render_layer.use_hair)
+ if(render_layer.use_hair && mesh->subdivision_type == Mesh::SUBDIVISION_NONE)
sync_curves(mesh, b_mesh, b_ob, false);
if(can_free_caches) {
@@ -802,25 +982,13 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
}
/* free derived mesh */
- b_data.meshes.remove(b_mesh);
+ b_data.meshes.remove(b_mesh, false);
}
}
mesh->geometry_flags = requested_geometry_flags;
- /* displacement method */
- if(cmesh.data) {
- const int method = get_enum(cmesh,
- "displacement_method",
- Mesh::DISPLACE_NUM_METHODS,
- Mesh::DISPLACE_BUMP);
-
- if(method == 0 || !experimental)
- mesh->displacement_method = Mesh::DISPLACE_BUMP;
- else if(method == 1)
- mesh->displacement_method = Mesh::DISPLACE_TRUE;
- else
- mesh->displacement_method = Mesh::DISPLACE_BOTH;
- }
+ /* fluid motion */
+ sync_mesh_fluid_motion(b_ob, scene, mesh);
/* tag update */
bool rebuild = false;
@@ -828,14 +996,21 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
if(oldtriangle.size() != mesh->triangles.size())
rebuild = true;
else if(oldtriangle.size()) {
- if(memcmp(&oldtriangle[0], &mesh->triangles[0], sizeof(Mesh::Triangle)*oldtriangle.size()) != 0)
+ if(memcmp(&oldtriangle[0], &mesh->triangles[0], sizeof(int)*oldtriangle.size()) != 0)
rebuild = true;
}
if(oldcurve_keys.size() != mesh->curve_keys.size())
rebuild = true;
else if(oldcurve_keys.size()) {
- if(memcmp(&oldcurve_keys[0], &mesh->curve_keys[0], sizeof(float4)*oldcurve_keys.size()) != 0)
+ if(memcmp(&oldcurve_keys[0], &mesh->curve_keys[0], sizeof(float3)*oldcurve_keys.size()) != 0)
+ rebuild = true;
+ }
+
+ if(oldcurve_radius.size() != mesh->curve_radius.size())
+ rebuild = true;
+ else if(oldcurve_radius.size()) {
+ if(memcmp(&oldcurve_radius[0], &mesh->curve_radius[0], sizeof(float)*oldcurve_radius.size()) != 0)
rebuild = true;
}
@@ -904,9 +1079,14 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
* would need a more extensive check to see which objects are animated */
BL::Mesh b_mesh(PointerRNA_NULL);
+ /* fluid motion is exported immediate with mesh, skip here */
+ BL::DomainFluidSettings b_fluid_domain = object_fluid_domain_find(b_ob);
+ if(b_fluid_domain)
+ return;
+
if(ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) {
/* get derived mesh */
- b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, false);
+ b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, false, false);
}
if(!b_mesh) {
@@ -932,8 +1112,8 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
Attribute *attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
if(attr_mP) {
- float4 *keys = &mesh->curve_keys[0];
- memcpy(attr_mP->data_float4() + time_index*numkeys, keys, sizeof(float4)*numkeys);
+ float3 *keys = &mesh->curve_keys[0];
+ memcpy(attr_mP->data_float3() + time_index*numkeys, keys, sizeof(float3)*numkeys);
}
}
@@ -1007,7 +1187,7 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
sync_curves(mesh, b_mesh, b_ob, true, time_index);
/* free derived mesh */
- b_data.meshes.remove(b_mesh);
+ b_data.meshes.remove(b_mesh, false);
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp
index 5c0c30f28de..0d961c5bf88 100644
--- a/intern/cycles/blender/blender_object.cpp
+++ b/intern/cycles/blender/blender_object.cpp
@@ -153,15 +153,11 @@ void BlenderSync::sync_light(BL::Object& b_parent,
/* location and (inverted!) direction */
light->co = transform_get_column(&tfm, 3);
light->dir = -transform_get_column(&tfm, 2);
+ light->tfm = tfm;
/* shader */
- vector<uint> used_shaders;
-
+ vector<Shader*> used_shaders;
find_shader(b_lamp, used_shaders, scene->default_light);
-
- if(used_shaders.size() == 0)
- used_shaders.push_back(scene->default_light);
-
light->shader = used_shaders[0];
/* shadow */
@@ -258,11 +254,20 @@ static bool object_boundbox_clip(Scene *scene,
boundbox[3 * i + 1],
boundbox[3 * i + 2]);
p = transform_point(&tfm, p);
- p = transform_point(&worldtondc, p);
- if(p.z >= -margin) {
+
+ float4 b = make_float4(p.x, p.y, p.z, 1.0f);
+ float4 c = make_float4(dot(worldtondc.x, b),
+ dot(worldtondc.y, b),
+ dot(worldtondc.z, b),
+ dot(worldtondc.w, b));
+ p = float4_to_float3(c / c.w);
+ if(c.z < 0.0f) {
+ p.x = 1.0f - p.x;
+ p.y = 1.0f - p.y;
+ }
+ if(c.z >= -margin) {
all_behind = false;
}
- p /= p.z;
bb_min = min(bb_min, p);
bb_max = max(bb_max, p);
}
@@ -325,16 +330,18 @@ Object *BlenderSync::sync_object(BL::Object& b_parent,
/* object transformation */
if(tfm != object->tfm) {
VLOG(1) << "Object " << b_ob.name() << " motion detected.";
- if(motion_time == -1.0f) {
- object->motion.pre = tfm;
- object->use_motion = true;
- }
- else if(motion_time == 1.0f) {
- object->motion.post = tfm;
+ if(motion_time == -1.0f || motion_time == 1.0f) {
object->use_motion = true;
}
}
+ if(motion_time == -1.0f) {
+ object->motion.pre = tfm;
+ }
+ else if(motion_time == 1.0f) {
+ object->motion.post = tfm;
+ }
+
/* mesh deformation */
if(object->mesh)
sync_mesh_motion(b_ob, object, motion_time);
@@ -370,13 +377,12 @@ Object *BlenderSync::sync_object(BL::Object& b_parent,
}
/* make holdout objects on excluded layer invisible for non-camera rays */
- if(use_holdout && (layer_flag & render_layer.exclude_layer))
+ if(use_holdout && (layer_flag & render_layer.exclude_layer)) {
visibility &= ~(PATH_RAY_ALL_VISIBILITY - PATH_RAY_CAMERA);
+ }
- /* camera flag is not actually used, instead is tested against render layer
- * flags */
- if(visibility & PATH_RAY_CAMERA) {
- visibility |= layer_flag << PATH_RAY_LAYER_SHIFT;
+ /* hide objects not on render layer from camera rays */
+ if(!(layer_flag & render_layer.layer)) {
visibility &= ~PATH_RAY_CAMERA;
}
@@ -392,8 +398,8 @@ Object *BlenderSync::sync_object(BL::Object& b_parent,
object->name = b_ob.name().c_str();
object->pass_id = b_ob.pass_index();
object->tfm = tfm;
- object->motion.pre = tfm;
- object->motion.post = tfm;
+ object->motion.pre = transform_empty();
+ object->motion.post = transform_empty();
object->use_motion = false;
/* motion blur */
@@ -577,7 +583,6 @@ void BlenderSync::sync_objects(BL::SpaceView3D& b_v3d, float motion_time)
bool hide = (render_layer.use_viewport_visibility)? b_ob.hide(): b_ob.hide_render();
uint ob_layer = get_layer(b_base->layers(),
b_base->layers_local_view(),
- render_layer.use_localview,
object_is_light(b_ob),
scene_layers);
hide = hide || !(ob_layer & scene_layer);
@@ -694,6 +699,7 @@ void BlenderSync::sync_motion(BL::RenderSettings& b_render,
Camera prevcam = *(scene->camera);
int frame_center = b_scene.frame_current();
+ float subframe_center = b_scene.frame_subframe();
float frame_center_delta = 0.0f;
if(scene->need_motion() != Scene::MOTION_PASS &&
@@ -707,7 +713,7 @@ void BlenderSync::sync_motion(BL::RenderSettings& b_render,
assert(scene->camera->motion_position == Camera::MOTION_POSITION_START);
frame_center_delta = shuttertime * 0.5f;
}
- float time = frame_center + frame_center_delta;
+ float time = frame_center + subframe_center + frame_center_delta;
int frame = (int)floorf(time);
float subframe = time - frame;
python_thread_state_restore(python_thread_state);
@@ -727,15 +733,10 @@ void BlenderSync::sync_motion(BL::RenderSettings& b_render,
<< relative_time << ".";
/* fixed shutter time to get previous and next frame for motion pass */
- float shuttertime;
-
- if(scene->need_motion() == Scene::MOTION_PASS)
- shuttertime = 2.0f;
- else
- shuttertime = scene->camera->shuttertime;
+ float shuttertime = scene->motion_shutter_time();
/* compute frame and subframe time */
- float time = frame_center + frame_center_delta + relative_time * shuttertime * 0.5f;
+ float time = frame_center + subframe_center + frame_center_delta + relative_time * shuttertime * 0.5f;
int frame = (int)floorf(time);
float subframe = time - frame;
@@ -760,7 +761,7 @@ void BlenderSync::sync_motion(BL::RenderSettings& b_render,
* function assumes it is being executed from python and will
* try to save the thread state */
python_thread_state_restore(python_thread_state);
- b_engine.frame_set(frame_center, 0.0f);
+ b_engine.frame_set(frame_center, subframe_center);
python_thread_state_save(python_thread_state);
/* tag camera for motion update */
diff --git a/intern/cycles/blender/blender_particles.cpp b/intern/cycles/blender/blender_particles.cpp
index d1e702cfdc2..dd2900a8d5b 100644
--- a/intern/cycles/blender/blender_particles.cpp
+++ b/intern/cycles/blender/blender_particles.cpp
@@ -36,6 +36,8 @@ bool BlenderSync::sync_dupli_particle(BL::Object& b_ob,
if(!b_psys)
return false;
+ object->hide_on_missing_motion = true;
+
/* test if we need particle data */
if(!object->mesh->need_attribute(scene, ATTR_STD_PARTICLE))
return false;
@@ -76,7 +78,7 @@ bool BlenderSync::sync_dupli_particle(BL::Object& b_ob,
pa.velocity = get_float3(b_pa.velocity());
pa.angular_velocity = get_float3(b_pa.angular_velocity());
- psys->particles.push_back(pa);
+ psys->particles.push_back_slow(pa);
if(object->particle_index != psys->particles.size() - 1)
scene->object_manager->tag_update(scene);
diff --git a/intern/cycles/blender/blender_python.cpp b/intern/cycles/blender/blender_python.cpp
index 0161b5b192c..a50f5edb1df 100644
--- a/intern/cycles/blender/blender_python.cpp
+++ b/intern/cycles/blender/blender_python.cpp
@@ -26,6 +26,7 @@
#include "util_md5.h"
#include "util_opengl.h"
#include "util_path.h"
+#include "util_string.h"
#include "util_types.h"
#ifdef WITH_OSL
@@ -437,13 +438,13 @@ static PyObject *osl_update_node_func(PyObject * /*self*/, PyObject *args)
continue;
/* determine socket type */
- std::string socket_type;
+ string socket_type;
BL::NodeSocket::type_enum data_type = BL::NodeSocket::type_VALUE;
float4 default_float4 = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
float default_float = 0.0f;
int default_int = 0;
- std::string default_string = "";
-
+ string default_string = "";
+
if(param->isclosure) {
socket_type = "NodeSocketShader";
data_type = BL::NodeSocket::type_SHADER;
diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp
index 7a5243d3234..c250a54f259 100644
--- a/intern/cycles/blender/blender_session.cpp
+++ b/intern/cycles/blender/blender_session.cpp
@@ -473,7 +473,7 @@ void BlenderSession::render()
BL::RenderLayer b_rlay = *b_single_rlay;
/* add passes */
- vector<Pass> passes;
+ array<Pass> passes;
Pass::add(PASS_COMBINED, passes);
if(session_params.device.advanced_shading) {
@@ -681,8 +681,7 @@ void BlenderSession::bake(BL::Object& b_object,
}
}
- /* when used, non-instanced convention: object = ~object */
- int object = ~object_index;
+ int object = object_index;
BakeData *bake_data = scene->bake_manager->init(object, tri_offset, num_pixels);
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index 6bc29838809..c89443f260b 100644
--- a/intern/cycles/blender/blender_shader.cpp
+++ b/intern/cycles/blender/blender_shader.cpp
@@ -27,28 +27,24 @@
#include "blender_util.h"
#include "util_debug.h"
+#include "util_string.h"
CCL_NAMESPACE_BEGIN
typedef map<void*, ShaderInput*> PtrInputMap;
typedef map<void*, ShaderOutput*> PtrOutputMap;
-typedef map<std::string, ConvertNode*> ProxyMap;
+typedef map<string, ConvertNode*> ProxyMap;
/* Find */
void BlenderSync::find_shader(BL::ID& id,
- vector<uint>& used_shaders,
- int default_shader)
+ vector<Shader*>& used_shaders,
+ Shader *default_shader)
{
- Shader *shader = (id)? shader_map.find(id): scene->shaders[default_shader];
+ Shader *shader = (id)? shader_map.find(id): default_shader;
- for(size_t i = 0; i < scene->shaders.size(); i++) {
- if(scene->shaders[i] == shader) {
- used_shaders.push_back(i);
- scene->shaders[i]->tag_used(scene);
- break;
- }
- }
+ used_shaders.push_back(shader);
+ shader->tag_used(scene);
}
/* RNA translation utilities */
@@ -69,6 +65,14 @@ static VolumeInterpolation get_volume_interpolation(PointerRNA& ptr)
VOLUME_INTERPOLATION_LINEAR);
}
+static DisplacementMethod get_displacement_method(PointerRNA& ptr)
+{
+ return (DisplacementMethod)get_enum(ptr,
+ "displacement_method",
+ DISPLACE_NUM_METHODS,
+ DISPLACE_BUMP);
+}
+
static int validate_enum_value(int value, int num_values, int default_value)
{
if(value >= num_values) {
@@ -132,82 +136,60 @@ static float3 get_node_output_vector(BL::Node& b_node, const string& name)
return make_float3(value[0], value[1], value[2]);
}
-static ShaderSocketType convert_socket_type(BL::NodeSocket& b_socket)
+static SocketType::Type convert_socket_type(BL::NodeSocket& b_socket)
{
switch(b_socket.type()) {
case BL::NodeSocket::type_VALUE:
- return SHADER_SOCKET_FLOAT;
+ return SocketType::FLOAT;
case BL::NodeSocket::type_INT:
- return SHADER_SOCKET_INT;
+ return SocketType::INT;
case BL::NodeSocket::type_VECTOR:
- return SHADER_SOCKET_VECTOR;
+ return SocketType::VECTOR;
case BL::NodeSocket::type_RGBA:
- return SHADER_SOCKET_COLOR;
+ return SocketType::COLOR;
case BL::NodeSocket::type_STRING:
- return SHADER_SOCKET_STRING;
+ return SocketType::STRING;
case BL::NodeSocket::type_SHADER:
- return SHADER_SOCKET_CLOSURE;
+ return SocketType::CLOSURE;
default:
- return SHADER_SOCKET_UNDEFINED;
+ return SocketType::UNDEFINED;
}
}
-#ifdef WITH_OSL
-static ShaderSocketType convert_osl_socket_type(OSL::OSLQuery& query,
- BL::NodeSocket& b_socket)
-{
- ShaderSocketType socket_type = convert_socket_type(b_socket);
- if(socket_type == SHADER_SOCKET_VECTOR) {
- /* TODO(sergey): Do we need compatible_name() here? */
- const OSL::OSLQuery::Parameter *param = query.getparam(b_socket.name());
- assert(param != NULL);
- if(param != NULL) {
- if(param->type.vecsemantics == TypeDesc::POINT) {
- socket_type = SHADER_SOCKET_POINT;
- }
- else if(param->type.vecsemantics == TypeDesc::NORMAL) {
- socket_type = SHADER_SOCKET_NORMAL;
- }
- }
- }
-
- return socket_type;
-}
-#endif /* WITH_OSL */
-
static void set_default_value(ShaderInput *input,
BL::NodeSocket& b_sock,
BL::BlendData& b_data,
BL::ID& b_id)
{
+ Node *node = input->parent;
+ const SocketType& socket = input->socket_type;
+
/* copy values for non linked inputs */
- switch(input->type) {
- case SHADER_SOCKET_FLOAT: {
- input->set(get_float(b_sock.ptr, "default_value"));
+ switch(input->type()) {
+ case SocketType::FLOAT: {
+ node->set(socket, get_float(b_sock.ptr, "default_value"));
break;
}
- case SHADER_SOCKET_INT: {
- input->set((float)get_int(b_sock.ptr, "default_value"));
+ case SocketType::INT: {
+ node->set(socket, get_int(b_sock.ptr, "default_value"));
break;
}
- case SHADER_SOCKET_COLOR: {
- input->set(float4_to_float3(get_float4(b_sock.ptr, "default_value")));
+ case SocketType::COLOR: {
+ node->set(socket, float4_to_float3(get_float4(b_sock.ptr, "default_value")));
break;
}
- case SHADER_SOCKET_NORMAL:
- case SHADER_SOCKET_POINT:
- case SHADER_SOCKET_VECTOR: {
- input->set(get_float3(b_sock.ptr, "default_value"));
+ case SocketType::NORMAL:
+ case SocketType::POINT:
+ case SocketType::VECTOR: {
+ node->set(socket, get_float3(b_sock.ptr, "default_value"));
break;
}
- case SHADER_SOCKET_STRING: {
- input->set((ustring)blender_absolute_path(b_data, b_id, get_string(b_sock.ptr, "default_value")));
+ case SocketType::STRING: {
+ node->set(socket, (ustring)blender_absolute_path(b_data, b_id, get_string(b_sock.ptr, "default_value")));
break;
}
-
- case SHADER_SOCKET_CLOSURE:
- case SHADER_SOCKET_UNDEFINED:
+ default:
break;
}
}
@@ -291,7 +273,7 @@ static ShaderNode *add_node(Scene *scene,
RGBRampNode *ramp = new RGBRampNode();
BL::ShaderNodeValToRGB b_ramp_node(b_node);
BL::ColorRamp b_color_ramp(b_ramp_node.color_ramp());
- colorramp_to_array(b_color_ramp, ramp->ramp, RAMP_TABLE_SIZE);
+ colorramp_to_array(b_color_ramp, ramp->ramp, ramp->ramp_alpha, RAMP_TABLE_SIZE);
ramp->interpolate = b_color_ramp.interpolation() != BL::ColorRamp::interpolation_CONSTANT;
node = ramp;
}
@@ -320,7 +302,7 @@ static ShaderNode *add_node(Scene *scene,
else if(b_node.is_a(&RNA_ShaderNodeMixRGB)) {
BL::ShaderNodeMixRGB b_mix_node(b_node);
MixNode *mix = new MixNode();
- mix->type = MixNode::type_enum[b_mix_node.blend_type()];
+ mix->type = (NodeMix)b_mix_node.blend_type();
mix->use_clamp = b_mix_node.use_clamp();
node = mix;
}
@@ -346,27 +328,27 @@ static ShaderNode *add_node(Scene *scene,
node = new HSVNode();
}
else if(b_node.is_a(&RNA_ShaderNodeRGBToBW)) {
- node = new ConvertNode(SHADER_SOCKET_COLOR, SHADER_SOCKET_FLOAT);
+ node = new RGBToBWNode();
}
else if(b_node.is_a(&RNA_ShaderNodeMath)) {
BL::ShaderNodeMath b_math_node(b_node);
MathNode *math = new MathNode();
- math->type = MathNode::type_enum[b_math_node.operation()];
+ math->type = (NodeMath)b_math_node.operation();
math->use_clamp = b_math_node.use_clamp();
node = math;
}
else if(b_node.is_a(&RNA_ShaderNodeVectorMath)) {
BL::ShaderNodeVectorMath b_vector_math_node(b_node);
VectorMathNode *vmath = new VectorMathNode();
- vmath->type = VectorMathNode::type_enum[b_vector_math_node.operation()];
+ vmath->type = (NodeVectorMath)b_vector_math_node.operation();
node = vmath;
}
else if(b_node.is_a(&RNA_ShaderNodeVectorTransform)) {
BL::ShaderNodeVectorTransform b_vector_transform_node(b_node);
VectorTransformNode *vtransform = new VectorTransformNode();
- vtransform->type = VectorTransformNode::type_enum[b_vector_transform_node.vector_type()];
- vtransform->convert_from = VectorTransformNode::convert_space_enum[b_vector_transform_node.convert_from()];
- vtransform->convert_to = VectorTransformNode::convert_space_enum[b_vector_transform_node.convert_to()];
+ vtransform->type = (NodeVectorTransformType)b_vector_transform_node.vector_type();
+ vtransform->convert_from = (NodeVectorTransformConvertSpace)b_vector_transform_node.convert_from();
+ vtransform->convert_to = (NodeVectorTransformConvertSpace)b_vector_transform_node.convert_to();
node = vtransform;
}
else if(b_node.is_a(&RNA_ShaderNodeNormal)) {
@@ -415,13 +397,16 @@ static ShaderNode *add_node(Scene *scene,
switch(b_aniso_node.distribution()) {
case BL::ShaderNodeBsdfAnisotropic::distribution_BECKMANN:
- aniso->distribution = ustring("Beckmann");
+ aniso->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID;
break;
case BL::ShaderNodeBsdfAnisotropic::distribution_GGX:
- aniso->distribution = ustring("GGX");
+ aniso->distribution = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID;
+ break;
+ case BL::ShaderNodeBsdfAnisotropic::distribution_MULTI_GGX:
+ aniso->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID;
break;
case BL::ShaderNodeBsdfAnisotropic::distribution_ASHIKHMIN_SHIRLEY:
- aniso->distribution = ustring("Ashikhmin-Shirley");
+ aniso->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID;
break;
}
@@ -437,13 +422,13 @@ static ShaderNode *add_node(Scene *scene,
switch(b_subsurface_node.falloff()) {
case BL::ShaderNodeSubsurfaceScattering::falloff_CUBIC:
- subsurface->closure = CLOSURE_BSSRDF_CUBIC_ID;
+ subsurface->falloff = CLOSURE_BSSRDF_CUBIC_ID;
break;
case BL::ShaderNodeSubsurfaceScattering::falloff_GAUSSIAN:
- subsurface->closure = CLOSURE_BSSRDF_GAUSSIAN_ID;
+ subsurface->falloff = CLOSURE_BSSRDF_GAUSSIAN_ID;
break;
case BL::ShaderNodeSubsurfaceScattering::falloff_BURLEY:
- subsurface->closure = CLOSURE_BSSRDF_BURLEY_ID;
+ subsurface->falloff = CLOSURE_BSSRDF_BURLEY_ID;
break;
}
@@ -455,16 +440,19 @@ static ShaderNode *add_node(Scene *scene,
switch(b_glossy_node.distribution()) {
case BL::ShaderNodeBsdfGlossy::distribution_SHARP:
- glossy->distribution = ustring("Sharp");
+ glossy->distribution = CLOSURE_BSDF_REFLECTION_ID;
break;
case BL::ShaderNodeBsdfGlossy::distribution_BECKMANN:
- glossy->distribution = ustring("Beckmann");
+ glossy->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_ID;
break;
case BL::ShaderNodeBsdfGlossy::distribution_GGX:
- glossy->distribution = ustring("GGX");
+ glossy->distribution = CLOSURE_BSDF_MICROFACET_GGX_ID;
break;
case BL::ShaderNodeBsdfGlossy::distribution_ASHIKHMIN_SHIRLEY:
- glossy->distribution = ustring("Ashikhmin-Shirley");
+ glossy->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID;
+ break;
+ case BL::ShaderNodeBsdfGlossy::distribution_MULTI_GGX:
+ glossy->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID;
break;
}
node = glossy;
@@ -474,13 +462,16 @@ static ShaderNode *add_node(Scene *scene,
GlassBsdfNode *glass = new GlassBsdfNode();
switch(b_glass_node.distribution()) {
case BL::ShaderNodeBsdfGlass::distribution_SHARP:
- glass->distribution = ustring("Sharp");
+ glass->distribution = CLOSURE_BSDF_SHARP_GLASS_ID;
break;
case BL::ShaderNodeBsdfGlass::distribution_BECKMANN:
- glass->distribution = ustring("Beckmann");
+ glass->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID;
break;
case BL::ShaderNodeBsdfGlass::distribution_GGX:
- glass->distribution = ustring("GGX");
+ glass->distribution = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID;
+ break;
+ case BL::ShaderNodeBsdfGlass::distribution_MULTI_GGX:
+ glass->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID;
break;
}
node = glass;
@@ -490,13 +481,13 @@ static ShaderNode *add_node(Scene *scene,
RefractionBsdfNode *refraction = new RefractionBsdfNode();
switch(b_refraction_node.distribution()) {
case BL::ShaderNodeBsdfRefraction::distribution_SHARP:
- refraction->distribution = ustring("Sharp");
+ refraction->distribution = CLOSURE_BSDF_REFRACTION_ID;
break;
case BL::ShaderNodeBsdfRefraction::distribution_BECKMANN:
- refraction->distribution = ustring("Beckmann");
+ refraction->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
break;
case BL::ShaderNodeBsdfRefraction::distribution_GGX:
- refraction->distribution = ustring("GGX");
+ refraction->distribution = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
break;
}
node = refraction;
@@ -506,10 +497,10 @@ static ShaderNode *add_node(Scene *scene,
ToonBsdfNode *toon = new ToonBsdfNode();
switch(b_toon_node.component()) {
case BL::ShaderNodeBsdfToon::component_DIFFUSE:
- toon->component = ustring("Diffuse");
+ toon->component = CLOSURE_BSDF_DIFFUSE_TOON_ID;
break;
case BL::ShaderNodeBsdfToon::component_GLOSSY:
- toon->component = ustring("Glossy");
+ toon->component = CLOSURE_BSDF_GLOSSY_TOON_ID;
break;
}
node = toon;
@@ -519,10 +510,10 @@ static ShaderNode *add_node(Scene *scene,
HairBsdfNode *hair = new HairBsdfNode();
switch(b_hair_node.component()) {
case BL::ShaderNodeBsdfHair::component_Reflection:
- hair->component = ustring("Reflection");
+ hair->component = CLOSURE_BSDF_HAIR_REFLECTION_ID;
break;
case BL::ShaderNodeBsdfHair::component_Transmission:
- hair->component = ustring("Transmission");
+ hair->component = CLOSURE_BSDF_HAIR_TRANSMISSION_ID;
break;
}
node = hair;
@@ -589,62 +580,17 @@ static ShaderNode *add_node(Scene *scene,
if(scene->shader_manager->use_osl()) {
/* create script node */
BL::ShaderNodeScript b_script_node(b_node);
- OSLScriptNode *script_node = new OSLScriptNode();
OSLShaderManager *manager = (OSLShaderManager*)scene->shader_manager;
string bytecode_hash = b_script_node.bytecode_hash();
- /* Gather additional information from the shader, such as
- * input/output type info needed for proper node construction.
- */
- OSL::OSLQuery query;
- string absolute_filepath;
-
- if(!bytecode_hash.empty()) {
- query.open_bytecode(b_script_node.bytecode());
- }
- else {
- absolute_filepath = blender_absolute_path(b_data, b_ntree, b_script_node.filepath());
- OSLShaderManager::osl_query(query, absolute_filepath);
- }
- /* TODO(sergey): Add proper query info error parsing. */
-
- /* Generate inputs/outputs from node sockets
- *
- * Note: the node sockets are generated from OSL parameters,
- * so the names match those of the corresponding parameters exactly.
- *
- * Note 2: ShaderInput/ShaderOutput store shallow string copies only!
- * So we register them as ustring to ensure the pointer stays valid. */
- BL::Node::inputs_iterator b_input;
-
- for(b_script_node.inputs.begin(b_input); b_input != b_script_node.inputs.end(); ++b_input) {
- ShaderInput *input = script_node->add_input(ustring(b_input->name()).c_str(),
- convert_osl_socket_type(query, *b_input));
- set_default_value(input, *b_input, b_data, b_ntree);
- }
-
- BL::Node::outputs_iterator b_output;
-
- for(b_script_node.outputs.begin(b_output); b_output != b_script_node.outputs.end(); ++b_output) {
- script_node->add_output(ustring(b_output->name()).c_str(),
- convert_osl_socket_type(query, *b_output));
- }
-
- /* load bytecode or filepath */
if(!bytecode_hash.empty()) {
- /* loaded bytecode if not already done */
- if(!manager->shader_test_loaded(bytecode_hash))
- manager->shader_load_bytecode(bytecode_hash, b_script_node.bytecode());
-
- script_node->bytecode_hash = bytecode_hash;
+ node = manager->osl_node("", bytecode_hash, b_script_node.bytecode());
}
else {
- /* set filepath */
- script_node->filepath = absolute_filepath;
+ string absolute_filepath = blender_absolute_path(b_data, b_ntree, b_script_node.filepath());
+ node = manager->osl_node(absolute_filepath, "");
}
-
- node = script_node;
}
#else
(void)b_data;
@@ -691,14 +637,14 @@ static ShaderNode *add_node(Scene *scene,
/* TODO(sergey): Does not work properly when we change builtin type. */
if(b_image.is_updated()) {
scene->image_manager->tag_reload_image(
- image->filename,
+ image->filename.string(),
image->builtin_data,
get_image_interpolation(b_image_node),
get_image_extension(b_image_node));
}
}
- image->color_space = ImageTextureNode::color_space_enum[(int)b_image_node.color_space()];
- image->projection = ImageTextureNode::projection_enum[(int)b_image_node.projection()];
+ image->color_space = (NodeImageColorSpace)b_image_node.color_space();
+ image->projection = (NodeImageProjection)b_image_node.projection();
image->interpolation = get_image_interpolation(b_image_node);
image->extension = get_image_extension(b_image_node);
image->projection_blend = b_image_node.projection_blend();
@@ -737,15 +683,15 @@ static ShaderNode *add_node(Scene *scene,
/* TODO(sergey): Does not work properly when we change builtin type. */
if(b_image.is_updated()) {
scene->image_manager->tag_reload_image(
- env->filename,
+ env->filename.string(),
env->builtin_data,
get_image_interpolation(b_env_node),
EXTENSION_REPEAT);
}
}
- env->color_space = EnvironmentTextureNode::color_space_enum[(int)b_env_node.color_space()];
+ env->color_space = (NodeImageColorSpace)b_env_node.color_space();
env->interpolation = get_image_interpolation(b_env_node);
- env->projection = EnvironmentTextureNode::projection_enum[(int)b_env_node.projection()];
+ env->projection = (NodeEnvironmentProjection)b_env_node.projection();
BL::TexMapping b_texture_mapping(b_env_node.texture_mapping());
get_tex_mapping(&env->tex_mapping, b_texture_mapping);
node = env;
@@ -753,7 +699,7 @@ static ShaderNode *add_node(Scene *scene,
else if(b_node.is_a(&RNA_ShaderNodeTexGradient)) {
BL::ShaderNodeTexGradient b_gradient_node(b_node);
GradientTextureNode *gradient = new GradientTextureNode();
- gradient->type = GradientTextureNode::type_enum[(int)b_gradient_node.gradient_type()];
+ gradient->type = (NodeGradientType)b_gradient_node.gradient_type();
BL::TexMapping b_texture_mapping(b_gradient_node.texture_mapping());
get_tex_mapping(&gradient->tex_mapping, b_texture_mapping);
node = gradient;
@@ -761,7 +707,7 @@ static ShaderNode *add_node(Scene *scene,
else if(b_node.is_a(&RNA_ShaderNodeTexVoronoi)) {
BL::ShaderNodeTexVoronoi b_voronoi_node(b_node);
VoronoiTextureNode *voronoi = new VoronoiTextureNode();
- voronoi->coloring = VoronoiTextureNode::coloring_enum[(int)b_voronoi_node.coloring()];
+ voronoi->coloring = (NodeVoronoiColoring)b_voronoi_node.coloring();
BL::TexMapping b_texture_mapping(b_voronoi_node.texture_mapping());
get_tex_mapping(&voronoi->tex_mapping, b_texture_mapping);
node = voronoi;
@@ -777,8 +723,8 @@ static ShaderNode *add_node(Scene *scene,
else if(b_node.is_a(&RNA_ShaderNodeTexWave)) {
BL::ShaderNodeTexWave b_wave_node(b_node);
WaveTextureNode *wave = new WaveTextureNode();
- wave->type = WaveTextureNode::type_enum[(int)b_wave_node.wave_type()];
- wave->profile = WaveTextureNode::profile_enum[(int)b_wave_node.wave_profile()];
+ wave->type = (NodeWaveType)b_wave_node.wave_type();
+ wave->profile = (NodeWaveProfile)b_wave_node.wave_profile();
BL::TexMapping b_texture_mapping(b_wave_node.texture_mapping());
get_tex_mapping(&wave->tex_mapping, b_texture_mapping);
node = wave;
@@ -811,7 +757,7 @@ static ShaderNode *add_node(Scene *scene,
else if(b_node.is_a(&RNA_ShaderNodeTexMusgrave)) {
BL::ShaderNodeTexMusgrave b_musgrave_node(b_node);
MusgraveTextureNode *musgrave = new MusgraveTextureNode();
- musgrave->type = MusgraveTextureNode::type_enum[(int)b_musgrave_node.musgrave_type()];
+ musgrave->type = (NodeMusgraveType)b_musgrave_node.musgrave_type();
BL::TexMapping b_texture_mapping(b_musgrave_node.texture_mapping());
get_tex_mapping(&musgrave->tex_mapping, b_texture_mapping);
node = musgrave;
@@ -829,7 +775,7 @@ static ShaderNode *add_node(Scene *scene,
else if(b_node.is_a(&RNA_ShaderNodeTexSky)) {
BL::ShaderNodeTexSky b_sky_node(b_node);
SkyTextureNode *sky = new SkyTextureNode();
- sky->type = SkyTextureNode::type_enum[(int)b_sky_node.sky_type()];
+ sky->type = (NodeSkyType)b_sky_node.sky_type();
sky->sun_direction = normalize(get_float3(b_sky_node.sun_direction()));
sky->turbidity = b_sky_node.turbidity();
sky->ground_albedo = b_sky_node.ground_albedo();
@@ -840,15 +786,15 @@ static ShaderNode *add_node(Scene *scene,
else if(b_node.is_a(&RNA_ShaderNodeNormalMap)) {
BL::ShaderNodeNormalMap b_normal_map_node(b_node);
NormalMapNode *nmap = new NormalMapNode();
- nmap->space = NormalMapNode::space_enum[(int)b_normal_map_node.space()];
+ nmap->space = (NodeNormalMapSpace)b_normal_map_node.space();
nmap->attribute = b_normal_map_node.uv_map();
node = nmap;
}
else if(b_node.is_a(&RNA_ShaderNodeTangent)) {
BL::ShaderNodeTangent b_tangent_node(b_node);
TangentNode *tangent = new TangentNode();
- tangent->direction_type = TangentNode::direction_type_enum[(int)b_tangent_node.direction_type()];
- tangent->axis = TangentNode::axis_enum[(int)b_tangent_node.axis()];
+ tangent->direction_type = (NodeTangentDirectionType)b_tangent_node.direction_type();
+ tangent->axis = (NodeTangentAxis)b_tangent_node.axis();
tangent->attribute = b_tangent_node.uv_map();
node = tangent;
}
@@ -863,8 +809,7 @@ static ShaderNode *add_node(Scene *scene,
BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
PointDensityTextureNode *point_density = new PointDensityTextureNode();
point_density->filename = b_point_density_node.name();
- point_density->space =
- PointDensityTextureNode::space_enum[(int)b_point_density_node.space()];
+ point_density->space = (NodeTexVoxelSpace)b_point_density_node.space();
point_density->interpolation = get_image_interpolation(b_point_density_node);
point_density->builtin_data = b_point_density_node.ptr.data;
@@ -875,7 +820,7 @@ static ShaderNode *add_node(Scene *scene,
if(true) {
b_point_density_node.cache_point_density(b_scene, settings);
scene->image_manager->tag_reload_image(
- point_density->filename,
+ point_density->filename.string(),
point_density->builtin_data,
point_density->interpolation,
EXTENSION_CLIP);
@@ -920,17 +865,28 @@ static ShaderNode *add_node(Scene *scene,
BL::Node::outputs_iterator b_output;
- for(b_vdb_node.outputs.begin(b_output); b_output != b_vdb_node.outputs.end(); ++b_output) {
- vdb_node->output_names.push_back(ustring(b_output->name()));
- vdb_node->add_output(vdb_node->output_names.back().c_str(),
- convert_socket_type(*b_output));
+ vdb_node->output_sockets.resize(b_vdb_node.outputs.length());
+ int i = 0;
+ for(b_vdb_node.outputs.begin(b_output); b_output != b_vdb_node.outputs.end(); ++b_output, ++i) {
+ SocketType &socket = vdb_node->output_sockets.at(i);
+ socket.name = ustring(b_output->name());
+ socket.ui_name = ustring(b_output->name());
+ socket.type = convert_socket_type(*b_output);
+ socket.struct_offset = 0;
+ socket.default_value = NULL;
+ socket.enum_values = NULL;
+ socket.node_type = NULL;
+ socket.flags = SocketType::LINKABLE;
+ vdb_node->outputs.push_back(new ShaderOutput(vdb_node->output_sockets.back(), vdb_node));
}
node = vdb_node;
}
- if(node)
+ if(node) {
+ node->name = b_node.name();
graph->add(node);
+ }
return node;
}
@@ -1053,7 +1009,7 @@ static void add_nodes(Scene *scene,
BL::Node::internal_links_iterator b_link;
for(b_node->internal_links.begin(b_link); b_link != b_node->internal_links.end(); ++b_link) {
BL::NodeSocket to_socket(b_link->to_socket());
- ShaderSocketType to_socket_type = convert_socket_type(to_socket);
+ SocketType::Type to_socket_type = convert_socket_type(to_socket);
ConvertNode *proxy = new ConvertNode(to_socket_type, to_socket_type, true);
input_map[b_link->from_socket().ptr.data] = proxy->inputs[0];
@@ -1076,7 +1032,7 @@ static void add_nodes(Scene *scene,
* so that links have something to connect to and assert won't fail.
*/
for(b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) {
- ShaderSocketType input_type = convert_socket_type(*b_input);
+ SocketType::Type input_type = convert_socket_type(*b_input);
ConvertNode *proxy = new ConvertNode(input_type, input_type, true);
graph->add(proxy);
@@ -1088,7 +1044,7 @@ static void add_nodes(Scene *scene,
set_default_value(proxy->inputs[0], *b_input, b_data, b_ntree);
}
for(b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) {
- ShaderSocketType output_type = convert_socket_type(*b_output);
+ SocketType::Type output_type = convert_socket_type(*b_output);
ConvertNode *proxy = new ConvertNode(output_type, output_type, true);
graph->add(proxy);
@@ -1235,7 +1191,7 @@ static void add_nodes(Scene *scene,
void BlenderSync::sync_materials(bool update_all)
{
- shader_map.set_default(scene->shaders[scene->default_surface]);
+ shader_map.set_default(scene->default_surface);
/* material loop */
BL::BlendData::materials_iterator b_mat;
@@ -1257,13 +1213,12 @@ void BlenderSync::sync_materials(bool update_all)
add_nodes(scene, b_engine, b_data, b_scene, !preview, graph, b_ntree);
}
else {
- ShaderNode *closure, *out;
+ DiffuseBsdfNode *diffuse = new DiffuseBsdfNode();
+ diffuse->color = get_float3(b_mat->diffuse_color());
+ graph->add(diffuse);
- closure = graph->add(new DiffuseBsdfNode());
- closure->input("Color")->value = get_float3(b_mat->diffuse_color());
- out = graph->output();
-
- graph->connect(closure->output("BSDF"), out->input("Surface"));
+ ShaderNode *out = graph->output();
+ graph->connect(diffuse->output("BSDF"), out->input("Surface"));
}
/* settings */
@@ -1273,6 +1228,7 @@ void BlenderSync::sync_materials(bool update_all)
shader->heterogeneous_volume = !get_boolean(cmat, "homogeneous_volume");
shader->volume_sampling_method = get_volume_sampling(cmat);
shader->volume_interpolation_method = get_volume_interpolation(cmat);
+ shader->displacement_method = (experimental) ? get_displacement_method(cmat) : DISPLACE_BUMP;
shader->set_graph(graph);
shader->tag_update(scene);
@@ -1290,7 +1246,7 @@ void BlenderSync::sync_world(bool update_all)
BL::World b_world = b_scene.world();
if(world_recalc || update_all || b_world.ptr.data != world_map) {
- Shader *shader = scene->shaders[scene->default_background];
+ Shader *shader = scene->default_background;
ShaderGraph *graph = new ShaderGraph();
/* create nodes */
@@ -1306,13 +1262,12 @@ void BlenderSync::sync_world(bool update_all)
shader->volume_interpolation_method = get_volume_interpolation(cworld);
}
else if(b_world) {
- ShaderNode *closure, *out;
-
- closure = graph->add(new BackgroundNode());
- closure->input("Color")->value = get_float3(b_world.horizon_color());
- out = graph->output();
+ BackgroundNode *background = new BackgroundNode();
+ background->color = get_float3(b_world.horizon_color());
+ graph->add(background);
- graph->connect(closure->output("Background"), out->input("Surface"));
+ ShaderNode *out = graph->output();
+ graph->connect(background->output("Background"), out->input("Surface"));
}
if(b_world) {
@@ -1370,7 +1325,7 @@ void BlenderSync::sync_world(bool update_all)
void BlenderSync::sync_lamps(bool update_all)
{
- shader_map.set_default(scene->shaders[scene->default_light]);
+ shader_map.set_default(scene->default_light);
/* lamp loop */
BL::BlendData::lamps_iterator b_lamp;
@@ -1391,7 +1346,6 @@ void BlenderSync::sync_lamps(bool update_all)
add_nodes(scene, b_engine, b_data, b_scene, !preview, graph, b_ntree);
}
else {
- ShaderNode *closure, *out;
float strength = 1.0f;
if(b_lamp->type() == BL::Lamp::type_POINT ||
@@ -1401,12 +1355,13 @@ void BlenderSync::sync_lamps(bool update_all)
strength = 100.0f;
}
- closure = graph->add(new EmissionNode());
- closure->input("Color")->value = get_float3(b_lamp->color());
- closure->input("Strength")->value.x = strength;
- out = graph->output();
+ EmissionNode *emission = new EmissionNode();
+ emission->color = get_float3(b_lamp->color());
+ emission->strength = strength;
+ graph->add(emission);
- graph->connect(closure->output("Emission"), out->input("Surface"));
+ ShaderNode *out = graph->output();
+ graph->connect(emission->output("Emission"), out->input("Surface"));
}
shader->set_graph(graph);
diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp
index 6291b38d462..4ca202ac40d 100644
--- a/intern/cycles/blender/blender_sync.cpp
+++ b/intern/cycles/blender/blender_sync.cpp
@@ -103,6 +103,27 @@ bool BlenderSync::sync_recalc()
if(b_lamp->is_updated() || (b_lamp->node_tree() && b_lamp->node_tree().is_updated()))
shader_map.set_recalc(*b_lamp);
+ bool dicing_prop_changed = false;
+
+ if(experimental) {
+ PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+
+ float updated_dicing_rate = preview ? RNA_float_get(&cscene, "preview_dicing_rate")
+ : RNA_float_get(&cscene, "dicing_rate");
+
+ if(dicing_rate != updated_dicing_rate) {
+ dicing_rate = updated_dicing_rate;
+ dicing_prop_changed = true;
+ }
+
+ int updated_max_subdivisions = RNA_int_get(&cscene, "max_subdivisions");
+
+ if(max_subdivisions != updated_max_subdivisions) {
+ max_subdivisions = updated_max_subdivisions;
+ dicing_prop_changed = true;
+ }
+ }
+
BL::BlendData::objects_iterator b_ob;
for(b_data.objects.begin(b_ob); b_ob != b_data.objects.end(); ++b_ob) {
@@ -112,7 +133,9 @@ bool BlenderSync::sync_recalc()
}
if(object_is_mesh(*b_ob)) {
- if(b_ob->is_updated_data() || b_ob->data().is_updated()) {
+ if(b_ob->is_updated_data() || b_ob->data().is_updated() ||
+ (dicing_prop_changed && object_subdivision_type(*b_ob, preview, experimental) != Mesh::SUBDIVISION_NONE))
+ {
BL::ID key = BKE_object_is_modified(*b_ob)? *b_ob: b_ob->data();
mesh_map.set_recalc(key);
}
@@ -129,42 +152,14 @@ bool BlenderSync::sync_recalc()
}
}
- bool dicing_prop_changed = false;
-
- if(experimental) {
- PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
-
- float updated_dicing_rate = preview ? RNA_float_get(&cscene, "preview_dicing_rate")
- : RNA_float_get(&cscene, "dicing_rate");
-
- if(dicing_rate != updated_dicing_rate) {
- dicing_rate = updated_dicing_rate;
- dicing_prop_changed = true;
- }
-
- int updated_max_subdivisions = RNA_int_get(&cscene, "max_subdivisions");
-
- if(max_subdivisions != updated_max_subdivisions) {
- max_subdivisions = updated_max_subdivisions;
- dicing_prop_changed = true;
- }
- }
-
BL::BlendData::meshes_iterator b_mesh;
for(b_data.meshes.begin(b_mesh); b_mesh != b_data.meshes.end(); ++b_mesh) {
if(b_mesh->is_updated()) {
mesh_map.set_recalc(*b_mesh);
}
- else if(dicing_prop_changed) {
- PointerRNA cmesh = RNA_pointer_get(&b_mesh->ptr, "cycles");
-
- if(RNA_enum_get(&cmesh, "subdivision_type"))
- mesh_map.set_recalc(*b_mesh);
- }
}
-
BL::BlendData::worlds_iterator b_world;
for(b_data.worlds.begin(b_world); b_world != b_data.worlds.end(); ++b_world) {
@@ -175,8 +170,8 @@ bool BlenderSync::sync_recalc()
world_recalc = true;
}
else if(b_world->node_tree() && b_world->use_nodes()) {
- Shader *shader = scene->shaders[scene->default_background];
- if(has_updated_objects && shader != NULL && shader->has_object_dependency) {
+ Shader *shader = scene->default_background;
+ if(has_updated_objects && shader->has_object_dependency) {
world_recalc = true;
}
}
@@ -269,8 +264,6 @@ void BlenderSync::sync_integrator()
SAMPLING_NUM_PATTERNS,
SAMPLING_PATTERN_SOBOL);
- integrator->layer_flag = render_layer.layer;
-
integrator->sample_clamp_direct = get_float(cscene, "sample_clamp_direct");
integrator->sample_clamp_indirect = get_float(cscene, "sample_clamp_indirect");
#ifdef __CAMERA_MOTION__
@@ -377,8 +370,7 @@ void BlenderSync::sync_render_layers(BL::SpaceView3D& b_v3d, const char *layer)
layer = layername.c_str();
}
else {
- render_layer.use_localview = (b_v3d.local_view() ? true : false);
- render_layer.scene_layer = get_layer(b_v3d.layers(), b_v3d.layers_local_view(), render_layer.use_localview);
+ render_layer.scene_layer = get_layer(b_v3d.layers(), b_v3d.layers_local_view());
render_layer.layer = render_layer.scene_layer;
render_layer.exclude_layer = 0;
render_layer.holdout_layer = 0;
@@ -421,7 +413,6 @@ void BlenderSync::sync_render_layers(BL::SpaceView3D& b_v3d, const char *layer)
render_layer.use_surfaces = b_rlay->use_solid();
render_layer.use_hair = b_rlay->use_strand();
render_layer.use_viewport_visibility = false;
- render_layer.use_localview = false;
render_layer.bound_samples = (use_layer_samples == 1);
if(use_layer_samples != 2) {
@@ -496,6 +487,7 @@ SceneParams BlenderSync::get_scene_params(BL::Scene& b_scene,
SceneParams::BVH_STATIC);
params.use_bvh_spatial_split = RNA_boolean_get(&cscene, "debug_use_spatial_splits");
+ params.use_bvh_unaligned_nodes = RNA_boolean_get(&cscene, "debug_use_hair_bvh");
if(background && params.shadingsystem != SHADINGSYSTEM_OSL)
params.persistent_data = r.use_persistent_data();
@@ -631,9 +623,9 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine& b_engine,
else
params.threads = 0;
- params.cancel_timeout = get_float(cscene, "debug_cancel_timeout");
- params.reset_timeout = get_float(cscene, "debug_reset_timeout");
- params.text_timeout = get_float(cscene, "debug_text_timeout");
+ params.cancel_timeout = (double)get_float(cscene, "debug_cancel_timeout");
+ params.reset_timeout = (double)get_float(cscene, "debug_reset_timeout");
+ params.text_timeout = (double)get_float(cscene, "debug_text_timeout");
params.progressive_refine = get_boolean(cscene, "use_progressive_refine");
diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h
index 6ff5326f39f..9a01b4f2b6e 100644
--- a/intern/cycles/blender/blender_sync.h
+++ b/intern/cycles/blender/blender_sync.h
@@ -131,7 +131,9 @@ private:
Transform& tfm,
bool *use_portal);
void sync_background_light(bool use_portal);
- void sync_mesh_motion(BL::Object& b_ob, Object *object, float motion_time);
+ void sync_mesh_motion(BL::Object& b_ob,
+ Object *object,
+ float motion_time);
void sync_camera_motion(BL::RenderSettings& b_render,
BL::Object& b_ob,
int width, int height,
@@ -146,7 +148,7 @@ private:
void sync_images();
/* util */
- void find_shader(BL::ID& id, vector<uint>& used_shaders, int default_shader);
+ void find_shader(BL::ID& id, vector<Shader*>& used_shaders, Shader *default_shader);
bool BKE_object_is_modified(BL::Object& b_ob);
bool object_is_mesh(BL::Object& b_ob);
bool object_is_light(BL::Object& b_ob);
@@ -163,7 +165,7 @@ private:
id_map<ParticleSystemKey, ParticleSystem> particle_system_map;
set<Mesh*> mesh_synced;
set<Mesh*> mesh_motion_synced;
- std::set<float> motion_times;
+ set<float> motion_times;
void *world_map;
bool world_recalc;
@@ -185,7 +187,6 @@ private:
use_surfaces(true),
use_hair(true),
use_viewport_visibility(false),
- use_localview(false),
samples(0), bound_samples(false)
{}
@@ -200,7 +201,6 @@ private:
bool use_surfaces;
bool use_hair;
bool use_viewport_visibility;
- bool use_localview;
int samples;
bool bound_samples;
} render_layer;
diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h
index cefc01bfa91..f17a61f0ac8 100644
--- a/intern/cycles/blender/blender_util.h
+++ b/intern/cycles/blender/blender_util.h
@@ -17,6 +17,8 @@
#ifndef __BLENDER_UTIL_H__
#define __BLENDER_UTIL_H__
+#include "mesh.h"
+
#include "util_map.h"
#include "util_path.h"
#include "util_set.h"
@@ -45,27 +47,56 @@ static inline BL::Mesh object_to_mesh(BL::BlendData& data,
BL::Scene& scene,
bool apply_modifiers,
bool render,
- bool calc_undeformed)
+ bool calc_undeformed,
+ bool subdivision)
{
+ bool subsurf_mod_show_render;
+ bool subsurf_mod_show_viewport;
+
+ if(subdivision) {
+ BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length()-1];
+
+ subsurf_mod_show_render = subsurf_mod.show_render();
+ subsurf_mod_show_viewport = subsurf_mod.show_viewport();
+
+ subsurf_mod.show_render(false);
+ subsurf_mod.show_viewport(false);
+ }
+
BL::Mesh me = data.meshes.new_from_object(scene, object, apply_modifiers, (render)? 2: 1, false, calc_undeformed);
+
+ if(subdivision) {
+ BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length()-1];
+
+ subsurf_mod.show_render(subsurf_mod_show_render);
+ subsurf_mod.show_viewport(subsurf_mod_show_viewport);
+ }
+
if((bool)me) {
if(me.use_auto_smooth()) {
me.calc_normals_split();
}
- me.calc_tessface(true);
+ if(!subdivision) {
+ me.calc_tessface(true);
+ }
}
return me;
}
static inline void colorramp_to_array(BL::ColorRamp& ramp,
- float4 *data,
+ array<float3>& ramp_color,
+ array<float>& ramp_alpha,
int size)
{
+ ramp_color.resize(size);
+ ramp_alpha.resize(size);
+
for(int i = 0; i < size; i++) {
float color[4];
ramp.evaluate((float)i/(float)(size-1), color);
- data[i] = make_float4(color[0], color[1], color[2], color[3]);
+ ramp_color[i] = make_float3(color[0], color[1], color[2]);
+ ramp_alpha[i] = color[3];
}
}
@@ -93,11 +124,12 @@ static inline void curvemapping_minmax(/*const*/ BL::CurveMapping& cumap,
}
static inline void curvemapping_to_array(BL::CurveMapping& cumap,
- float *data,
+ array<float>& data,
int size)
{
cumap.update();
BL::CurveMap curve = cumap.curves[0];
+ data.resize(size);
for(int i = 0; i < size; i++) {
float t = (float)i/(float)(size-1);
data[i] = curve.evaluate(t);
@@ -105,7 +137,7 @@ static inline void curvemapping_to_array(BL::CurveMapping& cumap,
}
static inline void curvemapping_color_to_array(BL::CurveMapping& cumap,
- float4 *data,
+ array<float3>& data,
int size,
bool rgb_curve)
{
@@ -132,6 +164,8 @@ static inline void curvemapping_color_to_array(BL::CurveMapping& cumap,
BL::CurveMap mapG = cumap.curves[1];
BL::CurveMap mapB = cumap.curves[2];
+ data.resize(size);
+
if(rgb_curve) {
BL::CurveMap mapI = cumap.curves[3];
@@ -268,7 +302,6 @@ static inline uint get_layer(const BL::Array<int, 20>& array)
static inline uint get_layer(const BL::Array<int, 20>& array,
const BL::Array<int, 8>& local_array,
- bool use_local,
bool is_light = false,
uint scene_layers = (1 << 20) - 1)
{
@@ -293,13 +326,6 @@ static inline uint get_layer(const BL::Array<int, 20>& array,
layer |= (1 << (20+i));
}
- /* we don't have spare bits for localview (normally 20-28) because
- * PATH_RAY_LAYER_SHIFT uses 20-32. So - check if we have localview and if
- * so, shift local view bits down to 1-8, since this is done for the view
- * port only - it should be OK and not conflict with render layers. */
- if(use_local)
- layer >>= 20;
-
return layer;
}
@@ -519,6 +545,46 @@ static inline BL::SmokeDomainSettings object_smoke_domain_find(BL::Object& b_ob)
return BL::SmokeDomainSettings(PointerRNA_NULL);
}
+static inline BL::DomainFluidSettings object_fluid_domain_find(BL::Object b_ob)
+{
+ BL::Object::modifiers_iterator b_mod;
+
+ for(b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) {
+ if(b_mod->is_a(&RNA_FluidSimulationModifier)) {
+ BL::FluidSimulationModifier b_fmd(*b_mod);
+ BL::FluidSettings fss = b_fmd.settings();
+
+ if(fss.type() == BL::FluidSettings::type_DOMAIN)
+ return (BL::DomainFluidSettings)b_fmd.settings();
+ }
+ }
+
+ return BL::DomainFluidSettings(PointerRNA_NULL);
+}
+
+static inline Mesh::SubdivisionType object_subdivision_type(BL::Object& b_ob, bool preview, bool experimental)
+{
+ PointerRNA cobj = RNA_pointer_get(&b_ob.ptr, "cycles");
+
+ if(cobj.data && b_ob.modifiers.length() > 0 && experimental) {
+ BL::Modifier mod = b_ob.modifiers[b_ob.modifiers.length()-1];
+ bool enabled = preview ? mod.show_viewport() : mod.show_render();
+
+ if(enabled && mod.type() == BL::Modifier::type_SUBSURF && RNA_boolean_get(&cobj, "use_adaptive_subdivision")) {
+ BL::SubsurfModifier subsurf(mod);
+
+ if(subsurf.subdivision_type() == BL::SubsurfModifier::subdivision_type_CATMULL_CLARK) {
+ return Mesh::SUBDIVISION_CATMULL_CLARK;
+ }
+ else {
+ return Mesh::SUBDIVISION_LINEAR;
+ }
+ }
+ }
+
+ return Mesh::SUBDIVISION_NONE;
+}
+
/* ID Map
*
* Utility class to keep in sync with blender data.
@@ -656,7 +722,7 @@ protected:
/* Object Key */
-enum { OBJECT_PERSISTENT_ID_SIZE = 8 };
+enum { OBJECT_PERSISTENT_ID_SIZE = 16 };
struct ObjectKey {
void *parent;
diff --git a/intern/cycles/bvh/CMakeLists.txt b/intern/cycles/bvh/CMakeLists.txt
index cbbd23fcff8..92e48f0d87f 100644
--- a/intern/cycles/bvh/CMakeLists.txt
+++ b/intern/cycles/bvh/CMakeLists.txt
@@ -1,6 +1,7 @@
set(INC
.
+ ../graph
../kernel
../kernel/svm
../render
@@ -18,6 +19,7 @@ set(SRC
bvh_node.cpp
bvh_sort.cpp
bvh_split.cpp
+ bvh_unaligned.cpp
)
set(SRC_HEADERS
@@ -28,6 +30,7 @@ set(SRC_HEADERS
bvh_params.h
bvh_sort.h
bvh_split.h
+ bvh_unaligned.h
)
include_directories(${INC})
diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp
index 5c474c8c3e9..4851de5b481 100644
--- a/intern/cycles/bvh/bvh.cpp
+++ b/intern/cycles/bvh/bvh.cpp
@@ -24,6 +24,7 @@
#include "bvh_build.h"
#include "bvh_node.h"
#include "bvh_params.h"
+#include "bvh_unaligned.h"
#include "util_debug.h"
#include "util_foreach.h"
@@ -121,57 +122,66 @@ void BVH::refit(Progress& progress)
/* Triangles */
-void BVH::pack_triangle(int idx, float4 storage[3])
+void BVH::pack_triangle(int idx, float4 tri_verts[3])
{
int tob = pack.prim_object[idx];
assert(tob >= 0 && tob < objects.size());
const Mesh *mesh = objects[tob]->mesh;
int tidx = pack.prim_index[idx];
- const int *vidx = mesh->triangles[tidx].v;
- const float3* vpos = &mesh->verts[0];
- float3 v0 = vpos[vidx[0]];
- float3 v1 = vpos[vidx[1]];
- float3 v2 = vpos[vidx[2]];
-
- storage[0] = float3_to_float4(v0);
- storage[1] = float3_to_float4(v1);
- storage[2] = float3_to_float4(v2);
+ Mesh::Triangle t = mesh->get_triangle(tidx);
+ const float3 *vpos = &mesh->verts[0];
+ float3 v0 = vpos[t.v[0]];
+ float3 v1 = vpos[t.v[1]];
+ float3 v2 = vpos[t.v[2]];
+
+ tri_verts[0] = float3_to_float4(v0);
+ tri_verts[1] = float3_to_float4(v1);
+ tri_verts[2] = float3_to_float4(v2);
}
void BVH::pack_primitives()
{
- int nsize = TRI_NODE_SIZE;
- size_t tidx_size = pack.prim_index.size();
-
- pack.tri_storage.clear();
- pack.tri_storage.resize(tidx_size * nsize);
+ const size_t tidx_size = pack.prim_index.size();
+ size_t num_prim_triangles = 0;
+ /* Count number of triangles primitives in BVH. */
+ for(unsigned int i = 0; i < tidx_size; i++) {
+ if((pack.prim_index[i] != -1)) {
+ if((pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) {
+ ++num_prim_triangles;
+ }
+ }
+ }
+ /* Reserve size for arrays. */
+ pack.prim_tri_index.clear();
+ pack.prim_tri_index.resize(tidx_size);
+ pack.prim_tri_verts.clear();
+ pack.prim_tri_verts.resize(num_prim_triangles * 3);
pack.prim_visibility.clear();
pack.prim_visibility.resize(tidx_size);
-
+ /* Fill in all the arrays. */
+ size_t prim_triangle_index = 0;
for(unsigned int i = 0; i < tidx_size; i++) {
if(pack.prim_index[i] != -1) {
- float4 storage[3];
+ int tob = pack.prim_object[i];
+ Object *ob = objects[tob];
- if(pack.prim_type[i] & PRIMITIVE_TRIANGLE) {
- pack_triangle(i, storage);
+ if((pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) {
+ pack_triangle(i, (float4*)&pack.prim_tri_verts[3 * prim_triangle_index]);
+ pack.prim_tri_index[i] = 3 * prim_triangle_index;
+ ++prim_triangle_index;
}
else {
- /* Avoid use of uninitialized memory. */
- memset(&storage, 0, sizeof(storage));
+ pack.prim_tri_index[i] = -1;
}
- memcpy(&pack.tri_storage[i * nsize], storage, sizeof(float4)*3);
-
- int tob = pack.prim_object[i];
- Object *ob = objects[tob];
pack.prim_visibility[i] = ob->visibility;
if(pack.prim_type[i] & PRIMITIVE_ALL_CURVE)
pack.prim_visibility[i] |= PATH_RAY_CURVE;
}
else {
- memset(&pack.tri_storage[i * nsize], 0, sizeof(float4)*3);
+ pack.prim_tri_index[i] = -1;
pack.prim_visibility[i] = 0;
}
}
@@ -183,13 +193,13 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
{
/* The BVH's for instances are built separately, but for traversal all
* BVH's are stored in global arrays. This function merges them into the
- * top level BVH, adjusting indexes and offsets where appropriate. */
- bool use_qbvh = params.use_qbvh;
- size_t nsize = (use_qbvh)? BVH_QNODE_SIZE: BVH_NODE_SIZE;
- size_t nsize_leaf = (use_qbvh)? BVH_QNODE_LEAF_SIZE: BVH_NODE_LEAF_SIZE;
+ * top level BVH, adjusting indexes and offsets where appropriate.
+ */
+ const bool use_qbvh = params.use_qbvh;
- /* adjust primitive index to point to the triangle in the global array, for
- * meshes with transform applied and already in the top level BVH */
+ /* Adjust primitive index to point to the triangle in the global array, for
+ * meshes with transform applied and already in the top level BVH.
+ */
for(size_t i = 0; i < pack.prim_index.size(); i++)
if(pack.prim_index[i] != -1) {
if(pack.prim_type[i] & PRIMITIVE_ALL_CURVE)
@@ -208,10 +218,10 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
/* reserve */
size_t prim_index_size = pack.prim_index.size();
- size_t tri_storage_size = pack.tri_storage.size();
+ size_t prim_tri_verts_size = pack.prim_tri_verts.size();
size_t pack_prim_index_offset = prim_index_size;
- size_t pack_tri_storage_offset = tri_storage_size;
+ size_t pack_prim_tri_verts_offset = prim_tri_verts_size;
size_t pack_nodes_offset = nodes_size;
size_t pack_leaf_nodes_offset = leaf_nodes_size;
size_t object_offset = 0;
@@ -225,7 +235,7 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
if(mesh->need_build_bvh()) {
if(mesh_map.find(mesh) == mesh_map.end()) {
prim_index_size += bvh->pack.prim_index.size();
- tri_storage_size += bvh->pack.tri_storage.size();
+ prim_tri_verts_size += bvh->pack.prim_tri_verts.size();
nodes_size += bvh->pack.nodes.size();
leaf_nodes_size += bvh->pack.leaf_nodes.size();
@@ -240,7 +250,8 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
pack.prim_type.resize(prim_index_size);
pack.prim_object.resize(prim_index_size);
pack.prim_visibility.resize(prim_index_size);
- pack.tri_storage.resize(tri_storage_size);
+ pack.prim_tri_verts.resize(prim_tri_verts_size);
+ pack.prim_tri_index.resize(prim_index_size);
pack.nodes.resize(nodes_size);
pack.leaf_nodes.resize(leaf_nodes_size);
pack.object_node.resize(objects.size());
@@ -249,7 +260,8 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
int *pack_prim_type = (pack.prim_type.size())? &pack.prim_type[0]: NULL;
int *pack_prim_object = (pack.prim_object.size())? &pack.prim_object[0]: NULL;
uint *pack_prim_visibility = (pack.prim_visibility.size())? &pack.prim_visibility[0]: NULL;
- float4 *pack_tri_storage = (pack.tri_storage.size())? &pack.tri_storage[0]: NULL;
+ float4 *pack_prim_tri_verts = (pack.prim_tri_verts.size())? &pack.prim_tri_verts[0]: NULL;
+ uint *pack_prim_tri_index = (pack.prim_tri_index.size())? &pack.prim_tri_index[0]: NULL;
int4 *pack_nodes = (pack.nodes.size())? &pack.nodes[0]: NULL;
int4 *pack_leaf_nodes = (pack.leaf_nodes.size())? &pack.leaf_nodes[0]: NULL;
@@ -277,8 +289,8 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
BVH *bvh = mesh->bvh;
- int noffset = nodes_offset/nsize;
- int noffset_leaf = nodes_leaf_offset/nsize_leaf;
+ int noffset = nodes_offset;
+ int noffset_leaf = nodes_leaf_offset;
int mesh_tri_offset = mesh->tri_offset;
int mesh_curve_offset = mesh->curve_offset;
@@ -290,18 +302,24 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
mesh_map[mesh] = pack.object_node[object_offset-1];
- /* merge primitive and object indexes */
+ /* merge primitive, object and triangle indexes */
if(bvh->pack.prim_index.size()) {
size_t bvh_prim_index_size = bvh->pack.prim_index.size();
int *bvh_prim_index = &bvh->pack.prim_index[0];
int *bvh_prim_type = &bvh->pack.prim_type[0];
uint *bvh_prim_visibility = &bvh->pack.prim_visibility[0];
+ uint *bvh_prim_tri_index = &bvh->pack.prim_tri_index[0];
for(size_t i = 0; i < bvh_prim_index_size; i++) {
- if(bvh->pack.prim_type[i] & PRIMITIVE_ALL_CURVE)
+ if(bvh->pack.prim_type[i] & PRIMITIVE_ALL_CURVE) {
pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_curve_offset;
- else
+ pack_prim_tri_index[pack_prim_index_offset] = -1;
+ }
+ else {
pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_tri_offset;
+ pack_prim_tri_index[pack_prim_index_offset] =
+ bvh_prim_tri_index[i] + pack_prim_tri_verts_offset;
+ }
pack_prim_type[pack_prim_index_offset] = bvh_prim_type[i];
pack_prim_visibility[pack_prim_index_offset] = bvh_prim_visibility[i];
@@ -310,50 +328,64 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
}
}
- /* merge triangle intersection data */
- if(bvh->pack.tri_storage.size()) {
- memcpy(pack_tri_storage + pack_tri_storage_offset,
- &bvh->pack.tri_storage[0],
- bvh->pack.tri_storage.size()*sizeof(float4));
- pack_tri_storage_offset += bvh->pack.tri_storage.size();
+ /* Merge triangle vertices data. */
+ if(bvh->pack.prim_tri_verts.size()) {
+ const size_t prim_tri_size = bvh->pack.prim_tri_verts.size();
+ memcpy(pack_prim_tri_verts + pack_prim_tri_verts_offset,
+ &bvh->pack.prim_tri_verts[0],
+ prim_tri_size*sizeof(float4));
+ pack_prim_tri_verts_offset += prim_tri_size;
}
/* merge nodes */
if(bvh->pack.leaf_nodes.size()) {
int4 *leaf_nodes_offset = &bvh->pack.leaf_nodes[0];
size_t leaf_nodes_offset_size = bvh->pack.leaf_nodes.size();
- for(size_t i = 0, j = 0; i < leaf_nodes_offset_size; i+=nsize_leaf, j++) {
+ for(size_t i = 0, j = 0;
+ i < leaf_nodes_offset_size;
+ i += BVH_NODE_LEAF_SIZE, j++)
+ {
int4 data = leaf_nodes_offset[i];
data.x += prim_offset;
data.y += prim_offset;
pack_leaf_nodes[pack_leaf_nodes_offset] = data;
- for(int j = 1; j < nsize_leaf; ++j) {
+ for(int j = 1; j < BVH_NODE_LEAF_SIZE; ++j) {
pack_leaf_nodes[pack_leaf_nodes_offset + j] = leaf_nodes_offset[i + j];
}
- pack_leaf_nodes_offset += nsize_leaf;
+ pack_leaf_nodes_offset += BVH_NODE_LEAF_SIZE;
}
}
if(bvh->pack.nodes.size()) {
- /* For QBVH we're packing a child bbox into 6 float4,
- * and for regular BVH they're packed into 3 float4.
- */
- size_t nsize_bbox = (use_qbvh)? 6: 3;
int4 *bvh_nodes = &bvh->pack.nodes[0];
- size_t bvh_nodes_size = bvh->pack.nodes.size();
+ size_t bvh_nodes_size = bvh->pack.nodes.size();
+
+ for(size_t i = 0, j = 0; i < bvh_nodes_size; j++) {
+ size_t nsize, nsize_bbox;
+ if(bvh_nodes[i].x & PATH_RAY_NODE_UNALIGNED) {
+ nsize = use_qbvh
+ ? BVH_UNALIGNED_QNODE_SIZE
+ : BVH_UNALIGNED_NODE_SIZE;
+ nsize_bbox = (use_qbvh)? 13: 0;
+ }
+ else {
+ nsize = (use_qbvh)? BVH_QNODE_SIZE: BVH_NODE_SIZE;
+ nsize_bbox = (use_qbvh)? 7: 0;
+ }
- for(size_t i = 0, j = 0; i < bvh_nodes_size; i+=nsize, j++) {
- memcpy(pack_nodes + pack_nodes_offset, bvh_nodes + i, nsize_bbox*sizeof(int4));
+ memcpy(pack_nodes + pack_nodes_offset,
+ bvh_nodes + i,
+ nsize_bbox*sizeof(int4));
- /* modify offsets into arrays */
+ /* Modify offsets into arrays */
int4 data = bvh_nodes[i + nsize_bbox];
- data.x += (data.x < 0)? -noffset_leaf: noffset;
- data.y += (data.y < 0)? -noffset_leaf: noffset;
+ data.z += (data.z < 0)? -noffset_leaf: noffset;
+ data.w += (data.w < 0)? -noffset_leaf: noffset;
if(use_qbvh) {
- data.z += (data.z < 0)? -noffset_leaf: noffset;
- data.w += (data.w < 0)? -noffset_leaf: noffset;
+ data.x += (data.x < 0)? -noffset_leaf: noffset;
+ data.y += (data.y < 0)? -noffset_leaf: noffset;
}
pack_nodes[pack_nodes_offset + nsize_bbox] = data;
@@ -366,6 +398,7 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
sizeof(int4) * (nsize - (nsize_bbox+1)));
pack_nodes_offset += nsize;
+ i += nsize;
}
}
@@ -377,13 +410,22 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
/* Regular BVH */
+static bool node_bvh_is_unaligned(const BVHNode *node)
+{
+ const BVHNode *node0 = node->get_child(0),
+ *node1 = node->get_child(1);
+ return node0->is_unaligned() || node1->is_unaligned();
+}
+
RegularBVH::RegularBVH(const BVHParams& params_, const vector<Object*>& objects_)
: BVH(params_, objects_)
{
}
-void RegularBVH::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf)
+void RegularBVH::pack_leaf(const BVHStackEntry& e,
+ const LeafNode *leaf)
{
+ assert(e.idx + BVH_NODE_LEAF_SIZE <= pack.leaf_nodes.size());
float4 data[BVH_NODE_LEAF_SIZE];
memset(data, 0, sizeof(data));
if(leaf->num_triangles() == 1 && pack.prim_index[leaf->m_lo] == -1) {
@@ -401,54 +443,147 @@ void RegularBVH::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf)
data[0].w = __uint_as_float(pack.prim_type[leaf->m_lo]);
}
- memcpy(&pack.leaf_nodes[e.idx * BVH_NODE_LEAF_SIZE], data, sizeof(float4)*BVH_NODE_LEAF_SIZE);
+ memcpy(&pack.leaf_nodes[e.idx], data, sizeof(float4)*BVH_NODE_LEAF_SIZE);
}
-void RegularBVH::pack_inner(const BVHStackEntry& e, const BVHStackEntry& e0, const BVHStackEntry& e1)
+void RegularBVH::pack_inner(const BVHStackEntry& e,
+ const BVHStackEntry& e0,
+ const BVHStackEntry& e1)
{
- pack_node(e.idx, e0.node->m_bounds, e1.node->m_bounds, e0.encodeIdx(), e1.encodeIdx(), e0.node->m_visibility, e1.node->m_visibility);
+ if(e0.node->is_unaligned() || e1.node->is_unaligned()) {
+ pack_unaligned_inner(e, e0, e1);
+ } else {
+ pack_aligned_inner(e, e0, e1);
+ }
}
-void RegularBVH::pack_node(int idx, const BoundBox& b0, const BoundBox& b1, int c0, int c1, uint visibility0, uint visibility1)
+void RegularBVH::pack_aligned_inner(const BVHStackEntry& e,
+ const BVHStackEntry& e0,
+ const BVHStackEntry& e1)
{
- int4 data[BVH_NODE_SIZE] =
- {
- make_int4(__float_as_int(b0.min.x), __float_as_int(b1.min.x), __float_as_int(b0.max.x), __float_as_int(b1.max.x)),
- make_int4(__float_as_int(b0.min.y), __float_as_int(b1.min.y), __float_as_int(b0.max.y), __float_as_int(b1.max.y)),
- make_int4(__float_as_int(b0.min.z), __float_as_int(b1.min.z), __float_as_int(b0.max.z), __float_as_int(b1.max.z)),
- make_int4(c0, c1, visibility0, visibility1)
+ pack_aligned_node(e.idx,
+ e0.node->m_bounds, e1.node->m_bounds,
+ e0.encodeIdx(), e1.encodeIdx(),
+ e0.node->m_visibility, e1.node->m_visibility);
+}
+
+void RegularBVH::pack_aligned_node(int idx,
+ const BoundBox& b0,
+ const BoundBox& b1,
+ int c0, int c1,
+ uint visibility0, uint visibility1)
+{
+ assert(idx + BVH_NODE_SIZE <= pack.nodes.size());
+ assert(c0 < 0 || c0 < pack.nodes.size());
+ assert(c1 < 0 || c1 < pack.nodes.size());
+
+ int4 data[BVH_NODE_SIZE] = {
+ make_int4(visibility0 & ~PATH_RAY_NODE_UNALIGNED,
+ visibility1 & ~PATH_RAY_NODE_UNALIGNED,
+ c0, c1),
+ make_int4(__float_as_int(b0.min.x),
+ __float_as_int(b1.min.x),
+ __float_as_int(b0.max.x),
+ __float_as_int(b1.max.x)),
+ make_int4(__float_as_int(b0.min.y),
+ __float_as_int(b1.min.y),
+ __float_as_int(b0.max.y),
+ __float_as_int(b1.max.y)),
+ make_int4(__float_as_int(b0.min.z),
+ __float_as_int(b1.min.z),
+ __float_as_int(b0.max.z),
+ __float_as_int(b1.max.z)),
};
- memcpy(&pack.nodes[idx * BVH_NODE_SIZE], data, sizeof(int4)*BVH_NODE_SIZE);
+ memcpy(&pack.nodes[idx], data, sizeof(int4)*BVH_NODE_SIZE);
}
-void RegularBVH::pack_nodes(const BVHNode *root)
+void RegularBVH::pack_unaligned_inner(const BVHStackEntry& e,
+ const BVHStackEntry& e0,
+ const BVHStackEntry& e1)
{
- size_t tot_node_size = root->getSubtreeSize(BVH_STAT_NODE_COUNT);
- size_t leaf_node_size = root->getSubtreeSize(BVH_STAT_LEAF_COUNT);
- size_t node_size = tot_node_size - leaf_node_size;
+ pack_unaligned_node(e.idx,
+ e0.node->get_aligned_space(),
+ e1.node->get_aligned_space(),
+ e0.node->m_bounds,
+ e1.node->m_bounds,
+ e0.encodeIdx(), e1.encodeIdx(),
+ e0.node->m_visibility, e1.node->m_visibility);
+}
- /* resize arrays */
- pack.nodes.clear();
+void RegularBVH::pack_unaligned_node(int idx,
+ const Transform& aligned_space0,
+ const Transform& aligned_space1,
+ const BoundBox& bounds0,
+ const BoundBox& bounds1,
+ int c0, int c1,
+ uint visibility0, uint visibility1)
+{
+ assert(idx + BVH_UNALIGNED_NODE_SIZE <= pack.nodes.size());
+ assert(c0 < 0 || c0 < pack.nodes.size());
+ assert(c1 < 0 || c1 < pack.nodes.size());
+
+ float4 data[BVH_UNALIGNED_NODE_SIZE];
+ Transform space0 = BVHUnaligned::compute_node_transform(bounds0,
+ aligned_space0);
+ Transform space1 = BVHUnaligned::compute_node_transform(bounds1,
+ aligned_space1);
+ data[0] = make_float4(__int_as_float(visibility0 | PATH_RAY_NODE_UNALIGNED),
+ __int_as_float(visibility1 | PATH_RAY_NODE_UNALIGNED),
+ __int_as_float(c0),
+ __int_as_float(c1));
+
+ data[1] = space0.x;
+ data[2] = space0.y;
+ data[3] = space0.z;
+ data[4] = space1.x;
+ data[5] = space1.y;
+ data[6] = space1.z;
+
+ memcpy(&pack.nodes[idx], data, sizeof(float4)*BVH_UNALIGNED_NODE_SIZE);
+}
- /* for top level BVH, first merge existing BVH's so we know the offsets */
+void RegularBVH::pack_nodes(const BVHNode *root)
+{
+ const size_t num_nodes = root->getSubtreeSize(BVH_STAT_NODE_COUNT);
+ const size_t num_leaf_nodes = root->getSubtreeSize(BVH_STAT_LEAF_COUNT);
+ assert(num_leaf_nodes <= num_nodes);
+ const size_t num_inner_nodes = num_nodes - num_leaf_nodes;
+ size_t node_size;
+ if(params.use_unaligned_nodes) {
+ const size_t num_unaligned_nodes =
+ root->getSubtreeSize(BVH_STAT_UNALIGNED_INNER_COUNT);
+ node_size = (num_unaligned_nodes * BVH_UNALIGNED_NODE_SIZE) +
+ (num_inner_nodes - num_unaligned_nodes) * BVH_NODE_SIZE;
+ }
+ else {
+ node_size = num_inner_nodes * BVH_NODE_SIZE;
+ }
+ /* Resize arrays */
+ pack.nodes.clear();
+ pack.leaf_nodes.clear();
+ /* For top level BVH, first merge existing BVH's so we know the offsets. */
if(params.top_level) {
- pack_instances(node_size*BVH_NODE_SIZE,
- leaf_node_size*BVH_NODE_LEAF_SIZE);
+ pack_instances(node_size, num_leaf_nodes*BVH_NODE_LEAF_SIZE);
}
else {
- pack.nodes.resize(node_size*BVH_NODE_SIZE);
- pack.leaf_nodes.resize(leaf_node_size*BVH_NODE_LEAF_SIZE);
+ pack.nodes.resize(node_size);
+ pack.leaf_nodes.resize(num_leaf_nodes*BVH_NODE_LEAF_SIZE);
}
int nextNodeIdx = 0, nextLeafNodeIdx = 0;
vector<BVHStackEntry> stack;
stack.reserve(BVHParams::MAX_DEPTH*2);
- if(root->is_leaf())
+ if(root->is_leaf()) {
stack.push_back(BVHStackEntry(root, nextLeafNodeIdx++));
- else
- stack.push_back(BVHStackEntry(root, nextNodeIdx++));
+ }
+ else {
+ stack.push_back(BVHStackEntry(root, nextNodeIdx));
+ nextNodeIdx += node_bvh_is_unaligned(root)
+ ? BVH_UNALIGNED_NODE_SIZE
+ : BVH_NODE_SIZE;
+ }
while(stack.size()) {
BVHStackEntry e = stack.back();
@@ -456,20 +591,31 @@ void RegularBVH::pack_nodes(const BVHNode *root)
if(e.node->is_leaf()) {
/* leaf node */
- const LeafNode* leaf = reinterpret_cast<const LeafNode*>(e.node);
+ const LeafNode *leaf = reinterpret_cast<const LeafNode*>(e.node);
pack_leaf(e, leaf);
}
else {
/* innner node */
- int idx0 = (e.node->get_child(0)->is_leaf())? (nextLeafNodeIdx++) : (nextNodeIdx++);
- int idx1 = (e.node->get_child(1)->is_leaf())? (nextLeafNodeIdx++) : (nextNodeIdx++);
- stack.push_back(BVHStackEntry(e.node->get_child(0), idx0));
- stack.push_back(BVHStackEntry(e.node->get_child(1), idx1));
+ int idx[2];
+ for(int i = 0; i < 2; ++i) {
+ if(e.node->get_child(i)->is_leaf()) {
+ idx[i] = nextLeafNodeIdx++;
+ }
+ else {
+ idx[i] = nextNodeIdx;
+ nextNodeIdx += node_bvh_is_unaligned(e.node->get_child(i))
+ ? BVH_UNALIGNED_NODE_SIZE
+ : BVH_NODE_SIZE;
+ }
+ }
+
+ stack.push_back(BVHStackEntry(e.node->get_child(0), idx[0]));
+ stack.push_back(BVHStackEntry(e.node->get_child(1), idx[1]));
pack_inner(e, stack[stack.size()-2], stack[stack.size()-1]);
}
}
-
+ assert(node_size == nextNodeIdx);
/* root index to start traversal at, to handle case of single leaf node */
pack.root_index = (root->is_leaf())? -1: 0;
}
@@ -486,9 +632,10 @@ void RegularBVH::refit_nodes()
void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility)
{
if(leaf) {
- int4 *data = &pack.leaf_nodes[idx*BVH_NODE_LEAF_SIZE];
- int c0 = data[0].x;
- int c1 = data[0].y;
+ assert(idx + BVH_NODE_LEAF_SIZE <= pack.leaf_nodes.size());
+ const int4 *data = &pack.leaf_nodes[idx];
+ const int c0 = data[0].x;
+ const int c1 = data[0].y;
/* refit leaf node */
for(int prim = c0; prim < c1; prim++) {
int pidx = pack.prim_index[prim];
@@ -506,10 +653,10 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility
if(pack.prim_type[prim] & PRIMITIVE_ALL_CURVE) {
/* curves */
int str_offset = (params.top_level)? mesh->curve_offset: 0;
- const Mesh::Curve& curve = mesh->curves[pidx - str_offset];
+ Mesh::Curve curve = mesh->get_curve(pidx - str_offset);
int k = PRIMITIVE_UNPACK_SEGMENT(pack.prim_type[prim]);
- curve.bounds_grow(k, &mesh->curve_keys[0], bbox);
+ curve.bounds_grow(k, &mesh->curve_keys[0], &mesh->curve_radius[0], bbox);
visibility |= PATH_RAY_CURVE;
@@ -520,17 +667,17 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility
if(attr) {
size_t mesh_size = mesh->curve_keys.size();
size_t steps = mesh->motion_steps - 1;
- float4 *key_steps = attr->data_float4();
+ float3 *key_steps = attr->data_float3();
for(size_t i = 0; i < steps; i++)
- curve.bounds_grow(k, key_steps + i*mesh_size, bbox);
+ curve.bounds_grow(k, key_steps + i*mesh_size, &mesh->curve_radius[0], bbox);
}
}
}
else {
/* triangles */
int tri_offset = (params.top_level)? mesh->tri_offset: 0;
- const Mesh::Triangle& triangle = mesh->triangles[pidx - tri_offset];
+ Mesh::Triangle triangle = mesh->get_triangle(pidx - tri_offset);
const float3 *vpos = &mesh->verts[0];
triangle.bounds_grow(vpos, bbox);
@@ -560,14 +707,15 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility
leaf_data[0].y = __int_as_float(c1);
leaf_data[0].z = __uint_as_float(visibility);
leaf_data[0].w = __uint_as_float(data[0].w);
- memcpy(&pack.leaf_nodes[idx * BVH_NODE_LEAF_SIZE],
- leaf_data,
- sizeof(float4)*BVH_NODE_LEAF_SIZE);
+ memcpy(&pack.leaf_nodes[idx], leaf_data, sizeof(float4)*BVH_NODE_LEAF_SIZE);
}
else {
- int4 *data = &pack.nodes[idx*BVH_NODE_SIZE];
- int c0 = data[3].x;
- int c1 = data[3].y;
+ assert(idx + BVH_NODE_SIZE <= pack.nodes.size());
+
+ const int4 *data = &pack.nodes[idx];
+ const bool is_unaligned = (data[0].x & PATH_RAY_NODE_UNALIGNED) != 0;
+ const int c0 = data[0].z;
+ const int c1 = data[0].w;
/* refit inner node, set bbox from children */
BoundBox bbox0 = BoundBox::empty, bbox1 = BoundBox::empty;
uint visibility0 = 0, visibility1 = 0;
@@ -575,7 +723,22 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility
refit_node((c0 < 0)? -c0-1: c0, (c0 < 0), bbox0, visibility0);
refit_node((c1 < 0)? -c1-1: c1, (c1 < 0), bbox1, visibility1);
- pack_node(idx, bbox0, bbox1, c0, c1, visibility0, visibility1);
+ if(is_unaligned) {
+ Transform aligned_space = transform_identity();
+ pack_unaligned_node(idx,
+ aligned_space, aligned_space,
+ bbox0, bbox1,
+ c0, c1,
+ visibility0,
+ visibility1);
+ }
+ else {
+ pack_aligned_node(idx,
+ bbox0, bbox1,
+ c0, c1,
+ visibility0,
+ visibility1);
+ }
bbox.grow(bbox0);
bbox.grow(bbox1);
@@ -585,6 +748,33 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility
/* QBVH */
+/* Can we avoid this somehow or make more generic?
+ *
+ * Perhaps we can merge nodes in actual tree and make our
+ * life easier all over the place.
+ */
+static bool node_qbvh_is_unaligned(const BVHNode *node)
+{
+ const BVHNode *node0 = node->get_child(0),
+ *node1 = node->get_child(1);
+ bool has_unaligned = false;
+ if(node0->is_leaf()) {
+ has_unaligned |= node0->is_unaligned();
+ }
+ else {
+ has_unaligned |= node0->get_child(0)->is_unaligned();
+ has_unaligned |= node0->get_child(1)->is_unaligned();
+ }
+ if(node1->is_leaf()) {
+ has_unaligned |= node1->is_unaligned();
+ }
+ else {
+ has_unaligned |= node1->get_child(0)->is_unaligned();
+ has_unaligned |= node1->get_child(1)->is_unaligned();
+ }
+ return has_unaligned;
+}
+
QBVH::QBVH(const BVHParams& params_, const vector<Object*>& objects_)
: BVH(params_, objects_)
{
@@ -610,66 +800,209 @@ void QBVH::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf)
data[0].w = __uint_as_float(pack.prim_type[leaf->m_lo]);
}
- memcpy(&pack.leaf_nodes[e.idx * BVH_QNODE_LEAF_SIZE], data, sizeof(float4)*BVH_QNODE_LEAF_SIZE);
+ memcpy(&pack.leaf_nodes[e.idx], data, sizeof(float4)*BVH_QNODE_LEAF_SIZE);
}
-void QBVH::pack_inner(const BVHStackEntry& e, const BVHStackEntry *en, int num)
+void QBVH::pack_inner(const BVHStackEntry& e,
+ const BVHStackEntry *en,
+ int num)
+{
+ bool has_unaligned = false;
+ /* Check whether we have to create unaligned node or all nodes are aligned
+ * and we can cut some corner here.
+ */
+ if(params.use_unaligned_nodes) {
+ for(int i = 0; i < num; i++) {
+ if(en[i].node->is_unaligned()) {
+ has_unaligned = true;
+ break;
+ }
+ }
+ }
+ if(has_unaligned) {
+ /* There's no unaligned children, pack into AABB node. */
+ pack_unaligned_inner(e, en, num);
+ }
+ else {
+ /* Create unaligned node with orientation transform for each of the
+ * children.
+ */
+ pack_aligned_inner(e, en, num);
+ }
+}
+
+void QBVH::pack_aligned_inner(const BVHStackEntry& e,
+ const BVHStackEntry *en,
+ int num)
+{
+ BoundBox bounds[4];
+ int child[4];
+ for(int i = 0; i < num; ++i) {
+ bounds[i] = en[i].node->m_bounds;
+ child[i] = en[i].encodeIdx();
+ }
+ pack_aligned_node(e.idx,
+ bounds,
+ child,
+ e.node->m_visibility,
+ num);
+}
+
+void QBVH::pack_aligned_node(int idx,
+ const BoundBox *bounds,
+ const int *child,
+ const uint visibility,
+ const int num)
{
float4 data[BVH_QNODE_SIZE];
+ memset(data, 0, sizeof(data));
+
+ data[0].x = __uint_as_float(visibility & ~PATH_RAY_NODE_UNALIGNED);
+ for(int i = 0; i < num; i++) {
+ float3 bb_min = bounds[i].min;
+ float3 bb_max = bounds[i].max;
+
+ data[1][i] = bb_min.x;
+ data[2][i] = bb_max.x;
+ data[3][i] = bb_min.y;
+ data[4][i] = bb_max.y;
+ data[5][i] = bb_min.z;
+ data[6][i] = bb_max.z;
+
+ data[7][i] = __int_as_float(child[i]);
+ }
+
+ for(int i = num; i < 4; i++) {
+ /* We store BB which would never be recorded as intersection
+ * so kernel might safely assume there are always 4 child nodes.
+ */
+ data[1][i] = FLT_MAX;
+ data[2][i] = -FLT_MAX;
+
+ data[3][i] = FLT_MAX;
+ data[4][i] = -FLT_MAX;
+
+ data[5][i] = FLT_MAX;
+ data[6][i] = -FLT_MAX;
+
+ data[7][i] = __int_as_float(0);
+ }
+
+ memcpy(&pack.nodes[idx], data, sizeof(float4)*BVH_QNODE_SIZE);
+}
+
+void QBVH::pack_unaligned_inner(const BVHStackEntry& e,
+ const BVHStackEntry *en,
+ int num)
+{
+ Transform aligned_space[4];
+ BoundBox bounds[4];
+ int child[4];
+ for(int i = 0; i < num; ++i) {
+ aligned_space[i] = en[i].node->get_aligned_space();
+ bounds[i] = en[i].node->m_bounds;
+ child[i] = en[i].encodeIdx();
+ }
+ pack_unaligned_node(e.idx,
+ aligned_space,
+ bounds,
+ child,
+ e.node->m_visibility,
+ num);
+}
+
+void QBVH::pack_unaligned_node(int idx,
+ const Transform *aligned_space,
+ const BoundBox *bounds,
+ const int *child,
+ const uint visibility,
+ const int num)
+{
+ float4 data[BVH_UNALIGNED_QNODE_SIZE];
+ memset(data, 0, sizeof(data));
+
+ data[0].x = __uint_as_float(visibility | PATH_RAY_NODE_UNALIGNED);
for(int i = 0; i < num; i++) {
- float3 bb_min = en[i].node->m_bounds.min;
- float3 bb_max = en[i].node->m_bounds.max;
+ Transform space = BVHUnaligned::compute_node_transform(
+ bounds[i],
+ aligned_space[i]);
- data[0][i] = bb_min.x;
- data[1][i] = bb_max.x;
- data[2][i] = bb_min.y;
- data[3][i] = bb_max.y;
- data[4][i] = bb_min.z;
- data[5][i] = bb_max.z;
+ data[1][i] = space.x.x;
+ data[2][i] = space.x.y;
+ data[3][i] = space.x.z;
- data[6][i] = __int_as_float(en[i].encodeIdx());
+ data[4][i] = space.y.x;
+ data[5][i] = space.y.y;
+ data[6][i] = space.y.z;
+
+ data[7][i] = space.z.x;
+ data[8][i] = space.z.y;
+ data[9][i] = space.z.z;
+
+ data[10][i] = space.x.w;
+ data[11][i] = space.y.w;
+ data[12][i] = space.z.w;
+
+ data[13][i] = __int_as_float(child[i]);
}
for(int i = num; i < 4; i++) {
/* We store BB which would never be recorded as intersection
* so kernel might safely assume there are always 4 child nodes.
*/
- data[0][i] = FLT_MAX;
- data[1][i] = -FLT_MAX;
- data[2][i] = FLT_MAX;
- data[3][i] = -FLT_MAX;
+ data[1][i] = 1.0f;
+ data[2][i] = 0.0f;
+ data[3][i] = 0.0f;
+
+ data[4][i] = 0.0f;
+ data[5][i] = 0.0f;
+ data[6][i] = 0.0f;
- data[4][i] = FLT_MAX;
- data[5][i] = -FLT_MAX;
+ data[7][i] = 0.0f;
+ data[8][i] = 0.0f;
+ data[9][i] = 0.0f;
- data[6][i] = __int_as_float(0);
+ data[10][i] = -FLT_MAX;
+ data[11][i] = -FLT_MAX;
+ data[12][i] = -FLT_MAX;
+
+ data[13][i] = __int_as_float(0);
}
- memcpy(&pack.nodes[e.idx * BVH_QNODE_SIZE], data, sizeof(float4)*BVH_QNODE_SIZE);
+ memcpy(&pack.nodes[idx], data, sizeof(float4)*BVH_UNALIGNED_QNODE_SIZE);
}
/* Quad SIMD Nodes */
void QBVH::pack_nodes(const BVHNode *root)
{
- size_t tot_node_size = root->getSubtreeSize(BVH_STAT_QNODE_COUNT);
- size_t leaf_node_size = root->getSubtreeSize(BVH_STAT_LEAF_COUNT);
- size_t node_size = tot_node_size - leaf_node_size;
-
- /* resize arrays */
+ /* Calculate size of the arrays required. */
+ const size_t num_nodes = root->getSubtreeSize(BVH_STAT_QNODE_COUNT);
+ const size_t num_leaf_nodes = root->getSubtreeSize(BVH_STAT_LEAF_COUNT);
+ assert(num_leaf_nodes <= num_nodes);
+ const size_t num_inner_nodes = num_nodes - num_leaf_nodes;
+ size_t node_size;
+ if(params.use_unaligned_nodes) {
+ const size_t num_unaligned_nodes =
+ root->getSubtreeSize(BVH_STAT_UNALIGNED_INNER_QNODE_COUNT);
+ node_size = (num_unaligned_nodes * BVH_UNALIGNED_QNODE_SIZE) +
+ (num_inner_nodes - num_unaligned_nodes) * BVH_QNODE_SIZE;
+ }
+ else {
+ node_size = num_inner_nodes * BVH_QNODE_SIZE;
+ }
+ /* Resize arrays. */
pack.nodes.clear();
pack.leaf_nodes.clear();
-
- /* for top level BVH, first merge existing BVH's so we know the offsets */
+ /* For top level BVH, first merge existing BVH's so we know the offsets. */
if(params.top_level) {
- pack_instances(node_size*BVH_QNODE_SIZE,
- leaf_node_size*BVH_QNODE_LEAF_SIZE);
+ pack_instances(node_size, num_leaf_nodes*BVH_QNODE_LEAF_SIZE);
}
else {
- pack.nodes.resize(node_size*BVH_QNODE_SIZE);
- pack.leaf_nodes.resize(leaf_node_size*BVH_QNODE_LEAF_SIZE);
+ pack.nodes.resize(node_size);
+ pack.leaf_nodes.resize(num_leaf_nodes*BVH_QNODE_LEAF_SIZE);
}
int nextNodeIdx = 0, nextLeafNodeIdx = 0;
@@ -680,7 +1013,10 @@ void QBVH::pack_nodes(const BVHNode *root)
stack.push_back(BVHStackEntry(root, nextLeafNodeIdx++));
}
else {
- stack.push_back(BVHStackEntry(root, nextNodeIdx++));
+ stack.push_back(BVHStackEntry(root, nextNodeIdx));
+ nextNodeIdx += node_qbvh_is_unaligned(root)
+ ? BVH_UNALIGNED_QNODE_SIZE
+ : BVH_QNODE_SIZE;
}
while(stack.size()) {
@@ -689,19 +1025,17 @@ void QBVH::pack_nodes(const BVHNode *root)
if(e.node->is_leaf()) {
/* leaf node */
- const LeafNode* leaf = reinterpret_cast<const LeafNode*>(e.node);
+ const LeafNode *leaf = reinterpret_cast<const LeafNode*>(e.node);
pack_leaf(e, leaf);
}
else {
- /* inner node */
+ /* Inner node. */
const BVHNode *node = e.node;
const BVHNode *node0 = node->get_child(0);
const BVHNode *node1 = node->get_child(1);
-
- /* collect nodes */
+ /* Collect nodes. */
const BVHNode *nodes[4];
int numnodes = 0;
-
if(node0->is_leaf()) {
nodes[numnodes++] = node0;
}
@@ -709,7 +1043,6 @@ void QBVH::pack_nodes(const BVHNode *root)
nodes[numnodes++] = node0->get_child(0);
nodes[numnodes++] = node0->get_child(1);
}
-
if(node1->is_leaf()) {
nodes[numnodes++] = node1;
}
@@ -717,25 +1050,26 @@ void QBVH::pack_nodes(const BVHNode *root)
nodes[numnodes++] = node1->get_child(0);
nodes[numnodes++] = node1->get_child(1);
}
-
- /* push entries on the stack */
- for(int i = 0; i < numnodes; i++) {
+ /* Push entries on the stack. */
+ for(int i = 0; i < numnodes; ++i) {
int idx;
if(nodes[i]->is_leaf()) {
idx = nextLeafNodeIdx++;
}
else {
- idx = nextNodeIdx++;
+ idx = nextNodeIdx;
+ nextNodeIdx += node_qbvh_is_unaligned(nodes[i])
+ ? BVH_UNALIGNED_QNODE_SIZE
+ : BVH_QNODE_SIZE;
}
stack.push_back(BVHStackEntry(nodes[i], idx));
}
-
- /* set node */
+ /* Set node. */
pack_inner(e, &stack[stack.size()-numnodes], numnodes);
}
}
-
- /* root index to start traversal at, to handle case of single leaf node */
+ assert(node_size == nextNodeIdx);
+ /* Root index to start traversal at, to handle case of single leaf node. */
pack.root_index = (root->is_leaf())? -1: 0;
}
@@ -751,7 +1085,7 @@ void QBVH::refit_nodes()
void QBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility)
{
if(leaf) {
- int4 *data = &pack.leaf_nodes[idx*BVH_QNODE_LEAF_SIZE];
+ int4 *data = &pack.leaf_nodes[idx];
int4 c = data[0];
/* Refit leaf node. */
for(int prim = c.x; prim < c.y; prim++) {
@@ -770,10 +1104,10 @@ void QBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility)
if(pack.prim_type[prim] & PRIMITIVE_ALL_CURVE) {
/* Curves. */
int str_offset = (params.top_level)? mesh->curve_offset: 0;
- const Mesh::Curve& curve = mesh->curves[pidx - str_offset];
+ Mesh::Curve curve = mesh->get_curve(pidx - str_offset);
int k = PRIMITIVE_UNPACK_SEGMENT(pack.prim_type[prim]);
- curve.bounds_grow(k, &mesh->curve_keys[0], bbox);
+ curve.bounds_grow(k, &mesh->curve_keys[0], &mesh->curve_radius[0], bbox);
visibility |= PATH_RAY_CURVE;
@@ -784,17 +1118,17 @@ void QBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility)
if(attr) {
size_t mesh_size = mesh->curve_keys.size();
size_t steps = mesh->motion_steps - 1;
- float4 *key_steps = attr->data_float4();
+ float3 *key_steps = attr->data_float3();
for(size_t i = 0; i < steps; i++)
- curve.bounds_grow(k, key_steps + i*mesh_size, bbox);
+ curve.bounds_grow(k, key_steps + i*mesh_size, &mesh->curve_radius[0], bbox);
}
}
}
else {
/* Triangles. */
int tri_offset = (params.top_level)? mesh->tri_offset: 0;
- const Mesh::Triangle& triangle = mesh->triangles[pidx - tri_offset];
+ Mesh::Triangle triangle = mesh->get_triangle(pidx - tri_offset);
const float3 *vpos = &mesh->verts[0];
triangle.bounds_grow(vpos, bbox);
@@ -833,13 +1167,18 @@ void QBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility)
leaf_data[0].y = __int_as_float(c.y);
leaf_data[0].z = __uint_as_float(visibility);
leaf_data[0].w = __uint_as_float(c.w);
- memcpy(&pack.leaf_nodes[idx * BVH_QNODE_LEAF_SIZE],
- leaf_data,
- sizeof(float4)*BVH_QNODE_LEAF_SIZE);
+ memcpy(&pack.leaf_nodes[idx], leaf_data, sizeof(float4)*BVH_QNODE_LEAF_SIZE);
}
else {
- int4 *data = &pack.nodes[idx*BVH_QNODE_SIZE];
- int4 c = data[6];
+ int4 *data = &pack.nodes[idx];
+ bool is_unaligned = (data[0].x & PATH_RAY_NODE_UNALIGNED) != 0;
+ int4 c;
+ if(is_unaligned) {
+ c = data[13];
+ }
+ else {
+ c = data[7];
+ }
/* Refit inner node, set bbox from children. */
BoundBox child_bbox[4] = {BoundBox::empty,
BoundBox::empty,
@@ -858,21 +1197,25 @@ void QBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility)
}
}
- float4 inner_data[BVH_QNODE_SIZE];
- for(int i = 0; i < 4; ++i) {
- float3 bb_min = child_bbox[i].min;
- float3 bb_max = child_bbox[i].max;
- inner_data[0][i] = bb_min.x;
- inner_data[1][i] = bb_max.x;
- inner_data[2][i] = bb_min.y;
- inner_data[3][i] = bb_max.y;
- inner_data[4][i] = bb_min.z;
- inner_data[5][i] = bb_max.z;
- inner_data[6][i] = __int_as_float(c[i]);
+ if(is_unaligned) {
+ Transform aligned_space[4] = {transform_identity(),
+ transform_identity(),
+ transform_identity(),
+ transform_identity()};
+ pack_unaligned_node(idx,
+ aligned_space,
+ child_bbox,
+ &c[0],
+ visibility,
+ 4);
+ }
+ else {
+ pack_aligned_node(idx,
+ child_bbox,
+ &c[0],
+ visibility,
+ 4);
}
- memcpy(&pack.nodes[idx * BVH_QNODE_SIZE],
- inner_data,
- sizeof(float4)*BVH_QNODE_SIZE);
}
}
diff --git a/intern/cycles/bvh/bvh.h b/intern/cycles/bvh/bvh.h
index 6076c25ca31..f8fb3b568ca 100644
--- a/intern/cycles/bvh/bvh.h
+++ b/intern/cycles/bvh/bvh.h
@@ -35,11 +35,14 @@ class Progress;
#define BVH_NODE_SIZE 4
#define BVH_NODE_LEAF_SIZE 1
-#define BVH_QNODE_SIZE 7
+#define BVH_QNODE_SIZE 8
#define BVH_QNODE_LEAF_SIZE 1
#define BVH_ALIGN 4096
#define TRI_NODE_SIZE 3
+#define BVH_UNALIGNED_NODE_SIZE 7
+#define BVH_UNALIGNED_QNODE_SIZE 14
+
/* Packed BVH
*
* BVH stored as it will be used for traversal on the rendering device. */
@@ -52,8 +55,10 @@ struct PackedBVH {
array<int4> leaf_nodes;
/* object index to BVH node index mapping for instances */
array<int> object_node;
- /* Aligned triangle storage for fatser lookup in the kernel. */
- array<float4> tri_storage;
+ /* Mapping from primitive index to index in triangle array. */
+ array<uint> prim_tri_index;
+ /* Continuous storage of triangle vertices. */
+ array<float4> prim_tri_verts;
/* primitive type - triangle or strand */
array<int> prim_type;
/* visibility visibilitys for primitives */
@@ -91,7 +96,7 @@ public:
protected:
BVH(const BVHParams& params, const vector<Object*>& objects);
- /* triangles and strands*/
+ /* triangles and strands */
void pack_primitives();
void pack_triangle(int idx, float4 storage[3]);
@@ -115,9 +120,32 @@ protected:
/* pack */
void pack_nodes(const BVHNode *root);
- void pack_leaf(const BVHStackEntry& e, const LeafNode *leaf);
- void pack_inner(const BVHStackEntry& e, const BVHStackEntry& e0, const BVHStackEntry& e1);
- void pack_node(int idx, const BoundBox& b0, const BoundBox& b1, int c0, int c1, uint visibility0, uint visibility1);
+
+ void pack_leaf(const BVHStackEntry& e,
+ const LeafNode *leaf);
+ void pack_inner(const BVHStackEntry& e,
+ const BVHStackEntry& e0,
+ const BVHStackEntry& e1);
+
+ void pack_aligned_inner(const BVHStackEntry& e,
+ const BVHStackEntry& e0,
+ const BVHStackEntry& e1);
+ void pack_aligned_node(int idx,
+ const BoundBox& b0,
+ const BoundBox& b1,
+ int c0, int c1,
+ uint visibility0, uint visibility1);
+
+ void pack_unaligned_inner(const BVHStackEntry& e,
+ const BVHStackEntry& e0,
+ const BVHStackEntry& e1);
+ void pack_unaligned_node(int idx,
+ const Transform& aligned_space0,
+ const Transform& aligned_space1,
+ const BoundBox& b0,
+ const BoundBox& b1,
+ int c0, int c1,
+ uint visibility0, uint visibility1);
/* refit */
void refit_nodes();
@@ -136,9 +164,29 @@ protected:
/* pack */
void pack_nodes(const BVHNode *root);
+
void pack_leaf(const BVHStackEntry& e, const LeafNode *leaf);
void pack_inner(const BVHStackEntry& e, const BVHStackEntry *en, int num);
+ void pack_aligned_inner(const BVHStackEntry& e,
+ const BVHStackEntry *en,
+ int num);
+ void pack_aligned_node(int idx,
+ const BoundBox *bounds,
+ const int *child,
+ const uint visibility,
+ const int num);
+
+ void pack_unaligned_inner(const BVHStackEntry& e,
+ const BVHStackEntry *en,
+ int num);
+ void pack_unaligned_node(int idx,
+ const Transform *aligned_space,
+ const BoundBox *bounds,
+ const int *child,
+ const uint visibility,
+ const int num);
+
/* refit */
void refit_nodes();
void refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility);
diff --git a/intern/cycles/bvh/bvh_binning.cpp b/intern/cycles/bvh/bvh_binning.cpp
index b07e870d759..5ddd7349f7b 100644
--- a/intern/cycles/bvh/bvh_binning.cpp
+++ b/intern/cycles/bvh/bvh_binning.cpp
@@ -52,12 +52,35 @@ __forceinline int get_best_dimension(const float4& bestSAH)
/* BVH Object Binning */
-BVHObjectBinning::BVHObjectBinning(const BVHRange& job, BVHReference *prims)
-: BVHRange(job), splitSAH(FLT_MAX), dim(0), pos(0)
+BVHObjectBinning::BVHObjectBinning(const BVHRange& job,
+ BVHReference *prims,
+ const BVHUnaligned *unaligned_heuristic,
+ const Transform *aligned_space)
+: BVHRange(job),
+ splitSAH(FLT_MAX),
+ dim(0),
+ pos(0),
+ unaligned_heuristic_(unaligned_heuristic),
+ aligned_space_(aligned_space)
{
+ if(aligned_space_ == NULL) {
+ bounds_ = bounds();
+ cent_bounds_ = cent_bounds();
+ }
+ else {
+ /* TODO(sergey): With some additional storage we can avoid
+ * need in re-calculating this.
+ */
+ bounds_ = unaligned_heuristic->compute_aligned_boundbox(
+ *this,
+ prims,
+ *aligned_space,
+ &cent_bounds_);
+ }
+
/* compute number of bins to use and precompute scaling factor for binning */
num_bins = min(size_t(MAX_BINS), size_t(4.0f + 0.05f*size()));
- scale = rcp(cent_bounds().size()) * make_float3((float)num_bins);
+ scale = rcp(cent_bounds_.size()) * make_float3((float)num_bins);
/* initialize binning counter and bounds */
BoundBox bin_bounds[MAX_BINS][4]; /* bounds for every bin in every dimension */
@@ -79,30 +102,34 @@ BVHObjectBinning::BVHObjectBinning(const BVHRange& job, BVHReference *prims)
const BVHReference& prim0 = prims[start() + i + 0];
const BVHReference& prim1 = prims[start() + i + 1];
- int4 bin0 = get_bin(prim0.bounds());
- int4 bin1 = get_bin(prim1.bounds());
+ BoundBox bounds0 = get_prim_bounds(prim0);
+ BoundBox bounds1 = get_prim_bounds(prim1);
+
+ int4 bin0 = get_bin(bounds0);
+ int4 bin1 = get_bin(bounds1);
/* increase bounds for bins for even primitive */
- int b00 = (int)extract<0>(bin0); bin_count[b00][0]++; bin_bounds[b00][0].grow(prim0.bounds());
- int b01 = (int)extract<1>(bin0); bin_count[b01][1]++; bin_bounds[b01][1].grow(prim0.bounds());
- int b02 = (int)extract<2>(bin0); bin_count[b02][2]++; bin_bounds[b02][2].grow(prim0.bounds());
+ int b00 = (int)extract<0>(bin0); bin_count[b00][0]++; bin_bounds[b00][0].grow(bounds0);
+ int b01 = (int)extract<1>(bin0); bin_count[b01][1]++; bin_bounds[b01][1].grow(bounds0);
+ int b02 = (int)extract<2>(bin0); bin_count[b02][2]++; bin_bounds[b02][2].grow(bounds0);
/* increase bounds of bins for odd primitive */
- int b10 = (int)extract<0>(bin1); bin_count[b10][0]++; bin_bounds[b10][0].grow(prim1.bounds());
- int b11 = (int)extract<1>(bin1); bin_count[b11][1]++; bin_bounds[b11][1].grow(prim1.bounds());
- int b12 = (int)extract<2>(bin1); bin_count[b12][2]++; bin_bounds[b12][2].grow(prim1.bounds());
+ int b10 = (int)extract<0>(bin1); bin_count[b10][0]++; bin_bounds[b10][0].grow(bounds1);
+ int b11 = (int)extract<1>(bin1); bin_count[b11][1]++; bin_bounds[b11][1].grow(bounds1);
+ int b12 = (int)extract<2>(bin1); bin_count[b12][2]++; bin_bounds[b12][2].grow(bounds1);
}
/* for uneven number of primitives */
if(i < ssize_t(size())) {
/* map primitive to bin */
const BVHReference& prim0 = prims[start() + i];
- int4 bin0 = get_bin(prim0.bounds());
+ BoundBox bounds0 = get_prim_bounds(prim0);
+ int4 bin0 = get_bin(bounds0);
/* increase bounds of bins */
- int b00 = (int)extract<0>(bin0); bin_count[b00][0]++; bin_bounds[b00][0].grow(prim0.bounds());
- int b01 = (int)extract<1>(bin0); bin_count[b01][1]++; bin_bounds[b01][1].grow(prim0.bounds());
- int b02 = (int)extract<2>(bin0); bin_count[b02][2]++; bin_bounds[b02][2].grow(prim0.bounds());
+ int b00 = (int)extract<0>(bin0); bin_count[b00][0]++; bin_bounds[b00][0].grow(bounds0);
+ int b01 = (int)extract<1>(bin0); bin_count[b01][1]++; bin_bounds[b01][1].grow(bounds0);
+ int b02 = (int)extract<2>(bin0); bin_count[b02][2]++; bin_bounds[b02][2].grow(bounds0);
}
}
@@ -151,17 +178,19 @@ BVHObjectBinning::BVHObjectBinning(const BVHRange& job, BVHReference *prims)
bestSAH = min(sah,bestSAH);
}
- int4 mask = float3_to_float4(cent_bounds().size()) <= make_float4(0.0f);
+ int4 mask = float3_to_float4(cent_bounds_.size()) <= make_float4(0.0f);
bestSAH = insert<3>(select(mask, make_float4(FLT_MAX), bestSAH), FLT_MAX);
/* find best dimension */
dim = get_best_dimension(bestSAH);
splitSAH = bestSAH[dim];
pos = bestSplit[dim];
- leafSAH = bounds().half_area() * blocks(size());
+ leafSAH = bounds_.half_area() * blocks(size());
}
-void BVHObjectBinning::split(BVHReference* prims, BVHObjectBinning& left_o, BVHObjectBinning& right_o) const
+void BVHObjectBinning::split(BVHReference* prims,
+ BVHObjectBinning& left_o,
+ BVHObjectBinning& right_o) const
{
size_t N = size();
@@ -176,10 +205,12 @@ void BVHObjectBinning::split(BVHReference* prims, BVHObjectBinning& left_o, BVHO
prefetch_L2(&prims[start() + l + 8]);
prefetch_L2(&prims[start() + r - 8]);
- const BVHReference& prim = prims[start() + l];
+ BVHReference prim = prims[start() + l];
+ BoundBox unaligned_bounds = get_prim_bounds(prim);
+ float3 unaligned_center = unaligned_bounds.center2();
float3 center = prim.bounds().center2();
- if(get_bin(center)[dim] < pos) {
+ if(get_bin(unaligned_center)[dim] < pos) {
lgeom_bounds.grow(prim.bounds());
lcent_bounds.grow(center);
l++;
@@ -191,7 +222,6 @@ void BVHObjectBinning::split(BVHReference* prims, BVHObjectBinning& left_o, BVHO
r--;
}
}
-
/* finish */
if(l != 0 && N-1-r != 0) {
right_o = BVHObjectBinning(BVHRange(rgeom_bounds, rcent_bounds, start() + l, N-1-r), prims);
diff --git a/intern/cycles/bvh/bvh_binning.h b/intern/cycles/bvh/bvh_binning.h
index 60742157055..52955f70151 100644
--- a/intern/cycles/bvh/bvh_binning.h
+++ b/intern/cycles/bvh/bvh_binning.h
@@ -19,11 +19,14 @@
#define __BVH_BINNING_H__
#include "bvh_params.h"
+#include "bvh_unaligned.h"
#include "util_types.h"
CCL_NAMESPACE_BEGIN
+class BVHBuild;
+
/* Single threaded object binner. Finds the split with the best SAH heuristic
* by testing for each dimension multiple partitionings for regular spaced
* partition locations. A partitioning for a partition location is computed,
@@ -34,10 +37,18 @@ CCL_NAMESPACE_BEGIN
class BVHObjectBinning : public BVHRange
{
public:
- __forceinline BVHObjectBinning() {}
- BVHObjectBinning(const BVHRange& job, BVHReference *prims);
+ __forceinline BVHObjectBinning() : leafSAH(FLT_MAX) {}
+
+ BVHObjectBinning(const BVHRange& job,
+ BVHReference *prims,
+ const BVHUnaligned *unaligned_heuristic = NULL,
+ const Transform *aligned_space = NULL);
- void split(BVHReference *prims, BVHObjectBinning& left_o, BVHObjectBinning& right_o) const;
+ void split(BVHReference *prims,
+ BVHObjectBinning& left_o,
+ BVHObjectBinning& right_o) const;
+
+ __forceinline const BoundBox& unaligned_bounds() { return bounds_; }
float splitSAH; /* SAH cost of the best split */
float leafSAH; /* SAH cost of creating a leaf */
@@ -48,13 +59,20 @@ protected:
size_t num_bins; /* actual number of bins to use */
float3 scale; /* scaling factor to compute bin */
+ /* Effective bounds and centroid bounds. */
+ BoundBox bounds_;
+ BoundBox cent_bounds_;
+
+ const BVHUnaligned *unaligned_heuristic_;
+ const Transform *aligned_space_;
+
enum { MAX_BINS = 32 };
enum { LOG_BLOCK_SIZE = 2 };
/* computes the bin numbers for each dimension for a box. */
__forceinline int4 get_bin(const BoundBox& box) const
{
- int4 a = make_int4((box.center2() - cent_bounds().min)*scale - make_float3(0.5f));
+ int4 a = make_int4((box.center2() - cent_bounds_.min)*scale - make_float3(0.5f));
int4 mn = make_int4(0);
int4 mx = make_int4((int)num_bins-1);
@@ -64,7 +82,7 @@ protected:
/* computes the bin numbers for each dimension for a point. */
__forceinline int4 get_bin(const float3& c) const
{
- return make_int4((c - cent_bounds().min)*scale - make_float3(0.5f));
+ return make_int4((c - cent_bounds_.min)*scale - make_float3(0.5f));
}
/* compute the number of blocks occupied for each dimension. */
@@ -78,6 +96,17 @@ protected:
{
return (int)((a+((1LL << LOG_BLOCK_SIZE)-1)) >> LOG_BLOCK_SIZE);
}
+
+ __forceinline BoundBox get_prim_bounds(const BVHReference& prim) const
+ {
+ if(aligned_space_ == NULL) {
+ return prim.bounds();
+ }
+ else {
+ return unaligned_heuristic_->compute_aligned_prim_boundbox(
+ prim, *aligned_space_);
+ }
+ }
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp
index 63edbc9998f..14f66aca70f 100644
--- a/intern/cycles/bvh/bvh_build.cpp
+++ b/intern/cycles/bvh/bvh_build.cpp
@@ -33,6 +33,7 @@
#include "util_stack_allocator.h"
#include "util_simd.h"
#include "util_time.h"
+#include "util_queue.h"
CCL_NAMESPACE_BEGIN
@@ -99,7 +100,8 @@ BVHBuild::BVHBuild(const vector<Object*>& objects_,
prim_object(prim_object_),
params(params_),
progress(progress_),
- progress_start_time(0.0)
+ progress_start_time(0.0),
+ unaligned_heuristic(objects_)
{
spatial_min_overlap = 0.0f;
}
@@ -112,68 +114,74 @@ BVHBuild::~BVHBuild()
void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, int i)
{
- Attribute *attr_mP = NULL;
-
- if(mesh->has_motion_blur())
- attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if(params.primitive_mask & PRIMITIVE_ALL_TRIANGLE) {
+ Attribute *attr_mP = NULL;
- for(uint j = 0; j < mesh->triangles.size(); j++) {
- Mesh::Triangle t = mesh->triangles[j];
- BoundBox bounds = BoundBox::empty;
- PrimitiveType type = PRIMITIVE_TRIANGLE;
+ if(mesh->has_motion_blur())
+ attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+
+ size_t num_triangles = mesh->num_triangles();
+ for(uint j = 0; j < num_triangles; j++) {
+ Mesh::Triangle t = mesh->get_triangle(j);
+ BoundBox bounds = BoundBox::empty;
+ PrimitiveType type = PRIMITIVE_TRIANGLE;
- t.bounds_grow(&mesh->verts[0], bounds);
+ t.bounds_grow(&mesh->verts[0], bounds);
- /* motion triangles */
- if(attr_mP) {
- size_t mesh_size = mesh->verts.size();
- size_t steps = mesh->motion_steps - 1;
- float3 *vert_steps = attr_mP->data_float3();
+ /* motion triangles */
+ if(attr_mP) {
+ size_t mesh_size = mesh->verts.size();
+ size_t steps = mesh->motion_steps - 1;
+ float3 *vert_steps = attr_mP->data_float3();
- for(size_t i = 0; i < steps; i++)
- t.bounds_grow(vert_steps + i*mesh_size, bounds);
+ for(size_t i = 0; i < steps; i++)
+ t.bounds_grow(vert_steps + i*mesh_size, bounds);
- type = PRIMITIVE_MOTION_TRIANGLE;
- }
+ type = PRIMITIVE_MOTION_TRIANGLE;
+ }
- if(bounds.valid()) {
- references.push_back(BVHReference(bounds, j, i, type));
- root.grow(bounds);
- center.grow(bounds.center2());
+ if(bounds.valid()) {
+ references.push_back(BVHReference(bounds, j, i, type));
+ root.grow(bounds);
+ center.grow(bounds.center2());
+ }
}
}
- Attribute *curve_attr_mP = NULL;
+ if(params.primitive_mask & PRIMITIVE_ALL_CURVE) {
+ Attribute *curve_attr_mP = NULL;
- if(mesh->has_motion_blur())
- curve_attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if(mesh->has_motion_blur())
+ curve_attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- for(uint j = 0; j < mesh->curves.size(); j++) {
- Mesh::Curve curve = mesh->curves[j];
- PrimitiveType type = PRIMITIVE_CURVE;
+ size_t num_curves = mesh->num_curves();
+ for(uint j = 0; j < num_curves; j++) {
+ Mesh::Curve curve = mesh->get_curve(j);
+ PrimitiveType type = PRIMITIVE_CURVE;
- for(int k = 0; k < curve.num_keys - 1; k++) {
- BoundBox bounds = BoundBox::empty;
- curve.bounds_grow(k, &mesh->curve_keys[0], bounds);
+ for(int k = 0; k < curve.num_keys - 1; k++) {
+ BoundBox bounds = BoundBox::empty;
+ curve.bounds_grow(k, &mesh->curve_keys[0], &mesh->curve_radius[0], bounds);
- /* motion curve */
- if(curve_attr_mP) {
- size_t mesh_size = mesh->curve_keys.size();
- size_t steps = mesh->motion_steps - 1;
- float4 *key_steps = curve_attr_mP->data_float4();
+ /* motion curve */
+ if(curve_attr_mP) {
+ size_t mesh_size = mesh->curve_keys.size();
+ size_t steps = mesh->motion_steps - 1;
+ float3 *key_steps = curve_attr_mP->data_float3();
- for(size_t i = 0; i < steps; i++)
- curve.bounds_grow(k, key_steps + i*mesh_size, bounds);
+ for(size_t i = 0; i < steps; i++)
+ curve.bounds_grow(k, key_steps + i*mesh_size, &mesh->curve_radius[0], bounds);
- type = PRIMITIVE_MOTION_CURVE;
- }
+ type = PRIMITIVE_MOTION_CURVE;
+ }
- if(bounds.valid()) {
- int packed_type = PRIMITIVE_PACK_SEGMENT(type, k);
-
- references.push_back(BVHReference(bounds, j, i, packed_type));
- root.grow(bounds);
- center.grow(bounds.center2());
+ if(bounds.valid()) {
+ int packed_type = PRIMITIVE_PACK_SEGMENT(type, k);
+
+ references.push_back(BVHReference(bounds, j, i, packed_type));
+ root.grow(bounds);
+ center.grow(bounds.center2());
+ }
}
}
}
@@ -188,10 +196,10 @@ void BVHBuild::add_reference_object(BoundBox& root, BoundBox& center, Object *ob
static size_t count_curve_segments(Mesh *mesh)
{
- size_t num = 0, num_curves = mesh->curves.size();
+ size_t num = 0, num_curves = mesh->num_curves();
for(size_t i = 0; i < num_curves; i++)
- num += mesh->curves[i].num_keys - 1;
+ num += mesh->get_curve(i).num_keys - 1;
return num;
}
@@ -203,16 +211,27 @@ void BVHBuild::add_references(BVHRange& root)
foreach(Object *ob, objects) {
if(params.top_level) {
+ if(!ob->is_traceable()) {
+ continue;
+ }
if(!ob->mesh->is_instanced()) {
- num_alloc_references += ob->mesh->triangles.size();
- num_alloc_references += count_curve_segments(ob->mesh);
+ if(params.primitive_mask & PRIMITIVE_ALL_TRIANGLE) {
+ num_alloc_references += ob->mesh->num_triangles();
+ }
+ if(params.primitive_mask & PRIMITIVE_ALL_CURVE) {
+ num_alloc_references += count_curve_segments(ob->mesh);
+ }
}
else
num_alloc_references++;
}
else {
- num_alloc_references += ob->mesh->triangles.size();
- num_alloc_references += count_curve_segments(ob->mesh);
+ if(params.primitive_mask & PRIMITIVE_ALL_TRIANGLE) {
+ num_alloc_references += ob->mesh->num_triangles();
+ }
+ if(params.primitive_mask & PRIMITIVE_ALL_CURVE) {
+ num_alloc_references += count_curve_segments(ob->mesh);
+ }
}
}
@@ -224,6 +243,10 @@ void BVHBuild::add_references(BVHRange& root)
foreach(Object *ob, objects) {
if(params.top_level) {
+ if(!ob->is_traceable()) {
+ ++i;
+ continue;
+ }
if(!ob->mesh->is_instanced())
add_reference_mesh(bounds, center, ob->mesh, i);
else
@@ -326,11 +349,13 @@ BVHNode* BVHBuild::run()
VLOG(1) << "BVH build statistics:\n"
<< " Build time: " << time_dt() - build_start_time << "\n"
<< " Total number of nodes: "
- << rootnode->getSubtreeSize(BVH_STAT_NODE_COUNT) << "\n"
+ << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_NODE_COUNT)) << "\n"
<< " Number of inner nodes: "
- << rootnode->getSubtreeSize(BVH_STAT_INNER_COUNT) << "\n"
+ << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_INNER_COUNT)) << "\n"
<< " Number of leaf nodes: "
- << rootnode->getSubtreeSize(BVH_STAT_LEAF_COUNT) << "\n"
+ << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_LEAF_COUNT)) << "\n"
+ << " Number of unaligned nodes: "
+ << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_UNALIGNED_COUNT)) << "\n"
<< " Allocation slop factor: "
<< ((prim_type.capacity() != 0)
? (float)prim_type.size() / prim_type.capacity()
@@ -436,10 +461,11 @@ BVHNode* BVHBuild::build_node(const BVHObjectBinning& range, int level)
float leafSAH = params.sah_primitive_cost * range.leafSAH;
float splitSAH = params.sah_node_cost * range.bounds().half_area() + params.sah_primitive_cost * range.splitSAH;
- /* have at least one inner node on top level, for performance and correct
- * visibility tests, since object instances do not check visibility flag */
+ /* Have at least one inner node on top level, for performance and correct
+ * visibility tests, since object instances do not check visibility flag.
+ */
if(!(range.size() > 0 && params.top_level && level == 0)) {
- /* make leaf node when threshold reached or SAH tells us */
+ /* Make leaf node when threshold reached or SAH tells us. */
if((params.small_enough_for_leaf(size, level)) ||
(range_within_max_leaf_size(range, references) && leafSAH < splitSAH))
{
@@ -447,28 +473,75 @@ BVHNode* BVHBuild::build_node(const BVHObjectBinning& range, int level)
}
}
- /* perform split */
+ BVHObjectBinning unaligned_range;
+ float unalignedSplitSAH = FLT_MAX;
+ float unalignedLeafSAH = FLT_MAX;
+ Transform aligned_space;
+ bool do_unalinged_split = false;
+ if(params.use_unaligned_nodes &&
+ splitSAH > params.unaligned_split_threshold*leafSAH)
+ {
+ aligned_space = unaligned_heuristic.compute_aligned_space(
+ range, &references[0]);
+ unaligned_range = BVHObjectBinning(range,
+ &references[0],
+ &unaligned_heuristic,
+ &aligned_space);
+ unalignedSplitSAH = params.sah_node_cost * unaligned_range.unaligned_bounds().half_area() +
+ params.sah_primitive_cost * unaligned_range.splitSAH;
+ unalignedLeafSAH = params.sah_primitive_cost * unaligned_range.leafSAH;
+ if(!(range.size() > 0 && params.top_level && level == 0)) {
+ if(unalignedLeafSAH < unalignedSplitSAH && unalignedSplitSAH < splitSAH &&
+ range_within_max_leaf_size(range, references))
+ {
+ return create_leaf_node(range, references);
+ }
+ }
+ /* Check whether unaligned split is better than the regulat one. */
+ if(unalignedSplitSAH < splitSAH) {
+ do_unalinged_split = true;
+ }
+ }
+
+ /* Perform split. */
BVHObjectBinning left, right;
- range.split(&references[0], left, right);
+ if(do_unalinged_split) {
+ unaligned_range.split(&references[0], left, right);
+ }
+ else {
+ range.split(&references[0], left, right);
+ }
- /* create inner node. */
- InnerNode *inner;
+ BoundBox bounds;
+ if(do_unalinged_split) {
+ bounds = unaligned_heuristic.compute_aligned_boundbox(
+ range, &references[0], aligned_space);
+ }
+ else {
+ bounds = range.bounds();
+ }
+ /* Create inner node. */
+ InnerNode *inner;
if(range.size() < THREAD_TASK_SIZE) {
/* local build */
BVHNode *leftnode = build_node(left, level + 1);
BVHNode *rightnode = build_node(right, level + 1);
- inner = new InnerNode(range.bounds(), leftnode, rightnode);
+ inner = new InnerNode(bounds, leftnode, rightnode);
}
else {
- /* threaded build */
- inner = new InnerNode(range.bounds());
+ /* Threaded build */
+ inner = new InnerNode(bounds);
task_pool.push(new BVHBuildTask(this, inner, 0, left, level + 1), true);
task_pool.push(new BVHBuildTask(this, inner, 1, right, level + 1), true);
}
+ if(do_unalinged_split) {
+ inner->set_aligned_space(aligned_space);
+ }
+
return inner;
}
@@ -507,16 +580,59 @@ BVHNode* BVHBuild::build_node(const BVHRange& range,
return create_leaf_node(range, *references);
}
}
+ float leafSAH = params.sah_primitive_cost * split.leafSAH;
+ float splitSAH = params.sah_node_cost * range.bounds().half_area() +
+ params.sah_primitive_cost * split.nodeSAH;
+
+ BVHMixedSplit unaligned_split;
+ float unalignedSplitSAH = FLT_MAX;
+ /* float unalignedLeafSAH = FLT_MAX; */
+ Transform aligned_space;
+ bool do_unalinged_split = false;
+ if(params.use_unaligned_nodes &&
+ splitSAH > params.unaligned_split_threshold*leafSAH)
+ {
+ aligned_space =
+ unaligned_heuristic.compute_aligned_space(range, &references->at(0));
+ unaligned_split = BVHMixedSplit(this,
+ storage,
+ range,
+ references,
+ level,
+ &unaligned_heuristic,
+ &aligned_space);
+ /* unalignedLeafSAH = params.sah_primitive_cost * split.leafSAH; */
+ unalignedSplitSAH = params.sah_node_cost * unaligned_split.bounds.half_area() +
+ params.sah_primitive_cost * unaligned_split.nodeSAH;
+ /* TOOD(sergey): Check we can create leaf already. */
+ /* Check whether unaligned split is better than the regulat one. */
+ if(unalignedSplitSAH < splitSAH) {
+ do_unalinged_split = true;
+ }
+ }
/* Do split. */
BVHRange left, right;
- split.split(this, left, right, range);
+ if(do_unalinged_split) {
+ unaligned_split.split(this, left, right, range);
+ }
+ else {
+ split.split(this, left, right, range);
+ }
progress_total += left.size() + right.size() - range.size();
+ BoundBox bounds;
+ if(do_unalinged_split) {
+ bounds = unaligned_heuristic.compute_aligned_boundbox(
+ range, &references->at(0), aligned_space);
+ }
+ else {
+ bounds = range.bounds();
+ }
+
/* Create inner node. */
InnerNode *inner;
-
if(range.size() < THREAD_TASK_SIZE) {
/* Local build. */
@@ -530,11 +646,11 @@ BVHNode* BVHBuild::build_node(const BVHRange& range,
/* Build right node. */
BVHNode *rightnode = build_node(right, &copy, level + 1, thread_id);
- inner = new InnerNode(range.bounds(), leftnode, rightnode);
+ inner = new InnerNode(bounds, leftnode, rightnode);
}
else {
/* Threaded build. */
- inner = new InnerNode(range.bounds());
+ inner = new InnerNode(bounds);
task_pool.push(new BVHSpatialSplitBuildTask(this,
inner,
0,
@@ -551,6 +667,10 @@ BVHNode* BVHBuild::build_node(const BVHRange& range,
true);
}
+ if(do_unalinged_split) {
+ inner->set_aligned_space(aligned_space);
+ }
+
return inner;
}
@@ -603,12 +723,15 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range,
* can not control.
*/
typedef StackAllocator<256, int> LeafStackAllocator;
+ typedef StackAllocator<256, BVHReference> LeafReferenceStackAllocator;
vector<int, LeafStackAllocator> p_type[PRIMITIVE_NUM_TOTAL];
vector<int, LeafStackAllocator> p_index[PRIMITIVE_NUM_TOTAL];
vector<int, LeafStackAllocator> p_object[PRIMITIVE_NUM_TOTAL];
+ vector<BVHReference, LeafReferenceStackAllocator> p_ref[PRIMITIVE_NUM_TOTAL];
+
/* TODO(sergey): In theory we should be able to store references. */
- vector<BVHReference, LeafStackAllocator> object_references;
+ vector<BVHReference, LeafReferenceStackAllocator> object_references;
uint visibility[PRIMITIVE_NUM_TOTAL] = {0};
/* NOTE: Keep initializtion in sync with actual number of primitives. */
@@ -623,13 +746,14 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range,
const BVHReference& ref = references[range.start() + i];
if(ref.prim_index() != -1) {
int type_index = bitscan(ref.prim_type() & PRIMITIVE_ALL);
+ p_ref[type_index].push_back(ref);
p_type[type_index].push_back(ref.prim_type());
p_index[type_index].push_back(ref.prim_index());
p_object[type_index].push_back(ref.prim_object());
bounds[type_index].grow(ref.bounds());
visibility[type_index] |= objects[ref.prim_object()]->visibility;
- if (ref.prim_type() & PRIMITIVE_ALL_CURVE) {
+ if(ref.prim_type() & PRIMITIVE_ALL_CURVE) {
visibility[type_index] |= PATH_RAY_CURVE;
}
++num_new_prims;
@@ -663,16 +787,38 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range,
if(num != 0) {
assert(p_type[i].size() == p_index[i].size());
assert(p_type[i].size() == p_object[i].size());
+ Transform aligned_space;
+ bool alignment_found = false;
for(int j = 0; j < num; ++j) {
const int index = start_index + j;
local_prim_type[index] = p_type[i][j];
local_prim_index[index] = p_index[i][j];
local_prim_object[index] = p_object[i][j];
+ if(params.use_unaligned_nodes && !alignment_found) {
+ alignment_found =
+ unaligned_heuristic.compute_aligned_space(p_ref[i][j],
+ &aligned_space);
+ }
+ }
+ LeafNode *leaf_node = new LeafNode(bounds[i],
+ visibility[i],
+ start_index,
+ start_index + num);
+ if(alignment_found) {
+ /* Need to recalculate leaf bounds with new alignment. */
+ leaf_node->m_bounds = BoundBox::empty;
+ for(int j = 0; j < num; ++j) {
+ const BVHReference &ref = p_ref[i][j];
+ BoundBox ref_bounds =
+ unaligned_heuristic.compute_aligned_prim_boundbox(
+ ref,
+ aligned_space);
+ leaf_node->m_bounds.grow(ref_bounds);
+ }
+ /* Set alignment space. */
+ leaf_node->set_aligned_space(aligned_space);
}
- leaves[num_leaves++] = new LeafNode(bounds[i],
- visibility[i],
- start_index,
- start_index + num);
+ leaves[num_leaves++] = leaf_node;
start_index += num;
}
}
@@ -754,6 +900,9 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range,
++num_leaves;
}
+ /* TODO(sergey): Need to take care of alignment when number of leaves
+ * is more than 1.
+ */
if(num_leaves == 1) {
/* Simplest case: single leaf, just return it.
* In all the rest cases we'll be creating intermediate inner node with
diff --git a/intern/cycles/bvh/bvh_build.h b/intern/cycles/bvh/bvh_build.h
index a015b89d72f..64180349935 100644
--- a/intern/cycles/bvh/bvh_build.h
+++ b/intern/cycles/bvh/bvh_build.h
@@ -22,6 +22,7 @@
#include "bvh.h"
#include "bvh_binning.h"
+#include "bvh_unaligned.h"
#include "util_boundbox.h"
#include "util_task.h"
@@ -59,13 +60,14 @@ protected:
friend class BVHSpatialSplit;
friend class BVHBuildTask;
friend class BVHSpatialSplitBuildTask;
+ friend class BVHObjectBinning;
- /* adding references */
+ /* Adding references. */
void add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, int i);
void add_reference_object(BoundBox& root, BoundBox& center, Object *ob, int i);
void add_references(BVHRange& root);
- /* building */
+ /* Building. */
BVHNode *build_node(const BVHRange& range,
vector<BVHReference> *references,
int level,
@@ -78,7 +80,7 @@ protected:
bool range_within_max_leaf_size(const BVHRange& range,
const vector<BVHReference>& references) const;
- /* threads */
+ /* Threads. */
enum { THREAD_TASK_SIZE = 4096 };
void thread_build_node(InnerNode *node,
int child,
@@ -92,41 +94,44 @@ protected:
int thread_id);
thread_mutex build_mutex;
- /* progress */
+ /* Progress. */
void progress_update();
- /* tree rotations */
+ /* Tree rotations. */
void rotate(BVHNode *node, int max_depth);
void rotate(BVHNode *node, int max_depth, int iterations);
- /* objects and primitive references */
+ /* Objects and primitive references. */
vector<Object*> objects;
vector<BVHReference> references;
int num_original_references;
- /* output primitive indexes and objects */
+ /* Output primitive indexes and objects. */
array<int>& prim_type;
array<int>& prim_index;
array<int>& prim_object;
- /* build parameters */
+ /* Build parameters. */
BVHParams params;
- /* progress reporting */
+ /* Progress reporting. */
Progress& progress;
double progress_start_time;
size_t progress_count;
size_t progress_total;
size_t progress_original_total;
- /* spatial splitting */
+ /* Spatial splitting. */
float spatial_min_overlap;
vector<BVHSpatialStorage> spatial_storage;
size_t spatial_free_index;
thread_spin_lock spatial_spin_lock;
- /* threads */
+ /* Threads. */
TaskPool task_pool;
+
+ /* Unaligned building. */
+ BVHUnaligned unaligned_heuristic;
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh_node.cpp b/intern/cycles/bvh/bvh_node.cpp
index 8294690da7d..f5cd699bdf4 100644
--- a/intern/cycles/bvh/bvh_node.cpp
+++ b/intern/cycles/bvh/bvh_node.cpp
@@ -61,6 +61,76 @@ int BVHNode::getSubtreeSize(BVH_STAT stat) const
}
}
return cnt;
+ case BVH_STAT_ALIGNED_COUNT:
+ if(!is_unaligned()) {
+ cnt = 1;
+ }
+ break;
+ case BVH_STAT_UNALIGNED_COUNT:
+ if(is_unaligned()) {
+ cnt = 1;
+ }
+ break;
+ case BVH_STAT_ALIGNED_INNER_COUNT:
+ if(!is_leaf()) {
+ bool has_unaligned = false;
+ for(int j = 0; j < num_children(); j++) {
+ has_unaligned |= get_child(j)->is_unaligned();
+ }
+ cnt += has_unaligned? 0: 1;
+ }
+ break;
+ case BVH_STAT_UNALIGNED_INNER_COUNT:
+ if(!is_leaf()) {
+ bool has_unaligned = false;
+ for(int j = 0; j < num_children(); j++) {
+ has_unaligned |= get_child(j)->is_unaligned();
+ }
+ cnt += has_unaligned? 1: 0;
+ }
+ break;
+ case BVH_STAT_ALIGNED_INNER_QNODE_COUNT:
+ {
+ bool has_unaligned = false;
+ for(int i = 0; i < num_children(); i++) {
+ BVHNode *node = get_child(i);
+ if(node->is_leaf()) {
+ has_unaligned |= node->is_unaligned();
+ }
+ else {
+ for(int j = 0; j < node->num_children(); j++) {
+ cnt += node->get_child(j)->getSubtreeSize(stat);
+ has_unaligned |= node->get_child(j)->is_unaligned();
+ }
+ }
+ }
+ cnt += has_unaligned? 0: 1;
+ }
+ return cnt;
+ case BVH_STAT_UNALIGNED_INNER_QNODE_COUNT:
+ {
+ bool has_unaligned = false;
+ for(int i = 0; i < num_children(); i++) {
+ BVHNode *node = get_child(i);
+ if(node->is_leaf()) {
+ has_unaligned |= node->is_unaligned();
+ }
+ else {
+ for(int j = 0; j < node->num_children(); j++) {
+ cnt += node->get_child(j)->getSubtreeSize(stat);
+ has_unaligned |= node->get_child(j)->is_unaligned();
+ }
+ }
+ }
+ cnt += has_unaligned? 1: 0;
+ }
+ return cnt;
+ case BVH_STAT_ALIGNED_LEAF_COUNT:
+ cnt = (is_leaf() && !is_unaligned()) ? 1 : 0;
+ break;
+ case BVH_STAT_UNALIGNED_LEAF_COUNT:
+ cnt = (is_leaf() && is_unaligned()) ? 1 : 0;
+ break;
default:
assert(0); /* unknown mode */
}
diff --git a/intern/cycles/bvh/bvh_node.h b/intern/cycles/bvh/bvh_node.h
index 44f5518229b..2faa40ab657 100644
--- a/intern/cycles/bvh/bvh_node.h
+++ b/intern/cycles/bvh/bvh_node.h
@@ -31,6 +31,14 @@ enum BVH_STAT {
BVH_STAT_TRIANGLE_COUNT,
BVH_STAT_CHILDNODE_COUNT,
BVH_STAT_QNODE_COUNT,
+ BVH_STAT_ALIGNED_COUNT,
+ BVH_STAT_UNALIGNED_COUNT,
+ BVH_STAT_ALIGNED_INNER_COUNT,
+ BVH_STAT_UNALIGNED_INNER_COUNT,
+ BVH_STAT_ALIGNED_INNER_QNODE_COUNT,
+ BVH_STAT_UNALIGNED_INNER_QNODE_COUNT,
+ BVH_STAT_ALIGNED_LEAF_COUNT,
+ BVH_STAT_UNALIGNED_LEAF_COUNT,
};
class BVHParams;
@@ -38,16 +46,41 @@ class BVHParams;
class BVHNode
{
public:
- BVHNode()
+ BVHNode() : m_is_unaligned(false),
+ m_aligned_space(NULL)
{
}
- virtual ~BVHNode() {}
+ virtual ~BVHNode()
+ {
+ delete m_aligned_space;
+ }
+
virtual bool is_leaf() const = 0;
virtual int num_children() const = 0;
virtual BVHNode *get_child(int i) const = 0;
virtual int num_triangles() const { return 0; }
virtual void print(int depth = 0) const = 0;
+ bool is_unaligned() const { return m_is_unaligned; }
+
+ inline void set_aligned_space(const Transform& aligned_space)
+ {
+ m_is_unaligned = true;
+ if(m_aligned_space == NULL) {
+ m_aligned_space = new Transform(aligned_space);
+ }
+ else {
+ *m_aligned_space = aligned_space;
+ }
+ }
+
+ inline Transform get_aligned_space() const
+ {
+ if(m_aligned_space == NULL) {
+ return transform_identity();
+ }
+ return *m_aligned_space;
+ }
BoundBox m_bounds;
uint m_visibility;
@@ -58,12 +91,20 @@ public:
void deleteSubtree();
uint update_visibility();
+
+ bool m_is_unaligned;
+
+ // TODO(sergey): Can be stored as 3x3 matrix, but better to have some
+ // utilities and type defines in util_transform first.
+ Transform *m_aligned_space;
};
class InnerNode : public BVHNode
{
public:
- InnerNode(const BoundBox& bounds, BVHNode* child0, BVHNode* child1)
+ InnerNode(const BoundBox& bounds,
+ BVHNode* child0,
+ BVHNode* child1)
{
m_bounds = bounds;
children[0] = child0;
@@ -75,7 +116,7 @@ public:
m_visibility = 0; /* happens on build cancel */
}
- InnerNode(const BoundBox& bounds)
+ explicit InnerNode(const BoundBox& bounds)
{
m_bounds = bounds;
m_visibility = 0;
diff --git a/intern/cycles/bvh/bvh_params.h b/intern/cycles/bvh/bvh_params.h
index cf683df1b31..2e698a80742 100644
--- a/intern/cycles/bvh/bvh_params.h
+++ b/intern/cycles/bvh/bvh_params.h
@@ -20,6 +20,8 @@
#include "util_boundbox.h"
+#include "kernel_types.h"
+
CCL_NAMESPACE_BEGIN
/* BVH Parameters */
@@ -31,6 +33,9 @@ public:
bool use_spatial_split;
float spatial_split_alpha;
+ /* Unaligned nodes creation threshold */
+ float unaligned_split_threshold;
+
/* SAH costs */
float sah_node_cost;
float sah_primitive_cost;
@@ -46,6 +51,14 @@ public:
/* QBVH */
bool use_qbvh;
+ /* Mask of primitives to be included into the BVH. */
+ int primitive_mask;
+
+ /* Use unaligned bounding boxes.
+ * Only used for curves BVH.
+ */
+ bool use_unaligned_nodes;
+
/* fixed parameters */
enum {
MAX_DEPTH = 64,
@@ -58,6 +71,8 @@ public:
use_spatial_split = true;
spatial_split_alpha = 1e-5f;
+ unaligned_split_threshold = 0.7f;
+
/* todo: see if splitting up primitive cost to be separate for triangles
* and curves can help. so far in tests it doesn't help, but why? */
sah_node_cost = 1.0f;
@@ -69,6 +84,9 @@ public:
top_level = false;
use_qbvh = false;
+ use_unaligned_nodes = false;
+
+ primitive_mask = PRIMITIVE_ALL;
}
/* SAH costs */
diff --git a/intern/cycles/bvh/bvh_sort.cpp b/intern/cycles/bvh/bvh_sort.cpp
index c12751979cd..e5bcf9995bf 100644
--- a/intern/cycles/bvh/bvh_sort.cpp
+++ b/intern/cycles/bvh/bvh_sort.cpp
@@ -26,23 +26,27 @@ CCL_NAMESPACE_BEGIN
static const int BVH_SORT_THRESHOLD = 4096;
-/* Silly workaround for float extended precision that happens when compiling
- * on x86, due to one float staying in 80 bit precision register and the other
- * not, which causes the strictly weak ordering to break.
- */
-#if !defined(__i386__)
-# define NO_EXTENDED_PRECISION
-#else
-# define NO_EXTENDED_PRECISION volatile
-#endif
-
struct BVHReferenceCompare {
public:
int dim;
+ const BVHUnaligned *unaligned_heuristic;
+ const Transform *aligned_space;
+
+ BVHReferenceCompare(int dim,
+ const BVHUnaligned *unaligned_heuristic,
+ const Transform *aligned_space)
+ : dim(dim),
+ unaligned_heuristic(unaligned_heuristic),
+ aligned_space(aligned_space)
+ {
+ }
- BVHReferenceCompare(int dim_)
+ __forceinline BoundBox get_prim_bounds(const BVHReference& prim) const
{
- dim = dim_;
+ return (aligned_space != NULL)
+ ? unaligned_heuristic->compute_aligned_prim_boundbox(
+ prim, *aligned_space)
+ : prim.bounds();
}
/* Compare two references.
@@ -52,8 +56,10 @@ public:
__forceinline int compare(const BVHReference& ra,
const BVHReference& rb) const
{
- NO_EXTENDED_PRECISION float ca = ra.bounds().min[dim] + ra.bounds().max[dim];
- NO_EXTENDED_PRECISION float cb = rb.bounds().min[dim] + rb.bounds().max[dim];
+ BoundBox ra_bounds = get_prim_bounds(ra),
+ rb_bounds = get_prim_bounds(rb);
+ float ca = ra_bounds.min[dim] + ra_bounds.max[dim];
+ float cb = rb_bounds.min[dim] + rb_bounds.max[dim];
if(ca < cb) return -1;
else if(ca > cb) return 1;
@@ -125,7 +131,7 @@ static void bvh_reference_sort_threaded(TaskPool *task_pool,
if(compare.compare(data[left], data[right]) > 0) {
swap(data[left], data[right]);
}
- if (compare.compare(data[center], data[right]) > 0) {
+ if(compare.compare(data[center], data[right]) > 0) {
swap(data[center], data[right]);
}
swap(data[center], data[right - 1]);
@@ -171,10 +177,15 @@ static void bvh_reference_sort_threaded(TaskPool *task_pool,
}
}
-void bvh_reference_sort(int start, int end, BVHReference *data, int dim)
+void bvh_reference_sort(int start,
+ int end,
+ BVHReference *data,
+ int dim,
+ const BVHUnaligned *unaligned_heuristic,
+ const Transform *aligned_space)
{
const int count = end - start;
- BVHReferenceCompare compare(dim);
+ BVHReferenceCompare compare(dim, unaligned_heuristic, aligned_space);
if(count < BVH_SORT_THRESHOLD) {
/* It is important to not use any mutex if array is small enough,
* otherwise we end up in situation when we're going to sleep far
@@ -184,7 +195,7 @@ void bvh_reference_sort(int start, int end, BVHReference *data, int dim)
}
else {
TaskPool task_pool;
- bvh_reference_sort_threaded(&task_pool, data, start, end - 1, dim);
+ bvh_reference_sort_threaded(&task_pool, data, start, end - 1, compare);
task_pool.wait_work();
}
}
diff --git a/intern/cycles/bvh/bvh_sort.h b/intern/cycles/bvh/bvh_sort.h
index 18aafb5f1ff..b49ca02eb60 100644
--- a/intern/cycles/bvh/bvh_sort.h
+++ b/intern/cycles/bvh/bvh_sort.h
@@ -20,7 +20,15 @@
CCL_NAMESPACE_BEGIN
-void bvh_reference_sort(int start, int end, BVHReference *data, int dim);
+class BVHUnaligned;
+struct Transform;
+
+void bvh_reference_sort(int start,
+ int end,
+ BVHReference *data,
+ int dim,
+ const BVHUnaligned *unaligned_heuristic = NULL,
+ const Transform *aligned_space = NULL);
CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh_split.cpp b/intern/cycles/bvh/bvh_split.cpp
index 8084975565e..d0d5fbe5a7a 100644
--- a/intern/cycles/bvh/bvh_split.cpp
+++ b/intern/cycles/bvh/bvh_split.cpp
@@ -32,14 +32,18 @@ BVHObjectSplit::BVHObjectSplit(BVHBuild *builder,
BVHSpatialStorage *storage,
const BVHRange& range,
vector<BVHReference> *references,
- float nodeSAH)
+ float nodeSAH,
+ const BVHUnaligned *unaligned_heuristic,
+ const Transform *aligned_space)
: sah(FLT_MAX),
dim(0),
num_left(0),
left_bounds(BoundBox::empty),
right_bounds(BoundBox::empty),
storage_(storage),
- references_(references)
+ references_(references),
+ unaligned_heuristic_(unaligned_heuristic),
+ aligned_space_(aligned_space)
{
const BVHReference *ref_ptr = &references_->at(range.start());
float min_sah = FLT_MAX;
@@ -51,12 +55,15 @@ BVHObjectSplit::BVHObjectSplit(BVHBuild *builder,
bvh_reference_sort(range.start(),
range.end(),
&references_->at(0),
- dim);
+ dim,
+ unaligned_heuristic_,
+ aligned_space_);
/* sweep right to left and determine bounds. */
BoundBox right_bounds = BoundBox::empty;
for(int i = range.size() - 1; i > 0; i--) {
- right_bounds.grow(ref_ptr[i].bounds());
+ BoundBox prim_bounds = get_prim_bounds(ref_ptr[i]);
+ right_bounds.grow(prim_bounds);
storage_->right_bounds[i - 1] = right_bounds;
}
@@ -64,7 +71,8 @@ BVHObjectSplit::BVHObjectSplit(BVHBuild *builder,
BoundBox left_bounds = BoundBox::empty;
for(int i = 1; i < range.size(); i++) {
- left_bounds.grow(ref_ptr[i - 1].bounds());
+ BoundBox prim_bounds = get_prim_bounds(ref_ptr[i - 1]);
+ left_bounds.grow(prim_bounds);
right_bounds = storage_->right_bounds[i - 1];
float sah = nodeSAH +
@@ -88,16 +96,37 @@ void BVHObjectSplit::split(BVHRange& left,
BVHRange& right,
const BVHRange& range)
{
+ assert(references_->size() > 0);
/* sort references according to split */
bvh_reference_sort(range.start(),
range.end(),
&references_->at(0),
- this->dim);
+ this->dim,
+ unaligned_heuristic_,
+ aligned_space_);
+
+ BoundBox effective_left_bounds, effective_right_bounds;
+ const int num_right = range.size() - this->num_left;
+ if(aligned_space_ == NULL) {
+ effective_left_bounds = left_bounds;
+ effective_right_bounds = right_bounds;
+ }
+ else {
+ effective_left_bounds = BoundBox::empty;
+ effective_right_bounds = BoundBox::empty;
+ for(int i = 0; i < this->num_left; ++i) {
+ BoundBox prim_boundbox = references_->at(range.start() + i).bounds();
+ effective_left_bounds.grow(prim_boundbox);
+ }
+ for(int i = 0; i < num_right; ++i) {
+ BoundBox prim_boundbox = references_->at(range.start() + this->num_left + i).bounds();
+ effective_right_bounds.grow(prim_boundbox);
+ }
+ }
/* split node ranges */
- left = BVHRange(this->left_bounds, range.start(), this->num_left);
- right = BVHRange(this->right_bounds, left.end(), range.size() - this->num_left);
-
+ left = BVHRange(effective_left_bounds, range.start(), this->num_left);
+ right = BVHRange(effective_right_bounds, left.end(), num_right);
}
/* Spatial Split */
@@ -106,16 +135,31 @@ BVHSpatialSplit::BVHSpatialSplit(const BVHBuild& builder,
BVHSpatialStorage *storage,
const BVHRange& range,
vector<BVHReference> *references,
- float nodeSAH)
+ float nodeSAH,
+ const BVHUnaligned *unaligned_heuristic,
+ const Transform *aligned_space)
: sah(FLT_MAX),
dim(0),
pos(0.0f),
storage_(storage),
- references_(references)
+ references_(references),
+ unaligned_heuristic_(unaligned_heuristic),
+ aligned_space_(aligned_space)
{
/* initialize bins. */
- float3 origin = range.bounds().min;
- float3 binSize = (range.bounds().max - origin) * (1.0f / (float)BVHParams::NUM_SPATIAL_BINS);
+ BoundBox range_bounds;
+ if(aligned_space == NULL) {
+ range_bounds = range.bounds();
+ }
+ else {
+ range_bounds = unaligned_heuristic->compute_aligned_boundbox(
+ range,
+ &references->at(0),
+ *aligned_space);
+ }
+
+ float3 origin = range_bounds.min;
+ float3 binSize = (range_bounds.max - origin) * (1.0f / (float)BVHParams::NUM_SPATIAL_BINS);
float3 invBinSize = 1.0f / binSize;
for(int dim = 0; dim < 3; dim++) {
@@ -131,8 +175,9 @@ BVHSpatialSplit::BVHSpatialSplit(const BVHBuild& builder,
/* chop references into bins. */
for(unsigned int refIdx = range.start(); refIdx < range.end(); refIdx++) {
const BVHReference& ref = references_->at(refIdx);
- float3 firstBinf = (ref.bounds().min - origin) * invBinSize;
- float3 lastBinf = (ref.bounds().max - origin) * invBinSize;
+ BoundBox prim_bounds = get_prim_bounds(ref);
+ float3 firstBinf = (prim_bounds.min - origin) * invBinSize;
+ float3 lastBinf = (prim_bounds.max - origin) * invBinSize;
int3 firstBin = make_int3((int)firstBinf.x, (int)firstBinf.y, (int)firstBinf.z);
int3 lastBin = make_int3((int)lastBinf.x, (int)lastBinf.y, (int)lastBinf.z);
@@ -140,7 +185,10 @@ BVHSpatialSplit::BVHSpatialSplit(const BVHBuild& builder,
lastBin = clamp(lastBin, firstBin, BVHParams::NUM_SPATIAL_BINS - 1);
for(int dim = 0; dim < 3; dim++) {
- BVHReference currRef = ref;
+ BVHReference currRef(get_prim_bounds(ref),
+ ref.prim_index(),
+ ref.prim_object(),
+ ref.prim_type());
for(int i = firstBin[dim]; i < lastBin[dim]; i++) {
BVHReference leftRef, rightRef;
@@ -209,14 +257,15 @@ void BVHSpatialSplit::split(BVHBuild *builder,
BoundBox right_bounds = BoundBox::empty;
for(int i = left_end; i < right_start; i++) {
- if(refs[i].bounds().max[this->dim] <= this->pos) {
+ BoundBox prim_bounds = get_prim_bounds(refs[i]);
+ if(prim_bounds.max[this->dim] <= this->pos) {
/* entirely on the left-hand side */
- left_bounds.grow(refs[i].bounds());
+ left_bounds.grow(prim_bounds);
swap(refs[i], refs[left_end++]);
}
- else if(refs[i].bounds().min[this->dim] >= this->pos) {
+ else if(prim_bounds.min[this->dim] >= this->pos) {
/* entirely on the right-hand side */
- right_bounds.grow(refs[i].bounds());
+ right_bounds.grow(prim_bounds);
swap(refs[i--], refs[--right_start]);
}
}
@@ -231,8 +280,12 @@ void BVHSpatialSplit::split(BVHBuild *builder,
new_refs.reserve(right_start - left_end);
while(left_end < right_start) {
/* split reference. */
+ BVHReference curr_ref(get_prim_bounds(refs[left_end]),
+ refs[left_end].prim_index(),
+ refs[left_end].prim_object(),
+ refs[left_end].prim_type());
BVHReference lref, rref;
- split_reference(*builder, lref, rref, refs[left_end], this->dim, this->pos);
+ split_reference(*builder, lref, rref, curr_ref, this->dim, this->pos);
/* compute SAH for duplicate/unsplit candidates. */
BoundBox lub = left_bounds; // Unsplit to left: new left-hand bounds.
@@ -240,8 +293,8 @@ void BVHSpatialSplit::split(BVHBuild *builder,
BoundBox ldb = left_bounds; // Duplicate: new left-hand bounds.
BoundBox rdb = right_bounds; // Duplicate: new right-hand bounds.
- lub.grow(refs[left_end].bounds());
- rub.grow(refs[left_end].bounds());
+ lub.grow(curr_ref.bounds());
+ rub.grow(curr_ref.bounds());
ldb.grow(lref.bounds());
rdb.grow(rref.bounds());
@@ -280,6 +333,17 @@ void BVHSpatialSplit::split(BVHBuild *builder,
new_refs.begin(),
new_refs.end());
}
+ if(aligned_space_ != NULL) {
+ left_bounds = right_bounds = BoundBox::empty;
+ for(int i = left_start; i < left_end - left_start; ++i) {
+ BoundBox prim_boundbox = references_->at(i).bounds();
+ left_bounds.grow(prim_boundbox);
+ }
+ for(int i = right_start; i < right_end - right_start; ++i) {
+ BoundBox prim_boundbox = references_->at(i).bounds();
+ right_bounds.grow(prim_boundbox);
+ }
+ }
left = BVHRange(left_bounds, left_start, left_end - left_start);
right = BVHRange(right_bounds, right_start, right_end - right_start);
}
@@ -292,14 +356,16 @@ void BVHSpatialSplit::split_triangle_primitive(const Mesh *mesh,
BoundBox& left_bounds,
BoundBox& right_bounds)
{
- const int *inds = mesh->triangles[prim_index].v;
+ Mesh::Triangle t = mesh->get_triangle(prim_index);
const float3 *verts = &mesh->verts[0];
- float3 v1 = tfm ? transform_point(tfm, verts[inds[2]]) : verts[inds[2]];
+ float3 v1 = tfm ? transform_point(tfm, verts[t.v[2]]) : verts[t.v[2]];
+ v1 = get_unaligned_point(v1);
for(int i = 0; i < 3; i++) {
float3 v0 = v1;
- int vindex = inds[i];
+ int vindex = t.v[i];
v1 = tfm ? transform_point(tfm, verts[vindex]) : verts[vindex];
+ v1 = get_unaligned_point(v1);
float v0p = v0[dim];
float v1p = v1[dim];
@@ -329,17 +395,18 @@ void BVHSpatialSplit::split_curve_primitive(const Mesh *mesh,
BoundBox& right_bounds)
{
/* curve split: NOTE - Currently ignores curve width and needs to be fixed.*/
- const int k0 = mesh->curves[prim_index].first_key + segment_index;
+ Mesh::Curve curve = mesh->get_curve(prim_index);
+ const int k0 = curve.first_key + segment_index;
const int k1 = k0 + 1;
- const float4& key0 = mesh->curve_keys[k0];
- const float4& key1 = mesh->curve_keys[k1];
- float3 v0 = float4_to_float3(key0);
- float3 v1 = float4_to_float3(key1);
+ float3 v0 = mesh->curve_keys[k0];
+ float3 v1 = mesh->curve_keys[k1];
if(tfm != NULL) {
v0 = transform_point(tfm, v0);
v1 = transform_point(tfm, v1);
}
+ v0 = get_unaligned_point(v0);
+ v1 = get_unaligned_point(v1);
float v0p = v0[dim];
float v1p = v1[dim];
@@ -405,7 +472,7 @@ void BVHSpatialSplit::split_object_reference(const Object *object,
BoundBox& right_bounds)
{
Mesh *mesh = object->mesh;
- for(int tri_idx = 0; tri_idx < mesh->triangles.size(); ++tri_idx) {
+ for(int tri_idx = 0; tri_idx < mesh->num_triangles(); ++tri_idx) {
split_triangle_primitive(mesh,
&object->tfm,
tri_idx,
@@ -414,8 +481,8 @@ void BVHSpatialSplit::split_object_reference(const Object *object,
left_bounds,
right_bounds);
}
- for(int curve_idx = 0; curve_idx < mesh->curves.size(); ++curve_idx) {
- Mesh::Curve &curve = mesh->curves[curve_idx];
+ for(int curve_idx = 0; curve_idx < mesh->num_curves(); ++curve_idx) {
+ Mesh::Curve curve = mesh->get_curve(curve_idx);
for(int segment_idx = 0;
segment_idx < curve.num_keys - 1;
++segment_idx)
@@ -474,6 +541,7 @@ void BVHSpatialSplit::split_reference(const BVHBuild& builder,
/* intersect with original bounds. */
left_bounds.max[dim] = pos;
right_bounds.min[dim] = pos;
+
left_bounds.intersect(ref.bounds());
right_bounds.intersect(ref.bounds());
diff --git a/intern/cycles/bvh/bvh_split.h b/intern/cycles/bvh/bvh_split.h
index aea8b2565e0..dbdb51f1a5b 100644
--- a/intern/cycles/bvh/bvh_split.h
+++ b/intern/cycles/bvh/bvh_split.h
@@ -24,6 +24,7 @@
CCL_NAMESPACE_BEGIN
class BVHBuild;
+struct Transform;
/* Object Split */
@@ -41,7 +42,9 @@ public:
BVHSpatialStorage *storage,
const BVHRange& range,
vector<BVHReference> *references,
- float nodeSAH);
+ float nodeSAH,
+ const BVHUnaligned *unaligned_heuristic = NULL,
+ const Transform *aligned_space = NULL);
void split(BVHRange& left,
BVHRange& right,
@@ -50,6 +53,19 @@ public:
protected:
BVHSpatialStorage *storage_;
vector<BVHReference> *references_;
+ const BVHUnaligned *unaligned_heuristic_;
+ const Transform *aligned_space_;
+
+ __forceinline BoundBox get_prim_bounds(const BVHReference& prim) const
+ {
+ if(aligned_space_ == NULL) {
+ return prim.bounds();
+ }
+ else {
+ return unaligned_heuristic_->compute_aligned_prim_boundbox(
+ prim, *aligned_space_);
+ }
+ }
};
/* Spatial Split */
@@ -70,7 +86,9 @@ public:
BVHSpatialStorage *storage,
const BVHRange& range,
vector<BVHReference> *references,
- float nodeSAH);
+ float nodeSAH,
+ const BVHUnaligned *unaligned_heuristic = NULL,
+ const Transform *aligned_space = NULL);
void split(BVHBuild *builder,
BVHRange& left,
@@ -87,6 +105,8 @@ public:
protected:
BVHSpatialStorage *storage_;
vector<BVHReference> *references_;
+ const BVHUnaligned *unaligned_heuristic_;
+ const Transform *aligned_space_;
/* Lower-level functions which calculates boundaries of left and right nodes
* needed for spatial split.
@@ -132,6 +152,27 @@ protected:
float pos,
BoundBox& left_bounds,
BoundBox& right_bounds);
+
+ __forceinline BoundBox get_prim_bounds(const BVHReference& prim) const
+ {
+ if(aligned_space_ == NULL) {
+ return prim.bounds();
+ }
+ else {
+ return unaligned_heuristic_->compute_aligned_prim_boundbox(
+ prim, *aligned_space_);
+ }
+ }
+
+ __forceinline float3 get_unaligned_point(const float3& point) const
+ {
+ if(aligned_space_ == NULL) {
+ return point;
+ }
+ else {
+ return transform_point(aligned_space_, point);
+ }
+ }
};
/* Mixed Object-Spatial Split */
@@ -148,19 +189,40 @@ public:
bool no_split;
+ BoundBox bounds;
+
+ BVHMixedSplit() {}
+
__forceinline BVHMixedSplit(BVHBuild *builder,
BVHSpatialStorage *storage,
const BVHRange& range,
vector<BVHReference> *references,
- int level)
+ int level,
+ const BVHUnaligned *unaligned_heuristic = NULL,
+ const Transform *aligned_space = NULL)
{
+ if(aligned_space == NULL) {
+ bounds = range.bounds();
+ }
+ else {
+ bounds = unaligned_heuristic->compute_aligned_boundbox(
+ range,
+ &references->at(0),
+ *aligned_space);
+ }
/* find split candidates. */
- float area = range.bounds().safe_area();
+ float area = bounds.safe_area();
leafSAH = area * builder->params.primitive_cost(range.size());
nodeSAH = area * builder->params.node_cost(2);
- object = BVHObjectSplit(builder, storage, range, references, nodeSAH);
+ object = BVHObjectSplit(builder,
+ storage,
+ range,
+ references,
+ nodeSAH,
+ unaligned_heuristic,
+ aligned_space);
if(builder->params.use_spatial_split && level < BVHParams::MAX_SPATIAL_DEPTH) {
BoundBox overlap = object.left_bounds;
@@ -171,7 +233,9 @@ public:
storage,
range,
references,
- nodeSAH);
+ nodeSAH,
+ unaligned_heuristic,
+ aligned_space);
}
}
@@ -181,7 +245,10 @@ public:
builder->range_within_max_leaf_size(range, *references));
}
- __forceinline void split(BVHBuild *builder, BVHRange& left, BVHRange& right, const BVHRange& range)
+ __forceinline void split(BVHBuild *builder,
+ BVHRange& left,
+ BVHRange& right,
+ const BVHRange& range)
{
if(builder->params.use_spatial_split && minSAH == spatial.sah)
spatial.split(builder, left, right, range);
@@ -193,4 +260,3 @@ public:
CCL_NAMESPACE_END
#endif /* __BVH_SPLIT_H__ */
-
diff --git a/intern/cycles/bvh/bvh_unaligned.cpp b/intern/cycles/bvh/bvh_unaligned.cpp
new file mode 100644
index 00000000000..a876c670914
--- /dev/null
+++ b/intern/cycles/bvh/bvh_unaligned.cpp
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "bvh_unaligned.h"
+
+#include "mesh.h"
+#include "object.h"
+
+#include "bvh_binning.h"
+#include "bvh_params.h"
+
+#include "util_boundbox.h"
+#include "util_debug.h"
+#include "util_transform.h"
+
+CCL_NAMESPACE_BEGIN
+
+
+BVHUnaligned::BVHUnaligned(const vector<Object*>& objects)
+ : objects_(objects)
+{
+}
+
+Transform BVHUnaligned::compute_aligned_space(
+ const BVHObjectBinning& range,
+ const BVHReference *references) const
+{
+ for(int i = range.start(); i < range.end(); ++i) {
+ const BVHReference& ref = references[i];
+ Transform aligned_space;
+ /* Use first primitive which defines correct direction to define
+ * the orientation space.
+ */
+ if(compute_aligned_space(ref, &aligned_space)) {
+ return aligned_space;
+ }
+ }
+ return transform_identity();
+}
+
+Transform BVHUnaligned::compute_aligned_space(
+ const BVHRange& range,
+ const BVHReference *references) const
+{
+ for(int i = range.start(); i < range.end(); ++i) {
+ const BVHReference& ref = references[i];
+ Transform aligned_space;
+ /* Use first primitive which defines correct direction to define
+ * the orientation space.
+ */
+ if(compute_aligned_space(ref, &aligned_space)) {
+ return aligned_space;
+ }
+ }
+ return transform_identity();
+}
+
+bool BVHUnaligned::compute_aligned_space(const BVHReference& ref,
+ Transform *aligned_space) const
+{
+ const Object *object = objects_[ref.prim_object()];
+ const int packed_type = ref.prim_type();
+ const int type = (packed_type & PRIMITIVE_ALL);
+ if(type & PRIMITIVE_CURVE) {
+ const int curve_index = ref.prim_index();
+ const int segment = PRIMITIVE_UNPACK_SEGMENT(packed_type);
+ const Mesh *mesh = object->mesh;
+ const Mesh::Curve& curve = mesh->get_curve(curve_index);
+ const int key = curve.first_key + segment;
+ const float3 v1 = mesh->curve_keys[key],
+ v2 = mesh->curve_keys[key + 1];
+ float length;
+ const float3 axis = normalize_len(v2 - v1, &length);
+ if(length > 1e-6f) {
+ *aligned_space = make_transform_frame(axis);
+ return true;
+ }
+ }
+ *aligned_space = transform_identity();
+ return false;
+}
+
+BoundBox BVHUnaligned::compute_aligned_prim_boundbox(
+ const BVHReference& prim,
+ const Transform& aligned_space) const
+{
+ BoundBox bounds = BoundBox::empty;
+ const Object *object = objects_[prim.prim_object()];
+ const int packed_type = prim.prim_type();
+ const int type = (packed_type & PRIMITIVE_ALL);
+ if(type & PRIMITIVE_CURVE) {
+ const int curve_index = prim.prim_index();
+ const int segment = PRIMITIVE_UNPACK_SEGMENT(packed_type);
+ const Mesh *mesh = object->mesh;
+ const Mesh::Curve& curve = mesh->get_curve(curve_index);
+ curve.bounds_grow(segment,
+ &mesh->curve_keys[0],
+ &mesh->curve_radius[0],
+ aligned_space,
+ bounds);
+ }
+ else {
+ bounds = prim.bounds().transformed(&aligned_space);
+ }
+ return bounds;
+}
+
+BoundBox BVHUnaligned::compute_aligned_boundbox(
+ const BVHObjectBinning& range,
+ const BVHReference *references,
+ const Transform& aligned_space,
+ BoundBox *cent_bounds) const
+{
+ BoundBox bounds = BoundBox::empty;
+ if(cent_bounds != NULL) {
+ *cent_bounds = BoundBox::empty;
+ }
+ for(int i = range.start(); i < range.end(); ++i) {
+ const BVHReference& ref = references[i];
+ BoundBox ref_bounds = compute_aligned_prim_boundbox(ref, aligned_space);
+ bounds.grow(ref_bounds);
+ if(cent_bounds != NULL) {
+ cent_bounds->grow(ref_bounds.center2());
+ }
+ }
+ return bounds;
+}
+
+BoundBox BVHUnaligned::compute_aligned_boundbox(
+ const BVHRange& range,
+ const BVHReference *references,
+ const Transform& aligned_space,
+ BoundBox *cent_bounds) const
+{
+ BoundBox bounds = BoundBox::empty;
+ if(cent_bounds != NULL) {
+ *cent_bounds = BoundBox::empty;
+ }
+ for(int i = range.start(); i < range.end(); ++i) {
+ const BVHReference& ref = references[i];
+ BoundBox ref_bounds = compute_aligned_prim_boundbox(ref, aligned_space);
+ bounds.grow(ref_bounds);
+ if(cent_bounds != NULL) {
+ cent_bounds->grow(ref_bounds.center2());
+ }
+ }
+ return bounds;
+}
+
+Transform BVHUnaligned::compute_node_transform(
+ const BoundBox& bounds,
+ const Transform& aligned_space)
+{
+ Transform space = aligned_space;
+ space.x.w -= bounds.min.x;
+ space.y.w -= bounds.min.y;
+ space.z.w -= bounds.min.z;
+ float3 dim = bounds.max - bounds.min;
+ return transform_scale(1.0f / max(1e-18f, dim.x),
+ 1.0f / max(1e-18f, dim.y),
+ 1.0f / max(1e-18f, dim.z)) * space;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh_unaligned.h b/intern/cycles/bvh/bvh_unaligned.h
new file mode 100644
index 00000000000..4d0872f4a39
--- /dev/null
+++ b/intern/cycles/bvh/bvh_unaligned.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BVH_UNALIGNED_H__
+#define __BVH_UNALIGNED_H__
+
+#include "util_vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+class BoundBox;
+class BVHObjectBinning;
+class BVHRange;
+class BVHReference;
+struct Transform;
+class Object;
+
+/* Helper class to perform calculations needed for unaligned nodes. */
+class BVHUnaligned {
+public:
+ BVHUnaligned(const vector<Object*>& objects);
+
+ /* Calculate alignment for the oriented node for a given range. */
+ Transform compute_aligned_space(
+ const BVHObjectBinning& range,
+ const BVHReference *references) const;
+ Transform compute_aligned_space(
+ const BVHRange& range,
+ const BVHReference *references) const;
+
+ /* Calculate alignment for the oriented node for a given reference.
+ *
+ * Return true when space was calculated successfully.
+ */
+ bool compute_aligned_space(const BVHReference& ref,
+ Transform *aligned_space) const;
+
+ /* Calculate primitive's bounding box in given space. */
+ BoundBox compute_aligned_prim_boundbox(
+ const BVHReference& prim,
+ const Transform& aligned_space) const;
+
+ /* Calculate bounding box in given space. */
+ BoundBox compute_aligned_boundbox(
+ const BVHObjectBinning& range,
+ const BVHReference *references,
+ const Transform& aligned_space,
+ BoundBox *cent_bounds = NULL) const;
+ BoundBox compute_aligned_boundbox(
+ const BVHRange& range,
+ const BVHReference *references,
+ const Transform& aligned_space,
+ BoundBox *cent_bounds = NULL) const;
+
+ /* Calculate affine transform for node packing.
+ * Bounds will be in the range of 0..1.
+ */
+ static Transform compute_node_transform(const BoundBox& bounds,
+ const Transform& aligned_space);
+protected:
+ /* List of objects BVH is being created for. */
+ const vector<Object*>& objects_;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __BVH_UNALIGNED_H__ */
+
diff --git a/intern/cycles/device/CMakeLists.txt b/intern/cycles/device/CMakeLists.txt
index 2a9ec0c3818..966ff5e52ba 100644
--- a/intern/cycles/device/CMakeLists.txt
+++ b/intern/cycles/device/CMakeLists.txt
@@ -1,6 +1,7 @@
set(INC
.
+ ../graph
../kernel
../kernel/svm
../kernel/osl
@@ -35,6 +36,15 @@ set(SRC
device_task.cpp
)
+set(SRC_OPENCL
+ opencl/opencl.h
+
+ opencl/opencl_base.cpp
+ opencl/opencl_mega.cpp
+ opencl/opencl_split.cpp
+ opencl/opencl_util.cpp
+)
+
if(WITH_CYCLES_NETWORK)
list(APPEND SRC
device_network.cpp
@@ -66,4 +76,4 @@ endif()
include_directories(${INC})
include_directories(SYSTEM ${INC_SYS})
-add_library(cycles_device ${SRC} ${SRC_HEADERS})
+add_library(cycles_device ${SRC} ${SRC_OPENCL} ${SRC_HEADERS})
diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp
index 8c01bcb116f..909ec7a6d60 100644
--- a/intern/cycles/device/device.cpp
+++ b/intern/cycles/device/device.cpp
@@ -49,13 +49,21 @@ std::ostream& operator <<(std::ostream &os,
/* TODO(sergey): Decode bitflag into list of names. */
os << "Nodes features: " << requested_features.nodes_features << std::endl;
os << "Use hair: "
- << string_from_bool(requested_features.use_hair) << std::endl;
+ << string_from_bool(requested_features.use_hair) << std::endl;
os << "Use object motion: "
- << string_from_bool(requested_features.use_object_motion) << std::endl;
+ << string_from_bool(requested_features.use_object_motion) << std::endl;
os << "Use camera motion: "
- << string_from_bool(requested_features.use_camera_motion) << std::endl;
+ << string_from_bool(requested_features.use_camera_motion) << std::endl;
os << "Use Baking: "
- << string_from_bool(requested_features.use_baking) << std::endl;
+ << string_from_bool(requested_features.use_baking) << std::endl;
+ os << "Use Subsurface: "
+ << string_from_bool(requested_features.use_subsurface) << std::endl;
+ os << "Use Volume: "
+ << string_from_bool(requested_features.use_volume) << std::endl;
+ os << "Use Branched Integrator: "
+ << string_from_bool(requested_features.use_integrator_branched) << std::endl;
+ os << "Use Patch Evaluation: "
+ << string_from_bool(requested_features.use_patch_evaluation) << std::endl;
return os;
}
diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h
index 4c1b7224837..77dc1fa9713 100644
--- a/intern/cycles/device/device.h
+++ b/intern/cycles/device/device.h
@@ -54,7 +54,7 @@ public:
bool display_device;
bool advanced_shading;
bool pack_images;
- bool extended_images; /* flag for GPU and Multi device */
+ bool has_bindless_textures; /* flag for GPU and Multi device */
bool use_split_kernel; /* Denotes if the device is going to run cycles using split-kernel */
vector<DeviceInfo> multi_devices;
@@ -66,7 +66,7 @@ public:
display_device = false;
advanced_shading = true;
pack_images = false;
- extended_images = false;
+ has_bindless_textures = false;
use_split_kernel = false;
}
};
@@ -109,6 +109,9 @@ public:
/* Use branched integrator. */
bool use_integrator_branched;
+ /* Use OpenSubdiv patch evaluation */
+ bool use_patch_evaluation;
+
DeviceRequestedFeatures()
{
/* TODO(sergey): Find more meaningful defaults. */
@@ -123,6 +126,7 @@ public:
use_subsurface = false;
use_volume = false;
use_integrator_branched = false;
+ use_patch_evaluation = false;
}
bool modified(const DeviceRequestedFeatures& requested_features)
@@ -137,7 +141,8 @@ public:
use_baking == requested_features.use_baking &&
use_subsurface == requested_features.use_subsurface &&
use_volume == requested_features.use_volume &&
- use_integrator_branched == requested_features.use_integrator_branched);
+ use_integrator_branched == requested_features.use_integrator_branched &&
+ use_patch_evaluation == requested_features.use_patch_evaluation);
}
/* Convert the requested features structure to a build options,
@@ -175,6 +180,9 @@ public:
if(!use_integrator_branched) {
build_options += " -D__NO_BRANCHED_PATH__";
}
+ if(!use_patch_evaluation) {
+ build_options += " -D__NO_PATCH_EVAL__";
+ }
return build_options;
}
};
@@ -230,6 +238,7 @@ public:
(void)interpolation; /* Ignored. */
(void)extension; /* Ignored. */
};
+
virtual void tex_free(device_memory& /*mem*/) {};
/* pixel memory */
diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp
index 4d0a57d870a..aed86d8d853 100644
--- a/intern/cycles/device/device_cpu.cpp
+++ b/intern/cycles/device/device_cpu.cpp
@@ -27,9 +27,6 @@
#include "device.h"
#include "device_intern.h"
-/* Texture limits and slot info */
-#include "util_texture.h"
-
#include "kernel.h"
#include "kernel_compat_cpu.h"
#include "kernel_types.h"
@@ -158,7 +155,9 @@ public:
InterpolationType interpolation,
ExtensionType extension)
{
- VLOG(1) << "Texture allocate: " << name << ", " << mem.memory_size() << " bytes.";
+ VLOG(1) << "Texture allocate: " << name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
kernel_tex_copy(&kernel_globals,
name,
mem.data_pointer,
@@ -216,12 +215,7 @@ public:
return;
}
- KernelGlobals kg = kernel_globals;
-
-#ifdef WITH_OSL
- OSLShader::thread_init(&kg, &kernel_globals, &osl_globals);
-#endif
-
+ KernelGlobals kg = thread_kernel_globals_init();
RenderTile tile;
void(*path_trace_kernel)(KernelGlobals*, float*, unsigned int*, int, int, int, int, int);
@@ -292,9 +286,7 @@ public:
}
}
-#ifdef WITH_OSL
- OSLShader::thread_free(&kg);
-#endif
+ thread_kernel_globals_free(&kg);
}
void thread_film_convert(DeviceTask& task)
@@ -484,6 +476,40 @@ public:
{
task_pool.cancel();
}
+
+protected:
+ inline KernelGlobals thread_kernel_globals_init()
+ {
+ KernelGlobals kg = kernel_globals;
+ kg.transparent_shadow_intersections = NULL;
+ const int decoupled_count = sizeof(kg.decoupled_volume_steps) /
+ sizeof(*kg.decoupled_volume_steps);
+ for(int i = 0; i < decoupled_count; ++i) {
+ kg.decoupled_volume_steps[i] = NULL;
+ }
+ kg.decoupled_volume_steps_index = 0;
+#ifdef WITH_OSL
+ OSLShader::thread_init(&kg, &kernel_globals, &osl_globals);
+#endif
+ return kg;
+ }
+
+ inline void thread_kernel_globals_free(KernelGlobals *kg)
+ {
+ if(kg->transparent_shadow_intersections != NULL) {
+ free(kg->transparent_shadow_intersections);
+ }
+ const int decoupled_count = sizeof(kg->decoupled_volume_steps) /
+ sizeof(*kg->decoupled_volume_steps);
+ for(int i = 0; i < decoupled_count; ++i) {
+ if(kg->decoupled_volume_steps[i] != NULL) {
+ free(kg->decoupled_volume_steps[i]);
+ }
+ }
+#ifdef WITH_OSL
+ OSLShader::thread_free(kg);
+#endif
+ }
};
Device *device_cpu_create(DeviceInfo& info, Stats &stats, bool background)
diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp
index 69015e7401b..7f8a0bf2f43 100644
--- a/intern/cycles/device/device_cuda.cpp
+++ b/intern/cycles/device/device_cuda.cpp
@@ -85,10 +85,10 @@ public:
CUcontext cuContext;
CUmodule cuModule;
map<device_ptr, bool> tex_interp_map;
+ map<device_ptr, uint> tex_bindless_map;
int cuDevId;
int cuDevArchitecture;
bool first_error;
- bool use_texture_storage;
struct PixelMem {
GLuint cuPBO;
@@ -99,6 +99,10 @@ public:
map<device_ptr, PixelMem> pixel_mem_map;
+ /* Bindless Textures */
+ device_vector<uint> bindless_mapping;
+ bool need_bindless_mapping;
+
CUdeviceptr cuda_device_ptr(device_ptr mem)
{
return (CUdeviceptr)mem;
@@ -176,12 +180,13 @@ public:
{
first_error = true;
background = background_;
- use_texture_storage = true;
cuDevId = info.num;
cuDevice = 0;
cuContext = 0;
+ need_bindless_mapping = false;
+
/* intialize */
if(cuda_error(cuInit(0)))
return;
@@ -211,11 +216,6 @@ public:
cuDeviceComputeCapability(&major, &minor, cuDevId);
cuDevArchitecture = major*100 + minor*10;
- /* In order to use full 6GB of memory on Titan cards, use arrays instead
- * of textures. On earlier cards this seems slower, but on Titan it is
- * actually slightly faster in tests. */
- use_texture_storage = (cuDevArchitecture < 300);
-
cuda_pop_context();
}
@@ -223,6 +223,10 @@ public:
{
task_pool.stop();
+ if(info.has_bindless_textures) {
+ tex_free(bindless_mapping);
+ }
+
cuda_assert(cuCtxDestroy(cuContext));
}
@@ -245,118 +249,161 @@ public:
return DebugFlags().cuda.adaptive_compile;
}
+ /* Common NVCC flags which stays the same regardless of shading model,
+ * kernel sources md5 and only depends on compiler or compilation settings.
+ */
+ string compile_kernel_get_common_cflags(
+ const DeviceRequestedFeatures& requested_features)
+ {
+ const int cuda_version = cuewCompilerVersion();
+ const int machine = system_cpu_bits();
+ const string kernel_path = path_get("kernel");
+ const string include = kernel_path;
+ string cflags = string_printf("-m%d "
+ "--ptxas-options=\"-v\" "
+ "--use_fast_math "
+ "-DNVCC "
+ "-D__KERNEL_CUDA_VERSION__=%d "
+ "-I\"%s\"",
+ machine,
+ cuda_version,
+ include.c_str());
+ if(use_adaptive_compilation()) {
+ cflags += " " + requested_features.get_build_options();
+ }
+ const char *extra_cflags = getenv("CYCLES_CUDA_EXTRA_CFLAGS");
+ if(extra_cflags) {
+ cflags += string(" ") + string(extra_cflags);
+ }
+#ifdef WITH_CYCLES_DEBUG
+ cflags += " -D__KERNEL_DEBUG__";
+#endif
+ return cflags;
+ }
+
+ bool compile_check_compiler() {
+ const char *nvcc = cuewCompilerPath();
+ if(nvcc == NULL) {
+ cuda_error_message("CUDA nvcc compiler not found. "
+ "Install CUDA toolkit in default location.");
+ return false;
+ }
+ const int cuda_version = cuewCompilerVersion();
+ VLOG(1) << "Found nvcc " << nvcc
+ << ", CUDA version " << cuda_version
+ << ".";
+ const int major = cuda_version / 10, minor = cuda_version & 10;
+ if(cuda_version == 0) {
+ cuda_error_message("CUDA nvcc compiler version could not be parsed.");
+ return false;
+ }
+ if(cuda_version < 75) {
+ printf("Unsupported CUDA version %d.%d detected, "
+ "you need CUDA 7.5 or newer.\n",
+ major, minor);
+ return false;
+ }
+ else if(cuda_version != 75 && cuda_version != 80) {
+ printf("CUDA version %d.%d detected, build may succeed but only "
+ "CUDA 7.5 and 8.0 are officially supported.\n",
+ major, minor);
+ }
+ return true;
+ }
+
string compile_kernel(const DeviceRequestedFeatures& requested_features)
{
- /* compute cubin name */
+ /* Compute cubin name. */
int major, minor;
cuDeviceComputeCapability(&major, &minor, cuDevId);
- string cubin;
- /* adaptive compile */
- bool use_adaptive_compile = use_adaptive_compilation();
-
- /* attempt to use kernel provided with blender */
- cubin = path_get(string_printf("lib/kernel_sm_%d%d.cubin", major, minor));
- VLOG(1) << "Testing for pre-compiled kernel " << cubin;
- if(path_exists(cubin)) {
- VLOG(1) << "Using precompiled kernel";
- return cubin;
+ /* Attempt to use kernel provided with Blender. */
+ if(!use_adaptive_compilation()) {
+ const string cubin = path_get(string_printf("lib/kernel_sm_%d%d.cubin",
+ major, minor));
+ VLOG(1) << "Testing for pre-compiled kernel " << cubin << ".";
+ if(path_exists(cubin)) {
+ VLOG(1) << "Using precompiled kernel.";
+ return cubin;
+ }
}
- /* not found, try to use locally compiled kernel */
- string kernel_path = path_get("kernel");
- string md5 = path_files_md5_hash(kernel_path);
-
- string feature_build_options;
- if(use_adaptive_compile) {
- feature_build_options = requested_features.get_build_options();
- string device_md5 = util_md5_string(feature_build_options);
- cubin = string_printf("cycles_kernel_%s_sm%d%d_%s.cubin",
- device_md5.c_str(),
- major, minor,
- md5.c_str());
- }
- else {
- cubin = string_printf("cycles_kernel_sm%d%d_%s.cubin", major, minor, md5.c_str());
- }
+ const string common_cflags =
+ compile_kernel_get_common_cflags(requested_features);
+
+ /* Try to use locally compiled kernel. */
+ const string kernel_path = path_get("kernel");
+ const string kernel_md5 = path_files_md5_hash(kernel_path);
- cubin = path_user_get(path_join("cache", cubin));
- VLOG(1) << "Testing for locally compiled kernel " << cubin;
- /* if exists already, use it */
+ /* We include cflags into md5 so changing cuda toolkit or changing other
+ * compiler command line arguments makes sure cubin gets re-built.
+ */
+ const string cubin_md5 = util_md5_string(kernel_md5 + common_cflags);
+
+ const string cubin_file = string_printf("cycles_kernel_sm%d%d_%s.cubin",
+ major, minor,
+ cubin_md5.c_str());
+ const string cubin = path_cache_get(path_join("kernels", cubin_file));
+ VLOG(1) << "Testing for locally compiled kernel " << cubin << ".";
if(path_exists(cubin)) {
- VLOG(1) << "Using locally compiled kernel";
+ VLOG(1) << "Using locally compiled kernel.";
return cubin;
}
#ifdef _WIN32
if(have_precompiled_kernels()) {
- if(major < 2)
- cuda_error_message(string_printf("CUDA device requires compute capability 2.0 or up, found %d.%d. Your GPU is not supported.", major, minor));
- else
- cuda_error_message(string_printf("CUDA binary kernel for this graphics card compute capability (%d.%d) not found.", major, minor));
+ if(major < 2) {
+ cuda_error_message(string_printf(
+ "CUDA device requires compute capability 2.0 or up, "
+ "found %d.%d. Your GPU is not supported.",
+ major, minor));
+ }
+ else {
+ cuda_error_message(string_printf(
+ "CUDA binary kernel for this graphics card compute "
+ "capability (%d.%d) not found.",
+ major, minor));
+ }
return "";
}
#endif
- /* if not, find CUDA compiler */
- const char *nvcc = cuewCompilerPath();
-
- if(nvcc == NULL) {
- cuda_error_message("CUDA nvcc compiler not found. Install CUDA toolkit in default location.");
+ /* Compile. */
+ if(!compile_check_compiler()) {
return "";
}
-
- int cuda_version = cuewCompilerVersion();
- VLOG(1) << "Found nvcc " << nvcc << ", CUDA version " << cuda_version;
-
- if(cuda_version == 0) {
- cuda_error_message("CUDA nvcc compiler version could not be parsed.");
- return "";
- }
- if(cuda_version < 60) {
- printf("Unsupported CUDA version %d.%d detected, you need CUDA 7.5.\n", cuda_version/10, cuda_version%10);
- return "";
- }
- else if(cuda_version != 75)
- printf("CUDA version %d.%d detected, build may succeed but only CUDA 7.5 is officially supported.\n", cuda_version/10, cuda_version%10);
-
- /* compile */
- string kernel = path_join(kernel_path, path_join("kernels", path_join("cuda", "kernel.cu")));
- string include = kernel_path;
- const int machine = system_cpu_bits();
-
+ const char *nvcc = cuewCompilerPath();
+ const string kernel = path_join(kernel_path,
+ path_join("kernels",
+ path_join("cuda", "kernel.cu")));
double starttime = time_dt();
printf("Compiling CUDA kernel ...\n");
path_create_directories(cubin);
- string command = string_printf("\"%s\" -arch=sm_%d%d -m%d --cubin \"%s\" "
- "-o \"%s\" --ptxas-options=\"-v\" --use_fast_math -I\"%s\" "
- "-DNVCC -D__KERNEL_CUDA_VERSION__=%d",
- nvcc, major, minor, machine, kernel.c_str(), cubin.c_str(), include.c_str(), cuda_version);
-
- if(use_adaptive_compile)
- command += " " + feature_build_options;
-
- const char* extra_cflags = getenv("CYCLES_CUDA_EXTRA_CFLAGS");
- if(extra_cflags) {
- command += string(" ") + string(extra_cflags);
- }
-
-#ifdef WITH_CYCLES_DEBUG
- command += " -D__KERNEL_DEBUG__";
-#endif
+ string command = string_printf("\"%s\" "
+ "-arch=sm_%d%d "
+ "--cubin \"%s\" "
+ "-o \"%s\" "
+ "%s ",
+ nvcc,
+ major, minor,
+ kernel.c_str(),
+ cubin.c_str(),
+ common_cflags.c_str());
printf("%s\n", command.c_str());
if(system(command.c_str()) == -1) {
- cuda_error_message("Failed to execute compilation command, see console for details.");
+ cuda_error_message("Failed to execute compilation command, "
+ "see console for details.");
return "";
}
- /* verify if compilation succeeded */
+ /* Verify if compilation succeeded */
if(!path_exists(cubin)) {
- cuda_error_message("CUDA kernel compilation failed, see console for details.");
+ cuda_error_message("CUDA kernel compilation failed, "
+ "see console for details.");
return "";
}
@@ -400,6 +447,15 @@ public:
return (result == CUDA_SUCCESS);
}
+ void load_bindless_mapping()
+ {
+ if(info.has_bindless_textures && need_bindless_mapping) {
+ tex_free(bindless_mapping);
+ tex_alloc("__bindless_mapping", bindless_mapping, INTERPOLATION_NONE, EXTENSION_REPEAT);
+ need_bindless_mapping = false;
+ }
+ }
+
void mem_alloc(device_memory& mem, MemoryType /*type*/)
{
cuda_push_context();
@@ -477,128 +533,104 @@ public:
InterpolationType interpolation,
ExtensionType extension)
{
- VLOG(1) << "Texture allocate: " << name << ", " << mem.memory_size() << " bytes.";
+ VLOG(1) << "Texture allocate: " << name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
+
+ /* Check if we are on sm_30 or above.
+ * We use arrays and bindles textures for storage there */
+ bool has_bindless_textures = info.has_bindless_textures;
+ /* General variables for both architectures */
string bind_name = name;
- if(mem.data_depth > 1) {
- /* Kernel uses different bind names for 2d and 3d float textures,
- * so we have to adjust couple of things here.
- */
- vector<string> tokens;
- string_split(tokens, name, "_");
- bind_name = string_printf("__tex_image_%s_3d_%s",
- tokens[2].c_str(),
- tokens[3].c_str());
+ size_t dsize = datatype_size(mem.data_type);
+ size_t size = mem.memory_size();
+
+ CUaddress_mode address_mode = CU_TR_ADDRESS_MODE_WRAP;
+ switch(extension) {
+ case EXTENSION_REPEAT:
+ address_mode = CU_TR_ADDRESS_MODE_WRAP;
+ break;
+ case EXTENSION_EXTEND:
+ address_mode = CU_TR_ADDRESS_MODE_CLAMP;
+ break;
+ case EXTENSION_CLIP:
+ address_mode = CU_TR_ADDRESS_MODE_BORDER;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ CUfilter_mode filter_mode;
+ if(interpolation == INTERPOLATION_CLOSEST) {
+ filter_mode = CU_TR_FILTER_MODE_POINT;
+ }
+ else {
+ filter_mode = CU_TR_FILTER_MODE_LINEAR;
}
- /* determine format */
CUarray_format_enum format;
- size_t dsize = datatype_size(mem.data_type);
- size_t size = mem.memory_size();
- bool use_texture = (interpolation != INTERPOLATION_NONE) || use_texture_storage;
+ switch(mem.data_type) {
+ case TYPE_UCHAR: format = CU_AD_FORMAT_UNSIGNED_INT8; break;
+ case TYPE_UINT: format = CU_AD_FORMAT_UNSIGNED_INT32; break;
+ case TYPE_INT: format = CU_AD_FORMAT_SIGNED_INT32; break;
+ case TYPE_FLOAT: format = CU_AD_FORMAT_FLOAT; break;
+ case TYPE_HALF: format = CU_AD_FORMAT_HALF; break;
+ default: assert(0); return;
+ }
- if(use_texture) {
+ /* General variables for Fermi */
+ CUtexref texref = NULL;
- switch(mem.data_type) {
- case TYPE_UCHAR: format = CU_AD_FORMAT_UNSIGNED_INT8; break;
- case TYPE_UINT: format = CU_AD_FORMAT_UNSIGNED_INT32; break;
- case TYPE_INT: format = CU_AD_FORMAT_SIGNED_INT32; break;
- case TYPE_FLOAT: format = CU_AD_FORMAT_FLOAT; break;
- default: assert(0); return;
+ if(!has_bindless_textures) {
+ if(mem.data_depth > 1) {
+ /* Kernel uses different bind names for 2d and 3d float textures,
+ * so we have to adjust couple of things here.
+ */
+ vector<string> tokens;
+ string_split(tokens, name, "_");
+ bind_name = string_printf("__tex_image_%s_3d_%s",
+ tokens[2].c_str(),
+ tokens[3].c_str());
}
- CUtexref texref = NULL;
-
cuda_push_context();
cuda_assert(cuModuleGetTexRef(&texref, cuModule, bind_name.c_str()));
+ cuda_pop_context();
if(!texref) {
- cuda_pop_context();
return;
}
+ }
- if(interpolation != INTERPOLATION_NONE) {
- CUarray handle = NULL;
-
- if(mem.data_depth > 1) {
- CUDA_ARRAY3D_DESCRIPTOR desc;
-
- desc.Width = mem.data_width;
- desc.Height = mem.data_height;
- desc.Depth = mem.data_depth;
- desc.Format = format;
- desc.NumChannels = mem.data_elements;
- desc.Flags = 0;
-
- cuda_assert(cuArray3DCreate(&handle, &desc));
- }
- else {
- CUDA_ARRAY_DESCRIPTOR desc;
-
- desc.Width = mem.data_width;
- desc.Height = mem.data_height;
- desc.Format = format;
- desc.NumChannels = mem.data_elements;
-
- cuda_assert(cuArrayCreate(&handle, &desc));
- }
+ /* Data Storage */
+ if(interpolation == INTERPOLATION_NONE) {
+ if(has_bindless_textures) {
+ mem_alloc(mem, MEM_READ_ONLY);
+ mem_copy_to(mem);
- if(!handle) {
- cuda_pop_context();
- return;
- }
+ cuda_push_context();
- if(mem.data_depth > 1) {
- CUDA_MEMCPY3D param;
- memset(&param, 0, sizeof(param));
- param.dstMemoryType = CU_MEMORYTYPE_ARRAY;
- param.dstArray = handle;
- param.srcMemoryType = CU_MEMORYTYPE_HOST;
- param.srcHost = (void*)mem.data_pointer;
- param.srcPitch = mem.data_width*dsize*mem.data_elements;
- param.WidthInBytes = param.srcPitch;
- param.Height = mem.data_height;
- param.Depth = mem.data_depth;
-
- cuda_assert(cuMemcpy3D(&param));
- }
- if(mem.data_height > 1) {
- CUDA_MEMCPY2D param;
- memset(&param, 0, sizeof(param));
- param.dstMemoryType = CU_MEMORYTYPE_ARRAY;
- param.dstArray = handle;
- param.srcMemoryType = CU_MEMORYTYPE_HOST;
- param.srcHost = (void*)mem.data_pointer;
- param.srcPitch = mem.data_width*dsize*mem.data_elements;
- param.WidthInBytes = param.srcPitch;
- param.Height = mem.data_height;
-
- cuda_assert(cuMemcpy2D(&param));
- }
- else
- cuda_assert(cuMemcpyHtoA(handle, 0, (void*)mem.data_pointer, size));
+ CUdeviceptr cumem;
+ size_t cubytes;
- cuda_assert(cuTexRefSetArray(texref, handle, CU_TRSA_OVERRIDE_FORMAT));
+ cuda_assert(cuModuleGetGlobal(&cumem, &cubytes, cuModule, bind_name.c_str()));
- if(interpolation == INTERPOLATION_CLOSEST) {
- cuda_assert(cuTexRefSetFilterMode(texref, CU_TR_FILTER_MODE_POINT));
+ if(cubytes == 8) {
+ /* 64 bit device pointer */
+ uint64_t ptr = mem.device_pointer;
+ cuda_assert(cuMemcpyHtoD(cumem, (void*)&ptr, cubytes));
}
- else if(interpolation == INTERPOLATION_LINEAR) {
- cuda_assert(cuTexRefSetFilterMode(texref, CU_TR_FILTER_MODE_LINEAR));
- }
- else {/* CUBIC and SMART are unsupported for CUDA */
- cuda_assert(cuTexRefSetFilterMode(texref, CU_TR_FILTER_MODE_LINEAR));
+ else {
+ /* 32 bit device pointer */
+ uint32_t ptr = (uint32_t)mem.device_pointer;
+ cuda_assert(cuMemcpyHtoD(cumem, (void*)&ptr, cubytes));
}
- cuda_assert(cuTexRefSetFlags(texref, CU_TRSF_NORMALIZED_COORDINATES));
- mem.device_pointer = (device_ptr)handle;
- mem.device_size = size;
-
- stats.mem_alloc(size);
+ cuda_pop_context();
}
else {
- cuda_pop_context();
-
mem_alloc(mem, MEM_READ_ONLY);
mem_copy_to(mem);
@@ -607,58 +639,153 @@ public:
cuda_assert(cuTexRefSetAddress(NULL, texref, cuda_device_ptr(mem.device_pointer), size));
cuda_assert(cuTexRefSetFilterMode(texref, CU_TR_FILTER_MODE_POINT));
cuda_assert(cuTexRefSetFlags(texref, CU_TRSF_READ_AS_INTEGER));
+
+ cuda_pop_context();
+ }
+ }
+ /* Texture Storage */
+ else {
+ CUarray handle = NULL;
+
+ cuda_push_context();
+
+ if(mem.data_depth > 1) {
+ CUDA_ARRAY3D_DESCRIPTOR desc;
+
+ desc.Width = mem.data_width;
+ desc.Height = mem.data_height;
+ desc.Depth = mem.data_depth;
+ desc.Format = format;
+ desc.NumChannels = mem.data_elements;
+ desc.Flags = 0;
+
+ cuda_assert(cuArray3DCreate(&handle, &desc));
}
+ else {
+ CUDA_ARRAY_DESCRIPTOR desc;
- CUaddress_mode address_mode = CU_TR_ADDRESS_MODE_WRAP;
- switch(extension) {
- case EXTENSION_REPEAT:
- address_mode = CU_TR_ADDRESS_MODE_WRAP;
- break;
- case EXTENSION_EXTEND:
- address_mode = CU_TR_ADDRESS_MODE_CLAMP;
- break;
- case EXTENSION_CLIP:
- address_mode = CU_TR_ADDRESS_MODE_BORDER;
- break;
- default:
- assert(0);
- break;
+ desc.Width = mem.data_width;
+ desc.Height = mem.data_height;
+ desc.Format = format;
+ desc.NumChannels = mem.data_elements;
+
+ cuda_assert(cuArrayCreate(&handle, &desc));
}
- cuda_assert(cuTexRefSetAddressMode(texref, 0, address_mode));
- cuda_assert(cuTexRefSetAddressMode(texref, 1, address_mode));
+
+ if(!handle) {
+ cuda_pop_context();
+ return;
+ }
+
+ /* Allocate 3D, 2D or 1D memory */
if(mem.data_depth > 1) {
- cuda_assert(cuTexRefSetAddressMode(texref, 2, address_mode));
+ CUDA_MEMCPY3D param;
+ memset(&param, 0, sizeof(param));
+ param.dstMemoryType = CU_MEMORYTYPE_ARRAY;
+ param.dstArray = handle;
+ param.srcMemoryType = CU_MEMORYTYPE_HOST;
+ param.srcHost = (void*)mem.data_pointer;
+ param.srcPitch = mem.data_width*dsize*mem.data_elements;
+ param.WidthInBytes = param.srcPitch;
+ param.Height = mem.data_height;
+ param.Depth = mem.data_depth;
+
+ cuda_assert(cuMemcpy3D(&param));
}
+ else if(mem.data_height > 1) {
+ CUDA_MEMCPY2D param;
+ memset(&param, 0, sizeof(param));
+ param.dstMemoryType = CU_MEMORYTYPE_ARRAY;
+ param.dstArray = handle;
+ param.srcMemoryType = CU_MEMORYTYPE_HOST;
+ param.srcHost = (void*)mem.data_pointer;
+ param.srcPitch = mem.data_width*dsize*mem.data_elements;
+ param.WidthInBytes = param.srcPitch;
+ param.Height = mem.data_height;
+
+ cuda_assert(cuMemcpy2D(&param));
+ }
+ else
+ cuda_assert(cuMemcpyHtoA(handle, 0, (void*)mem.data_pointer, size));
- cuda_assert(cuTexRefSetFormat(texref, format, mem.data_elements));
+ /* Fermi and Kepler */
+ mem.device_pointer = (device_ptr)handle;
+ mem.device_size = size;
- cuda_pop_context();
- }
- else {
- mem_alloc(mem, MEM_READ_ONLY);
- mem_copy_to(mem);
+ stats.mem_alloc(size);
- cuda_push_context();
+ /* Bindless Textures - Kepler */
+ if(has_bindless_textures) {
+ int flat_slot = 0;
+ if(string_startswith(name, "__tex_image")) {
+ int pos = string(name).rfind("_");
+ flat_slot = atoi(name + pos + 1);
+ }
+ else {
+ assert(0);
+ }
- CUdeviceptr cumem;
- size_t cubytes;
+ CUDA_RESOURCE_DESC resDesc;
+ memset(&resDesc, 0, sizeof(resDesc));
+ resDesc.resType = CU_RESOURCE_TYPE_ARRAY;
+ resDesc.res.array.hArray = handle;
+ resDesc.flags = 0;
+
+ CUDA_TEXTURE_DESC texDesc;
+ memset(&texDesc, 0, sizeof(texDesc));
+ texDesc.addressMode[0] = address_mode;
+ texDesc.addressMode[1] = address_mode;
+ texDesc.addressMode[2] = address_mode;
+ texDesc.filterMode = filter_mode;
+ texDesc.flags = CU_TRSF_NORMALIZED_COORDINATES;
+
+ CUtexObject tex = 0;
+ cuda_assert(cuTexObjectCreate(&tex, &resDesc, &texDesc, NULL));
+
+ /* Safety check */
+ if((uint)tex > UINT_MAX) {
+ assert(0);
+ }
- cuda_assert(cuModuleGetGlobal(&cumem, &cubytes, cuModule, bind_name.c_str()));
+ /* Resize once */
+ if(flat_slot >= bindless_mapping.size()) {
+ /* Allocate some slots in advance, to reduce amount
+ * of re-allocations.
+ */
+ bindless_mapping.resize(flat_slot + 128);
+ }
- if(cubytes == 8) {
- /* 64 bit device pointer */
- uint64_t ptr = mem.device_pointer;
- cuda_assert(cuMemcpyHtoD(cumem, (void*)&ptr, cubytes));
+ /* Set Mapping and tag that we need to (re-)upload to device */
+ bindless_mapping.get_data()[flat_slot] = (uint)tex;
+ tex_bindless_map[mem.device_pointer] = (uint)tex;
+ need_bindless_mapping = true;
}
+ /* Regular Textures - Fermi */
else {
- /* 32 bit device pointer */
- uint32_t ptr = (uint32_t)mem.device_pointer;
- cuda_assert(cuMemcpyHtoD(cumem, (void*)&ptr, cubytes));
+ cuda_assert(cuTexRefSetArray(texref, handle, CU_TRSA_OVERRIDE_FORMAT));
+ cuda_assert(cuTexRefSetFilterMode(texref, filter_mode));
+ cuda_assert(cuTexRefSetFlags(texref, CU_TRSF_NORMALIZED_COORDINATES));
+ }
+
+ cuda_pop_context();
+ }
+
+ /* Fermi, Data and Image Textures */
+ if(!has_bindless_textures) {
+ cuda_push_context();
+
+ cuda_assert(cuTexRefSetAddressMode(texref, 0, address_mode));
+ cuda_assert(cuTexRefSetAddressMode(texref, 1, address_mode));
+ if(mem.data_depth > 1) {
+ cuda_assert(cuTexRefSetAddressMode(texref, 2, address_mode));
}
+ cuda_assert(cuTexRefSetFormat(texref, format, mem.data_elements));
+
cuda_pop_context();
}
+ /* Fermi and Kepler */
tex_interp_map[mem.device_pointer] = (interpolation != INTERPOLATION_NONE);
}
@@ -670,6 +797,12 @@ public:
cuArrayDestroy((CUarray)mem.device_pointer);
cuda_pop_context();
+ /* Free CUtexObject (Bindless Textures) */
+ if(info.has_bindless_textures && tex_bindless_map[mem.device_pointer]) {
+ uint flat_slot = tex_bindless_map[mem.device_pointer];
+ cuTexObjectDestroy(flat_slot);
+ }
+
tex_interp_map.erase(tex_interp_map.find(mem.device_pointer));
mem.device_pointer = 0;
@@ -726,8 +859,8 @@ public:
printf("threads_per_block %d\n", threads_per_block);
printf("num_registers %d\n", num_registers);*/
- int xthreads = (int)sqrt((float)threads_per_block);
- int ythreads = (int)sqrt((float)threads_per_block);
+ int xthreads = (int)sqrt(threads_per_block);
+ int ythreads = (int)sqrt(threads_per_block);
int xblocks = (rtile.w + xthreads - 1)/xthreads;
int yblocks = (rtile.h + ythreads - 1)/ythreads;
@@ -780,8 +913,8 @@ public:
int threads_per_block;
cuda_assert(cuFuncGetAttribute(&threads_per_block, CU_FUNC_ATTRIBUTE_MAX_THREADS_PER_BLOCK, cuFilmConvert));
- int xthreads = (int)sqrt((float)threads_per_block);
- int ythreads = (int)sqrt((float)threads_per_block);
+ int xthreads = (int)sqrt(threads_per_block);
+ int ythreads = (int)sqrt(threads_per_block);
int xblocks = (task.w + xthreads - 1)/xthreads;
int yblocks = (task.h + ythreads - 1)/ythreads;
@@ -860,7 +993,7 @@ public:
cuda_assert(cuCtxSynchronize());
if(task.get_cancel()) {
- canceled = false;
+ canceled = true;
break;
}
}
@@ -876,11 +1009,11 @@ public:
if(!background) {
PixelMem pmem = pixel_mem_map[mem];
CUdeviceptr buffer;
-
+
size_t bytes;
cuda_assert(cuGraphicsMapResources(1, &pmem.cuPBOresource, 0));
cuda_assert(cuGraphicsResourceGetMappedPointer(&buffer, &bytes, pmem.cuPBOresource));
-
+
return buffer;
}
@@ -912,9 +1045,9 @@ public:
glBufferData(GL_PIXEL_UNPACK_BUFFER, pmem.w*pmem.h*sizeof(GLhalf)*4, NULL, GL_DYNAMIC_DRAW);
else
glBufferData(GL_PIXEL_UNPACK_BUFFER, pmem.w*pmem.h*sizeof(uint8_t)*4, NULL, GL_DYNAMIC_DRAW);
-
+
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
-
+
glGenTextures(1, &pmem.cuTexId);
glBindTexture(GL_TEXTURE_2D, pmem.cuTexId);
if(mem.data_type == TYPE_HALF)
@@ -924,7 +1057,7 @@ public:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);
-
+
CUresult result = cuGraphicsGLRegisterBuffer(&pmem.cuPBOresource, pmem.cuPBO, CU_GRAPHICS_MAP_RESOURCE_FLAGS_NONE);
if(result == CUDA_SUCCESS) {
@@ -1026,9 +1159,9 @@ public:
else
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)offset);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
-
+
glEnable(GL_TEXTURE_2D);
-
+
if(transparent) {
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
@@ -1093,7 +1226,7 @@ public:
if(transparent)
glDisable(GL_BLEND);
-
+
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
@@ -1109,9 +1242,12 @@ public:
{
if(task->type == DeviceTask::PATH_TRACE) {
RenderTile tile;
-
+
bool branched = task->integrator_branched;
-
+
+ /* Upload Bindless Mapping */
+ load_bindless_mapping();
+
/* keep rendering tiles until done */
while(task->acquire_tile(this, tile)) {
int start_sample = tile.start_sample;
@@ -1134,6 +1270,9 @@ public:
}
}
else if(task->type == DeviceTask::SHADER) {
+ /* Upload Bindless Mapping */
+ load_bindless_mapping();
+
shader(*task);
cuda_push_context();
@@ -1245,7 +1384,7 @@ void device_cuda_info(vector<DeviceInfo>& devices)
fprintf(stderr, "CUDA cuDeviceGetCount: %s\n", cuewErrorString(result));
return;
}
-
+
vector<DeviceInfo> display_devices;
for(int num = 0; num < count; num++) {
@@ -1269,11 +1408,12 @@ void device_cuda_info(vector<DeviceInfo>& devices)
info.num = num;
info.advanced_shading = (major >= 2);
- info.extended_images = (major >= 3);
+ info.has_bindless_textures = (major >= 3);
info.pack_images = false;
/* if device has a kernel timeout, assume it is used for display */
if(cuDeviceGetAttribute(&attr, CU_DEVICE_ATTRIBUTE_KERNEL_EXEC_TIMEOUT, num) == CUDA_SUCCESS && attr == 1) {
+ info.description += " (Display)";
info.display_device = true;
display_devices.push_back(info);
}
diff --git a/intern/cycles/device/device_memory.h b/intern/cycles/device/device_memory.h
index 8c32d03135e..5b5b4dc6802 100644
--- a/intern/cycles/device/device_memory.h
+++ b/intern/cycles/device/device_memory.h
@@ -150,6 +150,11 @@ template<> struct device_type_traits<float4> {
static const int num_elements = 4;
};
+template<> struct device_type_traits<half> {
+ static const DataType data_type = TYPE_HALF;
+ static const int num_elements = 1;
+};
+
template<> struct device_type_traits<half4> {
static const DataType data_type = TYPE_HALF;
static const int num_elements = 4;
diff --git a/intern/cycles/device/device_multi.cpp b/intern/cycles/device/device_multi.cpp
index 069305e8a29..ef257358b22 100644
--- a/intern/cycles/device/device_multi.cpp
+++ b/intern/cycles/device/device_multi.cpp
@@ -35,7 +35,7 @@ class MultiDevice : public Device
{
public:
struct SubDevice {
- SubDevice(Device *device_)
+ explicit SubDevice(Device *device_)
: device(device_) {}
Device *device;
@@ -51,7 +51,7 @@ public:
Device *device;
foreach(DeviceInfo& subinfo, info.multi_devices) {
- device = Device::create(subinfo, stats, background);
+ device = Device::create(subinfo, sub_stats_, background);
devices.push_back(SubDevice(device));
}
@@ -107,6 +107,7 @@ public:
}
mem.device_pointer = unique_ptr++;
+ stats.mem_alloc(mem.device_size);
}
void mem_copy_to(device_memory& mem)
@@ -161,6 +162,7 @@ public:
}
mem.device_pointer = 0;
+ stats.mem_free(mem.device_size);
}
void const_copy_to(const char *name, void *host, size_t size)
@@ -175,7 +177,9 @@ public:
interpolation,
ExtensionType extension)
{
- VLOG(1) << "Texture allocate: " << name << ", " << mem.memory_size() << " bytes.";
+ VLOG(1) << "Texture allocate: " << name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
foreach(SubDevice& sub, devices) {
mem.device_pointer = 0;
@@ -184,6 +188,7 @@ public:
}
mem.device_pointer = unique_ptr++;
+ stats.mem_alloc(mem.device_size);
}
void tex_free(device_memory& mem)
@@ -197,6 +202,7 @@ public:
}
mem.device_pointer = 0;
+ stats.mem_free(mem.device_size);
}
void pixels_alloc(device_memory& mem)
@@ -334,6 +340,9 @@ public:
foreach(SubDevice& sub, devices)
sub.device->task_cancel();
}
+
+protected:
+ Stats sub_stats_;
};
Device *device_multi_create(DeviceInfo& info, Stats &stats, bool background)
@@ -352,7 +361,7 @@ static bool device_multi_add(vector<DeviceInfo>& devices, DeviceType type, bool
info.advanced_shading = with_advanced_shading;
info.pack_images = false;
- info.extended_images = true;
+ info.has_bindless_textures = true;
foreach(DeviceInfo& subinfo, devices) {
if(subinfo.type == type) {
@@ -376,7 +385,7 @@ static bool device_multi_add(vector<DeviceInfo>& devices, DeviceType type, bool
if(subinfo.display_device)
info.display_device = true;
info.pack_images = info.pack_images || subinfo.pack_images;
- info.extended_images = info.extended_images && subinfo.extended_images;
+ info.has_bindless_textures = info.has_bindless_textures && subinfo.has_bindless_textures;
num_added++;
}
}
diff --git a/intern/cycles/device/device_network.cpp b/intern/cycles/device/device_network.cpp
index cf4a05de8fc..3eb5ad2d2db 100644
--- a/intern/cycles/device/device_network.cpp
+++ b/intern/cycles/device/device_network.cpp
@@ -168,7 +168,9 @@ public:
InterpolationType interpolation,
ExtensionType extension)
{
- VLOG(1) << "Texture allocate: " << name << ", " << mem.memory_size() << " bytes.";
+ VLOG(1) << "Texture allocate: " << name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
thread_scoped_lock lock(rpc_lock);
diff --git a/intern/cycles/device/device_network.h b/intern/cycles/device/device_network.h
index 60ecc1d0a86..d28cfe3121f 100644
--- a/intern/cycles/device/device_network.h
+++ b/intern/cycles/device/device_network.h
@@ -322,7 +322,7 @@ protected:
class ServerDiscovery {
public:
- ServerDiscovery(bool discover = false)
+ explicit ServerDiscovery(bool discover = false)
: listen_socket(io_service), collect_servers(false)
{
/* setup listen socket */
diff --git a/intern/cycles/device/device_opencl.cpp b/intern/cycles/device/device_opencl.cpp
index 1b4e5421b5a..45cf6b074e9 100644
--- a/intern/cycles/device/device_opencl.cpp
+++ b/intern/cycles/device/device_opencl.cpp
@@ -16,3230 +16,29 @@
#ifdef WITH_OPENCL
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+#include "opencl/opencl.h"
-#include "clew.h"
-
-#include "device.h"
#include "device_intern.h"
-#include "buffers.h"
-
-#include "util_debug.h"
#include "util_foreach.h"
#include "util_logging.h"
-#include "util_map.h"
-#include "util_math.h"
-#include "util_md5.h"
-#include "util_opengl.h"
-#include "util_path.h"
-#include "util_time.h"
CCL_NAMESPACE_BEGIN
-#define CL_MEM_PTR(p) ((cl_mem)(uintptr_t)(p))
-
-/* Macro declarations used with split kernel */
-
-/* Macro to enable/disable work-stealing */
-#define __WORK_STEALING__
-
-#define SPLIT_KERNEL_LOCAL_SIZE_X 64
-#define SPLIT_KERNEL_LOCAL_SIZE_Y 1
-
-/* This value may be tuned according to the scene we are rendering.
- *
- * Modifying PATH_ITER_INC_FACTOR value proportional to number of expected
- * ray-bounces will improve performance.
- */
-#define PATH_ITER_INC_FACTOR 8
-
-/* When allocate global memory in chunks. We may not be able to
- * allocate exactly "CL_DEVICE_MAX_MEM_ALLOC_SIZE" bytes in chunks;
- * Since some bytes may be needed for aligning chunks of memory;
- * This is the amount of memory that we dedicate for that purpose.
- */
-#define DATA_ALLOCATION_MEM_FACTOR 5000000 //5MB
-
-struct OpenCLPlatformDevice {
- OpenCLPlatformDevice(cl_platform_id platform_id,
- const string& platform_name,
- cl_device_id device_id,
- cl_device_type device_type,
- const string& device_name)
- : platform_id(platform_id),
- platform_name(platform_name),
- device_id(device_id),
- device_type(device_type),
- device_name(device_name) {}
- cl_platform_id platform_id;
- string platform_name;
- cl_device_id device_id;
- cl_device_type device_type;
- string device_name;
-};
-
-namespace {
-
-cl_device_type opencl_device_type()
-{
- switch(DebugFlags().opencl.device_type)
- {
- case DebugFlags::OpenCL::DEVICE_NONE:
- return 0;
- case DebugFlags::OpenCL::DEVICE_ALL:
- return CL_DEVICE_TYPE_ALL;
- case DebugFlags::OpenCL::DEVICE_DEFAULT:
- return CL_DEVICE_TYPE_DEFAULT;
- case DebugFlags::OpenCL::DEVICE_CPU:
- return CL_DEVICE_TYPE_CPU;
- case DebugFlags::OpenCL::DEVICE_GPU:
- return CL_DEVICE_TYPE_GPU;
- case DebugFlags::OpenCL::DEVICE_ACCELERATOR:
- return CL_DEVICE_TYPE_ACCELERATOR;
- default:
- return CL_DEVICE_TYPE_ALL;
- }
-}
-
-inline bool opencl_kernel_use_debug()
-{
- return DebugFlags().opencl.debug;
-}
-
-bool opencl_kernel_use_advanced_shading(const string& platform)
-{
- /* keep this in sync with kernel_types.h! */
- if(platform == "NVIDIA CUDA")
- return true;
- else if(platform == "Apple")
- return true;
- else if(platform == "AMD Accelerated Parallel Processing")
- return true;
- else if(platform == "Intel(R) OpenCL")
- return true;
- /* Make sure officially unsupported OpenCL platforms
- * does not set up to use advanced shading.
- */
- return false;
-}
-
-bool opencl_kernel_use_split(const string& platform_name,
- const cl_device_type device_type)
-{
- if(DebugFlags().opencl.kernel_type == DebugFlags::OpenCL::KERNEL_SPLIT) {
- VLOG(1) << "Forcing split kernel to use.";
- return true;
- }
- if(DebugFlags().opencl.kernel_type == DebugFlags::OpenCL::KERNEL_MEGA) {
- VLOG(1) << "Forcing mega kernel to use.";
- return false;
- }
- /* TODO(sergey): Replace string lookups with more enum-like API,
- * similar to device/vendor checks blender's gpu.
- */
- if(platform_name == "AMD Accelerated Parallel Processing" &&
- device_type == CL_DEVICE_TYPE_GPU)
- {
- return true;
- }
- return false;
-}
-
-bool opencl_device_supported(const string& platform_name,
- const cl_device_id device_id)
-{
- cl_device_type device_type;
- clGetDeviceInfo(device_id,
- CL_DEVICE_TYPE,
- sizeof(cl_device_type),
- &device_type,
- NULL);
- if(platform_name == "AMD Accelerated Parallel Processing" &&
- device_type == CL_DEVICE_TYPE_GPU)
- {
- return true;
- }
- if(platform_name == "Apple" && device_type == CL_DEVICE_TYPE_GPU) {
- return true;
- }
- return false;
-}
-
-bool opencl_platform_version_check(cl_platform_id platform,
- string *error = NULL)
-{
- const int req_major = 1, req_minor = 1;
- int major, minor;
- char version[256];
- clGetPlatformInfo(platform,
- CL_PLATFORM_VERSION,
- sizeof(version),
- &version,
- NULL);
- if(sscanf(version, "OpenCL %d.%d", &major, &minor) < 2) {
- if(error != NULL) {
- *error = string_printf("OpenCL: failed to parse platform version string (%s).", version);
- }
- return false;
- }
- if(!((major == req_major && minor >= req_minor) || (major > req_major))) {
- if(error != NULL) {
- *error = string_printf("OpenCL: platform version 1.1 or later required, found %d.%d", major, minor);
- }
- return false;
- }
- if(error != NULL) {
- *error = "";
- }
- return true;
-}
-
-bool opencl_device_version_check(cl_device_id device,
- string *error = NULL)
-{
- const int req_major = 1, req_minor = 1;
- int major, minor;
- char version[256];
- clGetDeviceInfo(device,
- CL_DEVICE_OPENCL_C_VERSION,
- sizeof(version),
- &version,
- NULL);
- if(sscanf(version, "OpenCL C %d.%d", &major, &minor) < 2) {
- if(error != NULL) {
- *error = string_printf("OpenCL: failed to parse OpenCL C version string (%s).", version);
- }
- return false;
- }
- if(!((major == req_major && minor >= req_minor) || (major > req_major))) {
- if(error != NULL) {
- *error = string_printf("OpenCL: C version 1.1 or later required, found %d.%d", major, minor);
- }
- return false;
- }
- if(error != NULL) {
- *error = "";
- }
- return true;
-}
-
-void opencl_get_usable_devices(vector<OpenCLPlatformDevice> *usable_devices)
-{
- const bool force_all_platforms =
- (DebugFlags().opencl.kernel_type != DebugFlags::OpenCL::KERNEL_DEFAULT);
- const cl_device_type device_type = opencl_device_type();
- static bool first_time = true;
-#define FIRST_VLOG(severity) if(first_time) VLOG(severity)
-
- usable_devices->clear();
-
- if(device_type == 0) {
- FIRST_VLOG(2) << "OpenCL devices are forced to be disabled.";
- first_time = false;
- return;
- }
-
- vector<cl_device_id> device_ids;
- cl_uint num_devices = 0;
- vector<cl_platform_id> platform_ids;
- cl_uint num_platforms = 0;
-
- /* Get devices. */
- if(clGetPlatformIDs(0, NULL, &num_platforms) != CL_SUCCESS ||
- num_platforms == 0)
- {
- FIRST_VLOG(2) << "No OpenCL platforms were found.";
- first_time = false;
- return;
- }
- platform_ids.resize(num_platforms);
- if(clGetPlatformIDs(num_platforms, &platform_ids[0], NULL) != CL_SUCCESS) {
- FIRST_VLOG(2) << "Failed to fetch platform IDs from the driver..";
- first_time = false;
- return;
- }
- /* Devices are numbered consecutively across platforms. */
- for(int platform = 0; platform < num_platforms; platform++) {
- cl_platform_id platform_id = platform_ids[platform];
- char pname[256];
- if(clGetPlatformInfo(platform_id,
- CL_PLATFORM_NAME,
- sizeof(pname),
- &pname,
- NULL) != CL_SUCCESS)
- {
- FIRST_VLOG(2) << "Failed to get platform name, ignoring.";
- continue;
- }
- string platform_name = pname;
- FIRST_VLOG(2) << "Enumerating devices for platform "
- << platform_name << ".";
- if(!opencl_platform_version_check(platform_id)) {
- FIRST_VLOG(2) << "Ignoring platform " << platform_name
- << " due to too old compiler version.";
- continue;
- }
- num_devices = 0;
- if(clGetDeviceIDs(platform_id,
- device_type,
- 0,
- NULL,
- &num_devices) != CL_SUCCESS || num_devices == 0)
- {
- FIRST_VLOG(2) << "Ignoring platform " << platform_name
- << ", failed to fetch number of devices.";
- continue;
- }
- device_ids.resize(num_devices);
- if(clGetDeviceIDs(platform_id,
- device_type,
- num_devices,
- &device_ids[0],
- NULL) != CL_SUCCESS)
- {
- FIRST_VLOG(2) << "Ignoring platform " << platform_name
- << ", failed to fetch devices list.";
- continue;
- }
- for(int num = 0; num < num_devices; num++) {
- cl_device_id device_id = device_ids[num];
- char device_name[1024] = "\0";
- if(clGetDeviceInfo(device_id,
- CL_DEVICE_NAME,
- sizeof(device_name),
- &device_name,
- NULL) != CL_SUCCESS)
- {
- FIRST_VLOG(2) << "Failed to fetch device name, ignoring.";
- continue;
- }
- if(!opencl_device_version_check(device_id)) {
- FIRST_VLOG(2) << "Ignoring device " << device_name
- << " due to old compiler version.";
- continue;
- }
- if(force_all_platforms ||
- opencl_device_supported(platform_name, device_id))
- {
- cl_device_type device_type;
- if(clGetDeviceInfo(device_id,
- CL_DEVICE_TYPE,
- sizeof(cl_device_type),
- &device_type,
- NULL) != CL_SUCCESS)
- {
- FIRST_VLOG(2) << "Ignoring device " << device_name
- << ", failed to fetch device type.";
- continue;
- }
- FIRST_VLOG(2) << "Adding new device " << device_name << ".";
- usable_devices->push_back(OpenCLPlatformDevice(platform_id,
- platform_name,
- device_id,
- device_type,
- device_name));
- }
- else {
- FIRST_VLOG(2) << "Ignoring device " << device_name
- << ", not officially supported yet.";
- }
- }
- }
- first_time = false;
-}
-
-} /* namespace */
-
-/* Thread safe cache for contexts and programs.
- *
- * TODO(sergey): Make it more generous, so it can contain any type of program
- * without hardcoding possible program types in the slot.
- */
-class OpenCLCache
-{
- struct Slot
- {
- thread_mutex *mutex;
- cl_context context;
- /* cl_program for shader, bake, film_convert kernels (used in OpenCLDeviceBase) */
- cl_program ocl_dev_base_program;
- /* cl_program for megakernel (used in OpenCLDeviceMegaKernel) */
- cl_program ocl_dev_megakernel_program;
-
- Slot() : mutex(NULL),
- context(NULL),
- ocl_dev_base_program(NULL),
- ocl_dev_megakernel_program(NULL) {}
-
- Slot(const Slot& rhs)
- : mutex(rhs.mutex),
- context(rhs.context),
- ocl_dev_base_program(rhs.ocl_dev_base_program),
- ocl_dev_megakernel_program(rhs.ocl_dev_megakernel_program)
- {
- /* copy can only happen in map insert, assert that */
- assert(mutex == NULL);
- }
-
- ~Slot()
- {
- delete mutex;
- mutex = NULL;
- }
- };
-
- /* key is combination of platform ID and device ID */
- typedef pair<cl_platform_id, cl_device_id> PlatformDevicePair;
-
- /* map of Slot objects */
- typedef map<PlatformDevicePair, Slot> CacheMap;
- CacheMap cache;
-
- thread_mutex cache_lock;
-
- /* lazy instantiate */
- static OpenCLCache &global_instance()
- {
- static OpenCLCache instance;
- return instance;
- }
-
- OpenCLCache()
- {
- }
-
- ~OpenCLCache()
- {
- /* Intel OpenCL bug raises SIGABRT due to pure virtual call
- * so this is disabled. It's not necessary to free objects
- * at process exit anyway.
- * http://software.intel.com/en-us/forums/topic/370083#comments */
-
- //flush();
- }
-
- /* lookup something in the cache. If this returns NULL, slot_locker
- * will be holding a lock for the cache. slot_locker should refer to a
- * default constructed thread_scoped_lock */
- template<typename T>
- static T get_something(cl_platform_id platform,
- cl_device_id device,
- T Slot::*member,
- thread_scoped_lock& slot_locker)
- {
- assert(platform != NULL);
-
- OpenCLCache& self = global_instance();
-
- thread_scoped_lock cache_lock(self.cache_lock);
-
- pair<CacheMap::iterator,bool> ins = self.cache.insert(
- CacheMap::value_type(PlatformDevicePair(platform, device), Slot()));
-
- Slot &slot = ins.first->second;
-
- /* create slot lock only while holding cache lock */
- if(!slot.mutex)
- slot.mutex = new thread_mutex;
-
- /* need to unlock cache before locking slot, to allow store to complete */
- cache_lock.unlock();
-
- /* lock the slot */
- slot_locker = thread_scoped_lock(*slot.mutex);
-
- /* If the thing isn't cached */
- if(slot.*member == NULL) {
- /* return with the caller's lock holder holding the slot lock */
- return NULL;
- }
-
- /* the item was already cached, release the slot lock */
- slot_locker.unlock();
-
- return slot.*member;
- }
-
- /* store something in the cache. you MUST have tried to get the item before storing to it */
- template<typename T>
- static void store_something(cl_platform_id platform,
- cl_device_id device,
- T thing,
- T Slot::*member,
- thread_scoped_lock& slot_locker)
- {
- assert(platform != NULL);
- assert(device != NULL);
- assert(thing != NULL);
-
- OpenCLCache &self = global_instance();
-
- thread_scoped_lock cache_lock(self.cache_lock);
- CacheMap::iterator i = self.cache.find(PlatformDevicePair(platform, device));
- cache_lock.unlock();
-
- Slot &slot = i->second;
-
- /* sanity check */
- assert(i != self.cache.end());
- assert(slot.*member == NULL);
-
- slot.*member = thing;
-
- /* unlock the slot */
- slot_locker.unlock();
- }
-
-public:
-
- enum ProgramName {
- OCL_DEV_BASE_PROGRAM,
- OCL_DEV_MEGAKERNEL_PROGRAM,
- };
-
- /* see get_something comment */
- static cl_context get_context(cl_platform_id platform,
- cl_device_id device,
- thread_scoped_lock& slot_locker)
- {
- cl_context context = get_something<cl_context>(platform,
- device,
- &Slot::context,
- slot_locker);
-
- if(!context)
- return NULL;
-
- /* caller is going to release it when done with it, so retain it */
- cl_int ciErr = clRetainContext(context);
- assert(ciErr == CL_SUCCESS);
- (void)ciErr;
-
- return context;
- }
-
- /* see get_something comment */
- static cl_program get_program(cl_platform_id platform,
- cl_device_id device,
- ProgramName program_name,
- thread_scoped_lock& slot_locker)
- {
- cl_program program = NULL;
-
- switch(program_name) {
- case OCL_DEV_BASE_PROGRAM:
- /* Get program related to OpenCLDeviceBase */
- program = get_something<cl_program>(platform,
- device,
- &Slot::ocl_dev_base_program,
- slot_locker);
- break;
- case OCL_DEV_MEGAKERNEL_PROGRAM:
- /* Get program related to megakernel */
- program = get_something<cl_program>(platform,
- device,
- &Slot::ocl_dev_megakernel_program,
- slot_locker);
- break;
- default:
- assert(!"Invalid program name");
- }
-
- if(!program)
- return NULL;
-
- /* caller is going to release it when done with it, so retain it */
- cl_int ciErr = clRetainProgram(program);
- assert(ciErr == CL_SUCCESS);
- (void)ciErr;
-
- return program;
- }
-
- /* see store_something comment */
- static void store_context(cl_platform_id platform,
- cl_device_id device,
- cl_context context,
- thread_scoped_lock& slot_locker)
- {
- store_something<cl_context>(platform,
- device,
- context,
- &Slot::context,
- slot_locker);
-
- /* increment reference count in OpenCL.
- * The caller is going to release the object when done with it. */
- cl_int ciErr = clRetainContext(context);
- assert(ciErr == CL_SUCCESS);
- (void)ciErr;
- }
-
- /* see store_something comment */
- static void store_program(cl_platform_id platform,
- cl_device_id device,
- cl_program program,
- ProgramName program_name,
- thread_scoped_lock& slot_locker)
- {
- switch(program_name) {
- case OCL_DEV_BASE_PROGRAM:
- store_something<cl_program>(platform,
- device,
- program,
- &Slot::ocl_dev_base_program,
- slot_locker);
- break;
- case OCL_DEV_MEGAKERNEL_PROGRAM:
- store_something<cl_program>(platform,
- device,
- program,
- &Slot::ocl_dev_megakernel_program,
- slot_locker);
- break;
- default:
- assert(!"Invalid program name\n");
- return;
- }
-
- /* Increment reference count in OpenCL.
- * The caller is going to release the object when done with it.
- */
- cl_int ciErr = clRetainProgram(program);
- assert(ciErr == CL_SUCCESS);
- (void)ciErr;
- }
-
- /* Discard all cached contexts and programs. */
- static void flush()
- {
- OpenCLCache &self = global_instance();
- thread_scoped_lock cache_lock(self.cache_lock);
-
- foreach(CacheMap::value_type &item, self.cache) {
- if(item.second.ocl_dev_base_program != NULL)
- clReleaseProgram(item.second.ocl_dev_base_program);
- if(item.second.ocl_dev_megakernel_program != NULL)
- clReleaseProgram(item.second.ocl_dev_megakernel_program);
- if(item.second.context != NULL)
- clReleaseContext(item.second.context);
- }
-
- self.cache.clear();
- }
-};
-
-class OpenCLDeviceBase : public Device
-{
-public:
- DedicatedTaskPool task_pool;
- cl_context cxContext;
- cl_command_queue cqCommandQueue;
- cl_platform_id cpPlatform;
- cl_device_id cdDevice;
- cl_program cpProgram;
- cl_kernel ckFilmConvertByteKernel;
- cl_kernel ckFilmConvertHalfFloatKernel;
- cl_kernel ckShaderKernel;
- cl_kernel ckBakeKernel;
- cl_int ciErr;
-
- typedef map<string, device_vector<uchar>*> ConstMemMap;
- typedef map<string, device_ptr> MemMap;
-
- ConstMemMap const_mem_map;
- MemMap mem_map;
- device_ptr null_mem;
-
- bool device_initialized;
- string platform_name;
-
- bool opencl_error(cl_int err)
- {
- if(err != CL_SUCCESS) {
- string message = string_printf("OpenCL error (%d): %s", err, clewErrorString(err));
- if(error_msg == "")
- error_msg = message;
- fprintf(stderr, "%s\n", message.c_str());
- return true;
- }
-
- return false;
- }
-
- void opencl_error(const string& message)
- {
- if(error_msg == "")
- error_msg = message;
- fprintf(stderr, "%s\n", message.c_str());
- }
-
-#define opencl_assert(stmt) \
- { \
- cl_int err = stmt; \
- \
- if(err != CL_SUCCESS) { \
- string message = string_printf("OpenCL error: %s in %s", clewErrorString(err), #stmt); \
- if(error_msg == "") \
- error_msg = message; \
- fprintf(stderr, "%s\n", message.c_str()); \
- } \
- } (void)0
-
- void opencl_assert_err(cl_int err, const char* where)
- {
- if(err != CL_SUCCESS) {
- string message = string_printf("OpenCL error (%d): %s in %s", err, clewErrorString(err), where);
- if(error_msg == "")
- error_msg = message;
- fprintf(stderr, "%s\n", message.c_str());
-#ifndef NDEBUG
- abort();
-#endif
- }
- }
-
- OpenCLDeviceBase(DeviceInfo& info, Stats &stats, bool background_)
- : Device(info, stats, background_)
- {
- cpPlatform = NULL;
- cdDevice = NULL;
- cxContext = NULL;
- cqCommandQueue = NULL;
- cpProgram = NULL;
- ckFilmConvertByteKernel = NULL;
- ckFilmConvertHalfFloatKernel = NULL;
- ckShaderKernel = NULL;
- ckBakeKernel = NULL;
- null_mem = 0;
- device_initialized = false;
-
- vector<OpenCLPlatformDevice> usable_devices;
- opencl_get_usable_devices(&usable_devices);
- if(usable_devices.size() == 0) {
- opencl_error("OpenCL: no devices found.");
- return;
- }
- assert(info.num < usable_devices.size());
- OpenCLPlatformDevice& platform_device = usable_devices[info.num];
- cpPlatform = platform_device.platform_id;
- cdDevice = platform_device.device_id;
- platform_name = platform_device.platform_name;
- VLOG(2) << "Creating new Cycles device for OpenCL platform "
- << platform_name << ", device "
- << platform_device.device_name << ".";
-
- {
- /* try to use cached context */
- thread_scoped_lock cache_locker;
- cxContext = OpenCLCache::get_context(cpPlatform, cdDevice, cache_locker);
-
- if(cxContext == NULL) {
- /* create context properties array to specify platform */
- const cl_context_properties context_props[] = {
- CL_CONTEXT_PLATFORM, (cl_context_properties)cpPlatform,
- 0, 0
- };
-
- /* create context */
- cxContext = clCreateContext(context_props, 1, &cdDevice,
- context_notify_callback, cdDevice, &ciErr);
-
- if(opencl_error(ciErr)) {
- opencl_error("OpenCL: clCreateContext failed");
- return;
- }
-
- /* cache it */
- OpenCLCache::store_context(cpPlatform, cdDevice, cxContext, cache_locker);
- }
- }
-
- cqCommandQueue = clCreateCommandQueue(cxContext, cdDevice, 0, &ciErr);
- if(opencl_error(ciErr))
- return;
-
- null_mem = (device_ptr)clCreateBuffer(cxContext, CL_MEM_READ_ONLY, 1, NULL, &ciErr);
- if(opencl_error(ciErr))
- return;
-
- fprintf(stderr, "Device init success\n");
- device_initialized = true;
- }
-
- static void CL_CALLBACK context_notify_callback(const char *err_info,
- const void * /*private_info*/, size_t /*cb*/, void *user_data)
- {
- char name[256];
- clGetDeviceInfo((cl_device_id)user_data, CL_DEVICE_NAME, sizeof(name), &name, NULL);
-
- fprintf(stderr, "OpenCL error (%s): %s\n", name, err_info);
- }
-
- bool opencl_version_check()
- {
- string error;
- if(!opencl_platform_version_check(cpPlatform, &error)) {
- opencl_error(error);
- return false;
- }
- if(!opencl_device_version_check(cdDevice, &error)) {
- opencl_error(error);
- return false;
- }
- return true;
- }
-
- bool load_binary(const string& /*kernel_path*/,
- const string& clbin,
- string custom_kernel_build_options,
- cl_program *program,
- const string *debug_src = NULL)
- {
- /* read binary into memory */
- vector<uint8_t> binary;
-
- if(!path_read_binary(clbin, binary)) {
- opencl_error(string_printf("OpenCL failed to read cached binary %s.", clbin.c_str()));
- return false;
- }
-
- /* create program */
- cl_int status;
- size_t size = binary.size();
- const uint8_t *bytes = &binary[0];
-
- *program = clCreateProgramWithBinary(cxContext, 1, &cdDevice,
- &size, &bytes, &status, &ciErr);
-
- if(opencl_error(status) || opencl_error(ciErr)) {
- opencl_error(string_printf("OpenCL failed create program from cached binary %s.", clbin.c_str()));
- return false;
- }
-
- if(!build_kernel(program, custom_kernel_build_options, debug_src))
- return false;
-
- return true;
- }
-
- bool save_binary(cl_program *program, const string& clbin)
- {
- size_t size = 0;
- clGetProgramInfo(*program, CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &size, NULL);
-
- if(!size)
- return false;
-
- vector<uint8_t> binary(size);
- uint8_t *bytes = &binary[0];
-
- clGetProgramInfo(*program, CL_PROGRAM_BINARIES, sizeof(uint8_t*), &bytes, NULL);
-
- if(!path_write_binary(clbin, binary)) {
- opencl_error(string_printf("OpenCL failed to write cached binary %s.", clbin.c_str()));
- return false;
- }
-
- return true;
- }
-
- bool build_kernel(cl_program *kernel_program,
- string custom_kernel_build_options,
- const string *debug_src = NULL)
- {
- string build_options;
- build_options = kernel_build_options(debug_src) + custom_kernel_build_options;
-
- ciErr = clBuildProgram(*kernel_program, 0, NULL, build_options.c_str(), NULL, NULL);
-
- /* show warnings even if build is successful */
- size_t ret_val_size = 0;
-
- clGetProgramBuildInfo(*kernel_program, cdDevice, CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size);
-
- if(ret_val_size > 1) {
- vector<char> build_log(ret_val_size + 1);
- clGetProgramBuildInfo(*kernel_program, cdDevice, CL_PROGRAM_BUILD_LOG, ret_val_size, &build_log[0], NULL);
-
- build_log[ret_val_size] = '\0';
- /* Skip meaningless empty output from the NVidia compiler. */
- if(!(ret_val_size == 2 && build_log[0] == '\n')) {
- fprintf(stderr, "OpenCL kernel build output:\n");
- fprintf(stderr, "%s\n", &build_log[0]);
- }
- }
-
- if(ciErr != CL_SUCCESS) {
- opencl_error("OpenCL build failed: errors in console");
- return false;
- }
-
- return true;
- }
-
- bool compile_kernel(const string& kernel_path,
- string source,
- string custom_kernel_build_options,
- cl_program *kernel_program,
- const string *debug_src = NULL)
- {
- /* we compile kernels consisting of many files. unfortunately opencl
- * kernel caches do not seem to recognize changes in included files.
- * so we force recompile on changes by adding the md5 hash of all files */
- source = path_source_replace_includes(source, kernel_path);
-
- if(debug_src)
- path_write_text(*debug_src, source);
-
- size_t source_len = source.size();
- const char *source_str = source.c_str();
-
- *kernel_program = clCreateProgramWithSource(cxContext, 1, &source_str, &source_len, &ciErr);
-
- if(opencl_error(ciErr))
- return false;
-
- double starttime = time_dt();
- printf("Compiling OpenCL kernel ...\n");
- /* TODO(sergey): Report which kernel is being compiled
- * as well (megakernel or which of split kernels etc..).
- */
- printf("Build flags: %s\n", custom_kernel_build_options.c_str());
-
- if(!build_kernel(kernel_program, custom_kernel_build_options, debug_src))
- return false;
-
- printf("Kernel compilation finished in %.2lfs.\n", time_dt() - starttime);
-
- return true;
- }
-
- string device_md5_hash(string kernel_custom_build_options = "")
- {
- MD5Hash md5;
- char version[256], driver[256], name[256], vendor[256];
-
- clGetPlatformInfo(cpPlatform, CL_PLATFORM_VENDOR, sizeof(vendor), &vendor, NULL);
- clGetDeviceInfo(cdDevice, CL_DEVICE_VERSION, sizeof(version), &version, NULL);
- clGetDeviceInfo(cdDevice, CL_DEVICE_NAME, sizeof(name), &name, NULL);
- clGetDeviceInfo(cdDevice, CL_DRIVER_VERSION, sizeof(driver), &driver, NULL);
-
- md5.append((uint8_t*)vendor, strlen(vendor));
- md5.append((uint8_t*)version, strlen(version));
- md5.append((uint8_t*)name, strlen(name));
- md5.append((uint8_t*)driver, strlen(driver));
-
- string options = kernel_build_options();
- options += kernel_custom_build_options;
- md5.append((uint8_t*)options.c_str(), options.size());
-
- return md5.get_hex();
- }
-
- bool load_kernels(const DeviceRequestedFeatures& requested_features)
- {
- /* Verify if device was initialized. */
- if(!device_initialized) {
- fprintf(stderr, "OpenCL: failed to initialize device.\n");
- return false;
- }
-
- /* Try to use cached kernel. */
- thread_scoped_lock cache_locker;
- cpProgram = load_cached_kernel(requested_features,
- OpenCLCache::OCL_DEV_BASE_PROGRAM,
- cache_locker);
-
- if(!cpProgram) {
- VLOG(2) << "No cached OpenCL kernel.";
-
- /* Verify we have right opencl version. */
- if(!opencl_version_check())
- return false;
-
- string build_flags = build_options_for_base_program(requested_features);
-
- /* Calculate md5 hashes to detect changes. */
- string kernel_path = path_get("kernel");
- string kernel_md5 = path_files_md5_hash(kernel_path);
- string device_md5 = device_md5_hash(build_flags);
-
- /* Path to cached binary.
- *
- * TODO(sergey): Seems we could de-duplicate all this string_printf()
- * calls with some utility function which will give file name for a
- * given hashes..
- */
- string clbin = string_printf("cycles_kernel_%s_%s.clbin",
- device_md5.c_str(),
- kernel_md5.c_str());
- clbin = path_user_get(path_join("cache", clbin));
-
- /* path to preprocessed source for debugging */
- string clsrc, *debug_src = NULL;
-
- if(opencl_kernel_use_debug()) {
- clsrc = string_printf("cycles_kernel_%s_%s.cl",
- device_md5.c_str(),
- kernel_md5.c_str());
- clsrc = path_user_get(path_join("cache", clsrc));
- debug_src = &clsrc;
- }
-
- /* If binary kernel exists already, try use it. */
- if(path_exists(clbin) && load_binary(kernel_path,
- clbin,
- build_flags,
- &cpProgram))
- {
- /* Kernel loaded from binary, nothing to do. */
- VLOG(2) << "Loaded kernel from " << clbin << ".";
- }
- else {
- VLOG(2) << "Kernel file " << clbin << " either doesn't exist or failed to be loaded by driver.";
- string init_kernel_source = "#include \"kernels/opencl/kernel.cl\" // " + kernel_md5 + "\n";
-
- /* If does not exist or loading binary failed, compile kernel. */
- if(!compile_kernel(kernel_path,
- init_kernel_source,
- build_flags,
- &cpProgram,
- debug_src))
- {
- return false;
- }
-
- /* Save binary for reuse. */
- if(!save_binary(&cpProgram, clbin)) {
- return false;
- }
- }
-
- /* Cache the program. */
- store_cached_kernel(cpPlatform,
- cdDevice,
- cpProgram,
- OpenCLCache::OCL_DEV_BASE_PROGRAM,
- cache_locker);
- }
- else {
- VLOG(2) << "Found cached OpenCL kernel.";
- }
-
- /* Find kernels. */
-#define FIND_KERNEL(kernel_var, kernel_name) \
- do { \
- kernel_var = clCreateKernel(cpProgram, "kernel_ocl_" kernel_name, &ciErr); \
- if(opencl_error(ciErr)) \
- return false; \
- } while(0)
-
- FIND_KERNEL(ckFilmConvertByteKernel, "convert_to_byte");
- FIND_KERNEL(ckFilmConvertHalfFloatKernel, "convert_to_half_float");
- FIND_KERNEL(ckShaderKernel, "shader");
- FIND_KERNEL(ckBakeKernel, "bake");
-
-#undef FIND_KERNEL
- return true;
- }
-
- ~OpenCLDeviceBase()
- {
- task_pool.stop();
-
- if(null_mem)
- clReleaseMemObject(CL_MEM_PTR(null_mem));
-
- ConstMemMap::iterator mt;
- for(mt = const_mem_map.begin(); mt != const_mem_map.end(); mt++) {
- mem_free(*(mt->second));
- delete mt->second;
- }
-
- if(ckFilmConvertByteKernel)
- clReleaseKernel(ckFilmConvertByteKernel);
- if(ckFilmConvertHalfFloatKernel)
- clReleaseKernel(ckFilmConvertHalfFloatKernel);
- if(ckShaderKernel)
- clReleaseKernel(ckShaderKernel);
- if(ckBakeKernel)
- clReleaseKernel(ckBakeKernel);
- if(cpProgram)
- clReleaseProgram(cpProgram);
- if(cqCommandQueue)
- clReleaseCommandQueue(cqCommandQueue);
- if(cxContext)
- clReleaseContext(cxContext);
- }
-
- void mem_alloc(device_memory& mem, MemoryType type)
- {
- size_t size = mem.memory_size();
-
- cl_mem_flags mem_flag;
- void *mem_ptr = NULL;
-
- if(type == MEM_READ_ONLY)
- mem_flag = CL_MEM_READ_ONLY;
- else if(type == MEM_WRITE_ONLY)
- mem_flag = CL_MEM_WRITE_ONLY;
- else
- mem_flag = CL_MEM_READ_WRITE;
-
- /* Zero-size allocation might be invoked by render, but not really
- * supported by OpenCL. Using NULL as device pointer also doesn't really
- * work for some reason, so for the time being we'll use special case
- * will null_mem buffer.
- */
- if(size != 0) {
- mem.device_pointer = (device_ptr)clCreateBuffer(cxContext,
- mem_flag,
- size,
- mem_ptr,
- &ciErr);
- opencl_assert_err(ciErr, "clCreateBuffer");
- }
- else {
- mem.device_pointer = null_mem;
- }
-
- stats.mem_alloc(size);
- mem.device_size = size;
- }
-
- void mem_copy_to(device_memory& mem)
- {
- /* this is blocking */
- size_t size = mem.memory_size();
- if(size != 0) {
- opencl_assert(clEnqueueWriteBuffer(cqCommandQueue,
- CL_MEM_PTR(mem.device_pointer),
- CL_TRUE,
- 0,
- size,
- (void*)mem.data_pointer,
- 0,
- NULL, NULL));
- }
- }
-
- void mem_copy_from(device_memory& mem, int y, int w, int h, int elem)
- {
- size_t offset = elem*y*w;
- size_t size = elem*w*h;
- assert(size != 0);
- opencl_assert(clEnqueueReadBuffer(cqCommandQueue,
- CL_MEM_PTR(mem.device_pointer),
- CL_TRUE,
- offset,
- size,
- (uchar*)mem.data_pointer + offset,
- 0,
- NULL, NULL));
- }
-
- void mem_zero(device_memory& mem)
- {
- if(mem.device_pointer) {
- memset((void*)mem.data_pointer, 0, mem.memory_size());
- mem_copy_to(mem);
- }
- }
-
- void mem_free(device_memory& mem)
- {
- if(mem.device_pointer) {
- if(mem.device_pointer != null_mem) {
- opencl_assert(clReleaseMemObject(CL_MEM_PTR(mem.device_pointer)));
- }
- mem.device_pointer = 0;
-
- stats.mem_free(mem.device_size);
- mem.device_size = 0;
- }
- }
-
- void const_copy_to(const char *name, void *host, size_t size)
- {
- ConstMemMap::iterator i = const_mem_map.find(name);
-
- if(i == const_mem_map.end()) {
- device_vector<uchar> *data = new device_vector<uchar>();
- data->copy((uchar*)host, size);
-
- mem_alloc(*data, MEM_READ_ONLY);
- i = const_mem_map.insert(ConstMemMap::value_type(name, data)).first;
- }
- else {
- device_vector<uchar> *data = i->second;
- data->copy((uchar*)host, size);
- }
-
- mem_copy_to(*i->second);
- }
-
- void tex_alloc(const char *name,
- device_memory& mem,
- InterpolationType /*interpolation*/,
- ExtensionType /*extension*/)
- {
- VLOG(1) << "Texture allocate: " << name << ", " << mem.memory_size() << " bytes.";
- mem_alloc(mem, MEM_READ_ONLY);
- mem_copy_to(mem);
- assert(mem_map.find(name) == mem_map.end());
- mem_map.insert(MemMap::value_type(name, mem.device_pointer));
- }
-
- void tex_free(device_memory& mem)
- {
- if(mem.device_pointer) {
- foreach(const MemMap::value_type& value, mem_map) {
- if(value.second == mem.device_pointer) {
- mem_map.erase(value.first);
- break;
- }
- }
-
- mem_free(mem);
- }
- }
-
- size_t global_size_round_up(int group_size, int global_size)
- {
- int r = global_size % group_size;
- return global_size + ((r == 0)? 0: group_size - r);
- }
-
- void enqueue_kernel(cl_kernel kernel, size_t w, size_t h)
- {
- size_t workgroup_size, max_work_items[3];
-
- clGetKernelWorkGroupInfo(kernel, cdDevice,
- CL_KERNEL_WORK_GROUP_SIZE, sizeof(size_t), &workgroup_size, NULL);
- clGetDeviceInfo(cdDevice,
- CL_DEVICE_MAX_WORK_ITEM_SIZES, sizeof(size_t)*3, max_work_items, NULL);
-
- /* try to divide evenly over 2 dimensions */
- size_t sqrt_workgroup_size = max((size_t)sqrt((double)workgroup_size), 1);
- size_t local_size[2] = {sqrt_workgroup_size, sqrt_workgroup_size};
-
- /* some implementations have max size 1 on 2nd dimension */
- if(local_size[1] > max_work_items[1]) {
- local_size[0] = workgroup_size/max_work_items[1];
- local_size[1] = max_work_items[1];
- }
-
- size_t global_size[2] = {global_size_round_up(local_size[0], w), global_size_round_up(local_size[1], h)};
-
- /* run kernel */
- opencl_assert(clEnqueueNDRangeKernel(cqCommandQueue, kernel, 2, NULL, global_size, NULL, 0, NULL, NULL));
- opencl_assert(clFlush(cqCommandQueue));
- }
-
- void set_kernel_arg_mem(cl_kernel kernel, cl_uint *narg, const char *name)
- {
- cl_mem ptr;
-
- MemMap::iterator i = mem_map.find(name);
- if(i != mem_map.end()) {
- ptr = CL_MEM_PTR(i->second);
- }
- else {
- /* work around NULL not working, even though the spec says otherwise */
- ptr = CL_MEM_PTR(null_mem);
- }
-
- opencl_assert(clSetKernelArg(kernel, (*narg)++, sizeof(ptr), (void*)&ptr));
- }
-
- void film_convert(DeviceTask& task, device_ptr buffer, device_ptr rgba_byte, device_ptr rgba_half)
- {
- /* cast arguments to cl types */
- cl_mem d_data = CL_MEM_PTR(const_mem_map["__data"]->device_pointer);
- cl_mem d_rgba = (rgba_byte)? CL_MEM_PTR(rgba_byte): CL_MEM_PTR(rgba_half);
- cl_mem d_buffer = CL_MEM_PTR(buffer);
- cl_int d_x = task.x;
- cl_int d_y = task.y;
- cl_int d_w = task.w;
- cl_int d_h = task.h;
- cl_float d_sample_scale = 1.0f/(task.sample + 1);
- cl_int d_offset = task.offset;
- cl_int d_stride = task.stride;
-
-
- cl_kernel ckFilmConvertKernel = (rgba_byte)? ckFilmConvertByteKernel: ckFilmConvertHalfFloatKernel;
-
- cl_uint start_arg_index =
- kernel_set_args(ckFilmConvertKernel,
- 0,
- d_data,
- d_rgba,
- d_buffer);
-
-#define KERNEL_TEX(type, ttype, name) \
- set_kernel_arg_mem(ckFilmConvertKernel, &start_arg_index, #name);
-#include "kernel_textures.h"
-#undef KERNEL_TEX
-
- start_arg_index += kernel_set_args(ckFilmConvertKernel,
- start_arg_index,
- d_sample_scale,
- d_x,
- d_y,
- d_w,
- d_h,
- d_offset,
- d_stride);
-
- enqueue_kernel(ckFilmConvertKernel, d_w, d_h);
- }
-
- void shader(DeviceTask& task)
- {
- /* cast arguments to cl types */
- cl_mem d_data = CL_MEM_PTR(const_mem_map["__data"]->device_pointer);
- cl_mem d_input = CL_MEM_PTR(task.shader_input);
- cl_mem d_output = CL_MEM_PTR(task.shader_output);
- cl_mem d_output_luma = CL_MEM_PTR(task.shader_output_luma);
- cl_int d_shader_eval_type = task.shader_eval_type;
- cl_int d_shader_filter = task.shader_filter;
- cl_int d_shader_x = task.shader_x;
- cl_int d_shader_w = task.shader_w;
- cl_int d_offset = task.offset;
-
- cl_kernel kernel;
-
- if(task.shader_eval_type >= SHADER_EVAL_BAKE)
- kernel = ckBakeKernel;
- else
- kernel = ckShaderKernel;
-
- for(int sample = 0; sample < task.num_samples; sample++) {
-
- if(task.get_cancel())
- break;
-
- cl_int d_sample = sample;
-
- cl_uint start_arg_index =
- kernel_set_args(kernel,
- 0,
- d_data,
- d_input,
- d_output);
-
- if(task.shader_eval_type < SHADER_EVAL_BAKE) {
- start_arg_index += kernel_set_args(kernel,
- start_arg_index,
- d_output_luma);
- }
-
-#define KERNEL_TEX(type, ttype, name) \
- set_kernel_arg_mem(kernel, &start_arg_index, #name);
-#include "kernel_textures.h"
-#undef KERNEL_TEX
-
- start_arg_index += kernel_set_args(kernel,
- start_arg_index,
- d_shader_eval_type);
- if(task.shader_eval_type >= SHADER_EVAL_BAKE) {
- start_arg_index += kernel_set_args(kernel,
- start_arg_index,
- d_shader_filter);
- }
- start_arg_index += kernel_set_args(kernel,
- start_arg_index,
- d_shader_x,
- d_shader_w,
- d_offset,
- d_sample);
-
- enqueue_kernel(kernel, task.shader_w, 1);
-
- task.update_progress(NULL);
- }
- }
-
- class OpenCLDeviceTask : public DeviceTask {
- public:
- OpenCLDeviceTask(OpenCLDeviceBase *device, DeviceTask& task)
- : DeviceTask(task)
- {
- run = function_bind(&OpenCLDeviceBase::thread_run,
- device,
- this);
- }
- };
-
- int get_split_task_count(DeviceTask& /*task*/)
- {
- return 1;
- }
-
- void task_add(DeviceTask& task)
- {
- task_pool.push(new OpenCLDeviceTask(this, task));
- }
-
- void task_wait()
- {
- task_pool.wait();
- }
-
- void task_cancel()
- {
- task_pool.cancel();
- }
-
- virtual void thread_run(DeviceTask * /*task*/) = 0;
-
-protected:
- string kernel_build_options(const string *debug_src = NULL)
- {
- string build_options = "-cl-fast-relaxed-math ";
-
- if(platform_name == "NVIDIA CUDA") {
- build_options += "-D__KERNEL_OPENCL_NVIDIA__ "
- "-cl-nv-maxrregcount=32 "
- "-cl-nv-verbose ";
-
- uint compute_capability_major, compute_capability_minor;
- clGetDeviceInfo(cdDevice, CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV,
- sizeof(cl_uint), &compute_capability_major, NULL);
- clGetDeviceInfo(cdDevice, CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV,
- sizeof(cl_uint), &compute_capability_minor, NULL);
-
- build_options += string_printf("-D__COMPUTE_CAPABILITY__=%u ",
- compute_capability_major * 100 +
- compute_capability_minor * 10);
- }
-
- else if(platform_name == "Apple")
- build_options += "-D__KERNEL_OPENCL_APPLE__ ";
-
- else if(platform_name == "AMD Accelerated Parallel Processing")
- build_options += "-D__KERNEL_OPENCL_AMD__ ";
-
- else if(platform_name == "Intel(R) OpenCL") {
- build_options += "-D__KERNEL_OPENCL_INTEL_CPU__ ";
-
- /* Options for gdb source level kernel debugging.
- * this segfaults on linux currently.
- */
- if(opencl_kernel_use_debug() && debug_src)
- build_options += "-g -s \"" + *debug_src + "\" ";
- }
-
- if(opencl_kernel_use_debug())
- build_options += "-D__KERNEL_OPENCL_DEBUG__ ";
-
-#ifdef WITH_CYCLES_DEBUG
- build_options += "-D__KERNEL_DEBUG__ ";
-#endif
-
- return build_options;
- }
-
- class ArgumentWrapper {
- public:
- ArgumentWrapper() : size(0), pointer(NULL) {}
- template <typename T>
- ArgumentWrapper(T& argument) : size(sizeof(argument)),
- pointer(&argument) { }
- ArgumentWrapper(int argument) : size(sizeof(int)),
- int_value(argument),
- pointer(&int_value) { }
- ArgumentWrapper(float argument) : size(sizeof(float)),
- float_value(argument),
- pointer(&float_value) { }
- size_t size;
- int int_value;
- float float_value;
- void *pointer;
- };
-
- /* TODO(sergey): In the future we can use variadic templates, once
- * C++0x is allowed. Should allow to clean this up a bit.
- */
- int kernel_set_args(cl_kernel kernel,
- int start_argument_index,
- const ArgumentWrapper& arg1 = ArgumentWrapper(),
- const ArgumentWrapper& arg2 = ArgumentWrapper(),
- const ArgumentWrapper& arg3 = ArgumentWrapper(),
- const ArgumentWrapper& arg4 = ArgumentWrapper(),
- const ArgumentWrapper& arg5 = ArgumentWrapper(),
- const ArgumentWrapper& arg6 = ArgumentWrapper(),
- const ArgumentWrapper& arg7 = ArgumentWrapper(),
- const ArgumentWrapper& arg8 = ArgumentWrapper(),
- const ArgumentWrapper& arg9 = ArgumentWrapper(),
- const ArgumentWrapper& arg10 = ArgumentWrapper(),
- const ArgumentWrapper& arg11 = ArgumentWrapper(),
- const ArgumentWrapper& arg12 = ArgumentWrapper(),
- const ArgumentWrapper& arg13 = ArgumentWrapper(),
- const ArgumentWrapper& arg14 = ArgumentWrapper(),
- const ArgumentWrapper& arg15 = ArgumentWrapper(),
- const ArgumentWrapper& arg16 = ArgumentWrapper(),
- const ArgumentWrapper& arg17 = ArgumentWrapper(),
- const ArgumentWrapper& arg18 = ArgumentWrapper(),
- const ArgumentWrapper& arg19 = ArgumentWrapper(),
- const ArgumentWrapper& arg20 = ArgumentWrapper(),
- const ArgumentWrapper& arg21 = ArgumentWrapper(),
- const ArgumentWrapper& arg22 = ArgumentWrapper(),
- const ArgumentWrapper& arg23 = ArgumentWrapper(),
- const ArgumentWrapper& arg24 = ArgumentWrapper(),
- const ArgumentWrapper& arg25 = ArgumentWrapper(),
- const ArgumentWrapper& arg26 = ArgumentWrapper(),
- const ArgumentWrapper& arg27 = ArgumentWrapper(),
- const ArgumentWrapper& arg28 = ArgumentWrapper(),
- const ArgumentWrapper& arg29 = ArgumentWrapper(),
- const ArgumentWrapper& arg30 = ArgumentWrapper(),
- const ArgumentWrapper& arg31 = ArgumentWrapper(),
- const ArgumentWrapper& arg32 = ArgumentWrapper(),
- const ArgumentWrapper& arg33 = ArgumentWrapper())
- {
- int current_arg_index = 0;
-#define FAKE_VARARG_HANDLE_ARG(arg) \
- do { \
- if(arg.pointer != NULL) { \
- opencl_assert(clSetKernelArg( \
- kernel, \
- start_argument_index + current_arg_index, \
- arg.size, arg.pointer)); \
- ++current_arg_index; \
- } \
- else { \
- return current_arg_index; \
- } \
- } while(false)
- FAKE_VARARG_HANDLE_ARG(arg1);
- FAKE_VARARG_HANDLE_ARG(arg2);
- FAKE_VARARG_HANDLE_ARG(arg3);
- FAKE_VARARG_HANDLE_ARG(arg4);
- FAKE_VARARG_HANDLE_ARG(arg5);
- FAKE_VARARG_HANDLE_ARG(arg6);
- FAKE_VARARG_HANDLE_ARG(arg7);
- FAKE_VARARG_HANDLE_ARG(arg8);
- FAKE_VARARG_HANDLE_ARG(arg9);
- FAKE_VARARG_HANDLE_ARG(arg10);
- FAKE_VARARG_HANDLE_ARG(arg11);
- FAKE_VARARG_HANDLE_ARG(arg12);
- FAKE_VARARG_HANDLE_ARG(arg13);
- FAKE_VARARG_HANDLE_ARG(arg14);
- FAKE_VARARG_HANDLE_ARG(arg15);
- FAKE_VARARG_HANDLE_ARG(arg16);
- FAKE_VARARG_HANDLE_ARG(arg17);
- FAKE_VARARG_HANDLE_ARG(arg18);
- FAKE_VARARG_HANDLE_ARG(arg19);
- FAKE_VARARG_HANDLE_ARG(arg20);
- FAKE_VARARG_HANDLE_ARG(arg21);
- FAKE_VARARG_HANDLE_ARG(arg22);
- FAKE_VARARG_HANDLE_ARG(arg23);
- FAKE_VARARG_HANDLE_ARG(arg24);
- FAKE_VARARG_HANDLE_ARG(arg25);
- FAKE_VARARG_HANDLE_ARG(arg26);
- FAKE_VARARG_HANDLE_ARG(arg27);
- FAKE_VARARG_HANDLE_ARG(arg28);
- FAKE_VARARG_HANDLE_ARG(arg29);
- FAKE_VARARG_HANDLE_ARG(arg30);
- FAKE_VARARG_HANDLE_ARG(arg31);
- FAKE_VARARG_HANDLE_ARG(arg32);
- FAKE_VARARG_HANDLE_ARG(arg33);
-#undef FAKE_VARARG_HANDLE_ARG
- return current_arg_index;
- }
-
- inline void release_kernel_safe(cl_kernel kernel)
- {
- if(kernel) {
- clReleaseKernel(kernel);
- }
- }
-
- inline void release_mem_object_safe(cl_mem mem)
- {
- if(mem != NULL) {
- clReleaseMemObject(mem);
- }
- }
-
- inline void release_program_safe(cl_program program)
- {
- if(program) {
- clReleaseProgram(program);
- }
- }
-
- /* ** Those guys are for workign around some compiler-specific bugs ** */
-
- virtual cl_program load_cached_kernel(
- const DeviceRequestedFeatures& /*requested_features*/,
- OpenCLCache::ProgramName program_name,
- thread_scoped_lock& cache_locker)
- {
- return OpenCLCache::get_program(cpPlatform,
- cdDevice,
- program_name,
- cache_locker);
- }
-
- virtual void store_cached_kernel(cl_platform_id platform,
- cl_device_id device,
- cl_program program,
- OpenCLCache::ProgramName program_name,
- thread_scoped_lock& cache_locker)
- {
- OpenCLCache::store_program(platform,
- device,
- program,
- program_name,
- cache_locker);
- }
-
- virtual string build_options_for_base_program(
- const DeviceRequestedFeatures& /*requested_features*/)
- {
- /* TODO(sergey): By default we compile all features, meaning
- * mega kernel is not getting feature-based optimizations.
- *
- * Ideally we need always compile kernel with as less features
- * enabled as possible to keep performance at it's max.
- */
- return "";
- }
-};
-
-class OpenCLDeviceMegaKernel : public OpenCLDeviceBase
-{
-public:
- cl_kernel ckPathTraceKernel;
- cl_program path_trace_program;
-
- OpenCLDeviceMegaKernel(DeviceInfo& info, Stats &stats, bool background_)
- : OpenCLDeviceBase(info, stats, background_)
- {
- ckPathTraceKernel = NULL;
- path_trace_program = NULL;
- }
-
- bool load_kernels(const DeviceRequestedFeatures& requested_features)
- {
- /* Get Shader, bake and film convert kernels.
- * It'll also do verification of OpenCL actually initialized.
- */
- if(!OpenCLDeviceBase::load_kernels(requested_features)) {
- return false;
- }
-
- /* Try to use cached kernel. */
- thread_scoped_lock cache_locker;
- path_trace_program = OpenCLCache::get_program(cpPlatform,
- cdDevice,
- OpenCLCache::OCL_DEV_MEGAKERNEL_PROGRAM,
- cache_locker);
-
- if(!path_trace_program) {
- /* Verify we have right opencl version. */
- if(!opencl_version_check())
- return false;
-
- /* Calculate md5 hash to detect changes. */
- string kernel_path = path_get("kernel");
- string kernel_md5 = path_files_md5_hash(kernel_path);
- string custom_kernel_build_options = "-D__COMPILE_ONLY_MEGAKERNEL__ ";
- string device_md5 = device_md5_hash(custom_kernel_build_options);
-
- /* Path to cached binary. */
- string clbin = string_printf("cycles_kernel_%s_%s.clbin",
- device_md5.c_str(),
- kernel_md5.c_str());
- clbin = path_user_get(path_join("cache", clbin));
-
- /* Path to preprocessed source for debugging. */
- string clsrc, *debug_src = NULL;
- if(opencl_kernel_use_debug()) {
- clsrc = string_printf("cycles_kernel_%s_%s.cl",
- device_md5.c_str(),
- kernel_md5.c_str());
- clsrc = path_user_get(path_join("cache", clsrc));
- debug_src = &clsrc;
- }
-
- /* If exists already, try use it. */
- if(path_exists(clbin) && load_binary(kernel_path,
- clbin,
- custom_kernel_build_options,
- &path_trace_program,
- debug_src))
- {
- /* Kernel loaded from binary, nothing to do. */
- }
- else {
- string init_kernel_source = "#include \"kernels/opencl/kernel.cl\" // " +
- kernel_md5 + "\n";
- /* If does not exist or loading binary failed, compile kernel. */
- if(!compile_kernel(kernel_path,
- init_kernel_source,
- custom_kernel_build_options,
- &path_trace_program,
- debug_src))
- {
- return false;
- }
- /* Save binary for reuse. */
- if(!save_binary(&path_trace_program, clbin)) {
- return false;
- }
- }
- /* Cache the program. */
- OpenCLCache::store_program(cpPlatform,
- cdDevice,
- path_trace_program,
- OpenCLCache::OCL_DEV_MEGAKERNEL_PROGRAM,
- cache_locker);
- }
-
- /* Find kernels. */
- ckPathTraceKernel = clCreateKernel(path_trace_program,
- "kernel_ocl_path_trace",
- &ciErr);
- if(opencl_error(ciErr))
- return false;
- return true;
- }
-
- ~OpenCLDeviceMegaKernel()
- {
- task_pool.stop();
- release_kernel_safe(ckPathTraceKernel);
- release_program_safe(path_trace_program);
- }
-
- void path_trace(RenderTile& rtile, int sample)
- {
- /* Cast arguments to cl types. */
- cl_mem d_data = CL_MEM_PTR(const_mem_map["__data"]->device_pointer);
- cl_mem d_buffer = CL_MEM_PTR(rtile.buffer);
- cl_mem d_rng_state = CL_MEM_PTR(rtile.rng_state);
- cl_int d_x = rtile.x;
- cl_int d_y = rtile.y;
- cl_int d_w = rtile.w;
- cl_int d_h = rtile.h;
- cl_int d_offset = rtile.offset;
- cl_int d_stride = rtile.stride;
-
- /* Sample arguments. */
- cl_int d_sample = sample;
-
- cl_uint start_arg_index =
- kernel_set_args(ckPathTraceKernel,
- 0,
- d_data,
- d_buffer,
- d_rng_state);
-
-#define KERNEL_TEX(type, ttype, name) \
- set_kernel_arg_mem(ckPathTraceKernel, &start_arg_index, #name);
-#include "kernel_textures.h"
-#undef KERNEL_TEX
-
- start_arg_index += kernel_set_args(ckPathTraceKernel,
- start_arg_index,
- d_sample,
- d_x,
- d_y,
- d_w,
- d_h,
- d_offset,
- d_stride);
-
- enqueue_kernel(ckPathTraceKernel, d_w, d_h);
- }
-
- void thread_run(DeviceTask *task)
- {
- if(task->type == DeviceTask::FILM_CONVERT) {
- film_convert(*task, task->buffer, task->rgba_byte, task->rgba_half);
- }
- else if(task->type == DeviceTask::SHADER) {
- shader(*task);
- }
- else if(task->type == DeviceTask::PATH_TRACE) {
- RenderTile tile;
- /* Keep rendering tiles until done. */
- while(task->acquire_tile(this, tile)) {
- int start_sample = tile.start_sample;
- int end_sample = tile.start_sample + tile.num_samples;
-
- for(int sample = start_sample; sample < end_sample; sample++) {
- if(task->get_cancel()) {
- if(task->need_finish_queue == false)
- break;
- }
-
- path_trace(tile, sample);
-
- tile.sample = sample + 1;
-
- task->update_progress(&tile);
- }
-
- /* Complete kernel execution before release tile */
- /* This helps in multi-device render;
- * The device that reaches the critical-section function
- * release_tile waits (stalling other devices from entering
- * release_tile) for all kernels to complete. If device1 (a
- * slow-render device) reaches release_tile first then it would
- * stall device2 (a fast-render device) from proceeding to render
- * next tile.
- */
- clFinish(cqCommandQueue);
-
- task->release_tile(tile);
- }
- }
- }
-};
-
-/* TODO(sergey): This is to keep tile split on OpenCL level working
- * for now, since without this view-port render does not work as it
- * should.
- *
- * Ideally it'll be done on the higher level, but we need to get ready
- * for merge rather soon, so let's keep split logic private here in
- * the file.
- */
-class SplitRenderTile : public RenderTile {
-public:
- SplitRenderTile()
- : RenderTile(),
- buffer_offset_x(0),
- buffer_offset_y(0),
- rng_state_offset_x(0),
- rng_state_offset_y(0),
- buffer_rng_state_stride(0) {}
-
- explicit SplitRenderTile(RenderTile& tile)
- : RenderTile(),
- buffer_offset_x(0),
- buffer_offset_y(0),
- rng_state_offset_x(0),
- rng_state_offset_y(0),
- buffer_rng_state_stride(0)
- {
- x = tile.x;
- y = tile.y;
- w = tile.w;
- h = tile.h;
- start_sample = tile.start_sample;
- num_samples = tile.num_samples;
- sample = tile.sample;
- resolution = tile.resolution;
- offset = tile.offset;
- stride = tile.stride;
- buffer = tile.buffer;
- rng_state = tile.rng_state;
- buffers = tile.buffers;
- }
-
- /* Split kernel is device global memory constrained;
- * hence split kernel cant render big tile size's in
- * one go. If the user sets a big tile size (big tile size
- * is a term relative to the available device global memory),
- * we split the tile further and then call path_trace on
- * each of those split tiles. The following variables declared,
- * assist in achieving that purpose
- */
- int buffer_offset_x;
- int buffer_offset_y;
- int rng_state_offset_x;
- int rng_state_offset_y;
- int buffer_rng_state_stride;
-};
-
-/* OpenCLDeviceSplitKernel's declaration/definition. */
-class OpenCLDeviceSplitKernel : public OpenCLDeviceBase
-{
-public:
- /* Kernel declaration. */
- cl_kernel ckPathTraceKernel_data_init;
- cl_kernel ckPathTraceKernel_scene_intersect;
- cl_kernel ckPathTraceKernel_lamp_emission;
- cl_kernel ckPathTraceKernel_queue_enqueue;
- cl_kernel ckPathTraceKernel_background_buffer_update;
- cl_kernel ckPathTraceKernel_shader_eval;
- cl_kernel ckPathTraceKernel_holdout_emission_blurring_pathtermination_ao;
- cl_kernel ckPathTraceKernel_direct_lighting;
- cl_kernel ckPathTraceKernel_shadow_blocked;
- cl_kernel ckPathTraceKernel_next_iteration_setup;
- cl_kernel ckPathTraceKernel_sum_all_radiance;
-
- /* cl_program declaration. */
- cl_program data_init_program;
- cl_program scene_intersect_program;
- cl_program lamp_emission_program;
- cl_program queue_enqueue_program;
- cl_program background_buffer_update_program;
- cl_program shader_eval_program;
- cl_program holdout_emission_blurring_pathtermination_ao_program;
- cl_program direct_lighting_program;
- cl_program shadow_blocked_program;
- cl_program next_iteration_setup_program;
- cl_program sum_all_radiance_program;
-
- /* Global memory variables [porting]; These memory is used for
- * co-operation between different kernels; Data written by one
- * kernel will be available to another kernel via this global
- * memory.
- */
- cl_mem rng_coop;
- cl_mem throughput_coop;
- cl_mem L_transparent_coop;
- cl_mem PathRadiance_coop;
- cl_mem Ray_coop;
- cl_mem PathState_coop;
- cl_mem Intersection_coop;
- cl_mem kgbuffer; /* KernelGlobals buffer. */
-
- /* Global buffers for ShaderData. */
- cl_mem sd; /* ShaderData used in the main path-iteration loop. */
- cl_mem sd_DL_shadow; /* ShaderData used in Direct Lighting and
- * shadow_blocked kernel.
- */
-
- /* Global memory required for shadow blocked and accum_radiance. */
- cl_mem BSDFEval_coop;
- cl_mem ISLamp_coop;
- cl_mem LightRay_coop;
- cl_mem AOAlpha_coop;
- cl_mem AOBSDF_coop;
- cl_mem AOLightRay_coop;
- cl_mem Intersection_coop_shadow;
-
-#ifdef WITH_CYCLES_DEBUG
- /* DebugData memory */
- cl_mem debugdata_coop;
-#endif
-
- /* Global state array that tracks ray state. */
- cl_mem ray_state;
-
- /* Per sample buffers. */
- cl_mem per_sample_output_buffers;
-
- /* Denotes which sample each ray is being processed for. */
- cl_mem work_array;
-
- /* Queue */
- cl_mem Queue_data; /* Array of size queuesize * num_queues * sizeof(int). */
- cl_mem Queue_index; /* Array of size num_queues * sizeof(int);
- * Tracks the size of each queue.
- */
-
- /* Flag to make sceneintersect and lampemission kernel use queues. */
- cl_mem use_queues_flag;
-
- /* Amount of memory in output buffer associated with one pixel/thread. */
- size_t per_thread_output_buffer_size;
-
- /* Total allocatable available device memory. */
- size_t total_allocatable_memory;
-
- /* host version of ray_state; Used in checking host path-iteration
- * termination.
- */
- char *hostRayStateArray;
-
- /* Number of path-iterations to be done in one shot. */
- unsigned int PathIteration_times;
-
-#ifdef __WORK_STEALING__
- /* Work pool with respect to each work group. */
- cl_mem work_pool_wgs;
-
- /* Denotes the maximum work groups possible w.r.t. current tile size. */
- unsigned int max_work_groups;
-#endif
-
- /* clos_max value for which the kernels have been loaded currently. */
- int current_max_closure;
-
- /* Marked True in constructor and marked false at the end of path_trace(). */
- bool first_tile;
-
- OpenCLDeviceSplitKernel(DeviceInfo& info, Stats &stats, bool background_)
- : OpenCLDeviceBase(info, stats, background_)
- {
- background = background_;
-
- /* Initialize kernels. */
- ckPathTraceKernel_data_init = NULL;
- ckPathTraceKernel_scene_intersect = NULL;
- ckPathTraceKernel_lamp_emission = NULL;
- ckPathTraceKernel_background_buffer_update = NULL;
- ckPathTraceKernel_shader_eval = NULL;
- ckPathTraceKernel_holdout_emission_blurring_pathtermination_ao = NULL;
- ckPathTraceKernel_direct_lighting = NULL;
- ckPathTraceKernel_shadow_blocked = NULL;
- ckPathTraceKernel_next_iteration_setup = NULL;
- ckPathTraceKernel_sum_all_radiance = NULL;
- ckPathTraceKernel_queue_enqueue = NULL;
-
- /* Initialize program. */
- data_init_program = NULL;
- scene_intersect_program = NULL;
- lamp_emission_program = NULL;
- queue_enqueue_program = NULL;
- background_buffer_update_program = NULL;
- shader_eval_program = NULL;
- holdout_emission_blurring_pathtermination_ao_program = NULL;
- direct_lighting_program = NULL;
- shadow_blocked_program = NULL;
- next_iteration_setup_program = NULL;
- sum_all_radiance_program = NULL;
-
- /* Initialize cl_mem variables. */
- kgbuffer = NULL;
- sd = NULL;
- sd_DL_shadow = NULL;
-
- rng_coop = NULL;
- throughput_coop = NULL;
- L_transparent_coop = NULL;
- PathRadiance_coop = NULL;
- Ray_coop = NULL;
- PathState_coop = NULL;
- Intersection_coop = NULL;
- ray_state = NULL;
-
- AOAlpha_coop = NULL;
- AOBSDF_coop = NULL;
- AOLightRay_coop = NULL;
- BSDFEval_coop = NULL;
- ISLamp_coop = NULL;
- LightRay_coop = NULL;
- Intersection_coop_shadow = NULL;
-
-#ifdef WITH_CYCLES_DEBUG
- debugdata_coop = NULL;
-#endif
-
- work_array = NULL;
-
- /* Queue. */
- Queue_data = NULL;
- Queue_index = NULL;
- use_queues_flag = NULL;
-
- per_sample_output_buffers = NULL;
-
- per_thread_output_buffer_size = 0;
- hostRayStateArray = NULL;
- PathIteration_times = PATH_ITER_INC_FACTOR;
-#ifdef __WORK_STEALING__
- work_pool_wgs = NULL;
- max_work_groups = 0;
-#endif
- current_max_closure = -1;
- first_tile = true;
-
- /* Get device's maximum memory that can be allocated. */
- ciErr = clGetDeviceInfo(cdDevice,
- CL_DEVICE_MAX_MEM_ALLOC_SIZE,
- sizeof(size_t),
- &total_allocatable_memory,
- NULL);
- assert(ciErr == CL_SUCCESS);
- if(platform_name == "AMD Accelerated Parallel Processing") {
- /* This value is tweak-able; AMD platform does not seem to
- * give maximum performance when all of CL_DEVICE_MAX_MEM_ALLOC_SIZE
- * is considered for further computation.
- */
- total_allocatable_memory /= 2;
- }
- }
-
- /* TODO(sergey): Seems really close to load_kernel(),
- * could it be de-duplicated?
- */
- bool load_split_kernel(string kernel_path,
- string kernel_init_source,
- string clbin,
- string custom_kernel_build_options,
- cl_program *program,
- const string *debug_src = NULL)
- {
- if(!opencl_version_check())
- return false;
-
- clbin = path_user_get(path_join("cache", clbin));
-
- /* If exists already, try use it. */
- if(path_exists(clbin) && load_binary(kernel_path,
- clbin,
- custom_kernel_build_options,
- program,
- debug_src))
- {
- /* Kernel loaded from binary. */
- }
- else {
- /* If does not exist or loading binary failed, compile kernel. */
- if(!compile_kernel(kernel_path,
- kernel_init_source,
- custom_kernel_build_options,
- program,
- debug_src))
- {
- return false;
- }
- /* Save binary for reuse. */
- if(!save_binary(program, clbin)) {
- return false;
- }
- }
- return true;
- }
-
- /* Split kernel utility functions. */
- size_t get_tex_size(const char *tex_name)
- {
- cl_mem ptr;
- size_t ret_size = 0;
- MemMap::iterator i = mem_map.find(tex_name);
- if(i != mem_map.end()) {
- ptr = CL_MEM_PTR(i->second);
- ciErr = clGetMemObjectInfo(ptr,
- CL_MEM_SIZE,
- sizeof(ret_size),
- &ret_size,
- NULL);
- assert(ciErr == CL_SUCCESS);
- }
- return ret_size;
- }
-
- size_t get_shader_data_size(size_t max_closure)
- {
- /* ShaderData size with variable size ShaderClosure array */
- return sizeof(ShaderData) - (sizeof(ShaderClosure) * (MAX_CLOSURE - max_closure));
- }
-
- /* Returns size of KernelGlobals structure associated with OpenCL. */
- size_t get_KernelGlobals_size()
- {
- /* Copy dummy KernelGlobals related to OpenCL from kernel_globals.h to
- * fetch its size.
- */
- typedef struct KernelGlobals {
- ccl_constant KernelData *data;
-#define KERNEL_TEX(type, ttype, name) \
- ccl_global type *name;
-#include "kernel_textures.h"
-#undef KERNEL_TEX
- void *sd_input;
- void *isect_shadow;
- } KernelGlobals;
-
- return sizeof(KernelGlobals);
- }
-
- bool load_kernels(const DeviceRequestedFeatures& requested_features)
- {
- /* Get Shader, bake and film_convert kernels.
- * It'll also do verification of OpenCL actually initialized.
- */
- if(!OpenCLDeviceBase::load_kernels(requested_features)) {
- return false;
- }
-
- string kernel_path = path_get("kernel");
- string kernel_md5 = path_files_md5_hash(kernel_path);
- string device_md5;
- string kernel_init_source;
- string clbin;
- string clsrc, *debug_src = NULL;
-
- string build_options = "-D__SPLIT_KERNEL__ ";
-#ifdef __WORK_STEALING__
- build_options += "-D__WORK_STEALING__ ";
-#endif
- build_options += requested_features.get_build_options();
-
- /* Set compute device build option. */
- cl_device_type device_type;
- ciErr = clGetDeviceInfo(cdDevice,
- CL_DEVICE_TYPE,
- sizeof(cl_device_type),
- &device_type,
- NULL);
- assert(ciErr == CL_SUCCESS);
- if(device_type == CL_DEVICE_TYPE_GPU) {
- build_options += " -D__COMPUTE_DEVICE_GPU__";
- }
-
-#define GLUE(a, b) a ## b
-#define LOAD_KERNEL(name) \
- do { \
- kernel_init_source = "#include \"kernels/opencl/kernel_" #name ".cl\" // " + \
- kernel_md5 + "\n"; \
- device_md5 = device_md5_hash(build_options); \
- clbin = string_printf("cycles_kernel_%s_%s_" #name ".clbin", \
- device_md5.c_str(), kernel_md5.c_str()); \
- if(opencl_kernel_use_debug()) { \
- clsrc = string_printf("cycles_kernel_%s_%s_" #name ".cl", \
- device_md5.c_str(), kernel_md5.c_str()); \
- clsrc = path_user_get(path_join("cache", clsrc)); \
- debug_src = &clsrc; \
- } \
- if(!load_split_kernel(kernel_path, kernel_init_source, clbin, \
- build_options, \
- &GLUE(name, _program), \
- debug_src)) \
- { \
- fprintf(stderr, "Faled to compile %s\n", #name); \
- return false; \
- } \
- } while(false)
-
- LOAD_KERNEL(data_init);
- LOAD_KERNEL(scene_intersect);
- LOAD_KERNEL(lamp_emission);
- LOAD_KERNEL(queue_enqueue);
- LOAD_KERNEL(background_buffer_update);
- LOAD_KERNEL(shader_eval);
- LOAD_KERNEL(holdout_emission_blurring_pathtermination_ao);
- LOAD_KERNEL(direct_lighting);
- LOAD_KERNEL(shadow_blocked);
- LOAD_KERNEL(next_iteration_setup);
- LOAD_KERNEL(sum_all_radiance);
-
-#undef LOAD_KERNEL
-
-#define FIND_KERNEL(name) \
- do { \
- GLUE(ckPathTraceKernel_, name) = \
- clCreateKernel(GLUE(name, _program), \
- "kernel_ocl_path_trace_" #name, &ciErr); \
- if(opencl_error(ciErr)) { \
- fprintf(stderr,"Missing kernel kernel_ocl_path_trace_%s\n", #name); \
- return false; \
- } \
- } while(false)
-
- FIND_KERNEL(data_init);
- FIND_KERNEL(scene_intersect);
- FIND_KERNEL(lamp_emission);
- FIND_KERNEL(queue_enqueue);
- FIND_KERNEL(background_buffer_update);
- FIND_KERNEL(shader_eval);
- FIND_KERNEL(holdout_emission_blurring_pathtermination_ao);
- FIND_KERNEL(direct_lighting);
- FIND_KERNEL(shadow_blocked);
- FIND_KERNEL(next_iteration_setup);
- FIND_KERNEL(sum_all_radiance);
-#undef FIND_KERNEL
-#undef GLUE
-
- current_max_closure = requested_features.max_closure;
-
- return true;
- }
-
- ~OpenCLDeviceSplitKernel()
- {
- task_pool.stop();
-
- /* Release kernels */
- release_kernel_safe(ckPathTraceKernel_data_init);
- release_kernel_safe(ckPathTraceKernel_scene_intersect);
- release_kernel_safe(ckPathTraceKernel_lamp_emission);
- release_kernel_safe(ckPathTraceKernel_queue_enqueue);
- release_kernel_safe(ckPathTraceKernel_background_buffer_update);
- release_kernel_safe(ckPathTraceKernel_shader_eval);
- release_kernel_safe(ckPathTraceKernel_holdout_emission_blurring_pathtermination_ao);
- release_kernel_safe(ckPathTraceKernel_direct_lighting);
- release_kernel_safe(ckPathTraceKernel_shadow_blocked);
- release_kernel_safe(ckPathTraceKernel_next_iteration_setup);
- release_kernel_safe(ckPathTraceKernel_sum_all_radiance);
-
- /* Release global memory */
- release_mem_object_safe(rng_coop);
- release_mem_object_safe(throughput_coop);
- release_mem_object_safe(L_transparent_coop);
- release_mem_object_safe(PathRadiance_coop);
- release_mem_object_safe(Ray_coop);
- release_mem_object_safe(PathState_coop);
- release_mem_object_safe(Intersection_coop);
- release_mem_object_safe(kgbuffer);
- release_mem_object_safe(sd);
- release_mem_object_safe(sd_DL_shadow);
- release_mem_object_safe(ray_state);
- release_mem_object_safe(AOAlpha_coop);
- release_mem_object_safe(AOBSDF_coop);
- release_mem_object_safe(AOLightRay_coop);
- release_mem_object_safe(BSDFEval_coop);
- release_mem_object_safe(ISLamp_coop);
- release_mem_object_safe(LightRay_coop);
- release_mem_object_safe(Intersection_coop_shadow);
-#ifdef WITH_CYCLES_DEBUG
- release_mem_object_safe(debugdata_coop);
-#endif
- release_mem_object_safe(use_queues_flag);
- release_mem_object_safe(Queue_data);
- release_mem_object_safe(Queue_index);
- release_mem_object_safe(work_array);
-#ifdef __WORK_STEALING__
- release_mem_object_safe(work_pool_wgs);
-#endif
- release_mem_object_safe(per_sample_output_buffers);
-
- /* Release programs */
- release_program_safe(data_init_program);
- release_program_safe(scene_intersect_program);
- release_program_safe(lamp_emission_program);
- release_program_safe(queue_enqueue_program);
- release_program_safe(background_buffer_update_program);
- release_program_safe(shader_eval_program);
- release_program_safe(holdout_emission_blurring_pathtermination_ao_program);
- release_program_safe(direct_lighting_program);
- release_program_safe(shadow_blocked_program);
- release_program_safe(next_iteration_setup_program);
- release_program_safe(sum_all_radiance_program);
-
- if(hostRayStateArray != NULL) {
- free(hostRayStateArray);
- }
- }
-
- void path_trace(SplitRenderTile& rtile, int2 max_render_feasible_tile_size)
- {
- /* cast arguments to cl types */
- cl_mem d_data = CL_MEM_PTR(const_mem_map["__data"]->device_pointer);
- cl_mem d_buffer = CL_MEM_PTR(rtile.buffer);
- cl_mem d_rng_state = CL_MEM_PTR(rtile.rng_state);
- cl_int d_x = rtile.x;
- cl_int d_y = rtile.y;
- cl_int d_w = rtile.w;
- cl_int d_h = rtile.h;
- cl_int d_offset = rtile.offset;
- cl_int d_stride = rtile.stride;
-
- /* Make sure that set render feasible tile size is a multiple of local
- * work size dimensions.
- */
- assert(max_render_feasible_tile_size.x % SPLIT_KERNEL_LOCAL_SIZE_X == 0);
- assert(max_render_feasible_tile_size.y % SPLIT_KERNEL_LOCAL_SIZE_Y == 0);
-
- size_t global_size[2];
- size_t local_size[2] = {SPLIT_KERNEL_LOCAL_SIZE_X,
- SPLIT_KERNEL_LOCAL_SIZE_Y};
-
- /* Set the range of samples to be processed for every ray in
- * path-regeneration logic.
- */
- cl_int start_sample = rtile.start_sample;
- cl_int end_sample = rtile.start_sample + rtile.num_samples;
- cl_int num_samples = rtile.num_samples;
-
-#ifdef __WORK_STEALING__
- global_size[0] = (((d_w - 1) / local_size[0]) + 1) * local_size[0];
- global_size[1] = (((d_h - 1) / local_size[1]) + 1) * local_size[1];
- unsigned int num_parallel_samples = 1;
-#else
- global_size[1] = (((d_h - 1) / local_size[1]) + 1) * local_size[1];
- unsigned int num_threads = max_render_feasible_tile_size.x *
- max_render_feasible_tile_size.y;
- unsigned int num_tile_columns_possible = num_threads / global_size[1];
- /* Estimate number of parallel samples that can be
- * processed in parallel.
- */
- unsigned int num_parallel_samples = min(num_tile_columns_possible / d_w,
- rtile.num_samples);
- /* Wavefront size in AMD is 64.
- * TODO(sergey): What about other platforms?
- */
- if(num_parallel_samples >= 64) {
- /* TODO(sergey): Could use generic round-up here. */
- num_parallel_samples = (num_parallel_samples / 64) * 64;
- }
- assert(num_parallel_samples != 0);
-
- global_size[0] = d_w * num_parallel_samples;
-#endif /* __WORK_STEALING__ */
-
- assert(global_size[0] * global_size[1] <=
- max_render_feasible_tile_size.x * max_render_feasible_tile_size.y);
-
- /* Allocate all required global memory once. */
- if(first_tile) {
- size_t num_global_elements = max_render_feasible_tile_size.x *
- max_render_feasible_tile_size.y;
- /* TODO(sergey): This will actually over-allocate if
- * particular kernel does not support multiclosure.
- */
- size_t shaderdata_size = get_shader_data_size(current_max_closure);
-
-#ifdef __WORK_STEALING__
- /* Calculate max groups */
- size_t max_global_size[2];
- size_t tile_x = max_render_feasible_tile_size.x;
- size_t tile_y = max_render_feasible_tile_size.y;
- max_global_size[0] = (((tile_x - 1) / local_size[0]) + 1) * local_size[0];
- max_global_size[1] = (((tile_y - 1) / local_size[1]) + 1) * local_size[1];
- max_work_groups = (max_global_size[0] * max_global_size[1]) /
- (local_size[0] * local_size[1]);
- /* Allocate work_pool_wgs memory. */
- work_pool_wgs = mem_alloc(max_work_groups * sizeof(unsigned int));
-#endif /* __WORK_STEALING__ */
-
- /* Allocate queue_index memory only once. */
- Queue_index = mem_alloc(NUM_QUEUES * sizeof(int));
- use_queues_flag = mem_alloc(sizeof(char));
- kgbuffer = mem_alloc(get_KernelGlobals_size());
-
- /* Create global buffers for ShaderData. */
- sd = mem_alloc(num_global_elements * shaderdata_size);
- sd_DL_shadow = mem_alloc(num_global_elements * 2 * shaderdata_size);
-
- /* Creation of global memory buffers which are shared among
- * the kernels.
- */
- rng_coop = mem_alloc(num_global_elements * sizeof(RNG));
- throughput_coop = mem_alloc(num_global_elements * sizeof(float3));
- L_transparent_coop = mem_alloc(num_global_elements * sizeof(float));
- PathRadiance_coop = mem_alloc(num_global_elements * sizeof(PathRadiance));
- Ray_coop = mem_alloc(num_global_elements * sizeof(Ray));
- PathState_coop = mem_alloc(num_global_elements * sizeof(PathState));
- Intersection_coop = mem_alloc(num_global_elements * sizeof(Intersection));
- AOAlpha_coop = mem_alloc(num_global_elements * sizeof(float3));
- AOBSDF_coop = mem_alloc(num_global_elements * sizeof(float3));
- AOLightRay_coop = mem_alloc(num_global_elements * sizeof(Ray));
- BSDFEval_coop = mem_alloc(num_global_elements * sizeof(BsdfEval));
- ISLamp_coop = mem_alloc(num_global_elements * sizeof(int));
- LightRay_coop = mem_alloc(num_global_elements * sizeof(Ray));
- Intersection_coop_shadow = mem_alloc(2 * num_global_elements * sizeof(Intersection));
-
-#ifdef WITH_CYCLES_DEBUG
- debugdata_coop = mem_alloc(num_global_elements * sizeof(DebugData));
-#endif
-
- ray_state = mem_alloc(num_global_elements * sizeof(char));
-
- hostRayStateArray = (char *)calloc(num_global_elements, sizeof(char));
- assert(hostRayStateArray != NULL && "Can't create hostRayStateArray memory");
-
- Queue_data = mem_alloc(num_global_elements * (NUM_QUEUES * sizeof(int)+sizeof(int)));
- work_array = mem_alloc(num_global_elements * sizeof(unsigned int));
- per_sample_output_buffers = mem_alloc(num_global_elements *
- per_thread_output_buffer_size);
- }
-
- cl_int dQueue_size = global_size[0] * global_size[1];
-
- cl_uint start_arg_index =
- kernel_set_args(ckPathTraceKernel_data_init,
- 0,
- kgbuffer,
- sd_DL_shadow,
- d_data,
- per_sample_output_buffers,
- d_rng_state,
- rng_coop,
- throughput_coop,
- L_transparent_coop,
- PathRadiance_coop,
- Ray_coop,
- PathState_coop,
- Intersection_coop_shadow,
- ray_state);
-
-/* TODO(sergey): Avoid map lookup here. */
-#define KERNEL_TEX(type, ttype, name) \
- set_kernel_arg_mem(ckPathTraceKernel_data_init, &start_arg_index, #name);
-#include "kernel_textures.h"
-#undef KERNEL_TEX
-
- start_arg_index +=
- kernel_set_args(ckPathTraceKernel_data_init,
- start_arg_index,
- start_sample,
- d_x,
- d_y,
- d_w,
- d_h,
- d_offset,
- d_stride,
- rtile.rng_state_offset_x,
- rtile.rng_state_offset_y,
- rtile.buffer_rng_state_stride,
- Queue_data,
- Queue_index,
- dQueue_size,
- use_queues_flag,
- work_array,
-#ifdef __WORK_STEALING__
- work_pool_wgs,
- num_samples,
-#endif
-#ifdef WITH_CYCLES_DEBUG
- debugdata_coop,
-#endif
- num_parallel_samples);
-
- kernel_set_args(ckPathTraceKernel_scene_intersect,
- 0,
- kgbuffer,
- d_data,
- rng_coop,
- Ray_coop,
- PathState_coop,
- Intersection_coop,
- ray_state,
- d_w,
- d_h,
- Queue_data,
- Queue_index,
- dQueue_size,
- use_queues_flag,
-#ifdef WITH_CYCLES_DEBUG
- debugdata_coop,
-#endif
- num_parallel_samples);
-
- kernel_set_args(ckPathTraceKernel_lamp_emission,
- 0,
- kgbuffer,
- d_data,
- throughput_coop,
- PathRadiance_coop,
- Ray_coop,
- PathState_coop,
- Intersection_coop,
- ray_state,
- d_w,
- d_h,
- Queue_data,
- Queue_index,
- dQueue_size,
- use_queues_flag,
- num_parallel_samples);
-
- kernel_set_args(ckPathTraceKernel_queue_enqueue,
- 0,
- Queue_data,
- Queue_index,
- ray_state,
- dQueue_size);
-
- kernel_set_args(ckPathTraceKernel_background_buffer_update,
- 0,
- kgbuffer,
- d_data,
- per_sample_output_buffers,
- d_rng_state,
- rng_coop,
- throughput_coop,
- PathRadiance_coop,
- Ray_coop,
- PathState_coop,
- L_transparent_coop,
- ray_state,
- d_w,
- d_h,
- d_x,
- d_y,
- d_stride,
- rtile.rng_state_offset_x,
- rtile.rng_state_offset_y,
- rtile.buffer_rng_state_stride,
- work_array,
- Queue_data,
- Queue_index,
- dQueue_size,
- end_sample,
- start_sample,
-#ifdef __WORK_STEALING__
- work_pool_wgs,
- num_samples,
-#endif
-#ifdef WITH_CYCLES_DEBUG
- debugdata_coop,
-#endif
- num_parallel_samples);
-
- kernel_set_args(ckPathTraceKernel_shader_eval,
- 0,
- kgbuffer,
- d_data,
- sd,
- rng_coop,
- Ray_coop,
- PathState_coop,
- Intersection_coop,
- ray_state,
- Queue_data,
- Queue_index,
- dQueue_size);
-
- kernel_set_args(ckPathTraceKernel_holdout_emission_blurring_pathtermination_ao,
- 0,
- kgbuffer,
- d_data,
- sd,
- per_sample_output_buffers,
- rng_coop,
- throughput_coop,
- L_transparent_coop,
- PathRadiance_coop,
- PathState_coop,
- Intersection_coop,
- AOAlpha_coop,
- AOBSDF_coop,
- AOLightRay_coop,
- d_w,
- d_h,
- d_x,
- d_y,
- d_stride,
- ray_state,
- work_array,
- Queue_data,
- Queue_index,
- dQueue_size,
-#ifdef __WORK_STEALING__
- start_sample,
-#endif
- num_parallel_samples);
-
- kernel_set_args(ckPathTraceKernel_direct_lighting,
- 0,
- kgbuffer,
- d_data,
- sd,
- rng_coop,
- PathState_coop,
- ISLamp_coop,
- LightRay_coop,
- BSDFEval_coop,
- ray_state,
- Queue_data,
- Queue_index,
- dQueue_size);
-
- kernel_set_args(ckPathTraceKernel_shadow_blocked,
- 0,
- kgbuffer,
- d_data,
- PathState_coop,
- LightRay_coop,
- AOLightRay_coop,
- ray_state,
- Queue_data,
- Queue_index,
- dQueue_size);
-
- kernel_set_args(ckPathTraceKernel_next_iteration_setup,
- 0,
- kgbuffer,
- d_data,
- sd,
- rng_coop,
- throughput_coop,
- PathRadiance_coop,
- Ray_coop,
- PathState_coop,
- LightRay_coop,
- ISLamp_coop,
- BSDFEval_coop,
- AOLightRay_coop,
- AOBSDF_coop,
- AOAlpha_coop,
- ray_state,
- Queue_data,
- Queue_index,
- dQueue_size,
- use_queues_flag);
-
- kernel_set_args(ckPathTraceKernel_sum_all_radiance,
- 0,
- d_data,
- d_buffer,
- per_sample_output_buffers,
- num_parallel_samples,
- d_w,
- d_h,
- d_stride,
- rtile.buffer_offset_x,
- rtile.buffer_offset_y,
- rtile.buffer_rng_state_stride,
- start_sample);
-
- /* Macro for Enqueuing split kernels. */
-#define GLUE(a, b) a ## b
-#define ENQUEUE_SPLIT_KERNEL(kernelName, globalSize, localSize) \
- { \
- ciErr = clEnqueueNDRangeKernel(cqCommandQueue, \
- GLUE(ckPathTraceKernel_, \
- kernelName), \
- 2, \
- NULL, \
- globalSize, \
- localSize, \
- 0, \
- NULL, \
- NULL); \
- opencl_assert_err(ciErr, "clEnqueueNDRangeKernel"); \
- if(ciErr != CL_SUCCESS) { \
- string message = string_printf("OpenCL error: %s in clEnqueueNDRangeKernel()", \
- clewErrorString(ciErr)); \
- opencl_error(message); \
- return; \
- } \
- } (void) 0
-
- /* Enqueue ckPathTraceKernel_data_init kernel. */
- ENQUEUE_SPLIT_KERNEL(data_init, global_size, local_size);
- bool activeRaysAvailable = true;
-
- /* Record number of time host intervention has been made */
- unsigned int numHostIntervention = 0;
- unsigned int numNextPathIterTimes = PathIteration_times;
- while(activeRaysAvailable) {
- /* Twice the global work size of other kernels for
- * ckPathTraceKernel_shadow_blocked_direct_lighting. */
- size_t global_size_shadow_blocked[2];
- global_size_shadow_blocked[0] = global_size[0] * 2;
- global_size_shadow_blocked[1] = global_size[1];
-
- /* Do path-iteration in host [Enqueue Path-iteration kernels. */
- for(int PathIter = 0; PathIter < PathIteration_times; PathIter++) {
- ENQUEUE_SPLIT_KERNEL(scene_intersect, global_size, local_size);
- ENQUEUE_SPLIT_KERNEL(lamp_emission, global_size, local_size);
- ENQUEUE_SPLIT_KERNEL(queue_enqueue, global_size, local_size);
- ENQUEUE_SPLIT_KERNEL(background_buffer_update, global_size, local_size);
- ENQUEUE_SPLIT_KERNEL(shader_eval, global_size, local_size);
- ENQUEUE_SPLIT_KERNEL(holdout_emission_blurring_pathtermination_ao, global_size, local_size);
- ENQUEUE_SPLIT_KERNEL(direct_lighting, global_size, local_size);
- ENQUEUE_SPLIT_KERNEL(shadow_blocked, global_size_shadow_blocked, local_size);
- ENQUEUE_SPLIT_KERNEL(next_iteration_setup, global_size, local_size);
- }
-
- /* Read ray-state into Host memory to decide if we should exit
- * path-iteration in host.
- */
- ciErr = clEnqueueReadBuffer(cqCommandQueue,
- ray_state,
- CL_TRUE,
- 0,
- global_size[0] * global_size[1] * sizeof(char),
- hostRayStateArray,
- 0,
- NULL,
- NULL);
- assert(ciErr == CL_SUCCESS);
-
- activeRaysAvailable = false;
-
- for(int rayStateIter = 0;
- rayStateIter < global_size[0] * global_size[1];
- ++rayStateIter)
- {
- if(int8_t(hostRayStateArray[rayStateIter]) != RAY_INACTIVE) {
- /* Not all rays are RAY_INACTIVE. */
- activeRaysAvailable = true;
- break;
- }
- }
-
- if(activeRaysAvailable) {
- numHostIntervention++;
- PathIteration_times = PATH_ITER_INC_FACTOR;
- /* Host intervention done before all rays become RAY_INACTIVE;
- * Set do more initial iterations for the next tile.
- */
- numNextPathIterTimes += PATH_ITER_INC_FACTOR;
- }
- }
-
- /* Execute SumALLRadiance kernel to accumulate radiance calculated in
- * per_sample_output_buffers into RenderTile's output buffer.
- */
- size_t sum_all_radiance_local_size[2] = {16, 16};
- size_t sum_all_radiance_global_size[2];
- sum_all_radiance_global_size[0] =
- (((d_w - 1) / sum_all_radiance_local_size[0]) + 1) *
- sum_all_radiance_local_size[0];
- sum_all_radiance_global_size[1] =
- (((d_h - 1) / sum_all_radiance_local_size[1]) + 1) *
- sum_all_radiance_local_size[1];
- ENQUEUE_SPLIT_KERNEL(sum_all_radiance,
- sum_all_radiance_global_size,
- sum_all_radiance_local_size);
-
-#undef ENQUEUE_SPLIT_KERNEL
-#undef GLUE
-
- if(numHostIntervention == 0) {
- /* This means that we are executing kernel more than required
- * Must avoid this for the next sample/tile.
- */
- PathIteration_times = ((numNextPathIterTimes - PATH_ITER_INC_FACTOR) <= 0) ?
- PATH_ITER_INC_FACTOR : numNextPathIterTimes - PATH_ITER_INC_FACTOR;
- }
- else {
- /* Number of path-iterations done for this tile is set as
- * Initial path-iteration times for the next tile
- */
- PathIteration_times = numNextPathIterTimes;
- }
-
- first_tile = false;
- }
-
- /* Calculates the amount of memory that has to be always
- * allocated in order for the split kernel to function.
- * This memory is tile/scene-property invariant (meaning,
- * the value returned by this function does not depend
- * on the user set tile size or scene properties.
- */
- size_t get_invariable_mem_allocated()
- {
- size_t total_invariable_mem_allocated = 0;
- size_t KernelGlobals_size = 0;
-
- KernelGlobals_size = get_KernelGlobals_size();
-
- total_invariable_mem_allocated += KernelGlobals_size; /* KernelGlobals size */
- total_invariable_mem_allocated += NUM_QUEUES * sizeof(unsigned int); /* Queue index size */
- total_invariable_mem_allocated += sizeof(char); /* use_queues_flag size */
-
- return total_invariable_mem_allocated;
- }
-
- /* Calculate the memory that has-to-be/has-been allocated for
- * the split kernel to function.
- */
- size_t get_tile_specific_mem_allocated(const int2 tile_size)
- {
- size_t tile_specific_mem_allocated = 0;
-
- /* Get required tile info */
- unsigned int user_set_tile_w = tile_size.x;
- unsigned int user_set_tile_h = tile_size.y;
-
-#ifdef __WORK_STEALING__
- /* Calculate memory to be allocated for work_pools in
- * case of work_stealing.
- */
- size_t max_global_size[2];
- size_t max_num_work_pools = 0;
- max_global_size[0] =
- (((user_set_tile_w - 1) / SPLIT_KERNEL_LOCAL_SIZE_X) + 1) *
- SPLIT_KERNEL_LOCAL_SIZE_X;
- max_global_size[1] =
- (((user_set_tile_h - 1) / SPLIT_KERNEL_LOCAL_SIZE_Y) + 1) *
- SPLIT_KERNEL_LOCAL_SIZE_Y;
- max_num_work_pools =
- (max_global_size[0] * max_global_size[1]) /
- (SPLIT_KERNEL_LOCAL_SIZE_X * SPLIT_KERNEL_LOCAL_SIZE_Y);
- tile_specific_mem_allocated += max_num_work_pools * sizeof(unsigned int);
-#endif
-
- tile_specific_mem_allocated +=
- user_set_tile_w * user_set_tile_h * per_thread_output_buffer_size;
- tile_specific_mem_allocated +=
- user_set_tile_w * user_set_tile_h * sizeof(RNG);
-
- return tile_specific_mem_allocated;
- }
-
- /* Calculates the texture memories and KernelData (d_data) memory
- * that has been allocated.
- */
- size_t get_scene_specific_mem_allocated(cl_mem d_data)
- {
- size_t scene_specific_mem_allocated = 0;
- /* Calculate texture memories. */
-#define KERNEL_TEX(type, ttype, name) \
- scene_specific_mem_allocated += get_tex_size(#name);
-#include "kernel_textures.h"
-#undef KERNEL_TEX
- size_t d_data_size;
- ciErr = clGetMemObjectInfo(d_data,
- CL_MEM_SIZE,
- sizeof(d_data_size),
- &d_data_size,
- NULL);
- assert(ciErr == CL_SUCCESS && "Can't get d_data mem object info");
- scene_specific_mem_allocated += d_data_size;
- return scene_specific_mem_allocated;
- }
-
- /* Calculate the memory required for one thread in split kernel. */
- size_t get_per_thread_memory()
- {
- size_t shaderdata_size = 0;
- /* TODO(sergey): This will actually over-allocate if
- * particular kernel does not support multiclosure.
- */
- shaderdata_size = get_shader_data_size(current_max_closure);
- size_t retval = sizeof(RNG)
- + sizeof(float3) /* Throughput size */
- + sizeof(float) /* L transparent size */
- + sizeof(char) /* Ray state size */
- + sizeof(unsigned int) /* Work element size */
- + sizeof(int) /* ISLamp_size */
- + sizeof(PathRadiance) + sizeof(Ray) + sizeof(PathState)
- + sizeof(Intersection) /* Overall isect */
- + sizeof(Intersection) /* Instersection_coop_AO */
- + sizeof(Intersection) /* Intersection coop DL */
- + shaderdata_size /* Overall ShaderData */
- + (shaderdata_size * 2) /* ShaderData : DL and shadow */
- + sizeof(Ray) + sizeof(BsdfEval)
- + sizeof(float3) /* AOAlpha size */
- + sizeof(float3) /* AOBSDF size */
- + sizeof(Ray)
- + (sizeof(int) * NUM_QUEUES)
- + per_thread_output_buffer_size;
- return retval;
- }
-
- /* Considers the total memory available in the device and
- * and returns the maximum global work size possible.
- */
- size_t get_feasible_global_work_size(int2 tile_size, cl_mem d_data)
- {
- /* Calculate invariably allocated memory. */
- size_t invariable_mem_allocated = get_invariable_mem_allocated();
- /* Calculate tile specific allocated memory. */
- size_t tile_specific_mem_allocated =
- get_tile_specific_mem_allocated(tile_size);
- /* Calculate scene specific allocated memory. */
- size_t scene_specific_mem_allocated =
- get_scene_specific_mem_allocated(d_data);
- /* Calculate total memory available for the threads in global work size. */
- size_t available_memory = total_allocatable_memory
- - invariable_mem_allocated
- - tile_specific_mem_allocated
- - scene_specific_mem_allocated
- - DATA_ALLOCATION_MEM_FACTOR;
- size_t per_thread_memory_required = get_per_thread_memory();
- return (available_memory / per_thread_memory_required);
- }
-
- /* Checks if the device has enough memory to render the whole tile;
- * If not, we should split single tile into multiple tiles of small size
- * and process them all.
- */
- bool need_to_split_tile(unsigned int d_w,
- unsigned int d_h,
- int2 max_render_feasible_tile_size)
- {
- size_t global_size_estimate[2];
- /* TODO(sergey): Such round-ups are in quite few places, need to replace
- * them with an utility macro.
- */
- global_size_estimate[0] =
- (((d_w - 1) / SPLIT_KERNEL_LOCAL_SIZE_X) + 1) *
- SPLIT_KERNEL_LOCAL_SIZE_X;
- global_size_estimate[1] =
- (((d_h - 1) / SPLIT_KERNEL_LOCAL_SIZE_Y) + 1) *
- SPLIT_KERNEL_LOCAL_SIZE_Y;
- if((global_size_estimate[0] * global_size_estimate[1]) >
- (max_render_feasible_tile_size.x * max_render_feasible_tile_size.y))
- {
- return true;
- }
- else {
- return false;
- }
- }
-
- /* Considers the scene properties, global memory available in the device
- * and returns a rectanglular tile dimension (approx the maximum)
- * that should render on split kernel.
- */
- int2 get_max_render_feasible_tile_size(size_t feasible_global_work_size)
- {
- int2 max_render_feasible_tile_size;
- int square_root_val = (int)sqrt(feasible_global_work_size);
- max_render_feasible_tile_size.x = square_root_val;
- max_render_feasible_tile_size.y = square_root_val;
- /* Ciel round-off max_render_feasible_tile_size. */
- int2 ceil_render_feasible_tile_size;
- ceil_render_feasible_tile_size.x =
- (((max_render_feasible_tile_size.x - 1) / SPLIT_KERNEL_LOCAL_SIZE_X) + 1) *
- SPLIT_KERNEL_LOCAL_SIZE_X;
- ceil_render_feasible_tile_size.y =
- (((max_render_feasible_tile_size.y - 1) / SPLIT_KERNEL_LOCAL_SIZE_Y) + 1) *
- SPLIT_KERNEL_LOCAL_SIZE_Y;
- if(ceil_render_feasible_tile_size.x * ceil_render_feasible_tile_size.y <=
- feasible_global_work_size)
- {
- return ceil_render_feasible_tile_size;
- }
- /* Floor round-off max_render_feasible_tile_size. */
- int2 floor_render_feasible_tile_size;
- floor_render_feasible_tile_size.x =
- (max_render_feasible_tile_size.x / SPLIT_KERNEL_LOCAL_SIZE_X) *
- SPLIT_KERNEL_LOCAL_SIZE_X;
- floor_render_feasible_tile_size.y =
- (max_render_feasible_tile_size.y / SPLIT_KERNEL_LOCAL_SIZE_Y) *
- SPLIT_KERNEL_LOCAL_SIZE_Y;
- return floor_render_feasible_tile_size;
- }
-
- /* Try splitting the current tile into multiple smaller
- * almost-square-tiles.
- */
- int2 get_split_tile_size(RenderTile rtile,
- int2 max_render_feasible_tile_size)
- {
- int2 split_tile_size;
- int num_global_threads = max_render_feasible_tile_size.x *
- max_render_feasible_tile_size.y;
- int d_w = rtile.w;
- int d_h = rtile.h;
- /* Ceil round off d_w and d_h */
- d_w = (((d_w - 1) / SPLIT_KERNEL_LOCAL_SIZE_X) + 1) *
- SPLIT_KERNEL_LOCAL_SIZE_X;
- d_h = (((d_h - 1) / SPLIT_KERNEL_LOCAL_SIZE_Y) + 1) *
- SPLIT_KERNEL_LOCAL_SIZE_Y;
- while(d_w * d_h > num_global_threads) {
- /* Halve the longer dimension. */
- if(d_w >= d_h) {
- d_w = d_w / 2;
- d_w = (((d_w - 1) / SPLIT_KERNEL_LOCAL_SIZE_X) + 1) *
- SPLIT_KERNEL_LOCAL_SIZE_X;
- }
- else {
- d_h = d_h / 2;
- d_h = (((d_h - 1) / SPLIT_KERNEL_LOCAL_SIZE_Y) + 1) *
- SPLIT_KERNEL_LOCAL_SIZE_Y;
- }
- }
- split_tile_size.x = d_w;
- split_tile_size.y = d_h;
- return split_tile_size;
- }
-
- /* Splits existing tile into multiple tiles of tile size split_tile_size. */
- vector<SplitRenderTile> split_tiles(RenderTile rtile, int2 split_tile_size)
- {
- vector<SplitRenderTile> to_path_trace_rtile;
- int d_w = rtile.w;
- int d_h = rtile.h;
- int num_tiles_x = (((d_w - 1) / split_tile_size.x) + 1);
- int num_tiles_y = (((d_h - 1) / split_tile_size.y) + 1);
- /* Buffer and rng_state offset calc. */
- size_t offset_index = rtile.offset + (rtile.x + rtile.y * rtile.stride);
- size_t offset_x = offset_index % rtile.stride;
- size_t offset_y = offset_index / rtile.stride;
- /* Resize to_path_trace_rtile. */
- to_path_trace_rtile.resize(num_tiles_x * num_tiles_y);
- for(int tile_iter_y = 0; tile_iter_y < num_tiles_y; tile_iter_y++) {
- for(int tile_iter_x = 0; tile_iter_x < num_tiles_x; tile_iter_x++) {
- int rtile_index = tile_iter_y * num_tiles_x + tile_iter_x;
- to_path_trace_rtile[rtile_index].rng_state_offset_x = offset_x + tile_iter_x * split_tile_size.x;
- to_path_trace_rtile[rtile_index].rng_state_offset_y = offset_y + tile_iter_y * split_tile_size.y;
- to_path_trace_rtile[rtile_index].buffer_offset_x = offset_x + tile_iter_x * split_tile_size.x;
- to_path_trace_rtile[rtile_index].buffer_offset_y = offset_y + tile_iter_y * split_tile_size.y;
- to_path_trace_rtile[rtile_index].start_sample = rtile.start_sample;
- to_path_trace_rtile[rtile_index].num_samples = rtile.num_samples;
- to_path_trace_rtile[rtile_index].sample = rtile.sample;
- to_path_trace_rtile[rtile_index].resolution = rtile.resolution;
- to_path_trace_rtile[rtile_index].offset = rtile.offset;
- to_path_trace_rtile[rtile_index].buffers = rtile.buffers;
- to_path_trace_rtile[rtile_index].buffer = rtile.buffer;
- to_path_trace_rtile[rtile_index].rng_state = rtile.rng_state;
- to_path_trace_rtile[rtile_index].x = rtile.x + (tile_iter_x * split_tile_size.x);
- to_path_trace_rtile[rtile_index].y = rtile.y + (tile_iter_y * split_tile_size.y);
- to_path_trace_rtile[rtile_index].buffer_rng_state_stride = rtile.stride;
- /* Fill width and height of the new render tile. */
- to_path_trace_rtile[rtile_index].w = (tile_iter_x == (num_tiles_x - 1)) ?
- (d_w - (tile_iter_x * split_tile_size.x)) /* Border tile */
- : split_tile_size.x;
- to_path_trace_rtile[rtile_index].h = (tile_iter_y == (num_tiles_y - 1)) ?
- (d_h - (tile_iter_y * split_tile_size.y)) /* Border tile */
- : split_tile_size.y;
- to_path_trace_rtile[rtile_index].stride = to_path_trace_rtile[rtile_index].w;
- }
- }
- return to_path_trace_rtile;
- }
-
- void thread_run(DeviceTask *task)
- {
- if(task->type == DeviceTask::FILM_CONVERT) {
- film_convert(*task, task->buffer, task->rgba_byte, task->rgba_half);
- }
- else if(task->type == DeviceTask::SHADER) {
- shader(*task);
- }
- else if(task->type == DeviceTask::PATH_TRACE) {
- RenderTile tile;
- bool initialize_data_and_check_render_feasibility = false;
- bool need_to_split_tiles_further = false;
- int2 max_render_feasible_tile_size;
- size_t feasible_global_work_size;
- const int2 tile_size = task->requested_tile_size;
- /* Keep rendering tiles until done. */
- while(task->acquire_tile(this, tile)) {
- if(!initialize_data_and_check_render_feasibility) {
- /* Initialize data. */
- /* Calculate per_thread_output_buffer_size. */
- size_t output_buffer_size = 0;
- ciErr = clGetMemObjectInfo((cl_mem)tile.buffer,
- CL_MEM_SIZE,
- sizeof(output_buffer_size),
- &output_buffer_size,
- NULL);
- assert(ciErr == CL_SUCCESS && "Can't get tile.buffer mem object info");
- /* This value is different when running on AMD and NV. */
- if(background) {
- /* In offline render the number of buffer elements
- * associated with tile.buffer is the current tile size.
- */
- per_thread_output_buffer_size =
- output_buffer_size / (tile.w * tile.h);
- }
- else {
- /* interactive rendering, unlike offline render, the number of buffer elements
- * associated with tile.buffer is the entire viewport size.
- */
- per_thread_output_buffer_size =
- output_buffer_size / (tile.buffers->params.width *
- tile.buffers->params.height);
- }
- /* Check render feasibility. */
- feasible_global_work_size = get_feasible_global_work_size(
- tile_size,
- CL_MEM_PTR(const_mem_map["__data"]->device_pointer));
- max_render_feasible_tile_size =
- get_max_render_feasible_tile_size(
- feasible_global_work_size);
- need_to_split_tiles_further =
- need_to_split_tile(tile_size.x,
- tile_size.y,
- max_render_feasible_tile_size);
- initialize_data_and_check_render_feasibility = true;
- }
- if(need_to_split_tiles_further) {
- int2 split_tile_size =
- get_split_tile_size(tile,
- max_render_feasible_tile_size);
- vector<SplitRenderTile> to_path_trace_render_tiles =
- split_tiles(tile, split_tile_size);
- /* Print message to console */
- if(background && (to_path_trace_render_tiles.size() > 1)) {
- fprintf(stderr, "Message : Tiles need to be split "
- "further inside path trace (due to insufficient "
- "device-global-memory for split kernel to "
- "function) \n"
- "The current tile of dimensions %dx%d is split "
- "into tiles of dimension %dx%d for render \n",
- tile.w, tile.h,
- split_tile_size.x,
- split_tile_size.y);
- }
- /* Process all split tiles. */
- for(int tile_iter = 0;
- tile_iter < to_path_trace_render_tiles.size();
- ++tile_iter)
- {
- path_trace(to_path_trace_render_tiles[tile_iter],
- max_render_feasible_tile_size);
- }
- }
- else {
- /* No splitting required; process the entire tile at once. */
- /* Render feasible tile size is user-set-tile-size itself. */
- max_render_feasible_tile_size.x =
- (((tile_size.x - 1) / SPLIT_KERNEL_LOCAL_SIZE_X) + 1) *
- SPLIT_KERNEL_LOCAL_SIZE_X;
- max_render_feasible_tile_size.y =
- (((tile_size.y - 1) / SPLIT_KERNEL_LOCAL_SIZE_Y) + 1) *
- SPLIT_KERNEL_LOCAL_SIZE_Y;
- /* buffer_rng_state_stride is stride itself. */
- SplitRenderTile split_tile(tile);
- split_tile.buffer_rng_state_stride = tile.stride;
- path_trace(split_tile, max_render_feasible_tile_size);
- }
- tile.sample = tile.start_sample + tile.num_samples;
-
- /* Complete kernel execution before release tile. */
- /* This helps in multi-device render;
- * The device that reaches the critical-section function
- * release_tile waits (stalling other devices from entering
- * release_tile) for all kernels to complete. If device1 (a
- * slow-render device) reaches release_tile first then it would
- * stall device2 (a fast-render device) from proceeding to render
- * next tile.
- */
- clFinish(cqCommandQueue);
-
- task->release_tile(tile);
- }
- }
- }
-
-protected:
- cl_mem mem_alloc(size_t bufsize, cl_mem_flags mem_flag = CL_MEM_READ_WRITE)
- {
- cl_mem ptr;
- assert(bufsize != 0);
- ptr = clCreateBuffer(cxContext, mem_flag, bufsize, NULL, &ciErr);
- opencl_assert_err(ciErr, "clCreateBuffer");
- return ptr;
- }
-
- /* ** Those guys are for workign around some compiler-specific bugs ** */
-
- cl_program load_cached_kernel(
- const DeviceRequestedFeatures& /*requested_features*/,
- OpenCLCache::ProgramName /*program_name*/,
- thread_scoped_lock /*cache_locker*/)
- {
- VLOG(2) << "Skip loading kernel from cache, "
- << "not supported by split kernel.";
- return NULL;
- }
-
- void store_cached_kernel(cl_platform_id /*platform*/,
- cl_device_id /*device*/,
- cl_program /*program*/,
- OpenCLCache::ProgramName /*program_name*/,
- thread_scoped_lock& /*slot_locker*/)
- {
- VLOG(2) << "Skip storing kernel in cache, "
- << "not supported by split kernel.";
- }
-
- string build_options_for_base_program(
- const DeviceRequestedFeatures& requested_features)
- {
- return requested_features.get_build_options();
- }
-};
-
Device *device_opencl_create(DeviceInfo& info, Stats &stats, bool background)
{
vector<OpenCLPlatformDevice> usable_devices;
- opencl_get_usable_devices(&usable_devices);
+ OpenCLInfo::get_usable_devices(&usable_devices);
assert(info.num < usable_devices.size());
const OpenCLPlatformDevice& platform_device = usable_devices[info.num];
const string& platform_name = platform_device.platform_name;
const cl_device_type device_type = platform_device.device_type;
- if(opencl_kernel_use_split(platform_name, device_type)) {
+ if(OpenCLInfo::kernel_use_split(platform_name, device_type)) {
VLOG(1) << "Using split kernel.";
- return new OpenCLDeviceSplitKernel(info, stats, background);
+ return opencl_create_split_device(info, stats, background);
} else {
VLOG(1) << "Using mega kernel.";
- return new OpenCLDeviceMegaKernel(info, stats, background);
+ return opencl_create_mega_device(info, stats, background);
}
}
@@ -3253,7 +52,7 @@ bool device_opencl_init(void)
initialized = true;
- if(opencl_device_type() != 0) {
+ if(OpenCLInfo::device_type() != 0) {
int clew_result = clewInit();
if(clew_result == CLEW_SUCCESS) {
VLOG(1) << "CLEW initialization succeeded.";
@@ -3277,7 +76,7 @@ bool device_opencl_init(void)
void device_opencl_info(vector<DeviceInfo>& devices)
{
vector<OpenCLPlatformDevice> usable_devices;
- opencl_get_usable_devices(&usable_devices);
+ OpenCLInfo::get_usable_devices(&usable_devices);
/* Devices are numbered consecutively across platforms. */
int num_devices = 0;
foreach(OpenCLPlatformDevice& platform_device, usable_devices) {
@@ -3291,10 +90,10 @@ void device_opencl_info(vector<DeviceInfo>& devices)
info.id = string_printf("OPENCL_%d", info.num);
/* We don't know if it's used for display, but assume it is. */
info.display_device = true;
- info.advanced_shading = opencl_kernel_use_advanced_shading(platform_name);
+ info.advanced_shading = OpenCLInfo::kernel_use_advanced_shading(platform_name);
info.pack_images = true;
- info.use_split_kernel = opencl_kernel_use_split(platform_name,
- device_type);
+ info.use_split_kernel = OpenCLInfo::kernel_use_split(platform_name,
+ device_type);
devices.push_back(info);
num_devices++;
}
@@ -3302,7 +101,7 @@ void device_opencl_info(vector<DeviceInfo>& devices)
string device_opencl_capabilities(void)
{
- if(opencl_device_type() == 0) {
+ if(OpenCLInfo::device_type() == 0) {
return "All OpenCL devices are forced to be OFF";
}
string result = "";
diff --git a/intern/cycles/device/device_task.h b/intern/cycles/device/device_task.h
index d7912f386f5..8423e83bdfd 100644
--- a/intern/cycles/device/device_task.h
+++ b/intern/cycles/device/device_task.h
@@ -51,7 +51,7 @@ public:
int shader_filter;
int shader_x, shader_w;
- DeviceTask(Type type = PATH_TRACE);
+ explicit DeviceTask(Type type = PATH_TRACE);
int get_subtask_count(int num, int max_size = 0);
void split(list<DeviceTask>& tasks, int num, int max_size = 0);
diff --git a/intern/cycles/device/opencl/opencl.h b/intern/cycles/device/opencl/opencl.h
new file mode 100644
index 00000000000..30a35acbb2a
--- /dev/null
+++ b/intern/cycles/device/opencl/opencl.h
@@ -0,0 +1,403 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef WITH_OPENCL
+
+#include "clew.h"
+
+#include "device.h"
+
+#include "util_map.h"
+#include "util_param.h"
+#include "util_string.h"
+
+CCL_NAMESPACE_BEGIN
+
+#define CL_MEM_PTR(p) ((cl_mem)(uintptr_t)(p))
+
+/* Macro declarations used with split kernel */
+
+/* Macro to enable/disable work-stealing */
+#define __WORK_STEALING__
+
+#define SPLIT_KERNEL_LOCAL_SIZE_X 64
+#define SPLIT_KERNEL_LOCAL_SIZE_Y 1
+
+/* This value may be tuned according to the scene we are rendering.
+ *
+ * Modifying PATH_ITER_INC_FACTOR value proportional to number of expected
+ * ray-bounces will improve performance.
+ */
+#define PATH_ITER_INC_FACTOR 8
+
+/* When allocate global memory in chunks. We may not be able to
+ * allocate exactly "CL_DEVICE_MAX_MEM_ALLOC_SIZE" bytes in chunks;
+ * Since some bytes may be needed for aligning chunks of memory;
+ * This is the amount of memory that we dedicate for that purpose.
+ */
+#define DATA_ALLOCATION_MEM_FACTOR 5000000 //5MB
+
+struct OpenCLPlatformDevice {
+ OpenCLPlatformDevice(cl_platform_id platform_id,
+ const string& platform_name,
+ cl_device_id device_id,
+ cl_device_type device_type,
+ const string& device_name)
+ : platform_id(platform_id),
+ platform_name(platform_name),
+ device_id(device_id),
+ device_type(device_type),
+ device_name(device_name) {}
+ cl_platform_id platform_id;
+ string platform_name;
+ cl_device_id device_id;
+ cl_device_type device_type;
+ string device_name;
+};
+
+/* Contains all static OpenCL helper functions. */
+class OpenCLInfo
+{
+public:
+ static cl_device_type device_type();
+ static bool use_debug();
+ static bool kernel_use_advanced_shading(const string& platform_name);
+ static bool kernel_use_split(const string& platform_name,
+ const cl_device_type device_type);
+ static bool device_supported(const string& platform_name,
+ const cl_device_id device_id);
+ static bool platform_version_check(cl_platform_id platform,
+ string *error = NULL);
+ static bool device_version_check(cl_device_id device,
+ string *error = NULL);
+ static void get_usable_devices(vector<OpenCLPlatformDevice> *usable_devices,
+ bool force_all = false);
+};
+
+/* Thread safe cache for contexts and programs.
+ */
+class OpenCLCache
+{
+ struct Slot
+ {
+ struct ProgramEntry
+ {
+ ProgramEntry();
+ ProgramEntry(const ProgramEntry& rhs);
+ ~ProgramEntry();
+ cl_program program;
+ thread_mutex *mutex;
+ };
+
+ Slot();
+ Slot(const Slot& rhs);
+ ~Slot();
+
+ thread_mutex *context_mutex;
+ cl_context context;
+ typedef map<ustring, ProgramEntry> EntryMap;
+ EntryMap programs;
+
+ };
+
+ /* key is combination of platform ID and device ID */
+ typedef pair<cl_platform_id, cl_device_id> PlatformDevicePair;
+
+ /* map of Slot objects */
+ typedef map<PlatformDevicePair, Slot> CacheMap;
+ CacheMap cache;
+
+ /* MD5 hash of the kernel source. */
+ string kernel_md5;
+
+ thread_mutex cache_lock;
+ thread_mutex kernel_md5_lock;
+
+ /* lazy instantiate */
+ static OpenCLCache& global_instance();
+
+public:
+
+ enum ProgramName {
+ OCL_DEV_BASE_PROGRAM,
+ OCL_DEV_MEGAKERNEL_PROGRAM,
+ };
+
+ /* Lookup context in the cache. If this returns NULL, slot_locker
+ * will be holding a lock for the cache. slot_locker should refer to a
+ * default constructed thread_scoped_lock. */
+ static cl_context get_context(cl_platform_id platform,
+ cl_device_id device,
+ thread_scoped_lock& slot_locker);
+ /* Same as above. */
+ static cl_program get_program(cl_platform_id platform,
+ cl_device_id device,
+ ustring key,
+ thread_scoped_lock& slot_locker);
+
+ /* Store context in the cache. You MUST have tried to get the item before storing to it. */
+ static void store_context(cl_platform_id platform,
+ cl_device_id device,
+ cl_context context,
+ thread_scoped_lock& slot_locker);
+ /* Same as above. */
+ static void store_program(cl_platform_id platform,
+ cl_device_id device,
+ cl_program program,
+ ustring key,
+ thread_scoped_lock& slot_locker);
+
+ static string get_kernel_md5();
+};
+
+#define opencl_assert(stmt) \
+ { \
+ cl_int err = stmt; \
+ \
+ if(err != CL_SUCCESS) { \
+ string message = string_printf("OpenCL error: %s in %s", clewErrorString(err), #stmt); \
+ if(error_msg == "") \
+ error_msg = message; \
+ fprintf(stderr, "%s\n", message.c_str()); \
+ } \
+ } (void)0
+
+class OpenCLDeviceBase : public Device
+{
+public:
+ DedicatedTaskPool task_pool;
+ cl_context cxContext;
+ cl_command_queue cqCommandQueue;
+ cl_platform_id cpPlatform;
+ cl_device_id cdDevice;
+ cl_int ciErr;
+
+ class OpenCLProgram {
+ public:
+ OpenCLProgram() : loaded(false), device(NULL) {}
+ OpenCLProgram(OpenCLDeviceBase *device,
+ string program_name,
+ string kernel_name,
+ string kernel_build_options,
+ bool use_stdout = true);
+ ~OpenCLProgram();
+
+ void add_kernel(ustring name);
+ void load();
+
+ bool is_loaded() { return loaded; }
+ string get_log() { return log; }
+ void report_error();
+
+ cl_kernel operator()();
+ cl_kernel operator()(ustring name);
+
+ void release();
+
+ private:
+ bool build_kernel(const string *debug_src);
+ bool compile_kernel(const string *debug_src);
+ bool load_binary(const string& clbin, const string *debug_src = NULL);
+ bool save_binary(const string& clbin);
+
+ void add_log(string msg, bool is_debug);
+ void add_error(string msg);
+
+ bool loaded;
+ cl_program program;
+ OpenCLDeviceBase *device;
+
+ /* Used for the OpenCLCache key. */
+ string program_name;
+
+ string kernel_file, kernel_build_options, device_md5;
+
+ bool use_stdout;
+ string log, error_msg;
+ string compile_output;
+
+ map<ustring, cl_kernel> kernels;
+ };
+
+ OpenCLProgram base_program;
+
+ typedef map<string, device_vector<uchar>*> ConstMemMap;
+ typedef map<string, device_ptr> MemMap;
+
+ ConstMemMap const_mem_map;
+ MemMap mem_map;
+ device_ptr null_mem;
+
+ bool device_initialized;
+ string platform_name;
+
+ bool opencl_error(cl_int err);
+ void opencl_error(const string& message);
+ void opencl_assert_err(cl_int err, const char* where);
+
+ OpenCLDeviceBase(DeviceInfo& info, Stats &stats, bool background_);
+ ~OpenCLDeviceBase();
+
+ static void CL_CALLBACK context_notify_callback(const char *err_info,
+ const void * /*private_info*/, size_t /*cb*/, void *user_data);
+
+ bool opencl_version_check();
+
+ string device_md5_hash(string kernel_custom_build_options = "");
+ bool load_kernels(const DeviceRequestedFeatures& requested_features);
+
+ /* Has to be implemented by the real device classes.
+ * The base device will then load all these programs. */
+ virtual void load_kernels(const DeviceRequestedFeatures& requested_features,
+ vector<OpenCLProgram*> &programs) = 0;
+
+ void mem_alloc(device_memory& mem, MemoryType type);
+ void mem_copy_to(device_memory& mem);
+ void mem_copy_from(device_memory& mem, int y, int w, int h, int elem);
+ void mem_zero(device_memory& mem);
+ void mem_free(device_memory& mem);
+ void const_copy_to(const char *name, void *host, size_t size);
+ void tex_alloc(const char *name,
+ device_memory& mem,
+ InterpolationType /*interpolation*/,
+ ExtensionType /*extension*/);
+ void tex_free(device_memory& mem);
+
+ size_t global_size_round_up(int group_size, int global_size);
+ void enqueue_kernel(cl_kernel kernel, size_t w, size_t h);
+ void set_kernel_arg_mem(cl_kernel kernel, cl_uint *narg, const char *name);
+
+ void film_convert(DeviceTask& task, device_ptr buffer, device_ptr rgba_byte, device_ptr rgba_half);
+ void shader(DeviceTask& task);
+
+ class OpenCLDeviceTask : public DeviceTask {
+ public:
+ OpenCLDeviceTask(OpenCLDeviceBase *device, DeviceTask& task)
+ : DeviceTask(task)
+ {
+ run = function_bind(&OpenCLDeviceBase::thread_run,
+ device,
+ this);
+ }
+ };
+
+ int get_split_task_count(DeviceTask& /*task*/)
+ {
+ return 1;
+ }
+
+ void task_add(DeviceTask& task)
+ {
+ task_pool.push(new OpenCLDeviceTask(this, task));
+ }
+
+ void task_wait()
+ {
+ task_pool.wait();
+ }
+
+ void task_cancel()
+ {
+ task_pool.cancel();
+ }
+
+ virtual void thread_run(DeviceTask * /*task*/) = 0;
+
+protected:
+ string kernel_build_options(const string *debug_src = NULL);
+
+ class ArgumentWrapper {
+ public:
+ ArgumentWrapper() : size(0), pointer(NULL) {}
+ template <typename T>
+ ArgumentWrapper(T& argument) : size(sizeof(argument)),
+ pointer(&argument) { }
+ ArgumentWrapper(int argument) : size(sizeof(int)),
+ int_value(argument),
+ pointer(&int_value) { }
+ ArgumentWrapper(float argument) : size(sizeof(float)),
+ float_value(argument),
+ pointer(&float_value) { }
+ size_t size;
+ int int_value;
+ float float_value;
+ void *pointer;
+ };
+
+ /* TODO(sergey): In the future we can use variadic templates, once
+ * C++0x is allowed. Should allow to clean this up a bit.
+ */
+ int kernel_set_args(cl_kernel kernel,
+ int start_argument_index,
+ const ArgumentWrapper& arg1 = ArgumentWrapper(),
+ const ArgumentWrapper& arg2 = ArgumentWrapper(),
+ const ArgumentWrapper& arg3 = ArgumentWrapper(),
+ const ArgumentWrapper& arg4 = ArgumentWrapper(),
+ const ArgumentWrapper& arg5 = ArgumentWrapper(),
+ const ArgumentWrapper& arg6 = ArgumentWrapper(),
+ const ArgumentWrapper& arg7 = ArgumentWrapper(),
+ const ArgumentWrapper& arg8 = ArgumentWrapper(),
+ const ArgumentWrapper& arg9 = ArgumentWrapper(),
+ const ArgumentWrapper& arg10 = ArgumentWrapper(),
+ const ArgumentWrapper& arg11 = ArgumentWrapper(),
+ const ArgumentWrapper& arg12 = ArgumentWrapper(),
+ const ArgumentWrapper& arg13 = ArgumentWrapper(),
+ const ArgumentWrapper& arg14 = ArgumentWrapper(),
+ const ArgumentWrapper& arg15 = ArgumentWrapper(),
+ const ArgumentWrapper& arg16 = ArgumentWrapper(),
+ const ArgumentWrapper& arg17 = ArgumentWrapper(),
+ const ArgumentWrapper& arg18 = ArgumentWrapper(),
+ const ArgumentWrapper& arg19 = ArgumentWrapper(),
+ const ArgumentWrapper& arg20 = ArgumentWrapper(),
+ const ArgumentWrapper& arg21 = ArgumentWrapper(),
+ const ArgumentWrapper& arg22 = ArgumentWrapper(),
+ const ArgumentWrapper& arg23 = ArgumentWrapper(),
+ const ArgumentWrapper& arg24 = ArgumentWrapper(),
+ const ArgumentWrapper& arg25 = ArgumentWrapper(),
+ const ArgumentWrapper& arg26 = ArgumentWrapper(),
+ const ArgumentWrapper& arg27 = ArgumentWrapper(),
+ const ArgumentWrapper& arg28 = ArgumentWrapper(),
+ const ArgumentWrapper& arg29 = ArgumentWrapper(),
+ const ArgumentWrapper& arg30 = ArgumentWrapper(),
+ const ArgumentWrapper& arg31 = ArgumentWrapper(),
+ const ArgumentWrapper& arg32 = ArgumentWrapper(),
+ const ArgumentWrapper& arg33 = ArgumentWrapper());
+
+ void release_kernel_safe(cl_kernel kernel);
+ void release_mem_object_safe(cl_mem mem);
+ void release_program_safe(cl_program program);
+
+ /* ** Those guys are for workign around some compiler-specific bugs ** */
+
+ virtual cl_program load_cached_kernel(
+ ustring key,
+ thread_scoped_lock& cache_locker);
+
+ virtual void store_cached_kernel(
+ cl_program program,
+ ustring key,
+ thread_scoped_lock& cache_locker);
+
+ virtual string build_options_for_base_program(
+ const DeviceRequestedFeatures& /*requested_features*/);
+};
+
+Device *opencl_create_mega_device(DeviceInfo& info, Stats& stats, bool background);
+Device *opencl_create_split_device(DeviceInfo& info, Stats& stats, bool background);
+
+CCL_NAMESPACE_END
+
+#endif
diff --git a/intern/cycles/device/opencl/opencl_base.cpp b/intern/cycles/device/opencl/opencl_base.cpp
new file mode 100644
index 00000000000..a2b900312e7
--- /dev/null
+++ b/intern/cycles/device/opencl/opencl_base.cpp
@@ -0,0 +1,741 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef WITH_OPENCL
+
+#include "opencl.h"
+
+#include "kernel_types.h"
+
+#include "util_foreach.h"
+#include "util_logging.h"
+#include "util_md5.h"
+#include "util_path.h"
+#include "util_time.h"
+
+CCL_NAMESPACE_BEGIN
+
+bool OpenCLDeviceBase::opencl_error(cl_int err)
+{
+ if(err != CL_SUCCESS) {
+ string message = string_printf("OpenCL error (%d): %s", err, clewErrorString(err));
+ if(error_msg == "")
+ error_msg = message;
+ fprintf(stderr, "%s\n", message.c_str());
+ return true;
+ }
+
+ return false;
+}
+
+void OpenCLDeviceBase::opencl_error(const string& message)
+{
+ if(error_msg == "")
+ error_msg = message;
+ fprintf(stderr, "%s\n", message.c_str());
+}
+
+void OpenCLDeviceBase::opencl_assert_err(cl_int err, const char* where)
+{
+ if(err != CL_SUCCESS) {
+ string message = string_printf("OpenCL error (%d): %s in %s", err, clewErrorString(err), where);
+ if(error_msg == "")
+ error_msg = message;
+ fprintf(stderr, "%s\n", message.c_str());
+#ifndef NDEBUG
+ abort();
+#endif
+ }
+}
+
+OpenCLDeviceBase::OpenCLDeviceBase(DeviceInfo& info, Stats &stats, bool background_)
+: Device(info, stats, background_)
+{
+ cpPlatform = NULL;
+ cdDevice = NULL;
+ cxContext = NULL;
+ cqCommandQueue = NULL;
+ null_mem = 0;
+ device_initialized = false;
+
+ vector<OpenCLPlatformDevice> usable_devices;
+ OpenCLInfo::get_usable_devices(&usable_devices);
+ if(usable_devices.size() == 0) {
+ opencl_error("OpenCL: no devices found.");
+ return;
+ }
+ assert(info.num < usable_devices.size());
+ OpenCLPlatformDevice& platform_device = usable_devices[info.num];
+ cpPlatform = platform_device.platform_id;
+ cdDevice = platform_device.device_id;
+ platform_name = platform_device.platform_name;
+ VLOG(2) << "Creating new Cycles device for OpenCL platform "
+ << platform_name << ", device "
+ << platform_device.device_name << ".";
+
+ {
+ /* try to use cached context */
+ thread_scoped_lock cache_locker;
+ cxContext = OpenCLCache::get_context(cpPlatform, cdDevice, cache_locker);
+
+ if(cxContext == NULL) {
+ /* create context properties array to specify platform */
+ const cl_context_properties context_props[] = {
+ CL_CONTEXT_PLATFORM, (cl_context_properties)cpPlatform,
+ 0, 0
+ };
+
+ /* create context */
+ cxContext = clCreateContext(context_props, 1, &cdDevice,
+ context_notify_callback, cdDevice, &ciErr);
+
+ if(opencl_error(ciErr)) {
+ opencl_error("OpenCL: clCreateContext failed");
+ return;
+ }
+
+ /* cache it */
+ OpenCLCache::store_context(cpPlatform, cdDevice, cxContext, cache_locker);
+ }
+ }
+
+ cqCommandQueue = clCreateCommandQueue(cxContext, cdDevice, 0, &ciErr);
+ if(opencl_error(ciErr))
+ return;
+
+ null_mem = (device_ptr)clCreateBuffer(cxContext, CL_MEM_READ_ONLY, 1, NULL, &ciErr);
+ if(opencl_error(ciErr))
+ return;
+
+ fprintf(stderr, "Device init success\n");
+ device_initialized = true;
+}
+
+OpenCLDeviceBase::~OpenCLDeviceBase()
+{
+ task_pool.stop();
+
+ if(null_mem)
+ clReleaseMemObject(CL_MEM_PTR(null_mem));
+
+ ConstMemMap::iterator mt;
+ for(mt = const_mem_map.begin(); mt != const_mem_map.end(); mt++) {
+ mem_free(*(mt->second));
+ delete mt->second;
+ }
+
+ base_program.release();
+ if(cqCommandQueue)
+ clReleaseCommandQueue(cqCommandQueue);
+ if(cxContext)
+ clReleaseContext(cxContext);
+}
+
+void CL_CALLBACK OpenCLDeviceBase::context_notify_callback(const char *err_info,
+ const void * /*private_info*/, size_t /*cb*/, void *user_data)
+{
+ char name[256];
+ clGetDeviceInfo((cl_device_id)user_data, CL_DEVICE_NAME, sizeof(name), &name, NULL);
+
+ fprintf(stderr, "OpenCL error (%s): %s\n", name, err_info);
+}
+
+bool OpenCLDeviceBase::opencl_version_check()
+{
+ string error;
+ if(!OpenCLInfo::platform_version_check(cpPlatform, &error)) {
+ opencl_error(error);
+ return false;
+ }
+ if(!OpenCLInfo::device_version_check(cdDevice, &error)) {
+ opencl_error(error);
+ return false;
+ }
+ return true;
+}
+
+string OpenCLDeviceBase::device_md5_hash(string kernel_custom_build_options)
+{
+ MD5Hash md5;
+ char version[256], driver[256], name[256], vendor[256];
+
+ clGetPlatformInfo(cpPlatform, CL_PLATFORM_VENDOR, sizeof(vendor), &vendor, NULL);
+ clGetDeviceInfo(cdDevice, CL_DEVICE_VERSION, sizeof(version), &version, NULL);
+ clGetDeviceInfo(cdDevice, CL_DEVICE_NAME, sizeof(name), &name, NULL);
+ clGetDeviceInfo(cdDevice, CL_DRIVER_VERSION, sizeof(driver), &driver, NULL);
+
+ md5.append((uint8_t*)vendor, strlen(vendor));
+ md5.append((uint8_t*)version, strlen(version));
+ md5.append((uint8_t*)name, strlen(name));
+ md5.append((uint8_t*)driver, strlen(driver));
+
+ string options = kernel_build_options();
+ options += kernel_custom_build_options;
+ md5.append((uint8_t*)options.c_str(), options.size());
+
+ return md5.get_hex();
+}
+
+bool OpenCLDeviceBase::load_kernels(const DeviceRequestedFeatures& requested_features)
+{
+ /* Verify if device was initialized. */
+ if(!device_initialized) {
+ fprintf(stderr, "OpenCL: failed to initialize device.\n");
+ return false;
+ }
+
+ /* Verify we have right opencl version. */
+ if(!opencl_version_check())
+ return false;
+
+ base_program = OpenCLProgram(this, "base", "kernel.cl", build_options_for_base_program(requested_features));
+ base_program.add_kernel(ustring("convert_to_byte"));
+ base_program.add_kernel(ustring("convert_to_half_float"));
+ base_program.add_kernel(ustring("shader"));
+ base_program.add_kernel(ustring("bake"));
+
+ vector<OpenCLProgram*> programs;
+ programs.push_back(&base_program);
+ /* Call actual class to fill the vector with its programs. */
+ load_kernels(requested_features, programs);
+
+ /* Parallel compilation is supported by Cycles, but currently all OpenCL frameworks
+ * serialize the calls internally, so it's not much use right now.
+ * Note: When enabling parallel compilation, use_stdout in the OpenCLProgram constructor
+ * should be set to false as well. */
+#if 0
+ TaskPool task_pool;
+ foreach(OpenCLProgram *program, programs) {
+ task_pool.push(function_bind(&OpenCLProgram::load, program));
+ }
+ task_pool.wait_work();
+
+ foreach(OpenCLProgram *program, programs) {
+ VLOG(2) << program->get_log();
+ if(!program->is_loaded()) {
+ program->report_error();
+ return false;
+ }
+ }
+#else
+ foreach(OpenCLProgram *program, programs) {
+ program->load();
+ if(!program->is_loaded()) {
+ return false;
+ }
+ }
+#endif
+
+ return true;
+}
+
+void OpenCLDeviceBase::mem_alloc(device_memory& mem, MemoryType type)
+{
+ size_t size = mem.memory_size();
+
+ cl_mem_flags mem_flag;
+ void *mem_ptr = NULL;
+
+ if(type == MEM_READ_ONLY)
+ mem_flag = CL_MEM_READ_ONLY;
+ else if(type == MEM_WRITE_ONLY)
+ mem_flag = CL_MEM_WRITE_ONLY;
+ else
+ mem_flag = CL_MEM_READ_WRITE;
+
+ /* Zero-size allocation might be invoked by render, but not really
+ * supported by OpenCL. Using NULL as device pointer also doesn't really
+ * work for some reason, so for the time being we'll use special case
+ * will null_mem buffer.
+ */
+ if(size != 0) {
+ mem.device_pointer = (device_ptr)clCreateBuffer(cxContext,
+ mem_flag,
+ size,
+ mem_ptr,
+ &ciErr);
+ opencl_assert_err(ciErr, "clCreateBuffer");
+ }
+ else {
+ mem.device_pointer = null_mem;
+ }
+
+ stats.mem_alloc(size);
+ mem.device_size = size;
+}
+
+void OpenCLDeviceBase::mem_copy_to(device_memory& mem)
+{
+ /* this is blocking */
+ size_t size = mem.memory_size();
+ if(size != 0) {
+ opencl_assert(clEnqueueWriteBuffer(cqCommandQueue,
+ CL_MEM_PTR(mem.device_pointer),
+ CL_TRUE,
+ 0,
+ size,
+ (void*)mem.data_pointer,
+ 0,
+ NULL, NULL));
+ }
+}
+
+void OpenCLDeviceBase::mem_copy_from(device_memory& mem, int y, int w, int h, int elem)
+{
+ size_t offset = elem*y*w;
+ size_t size = elem*w*h;
+ assert(size != 0);
+ opencl_assert(clEnqueueReadBuffer(cqCommandQueue,
+ CL_MEM_PTR(mem.device_pointer),
+ CL_TRUE,
+ offset,
+ size,
+ (uchar*)mem.data_pointer + offset,
+ 0,
+ NULL, NULL));
+}
+
+void OpenCLDeviceBase::mem_zero(device_memory& mem)
+{
+ if(mem.device_pointer) {
+ memset((void*)mem.data_pointer, 0, mem.memory_size());
+ mem_copy_to(mem);
+ }
+}
+
+void OpenCLDeviceBase::mem_free(device_memory& mem)
+{
+ if(mem.device_pointer) {
+ if(mem.device_pointer != null_mem) {
+ opencl_assert(clReleaseMemObject(CL_MEM_PTR(mem.device_pointer)));
+ }
+ mem.device_pointer = 0;
+
+ stats.mem_free(mem.device_size);
+ mem.device_size = 0;
+ }
+}
+
+void OpenCLDeviceBase::const_copy_to(const char *name, void *host, size_t size)
+{
+ ConstMemMap::iterator i = const_mem_map.find(name);
+
+ if(i == const_mem_map.end()) {
+ device_vector<uchar> *data = new device_vector<uchar>();
+ data->copy((uchar*)host, size);
+
+ mem_alloc(*data, MEM_READ_ONLY);
+ i = const_mem_map.insert(ConstMemMap::value_type(name, data)).first;
+ }
+ else {
+ device_vector<uchar> *data = i->second;
+ data->copy((uchar*)host, size);
+ }
+
+ mem_copy_to(*i->second);
+}
+
+void OpenCLDeviceBase::tex_alloc(const char *name,
+ device_memory& mem,
+ InterpolationType /*interpolation*/,
+ ExtensionType /*extension*/)
+{
+ VLOG(1) << "Texture allocate: " << name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
+ mem_alloc(mem, MEM_READ_ONLY);
+ mem_copy_to(mem);
+ assert(mem_map.find(name) == mem_map.end());
+ mem_map.insert(MemMap::value_type(name, mem.device_pointer));
+}
+
+void OpenCLDeviceBase::tex_free(device_memory& mem)
+{
+ if(mem.device_pointer) {
+ foreach(const MemMap::value_type& value, mem_map) {
+ if(value.second == mem.device_pointer) {
+ mem_map.erase(value.first);
+ break;
+ }
+ }
+
+ mem_free(mem);
+ }
+}
+
+size_t OpenCLDeviceBase::global_size_round_up(int group_size, int global_size)
+{
+ int r = global_size % group_size;
+ return global_size + ((r == 0)? 0: group_size - r);
+}
+
+void OpenCLDeviceBase::enqueue_kernel(cl_kernel kernel, size_t w, size_t h)
+{
+ size_t workgroup_size, max_work_items[3];
+
+ clGetKernelWorkGroupInfo(kernel, cdDevice,
+ CL_KERNEL_WORK_GROUP_SIZE, sizeof(size_t), &workgroup_size, NULL);
+ clGetDeviceInfo(cdDevice,
+ CL_DEVICE_MAX_WORK_ITEM_SIZES, sizeof(size_t)*3, max_work_items, NULL);
+
+ /* Try to divide evenly over 2 dimensions. */
+ size_t sqrt_workgroup_size = max((size_t)sqrt((double)workgroup_size), 1);
+ size_t local_size[2] = {sqrt_workgroup_size, sqrt_workgroup_size};
+
+ /* Some implementations have max size 1 on 2nd dimension. */
+ if(local_size[1] > max_work_items[1]) {
+ local_size[0] = workgroup_size/max_work_items[1];
+ local_size[1] = max_work_items[1];
+ }
+
+ size_t global_size[2] = {global_size_round_up(local_size[0], w),
+ global_size_round_up(local_size[1], h)};
+
+ /* Vertical size of 1 is coming from bake/shade kernels where we should
+ * not round anything up because otherwise we'll either be doing too
+ * much work per pixel (if we don't check global ID on Y axis) or will
+ * be checking for global ID to always have Y of 0.
+ */
+ if(h == 1) {
+ global_size[h] = 1;
+ }
+
+ /* run kernel */
+ opencl_assert(clEnqueueNDRangeKernel(cqCommandQueue, kernel, 2, NULL, global_size, NULL, 0, NULL, NULL));
+ opencl_assert(clFlush(cqCommandQueue));
+}
+
+void OpenCLDeviceBase::set_kernel_arg_mem(cl_kernel kernel, cl_uint *narg, const char *name)
+{
+ cl_mem ptr;
+
+ MemMap::iterator i = mem_map.find(name);
+ if(i != mem_map.end()) {
+ ptr = CL_MEM_PTR(i->second);
+ }
+ else {
+ /* work around NULL not working, even though the spec says otherwise */
+ ptr = CL_MEM_PTR(null_mem);
+ }
+
+ opencl_assert(clSetKernelArg(kernel, (*narg)++, sizeof(ptr), (void*)&ptr));
+}
+
+void OpenCLDeviceBase::film_convert(DeviceTask& task, device_ptr buffer, device_ptr rgba_byte, device_ptr rgba_half)
+{
+ /* cast arguments to cl types */
+ cl_mem d_data = CL_MEM_PTR(const_mem_map["__data"]->device_pointer);
+ cl_mem d_rgba = (rgba_byte)? CL_MEM_PTR(rgba_byte): CL_MEM_PTR(rgba_half);
+ cl_mem d_buffer = CL_MEM_PTR(buffer);
+ cl_int d_x = task.x;
+ cl_int d_y = task.y;
+ cl_int d_w = task.w;
+ cl_int d_h = task.h;
+ cl_float d_sample_scale = 1.0f/(task.sample + 1);
+ cl_int d_offset = task.offset;
+ cl_int d_stride = task.stride;
+
+
+ cl_kernel ckFilmConvertKernel = (rgba_byte)? base_program(ustring("convert_to_byte")): base_program(ustring("convert_to_half_float"));
+
+ cl_uint start_arg_index =
+ kernel_set_args(ckFilmConvertKernel,
+ 0,
+ d_data,
+ d_rgba,
+ d_buffer);
+
+#define KERNEL_TEX(type, ttype, name) \
+set_kernel_arg_mem(ckFilmConvertKernel, &start_arg_index, #name);
+#include "kernel_textures.h"
+#undef KERNEL_TEX
+
+ start_arg_index += kernel_set_args(ckFilmConvertKernel,
+ start_arg_index,
+ d_sample_scale,
+ d_x,
+ d_y,
+ d_w,
+ d_h,
+ d_offset,
+ d_stride);
+
+ enqueue_kernel(ckFilmConvertKernel, d_w, d_h);
+}
+
+void OpenCLDeviceBase::shader(DeviceTask& task)
+{
+ /* cast arguments to cl types */
+ cl_mem d_data = CL_MEM_PTR(const_mem_map["__data"]->device_pointer);
+ cl_mem d_input = CL_MEM_PTR(task.shader_input);
+ cl_mem d_output = CL_MEM_PTR(task.shader_output);
+ cl_mem d_output_luma = CL_MEM_PTR(task.shader_output_luma);
+ cl_int d_shader_eval_type = task.shader_eval_type;
+ cl_int d_shader_filter = task.shader_filter;
+ cl_int d_shader_x = task.shader_x;
+ cl_int d_shader_w = task.shader_w;
+ cl_int d_offset = task.offset;
+
+ cl_kernel kernel;
+
+ if(task.shader_eval_type >= SHADER_EVAL_BAKE)
+ kernel = base_program(ustring("bake"));
+ else
+ kernel = base_program(ustring("shader"));
+
+ cl_uint start_arg_index =
+ kernel_set_args(kernel,
+ 0,
+ d_data,
+ d_input,
+ d_output);
+
+ if(task.shader_eval_type < SHADER_EVAL_BAKE) {
+ start_arg_index += kernel_set_args(kernel,
+ start_arg_index,
+ d_output_luma);
+ }
+
+#define KERNEL_TEX(type, ttype, name) \
+ set_kernel_arg_mem(kernel, &start_arg_index, #name);
+#include "kernel_textures.h"
+#undef KERNEL_TEX
+
+ start_arg_index += kernel_set_args(kernel,
+ start_arg_index,
+ d_shader_eval_type);
+ if(task.shader_eval_type >= SHADER_EVAL_BAKE) {
+ start_arg_index += kernel_set_args(kernel,
+ start_arg_index,
+ d_shader_filter);
+ }
+ start_arg_index += kernel_set_args(kernel,
+ start_arg_index,
+ d_shader_x,
+ d_shader_w,
+ d_offset);
+
+ for(int sample = 0; sample < task.num_samples; sample++) {
+
+ if(task.get_cancel())
+ break;
+
+ kernel_set_args(kernel, start_arg_index, sample);
+
+ enqueue_kernel(kernel, task.shader_w, 1);
+
+ clFinish(cqCommandQueue);
+
+ task.update_progress(NULL);
+ }
+}
+
+string OpenCLDeviceBase::kernel_build_options(const string *debug_src)
+{
+ string build_options = "-cl-fast-relaxed-math ";
+
+ if(platform_name == "NVIDIA CUDA") {
+ build_options += "-D__KERNEL_OPENCL_NVIDIA__ "
+ "-cl-nv-maxrregcount=32 "
+ "-cl-nv-verbose ";
+
+ uint compute_capability_major, compute_capability_minor;
+ clGetDeviceInfo(cdDevice, CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV,
+ sizeof(cl_uint), &compute_capability_major, NULL);
+ clGetDeviceInfo(cdDevice, CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV,
+ sizeof(cl_uint), &compute_capability_minor, NULL);
+
+ build_options += string_printf("-D__COMPUTE_CAPABILITY__=%u ",
+ compute_capability_major * 100 +
+ compute_capability_minor * 10);
+ }
+
+ else if(platform_name == "Apple")
+ build_options += "-D__KERNEL_OPENCL_APPLE__ ";
+
+ else if(platform_name == "AMD Accelerated Parallel Processing")
+ build_options += "-D__KERNEL_OPENCL_AMD__ ";
+
+ else if(platform_name == "Intel(R) OpenCL") {
+ build_options += "-D__KERNEL_OPENCL_INTEL_CPU__ ";
+
+ /* Options for gdb source level kernel debugging.
+ * this segfaults on linux currently.
+ */
+ if(OpenCLInfo::use_debug() && debug_src)
+ build_options += "-g -s \"" + *debug_src + "\" ";
+ }
+
+ if(OpenCLInfo::use_debug())
+ build_options += "-D__KERNEL_OPENCL_DEBUG__ ";
+
+#ifdef WITH_CYCLES_DEBUG
+ build_options += "-D__KERNEL_DEBUG__ ";
+#endif
+
+ return build_options;
+}
+
+/* TODO(sergey): In the future we can use variadic templates, once
+ * C++0x is allowed. Should allow to clean this up a bit.
+ */
+int OpenCLDeviceBase::kernel_set_args(cl_kernel kernel,
+ int start_argument_index,
+ const ArgumentWrapper& arg1,
+ const ArgumentWrapper& arg2,
+ const ArgumentWrapper& arg3,
+ const ArgumentWrapper& arg4,
+ const ArgumentWrapper& arg5,
+ const ArgumentWrapper& arg6,
+ const ArgumentWrapper& arg7,
+ const ArgumentWrapper& arg8,
+ const ArgumentWrapper& arg9,
+ const ArgumentWrapper& arg10,
+ const ArgumentWrapper& arg11,
+ const ArgumentWrapper& arg12,
+ const ArgumentWrapper& arg13,
+ const ArgumentWrapper& arg14,
+ const ArgumentWrapper& arg15,
+ const ArgumentWrapper& arg16,
+ const ArgumentWrapper& arg17,
+ const ArgumentWrapper& arg18,
+ const ArgumentWrapper& arg19,
+ const ArgumentWrapper& arg20,
+ const ArgumentWrapper& arg21,
+ const ArgumentWrapper& arg22,
+ const ArgumentWrapper& arg23,
+ const ArgumentWrapper& arg24,
+ const ArgumentWrapper& arg25,
+ const ArgumentWrapper& arg26,
+ const ArgumentWrapper& arg27,
+ const ArgumentWrapper& arg28,
+ const ArgumentWrapper& arg29,
+ const ArgumentWrapper& arg30,
+ const ArgumentWrapper& arg31,
+ const ArgumentWrapper& arg32,
+ const ArgumentWrapper& arg33)
+{
+ int current_arg_index = 0;
+#define FAKE_VARARG_HANDLE_ARG(arg) \
+ do { \
+ if(arg.pointer != NULL) { \
+ opencl_assert(clSetKernelArg( \
+ kernel, \
+ start_argument_index + current_arg_index, \
+ arg.size, arg.pointer)); \
+ ++current_arg_index; \
+ } \
+ else { \
+ return current_arg_index; \
+ } \
+ } while(false)
+ FAKE_VARARG_HANDLE_ARG(arg1);
+ FAKE_VARARG_HANDLE_ARG(arg2);
+ FAKE_VARARG_HANDLE_ARG(arg3);
+ FAKE_VARARG_HANDLE_ARG(arg4);
+ FAKE_VARARG_HANDLE_ARG(arg5);
+ FAKE_VARARG_HANDLE_ARG(arg6);
+ FAKE_VARARG_HANDLE_ARG(arg7);
+ FAKE_VARARG_HANDLE_ARG(arg8);
+ FAKE_VARARG_HANDLE_ARG(arg9);
+ FAKE_VARARG_HANDLE_ARG(arg10);
+ FAKE_VARARG_HANDLE_ARG(arg11);
+ FAKE_VARARG_HANDLE_ARG(arg12);
+ FAKE_VARARG_HANDLE_ARG(arg13);
+ FAKE_VARARG_HANDLE_ARG(arg14);
+ FAKE_VARARG_HANDLE_ARG(arg15);
+ FAKE_VARARG_HANDLE_ARG(arg16);
+ FAKE_VARARG_HANDLE_ARG(arg17);
+ FAKE_VARARG_HANDLE_ARG(arg18);
+ FAKE_VARARG_HANDLE_ARG(arg19);
+ FAKE_VARARG_HANDLE_ARG(arg20);
+ FAKE_VARARG_HANDLE_ARG(arg21);
+ FAKE_VARARG_HANDLE_ARG(arg22);
+ FAKE_VARARG_HANDLE_ARG(arg23);
+ FAKE_VARARG_HANDLE_ARG(arg24);
+ FAKE_VARARG_HANDLE_ARG(arg25);
+ FAKE_VARARG_HANDLE_ARG(arg26);
+ FAKE_VARARG_HANDLE_ARG(arg27);
+ FAKE_VARARG_HANDLE_ARG(arg28);
+ FAKE_VARARG_HANDLE_ARG(arg29);
+ FAKE_VARARG_HANDLE_ARG(arg30);
+ FAKE_VARARG_HANDLE_ARG(arg31);
+ FAKE_VARARG_HANDLE_ARG(arg32);
+ FAKE_VARARG_HANDLE_ARG(arg33);
+#undef FAKE_VARARG_HANDLE_ARG
+ return current_arg_index;
+}
+
+void OpenCLDeviceBase::release_kernel_safe(cl_kernel kernel)
+{
+ if(kernel) {
+ clReleaseKernel(kernel);
+ }
+}
+
+void OpenCLDeviceBase::release_mem_object_safe(cl_mem mem)
+{
+ if(mem != NULL) {
+ clReleaseMemObject(mem);
+ }
+}
+
+void OpenCLDeviceBase::release_program_safe(cl_program program)
+{
+ if(program) {
+ clReleaseProgram(program);
+ }
+}
+
+/* ** Those guys are for workign around some compiler-specific bugs ** */
+
+cl_program OpenCLDeviceBase::load_cached_kernel(
+ ustring key,
+ thread_scoped_lock& cache_locker)
+{
+ return OpenCLCache::get_program(cpPlatform,
+ cdDevice,
+ key,
+ cache_locker);
+}
+
+void OpenCLDeviceBase::store_cached_kernel(
+ cl_program program,
+ ustring key,
+ thread_scoped_lock& cache_locker)
+{
+ OpenCLCache::store_program(cpPlatform,
+ cdDevice,
+ program,
+ key,
+ cache_locker);
+}
+
+string OpenCLDeviceBase::build_options_for_base_program(
+ const DeviceRequestedFeatures& /*requested_features*/)
+{
+ /* TODO(sergey): By default we compile all features, meaning
+ * mega kernel is not getting feature-based optimizations.
+ *
+ * Ideally we need always compile kernel with as less features
+ * enabled as possible to keep performance at it's max.
+ */
+ return "";
+}
+
+CCL_NAMESPACE_END
+
+#endif
diff --git a/intern/cycles/device/opencl/opencl_mega.cpp b/intern/cycles/device/opencl/opencl_mega.cpp
new file mode 100644
index 00000000000..369c086df57
--- /dev/null
+++ b/intern/cycles/device/opencl/opencl_mega.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef WITH_OPENCL
+
+#include "opencl.h"
+
+#include "buffers.h"
+
+#include "kernel_types.h"
+
+#include "util_md5.h"
+#include "util_path.h"
+#include "util_time.h"
+
+CCL_NAMESPACE_BEGIN
+
+class OpenCLDeviceMegaKernel : public OpenCLDeviceBase
+{
+public:
+ OpenCLProgram path_trace_program;
+
+ OpenCLDeviceMegaKernel(DeviceInfo& info, Stats &stats, bool background_)
+ : OpenCLDeviceBase(info, stats, background_),
+ path_trace_program(this, "megakernel", "kernel.cl", "-D__COMPILE_ONLY_MEGAKERNEL__ ")
+ {
+ }
+
+ virtual void load_kernels(const DeviceRequestedFeatures& /*requested_features*/,
+ vector<OpenCLProgram*> &programs)
+ {
+ path_trace_program.add_kernel(ustring("path_trace"));
+ programs.push_back(&path_trace_program);
+ }
+
+ ~OpenCLDeviceMegaKernel()
+ {
+ task_pool.stop();
+ path_trace_program.release();
+ }
+
+ void path_trace(RenderTile& rtile, int sample)
+ {
+ /* Cast arguments to cl types. */
+ cl_mem d_data = CL_MEM_PTR(const_mem_map["__data"]->device_pointer);
+ cl_mem d_buffer = CL_MEM_PTR(rtile.buffer);
+ cl_mem d_rng_state = CL_MEM_PTR(rtile.rng_state);
+ cl_int d_x = rtile.x;
+ cl_int d_y = rtile.y;
+ cl_int d_w = rtile.w;
+ cl_int d_h = rtile.h;
+ cl_int d_offset = rtile.offset;
+ cl_int d_stride = rtile.stride;
+
+ /* Sample arguments. */
+ cl_int d_sample = sample;
+
+ cl_kernel ckPathTraceKernel = path_trace_program(ustring("path_trace"));
+
+ cl_uint start_arg_index =
+ kernel_set_args(ckPathTraceKernel,
+ 0,
+ d_data,
+ d_buffer,
+ d_rng_state);
+
+#define KERNEL_TEX(type, ttype, name) \
+ set_kernel_arg_mem(ckPathTraceKernel, &start_arg_index, #name);
+#include "kernel_textures.h"
+#undef KERNEL_TEX
+
+ start_arg_index += kernel_set_args(ckPathTraceKernel,
+ start_arg_index,
+ d_sample,
+ d_x,
+ d_y,
+ d_w,
+ d_h,
+ d_offset,
+ d_stride);
+
+ enqueue_kernel(ckPathTraceKernel, d_w, d_h);
+ }
+
+ void thread_run(DeviceTask *task)
+ {
+ if(task->type == DeviceTask::FILM_CONVERT) {
+ film_convert(*task, task->buffer, task->rgba_byte, task->rgba_half);
+ }
+ else if(task->type == DeviceTask::SHADER) {
+ shader(*task);
+ }
+ else if(task->type == DeviceTask::PATH_TRACE) {
+ RenderTile tile;
+ /* Keep rendering tiles until done. */
+ while(task->acquire_tile(this, tile)) {
+ int start_sample = tile.start_sample;
+ int end_sample = tile.start_sample + tile.num_samples;
+
+ for(int sample = start_sample; sample < end_sample; sample++) {
+ if(task->get_cancel()) {
+ if(task->need_finish_queue == false)
+ break;
+ }
+
+ path_trace(tile, sample);
+
+ tile.sample = sample + 1;
+
+ task->update_progress(&tile);
+ }
+
+ /* Complete kernel execution before release tile */
+ /* This helps in multi-device render;
+ * The device that reaches the critical-section function
+ * release_tile waits (stalling other devices from entering
+ * release_tile) for all kernels to complete. If device1 (a
+ * slow-render device) reaches release_tile first then it would
+ * stall device2 (a fast-render device) from proceeding to render
+ * next tile.
+ */
+ clFinish(cqCommandQueue);
+
+ task->release_tile(tile);
+ }
+ }
+ }
+};
+
+Device *opencl_create_mega_device(DeviceInfo& info, Stats& stats, bool background)
+{
+ return new OpenCLDeviceMegaKernel(info, stats, background);
+}
+
+CCL_NAMESPACE_END
+
+#endif
diff --git a/intern/cycles/device/opencl/opencl_split.cpp b/intern/cycles/device/opencl/opencl_split.cpp
new file mode 100644
index 00000000000..239e73a40fd
--- /dev/null
+++ b/intern/cycles/device/opencl/opencl_split.cpp
@@ -0,0 +1,1307 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef WITH_OPENCL
+
+#include "opencl.h"
+
+#include "buffers.h"
+
+#include "kernel_types.h"
+
+#include "util_md5.h"
+#include "util_path.h"
+#include "util_time.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* TODO(sergey): This is to keep tile split on OpenCL level working
+ * for now, since without this view-port render does not work as it
+ * should.
+ *
+ * Ideally it'll be done on the higher level, but we need to get ready
+ * for merge rather soon, so let's keep split logic private here in
+ * the file.
+ */
+class SplitRenderTile : public RenderTile {
+public:
+ SplitRenderTile()
+ : RenderTile(),
+ buffer_offset_x(0),
+ buffer_offset_y(0),
+ rng_state_offset_x(0),
+ rng_state_offset_y(0),
+ buffer_rng_state_stride(0) {}
+
+ explicit SplitRenderTile(RenderTile& tile)
+ : RenderTile(),
+ buffer_offset_x(0),
+ buffer_offset_y(0),
+ rng_state_offset_x(0),
+ rng_state_offset_y(0),
+ buffer_rng_state_stride(0)
+ {
+ x = tile.x;
+ y = tile.y;
+ w = tile.w;
+ h = tile.h;
+ start_sample = tile.start_sample;
+ num_samples = tile.num_samples;
+ sample = tile.sample;
+ resolution = tile.resolution;
+ offset = tile.offset;
+ stride = tile.stride;
+ buffer = tile.buffer;
+ rng_state = tile.rng_state;
+ buffers = tile.buffers;
+ }
+
+ /* Split kernel is device global memory constrained;
+ * hence split kernel cant render big tile size's in
+ * one go. If the user sets a big tile size (big tile size
+ * is a term relative to the available device global memory),
+ * we split the tile further and then call path_trace on
+ * each of those split tiles. The following variables declared,
+ * assist in achieving that purpose
+ */
+ int buffer_offset_x;
+ int buffer_offset_y;
+ int rng_state_offset_x;
+ int rng_state_offset_y;
+ int buffer_rng_state_stride;
+};
+
+/* OpenCLDeviceSplitKernel's declaration/definition. */
+class OpenCLDeviceSplitKernel : public OpenCLDeviceBase
+{
+public:
+ /* Kernel declaration. */
+ OpenCLProgram program_data_init;
+ OpenCLProgram program_scene_intersect;
+ OpenCLProgram program_lamp_emission;
+ OpenCLProgram program_queue_enqueue;
+ OpenCLProgram program_background_buffer_update;
+ OpenCLProgram program_shader_eval;
+ OpenCLProgram program_holdout_emission_blurring_pathtermination_ao;
+ OpenCLProgram program_direct_lighting;
+ OpenCLProgram program_shadow_blocked;
+ OpenCLProgram program_next_iteration_setup;
+ OpenCLProgram program_sum_all_radiance;
+
+ /* Global memory variables [porting]; These memory is used for
+ * co-operation between different kernels; Data written by one
+ * kernel will be available to another kernel via this global
+ * memory.
+ */
+ cl_mem rng_coop;
+ cl_mem throughput_coop;
+ cl_mem L_transparent_coop;
+ cl_mem PathRadiance_coop;
+ cl_mem Ray_coop;
+ cl_mem PathState_coop;
+ cl_mem Intersection_coop;
+ cl_mem kgbuffer; /* KernelGlobals buffer. */
+
+ /* Global buffers for ShaderData. */
+ cl_mem sd; /* ShaderData used in the main path-iteration loop. */
+ cl_mem sd_DL_shadow; /* ShaderData used in Direct Lighting and
+ * shadow_blocked kernel.
+ */
+
+ /* Global memory required for shadow blocked and accum_radiance. */
+ cl_mem BSDFEval_coop;
+ cl_mem ISLamp_coop;
+ cl_mem LightRay_coop;
+ cl_mem AOAlpha_coop;
+ cl_mem AOBSDF_coop;
+ cl_mem AOLightRay_coop;
+ cl_mem Intersection_coop_shadow;
+
+#ifdef WITH_CYCLES_DEBUG
+ /* DebugData memory */
+ cl_mem debugdata_coop;
+#endif
+
+ /* Global state array that tracks ray state. */
+ cl_mem ray_state;
+
+ /* Per sample buffers. */
+ cl_mem per_sample_output_buffers;
+
+ /* Denotes which sample each ray is being processed for. */
+ cl_mem work_array;
+
+ /* Queue */
+ cl_mem Queue_data; /* Array of size queuesize * num_queues * sizeof(int). */
+ cl_mem Queue_index; /* Array of size num_queues * sizeof(int);
+ * Tracks the size of each queue.
+ */
+
+ /* Flag to make sceneintersect and lampemission kernel use queues. */
+ cl_mem use_queues_flag;
+
+ /* Amount of memory in output buffer associated with one pixel/thread. */
+ size_t per_thread_output_buffer_size;
+
+ /* Total allocatable available device memory. */
+ size_t total_allocatable_memory;
+
+ /* host version of ray_state; Used in checking host path-iteration
+ * termination.
+ */
+ char *hostRayStateArray;
+
+ /* Number of path-iterations to be done in one shot. */
+ unsigned int PathIteration_times;
+
+#ifdef __WORK_STEALING__
+ /* Work pool with respect to each work group. */
+ cl_mem work_pool_wgs;
+
+ /* Denotes the maximum work groups possible w.r.t. current tile size. */
+ unsigned int max_work_groups;
+#endif
+
+ /* clos_max value for which the kernels have been loaded currently. */
+ int current_max_closure;
+
+ /* Marked True in constructor and marked false at the end of path_trace(). */
+ bool first_tile;
+
+ OpenCLDeviceSplitKernel(DeviceInfo& info, Stats &stats, bool background_)
+ : OpenCLDeviceBase(info, stats, background_)
+ {
+ background = background_;
+
+ /* Initialize cl_mem variables. */
+ kgbuffer = NULL;
+ sd = NULL;
+ sd_DL_shadow = NULL;
+
+ rng_coop = NULL;
+ throughput_coop = NULL;
+ L_transparent_coop = NULL;
+ PathRadiance_coop = NULL;
+ Ray_coop = NULL;
+ PathState_coop = NULL;
+ Intersection_coop = NULL;
+ ray_state = NULL;
+
+ AOAlpha_coop = NULL;
+ AOBSDF_coop = NULL;
+ AOLightRay_coop = NULL;
+ BSDFEval_coop = NULL;
+ ISLamp_coop = NULL;
+ LightRay_coop = NULL;
+ Intersection_coop_shadow = NULL;
+
+#ifdef WITH_CYCLES_DEBUG
+ debugdata_coop = NULL;
+#endif
+
+ work_array = NULL;
+
+ /* Queue. */
+ Queue_data = NULL;
+ Queue_index = NULL;
+ use_queues_flag = NULL;
+
+ per_sample_output_buffers = NULL;
+
+ per_thread_output_buffer_size = 0;
+ hostRayStateArray = NULL;
+ PathIteration_times = PATH_ITER_INC_FACTOR;
+#ifdef __WORK_STEALING__
+ work_pool_wgs = NULL;
+ max_work_groups = 0;
+#endif
+ current_max_closure = -1;
+ first_tile = true;
+
+ /* Get device's maximum memory that can be allocated. */
+ ciErr = clGetDeviceInfo(cdDevice,
+ CL_DEVICE_MAX_MEM_ALLOC_SIZE,
+ sizeof(size_t),
+ &total_allocatable_memory,
+ NULL);
+ assert(ciErr == CL_SUCCESS);
+ if(platform_name == "AMD Accelerated Parallel Processing") {
+ /* This value is tweak-able; AMD platform does not seem to
+ * give maximum performance when all of CL_DEVICE_MAX_MEM_ALLOC_SIZE
+ * is considered for further computation.
+ */
+ total_allocatable_memory /= 2;
+ }
+ }
+
+ /* Split kernel utility functions. */
+ size_t get_tex_size(const char *tex_name)
+ {
+ cl_mem ptr;
+ size_t ret_size = 0;
+ MemMap::iterator i = mem_map.find(tex_name);
+ if(i != mem_map.end()) {
+ ptr = CL_MEM_PTR(i->second);
+ ciErr = clGetMemObjectInfo(ptr,
+ CL_MEM_SIZE,
+ sizeof(ret_size),
+ &ret_size,
+ NULL);
+ assert(ciErr == CL_SUCCESS);
+ }
+ return ret_size;
+ }
+
+ size_t get_shader_data_size(size_t max_closure)
+ {
+ /* ShaderData size with variable size ShaderClosure array */
+ return sizeof(ShaderData) - (sizeof(ShaderClosure) * (MAX_CLOSURE - max_closure));
+ }
+
+ /* Returns size of KernelGlobals structure associated with OpenCL. */
+ size_t get_KernelGlobals_size()
+ {
+ /* Copy dummy KernelGlobals related to OpenCL from kernel_globals.h to
+ * fetch its size.
+ */
+ typedef struct KernelGlobals {
+ ccl_constant KernelData *data;
+#define KERNEL_TEX(type, ttype, name) \
+ ccl_global type *name;
+#include "kernel_textures.h"
+#undef KERNEL_TEX
+ void *sd_input;
+ void *isect_shadow;
+ } KernelGlobals;
+
+ return sizeof(KernelGlobals);
+ }
+
+ virtual void load_kernels(const DeviceRequestedFeatures& requested_features,
+ vector<OpenCLProgram*> &programs)
+ {
+ string build_options = "-D__SPLIT_KERNEL__ ";
+#ifdef __WORK_STEALING__
+ build_options += "-D__WORK_STEALING__ ";
+#endif
+ build_options += requested_features.get_build_options();
+
+ /* Set compute device build option. */
+ cl_device_type device_type;
+ ciErr = clGetDeviceInfo(cdDevice,
+ CL_DEVICE_TYPE,
+ sizeof(cl_device_type),
+ &device_type,
+ NULL);
+ assert(ciErr == CL_SUCCESS);
+ if(device_type == CL_DEVICE_TYPE_GPU) {
+ build_options += " -D__COMPUTE_DEVICE_GPU__";
+ }
+
+#define GLUE(a, b) a ## b
+#define LOAD_KERNEL(name) \
+ do { \
+ GLUE(program_, name) = OpenCLProgram(this, "split_" #name, "kernel_" #name ".cl", build_options); \
+ GLUE(program_, name).add_kernel(ustring("path_trace_" #name)); \
+ programs.push_back(&GLUE(program_, name)); \
+ } while(false)
+
+ LOAD_KERNEL(data_init);
+ LOAD_KERNEL(scene_intersect);
+ LOAD_KERNEL(lamp_emission);
+ LOAD_KERNEL(queue_enqueue);
+ LOAD_KERNEL(background_buffer_update);
+ LOAD_KERNEL(shader_eval);
+ LOAD_KERNEL(holdout_emission_blurring_pathtermination_ao);
+ LOAD_KERNEL(direct_lighting);
+ LOAD_KERNEL(shadow_blocked);
+ LOAD_KERNEL(next_iteration_setup);
+ LOAD_KERNEL(sum_all_radiance);
+
+#undef FIND_KERNEL
+#undef GLUE
+
+ current_max_closure = requested_features.max_closure;
+ }
+
+ ~OpenCLDeviceSplitKernel()
+ {
+ task_pool.stop();
+
+ /* Release kernels */
+ program_data_init.release();
+ program_scene_intersect.release();
+ program_lamp_emission.release();
+ program_queue_enqueue.release();
+ program_background_buffer_update.release();
+ program_shader_eval.release();
+ program_holdout_emission_blurring_pathtermination_ao.release();
+ program_direct_lighting.release();
+ program_shadow_blocked.release();
+ program_next_iteration_setup.release();
+ program_sum_all_radiance.release();
+
+ /* Release global memory */
+ release_mem_object_safe(rng_coop);
+ release_mem_object_safe(throughput_coop);
+ release_mem_object_safe(L_transparent_coop);
+ release_mem_object_safe(PathRadiance_coop);
+ release_mem_object_safe(Ray_coop);
+ release_mem_object_safe(PathState_coop);
+ release_mem_object_safe(Intersection_coop);
+ release_mem_object_safe(kgbuffer);
+ release_mem_object_safe(sd);
+ release_mem_object_safe(sd_DL_shadow);
+ release_mem_object_safe(ray_state);
+ release_mem_object_safe(AOAlpha_coop);
+ release_mem_object_safe(AOBSDF_coop);
+ release_mem_object_safe(AOLightRay_coop);
+ release_mem_object_safe(BSDFEval_coop);
+ release_mem_object_safe(ISLamp_coop);
+ release_mem_object_safe(LightRay_coop);
+ release_mem_object_safe(Intersection_coop_shadow);
+#ifdef WITH_CYCLES_DEBUG
+ release_mem_object_safe(debugdata_coop);
+#endif
+ release_mem_object_safe(use_queues_flag);
+ release_mem_object_safe(Queue_data);
+ release_mem_object_safe(Queue_index);
+ release_mem_object_safe(work_array);
+#ifdef __WORK_STEALING__
+ release_mem_object_safe(work_pool_wgs);
+#endif
+ release_mem_object_safe(per_sample_output_buffers);
+
+ if(hostRayStateArray != NULL) {
+ free(hostRayStateArray);
+ }
+ }
+
+ void path_trace(DeviceTask *task,
+ SplitRenderTile& rtile,
+ int2 max_render_feasible_tile_size)
+ {
+ /* cast arguments to cl types */
+ cl_mem d_data = CL_MEM_PTR(const_mem_map["__data"]->device_pointer);
+ cl_mem d_buffer = CL_MEM_PTR(rtile.buffer);
+ cl_mem d_rng_state = CL_MEM_PTR(rtile.rng_state);
+ cl_int d_x = rtile.x;
+ cl_int d_y = rtile.y;
+ cl_int d_w = rtile.w;
+ cl_int d_h = rtile.h;
+ cl_int d_offset = rtile.offset;
+ cl_int d_stride = rtile.stride;
+
+ /* Make sure that set render feasible tile size is a multiple of local
+ * work size dimensions.
+ */
+ assert(max_render_feasible_tile_size.x % SPLIT_KERNEL_LOCAL_SIZE_X == 0);
+ assert(max_render_feasible_tile_size.y % SPLIT_KERNEL_LOCAL_SIZE_Y == 0);
+
+ size_t global_size[2];
+ size_t local_size[2] = {SPLIT_KERNEL_LOCAL_SIZE_X,
+ SPLIT_KERNEL_LOCAL_SIZE_Y};
+
+ /* Set the range of samples to be processed for every ray in
+ * path-regeneration logic.
+ */
+ cl_int start_sample = rtile.start_sample;
+ cl_int end_sample = rtile.start_sample + rtile.num_samples;
+ cl_int num_samples = rtile.num_samples;
+
+#ifdef __WORK_STEALING__
+ global_size[0] = (((d_w - 1) / local_size[0]) + 1) * local_size[0];
+ global_size[1] = (((d_h - 1) / local_size[1]) + 1) * local_size[1];
+ unsigned int num_parallel_samples = 1;
+#else
+ global_size[1] = (((d_h - 1) / local_size[1]) + 1) * local_size[1];
+ unsigned int num_threads = max_render_feasible_tile_size.x *
+ max_render_feasible_tile_size.y;
+ unsigned int num_tile_columns_possible = num_threads / global_size[1];
+ /* Estimate number of parallel samples that can be
+ * processed in parallel.
+ */
+ unsigned int num_parallel_samples = min(num_tile_columns_possible / d_w,
+ rtile.num_samples);
+ /* Wavefront size in AMD is 64.
+ * TODO(sergey): What about other platforms?
+ */
+ if(num_parallel_samples >= 64) {
+ /* TODO(sergey): Could use generic round-up here. */
+ num_parallel_samples = (num_parallel_samples / 64) * 64;
+ }
+ assert(num_parallel_samples != 0);
+
+ global_size[0] = d_w * num_parallel_samples;
+#endif /* __WORK_STEALING__ */
+
+ assert(global_size[0] * global_size[1] <=
+ max_render_feasible_tile_size.x * max_render_feasible_tile_size.y);
+
+ /* Allocate all required global memory once. */
+ if(first_tile) {
+ size_t num_global_elements = max_render_feasible_tile_size.x *
+ max_render_feasible_tile_size.y;
+ /* TODO(sergey): This will actually over-allocate if
+ * particular kernel does not support multiclosure.
+ */
+ size_t shaderdata_size = get_shader_data_size(current_max_closure);
+
+#ifdef __WORK_STEALING__
+ /* Calculate max groups */
+ size_t max_global_size[2];
+ size_t tile_x = max_render_feasible_tile_size.x;
+ size_t tile_y = max_render_feasible_tile_size.y;
+ max_global_size[0] = (((tile_x - 1) / local_size[0]) + 1) * local_size[0];
+ max_global_size[1] = (((tile_y - 1) / local_size[1]) + 1) * local_size[1];
+ max_work_groups = (max_global_size[0] * max_global_size[1]) /
+ (local_size[0] * local_size[1]);
+ /* Allocate work_pool_wgs memory. */
+ work_pool_wgs = mem_alloc(max_work_groups * sizeof(unsigned int));
+#endif /* __WORK_STEALING__ */
+
+ /* Allocate queue_index memory only once. */
+ Queue_index = mem_alloc(NUM_QUEUES * sizeof(int));
+ use_queues_flag = mem_alloc(sizeof(char));
+ kgbuffer = mem_alloc(get_KernelGlobals_size());
+
+ /* Create global buffers for ShaderData. */
+ sd = mem_alloc(num_global_elements * shaderdata_size);
+ sd_DL_shadow = mem_alloc(num_global_elements * 2 * shaderdata_size);
+
+ /* Creation of global memory buffers which are shared among
+ * the kernels.
+ */
+ rng_coop = mem_alloc(num_global_elements * sizeof(RNG));
+ throughput_coop = mem_alloc(num_global_elements * sizeof(float3));
+ L_transparent_coop = mem_alloc(num_global_elements * sizeof(float));
+ PathRadiance_coop = mem_alloc(num_global_elements * sizeof(PathRadiance));
+ Ray_coop = mem_alloc(num_global_elements * sizeof(Ray));
+ PathState_coop = mem_alloc(num_global_elements * sizeof(PathState));
+ Intersection_coop = mem_alloc(num_global_elements * sizeof(Intersection));
+ AOAlpha_coop = mem_alloc(num_global_elements * sizeof(float3));
+ AOBSDF_coop = mem_alloc(num_global_elements * sizeof(float3));
+ AOLightRay_coop = mem_alloc(num_global_elements * sizeof(Ray));
+ BSDFEval_coop = mem_alloc(num_global_elements * sizeof(BsdfEval));
+ ISLamp_coop = mem_alloc(num_global_elements * sizeof(int));
+ LightRay_coop = mem_alloc(num_global_elements * sizeof(Ray));
+ Intersection_coop_shadow = mem_alloc(2 * num_global_elements * sizeof(Intersection));
+
+#ifdef WITH_CYCLES_DEBUG
+ debugdata_coop = mem_alloc(num_global_elements * sizeof(DebugData));
+#endif
+
+ ray_state = mem_alloc(num_global_elements * sizeof(char));
+
+ hostRayStateArray = (char *)calloc(num_global_elements, sizeof(char));
+ assert(hostRayStateArray != NULL && "Can't create hostRayStateArray memory");
+
+ Queue_data = mem_alloc(num_global_elements * (NUM_QUEUES * sizeof(int)+sizeof(int)));
+ work_array = mem_alloc(num_global_elements * sizeof(unsigned int));
+ per_sample_output_buffers = mem_alloc(num_global_elements *
+ per_thread_output_buffer_size);
+ }
+
+ cl_int dQueue_size = global_size[0] * global_size[1];
+
+ cl_uint start_arg_index =
+ kernel_set_args(program_data_init(),
+ 0,
+ kgbuffer,
+ sd_DL_shadow,
+ d_data,
+ per_sample_output_buffers,
+ d_rng_state,
+ rng_coop,
+ throughput_coop,
+ L_transparent_coop,
+ PathRadiance_coop,
+ Ray_coop,
+ PathState_coop,
+ Intersection_coop_shadow,
+ ray_state);
+
+/* TODO(sergey): Avoid map lookup here. */
+#define KERNEL_TEX(type, ttype, name) \
+ set_kernel_arg_mem(program_data_init(), &start_arg_index, #name);
+#include "kernel_textures.h"
+#undef KERNEL_TEX
+
+ start_arg_index +=
+ kernel_set_args(program_data_init(),
+ start_arg_index,
+ start_sample,
+ d_x,
+ d_y,
+ d_w,
+ d_h,
+ d_offset,
+ d_stride,
+ rtile.rng_state_offset_x,
+ rtile.rng_state_offset_y,
+ rtile.buffer_rng_state_stride,
+ Queue_data,
+ Queue_index,
+ dQueue_size,
+ use_queues_flag,
+ work_array,
+#ifdef __WORK_STEALING__
+ work_pool_wgs,
+ num_samples,
+#endif
+#ifdef WITH_CYCLES_DEBUG
+ debugdata_coop,
+#endif
+ num_parallel_samples);
+
+ kernel_set_args(program_scene_intersect(),
+ 0,
+ kgbuffer,
+ d_data,
+ rng_coop,
+ Ray_coop,
+ PathState_coop,
+ Intersection_coop,
+ ray_state,
+ d_w,
+ d_h,
+ Queue_data,
+ Queue_index,
+ dQueue_size,
+ use_queues_flag,
+#ifdef WITH_CYCLES_DEBUG
+ debugdata_coop,
+#endif
+ num_parallel_samples);
+
+ kernel_set_args(program_lamp_emission(),
+ 0,
+ kgbuffer,
+ d_data,
+ throughput_coop,
+ PathRadiance_coop,
+ Ray_coop,
+ PathState_coop,
+ Intersection_coop,
+ ray_state,
+ d_w,
+ d_h,
+ Queue_data,
+ Queue_index,
+ dQueue_size,
+ use_queues_flag,
+ num_parallel_samples);
+
+ kernel_set_args(program_queue_enqueue(),
+ 0,
+ Queue_data,
+ Queue_index,
+ ray_state,
+ dQueue_size);
+
+ kernel_set_args(program_background_buffer_update(),
+ 0,
+ kgbuffer,
+ d_data,
+ per_sample_output_buffers,
+ d_rng_state,
+ rng_coop,
+ throughput_coop,
+ PathRadiance_coop,
+ Ray_coop,
+ PathState_coop,
+ L_transparent_coop,
+ ray_state,
+ d_w,
+ d_h,
+ d_x,
+ d_y,
+ d_stride,
+ rtile.rng_state_offset_x,
+ rtile.rng_state_offset_y,
+ rtile.buffer_rng_state_stride,
+ work_array,
+ Queue_data,
+ Queue_index,
+ dQueue_size,
+ end_sample,
+ start_sample,
+#ifdef __WORK_STEALING__
+ work_pool_wgs,
+ num_samples,
+#endif
+#ifdef WITH_CYCLES_DEBUG
+ debugdata_coop,
+#endif
+ num_parallel_samples);
+
+ kernel_set_args(program_shader_eval(),
+ 0,
+ kgbuffer,
+ d_data,
+ sd,
+ rng_coop,
+ Ray_coop,
+ PathState_coop,
+ Intersection_coop,
+ ray_state,
+ Queue_data,
+ Queue_index,
+ dQueue_size);
+
+ kernel_set_args(program_holdout_emission_blurring_pathtermination_ao(),
+ 0,
+ kgbuffer,
+ d_data,
+ sd,
+ per_sample_output_buffers,
+ rng_coop,
+ throughput_coop,
+ L_transparent_coop,
+ PathRadiance_coop,
+ PathState_coop,
+ Intersection_coop,
+ AOAlpha_coop,
+ AOBSDF_coop,
+ AOLightRay_coop,
+ d_w,
+ d_h,
+ d_x,
+ d_y,
+ d_stride,
+ ray_state,
+ work_array,
+ Queue_data,
+ Queue_index,
+ dQueue_size,
+#ifdef __WORK_STEALING__
+ start_sample,
+#endif
+ num_parallel_samples);
+
+ kernel_set_args(program_direct_lighting(),
+ 0,
+ kgbuffer,
+ d_data,
+ sd,
+ rng_coop,
+ PathState_coop,
+ ISLamp_coop,
+ LightRay_coop,
+ BSDFEval_coop,
+ ray_state,
+ Queue_data,
+ Queue_index,
+ dQueue_size);
+
+ kernel_set_args(program_shadow_blocked(),
+ 0,
+ kgbuffer,
+ d_data,
+ PathState_coop,
+ LightRay_coop,
+ AOLightRay_coop,
+ ray_state,
+ Queue_data,
+ Queue_index,
+ dQueue_size);
+
+ kernel_set_args(program_next_iteration_setup(),
+ 0,
+ kgbuffer,
+ d_data,
+ sd,
+ rng_coop,
+ throughput_coop,
+ PathRadiance_coop,
+ Ray_coop,
+ PathState_coop,
+ LightRay_coop,
+ ISLamp_coop,
+ BSDFEval_coop,
+ AOLightRay_coop,
+ AOBSDF_coop,
+ AOAlpha_coop,
+ ray_state,
+ Queue_data,
+ Queue_index,
+ dQueue_size,
+ use_queues_flag);
+
+ kernel_set_args(program_sum_all_radiance(),
+ 0,
+ d_data,
+ d_buffer,
+ per_sample_output_buffers,
+ num_parallel_samples,
+ d_w,
+ d_h,
+ d_stride,
+ rtile.buffer_offset_x,
+ rtile.buffer_offset_y,
+ rtile.buffer_rng_state_stride,
+ start_sample);
+
+ /* Macro for Enqueuing split kernels. */
+#define GLUE(a, b) a ## b
+#define ENQUEUE_SPLIT_KERNEL(kernelName, globalSize, localSize) \
+ { \
+ ciErr = clEnqueueNDRangeKernel(cqCommandQueue, \
+ GLUE(program_, \
+ kernelName)(), \
+ 2, \
+ NULL, \
+ globalSize, \
+ localSize, \
+ 0, \
+ NULL, \
+ NULL); \
+ opencl_assert_err(ciErr, "clEnqueueNDRangeKernel"); \
+ if(ciErr != CL_SUCCESS) { \
+ string message = string_printf("OpenCL error: %s in clEnqueueNDRangeKernel()", \
+ clewErrorString(ciErr)); \
+ opencl_error(message); \
+ return; \
+ } \
+ } (void) 0
+
+ /* Enqueue ckPathTraceKernel_data_init kernel. */
+ ENQUEUE_SPLIT_KERNEL(data_init, global_size, local_size);
+ bool activeRaysAvailable = true;
+
+ /* Record number of time host intervention has been made */
+ unsigned int numHostIntervention = 0;
+ unsigned int numNextPathIterTimes = PathIteration_times;
+ bool canceled = false;
+ while(activeRaysAvailable) {
+ /* Twice the global work size of other kernels for
+ * ckPathTraceKernel_shadow_blocked_direct_lighting. */
+ size_t global_size_shadow_blocked[2];
+ global_size_shadow_blocked[0] = global_size[0] * 2;
+ global_size_shadow_blocked[1] = global_size[1];
+
+ /* Do path-iteration in host [Enqueue Path-iteration kernels. */
+ for(int PathIter = 0; PathIter < PathIteration_times; PathIter++) {
+ ENQUEUE_SPLIT_KERNEL(scene_intersect, global_size, local_size);
+ ENQUEUE_SPLIT_KERNEL(lamp_emission, global_size, local_size);
+ ENQUEUE_SPLIT_KERNEL(queue_enqueue, global_size, local_size);
+ ENQUEUE_SPLIT_KERNEL(background_buffer_update, global_size, local_size);
+ ENQUEUE_SPLIT_KERNEL(shader_eval, global_size, local_size);
+ ENQUEUE_SPLIT_KERNEL(holdout_emission_blurring_pathtermination_ao, global_size, local_size);
+ ENQUEUE_SPLIT_KERNEL(direct_lighting, global_size, local_size);
+ ENQUEUE_SPLIT_KERNEL(shadow_blocked, global_size_shadow_blocked, local_size);
+ ENQUEUE_SPLIT_KERNEL(next_iteration_setup, global_size, local_size);
+
+ if(task->get_cancel()) {
+ canceled = true;
+ break;
+ }
+ }
+
+ /* Read ray-state into Host memory to decide if we should exit
+ * path-iteration in host.
+ */
+ ciErr = clEnqueueReadBuffer(cqCommandQueue,
+ ray_state,
+ CL_TRUE,
+ 0,
+ global_size[0] * global_size[1] * sizeof(char),
+ hostRayStateArray,
+ 0,
+ NULL,
+ NULL);
+ assert(ciErr == CL_SUCCESS);
+
+ activeRaysAvailable = false;
+
+ for(int rayStateIter = 0;
+ rayStateIter < global_size[0] * global_size[1];
+ ++rayStateIter)
+ {
+ if(int8_t(hostRayStateArray[rayStateIter]) != RAY_INACTIVE) {
+ /* Not all rays are RAY_INACTIVE. */
+ activeRaysAvailable = true;
+ break;
+ }
+ }
+
+ if(activeRaysAvailable) {
+ numHostIntervention++;
+ PathIteration_times = PATH_ITER_INC_FACTOR;
+ /* Host intervention done before all rays become RAY_INACTIVE;
+ * Set do more initial iterations for the next tile.
+ */
+ numNextPathIterTimes += PATH_ITER_INC_FACTOR;
+ }
+
+ if(task->get_cancel()) {
+ canceled = true;
+ break;
+ }
+ }
+
+ /* Execute SumALLRadiance kernel to accumulate radiance calculated in
+ * per_sample_output_buffers into RenderTile's output buffer.
+ */
+ if(!canceled) {
+ size_t sum_all_radiance_local_size[2] = {16, 16};
+ size_t sum_all_radiance_global_size[2];
+ sum_all_radiance_global_size[0] =
+ (((d_w - 1) / sum_all_radiance_local_size[0]) + 1) *
+ sum_all_radiance_local_size[0];
+ sum_all_radiance_global_size[1] =
+ (((d_h - 1) / sum_all_radiance_local_size[1]) + 1) *
+ sum_all_radiance_local_size[1];
+ ENQUEUE_SPLIT_KERNEL(sum_all_radiance,
+ sum_all_radiance_global_size,
+ sum_all_radiance_local_size);
+ }
+
+#undef ENQUEUE_SPLIT_KERNEL
+#undef GLUE
+
+ if(numHostIntervention == 0) {
+ /* This means that we are executing kernel more than required
+ * Must avoid this for the next sample/tile.
+ */
+ PathIteration_times = ((numNextPathIterTimes - PATH_ITER_INC_FACTOR) <= 0) ?
+ PATH_ITER_INC_FACTOR : numNextPathIterTimes - PATH_ITER_INC_FACTOR;
+ }
+ else {
+ /* Number of path-iterations done for this tile is set as
+ * Initial path-iteration times for the next tile
+ */
+ PathIteration_times = numNextPathIterTimes;
+ }
+
+ first_tile = false;
+ }
+
+ /* Calculates the amount of memory that has to be always
+ * allocated in order for the split kernel to function.
+ * This memory is tile/scene-property invariant (meaning,
+ * the value returned by this function does not depend
+ * on the user set tile size or scene properties.
+ */
+ size_t get_invariable_mem_allocated()
+ {
+ size_t total_invariable_mem_allocated = 0;
+ size_t KernelGlobals_size = 0;
+
+ KernelGlobals_size = get_KernelGlobals_size();
+
+ total_invariable_mem_allocated += KernelGlobals_size; /* KernelGlobals size */
+ total_invariable_mem_allocated += NUM_QUEUES * sizeof(unsigned int); /* Queue index size */
+ total_invariable_mem_allocated += sizeof(char); /* use_queues_flag size */
+
+ return total_invariable_mem_allocated;
+ }
+
+ /* Calculate the memory that has-to-be/has-been allocated for
+ * the split kernel to function.
+ */
+ size_t get_tile_specific_mem_allocated(const int2 tile_size)
+ {
+ size_t tile_specific_mem_allocated = 0;
+
+ /* Get required tile info */
+ unsigned int user_set_tile_w = tile_size.x;
+ unsigned int user_set_tile_h = tile_size.y;
+
+#ifdef __WORK_STEALING__
+ /* Calculate memory to be allocated for work_pools in
+ * case of work_stealing.
+ */
+ size_t max_global_size[2];
+ size_t max_num_work_pools = 0;
+ max_global_size[0] =
+ (((user_set_tile_w - 1) / SPLIT_KERNEL_LOCAL_SIZE_X) + 1) *
+ SPLIT_KERNEL_LOCAL_SIZE_X;
+ max_global_size[1] =
+ (((user_set_tile_h - 1) / SPLIT_KERNEL_LOCAL_SIZE_Y) + 1) *
+ SPLIT_KERNEL_LOCAL_SIZE_Y;
+ max_num_work_pools =
+ (max_global_size[0] * max_global_size[1]) /
+ (SPLIT_KERNEL_LOCAL_SIZE_X * SPLIT_KERNEL_LOCAL_SIZE_Y);
+ tile_specific_mem_allocated += max_num_work_pools * sizeof(unsigned int);
+#endif
+
+ tile_specific_mem_allocated +=
+ user_set_tile_w * user_set_tile_h * per_thread_output_buffer_size;
+ tile_specific_mem_allocated +=
+ user_set_tile_w * user_set_tile_h * sizeof(RNG);
+
+ return tile_specific_mem_allocated;
+ }
+
+ /* Calculates the texture memories and KernelData (d_data) memory
+ * that has been allocated.
+ */
+ size_t get_scene_specific_mem_allocated(cl_mem d_data)
+ {
+ size_t scene_specific_mem_allocated = 0;
+ /* Calculate texture memories. */
+#define KERNEL_TEX(type, ttype, name) \
+ scene_specific_mem_allocated += get_tex_size(#name);
+#include "kernel_textures.h"
+#undef KERNEL_TEX
+ size_t d_data_size;
+ ciErr = clGetMemObjectInfo(d_data,
+ CL_MEM_SIZE,
+ sizeof(d_data_size),
+ &d_data_size,
+ NULL);
+ assert(ciErr == CL_SUCCESS && "Can't get d_data mem object info");
+ scene_specific_mem_allocated += d_data_size;
+ return scene_specific_mem_allocated;
+ }
+
+ /* Calculate the memory required for one thread in split kernel. */
+ size_t get_per_thread_memory()
+ {
+ size_t shaderdata_size = 0;
+ /* TODO(sergey): This will actually over-allocate if
+ * particular kernel does not support multiclosure.
+ */
+ shaderdata_size = get_shader_data_size(current_max_closure);
+ size_t retval = sizeof(RNG)
+ + sizeof(float3) /* Throughput size */
+ + sizeof(float) /* L transparent size */
+ + sizeof(char) /* Ray state size */
+ + sizeof(unsigned int) /* Work element size */
+ + sizeof(int) /* ISLamp_size */
+ + sizeof(PathRadiance) + sizeof(Ray) + sizeof(PathState)
+ + sizeof(Intersection) /* Overall isect */
+ + sizeof(Intersection) /* Instersection_coop_AO */
+ + sizeof(Intersection) /* Intersection coop DL */
+ + shaderdata_size /* Overall ShaderData */
+ + (shaderdata_size * 2) /* ShaderData : DL and shadow */
+ + sizeof(Ray) + sizeof(BsdfEval)
+ + sizeof(float3) /* AOAlpha size */
+ + sizeof(float3) /* AOBSDF size */
+ + sizeof(Ray)
+ + (sizeof(int) * NUM_QUEUES)
+ + per_thread_output_buffer_size;
+ return retval;
+ }
+
+ /* Considers the total memory available in the device and
+ * and returns the maximum global work size possible.
+ */
+ size_t get_feasible_global_work_size(int2 tile_size, cl_mem d_data)
+ {
+ /* Calculate invariably allocated memory. */
+ size_t invariable_mem_allocated = get_invariable_mem_allocated();
+ /* Calculate tile specific allocated memory. */
+ size_t tile_specific_mem_allocated =
+ get_tile_specific_mem_allocated(tile_size);
+ /* Calculate scene specific allocated memory. */
+ size_t scene_specific_mem_allocated =
+ get_scene_specific_mem_allocated(d_data);
+ /* Calculate total memory available for the threads in global work size. */
+ size_t available_memory = total_allocatable_memory
+ - invariable_mem_allocated
+ - tile_specific_mem_allocated
+ - scene_specific_mem_allocated
+ - DATA_ALLOCATION_MEM_FACTOR;
+ size_t per_thread_memory_required = get_per_thread_memory();
+ return (available_memory / per_thread_memory_required);
+ }
+
+ /* Checks if the device has enough memory to render the whole tile;
+ * If not, we should split single tile into multiple tiles of small size
+ * and process them all.
+ */
+ bool need_to_split_tile(unsigned int d_w,
+ unsigned int d_h,
+ int2 max_render_feasible_tile_size)
+ {
+ size_t global_size_estimate[2];
+ /* TODO(sergey): Such round-ups are in quite few places, need to replace
+ * them with an utility macro.
+ */
+ global_size_estimate[0] =
+ (((d_w - 1) / SPLIT_KERNEL_LOCAL_SIZE_X) + 1) *
+ SPLIT_KERNEL_LOCAL_SIZE_X;
+ global_size_estimate[1] =
+ (((d_h - 1) / SPLIT_KERNEL_LOCAL_SIZE_Y) + 1) *
+ SPLIT_KERNEL_LOCAL_SIZE_Y;
+ if((global_size_estimate[0] * global_size_estimate[1]) >
+ (max_render_feasible_tile_size.x * max_render_feasible_tile_size.y))
+ {
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
+ /* Considers the scene properties, global memory available in the device
+ * and returns a rectanglular tile dimension (approx the maximum)
+ * that should render on split kernel.
+ */
+ int2 get_max_render_feasible_tile_size(size_t feasible_global_work_size)
+ {
+ int2 max_render_feasible_tile_size;
+ int square_root_val = (int)sqrt(feasible_global_work_size);
+ max_render_feasible_tile_size.x = square_root_val;
+ max_render_feasible_tile_size.y = square_root_val;
+ /* Ciel round-off max_render_feasible_tile_size. */
+ int2 ceil_render_feasible_tile_size;
+ ceil_render_feasible_tile_size.x =
+ (((max_render_feasible_tile_size.x - 1) / SPLIT_KERNEL_LOCAL_SIZE_X) + 1) *
+ SPLIT_KERNEL_LOCAL_SIZE_X;
+ ceil_render_feasible_tile_size.y =
+ (((max_render_feasible_tile_size.y - 1) / SPLIT_KERNEL_LOCAL_SIZE_Y) + 1) *
+ SPLIT_KERNEL_LOCAL_SIZE_Y;
+ if(ceil_render_feasible_tile_size.x * ceil_render_feasible_tile_size.y <=
+ feasible_global_work_size)
+ {
+ return ceil_render_feasible_tile_size;
+ }
+ /* Floor round-off max_render_feasible_tile_size. */
+ int2 floor_render_feasible_tile_size;
+ floor_render_feasible_tile_size.x =
+ (max_render_feasible_tile_size.x / SPLIT_KERNEL_LOCAL_SIZE_X) *
+ SPLIT_KERNEL_LOCAL_SIZE_X;
+ floor_render_feasible_tile_size.y =
+ (max_render_feasible_tile_size.y / SPLIT_KERNEL_LOCAL_SIZE_Y) *
+ SPLIT_KERNEL_LOCAL_SIZE_Y;
+ return floor_render_feasible_tile_size;
+ }
+
+ /* Try splitting the current tile into multiple smaller
+ * almost-square-tiles.
+ */
+ int2 get_split_tile_size(RenderTile rtile,
+ int2 max_render_feasible_tile_size)
+ {
+ int2 split_tile_size;
+ int num_global_threads = max_render_feasible_tile_size.x *
+ max_render_feasible_tile_size.y;
+ int d_w = rtile.w;
+ int d_h = rtile.h;
+ /* Ceil round off d_w and d_h */
+ d_w = (((d_w - 1) / SPLIT_KERNEL_LOCAL_SIZE_X) + 1) *
+ SPLIT_KERNEL_LOCAL_SIZE_X;
+ d_h = (((d_h - 1) / SPLIT_KERNEL_LOCAL_SIZE_Y) + 1) *
+ SPLIT_KERNEL_LOCAL_SIZE_Y;
+ while(d_w * d_h > num_global_threads) {
+ /* Halve the longer dimension. */
+ if(d_w >= d_h) {
+ d_w = d_w / 2;
+ d_w = (((d_w - 1) / SPLIT_KERNEL_LOCAL_SIZE_X) + 1) *
+ SPLIT_KERNEL_LOCAL_SIZE_X;
+ }
+ else {
+ d_h = d_h / 2;
+ d_h = (((d_h - 1) / SPLIT_KERNEL_LOCAL_SIZE_Y) + 1) *
+ SPLIT_KERNEL_LOCAL_SIZE_Y;
+ }
+ }
+ split_tile_size.x = d_w;
+ split_tile_size.y = d_h;
+ return split_tile_size;
+ }
+
+ /* Splits existing tile into multiple tiles of tile size split_tile_size. */
+ vector<SplitRenderTile> split_tiles(RenderTile rtile, int2 split_tile_size)
+ {
+ vector<SplitRenderTile> to_path_trace_rtile;
+ int d_w = rtile.w;
+ int d_h = rtile.h;
+ int num_tiles_x = (((d_w - 1) / split_tile_size.x) + 1);
+ int num_tiles_y = (((d_h - 1) / split_tile_size.y) + 1);
+ /* Buffer and rng_state offset calc. */
+ size_t offset_index = rtile.offset + (rtile.x + rtile.y * rtile.stride);
+ size_t offset_x = offset_index % rtile.stride;
+ size_t offset_y = offset_index / rtile.stride;
+ /* Resize to_path_trace_rtile. */
+ to_path_trace_rtile.resize(num_tiles_x * num_tiles_y);
+ for(int tile_iter_y = 0; tile_iter_y < num_tiles_y; tile_iter_y++) {
+ for(int tile_iter_x = 0; tile_iter_x < num_tiles_x; tile_iter_x++) {
+ int rtile_index = tile_iter_y * num_tiles_x + tile_iter_x;
+ to_path_trace_rtile[rtile_index].rng_state_offset_x = offset_x + tile_iter_x * split_tile_size.x;
+ to_path_trace_rtile[rtile_index].rng_state_offset_y = offset_y + tile_iter_y * split_tile_size.y;
+ to_path_trace_rtile[rtile_index].buffer_offset_x = offset_x + tile_iter_x * split_tile_size.x;
+ to_path_trace_rtile[rtile_index].buffer_offset_y = offset_y + tile_iter_y * split_tile_size.y;
+ to_path_trace_rtile[rtile_index].start_sample = rtile.start_sample;
+ to_path_trace_rtile[rtile_index].num_samples = rtile.num_samples;
+ to_path_trace_rtile[rtile_index].sample = rtile.sample;
+ to_path_trace_rtile[rtile_index].resolution = rtile.resolution;
+ to_path_trace_rtile[rtile_index].offset = rtile.offset;
+ to_path_trace_rtile[rtile_index].buffers = rtile.buffers;
+ to_path_trace_rtile[rtile_index].buffer = rtile.buffer;
+ to_path_trace_rtile[rtile_index].rng_state = rtile.rng_state;
+ to_path_trace_rtile[rtile_index].x = rtile.x + (tile_iter_x * split_tile_size.x);
+ to_path_trace_rtile[rtile_index].y = rtile.y + (tile_iter_y * split_tile_size.y);
+ to_path_trace_rtile[rtile_index].buffer_rng_state_stride = rtile.stride;
+ /* Fill width and height of the new render tile. */
+ to_path_trace_rtile[rtile_index].w = (tile_iter_x == (num_tiles_x - 1)) ?
+ (d_w - (tile_iter_x * split_tile_size.x)) /* Border tile */
+ : split_tile_size.x;
+ to_path_trace_rtile[rtile_index].h = (tile_iter_y == (num_tiles_y - 1)) ?
+ (d_h - (tile_iter_y * split_tile_size.y)) /* Border tile */
+ : split_tile_size.y;
+ to_path_trace_rtile[rtile_index].stride = to_path_trace_rtile[rtile_index].w;
+ }
+ }
+ return to_path_trace_rtile;
+ }
+
+ void thread_run(DeviceTask *task)
+ {
+ if(task->type == DeviceTask::FILM_CONVERT) {
+ film_convert(*task, task->buffer, task->rgba_byte, task->rgba_half);
+ }
+ else if(task->type == DeviceTask::SHADER) {
+ shader(*task);
+ }
+ else if(task->type == DeviceTask::PATH_TRACE) {
+ RenderTile tile;
+ bool initialize_data_and_check_render_feasibility = false;
+ bool need_to_split_tiles_further = false;
+ int2 max_render_feasible_tile_size;
+ size_t feasible_global_work_size;
+ const int2 tile_size = task->requested_tile_size;
+ /* Keep rendering tiles until done. */
+ while(task->acquire_tile(this, tile)) {
+ if(!initialize_data_and_check_render_feasibility) {
+ /* Initialize data. */
+ /* Calculate per_thread_output_buffer_size. */
+ size_t output_buffer_size = 0;
+ ciErr = clGetMemObjectInfo((cl_mem)tile.buffer,
+ CL_MEM_SIZE,
+ sizeof(output_buffer_size),
+ &output_buffer_size,
+ NULL);
+ assert(ciErr == CL_SUCCESS && "Can't get tile.buffer mem object info");
+ /* This value is different when running on AMD and NV. */
+ if(background) {
+ /* In offline render the number of buffer elements
+ * associated with tile.buffer is the current tile size.
+ */
+ per_thread_output_buffer_size =
+ output_buffer_size / (tile.w * tile.h);
+ }
+ else {
+ /* interactive rendering, unlike offline render, the number of buffer elements
+ * associated with tile.buffer is the entire viewport size.
+ */
+ per_thread_output_buffer_size =
+ output_buffer_size / (tile.buffers->params.width *
+ tile.buffers->params.height);
+ }
+ /* Check render feasibility. */
+ feasible_global_work_size = get_feasible_global_work_size(
+ tile_size,
+ CL_MEM_PTR(const_mem_map["__data"]->device_pointer));
+ max_render_feasible_tile_size =
+ get_max_render_feasible_tile_size(
+ feasible_global_work_size);
+ need_to_split_tiles_further =
+ need_to_split_tile(tile_size.x,
+ tile_size.y,
+ max_render_feasible_tile_size);
+ initialize_data_and_check_render_feasibility = true;
+ }
+ if(need_to_split_tiles_further) {
+ int2 split_tile_size =
+ get_split_tile_size(tile,
+ max_render_feasible_tile_size);
+ vector<SplitRenderTile> to_path_trace_render_tiles =
+ split_tiles(tile, split_tile_size);
+ /* Print message to console */
+ if(background && (to_path_trace_render_tiles.size() > 1)) {
+ fprintf(stderr, "Message : Tiles need to be split "
+ "further inside path trace (due to insufficient "
+ "device-global-memory for split kernel to "
+ "function) \n"
+ "The current tile of dimensions %dx%d is split "
+ "into tiles of dimension %dx%d for render \n",
+ tile.w, tile.h,
+ split_tile_size.x,
+ split_tile_size.y);
+ }
+ /* Process all split tiles. */
+ for(int tile_iter = 0;
+ tile_iter < to_path_trace_render_tiles.size();
+ ++tile_iter)
+ {
+ path_trace(task,
+ to_path_trace_render_tiles[tile_iter],
+ max_render_feasible_tile_size);
+ }
+ }
+ else {
+ /* No splitting required; process the entire tile at once. */
+ /* Render feasible tile size is user-set-tile-size itself. */
+ max_render_feasible_tile_size.x =
+ (((tile_size.x - 1) / SPLIT_KERNEL_LOCAL_SIZE_X) + 1) *
+ SPLIT_KERNEL_LOCAL_SIZE_X;
+ max_render_feasible_tile_size.y =
+ (((tile_size.y - 1) / SPLIT_KERNEL_LOCAL_SIZE_Y) + 1) *
+ SPLIT_KERNEL_LOCAL_SIZE_Y;
+ /* buffer_rng_state_stride is stride itself. */
+ SplitRenderTile split_tile(tile);
+ split_tile.buffer_rng_state_stride = tile.stride;
+ path_trace(task, split_tile, max_render_feasible_tile_size);
+ }
+ tile.sample = tile.start_sample + tile.num_samples;
+
+ /* Complete kernel execution before release tile. */
+ /* This helps in multi-device render;
+ * The device that reaches the critical-section function
+ * release_tile waits (stalling other devices from entering
+ * release_tile) for all kernels to complete. If device1 (a
+ * slow-render device) reaches release_tile first then it would
+ * stall device2 (a fast-render device) from proceeding to render
+ * next tile.
+ */
+ clFinish(cqCommandQueue);
+
+ task->release_tile(tile);
+ }
+ }
+ }
+
+protected:
+ cl_mem mem_alloc(size_t bufsize, cl_mem_flags mem_flag = CL_MEM_READ_WRITE)
+ {
+ cl_mem ptr;
+ assert(bufsize != 0);
+ ptr = clCreateBuffer(cxContext, mem_flag, bufsize, NULL, &ciErr);
+ opencl_assert_err(ciErr, "clCreateBuffer");
+ return ptr;
+ }
+
+ /* ** Those guys are for workign around some compiler-specific bugs ** */
+
+ string build_options_for_base_program(
+ const DeviceRequestedFeatures& requested_features)
+ {
+ return requested_features.get_build_options();
+ }
+};
+
+Device *opencl_create_split_device(DeviceInfo& info, Stats& stats, bool background)
+{
+ return new OpenCLDeviceSplitKernel(info, stats, background);
+}
+
+CCL_NAMESPACE_END
+
+#endif /* WITH_OPENCL */
diff --git a/intern/cycles/device/opencl/opencl_util.cpp b/intern/cycles/device/opencl/opencl_util.cpp
new file mode 100644
index 00000000000..e425ae8e2e8
--- /dev/null
+++ b/intern/cycles/device/opencl/opencl_util.cpp
@@ -0,0 +1,793 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef WITH_OPENCL
+
+#include "opencl.h"
+
+#include "util_logging.h"
+#include "util_path.h"
+#include "util_time.h"
+
+using std::cerr;
+using std::endl;
+
+CCL_NAMESPACE_BEGIN
+
+OpenCLCache::Slot::ProgramEntry::ProgramEntry()
+ : program(NULL),
+ mutex(NULL)
+{
+}
+
+OpenCLCache::Slot::ProgramEntry::ProgramEntry(const ProgramEntry& rhs)
+ : program(rhs.program),
+ mutex(NULL)
+{
+}
+
+OpenCLCache::Slot::ProgramEntry::~ProgramEntry()
+{
+ delete mutex;
+}
+
+OpenCLCache::Slot::Slot()
+ : context_mutex(NULL),
+ context(NULL)
+{
+}
+
+OpenCLCache::Slot::Slot(const Slot& rhs)
+ : context_mutex(NULL),
+ context(NULL),
+ programs(rhs.programs)
+{
+}
+
+OpenCLCache::Slot::~Slot()
+{
+ delete context_mutex;
+}
+
+OpenCLCache& OpenCLCache::global_instance()
+{
+ static OpenCLCache instance;
+ return instance;
+}
+
+cl_context OpenCLCache::get_context(cl_platform_id platform,
+ cl_device_id device,
+ thread_scoped_lock& slot_locker)
+{
+ assert(platform != NULL);
+
+ OpenCLCache& self = global_instance();
+
+ thread_scoped_lock cache_lock(self.cache_lock);
+
+ pair<CacheMap::iterator,bool> ins = self.cache.insert(
+ CacheMap::value_type(PlatformDevicePair(platform, device), Slot()));
+
+ Slot &slot = ins.first->second;
+
+ /* create slot lock only while holding cache lock */
+ if(!slot.context_mutex)
+ slot.context_mutex = new thread_mutex;
+
+ /* need to unlock cache before locking slot, to allow store to complete */
+ cache_lock.unlock();
+
+ /* lock the slot */
+ slot_locker = thread_scoped_lock(*slot.context_mutex);
+
+ /* If the thing isn't cached */
+ if(slot.context == NULL) {
+ /* return with the caller's lock holder holding the slot lock */
+ return NULL;
+ }
+
+ /* the item was already cached, release the slot lock */
+ slot_locker.unlock();
+
+ cl_int ciErr = clRetainContext(slot.context);
+ assert(ciErr == CL_SUCCESS);
+ (void)ciErr;
+
+ return slot.context;
+}
+
+cl_program OpenCLCache::get_program(cl_platform_id platform,
+ cl_device_id device,
+ ustring key,
+ thread_scoped_lock& slot_locker)
+{
+ assert(platform != NULL);
+
+ OpenCLCache& self = global_instance();
+
+ thread_scoped_lock cache_lock(self.cache_lock);
+
+ pair<CacheMap::iterator,bool> ins = self.cache.insert(
+ CacheMap::value_type(PlatformDevicePair(platform, device), Slot()));
+
+ Slot &slot = ins.first->second;
+
+ pair<Slot::EntryMap::iterator,bool> ins2 = slot.programs.insert(
+ Slot::EntryMap::value_type(key, Slot::ProgramEntry()));
+
+ Slot::ProgramEntry &entry = ins2.first->second;
+
+ /* create slot lock only while holding cache lock */
+ if(!entry.mutex)
+ entry.mutex = new thread_mutex;
+
+ /* need to unlock cache before locking slot, to allow store to complete */
+ cache_lock.unlock();
+
+ /* lock the slot */
+ slot_locker = thread_scoped_lock(*entry.mutex);
+
+ /* If the thing isn't cached */
+ if(entry.program == NULL) {
+ /* return with the caller's lock holder holding the slot lock */
+ return NULL;
+ }
+
+ /* the item was already cached, release the slot lock */
+ slot_locker.unlock();
+
+ cl_int ciErr = clRetainProgram(entry.program);
+ assert(ciErr == CL_SUCCESS);
+ (void)ciErr;
+
+ return entry.program;
+}
+
+void OpenCLCache::store_context(cl_platform_id platform,
+ cl_device_id device,
+ cl_context context,
+ thread_scoped_lock& slot_locker)
+{
+ assert(platform != NULL);
+ assert(device != NULL);
+ assert(context != NULL);
+
+ OpenCLCache &self = global_instance();
+
+ thread_scoped_lock cache_lock(self.cache_lock);
+ CacheMap::iterator i = self.cache.find(PlatformDevicePair(platform, device));
+ cache_lock.unlock();
+
+ Slot &slot = i->second;
+
+ /* sanity check */
+ assert(i != self.cache.end());
+ assert(slot.context == NULL);
+
+ slot.context = context;
+
+ /* unlock the slot */
+ slot_locker.unlock();
+
+ /* increment reference count in OpenCL.
+ * The caller is going to release the object when done with it. */
+ cl_int ciErr = clRetainContext(context);
+ assert(ciErr == CL_SUCCESS);
+ (void)ciErr;
+}
+
+void OpenCLCache::store_program(cl_platform_id platform,
+ cl_device_id device,
+ cl_program program,
+ ustring key,
+ thread_scoped_lock& slot_locker)
+{
+ assert(platform != NULL);
+ assert(device != NULL);
+ assert(program != NULL);
+
+ OpenCLCache &self = global_instance();
+
+ thread_scoped_lock cache_lock(self.cache_lock);
+
+ CacheMap::iterator i = self.cache.find(PlatformDevicePair(platform, device));
+ assert(i != self.cache.end());
+ Slot &slot = i->second;
+
+ Slot::EntryMap::iterator i2 = slot.programs.find(key);
+ assert(i2 != slot.programs.end());
+ Slot::ProgramEntry &entry = i2->second;
+
+ assert(entry.program == NULL);
+
+ cache_lock.unlock();
+
+ entry.program = program;
+
+ /* unlock the slot */
+ slot_locker.unlock();
+
+ /* Increment reference count in OpenCL.
+ * The caller is going to release the object when done with it.
+ */
+ cl_int ciErr = clRetainProgram(program);
+ assert(ciErr == CL_SUCCESS);
+ (void)ciErr;
+}
+
+string OpenCLCache::get_kernel_md5()
+{
+ OpenCLCache &self = global_instance();
+ thread_scoped_lock lock(self.kernel_md5_lock);
+
+ if(self.kernel_md5.empty()) {
+ self.kernel_md5 = path_files_md5_hash(path_get("kernel"));
+ }
+ return self.kernel_md5;
+}
+
+OpenCLDeviceBase::OpenCLProgram::OpenCLProgram(OpenCLDeviceBase *device,
+ string program_name,
+ string kernel_file,
+ string kernel_build_options,
+ bool use_stdout)
+ : device(device),
+ program_name(program_name),
+ kernel_file(kernel_file),
+ kernel_build_options(kernel_build_options),
+ use_stdout(use_stdout)
+{
+ loaded = false;
+ program = NULL;
+}
+
+OpenCLDeviceBase::OpenCLProgram::~OpenCLProgram()
+{
+ release();
+}
+
+void OpenCLDeviceBase::OpenCLProgram::release()
+{
+ for(map<ustring, cl_kernel>::iterator kernel = kernels.begin(); kernel != kernels.end(); ++kernel) {
+ if(kernel->second) {
+ clReleaseKernel(kernel->second);
+ kernel->second = NULL;
+ }
+ }
+ if(program) {
+ clReleaseProgram(program);
+ program = NULL;
+ }
+}
+
+void OpenCLDeviceBase::OpenCLProgram::add_log(string msg, bool debug)
+{
+ if(!use_stdout) {
+ log += msg + "\n";
+ }
+ else if(!debug) {
+ printf("%s\n", msg.c_str());
+ }
+ else {
+ VLOG(2) << msg;
+ }
+}
+
+void OpenCLDeviceBase::OpenCLProgram::add_error(string msg)
+{
+ if(use_stdout) {
+ fprintf(stderr, "%s\n", msg.c_str());
+ }
+ if(error_msg == "") {
+ error_msg += "\n";
+ }
+ error_msg += msg;
+}
+
+void OpenCLDeviceBase::OpenCLProgram::add_kernel(ustring name)
+{
+ if(!kernels.count(name)) {
+ kernels[name] = NULL;
+ }
+}
+
+bool OpenCLDeviceBase::OpenCLProgram::build_kernel(const string *debug_src)
+{
+ string build_options;
+ build_options = device->kernel_build_options(debug_src) + kernel_build_options;
+
+ cl_int ciErr = clBuildProgram(program, 0, NULL, build_options.c_str(), NULL, NULL);
+
+ /* show warnings even if build is successful */
+ size_t ret_val_size = 0;
+
+ clGetProgramBuildInfo(program, device->cdDevice, CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size);
+
+ if(ciErr != CL_SUCCESS) {
+ add_error(string("OpenCL build failed with error ") + clewErrorString(ciErr) + ", errors in console.");
+ }
+
+ if(ret_val_size > 1) {
+ vector<char> build_log(ret_val_size + 1);
+ clGetProgramBuildInfo(program, device->cdDevice, CL_PROGRAM_BUILD_LOG, ret_val_size, &build_log[0], NULL);
+
+ build_log[ret_val_size] = '\0';
+ /* Skip meaningless empty output from the NVidia compiler. */
+ if(!(ret_val_size == 2 && build_log[0] == '\n')) {
+ add_log(string("OpenCL program ") + program_name + " build output: " + string(&build_log[0]), ciErr == CL_SUCCESS);
+ }
+ }
+
+ return (ciErr == CL_SUCCESS);
+}
+
+bool OpenCLDeviceBase::OpenCLProgram::compile_kernel(const string *debug_src)
+{
+ string source = "#include \"kernels/opencl/" + kernel_file + "\" // " + OpenCLCache::get_kernel_md5() + "\n";
+ /* We compile kernels consisting of many files. unfortunately OpenCL
+ * kernel caches do not seem to recognize changes in included files.
+ * so we force recompile on changes by adding the md5 hash of all files.
+ */
+ source = path_source_replace_includes(source, path_get("kernel"));
+
+ if(debug_src) {
+ path_write_text(*debug_src, source);
+ }
+
+ size_t source_len = source.size();
+ const char *source_str = source.c_str();
+ cl_int ciErr;
+
+ program = clCreateProgramWithSource(device->cxContext,
+ 1,
+ &source_str,
+ &source_len,
+ &ciErr);
+
+ if(ciErr != CL_SUCCESS) {
+ add_error(string("OpenCL program creation failed: ") + clewErrorString(ciErr));
+ return false;
+ }
+
+ double starttime = time_dt();
+ add_log(string("Compiling OpenCL program ") + program_name.c_str(), false);
+ add_log(string("Build flags: ") + kernel_build_options, true);
+
+ if(!build_kernel(debug_src))
+ return false;
+
+ add_log(string("Kernel compilation of ") + program_name + " finished in " + string_printf("%.2lfs.\n", time_dt() - starttime), false);
+
+ return true;
+}
+
+bool OpenCLDeviceBase::OpenCLProgram::load_binary(const string& clbin,
+ const string *debug_src)
+{
+ /* read binary into memory */
+ vector<uint8_t> binary;
+
+ if(!path_read_binary(clbin, binary)) {
+ add_error(string_printf("OpenCL failed to read cached binary %s.", clbin.c_str()));
+ return false;
+ }
+
+ /* create program */
+ cl_int status, ciErr;
+ size_t size = binary.size();
+ const uint8_t *bytes = &binary[0];
+
+ program = clCreateProgramWithBinary(device->cxContext, 1, &device->cdDevice,
+ &size, &bytes, &status, &ciErr);
+
+ if(status != CL_SUCCESS || ciErr != CL_SUCCESS) {
+ add_error(string("OpenCL failed create program from cached binary ") + clbin + ": "
+ + clewErrorString(status) + " " + clewErrorString(ciErr));
+ return false;
+ }
+
+ if(!build_kernel(debug_src))
+ return false;
+
+ return true;
+}
+
+bool OpenCLDeviceBase::OpenCLProgram::save_binary(const string& clbin)
+{
+ size_t size = 0;
+ clGetProgramInfo(program, CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &size, NULL);
+
+ if(!size)
+ return false;
+
+ vector<uint8_t> binary(size);
+ uint8_t *bytes = &binary[0];
+
+ clGetProgramInfo(program, CL_PROGRAM_BINARIES, sizeof(uint8_t*), &bytes, NULL);
+
+ return path_write_binary(clbin, binary);
+}
+
+void OpenCLDeviceBase::OpenCLProgram::load()
+{
+ assert(device);
+
+ loaded = false;
+
+ string device_md5 = device->device_md5_hash(kernel_build_options);
+
+ /* Try to use cached kernel. */
+ thread_scoped_lock cache_locker;
+ ustring cache_key(program_name + device_md5);
+ program = device->load_cached_kernel(cache_key,
+ cache_locker);
+
+ if(!program) {
+ add_log(string("OpenCL program ") + program_name + " not found in cache.", true);
+
+ string basename = "cycles_kernel_" + program_name + "_" + device_md5 + "_" + OpenCLCache::get_kernel_md5();
+ basename = path_cache_get(path_join("kernels", basename));
+ string clbin = basename + ".clbin";
+
+ /* path to preprocessed source for debugging */
+ string clsrc, *debug_src = NULL;
+
+ if(OpenCLInfo::use_debug()) {
+ clsrc = basename + ".cl";
+ debug_src = &clsrc;
+ }
+
+ /* If binary kernel exists already, try use it. */
+ if(path_exists(clbin) && load_binary(clbin)) {
+ /* Kernel loaded from binary, nothing to do. */
+ add_log(string("Loaded program from ") + clbin + ".", true);
+ }
+ else {
+ add_log(string("Kernel file ") + clbin + " either doesn't exist or failed to be loaded by driver.", true);
+
+ /* If does not exist or loading binary failed, compile kernel. */
+ if(!compile_kernel(debug_src)) {
+ return;
+ }
+
+ /* Save binary for reuse. */
+ if(!save_binary(clbin)) {
+ add_log(string("Saving compiled OpenCL kernel to ") + clbin + " failed!", true);
+ }
+ }
+
+ /* Cache the program. */
+ device->store_cached_kernel(program,
+ cache_key,
+ cache_locker);
+ }
+ else {
+ add_log(string("Found cached OpenCL program ") + program_name + ".", true);
+ }
+
+ for(map<ustring, cl_kernel>::iterator kernel = kernels.begin(); kernel != kernels.end(); ++kernel) {
+ assert(kernel->second == NULL);
+ cl_int ciErr;
+ string name = "kernel_ocl_" + kernel->first.string();
+ kernel->second = clCreateKernel(program, name.c_str(), &ciErr);
+ if(device->opencl_error(ciErr)) {
+ add_error(string("Error getting kernel ") + name + " from program " + program_name + ": " + clewErrorString(ciErr));
+ return;
+ }
+ }
+
+ loaded = true;
+}
+
+void OpenCLDeviceBase::OpenCLProgram::report_error()
+{
+ /* If loaded is true, there was no error. */
+ if(loaded) return;
+ /* if use_stdout is true, the error was already reported. */
+ if(use_stdout) return;
+
+ cerr << error_msg << endl;
+ if(!compile_output.empty()) {
+ cerr << "OpenCL kernel build output for " << program_name << ":" << endl;
+ cerr << compile_output << endl;
+ }
+}
+
+cl_kernel OpenCLDeviceBase::OpenCLProgram::operator()()
+{
+ assert(kernels.size() == 1);
+ return kernels.begin()->second;
+}
+
+cl_kernel OpenCLDeviceBase::OpenCLProgram::operator()(ustring name)
+{
+ assert(kernels.count(name));
+ return kernels[name];
+}
+
+cl_device_type OpenCLInfo::device_type()
+{
+ switch(DebugFlags().opencl.device_type)
+ {
+ case DebugFlags::OpenCL::DEVICE_NONE:
+ return 0;
+ case DebugFlags::OpenCL::DEVICE_ALL:
+ return CL_DEVICE_TYPE_ALL;
+ case DebugFlags::OpenCL::DEVICE_DEFAULT:
+ return CL_DEVICE_TYPE_DEFAULT;
+ case DebugFlags::OpenCL::DEVICE_CPU:
+ return CL_DEVICE_TYPE_CPU;
+ case DebugFlags::OpenCL::DEVICE_GPU:
+ return CL_DEVICE_TYPE_GPU;
+ case DebugFlags::OpenCL::DEVICE_ACCELERATOR:
+ return CL_DEVICE_TYPE_ACCELERATOR;
+ default:
+ return CL_DEVICE_TYPE_ALL;
+ }
+}
+
+bool OpenCLInfo::use_debug()
+{
+ return DebugFlags().opencl.debug;
+}
+
+bool OpenCLInfo::kernel_use_advanced_shading(const string& platform)
+{
+ /* keep this in sync with kernel_types.h! */
+ if(platform == "NVIDIA CUDA")
+ return true;
+ else if(platform == "Apple")
+ return true;
+ else if(platform == "AMD Accelerated Parallel Processing")
+ return true;
+ else if(platform == "Intel(R) OpenCL")
+ return true;
+ /* Make sure officially unsupported OpenCL platforms
+ * does not set up to use advanced shading.
+ */
+ return false;
+}
+
+bool OpenCLInfo::kernel_use_split(const string& platform_name,
+ const cl_device_type device_type)
+{
+ if(DebugFlags().opencl.kernel_type == DebugFlags::OpenCL::KERNEL_SPLIT) {
+ VLOG(1) << "Forcing split kernel to use.";
+ return true;
+ }
+ if(DebugFlags().opencl.kernel_type == DebugFlags::OpenCL::KERNEL_MEGA) {
+ VLOG(1) << "Forcing mega kernel to use.";
+ return false;
+ }
+ /* TODO(sergey): Replace string lookups with more enum-like API,
+ * similar to device/vendor checks blender's gpu.
+ */
+ if(platform_name == "AMD Accelerated Parallel Processing" &&
+ device_type == CL_DEVICE_TYPE_GPU)
+ {
+ return true;
+ }
+ return false;
+}
+
+bool OpenCLInfo::device_supported(const string& platform_name,
+ const cl_device_id device_id)
+{
+ cl_device_type device_type;
+ clGetDeviceInfo(device_id,
+ CL_DEVICE_TYPE,
+ sizeof(cl_device_type),
+ &device_type,
+ NULL);
+ if(platform_name == "AMD Accelerated Parallel Processing" &&
+ device_type == CL_DEVICE_TYPE_GPU)
+ {
+ return true;
+ }
+ if(platform_name == "Apple" && device_type == CL_DEVICE_TYPE_GPU) {
+ return true;
+ }
+ return false;
+}
+
+bool OpenCLInfo::platform_version_check(cl_platform_id platform,
+ string *error)
+{
+ const int req_major = 1, req_minor = 1;
+ int major, minor;
+ char version[256];
+ clGetPlatformInfo(platform,
+ CL_PLATFORM_VERSION,
+ sizeof(version),
+ &version,
+ NULL);
+ if(sscanf(version, "OpenCL %d.%d", &major, &minor) < 2) {
+ if(error != NULL) {
+ *error = string_printf("OpenCL: failed to parse platform version string (%s).", version);
+ }
+ return false;
+ }
+ if(!((major == req_major && minor >= req_minor) || (major > req_major))) {
+ if(error != NULL) {
+ *error = string_printf("OpenCL: platform version 1.1 or later required, found %d.%d", major, minor);
+ }
+ return false;
+ }
+ if(error != NULL) {
+ *error = "";
+ }
+ return true;
+}
+
+bool OpenCLInfo::device_version_check(cl_device_id device,
+ string *error)
+{
+ const int req_major = 1, req_minor = 1;
+ int major, minor;
+ char version[256];
+ clGetDeviceInfo(device,
+ CL_DEVICE_OPENCL_C_VERSION,
+ sizeof(version),
+ &version,
+ NULL);
+ if(sscanf(version, "OpenCL C %d.%d", &major, &minor) < 2) {
+ if(error != NULL) {
+ *error = string_printf("OpenCL: failed to parse OpenCL C version string (%s).", version);
+ }
+ return false;
+ }
+ if(!((major == req_major && minor >= req_minor) || (major > req_major))) {
+ if(error != NULL) {
+ *error = string_printf("OpenCL: C version 1.1 or later required, found %d.%d", major, minor);
+ }
+ return false;
+ }
+ if(error != NULL) {
+ *error = "";
+ }
+ return true;
+}
+
+void OpenCLInfo::get_usable_devices(vector<OpenCLPlatformDevice> *usable_devices,
+ bool force_all)
+{
+ const bool force_all_platforms = force_all ||
+ (DebugFlags().opencl.kernel_type != DebugFlags::OpenCL::KERNEL_DEFAULT);
+ const cl_device_type device_type = OpenCLInfo::device_type();
+ static bool first_time = true;
+#define FIRST_VLOG(severity) if(first_time) VLOG(severity)
+
+ usable_devices->clear();
+
+ if(device_type == 0) {
+ FIRST_VLOG(2) << "OpenCL devices are forced to be disabled.";
+ first_time = false;
+ return;
+ }
+
+ vector<cl_device_id> device_ids;
+ cl_uint num_devices = 0;
+ vector<cl_platform_id> platform_ids;
+ cl_uint num_platforms = 0;
+
+ /* Get devices. */
+ if(clGetPlatformIDs(0, NULL, &num_platforms) != CL_SUCCESS ||
+ num_platforms == 0)
+ {
+ FIRST_VLOG(2) << "No OpenCL platforms were found.";
+ first_time = false;
+ return;
+ }
+ platform_ids.resize(num_platforms);
+ if(clGetPlatformIDs(num_platforms, &platform_ids[0], NULL) != CL_SUCCESS) {
+ FIRST_VLOG(2) << "Failed to fetch platform IDs from the driver..";
+ first_time = false;
+ return;
+ }
+ /* Devices are numbered consecutively across platforms. */
+ for(int platform = 0; platform < num_platforms; platform++) {
+ cl_platform_id platform_id = platform_ids[platform];
+ char pname[256];
+ if(clGetPlatformInfo(platform_id,
+ CL_PLATFORM_NAME,
+ sizeof(pname),
+ &pname,
+ NULL) != CL_SUCCESS)
+ {
+ FIRST_VLOG(2) << "Failed to get platform name, ignoring.";
+ continue;
+ }
+ string platform_name = pname;
+ FIRST_VLOG(2) << "Enumerating devices for platform "
+ << platform_name << ".";
+ if(!platform_version_check(platform_id)) {
+ FIRST_VLOG(2) << "Ignoring platform " << platform_name
+ << " due to too old compiler version.";
+ continue;
+ }
+ num_devices = 0;
+ cl_int ciErr;
+ if((ciErr = clGetDeviceIDs(platform_id,
+ device_type,
+ 0,
+ NULL,
+ &num_devices)) != CL_SUCCESS || num_devices == 0)
+ {
+ FIRST_VLOG(2) << "Ignoring platform " << platform_name
+ << ", failed to fetch number of devices: " << string(clewErrorString(ciErr));
+ continue;
+ }
+ device_ids.resize(num_devices);
+ if(clGetDeviceIDs(platform_id,
+ device_type,
+ num_devices,
+ &device_ids[0],
+ NULL) != CL_SUCCESS)
+ {
+ FIRST_VLOG(2) << "Ignoring platform " << platform_name
+ << ", failed to fetch devices list.";
+ continue;
+ }
+ for(int num = 0; num < num_devices; num++) {
+ cl_device_id device_id = device_ids[num];
+ char device_name[1024] = "\0";
+ if(clGetDeviceInfo(device_id,
+ CL_DEVICE_NAME,
+ sizeof(device_name),
+ &device_name,
+ NULL) != CL_SUCCESS)
+ {
+ FIRST_VLOG(2) << "Failed to fetch device name, ignoring.";
+ continue;
+ }
+ if(!device_version_check(device_id)) {
+ FIRST_VLOG(2) << "Ignoring device " << device_name
+ << " due to old compiler version.";
+ continue;
+ }
+ if(force_all_platforms ||
+ device_supported(platform_name, device_id))
+ {
+ cl_device_type device_type;
+ if(clGetDeviceInfo(device_id,
+ CL_DEVICE_TYPE,
+ sizeof(cl_device_type),
+ &device_type,
+ NULL) != CL_SUCCESS)
+ {
+ FIRST_VLOG(2) << "Ignoring device " << device_name
+ << ", failed to fetch device type.";
+ continue;
+ }
+ FIRST_VLOG(2) << "Adding new device " << device_name << ".";
+ usable_devices->push_back(OpenCLPlatformDevice(platform_id,
+ platform_name,
+ device_id,
+ device_type,
+ device_name));
+ }
+ else {
+ FIRST_VLOG(2) << "Ignoring device " << device_name
+ << ", not officially supported yet.";
+ }
+ }
+ }
+ first_time = false;
+}
+
+CCL_NAMESPACE_END
+
+#endif
diff --git a/intern/cycles/graph/CMakeLists.txt b/intern/cycles/graph/CMakeLists.txt
new file mode 100644
index 00000000000..4ea18728f1c
--- /dev/null
+++ b/intern/cycles/graph/CMakeLists.txt
@@ -0,0 +1,24 @@
+
+set(INC
+ .
+ ../util
+)
+
+set(SRC
+ node.cpp
+ node_type.cpp
+ node_xml.cpp
+)
+
+set(SRC_HEADERS
+ node.h
+ node_enum.h
+ node_type.h
+ node_xml.h
+)
+
+include_directories(${INC})
+include_directories(SYSTEM ${INC_SYS})
+
+add_library(cycles_graph ${SRC} ${SRC_HEADERS})
+
diff --git a/intern/cycles/graph/node.cpp b/intern/cycles/graph/node.cpp
new file mode 100644
index 00000000000..3c228a716d5
--- /dev/null
+++ b/intern/cycles/graph/node.cpp
@@ -0,0 +1,407 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "node.h"
+#include "node_type.h"
+
+#include "util_foreach.h"
+#include "util_param.h"
+#include "util_transform.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Node Type */
+
+Node::Node(const NodeType *type_, ustring name_)
+: name(name_), type(type_)
+{
+ assert(type);
+
+ /* assign non-empty name, convenient for debugging */
+ if(name.empty()) {
+ name = type->name;
+ }
+
+ /* initialize default values */
+ foreach(const SocketType& socket, type->inputs) {
+ set_default_value(socket);
+ }
+}
+
+Node::~Node()
+{
+}
+
+template<typename T>
+static T& get_socket_value(const Node *node, const SocketType& socket)
+{
+ return (T&)*(((char*)node) + socket.struct_offset);
+}
+
+#ifndef NDEBUG
+static bool is_socket_float3(const SocketType& socket)
+{
+ return socket.type == SocketType::COLOR ||
+ socket.type == SocketType::POINT ||
+ socket.type == SocketType::VECTOR ||
+ socket.type == SocketType::NORMAL;
+}
+
+static bool is_socket_array_float3(const SocketType& socket)
+{
+ return socket.type == SocketType::COLOR_ARRAY ||
+ socket.type == SocketType::POINT_ARRAY ||
+ socket.type == SocketType::VECTOR_ARRAY ||
+ socket.type == SocketType::NORMAL_ARRAY;
+}
+#endif
+
+/* set values */
+void Node::set(const SocketType& input, bool value)
+{
+ assert(input.type == SocketType::BOOLEAN);
+ get_socket_value<bool>(this, input) = value;
+}
+
+void Node::set(const SocketType& input, int value)
+{
+ assert((input.type == SocketType::INT || input.type == SocketType::ENUM));
+ get_socket_value<int>(this, input) = value;
+}
+
+void Node::set(const SocketType& input, uint value)
+{
+ assert(input.type == SocketType::UINT);
+ get_socket_value<uint>(this, input) = value;
+}
+
+void Node::set(const SocketType& input, float value)
+{
+ assert(input.type == SocketType::FLOAT);
+ get_socket_value<float>(this, input) = value;
+}
+
+void Node::set(const SocketType& input, float2 value)
+{
+ assert(input.type == SocketType::FLOAT);
+ get_socket_value<float2>(this, input) = value;
+}
+
+void Node::set(const SocketType& input, float3 value)
+{
+ assert(is_socket_float3(input));
+ get_socket_value<float3>(this, input) = value;
+}
+
+void Node::set(const SocketType& input, const char *value)
+{
+ set(input, ustring(value));
+}
+
+void Node::set(const SocketType& input, ustring value)
+{
+ if(input.type == SocketType::STRING) {
+ get_socket_value<ustring>(this, input) = value;
+ }
+ else if(input.type == SocketType::ENUM) {
+ const NodeEnum& enm = *input.enum_values;
+ if(enm.exists(value)) {
+ get_socket_value<int>(this, input) = enm[value];
+ }
+ else {
+ assert(0);
+ }
+ }
+ else {
+ assert(0);
+ }
+}
+
+void Node::set(const SocketType& input, const Transform& value)
+{
+ assert(input.type == SocketType::TRANSFORM);
+ get_socket_value<Transform>(this, input) = value;
+}
+
+void Node::set(const SocketType& input, Node *value)
+{
+ assert(input.type == SocketType::TRANSFORM);
+ get_socket_value<Node*>(this, input) = value;
+}
+
+/* set array values */
+void Node::set(const SocketType& input, array<bool>& value)
+{
+ assert(input.type == SocketType::BOOLEAN_ARRAY);
+ get_socket_value<array<bool> >(this, input).steal_data(value);
+}
+
+void Node::set(const SocketType& input, array<int>& value)
+{
+ assert(input.type == SocketType::INT_ARRAY);
+ get_socket_value<array<int> >(this, input).steal_data(value);
+}
+
+void Node::set(const SocketType& input, array<float>& value)
+{
+ assert(input.type == SocketType::FLOAT_ARRAY);
+ get_socket_value<array<float> >(this, input).steal_data(value);
+}
+
+void Node::set(const SocketType& input, array<float2>& value)
+{
+ assert(input.type == SocketType::FLOAT_ARRAY);
+ get_socket_value<array<float2> >(this, input).steal_data(value);
+}
+
+void Node::set(const SocketType& input, array<float3>& value)
+{
+ assert(is_socket_array_float3(input));
+ get_socket_value<array<float3> >(this, input).steal_data(value);
+}
+
+void Node::set(const SocketType& input, array<ustring>& value)
+{
+ assert(input.type == SocketType::STRING_ARRAY);
+ get_socket_value<array<ustring> >(this, input).steal_data(value);
+}
+
+void Node::set(const SocketType& input, array<Transform>& value)
+{
+ assert(input.type == SocketType::TRANSFORM_ARRAY);
+ get_socket_value<array<Transform> >(this, input).steal_data(value);
+}
+
+void Node::set(const SocketType& input, array<Node*>& value)
+{
+ assert(input.type == SocketType::TRANSFORM_ARRAY);
+ get_socket_value<array<Node*> >(this, input).steal_data(value);
+}
+
+/* get values */
+bool Node::get_bool(const SocketType& input) const
+{
+ assert(input.type == SocketType::BOOLEAN);
+ return get_socket_value<bool>(this, input);
+}
+
+int Node::get_int(const SocketType& input) const
+{
+ assert(input.type == SocketType::INT || input.type == SocketType::ENUM);
+ return get_socket_value<int>(this, input);
+}
+
+uint Node::get_uint(const SocketType& input) const
+{
+ assert(input.type == SocketType::UINT);
+ return get_socket_value<uint>(this, input);
+}
+
+float Node::get_float(const SocketType& input) const
+{
+ assert(input.type == SocketType::FLOAT);
+ return get_socket_value<float>(this, input);
+}
+
+float2 Node::get_float2(const SocketType& input) const
+{
+ assert(input.type == SocketType::FLOAT);
+ return get_socket_value<float2>(this, input);
+}
+
+float3 Node::get_float3(const SocketType& input) const
+{
+ assert(is_socket_float3(input));
+ return get_socket_value<float3>(this, input);
+}
+
+ustring Node::get_string(const SocketType& input) const
+{
+ if(input.type == SocketType::STRING) {
+ return get_socket_value<ustring>(this, input);
+ }
+ else if(input.type == SocketType::ENUM) {
+ const NodeEnum& enm = *input.enum_values;
+ int intvalue = get_socket_value<int>(this, input);
+ return (enm.exists(intvalue)) ? enm[intvalue] : ustring();
+ }
+ else {
+ assert(0);
+ return ustring();
+ }
+}
+
+Transform Node::get_transform(const SocketType& input) const
+{
+ assert(input.type == SocketType::TRANSFORM);
+ return get_socket_value<Transform>(this, input);
+}
+
+Node *Node::get_node(const SocketType& input) const
+{
+ assert(input.type == SocketType::NODE);
+ return get_socket_value<Node*>(this, input);
+}
+
+/* get array values */
+const array<bool>& Node::get_bool_array(const SocketType& input) const
+{
+ assert(input.type == SocketType::BOOLEAN_ARRAY);
+ return get_socket_value<array<bool> >(this, input);
+}
+
+const array<int>& Node::get_int_array(const SocketType& input) const
+{
+ assert(input.type == SocketType::INT_ARRAY);
+ return get_socket_value<array<int> >(this, input);
+}
+
+const array<float>& Node::get_float_array(const SocketType& input) const
+{
+ assert(input.type == SocketType::FLOAT_ARRAY);
+ return get_socket_value<array<float> >(this, input);
+}
+
+const array<float2>& Node::get_float2_array(const SocketType& input) const
+{
+ assert(input.type == SocketType::FLOAT_ARRAY);
+ return get_socket_value<array<float2> >(this, input);
+}
+
+const array<float3>& Node::get_float3_array(const SocketType& input) const
+{
+ assert(is_socket_array_float3(input));
+ return get_socket_value<array<float3> >(this, input);
+}
+
+const array<ustring>& Node::get_string_array(const SocketType& input) const
+{
+ assert(input.type == SocketType::STRING_ARRAY);
+ return get_socket_value<array<ustring> >(this, input);
+}
+
+const array<Transform>& Node::get_transform_array(const SocketType& input) const
+{
+ assert(input.type == SocketType::TRANSFORM_ARRAY);
+ return get_socket_value<array<Transform> >(this, input);
+}
+
+const array<Node*>& Node::get_node_array(const SocketType& input) const
+{
+ assert(input.type == SocketType::NODE_ARRAY);
+ return get_socket_value<array<Node*> >(this, input);
+}
+
+/* generic value operations */
+
+bool Node::has_default_value(const SocketType& input) const
+{
+ const void *src = input.default_value;
+ void *dst = &get_socket_value<char>(this, input);
+ return memcmp(dst, src, input.size()) == 0;
+}
+
+void Node::set_default_value(const SocketType& socket)
+{
+ const void *src = socket.default_value;
+ void *dst = ((char*)this) + socket.struct_offset;
+ memcpy(dst, src, socket.size());
+}
+
+template<typename T>
+static void copy_array(const Node *node, const SocketType& socket, const Node *other, const SocketType& other_socket)
+{
+ const array<T>* src = (const array<T>*)(((char*)other) + other_socket.struct_offset);
+ array<T>* dst = (array<T>*)(((char*)node) + socket.struct_offset);
+ *dst = *src;
+}
+
+void Node::copy_value(const SocketType& socket, const Node& other, const SocketType& other_socket)
+{
+ assert(socket.type == other_socket.type);
+
+ if(socket.is_array()) {
+ switch(socket.type) {
+ case SocketType::BOOLEAN_ARRAY: copy_array<bool>(this, socket, &other, other_socket); break;
+ case SocketType::FLOAT_ARRAY: copy_array<float>(this, socket, &other, other_socket); break;
+ case SocketType::INT_ARRAY: copy_array<int>(this, socket, &other, other_socket); break;
+ case SocketType::COLOR_ARRAY: copy_array<float3>(this, socket, &other, other_socket); break;
+ case SocketType::VECTOR_ARRAY: copy_array<float3>(this, socket, &other, other_socket); break;
+ case SocketType::POINT_ARRAY: copy_array<float3>(this, socket, &other, other_socket); break;
+ case SocketType::NORMAL_ARRAY: copy_array<float3>(this, socket, &other, other_socket); break;
+ case SocketType::POINT2_ARRAY: copy_array<float2>(this, socket, &other, other_socket); break;
+ case SocketType::STRING_ARRAY: copy_array<ustring>(this, socket, &other, other_socket); break;
+ case SocketType::TRANSFORM_ARRAY: copy_array<Transform>(this, socket, &other, other_socket); break;
+ case SocketType::NODE_ARRAY: copy_array<void*>(this, socket, &other, other_socket); break;
+ default: assert(0); break;
+ }
+ }
+ else {
+ const void *src = ((char*)&other) + other_socket.struct_offset;
+ void *dst = ((char*)this) + socket.struct_offset;
+ memcpy(dst, src, socket.size());
+ }
+}
+
+template<typename T>
+static bool is_array_equal(const Node *node, const Node *other, const SocketType& socket)
+{
+ const array<T>* a = (const array<T>*)(((char*)node) + socket.struct_offset);
+ const array<T>* b = (const array<T>*)(((char*)other) + socket.struct_offset);
+ return *a == *b;
+}
+
+bool Node::equals_value(const Node& other, const SocketType& socket) const
+{
+ if(socket.is_array()) {
+ switch(socket.type) {
+ case SocketType::BOOLEAN_ARRAY: return is_array_equal<bool>(this, &other, socket);
+ case SocketType::FLOAT_ARRAY: return is_array_equal<float>(this, &other, socket);
+ case SocketType::INT_ARRAY: return is_array_equal<int>(this, &other, socket);
+ case SocketType::COLOR_ARRAY: return is_array_equal<float3>(this, &other, socket);
+ case SocketType::VECTOR_ARRAY: return is_array_equal<float3>(this, &other, socket);
+ case SocketType::POINT_ARRAY: return is_array_equal<float3>(this, &other, socket);
+ case SocketType::NORMAL_ARRAY: return is_array_equal<float3>(this, &other, socket);
+ case SocketType::POINT2_ARRAY: return is_array_equal<float2>(this, &other, socket);
+ case SocketType::STRING_ARRAY: return is_array_equal<ustring>(this, &other, socket);
+ case SocketType::TRANSFORM_ARRAY: return is_array_equal<Transform>(this, &other, socket);
+ case SocketType::NODE_ARRAY: return is_array_equal<void*>(this, &other, socket);
+ default: assert(0); return true;
+ }
+ }
+ else {
+ const void *a = ((char*)this) + socket.struct_offset;
+ const void *b = ((char*)&other) + socket.struct_offset;
+ return (memcmp(a, b, socket.size()) == 0);
+ }
+}
+
+/* equals */
+
+bool Node::equals(const Node& other) const
+{
+ assert(type == other.type);
+
+ foreach(const SocketType& socket, type->inputs) {
+ if(!equals_value(other, socket))
+ return false;
+ }
+
+ return true;
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/graph/node.h b/intern/cycles/graph/node.h
new file mode 100644
index 00000000000..64410f4539b
--- /dev/null
+++ b/intern/cycles/graph/node.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "node_type.h"
+
+#include "util_map.h"
+#include "util_param.h"
+#include "util_vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+struct Node;
+struct NodeType;
+struct Transform;
+
+/* Node */
+
+struct Node
+{
+ explicit Node(const NodeType *type, ustring name = ustring());
+ virtual ~Node();
+
+ /* set values */
+ void set(const SocketType& input, bool value);
+ void set(const SocketType& input, int value);
+ void set(const SocketType& input, uint value);
+ void set(const SocketType& input, float value);
+ void set(const SocketType& input, float2 value);
+ void set(const SocketType& input, float3 value);
+ void set(const SocketType& input, const char *value);
+ void set(const SocketType& input, ustring value);
+ void set(const SocketType& input, const Transform& value);
+ void set(const SocketType& input, Node *value);
+
+ /* set array values. the memory from the input array will taken over
+ * by the node and the input array will be empty after return */
+ void set(const SocketType& input, array<bool>& value);
+ void set(const SocketType& input, array<int>& value);
+ void set(const SocketType& input, array<float>& value);
+ void set(const SocketType& input, array<float2>& value);
+ void set(const SocketType& input, array<float3>& value);
+ void set(const SocketType& input, array<ustring>& value);
+ void set(const SocketType& input, array<Transform>& value);
+ void set(const SocketType& input, array<Node*>& value);
+
+ /* get values */
+ bool get_bool(const SocketType& input) const;
+ int get_int(const SocketType& input) const;
+ uint get_uint(const SocketType& input) const;
+ float get_float(const SocketType& input) const;
+ float2 get_float2(const SocketType& input) const;
+ float3 get_float3(const SocketType& input) const;
+ ustring get_string(const SocketType& input) const;
+ Transform get_transform(const SocketType& input) const;
+ Node *get_node(const SocketType& input) const;
+
+ /* get array values */
+ const array<bool>& get_bool_array(const SocketType& input) const;
+ const array<int>& get_int_array(const SocketType& input) const;
+ const array<float>& get_float_array(const SocketType& input) const;
+ const array<float2>& get_float2_array(const SocketType& input) const;
+ const array<float3>& get_float3_array(const SocketType& input) const;
+ const array<ustring>& get_string_array(const SocketType& input) const;
+ const array<Transform>& get_transform_array(const SocketType& input) const;
+ const array<Node*>& get_node_array(const SocketType& input) const;
+
+ /* generic values operations */
+ bool has_default_value(const SocketType& input) const;
+ void set_default_value(const SocketType& input);
+ bool equals_value(const Node& other, const SocketType& input) const;
+ void copy_value(const SocketType& input, const Node& other, const SocketType& other_input);
+
+ /* equals */
+ bool equals(const Node& other) const;
+
+ ustring name;
+ const NodeType *type;
+};
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/graph/node_enum.h b/intern/cycles/graph/node_enum.h
new file mode 100644
index 00000000000..2bae531c036
--- /dev/null
+++ b/intern/cycles/graph/node_enum.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "util_map.h"
+#include "util_param.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Enum
+ *
+ * Utility class for enum values. */
+
+struct NodeEnum {
+ bool empty() const { return left.empty(); }
+ void insert(const char *x, int y) {
+ left[ustring(x)] = y;
+ right[y] = ustring(x);
+ }
+
+ bool exists(ustring x) const { return left.find(x) != left.end(); }
+ bool exists(int y) const { return right.find(y) != right.end(); }
+
+ int operator[](const char *x) const { return left.find(ustring(x))->second; }
+ int operator[](ustring x) const { return left.find(x)->second; }
+ ustring operator[](int y) const { return right.find(y)->second; }
+
+private:
+ unordered_map<ustring, int, ustringHash> left;
+ unordered_map<int, ustring> right;
+};
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/graph/node_type.cpp b/intern/cycles/graph/node_type.cpp
new file mode 100644
index 00000000000..5b98de778ad
--- /dev/null
+++ b/intern/cycles/graph/node_type.cpp
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "node_type.h"
+#include "util_foreach.h"
+#include "util_transform.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Node Socket Type */
+
+size_t SocketType::size() const
+{
+ return size(type);
+}
+
+bool SocketType::is_array() const
+{
+ return (type >= BOOLEAN_ARRAY);
+}
+
+size_t SocketType::size(Type type)
+{
+ switch(type)
+ {
+ case UNDEFINED: return 0;
+
+ case BOOLEAN: return sizeof(bool);
+ case FLOAT: return sizeof(float);
+ case INT: return sizeof(int);
+ case UINT: return sizeof(uint);
+ case COLOR: return sizeof(float3);
+ case VECTOR: return sizeof(float3);
+ case POINT: return sizeof(float3);
+ case NORMAL: return sizeof(float3);
+ case POINT2: return sizeof(float2);
+ case CLOSURE: return 0;
+ case STRING: return sizeof(ustring);
+ case ENUM: return sizeof(int);
+ case TRANSFORM: return sizeof(Transform);
+ case NODE: return sizeof(void*);
+
+ case BOOLEAN_ARRAY: return sizeof(array<bool>);
+ case FLOAT_ARRAY: return sizeof(array<float>);
+ case INT_ARRAY: return sizeof(array<int>);
+ case COLOR_ARRAY: return sizeof(array<float3>);
+ case VECTOR_ARRAY: return sizeof(array<float3>);
+ case POINT_ARRAY: return sizeof(array<float3>);
+ case NORMAL_ARRAY: return sizeof(array<float3>);
+ case POINT2_ARRAY: return sizeof(array<float2>);
+ case STRING_ARRAY: return sizeof(array<ustring>);
+ case TRANSFORM_ARRAY: return sizeof(array<Transform>);
+ case NODE_ARRAY: return sizeof(array<void*>);
+ }
+
+ assert(0);
+ return 0;
+}
+
+size_t SocketType::max_size()
+{
+ return sizeof(Transform);
+}
+
+void *SocketType::zero_default_value()
+{
+ static Transform zero_transform = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
+ return &zero_transform;
+}
+
+ustring SocketType::type_name(Type type)
+{
+ static ustring names[] = {
+ ustring("undefined"),
+
+ ustring("boolean"),
+ ustring("float"),
+ ustring("int"),
+ ustring("uint"),
+ ustring("color"),
+ ustring("vector"),
+ ustring("point"),
+ ustring("normal"),
+ ustring("point2"),
+ ustring("closure"),
+ ustring("string"),
+ ustring("enum"),
+ ustring("transform"),
+ ustring("node"),
+
+ ustring("array_boolean"),
+ ustring("array_float"),
+ ustring("array_int"),
+ ustring("array_color"),
+ ustring("array_vector"),
+ ustring("array_point"),
+ ustring("array_normal"),
+ ustring("array_point2"),
+ ustring("array_string"),
+ ustring("array_transform"),
+ ustring("array_node")};
+
+ return names[(int)type];
+}
+
+bool SocketType::is_float3(Type type)
+{
+ return (type == COLOR || type == VECTOR || type == POINT || type == NORMAL);
+}
+
+/* Node Type */
+
+NodeType::NodeType(Type type_)
+: type(type_)
+{
+}
+
+NodeType::~NodeType()
+{
+}
+
+void NodeType::register_input(ustring name, ustring ui_name, SocketType::Type type, int struct_offset,
+ const void *default_value, const NodeEnum *enum_values,
+ const NodeType **node_type, int flags, int extra_flags)
+{
+ SocketType socket;
+ socket.name = name;
+ socket.ui_name = ui_name;
+ socket.type = type;
+ socket.struct_offset = struct_offset;
+ socket.default_value = default_value;
+ socket.enum_values = enum_values;
+ socket.node_type = node_type;
+ socket.flags = flags | extra_flags;
+ inputs.push_back(socket);
+}
+
+void NodeType::register_output(ustring name, ustring ui_name, SocketType::Type type)
+{
+ SocketType socket;
+ socket.name = name;
+ socket.ui_name = ui_name;
+ socket.type = type;
+ socket.struct_offset = 0;
+ socket.default_value = NULL;
+ socket.enum_values = NULL;
+ socket.node_type = NULL;
+ socket.flags = SocketType::LINKABLE;
+ outputs.push_back(socket);
+}
+
+const SocketType *NodeType::find_input(ustring name) const
+{
+ foreach(const SocketType& socket, inputs) {
+ if(socket.name == name) {
+ return &socket;
+ }
+ }
+
+ return NULL;
+}
+
+const SocketType *NodeType::find_output(ustring name) const
+{
+ foreach(const SocketType& socket, outputs) {
+ if(socket.name == name) {
+ return &socket;
+ }
+ }
+
+ return NULL;
+}
+
+/* Node Type Registry */
+
+unordered_map<ustring, NodeType, ustringHash>& NodeType::types()
+{
+ static unordered_map<ustring, NodeType, ustringHash> _types;
+ return _types;
+}
+
+NodeType *NodeType::add(const char *name_, CreateFunc create_, Type type_)
+{
+ ustring name(name_);
+
+ if(types().find(name) != types().end()) {
+ fprintf(stderr, "Node type %s registered twice!\n", name_);
+ assert(0);
+ return NULL;
+ }
+
+ types()[name] = NodeType(type_);
+
+ NodeType *type = &types()[name];
+ type->name = name;
+ type->create = create_;
+ return type;
+}
+
+const NodeType *NodeType::find(ustring name)
+{
+ unordered_map<ustring, NodeType, ustringHash>::iterator it = types().find(name);
+ return (it == types().end()) ? NULL : &it->second;
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/graph/node_type.h b/intern/cycles/graph/node_type.h
new file mode 100644
index 00000000000..1fb135f6d22
--- /dev/null
+++ b/intern/cycles/graph/node_type.h
@@ -0,0 +1,265 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "node_enum.h"
+
+#include "util_map.h"
+#include "util_param.h"
+#include "util_string.h"
+#include "util_vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+struct Node;
+struct NodeType;
+
+/* Socket Type */
+
+struct SocketType
+{
+ enum Type
+ {
+ UNDEFINED,
+
+ BOOLEAN,
+ FLOAT,
+ INT,
+ UINT,
+ COLOR,
+ VECTOR,
+ POINT,
+ NORMAL,
+ POINT2,
+ CLOSURE,
+ STRING,
+ ENUM,
+ TRANSFORM,
+ NODE,
+
+ BOOLEAN_ARRAY,
+ FLOAT_ARRAY,
+ INT_ARRAY,
+ COLOR_ARRAY,
+ VECTOR_ARRAY,
+ POINT_ARRAY,
+ NORMAL_ARRAY,
+ POINT2_ARRAY,
+ STRING_ARRAY,
+ TRANSFORM_ARRAY,
+ NODE_ARRAY,
+ };
+
+ enum Flags {
+ LINKABLE = (1 << 0),
+ ANIMATABLE = (1 << 1),
+
+ SVM_INTERNAL = (1 << 2),
+ OSL_INTERNAL = (1 << 3),
+ INTERNAL = (1 << 2) | (1 << 3),
+
+ LINK_TEXTURE_GENERATED = (1 << 4),
+ LINK_TEXTURE_UV = (1 << 5),
+ LINK_INCOMING = (1 << 6),
+ LINK_NORMAL = (1 << 7),
+ LINK_POSITION = (1 << 8),
+ LINK_TANGENT = (1 << 9),
+ DEFAULT_LINK_MASK = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 9)
+ };
+
+ ustring name;
+ Type type;
+ int struct_offset;
+ const void *default_value;
+ const NodeEnum *enum_values;
+ const NodeType **node_type;
+ int flags;
+ ustring ui_name;
+
+ size_t size() const;
+ bool is_array() const;
+ static size_t size(Type type);
+ static size_t max_size();
+ static ustring type_name(Type type);
+ static void *zero_default_value();
+ static bool is_float3(Type type);
+};
+
+/* Node Type */
+
+struct NodeType
+{
+ enum Type {
+ NONE,
+ SHADER
+ };
+
+ explicit NodeType(Type type = NONE);
+ ~NodeType();
+
+ void register_input(ustring name, ustring ui_name, SocketType::Type type,
+ int struct_offset, const void *default_value,
+ const NodeEnum *enum_values = NULL,
+ const NodeType **node_type = NULL,
+ int flags = 0, int extra_flags = 0);
+ void register_output(ustring name, ustring ui_name, SocketType::Type type);
+
+ const SocketType *find_input(ustring name) const;
+ const SocketType *find_output(ustring name) const;
+
+ typedef Node *(*CreateFunc)(const NodeType *type);
+
+ ustring name;
+ Type type;
+ vector<SocketType, std::allocator<SocketType> > inputs;
+ vector<SocketType, std::allocator<SocketType> > outputs;
+ CreateFunc create;
+
+ static NodeType *add(const char *name, CreateFunc create, Type type = NONE);
+ static const NodeType *find(ustring name);
+ static unordered_map<ustring, NodeType, ustringHash>& types();
+};
+
+/* Node Definition Macros */
+
+#define NODE_DECLARE \
+template<typename T> \
+static const NodeType *register_type(); \
+static Node *create(const NodeType *type); \
+static const NodeType *node_type;
+
+#define NODE_DEFINE(structname) \
+const NodeType *structname::node_type = structname::register_type<structname>(); \
+Node *structname::create(const NodeType*) { return new structname(); } \
+template<typename T> \
+const NodeType *structname::register_type()
+
+/* Sock Definition Macros */
+
+#define SOCKET_OFFSETOF(T, name) (((char *)&(((T *)1)->name)) - (char *)1)
+#define SOCKET_SIZEOF(T, name) (sizeof(((T *)1)->name))
+#define SOCKET_DEFINE(name, ui_name, default_value, datatype, TYPE, flags, ...) \
+ { \
+ static datatype defval = default_value; \
+ CHECK_TYPE(((T *)1)->name, datatype); \
+ type->register_input(ustring(#name), ustring(ui_name), TYPE, SOCKET_OFFSETOF(T, name), &defval, NULL, NULL, flags, ##__VA_ARGS__); \
+ }
+
+#define SOCKET_BOOLEAN(name, ui_name, default_value, ...) \
+ SOCKET_DEFINE(name, ui_name, default_value, bool, SocketType::BOOLEAN, 0, ##__VA_ARGS__)
+#define SOCKET_INT(name, ui_name, default_value, ...) \
+ SOCKET_DEFINE(name, ui_name, default_value, int, SocketType::INT, 0, ##__VA_ARGS__)
+#define SOCKET_UINT(name, ui_name, default_value, ...) \
+ SOCKET_DEFINE(name, ui_name, default_value, uint, SocketType::UINT, 0, ##__VA_ARGS__)
+#define SOCKET_FLOAT(name, ui_name, default_value, ...) \
+ SOCKET_DEFINE(name, ui_name, default_value, float, SocketType::FLOAT, 0, ##__VA_ARGS__)
+#define SOCKET_COLOR(name, ui_name, default_value, ...) \
+ SOCKET_DEFINE(name, ui_name, default_value, float3, SocketType::COLOR, 0, ##__VA_ARGS__)
+#define SOCKET_VECTOR(name, ui_name, default_value, ...) \
+ SOCKET_DEFINE(name, ui_name, default_value, float3, SocketType::VECTOR, 0, ##__VA_ARGS__)
+#define SOCKET_POINT(name, ui_name, default_value, ...) \
+ SOCKET_DEFINE(name, ui_name, default_value, float3, SocketType::POINT, 0, ##__VA_ARGS__)
+#define SOCKET_NORMAL(name, ui_name, default_value, ...) \
+ SOCKET_DEFINE(name, ui_name, default_value, float3, SocketType::NORMAL, 0, ##__VA_ARGS__)
+#define SOCKET_POINT2(name, ui_name, default_value, ...) \
+ SOCKET_DEFINE(name, ui_name, default_value, float2, SocketType::POINT2, 0, ##__VA_ARGS__)
+#define SOCKET_STRING(name, ui_name, default_value, ...) \
+ SOCKET_DEFINE(name, ui_name, default_value, ustring, SocketType::STRING, 0, ##__VA_ARGS__)
+#define SOCKET_TRANSFORM(name, ui_name, default_value, ...) \
+ SOCKET_DEFINE(name, ui_name, default_value, Transform, SocketType::TRANSFORM, 0, ##__VA_ARGS__)
+#define SOCKET_ENUM(name, ui_name, values, default_value, ...) \
+ { \
+ static int defval = default_value; \
+ assert(SOCKET_SIZEOF(T, name) == sizeof(int)); \
+ type->register_input(ustring(#name), ustring(ui_name), SocketType::ENUM, SOCKET_OFFSETOF(T, name), &defval, &values, NULL, ##__VA_ARGS__); \
+ }
+#define SOCKET_NODE(name, ui_name, node_type, ...) \
+ { \
+ static Node *defval = NULL; \
+ assert(SOCKET_SIZEOF(T, name) == sizeof(Node*)); \
+ type->register_input(ustring(#name), ustring(ui_name), SocketType::NODE, SOCKET_OFFSETOF(T, name), &defval, NULL, node_type, ##__VA_ARGS__); \
+ }
+
+#define SOCKET_BOOLEAN_ARRAY(name, ui_name, default_value, ...) \
+ SOCKET_DEFINE(name, ui_name, default_value, array<bool>, SocketType::BOOLEAN_ARRAY, 0, ##__VA_ARGS__)
+#define SOCKET_INT_ARRAY(name, ui_name, default_value, ...) \
+ SOCKET_DEFINE(name, ui_name, default_value, array<int>, SocketType::INT_ARRAY, 0, ##__VA_ARGS__)
+#define SOCKET_FLOAT_ARRAY(name, ui_name, default_value, ...) \
+ SOCKET_DEFINE(name, ui_name, default_value, array<float>, SocketType::FLOAT_ARRAY, 0, ##__VA_ARGS__)
+#define SOCKET_COLOR_ARRAY(name, ui_name, default_value, ...) \
+ SOCKET_DEFINE(name, ui_name, default_value, array<float3>, SocketType::COLOR_ARRAY, 0, ##__VA_ARGS__)
+#define SOCKET_VECTOR_ARRAY(name, ui_name, default_value, ...) \
+ SOCKET_DEFINE(name, ui_name, default_value, array<float3>, SocketType::VECTOR_ARRAY, 0, ##__VA_ARGS__)
+#define SOCKET_POINT_ARRAY(name, ui_name, default_value, ...) \
+ SOCKET_DEFINE(name, ui_name, default_value, array<float3>, SocketType::POINT_ARRAY, 0, ##__VA_ARGS__)
+#define SOCKET_NORMAL_ARRAY(name, ui_name, default_value, ...) \
+ SOCKET_DEFINE(name, ui_name, default_value, array<float3>, SocketType::NORMAL_ARRAY, 0, ##__VA_ARGS__)
+#define SOCKET_POINT2_ARRAY(name, ui_name, default_value, ...) \
+ SOCKET_DEFINE(name, ui_name, default_value, array<float2>, SocketType::POINT2_ARRAY, 0, ##__VA_ARGS__)
+#define SOCKET_STRING_ARRAY(name, ui_name, default_value, ...) \
+ SOCKET_DEFINE(name, ui_name, default_value, array<ustring>, SocketType::STRING_ARRAY, 0, ##__VA_ARGS__)
+#define SOCKET_TRANSFORM_ARRAY(name, ui_name, default_value, ...) \
+ SOCKET_DEFINE(name, ui_name, default_value, array<Transform>, SocketType::TRANSFORM_ARRAY, 0, ##__VA_ARGS__)
+#define SOCKET_NODE_ARRAY(name, ui_name, node_type, ...) \
+ { \
+ static Node *defval = NULL; \
+ assert(SOCKET_SIZEOF(T, name) == sizeof(Node*)); \
+ type->register_input(ustring(#name), ustring(ui_name), SocketType::NODE_ARRAY, SOCKET_OFFSETOF(T, name), &defval, NULL, node_type, ##__VA_ARGS__); \
+ }
+
+#define SOCKET_IN_BOOLEAN(name, ui_name, default_value, ...) \
+ SOCKET_DEFINE(name, ui_name, default_value, bool, SocketType::BOOLEAN, SocketType::LINKABLE, ##__VA_ARGS__)
+#define SOCKET_IN_INT(name, ui_name, default_value, ...) \
+ SOCKET_DEFINE(name, ui_name, default_value, int, SocketType::INT, SocketType::LINKABLE, ##__VA_ARGS__)
+#define SOCKET_IN_FLOAT(name, ui_name, default_value, ...) \
+ SOCKET_DEFINE(name, ui_name, default_value, float, SocketType::FLOAT, SocketType::LINKABLE, ##__VA_ARGS__)
+#define SOCKET_IN_COLOR(name, ui_name, default_value, ...) \
+ SOCKET_DEFINE(name, ui_name, default_value, float3, SocketType::COLOR, SocketType::LINKABLE, ##__VA_ARGS__)
+#define SOCKET_IN_VECTOR(name, ui_name, default_value, ...) \
+ SOCKET_DEFINE(name, ui_name, default_value, float3, SocketType::VECTOR, SocketType::LINKABLE, ##__VA_ARGS__)
+#define SOCKET_IN_POINT(name, ui_name, default_value, ...) \
+ SOCKET_DEFINE(name, ui_name, default_value, float3, SocketType::POINT, SocketType::LINKABLE, ##__VA_ARGS__)
+#define SOCKET_IN_NORMAL(name, ui_name, default_value, ...) \
+ SOCKET_DEFINE(name, ui_name, default_value, float3, SocketType::NORMAL, SocketType::LINKABLE, ##__VA_ARGS__)
+#define SOCKET_IN_STRING(name, ui_name, default_value, ...) \
+ SOCKET_DEFINE(name, ui_name, default_value, ustring, SocketType::STRING, SocketType::LINKABLE, ##__VA_ARGS__)
+#define SOCKET_IN_CLOSURE(name, ui_name, ...) \
+ type->register_input(ustring(#name), ustring(ui_name), SocketType::CLOSURE, 0, NULL, NULL, NULL, SocketType::LINKABLE, ##__VA_ARGS__)
+
+#define SOCKET_OUT_BOOLEAN(name, ui_name) \
+ { type->register_output(ustring(#name), ustring(ui_name), SocketType::BOOLEAN); }
+#define SOCKET_OUT_INT(name, ui_name) \
+ { type->register_output(ustring(#name), ustring(ui_name), SocketType::INT); }
+#define SOCKET_OUT_FLOAT(name, ui_name) \
+ { type->register_output(ustring(#name), ustring(ui_name), SocketType::FLOAT); }
+#define SOCKET_OUT_COLOR(name, ui_name) \
+ { type->register_output(ustring(#name), ustring(ui_name), SocketType::COLOR); }
+#define SOCKET_OUT_VECTOR(name, ui_name) \
+ { type->register_output(ustring(#name), ustring(ui_name), SocketType::VECTOR); }
+#define SOCKET_OUT_POINT(name, ui_name) \
+ { type->register_output(ustring(#name), ustring(ui_name), SocketType::POINT); }
+#define SOCKET_OUT_NORMAL(name, ui_name) \
+ { type->register_output(ustring(#name), ustring(ui_name), SocketType::NORMAL); }
+#define SOCKET_OUT_CLOSURE(name, ui_name) \
+ { type->register_output(ustring(#name), ustring(ui_name), SocketType::CLOSURE); }
+#define SOCKET_OUT_STRING(name, ui_name) \
+ { type->register_output(ustring(#name), ustring(ui_name), SocketType::STRING); }
+#define SOCKET_OUT_ENUM(name, ui_name) \
+ { type->register_output(ustring(#name), ustring(ui_name), SocketType::ENUM); }
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/graph/node_xml.cpp b/intern/cycles/graph/node_xml.cpp
new file mode 100644
index 00000000000..590e09645ed
--- /dev/null
+++ b/intern/cycles/graph/node_xml.cpp
@@ -0,0 +1,462 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "node_xml.h"
+
+#include "util_foreach.h"
+#include "util_string.h"
+#include "util_transform.h"
+
+CCL_NAMESPACE_BEGIN
+
+static bool xml_read_boolean(const char *value)
+{
+ return string_iequals(value, "true") || (atoi(value) != 0);
+}
+
+static const char *xml_write_boolean(bool value)
+{
+ return (value) ? "true" : "false";
+}
+
+template<int VECTOR_SIZE, typename T>
+static void xml_read_float_array(T& value, pugi::xml_attribute attr)
+{
+ vector<string> tokens;
+ string_split(tokens, attr.value());
+
+ if(tokens.size() % VECTOR_SIZE != 0) {
+ return;
+ }
+
+ value.resize(tokens.size() / VECTOR_SIZE);
+ for(size_t i = 0; i < value.size(); i++) {
+ float *value_float = (float*)&value[i];
+
+ for(size_t j = 0; j < VECTOR_SIZE; j++)
+ value_float[j] = (float)atof(tokens[i * VECTOR_SIZE + j].c_str());
+ }
+}
+
+void xml_read_node(XMLReader& reader, Node *node, pugi::xml_node xml_node)
+{
+ pugi::xml_attribute name_attr = xml_node.attribute("name");
+ if(name_attr) {
+ node->name = ustring(name_attr.value());
+ }
+
+ foreach(const SocketType& socket, node->type->inputs) {
+ if(socket.type == SocketType::CLOSURE || socket.type == SocketType::UNDEFINED) {
+ continue;
+ }
+ if(socket.flags & SocketType::INTERNAL) {
+ continue;
+ }
+
+ pugi::xml_attribute attr = xml_node.attribute(socket.name.c_str());
+
+ if(!attr) {
+ continue;
+ }
+
+ switch(socket.type)
+ {
+ case SocketType::BOOLEAN:
+ {
+ node->set(socket, xml_read_boolean(attr.value()));
+ break;
+ }
+ case SocketType::BOOLEAN_ARRAY:
+ {
+ vector<string> tokens;
+ string_split(tokens, attr.value());
+
+ array<bool> value;
+ value.resize(tokens.size());
+ for(size_t i = 0; i < value.size(); i++)
+ value[i] = xml_read_boolean(tokens[i].c_str());
+ node->set(socket, value);
+ break;
+ }
+ case SocketType::FLOAT:
+ {
+ node->set(socket, (float)atof(attr.value()));
+ break;
+ }
+ case SocketType::FLOAT_ARRAY:
+ {
+ array<float> value;
+ xml_read_float_array<1>(value, attr);
+ node->set(socket, value);
+ break;
+ }
+ case SocketType::INT:
+ {
+ node->set(socket, (int)atoi(attr.value()));
+ break;
+ }
+ case SocketType::UINT:
+ {
+ node->set(socket, (uint)atoi(attr.value()));
+ break;
+ }
+ case SocketType::INT_ARRAY:
+ {
+ vector<string> tokens;
+ string_split(tokens, attr.value());
+
+ array<int> value;
+ value.resize(tokens.size());
+ for(size_t i = 0; i < value.size(); i++) {
+ value[i] = (int)atoi(attr.value());
+ }
+ node->set(socket, value);
+ break;
+ }
+ case SocketType::COLOR:
+ case SocketType::VECTOR:
+ case SocketType::POINT:
+ case SocketType::NORMAL:
+ {
+ array<float3> value;
+ xml_read_float_array<3>(value, attr);
+ if(value.size() == 1) {
+ node->set(socket, value[0]);
+ }
+ break;
+ }
+ case SocketType::COLOR_ARRAY:
+ case SocketType::VECTOR_ARRAY:
+ case SocketType::POINT_ARRAY:
+ case SocketType::NORMAL_ARRAY:
+ {
+ array<float3> value;
+ xml_read_float_array<3>(value, attr);
+ node->set(socket, value);
+ break;
+ }
+ case SocketType::POINT2:
+ {
+ array<float2> value;
+ xml_read_float_array<2>(value, attr);
+ if(value.size() == 1) {
+ node->set(socket, value[0]);
+ }
+ break;
+ }
+ case SocketType::POINT2_ARRAY:
+ {
+ array<float2> value;
+ xml_read_float_array<2>(value, attr);
+ node->set(socket, value);
+ break;
+ }
+ case SocketType::STRING:
+ {
+ node->set(socket, attr.value());
+ break;
+ }
+ case SocketType::ENUM:
+ {
+ ustring value(attr.value());
+ if(socket.enum_values->exists(value)) {
+ node->set(socket, value);
+ }
+ else {
+ fprintf(stderr, "Unknown value \"%s\" for attribute \"%s\".\n", value.c_str(), socket.name.c_str());
+ }
+ break;
+ }
+ case SocketType::STRING_ARRAY:
+ {
+ vector<string> tokens;
+ string_split(tokens, attr.value());
+
+ array<ustring> value;
+ value.resize(tokens.size());
+ for(size_t i = 0; i < value.size(); i++) {
+ value[i] = ustring(tokens[i]);
+ }
+ node->set(socket, value);
+ break;
+ }
+ case SocketType::TRANSFORM:
+ {
+ array<Transform> value;
+ xml_read_float_array<16>(value, attr);
+ if(value.size() == 1) {
+ node->set(socket, value[0]);
+ }
+ break;
+ }
+ case SocketType::TRANSFORM_ARRAY:
+ {
+ array<Transform> value;
+ xml_read_float_array<16>(value, attr);
+ node->set(socket, value);
+ break;
+ }
+ case SocketType::NODE:
+ {
+ ustring value(attr.value());
+ map<ustring, Node*>::iterator it = reader.node_map.find(value);
+ if(it != reader.node_map.end())
+ {
+ Node *value_node = it->second;
+ if(value_node->type == *(socket.node_type))
+ node->set(socket, it->second);
+ }
+ break;
+ }
+ case SocketType::NODE_ARRAY:
+ {
+ vector<string> tokens;
+ string_split(tokens, attr.value());
+
+ array<Node*> value;
+ value.resize(tokens.size());
+ for(size_t i = 0; i < value.size(); i++)
+ {
+ map<ustring, Node*>::iterator it = reader.node_map.find(ustring(tokens[i]));
+ if(it != reader.node_map.end())
+ {
+ Node *value_node = it->second;
+ value[i] = (value_node->type == *(socket.node_type)) ? value_node : NULL;
+ }
+ else
+ {
+ value[i] = NULL;
+ }
+ }
+ node->set(socket, value);
+ break;
+ }
+ case SocketType::CLOSURE:
+ case SocketType::UNDEFINED:
+ break;
+ }
+ }
+
+ if(node->name)
+ reader.node_map[node->name] = node;
+}
+
+pugi::xml_node xml_write_node(Node *node, pugi::xml_node xml_root)
+{
+ pugi::xml_node xml_node = xml_root.append_child(node->type->name.c_str());
+
+ xml_node.append_attribute("name") = node->name.c_str();
+
+ foreach(const SocketType& socket, node->type->inputs) {
+ if(socket.type == SocketType::CLOSURE || socket.type == SocketType::UNDEFINED) {
+ continue;
+ }
+ if(socket.flags & SocketType::INTERNAL) {
+ continue;
+ }
+ if(node->has_default_value(socket)) {
+ continue;
+ }
+
+ pugi::xml_attribute attr = xml_node.append_attribute(socket.name.c_str());
+
+ switch(socket.type)
+ {
+ case SocketType::BOOLEAN:
+ {
+ attr = xml_write_boolean(node->get_bool(socket));
+ break;
+ }
+ case SocketType::BOOLEAN_ARRAY:
+ {
+ std::stringstream ss;
+ const array<bool>& value = node->get_bool_array(socket);
+ for(size_t i = 0; i < value.size(); i++) {
+ ss << xml_write_boolean(value[i]);
+ if(i != value.size() - 1)
+ ss << " ";
+ }
+ attr = ss.str().c_str();
+ break;
+ }
+ case SocketType::FLOAT:
+ {
+ attr = (double)node->get_float(socket);
+ break;
+ }
+ case SocketType::FLOAT_ARRAY:
+ {
+ std::stringstream ss;
+ const array<float>& value = node->get_float_array(socket);
+ for(size_t i = 0; i < value.size(); i++) {
+ ss << value[i];
+ if(i != value.size() - 1) {
+ ss << " ";
+ }
+ }
+ attr = ss.str().c_str();
+ break;
+ }
+ case SocketType::INT:
+ {
+ attr = node->get_int(socket);
+ break;
+ }
+ case SocketType::UINT:
+ {
+ attr = node->get_uint(socket);
+ break;
+ }
+ case SocketType::INT_ARRAY:
+ {
+ std::stringstream ss;
+ const array<int>& value = node->get_int_array(socket);
+ for(size_t i = 0; i < value.size(); i++) {
+ ss << value[i];
+ if(i != value.size() - 1) {
+ ss << " ";
+ }
+ }
+ attr = ss.str().c_str();
+ break;
+ }
+ case SocketType::COLOR:
+ case SocketType::VECTOR:
+ case SocketType::POINT:
+ case SocketType::NORMAL:
+ {
+ float3 value = node->get_float3(socket);
+ attr = string_printf("%g %g %g", (double)value.x, (double)value.y, (double)value.z).c_str();
+ break;
+ }
+ case SocketType::COLOR_ARRAY:
+ case SocketType::VECTOR_ARRAY:
+ case SocketType::POINT_ARRAY:
+ case SocketType::NORMAL_ARRAY:
+ {
+ std::stringstream ss;
+ const array<float3>& value = node->get_float3_array(socket);
+ for(size_t i = 0; i < value.size(); i++) {
+ ss << string_printf("%g %g %g", (double)value[i].x, (double)value[i].y, (double)value[i].z);
+ if(i != value.size() - 1) {
+ ss << " ";
+ }
+ }
+ attr = ss.str().c_str();
+ break;
+ }
+ case SocketType::POINT2:
+ {
+ float2 value = node->get_float2(socket);
+ attr = string_printf("%g %g", (double)value.x, (double)value.y).c_str();
+ break;
+ }
+ case SocketType::POINT2_ARRAY:
+ {
+ std::stringstream ss;
+ const array<float2>& value = node->get_float2_array(socket);
+ for(size_t i = 0; i < value.size(); i++) {
+ ss << string_printf("%g %g", (double)value[i].x, (double)value[i].y);
+ if(i != value.size() - 1) {
+ ss << " ";
+ }
+ }
+ attr = ss.str().c_str();
+ break;
+ }
+ case SocketType::STRING:
+ case SocketType::ENUM:
+ {
+ attr = node->get_string(socket).c_str();
+ break;
+ }
+ case SocketType::STRING_ARRAY:
+ {
+ std::stringstream ss;
+ const array<ustring>& value = node->get_string_array(socket);
+ for(size_t i = 0; i < value.size(); i++) {
+ ss << value[i];
+ if(i != value.size() - 1) {
+ ss << " ";
+ }
+ }
+ attr = ss.str().c_str();
+ break;
+ }
+ case SocketType::TRANSFORM:
+ {
+ Transform tfm = node->get_transform(socket);
+ std::stringstream ss;
+ for(int i = 0; i < 4; i++) {
+ ss << string_printf("%g %g %g %g", (double)tfm[i][0], (double)tfm[i][1], (double)tfm[i][2], (double)tfm[i][3]);
+ if(i != 3) {
+ ss << " ";
+ }
+ }
+ attr = ss.str().c_str();
+ break;
+ }
+ case SocketType::TRANSFORM_ARRAY:
+ {
+ std::stringstream ss;
+ const array<Transform>& value = node->get_transform_array(socket);
+ for(size_t j = 0; j < value.size(); j++) {
+ const Transform& tfm = value[j];
+
+ for(int i = 0; i < 4; i++) {
+ ss << string_printf("%g %g %g %g", (double)tfm[i][0], (double)tfm[i][1], (double)tfm[i][2], (double)tfm[i][3]);
+ if(j != value.size() - 1 || i != 3) {
+ ss << " ";
+ }
+ }
+ }
+ attr = ss.str().c_str();
+ break;
+ }
+ case SocketType::NODE:
+ {
+ Node *value = node->get_node(socket);
+ if(value) {
+ attr = value->name.c_str();
+ }
+ break;
+ }
+ case SocketType::NODE_ARRAY:
+ {
+ std::stringstream ss;
+ const array<Node*>& value = node->get_node_array(socket);
+ for(size_t i = 0; i < value.size(); i++) {
+ if(value[i]) {
+ ss << value[i]->name.c_str();
+ }
+ if(i != value.size() - 1) {
+ ss << " ";
+ }
+ }
+ attr = ss.str().c_str();
+ break;
+ }
+ case SocketType::CLOSURE:
+ case SocketType::UNDEFINED:
+ break;
+ }
+ }
+
+ return xml_node;
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/graph/node_xml.h b/intern/cycles/graph/node_xml.h
new file mode 100644
index 00000000000..7494c5e6e55
--- /dev/null
+++ b/intern/cycles/graph/node_xml.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "node.h"
+
+#include "util_map.h"
+#include "util_string.h"
+#include "util_xml.h"
+
+CCL_NAMESPACE_BEGIN
+
+struct XMLReader {
+ map<ustring, Node*> node_map;
+};
+
+void xml_read_node(XMLReader& reader, Node *node, pugi::xml_node xml_node);
+pugi::xml_node xml_write_node(Node *node, pugi::xml_node xml_root);
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index a54944b6b0e..7a9b8280ca9 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -28,6 +28,23 @@ set(SRC
kernels/cuda/kernel.cu
)
+set(SRC_BVH_HEADERS
+ bvh/bvh.h
+ bvh/bvh_nodes.h
+ bvh/bvh_shadow_all.h
+ bvh/bvh_subsurface.h
+ bvh/bvh_traversal.h
+ bvh/bvh_types.h
+ bvh/bvh_volume.h
+ bvh/bvh_volume_all.h
+ bvh/qbvh_nodes.h
+ bvh/qbvh_shadow_all.h
+ bvh/qbvh_subsurface.h
+ bvh/qbvh_traversal.h
+ bvh/qbvh_volume.h
+ bvh/qbvh_volume_all.h
+)
+
set(SRC_HEADERS
kernel_accumulate.h
kernel_bake.h
@@ -40,6 +57,7 @@ set(SRC_HEADERS
kernel_emission.h
kernel_film.h
kernel_globals.h
+ kernel_image_opencl.h
kernel_jitter.h
kernel_light.h
kernel_math.h
@@ -67,14 +85,18 @@ set(SRC_KERNELS_CPU_HEADERS
kernel.h
kernels/cpu/kernel_cpu.h
kernels/cpu/kernel_cpu_impl.h
+ kernels/cpu/kernel_cpu_image.h
)
set(SRC_CLOSURE_HEADERS
+ closure/alloc.h
closure/bsdf.h
closure/bsdf_ashikhmin_velvet.h
closure/bsdf_diffuse.h
closure/bsdf_diffuse_ramp.h
closure/bsdf_microfacet.h
+ closure/bsdf_microfacet_multi.h
+ closure/bsdf_microfacet_multi_impl.h
closure/bsdf_oren_nayar.h
closure/bsdf_phong_ramp.h
closure/bsdf_reflection.h
@@ -93,10 +115,12 @@ set(SRC_SVM_HEADERS
svm/svm.h
svm/svm_attribute.h
svm/svm_blackbody.h
+ svm/svm_bump.h
svm/svm_camera.h
svm/svm_closure.h
svm/svm_convert.h
svm/svm_checker.h
+ svm/svm_color_util.h
svm/svm_brick.h
svm/svm_displace.h
svm/svm_fresnel.h
@@ -121,6 +145,7 @@ set(SRC_SVM_HEADERS
svm/svm_normal.h
svm/svm_openvdb.h
svm/svm_ramp.h
+ svm/svm_ramp_util.h
svm/svm_sepcomb_hsv.h
svm/svm_sepcomb_vector.h
svm/svm_sky.h
@@ -137,23 +162,13 @@ set(SRC_SVM_HEADERS
set(SRC_GEOM_HEADERS
geom/geom.h
geom/geom_attribute.h
- geom/geom_bvh.h
- geom/geom_bvh_shadow.h
- geom/geom_bvh_subsurface.h
- geom/geom_bvh_traversal.h
- geom/geom_bvh_volume.h
- geom/geom_bvh_volume_all.h
geom/geom_curve.h
geom/geom_motion_curve.h
geom/geom_motion_triangle.h
geom/geom_object.h
+ geom/geom_patch.h
geom/geom_primitive.h
- geom/geom_qbvh.h
- geom/geom_qbvh_shadow.h
- geom/geom_qbvh_subsurface.h
- geom/geom_qbvh_traversal.h
- geom/geom_qbvh_volume.h
- geom/geom_qbvh_volume_all.h
+ geom/geom_subd_triangle.h
geom/geom_triangle.h
geom/geom_triangle_intersect.h
geom/geom_volume.h
@@ -165,6 +180,7 @@ set(SRC_UTIL_HEADERS
../util/util_half.h
../util/util_math.h
../util/util_math_fast.h
+ ../util/util_static_assert.h
../util/util_transform.h
../util/util_texture.h
../util/util_types.h
@@ -201,15 +217,22 @@ if(WITH_CYCLES_CUDA_BINARIES)
set(CUDA_VERSION "${CUDA_VERSION_MAJOR}${CUDA_VERSION_MINOR}")
# warn for other versions
- if(CUDA_VERSION MATCHES "75")
+ if(CUDA_VERSION MATCHES "80")
else()
message(WARNING
"CUDA version ${CUDA_VERSION_MAJOR}.${CUDA_VERSION_MINOR} detected, "
- "build may succeed but only CUDA 7.5 is officially supported")
+ "build may succeed but only CUDA 8.0 is officially supported")
endif()
# build for each arch
- set(cuda_sources kernels/cuda/kernel.cu ${SRC_HEADERS} ${SRC_SVM_HEADERS} ${SRC_GEOM_HEADERS} ${SRC_CLOSURE_HEADERS} ${SRC_UTIL_HEADERS})
+ set(cuda_sources kernels/cuda/kernel.cu
+ ${SRC_HEADERS}
+ ${SRC_BVH_HEADERS}
+ ${SRC_SVM_HEADERS}
+ ${SRC_GEOM_HEADERS}
+ ${SRC_CLOSURE_HEADERS}
+ ${SRC_UTIL_HEADERS}
+ )
set(cuda_cubins)
macro(CYCLES_CUDA_KERNEL_ADD arch experimental)
@@ -227,13 +250,17 @@ if(WITH_CYCLES_CUDA_BINARIES)
set(cuda_debug_flags "")
endif()
- set(cuda_version_flags "-D__KERNEL_CUDA_VERSION__=${CUDA_VERSION}")
+ set(cuda_nvcc_command ${CUDA_NVCC_EXECUTABLE})
+ set(cuda_nvcc_version ${CUDA_VERSION})
+
+ set(cuda_version_flags "-D__KERNEL_CUDA_VERSION__=${cuda_nvcc_version}")
set(cuda_math_flags "--use_fast_math")
add_custom_command(
OUTPUT ${cuda_cubin}
- COMMAND ${CUDA_NVCC_EXECUTABLE}
+ COMMAND ${cuda_nvcc_command}
-arch=${arch}
+ ${CUDA_NVCC_FLAGS}
-m${CUDA_BITS}
--cubin ${CMAKE_CURRENT_SOURCE_DIR}/kernels/cuda/kernel.cu
-o ${CMAKE_CURRENT_BINARY_DIR}/${cuda_cubin}
@@ -248,7 +275,6 @@ if(WITH_CYCLES_CUDA_BINARIES)
-DCCL_NAMESPACE_BEGIN=
-DCCL_NAMESPACE_END=
-DNVCC
-
DEPENDS ${cuda_sources})
delayed_install("${CMAKE_CURRENT_BINARY_DIR}" "${cuda_cubin}" ${CYCLES_INSTALL_PATH}/lib)
@@ -256,6 +282,9 @@ if(WITH_CYCLES_CUDA_BINARIES)
unset(cuda_extra_flags)
unset(cuda_debug_flags)
+
+ unset(cuda_nvcc_command)
+ unset(cuda_nvcc_version)
endmacro()
foreach(arch ${CYCLES_CUDA_BINARIES_ARCH})
@@ -308,6 +337,7 @@ add_library(cycles_kernel
${SRC}
${SRC_HEADERS}
${SRC_KERNELS_CPU_HEADERS}
+ ${SRC_BVH_HEADERS}
${SRC_CLOSURE_HEADERS}
${SRC_SVM_HEADERS}
${SRC_GEOM_HEADERS}
@@ -342,6 +372,7 @@ delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_next_iteratio
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_sum_all_radiance.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/cuda/kernel.cu" ${CYCLES_INSTALL_PATH}/kernel/kernels/cuda)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_BVH_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel/bvh)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_CLOSURE_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel/closure)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_SVM_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel/svm)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_GEOM_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel/geom)
diff --git a/intern/cycles/kernel/geom/geom_bvh.h b/intern/cycles/kernel/bvh/bvh.h
index 9eadc97386c..36798982653 100644
--- a/intern/cycles/kernel/geom/geom_bvh.h
+++ b/intern/cycles/kernel/bvh/bvh.h
@@ -1,6 +1,5 @@
/*
- * Adapted from code Copyright 2009-2010 NVIDIA Corporation
- * Modifications Copyright 2011, Blender Foundation.
+ * Copyright 2011-2013 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,154 +27,139 @@
CCL_NAMESPACE_BEGIN
-/* Don't inline intersect functions on GPU, this is faster */
-#ifdef __KERNEL_GPU__
-# define ccl_device_intersect ccl_device_noinline
-#else
-# define ccl_device_intersect ccl_device_inline
-#endif
-
-/* BVH intersection function variations */
-
-#define BVH_INSTANCING 1
-#define BVH_MOTION 2
-#define BVH_HAIR 4
-#define BVH_HAIR_MINIMUM_WIDTH 8
-
-#define BVH_NAME_JOIN(x,y) x ## _ ## y
-#define BVH_NAME_EVAL(x,y) BVH_NAME_JOIN(x,y)
-#define BVH_FUNCTION_FULL_NAME(prefix) BVH_NAME_EVAL(prefix, BVH_FUNCTION_NAME)
-
-#define BVH_FEATURE(f) (((BVH_FUNCTION_FEATURES) & (f)) != 0)
+#include "bvh_types.h"
/* Common QBVH functions. */
#ifdef __QBVH__
-# include "geom_qbvh.h"
+# include "qbvh_nodes.h"
#endif
/* Regular BVH traversal */
+#include "bvh_nodes.h"
+
#define BVH_FUNCTION_NAME bvh_intersect
#define BVH_FUNCTION_FEATURES 0
-#include "geom_bvh_traversal.h"
+#include "bvh_traversal.h"
#if defined(__INSTANCING__)
# define BVH_FUNCTION_NAME bvh_intersect_instancing
# define BVH_FUNCTION_FEATURES BVH_INSTANCING
-# include "geom_bvh_traversal.h"
+# include "bvh_traversal.h"
#endif
#if defined(__HAIR__)
# define BVH_FUNCTION_NAME bvh_intersect_hair
# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_HAIR_MINIMUM_WIDTH
-# include "geom_bvh_traversal.h"
+# include "bvh_traversal.h"
#endif
#if defined(__OBJECT_MOTION__)
# define BVH_FUNCTION_NAME bvh_intersect_motion
# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION
-# include "geom_bvh_traversal.h"
+# include "bvh_traversal.h"
#endif
#if defined(__HAIR__) && defined(__OBJECT_MOTION__)
# define BVH_FUNCTION_NAME bvh_intersect_hair_motion
# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_HAIR_MINIMUM_WIDTH|BVH_MOTION
-# include "geom_bvh_traversal.h"
+# include "bvh_traversal.h"
#endif
/* Subsurface scattering BVH traversal */
#if defined(__SUBSURFACE__)
# define BVH_FUNCTION_NAME bvh_intersect_subsurface
-# define BVH_FUNCTION_FEATURES 0
-# include "geom_bvh_subsurface.h"
-#endif
+# define BVH_FUNCTION_FEATURES BVH_HAIR
+# include "bvh_subsurface.h"
-#if defined(__SUBSURFACE__) && defined(__OBJECT_MOTION__)
-# define BVH_FUNCTION_NAME bvh_intersect_subsurface_motion
-# define BVH_FUNCTION_FEATURES BVH_MOTION
-# include "geom_bvh_subsurface.h"
-#endif
+# if defined(__OBJECT_MOTION__)
+# define BVH_FUNCTION_NAME bvh_intersect_subsurface_motion
+# define BVH_FUNCTION_FEATURES BVH_MOTION|BVH_HAIR
+# include "bvh_subsurface.h"
+# endif
+#endif /* __SUBSURFACE__ */
/* Volume BVH traversal */
#if defined(__VOLUME__)
# define BVH_FUNCTION_NAME bvh_intersect_volume
-# define BVH_FUNCTION_FEATURES 0
-# include "geom_bvh_volume.h"
-#endif
-
-#if defined(__VOLUME__) && defined(__INSTANCING__)
-# define BVH_FUNCTION_NAME bvh_intersect_volume_instancing
-# define BVH_FUNCTION_FEATURES BVH_INSTANCING
-# include "geom_bvh_volume.h"
-#endif
-
-#if defined(__VOLUME__) && defined(__OBJECT_MOTION__)
-# define BVH_FUNCTION_NAME bvh_intersect_volume_motion
-# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION
-# include "geom_bvh_volume.h"
-#endif
+# define BVH_FUNCTION_FEATURES BVH_HAIR
+# include "bvh_volume.h"
+
+# if defined(__INSTANCING__)
+# define BVH_FUNCTION_NAME bvh_intersect_volume_instancing
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR
+# include "bvh_volume.h"
+# endif
+
+# if defined(__OBJECT_MOTION__)
+# define BVH_FUNCTION_NAME bvh_intersect_volume_motion
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION|BVH_HAIR
+# include "bvh_volume.h"
+# endif
+#endif /* __VOLUME__ */
/* Record all intersections - Shadow BVH traversal */
#if defined(__SHADOW_RECORD_ALL__)
# define BVH_FUNCTION_NAME bvh_intersect_shadow_all
# define BVH_FUNCTION_FEATURES 0
-# include "geom_bvh_shadow.h"
-#endif
-
-#if defined(__SHADOW_RECORD_ALL__) && defined(__INSTANCING__)
-# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_instancing
-# define BVH_FUNCTION_FEATURES BVH_INSTANCING
-# include "geom_bvh_shadow.h"
-#endif
-
-#if defined(__SHADOW_RECORD_ALL__) && defined(__HAIR__)
-# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair
-# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR
-# include "geom_bvh_shadow.h"
-#endif
-
-#if defined(__SHADOW_RECORD_ALL__) && defined(__OBJECT_MOTION__)
-# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_motion
-# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION
-# include "geom_bvh_shadow.h"
-#endif
-
-#if defined(__SHADOW_RECORD_ALL__) && defined(__HAIR__) && defined(__OBJECT_MOTION__)
-# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair_motion
-# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_MOTION
-# include "geom_bvh_shadow.h"
-#endif
+# include "bvh_shadow_all.h"
+
+# if defined(__INSTANCING__)
+# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_instancing
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING
+# include "bvh_shadow_all.h"
+# endif
+
+# if defined(__HAIR__)
+# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR
+# include "bvh_shadow_all.h"
+# endif
+
+# if defined(__OBJECT_MOTION__)
+# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_motion
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION
+# include "bvh_shadow_all.h"
+# endif
+
+# if defined(__HAIR__) && defined(__OBJECT_MOTION__)
+# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair_motion
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_MOTION
+# include "bvh_shadow_all.h"
+# endif
+#endif /* __SHADOW_RECORD_ALL__ */
/* Record all intersections - Volume BVH traversal */
#if defined(__VOLUME_RECORD_ALL__)
# define BVH_FUNCTION_NAME bvh_intersect_volume_all
-# define BVH_FUNCTION_FEATURES 0
-# include "geom_bvh_volume_all.h"
-#endif
-
-#if defined(__VOLUME_RECORD_ALL__) && defined(__INSTANCING__)
-# define BVH_FUNCTION_NAME bvh_intersect_volume_all_instancing
-# define BVH_FUNCTION_FEATURES BVH_INSTANCING
-# include "geom_bvh_volume_all.h"
-#endif
-
-#if defined(__VOLUME_RECORD_ALL__) && defined(__OBJECT_MOTION__)
-# define BVH_FUNCTION_NAME bvh_intersect_volume_all_motion
-# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION
-# include "geom_bvh_volume_all.h"
-#endif
+# define BVH_FUNCTION_FEATURES BVH_HAIR
+# include "bvh_volume_all.h"
+
+# if defined(__INSTANCING__)
+# define BVH_FUNCTION_NAME bvh_intersect_volume_all_instancing
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR
+# include "bvh_volume_all.h"
+# endif
+
+# if defined(__OBJECT_MOTION__)
+# define BVH_FUNCTION_NAME bvh_intersect_volume_all_motion
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION|BVH_HAIR
+# include "bvh_volume_all.h"
+# endif
+#endif /* __VOLUME_RECORD_ALL__ */
#undef BVH_FEATURE
#undef BVH_NAME_JOIN
#undef BVH_NAME_EVAL
#undef BVH_FUNCTION_FULL_NAME
+/* Note: ray is passed by value to work around a possible CUDA compiler bug. */
ccl_device_intersect bool scene_intersect(KernelGlobals *kg,
- const Ray *ray,
+ const Ray ray,
const uint visibility,
Intersection *isect,
uint *lcg_state,
@@ -186,32 +170,32 @@ ccl_device_intersect bool scene_intersect(KernelGlobals *kg,
if(kernel_data.bvh.have_motion) {
# ifdef __HAIR__
if(kernel_data.bvh.have_curves)
- return bvh_intersect_hair_motion(kg, ray, isect, visibility, lcg_state, difl, extmax);
+ return bvh_intersect_hair_motion(kg, &ray, isect, visibility, lcg_state, difl, extmax);
# endif /* __HAIR__ */
- return bvh_intersect_motion(kg, ray, isect, visibility);
+ return bvh_intersect_motion(kg, &ray, isect, visibility);
}
#endif /* __OBJECT_MOTION__ */
#ifdef __HAIR__
if(kernel_data.bvh.have_curves)
- return bvh_intersect_hair(kg, ray, isect, visibility, lcg_state, difl, extmax);
+ return bvh_intersect_hair(kg, &ray, isect, visibility, lcg_state, difl, extmax);
#endif /* __HAIR__ */
#ifdef __KERNEL_CPU__
# ifdef __INSTANCING__
if(kernel_data.bvh.have_instancing)
- return bvh_intersect_instancing(kg, ray, isect, visibility);
+ return bvh_intersect_instancing(kg, &ray, isect, visibility);
# endif /* __INSTANCING__ */
- return bvh_intersect(kg, ray, isect, visibility);
+ return bvh_intersect(kg, &ray, isect, visibility);
#else /* __KERNEL_CPU__ */
# ifdef __INSTANCING__
- return bvh_intersect_instancing(kg, ray, isect, visibility);
+ return bvh_intersect_instancing(kg, &ray, isect, visibility);
# else
- return bvh_intersect(kg, ray, isect, visibility);
+ return bvh_intersect(kg, &ray, isect, visibility);
# endif /* __INSTANCING__ */
#endif /* __KERNEL_CPU__ */
diff --git a/intern/cycles/kernel/bvh/bvh_nodes.h b/intern/cycles/kernel/bvh/bvh_nodes.h
new file mode 100644
index 00000000000..726bef1794c
--- /dev/null
+++ b/intern/cycles/kernel/bvh/bvh_nodes.h
@@ -0,0 +1,656 @@
+/*
+ * Copyright 2011-2016, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TODO(sergey): Look into avoid use of full Transform and use 3x3 matrix and
+// 3-vector which might be faster.
+ccl_device_forceinline Transform bvh_unaligned_node_fetch_space(KernelGlobals *kg,
+ int node_addr,
+ int child)
+{
+ Transform space;
+ const int child_addr = node_addr + child * 3;
+ space.x = kernel_tex_fetch(__bvh_nodes, child_addr+1);
+ space.y = kernel_tex_fetch(__bvh_nodes, child_addr+2);
+ space.z = kernel_tex_fetch(__bvh_nodes, child_addr+3);
+ space.w = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
+ return space;
+}
+
+#if !defined(__KERNEL_SSE2__)
+ccl_device_forceinline int bvh_aligned_node_intersect(KernelGlobals *kg,
+ const float3 P,
+ const float3 idir,
+ const float t,
+ const int node_addr,
+ const uint visibility,
+ float dist[2])
+{
+
+ /* fetch node data */
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
+ float4 node0 = kernel_tex_fetch(__bvh_nodes, node_addr+1);
+ float4 node1 = kernel_tex_fetch(__bvh_nodes, node_addr+2);
+ float4 node2 = kernel_tex_fetch(__bvh_nodes, node_addr+3);
+
+ /* intersect ray against child nodes */
+ float c0lox = (node0.x - P.x) * idir.x;
+ float c0hix = (node0.z - P.x) * idir.x;
+ float c0loy = (node1.x - P.y) * idir.y;
+ float c0hiy = (node1.z - P.y) * idir.y;
+ float c0loz = (node2.x - P.z) * idir.z;
+ float c0hiz = (node2.z - P.z) * idir.z;
+ float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f);
+ float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t);
+
+ float c1lox = (node0.y - P.x) * idir.x;
+ float c1hix = (node0.w - P.x) * idir.x;
+ float c1loy = (node1.y - P.y) * idir.y;
+ float c1hiy = (node1.w - P.y) * idir.y;
+ float c1loz = (node2.y - P.z) * idir.z;
+ float c1hiz = (node2.w - P.z) * idir.z;
+ float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f);
+ float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t);
+
+ dist[0] = c0min;
+ dist[1] = c1min;
+
+#ifdef __VISIBILITY_FLAG__
+ /* this visibility test gives a 5% performance hit, how to solve? */
+ return (((c0max >= c0min) && (__float_as_uint(cnodes.x) & visibility))? 1: 0) |
+ (((c1max >= c1min) && (__float_as_uint(cnodes.y) & visibility))? 2: 0);
+#else
+ return ((c0max >= c0min)? 1: 0) |
+ ((c1max >= c1min)? 2: 0);
+#endif
+}
+
+ccl_device_forceinline int bvh_aligned_node_intersect_robust(KernelGlobals *kg,
+ const float3 P,
+ const float3 idir,
+ const float t,
+ const float difl,
+ const float extmax,
+ const int node_addr,
+ const uint visibility,
+ float dist[2])
+{
+
+ /* fetch node data */
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
+ float4 node0 = kernel_tex_fetch(__bvh_nodes, node_addr+1);
+ float4 node1 = kernel_tex_fetch(__bvh_nodes, node_addr+2);
+ float4 node2 = kernel_tex_fetch(__bvh_nodes, node_addr+3);
+
+ /* intersect ray against child nodes */
+ float c0lox = (node0.x - P.x) * idir.x;
+ float c0hix = (node0.z - P.x) * idir.x;
+ float c0loy = (node1.x - P.y) * idir.y;
+ float c0hiy = (node1.z - P.y) * idir.y;
+ float c0loz = (node2.x - P.z) * idir.z;
+ float c0hiz = (node2.z - P.z) * idir.z;
+ float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f);
+ float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t);
+
+ float c1lox = (node0.y - P.x) * idir.x;
+ float c1hix = (node0.w - P.x) * idir.x;
+ float c1loy = (node1.y - P.y) * idir.y;
+ float c1hiy = (node1.w - P.y) * idir.y;
+ float c1loz = (node2.y - P.z) * idir.z;
+ float c1hiz = (node2.w - P.z) * idir.z;
+ float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f);
+ float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t);
+
+ if(difl != 0.0f) {
+ float hdiff = 1.0f + difl;
+ float ldiff = 1.0f - difl;
+ if(__float_as_int(cnodes.z) & PATH_RAY_CURVE) {
+ c0min = max(ldiff * c0min, c0min - extmax);
+ c0max = min(hdiff * c0max, c0max + extmax);
+ }
+ if(__float_as_int(cnodes.w) & PATH_RAY_CURVE) {
+ c1min = max(ldiff * c1min, c1min - extmax);
+ c1max = min(hdiff * c1max, c1max + extmax);
+ }
+ }
+
+ dist[0] = c0min;
+ dist[1] = c1min;
+
+#ifdef __VISIBILITY_FLAG__
+ /* this visibility test gives a 5% performance hit, how to solve? */
+ return (((c0max >= c0min) && (__float_as_uint(cnodes.x) & visibility))? 1: 0) |
+ (((c1max >= c1min) && (__float_as_uint(cnodes.y) & visibility))? 2: 0);
+#else
+ return ((c0max >= c0min)? 1: 0) |
+ ((c1max >= c1min)? 2: 0);
+#endif
+}
+
+ccl_device_forceinline bool bvh_unaligned_node_intersect_child(
+ KernelGlobals *kg,
+ const float3 P,
+ const float3 dir,
+ const float t,
+ int node_addr,
+ int child,
+ float dist[2])
+{
+ Transform space = bvh_unaligned_node_fetch_space(kg, node_addr, child);
+ float3 aligned_dir = transform_direction(&space, dir);
+ float3 aligned_P = transform_point(&space, P);
+ float3 nrdir = -bvh_inverse_direction(aligned_dir);
+ float3 lower_xyz = aligned_P * nrdir;
+ float3 upper_xyz = lower_xyz - nrdir;
+ const float near_x = min(lower_xyz.x, upper_xyz.x);
+ const float near_y = min(lower_xyz.y, upper_xyz.y);
+ const float near_z = min(lower_xyz.z, upper_xyz.z);
+ const float far_x = max(lower_xyz.x, upper_xyz.x);
+ const float far_y = max(lower_xyz.y, upper_xyz.y);
+ const float far_z = max(lower_xyz.z, upper_xyz.z);
+ const float tnear = max4(0.0f, near_x, near_y, near_z);
+ const float tfar = min4(t, far_x, far_y, far_z);
+ *dist = tnear;
+ return tnear <= tfar;
+}
+
+ccl_device_forceinline bool bvh_unaligned_node_intersect_child_robust(
+ KernelGlobals *kg,
+ const float3 P,
+ const float3 dir,
+ const float t,
+ const float difl,
+ int node_addr,
+ int child,
+ float dist[2])
+{
+ Transform space = bvh_unaligned_node_fetch_space(kg, node_addr, child);
+ float3 aligned_dir = transform_direction(&space, dir);
+ float3 aligned_P = transform_point(&space, P);
+ float3 nrdir = -bvh_inverse_direction(aligned_dir);
+ float3 tLowerXYZ = aligned_P * nrdir;
+ float3 tUpperXYZ = tLowerXYZ - nrdir;
+ const float near_x = min(tLowerXYZ.x, tUpperXYZ.x);
+ const float near_y = min(tLowerXYZ.y, tUpperXYZ.y);
+ const float near_z = min(tLowerXYZ.z, tUpperXYZ.z);
+ const float far_x = max(tLowerXYZ.x, tUpperXYZ.x);
+ const float far_y = max(tLowerXYZ.y, tUpperXYZ.y);
+ const float far_z = max(tLowerXYZ.z, tUpperXYZ.z);
+ const float tnear = max4(0.0f, near_x, near_y, near_z);
+ const float tfar = min4(t, far_x, far_y, far_z);
+ *dist = tnear;
+ if(difl != 0.0f) {
+ /* TODO(sergey): Same as for QBVH, needs a proper use. */
+ const float round_down = 1.0f - difl;
+ const float round_up = 1.0f + difl;
+ return round_down*tnear <= round_up*tfar;
+ }
+ else {
+ return tnear <= tfar;
+ }
+}
+
+ccl_device_forceinline int bvh_unaligned_node_intersect(KernelGlobals *kg,
+ const float3 P,
+ const float3 dir,
+ const float3 idir,
+ const float t,
+ const int node_addr,
+ const uint visibility,
+ float dist[2])
+{
+ int mask = 0;
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
+ if(bvh_unaligned_node_intersect_child(kg, P, dir, t, node_addr, 0, &dist[0])) {
+#ifdef __VISIBILITY_FLAG__
+ if((__float_as_uint(cnodes.x) & visibility))
+#endif
+ {
+ mask |= 1;
+ }
+ }
+ if(bvh_unaligned_node_intersect_child(kg, P, dir, t, node_addr, 1, &dist[1])) {
+#ifdef __VISIBILITY_FLAG__
+ if((__float_as_uint(cnodes.y) & visibility))
+#endif
+ {
+ mask |= 2;
+ }
+ }
+ return mask;
+}
+
+ccl_device_forceinline int bvh_unaligned_node_intersect_robust(KernelGlobals *kg,
+ const float3 P,
+ const float3 dir,
+ const float3 idir,
+ const float t,
+ const float difl,
+ const float extmax,
+ const int node_addr,
+ const uint visibility,
+ float dist[2])
+{
+ int mask = 0;
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
+ if(bvh_unaligned_node_intersect_child_robust(kg, P, dir, t, difl, node_addr, 0, &dist[0])) {
+#ifdef __VISIBILITY_FLAG__
+ if((__float_as_uint(cnodes.x) & visibility))
+#endif
+ {
+ mask |= 1;
+ }
+ }
+ if(bvh_unaligned_node_intersect_child_robust(kg, P, dir, t, difl, node_addr, 1, &dist[1])) {
+#ifdef __VISIBILITY_FLAG__
+ if((__float_as_uint(cnodes.y) & visibility))
+#endif
+ {
+ mask |= 2;
+ }
+ }
+ return mask;
+}
+
+ccl_device_forceinline int bvh_node_intersect(KernelGlobals *kg,
+ const float3 P,
+ const float3 dir,
+ const float3 idir,
+ const float t,
+ const int node_addr,
+ const uint visibility,
+ float dist[2])
+{
+ float4 node = kernel_tex_fetch(__bvh_nodes, node_addr);
+ if(__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) {
+ return bvh_unaligned_node_intersect(kg,
+ P,
+ dir,
+ idir,
+ t,
+ node_addr,
+ visibility,
+ dist);
+ }
+ else {
+ return bvh_aligned_node_intersect(kg,
+ P,
+ idir,
+ t,
+ node_addr,
+ visibility,
+ dist);
+ }
+}
+
+ccl_device_forceinline int bvh_node_intersect_robust(KernelGlobals *kg,
+ const float3 P,
+ const float3 dir,
+ const float3 idir,
+ const float t,
+ const float difl,
+ const float extmax,
+ const int node_addr,
+ const uint visibility,
+ float dist[2])
+{
+ float4 node = kernel_tex_fetch(__bvh_nodes, node_addr);
+ if(__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) {
+ return bvh_unaligned_node_intersect_robust(kg,
+ P,
+ dir,
+ idir,
+ t,
+ difl,
+ extmax,
+ node_addr,
+ visibility,
+ dist);
+ }
+ else {
+ return bvh_aligned_node_intersect_robust(kg,
+ P,
+ idir,
+ t,
+ difl,
+ extmax,
+ node_addr,
+ visibility,
+ dist);
+ }
+}
+#else /* !defined(__KERNEL_SSE2__) */
+
+int ccl_device_forceinline bvh_aligned_node_intersect(
+ KernelGlobals *kg,
+ const float3& P,
+ const float3& dir,
+ const ssef& tsplat,
+ const ssef Psplat[3],
+ const ssef idirsplat[3],
+ const shuffle_swap_t shufflexyz[3],
+ const int node_addr,
+ const uint visibility,
+ float dist[2])
+{
+ /* Intersect two child bounding boxes, SSE3 version adapted from Embree */
+ const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000));
+
+ /* fetch node data */
+ const ssef *bvh_nodes = (ssef*)kg->__bvh_nodes.data + node_addr;
+
+ /* intersect ray against child nodes */
+ const ssef tminmaxx = (shuffle_swap(bvh_nodes[1], shufflexyz[0]) - Psplat[0]) * idirsplat[0];
+ const ssef tminmaxy = (shuffle_swap(bvh_nodes[2], shufflexyz[1]) - Psplat[1]) * idirsplat[1];
+ const ssef tminmaxz = (shuffle_swap(bvh_nodes[3], shufflexyz[2]) - Psplat[2]) * idirsplat[2];
+
+ /* calculate { c0min, c1min, -c0max, -c1max} */
+ ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat));
+ const ssef tminmax = minmax ^ pn;
+ const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax);
+
+ dist[0] = tminmax[0];
+ dist[1] = tminmax[1];
+
+ int mask = movemask(lrhit);
+
+# ifdef __VISIBILITY_FLAG__
+ /* this visibility test gives a 5% performance hit, how to solve? */
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
+ int cmask = (((mask & 1) && (__float_as_uint(cnodes.x) & visibility))? 1: 0) |
+ (((mask & 2) && (__float_as_uint(cnodes.y) & visibility))? 2: 0);
+ return cmask;
+# else
+ return mask & 3;
+# endif
+}
+
+ccl_device_forceinline int bvh_aligned_node_intersect_robust(
+ KernelGlobals *kg,
+ const float3& P,
+ const float3& dir,
+ const ssef& tsplat,
+ const ssef Psplat[3],
+ const ssef idirsplat[3],
+ const shuffle_swap_t shufflexyz[3],
+ const float difl,
+ const float extmax,
+ const int nodeAddr,
+ const uint visibility,
+ float dist[2])
+{
+ /* Intersect two child bounding boxes, SSE3 version adapted from Embree */
+ const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000));
+
+ /* fetch node data */
+ const ssef *bvh_nodes = (ssef*)kg->__bvh_nodes.data + nodeAddr;
+
+ /* intersect ray against child nodes */
+ const ssef tminmaxx = (shuffle_swap(bvh_nodes[1], shufflexyz[0]) - Psplat[0]) * idirsplat[0];
+ const ssef tminmaxy = (shuffle_swap(bvh_nodes[2], shufflexyz[1]) - Psplat[1]) * idirsplat[1];
+ const ssef tminmaxz = (shuffle_swap(bvh_nodes[3], shufflexyz[2]) - Psplat[2]) * idirsplat[2];
+
+ /* calculate { c0min, c1min, -c0max, -c1max} */
+ ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat));
+ const ssef tminmax = minmax ^ pn;
+
+ if(difl != 0.0f) {
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr+0);
+ float4 *tminmaxview = (float4*)&tminmax;
+ float& c0min = tminmaxview->x, &c1min = tminmaxview->y;
+ float& c0max = tminmaxview->z, &c1max = tminmaxview->w;
+ float hdiff = 1.0f + difl;
+ float ldiff = 1.0f - difl;
+ if(__float_as_int(cnodes.x) & PATH_RAY_CURVE) {
+ c0min = max(ldiff * c0min, c0min - extmax);
+ c0max = min(hdiff * c0max, c0max + extmax);
+ }
+ if(__float_as_int(cnodes.y) & PATH_RAY_CURVE) {
+ c1min = max(ldiff * c1min, c1min - extmax);
+ c1max = min(hdiff * c1max, c1max + extmax);
+ }
+ }
+
+ const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax);
+
+ dist[0] = tminmax[0];
+ dist[1] = tminmax[1];
+
+ int mask = movemask(lrhit);
+
+# ifdef __VISIBILITY_FLAG__
+ /* this visibility test gives a 5% performance hit, how to solve? */
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr+0);
+ int cmask = (((mask & 1) && (__float_as_uint(cnodes.x) & visibility))? 1: 0) |
+ (((mask & 2) && (__float_as_uint(cnodes.y) & visibility))? 2: 0);
+ return cmask;
+# else
+ return mask & 3;
+# endif
+}
+
+ccl_device_forceinline int bvh_unaligned_node_intersect(KernelGlobals *kg,
+ const float3 P,
+ const float3 dir,
+ const ssef& isect_near,
+ const ssef& isect_far,
+ const int node_addr,
+ const uint visibility,
+ float dist[2])
+{
+ Transform space0 = bvh_unaligned_node_fetch_space(kg, node_addr, 0);
+ Transform space1 = bvh_unaligned_node_fetch_space(kg, node_addr, 1);
+
+ float3 aligned_dir0 = transform_direction(&space0, dir),
+ aligned_dir1 = transform_direction(&space1, dir);;
+ float3 aligned_P0 = transform_point(&space0, P),
+ aligned_P1 = transform_point(&space1, P);
+ float3 nrdir0 = -bvh_inverse_direction(aligned_dir0),
+ nrdir1 = -bvh_inverse_direction(aligned_dir1);
+
+ ssef lower_x = ssef(aligned_P0.x * nrdir0.x,
+ aligned_P1.x * nrdir1.x,
+ 0.0f, 0.0f),
+ lower_y = ssef(aligned_P0.y * nrdir0.y,
+ aligned_P1.y * nrdir1.y,
+ 0.0f,
+ 0.0f),
+ lower_z = ssef(aligned_P0.z * nrdir0.z,
+ aligned_P1.z * nrdir1.z,
+ 0.0f,
+ 0.0f);
+
+ ssef upper_x = lower_x - ssef(nrdir0.x, nrdir1.x, 0.0f, 0.0f),
+ upper_y = lower_y - ssef(nrdir0.y, nrdir1.y, 0.0f, 0.0f),
+ upper_z = lower_z - ssef(nrdir0.z, nrdir1.z, 0.0f, 0.0f);
+
+ ssef tnear_x = min(lower_x, upper_x);
+ ssef tnear_y = min(lower_y, upper_y);
+ ssef tnear_z = min(lower_z, upper_z);
+ ssef tfar_x = max(lower_x, upper_x);
+ ssef tfar_y = max(lower_y, upper_y);
+ ssef tfar_z = max(lower_z, upper_z);
+
+ const ssef tnear = max4(tnear_x, tnear_y, tnear_z, isect_near);
+ const ssef tfar = min4(tfar_x, tfar_y, tfar_z, isect_far);
+ sseb vmask = tnear <= tfar;
+ dist[0] = tnear.f[0];
+ dist[1] = tnear.f[1];
+
+ int mask = (int)movemask(vmask);
+
+# ifdef __VISIBILITY_FLAG__
+ /* this visibility test gives a 5% performance hit, how to solve? */
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
+ int cmask = (((mask & 1) && (__float_as_uint(cnodes.x) & visibility))? 1: 0) |
+ (((mask & 2) && (__float_as_uint(cnodes.y) & visibility))? 2: 0);
+ return cmask;
+# else
+ return mask & 3;
+# endif
+}
+
+ccl_device_forceinline int bvh_unaligned_node_intersect_robust(KernelGlobals *kg,
+ const float3 P,
+ const float3 dir,
+ const ssef& isect_near,
+ const ssef& isect_far,
+ const float difl,
+ const int node_addr,
+ const uint visibility,
+ float dist[2])
+{
+ Transform space0 = bvh_unaligned_node_fetch_space(kg, node_addr, 0);
+ Transform space1 = bvh_unaligned_node_fetch_space(kg, node_addr, 1);
+
+ float3 aligned_dir0 = transform_direction(&space0, dir),
+ aligned_dir1 = transform_direction(&space1, dir);;
+ float3 aligned_P0 = transform_point(&space0, P),
+ aligned_P1 = transform_point(&space1, P);
+ float3 nrdir0 = -bvh_inverse_direction(aligned_dir0),
+ nrdir1 = -bvh_inverse_direction(aligned_dir1);
+
+ ssef lower_x = ssef(aligned_P0.x * nrdir0.x,
+ aligned_P1.x * nrdir1.x,
+ 0.0f, 0.0f),
+ lower_y = ssef(aligned_P0.y * nrdir0.y,
+ aligned_P1.y * nrdir1.y,
+ 0.0f,
+ 0.0f),
+ lower_z = ssef(aligned_P0.z * nrdir0.z,
+ aligned_P1.z * nrdir1.z,
+ 0.0f,
+ 0.0f);
+
+ ssef upper_x = lower_x - ssef(nrdir0.x, nrdir1.x, 0.0f, 0.0f),
+ upper_y = lower_y - ssef(nrdir0.y, nrdir1.y, 0.0f, 0.0f),
+ upper_z = lower_z - ssef(nrdir0.z, nrdir1.z, 0.0f, 0.0f);
+
+ ssef tnear_x = min(lower_x, upper_x);
+ ssef tnear_y = min(lower_y, upper_y);
+ ssef tnear_z = min(lower_z, upper_z);
+ ssef tfar_x = max(lower_x, upper_x);
+ ssef tfar_y = max(lower_y, upper_y);
+ ssef tfar_z = max(lower_z, upper_z);
+
+ const ssef tnear = max4(tnear_x, tnear_y, tnear_z, isect_near);
+ const ssef tfar = min4(tfar_x, tfar_y, tfar_z, isect_far);
+ sseb vmask;
+ if(difl != 0.0f) {
+ const float round_down = 1.0f - difl;
+ const float round_up = 1.0f + difl;
+ vmask = round_down*tnear <= round_up*tfar;
+ }
+ else {
+ vmask = tnear <= tfar;
+ }
+
+ dist[0] = tnear.f[0];
+ dist[1] = tnear.f[1];
+
+ int mask = (int)movemask(vmask);
+
+# ifdef __VISIBILITY_FLAG__
+ /* this visibility test gives a 5% performance hit, how to solve? */
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
+ int cmask = (((mask & 1) && (__float_as_uint(cnodes.x) & visibility))? 1: 0) |
+ (((mask & 2) && (__float_as_uint(cnodes.y) & visibility))? 2: 0);
+ return cmask;
+# else
+ return mask & 3;
+# endif
+}
+
+ccl_device_forceinline int bvh_node_intersect(KernelGlobals *kg,
+ const float3& P,
+ const float3& dir,
+ const ssef& isect_near,
+ const ssef& isect_far,
+ const ssef& tsplat,
+ const ssef Psplat[3],
+ const ssef idirsplat[3],
+ const shuffle_swap_t shufflexyz[3],
+ const int node_addr,
+ const uint visibility,
+ float dist[2])
+{
+ float4 node = kernel_tex_fetch(__bvh_nodes, node_addr);
+ if(__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) {
+ return bvh_unaligned_node_intersect(kg,
+ P,
+ dir,
+ isect_near,
+ isect_far,
+ node_addr,
+ visibility,
+ dist);
+ }
+ else {
+ return bvh_aligned_node_intersect(kg,
+ P,
+ dir,
+ tsplat,
+ Psplat,
+ idirsplat,
+ shufflexyz,
+ node_addr,
+ visibility,
+ dist);
+ }
+}
+
+ccl_device_forceinline int bvh_node_intersect_robust(KernelGlobals *kg,
+ const float3& P,
+ const float3& dir,
+ const ssef& isect_near,
+ const ssef& isect_far,
+ const ssef& tsplat,
+ const ssef Psplat[3],
+ const ssef idirsplat[3],
+ const shuffle_swap_t shufflexyz[3],
+ const float difl,
+ const float extmax,
+ const int node_addr,
+ const uint visibility,
+ float dist[2])
+{
+ float4 node = kernel_tex_fetch(__bvh_nodes, node_addr);
+ if(__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) {
+ return bvh_unaligned_node_intersect_robust(kg,
+ P,
+ dir,
+ isect_near,
+ isect_far,
+ difl,
+ node_addr,
+ visibility,
+ dist);
+ }
+ else {
+ return bvh_aligned_node_intersect_robust(kg,
+ P,
+ dir,
+ tsplat,
+ Psplat,
+ idirsplat,
+ shufflexyz,
+ difl,
+ extmax,
+ node_addr,
+ visibility,
+ dist);
+ }
+}
+#endif /* !defined(__KERNEL_SSE2__) */
diff --git a/intern/cycles/kernel/geom/geom_bvh_shadow.h b/intern/cycles/kernel/bvh/bvh_shadow_all.h
index 4005489f77d..294362ea995 100644
--- a/intern/cycles/kernel/geom/geom_bvh_shadow.h
+++ b/intern/cycles/kernel/bvh/bvh_shadow_all.h
@@ -18,7 +18,13 @@
*/
#ifdef __QBVH__
-# include "geom_qbvh_shadow.h"
+# include "qbvh_shadow_all.h"
+#endif
+
+#if BVH_FEATURE(BVH_HAIR)
+# define NODE_INTERSECT bvh_node_intersect
+#else
+# define NODE_INTERSECT bvh_aligned_node_intersect
#endif
/* This is a template BVH traversal function, where various features can be
@@ -31,24 +37,29 @@
*
*/
-ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
- const Ray *ray,
- Intersection *isect_array,
- const uint max_hits,
- uint *num_hits)
+#ifndef __KERNEL_GPU__
+ccl_device
+#else
+ccl_device_inline
+#endif
+bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
+ const Ray *ray,
+ Intersection *isect_array,
+ const uint max_hits,
+ uint *num_hits)
{
/* todo:
* - likely and unlikely for if() statements
* - test restrict attribute for pointers
*/
-
+
/* traversal stack in CUDA thread-local memory */
- int traversalStack[BVH_STACK_SIZE];
- traversalStack[0] = ENTRYPOINT_SENTINEL;
+ int traversal_stack[BVH_STACK_SIZE];
+ traversal_stack[0] = ENTRYPOINT_SENTINEL;
/* traversal variables in registers */
- int stackPtr = 0;
- int nodeAddr = kernel_data.bvh.root;
+ int stack_ptr = 0;
+ int node_addr = kernel_data.bvh.root;
/* ray parameters in registers */
const float tmax = ray->t;
@@ -72,9 +83,12 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
#if defined(__KERNEL_SSE2__)
const shuffle_swap_t shuf_identity = shuffle_swap_identity();
const shuffle_swap_t shuf_swap = shuffle_swap_swap();
-
+
const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000));
ssef Psplat[3], idirsplat[3];
+# if BVH_FEATURE(BVH_HAIR)
+ ssef tnear(0.0f), tfar(isect_t);
+# endif
shuffle_swap_t shufflexyz[3];
Psplat[0] = ssef(P.x);
@@ -93,130 +107,87 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
do {
do {
/* traverse internal nodes */
- while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) {
- bool traverseChild0, traverseChild1;
- int nodeAddrChild1;
+ while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
+ int node_addr_child1, traverse_mask;
+ float dist[2];
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
#if !defined(__KERNEL_SSE2__)
- /* Intersect two child bounding boxes, non-SSE version */
- float t = isect_t;
-
- /* fetch node data */
- float4 node0 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+0);
- float4 node1 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+1);
- float4 node2 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+2);
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+3);
-
- /* intersect ray against child nodes */
- NO_EXTENDED_PRECISION float c0lox = (node0.x - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c0hix = (node0.z - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c0loy = (node1.x - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c0hiy = (node1.z - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c0loz = (node2.x - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c0hiz = (node2.z - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f);
- NO_EXTENDED_PRECISION float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t);
-
- NO_EXTENDED_PRECISION float c1lox = (node0.y - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c1hix = (node0.w - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c1loy = (node1.y - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c1hiy = (node1.w - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c1loz = (node2.y - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c1hiz = (node2.w - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f);
- NO_EXTENDED_PRECISION float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t);
-
- /* decide which nodes to traverse next */
-# ifdef __VISIBILITY_FLAG__
- /* this visibility test gives a 5% performance hit, how to solve? */
- traverseChild0 = (c0max >= c0min) && (__float_as_uint(cnodes.z) & PATH_RAY_SHADOW);
- traverseChild1 = (c1max >= c1min) && (__float_as_uint(cnodes.w) & PATH_RAY_SHADOW);
-# else
- traverseChild0 = (c0max >= c0min);
- traverseChild1 = (c1max >= c1min);
+ traverse_mask = NODE_INTERSECT(kg,
+ P,
+# if BVH_FEATURE(BVH_HAIR)
+ dir,
# endif
-
+ idir,
+ isect_t,
+ node_addr,
+ PATH_RAY_SHADOW,
+ dist);
#else // __KERNEL_SSE2__
- /* Intersect two child bounding boxes, SSE3 version adapted from Embree */
-
- /* fetch node data */
- const ssef *bvh_nodes = (ssef*)kg->__bvh_nodes.data + nodeAddr*BVH_NODE_SIZE;
- const float4 cnodes = ((float4*)bvh_nodes)[3];
-
- /* intersect ray against child nodes */
- const ssef tminmaxx = (shuffle_swap(bvh_nodes[0], shufflexyz[0]) - Psplat[0]) * idirsplat[0];
- const ssef tminmaxy = (shuffle_swap(bvh_nodes[1], shufflexyz[1]) - Psplat[1]) * idirsplat[1];
- const ssef tminmaxz = (shuffle_swap(bvh_nodes[2], shufflexyz[2]) - Psplat[2]) * idirsplat[2];
-
- /* calculate { c0min, c1min, -c0max, -c1max} */
- const ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat));
- const ssef tminmax = minmax ^ pn;
- const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax);
-
- /* decide which nodes to traverse next */
-# ifdef __VISIBILITY_FLAG__
- /* this visibility test gives a 5% performance hit, how to solve? */
- traverseChild0 = (movemask(lrhit) & 1) && (__float_as_uint(cnodes.z) & PATH_RAY_SHADOW);
- traverseChild1 = (movemask(lrhit) & 2) && (__float_as_uint(cnodes.w) & PATH_RAY_SHADOW);
-# else
- traverseChild0 = (movemask(lrhit) & 1);
- traverseChild1 = (movemask(lrhit) & 2);
+ traverse_mask = NODE_INTERSECT(kg,
+ P,
+ dir,
+# if BVH_FEATURE(BVH_HAIR)
+ tnear,
+ tfar,
# endif
+ tsplat,
+ Psplat,
+ idirsplat,
+ shufflexyz,
+ node_addr,
+ PATH_RAY_SHADOW,
+ dist);
#endif // __KERNEL_SSE2__
- nodeAddr = __float_as_int(cnodes.x);
- nodeAddrChild1 = __float_as_int(cnodes.y);
-
- if(traverseChild0 && traverseChild1) {
- /* both children were intersected, push the farther one */
-#if !defined(__KERNEL_SSE2__)
- bool closestChild1 = (c1min < c0min);
-#else
- bool closestChild1 = tminmax[1] < tminmax[0];
-#endif
+ node_addr = __float_as_int(cnodes.z);
+ node_addr_child1 = __float_as_int(cnodes.w);
- if(closestChild1) {
- int tmp = nodeAddr;
- nodeAddr = nodeAddrChild1;
- nodeAddrChild1 = tmp;
+ if(traverse_mask == 3) {
+ /* Both children were intersected, push the farther one. */
+ bool is_closest_child1 = (dist[1] < dist[0]);
+ if(is_closest_child1) {
+ int tmp = node_addr;
+ node_addr = node_addr_child1;
+ node_addr_child1 = tmp;
}
- ++stackPtr;
- kernel_assert(stackPtr < BVH_STACK_SIZE);
- traversalStack[stackPtr] = nodeAddrChild1;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_STACK_SIZE);
+ traversal_stack[stack_ptr] = node_addr_child1;
}
else {
- /* one child was intersected */
- if(traverseChild1) {
- nodeAddr = nodeAddrChild1;
+ /* One child was intersected. */
+ if(traverse_mask == 2) {
+ node_addr = node_addr_child1;
}
- else if(!traverseChild0) {
- /* neither child was intersected */
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
+ else if(traverse_mask == 0) {
+ /* Neither child was intersected. */
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
}
}
}
/* if node is leaf, fetch triangle list */
- if(nodeAddr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_NODE_LEAF_SIZE);
- int primAddr = __float_as_int(leaf.x);
+ if(node_addr < 0) {
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1));
+ int prim_addr = __float_as_int(leaf.x);
#if BVH_FEATURE(BVH_INSTANCING)
- if(primAddr >= 0) {
+ if(prim_addr >= 0) {
#endif
- const int primAddr2 = __float_as_int(leaf.y);
+ const int prim_addr2 = __float_as_int(leaf.y);
const uint type = __float_as_int(leaf.w);
const uint p_type = type & PRIMITIVE_ALL;
/* pop */
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
/* primitive intersection */
- while(primAddr < primAddr2) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ while(prim_addr < prim_addr2) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
bool hit;
@@ -226,22 +197,57 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
switch(p_type) {
case PRIMITIVE_TRIANGLE: {
- hit = triangle_intersect(kg, &isect_precalc, isect_array, P, PATH_RAY_SHADOW, object, primAddr);
+ hit = triangle_intersect(kg,
+ &isect_precalc,
+ isect_array,
+ P,
+ PATH_RAY_SHADOW,
+ object,
+ prim_addr);
break;
}
#if BVH_FEATURE(BVH_MOTION)
case PRIMITIVE_MOTION_TRIANGLE: {
- hit = motion_triangle_intersect(kg, isect_array, P, dir, ray->time, PATH_RAY_SHADOW, object, primAddr);
+ hit = motion_triangle_intersect(kg,
+ isect_array,
+ P,
+ dir,
+ ray->time,
+ PATH_RAY_SHADOW,
+ object,
+ prim_addr);
break;
}
#endif
#if BVH_FEATURE(BVH_HAIR)
case PRIMITIVE_CURVE:
case PRIMITIVE_MOTION_CURVE: {
- if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE)
- hit = bvh_cardinal_curve_intersect(kg, isect_array, P, dir, PATH_RAY_SHADOW, object, primAddr, ray->time, type, NULL, 0, 0);
- else
- hit = bvh_curve_intersect(kg, isect_array, P, dir, PATH_RAY_SHADOW, object, primAddr, ray->time, type, NULL, 0, 0);
+ if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) {
+ hit = bvh_cardinal_curve_intersect(kg,
+ isect_array,
+ P,
+ dir,
+ PATH_RAY_SHADOW,
+ object,
+ prim_addr,
+ ray->time,
+ type,
+ NULL,
+ 0, 0);
+ }
+ else {
+ hit = bvh_curve_intersect(kg,
+ isect_array,
+ P,
+ dir,
+ PATH_RAY_SHADOW,
+ object,
+ prim_addr,
+ ray->time,
+ type,
+ NULL,
+ 0, 0);
+ }
break;
}
#endif
@@ -272,7 +278,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
shader = __float_as_int(str.z);
}
#endif
- int flag = kernel_tex_fetch(__shader_flag, (shader & SHADER_MASK)*2);
+ int flag = kernel_tex_fetch(__shader_flag, (shader & SHADER_MASK)*SHADER_SIZE);
/* if no transparent shadows, all light is blocked */
if(!(flag & SD_HAS_TRANSPARENT_SHADOW)) {
@@ -293,13 +299,13 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
isect_array->t = isect_t;
}
- primAddr++;
+ prim_addr++;
}
}
#if BVH_FEATURE(BVH_INSTANCING)
else {
/* instance push */
- object = kernel_tex_fetch(__prim_object, -primAddr-1);
+ object = kernel_tex_fetch(__prim_object, -prim_addr-1);
# if BVH_FEATURE(BVH_MOTION)
bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect_t, &ob_itfm);
@@ -317,23 +323,27 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
Psplat[2] = ssef(P.z);
tsplat = ssef(0.0f, 0.0f, -isect_t, -isect_t);
+# if BVH_FEATURE(BVH_HAIR)
+ tfar = ssef(isect_t);
+# endif
gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
# endif
- ++stackPtr;
- kernel_assert(stackPtr < BVH_STACK_SIZE);
- traversalStack[stackPtr] = ENTRYPOINT_SENTINEL;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_STACK_SIZE);
+ traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL;
- nodeAddr = kernel_tex_fetch(__object_node, object);
+ node_addr = kernel_tex_fetch(__object_node, object);
}
}
#endif /* FEATURE(BVH_INSTANCING) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
+ } while(node_addr != ENTRYPOINT_SENTINEL);
#if BVH_FEATURE(BVH_INSTANCING)
- if(stackPtr >= 0) {
+ if(stack_ptr >= 0) {
kernel_assert(object != OBJECT_NONE);
+ /* Instance pop. */
if(num_hits_in_instance) {
float t_fac;
@@ -346,8 +356,9 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
triangle_intersect_precalc(dir, &isect_precalc);
/* scale isect->t to adjust for instancing */
- for(int i = 0; i < num_hits_in_instance; i++)
+ for(int i = 0; i < num_hits_in_instance; i++) {
(isect_array-i-1)->t *= t_fac;
+ }
}
else {
float ignore_t = FLT_MAX;
@@ -369,15 +380,18 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
Psplat[2] = ssef(P.z);
tsplat = ssef(0.0f, 0.0f, -isect_t, -isect_t);
+# if BVH_FEATURE(BVH_HAIR)
+ tfar = ssef(isect_t);
+# endif
gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
# endif
object = OBJECT_NONE;
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
}
#endif /* FEATURE(BVH_INSTANCING) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
+ } while(node_addr != ENTRYPOINT_SENTINEL);
return false;
}
@@ -410,3 +424,4 @@ ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals *kg,
#undef BVH_FUNCTION_NAME
#undef BVH_FUNCTION_FEATURES
+#undef NODE_INTERSECT
diff --git a/intern/cycles/kernel/geom/geom_bvh_subsurface.h b/intern/cycles/kernel/bvh/bvh_subsurface.h
index 915e9415c93..d9623c94b2e 100644
--- a/intern/cycles/kernel/geom/geom_bvh_subsurface.h
+++ b/intern/cycles/kernel/bvh/bvh_subsurface.h
@@ -18,7 +18,13 @@
*/
#ifdef __QBVH__
-# include "geom_qbvh_subsurface.h"
+# include "qbvh_subsurface.h"
+#endif
+
+#if BVH_FEATURE(BVH_HAIR)
+# define NODE_INTERSECT bvh_node_intersect
+#else
+# define NODE_INTERSECT bvh_aligned_node_intersect
#endif
/* This is a template BVH traversal function for subsurface scattering, where
@@ -29,12 +35,17 @@
*
*/
-ccl_device void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
- const Ray *ray,
- SubsurfaceIntersection *ss_isect,
- int subsurface_object,
- uint *lcg_state,
- int max_hits)
+#ifndef __KERNEL_GPU__
+ccl_device
+#else
+ccl_device_inline
+#endif
+void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
+ const Ray *ray,
+ SubsurfaceIntersection *ss_isect,
+ int subsurface_object,
+ uint *lcg_state,
+ int max_hits)
{
/* todo:
* - test if pushing distance on the stack helps (for non shadow rays)
@@ -44,12 +55,12 @@ ccl_device void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
*/
/* traversal stack in CUDA thread-local memory */
- int traversalStack[BVH_STACK_SIZE];
- traversalStack[0] = ENTRYPOINT_SENTINEL;
+ int traversal_stack[BVH_STACK_SIZE];
+ traversal_stack[0] = ENTRYPOINT_SENTINEL;
/* traversal variables in registers */
- int stackPtr = 0;
- int nodeAddr = kernel_tex_fetch(__object_node, subsurface_object);
+ int stack_ptr = 0;
+ int node_addr = kernel_tex_fetch(__object_node, subsurface_object);
/* ray parameters in registers */
float3 P = ray->P;
@@ -84,6 +95,9 @@ ccl_device void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000));
ssef Psplat[3], idirsplat[3];
+# if BVH_FEATURE(BVH_HAIR)
+ ssef tnear(0.0f), tfar(isect_t);
+# endif
shuffle_swap_t shufflexyz[3];
Psplat[0] = ssef(P.x);
@@ -100,127 +114,94 @@ ccl_device void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
/* traversal loop */
do {
- do
- {
+ do {
/* traverse internal nodes */
- while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL)
- {
- bool traverseChild0, traverseChild1;
- int nodeAddrChild1;
+ while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
+ int node_addr_child1, traverse_mask;
+ float dist[2];
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
#if !defined(__KERNEL_SSE2__)
- /* Intersect two child bounding boxes, non-SSE version */
- float t = isect_t;
-
- /* fetch node data */
- float4 node0 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+0);
- float4 node1 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+1);
- float4 node2 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+2);
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+3);
-
- /* intersect ray against child nodes */
- NO_EXTENDED_PRECISION float c0lox = (node0.x - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c0hix = (node0.z - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c0loy = (node1.x - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c0hiy = (node1.z - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c0loz = (node2.x - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c0hiz = (node2.z - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f);
- NO_EXTENDED_PRECISION float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t);
-
- NO_EXTENDED_PRECISION float c1lox = (node0.y - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c1hix = (node0.w - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c1loy = (node1.y - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c1hiy = (node1.w - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c1loz = (node2.y - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c1hiz = (node2.w - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f);
- NO_EXTENDED_PRECISION float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t);
-
- /* decide which nodes to traverse next */
- traverseChild0 = (c0max >= c0min);
- traverseChild1 = (c1max >= c1min);
-
+ traverse_mask = NODE_INTERSECT(kg,
+ P,
+# if BVH_FEATURE(BVH_HAIR)
+ dir,
+# endif
+ idir,
+ isect_t,
+ node_addr,
+ PATH_RAY_ALL_VISIBILITY,
+ dist);
#else // __KERNEL_SSE2__
- /* Intersect two child bounding boxes, SSE3 version adapted from Embree */
-
- /* fetch node data */
- const ssef *bvh_nodes = (ssef*)kg->__bvh_nodes.data + nodeAddr*BVH_NODE_SIZE;
- const float4 cnodes = ((float4*)bvh_nodes)[3];
-
- /* intersect ray against child nodes */
- const ssef tminmaxx = (shuffle_swap(bvh_nodes[0], shufflexyz[0]) - Psplat[0]) * idirsplat[0];
- const ssef tminmaxy = (shuffle_swap(bvh_nodes[1], shufflexyz[1]) - Psplat[1]) * idirsplat[1];
- const ssef tminmaxz = (shuffle_swap(bvh_nodes[2], shufflexyz[2]) - Psplat[2]) * idirsplat[2];
-
- /* calculate { c0min, c1min, -c0max, -c1max} */
- const ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat));
- const ssef tminmax = minmax ^ pn;
- const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax);
-
- /* decide which nodes to traverse next */
- traverseChild0 = (movemask(lrhit) & 1);
- traverseChild1 = (movemask(lrhit) & 2);
+ traverse_mask = NODE_INTERSECT(kg,
+ P,
+ dir,
+# if BVH_FEATURE(BVH_HAIR)
+ tnear,
+ tfar,
+# endif
+ tsplat,
+ Psplat,
+ idirsplat,
+ shufflexyz,
+ node_addr,
+ PATH_RAY_ALL_VISIBILITY,
+ dist);
#endif // __KERNEL_SSE2__
- nodeAddr = __float_as_int(cnodes.x);
- nodeAddrChild1 = __float_as_int(cnodes.y);
-
- if(traverseChild0 && traverseChild1) {
- /* both children were intersected, push the farther one */
-#if !defined(__KERNEL_SSE2__)
- bool closestChild1 = (c1min < c0min);
-#else
- bool closestChild1 = tminmax[1] < tminmax[0];
-#endif
+ node_addr = __float_as_int(cnodes.z);
+ node_addr_child1 = __float_as_int(cnodes.w);
- if(closestChild1) {
- int tmp = nodeAddr;
- nodeAddr = nodeAddrChild1;
- nodeAddrChild1 = tmp;
+ if(traverse_mask == 3) {
+ /* Both children were intersected, push the farther one. */
+ bool is_closest_child1 = (dist[1] < dist[0]);
+ if(is_closest_child1) {
+ int tmp = node_addr;
+ node_addr = node_addr_child1;
+ node_addr_child1 = tmp;
}
- ++stackPtr;
- kernel_assert(stackPtr < BVH_STACK_SIZE);
- traversalStack[stackPtr] = nodeAddrChild1;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_STACK_SIZE);
+ traversal_stack[stack_ptr] = node_addr_child1;
}
else {
- /* one child was intersected */
- if(traverseChild1) {
- nodeAddr = nodeAddrChild1;
+ /* One child was intersected. */
+ if(traverse_mask == 2) {
+ node_addr = node_addr_child1;
}
- else if(!traverseChild0) {
- /* neither child was intersected */
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
+ else if(traverse_mask == 0) {
+ /* Neither child was intersected. */
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
}
}
}
/* if node is leaf, fetch triangle list */
- if(nodeAddr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_NODE_LEAF_SIZE);
- int primAddr = __float_as_int(leaf.x);
+ if(node_addr < 0) {
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1));
+ int prim_addr = __float_as_int(leaf.x);
- const int primAddr2 = __float_as_int(leaf.y);
+ const int prim_addr2 = __float_as_int(leaf.y);
const uint type = __float_as_int(leaf.w);
/* pop */
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
/* primitive intersection */
switch(type & PRIMITIVE_ALL) {
case PRIMITIVE_TRIANGLE: {
/* intersect ray against primitive */
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
triangle_intersect_subsurface(kg,
&isect_precalc,
ss_isect,
P,
object,
- primAddr,
+ prim_addr,
isect_t,
lcg_state,
max_hits);
@@ -230,15 +211,15 @@ ccl_device void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
#if BVH_FEATURE(BVH_MOTION)
case PRIMITIVE_MOTION_TRIANGLE: {
/* intersect ray against primitive */
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
motion_triangle_intersect_subsurface(kg,
ss_isect,
P,
dir,
ray->time,
object,
- primAddr,
+ prim_addr,
isect_t,
lcg_state,
max_hits);
@@ -251,8 +232,8 @@ ccl_device void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
}
}
}
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
+ } while(node_addr != ENTRYPOINT_SENTINEL);
+ } while(node_addr != ENTRYPOINT_SENTINEL);
}
ccl_device_inline void BVH_FUNCTION_NAME(KernelGlobals *kg,
@@ -286,3 +267,4 @@ ccl_device_inline void BVH_FUNCTION_NAME(KernelGlobals *kg,
#undef BVH_FUNCTION_NAME
#undef BVH_FUNCTION_FEATURES
+#undef NODE_INTERSECT
diff --git a/intern/cycles/kernel/bvh/bvh_traversal.h b/intern/cycles/kernel/bvh/bvh_traversal.h
new file mode 100644
index 00000000000..a0e478e972b
--- /dev/null
+++ b/intern/cycles/kernel/bvh/bvh_traversal.h
@@ -0,0 +1,466 @@
+/*
+ * Adapted from code Copyright 2009-2010 NVIDIA Corporation,
+ * and code copyright 2009-2012 Intel Corporation
+ *
+ * Modifications Copyright 2011-2013, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef __QBVH__
+# include "qbvh_traversal.h"
+#endif
+
+#if BVH_FEATURE(BVH_HAIR)
+# define NODE_INTERSECT bvh_node_intersect
+# define NODE_INTERSECT_ROBUST bvh_node_intersect_robust
+#else
+# define NODE_INTERSECT bvh_aligned_node_intersect
+# define NODE_INTERSECT_ROBUST bvh_aligned_node_intersect_robust
+#endif
+
+/* This is a template BVH traversal function, where various features can be
+ * enabled/disabled. This way we can compile optimized versions for each case
+ * without new features slowing things down.
+ *
+ * BVH_INSTANCING: object instancing
+ * BVH_HAIR: hair curve rendering
+ * BVH_HAIR_MINIMUM_WIDTH: hair curve rendering with minimum width
+ * BVH_MOTION: motion blur rendering
+ *
+ */
+
+ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
+ const Ray *ray,
+ Intersection *isect,
+ const uint visibility
+#if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH)
+ , uint *lcg_state,
+ float difl,
+ float extmax
+#endif
+ )
+{
+ /* todo:
+ * - test if pushing distance on the stack helps (for non shadow rays)
+ * - separate version for shadow rays
+ * - likely and unlikely for if() statements
+ * - test restrict attribute for pointers
+ */
+
+ /* traversal stack in CUDA thread-local memory */
+ int traversal_stack[BVH_STACK_SIZE];
+ traversal_stack[0] = ENTRYPOINT_SENTINEL;
+
+ /* traversal variables in registers */
+ int stack_ptr = 0;
+ int node_addr = kernel_data.bvh.root;
+
+ /* ray parameters in registers */
+ float3 P = ray->P;
+ float3 dir = bvh_clamp_direction(ray->D);
+ float3 idir = bvh_inverse_direction(dir);
+ int object = OBJECT_NONE;
+
+#if BVH_FEATURE(BVH_MOTION)
+ Transform ob_itfm;
+#endif
+
+ isect->t = ray->t;
+ isect->u = 0.0f;
+ isect->v = 0.0f;
+ isect->prim = PRIM_NONE;
+ isect->object = OBJECT_NONE;
+
+ BVH_DEBUG_INIT();
+
+#if defined(__KERNEL_SSE2__)
+ const shuffle_swap_t shuf_identity = shuffle_swap_identity();
+ const shuffle_swap_t shuf_swap = shuffle_swap_swap();
+
+ const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000));
+ ssef Psplat[3], idirsplat[3];
+# if BVH_FEATURE(BVH_HAIR)
+ ssef tnear(0.0f), tfar(isect->t);
+# endif
+ shuffle_swap_t shufflexyz[3];
+
+ Psplat[0] = ssef(P.x);
+ Psplat[1] = ssef(P.y);
+ Psplat[2] = ssef(P.z);
+
+ ssef tsplat(0.0f, 0.0f, -isect->t, -isect->t);
+
+ gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
+#endif
+
+ IsectPrecalc isect_precalc;
+ triangle_intersect_precalc(dir, &isect_precalc);
+
+ /* traversal loop */
+ do {
+ do {
+ /* traverse internal nodes */
+ while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
+ int node_addr_child1, traverse_mask;
+ float dist[2];
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
+
+#if !defined(__KERNEL_SSE2__)
+# if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH)
+ if(difl != 0.0f) {
+ traverse_mask = NODE_INTERSECT_ROBUST(kg,
+ P,
+# if BVH_FEATURE(BVH_HAIR)
+ dir,
+# endif
+ idir,
+ isect->t,
+ difl,
+ extmax,
+ node_addr,
+ visibility,
+ dist);
+ }
+ else
+# endif
+ {
+ traverse_mask = NODE_INTERSECT(kg,
+ P,
+# if BVH_FEATURE(BVH_HAIR)
+ dir,
+# endif
+ idir,
+ isect->t,
+ node_addr,
+ visibility,
+ dist);
+ }
+#else // __KERNEL_SSE2__
+# if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH)
+ if(difl != 0.0f) {
+ traverse_mask = NODE_INTERSECT_ROBUST(kg,
+ P,
+ dir,
+# if BVH_FEATURE(BVH_HAIR)
+ tnear,
+ tfar,
+# endif
+ tsplat,
+ Psplat,
+ idirsplat,
+ shufflexyz,
+ difl,
+ extmax,
+ node_addr,
+ visibility,
+ dist);
+ }
+ else
+# endif
+ {
+ traverse_mask = NODE_INTERSECT(kg,
+ P,
+ dir,
+# if BVH_FEATURE(BVH_HAIR)
+ tnear,
+ tfar,
+# endif
+ tsplat,
+ Psplat,
+ idirsplat,
+ shufflexyz,
+ node_addr,
+ visibility,
+ dist);
+ }
+#endif // __KERNEL_SSE2__
+
+ node_addr = __float_as_int(cnodes.z);
+ node_addr_child1 = __float_as_int(cnodes.w);
+
+ if(traverse_mask == 3) {
+ /* Both children were intersected, push the farther one. */
+ bool is_closest_child1 = (dist[1] < dist[0]);
+ if(is_closest_child1) {
+ int tmp = node_addr;
+ node_addr = node_addr_child1;
+ node_addr_child1 = tmp;
+ }
+
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_STACK_SIZE);
+ traversal_stack[stack_ptr] = node_addr_child1;
+ }
+ else {
+ /* One child was intersected. */
+ if(traverse_mask == 2) {
+ node_addr = node_addr_child1;
+ }
+ else if(traverse_mask == 0) {
+ /* Neither child was intersected. */
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
+ }
+ }
+ BVH_DEBUG_NEXT_STEP();
+ }
+
+ /* if node is leaf, fetch triangle list */
+ if(node_addr < 0) {
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1));
+ int prim_addr = __float_as_int(leaf.x);
+
+#if BVH_FEATURE(BVH_INSTANCING)
+ if(prim_addr >= 0) {
+#endif
+ const int prim_addr2 = __float_as_int(leaf.y);
+ const uint type = __float_as_int(leaf.w);
+
+ /* pop */
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
+
+ /* primitive intersection */
+ switch(type & PRIMITIVE_ALL) {
+ case PRIMITIVE_TRIANGLE: {
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ BVH_DEBUG_NEXT_STEP();
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
+ if(triangle_intersect(kg,
+ &isect_precalc,
+ isect,
+ P,
+ visibility,
+ object,
+ prim_addr))
+ {
+ /* shadow ray early termination */
+#if defined(__KERNEL_SSE2__)
+ if(visibility == PATH_RAY_SHADOW_OPAQUE)
+ return true;
+ tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t);
+# if BVH_FEATURE(BVH_HAIR)
+ tfar = ssef(isect->t);
+# endif
+#else
+ if(visibility == PATH_RAY_SHADOW_OPAQUE)
+ return true;
+#endif
+ }
+ }
+ break;
+ }
+#if BVH_FEATURE(BVH_MOTION)
+ case PRIMITIVE_MOTION_TRIANGLE: {
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ BVH_DEBUG_NEXT_STEP();
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
+ if(motion_triangle_intersect(kg,
+ isect,
+ P,
+ dir,
+ ray->time,
+ visibility,
+ object,
+ prim_addr))
+ {
+ /* shadow ray early termination */
+# if defined(__KERNEL_SSE2__)
+ if(visibility == PATH_RAY_SHADOW_OPAQUE)
+ return true;
+ tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t);
+# if BVH_FEATURE(BVH_HAIR)
+ tfar = ssef(isect->t);
+# endif
+# else
+ if(visibility == PATH_RAY_SHADOW_OPAQUE)
+ return true;
+# endif
+ }
+ }
+ break;
+ }
+#endif /* BVH_FEATURE(BVH_MOTION) */
+#if BVH_FEATURE(BVH_HAIR)
+ case PRIMITIVE_CURVE:
+ case PRIMITIVE_MOTION_CURVE: {
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ BVH_DEBUG_NEXT_STEP();
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
+ bool hit;
+ if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) {
+ hit = bvh_cardinal_curve_intersect(kg,
+ isect,
+ P,
+ dir,
+ visibility,
+ object,
+ prim_addr,
+ ray->time,
+ type,
+ lcg_state,
+ difl,
+ extmax);
+ }
+ else {
+ hit = bvh_curve_intersect(kg,
+ isect,
+ P,
+ dir,
+ visibility,
+ object,
+ prim_addr,
+ ray->time,
+ type,
+ lcg_state,
+ difl,
+ extmax);
+ }
+ if(hit) {
+ /* shadow ray early termination */
+# if defined(__KERNEL_SSE2__)
+ if(visibility == PATH_RAY_SHADOW_OPAQUE)
+ return true;
+ tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t);
+# if BVH_FEATURE(BVH_HAIR)
+ tfar = ssef(isect->t);
+# endif
+# else
+ if(visibility == PATH_RAY_SHADOW_OPAQUE)
+ return true;
+# endif
+ }
+ }
+ break;
+ }
+#endif /* BVH_FEATURE(BVH_HAIR) */
+ }
+ }
+#if BVH_FEATURE(BVH_INSTANCING)
+ else {
+ /* instance push */
+ object = kernel_tex_fetch(__prim_object, -prim_addr-1);
+
+# if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_itfm);
+# else
+ bvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect->t);
+# endif
+ triangle_intersect_precalc(dir, &isect_precalc);
+
+# if defined(__KERNEL_SSE2__)
+ Psplat[0] = ssef(P.x);
+ Psplat[1] = ssef(P.y);
+ Psplat[2] = ssef(P.z);
+
+ tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t);
+# if BVH_FEATURE(BVH_HAIR)
+ tfar = ssef(isect->t);
+# endif
+
+ gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
+# endif
+
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_STACK_SIZE);
+ traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL;
+
+ node_addr = kernel_tex_fetch(__object_node, object);
+
+ BVH_DEBUG_NEXT_INSTANCE();
+ }
+ }
+#endif /* FEATURE(BVH_INSTANCING) */
+ } while(node_addr != ENTRYPOINT_SENTINEL);
+
+#if BVH_FEATURE(BVH_INSTANCING)
+ if(stack_ptr >= 0) {
+ kernel_assert(object != OBJECT_NONE);
+
+ /* instance pop */
+# if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_itfm);
+# else
+ bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &isect->t);
+# endif
+ triangle_intersect_precalc(dir, &isect_precalc);
+
+# if defined(__KERNEL_SSE2__)
+ Psplat[0] = ssef(P.x);
+ Psplat[1] = ssef(P.y);
+ Psplat[2] = ssef(P.z);
+
+ tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t);
+# if BVH_FEATURE(BVH_HAIR)
+ tfar = ssef(isect->t);
+# endif
+
+ gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
+# endif
+
+ object = OBJECT_NONE;
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
+ }
+#endif /* FEATURE(BVH_INSTANCING) */
+ } while(node_addr != ENTRYPOINT_SENTINEL);
+
+ return (isect->prim != PRIM_NONE);
+}
+
+ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals *kg,
+ const Ray *ray,
+ Intersection *isect,
+ const uint visibility
+#if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH)
+ , uint *lcg_state,
+ float difl,
+ float extmax
+#endif
+ )
+{
+#ifdef __QBVH__
+ if(kernel_data.bvh.use_qbvh) {
+ return BVH_FUNCTION_FULL_NAME(QBVH)(kg,
+ ray,
+ isect,
+ visibility
+#if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH)
+ , lcg_state,
+ difl,
+ extmax
+#endif
+ );
+ }
+ else
+#endif
+ {
+ kernel_assert(kernel_data.bvh.use_qbvh == false);
+ return BVH_FUNCTION_FULL_NAME(BVH)(kg,
+ ray,
+ isect,
+ visibility
+#if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH)
+ , lcg_state,
+ difl,
+ extmax
+#endif
+ );
+ }
+}
+
+#undef BVH_FUNCTION_NAME
+#undef BVH_FUNCTION_FEATURES
+#undef NODE_INTERSECT
+#undef NODE_INTERSECT_ROBUST
diff --git a/intern/cycles/kernel/bvh/bvh_types.h b/intern/cycles/kernel/bvh/bvh_types.h
new file mode 100644
index 00000000000..c3abe2e157d
--- /dev/null
+++ b/intern/cycles/kernel/bvh/bvh_types.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BVH_TYPES__
+#define __BVH_TYPES__
+
+CCL_NAMESPACE_BEGIN
+
+/* Don't inline intersect functions on GPU, this is faster */
+#ifdef __KERNEL_GPU__
+# define ccl_device_intersect ccl_device_forceinline
+#else
+# define ccl_device_intersect ccl_device_inline
+#endif
+
+/* bottom-most stack entry, indicating the end of traversal */
+#define ENTRYPOINT_SENTINEL 0x76543210
+
+/* 64 object BVH + 64 mesh BVH + 64 object node splitting */
+#define BVH_STACK_SIZE 192
+#define BVH_QSTACK_SIZE 384
+
+/* BVH intersection function variations */
+
+#define BVH_INSTANCING 1
+#define BVH_MOTION 2
+#define BVH_HAIR 4
+#define BVH_HAIR_MINIMUM_WIDTH 8
+
+#define BVH_NAME_JOIN(x,y) x ## _ ## y
+#define BVH_NAME_EVAL(x,y) BVH_NAME_JOIN(x,y)
+#define BVH_FUNCTION_FULL_NAME(prefix) BVH_NAME_EVAL(prefix, BVH_FUNCTION_NAME)
+
+#define BVH_FEATURE(f) (((BVH_FUNCTION_FEATURES) & (f)) != 0)
+
+/* Debugging heleprs */
+#ifdef __KERNEL_DEBUG__
+# define BVH_DEBUG_INIT() \
+ do { \
+ isect->num_traversal_steps = 0; \
+ isect->num_traversed_instances = 0; \
+ } while(0)
+# define BVH_DEBUG_NEXT_STEP() \
+ do { \
+ ++isect->num_traversal_steps; \
+ } while(0)
+# define BVH_DEBUG_NEXT_INSTANCE() \
+ do { \
+ ++isect->num_traversed_instances; \
+ } while(0)
+#else /* __KERNEL_DEBUG__ */
+# define BVH_DEBUG_INIT()
+# define BVH_DEBUG_NEXT_STEP()
+# define BVH_DEBUG_NEXT_INSTANCE()
+#endif /* __KERNEL_DEBUG__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __BVH_TYPES__ */
diff --git a/intern/cycles/kernel/geom/geom_bvh_volume.h b/intern/cycles/kernel/bvh/bvh_volume.h
index f3edf85d723..107373c17dc 100644
--- a/intern/cycles/kernel/geom/geom_bvh_volume.h
+++ b/intern/cycles/kernel/bvh/bvh_volume.h
@@ -18,7 +18,13 @@
*/
#ifdef __QBVH__
-#include "geom_qbvh_volume.h"
+# include "qbvh_volume.h"
+#endif
+
+#if BVH_FEATURE(BVH_HAIR)
+# define NODE_INTERSECT bvh_node_intersect
+#else
+# define NODE_INTERSECT bvh_aligned_node_intersect
#endif
/* This is a template BVH traversal function for volumes, where
@@ -30,10 +36,15 @@
*
*/
-ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
- const Ray *ray,
- Intersection *isect,
- const uint visibility)
+#ifndef __KERNEL_GPU__
+ccl_device
+#else
+ccl_device_inline
+#endif
+bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
+ const Ray *ray,
+ Intersection *isect,
+ const uint visibility)
{
/* todo:
* - test if pushing distance on the stack helps (for non shadow rays)
@@ -43,12 +54,12 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
*/
/* traversal stack in CUDA thread-local memory */
- int traversalStack[BVH_STACK_SIZE];
- traversalStack[0] = ENTRYPOINT_SENTINEL;
+ int traversal_stack[BVH_STACK_SIZE];
+ traversal_stack[0] = ENTRYPOINT_SENTINEL;
/* traversal variables in registers */
- int stackPtr = 0;
- int nodeAddr = kernel_data.bvh.root;
+ int stack_ptr = 0;
+ int node_addr = kernel_data.bvh.root;
/* ray parameters in registers */
float3 P = ray->P;
@@ -69,9 +80,12 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
#if defined(__KERNEL_SSE2__)
const shuffle_swap_t shuf_identity = shuffle_swap_identity();
const shuffle_swap_t shuf_swap = shuffle_swap_swap();
-
+
const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000));
ssef Psplat[3], idirsplat[3];
+# if BVH_FEATURE(BVH_HAIR)
+ ssef tnear(0.0f), tfar(isect->t);
+# endif
shuffle_swap_t shufflexyz[3];
Psplat[0] = ssef(P.x);
@@ -90,143 +104,124 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
do {
do {
/* traverse internal nodes */
- while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) {
- bool traverseChild0, traverseChild1;
- int nodeAddrChild1;
+ while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
+ int node_addr_child1, traverse_mask;
+ float dist[2];
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
#if !defined(__KERNEL_SSE2__)
- /* Intersect two child bounding boxes, non-SSE version */
- float t = isect->t;
-
- /* fetch node data */
- float4 node0 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+0);
- float4 node1 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+1);
- float4 node2 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+2);
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+3);
-
- /* intersect ray against child nodes */
- NO_EXTENDED_PRECISION float c0lox = (node0.x - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c0hix = (node0.z - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c0loy = (node1.x - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c0hiy = (node1.z - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c0loz = (node2.x - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c0hiz = (node2.z - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f);
- NO_EXTENDED_PRECISION float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t);
-
- NO_EXTENDED_PRECISION float c1lox = (node0.y - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c1hix = (node0.w - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c1loy = (node1.y - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c1hiy = (node1.w - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c1loz = (node2.y - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c1hiz = (node2.w - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f);
- NO_EXTENDED_PRECISION float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t);
-
- /* decide which nodes to traverse next */
- traverseChild0 = (c0max >= c0min);
- traverseChild1 = (c1max >= c1min);
-
+ traverse_mask = NODE_INTERSECT(kg,
+ P,
+# if BVH_FEATURE(BVH_HAIR)
+ dir,
+# endif
+ idir,
+ isect->t,
+ node_addr,
+ visibility,
+ dist);
#else // __KERNEL_SSE2__
- /* Intersect two child bounding boxes, SSE3 version adapted from Embree */
-
- /* fetch node data */
- const ssef *bvh_nodes = (ssef*)kg->__bvh_nodes.data + nodeAddr*BVH_NODE_SIZE;
- const float4 cnodes = ((float4*)bvh_nodes)[3];
-
- /* intersect ray against child nodes */
- const ssef tminmaxx = (shuffle_swap(bvh_nodes[0], shufflexyz[0]) - Psplat[0]) * idirsplat[0];
- const ssef tminmaxy = (shuffle_swap(bvh_nodes[1], shufflexyz[1]) - Psplat[1]) * idirsplat[1];
- const ssef tminmaxz = (shuffle_swap(bvh_nodes[2], shufflexyz[2]) - Psplat[2]) * idirsplat[2];
-
- /* calculate { c0min, c1min, -c0max, -c1max} */
- ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat));
- const ssef tminmax = minmax ^ pn;
-
- const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax);
-
- /* decide which nodes to traverse next */
- traverseChild0 = (movemask(lrhit) & 1);
- traverseChild1 = (movemask(lrhit) & 2);
+ traverse_mask = NODE_INTERSECT(kg,
+ P,
+ dir,
+# if BVH_FEATURE(BVH_HAIR)
+ tnear,
+ tfar,
+# endif
+ tsplat,
+ Psplat,
+ idirsplat,
+ shufflexyz,
+ node_addr,
+ visibility,
+ dist);
#endif // __KERNEL_SSE2__
- nodeAddr = __float_as_int(cnodes.x);
- nodeAddrChild1 = __float_as_int(cnodes.y);
-
- if(traverseChild0 && traverseChild1) {
- /* both children were intersected, push the farther one */
-#if !defined(__KERNEL_SSE2__)
- bool closestChild1 = (c1min < c0min);
-#else
- bool closestChild1 = tminmax[1] < tminmax[0];
-#endif
+ node_addr = __float_as_int(cnodes.z);
+ node_addr_child1 = __float_as_int(cnodes.w);
- if(closestChild1) {
- int tmp = nodeAddr;
- nodeAddr = nodeAddrChild1;
- nodeAddrChild1 = tmp;
+ if(traverse_mask == 3) {
+ /* Both children were intersected, push the farther one. */
+ bool is_closest_child1 = (dist[1] < dist[0]);
+ if(is_closest_child1) {
+ int tmp = node_addr;
+ node_addr = node_addr_child1;
+ node_addr_child1 = tmp;
}
- ++stackPtr;
- kernel_assert(stackPtr < BVH_STACK_SIZE);
- traversalStack[stackPtr] = nodeAddrChild1;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_STACK_SIZE);
+ traversal_stack[stack_ptr] = node_addr_child1;
}
else {
- /* one child was intersected */
- if(traverseChild1) {
- nodeAddr = nodeAddrChild1;
+ /* One child was intersected. */
+ if(traverse_mask == 2) {
+ node_addr = node_addr_child1;
}
- else if(!traverseChild0) {
- /* neither child was intersected */
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
+ else if(traverse_mask == 0) {
+ /* Neither child was intersected. */
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
}
}
}
/* if node is leaf, fetch triangle list */
- if(nodeAddr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_NODE_LEAF_SIZE);
- int primAddr = __float_as_int(leaf.x);
+ if(node_addr < 0) {
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1));
+ int prim_addr = __float_as_int(leaf.x);
#if BVH_FEATURE(BVH_INSTANCING)
- if(primAddr >= 0) {
+ if(prim_addr >= 0) {
#endif
- const int primAddr2 = __float_as_int(leaf.y);
+ const int prim_addr2 = __float_as_int(leaf.y);
const uint type = __float_as_int(leaf.w);
/* pop */
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
/* primitive intersection */
switch(type & PRIMITIVE_ALL) {
case PRIMITIVE_TRIANGLE: {
/* intersect ray against primitive */
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
/* only primitives from volume object */
- uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
+ uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object;
int object_flag = kernel_tex_fetch(__object_flag, tri_object);
if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
continue;
}
- triangle_intersect(kg, &isect_precalc, isect, P, visibility, object, primAddr);
+ triangle_intersect(kg,
+ &isect_precalc,
+ isect,
+ P,
+ visibility,
+ object,
+ prim_addr);
}
break;
}
#if BVH_FEATURE(BVH_MOTION)
case PRIMITIVE_MOTION_TRIANGLE: {
/* intersect ray against primitive */
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
/* only primitives from volume object */
- uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
+ uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object;
int object_flag = kernel_tex_fetch(__object_flag, tri_object);
if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
continue;
}
- motion_triangle_intersect(kg, isect, P, dir, ray->time, visibility, object, primAddr);
+ motion_triangle_intersect(kg,
+ isect,
+ P,
+ dir,
+ ray->time,
+ visibility,
+ object,
+ prim_addr);
}
break;
}
@@ -239,7 +234,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
#if BVH_FEATURE(BVH_INSTANCING)
else {
/* instance push */
- object = kernel_tex_fetch(__prim_object, -primAddr-1);
+ object = kernel_tex_fetch(__prim_object, -prim_addr-1);
int object_flag = kernel_tex_fetch(__object_flag, object);
if(object_flag & SD_OBJECT_HAS_VOLUME) {
@@ -258,29 +253,32 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
Psplat[2] = ssef(P.z);
tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t);
+# if BVH_FEATURE(BVH_HAIR)
+ tfar = ssef(isect->t);
+# endif
gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
# endif
- ++stackPtr;
- kernel_assert(stackPtr < BVH_STACK_SIZE);
- traversalStack[stackPtr] = ENTRYPOINT_SENTINEL;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_STACK_SIZE);
+ traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL;
- nodeAddr = kernel_tex_fetch(__object_node, object);
+ node_addr = kernel_tex_fetch(__object_node, object);
}
else {
/* pop */
object = OBJECT_NONE;
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
}
}
}
#endif /* FEATURE(BVH_INSTANCING) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
+ } while(node_addr != ENTRYPOINT_SENTINEL);
#if BVH_FEATURE(BVH_INSTANCING)
- if(stackPtr >= 0) {
+ if(stack_ptr >= 0) {
kernel_assert(object != OBJECT_NONE);
/* instance pop */
@@ -298,16 +296,19 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
Psplat[2] = ssef(P.z);
tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t);
+# if BVH_FEATURE(BVH_HAIR)
+ tfar = ssef(isect->t);
+# endif
gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
# endif
object = OBJECT_NONE;
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
}
#endif /* FEATURE(BVH_MOTION) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
+ } while(node_addr != ENTRYPOINT_SENTINEL);
return (isect->prim != PRIM_NONE);
}
@@ -337,3 +338,4 @@ ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals *kg,
#undef BVH_FUNCTION_NAME
#undef BVH_FUNCTION_FEATURES
+#undef NODE_INTERSECT
diff --git a/intern/cycles/kernel/geom/geom_bvh_volume_all.h b/intern/cycles/kernel/bvh/bvh_volume_all.h
index ec837212471..529848ebe7b 100644
--- a/intern/cycles/kernel/geom/geom_bvh_volume_all.h
+++ b/intern/cycles/kernel/bvh/bvh_volume_all.h
@@ -18,7 +18,13 @@
*/
#ifdef __QBVH__
-#include "geom_qbvh_volume_all.h"
+# include "qbvh_volume_all.h"
+#endif
+
+#if BVH_FEATURE(BVH_HAIR)
+# define NODE_INTERSECT bvh_node_intersect
+#else
+# define NODE_INTERSECT bvh_aligned_node_intersect
#endif
/* This is a template BVH traversal function for volumes, where
@@ -30,11 +36,16 @@
*
*/
-ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
- const Ray *ray,
- Intersection *isect_array,
- const uint max_hits,
- const uint visibility)
+#ifndef __KERNEL_GPU__
+ccl_device
+#else
+ccl_device_inline
+#endif
+uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
+ const Ray *ray,
+ Intersection *isect_array,
+ const uint max_hits,
+ const uint visibility)
{
/* todo:
* - test if pushing distance on the stack helps (for non shadow rays)
@@ -44,12 +55,12 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
*/
/* traversal stack in CUDA thread-local memory */
- int traversalStack[BVH_STACK_SIZE];
- traversalStack[0] = ENTRYPOINT_SENTINEL;
+ int traversal_stack[BVH_STACK_SIZE];
+ traversal_stack[0] = ENTRYPOINT_SENTINEL;
/* traversal variables in registers */
- int stackPtr = 0;
- int nodeAddr = kernel_data.bvh.root;
+ int stack_ptr = 0;
+ int node_addr = kernel_data.bvh.root;
/* ray parameters in registers */
const float tmax = ray->t;
@@ -73,9 +84,12 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
#if defined(__KERNEL_SSE2__)
const shuffle_swap_t shuf_identity = shuffle_swap_identity();
const shuffle_swap_t shuf_swap = shuffle_swap_swap();
-
+
const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000));
ssef Psplat[3], idirsplat[3];
+# if BVH_FEATURE(BVH_HAIR)
+ ssef tnear(0.0f), tfar(isect_t);
+# endif
shuffle_swap_t shufflexyz[3];
Psplat[0] = ssef(P.x);
@@ -85,7 +99,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
ssef tsplat(0.0f, 0.0f, -isect_t, -isect_t);
gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
-#endif
+#endif /* __KERNEL_SSE2__ */
IsectPrecalc isect_precalc;
triangle_intersect_precalc(dir, &isect_precalc);
@@ -94,129 +108,103 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
do {
do {
/* traverse internal nodes */
- while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) {
- bool traverseChild0, traverseChild1;
- int nodeAddrChild1;
+ while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
+ int node_addr_child1, traverse_mask;
+ float dist[2];
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
#if !defined(__KERNEL_SSE2__)
- /* Intersect two child bounding boxes, non-SSE version */
- float t = isect_array->t;
-
- /* fetch node data */
- float4 node0 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+0);
- float4 node1 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+1);
- float4 node2 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+2);
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+3);
-
- /* intersect ray against child nodes */
- NO_EXTENDED_PRECISION float c0lox = (node0.x - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c0hix = (node0.z - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c0loy = (node1.x - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c0hiy = (node1.z - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c0loz = (node2.x - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c0hiz = (node2.z - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f);
- NO_EXTENDED_PRECISION float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t);
-
- NO_EXTENDED_PRECISION float c1lox = (node0.y - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c1hix = (node0.w - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c1loy = (node1.y - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c1hiy = (node1.w - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c1loz = (node2.y - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c1hiz = (node2.w - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f);
- NO_EXTENDED_PRECISION float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t);
-
- /* decide which nodes to traverse next */
- traverseChild0 = (c0max >= c0min);
- traverseChild1 = (c1max >= c1min);
-
+ traverse_mask = NODE_INTERSECT(kg,
+ P,
+# if BVH_FEATURE(BVH_HAIR)
+ dir,
+# endif
+ idir,
+ isect_t,
+ node_addr,
+ visibility,
+ dist);
#else // __KERNEL_SSE2__
- /* Intersect two child bounding boxes, SSE3 version adapted from Embree */
-
- /* fetch node data */
- const ssef *bvh_nodes = (ssef*)kg->__bvh_nodes.data + nodeAddr*BVH_NODE_SIZE;
- const float4 cnodes = ((float4*)bvh_nodes)[3];
-
- /* intersect ray against child nodes */
- const ssef tminmaxx = (shuffle_swap(bvh_nodes[0], shufflexyz[0]) - Psplat[0]) * idirsplat[0];
- const ssef tminmaxy = (shuffle_swap(bvh_nodes[1], shufflexyz[1]) - Psplat[1]) * idirsplat[1];
- const ssef tminmaxz = (shuffle_swap(bvh_nodes[2], shufflexyz[2]) - Psplat[2]) * idirsplat[2];
-
- /* calculate { c0min, c1min, -c0max, -c1max} */
- ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat));
- const ssef tminmax = minmax ^ pn;
-
- const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax);
-
- /* decide which nodes to traverse next */
- traverseChild0 = (movemask(lrhit) & 1);
- traverseChild1 = (movemask(lrhit) & 2);
+ traverse_mask = NODE_INTERSECT(kg,
+ P,
+ dir,
+# if BVH_FEATURE(BVH_HAIR)
+ tnear,
+ tfar,
+# endif
+ tsplat,
+ Psplat,
+ idirsplat,
+ shufflexyz,
+ node_addr,
+ visibility,
+ dist);
#endif // __KERNEL_SSE2__
- nodeAddr = __float_as_int(cnodes.x);
- nodeAddrChild1 = __float_as_int(cnodes.y);
+ node_addr = __float_as_int(cnodes.z);
+ node_addr_child1 = __float_as_int(cnodes.w);
- if(traverseChild0 && traverseChild1) {
- /* both children were intersected, push the farther one */
-#if !defined(__KERNEL_SSE2__)
- bool closestChild1 = (c1min < c0min);
-#else
- bool closestChild1 = tminmax[1] < tminmax[0];
-#endif
-
- if(closestChild1) {
- int tmp = nodeAddr;
- nodeAddr = nodeAddrChild1;
- nodeAddrChild1 = tmp;
+ if(traverse_mask == 3) {
+ /* Both children were intersected, push the farther one. */
+ bool is_closest_child1 = (dist[1] < dist[0]);
+ if(is_closest_child1) {
+ int tmp = node_addr;
+ node_addr = node_addr_child1;
+ node_addr_child1 = tmp;
}
- ++stackPtr;
- kernel_assert(stackPtr < BVH_STACK_SIZE);
- traversalStack[stackPtr] = nodeAddrChild1;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_STACK_SIZE);
+ traversal_stack[stack_ptr] = node_addr_child1;
}
else {
- /* one child was intersected */
- if(traverseChild1) {
- nodeAddr = nodeAddrChild1;
+ /* One child was intersected. */
+ if(traverse_mask == 2) {
+ node_addr = node_addr_child1;
}
- else if(!traverseChild0) {
- /* neither child was intersected */
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
+ else if(traverse_mask == 0) {
+ /* Neither child was intersected. */
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
}
}
}
/* if node is leaf, fetch triangle list */
- if(nodeAddr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_NODE_LEAF_SIZE);
- int primAddr = __float_as_int(leaf.x);
+ if(node_addr < 0) {
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1));
+ int prim_addr = __float_as_int(leaf.x);
#if BVH_FEATURE(BVH_INSTANCING)
- if(primAddr >= 0) {
+ if(prim_addr >= 0) {
#endif
- const int primAddr2 = __float_as_int(leaf.y);
+ const int prim_addr2 = __float_as_int(leaf.y);
const uint type = __float_as_int(leaf.w);
bool hit;
/* pop */
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
/* primitive intersection */
switch(type & PRIMITIVE_ALL) {
case PRIMITIVE_TRIANGLE: {
/* intersect ray against primitive */
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
/* only primitives from volume object */
- uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
+ uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object;
int object_flag = kernel_tex_fetch(__object_flag, tri_object);
if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
continue;
}
- hit = triangle_intersect(kg, &isect_precalc, isect_array, P, visibility, object, primAddr);
+ hit = triangle_intersect(kg,
+ &isect_precalc,
+ isect_array,
+ P,
+ visibility,
+ object,
+ prim_addr);
if(hit) {
/* Move on to next entry in intersections array. */
isect_array++;
@@ -246,15 +234,22 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
#if BVH_FEATURE(BVH_MOTION)
case PRIMITIVE_MOTION_TRIANGLE: {
/* intersect ray against primitive */
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
/* only primitives from volume object */
- uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
+ uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object;
int object_flag = kernel_tex_fetch(__object_flag, tri_object);
if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
continue;
}
- hit = motion_triangle_intersect(kg, isect_array, P, dir, ray->time, visibility, object, primAddr);
+ hit = motion_triangle_intersect(kg,
+ isect_array,
+ P,
+ dir,
+ ray->time,
+ visibility,
+ object,
+ prim_addr);
if(hit) {
/* Move on to next entry in intersections array. */
isect_array++;
@@ -290,7 +285,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
#if BVH_FEATURE(BVH_INSTANCING)
else {
/* instance push */
- object = kernel_tex_fetch(__prim_object, -primAddr-1);
+ object = kernel_tex_fetch(__prim_object, -prim_addr-1);
int object_flag = kernel_tex_fetch(__object_flag, object);
if(object_flag & SD_OBJECT_HAS_VOLUME) {
@@ -311,31 +306,35 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
Psplat[2] = ssef(P.z);
tsplat = ssef(0.0f, 0.0f, -isect_t, -isect_t);
+# if BVH_FEATURE(BVH_HAIR)
+ tfar = ssef(isect_t);
+# endif
gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
# endif
- ++stackPtr;
- kernel_assert(stackPtr < BVH_STACK_SIZE);
- traversalStack[stackPtr] = ENTRYPOINT_SENTINEL;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_STACK_SIZE);
+ traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL;
- nodeAddr = kernel_tex_fetch(__object_node, object);
+ node_addr = kernel_tex_fetch(__object_node, object);
}
else {
/* pop */
object = OBJECT_NONE;
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
}
}
}
#endif /* FEATURE(BVH_INSTANCING) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
+ } while(node_addr != ENTRYPOINT_SENTINEL);
#if BVH_FEATURE(BVH_INSTANCING)
- if(stackPtr >= 0) {
+ if(stack_ptr >= 0) {
kernel_assert(object != OBJECT_NONE);
+ /* Instance pop. */
if(num_hits_in_instance) {
float t_fac;
# if BVH_FEATURE(BVH_MOTION)
@@ -368,16 +367,19 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
Psplat[2] = ssef(P.z);
tsplat = ssef(0.0f, 0.0f, -isect_t, -isect_t);
+# if BVH_FEATURE(BVH_HAIR)
+ tfar = ssef(isect_t);
+# endif
gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
# endif
object = OBJECT_NONE;
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
}
-#endif /* FEATURE(BVH_MOTION) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
+#endif /* FEATURE(BVH_INSTANCING) */
+ } while(node_addr != ENTRYPOINT_SENTINEL);
return num_hits;
}
@@ -410,3 +412,4 @@ ccl_device_inline uint BVH_FUNCTION_NAME(KernelGlobals *kg,
#undef BVH_FUNCTION_NAME
#undef BVH_FUNCTION_FEATURES
+#undef NODE_INTERSECT
diff --git a/intern/cycles/kernel/bvh/qbvh_nodes.h b/intern/cycles/kernel/bvh/qbvh_nodes.h
new file mode 100644
index 00000000000..6d22f0b0d6a
--- /dev/null
+++ b/intern/cycles/kernel/bvh/qbvh_nodes.h
@@ -0,0 +1,465 @@
+/*
+ * Copyright 2011-2014, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Aligned nodes intersection SSE code is adopted from Embree,
+ */
+
+struct QBVHStackItem {
+ int addr;
+ float dist;
+};
+
+ccl_device_inline void qbvh_near_far_idx_calc(const float3& idir,
+ int *ccl_restrict near_x,
+ int *ccl_restrict near_y,
+ int *ccl_restrict near_z,
+ int *ccl_restrict far_x,
+ int *ccl_restrict far_y,
+ int *ccl_restrict far_z)
+
+{
+#ifdef __KERNEL_SSE__
+ *near_x = 0; *far_x = 1;
+ *near_y = 2; *far_y = 3;
+ *near_z = 4; *far_z = 5;
+
+ const size_t mask = movemask(ssef(idir.m128));
+
+ const int mask_x = mask & 1;
+ const int mask_y = (mask & 2) >> 1;
+ const int mask_z = (mask & 4) >> 2;
+
+ *near_x += mask_x; *far_x -= mask_x;
+ *near_y += mask_y; *far_y -= mask_y;
+ *near_z += mask_z; *far_z -= mask_z;
+#else
+ if(idir.x >= 0.0f) { *near_x = 0; *far_x = 1; } else { *near_x = 1; *far_x = 0; }
+ if(idir.y >= 0.0f) { *near_y = 2; *far_y = 3; } else { *near_y = 3; *far_y = 2; }
+ if(idir.z >= 0.0f) { *near_z = 4; *far_z = 5; } else { *near_z = 5; *far_z = 4; }
+#endif
+}
+
+/* TOOD(sergey): Investigate if using intrinsics helps for both
+ * stack item swap and float comparison.
+ */
+ccl_device_inline void qbvh_item_swap(QBVHStackItem *ccl_restrict a,
+ QBVHStackItem *ccl_restrict b)
+{
+ QBVHStackItem tmp = *a;
+ *a = *b;
+ *b = tmp;
+}
+
+ccl_device_inline void qbvh_stack_sort(QBVHStackItem *ccl_restrict s1,
+ QBVHStackItem *ccl_restrict s2,
+ QBVHStackItem *ccl_restrict s3)
+{
+ if(s2->dist < s1->dist) { qbvh_item_swap(s2, s1); }
+ if(s3->dist < s2->dist) { qbvh_item_swap(s3, s2); }
+ if(s2->dist < s1->dist) { qbvh_item_swap(s2, s1); }
+}
+
+ccl_device_inline void qbvh_stack_sort(QBVHStackItem *ccl_restrict s1,
+ QBVHStackItem *ccl_restrict s2,
+ QBVHStackItem *ccl_restrict s3,
+ QBVHStackItem *ccl_restrict s4)
+{
+ if(s2->dist < s1->dist) { qbvh_item_swap(s2, s1); }
+ if(s4->dist < s3->dist) { qbvh_item_swap(s4, s3); }
+ if(s3->dist < s1->dist) { qbvh_item_swap(s3, s1); }
+ if(s4->dist < s2->dist) { qbvh_item_swap(s4, s2); }
+ if(s3->dist < s2->dist) { qbvh_item_swap(s3, s2); }
+}
+
+/* Axis-aligned nodes intersection */
+
+ccl_device_inline int qbvh_aligned_node_intersect(KernelGlobals *ccl_restrict kg,
+ const ssef& isect_near,
+ const ssef& isect_far,
+#ifdef __KERNEL_AVX2__
+ const sse3f& org_idir,
+#else
+ const sse3f& org,
+#endif
+ const sse3f& idir,
+ const int near_x,
+ const int near_y,
+ const int near_z,
+ const int far_x,
+ const int far_y,
+ const int far_z,
+ const int node_addr,
+ ssef *ccl_restrict dist)
+{
+ const int offset = node_addr + 1;
+#ifdef __KERNEL_AVX2__
+ const ssef tnear_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x), idir.x, org_idir.x);
+ const ssef tnear_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y), idir.y, org_idir.y);
+ const ssef tnear_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z), idir.z, org_idir.z);
+ const ssef tfar_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x), idir.x, org_idir.x);
+ const ssef tfar_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y), idir.y, org_idir.y);
+ const ssef tfar_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z), idir.z, org_idir.z);
+#else
+ const ssef tnear_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x) - org.x) * idir.x;
+ const ssef tnear_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y) - org.y) * idir.y;
+ const ssef tnear_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z) - org.z) * idir.z;
+ const ssef tfar_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x) - org.x) * idir.x;
+ const ssef tfar_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y) - org.y) * idir.y;
+ const ssef tfar_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z) - org.z) * idir.z;
+#endif
+
+#ifdef __KERNEL_SSE41__
+ const ssef tnear = maxi(maxi(tnear_x, tnear_y), maxi(tnear_z, isect_near));
+ const ssef tfar = mini(mini(tfar_x, tfar_y), mini(tfar_z, isect_far));
+ const sseb vmask = cast(tnear) > cast(tfar);
+ int mask = (int)movemask(vmask)^0xf;
+#else
+ const ssef tnear = max4(tnear_x, tnear_y, tnear_z, isect_near);
+ const ssef tfar = min4(tfar_x, tfar_y, tfar_z, isect_far);
+ const sseb vmask = tnear <= tfar;
+ int mask = (int)movemask(vmask);
+#endif
+ *dist = tnear;
+ return mask;
+}
+
+ccl_device_inline int qbvh_aligned_node_intersect_robust(
+ KernelGlobals *ccl_restrict kg,
+ const ssef& isect_near,
+ const ssef& isect_far,
+#ifdef __KERNEL_AVX2__
+ const sse3f& P_idir,
+#else
+ const sse3f& P,
+#endif
+ const sse3f& idir,
+ const int near_x,
+ const int near_y,
+ const int near_z,
+ const int far_x,
+ const int far_y,
+ const int far_z,
+ const int node_addr,
+ const float difl,
+ ssef *ccl_restrict dist)
+{
+ const int offset = node_addr + 1;
+#ifdef __KERNEL_AVX2__
+ const ssef tnear_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x), idir.x, P_idir.x);
+ const ssef tnear_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y), idir.y, P_idir.y);
+ const ssef tnear_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z), idir.z, P_idir.z);
+ const ssef tfar_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x), idir.x, P_idir.x);
+ const ssef tfar_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y), idir.y, P_idir.y);
+ const ssef tfar_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z), idir.z, P_idir.z);
+#else
+ const ssef tnear_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x) - P.x) * idir.x;
+ const ssef tnear_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y) - P.y) * idir.y;
+ const ssef tnear_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z) - P.z) * idir.z;
+ const ssef tfar_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x) - P.x) * idir.x;
+ const ssef tfar_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y) - P.y) * idir.y;
+ const ssef tfar_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z) - P.z) * idir.z;
+#endif
+
+ const float round_down = 1.0f - difl;
+ const float round_up = 1.0f + difl;
+ const ssef tnear = max4(tnear_x, tnear_y, tnear_z, isect_near);
+ const ssef tfar = min4(tfar_x, tfar_y, tfar_z, isect_far);
+ const sseb vmask = round_down*tnear <= round_up*tfar;
+ *dist = tnear;
+ return (int)movemask(vmask);
+}
+
+/* Unaligned nodes intersection */
+
+ccl_device_inline int qbvh_unaligned_node_intersect(
+ KernelGlobals *ccl_restrict kg,
+ const ssef& isect_near,
+ const ssef& isect_far,
+#ifdef __KERNEL_AVX2__
+ const sse3f& org_idir,
+#endif
+ const sse3f& org,
+ const sse3f& dir,
+ const sse3f& idir,
+ const int near_x,
+ const int near_y,
+ const int near_z,
+ const int far_x,
+ const int far_y,
+ const int far_z,
+ const int node_addr,
+ ssef *ccl_restrict dist)
+{
+ const int offset = node_addr;
+ const ssef tfm_x_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+1);
+ const ssef tfm_x_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+2);
+ const ssef tfm_x_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+3);
+
+ const ssef tfm_y_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+4);
+ const ssef tfm_y_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+5);
+ const ssef tfm_y_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+6);
+
+ const ssef tfm_z_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+7);
+ const ssef tfm_z_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+8);
+ const ssef tfm_z_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+9);
+
+ const ssef tfm_t_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+10);
+ const ssef tfm_t_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+11);
+ const ssef tfm_t_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+12);
+
+ const ssef aligned_dir_x = dir.x*tfm_x_x + dir.y*tfm_x_y + dir.z*tfm_x_z,
+ aligned_dir_y = dir.x*tfm_y_x + dir.y*tfm_y_y + dir.z*tfm_y_z,
+ aligned_dir_z = dir.x*tfm_z_x + dir.y*tfm_z_y + dir.z*tfm_z_z;
+
+ const ssef aligned_P_x = org.x*tfm_x_x + org.y*tfm_x_y + org.z*tfm_x_z + tfm_t_x,
+ aligned_P_y = org.x*tfm_y_x + org.y*tfm_y_y + org.z*tfm_y_z + tfm_t_y,
+ aligned_P_z = org.x*tfm_z_x + org.y*tfm_z_y + org.z*tfm_z_z + tfm_t_z;
+
+ const ssef neg_one(-1.0f, -1.0f, -1.0f, -1.0f);
+ const ssef nrdir_x = neg_one / aligned_dir_x,
+ nrdir_y = neg_one / aligned_dir_y,
+ nrdir_z = neg_one / aligned_dir_z;
+
+ const ssef tlower_x = aligned_P_x * nrdir_x,
+ tlower_y = aligned_P_y * nrdir_y,
+ tlower_z = aligned_P_z * nrdir_z;
+
+ const ssef tupper_x = tlower_x - nrdir_x,
+ tupper_y = tlower_y - nrdir_y,
+ tupper_z = tlower_z - nrdir_z;
+
+#ifdef __KERNEL_SSE41__
+ const ssef tnear_x = mini(tlower_x, tupper_x);
+ const ssef tnear_y = mini(tlower_y, tupper_y);
+ const ssef tnear_z = mini(tlower_z, tupper_z);
+ const ssef tfar_x = maxi(tlower_x, tupper_x);
+ const ssef tfar_y = maxi(tlower_y, tupper_y);
+ const ssef tfar_z = maxi(tlower_z, tupper_z);
+ const ssef tnear = max4(isect_near, tnear_x, tnear_y, tnear_z);
+ const ssef tfar = min4(isect_far, tfar_x, tfar_y, tfar_z);
+ const sseb vmask = tnear <= tfar;
+ *dist = tnear;
+ return movemask(vmask);
+#else
+ const ssef tnear_x = min(tlower_x, tupper_x);
+ const ssef tnear_y = min(tlower_y, tupper_y);
+ const ssef tnear_z = min(tlower_z, tupper_z);
+ const ssef tfar_x = max(tlower_x, tupper_x);
+ const ssef tfar_y = max(tlower_y, tupper_y);
+ const ssef tfar_z = max(tlower_z, tupper_z);
+ const ssef tnear = max4(isect_near, tnear_x, tnear_y, tnear_z);
+ const ssef tfar = min4(isect_far, tfar_x, tfar_y, tfar_z);
+ const sseb vmask = tnear <= tfar;
+ *dist = tnear;
+ return movemask(vmask);
+#endif
+}
+
+ccl_device_inline int qbvh_unaligned_node_intersect_robust(
+ KernelGlobals *ccl_restrict kg,
+ const ssef& isect_near,
+ const ssef& isect_far,
+#ifdef __KERNEL_AVX2__
+ const sse3f& P_idir,
+#endif
+ const sse3f& P,
+ const sse3f& dir,
+ const sse3f& idir,
+ const int near_x,
+ const int near_y,
+ const int near_z,
+ const int far_x,
+ const int far_y,
+ const int far_z,
+ const int node_addr,
+ const float difl,
+ ssef *ccl_restrict dist)
+{
+ const int offset = node_addr;
+ const ssef tfm_x_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+1);
+ const ssef tfm_x_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+2);
+ const ssef tfm_x_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+3);
+
+ const ssef tfm_y_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+4);
+ const ssef tfm_y_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+5);
+ const ssef tfm_y_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+6);
+
+ const ssef tfm_z_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+7);
+ const ssef tfm_z_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+8);
+ const ssef tfm_z_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+9);
+
+ const ssef tfm_t_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+10);
+ const ssef tfm_t_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+11);
+ const ssef tfm_t_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+12);
+
+ const ssef aligned_dir_x = dir.x*tfm_x_x + dir.y*tfm_x_y + dir.z*tfm_x_z,
+ aligned_dir_y = dir.x*tfm_y_x + dir.y*tfm_y_y + dir.z*tfm_y_z,
+ aligned_dir_z = dir.x*tfm_z_x + dir.y*tfm_z_y + dir.z*tfm_z_z;
+
+ const ssef aligned_P_x = P.x*tfm_x_x + P.y*tfm_x_y + P.z*tfm_x_z + tfm_t_x,
+ aligned_P_y = P.x*tfm_y_x + P.y*tfm_y_y + P.z*tfm_y_z + tfm_t_y,
+ aligned_P_z = P.x*tfm_z_x + P.y*tfm_z_y + P.z*tfm_z_z + tfm_t_z;
+
+ const ssef neg_one(-1.0f, -1.0f, -1.0f, -1.0f);
+ const ssef nrdir_x = neg_one / aligned_dir_x,
+ nrdir_y = neg_one / aligned_dir_y,
+ nrdir_z = neg_one / aligned_dir_z;
+
+ const ssef tlower_x = aligned_P_x * nrdir_x,
+ tlower_y = aligned_P_y * nrdir_y,
+ tlower_z = aligned_P_z * nrdir_z;
+
+ const ssef tupper_x = tlower_x - nrdir_x,
+ tupper_y = tlower_y - nrdir_y,
+ tupper_z = tlower_z - nrdir_z;
+
+ const float round_down = 1.0f - difl;
+ const float round_up = 1.0f + difl;
+
+#ifdef __KERNEL_SSE41__
+ const ssef tnear_x = mini(tlower_x, tupper_x);
+ const ssef tnear_y = mini(tlower_y, tupper_y);
+ const ssef tnear_z = mini(tlower_z, tupper_z);
+ const ssef tfar_x = maxi(tlower_x, tupper_x);
+ const ssef tfar_y = maxi(tlower_y, tupper_y);
+ const ssef tfar_z = maxi(tlower_z, tupper_z);
+#else
+ const ssef tnear_x = min(tlower_x, tupper_x);
+ const ssef tnear_y = min(tlower_y, tupper_y);
+ const ssef tnear_z = min(tlower_z, tupper_z);
+ const ssef tfar_x = max(tlower_x, tupper_x);
+ const ssef tfar_y = max(tlower_y, tupper_y);
+ const ssef tfar_z = max(tlower_z, tupper_z);
+#endif
+ const ssef tnear = max4(isect_near, tnear_x, tnear_y, tnear_z);
+ const ssef tfar = min4(isect_far, tfar_x, tfar_y, tfar_z);
+ const sseb vmask = round_down*tnear <= round_up*tfar;
+ *dist = tnear;
+ return movemask(vmask);
+}
+
+/* Intersectors wrappers.
+ *
+ * They'll check node type and call appropriate intersection code.
+ */
+
+ccl_device_inline int qbvh_node_intersect(
+ KernelGlobals *ccl_restrict kg,
+ const ssef& isect_near,
+ const ssef& isect_far,
+#ifdef __KERNEL_AVX2__
+ const sse3f& org_idir,
+#endif
+ const sse3f& org,
+ const sse3f& dir,
+ const sse3f& idir,
+ const int near_x,
+ const int near_y,
+ const int near_z,
+ const int far_x,
+ const int far_y,
+ const int far_z,
+ const int node_addr,
+ ssef *ccl_restrict dist)
+{
+ const int offset = node_addr;
+ const float4 node = kernel_tex_fetch(__bvh_nodes, offset);
+ if(__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) {
+ return qbvh_unaligned_node_intersect(kg,
+ isect_near,
+ isect_far,
+#ifdef __KERNEL_AVX2__
+ org_idir,
+#endif
+ org,
+ dir,
+ idir,
+ near_x, near_y, near_z,
+ far_x, far_y, far_z,
+ node_addr,
+ dist);
+ }
+ else {
+ return qbvh_aligned_node_intersect(kg,
+ isect_near,
+ isect_far,
+#ifdef __KERNEL_AVX2__
+ org_idir,
+#else
+ org,
+#endif
+ idir,
+ near_x, near_y, near_z,
+ far_x, far_y, far_z,
+ node_addr,
+ dist);
+ }
+}
+
+ccl_device_inline int qbvh_node_intersect_robust(
+ KernelGlobals *ccl_restrict kg,
+ const ssef& isect_near,
+ const ssef& isect_far,
+#ifdef __KERNEL_AVX2__
+ const sse3f& P_idir,
+#endif
+ const sse3f& P,
+ const sse3f& dir,
+ const sse3f& idir,
+ const int near_x,
+ const int near_y,
+ const int near_z,
+ const int far_x,
+ const int far_y,
+ const int far_z,
+ const int node_addr,
+ const float difl,
+ ssef *ccl_restrict dist)
+{
+ const int offset = node_addr;
+ const float4 node = kernel_tex_fetch(__bvh_nodes, offset);
+ if(__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) {
+ return qbvh_unaligned_node_intersect_robust(kg,
+ isect_near,
+ isect_far,
+#ifdef __KERNEL_AVX2__
+ P_idir,
+#endif
+ P,
+ dir,
+ idir,
+ near_x, near_y, near_z,
+ far_x, far_y, far_z,
+ node_addr,
+ difl,
+ dist);
+ }
+ else {
+ return qbvh_aligned_node_intersect_robust(kg,
+ isect_near,
+ isect_far,
+#ifdef __KERNEL_AVX2__
+ P_idir,
+#else
+ P,
+#endif
+ idir,
+ near_x, near_y, near_z,
+ far_x, far_y, far_z,
+ node_addr,
+ difl,
+ dist);
+ }
+}
diff --git a/intern/cycles/kernel/bvh/qbvh_shadow_all.h b/intern/cycles/kernel/bvh/qbvh_shadow_all.h
new file mode 100644
index 00000000000..5f4d06f12ea
--- /dev/null
+++ b/intern/cycles/kernel/bvh/qbvh_shadow_all.h
@@ -0,0 +1,480 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* This is a template BVH traversal function, where various features can be
+ * enabled/disabled. This way we can compile optimized versions for each case
+ * without new features slowing things down.
+ *
+ * BVH_INSTANCING: object instancing
+ * BVH_HAIR: hair curve rendering
+ * BVH_MOTION: motion blur rendering
+ *
+ */
+
+#if BVH_FEATURE(BVH_HAIR)
+# define NODE_INTERSECT qbvh_node_intersect
+#else
+# define NODE_INTERSECT qbvh_aligned_node_intersect
+#endif
+
+ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
+ const Ray *ray,
+ Intersection *isect_array,
+ const uint max_hits,
+ uint *num_hits)
+{
+ /* TODO(sergey):
+ * - Test if pushing distance on the stack helps.
+ * - Likely and unlikely for if() statements.
+ * - Test restrict attribute for pointers.
+ */
+
+ /* Traversal stack in CUDA thread-local memory. */
+ QBVHStackItem traversal_stack[BVH_QSTACK_SIZE];
+ traversal_stack[0].addr = ENTRYPOINT_SENTINEL;
+
+ /* Traversal variables in registers. */
+ int stack_ptr = 0;
+ int node_addr = kernel_data.bvh.root;
+
+ /* Ray parameters in registers. */
+ const float tmax = ray->t;
+ float3 P = ray->P;
+ float3 dir = bvh_clamp_direction(ray->D);
+ float3 idir = bvh_inverse_direction(dir);
+ int object = OBJECT_NONE;
+ float isect_t = tmax;
+
+#if BVH_FEATURE(BVH_MOTION)
+ Transform ob_itfm;
+#endif
+
+ *num_hits = 0;
+ isect_array->t = tmax;
+
+#ifndef __KERNEL_SSE41__
+ if(!isfinite(P.x)) {
+ return false;
+ }
+#endif
+
+#if BVH_FEATURE(BVH_INSTANCING)
+ int num_hits_in_instance = 0;
+#endif
+
+ ssef tnear(0.0f), tfar(isect_t);
+#if BVH_FEATURE(BVH_HAIR)
+ sse3f dir4(ssef(dir.x), ssef(dir.y), ssef(dir.z));
+#endif
+ sse3f idir4(ssef(idir.x), ssef(idir.y), ssef(idir.z));
+
+#ifdef __KERNEL_AVX2__
+ float3 P_idir = P*idir;
+ sse3f P_idir4(P_idir.x, P_idir.y, P_idir.z);
+#endif
+#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ sse3f org4(ssef(P.x), ssef(P.y), ssef(P.z));
+#endif
+
+ /* Offsets to select the side that becomes the lower or upper bound. */
+ int near_x, near_y, near_z;
+ int far_x, far_y, far_z;
+ qbvh_near_far_idx_calc(idir,
+ &near_x, &near_y, &near_z,
+ &far_x, &far_y, &far_z);
+
+ IsectPrecalc isect_precalc;
+ triangle_intersect_precalc(dir, &isect_precalc);
+
+ /* Traversal loop. */
+ do {
+ do {
+ /* Traverse internal nodes. */
+ while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
+ float4 inodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
+
+#ifdef __VISIBILITY_FLAG__
+ if((__float_as_uint(inodes.x) & PATH_RAY_SHADOW) == 0) {
+ /* Pop. */
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
+ continue;
+ }
+#endif
+
+ ssef dist;
+ int child_mask = NODE_INTERSECT(kg,
+ tnear,
+ tfar,
+#ifdef __KERNEL_AVX2__
+ P_idir4,
+#endif
+#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ org4,
+#endif
+#if BVH_FEATURE(BVH_HAIR)
+ dir4,
+#endif
+ idir4,
+ near_x, near_y, near_z,
+ far_x, far_y, far_z,
+ node_addr,
+ &dist);
+
+ if(child_mask != 0) {
+ float4 cnodes;
+#if BVH_FEATURE(BVH_HAIR)
+ if(__float_as_uint(inodes.x) & PATH_RAY_NODE_UNALIGNED) {
+ cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+13);
+ }
+ else
+#endif
+ {
+ cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+7);
+ }
+
+ /* One child is hit, continue with that child. */
+ int r = __bscf(child_mask);
+ if(child_mask == 0) {
+ node_addr = __float_as_int(cnodes[r]);
+ continue;
+ }
+
+ /* Two children are hit, push far child, and continue with
+ * closer child.
+ */
+ int c0 = __float_as_int(cnodes[r]);
+ float d0 = ((float*)&dist)[r];
+ r = __bscf(child_mask);
+ int c1 = __float_as_int(cnodes[r]);
+ float d1 = ((float*)&dist)[r];
+ if(child_mask == 0) {
+ if(d1 < d0) {
+ node_addr = c1;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c0;
+ traversal_stack[stack_ptr].dist = d0;
+ continue;
+ }
+ else {
+ node_addr = c0;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c1;
+ traversal_stack[stack_ptr].dist = d1;
+ continue;
+ }
+ }
+
+ /* Here starts the slow path for 3 or 4 hit children. We push
+ * all nodes onto the stack to sort them there.
+ */
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c1;
+ traversal_stack[stack_ptr].dist = d1;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c0;
+ traversal_stack[stack_ptr].dist = d0;
+
+ /* Three children are hit, push all onto stack and sort 3
+ * stack items, continue with closest child.
+ */
+ r = __bscf(child_mask);
+ int c2 = __float_as_int(cnodes[r]);
+ float d2 = ((float*)&dist)[r];
+ if(child_mask == 0) {
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c2;
+ traversal_stack[stack_ptr].dist = d2;
+ qbvh_stack_sort(&traversal_stack[stack_ptr],
+ &traversal_stack[stack_ptr - 1],
+ &traversal_stack[stack_ptr - 2]);
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
+ continue;
+ }
+
+ /* Four children are hit, push all onto stack and sort 4
+ * stack items, continue with closest child.
+ */
+ r = __bscf(child_mask);
+ int c3 = __float_as_int(cnodes[r]);
+ float d3 = ((float*)&dist)[r];
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c3;
+ traversal_stack[stack_ptr].dist = d3;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c2;
+ traversal_stack[stack_ptr].dist = d2;
+ qbvh_stack_sort(&traversal_stack[stack_ptr],
+ &traversal_stack[stack_ptr - 1],
+ &traversal_stack[stack_ptr - 2],
+ &traversal_stack[stack_ptr - 3]);
+ }
+
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
+ }
+
+ /* If node is leaf, fetch triangle list. */
+ if(node_addr < 0) {
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1));
+#ifdef __VISIBILITY_FLAG__
+ if((__float_as_uint(leaf.z) & PATH_RAY_SHADOW) == 0) {
+ /* Pop. */
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
+ continue;
+ }
+#endif
+
+ int prim_addr = __float_as_int(leaf.x);
+
+#if BVH_FEATURE(BVH_INSTANCING)
+ if(prim_addr >= 0) {
+#endif
+ int prim_addr2 = __float_as_int(leaf.y);
+ const uint type = __float_as_int(leaf.w);
+ const uint p_type = type & PRIMITIVE_ALL;
+
+ /* Pop. */
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
+
+ /* Primitive intersection. */
+ while(prim_addr < prim_addr2) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
+
+ bool hit;
+
+ /* todo: specialized intersect functions which don't fill in
+ * isect unless needed and check SD_HAS_TRANSPARENT_SHADOW?
+ * might give a few % performance improvement */
+
+ switch(p_type) {
+ case PRIMITIVE_TRIANGLE: {
+ hit = triangle_intersect(kg,
+ &isect_precalc,
+ isect_array,
+ P,
+ PATH_RAY_SHADOW,
+ object,
+ prim_addr);
+ break;
+ }
+#if BVH_FEATURE(BVH_MOTION)
+ case PRIMITIVE_MOTION_TRIANGLE: {
+ hit = motion_triangle_intersect(kg,
+ isect_array,
+ P,
+ dir,
+ ray->time,
+ PATH_RAY_SHADOW,
+ object,
+ prim_addr);
+ break;
+ }
+#endif
+#if BVH_FEATURE(BVH_HAIR)
+ case PRIMITIVE_CURVE:
+ case PRIMITIVE_MOTION_CURVE: {
+ if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) {
+ hit = bvh_cardinal_curve_intersect(kg,
+ isect_array,
+ P,
+ dir,
+ PATH_RAY_SHADOW,
+ object,
+ prim_addr,
+ ray->time,
+ type,
+ NULL,
+ 0, 0);
+ }
+ else {
+ hit = bvh_curve_intersect(kg,
+ isect_array,
+ P,
+ dir,
+ PATH_RAY_SHADOW,
+ object,
+ prim_addr,
+ ray->time,
+ type,
+ NULL,
+ 0, 0);
+ }
+ break;
+ }
+#endif
+ default: {
+ hit = false;
+ break;
+ }
+ }
+
+ /* Shadow ray early termination. */
+ if(hit) {
+ /* detect if this surface has a shader with transparent shadows */
+
+ /* todo: optimize so primitive visibility flag indicates if
+ * the primitive has a transparent shadow shader? */
+ int prim = kernel_tex_fetch(__prim_index, isect_array->prim);
+ int shader = 0;
+
+#ifdef __HAIR__
+ if(kernel_tex_fetch(__prim_type, isect_array->prim) & PRIMITIVE_ALL_TRIANGLE)
+#endif
+ {
+ shader = kernel_tex_fetch(__tri_shader, prim);
+ }
+#ifdef __HAIR__
+ else {
+ float4 str = kernel_tex_fetch(__curves, prim);
+ shader = __float_as_int(str.z);
+ }
+#endif
+ int flag = kernel_tex_fetch(__shader_flag, (shader & SHADER_MASK)*SHADER_SIZE);
+
+ /* if no transparent shadows, all light is blocked */
+ if(!(flag & SD_HAS_TRANSPARENT_SHADOW)) {
+ return true;
+ }
+ /* if maximum number of hits reached, block all light */
+ else if(*num_hits == max_hits) {
+ return true;
+ }
+
+ /* move on to next entry in intersections array */
+ isect_array++;
+ (*num_hits)++;
+#if BVH_FEATURE(BVH_INSTANCING)
+ num_hits_in_instance++;
+#endif
+
+ isect_array->t = isect_t;
+ }
+
+ prim_addr++;
+ }
+ }
+#if BVH_FEATURE(BVH_INSTANCING)
+ else {
+ /* Instance push. */
+ object = kernel_tex_fetch(__prim_object, -prim_addr-1);
+
+# if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect_t, &ob_itfm);
+# else
+ bvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect_t);
+# endif
+
+ num_hits_in_instance = 0;
+ isect_array->t = isect_t;
+
+ qbvh_near_far_idx_calc(idir,
+ &near_x, &near_y, &near_z,
+ &far_x, &far_y, &far_z);
+ tfar = ssef(isect_t);
+# if BVH_FEATURE(BVH_HAIR)
+ dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z));
+# endif
+ idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
+# ifdef __KERNEL_AVX2__
+ P_idir = P*idir;
+ P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
+# endif
+# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
+# endif
+
+ triangle_intersect_precalc(dir, &isect_precalc);
+
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = ENTRYPOINT_SENTINEL;
+
+ node_addr = kernel_tex_fetch(__object_node, object);
+
+ }
+ }
+#endif /* FEATURE(BVH_INSTANCING) */
+ } while(node_addr != ENTRYPOINT_SENTINEL);
+
+#if BVH_FEATURE(BVH_INSTANCING)
+ if(stack_ptr >= 0) {
+ kernel_assert(object != OBJECT_NONE);
+
+ /* Instance pop. */
+ if(num_hits_in_instance) {
+ float t_fac;
+# if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_pop_factor(kg, object, ray, &P, &dir, &idir, &t_fac, &ob_itfm);
+# else
+ bvh_instance_pop_factor(kg, object, ray, &P, &dir, &idir, &t_fac);
+# endif
+ /* Scale isect->t to adjust for instancing. */
+ for(int i = 0; i < num_hits_in_instance; i++) {
+ (isect_array-i-1)->t *= t_fac;
+ }
+ }
+ else {
+ float ignore_t = FLT_MAX;
+# if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &ignore_t, &ob_itfm);
+# else
+ bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &ignore_t);
+# endif
+ }
+
+ isect_t = tmax;
+ isect_array->t = isect_t;
+
+ qbvh_near_far_idx_calc(idir,
+ &near_x, &near_y, &near_z,
+ &far_x, &far_y, &far_z);
+ tfar = ssef(isect_t);
+# if BVH_FEATURE(BVH_HAIR)
+ dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z));
+# endif
+ idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
+# ifdef __KERNEL_AVX2__
+ P_idir = P*idir;
+ P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
+# endif
+# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
+# endif
+
+ triangle_intersect_precalc(dir, &isect_precalc);
+
+ object = OBJECT_NONE;
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
+ }
+#endif /* FEATURE(BVH_INSTANCING) */
+ } while(node_addr != ENTRYPOINT_SENTINEL);
+
+ return false;
+}
+
+#undef NODE_INTERSECT
diff --git a/intern/cycles/kernel/geom/geom_qbvh_subsurface.h b/intern/cycles/kernel/bvh/qbvh_subsurface.h
index 84512a8783c..ccd36df034a 100644
--- a/intern/cycles/kernel/geom/geom_qbvh_subsurface.h
+++ b/intern/cycles/kernel/bvh/qbvh_subsurface.h
@@ -1,8 +1,5 @@
/*
- * Adapted from code Copyright 2009-2010 NVIDIA Corporation,
- * and code copyright 2009-2012 Intel Corporation
- *
- * Modifications Copyright 2011-2014, Blender Foundation.
+ * Copyright 2011-2013 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,6 +22,12 @@
*
*/
+#if BVH_FEATURE(BVH_HAIR)
+# define NODE_INTERSECT qbvh_node_intersect
+#else
+# define NODE_INTERSECT qbvh_aligned_node_intersect
+#endif
+
ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
const Ray *ray,
SubsurfaceIntersection *ss_isect,
@@ -41,12 +44,12 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
*/
/* Traversal stack in CUDA thread-local memory. */
- QBVHStackItem traversalStack[BVH_QSTACK_SIZE];
- traversalStack[0].addr = ENTRYPOINT_SENTINEL;
+ QBVHStackItem traversal_stack[BVH_QSTACK_SIZE];
+ traversal_stack[0].addr = ENTRYPOINT_SENTINEL;
/* Traversal variables in registers. */
- int stackPtr = 0;
- int nodeAddr = kernel_tex_fetch(__object_node, subsurface_object);
+ int stack_ptr = 0;
+ int node_addr = kernel_tex_fetch(__object_node, subsurface_object);
/* Ray parameters in registers. */
float3 P = ray->P;
@@ -82,22 +85,25 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
#endif
ssef tnear(0.0f), tfar(isect_t);
+#if BVH_FEATURE(BVH_HAIR)
+ sse3f dir4(ssef(dir.x), ssef(dir.y), ssef(dir.z));
+#endif
sse3f idir4(ssef(idir.x), ssef(idir.y), ssef(idir.z));
#ifdef __KERNEL_AVX2__
float3 P_idir = P*idir;
- sse3f P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-#else
- sse3f org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
+ sse3f P_idir4(P_idir.x, P_idir.y, P_idir.z);
+#endif
+#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ sse3f org4(ssef(P.x), ssef(P.y), ssef(P.z));
#endif
/* Offsets to select the side that becomes the lower or upper bound. */
int near_x, near_y, near_z;
int far_x, far_y, far_z;
-
- if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; }
- if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
- if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
+ qbvh_near_far_idx_calc(idir,
+ &near_x, &near_y, &near_z,
+ &far_x, &far_y, &far_z);
IsectPrecalc isect_precalc;
triangle_intersect_precalc(dir, &isect_precalc);
@@ -106,29 +112,43 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
do {
do {
/* Traverse internal nodes. */
- while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) {
+ while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
ssef dist;
- int traverseChild = qbvh_node_intersect(kg,
- tnear,
- tfar,
+ int child_mask = NODE_INTERSECT(kg,
+ tnear,
+ tfar,
#ifdef __KERNEL_AVX2__
- P_idir4,
-#else
- org,
+ P_idir4,
+#endif
+#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ org4,
#endif
- idir4,
- near_x, near_y, near_z,
- far_x, far_y, far_z,
- nodeAddr,
- &dist);
+#if BVH_FEATURE(BVH_HAIR)
+ dir4,
+#endif
+ idir4,
+ near_x, near_y, near_z,
+ far_x, far_y, far_z,
+ node_addr,
+ &dist);
- if(traverseChild != 0) {
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_QNODE_SIZE+6);
+ if(child_mask != 0) {
+ float4 inodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
+ float4 cnodes;
+#if BVH_FEATURE(BVH_HAIR)
+ if(__float_as_uint(inodes.x) & PATH_RAY_NODE_UNALIGNED) {
+ cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+13);
+ }
+ else
+#endif
+ {
+ cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+7);
+ }
/* One child is hit, continue with that child. */
- int r = __bscf(traverseChild);
- if(traverseChild == 0) {
- nodeAddr = __float_as_int(cnodes[r]);
+ int r = __bscf(child_mask);
+ if(child_mask == 0) {
+ node_addr = __float_as_int(cnodes[r]);
continue;
}
@@ -137,24 +157,24 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
*/
int c0 = __float_as_int(cnodes[r]);
float d0 = ((float*)&dist)[r];
- r = __bscf(traverseChild);
+ r = __bscf(child_mask);
int c1 = __float_as_int(cnodes[r]);
float d1 = ((float*)&dist)[r];
- if(traverseChild == 0) {
+ if(child_mask == 0) {
if(d1 < d0) {
- nodeAddr = c1;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c0;
- traversalStack[stackPtr].dist = d0;
+ node_addr = c1;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c0;
+ traversal_stack[stack_ptr].dist = d0;
continue;
}
else {
- nodeAddr = c0;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c1;
- traversalStack[stackPtr].dist = d1;
+ node_addr = c0;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c1;
+ traversal_stack[stack_ptr].dist = d1;
continue;
}
}
@@ -162,82 +182,82 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
/* Here starts the slow path for 3 or 4 hit children. We push
* all nodes onto the stack to sort them there.
*/
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c1;
- traversalStack[stackPtr].dist = d1;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c0;
- traversalStack[stackPtr].dist = d0;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c1;
+ traversal_stack[stack_ptr].dist = d1;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c0;
+ traversal_stack[stack_ptr].dist = d0;
/* Three children are hit, push all onto stack and sort 3
* stack items, continue with closest child.
*/
- r = __bscf(traverseChild);
+ r = __bscf(child_mask);
int c2 = __float_as_int(cnodes[r]);
float d2 = ((float*)&dist)[r];
- if(traverseChild == 0) {
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c2;
- traversalStack[stackPtr].dist = d2;
- qbvh_stack_sort(&traversalStack[stackPtr],
- &traversalStack[stackPtr - 1],
- &traversalStack[stackPtr - 2]);
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ if(child_mask == 0) {
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c2;
+ traversal_stack[stack_ptr].dist = d2;
+ qbvh_stack_sort(&traversal_stack[stack_ptr],
+ &traversal_stack[stack_ptr - 1],
+ &traversal_stack[stack_ptr - 2]);
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
continue;
}
/* Four children are hit, push all onto stack and sort 4
* stack items, continue with closest child.
*/
- r = __bscf(traverseChild);
+ r = __bscf(child_mask);
int c3 = __float_as_int(cnodes[r]);
float d3 = ((float*)&dist)[r];
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c3;
- traversalStack[stackPtr].dist = d3;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c2;
- traversalStack[stackPtr].dist = d2;
- qbvh_stack_sort(&traversalStack[stackPtr],
- &traversalStack[stackPtr - 1],
- &traversalStack[stackPtr - 2],
- &traversalStack[stackPtr - 3]);
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c3;
+ traversal_stack[stack_ptr].dist = d3;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c2;
+ traversal_stack[stack_ptr].dist = d2;
+ qbvh_stack_sort(&traversal_stack[stack_ptr],
+ &traversal_stack[stack_ptr - 1],
+ &traversal_stack[stack_ptr - 2],
+ &traversal_stack[stack_ptr - 3]);
}
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
}
/* If node is leaf, fetch triangle list. */
- if(nodeAddr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_QNODE_LEAF_SIZE);
- int primAddr = __float_as_int(leaf.x);
+ if(node_addr < 0) {
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1));
+ int prim_addr = __float_as_int(leaf.x);
- int primAddr2 = __float_as_int(leaf.y);
+ int prim_addr2 = __float_as_int(leaf.y);
const uint type = __float_as_int(leaf.w);
/* Pop. */
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
/* Primitive intersection. */
switch(type & PRIMITIVE_ALL) {
case PRIMITIVE_TRIANGLE: {
/* Intersect ray against primitive, */
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
triangle_intersect_subsurface(kg,
&isect_precalc,
ss_isect,
P,
object,
- primAddr,
+ prim_addr,
isect_t,
lcg_state,
max_hits);
@@ -247,15 +267,15 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
#if BVH_FEATURE(BVH_MOTION)
case PRIMITIVE_MOTION_TRIANGLE: {
/* Intersect ray against primitive. */
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
motion_triangle_intersect_subsurface(kg,
ss_isect,
P,
dir,
ray->time,
object,
- primAddr,
+ prim_addr,
isect_t,
lcg_state,
max_hits);
@@ -267,6 +287,8 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
break;
}
}
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
+ } while(node_addr != ENTRYPOINT_SENTINEL);
+ } while(node_addr != ENTRYPOINT_SENTINEL);
}
+
+#undef NODE_INTERSECT
diff --git a/intern/cycles/kernel/bvh/qbvh_traversal.h b/intern/cycles/kernel/bvh/qbvh_traversal.h
new file mode 100644
index 00000000000..f2d8e558dcc
--- /dev/null
+++ b/intern/cycles/kernel/bvh/qbvh_traversal.h
@@ -0,0 +1,501 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* This is a template BVH traversal function, where various features can be
+ * enabled/disabled. This way we can compile optimized versions for each case
+ * without new features slowing things down.
+ *
+ * BVH_INSTANCING: object instancing
+ * BVH_HAIR: hair curve rendering
+ * BVH_HAIR_MINIMUM_WIDTH: hair curve rendering with minimum width
+ * BVH_MOTION: motion blur rendering
+ *
+ */
+
+#if BVH_FEATURE(BVH_HAIR)
+# define NODE_INTERSECT qbvh_node_intersect
+# define NODE_INTERSECT_ROBUST qbvh_node_intersect_robust
+#else
+# define NODE_INTERSECT qbvh_aligned_node_intersect
+# define NODE_INTERSECT_ROBUST qbvh_aligned_node_intersect_robust
+#endif
+
+ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
+ const Ray *ray,
+ Intersection *isect,
+ const uint visibility
+#if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH)
+ ,uint *lcg_state,
+ float difl,
+ float extmax
+#endif
+ )
+{
+ /* TODO(sergey):
+ * - Test if pushing distance on the stack helps (for non shadow rays).
+ * - Separate version for shadow rays.
+ * - Likely and unlikely for if() statements.
+ * - Test restrict attribute for pointers.
+ */
+
+ /* Traversal stack in CUDA thread-local memory. */
+ QBVHStackItem traversal_stack[BVH_QSTACK_SIZE];
+ traversal_stack[0].addr = ENTRYPOINT_SENTINEL;
+ traversal_stack[0].dist = -FLT_MAX;
+
+ /* Traversal variables in registers. */
+ int stack_ptr = 0;
+ int node_addr = kernel_data.bvh.root;
+ float node_dist = -FLT_MAX;
+
+ /* Ray parameters in registers. */
+ float3 P = ray->P;
+ float3 dir = bvh_clamp_direction(ray->D);
+ float3 idir = bvh_inverse_direction(dir);
+ int object = OBJECT_NONE;
+
+#if BVH_FEATURE(BVH_MOTION)
+ Transform ob_itfm;
+#endif
+
+#ifndef __KERNEL_SSE41__
+ if(!isfinite(P.x)) {
+ return false;
+ }
+#endif
+
+ isect->t = ray->t;
+ isect->u = 0.0f;
+ isect->v = 0.0f;
+ isect->prim = PRIM_NONE;
+ isect->object = OBJECT_NONE;
+
+ BVH_DEBUG_INIT();
+
+ ssef tnear(0.0f), tfar(ray->t);
+#if BVH_FEATURE(BVH_HAIR)
+ sse3f dir4(ssef(dir.x), ssef(dir.y), ssef(dir.z));
+#endif
+ sse3f idir4(ssef(idir.x), ssef(idir.y), ssef(idir.z));
+
+#ifdef __KERNEL_AVX2__
+ float3 P_idir = P*idir;
+ sse3f P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
+#endif
+#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ sse3f org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
+#endif
+
+ /* Offsets to select the side that becomes the lower or upper bound. */
+ int near_x, near_y, near_z;
+ int far_x, far_y, far_z;
+ qbvh_near_far_idx_calc(idir,
+ &near_x, &near_y, &near_z,
+ &far_x, &far_y, &far_z);
+
+ IsectPrecalc isect_precalc;
+ triangle_intersect_precalc(dir, &isect_precalc);
+
+ /* Traversal loop. */
+ do {
+ do {
+ /* Traverse internal nodes. */
+ while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
+ float4 inodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
+
+ if(UNLIKELY(node_dist > isect->t)
+#ifdef __VISIBILITY_FLAG__
+ || (__float_as_uint(inodes.x) & visibility) == 0)
+#endif
+ {
+ /* Pop. */
+ node_addr = traversal_stack[stack_ptr].addr;
+ node_dist = traversal_stack[stack_ptr].dist;
+ --stack_ptr;
+ continue;
+ }
+
+ int child_mask;
+ ssef dist;
+
+ BVH_DEBUG_NEXT_STEP();
+
+#if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH)
+ if(difl != 0.0f) {
+ /* NOTE: We extend all the child BB instead of fetching
+ * and checking visibility flags for each of the,
+ *
+ * Need to test if doing opposite would be any faster.
+ */
+ child_mask = NODE_INTERSECT_ROBUST(kg,
+ tnear,
+ tfar,
+# ifdef __KERNEL_AVX2__
+ P_idir4,
+# endif
+# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ org4,
+# endif
+# if BVH_FEATURE(BVH_HAIR)
+ dir4,
+# endif
+ idir4,
+ near_x, near_y, near_z,
+ far_x, far_y, far_z,
+ node_addr,
+ difl,
+ &dist);
+ }
+ else
+#endif /* BVH_HAIR_MINIMUM_WIDTH */
+ {
+ child_mask = NODE_INTERSECT(kg,
+ tnear,
+ tfar,
+#ifdef __KERNEL_AVX2__
+ P_idir4,
+#endif
+#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ org4,
+#endif
+#if BVH_FEATURE(BVH_HAIR)
+ dir4,
+#endif
+ idir4,
+ near_x, near_y, near_z,
+ far_x, far_y, far_z,
+ node_addr,
+ &dist);
+ }
+
+ if(child_mask != 0) {
+ float4 cnodes;
+ /* TODO(sergey): Investigate whether moving cnodes upwards
+ * gives a speedup (will be different cache pattern but will
+ * avoid extra check here),
+ */
+#if BVH_FEATURE(BVH_HAIR)
+ if(__float_as_uint(inodes.x) & PATH_RAY_NODE_UNALIGNED) {
+ cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+13);
+ }
+ else
+#endif
+ {
+ cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+7);
+ }
+
+ /* One child is hit, continue with that child. */
+ int r = __bscf(child_mask);
+ float d0 = ((float*)&dist)[r];
+ if(child_mask == 0) {
+ node_addr = __float_as_int(cnodes[r]);
+ node_dist = d0;
+ continue;
+ }
+
+ /* Two children are hit, push far child, and continue with
+ * closer child.
+ */
+ int c0 = __float_as_int(cnodes[r]);
+ r = __bscf(child_mask);
+ int c1 = __float_as_int(cnodes[r]);
+ float d1 = ((float*)&dist)[r];
+ if(child_mask == 0) {
+ if(d1 < d0) {
+ node_addr = c1;
+ node_dist = d1;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c0;
+ traversal_stack[stack_ptr].dist = d0;
+ continue;
+ }
+ else {
+ node_addr = c0;
+ node_dist = d0;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c1;
+ traversal_stack[stack_ptr].dist = d1;
+ continue;
+ }
+ }
+
+ /* Here starts the slow path for 3 or 4 hit children. We push
+ * all nodes onto the stack to sort them there.
+ */
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c1;
+ traversal_stack[stack_ptr].dist = d1;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c0;
+ traversal_stack[stack_ptr].dist = d0;
+
+ /* Three children are hit, push all onto stack and sort 3
+ * stack items, continue with closest child.
+ */
+ r = __bscf(child_mask);
+ int c2 = __float_as_int(cnodes[r]);
+ float d2 = ((float*)&dist)[r];
+ if(child_mask == 0) {
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c2;
+ traversal_stack[stack_ptr].dist = d2;
+ qbvh_stack_sort(&traversal_stack[stack_ptr],
+ &traversal_stack[stack_ptr - 1],
+ &traversal_stack[stack_ptr - 2]);
+ node_addr = traversal_stack[stack_ptr].addr;
+ node_dist = traversal_stack[stack_ptr].dist;
+ --stack_ptr;
+ continue;
+ }
+
+ /* Four children are hit, push all onto stack and sort 4
+ * stack items, continue with closest child.
+ */
+ r = __bscf(child_mask);
+ int c3 = __float_as_int(cnodes[r]);
+ float d3 = ((float*)&dist)[r];
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c3;
+ traversal_stack[stack_ptr].dist = d3;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c2;
+ traversal_stack[stack_ptr].dist = d2;
+ qbvh_stack_sort(&traversal_stack[stack_ptr],
+ &traversal_stack[stack_ptr - 1],
+ &traversal_stack[stack_ptr - 2],
+ &traversal_stack[stack_ptr - 3]);
+ }
+
+ node_addr = traversal_stack[stack_ptr].addr;
+ node_dist = traversal_stack[stack_ptr].dist;
+ --stack_ptr;
+ }
+
+ /* If node is leaf, fetch triangle list. */
+ if(node_addr < 0) {
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1));
+
+#ifdef __VISIBILITY_FLAG__
+ if(UNLIKELY((node_dist > isect->t) ||
+ ((__float_as_uint(leaf.z) & visibility) == 0)))
+#else
+ if(UNLIKELY((node_dist > isect->t)))
+#endif
+ {
+ /* Pop. */
+ node_addr = traversal_stack[stack_ptr].addr;
+ node_dist = traversal_stack[stack_ptr].dist;
+ --stack_ptr;
+ continue;
+ }
+
+ int prim_addr = __float_as_int(leaf.x);
+
+#if BVH_FEATURE(BVH_INSTANCING)
+ if(prim_addr >= 0) {
+#endif
+ int prim_addr2 = __float_as_int(leaf.y);
+ const uint type = __float_as_int(leaf.w);
+
+ /* Pop. */
+ node_addr = traversal_stack[stack_ptr].addr;
+ node_dist = traversal_stack[stack_ptr].dist;
+ --stack_ptr;
+
+ /* Primitive intersection. */
+ switch(type & PRIMITIVE_ALL) {
+ case PRIMITIVE_TRIANGLE: {
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ BVH_DEBUG_NEXT_STEP();
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
+ if(triangle_intersect(kg,
+ &isect_precalc,
+ isect,
+ P,
+ visibility,
+ object,
+ prim_addr)) {
+ tfar = ssef(isect->t);
+ /* Shadow ray early termination. */
+ if(visibility == PATH_RAY_SHADOW_OPAQUE) {
+ return true;
+ }
+ }
+ }
+ break;
+ }
+#if BVH_FEATURE(BVH_MOTION)
+ case PRIMITIVE_MOTION_TRIANGLE: {
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ BVH_DEBUG_NEXT_STEP();
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
+ if(motion_triangle_intersect(kg,
+ isect,
+ P,
+ dir,
+ ray->time,
+ visibility,
+ object,
+ prim_addr)) {
+ tfar = ssef(isect->t);
+ /* Shadow ray early termination. */
+ if(visibility == PATH_RAY_SHADOW_OPAQUE) {
+ return true;
+ }
+ }
+ }
+ break;
+ }
+#endif /* BVH_FEATURE(BVH_MOTION) */
+#if BVH_FEATURE(BVH_HAIR)
+ case PRIMITIVE_CURVE:
+ case PRIMITIVE_MOTION_CURVE: {
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ BVH_DEBUG_NEXT_STEP();
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
+ bool hit;
+ if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) {
+ hit = bvh_cardinal_curve_intersect(kg,
+ isect,
+ P,
+ dir,
+ visibility,
+ object,
+ prim_addr,
+ ray->time,
+ type,
+ lcg_state,
+ difl,
+ extmax);
+ }
+ else {
+ hit = bvh_curve_intersect(kg,
+ isect,
+ P,
+ dir,
+ visibility,
+ object,
+ prim_addr,
+ ray->time,
+ type,
+ lcg_state,
+ difl,
+ extmax);
+ }
+ if(hit) {
+ tfar = ssef(isect->t);
+ /* Shadow ray early termination. */
+ if(visibility == PATH_RAY_SHADOW_OPAQUE) {
+ return true;
+ }
+ }
+ }
+ break;
+ }
+#endif /* BVH_FEATURE(BVH_HAIR) */
+ }
+ }
+#if BVH_FEATURE(BVH_INSTANCING)
+ else {
+ /* Instance push. */
+ object = kernel_tex_fetch(__prim_object, -prim_addr-1);
+
+# if BVH_FEATURE(BVH_MOTION)
+ qbvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect->t, &node_dist, &ob_itfm);
+# else
+ qbvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect->t, &node_dist);
+# endif
+
+ qbvh_near_far_idx_calc(idir,
+ &near_x, &near_y, &near_z,
+ &far_x, &far_y, &far_z);
+ tfar = ssef(isect->t);
+# if BVH_FEATURE(BVH_HAIR)
+ dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z));
+# endif
+ idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
+# ifdef __KERNEL_AVX2__
+ P_idir = P*idir;
+ P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
+# endif
+# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
+# endif
+
+ triangle_intersect_precalc(dir, &isect_precalc);
+
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = ENTRYPOINT_SENTINEL;
+ traversal_stack[stack_ptr].dist = -FLT_MAX;
+
+ node_addr = kernel_tex_fetch(__object_node, object);
+
+ BVH_DEBUG_NEXT_INSTANCE();
+ }
+ }
+#endif /* FEATURE(BVH_INSTANCING) */
+ } while(node_addr != ENTRYPOINT_SENTINEL);
+
+#if BVH_FEATURE(BVH_INSTANCING)
+ if(stack_ptr >= 0) {
+ kernel_assert(object != OBJECT_NONE);
+
+ /* Instance pop. */
+# if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_itfm);
+# else
+ bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &isect->t);
+# endif
+
+ qbvh_near_far_idx_calc(idir,
+ &near_x, &near_y, &near_z,
+ &far_x, &far_y, &far_z);
+ tfar = ssef(isect->t);
+# if BVH_FEATURE(BVH_HAIR)
+ dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z));
+# endif
+ idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
+# ifdef __KERNEL_AVX2__
+ P_idir = P*idir;
+ P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
+# endif
+# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
+# endif
+
+ triangle_intersect_precalc(dir, &isect_precalc);
+
+ object = OBJECT_NONE;
+ node_addr = traversal_stack[stack_ptr].addr;
+ node_dist = traversal_stack[stack_ptr].dist;
+ --stack_ptr;
+ }
+#endif /* FEATURE(BVH_INSTANCING) */
+ } while(node_addr != ENTRYPOINT_SENTINEL);
+
+ return (isect->prim != PRIM_NONE);
+}
+
+#undef NODE_INTERSECT
+#undef NODE_INTERSECT_ROBUST
diff --git a/intern/cycles/kernel/geom/geom_qbvh_volume.h b/intern/cycles/kernel/bvh/qbvh_volume.h
index ab2e530dd20..424710b69f2 100644
--- a/intern/cycles/kernel/geom/geom_qbvh_volume.h
+++ b/intern/cycles/kernel/bvh/qbvh_volume.h
@@ -1,8 +1,5 @@
/*
- * Adapted from code Copyright 2009-2010 NVIDIA Corporation,
- * and code copyright 2009-2012 Intel Corporation
- *
- * Modifications Copyright 2011-2014, Blender Foundation.
+ * Copyright 2011-2013 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,6 +23,12 @@
*
*/
+#if BVH_FEATURE(BVH_HAIR)
+# define NODE_INTERSECT qbvh_node_intersect
+#else
+# define NODE_INTERSECT qbvh_aligned_node_intersect
+#endif
+
ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
const Ray *ray,
Intersection *isect,
@@ -38,12 +41,12 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
*/
/* Traversal stack in CUDA thread-local memory. */
- QBVHStackItem traversalStack[BVH_QSTACK_SIZE];
- traversalStack[0].addr = ENTRYPOINT_SENTINEL;
+ QBVHStackItem traversal_stack[BVH_QSTACK_SIZE];
+ traversal_stack[0].addr = ENTRYPOINT_SENTINEL;
/* Traversal variables in registers. */
- int stackPtr = 0;
- int nodeAddr = kernel_data.bvh.root;
+ int stack_ptr = 0;
+ int node_addr = kernel_data.bvh.root;
/* Ray parameters in registers. */
float3 P = ray->P;
@@ -68,22 +71,25 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
isect->object = OBJECT_NONE;
ssef tnear(0.0f), tfar(ray->t);
+#if BVH_FEATURE(BVH_HAIR)
+ sse3f dir4(ssef(dir.x), ssef(dir.y), ssef(dir.z));
+#endif
sse3f idir4(ssef(idir.x), ssef(idir.y), ssef(idir.z));
#ifdef __KERNEL_AVX2__
float3 P_idir = P*idir;
- sse3f P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-#else
- sse3f org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
+ sse3f P_idir4(P_idir.x, P_idir.y, P_idir.z);
+#endif
+#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ sse3f org4(ssef(P.x), ssef(P.y), ssef(P.z));
#endif
/* Offsets to select the side that becomes the lower or upper bound. */
int near_x, near_y, near_z;
int far_x, far_y, far_z;
-
- if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; }
- if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
- if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
+ qbvh_near_far_idx_calc(idir,
+ &near_x, &near_y, &near_z,
+ &far_x, &far_y, &far_z);
IsectPrecalc isect_precalc;
triangle_intersect_precalc(dir, &isect_precalc);
@@ -92,29 +98,53 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
do {
do {
/* Traverse internal nodes. */
- while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) {
+ while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
+ float4 inodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
+
+#ifdef __VISIBILITY_FLAG__
+ if((__float_as_uint(inodes.x) & visibility) == 0) {
+ /* Pop. */
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
+ continue;
+ }
+#endif
+
ssef dist;
- int traverseChild = qbvh_node_intersect(kg,
- tnear,
- tfar,
+ int child_mask = NODE_INTERSECT(kg,
+ tnear,
+ tfar,
#ifdef __KERNEL_AVX2__
- P_idir4,
-#else
- org,
+ P_idir4,
#endif
- idir4,
- near_x, near_y, near_z,
- far_x, far_y, far_z,
- nodeAddr,
- &dist);
-
- if(traverseChild != 0) {
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_QNODE_SIZE+6);
+#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ org4,
+#endif
+#if BVH_FEATURE(BVH_HAIR)
+ dir4,
+#endif
+ idir4,
+ near_x, near_y, near_z,
+ far_x, far_y, far_z,
+ node_addr,
+ &dist);
+
+ if(child_mask != 0) {
+ float4 cnodes;
+#if BVH_FEATURE(BVH_HAIR)
+ if(__float_as_uint(inodes.x) & PATH_RAY_NODE_UNALIGNED) {
+ cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+13);
+ }
+ else
+#endif
+ {
+ cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+7);
+ }
/* One child is hit, continue with that child. */
- int r = __bscf(traverseChild);
- if(traverseChild == 0) {
- nodeAddr = __float_as_int(cnodes[r]);
+ int r = __bscf(child_mask);
+ if(child_mask == 0) {
+ node_addr = __float_as_int(cnodes[r]);
continue;
}
@@ -123,24 +153,24 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
*/
int c0 = __float_as_int(cnodes[r]);
float d0 = ((float*)&dist)[r];
- r = __bscf(traverseChild);
+ r = __bscf(child_mask);
int c1 = __float_as_int(cnodes[r]);
float d1 = ((float*)&dist)[r];
- if(traverseChild == 0) {
+ if(child_mask == 0) {
if(d1 < d0) {
- nodeAddr = c1;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c0;
- traversalStack[stackPtr].dist = d0;
+ node_addr = c1;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c0;
+ traversal_stack[stack_ptr].dist = d0;
continue;
}
else {
- nodeAddr = c0;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c1;
- traversalStack[stackPtr].dist = d1;
+ node_addr = c0;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c1;
+ traversal_stack[stack_ptr].dist = d1;
continue;
}
}
@@ -148,102 +178,110 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
/* Here starts the slow path for 3 or 4 hit children. We push
* all nodes onto the stack to sort them there.
*/
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c1;
- traversalStack[stackPtr].dist = d1;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c0;
- traversalStack[stackPtr].dist = d0;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c1;
+ traversal_stack[stack_ptr].dist = d1;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c0;
+ traversal_stack[stack_ptr].dist = d0;
/* Three children are hit, push all onto stack and sort 3
* stack items, continue with closest child.
*/
- r = __bscf(traverseChild);
+ r = __bscf(child_mask);
int c2 = __float_as_int(cnodes[r]);
float d2 = ((float*)&dist)[r];
- if(traverseChild == 0) {
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c2;
- traversalStack[stackPtr].dist = d2;
- qbvh_stack_sort(&traversalStack[stackPtr],
- &traversalStack[stackPtr - 1],
- &traversalStack[stackPtr - 2]);
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ if(child_mask == 0) {
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c2;
+ traversal_stack[stack_ptr].dist = d2;
+ qbvh_stack_sort(&traversal_stack[stack_ptr],
+ &traversal_stack[stack_ptr - 1],
+ &traversal_stack[stack_ptr - 2]);
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
continue;
}
/* Four children are hit, push all onto stack and sort 4
* stack items, continue with closest child.
*/
- r = __bscf(traverseChild);
+ r = __bscf(child_mask);
int c3 = __float_as_int(cnodes[r]);
float d3 = ((float*)&dist)[r];
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c3;
- traversalStack[stackPtr].dist = d3;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c2;
- traversalStack[stackPtr].dist = d2;
- qbvh_stack_sort(&traversalStack[stackPtr],
- &traversalStack[stackPtr - 1],
- &traversalStack[stackPtr - 2],
- &traversalStack[stackPtr - 3]);
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c3;
+ traversal_stack[stack_ptr].dist = d3;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c2;
+ traversal_stack[stack_ptr].dist = d2;
+ qbvh_stack_sort(&traversal_stack[stack_ptr],
+ &traversal_stack[stack_ptr - 1],
+ &traversal_stack[stack_ptr - 2],
+ &traversal_stack[stack_ptr - 3]);
}
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
}
/* If node is leaf, fetch triangle list. */
- if(nodeAddr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_QNODE_LEAF_SIZE);
- int primAddr = __float_as_int(leaf.x);
+ if(node_addr < 0) {
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1));
+
+ if((__float_as_uint(leaf.z) & visibility) == 0) {
+ /* Pop. */
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
+ continue;
+ }
+
+ int prim_addr = __float_as_int(leaf.x);
#if BVH_FEATURE(BVH_INSTANCING)
- if(primAddr >= 0) {
+ if(prim_addr >= 0) {
#endif
- int primAddr2 = __float_as_int(leaf.y);
+ int prim_addr2 = __float_as_int(leaf.y);
const uint type = __float_as_int(leaf.w);
const uint p_type = type & PRIMITIVE_ALL;
/* Pop. */
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
/* Primitive intersection. */
switch(p_type) {
case PRIMITIVE_TRIANGLE: {
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
/* Only primitives from volume object. */
- uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
+ uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object;
int object_flag = kernel_tex_fetch(__object_flag, tri_object);
if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
continue;
}
/* Intersect ray against primitive. */
- triangle_intersect(kg, &isect_precalc, isect, P, visibility, object, primAddr);
+ triangle_intersect(kg, &isect_precalc, isect, P, visibility, object, prim_addr);
}
break;
}
#if BVH_FEATURE(BVH_MOTION)
case PRIMITIVE_MOTION_TRIANGLE: {
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
/* Only primitives from volume object. */
- uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
+ uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object;
int object_flag = kernel_tex_fetch(__object_flag, tri_object);
if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
continue;
}
/* Intersect ray against primitive. */
- motion_triangle_intersect(kg, isect, P, dir, ray->time, visibility, object, primAddr);
+ motion_triangle_intersect(kg, isect, P, dir, ray->time, visibility, object, prim_addr);
}
break;
}
@@ -253,7 +291,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
#if BVH_FEATURE(BVH_INSTANCING)
else {
/* Instance push. */
- object = kernel_tex_fetch(__prim_object, -primAddr-1);
+ object = kernel_tex_fetch(__prim_object, -prim_addr-1);
int object_flag = kernel_tex_fetch(__object_flag, object);
if(object_flag & SD_OBJECT_HAS_VOLUME) {
@@ -264,38 +302,43 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
bvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect->t);
# endif
- if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; }
- if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
- if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
+ qbvh_near_far_idx_calc(idir,
+ &near_x, &near_y, &near_z,
+ &far_x, &far_y, &far_z);
tfar = ssef(isect->t);
+# if BVH_FEATURE(BVH_HAIR)
+ dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z));
+# endif
idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
# ifdef __KERNEL_AVX2__
P_idir = P*idir;
P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-# else
- org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
# endif
+# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
+# endif
+
triangle_intersect_precalc(dir, &isect_precalc);
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = ENTRYPOINT_SENTINEL;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = ENTRYPOINT_SENTINEL;
- nodeAddr = kernel_tex_fetch(__object_node, object);
+ node_addr = kernel_tex_fetch(__object_node, object);
}
else {
/* Pop. */
object = OBJECT_NONE;
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
}
}
}
#endif /* FEATURE(BVH_INSTANCING) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
+ } while(node_addr != ENTRYPOINT_SENTINEL);
#if BVH_FEATURE(BVH_INSTANCING)
- if(stackPtr >= 0) {
+ if(stack_ptr >= 0) {
kernel_assert(object != OBJECT_NONE);
/* Instance pop. */
@@ -305,25 +348,32 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &isect->t);
# endif
- if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; }
- if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
- if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
+ qbvh_near_far_idx_calc(idir,
+ &near_x, &near_y, &near_z,
+ &far_x, &far_y, &far_z);
tfar = ssef(isect->t);
+# if BVH_FEATURE(BVH_HAIR)
+ dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z));
+# endif
idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
# ifdef __KERNEL_AVX2__
P_idir = P*idir;
P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-# else
- org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
# endif
+# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
+# endif
+
triangle_intersect_precalc(dir, &isect_precalc);
object = OBJECT_NONE;
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
}
#endif /* FEATURE(BVH_INSTANCING) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
+ } while(node_addr != ENTRYPOINT_SENTINEL);
return (isect->prim != PRIM_NONE);
}
+
+#undef NODE_INTERSECT
diff --git a/intern/cycles/kernel/geom/geom_qbvh_volume_all.h b/intern/cycles/kernel/bvh/qbvh_volume_all.h
index 5546471b0e3..eb48af6fc68 100644
--- a/intern/cycles/kernel/geom/geom_qbvh_volume_all.h
+++ b/intern/cycles/kernel/bvh/qbvh_volume_all.h
@@ -1,8 +1,5 @@
/*
- * Adapted from code Copyright 2009-2010 NVIDIA Corporation,
- * and code copyright 2009-2012 Intel Corporation
- *
- * Modifications Copyright 2011-2014, Blender Foundation.
+ * Copyright 2011-2013 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,6 +23,12 @@
*
*/
+#if BVH_FEATURE(BVH_HAIR)
+# define NODE_INTERSECT qbvh_node_intersect
+#else
+# define NODE_INTERSECT qbvh_aligned_node_intersect
+#endif
+
ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
const Ray *ray,
Intersection *isect_array,
@@ -39,12 +42,12 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
*/
/* Traversal stack in CUDA thread-local memory. */
- QBVHStackItem traversalStack[BVH_QSTACK_SIZE];
- traversalStack[0].addr = ENTRYPOINT_SENTINEL;
+ QBVHStackItem traversal_stack[BVH_QSTACK_SIZE];
+ traversal_stack[0].addr = ENTRYPOINT_SENTINEL;
/* Traversal variables in registers. */
- int stackPtr = 0;
- int nodeAddr = kernel_data.bvh.root;
+ int stack_ptr = 0;
+ int node_addr = kernel_data.bvh.root;
/* Ray parameters in registers. */
const float tmax = ray->t;
@@ -63,7 +66,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
#ifndef __KERNEL_SSE41__
if(!isfinite(P.x)) {
- return false;
+ return 0;
}
#endif
@@ -72,22 +75,25 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
#endif
ssef tnear(0.0f), tfar(isect_t);
+#if BVH_FEATURE(BVH_HAIR)
+ sse3f dir4(ssef(dir.x), ssef(dir.y), ssef(dir.z));
+#endif
sse3f idir4(ssef(idir.x), ssef(idir.y), ssef(idir.z));
#ifdef __KERNEL_AVX2__
float3 P_idir = P*idir;
- sse3f P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-#else
- sse3f org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
+ sse3f P_idir4(P_idir.x, P_idir.y, P_idir.z);
+#endif
+#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ sse3f org4(ssef(P.x), ssef(P.y), ssef(P.z));
#endif
/* Offsets to select the side that becomes the lower or upper bound. */
int near_x, near_y, near_z;
int far_x, far_y, far_z;
-
- if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; }
- if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
- if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
+ qbvh_near_far_idx_calc(idir,
+ &near_x, &near_y, &near_z,
+ &far_x, &far_y, &far_z);
IsectPrecalc isect_precalc;
triangle_intersect_precalc(dir, &isect_precalc);
@@ -96,29 +102,53 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
do {
do {
/* Traverse internal nodes. */
- while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) {
+ while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
+ float4 inodes = kernel_tex_fetch(__bvh_nodes, node_addr+0);
+
+#ifdef __VISIBILITY_FLAG__
+ if((__float_as_uint(inodes.x) & visibility) == 0) {
+ /* Pop. */
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
+ continue;
+ }
+#endif
+
ssef dist;
- int traverseChild = qbvh_node_intersect(kg,
- tnear,
- tfar,
+ int child_mask = NODE_INTERSECT(kg,
+ tnear,
+ tfar,
#ifdef __KERNEL_AVX2__
- P_idir4,
-#else
- org,
+ P_idir4,
#endif
- idir4,
- near_x, near_y, near_z,
- far_x, far_y, far_z,
- nodeAddr,
- &dist);
-
- if(traverseChild != 0) {
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_QNODE_SIZE+6);
+#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ org4,
+#endif
+#if BVH_FEATURE(BVH_HAIR)
+ dir4,
+#endif
+ idir4,
+ near_x, near_y, near_z,
+ far_x, far_y, far_z,
+ node_addr,
+ &dist);
+
+ if(child_mask != 0) {
+ float4 cnodes;
+#if BVH_FEATURE(BVH_HAIR)
+ if(__float_as_uint(inodes.x) & PATH_RAY_NODE_UNALIGNED) {
+ cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+13);
+ }
+ else
+#endif
+ {
+ cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+7);
+ }
/* One child is hit, continue with that child. */
- int r = __bscf(traverseChild);
- if(traverseChild == 0) {
- nodeAddr = __float_as_int(cnodes[r]);
+ int r = __bscf(child_mask);
+ if(child_mask == 0) {
+ node_addr = __float_as_int(cnodes[r]);
continue;
}
@@ -127,24 +157,24 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
*/
int c0 = __float_as_int(cnodes[r]);
float d0 = ((float*)&dist)[r];
- r = __bscf(traverseChild);
+ r = __bscf(child_mask);
int c1 = __float_as_int(cnodes[r]);
float d1 = ((float*)&dist)[r];
- if(traverseChild == 0) {
+ if(child_mask == 0) {
if(d1 < d0) {
- nodeAddr = c1;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c0;
- traversalStack[stackPtr].dist = d0;
+ node_addr = c1;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c0;
+ traversal_stack[stack_ptr].dist = d0;
continue;
}
else {
- nodeAddr = c0;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c1;
- traversalStack[stackPtr].dist = d1;
+ node_addr = c0;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c1;
+ traversal_stack[stack_ptr].dist = d1;
continue;
}
}
@@ -152,88 +182,96 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
/* Here starts the slow path for 3 or 4 hit children. We push
* all nodes onto the stack to sort them there.
*/
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c1;
- traversalStack[stackPtr].dist = d1;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c0;
- traversalStack[stackPtr].dist = d0;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c1;
+ traversal_stack[stack_ptr].dist = d1;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c0;
+ traversal_stack[stack_ptr].dist = d0;
/* Three children are hit, push all onto stack and sort 3
* stack items, continue with closest child.
*/
- r = __bscf(traverseChild);
+ r = __bscf(child_mask);
int c2 = __float_as_int(cnodes[r]);
float d2 = ((float*)&dist)[r];
- if(traverseChild == 0) {
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c2;
- traversalStack[stackPtr].dist = d2;
- qbvh_stack_sort(&traversalStack[stackPtr],
- &traversalStack[stackPtr - 1],
- &traversalStack[stackPtr - 2]);
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ if(child_mask == 0) {
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c2;
+ traversal_stack[stack_ptr].dist = d2;
+ qbvh_stack_sort(&traversal_stack[stack_ptr],
+ &traversal_stack[stack_ptr - 1],
+ &traversal_stack[stack_ptr - 2]);
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
continue;
}
/* Four children are hit, push all onto stack and sort 4
* stack items, continue with closest child.
*/
- r = __bscf(traverseChild);
+ r = __bscf(child_mask);
int c3 = __float_as_int(cnodes[r]);
float d3 = ((float*)&dist)[r];
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c3;
- traversalStack[stackPtr].dist = d3;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c2;
- traversalStack[stackPtr].dist = d2;
- qbvh_stack_sort(&traversalStack[stackPtr],
- &traversalStack[stackPtr - 1],
- &traversalStack[stackPtr - 2],
- &traversalStack[stackPtr - 3]);
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c3;
+ traversal_stack[stack_ptr].dist = d3;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = c2;
+ traversal_stack[stack_ptr].dist = d2;
+ qbvh_stack_sort(&traversal_stack[stack_ptr],
+ &traversal_stack[stack_ptr - 1],
+ &traversal_stack[stack_ptr - 2],
+ &traversal_stack[stack_ptr - 3]);
}
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
}
/* If node is leaf, fetch triangle list. */
- if(nodeAddr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_QNODE_LEAF_SIZE);
- int primAddr = __float_as_int(leaf.x);
+ if(node_addr < 0) {
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1));
+
+ if((__float_as_uint(leaf.z) & visibility) == 0) {
+ /* Pop. */
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
+ continue;
+ }
+
+ int prim_addr = __float_as_int(leaf.x);
#if BVH_FEATURE(BVH_INSTANCING)
- if(primAddr >= 0) {
+ if(prim_addr >= 0) {
#endif
- int primAddr2 = __float_as_int(leaf.y);
+ int prim_addr2 = __float_as_int(leaf.y);
const uint type = __float_as_int(leaf.w);
const uint p_type = type & PRIMITIVE_ALL;
bool hit;
/* Pop. */
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
/* Primitive intersection. */
switch(p_type) {
case PRIMITIVE_TRIANGLE: {
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
/* Only primitives from volume object. */
- uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
+ uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object;
int object_flag = kernel_tex_fetch(__object_flag, tri_object);
if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
continue;
}
/* Intersect ray against primitive. */
- hit = triangle_intersect(kg, &isect_precalc, isect_array, P, visibility, object, primAddr);
+ hit = triangle_intersect(kg, &isect_precalc, isect_array, P, visibility, object, prim_addr);
if(hit) {
/* Move on to next entry in intersections array. */
isect_array++;
@@ -262,16 +300,16 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
}
#if BVH_FEATURE(BVH_MOTION)
case PRIMITIVE_MOTION_TRIANGLE: {
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ for(; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
/* Only primitives from volume object. */
- uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
+ uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object;
int object_flag = kernel_tex_fetch(__object_flag, tri_object);
if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
continue;
}
/* Intersect ray against primitive. */
- hit = motion_triangle_intersect(kg, isect_array, P, dir, ray->time, visibility, object, primAddr);
+ hit = motion_triangle_intersect(kg, isect_array, P, dir, ray->time, visibility, object, prim_addr);
if(hit) {
/* Move on to next entry in intersections array. */
isect_array++;
@@ -304,7 +342,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
#if BVH_FEATURE(BVH_INSTANCING)
else {
/* Instance push. */
- object = kernel_tex_fetch(__prim_object, -primAddr-1);
+ object = kernel_tex_fetch(__prim_object, -prim_addr-1);
int object_flag = kernel_tex_fetch(__object_flag, object);
if(object_flag & SD_OBJECT_HAS_VOLUME) {
@@ -315,40 +353,45 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
bvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect_t);
# endif
- if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; }
- if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
- if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
+ qbvh_near_far_idx_calc(idir,
+ &near_x, &near_y, &near_z,
+ &far_x, &far_y, &far_z);
tfar = ssef(isect_t);
idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
+# if BVH_FEATURE(BVH_HAIR)
+ dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z));
+# endif
# ifdef __KERNEL_AVX2__
P_idir = P*idir;
P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-# else
- org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
# endif
+# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
+# endif
+
triangle_intersect_precalc(dir, &isect_precalc);
num_hits_in_instance = 0;
isect_array->t = isect_t;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = ENTRYPOINT_SENTINEL;
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_QSTACK_SIZE);
+ traversal_stack[stack_ptr].addr = ENTRYPOINT_SENTINEL;
- nodeAddr = kernel_tex_fetch(__object_node, object);
+ node_addr = kernel_tex_fetch(__object_node, object);
}
else {
/* Pop. */
object = OBJECT_NONE;
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
}
}
}
#endif /* FEATURE(BVH_INSTANCING) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
+ } while(node_addr != ENTRYPOINT_SENTINEL);
#if BVH_FEATURE(BVH_INSTANCING)
- if(stackPtr >= 0) {
+ if(stack_ptr >= 0) {
kernel_assert(object != OBJECT_NONE);
/* Instance pop. */
@@ -359,7 +402,6 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
# else
bvh_instance_pop_factor(kg, object, ray, &P, &dir, &idir, &t_fac);
# endif
- triangle_intersect_precalc(dir, &isect_precalc);
/* Scale isect->t to adjust for instancing. */
for(int i = 0; i < num_hits_in_instance; i++) {
(isect_array-i-1)->t *= t_fac;
@@ -372,30 +414,37 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
# else
bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &ignore_t);
# endif
- triangle_intersect_precalc(dir, &isect_precalc);
}
- if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; }
- if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
- if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
+ isect_t = tmax;
+ isect_array->t = isect_t;
+
+ qbvh_near_far_idx_calc(idir,
+ &near_x, &near_y, &near_z,
+ &far_x, &far_y, &far_z);
tfar = ssef(isect_t);
+# if BVH_FEATURE(BVH_HAIR)
+ dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z));
+# endif
idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
# ifdef __KERNEL_AVX2__
P_idir = P*idir;
P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-# else
- org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
# endif
+# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__)
+ org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
+# endif
+
triangle_intersect_precalc(dir, &isect_precalc);
- isect_t = tmax;
- isect_array->t = isect_t;
object = OBJECT_NONE;
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ node_addr = traversal_stack[stack_ptr].addr;
+ --stack_ptr;
}
#endif /* FEATURE(BVH_INSTANCING) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
+ } while(node_addr != ENTRYPOINT_SENTINEL);
return num_hits;
}
+
+#undef NODE_INTERSECT
diff --git a/intern/cycles/kernel/closure/alloc.h b/intern/cycles/kernel/closure/alloc.h
new file mode 100644
index 00000000000..b7abc1ec507
--- /dev/null
+++ b/intern/cycles/kernel/closure/alloc.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device ShaderClosure *closure_alloc(ShaderData *sd, int size, ClosureType type, float3 weight)
+{
+ kernel_assert(size <= sizeof(ShaderClosure));
+
+ int num_closure = ccl_fetch(sd, num_closure);
+ int num_closure_extra = ccl_fetch(sd, num_closure_extra);
+ if(num_closure + num_closure_extra >= MAX_CLOSURE)
+ return NULL;
+
+ ShaderClosure *sc = &ccl_fetch(sd, closure)[num_closure];
+
+ sc->type = type;
+ sc->weight = weight;
+
+ ccl_fetch(sd, num_closure)++;
+
+ return sc;
+}
+
+ccl_device ccl_addr_space void *closure_alloc_extra(ShaderData *sd, int size)
+{
+ /* Allocate extra space for closure that need more parameters. We allocate
+ * in chunks of sizeof(ShaderClosure) starting from the end of the closure
+ * array.
+ *
+ * This lets us keep the same fast array iteration over closures, as we
+ * found linked list iteration and iteration with skipping to be slower. */
+ int num_extra = ((size + sizeof(ShaderClosure) - 1) / sizeof(ShaderClosure));
+ int num_closure = ccl_fetch(sd, num_closure);
+ int num_closure_extra = ccl_fetch(sd, num_closure_extra) + num_extra;
+
+ if(num_closure + num_closure_extra > MAX_CLOSURE) {
+ /* Remove previous closure. */
+ ccl_fetch(sd, num_closure)--;
+ ccl_fetch(sd, num_closure_extra)++;
+ return NULL;
+ }
+
+ ccl_fetch(sd, num_closure_extra) = num_closure_extra;
+ return (ccl_addr_space void*)(ccl_fetch(sd, closure) + MAX_CLOSURE - num_closure_extra);
+}
+
+ccl_device_inline ShaderClosure *bsdf_alloc(ShaderData *sd, int size, float3 weight)
+{
+ ShaderClosure *sc = closure_alloc(sd, size, CLOSURE_NONE_ID, weight);
+
+ if(!sc)
+ return NULL;
+
+ float sample_weight = fabsf(average(weight));
+ sc->sample_weight = sample_weight;
+ return (sample_weight >= CLOSURE_WEIGHT_CUTOFF) ? sc : NULL;
+}
+
+#ifdef __OSL__
+ccl_device_inline ShaderClosure *bsdf_alloc_osl(ShaderData *sd, int size, float3 weight, void *data)
+{
+ ShaderClosure *sc = closure_alloc(sd, size, CLOSURE_NONE_ID, weight);
+
+ if(!sc)
+ return NULL;
+
+ memcpy(sc, data, size);
+
+ float sample_weight = fabsf(average(weight));
+ sc->weight = weight;
+ sc->sample_weight = sample_weight;
+ return (sample_weight >= CLOSURE_WEIGHT_CUTOFF) ? sc : NULL;
+}
+#endif
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/closure/bsdf.h b/intern/cycles/kernel/closure/bsdf.h
index f0add804c32..7e4d5fe2e37 100644
--- a/intern/cycles/kernel/closure/bsdf.h
+++ b/intern/cycles/kernel/closure/bsdf.h
@@ -20,6 +20,7 @@
#include "../closure/bsdf_phong_ramp.h"
#include "../closure/bsdf_diffuse_ramp.h"
#include "../closure/bsdf_microfacet.h"
+#include "../closure/bsdf_microfacet_multi.h"
#include "../closure/bsdf_reflection.h"
#include "../closure/bsdf_refraction.h"
#include "../closure/bsdf_transparent.h"
@@ -35,15 +36,18 @@
CCL_NAMESPACE_BEGIN
-ccl_device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, differential3 *domega_in, float *pdf)
+ccl_device_forceinline int bsdf_sample(KernelGlobals *kg,
+ ShaderData *sd,
+ const ShaderClosure *sc,
+ float randu,
+ float randv,
+ float3 *eval,
+ float3 *omega_in,
+ differential3 *domega_in,
+ float *pdf)
{
int label;
-#ifdef __OSL__
- if(kg->osl && sc->prim)
- return OSLShader::bsdf_sample(sd, sc, randu, randv, *eval, *omega_in, *domega_in, *pdf);
-#endif
-
switch(sc->type) {
case CLOSURE_BSDF_DIFFUSE_ID:
case CLOSURE_BSDF_BSSRDF_ID:
@@ -55,14 +59,16 @@ ccl_device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const Shader
label = bsdf_oren_nayar_sample(sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
- /*case CLOSURE_BSDF_PHONG_RAMP_ID:
+#ifdef __OSL__
+ case CLOSURE_BSDF_PHONG_RAMP_ID:
label = bsdf_phong_ramp_sample(sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
case CLOSURE_BSDF_DIFFUSE_RAMP_ID:
label = bsdf_diffuse_ramp_sample(sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
- break;*/
+ break;
+#endif
case CLOSURE_BSDF_TRANSLUCENT_ID:
label = bsdf_translucent_sample(sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
@@ -85,6 +91,14 @@ ccl_device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const Shader
label = bsdf_microfacet_ggx_sample(kg, sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
+ label = bsdf_microfacet_multi_ggx_sample(kg, sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
+ eval, omega_in, &domega_in->dx, &domega_in->dy, pdf, &ccl_fetch(sd, lcg_state));
+ break;
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID:
+ label = bsdf_microfacet_multi_ggx_glass_sample(kg, sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
+ eval, omega_in, &domega_in->dx, &domega_in->dy, pdf, &ccl_fetch(sd, lcg_state));
+ break;
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
@@ -130,15 +144,19 @@ ccl_device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const Shader
return label;
}
-ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const ShaderClosure *sc, const float3 omega_in, float *pdf)
+#ifndef __KERNEL_CUDA__
+ccl_device
+#else
+ccl_device_forceinline
+#endif
+float3 bsdf_eval(KernelGlobals *kg,
+ ShaderData *sd,
+ const ShaderClosure *sc,
+ const float3 omega_in,
+ float *pdf)
{
float3 eval;
-#ifdef __OSL__
- if(kg->osl && sc->prim)
- return OSLShader::bsdf_eval(sd, sc, omega_in, *pdf);
-#endif
-
if(dot(ccl_fetch(sd, Ng), omega_in) >= 0.0f) {
switch(sc->type) {
case CLOSURE_BSDF_DIFFUSE_ID:
@@ -149,12 +167,14 @@ ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const Shade
case CLOSURE_BSDF_OREN_NAYAR_ID:
eval = bsdf_oren_nayar_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
- /*case CLOSURE_BSDF_PHONG_RAMP_ID:
+#ifdef __OSL__
+ case CLOSURE_BSDF_PHONG_RAMP_ID:
eval = bsdf_phong_ramp_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
case CLOSURE_BSDF_DIFFUSE_RAMP_ID:
eval = bsdf_diffuse_ramp_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf);
- break;*/
+ break;
+#endif
case CLOSURE_BSDF_TRANSLUCENT_ID:
eval = bsdf_translucent_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
@@ -172,6 +192,12 @@ ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const Shade
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
eval = bsdf_microfacet_ggx_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
+ eval = bsdf_microfacet_multi_ggx_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state));
+ break;
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID:
+ eval = bsdf_microfacet_multi_ggx_glass_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state));
+ break;
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
@@ -234,6 +260,12 @@ ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const Shade
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
eval = bsdf_microfacet_ggx_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
+ eval = bsdf_microfacet_multi_ggx_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state));
+ break;
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID:
+ eval = bsdf_microfacet_multi_ggx_glass_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state));
+ break;
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
@@ -275,17 +307,13 @@ ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const Shade
ccl_device void bsdf_blur(KernelGlobals *kg, ShaderClosure *sc, float roughness)
{
-/* ToDo: do we want to blur volume closures? */
-
-#ifdef __OSL__
- if(kg->osl && sc->prim) {
- OSLShader::bsdf_blur(sc, roughness);
- return;
- }
-#endif
-
+ /* ToDo: do we want to blur volume closures? */
#ifdef __SVM__
switch(sc->type) {
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID:
+ bsdf_microfacet_multi_ggx_blur(sc, roughness);
+ break;
case CLOSURE_BSDF_MICROFACET_GGX_ID:
case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID:
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
@@ -306,5 +334,50 @@ ccl_device void bsdf_blur(KernelGlobals *kg, ShaderClosure *sc, float roughness)
#endif
}
+ccl_device bool bsdf_merge(ShaderClosure *a, ShaderClosure *b)
+{
+#ifdef __SVM__
+ switch(a->type) {
+ case CLOSURE_BSDF_TRANSPARENT_ID:
+ return true;
+ case CLOSURE_BSDF_DIFFUSE_ID:
+ case CLOSURE_BSDF_BSSRDF_ID:
+ case CLOSURE_BSDF_TRANSLUCENT_ID:
+ return bsdf_diffuse_merge(a, b);
+ case CLOSURE_BSDF_OREN_NAYAR_ID:
+ return bsdf_oren_nayar_merge(a, b);
+ case CLOSURE_BSDF_REFLECTION_ID:
+ case CLOSURE_BSDF_REFRACTION_ID:
+ case CLOSURE_BSDF_MICROFACET_GGX_ID:
+ case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID:
+ case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID:
+ case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
+ case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID:
+ case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
+ case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID:
+ case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID:
+ return bsdf_microfacet_merge(a, b);
+ case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID:
+ return bsdf_ashikhmin_velvet_merge(a, b);
+ case CLOSURE_BSDF_DIFFUSE_TOON_ID:
+ case CLOSURE_BSDF_GLOSSY_TOON_ID:
+ return bsdf_toon_merge(a, b);
+ case CLOSURE_BSDF_HAIR_REFLECTION_ID:
+ case CLOSURE_BSDF_HAIR_TRANSMISSION_ID:
+ return bsdf_hair_merge(a, b);
+#ifdef __VOLUME__
+ case CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID:
+ return volume_henyey_greenstein_merge(a, b);
+#endif
+ default:
+ return false;
+ }
+#else
+ return false;
+#endif
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h b/intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h
index 8d7d533d6f8..1cd8246aa71 100644
--- a/intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h
+++ b/intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h
@@ -31,28 +31,30 @@ Other than that, the implementation directly follows the paper.
CCL_NAMESPACE_BEGIN
-ccl_device int bsdf_ashikhmin_shirley_setup(ShaderClosure *sc)
+ccl_device int bsdf_ashikhmin_shirley_setup(MicrofacetBsdf *bsdf)
{
- sc->data0 = clamp(sc->data0, 1e-4f, 1.0f);
- sc->data1 = sc->data0;
+ bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f);
+ bsdf->alpha_y = bsdf->alpha_x;
- sc->type = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID;
+ bsdf->type = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
-ccl_device int bsdf_ashikhmin_shirley_aniso_setup(ShaderClosure *sc)
+ccl_device int bsdf_ashikhmin_shirley_aniso_setup(MicrofacetBsdf *bsdf)
{
- sc->data0 = clamp(sc->data0, 1e-4f, 1.0f);
- sc->data1 = clamp(sc->data1, 1e-4f, 1.0f);
+ bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f);
+ bsdf->alpha_y = clamp(bsdf->alpha_y, 1e-4f, 1.0f);
- sc->type = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID;
+ bsdf->type = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
ccl_device void bsdf_ashikhmin_shirley_blur(ShaderClosure *sc, float roughness)
{
- sc->data0 = fmaxf(roughness, sc->data0); /* clamp roughness */
- sc->data1 = fmaxf(roughness, sc->data1);
+ MicrofacetBsdf *bsdf = (MicrofacetBsdf*)sc;
+
+ bsdf->alpha_x = fmaxf(roughness, bsdf->alpha_x);
+ bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y);
}
ccl_device_inline float bsdf_ashikhmin_shirley_roughness_to_exponent(float roughness)
@@ -60,16 +62,21 @@ ccl_device_inline float bsdf_ashikhmin_shirley_roughness_to_exponent(float rough
return 2.0f / (roughness*roughness) - 2.0f;
}
-ccl_device float3 bsdf_ashikhmin_shirley_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
+ccl_device_forceinline float3 bsdf_ashikhmin_shirley_eval_reflect(
+ const ShaderClosure *sc,
+ const float3 I,
+ const float3 omega_in,
+ float *pdf)
{
- float3 N = sc->N;
+ const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc;
+ float3 N = bsdf->N;
float NdotI = dot(N, I); /* in Cycles/OSL convention I is omega_out */
float NdotO = dot(N, omega_in); /* and consequently we use for O omaga_in ;) */
float out = 0.0f;
- if(fmaxf(sc->data0, sc->data1) <= 1e-4f)
+ if(fmaxf(bsdf->alpha_x, bsdf->alpha_y) <= 1e-4f)
return make_float3(0.0f, 0.0f, 0.0f);
if(NdotI > 0.0f && NdotO > 0.0f) {
@@ -82,8 +89,8 @@ ccl_device float3 bsdf_ashikhmin_shirley_eval_reflect(const ShaderClosure *sc, c
float pump = 1.0f / fmaxf(1e-6f, (HdotI*fmaxf(NdotO, NdotI))); /* pump from original paper (first derivative disc., but cancels the HdotI in the pdf nicely) */
/*float pump = 1.0f / fmaxf(1e-4f, ((NdotO + NdotI) * (NdotO*NdotI))); */ /* pump from d-brdf paper */
- float n_x = bsdf_ashikhmin_shirley_roughness_to_exponent(sc->data0);
- float n_y = bsdf_ashikhmin_shirley_roughness_to_exponent(sc->data1);
+ float n_x = bsdf_ashikhmin_shirley_roughness_to_exponent(bsdf->alpha_x);
+ float n_y = bsdf_ashikhmin_shirley_roughness_to_exponent(bsdf->alpha_y);
if(n_x == n_y) {
/* isotropic */
@@ -97,12 +104,18 @@ ccl_device float3 bsdf_ashikhmin_shirley_eval_reflect(const ShaderClosure *sc, c
else {
/* anisotropic */
float3 X, Y;
- make_orthonormals_tangent(N, sc->T, &X, &Y);
+ make_orthonormals_tangent(N, bsdf->T, &X, &Y);
float HdotX = dot(H, X);
float HdotY = dot(H, Y);
- float e = (n_x * HdotX*HdotX + n_y * HdotY*HdotY) / (1.0f - HdotN*HdotN);
- float lobe = powf(HdotN, e);
+ float lobe;
+ if(HdotN < 1.0f) {
+ float e = (n_x * HdotX*HdotX + n_y * HdotY*HdotY) / (1.0f - HdotN*HdotN);
+ lobe = powf(HdotN, e);
+ }
+ else {
+ lobe = 1.0f;
+ }
float norm = sqrtf((n_x + 1.0f)*(n_y + 1.0f)) / (8.0f * M_PI_F);
out = NdotO * norm * lobe * pump;
@@ -128,13 +141,14 @@ ccl_device_inline void bsdf_ashikhmin_shirley_sample_first_quadrant(float n_x, f
ccl_device int bsdf_ashikhmin_shirley_sample(const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
{
- float3 N = sc->N;
+ const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc;
+ float3 N = bsdf->N;
float NdotI = dot(N, I);
if(NdotI > 0.0f) {
- float n_x = bsdf_ashikhmin_shirley_roughness_to_exponent(sc->data0);
- float n_y = bsdf_ashikhmin_shirley_roughness_to_exponent(sc->data1);
+ float n_x = bsdf_ashikhmin_shirley_roughness_to_exponent(bsdf->alpha_x);
+ float n_y = bsdf_ashikhmin_shirley_roughness_to_exponent(bsdf->alpha_y);
/* get x,y basis on the surface for anisotropy */
float3 X, Y;
@@ -142,7 +156,7 @@ ccl_device int bsdf_ashikhmin_shirley_sample(const ShaderClosure *sc, float3 Ng,
if(n_x == n_y)
make_orthonormals(N, &X, &Y);
else
- make_orthonormals_tangent(N, sc->T, &X, &Y);
+ make_orthonormals_tangent(N, bsdf->T, &X, &Y);
/* sample spherical coords for h in tangent space */
float phi;
@@ -193,7 +207,7 @@ ccl_device int bsdf_ashikhmin_shirley_sample(const ShaderClosure *sc, float3 Ng,
/* reflect I on H to get omega_in */
*omega_in = -I + (2.0f * HdotI) * H;
- if(fmaxf(sc->data0, sc->data1) <= 1e-4f) {
+ if(fmaxf(bsdf->alpha_x, bsdf->alpha_y) <= 1e-4f) {
/* Some high number for MIS. */
*pdf = 1e6f;
*eval = make_float3(1e6f, 1e6f, 1e6f);
diff --git a/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h b/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h
index f1a26650078..7e0f5a7ec75 100644
--- a/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h
+++ b/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h
@@ -35,20 +35,38 @@
CCL_NAMESPACE_BEGIN
-ccl_device int bsdf_ashikhmin_velvet_setup(ShaderClosure *sc)
+typedef ccl_addr_space struct VelvetBsdf {
+ SHADER_CLOSURE_BASE;
+
+ float sigma;
+ float invsigma2;
+ float3 N;
+} VelvetBsdf;
+
+ccl_device int bsdf_ashikhmin_velvet_setup(VelvetBsdf *bsdf)
{
- float sigma = fmaxf(sc->data0, 0.01f);
- sc->data0 = 1.0f/(sigma * sigma); /* m_invsigma2 */
+ float sigma = fmaxf(bsdf->sigma, 0.01f);
+ bsdf->invsigma2 = 1.0f/(sigma * sigma);
- sc->type = CLOSURE_BSDF_ASHIKHMIN_VELVET_ID;
+ bsdf->type = CLOSURE_BSDF_ASHIKHMIN_VELVET_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
+ccl_device bool bsdf_ashikhmin_velvet_merge(const ShaderClosure *a, const ShaderClosure *b)
+{
+ const VelvetBsdf *bsdf_a = (const VelvetBsdf*)a;
+ const VelvetBsdf *bsdf_b = (const VelvetBsdf*)b;
+
+ return (isequal_float3(bsdf_a->N, bsdf_b->N)) &&
+ (bsdf_a->sigma == bsdf_b->sigma);
+}
+
ccl_device float3 bsdf_ashikhmin_velvet_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
- float m_invsigma2 = sc->data0;
- float3 N = sc->N;
+ const VelvetBsdf *bsdf = (const VelvetBsdf*)sc;
+ float m_invsigma2 = bsdf->invsigma2;
+ float3 N = bsdf->N;
float cosNO = dot(N, I);
float cosNI = dot(N, omega_in);
@@ -90,8 +108,9 @@ ccl_device float3 bsdf_ashikhmin_velvet_eval_transmit(const ShaderClosure *sc, c
ccl_device int bsdf_ashikhmin_velvet_sample(const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
{
- float m_invsigma2 = sc->data0;
- float3 N = sc->N;
+ const VelvetBsdf *bsdf = (const VelvetBsdf*)sc;
+ float m_invsigma2 = bsdf->invsigma2;
+ float3 N = bsdf->N;
// we are viewing the surface from above - send a ray out with uniform
// distribution over the hemisphere
diff --git a/intern/cycles/kernel/closure/bsdf_diffuse.h b/intern/cycles/kernel/closure/bsdf_diffuse.h
index 4b29bb096d1..dcd187f9305 100644
--- a/intern/cycles/kernel/closure/bsdf_diffuse.h
+++ b/intern/cycles/kernel/closure/bsdf_diffuse.h
@@ -35,17 +35,31 @@
CCL_NAMESPACE_BEGIN
+typedef ccl_addr_space struct DiffuseBsdf {
+ SHADER_CLOSURE_BASE;
+ float3 N;
+} DiffuseBsdf;
+
/* DIFFUSE */
-ccl_device int bsdf_diffuse_setup(ShaderClosure *sc)
+ccl_device int bsdf_diffuse_setup(DiffuseBsdf *bsdf)
{
- sc->type = CLOSURE_BSDF_DIFFUSE_ID;
+ bsdf->type = CLOSURE_BSDF_DIFFUSE_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
+ccl_device bool bsdf_diffuse_merge(const ShaderClosure *a, const ShaderClosure *b)
+{
+ const DiffuseBsdf *bsdf_a = (const DiffuseBsdf*)a;
+ const DiffuseBsdf *bsdf_b = (const DiffuseBsdf*)b;
+
+ return (isequal_float3(bsdf_a->N, bsdf_b->N));
+}
+
ccl_device float3 bsdf_diffuse_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
- float3 N = sc->N;
+ const DiffuseBsdf *bsdf = (const DiffuseBsdf*)sc;
+ float3 N = bsdf->N;
float cos_pi = fmaxf(dot(N, omega_in), 0.0f) * M_1_PI_F;
*pdf = cos_pi;
@@ -59,7 +73,8 @@ ccl_device float3 bsdf_diffuse_eval_transmit(const ShaderClosure *sc, const floa
ccl_device int bsdf_diffuse_sample(const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
{
- float3 N = sc->N;
+ const DiffuseBsdf *bsdf = (const DiffuseBsdf*)sc;
+ float3 N = bsdf->N;
// distribution over the hemisphere
sample_cos_hemisphere(N, randu, randv, omega_in, pdf);
@@ -80,9 +95,9 @@ ccl_device int bsdf_diffuse_sample(const ShaderClosure *sc, float3 Ng, float3 I,
/* TRANSLUCENT */
-ccl_device int bsdf_translucent_setup(ShaderClosure *sc)
+ccl_device int bsdf_translucent_setup(DiffuseBsdf *bsdf)
{
- sc->type = CLOSURE_BSDF_TRANSLUCENT_ID;
+ bsdf->type = CLOSURE_BSDF_TRANSLUCENT_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
@@ -93,7 +108,8 @@ ccl_device float3 bsdf_translucent_eval_reflect(const ShaderClosure *sc, const f
ccl_device float3 bsdf_translucent_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
- float3 N = sc->N;
+ const DiffuseBsdf *bsdf = (const DiffuseBsdf*)sc;
+ float3 N = bsdf->N;
float cos_pi = fmaxf(-dot(N, omega_in), 0.0f) * M_1_PI_F;
*pdf = cos_pi;
@@ -102,7 +118,8 @@ ccl_device float3 bsdf_translucent_eval_transmit(const ShaderClosure *sc, const
ccl_device int bsdf_translucent_sample(const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
{
- float3 N = sc->N;
+ const DiffuseBsdf *bsdf = (const DiffuseBsdf*)sc;
+ float3 N = bsdf->N;
// we are viewing the surface from the right side - send a ray out with cosine
// distribution over the hemisphere
diff --git a/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h b/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h
index e0287e7655a..2d982a95fe4 100644
--- a/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h
+++ b/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h
@@ -35,7 +35,16 @@
CCL_NAMESPACE_BEGIN
-ccl_device float3 bsdf_diffuse_ramp_get_color(const ShaderClosure *sc, const float3 colors[8], float pos)
+#ifdef __OSL__
+
+typedef ccl_addr_space struct DiffuseRampBsdf {
+ SHADER_CLOSURE_BASE;
+
+ float3 N;
+ float3 *colors;
+} DiffuseRampBsdf;
+
+ccl_device float3 bsdf_diffuse_ramp_get_color(const float3 colors[8], float pos)
{
int MAXCOLORS = 8;
@@ -49,11 +58,9 @@ ccl_device float3 bsdf_diffuse_ramp_get_color(const ShaderClosure *sc, const flo
return colors[ipos] * (1.0f - offset) + colors[ipos+1] * offset;
}
-ccl_device int bsdf_diffuse_ramp_setup(ShaderClosure *sc)
+ccl_device int bsdf_diffuse_ramp_setup(DiffuseRampBsdf *bsdf)
{
- sc->type = CLOSURE_BSDF_DIFFUSE_RAMP_ID;
- sc->data0 = 0.0f;
- sc->data1 = 0.0f;
+ bsdf->type = CLOSURE_BSDF_DIFFUSE_RAMP_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
@@ -61,29 +68,31 @@ ccl_device void bsdf_diffuse_ramp_blur(ShaderClosure *sc, float roughness)
{
}
-ccl_device float3 bsdf_diffuse_ramp_eval_reflect(const ShaderClosure *sc, const float3 colors[8], const float3 I, const float3 omega_in, float *pdf)
+ccl_device float3 bsdf_diffuse_ramp_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
- float3 N = sc->N;
+ const DiffuseRampBsdf *bsdf = (const DiffuseRampBsdf*)sc;
+ float3 N = bsdf->N;
float cos_pi = fmaxf(dot(N, omega_in), 0.0f);
*pdf = cos_pi * M_1_PI_F;
- return bsdf_diffuse_ramp_get_color(sc, colors, cos_pi) * M_1_PI_F;
+ return bsdf_diffuse_ramp_get_color(bsdf->colors, cos_pi) * M_1_PI_F;
}
-ccl_device float3 bsdf_diffuse_ramp_eval_transmit(const ShaderClosure *sc, const float3 colors[8], const float3 I, const float3 omega_in, float *pdf)
+ccl_device float3 bsdf_diffuse_ramp_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
-ccl_device int bsdf_diffuse_ramp_sample(const ShaderClosure *sc, const float3 colors[8], float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
+ccl_device int bsdf_diffuse_ramp_sample(const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
{
- float3 N = sc->N;
+ const DiffuseRampBsdf *bsdf = (const DiffuseRampBsdf*)sc;
+ float3 N = bsdf->N;
// distribution over the hemisphere
sample_cos_hemisphere(N, randu, randv, omega_in, pdf);
if(dot(Ng, *omega_in) > 0.0f) {
- *eval = bsdf_diffuse_ramp_get_color(sc, colors, *pdf * M_PI_F) * M_1_PI_F;
+ *eval = bsdf_diffuse_ramp_get_color(bsdf->colors, *pdf * M_PI_F) * M_1_PI_F;
#ifdef __RAY_DIFFERENTIALS__
*domega_in_dx = (2 * dot(N, dIdx)) * N - dIdx;
*domega_in_dy = (2 * dot(N, dIdy)) * N - dIdy;
@@ -95,6 +104,8 @@ ccl_device int bsdf_diffuse_ramp_sample(const ShaderClosure *sc, const float3 co
return LABEL_REFLECT|LABEL_DIFFUSE;
}
+#endif /* __OSL__ */
+
CCL_NAMESPACE_END
#endif /* __BSDF_DIFFUSE_RAMP_H__ */
diff --git a/intern/cycles/kernel/closure/bsdf_hair.h b/intern/cycles/kernel/closure/bsdf_hair.h
index 1e81617a7d3..bede5f45e7e 100644
--- a/intern/cycles/kernel/closure/bsdf_hair.h
+++ b/intern/cycles/kernel/closure/bsdf_hair.h
@@ -35,29 +35,49 @@
CCL_NAMESPACE_BEGIN
+typedef ccl_addr_space struct HairBsdf {
+ SHADER_CLOSURE_BASE;
-ccl_device int bsdf_hair_reflection_setup(ShaderClosure *sc)
+ float3 T;
+ float roughness1;
+ float roughness2;
+ float offset;
+} HairBsdf;
+
+ccl_device int bsdf_hair_reflection_setup(HairBsdf *bsdf)
{
- sc->type = CLOSURE_BSDF_HAIR_REFLECTION_ID;
- sc->data0 = clamp(sc->data0, 0.001f, 1.0f);
- sc->data1 = clamp(sc->data1, 0.001f, 1.0f);
+ bsdf->type = CLOSURE_BSDF_HAIR_REFLECTION_ID;
+ bsdf->roughness1 = clamp(bsdf->roughness1, 0.001f, 1.0f);
+ bsdf->roughness2 = clamp(bsdf->roughness2, 0.001f, 1.0f);
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
-ccl_device int bsdf_hair_transmission_setup(ShaderClosure *sc)
+ccl_device int bsdf_hair_transmission_setup(HairBsdf *bsdf)
{
- sc->type = CLOSURE_BSDF_HAIR_TRANSMISSION_ID;
- sc->data0 = clamp(sc->data0, 0.001f, 1.0f);
- sc->data1 = clamp(sc->data1, 0.001f, 1.0f);
+ bsdf->type = CLOSURE_BSDF_HAIR_TRANSMISSION_ID;
+ bsdf->roughness1 = clamp(bsdf->roughness1, 0.001f, 1.0f);
+ bsdf->roughness2 = clamp(bsdf->roughness2, 0.001f, 1.0f);
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
+ccl_device bool bsdf_hair_merge(const ShaderClosure *a, const ShaderClosure *b)
+{
+ const HairBsdf *bsdf_a = (const HairBsdf*)a;
+ const HairBsdf *bsdf_b = (const HairBsdf*)b;
+
+ return (isequal_float3(bsdf_a->T, bsdf_b->T)) &&
+ (bsdf_a->roughness1 == bsdf_b->roughness1) &&
+ (bsdf_a->roughness2 == bsdf_b->roughness2) &&
+ (bsdf_a->offset == bsdf_b->offset);
+}
+
ccl_device float3 bsdf_hair_reflection_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
- float offset = sc->data2;
- float3 Tg = sc->T;
- float roughness1 = sc->data0;
- float roughness2 = sc->data1;
+ const HairBsdf *bsdf = (const HairBsdf*)sc;
+ float offset = bsdf->offset;
+ float3 Tg = bsdf->T;
+ float roughness1 = bsdf->roughness1;
+ float roughness2 = bsdf->roughness2;
float Iz = dot(Tg, I);
float3 locy = normalize(I - Tg * Iz);
@@ -107,10 +127,11 @@ ccl_device float3 bsdf_hair_reflection_eval_transmit(const ShaderClosure *sc, co
ccl_device float3 bsdf_hair_transmission_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
- float offset = sc->data2;
- float3 Tg = sc->T;
- float roughness1 = sc->data0;
- float roughness2 = sc->data1;
+ const HairBsdf *bsdf = (const HairBsdf*)sc;
+ float offset = bsdf->offset;
+ float3 Tg = bsdf->T;
+ float roughness1 = bsdf->roughness1;
+ float roughness2 = bsdf->roughness2;
float Iz = dot(Tg, I);
float3 locy = normalize(I - Tg * Iz);
@@ -148,10 +169,11 @@ ccl_device float3 bsdf_hair_transmission_eval_transmit(const ShaderClosure *sc,
ccl_device int bsdf_hair_reflection_sample(const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
{
- float offset = sc->data2;
- float3 Tg = sc->T;
- float roughness1 = sc->data0;
- float roughness2 = sc->data1;
+ const HairBsdf *bsdf = (const HairBsdf*)sc;
+ float offset = bsdf->offset;
+ float3 Tg = bsdf->T;
+ float roughness1 = bsdf->roughness1;
+ float roughness2 = bsdf->roughness2;
float Iz = dot(Tg, I);
float3 locy = normalize(I - Tg * Iz);
float3 locx = cross(locy, Tg);
@@ -198,10 +220,11 @@ ccl_device int bsdf_hair_reflection_sample(const ShaderClosure *sc, float3 Ng, f
ccl_device int bsdf_hair_transmission_sample(const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
{
- float offset = sc->data2;
- float3 Tg = sc->T;
- float roughness1 = sc->data0;
- float roughness2 = sc->data1;
+ const HairBsdf *bsdf = (const HairBsdf*)sc;
+ float offset = bsdf->offset;
+ float3 Tg = bsdf->T;
+ float roughness1 = bsdf->roughness1;
+ float roughness2 = bsdf->roughness2;
float Iz = dot(Tg, I);
float3 locy = normalize(I - Tg * Iz);
float3 locx = cross(locy, Tg);
diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h
index 2a0e8f62e7c..0a8d14a00c2 100644
--- a/intern/cycles/kernel/closure/bsdf_microfacet.h
+++ b/intern/cycles/kernel/closure/bsdf_microfacet.h
@@ -35,6 +35,19 @@
CCL_NAMESPACE_BEGIN
+typedef ccl_addr_space struct MicrofacetExtra {
+ float3 color;
+} MicrofacetExtra;
+
+typedef ccl_addr_space struct MicrofacetBsdf {
+ SHADER_CLOSURE_BASE;
+
+ float alpha_x, alpha_y, ior;
+ MicrofacetExtra *extra;
+ float3 T;
+ float3 N;
+} MicrofacetBsdf;
+
/* Beckmann and GGX microfacet importance sampling. */
ccl_device_inline void microfacet_beckmann_sample_slopes(
@@ -170,7 +183,7 @@ ccl_device_inline void microfacet_ggx_sample_slopes(
*slope_y = S * z * safe_sqrtf(1.0f + (*slope_x)*(*slope_x));
}
-ccl_device_inline float3 microfacet_sample_stretched(
+ccl_device_forceinline float3 microfacet_sample_stretched(
KernelGlobals *kg, const float3 omega_i,
const float alpha_x, const float alpha_y,
const float randu, const float randv,
@@ -233,50 +246,68 @@ ccl_device_inline float3 microfacet_sample_stretched(
* Anisotropy is only supported for reflection currently, but adding it for
* transmission is just a matter of copying code from reflection if needed. */
-ccl_device int bsdf_microfacet_ggx_setup(ShaderClosure *sc)
+ccl_device int bsdf_microfacet_ggx_setup(MicrofacetBsdf *bsdf)
{
- sc->data0 = saturate(sc->data0); /* alpha_x */
- sc->data1 = sc->data0; /* alpha_y */
+ bsdf->alpha_x = saturate(bsdf->alpha_x);
+ bsdf->alpha_y = bsdf->alpha_x;
- sc->type = CLOSURE_BSDF_MICROFACET_GGX_ID;
+ bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
-ccl_device int bsdf_microfacet_ggx_aniso_setup(ShaderClosure *sc)
+ccl_device bool bsdf_microfacet_merge(const ShaderClosure *a, const ShaderClosure *b)
+{
+ const MicrofacetBsdf *bsdf_a = (const MicrofacetBsdf*)a;
+ const MicrofacetBsdf *bsdf_b = (const MicrofacetBsdf*)b;
+
+ return (isequal_float3(bsdf_a->N, bsdf_b->N)) &&
+ (bsdf_a->alpha_x == bsdf_b->alpha_x) &&
+ (bsdf_a->alpha_y == bsdf_b->alpha_y) &&
+ (isequal_float3(bsdf_a->T, bsdf_b->T)) &&
+ (bsdf_a->ior == bsdf_b->ior) &&
+ ((!bsdf_a->extra && !bsdf_b->extra) ||
+ ((bsdf_a->extra && bsdf_b->extra) &&
+ (isequal_float3(bsdf_a->extra->color, bsdf_b->extra->color))));
+}
+
+ccl_device int bsdf_microfacet_ggx_aniso_setup(MicrofacetBsdf *bsdf)
{
- sc->data0 = saturate(sc->data0); /* alpha_x */
- sc->data1 = saturate(sc->data1); /* alpha_y */
+ bsdf->alpha_x = saturate(bsdf->alpha_x);
+ bsdf->alpha_y = saturate(bsdf->alpha_y);
- sc->type = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID;
+ bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
-ccl_device int bsdf_microfacet_ggx_refraction_setup(ShaderClosure *sc)
+ccl_device int bsdf_microfacet_ggx_refraction_setup(MicrofacetBsdf *bsdf)
{
- sc->data0 = saturate(sc->data0); /* alpha_x */
- sc->data1 = sc->data0; /* alpha_y */
+ bsdf->alpha_x = saturate(bsdf->alpha_x);
+ bsdf->alpha_y = bsdf->alpha_x;
- sc->type = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
+ bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
ccl_device void bsdf_microfacet_ggx_blur(ShaderClosure *sc, float roughness)
{
- sc->data0 = fmaxf(roughness, sc->data0); /* alpha_x */
- sc->data1 = fmaxf(roughness, sc->data1); /* alpha_y */
+ MicrofacetBsdf *bsdf = (MicrofacetBsdf*)sc;
+
+ bsdf->alpha_x = fmaxf(roughness, bsdf->alpha_x);
+ bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y);
}
ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
- float alpha_x = sc->data0;
- float alpha_y = sc->data1;
- bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
- float3 N = sc->N;
+ const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc;
+ float alpha_x = bsdf->alpha_x;
+ float alpha_y = bsdf->alpha_y;
+ bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
+ float3 N = bsdf->N;
- if(m_refractive || fmaxf(alpha_x, alpha_y) <= 1e-4f)
+ if(m_refractive || alpha_x*alpha_y <= 1e-7f)
return make_float3(0.0f, 0.0f, 0.0f);
float cosNO = dot(N, I);
@@ -305,7 +336,7 @@ ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc, cons
else {
/* anisotropic */
float3 X, Y, Z = N;
- make_orthonormals_tangent(Z, sc->T, &X, &Y);
+ make_orthonormals_tangent(Z, bsdf->T, &X, &Y);
/* distribution */
float3 local_m = make_float3(dot(X, m), dot(Y, m), dot(Z, m));
@@ -361,13 +392,14 @@ ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc, cons
ccl_device float3 bsdf_microfacet_ggx_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
- float alpha_x = sc->data0;
- float alpha_y = sc->data1;
- float m_eta = sc->data2;
- bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
- float3 N = sc->N;
-
- if(!m_refractive || fmaxf(alpha_x, alpha_y) <= 1e-4f)
+ const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc;
+ float alpha_x = bsdf->alpha_x;
+ float alpha_y = bsdf->alpha_y;
+ float m_eta = bsdf->ior;
+ bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
+ float3 N = bsdf->N;
+
+ if(!m_refractive || alpha_x*alpha_y <= 1e-7f)
return make_float3(0.0f, 0.0f, 0.0f);
float cosNO = dot(N, I);
@@ -415,10 +447,11 @@ ccl_device float3 bsdf_microfacet_ggx_eval_transmit(const ShaderClosure *sc, con
ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
{
- float alpha_x = sc->data0;
- float alpha_y = sc->data1;
- bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
- float3 N = sc->N;
+ const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc;
+ float alpha_x = bsdf->alpha_x;
+ float alpha_y = bsdf->alpha_y;
+ bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
+ float3 N = bsdf->N;
float cosNO = dot(N, I);
if(cosNO > 0) {
@@ -427,7 +460,7 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure
if(alpha_x == alpha_y)
make_orthonormals(Z, &X, &Y);
else
- make_orthonormals_tangent(Z, sc->T, &X, &Y);
+ make_orthonormals_tangent(Z, bsdf->T, &X, &Y);
/* importance sampling with distribution of visible normals. vectors are
* transformed to local space before and after */
@@ -450,7 +483,7 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure
*omega_in = 2 * cosMO * m - I;
if(dot(Ng, *omega_in) > 0) {
- if(fmaxf(alpha_x, alpha_y) <= 1e-4f) {
+ if(alpha_x*alpha_y <= 1e-7f) {
/* some high number for MIS */
*pdf = 1e6f;
*eval = make_float3(1e6f, 1e6f, 1e6f);
@@ -522,7 +555,7 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure
#ifdef __RAY_DIFFERENTIALS__
float3 dRdx, dRdy, dTdx, dTdy;
#endif
- float m_eta = sc->data2, fresnel;
+ float m_eta = bsdf->ior, fresnel;
bool inside;
fresnel = fresnel_dielectric(m_eta, m, I, &R, &T,
@@ -539,7 +572,7 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure
*domega_in_dy = dTdy;
#endif
- if(fmaxf(alpha_x, alpha_y) <= 1e-4f || fabsf(m_eta - 1.0f) < 1e-4f) {
+ if(alpha_x*alpha_y <= 1e-7f || fabsf(m_eta - 1.0f) < 1e-4f) {
/* some high number for MIS */
*pdf = 1e6f;
*eval = make_float3(1e6f, 1e6f, 1e6f);
@@ -582,47 +615,80 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure
* Microfacet Models for Refraction through Rough Surfaces
* B. Walter, S. R. Marschner, H. Li, K. E. Torrance, EGSR 2007 */
-ccl_device int bsdf_microfacet_beckmann_setup(ShaderClosure *sc)
+ccl_device int bsdf_microfacet_beckmann_setup(MicrofacetBsdf *bsdf)
{
- sc->data0 = saturate(sc->data0); /* alpha_x */
- sc->data1 = sc->data0; /* alpha_y */
+ bsdf->alpha_x = saturate(bsdf->alpha_x);
+ bsdf->alpha_y = bsdf->alpha_x;
- sc->type = CLOSURE_BSDF_MICROFACET_BECKMANN_ID;
+ bsdf->type = CLOSURE_BSDF_MICROFACET_BECKMANN_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
-ccl_device int bsdf_microfacet_beckmann_aniso_setup(ShaderClosure *sc)
+ccl_device int bsdf_microfacet_beckmann_aniso_setup(MicrofacetBsdf *bsdf)
{
- sc->data0 = saturate(sc->data0); /* alpha_x */
- sc->data1 = saturate(sc->data1); /* alpha_y */
+ bsdf->alpha_x = saturate(bsdf->alpha_x);
+ bsdf->alpha_y = saturate(bsdf->alpha_y);
- sc->type = CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID;
+ bsdf->type = CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
-ccl_device int bsdf_microfacet_beckmann_refraction_setup(ShaderClosure *sc)
+ccl_device int bsdf_microfacet_beckmann_refraction_setup(MicrofacetBsdf *bsdf)
{
- sc->data0 = saturate(sc->data0); /* alpha_x */
- sc->data1 = sc->data0; /* alpha_y */
+ bsdf->alpha_x = saturate(bsdf->alpha_x);
+ bsdf->alpha_y = bsdf->alpha_x;
- sc->type = CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
+ bsdf->type = CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
ccl_device void bsdf_microfacet_beckmann_blur(ShaderClosure *sc, float roughness)
{
- sc->data0 = fmaxf(roughness, sc->data0); /* alpha_x */
- sc->data1 = fmaxf(roughness, sc->data1); /* alpha_y */
+ MicrofacetBsdf *bsdf = (MicrofacetBsdf*)sc;
+
+ bsdf->alpha_x = fmaxf(roughness, bsdf->alpha_x);
+ bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y);
+}
+
+ccl_device_inline float bsdf_beckmann_G1(float alpha, float cos_n)
+{
+ cos_n *= cos_n;
+ float invA = alpha * safe_sqrtf((1.0f - cos_n) / cos_n);
+ if(invA < 0.625f) {
+ return 1.0f;
+ }
+
+ float a = 1.0f / invA;
+ return ((2.181f*a + 3.535f)*a) / ((2.577f*a + 2.276f)*a + 1.0f);
+}
+
+ccl_device_inline float bsdf_beckmann_aniso_G1(float alpha_x, float alpha_y, float cos_n, float cos_phi, float sin_phi)
+{
+ cos_n *= cos_n;
+ sin_phi *= sin_phi;
+ cos_phi *= cos_phi;
+ alpha_x *= alpha_x;
+ alpha_y *= alpha_y;
+
+ float alphaO2 = (cos_phi*alpha_x + sin_phi*alpha_y) / (cos_phi + sin_phi);
+ float invA = safe_sqrtf(alphaO2 * (1 - cos_n) / cos_n);
+ if(invA < 0.625f) {
+ return 1.0f;
+ }
+
+ float a = 1.0f / invA;
+ return ((2.181f*a + 3.535f)*a) / ((2.577f*a + 2.276f)*a + 1.0f);
}
ccl_device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
- float alpha_x = sc->data0;
- float alpha_y = sc->data1;
- bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
- float3 N = sc->N;
+ const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc;
+ float alpha_x = bsdf->alpha_x;
+ float alpha_y = bsdf->alpha_y;
+ bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
+ float3 N = bsdf->N;
- if(m_refractive || fmaxf(alpha_x, alpha_y) <= 1e-4f)
+ if(m_refractive || alpha_x*alpha_y <= 1e-7f)
return make_float3(0.0f, 0.0f, 0.0f);
float cosNO = dot(N, I);
@@ -646,15 +712,13 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderClosure *sc,
D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4);
/* eq. 26, 27: now calculate G1(i,m) and G1(o,m) */
- float ao = 1 / (alpha_x * safe_sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO)));
- float ai = 1 / (alpha_x * safe_sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI)));
- G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f;
- G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
+ G1o = bsdf_beckmann_G1(alpha_x, cosNO);
+ G1i = bsdf_beckmann_G1(alpha_x, cosNI);
}
else {
/* anisotropic */
float3 X, Y, Z = N;
- make_orthonormals_tangent(Z, sc->T, &X, &Y);
+ make_orthonormals_tangent(Z, bsdf->T, &X, &Y);
/* distribution */
float3 local_m = make_float3(dot(X, m), dot(Y, m), dot(Z, m));
@@ -668,24 +732,8 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderClosure *sc,
D = expf(-slope_x*slope_x - slope_y*slope_y) / (M_PI_F * alpha2 * cosThetaM4);
/* G1(i,m) and G1(o,m) */
- float tanThetaO2 = (1 - cosNO * cosNO) / (cosNO * cosNO);
- float cosPhiO = dot(I, X);
- float sinPhiO = dot(I, Y);
-
- float alphaO2 = (cosPhiO*cosPhiO)*(alpha_x*alpha_x) + (sinPhiO*sinPhiO)*(alpha_y*alpha_y);
- alphaO2 /= cosPhiO*cosPhiO + sinPhiO*sinPhiO;
-
- float tanThetaI2 = (1 - cosNI * cosNI) / (cosNI * cosNI);
- float cosPhiI = dot(omega_in, X);
- float sinPhiI = dot(omega_in, Y);
-
- float alphaI2 = (cosPhiI*cosPhiI)*(alpha_x*alpha_x) + (sinPhiI*sinPhiI)*(alpha_y*alpha_y);
- alphaI2 /= cosPhiI*cosPhiI + sinPhiI*sinPhiI;
-
- float ao = 1 / (safe_sqrtf(alphaO2 * tanThetaO2));
- float ai = 1 / (safe_sqrtf(alphaI2 * tanThetaI2));
- G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f;
- G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
+ G1o = bsdf_beckmann_aniso_G1(alpha_x, alpha_y, cosNO, dot(I, X), dot(I, Y));
+ G1i = bsdf_beckmann_aniso_G1(alpha_x, alpha_y, cosNI, dot(omega_in, X), dot(omega_in, Y));
}
float G = G1o * G1i;
@@ -710,13 +758,14 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderClosure *sc,
ccl_device float3 bsdf_microfacet_beckmann_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
- float alpha_x = sc->data0;
- float alpha_y = sc->data1;
- float m_eta = sc->data2;
- bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
- float3 N = sc->N;
-
- if(!m_refractive || fmaxf(alpha_x, alpha_y) <= 1e-4f)
+ const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc;
+ float alpha_x = bsdf->alpha_x;
+ float alpha_y = bsdf->alpha_y;
+ float m_eta = bsdf->ior;
+ bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
+ float3 N = bsdf->N;
+
+ if(!m_refractive || alpha_x*alpha_y <= 1e-7f)
return make_float3(0.0f, 0.0f, 0.0f);
float cosNO = dot(N, I);
@@ -740,10 +789,8 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_transmit(const ShaderClosure *sc
float D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4);
/* eq. 26, 27: now calculate G1(i,m) and G1(o,m) */
- float ao = 1 / (alpha_x * safe_sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO)));
- float ai = 1 / (alpha_x * safe_sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI)));
- float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f;
- float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
+ float G1o = bsdf_beckmann_G1(alpha_x, cosNO);
+ float G1i = bsdf_beckmann_G1(alpha_x, cosNI);
float G = G1o * G1i;
/* probability */
@@ -763,10 +810,11 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_transmit(const ShaderClosure *sc
ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
{
- float alpha_x = sc->data0;
- float alpha_y = sc->data1;
- bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
- float3 N = sc->N;
+ const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc;
+ float alpha_x = bsdf->alpha_x;
+ float alpha_y = bsdf->alpha_y;
+ bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
+ float3 N = bsdf->N;
float cosNO = dot(N, I);
if(cosNO > 0) {
@@ -775,7 +823,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl
if(alpha_x == alpha_y)
make_orthonormals(Z, &X, &Y);
else
- make_orthonormals_tangent(Z, sc->T, &X, &Y);
+ make_orthonormals_tangent(Z, bsdf->T, &X, &Y);
/* importance sampling with distribution of visible normals. vectors are
* transformed to local space before and after */
@@ -798,7 +846,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl
*omega_in = 2 * cosMO * m - I;
if(dot(Ng, *omega_in) > 0) {
- if(fmaxf(alpha_x, alpha_y) <= 1e-4f) {
+ if(alpha_x*alpha_y <= 1e-7f) {
/* some high number for MIS */
*pdf = 1e6f;
*eval = make_float3(1e6f, 1e6f, 1e6f);
@@ -820,8 +868,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl
float cosNI = dot(N, *omega_in);
/* eq. 26, 27: now calculate G1(i,m) */
- float ai = 1 / (alpha_x * safe_sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI)));
- G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
+ G1i = bsdf_beckmann_G1(alpha_x, cosNI);
}
else {
/* anisotropic distribution */
@@ -836,16 +883,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl
D = expf(-slope_x*slope_x - slope_y*slope_y) / (M_PI_F * alpha2 * cosThetaM4);
/* G1(i,m) */
- float cosNI = dot(N, *omega_in);
- float tanThetaI2 = (1 - cosNI * cosNI) / (cosNI * cosNI);
- float cosPhiI = dot(*omega_in, X);
- float sinPhiI = dot(*omega_in, Y);
-
- float alphaI2 = (cosPhiI*cosPhiI)*(alpha_x*alpha_x) + (sinPhiI*sinPhiI)*(alpha_y*alpha_y);
- alphaI2 /= cosPhiI*cosPhiI + sinPhiI*sinPhiI;
-
- float ai = 1 / (safe_sqrtf(alphaI2 * tanThetaI2));
- G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
+ G1i = bsdf_beckmann_aniso_G1(alpha_x, alpha_y, dot(*omega_in, N), dot(*omega_in, X), dot(*omega_in, Y));
}
float G = G1o * G1i;
@@ -872,7 +910,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl
#ifdef __RAY_DIFFERENTIALS__
float3 dRdx, dRdy, dTdx, dTdy;
#endif
- float m_eta = sc->data2, fresnel;
+ float m_eta = bsdf->ior, fresnel;
bool inside;
fresnel = fresnel_dielectric(m_eta, m, I, &R, &T,
@@ -889,7 +927,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl
*domega_in_dy = dTdy;
#endif
- if(fmaxf(alpha_x, alpha_y) <= 1e-4f || fabsf(m_eta - 1.0f) < 1e-4f) {
+ if(alpha_x*alpha_y <= 1e-7f || fabsf(m_eta - 1.0f) < 1e-4f) {
/* some high number for MIS */
*pdf = 1e6f;
*eval = make_float3(1e6f, 1e6f, 1e6f);
@@ -906,8 +944,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl
float cosNI = dot(N, *omega_in);
/* eq. 26, 27: now calculate G1(i,m) */
- float ai = 1 / (alpha_x * safe_sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI)));
- float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
+ float G1i = bsdf_beckmann_G1(alpha_x, cosNI);
float G = G1o * G1i;
/* eq. 21 */
diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h
new file mode 100644
index 00000000000..cea59adfebe
--- /dev/null
+++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h
@@ -0,0 +1,557 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* Most of the code is based on the supplemental implementations from https://eheitzresearch.wordpress.com/240-2/. */
+
+/* === GGX Microfacet distribution functions === */
+
+/* Isotropic GGX microfacet distribution */
+ccl_device_forceinline float D_ggx(float3 wm, float alpha)
+{
+ wm.z *= wm.z;
+ alpha *= alpha;
+ float tmp = (1.0f - wm.z) + alpha * wm.z;
+ return alpha / max(M_PI_F * tmp*tmp, 1e-7f);
+}
+
+/* Anisotropic GGX microfacet distribution */
+ccl_device_forceinline float D_ggx_aniso(const float3 wm, const float2 alpha)
+{
+ float slope_x = -wm.x/alpha.x;
+ float slope_y = -wm.y/alpha.y;
+ float tmp = wm.z*wm.z + slope_x*slope_x + slope_y*slope_y;
+
+ return 1.0f / max(M_PI_F * tmp*tmp * alpha.x*alpha.y, 1e-7f);
+}
+
+/* Sample slope distribution (based on page 14 of the supplemental implementation). */
+ccl_device_forceinline float2 mf_sampleP22_11(const float cosI, const float2 randU)
+{
+ if(cosI > 0.9999f || cosI < 1e-6f) {
+ const float r = sqrtf(randU.x / (1.0f - randU.x));
+ const float phi = M_2PI_F * randU.y;
+ return make_float2(r*cosf(phi), r*sinf(phi));
+ }
+
+ const float sinI = sqrtf(1.0f - cosI*cosI);
+ const float tanI = sinI/cosI;
+ const float projA = 0.5f * (cosI + 1.0f);
+ if(projA < 0.0001f)
+ return make_float2(0.0f, 0.0f);
+ const float A = 2.0f*randU.x*projA / cosI - 1.0f;
+ float tmp = A*A-1.0f;
+ if(fabsf(tmp) < 1e-7f)
+ return make_float2(0.0f, 0.0f);
+ tmp = 1.0f / tmp;
+ const float D = safe_sqrtf(tanI*tanI*tmp*tmp - (A*A-tanI*tanI)*tmp);
+
+ const float slopeX2 = tanI*tmp + D;
+ const float slopeX = (A < 0.0f || slopeX2 > 1.0f/tanI)? (tanI*tmp - D) : slopeX2;
+
+ float U2;
+ if(randU.y >= 0.5f)
+ U2 = 2.0f*(randU.y - 0.5f);
+ else
+ U2 = 2.0f*(0.5f - randU.y);
+ const float z = (U2*(U2*(U2*0.27385f-0.73369f)+0.46341f)) / (U2*(U2*(U2*0.093073f+0.309420f)-1.0f)+0.597999f);
+ const float slopeY = z * sqrtf(1.0f + slopeX*slopeX);
+
+ if(randU.y >= 0.5f)
+ return make_float2(slopeX, slopeY);
+ else
+ return make_float2(slopeX, -slopeY);
+}
+
+/* Visible normal sampling for the GGX distribution (based on page 7 of the supplemental implementation). */
+ccl_device_forceinline float3 mf_sample_vndf(const float3 wi, const float2 alpha, const float2 randU)
+{
+ const float3 wi_11 = normalize(make_float3(alpha.x*wi.x, alpha.y*wi.y, wi.z));
+ const float2 slope_11 = mf_sampleP22_11(wi_11.z, randU);
+
+ const float2 cossin_phi = normalize(make_float2(wi_11.x, wi_11.y));
+ const float slope_x = alpha.x*(cossin_phi.x * slope_11.x - cossin_phi.y * slope_11.y);
+ const float slope_y = alpha.y*(cossin_phi.y * slope_11.x + cossin_phi.x * slope_11.y);
+
+ kernel_assert(isfinite(slope_x));
+ return normalize(make_float3(-slope_x, -slope_y, 1.0f));
+}
+
+/* === Phase functions: Glossy, Diffuse and Glass === */
+
+/* Phase function for reflective materials, either without a fresnel term (for compatibility) or with the conductive fresnel term. */
+ccl_device_forceinline float3 mf_sample_phase_glossy(const float3 wi, float3 *n, float3 *k, float3 *weight, const float3 wm)
+{
+ if(n && k)
+ *weight *= fresnel_conductor(dot(wi, wm), *n, *k);
+
+ return -wi + 2.0f * wm * dot(wi, wm);
+}
+
+ccl_device_forceinline float3 mf_eval_phase_glossy(const float3 w, const float lambda, const float3 wo, const float2 alpha, float3 *n, float3 *k)
+{
+ if(w.z > 0.9999f)
+ return make_float3(0.0f, 0.0f, 0.0f);
+
+ const float3 wh = normalize(wo - w);
+ if(wh.z < 0.0f)
+ return make_float3(0.0f, 0.0f, 0.0f);
+
+ float pArea = (w.z < -0.9999f)? 1.0f: lambda*w.z;
+
+ const float dotW_WH = dot(-w, wh);
+ if(dotW_WH < 0.0f)
+ return make_float3(0.0f, 0.0f, 0.0f);
+
+ float phase = max(0.0f, dotW_WH) * 0.25f / max(pArea * dotW_WH, 1e-7f);
+ if(alpha.x == alpha.y)
+ phase *= D_ggx(wh, alpha.x);
+ else
+ phase *= D_ggx_aniso(wh, alpha);
+
+ if(n && k) {
+ /* Apply conductive fresnel term. */
+ return phase * fresnel_conductor(dotW_WH, *n, *k);
+ }
+
+ return make_float3(phase, phase, phase);
+}
+
+/* Phase function for rough lambertian diffuse surfaces. */
+ccl_device_forceinline float3 mf_sample_phase_diffuse(const float3 wm, const float randu, const float randv)
+{
+ float3 tm, bm;
+ make_orthonormals(wm, &tm, &bm);
+
+ float2 disk = concentric_sample_disk(randu, randv);
+ return disk.x*tm + disk.y*bm + safe_sqrtf(1.0f - disk.x*disk.x - disk.y*disk.y)*wm;
+}
+
+ccl_device_forceinline float3 mf_eval_phase_diffuse(const float3 w, const float3 wm)
+{
+ const float v = max(0.0f, dot(w, wm)) * M_1_PI_F;
+ return make_float3(v, v, v);
+}
+
+/* Phase function for dielectric transmissive materials, including both reflection and refraction according to the dielectric fresnel term. */
+ccl_device_forceinline float3 mf_sample_phase_glass(const float3 wi, const float eta, const float3 wm, const float randV, bool *outside)
+{
+ float cosI = dot(wi, wm);
+ float f = fresnel_dielectric_cos(cosI, eta);
+ if(randV < f) {
+ *outside = true;
+ return -wi + 2.0f * wm * cosI;
+ }
+ *outside = false;
+ float inv_eta = 1.0f/eta;
+ float cosT = -safe_sqrtf(1.0f - (1.0f - cosI*cosI) * inv_eta*inv_eta);
+ return normalize(wm*(cosI*inv_eta + cosT) - wi*inv_eta);
+}
+
+ccl_device_forceinline float3 mf_eval_phase_glass(const float3 w, const float lambda, const float3 wo, const bool wo_outside, const float2 alpha, const float eta)
+{
+ if(w.z > 0.9999f)
+ return make_float3(0.0f, 0.0f, 0.0f);
+
+ float pArea = (w.z < -0.9999f)? 1.0f: lambda*w.z;
+ float v;
+ if(wo_outside) {
+ const float3 wh = normalize(wo - w);
+ if(wh.z < 0.0f)
+ return make_float3(0.0f, 0.0f, 0.0f);
+
+ const float dotW_WH = dot(-w, wh);
+ v = fresnel_dielectric_cos(dotW_WH, eta) * max(0.0f, dotW_WH) * D_ggx(wh, alpha.x) * 0.25f / (pArea * dotW_WH);
+ }
+ else {
+ float3 wh = normalize(wo*eta - w);
+ if(wh.z < 0.0f)
+ wh = -wh;
+ const float dotW_WH = dot(-w, wh), dotWO_WH = dot(wo, wh);
+ if(dotW_WH < 0.0f)
+ return make_float3(0.0f, 0.0f, 0.0f);
+
+ float temp = dotW_WH + eta*dotWO_WH;
+ v = (1.0f - fresnel_dielectric_cos(dotW_WH, eta)) * max(0.0f, dotW_WH) * max(0.0f, -dotWO_WH) * D_ggx(wh, alpha.x) / (pArea * temp * temp);
+ }
+
+ return make_float3(v, v, v);
+}
+
+/* === Utility functions for the random walks === */
+
+/* Smith Lambda function for GGX (based on page 12 of the supplemental implementation). */
+ccl_device_forceinline float mf_lambda(const float3 w, const float2 alpha)
+{
+ if(w.z > 0.9999f)
+ return 0.0f;
+ else if(w.z < -0.9999f)
+ return -0.9999f;
+
+ const float inv_wz2 = 1.0f / max(w.z*w.z, 1e-7f);
+ const float2 wa = make_float2(w.x, w.y)*alpha;
+ float v = sqrtf(1.0f + dot(wa, wa) * inv_wz2);
+ if(w.z <= 0.0f)
+ v = -v;
+
+ return 0.5f*(v - 1.0f);
+}
+
+/* Height distribution CDF (based on page 4 of the supplemental implementation). */
+ccl_device_forceinline float mf_invC1(const float h)
+{
+ return 2.0f * saturate(h) - 1.0f;
+}
+
+ccl_device_forceinline float mf_C1(const float h)
+{
+ return saturate(0.5f * (h + 1.0f));
+}
+
+/* Masking function (based on page 16 of the supplemental implementation). */
+ccl_device_forceinline float mf_G1(const float3 w, const float C1, const float lambda)
+{
+ if(w.z > 0.9999f)
+ return 1.0f;
+ if(w.z < 1e-5f)
+ return 0.0f;
+ return powf(C1, lambda);
+}
+
+/* Sampling from the visible height distribution (based on page 17 of the supplemental implementation). */
+ccl_device_forceinline bool mf_sample_height(const float3 w, float *h, float *C1, float *G1, float *lambda, const float U)
+{
+ if(w.z > 0.9999f)
+ return false;
+ if(w.z < -0.9999f) {
+ *C1 *= U;
+ *h = mf_invC1(*C1);
+ *G1 = mf_G1(w, *C1, *lambda);
+ }
+ else if(fabsf(w.z) >= 0.0001f) {
+ if(U > 1.0f - *G1)
+ return false;
+ if(*lambda >= 0.0f) {
+ *C1 = 1.0f;
+ }
+ else {
+ *C1 *= powf(1.0f-U, -1.0f / *lambda);
+ }
+ *h = mf_invC1(*C1);
+ *G1 = mf_G1(w, *C1, *lambda);
+ }
+ return true;
+}
+
+/* === PDF approximations for the different phase functions. ===
+ * As explained in bsdf_microfacet_multi_impl.h, using approximations with MIS still produces an unbiased result. */
+
+/* Approximation for the albedo of the single-scattering GGX distribution,
+ * the missing energy is then approximated as a diffuse reflection for the PDF. */
+ccl_device_forceinline float mf_ggx_albedo(float r)
+{
+ float albedo = 0.806495f*expf(-1.98712f*r*r) + 0.199531f;
+ albedo -= ((((((1.76741f*r - 8.43891f)*r + 15.784f)*r - 14.398f)*r + 6.45221f)*r - 1.19722f)*r + 0.027803f)*r + 0.00568739f;
+ return saturate(albedo);
+}
+
+ccl_device_forceinline float mf_ggx_pdf(const float3 wi, const float3 wo, const float alpha)
+{
+ float D = D_ggx(normalize(wi+wo), alpha);
+ float lambda = mf_lambda(wi, make_float2(alpha, alpha));
+ float albedo = mf_ggx_albedo(alpha);
+ return 0.25f * D / max((1.0f + lambda) * wi.z, 1e-7f) + (1.0f - albedo) * wo.z;
+}
+
+ccl_device_forceinline float mf_ggx_aniso_pdf(const float3 wi, const float3 wo, const float2 alpha)
+{
+ return 0.25f * D_ggx_aniso(normalize(wi+wo), alpha) / ((1.0f + mf_lambda(wi, alpha)) * wi.z) + (1.0f - mf_ggx_albedo(sqrtf(alpha.x*alpha.y))) * wo.z;
+}
+
+ccl_device_forceinline float mf_diffuse_pdf(const float3 wo)
+{
+ return M_1_PI_F * wo.z;
+}
+
+ccl_device_forceinline float mf_glass_pdf(const float3 wi, const float3 wo, const float alpha, const float eta)
+{
+ float3 wh;
+ float fresnel;
+ if(wi.z*wo.z > 0.0f) {
+ wh = normalize(wi + wo);
+ fresnel = fresnel_dielectric_cos(dot(wi, wh), eta);
+ }
+ else {
+ wh = normalize(wi + wo*eta);
+ fresnel = 1.0f - fresnel_dielectric_cos(dot(wi, wh), eta);
+ }
+ if(wh.z < 0.0f)
+ wh = -wh;
+ float3 r_wi = (wi.z < 0.0f)? -wi: wi;
+ return fresnel * max(0.0f, dot(r_wi, wh)) * D_ggx(wh, alpha) / ((1.0f + mf_lambda(r_wi, make_float2(alpha, alpha))) * r_wi.z) + fabsf(wo.z);
+}
+
+/* === Actual random walk implementations, one version of mf_eval and mf_sample per phase function. === */
+
+#define MF_NAME_JOIN(x,y) x ## _ ## y
+#define MF_NAME_EVAL(x,y) MF_NAME_JOIN(x,y)
+#define MF_FUNCTION_FULL_NAME(prefix) MF_NAME_EVAL(prefix, MF_PHASE_FUNCTION)
+
+#define MF_PHASE_FUNCTION glass
+#define MF_MULTI_GLASS
+#include "bsdf_microfacet_multi_impl.h"
+
+/* The diffuse phase function is not implemented as a node yet. */
+#if 0
+#define MF_PHASE_FUNCTION diffuse
+#define MF_MULTI_DIFFUSE
+#include "bsdf_microfacet_multi_impl.h"
+#endif
+
+#define MF_PHASE_FUNCTION glossy
+#define MF_MULTI_GLOSSY
+#include "bsdf_microfacet_multi_impl.h"
+
+ccl_device void bsdf_microfacet_multi_ggx_blur(ShaderClosure *sc, float roughness)
+{
+ MicrofacetBsdf *bsdf = (MicrofacetBsdf*)sc;
+
+ bsdf->alpha_x = fmaxf(roughness, bsdf->alpha_x);
+ bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y);
+}
+
+/* === Closure implementations === */
+
+/* Multiscattering GGX Glossy closure */
+
+ccl_device int bsdf_microfacet_multi_ggx_common_setup(MicrofacetBsdf *bsdf)
+{
+ bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f);
+ bsdf->alpha_y = clamp(bsdf->alpha_y, 1e-4f, 1.0f);
+ bsdf->extra->color.x = saturate(bsdf->extra->color.x);
+ bsdf->extra->color.y = saturate(bsdf->extra->color.y);
+ bsdf->extra->color.z = saturate(bsdf->extra->color.z);
+
+ bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID;
+
+ return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_NEEDS_LCG;
+}
+
+ccl_device int bsdf_microfacet_multi_ggx_aniso_setup(MicrofacetBsdf *bsdf)
+{
+ if(is_zero(bsdf->T))
+ bsdf->T = make_float3(1.0f, 0.0f, 0.0f);
+
+ return bsdf_microfacet_multi_ggx_common_setup(bsdf);
+}
+
+ccl_device int bsdf_microfacet_multi_ggx_setup(MicrofacetBsdf *bsdf)
+{
+ bsdf->alpha_y = bsdf->alpha_x;
+
+ return bsdf_microfacet_multi_ggx_common_setup(bsdf);
+}
+
+ccl_device float3 bsdf_microfacet_multi_ggx_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) {
+ *pdf = 0.0f;
+ return make_float3(0.0f, 0.0f, 0.0f);
+}
+
+ccl_device float3 bsdf_microfacet_multi_ggx_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) {
+ const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc;
+
+ if(bsdf->alpha_x*bsdf->alpha_y < 1e-7f) {
+ return make_float3(0.0f, 0.0f, 0.0f);
+ }
+
+ bool is_aniso = (bsdf->alpha_x != bsdf->alpha_y);
+ float3 X, Y, Z;
+ Z = bsdf->N;
+ if(is_aniso)
+ make_orthonormals_tangent(Z, bsdf->T, &X, &Y);
+ else
+ make_orthonormals(Z, &X, &Y);
+
+ float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z));
+ float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z));
+
+ if(is_aniso)
+ *pdf = mf_ggx_aniso_pdf(localI, localO, make_float2(bsdf->alpha_x, bsdf->alpha_y));
+ else
+ *pdf = mf_ggx_pdf(localI, localO, bsdf->alpha_x);
+ return mf_eval_glossy(localI, localO, true, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, NULL, NULL);
+}
+
+ccl_device int bsdf_microfacet_multi_ggx_sample(KernelGlobals *kg, const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf, ccl_addr_space uint *lcg_state)
+{
+ const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc;
+
+ float3 X, Y, Z;
+ Z = bsdf->N;
+
+ if(bsdf->alpha_x*bsdf->alpha_y < 1e-7f) {
+ *omega_in = 2*dot(Z, I)*Z - I;
+ *pdf = 1e6f;
+ *eval = make_float3(1e6f, 1e6f, 1e6f);
+ return LABEL_REFLECT|LABEL_SINGULAR;
+ }
+
+ bool is_aniso = (bsdf->alpha_x != bsdf->alpha_y);
+ if(is_aniso)
+ make_orthonormals_tangent(Z, bsdf->T, &X, &Y);
+ else
+ make_orthonormals(Z, &X, &Y);
+
+ float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z));
+ float3 localO;
+
+ *eval = mf_sample_glossy(localI, &localO, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, NULL, NULL);
+ if(is_aniso)
+ *pdf = mf_ggx_aniso_pdf(localI, localO, make_float2(bsdf->alpha_x, bsdf->alpha_y));
+ else
+ *pdf = mf_ggx_pdf(localI, localO, bsdf->alpha_x);
+ *eval *= *pdf;
+
+ *omega_in = X*localO.x + Y*localO.y + Z*localO.z;
+#ifdef __RAY_DIFFERENTIALS__
+ *domega_in_dx = (2 * dot(Z, dIdx)) * Z - dIdx;
+ *domega_in_dy = (2 * dot(Z, dIdy)) * Z - dIdy;
+#endif
+ return LABEL_REFLECT|LABEL_GLOSSY;
+}
+
+/* Multiscattering GGX Glass closure */
+
+ccl_device int bsdf_microfacet_multi_ggx_glass_setup(MicrofacetBsdf *bsdf)
+{
+ bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f);
+ bsdf->alpha_y = bsdf->alpha_x;
+ bsdf->ior = max(0.0f, bsdf->ior);
+ bsdf->extra->color.x = saturate(bsdf->extra->color.x);
+ bsdf->extra->color.y = saturate(bsdf->extra->color.y);
+ bsdf->extra->color.z = saturate(bsdf->extra->color.z);
+
+ bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID;
+
+ return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_NEEDS_LCG;
+}
+
+ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) {
+ const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc;
+
+ if(bsdf->alpha_x*bsdf->alpha_y < 1e-7f) {
+ return make_float3(0.0f, 0.0f, 0.0f);
+ }
+
+ float3 X, Y, Z;
+ Z = bsdf->N;
+ make_orthonormals(Z, &X, &Y);
+
+ float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z));
+ float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z));
+
+ *pdf = mf_glass_pdf(localI, localO, bsdf->alpha_x, bsdf->ior);
+ return mf_eval_glass(localI, localO, false, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, bsdf->ior);
+}
+
+ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) {
+ const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc;
+
+ if(bsdf->alpha_x*bsdf->alpha_y < 1e-7f) {
+ return make_float3(0.0f, 0.0f, 0.0f);
+ }
+
+ float3 X, Y, Z;
+ Z = bsdf->N;
+ make_orthonormals(Z, &X, &Y);
+
+ float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z));
+ float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z));
+
+ *pdf = mf_glass_pdf(localI, localO, bsdf->alpha_x, bsdf->ior);
+ return mf_eval_glass(localI, localO, true, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, bsdf->ior);
+}
+
+ccl_device int bsdf_microfacet_multi_ggx_glass_sample(KernelGlobals *kg, const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf, ccl_addr_space uint *lcg_state)
+{
+ const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc;
+
+ float3 X, Y, Z;
+ Z = bsdf->N;
+
+ if(bsdf->alpha_x*bsdf->alpha_y < 1e-7f) {
+ float3 R, T;
+#ifdef __RAY_DIFFERENTIALS__
+ float3 dRdx, dRdy, dTdx, dTdy;
+#endif
+ bool inside;
+ float fresnel = fresnel_dielectric(bsdf->ior, Z, I, &R, &T,
+#ifdef __RAY_DIFFERENTIALS__
+ dIdx, dIdy, &dRdx, &dRdy, &dTdx, &dTdy,
+#endif
+ &inside);
+
+ *pdf = 1e6f;
+ *eval = make_float3(1e6f, 1e6f, 1e6f);
+ if(randu < fresnel) {
+ *omega_in = R;
+#ifdef __RAY_DIFFERENTIALS__
+ *domega_in_dx = dRdx;
+ *domega_in_dy = dRdy;
+#endif
+ return LABEL_REFLECT|LABEL_SINGULAR;
+ }
+ else {
+ *omega_in = T;
+#ifdef __RAY_DIFFERENTIALS__
+ *domega_in_dx = dTdx;
+ *domega_in_dy = dTdy;
+#endif
+ return LABEL_TRANSMIT|LABEL_SINGULAR;
+ }
+ }
+
+ make_orthonormals(Z, &X, &Y);
+
+ float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z));
+ float3 localO;
+
+ *eval = mf_sample_glass(localI, &localO, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, bsdf->ior);
+ *pdf = mf_glass_pdf(localI, localO, bsdf->alpha_x, bsdf->ior);
+ *eval *= *pdf;
+
+ *omega_in = X*localO.x + Y*localO.y + Z*localO.z;
+ if(localO.z*localI.z > 0.0f) {
+#ifdef __RAY_DIFFERENTIALS__
+ *domega_in_dx = (2 * dot(Z, dIdx)) * Z - dIdx;
+ *domega_in_dy = (2 * dot(Z, dIdy)) * Z - dIdy;
+#endif
+ return LABEL_REFLECT|LABEL_GLOSSY;
+ }
+ else {
+#ifdef __RAY_DIFFERENTIALS__
+ float cosI = dot(Z, I);
+ float dnp = max(sqrtf(1.0f - (bsdf->ior * bsdf->ior * (1.0f - cosI*cosI))), 1e-7f);
+ *domega_in_dx = -(bsdf->ior * dIdx) + ((bsdf->ior - bsdf->ior * bsdf->ior * cosI / dnp) * dot(dIdx, Z)) * Z;
+ *domega_in_dy = -(bsdf->ior * dIdy) + ((bsdf->ior - bsdf->ior * bsdf->ior * cosI / dnp) * dot(dIdy, Z)) * Z;
+#endif
+
+ return LABEL_TRANSMIT|LABEL_GLOSSY;
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h
new file mode 100644
index 00000000000..8054fa8e849
--- /dev/null
+++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Evaluate the BSDF from wi to wo.
+ * Evaluation is split into the analytical single-scattering BSDF and the multi-scattering BSDF,
+ * which is evaluated stochastically through a random walk. At each bounce (except for the first one),
+ * the amount of reflection from here towards wo is evaluated before bouncing again.
+ *
+ * Because of the random walk, the evaluation is not deterministic, but its expected value is equal to
+ * the correct BSDF, which is enough for Monte-Carlo rendering. The PDF also can't be determined
+ * analytically, so the single-scattering PDF plus a diffuse term to account for the multi-scattered
+ * energy is used. In combination with MIS, that is enough to produce an unbiased result, although
+ * the balance heuristic isn't necessarily optimal anymore.
+ */
+ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_eval)(
+ float3 wi,
+ float3 wo,
+ const bool wo_outside,
+ const float3 color,
+ const float alpha_x,
+ const float alpha_y,
+ ccl_addr_space uint *lcg_state
+#ifdef MF_MULTI_GLASS
+ , const float eta
+#elif defined(MF_MULTI_GLOSSY)
+ , float3 *n, float3 *k
+#endif
+)
+{
+ /* Evaluating for a shallower incoming direction produces less noise, and the properties of the BSDF guarantee reciprocity. */
+ bool swapped = false;
+#ifdef MF_MULTI_GLASS
+ if(wi.z*wo.z < 0.0f) {
+ /* Glass transmission is a special case and requires the directions to change hemisphere. */
+ if(-wo.z < wi.z) {
+ swapped = true;
+ float3 tmp = -wo;
+ wo = -wi;
+ wi = tmp;
+ }
+ }
+ else
+#endif
+ if(wo.z < wi.z) {
+ swapped = true;
+ float3 tmp = wo;
+ wo = wi;
+ wi = tmp;
+ }
+
+ if(wi.z < 1e-5f || (wo.z < 1e-5f && wo_outside) || (wo.z > -1e-5f && !wo_outside))
+ return make_float3(0.0f, 0.0f, 0.0f);
+
+ const float2 alpha = make_float2(alpha_x, alpha_y);
+
+ float lambda_r = mf_lambda(-wi, alpha);
+ float shadowing_lambda = mf_lambda(wo_outside? wo: -wo, alpha);
+
+ /* Analytically compute single scattering for lower noise. */
+ float3 eval;
+#ifdef MF_MULTI_GLASS
+ eval = mf_eval_phase_glass(-wi, lambda_r, wo, wo_outside, alpha, eta);
+ if(wo_outside)
+ eval *= -lambda_r / (shadowing_lambda - lambda_r);
+ else
+ eval *= -lambda_r * beta(-lambda_r, shadowing_lambda+1.0f);
+#elif defined(MF_MULTI_DIFFUSE)
+ /* Diffuse has no special closed form for the single scattering bounce */
+ eval = make_float3(0.0f, 0.0f, 0.0f);
+#else /* MF_MULTI_GLOSSY */
+ const float3 wh = normalize(wi+wo);
+ const float G2 = 1.0f / (1.0f - (lambda_r + 1.0f) + shadowing_lambda);
+ float val = G2 * 0.25f / wi.z;
+ if(alpha.x == alpha.y)
+ val *= D_ggx(wh, alpha.x);
+ else
+ val *= D_ggx_aniso(wh, alpha);
+ if(n && k) {
+ eval = fresnel_conductor(dot(wh, wi), *n, *k) * val;
+ }
+ else {
+ eval = make_float3(val, val, val);
+ }
+#endif
+
+ float3 wr = -wi;
+ float hr = 1.0f;
+ float C1_r = 1.0f;
+ float G1_r = 0.0f;
+ bool outside = true;
+ float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
+
+ for(int order = 0; order < 10; order++) {
+ /* Sample microfacet height and normal */
+ if(!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, lcg_step_float_addrspace(lcg_state)))
+ break;
+ float3 wm = mf_sample_vndf(-wr, alpha, make_float2(lcg_step_float_addrspace(lcg_state),
+ lcg_step_float_addrspace(lcg_state)));
+
+#ifdef MF_MULTI_DIFFUSE
+ if(order == 0) {
+ /* Compute single-scattering for diffuse. */
+ const float G2_G1 = -lambda_r / (shadowing_lambda - lambda_r);
+ eval += throughput * G2_G1 * mf_eval_phase_diffuse(wo, wm);
+ }
+#endif
+ if(order > 0) {
+ /* Evaluate amount of scattering towards wo on this microfacet. */
+ float3 phase;
+#ifdef MF_MULTI_GLASS
+ if(outside)
+ phase = mf_eval_phase_glass(wr, lambda_r, wo, wo_outside, alpha, eta);
+ else
+ phase = mf_eval_phase_glass(wr, lambda_r, -wo, !wo_outside, alpha, 1.0f/eta);
+#elif defined(MF_MULTI_DIFFUSE)
+ phase = mf_eval_phase_diffuse(wo, wm);
+#else /* MF_MULTI_GLOSSY */
+ phase = mf_eval_phase_glossy(wr, lambda_r, wo, alpha, n, k) * throughput;
+#endif
+ eval += throughput * phase * mf_G1(wo_outside? wo: -wo, mf_C1((outside == wo_outside)? hr: -hr), shadowing_lambda);
+ }
+ if(order+1 < 10) {
+ /* Bounce from the microfacet. */
+#ifdef MF_MULTI_GLASS
+ bool next_outside;
+ wr = mf_sample_phase_glass(-wr, outside? eta: 1.0f/eta, wm, lcg_step_float_addrspace(lcg_state), &next_outside);
+ if(!next_outside) {
+ outside = !outside;
+ wr = -wr;
+ hr = -hr;
+ }
+#elif defined(MF_MULTI_DIFFUSE)
+ wr = mf_sample_phase_diffuse(wm,
+ lcg_step_float_addrspace(lcg_state),
+ lcg_step_float_addrspace(lcg_state));
+#else /* MF_MULTI_GLOSSY */
+ wr = mf_sample_phase_glossy(-wr, n, k, &throughput, wm);
+#endif
+
+ lambda_r = mf_lambda(wr, alpha);
+
+ throughput *= color;
+
+ C1_r = mf_C1(hr);
+ G1_r = mf_G1(wr, C1_r, lambda_r);
+ }
+ }
+
+ if(swapped)
+ eval *= fabsf(wi.z / wo.z);
+ return eval;
+}
+
+/* Perform a random walk on the microsurface starting from wi, returning the direction in which the walk
+ * escaped the surface in wo. The function returns the throughput between wi and wo.
+ * Without reflection losses due to coloring or fresnel absorption in conductors, the sampling is optimal.
+ */
+ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_sample)(float3 wi, float3 *wo, const float3 color, const float alpha_x, const float alpha_y, ccl_addr_space uint *lcg_state
+#ifdef MF_MULTI_GLASS
+ , const float eta
+#elif defined(MF_MULTI_GLOSSY)
+ , float3 *n, float3 *k
+#endif
+)
+{
+ const float2 alpha = make_float2(alpha_x, alpha_y);
+
+ float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
+ float3 wr = -wi;
+ float lambda_r = mf_lambda(wr, alpha);
+ float hr = 1.0f;
+ float C1_r = 1.0f;
+ float G1_r = 0.0f;
+ bool outside = true;
+
+ int order;
+ for(order = 0; order < 10; order++) {
+ /* Sample microfacet height. */
+ if(!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, lcg_step_float_addrspace(lcg_state))) {
+ /* The random walk has left the surface. */
+ *wo = outside? wr: -wr;
+ return throughput;
+ }
+ /* Sample microfacet normal. */
+ float3 wm = mf_sample_vndf(-wr, alpha, make_float2(lcg_step_float_addrspace(lcg_state),
+ lcg_step_float_addrspace(lcg_state)));
+
+ /* First-bounce color is already accounted for in mix weight. */
+ if(order > 0)
+ throughput *= color;
+
+ /* Bounce from the microfacet. */
+#ifdef MF_MULTI_GLASS
+ bool next_outside;
+ wr = mf_sample_phase_glass(-wr, outside? eta: 1.0f/eta, wm, lcg_step_float_addrspace(lcg_state), &next_outside);
+ if(!next_outside) {
+ hr = -hr;
+ wr = -wr;
+ outside = !outside;
+ }
+#elif defined(MF_MULTI_DIFFUSE)
+ wr = mf_sample_phase_diffuse(wm,
+ lcg_step_float_addrspace(lcg_state),
+ lcg_step_float_addrspace(lcg_state));
+#else /* MF_MULTI_GLOSSY */
+ wr = mf_sample_phase_glossy(-wr, n, k, &throughput, wm);
+#endif
+
+ /* Update random walk parameters. */
+ lambda_r = mf_lambda(wr, alpha);
+ G1_r = mf_G1(wr, C1_r, lambda_r);
+ }
+ *wo = make_float3(0.0f, 0.0f, 1.0f);
+ return make_float3(0.0f, 0.0f, 0.0f);
+}
+
+#undef MF_MULTI_GLASS
+#undef MF_MULTI_DIFFUSE
+#undef MF_MULTI_GLOSSY
+#undef MF_PHASE_FUNCTION
diff --git a/intern/cycles/kernel/closure/bsdf_oren_nayar.h b/intern/cycles/kernel/closure/bsdf_oren_nayar.h
index 61b7cb11b02..cb342a026ef 100644
--- a/intern/cycles/kernel/closure/bsdf_oren_nayar.h
+++ b/intern/cycles/kernel/closure/bsdf_oren_nayar.h
@@ -19,39 +19,59 @@
CCL_NAMESPACE_BEGIN
+typedef ccl_addr_space struct OrenNayarBsdf {
+ SHADER_CLOSURE_BASE;
+
+ float3 N;
+ float roughness;
+ float a;
+ float b;
+} OrenNayarBsdf;
+
ccl_device float3 bsdf_oren_nayar_get_intensity(const ShaderClosure *sc, float3 n, float3 v, float3 l)
{
+ const OrenNayarBsdf *bsdf = (const OrenNayarBsdf*)sc;
float nl = max(dot(n, l), 0.0f);
float nv = max(dot(n, v), 0.0f);
float t = dot(l, v) - nl * nv;
if(t > 0.0f)
t /= max(nl, nv) + FLT_MIN;
- float is = nl * (sc->data0 + sc->data1 * t);
+ float is = nl * (bsdf->a + bsdf->b * t);
return make_float3(is, is, is);
}
-ccl_device int bsdf_oren_nayar_setup(ShaderClosure *sc)
+ccl_device int bsdf_oren_nayar_setup(OrenNayarBsdf *bsdf)
{
- float sigma = sc->data0;
+ float sigma = bsdf->roughness;
- sc->type = CLOSURE_BSDF_OREN_NAYAR_ID;
+ bsdf->type = CLOSURE_BSDF_OREN_NAYAR_ID;
sigma = saturate(sigma);
float div = 1.0f / (M_PI_F + ((3.0f * M_PI_F - 4.0f) / 6.0f) * sigma);
- sc->data0 = 1.0f * div;
- sc->data1 = sigma * div;
+ bsdf->a = 1.0f * div;
+ bsdf->b = sigma * div;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
+ccl_device bool bsdf_oren_nayar_merge(const ShaderClosure *a, const ShaderClosure *b)
+{
+ const OrenNayarBsdf *bsdf_a = (const OrenNayarBsdf*)a;
+ const OrenNayarBsdf *bsdf_b = (const OrenNayarBsdf*)b;
+
+ return (isequal_float3(bsdf_a->N, bsdf_b->N)) &&
+ (bsdf_a->roughness == bsdf_b->roughness);
+}
+
ccl_device float3 bsdf_oren_nayar_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
- if(dot(sc->N, omega_in) > 0.0f) {
+ const OrenNayarBsdf *bsdf = (const OrenNayarBsdf*)sc;
+ if(dot(bsdf->N, omega_in) > 0.0f) {
*pdf = 0.5f * M_1_PI_F;
- return bsdf_oren_nayar_get_intensity(sc, sc->N, I, omega_in);
+ return bsdf_oren_nayar_get_intensity(sc, bsdf->N, I, omega_in);
}
else {
*pdf = 0.0f;
@@ -66,15 +86,16 @@ ccl_device float3 bsdf_oren_nayar_eval_transmit(const ShaderClosure *sc, const f
ccl_device int bsdf_oren_nayar_sample(const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
{
- sample_uniform_hemisphere(sc->N, randu, randv, omega_in, pdf);
+ const OrenNayarBsdf *bsdf = (const OrenNayarBsdf*)sc;
+ sample_uniform_hemisphere(bsdf->N, randu, randv, omega_in, pdf);
if(dot(Ng, *omega_in) > 0.0f) {
- *eval = bsdf_oren_nayar_get_intensity(sc, sc->N, I, *omega_in);
+ *eval = bsdf_oren_nayar_get_intensity(sc, bsdf->N, I, *omega_in);
#ifdef __RAY_DIFFERENTIALS__
// TODO: find a better approximation for the bounce
- *domega_in_dx = (2.0f * dot(sc->N, dIdx)) * sc->N - dIdx;
- *domega_in_dy = (2.0f * dot(sc->N, dIdy)) * sc->N - dIdy;
+ *domega_in_dx = (2.0f * dot(bsdf->N, dIdx)) * bsdf->N - dIdx;
+ *domega_in_dy = (2.0f * dot(bsdf->N, dIdy)) * bsdf->N - dIdy;
#endif
}
else {
diff --git a/intern/cycles/kernel/closure/bsdf_phong_ramp.h b/intern/cycles/kernel/closure/bsdf_phong_ramp.h
index 1ab15eee954..e152a8780db 100644
--- a/intern/cycles/kernel/closure/bsdf_phong_ramp.h
+++ b/intern/cycles/kernel/closure/bsdf_phong_ramp.h
@@ -35,7 +35,17 @@
CCL_NAMESPACE_BEGIN
-ccl_device float3 bsdf_phong_ramp_get_color(const ShaderClosure *sc, const float3 colors[8], float pos)
+#ifdef __OSL__
+
+typedef ccl_addr_space struct PhongRampBsdf {
+ SHADER_CLOSURE_BASE;
+
+ float3 N;
+ float exponent;
+ float3 *colors;
+} PhongRampBsdf;
+
+ccl_device float3 bsdf_phong_ramp_get_color(const float3 colors[8], float pos)
{
int MAXCOLORS = 8;
@@ -49,57 +59,54 @@ ccl_device float3 bsdf_phong_ramp_get_color(const ShaderClosure *sc, const float
return colors[ipos] * (1.0f - offset) + colors[ipos+1] * offset;
}
-ccl_device int bsdf_phong_ramp_setup(ShaderClosure *sc)
+ccl_device int bsdf_phong_ramp_setup(PhongRampBsdf *bsdf)
{
- sc->type = CLOSURE_BSDF_PHONG_RAMP_ID;
- sc->data0 = max(sc->data0, 0.0f);
- sc->data1 = 0.0f;
+ bsdf->type = CLOSURE_BSDF_PHONG_RAMP_ID;
+ bsdf->exponent = max(bsdf->exponent, 0.0f);
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
-ccl_device void bsdf_phong_ramp_blur(ShaderClosure *sc, float roughness)
-{
-}
-
-ccl_device float3 bsdf_phong_ramp_eval_reflect(const ShaderClosure *sc, const float3 colors[8], const float3 I, const float3 omega_in, float *pdf)
+ccl_device float3 bsdf_phong_ramp_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
- float m_exponent = sc->data0;
- float cosNI = dot(sc->N, omega_in);
- float cosNO = dot(sc->N, I);
+ const PhongRampBsdf *bsdf = (const PhongRampBsdf*)sc;
+ float m_exponent = bsdf->exponent;
+ float cosNI = dot(bsdf->N, omega_in);
+ float cosNO = dot(bsdf->N, I);
if(cosNI > 0 && cosNO > 0) {
// reflect the view vector
- float3 R = (2 * cosNO) * sc->N - I;
+ float3 R = (2 * cosNO) * bsdf->N - I;
float cosRI = dot(R, omega_in);
if(cosRI > 0) {
float cosp = powf(cosRI, m_exponent);
float common = 0.5f * M_1_PI_F * cosp;
float out = cosNI * (m_exponent + 2) * common;
*pdf = (m_exponent + 1) * common;
- return bsdf_phong_ramp_get_color(sc, colors, cosp) * out;
+ return bsdf_phong_ramp_get_color(bsdf->colors, cosp) * out;
}
}
return make_float3(0.0f, 0.0f, 0.0f);
}
-ccl_device float3 bsdf_phong_ramp_eval_transmit(const ShaderClosure *sc, const float3 colors[8], const float3 I, const float3 omega_in, float *pdf)
+ccl_device float3 bsdf_phong_ramp_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
-ccl_device int bsdf_phong_ramp_sample(const ShaderClosure *sc, const float3 colors[8], float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
+ccl_device int bsdf_phong_ramp_sample(const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
{
- float cosNO = dot(sc->N, I);
- float m_exponent = sc->data0;
+ const PhongRampBsdf *bsdf = (const PhongRampBsdf*)sc;
+ float cosNO = dot(bsdf->N, I);
+ float m_exponent = bsdf->exponent;
if(cosNO > 0) {
// reflect the view vector
- float3 R = (2 * cosNO) * sc->N - I;
+ float3 R = (2 * cosNO) * bsdf->N - I;
#ifdef __RAY_DIFFERENTIALS__
- *domega_in_dx = (2 * dot(sc->N, dIdx)) * sc->N - dIdx;
- *domega_in_dy = (2 * dot(sc->N, dIdy)) * sc->N - dIdy;
+ *domega_in_dx = (2 * dot(bsdf->N, dIdx)) * bsdf->N - dIdx;
+ *domega_in_dy = (2 * dot(bsdf->N, dIdy)) * bsdf->N - dIdy;
#endif
float3 T, B;
@@ -114,7 +121,7 @@ ccl_device int bsdf_phong_ramp_sample(const ShaderClosure *sc, const float3 colo
if(dot(Ng, *omega_in) > 0.0f)
{
// common terms for pdf and eval
- float cosNI = dot(sc->N, *omega_in);
+ float cosNI = dot(bsdf->N, *omega_in);
// make sure the direction we chose is still in the right hemisphere
if(cosNI > 0)
{
@@ -122,13 +129,14 @@ ccl_device int bsdf_phong_ramp_sample(const ShaderClosure *sc, const float3 colo
float common = 0.5f * M_1_PI_F * cosp;
*pdf = (m_exponent + 1) * common;
float out = cosNI * (m_exponent + 2) * common;
- *eval = bsdf_phong_ramp_get_color(sc, colors, cosp) * out;
+ *eval = bsdf_phong_ramp_get_color(bsdf->colors, cosp) * out;
}
}
}
return LABEL_REFLECT|LABEL_GLOSSY;
}
+#endif /* __OSL__ */
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/closure/bsdf_reflection.h b/intern/cycles/kernel/closure/bsdf_reflection.h
index 303f4c9ce34..1d21614ecee 100644
--- a/intern/cycles/kernel/closure/bsdf_reflection.h
+++ b/intern/cycles/kernel/closure/bsdf_reflection.h
@@ -37,9 +37,9 @@ CCL_NAMESPACE_BEGIN
/* REFLECTION */
-ccl_device int bsdf_reflection_setup(ShaderClosure *sc)
+ccl_device int bsdf_reflection_setup(MicrofacetBsdf *bsdf)
{
- sc->type = CLOSURE_BSDF_REFLECTION_ID;
+ bsdf->type = CLOSURE_BSDF_REFLECTION_ID;
return SD_BSDF;
}
@@ -55,7 +55,8 @@ ccl_device float3 bsdf_reflection_eval_transmit(const ShaderClosure *sc, const f
ccl_device int bsdf_reflection_sample(const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
{
- float3 N = sc->N;
+ const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc;
+ float3 N = bsdf->N;
// only one direction is possible
float cosNO = dot(N, I);
diff --git a/intern/cycles/kernel/closure/bsdf_refraction.h b/intern/cycles/kernel/closure/bsdf_refraction.h
index c78a4b67134..050a4e76fa9 100644
--- a/intern/cycles/kernel/closure/bsdf_refraction.h
+++ b/intern/cycles/kernel/closure/bsdf_refraction.h
@@ -37,9 +37,9 @@ CCL_NAMESPACE_BEGIN
/* REFRACTION */
-ccl_device int bsdf_refraction_setup(ShaderClosure *sc)
+ccl_device int bsdf_refraction_setup(MicrofacetBsdf *bsdf)
{
- sc->type = CLOSURE_BSDF_REFRACTION_ID;
+ bsdf->type = CLOSURE_BSDF_REFRACTION_ID;
return SD_BSDF;
}
@@ -55,8 +55,9 @@ ccl_device float3 bsdf_refraction_eval_transmit(const ShaderClosure *sc, const f
ccl_device int bsdf_refraction_sample(const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
{
- float m_eta = sc->data0;
- float3 N = sc->N;
+ const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc;
+ float m_eta = bsdf->ior;
+ float3 N = bsdf->N;
float3 R, T;
#ifdef __RAY_DIFFERENTIALS__
diff --git a/intern/cycles/kernel/closure/bsdf_toon.h b/intern/cycles/kernel/closure/bsdf_toon.h
index e5b6ab93a64..28e775bcbc8 100644
--- a/intern/cycles/kernel/closure/bsdf_toon.h
+++ b/intern/cycles/kernel/closure/bsdf_toon.h
@@ -35,17 +35,35 @@
CCL_NAMESPACE_BEGIN
+typedef ccl_addr_space struct ToonBsdf {
+ SHADER_CLOSURE_BASE;
+
+ float3 N;
+ float size;
+ float smooth;
+} ToonBsdf;
+
/* DIFFUSE TOON */
-ccl_device int bsdf_diffuse_toon_setup(ShaderClosure *sc)
+ccl_device int bsdf_diffuse_toon_setup(ToonBsdf *bsdf)
{
- sc->type = CLOSURE_BSDF_DIFFUSE_TOON_ID;
- sc->data0 = saturate(sc->data0);
- sc->data1 = saturate(sc->data1);
+ bsdf->type = CLOSURE_BSDF_DIFFUSE_TOON_ID;
+ bsdf->size = saturate(bsdf->size);
+ bsdf->smooth = saturate(bsdf->smooth);
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
+ccl_device bool bsdf_toon_merge(const ShaderClosure *a, const ShaderClosure *b)
+{
+ const ToonBsdf *bsdf_a = (const ToonBsdf*)a;
+ const ToonBsdf *bsdf_b = (const ToonBsdf*)b;
+
+ return (isequal_float3(bsdf_a->N, bsdf_b->N)) &&
+ (bsdf_a->size == bsdf_b->size) &&
+ (bsdf_a->smooth == bsdf_b->smooth);
+}
+
ccl_device float3 bsdf_toon_get_intensity(float max_angle, float smooth, float angle)
{
float is;
@@ -67,9 +85,10 @@ ccl_device float bsdf_toon_get_sample_angle(float max_angle, float smooth)
ccl_device float3 bsdf_diffuse_toon_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
- float max_angle = sc->data0*M_PI_2_F;
- float smooth = sc->data1*M_PI_2_F;
- float angle = safe_acosf(fmaxf(dot(sc->N, omega_in), 0.0f));
+ const ToonBsdf *bsdf = (const ToonBsdf*)sc;
+ float max_angle = bsdf->size*M_PI_2_F;
+ float smooth = bsdf->smooth*M_PI_2_F;
+ float angle = safe_acosf(fmaxf(dot(bsdf->N, omega_in), 0.0f));
float3 eval = bsdf_toon_get_intensity(max_angle, smooth, angle);
@@ -90,21 +109,22 @@ ccl_device float3 bsdf_diffuse_toon_eval_transmit(const ShaderClosure *sc, const
ccl_device int bsdf_diffuse_toon_sample(const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
{
- float max_angle = sc->data0*M_PI_2_F;
- float smooth = sc->data1*M_PI_2_F;
+ const ToonBsdf *bsdf = (const ToonBsdf*)sc;
+ float max_angle = bsdf->size*M_PI_2_F;
+ float smooth = bsdf->smooth*M_PI_2_F;
float sample_angle = bsdf_toon_get_sample_angle(max_angle, smooth);
float angle = sample_angle*randu;
if(sample_angle > 0.0f) {
- sample_uniform_cone(sc->N, sample_angle, randu, randv, omega_in, pdf);
+ sample_uniform_cone(bsdf->N, sample_angle, randu, randv, omega_in, pdf);
if(dot(Ng, *omega_in) > 0.0f) {
*eval = *pdf * bsdf_toon_get_intensity(max_angle, smooth, angle);
#ifdef __RAY_DIFFERENTIALS__
// TODO: find a better approximation for the bounce
- *domega_in_dx = (2.0f * dot(sc->N, dIdx)) * sc->N - dIdx;
- *domega_in_dy = (2.0f * dot(sc->N, dIdy)) * sc->N - dIdy;
+ *domega_in_dx = (2.0f * dot(bsdf->N, dIdx)) * bsdf->N - dIdx;
+ *domega_in_dy = (2.0f * dot(bsdf->N, dIdy)) * bsdf->N - dIdy;
#endif
}
else
@@ -117,25 +137,26 @@ ccl_device int bsdf_diffuse_toon_sample(const ShaderClosure *sc, float3 Ng, floa
/* GLOSSY TOON */
-ccl_device int bsdf_glossy_toon_setup(ShaderClosure *sc)
+ccl_device int bsdf_glossy_toon_setup(ToonBsdf *bsdf)
{
- sc->type = CLOSURE_BSDF_GLOSSY_TOON_ID;
- sc->data0 = saturate(sc->data0);
- sc->data1 = saturate(sc->data1);
+ bsdf->type = CLOSURE_BSDF_GLOSSY_TOON_ID;
+ bsdf->size = saturate(bsdf->size);
+ bsdf->smooth = saturate(bsdf->smooth);
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
ccl_device float3 bsdf_glossy_toon_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
- float max_angle = sc->data0*M_PI_2_F;
- float smooth = sc->data1*M_PI_2_F;
- float cosNI = dot(sc->N, omega_in);
- float cosNO = dot(sc->N, I);
+ const ToonBsdf *bsdf = (const ToonBsdf*)sc;
+ float max_angle = bsdf->size*M_PI_2_F;
+ float smooth = bsdf->smooth*M_PI_2_F;
+ float cosNI = dot(bsdf->N, omega_in);
+ float cosNO = dot(bsdf->N, I);
if(cosNI > 0 && cosNO > 0) {
/* reflect the view vector */
- float3 R = (2 * cosNO) * sc->N - I;
+ float3 R = (2 * cosNO) * bsdf->N - I;
float cosRI = dot(R, omega_in);
float angle = safe_acosf(fmaxf(cosRI, 0.0f));
@@ -157,13 +178,14 @@ ccl_device float3 bsdf_glossy_toon_eval_transmit(const ShaderClosure *sc, const
ccl_device int bsdf_glossy_toon_sample(const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
{
- float max_angle = sc->data0*M_PI_2_F;
- float smooth = sc->data1*M_PI_2_F;
- float cosNO = dot(sc->N, I);
+ const ToonBsdf *bsdf = (const ToonBsdf*)sc;
+ float max_angle = bsdf->size*M_PI_2_F;
+ float smooth = bsdf->smooth*M_PI_2_F;
+ float cosNO = dot(bsdf->N, I);
if(cosNO > 0) {
/* reflect the view vector */
- float3 R = (2 * cosNO) * sc->N - I;
+ float3 R = (2 * cosNO) * bsdf->N - I;
float sample_angle = bsdf_toon_get_sample_angle(max_angle, smooth);
float angle = sample_angle*randu;
@@ -171,15 +193,15 @@ ccl_device int bsdf_glossy_toon_sample(const ShaderClosure *sc, float3 Ng, float
sample_uniform_cone(R, sample_angle, randu, randv, omega_in, pdf);
if(dot(Ng, *omega_in) > 0.0f) {
- float cosNI = dot(sc->N, *omega_in);
+ float cosNI = dot(bsdf->N, *omega_in);
/* make sure the direction we chose is still in the right hemisphere */
if(cosNI > 0) {
*eval = *pdf * bsdf_toon_get_intensity(max_angle, smooth, angle);
#ifdef __RAY_DIFFERENTIALS__
- *domega_in_dx = (2 * dot(sc->N, dIdx)) * sc->N - dIdx;
- *domega_in_dy = (2 * dot(sc->N, dIdy)) * sc->N - dIdy;
+ *domega_in_dx = (2 * dot(bsdf->N, dIdx)) * bsdf->N - dIdx;
+ *domega_in_dy = (2 * dot(bsdf->N, dIdy)) * bsdf->N - dIdy;
#endif
}
else
diff --git a/intern/cycles/kernel/closure/bsdf_util.h b/intern/cycles/kernel/closure/bsdf_util.h
index 05816bac2c1..b0c5280b6cb 100644
--- a/intern/cycles/kernel/closure/bsdf_util.h
+++ b/intern/cycles/kernel/closure/bsdf_util.h
@@ -80,7 +80,7 @@ ccl_device float fresnel_dielectric(
return 1; // total internal reflection
}
else {
- float dnp = sqrtf(arg);
+ float dnp = max(sqrtf(arg), 1e-7f);
float nK = (neta * cos)- dnp;
*T = -(neta * I)+(nK * Nn);
#ifdef __RAY_DIFFERENTIALS__
@@ -111,10 +111,9 @@ ccl_device float fresnel_dielectric_cos(float cosi, float eta)
return 1.0f; // TIR(no refracted component)
}
-#if 0
ccl_device float3 fresnel_conductor(float cosi, const float3 eta, const float3 k)
{
- float3 cosi2 = make_float3(cosi*cosi);
+ float3 cosi2 = make_float3(cosi*cosi, cosi*cosi, cosi*cosi);
float3 one = make_float3(1.0f, 1.0f, 1.0f);
float3 tmp_f = eta * eta + k * k;
float3 tmp = tmp_f * cosi2;
@@ -124,7 +123,6 @@ ccl_device float3 fresnel_conductor(float cosi, const float3 eta, const float3 k
(tmp_f + (2.0f * eta * cosi) + cosi2);
return(Rparl2 + Rperp2) * 0.5f;
}
-#endif
ccl_device float smooth_step(float edge0, float edge1, float x)
{
diff --git a/intern/cycles/kernel/closure/bssrdf.h b/intern/cycles/kernel/closure/bssrdf.h
index c24720cefbe..af0bbd861a9 100644
--- a/intern/cycles/kernel/closure/bssrdf.h
+++ b/intern/cycles/kernel/closure/bssrdf.h
@@ -19,6 +19,17 @@
CCL_NAMESPACE_BEGIN
+typedef ccl_addr_space struct Bssrdf {
+ SHADER_CLOSURE_BASE;
+
+ float radius;
+ float sharpness;
+ float d;
+ float texture_blur;
+ float albedo;
+ float3 N;
+} Bssrdf;
+
/* Planar Truncated Gaussian
*
* Note how this is different from the typical gaussian, this one integrates
@@ -28,11 +39,12 @@ CCL_NAMESPACE_BEGIN
/* paper suggests 1/12.46 which is much too small, suspect it's *12.46 */
#define GAUSS_TRUNCATE 12.46f
-ccl_device float bssrdf_gaussian_eval(ShaderClosure *sc, float r)
+ccl_device float bssrdf_gaussian_eval(const ShaderClosure *sc, float r)
{
/* integrate (2*pi*r * exp(-r*r/(2*v)))/(2*pi*v)) from 0 to Rm
* = 1 - exp(-Rm*Rm/(2*v)) */
- const float v = sc->data0*sc->data0*(0.25f*0.25f);
+ const Bssrdf *bssrdf = (const Bssrdf*)sc;
+ const float v = bssrdf->radius*bssrdf->radius*(0.25f*0.25f);
const float Rm = sqrtf(v*GAUSS_TRUNCATE);
if(r >= Rm)
@@ -41,7 +53,7 @@ ccl_device float bssrdf_gaussian_eval(ShaderClosure *sc, float r)
return expf(-r*r/(2.0f*v))/(2.0f*M_PI_F*v);
}
-ccl_device float bssrdf_gaussian_pdf(ShaderClosure *sc, float r)
+ccl_device float bssrdf_gaussian_pdf(const ShaderClosure *sc, float r)
{
/* 1.0 - expf(-Rm*Rm/(2*v)) simplified */
const float area_truncated = 1.0f - expf(-0.5f*GAUSS_TRUNCATE);
@@ -49,12 +61,12 @@ ccl_device float bssrdf_gaussian_pdf(ShaderClosure *sc, float r)
return bssrdf_gaussian_eval(sc, r) * (1.0f/(area_truncated));
}
-ccl_device void bssrdf_gaussian_sample(ShaderClosure *sc, float xi, float *r, float *h)
+ccl_device void bssrdf_gaussian_sample(const ShaderClosure *sc, float xi, float *r, float *h)
{
/* xi = integrate (2*pi*r * exp(-r*r/(2*v)))/(2*pi*v)) = -exp(-r^2/(2*v))
* r = sqrt(-2*v*logf(xi)) */
-
- const float v = sc->data0*sc->data0*(0.25f*0.25f);
+ const Bssrdf *bssrdf = (const Bssrdf*)sc;
+ const float v = bssrdf->radius*bssrdf->radius*(0.25f*0.25f);
const float Rm = sqrtf(v*GAUSS_TRUNCATE);
/* 1.0 - expf(-Rm*Rm/(2*v)) simplified */
@@ -75,12 +87,13 @@ ccl_device void bssrdf_gaussian_sample(ShaderClosure *sc, float xi, float *r, fl
* far as I can tell has no closed form solution. So we get an iterative solution
* instead with newton-raphson. */
-ccl_device float bssrdf_cubic_eval(ShaderClosure *sc, float r)
+ccl_device float bssrdf_cubic_eval(const ShaderClosure *sc, float r)
{
- const float sharpness = sc->T.x;
+ const Bssrdf *bssrdf = (const Bssrdf*)sc;
+ const float sharpness = bssrdf->sharpness;
if(sharpness == 0.0f) {
- const float Rm = sc->data0;
+ const float Rm = bssrdf->radius;
if(r >= Rm)
return 0.0f;
@@ -94,7 +107,7 @@ ccl_device float bssrdf_cubic_eval(ShaderClosure *sc, float r)
}
else {
- float Rm = sc->data0*(1.0f + sharpness);
+ float Rm = bssrdf->radius*(1.0f + sharpness);
if(r >= Rm)
return 0.0f;
@@ -122,13 +135,13 @@ ccl_device float bssrdf_cubic_eval(ShaderClosure *sc, float r)
}
}
-ccl_device float bssrdf_cubic_pdf(ShaderClosure *sc, float r)
+ccl_device float bssrdf_cubic_pdf(const ShaderClosure *sc, float r)
{
return bssrdf_cubic_eval(sc, r);
}
/* solve 10x^2 - 20x^3 + 15x^4 - 4x^5 - xi == 0 */
-ccl_device float bssrdf_cubic_quintic_root_find(float xi)
+ccl_device_forceinline float bssrdf_cubic_quintic_root_find(float xi)
{
/* newton-raphson iteration, usually succeeds in 2-4 iterations, except
* outside 0.02 ... 0.98 where it can go up to 10, so overall performance
@@ -155,12 +168,13 @@ ccl_device float bssrdf_cubic_quintic_root_find(float xi)
return x;
}
-ccl_device void bssrdf_cubic_sample(ShaderClosure *sc, float xi, float *r, float *h)
+ccl_device void bssrdf_cubic_sample(const ShaderClosure *sc, float xi, float *r, float *h)
{
- float Rm = sc->data0;
+ const Bssrdf *bssrdf = (const Bssrdf*)sc;
+ const float sharpness = bssrdf->sharpness;
+ float Rm = bssrdf->radius;
float r_ = bssrdf_cubic_quintic_root_find(xi);
- const float sharpness = sc->T.x;
if(sharpness != 0.0f) {
r_ = powf(r_, 1.0f + sharpness);
Rm *= (1.0f + sharpness);
@@ -198,21 +212,22 @@ ccl_device_inline float bssrdf_burley_compatible_mfp(float r)
return 0.25f * M_1_PI_F * r;
}
-ccl_device void bssrdf_burley_setup(ShaderClosure *sc)
+ccl_device void bssrdf_burley_setup(Bssrdf *bssrdf)
{
/* Mean free path length. */
- const float l = bssrdf_burley_compatible_mfp(sc->data0);
+ const float l = bssrdf_burley_compatible_mfp(bssrdf->radius);
/* Surface albedo. */
- const float A = sc->data2;
+ const float A = bssrdf->albedo;
const float s = bssrdf_burley_fitting(A);
const float d = l / s;
- sc->custom1 = d;
+ bssrdf->d = d;
}
-ccl_device float bssrdf_burley_eval(ShaderClosure *sc, float r)
+ccl_device float bssrdf_burley_eval(const ShaderClosure *sc, float r)
{
- const float d = sc->custom1;
+ const Bssrdf *bssrdf = (const Bssrdf*)sc;
+ const float d = bssrdf->d;
const float Rm = BURLEY_TRUNCATE * d;
if(r >= Rm)
@@ -231,7 +246,7 @@ ccl_device float bssrdf_burley_eval(ShaderClosure *sc, float r)
return (exp_r_d + exp_r_3_d) / (4.0f*d);
}
-ccl_device float bssrdf_burley_pdf(ShaderClosure *sc, float r)
+ccl_device float bssrdf_burley_pdf(const ShaderClosure *sc, float r)
{
return bssrdf_burley_eval(sc, r) * (1.0f/BURLEY_TRUNCATE_CDF);
}
@@ -240,7 +255,7 @@ ccl_device float bssrdf_burley_pdf(ShaderClosure *sc, float r)
* Returns scaled radius, meaning the result is to be scaled up by d.
* Since there's no closed form solution we do Newton-Raphson method to find it.
*/
-ccl_device float bssrdf_burley_root_find(float xi)
+ccl_device_forceinline float bssrdf_burley_root_find(float xi)
{
const float tolerance = 1e-6f;
const int max_iteration_count = 10;
@@ -276,12 +291,13 @@ ccl_device float bssrdf_burley_root_find(float xi)
return r;
}
-ccl_device void bssrdf_burley_sample(ShaderClosure *sc,
+ccl_device void bssrdf_burley_sample(const ShaderClosure *sc,
float xi,
float *r,
float *h)
{
- const float d = sc->custom1;
+ const Bssrdf *bssrdf = (const Bssrdf*)sc;
+ const float d = bssrdf->d;
const float Rm = BURLEY_TRUNCATE * d;
const float r_ = bssrdf_burley_root_find(xi * BURLEY_TRUNCATE_CDF) * d;
@@ -295,26 +311,29 @@ ccl_device void bssrdf_burley_sample(ShaderClosure *sc,
*
* Samples distributed over disk with no falloff, for reference. */
-ccl_device float bssrdf_none_eval(ShaderClosure *sc, float r)
+ccl_device float bssrdf_none_eval(const ShaderClosure *sc, float r)
{
- const float Rm = sc->data0;
+ const Bssrdf *bssrdf = (const Bssrdf*)sc;
+ const float Rm = bssrdf->radius;
return (r < Rm)? 1.0f: 0.0f;
}
-ccl_device float bssrdf_none_pdf(ShaderClosure *sc, float r)
+ccl_device float bssrdf_none_pdf(const ShaderClosure *sc, float r)
{
/* integrate (2*pi*r)/(pi*Rm*Rm) from 0 to Rm = 1 */
- const float Rm = sc->data0;
+ const Bssrdf *bssrdf = (const Bssrdf*)sc;
+ const float Rm = bssrdf->radius;
const float area = (M_PI_F*Rm*Rm);
return bssrdf_none_eval(sc, r) / area;
}
-ccl_device void bssrdf_none_sample(ShaderClosure *sc, float xi, float *r, float *h)
+ccl_device void bssrdf_none_sample(const ShaderClosure *sc, float xi, float *r, float *h)
{
/* xi = integrate (2*pi*r)/(pi*Rm*Rm) = r^2/Rm^2
* r = sqrt(xi)*Rm */
- const float Rm = sc->data0;
+ const Bssrdf *bssrdf = (const Bssrdf*)sc;
+ const float Rm = bssrdf->radius;
const float r_ = sqrtf(xi)*Rm;
*r = r_;
@@ -325,30 +344,42 @@ ccl_device void bssrdf_none_sample(ShaderClosure *sc, float xi, float *r, float
/* Generic */
-ccl_device int bssrdf_setup(ShaderClosure *sc, ClosureType type)
+ccl_device_inline Bssrdf *bssrdf_alloc(ShaderData *sd, float3 weight)
+{
+ Bssrdf *bssrdf = (Bssrdf*)closure_alloc(sd, sizeof(Bssrdf), CLOSURE_NONE_ID, weight);
+
+ if(!bssrdf)
+ return NULL;
+
+ float sample_weight = fabsf(average(weight));
+ bssrdf->sample_weight = sample_weight;
+ return (sample_weight >= CLOSURE_WEIGHT_CUTOFF) ? bssrdf : NULL;
+}
+
+ccl_device int bssrdf_setup(Bssrdf *bssrdf, ClosureType type)
{
- if(sc->data0 < BSSRDF_MIN_RADIUS) {
+ if(bssrdf->radius < BSSRDF_MIN_RADIUS) {
/* revert to diffuse BSDF if radius too small */
- sc->data0 = 0.0f;
- sc->data1 = 0.0f;
- int flag = bsdf_diffuse_setup(sc);
- sc->type = CLOSURE_BSDF_BSSRDF_ID;
+ DiffuseBsdf *bsdf = (DiffuseBsdf*)bssrdf;
+ bsdf->N = bssrdf->N;
+ int flag = bsdf_diffuse_setup(bsdf);
+ bsdf->type = CLOSURE_BSDF_BSSRDF_ID;
return flag;
}
else {
- sc->data1 = saturate(sc->data1); /* texture blur */
- sc->T.x = saturate(sc->T.x); /* sharpness */
- sc->type = type;
+ bssrdf->texture_blur = saturate(bssrdf->texture_blur);
+ bssrdf->sharpness = saturate(bssrdf->sharpness);
+ bssrdf->type = type;
if(type == CLOSURE_BSSRDF_BURLEY_ID) {
- bssrdf_burley_setup(sc);
+ bssrdf_burley_setup(bssrdf);
}
return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSSRDF;
}
}
-ccl_device void bssrdf_sample(ShaderClosure *sc, float xi, float *r, float *h)
+ccl_device void bssrdf_sample(const ShaderClosure *sc, float xi, float *r, float *h)
{
if(sc->type == CLOSURE_BSSRDF_CUBIC_ID)
bssrdf_cubic_sample(sc, xi, r, h);
@@ -358,7 +389,7 @@ ccl_device void bssrdf_sample(ShaderClosure *sc, float xi, float *r, float *h)
bssrdf_burley_sample(sc, xi, r, h);
}
-ccl_device float bssrdf_pdf(ShaderClosure *sc, float r)
+ccl_device_forceinline float bssrdf_pdf(const ShaderClosure *sc, float r)
{
if(sc->type == CLOSURE_BSSRDF_CUBIC_ID)
return bssrdf_cubic_pdf(sc, r);
diff --git a/intern/cycles/kernel/closure/volume.h b/intern/cycles/kernel/closure/volume.h
index 4d71ba50ec3..01e67c7c2fd 100644
--- a/intern/cycles/kernel/closure/volume.h
+++ b/intern/cycles/kernel/closure/volume.h
@@ -19,6 +19,12 @@
CCL_NAMESPACE_BEGIN
+typedef ccl_addr_space struct HenyeyGreensteinVolume {
+ SHADER_CLOSURE_BASE;
+
+ float g;
+} HenyeyGreensteinVolume;
+
/* HENYEY-GREENSTEIN CLOSURE */
/* Given cosine between rays, return probability density that a photon bounces
@@ -29,19 +35,28 @@ ccl_device float single_peaked_henyey_greenstein(float cos_theta, float g)
return ((1.0f - g * g) / safe_powf(1.0f + g * g - 2.0f * g * cos_theta, 1.5f)) * (M_1_PI_F * 0.25f);
};
-ccl_device int volume_henyey_greenstein_setup(ShaderClosure *sc)
+ccl_device int volume_henyey_greenstein_setup(HenyeyGreensteinVolume *volume)
{
- sc->type = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
+ volume->type = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
/* clamp anisotropy to avoid delta function */
- sc->data0 = signf(sc->data0) * min(fabsf(sc->data0), 1.0f - 1e-3f);
+ volume->g = signf(volume->g) * min(fabsf(volume->g), 1.0f - 1e-3f);
return SD_SCATTER;
}
+ccl_device bool volume_henyey_greenstein_merge(const ShaderClosure *a, const ShaderClosure *b)
+{
+ const HenyeyGreensteinVolume *volume_a = (const HenyeyGreensteinVolume*)a;
+ const HenyeyGreensteinVolume *volume_b = (const HenyeyGreensteinVolume*)b;
+
+ return (volume_a->g == volume_b->g);
+}
+
ccl_device float3 volume_henyey_greenstein_eval_phase(const ShaderClosure *sc, const float3 I, float3 omega_in, float *pdf)
{
- float g = sc->data0;
+ const HenyeyGreensteinVolume *volume = (const HenyeyGreensteinVolume*)sc;
+ float g = volume->g;
/* note that I points towards the viewer */
if(fabsf(g) < 1e-3f) {
@@ -58,7 +73,8 @@ ccl_device float3 volume_henyey_greenstein_eval_phase(const ShaderClosure *sc, c
ccl_device int volume_henyey_greenstein_sample(const ShaderClosure *sc, float3 I, float3 dIdx, float3 dIdy, float randu, float randv,
float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
{
- float g = sc->data0;
+ const HenyeyGreensteinVolume *volume = (const HenyeyGreensteinVolume*)sc;
+ float g = volume->g;
float cos_phi, sin_phi, cos_theta;
/* match pdf for small g */
diff --git a/intern/cycles/kernel/geom/geom.h b/intern/cycles/kernel/geom/geom.h
index c94a5384d1f..24ced934c8b 100644
--- a/intern/cycles/kernel/geom/geom.h
+++ b/intern/cycles/kernel/geom/geom.h
@@ -1,6 +1,5 @@
/*
- * Adapted from code Copyright 2009-2010 NVIDIA Corporation
- * Modifications Copyright 2011, Blender Foundation.
+ * Copyright 2011-2013 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,35 +14,17 @@
* limitations under the License.
*/
-/* bottom-most stack entry, indicating the end of traversal */
-#define ENTRYPOINT_SENTINEL 0x76543210
-
-/* 64 object BVH + 64 mesh BVH + 64 object node splitting */
-#define BVH_STACK_SIZE 192
-#define BVH_QSTACK_SIZE 384
-#define BVH_NODE_SIZE 4
-#define BVH_NODE_LEAF_SIZE 1
-#define BVH_QNODE_SIZE 7
-#define BVH_QNODE_LEAF_SIZE 1
-#define TRI_NODE_SIZE 3
-
-/* silly workaround for float extended precision that happens when compiling
- * without sse support on x86, it results in different results for float ops
- * that you would otherwise expect to compare correctly */
-#if !defined(__i386__) || defined(__SSE__)
-# define NO_EXTENDED_PRECISION
-#else
-# define NO_EXTENDED_PRECISION volatile
-#endif
-
#include "geom_attribute.h"
#include "geom_object.h"
+#ifdef __PATCH_EVAL__
+# include "geom_patch.h"
+#endif
#include "geom_triangle.h"
+#include "geom_subd_triangle.h"
#include "geom_triangle_intersect.h"
#include "geom_motion_triangle.h"
#include "geom_motion_curve.h"
#include "geom_curve.h"
#include "geom_volume.h"
#include "geom_primitive.h"
-#include "geom_bvh.h"
diff --git a/intern/cycles/kernel/geom/geom_attribute.h b/intern/cycles/kernel/geom/geom_attribute.h
index c7364e9edac..08ccee56335 100644
--- a/intern/cycles/kernel/geom/geom_attribute.h
+++ b/intern/cycles/kernel/geom/geom_attribute.h
@@ -25,47 +25,80 @@ CCL_NAMESPACE_BEGIN
* Lookup of attributes is different between OSL and SVM, as OSL is ustring
* based while for SVM we use integer ids. */
+ccl_device_inline uint subd_triangle_patch(KernelGlobals *kg, const ShaderData *sd);
+
+ccl_device_inline uint attribute_primitive_type(KernelGlobals *kg, const ShaderData *sd)
+{
+#ifdef __HAIR__
+ if(ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE) {
+ return ATTR_PRIM_CURVE;
+ }
+ else
+#endif
+ if(subd_triangle_patch(kg, sd) != ~0) {
+ return ATTR_PRIM_SUBD;
+ }
+ else {
+ return ATTR_PRIM_TRIANGLE;
+ }
+}
+
+ccl_device_inline AttributeDescriptor attribute_not_found()
+{
+ const AttributeDescriptor desc = {ATTR_ELEMENT_NONE, (NodeAttributeType)0, 0, ATTR_STD_NOT_FOUND};
+ return desc;
+}
+
/* Find attribute based on ID */
-ccl_device_inline int find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeElement *elem)
+ccl_device_inline AttributeDescriptor find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id)
{
- if(ccl_fetch(sd, object) == PRIM_NONE)
- return (int)ATTR_STD_NOT_FOUND;
+ if(ccl_fetch(sd, object) == PRIM_NONE) {
+ return attribute_not_found();
+ }
/* for SVM, find attribute by unique id */
uint attr_offset = ccl_fetch(sd, object)*kernel_data.bvh.attributes_map_stride;
-#ifdef __HAIR__
- attr_offset = (ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE)? attr_offset + ATTR_PRIM_CURVE: attr_offset;
-#endif
+ attr_offset += attribute_primitive_type(kg, sd);
uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
while(attr_map.x != id) {
if(UNLIKELY(attr_map.x == ATTR_STD_NONE)) {
- return ATTR_STD_NOT_FOUND;
+ return attribute_not_found();
}
attr_offset += ATTR_PRIM_TYPES;
attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
}
- *elem = (AttributeElement)attr_map.y;
+ AttributeDescriptor desc;
+ desc.element = (AttributeElement)attr_map.y;
- if(ccl_fetch(sd, prim) == PRIM_NONE && (AttributeElement)attr_map.y != ATTR_ELEMENT_MESH)
- return ATTR_STD_NOT_FOUND;
+ if(ccl_fetch(sd, prim) == PRIM_NONE &&
+ desc.element != ATTR_ELEMENT_MESH &&
+ desc.element != ATTR_ELEMENT_VOXEL &&
+ desc.element != ATTR_ELEMENT_OBJECT)
+ {
+ return attribute_not_found();
+ }
/* return result */
- return (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z;
+ desc.offset = (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z;
+ desc.type = (NodeAttributeType)(attr_map.w & 0xff);
+ desc.flags = (AttributeFlag)(attr_map.w >> 8);
+
+ return desc;
}
/* Transform matrix attribute on meshes */
-ccl_device Transform primitive_attribute_matrix(KernelGlobals *kg, const ShaderData *sd, int offset)
+ccl_device Transform primitive_attribute_matrix(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc)
{
Transform tfm;
- tfm.x = kernel_tex_fetch(__attributes_float3, offset + 0);
- tfm.y = kernel_tex_fetch(__attributes_float3, offset + 1);
- tfm.z = kernel_tex_fetch(__attributes_float3, offset + 2);
- tfm.w = kernel_tex_fetch(__attributes_float3, offset + 3);
+ tfm.x = kernel_tex_fetch(__attributes_float3, desc.offset + 0);
+ tfm.y = kernel_tex_fetch(__attributes_float3, desc.offset + 1);
+ tfm.z = kernel_tex_fetch(__attributes_float3, desc.offset + 2);
+ tfm.w = kernel_tex_fetch(__attributes_float3, desc.offset + 3);
return tfm;
}
diff --git a/intern/cycles/kernel/geom/geom_bvh_traversal.h b/intern/cycles/kernel/geom/geom_bvh_traversal.h
deleted file mode 100644
index 8560612addc..00000000000
--- a/intern/cycles/kernel/geom/geom_bvh_traversal.h
+++ /dev/null
@@ -1,449 +0,0 @@
-/*
- * Adapted from code Copyright 2009-2010 NVIDIA Corporation,
- * and code copyright 2009-2012 Intel Corporation
- *
- * Modifications Copyright 2011-2013, Blender Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifdef __QBVH__
-# include "geom_qbvh_traversal.h"
-#endif
-
-/* This is a template BVH traversal function, where various features can be
- * enabled/disabled. This way we can compile optimized versions for each case
- * without new features slowing things down.
- *
- * BVH_INSTANCING: object instancing
- * BVH_HAIR: hair curve rendering
- * BVH_HAIR_MINIMUM_WIDTH: hair curve rendering with minimum width
- * BVH_MOTION: motion blur rendering
- *
- */
-
-ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
- const Ray *ray,
- Intersection *isect,
- const uint visibility
-#if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH)
- , uint *lcg_state,
- float difl,
- float extmax
-#endif
- )
-{
- /* todo:
- * - test if pushing distance on the stack helps (for non shadow rays)
- * - separate version for shadow rays
- * - likely and unlikely for if() statements
- * - test restrict attribute for pointers
- */
-
- /* traversal stack in CUDA thread-local memory */
- int traversalStack[BVH_STACK_SIZE];
- traversalStack[0] = ENTRYPOINT_SENTINEL;
-
- /* traversal variables in registers */
- int stackPtr = 0;
- int nodeAddr = kernel_data.bvh.root;
-
- /* ray parameters in registers */
- float3 P = ray->P;
- float3 dir = bvh_clamp_direction(ray->D);
- float3 idir = bvh_inverse_direction(dir);
- int object = OBJECT_NONE;
-
-#if BVH_FEATURE(BVH_MOTION)
- Transform ob_itfm;
-#endif
-
- isect->t = ray->t;
- isect->u = 0.0f;
- isect->v = 0.0f;
- isect->prim = PRIM_NONE;
- isect->object = OBJECT_NONE;
-
-#if defined(__KERNEL_DEBUG__)
- isect->num_traversal_steps = 0;
- isect->num_traversed_instances = 0;
-#endif
-
-#if defined(__KERNEL_SSE2__)
- const shuffle_swap_t shuf_identity = shuffle_swap_identity();
- const shuffle_swap_t shuf_swap = shuffle_swap_swap();
-
- const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000));
- ssef Psplat[3], idirsplat[3];
- shuffle_swap_t shufflexyz[3];
-
- Psplat[0] = ssef(P.x);
- Psplat[1] = ssef(P.y);
- Psplat[2] = ssef(P.z);
-
- ssef tsplat(0.0f, 0.0f, -isect->t, -isect->t);
-
- gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
-#endif
-
- IsectPrecalc isect_precalc;
- triangle_intersect_precalc(dir, &isect_precalc);
-
- /* traversal loop */
- do {
- do {
- /* traverse internal nodes */
- while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) {
- bool traverseChild0, traverseChild1;
- int nodeAddrChild1;
-
-#if !defined(__KERNEL_SSE2__)
- /* Intersect two child bounding boxes, non-SSE version */
- float t = isect->t;
-
- /* fetch node data */
- float4 node0 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+0);
- float4 node1 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+1);
- float4 node2 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+2);
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+3);
-
- /* intersect ray against child nodes */
- NO_EXTENDED_PRECISION float c0lox = (node0.x - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c0hix = (node0.z - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c0loy = (node1.x - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c0hiy = (node1.z - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c0loz = (node2.x - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c0hiz = (node2.z - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f);
- NO_EXTENDED_PRECISION float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t);
-
- NO_EXTENDED_PRECISION float c1lox = (node0.y - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c1hix = (node0.w - P.x) * idir.x;
- NO_EXTENDED_PRECISION float c1loy = (node1.y - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c1hiy = (node1.w - P.y) * idir.y;
- NO_EXTENDED_PRECISION float c1loz = (node2.y - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c1hiz = (node2.w - P.z) * idir.z;
- NO_EXTENDED_PRECISION float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f);
- NO_EXTENDED_PRECISION float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t);
-
-# if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH)
- if(difl != 0.0f) {
- float hdiff = 1.0f + difl;
- float ldiff = 1.0f - difl;
- if(__float_as_int(cnodes.z) & PATH_RAY_CURVE) {
- c0min = max(ldiff * c0min, c0min - extmax);
- c0max = min(hdiff * c0max, c0max + extmax);
- }
- if(__float_as_int(cnodes.w) & PATH_RAY_CURVE) {
- c1min = max(ldiff * c1min, c1min - extmax);
- c1max = min(hdiff * c1max, c1max + extmax);
- }
- }
-# endif
-
- /* decide which nodes to traverse next */
-# ifdef __VISIBILITY_FLAG__
- /* this visibility test gives a 5% performance hit, how to solve? */
- traverseChild0 = (c0max >= c0min) && (__float_as_uint(cnodes.z) & visibility);
- traverseChild1 = (c1max >= c1min) && (__float_as_uint(cnodes.w) & visibility);
-# else
- traverseChild0 = (c0max >= c0min);
- traverseChild1 = (c1max >= c1min);
-# endif
-
-#else // __KERNEL_SSE2__
- /* Intersect two child bounding boxes, SSE3 version adapted from Embree */
-
- /* fetch node data */
- const ssef *bvh_nodes = (ssef*)kg->__bvh_nodes.data + nodeAddr*BVH_NODE_SIZE;
- const float4 cnodes = ((float4*)bvh_nodes)[3];
-
- /* intersect ray against child nodes */
- const ssef tminmaxx = (shuffle_swap(bvh_nodes[0], shufflexyz[0]) - Psplat[0]) * idirsplat[0];
- const ssef tminmaxy = (shuffle_swap(bvh_nodes[1], shufflexyz[1]) - Psplat[1]) * idirsplat[1];
- const ssef tminmaxz = (shuffle_swap(bvh_nodes[2], shufflexyz[2]) - Psplat[2]) * idirsplat[2];
-
- /* calculate { c0min, c1min, -c0max, -c1max} */
- ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat));
- const ssef tminmax = minmax ^ pn;
-
-# if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH)
- if(difl != 0.0f) {
- float4 *tminmaxview = (float4*)&tminmax;
- float &c0min = tminmaxview->x, &c1min = tminmaxview->y;
- float &c0max = tminmaxview->z, &c1max = tminmaxview->w;
-
- float hdiff = 1.0f + difl;
- float ldiff = 1.0f - difl;
- if(__float_as_int(cnodes.z) & PATH_RAY_CURVE) {
- c0min = max(ldiff * c0min, c0min - extmax);
- c0max = min(hdiff * c0max, c0max + extmax);
- }
- if(__float_as_int(cnodes.w) & PATH_RAY_CURVE) {
- c1min = max(ldiff * c1min, c1min - extmax);
- c1max = min(hdiff * c1max, c1max + extmax);
- }
- }
-# endif
-
- const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax);
-
- /* decide which nodes to traverse next */
-# ifdef __VISIBILITY_FLAG__
- /* this visibility test gives a 5% performance hit, how to solve? */
- traverseChild0 = (movemask(lrhit) & 1) && (__float_as_uint(cnodes.z) & visibility);
- traverseChild1 = (movemask(lrhit) & 2) && (__float_as_uint(cnodes.w) & visibility);
-# else
- traverseChild0 = (movemask(lrhit) & 1);
- traverseChild1 = (movemask(lrhit) & 2);
-# endif
-#endif // __KERNEL_SSE2__
-
- nodeAddr = __float_as_int(cnodes.x);
- nodeAddrChild1 = __float_as_int(cnodes.y);
-
- if(traverseChild0 && traverseChild1) {
- /* both children were intersected, push the farther one */
-#if !defined(__KERNEL_SSE2__)
- bool closestChild1 = (c1min < c0min);
-#else
- bool closestChild1 = tminmax[1] < tminmax[0];
-#endif
-
- if(closestChild1) {
- int tmp = nodeAddr;
- nodeAddr = nodeAddrChild1;
- nodeAddrChild1 = tmp;
- }
-
- ++stackPtr;
- kernel_assert(stackPtr < BVH_STACK_SIZE);
- traversalStack[stackPtr] = nodeAddrChild1;
- }
- else {
- /* one child was intersected */
- if(traverseChild1) {
- nodeAddr = nodeAddrChild1;
- }
- else if(!traverseChild0) {
- /* neither child was intersected */
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
- }
- }
-
-#if defined(__KERNEL_DEBUG__)
- isect->num_traversal_steps++;
-#endif
- }
-
- /* if node is leaf, fetch triangle list */
- if(nodeAddr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_NODE_LEAF_SIZE);
- int primAddr = __float_as_int(leaf.x);
-
-#if BVH_FEATURE(BVH_INSTANCING)
- if(primAddr >= 0) {
-#endif
- const int primAddr2 = __float_as_int(leaf.y);
- const uint type = __float_as_int(leaf.w);
-
- /* pop */
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
-
- /* primitive intersection */
- switch(type & PRIMITIVE_ALL) {
- case PRIMITIVE_TRIANGLE: {
- for(; primAddr < primAddr2; primAddr++) {
-#if defined(__KERNEL_DEBUG__)
- isect->num_traversal_steps++;
-#endif
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
- if(triangle_intersect(kg, &isect_precalc, isect, P, visibility, object, primAddr)) {
- /* shadow ray early termination */
-#if defined(__KERNEL_SSE2__)
- if(visibility == PATH_RAY_SHADOW_OPAQUE)
- return true;
- tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t);
-#else
- if(visibility == PATH_RAY_SHADOW_OPAQUE)
- return true;
-#endif
- }
- }
- break;
- }
-#if BVH_FEATURE(BVH_MOTION)
- case PRIMITIVE_MOTION_TRIANGLE: {
- for(; primAddr < primAddr2; primAddr++) {
-# if defined(__KERNEL_DEBUG__)
- isect->num_traversal_steps++;
-# endif
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
- if(motion_triangle_intersect(kg, isect, P, dir, ray->time, visibility, object, primAddr)) {
- /* shadow ray early termination */
-# if defined(__KERNEL_SSE2__)
- if(visibility == PATH_RAY_SHADOW_OPAQUE)
- return true;
- tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t);
-# else
- if(visibility == PATH_RAY_SHADOW_OPAQUE)
- return true;
-# endif
- }
- }
- break;
- }
-#endif /* BVH_FEATURE(BVH_MOTION) */
-#if BVH_FEATURE(BVH_HAIR)
- case PRIMITIVE_CURVE:
- case PRIMITIVE_MOTION_CURVE: {
- for(; primAddr < primAddr2; primAddr++) {
-# if defined(__KERNEL_DEBUG__)
- isect->num_traversal_steps++;
-# endif
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
- bool hit;
- if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE)
- hit = bvh_cardinal_curve_intersect(kg, isect, P, dir, visibility, object, primAddr, ray->time, type, lcg_state, difl, extmax);
- else
- hit = bvh_curve_intersect(kg, isect, P, dir, visibility, object, primAddr, ray->time, type, lcg_state, difl, extmax);
- if(hit) {
- /* shadow ray early termination */
-# if defined(__KERNEL_SSE2__)
- if(visibility == PATH_RAY_SHADOW_OPAQUE)
- return true;
- tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t);
-# else
- if(visibility == PATH_RAY_SHADOW_OPAQUE)
- return true;
-# endif
- }
- }
- break;
- }
-#endif /* BVH_FEATURE(BVH_HAIR) */
- }
- }
-#if BVH_FEATURE(BVH_INSTANCING)
- else {
- /* instance push */
- object = kernel_tex_fetch(__prim_object, -primAddr-1);
-
-# if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_itfm);
-# else
- bvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect->t);
-# endif
- triangle_intersect_precalc(dir, &isect_precalc);
-
-# if defined(__KERNEL_SSE2__)
- Psplat[0] = ssef(P.x);
- Psplat[1] = ssef(P.y);
- Psplat[2] = ssef(P.z);
-
- tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t);
-
- gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
-# endif
-
- ++stackPtr;
- kernel_assert(stackPtr < BVH_STACK_SIZE);
- traversalStack[stackPtr] = ENTRYPOINT_SENTINEL;
-
- nodeAddr = kernel_tex_fetch(__object_node, object);
-
-# if defined(__KERNEL_DEBUG__)
- isect->num_traversed_instances++;
-# endif
- }
- }
-#endif /* FEATURE(BVH_INSTANCING) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
-
-#if BVH_FEATURE(BVH_INSTANCING)
- if(stackPtr >= 0) {
- kernel_assert(object != OBJECT_NONE);
-
- /* instance pop */
-# if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_itfm);
-# else
- bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &isect->t);
-# endif
- triangle_intersect_precalc(dir, &isect_precalc);
-
-# if defined(__KERNEL_SSE2__)
- Psplat[0] = ssef(P.x);
- Psplat[1] = ssef(P.y);
- Psplat[2] = ssef(P.z);
-
- tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t);
-
- gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
-# endif
-
- object = OBJECT_NONE;
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
- }
-#endif /* FEATURE(BVH_INSTANCING) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
-
- return (isect->prim != PRIM_NONE);
-}
-
-ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals *kg,
- const Ray *ray,
- Intersection *isect,
- const uint visibility
-#if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH)
- , uint *lcg_state,
- float difl,
- float extmax
-#endif
- )
-{
-#ifdef __QBVH__
- if(kernel_data.bvh.use_qbvh) {
- return BVH_FUNCTION_FULL_NAME(QBVH)(kg,
- ray,
- isect,
- visibility
-#if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH)
- , lcg_state,
- difl,
- extmax
-#endif
- );
- }
- else
-#endif
- {
- kernel_assert(kernel_data.bvh.use_qbvh == false);
- return BVH_FUNCTION_FULL_NAME(BVH)(kg,
- ray,
- isect,
- visibility
-#if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH)
- , lcg_state,
- difl,
- extmax
-#endif
- );
- }
-}
-
-#undef BVH_FUNCTION_NAME
-#undef BVH_FUNCTION_FEATURES
diff --git a/intern/cycles/kernel/geom/geom_curve.h b/intern/cycles/kernel/geom/geom_curve.h
index 8894843997c..84aaaab7453 100644
--- a/intern/cycles/kernel/geom/geom_curve.h
+++ b/intern/cycles/kernel/geom/geom_curve.h
@@ -24,23 +24,23 @@ CCL_NAMESPACE_BEGIN
/* Reading attributes on various curve elements */
-ccl_device float curve_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy)
+ccl_device float curve_attribute_float(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float *dx, float *dy)
{
- if(elem == ATTR_ELEMENT_CURVE) {
+ if(desc.element == ATTR_ELEMENT_CURVE) {
#ifdef __RAY_DIFFERENTIALS__
if(dx) *dx = 0.0f;
if(dy) *dy = 0.0f;
#endif
- return kernel_tex_fetch(__attributes_float, offset + ccl_fetch(sd, prim));
+ return kernel_tex_fetch(__attributes_float, desc.offset + ccl_fetch(sd, prim));
}
- else if(elem == ATTR_ELEMENT_CURVE_KEY || elem == ATTR_ELEMENT_CURVE_KEY_MOTION) {
+ else if(desc.element == ATTR_ELEMENT_CURVE_KEY || desc.element == ATTR_ELEMENT_CURVE_KEY_MOTION) {
float4 curvedata = kernel_tex_fetch(__curves, ccl_fetch(sd, prim));
int k0 = __float_as_int(curvedata.x) + PRIMITIVE_UNPACK_SEGMENT(ccl_fetch(sd, type));
int k1 = k0 + 1;
- float f0 = kernel_tex_fetch(__attributes_float, offset + k0);
- float f1 = kernel_tex_fetch(__attributes_float, offset + k1);
+ float f0 = kernel_tex_fetch(__attributes_float, desc.offset + k0);
+ float f1 = kernel_tex_fetch(__attributes_float, desc.offset + k1);
#ifdef __RAY_DIFFERENTIALS__
if(dx) *dx = ccl_fetch(sd, du).dx*(f1 - f0);
@@ -59,9 +59,9 @@ ccl_device float curve_attribute_float(KernelGlobals *kg, const ShaderData *sd,
}
}
-ccl_device float3 curve_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy)
+ccl_device float3 curve_attribute_float3(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float3 *dx, float3 *dy)
{
- if(elem == ATTR_ELEMENT_CURVE) {
+ if(desc.element == ATTR_ELEMENT_CURVE) {
/* idea: we can't derive any useful differentials here, but for tiled
* mipmap image caching it would be useful to avoid reading the highest
* detail level always. maybe a derivative based on the hair density
@@ -71,15 +71,15 @@ ccl_device float3 curve_attribute_float3(KernelGlobals *kg, const ShaderData *sd
if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
#endif
- return float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + ccl_fetch(sd, prim)));
+ return float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + ccl_fetch(sd, prim)));
}
- else if(elem == ATTR_ELEMENT_CURVE_KEY || elem == ATTR_ELEMENT_CURVE_KEY_MOTION) {
+ else if(desc.element == ATTR_ELEMENT_CURVE_KEY || desc.element == ATTR_ELEMENT_CURVE_KEY_MOTION) {
float4 curvedata = kernel_tex_fetch(__curves, ccl_fetch(sd, prim));
int k0 = __float_as_int(curvedata.x) + PRIMITIVE_UNPACK_SEGMENT(ccl_fetch(sd, type));
int k1 = k0 + 1;
- float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + k0));
- float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + k1));
+ float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + k0));
+ float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + k1));
#ifdef __RAY_DIFFERENTIALS__
if(dx) *dx = ccl_fetch(sd, du).dx*(f1 - f0);
@@ -222,10 +222,10 @@ ccl_device_inline ssef transform_point_T3(const ssef t[3], const ssef &a)
#ifdef __KERNEL_SSE2__
/* Pass P and dir by reference to aligned vector */
-ccl_device_inline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersection *isect,
+ccl_device_forceinline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersection *isect,
const float3 &P, const float3 &dir, uint visibility, int object, int curveAddr, float time, int type, uint *lcg_state, float difl, float extmax)
#else
-ccl_device_inline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersection *isect,
+ccl_device_forceinline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersection *isect,
float3 P, float3 dir, uint visibility, int object, int curveAddr, float time,int type, uint *lcg_state, float difl, float extmax)
#endif
{
@@ -450,8 +450,8 @@ ccl_device_inline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersect
else if(level == 1) {
/* the maximum recursion depth is reached.
- * check if dP0.(Q-P0)>=0 and dPn.(Pn-Q)>=0.
- * dP* is reversed if necessary.*/
+ * check if dP0.(Q-P0)>=0 and dPn.(Pn-Q)>=0.
+ * dP* is reversed if necessary.*/
float t = isect->t;
float u = 0.0f;
float gd = 0.0f;
@@ -621,7 +621,7 @@ ccl_device_inline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersect
return hit;
}
-ccl_device_inline bool bvh_curve_intersect(KernelGlobals *kg, Intersection *isect,
+ccl_device_forceinline bool bvh_curve_intersect(KernelGlobals *kg, Intersection *isect,
float3 P, float3 direction, uint visibility, int object, int curveAddr, float time, int type, uint *lcg_state, float difl, float extmax)
{
/* define few macros to minimize code duplication for SSE */
diff --git a/intern/cycles/kernel/geom/geom_motion_triangle.h b/intern/cycles/kernel/geom/geom_motion_triangle.h
index ffe55529110..3cbe59aaece 100644
--- a/intern/cycles/kernel/geom/geom_motion_triangle.h
+++ b/intern/cycles/kernel/geom/geom_motion_triangle.h
@@ -1,6 +1,5 @@
/*
- * Adapted from code Copyright 2009-2010 NVIDIA Corporation
- * Modifications Copyright 2011, Blender Foundation.
+ * Copyright 2011-2013 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -47,13 +46,13 @@ ccl_device_inline int find_attribute_motion(KernelGlobals *kg, int object, uint
return (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z;
}
-ccl_device_inline void motion_triangle_verts_for_step(KernelGlobals *kg, float3 tri_vindex, int offset, int numverts, int numsteps, int step, float3 verts[3])
+ccl_device_inline void motion_triangle_verts_for_step(KernelGlobals *kg, uint4 tri_vindex, int offset, int numverts, int numsteps, int step, float3 verts[3])
{
if(step == numsteps) {
/* center step: regular vertex location */
- verts[0] = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x)));
- verts[1] = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y)));
- verts[2] = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z)));
+ verts[0] = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+0));
+ verts[1] = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+1));
+ verts[2] = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+2));
}
else {
/* center step not store in this array */
@@ -62,19 +61,19 @@ ccl_device_inline void motion_triangle_verts_for_step(KernelGlobals *kg, float3
offset += step*numverts;
- verts[0] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.x)));
- verts[1] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.y)));
- verts[2] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.z)));
+ verts[0] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.x));
+ verts[1] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.y));
+ verts[2] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.z));
}
}
-ccl_device_inline void motion_triangle_normals_for_step(KernelGlobals *kg, float3 tri_vindex, int offset, int numverts, int numsteps, int step, float3 normals[3])
+ccl_device_inline void motion_triangle_normals_for_step(KernelGlobals *kg, uint4 tri_vindex, int offset, int numverts, int numsteps, int step, float3 normals[3])
{
if(step == numsteps) {
/* center step: regular vertex location */
- normals[0] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.x)));
- normals[1] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.y)));
- normals[2] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.z)));
+ normals[0] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.x));
+ normals[1] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.y));
+ normals[2] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.z));
}
else {
/* center step not stored in this array */
@@ -83,9 +82,9 @@ ccl_device_inline void motion_triangle_normals_for_step(KernelGlobals *kg, float
offset += step*numverts;
- normals[0] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.x)));
- normals[1] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.y)));
- normals[2] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.z)));
+ normals[0] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.x));
+ normals[1] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.y));
+ normals[2] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.z));
}
}
@@ -107,7 +106,7 @@ ccl_device_inline void motion_triangle_vertices(KernelGlobals *kg, int object, i
/* fetch vertex coordinates */
float3 next_verts[3];
- float3 tri_vindex = float4_to_float3(kernel_tex_fetch(__tri_vindex, prim));
+ uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step, verts);
motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step+1, next_verts);
@@ -259,7 +258,7 @@ ccl_device_noinline void motion_triangle_shader_setup(KernelGlobals *kg, ShaderD
/* fetch vertex coordinates */
float3 verts[3], next_verts[3];
- float3 tri_vindex = float4_to_float3(kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim)));
+ uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim));
motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step, verts);
motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step+1, next_verts);
@@ -387,6 +386,12 @@ ccl_device_inline void motion_triangle_intersect_subsurface(
float t, u, v;
if(ray_triangle_intersect_uv(P, dir, tmax, verts[2], verts[0], verts[1], &u, &v, &t)) {
+ for(int i = min(max_hits, ss_isect->num_hits) - 1; i >= 0; --i) {
+ if(ss_isect->hits[i].t == t) {
+ return;
+ }
+ }
+
ss_isect->num_hits++;
int hit;
diff --git a/intern/cycles/kernel/geom/geom_object.h b/intern/cycles/kernel/geom/geom_object.h
index c0d15a95954..6b42f66b0d5 100644
--- a/intern/cycles/kernel/geom/geom_object.h
+++ b/intern/cycles/kernel/geom/geom_object.h
@@ -55,6 +55,21 @@ ccl_device_inline Transform object_fetch_transform(KernelGlobals *kg, int object
return tfm;
}
+/* Lamp to world space transformation */
+
+ccl_device_inline Transform lamp_fetch_transform(KernelGlobals *kg, int lamp, bool inverse)
+{
+ int offset = lamp*LIGHT_SIZE + (inverse? 8 : 5);
+
+ Transform tfm;
+ tfm.x = kernel_tex_fetch(__light_data, offset + 0);
+ tfm.y = kernel_tex_fetch(__light_data, offset + 1);
+ tfm.z = kernel_tex_fetch(__light_data, offset + 2);
+ tfm.w = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
+
+ return tfm;
+}
+
/* Object to world space transformation for motion vectors */
ccl_device_inline Transform object_fetch_vector_transform(KernelGlobals *kg, int object, enum ObjectVectorTransform type)
@@ -292,11 +307,23 @@ ccl_device_inline void object_motion_info(KernelGlobals *kg, int object, int *nu
*numverts = __float_as_int(f.w);
}
+/* Offset to an objects patch map */
+
+ccl_device_inline uint object_patch_map_offset(KernelGlobals *kg, int object)
+{
+ if(object == OBJECT_NONE)
+ return 0;
+
+ int offset = object*OBJECT_SIZE + 11;
+ float4 f = kernel_tex_fetch(__objects, offset);
+ return __float_as_uint(f.x);
+}
+
/* Pass ID for shader */
ccl_device int shader_pass_id(KernelGlobals *kg, const ShaderData *sd)
{
- return kernel_tex_fetch(__shader_flag, (ccl_fetch(sd, shader) & SHADER_MASK)*2 + 1);
+ return kernel_tex_fetch(__shader_flag, (ccl_fetch(sd, shader) & SHADER_MASK)*SHADER_SIZE + 1);
}
/* Particle data from which object was instanced */
@@ -364,15 +391,33 @@ ccl_device float3 particle_angular_velocity(KernelGlobals *kg, int particle)
ccl_device_inline float3 bvh_clamp_direction(float3 dir)
{
/* clamp absolute values by exp2f(-80.0f) to avoid division by zero when calculating inverse direction */
- float ooeps = 8.271806E-25f;
+#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__)
+ const ssef oopes(8.271806E-25f,8.271806E-25f,8.271806E-25f,0.0f);
+ const ssef mask = _mm_cmpgt_ps(fabs(dir), oopes);
+ const ssef signdir = signmsk(dir.m128) | oopes;
+# ifndef __KERNEL_AVX__
+ ssef res = mask & ssef(dir);
+ res = _mm_or_ps(res,_mm_andnot_ps(mask, signdir));
+# else
+ ssef res = _mm_blendv_ps(signdir, dir, mask);
+# endif
+ return float3(res);
+#else /* __KERNEL_SSE__ && __KERNEL_SSE2__ */
+ const float ooeps = 8.271806E-25f;
return make_float3((fabsf(dir.x) > ooeps)? dir.x: copysignf(ooeps, dir.x),
(fabsf(dir.y) > ooeps)? dir.y: copysignf(ooeps, dir.y),
(fabsf(dir.z) > ooeps)? dir.z: copysignf(ooeps, dir.z));
+#endif /* __KERNEL_SSE__ && __KERNEL_SSE2__ */
}
ccl_device_inline float3 bvh_inverse_direction(float3 dir)
{
+ /* TODO(sergey): Currently disabled, gives speedup but causes precision issues. */
+#if defined(__KERNEL_SSE__) && 0
+ return rcp(dir);
+#else
return 1.0f / dir;
+#endif
}
/* Transform ray into object space to enter static object in BVH */
@@ -552,6 +597,15 @@ ccl_device_inline void bvh_instance_motion_pop_factor(KernelGlobals *kg,
*/
#ifdef __KERNEL_OPENCL__
+ccl_device_inline void object_position_transform_addrspace(KernelGlobals *kg,
+ const ShaderData *sd,
+ ccl_addr_space float3 *P)
+{
+ float3 private_P = *P;
+ object_position_transform(kg, sd, &private_P);
+ *P = private_P;
+}
+
ccl_device_inline void object_dir_transform_addrspace(KernelGlobals *kg,
const ShaderData *sd,
ccl_addr_space float3 *D)
@@ -572,9 +626,11 @@ ccl_device_inline void object_normal_transform_addrspace(KernelGlobals *kg,
#endif
#ifndef __KERNEL_OPENCL__
+# define object_position_transform_auto object_position_transform
# define object_dir_transform_auto object_dir_transform
# define object_normal_transform_auto object_normal_transform
#else
+# define object_position_transform_auto object_position_transform_addrspace
# define object_dir_transform_auto object_dir_transform_addrspace
# define object_normal_transform_auto object_normal_transform_addrspace
#endif
diff --git a/intern/cycles/kernel/geom/geom_patch.h b/intern/cycles/kernel/geom/geom_patch.h
new file mode 100644
index 00000000000..6a0ff5a4a04
--- /dev/null
+++ b/intern/cycles/kernel/geom/geom_patch.h
@@ -0,0 +1,343 @@
+/*
+ * Based on code from OpenSubdiv released under this license:
+ *
+ * Copyright 2013 Pixar
+ *
+ * Licensed under the Apache License, Version 2.0 (the "Apache License")
+ * with the following modification; you may not use this file except in
+ * compliance with the Apache License and the following modification to it:
+ * Section 6. Trademarks. is deleted and replaced with:
+ *
+ * 6. Trademarks. This License does not grant permission to use the trade
+ * names, trademarks, service marks, or product names of the Licensor
+ * and its affiliates, except as required to comply with Section 4(c) of
+ * the License and to reproduce the content of the NOTICE file.
+ *
+ * You may obtain a copy of the Apache License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Apache License with the above modification is
+ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the Apache License for the specific
+ * language governing permissions and limitations under the Apache License.
+ *
+ */
+
+CCL_NAMESPACE_BEGIN
+
+typedef struct PatchHandle {
+ int array_index, patch_index, vert_index;
+} PatchHandle;
+
+ccl_device_inline int patch_map_resolve_quadrant(float median, float *u, float *v)
+{
+ int quadrant = -1;
+
+ if(*u < median) {
+ if(*v < median) {
+ quadrant = 0;
+ }
+ else {
+ quadrant = 1;
+ *v -= median;
+ }
+ }
+ else {
+ if(*v < median) {
+ quadrant = 3;
+ }
+ else {
+ quadrant = 2;
+ *v -= median;
+ }
+ *u -= median;
+ }
+
+ return quadrant;
+}
+
+/* retrieve PatchHandle from patch coords */
+
+ccl_device_inline PatchHandle patch_map_find_patch(KernelGlobals *kg, int object, int patch, float u, float v)
+{
+ PatchHandle handle;
+
+ kernel_assert((u >= 0.0f) && (u <= 1.0f) && (v >= 0.0f) && (v <= 1.0f));
+
+ int node = (object_patch_map_offset(kg, object) + patch)/2;
+ float median = 0.5f;
+
+ for(int depth = 0; depth < 0xff; depth++) {
+ float delta = median * 0.5f;
+
+ int quadrant = patch_map_resolve_quadrant(median, &u, &v);
+ kernel_assert(quadrant >= 0);
+
+ uint child = kernel_tex_fetch(__patches, node + quadrant);
+
+ /* is the quadrant a hole? */
+ if(!(child & PATCH_MAP_NODE_IS_SET)) {
+ handle.array_index = -1;
+ return handle;
+ }
+
+ uint index = child & PATCH_MAP_NODE_INDEX_MASK;
+
+ if(child & PATCH_MAP_NODE_IS_LEAF) {
+ handle.array_index = kernel_tex_fetch(__patches, index + 0);
+ handle.patch_index = kernel_tex_fetch(__patches, index + 1);
+ handle.vert_index = kernel_tex_fetch(__patches, index + 2);
+
+ return handle;
+ } else {
+ node = index;
+ }
+
+ median = delta;
+ }
+
+ /* no leaf found */
+ kernel_assert(0);
+
+ handle.array_index = -1;
+ return handle;
+}
+
+ccl_device_inline void patch_eval_bspline_weights(float t, float *point, float *deriv)
+{
+ /* The four uniform cubic B-Spline basis functions evaluated at t */
+ float inv_6 = 1.0f / 6.0f;
+
+ float t2 = t * t;
+ float t3 = t * t2;
+
+ point[0] = inv_6 * (1.0f - 3.0f*(t - t2) - t3);
+ point[1] = inv_6 * (4.0f - 6.0f*t2 + 3.0f*t3);
+ point[2] = inv_6 * (1.0f + 3.0f*(t + t2 - t3));
+ point[3] = inv_6 * t3;
+
+ /* Derivatives of the above four basis functions at t */
+ deriv[0] = -0.5f*t2 + t - 0.5f;
+ deriv[1] = 1.5f*t2 - 2.0f*t;
+ deriv[2] = -1.5f*t2 + t + 0.5f;
+ deriv[3] = 0.5f*t2;
+}
+
+ccl_device_inline void patch_eval_adjust_boundary_weights(uint bits, float *s, float *t)
+{
+ int boundary = ((bits >> 8) & 0xf);
+
+ if(boundary & 1) {
+ t[2] -= t[0];
+ t[1] += 2*t[0];
+ t[0] = 0;
+ }
+
+ if(boundary & 2) {
+ s[1] -= s[3];
+ s[2] += 2*s[3];
+ s[3] = 0;
+ }
+
+ if(boundary & 4) {
+ t[1] -= t[3];
+ t[2] += 2*t[3];
+ t[3] = 0;
+ }
+
+ if(boundary & 8) {
+ s[2] -= s[0];
+ s[1] += 2*s[0];
+ s[0] = 0;
+ }
+}
+
+ccl_device_inline int patch_eval_depth(uint patch_bits)
+{
+ return (patch_bits & 0xf);
+}
+
+ccl_device_inline float patch_eval_param_fraction(uint patch_bits)
+{
+ bool non_quad_root = (patch_bits >> 4) & 0x1;
+ int depth = patch_eval_depth(patch_bits);
+
+ if(non_quad_root) {
+ return 1.0f / (float)(1 << (depth-1));
+ }
+ else {
+ return 1.0f / (float)(1 << depth);
+ }
+}
+
+ccl_device_inline void patch_eval_normalize_coords(uint patch_bits, float *u, float *v)
+{
+ float frac = patch_eval_param_fraction(patch_bits);
+
+ int iu = (patch_bits >> 22) & 0x3ff;
+ int iv = (patch_bits >> 12) & 0x3ff;
+
+ /* top left corner */
+ float pu = (float)iu*frac;
+ float pv = (float)iv*frac;
+
+ /* normalize uv coordinates */
+ *u = (*u - pu) / frac;
+ *v = (*v - pv) / frac;
+}
+
+/* retrieve patch control indices */
+
+ccl_device_inline int patch_eval_indices(KernelGlobals *kg, const PatchHandle *handle, int channel,
+ int indices[PATCH_MAX_CONTROL_VERTS])
+{
+ int index_base = kernel_tex_fetch(__patches, handle->array_index + 2) + handle->vert_index;
+
+ /* XXX: regular patches only */
+ for(int i = 0; i < 16; i++) {
+ indices[i] = kernel_tex_fetch(__patches, index_base + i);
+ }
+
+ return 16;
+}
+
+/* evaluate patch basis functions */
+
+ccl_device_inline void patch_eval_basis(KernelGlobals *kg, const PatchHandle *handle, float u, float v,
+ float weights[PATCH_MAX_CONTROL_VERTS],
+ float weights_du[PATCH_MAX_CONTROL_VERTS],
+ float weights_dv[PATCH_MAX_CONTROL_VERTS])
+{
+ uint patch_bits = kernel_tex_fetch(__patches, handle->patch_index + 1); /* read patch param */
+ float d_scale = 1 << patch_eval_depth(patch_bits);
+
+ bool non_quad_root = (patch_bits >> 4) & 0x1;
+ if(non_quad_root) {
+ d_scale *= 0.5f;
+ }
+
+ patch_eval_normalize_coords(patch_bits, &u, &v);
+
+ /* XXX: regular patches only for now. */
+
+ float s[4], t[4], ds[4], dt[4];
+
+ patch_eval_bspline_weights(u, s, ds);
+ patch_eval_bspline_weights(v, t, dt);
+
+ patch_eval_adjust_boundary_weights(patch_bits, s, t);
+ patch_eval_adjust_boundary_weights(patch_bits, ds, dt);
+
+ for(int k = 0; k < 4; k++) {
+ for(int l = 0; l < 4; l++) {
+ weights[4*k+l] = s[l] * t[k];
+ weights_du[4*k+l] = ds[l] * t[k] * d_scale;
+ weights_dv[4*k+l] = s[l] * dt[k] * d_scale;
+ }
+ }
+}
+
+/* generic function for evaluating indices and weights from patch coords */
+
+ccl_device_inline int patch_eval_control_verts(KernelGlobals *kg, int object, int patch, float u, float v, int channel,
+ int indices[PATCH_MAX_CONTROL_VERTS],
+ float weights[PATCH_MAX_CONTROL_VERTS],
+ float weights_du[PATCH_MAX_CONTROL_VERTS],
+ float weights_dv[PATCH_MAX_CONTROL_VERTS])
+{
+ PatchHandle handle = patch_map_find_patch(kg, object, patch, u, v);
+ kernel_assert(handle.array_index >= 0);
+
+ int num_control = patch_eval_indices(kg, &handle, channel, indices);
+ patch_eval_basis(kg, &handle, u, v, weights, weights_du, weights_dv);
+
+ return num_control;
+}
+
+/* functions for evaluating attributes on patches */
+
+ccl_device float patch_eval_float(KernelGlobals *kg, const ShaderData *sd, int offset,
+ int patch, float u, float v, int channel,
+ float *du, float* dv)
+{
+ int indices[PATCH_MAX_CONTROL_VERTS];
+ float weights[PATCH_MAX_CONTROL_VERTS];
+ float weights_du[PATCH_MAX_CONTROL_VERTS];
+ float weights_dv[PATCH_MAX_CONTROL_VERTS];
+
+ int num_control = patch_eval_control_verts(kg, ccl_fetch(sd, object), patch, u, v, channel,
+ indices, weights, weights_du, weights_dv);
+
+ float val = 0.0f;
+ if(du) *du = 0.0f;
+ if(dv) *dv = 0.0f;
+
+ for(int i = 0; i < num_control; i++) {
+ float v = kernel_tex_fetch(__attributes_float, offset + indices[i]);
+
+ val += v * weights[i];
+ if(du) *du += v * weights_du[i];
+ if(dv) *dv += v * weights_dv[i];
+ }
+
+ return val;
+}
+
+ccl_device float3 patch_eval_float3(KernelGlobals *kg, const ShaderData *sd, int offset,
+ int patch, float u, float v, int channel,
+ float3 *du, float3 *dv)
+{
+ int indices[PATCH_MAX_CONTROL_VERTS];
+ float weights[PATCH_MAX_CONTROL_VERTS];
+ float weights_du[PATCH_MAX_CONTROL_VERTS];
+ float weights_dv[PATCH_MAX_CONTROL_VERTS];
+
+ int num_control = patch_eval_control_verts(kg, ccl_fetch(sd, object), patch, u, v, channel,
+ indices, weights, weights_du, weights_dv);
+
+ float3 val = make_float3(0.0f, 0.0f, 0.0f);
+ if(du) *du = make_float3(0.0f, 0.0f, 0.0f);
+ if(dv) *dv = make_float3(0.0f, 0.0f, 0.0f);
+
+ for(int i = 0; i < num_control; i++) {
+ float3 v = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + indices[i]));
+
+ val += v * weights[i];
+ if(du) *du += v * weights_du[i];
+ if(dv) *dv += v * weights_dv[i];
+ }
+
+ return val;
+}
+
+ccl_device float3 patch_eval_uchar4(KernelGlobals *kg, const ShaderData *sd, int offset,
+ int patch, float u, float v, int channel,
+ float3 *du, float3 *dv)
+{
+ int indices[PATCH_MAX_CONTROL_VERTS];
+ float weights[PATCH_MAX_CONTROL_VERTS];
+ float weights_du[PATCH_MAX_CONTROL_VERTS];
+ float weights_dv[PATCH_MAX_CONTROL_VERTS];
+
+ int num_control = patch_eval_control_verts(kg, ccl_fetch(sd, object), patch, u, v, channel,
+ indices, weights, weights_du, weights_dv);
+
+ float3 val = make_float3(0.0f, 0.0f, 0.0f);
+ if(du) *du = make_float3(0.0f, 0.0f, 0.0f);
+ if(dv) *dv = make_float3(0.0f, 0.0f, 0.0f);
+
+ for(int i = 0; i < num_control; i++) {
+ float3 v = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, offset + indices[i]));
+
+ val += v * weights[i];
+ if(du) *du += v * weights_du[i];
+ if(dv) *dv += v * weights_dv[i];
+ }
+
+ return val;
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/geom/geom_primitive.h b/intern/cycles/kernel/geom/geom_primitive.h
index b1b1e919e00..4384c2093e9 100644
--- a/intern/cycles/kernel/geom/geom_primitive.h
+++ b/intern/cycles/kernel/geom/geom_primitive.h
@@ -23,19 +23,25 @@ CCL_NAMESPACE_BEGIN
/* Generic primitive attribute reading functions */
-ccl_device float primitive_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy)
+ccl_device_inline float primitive_attribute_float(KernelGlobals *kg,
+ const ShaderData *sd,
+ const AttributeDescriptor desc,
+ float *dx, float *dy)
{
if(ccl_fetch(sd, type) & PRIMITIVE_ALL_TRIANGLE) {
- return triangle_attribute_float(kg, sd, elem, offset, dx, dy);
+ if(subd_triangle_patch(kg, sd) == ~0)
+ return triangle_attribute_float(kg, sd, desc, dx, dy);
+ else
+ return subd_triangle_attribute_float(kg, sd, desc, dx, dy);
}
#ifdef __HAIR__
else if(ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE) {
- return curve_attribute_float(kg, sd, elem, offset, dx, dy);
+ return curve_attribute_float(kg, sd, desc, dx, dy);
}
#endif
#ifdef __VOLUME__
- else if(ccl_fetch(sd, object) != OBJECT_NONE && elem == ATTR_ELEMENT_VOXEL) {
- return volume_attribute_float(kg, sd, elem, offset, dx, dy);
+ else if(ccl_fetch(sd, object) != OBJECT_NONE && desc.element == ATTR_ELEMENT_VOXEL) {
+ return volume_attribute_float(kg, sd, desc, dx, dy);
}
#endif
else {
@@ -45,19 +51,25 @@ ccl_device float primitive_attribute_float(KernelGlobals *kg, const ShaderData *
}
}
-ccl_device float3 primitive_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy)
+ccl_device_inline float3 primitive_attribute_float3(KernelGlobals *kg,
+ const ShaderData *sd,
+ const AttributeDescriptor desc,
+ float3 *dx, float3 *dy)
{
if(ccl_fetch(sd, type) & PRIMITIVE_ALL_TRIANGLE) {
- return triangle_attribute_float3(kg, sd, elem, offset, dx, dy);
+ if(subd_triangle_patch(kg, sd) == ~0)
+ return triangle_attribute_float3(kg, sd, desc, dx, dy);
+ else
+ return subd_triangle_attribute_float3(kg, sd, desc, dx, dy);
}
#ifdef __HAIR__
else if(ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE) {
- return curve_attribute_float3(kg, sd, elem, offset, dx, dy);
+ return curve_attribute_float3(kg, sd, desc, dx, dy);
}
#endif
#ifdef __VOLUME__
- else if(ccl_fetch(sd, object) != OBJECT_NONE && elem == ATTR_ELEMENT_VOXEL) {
- return volume_attribute_float3(kg, sd, elem, offset, dx, dy);
+ else if(ccl_fetch(sd, object) != OBJECT_NONE && desc.element == ATTR_ELEMENT_VOXEL) {
+ return volume_attribute_float3(kg, sd, desc, dx, dy);
}
#endif
else {
@@ -69,15 +81,14 @@ ccl_device float3 primitive_attribute_float3(KernelGlobals *kg, const ShaderData
/* Default UV coordinate */
-ccl_device float3 primitive_uv(KernelGlobals *kg, ShaderData *sd)
+ccl_device_inline float3 primitive_uv(KernelGlobals *kg, ShaderData *sd)
{
- AttributeElement elem_uv;
- int offset_uv = find_attribute(kg, sd, ATTR_STD_UV, &elem_uv);
+ const AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_UV);
- if(offset_uv == ATTR_STD_NOT_FOUND)
+ if(desc.offset == ATTR_STD_NOT_FOUND)
return make_float3(0.0f, 0.0f, 0.0f);
- float3 uv = primitive_attribute_float3(kg, sd, elem_uv, offset_uv, NULL, NULL);
+ float3 uv = primitive_attribute_float3(kg, sd, desc, NULL, NULL);
uv.z = 1.0f;
return uv;
}
@@ -87,15 +98,14 @@ ccl_device float3 primitive_uv(KernelGlobals *kg, ShaderData *sd)
ccl_device bool primitive_ptex(KernelGlobals *kg, ShaderData *sd, float2 *uv, int *face_id)
{
/* storing ptex data as attributes is not memory efficient but simple for tests */
- AttributeElement elem_face_id, elem_uv;
- int offset_face_id = find_attribute(kg, sd, ATTR_STD_PTEX_FACE_ID, &elem_face_id);
- int offset_uv = find_attribute(kg, sd, ATTR_STD_PTEX_UV, &elem_uv);
+ const AttributeDescriptor desc_face_id = find_attribute(kg, sd, ATTR_STD_PTEX_FACE_ID);
+ const AttributeDescriptor desc_uv = find_attribute(kg, sd, ATTR_STD_PTEX_UV);
- if(offset_face_id == ATTR_STD_NOT_FOUND || offset_uv == ATTR_STD_NOT_FOUND)
+ if(desc_face_id.offset == ATTR_STD_NOT_FOUND || desc_uv.offset == ATTR_STD_NOT_FOUND)
return false;
- float3 uv3 = primitive_attribute_float3(kg, sd, elem_uv, offset_uv, NULL, NULL);
- float face_id_f = primitive_attribute_float(kg, sd, elem_face_id, offset_face_id, NULL, NULL);
+ float3 uv3 = primitive_attribute_float3(kg, sd, desc_uv, NULL, NULL);
+ float face_id_f = primitive_attribute_float(kg, sd, desc_face_id, NULL, NULL);
*uv = make_float2(uv3.x, uv3.y);
*face_id = (int)face_id_f;
@@ -117,11 +127,10 @@ ccl_device float3 primitive_tangent(KernelGlobals *kg, ShaderData *sd)
#endif
/* try to create spherical tangent from generated coordinates */
- AttributeElement attr_elem;
- int attr_offset = find_attribute(kg, sd, ATTR_STD_GENERATED, &attr_elem);
+ const AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_GENERATED);
- if(attr_offset != ATTR_STD_NOT_FOUND) {
- float3 data = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL);
+ if(desc.offset != ATTR_STD_NOT_FOUND) {
+ float3 data = primitive_attribute_float3(kg, sd, desc, NULL, NULL);
data = make_float3(-(data.y - 0.5f), (data.x - 0.5f), 0.0f);
object_normal_transform(kg, sd, &data);
return cross(ccl_fetch(sd, N), normalize(cross(data, ccl_fetch(sd, N))));
@@ -138,7 +147,7 @@ ccl_device float3 primitive_tangent(KernelGlobals *kg, ShaderData *sd)
/* Motion vector for motion pass */
-ccl_device float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *sd)
+ccl_device_inline float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *sd)
{
/* center position */
float3 center;
@@ -158,19 +167,18 @@ ccl_device float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *sd)
float3 motion_pre = center, motion_post = center;
/* deformation motion */
- AttributeElement elem;
- int offset = find_attribute(kg, sd, ATTR_STD_MOTION_VERTEX_POSITION, &elem);
+ AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_MOTION_VERTEX_POSITION);
- if(offset != ATTR_STD_NOT_FOUND) {
+ if(desc.offset != ATTR_STD_NOT_FOUND) {
/* get motion info */
int numverts, numkeys;
object_motion_info(kg, ccl_fetch(sd, object), NULL, &numverts, &numkeys);
/* lookup attributes */
- int offset_next = (ccl_fetch(sd, type) & PRIMITIVE_ALL_TRIANGLE)? offset + numverts: offset + numkeys;
+ motion_pre = primitive_attribute_float3(kg, sd, desc, NULL, NULL);
- motion_pre = primitive_attribute_float3(kg, sd, elem, offset, NULL, NULL);
- motion_post = primitive_attribute_float3(kg, sd, elem, offset_next, NULL, NULL);
+ desc.offset += (ccl_fetch(sd, type) & PRIMITIVE_ALL_TRIANGLE)? numverts: numkeys;
+ motion_post = primitive_attribute_float3(kg, sd, desc, NULL, NULL);
#ifdef __HAIR__
if(is_curve_primitive && (ccl_fetch(sd, flag) & SD_OBJECT_HAS_VERTEX_MOTION) == 0) {
diff --git a/intern/cycles/kernel/geom/geom_qbvh.h b/intern/cycles/kernel/geom/geom_qbvh.h
deleted file mode 100644
index 2a2d7822eee..00000000000
--- a/intern/cycles/kernel/geom/geom_qbvh.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright 2011-2014, Blender Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-struct QBVHStackItem {
- int addr;
- float dist;
-};
-
-/* TOOD(sergey): Investigate if using intrinsics helps for both
- * stack item swap and float comparison.
- */
-ccl_device_inline void qbvh_item_swap(QBVHStackItem *__restrict a,
- QBVHStackItem *__restrict b)
-{
- QBVHStackItem tmp = *a;
- *a = *b;
- *b = tmp;
-}
-
-ccl_device_inline void qbvh_stack_sort(QBVHStackItem *__restrict s1,
- QBVHStackItem *__restrict s2,
- QBVHStackItem *__restrict s3)
-{
- if(s2->dist < s1->dist) { qbvh_item_swap(s2, s1); }
- if(s3->dist < s2->dist) { qbvh_item_swap(s3, s2); }
- if(s2->dist < s1->dist) { qbvh_item_swap(s2, s1); }
-}
-
-ccl_device_inline void qbvh_stack_sort(QBVHStackItem *__restrict s1,
- QBVHStackItem *__restrict s2,
- QBVHStackItem *__restrict s3,
- QBVHStackItem *__restrict s4)
-{
- if(s2->dist < s1->dist) { qbvh_item_swap(s2, s1); }
- if(s4->dist < s3->dist) { qbvh_item_swap(s4, s3); }
- if(s3->dist < s1->dist) { qbvh_item_swap(s3, s1); }
- if(s4->dist < s2->dist) { qbvh_item_swap(s4, s2); }
- if(s3->dist < s2->dist) { qbvh_item_swap(s3, s2); }
-}
-
-ccl_device_inline int qbvh_node_intersect(KernelGlobals *__restrict kg,
- const ssef& tnear,
- const ssef& tfar,
-#ifdef __KERNEL_AVX2__
- const sse3f& org_idir,
-#else
- const sse3f& org,
-#endif
- const sse3f& idir,
- const int near_x,
- const int near_y,
- const int near_z,
- const int far_x,
- const int far_y,
- const int far_z,
- const int nodeAddr,
- ssef *__restrict dist)
-{
- const int offset = nodeAddr*BVH_QNODE_SIZE;
-#ifdef __KERNEL_AVX2__
- const ssef tnear_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x), idir.x, org_idir.x);
- const ssef tnear_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y), idir.y, org_idir.y);
- const ssef tnear_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z), idir.z, org_idir.z);
- const ssef tfar_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x), idir.x, org_idir.x);
- const ssef tfar_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y), idir.y, org_idir.y);
- const ssef tfar_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z), idir.z, org_idir.z);
-#else
- const ssef tnear_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x) - org.x) * idir.x;
- const ssef tnear_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y) - org.y) * idir.y;
- const ssef tnear_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z) - org.z) * idir.z;
- const ssef tfar_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x) - org.x) * idir.x;
- const ssef tfar_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y) - org.y) * idir.y;
- const ssef tfar_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z) - org.z) * idir.z;
-#endif
-
-#ifdef __KERNEL_SSE41__
- const ssef tNear = maxi(maxi(tnear_x, tnear_y), maxi(tnear_z, tnear));
- const ssef tFar = mini(mini(tfar_x, tfar_y), mini(tfar_z, tfar));
- const sseb vmask = cast(tNear) > cast(tFar);
- int mask = (int)movemask(vmask)^0xf;
-#else
- const ssef tNear = max4(tnear_x, tnear_y, tnear_z, tnear);
- const ssef tFar = min4(tfar_x, tfar_y, tfar_z, tfar);
- const sseb vmask = tNear <= tFar;
- int mask = (int)movemask(vmask);
-#endif
- *dist = tNear;
- return mask;
-}
-
-ccl_device_inline int qbvh_node_intersect_robust(KernelGlobals *__restrict kg,
- const ssef& tnear,
- const ssef& tfar,
-#ifdef __KERNEL_AVX2__
- const sse3f& P_idir,
-#else
- const sse3f& P,
-#endif
- const sse3f& idir,
- const int near_x,
- const int near_y,
- const int near_z,
- const int far_x,
- const int far_y,
- const int far_z,
- const int nodeAddr,
- const float difl,
- ssef *__restrict dist)
-{
- const int offset = nodeAddr*BVH_QNODE_SIZE;
-#ifdef __KERNEL_AVX2__
- const ssef tnear_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x), idir.x, P_idir.x);
- const ssef tnear_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y), idir.y, P_idir.y);
- const ssef tnear_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z), idir.z, P_idir.z);
- const ssef tfar_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x), idir.x, P_idir.x);
- const ssef tfar_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y), idir.y, P_idir.y);
- const ssef tfar_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z), idir.z, P_idir.z);
-#else
- const ssef tnear_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x) - P.x) * idir.x;
- const ssef tnear_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y) - P.y) * idir.y;
- const ssef tnear_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z) - P.z) * idir.z;
- const ssef tfar_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x) - P.x) * idir.x;
- const ssef tfar_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y) - P.y) * idir.y;
- const ssef tfar_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z) - P.z) * idir.z;
-#endif
-
- const float round_down = 1.0f - difl;
- const float round_up = 1.0f + difl;
- const ssef tNear = max4(tnear_x, tnear_y, tnear_z, tnear);
- const ssef tFar = min4(tfar_x, tfar_y, tfar_z, tfar);
- const sseb vmask = round_down*tNear <= round_up*tFar;
- *dist = tNear;
- return (int)movemask(vmask);
-}
diff --git a/intern/cycles/kernel/geom/geom_qbvh_shadow.h b/intern/cycles/kernel/geom/geom_qbvh_shadow.h
deleted file mode 100644
index edb5b5c78c3..00000000000
--- a/intern/cycles/kernel/geom/geom_qbvh_shadow.h
+++ /dev/null
@@ -1,403 +0,0 @@
-/*
- * Adapted from code Copyright 2009-2010 NVIDIA Corporation,
- * and code copyright 2009-2012 Intel Corporation
- *
- * Modifications Copyright 2011-2014, Blender Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* This is a template BVH traversal function, where various features can be
- * enabled/disabled. This way we can compile optimized versions for each case
- * without new features slowing things down.
- *
- * BVH_INSTANCING: object instancing
- * BVH_HAIR: hair curve rendering
- * BVH_MOTION: motion blur rendering
- *
- */
-
-ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
- const Ray *ray,
- Intersection *isect_array,
- const uint max_hits,
- uint *num_hits)
-{
- /* TODO(sergey):
- * - Likely and unlikely for if() statements.
- * - Test restrict attribute for pointers.
- */
-
- /* Traversal stack in CUDA thread-local memory. */
- QBVHStackItem traversalStack[BVH_QSTACK_SIZE];
- traversalStack[0].addr = ENTRYPOINT_SENTINEL;
-
- /* Traversal variables in registers. */
- int stackPtr = 0;
- int nodeAddr = kernel_data.bvh.root;
-
- /* Ray parameters in registers. */
- const float tmax = ray->t;
- float3 P = ray->P;
- float3 dir = bvh_clamp_direction(ray->D);
- float3 idir = bvh_inverse_direction(dir);
- int object = OBJECT_NONE;
- float isect_t = tmax;
-
-#if BVH_FEATURE(BVH_MOTION)
- Transform ob_itfm;
-#endif
-
- *num_hits = 0;
- isect_array->t = tmax;
-
-#ifndef __KERNEL_SSE41__
- if(!isfinite(P.x)) {
- return false;
- }
-#endif
-
-#if BVH_FEATURE(BVH_INSTANCING)
- int num_hits_in_instance = 0;
-#endif
-
- ssef tnear(0.0f), tfar(tmax);
- sse3f idir4(ssef(idir.x), ssef(idir.y), ssef(idir.z));
-
-#ifdef __KERNEL_AVX2__
- float3 P_idir = P*idir;
- sse3f P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-#else
- sse3f org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
-#endif
-
- /* Offsets to select the side that becomes the lower or upper bound. */
- int near_x, near_y, near_z;
- int far_x, far_y, far_z;
-
- if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; }
- if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
- if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
-
- IsectPrecalc isect_precalc;
- triangle_intersect_precalc(dir, &isect_precalc);
-
- /* Traversal loop. */
- do {
- do {
- /* Traverse internal nodes. */
- while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) {
- ssef dist;
- int traverseChild = qbvh_node_intersect(kg,
- tnear,
- tfar,
-#ifdef __KERNEL_AVX2__
- P_idir4,
-#else
- org,
-#endif
- idir4,
- near_x, near_y, near_z,
- far_x, far_y, far_z,
- nodeAddr,
- &dist);
-
- if(traverseChild != 0) {
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_QNODE_SIZE+6);
-
- /* One child is hit, continue with that child. */
- int r = __bscf(traverseChild);
- if(traverseChild == 0) {
- nodeAddr = __float_as_int(cnodes[r]);
- continue;
- }
-
- /* Two children are hit, push far child, and continue with
- * closer child.
- */
- int c0 = __float_as_int(cnodes[r]);
- float d0 = ((float*)&dist)[r];
- r = __bscf(traverseChild);
- int c1 = __float_as_int(cnodes[r]);
- float d1 = ((float*)&dist)[r];
- if(traverseChild == 0) {
- if(d1 < d0) {
- nodeAddr = c1;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c0;
- traversalStack[stackPtr].dist = d0;
- continue;
- }
- else {
- nodeAddr = c0;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c1;
- traversalStack[stackPtr].dist = d1;
- continue;
- }
- }
-
- /* Here starts the slow path for 3 or 4 hit children. We push
- * all nodes onto the stack to sort them there.
- */
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c1;
- traversalStack[stackPtr].dist = d1;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c0;
- traversalStack[stackPtr].dist = d0;
-
- /* Three children are hit, push all onto stack and sort 3
- * stack items, continue with closest child.
- */
- r = __bscf(traverseChild);
- int c2 = __float_as_int(cnodes[r]);
- float d2 = ((float*)&dist)[r];
- if(traverseChild == 0) {
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c2;
- traversalStack[stackPtr].dist = d2;
- qbvh_stack_sort(&traversalStack[stackPtr],
- &traversalStack[stackPtr - 1],
- &traversalStack[stackPtr - 2]);
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
- continue;
- }
-
- /* Four children are hit, push all onto stack and sort 4
- * stack items, continue with closest child.
- */
- r = __bscf(traverseChild);
- int c3 = __float_as_int(cnodes[r]);
- float d3 = ((float*)&dist)[r];
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c3;
- traversalStack[stackPtr].dist = d3;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c2;
- traversalStack[stackPtr].dist = d2;
- qbvh_stack_sort(&traversalStack[stackPtr],
- &traversalStack[stackPtr - 1],
- &traversalStack[stackPtr - 2],
- &traversalStack[stackPtr - 3]);
- }
-
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
- }
-
- /* If node is leaf, fetch triangle list. */
- if(nodeAddr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_QNODE_LEAF_SIZE);
-#ifdef __VISIBILITY_FLAG__
- if((__float_as_uint(leaf.z) & PATH_RAY_SHADOW) == 0) {
- /* Pop. */
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
- continue;
- }
-#endif
-
- int primAddr = __float_as_int(leaf.x);
-
-#if BVH_FEATURE(BVH_INSTANCING)
- if(primAddr >= 0) {
-#endif
- int primAddr2 = __float_as_int(leaf.y);
- const uint type = __float_as_int(leaf.w);
- const uint p_type = type & PRIMITIVE_ALL;
-
- /* Pop. */
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
-
- /* Primitive intersection. */
- while(primAddr < primAddr2) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
-
- bool hit;
-
- /* todo: specialized intersect functions which don't fill in
- * isect unless needed and check SD_HAS_TRANSPARENT_SHADOW?
- * might give a few % performance improvement */
-
- switch(p_type) {
- case PRIMITIVE_TRIANGLE: {
- hit = triangle_intersect(kg, &isect_precalc, isect_array, P, PATH_RAY_SHADOW, object, primAddr);
- break;
- }
-#if BVH_FEATURE(BVH_MOTION)
- case PRIMITIVE_MOTION_TRIANGLE: {
- hit = motion_triangle_intersect(kg, isect_array, P, dir, ray->time, PATH_RAY_SHADOW, object, primAddr);
- break;
- }
-#endif
-#if BVH_FEATURE(BVH_HAIR)
- case PRIMITIVE_CURVE:
- case PRIMITIVE_MOTION_CURVE: {
- if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE)
- hit = bvh_cardinal_curve_intersect(kg, isect_array, P, dir, PATH_RAY_SHADOW, object, primAddr, ray->time, type, NULL, 0, 0);
- else
- hit = bvh_curve_intersect(kg, isect_array, P, dir, PATH_RAY_SHADOW, object, primAddr, ray->time, type, NULL, 0, 0);
- break;
- }
-#endif
- default: {
- hit = false;
- break;
- }
- }
-
- /* Shadow ray early termination. */
- if(hit) {
- /* detect if this surface has a shader with transparent shadows */
-
- /* todo: optimize so primitive visibility flag indicates if
- * the primitive has a transparent shadow shader? */
- int prim = kernel_tex_fetch(__prim_index, isect_array->prim);
- int shader = 0;
-
-#ifdef __HAIR__
- if(kernel_tex_fetch(__prim_type, isect_array->prim) & PRIMITIVE_ALL_TRIANGLE)
-#endif
- {
- shader = kernel_tex_fetch(__tri_shader, prim);
- }
-#ifdef __HAIR__
- else {
- float4 str = kernel_tex_fetch(__curves, prim);
- shader = __float_as_int(str.z);
- }
-#endif
- int flag = kernel_tex_fetch(__shader_flag, (shader & SHADER_MASK)*2);
-
- /* if no transparent shadows, all light is blocked */
- if(!(flag & SD_HAS_TRANSPARENT_SHADOW)) {
- return true;
- }
- /* if maximum number of hits reached, block all light */
- else if(*num_hits == max_hits) {
- return true;
- }
-
- /* move on to next entry in intersections array */
- isect_array++;
- (*num_hits)++;
-#if BVH_FEATURE(BVH_INSTANCING)
- num_hits_in_instance++;
-#endif
-
- isect_array->t = isect_t;
- }
-
- primAddr++;
- }
- }
-#if BVH_FEATURE(BVH_INSTANCING)
- else {
- /* Instance push. */
- object = kernel_tex_fetch(__prim_object, -primAddr-1);
-
-# if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect_t, &ob_itfm);
-# else
- bvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect_t);
-# endif
-
- num_hits_in_instance = 0;
- isect_array->t = isect_t;
-
- if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; }
- if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
- if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
- tfar = ssef(isect_t);
- idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
-# ifdef __KERNEL_AVX2__
- P_idir = P*idir;
- P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-# else
- org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
-# endif
- triangle_intersect_precalc(dir, &isect_precalc);
-
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = ENTRYPOINT_SENTINEL;
-
- nodeAddr = kernel_tex_fetch(__object_node, object);
-
- }
- }
-#endif /* FEATURE(BVH_INSTANCING) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
-
-#if BVH_FEATURE(BVH_INSTANCING)
- if(stackPtr >= 0) {
- kernel_assert(object != OBJECT_NONE);
-
- if(num_hits_in_instance) {
- float t_fac;
-
-# if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_pop_factor(kg, object, ray, &P, &dir, &idir, &t_fac, &ob_itfm);
-# else
- bvh_instance_pop_factor(kg, object, ray, &P, &dir, &idir, &t_fac);
-# endif
-
- /* scale isect->t to adjust for instancing */
- for(int i = 0; i < num_hits_in_instance; i++)
- (isect_array-i-1)->t *= t_fac;
- }
- else {
- float ignore_t = FLT_MAX;
-
-# if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &ignore_t, &ob_itfm);
-# else
- bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &ignore_t);
-# endif
- }
-
- isect_t = tmax;
- isect_array->t = isect_t;
-
- if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; }
- if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
- if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
- tfar = ssef(tmax);
- idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
-# ifdef __KERNEL_AVX2__
- P_idir = P*idir;
- P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-# else
- org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
-# endif
- triangle_intersect_precalc(dir, &isect_precalc);
-
- object = OBJECT_NONE;
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
- }
-#endif /* FEATURE(BVH_INSTANCING) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
-
- return false;
-}
diff --git a/intern/cycles/kernel/geom/geom_qbvh_traversal.h b/intern/cycles/kernel/geom/geom_qbvh_traversal.h
deleted file mode 100644
index ce3bbbdf957..00000000000
--- a/intern/cycles/kernel/geom/geom_qbvh_traversal.h
+++ /dev/null
@@ -1,425 +0,0 @@
-/*
- * Adapted from code Copyright 2009-2010 NVIDIA Corporation,
- * and code copyright 2009-2012 Intel Corporation
- *
- * Modifications Copyright 2011-2014, Blender Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* This is a template BVH traversal function, where various features can be
- * enabled/disabled. This way we can compile optimized versions for each case
- * without new features slowing things down.
- *
- * BVH_INSTANCING: object instancing
- * BVH_HAIR: hair curve rendering
- * BVH_HAIR_MINIMUM_WIDTH: hair curve rendering with minimum width
- * BVH_MOTION: motion blur rendering
- *
- */
-
-ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
- const Ray *ray,
- Intersection *isect,
- const uint visibility
-#if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH)
- ,uint *lcg_state,
- float difl,
- float extmax
-#endif
- )
-{
- /* TODO(sergey):
- * - Test if pushing distance on the stack helps (for non shadow rays).
- * - Separate version for shadow rays.
- * - Likely and unlikely for if() statements.
- * - Test restrict attribute for pointers.
- */
-
- /* Traversal stack in CUDA thread-local memory. */
- QBVHStackItem traversalStack[BVH_QSTACK_SIZE];
- traversalStack[0].addr = ENTRYPOINT_SENTINEL;
- traversalStack[0].dist = -FLT_MAX;
-
- /* Traversal variables in registers. */
- int stackPtr = 0;
- int nodeAddr = kernel_data.bvh.root;
- float nodeDist = -FLT_MAX;
-
- /* Ray parameters in registers. */
- float3 P = ray->P;
- float3 dir = bvh_clamp_direction(ray->D);
- float3 idir = bvh_inverse_direction(dir);
- int object = OBJECT_NONE;
-
-#if BVH_FEATURE(BVH_MOTION)
- Transform ob_itfm;
-#endif
-
-#ifndef __KERNEL_SSE41__
- if(!isfinite(P.x)) {
- return false;
- }
-#endif
-
- isect->t = ray->t;
- isect->u = 0.0f;
- isect->v = 0.0f;
- isect->prim = PRIM_NONE;
- isect->object = OBJECT_NONE;
-
-#if defined(__KERNEL_DEBUG__)
- isect->num_traversal_steps = 0;
- isect->num_traversed_instances = 0;
-#endif
-
- ssef tnear(0.0f), tfar(ray->t);
- sse3f idir4(ssef(idir.x), ssef(idir.y), ssef(idir.z));
-
-#ifdef __KERNEL_AVX2__
- float3 P_idir = P*idir;
- sse3f P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-#else
- sse3f org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
-#endif
-
- /* Offsets to select the side that becomes the lower or upper bound. */
- int near_x, near_y, near_z;
- int far_x, far_y, far_z;
-
- if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; }
- if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
- if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
-
- IsectPrecalc isect_precalc;
- triangle_intersect_precalc(dir, &isect_precalc);
-
- /* Traversal loop. */
- do {
- do {
- /* Traverse internal nodes. */
- while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) {
- if(UNLIKELY(nodeDist > isect->t)) {
- /* Pop. */
- nodeAddr = traversalStack[stackPtr].addr;
- nodeDist = traversalStack[stackPtr].dist;
- --stackPtr;
- continue;
- }
-
- int traverseChild;
- ssef dist;
-
-#if defined(__KERNEL_DEBUG__)
- isect->num_traversal_steps++;
-#endif
-
-#if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH)
- if(difl != 0.0f) {
- /* NOTE: We extend all the child BB instead of fetching
- * and checking visibility flags for each of the,
- *
- * Need to test if doing opposite would be any faster.
- */
- traverseChild = qbvh_node_intersect_robust(kg,
- tnear,
- tfar,
-# ifdef __KERNEL_AVX2__
- P_idir4,
-# else
- org,
-# endif
- idir4,
- near_x, near_y, near_z,
- far_x, far_y, far_z,
- nodeAddr,
- difl,
- &dist);
- }
- else
-#endif /* BVH_HAIR_MINIMUM_WIDTH */
- {
- traverseChild = qbvh_node_intersect(kg,
- tnear,
- tfar,
-#ifdef __KERNEL_AVX2__
- P_idir4,
-#else
- org,
-#endif
- idir4,
- near_x, near_y, near_z,
- far_x, far_y, far_z,
- nodeAddr,
- &dist);
- }
-
- if(traverseChild != 0) {
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_QNODE_SIZE+6);
-
- /* One child is hit, continue with that child. */
- int r = __bscf(traverseChild);
- float d0 = ((float*)&dist)[r];
- if(traverseChild == 0) {
- nodeAddr = __float_as_int(cnodes[r]);
- nodeDist = d0;
- continue;
- }
-
- /* Two children are hit, push far child, and continue with
- * closer child.
- */
- int c0 = __float_as_int(cnodes[r]);
- r = __bscf(traverseChild);
- int c1 = __float_as_int(cnodes[r]);
- float d1 = ((float*)&dist)[r];
- if(traverseChild == 0) {
- if(d1 < d0) {
- nodeAddr = c1;
- nodeDist = d1;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c0;
- traversalStack[stackPtr].dist = d0;
- continue;
- }
- else {
- nodeAddr = c0;
- nodeDist = d0;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c1;
- traversalStack[stackPtr].dist = d1;
- continue;
- }
- }
-
- /* Here starts the slow path for 3 or 4 hit children. We push
- * all nodes onto the stack to sort them there.
- */
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c1;
- traversalStack[stackPtr].dist = d1;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c0;
- traversalStack[stackPtr].dist = d0;
-
- /* Three children are hit, push all onto stack and sort 3
- * stack items, continue with closest child.
- */
- r = __bscf(traverseChild);
- int c2 = __float_as_int(cnodes[r]);
- float d2 = ((float*)&dist)[r];
- if(traverseChild == 0) {
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c2;
- traversalStack[stackPtr].dist = d2;
- qbvh_stack_sort(&traversalStack[stackPtr],
- &traversalStack[stackPtr - 1],
- &traversalStack[stackPtr - 2]);
- nodeAddr = traversalStack[stackPtr].addr;
- nodeDist = traversalStack[stackPtr].dist;
- --stackPtr;
- continue;
- }
-
- /* Four children are hit, push all onto stack and sort 4
- * stack items, continue with closest child.
- */
- r = __bscf(traverseChild);
- int c3 = __float_as_int(cnodes[r]);
- float d3 = ((float*)&dist)[r];
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c3;
- traversalStack[stackPtr].dist = d3;
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = c2;
- traversalStack[stackPtr].dist = d2;
- qbvh_stack_sort(&traversalStack[stackPtr],
- &traversalStack[stackPtr - 1],
- &traversalStack[stackPtr - 2],
- &traversalStack[stackPtr - 3]);
- }
-
- nodeAddr = traversalStack[stackPtr].addr;
- nodeDist = traversalStack[stackPtr].dist;
- --stackPtr;
- }
-
- /* If node is leaf, fetch triangle list. */
- if(nodeAddr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_QNODE_LEAF_SIZE);
-
-#ifdef __VISIBILITY_FLAG__
- if(UNLIKELY((nodeDist > isect->t) || ((__float_as_uint(leaf.z) & visibility) == 0)))
-#else
- if(UNLIKELY((nodeDist > isect->t)))
-#endif
- {
- /* Pop. */
- nodeAddr = traversalStack[stackPtr].addr;
- nodeDist = traversalStack[stackPtr].dist;
- --stackPtr;
- continue;
- }
-
- int primAddr = __float_as_int(leaf.x);
-
-#if BVH_FEATURE(BVH_INSTANCING)
- if(primAddr >= 0) {
-#endif
- int primAddr2 = __float_as_int(leaf.y);
- const uint type = __float_as_int(leaf.w);
-
- /* Pop. */
- nodeAddr = traversalStack[stackPtr].addr;
- nodeDist = traversalStack[stackPtr].dist;
- --stackPtr;
-
- /* Primitive intersection. */
- switch(type & PRIMITIVE_ALL) {
- case PRIMITIVE_TRIANGLE: {
- for(; primAddr < primAddr2; primAddr++) {
-#if defined(__KERNEL_DEBUG__)
- isect->num_traversal_steps++;
-#endif
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
- if(triangle_intersect(kg, &isect_precalc, isect, P, visibility, object, primAddr)) {
- tfar = ssef(isect->t);
- /* Shadow ray early termination. */
- if(visibility == PATH_RAY_SHADOW_OPAQUE)
- return true;
- }
- }
- break;
- }
-#if BVH_FEATURE(BVH_MOTION)
- case PRIMITIVE_MOTION_TRIANGLE: {
- for(; primAddr < primAddr2; primAddr++) {
-# if defined(__KERNEL_DEBUG__)
- isect->num_traversal_steps++;
-# endif
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
- if(motion_triangle_intersect(kg, isect, P, dir, ray->time, visibility, object, primAddr)) {
- tfar = ssef(isect->t);
- /* Shadow ray early termination. */
- if(visibility == PATH_RAY_SHADOW_OPAQUE)
- return true;
- }
- }
- break;
- }
-#endif /* BVH_FEATURE(BVH_MOTION) */
-#if BVH_FEATURE(BVH_HAIR)
- case PRIMITIVE_CURVE:
- case PRIMITIVE_MOTION_CURVE: {
- for(; primAddr < primAddr2; primAddr++) {
-# if defined(__KERNEL_DEBUG__)
- isect->num_traversal_steps++;
-# endif
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
- bool hit;
- if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE)
- hit = bvh_cardinal_curve_intersect(kg, isect, P, dir, visibility, object, primAddr, ray->time, type, lcg_state, difl, extmax);
- else
- hit = bvh_curve_intersect(kg, isect, P, dir, visibility, object, primAddr, ray->time, type, lcg_state, difl, extmax);
- if(hit) {
- tfar = ssef(isect->t);
- /* Shadow ray early termination. */
- if(visibility == PATH_RAY_SHADOW_OPAQUE)
- return true;
- }
- }
- break;
- }
-#endif /* BVH_FEATURE(BVH_HAIR) */
- }
- }
-#if BVH_FEATURE(BVH_INSTANCING)
- else {
- /* Instance push. */
- object = kernel_tex_fetch(__prim_object, -primAddr-1);
-
-# if BVH_FEATURE(BVH_MOTION)
- qbvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect->t, &nodeDist, &ob_itfm);
-# else
- qbvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect->t, &nodeDist);
-# endif
-
- if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; }
- if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
- if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
- tfar = ssef(isect->t);
- idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
-# ifdef __KERNEL_AVX2__
- P_idir = P*idir;
- P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-# else
- org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
-# endif
- triangle_intersect_precalc(dir, &isect_precalc);
-
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = ENTRYPOINT_SENTINEL;
- traversalStack[stackPtr].dist = -FLT_MAX;
-
- nodeAddr = kernel_tex_fetch(__object_node, object);
-
-# if defined(__KERNEL_DEBUG__)
- isect->num_traversed_instances++;
-# endif
- }
- }
-#endif /* FEATURE(BVH_INSTANCING) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
-
-#if BVH_FEATURE(BVH_INSTANCING)
- if(stackPtr >= 0) {
- kernel_assert(object != OBJECT_NONE);
-
- /* Instance pop. */
-# if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_itfm);
-# else
- bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &isect->t);
-# endif
-
- if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; }
- if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
- if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
- tfar = ssef(isect->t);
- idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
-# ifdef __KERNEL_AVX2__
- P_idir = P*idir;
- P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-# else
- org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
-# endif
- triangle_intersect_precalc(dir, &isect_precalc);
-
- object = OBJECT_NONE;
- nodeAddr = traversalStack[stackPtr].addr;
- nodeDist = traversalStack[stackPtr].dist;
- --stackPtr;
- }
-#endif /* FEATURE(BVH_INSTANCING) */
- } while(nodeAddr != ENTRYPOINT_SENTINEL);
-
- return (isect->prim != PRIM_NONE);
-}
diff --git a/intern/cycles/kernel/geom/geom_subd_triangle.h b/intern/cycles/kernel/geom/geom_subd_triangle.h
new file mode 100644
index 00000000000..647840dc696
--- /dev/null
+++ b/intern/cycles/kernel/geom/geom_subd_triangle.h
@@ -0,0 +1,355 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Functions for retrieving attributes on triangles produced from subdivision meshes */
+
+CCL_NAMESPACE_BEGIN
+
+/* Patch index for triangle, -1 if not subdivision triangle */
+
+ccl_device_inline uint subd_triangle_patch(KernelGlobals *kg, const ShaderData *sd)
+{
+ return (ccl_fetch(sd, prim) != PRIM_NONE) ? kernel_tex_fetch(__tri_patch, ccl_fetch(sd, prim)) : ~0;
+}
+
+/* UV coords of triangle within patch */
+
+ccl_device_inline void subd_triangle_patch_uv(KernelGlobals *kg, const ShaderData *sd, float2 uv[3])
+{
+ uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim));
+
+ uv[0] = kernel_tex_fetch(__tri_patch_uv, tri_vindex.x);
+ uv[1] = kernel_tex_fetch(__tri_patch_uv, tri_vindex.y);
+ uv[2] = kernel_tex_fetch(__tri_patch_uv, tri_vindex.z);
+}
+
+/* Vertex indices of patch */
+
+ccl_device_inline uint4 subd_triangle_patch_indices(KernelGlobals *kg, int patch)
+{
+ uint4 indices;
+
+ indices.x = kernel_tex_fetch(__patches, patch+0);
+ indices.y = kernel_tex_fetch(__patches, patch+1);
+ indices.z = kernel_tex_fetch(__patches, patch+2);
+ indices.w = kernel_tex_fetch(__patches, patch+3);
+
+ return indices;
+}
+
+/* Originating face for patch */
+
+ccl_device_inline uint subd_triangle_patch_face(KernelGlobals *kg, int patch)
+{
+ return kernel_tex_fetch(__patches, patch+4);
+}
+
+/* Number of corners on originating face */
+
+ccl_device_inline uint subd_triangle_patch_num_corners(KernelGlobals *kg, int patch)
+{
+ return kernel_tex_fetch(__patches, patch+5) & 0xffff;
+}
+
+/* Indices of the four corners that are used by the patch */
+
+ccl_device_inline void subd_triangle_patch_corners(KernelGlobals *kg, int patch, int corners[4])
+{
+ uint4 data;
+
+ data.x = kernel_tex_fetch(__patches, patch+4);
+ data.y = kernel_tex_fetch(__patches, patch+5);
+ data.z = kernel_tex_fetch(__patches, patch+6);
+ data.w = kernel_tex_fetch(__patches, patch+7);
+
+ int num_corners = data.y & 0xffff;
+
+ if(num_corners == 4) {
+ /* quad */
+ corners[0] = data.z;
+ corners[1] = data.z+1;
+ corners[2] = data.z+2;
+ corners[3] = data.z+3;
+ }
+ else {
+ /* ngon */
+ int c = data.y >> 16;
+
+ corners[0] = data.z + c;
+ corners[1] = data.z + mod(c+1, num_corners);
+ corners[2] = data.w;
+ corners[3] = data.z + mod(c-1, num_corners);
+ }
+}
+
+/* Reading attributes on various subdivision triangle elements */
+
+ccl_device_noinline float subd_triangle_attribute_float(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float *dx, float *dy)
+{
+ int patch = subd_triangle_patch(kg, sd);
+
+#ifdef __PATCH_EVAL__
+ if(desc.flags & ATTR_SUBDIVIDED) {
+ float2 uv[3];
+ subd_triangle_patch_uv(kg, sd, uv);
+
+ float2 dpdu = uv[0] - uv[2];
+ float2 dpdv = uv[1] - uv[2];
+
+ /* p is [s, t] */
+ float2 p = dpdu * ccl_fetch(sd, u) + dpdv * ccl_fetch(sd, v) + uv[2];
+
+ float a, dads, dadt;
+ a = patch_eval_float(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
+
+#ifdef __RAY_DIFFERENTIALS__
+ if(dx || dy) {
+ float dsdu = dpdu.x;
+ float dtdu = dpdu.y;
+ float dsdv = dpdv.x;
+ float dtdv = dpdv.y;
+
+ if(dx) {
+ float dudx = ccl_fetch(sd, du).dx;
+ float dvdx = ccl_fetch(sd, dv).dx;
+
+ float dsdx = dsdu*dudx + dsdv*dvdx;
+ float dtdx = dtdu*dudx + dtdv*dvdx;
+
+ *dx = dads*dsdx + dadt*dtdx;
+ }
+ if(dy) {
+ float dudy = ccl_fetch(sd, du).dy;
+ float dvdy = ccl_fetch(sd, dv).dy;
+
+ float dsdy = dsdu*dudy + dsdv*dvdy;
+ float dtdy = dtdu*dudy + dtdv*dvdy;
+
+ *dy = dads*dsdy + dadt*dtdy;
+ }
+ }
+#endif
+
+ return a;
+ }
+ else
+#endif /* __PATCH_EVAL__ */
+ if(desc.element == ATTR_ELEMENT_FACE) {
+ if(dx) *dx = 0.0f;
+ if(dy) *dy = 0.0f;
+
+ return kernel_tex_fetch(__attributes_float, desc.offset + subd_triangle_patch_face(kg, patch));
+ }
+ else if(desc.element == ATTR_ELEMENT_VERTEX || desc.element == ATTR_ELEMENT_VERTEX_MOTION) {
+ float2 uv[3];
+ subd_triangle_patch_uv(kg, sd, uv);
+
+ uint4 v = subd_triangle_patch_indices(kg, patch);
+
+ float f0 = kernel_tex_fetch(__attributes_float, desc.offset + v.x);
+ float f1 = kernel_tex_fetch(__attributes_float, desc.offset + v.y);
+ float f2 = kernel_tex_fetch(__attributes_float, desc.offset + v.z);
+ float f3 = kernel_tex_fetch(__attributes_float, desc.offset + v.w);
+
+ if(subd_triangle_patch_num_corners(kg, patch) != 4) {
+ f1 = (f1+f0)*0.5f;
+ f3 = (f3+f0)*0.5f;
+ }
+
+ float a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
+ float b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
+ float c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
+
+#ifdef __RAY_DIFFERENTIALS__
+ if(dx) *dx = ccl_fetch(sd, du).dx*a + ccl_fetch(sd, dv).dx*b - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*c;
+ if(dy) *dy = ccl_fetch(sd, du).dy*a + ccl_fetch(sd, dv).dy*b - (ccl_fetch(sd, du).dy + ccl_fetch(sd, dv).dy)*c;
+#endif
+
+ return ccl_fetch(sd, u)*a + ccl_fetch(sd, v)*b + (1.0f - ccl_fetch(sd, u) - ccl_fetch(sd, v))*c;
+ }
+ else if(desc.element == ATTR_ELEMENT_CORNER) {
+ float2 uv[3];
+ subd_triangle_patch_uv(kg, sd, uv);
+
+ int corners[4];
+ subd_triangle_patch_corners(kg, patch, corners);
+
+ float f0 = kernel_tex_fetch(__attributes_float, corners[0] + desc.offset);
+ float f1 = kernel_tex_fetch(__attributes_float, corners[1] + desc.offset);
+ float f2 = kernel_tex_fetch(__attributes_float, corners[2] + desc.offset);
+ float f3 = kernel_tex_fetch(__attributes_float, corners[3] + desc.offset);
+
+ if(subd_triangle_patch_num_corners(kg, patch) != 4) {
+ f1 = (f1+f0)*0.5f;
+ f3 = (f3+f0)*0.5f;
+ }
+
+ float a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
+ float b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
+ float c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
+
+#ifdef __RAY_DIFFERENTIALS__
+ if(dx) *dx = ccl_fetch(sd, du).dx*a + ccl_fetch(sd, dv).dx*b - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*c;
+ if(dy) *dy = ccl_fetch(sd, du).dy*a + ccl_fetch(sd, dv).dy*b - (ccl_fetch(sd, du).dy + ccl_fetch(sd, dv).dy)*c;
+#endif
+
+ return ccl_fetch(sd, u)*a + ccl_fetch(sd, v)*b + (1.0f - ccl_fetch(sd, u) - ccl_fetch(sd, v))*c;
+ }
+ else {
+ if(dx) *dx = 0.0f;
+ if(dy) *dy = 0.0f;
+
+ return 0.0f;
+ }
+}
+
+ccl_device_noinline float3 subd_triangle_attribute_float3(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float3 *dx, float3 *dy)
+{
+ int patch = subd_triangle_patch(kg, sd);
+
+#ifdef __PATCH_EVAL__
+ if(desc.flags & ATTR_SUBDIVIDED) {
+ float2 uv[3];
+ subd_triangle_patch_uv(kg, sd, uv);
+
+ float2 dpdu = uv[0] - uv[2];
+ float2 dpdv = uv[1] - uv[2];
+
+ /* p is [s, t] */
+ float2 p = dpdu * ccl_fetch(sd, u) + dpdv * ccl_fetch(sd, v) + uv[2];
+
+ float3 a, dads, dadt;
+
+ if(desc.element == ATTR_ELEMENT_CORNER_BYTE) {
+ a = patch_eval_uchar4(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
+ }
+ else {
+ a = patch_eval_float3(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
+ }
+
+#ifdef __RAY_DIFFERENTIALS__
+ if(dx || dy) {
+ float dsdu = dpdu.x;
+ float dtdu = dpdu.y;
+ float dsdv = dpdv.x;
+ float dtdv = dpdv.y;
+
+ if(dx) {
+ float dudx = ccl_fetch(sd, du).dx;
+ float dvdx = ccl_fetch(sd, dv).dx;
+
+ float dsdx = dsdu*dudx + dsdv*dvdx;
+ float dtdx = dtdu*dudx + dtdv*dvdx;
+
+ *dx = dads*dsdx + dadt*dtdx;
+ }
+ if(dy) {
+ float dudy = ccl_fetch(sd, du).dy;
+ float dvdy = ccl_fetch(sd, dv).dy;
+
+ float dsdy = dsdu*dudy + dsdv*dvdy;
+ float dtdy = dtdu*dudy + dtdv*dvdy;
+
+ *dy = dads*dsdy + dadt*dtdy;
+ }
+ }
+#endif
+
+ return a;
+ }
+ else
+#endif /* __PATCH_EVAL__ */
+ if(desc.element == ATTR_ELEMENT_FACE) {
+ if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
+ if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
+
+ return float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + subd_triangle_patch_face(kg, patch)));
+ }
+ else if(desc.element == ATTR_ELEMENT_VERTEX || desc.element == ATTR_ELEMENT_VERTEX_MOTION) {
+ float2 uv[3];
+ subd_triangle_patch_uv(kg, sd, uv);
+
+ uint4 v = subd_triangle_patch_indices(kg, patch);
+
+ float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + v.x));
+ float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + v.y));
+ float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + v.z));
+ float3 f3 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + v.w));
+
+ if(subd_triangle_patch_num_corners(kg, patch) != 4) {
+ f1 = (f1+f0)*0.5f;
+ f3 = (f3+f0)*0.5f;
+ }
+
+ float3 a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
+ float3 b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
+ float3 c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
+
+#ifdef __RAY_DIFFERENTIALS__
+ if(dx) *dx = ccl_fetch(sd, du).dx*a + ccl_fetch(sd, dv).dx*b - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*c;
+ if(dy) *dy = ccl_fetch(sd, du).dy*a + ccl_fetch(sd, dv).dy*b - (ccl_fetch(sd, du).dy + ccl_fetch(sd, dv).dy)*c;
+#endif
+
+ return ccl_fetch(sd, u)*a + ccl_fetch(sd, v)*b + (1.0f - ccl_fetch(sd, u) - ccl_fetch(sd, v))*c;
+ }
+ else if(desc.element == ATTR_ELEMENT_CORNER || desc.element == ATTR_ELEMENT_CORNER_BYTE) {
+ float2 uv[3];
+ subd_triangle_patch_uv(kg, sd, uv);
+
+ int corners[4];
+ subd_triangle_patch_corners(kg, patch, corners);
+
+ float3 f0, f1, f2, f3;
+
+ if(desc.element == ATTR_ELEMENT_CORNER) {
+ f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[0] + desc.offset));
+ f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[1] + desc.offset));
+ f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[2] + desc.offset));
+ f3 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[3] + desc.offset));
+ }
+ else {
+ f0 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[0] + desc.offset));
+ f1 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[1] + desc.offset));
+ f2 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[2] + desc.offset));
+ f3 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[3] + desc.offset));
+ }
+
+ if(subd_triangle_patch_num_corners(kg, patch) != 4) {
+ f1 = (f1+f0)*0.5f;
+ f3 = (f3+f0)*0.5f;
+ }
+
+ float3 a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
+ float3 b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
+ float3 c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
+
+#ifdef __RAY_DIFFERENTIALS__
+ if(dx) *dx = ccl_fetch(sd, du).dx*a + ccl_fetch(sd, dv).dx*b - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*c;
+ if(dy) *dy = ccl_fetch(sd, du).dy*a + ccl_fetch(sd, dv).dy*b - (ccl_fetch(sd, du).dy + ccl_fetch(sd, dv).dy)*c;
+#endif
+
+ return ccl_fetch(sd, u)*a + ccl_fetch(sd, v)*b + (1.0f - ccl_fetch(sd, u) - ccl_fetch(sd, v))*c;
+ }
+ else {
+ if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
+ if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
+
+ return make_float3(0.0f, 0.0f, 0.0f);
+ }
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/geom/geom_triangle.h b/intern/cycles/kernel/geom/geom_triangle.h
index 995dfac5b09..17538872ead 100644
--- a/intern/cycles/kernel/geom/geom_triangle.h
+++ b/intern/cycles/kernel/geom/geom_triangle.h
@@ -1,6 +1,5 @@
/*
- * Adapted from code Copyright 2009-2010 NVIDIA Corporation
- * Modifications Copyright 2011, Blender Foundation.
+ * Copyright 2011-2013 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,12 +26,11 @@ CCL_NAMESPACE_BEGIN
ccl_device_inline float3 triangle_normal(KernelGlobals *kg, ShaderData *sd)
{
/* load triangle vertices */
- float4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim));
+ const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim));
+ const float3 v0 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+0));
+ const float3 v1 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+1));
+ const float3 v2 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+2));
- float3 v0 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x)));
- float3 v1 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y)));
- float3 v2 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z)));
-
/* return normal */
if(ccl_fetch(sd, flag) & SD_NEGATIVE_SCALE_APPLIED)
return normalize(cross(v2 - v0, v1 - v0));
@@ -44,18 +42,17 @@ ccl_device_inline float3 triangle_normal(KernelGlobals *kg, ShaderData *sd)
ccl_device_inline void triangle_point_normal(KernelGlobals *kg, int object, int prim, float u, float v, float3 *P, float3 *Ng, int *shader)
{
/* load triangle vertices */
- float4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
-
- float3 v0 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x)));
- float3 v1 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y)));
- float3 v2 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z)));
+ const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
+ float3 v0 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+0));
+ float3 v1 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+1));
+ float3 v2 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+2));
/* compute point */
float t = 1.0f - u - v;
*P = (u*v0 + v*v1 + t*v2);
- /* get object flags, instance-aware */
- int object_flag = kernel_tex_fetch(__object_flag, object >= 0 ? object : ~object);
+ /* get object flags */
+ int object_flag = kernel_tex_fetch(__object_flag, object);
/* compute normal */
if(object_flag & SD_NEGATIVE_SCALE_APPLIED)
@@ -71,11 +68,10 @@ ccl_device_inline void triangle_point_normal(KernelGlobals *kg, int object, int
ccl_device_inline void triangle_vertices(KernelGlobals *kg, int prim, float3 P[3])
{
- float4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
-
- P[0] = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x)));
- P[1] = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y)));
- P[2] = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z)));
+ const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
+ P[0] = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+0));
+ P[1] = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+1));
+ P[2] = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+2));
}
/* Interpolate smooth vertex normal from vertices */
@@ -83,11 +79,10 @@ ccl_device_inline void triangle_vertices(KernelGlobals *kg, int prim, float3 P[3
ccl_device_inline float3 triangle_smooth_normal(KernelGlobals *kg, int prim, float u, float v)
{
/* load triangle vertices */
- float4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
-
- float3 n0 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.x)));
- float3 n1 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.y)));
- float3 n2 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.z)));
+ const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
+ float3 n0 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.x));
+ float3 n1 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.y));
+ float3 n2 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.z));
return normalize((1.0f - u - v)*n2 + u*n0 + v*n1);
}
@@ -97,11 +92,10 @@ ccl_device_inline float3 triangle_smooth_normal(KernelGlobals *kg, int prim, flo
ccl_device_inline void triangle_dPdudv(KernelGlobals *kg, int prim, ccl_addr_space float3 *dPdu, ccl_addr_space float3 *dPdv)
{
/* fetch triangle vertex coordinates */
- float4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
-
- float3 p0 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x)));
- float3 p1 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y)));
- float3 p2 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z)));
+ const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
+ const float3 p0 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+0));
+ const float3 p1 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+1));
+ const float3 p2 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+2));
/* compute derivatives of P w.r.t. uv */
*dPdu = (p0 - p2);
@@ -110,20 +104,20 @@ ccl_device_inline void triangle_dPdudv(KernelGlobals *kg, int prim, ccl_addr_spa
/* Reading attributes on various triangle elements */
-ccl_device float triangle_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy)
+ccl_device float triangle_attribute_float(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float *dx, float *dy)
{
- if(elem == ATTR_ELEMENT_FACE) {
+ if(desc.element == ATTR_ELEMENT_FACE) {
if(dx) *dx = 0.0f;
if(dy) *dy = 0.0f;
- return kernel_tex_fetch(__attributes_float, offset + ccl_fetch(sd, prim));
+ return kernel_tex_fetch(__attributes_float, desc.offset + ccl_fetch(sd, prim));
}
- else if(elem == ATTR_ELEMENT_VERTEX || elem == ATTR_ELEMENT_VERTEX_MOTION) {
- float4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim));
+ else if(desc.element == ATTR_ELEMENT_VERTEX || desc.element == ATTR_ELEMENT_VERTEX_MOTION) {
+ uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim));
- float f0 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.x));
- float f1 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.y));
- float f2 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.z));
+ float f0 = kernel_tex_fetch(__attributes_float, desc.offset + tri_vindex.x);
+ float f1 = kernel_tex_fetch(__attributes_float, desc.offset + tri_vindex.y);
+ float f2 = kernel_tex_fetch(__attributes_float, desc.offset + tri_vindex.z);
#ifdef __RAY_DIFFERENTIALS__
if(dx) *dx = ccl_fetch(sd, du).dx*f0 + ccl_fetch(sd, dv).dx*f1 - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*f2;
@@ -132,8 +126,8 @@ ccl_device float triangle_attribute_float(KernelGlobals *kg, const ShaderData *s
return ccl_fetch(sd, u)*f0 + ccl_fetch(sd, v)*f1 + (1.0f - ccl_fetch(sd, u) - ccl_fetch(sd, v))*f2;
}
- else if(elem == ATTR_ELEMENT_CORNER) {
- int tri = offset + ccl_fetch(sd, prim)*3;
+ else if(desc.element == ATTR_ELEMENT_CORNER) {
+ int tri = desc.offset + ccl_fetch(sd, prim)*3;
float f0 = kernel_tex_fetch(__attributes_float, tri + 0);
float f1 = kernel_tex_fetch(__attributes_float, tri + 1);
float f2 = kernel_tex_fetch(__attributes_float, tri + 2);
@@ -153,20 +147,20 @@ ccl_device float triangle_attribute_float(KernelGlobals *kg, const ShaderData *s
}
}
-ccl_device float3 triangle_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy)
+ccl_device float3 triangle_attribute_float3(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float3 *dx, float3 *dy)
{
- if(elem == ATTR_ELEMENT_FACE) {
+ if(desc.element == ATTR_ELEMENT_FACE) {
if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
- return float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + ccl_fetch(sd, prim)));
+ return float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + ccl_fetch(sd, prim)));
}
- else if(elem == ATTR_ELEMENT_VERTEX || elem == ATTR_ELEMENT_VERTEX_MOTION) {
- float4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim));
+ else if(desc.element == ATTR_ELEMENT_VERTEX || desc.element == ATTR_ELEMENT_VERTEX_MOTION) {
+ uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim));
- float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.x)));
- float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.y)));
- float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.z)));
+ float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + tri_vindex.x));
+ float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + tri_vindex.y));
+ float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + tri_vindex.z));
#ifdef __RAY_DIFFERENTIALS__
if(dx) *dx = ccl_fetch(sd, du).dx*f0 + ccl_fetch(sd, dv).dx*f1 - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*f2;
@@ -175,11 +169,11 @@ ccl_device float3 triangle_attribute_float3(KernelGlobals *kg, const ShaderData
return ccl_fetch(sd, u)*f0 + ccl_fetch(sd, v)*f1 + (1.0f - ccl_fetch(sd, u) - ccl_fetch(sd, v))*f2;
}
- else if(elem == ATTR_ELEMENT_CORNER || elem == ATTR_ELEMENT_CORNER_BYTE) {
- int tri = offset + ccl_fetch(sd, prim)*3;
+ else if(desc.element == ATTR_ELEMENT_CORNER || desc.element == ATTR_ELEMENT_CORNER_BYTE) {
+ int tri = desc.offset + ccl_fetch(sd, prim)*3;
float3 f0, f1, f2;
- if(elem == ATTR_ELEMENT_CORNER) {
+ if(desc.element == ATTR_ELEMENT_CORNER) {
f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 0));
f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 1));
f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 2));
diff --git a/intern/cycles/kernel/geom/geom_triangle_intersect.h b/intern/cycles/kernel/geom/geom_triangle_intersect.h
index d2957ad5474..eb7340583c8 100644
--- a/intern/cycles/kernel/geom/geom_triangle_intersect.h
+++ b/intern/cycles/kernel/geom/geom_triangle_intersect.h
@@ -59,21 +59,33 @@ void triangle_intersect_precalc(float3 dir,
IsectPrecalc *isect_precalc)
{
/* Calculate dimension where the ray direction is maximal. */
+#ifndef __KERNEL_SSE__
int kz = util_max_axis(make_float3(fabsf(dir.x),
fabsf(dir.y),
fabsf(dir.z)));
int kx = kz + 1; if(kx == 3) kx = 0;
int ky = kx + 1; if(ky == 3) ky = 0;
+#else
+ int kx, ky, kz;
+ /* Avoiding mispredicted branch on direction. */
+ kz = util_max_axis(fabs(dir));
+ static const char inc_xaxis[] = {1, 2, 0, 55};
+ static const char inc_yaxis[] = {2, 0, 1, 55};
+ kx = inc_xaxis[kz];
+ ky = inc_yaxis[kz];
+#endif
+
+ float dir_kz = IDX(dir, kz);
/* Swap kx and ky dimensions to preserve winding direction of triangles. */
- if(IDX(dir, kz) < 0.0f) {
+ if(dir_kz < 0.0f) {
int tmp = kx;
kx = ky;
ky = tmp;
}
/* Calculate the shear constants. */
- float inv_dir_z = 1.0f / IDX(dir, kz);
+ float inv_dir_z = 1.0f / dir_kz;
isect_precalc->Sx = IDX(dir, kx) * inv_dir_z;
isect_precalc->Sy = IDX(dir, ky) * inv_dir_z;
isect_precalc->Sz = inv_dir_z;
@@ -106,9 +118,71 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg,
const float Sz = isect_precalc->Sz;
/* Calculate vertices relative to ray origin. */
- const float4 tri_a = kernel_tex_fetch(__tri_storage, triAddr*TRI_NODE_SIZE+0),
- tri_b = kernel_tex_fetch(__tri_storage, triAddr*TRI_NODE_SIZE+1),
- tri_c = kernel_tex_fetch(__tri_storage, triAddr*TRI_NODE_SIZE+2);
+ const uint tri_vindex = kernel_tex_fetch(__prim_tri_index, triAddr);
+
+#if defined(__KERNEL_AVX2__) && defined(__KERNEL_SSE__)
+ const avxf avxf_P(P.m128, P.m128);
+
+ const avxf tri_ab = kernel_tex_fetch_avxf(__prim_tri_verts, tri_vindex + 0);
+ const avxf tri_bc = kernel_tex_fetch_avxf(__prim_tri_verts, tri_vindex + 1);
+
+ const avxf AB = tri_ab - avxf_P;
+ const avxf BC = tri_bc - avxf_P;
+
+ const __m256i permuteMask = _mm256_set_epi32(0x3, kz, ky, kx, 0x3, kz, ky, kx);
+
+ const avxf AB_k = shuffle(AB, permuteMask);
+ const avxf BC_k = shuffle(BC, permuteMask);
+
+ /* Akz, Akz, Bkz, Bkz, Bkz, Bkz, Ckz, Ckz */
+ const avxf ABBC_kz = shuffle<2>(AB_k, BC_k);
+
+ /* Akx, Aky, Bkx, Bky, Bkx,Bky, Ckx, Cky */
+ const avxf ABBC_kxy = shuffle<0,1,0,1>(AB_k, BC_k);
+
+ const avxf Sxy(Sy, Sx, Sy, Sx);
+
+ /* Ax, Ay, Bx, By, Bx, By, Cx, Cy */
+ const avxf ABBC_xy = nmadd(ABBC_kz, Sxy, ABBC_kxy);
+
+ float ABBC_kz_array[8];
+ _mm256_storeu_ps((float*)&ABBC_kz_array, ABBC_kz);
+
+ const float A_kz = ABBC_kz_array[0];
+ const float B_kz = ABBC_kz_array[2];
+ const float C_kz = ABBC_kz_array[6];
+
+ /* By, Bx, Cy, Cx, By, Bx, Ay, Ax */
+ const avxf BCBA_yx = permute<3,2,7,6,3,2,1,0>(ABBC_xy);
+
+ const avxf negMask(0,0,0,0,0x80000000, 0x80000000, 0x80000000, 0x80000000);
+
+ /* W U V
+ * (AxBy-AyBx) (BxCy-ByCx) XX XX (BxBy-ByBx) (CxAy-CyAx) XX XX
+ */
+ const avxf WUxxxxVxx_neg = _mm256_hsub_ps(ABBC_xy * BCBA_yx, negMask /* Dont care */);
+
+ const avxf WUVWnegWUVW = permute<0,1,5,0,0,1,5,0>(WUxxxxVxx_neg) ^ negMask;
+
+ /* Calculate scaled barycentric coordinates. */
+ float WUVW_array[4];
+ _mm_storeu_ps((float*)&WUVW_array, _mm256_castps256_ps128 (WUVWnegWUVW));
+
+ const float W = WUVW_array[0];
+ const float U = WUVW_array[1];
+ const float V = WUVW_array[2];
+
+ const int WUVW_mask = 0x7 & _mm256_movemask_ps(WUVWnegWUVW);
+ const int WUVW_zero = 0x7 & _mm256_movemask_ps(_mm256_cmp_ps(WUVWnegWUVW,
+ _mm256_setzero_ps(), 0));
+
+ if(!((WUVW_mask == 7) || (WUVW_mask == 0)) && ((WUVW_mask | WUVW_zero) != 7)) {
+ return false;
+ }
+#else
+ const float4 tri_a = kernel_tex_fetch(__prim_tri_verts, tri_vindex+0),
+ tri_b = kernel_tex_fetch(__prim_tri_verts, tri_vindex+1),
+ tri_c = kernel_tex_fetch(__prim_tri_verts, tri_vindex+2);
const float3 A = make_float3(tri_a.x - P.x, tri_a.y - P.y, tri_a.z - P.z);
const float3 B = make_float3(tri_b.x - P.x, tri_b.y - P.y, tri_b.z - P.z);
const float3 C = make_float3(tri_c.x - P.x, tri_c.y - P.y, tri_c.z - P.z);
@@ -134,6 +208,7 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg,
{
return false;
}
+#endif
/* Calculate determinant. */
float det = U + V + W;
@@ -159,16 +234,11 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg,
if(kernel_tex_fetch(__prim_visibility, triAddr) & visibility)
#endif
{
-#ifdef __KERNEL_GPU__
- float4 a = tri_b - tri_a, b = tri_c - tri_a;
- if(len_squared(make_float3(a.y*b.z - a.z*b.y,
- a.z*b.x - a.x*b.z,
- a.x*b.y - a.y*b.x)) == 0.0f)
- {
+#ifdef __KERNEL_CUDA__
+ if(A == B && B == C) {
return false;
}
#endif
-
/* Normalize U, V, W, and T. */
const float inv_det = 1.0f / det;
isect->prim = triAddr;
@@ -207,9 +277,71 @@ ccl_device_inline void triangle_intersect_subsurface(
const float Sz = isect_precalc->Sz;
/* Calculate vertices relative to ray origin. */
- const float4 tri_a = kernel_tex_fetch(__tri_storage, triAddr*TRI_NODE_SIZE+0),
- tri_b = kernel_tex_fetch(__tri_storage, triAddr*TRI_NODE_SIZE+1),
- tri_c = kernel_tex_fetch(__tri_storage, triAddr*TRI_NODE_SIZE+2);
+ const uint tri_vindex = kernel_tex_fetch(__prim_tri_index, triAddr);
+ const float4 tri_a = kernel_tex_fetch(__prim_tri_verts, tri_vindex+0),
+ tri_b = kernel_tex_fetch(__prim_tri_verts, tri_vindex+1),
+ tri_c = kernel_tex_fetch(__prim_tri_verts, tri_vindex+2);
+
+#if defined(__KERNEL_AVX2__) && defined(__KERNEL_SSE__)
+ const avxf avxf_P(P.m128, P.m128);
+
+ const avxf tri_ab = kernel_tex_fetch_avxf(__prim_tri_verts, tri_vindex + 0);
+ const avxf tri_bc = kernel_tex_fetch_avxf(__prim_tri_verts, tri_vindex + 1);
+
+ const avxf AB = tri_ab - avxf_P;
+ const avxf BC = tri_bc - avxf_P;
+
+ const __m256i permuteMask = _mm256_set_epi32(0x3, kz, ky, kx, 0x3, kz, ky, kx);
+
+ const avxf AB_k = shuffle(AB, permuteMask);
+ const avxf BC_k = shuffle(BC, permuteMask);
+
+ /* Akz, Akz, Bkz, Bkz, Bkz, Bkz, Ckz, Ckz */
+ const avxf ABBC_kz = shuffle<2>(AB_k, BC_k);
+
+ /* Akx, Aky, Bkx, Bky, Bkx,Bky, Ckx, Cky */
+ const avxf ABBC_kxy = shuffle<0,1,0,1>(AB_k, BC_k);
+
+ const avxf Sxy(Sy, Sx, Sy, Sx);
+
+ /* Ax, Ay, Bx, By, Bx, By, Cx, Cy */
+ const avxf ABBC_xy = nmadd(ABBC_kz, Sxy, ABBC_kxy);
+
+ float ABBC_kz_array[8];
+ _mm256_storeu_ps((float*)&ABBC_kz_array, ABBC_kz);
+
+ const float A_kz = ABBC_kz_array[0];
+ const float B_kz = ABBC_kz_array[2];
+ const float C_kz = ABBC_kz_array[6];
+
+ /* By, Bx, Cy, Cx, By, Bx, Ay, Ax */
+ const avxf BCBA_yx = permute<3,2,7,6,3,2,1,0>(ABBC_xy);
+
+ const avxf negMask(0,0,0,0,0x80000000, 0x80000000, 0x80000000, 0x80000000);
+
+ /* W U V
+ * (AxBy-AyBx) (BxCy-ByCx) XX XX (BxBy-ByBx) (CxAy-CyAx) XX XX
+ */
+ const avxf WUxxxxVxx_neg = _mm256_hsub_ps(ABBC_xy * BCBA_yx, negMask /* Dont care */);
+
+ const avxf WUVWnegWUVW = permute<0,1,5,0,0,1,5,0>(WUxxxxVxx_neg) ^ negMask;
+
+ /* Calculate scaled barycentric coordinates. */
+ float WUVW_array[4];
+ _mm_storeu_ps((float*)&WUVW_array, _mm256_castps256_ps128 (WUVWnegWUVW));
+
+ const float W = WUVW_array[0];
+ const float U = WUVW_array[1];
+ const float V = WUVW_array[2];
+
+ const int WUVW_mask = 0x7 & _mm256_movemask_ps(WUVWnegWUVW);
+ const int WUVW_zero = 0x7 & _mm256_movemask_ps(_mm256_cmp_ps(WUVWnegWUVW,
+ _mm256_setzero_ps(), 0));
+
+ if(!((WUVW_mask == 7) || (WUVW_mask == 0)) && ((WUVW_mask | WUVW_zero) != 7)) {
+ return;
+ }
+#else
const float3 A = make_float3(tri_a.x - P.x, tri_a.y - P.y, tri_a.z - P.z);
const float3 B = make_float3(tri_b.x - P.x, tri_b.y - P.y, tri_b.z - P.z);
const float3 C = make_float3(tri_c.x - P.x, tri_c.y - P.y, tri_c.z - P.z);
@@ -236,6 +368,7 @@ ccl_device_inline void triangle_intersect_subsurface(
{
return;
}
+#endif
/* Calculate determinant. */
float det = U + V + W;
@@ -258,6 +391,13 @@ ccl_device_inline void triangle_intersect_subsurface(
/* Normalize U, V, W, and T. */
const float inv_det = 1.0f / det;
+ const float t = T * inv_det;
+ for(int i = min(max_hits, ss_isect->num_hits) - 1; i >= 0; --i) {
+ if(ss_isect->hits[i].t == t) {
+ return;
+ }
+ }
+
ss_isect->num_hits++;
int hit;
@@ -280,7 +420,7 @@ ccl_device_inline void triangle_intersect_subsurface(
isect->type = PRIMITIVE_TRIANGLE;
isect->u = U * inv_det;
isect->v = V * inv_det;
- isect->t = T * inv_det;
+ isect->t = t;
/* Record geometric normal. */
/* TODO(sergey): Use float4_to_float3() on just an edges. */
@@ -329,17 +469,25 @@ ccl_device_inline float3 triangle_refine(KernelGlobals *kg,
P = P + D*t;
- const float4 tri_a = kernel_tex_fetch(__tri_storage, isect->prim*TRI_NODE_SIZE+0),
- tri_b = kernel_tex_fetch(__tri_storage, isect->prim*TRI_NODE_SIZE+1),
- tri_c = kernel_tex_fetch(__tri_storage, isect->prim*TRI_NODE_SIZE+2);
+ const uint tri_vindex = kernel_tex_fetch(__prim_tri_index, isect->prim);
+ const float4 tri_a = kernel_tex_fetch(__prim_tri_verts, tri_vindex+0),
+ tri_b = kernel_tex_fetch(__prim_tri_verts, tri_vindex+1),
+ tri_c = kernel_tex_fetch(__prim_tri_verts, tri_vindex+2);
float3 edge1 = make_float3(tri_a.x - tri_c.x, tri_a.y - tri_c.y, tri_a.z - tri_c.z);
float3 edge2 = make_float3(tri_b.x - tri_c.x, tri_b.y - tri_c.y, tri_b.z - tri_c.z);
float3 tvec = make_float3(P.x - tri_c.x, P.y - tri_c.y, P.z - tri_c.z);
float3 qvec = cross(tvec, edge1);
float3 pvec = cross(D, edge2);
- float rt = dot(edge2, qvec) / dot(edge1, pvec);
-
- P = P + D*rt;
+ float det = dot(edge1, pvec);
+ if(det != 0.0f) {
+ /* If determinant is zero it means ray lies in the plane of
+ * the triangle. It is possible in theory due to watertight
+ * nature of triangle intersection. For such cases we simply
+ * don't refine intersection hoping it'll go all fine.
+ */
+ float rt = dot(edge2, qvec) / det;
+ P = P + D*rt;
+ }
if(isect->object != OBJECT_NONE) {
# ifdef __OBJECT_MOTION__
@@ -386,17 +534,25 @@ ccl_device_inline float3 triangle_refine_subsurface(KernelGlobals *kg,
P = P + D*t;
#ifdef __INTERSECTION_REFINE__
- const float4 tri_a = kernel_tex_fetch(__tri_storage, isect->prim*TRI_NODE_SIZE+0),
- tri_b = kernel_tex_fetch(__tri_storage, isect->prim*TRI_NODE_SIZE+1),
- tri_c = kernel_tex_fetch(__tri_storage, isect->prim*TRI_NODE_SIZE+2);
+ const uint tri_vindex = kernel_tex_fetch(__prim_tri_index, isect->prim);
+ const float4 tri_a = kernel_tex_fetch(__prim_tri_verts, tri_vindex+0),
+ tri_b = kernel_tex_fetch(__prim_tri_verts, tri_vindex+1),
+ tri_c = kernel_tex_fetch(__prim_tri_verts, tri_vindex+2);
float3 edge1 = make_float3(tri_a.x - tri_c.x, tri_a.y - tri_c.y, tri_a.z - tri_c.z);
float3 edge2 = make_float3(tri_b.x - tri_c.x, tri_b.y - tri_c.y, tri_b.z - tri_c.z);
float3 tvec = make_float3(P.x - tri_c.x, P.y - tri_c.y, P.z - tri_c.z);
float3 qvec = cross(tvec, edge1);
float3 pvec = cross(D, edge2);
- float rt = dot(edge2, qvec) / dot(edge1, pvec);
-
- P = P + D*rt;
+ float det = dot(edge1, pvec);
+ if(det != 0.0f) {
+ /* If determinant is zero it means ray lies in the plane of
+ * the triangle. It is possible in theory due to watertight
+ * nature of triangle intersection. For such cases we simply
+ * don't refine intersection hoping it'll go all fine.
+ */
+ float rt = dot(edge2, qvec) / det;
+ P = P + D*rt;
+ }
#endif /* __INTERSECTION_REFINE__ */
if(isect->object != OBJECT_NONE) {
diff --git a/intern/cycles/kernel/geom/geom_volume.h b/intern/cycles/kernel/geom/geom_volume.h
index 7bd3933a1f8..03724c955be 100644
--- a/intern/cycles/kernel/geom/geom_volume.h
+++ b/intern/cycles/kernel/geom/geom_volume.h
@@ -29,7 +29,7 @@ CCL_NAMESPACE_BEGIN
/* Return position normalized to 0..1 in mesh bounds */
-#ifdef __KERNEL_GPU__
+#if defined(__KERNEL_CUDA__) && __CUDA_ARCH__ < 300
ccl_device float4 volume_image_texture_3d(int id, float x, float y, float z)
{
float4 r;
@@ -42,56 +42,71 @@ ccl_device float4 volume_image_texture_3d(int id, float x, float y, float z)
}
return r;
}
-#endif /* __KERNEL_GPU__ */
+#endif /* __KERNEL_CUDA__ */
-ccl_device float3 volume_normalized_position(KernelGlobals *kg, const ShaderData *sd, float3 P)
+ccl_device_inline float3 volume_normalized_position(KernelGlobals *kg,
+ const ShaderData *sd,
+ float3 P)
{
/* todo: optimize this so it's just a single matrix multiplication when
* possible (not motion blur), or perhaps even just translation + scale */
- AttributeElement attr_elem;
- int attr_offset = find_attribute(kg, sd, ATTR_STD_GENERATED_TRANSFORM, &attr_elem);
+ const AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_GENERATED_TRANSFORM);
object_inverse_position_transform(kg, sd, &P);
- if(attr_offset != ATTR_STD_NOT_FOUND) {
- Transform tfm = primitive_attribute_matrix(kg, sd, attr_offset);
+ if(desc.offset != ATTR_STD_NOT_FOUND) {
+ Transform tfm = primitive_attribute_matrix(kg, sd, desc);
P = transform_point(&tfm, P);
}
return P;
}
-ccl_device float volume_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int id, float *dx, float *dy)
+ccl_device float volume_attribute_float(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float *dx, float *dy)
{
- float3 P = volume_normalized_position(kg, sd, sd->P);
-#ifdef __KERNEL_GPU__
- float4 r = volume_image_texture_3d(id, P.x, P.y, P.z);
+ float3 P = volume_normalized_position(kg, sd, ccl_fetch(sd, P));
+#ifdef __KERNEL_CUDA__
+# if __CUDA_ARCH__ >= 300
+ CUtexObject tex = kernel_tex_fetch(__bindless_mapping, desc.offset);
+ float f = kernel_tex_image_interp_3d_float(tex, P.x, P.y, P.z);
+ float4 r = make_float4(f, f, f, 1.0f);
+# else
+ float4 r = volume_image_texture_3d(desc.offset, P.x, P.y, P.z);
+# endif
+#elif defined(__KERNEL_OPENCL__)
+ float4 r = kernel_tex_image_interp_3d(kg, desc.offset, P.x, P.y, P.z);
#else
float4 r;
if(sd->flag & SD_VOLUME_CUBIC)
- r = kernel_tex_image_interp_3d_ex(id, P.x, P.y, P.z, INTERPOLATION_CUBIC);
+ r = kernel_tex_image_interp_3d_ex(desc.offset, P.x, P.y, P.z, INTERPOLATION_CUBIC);
else
- r = kernel_tex_image_interp_3d(id, P.x, P.y, P.z);
+ r = kernel_tex_image_interp_3d(desc.offset, P.x, P.y, P.z);
#endif
if(dx) *dx = 0.0f;
if(dy) *dy = 0.0f;
- /* todo: support float textures to lower memory usage for single floats */
return average(float4_to_float3(r));
}
-ccl_device float3 volume_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int id, float3 *dx, float3 *dy)
+ccl_device float3 volume_attribute_float3(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float3 *dx, float3 *dy)
{
- float3 P = volume_normalized_position(kg, sd, sd->P);
-#ifdef __KERNEL_GPU__
- float4 r = volume_image_texture_3d(id, P.x, P.y, P.z);
+ float3 P = volume_normalized_position(kg, sd, ccl_fetch(sd, P));
+#ifdef __KERNEL_CUDA__
+# if __CUDA_ARCH__ >= 300
+ CUtexObject tex = kernel_tex_fetch(__bindless_mapping, desc.offset);
+ float4 r = kernel_tex_image_interp_3d_float4(tex, P.x, P.y, P.z);
+# else
+ float4 r = volume_image_texture_3d(desc.offset, P.x, P.y, P.z);
+# endif
+#elif defined(__KERNEL_OPENCL__)
+ float4 r = kernel_tex_image_interp_3d(kg, desc.offset, P.x, P.y, P.z);
#else
float4 r;
if(sd->flag & SD_VOLUME_CUBIC)
- r = kernel_tex_image_interp_3d_ex(id, P.x, P.y, P.z, INTERPOLATION_CUBIC);
+ r = kernel_tex_image_interp_3d_ex(desc.offset, P.x, P.y, P.z, INTERPOLATION_CUBIC);
else
- r = kernel_tex_image_interp_3d(id, P.x, P.y, P.z);
+ r = kernel_tex_image_interp_3d(desc.offset, P.x, P.y, P.z);
#endif
if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
diff --git a/intern/cycles/kernel/kernel_accumulate.h b/intern/cycles/kernel/kernel_accumulate.h
index 5f5a3609ded..623c1dcaaa1 100644
--- a/intern/cycles/kernel/kernel_accumulate.h
+++ b/intern/cycles/kernel/kernel_accumulate.h
@@ -48,19 +48,13 @@ ccl_device_inline void bsdf_eval_init(BsdfEval *eval, ClosureType type, float3 v
eval->scatter = value;
}
else
- eval->diffuse = value;
-#else
- *eval = value;
#endif
+ {
+ eval->diffuse = value;
+ }
}
-/* TODO(sergey): This is just a workaround for annoying 6.5 compiler bug. */
-#if !defined(__KERNEL_CUDA__) || __CUDA_ARCH__ < 500
-ccl_device_inline
-#else
-ccl_device_noinline
-#endif
-void bsdf_eval_accum(BsdfEval *eval, ClosureType type, float3 value)
+ccl_device_inline void bsdf_eval_accum(BsdfEval *eval, ClosureType type, float3 value)
{
#ifdef __PASSES__
if(eval->use_light_pass) {
@@ -78,10 +72,10 @@ void bsdf_eval_accum(BsdfEval *eval, ClosureType type, float3 value)
/* skipping transparent, this function is used by for eval(), will be zero then */
}
else
- eval->diffuse += value;
-#else
- *eval += value;
#endif
+ {
+ eval->diffuse += value;
+ }
}
ccl_device_inline bool bsdf_eval_is_zero(BsdfEval *eval)
@@ -96,10 +90,10 @@ ccl_device_inline bool bsdf_eval_is_zero(BsdfEval *eval)
&& is_zero(eval->scatter);
}
else
- return is_zero(eval->diffuse);
-#else
- return is_zero(*eval);
#endif
+ {
+ return is_zero(eval->diffuse);
+ }
}
ccl_device_inline void bsdf_eval_mul(BsdfEval *eval, float3 value)
@@ -115,10 +109,10 @@ ccl_device_inline void bsdf_eval_mul(BsdfEval *eval, float3 value)
/* skipping transparent, this function is used by for eval(), will be zero then */
}
else
- eval->diffuse *= value;
-#else
- *eval *= value;
#endif
+ {
+ eval->diffuse *= value;
+ }
}
/* Path Radiance
@@ -170,10 +164,10 @@ ccl_device_inline void path_radiance_init(PathRadiance *L, int use_light_pass)
L->mist = 0.0f;
}
else
- L->emission = make_float3(0.0f, 0.0f, 0.0f);
-#else
- *L = make_float3(0.0f, 0.0f, 0.0f);
#endif
+ {
+ L->emission = make_float3(0.0f, 0.0f, 0.0f);
+ }
}
ccl_device_inline void path_radiance_bsdf_bounce(PathRadiance *L, ccl_addr_space float3 *throughput,
@@ -205,10 +199,10 @@ ccl_device_inline void path_radiance_bsdf_bounce(PathRadiance *L, ccl_addr_space
}
}
else
- *throughput *= bsdf_eval->diffuse*inverse_pdf;
-#else
- *throughput *= *bsdf_eval*inverse_pdf;
#endif
+ {
+ *throughput *= bsdf_eval->diffuse*inverse_pdf;
+ }
}
ccl_device_inline void path_radiance_accum_emission(PathRadiance *L, float3 throughput, float3 value, int bounce)
@@ -223,10 +217,10 @@ ccl_device_inline void path_radiance_accum_emission(PathRadiance *L, float3 thro
L->indirect += throughput*value;
}
else
- L->emission += throughput*value;
-#else
- *L += throughput*value;
#endif
+ {
+ L->emission += throughput*value;
+ }
}
ccl_device_inline void path_radiance_accum_ao(PathRadiance *L, float3 throughput, float3 alpha, float3 bsdf, float3 ao, int bounce)
@@ -244,10 +238,10 @@ ccl_device_inline void path_radiance_accum_ao(PathRadiance *L, float3 throughput
}
}
else
- L->emission += throughput*bsdf*ao;
-#else
- *L += throughput*bsdf*ao;
#endif
+ {
+ L->emission += throughput*bsdf*ao;
+ }
}
ccl_device_inline void path_radiance_accum_light(PathRadiance *L, float3 throughput, BsdfEval *bsdf_eval, float3 shadow, float shadow_fac, int bounce, bool is_lamp)
@@ -275,10 +269,10 @@ ccl_device_inline void path_radiance_accum_light(PathRadiance *L, float3 through
}
}
else
- L->emission += throughput*bsdf_eval->diffuse*shadow;
-#else
- *L += throughput*(*bsdf_eval)*shadow;
#endif
+ {
+ L->emission += throughput*bsdf_eval->diffuse*shadow;
+ }
}
ccl_device_inline void path_radiance_accum_background(PathRadiance *L, float3 throughput, float3 value, int bounce)
@@ -293,10 +287,10 @@ ccl_device_inline void path_radiance_accum_background(PathRadiance *L, float3 th
L->indirect += throughput*value;
}
else
- L->emission += throughput*value;
-#else
- *L += throughput*value;
#endif
+ {
+ L->emission += throughput*value;
+ }
}
ccl_device_inline void path_radiance_sum_indirect(PathRadiance *L)
@@ -439,10 +433,10 @@ ccl_device_inline float3 path_radiance_clamp_and_sum(KernelGlobals *kg, PathRadi
/* No Light Passes */
else
- L_sum = L->emission;
-#else
- L_sum = *L;
#endif
+ {
+ L_sum = L->emission;
+ }
/* Reject invalid value */
float sum = fabsf((L_sum).x) + fabsf((L_sum).y) + fabsf((L_sum).z);
@@ -471,14 +465,12 @@ ccl_device_inline void path_radiance_accum_sample(PathRadiance *L, PathRadiance
L->indirect_subsurface += L_sample->indirect_subsurface*fac;
L->indirect_scatter += L_sample->indirect_scatter*fac;
- L->emission += L_sample->emission*fac;
L->background += L_sample->background*fac;
L->ao += L_sample->ao*fac;
L->shadow += L_sample->shadow*fac;
L->mist += L_sample->mist*fac;
-#else
- *L += *L_sample * fac;
#endif
+ L->emission += L_sample->emission * fac;
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_bake.h b/intern/cycles/kernel/kernel_bake.h
index 60110fb980a..84575d35d7f 100644
--- a/intern/cycles/kernel/kernel_bake.h
+++ b/intern/cycles/kernel/kernel_bake.h
@@ -18,8 +18,12 @@ CCL_NAMESPACE_BEGIN
#ifdef __BAKING__
-ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadiance *L, RNG rng,
- int pass_filter, int sample)
+ccl_device_inline void compute_light_pass(KernelGlobals *kg,
+ ShaderData *sd,
+ PathRadiance *L,
+ RNG rng,
+ int pass_filter,
+ int sample)
{
/* initialize master radiance accumulator */
kernel_assert(kernel_data.film.use_light_pass);
@@ -30,22 +34,25 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian
Ray ray;
float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
+ /* emission and indirect shader data memory used by various functions */
+ ShaderData emission_sd, indirect_sd;
+
ray.P = sd->P + sd->Ng;
ray.D = -sd->Ng;
ray.t = FLT_MAX;
#ifdef __CAMERA_MOTION__
- ray.time = TIME_INVALID;
+ ray.time = 0.5f;
#endif
/* init radiance */
path_radiance_init(&L_sample, kernel_data.film.use_light_pass);
/* init path state */
- path_state_init(kg, &state, &rng, sample, NULL);
+ path_state_init(kg, &emission_sd, &state, &rng, sample, NULL);
/* evaluate surface shader */
float rbsdf = path_state_rng_1D(kg, &rng, &state, PRNG_BSDF);
- shader_eval_surface(kg, sd, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN);
+ shader_eval_surface(kg, sd, &rng, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN);
/* TODO, disable the closures we won't need */
@@ -56,7 +63,7 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian
/* sample ambient occlusion */
if(pass_filter & BAKE_FILTER_AO) {
- kernel_path_ao(kg, sd, &L_sample, &state, &rng, throughput);
+ kernel_path_ao(kg, sd, &emission_sd, &L_sample, &state, &rng, throughput);
}
/* sample emission */
@@ -75,6 +82,7 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian
kernel_path_subsurface_init_indirect(&ss_indirect);
if(kernel_path_subsurface_scatter(kg,
sd,
+ &emission_sd,
&L_sample,
&state,
&rng,
@@ -90,6 +98,8 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian
&L_sample,
&throughput);
kernel_path_indirect(kg,
+ &indirect_sd,
+ &emission_sd,
&rng,
&ray,
throughput,
@@ -105,14 +115,14 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian
/* sample light and BSDF */
if(!is_sss_sample && (pass_filter & (BAKE_FILTER_DIRECT | BAKE_FILTER_INDIRECT))) {
- kernel_path_surface_connect_light(kg, &rng, sd, throughput, &state, &L_sample);
+ kernel_path_surface_connect_light(kg, &rng, sd, &emission_sd, throughput, &state, &L_sample);
if(kernel_path_surface_bounce(kg, &rng, sd, &throughput, &state, &L_sample, &ray)) {
#ifdef __LAMP_MIS__
state.ray_t = 0.0f;
#endif
/* compute indirect light */
- kernel_path_indirect(kg, &rng, &ray, throughput, 1, &state, &L_sample);
+ kernel_path_indirect(kg, &indirect_sd, &emission_sd, &rng, &ray, throughput, 1, &state, &L_sample);
/* sum and reset indirect light pass variables for the next samples */
path_radiance_sum_indirect(&L_sample);
@@ -126,7 +136,7 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian
/* sample ambient occlusion */
if(pass_filter & BAKE_FILTER_AO) {
- kernel_branched_path_ao(kg, sd, &L_sample, &state, &rng, throughput);
+ kernel_branched_path_ao(kg, sd, &emission_sd, &L_sample, &state, &rng, throughput);
}
/* sample emission */
@@ -139,7 +149,8 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian
/* sample subsurface scattering */
if((pass_filter & BAKE_FILTER_SUBSURFACE) && (sd->flag & SD_BSSRDF)) {
/* when mixing BSSRDF and BSDF closures we should skip BSDF lighting if scattering was successful */
- kernel_branched_path_subsurface_scatter(kg, sd, &L_sample, &state, &rng, &ray, throughput);
+ kernel_branched_path_subsurface_scatter(kg, sd, &indirect_sd,
+ &emission_sd, &L_sample, &state, &rng, &ray, throughput);
}
#endif
@@ -150,13 +161,13 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian
if(kernel_data.integrator.use_direct_light) {
int all = kernel_data.integrator.sample_all_lights_direct;
kernel_branched_path_surface_connect_light(kg, &rng,
- sd, &state, throughput, 1.0f, &L_sample, all);
+ sd, &emission_sd, &state, throughput, 1.0f, &L_sample, all);
}
#endif
/* indirect light */
kernel_branched_path_surface_indirect_light(kg, &rng,
- sd, throughput, 1.0f, &state, &L_sample);
+ sd, &indirect_sd, &emission_sd, throughput, 1.0f, &state, &L_sample);
}
}
#endif
@@ -213,6 +224,7 @@ ccl_device_inline float3 kernel_bake_shader_bsdf(KernelGlobals *kg,
ccl_device float3 kernel_bake_evaluate_direct_indirect(KernelGlobals *kg,
ShaderData *sd,
+ RNG *rng,
PathState *state,
float3 direct,
float3 indirect,
@@ -232,21 +244,21 @@ ccl_device float3 kernel_bake_evaluate_direct_indirect(KernelGlobals *kg,
}
else {
/* surface color of the pass only */
- shader_eval_surface(kg, sd, state, 0.0f, 0, SHADER_CONTEXT_MAIN);
+ shader_eval_surface(kg, sd, rng, state, 0.0f, 0, SHADER_CONTEXT_MAIN);
return kernel_bake_shader_bsdf(kg, sd, type);
}
}
else {
- shader_eval_surface(kg, sd, state, 0.0f, 0, SHADER_CONTEXT_MAIN);
+ shader_eval_surface(kg, sd, rng, state, 0.0f, 0, SHADER_CONTEXT_MAIN);
color = kernel_bake_shader_bsdf(kg, sd, type);
}
if(is_direct) {
- out += safe_divide_color(direct, color);
+ out += safe_divide_even_color(direct, color);
}
if(is_indirect) {
- out += safe_divide_color(indirect, color);
+ out += safe_divide_even_color(indirect, color);
}
return out;
@@ -301,15 +313,15 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
triangle_point_normal(kg, object, prim, u, v, &P, &Ng, &shader);
- /* dummy initilizations copied from SHADER_EVAL_DISPLACE */
- float3 I = Ng;
- float t = 1.0f;
- float time = TIME_INVALID;
-
/* light passes */
PathRadiance L;
- shader_setup_from_sample(kg, &sd, P, Ng, I, shader, object, prim, u, v, t, time);
+ shader_setup_from_sample(kg, &sd,
+ P, Ng, Ng,
+ shader, object, prim,
+ u, v, 1.0f, 0.5f,
+ !(kernel_tex_fetch(__object_flag, object) & SD_TRANSFORM_APPLIED),
+ LAMP_NONE);
sd.I = sd.N;
/* update differentials */
@@ -329,7 +341,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
case SHADER_EVAL_NORMAL:
{
if((sd.flag & SD_HAS_BUMP)) {
- shader_eval_surface(kg, &sd, &state, 0.f, 0, SHADER_CONTEXT_MAIN);
+ shader_eval_surface(kg, &sd, &rng, &state, 0.f, 0, SHADER_CONTEXT_MAIN);
}
/* compression: normal = (2 * color) - 1 */
@@ -343,7 +355,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
}
case SHADER_EVAL_EMISSION:
{
- shader_eval_surface(kg, &sd, &state, 0.f, 0, SHADER_CONTEXT_EMISSION);
+ shader_eval_surface(kg, &sd, &rng, &state, 0.f, 0, SHADER_CONTEXT_EMISSION);
out = shader_emissive_eval(kg, &sd);
break;
}
@@ -396,6 +408,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
{
out = kernel_bake_evaluate_direct_indirect(kg,
&sd,
+ &rng,
&state,
L.direct_diffuse,
L.indirect_diffuse,
@@ -407,6 +420,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
{
out = kernel_bake_evaluate_direct_indirect(kg,
&sd,
+ &rng,
&state,
L.direct_glossy,
L.indirect_glossy,
@@ -418,6 +432,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
{
out = kernel_bake_evaluate_direct_indirect(kg,
&sd,
+ &rng,
&state,
L.direct_transmission,
L.indirect_transmission,
@@ -430,6 +445,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
#ifdef __SUBSURFACE__
out = kernel_bake_evaluate_direct_indirect(kg,
&sd,
+ &rng,
&state,
L.direct_subsurface,
L.indirect_subsurface,
@@ -475,12 +491,10 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
}
/* write output */
- float output_fac = is_aa_pass(type)? 1.0f/num_samples: 1.0f;
+ const float output_fac = is_aa_pass(type)? 1.0f/num_samples: 1.0f;
+ const float4 scaled_result = make_float4(out.x, out.y, out.z, 1.0f) * output_fac;
- if(sample == 0)
- output[i] = make_float4(out.x, out.y, out.z, 1.0f) * output_fac;
- else
- output[i] += make_float4(out.x, out.y, out.z, 1.0f) * output_fac;
+ output[i] = (sample == 0)? scaled_result: output[i] + scaled_result;
}
#endif /* __BAKING__ */
@@ -511,6 +525,8 @@ ccl_device void kernel_shader_evaluate(KernelGlobals *kg,
float3 P = sd.P;
shader_eval_displacement(kg, &sd, &state, SHADER_CONTEXT_MAIN);
out = sd.P - P;
+
+ object_inverse_dir_transform(kg, &sd, &out);
}
else { // SHADER_EVAL_BACKGROUND
/* setup ray */
diff --git a/intern/cycles/kernel/kernel_camera.h b/intern/cycles/kernel/kernel_camera.h
index f6c103d59dd..dedac6b1465 100644
--- a/intern/cycles/kernel/kernel_camera.h
+++ b/intern/cycles/kernel/kernel_camera.h
@@ -68,8 +68,8 @@ ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, flo
}
#endif
- ray->P = make_float3(0.0f, 0.0f, 0.0f);
- ray->D = Pcamera;
+ float3 P = make_float3(0.0f, 0.0f, 0.0f);
+ float3 D = Pcamera;
/* modify ray for depth of field */
float aperturesize = kernel_data.cam.aperturesize;
@@ -79,12 +79,12 @@ ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, flo
float2 lensuv = camera_sample_aperture(kg, lens_u, lens_v)*aperturesize;
/* compute point on plane of focus */
- float ft = kernel_data.cam.focaldistance/ray->D.z;
- float3 Pfocus = ray->D*ft;
+ float ft = kernel_data.cam.focaldistance/D.z;
+ float3 Pfocus = D*ft;
/* update ray for effect of lens */
- ray->P = make_float3(lensuv.x, lensuv.y, 0.0f);
- ray->D = normalize(Pfocus - ray->P);
+ P = make_float3(lensuv.x, lensuv.y, 0.0f);
+ D = normalize(Pfocus - P);
}
/* transform ray from camera to world */
@@ -105,39 +105,66 @@ ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, flo
}
#endif
- float3 tP = transform_point(&cameratoworld, ray->P);
- float3 tD = transform_direction(&cameratoworld, ray->D);
- ray->P = spherical_stereo_position(kg, tD, tP);
- ray->D = spherical_stereo_direction(kg, tD, tP, ray->P);
+ P = transform_point(&cameratoworld, P);
+ D = normalize(transform_direction(&cameratoworld, D));
+
+ bool use_stereo = kernel_data.cam.interocular_offset != 0.0f;
+ if(!use_stereo) {
+ /* No stereo */
+ ray->P = P;
+ ray->D = D;
#ifdef __RAY_DIFFERENTIALS__
- /* ray differential */
- ray->dP = differential3_zero();
-
- float3 tD_diff = transform_direction(&cameratoworld, Pcamera);
- float3 Pdiff = spherical_stereo_position(kg, tD_diff, Pcamera);
- float3 Ddiff = spherical_stereo_direction(kg, tD_diff, Pcamera, Pdiff);
-
- tP = transform_perspective(&rastertocamera,
- make_float3(raster_x + 1.0f, raster_y, 0.0f));
- tD = tD_diff + float4_to_float3(kernel_data.cam.dx);
- Pcamera = spherical_stereo_position(kg, tD, tP);
- ray->dD.dx = spherical_stereo_direction(kg, tD, tP, Pcamera) - Ddiff;
- ray->dP.dx = Pcamera - Pdiff;
-
- tP = transform_perspective(&rastertocamera,
- make_float3(raster_x, raster_y + 1.0f, 0.0f));
- tD = tD_diff + float4_to_float3(kernel_data.cam.dy);
- Pcamera = spherical_stereo_position(kg, tD, tP);
- ray->dD.dy = spherical_stereo_direction(kg, tD, tP, Pcamera) - Ddiff;
- /* dP.dy is zero, since the omnidirectional panorama only shift the eyes horizontally */
+ float3 Dcenter = transform_direction(&cameratoworld, Pcamera);
+
+ ray->dP = differential3_zero();
+ ray->dD.dx = normalize(Dcenter + float4_to_float3(kernel_data.cam.dx)) - normalize(Dcenter);
+ ray->dD.dy = normalize(Dcenter + float4_to_float3(kernel_data.cam.dy)) - normalize(Dcenter);
+#endif
+ }
+ else {
+ /* Spherical stereo */
+ spherical_stereo_transform(kg, &P, &D);
+ ray->P = P;
+ ray->D = D;
+
+#ifdef __RAY_DIFFERENTIALS__
+ /* Ray differentials, computed from scratch using the raster coordinates
+ * because we don't want to be affected by depth of field. We compute
+ * ray origin and direction for the center and two neighbouring pixels
+ * and simply take their differences. */
+ float3 Pnostereo = transform_point(&cameratoworld, make_float3(0.0f, 0.0f, 0.0f));
+
+ float3 Pcenter = Pnostereo;
+ float3 Dcenter = Pcamera;
+ Dcenter = normalize(transform_direction(&cameratoworld, Dcenter));
+ spherical_stereo_transform(kg, &Pcenter, &Dcenter);
+
+ float3 Px = Pnostereo;
+ float3 Dx = transform_perspective(&rastertocamera, make_float3(raster_x + 1.0f, raster_y, 0.0f));
+ Dx = normalize(transform_direction(&cameratoworld, Dx));
+ spherical_stereo_transform(kg, &Px, &Dx);
+
+ ray->dP.dx = Px - Pcenter;
+ ray->dD.dx = Dx - Dcenter;
+
+ float3 Py = Pnostereo;
+ float3 Dy = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y + 1.0f, 0.0f));
+ Dy = normalize(transform_direction(&cameratoworld, Dy));
+ spherical_stereo_transform(kg, &Py, &Dy);
+
+ ray->dP.dy = Py - Pcenter;
+ ray->dD.dy = Dy - Dcenter;
#endif
+ }
#ifdef __CAMERA_CLIPPING__
/* clipping */
- float3 Pclip = normalize(Pcamera);
- float z_inv = 1.0f / Pclip.z;
- ray->P += kernel_data.cam.nearclip*ray->D * z_inv;
+ float z_inv = 1.0f / normalize(Pcamera).z;
+ float nearclip = kernel_data.cam.nearclip * z_inv;
+ ray->P += nearclip * ray->D;
+ ray->dP.dx += nearclip * ray->dD.dx;
+ ray->dP.dy += nearclip * ray->dD.dy;
ray->t = kernel_data.cam.cliplength * z_inv;
#else
ray->t = FLT_MAX;
@@ -151,7 +178,8 @@ ccl_device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, fl
Transform rastertocamera = kernel_data.cam.rastertocamera;
float3 Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
- ray->D = make_float3(0.0f, 0.0f, 1.0f);
+ float3 P;
+ float3 D = make_float3(0.0f, 0.0f, 1.0f);
/* modify ray for depth of field */
float aperturesize = kernel_data.cam.aperturesize;
@@ -161,15 +189,15 @@ ccl_device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, fl
float2 lensuv = camera_sample_aperture(kg, lens_u, lens_v)*aperturesize;
/* compute point on plane of focus */
- float3 Pfocus = ray->D * kernel_data.cam.focaldistance;
+ float3 Pfocus = D * kernel_data.cam.focaldistance;
/* update ray for effect of lens */
float3 lensuvw = make_float3(lensuv.x, lensuv.y, 0.0f);
- ray->P = Pcamera + lensuvw;
- ray->D = normalize(Pfocus - lensuvw);
+ P = Pcamera + lensuvw;
+ D = normalize(Pfocus - lensuvw);
}
else {
- ray->P = Pcamera;
+ P = Pcamera;
}
/* transform ray from camera to world */
Transform cameratoworld = kernel_data.cam.cameratoworld;
@@ -189,9 +217,8 @@ ccl_device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, fl
}
#endif
- ray->P = transform_point(&cameratoworld, ray->P);
- ray->D = transform_direction(&cameratoworld, ray->D);
- ray->D = normalize(ray->D);
+ ray->P = transform_point(&cameratoworld, P);
+ ray->D = normalize(transform_direction(&cameratoworld, D));
#ifdef __RAY_DIFFERENTIALS__
/* ray differential */
@@ -211,25 +238,20 @@ ccl_device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, fl
/* Panorama Camera */
-ccl_device void camera_sample_panorama(KernelGlobals *kg, float raster_x, float raster_y, float lens_u, float lens_v, ccl_addr_space Ray *ray)
+ccl_device_inline void camera_sample_panorama(KernelGlobals *kg,
+ float raster_x, float raster_y,
+ float lens_u, float lens_v,
+ ccl_addr_space Ray *ray)
{
Transform rastertocamera = kernel_data.cam.rastertocamera;
float3 Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
/* create ray form raster position */
- ray->P = make_float3(0.0f, 0.0f, 0.0f);
-
-#ifdef __CAMERA_CLIPPING__
- /* clipping */
- ray->t = kernel_data.cam.cliplength;
-#else
- ray->t = FLT_MAX;
-#endif
-
- ray->D = panorama_to_direction(kg, Pcamera.x, Pcamera.y);
+ float3 P = make_float3(0.0f, 0.0f, 0.0f);
+ float3 D = panorama_to_direction(kg, Pcamera.x, Pcamera.y);
/* indicates ray should not receive any light, outside of the lens */
- if(is_zero(ray->D)) {
+ if(is_zero(D)) {
ray->t = 0.0f;
return;
}
@@ -242,17 +264,17 @@ ccl_device void camera_sample_panorama(KernelGlobals *kg, float raster_x, float
float2 lensuv = camera_sample_aperture(kg, lens_u, lens_v)*aperturesize;
/* compute point on plane of focus */
- float3 D = normalize(ray->D);
- float3 Pfocus = D * kernel_data.cam.focaldistance;
+ float3 Dfocus = normalize(D);
+ float3 Pfocus = Dfocus * kernel_data.cam.focaldistance;
- /* calculate orthonormal coordinates perpendicular to D */
+ /* calculate orthonormal coordinates perpendicular to Dfocus */
float3 U, V;
- U = normalize(make_float3(1.0f, 0.0f, 0.0f) - D.x * D);
- V = normalize(cross(D, U));
+ U = normalize(make_float3(1.0f, 0.0f, 0.0f) - Dfocus.x * Dfocus);
+ V = normalize(cross(Dfocus, U));
/* update ray for effect of lens */
- ray->P = U * lensuv.x + V * lensuv.y;
- ray->D = normalize(Pfocus - ray->P);
+ P = U * lensuv.x + V * lensuv.y;
+ D = normalize(Pfocus - P);
}
/* transform ray from camera to world */
@@ -273,38 +295,74 @@ ccl_device void camera_sample_panorama(KernelGlobals *kg, float raster_x, float
}
#endif
- float3 tP = transform_point(&cameratoworld, ray->P);
- float3 tD = transform_direction(&cameratoworld, ray->D);
- ray->P = spherical_stereo_position(kg, tD, tP);
- ray->D = spherical_stereo_direction(kg, tD, tP, ray->P);
+ P = transform_point(&cameratoworld, P);
+ D = normalize(transform_direction(&cameratoworld, D));
+
+ /* Stereo transform */
+ bool use_stereo = kernel_data.cam.interocular_offset != 0.0f;
+ if(use_stereo) {
+ spherical_stereo_transform(kg, &P, &D);
+ }
+
+ ray->P = P;
+ ray->D = D;
#ifdef __RAY_DIFFERENTIALS__
- /* ray differential */
- ray->dP = differential3_zero();
-
- tP = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
- tD = transform_direction(&cameratoworld, panorama_to_direction(kg, tP.x, tP.y));
- float3 Pdiff = spherical_stereo_position(kg, tD, tP);
- float3 Ddiff = spherical_stereo_direction(kg, tD, tP, Pdiff);
-
- tP = transform_perspective(&rastertocamera, make_float3(raster_x + 1.0f, raster_y, 0.0f));
- tD = transform_direction(&cameratoworld, panorama_to_direction(kg, tP.x, tP.y));
- Pcamera = spherical_stereo_position(kg, tD, tP);
- ray->dD.dx = spherical_stereo_direction(kg, tD, tP, Pcamera) - Ddiff;
- ray->dP.dx = Pcamera - Pdiff;
-
- tP = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y + 1.0f, 0.0f));
- tD = transform_direction(&cameratoworld, panorama_to_direction(kg, tP.x, tP.y));
- Pcamera = spherical_stereo_position(kg, tD, tP);
- ray->dD.dy = spherical_stereo_direction(kg, tD, tP, Pcamera) - Ddiff;
- /* dP.dy is zero, since the omnidirectional panorama only shift the eyes horizontally */
+ /* Ray differentials, computed from scratch using the raster coordinates
+ * because we don't want to be affected by depth of field. We compute
+ * ray origin and direction for the center and two neighbouring pixels
+ * and simply take their differences. */
+ float3 Pcenter = Pcamera;
+ float3 Dcenter = panorama_to_direction(kg, Pcenter.x, Pcenter.y);
+ Pcenter = transform_point(&cameratoworld, Pcenter);
+ Dcenter = normalize(transform_direction(&cameratoworld, Dcenter));
+ if(use_stereo) {
+ spherical_stereo_transform(kg, &Pcenter, &Dcenter);
+ }
+
+ float3 Px = transform_perspective(&rastertocamera, make_float3(raster_x + 1.0f, raster_y, 0.0f));
+ float3 Dx = panorama_to_direction(kg, Px.x, Px.y);
+ Px = transform_point(&cameratoworld, Px);
+ Dx = normalize(transform_direction(&cameratoworld, Dx));
+ if(use_stereo) {
+ spherical_stereo_transform(kg, &Px, &Dx);
+ }
+
+ ray->dP.dx = Px - Pcenter;
+ ray->dD.dx = Dx - Dcenter;
+
+ float3 Py = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y + 1.0f, 0.0f));
+ float3 Dy = panorama_to_direction(kg, Py.x, Py.y);
+ Py = transform_point(&cameratoworld, Py);
+ Dy = normalize(transform_direction(&cameratoworld, Dy));
+ if(use_stereo) {
+ spherical_stereo_transform(kg, &Py, &Dy);
+ }
+
+ ray->dP.dy = Py - Pcenter;
+ ray->dD.dy = Dy - Dcenter;
+#endif
+
+#ifdef __CAMERA_CLIPPING__
+ /* clipping */
+ float nearclip = kernel_data.cam.nearclip;
+ ray->P += nearclip * ray->D;
+ ray->dP.dx += nearclip * ray->dD.dx;
+ ray->dP.dy += nearclip * ray->dD.dy;
+ ray->t = kernel_data.cam.cliplength;
+#else
+ ray->t = FLT_MAX;
#endif
}
/* Common */
-ccl_device void camera_sample(KernelGlobals *kg, int x, int y, float filter_u, float filter_v,
- float lens_u, float lens_v, float time, ccl_addr_space Ray *ray)
+ccl_device_inline void camera_sample(KernelGlobals *kg,
+ int x, int y,
+ float filter_u, float filter_v,
+ float lens_u, float lens_v,
+ float time,
+ ccl_addr_space Ray *ray)
{
/* pixel filter */
int filter_table_offset = kernel_data.film.filter_table_offset;
@@ -314,7 +372,7 @@ ccl_device void camera_sample(KernelGlobals *kg, int x, int y, float filter_u, f
#ifdef __CAMERA_MOTION__
/* motion blur */
if(kernel_data.cam.shuttertime == -1.0f) {
- ray->time = TIME_INVALID;
+ ray->time = 0.5f;
}
else {
/* TODO(sergey): Such lookup is unneeded when there's rolling shutter
diff --git a/intern/cycles/kernel/kernel_compat_cpu.h b/intern/cycles/kernel/kernel_compat_cpu.h
index 16994b4fef6..d8256cdebf5 100644
--- a/intern/cycles/kernel/kernel_compat_cpu.h
+++ b/intern/cycles/kernel/kernel_compat_cpu.h
@@ -40,6 +40,7 @@
#include "util_simd.h"
#include "util_half.h"
#include "util_types.h"
+#include "util_texture.h"
#include "util_volume.h"
#define ccl_addr_space
@@ -71,6 +72,20 @@ template<typename T> struct texture {
return data[index];
}
+#ifdef __KERNEL_AVX__
+ /* Reads 256 bytes but indexes in blocks of 128 bytes to maintain
+ * compatibility with existing indicies and data structures.
+ */
+ ccl_always_inline avxf fetch_avxf(const int index)
+ {
+ kernel_assert(index >= 0 && (index+1) < width);
+ ssef *ssefData = (ssef*)data;
+ ssef *ssefNodeData = &ssefData[index];
+ return _mm256_loadu_ps((float *)ssefNodeData);
+ }
+
+#endif
+
#ifdef __KERNEL_SSE2__
ccl_always_inline ssef fetch_ssef(int index)
{
@@ -109,6 +124,30 @@ template<typename T> struct texture_image {
return make_float4(r.x*f, r.y*f, r.z*f, r.w*f);
}
+ ccl_always_inline float4 read(uchar r)
+ {
+ float f = r*(1.0f/255.0f);
+ return make_float4(f, f, f, 1.0f);
+ }
+
+ ccl_always_inline float4 read(float r)
+ {
+ /* TODO(dingto): Optimize this, so interpolation
+ * happens on float instead of float4 */
+ return make_float4(r, r, r, 1.0f);
+ }
+
+ ccl_always_inline float4 read(half4 r)
+ {
+ return half4_to_float4(r);
+ }
+
+ ccl_always_inline float4 read(half r)
+ {
+ float f = half_to_float(r);
+ return make_float4(f, f, f, 1.0f);
+ }
+
ccl_always_inline int wrap_periodic(int x, int width)
{
x %= width;
@@ -471,18 +510,25 @@ typedef texture<uint> texture_uint;
typedef texture<int> texture_int;
typedef texture<uint4> texture_uint4;
typedef texture<uchar4> texture_uchar4;
+typedef texture<uchar> texture_uchar;
+typedef texture_image<float> texture_image_float;
+typedef texture_image<uchar> texture_image_uchar;
+typedef texture_image<half> texture_image_half;
typedef texture_image<float4> texture_image_float4;
typedef texture_image<uchar4> texture_image_uchar4;
+typedef texture_image<half4> texture_image_half4;
/* Macros to handle different memory storage on different devices */
#define kernel_tex_fetch(tex, index) (kg->tex.fetch(index))
+#define kernel_tex_fetch_avxf(tex, index) (kg->tex.fetch_avxf(index))
#define kernel_tex_fetch_ssef(tex, index) (kg->tex.fetch_ssef(index))
#define kernel_tex_fetch_ssei(tex, index) (kg->tex.fetch_ssei(index))
#define kernel_tex_lookup(tex, t, offset, size) (kg->tex.lookup(t, offset, size))
-#define kernel_tex_image_interp(tex, x, y) ((tex < TEX_NUM_FLOAT4_IMAGES_CPU) ? kg->texture_float4_images[tex].interp(x, y) : kg->texture_byte4_images[tex - TEX_NUM_FLOAT4_IMAGES_CPU].interp(x, y))
-#define kernel_tex_image_interp_3d(tex, x, y, z) ((tex < TEX_NUM_FLOAT4_IMAGES_CPU) ? kg->texture_float4_images[tex].interp_3d(x, y, z) : kg->texture_byte4_images[tex - TEX_NUM_FLOAT4_IMAGES_CPU].interp_3d(x, y, z))
-#define kernel_tex_image_interp_3d_ex(tex, x, y, z, interpolation) ((tex < TEX_NUM_FLOAT4_IMAGES_CPU) ? kg->texture_float4_images[tex].interp_3d_ex(x, y, z, interpolation) : kg->texture_byte4_images[tex - TEX_NUM_FLOAT4_IMAGES_CPU].interp_3d_ex(x, y, z, interpolation))
+
+#define kernel_tex_image_interp(tex,x,y) kernel_tex_image_interp_impl(kg,tex,x,y)
+#define kernel_tex_image_interp_3d(tex, x, y, z) kernel_tex_image_interp_3d_impl(kg,tex,x,y,z)
+#define kernel_tex_image_interp_3d_ex(tex, x, y, z, interpolation) kernel_tex_image_interp_3d_ex_impl(kg,tex, x, y, z, interpolation)
#define kernel_tex_voxel_float(tex, x, y, z, sampling) (kg->float_volumes[tex]->sample(x, y, z, sampling))
#define kernel_tex_voxel_float3(tex, x, y, z, sampling) (kg->float3_volumes[tex]->sample(x, y, z, sampling))
diff --git a/intern/cycles/kernel/kernel_compat_cuda.h b/intern/cycles/kernel/kernel_compat_cuda.h
index d10d3255e1b..e0c7b17c6a0 100644
--- a/intern/cycles/kernel/kernel_compat_cuda.h
+++ b/intern/cycles/kernel/kernel_compat_cuda.h
@@ -31,17 +31,25 @@
#endif
#include <cuda.h>
+#include <cuda_fp16.h>
#include <float.h>
/* Qualifier wrappers for different names on different devices */
#define ccl_device __device__ __inline__
-#define ccl_device_inline __device__ __inline__
+# define ccl_device_forceinline __device__ __forceinline__
+#if (__KERNEL_CUDA_VERSION__ == 80) && (__CUDA_ARCH__ < 500)
+# define ccl_device_inline __device__ __forceinline__
+#else
+# define ccl_device_inline __device__ __inline__
+#endif
#define ccl_device_noinline __device__ __noinline__
#define ccl_global
#define ccl_constant
#define ccl_may_alias
#define ccl_addr_space
+#define ccl_restrict __restrict__
+#define ccl_align(n) __align__(n)
/* No assert supported for CUDA */
@@ -60,6 +68,7 @@ typedef texture<float, 1> texture_float;
typedef texture<uint, 1> texture_uint;
typedef texture<int, 1> texture_int;
typedef texture<uint4, 1> texture_uint4;
+typedef texture<uchar, 1> texture_uchar;
typedef texture<uchar4, 1> texture_uchar4;
typedef texture<float4, 2> texture_image_float4;
typedef texture<float4, 3> texture_image3d_float4;
@@ -67,20 +76,29 @@ typedef texture<uchar4, 2, cudaReadModeNormalizedFloat> texture_image_uchar4;
/* Macros to handle different memory storage on different devices */
-/* In order to use full 6GB of memory on Titan cards, use arrays instead
- * of textures. On earlier cards this seems slower, but on Titan it is
- * actually slightly faster in tests. */
+/* On Fermi cards (4xx and 5xx), we use regular textures for both data and images.
+ * On Kepler (6xx) and above, we use Bindless Textures for images and arrays for data.
+ *
+ * Arrays are necessary in order to use the full VRAM on newer cards, and it's slightly faster.
+ * Using Arrays on Fermi turned out to be slower.*/
+
+/* Fermi */
#if __CUDA_ARCH__ < 300
# define __KERNEL_CUDA_TEX_STORAGE__
-#endif
-
-#ifdef __KERNEL_CUDA_TEX_STORAGE__
# define kernel_tex_fetch(t, index) tex1Dfetch(t, index)
+
+# define kernel_tex_image_interp(t, x, y) tex2D(t, x, y)
+# define kernel_tex_image_interp_3d(t, x, y, z) tex3D(t, x, y, z)
+
+/* Kepler */
#else
# define kernel_tex_fetch(t, index) t[(index)]
+
+# define kernel_tex_image_interp_float4(t, x, y) tex2D<float4>(t, x, y)
+# define kernel_tex_image_interp_float(t, x, y) tex2D<float>(t, x, y)
+# define kernel_tex_image_interp_3d_float4(t, x, y, z) tex3D<float4>(t, x, y, z)
+# define kernel_tex_image_interp_3d_float(t, x, y, z) tex3D<float>(t, x, y, z)
#endif
-#define kernel_tex_image_interp(t, x, y) tex2D(t, x, y)
-#define kernel_tex_image_interp_3d(t, x, y, z) tex3D(t, x, y, z)
#define kernel_data __data
diff --git a/intern/cycles/kernel/kernel_compat_opencl.h b/intern/cycles/kernel/kernel_compat_opencl.h
index a5708448e23..f076e3a7d37 100644
--- a/intern/cycles/kernel/kernel_compat_opencl.h
+++ b/intern/cycles/kernel/kernel_compat_opencl.h
@@ -33,12 +33,15 @@
/* in opencl all functions are device functions, so leave this empty */
#define ccl_device
#define ccl_device_inline ccl_device
+#define ccl_device_forceinline ccl_device
#define ccl_device_noinline ccl_device ccl_noinline
#define ccl_may_alias
#define ccl_constant __constant
#define ccl_global __global
#define ccl_local __local
#define ccl_private __private
+#define ccl_restrict restrict
+#define ccl_align(n) __attribute__((aligned(n)))
#ifdef __SPLIT_KERNEL__
# define ccl_addr_space __global
diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h
index 5cf52f9d176..9e4a631b998 100644
--- a/intern/cycles/kernel/kernel_emission.h
+++ b/intern/cycles/kernel/kernel_emission.h
@@ -18,6 +18,7 @@ CCL_NAMESPACE_BEGIN
/* Direction Emission */
ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
+ ShaderData *emission_sd,
LightSample *ls,
ccl_addr_space PathState *state,
float3 I,
@@ -26,14 +27,10 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
float time)
{
/* setup shading at emitter */
-#ifdef __SPLIT_KERNEL__
- ShaderData *sd = kg->sd_input;
-#else
- ShaderData sd_object;
- ShaderData *sd = &sd_object;
-#endif
float3 eval;
+ int shader_flag = kernel_tex_fetch(__shader_flag, (ls->shader & SHADER_MASK)*SHADER_SIZE);
+
#ifdef __BACKGROUND_MIS__
if(ls->type == LIGHT_BACKGROUND) {
Ray ray;
@@ -46,28 +43,41 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
ray.dP = differential3_zero();
ray.dD = dI;
- shader_setup_from_background(kg, sd, &ray);
+ shader_setup_from_background(kg, emission_sd, &ray);
path_state_modify_bounce(state, true);
- eval = shader_eval_background(kg, sd, state, 0, SHADER_CONTEXT_EMISSION);
+ eval = shader_eval_background(kg, emission_sd, state, 0, SHADER_CONTEXT_EMISSION);
path_state_modify_bounce(state, false);
}
else
#endif
+ if(shader_flag & SD_HAS_CONSTANT_EMISSION)
+ {
+ eval.x = __int_as_float(kernel_tex_fetch(__shader_flag, (ls->shader & SHADER_MASK)*SHADER_SIZE + 2));
+ eval.y = __int_as_float(kernel_tex_fetch(__shader_flag, (ls->shader & SHADER_MASK)*SHADER_SIZE + 3));
+ eval.z = __int_as_float(kernel_tex_fetch(__shader_flag, (ls->shader & SHADER_MASK)*SHADER_SIZE + 4));
+ if((ls->prim != PRIM_NONE) && dot(ls->Ng, I) < 0.0f) {
+ ls->Ng = -ls->Ng;
+ }
+ }
+ else
{
- shader_setup_from_sample(kg, sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, ls->u, ls->v, t, time);
+ shader_setup_from_sample(kg, emission_sd,
+ ls->P, ls->Ng, I,
+ ls->shader, ls->object, ls->prim,
+ ls->u, ls->v, t, time, false, ls->lamp);
- ls->Ng = ccl_fetch(sd, Ng);
+ ls->Ng = ccl_fetch(emission_sd, Ng);
/* no path flag, we're evaluating this for all closures. that's weak but
* we'd have to do multiple evaluations otherwise */
path_state_modify_bounce(state, true);
- shader_eval_surface(kg, sd, state, 0.0f, 0, SHADER_CONTEXT_EMISSION);
+ shader_eval_surface(kg, emission_sd, NULL, state, 0.0f, 0, SHADER_CONTEXT_EMISSION);
path_state_modify_bounce(state, false);
/* evaluate emissive closure */
- if(ccl_fetch(sd, flag) & SD_EMISSION)
- eval = shader_emissive_eval(kg, sd);
+ if(ccl_fetch(emission_sd, flag) & SD_EMISSION)
+ eval = shader_emissive_eval(kg, emission_sd);
else
eval = make_float3(0.0f, 0.0f, 0.0f);
}
@@ -79,6 +89,7 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
ccl_device_noinline bool direct_emission(KernelGlobals *kg,
ShaderData *sd,
+ ShaderData *emission_sd,
LightSample *ls,
ccl_addr_space PathState *state,
Ray *ray,
@@ -94,6 +105,7 @@ ccl_device_noinline bool direct_emission(KernelGlobals *kg,
/* evaluate closure */
float3 light_eval = direct_emissive_eval(kg,
+ emission_sd,
ls,
state,
-ls->D,
@@ -127,8 +139,10 @@ ccl_device_noinline bool direct_emission(KernelGlobals *kg,
#ifdef __PASSES__
/* use visibility flag to skip lights */
if(ls->shader & SHADER_EXCLUDE_ANY) {
- if(ls->shader & SHADER_EXCLUDE_DIFFUSE)
+ if(ls->shader & SHADER_EXCLUDE_DIFFUSE) {
eval->diffuse = make_float3(0.0f, 0.0f, 0.0f);
+ eval->subsurface = make_float3(0.0f, 0.0f, 0.0f);
+ }
if(ls->shader & SHADER_EXCLUDE_GLOSSY)
eval->glossy = make_float3(0.0f, 0.0f, 0.0f);
if(ls->shader & SHADER_EXCLUDE_TRANSMIT)
@@ -198,6 +212,7 @@ ccl_device_noinline float3 indirect_primitive_emission(KernelGlobals *kg, Shader
/* Indirect Lamp Emission */
ccl_device_noinline bool indirect_lamp_emission(KernelGlobals *kg,
+ ShaderData *emission_sd,
ccl_addr_space PathState *state,
Ray *ray,
float3 *emission)
@@ -225,6 +240,7 @@ ccl_device_noinline bool indirect_lamp_emission(KernelGlobals *kg,
#endif
float3 L = direct_emissive_eval(kg,
+ emission_sd,
&ls,
state,
-ray->D,
@@ -238,7 +254,7 @@ ccl_device_noinline bool indirect_lamp_emission(KernelGlobals *kg,
Ray volume_ray = *ray;
volume_ray.t = ls.t;
float3 volume_tp = make_float3(1.0f, 1.0f, 1.0f);
- kernel_volume_shadow(kg, state, &volume_ray, &volume_tp);
+ kernel_volume_shadow(kg, emission_sd, state, &volume_ray, &volume_tp);
L *= volume_tp;
}
#endif
@@ -260,6 +276,7 @@ ccl_device_noinline bool indirect_lamp_emission(KernelGlobals *kg,
/* Indirect Background */
ccl_device_noinline float3 indirect_background(KernelGlobals *kg,
+ ShaderData *emission_sd,
ccl_addr_space PathState *state,
ccl_addr_space Ray *ray)
{
@@ -280,19 +297,14 @@ ccl_device_noinline float3 indirect_background(KernelGlobals *kg,
/* evaluate background closure */
# ifdef __SPLIT_KERNEL__
Ray priv_ray = *ray;
- shader_setup_from_background(kg, kg->sd_input, &priv_ray);
-
- path_state_modify_bounce(state, true);
- float3 L = shader_eval_background(kg, kg->sd_input, state, state->flag, SHADER_CONTEXT_EMISSION);
- path_state_modify_bounce(state, false);
+ shader_setup_from_background(kg, emission_sd, &priv_ray);
# else
- ShaderData sd;
- shader_setup_from_background(kg, &sd, ray);
+ shader_setup_from_background(kg, emission_sd, ray);
+# endif
path_state_modify_bounce(state, true);
- float3 L = shader_eval_background(kg, &sd, state, state->flag, SHADER_CONTEXT_EMISSION);
+ float3 L = shader_eval_background(kg, emission_sd, state, state->flag, SHADER_CONTEXT_EMISSION);
path_state_modify_bounce(state, false);
-# endif
#ifdef __BACKGROUND_MIS__
/* check if background light exists or if we should skip pdf */
diff --git a/intern/cycles/kernel/kernel_globals.h b/intern/cycles/kernel/kernel_globals.h
index ab03aad46c5..d8c4b7c71e4 100644
--- a/intern/cycles/kernel/kernel_globals.h
+++ b/intern/cycles/kernel/kernel_globals.h
@@ -31,11 +31,18 @@ struct OSLThreadData;
struct OSLShadingSystem;
# endif
+struct Intersection;
+struct VolumeStep;
+
# define MAX_VOLUME 1024
typedef struct KernelGlobals {
- texture_image_uchar4 texture_byte4_images[TEX_NUM_BYTE4_IMAGES_CPU];
- texture_image_float4 texture_float4_images[TEX_NUM_FLOAT4_IMAGES_CPU];
+ texture_image_uchar4 texture_byte4_images[TEX_NUM_BYTE4_CPU];
+ texture_image_float4 texture_float4_images[TEX_NUM_FLOAT4_CPU];
+ texture_image_half4 texture_half4_images[TEX_NUM_HALF4_CPU];
+ texture_image_float texture_float_images[TEX_NUM_FLOAT_CPU];
+ texture_image_uchar texture_byte_images[TEX_NUM_BYTE_CPU];
+ texture_image_half texture_half_images[TEX_NUM_HALF_CPU];
float_volume *float_volumes[MAX_VOLUME];
float3_volume *float3_volumes[MAX_VOLUME];
@@ -54,6 +61,14 @@ typedef struct KernelGlobals {
OSLThreadData *osl_tdata;
# endif
+ /* **** Run-time data **** */
+
+ /* Heap-allocated storage for transparent shadows intersections. */
+ Intersection *transparent_shadow_intersections;
+
+ /* Storage for decoupled volume steps. */
+ VolumeStep *decoupled_volume_steps[2];
+ int decoupled_volume_steps_index;
} KernelGlobals;
#endif /* __KERNEL_CPU__ */
diff --git a/intern/cycles/kernel/kernel_image_opencl.h b/intern/cycles/kernel/kernel_image_opencl.h
new file mode 100644
index 00000000000..0352c58037d
--- /dev/null
+++ b/intern/cycles/kernel/kernel_image_opencl.h
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/* For OpenCL all images are packed in a single array, and we do manual lookup
+ * and interpolation. */
+
+ccl_device_inline float4 svm_image_texture_read(KernelGlobals *kg, int id, int offset)
+{
+ /* Float4 */
+ if(id < TEX_START_BYTE4_OPENCL) {
+ return kernel_tex_fetch(__tex_image_float4_packed, offset);
+ }
+ /* Byte4 */
+ else if(id < TEX_START_FLOAT_OPENCL) {
+ uchar4 r = kernel_tex_fetch(__tex_image_byte4_packed, offset);
+ float f = 1.0f/255.0f;
+ return make_float4(r.x*f, r.y*f, r.z*f, r.w*f);
+ }
+ /* Float */
+ else if(id < TEX_START_BYTE_OPENCL) {
+ float f = kernel_tex_fetch(__tex_image_float_packed, offset);
+ return make_float4(f, f, f, 1.0f);
+ }
+ /* Byte */
+ else {
+ uchar r = kernel_tex_fetch(__tex_image_byte_packed, offset);
+ float f = r * (1.0f/255.0f);
+ return make_float4(f, f, f, 1.0f);
+ }
+}
+
+ccl_device_inline int svm_image_texture_wrap_periodic(int x, int width)
+{
+ x %= width;
+ if(x < 0)
+ x += width;
+ return x;
+}
+
+ccl_device_inline int svm_image_texture_wrap_clamp(int x, int width)
+{
+ return clamp(x, 0, width-1);
+}
+
+ccl_device_inline float svm_image_texture_frac(float x, int *ix)
+{
+ int i = float_to_int(x) - ((x < 0.0f)? 1: 0);
+ *ix = i;
+ return x - (float)i;
+}
+
+ccl_device float4 kernel_tex_image_interp(KernelGlobals *kg, int id, float x, float y)
+{
+ uint4 info = kernel_tex_fetch(__tex_image_packed_info, id*2);
+ uint width = info.x;
+ uint height = info.y;
+ uint offset = info.z;
+
+ /* Image Options */
+ uint interpolation = (info.w & (1 << 0)) ? INTERPOLATION_CLOSEST : INTERPOLATION_LINEAR;
+ uint extension;
+ if(info.w & (1 << 1))
+ extension = EXTENSION_REPEAT;
+ else if(info.w & (1 << 2))
+ extension = EXTENSION_EXTEND;
+ else
+ extension = EXTENSION_CLIP;
+
+ float4 r;
+ int ix, iy, nix, niy;
+ if(interpolation == INTERPOLATION_CLOSEST) {
+ svm_image_texture_frac(x*width, &ix);
+ svm_image_texture_frac(y*height, &iy);
+
+ if(extension == EXTENSION_REPEAT) {
+ ix = svm_image_texture_wrap_periodic(ix, width);
+ iy = svm_image_texture_wrap_periodic(iy, height);
+ }
+ else {
+ if(extension == EXTENSION_CLIP) {
+ if(x < 0.0f || y < 0.0f || x > 1.0f || y > 1.0f) {
+ return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+ }
+ /* Fall through. */
+ /* EXTENSION_EXTEND */
+ ix = svm_image_texture_wrap_clamp(ix, width);
+ iy = svm_image_texture_wrap_clamp(iy, height);
+ }
+
+ r = svm_image_texture_read(kg, id, offset + ix + iy*width);
+ }
+ else { /* INTERPOLATION_LINEAR */
+ float tx = svm_image_texture_frac(x*width - 0.5f, &ix);
+ float ty = svm_image_texture_frac(y*height - 0.5f, &iy);
+
+ if(extension == EXTENSION_REPEAT) {
+ ix = svm_image_texture_wrap_periodic(ix, width);
+ iy = svm_image_texture_wrap_periodic(iy, height);
+
+ nix = svm_image_texture_wrap_periodic(ix+1, width);
+ niy = svm_image_texture_wrap_periodic(iy+1, height);
+ }
+ else {
+ if(extension == EXTENSION_CLIP) {
+ if(x < 0.0f || y < 0.0f || x > 1.0f || y > 1.0f) {
+ return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+ }
+ nix = svm_image_texture_wrap_clamp(ix+1, width);
+ niy = svm_image_texture_wrap_clamp(iy+1, height);
+ ix = svm_image_texture_wrap_clamp(ix, width);
+ iy = svm_image_texture_wrap_clamp(iy, height);
+ }
+
+ r = (1.0f - ty)*(1.0f - tx)*svm_image_texture_read(kg, id, offset + ix + iy*width);
+ r += (1.0f - ty)*tx*svm_image_texture_read(kg, id, offset + nix + iy*width);
+ r += ty*(1.0f - tx)*svm_image_texture_read(kg, id, offset + ix + niy*width);
+ r += ty*tx*svm_image_texture_read(kg, id, offset + nix + niy*width);
+ }
+
+ return r;
+}
+
+
+ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals *kg, int id, float x, float y, float z)
+{
+ uint4 info = kernel_tex_fetch(__tex_image_packed_info, id*2);
+ uint width = info.x;
+ uint height = info.y;
+ uint offset = info.z;
+ uint depth = kernel_tex_fetch(__tex_image_packed_info, id*2+1).x;
+
+ /* Image Options */
+ uint interpolation = (info.w & (1 << 0)) ? INTERPOLATION_CLOSEST : INTERPOLATION_LINEAR;
+ uint extension;
+ if(info.w & (1 << 1))
+ extension = EXTENSION_REPEAT;
+ else if(info.w & (1 << 2))
+ extension = EXTENSION_EXTEND;
+ else
+ extension = EXTENSION_CLIP;
+
+ float4 r;
+ int ix, iy, iz, nix, niy, niz;
+ if(interpolation == INTERPOLATION_CLOSEST) {
+ svm_image_texture_frac(x*width, &ix);
+ svm_image_texture_frac(y*height, &iy);
+ svm_image_texture_frac(z*depth, &iz);
+
+ if(extension == EXTENSION_REPEAT) {
+ ix = svm_image_texture_wrap_periodic(ix, width);
+ iy = svm_image_texture_wrap_periodic(iy, height);
+ iz = svm_image_texture_wrap_periodic(iz, depth);
+ }
+ else {
+ if(extension == EXTENSION_CLIP) {
+ if(x < 0.0f || y < 0.0f || z < 0.0f ||
+ x > 1.0f || y > 1.0f || z > 1.0f)
+ {
+ return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+ }
+ /* Fall through. */
+ /* EXTENSION_EXTEND */
+ ix = svm_image_texture_wrap_clamp(ix, width);
+ iy = svm_image_texture_wrap_clamp(iy, height);
+ iz = svm_image_texture_wrap_clamp(iz, depth);
+ }
+ r = svm_image_texture_read(kg, id, offset + ix + iy*width + iz*width*height);
+ }
+ else { /* INTERPOLATION_LINEAR */
+ float tx = svm_image_texture_frac(x*(float)width - 0.5f, &ix);
+ float ty = svm_image_texture_frac(y*(float)height - 0.5f, &iy);
+ float tz = svm_image_texture_frac(z*(float)depth - 0.5f, &iz);
+
+ if(extension == EXTENSION_REPEAT) {
+ ix = svm_image_texture_wrap_periodic(ix, width);
+ iy = svm_image_texture_wrap_periodic(iy, height);
+ iz = svm_image_texture_wrap_periodic(iz, depth);
+
+ nix = svm_image_texture_wrap_periodic(ix+1, width);
+ niy = svm_image_texture_wrap_periodic(iy+1, height);
+ niz = svm_image_texture_wrap_periodic(iz+1, depth);
+ }
+ else {
+ if(extension == EXTENSION_CLIP)
+ if(x < 0.0f || y < 0.0f || z < 0.0f ||
+ x > 1.0f || y > 1.0f || z > 1.0f)
+ {
+ return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+ /* Fall through. */
+ /* EXTENSION_EXTEND */
+ nix = svm_image_texture_wrap_clamp(ix+1, width);
+ niy = svm_image_texture_wrap_clamp(iy+1, height);
+ niz = svm_image_texture_wrap_clamp(iz+1, depth);
+
+ ix = svm_image_texture_wrap_clamp(ix, width);
+ iy = svm_image_texture_wrap_clamp(iy, height);
+ iz = svm_image_texture_wrap_clamp(iz, depth);
+ }
+
+ r = (1.0f - tz)*(1.0f - ty)*(1.0f - tx)*svm_image_texture_read(kg, id, offset + ix + iy*width + iz*width*height);
+ r += (1.0f - tz)*(1.0f - ty)*tx*svm_image_texture_read(kg, id, offset + nix + iy*width + iz*width*height);
+ r += (1.0f - tz)*ty*(1.0f - tx)*svm_image_texture_read(kg, id, offset + ix + niy*width + iz*width*height);
+ r += (1.0f - tz)*ty*tx*svm_image_texture_read(kg, id, offset + nix + niy*width + iz*width*height);
+
+ r += tz*(1.0f - ty)*(1.0f - tx)*svm_image_texture_read(kg, id, offset + ix + iy*width + niz*width*height);
+ r += tz*(1.0f - ty)*tx*svm_image_texture_read(kg, id, offset + nix + iy*width + niz*width*height);
+ r += tz*ty*(1.0f - tx)*svm_image_texture_read(kg, id, offset + ix + niy*width + niz*width*height);
+ r += tz*ty*tx*svm_image_texture_read(kg, id, offset + nix + niy*width + niz*width*height);
+
+ }
+
+ return r;
+}
diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h
index 675eacfc5ee..d4cc36d1495 100644
--- a/intern/cycles/kernel/kernel_light.h
+++ b/intern/cycles/kernel/kernel_light.h
@@ -44,15 +44,15 @@ typedef struct LightSample {
*
* Note: light_p is modified when sample_coord is true.
*/
-ccl_device float area_light_sample(float3 P,
- float3 *light_p,
- float3 axisu, float3 axisv,
- float randu, float randv,
- bool sample_coord)
+ccl_device_inline float area_light_sample(float3 P,
+ float3 *light_p,
+ float3 axisu, float3 axisv,
+ float randu, float randv,
+ bool sample_coord)
{
/* In our name system we're using P for the center,
- * which is o in the paper.
- */
+ * which is o in the paper.
+ */
float3 corner = *light_p - axisu * 0.5f - axisv * 0.5f;
float axisu_len, axisv_len;
@@ -268,11 +268,11 @@ ccl_device_inline bool background_portal_data_fetch_and_check_side(KernelGlobals
return false;
}
-ccl_device float background_portal_pdf(KernelGlobals *kg,
- float3 P,
- float3 direction,
- int ignore_portal,
- bool *is_possible)
+ccl_device_inline float background_portal_pdf(KernelGlobals *kg,
+ float3 P,
+ float3 direction,
+ int ignore_portal,
+ bool *is_possible)
{
float portal_pdf = 0.0f;
@@ -291,24 +291,13 @@ ccl_device float background_portal_pdf(KernelGlobals *kg,
}
num_possible++;
- float t = -(dot(P, dir) - dot(lightpos, dir)) / dot(direction, dir);
- if(t <= 1e-4f) {
- /* Either behind the portal or too close. */
- continue;
- }
-
float4 data1 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 1);
float4 data2 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 2);
float3 axisu = make_float3(data1.y, data1.z, data1.w);
float3 axisv = make_float3(data2.y, data2.z, data2.w);
- float3 hit = P + t*direction;
- float3 inplane = hit - lightpos;
- /* Skip if the the ray doesn't pass through portal. */
- if(fabsf(dot(inplane, axisu) / dot(axisu, axisu)) > 0.5f)
- continue;
- if(fabsf(dot(inplane, axisv) / dot(axisv, axisv)) > 0.5f)
+ if(!ray_quad_intersect(P, direction, 1e-4f, FLT_MAX, lightpos, axisu, axisv, dir, NULL, NULL, NULL, NULL))
continue;
portal_pdf += area_light_sample(P, &lightpos, axisu, axisv, 0.0f, 0.0f, false);
@@ -378,7 +367,10 @@ ccl_device float3 background_portal_sample(KernelGlobals *kg,
return make_float3(0.0f, 0.0f, 0.0f);
}
-ccl_device float3 background_light_sample(KernelGlobals *kg, float3 P, float randu, float randv, float *pdf)
+ccl_device_inline float3 background_light_sample(KernelGlobals *kg,
+ float3 P,
+ float randu, float randv,
+ float *pdf)
{
/* Probability of sampling portals instead of the map. */
float portal_sampling_pdf = kernel_data.integrator.portal_pdf;
@@ -518,8 +510,11 @@ ccl_device float lamp_light_pdf(KernelGlobals *kg, const float3 Ng, const float3
return t*t/cos_pi;
}
-ccl_device void lamp_light_sample(KernelGlobals *kg, int lamp,
- float randu, float randv, float3 P, LightSample *ls)
+ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
+ int lamp,
+ float randu, float randv,
+ float3 P,
+ LightSample *ls)
{
float4 data0 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 0);
float4 data1 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 1);
@@ -586,7 +581,14 @@ ccl_device void lamp_light_sample(KernelGlobals *kg, int lamp,
/* spot light attenuation */
float4 data2 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 2);
ls->eval_fac *= spot_light_attenuation(data1, data2, ls);
+ if(ls->eval_fac == 0.0f) {
+ return false;
+ }
}
+ float2 uv = map_to_sphere(ls->Ng);
+ ls->u = uv.x;
+ ls->v = uv.y;
+
ls->pdf *= lamp_light_pdf(kg, ls->Ng, -ls->D, ls->t);
}
else {
@@ -598,23 +600,31 @@ ccl_device void lamp_light_sample(KernelGlobals *kg, int lamp,
float3 axisv = make_float3(data2.y, data2.z, data2.w);
float3 D = make_float3(data3.y, data3.z, data3.w);
+ if(dot(ls->P - P, D) > 0.0f) {
+ return false;
+ }
+
+ float3 inplane = ls->P;
ls->pdf = area_light_sample(P, &ls->P,
axisu, axisv,
randu, randv,
true);
+ inplane = ls->P - inplane;
+ ls->u = dot(inplane, axisu) * (1.0f / dot(axisu, axisu)) + 0.5f;
+ ls->v = dot(inplane, axisv) * (1.0f / dot(axisv, axisv)) + 0.5f;
+
ls->Ng = D;
ls->D = normalize_len(ls->P - P, &ls->t);
float invarea = data2.x;
ls->eval_fac = 0.25f*invarea;
-
- if(dot(ls->D, D) > 0.0f)
- ls->pdf = 0.0f;
}
ls->eval_fac *= kernel_data.integrator.inv_pdf_lights;
}
+
+ return (ls->pdf > 0.0f);
}
ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D, float t, LightSample *ls)
@@ -705,6 +715,9 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D,
if(ls->eval_fac == 0.0f)
return false;
}
+ float2 uv = map_to_sphere(ls->Ng);
+ ls->u = uv.x;
+ ls->v = uv.y;
/* compute pdf */
if(ls->t != FLT_MAX)
@@ -729,8 +742,10 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D,
float3 light_P = make_float3(data0.y, data0.z, data0.w);
- if(!ray_quad_intersect(P, D, t,
- light_P, axisu, axisv, &ls->P, &ls->t))
+ if(!ray_quad_intersect(P, D, 0.0f, t, light_P,
+ axisu, axisv, Ng,
+ &ls->P, &ls->t,
+ &ls->u, &ls->v))
{
return false;
}
@@ -752,7 +767,7 @@ ccl_device void object_transform_light_sample(KernelGlobals *kg, LightSample *ls
{
#ifdef __INSTANCING__
/* instance transform */
- if(object >= 0) {
+ if(!(kernel_tex_fetch(__object_flag, object) & SD_TRANSFORM_APPLIED)) {
# ifdef __OBJECT_MOTION__
Transform itfm;
Transform tfm = object_fetch_transform_motion_test(kg, object, time, &itfm);
@@ -841,7 +856,7 @@ ccl_device bool light_select_reached_max_bounces(KernelGlobals *kg, int index, i
return (bounce > __float_as_int(data4.x));
}
-ccl_device_noinline void light_sample(KernelGlobals *kg,
+ccl_device_noinline bool light_sample(KernelGlobals *kg,
float randt,
float randu,
float randv,
@@ -862,21 +877,20 @@ ccl_device_noinline void light_sample(KernelGlobals *kg,
int shader_flag = __float_as_int(l.z);
triangle_light_sample(kg, prim, object, randu, randv, time, ls);
-
/* compute incoming direction, distance and pdf */
ls->D = normalize_len(ls->P - P, &ls->t);
ls->pdf = triangle_light_pdf(kg, ls->Ng, -ls->D, ls->t);
ls->shader |= shader_flag;
+ return (ls->pdf > 0.0f);
}
else {
int lamp = -prim-1;
if(UNLIKELY(light_select_reached_max_bounces(kg, lamp, bounce))) {
- ls->pdf = 0.0f;
- return;
+ return false;
}
- lamp_light_sample(kg, lamp, randu, randv, P, ls);
+ return lamp_light_sample(kg, lamp, randu, randv, P, ls);
}
}
@@ -887,4 +901,3 @@ ccl_device int light_select_num_samples(KernelGlobals *kg, int index)
}
CCL_NAMESPACE_END
-
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h
index c136c85df59..7558fb94478 100644
--- a/intern/cycles/kernel/kernel_path.h
+++ b/intern/cycles/kernel/kernel_path.h
@@ -25,6 +25,7 @@
#include "kernel_camera.h"
#include "geom/geom.h"
+#include "bvh/bvh.h"
#include "kernel_accumulate.h"
#include "kernel_shader.h"
@@ -53,6 +54,8 @@
CCL_NAMESPACE_BEGIN
ccl_device void kernel_path_indirect(KernelGlobals *kg,
+ ShaderData *sd,
+ ShaderData *emission_sd,
RNG *rng,
Ray *ray,
float3 throughput,
@@ -66,7 +69,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
Intersection isect;
uint visibility = path_state_ray_visibility(kg, state);
bool hit = scene_intersect(kg,
- ray,
+ *ray,
visibility,
&isect,
NULL,
@@ -87,7 +90,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
/* intersect with lamp */
float3 emission;
- if(indirect_lamp_emission(kg, state, &light_ray, &emission)) {
+ if(indirect_lamp_emission(kg, emission_sd, state, &light_ray, &emission)) {
path_radiance_accum_emission(L,
throughput,
emission,
@@ -115,15 +118,14 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
if(decoupled) {
/* cache steps along volume for repeated sampling */
VolumeSegment volume_segment;
- ShaderData volume_sd;
shader_setup_from_volume(kg,
- &volume_sd,
+ sd,
&volume_ray);
kernel_volume_decoupled_record(kg,
state,
&volume_ray,
- &volume_sd,
+ sd,
&volume_segment,
heterogeneous);
@@ -146,7 +148,8 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
/* direct light sampling */
kernel_branched_path_volume_connect_light(kg,
rng,
- &volume_sd,
+ sd,
+ emission_sd,
throughput,
state,
L,
@@ -163,7 +166,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
result = kernel_volume_decoupled_scatter(kg,
state,
&volume_ray,
- &volume_sd,
+ sd,
&throughput,
rphase,
rscatter,
@@ -178,7 +181,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
if(result == VOLUME_PATH_SCATTERED) {
if(kernel_path_volume_bounce(kg,
rng,
- &volume_sd,
+ sd,
&throughput,
state,
L,
@@ -198,16 +201,16 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
# endif
{
/* integrate along volume segment with distance sampling */
- ShaderData volume_sd;
VolumeIntegrateResult result = kernel_volume_integrate(
- kg, state, &volume_sd, &volume_ray, L, &throughput, rng, heterogeneous);
+ kg, state, sd, &volume_ray, L, &throughput, rng, heterogeneous);
# ifdef __VOLUME_SCATTER__
if(result == VOLUME_PATH_SCATTERED) {
/* direct lighting */
kernel_path_volume_connect_light(kg,
rng,
- &volume_sd,
+ sd,
+ emission_sd,
throughput,
state,
L);
@@ -215,7 +218,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
/* indirect light bounce */
if(kernel_path_volume_bounce(kg,
rng,
- &volume_sd,
+ sd,
&throughput,
state,
L,
@@ -235,7 +238,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
if(!hit) {
#ifdef __BACKGROUND__
/* sample background shader */
- float3 L_background = indirect_background(kg, state, ray);
+ float3 L_background = indirect_background(kg, emission_sd, state, ray);
path_radiance_accum_background(L,
throughput,
L_background,
@@ -246,15 +249,14 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
}
/* setup shading */
- ShaderData sd;
shader_setup_from_ray(kg,
- &sd,
+ sd,
&isect,
ray);
float rbsdf = path_state_rng_1D_for_decision(kg, rng, state, PRNG_BSDF);
- shader_eval_surface(kg, &sd, state, rbsdf, state->flag, SHADER_CONTEXT_INDIRECT);
+ shader_eval_surface(kg, sd, rng, state, rbsdf, state->flag, SHADER_CONTEXT_INDIRECT);
#ifdef __BRANCHED_PATH__
- shader_merge_closures(&sd);
+ shader_merge_closures(sd);
#endif
/* blurring of bsdf after bounces, for rays that have a small likelihood
@@ -264,15 +266,15 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
if(blur_pdf < 1.0f) {
float blur_roughness = sqrtf(1.0f - blur_pdf)*0.5f;
- shader_bsdf_blur(kg, &sd, blur_roughness);
+ shader_bsdf_blur(kg, sd, blur_roughness);
}
}
#ifdef __EMISSION__
/* emission */
- if(sd.flag & SD_EMISSION) {
+ if(sd->flag & SD_EMISSION) {
float3 emission = indirect_primitive_emission(kg,
- &sd,
+ sd,
isect.t,
state->flag,
state->ray_pdf);
@@ -302,33 +304,33 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
#ifdef __AO__
/* ambient occlusion */
- if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) {
+ if(kernel_data.integrator.use_ambient_occlusion || (sd->flag & SD_AO)) {
float bsdf_u, bsdf_v;
path_state_rng_2D(kg, rng, state, PRNG_BSDF_U, &bsdf_u, &bsdf_v);
float ao_factor = kernel_data.background.ao_factor;
float3 ao_N;
- float3 ao_bsdf = shader_bsdf_ao(kg, &sd, ao_factor, &ao_N);
+ float3 ao_bsdf = shader_bsdf_ao(kg, sd, ao_factor, &ao_N);
float3 ao_D;
float ao_pdf;
float3 ao_alpha = make_float3(0.0f, 0.0f, 0.0f);
sample_cos_hemisphere(ao_N, bsdf_u, bsdf_v, &ao_D, &ao_pdf);
- if(dot(sd.Ng, ao_D) > 0.0f && ao_pdf != 0.0f) {
+ if(dot(sd->Ng, ao_D) > 0.0f && ao_pdf != 0.0f) {
Ray light_ray;
float3 ao_shadow;
- light_ray.P = ray_offset(sd.P, sd.Ng);
+ light_ray.P = ray_offset(sd->P, sd->Ng);
light_ray.D = ao_D;
light_ray.t = kernel_data.background.ao_distance;
# ifdef __OBJECT_MOTION__
- light_ray.time = sd.time;
+ light_ray.time = sd->time;
# endif
- light_ray.dP = sd.dP;
+ light_ray.dP = sd->dP;
light_ray.dD = differential3_zero();
- if(!shadow_blocked(kg, state, &light_ray, &ao_shadow)) {
+ if(!shadow_blocked(kg, emission_sd, state, &light_ray, &ao_shadow)) {
path_radiance_accum_ao(L,
throughput,
ao_alpha,
@@ -343,9 +345,9 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
#ifdef __SUBSURFACE__
/* bssrdf scatter to a different location on the same object, replacing
* the closures with a diffuse BSDF */
- if(sd.flag & SD_BSSRDF) {
+ if(sd->flag & SD_BSSRDF) {
float bssrdf_probability;
- ShaderClosure *sc = subsurface_scatter_pick_closure(kg, &sd, &bssrdf_probability);
+ ShaderClosure *sc = subsurface_scatter_pick_closure(kg, sd, &bssrdf_probability);
/* modify throughput for picking bssrdf or bsdf */
throughput *= bssrdf_probability;
@@ -361,7 +363,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
PRNG_BSDF_U,
&bssrdf_u, &bssrdf_v);
subsurface_scatter_step(kg,
- &sd,
+ sd,
state,
state->flag,
sc,
@@ -377,7 +379,8 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
int all = kernel_data.integrator.sample_all_lights_indirect;
kernel_branched_path_surface_connect_light(kg,
rng,
- &sd,
+ sd,
+ emission_sd,
state,
throughput,
1.0f,
@@ -386,13 +389,14 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
}
#endif
- if(!kernel_path_surface_bounce(kg, rng, &sd, &throughput, state, L, ray))
+ if(!kernel_path_surface_bounce(kg, rng, sd, &throughput, state, L, ray))
break;
}
}
ccl_device_noinline void kernel_path_ao(KernelGlobals *kg,
ShaderData *sd,
+ ShaderData *emission_sd,
PathRadiance *L,
PathState *state,
RNG *rng,
@@ -425,16 +429,21 @@ ccl_device_noinline void kernel_path_ao(KernelGlobals *kg,
light_ray.dP = ccl_fetch(sd, dP);
light_ray.dD = differential3_zero();
- if(!shadow_blocked(kg, state, &light_ray, &ao_shadow))
+ if(!shadow_blocked(kg, emission_sd, state, &light_ray, &ao_shadow))
path_radiance_accum_ao(L, throughput, ao_alpha, ao_bsdf, ao_shadow, state->bounce);
}
}
#ifdef __SUBSURFACE__
-
-ccl_device bool kernel_path_subsurface_scatter(
+# ifndef __KERNEL_CUDA__
+ccl_device
+# else
+ccl_device_inline
+# endif
+bool kernel_path_subsurface_scatter(
KernelGlobals *kg,
ShaderData *sd,
+ ShaderData *emission_sd,
PathRadiance *L,
PathState *state,
RNG *rng,
@@ -503,7 +512,7 @@ ccl_device bool kernel_path_subsurface_scatter(
hit_L->direct_throughput = L->direct_throughput;
path_radiance_copy_indirect(hit_L, L);
- kernel_path_surface_connect_light(kg, rng, sd, *hit_tp, state, hit_L);
+ kernel_path_surface_connect_light(kg, rng, sd, emission_sd, *hit_tp, state, hit_L);
if(kernel_path_surface_bounce(kg,
rng,
@@ -526,6 +535,7 @@ ccl_device bool kernel_path_subsurface_scatter(
kernel_volume_stack_update_for_subsurface(
kg,
+ emission_sd,
&volume_ray,
hit_state->volume_stack);
}
@@ -604,8 +614,13 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
path_radiance_init(&L, kernel_data.film.use_light_pass);
+ /* shader data memory used for both volumes and surfaces, saves stack space */
+ ShaderData sd;
+ /* shader data used by emission, shadows, volume stacks */
+ ShaderData emission_sd;
+
PathState state;
- path_state_init(kg, &state, rng, sample, &ray);
+ path_state_init(kg, &emission_sd, &state, rng, sample, &ray);
#ifdef __KERNEL_DEBUG__
DebugData debug_data;
@@ -640,9 +655,9 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
lcg_state = lcg_state_init(rng, &state, 0x51633e2d);
}
- bool hit = scene_intersect(kg, &ray, visibility, &isect, &lcg_state, difl, extmax);
+ bool hit = scene_intersect(kg, ray, visibility, &isect, &lcg_state, difl, extmax);
#else
- bool hit = scene_intersect(kg, &ray, visibility, &isect, NULL, 0.0f, 0.0f);
+ bool hit = scene_intersect(kg, ray, visibility, &isect, NULL, 0.0f, 0.0f);
#endif
#ifdef __KERNEL_DEBUG__
@@ -669,7 +684,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
/* intersect with lamp */
float3 emission;
- if(indirect_lamp_emission(kg, &state, &light_ray, &emission))
+ if(indirect_lamp_emission(kg, &emission_sd, &state, &light_ray, &emission))
path_radiance_accum_emission(&L, throughput, emission, state.bounce);
}
#endif
@@ -689,11 +704,10 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
if(decoupled) {
/* cache steps along volume for repeated sampling */
VolumeSegment volume_segment;
- ShaderData volume_sd;
- shader_setup_from_volume(kg, &volume_sd, &volume_ray);
+ shader_setup_from_volume(kg, &sd, &volume_ray);
kernel_volume_decoupled_record(kg, &state,
- &volume_ray, &volume_sd, &volume_segment, heterogeneous);
+ &volume_ray, &sd, &volume_segment, heterogeneous);
volume_segment.sampling_method = sampling_method;
@@ -708,8 +722,9 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
int all = false;
/* direct light sampling */
- kernel_branched_path_volume_connect_light(kg, rng, &volume_sd,
- throughput, &state, &L, all, &volume_ray, &volume_segment);
+ kernel_branched_path_volume_connect_light(kg, rng, &sd,
+ &emission_sd, throughput, &state, &L, all,
+ &volume_ray, &volume_segment);
/* indirect sample. if we use distance sampling and take just
* one sample for direct and indirect light, we could share
@@ -718,7 +733,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
float rscatter = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_SCATTER_DISTANCE);
result = kernel_volume_decoupled_scatter(kg,
- &state, &volume_ray, &volume_sd, &throughput,
+ &state, &volume_ray, &sd, &throughput,
rphase, rscatter, &volume_segment, NULL, true);
}
@@ -726,7 +741,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
kernel_volume_decoupled_free(kg, &volume_segment);
if(result == VOLUME_PATH_SCATTERED) {
- if(kernel_path_volume_bounce(kg, rng, &volume_sd, &throughput, &state, &L, &ray))
+ if(kernel_path_volume_bounce(kg, rng, &sd, &throughput, &state, &L, &ray))
continue;
else
break;
@@ -739,17 +754,16 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
# endif
{
/* integrate along volume segment with distance sampling */
- ShaderData volume_sd;
VolumeIntegrateResult result = kernel_volume_integrate(
- kg, &state, &volume_sd, &volume_ray, &L, &throughput, rng, heterogeneous);
+ kg, &state, &sd, &volume_ray, &L, &throughput, rng, heterogeneous);
# ifdef __VOLUME_SCATTER__
if(result == VOLUME_PATH_SCATTERED) {
/* direct lighting */
- kernel_path_volume_connect_light(kg, rng, &volume_sd, throughput, &state, &L);
+ kernel_path_volume_connect_light(kg, rng, &sd, &emission_sd, throughput, &state, &L);
/* indirect light bounce */
- if(kernel_path_volume_bounce(kg, rng, &volume_sd, &throughput, &state, &L, &ray))
+ if(kernel_path_volume_bounce(kg, rng, &sd, &throughput, &state, &L, &ray))
continue;
else
break;
@@ -772,7 +786,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
#ifdef __BACKGROUND__
/* sample background shader */
- float3 L_background = indirect_background(kg, &state, &ray);
+ float3 L_background = indirect_background(kg, &emission_sd, &state, &ray);
path_radiance_accum_background(&L, throughput, L_background, state.bounce);
#endif
@@ -780,10 +794,9 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
}
/* setup shading */
- ShaderData sd;
shader_setup_from_ray(kg, &sd, &isect, &ray);
float rbsdf = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_BSDF);
- shader_eval_surface(kg, &sd, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN);
+ shader_eval_surface(kg, &sd, rng, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN);
/* holdout */
#ifdef __HOLDOUT__
@@ -848,7 +861,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
#ifdef __AO__
/* ambient occlusion */
if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) {
- kernel_path_ao(kg, &sd, &L, &state, rng, throughput);
+ kernel_path_ao(kg, &sd, &emission_sd, &L, &state, rng, throughput);
}
#endif
@@ -858,6 +871,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
if(sd.flag & SD_BSSRDF) {
if(kernel_path_subsurface_scatter(kg,
&sd,
+ &emission_sd,
&L,
&state,
rng,
@@ -871,7 +885,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
#endif /* __SUBSURFACE__ */
/* direct lighting */
- kernel_path_surface_connect_light(kg, rng, &sd, throughput, &state, &L);
+ kernel_path_surface_connect_light(kg, rng, &sd, &emission_sd, throughput, &state, &L);
/* compute direct lighting and next bounce */
if(!kernel_path_surface_bounce(kg, rng, &sd, &throughput, &state, &L, &ray))
diff --git a/intern/cycles/kernel/kernel_path_branched.h b/intern/cycles/kernel/kernel_path_branched.h
index 13ae4cf669b..cdb07db587a 100644
--- a/intern/cycles/kernel/kernel_path_branched.h
+++ b/intern/cycles/kernel/kernel_path_branched.h
@@ -18,7 +18,13 @@ CCL_NAMESPACE_BEGIN
#ifdef __BRANCHED_PATH__
-ccl_device void kernel_branched_path_ao(KernelGlobals *kg, ShaderData *sd, PathRadiance *L, PathState *state, RNG *rng, float3 throughput)
+ccl_device_inline void kernel_branched_path_ao(KernelGlobals *kg,
+ ShaderData *sd,
+ ShaderData *emission_sd,
+ PathRadiance *L,
+ PathState *state,
+ RNG *rng,
+ float3 throughput)
{
int num_samples = kernel_data.integrator.ao_samples;
float num_samples_inv = 1.0f/num_samples;
@@ -49,7 +55,7 @@ ccl_device void kernel_branched_path_ao(KernelGlobals *kg, ShaderData *sd, PathR
light_ray.dP = ccl_fetch(sd, dP);
light_ray.dD = differential3_zero();
- if(!shadow_blocked(kg, state, &light_ray, &ao_shadow))
+ if(!shadow_blocked(kg, emission_sd, state, &light_ray, &ao_shadow))
path_radiance_accum_ao(L, throughput*num_samples_inv, ao_alpha, ao_bsdf, ao_shadow, state->bounce);
}
}
@@ -58,8 +64,8 @@ ccl_device void kernel_branched_path_ao(KernelGlobals *kg, ShaderData *sd, PathR
/* bounce off surface and integrate indirect light */
ccl_device_noinline void kernel_branched_path_surface_indirect_light(KernelGlobals *kg,
- RNG *rng, ShaderData *sd, float3 throughput, float num_samples_adjust,
- PathState *state, PathRadiance *L)
+ RNG *rng, ShaderData *sd, ShaderData *indirect_sd, ShaderData *emission_sd,
+ float3 throughput, float num_samples_adjust, PathState *state, PathRadiance *L)
{
for(int i = 0; i < ccl_fetch(sd, num_closure); i++) {
const ShaderClosure *sc = &ccl_fetch(sd, closure)[i];
@@ -106,6 +112,8 @@ ccl_device_noinline void kernel_branched_path_surface_indirect_light(KernelGloba
}
kernel_path_indirect(kg,
+ indirect_sd,
+ emission_sd,
rng,
&bsdf_ray,
tp*num_samples_inv,
@@ -124,6 +132,8 @@ ccl_device_noinline void kernel_branched_path_surface_indirect_light(KernelGloba
#ifdef __SUBSURFACE__
ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg,
ShaderData *sd,
+ ShaderData *indirect_sd,
+ ShaderData *emission_sd,
PathRadiance *L,
PathState *state,
RNG *rng,
@@ -186,6 +196,7 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg,
kernel_volume_stack_update_for_subsurface(
kg,
+ emission_sd,
&volume_ray,
hit_state.volume_stack);
}
@@ -199,6 +210,7 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg,
kg,
rng,
&bssrdf_sd,
+ emission_sd,
&hit_state,
throughput,
num_samples_inv,
@@ -212,6 +224,8 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg,
kg,
rng,
&bssrdf_sd,
+ indirect_sd,
+ emission_sd,
throughput,
num_samples_inv,
&hit_state,
@@ -231,8 +245,13 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
path_radiance_init(&L, kernel_data.film.use_light_pass);
+ /* shader data memory used for both volumes and surfaces, saves stack space */
+ ShaderData sd;
+ /* shader data used by emission, shadows, volume stacks, indirect path */
+ ShaderData emission_sd, indirect_sd;
+
PathState state;
- path_state_init(kg, &state, rng, sample, &ray);
+ path_state_init(kg, &emission_sd, &state, rng, sample, &ray);
#ifdef __KERNEL_DEBUG__
DebugData debug_data;
@@ -263,9 +282,9 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
lcg_state = lcg_state_init(rng, &state, 0x51633e2d);
}
- bool hit = scene_intersect(kg, &ray, visibility, &isect, &lcg_state, difl, extmax);
+ bool hit = scene_intersect(kg, ray, visibility, &isect, &lcg_state, difl, extmax);
#else
- bool hit = scene_intersect(kg, &ray, visibility, &isect, NULL, 0.0f, 0.0f);
+ bool hit = scene_intersect(kg, ray, visibility, &isect, NULL, 0.0f, 0.0f);
#endif
#ifdef __KERNEL_DEBUG__
@@ -287,11 +306,10 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
/* cache steps along volume for repeated sampling */
VolumeSegment volume_segment;
- ShaderData volume_sd;
- shader_setup_from_volume(kg, &volume_sd, &volume_ray);
+ shader_setup_from_volume(kg, &sd, &volume_ray);
kernel_volume_decoupled_record(kg, &state,
- &volume_ray, &volume_sd, &volume_segment, heterogeneous);
+ &volume_ray, &sd, &volume_segment, heterogeneous);
/* direct light sampling */
if(volume_segment.closure_flag & SD_SCATTER) {
@@ -299,8 +317,9 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
int all = kernel_data.integrator.sample_all_lights_direct;
- kernel_branched_path_volume_connect_light(kg, rng, &volume_sd,
- throughput, &state, &L, all, &volume_ray, &volume_segment);
+ kernel_branched_path_volume_connect_light(kg, rng, &sd,
+ &emission_sd, throughput, &state, &L, all,
+ &volume_ray, &volume_segment);
/* indirect light sampling */
int num_samples = kernel_data.integrator.volume_samples;
@@ -326,20 +345,22 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
float rscatter = path_state_rng_1D_for_decision(kg, &tmp_rng, &ps, PRNG_SCATTER_DISTANCE);
VolumeIntegrateResult result = kernel_volume_decoupled_scatter(kg,
- &ps, &pray, &volume_sd, &tp, rphase, rscatter, &volume_segment, NULL, false);
+ &ps, &pray, &sd, &tp, rphase, rscatter, &volume_segment, NULL, false);
(void)result;
kernel_assert(result == VOLUME_PATH_SCATTERED);
if(kernel_path_volume_bounce(kg,
rng,
- &volume_sd,
+ &sd,
&tp,
&ps,
&L,
&pray))
{
kernel_path_indirect(kg,
+ &indirect_sd,
+ &emission_sd,
rng,
&pray,
tp*num_samples_inv,
@@ -373,30 +394,31 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
for(int j = 0; j < num_samples; j++) {
PathState ps = state;
Ray pray = ray;
- ShaderData volume_sd;
float3 tp = throughput * num_samples_inv;
/* branch RNG state */
path_state_branch(&ps, j, num_samples);
VolumeIntegrateResult result = kernel_volume_integrate(
- kg, &ps, &volume_sd, &volume_ray, &L, &tp, rng, heterogeneous);
+ kg, &ps, &sd, &volume_ray, &L, &tp, rng, heterogeneous);
#ifdef __VOLUME_SCATTER__
if(result == VOLUME_PATH_SCATTERED) {
/* todo: support equiangular, MIS and all light sampling.
* alternatively get decoupled ray marching working on the GPU */
- kernel_path_volume_connect_light(kg, rng, &volume_sd, tp, &state, &L);
+ kernel_path_volume_connect_light(kg, rng, &sd, &emission_sd, tp, &state, &L);
if(kernel_path_volume_bounce(kg,
rng,
- &volume_sd,
+ &sd,
&tp,
&ps,
&L,
&pray))
{
kernel_path_indirect(kg,
+ &indirect_sd,
+ &emission_sd,
rng,
&pray,
tp,
@@ -414,7 +436,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
}
/* todo: avoid this calculation using decoupled ray marching */
- kernel_volume_shadow(kg, &state, &volume_ray, &throughput);
+ kernel_volume_shadow(kg, &emission_sd, &state, &volume_ray, &throughput);
#endif
}
#endif
@@ -432,7 +454,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
#ifdef __BACKGROUND__
/* sample background shader */
- float3 L_background = indirect_background(kg, &state, &ray);
+ float3 L_background = indirect_background(kg, &emission_sd, &state, &ray);
path_radiance_accum_background(&L, throughput, L_background, state.bounce);
#endif
@@ -440,9 +462,8 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
}
/* setup shading */
- ShaderData sd;
shader_setup_from_ray(kg, &sd, &isect, &ray);
- shader_eval_surface(kg, &sd, &state, 0.0f, state.flag, SHADER_CONTEXT_MAIN);
+ shader_eval_surface(kg, &sd, rng, &state, 0.0f, state.flag, SHADER_CONTEXT_MAIN);
shader_merge_closures(&sd);
/* holdout */
@@ -499,15 +520,15 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
#ifdef __AO__
/* ambient occlusion */
if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) {
- kernel_branched_path_ao(kg, &sd, &L, &state, rng, throughput);
+ kernel_branched_path_ao(kg, &sd, &emission_sd, &L, &state, rng, throughput);
}
#endif
#ifdef __SUBSURFACE__
/* bssrdf scatter to a different location on the same object */
if(sd.flag & SD_BSSRDF) {
- kernel_branched_path_subsurface_scatter(kg, &sd, &L, &state,
- rng, &ray, throughput);
+ kernel_branched_path_subsurface_scatter(kg, &sd, &indirect_sd, &emission_sd,
+ &L, &state, rng, &ray, throughput);
}
#endif
@@ -519,13 +540,13 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
if(kernel_data.integrator.use_direct_light) {
int all = kernel_data.integrator.sample_all_lights_direct;
kernel_branched_path_surface_connect_light(kg, rng,
- &sd, &hit_state, throughput, 1.0f, &L, all);
+ &sd, &emission_sd, &hit_state, throughput, 1.0f, &L, all);
}
#endif
/* indirect light */
kernel_branched_path_surface_indirect_light(kg, rng,
- &sd, throughput, 1.0f, &hit_state, &L);
+ &sd, &indirect_sd, &emission_sd, throughput, 1.0f, &hit_state, &L);
/* continue in case of transparency */
throughput *= shader_bsdf_transparency(kg, &sd);
diff --git a/intern/cycles/kernel/kernel_path_state.h b/intern/cycles/kernel/kernel_path_state.h
index 540f289eae0..661dc52fb31 100644
--- a/intern/cycles/kernel/kernel_path_state.h
+++ b/intern/cycles/kernel/kernel_path_state.h
@@ -16,7 +16,12 @@
CCL_NAMESPACE_BEGIN
-ccl_device_inline void path_state_init(KernelGlobals *kg, ccl_addr_space PathState *state, ccl_addr_space RNG *rng, int sample, ccl_addr_space Ray *ray)
+ccl_device_inline void path_state_init(KernelGlobals *kg,
+ ShaderData *stack_sd,
+ ccl_addr_space PathState *state,
+ ccl_addr_space RNG *rng,
+ int sample,
+ ccl_addr_space Ray *ray)
{
state->flag = PATH_RAY_CAMERA|PATH_RAY_MIS_SKIP;
@@ -40,9 +45,9 @@ ccl_device_inline void path_state_init(KernelGlobals *kg, ccl_addr_space PathSta
state->volume_bounce = 0;
if(kernel_data.integrator.use_volumes) {
- /* initialize volume stack with volume we are inside of */
- kernel_volume_stack_init(kg, ray, state->volume_stack);
- /* seed RNG for cases where we can't use stratified samples */
+ /* Initialize volume stack with volume we are inside of. */
+ kernel_volume_stack_init(kg, stack_sd, state, ray, state->volume_stack);
+ /* Seed RNG for cases where we can't use stratified samples .*/
state->rng_congruential = lcg_init(*rng + sample*0x51633e2d);
}
else {
@@ -131,9 +136,6 @@ ccl_device_inline uint path_state_ray_visibility(KernelGlobals *kg, PathState *s
/* todo: this is not supported as its own ray visibility yet */
if(state->flag & PATH_RAY_VOLUME_SCATTER)
flag |= PATH_RAY_DIFFUSE;
- /* for camera visibility, use render layer flags */
- if(flag & PATH_RAY_CAMERA)
- flag |= kernel_data.integrator.layer_flag;
return flag;
}
diff --git a/intern/cycles/kernel/kernel_path_surface.h b/intern/cycles/kernel/kernel_path_surface.h
index 1818c4fd2da..45f0f1cbfaa 100644
--- a/intern/cycles/kernel/kernel_path_surface.h
+++ b/intern/cycles/kernel/kernel_path_surface.h
@@ -20,7 +20,8 @@ CCL_NAMESPACE_BEGIN
/* branched path tracing: connect path directly to position on one or more lights and add it to L */
ccl_device_noinline void kernel_branched_path_surface_connect_light(KernelGlobals *kg, RNG *rng,
- ShaderData *sd, PathState *state, float3 throughput, float num_samples_adjust, PathRadiance *L, int sample_all_lights)
+ ShaderData *sd, ShaderData *emission_sd, PathState *state, float3 throughput,
+ float num_samples_adjust, PathRadiance *L, int sample_all_lights)
{
#ifdef __EMISSION__
/* sample illumination from lights to find path contribution */
@@ -45,23 +46,25 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light(KernelGlobal
float num_samples_inv = num_samples_adjust/(num_samples*kernel_data.integrator.num_all_lights);
RNG lamp_rng = cmj_hash(*rng, i);
- if(kernel_data.integrator.pdf_triangles != 0.0f)
- num_samples_inv *= 0.5f;
-
for(int j = 0; j < num_samples; j++) {
float light_u, light_v;
path_branched_rng_2D(kg, &lamp_rng, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v);
LightSample ls;
- lamp_light_sample(kg, i, light_u, light_v, ccl_fetch(sd, P), &ls);
-
- if(direct_emission(kg, sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
- /* trace shadow ray */
- float3 shadow;
-
- if(!shadow_blocked(kg, state, &light_ray, &shadow)) {
- /* accumulate */
- path_radiance_accum_light(L, throughput*num_samples_inv, &L_light, shadow, num_samples_inv, state->bounce, is_lamp);
+ if(lamp_light_sample(kg, i, light_u, light_v, ccl_fetch(sd, P), &ls)) {
+ /* The sampling probability returned by lamp_light_sample assumes that all lights were sampled.
+ * However, this code only samples lamps, so if the scene also had mesh lights, the real probability is twice as high. */
+ if(kernel_data.integrator.pdf_triangles != 0.0f)
+ ls.pdf *= 2.0f;
+
+ if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
+ /* trace shadow ray */
+ float3 shadow;
+
+ if(!shadow_blocked(kg, emission_sd, state, &light_ray, &shadow)) {
+ /* accumulate */
+ path_radiance_accum_light(L, throughput*num_samples_inv, &L_light, shadow, num_samples_inv, state->bounce, is_lamp);
+ }
}
}
}
@@ -72,9 +75,6 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light(KernelGlobal
int num_samples = ceil_to_int(num_samples_adjust*kernel_data.integrator.mesh_light_samples);
float num_samples_inv = num_samples_adjust/num_samples;
- if(kernel_data.integrator.num_all_lights)
- num_samples_inv *= 0.5f;
-
for(int j = 0; j < num_samples; j++) {
float light_t = path_branched_rng_1D(kg, rng, state, j, num_samples, PRNG_LIGHT);
float light_u, light_v;
@@ -85,15 +85,19 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light(KernelGlobal
light_t = 0.5f*light_t;
LightSample ls;
- light_sample(kg, light_t, light_u, light_v, ccl_fetch(sd, time), ccl_fetch(sd, P), state->bounce, &ls);
-
- if(direct_emission(kg, sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
- /* trace shadow ray */
- float3 shadow;
-
- if(!shadow_blocked(kg, state, &light_ray, &shadow)) {
- /* accumulate */
- path_radiance_accum_light(L, throughput*num_samples_inv, &L_light, shadow, num_samples_inv, state->bounce, is_lamp);
+ if(light_sample(kg, light_t, light_u, light_v, ccl_fetch(sd, time), ccl_fetch(sd, P), state->bounce, &ls)) {
+ /* Same as above, probability needs to be corrected since the sampling was forced to select a mesh light. */
+ if(kernel_data.integrator.num_all_lights)
+ ls.pdf *= 2.0f;
+
+ if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
+ /* trace shadow ray */
+ float3 shadow;
+
+ if(!shadow_blocked(kg, emission_sd, state, &light_ray, &shadow)) {
+ /* accumulate */
+ path_radiance_accum_light(L, throughput*num_samples_inv, &L_light, shadow, num_samples_inv, state->bounce, is_lamp);
+ }
}
}
}
@@ -106,16 +110,16 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light(KernelGlobal
path_state_rng_2D(kg, rng, state, PRNG_LIGHT_U, &light_u, &light_v);
LightSample ls;
- light_sample(kg, light_t, light_u, light_v, ccl_fetch(sd, time), ccl_fetch(sd, P), state->bounce, &ls);
-
- /* sample random light */
- if(direct_emission(kg, sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
- /* trace shadow ray */
- float3 shadow;
-
- if(!shadow_blocked(kg, state, &light_ray, &shadow)) {
- /* accumulate */
- path_radiance_accum_light(L, throughput*num_samples_adjust, &L_light, shadow, num_samples_adjust, state->bounce, is_lamp);
+ if(light_sample(kg, light_t, light_u, light_v, ccl_fetch(sd, time), ccl_fetch(sd, P), state->bounce, &ls)) {
+ /* sample random light */
+ if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
+ /* trace shadow ray */
+ float3 shadow;
+
+ if(!shadow_blocked(kg, emission_sd, state, &light_ray, &shadow)) {
+ /* accumulate */
+ path_radiance_accum_light(L, throughput*num_samples_adjust, &L_light, shadow, num_samples_adjust, state->bounce, is_lamp);
+ }
}
}
}
@@ -184,7 +188,8 @@ ccl_device bool kernel_branched_path_surface_bounce(KernelGlobals *kg, RNG *rng,
#ifndef __SPLIT_KERNEL__
/* path tracing: connect path directly to position on a light and add it to L */
ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg, ccl_addr_space RNG *rng,
- ShaderData *sd, float3 throughput, ccl_addr_space PathState *state, PathRadiance *L)
+ ShaderData *sd, ShaderData *emission_sd, float3 throughput, ccl_addr_space PathState *state,
+ PathRadiance *L)
{
#ifdef __EMISSION__
if(!(kernel_data.integrator.use_direct_light && (ccl_fetch(sd, flag) & SD_BSDF_HAS_EVAL)))
@@ -204,15 +209,15 @@ ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg, ccl_
#endif
LightSample ls;
- light_sample(kg, light_t, light_u, light_v, ccl_fetch(sd, time), ccl_fetch(sd, P), state->bounce, &ls);
-
- if(direct_emission(kg, sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
- /* trace shadow ray */
- float3 shadow;
+ if(light_sample(kg, light_t, light_u, light_v, ccl_fetch(sd, time), ccl_fetch(sd, P), state->bounce, &ls)) {
+ if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
+ /* trace shadow ray */
+ float3 shadow;
- if(!shadow_blocked(kg, state, &light_ray, &shadow)) {
- /* accumulate */
- path_radiance_accum_light(L, throughput, &L_light, shadow, 1.0f, state->bounce, is_lamp);
+ if(!shadow_blocked(kg, emission_sd, state, &light_ray, &shadow)) {
+ /* accumulate */
+ path_radiance_accum_light(L, throughput, &L_light, shadow, 1.0f, state->bounce, is_lamp);
+ }
}
}
#endif
@@ -220,8 +225,13 @@ ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg, ccl_
#endif
/* path tracing: bounce off or through surface to with new direction stored in ray */
-ccl_device_inline bool kernel_path_surface_bounce(KernelGlobals *kg, ccl_addr_space RNG *rng,
- ShaderData *sd, ccl_addr_space float3 *throughput, ccl_addr_space PathState *state, PathRadiance *L, ccl_addr_space Ray *ray)
+ccl_device bool kernel_path_surface_bounce(KernelGlobals *kg,
+ ccl_addr_space RNG *rng,
+ ShaderData *sd,
+ ccl_addr_space float3 *throughput,
+ ccl_addr_space PathState *state,
+ PathRadiance *L,
+ ccl_addr_space Ray *ray)
{
/* no BSDF? we can stop here */
if(ccl_fetch(sd, flag) & SD_BSDF) {
diff --git a/intern/cycles/kernel/kernel_path_volume.h b/intern/cycles/kernel/kernel_path_volume.h
index 9eb8b240b88..5ee1912c913 100644
--- a/intern/cycles/kernel/kernel_path_volume.h
+++ b/intern/cycles/kernel/kernel_path_volume.h
@@ -18,8 +18,14 @@ CCL_NAMESPACE_BEGIN
#ifdef __VOLUME_SCATTER__
-ccl_device void kernel_path_volume_connect_light(KernelGlobals *kg, RNG *rng,
- ShaderData *sd, float3 throughput, PathState *state, PathRadiance *L)
+ccl_device_inline void kernel_path_volume_connect_light(
+ KernelGlobals *kg,
+ RNG *rng,
+ ShaderData *sd,
+ ShaderData *emission_sd,
+ float3 throughput,
+ PathState *state,
+ PathRadiance *L)
{
#ifdef __EMISSION__
if(!kernel_data.integrator.use_direct_light)
@@ -40,17 +46,16 @@ ccl_device void kernel_path_volume_connect_light(KernelGlobals *kg, RNG *rng,
light_ray.time = sd->time;
# endif
- light_sample(kg, light_t, light_u, light_v, sd->time, sd->P, state->bounce, &ls);
- if(ls.pdf == 0.0f)
- return;
-
- if(direct_emission(kg, sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
- /* trace shadow ray */
- float3 shadow;
+ if(light_sample(kg, light_t, light_u, light_v, sd->time, sd->P, state->bounce, &ls))
+ {
+ if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
+ /* trace shadow ray */
+ float3 shadow;
- if(!shadow_blocked(kg, state, &light_ray, &shadow)) {
- /* accumulate */
- path_radiance_accum_light(L, throughput, &L_light, shadow, 1.0f, state->bounce, is_lamp);
+ if(!shadow_blocked(kg, emission_sd, state, &light_ray, &shadow)) {
+ /* accumulate */
+ path_radiance_accum_light(L, throughput, &L_light, shadow, 1.0f, state->bounce, is_lamp);
+ }
}
}
#endif
@@ -106,7 +111,7 @@ bool kernel_path_volume_bounce(KernelGlobals *kg, RNG *rng,
}
ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg, RNG *rng,
- ShaderData *sd, float3 throughput, PathState *state, PathRadiance *L,
+ ShaderData *sd, ShaderData *emission_sd, float3 throughput, PathState *state, PathRadiance *L,
bool sample_all_lights, Ray *ray, const VolumeSegment *segment)
{
#ifdef __EMISSION__
@@ -131,16 +136,13 @@ ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg, RNG
float num_samples_inv = 1.0f/(num_samples*kernel_data.integrator.num_all_lights);
RNG lamp_rng = cmj_hash(*rng, i);
- if(kernel_data.integrator.pdf_triangles != 0.0f)
- num_samples_inv *= 0.5f;
-
for(int j = 0; j < num_samples; j++) {
/* sample random position on given light */
float light_u, light_v;
path_branched_rng_2D(kg, &lamp_rng, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v);
LightSample ls;
- lamp_light_sample(kg, i, light_u, light_v, ray->P, &ls);
+ lamp_light_sample(kg, i, light_u, light_v, ray->P, &ls);
float3 tp = throughput;
@@ -150,23 +152,23 @@ ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg, RNG
VolumeIntegrateResult result = kernel_volume_decoupled_scatter(kg,
state, ray, sd, &tp, rphase, rscatter, segment, (ls.t != FLT_MAX)? &ls.P: NULL, false);
-
+
(void)result;
kernel_assert(result == VOLUME_PATH_SCATTERED);
/* todo: split up light_sample so we don't have to call it again with new position */
- lamp_light_sample(kg, i, light_u, light_v, sd->P, &ls);
-
- if(ls.pdf == 0.0f)
- continue;
-
- if(direct_emission(kg, sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
- /* trace shadow ray */
- float3 shadow;
-
- if(!shadow_blocked(kg, state, &light_ray, &shadow)) {
- /* accumulate */
- path_radiance_accum_light(L, tp*num_samples_inv, &L_light, shadow, num_samples_inv, state->bounce, is_lamp);
+ if(lamp_light_sample(kg, i, light_u, light_v, sd->P, &ls)) {
+ if(kernel_data.integrator.pdf_triangles != 0.0f)
+ ls.pdf *= 2.0f;
+
+ if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
+ /* trace shadow ray */
+ float3 shadow;
+
+ if(!shadow_blocked(kg, emission_sd, state, &light_ray, &shadow)) {
+ /* accumulate */
+ path_radiance_accum_light(L, tp*num_samples_inv, &L_light, shadow, num_samples_inv, state->bounce, is_lamp);
+ }
}
}
}
@@ -177,9 +179,6 @@ ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg, RNG
int num_samples = kernel_data.integrator.mesh_light_samples;
float num_samples_inv = 1.0f/num_samples;
- if(kernel_data.integrator.num_all_lights)
- num_samples_inv *= 0.5f;
-
for(int j = 0; j < num_samples; j++) {
/* sample random position on random triangle */
float light_t = path_branched_rng_1D_for_decision(kg, rng, state, j, num_samples, PRNG_LIGHT);
@@ -206,18 +205,18 @@ ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg, RNG
kernel_assert(result == VOLUME_PATH_SCATTERED);
/* todo: split up light_sample so we don't have to call it again with new position */
- light_sample(kg, light_t, light_u, light_v, sd->time, sd->P, state->bounce, &ls);
-
- if(ls.pdf == 0.0f)
- continue;
-
- if(direct_emission(kg, sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
- /* trace shadow ray */
- float3 shadow;
-
- if(!shadow_blocked(kg, state, &light_ray, &shadow)) {
- /* accumulate */
- path_radiance_accum_light(L, tp*num_samples_inv, &L_light, shadow, num_samples_inv, state->bounce, is_lamp);
+ if(light_sample(kg, light_t, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
+ if(kernel_data.integrator.num_all_lights)
+ ls.pdf *= 2.0f;
+
+ if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
+ /* trace shadow ray */
+ float3 shadow;
+
+ if(!shadow_blocked(kg, emission_sd, state, &light_ray, &shadow)) {
+ /* accumulate */
+ path_radiance_accum_light(L, tp*num_samples_inv, &L_light, shadow, num_samples_inv, state->bounce, is_lamp);
+ }
}
}
}
@@ -245,19 +244,16 @@ ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg, RNG
kernel_assert(result == VOLUME_PATH_SCATTERED);
/* todo: split up light_sample so we don't have to call it again with new position */
- light_sample(kg, light_t, light_u, light_v, sd->time, sd->P, state->bounce, &ls);
-
- if(ls.pdf == 0.0f)
- return;
-
- /* sample random light */
- if(direct_emission(kg, sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
- /* trace shadow ray */
- float3 shadow;
-
- if(!shadow_blocked(kg, state, &light_ray, &shadow)) {
- /* accumulate */
- path_radiance_accum_light(L, tp, &L_light, shadow, 1.0f, state->bounce, is_lamp);
+ if(light_sample(kg, light_t, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
+ /* sample random light */
+ if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
+ /* trace shadow ray */
+ float3 shadow;
+
+ if(!shadow_blocked(kg, emission_sd, state, &light_ray, &shadow)) {
+ /* accumulate */
+ path_radiance_accum_light(L, tp, &L_light, shadow, 1.0f, state->bounce, is_lamp);
+ }
}
}
}
diff --git a/intern/cycles/kernel/kernel_projection.h b/intern/cycles/kernel/kernel_projection.h
index c1a359e9269..9a2b0884a7e 100644
--- a/intern/cycles/kernel/kernel_projection.h
+++ b/intern/cycles/kernel/kernel_projection.h
@@ -130,7 +130,10 @@ ccl_device float2 direction_to_fisheye_equisolid(float3 dir, float lens, float w
return make_float2(u, v);
}
-ccl_device float3 fisheye_equisolid_to_direction(float u, float v, float lens, float fov, float width, float height)
+ccl_device_inline float3 fisheye_equisolid_to_direction(float u, float v,
+ float lens,
+ float fov,
+ float width, float height)
{
u = (u - 0.5f) * width;
v = (v - 0.5f) * height;
@@ -189,7 +192,7 @@ ccl_device float2 direction_to_mirrorball(float3 dir)
return make_float2(u, v);
}
-ccl_device float3 panorama_to_direction(KernelGlobals *kg, float u, float v)
+ccl_device_inline float3 panorama_to_direction(KernelGlobals *kg, float u, float v)
{
switch(kernel_data.cam.panorama_type) {
case PANORAMA_EQUIRECTANGULAR:
@@ -205,7 +208,7 @@ ccl_device float3 panorama_to_direction(KernelGlobals *kg, float u, float v)
}
}
-ccl_device float2 direction_to_panorama(KernelGlobals *kg, float3 dir)
+ccl_device_inline float2 direction_to_panorama(KernelGlobals *kg, float3 dir)
{
switch(kernel_data.cam.panorama_type) {
case PANORAMA_EQUIRECTANGULAR:
@@ -221,46 +224,43 @@ ccl_device float2 direction_to_panorama(KernelGlobals *kg, float3 dir)
}
}
-ccl_device float3 spherical_stereo_position(KernelGlobals *kg,
- float3 dir,
- float3 pos)
+ccl_device_inline void spherical_stereo_transform(KernelGlobals *kg, float3 *P, float3 *D)
{
- const float interocular_offset = kernel_data.cam.interocular_offset;
+ float interocular_offset = kernel_data.cam.interocular_offset;
/* Interocular offset of zero means either non stereo, or stereo without
- * spherical stereo.
- */
- if(interocular_offset == 0.0f) {
- return pos;
+ * spherical stereo. */
+ kernel_assert(interocular_offset != 0.0f);
+
+ if(kernel_data.cam.pole_merge_angle_to > 0.0f) {
+ const float pole_merge_angle_from = kernel_data.cam.pole_merge_angle_from,
+ pole_merge_angle_to = kernel_data.cam.pole_merge_angle_to;
+ float altitude = fabsf(safe_asinf((*D).z));
+ if(altitude > pole_merge_angle_to) {
+ interocular_offset = 0.0f;
+ }
+ else if(altitude > pole_merge_angle_from) {
+ float fac = (altitude - pole_merge_angle_from) / (pole_merge_angle_to - pole_merge_angle_from);
+ float fade = cosf(fac * M_PI_2_F);
+ interocular_offset *= fade;
+ }
}
float3 up = make_float3(0.0f, 0.0f, 1.0f);
- float3 side = normalize(cross(dir, up));
+ float3 side = normalize(cross(*D, up));
+ float3 stereo_offset = side * interocular_offset;
- return pos + (side * interocular_offset);
-}
+ *P += stereo_offset;
-/* NOTE: Ensures direction is normalized. */
-ccl_device float3 spherical_stereo_direction(KernelGlobals *kg,
- float3 dir,
- float3 pos,
- float3 newpos)
-{
+ /* Convergence distance is FLT_MAX in the case of parallel convergence mode,
+ * no need to modify direction in this case either. */
const float convergence_distance = kernel_data.cam.convergence_distance;
- const float3 normalized_dir = normalize(dir);
- /* Interocular offset of zero means either no stereo, or stereo without
- * spherical stereo.
- * Convergence distance is FLT_MAX in the case of parallel convergence mode,
- * no need to mdify direction in this case either.
- */
- if(kernel_data.cam.interocular_offset == 0.0f ||
- convergence_distance == FLT_MAX)
+
+ if(convergence_distance != FLT_MAX)
{
- return normalized_dir;
+ float3 screen_offset = convergence_distance * (*D);
+ *D = normalize(screen_offset - stereo_offset);
}
-
- float3 screenpos = pos + (normalized_dir * convergence_distance);
- return normalize(screenpos - newpos);
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_random.h b/intern/cycles/kernel/kernel_random.h
index 631a2cb75de..4a76ffddbe7 100644
--- a/intern/cycles/kernel/kernel_random.h
+++ b/intern/cycles/kernel/kernel_random.h
@@ -98,7 +98,7 @@ ccl_device uint sobol_lookup(const uint m, const uint frame, const uint ex, cons
return index;
}
-ccl_device_inline float path_rng_1D(KernelGlobals *kg, ccl_addr_space RNG *rng, int sample, int num_samples, int dimension)
+ccl_device_forceinline float path_rng_1D(KernelGlobals *kg, ccl_addr_space RNG *rng, int sample, int num_samples, int dimension)
{
#ifdef __CMJ__
if(kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_CMJ) {
@@ -132,7 +132,7 @@ ccl_device_inline float path_rng_1D(KernelGlobals *kg, ccl_addr_space RNG *rng,
#endif
}
-ccl_device_inline void path_rng_2D(KernelGlobals *kg, ccl_addr_space RNG *rng, int sample, int num_samples, int dimension, float *fx, float *fy)
+ccl_device_forceinline void path_rng_2D(KernelGlobals *kg, ccl_addr_space RNG *rng, int sample, int num_samples, int dimension, float *fx, float *fy)
{
#ifdef __CMJ__
if(kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_CMJ) {
@@ -193,7 +193,7 @@ ccl_device void path_rng_end(KernelGlobals *kg, ccl_global uint *rng_state, RNG
/* Linear Congruential Generator */
-ccl_device_inline float path_rng_1D(KernelGlobals *kg, RNG& rng, int sample, int num_samples, int dimension)
+ccl_device_forceinline float path_rng_1D(KernelGlobals *kg, RNG& rng, int sample, int num_samples, int dimension)
{
/* implicit mod 2^32 */
rng = (1103515245*(rng) + 12345);
@@ -314,5 +314,21 @@ ccl_device_inline uint lcg_state_init(RNG *rng, const PathState *state, uint scr
return lcg_init(*rng + state->rng_offset + state->sample*scramble);
}
+/* TODO(sergey): For until we can use generic address space from OpenCL 2.0. */
+
+ccl_device_inline uint lcg_state_init_addrspace(ccl_addr_space RNG *rng,
+ const ccl_addr_space PathState *state,
+ uint scramble)
+{
+ return lcg_init(*rng + state->rng_offset + state->sample*scramble);
+}
+
+ccl_device float lcg_step_float_addrspace(ccl_addr_space uint *rng)
+{
+ /* implicit mod 2^32 */
+ *rng = (1103515245*(*rng) + 12345);
+ return (float)*rng * (1.0f/(float)0xFFFFFFFF);
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h
index a0b56118ab7..a8070a133de 100644
--- a/intern/cycles/kernel/kernel_shader.h
+++ b/intern/cycles/kernel/kernel_shader.h
@@ -24,6 +24,7 @@
*
*/
+#include "closure/alloc.h"
#include "closure/bsdf_util.h"
#include "closure/bsdf.h"
#include "closure/emissive.h"
@@ -110,7 +111,7 @@ ccl_device_noinline void shader_setup_from_ray(KernelGlobals *kg,
ccl_fetch(sd, I) = -ray->D;
- ccl_fetch(sd, flag) |= kernel_tex_fetch(__shader_flag, (ccl_fetch(sd, shader) & SHADER_MASK)*2);
+ ccl_fetch(sd, flag) |= kernel_tex_fetch(__shader_flag, (ccl_fetch(sd, shader) & SHADER_MASK)*SHADER_SIZE);
#ifdef __INSTANCING__
if(isect->object != OBJECT_NONE) {
@@ -148,8 +149,16 @@ ccl_device_noinline void shader_setup_from_ray(KernelGlobals *kg,
/* ShaderData setup from BSSRDF scatter */
#ifdef __SUBSURFACE__
-ccl_device_inline void shader_setup_from_subsurface(KernelGlobals *kg, ShaderData *sd,
- const Intersection *isect, const Ray *ray)
+# ifndef __KERNEL_CUDA__
+ccl_device
+# else
+ccl_device_inline
+# endif
+void shader_setup_from_subsurface(
+ KernelGlobals *kg,
+ ShaderData *sd,
+ const Intersection *isect,
+ const Ray *ray)
{
bool backfacing = sd->flag & SD_BACKFACING;
@@ -186,7 +195,7 @@ ccl_device_inline void shader_setup_from_subsurface(KernelGlobals *kg, ShaderDat
motion_triangle_shader_setup(kg, sd, isect, ray, true);
}
- sd->flag |= kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*2);
+ sd->flag |= kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE);
# ifdef __INSTANCING__
if(isect->object != OBJECT_NONE) {
@@ -225,14 +234,16 @@ ccl_device_inline void shader_setup_from_subsurface(KernelGlobals *kg, ShaderDat
/* ShaderData setup from position sampled on mesh */
-ccl_device void shader_setup_from_sample(KernelGlobals *kg,
- ShaderData *sd,
- const float3 P,
- const float3 Ng,
- const float3 I,
- int shader, int object, int prim,
- float u, float v, float t,
- float time)
+ccl_device_inline void shader_setup_from_sample(KernelGlobals *kg,
+ ShaderData *sd,
+ const float3 P,
+ const float3 Ng,
+ const float3 I,
+ int shader, int object, int prim,
+ float u, float v, float t,
+ float time,
+ bool object_space,
+ int lamp)
{
/* vectors */
ccl_fetch(sd, P) = P;
@@ -240,7 +251,12 @@ ccl_device void shader_setup_from_sample(KernelGlobals *kg,
ccl_fetch(sd, Ng) = Ng;
ccl_fetch(sd, I) = I;
ccl_fetch(sd, shader) = shader;
- ccl_fetch(sd, type) = (prim == PRIM_NONE)? PRIMITIVE_NONE: PRIMITIVE_TRIANGLE;
+ if(prim != PRIM_NONE)
+ ccl_fetch(sd, type) = PRIMITIVE_TRIANGLE;
+ else if(lamp != LAMP_NONE)
+ ccl_fetch(sd, type) = PRIMITIVE_LAMP;
+ else
+ ccl_fetch(sd, type) = PRIMITIVE_NONE;
/* primitive */
#ifdef __INSTANCING__
@@ -254,41 +270,40 @@ ccl_device void shader_setup_from_sample(KernelGlobals *kg,
#endif
ccl_fetch(sd, ray_length) = t;
- /* detect instancing, for non-instanced the object index is -object-1 */
-#ifdef __INSTANCING__
- bool instanced = false;
-
- if(ccl_fetch(sd, prim) != PRIM_NONE) {
- if(ccl_fetch(sd, object) >= 0)
- instanced = true;
- else
-#endif
- ccl_fetch(sd, object) = ~ccl_fetch(sd, object);
-#ifdef __INSTANCING__
- }
-#endif
-
- ccl_fetch(sd, flag) = kernel_tex_fetch(__shader_flag, (ccl_fetch(sd, shader) & SHADER_MASK)*2);
+ ccl_fetch(sd, flag) = kernel_tex_fetch(__shader_flag, (ccl_fetch(sd, shader) & SHADER_MASK)*SHADER_SIZE);
if(ccl_fetch(sd, object) != OBJECT_NONE) {
ccl_fetch(sd, flag) |= kernel_tex_fetch(__object_flag, ccl_fetch(sd, object));
#ifdef __OBJECT_MOTION__
shader_setup_object_transforms(kg, sd, time);
+#endif
+ }
+ else if(lamp != LAMP_NONE) {
+ ccl_fetch(sd, ob_tfm) = lamp_fetch_transform(kg, lamp, false);
+ ccl_fetch(sd, ob_itfm) = lamp_fetch_transform(kg, lamp, true);
}
+#ifdef __OBJECT_MOTION__
ccl_fetch(sd, time) = time;
-#else
- }
#endif
+ /* transform into world space */
+ if(object_space) {
+ object_position_transform_auto(kg, sd, &ccl_fetch(sd, P));
+ object_normal_transform_auto(kg, sd, &ccl_fetch(sd, Ng));
+ ccl_fetch(sd, N) = ccl_fetch(sd, Ng);
+ object_dir_transform_auto(kg, sd, &ccl_fetch(sd, I));
+ }
+
if(ccl_fetch(sd, type) & PRIMITIVE_TRIANGLE) {
/* smooth normal */
if(ccl_fetch(sd, shader) & SHADER_SMOOTH_NORMAL) {
ccl_fetch(sd, N) = triangle_smooth_normal(kg, ccl_fetch(sd, prim), ccl_fetch(sd, u), ccl_fetch(sd, v));
#ifdef __INSTANCING__
- if(instanced)
+ if(!(ccl_fetch(sd, flag) & SD_TRANSFORM_APPLIED)) {
object_normal_transform_auto(kg, sd, &ccl_fetch(sd, N));
+ }
#endif
}
@@ -297,7 +312,7 @@ ccl_device void shader_setup_from_sample(KernelGlobals *kg,
triangle_dPdudv(kg, ccl_fetch(sd, prim), &ccl_fetch(sd, dPdu), &ccl_fetch(sd, dPdv));
# ifdef __INSTANCING__
- if(instanced) {
+ if(!(ccl_fetch(sd, flag) & SD_TRANSFORM_APPLIED)) {
object_dir_transform_auto(kg, sd, &ccl_fetch(sd, dPdu));
object_dir_transform_auto(kg, sd, &ccl_fetch(sd, dPdv));
}
@@ -348,9 +363,12 @@ ccl_device void shader_setup_from_displace(KernelGlobals *kg, ShaderData *sd,
/* force smooth shading for displacement */
shader |= SHADER_SMOOTH_NORMAL;
- /* watch out: no instance transform currently */
-
- shader_setup_from_sample(kg, sd, P, Ng, I, shader, object, prim, u, v, 0.0f, TIME_INVALID);
+ shader_setup_from_sample(kg, sd,
+ P, Ng, I,
+ shader, object, prim,
+ u, v, 0.0f, 0.5f,
+ !(kernel_tex_fetch(__object_flag, object) & SD_TRANSFORM_APPLIED),
+ LAMP_NONE);
}
/* ShaderData setup from ray into background */
@@ -363,7 +381,7 @@ ccl_device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderDat
ccl_fetch(sd, Ng) = -ray->D;
ccl_fetch(sd, I) = -ray->D;
ccl_fetch(sd, shader) = kernel_data.background.surface_shader;
- ccl_fetch(sd, flag) = kernel_tex_fetch(__shader_flag, (ccl_fetch(sd, shader) & SHADER_MASK)*2);
+ ccl_fetch(sd, flag) = kernel_tex_fetch(__shader_flag, (ccl_fetch(sd, shader) & SHADER_MASK)*SHADER_SIZE);
#ifdef __OBJECT_MOTION__
ccl_fetch(sd, time) = ray->time;
#endif
@@ -444,7 +462,7 @@ ccl_device_inline void shader_setup_from_volume(KernelGlobals *kg, ShaderData *s
/* Merging */
#if defined(__BRANCHED_PATH__) || defined(__VOLUME__)
-ccl_device void shader_merge_closures(ShaderData *sd)
+ccl_device_inline void shader_merge_closures(ShaderData *sd)
{
/* merge identical closures, better when we sample a single closure at a time */
for(int i = 0; i < sd->num_closure; i++) {
@@ -453,21 +471,11 @@ ccl_device void shader_merge_closures(ShaderData *sd)
for(int j = i + 1; j < sd->num_closure; j++) {
ShaderClosure *scj = &sd->closure[j];
-#ifdef __OSL__
- if(sci->prim || scj->prim)
+ if(sci->type != scj->type)
continue;
-#endif
-
- if(!(sci->type == scj->type && sci->data0 == scj->data0 && sci->data1 == scj->data1 && sci->data2 == scj->data2))
+ if(!bsdf_merge(sci, scj))
continue;
- if(CLOSURE_IS_BSDF_OR_BSSRDF(sci->type)) {
- if(sci->N != scj->N)
- continue;
- else if(CLOSURE_IS_BSDF_ANISOTROPIC(sci->type) && sci->T != scj->T)
- continue;
- }
-
sci->weight += scj->weight;
sci->sample_weight += scj->sample_weight;
@@ -488,7 +496,7 @@ ccl_device void shader_merge_closures(ShaderData *sd)
/* BSDF */
-ccl_device_inline void _shader_bsdf_multi_eval(KernelGlobals *kg, const ShaderData *sd, const float3 omega_in, float *pdf,
+ccl_device_inline void _shader_bsdf_multi_eval(KernelGlobals *kg, ShaderData *sd, const float3 omega_in, float *pdf,
int skip_bsdf, BsdfEval *result_eval, float sum_pdf, float sum_sample_weight)
{
/* this is the veach one-sample model with balance heuristic, some pdf
@@ -517,7 +525,7 @@ ccl_device_inline void _shader_bsdf_multi_eval(KernelGlobals *kg, const ShaderDa
#ifdef __BRANCHED_PATH__
ccl_device_inline void _shader_bsdf_multi_eval_branched(KernelGlobals *kg,
- const ShaderData *sd,
+ ShaderData *sd,
const float3 omega_in,
BsdfEval *result_eval,
float light_pdf,
@@ -539,12 +547,18 @@ ccl_device_inline void _shader_bsdf_multi_eval_branched(KernelGlobals *kg,
}
#endif
-ccl_device void shader_bsdf_eval(KernelGlobals *kg,
- ShaderData *sd,
- const float3 omega_in,
- BsdfEval *eval,
- float light_pdf,
- bool use_mis)
+
+#ifndef __KERNEL_CUDA__
+ccl_device
+#else
+ccl_device_inline
+#endif
+void shader_bsdf_eval(KernelGlobals *kg,
+ ShaderData *sd,
+ const float3 omega_in,
+ BsdfEval *eval,
+ float light_pdf,
+ bool use_mis)
{
bsdf_eval_init(eval, NBUILTIN_CLOSURES, make_float3(0.0f, 0.0f, 0.0f), kernel_data.film.use_light_pass);
@@ -563,9 +577,13 @@ ccl_device void shader_bsdf_eval(KernelGlobals *kg,
}
}
-ccl_device int shader_bsdf_sample(KernelGlobals *kg, const ShaderData *sd,
- float randu, float randv, BsdfEval *bsdf_eval,
- float3 *omega_in, differential3 *domega_in, float *pdf)
+ccl_device_inline int shader_bsdf_sample(KernelGlobals *kg,
+ ShaderData *sd,
+ float randu, float randv,
+ BsdfEval *bsdf_eval,
+ float3 *omega_in,
+ differential3 *domega_in,
+ float *pdf)
{
int sampled = 0;
@@ -620,7 +638,7 @@ ccl_device int shader_bsdf_sample(KernelGlobals *kg, const ShaderData *sd,
return label;
}
-ccl_device int shader_bsdf_sample_closure(KernelGlobals *kg, const ShaderData *sd,
+ccl_device int shader_bsdf_sample_closure(KernelGlobals *kg, ShaderData *sd,
const ShaderClosure *sc, float randu, float randv, BsdfEval *bsdf_eval,
float3 *omega_in, differential3 *domega_in, float *pdf)
{
@@ -738,8 +756,9 @@ ccl_device float3 shader_bsdf_ao(KernelGlobals *kg, ShaderData *sd, float ao_fac
ShaderClosure *sc = ccl_fetch_array(sd, closure, i);
if(CLOSURE_IS_BSDF_DIFFUSE(sc->type)) {
+ const DiffuseBsdf *bsdf = (const DiffuseBsdf*)sc;
eval += sc->weight*ao_factor;
- N += sc->N*average(sc->weight);
+ N += bsdf->N*average(sc->weight);
}
else if(CLOSURE_IS_AMBIENT_OCCLUSION(sc->type)) {
eval += sc->weight;
@@ -756,6 +775,7 @@ ccl_device float3 shader_bsdf_ao(KernelGlobals *kg, ShaderData *sd, float ao_fac
return eval;
}
+#ifdef __SUBSURFACE__
ccl_device float3 shader_bssrdf_sum(ShaderData *sd, float3 *N_, float *texture_blur_)
{
float3 eval = make_float3(0.0f, 0.0f, 0.0f);
@@ -766,11 +786,12 @@ ccl_device float3 shader_bssrdf_sum(ShaderData *sd, float3 *N_, float *texture_b
ShaderClosure *sc = ccl_fetch_array(sd, closure, i);
if(CLOSURE_IS_BSSRDF(sc->type)) {
+ const Bssrdf *bssrdf = (const Bssrdf*)sc;
float avg_weight = fabsf(average(sc->weight));
- N += sc->N*avg_weight;
+ N += bssrdf->N*avg_weight;
eval += sc->weight;
- texture_blur += sc->data1*avg_weight;
+ texture_blur += bssrdf->texture_blur*avg_weight;
weight_sum += avg_weight;
}
}
@@ -783,6 +804,7 @@ ccl_device float3 shader_bssrdf_sum(ShaderData *sd, float3 *N_, float *texture_b
return eval;
}
+#endif
/* Emission */
@@ -824,10 +846,11 @@ ccl_device float3 shader_holdout_eval(KernelGlobals *kg, ShaderData *sd)
/* Surface Evaluation */
-ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd,
+ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd, ccl_addr_space RNG *rng,
ccl_addr_space PathState *state, float randb, int path_flag, ShaderContext ctx)
{
ccl_fetch(sd, num_closure) = 0;
+ ccl_fetch(sd, num_closure_extra) = 0;
ccl_fetch(sd, randb_closure) = randb;
#ifdef __OSL__
@@ -839,13 +862,17 @@ ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd,
#ifdef __SVM__
svm_eval_nodes(kg, sd, state, SHADER_TYPE_SURFACE, path_flag);
#else
- ccl_fetch_array(sd, closure, 0)->weight = make_float3(0.8f, 0.8f, 0.8f);
- ccl_fetch_array(sd, closure, 0)->N = ccl_fetch(sd, N);
- ccl_fetch_array(sd, closure, 0)->data0 = 0.0f;
- ccl_fetch_array(sd, closure, 0)->data1 = 0.0f;
- ccl_fetch(sd, flag) |= bsdf_diffuse_setup(ccl_fetch_array(sd, closure, 0));
+ DiffuseBsdf *bsdf = (DiffuseBsdf*)bsdf_alloc(sd,
+ sizeof(DiffuseBsdf),
+ make_float3(0.8f, 0.8f, 0.8f));
+ bsdf->N = ccl_fetch(sd, N);
+ ccl_fetch(sd, flag) |= bsdf_diffuse_setup(bsdf);
#endif
}
+
+ if(rng && (ccl_fetch(sd, flag) & SD_BSDF_NEEDS_LCG)) {
+ ccl_fetch(sd, lcg_state) = lcg_state_init_addrspace(rng, state, 0xb4bc3953);
+ }
}
/* Background Evaluation */
@@ -854,33 +881,33 @@ ccl_device float3 shader_eval_background(KernelGlobals *kg, ShaderData *sd,
ccl_addr_space PathState *state, int path_flag, ShaderContext ctx)
{
ccl_fetch(sd, num_closure) = 0;
+ ccl_fetch(sd, num_closure_extra) = 0;
ccl_fetch(sd, randb_closure) = 0.0f;
+#ifdef __SVM__
#ifdef __OSL__
if(kg->osl) {
- return OSLShader::eval_background(kg, sd, state, path_flag, ctx);
+ OSLShader::eval_background(kg, sd, state, path_flag, ctx);
}
else
#endif
-
{
-#ifdef __SVM__
svm_eval_nodes(kg, sd, state, SHADER_TYPE_SURFACE, path_flag);
+ }
- float3 eval = make_float3(0.0f, 0.0f, 0.0f);
+ float3 eval = make_float3(0.0f, 0.0f, 0.0f);
- for(int i = 0; i < ccl_fetch(sd, num_closure); i++) {
- const ShaderClosure *sc = ccl_fetch_array(sd, closure, i);
+ for(int i = 0; i < ccl_fetch(sd, num_closure); i++) {
+ const ShaderClosure *sc = ccl_fetch_array(sd, closure, i);
- if(CLOSURE_IS_BACKGROUND(sc->type))
- eval += sc->weight;
- }
+ if(CLOSURE_IS_BACKGROUND(sc->type))
+ eval += sc->weight;
+ }
- return eval;
+ return eval;
#else
- return make_float3(0.8f, 0.8f, 0.8f);
+ return make_float3(0.8f, 0.8f, 0.8f);
#endif
- }
}
/* Volume */
@@ -991,12 +1018,17 @@ ccl_device int shader_phase_sample_closure(KernelGlobals *kg, const ShaderData *
/* Volume Evaluation */
-ccl_device void shader_eval_volume(KernelGlobals *kg, ShaderData *sd,
- PathState *state, VolumeStack *stack, int path_flag, ShaderContext ctx)
+ccl_device_inline void shader_eval_volume(KernelGlobals *kg,
+ ShaderData *sd,
+ PathState *state,
+ VolumeStack *stack,
+ int path_flag,
+ ShaderContext ctx)
{
/* reset closures once at the start, we will be accumulating the closures
* for all volumes in the stack into a single array of closures */
sd->num_closure = 0;
+ sd->num_closure_extra = 0;
sd->flag = 0;
for(int i = 0; stack[i].shader != SHADER_NONE; i++) {
@@ -1006,7 +1038,7 @@ ccl_device void shader_eval_volume(KernelGlobals *kg, ShaderData *sd,
sd->shader = stack[i].shader;
sd->flag &= ~(SD_SHADER_FLAGS|SD_OBJECT_FLAGS);
- sd->flag |= kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*2);
+ sd->flag |= kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE);
if(sd->object != OBJECT_NONE) {
sd->flag |= kernel_tex_fetch(__object_flag, sd->object);
@@ -1044,6 +1076,7 @@ ccl_device void shader_eval_volume(KernelGlobals *kg, ShaderData *sd,
ccl_device void shader_eval_displacement(KernelGlobals *kg, ShaderData *sd, ccl_addr_space PathState *state, ShaderContext ctx)
{
ccl_fetch(sd, num_closure) = 0;
+ ccl_fetch(sd, num_closure_extra) = 0;
ccl_fetch(sd, randb_closure) = 0.0f;
/* this will modify sd->P */
@@ -1078,7 +1111,7 @@ ccl_device bool shader_transparent_shadow(KernelGlobals *kg, Intersection *isect
shader = __float_as_int(str.z);
}
#endif
- int flag = kernel_tex_fetch(__shader_flag, (shader & SHADER_MASK)*2);
+ int flag = kernel_tex_fetch(__shader_flag, (shader & SHADER_MASK)*SHADER_SIZE);
return (flag & SD_HAS_TRANSPARENT_SHADOW) != 0;
}
diff --git a/intern/cycles/kernel/kernel_shadow.h b/intern/cycles/kernel/kernel_shadow.h
index 3b1111e5069..2981f6ac566 100644
--- a/intern/cycles/kernel/kernel_shadow.h
+++ b/intern/cycles/kernel/kernel_shadow.h
@@ -41,7 +41,7 @@ CCL_NAMESPACE_BEGIN
#define STACK_MAX_HITS 64
-ccl_device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *ray, float3 *shadow)
+ccl_device_inline bool shadow_blocked(KernelGlobals *kg, ShaderData *shadow_sd, PathState *state, Ray *ray, float3 *shadow)
{
*shadow = make_float3(1.0f, 1.0f, 1.0f);
@@ -59,14 +59,20 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *
/* intersect to find an opaque surface, or record all transparent surface hits */
Intersection hits_stack[STACK_MAX_HITS];
Intersection *hits = hits_stack;
- uint max_hits = kernel_data.integrator.transparent_max_bounce - state->transparent_bounce - 1;
+ const int transparent_max_bounce = kernel_data.integrator.transparent_max_bounce;
+ uint max_hits = transparent_max_bounce - state->transparent_bounce - 1;
/* prefer to use stack but use dynamic allocation if too deep max hits
* we need max_hits + 1 storage space due to the logic in
* scene_intersect_shadow_all which will first store and then check if
* the limit is exceeded */
- if(max_hits + 1 > STACK_MAX_HITS)
- hits = (Intersection*)malloc(sizeof(Intersection)*(max_hits + 1));
+ if(max_hits + 1 > STACK_MAX_HITS) {
+ if(kg->transparent_shadow_intersections == NULL) {
+ kg->transparent_shadow_intersections =
+ (Intersection*)malloc(sizeof(Intersection)*(transparent_max_bounce + 1));
+ }
+ hits = kg->transparent_shadow_intersections;
+ }
uint num_hits;
blocked = scene_intersect_shadow_all(kg, ray, hits, max_hits, &num_hits);
@@ -101,39 +107,36 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *
if(ps.volume_stack[0].shader != SHADER_NONE) {
Ray segment_ray = *ray;
segment_ray.t = isect->t;
- kernel_volume_shadow(kg, &ps, &segment_ray, &throughput);
+ kernel_volume_shadow(kg, shadow_sd, &ps, &segment_ray, &throughput);
}
#endif
/* setup shader data at surface */
- ShaderData sd;
- shader_setup_from_ray(kg, &sd, isect, ray);
+ shader_setup_from_ray(kg, shadow_sd, isect, ray);
/* attenuation from transparent surface */
- if(!(sd.flag & SD_HAS_ONLY_VOLUME)) {
+ if(!(shadow_sd->flag & SD_HAS_ONLY_VOLUME)) {
path_state_modify_bounce(state, true);
- shader_eval_surface(kg, &sd, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
+ shader_eval_surface(kg, shadow_sd, NULL, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
path_state_modify_bounce(state, false);
- throughput *= shader_bsdf_transparency(kg, &sd);
+ throughput *= shader_bsdf_transparency(kg, shadow_sd);
}
/* stop if all light is blocked */
if(is_zero(throughput)) {
- /* free dynamic storage */
- if(hits != hits_stack)
- free(hits);
return true;
}
/* move ray forward */
- ray->P = sd.P;
- if(ray->t != FLT_MAX)
+ ray->P = shadow_sd->P;
+ if(ray->t != FLT_MAX) {
ray->D = normalize_len(Pend - ray->P, &ray->t);
+ }
#ifdef __VOLUME__
/* exit/enter volume */
- kernel_volume_stack_enter_exit(kg, &sd, ps.volume_stack);
+ kernel_volume_stack_enter_exit(kg, shadow_sd, ps.volume_stack);
#endif
bounce++;
@@ -142,29 +145,23 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *
#ifdef __VOLUME__
/* attenuation for last line segment towards light */
if(ps.volume_stack[0].shader != SHADER_NONE)
- kernel_volume_shadow(kg, &ps, ray, &throughput);
+ kernel_volume_shadow(kg, shadow_sd, &ps, ray, &throughput);
#endif
*shadow = throughput;
- if(hits != hits_stack)
- free(hits);
return is_zero(throughput);
}
-
- /* free dynamic storage */
- if(hits != hits_stack)
- free(hits);
}
else {
Intersection isect;
- blocked = scene_intersect(kg, ray, PATH_RAY_SHADOW_OPAQUE, &isect, NULL, 0.0f, 0.0f);
+ blocked = scene_intersect(kg, *ray, PATH_RAY_SHADOW_OPAQUE, &isect, NULL, 0.0f, 0.0f);
}
#ifdef __VOLUME__
if(!blocked && state->volume_stack[0].shader != SHADER_NONE) {
/* apply attenuation from current volume shader */
- kernel_volume_shadow(kg, state, ray, shadow);
+ kernel_volume_shadow(kg, shadow_sd, state, ray, shadow);
}
#endif
@@ -184,6 +181,7 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *
* one extra ray cast for the cases were we do want transparency. */
ccl_device_noinline bool shadow_blocked(KernelGlobals *kg,
+ ShaderData *shadow_sd,
ccl_addr_space PathState *state,
ccl_addr_space Ray *ray_input,
float3 *shadow)
@@ -207,7 +205,7 @@ ccl_device_noinline bool shadow_blocked(KernelGlobals *kg,
Intersection *isect = &isect_object;
#endif
- bool blocked = scene_intersect(kg, ray, PATH_RAY_SHADOW_OPAQUE, isect, NULL, 0.0f, 0.0f);
+ bool blocked = scene_intersect(kg, *ray, PATH_RAY_SHADOW_OPAQUE, isect, NULL, 0.0f, 0.0f);
#ifdef __TRANSPARENT_SHADOWS__
if(blocked && kernel_data.integrator.transparent_shadows) {
@@ -223,12 +221,12 @@ ccl_device_noinline bool shadow_blocked(KernelGlobals *kg,
if(bounce >= kernel_data.integrator.transparent_max_bounce)
return true;
- if(!scene_intersect(kg, ray, PATH_RAY_SHADOW_TRANSPARENT, isect, NULL, 0.0f, 0.0f))
+ if(!scene_intersect(kg, *ray, PATH_RAY_SHADOW_TRANSPARENT, isect, NULL, 0.0f, 0.0f))
{
#ifdef __VOLUME__
/* attenuation for last line segment towards light */
if(ps.volume_stack[0].shader != SHADER_NONE)
- kernel_volume_shadow(kg, &ps, ray, &throughput);
+ kernel_volume_shadow(kg, shadow_sd, &ps, ray, &throughput);
#endif
*shadow *= throughput;
@@ -236,47 +234,45 @@ ccl_device_noinline bool shadow_blocked(KernelGlobals *kg,
return false;
}
- if(!shader_transparent_shadow(kg, isect))
+ if(!shader_transparent_shadow(kg, isect)) {
return true;
+ }
#ifdef __VOLUME__
/* attenuation between last surface and next surface */
if(ps.volume_stack[0].shader != SHADER_NONE) {
Ray segment_ray = *ray;
segment_ray.t = isect->t;
- kernel_volume_shadow(kg, &ps, &segment_ray, &throughput);
+ kernel_volume_shadow(kg, shadow_sd, &ps, &segment_ray, &throughput);
}
#endif
/* setup shader data at surface */
-#ifdef __SPLIT_KERNEL__
- ShaderData *sd = kg->sd_input;
-#else
- ShaderData sd_object;
- ShaderData *sd = &sd_object;
-#endif
- shader_setup_from_ray(kg, sd, isect, ray);
+ shader_setup_from_ray(kg, shadow_sd, isect, ray);
/* attenuation from transparent surface */
- if(!(ccl_fetch(sd, flag) & SD_HAS_ONLY_VOLUME)) {
+ if(!(ccl_fetch(shadow_sd, flag) & SD_HAS_ONLY_VOLUME)) {
path_state_modify_bounce(state, true);
- shader_eval_surface(kg, sd, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
+ shader_eval_surface(kg, shadow_sd, NULL, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
path_state_modify_bounce(state, false);
- throughput *= shader_bsdf_transparency(kg, sd);
+ throughput *= shader_bsdf_transparency(kg, shadow_sd);
}
- if(is_zero(throughput))
+ /* stop if all light is blocked */
+ if(is_zero(throughput)) {
return true;
+ }
/* move ray forward */
- ray->P = ray_offset(ccl_fetch(sd, P), -ccl_fetch(sd, Ng));
- if(ray->t != FLT_MAX)
+ ray->P = ray_offset(ccl_fetch(shadow_sd, P), -ccl_fetch(shadow_sd, Ng));
+ if(ray->t != FLT_MAX) {
ray->D = normalize_len(Pend - ray->P, &ray->t);
+ }
#ifdef __VOLUME__
/* exit/enter volume */
- kernel_volume_stack_enter_exit(kg, sd, ps.volume_stack);
+ kernel_volume_stack_enter_exit(kg, shadow_sd, ps.volume_stack);
#endif
bounce++;
@@ -286,7 +282,7 @@ ccl_device_noinline bool shadow_blocked(KernelGlobals *kg,
#ifdef __VOLUME__
else if(!blocked && state->volume_stack[0].shader != SHADER_NONE) {
/* apply attenuation from current volume shader */
- kernel_volume_shadow(kg, state, ray, shadow);
+ kernel_volume_shadow(kg, shadow_sd, state, ray, shadow);
}
#endif
#endif
diff --git a/intern/cycles/kernel/kernel_subsurface.h b/intern/cycles/kernel/kernel_subsurface.h
index 705b57ba6ff..52c05b85aee 100644
--- a/intern/cycles/kernel/kernel_subsurface.h
+++ b/intern/cycles/kernel/kernel_subsurface.h
@@ -85,7 +85,11 @@ ccl_device ShaderClosure *subsurface_scatter_pick_closure(KernelGlobals *kg, Sha
return NULL;
}
-ccl_device float3 subsurface_scatter_eval(ShaderData *sd, ShaderClosure *sc, float disk_r, float r, bool all)
+ccl_device_inline float3 subsurface_scatter_eval(ShaderData *sd,
+ ShaderClosure *sc,
+ float disk_r,
+ float r,
+ bool all)
{
#ifdef BSSRDF_MULTI_EVAL
/* this is the veach one-sample model with balance heuristic, some pdf
@@ -140,24 +144,21 @@ ccl_device void subsurface_scatter_setup_diffuse_bsdf(ShaderData *sd, float3 wei
{
sd->flag &= ~SD_CLOSURE_FLAGS;
sd->randb_closure = 0.0f;
+ sd->num_closure = 0;
+ sd->num_closure_extra = 0;
if(hit) {
- ShaderClosure *sc = &sd->closure[0];
- sd->num_closure = 1;
-
- sc->weight = weight;
- sc->sample_weight = 1.0f;
- sc->data0 = 0.0f;
- sc->data1 = 0.0f;
- sc->N = N;
- sd->flag |= bsdf_diffuse_setup(sc);
-
- /* replace CLOSURE_BSDF_DIFFUSE_ID with this special ID so render passes
- * can recognize it as not being a regular diffuse closure */
- sc->type = CLOSURE_BSDF_BSSRDF_ID;
+ DiffuseBsdf *bsdf = (DiffuseBsdf*)bsdf_alloc(sd, sizeof(DiffuseBsdf), weight);
+
+ if(bsdf) {
+ bsdf->N = N;
+ sd->flag |= bsdf_diffuse_setup(bsdf);
+
+ /* replace CLOSURE_BSDF_DIFFUSE_ID with this special ID so render passes
+ * can recognize it as not being a regular diffuse closure */
+ bsdf->type = CLOSURE_BSDF_BSSRDF_ID;
+ }
}
- else
- sd->num_closure = 0;
}
/* optionally do blurring of color and/or bump mapping, at the cost of a shader evaluation */
@@ -198,7 +199,7 @@ ccl_device void subsurface_color_bump_blur(KernelGlobals *kg,
if(bump || texture_blur > 0.0f) {
/* average color and normal at incoming point */
- shader_eval_surface(kg, sd, state, 0.0f, state_flag, SHADER_CONTEXT_SSS);
+ shader_eval_surface(kg, sd, NULL, state, 0.0f, state_flag, SHADER_CONTEXT_SSS);
float3 in_color = shader_bssrdf_sum(sd, (bump)? N: NULL, NULL);
/* we simply divide out the average color and multiply with the average
@@ -217,9 +218,9 @@ ccl_device void subsurface_color_bump_blur(KernelGlobals *kg,
/* Subsurface scattering step, from a point on the surface to other
* nearby points on the same object.
*/
-ccl_device int subsurface_scatter_multi_intersect(
+ccl_device_inline int subsurface_scatter_multi_intersect(
KernelGlobals *kg,
- SubsurfaceIntersection* ss_isect,
+ SubsurfaceIntersection *ss_isect,
ShaderData *sd,
ShaderClosure *sc,
uint *lcg_state,
@@ -319,6 +320,10 @@ ccl_device int subsurface_scatter_multi_intersect(
verts);
}
#endif /* __OBJECT_MOTION__ */
+ else {
+ ss_isect->weight[hit] = make_float3(0.0f, 0.0f, 0.0f);
+ continue;
+ }
float3 hit_Ng = ss_isect->Ng[hit];
if(ss_isect->hits[hit].object != OBJECT_NONE) {
@@ -349,14 +354,15 @@ ccl_device int subsurface_scatter_multi_intersect(
return num_eval_hits;
}
-ccl_device void subsurface_scatter_multi_setup(KernelGlobals *kg,
- SubsurfaceIntersection* ss_isect,
- int hit,
- ShaderData *sd,
- PathState *state,
- int state_flag,
- ShaderClosure *sc,
- bool all)
+ccl_device_noinline void subsurface_scatter_multi_setup(
+ KernelGlobals *kg,
+ SubsurfaceIntersection* ss_isect,
+ int hit,
+ ShaderData *sd,
+ PathState *state,
+ int state_flag,
+ ShaderClosure *sc,
+ bool all)
{
/* Setup new shading point. */
shader_setup_from_subsurface(kg, sd, &ss_isect->hits[hit], &ss_isect->ray);
diff --git a/intern/cycles/kernel/kernel_textures.h b/intern/cycles/kernel/kernel_textures.h
index 62b0a6f2923..8d5bb75a428 100644
--- a/intern/cycles/kernel/kernel_textures.h
+++ b/intern/cycles/kernel/kernel_textures.h
@@ -25,7 +25,8 @@
/* bvh */
KERNEL_TEX(float4, texture_float4, __bvh_nodes)
KERNEL_TEX(float4, texture_float4, __bvh_leaf_nodes)
-KERNEL_TEX(float4, texture_float4, __tri_storage)
+KERNEL_TEX(float4, texture_float4, __prim_tri_verts)
+KERNEL_TEX(uint, texture_uint, __prim_tri_index)
KERNEL_TEX(uint, texture_uint, __prim_type)
KERNEL_TEX(uint, texture_uint, __prim_visibility)
KERNEL_TEX(uint, texture_uint, __prim_index)
@@ -39,13 +40,17 @@ KERNEL_TEX(float4, texture_float4, __objects_vector)
/* triangles */
KERNEL_TEX(uint, texture_uint, __tri_shader)
KERNEL_TEX(float4, texture_float4, __tri_vnormal)
-KERNEL_TEX(float4, texture_float4, __tri_vindex)
-KERNEL_TEX(float4, texture_float4, __tri_verts)
+KERNEL_TEX(uint4, texture_uint4, __tri_vindex)
+KERNEL_TEX(uint, texture_uint, __tri_patch)
+KERNEL_TEX(float2, texture_float2, __tri_patch_uv)
/* curves */
KERNEL_TEX(float4, texture_float4, __curves)
KERNEL_TEX(float4, texture_float4, __curve_keys)
+/* patches */
+KERNEL_TEX(uint, texture_uint, __patches)
+
/* attributes */
KERNEL_TEX(uint4, texture_uint4, __attributes_map)
KERNEL_TEX(float, texture_float, __attributes_float)
@@ -72,6 +77,8 @@ KERNEL_TEX(float, texture_float, __lookup_table)
/* sobol */
KERNEL_TEX(uint, texture_uint, __sobol_directions)
+#ifdef __KERNEL_CUDA__
+# if __CUDA_ARCH__ < 300
/* full-float image */
KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float4_000)
KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float4_001)
@@ -171,73 +178,18 @@ KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_086)
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_087)
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_088)
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_089)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_090)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_091)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_092)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_093)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_094)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_095)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_096)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_097)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_098)
-
-/* Kepler and above */
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_099)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_100)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_101)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_102)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_103)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_104)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_105)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_106)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_107)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_108)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_109)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_110)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_111)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_112)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_113)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_114)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_115)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_116)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_117)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_118)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_119)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_120)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_121)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_122)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_123)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_124)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_125)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_126)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_127)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_128)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_129)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_130)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_131)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_132)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_133)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_134)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_135)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_136)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_137)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_138)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_139)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_140)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_141)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_142)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_143)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_144)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_145)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_146)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_147)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_148)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_149)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_150)
+
+# else
+/* bindless textures */
+KERNEL_TEX(uint, texture_uint, __bindless_mapping)
+# endif
+#endif
/* packed image (opencl) */
KERNEL_TEX(uchar4, texture_uchar4, __tex_image_byte4_packed)
KERNEL_TEX(float4, texture_float4, __tex_image_float4_packed)
+KERNEL_TEX(uchar, texture_uchar, __tex_image_byte_packed)
+KERNEL_TEX(float, texture_float, __tex_image_float_packed)
KERNEL_TEX(uint4, texture_uint4, __tex_image_packed_info)
#undef KERNEL_TEX
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index 05edf0eae2c..8220934312b 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -19,6 +19,7 @@
#include "kernel_math.h"
#include "svm/svm_types.h"
+#include "util_static_assert.h"
#ifndef __KERNEL_GPU__
# define __KERNEL_CPU__
@@ -34,14 +35,14 @@
CCL_NAMESPACE_BEGIN
/* constants */
-#define OBJECT_SIZE 11
+#define OBJECT_SIZE 12
#define OBJECT_VECTOR_SIZE 6
-#define LIGHT_SIZE 5
+#define LIGHT_SIZE 11
#define FILTER_TABLE_SIZE 1024
#define RAMP_TABLE_SIZE 256
#define SHUTTER_TABLE_SIZE 256
#define PARTICLE_SIZE 5
-#define TIME_INVALID FLT_MAX
+#define SHADER_SIZE 5
#define BSSRDF_MIN_RADIUS 1e-8f
#define BSSRDF_MAX_HITS 4
@@ -115,18 +116,7 @@ CCL_NAMESPACE_BEGIN
# ifdef __KERNEL_OPENCL_AMD__
# define __CL_USE_NATIVE__
# define __KERNEL_SHADING__
-# define __MULTI_CLOSURE__
-# define __PASSES__
-# define __BACKGROUND_MIS__
-# define __LAMP_MIS__
-# define __AO__
-# define __CAMERA_MOTION__
-# define __OBJECT_MOTION__
-# define __HAIR__
-# define __BAKING__
-# ifdef __KERNEL_EXPERIMENTAL__
-# define __TRANSPARENT_SHADOWS__
-# endif
+# define __KERNEL_ADV_SHADING__
# endif /* __KERNEL_OPENCL_AMD__ */
# ifdef __KERNEL_OPENCL_INTEL_CPU__
@@ -152,6 +142,7 @@ CCL_NAMESPACE_BEGIN
#define __CAMERA_CLIPPING__
#define __INTERSECTION_REFINE__
#define __CLAMP_SAMPLE__
+#define __PATCH_EVAL__
#ifdef __KERNEL_SHADING__
# define __SVM__
@@ -201,6 +192,9 @@ CCL_NAMESPACE_BEGIN
#ifdef __NO_BRANCHED_PATH__
# undef __BRANCHED_PATH__
#endif
+#ifdef __NO_PATCH_EVAL__
+# undef __PATCH_EVAL__
+#endif
/* Random Numbers */
@@ -279,10 +273,7 @@ enum SamplingPattern {
SAMPLING_NUM_PATTERNS,
};
-/* these flags values correspond to raytypes in osl.cpp, so keep them in sync!
- *
- * for ray visibility tests in BVH traversal, the upper 20 bits are used for
- * layer visibility tests. */
+/* these flags values correspond to raytypes in osl.cpp, so keep them in sync! */
enum PathRayFlag {
PATH_RAY_CAMERA = 1,
@@ -300,15 +291,14 @@ enum PathRayFlag {
PATH_RAY_CURVE = 512, /* visibility flag to define curve segments */
PATH_RAY_VOLUME_SCATTER = 1024, /* volume scattering */
- /* note that these can use maximum 12 bits, the other are for layers */
- PATH_RAY_ALL_VISIBILITY = (1|2|4|8|16|32|64|128|256|512|1024),
+ /* Special flag to tag unaligned BVH nodes. */
+ PATH_RAY_NODE_UNALIGNED = 2048,
- PATH_RAY_MIS_SKIP = 2048,
- PATH_RAY_DIFFUSE_ANCESTOR = 4096,
- PATH_RAY_SINGLE_PASS_DONE = 8192,
+ PATH_RAY_ALL_VISIBILITY = (1|2|4|8|16|32|64|128|256|512|1024|2048),
- /* we need layer member flags to be the 20 upper bits */
- PATH_RAY_LAYER_SHIFT = (32-20)
+ PATH_RAY_MIS_SKIP = 4096,
+ PATH_RAY_DIFFUSE_ANCESTOR = 8192,
+ PATH_RAY_SINGLE_PASS_DONE = 16384,
};
/* Closure Label */
@@ -396,12 +386,13 @@ typedef enum BakePassFilterCombos {
BAKE_FILTER_SUBSURFACE_INDIRECT = (BAKE_FILTER_INDIRECT | BAKE_FILTER_SUBSURFACE),
} BakePassFilterCombos;
-#ifdef __PASSES__
-
typedef ccl_addr_space struct PathRadiance {
+#ifdef __PASSES__
int use_light_pass;
+#endif
float3 emission;
+#ifdef __PASSES__
float3 background;
float3 ao;
@@ -435,25 +426,23 @@ typedef ccl_addr_space struct PathRadiance {
float4 shadow;
float mist;
+#endif
} PathRadiance;
typedef struct BsdfEval {
+#ifdef __PASSES__
int use_light_pass;
+#endif
float3 diffuse;
+#ifdef __PASSES__
float3 glossy;
float3 transmission;
float3 transparent;
float3 subsurface;
float3 scatter;
-} BsdfEval;
-
-#else
-
-typedef ccl_addr_space float3 PathRadiance;
-typedef float3 BsdfEval;
-
#endif
+} BsdfEval;
/* Shader Flag */
@@ -566,6 +555,8 @@ typedef enum PrimitiveType {
PRIMITIVE_MOTION_TRIANGLE = 2,
PRIMITIVE_CURVE = 4,
PRIMITIVE_MOTION_CURVE = 8,
+ /* Lamp primitive is not included below on purpose, since it is no real traceable primitive */
+ PRIMITIVE_LAMP = 16,
PRIMITIVE_ALL_TRIANGLE = (PRIMITIVE_TRIANGLE|PRIMITIVE_MOTION_TRIANGLE),
PRIMITIVE_ALL_CURVE = (PRIMITIVE_CURVE|PRIMITIVE_MOTION_CURVE),
@@ -583,8 +574,13 @@ typedef enum PrimitiveType {
/* Attributes */
-#define ATTR_PRIM_TYPES 2
-#define ATTR_PRIM_CURVE 1
+typedef enum AttributePrimitive {
+ ATTR_PRIM_TRIANGLE = 0,
+ ATTR_PRIM_CURVE,
+ ATTR_PRIM_SUBD,
+
+ ATTR_PRIM_TYPES
+} AttributePrimitive;
typedef enum AttributeElement {
ATTR_ELEMENT_NONE,
@@ -629,6 +625,18 @@ typedef enum AttributeStandard {
ATTR_STD_NOT_FOUND = ~0
} AttributeStandard;
+typedef enum AttributeFlag {
+ ATTR_FINAL_SIZE = (1 << 0),
+ ATTR_SUBDIVIDED = (1 << 1),
+} AttributeFlag;
+
+typedef struct AttributeDescriptor {
+ AttributeElement element;
+ NodeAttributeType type;
+ uint flags; /* see enum AttributeFlag */
+ int offset;
+} AttributeDescriptor;
+
/* Closure data */
#ifdef __MULTI_CLOSURE__
@@ -641,33 +649,26 @@ typedef enum AttributeStandard {
# define MAX_CLOSURE 1
#endif
-/* This struct is to be 16 bytes aligned, we also keep some extra precautions:
- * - All the float3 members are in the beginning of the struct, so compiler
- * does not put own padding trying to align this members.
- * - We make sure OSL pointer is also 16 bytes aligned.
- */
-typedef ccl_addr_space struct ShaderClosure {
- float3 weight;
- float3 N;
- float3 T;
-
- ClosureType type;
- float sample_weight;
- float data0;
- float data1;
- float data2;
-
- /* Following fields could be used to store pre-calculated
- * values by various BSDF closures for more effective sampling
- * and evaluation.
- */
- float custom1;
- float custom2;
- float custom3;
+/* This struct is the base class for all closures. The common members are
+ * duplicated in all derived classes since we don't have C++ in the kernel
+ * yet, and because it lets us lay out the members to minimize padding. The
+ * weight member is located at the beginning of the struct for this reason.
+ *
+ * ShaderClosure has a fixed size, and any extra space must be allocated
+ * with closure_alloc_extra().
+ *
+ * We pad the struct to 80 bytes and ensure it is aligned to 16 bytes, which
+ * we assume to be the maximum required alignment for any struct. */
-#ifdef __OSL__
- void *prim, *pad4;
-#endif
+#define SHADER_CLOSURE_BASE \
+ float3 weight; \
+ ClosureType type; \
+ float sample_weight \
+
+typedef ccl_addr_space struct ccl_align(16) ShaderClosure {
+ SHADER_CLOSURE_BASE;
+
+ float data[14]; /* pad to 80 bytes */
} ShaderClosure;
/* Shader Context
@@ -691,139 +692,149 @@ typedef enum ShaderContext {
enum ShaderDataFlag {
/* runtime flags */
- SD_BACKFACING = (1 << 0), /* backside of surface? */
- SD_EMISSION = (1 << 1), /* have emissive closure? */
- SD_BSDF = (1 << 2), /* have bsdf closure? */
- SD_BSDF_HAS_EVAL = (1 << 3), /* have non-singular bsdf closure? */
- SD_BSSRDF = (1 << 4), /* have bssrdf */
- SD_HOLDOUT = (1 << 5), /* have holdout closure? */
- SD_ABSORPTION = (1 << 6), /* have volume absorption closure? */
- SD_SCATTER = (1 << 7), /* have volume phase closure? */
- SD_AO = (1 << 8), /* have ao closure? */
- SD_TRANSPARENT = (1 << 9), /* have transparent closure? */
+ SD_BACKFACING = (1 << 0), /* backside of surface? */
+ SD_EMISSION = (1 << 1), /* have emissive closure? */
+ SD_BSDF = (1 << 2), /* have bsdf closure? */
+ SD_BSDF_HAS_EVAL = (1 << 3), /* have non-singular bsdf closure? */
+ SD_BSSRDF = (1 << 4), /* have bssrdf */
+ SD_HOLDOUT = (1 << 5), /* have holdout closure? */
+ SD_ABSORPTION = (1 << 6), /* have volume absorption closure? */
+ SD_SCATTER = (1 << 7), /* have volume phase closure? */
+ SD_AO = (1 << 8), /* have ao closure? */
+ SD_TRANSPARENT = (1 << 9), /* have transparent closure? */
+ SD_BSDF_NEEDS_LCG = (1 << 10),
SD_CLOSURE_FLAGS = (SD_EMISSION|SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSSRDF|
- SD_HOLDOUT|SD_ABSORPTION|SD_SCATTER|SD_AO),
+ SD_HOLDOUT|SD_ABSORPTION|SD_SCATTER|SD_AO|
+ SD_BSDF_NEEDS_LCG),
/* shader flags */
- SD_USE_MIS = (1 << 10), /* direct light sample */
- SD_HAS_TRANSPARENT_SHADOW = (1 << 11), /* has transparent shadow */
- SD_HAS_VOLUME = (1 << 12), /* has volume shader */
- SD_HAS_ONLY_VOLUME = (1 << 13), /* has only volume shader, no surface */
- SD_HETEROGENEOUS_VOLUME = (1 << 14), /* has heterogeneous volume */
- SD_HAS_BSSRDF_BUMP = (1 << 15), /* bssrdf normal uses bump */
- SD_VOLUME_EQUIANGULAR = (1 << 16), /* use equiangular sampling */
- SD_VOLUME_MIS = (1 << 17), /* use multiple importance sampling */
- SD_VOLUME_CUBIC = (1 << 18), /* use cubic interpolation for voxels */
- SD_HAS_BUMP = (1 << 19), /* has data connected to the displacement input */
+ SD_USE_MIS = (1 << 12), /* direct light sample */
+ SD_HAS_TRANSPARENT_SHADOW = (1 << 13), /* has transparent shadow */
+ SD_HAS_VOLUME = (1 << 14), /* has volume shader */
+ SD_HAS_ONLY_VOLUME = (1 << 15), /* has only volume shader, no surface */
+ SD_HETEROGENEOUS_VOLUME = (1 << 16), /* has heterogeneous volume */
+ SD_HAS_BSSRDF_BUMP = (1 << 17), /* bssrdf normal uses bump */
+ SD_VOLUME_EQUIANGULAR = (1 << 18), /* use equiangular sampling */
+ SD_VOLUME_MIS = (1 << 19), /* use multiple importance sampling */
+ SD_VOLUME_CUBIC = (1 << 20), /* use cubic interpolation for voxels */
+ SD_HAS_BUMP = (1 << 21), /* has data connected to the displacement input */
+ SD_HAS_DISPLACEMENT = (1 << 22), /* has true displacement */
+ SD_HAS_CONSTANT_EMISSION = (1 << 23), /* has constant emission (value stored in __shader_flag) */
SD_SHADER_FLAGS = (SD_USE_MIS|SD_HAS_TRANSPARENT_SHADOW|SD_HAS_VOLUME|
SD_HAS_ONLY_VOLUME|SD_HETEROGENEOUS_VOLUME|
SD_HAS_BSSRDF_BUMP|SD_VOLUME_EQUIANGULAR|SD_VOLUME_MIS|
- SD_VOLUME_CUBIC|SD_HAS_BUMP),
+ SD_VOLUME_CUBIC|SD_HAS_BUMP|SD_HAS_DISPLACEMENT|SD_HAS_CONSTANT_EMISSION),
/* object flags */
- SD_HOLDOUT_MASK = (1 << 20), /* holdout for camera rays */
- SD_OBJECT_MOTION = (1 << 21), /* has object motion blur */
- SD_TRANSFORM_APPLIED = (1 << 22), /* vertices have transform applied */
- SD_NEGATIVE_SCALE_APPLIED = (1 << 23), /* vertices have negative scale applied */
- SD_OBJECT_HAS_VOLUME = (1 << 24), /* object has a volume shader */
- SD_OBJECT_INTERSECTS_VOLUME = (1 << 25), /* object intersects AABB of an object with volume shader */
- SD_OBJECT_HAS_VERTEX_MOTION = (1 << 26), /* has position for motion vertices */
+ SD_HOLDOUT_MASK = (1 << 24), /* holdout for camera rays */
+ SD_OBJECT_MOTION = (1 << 25), /* has object motion blur */
+ SD_TRANSFORM_APPLIED = (1 << 26), /* vertices have transform applied */
+ SD_NEGATIVE_SCALE_APPLIED = (1 << 27), /* vertices have negative scale applied */
+ SD_OBJECT_HAS_VOLUME = (1 << 28), /* object has a volume shader */
+ SD_OBJECT_INTERSECTS_VOLUME = (1 << 29), /* object intersects AABB of an object with volume shader */
+ SD_OBJECT_HAS_VERTEX_MOTION = (1 << 30), /* has position for motion vertices */
SD_OBJECT_FLAGS = (SD_HOLDOUT_MASK|SD_OBJECT_MOTION|SD_TRANSFORM_APPLIED|
SD_NEGATIVE_SCALE_APPLIED|SD_OBJECT_HAS_VOLUME|
SD_OBJECT_INTERSECTS_VOLUME)
};
-struct KernelGlobals;
-
#ifdef __SPLIT_KERNEL__
# define SD_THREAD (get_global_id(1) * get_global_size(0) + get_global_id(0))
-# if defined(__SPLIT_KERNEL_AOS__)
+# if !defined(__SPLIT_KERNEL_SOA__)
/* ShaderData is stored as an Array-of-Structures */
-# define ccl_fetch(s, t) (s[SD_THREAD].t)
-# define ccl_fetch_array(s, t, index) (&s[SD_THREAD].t[index])
+# define ccl_soa_member(type, name) type soa_##name
+# define ccl_fetch(s, t) (s[SD_THREAD].soa_##t)
+# define ccl_fetch_array(s, t, index) (&s[SD_THREAD].soa_##t[index])
# else
/* ShaderData is stored as an Structure-of-Arrays */
# define SD_GLOBAL_SIZE (get_global_size(0) * get_global_size(1))
# define SD_FIELD_SIZE(t) sizeof(((struct ShaderData*)0)->t)
# define SD_OFFSETOF(t) ((char*)(&((struct ShaderData*)0)->t) - (char*)0)
-# define ccl_fetch(s, t) (((ShaderData*)((ccl_addr_space char*)s + SD_GLOBAL_SIZE * SD_OFFSETOF(t) + SD_FIELD_SIZE(t) * SD_THREAD - SD_OFFSETOF(t)))->t)
+# define ccl_soa_member(type, name) type soa_##name
+# define ccl_fetch(s, t) (((ShaderData*)((ccl_addr_space char*)s + SD_GLOBAL_SIZE * SD_OFFSETOF(soa_##t) + SD_FIELD_SIZE(soa_##t) * SD_THREAD - SD_OFFSETOF(soa_##t)))->soa_##t)
# define ccl_fetch_array(s, t, index) (&ccl_fetch(s, t)[index])
# endif
#else
+# define ccl_soa_member(type, name) type name
# define ccl_fetch(s, t) (s->t)
# define ccl_fetch_array(s, t, index) (&s->t[index])
#endif
typedef ccl_addr_space struct ShaderData {
/* position */
- float3 P;
+ ccl_soa_member(float3, P);
/* smooth normal for shading */
- float3 N;
+ ccl_soa_member(float3, N);
/* true geometric normal */
- float3 Ng;
+ ccl_soa_member(float3, Ng);
/* view/incoming direction */
- float3 I;
+ ccl_soa_member(float3, I);
/* shader id */
- int shader;
+ ccl_soa_member(int, shader);
/* booleans describing shader, see ShaderDataFlag */
- int flag;
+ ccl_soa_member(int, flag);
/* primitive id if there is one, ~0 otherwise */
- int prim;
+ ccl_soa_member(int, prim);
/* combined type and curve segment for hair */
- int type;
+ ccl_soa_member(int, type);
/* parametric coordinates
- * - barycentric weights for triangles */
- float u;
- float v;
+ * - barycentric weights for triangles */
+ ccl_soa_member(float, u);
+ ccl_soa_member(float, v);
/* object id if there is one, ~0 otherwise */
- int object;
+ ccl_soa_member(int, object);
/* motion blur sample time */
- float time;
+ ccl_soa_member(float, time);
/* length of the ray being shaded */
- float ray_length;
+ ccl_soa_member(float, ray_length);
#ifdef __RAY_DIFFERENTIALS__
/* differential of P. these are orthogonal to Ng, not N */
- differential3 dP;
+ ccl_soa_member(differential3, dP);
/* differential of I */
- differential3 dI;
+ ccl_soa_member(differential3, dI);
/* differential of u, v */
- differential du;
- differential dv;
+ ccl_soa_member(differential, du);
+ ccl_soa_member(differential, dv);
#endif
#ifdef __DPDU__
/* differential of P w.r.t. parametric coordinates. note that dPdu is
- * not readily suitable as a tangent for shading on triangles. */
- float3 dPdu;
- float3 dPdv;
+ * not readily suitable as a tangent for shading on triangles. */
+ ccl_soa_member(float3, dPdu);
+ ccl_soa_member(float3, dPdv);
#endif
#ifdef __OBJECT_MOTION__
/* object <-> world space transformations, cached to avoid
- * re-interpolating them constantly for shading */
- Transform ob_tfm;
- Transform ob_itfm;
+ * re-interpolating them constantly for shading */
+ ccl_soa_member(Transform, ob_tfm);
+ ccl_soa_member(Transform, ob_itfm);
#endif
/* Closure data, we store a fixed array of closures */
- struct ShaderClosure closure[MAX_CLOSURE];
- int num_closure;
- float randb_closure;
+ ccl_soa_member(struct ShaderClosure, closure[MAX_CLOSURE]);
+ ccl_soa_member(int, num_closure);
+ ccl_soa_member(int, num_closure_extra);
+ ccl_soa_member(float, randb_closure);
+ ccl_soa_member(float3, svm_closure_weight);
+
+ /* LCG state for closures that require additional random numbers. */
+ ccl_soa_member(uint, lcg_state);
/* ray start position, only set for backgrounds */
- float3 ray_P;
- differential3 ray_dP;
+ ccl_soa_member(float3, ray_P);
+ ccl_soa_member(differential3, ray_dP);
#ifdef __OSL__
- struct KernelGlobals * osl_globals;
+ struct KernelGlobals *osl_globals;
struct PathState *osl_path_state;
#endif
} ShaderData;
@@ -912,9 +923,10 @@ typedef struct KernelCamera {
float4 equirectangular_range;
/* stereo */
- int pad1, pad2;
float interocular_offset;
float convergence_distance;
+ float pole_merge_angle_from;
+ float pole_merge_angle_to;
/* matrices */
Transform cameratoworld;
@@ -977,6 +989,7 @@ typedef struct KernelCamera {
int pad;
} KernelCamera;
+static_assert_align(KernelCamera, 16);
typedef struct KernelFilm {
float exposure;
@@ -1031,6 +1044,7 @@ typedef struct KernelFilm {
int pass_pad3;
#endif
} KernelFilm;
+static_assert_align(KernelFilm, 16);
typedef struct KernelBackground {
/* only shader index */
@@ -1044,6 +1058,7 @@ typedef struct KernelBackground {
float ao_distance;
float ao_pad1, ao_pad2;
} KernelBackground;
+static_assert_align(KernelBackground, 16);
typedef struct KernelIntegrator {
/* emission */
@@ -1083,9 +1098,6 @@ typedef struct KernelIntegrator {
/* seed */
int seed;
- /* render layer */
- int layer_flag;
-
/* clamp */
float sample_clamp_direct;
float sample_clamp_indirect;
@@ -1114,8 +1126,10 @@ typedef struct KernelIntegrator {
float volume_step_size;
int volume_samples;
- int pad;
+ int pad1;
+ int pad2;
} KernelIntegrator;
+static_assert_align(KernelIntegrator, 16);
typedef struct KernelBVH {
/* root node */
@@ -1127,6 +1141,7 @@ typedef struct KernelBVH {
int use_qbvh;
int pad1, pad2;
} KernelBVH;
+static_assert_align(KernelBVH, 16);
typedef enum CurveFlag {
/* runtime flags */
@@ -1146,12 +1161,14 @@ typedef struct KernelCurves {
float minimum_width;
float maximum_width;
} KernelCurves;
+static_assert_align(KernelCurves, 16);
typedef struct KernelTables {
int beckmann_offset;
int num_volumes;
int density_index, pad2;
} KernelTables;
+static_assert_align(KernelTables, 16);
typedef struct KernelData {
KernelCamera cam;
@@ -1162,8 +1179,12 @@ typedef struct KernelData {
KernelCurves curve;
KernelTables tables;
} KernelData;
+static_assert_align(KernelData, 16);
#ifdef __KERNEL_DEBUG__
+/* NOTE: This is a runtime-only struct, alignment is not
+ * really important here.
+ */
typedef ccl_addr_space struct DebugData {
// Total number of BVH node traversal steps and primitives intersections
// for the camera rays.
@@ -1180,11 +1201,11 @@ typedef ccl_addr_space struct DebugData {
#define QUEUE_EMPTY_SLOT -1
/*
-* Queue 1 - Active rays
-* Queue 2 - Background queue
-* Queue 3 - Shadow ray cast kernel - AO
-* Queeu 4 - Shadow ray cast kernel - direct lighting
-*/
+ * Queue 1 - Active rays
+ * Queue 2 - Background queue
+ * Queue 3 - Shadow ray cast kernel - AO
+ * Queeu 4 - Shadow ray cast kernel - direct lighting
+ */
#define NUM_QUEUES 4
/* Queue names */
@@ -1241,6 +1262,16 @@ enum RayState {
#define REMOVE_RAY_FLAG(ray_state, ray_index, flag) (ray_state[ray_index] = (ray_state[ray_index] & (~flag)))
#define IS_FLAG(ray_state, ray_index, flag) (ray_state[ray_index] & flag)
+/* Patches */
+
+#define PATCH_MAX_CONTROL_VERTS 16
+
+/* Patch map node flags */
+
+#define PATCH_MAP_NODE_IS_SET (1 << 30)
+#define PATCH_MAP_NODE_IS_LEAF (1u << 31)
+#define PATCH_MAP_NODE_INDEX_MASK (~(PATCH_MAP_NODE_IS_SET | PATCH_MAP_NODE_IS_LEAF))
+
CCL_NAMESPACE_END
#endif /* __KERNEL_TYPES_H__ */
diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h
index c69ed9bc862..f0e9b68a9a4 100644
--- a/intern/cycles/kernel/kernel_volume.h
+++ b/intern/cycles/kernel/kernel_volume.h
@@ -37,7 +37,11 @@ typedef struct VolumeShaderCoefficients {
} VolumeShaderCoefficients;
/* evaluate shader to get extinction coefficient at P */
-ccl_device bool volume_shader_extinction_sample(KernelGlobals *kg, ShaderData *sd, PathState *state, float3 P, float3 *extinction)
+ccl_device_inline bool volume_shader_extinction_sample(KernelGlobals *kg,
+ ShaderData *sd,
+ PathState *state,
+ float3 P,
+ float3 *extinction)
{
sd->P = P;
shader_eval_volume(kg, sd, state, state->volume_stack, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
@@ -59,7 +63,11 @@ ccl_device bool volume_shader_extinction_sample(KernelGlobals *kg, ShaderData *s
}
/* evaluate shader to get absorption, scattering and emission at P */
-ccl_device bool volume_shader_sample(KernelGlobals *kg, ShaderData *sd, PathState *state, float3 P, VolumeShaderCoefficients *coeff)
+ccl_device_inline bool volume_shader_sample(KernelGlobals *kg,
+ ShaderData *sd,
+ PathState *state,
+ float3 P,
+ VolumeShaderCoefficients *coeff)
{
sd->P = P;
shader_eval_volume(kg, sd, state, state->volume_stack, state->flag, SHADER_CONTEXT_VOLUME);
@@ -108,7 +116,7 @@ ccl_device float kernel_volume_channel_get(float3 value, int channel)
ccl_device bool volume_stack_is_heterogeneous(KernelGlobals *kg, VolumeStack *stack)
{
for(int i = 0; stack[i].shader != SHADER_NONE; i++) {
- int shader_flag = kernel_tex_fetch(__shader_flag, (stack[i].shader & SHADER_MASK)*2);
+ int shader_flag = kernel_tex_fetch(__shader_flag, (stack[i].shader & SHADER_MASK)*SHADER_SIZE);
if(shader_flag & SD_HETEROGENEOUS_VOLUME)
return true;
@@ -125,7 +133,7 @@ ccl_device int volume_stack_sampling_method(KernelGlobals *kg, VolumeStack *stac
int method = -1;
for(int i = 0; stack[i].shader != SHADER_NONE; i++) {
- int shader_flag = kernel_tex_fetch(__shader_flag, (stack[i].shader & SHADER_MASK)*2);
+ int shader_flag = kernel_tex_fetch(__shader_flag, (stack[i].shader & SHADER_MASK)*SHADER_SIZE);
if(shader_flag & SD_VOLUME_MIS) {
return SD_VOLUME_MIS;
@@ -276,15 +284,14 @@ ccl_device void kernel_volume_shadow_heterogeneous(KernelGlobals *kg, PathState
/* get the volume attenuation over line segment defined by ray, with the
* assumption that there are no surfaces blocking light between the endpoints */
-ccl_device_noinline void kernel_volume_shadow(KernelGlobals *kg, PathState *state, Ray *ray, float3 *throughput)
+ccl_device_noinline void kernel_volume_shadow(KernelGlobals *kg, ShaderData *shadow_sd, PathState *state, Ray *ray, float3 *throughput)
{
- ShaderData sd;
- shader_setup_from_volume(kg, &sd, ray);
+ shader_setup_from_volume(kg, shadow_sd, ray);
if(volume_stack_is_heterogeneous(kg, state->volume_stack))
- kernel_volume_shadow_heterogeneous(kg, state, ray, &sd, throughput);
+ kernel_volume_shadow_heterogeneous(kg, state, ray, shadow_sd, throughput);
else
- kernel_volume_shadow_homogeneous(kg, state, ray, &sd, throughput);
+ kernel_volume_shadow_homogeneous(kg, state, ray, shadow_sd, throughput);
}
/* Equi-angular sampling as in:
@@ -334,7 +341,7 @@ ccl_device float kernel_volume_distance_sample(float max_t, float3 sigma_t, int
float sample_t = min(max_t, -logf(1.0f - xi*(1.0f - sample_transmittance))/sample_sigma_t);
*transmittance = volume_color_transmittance(sigma_t, sample_t);
- *pdf = (sigma_t * *transmittance)/(make_float3(1.0f, 1.0f, 1.0f) - full_transmittance);
+ *pdf = safe_divide_color(sigma_t * *transmittance, make_float3(1.0f, 1.0f, 1.0f) - full_transmittance);
/* todo: optimization: when taken together with hit/miss decision,
* the full_transmittance cancels out drops out and xi does not
@@ -348,7 +355,7 @@ ccl_device float3 kernel_volume_distance_pdf(float max_t, float3 sigma_t, float
float3 full_transmittance = volume_color_transmittance(sigma_t, max_t);
float3 transmittance = volume_color_transmittance(sigma_t, sample_t);
- return (sigma_t * transmittance)/(make_float3(1.0f, 1.0f, 1.0f) - full_transmittance);
+ return safe_divide_color(sigma_t * transmittance, make_float3(1.0f, 1.0f, 1.0f) - full_transmittance);
}
/* Emission */
@@ -742,12 +749,36 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg, PathState *sta
const int global_max_steps = kernel_data.integrator.volume_max_steps;
step_size = kernel_data.integrator.volume_step_size;
/* compute exact steps in advance for malloc */
- max_steps = max((int)ceilf(ray->t/step_size), 1);
- if(max_steps > global_max_steps) {
+ if(ray->t > global_max_steps*step_size) {
max_steps = global_max_steps;
step_size = ray->t / (float)max_steps;
}
+ else {
+ max_steps = max((int)ceilf(ray->t/step_size), 1);
+ }
+#ifdef __KERNEL_CPU__
+ /* NOTE: For the branched path tracing it's possible to have direct
+ * and indirect light integration both having volume segments allocated.
+ * We detect this using index in the pre-allocated memory. Currently we
+ * only support two segments allocated at a time, if more needed some
+ * modifications to the KernelGlobals will be needed.
+ *
+ * This gives us restrictions that decoupled record should only happen
+ * in the stack manner, meaning if there's subsequent call of decoupled
+ * record it'll need to free memory before it's caller frees memory.
+ */
+ const int index = kg->decoupled_volume_steps_index;
+ assert(index < sizeof(kg->decoupled_volume_steps) /
+ sizeof(*kg->decoupled_volume_steps));
+ if(kg->decoupled_volume_steps[index] == NULL) {
+ kg->decoupled_volume_steps[index] =
+ (VolumeStep*)malloc(sizeof(VolumeStep)*global_max_steps);
+ }
+ segment->steps = kg->decoupled_volume_steps[index];
+ ++kg->decoupled_volume_steps_index;
+#else
segment->steps = (VolumeStep*)malloc(sizeof(VolumeStep)*max_steps);
+#endif
random_jitter_offset = lcg_step_float(&state->rng_congruential) * step_size;
}
else {
@@ -961,8 +992,18 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg, PathState *sta
ccl_device void kernel_volume_decoupled_free(KernelGlobals *kg, VolumeSegment *segment)
{
- if(segment->steps != &segment->stack_step)
+ if(segment->steps != &segment->stack_step) {
+#ifdef __KERNEL_CPU__
+ /* NOTE: We only allow free last allocated segment.
+ * No random order of alloc/free is supported.
+ */
+ assert(kg->decoupled_volume_steps_index > 0);
+ assert(segment->steps == kg->decoupled_volume_steps[kg->decoupled_volume_steps_index - 1]);
+ --kg->decoupled_volume_steps_index;
+#else
free(segment->steps);
+#endif
+ }
}
/* scattering for homogeneous and heterogeneous volumes, using decoupled ray
@@ -1184,7 +1225,9 @@ ccl_device bool kernel_volume_use_decoupled(KernelGlobals *kg, bool heterogeneou
* is inside of. */
ccl_device void kernel_volume_stack_init(KernelGlobals *kg,
- Ray *ray,
+ ShaderData *stack_sd,
+ const PathState *state,
+ const Ray *ray,
VolumeStack *stack)
{
/* NULL ray happens in the baker, does it need proper initialization of
@@ -1205,14 +1248,16 @@ ccl_device void kernel_volume_stack_init(KernelGlobals *kg,
return;
}
+ kernel_assert(state->flag & PATH_RAY_CAMERA);
+
Ray volume_ray = *ray;
volume_ray.t = FLT_MAX;
+ const uint visibility = (state->flag & PATH_RAY_ALL_VISIBILITY);
int stack_index = 0, enclosed_index = 0;
- const uint visibility = PATH_RAY_ALL_VISIBILITY | kernel_data.integrator.layer_flag;
#ifdef __VOLUME_RECORD_ALL__
- Intersection hits[2*VOLUME_STACK_SIZE];
+ Intersection hits[2*VOLUME_STACK_SIZE + 1];
uint num_hits = scene_intersect_volume_all(kg,
&volume_ray,
hits,
@@ -1225,28 +1270,27 @@ ccl_device void kernel_volume_stack_init(KernelGlobals *kg,
qsort(hits, num_hits, sizeof(Intersection), intersections_compare);
for(uint hit = 0; hit < num_hits; ++hit, ++isect) {
- ShaderData sd;
- shader_setup_from_ray(kg, &sd, isect, &volume_ray);
- if(sd.flag & SD_BACKFACING) {
+ shader_setup_from_ray(kg, stack_sd, isect, &volume_ray);
+ if(stack_sd->flag & SD_BACKFACING) {
bool need_add = true;
for(int i = 0; i < enclosed_index && need_add; ++i) {
/* If ray exited the volume and never entered to that volume
* it means that camera is inside such a volume.
*/
- if(enclosed_volumes[i] == sd.object) {
+ if(enclosed_volumes[i] == stack_sd->object) {
need_add = false;
}
}
for(int i = 0; i < stack_index && need_add; ++i) {
/* Don't add intersections twice. */
- if(stack[i].object == sd.object) {
+ if(stack[i].object == stack_sd->object) {
need_add = false;
break;
}
}
if(need_add) {
- stack[stack_index].object = sd.object;
- stack[stack_index].shader = sd.shader;
+ stack[stack_index].object = stack_sd->object;
+ stack[stack_index].shader = stack_sd->shader;
++stack_index;
}
}
@@ -1254,7 +1298,7 @@ ccl_device void kernel_volume_stack_init(KernelGlobals *kg,
/* If ray from camera enters the volume, this volume shouldn't
* be added to the stack on exit.
*/
- enclosed_volumes[enclosed_index++] = sd.object;
+ enclosed_volumes[enclosed_index++] = stack_sd->object;
}
}
}
@@ -1271,9 +1315,8 @@ ccl_device void kernel_volume_stack_init(KernelGlobals *kg,
break;
}
- ShaderData sd;
- shader_setup_from_ray(kg, &sd, &isect, &volume_ray);
- if(sd.flag & SD_BACKFACING) {
+ shader_setup_from_ray(kg, stack_sd, &isect, &volume_ray);
+ if(stack_sd->flag & SD_BACKFACING) {
/* If ray exited the volume and never entered to that volume
* it means that camera is inside such a volume.
*/
@@ -1282,20 +1325,20 @@ ccl_device void kernel_volume_stack_init(KernelGlobals *kg,
/* If ray exited the volume and never entered to that volume
* it means that camera is inside such a volume.
*/
- if(enclosed_volumes[i] == sd.object) {
+ if(enclosed_volumes[i] == stack_sd->object) {
need_add = false;
}
}
for(int i = 0; i < stack_index && need_add; ++i) {
/* Don't add intersections twice. */
- if(stack[i].object == sd.object) {
+ if(stack[i].object == stack_sd->object) {
need_add = false;
break;
}
}
if(need_add) {
- stack[stack_index].object = sd.object;
- stack[stack_index].shader = sd.shader;
+ stack[stack_index].object = stack_sd->object;
+ stack[stack_index].shader = stack_sd->shader;
++stack_index;
}
}
@@ -1303,11 +1346,11 @@ ccl_device void kernel_volume_stack_init(KernelGlobals *kg,
/* If ray from camera enters the volume, this volume shouldn't
* be added to the stack on exit.
*/
- enclosed_volumes[enclosed_index++] = sd.object;
+ enclosed_volumes[enclosed_index++] = stack_sd->object;
}
/* Move ray forward. */
- volume_ray.P = ray_offset(sd.P, -sd.Ng);
+ volume_ray.P = ray_offset(stack_sd->P, -stack_sd->Ng);
++step;
}
#endif
@@ -1375,6 +1418,7 @@ ccl_device void kernel_volume_stack_enter_exit(KernelGlobals *kg, ShaderData *sd
#ifdef __SUBSURFACE__
ccl_device void kernel_volume_stack_update_for_subsurface(KernelGlobals *kg,
+ ShaderData *stack_sd,
Ray *ray,
VolumeStack *stack)
{
@@ -1383,7 +1427,7 @@ ccl_device void kernel_volume_stack_update_for_subsurface(KernelGlobals *kg,
Ray volume_ray = *ray;
# ifdef __VOLUME_RECORD_ALL__
- Intersection hits[2*VOLUME_STACK_SIZE];
+ Intersection hits[2*VOLUME_STACK_SIZE + 1];
uint num_hits = scene_intersect_volume_all(kg,
&volume_ray,
hits,
@@ -1395,27 +1439,28 @@ ccl_device void kernel_volume_stack_update_for_subsurface(KernelGlobals *kg,
qsort(hits, num_hits, sizeof(Intersection), intersections_compare);
for(uint hit = 0; hit < num_hits; ++hit, ++isect) {
- ShaderData sd;
- shader_setup_from_ray(kg, &sd, isect, &volume_ray);
- kernel_volume_stack_enter_exit(kg, &sd, stack);
+ shader_setup_from_ray(kg, stack_sd, isect, &volume_ray);
+ kernel_volume_stack_enter_exit(kg, stack_sd, stack);
}
}
# else
Intersection isect;
int step = 0;
+ float3 Pend = ray->P + ray->D*ray->t;
while(step < 2 * VOLUME_STACK_SIZE &&
scene_intersect_volume(kg,
&volume_ray,
&isect,
PATH_RAY_ALL_VISIBILITY))
{
- ShaderData sd;
- shader_setup_from_ray(kg, &sd, &isect, &volume_ray);
- kernel_volume_stack_enter_exit(kg, &sd, stack);
+ shader_setup_from_ray(kg, stack_sd, &isect, &volume_ray);
+ kernel_volume_stack_enter_exit(kg, stack_sd, stack);
/* Move ray forward. */
- volume_ray.P = ray_offset(sd.P, -sd.Ng);
- volume_ray.t -= sd.ray_length;
+ volume_ray.P = ray_offset(stack_sd->P, -stack_sd->Ng);
+ if(volume_ray.t != FLT_MAX) {
+ volume_ray.D = normalize_len(Pend - volume_ray.P, &volume_ray.t);
+ }
++step;
}
# endif
diff --git a/intern/cycles/kernel/kernels/cpu/kernel.cpp b/intern/cycles/kernel/kernels/cpu/kernel.cpp
index 415c3a35009..b530e980fe6 100644
--- a/intern/cycles/kernel/kernels/cpu/kernel.cpp
+++ b/intern/cycles/kernel/kernels/cpu/kernel.cpp
@@ -42,9 +42,11 @@
# define __KERNEL_SSE41__
# endif
# ifdef __AVX__
+# define __KERNEL_SSE__
# define __KERNEL_AVX__
# endif
# ifdef __AVX2__
+# define __KERNEL_SSE__
# define __KERNEL_AVX2__
# endif
#endif
@@ -99,7 +101,7 @@ void kernel_tex_copy(KernelGlobals *kg,
int id = atoi(name + strlen("__tex_image_float4_"));
int array_index = id;
- if(array_index >= 0 && array_index < TEX_NUM_FLOAT4_IMAGES_CPU) {
+ if(array_index >= 0 && array_index < TEX_NUM_FLOAT4_CPU) {
tex = &kg->texture_float4_images[array_index];
}
@@ -110,12 +112,28 @@ void kernel_tex_copy(KernelGlobals *kg,
tex->extension = extension;
}
}
+ else if(strstr(name, "__tex_image_float")) {
+ texture_image_float *tex = NULL;
+ int id = atoi(name + strlen("__tex_image_float_"));
+ int array_index = id - TEX_START_FLOAT_CPU;
+
+ if(array_index >= 0 && array_index < TEX_NUM_FLOAT_CPU) {
+ tex = &kg->texture_float_images[array_index];
+ }
+
+ if(tex) {
+ tex->data = (float*)mem;
+ tex->dimensions_set(width, height, depth);
+ tex->interpolation = interpolation;
+ tex->extension = extension;
+ }
+ }
else if(strstr(name, "__tex_image_byte4")) {
texture_image_uchar4 *tex = NULL;
int id = atoi(name + strlen("__tex_image_byte4_"));
- int array_index = id - TEX_NUM_FLOAT4_IMAGES_CPU;
+ int array_index = id - TEX_START_BYTE4_CPU;
- if(array_index >= 0 && array_index < TEX_NUM_BYTE4_IMAGES_CPU) {
+ if(array_index >= 0 && array_index < TEX_NUM_BYTE4_CPU) {
tex = &kg->texture_byte4_images[array_index];
}
@@ -126,6 +144,54 @@ void kernel_tex_copy(KernelGlobals *kg,
tex->extension = extension;
}
}
+ else if(strstr(name, "__tex_image_byte")) {
+ texture_image_uchar *tex = NULL;
+ int id = atoi(name + strlen("__tex_image_byte_"));
+ int array_index = id - TEX_START_BYTE_CPU;
+
+ if(array_index >= 0 && array_index < TEX_NUM_BYTE_CPU) {
+ tex = &kg->texture_byte_images[array_index];
+ }
+
+ if(tex) {
+ tex->data = (uchar*)mem;
+ tex->dimensions_set(width, height, depth);
+ tex->interpolation = interpolation;
+ tex->extension = extension;
+ }
+ }
+ else if(strstr(name, "__tex_image_half4")) {
+ texture_image_half4 *tex = NULL;
+ int id = atoi(name + strlen("__tex_image_half4_"));
+ int array_index = id - TEX_START_HALF4_CPU;
+
+ if(array_index >= 0 && array_index < TEX_NUM_HALF4_CPU) {
+ tex = &kg->texture_half4_images[array_index];
+ }
+
+ if(tex) {
+ tex->data = (half4*)mem;
+ tex->dimensions_set(width, height, depth);
+ tex->interpolation = interpolation;
+ tex->extension = extension;
+ }
+ }
+ else if(strstr(name, "__tex_image_half")) {
+ texture_image_half *tex = NULL;
+ int id = atoi(name + strlen("__tex_image_half_"));
+ int array_index = id - TEX_START_HALF_CPU;
+
+ if(array_index >= 0 && array_index < TEX_NUM_HALF_CPU) {
+ tex = &kg->texture_half_images[array_index];
+ }
+
+ if(tex) {
+ tex->data = (half*)mem;
+ tex->dimensions_set(width, height, depth);
+ tex->interpolation = interpolation;
+ tex->extension = extension;
+ }
+ }
else
assert(0);
}
diff --git a/intern/cycles/kernel/kernels/cpu/kernel_avx.cpp b/intern/cycles/kernel/kernels/cpu/kernel_avx.cpp
index 533ab46b741..1350d9e5c2e 100644
--- a/intern/cycles/kernel/kernels/cpu/kernel_avx.cpp
+++ b/intern/cycles/kernel/kernels/cpu/kernel_avx.cpp
@@ -20,6 +20,7 @@
/* SSE optimization disabled for now on 32 bit, see bug #36316 */
#if !(defined(__GNUC__) && (defined(i386) || defined(_M_IX86)))
+# define __KERNEL_SSE__
# define __KERNEL_SSE2__
# define __KERNEL_SSE3__
# define __KERNEL_SSSE3__
diff --git a/intern/cycles/kernel/kernels/cpu/kernel_avx2.cpp b/intern/cycles/kernel/kernels/cpu/kernel_avx2.cpp
index 7351e2bad6b..1a416e771ee 100644
--- a/intern/cycles/kernel/kernels/cpu/kernel_avx2.cpp
+++ b/intern/cycles/kernel/kernels/cpu/kernel_avx2.cpp
@@ -20,6 +20,7 @@
/* SSE optimization disabled for now on 32 bit, see bug #36316 */
#if !(defined(__GNUC__) && (defined(i386) || defined(_M_IX86)))
+# define __KERNEL_SSE__
# define __KERNEL_SSE2__
# define __KERNEL_SSE3__
# define __KERNEL_SSSE3__
diff --git a/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h b/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h
new file mode 100644
index 00000000000..af68907a5c2
--- /dev/null
+++ b/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __KERNEL_CPU_IMAGE_H__
+#define __KERNEL_CPU_IMAGE_H__
+
+#ifdef __KERNEL_CPU__
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device float4 kernel_tex_image_interp_impl(KernelGlobals *kg, int tex, float x, float y)
+{
+ if(tex >= TEX_START_HALF_CPU)
+ return kg->texture_half_images[tex - TEX_START_HALF_CPU].interp(x, y);
+ else if(tex >= TEX_START_BYTE_CPU)
+ return kg->texture_byte_images[tex - TEX_START_BYTE_CPU].interp(x, y);
+ else if(tex >= TEX_START_FLOAT_CPU)
+ return kg->texture_float_images[tex - TEX_START_FLOAT_CPU].interp(x, y);
+ else if(tex >= TEX_START_HALF4_CPU)
+ return kg->texture_half4_images[tex - TEX_START_HALF4_CPU].interp(x, y);
+ else if(tex >= TEX_START_BYTE4_CPU)
+ return kg->texture_byte4_images[tex - TEX_START_BYTE4_CPU].interp(x, y);
+ else
+ return kg->texture_float4_images[tex].interp(x, y);
+}
+
+ccl_device float4 kernel_tex_image_interp_3d_impl(KernelGlobals *kg, int tex, float x, float y, float z)
+{
+ if(tex >= TEX_START_HALF_CPU)
+ return kg->texture_half_images[tex - TEX_START_HALF_CPU].interp_3d(x, y, z);
+ else if(tex >= TEX_START_BYTE_CPU)
+ return kg->texture_byte_images[tex - TEX_START_BYTE_CPU].interp_3d(x, y, z);
+ else if(tex >= TEX_START_FLOAT_CPU)
+ return kg->texture_float_images[tex - TEX_START_FLOAT_CPU].interp_3d(x, y, z);
+ else if(tex >= TEX_START_HALF4_CPU)
+ return kg->texture_half4_images[tex - TEX_START_HALF4_CPU].interp_3d(x, y, z);
+ else if(tex >= TEX_START_BYTE4_CPU)
+ return kg->texture_byte4_images[tex - TEX_START_BYTE4_CPU].interp_3d(x, y, z);
+ else
+ return kg->texture_float4_images[tex].interp_3d(x, y, z);
+
+}
+
+ccl_device float4 kernel_tex_image_interp_3d_ex_impl(KernelGlobals *kg, int tex, float x, float y, float z, int interpolation)
+{
+ if(tex >= TEX_START_HALF_CPU)
+ return kg->texture_half_images[tex - TEX_START_HALF_CPU].interp_3d_ex(x, y, z, interpolation);
+ else if(tex >= TEX_START_BYTE_CPU)
+ return kg->texture_byte_images[tex - TEX_START_BYTE_CPU].interp_3d_ex(x, y, z, interpolation);
+ else if(tex >= TEX_START_FLOAT_CPU)
+ return kg->texture_float_images[tex - TEX_START_FLOAT_CPU].interp_3d_ex(x, y, z, interpolation);
+ else if(tex >= TEX_START_HALF4_CPU)
+ return kg->texture_half4_images[tex - TEX_START_HALF4_CPU].interp_3d_ex(x, y, z, interpolation);
+ else if(tex >= TEX_START_BYTE4_CPU)
+ return kg->texture_byte4_images[tex - TEX_START_BYTE4_CPU].interp_3d_ex(x, y, z, interpolation);
+ else
+ return kg->texture_float4_images[tex].interp_3d_ex(x, y, z, interpolation);
+}
+
+CCL_NAMESPACE_END
+
+#endif // __KERNEL_CPU__
+
+
+#endif // __KERNEL_CPU_IMAGE_H__
diff --git a/intern/cycles/kernel/kernels/cpu/kernel_cpu_impl.h b/intern/cycles/kernel/kernels/cpu/kernel_cpu_impl.h
index 1454f925ab9..ec82d4b4c22 100644
--- a/intern/cycles/kernel/kernels/cpu/kernel_cpu_impl.h
+++ b/intern/cycles/kernel/kernels/cpu/kernel_cpu_impl.h
@@ -24,6 +24,7 @@
#include "kernel_math.h"
#include "kernel_types.h"
#include "kernel_globals.h"
+#include "kernel_cpu_image.h"
#include "kernel_film.h"
#include "kernel_path.h"
#include "kernel_path_branched.h"
@@ -108,6 +109,7 @@ void KERNEL_FUNCTION_FULL_NAME(shader)(KernelGlobals *kg,
{
if(type >= SHADER_EVAL_BAKE) {
kernel_assert(output_luma == NULL);
+#ifdef __BAKING__
kernel_bake_evaluate(kg,
input,
output,
@@ -116,6 +118,7 @@ void KERNEL_FUNCTION_FULL_NAME(shader)(KernelGlobals *kg,
i,
offset,
sample);
+#endif
}
else {
kernel_shader_evaluate(kg,
diff --git a/intern/cycles/kernel/kernels/cuda/kernel.cu b/intern/cycles/kernel/kernels/cuda/kernel.cu
index 37fae54faf0..eb2b6ea5414 100644
--- a/intern/cycles/kernel/kernels/cuda/kernel.cu
+++ b/intern/cycles/kernel/kernels/cuda/kernel.cu
@@ -77,8 +77,8 @@
# define CUDA_KERNEL_MAX_REGISTERS 63
# define CUDA_KERNEL_BRANCHED_MAX_REGISTERS 63
-/* 5.0, 5.2 and 5.3 */
-#elif __CUDA_ARCH__ == 500 || __CUDA_ARCH__ == 520 || __CUDA_ARCH__ == 530
+/* 5.0, 5.2, 5.3, 6.0, 6.1 */
+#elif __CUDA_ARCH__ >= 500
# define CUDA_MULTIPRESSOR_MAX_REGISTERS 65536
# define CUDA_MULTIPROCESSOR_MAX_BLOCKS 32
# define CUDA_BLOCK_MAX_THREADS 1024
@@ -86,7 +86,7 @@
/* tunable parameters */
# define CUDA_THREADS_BLOCK_WIDTH 16
-# define CUDA_KERNEL_MAX_REGISTERS 40
+# define CUDA_KERNEL_MAX_REGISTERS 48
# define CUDA_KERNEL_BRANCHED_MAX_REGISTERS 63
/* unknown architecture */
diff --git a/intern/cycles/kernel/kernels/opencl/kernel.cl b/intern/cycles/kernel/kernels/opencl/kernel.cl
index aad06ed5c76..a68f97857b6 100644
--- a/intern/cycles/kernel/kernels/opencl/kernel.cl
+++ b/intern/cycles/kernel/kernels/opencl/kernel.cl
@@ -20,6 +20,7 @@
#include "../../kernel_math.h"
#include "../../kernel_types.h"
#include "../../kernel_globals.h"
+#include "../../kernel_image_opencl.h"
#include "../../kernel_film.h"
@@ -35,6 +36,7 @@
# include "../../kernel_montecarlo.h"
# include "../../kernel_projection.h"
# include "../../geom/geom.h"
+# include "../../bvh/bvh.h"
# include "../../kernel_accumulate.h"
# include "../../kernel_camera.h"
diff --git a/intern/cycles/kernel/osl/CMakeLists.txt b/intern/cycles/kernel/osl/CMakeLists.txt
index b10ec588757..98de40e5a8a 100644
--- a/intern/cycles/kernel/osl/CMakeLists.txt
+++ b/intern/cycles/kernel/osl/CMakeLists.txt
@@ -3,6 +3,7 @@ set(INC
.
..
../svm
+ ../../graph
../../render
../../util
../../device
@@ -24,7 +25,6 @@ set(SRC
)
set(HEADER_SRC
- osl_bssrdf.h
osl_closures.h
osl_globals.h
osl_services.h
diff --git a/intern/cycles/kernel/osl/background.cpp b/intern/cycles/kernel/osl/background.cpp
index 85fa7b34bcc..d835f9be45c 100644
--- a/intern/cycles/kernel/osl/background.cpp
+++ b/intern/cycles/kernel/osl/background.cpp
@@ -36,6 +36,9 @@
#include "osl_closures.h"
+#include "kernel_compat_cpu.h"
+#include "closure/alloc.h"
+
CCL_NAMESPACE_BEGIN
using namespace OSL;
@@ -48,7 +51,10 @@ using namespace OSL;
///
class GenericBackgroundClosure : public CClosurePrimitive {
public:
- GenericBackgroundClosure() : CClosurePrimitive(Background) {}
+ void setup(ShaderData *sd, int /* path_flag */, float3 weight)
+ {
+ closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_BACKGROUND_ID, weight);
+ }
};
/// Holdout closure
@@ -60,7 +66,11 @@ public:
///
class HoldoutClosure : CClosurePrimitive {
public:
- HoldoutClosure () : CClosurePrimitive(Holdout) {}
+ void setup(ShaderData *sd, int /* path_flag */, float3 weight)
+ {
+ closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_HOLDOUT_ID, weight);
+ sd->flag |= SD_HOLDOUT;
+ }
};
/// ambient occlusion closure
@@ -71,7 +81,11 @@ public:
///
class AmbientOcclusionClosure : public CClosurePrimitive {
public:
- AmbientOcclusionClosure () : CClosurePrimitive(AmbientOcclusion) {}
+ void setup(ShaderData *sd, int /* path_flag */, float3 weight)
+ {
+ closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_AMBIENT_OCCLUSION_ID, weight);
+ sd->flag |= SD_AO;
+ }
};
ClosureParam *closure_background_params()
diff --git a/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp b/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp
index b5c0d76cf37..bc26f42b559 100644
--- a/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp
+++ b/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp
@@ -39,6 +39,7 @@
#include "kernel_types.h"
#include "kernel_montecarlo.h"
+#include "closure/alloc.h"
#include "closure/bsdf_diffuse_ramp.h"
CCL_NAMESPACE_BEGIN
@@ -47,51 +48,30 @@ using namespace OSL;
class DiffuseRampClosure : public CBSDFClosure {
public:
+ DiffuseRampBsdf params;
Color3 colors[8];
- float3 fcolors[8];
- DiffuseRampClosure() : CBSDFClosure(LABEL_DIFFUSE)
- {}
-
- void setup()
+ void setup(ShaderData *sd, int /* path_flag */, float3 weight)
{
- sc.prim = this;
- m_shaderdata_flag = bsdf_diffuse_ramp_setup(&sc);
+ DiffuseRampBsdf *bsdf = (DiffuseRampBsdf*)bsdf_alloc_osl(sd, sizeof(DiffuseRampBsdf), weight, &params);
- for(int i = 0; i < 8; i++)
- fcolors[i] = TO_FLOAT3(colors[i]);
- }
+ if(bsdf) {
+ bsdf->colors = (float3*)closure_alloc_extra(sd, sizeof(float3)*8);
- void blur(float roughness)
- {
- bsdf_diffuse_ramp_blur(&sc, roughness);
- }
+ if(bsdf->colors) {
+ for(int i = 0; i < 8; i++)
+ bsdf->colors[i] = TO_FLOAT3(colors[i]);
- float3 eval_reflect(const float3 &omega_out, const float3 &omega_in, float& pdf) const
- {
- return bsdf_diffuse_ramp_eval_reflect(&sc, fcolors, omega_out, omega_in, &pdf);
- }
-
- float3 eval_transmit(const float3 &omega_out, const float3 &omega_in, float& pdf) const
- {
- return bsdf_diffuse_ramp_eval_transmit(&sc, fcolors, omega_out, omega_in, &pdf);
- }
-
- int sample(const float3 &Ng,
- const float3 &omega_out, const float3 &domega_out_dx, const float3 &domega_out_dy,
- float randu, float randv,
- float3 &omega_in, float3 &domega_in_dx, float3 &domega_in_dy,
- float &pdf, float3 &eval) const
- {
- return bsdf_diffuse_ramp_sample(&sc, fcolors, Ng, omega_out, domega_out_dx, domega_out_dy,
- randu, randv, &eval, &omega_in, &domega_in_dx, &domega_in_dy, &pdf);
+ sd->flag |= bsdf_diffuse_ramp_setup(bsdf);
+ }
+ }
}
};
ClosureParam *closure_bsdf_diffuse_ramp_params()
{
static ClosureParam params[] = {
- CLOSURE_FLOAT3_PARAM(DiffuseRampClosure, sc.N),
+ CLOSURE_FLOAT3_PARAM(DiffuseRampClosure, params.N),
CLOSURE_COLOR_ARRAY_PARAM(DiffuseRampClosure, colors, 8),
CLOSURE_STRING_KEYPARAM(DiffuseRampClosure, label, "label"),
CLOSURE_FINISH_PARAM(DiffuseRampClosure)
diff --git a/intern/cycles/kernel/osl/bsdf_phong_ramp.cpp b/intern/cycles/kernel/osl/bsdf_phong_ramp.cpp
index bc73d80cd78..14c7644936e 100644
--- a/intern/cycles/kernel/osl/bsdf_phong_ramp.cpp
+++ b/intern/cycles/kernel/osl/bsdf_phong_ramp.cpp
@@ -38,6 +38,7 @@
#include "osl_closures.h"
#include "kernel_types.h"
+#include "closure/alloc.h"
#include "closure/bsdf_phong_ramp.h"
CCL_NAMESPACE_BEGIN
@@ -46,52 +47,31 @@ using namespace OSL;
class PhongRampClosure : public CBSDFClosure {
public:
+ PhongRampBsdf params;
Color3 colors[8];
- float3 fcolors[8];
- PhongRampClosure() : CBSDFClosure(LABEL_GLOSSY)
- {}
-
- void setup()
+ void setup(ShaderData *sd, int /* path_flag */, float3 weight)
{
- sc.prim = this;
- m_shaderdata_flag = bsdf_phong_ramp_setup(&sc);
+ PhongRampBsdf *bsdf = (PhongRampBsdf*)bsdf_alloc_osl(sd, sizeof(PhongRampBsdf), weight, &params);
- for(int i = 0; i < 8; i++)
- fcolors[i] = TO_FLOAT3(colors[i]);
- }
+ if(bsdf) {
+ bsdf->colors = (float3*)closure_alloc_extra(sd, sizeof(float3)*8);
- void blur(float roughness)
- {
- bsdf_phong_ramp_blur(&sc, roughness);
- }
+ if(bsdf->colors) {
+ for(int i = 0; i < 8; i++)
+ bsdf->colors[i] = TO_FLOAT3(colors[i]);
- float3 eval_reflect(const float3 &omega_out, const float3 &omega_in, float& pdf) const
- {
- return bsdf_phong_ramp_eval_reflect(&sc, fcolors, omega_out, omega_in, &pdf);
- }
-
- float3 eval_transmit(const float3 &omega_out, const float3 &omega_in, float& pdf) const
- {
- return bsdf_phong_ramp_eval_transmit(&sc, fcolors, omega_out, omega_in, &pdf);
- }
-
- int sample(const float3 &Ng,
- const float3 &omega_out, const float3 &domega_out_dx, const float3 &domega_out_dy,
- float randu, float randv,
- float3 &omega_in, float3 &domega_in_dx, float3 &domega_in_dy,
- float &pdf, float3 &eval) const
- {
- return bsdf_phong_ramp_sample(&sc, fcolors, Ng, omega_out, domega_out_dx, domega_out_dy,
- randu, randv, &eval, &omega_in, &domega_in_dx, &domega_in_dy, &pdf);
+ sd->flag |= bsdf_phong_ramp_setup(bsdf);
+ }
+ }
}
};
ClosureParam *closure_bsdf_phong_ramp_params()
{
static ClosureParam params[] = {
- CLOSURE_FLOAT3_PARAM(PhongRampClosure, sc.N),
- CLOSURE_FLOAT_PARAM(PhongRampClosure, sc.data0),
+ CLOSURE_FLOAT3_PARAM(PhongRampClosure, params.N),
+ CLOSURE_FLOAT_PARAM(PhongRampClosure, params.exponent),
CLOSURE_COLOR_ARRAY_PARAM(PhongRampClosure, colors, 8),
CLOSURE_STRING_KEYPARAM(PhongRampClosure, label, "label"),
CLOSURE_FINISH_PARAM(PhongRampClosure)
diff --git a/intern/cycles/kernel/osl/emissive.cpp b/intern/cycles/kernel/osl/emissive.cpp
index f91fd6e015c..3f13e08b302 100644
--- a/intern/cycles/kernel/osl/emissive.cpp
+++ b/intern/cycles/kernel/osl/emissive.cpp
@@ -36,7 +36,9 @@
#include "osl_closures.h"
+#include "kernel_compat_cpu.h"
#include "kernel_types.h"
+#include "closure/alloc.h"
#include "closure/emissive.h"
CCL_NAMESPACE_BEGIN
@@ -52,25 +54,10 @@ using namespace OSL;
///
class GenericEmissiveClosure : public CClosurePrimitive {
public:
- GenericEmissiveClosure() : CClosurePrimitive(Emissive) { }
-
- Color3 eval(const Vec3 &Ng, const Vec3 &omega_out) const
- {
- float3 result = emissive_simple_eval(TO_FLOAT3(Ng), TO_FLOAT3(omega_out));
- return TO_COLOR3(result);
- }
-
- void sample(const Vec3 &Ng, float randu, float randv,
- Vec3 &omega_out, float &pdf) const
- {
- float3 omega_out_;
- emissive_sample(TO_FLOAT3(Ng), randu, randv, &omega_out_, &pdf);
- omega_out = TO_VEC3(omega_out_);
- }
-
- float pdf(const Vec3 &Ng, const Vec3 &omega_out) const
+ void setup(ShaderData *sd, int /* path_flag */, float3 weight)
{
- return emissive_pdf(TO_FLOAT3(Ng), TO_FLOAT3(omega_out));
+ closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_EMISSION_ID, weight);
+ sd->flag |= SD_EMISSION;
}
};
diff --git a/intern/cycles/kernel/osl/osl_bssrdf.cpp b/intern/cycles/kernel/osl/osl_bssrdf.cpp
index da4afb138f6..3614717e28c 100644
--- a/intern/cycles/kernel/osl/osl_bssrdf.cpp
+++ b/intern/cycles/kernel/osl/osl_bssrdf.cpp
@@ -30,17 +30,15 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <OpenImageIO/fmath.h>
-
#include <OSL/genclosure.h>
#include "kernel_compat_cpu.h"
-#include "osl_bssrdf.h"
#include "osl_closures.h"
#include "kernel_types.h"
#include "kernel_montecarlo.h"
+#include "closure/alloc.h"
#include "closure/bsdf_diffuse.h"
#include "closure/bssrdf.h"
@@ -48,27 +46,83 @@ CCL_NAMESPACE_BEGIN
using namespace OSL;
+class CBSSRDFClosure : public CClosurePrimitive {
+public:
+ Bssrdf params;
+ float3 radius;
+ float3 albedo;
+
+ void alloc(ShaderData *sd, int path_flag, float3 weight, ClosureType type)
+ {
+ float sample_weight = fabsf(average(weight));
+
+ /* disable in case of diffuse ancestor, can't see it well then and
+ * adds considerably noise due to probabilities of continuing path
+ * getting lower and lower */
+ if(path_flag & PATH_RAY_DIFFUSE_ANCESTOR) {
+ radius = make_float3(0.0f, 0.0f, 0.0f);
+ }
+
+ if(sample_weight > CLOSURE_WEIGHT_CUTOFF) {
+ /* sharpness */
+ float sharpness = params.sharpness;
+ /* texture color blur */
+ float texture_blur = params.texture_blur;
+
+ /* create one closure per color channel */
+ Bssrdf *bssrdf = bssrdf_alloc(sd, make_float3(weight.x, 0.0f, 0.0f));
+ if(bssrdf) {
+ bssrdf->sample_weight = sample_weight;
+ bssrdf->radius = radius.x;
+ bssrdf->texture_blur = texture_blur;
+ bssrdf->albedo = albedo.x;
+ bssrdf->sharpness = sharpness;
+ bssrdf->N = params.N;
+ ccl_fetch(sd, flag) |= bssrdf_setup(bssrdf, (ClosureType)type);
+ }
+
+ bssrdf = bssrdf_alloc(sd, make_float3(0.0f, weight.y, 0.0f));
+ if(bssrdf) {
+ bssrdf->sample_weight = sample_weight;
+ bssrdf->radius = radius.y;
+ bssrdf->texture_blur = texture_blur;
+ bssrdf->albedo = albedo.y;
+ bssrdf->sharpness = sharpness;
+ bssrdf->N = params.N;
+ ccl_fetch(sd, flag) |= bssrdf_setup(bssrdf, (ClosureType)type);
+ }
+
+ bssrdf = bssrdf_alloc(sd, make_float3(0.0f, 0.0f, weight.z));
+ if(bssrdf) {
+ bssrdf->sample_weight = sample_weight;
+ bssrdf->radius = radius.z;
+ bssrdf->texture_blur = texture_blur;
+ bssrdf->albedo = albedo.z;
+ bssrdf->sharpness = sharpness;
+ bssrdf->N = params.N;
+ ccl_fetch(sd, flag) |= bssrdf_setup(bssrdf, (ClosureType)type);
+ }
+ }
+ }
+};
+
/* Cubic */
class CubicBSSRDFClosure : public CBSSRDFClosure {
public:
- CubicBSSRDFClosure()
- {}
-
- void setup()
+ void setup(ShaderData *sd, int path_flag, float3 weight)
{
- sc.type = CLOSURE_BSSRDF_CUBIC_ID;
- sc.data0 = fabsf(average(radius));
+ alloc(sd, path_flag, weight, CLOSURE_BSSRDF_CUBIC_ID);
}
};
ClosureParam *closure_bssrdf_cubic_params()
{
static ClosureParam params[] = {
- CLOSURE_FLOAT3_PARAM(CubicBSSRDFClosure, sc.N),
+ CLOSURE_FLOAT3_PARAM(CubicBSSRDFClosure, params.N),
CLOSURE_FLOAT3_PARAM(CubicBSSRDFClosure, radius),
- CLOSURE_FLOAT_PARAM(CubicBSSRDFClosure, sc.data1),
- CLOSURE_FLOAT_PARAM(CubicBSSRDFClosure, sc.T.x),
+ CLOSURE_FLOAT_PARAM(CubicBSSRDFClosure, params.texture_blur),
+ CLOSURE_FLOAT_PARAM(CubicBSSRDFClosure, params.sharpness),
CLOSURE_STRING_KEYPARAM(CubicBSSRDFClosure, label, "label"),
CLOSURE_FINISH_PARAM(CubicBSSRDFClosure)
};
@@ -81,22 +135,18 @@ CCLOSURE_PREPARE(closure_bssrdf_cubic_prepare, CubicBSSRDFClosure)
class GaussianBSSRDFClosure : public CBSSRDFClosure {
public:
- GaussianBSSRDFClosure()
- {}
-
- void setup()
+ void setup(ShaderData *sd, int path_flag, float3 weight)
{
- sc.type = CLOSURE_BSSRDF_GAUSSIAN_ID;
- sc.data0 = fabsf(average(radius));
+ alloc(sd, path_flag, weight, CLOSURE_BSSRDF_GAUSSIAN_ID);
}
};
ClosureParam *closure_bssrdf_gaussian_params()
{
static ClosureParam params[] = {
- CLOSURE_FLOAT3_PARAM(GaussianBSSRDFClosure, sc.N),
+ CLOSURE_FLOAT3_PARAM(GaussianBSSRDFClosure, params.N),
CLOSURE_FLOAT3_PARAM(GaussianBSSRDFClosure, radius),
- CLOSURE_FLOAT_PARAM(GaussianBSSRDFClosure, sc.data1),
+ CLOSURE_FLOAT_PARAM(GaussianBSSRDFClosure, params.texture_blur),
CLOSURE_STRING_KEYPARAM(GaussianBSSRDFClosure, label, "label"),
CLOSURE_FINISH_PARAM(GaussianBSSRDFClosure)
};
@@ -109,22 +159,18 @@ CCLOSURE_PREPARE(closure_bssrdf_gaussian_prepare, GaussianBSSRDFClosure)
class BurleyBSSRDFClosure : public CBSSRDFClosure {
public:
- BurleyBSSRDFClosure()
- {}
-
- void setup()
+ void setup(ShaderData *sd, int path_flag, float3 weight)
{
- sc.type = CLOSURE_BSSRDF_BURLEY_ID;
- sc.data0 = fabsf(average(radius));
+ alloc(sd, path_flag, weight, CLOSURE_BSSRDF_BURLEY_ID);
}
};
ClosureParam *closure_bssrdf_burley_params()
{
static ClosureParam params[] = {
- CLOSURE_FLOAT3_PARAM(BurleyBSSRDFClosure, sc.N),
+ CLOSURE_FLOAT3_PARAM(BurleyBSSRDFClosure, params.N),
CLOSURE_FLOAT3_PARAM(BurleyBSSRDFClosure, radius),
- CLOSURE_FLOAT_PARAM(BurleyBSSRDFClosure, sc.data1),
+ CLOSURE_FLOAT_PARAM(BurleyBSSRDFClosure, params.texture_blur),
CLOSURE_FLOAT3_PARAM(BurleyBSSRDFClosure, albedo),
CLOSURE_STRING_KEYPARAM(BurleyBSSRDFClosure, label, "label"),
CLOSURE_FINISH_PARAM(BurleyBSSRDFClosure)
diff --git a/intern/cycles/kernel/osl/osl_bssrdf.h b/intern/cycles/kernel/osl/osl_bssrdf.h
deleted file mode 100644
index d81ecade543..00000000000
--- a/intern/cycles/kernel/osl/osl_bssrdf.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Adapted from Open Shading Language with this license:
- *
- * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
- * All Rights Reserved.
- *
- * Modifications Copyright 2011, Blender Foundation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of Sony Pictures Imageworks nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef __OSL_BSSRDF_H__
-#define __OSL_BSSRDF_H__
-
-#include <OSL/oslclosure.h>
-#include <OSL/oslexec.h>
-#include <OSL/genclosure.h>
-
-#include "osl_closures.h"
-
-#include "kernel_types.h"
-
-#include "util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-class CBSSRDFClosure : public CClosurePrimitive {
-public:
- ShaderClosure sc;
- float3 radius;
- float3 albedo;
-
- CBSSRDFClosure() : CClosurePrimitive(BSSRDF) { }
- int scattering() const { return LABEL_DIFFUSE; }
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __OSL_BSSRDF_H__ */
-
diff --git a/intern/cycles/kernel/osl/osl_closures.cpp b/intern/cycles/kernel/osl/osl_closures.cpp
index 95b8cea0922..94de782dca0 100644
--- a/intern/cycles/kernel/osl/osl_closures.cpp
+++ b/intern/cycles/kernel/osl/osl_closures.cpp
@@ -44,11 +44,14 @@
#include "kernel_compat_cpu.h"
#include "kernel_globals.h"
#include "kernel_montecarlo.h"
+#include "kernel_random.h"
+#include "closure/alloc.h"
#include "closure/bsdf_util.h"
#include "closure/bsdf_ashikhmin_velvet.h"
#include "closure/bsdf_diffuse.h"
#include "closure/bsdf_microfacet.h"
+#include "closure/bsdf_microfacet_multi.h"
#include "closure/bsdf_oren_nayar.h"
#include "closure/bsdf_reflection.h"
#include "closure/bsdf_refraction.h"
@@ -64,112 +67,112 @@ using namespace OSL;
/* BSDF class definitions */
-BSDF_CLOSURE_CLASS_BEGIN(Diffuse, diffuse, diffuse, LABEL_DIFFUSE)
- CLOSURE_FLOAT3_PARAM(DiffuseClosure, sc.N),
+BSDF_CLOSURE_CLASS_BEGIN(Diffuse, diffuse, DiffuseBsdf, LABEL_DIFFUSE)
+ CLOSURE_FLOAT3_PARAM(DiffuseClosure, params.N),
BSDF_CLOSURE_CLASS_END(Diffuse, diffuse)
-BSDF_CLOSURE_CLASS_BEGIN(Translucent, translucent, translucent, LABEL_DIFFUSE)
- CLOSURE_FLOAT3_PARAM(TranslucentClosure, sc.N),
+BSDF_CLOSURE_CLASS_BEGIN(Translucent, translucent, DiffuseBsdf, LABEL_DIFFUSE)
+ CLOSURE_FLOAT3_PARAM(TranslucentClosure, params.N),
BSDF_CLOSURE_CLASS_END(Translucent, translucent)
-BSDF_CLOSURE_CLASS_BEGIN(OrenNayar, oren_nayar, oren_nayar, LABEL_DIFFUSE)
- CLOSURE_FLOAT3_PARAM(OrenNayarClosure, sc.N),
- CLOSURE_FLOAT_PARAM(OrenNayarClosure, sc.data0),
+BSDF_CLOSURE_CLASS_BEGIN(OrenNayar, oren_nayar, OrenNayarBsdf, LABEL_DIFFUSE)
+ CLOSURE_FLOAT3_PARAM(OrenNayarClosure, params.N),
+ CLOSURE_FLOAT_PARAM(OrenNayarClosure, params.roughness),
BSDF_CLOSURE_CLASS_END(OrenNayar, oren_nayar)
-BSDF_CLOSURE_CLASS_BEGIN(Reflection, reflection, reflection, LABEL_SINGULAR)
- CLOSURE_FLOAT3_PARAM(ReflectionClosure, sc.N),
+BSDF_CLOSURE_CLASS_BEGIN(Reflection, reflection, MicrofacetBsdf, LABEL_SINGULAR)
+ CLOSURE_FLOAT3_PARAM(ReflectionClosure, params.N),
BSDF_CLOSURE_CLASS_END(Reflection, reflection)
-BSDF_CLOSURE_CLASS_BEGIN(Refraction, refraction, refraction, LABEL_SINGULAR)
- CLOSURE_FLOAT3_PARAM(RefractionClosure, sc.N),
- CLOSURE_FLOAT_PARAM(RefractionClosure, sc.data0),
+BSDF_CLOSURE_CLASS_BEGIN(Refraction, refraction, MicrofacetBsdf, LABEL_SINGULAR)
+ CLOSURE_FLOAT3_PARAM(RefractionClosure, params.N),
+ CLOSURE_FLOAT_PARAM(RefractionClosure, params.ior),
BSDF_CLOSURE_CLASS_END(Refraction, refraction)
-BSDF_CLOSURE_CLASS_BEGIN(Transparent, transparent, transparent, LABEL_SINGULAR)
+BSDF_CLOSURE_CLASS_BEGIN(Transparent, transparent, ShaderClosure, LABEL_SINGULAR)
BSDF_CLOSURE_CLASS_END(Transparent, transparent)
-BSDF_CLOSURE_CLASS_BEGIN(AshikhminVelvet, ashikhmin_velvet, ashikhmin_velvet, LABEL_DIFFUSE)
- CLOSURE_FLOAT3_PARAM(AshikhminVelvetClosure, sc.N),
- CLOSURE_FLOAT_PARAM(AshikhminVelvetClosure, sc.data0),
+BSDF_CLOSURE_CLASS_BEGIN(AshikhminVelvet, ashikhmin_velvet, VelvetBsdf, LABEL_DIFFUSE)
+ CLOSURE_FLOAT3_PARAM(AshikhminVelvetClosure, params.N),
+ CLOSURE_FLOAT_PARAM(AshikhminVelvetClosure, params.sigma),
BSDF_CLOSURE_CLASS_END(AshikhminVelvet, ashikhmin_velvet)
-BSDF_CLOSURE_CLASS_BEGIN(AshikhminShirley, ashikhmin_shirley_aniso, ashikhmin_shirley, LABEL_GLOSSY|LABEL_REFLECT)
- CLOSURE_FLOAT3_PARAM(AshikhminShirleyClosure, sc.N),
- CLOSURE_FLOAT3_PARAM(AshikhminShirleyClosure, sc.T),
- CLOSURE_FLOAT_PARAM(AshikhminShirleyClosure, sc.data0),
- CLOSURE_FLOAT_PARAM(AshikhminShirleyClosure, sc.data1),
+BSDF_CLOSURE_CLASS_BEGIN(AshikhminShirley, ashikhmin_shirley_aniso, MicrofacetBsdf, LABEL_GLOSSY|LABEL_REFLECT)
+ CLOSURE_FLOAT3_PARAM(AshikhminShirleyClosure, params.N),
+ CLOSURE_FLOAT3_PARAM(AshikhminShirleyClosure, params.T),
+ CLOSURE_FLOAT_PARAM(AshikhminShirleyClosure, params.alpha_x),
+ CLOSURE_FLOAT_PARAM(AshikhminShirleyClosure, params.alpha_y),
BSDF_CLOSURE_CLASS_END(AshikhminShirley, ashikhmin_shirley_aniso)
-BSDF_CLOSURE_CLASS_BEGIN(DiffuseToon, diffuse_toon, diffuse_toon, LABEL_DIFFUSE)
- CLOSURE_FLOAT3_PARAM(DiffuseToonClosure, sc.N),
- CLOSURE_FLOAT_PARAM(DiffuseToonClosure, sc.data0),
- CLOSURE_FLOAT_PARAM(DiffuseToonClosure, sc.data1),
+BSDF_CLOSURE_CLASS_BEGIN(DiffuseToon, diffuse_toon, ToonBsdf, LABEL_DIFFUSE)
+ CLOSURE_FLOAT3_PARAM(DiffuseToonClosure, params.N),
+ CLOSURE_FLOAT_PARAM(DiffuseToonClosure, params.size),
+ CLOSURE_FLOAT_PARAM(DiffuseToonClosure, params.smooth),
BSDF_CLOSURE_CLASS_END(DiffuseToon, diffuse_toon)
-BSDF_CLOSURE_CLASS_BEGIN(GlossyToon, glossy_toon, glossy_toon, LABEL_GLOSSY)
- CLOSURE_FLOAT3_PARAM(GlossyToonClosure, sc.N),
- CLOSURE_FLOAT_PARAM(GlossyToonClosure, sc.data0),
- CLOSURE_FLOAT_PARAM(GlossyToonClosure, sc.data1),
+BSDF_CLOSURE_CLASS_BEGIN(GlossyToon, glossy_toon, ToonBsdf, LABEL_GLOSSY)
+ CLOSURE_FLOAT3_PARAM(GlossyToonClosure, params.N),
+ CLOSURE_FLOAT_PARAM(GlossyToonClosure, params.size),
+ CLOSURE_FLOAT_PARAM(GlossyToonClosure, params.smooth),
BSDF_CLOSURE_CLASS_END(GlossyToon, glossy_toon)
-BSDF_CLOSURE_CLASS_BEGIN(MicrofacetGGX, microfacet_ggx, microfacet_ggx, LABEL_GLOSSY|LABEL_REFLECT)
- CLOSURE_FLOAT3_PARAM(MicrofacetGGXClosure, sc.N),
- CLOSURE_FLOAT_PARAM(MicrofacetGGXClosure, sc.data0),
+BSDF_CLOSURE_CLASS_BEGIN(MicrofacetGGX, microfacet_ggx, MicrofacetBsdf, LABEL_GLOSSY|LABEL_REFLECT)
+ CLOSURE_FLOAT3_PARAM(MicrofacetGGXClosure, params.N),
+ CLOSURE_FLOAT_PARAM(MicrofacetGGXClosure, params.alpha_x),
BSDF_CLOSURE_CLASS_END(MicrofacetGGX, microfacet_ggx)
-BSDF_CLOSURE_CLASS_BEGIN(MicrofacetGGXAniso, microfacet_ggx_aniso, microfacet_ggx, LABEL_GLOSSY|LABEL_REFLECT)
- CLOSURE_FLOAT3_PARAM(MicrofacetGGXAnisoClosure, sc.N),
- CLOSURE_FLOAT3_PARAM(MicrofacetGGXAnisoClosure, sc.T),
- CLOSURE_FLOAT_PARAM(MicrofacetGGXAnisoClosure, sc.data0),
- CLOSURE_FLOAT_PARAM(MicrofacetGGXAnisoClosure, sc.data1),
+BSDF_CLOSURE_CLASS_BEGIN(MicrofacetGGXAniso, microfacet_ggx_aniso, MicrofacetBsdf, LABEL_GLOSSY|LABEL_REFLECT)
+ CLOSURE_FLOAT3_PARAM(MicrofacetGGXAnisoClosure, params.N),
+ CLOSURE_FLOAT3_PARAM(MicrofacetGGXAnisoClosure, params.T),
+ CLOSURE_FLOAT_PARAM(MicrofacetGGXAnisoClosure, params.alpha_x),
+ CLOSURE_FLOAT_PARAM(MicrofacetGGXAnisoClosure, params.alpha_y),
BSDF_CLOSURE_CLASS_END(MicrofacetGGXAniso, microfacet_ggx_aniso)
-BSDF_CLOSURE_CLASS_BEGIN(MicrofacetBeckmann, microfacet_beckmann, microfacet_beckmann, LABEL_GLOSSY|LABEL_REFLECT)
- CLOSURE_FLOAT3_PARAM(MicrofacetBeckmannClosure, sc.N),
- CLOSURE_FLOAT_PARAM(MicrofacetBeckmannClosure, sc.data0),
+BSDF_CLOSURE_CLASS_BEGIN(MicrofacetBeckmann, microfacet_beckmann, MicrofacetBsdf, LABEL_GLOSSY|LABEL_REFLECT)
+ CLOSURE_FLOAT3_PARAM(MicrofacetBeckmannClosure, params.N),
+ CLOSURE_FLOAT_PARAM(MicrofacetBeckmannClosure, params.alpha_x),
BSDF_CLOSURE_CLASS_END(MicrofacetBeckmann, microfacet_beckmann)
-BSDF_CLOSURE_CLASS_BEGIN(MicrofacetBeckmannAniso, microfacet_beckmann_aniso, microfacet_beckmann, LABEL_GLOSSY|LABEL_REFLECT)
- CLOSURE_FLOAT3_PARAM(MicrofacetBeckmannAnisoClosure, sc.N),
- CLOSURE_FLOAT3_PARAM(MicrofacetBeckmannAnisoClosure, sc.T),
- CLOSURE_FLOAT_PARAM(MicrofacetBeckmannAnisoClosure, sc.data0),
- CLOSURE_FLOAT_PARAM(MicrofacetBeckmannAnisoClosure, sc.data1),
+BSDF_CLOSURE_CLASS_BEGIN(MicrofacetBeckmannAniso, microfacet_beckmann_aniso, MicrofacetBsdf, LABEL_GLOSSY|LABEL_REFLECT)
+ CLOSURE_FLOAT3_PARAM(MicrofacetBeckmannAnisoClosure, params.N),
+ CLOSURE_FLOAT3_PARAM(MicrofacetBeckmannAnisoClosure, params.T),
+ CLOSURE_FLOAT_PARAM(MicrofacetBeckmannAnisoClosure, params.alpha_x),
+ CLOSURE_FLOAT_PARAM(MicrofacetBeckmannAnisoClosure, params.alpha_y),
BSDF_CLOSURE_CLASS_END(MicrofacetBeckmannAniso, microfacet_beckmann_aniso)
-BSDF_CLOSURE_CLASS_BEGIN(MicrofacetGGXRefraction, microfacet_ggx_refraction, microfacet_ggx, LABEL_GLOSSY|LABEL_TRANSMIT)
- CLOSURE_FLOAT3_PARAM(MicrofacetGGXRefractionClosure, sc.N),
- CLOSURE_FLOAT_PARAM(MicrofacetGGXRefractionClosure, sc.data0),
- CLOSURE_FLOAT_PARAM(MicrofacetGGXRefractionClosure, sc.data2),
+BSDF_CLOSURE_CLASS_BEGIN(MicrofacetGGXRefraction, microfacet_ggx_refraction, MicrofacetBsdf, LABEL_GLOSSY|LABEL_TRANSMIT)
+ CLOSURE_FLOAT3_PARAM(MicrofacetGGXRefractionClosure, params.N),
+ CLOSURE_FLOAT_PARAM(MicrofacetGGXRefractionClosure, params.alpha_x),
+ CLOSURE_FLOAT_PARAM(MicrofacetGGXRefractionClosure, params.ior),
BSDF_CLOSURE_CLASS_END(MicrofacetGGXRefraction, microfacet_ggx_refraction)
-BSDF_CLOSURE_CLASS_BEGIN(MicrofacetBeckmannRefraction, microfacet_beckmann_refraction, microfacet_beckmann, LABEL_GLOSSY|LABEL_TRANSMIT)
- CLOSURE_FLOAT3_PARAM(MicrofacetBeckmannRefractionClosure, sc.N),
- CLOSURE_FLOAT_PARAM(MicrofacetBeckmannRefractionClosure, sc.data0),
- CLOSURE_FLOAT_PARAM(MicrofacetBeckmannRefractionClosure, sc.data2),
+BSDF_CLOSURE_CLASS_BEGIN(MicrofacetBeckmannRefraction, microfacet_beckmann_refraction, MicrofacetBsdf, LABEL_GLOSSY|LABEL_TRANSMIT)
+ CLOSURE_FLOAT3_PARAM(MicrofacetBeckmannRefractionClosure, params.N),
+ CLOSURE_FLOAT_PARAM(MicrofacetBeckmannRefractionClosure, params.alpha_x),
+ CLOSURE_FLOAT_PARAM(MicrofacetBeckmannRefractionClosure, params.ior),
BSDF_CLOSURE_CLASS_END(MicrofacetBeckmannRefraction, microfacet_beckmann_refraction)
-BSDF_CLOSURE_CLASS_BEGIN(HairReflection, hair_reflection, hair_reflection, LABEL_GLOSSY)
- CLOSURE_FLOAT3_PARAM(HairReflectionClosure, sc.N),
- CLOSURE_FLOAT_PARAM(HairReflectionClosure, sc.data0),
- CLOSURE_FLOAT_PARAM(HairReflectionClosure, sc.data1),
- CLOSURE_FLOAT3_PARAM(HairReflectionClosure, sc.T),
- CLOSURE_FLOAT_PARAM(HairReflectionClosure, sc.data2),
+BSDF_CLOSURE_CLASS_BEGIN(HairReflection, hair_reflection, HairBsdf, LABEL_GLOSSY)
+ CLOSURE_FLOAT3_PARAM(HairReflectionClosure, unused),
+ CLOSURE_FLOAT_PARAM(HairReflectionClosure, params.roughness1),
+ CLOSURE_FLOAT_PARAM(HairReflectionClosure, params.roughness2),
+ CLOSURE_FLOAT3_PARAM(HairReflectionClosure, params.T),
+ CLOSURE_FLOAT_PARAM(HairReflectionClosure, params.offset),
BSDF_CLOSURE_CLASS_END(HairReflection, hair_reflection)
-BSDF_CLOSURE_CLASS_BEGIN(HairTransmission, hair_transmission, hair_transmission, LABEL_GLOSSY)
- CLOSURE_FLOAT3_PARAM(HairTransmissionClosure, sc.N),
- CLOSURE_FLOAT_PARAM(HairTransmissionClosure, sc.data0),
- CLOSURE_FLOAT_PARAM(HairTransmissionClosure, sc.data1),
- CLOSURE_FLOAT3_PARAM(HairReflectionClosure, sc.T),
- CLOSURE_FLOAT_PARAM(HairReflectionClosure, sc.data2),
+BSDF_CLOSURE_CLASS_BEGIN(HairTransmission, hair_transmission, HairBsdf, LABEL_GLOSSY)
+ CLOSURE_FLOAT3_PARAM(HairTransmissionClosure, unused),
+ CLOSURE_FLOAT_PARAM(HairTransmissionClosure, params.roughness1),
+ CLOSURE_FLOAT_PARAM(HairTransmissionClosure, params.roughness2),
+ CLOSURE_FLOAT3_PARAM(HairReflectionClosure, params.T),
+ CLOSURE_FLOAT_PARAM(HairReflectionClosure, params.offset),
BSDF_CLOSURE_CLASS_END(HairTransmission, hair_transmission)
-VOLUME_CLOSURE_CLASS_BEGIN(VolumeHenyeyGreenstein, henyey_greenstein, LABEL_VOLUME_SCATTER)
- CLOSURE_FLOAT_PARAM(VolumeHenyeyGreensteinClosure, sc.data0),
+VOLUME_CLOSURE_CLASS_BEGIN(VolumeHenyeyGreenstein, henyey_greenstein, HenyeyGreensteinVolume, LABEL_VOLUME_SCATTER)
+ CLOSURE_FLOAT_PARAM(VolumeHenyeyGreensteinClosure, params.g),
VOLUME_CLOSURE_CLASS_END(VolumeHenyeyGreenstein, henyey_greenstein)
-VOLUME_CLOSURE_CLASS_BEGIN(VolumeAbsorption, absorption, LABEL_SINGULAR)
+VOLUME_CLOSURE_CLASS_BEGIN(VolumeAbsorption, absorption, ShaderClosure, LABEL_SINGULAR)
VOLUME_CLOSURE_CLASS_END(VolumeAbsorption, absorption)
/* Registration */
@@ -205,6 +208,12 @@ void OSLShader::register_closures(OSLShadingSystem *ss_)
bsdf_microfacet_ggx_aniso_params(), bsdf_microfacet_ggx_aniso_prepare);
register_closure(ss, "microfacet_ggx_refraction", id++,
bsdf_microfacet_ggx_refraction_params(), bsdf_microfacet_ggx_refraction_prepare);
+ register_closure(ss, "microfacet_multi_ggx", id++,
+ closure_bsdf_microfacet_multi_ggx_params(), closure_bsdf_microfacet_multi_ggx_prepare);
+ register_closure(ss, "microfacet_multi_ggx_glass", id++,
+ closure_bsdf_microfacet_multi_ggx_glass_params(), closure_bsdf_microfacet_multi_ggx_glass_prepare);
+ register_closure(ss, "microfacet_multi_ggx_aniso", id++,
+ closure_bsdf_microfacet_multi_ggx_aniso_params(), closure_bsdf_microfacet_multi_ggx_aniso_prepare);
register_closure(ss, "microfacet_beckmann", id++,
bsdf_microfacet_beckmann_params(), bsdf_microfacet_beckmann_prepare);
register_closure(ss, "microfacet_beckmann_aniso", id++,
@@ -250,5 +259,120 @@ void OSLShader::register_closures(OSLShadingSystem *ss_)
volume_absorption_params(), volume_absorption_prepare);
}
+/* BSDF Closure */
+
+bool CBSDFClosure::skip(const ShaderData *sd, int path_flag, int scattering)
+{
+ /* caustic options */
+ if((scattering & LABEL_GLOSSY) && (path_flag & PATH_RAY_DIFFUSE)) {
+ KernelGlobals *kg = sd->osl_globals;
+
+ if((!kernel_data.integrator.caustics_reflective && (scattering & LABEL_REFLECT)) ||
+ (!kernel_data.integrator.caustics_refractive && (scattering & LABEL_TRANSMIT)))
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* Multiscattering GGX closures */
+
+class MicrofacetMultiClosure : public CBSDFClosure {
+public:
+ MicrofacetBsdf params;
+ float3 color;
+
+ MicrofacetBsdf *alloc(ShaderData *sd, int path_flag, float3 weight)
+ {
+ /* Technically, the MultiGGX Glass closure may also transmit. However,
+ * since this is set statically and only used for caustic flags, this
+ * is probably as good as it gets. */
+ if(!skip(sd, path_flag, LABEL_GLOSSY|LABEL_REFLECT)) {
+ MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc_osl(sd, sizeof(MicrofacetBsdf), weight, &params);
+ MicrofacetExtra *extra = (MicrofacetExtra*)closure_alloc_extra(sd, sizeof(MicrofacetExtra));
+ if(bsdf && extra) {
+ bsdf->extra = extra;
+ bsdf->extra->color = color;
+ return bsdf;
+ }
+ }
+
+ return NULL;
+ }
+};
+
+class MicrofacetMultiGGXClosure : public MicrofacetMultiClosure {
+public:
+ void setup(ShaderData *sd, int path_flag, float3 weight)
+ {
+ MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight);
+ sd->flag |= (bsdf) ? bsdf_microfacet_multi_ggx_setup(bsdf) : 0;
+ }
+};
+
+ClosureParam *closure_bsdf_microfacet_multi_ggx_params()
+{
+ static ClosureParam params[] = {
+ CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, params.N),
+ CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, params.alpha_x),
+ CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, color),
+ CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXClosure, label, "label"),
+ CLOSURE_FINISH_PARAM(MicrofacetMultiGGXClosure)
+ };
+ return params;
+}
+CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_prepare, MicrofacetMultiGGXClosure);
+
+class MicrofacetMultiGGXAnisoClosure : public MicrofacetMultiClosure {
+public:
+ void setup(ShaderData *sd, int path_flag, float3 weight)
+ {
+ MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight);
+ sd->flag |= (bsdf) ? bsdf_microfacet_multi_ggx_aniso_setup(bsdf) : 0;
+ }
+};
+
+ClosureParam *closure_bsdf_microfacet_multi_ggx_aniso_params()
+{
+ static ClosureParam params[] = {
+ CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, params.N),
+ CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, params.T),
+ CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, params.alpha_x),
+ CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, params.alpha_y),
+ CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, color),
+ CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXClosure, label, "label"),
+ CLOSURE_FINISH_PARAM(MicrofacetMultiGGXClosure)
+ };
+ return params;
+}
+CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_aniso_prepare, MicrofacetMultiGGXAnisoClosure);
+
+class MicrofacetMultiGGXGlassClosure : public MicrofacetMultiClosure {
+public:
+ MicrofacetMultiGGXGlassClosure() : MicrofacetMultiClosure() {}
+
+ void setup(ShaderData *sd, int path_flag, float3 weight)
+ {
+ MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight);
+ sd->flag |= (bsdf) ? bsdf_microfacet_multi_ggx_glass_setup(bsdf) : 0;
+ }
+};
+
+ClosureParam *closure_bsdf_microfacet_multi_ggx_glass_params()
+{
+ static ClosureParam params[] = {
+ CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, params.N),
+ CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, params.alpha_x),
+ CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, params.ior),
+ CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, color),
+ CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXClosure, label, "label"),
+ CLOSURE_FINISH_PARAM(MicrofacetMultiGGXClosure)
+ };
+ return params;
+}
+CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_glass_prepare, MicrofacetMultiGGXGlassClosure);
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/osl/osl_closures.h b/intern/cycles/kernel/osl/osl_closures.h
index 1578d06cd56..cd7b33703ff 100644
--- a/intern/cycles/kernel/osl/osl_closures.h
+++ b/intern/cycles/kernel/osl/osl_closures.h
@@ -52,6 +52,9 @@ OSL::ClosureParam *closure_bssrdf_cubic_params();
OSL::ClosureParam *closure_bssrdf_gaussian_params();
OSL::ClosureParam *closure_bssrdf_burley_params();
OSL::ClosureParam *closure_henyey_greenstein_volume_params();
+OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_params();
+OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_glass_params();
+OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_aniso_params();
void closure_emission_prepare(OSL::RendererServices *, int id, void *data);
void closure_background_prepare(OSL::RendererServices *, int id, void *data);
@@ -63,6 +66,9 @@ void closure_bssrdf_cubic_prepare(OSL::RendererServices *, int id, void *data);
void closure_bssrdf_gaussian_prepare(OSL::RendererServices *, int id, void *data);
void closure_bssrdf_burley_prepare(OSL::RendererServices *, int id, void *data);
void closure_henyey_greenstein_volume_prepare(OSL::RendererServices *, int id, void *data);
+void closure_bsdf_microfacet_multi_ggx_prepare(OSL::RendererServices *, int id, void *data);
+void closure_bsdf_microfacet_multi_ggx_glass_prepare(OSL::RendererServices *, int id, void *data);
+void closure_bsdf_microfacet_multi_ggx_aniso_prepare(OSL::RendererServices *, int id, void *data);
#define CCLOSURE_PREPARE(name, classname) \
void name(RendererServices *, int id, void *data) \
@@ -84,21 +90,7 @@ void name(RendererServices *, int id, void *data) \
class CClosurePrimitive {
public:
- enum Category {
- BSDF, ///< Reflective and/or transmissive surface
- BSSRDF, ///< Sub-surface light transfer
- Emissive, ///< Light emission
- Background, ///< Background emission
- Volume, ///< Volume scattering
- Holdout, ///< Holdout from alpha
- AmbientOcclusion, ///< Ambient occlusion
- };
-
- CClosurePrimitive (Category category_) : category (category_) {}
- virtual ~CClosurePrimitive() {}
- virtual void setup() {}
-
- Category category;
+ virtual void setup(ShaderData *sd, int path_flag, float3 weight) = 0;
OSL::ustring label;
};
@@ -107,68 +99,22 @@ public:
class CBSDFClosure : public CClosurePrimitive {
public:
- ShaderClosure sc;
-
- CBSDFClosure(int scattering) : CClosurePrimitive(BSDF),
- m_scattering_label(scattering), m_shaderdata_flag(0)
- {}
-
- int scattering() const { return m_scattering_label; }
- int shaderdata_flag() const { return m_shaderdata_flag; }
-
- virtual void blur(float roughness) = 0;
- virtual float3 eval_reflect(const float3 &omega_out, const float3 &omega_in, float &pdf) const = 0;
- virtual float3 eval_transmit(const float3 &omega_out, const float3 &omega_in, float &pdf) const = 0;
-
- virtual int sample(const float3 &Ng,
- const float3 &omega_out, const float3 &domega_out_dx, const float3 &domega_out_dy,
- float randu, float randv,
- float3 &omega_in, float3 &domega_in_dx, float3 &domega_in_dy,
- float &pdf, float3 &eval) const = 0;
-
-protected:
- int m_scattering_label;
- int m_shaderdata_flag;
+ bool skip(const ShaderData *sd, int path_flag, int scattering);
};
-#define BSDF_CLOSURE_CLASS_BEGIN(Upper, lower, svmlower, TYPE) \
+#define BSDF_CLOSURE_CLASS_BEGIN(Upper, lower, structname, TYPE) \
\
class Upper##Closure : public CBSDFClosure { \
public: \
- Upper##Closure() : CBSDFClosure(TYPE) \
- { \
- } \
+ structname params; \
+ float3 unused; \
\
- void setup() \
+ void setup(ShaderData *sd, int path_flag, float3 weight) \
{ \
- sc.prim = NULL; \
- m_shaderdata_flag = bsdf_##lower##_setup(&sc); \
- } \
-\
- void blur(float roughness) \
- { \
- } \
-\
- float3 eval_reflect(const float3 &omega_out, const float3 &omega_in, float& pdf) const \
- { \
- pdf = 0.0f; \
- return make_float3(0.0f, 0.0f, 0.0f); \
- } \
-\
- float3 eval_transmit(const float3 &omega_out, const float3 &omega_in, float& pdf) const \
- { \
- pdf = 0.0f; \
- return make_float3(0.0f, 0.0f, 0.0f); \
- } \
-\
- int sample(const float3 &Ng, \
- const float3 &omega_out, const float3 &domega_out_dx, const float3 &domega_out_dy, \
- float randu, float randv, \
- float3 &omega_in, float3 &domega_in_dx, float3 &domega_in_dy, \
- float &pdf, float3 &eval) const \
- { \
- pdf = 0; \
- return LABEL_NONE; \
+ if(!skip(sd, path_flag, TYPE)) { \
+ structname *bsdf = (structname*)bsdf_alloc_osl(sd, sizeof(structname), weight, &params); \
+ sd->flag |= (bsdf) ? bsdf_##lower##_setup(bsdf) : 0; \
+ } \
} \
}; \
\
@@ -187,36 +133,18 @@ static ClosureParam *bsdf_##lower##_params() \
\
CCLOSURE_PREPARE_STATIC(bsdf_##lower##_prepare, Upper##Closure)
-
/* Volume */
-class CVolumeClosure : public CClosurePrimitive {
-public:
- ShaderClosure sc;
-
- CVolumeClosure(int scattering) : CClosurePrimitive(Volume),
- m_scattering_label(scattering), m_shaderdata_flag(0)
- {}
- ~CVolumeClosure() { }
-
- int scattering() const { return m_scattering_label; }
- int shaderdata_flag() const { return m_shaderdata_flag; }
-
-protected:
- int m_scattering_label;
- int m_shaderdata_flag;
-};
-
-#define VOLUME_CLOSURE_CLASS_BEGIN(Upper, lower, TYPE) \
+#define VOLUME_CLOSURE_CLASS_BEGIN(Upper, lower, structname, TYPE) \
\
-class Upper##Closure : public CVolumeClosure { \
+class Upper##Closure : public CBSDFClosure { \
public: \
- Upper##Closure() : CVolumeClosure(TYPE) {} \
+ structname params; \
\
- void setup() \
+ void setup(ShaderData *sd, int path_flag, float3 weight) \
{ \
- sc.prim = NULL; \
- m_shaderdata_flag = volume_##lower##_setup(&sc); \
+ structname *volume = (structname*)bsdf_alloc_osl(sd, sizeof(structname), weight, &params); \
+ sd->flag |= (volume) ? volume_##lower##_setup(volume) : 0; \
} \
}; \
\
diff --git a/intern/cycles/kernel/osl/osl_globals.h b/intern/cycles/kernel/osl/osl_globals.h
index 916542ec628..65cb7ecc6b4 100644
--- a/intern/cycles/kernel/osl/osl_globals.h
+++ b/intern/cycles/kernel/osl/osl_globals.h
@@ -54,13 +54,13 @@ struct OSLGlobals {
vector<OSL::ShaderGroupRef> surface_state;
vector<OSL::ShaderGroupRef> volume_state;
vector<OSL::ShaderGroupRef> displacement_state;
+ vector<OSL::ShaderGroupRef> bump_state;
OSL::ShaderGroupRef background_state;
/* attributes */
struct Attribute {
TypeDesc type;
- AttributeElement elem;
- int offset;
+ AttributeDescriptor desc;
ParamValue value;
};
diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp
index 3b479fb2b89..f56ae9f7b8c 100644
--- a/intern/cycles/kernel/osl/osl_services.cpp
+++ b/intern/cycles/kernel/osl/osl_services.cpp
@@ -41,6 +41,7 @@
#include "kernel_differential.h"
#include "kernel_montecarlo.h"
#include "kernel_camera.h"
+#include "kernels/cpu/kernel_cpu_image.h"
/* Note: "util_foreach.h" needs to be included after "kernel_compat_cpu.h", as
* for some reason ccl::foreach conflicts with openvdb::tools::foreach, which is
@@ -49,8 +50,8 @@
#include "util_foreach.h"
#include "util_logging.h"
#include "util_string.h"
-
#include "geom/geom.h"
+#include "bvh/bvh.h"
#include "kernel_projection.h"
#include "kernel_accumulate.h"
@@ -96,6 +97,7 @@ ustring OSLRenderServices::u_geom_numpolyvertices("geom:numpolyvertices");
ustring OSLRenderServices::u_geom_trianglevertices("geom:trianglevertices");
ustring OSLRenderServices::u_geom_polyvertices("geom:polyvertices");
ustring OSLRenderServices::u_geom_name("geom:name");
+ustring OSLRenderServices::u_geom_undisplaced("geom:undisplaced");
ustring OSLRenderServices::u_is_smooth("geom:is_smooth");
#ifdef __HAIR__
ustring OSLRenderServices::u_is_curve("geom:is_curve");
@@ -130,8 +132,10 @@ OSLRenderServices::OSLRenderServices()
OSLRenderServices::~OSLRenderServices()
{
- VLOG(2) << "OSL texture system stats:\n"
- << osl_ts->getstats();
+ if(osl_ts) {
+ VLOG(2) << "OSL texture system stats:\n"
+ << osl_ts->getstats();
+ }
#ifdef WITH_PTEX
ptex_cache->release();
#endif
@@ -168,6 +172,12 @@ bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 &result
return true;
}
+ else if(sd->type == PRIMITIVE_LAMP) {
+ Transform tfm = transform_transpose(sd->ob_tfm);
+ COPY_MATRIX44(&result, &tfm);
+
+ return true;
+ }
}
return false;
@@ -198,6 +208,12 @@ bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44
return true;
}
+ else if(sd->type == PRIMITIVE_LAMP) {
+ Transform tfm = transform_transpose(sd->ob_itfm);
+ COPY_MATRIX44(&result, &tfm);
+
+ return true;
+ }
}
return false;
@@ -287,6 +303,12 @@ bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 &result
return true;
}
+ else if(sd->type == PRIMITIVE_LAMP) {
+ Transform tfm = transform_transpose(sd->ob_tfm);
+ COPY_MATRIX44(&result, &tfm);
+
+ return true;
+ }
}
return false;
@@ -312,6 +334,12 @@ bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44
return true;
}
+ else if(sd->type == PRIMITIVE_LAMP) {
+ Transform tfm = transform_transpose(sd->ob_itfm);
+ COPY_MATRIX44(&result, &tfm);
+
+ return true;
+ }
}
return false;
@@ -557,13 +585,13 @@ static bool get_mesh_element_attribute(KernelGlobals *kg, const ShaderData *sd,
attr.type == TypeDesc::TypeNormal || attr.type == TypeDesc::TypeColor)
{
float3 fval[3];
- fval[0] = primitive_attribute_float3(kg, sd, attr.elem, attr.offset,
+ fval[0] = primitive_attribute_float3(kg, sd, attr.desc,
(derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
return set_attribute_float3(fval, type, derivatives, val);
}
else if(attr.type == TypeDesc::TypeFloat) {
float fval[3];
- fval[0] = primitive_attribute_float(kg, sd, attr.elem, attr.offset,
+ fval[0] = primitive_attribute_float(kg, sd, attr.desc,
(derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
return set_attribute_float(fval, type, derivatives, val);
}
@@ -576,7 +604,7 @@ static bool get_mesh_attribute(KernelGlobals *kg, const ShaderData *sd, const OS
const TypeDesc& type, bool derivatives, void *val)
{
if(attr.type == TypeDesc::TypeMatrix) {
- Transform tfm = primitive_attribute_matrix(kg, sd, attr.offset);
+ Transform tfm = primitive_attribute_matrix(kg, sd, attr.desc);
return set_attribute_matrix(tfm, type, val);
}
else {
@@ -790,7 +818,7 @@ bool OSLRenderServices::get_attribute(ShaderData *sd, bool derivatives, ustring
TypeDesc type, ustring name, void *val)
{
KernelGlobals *kg = sd->osl_globals;
- bool is_curve;
+ int prim_type = 0;
int object;
/* lookup of attribute on another object */
@@ -801,25 +829,24 @@ bool OSLRenderServices::get_attribute(ShaderData *sd, bool derivatives, ustring
return false;
object = it->second;
- is_curve = false;
}
else {
object = sd->object;
- is_curve = (sd->type & PRIMITIVE_ALL_CURVE) != 0;
+ prim_type = attribute_primitive_type(kg, sd);
if(object == OBJECT_NONE)
return get_background_attribute(kg, sd, name, type, derivatives, val);
}
/* find attribute on object */
- object = object*ATTR_PRIM_TYPES + (is_curve == true);
+ object = object*ATTR_PRIM_TYPES + prim_type;
OSLGlobals::AttributeMap& attribute_map = kg->osl->attribute_map[object];
OSLGlobals::AttributeMap::iterator it = attribute_map.find(name);
if(it != attribute_map.end()) {
const OSLGlobals::Attribute& attr = it->second;
- if(attr.elem != ATTR_ELEMENT_OBJECT) {
+ if(attr.desc.element != ATTR_ELEMENT_OBJECT) {
/* triangle and vertex attributes */
if(get_mesh_element_attribute(kg, sd, attr, type, derivatives, val))
return true;
@@ -916,7 +943,7 @@ bool OSLRenderServices::texture(ustring filename,
#endif
bool status;
- if(filename[0] == '@') {
+ if(filename.length() && filename[0] == '@') {
int slot = atoi(filename.c_str() + 1);
float4 rgba = kernel_tex_image_interp(slot, s, 1.0f - t);
@@ -997,7 +1024,7 @@ bool OSLRenderServices::texture3d(ustring filename,
}
bool status;
- if(filename[0] == '@') {
+ if(filename.length() && filename[0] == '@') {
int slot = atoi(filename.c_str() + 1);
float4 rgba = kernel_tex_image_interp_3d(slot, P.x, P.y, P.z);
@@ -1154,7 +1181,7 @@ bool OSLRenderServices::trace(TraceOpt &options, OSL::ShaderGlobals *sg,
tracedata->sd.osl_globals = sd->osl_globals;
/* raytrace */
- return scene_intersect(sd->osl_globals, &ray, PATH_RAY_ALL_VISIBILITY, &tracedata->isect, NULL, 0.0f, 0.0f);
+ return scene_intersect(sd->osl_globals, ray, PATH_RAY_ALL_VISIBILITY, &tracedata->isect, NULL, 0.0f, 0.0f);
}
diff --git a/intern/cycles/kernel/osl/osl_services.h b/intern/cycles/kernel/osl/osl_services.h
index 2701abb483c..0f2e02c62b0 100644
--- a/intern/cycles/kernel/osl/osl_services.h
+++ b/intern/cycles/kernel/osl/osl_services.h
@@ -158,6 +158,7 @@ public:
static ustring u_geom_trianglevertices;
static ustring u_geom_polyvertices;
static ustring u_geom_name;
+ static ustring u_geom_undisplaced;
static ustring u_is_smooth;
static ustring u_is_curve;
static ustring u_curve_thickness;
diff --git a/intern/cycles/kernel/osl/osl_shader.cpp b/intern/cycles/kernel/osl/osl_shader.cpp
index f58368e6789..0d762bbdb38 100644
--- a/intern/cycles/kernel/osl/osl_shader.cpp
+++ b/intern/cycles/kernel/osl/osl_shader.cpp
@@ -23,10 +23,6 @@
#include "geom/geom_object.h"
-#include "closure/bsdf_diffuse.h"
-#include "closure/bssrdf.h"
-
-#include "osl_bssrdf.h"
#include "osl_closures.h"
#include "osl_globals.h"
#include "osl_services.h"
@@ -141,8 +137,10 @@ static void shaderdata_to_shaderglobals(KernelGlobals *kg, ShaderData *sd, PathS
/* Surface */
-static void flatten_surface_closure_tree(ShaderData *sd, int path_flag,
- const OSL::ClosureColor *closure, float3 weight = make_float3(1.0f, 1.0f, 1.0f))
+static void flatten_surface_closure_tree(ShaderData *sd,
+ int path_flag,
+ const OSL::ClosureColor *closure,
+ float3 weight = make_float3(1.0f, 1.0f, 1.0f))
{
/* OSL gives us a closure tree, we flatten it into arrays per
* closure type, for evaluation, sampling, etc later on. */
@@ -164,158 +162,10 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag,
CClosurePrimitive *prim = (CClosurePrimitive *)comp->data();
if(prim) {
- ShaderClosure sc;
-
#ifdef OSL_SUPPORTS_WEIGHTED_CLOSURE_COMPONENTS
weight = weight*TO_FLOAT3(comp->w);
#endif
- sc.weight = weight;
-
- prim->setup();
-
- switch(prim->category) {
- case CClosurePrimitive::BSDF: {
- CBSDFClosure *bsdf = (CBSDFClosure *)prim;
- int scattering = bsdf->scattering();
-
- /* caustic options */
- if((scattering & LABEL_GLOSSY) && (path_flag & PATH_RAY_DIFFUSE)) {
- KernelGlobals *kg = sd->osl_globals;
-
- if((!kernel_data.integrator.caustics_reflective && (scattering & LABEL_REFLECT)) ||
- (!kernel_data.integrator.caustics_refractive && (scattering & LABEL_TRANSMIT)))
- {
- return;
- }
- }
-
- /* sample weight */
- float sample_weight = fabsf(average(weight));
-
- sc.sample_weight = sample_weight;
-
- sc.type = bsdf->sc.type;
- sc.N = bsdf->sc.N;
- sc.T = bsdf->sc.T;
- sc.data0 = bsdf->sc.data0;
- sc.data1 = bsdf->sc.data1;
- sc.data2 = bsdf->sc.data2;
- sc.prim = bsdf->sc.prim;
-
- /* add */
- if(sc.sample_weight > CLOSURE_WEIGHT_CUTOFF && sd->num_closure < MAX_CLOSURE) {
- sd->closure[sd->num_closure++] = sc;
- sd->flag |= bsdf->shaderdata_flag();
- }
- break;
- }
- case CClosurePrimitive::Emissive: {
- /* sample weight */
- float sample_weight = fabsf(average(weight));
-
- sc.sample_weight = sample_weight;
- sc.type = CLOSURE_EMISSION_ID;
- sc.data0 = 0.0f;
- sc.data1 = 0.0f;
- sc.data2 = 0.0f;
- sc.prim = NULL;
-
- /* flag */
- if(sd->num_closure < MAX_CLOSURE) {
- sd->closure[sd->num_closure++] = sc;
- sd->flag |= SD_EMISSION;
- }
- break;
- }
- case CClosurePrimitive::AmbientOcclusion: {
- /* sample weight */
- float sample_weight = fabsf(average(weight));
-
- sc.sample_weight = sample_weight;
- sc.type = CLOSURE_AMBIENT_OCCLUSION_ID;
- sc.data0 = 0.0f;
- sc.data1 = 0.0f;
- sc.data2 = 0.0f;
- sc.prim = NULL;
-
- if(sd->num_closure < MAX_CLOSURE) {
- sd->closure[sd->num_closure++] = sc;
- sd->flag |= SD_AO;
- }
- break;
- }
- case CClosurePrimitive::Holdout: {
- sc.sample_weight = 0.0f;
- sc.type = CLOSURE_HOLDOUT_ID;
- sc.data0 = 0.0f;
- sc.data1 = 0.0f;
- sc.data2 = 0.0f;
- sc.prim = NULL;
-
- if(sd->num_closure < MAX_CLOSURE) {
- sd->closure[sd->num_closure++] = sc;
- sd->flag |= SD_HOLDOUT;
- }
- break;
- }
- case CClosurePrimitive::BSSRDF: {
- CBSSRDFClosure *bssrdf = (CBSSRDFClosure *)prim;
- float sample_weight = fabsf(average(weight));
-
- if(sample_weight > CLOSURE_WEIGHT_CUTOFF && sd->num_closure+2 < MAX_CLOSURE) {
- sc.sample_weight = sample_weight;
-
- sc.type = bssrdf->sc.type;
- sc.N = bssrdf->sc.N;
- sc.data1 = bssrdf->sc.data1;
- sc.T.x = bssrdf->sc.T.x;
- sc.prim = NULL;
-
- /* disable in case of diffuse ancestor, can't see it well then and
- * adds considerably noise due to probabilities of continuing path
- * getting lower and lower */
- if(path_flag & PATH_RAY_DIFFUSE_ANCESTOR)
- bssrdf->radius = make_float3(0.0f, 0.0f, 0.0f);
-
- float3 albedo =
- (bssrdf->sc.type == CLOSURE_BSSRDF_BURLEY_ID)
- ? bssrdf->albedo
- : make_float3(0.0f, 0.0f, 0.0f);
-
- /* create one closure for each color channel */
- if(fabsf(weight.x) > 0.0f) {
- sc.weight = make_float3(weight.x, 0.0f, 0.0f);
- sc.data0 = bssrdf->radius.x;
- sc.data1 = 0.0f;
- sc.data2 = albedo.x;
- sd->flag |= bssrdf_setup(&sc, sc.type);
- sd->closure[sd->num_closure++] = sc;
- }
-
- if(fabsf(weight.y) > 0.0f) {
- sc.weight = make_float3(0.0f, weight.y, 0.0f);
- sc.data0 = bssrdf->radius.y;
- sc.data1 = 0.0f;
- sc.data2 = albedo.y;
- sd->flag |= bssrdf_setup(&sc, sc.type);
- sd->closure[sd->num_closure++] = sc;
- }
-
- if(fabsf(weight.z) > 0.0f) {
- sc.weight = make_float3(0.0f, 0.0f, weight.z);
- sc.data0 = bssrdf->radius.z;
- sc.data1 = 0.0f;
- sc.data2 = albedo.z;
- sd->flag |= bssrdf_setup(&sc, sc.type);
- sd->closure[sd->num_closure++] = sc;
- }
- }
- break;
- }
- case CClosurePrimitive::Background:
- case CClosurePrimitive::Volume:
- break; /* not relevant */
- }
+ prim->setup(sd, path_flag, weight);
}
break;
}
@@ -334,6 +184,48 @@ void OSLShader::eval_surface(KernelGlobals *kg, ShaderData *sd, PathState *state
OSL::ShadingContext *octx = tdata->context[(int)ctx];
int shader = sd->shader & SHADER_MASK;
+ /* automatic bump shader */
+ if(kg->osl->bump_state[shader]) {
+ /* save state */
+ float3 P = sd->P;
+ float3 dPdx = sd->dP.dx;
+ float3 dPdy = sd->dP.dy;
+
+ /* set state as if undisplaced */
+ if(sd->flag & SD_HAS_DISPLACEMENT) {
+ float data[9];
+ bool found = kg->osl->services->get_attribute(sd, true, OSLRenderServices::u_empty, TypeDesc::TypeVector,
+ OSLRenderServices::u_geom_undisplaced, data);
+ (void)found;
+ assert(found);
+
+ memcpy(&sd->P, data, sizeof(float)*3);
+ memcpy(&sd->dP.dx, data+3, sizeof(float)*3);
+ memcpy(&sd->dP.dy, data+6, sizeof(float)*3);
+
+ object_position_transform(kg, sd, &sd->P);
+ object_dir_transform(kg, sd, &sd->dP.dx);
+ object_dir_transform(kg, sd, &sd->dP.dy);
+
+ globals->P = TO_VEC3(sd->P);
+ globals->dPdx = TO_VEC3(sd->dP.dx);
+ globals->dPdy = TO_VEC3(sd->dP.dy);
+ }
+
+ /* execute bump shader */
+ ss->execute(octx, *(kg->osl->bump_state[shader]), *globals);
+
+ /* reset state */
+ sd->P = P;
+ sd->dP.dx = dPdx;
+ sd->dP.dy = dPdy;
+
+ globals->P = TO_VEC3(P);
+ globals->dPdx = TO_VEC3(dPdx);
+ globals->dPdy = TO_VEC3(dPdy);
+ }
+
+ /* surface shader */
if(kg->osl->surface_state[shader]) {
ss->execute(octx, *(kg->osl->surface_state[shader]), *globals);
}
@@ -345,7 +237,9 @@ void OSLShader::eval_surface(KernelGlobals *kg, ShaderData *sd, PathState *state
/* Background */
-static float3 flatten_background_closure_tree(const OSL::ClosureColor *closure)
+static void flatten_background_closure_tree(ShaderData *sd,
+ const OSL::ClosureColor *closure,
+ float3 weight = make_float3(1.0f, 1.0f, 1.0f))
{
/* OSL gives us a closure tree, if we are shading for background there
* is only one supported closure type at the moment, which has no evaluation
@@ -354,32 +248,32 @@ static float3 flatten_background_closure_tree(const OSL::ClosureColor *closure)
switch(closure->id) {
case OSL::ClosureColor::MUL: {
OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
-
- return TO_FLOAT3(mul->weight) * flatten_background_closure_tree(mul->closure);
+ flatten_background_closure_tree(sd, mul->closure, weight * TO_FLOAT3(mul->weight));
+ break;
}
case OSL::ClosureColor::ADD: {
OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
- return flatten_background_closure_tree(add->closureA) +
- flatten_background_closure_tree(add->closureB);
+ flatten_background_closure_tree(sd, add->closureA, weight);
+ flatten_background_closure_tree(sd, add->closureB, weight);
+ break;
}
default: {
OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
CClosurePrimitive *prim = (CClosurePrimitive *)comp->data();
- if(prim && prim->category == CClosurePrimitive::Background)
+ if(prim) {
#ifdef OSL_SUPPORTS_WEIGHTED_CLOSURE_COMPONENTS
- return TO_FLOAT3(comp->w);
-#else
- return make_float3(1.0f, 1.0f, 1.0f);
+ weight = weight*TO_FLOAT3(comp->w);
#endif
+ prim->setup(sd, 0, weight);
+ }
+ break;
}
}
-
- return make_float3(0.0f, 0.0f, 0.0f);
}
-float3 OSLShader::eval_background(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag, ShaderContext ctx)
+void OSLShader::eval_background(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag, ShaderContext ctx)
{
/* setup shader globals from shader data */
OSLThreadData *tdata = kg->osl_tdata;
@@ -396,15 +290,14 @@ float3 OSLShader::eval_background(KernelGlobals *kg, ShaderData *sd, PathState *
/* return background color immediately */
if(globals->Ci)
- return flatten_background_closure_tree(globals->Ci);
-
- return make_float3(0.0f, 0.0f, 0.0f);
+ flatten_background_closure_tree(sd, globals->Ci);
}
/* Volume */
static void flatten_volume_closure_tree(ShaderData *sd,
- const OSL::ClosureColor *closure, float3 weight = make_float3(1.0f, 1.0f, 1.0f))
+ const OSL::ClosureColor *closure,
+ float3 weight = make_float3(1.0f, 1.0f, 1.0f))
{
/* OSL gives us a closure tree, we flatten it into arrays per
* closure type, for evaluation, sampling, etc later on. */
@@ -426,60 +319,10 @@ static void flatten_volume_closure_tree(ShaderData *sd,
CClosurePrimitive *prim = (CClosurePrimitive *)comp->data();
if(prim) {
- ShaderClosure sc;
-
#ifdef OSL_SUPPORTS_WEIGHTED_CLOSURE_COMPONENTS
weight = weight*TO_FLOAT3(comp->w);
#endif
- sc.weight = weight;
-
- prim->setup();
-
- switch(prim->category) {
- case CClosurePrimitive::Volume: {
- CVolumeClosure *volume = (CVolumeClosure *)prim;
- /* sample weight */
- float sample_weight = fabsf(average(weight));
-
- sc.sample_weight = sample_weight;
- sc.type = volume->sc.type;
- sc.data0 = volume->sc.data0;
- sc.data1 = volume->sc.data1;
-
- /* add */
- if((sc.sample_weight > CLOSURE_WEIGHT_CUTOFF) &&
- (sd->num_closure < MAX_CLOSURE))
- {
- sd->closure[sd->num_closure++] = sc;
- sd->flag |= volume->shaderdata_flag();
- }
- break;
- }
- case CClosurePrimitive::Emissive: {
- /* sample weight */
- float sample_weight = fabsf(average(weight));
-
- sc.sample_weight = sample_weight;
- sc.type = CLOSURE_EMISSION_ID;
- sc.data0 = 0.0f;
- sc.data1 = 0.0f;
- sc.prim = NULL;
-
- /* flag */
- if(sd->num_closure < MAX_CLOSURE) {
- sd->closure[sd->num_closure++] = sc;
- sd->flag |= SD_EMISSION;
- }
- break;
- }
- case CClosurePrimitive::Holdout:
- break; /* not implemented */
- case CClosurePrimitive::Background:
- case CClosurePrimitive::BSDF:
- case CClosurePrimitive::BSSRDF:
- case CClosurePrimitive::AmbientOcclusion:
- break; /* not relevant */
- }
+ prim->setup(sd, 0, weight);
}
}
}
@@ -531,43 +374,9 @@ void OSLShader::eval_displacement(KernelGlobals *kg, ShaderData *sd, ShaderConte
sd->P = TO_FLOAT3(globals->P);
}
-/* BSDF Closure */
-
-int OSLShader::bsdf_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3& eval, float3& omega_in, differential3& domega_in, float& pdf)
-{
- CBSDFClosure *sample_bsdf = (CBSDFClosure *)sc->prim;
-
- pdf = 0.0f;
-
- return sample_bsdf->sample(sd->Ng,
- sd->I, sd->dI.dx, sd->dI.dy,
- randu, randv,
- omega_in, domega_in.dx, domega_in.dy,
- pdf, eval);
-}
-
-float3 OSLShader::bsdf_eval(const ShaderData *sd, const ShaderClosure *sc, const float3& omega_in, float& pdf)
-{
- CBSDFClosure *bsdf = (CBSDFClosure *)sc->prim;
- float3 bsdf_eval;
-
- if(dot(sd->Ng, omega_in) >= 0.0f)
- bsdf_eval = bsdf->eval_reflect(sd->I, omega_in, pdf);
- else
- bsdf_eval = bsdf->eval_transmit(sd->I, omega_in, pdf);
-
- return bsdf_eval;
-}
-
-void OSLShader::bsdf_blur(ShaderClosure *sc, float roughness)
-{
- CBSDFClosure *bsdf = (CBSDFClosure *)sc->prim;
- bsdf->blur(roughness);
-}
-
/* Attributes */
-int OSLShader::find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeElement *elem)
+int OSLShader::find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeDescriptor *desc)
{
/* for OSL, a hash map is used to lookup the attribute by name. */
int object = sd->object*ATTR_PRIM_TYPES;
@@ -581,16 +390,23 @@ int OSLShader::find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id,
if(it != attr_map.end()) {
const OSLGlobals::Attribute &osl_attr = it->second;
- *elem = osl_attr.elem;
+ *desc = osl_attr.desc;
- if(sd->prim == PRIM_NONE && (AttributeElement)osl_attr.elem != ATTR_ELEMENT_MESH)
+ if(sd->prim == PRIM_NONE && (AttributeElement)osl_attr.desc.element != ATTR_ELEMENT_MESH) {
+ desc->offset = ATTR_STD_NOT_FOUND;
return ATTR_STD_NOT_FOUND;
+ }
/* return result */
- return (osl_attr.elem == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : osl_attr.offset;
+ if(osl_attr.desc.element == ATTR_ELEMENT_NONE) {
+ desc->offset = ATTR_STD_NOT_FOUND;
+ }
+ return desc->offset;
}
- else
+ else {
+ desc->offset = ATTR_STD_NOT_FOUND;
return (int)ATTR_STD_NOT_FOUND;
+ }
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/osl/osl_shader.h b/intern/cycles/kernel/osl/osl_shader.h
index 7d26cd40da5..ad06dd6929d 100644
--- a/intern/cycles/kernel/osl/osl_shader.h
+++ b/intern/cycles/kernel/osl/osl_shader.h
@@ -54,20 +54,12 @@ public:
/* eval */
static void eval_surface(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag, ShaderContext ctx);
- static float3 eval_background(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag, ShaderContext ctx);
+ static void eval_background(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag, ShaderContext ctx);
static void eval_volume(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag, ShaderContext ctx);
static void eval_displacement(KernelGlobals *kg, ShaderData *sd, ShaderContext ctx);
- /* sample & eval */
- static int bsdf_sample(const ShaderData *sd, const ShaderClosure *sc,
- float randu, float randv,
- float3& eval, float3& omega_in, differential3& domega_in, float& pdf);
- static float3 bsdf_eval(const ShaderData *sd, const ShaderClosure *sc,
- const float3& omega_in, float& pdf);
- static void bsdf_blur(ShaderClosure *sc, float roughness);
-
/* attributes */
- static int find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeElement *elem);
+ static int find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeDescriptor *desc);
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/shaders/CMakeLists.txt b/intern/cycles/kernel/shaders/CMakeLists.txt
index 49030f33c26..b43f8402d42 100644
--- a/intern/cycles/kernel/shaders/CMakeLists.txt
+++ b/intern/cycles/kernel/shaders/CMakeLists.txt
@@ -81,6 +81,7 @@ set(SRC_OSL
node_wireframe.osl
node_hair_bsdf.osl
node_uv_map.osl
+ node_rgb_to_bw.osl
)
set(SRC_OSL_HEADERS
diff --git a/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl b/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl
index 281ed4e8726..bef6d7e8809 100644
--- a/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl
+++ b/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl
@@ -45,12 +45,14 @@ shader node_anisotropic_bsdf(
RoughnessV = Roughness / (1.0 - aniso);
}
- if (distribution == "Sharp")
+ if (distribution == "sharp")
BSDF = Color * reflection(Normal);
- else if (distribution == "Beckmann")
+ else if (distribution == "beckmann")
BSDF = Color * microfacet_beckmann_aniso(Normal, T, RoughnessU, RoughnessV);
else if (distribution == "GGX")
BSDF = Color * microfacet_ggx_aniso(Normal, T, RoughnessU, RoughnessV);
+ else if (distribution == "Multiscatter GGX")
+ BSDF = Color * microfacet_multi_ggx_aniso(Normal, T, RoughnessU, RoughnessV, Color);
else
BSDF = Color * ashikhmin_shirley(Normal, T, RoughnessU, RoughnessV);
}
diff --git a/intern/cycles/kernel/shaders/node_brick_texture.osl b/intern/cycles/kernel/shaders/node_brick_texture.osl
index 35e01178ba8..c303594681c 100644
--- a/intern/cycles/kernel/shaders/node_brick_texture.osl
+++ b/intern/cycles/kernel/shaders/node_brick_texture.osl
@@ -28,7 +28,7 @@ float brick_noise(int n) /* fast integer noise */
return 0.5 * ((float)nn / 1073741824.0);
}
-float brick(point p, float mortar_size, float bias,
+float brick(point p, float mortar_size, float mortar_smooth, float bias,
float BrickWidth, float row_height, float offset_amount, int offset_frequency,
float squash_amount, int squash_frequency, float tint)
{
@@ -51,24 +51,33 @@ float brick(point p, float mortar_size, float bias,
tint = clamp((brick_noise((rownum << 16) + (bricknum & 65535)) + bias), 0.0, 1.0);
- return (x < mortar_size || y < mortar_size ||
- x > (brick_width - mortar_size) ||
- y > (row_height - mortar_size)) ? 1.0 : 0.0;
+ float min_dist = min(min(x, y), min(brick_width - x, row_height - y));
+ if(min_dist >= mortar_size) {
+ return 0.0;
+ }
+ else if(mortar_smooth == 0.0) {
+ return 1.0;
+ }
+ else {
+ min_dist = 1.0 - min_dist/mortar_size;
+ return smoothstep(0.0, mortar_smooth, min_dist);
+ }
}
shader node_brick_texture(
int use_mapping = 0,
matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
- float Offset = 0.5,
- int OffsetFrequency = 2,
- float Squash = 1.0,
- int SquashFrequency = 1,
+ float offset = 0.5,
+ int offset_frequency = 2,
+ float squash = 1.0,
+ int squash_frequency = 1,
point Vector = P,
color Color1 = 0.2,
color Color2 = 0.8,
color Mortar = 0.0,
float Scale = 5.0,
float MortarSize = 0.02,
+ float MortarSmooth = 0.0,
float Bias = 0.0,
float BrickWidth = 0.5,
float RowHeight = 0.25,
@@ -83,14 +92,14 @@ shader node_brick_texture(
float tint = 0.0;
color Col = Color1;
- Fac = brick(p * Scale, MortarSize, Bias, BrickWidth, RowHeight,
- Offset, OffsetFrequency, Squash, SquashFrequency, tint);
+ Fac = brick(p * Scale, MortarSize, MortarSmooth, Bias, BrickWidth, RowHeight,
+ offset, offset_frequency, squash, squash_frequency, tint);
if (Fac != 1.0) {
float facm = 1.0 - tint;
Col = facm * Color1 + tint * Color2;
}
- Color = (Fac == 1.0) ? Mortar : Col;
+ Color = mix(Col, Mortar, Fac);
}
diff --git a/intern/cycles/kernel/shaders/node_bump.osl b/intern/cycles/kernel/shaders/node_bump.osl
index 9882857f2ec..7f01cf2ca91 100644
--- a/intern/cycles/kernel/shaders/node_bump.osl
+++ b/intern/cycles/kernel/shaders/node_bump.osl
@@ -21,6 +21,7 @@
surface node_bump(
int invert = 0,
+ int use_object_space = 0,
normal NormalIn = N,
float Strength = 0.1,
float Distance = 1.0,
@@ -29,12 +30,20 @@ surface node_bump(
float SampleY = 0.0,
output normal NormalOut = N)
{
+ point Ptmp = P;
+ normal Normal = NormalIn;
+
+ if (use_object_space) {
+ Ptmp = transform("object", Ptmp);
+ Normal = normalize(transform("object", Normal));
+ }
+
/* get surface tangents from normal */
- vector dPdx = Dx(P);
- vector dPdy = Dy(P);
+ vector dPdx = Dx(Ptmp);
+ vector dPdy = Dy(Ptmp);
- vector Rx = cross(dPdy, NormalIn);
- vector Ry = cross(NormalIn, dPdx);
+ vector Rx = cross(dPdy, Normal);
+ vector Ry = cross(Normal, dPdx);
/* compute surface gradient and determinant */
float det = dot(dPdx, Rx);
@@ -49,7 +58,11 @@ surface node_bump(
dist *= -1.0;
/* compute and output perturbed normal */
- NormalOut = normalize(absdet * NormalIn - dist * sign(det) * surfgrad);
- NormalOut = normalize(strength * NormalOut + (1.0 - strength) * NormalIn);
+ NormalOut = normalize(absdet * Normal - dist * sign(det) * surfgrad);
+ NormalOut = normalize(strength * NormalOut + (1.0 - strength) * Normal);
+
+ if (use_object_space) {
+ NormalOut = normalize(transform("object", "world", NormalOut));
+ }
}
diff --git a/intern/cycles/kernel/shaders/node_convert_from_color.osl b/intern/cycles/kernel/shaders/node_convert_from_color.osl
index 44074317f42..e95a17f6fa1 100644
--- a/intern/cycles/kernel/shaders/node_convert_from_color.osl
+++ b/intern/cycles/kernel/shaders/node_convert_from_color.osl
@@ -17,18 +17,18 @@
#include "stdosl.h"
shader node_convert_from_color(
- color Color = 0.0,
- output string String = "",
- output float Val = 0.0,
- output int ValInt = 0,
- output vector Vector = vector(0.0, 0.0, 0.0),
- output point Point = point(0.0, 0.0, 0.0),
- output normal Normal = normal(0.0, 0.0, 0.0))
+ color value_color = 0.0,
+ output string value_string = "",
+ output float value_float = 0.0,
+ output int value_int = 0,
+ output vector value_vector = vector(0.0, 0.0, 0.0),
+ output point value_point = point(0.0, 0.0, 0.0),
+ output normal value_normal = normal(0.0, 0.0, 0.0))
{
- Val = Color[0] * 0.2126 + Color[1] * 0.7152 + Color[2] * 0.0722;
- ValInt = (int)(Color[0] * 0.2126 + Color[1] * 0.7152 + Color[2] * 0.0722);
- Vector = vector(Color[0], Color[1], Color[2]);
- Point = point(Color[0], Color[1], Color[2]);
- Normal = normal(Color[0], Color[1], Color[2]);
+ value_float = value_color[0] * 0.2126 + value_color[1] * 0.7152 + value_color[2] * 0.0722;
+ value_int = (int)(value_color[0] * 0.2126 + value_color[1] * 0.7152 + value_color[2] * 0.0722);
+ value_vector = vector(value_color[0], value_color[1], value_color[2]);
+ value_point = point(value_color[0], value_color[1], value_color[2]);
+ value_normal = normal(value_color[0], value_color[1], value_color[2]);
}
diff --git a/intern/cycles/kernel/shaders/node_convert_from_float.osl b/intern/cycles/kernel/shaders/node_convert_from_float.osl
index fc5c79c4c64..a5c2e3b26ad 100644
--- a/intern/cycles/kernel/shaders/node_convert_from_float.osl
+++ b/intern/cycles/kernel/shaders/node_convert_from_float.osl
@@ -17,18 +17,18 @@
#include "stdosl.h"
shader node_convert_from_float(
- float Val = 0.0,
- output string String = "",
- output int ValInt = 0,
- output color Color = 0.0,
- output vector Vector = vector(0.0, 0.0, 0.0),
- output point Point = point(0.0, 0.0, 0.0),
- output normal Normal = normal(0.0, 0.0, 0.0))
+ float value_float = 0.0,
+ output string value_string = "",
+ output int value_int = 0,
+ output color value_color = 0.0,
+ output vector value_vector = vector(0.0, 0.0, 0.0),
+ output point value_point = point(0.0, 0.0, 0.0),
+ output normal value_normal = normal(0.0, 0.0, 0.0))
{
- ValInt = (int)Val;
- Color = color(Val, Val, Val);
- Vector = vector(Val, Val, Val);
- Point = point(Val, Val, Val);
- Normal = normal(Val, Val, Val);
+ value_int = (int)value_float;
+ value_color = color(value_float, value_float, value_float);
+ value_vector = vector(value_float, value_float, value_float);
+ value_point = point(value_float, value_float, value_float);
+ value_normal = normal(value_float, value_float, value_float);
}
diff --git a/intern/cycles/kernel/shaders/node_convert_from_int.osl b/intern/cycles/kernel/shaders/node_convert_from_int.osl
index 3c3785ebc0d..0e6ae711210 100644
--- a/intern/cycles/kernel/shaders/node_convert_from_int.osl
+++ b/intern/cycles/kernel/shaders/node_convert_from_int.osl
@@ -17,19 +17,19 @@
#include "stdosl.h"
shader node_convert_from_int(
- int ValInt = 0,
- output string String = "",
- output float Val = 0.0,
- output color Color = 0.0,
- output vector Vector = vector(0.0, 0.0, 0.0),
- output point Point = point(0.0, 0.0, 0.0),
- output normal Normal = normal(0.0, 0.0, 0.0))
+ int value_int = 0,
+ output string value_string = "",
+ output float value_float = 0.0,
+ output color value_color = 0.0,
+ output vector value_vector = vector(0.0, 0.0, 0.0),
+ output point value_point = point(0.0, 0.0, 0.0),
+ output normal value_normal = normal(0.0, 0.0, 0.0))
{
- float f = (float)ValInt;
- Val = f;
- Color = color(f, f, f);
- Vector = vector(f, f, f);
- Point = point(f, f, f);
- Normal = normal(f, f, f);
+ float f = (float)value_int;
+ value_float = f;
+ value_color = color(f, f, f);
+ value_vector = vector(f, f, f);
+ value_point = point(f, f, f);
+ value_normal = normal(f, f, f);
}
diff --git a/intern/cycles/kernel/shaders/node_convert_from_normal.osl b/intern/cycles/kernel/shaders/node_convert_from_normal.osl
index 8ecc56ac8ce..7fffa7f6169 100644
--- a/intern/cycles/kernel/shaders/node_convert_from_normal.osl
+++ b/intern/cycles/kernel/shaders/node_convert_from_normal.osl
@@ -17,18 +17,18 @@
#include "stdosl.h"
shader node_convert_from_normal(
- normal Normal = normal(0.0, 0.0, 0.0),
- output string String = "",
- output float Val = 0.0,
- output int ValInt = 0,
- output vector Vector = vector(0.0, 0.0, 0.0),
- output color Color = 0.0,
- output point Point = point(0.0, 0.0, 0.0))
+ normal value_normal = normal(0.0, 0.0, 0.0),
+ output string value_string = "",
+ output float value_float = 0.0,
+ output int value_int = 0,
+ output vector value_vector = vector(0.0, 0.0, 0.0),
+ output color value_color = 0.0,
+ output point value_point = point(0.0, 0.0, 0.0))
{
- Val = (Normal[0] + Normal[1] + Normal[2]) * (1.0 / 3.0);
- ValInt = (int)((Normal[0] + Normal[1] + Normal[2]) * (1.0 / 3.0));
- Vector = vector(Normal[0], Normal[1], Normal[2]);
- Color = color(Normal[0], Normal[1], Normal[2]);
- Point = point(Normal[0], Normal[1], Normal[2]);
+ value_float = (value_normal[0] + value_normal[1] + value_normal[2]) * (1.0 / 3.0);
+ value_int = (int)((value_normal[0] + value_normal[1] + value_normal[2]) * (1.0 / 3.0));
+ value_vector = vector(value_normal[0], value_normal[1], value_normal[2]);
+ value_color = color(value_normal[0], value_normal[1], value_normal[2]);
+ value_point = point(value_normal[0], value_normal[1], value_normal[2]);
}
diff --git a/intern/cycles/kernel/shaders/node_convert_from_point.osl b/intern/cycles/kernel/shaders/node_convert_from_point.osl
index e5913b7a1e4..9e4930296bb 100644
--- a/intern/cycles/kernel/shaders/node_convert_from_point.osl
+++ b/intern/cycles/kernel/shaders/node_convert_from_point.osl
@@ -17,18 +17,18 @@
#include "stdosl.h"
shader node_convert_from_point(
- point Point = point(0.0, 0.0, 0.0),
- output string String = "",
- output float Val = 0.0,
- output int ValInt = 0,
- output vector Vector = vector(0.0, 0.0, 0.0),
- output color Color = 0.0,
- output normal Normal = normal(0.0, 0.0, 0.0))
+ point value_point = point(0.0, 0.0, 0.0),
+ output string value_string = "",
+ output float value_float = 0.0,
+ output int value_int = 0,
+ output vector value_vector = vector(0.0, 0.0, 0.0),
+ output color value_color = 0.0,
+ output normal value_normal = normal(0.0, 0.0, 0.0))
{
- Val = (Point[0] + Point[1] + Point[2]) * (1.0 / 3.0);
- ValInt = (int)((Normal[0] + Normal[1] + Normal[2]) * (1.0 / 3.0));
- Vector = vector(Point[0], Point[1], Point[2]);
- Color = color(Point[0], Point[1], Point[2]);
- Normal = normal(Point[0], Point[1], Point[2]);
+ value_float = (value_point[0] + value_point[1] + value_point[2]) * (1.0 / 3.0);
+ value_int = (int)((value_normal[0] + value_normal[1] + value_normal[2]) * (1.0 / 3.0));
+ value_vector = vector(value_point[0], value_point[1], value_point[2]);
+ value_color = color(value_point[0], value_point[1], value_point[2]);
+ value_normal = normal(value_point[0], value_point[1], value_point[2]);
}
diff --git a/intern/cycles/kernel/shaders/node_convert_from_string.osl b/intern/cycles/kernel/shaders/node_convert_from_string.osl
index 0466734277b..cbc6653eada 100644
--- a/intern/cycles/kernel/shaders/node_convert_from_string.osl
+++ b/intern/cycles/kernel/shaders/node_convert_from_string.osl
@@ -17,13 +17,13 @@
#include "stdosl.h"
shader node_convert_from_string(
- string String = "",
- output color Color = color(0.0, 0.0, 0.0),
- output float Val = 0.0,
- output int ValInt = 0,
- output vector Vector = vector(0.0, 0.0, 0.0),
- output point Point = point(0.0, 0.0, 0.0),
- output normal Normal = normal(0.0, 0.0, 0.0))
+ string value_string = "",
+ output color value_color = color(0.0, 0.0, 0.0),
+ output float value_float = 0.0,
+ output int value_int = 0,
+ output vector value_vector = vector(0.0, 0.0, 0.0),
+ output point value_point = point(0.0, 0.0, 0.0),
+ output normal value_normal = normal(0.0, 0.0, 0.0))
{
}
diff --git a/intern/cycles/kernel/shaders/node_convert_from_vector.osl b/intern/cycles/kernel/shaders/node_convert_from_vector.osl
index 79c5cb04550..8bdca469b90 100644
--- a/intern/cycles/kernel/shaders/node_convert_from_vector.osl
+++ b/intern/cycles/kernel/shaders/node_convert_from_vector.osl
@@ -17,18 +17,18 @@
#include "stdosl.h"
shader node_convert_from_vector(
- vector Vector = vector(0.0, 0.0, 0.0),
- output string String = "",
- output float Val = 0.0,
- output int ValInt = 0,
- output color Color = color(0.0, 0.0, 0.0),
- output point Point = point(0.0, 0.0, 0.0),
- output normal Normal = normal(0.0, 0.0, 0.0))
+ vector value_vector = vector(0.0, 0.0, 0.0),
+ output string value_string = "",
+ output float value_float = 0.0,
+ output int value_int = 0,
+ output color value_color = color(0.0, 0.0, 0.0),
+ output point value_point = point(0.0, 0.0, 0.0),
+ output normal value_normal = normal(0.0, 0.0, 0.0))
{
- Val = (Vector[0] + Vector[1] + Vector[2]) * (1.0 / 3.0);
- ValInt = (int)((Normal[0] + Normal[1] + Normal[2]) * (1.0 / 3.0));
- Color = color(Vector[0], Vector[1], Vector[2]);
- Point = point(Vector[0], Vector[1], Vector[2]);
- Normal = normal(Vector[0], Vector[1], Vector[2]);
+ value_float = (value_vector[0] + value_vector[1] + value_vector[2]) * (1.0 / 3.0);
+ value_int = (int)((value_normal[0] + value_normal[1] + value_normal[2]) * (1.0 / 3.0));
+ value_color = color(value_vector[0], value_vector[1], value_vector[2]);
+ value_point = point(value_vector[0], value_vector[1], value_vector[2]);
+ value_normal = normal(value_vector[0], value_vector[1], value_vector[2]);
}
diff --git a/intern/cycles/kernel/shaders/node_environment_texture.osl b/intern/cycles/kernel/shaders/node_environment_texture.osl
index 3a0b782c98e..0a7f602226d 100644
--- a/intern/cycles/kernel/shaders/node_environment_texture.osl
+++ b/intern/cycles/kernel/shaders/node_environment_texture.osl
@@ -44,7 +44,7 @@ shader node_environment_texture(
matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
vector Vector = P,
string filename = "",
- string projection = "Equirectangular",
+ string projection = "equirectangular",
string interpolation = "linear",
string color_space = "sRGB",
int is_float = 1,
@@ -59,7 +59,7 @@ shader node_environment_texture(
p = normalize(p);
- if (projection == "Equirectangular")
+ if (projection == "equirectangular")
p = environment_texture_direction_to_equirectangular(p);
else
p = environment_texture_direction_to_mirrorball(p);
diff --git a/intern/cycles/kernel/shaders/node_glass_bsdf.osl b/intern/cycles/kernel/shaders/node_glass_bsdf.osl
index 68bc107cc5e..a9723a8300a 100644
--- a/intern/cycles/kernel/shaders/node_glass_bsdf.osl
+++ b/intern/cycles/kernel/shaders/node_glass_bsdf.osl
@@ -19,7 +19,7 @@
shader node_glass_bsdf(
color Color = 0.8,
- string distribution = "Sharp",
+ string distribution = "sharp",
float Roughness = 0.2,
float IOR = 1.45,
normal Normal = N,
@@ -30,11 +30,13 @@ shader node_glass_bsdf(
float cosi = dot(I, Normal);
float Fr = fresnel_dielectric_cos(cosi, eta);
- if (distribution == "Sharp")
+ if (distribution == "sharp")
BSDF = Color * (Fr * reflection(Normal) + (1.0 - Fr) * refraction(Normal, eta));
- else if (distribution == "Beckmann")
+ else if (distribution == "beckmann")
BSDF = Color * (Fr * microfacet_beckmann(Normal, Roughness) +
(1.0 - Fr) * microfacet_beckmann_refraction(Normal, Roughness, eta));
+ else if (distribution == "Multiscatter GGX")
+ BSDF = Color * microfacet_multi_ggx_glass(Normal, Roughness, eta, Color);
else if (distribution == "GGX")
BSDF = Color * (Fr * microfacet_ggx(Normal, Roughness) +
(1.0 - Fr) * microfacet_ggx_refraction(Normal, Roughness, eta));
diff --git a/intern/cycles/kernel/shaders/node_glossy_bsdf.osl b/intern/cycles/kernel/shaders/node_glossy_bsdf.osl
index d3250b32d0b..f4ea7e7dc6a 100644
--- a/intern/cycles/kernel/shaders/node_glossy_bsdf.osl
+++ b/intern/cycles/kernel/shaders/node_glossy_bsdf.osl
@@ -24,12 +24,14 @@ shader node_glossy_bsdf(
normal Normal = N,
output closure color BSDF = 0)
{
- if (distribution == "Sharp")
+ if (distribution == "sharp")
BSDF = Color * reflection(Normal);
- else if (distribution == "Beckmann")
+ else if (distribution == "beckmann")
BSDF = Color * microfacet_beckmann(Normal, Roughness);
else if (distribution == "GGX")
BSDF = Color * microfacet_ggx(Normal, Roughness);
+ else if (distribution == "Multiscatter GGX")
+ BSDF = Color * microfacet_multi_ggx(Normal, Roughness, Color);
else
BSDF = Color * ashikhmin_shirley(Normal, vector(0, 0, 0), Roughness, Roughness);
diff --git a/intern/cycles/kernel/shaders/node_gradient_texture.osl b/intern/cycles/kernel/shaders/node_gradient_texture.osl
index 52b49688ab3..f458937a18f 100644
--- a/intern/cycles/kernel/shaders/node_gradient_texture.osl
+++ b/intern/cycles/kernel/shaders/node_gradient_texture.osl
@@ -29,31 +29,31 @@ float gradient(point p, string type)
float result = 0.0;
- if (type == "Linear") {
+ if (type == "linear") {
result = x;
}
- else if (type == "Quadratic") {
+ else if (type == "quadratic") {
float r = max(x, 0.0);
result = r * r;
}
- else if (type == "Easing") {
+ else if (type == "easing") {
float r = min(max(x, 0.0), 1.0);
float t = r * r;
result = (3.0 * t - 2.0 * t * r);
}
- else if (type == "Diagonal") {
+ else if (type == "diagonal") {
result = (x + y) * 0.5;
}
- else if (type == "Radial") {
+ else if (type == "radial") {
result = atan2(y, x) / M_2PI + 0.5;
}
else {
float r = max(1.0 - sqrt(x * x + y * y + z * z), 0.0);
- if (type == "Quadratic Sphere")
+ if (type == "quadratic_sphere")
result = r * r;
- else if (type == "Spherical")
+ else if (type == "spherical")
result = r;
}
@@ -63,7 +63,7 @@ float gradient(point p, string type)
shader node_gradient_texture(
int use_mapping = 0,
matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
- string Type = "Linear",
+ string type = "linear",
point Vector = P,
output float Fac = 0.0,
output color Color = 0.0)
@@ -73,7 +73,7 @@ shader node_gradient_texture(
if (use_mapping)
p = transform(mapping, p);
- Fac = gradient(p, Type);
+ Fac = gradient(p, type);
Color = color(Fac, Fac, Fac);
}
diff --git a/intern/cycles/kernel/shaders/node_hair_bsdf.osl b/intern/cycles/kernel/shaders/node_hair_bsdf.osl
index 54d4cb67c3b..ef8f2fae894 100644
--- a/intern/cycles/kernel/shaders/node_hair_bsdf.osl
+++ b/intern/cycles/kernel/shaders/node_hair_bsdf.osl
@@ -20,38 +20,39 @@
shader node_hair_bsdf(
color Color = 0.8,
- string component = "Reflection",
+ string component = "reflection",
float Offset = 0.0,
float RoughnessU = 0.1,
float RoughnessV = 1.0,
- normal Normal = Ng,
+ normal Tangent = normal(0, 0, 0),
output closure color BSDF = 0)
{
- float IsStrand;
float roughnessh = clamp(RoughnessU, 0.001, 1.0);
float roughnessv = clamp(RoughnessV, 0.001, 1.0);
- getattribute("geom:is_curve", IsStrand);
+ float offset = -Offset;
- if (!IsStrand) {
- if (backfacing()) {
- BSDF = transparent();
- }
- else {
- if (component == "Reflection")
- BSDF = Color * hair_reflection(Normal, roughnessh, roughnessv, normalize(dPdv), 0.0);
- else
- BSDF = Color * hair_transmission(Normal, roughnessh, roughnessv, normalize(dPdv), 0.0);
- }
+ normal T;
+ float IsCurve = 0;
+ getattribute("geom:is_curve", IsCurve);
+
+ if (isconnected(Tangent)) {
+ T = Tangent;
+ }
+ else if(!IsCurve) {
+ T = normalize(dPdv);
+ offset = 0.0;
+ }
+ else {
+ T = normalize(dPdu);
+ }
+
+ if (backfacing() && IsCurve) {
+ BSDF = transparent();
}
else {
- if (backfacing()) {
- BSDF = transparent();
- }
- else {
- if (component == "Reflection")
- BSDF = Color * hair_reflection(Normal, roughnessh, roughnessv, dPdu, -Offset);
- else
- BSDF = Color * hair_transmission(Normal, roughnessh, roughnessv, dPdu, -Offset);
- }
+ if (component == "reflection")
+ BSDF = Color * hair_reflection(Ng, roughnessh, roughnessv, T, offset);
+ else
+ BSDF = Color * hair_transmission(Ng, roughnessh, roughnessv, T, offset);
}
}
diff --git a/intern/cycles/kernel/shaders/node_image_texture.osl b/intern/cycles/kernel/shaders/node_image_texture.osl
index d3a347b70db..7cd2922dd4f 100644
--- a/intern/cycles/kernel/shaders/node_image_texture.osl
+++ b/intern/cycles/kernel/shaders/node_image_texture.osl
@@ -62,9 +62,9 @@ color image_texture_lookup(string filename,
int use_alpha,
int is_float,
string interpolation,
- string wrap)
+ string extension)
{
- color rgb = (color)texture(filename, u, 1.0 - v, "wrap", wrap, "interp", interpolation, "alpha", Alpha);
+ color rgb = (color)texture(filename, u, 1.0 - v, "wrap", extension, "interp", interpolation, "alpha", Alpha);
if (use_alpha) {
rgb = color_unpremultiply(rgb, Alpha);
@@ -86,9 +86,9 @@ shader node_image_texture(
point Vector = P,
string filename = "",
string color_space = "sRGB",
- string projection = "Flat",
+ string projection = "flat",
string interpolation = "smartcubic",
- string wrap = "periodic",
+ string extension = "periodic",
float projection_blend = 0.0,
int is_float = 1,
int use_alpha = 1,
@@ -100,7 +100,7 @@ shader node_image_texture(
if (use_mapping)
p = transform(mapping, p);
- if (projection == "Flat") {
+ if (projection == "flat") {
Color = image_texture_lookup(filename,
color_space,
p[0], p[1],
@@ -108,9 +108,9 @@ shader node_image_texture(
use_alpha,
is_float,
interpolation,
- wrap);
+ extension);
}
- else if (projection == "Box") {
+ else if (projection == "box") {
/* object space normal */
vector Nob = transform("world", "object", N);
@@ -184,7 +184,7 @@ shader node_image_texture(
use_alpha,
is_float,
interpolation,
- wrap);
+ extension);
Alpha += weight[0] * tmp_alpha;
}
if (weight[1] > 0.0) {
@@ -195,7 +195,7 @@ shader node_image_texture(
use_alpha,
is_float,
interpolation,
- wrap);
+ extension);
Alpha += weight[1] * tmp_alpha;
}
if (weight[2] > 0.0) {
@@ -206,11 +206,11 @@ shader node_image_texture(
use_alpha,
is_float,
interpolation,
- wrap);
+ extension);
Alpha += weight[2] * tmp_alpha;
}
}
- else if (projection == "Sphere") {
+ else if (projection == "sphere") {
point projected = map_to_sphere(texco_remap_square(p));
Color = image_texture_lookup(filename,
color_space,
@@ -219,9 +219,9 @@ shader node_image_texture(
use_alpha,
is_float,
interpolation,
- wrap);
+ extension);
}
- else if (projection == "Tube") {
+ else if (projection == "tube") {
point projected = map_to_tube(texco_remap_square(p));
Color = image_texture_lookup(filename,
color_space,
@@ -230,6 +230,6 @@ shader node_image_texture(
use_alpha,
is_float,
interpolation,
- wrap);
+ extension);
}
}
diff --git a/intern/cycles/kernel/shaders/node_magic_texture.osl b/intern/cycles/kernel/shaders/node_magic_texture.osl
index 55992e3494c..8d6af391e04 100644
--- a/intern/cycles/kernel/shaders/node_magic_texture.osl
+++ b/intern/cycles/kernel/shaders/node_magic_texture.osl
@@ -93,7 +93,7 @@ color magic(point p, int n, float distortion)
shader node_magic_texture(
int use_mapping = 0,
matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
- int Depth = 2,
+ int depth = 2,
float Distortion = 5.0,
float Scale = 5.0,
point Vector = P,
@@ -105,7 +105,7 @@ shader node_magic_texture(
if (use_mapping)
p = transform(mapping, p);
- Color = magic(p * Scale, Depth, Distortion);
+ Color = magic(p * Scale, depth, Distortion);
Fac = (Color[0] + Color[1] + Color[2]) * (1.0 / 3.0);
}
diff --git a/intern/cycles/kernel/shaders/node_math.osl b/intern/cycles/kernel/shaders/node_math.osl
index 7eef97fd7e8..f309ef7c6f3 100644
--- a/intern/cycles/kernel/shaders/node_math.osl
+++ b/intern/cycles/kernel/shaders/node_math.osl
@@ -49,54 +49,54 @@ float safe_log(float a, float b)
}
shader node_math(
- string type = "Add",
- int Clamp = 0,
+ string type = "add",
+ int use_clamp = 0,
float Value1 = 0.0,
float Value2 = 0.0,
output float Value = 0.0)
{
/* OSL asin, acos, pow check for values that could give rise to nan */
- if (type == "Add")
+ if (type == "add")
Value = Value1 + Value2;
- else if (type == "Subtract")
+ else if (type == "subtract")
Value = Value1 - Value2;
- else if (type == "Multiply")
+ else if (type == "multiply")
Value = Value1 * Value2;
- else if (type == "Divide")
+ else if (type == "divide")
Value = safe_divide(Value1, Value2);
- else if (type == "Sine")
+ else if (type == "sine")
Value = sin(Value1);
- else if (type == "Cosine")
+ else if (type == "cosine")
Value = cos(Value1);
- else if (type == "Tangent")
+ else if (type == "tangent")
Value = tan(Value1);
- else if (type == "Arcsine")
+ else if (type == "arcsine")
Value = asin(Value1);
- else if (type == "Arccosine")
+ else if (type == "arccosine")
Value = acos(Value1);
- else if (type == "Arctangent")
+ else if (type == "arctangent")
Value = atan(Value1);
- else if (type == "Power")
+ else if (type == "power")
Value = pow(Value1, Value2);
- else if (type == "Logarithm")
+ else if (type == "logarithm")
Value = safe_log(Value1, Value2);
- else if (type == "Minimum")
+ else if (type == "minimum")
Value = min(Value1, Value2);
- else if (type == "Maximum")
+ else if (type == "maximum")
Value = max(Value1, Value2);
- else if (type == "Round")
+ else if (type == "round")
Value = floor(Value1 + 0.5);
- else if (type == "Less Than")
+ else if (type == "less_than")
Value = Value1 < Value2;
- else if (type == "Greater Than")
+ else if (type == "greater_than")
Value = Value1 > Value2;
- else if (type == "Modulo")
+ else if (type == "modulo")
Value = safe_modulo(Value1, Value2);
- else if (type == "Absolute")
+ else if (type == "absolute")
Value = fabs(Value1);
- if (Clamp)
+ if (use_clamp)
Value = clamp(Value, 0.0, 1.0);
}
diff --git a/intern/cycles/kernel/shaders/node_mix.osl b/intern/cycles/kernel/shaders/node_mix.osl
index 9ef58e4cbba..0862c34b6e1 100644
--- a/intern/cycles/kernel/shaders/node_mix.osl
+++ b/intern/cycles/kernel/shaders/node_mix.osl
@@ -277,8 +277,8 @@ color node_mix_clamp(color col)
}
shader node_mix(
- string type = "Mix",
- int Clamp = 0,
+ string type = "mix",
+ int use_clamp = 0,
float Fac = 0.5,
color Color1 = 0.0,
color Color2 = 0.0,
@@ -286,44 +286,44 @@ shader node_mix(
{
float t = clamp(Fac, 0.0, 1.0);
- if (type == "Mix")
+ if (type == "mix")
Color = node_mix_blend(t, Color1, Color2);
- if (type == "Add")
+ if (type == "add")
Color = node_mix_add(t, Color1, Color2);
- if (type == "Multiply")
+ if (type == "multiply")
Color = node_mix_mul(t, Color1, Color2);
- if (type == "Screen")
+ if (type == "screen")
Color = node_mix_screen(t, Color1, Color2);
- if (type == "Overlay")
+ if (type == "overlay")
Color = node_mix_overlay(t, Color1, Color2);
- if (type == "Subtract")
+ if (type == "subtract")
Color = node_mix_sub(t, Color1, Color2);
- if (type == "Divide")
+ if (type == "divide")
Color = node_mix_div(t, Color1, Color2);
- if (type == "Difference")
+ if (type == "difference")
Color = node_mix_diff(t, Color1, Color2);
- if (type == "Darken")
+ if (type == "darken")
Color = node_mix_dark(t, Color1, Color2);
- if (type == "Lighten")
+ if (type == "lighten")
Color = node_mix_light(t, Color1, Color2);
- if (type == "Dodge")
+ if (type == "dodge")
Color = node_mix_dodge(t, Color1, Color2);
- if (type == "Burn")
+ if (type == "burn")
Color = node_mix_burn(t, Color1, Color2);
- if (type == "Hue")
+ if (type == "hue")
Color = node_mix_hue(t, Color1, Color2);
- if (type == "Saturation")
+ if (type == "saturation")
Color = node_mix_sat(t, Color1, Color2);
- if (type == "Value")
+ if (type == "value")
Color = node_mix_val (t, Color1, Color2);
- if (type == "Color")
+ if (type == "color")
Color = node_mix_color(t, Color1, Color2);
- if (type == "Soft Light")
+ if (type == "soft_light")
Color = node_mix_soft(t, Color1, Color2);
- if (type == "Linear Light")
+ if (type == "linear_light")
Color = node_mix_linear(t, Color1, Color2);
- if (Clamp)
+ if (use_clamp)
Color = node_mix_clamp(Color);
}
diff --git a/intern/cycles/kernel/shaders/node_musgrave_texture.osl b/intern/cycles/kernel/shaders/node_musgrave_texture.osl
index 4f95dec910a..91f4fba5898 100644
--- a/intern/cycles/kernel/shaders/node_musgrave_texture.osl
+++ b/intern/cycles/kernel/shaders/node_musgrave_texture.osl
@@ -187,7 +187,7 @@ float noise_musgrave_ridged_multi_fractal(point p, float H, float lacunarity,
shader node_musgrave_texture(
int use_mapping = 0,
matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
- string Type = "fBM",
+ string type = "fBM",
float Dimension = 2.0,
float Lacunarity = 1.0,
float Detail = 2.0,
@@ -210,15 +210,15 @@ shader node_musgrave_texture(
p = p * Scale;
- if (Type == "Multifractal")
+ if (type == "multifractal")
Fac = intensity * noise_musgrave_multi_fractal(p, dimension, lacunarity, octaves);
- else if (Type == "fBM")
+ else if (type == "fBM")
Fac = intensity * noise_musgrave_fBm(p, dimension, lacunarity, octaves);
- else if (Type == "Hybrid Multifractal")
+ else if (type == "hybrid_multifractal")
Fac = intensity * noise_musgrave_hybrid_multi_fractal(p, dimension, lacunarity, octaves, Offset, Gain);
- else if (Type == "Ridged Multifractal")
+ else if (type == "ridged_multifractal")
Fac = intensity * noise_musgrave_ridged_multi_fractal(p, dimension, lacunarity, octaves, Offset, Gain);
- else if (Type == "Hetero Terrain")
+ else if (type == "hetero_terrain")
Fac = intensity * noise_musgrave_hetero_terrain(p, dimension, lacunarity, octaves, Offset);
Color = color(Fac, Fac, Fac);
diff --git a/intern/cycles/kernel/shaders/node_normal.osl b/intern/cycles/kernel/shaders/node_normal.osl
index 2d04978fc72..7307971eddd 100644
--- a/intern/cycles/kernel/shaders/node_normal.osl
+++ b/intern/cycles/kernel/shaders/node_normal.osl
@@ -17,12 +17,12 @@
#include "stdosl.h"
shader node_normal(
- normal Direction = normal(0.0, 0.0, 0.0),
+ normal direction = normal(0.0, 0.0, 0.0),
normal NormalIn = normal(0.0, 0.0, 0.0),
output normal NormalOut = normal(0.0, 0.0, 0.0),
output float Dot = 1.0)
{
- NormalOut = normalize(Direction);
+ NormalOut = normalize(direction);
Dot = dot(NormalOut, normalize(NormalIn));
}
diff --git a/intern/cycles/kernel/shaders/node_normal_map.osl b/intern/cycles/kernel/shaders/node_normal_map.osl
index 01be566fb20..41bcac4fb10 100644
--- a/intern/cycles/kernel/shaders/node_normal_map.osl
+++ b/intern/cycles/kernel/shaders/node_normal_map.osl
@@ -20,23 +20,30 @@ shader node_normal_map(
normal NormalIn = N,
float Strength = 1.0,
color Color = color(0.5, 0.5, 1.0),
- string space = "Tangent",
+ string space = "tangent",
string attr_name = "geom:tangent",
string attr_sign_name = "geom:tangent_sign",
output normal Normal = NormalIn)
{
color mcolor = 2.0 * color(Color[0] - 0.5, Color[1] - 0.5, Color[2] - 0.5);
+ int is_backfacing = backfacing();
- if (space == "Tangent") {
+ if (space == "tangent") {
vector tangent;
vector ninterp;
float tangent_sign;
float is_smooth;
getattribute("geom:is_smooth", is_smooth);
- if (!is_smooth)
+ if (!is_smooth) {
ninterp = normalize(transform("world", "object", Ng));
+ /* the normal is already inverted, which is too soon for the math here */
+ if (is_backfacing) {
+ ninterp = -ninterp;
+ }
+ }
+
// get _unnormalized_ interpolated normal and tangent
if (getattribute(attr_name, tangent) &&
getattribute(attr_sign_name, tangent_sign) &&
@@ -53,27 +60,32 @@ shader node_normal_map(
Normal = normal(0, 0, 0);
}
}
- else if (space == "Object") {
+ else if (space == "object") {
Normal = normalize(transform("object", "world", vector(mcolor)));
}
- else if (space == "World") {
+ else if (space == "world") {
Normal = normalize(vector(mcolor));
}
- else if (space == "Blender Object") {
+ else if (space == "blender_object") {
/* strange blender convention */
mcolor[1] = -mcolor[1];
mcolor[2] = -mcolor[2];
Normal = normalize(transform("object", "world", vector(mcolor)));
}
- else if (space == "Blender World") {
+ else if (space == "blender_world") {
/* strange blender convention */
mcolor[1] = -mcolor[1];
mcolor[2] = -mcolor[2];
Normal = normalize(vector(mcolor));
}
-
+
+ /* invert normal for backfacing polygons */
+ if (is_backfacing) {
+ Normal = -Normal;
+ }
+
if (Strength != 1.0)
Normal = normalize(NormalIn + (Normal - NormalIn) * max(Strength, 0.0));
}
diff --git a/intern/cycles/kernel/shaders/node_output_displacement.osl b/intern/cycles/kernel/shaders/node_output_displacement.osl
index d0688cfda8d..294b8dd6bf2 100644
--- a/intern/cycles/kernel/shaders/node_output_displacement.osl
+++ b/intern/cycles/kernel/shaders/node_output_displacement.osl
@@ -18,6 +18,8 @@
displacement node_output_displacement(float Displacement = 0.0)
{
- P += N * Displacement * 0.1; /* todo: get rid of this factor */
+ vector dP = normalize(transform("object", N));
+ dP *= Displacement * 0.1; /* todo: get rid of this factor */
+ P += transform("object", "world", dP);
}
diff --git a/intern/cycles/kernel/shaders/node_ramp_util.h b/intern/cycles/kernel/shaders/node_ramp_util.h
new file mode 100644
index 00000000000..917fb65c6df
--- /dev/null
+++ b/intern/cycles/kernel/shaders/node_ramp_util.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* NOTE: svm_ramp.h, svm_ramp_util.h and node_ramp_util.h must stay consistent */
+
+color rgb_ramp_lookup(color ramp[], float at, int interpolate, int extrapolate)
+{
+ float f = at;
+ int table_size = arraylength(ramp);
+
+ if ((f < 0.0 || f > 1.0) && extrapolate) {
+ color t0, dy;
+ if (f < 0.0) {
+ t0 = ramp[0];
+ dy = t0 - ramp[1];
+ f = -f;
+ }
+ else {
+ t0 = ramp[table_size - 1];
+ dy = t0 - ramp[table_size - 2];
+ f = f - 1.0;
+ }
+ return t0 + dy * f * (table_size - 1);
+ }
+
+ f = clamp(at, 0.0, 1.0) * (table_size - 1);
+
+ /* clamp int as well in case of NaN */
+ int i = (int)f;
+ if (i < 0) i = 0;
+ if (i >= table_size) i = table_size - 1;
+ float t = f - (float)i;
+
+ color result = ramp[i];
+
+ if (interpolate && t > 0.0)
+ result = (1.0 - t) * result + t * ramp[i + 1];
+
+ return result;
+}
+
+float rgb_ramp_lookup(float ramp[], float at, int interpolate, int extrapolate)
+{
+ float f = at;
+ int table_size = arraylength(ramp);
+
+ if ((f < 0.0 || f > 1.0) && extrapolate) {
+ float t0, dy;
+ if (f < 0.0) {
+ t0 = ramp[0];
+ dy = t0 - ramp[1];
+ f = -f;
+ }
+ else {
+ t0 = ramp[table_size - 1];
+ dy = t0 - ramp[table_size - 2];
+ f = f - 1.0;
+ }
+ return t0 + dy * f * (table_size - 1);
+ }
+
+ f = clamp(at, 0.0, 1.0) * (table_size - 1);
+
+ /* clamp int as well in case of NaN */
+ int i = (int)f;
+ if (i < 0) i = 0;
+ if (i >= table_size) i = table_size - 1;
+ float t = f - (float)i;
+
+ float result = ramp[i];
+
+ if (interpolate && t > 0.0)
+ result = (1.0 - t) * result + t * ramp[i + 1];
+
+ return result;
+}
diff --git a/intern/cycles/kernel/shaders/node_refraction_bsdf.osl b/intern/cycles/kernel/shaders/node_refraction_bsdf.osl
index d458ca730a4..828becf1818 100644
--- a/intern/cycles/kernel/shaders/node_refraction_bsdf.osl
+++ b/intern/cycles/kernel/shaders/node_refraction_bsdf.osl
@@ -18,7 +18,7 @@
shader node_refraction_bsdf(
color Color = 0.8,
- string distribution = "Sharp",
+ string distribution = "sharp",
float Roughness = 0.2,
float IOR = 1.45,
normal Normal = N,
@@ -27,9 +27,9 @@ shader node_refraction_bsdf(
float f = max(IOR, 1e-5);
float eta = backfacing() ? 1.0 / f : f;
- if (distribution == "Sharp")
+ if (distribution == "sharp")
BSDF = Color * refraction(Normal, eta);
- else if (distribution == "Beckmann")
+ else if (distribution == "beckmann")
BSDF = Color * microfacet_beckmann_refraction(Normal, Roughness, eta);
else if (distribution == "GGX")
BSDF = Color * microfacet_ggx_refraction(Normal, Roughness, eta);
diff --git a/intern/cycles/kernel/shaders/node_rgb_curves.osl b/intern/cycles/kernel/shaders/node_rgb_curves.osl
index fc93dbd044b..0d5eeea5c43 100644
--- a/intern/cycles/kernel/shaders/node_rgb_curves.osl
+++ b/intern/cycles/kernel/shaders/node_rgb_curves.osl
@@ -15,43 +15,10 @@
*/
#include "stdosl.h"
-#include "oslutil.h"
-
-float ramp_lookup(color ramp[RAMP_TABLE_SIZE], float at, int component)
-{
- if (at < 0.0 || at > 1.0) {
- float t0, dy;
- if (at < 0.0) {
- t0 = ramp[0][component];
- dy = t0 - ramp[1][component];
- at = -at;
- }
- else {
- t0 = ramp[RAMP_TABLE_SIZE - 1][component];
- dy = t0 - ramp[RAMP_TABLE_SIZE - 2][component];
- at = at - 1.0;
- }
- return t0 + dy * at * (RAMP_TABLE_SIZE - 1);
- }
-
- float f = clamp(at, 0.0, 1.0) * (RAMP_TABLE_SIZE - 1);
-
- /* clamp int as well in case of NaN */
- int i = (int)f;
- if (i < 0) i = 0;
- if (i >= RAMP_TABLE_SIZE) i = RAMP_TABLE_SIZE - 1;
- float t = f - (float)i;
-
- float result = ramp[i][component];
-
- if (t > 0.0)
- result = (1.0 - t) * result + t * ramp[i + 1][component];
-
- return result;
-}
+#include "node_ramp_util.h"
shader node_rgb_curves(
- color ramp[RAMP_TABLE_SIZE] = {0.0},
+ color ramp[] = {0.0},
float min_x = 0.0,
float max_x = 1.0,
@@ -61,9 +28,13 @@ shader node_rgb_curves(
{
color c = (ColorIn - color(min_x, min_x, min_x)) / (max_x - min_x);
- ColorOut[0] = ramp_lookup(ramp, c[0], 0);
- ColorOut[1] = ramp_lookup(ramp, c[1], 1);
- ColorOut[2] = ramp_lookup(ramp, c[2], 2);
+ color r = rgb_ramp_lookup(ramp, c[0], 1, 1);
+ color g = rgb_ramp_lookup(ramp, c[1], 1, 1);
+ color b = rgb_ramp_lookup(ramp, c[2], 1, 1);
+
+ ColorOut[0] = r[0];
+ ColorOut[1] = g[1];
+ ColorOut[2] = b[2];
ColorOut = mix(ColorIn, ColorOut, Fac);
}
diff --git a/intern/cycles/kernel/shaders/node_rgb_ramp.osl b/intern/cycles/kernel/shaders/node_rgb_ramp.osl
index 0202ba0bf79..4e7d8fdcf65 100644
--- a/intern/cycles/kernel/shaders/node_rgb_ramp.osl
+++ b/intern/cycles/kernel/shaders/node_rgb_ramp.osl
@@ -15,31 +15,18 @@
*/
#include "stdosl.h"
-#include "oslutil.h"
+#include "node_ramp_util.h"
shader node_rgb_ramp(
- color ramp_color[RAMP_TABLE_SIZE] = {0.0},
- float ramp_alpha[RAMP_TABLE_SIZE] = {0.0},
- int ramp_interpolate = 1,
+ color ramp_color[] = {0.0},
+ float ramp_alpha[] = {0.0},
+ int interpolate = 1,
float Fac = 0.0,
output color Color = 0.0,
output float Alpha = 1.0)
{
- float f = clamp(Fac, 0.0, 1.0) * (RAMP_TABLE_SIZE - 1);
-
- /* clamp int as well in case of NaN */
- int i = (int)f;
- if (i < 0) i = 0;
- if (i >= RAMP_TABLE_SIZE) i = RAMP_TABLE_SIZE - 1;
- float t = f - (float)i;
-
- Color = ramp_color[i];
- Alpha = ramp_alpha[i];
-
- if (ramp_interpolate && t > 0.0) {
- Color = (1.0 - t) * Color + t * ramp_color[i + 1];
- Alpha = (1.0 - t) * Alpha + t * ramp_alpha[i + 1];
- }
+ Color = rgb_ramp_lookup(ramp_color, Fac, interpolate, 0);
+ Alpha = rgb_ramp_lookup(ramp_alpha, Fac, interpolate, 0);
}
diff --git a/intern/cycles/kernel/shaders/node_rgb_to_bw.osl b/intern/cycles/kernel/shaders/node_rgb_to_bw.osl
new file mode 100644
index 00000000000..903dfcdc881
--- /dev/null
+++ b/intern/cycles/kernel/shaders/node_rgb_to_bw.osl
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "stdosl.h"
+
+shader node_rgb_to_bw(
+ color Color = 0.0,
+ output float Val = 0.0)
+{
+ Val = Color[0] * 0.2126 + Color[1] * 0.7152 + Color[2] * 0.0722;
+}
+
diff --git a/intern/cycles/kernel/shaders/node_sky_texture.osl b/intern/cycles/kernel/shaders/node_sky_texture.osl
index 05eed23bea8..a6c187d15f2 100644
--- a/intern/cycles/kernel/shaders/node_sky_texture.osl
+++ b/intern/cycles/kernel/shaders/node_sky_texture.osl
@@ -111,7 +111,7 @@ shader node_sky_texture(
int use_mapping = 0,
matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
vector Vector = P,
- string sky_model = "Hosek / Wilkie",
+ string type = "hosek_wilkie",
float theta = 0.0,
float phi = 0.0,
color radiance = color(0.0, 0.0, 0.0),
@@ -125,7 +125,7 @@ shader node_sky_texture(
if (use_mapping)
p = transform(mapping, p);
- if (sky_model == "Hosek / Wilkie")
+ if (type == "hosek_wilkie")
Color = sky_radiance_new(p, phi, theta, radiance, config_x, config_y, config_z);
else
Color = sky_radiance_old(p, phi, theta, radiance, config_x, config_y, config_z);
diff --git a/intern/cycles/kernel/shaders/node_subsurface_scattering.osl b/intern/cycles/kernel/shaders/node_subsurface_scattering.osl
index a67333c5d4e..5ba8f34021d 100644
--- a/intern/cycles/kernel/shaders/node_subsurface_scattering.osl
+++ b/intern/cycles/kernel/shaders/node_subsurface_scattering.osl
@@ -22,13 +22,13 @@ shader node_subsurface_scattering(
vector Radius = vector(0.1, 0.1, 0.1),
float TextureBlur = 0.0,
float Sharpness = 0.0,
- string Falloff = "Cubic",
+ string falloff = "cubic",
normal Normal = N,
output closure color BSSRDF = 0)
{
- if (Falloff == "Gaussian")
+ if (falloff == "gaussian")
BSSRDF = Color * bssrdf_gaussian(Normal, Scale * Radius, TextureBlur);
- else if (Falloff == "Cubic")
+ else if (falloff == "cubic")
BSSRDF = Color * bssrdf_cubic(Normal, Scale * Radius, TextureBlur, Sharpness);
else
BSSRDF = Color * bssrdf_burley(Normal, Scale * Radius, TextureBlur, Color);
diff --git a/intern/cycles/kernel/shaders/node_tangent.osl b/intern/cycles/kernel/shaders/node_tangent.osl
index 53a47396f9f..c527070a2c8 100644
--- a/intern/cycles/kernel/shaders/node_tangent.osl
+++ b/intern/cycles/kernel/shaders/node_tangent.osl
@@ -19,24 +19,24 @@
shader node_tangent(
normal NormalIn = N,
string attr_name = "geom:tangent",
- string direction_type = "Radial",
- string axis = "Z",
+ string direction_type = "radial",
+ string axis = "z",
output normal Tangent = normalize(dPdu))
{
vector T;
- if (direction_type == "UV Map") {
+ if (direction_type == "uv_map") {
getattribute(attr_name, T);
}
- else if (direction_type == "Radial") {
+ else if (direction_type == "radial") {
point generated;
if (!getattribute("geom:generated", generated))
generated = P;
- if (axis == "X")
+ if (axis == "x")
T = vector(0.0, -(generated[2] - 0.5), (generated[1] - 0.5));
- else if (axis == "Y")
+ else if (axis == "y")
T = vector(-(generated[2] - 0.5), 0.0, (generated[0] - 0.5));
else
T = vector(-(generated[1] - 0.5), (generated[0] - 0.5), 0.0);
diff --git a/intern/cycles/kernel/shaders/node_toon_bsdf.osl b/intern/cycles/kernel/shaders/node_toon_bsdf.osl
index 75c5d06f847..ae68a463e46 100644
--- a/intern/cycles/kernel/shaders/node_toon_bsdf.osl
+++ b/intern/cycles/kernel/shaders/node_toon_bsdf.osl
@@ -18,15 +18,15 @@
shader node_toon_bsdf(
color Color = 0.8,
- string component = "Diffuse",
+ string component = "diffuse",
float Size = 0.5,
float Smooth = 0.0,
normal Normal = N,
output closure color BSDF = 0)
{
- if (component == "Diffuse")
+ if (component == "diffuse")
BSDF = Color * diffuse_toon(Normal, Size, Smooth);
- else if (component == "Glossy")
+ else if (component == "glossy")
BSDF = Color * glossy_toon(Normal, Size, Smooth);
}
diff --git a/intern/cycles/kernel/shaders/node_uv_map.osl b/intern/cycles/kernel/shaders/node_uv_map.osl
index 77e2e8d12d7..b46b2e73457 100644
--- a/intern/cycles/kernel/shaders/node_uv_map.osl
+++ b/intern/cycles/kernel/shaders/node_uv_map.osl
@@ -18,7 +18,7 @@
shader node_uv_map(
int from_dupli = 0,
- string name = "",
+ string attribute = "",
string bump_offset = "center",
output point UV = point(0.0, 0.0, 0.0))
{
@@ -26,10 +26,10 @@ shader node_uv_map(
getattribute("geom:dupli_uv", UV);
}
else {
- if (name == "")
+ if (attribute == "")
getattribute("geom:uv", UV);
else
- getattribute(name, UV);
+ getattribute(attribute, UV);
}
if (bump_offset == "dx") {
diff --git a/intern/cycles/kernel/shaders/node_vector_curves.osl b/intern/cycles/kernel/shaders/node_vector_curves.osl
index 4d4c28b57a2..ff284c48e0a 100644
--- a/intern/cycles/kernel/shaders/node_vector_curves.osl
+++ b/intern/cycles/kernel/shaders/node_vector_curves.osl
@@ -15,43 +15,10 @@
*/
#include "stdosl.h"
-#include "oslutil.h"
-
-float ramp_lookup(color ramp[RAMP_TABLE_SIZE], float at, int component)
-{
- if (at < 0.0 || at > 1.0) {
- float t0, dy;
- if (at < 0.0) {
- t0 = ramp[0][component];
- dy = t0 - ramp[1][component];
- at = -at;
- }
- else {
- t0 = ramp[RAMP_TABLE_SIZE - 1][component];
- dy = t0 - ramp[RAMP_TABLE_SIZE - 2][component];
- at = at - 1.0;
- }
- return t0 + dy * at * (RAMP_TABLE_SIZE - 1);
- }
-
- float f = clamp(at, 0.0, 1.0) * (RAMP_TABLE_SIZE - 1);
-
- /* clamp int as well in case of NaN */
- int i = (int)f;
- if (i < 0) i = 0;
- if (i >= RAMP_TABLE_SIZE) i = RAMP_TABLE_SIZE - 1;
- float t = f - (float)i;
-
- float result = ramp[i][component];
-
- if (t > 0.0)
- result = (1.0 - t) * result + t * ramp[i + 1][component];
-
- return result;
-}
+#include "node_ramp_util.h"
shader node_vector_curves(
- color ramp[RAMP_TABLE_SIZE] = {0.0},
+ color ramp[] = {0.0},
float min_x = 0.0,
float max_x = 1.0,
@@ -61,9 +28,13 @@ shader node_vector_curves(
{
vector c = (VectorIn - vector(min_x, min_x, min_x)) / (max_x - min_x);
- VectorOut[0] = ramp_lookup(ramp, c[0], 0);
- VectorOut[1] = ramp_lookup(ramp, c[1], 1);
- VectorOut[2] = ramp_lookup(ramp, c[2], 2);
+ color r = rgb_ramp_lookup(ramp, c[0], 1, 1);
+ color g = rgb_ramp_lookup(ramp, c[0], 1, 1);
+ color b = rgb_ramp_lookup(ramp, c[0], 1, 1);
+
+ VectorOut[0] = r[0];
+ VectorOut[1] = g[1];
+ VectorOut[2] = b[2];
VectorOut = mix(VectorIn, VectorOut, Fac);
}
diff --git a/intern/cycles/kernel/shaders/node_vector_math.osl b/intern/cycles/kernel/shaders/node_vector_math.osl
index f83412dc0f7..a7e3637402e 100644
--- a/intern/cycles/kernel/shaders/node_vector_math.osl
+++ b/intern/cycles/kernel/shaders/node_vector_math.osl
@@ -17,33 +17,33 @@
#include "stdosl.h"
shader node_vector_math(
- string type = "Add",
+ string type = "add",
vector Vector1 = vector(0.0, 0.0, 0.0),
vector Vector2 = vector(0.0, 0.0, 0.0),
output float Value = 0.0,
output vector Vector = vector(0.0, 0.0, 0.0))
{
- if (type == "Add") {
+ if (type == "add") {
Vector = Vector1 + Vector2;
Value = (abs(Vector[0]) + abs(Vector[1]) + abs(Vector[2])) / 3.0;
}
- else if (type == "Subtract") {
+ else if (type == "subtract") {
Vector = Vector1 - Vector2;
Value = (abs(Vector[0]) + abs(Vector[1]) + abs(Vector[2])) / 3.0;
}
- else if (type == "Average") {
+ else if (type == "average") {
Value = length(Vector1 + Vector2);
Vector = normalize(Vector1 + Vector2);
}
- else if (type == "Dot Product") {
+ else if (type == "dot_product") {
Value = dot(Vector1, Vector2);
}
- else if (type == "Cross Product") {
+ else if (type == "cross_product") {
vector c = cross(Vector1, Vector2);
Value = length(c);
Vector = normalize(c);
}
- else if (type == "Normalize") {
+ else if (type == "normalize") {
Value = length(Vector1);
Vector = normalize(Vector1);
}
diff --git a/intern/cycles/kernel/shaders/node_vector_transform.osl b/intern/cycles/kernel/shaders/node_vector_transform.osl
index 8ebaa31ab25..afb95b340d1 100644
--- a/intern/cycles/kernel/shaders/node_vector_transform.osl
+++ b/intern/cycles/kernel/shaders/node_vector_transform.osl
@@ -17,18 +17,18 @@
#include "stdosl.h"
shader node_vector_transform(
- string type = "Vector",
+ string type = "vector",
string convert_from = "world",
string convert_to = "object",
vector VectorIn = vector(0.0, 0.0, 0.0),
output vector VectorOut = vector(0.0, 0.0, 0.0))
{
- if (type == "Vector" || type == "Normal") {
+ if (type == "vector" || type == "normal") {
VectorOut = transform(convert_from, convert_to, VectorIn);
- if (type == "Normal")
+ if (type == "normal")
VectorOut = normalize(VectorOut);
}
- else if (type == "Point") {
+ else if (type == "point") {
point Point = (point)VectorIn;
VectorOut = transform(convert_from, convert_to, Point);
}
diff --git a/intern/cycles/kernel/shaders/node_voronoi_texture.osl b/intern/cycles/kernel/shaders/node_voronoi_texture.osl
index 29e143ae207..0c3b95ae4d0 100644
--- a/intern/cycles/kernel/shaders/node_voronoi_texture.osl
+++ b/intern/cycles/kernel/shaders/node_voronoi_texture.osl
@@ -22,7 +22,7 @@
shader node_voronoi_texture(
int use_mapping = 0,
matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
- string Coloring = "Intensity",
+ string coloring = "intensity",
float Scale = 5.0,
point Vector = P,
output float Fac = 0.0,
@@ -40,7 +40,7 @@ shader node_voronoi_texture(
voronoi(p * Scale, 1.0, da, pa);
/* Colored output */
- if (Coloring == "Intensity") {
+ if (coloring == "intensity") {
Fac = fabs(da[0]);
Color = color(Fac);
}
diff --git a/intern/cycles/kernel/shaders/node_wave_texture.osl b/intern/cycles/kernel/shaders/node_wave_texture.osl
index 59f61d3b46a..71bc9324705 100644
--- a/intern/cycles/kernel/shaders/node_wave_texture.osl
+++ b/intern/cycles/kernel/shaders/node_wave_texture.osl
@@ -23,10 +23,10 @@ float wave(point p, string type, string profile, float detail, float distortion,
{
float n = 0.0;
- if (type == "Bands") {
+ if (type == "bands") {
n = (p[0] + p[1] + p[2]) * 10.0;
}
- else if (type == "Rings") {
+ else if (type == "rings") {
n = length(p) * 20.0;
}
@@ -34,7 +34,7 @@ float wave(point p, string type, string profile, float detail, float distortion,
n = n + (distortion * noise_turbulence(p * dscale, detail, 0));
}
- if (profile == "Sine") {
+ if (profile == "sine") {
return 0.5 + 0.5 * sin(n);
}
else {
@@ -48,8 +48,8 @@ float wave(point p, string type, string profile, float detail, float distortion,
shader node_wave_texture(
int use_mapping = 0,
matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
- string Type = "Bands",
- string Profile = "Sine",
+ string type = "bands",
+ string profile = "sine",
float Scale = 5.0,
float Distortion = 0.0,
float Detail = 2.0,
@@ -63,7 +63,7 @@ shader node_wave_texture(
if (use_mapping)
p = transform(mapping, p);
- Fac = wave(p * Scale, Type, Profile, Detail, Distortion, DetailScale);
+ Fac = wave(p * Scale, type, profile, Detail, Distortion, DetailScale);
Color = Fac;
}
diff --git a/intern/cycles/kernel/shaders/oslutil.h b/intern/cycles/kernel/shaders/oslutil.h
index d90900bc474..141e5d27e3a 100644
--- a/intern/cycles/kernel/shaders/oslutil.h
+++ b/intern/cycles/kernel/shaders/oslutil.h
@@ -33,9 +33,6 @@
#ifndef CCL_OSLUTIL_H
#define CCL_OSLUTIL_H
-/* NB: must match the value in kernel_types.h */
-#define RAMP_TABLE_SIZE 256
-
// Return wireframe opacity factor [0, 1] given a geometry type in
// ("triangles", "polygons" or "patches"), and a line_width in raster
// or world space depending on the last (raster) boolean argument.
diff --git a/intern/cycles/kernel/shaders/stdosl.h b/intern/cycles/kernel/shaders/stdosl.h
index 8d5d3746caf..a8dda8a12c9 100644
--- a/intern/cycles/kernel/shaders/stdosl.h
+++ b/intern/cycles/kernel/shaders/stdosl.h
@@ -527,6 +527,9 @@ closure color transparent() BUILTIN;
closure color microfacet_ggx(normal N, float ag) BUILTIN;
closure color microfacet_ggx_aniso(normal N, vector T, float ax, float ay) BUILTIN;
closure color microfacet_ggx_refraction(normal N, float ag, float eta) BUILTIN;
+closure color microfacet_multi_ggx(normal N, float ag, color C) BUILTIN;
+closure color microfacet_multi_ggx_aniso(normal N, vector T, float ax, float ay, color C) BUILTIN;
+closure color microfacet_multi_ggx_glass(normal N, float ag, float eta, color C) BUILTIN;
closure color microfacet_beckmann(normal N, float ab) BUILTIN;
closure color microfacet_beckmann_aniso(normal N, vector T, float ax, float ay) BUILTIN;
closure color microfacet_beckmann_refraction(normal N, float ab, float eta) BUILTIN;
diff --git a/intern/cycles/kernel/split/kernel_background_buffer_update.h b/intern/cycles/kernel/split/kernel_background_buffer_update.h
index 3d12a3dd993..9bfa71c75ef 100644
--- a/intern/cycles/kernel/split/kernel_background_buffer_update.h
+++ b/intern/cycles/kernel/split/kernel_background_buffer_update.h
@@ -157,7 +157,7 @@ ccl_device char kernel_background_buffer_update(
if(IS_STATE(ray_state, ray_index, RAY_HIT_BACKGROUND)) {
#ifdef __BACKGROUND__
/* sample background shader */
- float3 L_background = indirect_background(kg, state, ray);
+ float3 L_background = indirect_background(kg, kg->sd_input, state, ray);
path_radiance_accum_background(L, (*throughput), L_background, state->bounce);
#endif
ASSIGN_RAY_STATE(ray_state, ray_index, RAY_UPDATE_BUFFER);
@@ -226,13 +226,14 @@ ccl_device char kernel_background_buffer_update(
*throughput = make_float3(1.0f, 1.0f, 1.0f);
*L_transparent = 0.0f;
path_radiance_init(L, kernel_data.film.use_light_pass);
- path_state_init(kg, state, rng, sample, ray);
+ path_state_init(kg, kg->sd_input, state, rng, sample, ray);
#ifdef __KERNEL_DEBUG__
debug_data_init(debug_data);
#endif
ASSIGN_RAY_STATE(ray_state, ray_index, RAY_REGENERATED);
enqueue_flag = 1;
- } else {
+ }
+ else {
/* These rays do not participate in path-iteration. */
float4 L_rad = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
/* Accumulate result in output buffer. */
diff --git a/intern/cycles/kernel/split/kernel_data_init.h b/intern/cycles/kernel/split/kernel_data_init.h
index 9891391a3a3..6e158d53d23 100644
--- a/intern/cycles/kernel/split/kernel_data_init.h
+++ b/intern/cycles/kernel/split/kernel_data_init.h
@@ -207,6 +207,7 @@ ccl_device void kernel_data_init(
L_transparent_coop[ray_index] = 0.0f;
path_radiance_init(&PathRadiance_coop[ray_index], kernel_data.film.use_light_pass);
path_state_init(kg,
+ kg->sd_input,
&PathState_coop[ray_index],
&rng_coop[ray_index],
my_sample,
@@ -214,7 +215,8 @@ ccl_device void kernel_data_init(
#ifdef __KERNEL_DEBUG__
debug_data_init(&debugdata_coop[ray_index]);
#endif
- } else {
+ }
+ else {
/* These rays do not participate in path-iteration. */
float4 L_rad = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
/* Accumulate result in output buffer. */
diff --git a/intern/cycles/kernel/split/kernel_direct_lighting.h b/intern/cycles/kernel/split/kernel_direct_lighting.h
index c7a2aa6426c..6ad736fc2c1 100644
--- a/intern/cycles/kernel/split/kernel_direct_lighting.h
+++ b/intern/cycles/kernel/split/kernel_direct_lighting.h
@@ -74,30 +74,31 @@ ccl_device char kernel_direct_lighting(
path_state_rng_2D(kg, rng, state, PRNG_LIGHT_U, &light_u, &light_v);
LightSample ls;
- light_sample(kg,
- light_t, light_u, light_v,
- ccl_fetch(sd, time),
- ccl_fetch(sd, P),
- state->bounce,
- &ls);
+ if(light_sample(kg,
+ light_t, light_u, light_v,
+ ccl_fetch(sd, time),
+ ccl_fetch(sd, P),
+ state->bounce,
+ &ls)) {
- Ray light_ray;
+ Ray light_ray;
#ifdef __OBJECT_MOTION__
- light_ray.time = ccl_fetch(sd, time);
+ light_ray.time = ccl_fetch(sd, time);
#endif
- BsdfEval L_light;
- bool is_lamp;
- if(direct_emission(kg, sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
- /* Write intermediate data to global memory to access from
- * the next kernel.
- */
- LightRay_coop[ray_index] = light_ray;
- BSDFEval_coop[ray_index] = L_light;
- ISLamp_coop[ray_index] = is_lamp;
- /* Mark ray state for next shadow kernel. */
- ADD_RAY_FLAG(ray_state, ray_index, RAY_SHADOW_RAY_CAST_DL);
- enqueue_flag = 1;
+ BsdfEval L_light;
+ bool is_lamp;
+ if(direct_emission(kg, sd, kg->sd_input, &ls, state, &light_ray, &L_light, &is_lamp)) {
+ /* Write intermediate data to global memory to access from
+ * the next kernel.
+ */
+ LightRay_coop[ray_index] = light_ray;
+ BSDFEval_coop[ray_index] = L_light;
+ ISLamp_coop[ray_index] = is_lamp;
+ /* Mark ray state for next shadow kernel. */
+ ADD_RAY_FLAG(ray_state, ray_index, RAY_SHADOW_RAY_CAST_DL);
+ enqueue_flag = 1;
+ }
}
}
#endif /* __EMISSION__ */
diff --git a/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h b/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h
index 78dada82d89..435d1171d5c 100644
--- a/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h
+++ b/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h
@@ -212,7 +212,8 @@ ccl_device void kernel_holdout_emission_blurring_pathtermination_ao(
if(terminate >= probability) {
ASSIGN_RAY_STATE(ray_state, ray_index, RAY_UPDATE_BUFFER);
*enqueue_flag = 1;
- } else {
+ }
+ else {
throughput_coop[ray_index] = throughput/probability;
}
}
diff --git a/intern/cycles/kernel/split/kernel_lamp_emission.h b/intern/cycles/kernel/split/kernel_lamp_emission.h
index dc3b4b34d4e..3bd0e361078 100644
--- a/intern/cycles/kernel/split/kernel_lamp_emission.h
+++ b/intern/cycles/kernel/split/kernel_lamp_emission.h
@@ -74,7 +74,7 @@ ccl_device void kernel_lamp_emission(
/* intersect with lamp */
float3 emission;
- if(indirect_lamp_emission(kg, state, &light_ray, &emission)) {
+ if(indirect_lamp_emission(kg, kg->sd_input, state, &light_ray, &emission)) {
path_radiance_accum_emission(L, throughput, emission, state->bounce);
}
}
diff --git a/intern/cycles/kernel/split/kernel_next_iteration_setup.h b/intern/cycles/kernel/split/kernel_next_iteration_setup.h
index 74da80b52cc..816f3a6fbff 100644
--- a/intern/cycles/kernel/split/kernel_next_iteration_setup.h
+++ b/intern/cycles/kernel/split/kernel_next_iteration_setup.h
@@ -126,7 +126,7 @@ ccl_device char kernel_next_iteration_setup(
if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) {
ccl_global float3 *throughput = &throughput_coop[ray_index];
ccl_global Ray *ray = &Ray_coop[ray_index];
- ccl_global RNG* rng = &rng_coop[ray_index];
+ ccl_global RNG *rng = &rng_coop[ray_index];
state = &PathState_coop[ray_index];
L = &PathRadiance_coop[ray_index];
diff --git a/intern/cycles/kernel/split/kernel_scene_intersect.h b/intern/cycles/kernel/split/kernel_scene_intersect.h
index faa752c360e..fc4b4ee38e5 100644
--- a/intern/cycles/kernel/split/kernel_scene_intersect.h
+++ b/intern/cycles/kernel/split/kernel_scene_intersect.h
@@ -109,9 +109,9 @@ ccl_device void kernel_scene_intersect(
lcg_state = lcg_state_init(&rng, &state, 0x51633e2d);
}
- bool hit = scene_intersect(kg, &ray, visibility, isect, &lcg_state, difl, extmax);
+ bool hit = scene_intersect(kg, ray, visibility, isect, &lcg_state, difl, extmax);
#else
- bool hit = scene_intersect(kg, &ray, visibility, isect, NULL, 0.0f, 0.0f);
+ bool hit = scene_intersect(kg, ray, visibility, isect, NULL, 0.0f, 0.0f);
#endif
#ifdef __KERNEL_DEBUG__
diff --git a/intern/cycles/kernel/split/kernel_shader_eval.h b/intern/cycles/kernel/split/kernel_shader_eval.h
index e816a818915..cef64bf5f36 100644
--- a/intern/cycles/kernel/split/kernel_shader_eval.h
+++ b/intern/cycles/kernel/split/kernel_shader_eval.h
@@ -65,6 +65,6 @@ ccl_device void kernel_shader_eval(
isect,
&ray);
float rbsdf = path_state_rng_1D_for_decision(kg, rng, state, PRNG_BSDF);
- shader_eval_surface(kg, sd, state, rbsdf, state->flag, SHADER_CONTEXT_MAIN);
+ shader_eval_surface(kg, sd, rng, state, rbsdf, state->flag, SHADER_CONTEXT_MAIN);
}
}
diff --git a/intern/cycles/kernel/split/kernel_shadow_blocked.h b/intern/cycles/kernel/split/kernel_shadow_blocked.h
index 0c989861eef..6153af47f96 100644
--- a/intern/cycles/kernel/split/kernel_shadow_blocked.h
+++ b/intern/cycles/kernel/split/kernel_shadow_blocked.h
@@ -71,6 +71,7 @@ ccl_device void kernel_shadow_blocked(
float3 shadow;
update_path_radiance = !(shadow_blocked(kg,
+ kg->sd_input,
state,
light_ray_global,
&shadow));
diff --git a/intern/cycles/kernel/split/kernel_split_common.h b/intern/cycles/kernel/split/kernel_split_common.h
index e1c7e2cea99..2135ee22b2e 100644
--- a/intern/cycles/kernel/split/kernel_split_common.h
+++ b/intern/cycles/kernel/split/kernel_split_common.h
@@ -21,6 +21,7 @@
#include "kernel_math.h"
#include "kernel_types.h"
#include "kernel_globals.h"
+#include "kernel_image_opencl.h"
#include "util_atomic.h"
@@ -31,6 +32,7 @@
#include "kernel_camera.h"
#include "geom/geom.h"
+#include "bvh/bvh.h"
#include "kernel_accumulate.h"
#include "kernel_shader.h"
diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h
index 416912d4a21..f7ce0c8e0e3 100644
--- a/intern/cycles/kernel/svm/svm.h
+++ b/intern/cycles/kernel/svm/svm.h
@@ -142,6 +142,7 @@ CCL_NAMESPACE_END
#include "svm_noise.h"
#include "svm_texture.h"
+#include "svm_color_util.h"
#include "svm_math_util.h"
#include "svm_attribute.h"
@@ -181,6 +182,7 @@ CCL_NAMESPACE_END
#include "svm_brick.h"
#include "svm_vector_transform.h"
#include "svm_voxel.h"
+#include "svm_bump.h"
CCL_NAMESPACE_BEGIN
@@ -260,7 +262,7 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ccl_a
svm_node_geometry_bump_dy(kg, sd, stack, node.y, node.z);
break;
case NODE_SET_DISPLACEMENT:
- svm_node_set_displacement(sd, stack, node.y);
+ svm_node_set_displacement(kg, sd, stack, node.y);
break;
# endif /* NODES_FEATURE(NODE_FEATURE_BUMP) */
# ifdef __TEXTURES__
@@ -294,6 +296,14 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ccl_a
case NODE_CLOSURE_SET_NORMAL:
svm_node_set_normal(kg, sd, stack, node.y, node.z);
break;
+# if NODES_FEATURE(NODE_FEATURE_BUMP_STATE)
+ case NODE_ENTER_BUMP_EVAL:
+ svm_node_enter_bump_eval(kg, sd, stack, node.y);
+ break;
+ case NODE_LEAVE_BUMP_EVAL:
+ svm_node_leave_bump_eval(kg, sd, stack, node.y);
+ break;
+# endif /* NODES_FEATURE(NODE_FEATURE_BUMP_STATE) */
# endif /* NODES_FEATURE(NODE_FEATURE_BUMP) */
case NODE_HSV:
svm_node_hsv(kg, sd, stack, node, &offset);
@@ -405,10 +415,8 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ccl_a
#if NODES_GROUP(NODE_GROUP_LEVEL_3)
case NODE_RGB_CURVES:
- svm_node_rgb_curves(kg, sd, stack, node, &offset);
- break;
case NODE_VECTOR_CURVES:
- svm_node_vector_curves(kg, sd, stack, node, &offset);
+ svm_node_curves(kg, sd, stack, node, &offset);
break;
case NODE_TANGENT:
svm_node_tangent(kg, sd, stack, node);
diff --git a/intern/cycles/kernel/svm/svm_attribute.h b/intern/cycles/kernel/svm/svm_attribute.h
index 63bbb27d873..0e55c99ae97 100644
--- a/intern/cycles/kernel/svm/svm_attribute.h
+++ b/intern/cycles/kernel/svm/svm_attribute.h
@@ -18,144 +18,136 @@ CCL_NAMESPACE_BEGIN
/* Attribute Node */
-ccl_device void svm_node_attr_init(KernelGlobals *kg, ShaderData *sd,
+ccl_device AttributeDescriptor svm_node_attr_init(KernelGlobals *kg, ShaderData *sd,
uint4 node, NodeAttributeType *type,
- NodeAttributeType *mesh_type, AttributeElement *elem, int *offset, uint *out_offset)
+ uint *out_offset)
{
*out_offset = node.z;
*type = (NodeAttributeType)node.w;
+
+ AttributeDescriptor desc;
+
if(ccl_fetch(sd, object) != OBJECT_NONE) {
- /* find attribute by unique id */
- uint id = node.y;
- uint attr_offset = ccl_fetch(sd, object)*kernel_data.bvh.attributes_map_stride;
-#ifdef __HAIR__
- attr_offset = (ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE)? attr_offset + ATTR_PRIM_CURVE: attr_offset;
-#endif
- uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
-
- while(attr_map.x != id) {
- if(UNLIKELY(attr_map.x == ATTR_STD_NONE)) {
- *elem = ATTR_ELEMENT_NONE;
- *offset = 0;
- *mesh_type = (NodeAttributeType)node.w;
- return;
- }
- attr_offset += ATTR_PRIM_TYPES;
- attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
+ desc = find_attribute(kg, sd, node.y);
+ if(desc.offset == ATTR_STD_NOT_FOUND) {
+ desc = attribute_not_found();
+ desc.offset = 0;
+ desc.type = (NodeAttributeType)node.w;
}
-
- /* return result */
- *elem = (AttributeElement)attr_map.y;
- *offset = as_int(attr_map.z);
- *mesh_type = (NodeAttributeType)attr_map.w;
}
else {
/* background */
- *elem = ATTR_ELEMENT_NONE;
- *offset = 0;
- *mesh_type = (NodeAttributeType)node.w;
+ desc = attribute_not_found();
+ desc.offset = 0;
+ desc.type = (NodeAttributeType)node.w;
}
+
+ return desc;
}
ccl_device void svm_node_attr(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node)
{
- NodeAttributeType type, mesh_type;
- AttributeElement elem;
+ NodeAttributeType type;
uint out_offset;
- int offset;
-
- svm_node_attr_init(kg, sd, node, &type, &mesh_type, &elem, &offset, &out_offset);
+ AttributeDescriptor desc = svm_node_attr_init(kg, sd, node, &type, &out_offset);
/* fetch and store attribute */
if(type == NODE_ATTR_FLOAT) {
- if(mesh_type == NODE_ATTR_FLOAT) {
- float f = primitive_attribute_float(kg, sd, elem, offset, NULL, NULL);
+ if(desc.type == NODE_ATTR_FLOAT) {
+ float f = primitive_attribute_float(kg, sd, desc, NULL, NULL);
stack_store_float(stack, out_offset, f);
}
else {
- float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, NULL);
+ float3 f = primitive_attribute_float3(kg, sd, desc, NULL, NULL);
stack_store_float(stack, out_offset, average(f));
}
}
else {
- if(mesh_type == NODE_ATTR_FLOAT3) {
- float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, NULL);
+ if(desc.type == NODE_ATTR_FLOAT3) {
+ float3 f = primitive_attribute_float3(kg, sd, desc, NULL, NULL);
stack_store_float3(stack, out_offset, f);
}
else {
- float f = primitive_attribute_float(kg, sd, elem, offset, NULL, NULL);
+ float f = primitive_attribute_float(kg, sd, desc, NULL, NULL);
stack_store_float3(stack, out_offset, make_float3(f, f, f));
}
}
}
-ccl_device void svm_node_attr_bump_dx(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node)
+#ifndef __KERNEL_CUDA__
+ccl_device
+#else
+ccl_device_noinline
+#endif
+void svm_node_attr_bump_dx(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node)
{
- NodeAttributeType type, mesh_type;
- AttributeElement elem;
+ NodeAttributeType type;
uint out_offset;
- int offset;
-
- svm_node_attr_init(kg, sd, node, &type, &mesh_type, &elem, &offset, &out_offset);
+ AttributeDescriptor desc = svm_node_attr_init(kg, sd, node, &type, &out_offset);
/* fetch and store attribute */
if(type == NODE_ATTR_FLOAT) {
- if(mesh_type == NODE_ATTR_FLOAT) {
+ if(desc.type == NODE_ATTR_FLOAT) {
float dx;
- float f = primitive_attribute_float(kg, sd, elem, offset, &dx, NULL);
+ float f = primitive_attribute_float(kg, sd, desc, &dx, NULL);
stack_store_float(stack, out_offset, f+dx);
}
else {
float3 dx;
- float3 f = primitive_attribute_float3(kg, sd, elem, offset, &dx, NULL);
+ float3 f = primitive_attribute_float3(kg, sd, desc, &dx, NULL);
stack_store_float(stack, out_offset, average(f+dx));
}
}
else {
- if(mesh_type == NODE_ATTR_FLOAT3) {
+ if(desc.type == NODE_ATTR_FLOAT3) {
float3 dx;
- float3 f = primitive_attribute_float3(kg, sd, elem, offset, &dx, NULL);
+ float3 f = primitive_attribute_float3(kg, sd, desc, &dx, NULL);
stack_store_float3(stack, out_offset, f+dx);
}
else {
float dx;
- float f = primitive_attribute_float(kg, sd, elem, offset, &dx, NULL);
+ float f = primitive_attribute_float(kg, sd, desc, &dx, NULL);
stack_store_float3(stack, out_offset, make_float3(f+dx, f+dx, f+dx));
}
}
}
-ccl_device void svm_node_attr_bump_dy(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node)
+#ifndef __KERNEL_CUDA__
+ccl_device
+#else
+ccl_device_noinline
+#endif
+void svm_node_attr_bump_dy(KernelGlobals *kg,
+ ShaderData *sd,
+ float *stack,
+ uint4 node)
{
- NodeAttributeType type, mesh_type;
- AttributeElement elem;
+ NodeAttributeType type;
uint out_offset;
- int offset;
-
- svm_node_attr_init(kg, sd, node, &type, &mesh_type, &elem, &offset, &out_offset);
+ AttributeDescriptor desc = svm_node_attr_init(kg, sd, node, &type, &out_offset);
/* fetch and store attribute */
if(type == NODE_ATTR_FLOAT) {
- if(mesh_type == NODE_ATTR_FLOAT) {
+ if(desc.type == NODE_ATTR_FLOAT) {
float dy;
- float f = primitive_attribute_float(kg, sd, elem, offset, NULL, &dy);
+ float f = primitive_attribute_float(kg, sd, desc, NULL, &dy);
stack_store_float(stack, out_offset, f+dy);
}
else {
float3 dy;
- float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, &dy);
+ float3 f = primitive_attribute_float3(kg, sd, desc, NULL, &dy);
stack_store_float(stack, out_offset, average(f+dy));
}
}
else {
- if(mesh_type == NODE_ATTR_FLOAT3) {
+ if(desc.type == NODE_ATTR_FLOAT3) {
float3 dy;
- float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, &dy);
+ float3 f = primitive_attribute_float3(kg, sd, desc, NULL, &dy);
stack_store_float3(stack, out_offset, f+dy);
}
else {
float dy;
- float f = primitive_attribute_float(kg, sd, elem, offset, NULL, &dy);
+ float f = primitive_attribute_float(kg, sd, desc, NULL, &dy);
stack_store_float3(stack, out_offset, make_float3(f+dy, f+dy, f+dy));
}
}
diff --git a/intern/cycles/kernel/svm/svm_brick.h b/intern/cycles/kernel/svm/svm_brick.h
index 9b0cf5ab8c4..47e1ba2ba6b 100644
--- a/intern/cycles/kernel/svm/svm_brick.h
+++ b/intern/cycles/kernel/svm/svm_brick.h
@@ -27,7 +27,7 @@ ccl_device_noinline float brick_noise(int n) /* fast integer noise */
return 0.5f * ((float)nn / 1073741824.0f);
}
-ccl_device_noinline float2 svm_brick(float3 p, float mortar_size, float bias,
+ccl_device_noinline float2 svm_brick(float3 p, float mortar_size, float mortar_smooth, float bias,
float brick_width, float row_height, float offset_amount, int offset_frequency,
float squash_amount, int squash_frequency)
{
@@ -47,30 +47,41 @@ ccl_device_noinline float2 svm_brick(float3 p, float mortar_size, float bias,
x = (p.x+offset) - brick_width*bricknum;
y = p.y - row_height*rownum;
- return make_float2(
- saturate((brick_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias)),
+ float tint = saturate((brick_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias));
+ float min_dist = min(min(x, y), min(brick_width - x, row_height - y));
- (x < mortar_size || y < mortar_size ||
- x > (brick_width - mortar_size) ||
- y > (row_height - mortar_size)) ? 1.0f : 0.0f);
+ float mortar;
+ if(min_dist >= mortar_size) {
+ mortar = 0.0f;
+ }
+ else if(mortar_smooth == 0.0f) {
+ mortar = 1.0f;
+ }
+ else {
+ min_dist = 1.0f - min_dist/mortar_size;
+ mortar = (min_dist < mortar_smooth)? smoothstepf(min_dist / mortar_smooth) : 1.0f;
+ }
+
+ return make_float2(tint, mortar);
}
ccl_device void svm_node_tex_brick(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset)
{
uint4 node2 = read_node(kg, offset);
uint4 node3 = read_node(kg, offset);
+ uint4 node4 = read_node(kg, offset);
/* Input and Output Sockets */
uint co_offset, color1_offset, color2_offset, mortar_offset, scale_offset;
uint mortar_size_offset, bias_offset, brick_width_offset, row_height_offset;
- uint color_offset, fac_offset;
+ uint color_offset, fac_offset, mortar_smooth_offset;
/* RNA properties */
uint offset_frequency, squash_frequency;
decode_node_uchar4(node.y, &co_offset, &color1_offset, &color2_offset, &mortar_offset);
decode_node_uchar4(node.z, &scale_offset, &mortar_size_offset, &bias_offset, &brick_width_offset);
- decode_node_uchar4(node.w, &row_height_offset, &color_offset, &fac_offset, NULL);
+ decode_node_uchar4(node.w, &row_height_offset, &color_offset, &fac_offset, &mortar_smooth_offset);
decode_node_uchar4(node2.x, &offset_frequency, &squash_frequency, NULL, NULL);
@@ -82,13 +93,14 @@ ccl_device void svm_node_tex_brick(KernelGlobals *kg, ShaderData *sd, float *sta
float scale = stack_load_float_default(stack, scale_offset, node2.y);
float mortar_size = stack_load_float_default(stack, mortar_size_offset, node2.z);
+ float mortar_smooth = stack_load_float_default(stack, mortar_smooth_offset, node4.x);
float bias = stack_load_float_default(stack, bias_offset, node2.w);
float brick_width = stack_load_float_default(stack, brick_width_offset, node3.x);
float row_height = stack_load_float_default(stack, row_height_offset, node3.y);
float offset_amount = __int_as_float(node3.z);
float squash_amount = __int_as_float(node3.w);
- float2 f2 = svm_brick(co*scale, mortar_size, bias, brick_width, row_height,
+ float2 f2 = svm_brick(co*scale, mortar_size, mortar_smooth, bias, brick_width, row_height,
offset_amount, offset_frequency, squash_amount, squash_frequency);
float tint = f2.x;
@@ -100,7 +112,7 @@ ccl_device void svm_node_tex_brick(KernelGlobals *kg, ShaderData *sd, float *sta
}
if(stack_valid(color_offset))
- stack_store_float3(stack, color_offset, (f == 1.0f)? mortar: color1);
+ stack_store_float3(stack, color_offset, lerp(color1, mortar, f));
if(stack_valid(fac_offset))
stack_store_float(stack, fac_offset, f);
}
diff --git a/intern/cycles/kernel/svm/svm_brightness.h b/intern/cycles/kernel/svm/svm_brightness.h
index e4d545a00ae..d71b0ee0b61 100644
--- a/intern/cycles/kernel/svm/svm_brightness.h
+++ b/intern/cycles/kernel/svm/svm_brightness.h
@@ -25,12 +25,7 @@ ccl_device void svm_node_brightness(ShaderData *sd, float *stack, uint in_color,
float brightness = stack_load_float(stack, bright_offset);
float contrast = stack_load_float(stack, contrast_offset);
- float a = 1.0f + contrast;
- float b = brightness - contrast*0.5f;
-
- color.x = max(a*color.x + b, 0.0f);
- color.y = max(a*color.y + b, 0.0f);
- color.z = max(a*color.z + b, 0.0f);
+ color = svm_brightness_contrast(color, brightness, contrast);
if(stack_valid(out_color))
stack_store_float3(stack, out_color, color);
diff --git a/intern/cycles/kernel/svm/svm_bump.h b/intern/cycles/kernel/svm/svm_bump.h
new file mode 100644
index 00000000000..04a8c7b64e5
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_bump.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* Bump Eval Nodes */
+
+ccl_device void svm_node_enter_bump_eval(KernelGlobals *kg, ShaderData *sd, float *stack, uint offset)
+{
+ /* save state */
+ stack_store_float3(stack, offset+0, ccl_fetch(sd, P));
+ stack_store_float3(stack, offset+3, ccl_fetch(sd, dP).dx);
+ stack_store_float3(stack, offset+6, ccl_fetch(sd, dP).dy);
+
+ /* set state as if undisplaced */
+ const AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_POSITION_UNDISPLACED);
+
+ if(desc.offset != ATTR_STD_NOT_FOUND) {
+ float3 P, dPdx, dPdy;
+ P = primitive_attribute_float3(kg, sd, desc, &dPdx, &dPdy);
+
+ object_position_transform(kg, sd, &P);
+ object_dir_transform(kg, sd, &dPdx);
+ object_dir_transform(kg, sd, &dPdy);
+
+ ccl_fetch(sd, P) = P;
+ ccl_fetch(sd, dP).dx = dPdx;
+ ccl_fetch(sd, dP).dy = dPdy;
+ }
+}
+
+ccl_device void svm_node_leave_bump_eval(KernelGlobals *kg, ShaderData *sd, float *stack, uint offset)
+{
+ /* restore state */
+ ccl_fetch(sd, P) = stack_load_float3(stack, offset+0);
+ ccl_fetch(sd, dP).dx = stack_load_float3(stack, offset+3);
+ ccl_fetch(sd, dP).dy = stack_load_float3(stack, offset+6);
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm_closure.h b/intern/cycles/kernel/svm/svm_closure.h
index 88397005b49..017d697f9f8 100644
--- a/intern/cycles/kernel/svm/svm_closure.h
+++ b/intern/cycles/kernel/svm/svm_closure.h
@@ -18,104 +18,44 @@ CCL_NAMESPACE_BEGIN
/* Closure Nodes */
-ccl_device void svm_node_glass_setup(ShaderData *sd, ShaderClosure *sc, int type, float eta, float roughness, bool refract)
+ccl_device void svm_node_glass_setup(ShaderData *sd, MicrofacetBsdf *bsdf, int type, float eta, float roughness, bool refract)
{
if(type == CLOSURE_BSDF_SHARP_GLASS_ID) {
if(refract) {
- sc->data0 = eta;
- sc->data1 = 0.0f;
- sc->data2 = 0.0f;
- ccl_fetch(sd, flag) |= bsdf_refraction_setup(sc);
+ bsdf->alpha_y = 0.0f;
+ bsdf->alpha_x = 0.0f;
+ bsdf->ior = eta;
+ ccl_fetch(sd, flag) |= bsdf_refraction_setup(bsdf);
}
else {
- sc->data0 = 0.0f;
- sc->data1 = 0.0f;
- sc->data2 = 0.0f;
- ccl_fetch(sd, flag) |= bsdf_reflection_setup(sc);
+ bsdf->alpha_y = 0.0f;
+ bsdf->alpha_x = 0.0f;
+ bsdf->ior = 0.0f;
+ ccl_fetch(sd, flag) |= bsdf_reflection_setup(bsdf);
}
}
else if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID) {
- sc->data0 = roughness;
- sc->data1 = roughness;
- sc->data2 = eta;
+ bsdf->alpha_x = roughness;
+ bsdf->alpha_y = roughness;
+ bsdf->ior = eta;
if(refract)
- ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_refraction_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_refraction_setup(bsdf);
else
- ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_setup(bsdf);
}
else {
- sc->data0 = roughness;
- sc->data1 = roughness;
- sc->data2 = eta;
+ bsdf->alpha_x = roughness;
+ bsdf->alpha_y = roughness;
+ bsdf->ior = eta;
if(refract)
- ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_refraction_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_refraction_setup(bsdf);
else
- ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_setup(bsdf);
}
}
-ccl_device_inline ShaderClosure *svm_node_closure_get_non_bsdf(ShaderData *sd, ClosureType type, float mix_weight)
-{
- ShaderClosure *sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure));
-
- if(ccl_fetch(sd, num_closure) < MAX_CLOSURE) {
- sc->weight *= mix_weight;
- sc->type = type;
- sc->data0 = 0.0f;
- sc->data1 = 0.0f;
- sc->data2 = 0.0f;
-#ifdef __OSL__
- sc->prim = NULL;
-#endif
- ccl_fetch(sd, num_closure)++;
- return sc;
- }
-
- return NULL;
-}
-
-ccl_device_inline ShaderClosure *svm_node_closure_get_bsdf(ShaderData *sd, float mix_weight)
-{
- ShaderClosure *sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure));
-
- float3 weight = sc->weight * mix_weight;
- float sample_weight = fabsf(average(weight));
-
- if(sample_weight > CLOSURE_WEIGHT_CUTOFF && ccl_fetch(sd, num_closure) < MAX_CLOSURE) {
- sc->weight = weight;
- sc->sample_weight = sample_weight;
- ccl_fetch(sd, num_closure)++;
-#ifdef __OSL__
- sc->prim = NULL;
-#endif
- return sc;
- }
-
- return NULL;
-}
-
-ccl_device_inline ShaderClosure *svm_node_closure_get_absorption(ShaderData *sd, float mix_weight)
-{
- ShaderClosure *sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure));
-
- float3 weight = (make_float3(1.0f, 1.0f, 1.0f) - sc->weight) * mix_weight;
- float sample_weight = fabsf(average(weight));
-
- if(sample_weight > CLOSURE_WEIGHT_CUTOFF && ccl_fetch(sd, num_closure) < MAX_CLOSURE) {
- sc->weight = weight;
- sc->sample_weight = sample_weight;
- ccl_fetch(sd, num_closure)++;
-#ifdef __OSL__
- sc->prim = NULL;
-#endif
- return sc;
- }
-
- return NULL;
-}
-
ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int path_flag, int *offset)
{
uint type, param1_offset, param2_offset;
@@ -137,77 +77,79 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
switch(type) {
case CLOSURE_BSDF_DIFFUSE_ID: {
- ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight);
+ float3 weight = ccl_fetch(sd, svm_closure_weight) * mix_weight;
+ OrenNayarBsdf *bsdf = (OrenNayarBsdf*)bsdf_alloc(sd, sizeof(OrenNayarBsdf), weight);
- if(sc) {
- sc->N = N;
+ if(bsdf) {
+ bsdf->N = N;
float roughness = param1;
if(roughness == 0.0f) {
- sc->data0 = 0.0f;
- sc->data1 = 0.0f;
- sc->data2 = 0.0f;
- ccl_fetch(sd, flag) |= bsdf_diffuse_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_diffuse_setup((DiffuseBsdf*)bsdf);
}
else {
- sc->data0 = roughness;
- sc->data1 = 0.0f;
- sc->data2 = 0.0f;
- ccl_fetch(sd, flag) |= bsdf_oren_nayar_setup(sc);
+ bsdf->roughness = roughness;
+ ccl_fetch(sd, flag) |= bsdf_oren_nayar_setup(bsdf);
}
}
break;
}
case CLOSURE_BSDF_TRANSLUCENT_ID: {
- ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight);
+ float3 weight = ccl_fetch(sd, svm_closure_weight) * mix_weight;
+ DiffuseBsdf *bsdf = (DiffuseBsdf*)bsdf_alloc(sd, sizeof(DiffuseBsdf), weight);
- if(sc) {
- sc->data0 = 0.0f;
- sc->data1 = 0.0f;
- sc->data2 = 0.0f;
- sc->N = N;
- ccl_fetch(sd, flag) |= bsdf_translucent_setup(sc);
+ if(bsdf) {
+ bsdf->N = N;
+ ccl_fetch(sd, flag) |= bsdf_translucent_setup(bsdf);
}
break;
}
case CLOSURE_BSDF_TRANSPARENT_ID: {
- ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight);
+ float3 weight = ccl_fetch(sd, svm_closure_weight) * mix_weight;
+ ShaderClosure *bsdf = bsdf_alloc(sd, sizeof(ShaderClosure), weight);
- if(sc) {
- sc->data0 = 0.0f;
- sc->data1 = 0.0f;
- sc->data2 = 0.0f;
- sc->N = N;
- ccl_fetch(sd, flag) |= bsdf_transparent_setup(sc);
+ if(bsdf) {
+ ccl_fetch(sd, flag) |= bsdf_transparent_setup(bsdf);
}
break;
}
case CLOSURE_BSDF_REFLECTION_ID:
case CLOSURE_BSDF_MICROFACET_GGX_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
- case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID: {
+ case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID:
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: {
#ifdef __CAUSTICS_TRICKS__
if(!kernel_data.integrator.caustics_reflective && (path_flag & PATH_RAY_DIFFUSE))
break;
#endif
- ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight);
+ float3 weight = ccl_fetch(sd, svm_closure_weight) * mix_weight;
+ MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc(sd, sizeof(MicrofacetBsdf), weight);
- if(sc) {
- sc->N = N;
- sc->data0 = param1;
- sc->data1 = param1;
- sc->data2 = 0.0f;
+ if(bsdf) {
+ bsdf->N = N;
+ bsdf->alpha_x = param1;
+ bsdf->alpha_y = param1;
+ bsdf->ior = 0.0f;
+ bsdf->extra = NULL;
/* setup bsdf */
if(type == CLOSURE_BSDF_REFLECTION_ID)
- ccl_fetch(sd, flag) |= bsdf_reflection_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_reflection_setup(bsdf);
else if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_ID)
- ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_setup(bsdf);
else if(type == CLOSURE_BSDF_MICROFACET_GGX_ID)
- ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_setup(bsdf);
+ else if(type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID) {
+ kernel_assert(stack_valid(data_node.z));
+ bsdf->extra = (MicrofacetExtra*)closure_alloc_extra(sd, sizeof(MicrofacetExtra));
+ if(bsdf->extra) {
+ bsdf->extra->color = stack_load_float3(stack, data_node.z);
+ ccl_fetch(sd, flag) |= bsdf_microfacet_multi_ggx_setup(bsdf);
+ }
+ }
else
- ccl_fetch(sd, flag) |= bsdf_ashikhmin_shirley_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_ashikhmin_shirley_setup(bsdf);
}
break;
@@ -219,31 +161,33 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
if(!kernel_data.integrator.caustics_refractive && (path_flag & PATH_RAY_DIFFUSE))
break;
#endif
- ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight);
+ float3 weight = ccl_fetch(sd, svm_closure_weight) * mix_weight;
+ MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc(sd, sizeof(MicrofacetBsdf), weight);
- if(sc) {
- sc->N = N;
+ if(bsdf) {
+ bsdf->N = N;
+ bsdf->extra = NULL;
float eta = fmaxf(param2, 1e-5f);
eta = (ccl_fetch(sd, flag) & SD_BACKFACING)? 1.0f/eta: eta;
/* setup bsdf */
if(type == CLOSURE_BSDF_REFRACTION_ID) {
- sc->data0 = eta;
- sc->data1 = 0.0f;
- sc->data2 = 0.0f;
+ bsdf->alpha_x = 0.0f;
+ bsdf->alpha_y = 0.0f;
+ bsdf->ior = eta;
- ccl_fetch(sd, flag) |= bsdf_refraction_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_refraction_setup(bsdf);
}
else {
- sc->data0 = param1;
- sc->data1 = param1;
- sc->data2 = eta;
+ bsdf->alpha_x = param1;
+ bsdf->alpha_y = param1;
+ bsdf->ior = eta;
if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID)
- ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_refraction_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_refraction_setup(bsdf);
else
- ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_refraction_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_refraction_setup(bsdf);
}
}
@@ -259,7 +203,7 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
break;
}
#endif
- int num_closure = ccl_fetch(sd, num_closure);
+ float3 weight = ccl_fetch(sd, svm_closure_weight) * mix_weight;
/* index of refraction */
float eta = fmaxf(param2, 1e-5f);
@@ -271,164 +215,193 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
float roughness = param1;
/* reflection */
- ShaderClosure *sc = ccl_fetch_array(sd, closure, num_closure);
- float3 weight = sc->weight;
- float sample_weight = sc->sample_weight;
-
- sc = svm_node_closure_get_bsdf(sd, mix_weight*fresnel);
#ifdef __CAUSTICS_TRICKS__
if(kernel_data.integrator.caustics_reflective || (path_flag & PATH_RAY_DIFFUSE) == 0)
#endif
{
- if(sc) {
- sc->N = N;
- svm_node_glass_setup(sd, sc, type, eta, roughness, false);
+ MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc(sd, sizeof(MicrofacetBsdf), weight*fresnel);
+
+ if(bsdf) {
+ bsdf->N = N;
+ bsdf->extra = NULL;
+ svm_node_glass_setup(sd, bsdf, type, eta, roughness, false);
+ }
+ }
+
+ /* refraction */
+#ifdef __CAUSTICS_TRICKS__
+ if(kernel_data.integrator.caustics_refractive || (path_flag & PATH_RAY_DIFFUSE) == 0)
+#endif
+ {
+ MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc(sd, sizeof(MicrofacetBsdf), weight*(1.0f - fresnel));
+
+ if(bsdf) {
+ bsdf->N = N;
+ bsdf->extra = NULL;
+ svm_node_glass_setup(sd, bsdf, type, eta, roughness, true);
}
}
+ break;
+ }
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: {
#ifdef __CAUSTICS_TRICKS__
- if(!kernel_data.integrator.caustics_refractive && (path_flag & PATH_RAY_DIFFUSE))
+ if(!kernel_data.integrator.caustics_reflective && !kernel_data.integrator.caustics_refractive && (path_flag & PATH_RAY_DIFFUSE))
break;
#endif
+ float3 weight = ccl_fetch(sd, svm_closure_weight) * mix_weight;
+ MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc(sd, sizeof(MicrofacetBsdf), weight);
+ MicrofacetExtra *extra = (MicrofacetExtra*)closure_alloc_extra(sd, sizeof(MicrofacetExtra));
- /* refraction */
- if(num_closure + 1 < MAX_CLOSURE) {
- sc = ccl_fetch_array(sd, closure, num_closure + 1);
- sc->weight = weight;
- sc->sample_weight = sample_weight;
+ if(bsdf && extra) {
+ bsdf->N = N;
+ bsdf->extra = extra;
+ bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
- sc = svm_node_closure_get_bsdf(sd, mix_weight*(1.0f - fresnel));
+ bsdf->alpha_x = param1;
+ bsdf->alpha_y = param1;
+ float eta = fmaxf(param2, 1e-5f);
+ bsdf->ior = (ccl_fetch(sd, flag) & SD_BACKFACING)? 1.0f/eta: eta;
- if(sc) {
- sc->N = N;
- svm_node_glass_setup(sd, sc, type, eta, roughness, true);
- }
+ kernel_assert(stack_valid(data_node.z));
+ bsdf->extra->color = stack_load_float3(stack, data_node.z);
+
+ /* setup bsdf */
+ ccl_fetch(sd, flag) |= bsdf_microfacet_multi_ggx_glass_setup(bsdf);
}
break;
}
case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID:
case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID:
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID:
case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID: {
#ifdef __CAUSTICS_TRICKS__
if(!kernel_data.integrator.caustics_reflective && (path_flag & PATH_RAY_DIFFUSE))
break;
#endif
- ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight);
+ float3 weight = ccl_fetch(sd, svm_closure_weight) * mix_weight;
+ MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc(sd, sizeof(MicrofacetBsdf), weight);
- if(sc) {
- sc->N = N;
-
- sc->T = stack_load_float3(stack, data_node.y);
+ if(bsdf) {
+ bsdf->N = N;
+ bsdf->extra = NULL;
+ bsdf->T = stack_load_float3(stack, data_node.y);
/* rotate tangent */
float rotation = stack_load_float(stack, data_node.z);
if(rotation != 0.0f)
- sc->T = rotate_around_axis(sc->T, sc->N, rotation * M_2PI_F);
+ bsdf->T = rotate_around_axis(bsdf->T, bsdf->N, rotation * M_2PI_F);
/* compute roughness */
float roughness = param1;
float anisotropy = clamp(param2, -0.99f, 0.99f);
if(anisotropy < 0.0f) {
- sc->data0 = roughness/(1.0f + anisotropy);
- sc->data1 = roughness*(1.0f + anisotropy);
+ bsdf->alpha_x = roughness/(1.0f + anisotropy);
+ bsdf->alpha_y = roughness*(1.0f + anisotropy);
}
else {
- sc->data0 = roughness*(1.0f - anisotropy);
- sc->data1 = roughness/(1.0f - anisotropy);
+ bsdf->alpha_x = roughness*(1.0f - anisotropy);
+ bsdf->alpha_y = roughness/(1.0f - anisotropy);
}
- sc->data2 = 0.0f;
+ bsdf->ior = 0.0f;
- if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID)
- ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_aniso_setup(sc);
- else if(type == CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID)
- ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_aniso_setup(sc);
+ if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID) {
+ ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_aniso_setup(bsdf);
+ }
+ else if(type == CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID) {
+ ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_aniso_setup(bsdf);
+ }
+ else if(type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID) {
+ kernel_assert(stack_valid(data_node.w));
+ bsdf->extra = (MicrofacetExtra*)closure_alloc_extra(sd, sizeof(MicrofacetExtra));
+ if(bsdf->extra) {
+ bsdf->extra->color = stack_load_float3(stack, data_node.w);
+ ccl_fetch(sd, flag) |= bsdf_microfacet_multi_ggx_aniso_setup(bsdf);
+ }
+ }
else
- ccl_fetch(sd, flag) |= bsdf_ashikhmin_shirley_aniso_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_ashikhmin_shirley_aniso_setup(bsdf);
}
break;
}
case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID: {
- ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight);
+ float3 weight = ccl_fetch(sd, svm_closure_weight) * mix_weight;
+ VelvetBsdf *bsdf = (VelvetBsdf*)bsdf_alloc(sd, sizeof(VelvetBsdf), weight);
- if(sc) {
- sc->N = N;
+ if(bsdf) {
+ bsdf->N = N;
- /* sigma */
- sc->data0 = saturate(param1);
- sc->data1 = 0.0f;
- sc->data2 = 0.0f;
- ccl_fetch(sd, flag) |= bsdf_ashikhmin_velvet_setup(sc);
+ bsdf->sigma = saturate(param1);
+ ccl_fetch(sd, flag) |= bsdf_ashikhmin_velvet_setup(bsdf);
}
break;
}
- case CLOSURE_BSDF_DIFFUSE_TOON_ID:
- case CLOSURE_BSDF_GLOSSY_TOON_ID: {
- ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight);
-
- if(sc) {
- /* Normal, Size and Smooth */
- sc->N = N;
- sc->data0 = param1;
- sc->data1 = param2;
- sc->data2 = 0.0f;
+ case CLOSURE_BSDF_GLOSSY_TOON_ID:
+#ifdef __CAUSTICS_TRICKS__
+ if(!kernel_data.integrator.caustics_reflective && (path_flag & PATH_RAY_DIFFUSE))
+ break;
+#endif
+ case CLOSURE_BSDF_DIFFUSE_TOON_ID: {
+ float3 weight = ccl_fetch(sd, svm_closure_weight) * mix_weight;
+ ToonBsdf *bsdf = (ToonBsdf*)bsdf_alloc(sd, sizeof(ToonBsdf), weight);
+
+ if(bsdf) {
+ bsdf->N = N;
+ bsdf->size = param1;
+ bsdf->smooth = param2;
if(type == CLOSURE_BSDF_DIFFUSE_TOON_ID)
- ccl_fetch(sd, flag) |= bsdf_diffuse_toon_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_diffuse_toon_setup(bsdf);
else
- ccl_fetch(sd, flag) |= bsdf_glossy_toon_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_glossy_toon_setup(bsdf);
}
break;
}
#ifdef __HAIR__
case CLOSURE_BSDF_HAIR_REFLECTION_ID:
case CLOSURE_BSDF_HAIR_TRANSMISSION_ID: {
+ float3 weight = ccl_fetch(sd, svm_closure_weight) * mix_weight;
if(ccl_fetch(sd, flag) & SD_BACKFACING && ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE) {
- ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight);
+ ShaderClosure *bsdf = bsdf_alloc(sd, sizeof(ShaderClosure), weight);
- if(sc) {
+ if(bsdf) {
/* todo: giving a fixed weight here will cause issues when
* mixing multiple BSDFS. energy will not be conserved and
* the throughput can blow up after multiple bounces. we
* better figure out a way to skip backfaces from rays
* spawned by transmission from the front */
- sc->weight = make_float3(1.0f, 1.0f, 1.0f);
- sc->N = N;
- sc->data0 = 0.0f;
- sc->data1 = 0.0f;
- sc->data2 = 0.0f;
- ccl_fetch(sd, flag) |= bsdf_transparent_setup(sc);
+ bsdf->weight = make_float3(1.0f, 1.0f, 1.0f);
+ ccl_fetch(sd, flag) |= bsdf_transparent_setup(bsdf);
}
}
else {
- ShaderClosure *sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure));
- sc = svm_node_closure_get_bsdf(sd, mix_weight);
+ HairBsdf *bsdf = (HairBsdf*)bsdf_alloc(sd, sizeof(HairBsdf), weight);
- if(sc) {
- sc->N = N;
- sc->data0 = param1;
- sc->data1 = param2;
- sc->data2 = -stack_load_float(stack, data_node.z);
+ if(bsdf) {
+ bsdf->roughness1 = param1;
+ bsdf->roughness2 = param2;
+ bsdf->offset = -stack_load_float(stack, data_node.z);
if(stack_valid(data_node.y)) {
- sc->T = normalize(stack_load_float3(stack, data_node.y));
+ bsdf->T = normalize(stack_load_float3(stack, data_node.y));
}
else if(!(ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE)) {
- sc->T = normalize(ccl_fetch(sd, dPdv));
- sc->data2 = 0.0f;
+ bsdf->T = normalize(ccl_fetch(sd, dPdv));
+ bsdf->offset = 0.0f;
}
else
- sc->T = normalize(ccl_fetch(sd, dPdu));
+ bsdf->T = normalize(ccl_fetch(sd, dPdu));
if(type == CLOSURE_BSDF_HAIR_REFLECTION_ID) {
- ccl_fetch(sd, flag) |= bsdf_hair_reflection_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_hair_reflection_setup(bsdf);
}
else {
- ccl_fetch(sd, flag) |= bsdf_hair_transmission_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_hair_transmission_setup(bsdf);
}
}
}
@@ -438,17 +411,11 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
#endif
#ifdef __SUBSURFACE__
-# ifndef __SPLIT_KERNEL__
-# define sc_next(sc) sc++
-# else
-# define sc_next(sc) sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure))
-# endif
case CLOSURE_BSSRDF_CUBIC_ID:
case CLOSURE_BSSRDF_GAUSSIAN_ID:
case CLOSURE_BSSRDF_BURLEY_ID: {
- ShaderClosure *sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure));
- float3 albedo = sc->weight;
- float3 weight = sc->weight * mix_weight;
+ float3 albedo = ccl_fetch(sd, svm_closure_weight);
+ float3 weight = ccl_fetch(sd, svm_closure_weight) * mix_weight;
float sample_weight = fabsf(average(weight));
/* disable in case of diffuse ancestor, can't see it well then and
@@ -457,7 +424,7 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
if(path_flag & PATH_RAY_DIFFUSE_ANCESTOR)
param1 = 0.0f;
- if(sample_weight > CLOSURE_WEIGHT_CUTOFF && ccl_fetch(sd, num_closure)+2 < MAX_CLOSURE) {
+ if(sample_weight > CLOSURE_WEIGHT_CUTOFF) {
/* radius * scale */
float3 radius = stack_load_float3(stack, data_node.z)*param1;
/* sharpness */
@@ -466,61 +433,42 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
float texture_blur = param2;
/* create one closure per color channel */
- if(fabsf(weight.x) > 0.0f) {
- sc->weight = make_float3(weight.x, 0.0f, 0.0f);
- sc->sample_weight = sample_weight;
- sc->data0 = radius.x;
- sc->data1 = texture_blur;
- sc->data2 = albedo.x;
- sc->T.x = sharpness;
-# ifdef __OSL__
- sc->prim = NULL;
-# endif
- sc->N = N;
- ccl_fetch(sd, flag) |= bssrdf_setup(sc, (ClosureType)type);
-
- ccl_fetch(sd, num_closure)++;
- sc_next(sc);
+ Bssrdf *bssrdf = bssrdf_alloc(sd, make_float3(weight.x, 0.0f, 0.0f));
+ if(bssrdf) {
+ bssrdf->sample_weight = sample_weight;
+ bssrdf->radius = radius.x;
+ bssrdf->texture_blur = texture_blur;
+ bssrdf->albedo = albedo.x;
+ bssrdf->sharpness = sharpness;
+ bssrdf->N = N;
+ ccl_fetch(sd, flag) |= bssrdf_setup(bssrdf, (ClosureType)type);
}
- if(fabsf(weight.y) > 0.0f) {
- sc->weight = make_float3(0.0f, weight.y, 0.0f);
- sc->sample_weight = sample_weight;
- sc->data0 = radius.y;
- sc->data1 = texture_blur;
- sc->data2 = albedo.y;
- sc->T.x = sharpness;
-# ifdef __OSL__
- sc->prim = NULL;
-# endif
- sc->N = N;
- ccl_fetch(sd, flag) |= bssrdf_setup(sc, (ClosureType)type);
-
- ccl_fetch(sd, num_closure)++;
- sc_next(sc);
+ bssrdf = bssrdf_alloc(sd, make_float3(0.0f, weight.y, 0.0f));
+ if(bssrdf) {
+ bssrdf->sample_weight = sample_weight;
+ bssrdf->radius = radius.y;
+ bssrdf->texture_blur = texture_blur;
+ bssrdf->albedo = albedo.y;
+ bssrdf->sharpness = sharpness;
+ bssrdf->N = N;
+ ccl_fetch(sd, flag) |= bssrdf_setup(bssrdf, (ClosureType)type);
}
- if(fabsf(weight.z) > 0.0f) {
- sc->weight = make_float3(0.0f, 0.0f, weight.z);
- sc->sample_weight = sample_weight;
- sc->data0 = radius.z;
- sc->data1 = texture_blur;
- sc->data2 = albedo.z;
- sc->T.x = sharpness;
-# ifdef __OSL__
- sc->prim = NULL;
-# endif
- sc->N = N;
- ccl_fetch(sd, flag) |= bssrdf_setup(sc, (ClosureType)type);
-
- ccl_fetch(sd, num_closure)++;
- sc_next(sc);
+ bssrdf = bssrdf_alloc(sd, make_float3(0.0f, 0.0f, weight.z));
+ if(bssrdf) {
+ bssrdf->sample_weight = sample_weight;
+ bssrdf->radius = radius.z;
+ bssrdf->texture_blur = texture_blur;
+ bssrdf->albedo = albedo.z;
+ bssrdf->sharpness = sharpness;
+ bssrdf->N = N;
+ ccl_fetch(sd, flag) |= bssrdf_setup(bssrdf, (ClosureType)type);
}
}
break;
}
-# undef sc_next
#endif
default:
break;
@@ -545,7 +493,8 @@ ccl_device void svm_node_closure_volume(KernelGlobals *kg, ShaderData *sd, float
switch(type) {
case CLOSURE_VOLUME_ABSORPTION_ID: {
- ShaderClosure *sc = svm_node_closure_get_absorption(sd, mix_weight * density);
+ float3 weight = (make_float3(1.0f, 1.0f, 1.0f) - ccl_fetch(sd, svm_closure_weight)) * mix_weight * density;
+ ShaderClosure *sc = closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_NONE_ID, weight);
if(sc) {
ccl_fetch(sd, flag) |= volume_absorption_setup(sc);
@@ -553,13 +502,12 @@ ccl_device void svm_node_closure_volume(KernelGlobals *kg, ShaderData *sd, float
break;
}
case CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID: {
- ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight * density);
+ float3 weight = ccl_fetch(sd, svm_closure_weight) * mix_weight * density;
+ HenyeyGreensteinVolume *volume = (HenyeyGreensteinVolume*)bsdf_alloc(sd, sizeof(HenyeyGreensteinVolume), weight);
- if(sc) {
- sc->data0 = param2; /* g */
- sc->data1 = 0.0f;
- sc->data2 = 0.0f;
- ccl_fetch(sd, flag) |= volume_henyey_greenstein_setup(sc);
+ if(volume) {
+ volume->g = param2; /* g */
+ ccl_fetch(sd, flag) |= volume_henyey_greenstein_setup(volume);
}
break;
}
@@ -579,10 +527,10 @@ ccl_device void svm_node_closure_emission(ShaderData *sd, float *stack, uint4 no
if(mix_weight == 0.0f)
return;
- svm_node_closure_get_non_bsdf(sd, CLOSURE_EMISSION_ID, mix_weight);
+ closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_EMISSION_ID, ccl_fetch(sd, svm_closure_weight) * mix_weight);
}
else
- svm_node_closure_get_non_bsdf(sd, CLOSURE_EMISSION_ID, 1.0f);
+ closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_EMISSION_ID, ccl_fetch(sd, svm_closure_weight));
ccl_fetch(sd, flag) |= SD_EMISSION;
}
@@ -597,10 +545,10 @@ ccl_device void svm_node_closure_background(ShaderData *sd, float *stack, uint4
if(mix_weight == 0.0f)
return;
- svm_node_closure_get_non_bsdf(sd, CLOSURE_BACKGROUND_ID, mix_weight);
+ closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_BACKGROUND_ID, ccl_fetch(sd, svm_closure_weight) * mix_weight);
}
else
- svm_node_closure_get_non_bsdf(sd, CLOSURE_BACKGROUND_ID, 1.0f);
+ closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_BACKGROUND_ID, ccl_fetch(sd, svm_closure_weight));
}
ccl_device void svm_node_closure_holdout(ShaderData *sd, float *stack, uint4 node)
@@ -613,10 +561,10 @@ ccl_device void svm_node_closure_holdout(ShaderData *sd, float *stack, uint4 nod
if(mix_weight == 0.0f)
return;
- svm_node_closure_get_non_bsdf(sd, CLOSURE_HOLDOUT_ID, mix_weight);
+ closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_HOLDOUT_ID, ccl_fetch(sd, svm_closure_weight) * mix_weight);
}
else
- svm_node_closure_get_non_bsdf(sd, CLOSURE_HOLDOUT_ID, 1.0f);
+ closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_HOLDOUT_ID, ccl_fetch(sd, svm_closure_weight));
ccl_fetch(sd, flag) |= SD_HOLDOUT;
}
@@ -631,10 +579,10 @@ ccl_device void svm_node_closure_ambient_occlusion(ShaderData *sd, float *stack,
if(mix_weight == 0.0f)
return;
- svm_node_closure_get_non_bsdf(sd, CLOSURE_AMBIENT_OCCLUSION_ID, mix_weight);
+ closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_AMBIENT_OCCLUSION_ID, ccl_fetch(sd, svm_closure_weight) * mix_weight);
}
else
- svm_node_closure_get_non_bsdf(sd, CLOSURE_AMBIENT_OCCLUSION_ID, 1.0f);
+ closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_AMBIENT_OCCLUSION_ID, ccl_fetch(sd, svm_closure_weight));
ccl_fetch(sd, flag) |= SD_AO;
}
@@ -643,10 +591,7 @@ ccl_device void svm_node_closure_ambient_occlusion(ShaderData *sd, float *stack,
ccl_device_inline void svm_node_closure_store_weight(ShaderData *sd, float3 weight)
{
- if(ccl_fetch(sd, num_closure) < MAX_CLOSURE) {
- ShaderClosure *sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure));
- sc->weight = weight;
- }
+ ccl_fetch(sd, svm_closure_weight) = weight;
}
ccl_device void svm_node_closure_set_weight(ShaderData *sd, uint r, uint g, uint b)
diff --git a/intern/cycles/kernel/svm/svm_color_util.h b/intern/cycles/kernel/svm/svm_color_util.h
new file mode 100644
index 00000000000..258cdeb630e
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_color_util.h
@@ -0,0 +1,306 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device float3 svm_mix_blend(float t, float3 col1, float3 col2)
+{
+ return interp(col1, col2, t);
+}
+
+ccl_device float3 svm_mix_add(float t, float3 col1, float3 col2)
+{
+ return interp(col1, col1 + col2, t);
+}
+
+ccl_device float3 svm_mix_mul(float t, float3 col1, float3 col2)
+{
+ return interp(col1, col1 * col2, t);
+}
+
+ccl_device float3 svm_mix_screen(float t, float3 col1, float3 col2)
+{
+ float tm = 1.0f - t;
+ float3 one = make_float3(1.0f, 1.0f, 1.0f);
+ float3 tm3 = make_float3(tm, tm, tm);
+
+ return one - (tm3 + t*(one - col2))*(one - col1);
+}
+
+ccl_device float3 svm_mix_overlay(float t, float3 col1, float3 col2)
+{
+ float tm = 1.0f - t;
+
+ float3 outcol = col1;
+
+ if(outcol.x < 0.5f)
+ outcol.x *= tm + 2.0f*t*col2.x;
+ else
+ outcol.x = 1.0f - (tm + 2.0f*t*(1.0f - col2.x))*(1.0f - outcol.x);
+
+ if(outcol.y < 0.5f)
+ outcol.y *= tm + 2.0f*t*col2.y;
+ else
+ outcol.y = 1.0f - (tm + 2.0f*t*(1.0f - col2.y))*(1.0f - outcol.y);
+
+ if(outcol.z < 0.5f)
+ outcol.z *= tm + 2.0f*t*col2.z;
+ else
+ outcol.z = 1.0f - (tm + 2.0f*t*(1.0f - col2.z))*(1.0f - outcol.z);
+
+ return outcol;
+}
+
+ccl_device float3 svm_mix_sub(float t, float3 col1, float3 col2)
+{
+ return interp(col1, col1 - col2, t);
+}
+
+ccl_device float3 svm_mix_div(float t, float3 col1, float3 col2)
+{
+ float tm = 1.0f - t;
+
+ float3 outcol = col1;
+
+ if(col2.x != 0.0f) outcol.x = tm*outcol.x + t*outcol.x/col2.x;
+ if(col2.y != 0.0f) outcol.y = tm*outcol.y + t*outcol.y/col2.y;
+ if(col2.z != 0.0f) outcol.z = tm*outcol.z + t*outcol.z/col2.z;
+
+ return outcol;
+}
+
+ccl_device float3 svm_mix_diff(float t, float3 col1, float3 col2)
+{
+ return interp(col1, fabs(col1 - col2), t);
+}
+
+ccl_device float3 svm_mix_dark(float t, float3 col1, float3 col2)
+{
+ return min(col1, col2)*t + col1*(1.0f - t);
+}
+
+ccl_device float3 svm_mix_light(float t, float3 col1, float3 col2)
+{
+ return max(col1, col2*t);
+}
+
+ccl_device float3 svm_mix_dodge(float t, float3 col1, float3 col2)
+{
+ float3 outcol = col1;
+
+ if(outcol.x != 0.0f) {
+ float tmp = 1.0f - t*col2.x;
+ if(tmp <= 0.0f)
+ outcol.x = 1.0f;
+ else if((tmp = outcol.x/tmp) > 1.0f)
+ outcol.x = 1.0f;
+ else
+ outcol.x = tmp;
+ }
+ if(outcol.y != 0.0f) {
+ float tmp = 1.0f - t*col2.y;
+ if(tmp <= 0.0f)
+ outcol.y = 1.0f;
+ else if((tmp = outcol.y/tmp) > 1.0f)
+ outcol.y = 1.0f;
+ else
+ outcol.y = tmp;
+ }
+ if(outcol.z != 0.0f) {
+ float tmp = 1.0f - t*col2.z;
+ if(tmp <= 0.0f)
+ outcol.z = 1.0f;
+ else if((tmp = outcol.z/tmp) > 1.0f)
+ outcol.z = 1.0f;
+ else
+ outcol.z = tmp;
+ }
+
+ return outcol;
+}
+
+ccl_device float3 svm_mix_burn(float t, float3 col1, float3 col2)
+{
+ float tmp, tm = 1.0f - t;
+
+ float3 outcol = col1;
+
+ tmp = tm + t*col2.x;
+ if(tmp <= 0.0f)
+ outcol.x = 0.0f;
+ else if((tmp = (1.0f - (1.0f - outcol.x)/tmp)) < 0.0f)
+ outcol.x = 0.0f;
+ else if(tmp > 1.0f)
+ outcol.x = 1.0f;
+ else
+ outcol.x = tmp;
+
+ tmp = tm + t*col2.y;
+ if(tmp <= 0.0f)
+ outcol.y = 0.0f;
+ else if((tmp = (1.0f - (1.0f - outcol.y)/tmp)) < 0.0f)
+ outcol.y = 0.0f;
+ else if(tmp > 1.0f)
+ outcol.y = 1.0f;
+ else
+ outcol.y = tmp;
+
+ tmp = tm + t*col2.z;
+ if(tmp <= 0.0f)
+ outcol.z = 0.0f;
+ else if((tmp = (1.0f - (1.0f - outcol.z)/tmp)) < 0.0f)
+ outcol.z = 0.0f;
+ else if(tmp > 1.0f)
+ outcol.z = 1.0f;
+ else
+ outcol.z = tmp;
+
+ return outcol;
+}
+
+ccl_device float3 svm_mix_hue(float t, float3 col1, float3 col2)
+{
+ float3 outcol = col1;
+
+ float3 hsv2 = rgb_to_hsv(col2);
+
+ if(hsv2.y != 0.0f) {
+ float3 hsv = rgb_to_hsv(outcol);
+ hsv.x = hsv2.x;
+ float3 tmp = hsv_to_rgb(hsv);
+
+ outcol = interp(outcol, tmp, t);
+ }
+
+ return outcol;
+}
+
+ccl_device float3 svm_mix_sat(float t, float3 col1, float3 col2)
+{
+ float tm = 1.0f - t;
+
+ float3 outcol = col1;
+
+ float3 hsv = rgb_to_hsv(outcol);
+
+ if(hsv.y != 0.0f) {
+ float3 hsv2 = rgb_to_hsv(col2);
+
+ hsv.y = tm*hsv.y + t*hsv2.y;
+ outcol = hsv_to_rgb(hsv);
+ }
+
+ return outcol;
+}
+
+ccl_device float3 svm_mix_val(float t, float3 col1, float3 col2)
+{
+ float tm = 1.0f - t;
+
+ float3 hsv = rgb_to_hsv(col1);
+ float3 hsv2 = rgb_to_hsv(col2);
+
+ hsv.z = tm*hsv.z + t*hsv2.z;
+
+ return hsv_to_rgb(hsv);
+}
+
+ccl_device float3 svm_mix_color(float t, float3 col1, float3 col2)
+{
+ float3 outcol = col1;
+ float3 hsv2 = rgb_to_hsv(col2);
+
+ if(hsv2.y != 0.0f) {
+ float3 hsv = rgb_to_hsv(outcol);
+ hsv.x = hsv2.x;
+ hsv.y = hsv2.y;
+ float3 tmp = hsv_to_rgb(hsv);
+
+ outcol = interp(outcol, tmp, t);
+ }
+
+ return outcol;
+}
+
+ccl_device float3 svm_mix_soft(float t, float3 col1, float3 col2)
+{
+ float tm = 1.0f - t;
+
+ float3 one = make_float3(1.0f, 1.0f, 1.0f);
+ float3 scr = one - (one - col2)*(one - col1);
+
+ return tm*col1 + t*((one - col1)*col2*col1 + col1*scr);
+}
+
+ccl_device float3 svm_mix_linear(float t, float3 col1, float3 col2)
+{
+ return col1 + t*(2.0f*col2 + make_float3(-1.0f, -1.0f, -1.0f));
+}
+
+ccl_device float3 svm_mix_clamp(float3 col)
+{
+ float3 outcol = col;
+
+ outcol.x = saturate(col.x);
+ outcol.y = saturate(col.y);
+ outcol.z = saturate(col.z);
+
+ return outcol;
+}
+
+ccl_device_noinline float3 svm_mix(NodeMix type, float fac, float3 c1, float3 c2)
+{
+ float t = saturate(fac);
+
+ switch(type) {
+ case NODE_MIX_BLEND: return svm_mix_blend(t, c1, c2);
+ case NODE_MIX_ADD: return svm_mix_add(t, c1, c2);
+ case NODE_MIX_MUL: return svm_mix_mul(t, c1, c2);
+ case NODE_MIX_SCREEN: return svm_mix_screen(t, c1, c2);
+ case NODE_MIX_OVERLAY: return svm_mix_overlay(t, c1, c2);
+ case NODE_MIX_SUB: return svm_mix_sub(t, c1, c2);
+ case NODE_MIX_DIV: return svm_mix_div(t, c1, c2);
+ case NODE_MIX_DIFF: return svm_mix_diff(t, c1, c2);
+ case NODE_MIX_DARK: return svm_mix_dark(t, c1, c2);
+ case NODE_MIX_LIGHT: return svm_mix_light(t, c1, c2);
+ case NODE_MIX_DODGE: return svm_mix_dodge(t, c1, c2);
+ case NODE_MIX_BURN: return svm_mix_burn(t, c1, c2);
+ case NODE_MIX_HUE: return svm_mix_hue(t, c1, c2);
+ case NODE_MIX_SAT: return svm_mix_sat(t, c1, c2);
+ case NODE_MIX_VAL: return svm_mix_val (t, c1, c2);
+ case NODE_MIX_COLOR: return svm_mix_color(t, c1, c2);
+ case NODE_MIX_SOFT: return svm_mix_soft(t, c1, c2);
+ case NODE_MIX_LINEAR: return svm_mix_linear(t, c1, c2);
+ case NODE_MIX_CLAMP: return svm_mix_clamp(c1);
+ }
+
+ return make_float3(0.0f, 0.0f, 0.0f);
+}
+
+ccl_device_inline float3 svm_brightness_contrast(float3 color, float brightness, float contrast)
+{
+ float a = 1.0f + contrast;
+ float b = brightness - contrast*0.5f;
+
+ color.x = max(a*color.x + b, 0.0f);
+ color.y = max(a*color.y + b, 0.0f);
+ color.z = max(a*color.z + b, 0.0f);
+
+ return color;
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm_displace.h b/intern/cycles/kernel/svm/svm_displace.h
index 8d4b07c9973..890ab41aaaa 100644
--- a/intern/cycles/kernel/svm/svm_displace.h
+++ b/intern/cycles/kernel/svm/svm_displace.h
@@ -22,14 +22,23 @@ ccl_device void svm_node_set_bump(KernelGlobals *kg, ShaderData *sd, float *stac
{
#ifdef __RAY_DIFFERENTIALS__
/* get normal input */
- uint normal_offset, distance_offset, invert;
- decode_node_uchar4(node.y, &normal_offset, &distance_offset, &invert, NULL);
+ uint normal_offset, distance_offset, invert, use_object_space;
+ decode_node_uchar4(node.y, &normal_offset, &distance_offset, &invert, &use_object_space);
float3 normal_in = stack_valid(normal_offset)? stack_load_float3(stack, normal_offset): ccl_fetch(sd, N);
+ float3 dPdx = ccl_fetch(sd, dP).dx;
+ float3 dPdy = ccl_fetch(sd, dP).dy;
+
+ if(use_object_space) {
+ object_inverse_normal_transform(kg, sd, &normal_in);
+ object_inverse_dir_transform(kg, sd, &dPdx);
+ object_inverse_dir_transform(kg, sd, &dPdy);
+ }
+
/* get surface tangents from normal */
- float3 Rx = cross(ccl_fetch(sd, dP).dy, normal_in);
- float3 Ry = cross(normal_in, ccl_fetch(sd, dP).dx);
+ float3 Rx = cross(dPdy, normal_in);
+ float3 Ry = cross(normal_in, dPdx);
/* get bump values */
uint c_offset, x_offset, y_offset, strength_offset;
@@ -40,7 +49,7 @@ ccl_device void svm_node_set_bump(KernelGlobals *kg, ShaderData *sd, float *stac
float h_y = stack_load_float(stack, y_offset);
/* compute surface gradient and determinant */
- float det = dot(ccl_fetch(sd, dP).dx, Rx);
+ float det = dot(dPdx, Rx);
float3 surfgrad = (h_x - h_c)*Rx + (h_y - h_c)*Ry;
float absdet = fabsf(det);
@@ -56,16 +65,29 @@ ccl_device void svm_node_set_bump(KernelGlobals *kg, ShaderData *sd, float *stac
/* compute and output perturbed normal */
float3 normal_out = normalize(absdet*normal_in - distance*signf(det)*surfgrad);
normal_out = normalize(strength*normal_out + (1.0f - strength)*normal_in);
+
+ if(use_object_space) {
+ object_normal_transform(kg, sd, &normal_out);
+ }
+
stack_store_float3(stack, node.w, normal_out);
#endif
}
/* Displacement Node */
-ccl_device void svm_node_set_displacement(ShaderData *sd, float *stack, uint fac_offset)
+ccl_device void svm_node_set_displacement(KernelGlobals *kg, ShaderData *sd, float *stack, uint fac_offset)
{
float d = stack_load_float(stack, fac_offset);
- ccl_fetch(sd, P) += ccl_fetch(sd, N)*d*0.1f; /* todo: get rid of this factor */
+
+ float3 dP = ccl_fetch(sd, N);
+ object_inverse_normal_transform(kg, sd, &dP);
+
+ dP *= d*0.1f; /* todo: get rid of this factor */
+
+ object_dir_transform(kg, sd, &dP);
+
+ ccl_fetch(sd, P) += dP;
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_geometry.h b/intern/cycles/kernel/svm/svm_geometry.h
index bb06254c3a9..7d512f7ff4d 100644
--- a/intern/cycles/kernel/svm/svm_geometry.h
+++ b/intern/cycles/kernel/svm/svm_geometry.h
@@ -18,7 +18,11 @@ CCL_NAMESPACE_BEGIN
/* Geometry Node */
-ccl_device void svm_node_geometry(KernelGlobals *kg, ShaderData *sd, float *stack, uint type, uint out_offset)
+ccl_device_inline void svm_node_geometry(KernelGlobals *kg,
+ ShaderData *sd,
+ float *stack,
+ uint type,
+ uint out_offset)
{
float3 data;
@@ -94,7 +98,11 @@ ccl_device void svm_node_object_info(KernelGlobals *kg, ShaderData *sd, float *s
/* Particle Info */
-ccl_device void svm_node_particle_info(KernelGlobals *kg, ShaderData *sd, float *stack, uint type, uint out_offset)
+ccl_device void svm_node_particle_info(KernelGlobals *kg,
+ ShaderData *sd,
+ float *stack,
+ uint type,
+ uint out_offset)
{
switch(type) {
case NODE_INFO_PAR_INDEX: {
@@ -146,7 +154,11 @@ ccl_device void svm_node_particle_info(KernelGlobals *kg, ShaderData *sd, float
/* Hair Info */
-ccl_device void svm_node_hair_info(KernelGlobals *kg, ShaderData *sd, float *stack, uint type, uint out_offset)
+ccl_device void svm_node_hair_info(KernelGlobals *kg,
+ ShaderData *sd,
+ float *stack,
+ uint type,
+ uint out_offset)
{
float data;
float3 data3;
diff --git a/intern/cycles/kernel/svm/svm_image.h b/intern/cycles/kernel/svm/svm_image.h
index faff4ce3e6d..9606064492e 100644
--- a/intern/cycles/kernel/svm/svm_image.h
+++ b/intern/cycles/kernel/svm/svm_image.h
@@ -18,126 +18,17 @@ CCL_NAMESPACE_BEGIN
/* Float4 textures on various devices. */
#if defined(__KERNEL_CPU__)
- #define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_IMAGES_CPU
+# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_CPU
#elif defined(__KERNEL_CUDA__)
- #define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_IMAGES_CUDA
+# if __CUDA_ARCH__ < 300
+# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_CUDA
+# else
+# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_CUDA_KEPLER
+# endif
#else
- #define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_IMAGES_OPENCL
+# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_OPENCL
#endif
-#ifdef __KERNEL_OPENCL__
-
-/* For OpenCL all images are packed in a single array, and we do manual lookup
- * and interpolation. */
-
-ccl_device_inline float4 svm_image_texture_read(KernelGlobals *kg, int id, int offset)
-{
- if(id >= TEX_NUM_FLOAT4_IMAGES) {
- uchar4 r = kernel_tex_fetch(__tex_image_byte4_packed, offset);
- float f = 1.0f/255.0f;
- return make_float4(r.x*f, r.y*f, r.z*f, r.w*f);
- }
- else {
- return kernel_tex_fetch(__tex_image_float4_packed, offset);
- }
-}
-
-ccl_device_inline int svm_image_texture_wrap_periodic(int x, int width)
-{
- x %= width;
- if(x < 0)
- x += width;
- return x;
-}
-
-ccl_device_inline int svm_image_texture_wrap_clamp(int x, int width)
-{
- return clamp(x, 0, width-1);
-}
-
-ccl_device_inline float svm_image_texture_frac(float x, int *ix)
-{
- int i = float_to_int(x) - ((x < 0.0f)? 1: 0);
- *ix = i;
- return x - (float)i;
-}
-
-ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, uint srgb, uint use_alpha)
-{
- uint4 info = kernel_tex_fetch(__tex_image_packed_info, id);
- uint width = info.x;
- uint height = info.y;
- uint offset = info.z;
- uint periodic = (info.w & 0x1);
- uint interpolation = info.w >> 1;
-
- float4 r;
- int ix, iy, nix, niy;
- if(interpolation == INTERPOLATION_CLOSEST) {
- svm_image_texture_frac(x*width, &ix);
- svm_image_texture_frac(y*height, &iy);
-
- if(periodic) {
- ix = svm_image_texture_wrap_periodic(ix, width);
- iy = svm_image_texture_wrap_periodic(iy, height);
- }
- else {
- ix = svm_image_texture_wrap_clamp(ix, width);
- iy = svm_image_texture_wrap_clamp(iy, height);
-
- }
- r = svm_image_texture_read(kg, id, offset + ix + iy*width);
- }
- else { /* We default to linear interpolation if it is not closest */
- float tx = svm_image_texture_frac(x*width, &ix);
- float ty = svm_image_texture_frac(y*height, &iy);
-
- if(periodic) {
- ix = svm_image_texture_wrap_periodic(ix, width);
- iy = svm_image_texture_wrap_periodic(iy, height);
-
- nix = svm_image_texture_wrap_periodic(ix+1, width);
- niy = svm_image_texture_wrap_periodic(iy+1, height);
- }
- else {
- ix = svm_image_texture_wrap_clamp(ix, width);
- iy = svm_image_texture_wrap_clamp(iy, height);
-
- nix = svm_image_texture_wrap_clamp(ix+1, width);
- niy = svm_image_texture_wrap_clamp(iy+1, height);
- }
-
-
- r = (1.0f - ty)*(1.0f - tx)*svm_image_texture_read(kg, id, offset + ix + iy*width);
- r += (1.0f - ty)*tx*svm_image_texture_read(kg, id, offset + nix + iy*width);
- r += ty*(1.0f - tx)*svm_image_texture_read(kg, id, offset + ix + niy*width);
- r += ty*tx*svm_image_texture_read(kg, id, offset + nix + niy*width);
- }
-
- if(use_alpha && r.w != 1.0f && r.w != 0.0f) {
- float invw = 1.0f/r.w;
- r.x *= invw;
- r.y *= invw;
- r.z *= invw;
-
- if(id >= TEX_NUM_FLOAT4_IMAGES) {
- r.x = min(r.x, 1.0f);
- r.y = min(r.y, 1.0f);
- r.z = min(r.z, 1.0f);
- }
- }
-
- if(srgb) {
- r.x = color_srgb_to_scene_linear(r.x);
- r.y = color_srgb_to_scene_linear(r.y);
- r.z = color_srgb_to_scene_linear(r.z);
- }
-
- return r;
-}
-
-#else
-
ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, uint srgb, uint use_alpha)
{
#ifdef __KERNEL_CPU__
@@ -148,9 +39,12 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y,
# else
float4 r = kernel_tex_image_interp(id, x, y);
# endif
+#elif defined(__KERNEL_OPENCL__)
+ float4 r = kernel_tex_image_interp(kg, id, x, y);
#else
float4 r;
+# if __CUDA_ARCH__ < 300
/* not particularly proud of this massive switch, what are the
* alternatives?
* - use a single big 1D texture, and do our own lookup/filtering
@@ -251,75 +145,21 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y,
case 87: r = kernel_tex_image_interp(__tex_image_byte4_087, x, y); break;
case 88: r = kernel_tex_image_interp(__tex_image_byte4_088, x, y); break;
case 89: r = kernel_tex_image_interp(__tex_image_byte4_089, x, y); break;
- case 90: r = kernel_tex_image_interp(__tex_image_byte4_090, x, y); break;
- case 91: r = kernel_tex_image_interp(__tex_image_byte4_091, x, y); break;
- case 92: r = kernel_tex_image_interp(__tex_image_byte4_092, x, y); break;
-
-# if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 300)
- case 93: r = kernel_tex_image_interp(__tex_image_byte4_093, x, y); break;
- case 94: r = kernel_tex_image_interp(__tex_image_byte4_094, x, y); break;
- case 95: r = kernel_tex_image_interp(__tex_image_byte4_095, x, y); break;
- case 96: r = kernel_tex_image_interp(__tex_image_byte4_096, x, y); break;
- case 97: r = kernel_tex_image_interp(__tex_image_byte4_097, x, y); break;
- case 98: r = kernel_tex_image_interp(__tex_image_byte4_098, x, y); break;
- case 99: r = kernel_tex_image_interp(__tex_image_byte4_099, x, y); break;
- case 100: r = kernel_tex_image_interp(__tex_image_byte4_100, x, y); break;
- case 101: r = kernel_tex_image_interp(__tex_image_byte4_101, x, y); break;
- case 102: r = kernel_tex_image_interp(__tex_image_byte4_102, x, y); break;
- case 103: r = kernel_tex_image_interp(__tex_image_byte4_103, x, y); break;
- case 104: r = kernel_tex_image_interp(__tex_image_byte4_104, x, y); break;
- case 105: r = kernel_tex_image_interp(__tex_image_byte4_105, x, y); break;
- case 106: r = kernel_tex_image_interp(__tex_image_byte4_106, x, y); break;
- case 107: r = kernel_tex_image_interp(__tex_image_byte4_107, x, y); break;
- case 108: r = kernel_tex_image_interp(__tex_image_byte4_108, x, y); break;
- case 109: r = kernel_tex_image_interp(__tex_image_byte4_109, x, y); break;
- case 110: r = kernel_tex_image_interp(__tex_image_byte4_110, x, y); break;
- case 111: r = kernel_tex_image_interp(__tex_image_byte4_111, x, y); break;
- case 112: r = kernel_tex_image_interp(__tex_image_byte4_112, x, y); break;
- case 113: r = kernel_tex_image_interp(__tex_image_byte4_113, x, y); break;
- case 114: r = kernel_tex_image_interp(__tex_image_byte4_114, x, y); break;
- case 115: r = kernel_tex_image_interp(__tex_image_byte4_115, x, y); break;
- case 116: r = kernel_tex_image_interp(__tex_image_byte4_116, x, y); break;
- case 117: r = kernel_tex_image_interp(__tex_image_byte4_117, x, y); break;
- case 118: r = kernel_tex_image_interp(__tex_image_byte4_118, x, y); break;
- case 119: r = kernel_tex_image_interp(__tex_image_byte4_119, x, y); break;
- case 120: r = kernel_tex_image_interp(__tex_image_byte4_120, x, y); break;
- case 121: r = kernel_tex_image_interp(__tex_image_byte4_121, x, y); break;
- case 122: r = kernel_tex_image_interp(__tex_image_byte4_122, x, y); break;
- case 123: r = kernel_tex_image_interp(__tex_image_byte4_123, x, y); break;
- case 124: r = kernel_tex_image_interp(__tex_image_byte4_124, x, y); break;
- case 125: r = kernel_tex_image_interp(__tex_image_byte4_125, x, y); break;
- case 126: r = kernel_tex_image_interp(__tex_image_byte4_126, x, y); break;
- case 127: r = kernel_tex_image_interp(__tex_image_byte4_127, x, y); break;
- case 128: r = kernel_tex_image_interp(__tex_image_byte4_128, x, y); break;
- case 129: r = kernel_tex_image_interp(__tex_image_byte4_129, x, y); break;
- case 130: r = kernel_tex_image_interp(__tex_image_byte4_130, x, y); break;
- case 131: r = kernel_tex_image_interp(__tex_image_byte4_131, x, y); break;
- case 132: r = kernel_tex_image_interp(__tex_image_byte4_132, x, y); break;
- case 133: r = kernel_tex_image_interp(__tex_image_byte4_133, x, y); break;
- case 134: r = kernel_tex_image_interp(__tex_image_byte4_134, x, y); break;
- case 135: r = kernel_tex_image_interp(__tex_image_byte4_135, x, y); break;
- case 136: r = kernel_tex_image_interp(__tex_image_byte4_136, x, y); break;
- case 137: r = kernel_tex_image_interp(__tex_image_byte4_137, x, y); break;
- case 138: r = kernel_tex_image_interp(__tex_image_byte4_138, x, y); break;
- case 139: r = kernel_tex_image_interp(__tex_image_byte4_139, x, y); break;
- case 140: r = kernel_tex_image_interp(__tex_image_byte4_140, x, y); break;
- case 141: r = kernel_tex_image_interp(__tex_image_byte4_141, x, y); break;
- case 142: r = kernel_tex_image_interp(__tex_image_byte4_142, x, y); break;
- case 143: r = kernel_tex_image_interp(__tex_image_byte4_143, x, y); break;
- case 144: r = kernel_tex_image_interp(__tex_image_byte4_144, x, y); break;
- case 145: r = kernel_tex_image_interp(__tex_image_byte4_145, x, y); break;
- case 146: r = kernel_tex_image_interp(__tex_image_byte4_146, x, y); break;
- case 147: r = kernel_tex_image_interp(__tex_image_byte4_147, x, y); break;
- case 148: r = kernel_tex_image_interp(__tex_image_byte4_148, x, y); break;
- case 149: r = kernel_tex_image_interp(__tex_image_byte4_149, x, y); break;
- case 150: r = kernel_tex_image_interp(__tex_image_byte4_150, x, y); break;
-# endif
-
default:
kernel_assert(0);
return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
}
+# else
+ CUtexObject tex = kernel_tex_fetch(__bindless_mapping, id);
+ /* float4, byte4 and half4 */
+ if(id < TEX_START_FLOAT_CUDA_KEPLER)
+ r = kernel_tex_image_interp_float4(tex, x, y);
+ /* float, byte and half */
+ else {
+ float f = kernel_tex_image_interp_float(tex, x, y);
+ r = make_float4(f, f, f, 1.0f);
+ }
+# endif
#endif
#ifdef __KERNEL_SSE2__
@@ -360,8 +200,6 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y,
return r;
}
-#endif
-
/* Remap coordnate from 0..1 box to -1..-1 */
ccl_device_inline float3 texco_remap_square(float3 co)
{
diff --git a/intern/cycles/kernel/svm/svm_math_util.h b/intern/cycles/kernel/svm/svm_math_util.h
index 3f7d18a02fe..01547b60014 100644
--- a/intern/cycles/kernel/svm/svm_math_util.h
+++ b/intern/cycles/kernel/svm/svm_math_util.h
@@ -32,21 +32,17 @@ ccl_device void svm_vector_math(float *Fac, float3 *Vector, NodeVectorMath type,
*Fac = average_fac(*Vector);
}
else if(type == NODE_VECTOR_MATH_AVERAGE) {
- *Fac = len(Vector1 + Vector2);
- *Vector = normalize(Vector1 + Vector2);
+ *Vector = safe_normalize_len(Vector1 + Vector2, Fac);
}
else if(type == NODE_VECTOR_MATH_DOT_PRODUCT) {
*Fac = dot(Vector1, Vector2);
*Vector = make_float3(0.0f, 0.0f, 0.0f);
}
else if(type == NODE_VECTOR_MATH_CROSS_PRODUCT) {
- float3 c = cross(Vector1, Vector2);
- *Fac = len(c);
- *Vector = normalize(c);
+ *Vector = safe_normalize_len(cross(Vector1, Vector2), Fac);
}
else if(type == NODE_VECTOR_MATH_NORMALIZE) {
- *Fac = len(Vector1);
- *Vector = normalize(Vector1);
+ *Vector = safe_normalize_len(Vector1, Fac);
}
else {
*Fac = 0.0f;
@@ -168,6 +164,9 @@ ccl_device float3 svm_math_blackbody_color(float t) {
ccl_device_inline float3 svm_math_gamma_color(float3 color, float gamma)
{
+ if(gamma == 0.0f)
+ return make_float3(1.0f, 1.0f, 1.0f);
+
if(color.x > 0.0f)
color.x = powf(color.x, gamma);
if(color.y > 0.0f)
diff --git a/intern/cycles/kernel/svm/svm_mix.h b/intern/cycles/kernel/svm/svm_mix.h
index 7cbda111d81..022a68d1928 100644
--- a/intern/cycles/kernel/svm/svm_mix.h
+++ b/intern/cycles/kernel/svm/svm_mix.h
@@ -16,280 +16,6 @@
CCL_NAMESPACE_BEGIN
-ccl_device float3 svm_mix_blend(float t, float3 col1, float3 col2)
-{
- return interp(col1, col2, t);
-}
-
-ccl_device float3 svm_mix_add(float t, float3 col1, float3 col2)
-{
- return interp(col1, col1 + col2, t);
-}
-
-ccl_device float3 svm_mix_mul(float t, float3 col1, float3 col2)
-{
- return interp(col1, col1 * col2, t);
-}
-
-ccl_device float3 svm_mix_screen(float t, float3 col1, float3 col2)
-{
- float tm = 1.0f - t;
- float3 one = make_float3(1.0f, 1.0f, 1.0f);
- float3 tm3 = make_float3(tm, tm, tm);
-
- return one - (tm3 + t*(one - col2))*(one - col1);
-}
-
-ccl_device float3 svm_mix_overlay(float t, float3 col1, float3 col2)
-{
- float tm = 1.0f - t;
-
- float3 outcol = col1;
-
- if(outcol.x < 0.5f)
- outcol.x *= tm + 2.0f*t*col2.x;
- else
- outcol.x = 1.0f - (tm + 2.0f*t*(1.0f - col2.x))*(1.0f - outcol.x);
-
- if(outcol.y < 0.5f)
- outcol.y *= tm + 2.0f*t*col2.y;
- else
- outcol.y = 1.0f - (tm + 2.0f*t*(1.0f - col2.y))*(1.0f - outcol.y);
-
- if(outcol.z < 0.5f)
- outcol.z *= tm + 2.0f*t*col2.z;
- else
- outcol.z = 1.0f - (tm + 2.0f*t*(1.0f - col2.z))*(1.0f - outcol.z);
-
- return outcol;
-}
-
-ccl_device float3 svm_mix_sub(float t, float3 col1, float3 col2)
-{
- return interp(col1, col1 - col2, t);
-}
-
-ccl_device float3 svm_mix_div(float t, float3 col1, float3 col2)
-{
- float tm = 1.0f - t;
-
- float3 outcol = col1;
-
- if(col2.x != 0.0f) outcol.x = tm*outcol.x + t*outcol.x/col2.x;
- if(col2.y != 0.0f) outcol.y = tm*outcol.y + t*outcol.y/col2.y;
- if(col2.z != 0.0f) outcol.z = tm*outcol.z + t*outcol.z/col2.z;
-
- return outcol;
-}
-
-ccl_device float3 svm_mix_diff(float t, float3 col1, float3 col2)
-{
- return interp(col1, fabs(col1 - col2), t);
-}
-
-ccl_device float3 svm_mix_dark(float t, float3 col1, float3 col2)
-{
- return min(col1, col2)*t + col1*(1.0f - t);
-}
-
-ccl_device float3 svm_mix_light(float t, float3 col1, float3 col2)
-{
- return max(col1, col2*t);
-}
-
-ccl_device float3 svm_mix_dodge(float t, float3 col1, float3 col2)
-{
- float3 outcol = col1;
-
- if(outcol.x != 0.0f) {
- float tmp = 1.0f - t*col2.x;
- if(tmp <= 0.0f)
- outcol.x = 1.0f;
- else if((tmp = outcol.x/tmp) > 1.0f)
- outcol.x = 1.0f;
- else
- outcol.x = tmp;
- }
- if(outcol.y != 0.0f) {
- float tmp = 1.0f - t*col2.y;
- if(tmp <= 0.0f)
- outcol.y = 1.0f;
- else if((tmp = outcol.y/tmp) > 1.0f)
- outcol.y = 1.0f;
- else
- outcol.y = tmp;
- }
- if(outcol.z != 0.0f) {
- float tmp = 1.0f - t*col2.z;
- if(tmp <= 0.0f)
- outcol.z = 1.0f;
- else if((tmp = outcol.z/tmp) > 1.0f)
- outcol.z = 1.0f;
- else
- outcol.z = tmp;
- }
-
- return outcol;
-}
-
-ccl_device float3 svm_mix_burn(float t, float3 col1, float3 col2)
-{
- float tmp, tm = 1.0f - t;
-
- float3 outcol = col1;
-
- tmp = tm + t*col2.x;
- if(tmp <= 0.0f)
- outcol.x = 0.0f;
- else if((tmp = (1.0f - (1.0f - outcol.x)/tmp)) < 0.0f)
- outcol.x = 0.0f;
- else if(tmp > 1.0f)
- outcol.x = 1.0f;
- else
- outcol.x = tmp;
-
- tmp = tm + t*col2.y;
- if(tmp <= 0.0f)
- outcol.y = 0.0f;
- else if((tmp = (1.0f - (1.0f - outcol.y)/tmp)) < 0.0f)
- outcol.y = 0.0f;
- else if(tmp > 1.0f)
- outcol.y = 1.0f;
- else
- outcol.y = tmp;
-
- tmp = tm + t*col2.z;
- if(tmp <= 0.0f)
- outcol.z = 0.0f;
- else if((tmp = (1.0f - (1.0f - outcol.z)/tmp)) < 0.0f)
- outcol.z = 0.0f;
- else if(tmp > 1.0f)
- outcol.z = 1.0f;
- else
- outcol.z = tmp;
-
- return outcol;
-}
-
-ccl_device float3 svm_mix_hue(float t, float3 col1, float3 col2)
-{
- float3 outcol = col1;
-
- float3 hsv2 = rgb_to_hsv(col2);
-
- if(hsv2.y != 0.0f) {
- float3 hsv = rgb_to_hsv(outcol);
- hsv.x = hsv2.x;
- float3 tmp = hsv_to_rgb(hsv);
-
- outcol = interp(outcol, tmp, t);
- }
-
- return outcol;
-}
-
-ccl_device float3 svm_mix_sat(float t, float3 col1, float3 col2)
-{
- float tm = 1.0f - t;
-
- float3 outcol = col1;
-
- float3 hsv = rgb_to_hsv(outcol);
-
- if(hsv.y != 0.0f) {
- float3 hsv2 = rgb_to_hsv(col2);
-
- hsv.y = tm*hsv.y + t*hsv2.y;
- outcol = hsv_to_rgb(hsv);
- }
-
- return outcol;
-}
-
-ccl_device float3 svm_mix_val(float t, float3 col1, float3 col2)
-{
- float tm = 1.0f - t;
-
- float3 hsv = rgb_to_hsv(col1);
- float3 hsv2 = rgb_to_hsv(col2);
-
- hsv.z = tm*hsv.z + t*hsv2.z;
-
- return hsv_to_rgb(hsv);
-}
-
-ccl_device float3 svm_mix_color(float t, float3 col1, float3 col2)
-{
- float3 outcol = col1;
- float3 hsv2 = rgb_to_hsv(col2);
-
- if(hsv2.y != 0.0f) {
- float3 hsv = rgb_to_hsv(outcol);
- hsv.x = hsv2.x;
- hsv.y = hsv2.y;
- float3 tmp = hsv_to_rgb(hsv);
-
- outcol = interp(outcol, tmp, t);
- }
-
- return outcol;
-}
-
-ccl_device float3 svm_mix_soft(float t, float3 col1, float3 col2)
-{
- float tm = 1.0f - t;
-
- float3 one = make_float3(1.0f, 1.0f, 1.0f);
- float3 scr = one - (one - col2)*(one - col1);
-
- return tm*col1 + t*((one - col1)*col2*col1 + col1*scr);
-}
-
-ccl_device float3 svm_mix_linear(float t, float3 col1, float3 col2)
-{
- return col1 + t*(2.0f*col2 + make_float3(-1.0f, -1.0f, -1.0f));
-}
-
-ccl_device float3 svm_mix_clamp(float3 col)
-{
- float3 outcol = col;
-
- outcol.x = saturate(col.x);
- outcol.y = saturate(col.y);
- outcol.z = saturate(col.z);
-
- return outcol;
-}
-
-ccl_device_noinline float3 svm_mix(NodeMix type, float fac, float3 c1, float3 c2)
-{
- float t = saturate(fac);
-
- switch(type) {
- case NODE_MIX_BLEND: return svm_mix_blend(t, c1, c2);
- case NODE_MIX_ADD: return svm_mix_add(t, c1, c2);
- case NODE_MIX_MUL: return svm_mix_mul(t, c1, c2);
- case NODE_MIX_SCREEN: return svm_mix_screen(t, c1, c2);
- case NODE_MIX_OVERLAY: return svm_mix_overlay(t, c1, c2);
- case NODE_MIX_SUB: return svm_mix_sub(t, c1, c2);
- case NODE_MIX_DIV: return svm_mix_div(t, c1, c2);
- case NODE_MIX_DIFF: return svm_mix_diff(t, c1, c2);
- case NODE_MIX_DARK: return svm_mix_dark(t, c1, c2);
- case NODE_MIX_LIGHT: return svm_mix_light(t, c1, c2);
- case NODE_MIX_DODGE: return svm_mix_dodge(t, c1, c2);
- case NODE_MIX_BURN: return svm_mix_burn(t, c1, c2);
- case NODE_MIX_HUE: return svm_mix_hue(t, c1, c2);
- case NODE_MIX_SAT: return svm_mix_sat(t, c1, c2);
- case NODE_MIX_VAL: return svm_mix_val (t, c1, c2);
- case NODE_MIX_COLOR: return svm_mix_color(t, c1, c2);
- case NODE_MIX_SOFT: return svm_mix_soft(t, c1, c2);
- case NODE_MIX_LINEAR: return svm_mix_linear(t, c1, c2);
- case NODE_MIX_CLAMP: return svm_mix_clamp(c1);
- }
-
- return make_float3(0.0f, 0.0f, 0.0f);
-}
-
/* Node */
ccl_device void svm_node_mix(KernelGlobals *kg, ShaderData *sd, float *stack, uint fac_offset, uint c1_offset, uint c2_offset, int *offset)
diff --git a/intern/cycles/kernel/svm/svm_ramp.h b/intern/cycles/kernel/svm/svm_ramp.h
index 7e4106e212e..368740f64c7 100644
--- a/intern/cycles/kernel/svm/svm_ramp.h
+++ b/intern/cycles/kernel/svm/svm_ramp.h
@@ -19,11 +19,14 @@
CCL_NAMESPACE_BEGIN
-ccl_device float4 rgb_ramp_lookup(KernelGlobals *kg,
- int offset,
- float f,
- bool interpolate,
- bool extrapolate)
+/* NOTE: svm_ramp.h, svm_ramp_util.h and node_ramp_util.h must stay consistent */
+
+ccl_device_inline float4 rgb_ramp_lookup(KernelGlobals *kg,
+ int offset,
+ float f,
+ bool interpolate,
+ bool extrapolate,
+ int table_size)
{
if((f < 0.0f || f > 1.0f) && extrapolate) {
float4 t0, dy;
@@ -33,17 +36,17 @@ ccl_device float4 rgb_ramp_lookup(KernelGlobals *kg,
f = -f;
}
else {
- t0 = fetch_node_float(kg, offset + RAMP_TABLE_SIZE - 1);
- dy = t0 - fetch_node_float(kg, offset + RAMP_TABLE_SIZE - 2);
+ t0 = fetch_node_float(kg, offset + table_size - 1);
+ dy = t0 - fetch_node_float(kg, offset + table_size - 2);
f = f - 1.0f;
}
- return t0 + dy * f * (RAMP_TABLE_SIZE-1);
+ return t0 + dy * f * (table_size-1);
}
- f = saturate(f)*(RAMP_TABLE_SIZE-1);
+ f = saturate(f)*(table_size-1);
/* clamp int as well in case of NaN */
- int i = clamp(float_to_int(f), 0, RAMP_TABLE_SIZE-1);
+ int i = clamp(float_to_int(f), 0, table_size-1);
float t = f - (float)i;
float4 a = fetch_node_float(kg, offset+i);
@@ -61,18 +64,20 @@ ccl_device void svm_node_rgb_ramp(KernelGlobals *kg, ShaderData *sd, float *stac
decode_node_uchar4(node.y, &fac_offset, &color_offset, &alpha_offset, NULL);
+ uint table_size = read_node(kg, offset).x;
+
float fac = stack_load_float(stack, fac_offset);
- float4 color = rgb_ramp_lookup(kg, *offset, fac, interpolate, false);
+ float4 color = rgb_ramp_lookup(kg, *offset, fac, interpolate, false, table_size);
if(stack_valid(color_offset))
stack_store_float3(stack, color_offset, float4_to_float3(color));
if(stack_valid(alpha_offset))
stack_store_float(stack, alpha_offset, color.w);
- *offset += RAMP_TABLE_SIZE;
+ *offset += table_size;
}
-ccl_device void svm_node_rgb_curves(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset)
+ccl_device void svm_node_curves(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset)
{
uint fac_offset, color_offset, out_offset;
decode_node_uchar4(node.y,
@@ -81,32 +86,7 @@ ccl_device void svm_node_rgb_curves(KernelGlobals *kg, ShaderData *sd, float *st
&out_offset,
NULL);
- float fac = stack_load_float(stack, fac_offset);
- float3 color = stack_load_float3(stack, color_offset);
-
- const float min_x = __int_as_float(node.z),
- max_x = __int_as_float(node.w);
- const float range_x = max_x - min_x;
- color = (color - make_float3(min_x, min_x, min_x)) / range_x;
-
- float r = rgb_ramp_lookup(kg, *offset, color.x, true, true).x;
- float g = rgb_ramp_lookup(kg, *offset, color.y, true, true).y;
- float b = rgb_ramp_lookup(kg, *offset, color.z, true, true).z;
-
- color = (1.0f - fac)*color + fac*make_float3(r, g, b);
- stack_store_float3(stack, out_offset, color);
-
- *offset += RAMP_TABLE_SIZE;
-}
-
-ccl_device void svm_node_vector_curves(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset)
-{
- uint fac_offset, color_offset, out_offset;
- decode_node_uchar4(node.y,
- &fac_offset,
- &color_offset,
- &out_offset,
- NULL);
+ uint table_size = read_node(kg, offset).x;
float fac = stack_load_float(stack, fac_offset);
float3 color = stack_load_float3(stack, color_offset);
@@ -114,16 +94,16 @@ ccl_device void svm_node_vector_curves(KernelGlobals *kg, ShaderData *sd, float
const float min_x = __int_as_float(node.z),
max_x = __int_as_float(node.w);
const float range_x = max_x - min_x;
- color = (color - make_float3(min_x, min_x, min_x)) / range_x;
+ const float3 relpos = (color - make_float3(min_x, min_x, min_x)) / range_x;
- float r = rgb_ramp_lookup(kg, *offset, color.x, true, true).x;
- float g = rgb_ramp_lookup(kg, *offset, color.y, true, true).y;
- float b = rgb_ramp_lookup(kg, *offset, color.z, true, true).z;
+ float r = rgb_ramp_lookup(kg, *offset, relpos.x, true, true, table_size).x;
+ float g = rgb_ramp_lookup(kg, *offset, relpos.y, true, true, table_size).y;
+ float b = rgb_ramp_lookup(kg, *offset, relpos.z, true, true, table_size).z;
color = (1.0f - fac)*color + fac*make_float3(r, g, b);
stack_store_float3(stack, out_offset, color);
- *offset += RAMP_TABLE_SIZE;
+ *offset += table_size;
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_ramp_util.h b/intern/cycles/kernel/svm/svm_ramp_util.h
new file mode 100644
index 00000000000..b0adadae9b7
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_ramp_util.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __SVM_RAMP_UTIL_H__
+#define __SVM_RAMP_UTIL_H__
+
+CCL_NAMESPACE_BEGIN
+
+/* NOTE: svm_ramp.h, svm_ramp_util.h and node_ramp_util.h must stay consistent */
+
+ccl_device_inline float3 rgb_ramp_lookup(const float3 *ramp,
+ float f,
+ bool interpolate,
+ bool extrapolate,
+ int table_size)
+{
+ if((f < 0.0f || f > 1.0f) && extrapolate) {
+ float3 t0, dy;
+ if(f < 0.0f) {
+ t0 = ramp[0];
+ dy = t0 - ramp[1],
+ f = -f;
+ }
+ else {
+ t0 = ramp[table_size - 1];
+ dy = t0 - ramp[table_size - 2];
+ f = f - 1.0f;
+ }
+ return t0 + dy * f * (table_size - 1);
+ }
+
+ f = clamp(f, 0.0f, 1.0f) * (table_size - 1);
+
+ /* clamp int as well in case of NaN */
+ int i = clamp(float_to_int(f), 0, table_size-1);
+ float t = f - (float)i;
+
+ float3 result = ramp[i];
+
+ if(interpolate && t > 0.0f) {
+ result = (1.0f - t) * result + t * ramp[i + 1];
+ }
+
+ return result;
+}
+
+ccl_device float float_ramp_lookup(const float *ramp,
+ float f,
+ bool interpolate,
+ bool extrapolate,
+ int table_size)
+{
+ if((f < 0.0f || f > 1.0f) && extrapolate) {
+ float t0, dy;
+ if(f < 0.0f) {
+ t0 = ramp[0];
+ dy = t0 - ramp[1],
+ f = -f;
+ }
+ else {
+ t0 = ramp[table_size - 1];
+ dy = t0 - ramp[table_size - 2];
+ f = f - 1.0f;
+ }
+ return t0 + dy * f * (table_size - 1);
+ }
+
+ f = clamp(f, 0.0f, 1.0f) * (table_size - 1);
+
+ /* clamp int as well in case of NaN */
+ int i = clamp(float_to_int(f), 0, table_size-1);
+ float t = f - (float)i;
+
+ float result = ramp[i];
+
+ if(interpolate && t > 0.0f) {
+ result = (1.0f - t) * result + t * ramp[i + 1];
+ }
+
+ return result;
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __SVM_RAMP_UTIL_H__ */
+
diff --git a/intern/cycles/kernel/svm/svm_tex_coord.h b/intern/cycles/kernel/svm/svm_tex_coord.h
index 27fed89fdf7..6c3394adbce 100644
--- a/intern/cycles/kernel/svm/svm_tex_coord.h
+++ b/intern/cycles/kernel/svm/svm_tex_coord.h
@@ -49,7 +49,7 @@ ccl_device void svm_node_tex_coord(KernelGlobals *kg,
}
case NODE_TEXCO_NORMAL: {
data = ccl_fetch(sd, N);
- if(ccl_fetch(sd, object) != OBJECT_NONE)
+ if((ccl_fetch(sd, object) != OBJECT_NONE) || (ccl_fetch(sd, type) == PRIMITIVE_LAMP))
object_inverse_normal_transform(kg, sd, &data);
break;
}
@@ -99,12 +99,12 @@ ccl_device void svm_node_tex_coord(KernelGlobals *kg,
stack_store_float3(stack, out_offset, data);
}
-ccl_device_inline void svm_node_tex_coord_bump_dx(KernelGlobals *kg,
- ShaderData *sd,
- int path_flag,
- float *stack,
- uint4 node,
- int *offset)
+ccl_device void svm_node_tex_coord_bump_dx(KernelGlobals *kg,
+ ShaderData *sd,
+ int path_flag,
+ float *stack,
+ uint4 node,
+ int *offset)
{
#ifdef __RAY_DIFFERENTIALS__
float3 data;
@@ -131,7 +131,7 @@ ccl_device_inline void svm_node_tex_coord_bump_dx(KernelGlobals *kg,
}
case NODE_TEXCO_NORMAL: {
data = ccl_fetch(sd, N);
- if(ccl_fetch(sd, object) != OBJECT_NONE)
+ if((ccl_fetch(sd, object) != OBJECT_NONE) || (ccl_fetch(sd, type) == PRIMITIVE_LAMP))
object_inverse_normal_transform(kg, sd, &data);
break;
}
@@ -184,12 +184,12 @@ ccl_device_inline void svm_node_tex_coord_bump_dx(KernelGlobals *kg,
#endif
}
-ccl_device_inline void svm_node_tex_coord_bump_dy(KernelGlobals *kg,
- ShaderData *sd,
- int path_flag,
- float *stack,
- uint4 node,
- int *offset)
+ccl_device void svm_node_tex_coord_bump_dy(KernelGlobals *kg,
+ ShaderData *sd,
+ int path_flag,
+ float *stack,
+ uint4 node,
+ int *offset)
{
#ifdef __RAY_DIFFERENTIALS__
float3 data;
@@ -216,7 +216,7 @@ ccl_device_inline void svm_node_tex_coord_bump_dy(KernelGlobals *kg,
}
case NODE_TEXCO_NORMAL: {
data = ccl_fetch(sd, N);
- if(ccl_fetch(sd, object) != OBJECT_NONE)
+ if((ccl_fetch(sd, object) != OBJECT_NONE) || (ccl_fetch(sd, type) == PRIMITIVE_LAMP))
object_inverse_normal_transform(kg, sd, &data);
break;
}
@@ -277,6 +277,7 @@ ccl_device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *st
float3 color = stack_load_float3(stack, color_offset);
color = 2.0f*make_float3(color.x - 0.5f, color.y - 0.5f, color.z - 0.5f);
+ bool is_backfacing = (ccl_fetch(sd, flag) & SD_BACKFACING) != 0;
float3 N;
if(space == NODE_NORMAL_MAP_TANGENT) {
@@ -287,32 +288,37 @@ ccl_device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *st
}
/* first try to get tangent attribute */
- AttributeElement attr_elem, attr_sign_elem, attr_normal_elem;
- int attr_offset = find_attribute(kg, sd, node.z, &attr_elem);
- int attr_sign_offset = find_attribute(kg, sd, node.w, &attr_sign_elem);
- int attr_normal_offset = find_attribute(kg, sd, ATTR_STD_VERTEX_NORMAL, &attr_normal_elem);
+ const AttributeDescriptor attr = find_attribute(kg, sd, node.z);
+ const AttributeDescriptor attr_sign = find_attribute(kg, sd, node.w);
+ const AttributeDescriptor attr_normal = find_attribute(kg, sd, ATTR_STD_VERTEX_NORMAL);
- if(attr_offset == ATTR_STD_NOT_FOUND || attr_sign_offset == ATTR_STD_NOT_FOUND || attr_normal_offset == ATTR_STD_NOT_FOUND) {
+ if(attr.offset == ATTR_STD_NOT_FOUND || attr_sign.offset == ATTR_STD_NOT_FOUND || attr_normal.offset == ATTR_STD_NOT_FOUND) {
stack_store_float3(stack, normal_offset, make_float3(0.0f, 0.0f, 0.0f));
return;
}
/* get _unnormalized_ interpolated normal and tangent */
- float3 tangent = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL);
- float sign = primitive_attribute_float(kg, sd, attr_sign_elem, attr_sign_offset, NULL, NULL);
+ float3 tangent = primitive_attribute_float3(kg, sd, attr, NULL, NULL);
+ float sign = primitive_attribute_float(kg, sd, attr_sign, NULL, NULL);
float3 normal;
if(ccl_fetch(sd, shader) & SHADER_SMOOTH_NORMAL) {
- normal = primitive_attribute_float3(kg, sd, attr_normal_elem, attr_normal_offset, NULL, NULL);
+ normal = primitive_attribute_float3(kg, sd, attr_normal, NULL, NULL);
}
else {
normal = ccl_fetch(sd, Ng);
+
+ /* the normal is already inverted, which is too soon for the math here */
+ if(is_backfacing) {
+ normal = -normal;
+ }
+
object_inverse_normal_transform(kg, sd, &normal);
}
/* apply normal map */
float3 B = sign * cross(normal, tangent);
- N = normalize(color.x * tangent + color.y * B + color.z * normal);
+ N = safe_normalize(color.x * tangent + color.y * B + color.z * normal);
/* transform to world space */
object_normal_transform(kg, sd, &N);
@@ -330,14 +336,23 @@ ccl_device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *st
if(space == NODE_NORMAL_MAP_OBJECT || space == NODE_NORMAL_MAP_BLENDER_OBJECT)
object_normal_transform(kg, sd, &N);
else
- N = normalize(N);
+ N = safe_normalize(N);
+ }
+
+ /* invert normal for backfacing polygons */
+ if(is_backfacing) {
+ N = -N;
}
float strength = stack_load_float(stack, strength_offset);
if(strength != 1.0f) {
strength = max(strength, 0.0f);
- N = normalize(ccl_fetch(sd, N) + (N - ccl_fetch(sd, N))*strength);
+ N = safe_normalize(ccl_fetch(sd, N) + (N - ccl_fetch(sd, N))*strength);
+ }
+
+ if(is_zero(N)) {
+ N = ccl_fetch(sd, N);
}
stack_store_float3(stack, normal_offset, N);
@@ -352,24 +367,22 @@ ccl_device void svm_node_tangent(KernelGlobals *kg, ShaderData *sd, float *stack
if(direction_type == NODE_TANGENT_UVMAP) {
/* UV map */
- AttributeElement attr_elem;
- int attr_offset = find_attribute(kg, sd, node.z, &attr_elem);
+ const AttributeDescriptor desc = find_attribute(kg, sd, node.z);
- if(attr_offset == ATTR_STD_NOT_FOUND)
+ if(desc.offset == ATTR_STD_NOT_FOUND)
tangent = make_float3(0.0f, 0.0f, 0.0f);
else
- tangent = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL);
+ tangent = primitive_attribute_float3(kg, sd, desc, NULL, NULL);
}
else {
/* radial */
- AttributeElement attr_elem;
- int attr_offset = find_attribute(kg, sd, node.z, &attr_elem);
+ const AttributeDescriptor desc = find_attribute(kg, sd, node.z);
float3 generated;
- if(attr_offset == ATTR_STD_NOT_FOUND)
+ if(desc.offset == ATTR_STD_NOT_FOUND)
generated = ccl_fetch(sd, P);
else
- generated = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL);
+ generated = primitive_attribute_float3(kg, sd, desc, NULL, NULL);
if(axis == NODE_TANGENT_AXIS_X)
tangent = make_float3(0.0f, -(generated.z - 0.5f), (generated.y - 0.5f));
diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h
index bbfc608ecbf..9867390f074 100644
--- a/intern/cycles/kernel/svm/svm_types.h
+++ b/intern/cycles/kernel/svm/svm_types.h
@@ -26,6 +26,8 @@ CCL_NAMESPACE_BEGIN
/* SVM stack offsets with this value indicate that it's not on the stack */
#define SVM_STACK_INVALID 255
+#define SVM_BUMP_EVAL_STATE_SIZE 9
+
/* Nodes */
/* Known frequencies of used nodes, used for selective nodes compilation
@@ -45,13 +47,14 @@ CCL_NAMESPACE_BEGIN
#define NODE_FEATURE_VOLUME (1 << 0)
#define NODE_FEATURE_HAIR (1 << 1)
#define NODE_FEATURE_BUMP (1 << 2)
+#define NODE_FEATURE_BUMP_STATE (1 << 3)
/* TODO(sergey): Consider using something like ((uint)(-1)).
* Need to check carefully operand types around usage of this
* define first.
*/
-#define NODE_FEATURE_ALL (NODE_FEATURE_VOLUME|NODE_FEATURE_HAIR|NODE_FEATURE_BUMP)
+#define NODE_FEATURE_ALL (NODE_FEATURE_VOLUME|NODE_FEATURE_HAIR|NODE_FEATURE_BUMP|NODE_FEATURE_BUMP_STATE)
-typedef enum NodeType {
+typedef enum ShaderNodeType {
NODE_END = 0,
NODE_CLOSURE_BSDF,
NODE_CLOSURE_EMISSION,
@@ -127,8 +130,10 @@ typedef enum NodeType {
NODE_HAIR_INFO,
NODE_UVMAP,
NODE_TEX_VOXEL,
+ NODE_ENTER_BUMP_EVAL,
+ NODE_LEAVE_BUMP_EVAL,
NODE_OPENVDB,
-} NodeType;
+} ShaderNodeType;
typedef enum NodeAttributeType {
NODE_ATTR_FLOAT = 0,
@@ -344,6 +349,11 @@ typedef enum NodeNormalMapSpace {
NODE_NORMAL_MAP_BLENDER_WORLD,
} NodeNormalMapSpace;
+typedef enum NodeImageColorSpace {
+ NODE_COLOR_SPACE_NONE = 0,
+ NODE_COLOR_SPACE_COLOR = 1,
+} NodeImageColorSpace;
+
typedef enum NodeImageProjection {
NODE_IMAGE_PROJ_FLAT = 0,
NODE_IMAGE_PROJ_BOX = 1,
@@ -351,6 +361,11 @@ typedef enum NodeImageProjection {
NODE_IMAGE_PROJ_TUBE = 3,
} NodeImageProjection;
+typedef enum NodeEnvironmentProjection {
+ NODE_ENVIRONMENT_EQUIRECTANGULAR = 0,
+ NODE_ENVIRONMENT_MIRROR_BALL = 1,
+} NodeEnvironmentProjection;
+
typedef enum NodeBumpOffset {
NODE_BUMP_OFFSET_CENTER,
NODE_BUMP_OFFSET_DX,
@@ -370,12 +385,16 @@ typedef enum NodeOpenVDBType {
typedef enum ShaderType {
SHADER_TYPE_SURFACE,
SHADER_TYPE_VOLUME,
- SHADER_TYPE_DISPLACEMENT
+ SHADER_TYPE_DISPLACEMENT,
+ SHADER_TYPE_BUMP,
} ShaderType;
/* Closure */
typedef enum ClosureType {
+ /* Special type, flags generic node as a non-BSDF. */
+ CLOSURE_NONE_ID,
+
CLOSURE_BSDF_ID,
/* Diffuse */
@@ -389,8 +408,10 @@ typedef enum ClosureType {
CLOSURE_BSDF_REFLECTION_ID,
CLOSURE_BSDF_MICROFACET_GGX_ID,
CLOSURE_BSDF_MICROFACET_BECKMANN_ID,
+ CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID,
CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID,
CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID,
+ CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID,
CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID,
CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID,
CLOSURE_BSDF_ASHIKHMIN_VELVET_ID,
@@ -406,6 +427,7 @@ typedef enum ClosureType {
CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID,
CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID,
CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID,
+ CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID,
CLOSURE_BSDF_SHARP_GLASS_ID,
CLOSURE_BSDF_HAIR_TRANSMISSION_ID,
@@ -439,6 +461,9 @@ typedef enum ClosureType {
#define CLOSURE_IS_BSDF_TRANSMISSION(type) (type >= CLOSURE_BSDF_TRANSMISSION_ID && type <= CLOSURE_BSDF_HAIR_TRANSMISSION_ID)
#define CLOSURE_IS_BSDF_BSSRDF(type) (type == CLOSURE_BSDF_BSSRDF_ID)
#define CLOSURE_IS_BSDF_ANISOTROPIC(type) (type >= CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID && type <= CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID)
+#define CLOSURE_IS_BSDF_MULTISCATTER(type) (type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID ||\
+ type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID || \
+ type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID)
#define CLOSURE_IS_BSDF_OR_BSSRDF(type) (type <= CLOSURE_BSSRDF_BURLEY_ID)
#define CLOSURE_IS_BSSRDF(type) (type >= CLOSURE_BSSRDF_CUBIC_ID && type <= CLOSURE_BSSRDF_BURLEY_ID)
#define CLOSURE_IS_VOLUME(type) (type >= CLOSURE_VOLUME_ID && type <= CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID)
diff --git a/intern/cycles/kernel/svm/svm_voxel.h b/intern/cycles/kernel/svm/svm_voxel.h
index 85ba2f906fa..a8b3604a8a7 100644
--- a/intern/cycles/kernel/svm/svm_voxel.h
+++ b/intern/cycles/kernel/svm/svm_voxel.h
@@ -42,11 +42,24 @@ ccl_device void svm_node_tex_voxel(KernelGlobals *kg,
tfm.w = read_node_float(kg, offset);
co = transform_point(&tfm, co);
}
-# if defined(__KERNEL_GPU__)
- float4 r = volume_image_texture_3d(id, co.x, co.y, co.z);
+ float4 r;
+# if defined(__KERNEL_CUDA__)
+# if __CUDA_ARCH__ >= 300
+ CUtexObject tex = kernel_tex_fetch(__bindless_mapping, id);
+ if(id < 2048) /* TODO(dingto): Make this a variable */
+ r = kernel_tex_image_interp_3d_float4(tex, co.x, co.y, co.z);
+ else {
+ float f = kernel_tex_image_interp_3d_float(tex, co.x, co.y, co.z);
+ r = make_float4(f, f, f, 1.0f);
+ }
+# else /* __CUDA_ARCH__ >= 300 */
+ r = volume_image_texture_3d(id, co.x, co.y, co.z);
+# endif
+# elif defined(__KERNEL_OPENCL__)
+ r = kernel_tex_image_interp_3d(kg, id, co.x, co.y, co.z);
# else
- float4 r = kernel_tex_image_interp_3d(id, co.x, co.y, co.z);
-# endif
+ r = kernel_tex_image_interp_3d(id, co.x, co.y, co.z);
+# endif /* __KERNEL_CUDA__ */
#else
float4 r = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
#endif
diff --git a/intern/cycles/kernel/svm/svm_wireframe.h b/intern/cycles/kernel/svm/svm_wireframe.h
index 30ccd523add..6eed9bc1a99 100644
--- a/intern/cycles/kernel/svm/svm_wireframe.h
+++ b/intern/cycles/kernel/svm/svm_wireframe.h
@@ -34,11 +34,11 @@ CCL_NAMESPACE_BEGIN
/* Wireframe Node */
-ccl_device float wireframe(KernelGlobals *kg,
- ShaderData *sd,
- float size,
- int pixel_size,
- float3 *P)
+ccl_device_inline float wireframe(KernelGlobals *kg,
+ ShaderData *sd,
+ float size,
+ int pixel_size,
+ float3 *P)
{
#ifdef __HAIR__
if(ccl_fetch(sd, prim) != PRIM_NONE && ccl_fetch(sd, type) & PRIMITIVE_ALL_TRIANGLE)
diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt
index fa09de01de5..2bb3515cb2b 100644
--- a/intern/cycles/render/CMakeLists.txt
+++ b/intern/cycles/render/CMakeLists.txt
@@ -2,6 +2,7 @@
set(INC
.
../device
+ ../graph
../kernel
../kernel/svm
../kernel/osl
@@ -27,6 +28,7 @@ set(SRC
bake.cpp
buffers.cpp
camera.cpp
+ constant_fold.cpp
film.cpp
graph.cpp
image.cpp
@@ -34,6 +36,7 @@ set(SRC
light.cpp
mesh.cpp
mesh_displace.cpp
+ mesh_subdivision.cpp
nodes.cpp
object.cpp
osl.cpp
@@ -55,6 +58,7 @@ set(SRC_HEADERS
background.h
buffers.h
camera.h
+ constant_fold.h
film.h
graph.h
image.h
diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp
index b7de83d89c1..c0d429a583c 100644
--- a/intern/cycles/render/attribute.cpp
+++ b/intern/cycles/render/attribute.cpp
@@ -44,6 +44,7 @@ void Attribute::set(ustring name_, TypeDesc type_, AttributeElement element_)
type = type_;
element = element_;
std = ATTR_STD_NONE;
+ flags = 0;
/* string and matrix not supported! */
assert(type == TypeDesc::TypeFloat || type == TypeDesc::TypeColor ||
@@ -51,16 +52,21 @@ void Attribute::set(ustring name_, TypeDesc type_, AttributeElement element_)
type == TypeDesc::TypeNormal || type == TypeDesc::TypeMatrix);
}
-void Attribute::reserve(int numverts, int numtris, int numsteps, int numcurves, int numkeys, bool resize)
+void Attribute::resize(Mesh *mesh, AttributePrimitive prim, bool reserve_only)
{
- if(resize) {
- buffer.resize(buffer_size(numverts, numtris, numsteps, numcurves, numkeys), 0);
+ if(reserve_only) {
+ buffer.reserve(buffer_size(mesh, prim));
}
else {
- buffer.reserve(buffer_size(numverts, numtris, numsteps, numcurves, numkeys));
+ buffer.resize(buffer_size(mesh, prim), 0);
}
}
+void Attribute::resize(size_t num_elements)
+{
+ buffer.resize(num_elements * data_sizeof(), 0);
+}
+
void Attribute::add(const float& f)
{
char *data = (char*)&f;
@@ -118,6 +124,8 @@ size_t Attribute::data_sizeof() const
{
if(element == ATTR_ELEMENT_VOXEL)
return sizeof(VoxelAttribute);
+ else if(element == ATTR_ELEMENT_CORNER_BYTE)
+ return sizeof(uchar4);
else if(type == TypeDesc::TypeFloat)
return sizeof(float);
else if(type == TypeDesc::TypeMatrix)
@@ -126,10 +134,14 @@ size_t Attribute::data_sizeof() const
return sizeof(float3);
}
-size_t Attribute::element_size(int numverts, int numtris, int numsteps, int numcurves, int numkeys) const
+size_t Attribute::element_size(Mesh *mesh, AttributePrimitive prim) const
{
+ if(flags & ATTR_FINAL_SIZE) {
+ return buffer.size() / data_sizeof();
+ }
+
size_t size;
-
+
switch(element) {
case ATTR_ELEMENT_OBJECT:
case ATTR_ELEMENT_MESH:
@@ -137,38 +149,54 @@ size_t Attribute::element_size(int numverts, int numtris, int numsteps, int numc
size = 1;
break;
case ATTR_ELEMENT_VERTEX:
- size = numverts;
+ size = mesh->verts.size() + mesh->num_ngons;
+ if(prim == ATTR_PRIM_SUBD) {
+ size -= mesh->num_subd_verts;
+ }
break;
case ATTR_ELEMENT_VERTEX_MOTION:
- size = numverts * (numsteps - 1);
+ size = (mesh->verts.size() + mesh->num_ngons) * (mesh->motion_steps - 1);
+ if(prim == ATTR_PRIM_SUBD) {
+ size -= mesh->num_subd_verts * (mesh->motion_steps - 1);
+ }
break;
case ATTR_ELEMENT_FACE:
- size = numtris;
+ if(prim == ATTR_PRIM_TRIANGLE) {
+ size = mesh->num_triangles();
+ }
+ else {
+ size = mesh->subd_faces.size() + mesh->num_ngons;
+ }
break;
case ATTR_ELEMENT_CORNER:
case ATTR_ELEMENT_CORNER_BYTE:
- size = numtris*3;
+ if(prim == ATTR_PRIM_TRIANGLE) {
+ size = mesh->num_triangles()*3;
+ }
+ else {
+ size = mesh->subd_face_corners.size() + mesh->num_ngons;
+ }
break;
case ATTR_ELEMENT_CURVE:
- size = numcurves;
+ size = mesh->num_curves();
break;
case ATTR_ELEMENT_CURVE_KEY:
- size = numkeys;
+ size = mesh->curve_keys.size();
break;
case ATTR_ELEMENT_CURVE_KEY_MOTION:
- size = numkeys * (numsteps - 1);
+ size = mesh->curve_keys.size() * (mesh->motion_steps - 1);
break;
default:
size = 0;
break;
}
-
+
return size;
}
-size_t Attribute::buffer_size(int numverts, int numtris, int numsteps, int numcurves, int numkeys) const
+size_t Attribute::buffer_size(Mesh *mesh, AttributePrimitive prim) const
{
- return element_size(numverts, numtris, numsteps, numcurves, numkeys)*data_sizeof();
+ return element_size(mesh, prim)*data_sizeof();
}
bool Attribute::same_storage(TypeDesc a, TypeDesc b)
@@ -188,6 +216,29 @@ bool Attribute::same_storage(TypeDesc a, TypeDesc b)
return false;
}
+void Attribute::zero_data(void* dst)
+{
+ memset(dst, 0, data_sizeof());
+}
+
+void Attribute::add_with_weight(void* dst, void* src, float weight)
+{
+ if(element == ATTR_ELEMENT_CORNER_BYTE) {
+ for(int i = 0; i < 4; i++) {
+ ((uchar*)dst)[i] += uchar(((uchar*)src)[i] * weight);
+ }
+ }
+ else if(same_storage(type, TypeDesc::TypeFloat)) {
+ *((float*)dst) += *((float*)src) * weight;
+ }
+ else if(same_storage(type, TypeDesc::TypeVector)) {
+ *((float4*)dst) += *((float4*)src) * weight;
+ }
+ else {
+ assert(!"not implemented for this type");
+ }
+}
+
const char *Attribute::standard_name(AttributeStandard std)
{
switch(std) {
@@ -257,13 +308,14 @@ AttributeSet::AttributeSet()
{
triangle_mesh = NULL;
curve_mesh = NULL;
+ subd_mesh = NULL;
}
AttributeSet::~AttributeSet()
{
}
-Attribute *AttributeSet::add(ustring name, TypeDesc type, AttributeElement element, bool resize)
+Attribute *AttributeSet::add(ustring name, TypeDesc type, AttributeElement element)
{
Attribute *attr = find(name);
@@ -291,10 +343,12 @@ Attribute *AttributeSet::add(ustring name, TypeDesc type, AttributeElement eleme
/* this is weak .. */
if(triangle_mesh)
- attr->reserve(triangle_mesh->verts.size(), triangle_mesh->triangles.size(), triangle_mesh->motion_steps, 0, 0, resize);
+ attr->resize(triangle_mesh, ATTR_PRIM_TRIANGLE, false);
if(curve_mesh)
- attr->reserve(0, 0, curve_mesh->motion_steps, curve_mesh->curves.size(), curve_mesh->curve_keys.size(), resize);
-
+ attr->resize(curve_mesh, ATTR_PRIM_CURVE, false);
+ if(subd_mesh)
+ attr->resize(subd_mesh, ATTR_PRIM_SUBD, false);
+
return attr;
}
@@ -330,7 +384,7 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name)
if(name == ustring())
name = Attribute::standard_name(std);
- if(triangle_mesh) {
+ if(triangle_mesh || subd_mesh) {
switch(std) {
case ATTR_STD_VERTEX_NORMAL:
attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_VERTEX);
@@ -448,13 +502,15 @@ Attribute *AttributeSet::find(AttributeRequest& req)
return find(req.std);
}
-void AttributeSet::reserve()
+void AttributeSet::resize(bool reserve_only)
{
foreach(Attribute& attr, attributes) {
if(triangle_mesh)
- attr.reserve(triangle_mesh->verts.size(), triangle_mesh->triangles.size(), triangle_mesh->motion_steps, 0, 0, true);
+ attr.resize(triangle_mesh, ATTR_PRIM_TRIANGLE, reserve_only);
if(curve_mesh)
- attr.reserve(0, 0, 0, curve_mesh->curves.size(), curve_mesh->curve_keys.size(), true);
+ attr.resize(curve_mesh, ATTR_PRIM_CURVE, reserve_only);
+ if(subd_mesh)
+ attr.resize(subd_mesh, ATTR_PRIM_SUBD, reserve_only);
}
}
@@ -471,12 +527,19 @@ AttributeRequest::AttributeRequest(ustring name_)
std = ATTR_STD_NONE;
triangle_type = TypeDesc::TypeFloat;
- triangle_element = ATTR_ELEMENT_NONE;
- triangle_offset = 0;
+ triangle_desc.element = ATTR_ELEMENT_NONE;
+ triangle_desc.offset = 0;
+ triangle_desc.type = NODE_ATTR_FLOAT;
curve_type = TypeDesc::TypeFloat;
- curve_element = ATTR_ELEMENT_NONE;
- curve_offset = 0;
+ curve_desc.element = ATTR_ELEMENT_NONE;
+ curve_desc.offset = 0;
+ curve_desc.type = NODE_ATTR_FLOAT;
+
+ subd_type = TypeDesc::TypeFloat;
+ subd_desc.element = ATTR_ELEMENT_NONE;
+ subd_desc.offset = 0;
+ subd_desc.type = NODE_ATTR_FLOAT;
}
AttributeRequest::AttributeRequest(AttributeStandard std_)
@@ -485,12 +548,19 @@ AttributeRequest::AttributeRequest(AttributeStandard std_)
std = std_;
triangle_type = TypeDesc::TypeFloat;
- triangle_element = ATTR_ELEMENT_NONE;
- triangle_offset = 0;
+ triangle_desc.element = ATTR_ELEMENT_NONE;
+ triangle_desc.offset = 0;
+ triangle_desc.type = NODE_ATTR_FLOAT;
curve_type = TypeDesc::TypeFloat;
- curve_element = ATTR_ELEMENT_NONE;
- curve_offset = 0;
+ curve_desc.element = ATTR_ELEMENT_NONE;
+ curve_desc.offset = 0;
+ curve_desc.type = NODE_ATTR_FLOAT;
+
+ subd_type = TypeDesc::TypeFloat;
+ subd_desc.element = ATTR_ELEMENT_NONE;
+ subd_desc.offset = 0;
+ subd_desc.type = NODE_ATTR_FLOAT;
}
/* AttributeRequestSet */
diff --git a/intern/cycles/render/attribute.h b/intern/cycles/render/attribute.h
index bbc6cf7f65f..f4538c76369 100644
--- a/intern/cycles/render/attribute.h
+++ b/intern/cycles/render/attribute.h
@@ -54,15 +54,17 @@ public:
TypeDesc type;
vector<char> buffer;
AttributeElement element;
+ uint flags; /* enum AttributeFlag */
Attribute() {}
~Attribute();
void set(ustring name, TypeDesc type, AttributeElement element);
- void reserve(int numverts, int numfaces, int numsteps, int numcurves, int numkeys, bool resize);
+ void resize(Mesh *mesh, AttributePrimitive prim, bool reserve_only);
+ void resize(size_t num_elements);
size_t data_sizeof() const;
- size_t element_size(int numverts, int numfaces, int numsteps, int numcurves, int numkeys) const;
- size_t buffer_size(int numverts, int numfaces, int numsteps, int numcurves, int numkeys) const;
+ size_t element_size(Mesh *mesh, AttributePrimitive prim) const;
+ size_t buffer_size(Mesh *mesh, AttributePrimitive prim) const;
char *data() { return (buffer.size())? &buffer[0]: NULL; };
float3 *data_float3() { return (float3*)data(); }
@@ -79,6 +81,9 @@ public:
const Transform *data_transform() const { return (const Transform*)data(); }
const VoxelAttribute *data_voxel() const { return (const VoxelAttribute*)data(); }
+ void zero_data(void* dst);
+ void add_with_weight(void* dst, void* src, float weight);
+
void add(const float& f);
void add(const float3& f);
void add(const uchar4& f);
@@ -99,12 +104,13 @@ class AttributeSet {
public:
Mesh *triangle_mesh;
Mesh *curve_mesh;
+ Mesh *subd_mesh;
list<Attribute> attributes;
AttributeSet();
~AttributeSet();
- Attribute *add(ustring name, TypeDesc type, AttributeElement element, bool resize = true);
+ Attribute *add(ustring name, TypeDesc type, AttributeElement element);
Attribute *find(ustring name) const;
void remove(ustring name);
@@ -114,7 +120,7 @@ public:
Attribute *find(AttributeRequest& req);
- void reserve();
+ void resize(bool reserve_only = false);
void clear();
};
@@ -130,12 +136,11 @@ public:
AttributeStandard std;
/* temporary variables used by MeshManager */
- TypeDesc triangle_type, curve_type;
- AttributeElement triangle_element, curve_element;
- int triangle_offset, curve_offset;
+ TypeDesc triangle_type, curve_type, subd_type;
+ AttributeDescriptor triangle_desc, curve_desc, subd_desc;
- AttributeRequest(ustring name_);
- AttributeRequest(AttributeStandard std);
+ explicit AttributeRequest(ustring name_);
+ explicit AttributeRequest(AttributeStandard std);
};
/* AttributeRequestSet
diff --git a/intern/cycles/render/background.cpp b/intern/cycles/render/background.cpp
index 0cd164dc03e..8d7d7b847fd 100644
--- a/intern/cycles/render/background.cpp
+++ b/intern/cycles/render/background.cpp
@@ -28,18 +28,26 @@
CCL_NAMESPACE_BEGIN
-Background::Background()
+NODE_DEFINE(Background)
{
- ao_factor = 0.0f;
- ao_distance = FLT_MAX;
+ NodeType* type = NodeType::add("background", create);
+
+ SOCKET_FLOAT(ao_factor, "AO Factor", 0.0f);
+ SOCKET_FLOAT(ao_distance, "AO Distance", FLT_MAX);
- use_shader = true;
- use_ao = false;
+ SOCKET_BOOLEAN(use_shader, "Use Shader", true);
+ SOCKET_BOOLEAN(use_ao, "Use AO", false);
+ SOCKET_UINT(visibility, "Visibility", PATH_RAY_ALL_VISIBILITY);
+ SOCKET_BOOLEAN(transparent, "Transparent", false);
- visibility = PATH_RAY_ALL_VISIBILITY;
- shader = 0;
+ SOCKET_NODE(shader, "Shader", &Shader::node_type);
+
+ return type;
+}
- transparent = false;
+Background::Background()
+: Node(node_type)
+{
need_update = true;
}
@@ -54,10 +62,14 @@ void Background::device_update(Device *device, DeviceScene *dscene, Scene *scene
device_free(device, dscene);
- if(use_shader)
- shader = scene->default_background;
+ Shader *bg_shader = shader;
+
+ if(use_shader) {
+ if(!bg_shader)
+ bg_shader = scene->default_background;
+ }
else
- shader = scene->default_empty;
+ bg_shader = scene->default_empty;
/* set shader index and transparent option */
KernelBackground *kbackground = &dscene->data.background;
@@ -72,15 +84,15 @@ void Background::device_update(Device *device, DeviceScene *dscene, Scene *scene
}
kbackground->transparent = transparent;
- kbackground->surface_shader = scene->shader_manager->get_shader_id(shader);
+ kbackground->surface_shader = scene->shader_manager->get_shader_id(bg_shader);
- if(scene->shaders[shader]->has_volume)
+ if(bg_shader->has_volume)
kbackground->volume_shader = kbackground->surface_shader;
else
kbackground->volume_shader = SHADER_NONE;
/* No background node, make world shader invisible to all rays, to skip evaluation in kernel. */
- if(scene->shaders[shader]->graph->nodes.size() <= 1) {
+ if(bg_shader->graph->nodes.size() <= 1) {
kbackground->surface_shader |= SHADER_EXCLUDE_ANY;
}
/* Background present, check visibilities */
@@ -106,12 +118,7 @@ void Background::device_free(Device * /*device*/, DeviceScene * /*dscene*/)
bool Background::modified(const Background& background)
{
- return !(transparent == background.transparent &&
- use_shader == background.use_shader &&
- use_ao == background.use_ao &&
- ao_factor == background.ao_factor &&
- ao_distance == background.ao_distance &&
- visibility == background.visibility);
+ return !Node::equals(background);
}
void Background::tag_update(Scene *scene)
diff --git a/intern/cycles/render/background.h b/intern/cycles/render/background.h
index 8bf97f5d6f7..8029c6a9e80 100644
--- a/intern/cycles/render/background.h
+++ b/intern/cycles/render/background.h
@@ -17,6 +17,8 @@
#ifndef __BACKGROUND_H__
#define __BACKGROUND_H__
+#include "node.h"
+
#include "util_types.h"
CCL_NAMESPACE_BEGIN
@@ -24,9 +26,12 @@ CCL_NAMESPACE_BEGIN
class Device;
class DeviceScene;
class Scene;
+class Shader;
-class Background {
+class Background : public Node {
public:
+ NODE_DECLARE;
+
float ao_factor;
float ao_distance;
@@ -34,7 +39,7 @@ public:
bool use_ao;
uint visibility;
- uint shader;
+ Shader *shader;
bool transparent;
bool need_update;
diff --git a/intern/cycles/render/bake.cpp b/intern/cycles/render/bake.cpp
index 5bf5e5113ef..13310a61761 100644
--- a/intern/cycles/render/bake.cpp
+++ b/intern/cycles/render/bake.cpp
@@ -177,7 +177,7 @@ bool BakeManager::bake(Device *device, DeviceScene *dscene, Scene *scene, Progre
device->mem_alloc(d_input, MEM_READ_ONLY);
device->mem_copy_to(d_input);
- device->mem_alloc(d_output, MEM_WRITE_ONLY);
+ device->mem_alloc(d_output, MEM_READ_WRITE);
DeviceTask task(DeviceTask::SHADER);
task.shader_input = d_input.device_pointer;
diff --git a/intern/cycles/render/buffers.cpp b/intern/cycles/render/buffers.cpp
index 0d62c1b72de..1e170d3a96e 100644
--- a/intern/cycles/render/buffers.cpp
+++ b/intern/cycles/render/buffers.cpp
@@ -66,8 +66,8 @@ int BufferParams::get_passes_size()
{
int size = 0;
- foreach(Pass& pass, passes)
- size += pass.components;
+ for(size_t i = 0; i < passes.size(); i++)
+ size += passes[i].components;
return align_up(size, 4);
}
@@ -160,7 +160,9 @@ bool RenderBuffers::get_pass_rect(PassType type, float exposure, int sample, int
{
int pass_offset = 0;
- foreach(Pass& pass, params.passes) {
+ for(size_t j = 0; j < params.passes.size(); j++) {
+ Pass& pass = params.passes[j];
+
if(pass.type != type) {
pass_offset += pass.components;
continue;
@@ -194,13 +196,13 @@ bool RenderBuffers::get_pass_rect(PassType type, float exposure, int sample, int
else if(type == PASS_BVH_TRAVERSAL_STEPS) {
for(int i = 0; i < size; i++, in += pass_stride, pixels++) {
float f = *in;
- pixels[0] = f;
+ pixels[0] = f*scale;
}
}
else if(type == PASS_RAY_BOUNCES) {
for(int i = 0; i < size; i++, in += pass_stride, pixels++) {
float f = *in;
- pixels[0] = f;
+ pixels[0] = f*scale;
}
}
#endif
@@ -228,7 +230,8 @@ bool RenderBuffers::get_pass_rect(PassType type, float exposure, int sample, int
else if(pass.divide_type != PASS_NONE) {
/* RGB lighting passes that need to divide out color */
pass_offset = 0;
- foreach(Pass& color_pass, params.passes) {
+ for(size_t k = 0; k < params.passes.size(); k++) {
+ Pass& color_pass = params.passes[k];
if(color_pass.type == pass.divide_type)
break;
pass_offset += color_pass.components;
@@ -276,7 +279,8 @@ bool RenderBuffers::get_pass_rect(PassType type, float exposure, int sample, int
else if(type == PASS_MOTION) {
/* need to normalize by number of samples accumulated for motion */
pass_offset = 0;
- foreach(Pass& color_pass, params.passes) {
+ for(size_t k = 0; k < params.passes.size(); k++) {
+ Pass& color_pass = params.passes[k];
if(color_pass.type == PASS_MOTION_WEIGHT)
break;
pass_offset += color_pass.components;
diff --git a/intern/cycles/render/buffers.h b/intern/cycles/render/buffers.h
index 4fa1c51d821..c9c2a21079a 100644
--- a/intern/cycles/render/buffers.h
+++ b/intern/cycles/render/buffers.h
@@ -50,7 +50,7 @@ public:
int full_height;
/* passes */
- vector<Pass> passes;
+ array<Pass> passes;
/* functions */
BufferParams();
@@ -73,7 +73,7 @@ public:
/* random number generator state */
device_vector<uint> rng_state;
- RenderBuffers(Device *device);
+ explicit RenderBuffers(Device *device);
~RenderBuffers();
void reset(Device *device, BufferParams& params);
diff --git a/intern/cycles/render/camera.cpp b/intern/cycles/render/camera.cpp
index ad96473e5d2..c8c51ec96d2 100644
--- a/intern/cycles/render/camera.cpp
+++ b/intern/cycles/render/camera.cpp
@@ -30,67 +30,127 @@
CCL_NAMESPACE_BEGIN
static float shutter_curve_eval(float x,
- float shutter_curve[RAMP_TABLE_SIZE])
+ array<float>& shutter_curve)
{
- x *= RAMP_TABLE_SIZE;
+ if(shutter_curve.size() == 0) {
+ return 1.0f;
+ }
+
+ x *= shutter_curve.size();
int index = (int)x;
float frac = x - index;
- if(index < RAMP_TABLE_SIZE - 1) {
+ if(index < shutter_curve.size() - 1) {
return lerp(shutter_curve[index], shutter_curve[index + 1], frac);
}
else {
- return shutter_curve[RAMP_TABLE_SIZE - 1];
+ return shutter_curve[shutter_curve.size() - 1];
}
}
+NODE_DEFINE(Camera)
+{
+ NodeType* type = NodeType::add("camera", create);
+
+ SOCKET_FLOAT(shuttertime, "Shutter Time", 1.0f);
+
+ static NodeEnum motion_position_enum;
+ motion_position_enum.insert("start", MOTION_POSITION_START);
+ motion_position_enum.insert("center", MOTION_POSITION_CENTER);
+ motion_position_enum.insert("end", MOTION_POSITION_END);
+ SOCKET_ENUM(motion_position, "Motion Position", motion_position_enum, MOTION_POSITION_CENTER);
+
+ static NodeEnum rolling_shutter_type_enum;
+ rolling_shutter_type_enum.insert("none", ROLLING_SHUTTER_NONE);
+ rolling_shutter_type_enum.insert("top", ROLLING_SHUTTER_TOP);
+ SOCKET_ENUM(rolling_shutter_type, "Rolling Shutter Type", rolling_shutter_type_enum, ROLLING_SHUTTER_NONE);
+ SOCKET_FLOAT(rolling_shutter_duration, "Rolling Shutter Duration", 0.1f);
+
+ SOCKET_FLOAT_ARRAY(shutter_curve, "Shutter Curve", array<float>());
+
+ SOCKET_FLOAT(aperturesize, "Aperture Size", 0.0f);
+ SOCKET_FLOAT(focaldistance, "Focal Distance", 10.0f);
+ SOCKET_UINT(blades, "Blades", 0);
+ SOCKET_FLOAT(bladesrotation, "Blades Rotation", 0.0f);
+
+ SOCKET_TRANSFORM(matrix, "Matrix", transform_identity());
+
+ SOCKET_FLOAT(aperture_ratio, "Aperture Ratio", 1.0f);
+
+ static NodeEnum type_enum;
+ type_enum.insert("perspective", CAMERA_PERSPECTIVE);
+ type_enum.insert("orthograph", CAMERA_ORTHOGRAPHIC);
+ type_enum.insert("panorama", CAMERA_PANORAMA);
+ SOCKET_ENUM(type, "Type", type_enum, CAMERA_PERSPECTIVE);
+
+ static NodeEnum panorama_type_enum;
+ panorama_type_enum.insert("equirectangular", PANORAMA_EQUIRECTANGULAR);
+ panorama_type_enum.insert("mirrorball", PANORAMA_MIRRORBALL);
+ panorama_type_enum.insert("fisheye_equidistant", PANORAMA_FISHEYE_EQUIDISTANT);
+ panorama_type_enum.insert("fisheye_equisolid", PANORAMA_FISHEYE_EQUISOLID);
+ SOCKET_ENUM(panorama_type, "Panorama Type", panorama_type_enum, PANORAMA_EQUIRECTANGULAR);
+
+ SOCKET_FLOAT(fisheye_fov, "Fisheye FOV", M_PI_F);
+ SOCKET_FLOAT(fisheye_lens, "Fisheye Lens", 10.5f);
+ SOCKET_FLOAT(latitude_min, "Latitude Min", -M_PI_2_F);
+ SOCKET_FLOAT(latitude_max, "Latitude Max", M_PI_2_F);
+ SOCKET_FLOAT(longitude_min, "Longitude Min", -M_PI_F);
+ SOCKET_FLOAT(longitude_max, "Longitude Max", M_PI_F);
+ SOCKET_FLOAT(fov, "FOV", M_PI_4_F);
+ SOCKET_FLOAT(fov_pre, "FOV Pre", M_PI_4_F);
+ SOCKET_FLOAT(fov_post, "FOV Post", M_PI_4_F);
+
+ static NodeEnum stereo_eye_enum;
+ stereo_eye_enum.insert("none", STEREO_NONE);
+ stereo_eye_enum.insert("left", STEREO_LEFT);
+ stereo_eye_enum.insert("right", STEREO_RIGHT);
+ SOCKET_ENUM(stereo_eye, "Stereo Eye", stereo_eye_enum, STEREO_NONE);
+
+ SOCKET_FLOAT(interocular_distance, "Interocular Distance", 0.065f);
+ SOCKET_FLOAT(convergence_distance, "Convergence Distance", 30.0f * 0.065f);
+
+ SOCKET_BOOLEAN(use_pole_merge, "Use Pole Merge", false);
+ SOCKET_FLOAT(pole_merge_angle_from, "Pole Merge Angle From", 60.0f * M_PI_F / 180.0f);
+ SOCKET_FLOAT(pole_merge_angle_to, "Pole Merge Angle To", 75.0f * M_PI_F / 180.0f);
+
+ SOCKET_FLOAT(sensorwidth, "Sensor Width", 0.036f);
+ SOCKET_FLOAT(sensorheight, "Sensor Height", 0.024f);
+
+ SOCKET_FLOAT(nearclip, "Near Clip", 1e-5f);
+ SOCKET_FLOAT(farclip, "Far Clip", 1e5f);
+
+ SOCKET_FLOAT(viewplane.left, "Viewplane Left", 0);
+ SOCKET_FLOAT(viewplane.right, "Viewplane Right", 0);
+ SOCKET_FLOAT(viewplane.bottom, "Viewplane Bottom", 0);
+ SOCKET_FLOAT(viewplane.top, "Viewplane Top", 0);
+
+ SOCKET_FLOAT(border.left, "Border Left", 0);
+ SOCKET_FLOAT(border.right, "Border Right", 0);
+ SOCKET_FLOAT(border.bottom, "Border Bottom", 0);
+ SOCKET_FLOAT(border.top, "Border Top", 0);
+
+ return type;
+}
+
Camera::Camera()
+: Node(node_type)
{
- shuttertime = 1.0f;
- motion_position = MOTION_POSITION_CENTER;
shutter_table_offset = TABLE_OFFSET_INVALID;
- aperturesize = 0.0f;
- focaldistance = 10.0f;
- blades = 0;
- bladesrotation = 0.0f;
-
- matrix = transform_identity();
+ width = 1024;
+ height = 512;
+ resolution = 1;
motion.pre = transform_identity();
motion.post = transform_identity();
use_motion = false;
use_perspective_motion = false;
- aperture_ratio = 1.0f;
-
- type = CAMERA_PERSPECTIVE;
- panorama_type = PANORAMA_EQUIRECTANGULAR;
- fisheye_fov = M_PI_F;
- fisheye_lens = 10.5f;
- latitude_min = -M_PI_2_F;
- latitude_max = M_PI_2_F;
- longitude_min = -M_PI_F;
- longitude_max = M_PI_F;
- fov = M_PI_4_F;
- fov_pre = fov_post = fov;
- stereo_eye = STEREO_NONE;
- interocular_distance = 0.065f;
- convergence_distance = 30.0f * 0.065f;
-
- sensorwidth = 0.036f;
- sensorheight = 0.024f;
-
- nearclip = 1e-5f;
- farclip = 1e5f;
-
- width = 1024;
- height = 512;
- resolution = 1;
+ shutter_curve.resize(RAMP_TABLE_SIZE);
+ for(int i = 0; i < shutter_curve.size(); ++i) {
+ shutter_curve[i] = 1.0f;
+ }
- viewplane.left = -((float)width/(float)height);
- viewplane.right = (float)width/(float)height;
- viewplane.bottom = -1.0f;
- viewplane.top = 1.0f;
+ compute_auto_viewplane();
screentoworld = transform_identity();
rastertoworld = transform_identity();
@@ -106,16 +166,6 @@ Camera::Camera()
need_device_update = true;
need_flags_update = true;
previous_need_motion = -1;
-
- /* Initialize shutter curve. */
- const int num_shutter_points = sizeof(shutter_curve) / sizeof(*shutter_curve);
- for(int i = 0; i < num_shutter_points; ++i) {
- shutter_curve[i] = 1.0f;
- }
-
- /* Initialize rolling shutter effect. */
- rolling_shutter_type = ROLLING_SHUTTER_NONE;
- rolling_shutter_duration = 0.1f;
}
Camera::~Camera()
@@ -367,6 +417,14 @@ void Camera::device_update(Device *device, DeviceScene *dscene, Scene *scene)
}
kcam->convergence_distance = convergence_distance;
+ if(use_pole_merge) {
+ kcam->pole_merge_angle_from = pole_merge_angle_from;
+ kcam->pole_merge_angle_to = pole_merge_angle_to;
+ }
+ else {
+ kcam->pole_merge_angle_from = -1.0f;
+ kcam->pole_merge_angle_to = -1.0f;
+ }
/* sensor size */
kcam->sensorwidth = sensorwidth;
@@ -427,38 +485,14 @@ void Camera::device_free(Device * /*device*/,
bool Camera::modified(const Camera& cam)
{
- return !((shuttertime == cam.shuttertime) &&
- (aperturesize == cam.aperturesize) &&
- (blades == cam.blades) &&
- (bladesrotation == cam.bladesrotation) &&
- (focaldistance == cam.focaldistance) &&
- (type == cam.type) &&
- (fov == cam.fov) &&
- (nearclip == cam.nearclip) &&
- (farclip == cam.farclip) &&
- (sensorwidth == cam.sensorwidth) &&
- (sensorheight == cam.sensorheight) &&
- // modified for progressive render
- // (width == cam.width) &&
- // (height == cam.height) &&
- (viewplane == cam.viewplane) &&
- (border == cam.border) &&
- (matrix == cam.matrix) &&
- (aperture_ratio == cam.aperture_ratio) &&
- (panorama_type == cam.panorama_type) &&
- (fisheye_fov == cam.fisheye_fov) &&
- (fisheye_lens == cam.fisheye_lens) &&
- (latitude_min == cam.latitude_min) &&
- (latitude_max == cam.latitude_max) &&
- (longitude_min == cam.longitude_min) &&
- (longitude_max == cam.longitude_max) &&
- (stereo_eye == cam.stereo_eye));
+ return !Node::equals(cam);
}
bool Camera::motion_modified(const Camera& cam)
{
return !((motion == cam.motion) &&
- (use_motion == cam.use_motion));
+ (use_motion == cam.use_motion) &&
+ (use_perspective_motion == cam.use_perspective_motion));
}
void Camera::tag_update()
diff --git a/intern/cycles/render/camera.h b/intern/cycles/render/camera.h
index 684b4458dfc..141ef9cccef 100644
--- a/intern/cycles/render/camera.h
+++ b/intern/cycles/render/camera.h
@@ -19,6 +19,8 @@
#include "kernel_types.h"
+#include "node.h"
+
#include "util_boundbox.h"
#include "util_transform.h"
#include "util_types.h"
@@ -35,8 +37,10 @@ class Scene;
* Renderman, and Blender after remapping.
*/
-class Camera {
+class Camera : public Node {
public:
+ NODE_DECLARE;
+
/* Specifies an offset for the shutter's time interval. */
enum MotionPosition {
/* Shutter opens at the current frame. */
@@ -69,7 +73,7 @@ public:
/* motion blur */
float shuttertime;
MotionPosition motion_position;
- float shutter_curve[RAMP_TABLE_SIZE];
+ array<float> shutter_curve;
size_t shutter_table_offset;
/* ** Rolling shutter effect. ** */
@@ -104,6 +108,9 @@ public:
bool use_spherical_stereo;
float interocular_distance;
float convergence_distance;
+ bool use_pole_merge;
+ float pole_merge_angle_from;
+ float pole_merge_angle_to;
/* anamorphic lens bokeh */
float aperture_ratio;
diff --git a/intern/cycles/render/constant_fold.cpp b/intern/cycles/render/constant_fold.cpp
new file mode 100644
index 00000000000..b7f25663bc3
--- /dev/null
+++ b/intern/cycles/render/constant_fold.cpp
@@ -0,0 +1,384 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "constant_fold.h"
+#include "graph.h"
+
+#include "util_foreach.h"
+#include "util_logging.h"
+
+CCL_NAMESPACE_BEGIN
+
+ConstantFolder::ConstantFolder(ShaderGraph *graph, ShaderNode *node, ShaderOutput *output)
+: graph(graph), node(node), output(output)
+{
+}
+
+bool ConstantFolder::all_inputs_constant() const
+{
+ foreach(ShaderInput *input, node->inputs) {
+ if(input->link) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void ConstantFolder::make_constant(float value) const
+{
+ VLOG(1) << "Folding " << node->name << "::" << output->name() << " to constant (" << value << ").";
+
+ foreach(ShaderInput *sock, output->links) {
+ sock->set(value);
+ }
+
+ graph->disconnect(output);
+}
+
+void ConstantFolder::make_constant(float3 value) const
+{
+ VLOG(1) << "Folding " << node->name << "::" << output->name() << " to constant " << value << ".";
+
+ foreach(ShaderInput *sock, output->links) {
+ sock->set(value);
+ }
+
+ graph->disconnect(output);
+}
+
+void ConstantFolder::make_constant_clamp(float value, bool clamp) const
+{
+ make_constant(clamp ? saturate(value) : value);
+}
+
+void ConstantFolder::make_constant_clamp(float3 value, bool clamp) const
+{
+ if(clamp) {
+ value.x = saturate(value.x);
+ value.y = saturate(value.y);
+ value.z = saturate(value.z);
+ }
+
+ make_constant(value);
+}
+
+void ConstantFolder::make_zero() const
+{
+ if(output->type() == SocketType::FLOAT) {
+ make_constant(0.0f);
+ }
+ else if(SocketType::is_float3(output->type())) {
+ make_constant(make_float3(0.0f, 0.0f, 0.0f));
+ }
+ else {
+ assert(0);
+ }
+}
+
+void ConstantFolder::make_one() const
+{
+ if(output->type() == SocketType::FLOAT) {
+ make_constant(1.0f);
+ }
+ else if(SocketType::is_float3(output->type())) {
+ make_constant(make_float3(1.0f, 1.0f, 1.0f));
+ }
+ else {
+ assert(0);
+ }
+}
+
+void ConstantFolder::bypass(ShaderOutput *new_output) const
+{
+ assert(new_output);
+
+ VLOG(1) << "Folding " << node->name << "::" << output->name() << " to socket " << new_output->parent->name << "::" << new_output->name() << ".";
+
+ /* Remove all outgoing links from socket and connect them to new_output instead.
+ * The graph->relink method affects node inputs, so it's not safe to use in constant
+ * folding if the node has multiple outputs and will thus be folded multiple times. */
+ vector<ShaderInput*> outputs = output->links;
+
+ graph->disconnect(output);
+
+ foreach(ShaderInput *sock, outputs) {
+ graph->connect(new_output, sock);
+ }
+}
+
+void ConstantFolder::discard() const
+{
+ assert(output->type() == SocketType::CLOSURE);
+
+ VLOG(1) << "Discarding closure " << node->name << ".";
+
+ graph->disconnect(output);
+}
+
+void ConstantFolder::bypass_or_discard(ShaderInput *input) const
+{
+ assert(input->type() == SocketType::CLOSURE);
+
+ if(input->link) {
+ bypass(input->link);
+ }
+ else {
+ discard();
+ }
+}
+
+bool ConstantFolder::try_bypass_or_make_constant(ShaderInput *input, bool clamp) const
+{
+ if(input->type() != output->type()) {
+ return false;
+ }
+ else if(!input->link) {
+ if(input->type() == SocketType::FLOAT) {
+ make_constant_clamp(node->get_float(input->socket_type), clamp);
+ return true;
+ }
+ else if(SocketType::is_float3(input->type())) {
+ make_constant_clamp(node->get_float3(input->socket_type), clamp);
+ return true;
+ }
+ }
+ else if(!clamp) {
+ bypass(input->link);
+ return true;
+ }
+
+ return false;
+}
+
+bool ConstantFolder::is_zero(ShaderInput *input) const
+{
+ if(!input->link) {
+ if(input->type() == SocketType::FLOAT) {
+ return node->get_float(input->socket_type) == 0.0f;
+ }
+ else if(SocketType::is_float3(input->type())) {
+ return node->get_float3(input->socket_type) ==
+ make_float3(0.0f, 0.0f, 0.0f);
+ }
+ }
+
+ return false;
+}
+
+bool ConstantFolder::is_one(ShaderInput *input) const
+{
+ if(!input->link) {
+ if(input->type() == SocketType::FLOAT) {
+ return node->get_float(input->socket_type) == 1.0f;
+ }
+ else if(SocketType::is_float3(input->type())) {
+ return node->get_float3(input->socket_type) ==
+ make_float3(1.0f, 1.0f, 1.0f);
+ }
+ }
+
+ return false;
+}
+
+/* Specific nodes */
+
+void ConstantFolder::fold_mix(NodeMix type, bool clamp) const
+{
+ ShaderInput *fac_in = node->input("Fac");
+ ShaderInput *color1_in = node->input("Color1");
+ ShaderInput *color2_in = node->input("Color2");
+
+ float fac = saturate(node->get_float(fac_in->socket_type));
+ bool fac_is_zero = !fac_in->link && fac == 0.0f;
+ bool fac_is_one = !fac_in->link && fac == 1.0f;
+
+ /* remove no-op node when factor is 0.0 */
+ if(fac_is_zero) {
+ /* note that some of the modes will clamp out of bounds values even without use_clamp */
+ if(!(type == NODE_MIX_LIGHT || type == NODE_MIX_DODGE || type == NODE_MIX_BURN)) {
+ if(try_bypass_or_make_constant(color1_in, clamp)) {
+ return;
+ }
+ }
+ }
+
+ switch(type) {
+ case NODE_MIX_BLEND:
+ /* remove useless mix colors nodes */
+ if(color1_in->link && color2_in->link) {
+ if(color1_in->link == color2_in->link) {
+ try_bypass_or_make_constant(color1_in, clamp);
+ break;
+ }
+ }
+ else if(!color1_in->link && !color2_in->link) {
+ float3 color1 = node->get_float3(color1_in->socket_type);
+ float3 color2 = node->get_float3(color2_in->socket_type);
+ if(color1 == color2) {
+ try_bypass_or_make_constant(color1_in, clamp);
+ break;
+ }
+ }
+ /* remove no-op mix color node when factor is 1.0 */
+ if(fac_is_one) {
+ try_bypass_or_make_constant(color2_in, clamp);
+ break;
+ }
+ break;
+ case NODE_MIX_ADD:
+ /* 0 + X (fac 1) == X */
+ if(is_zero(color1_in) && fac_is_one) {
+ try_bypass_or_make_constant(color2_in, clamp);
+ }
+ /* X + 0 (fac ?) == X */
+ else if(is_zero(color2_in)) {
+ try_bypass_or_make_constant(color1_in, clamp);
+ }
+ break;
+ case NODE_MIX_SUB:
+ /* X - 0 (fac ?) == X */
+ if(is_zero(color2_in)) {
+ try_bypass_or_make_constant(color1_in, clamp);
+ }
+ /* X - X (fac 1) == 0 */
+ else if(color1_in->link && color1_in->link == color2_in->link && fac_is_one) {
+ make_zero();
+ }
+ break;
+ case NODE_MIX_MUL:
+ /* X * 1 (fac ?) == X, 1 * X (fac 1) == X */
+ if(is_one(color1_in) && fac_is_one) {
+ try_bypass_or_make_constant(color2_in, clamp);
+ }
+ else if(is_one(color2_in)) {
+ try_bypass_or_make_constant(color1_in, clamp);
+ }
+ /* 0 * ? (fac ?) == 0, ? * 0 (fac 1) == 0 */
+ else if(is_zero(color1_in)) {
+ make_zero();
+ }
+ else if(is_zero(color2_in) && fac_is_one) {
+ make_zero();
+ }
+ break;
+ case NODE_MIX_DIV:
+ /* X / 1 (fac ?) == X */
+ if(is_one(color2_in)) {
+ try_bypass_or_make_constant(color1_in, clamp);
+ }
+ /* 0 / ? (fac ?) == 0 */
+ else if(is_zero(color1_in)) {
+ make_zero();
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void ConstantFolder::fold_math(NodeMath type, bool clamp) const
+{
+ ShaderInput *value1_in = node->input("Value1");
+ ShaderInput *value2_in = node->input("Value2");
+
+ switch(type) {
+ case NODE_MATH_ADD:
+ /* X + 0 == 0 + X == X */
+ if(is_zero(value1_in)) {
+ try_bypass_or_make_constant(value2_in, clamp);
+ }
+ else if(is_zero(value2_in)) {
+ try_bypass_or_make_constant(value1_in, clamp);
+ }
+ break;
+ case NODE_MATH_SUBTRACT:
+ /* X - 0 == X */
+ if(is_zero(value2_in)) {
+ try_bypass_or_make_constant(value1_in, clamp);
+ }
+ break;
+ case NODE_MATH_MULTIPLY:
+ /* X * 1 == 1 * X == X */
+ if(is_one(value1_in)) {
+ try_bypass_or_make_constant(value2_in, clamp);
+ }
+ else if(is_one(value2_in)) {
+ try_bypass_or_make_constant(value1_in, clamp);
+ }
+ /* X * 0 == 0 * X == 0 */
+ else if(is_zero(value1_in) || is_zero(value2_in)) {
+ make_zero();
+ }
+ break;
+ case NODE_MATH_DIVIDE:
+ /* X / 1 == X */
+ if(is_one(value2_in)) {
+ try_bypass_or_make_constant(value1_in, clamp);
+ }
+ /* 0 / X == 0 */
+ else if(is_zero(value1_in)) {
+ make_zero();
+ }
+ break;
+ case NODE_MATH_POWER:
+ /* 1 ^ X == X ^ 0 == 1 */
+ if(is_one(value1_in) || is_zero(value2_in)) {
+ make_one();
+ }
+ /* X ^ 1 == X */
+ else if(is_one(value2_in)) {
+ try_bypass_or_make_constant(value1_in, clamp);
+ }
+ default:
+ break;
+ }
+}
+
+void ConstantFolder::fold_vector_math(NodeVectorMath type) const
+{
+ ShaderInput *vector1_in = node->input("Vector1");
+ ShaderInput *vector2_in = node->input("Vector2");
+
+ switch(type) {
+ case NODE_VECTOR_MATH_ADD:
+ /* X + 0 == 0 + X == X */
+ if(is_zero(vector1_in)) {
+ try_bypass_or_make_constant(vector2_in);
+ }
+ else if(is_zero(vector2_in)) {
+ try_bypass_or_make_constant(vector1_in);
+ }
+ break;
+ case NODE_VECTOR_MATH_SUBTRACT:
+ /* X - 0 == X */
+ if(is_zero(vector2_in)) {
+ try_bypass_or_make_constant(vector1_in);
+ }
+ break;
+ case NODE_VECTOR_MATH_DOT_PRODUCT:
+ case NODE_VECTOR_MATH_CROSS_PRODUCT:
+ /* X * 0 == 0 * X == 0 */
+ if(is_zero(vector1_in) || is_zero(vector2_in)) {
+ make_zero();
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/render/constant_fold.h b/intern/cycles/render/constant_fold.h
new file mode 100644
index 00000000000..7962698319f
--- /dev/null
+++ b/intern/cycles/render/constant_fold.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CONSTANT_FOLD_H__
+#define __CONSTANT_FOLD_H__
+
+#include "util_types.h"
+#include "svm_types.h"
+
+CCL_NAMESPACE_BEGIN
+
+class ShaderGraph;
+class ShaderInput;
+class ShaderNode;
+class ShaderOutput;
+
+class ConstantFolder {
+public:
+ ShaderGraph *const graph;
+ ShaderNode *const node;
+ ShaderOutput *const output;
+
+ ConstantFolder(ShaderGraph *graph, ShaderNode *node, ShaderOutput *output);
+
+ bool all_inputs_constant() const;
+
+ /* Constant folding helpers */
+ void make_constant(float value) const;
+ void make_constant(float3 value) const;
+ void make_constant_clamp(float value, bool clamp) const;
+ void make_constant_clamp(float3 value, bool clamp) const;
+ void make_zero() const;
+ void make_one() const;
+
+ /* Bypass node, relinking to another output socket. */
+ void bypass(ShaderOutput *output) const;
+
+ /* For closure nodes, discard node entirely or bypass to one of its inputs. */
+ void discard() const;
+ void bypass_or_discard(ShaderInput *input) const;
+
+ /* Bypass or make constant, unless we can't due to clamp being true. */
+ bool try_bypass_or_make_constant(ShaderInput *input, bool clamp = false) const;
+
+ /* Test if shader inputs of the current nodes have fixed values. */
+ bool is_zero(ShaderInput *input) const;
+ bool is_one(ShaderInput *input) const;
+
+ /* Specific nodes. */
+ void fold_mix(NodeMix type, bool clamp) const;
+ void fold_math(NodeMath type, bool clamp) const;
+ void fold_vector_math(NodeVectorMath type) const;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __CONSTANT_FOLD_H__ */
+
diff --git a/intern/cycles/render/curves.h b/intern/cycles/render/curves.h
index 3d9b4e1f347..e41967eebf5 100644
--- a/intern/cycles/render/curves.h
+++ b/intern/cycles/render/curves.h
@@ -63,23 +63,23 @@ public:
ParticleCurveData();
~ParticleCurveData();
- vector<int> psys_firstcurve;
- vector<int> psys_curvenum;
- vector<int> psys_shader;
-
- vector<float> psys_rootradius;
- vector<float> psys_tipradius;
- vector<float> psys_shape;
- vector<bool> psys_closetip;
-
- vector<int> curve_firstkey;
- vector<int> curve_keynum;
- vector<float> curve_length;
- vector<float3> curve_uv;
- vector<float3> curve_vcol;
-
- vector<float3> curvekey_co;
- vector<float> curvekey_time;
+ array<int> psys_firstcurve;
+ array<int> psys_curvenum;
+ array<int> psys_shader;
+
+ array<float> psys_rootradius;
+ array<float> psys_tipradius;
+ array<float> psys_shape;
+ array<bool> psys_closetip;
+
+ array<int> curve_firstkey;
+ array<int> curve_keynum;
+ array<float> curve_length;
+ array<float3> curve_uv;
+ array<float3> curve_vcol;
+
+ array<float3> curvekey_co;
+ array<float> curvekey_time;
};
/* HairSystem Manager */
diff --git a/intern/cycles/render/film.cpp b/intern/cycles/render/film.cpp
index 95cb10ab13b..e10a938e1eb 100644
--- a/intern/cycles/render/film.cpp
+++ b/intern/cycles/render/film.cpp
@@ -39,10 +39,10 @@ static bool compare_pass_order(const Pass& a, const Pass& b)
return (a.components > b.components);
}
-void Pass::add(PassType type, vector<Pass>& passes)
+void Pass::add(PassType type, array<Pass>& passes)
{
- foreach(Pass& existing_pass, passes)
- if(existing_pass.type == type)
+ for(size_t i = 0; i < passes.size(); i++)
+ if(passes[i].type == type)
return;
Pass pass;
@@ -169,17 +169,17 @@ void Pass::add(PassType type, vector<Pass>& passes)
#endif
}
- passes.push_back(pass);
+ passes.push_back_slow(pass);
/* order from by components, to ensure alignment so passes with size 4
* come first and then passes with size 1 */
- sort(passes.begin(), passes.end(), compare_pass_order);
+ sort(&passes[0], &passes[0] + passes.size(), compare_pass_order);
if(pass.divide_type != PASS_NONE)
Pass::add(pass.divide_type, passes);
}
-bool Pass::equals(const vector<Pass>& A, const vector<Pass>& B)
+bool Pass::equals(const array<Pass>& A, const array<Pass>& B)
{
if(A.size() != B.size())
return false;
@@ -191,10 +191,10 @@ bool Pass::equals(const vector<Pass>& A, const vector<Pass>& B)
return true;
}
-bool Pass::contains(const vector<Pass>& passes, PassType type)
+bool Pass::contains(const array<Pass>& passes, PassType type)
{
- foreach(const Pass& pass, passes)
- if(pass.type == type)
+ for(size_t i = 0; i < passes.size(); i++)
+ if(passes[i].type == type)
return true;
return false;
@@ -263,22 +263,37 @@ static vector<float> filter_table(FilterType type, float width)
/* Film */
-Film::Film()
+NODE_DEFINE(Film)
{
- exposure = 0.8f;
- Pass::add(PASS_COMBINED, passes);
- pass_alpha_threshold = 0.5f;
+ NodeType* type = NodeType::add("film", create);
- filter_type = FILTER_BOX;
- filter_width = 1.0f;
- filter_table_offset = TABLE_OFFSET_INVALID;
+ SOCKET_FLOAT(exposure, "Exposure", 0.8f);
+ SOCKET_FLOAT(pass_alpha_threshold, "Pass Alpha Threshold", 0.5f);
+
+ static NodeEnum filter_enum;
+ filter_enum.insert("box", FILTER_BOX);
+ filter_enum.insert("gaussian", FILTER_GAUSSIAN);
+ filter_enum.insert("blackman_harris", FILTER_BLACKMAN_HARRIS);
- mist_start = 0.0f;
- mist_depth = 100.0f;
- mist_falloff = 1.0f;
+ SOCKET_ENUM(filter_type, "Filter Type", filter_enum, FILTER_BOX);
+ SOCKET_FLOAT(filter_width, "Filter Width", 1.0f);
+
+ SOCKET_FLOAT(mist_start, "Mist Start", 0.0f);
+ SOCKET_FLOAT(mist_depth, "Mist Depth", 100.0f);
+ SOCKET_FLOAT(mist_falloff, "Mist Falloff", 1.0f);
+
+ SOCKET_BOOLEAN(use_sample_clamp, "Use Sample Clamp", false);
+
+ return type;
+}
+
+Film::Film()
+: Node(node_type)
+{
+ Pass::add(PASS_COMBINED, passes);
use_light_visibility = false;
- use_sample_clamp = false;
+ filter_table_offset = TABLE_OFFSET_INVALID;
need_update = true;
}
@@ -302,7 +317,8 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
kfilm->pass_stride = 0;
kfilm->use_light_pass = use_light_visibility || use_sample_clamp;
- foreach(Pass& pass, passes) {
+ for(size_t i = 0; i < passes.size(); i++) {
+ Pass& pass = passes[i];
kfilm->pass_flag |= pass.type;
switch(pass.type) {
@@ -449,18 +465,10 @@ void Film::device_free(Device * /*device*/,
bool Film::modified(const Film& film)
{
- return !(exposure == film.exposure
- && Pass::equals(passes, film.passes)
- && pass_alpha_threshold == film.pass_alpha_threshold
- && use_sample_clamp == film.use_sample_clamp
- && filter_type == film.filter_type
- && filter_width == film.filter_width
- && mist_start == film.mist_start
- && mist_depth == film.mist_depth
- && mist_falloff == film.mist_falloff);
+ return !Node::equals(film) || !Pass::equals(passes, film.passes);
}
-void Film::tag_passes_update(Scene *scene, const vector<Pass>& passes_)
+void Film::tag_passes_update(Scene *scene, const array<Pass>& passes_)
{
if(Pass::contains(passes, PASS_UV) != Pass::contains(passes_, PASS_UV)) {
scene->mesh_manager->tag_update(scene);
diff --git a/intern/cycles/render/film.h b/intern/cycles/render/film.h
index 966e00a8d1f..9fa51c51f52 100644
--- a/intern/cycles/render/film.h
+++ b/intern/cycles/render/film.h
@@ -22,6 +22,8 @@
#include "kernel_types.h"
+#include "node.h"
+
CCL_NAMESPACE_BEGIN
class Device;
@@ -44,15 +46,17 @@ public:
bool exposure;
PassType divide_type;
- static void add(PassType type, vector<Pass>& passes);
- static bool equals(const vector<Pass>& A, const vector<Pass>& B);
- static bool contains(const vector<Pass>& passes, PassType);
+ static void add(PassType type, array<Pass>& passes);
+ static bool equals(const array<Pass>& A, const array<Pass>& B);
+ static bool contains(const array<Pass>& passes, PassType);
};
-class Film {
+class Film : public Node {
public:
+ NODE_DECLARE;
+
float exposure;
- vector<Pass> passes;
+ array<Pass> passes;
float pass_alpha_threshold;
FilterType filter_type;
@@ -75,7 +79,7 @@ public:
void device_free(Device *device, DeviceScene *dscene, Scene *scene);
bool modified(const Film& film);
- void tag_passes_update(Scene *scene, const vector<Pass>& passes_);
+ void tag_passes_update(Scene *scene, const array<Pass>& passes_);
void tag_update(Scene *scene);
};
diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp
index 920f5c7b50d..f6c83fb5c7e 100644
--- a/intern/cycles/render/graph.cpp
+++ b/intern/cycles/render/graph.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2013 Blender Foundation
+ * Copyright 2011-2016 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,11 +18,13 @@
#include "graph.h"
#include "nodes.h"
#include "shader.h"
+#include "constant_fold.h"
#include "util_algorithm.h"
#include "util_debug.h"
#include "util_foreach.h"
#include "util_queue.h"
+#include "util_logging.h"
CCL_NAMESPACE_BEGIN
@@ -51,73 +53,19 @@ bool check_node_inputs_traversed(const ShaderNode *node,
return true;
}
-bool check_node_inputs_equals(const ShaderNode *node_a,
- const ShaderNode *node_b)
-{
- if(node_a->inputs.size() != node_b->inputs.size()) {
- /* Happens with BSDF closure nodes which are currently sharing the same
- * name for all the BSDF types, making it impossible to filter out
- * incompatible nodes.
- */
- return false;
- }
- for(int i = 0; i < node_a->inputs.size(); ++i) {
- ShaderInput *input_a = node_a->inputs[i],
- *input_b = node_b->inputs[i];
- if(input_a->link == NULL && input_b->link == NULL) {
- /* Unconnected inputs are expected to have the same value. */
- if(input_a->value != input_b->value) {
- return false;
- }
- }
- else if(input_a->link != NULL && input_b->link != NULL) {
- /* Expect links are to come from the same exact socket. */
- if(input_a->link != input_b->link) {
- return false;
- }
- }
- else {
- /* One socket has a link and another has not, inputs can't be
- * considered equal.
- */
- return false;
- }
- }
- return true;
-}
-
} /* namespace */
-/* Input and Output */
-
-ShaderInput::ShaderInput(ShaderNode *parent_, const char *name_, ShaderSocketType type_)
-{
- parent = parent_;
- name = name_;
- type = type_;
- link = NULL;
- value = make_float3(0.0f, 0.0f, 0.0f);
- stack_offset = SVM_STACK_INVALID;
- default_value = NONE;
- usage = USE_ALL;
-}
-
-ShaderOutput::ShaderOutput(ShaderNode *parent_, const char *name_, ShaderSocketType type_)
-{
- parent = parent_;
- name = name_;
- type = type_;
- stack_offset = SVM_STACK_INVALID;
-}
-
/* Node */
-ShaderNode::ShaderNode(const char *name_)
+ShaderNode::ShaderNode(const NodeType *type)
+: Node(type)
{
- name = name_;
+ name = type->name;
id = -1;
bump = SHADER_BUMP_NONE;
special_type = SHADER_SPECIAL_TYPE_NONE;
+
+ create_inputs_outputs(type);
}
ShaderNode::~ShaderNode()
@@ -129,10 +77,23 @@ ShaderNode::~ShaderNode()
delete socket;
}
+void ShaderNode::create_inputs_outputs(const NodeType *type)
+{
+ foreach(const SocketType& socket, type->inputs) {
+ if(socket.flags & SocketType::LINKABLE) {
+ inputs.push_back(new ShaderInput(socket, this));
+ }
+ }
+
+ foreach(const SocketType& socket, type->outputs) {
+ outputs.push_back(new ShaderOutput(socket, this));
+ }
+}
+
ShaderInput *ShaderNode::input(const char *name)
{
foreach(ShaderInput *socket, inputs) {
- if(strcmp(socket->name, name) == 0)
+ if(socket->name() == name)
return socket;
}
@@ -142,56 +103,42 @@ ShaderInput *ShaderNode::input(const char *name)
ShaderOutput *ShaderNode::output(const char *name)
{
foreach(ShaderOutput *socket, outputs)
- if(strcmp(socket->name, name) == 0)
+ if(socket->name() == name)
return socket;
return NULL;
}
-ShaderInput *ShaderNode::add_input(const char *name, ShaderSocketType type, float value, int usage)
+ShaderInput *ShaderNode::input(ustring name)
{
- ShaderInput *input = new ShaderInput(this, name, type);
- input->value.x = value;
- input->usage = usage;
- inputs.push_back(input);
- return input;
-}
+ foreach(ShaderInput *socket, inputs) {
+ if(socket->name() == name)
+ return socket;
+ }
-ShaderInput *ShaderNode::add_input(const char *name, ShaderSocketType type, float3 value, int usage)
-{
- ShaderInput *input = new ShaderInput(this, name, type);
- input->value = value;
- input->usage = usage;
- inputs.push_back(input);
- return input;
+ return NULL;
}
-ShaderInput *ShaderNode::add_input(const char *name, ShaderSocketType type, ShaderInput::DefaultValue value, int usage)
+ShaderOutput *ShaderNode::output(ustring name)
{
- ShaderInput *input = add_input(name, type);
- input->default_value = value;
- input->usage = usage;
- return input;
-}
+ foreach(ShaderOutput *socket, outputs)
+ if(socket->name() == name)
+ return socket;
-ShaderOutput *ShaderNode::add_output(const char *name, ShaderSocketType type)
-{
- ShaderOutput *output = new ShaderOutput(this, name, type);
- outputs.push_back(output);
- return output;
+ return NULL;
}
void ShaderNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
foreach(ShaderInput *input, inputs) {
if(!input->link) {
- if(input->default_value == ShaderInput::TEXTURE_GENERATED) {
+ if(input->flags() & SocketType::LINK_TEXTURE_GENERATED) {
if(shader->has_surface)
attributes->add(ATTR_STD_GENERATED);
if(shader->has_volume)
attributes->add(ATTR_STD_GENERATED_TRANSFORM);
}
- else if(input->default_value == ShaderInput::TEXTURE_UV) {
+ else if(input->flags() & SocketType::LINK_TEXTURE_UV) {
if(shader->has_surface)
attributes->add(ATTR_STD_UV);
}
@@ -199,6 +146,50 @@ void ShaderNode::attributes(Shader *shader, AttributeRequestSet *attributes)
}
}
+bool ShaderNode::equals(const ShaderNode& other)
+{
+ if(type != other.type || bump != other.bump) {
+ return false;
+ }
+
+ assert(inputs.size() == other.inputs.size());
+
+ /* Compare unlinkable sockets */
+ foreach(const SocketType& socket, type->inputs) {
+ if(!(socket.flags & SocketType::LINKABLE)) {
+ if(!Node::equals_value(other, socket)) {
+ return false;
+ }
+ }
+ }
+
+ /* Compare linkable input sockets */
+ for(int i = 0; i < inputs.size(); ++i) {
+ ShaderInput *input_a = inputs[i],
+ *input_b = other.inputs[i];
+ if(input_a->link == NULL && input_b->link == NULL) {
+ /* Unconnected inputs are expected to have the same value. */
+ if(!Node::equals_value(other, input_a->socket_type)) {
+ return false;
+ }
+ }
+ else if(input_a->link != NULL && input_b->link != NULL) {
+ /* Expect links are to come from the same exact socket. */
+ if(input_a->link != input_b->link) {
+ return false;
+ }
+ }
+ else {
+ /* One socket has a link and another has not, inputs can't be
+ * considered equal.
+ */
+ return false;
+ }
+ }
+
+ return true;
+}
+
/* Graph */
ShaderGraph::ShaderGraph()
@@ -256,18 +247,18 @@ void ShaderGraph::connect(ShaderOutput *from, ShaderInput *to)
return;
}
- if(from->type != to->type) {
+ if(from->type() != to->type()) {
/* for closures we can't do automatic conversion */
- if(from->type == SHADER_SOCKET_CLOSURE || to->type == SHADER_SOCKET_CLOSURE) {
+ if(from->type() == SocketType::CLOSURE || to->type() == SocketType::CLOSURE) {
fprintf(stderr, "Cycles shader graph connect: can only connect closure to closure "
"(%s.%s to %s.%s).\n",
- from->parent->name.c_str(), from->name,
- to->parent->name.c_str(), to->name);
+ from->parent->name.c_str(), from->name().c_str(),
+ to->parent->name.c_str(), to->name().c_str());
return;
}
/* add automatic conversion node in case of type mismatch */
- ShaderNode *convert = add(new ConvertNode(from->type, to->type, true));
+ ShaderNode *convert = add(new ConvertNode(from->type(), to->type(), true));
connect(from, convert->inputs[0]);
connect(convert->outputs[0], to);
@@ -279,6 +270,17 @@ void ShaderGraph::connect(ShaderOutput *from, ShaderInput *to)
}
}
+void ShaderGraph::disconnect(ShaderOutput *from)
+{
+ assert(!finalized);
+
+ foreach(ShaderInput *sock, from->links) {
+ sock->link = NULL;
+ }
+
+ from->links.clear();
+}
+
void ShaderGraph::disconnect(ShaderInput *to)
{
assert(!finalized);
@@ -311,7 +313,8 @@ void ShaderGraph::relink(ShaderNode *node, ShaderOutput *from, ShaderOutput *to)
void ShaderGraph::finalize(Scene *scene,
bool do_bump,
bool do_osl,
- bool do_simplify)
+ bool do_simplify,
+ bool bump_in_object_space)
{
/* before compiling, the shader graph may undergo a number of modifications.
* currently we set default geometry shader inputs, and create automatic bump
@@ -319,12 +322,12 @@ void ShaderGraph::finalize(Scene *scene,
* modified afterwards. */
if(!finalized) {
- clean(scene);
default_inputs(do_osl);
+ clean(scene);
refine_bump_nodes();
if(do_bump)
- bump_from_displacement();
+ bump_from_displacement(bump_in_object_space);
ShaderInput *surface_in = output()->input("Surface");
ShaderInput *volume_in = output()->input("Volume");
@@ -374,24 +377,12 @@ void ShaderGraph::copy_nodes(ShaderNodeSet& nodes, ShaderNodeMap& nnodemap)
ShaderNode *nnode = node->clone();
nnodemap[node] = nnode;
+ /* create new inputs and outputs to recreate links and ensure
+ * that we still point to valid SocketType if the NodeType
+ * changed in cloning, as it does for OSL nodes */
nnode->inputs.clear();
nnode->outputs.clear();
-
- foreach(ShaderInput *input, node->inputs) {
- ShaderInput *ninput = new ShaderInput(*input);
- nnode->inputs.push_back(ninput);
-
- ninput->parent = nnode;
- ninput->link = NULL;
- }
-
- foreach(ShaderOutput *output, node->outputs) {
- ShaderOutput *noutput = new ShaderOutput(*output);
- nnode->outputs.push_back(noutput);
-
- noutput->parent = nnode;
- noutput->links.clear();
- }
+ nnode->create_inputs_outputs(nnode->type);
}
/* recreate links */
@@ -401,8 +392,8 @@ void ShaderGraph::copy_nodes(ShaderNodeSet& nodes, ShaderNodeMap& nnodemap)
/* find new input and output */
ShaderNode *nfrom = nnodemap[input->link->parent];
ShaderNode *nto = nnodemap[input->parent];
- ShaderOutput *noutput = nfrom->output(input->link->name);
- ShaderInput *ninput = nto->input(input->name);
+ ShaderOutput *noutput = nfrom->output(input->link->name());
+ ShaderInput *ninput = nto->input(input->name());
/* connect */
connect(noutput, ninput);
@@ -447,10 +438,10 @@ void ShaderGraph::remove_proxy_nodes()
vector<ShaderInput*> links = tonode->outputs[0]->links;
foreach(ShaderInput *autoin, links) {
- if(autoin->default_value == ShaderInput::NONE)
- all_links_removed = false;
- else
+ if(autoin->flags() & SocketType::DEFAULT_LINK_MASK)
disconnect(autoin);
+ else
+ all_links_removed = false;
}
if(all_links_removed)
@@ -460,8 +451,7 @@ void ShaderGraph::remove_proxy_nodes()
disconnect(to);
/* transfer the default input value to the target socket */
- to->set(input->value);
- to->set(input->value_string);
+ tonode->copy_value(to->socket_type, *proxy, input->socket_type);
}
}
@@ -494,6 +484,8 @@ void ShaderGraph::constant_fold()
ShaderNodeSet done, scheduled;
queue<ShaderNode*> traverse_queue;
+ bool has_displacement = (output()->input("Displacement")->link != NULL);
+
/* Schedule nodes which doesn't have any dependencies. */
foreach(ShaderNode *node, nodes) {
if(!check_node_inputs_has_links(node)) {
@@ -507,7 +499,7 @@ void ShaderGraph::constant_fold()
traverse_queue.pop();
done.insert(node);
foreach(ShaderOutput *output, node->outputs) {
- if (output->links.size() == 0) {
+ if(output->links.size() == 0) {
continue;
}
/* Schedule node which was depending on the value,
@@ -527,18 +519,21 @@ void ShaderGraph::constant_fold()
}
}
/* Optimize current node. */
- float3 optimized_value = make_float3(0.0f, 0.0f, 0.0f);
- if(node->constant_fold(this, output, &optimized_value)) {
- /* Apply optimized value to connected sockets. */
- vector<ShaderInput*> links(output->links);
- foreach(ShaderInput *input, links) {
- /* Assign value and disconnect the optimizedinput. */
- input->value = optimized_value;
- disconnect(input);
- }
- }
+ ConstantFolder folder(this, node, output);
+ node->constant_fold(folder);
}
}
+
+ /* Folding might have removed all nodes connected to the displacement output
+ * even tho there is displacement to be applied, so add in a value node if
+ * that happens to ensure there is still a valid graph for displacement.
+ */
+ if(has_displacement && !output()->input("Displacement")->link) {
+ ValueNode *value = (ValueNode*)add(new ValueNode());
+ value->value = output()->displacement;
+
+ connect(value->output("Value"), output()->input("Displacement"));
+ }
}
/* Step 3: Simplification. */
@@ -561,9 +556,10 @@ void ShaderGraph::deduplicate_nodes()
* already deduplicated.
*/
- ShaderNodeSet scheduled;
- map<ustring, ShaderNodeSet> done;
+ ShaderNodeSet scheduled, done;
+ map<ustring, ShaderNodeSet> candidates;
queue<ShaderNode*> traverse_queue;
+ int num_deduplicated = 0;
/* Schedule nodes which doesn't have any dependencies. */
foreach(ShaderNode *node, nodes) {
@@ -576,10 +572,12 @@ void ShaderGraph::deduplicate_nodes()
while(!traverse_queue.empty()) {
ShaderNode *node = traverse_queue.front();
traverse_queue.pop();
- done[node->name].insert(node);
+ done.insert(node);
/* Schedule the nodes which were depending on the current node. */
+ bool has_output_links = false;
foreach(ShaderOutput *output, node->outputs) {
foreach(ShaderInput *input, output->links) {
+ has_output_links = true;
if(scheduled.find(input->parent) != scheduled.end()) {
/* Node might not be optimized yet but scheduled already
* by other dependencies. No need to re-schedule it.
@@ -587,37 +585,39 @@ void ShaderGraph::deduplicate_nodes()
continue;
}
/* Schedule node if its inputs are fully done. */
- if(check_node_inputs_traversed(input->parent, done[input->parent->name])) {
+ if(check_node_inputs_traversed(input->parent, done)) {
traverse_queue.push(input->parent);
scheduled.insert(input->parent);
}
}
}
+ /* Only need to care about nodes that are actually used */
+ if(!has_output_links) {
+ continue;
+ }
/* Try to merge this node with another one. */
- foreach(ShaderNode *other_node, done[node->name]) {
- if(node == other_node) {
- /* Don't merge with self. */
- continue;
+ ShaderNode *merge_with = NULL;
+ foreach(ShaderNode *other_node, candidates[node->type->name]) {
+ if(node != other_node && node->equals(*other_node)) {
+ merge_with = other_node;
+ break;
}
- if(node->name != other_node->name) {
- /* Can only de-duplicate nodes of the same type. */
- continue;
- }
- if(!check_node_inputs_equals(node, other_node)) {
- /* Node inputs are different, can't merge them, */
- continue;
- }
- if(!node->equals(other_node)) {
- /* Node settings are different. */
- continue;
- }
- /* TODO(sergey): Consider making it an utility function. */
+ }
+ /* If found an equivalent, merge; otherwise keep node for later merges */
+ if(merge_with != NULL) {
for(int i = 0; i < node->outputs.size(); ++i) {
- relink(node, node->outputs[i], other_node->outputs[i]);
+ relink(node, node->outputs[i], merge_with->outputs[i]);
}
- break;
+ num_deduplicated++;
+ }
+ else {
+ candidates[node->type->name].insert(node);
}
}
+
+ if(num_deduplicated > 0) {
+ VLOG(1) << "Deduplicated " << num_deduplicated << " nodes.";
+ }
}
void ShaderGraph::break_cycles(ShaderNode *node, vector<bool>& visited, vector<bool>& on_stack)
@@ -706,38 +706,38 @@ void ShaderGraph::default_inputs(bool do_osl)
foreach(ShaderNode *node, nodes) {
foreach(ShaderInput *input, node->inputs) {
- if(!input->link && ((input->usage & ShaderInput::USE_SVM) || do_osl)) {
- if(input->default_value == ShaderInput::TEXTURE_GENERATED) {
+ if(!input->link && (!(input->flags() & SocketType::OSL_INTERNAL) || do_osl)) {
+ if(input->flags() & SocketType::LINK_TEXTURE_GENERATED) {
if(!texco)
texco = new TextureCoordinateNode();
connect(texco->output("Generated"), input);
}
- else if(input->default_value == ShaderInput::TEXTURE_UV) {
+ else if(input->flags() & SocketType::LINK_TEXTURE_UV) {
if(!texco)
texco = new TextureCoordinateNode();
connect(texco->output("UV"), input);
}
- else if(input->default_value == ShaderInput::INCOMING) {
+ else if(input->flags() & SocketType::LINK_INCOMING) {
if(!geom)
geom = new GeometryNode();
connect(geom->output("Incoming"), input);
}
- else if(input->default_value == ShaderInput::NORMAL) {
+ else if(input->flags() & SocketType::LINK_NORMAL) {
if(!geom)
geom = new GeometryNode();
connect(geom->output("Normal"), input);
}
- else if(input->default_value == ShaderInput::POSITION) {
+ else if(input->flags() & SocketType::LINK_POSITION) {
if(!geom)
geom = new GeometryNode();
connect(geom->output("Position"), input);
}
- else if(input->default_value == ShaderInput::TANGENT) {
+ else if(input->flags() & SocketType::LINK_TANGENT) {
if(!geom)
geom = new GeometryNode();
@@ -785,8 +785,8 @@ void ShaderGraph::refine_bump_nodes()
pair.second->bump = SHADER_BUMP_DY;
ShaderOutput *out = bump_input->link;
- ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name);
- ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name);
+ ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name());
+ ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name());
connect(out_dx, node->input("SampleX"));
connect(out_dy, node->input("SampleY"));
@@ -808,7 +808,7 @@ void ShaderGraph::refine_bump_nodes()
}
}
-void ShaderGraph::bump_from_displacement()
+void ShaderGraph::bump_from_displacement(bool use_object_space)
{
/* generate bump mapping automatically from displacement. bump mapping is
* done using a 3-tap filter, computing the displacement at the center,
@@ -857,12 +857,13 @@ void ShaderGraph::bump_from_displacement()
ShaderNode *set_normal = add(new SetNormalNode());
/* add bump node and connect copied graphs to it */
- ShaderNode *bump = add(new BumpNode());
+ BumpNode *bump = (BumpNode*)add(new BumpNode());
+ bump->use_object_space = use_object_space;
ShaderOutput *out = displacement_in->link;
- ShaderOutput *out_center = nodes_center[out->parent]->output(out->name);
- ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name);
- ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name);
+ ShaderOutput *out_center = nodes_center[out->parent]->output(out->name());
+ ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name());
+ ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name());
connect(out_center, bump->input("SampleCenter"));
connect(out_dx, bump->input("SampleX"));
@@ -871,27 +872,8 @@ void ShaderGraph::bump_from_displacement()
/* connect the bump out to the set normal in: */
connect(bump->output("Normal"), set_normal->input("Direction"));
- /* connect bump output to normal input nodes that aren't set yet. actually
- * this will only set the normal input to the geometry node that we created
- * and connected to all other normal inputs already. */
- foreach(ShaderNode *node, nodes) {
- /* Don't connect normal to the bump node we're coming from,
- * otherwise it'll be a cycle in graph.
- */
- if(node == bump) {
- continue;
- }
- foreach(ShaderInput *input, node->inputs) {
- if(!input->link && input->default_value == ShaderInput::NORMAL)
- connect(set_normal->output("Normal"), input);
- }
- }
-
- /* for displacement bump, clear the normal input in case the above loop
- * connected the setnormal out to the bump normalin */
- ShaderInput *bump_normal_in = bump->input("Normal");
- if(bump_normal_in)
- bump_normal_in->link = NULL;
+ /* connect to output node */
+ connect(set_normal->output("Normal"), output()->input("Normal"));
/* finally, add the copied nodes to the graph. we can't do this earlier
* because we would create dependency cycles in the above loop */
@@ -918,14 +900,15 @@ void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight
if(fin) {
/* mix closure: add node to mix closure weights */
- ShaderNode *mix_node = add(new MixClosureWeightNode());
+ MixClosureWeightNode *mix_node = new MixClosureWeightNode();
+ add(mix_node);
ShaderInput *fac_in = mix_node->input("Fac");
ShaderInput *weight_in = mix_node->input("Weight");
if(fin->link)
connect(fin->link, fac_in);
else
- fac_in->value = fin->value;
+ mix_node->fac = node->get_float(fin->socket_type);
if(weight_out)
connect(weight_out, weight_in);
@@ -952,20 +935,20 @@ void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight
return;
/* already has a weight connected to it? add weights */
- if(weight_in->link || weight_in->value.x != 0.0f) {
- ShaderNode *math_node = add(new MathNode());
- ShaderInput *value1_in = math_node->input("Value1");
- ShaderInput *value2_in = math_node->input("Value2");
+ float weight_value = node->get_float(weight_in->socket_type);
+ if(weight_in->link || weight_value != 0.0f) {
+ MathNode *math_node = new MathNode();
+ add(math_node);
if(weight_in->link)
- connect(weight_in->link, value1_in);
+ connect(weight_in->link, math_node->input("Value1"));
else
- value1_in->value = weight_in->value;
+ math_node->value1 = weight_value;
if(weight_out)
- connect(weight_out, value2_in);
+ connect(weight_out, math_node->input("Value2"));
else
- value2_in->value.x = 1.0f;
+ math_node->value2 = 1.0f;
weight_out = math_node->output("Value");
if(weight_in->link)
@@ -976,7 +959,7 @@ void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight
if(weight_out)
connect(weight_out, weight_in);
else
- weight_in->value.x += 1.0f;
+ node->set(weight_in->socket_type, weight_value + 1.0f);
}
}
@@ -984,17 +967,21 @@ int ShaderGraph::get_num_closures()
{
int num_closures = 0;
foreach(ShaderNode *node, nodes) {
- if(node->special_type == SHADER_SPECIAL_TYPE_CLOSURE) {
- BsdfNode *bsdf_node = static_cast<BsdfNode*>(node);
- /* TODO(sergey): Make it more generic approach, maybe some utility
- * macros like CLOSURE_IS_FOO()?
- */
- if(CLOSURE_IS_BSSRDF(bsdf_node->closure))
- num_closures = num_closures + 3;
- else if(CLOSURE_IS_GLASS(bsdf_node->closure))
- num_closures = num_closures + 2;
- else
- num_closures = num_closures + 1;
+ ClosureType closure_type = node->get_closure_type();
+ if(closure_type == CLOSURE_NONE_ID) {
+ continue;
+ }
+ else if(CLOSURE_IS_BSSRDF(closure_type)) {
+ num_closures += 3;
+ }
+ else if(CLOSURE_IS_GLASS(closure_type)) {
+ num_closures += 2;
+ }
+ else if(CLOSURE_IS_BSDF_MULTISCATTER(closure_type)) {
+ num_closures += 2;
+ }
+ else {
+ ++num_closures;
}
}
return num_closures;
@@ -1023,7 +1010,7 @@ void ShaderGraph::dump_graph(const char *filename)
if(socket != node->inputs[0]) {
fprintf(fd, "|");
}
- fprintf(fd, "<IN_%p>%s", socket, socket->name);
+ fprintf(fd, "<IN_%p>%s", socket, socket->name().c_str());
}
fprintf(fd, "}|");
}
@@ -1043,7 +1030,7 @@ void ShaderGraph::dump_graph(const char *filename)
if(socket != node->outputs[0]) {
fprintf(fd, "|");
}
- fprintf(fd, "<OUT_%p>%s", socket, socket->name);
+ fprintf(fd, "<OUT_%p>%s", socket, socket->name().c_str());
}
fprintf(fd, "}");
}
@@ -1057,7 +1044,7 @@ void ShaderGraph::dump_graph(const char *filename)
"// CONNECTION: OUT_%p->IN_%p (%s:%s)\n",
output,
input,
- output->name, input->name);
+ output->name().c_str(), input->name().c_str());
fprintf(fd,
"\"%p\":\"OUT_%p\":e -> \"%p\":\"IN_%p\":w [label=\"\"]\n",
output->parent,
diff --git a/intern/cycles/render/graph.h b/intern/cycles/render/graph.h
index 6619fcaebeb..780fdf49ca4 100644
--- a/intern/cycles/render/graph.h
+++ b/intern/cycles/render/graph.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2013 Blender Foundation
+ * Copyright 2011-2016 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,6 +17,9 @@
#ifndef __GRAPH_H__
#define __GRAPH_H__
+#include "node.h"
+#include "node_type.h"
+
#include "kernel_types.h"
#include "util_list.h"
@@ -38,23 +41,7 @@ class ShaderGraph;
class SVMCompiler;
class OSLCompiler;
class OutputNode;
-
-/* Socket Type
- *
- * Data type for inputs and outputs */
-
-enum ShaderSocketType {
- SHADER_SOCKET_UNDEFINED,
-
- SHADER_SOCKET_FLOAT,
- SHADER_SOCKET_INT,
- SHADER_SOCKET_COLOR,
- SHADER_SOCKET_VECTOR,
- SHADER_SOCKET_POINT,
- SHADER_SOCKET_NORMAL,
- SHADER_SOCKET_CLOSURE,
- SHADER_SOCKET_STRING
-};
+class ConstantFolder;
/* Bump
*
@@ -86,30 +73,6 @@ enum ShaderNodeSpecialType {
SHADER_SPECIAL_TYPE_BUMP,
};
-/* Enum
- *
- * Utility class for enum values. */
-
-class ShaderEnum {
-public:
- bool empty() const { return left.empty(); }
- void insert(const char *x, int y) {
- left[ustring(x)] = y;
- right[y] = ustring(x);
- }
-
- bool exists(ustring x) { return left.find(x) != left.end(); }
- bool exists(int y) { return right.find(y) != right.end(); }
-
- int operator[](const char *x) { return left[ustring(x)]; }
- int operator[](ustring x) { return left[x]; }
- ustring operator[](int y) { return right[y]; }
-
-protected:
- map<ustring, int> left;
- map<int, ustring> right;
-};
-
/* Input
*
* Input socket for a shader node. May be linked to an output or not. If not
@@ -118,39 +81,21 @@ protected:
class ShaderInput {
public:
- enum DefaultValue {
- TEXTURE_GENERATED,
- TEXTURE_UV,
- INCOMING,
- NORMAL,
- POSITION,
- TANGENT,
- NONE
- };
-
- enum Usage {
- USE_SVM = 1,
- USE_OSL = 2,
- USE_ALL = USE_SVM|USE_OSL
- };
-
- ShaderInput(ShaderNode *parent, const char *name, ShaderSocketType type);
- void set(const float3& v) { value = v; }
- void set(float f) { value = make_float3(f, 0, 0); }
- void set(const ustring v) { value_string = v; }
-
- const char *name;
- ShaderSocketType type;
+ ShaderInput(const SocketType& socket_type_, ShaderNode* parent_)
+ : socket_type(socket_type_), parent(parent_), link(NULL), stack_offset(SVM_STACK_INVALID)
+ {}
- ShaderNode *parent;
- ShaderOutput *link;
+ ustring name() { return socket_type.ui_name; }
+ int flags() { return socket_type.flags; }
+ SocketType::Type type() { return socket_type.type; }
- DefaultValue default_value;
- float3 value;
- ustring value_string;
+ void set(float f) { ((Node*)parent)->set(socket_type, f); }
+ void set(float3 f) { ((Node*)parent)->set(socket_type, f); }
+ const SocketType& socket_type;
+ ShaderNode *parent;
+ ShaderOutput *link;
int stack_offset; /* for SVM compiler */
- int usage;
};
/* Output
@@ -159,14 +104,16 @@ public:
class ShaderOutput {
public:
- ShaderOutput(ShaderNode *parent, const char *name, ShaderSocketType type);
+ ShaderOutput(const SocketType& socket_type_, ShaderNode* parent_)
+ : socket_type(socket_type_), parent(parent_), stack_offset(SVM_STACK_INVALID)
+ {}
- const char *name;
- ShaderNode *parent;
- ShaderSocketType type;
+ ustring name() { return socket_type.ui_name; }
+ SocketType::Type type() { return socket_type.type; }
+ const SocketType& socket_type;
+ ShaderNode *parent;
vector<ShaderInput*> links;
-
int stack_offset; /* for SVM compiler */
};
@@ -175,18 +122,17 @@ public:
* Shader node in graph, with input and output sockets. This is the virtual
* base class for all node types. */
-class ShaderNode {
+class ShaderNode : public Node {
public:
- ShaderNode(const char *name);
+ explicit ShaderNode(const NodeType *type);
virtual ~ShaderNode();
+ void create_inputs_outputs(const NodeType *type);
+
ShaderInput *input(const char *name);
ShaderOutput *output(const char *name);
-
- ShaderInput *add_input(const char *name, ShaderSocketType type, float value=0.0f, int usage=ShaderInput::USE_ALL);
- ShaderInput *add_input(const char *name, ShaderSocketType type, float3 value, int usage=ShaderInput::USE_ALL);
- ShaderInput *add_input(const char *name, ShaderSocketType type, ShaderInput::DefaultValue value, int usage=ShaderInput::USE_ALL);
- ShaderOutput *add_output(const char *name, ShaderSocketType type);
+ ShaderInput *input(ustring name);
+ ShaderOutput *output(ustring name);
virtual ShaderNode *clone() const = 0;
virtual void attributes(Shader *shader, AttributeRequestSet *attributes);
@@ -195,7 +141,7 @@ public:
/* ** Node optimization ** */
/* Check whether the node can be replaced with single constant. */
- virtual bool constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, float3 * /*optimized_value*/) { return false; }
+ virtual void constant_fold(const ConstantFolder& /*folder*/) {}
/* Simplify settings used by artists to the ones which are simpler to
* evaluate in the kernel but keep the final result unchanged.
@@ -213,7 +159,6 @@ public:
vector<ShaderInput*> inputs;
vector<ShaderOutput*> outputs;
- ustring name; /* name, not required to be unique */
int id; /* index in graph node array */
ShaderBump bump; /* for bump mapping utility */
@@ -237,6 +182,9 @@ public:
*/
virtual int get_feature() { return bump == SHADER_BUMP_NONE ? 0 : NODE_FEATURE_BUMP; }
+ /* Get closure ID to which the node compiles into. */
+ virtual ClosureType get_closure_type() { return CLOSURE_NONE_ID; }
+
/* Check whether settings of the node equals to another one.
*
* This is mainly used to check whether two nodes can be merged
@@ -246,23 +194,21 @@ public:
* NOTE: If some node can't be de-duplicated for whatever reason it
* is to be handled in the subclass.
*/
- virtual bool equals(const ShaderNode *other)
- {
- return name == other->name &&
- bump == other->bump;
- }
+ virtual bool equals(const ShaderNode& other);
};
/* Node definition utility macros */
#define SHADER_NODE_CLASS(type) \
+ NODE_DECLARE; \
type(); \
virtual ShaderNode *clone() const { return new type(*this); } \
virtual void compile(SVMCompiler& compiler); \
virtual void compile(OSLCompiler& compiler); \
#define SHADER_NODE_NO_CLONE_CLASS(type) \
+ NODE_DECLARE; \
type(); \
virtual void compile(SVMCompiler& compiler); \
virtual void compile(OSLCompiler& compiler); \
@@ -304,6 +250,7 @@ public:
OutputNode *output();
void connect(ShaderOutput *from, ShaderInput *to);
+ void disconnect(ShaderOutput *from);
void disconnect(ShaderInput *to);
void relink(ShaderNode *node, ShaderOutput *from, ShaderOutput *to);
@@ -311,7 +258,8 @@ public:
void finalize(Scene *scene,
bool do_bump = false,
bool do_osl = false,
- bool do_simplify = false);
+ bool do_simplify = false,
+ bool bump_in_object_space = false);
int get_num_closures();
@@ -325,7 +273,7 @@ protected:
void copy_nodes(ShaderNodeSet& nodes, ShaderNodeMap& nnodemap);
void break_cycles(ShaderNode *node, vector<bool>& visited, vector<bool>& on_stack);
- void bump_from_displacement();
+ void bump_from_displacement(bool use_object_space);
void refine_bump_nodes();
void default_inputs(bool do_osl);
void transform_multi_closure(ShaderNode *node, ShaderOutput *weight_out, bool volume);
diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp
index 10a5ca42fc0..073a0aa2ac9 100644
--- a/intern/cycles/render/image.cpp
+++ b/intern/cycles/render/image.cpp
@@ -19,7 +19,6 @@
#include "scene.h"
#include "util_foreach.h"
-#include "util_image.h"
#include "util_path.h"
#include "util_progress.h"
#include "util_texture.h"
@@ -37,39 +36,66 @@ ImageManager::ImageManager(const DeviceInfo& info)
osl_texture_system = NULL;
animation_frame = 0;
+ /* In case of multiple devices used we need to know type of an actual
+ * compute device.
+ *
+ * NOTE: We assume that all the devices are same type, otherwise we'll
+ * be screwed on so many levels..
+ */
+ DeviceType device_type = info.type;
+ if(device_type == DEVICE_MULTI) {
+ device_type = info.multi_devices[0].type;
+ }
+
/* Set image limits */
+#define SET_TEX_IMAGES_LIMITS(ARCH) \
+ { \
+ tex_num_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_NUM_FLOAT4_ ## ARCH; \
+ tex_num_images[IMAGE_DATA_TYPE_BYTE4] = TEX_NUM_BYTE4_ ## ARCH; \
+ tex_num_images[IMAGE_DATA_TYPE_HALF4] = TEX_NUM_HALF4_ ## ARCH; \
+ tex_num_images[IMAGE_DATA_TYPE_FLOAT] = TEX_NUM_FLOAT_ ## ARCH; \
+ tex_num_images[IMAGE_DATA_TYPE_BYTE] = TEX_NUM_BYTE_ ## ARCH; \
+ tex_num_images[IMAGE_DATA_TYPE_HALF] = TEX_NUM_HALF_ ## ARCH; \
+ tex_start_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_START_FLOAT4_ ## ARCH; \
+ tex_start_images[IMAGE_DATA_TYPE_BYTE4] = TEX_START_BYTE4_ ## ARCH; \
+ tex_start_images[IMAGE_DATA_TYPE_HALF4] = TEX_START_HALF4_ ## ARCH; \
+ tex_start_images[IMAGE_DATA_TYPE_FLOAT] = TEX_START_FLOAT_ ## ARCH; \
+ tex_start_images[IMAGE_DATA_TYPE_BYTE] = TEX_START_BYTE_ ## ARCH; \
+ tex_start_images[IMAGE_DATA_TYPE_HALF] = TEX_START_HALF_ ## ARCH; \
+ }
- /* CPU */
- if(info.type == DEVICE_CPU) {
- tex_num_images[IMAGE_DATA_TYPE_BYTE4] = TEX_NUM_BYTE4_IMAGES_CPU;
- tex_num_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_NUM_FLOAT4_IMAGES_CPU;
- tex_image_byte4_start = TEX_IMAGE_BYTE4_START_CPU;
- }
- /* CUDA (Fermi) */
- else if((info.type == DEVICE_CUDA || info.type == DEVICE_MULTI) && !info.extended_images) {
- tex_num_images[IMAGE_DATA_TYPE_BYTE4] = TEX_NUM_BYTE4_IMAGES_CUDA;
- tex_num_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_NUM_FLOAT4_IMAGES_CUDA;
- tex_image_byte4_start = TEX_IMAGE_BYTE4_START_CUDA;
- }
- /* CUDA (Kepler and above) */
- else if((info.type == DEVICE_CUDA || info.type == DEVICE_MULTI) && info.extended_images) {
- tex_num_images[IMAGE_DATA_TYPE_BYTE4] = TEX_NUM_BYTE4_IMAGES_CUDA_KEPLER;
- tex_num_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_NUM_FLOAT4_IMAGES_CUDA_KEPLER;
- tex_image_byte4_start = TEX_IMAGE_BYTE4_START_CUDA_KELPER;
- }
- /* OpenCL */
- else if(info.pack_images) {
- tex_num_images[IMAGE_DATA_TYPE_BYTE4] = TEX_NUM_BYTE4_IMAGES_OPENCL;
- tex_num_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_NUM_FLOAT4_IMAGES_OPENCL;
- tex_image_byte4_start = TEX_IMAGE_BYTE4_START_OPENCL;
- }
- /* Should never happen */
+ if(device_type == DEVICE_CPU) {
+ SET_TEX_IMAGES_LIMITS(CPU);
+ }
+ else if(device_type == DEVICE_CUDA) {
+ if(info.has_bindless_textures) {
+ SET_TEX_IMAGES_LIMITS(CUDA_KEPLER);
+ }
+ else {
+ SET_TEX_IMAGES_LIMITS(CUDA);
+ }
+ }
+ else if(device_type == DEVICE_OPENCL) {
+ SET_TEX_IMAGES_LIMITS(OPENCL);
+ }
else {
- tex_num_images[IMAGE_DATA_TYPE_BYTE4] = 0;
+ /* Should not happen. */
tex_num_images[IMAGE_DATA_TYPE_FLOAT4] = 0;
- tex_image_byte4_start = 0;
+ tex_num_images[IMAGE_DATA_TYPE_BYTE4] = 0;
+ tex_num_images[IMAGE_DATA_TYPE_HALF4] = 0;
+ tex_num_images[IMAGE_DATA_TYPE_FLOAT] = 0;
+ tex_num_images[IMAGE_DATA_TYPE_BYTE] = 0;
+ tex_num_images[IMAGE_DATA_TYPE_HALF] = 0;
+ tex_start_images[IMAGE_DATA_TYPE_FLOAT4] = 0;
+ tex_start_images[IMAGE_DATA_TYPE_BYTE4] = 0;
+ tex_start_images[IMAGE_DATA_TYPE_HALF4] = 0;
+ tex_start_images[IMAGE_DATA_TYPE_FLOAT] = 0;
+ tex_start_images[IMAGE_DATA_TYPE_BYTE] = 0;
+ tex_start_images[IMAGE_DATA_TYPE_HALF] = 0;
assert(0);
}
+
+#undef SET_TEX_IMAGES_LIMITS
}
ImageManager::~ImageManager()
@@ -106,21 +132,27 @@ bool ImageManager::set_animation_frame_update(int frame)
return false;
}
-bool ImageManager::is_float_image(const string& filename, void *builtin_data, bool& is_linear)
+ImageManager::ImageDataType ImageManager::get_image_metadata(const string& filename,
+ void *builtin_data,
+ bool& is_linear)
{
- bool is_float = false;
+ bool is_float = false, is_half = false;
is_linear = false;
+ int channels = 4;
if(builtin_data) {
if(builtin_image_info_cb) {
- int width, height, depth, channels;
+ int width, height, depth;
builtin_image_info_cb(filename, builtin_data, is_float, width, height, depth, channels);
}
- if(is_float)
+ if(is_float) {
is_linear = true;
-
- return is_float;
+ return (channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 : IMAGE_DATA_TYPE_FLOAT;
+ }
+ else {
+ return (channels > 1) ? IMAGE_DATA_TYPE_BYTE4 : IMAGE_DATA_TYPE_BYTE;
+ }
}
ImageInput *in = ImageInput::create(filename);
@@ -143,6 +175,12 @@ bool ImageManager::is_float_image(const string& filename, void *builtin_data, bo
}
}
+ /* check if it's half float */
+ if(spec.format == TypeDesc::HALF)
+ is_half = true;
+
+ channels = spec.nchannels;
+
/* basic color space detection, not great but better than nothing
* before we do OpenColorIO integration */
if(is_float) {
@@ -166,35 +204,53 @@ bool ImageManager::is_float_image(const string& filename, void *builtin_data, bo
delete in;
}
- return is_float;
+ if(is_half) {
+ return (channels > 1) ? IMAGE_DATA_TYPE_HALF4 : IMAGE_DATA_TYPE_HALF;
+ }
+ else if(is_float) {
+ return (channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 : IMAGE_DATA_TYPE_FLOAT;
+ }
+ else {
+ return (channels > 1) ? IMAGE_DATA_TYPE_BYTE4 : IMAGE_DATA_TYPE_BYTE;
+ }
}
+/* We use a consecutive slot counting scheme on the devices, in order
+ * float4, byte4, half4, float, byte, half.
+ * These functions convert the slot ids from ImageManager "images" ones
+ * to device ones and vice versa. */
int ImageManager::type_index_to_flattened_slot(int slot, ImageDataType type)
{
- if(type == IMAGE_DATA_TYPE_BYTE4)
- return slot + tex_image_byte4_start;
- else
- return slot;
+ return slot + tex_start_images[type];
}
int ImageManager::flattened_slot_to_type_index(int flat_slot, ImageDataType *type)
{
- if(flat_slot >= tex_image_byte4_start) {
- *type = IMAGE_DATA_TYPE_BYTE4;
- return flat_slot - tex_image_byte4_start;
- }
- else {
- *type = IMAGE_DATA_TYPE_FLOAT4;
- return flat_slot;
+ for(int i = IMAGE_DATA_NUM_TYPES - 1; i >= 0; i--) {
+ if(flat_slot >= tex_start_images[i]) {
+ *type = (ImageDataType)i;
+ return flat_slot - tex_start_images[i];
+ }
}
+
+ /* Should not happen. */
+ return flat_slot;
}
string ImageManager::name_from_type(int type)
{
if(type == IMAGE_DATA_TYPE_FLOAT4)
+ return "float4";
+ else if(type == IMAGE_DATA_TYPE_FLOAT)
return "float";
- else
+ else if(type == IMAGE_DATA_TYPE_BYTE)
return "byte";
+ else if(type == IMAGE_DATA_TYPE_HALF4)
+ return "half4";
+ else if(type == IMAGE_DATA_TYPE_HALF)
+ return "half";
+ else
+ return "byte4";
}
static bool image_equals(ImageManager::Image *image,
@@ -222,19 +278,33 @@ int ImageManager::add_image(const string& filename,
Image *img;
size_t slot;
- /* Load image info and find out if we need a float texture. */
- is_float = is_float_image(filename, builtin_data, is_linear);
+ ImageDataType type = get_image_metadata(filename, builtin_data, is_linear);
+
+ thread_scoped_lock device_lock(device_mutex);
+
+ /* Do we have a float? */
+ if(type == IMAGE_DATA_TYPE_FLOAT || type == IMAGE_DATA_TYPE_FLOAT4)
+ is_float = true;
- ImageDataType type = is_float? IMAGE_DATA_TYPE_FLOAT4 : IMAGE_DATA_TYPE_BYTE4;
+ /* No single channel and half textures on CUDA (Fermi) and no half on OpenCL, use available slots */
+ if((type == IMAGE_DATA_TYPE_FLOAT ||
+ type == IMAGE_DATA_TYPE_HALF4 ||
+ type == IMAGE_DATA_TYPE_HALF) &&
+ tex_num_images[type] == 0) {
+ type = IMAGE_DATA_TYPE_FLOAT4;
+ }
+ if(type == IMAGE_DATA_TYPE_BYTE && tex_num_images[type] == 0) {
+ type = IMAGE_DATA_TYPE_BYTE4;
+ }
/* Fnd existing image. */
for(slot = 0; slot < images[type].size(); slot++) {
img = images[type][slot];
if(img && image_equals(img,
- filename,
- builtin_data,
- interpolation,
- extension))
+ filename,
+ builtin_data,
+ interpolation,
+ extension))
{
if(img->frame != frame) {
img->frame = frame;
@@ -313,10 +383,10 @@ void ImageManager::remove_image(const string& filename,
for(int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) {
for(slot = 0; slot < images[type].size(); slot++) {
if(images[type][slot] && image_equals(images[type][slot],
- filename,
- builtin_data,
- interpolation,
- extension))
+ filename,
+ builtin_data,
+ interpolation,
+ extension))
{
remove_image(type_index_to_flattened_slot(slot, (ImageDataType)type));
return;
@@ -337,10 +407,10 @@ void ImageManager::tag_reload_image(const string& filename,
for(size_t type = 0; type < IMAGE_DATA_NUM_TYPES; type++) {
for(size_t slot = 0; slot < images[type].size(); slot++) {
if(images[type][slot] && image_equals(images[type][slot],
- filename,
- builtin_data,
- interpolation,
- extension))
+ filename,
+ builtin_data,
+ interpolation,
+ extension))
{
images[type][slot]->need_load = true;
break;
@@ -349,19 +419,16 @@ void ImageManager::tag_reload_image(const string& filename,
}
}
-bool ImageManager::file_load_image(Image *img, device_vector<uchar4>& tex_img)
+bool ImageManager::file_load_image_generic(Image *img, ImageInput **in, int &width, int &height, int &depth, int &components)
{
if(img->filename == "")
return false;
- ImageInput *in = NULL;
- int width, height, depth, components;
-
if(!img->builtin_data) {
/* load image from file through OIIO */
- in = ImageInput::create(img->filename);
+ *in = ImageInput::create(img->filename);
- if(!in)
+ if(!*in)
return false;
ImageSpec spec = ImageSpec();
@@ -370,8 +437,9 @@ bool ImageManager::file_load_image(Image *img, device_vector<uchar4>& tex_img)
if(img->use_alpha == false)
config.attribute("oiio:UnassociatedAlpha", 1);
- if(!in->open(img->filename, spec, config)) {
- delete in;
+ if(!(*in)->open(img->filename, spec, config)) {
+ delete *in;
+ *in = NULL;
return false;
}
@@ -391,14 +459,27 @@ bool ImageManager::file_load_image(Image *img, device_vector<uchar4>& tex_img)
/* we only handle certain number of components */
if(!(components >= 1 && components <= 4)) {
- if(in) {
- in->close();
- delete in;
+ if(*in) {
+ (*in)->close();
+ delete *in;
+ *in = NULL;
}
return false;
}
+ return true;
+}
+
+template<typename T>
+bool ImageManager::file_load_byte_image(Image *img, ImageDataType type, device_vector<T>& tex_img)
+{
+ ImageInput *in = NULL;
+ int width, height, depth, components;
+
+ if(!file_load_image_generic(img, &in, width, height, depth, components))
+ return false;
+
/* read RGBA pixels */
uchar *pixels = (uchar*)tex_img.resize(width, height, depth);
if(pixels == NULL) {
@@ -411,10 +492,10 @@ bool ImageManager::file_load_image(Image *img, device_vector<uchar4>& tex_img)
int scanlinesize = width*components*sizeof(uchar);
in->read_image(TypeDesc::UINT8,
- (uchar*)pixels + (((size_t)height)-1)*scanlinesize,
- AutoStride,
- -scanlinesize,
- AutoStride);
+ (uchar*)pixels + (((size_t)height)-1)*scanlinesize,
+ AutoStride,
+ -scanlinesize,
+ AutoStride);
}
else {
in->read_image(TypeDesc::UINT8, (uchar*)pixels);
@@ -429,101 +510,65 @@ bool ImageManager::file_load_image(Image *img, device_vector<uchar4>& tex_img)
builtin_image_pixels_cb(img->filename, img->builtin_data, pixels);
}
- size_t num_pixels = ((size_t)width) * height * depth;
- if(cmyk) {
- /* CMYK */
- for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+2] = (pixels[i*4+2]*pixels[i*4+3])/255;
- pixels[i*4+1] = (pixels[i*4+1]*pixels[i*4+3])/255;
- pixels[i*4+0] = (pixels[i*4+0]*pixels[i*4+3])/255;
- pixels[i*4+3] = 255;
+ /* Check if we actually have a byte4 slot, in case components == 1, but device
+ * doesn't support single channel textures. */
+ if(type == IMAGE_DATA_TYPE_BYTE4) {
+ size_t num_pixels = ((size_t)width) * height * depth;
+ if(cmyk) {
+ /* CMYK */
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
+ pixels[i*4+2] = (pixels[i*4+2]*pixels[i*4+3])/255;
+ pixels[i*4+1] = (pixels[i*4+1]*pixels[i*4+3])/255;
+ pixels[i*4+0] = (pixels[i*4+0]*pixels[i*4+3])/255;
+ pixels[i*4+3] = 255;
+ }
}
- }
- else if(components == 2) {
- /* grayscale + alpha */
- for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+3] = pixels[i*2+1];
- pixels[i*4+2] = pixels[i*2+0];
- pixels[i*4+1] = pixels[i*2+0];
- pixels[i*4+0] = pixels[i*2+0];
+ else if(components == 2) {
+ /* grayscale + alpha */
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
+ pixels[i*4+3] = pixels[i*2+1];
+ pixels[i*4+2] = pixels[i*2+0];
+ pixels[i*4+1] = pixels[i*2+0];
+ pixels[i*4+0] = pixels[i*2+0];
+ }
}
- }
- else if(components == 3) {
- /* RGB */
- for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+3] = 255;
- pixels[i*4+2] = pixels[i*3+2];
- pixels[i*4+1] = pixels[i*3+1];
- pixels[i*4+0] = pixels[i*3+0];
+ else if(components == 3) {
+ /* RGB */
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
+ pixels[i*4+3] = 255;
+ pixels[i*4+2] = pixels[i*3+2];
+ pixels[i*4+1] = pixels[i*3+1];
+ pixels[i*4+0] = pixels[i*3+0];
+ }
}
- }
- else if(components == 1) {
- /* grayscale */
- for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+3] = 255;
- pixels[i*4+2] = pixels[i];
- pixels[i*4+1] = pixels[i];
- pixels[i*4+0] = pixels[i];
+ else if(components == 1) {
+ /* grayscale */
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
+ pixels[i*4+3] = 255;
+ pixels[i*4+2] = pixels[i];
+ pixels[i*4+1] = pixels[i];
+ pixels[i*4+0] = pixels[i];
+ }
}
- }
- if(img->use_alpha == false) {
- for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+3] = 255;
+ if(img->use_alpha == false) {
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
+ pixels[i*4+3] = 255;
+ }
}
}
return true;
}
-bool ImageManager::file_load_float_image(Image *img, device_vector<float4>& tex_img)
+template<typename T>
+bool ImageManager::file_load_float_image(Image *img, ImageDataType type, device_vector<T>& tex_img)
{
- if(img->filename == "")
- return false;
-
ImageInput *in = NULL;
int width, height, depth, components;
- if(!img->builtin_data) {
- /* load image from file through OIIO */
- in = ImageInput::create(img->filename);
-
- if(!in)
- return false;
-
- ImageSpec spec = ImageSpec();
- ImageSpec config = ImageSpec();
-
- if(img->use_alpha == false)
- config.attribute("oiio:UnassociatedAlpha",1);
-
- if(!in->open(img->filename, spec, config)) {
- delete in;
- return false;
- }
-
- /* we only handle certain number of components */
- width = spec.width;
- height = spec.height;
- depth = spec.depth;
- components = spec.nchannels;
- }
- else {
- /* load image using builtin images callbacks */
- if(!builtin_image_info_cb || !builtin_image_float_pixels_cb)
- return false;
-
- bool is_float;
- builtin_image_info_cb(img->filename, img->builtin_data, is_float, width, height, depth, components);
- }
-
- if(components < 1 || width == 0 || height == 0) {
- if(in) {
- in->close();
- delete in;
- }
+ if(!file_load_image_generic(img, &in, width, height, depth, components))
return false;
- }
/* read RGBA pixels */
float *pixels = (float*)tex_img.resize(width, height, depth);
@@ -542,13 +587,12 @@ bool ImageManager::file_load_float_image(Image *img, device_vector<float4>& tex_
}
if(depth <= 1) {
- int scanlinesize = width*components*sizeof(float);
-
+ size_t scanlinesize = ((size_t)width)*components*sizeof(float);
in->read_image(TypeDesc::FLOAT,
- (uchar*)readpixels + (height-1)*scanlinesize,
- AutoStride,
- -scanlinesize,
- AutoStride);
+ (uchar*)readpixels + (height-1)*scanlinesize,
+ AutoStride,
+ -scanlinesize,
+ AutoStride);
}
else {
in->read_image(TypeDesc::FLOAT, (uchar*)readpixels);
@@ -575,47 +619,151 @@ bool ImageManager::file_load_float_image(Image *img, device_vector<float4>& tex_
builtin_image_float_pixels_cb(img->filename, img->builtin_data, pixels);
}
- size_t num_pixels = ((size_t)width) * height * depth;
- if(cmyk) {
- /* CMYK */
- for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+3] = 255;
- pixels[i*4+2] = (pixels[i*4+2]*pixels[i*4+3])/255;
- pixels[i*4+1] = (pixels[i*4+1]*pixels[i*4+3])/255;
- pixels[i*4+0] = (pixels[i*4+0]*pixels[i*4+3])/255;
+ /* Check if we actually have a float4 slot, in case components == 1, but device
+ * doesn't support single channel textures. */
+ if(type == IMAGE_DATA_TYPE_FLOAT4) {
+ size_t num_pixels = ((size_t)width) * height * depth;
+ if(cmyk) {
+ /* CMYK */
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
+ pixels[i*4+3] = 255;
+ pixels[i*4+2] = (pixels[i*4+2]*pixels[i*4+3])/255;
+ pixels[i*4+1] = (pixels[i*4+1]*pixels[i*4+3])/255;
+ pixels[i*4+0] = (pixels[i*4+0]*pixels[i*4+3])/255;
+ }
}
- }
- else if(components == 2) {
- /* grayscale + alpha */
- for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+3] = pixels[i*2+1];
- pixels[i*4+2] = pixels[i*2+0];
- pixels[i*4+1] = pixels[i*2+0];
- pixels[i*4+0] = pixels[i*2+0];
+ else if(components == 2) {
+ /* grayscale + alpha */
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
+ pixels[i*4+3] = pixels[i*2+1];
+ pixels[i*4+2] = pixels[i*2+0];
+ pixels[i*4+1] = pixels[i*2+0];
+ pixels[i*4+0] = pixels[i*2+0];
+ }
}
- }
- else if(components == 3) {
- /* RGB */
- for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+3] = 1.0f;
- pixels[i*4+2] = pixels[i*3+2];
- pixels[i*4+1] = pixels[i*3+1];
- pixels[i*4+0] = pixels[i*3+0];
+ else if(components == 3) {
+ /* RGB */
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
+ pixels[i*4+3] = 1.0f;
+ pixels[i*4+2] = pixels[i*3+2];
+ pixels[i*4+1] = pixels[i*3+1];
+ pixels[i*4+0] = pixels[i*3+0];
+ }
+ }
+ else if(components == 1) {
+ /* grayscale */
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
+ pixels[i*4+3] = 1.0f;
+ pixels[i*4+2] = pixels[i];
+ pixels[i*4+1] = pixels[i];
+ pixels[i*4+0] = pixels[i];
+ }
+ }
+
+ if(img->use_alpha == false) {
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
+ pixels[i*4+3] = 1.0f;
+ }
}
}
- else if(components == 1) {
- /* grayscale */
- for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+3] = 1.0f;
- pixels[i*4+2] = pixels[i];
- pixels[i*4+1] = pixels[i];
- pixels[i*4+0] = pixels[i];
+
+ return true;
+}
+
+template<typename T>
+bool ImageManager::file_load_half_image(Image *img, ImageDataType type, device_vector<T>& tex_img)
+{
+ ImageInput *in = NULL;
+ int width, height, depth, components;
+
+ if(!file_load_image_generic(img, &in, width, height, depth, components))
+ return false;
+
+ /* read RGBA pixels */
+ half *pixels = (half*)tex_img.resize(width, height, depth);
+ if(pixels == NULL) {
+ return false;
+ }
+
+ if(in) {
+ half *readpixels = pixels;
+ vector<half> tmppixels;
+
+ if(components > 4) {
+ tmppixels.resize(((size_t)width)*height*components);
+ readpixels = &tmppixels[0];
+ }
+
+ if(depth <= 1) {
+ size_t scanlinesize = ((size_t)width)*components*sizeof(half);
+ in->read_image(TypeDesc::HALF,
+ (uchar*)readpixels + (height-1)*scanlinesize,
+ AutoStride,
+ -scanlinesize,
+ AutoStride);
}
+ else {
+ in->read_image(TypeDesc::HALF, (uchar*)readpixels);
+ }
+
+ if(components > 4) {
+ size_t dimensions = ((size_t)width)*height;
+ for(size_t i = dimensions-1, pixel = 0; pixel < dimensions; pixel++, i--) {
+ pixels[i*4+3] = tmppixels[i*components+3];
+ pixels[i*4+2] = tmppixels[i*components+2];
+ pixels[i*4+1] = tmppixels[i*components+1];
+ pixels[i*4+0] = tmppixels[i*components+0];
+ }
+
+ tmppixels.clear();
+ }
+
+ in->close();
+ delete in;
+ }
+#if 0
+ /* TODO(dingto): Support half for ImBuf. */
+ else {
+ builtin_image_float_pixels_cb(img->filename, img->builtin_data, pixels);
}
+#endif
+
+ /* Check if we actually have a half4 slot, in case components == 1, but device
+ * doesn't support single channel textures. */
+ if(type == IMAGE_DATA_TYPE_HALF4) {
+ size_t num_pixels = ((size_t)width) * height * depth;
+ if(components == 2) {
+ /* grayscale + alpha */
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
+ pixels[i*4+3] = pixels[i*2+1];
+ pixels[i*4+2] = pixels[i*2+0];
+ pixels[i*4+1] = pixels[i*2+0];
+ pixels[i*4+0] = pixels[i*2+0];
+ }
+ }
+ else if(components == 3) {
+ /* RGB */
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
+ pixels[i*4+3] = 1.0f;
+ pixels[i*4+2] = pixels[i*3+2];
+ pixels[i*4+1] = pixels[i*3+1];
+ pixels[i*4+0] = pixels[i*3+0];
+ }
+ }
+ else if(components == 1) {
+ /* grayscale */
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
+ pixels[i*4+3] = 1.0f;
+ pixels[i*4+2] = pixels[i];
+ pixels[i*4+1] = pixels[i];
+ pixels[i*4+0] = pixels[i];
+ }
+ }
- if(img->use_alpha == false) {
- for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+3] = 1.0f;
+ if(img->use_alpha == false) {
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
+ pixels[i*4+3] = 1.0f;
+ }
}
}
@@ -635,6 +783,17 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD
string filename = path_filename(images[type][slot]->filename);
progress->set_status("Updating Images", "Loading " + filename);
+ /* Slot assignment */
+ int flat_slot = type_index_to_flattened_slot(slot, type);
+
+ string name;
+ if(flat_slot >= 100)
+ name = string_printf("__tex_image_%s_%d", name_from_type(type).c_str(), flat_slot);
+ else if(flat_slot >= 10)
+ name = string_printf("__tex_image_%s_0%d", name_from_type(type).c_str(), flat_slot);
+ else
+ name = string_printf("__tex_image_%s_00%d", name_from_type(type).c_str(), flat_slot);
+
if(type == IMAGE_DATA_TYPE_FLOAT4) {
device_vector<float4>& tex_img = dscene->tex_float4_image[slot];
@@ -643,7 +802,7 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD
device->tex_free(tex_img);
}
- if(!file_load_float_image(img, tex_img)) {
+ if(!file_load_float_image(img, type, tex_img)) {
/* on failure to load, we set a 1x1 pixels pink image */
float *pixels = (float*)tex_img.resize(1, 1);
@@ -653,12 +812,28 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD
pixels[3] = TEX_IMAGE_MISSING_A;
}
- string name;
+ if(!pack_images) {
+ thread_scoped_lock device_lock(device_mutex);
+ device->tex_alloc(name.c_str(),
+ tex_img,
+ img->interpolation,
+ img->extension);
+ }
+ }
+ else if(type == IMAGE_DATA_TYPE_FLOAT) {
+ device_vector<float>& tex_img = dscene->tex_float_image[slot];
- int flat_slot = type_index_to_flattened_slot(slot, type);
- if(flat_slot >= 100) name = string_printf("__tex_image_float4_%d", flat_slot);
- else if(flat_slot >= 10) name = string_printf("__tex_image_float4_0%d", flat_slot);
- else name = string_printf("__tex_image_float4_00%d", flat_slot);
+ if(tex_img.device_pointer) {
+ thread_scoped_lock device_lock(device_mutex);
+ device->tex_free(tex_img);
+ }
+
+ if(!file_load_float_image(img, type, tex_img)) {
+ /* on failure to load, we set a 1x1 pixels pink image */
+ float *pixels = (float*)tex_img.resize(1, 1);
+
+ pixels[0] = TEX_IMAGE_MISSING_R;
+ }
if(!pack_images) {
thread_scoped_lock device_lock(device_mutex);
@@ -668,7 +843,7 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD
img->extension);
}
}
- else {
+ else if(type == IMAGE_DATA_TYPE_BYTE4) {
device_vector<uchar4>& tex_img = dscene->tex_byte4_image[slot];
if(tex_img.device_pointer) {
@@ -676,7 +851,7 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD
device->tex_free(tex_img);
}
- if(!file_load_image(img, tex_img)) {
+ if(!file_load_byte_image(img, type, tex_img)) {
/* on failure to load, we set a 1x1 pixels pink image */
uchar *pixels = (uchar*)tex_img.resize(1, 1);
@@ -686,12 +861,77 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD
pixels[3] = (TEX_IMAGE_MISSING_A * 255);
}
- string name;
+ if(!pack_images) {
+ thread_scoped_lock device_lock(device_mutex);
+ device->tex_alloc(name.c_str(),
+ tex_img,
+ img->interpolation,
+ img->extension);
+ }
+ }
+ else if(type == IMAGE_DATA_TYPE_BYTE){
+ device_vector<uchar>& tex_img = dscene->tex_byte_image[slot];
- int flat_slot = type_index_to_flattened_slot(slot, type);
- if(flat_slot >= 100) name = string_printf("__tex_image_byte4_%d", flat_slot);
- else if(flat_slot >= 10) name = string_printf("__tex_image_byte4_0%d", flat_slot);
- else name = string_printf("__tex_image_byte4_00%d", flat_slot);
+ if(tex_img.device_pointer) {
+ thread_scoped_lock device_lock(device_mutex);
+ device->tex_free(tex_img);
+ }
+
+ if(!file_load_byte_image(img, type, tex_img)) {
+ /* on failure to load, we set a 1x1 pixels pink image */
+ uchar *pixels = (uchar*)tex_img.resize(1, 1);
+
+ pixels[0] = (TEX_IMAGE_MISSING_R * 255);
+ }
+
+ if(!pack_images) {
+ thread_scoped_lock device_lock(device_mutex);
+ device->tex_alloc(name.c_str(),
+ tex_img,
+ img->interpolation,
+ img->extension);
+ }
+ }
+ else if(type == IMAGE_DATA_TYPE_HALF4){
+ device_vector<half4>& tex_img = dscene->tex_half4_image[slot];
+
+ if(tex_img.device_pointer) {
+ thread_scoped_lock device_lock(device_mutex);
+ device->tex_free(tex_img);
+ }
+
+ if(!file_load_half_image(img, type, tex_img)) {
+ /* on failure to load, we set a 1x1 pixels pink image */
+ half *pixels = (half*)tex_img.resize(1, 1);
+
+ pixels[0] = TEX_IMAGE_MISSING_R;
+ pixels[1] = TEX_IMAGE_MISSING_G;
+ pixels[2] = TEX_IMAGE_MISSING_B;
+ pixels[3] = TEX_IMAGE_MISSING_A;
+ }
+
+ if(!pack_images) {
+ thread_scoped_lock device_lock(device_mutex);
+ device->tex_alloc(name.c_str(),
+ tex_img,
+ img->interpolation,
+ img->extension);
+ }
+ }
+ else if(type == IMAGE_DATA_TYPE_HALF){
+ device_vector<half>& tex_img = dscene->tex_half_image[slot];
+
+ if(tex_img.device_pointer) {
+ thread_scoped_lock device_lock(device_mutex);
+ device->tex_free(tex_img);
+ }
+
+ if(!file_load_half_image(img, type, tex_img)) {
+ /* on failure to load, we set a 1x1 pixels pink image */
+ half *pixels = (half*)tex_img.resize(1, 1);
+
+ pixels[0] = TEX_IMAGE_MISSING_R;
+ }
if(!pack_images) {
thread_scoped_lock device_lock(device_mutex);
@@ -725,11 +965,18 @@ void ImageManager::device_free_image(Device *device, DeviceScene *dscene, ImageD
}
tex_img.clear();
+ }
+ else if(type == IMAGE_DATA_TYPE_FLOAT) {
+ device_vector<float>& tex_img = dscene->tex_float_image[slot];
- delete images[type][slot];
- images[type][slot] = NULL;
+ if(tex_img.device_pointer) {
+ thread_scoped_lock device_lock(device_mutex);
+ device->tex_free(tex_img);
+ }
+
+ tex_img.clear();
}
- else {
+ else if(type == IMAGE_DATA_TYPE_BYTE4) {
device_vector<uchar4>& tex_img = dscene->tex_byte4_image[slot];
if(tex_img.device_pointer) {
@@ -738,10 +985,40 @@ void ImageManager::device_free_image(Device *device, DeviceScene *dscene, ImageD
}
tex_img.clear();
+ }
+ else if(type == IMAGE_DATA_TYPE_BYTE){
+ device_vector<uchar>& tex_img = dscene->tex_byte_image[slot];
- delete images[type][slot];
- images[type][slot] = NULL;
+ if(tex_img.device_pointer) {
+ thread_scoped_lock device_lock(device_mutex);
+ device->tex_free(tex_img);
+ }
+
+ tex_img.clear();
+ }
+ else if(type == IMAGE_DATA_TYPE_HALF4){
+ device_vector<half4>& tex_img = dscene->tex_half4_image[slot];
+
+ if(tex_img.device_pointer) {
+ thread_scoped_lock device_lock(device_mutex);
+ device->tex_free(tex_img);
+ }
+
+ tex_img.clear();
+ }
+ else if(type == IMAGE_DATA_TYPE_HALF){
+ device_vector<half>& tex_img = dscene->tex_half_image[slot];
+
+ if(tex_img.device_pointer) {
+ thread_scoped_lock device_lock(device_mutex);
+ device->tex_free(tex_img);
+ }
+
+ tex_img.clear();
}
+
+ delete images[type][slot];
+ images[type][slot] = NULL;
}
}
@@ -799,6 +1076,26 @@ void ImageManager::device_update_slot(Device *device,
}
}
+uint8_t ImageManager::pack_image_options(ImageDataType type, size_t slot)
+{
+ uint8_t options = 0;
+
+ /* Image Options are packed into one uint:
+ * bit 0 -> Interpolation
+ * bit 1 + 2 + 3-> Extension */
+ if(images[type][slot]->interpolation == INTERPOLATION_CLOSEST)
+ options |= (1 << 0);
+
+ if(images[type][slot]->extension == EXTENSION_REPEAT)
+ options |= (1 << 1);
+ else if(images[type][slot]->extension == EXTENSION_EXTEND)
+ options |= (1 << 2);
+ else /* EXTENSION_CLIP */
+ options |= (1 << 3);
+
+ return options;
+}
+
void ImageManager::device_pack_images(Device *device,
DeviceScene *dscene,
Progress& /*progess*/)
@@ -808,10 +1105,11 @@ void ImageManager::device_pack_images(Device *device,
size_t size = 0, offset = 0;
ImageDataType type;
- int info_size = tex_num_images[IMAGE_DATA_TYPE_FLOAT4] + tex_num_images[IMAGE_DATA_TYPE_BYTE4];
- uint4 *info = dscene->tex_image_packed_info.resize(info_size);
+ int info_size = tex_num_images[IMAGE_DATA_TYPE_FLOAT4] + tex_num_images[IMAGE_DATA_TYPE_BYTE4]
+ + tex_num_images[IMAGE_DATA_TYPE_FLOAT] + tex_num_images[IMAGE_DATA_TYPE_BYTE];
+ uint4 *info = dscene->tex_image_packed_info.resize(info_size*2);
- /* Byte Textures*/
+ /* Byte4 Textures*/
type = IMAGE_DATA_TYPE_BYTE4;
for(size_t slot = 0; slot < images[type].size(); slot++) {
@@ -822,7 +1120,7 @@ void ImageManager::device_pack_images(Device *device,
size += tex_img.size();
}
- uchar4 *pixels_byte = dscene->tex_image_byte4_packed.resize(size);
+ uchar4 *pixels_byte4 = dscene->tex_image_byte4_packed.resize(size);
for(size_t slot = 0; slot < images[type].size(); slot++) {
if(!images[type][slot])
@@ -830,17 +1128,17 @@ void ImageManager::device_pack_images(Device *device,
device_vector<uchar4>& tex_img = dscene->tex_byte4_image[slot];
- /* The image options are packed
- bit 0 -> periodic
- bit 1 + 2 -> interpolation type */
- uint8_t interpolation = (images[type][slot]->interpolation << 1) + 1;
- info[type_index_to_flattened_slot(slot, type)] = make_uint4(tex_img.data_width, tex_img.data_height, offset, interpolation);
+ uint8_t options = pack_image_options(type, slot);
- memcpy(pixels_byte+offset, (void*)tex_img.data_pointer, tex_img.memory_size());
+ int index = type_index_to_flattened_slot(slot, type) * 2;
+ info[index] = make_uint4(tex_img.data_width, tex_img.data_height, offset, options);
+ info[index+1] = make_uint4(tex_img.data_depth, 0, 0, 0);
+
+ memcpy(pixels_byte4+offset, (void*)tex_img.data_pointer, tex_img.memory_size());
offset += tex_img.size();
}
- /* Float Textures*/
+ /* Float4 Textures*/
type = IMAGE_DATA_TYPE_FLOAT4;
size = 0, offset = 0;
@@ -852,7 +1150,7 @@ void ImageManager::device_pack_images(Device *device,
size += tex_img.size();
}
- float4 *pixels_float = dscene->tex_image_float4_packed.resize(size);
+ float4 *pixels_float4 = dscene->tex_image_float4_packed.resize(size);
for(size_t slot = 0; slot < images[type].size(); slot++) {
if(!images[type][slot])
@@ -862,11 +1160,73 @@ void ImageManager::device_pack_images(Device *device,
/* todo: support 3D textures, only CPU for now */
- /* The image options are packed
- bit 0 -> periodic
- bit 1 + 2 -> interpolation type */
- uint8_t interpolation = (images[type][slot]->interpolation << 1) + 1;
- info[type_index_to_flattened_slot(slot, type)] = make_uint4(tex_img.data_width, tex_img.data_height, offset, interpolation);
+ uint8_t options = pack_image_options(type, slot);
+
+ int index = type_index_to_flattened_slot(slot, type) * 2;
+ info[index] = make_uint4(tex_img.data_width, tex_img.data_height, offset, options);
+ info[index+1] = make_uint4(tex_img.data_depth, 0, 0, 0);
+
+ memcpy(pixels_float4+offset, (void*)tex_img.data_pointer, tex_img.memory_size());
+ offset += tex_img.size();
+ }
+
+ /* Byte Textures*/
+ type = IMAGE_DATA_TYPE_BYTE;
+ size = 0, offset = 0;
+
+ for(size_t slot = 0; slot < images[type].size(); slot++) {
+ if(!images[type][slot])
+ continue;
+
+ device_vector<uchar>& tex_img = dscene->tex_byte_image[slot];
+ size += tex_img.size();
+ }
+
+ uchar *pixels_byte = dscene->tex_image_byte_packed.resize(size);
+
+ for(size_t slot = 0; slot < images[type].size(); slot++) {
+ if(!images[type][slot])
+ continue;
+
+ device_vector<uchar>& tex_img = dscene->tex_byte_image[slot];
+
+ uint8_t options = pack_image_options(type, slot);
+
+ int index = type_index_to_flattened_slot(slot, type) * 2;
+ info[index] = make_uint4(tex_img.data_width, tex_img.data_height, offset, options);
+ info[index+1] = make_uint4(tex_img.data_depth, 0, 0, 0);
+
+ memcpy(pixels_byte+offset, (void*)tex_img.data_pointer, tex_img.memory_size());
+ offset += tex_img.size();
+ }
+
+ /* Float Textures*/
+ type = IMAGE_DATA_TYPE_FLOAT;
+ size = 0, offset = 0;
+
+ for(size_t slot = 0; slot < images[type].size(); slot++) {
+ if(!images[type][slot])
+ continue;
+
+ device_vector<float>& tex_img = dscene->tex_float_image[slot];
+ size += tex_img.size();
+ }
+
+ float *pixels_float = dscene->tex_image_float_packed.resize(size);
+
+ for(size_t slot = 0; slot < images[type].size(); slot++) {
+ if(!images[type][slot])
+ continue;
+
+ device_vector<float>& tex_img = dscene->tex_float_image[slot];
+
+ /* todo: support 3D textures, only CPU for now */
+
+ uint8_t options = pack_image_options(type, slot);
+
+ int index = type_index_to_flattened_slot(slot, type) * 2;
+ info[index] = make_uint4(tex_img.data_width, tex_img.data_height, offset, options);
+ info[index+1] = make_uint4(tex_img.data_depth, 0, 0, 0);
memcpy(pixels_float+offset, (void*)tex_img.data_pointer, tex_img.memory_size());
offset += tex_img.size();
@@ -886,6 +1246,20 @@ void ImageManager::device_pack_images(Device *device,
}
device->tex_alloc("__tex_image_float4_packed", dscene->tex_image_float4_packed);
}
+ if(dscene->tex_image_byte_packed.size()) {
+ if(dscene->tex_image_byte_packed.device_pointer) {
+ thread_scoped_lock device_lock(device_mutex);
+ device->tex_free(dscene->tex_image_byte_packed);
+ }
+ device->tex_alloc("__tex_image_byte_packed", dscene->tex_image_byte_packed);
+ }
+ if(dscene->tex_image_float_packed.size()) {
+ if(dscene->tex_image_float_packed.device_pointer) {
+ thread_scoped_lock device_lock(device_mutex);
+ device->tex_free(dscene->tex_image_float_packed);
+ }
+ device->tex_alloc("__tex_image_float_packed", dscene->tex_image_float_packed);
+ }
if(dscene->tex_image_packed_info.size()) {
if(dscene->tex_image_packed_info.device_pointer) {
thread_scoped_lock device_lock(device_mutex);
@@ -916,10 +1290,14 @@ void ImageManager::device_free(Device *device, DeviceScene *dscene)
device->tex_free(dscene->tex_image_byte4_packed);
device->tex_free(dscene->tex_image_float4_packed);
+ device->tex_free(dscene->tex_image_byte_packed);
+ device->tex_free(dscene->tex_image_float_packed);
device->tex_free(dscene->tex_image_packed_info);
dscene->tex_image_byte4_packed.clear();
dscene->tex_image_float4_packed.clear();
+ dscene->tex_image_byte_packed.clear();
+ dscene->tex_image_float_packed.clear();
dscene->tex_image_packed_info.clear();
}
diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h
index 1bb9987f602..cca71a6bb93 100644
--- a/intern/cycles/render/image.h
+++ b/intern/cycles/render/image.h
@@ -20,6 +20,7 @@
#include "device.h"
#include "device_memory.h"
+#include "util_image.h"
#include "util_string.h"
#include "util_thread.h"
#include "util_vector.h"
@@ -32,12 +33,16 @@ class Progress;
class ImageManager {
public:
- ImageManager(const DeviceInfo& info);
+ explicit ImageManager(const DeviceInfo& info);
~ImageManager();
enum ImageDataType {
IMAGE_DATA_TYPE_FLOAT4 = 0,
IMAGE_DATA_TYPE_BYTE4 = 1,
+ IMAGE_DATA_TYPE_HALF4 = 2,
+ IMAGE_DATA_TYPE_FLOAT = 3,
+ IMAGE_DATA_TYPE_BYTE = 4,
+ IMAGE_DATA_TYPE_HALF = 5,
IMAGE_DATA_NUM_TYPES
};
@@ -60,7 +65,7 @@ public:
void *builtin_data,
InterpolationType interpolation,
ExtensionType extension);
- bool is_float_image(const string& filename, void *builtin_data, bool& is_linear);
+ ImageDataType get_image_metadata(const string& filename, void *builtin_data, bool& is_linear);
void device_update(Device *device, DeviceScene *dscene, Progress& progress);
void device_update_slot(Device *device, DeviceScene *dscene, int flat_slot, Progress *progress);
@@ -93,7 +98,8 @@ public:
private:
int tex_num_images[IMAGE_DATA_NUM_TYPES];
- int tex_image_byte4_start;
+ int tex_start_images[IMAGE_DATA_NUM_TYPES];
+
thread_mutex device_mutex;
int animation_frame;
@@ -101,13 +107,23 @@ private:
void *osl_texture_system;
bool pack_images;
- bool file_load_image(Image *img, device_vector<uchar4>& tex_img);
- bool file_load_float_image(Image *img, device_vector<float4>& tex_img);
+ bool file_load_image_generic(Image *img, ImageInput **in, int &width, int &height, int &depth, int &components);
+
+ template<typename T>
+ bool file_load_byte_image(Image *img, ImageDataType type, device_vector<T>& tex_img);
+
+ template<typename T>
+ bool file_load_float_image(Image *img, ImageDataType type, device_vector<T>& tex_img);
+
+ template<typename T>
+ bool file_load_half_image(Image *img, ImageDataType type, device_vector<T>& tex_img);
int type_index_to_flattened_slot(int slot, ImageDataType type);
int flattened_slot_to_type_index(int flat_slot, ImageDataType *type);
string name_from_type(int type);
+ uint8_t pack_image_options(ImageDataType type, size_t slot);
+
void device_load_image(Device *device, DeviceScene *dscene, ImageDataType type, int slot, Progress *progess);
void device_free_image(Device *device, DeviceScene *dscene, ImageDataType type, int slot);
diff --git a/intern/cycles/render/integrator.cpp b/intern/cycles/render/integrator.cpp
index be8fd552e78..63914e57319 100644
--- a/intern/cycles/render/integrator.cpp
+++ b/intern/cycles/render/integrator.cpp
@@ -27,48 +27,61 @@
CCL_NAMESPACE_BEGIN
-Integrator::Integrator()
+NODE_DEFINE(Integrator)
{
- min_bounce = 2;
- max_bounce = 7;
-
- max_diffuse_bounce = max_bounce;
- max_glossy_bounce = max_bounce;
- max_transmission_bounce = max_bounce;
- max_volume_bounce = max_bounce;
-
- transparent_min_bounce = min_bounce;
- transparent_max_bounce = max_bounce;
- transparent_shadows = false;
-
- volume_max_steps = 1024;
- volume_step_size = 0.1f;
-
- caustics_reflective = true;
- caustics_refractive = true;
- filter_glossy = 0.0f;
- seed = 0;
- layer_flag = ~0;
- sample_clamp_direct = 0.0f;
- sample_clamp_indirect = 0.0f;
- motion_blur = false;
-
- aa_samples = 0;
- diffuse_samples = 1;
- glossy_samples = 1;
- transmission_samples = 1;
- ao_samples = 1;
- mesh_light_samples = 1;
- subsurface_samples = 1;
- volume_samples = 1;
-
- sample_all_lights_direct = true;
- sample_all_lights_indirect = true;
-
- method = PATH;
-
- sampling_pattern = SAMPLING_PATTERN_SOBOL;
+ NodeType *type = NodeType::add("integrator", create);
+
+ SOCKET_INT(min_bounce, "Min Bounce", 2);
+ SOCKET_INT(max_bounce, "Max Bounce", 7);
+
+ SOCKET_INT(max_diffuse_bounce, "Max Diffuse Bounce", 7);
+ SOCKET_INT(max_glossy_bounce, "Max Glossy Bounce", 7);
+ SOCKET_INT(max_transmission_bounce, "Max Transmission Bounce", 7);
+ SOCKET_INT(max_volume_bounce, "Max Volume Bounce", 7);
+
+ SOCKET_INT(transparent_min_bounce, "Transparent Min Bounce", 2);
+ SOCKET_INT(transparent_max_bounce, "Transparent Max Bounce", 7);
+ SOCKET_BOOLEAN(transparent_shadows, "Transparent Shadows", false);
+
+ SOCKET_INT(volume_max_steps, "Volume Max Steps", 1024);
+ SOCKET_FLOAT(volume_step_size, "Volume Step Size", 0.1f);
+
+ SOCKET_BOOLEAN(caustics_reflective, "Reflective Caustics", true);
+ SOCKET_BOOLEAN(caustics_refractive, "Refractive Caustics", true);
+ SOCKET_FLOAT(filter_glossy, "Filter Glossy", 0.0f);
+ SOCKET_INT(seed, "Seed", 0);
+ SOCKET_FLOAT(sample_clamp_direct, "Sample Clamp Direct", 0.0f);
+ SOCKET_FLOAT(sample_clamp_indirect, "Sample Clamp Indirect", 0.0f);
+ SOCKET_BOOLEAN(motion_blur, "Motion Blur", false);
+
+ SOCKET_INT(aa_samples, "AA Samples", 0);
+ SOCKET_INT(diffuse_samples, "Diffuse Samples", 1);
+ SOCKET_INT(glossy_samples, "Glossy Samples", 1);
+ SOCKET_INT(transmission_samples, "Transmission Samples", 1);
+ SOCKET_INT(ao_samples, "AO Samples", 1);
+ SOCKET_INT(mesh_light_samples, "Mesh Light Samples", 1);
+ SOCKET_INT(subsurface_samples, "Subsurface Samples", 1);
+ SOCKET_INT(volume_samples, "Volume Samples", 1);
+
+ SOCKET_BOOLEAN(sample_all_lights_direct, "Sample All Lights Direct", true);
+ SOCKET_BOOLEAN(sample_all_lights_indirect, "Sample All Lights Indirect", true);
+
+ static NodeEnum method_enum;
+ method_enum.insert("path", PATH);
+ method_enum.insert("branched_path", BRANCHED_PATH);
+ SOCKET_ENUM(method, "Method", method_enum, PATH);
+
+ static NodeEnum sampling_pattern_enum;
+ sampling_pattern_enum.insert("sobol", SAMPLING_PATTERN_SOBOL);
+ sampling_pattern_enum.insert("cmj", SAMPLING_PATTERN_CMJ);
+ SOCKET_ENUM(sampling_pattern, "Sampling Pattern", sampling_pattern_enum, SAMPLING_PATTERN_SOBOL);
+
+ return type;
+}
+Integrator::Integrator()
+: Node(node_type)
+{
need_update = true;
}
@@ -123,10 +136,9 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
kintegrator->filter_glossy = (filter_glossy == 0.0f)? FLT_MAX: 1.0f/filter_glossy;
kintegrator->seed = hash_int(seed);
- kintegrator->layer_flag = layer_flag << PATH_RAY_LAYER_SHIFT;
kintegrator->use_ambient_occlusion =
- ((dscene->data.film.pass_flag & PASS_AO) || dscene->data.background.ao_factor != 0.0f);
+ ((Pass::contains(scene->film->passes, PASS_AO)) || dscene->data.background.ao_factor != 0.0f);
kintegrator->sample_clamp_direct = (sample_clamp_direct == 0.0f)? FLT_MAX: sample_clamp_direct*3.0f;
kintegrator->sample_clamp_indirect = (sample_clamp_indirect == 0.0f)? FLT_MAX: sample_clamp_indirect*3.0f;
@@ -164,7 +176,7 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
max_samples = max(max_samples, volume_samples);
}
- max_samples *= (max_bounce + transparent_max_bounce + 3);
+ max_samples *= (max_bounce + transparent_max_bounce + 3 + BSSRDF_MAX_HITS);
int dimensions = PRNG_BASE_NUM + max_samples*PRNG_BOUNCE_NUM;
dimensions = min(dimensions, SOBOL_MAX_DIMENSIONS);
@@ -194,37 +206,7 @@ void Integrator::device_free(Device *device, DeviceScene *dscene)
bool Integrator::modified(const Integrator& integrator)
{
- return !(min_bounce == integrator.min_bounce &&
- max_bounce == integrator.max_bounce &&
- max_diffuse_bounce == integrator.max_diffuse_bounce &&
- max_glossy_bounce == integrator.max_glossy_bounce &&
- max_transmission_bounce == integrator.max_transmission_bounce &&
- max_volume_bounce == integrator.max_volume_bounce &&
- transparent_min_bounce == integrator.transparent_min_bounce &&
- transparent_max_bounce == integrator.transparent_max_bounce &&
- transparent_shadows == integrator.transparent_shadows &&
- volume_max_steps == integrator.volume_max_steps &&
- volume_step_size == integrator.volume_step_size &&
- caustics_reflective == integrator.caustics_reflective &&
- caustics_refractive == integrator.caustics_refractive &&
- filter_glossy == integrator.filter_glossy &&
- layer_flag == integrator.layer_flag &&
- seed == integrator.seed &&
- sample_clamp_direct == integrator.sample_clamp_direct &&
- sample_clamp_indirect == integrator.sample_clamp_indirect &&
- method == integrator.method &&
- aa_samples == integrator.aa_samples &&
- diffuse_samples == integrator.diffuse_samples &&
- glossy_samples == integrator.glossy_samples &&
- transmission_samples == integrator.transmission_samples &&
- ao_samples == integrator.ao_samples &&
- mesh_light_samples == integrator.mesh_light_samples &&
- subsurface_samples == integrator.subsurface_samples &&
- volume_samples == integrator.volume_samples &&
- motion_blur == integrator.motion_blur &&
- sampling_pattern == integrator.sampling_pattern &&
- sample_all_lights_direct == integrator.sample_all_lights_direct &&
- sample_all_lights_indirect == integrator.sample_all_lights_indirect);
+ return !Node::equals(integrator);
}
void Integrator::tag_update(Scene *scene)
diff --git a/intern/cycles/render/integrator.h b/intern/cycles/render/integrator.h
index bb4e9c7056f..39eaaf246d4 100644
--- a/intern/cycles/render/integrator.h
+++ b/intern/cycles/render/integrator.h
@@ -19,14 +19,18 @@
#include "kernel_types.h"
+#include "node.h"
+
CCL_NAMESPACE_BEGIN
class Device;
class DeviceScene;
class Scene;
-class Integrator {
+class Integrator : public Node {
public:
+ NODE_DECLARE;
+
int min_bounce;
int max_bounce;
@@ -47,7 +51,6 @@ public:
float filter_glossy;
int seed;
- int layer_flag;
float sample_clamp_direct;
float sample_clamp_indirect;
diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp
index fef28b25f3e..777f3229ce6 100644
--- a/intern/cycles/render/light.cpp
+++ b/intern/cycles/render/light.cpp
@@ -100,38 +100,55 @@ static void shade_background_pixels(Device *device, DeviceScene *dscene, int res
/* Light */
-Light::Light()
+NODE_DEFINE(Light)
{
- type = LIGHT_POINT;
+ NodeType* type = NodeType::add("light", create);
+
+ static NodeEnum type_enum;
+ type_enum.insert("point", LIGHT_POINT);
+ type_enum.insert("background", LIGHT_BACKGROUND);
+ type_enum.insert("area", LIGHT_AREA);
+ type_enum.insert("spot", LIGHT_SPOT);
+ SOCKET_ENUM(type, "Type", type_enum, LIGHT_POINT);
+
+ SOCKET_POINT(co, "Co", make_float3(0.0f, 0.0f, 0.0f));
- co = make_float3(0.0f, 0.0f, 0.0f);
+ SOCKET_VECTOR(dir, "Dir", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_FLOAT(size, "Size", 0.0f);
- dir = make_float3(0.0f, 0.0f, 0.0f);
- size = 0.0f;
+ SOCKET_VECTOR(axisu, "Axis U", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_FLOAT(sizeu, "Size U", 1.0f);
+ SOCKET_VECTOR(axisv, "Axis V", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_FLOAT(sizev, "Size V", 1.0f);
- axisu = make_float3(0.0f, 0.0f, 0.0f);
- sizeu = 1.0f;
- axisv = make_float3(0.0f, 0.0f, 0.0f);
- sizev = 1.0f;
+ SOCKET_INT(map_resolution, "Map Resolution", 512);
- map_resolution = 512;
+ SOCKET_FLOAT(spot_angle, "Spot Angle", M_PI_4_F);
+ SOCKET_FLOAT(spot_smooth, "Spot Smooth", 0.0f);
- spot_angle = M_PI_4_F;
- spot_smooth = 0.0f;
+ SOCKET_TRANSFORM(tfm, "Transform", transform_identity());
- cast_shadow = true;
- use_mis = false;
- use_diffuse = true;
- use_glossy = true;
- use_transmission = true;
- use_scatter = true;
+ SOCKET_BOOLEAN(cast_shadow, "Cast Shadow", true);
+ SOCKET_BOOLEAN(use_mis, "Use Mis", false);
+ SOCKET_BOOLEAN(use_diffuse, "Use Diffuse", true);
+ SOCKET_BOOLEAN(use_glossy, "Use Glossy", true);
+ SOCKET_BOOLEAN(use_transmission, "Use Transmission", true);
+ SOCKET_BOOLEAN(use_scatter, "Use Scatter", true);
- shader = 0;
- samples = 1;
- max_bounces = 1024;
+ SOCKET_INT(samples, "Samples", 1);
+ SOCKET_INT(max_bounces, "Max Bounces", 1024);
- is_portal = false;
- is_enabled = true;
+ SOCKET_BOOLEAN(is_portal, "Is Portal", false);
+ SOCKET_BOOLEAN(is_enabled, "Is Enabled", true);
+
+ SOCKET_NODE(shader, "Shader", &Shader::node_type);
+
+ return type;
+}
+
+Light::Light()
+: Node(node_type)
+{
}
void Light::tag_update(Scene *scene)
@@ -147,7 +164,7 @@ bool Light::has_contribution(Scene *scene)
if(type == LIGHT_BACKGROUND) {
return true;
}
- return scene->shaders[shader]->has_surface_emission;
+ return (shader) ? shader->has_surface_emission : scene->default_light->has_surface_emission;
}
/* Light Manager */
@@ -162,6 +179,16 @@ LightManager::~LightManager()
{
}
+bool LightManager::has_background_light(Scene *scene)
+{
+ foreach(Light *light, scene->lights) {
+ if(light->type == LIGHT_BACKGROUND) {
+ return true;
+ }
+ }
+ return false;
+}
+
void LightManager::disable_ineffective_light(Device *device, Scene *scene)
{
/* Make all lights enabled by default, and perform some preliminary checks
@@ -180,7 +207,7 @@ void LightManager::disable_ineffective_light(Device *device, Scene *scene)
* - If unsupported on a device
* - If we don't need it (no HDRs etc.)
*/
- Shader *shader = scene->shaders[scene->background->shader];
+ Shader *shader = (scene->background->shader) ? scene->background->shader : scene->default_background;
bool disable_mis = !(has_portal || shader->has_surface_spatial_varying) ||
!(device->info.advanced_shading);
if(disable_mis) {
@@ -194,56 +221,73 @@ void LightManager::disable_ineffective_light(Device *device, Scene *scene)
}
}
+bool LightManager::object_usable_as_light(Object *object) {
+ Mesh *mesh = object->mesh;
+ /* Skip if we are not visible for BSDFs. */
+ if(!(object->visibility & (PATH_RAY_DIFFUSE|PATH_RAY_GLOSSY|PATH_RAY_TRANSMIT))) {
+ return false;
+ }
+ /* Skip motion blurred deforming meshes, not supported yet. */
+ if(mesh->has_motion_blur()) {
+ return false;
+ }
+ /* Skip if we have no emission shaders. */
+ /* TODO(sergey): Ideally we want to avoid such duplicated loop, since it'll
+ * iterate all mesh shaders twice (when counting and when calculating
+ * triangle area.
+ */
+ foreach(const Shader *shader, mesh->used_shaders) {
+ if(shader->use_mis && shader->has_surface_emission) {
+ return true;
+ }
+ }
+ return false;
+}
+
void LightManager::device_update_distribution(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
{
progress.set_status("Updating Lights", "Computing distribution");
/* count */
size_t num_lights = 0;
+ size_t num_portals = 0;
size_t num_background_lights = 0;
size_t num_triangles = 0;
bool background_mis = false;
foreach(Light *light, scene->lights) {
- if(light->is_enabled)
+ if(light->is_enabled) {
num_lights++;
+ }
+ if(light->is_portal) {
+ num_portals++;
+ }
}
foreach(Object *object, scene->objects) {
- Mesh *mesh = object->mesh;
- bool have_emission = false;
-
- /* skip if we are not visible for BSDFs */
- if(!(object->visibility & (PATH_RAY_DIFFUSE|PATH_RAY_GLOSSY|PATH_RAY_TRANSMIT)))
- continue;
+ if(progress.get_cancel()) return;
- /* skip motion blurred deforming meshes, not supported yet */
- if(mesh->has_motion_blur())
+ if(!object_usable_as_light(object)) {
continue;
-
- /* skip if we have no emission shaders */
- foreach(uint sindex, mesh->used_shaders) {
- Shader *shader = scene->shaders[sindex];
-
- if(shader->use_mis && shader->has_surface_emission) {
- have_emission = true;
- break;
- }
}
+ /* Count triangles. */
+ Mesh *mesh = object->mesh;
+ size_t mesh_num_triangles = mesh->num_triangles();
+ for(size_t i = 0; i < mesh_num_triangles; i++) {
+ int shader_index = mesh->shader[i];
+ Shader *shader = (shader_index < mesh->used_shaders.size())
+ ? mesh->used_shaders[shader_index]
+ : scene->default_surface;
- /* count triangles */
- if(have_emission) {
- for(size_t i = 0; i < mesh->triangles.size(); i++) {
- Shader *shader = scene->shaders[mesh->shader[i]];
-
- if(shader->use_mis && shader->has_surface_emission)
- num_triangles++;
+ if(shader->use_mis && shader->has_surface_emission) {
+ num_triangles++;
}
}
}
size_t num_distribution = num_triangles + num_lights;
+ VLOG(1) << "Total " << num_distribution << " of light distribution primitives.";
/* emission area */
float4 *distribution = dscene->light_distribution.resize(num_distribution + 1);
@@ -254,86 +298,65 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
int j = 0;
foreach(Object *object, scene->objects) {
- Mesh *mesh = object->mesh;
- bool have_emission = false;
+ if(progress.get_cancel()) return;
- /* skip if we are not visible for BSDFs */
- if(!(object->visibility & (PATH_RAY_DIFFUSE|PATH_RAY_GLOSSY|PATH_RAY_TRANSMIT))) {
+ if(!object_usable_as_light(object)) {
j++;
continue;
}
+ /* Sum area. */
+ Mesh *mesh = object->mesh;
+ bool transform_applied = mesh->transform_applied;
+ Transform tfm = object->tfm;
+ int object_id = j;
+ int shader_flag = 0;
- /* skip motion blurred deforming meshes, not supported yet */
- if(mesh->has_motion_blur()) {
- j++;
- continue;
+ if(!(object->visibility & PATH_RAY_DIFFUSE)) {
+ shader_flag |= SHADER_EXCLUDE_DIFFUSE;
+ use_light_visibility = true;
}
-
- /* skip if we have no emission shaders */
- foreach(uint sindex, mesh->used_shaders) {
- Shader *shader = scene->shaders[sindex];
-
- if(shader->use_mis && shader->has_surface_emission) {
- have_emission = true;
- break;
- }
+ if(!(object->visibility & PATH_RAY_GLOSSY)) {
+ shader_flag |= SHADER_EXCLUDE_GLOSSY;
+ use_light_visibility = true;
+ }
+ if(!(object->visibility & PATH_RAY_TRANSMIT)) {
+ shader_flag |= SHADER_EXCLUDE_TRANSMIT;
+ use_light_visibility = true;
+ }
+ if(!(object->visibility & PATH_RAY_VOLUME_SCATTER)) {
+ shader_flag |= SHADER_EXCLUDE_SCATTER;
+ use_light_visibility = true;
}
- /* sum area */
- if(have_emission) {
- bool transform_applied = mesh->transform_applied;
- Transform tfm = object->tfm;
- int object_id = j;
- int shader_flag = 0;
-
- if(transform_applied)
- object_id = ~object_id;
-
- if(!(object->visibility & PATH_RAY_DIFFUSE)) {
- shader_flag |= SHADER_EXCLUDE_DIFFUSE;
- use_light_visibility = true;
- }
- if(!(object->visibility & PATH_RAY_GLOSSY)) {
- shader_flag |= SHADER_EXCLUDE_GLOSSY;
- use_light_visibility = true;
- }
- if(!(object->visibility & PATH_RAY_TRANSMIT)) {
- shader_flag |= SHADER_EXCLUDE_TRANSMIT;
- use_light_visibility = true;
- }
- if(!(object->visibility & PATH_RAY_VOLUME_SCATTER)) {
- shader_flag |= SHADER_EXCLUDE_SCATTER;
- use_light_visibility = true;
- }
-
- for(size_t i = 0; i < mesh->triangles.size(); i++) {
- Shader *shader = scene->shaders[mesh->shader[i]];
-
- if(shader->use_mis && shader->has_surface_emission) {
- distribution[offset].x = totarea;
- distribution[offset].y = __int_as_float(i + mesh->tri_offset);
- distribution[offset].z = __int_as_float(shader_flag);
- distribution[offset].w = __int_as_float(object_id);
- offset++;
-
- Mesh::Triangle t = mesh->triangles[i];
- float3 p1 = mesh->verts[t.v[0]];
- float3 p2 = mesh->verts[t.v[1]];
- float3 p3 = mesh->verts[t.v[2]];
-
- if(!transform_applied) {
- p1 = transform_point(&tfm, p1);
- p2 = transform_point(&tfm, p2);
- p3 = transform_point(&tfm, p3);
- }
+ size_t mesh_num_triangles = mesh->num_triangles();
+ for(size_t i = 0; i < mesh_num_triangles; i++) {
+ int shader_index = mesh->shader[i];
+ Shader *shader = (shader_index < mesh->used_shaders.size())
+ ? mesh->used_shaders[shader_index]
+ : scene->default_surface;
- totarea += triangle_area(p1, p2, p3);
+ if(shader->use_mis && shader->has_surface_emission) {
+ distribution[offset].x = totarea;
+ distribution[offset].y = __int_as_float(i + mesh->tri_offset);
+ distribution[offset].z = __int_as_float(shader_flag);
+ distribution[offset].w = __int_as_float(object_id);
+ offset++;
+
+ Mesh::Triangle t = mesh->get_triangle(i);
+ float3 p1 = mesh->verts[t.v[0]];
+ float3 p2 = mesh->verts[t.v[1]];
+ float3 p3 = mesh->verts[t.v[2]];
+
+ if(!transform_applied) {
+ p1 = transform_point(&tfm, p1);
+ p2 = transform_point(&tfm, p2);
+ p3 = transform_point(&tfm, p3);
}
+
+ totarea += triangle_area(p1, p2, p3);
}
}
- if(progress.get_cancel()) return;
-
j++;
}
@@ -426,9 +449,9 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
device->tex_alloc("__light_distribution", dscene->light_distribution);
/* Portals */
- if(num_background_lights > 0 && light_index != scene->lights.size()) {
+ if(num_portals > 0) {
kintegrator->portal_offset = light_index;
- kintegrator->num_portals = scene->lights.size() - light_index;
+ kintegrator->num_portals = num_portals;
kintegrator->portal_pdf = background_mis? 0.5f: 1.0f;
}
else {
@@ -592,10 +615,21 @@ void LightManager::device_update_points(Device *device,
Scene *scene)
{
int num_scene_lights = scene->lights.size();
- if(num_scene_lights == 0)
+
+ int num_lights = 0;
+ foreach(Light *light, scene->lights) {
+ if(light->is_enabled || light->is_portal) {
+ num_lights++;
+ }
+ }
+
+ float4 *light_data = dscene->light_data.resize(num_lights*LIGHT_SIZE);
+
+ if(num_lights == 0) {
+ VLOG(1) << "No effective light, ignoring points update.";
return;
+ }
- float4 *light_data = dscene->light_data.resize(num_scene_lights*LIGHT_SIZE);
int light_index = 0;
foreach(Light *light, scene->lights) {
@@ -604,7 +638,8 @@ void LightManager::device_update_points(Device *device,
}
float3 co = light->co;
- int shader_id = scene->shader_manager->get_shader_id(light->shader);
+ Shader *shader = (light->shader) ? light->shader : scene->default_light;
+ int shader_id = scene->shader_manager->get_shader_id(shader);
float samples = __int_as_float(light->samples);
float max_bounces = __int_as_float(light->max_bounces);
@@ -641,7 +676,6 @@ void LightManager::device_update_points(Device *device,
light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, invarea, 0.0f);
light_data[light_index*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
- light_data[light_index*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
}
else if(light->type == LIGHT_DISTANT) {
shader_id &= ~SHADER_AREA_LIGHT;
@@ -662,7 +696,6 @@ void LightManager::device_update_points(Device *device,
light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, cosangle, invarea);
light_data[light_index*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
- light_data[light_index*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
}
else if(light->type == LIGHT_BACKGROUND) {
uint visibility = scene->background->visibility;
@@ -691,7 +724,6 @@ void LightManager::device_update_points(Device *device,
light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), 0.0f, 0.0f, 0.0f);
light_data[light_index*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
- light_data[light_index*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
}
else if(light->type == LIGHT_AREA) {
float3 axisu = light->axisu*(light->sizeu*light->size);
@@ -709,7 +741,6 @@ void LightManager::device_update_points(Device *device,
light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), axisu.x, axisu.y, axisu.z);
light_data[light_index*LIGHT_SIZE + 2] = make_float4(invarea, axisv.x, axisv.y, axisv.z);
light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, dir.x, dir.y, dir.z);
- light_data[light_index*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
}
else if(light->type == LIGHT_SPOT) {
shader_id &= ~SHADER_AREA_LIGHT;
@@ -729,9 +760,15 @@ void LightManager::device_update_points(Device *device,
light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, invarea, spot_angle);
light_data[light_index*LIGHT_SIZE + 2] = make_float4(spot_smooth, dir.x, dir.y, dir.z);
light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
- light_data[light_index*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
}
+ light_data[light_index*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
+
+ Transform tfm = light->tfm;
+ Transform itfm = transform_inverse(tfm);
+ memcpy(&light_data[light_index*LIGHT_SIZE + 5], &tfm, sizeof(float4)*3);
+ memcpy(&light_data[light_index*LIGHT_SIZE + 8], &itfm, sizeof(float4)*3);
+
light_index++;
}
@@ -758,6 +795,11 @@ void LightManager::device_update_points(Device *device,
light_data[light_index*LIGHT_SIZE + 3] = make_float4(-1, dir.x, dir.y, dir.z);
light_data[light_index*LIGHT_SIZE + 4] = make_float4(-1, 0.0f, 0.0f, 0.0f);
+ Transform tfm = light->tfm;
+ Transform itfm = transform_inverse(tfm);
+ memcpy(&light_data[light_index*LIGHT_SIZE + 5], &tfm, sizeof(float4)*3);
+ memcpy(&light_data[light_index*LIGHT_SIZE + 8], &itfm, sizeof(float4)*3);
+
light_index++;
}
diff --git a/intern/cycles/render/light.h b/intern/cycles/render/light.h
index 15038d0a920..f56530b6490 100644
--- a/intern/cycles/render/light.h
+++ b/intern/cycles/render/light.h
@@ -19,6 +19,8 @@
#include "kernel_types.h"
+#include "node.h"
+
#include "util_types.h"
#include "util_vector.h"
@@ -26,11 +28,15 @@ CCL_NAMESPACE_BEGIN
class Device;
class DeviceScene;
+class Object;
class Progress;
class Scene;
+class Shader;
-class Light {
+class Light : public Node {
public:
+ NODE_DECLARE;
+
Light();
LightType type;
@@ -44,6 +50,8 @@ public:
float3 axisv;
float sizev;
+ Transform tfm;
+
int map_resolution;
float spot_angle;
@@ -59,7 +67,7 @@ public:
bool is_portal;
bool is_enabled;
- int shader;
+ Shader *shader;
int samples;
int max_bounces;
@@ -85,6 +93,9 @@ public:
void tag_update(Scene *scene);
+ /* Check whether there is a background light. */
+ bool has_background_light(Scene *scene);
+
protected:
/* Optimization: disable light which is either unsupported or
* which doesn't contribute to the scene or which is only used for MIS
@@ -103,6 +114,9 @@ protected:
DeviceScene *dscene,
Scene *scene,
Progress& progress);
+
+ /* Check whether light manager can use the object as a light-emissive. */
+ bool object_usable_as_light(Object *object);
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp
index f8273107e1b..ac369a0d5f8 100644
--- a/intern/cycles/render/mesh.cpp
+++ b/intern/cycles/render/mesh.cpp
@@ -30,14 +30,14 @@
#include "osl_globals.h"
+#include "subd_split.h"
+#include "subd_patch_table.h"
+
#include "util_foreach.h"
#include "util_logging.h"
#include "util_progress.h"
#include "util_set.h"
-#include "subd_split.h"
-#include "subd_patch.h"
-
CCL_NAMESPACE_BEGIN
/* Triangle */
@@ -51,14 +51,45 @@ void Mesh::Triangle::bounds_grow(const float3 *verts, BoundBox& bounds) const
/* Curve */
-void Mesh::Curve::bounds_grow(const int k, const float4 *curve_keys, BoundBox& bounds) const
+void Mesh::Curve::bounds_grow(const int k, const float3 *curve_keys, const float *curve_radius, BoundBox& bounds) const
{
float3 P[4];
- P[0] = float4_to_float3(curve_keys[max(first_key + k - 1,first_key)]);
- P[1] = float4_to_float3(curve_keys[first_key + k]);
- P[2] = float4_to_float3(curve_keys[first_key + k + 1]);
- P[3] = float4_to_float3(curve_keys[min(first_key + k + 2, first_key + num_keys - 1)]);
+ P[0] = curve_keys[max(first_key + k - 1,first_key)];
+ P[1] = curve_keys[first_key + k];
+ P[2] = curve_keys[first_key + k + 1];
+ P[3] = curve_keys[min(first_key + k + 2, first_key + num_keys - 1)];
+
+ float3 lower;
+ float3 upper;
+
+ curvebounds(&lower.x, &upper.x, P, 0);
+ curvebounds(&lower.y, &upper.y, P, 1);
+ curvebounds(&lower.z, &upper.z, P, 2);
+
+ float mr = max(curve_radius[first_key + k], curve_radius[first_key + k + 1]);
+
+ bounds.grow(lower, mr);
+ bounds.grow(upper, mr);
+}
+
+void Mesh::Curve::bounds_grow(const int k,
+ const float3 *curve_keys,
+ const float *curve_radius,
+ const Transform& aligned_space,
+ BoundBox& bounds) const
+{
+ float3 P[4];
+
+ P[0] = curve_keys[max(first_key + k - 1,first_key)];
+ P[1] = curve_keys[first_key + k];
+ P[2] = curve_keys[first_key + k + 1];
+ P[3] = curve_keys[min(first_key + k + 2, first_key + num_keys - 1)];
+
+ P[0] = transform_point(&aligned_space, P[0]);
+ P[1] = transform_point(&aligned_space, P[1]);
+ P[2] = transform_point(&aligned_space, P[2]);
+ P[3] = transform_point(&aligned_space, P[3]);
float3 lower;
float3 upper;
@@ -67,27 +98,55 @@ void Mesh::Curve::bounds_grow(const int k, const float4 *curve_keys, BoundBox& b
curvebounds(&lower.y, &upper.y, P, 1);
curvebounds(&lower.z, &upper.z, P, 2);
- float mr = max(curve_keys[first_key + k].w, curve_keys[first_key + k + 1].w);
+ float mr = max(curve_radius[first_key + k], curve_radius[first_key + k + 1]);
bounds.grow(lower, mr);
bounds.grow(upper, mr);
}
+/* SubdFace */
+
+float3 Mesh::SubdFace::normal(const Mesh *mesh) const
+{
+ float3 v0 = mesh->verts[mesh->subd_face_corners[start_corner+0]];
+ float3 v1 = mesh->verts[mesh->subd_face_corners[start_corner+1]];
+ float3 v2 = mesh->verts[mesh->subd_face_corners[start_corner+2]];
+
+ return safe_normalize(cross(v1 - v0, v2 - v0));
+}
+
/* Mesh */
+NODE_DEFINE(Mesh)
+{
+ NodeType* type = NodeType::add("mesh", create);
+
+ SOCKET_UINT(motion_steps, "Motion Steps", 3);
+ SOCKET_BOOLEAN(use_motion_blur, "Use Motion Blur", false);
+
+ SOCKET_INT_ARRAY(triangles, "Triangles", array<int>());
+ SOCKET_POINT_ARRAY(verts, "Vertices", array<float3>());
+ SOCKET_INT_ARRAY(shader, "Shader", array<int>());
+ SOCKET_BOOLEAN_ARRAY(smooth, "Smooth", array<bool>());
+
+ SOCKET_POINT_ARRAY(curve_keys, "Curve Keys", array<float3>());
+ SOCKET_FLOAT_ARRAY(curve_radius, "Curve Radius", array<float>());
+ SOCKET_INT_ARRAY(curve_first_key, "Curve First Key", array<int>());
+ SOCKET_INT_ARRAY(curve_shader, "Curve Shader", array<int>());
+
+ return type;
+}
+
Mesh::Mesh()
+: Node(node_type)
{
need_update = true;
need_update_rebuild = false;
transform_applied = false;
transform_negative_scaled = false;
transform_normal = transform_identity();
- displacement_method = DISPLACE_BUMP;
bounds = BoundBox::empty;
- motion_steps = 3;
- use_motion_blur = false;
-
bvh = NULL;
tri_offset = 0;
@@ -96,33 +155,103 @@ Mesh::Mesh()
curve_offset = 0;
curvekey_offset = 0;
+ patch_offset = 0;
+ face_offset = 0;
+ corner_offset = 0;
+
+ num_subd_verts = 0;
+
attributes.triangle_mesh = this;
curve_attributes.curve_mesh = this;
+ subd_attributes.subd_mesh = this;
+
+ geometry_flags = GEOMETRY_NONE;
has_volume = false;
has_surface_bssrdf = false;
+
+ num_ngons = 0;
+
+ subdivision_type = SUBDIVISION_NONE;
+ subd_params = NULL;
+
+ patch_table = NULL;
}
Mesh::~Mesh()
{
delete bvh;
+ delete patch_table;
+ delete subd_params;
}
-void Mesh::reserve(int numverts, int numtris, int numcurves, int numcurvekeys)
+void Mesh::resize_mesh(int numverts, int numtris)
{
- /* reserve space to add verts and triangles later */
verts.resize(numverts);
- triangles.resize(numtris);
+ triangles.resize(numtris * 3);
shader.resize(numtris);
smooth.resize(numtris);
- forms_quad.resize(numtris);
+ if(subd_faces.size()) {
+ triangle_patch.resize(numtris);
+ vert_patch_uv.resize(numverts);
+ }
+
+ attributes.resize();
+}
+
+void Mesh::reserve_mesh(int numverts, int numtris)
+{
+ /* reserve space to add verts and triangles later */
+ verts.reserve(numverts);
+ triangles.reserve(numtris * 3);
+ shader.reserve(numtris);
+ smooth.reserve(numtris);
+
+ if(subd_faces.size()) {
+ triangle_patch.reserve(numtris);
+ vert_patch_uv.reserve(numverts);
+ }
+
+ attributes.resize(true);
+}
+
+void Mesh::resize_curves(int numcurves, int numkeys)
+{
+ curve_keys.resize(numkeys);
+ curve_radius.resize(numkeys);
+ curve_first_key.resize(numcurves);
+ curve_shader.resize(numcurves);
+
+ curve_attributes.resize();
+}
+
+void Mesh::reserve_curves(int numcurves, int numkeys)
+{
+ curve_keys.reserve(numkeys);
+ curve_radius.reserve(numkeys);
+ curve_first_key.reserve(numcurves);
+ curve_shader.reserve(numcurves);
+
+ curve_attributes.resize(true);
+}
+
+void Mesh::resize_subd_faces(int numfaces, int num_ngons_, int numcorners)
+{
+ subd_faces.resize(numfaces);
+ subd_face_corners.resize(numcorners);
+ num_ngons = num_ngons_;
+
+ subd_attributes.resize();
+}
- curve_keys.resize(numcurvekeys);
- curves.resize(numcurves);
+void Mesh::reserve_subd_faces(int numfaces, int num_ngons_, int numcorners)
+{
+ subd_faces.reserve(numfaces);
+ subd_face_corners.reserve(numcorners);
+ num_ngons = num_ngons_;
- attributes.reserve();
- curve_attributes.reserve();
+ subd_attributes.resize(true);
}
void Mesh::clear()
@@ -133,79 +262,119 @@ void Mesh::clear()
shader.clear();
smooth.clear();
- forms_quad.clear();
+ triangle_patch.clear();
+ vert_patch_uv.clear();
curve_keys.clear();
- curves.clear();
+ curve_radius.clear();
+ curve_first_key.clear();
+ curve_shader.clear();
+
+ subd_faces.clear();
+ subd_face_corners.clear();
+
+ num_subd_verts = 0;
+
+ subd_creases.clear();
attributes.clear();
curve_attributes.clear();
+ subd_attributes.clear();
used_shaders.clear();
transform_applied = false;
transform_negative_scaled = false;
transform_normal = transform_identity();
geometry_flags = GEOMETRY_NONE;
+
+ delete patch_table;
+ patch_table = NULL;
}
int Mesh::split_vertex(int vertex)
{
/* copy vertex location and vertex attributes */
- verts.push_back(verts[vertex]);
+ add_vertex_slow(verts[vertex]);
foreach(Attribute& attr, attributes.attributes) {
if(attr.element == ATTR_ELEMENT_VERTEX) {
- vector<char> tmp(attr.data_sizeof());
- memcpy(&tmp[0], attr.data() + tmp.size()*vertex, tmp.size());
- attr.add(&tmp[0]);
+ array<char> tmp(attr.data_sizeof());
+ memcpy(tmp.data(), attr.data() + tmp.size()*vertex, tmp.size());
+ attr.add(tmp.data());
+ }
+ }
+
+ foreach(Attribute& attr, subd_attributes.attributes) {
+ if(attr.element == ATTR_ELEMENT_VERTEX) {
+ array<char> tmp(attr.data_sizeof());
+ memcpy(tmp.data(), attr.data() + tmp.size()*vertex, tmp.size());
+ attr.add(tmp.data());
}
}
return verts.size() - 1;
}
-void Mesh::set_triangle(int i, int v0, int v1, int v2, int shader_, bool smooth_, bool forms_quad_)
+void Mesh::add_vertex(float3 P)
+{
+ verts.push_back_reserved(P);
+
+ if(subd_faces.size()) {
+ vert_patch_uv.push_back_reserved(make_float2(0.0f, 0.0f));
+ }
+}
+
+void Mesh::add_vertex_slow(float3 P)
{
- Triangle tri;
- tri.v[0] = v0;
- tri.v[1] = v1;
- tri.v[2] = v2;
-
- triangles[i] = tri;
- shader[i] = shader_;
- smooth[i] = smooth_;
- forms_quad[i] = forms_quad_;
+ verts.push_back_slow(P);
+
+ if(subd_faces.size()) {
+ vert_patch_uv.push_back_slow(make_float2(0.0f, 0.0f));
+ }
}
-void Mesh::add_triangle(int v0, int v1, int v2, int shader_, bool smooth_, bool forms_quad_)
+void Mesh::add_triangle(int v0, int v1, int v2, int shader_, bool smooth_)
{
- Triangle tri;
- tri.v[0] = v0;
- tri.v[1] = v1;
- tri.v[2] = v2;
-
- triangles.push_back(tri);
- shader.push_back(shader_);
- smooth.push_back(smooth_);
- forms_quad.push_back(forms_quad_);
+ triangles.push_back_reserved(v0);
+ triangles.push_back_reserved(v1);
+ triangles.push_back_reserved(v2);
+ shader.push_back_reserved(shader_);
+ smooth.push_back_reserved(smooth_);
+
+ if(subd_faces.size()) {
+ triangle_patch.push_back_reserved(-1);
+ }
}
void Mesh::add_curve_key(float3 co, float radius)
{
- float4 key = float3_to_float4(co);
- key.w = radius;
+ curve_keys.push_back_reserved(co);
+ curve_radius.push_back_reserved(radius);
+}
- curve_keys.push_back(key);
+void Mesh::add_curve(int first_key, int shader)
+{
+ curve_first_key.push_back_reserved(first_key);
+ curve_shader.push_back_reserved(shader);
}
-void Mesh::add_curve(int first_key, int num_keys, int shader)
+void Mesh::add_subd_face(int* corners, int num_corners, int shader_, bool smooth_)
{
- Curve curve;
- curve.first_key = first_key;
- curve.num_keys = num_keys;
- curve.shader = shader;
+ int start_corner = subd_face_corners.size();
+
+ for(int i = 0; i < num_corners; i++) {
+ subd_face_corners.push_back_reserved(corners[i]);
+ }
+
+ int ptex_offset = 0;
+
+ if(subd_faces.size()) {
+ SubdFace& s = subd_faces[subd_faces.size()-1];
+ ptex_offset = s.ptex_offset + s.num_ptex_faces();
+ }
- curves.push_back(curve);
+ SubdFace face = {start_corner, num_corners, shader_, smooth_, ptex_offset};
+ subd_faces.push_back_reserved(face);
}
void Mesh::compute_bounds()
@@ -219,7 +388,7 @@ void Mesh::compute_bounds()
bnds.grow(verts[i]);
for(size_t i = 0; i < curve_keys_size; i++)
- bnds.grow(float4_to_float3(curve_keys[i]), curve_keys[i].w);
+ bnds.grow(curve_keys[i], curve_radius[i]);
Attribute *attr = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
if(use_motion_blur && attr) {
@@ -247,7 +416,7 @@ void Mesh::compute_bounds()
bnds.grow_safe(verts[i]);
for(size_t i = 0; i < curve_keys_size; i++)
- bnds.grow_safe(float4_to_float3(curve_keys[i]), curve_keys[i].w);
+ bnds.grow_safe(curve_keys[i], curve_radius[i]);
if(use_motion_blur && attr) {
size_t steps_size = verts.size() * (motion_steps - 1);
@@ -285,7 +454,7 @@ static float3 compute_face_normal(const Mesh::Triangle& t, float3 *verts)
float normlen = len(norm);
if(normlen == 0.0f)
- return make_float3(0.0f, 0.0f, 0.0f);
+ return make_float3(1.0f, 0.0f, 0.0f);
return norm / normlen;
}
@@ -301,18 +470,13 @@ void Mesh::add_face_normals()
float3 *fN = attr_fN->data_float3();
/* compute face normals */
- size_t triangles_size = triangles.size();
- bool flip = transform_negative_scaled;
+ size_t triangles_size = num_triangles();
if(triangles_size) {
- float3 *verts_ptr = &verts[0];
- Triangle *triangles_ptr = &triangles[0];
+ float3 *verts_ptr = verts.data();
for(size_t i = 0; i < triangles_size; i++) {
- fN[i] = compute_face_normal(triangles_ptr[i], verts_ptr);
-
- if(flip)
- fN[i] = -fN[i];
+ fN[i] = compute_face_normal(get_triangle(i), verts_ptr);
}
}
@@ -329,10 +493,10 @@ void Mesh::add_vertex_normals()
{
bool flip = transform_negative_scaled;
size_t verts_size = verts.size();
- size_t triangles_size = triangles.size();
+ size_t triangles_size = num_triangles();
/* static vertex normals */
- if(!attributes.find(ATTR_STD_VERTEX_NORMAL)) {
+ if(!attributes.find(ATTR_STD_VERTEX_NORMAL) && triangles_size) {
/* get attributes */
Attribute *attr_fN = attributes.find(ATTR_STD_FACE_NORMAL);
Attribute *attr_vN = attributes.add(ATTR_STD_VERTEX_NORMAL);
@@ -343,18 +507,17 @@ void Mesh::add_vertex_normals()
/* compute vertex normals */
memset(vN, 0, verts.size()*sizeof(float3));
- if(triangles_size) {
- Triangle *triangles_ptr = &triangles[0];
-
- for(size_t i = 0; i < triangles_size; i++)
- for(size_t j = 0; j < 3; j++)
- vN[triangles_ptr[i].v[j]] += fN[i];
+ for(size_t i = 0; i < triangles_size; i++) {
+ for(size_t j = 0; j < 3; j++) {
+ vN[get_triangle(i).v[j]] += fN[i];
+ }
}
for(size_t i = 0; i < verts_size; i++) {
vN[i] = normalize(vN[i]);
- if(flip)
+ if(flip) {
vN[i] = -vN[i];
+ }
}
}
@@ -362,7 +525,7 @@ void Mesh::add_vertex_normals()
Attribute *attr_mP = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
Attribute *attr_mN = attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL);
- if(has_motion_blur() && attr_mP && !attr_mN) {
+ if(has_motion_blur() && attr_mP && !attr_mN && triangles_size) {
/* create attribute */
attr_mN = attributes.add(ATTR_STD_MOTION_VERTEX_NORMAL);
@@ -373,37 +536,93 @@ void Mesh::add_vertex_normals()
/* compute */
memset(mN, 0, verts.size()*sizeof(float3));
- if(triangles_size) {
- Triangle *triangles_ptr = &triangles[0];
-
- for(size_t i = 0; i < triangles_size; i++) {
- for(size_t j = 0; j < 3; j++) {
- float3 fN = compute_face_normal(triangles_ptr[i], mP);
- mN[triangles_ptr[i].v[j]] += fN;
- }
+ for(size_t i = 0; i < triangles_size; i++) {
+ for(size_t j = 0; j < 3; j++) {
+ float3 fN = compute_face_normal(get_triangle(i), mP);
+ mN[get_triangle(i).v[j]] += fN;
}
}
for(size_t i = 0; i < verts_size; i++) {
mN[i] = normalize(mN[i]);
- if(flip)
+ if(flip) {
mN[i] = -mN[i];
+ }
+ }
+ }
+ }
+
+ /* subd vertex normals */
+ if(!subd_attributes.find(ATTR_STD_VERTEX_NORMAL) && subd_faces.size()) {
+ /* get attributes */
+ Attribute *attr_vN = subd_attributes.add(ATTR_STD_VERTEX_NORMAL);
+ float3 *vN = attr_vN->data_float3();
+
+ /* compute vertex normals */
+ memset(vN, 0, verts.size()*sizeof(float3));
+
+ for(size_t i = 0; i < subd_faces.size(); i++) {
+ SubdFace& face = subd_faces[i];
+ float3 fN = face.normal(this);
+
+ for(size_t j = 0; j < face.num_corners; j++) {
+ size_t corner = subd_face_corners[face.start_corner+j];
+ vN[corner] += fN;
+ }
+ }
+
+ for(size_t i = 0; i < verts_size; i++) {
+ vN[i] = normalize(vN[i]);
+ if(flip) {
+ vN[i] = -vN[i];
}
}
}
}
+void Mesh::add_undisplaced()
+{
+ AttributeSet& attrs = (subdivision_type == SUBDIVISION_NONE) ? attributes : subd_attributes;
+
+ /* don't compute if already there */
+ if(attrs.find(ATTR_STD_POSITION_UNDISPLACED)) {
+ return;
+ }
+
+ /* get attribute */
+ Attribute *attr = attrs.add(ATTR_STD_POSITION_UNDISPLACED);
+ attr->flags |= ATTR_SUBDIVIDED;
+
+ float3 *data = attr->data_float3();
+
+ /* copy verts */
+ size_t size = attr->buffer_size(this, (subdivision_type == SUBDIVISION_NONE) ? ATTR_PRIM_TRIANGLE : ATTR_PRIM_SUBD);
+
+ /* Center points for ngons aren't stored in Mesh::verts but are included in size since they will be
+ * calculated later, we subtract them from size here so we don't have an overflow while copying.
+ */
+ size -= num_ngons * attr->data_sizeof();
+
+ if(size) {
+ memcpy(data, verts.data(), size);
+ }
+}
+
void Mesh::pack_normals(Scene *scene, uint *tri_shader, float4 *vnormal)
{
Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL);
+ if(attr_vN == NULL) {
+ /* Happens on objects with just hair. */
+ return;
+ }
float3 *vN = attr_vN->data_float3();
uint shader_id = 0;
uint last_shader = -1;
bool last_smooth = false;
- size_t triangles_size = triangles.size();
- uint *shader_ptr = (shader.size())? &shader[0]: NULL;
+ size_t triangles_size = num_triangles();
+ int *shader_ptr = shader.data();
bool do_transform = transform_applied;
Transform ntfm = transform_normal;
@@ -413,7 +632,9 @@ void Mesh::pack_normals(Scene *scene, uint *tri_shader, float4 *vnormal)
if(shader_ptr[i] != last_shader || last_smooth != smooth[i]) {
last_shader = shader_ptr[i];
last_smooth = smooth[i];
- shader_id = scene->shader_manager->get_shader_id(last_shader, this, last_smooth);
+ Shader *shader = (last_shader < used_shaders.size()) ?
+ used_shaders[last_shader] : scene->default_surface;
+ shader_id = scene->shader_manager->get_shader_id(shader, last_smooth);
}
tri_shader[i] = shader_id;
@@ -431,70 +652,118 @@ void Mesh::pack_normals(Scene *scene, uint *tri_shader, float4 *vnormal)
}
}
-void Mesh::pack_verts(float4 *tri_verts, float4 *tri_vindex, size_t vert_offset)
+void Mesh::pack_verts(const vector<uint>& tri_prim_index,
+ uint4 *tri_vindex,
+ uint *tri_patch,
+ float2 *tri_patch_uv,
+ size_t vert_offset,
+ size_t tri_offset)
{
size_t verts_size = verts.size();
- if(verts_size) {
- float3 *verts_ptr = &verts[0];
+ if(verts_size && subd_faces.size()) {
+ float2 *vert_patch_uv_ptr = vert_patch_uv.data();
for(size_t i = 0; i < verts_size; i++) {
- float3 p = verts_ptr[i];
- tri_verts[i] = make_float4(p.x, p.y, p.z, 0.0f);
+ tri_patch_uv[i] = vert_patch_uv_ptr[i];
}
}
- size_t triangles_size = triangles.size();
+ size_t triangles_size = num_triangles();
- if(triangles_size) {
- Triangle *triangles_ptr = &triangles[0];
-
- for(size_t i = 0; i < triangles_size; i++) {
- Triangle t = triangles_ptr[i];
+ for(size_t i = 0; i < triangles_size; i++) {
+ Triangle t = get_triangle(i);
+ tri_vindex[i] = make_uint4(t.v[0] + vert_offset,
+ t.v[1] + vert_offset,
+ t.v[2] + vert_offset,
+ tri_prim_index[i + tri_offset]);
- tri_vindex[i] = make_float4(
- __int_as_float(t.v[0] + vert_offset),
- __int_as_float(t.v[1] + vert_offset),
- __int_as_float(t.v[2] + vert_offset),
- 0);
- }
+ tri_patch[i] = (!subd_faces.size()) ? -1 : (triangle_patch[i]*8 + patch_offset);
}
}
void Mesh::pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, size_t curvekey_offset)
{
size_t curve_keys_size = curve_keys.size();
- float4 *keys_ptr = NULL;
/* pack curve keys */
if(curve_keys_size) {
- keys_ptr = &curve_keys[0];
+ float3 *keys_ptr = curve_keys.data();
+ float *radius_ptr = curve_radius.data();
for(size_t i = 0; i < curve_keys_size; i++)
- curve_key_co[i] = keys_ptr[i];
+ curve_key_co[i] = make_float4(keys_ptr[i].x, keys_ptr[i].y, keys_ptr[i].z, radius_ptr[i]);
}
/* pack curve segments */
- size_t curve_num = curves.size();
+ size_t curve_num = num_curves();
+
+ for(size_t i = 0; i < curve_num; i++) {
+ Curve curve = get_curve(i);
+ int shader_id = curve_shader[i];
+ Shader *shader = (shader_id < used_shaders.size()) ?
+ used_shaders[shader_id] : scene->default_surface;
+ shader_id = scene->shader_manager->get_shader_id(shader, false);
+
+ curve_data[i] = make_float4(
+ __int_as_float(curve.first_key + curvekey_offset),
+ __int_as_float(curve.num_keys),
+ __int_as_float(shader_id),
+ 0.0f);
+ }
+}
- if(curve_num) {
- Curve *curve_ptr = &curves[0];
- int shader_id = 0;
-
- for(size_t i = 0; i < curve_num; i++) {
- Curve curve = curve_ptr[i];
- shader_id = scene->shader_manager->get_shader_id(curve.shader, this, false);
-
- curve_data[i] = make_float4(
- __int_as_float(curve.first_key + curvekey_offset),
- __int_as_float(curve.num_keys),
- __int_as_float(shader_id),
- 0.0f);
+void Mesh::pack_patches(uint *patch_data, uint vert_offset, uint face_offset, uint corner_offset)
+{
+ size_t num_faces = subd_faces.size();
+ int ngons = 0;
+
+ for(size_t f = 0; f < num_faces; f++) {
+ SubdFace face = subd_faces[f];
+
+ if(face.is_quad()) {
+ int c[4];
+ memcpy(c, &subd_face_corners[face.start_corner], sizeof(int)*4);
+
+ *(patch_data++) = c[0] + vert_offset;
+ *(patch_data++) = c[1] + vert_offset;
+ *(patch_data++) = c[2] + vert_offset;
+ *(patch_data++) = c[3] + vert_offset;
+
+ *(patch_data++) = f+face_offset;
+ *(patch_data++) = face.num_corners;
+ *(patch_data++) = face.start_corner + corner_offset;
+ *(patch_data++) = 0;
+ }
+ else {
+ for(int i = 0; i < face.num_corners; i++) {
+ int c[4];
+ c[0] = subd_face_corners[face.start_corner + mod(i + 0, face.num_corners)];
+ c[1] = subd_face_corners[face.start_corner + mod(i + 1, face.num_corners)];
+ c[2] = verts.size() - num_subd_verts + ngons;
+ c[3] = subd_face_corners[face.start_corner + mod(i - 1, face.num_corners)];
+
+ *(patch_data++) = c[0] + vert_offset;
+ *(patch_data++) = c[1] + vert_offset;
+ *(patch_data++) = c[2] + vert_offset;
+ *(patch_data++) = c[3] + vert_offset;
+
+ *(patch_data++) = f+face_offset;
+ *(patch_data++) = face.num_corners | (i << 16);
+ *(patch_data++) = face.start_corner + corner_offset;
+ *(patch_data++) = subd_face_corners.size() + ngons + corner_offset;
+ }
+
+ ngons++;
}
}
}
-void Mesh::compute_bvh(SceneParams *params, Progress *progress, int n, int total)
+void Mesh::compute_bvh(DeviceScene *dscene,
+ SceneParams *params,
+ Progress *progress,
+ int n,
+ int total)
{
if(progress->get_cancel())
return;
@@ -525,6 +794,8 @@ void Mesh::compute_bvh(SceneParams *params, Progress *progress, int n, int total
BVHParams bparams;
bparams.use_spatial_split = params->use_bvh_spatial_split;
bparams.use_qbvh = params->use_qbvh;
+ bparams.use_unaligned_nodes = dscene->data.bvh.have_curves &&
+ params->use_bvh_unaligned_nodes;
delete bvh;
bvh = BVH::create(bparams, objects);
@@ -545,8 +816,8 @@ void Mesh::tag_update(Scene *scene, bool rebuild)
scene->light_manager->need_update = true;
}
else {
- foreach(uint sindex, used_shaders)
- if(scene->shaders[sindex]->has_surface_emission)
+ foreach(Shader *shader, used_shaders)
+ if(shader->has_surface_emission)
scene->light_manager->need_update = true;
}
@@ -561,6 +832,17 @@ bool Mesh::has_motion_blur() const
curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)));
}
+bool Mesh::has_true_displacement() const
+{
+ foreach(Shader *shader, used_shaders) {
+ if(shader->has_displacement && shader->displacement_method != DISPLACE_BUMP) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
bool Mesh::need_build_bvh() const
{
return !transform_applied || has_surface_bssrdf;
@@ -613,12 +895,14 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att
OSLGlobals::Attribute osl_attr;
osl_attr.type = attr.type();
- osl_attr.elem = ATTR_ELEMENT_OBJECT;
+ osl_attr.desc.element = ATTR_ELEMENT_OBJECT;
osl_attr.value = attr;
- osl_attr.offset = 0;
+ osl_attr.desc.offset = 0;
+ osl_attr.desc.flags = 0;
- og->attribute_map[i*ATTR_PRIM_TYPES][attr.name()] = osl_attr;
+ og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_TRIANGLE][attr.name()] = osl_attr;
og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][attr.name()] = osl_attr;
+ og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_SUBD][attr.name()] = osl_attr;
}
/* find mesh attributes */
@@ -634,9 +918,8 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att
foreach(AttributeRequest& req, attributes.requests) {
OSLGlobals::Attribute osl_attr;
- if(req.triangle_element != ATTR_ELEMENT_NONE) {
- osl_attr.elem = req.triangle_element;
- osl_attr.offset = req.triangle_offset;
+ if(req.triangle_desc.element != ATTR_ELEMENT_NONE) {
+ osl_attr.desc = req.triangle_desc;
if(req.triangle_type == TypeDesc::TypeFloat)
osl_attr.type = TypeDesc::TypeFloat;
@@ -648,17 +931,16 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att
if(req.std != ATTR_STD_NONE) {
/* if standard attribute, add lookup by geom: name convention */
ustring stdname(string("geom:") + string(Attribute::standard_name(req.std)));
- og->attribute_map[i*ATTR_PRIM_TYPES][stdname] = osl_attr;
+ og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_TRIANGLE][stdname] = osl_attr;
}
else if(req.name != ustring()) {
/* add lookup by mesh attribute name */
- og->attribute_map[i*ATTR_PRIM_TYPES][req.name] = osl_attr;
+ og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_TRIANGLE][req.name] = osl_attr;
}
}
- if(req.curve_element != ATTR_ELEMENT_NONE) {
- osl_attr.elem = req.curve_element;
- osl_attr.offset = req.curve_offset;
+ if(req.curve_desc.element != ATTR_ELEMENT_NONE) {
+ osl_attr.desc = req.curve_desc;
if(req.curve_type == TypeDesc::TypeFloat)
osl_attr.type = TypeDesc::TypeFloat;
@@ -677,6 +959,27 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att
og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][req.name] = osl_attr;
}
}
+
+ if(req.subd_desc.element != ATTR_ELEMENT_NONE) {
+ osl_attr.desc = req.subd_desc;
+
+ if(req.subd_type == TypeDesc::TypeFloat)
+ osl_attr.type = TypeDesc::TypeFloat;
+ else if(req.subd_type == TypeDesc::TypeMatrix)
+ osl_attr.type = TypeDesc::TypeMatrix;
+ else
+ osl_attr.type = TypeDesc::TypeColor;
+
+ if(req.std != ATTR_STD_NONE) {
+ /* if standard attribute, add lookup by geom: name convention */
+ ustring stdname(string("geom:") + string(Attribute::standard_name(req.std)));
+ og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_SUBD][stdname] = osl_attr;
+ }
+ else if(req.name != ustring()) {
+ /* add lookup by mesh attribute name */
+ og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_SUBD][req.name] = osl_attr;
+ }
+ }
}
}
#else
@@ -728,10 +1031,10 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
else
id = scene->shader_manager->get_attribute_id(req.std);
- if(mesh->triangles.size()) {
+ if(mesh->num_triangles()) {
attr_map[index].x = id;
- attr_map[index].y = req.triangle_element;
- attr_map[index].z = as_uint(req.triangle_offset);
+ attr_map[index].y = req.triangle_desc.element;
+ attr_map[index].z = as_uint(req.triangle_desc.offset);
if(req.triangle_type == TypeDesc::TypeFloat)
attr_map[index].w = NODE_ATTR_FLOAT;
@@ -739,14 +1042,16 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
attr_map[index].w = NODE_ATTR_MATRIX;
else
attr_map[index].w = NODE_ATTR_FLOAT3;
+
+ attr_map[index].w |= req.triangle_desc.flags << 8;
}
index++;
- if(mesh->curves.size()) {
+ if(mesh->num_curves()) {
attr_map[index].x = id;
- attr_map[index].y = req.curve_element;
- attr_map[index].z = as_uint(req.curve_offset);
+ attr_map[index].y = req.curve_desc.element;
+ attr_map[index].z = as_uint(req.curve_desc.offset);
if(req.curve_type == TypeDesc::TypeFloat)
attr_map[index].w = NODE_ATTR_FLOAT;
@@ -754,25 +1059,39 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
attr_map[index].w = NODE_ATTR_MATRIX;
else
attr_map[index].w = NODE_ATTR_FLOAT3;
+
+ attr_map[index].w |= req.curve_desc.flags << 8;
}
index++;
- }
- /* terminator */
- attr_map[index].x = ATTR_STD_NONE;
- attr_map[index].y = 0;
- attr_map[index].z = 0;
- attr_map[index].w = 0;
+ if(mesh->subd_faces.size()) {
+ attr_map[index].x = id;
+ attr_map[index].y = req.subd_desc.element;
+ attr_map[index].z = as_uint(req.subd_desc.offset);
+
+ if(req.subd_type == TypeDesc::TypeFloat)
+ attr_map[index].w = NODE_ATTR_FLOAT;
+ else if(req.subd_type == TypeDesc::TypeMatrix)
+ attr_map[index].w = NODE_ATTR_MATRIX;
+ else
+ attr_map[index].w = NODE_ATTR_FLOAT3;
- index++;
+ attr_map[index].w |= req.subd_desc.flags << 8;
+ }
- attr_map[index].x = ATTR_STD_NONE;
- attr_map[index].y = 0;
- attr_map[index].z = 0;
- attr_map[index].w = 0;
+ index++;
+ }
- index++;
+ /* terminator */
+ for(int i = 0; i < ATTR_PRIM_TYPES; i++) {
+ attr_map[index].x = ATTR_STD_NONE;
+ attr_map[index].y = 0;
+ attr_map[index].z = 0;
+ attr_map[index].w = 0;
+
+ index++;
+ }
}
/* copy to device */
@@ -782,17 +1101,13 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
static void update_attribute_element_size(Mesh *mesh,
Attribute *mattr,
+ AttributePrimitive prim,
size_t *attr_float_size,
size_t *attr_float3_size,
size_t *attr_uchar4_size)
{
if(mattr) {
- size_t size = mattr->element_size(
- mesh->verts.size(),
- mesh->triangles.size(),
- mesh->motion_steps,
- mesh->curves.size(),
- mesh->curve_keys.size());
+ size_t size = mattr->element_size(mesh, prim);
if(mattr->element == ATTR_ELEMENT_VOXEL) {
/* pass */
@@ -820,22 +1135,21 @@ static void update_attribute_element_offset(Mesh *mesh,
vector<uchar4>& attr_uchar4,
size_t& attr_uchar4_offset,
Attribute *mattr,
+ AttributePrimitive prim,
TypeDesc& type,
- int& offset,
- AttributeElement& element)
+ AttributeDescriptor& desc)
{
if(mattr) {
/* store element and type */
- element = mattr->element;
+ desc.element = mattr->element;
+ desc.flags = mattr->flags;
type = mattr->type;
/* store attribute data in arrays */
- size_t size = mattr->element_size(
- mesh->verts.size(),
- mesh->triangles.size(),
- mesh->motion_steps,
- mesh->curves.size(),
- mesh->curve_keys.size());
+ size_t size = mattr->element_size(mesh, prim);
+
+ AttributeElement& element = desc.element;
+ int& offset = desc.offset;
if(mattr->element == ATTR_ELEMENT_VOXEL) {
/* store slot in offset value */
@@ -885,14 +1199,26 @@ static void update_attribute_element_offset(Mesh *mesh,
/* mesh vertex/curve index is global, not per object, so we sneak
* a correction for that in here */
- if(element == ATTR_ELEMENT_VERTEX)
+ if(mesh->subdivision_type == Mesh::SUBDIVISION_CATMULL_CLARK && desc.flags & ATTR_SUBDIVIDED) {
+ /* indices for subdivided attributes are retrieved
+ * from patch table so no need for correction here*/
+ }
+ else if(element == ATTR_ELEMENT_VERTEX)
offset -= mesh->vert_offset;
else if(element == ATTR_ELEMENT_VERTEX_MOTION)
offset -= mesh->vert_offset;
- else if(element == ATTR_ELEMENT_FACE)
- offset -= mesh->tri_offset;
- else if(element == ATTR_ELEMENT_CORNER || element == ATTR_ELEMENT_CORNER_BYTE)
- offset -= 3*mesh->tri_offset;
+ else if(element == ATTR_ELEMENT_FACE) {
+ if(prim == ATTR_PRIM_TRIANGLE)
+ offset -= mesh->tri_offset;
+ else
+ offset -= mesh->face_offset;
+ }
+ else if(element == ATTR_ELEMENT_CORNER || element == ATTR_ELEMENT_CORNER_BYTE) {
+ if(prim == ATTR_PRIM_TRIANGLE)
+ offset -= 3*mesh->tri_offset;
+ else
+ offset -= mesh->corner_offset;
+ }
else if(element == ATTR_ELEMENT_CURVE)
offset -= mesh->curve_offset;
else if(element == ATTR_ELEMENT_CURVE_KEY)
@@ -902,8 +1228,8 @@ static void update_attribute_element_offset(Mesh *mesh,
}
else {
/* attribute not found */
- element = ATTR_ELEMENT_NONE;
- offset = 0;
+ desc.element = ATTR_ELEMENT_NONE;
+ desc.offset = 0;
}
}
@@ -921,8 +1247,7 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene,
scene->need_global_attributes(mesh_attributes[i]);
- foreach(uint sindex, mesh->used_shaders) {
- Shader *shader = scene->shaders[sindex];
+ foreach(Shader *shader, mesh->used_shaders) {
mesh_attributes[i].add(shader->attributes);
}
}
@@ -943,23 +1268,23 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene,
foreach(AttributeRequest& req, attributes.requests) {
Attribute *triangle_mattr = mesh->attributes.find(req);
Attribute *curve_mattr = mesh->curve_attributes.find(req);
-
- /* todo: get rid of this exception, it's only here for giving some
- * working texture coordinate for subdivision as we can't preserve
- * any attributes yet */
- if(!triangle_mattr && req.std == ATTR_STD_GENERATED) {
- triangle_mattr = mesh->attributes.add(ATTR_STD_GENERATED);
- if(mesh->verts.size())
- memcpy(triangle_mattr->data_float3(), &mesh->verts[0], sizeof(float3)*mesh->verts.size());
- }
+ Attribute *subd_mattr = mesh->subd_attributes.find(req);
update_attribute_element_size(mesh,
triangle_mattr,
+ ATTR_PRIM_TRIANGLE,
&attr_float_size,
&attr_float3_size,
&attr_uchar4_size);
update_attribute_element_size(mesh,
curve_mattr,
+ ATTR_PRIM_CURVE,
+ &attr_float_size,
+ &attr_float3_size,
+ &attr_uchar4_size);
+ update_attribute_element_size(mesh,
+ subd_mattr,
+ ATTR_PRIM_SUBD,
&attr_float_size,
&attr_float3_size,
&attr_uchar4_size);
@@ -984,24 +1309,34 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene,
foreach(AttributeRequest& req, attributes.requests) {
Attribute *triangle_mattr = mesh->attributes.find(req);
Attribute *curve_mattr = mesh->curve_attributes.find(req);
+ Attribute *subd_mattr = mesh->subd_attributes.find(req);
update_attribute_element_offset(mesh,
attr_float, attr_float_offset,
attr_float3, attr_float3_offset,
attr_uchar4, attr_uchar4_offset,
triangle_mattr,
+ ATTR_PRIM_TRIANGLE,
req.triangle_type,
- req.triangle_offset,
- req.triangle_element);
+ req.triangle_desc);
update_attribute_element_offset(mesh,
attr_float, attr_float_offset,
attr_float3, attr_float3_offset,
attr_uchar4, attr_uchar4_offset,
curve_mattr,
+ ATTR_PRIM_CURVE,
req.curve_type,
- req.curve_offset,
- req.curve_element);
+ req.curve_desc);
+
+ update_attribute_element_offset(mesh,
+ attr_float, attr_float_offset,
+ attr_float3, attr_float3_offset,
+ attr_uchar4, attr_uchar4_offset,
+ subd_mattr,
+ ATTR_PRIM_SUBD,
+ req.subd_type,
+ req.subd_desc);
if(progress.get_cancel()) return;
}
@@ -1032,15 +1367,18 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene,
}
}
-void MeshManager::device_update_mesh(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
+void MeshManager::mesh_calc_offset(Scene *scene)
{
- /* count and update offsets */
size_t vert_size = 0;
size_t tri_size = 0;
size_t curve_key_size = 0;
size_t curve_size = 0;
+ size_t patch_size = 0;
+ size_t face_size = 0;
+ size_t corner_size = 0;
+
foreach(Mesh *mesh, scene->meshes) {
mesh->vert_offset = vert_size;
mesh->tri_offset = tri_size;
@@ -1048,26 +1386,109 @@ void MeshManager::device_update_mesh(Device *device, DeviceScene *dscene, Scene
mesh->curvekey_offset = curve_key_size;
mesh->curve_offset = curve_size;
+ mesh->patch_offset = patch_size;
+ mesh->face_offset = face_size;
+ mesh->corner_offset = corner_size;
+
+ vert_size += mesh->verts.size();
+ tri_size += mesh->num_triangles();
+
+ curve_key_size += mesh->curve_keys.size();
+ curve_size += mesh->num_curves();
+
+ if(mesh->subd_faces.size()) {
+ Mesh::SubdFace& last = mesh->subd_faces[mesh->subd_faces.size()-1];
+ patch_size += (last.ptex_offset + last.num_ptex_faces()) * 8;
+
+ /* patch tables are stored in same array so include them in patch_size */
+ if(mesh->patch_table) {
+ mesh->patch_table_offset = patch_size;
+ patch_size += mesh->patch_table->total_size();
+ }
+ }
+ face_size += mesh->subd_faces.size();
+ corner_size += mesh->subd_face_corners.size();
+ }
+}
+
+void MeshManager::device_update_mesh(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ bool for_displacement,
+ Progress& progress)
+{
+ /* Count. */
+ size_t vert_size = 0;
+ size_t tri_size = 0;
+
+ size_t curve_key_size = 0;
+ size_t curve_size = 0;
+
+ size_t patch_size = 0;
+
+ foreach(Mesh *mesh, scene->meshes) {
vert_size += mesh->verts.size();
- tri_size += mesh->triangles.size();
+ tri_size += mesh->num_triangles();
curve_key_size += mesh->curve_keys.size();
- curve_size += mesh->curves.size();
+ curve_size += mesh->num_curves();
+
+ if(mesh->subd_faces.size()) {
+ Mesh::SubdFace& last = mesh->subd_faces[mesh->subd_faces.size()-1];
+ patch_size += (last.ptex_offset + last.num_ptex_faces()) * 8;
+
+ /* patch tables are stored in same array so include them in patch_size */
+ if(mesh->patch_table) {
+ mesh->patch_table_offset = patch_size;
+ patch_size += mesh->patch_table->total_size();
+ }
+ }
+ }
+
+ /* Create mapping from triangle to primitive triangle array. */
+ vector<uint> tri_prim_index(tri_size);
+ if(for_displacement) {
+ /* For displacement kernels we do some trickery to make them believe
+ * we've got all required data ready. However, that data is different
+ * from final render kernels since we don't have BVH yet, so can't
+ * really use same semantic of arrays.
+ */
+ foreach(Mesh *mesh, scene->meshes) {
+ for(size_t i = 0; i < mesh->num_triangles(); ++i) {
+ tri_prim_index[i + mesh->tri_offset] = 3 * (i + mesh->tri_offset);
+ }
+ }
+ }
+ else {
+ PackedBVH& pack = bvh->pack;
+ for(size_t i = 0; i < pack.prim_index.size(); ++i) {
+ if((pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) {
+ tri_prim_index[pack.prim_index[i]] = pack.prim_tri_index[i];
+ }
+ }
}
+ /* Fill in all the arrays. */
if(tri_size != 0) {
/* normals */
progress.set_status("Updating Mesh", "Computing normals");
uint *tri_shader = dscene->tri_shader.resize(tri_size);
float4 *vnormal = dscene->tri_vnormal.resize(vert_size);
- float4 *tri_verts = dscene->tri_verts.resize(vert_size);
- float4 *tri_vindex = dscene->tri_vindex.resize(tri_size);
+ uint4 *tri_vindex = dscene->tri_vindex.resize(tri_size);
+ uint *tri_patch = dscene->tri_patch.resize(tri_size);
+ float2 *tri_patch_uv = dscene->tri_patch_uv.resize(vert_size);
foreach(Mesh *mesh, scene->meshes) {
- mesh->pack_normals(scene, &tri_shader[mesh->tri_offset], &vnormal[mesh->vert_offset]);
- mesh->pack_verts(&tri_verts[mesh->vert_offset], &tri_vindex[mesh->tri_offset], mesh->vert_offset);
-
+ mesh->pack_normals(scene,
+ &tri_shader[mesh->tri_offset],
+ &vnormal[mesh->vert_offset]);
+ mesh->pack_verts(tri_prim_index,
+ &tri_vindex[mesh->tri_offset],
+ &tri_patch[mesh->tri_offset],
+ &tri_patch_uv[mesh->vert_offset],
+ mesh->vert_offset,
+ mesh->tri_offset);
if(progress.get_cancel()) return;
}
@@ -1076,8 +1497,9 @@ void MeshManager::device_update_mesh(Device *device, DeviceScene *dscene, Scene
device->tex_alloc("__tri_shader", dscene->tri_shader);
device->tex_alloc("__tri_vnormal", dscene->tri_vnormal);
- device->tex_alloc("__tri_verts", dscene->tri_verts);
device->tex_alloc("__tri_vindex", dscene->tri_vindex);
+ device->tex_alloc("__tri_patch", dscene->tri_patch);
+ device->tex_alloc("__tri_patch_uv", dscene->tri_patch_uv);
}
if(curve_size != 0) {
@@ -1094,6 +1516,38 @@ void MeshManager::device_update_mesh(Device *device, DeviceScene *dscene, Scene
device->tex_alloc("__curve_keys", dscene->curve_keys);
device->tex_alloc("__curves", dscene->curves);
}
+
+ if(patch_size != 0) {
+ progress.set_status("Updating Mesh", "Copying Patches to device");
+
+ uint *patch_data = dscene->patches.resize(patch_size);
+
+ foreach(Mesh *mesh, scene->meshes) {
+ mesh->pack_patches(&patch_data[mesh->patch_offset], mesh->vert_offset, mesh->face_offset, mesh->corner_offset);
+
+ if(mesh->patch_table) {
+ mesh->patch_table->copy_adjusting_offsets(&patch_data[mesh->patch_table_offset], mesh->patch_table_offset);
+ }
+
+ if(progress.get_cancel()) return;
+ }
+
+ device->tex_alloc("__patches", dscene->patches);
+ }
+
+ if(for_displacement) {
+ float4 *prim_tri_verts = dscene->prim_tri_verts.resize(tri_size * 3);
+ foreach(Mesh *mesh, scene->meshes) {
+ for(size_t i = 0; i < mesh->num_triangles(); ++i) {
+ Mesh::Triangle t = mesh->get_triangle(i);
+ size_t offset = 3 * (i + mesh->tri_offset);
+ prim_tri_verts[offset + 0] = float3_to_float4(mesh->verts[t.v[0]]);
+ prim_tri_verts[offset + 1] = float3_to_float4(mesh->verts[t.v[1]]);
+ prim_tri_verts[offset + 2] = float3_to_float4(mesh->verts[t.v[2]]);
+ }
+ }
+ device->tex_alloc("__prim_tri_verts", dscene->prim_tri_verts);
+ }
}
void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
@@ -1108,6 +1562,8 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *
bparams.top_level = true;
bparams.use_qbvh = scene->params.use_qbvh;
bparams.use_spatial_split = scene->params.use_bvh_spatial_split;
+ bparams.use_unaligned_nodes = dscene->data.bvh.have_curves &&
+ scene->params.use_bvh_unaligned_nodes;
delete bvh;
bvh = BVH::create(bparams, scene->objects);
@@ -1132,9 +1588,13 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *
dscene->object_node.reference((uint*)&pack.object_node[0], pack.object_node.size());
device->tex_alloc("__object_node", dscene->object_node);
}
- if(pack.tri_storage.size()) {
- dscene->tri_storage.reference(&pack.tri_storage[0], pack.tri_storage.size());
- device->tex_alloc("__tri_storage", dscene->tri_storage);
+ if(pack.prim_tri_index.size()) {
+ dscene->prim_tri_index.reference((uint*)&pack.prim_tri_index[0], pack.prim_tri_index.size());
+ device->tex_alloc("__prim_tri_index", dscene->prim_tri_index);
+ }
+ if(pack.prim_tri_verts.size()) {
+ dscene->prim_tri_verts.reference((float4*)&pack.prim_tri_verts[0], pack.prim_tri_verts.size());
+ device->tex_alloc("__prim_tri_verts", dscene->prim_tri_verts);
}
if(pack.prim_type.size()) {
dscene->prim_type.reference((uint*)&pack.prim_type[0], pack.prim_type.size());
@@ -1168,8 +1628,7 @@ void MeshManager::device_update_flags(Device * /*device*/,
/* update flags */
foreach(Mesh *mesh, scene->meshes) {
mesh->has_volume = false;
- foreach(uint shader_index, mesh->used_shaders) {
- const Shader *shader = scene->shaders[shader_index];
+ foreach(const Shader *shader, mesh->used_shaders) {
if(shader->has_volume) {
mesh->has_volume = true;
}
@@ -1192,12 +1651,11 @@ void MeshManager::device_update_displacement_images(Device *device,
set<int> bump_images;
foreach(Mesh *mesh, scene->meshes) {
if(mesh->need_update) {
- foreach(uint shader_index, mesh->used_shaders) {
- Shader *shader = scene->shaders[shader_index];
- if(shader->graph_bump == NULL) {
+ foreach(Shader *shader, mesh->used_shaders) {
+ if(!shader->has_displacement || shader->displacement_method == DISPLACE_BUMP) {
continue;
}
- foreach(ShaderNode* node, shader->graph_bump->nodes) {
+ foreach(ShaderNode* node, shader->graph->nodes) {
if(node->special_type != SHADER_SPECIAL_TYPE_IMAGE_SLOT) {
continue;
}
@@ -1237,10 +1695,10 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
VLOG(1) << "Total " << scene->meshes.size() << " meshes.";
- /* update normals */
+ /* Update normals. */
foreach(Mesh *mesh, scene->meshes) {
- foreach(uint shader, mesh->used_shaders) {
- if(scene->shaders[shader]->need_update_attributes)
+ foreach(Shader *shader, mesh->used_shaders) {
+ if(shader->need_update_attributes)
mesh->need_update = true;
}
@@ -1248,22 +1706,62 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
mesh->add_face_normals();
mesh->add_vertex_normals();
+ if(mesh->need_attribute(scene, ATTR_STD_POSITION_UNDISPLACED)) {
+ mesh->add_undisplaced();
+ }
+
+ if(progress.get_cancel()) return;
+ }
+ }
+
+ /* Tessellate meshes that are using subdivision */
+ size_t total_tess_needed = 0;
+ foreach(Mesh *mesh, scene->meshes) {
+ if(mesh->need_update &&
+ mesh->subdivision_type != Mesh::SUBDIVISION_NONE &&
+ mesh->num_subd_verts == 0 &&
+ mesh->subd_params)
+ {
+ total_tess_needed++;
+ }
+ }
+
+ size_t i = 0;
+ foreach(Mesh *mesh, scene->meshes) {
+ if(mesh->need_update &&
+ mesh->subdivision_type != Mesh::SUBDIVISION_NONE &&
+ mesh->num_subd_verts == 0 &&
+ mesh->subd_params)
+ {
+ string msg = "Tessellating ";
+ if(mesh->name == "")
+ msg += string_printf("%u/%u", (uint)(i+1), (uint)total_tess_needed);
+ else
+ msg += string_printf("%s %u/%u", mesh->name.c_str(), (uint)(i+1), (uint)total_tess_needed);
+
+ progress.set_status("Updating Mesh", msg);
+
+ DiagSplit dsplit(*mesh->subd_params);
+ mesh->tessellate(&dsplit);
+
+ i++;
+
if(progress.get_cancel()) return;
}
}
/* Update images needed for true displacement. */
- bool need_displacement_images = false;
+ bool true_displacement_used = false;
bool old_need_object_flags_update = false;
foreach(Mesh *mesh, scene->meshes) {
if(mesh->need_update &&
- mesh->displacement_method != Mesh::DISPLACE_BUMP)
+ mesh->has_true_displacement())
{
- need_displacement_images = true;
+ true_displacement_used = true;
break;
}
}
- if(need_displacement_images) {
+ if(true_displacement_used) {
VLOG(1) << "Updating images used for true displacement.";
device_update_displacement_images(device, dscene, scene, progress);
old_need_object_flags_update = scene->object_manager->need_flags_update;
@@ -1274,49 +1772,59 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
false);
}
- /* device update */
+ /* Device update. */
device_free(device, dscene);
- device_update_mesh(device, dscene, scene, progress);
+ mesh_calc_offset(scene);
+ if(true_displacement_used) {
+ device_update_mesh(device, dscene, scene, true, progress);
+ }
if(progress.get_cancel()) return;
+ /* after mesh data has been copied to device memory we need to update
+ * offsets for patch tables as this can't be known before hand */
+ scene->object_manager->device_update_patch_map_offsets(device, dscene, scene);
+
device_update_attributes(device, dscene, scene, progress);
if(progress.get_cancel()) return;
- /* update displacement */
+ /* Update displacement. */
bool displacement_done = false;
-
- foreach(Mesh *mesh, scene->meshes)
- if(mesh->need_update && displace(device, dscene, scene, mesh, progress))
+ foreach(Mesh *mesh, scene->meshes) {
+ if(mesh->need_update &&
+ displace(device, dscene, scene, mesh, progress))
+ {
displacement_done = true;
+ }
+ }
- /* todo: properly handle cancel halfway displacement */
+ /* TODO: properly handle cancel halfway displacement */
if(progress.get_cancel()) return;
- /* device re-update after displacement */
+ /* Device re-update after displacement. */
if(displacement_done) {
device_free(device, dscene);
- device_update_mesh(device, dscene, scene, progress);
- if(progress.get_cancel()) return;
-
device_update_attributes(device, dscene, scene, progress);
if(progress.get_cancel()) return;
}
- /* update bvh */
- size_t i = 0, num_bvh = 0;
-
- foreach(Mesh *mesh, scene->meshes)
- if(mesh->need_update && mesh->need_build_bvh())
+ /* Update bvh. */
+ size_t num_bvh = 0;
+ foreach(Mesh *mesh, scene->meshes) {
+ if(mesh->need_update && mesh->need_build_bvh()) {
num_bvh++;
+ }
+ }
TaskPool pool;
+ i = 0;
foreach(Mesh *mesh, scene->meshes) {
if(mesh->need_update) {
pool.push(function_bind(&Mesh::compute_bvh,
mesh,
+ dscene,
&scene->params,
&progress,
i,
@@ -1332,8 +1840,9 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
VLOG(2) << "Objects BVH build pool statistics:\n"
<< summary.full_report();
- foreach(Shader *shader, scene->shaders)
+ foreach(Shader *shader, scene->shaders) {
shader->need_update_attributes = false;
+ }
#ifdef __OBJECT_MOTION__
Scene::MotionType need_motion = scene->need_motion(device->info.advanced_shading);
@@ -1342,18 +1851,23 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
bool motion_blur = false;
#endif
- /* update obejcts */
+ /* Update objects. */
vector<Object *> volume_objects;
- foreach(Object *object, scene->objects)
+ foreach(Object *object, scene->objects) {
object->compute_bounds(motion_blur);
+ }
if(progress.get_cancel()) return;
device_update_bvh(device, dscene, scene, progress);
+ if(progress.get_cancel()) return;
+
+ device_update_mesh(device, dscene, scene, false, progress);
+ if(progress.get_cancel()) return;
need_update = false;
- if(need_displacement_images) {
+ if(true_displacement_used) {
/* Re-tag flags for update, so they're re-evaluated
* for meshes with correct bounding boxes.
*
@@ -1369,7 +1883,8 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene)
device->tex_free(dscene->bvh_nodes);
device->tex_free(dscene->bvh_leaf_nodes);
device->tex_free(dscene->object_node);
- device->tex_free(dscene->tri_storage);
+ device->tex_free(dscene->prim_tri_verts);
+ device->tex_free(dscene->prim_tri_index);
device->tex_free(dscene->prim_type);
device->tex_free(dscene->prim_visibility);
device->tex_free(dscene->prim_index);
@@ -1377,9 +1892,11 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene)
device->tex_free(dscene->tri_shader);
device->tex_free(dscene->tri_vnormal);
device->tex_free(dscene->tri_vindex);
- device->tex_free(dscene->tri_verts);
+ device->tex_free(dscene->tri_patch);
+ device->tex_free(dscene->tri_patch_uv);
device->tex_free(dscene->curves);
device->tex_free(dscene->curve_keys);
+ device->tex_free(dscene->patches);
device->tex_free(dscene->attributes_map);
device->tex_free(dscene->attributes_float);
device->tex_free(dscene->attributes_float3);
@@ -1387,7 +1904,8 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene)
dscene->bvh_nodes.clear();
dscene->object_node.clear();
- dscene->tri_storage.clear();
+ dscene->prim_tri_verts.clear();
+ dscene->prim_tri_index.clear();
dscene->prim_type.clear();
dscene->prim_visibility.clear();
dscene->prim_index.clear();
@@ -1395,9 +1913,11 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene)
dscene->tri_shader.clear();
dscene->tri_vnormal.clear();
dscene->tri_vindex.clear();
- dscene->tri_verts.clear();
+ dscene->tri_patch.clear();
+ dscene->tri_patch_uv.clear();
dscene->curves.clear();
dscene->curve_keys.clear();
+ dscene->patches.clear();
dscene->attributes_map.clear();
dscene->attributes_float.clear();
dscene->attributes_float3.clear();
@@ -1428,93 +1948,24 @@ bool Mesh::need_attribute(Scene *scene, AttributeStandard std)
if(scene->need_global_attribute(std))
return true;
- foreach(uint shader, used_shaders)
- if(scene->shaders[shader]->attributes.find(std))
+ foreach(Shader *shader, used_shaders)
+ if(shader->attributes.find(std))
return true;
return false;
}
-bool Mesh::need_attribute(Scene *scene, ustring name)
+bool Mesh::need_attribute(Scene * /*scene*/, ustring name)
{
if(name == ustring())
return false;
- foreach(uint shader, used_shaders)
- if(scene->shaders[shader]->attributes.find(name))
+ foreach(Shader *shader, used_shaders)
+ if(shader->attributes.find(name))
return true;
return false;
}
-void Mesh::tessellate(DiagSplit *split)
-{
- int num_faces = triangles.size();
-
- add_face_normals();
- add_vertex_normals();
-
- Attribute *attr_fN = attributes.find(ATTR_STD_FACE_NORMAL);
- float3 *fN = attr_fN->data_float3();
-
- Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL);
- float3 *vN = attr_vN->data_float3();
-
- for(int f = 0; f < num_faces; f++) {
- if(!forms_quad[f]) {
- /* triangle */
- LinearTrianglePatch patch;
- float3 *hull = patch.hull;
- float3 *normals = patch.normals;
-
- for(int i = 0; i < 3; i++) {
- hull[i] = verts[triangles[f].v[i]];
- }
-
- if(smooth[f]) {
- for(int i = 0; i < 3; i++) {
- normals[i] = vN[triangles[f].v[i]];
- }
- }
- else {
- for(int i = 0; i < 3; i++) {
- normals[i] = fN[f];
- }
- }
-
- split->split_triangle(&patch);
- }
- else {
- /* quad */
- LinearQuadPatch patch;
- float3 *hull = patch.hull;
- float3 *normals = patch.normals;
-
- hull[0] = verts[triangles[f ].v[0]];
- hull[1] = verts[triangles[f ].v[1]];
- hull[3] = verts[triangles[f ].v[2]];
- hull[2] = verts[triangles[f+1].v[2]];
-
- if(smooth[f]) {
- normals[0] = vN[triangles[f ].v[0]];
- normals[1] = vN[triangles[f ].v[1]];
- normals[3] = vN[triangles[f ].v[2]];
- normals[2] = vN[triangles[f+1].v[2]];
- }
- else {
- for(int i = 0; i < 4; i++) {
- normals[i] = fN[f];
- }
- }
-
- split->split_quad(&patch);
-
- // consume second triangle in quad
- f++;
- }
-
- }
-}
-
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h
index 006a4889d50..c0310f45840 100644
--- a/intern/cycles/render/mesh.h
+++ b/intern/cycles/render/mesh.h
@@ -18,6 +18,7 @@
#define __MESH_H__
#include "attribute.h"
+#include "node.h"
#include "shader.h"
#include "util_boundbox.h"
@@ -38,12 +39,16 @@ class Progress;
class Scene;
class SceneParams;
class AttributeRequest;
+struct SubdParams;
class DiagSplit;
+struct PackedPatchTable;
/* Mesh */
-class Mesh {
+class Mesh : public Node {
public:
+ NODE_DECLARE;
+
/* Mesh Triangle */
struct Triangle {
int v[3];
@@ -51,27 +56,74 @@ public:
void bounds_grow(const float3 *verts, BoundBox& bounds) const;
};
+ Triangle get_triangle(size_t i) const
+ {
+ Triangle tri = {{triangles[i*3 + 0], triangles[i*3 + 1], triangles[i*3 + 2]}};
+ return tri;
+ }
+
+ size_t num_triangles() const
+ {
+ return triangles.size() / 3;
+ }
+
/* Mesh Curve */
struct Curve {
int first_key;
int num_keys;
- uint shader;
int num_segments() { return num_keys - 1; }
- void bounds_grow(const int k, const float4 *curve_keys, BoundBox& bounds) const;
+ void bounds_grow(const int k,
+ const float3 *curve_keys,
+ const float *curve_radius,
+ BoundBox& bounds) const;
+ void bounds_grow(const int k,
+ const float3 *curve_keys,
+ const float *curve_radius,
+ const Transform& aligned_space,
+ BoundBox& bounds) const;
+ };
+
+ Curve get_curve(size_t i) const
+ {
+ int first = curve_first_key[i];
+ int next_first = (i+1 < curve_first_key.size()) ? curve_first_key[i+1] : curve_keys.size();
+
+ Curve curve = {first, next_first - first};
+ return curve;
+ }
+
+ size_t num_curves() const
+ {
+ return curve_first_key.size();
+ }
+
+ /* Mesh SubdFace */
+ struct SubdFace {
+ int start_corner;
+ int num_corners;
+ int shader;
+ bool smooth;
+ int ptex_offset;
+
+ bool is_quad() { return num_corners == 4; }
+ float3 normal(const Mesh *mesh) const;
+ int num_ptex_faces() const { return num_corners == 4 ? 1 : num_corners; }
};
- /* Displacement */
- enum DisplacementMethod {
- DISPLACE_BUMP = 0,
- DISPLACE_TRUE = 1,
- DISPLACE_BOTH = 2,
+ struct SubdEdgeCrease {
+ int v[2];
+ float crease;
+ };
- DISPLACE_NUM_METHODS,
+ enum SubdivisionType {
+ SUBDIVISION_NONE,
+ SUBDIVISION_LINEAR,
+ SUBDIVISION_CATMULL_CLARK,
};
- ustring name;
+ SubdivisionType subdivision_type;
/* Mesh Data */
enum GeometryFlags {
@@ -82,27 +134,42 @@ public:
int geometry_flags; /* used to distinguish meshes with no verts
and meshed for which geometry is not created */
- vector<float3> verts;
- vector<Triangle> triangles;
- vector<uint> shader;
- vector<bool> smooth;
- vector<bool> forms_quad; /* used to tell if triangle is part of a quad patch */
+ array<int> triangles;
+ array<float3> verts;
+ array<int> shader;
+ array<bool> smooth;
+
+ /* used for storing patch info for subd triangles, only allocated if there are patches */
+ array<int> triangle_patch; /* must be < 0 for non subd triangles */
+ array<float2> vert_patch_uv;
bool has_volume; /* Set in the device_update_flags(). */
bool has_surface_bssrdf; /* Set in the device_update_flags(). */
- vector<float4> curve_keys; /* co + radius */
- vector<Curve> curves;
+ array<float3> curve_keys;
+ array<float> curve_radius;
+ array<int> curve_first_key;
+ array<int> curve_shader;
+
+ array<SubdFace> subd_faces;
+ array<int> subd_face_corners;
+ int num_ngons;
- vector<uint> used_shaders;
+ array<SubdEdgeCrease> subd_creases;
+
+ SubdParams *subd_params;
+
+ vector<Shader*> used_shaders;
AttributeSet attributes;
AttributeSet curve_attributes;
+ AttributeSet subd_attributes;
BoundBox bounds;
bool transform_applied;
bool transform_negative_scaled;
Transform transform_normal;
- DisplacementMethod displacement_method;
+
+ PackedPatchTable *patch_table;
uint motion_steps;
bool use_motion_blur;
@@ -119,26 +186,52 @@ public:
size_t curve_offset;
size_t curvekey_offset;
+ size_t patch_offset;
+ size_t patch_table_offset;
+ size_t face_offset;
+ size_t corner_offset;
+
+ size_t num_subd_verts;
+
/* Functions */
Mesh();
~Mesh();
- void reserve(int numverts, int numfaces, int numcurves, int numcurvekeys);
+ void resize_mesh(int numverts, int numfaces);
+ void reserve_mesh(int numverts, int numfaces);
+ void resize_curves(int numcurves, int numkeys);
+ void reserve_curves(int numcurves, int numkeys);
+ void resize_subd_faces(int numfaces, int num_ngons, int numcorners);
+ void reserve_subd_faces(int numfaces, int num_ngons, int numcorners);
void clear();
- void set_triangle(int i, int v0, int v1, int v2, int shader, bool smooth, bool forms_quad = false);
- void add_triangle(int v0, int v1, int v2, int shader, bool smooth, bool forms_quad = false);
+ void add_vertex(float3 P);
+ void add_vertex_slow(float3 P);
+ void add_triangle(int v0, int v1, int v2, int shader, bool smooth);
void add_curve_key(float3 loc, float radius);
- void add_curve(int first_key, int num_keys, int shader);
+ void add_curve(int first_key, int shader);
+ void add_subd_face(int* corners, int num_corners, int shader_, bool smooth_);
int split_vertex(int vertex);
void compute_bounds();
void add_face_normals();
void add_vertex_normals();
+ void add_undisplaced();
void pack_normals(Scene *scene, uint *shader, float4 *vnormal);
- void pack_verts(float4 *tri_verts, float4 *tri_vindex, size_t vert_offset);
+ void pack_verts(const vector<uint>& tri_prim_index,
+ uint4 *tri_vindex,
+ uint *tri_patch,
+ float2 *tri_patch_uv,
+ size_t vert_offset,
+ size_t tri_offset);
void pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, size_t curvekey_offset);
- void compute_bvh(SceneParams *params, Progress *progress, int n, int total);
+ void pack_patches(uint *patch_data, uint vert_offset, uint face_offset, uint corner_offset);
+
+ void compute_bvh(DeviceScene *dscene,
+ SceneParams *params,
+ Progress *progress,
+ int n,
+ int total);
bool need_attribute(Scene *scene, AttributeStandard std);
bool need_attribute(Scene *scene, ustring name);
@@ -146,6 +239,7 @@ public:
void tag_update(Scene *scene, bool rebuild);
bool has_motion_blur() const;
+ bool has_true_displacement() const;
/* Check whether the mesh should have own BVH built separately. Briefly,
* own BVH is needed for mesh, if:
@@ -182,15 +276,41 @@ public:
void update_svm_attributes(Device *device, DeviceScene *dscene, Scene *scene, vector<AttributeRequestSet>& mesh_attributes);
void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
- void device_update_object(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
- void device_update_mesh(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
- void device_update_attributes(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
- void device_update_bvh(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
void device_update_flags(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
- void device_update_displacement_images(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
+
void device_free(Device *device, DeviceScene *dscene);
void tag_update(Scene *scene);
+
+protected:
+ /* Calculate verts/triangles/curves offsets in global arrays. */
+ void mesh_calc_offset(Scene *scene);
+
+ void device_update_object(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress& progress);
+
+ void device_update_mesh(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ bool for_displacement,
+ Progress& progress);
+
+ void device_update_attributes(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress& progress);
+
+ void device_update_bvh(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress& progress);
+
+ void device_update_displacement_images(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress& progress);
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/mesh_displace.cpp b/intern/cycles/render/mesh_displace.cpp
index dccfd74f17a..adc5b820298 100644
--- a/intern/cycles/render/mesh_displace.cpp
+++ b/intern/cycles/render/mesh_displace.cpp
@@ -26,19 +26,27 @@
CCL_NAMESPACE_BEGIN
+static float3 compute_face_normal(const Mesh::Triangle& t, float3 *verts)
+{
+ float3 v0 = verts[t.v[0]];
+ float3 v1 = verts[t.v[1]];
+ float3 v2 = verts[t.v[2]];
+
+ float3 norm = cross(v1 - v0, v2 - v0);
+ float normlen = len(norm);
+
+ if(normlen == 0.0f)
+ return make_float3(1.0f, 0.0f, 0.0f);
+
+ return norm / normlen;
+}
+
bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Mesh *mesh, Progress& progress)
{
/* verify if we have a displacement shader */
- bool has_displacement = false;
-
- if(mesh->displacement_method != Mesh::DISPLACE_BUMP) {
- foreach(uint sindex, mesh->used_shaders)
- if(scene->shaders[sindex]->has_displacement)
- has_displacement = true;
- }
-
- if(!has_displacement)
+ if(!mesh->has_true_displacement()) {
return false;
+ }
string msg = string_printf("Computing Displacement %s", mesh->name.c_str());
progress.set_status("Updating Mesh", msg);
@@ -60,12 +68,16 @@ bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Me
uint4 *d_input_data = d_input.resize(num_verts);
size_t d_input_size = 0;
- for(size_t i = 0; i < mesh->triangles.size(); i++) {
- Mesh::Triangle t = mesh->triangles[i];
- Shader *shader = scene->shaders[mesh->shader[i]];
+ size_t num_triangles = mesh->num_triangles();
+ for(size_t i = 0; i < num_triangles; i++) {
+ Mesh::Triangle t = mesh->get_triangle(i);
+ int shader_index = mesh->shader[i];
+ Shader *shader = (shader_index < mesh->used_shaders.size()) ?
+ mesh->used_shaders[shader_index] : scene->default_surface;
- if(!shader->has_displacement)
+ if(!shader->has_displacement || shader->displacement_method == DISPLACE_BUMP) {
continue;
+ }
for(int j = 0; j < 3; j++) {
if(done[t.v[j]])
@@ -74,8 +86,7 @@ bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Me
done[t.v[j]] = true;
/* set up object, primitive and barycentric coordinates */
- /* when used, non-instanced convention: object = ~object */
- int object = ~object_index;
+ int object = object_index;
int prim = mesh->tri_offset + i;
float u, v;
@@ -144,12 +155,15 @@ bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Me
float4 *offset = (float4*)d_output.data_pointer;
Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- for(size_t i = 0; i < mesh->triangles.size(); i++) {
- Mesh::Triangle t = mesh->triangles[i];
- Shader *shader = scene->shaders[mesh->shader[i]];
+ for(size_t i = 0; i < num_triangles; i++) {
+ Mesh::Triangle t = mesh->get_triangle(i);
+ int shader_index = mesh->shader[i];
+ Shader *shader = (shader_index < mesh->used_shaders.size()) ?
+ mesh->used_shaders[shader_index] : scene->default_surface;
- if(!shader->has_displacement)
+ if(!shader->has_displacement || shader->displacement_method == DISPLACE_BUMP) {
continue;
+ }
for(int j = 0; j < 3; j++) {
if(!done[t.v[j]]) {
@@ -173,9 +187,131 @@ bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Me
mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
mesh->add_face_normals();
- if(mesh->displacement_method == Mesh::DISPLACE_TRUE) {
- mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
- mesh->add_vertex_normals();
+ bool need_recompute_vertex_normals = false;
+
+ foreach(Shader *shader, mesh->used_shaders) {
+ if(shader->has_displacement && shader->displacement_method == DISPLACE_TRUE) {
+ need_recompute_vertex_normals = true;
+ break;
+ }
+ }
+
+ if(need_recompute_vertex_normals) {
+ bool flip = mesh->transform_negative_scaled;
+ vector<bool> tri_has_true_disp(num_triangles, false);
+
+ for(size_t i = 0; i < num_triangles; i++) {
+ int shader_index = mesh->shader[i];
+ Shader *shader = (shader_index < mesh->used_shaders.size()) ?
+ mesh->used_shaders[shader_index] : scene->default_surface;
+
+ tri_has_true_disp[i] = shader->has_displacement && shader->displacement_method == DISPLACE_TRUE;
+ }
+
+ /* static vertex normals */
+
+ /* get attributes */
+ Attribute *attr_fN = mesh->attributes.find(ATTR_STD_FACE_NORMAL);
+ Attribute *attr_vN = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL);
+
+ float3 *fN = attr_fN->data_float3();
+ float3 *vN = attr_vN->data_float3();
+
+ /* compute vertex normals */
+
+ /* zero vertex normals on triangles with true displacement */
+ for(size_t i = 0; i < num_triangles; i++) {
+ if(tri_has_true_disp[i]) {
+ for(size_t j = 0; j < 3; j++) {
+ vN[mesh->get_triangle(i).v[j]] = make_float3(0.0f, 0.0f, 0.0f);
+ }
+ }
+ }
+
+ /* add face normals to vertex normals */
+ for(size_t i = 0; i < num_triangles; i++) {
+ if(tri_has_true_disp[i]) {
+ for(size_t j = 0; j < 3; j++) {
+ vN[mesh->get_triangle(i).v[j]] += fN[i];
+ }
+ }
+ }
+
+ /* normalize vertex normals */
+ done.clear();
+ done.resize(num_verts, false);
+
+ for(size_t i = 0; i < num_triangles; i++) {
+ if(tri_has_true_disp[i]) {
+ for(size_t j = 0; j < 3; j++) {
+ int vert = mesh->get_triangle(i).v[j];
+
+ if(done[vert]) {
+ continue;
+ }
+
+ vN[vert] = normalize(vN[vert]);
+ if(flip)
+ vN[vert] = -vN[vert];
+
+ done[vert] = true;
+ }
+ }
+ }
+
+ /* motion vertex normals */
+ Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL);
+
+ if(mesh->has_motion_blur() && attr_mP && attr_mN) {
+ for(int step = 0; step < mesh->motion_steps - 1; step++) {
+ float3 *mP = attr_mP->data_float3() + step*mesh->verts.size();
+ float3 *mN = attr_mN->data_float3() + step*mesh->verts.size();
+
+ /* compute */
+
+ /* zero vertex normals on triangles with true displacement */
+ for(size_t i = 0; i < num_triangles; i++) {
+ if(tri_has_true_disp[i]) {
+ for(size_t j = 0; j < 3; j++) {
+ mN[mesh->get_triangle(i).v[j]] = make_float3(0.0f, 0.0f, 0.0f);
+ }
+ }
+ }
+
+ /* add face normals to vertex normals */
+ for(size_t i = 0; i < num_triangles; i++) {
+ if(tri_has_true_disp[i]) {
+ for(size_t j = 0; j < 3; j++) {
+ float3 fN = compute_face_normal(mesh->get_triangle(i), mP);
+ mN[mesh->get_triangle(i).v[j]] += fN;
+ }
+ }
+ }
+
+ /* normalize vertex normals */
+ done.clear();
+ done.resize(num_verts, false);
+
+ for(size_t i = 0; i < num_triangles; i++) {
+ if(tri_has_true_disp[i]) {
+ for(size_t j = 0; j < 3; j++) {
+ int vert = mesh->get_triangle(i).v[j];
+
+ if(done[vert]) {
+ continue;
+ }
+
+ mN[vert] = normalize(mN[vert]);
+ if(flip)
+ mN[vert] = -mN[vert];
+
+ done[vert] = true;
+ }
+ }
+ }
+ }
+ }
}
return true;
diff --git a/intern/cycles/render/mesh_subdivision.cpp b/intern/cycles/render/mesh_subdivision.cpp
new file mode 100644
index 00000000000..913c3c74b42
--- /dev/null
+++ b/intern/cycles/render/mesh_subdivision.cpp
@@ -0,0 +1,612 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mesh.h"
+#include "attribute.h"
+#include "camera.h"
+
+#include "subd_split.h"
+#include "subd_patch.h"
+#include "subd_patch_table.h"
+
+#include "util_foreach.h"
+#include "util_algorithm.h"
+
+CCL_NAMESPACE_BEGIN
+
+#ifdef WITH_OPENSUBDIV
+
+CCL_NAMESPACE_END
+
+#include <opensubdiv/far/topologyRefinerFactory.h>
+#include <opensubdiv/far/primvarRefiner.h>
+#include <opensubdiv/far/patchTableFactory.h>
+#include <opensubdiv/far/patchMap.h>
+
+/* specializations of TopologyRefinerFactory for ccl::Mesh */
+
+namespace OpenSubdiv {
+namespace OPENSUBDIV_VERSION {
+namespace Far {
+ template<>
+ bool TopologyRefinerFactory<ccl::Mesh>::resizeComponentTopology(TopologyRefiner& refiner, ccl::Mesh const& mesh)
+ {
+ setNumBaseVertices(refiner, mesh.verts.size());
+ setNumBaseFaces(refiner, mesh.subd_faces.size());
+
+ const ccl::Mesh::SubdFace* face = mesh.subd_faces.data();
+
+ for(int i = 0; i < mesh.subd_faces.size(); i++, face++) {
+ setNumBaseFaceVertices(refiner, i, face->num_corners);
+ }
+
+ return true;
+ }
+
+ template<>
+ bool TopologyRefinerFactory<ccl::Mesh>::assignComponentTopology(TopologyRefiner& refiner, ccl::Mesh const& mesh)
+ {
+ const ccl::Mesh::SubdFace* face = mesh.subd_faces.data();
+
+ for(int i = 0; i < mesh.subd_faces.size(); i++, face++) {
+ IndexArray face_verts = getBaseFaceVertices(refiner, i);
+
+ int* corner = &mesh.subd_face_corners[face->start_corner];
+
+ for(int j = 0; j < face->num_corners; j++, corner++) {
+ face_verts[j] = *corner;
+ }
+ }
+
+ return true;
+ }
+
+ template<>
+ bool TopologyRefinerFactory<ccl::Mesh>::assignComponentTags(TopologyRefiner& refiner, ccl::Mesh const& mesh)
+ {
+ const ccl::Mesh::SubdEdgeCrease* crease = mesh.subd_creases.data();
+
+ for(int i = 0; i < mesh.subd_creases.size(); i++, crease++) {
+ Index edge = findBaseEdge(refiner, crease->v[0], crease->v[1]);
+
+ if(edge != INDEX_INVALID) {
+ setBaseEdgeSharpness(refiner, edge, crease->crease * 10.0f);
+ }
+ }
+
+ for(int i = 0; i < mesh.verts.size(); i++) {
+ ConstIndexArray vert_edges = getBaseVertexEdges(refiner, i);
+
+ if(vert_edges.size() == 2) {
+ float sharpness = refiner.getLevel(0).getEdgeSharpness(vert_edges[0]);
+ sharpness = min(sharpness, refiner.getLevel(0).getEdgeSharpness(vert_edges[1]));
+
+ setBaseVertexSharpness(refiner, i, sharpness);
+ }
+ }
+
+ return true;
+ }
+
+ template<>
+ bool TopologyRefinerFactory<ccl::Mesh>::assignFaceVaryingTopology(TopologyRefiner& /*refiner*/, ccl::Mesh const& /*mesh*/)
+ {
+ return true;
+ }
+
+ template<>
+ void TopologyRefinerFactory<ccl::Mesh>::reportInvalidTopology(TopologyError /*err_code*/,
+ char const * /*msg*/, ccl::Mesh const& /*mesh*/)
+ {
+ }
+} /* namespace Far */
+} /* namespace OPENSUBDIV_VERSION */
+} /* namespace OpenSubdiv */
+
+CCL_NAMESPACE_BEGIN
+
+using namespace OpenSubdiv;
+
+/* struct that implements OpenSubdiv's vertex interface */
+
+template<typename T>
+struct OsdValue {
+ T value;
+
+ OsdValue() {}
+
+ void Clear(void* = 0) {
+ memset(&value, 0, sizeof(T));
+ }
+
+ void AddWithWeight(OsdValue<T> const& src, float weight) {
+ value += src.value * weight;
+ }
+};
+
+template<>
+void OsdValue<uchar4>::AddWithWeight(OsdValue<uchar4> const& src, float weight)
+{
+ for(int i = 0; i < 4; i++) {
+ value[i] += (uchar)(src.value[i] * weight);
+ }
+}
+
+/* class for holding OpenSubdiv data used during tessellation */
+
+class OsdData {
+ Mesh* mesh;
+ vector<OsdValue<float3> > verts;
+ Far::TopologyRefiner* refiner;
+ Far::PatchTable* patch_table;
+ Far::PatchMap* patch_map;
+
+public:
+ OsdData() : mesh(NULL), refiner(NULL), patch_table(NULL), patch_map(NULL) {}
+
+ ~OsdData()
+ {
+ delete refiner;
+ delete patch_table;
+ delete patch_map;
+ }
+
+ void build_from_mesh(Mesh* mesh_)
+ {
+ mesh = mesh_;
+
+ /* type and options */
+ Sdc::SchemeType type = Sdc::SCHEME_CATMARK;
+
+ Sdc::Options options;
+ options.SetVtxBoundaryInterpolation(Sdc::Options::VTX_BOUNDARY_EDGE_ONLY);
+
+ /* create refiner */
+ refiner = Far::TopologyRefinerFactory<Mesh>::Create(*mesh,
+ Far::TopologyRefinerFactory<Mesh>::Options(type, options));
+
+ /* adaptive refinement */
+ int max_isolation = calculate_max_isolation();
+ refiner->RefineAdaptive(Far::TopologyRefiner::AdaptiveOptions(max_isolation));
+
+ /* create patch table */
+ Far::PatchTableFactory::Options patch_options;
+ patch_options.endCapType = Far::PatchTableFactory::Options::ENDCAP_GREGORY_BASIS;
+
+ patch_table = Far::PatchTableFactory::Create(*refiner, patch_options);
+
+ /* interpolate verts */
+ int num_refiner_verts = refiner->GetNumVerticesTotal();
+ int num_local_points = patch_table->GetNumLocalPoints();
+
+ verts.resize(num_refiner_verts + num_local_points);
+ for(int i = 0; i < mesh->verts.size(); i++) {
+ verts[i].value = mesh->verts[i];
+ }
+
+ OsdValue<float3>* src = verts.data();
+ for(int i = 0; i < refiner->GetMaxLevel(); i++) {
+ OsdValue<float3>* dest = src + refiner->GetLevel(i).GetNumVertices();
+ Far::PrimvarRefiner(*refiner).Interpolate(i+1, src, dest);
+ src = dest;
+ }
+
+ patch_table->ComputeLocalPointValues(&verts[0], &verts[num_refiner_verts]);
+
+ /* create patch map */
+ patch_map = new Far::PatchMap(*patch_table);
+ }
+
+ void subdivide_attribute(Attribute& attr)
+ {
+ Far::PrimvarRefiner primvar_refiner(*refiner);
+
+ if(attr.element == ATTR_ELEMENT_VERTEX) {
+ int num_refiner_verts = refiner->GetNumVerticesTotal();
+ int num_local_points = patch_table->GetNumLocalPoints();
+
+ attr.resize(num_refiner_verts + num_local_points);
+ attr.flags |= ATTR_FINAL_SIZE;
+
+ char* src = attr.buffer.data();
+
+ for(int i = 0; i < refiner->GetMaxLevel(); i++) {
+ char* dest = src + refiner->GetLevel(i).GetNumVertices() * attr.data_sizeof();
+
+ if(attr.same_storage(attr.type, TypeDesc::TypeFloat)) {
+ primvar_refiner.Interpolate(i+1, (OsdValue<float>*)src, (OsdValue<float>*&)dest);
+ }
+ else {
+ primvar_refiner.Interpolate(i+1, (OsdValue<float4>*)src, (OsdValue<float4>*&)dest);
+ }
+
+ src = dest;
+ }
+
+ if(attr.same_storage(attr.type, TypeDesc::TypeFloat)) {
+ patch_table->ComputeLocalPointValues((OsdValue<float>*)&attr.buffer[0],
+ (OsdValue<float>*)&attr.buffer[num_refiner_verts * attr.data_sizeof()]);
+ }
+ else {
+ patch_table->ComputeLocalPointValues((OsdValue<float4>*)&attr.buffer[0],
+ (OsdValue<float4>*)&attr.buffer[num_refiner_verts * attr.data_sizeof()]);
+ }
+ }
+ else if(attr.element == ATTR_ELEMENT_CORNER || attr.element == ATTR_ELEMENT_CORNER_BYTE) {
+ // TODO(mai): fvar interpolation
+ }
+ }
+
+ int calculate_max_isolation()
+ {
+ /* loop over all edges to find longest in screen space */
+ const Far::TopologyLevel& level = refiner->GetLevel(0);
+ Transform objecttoworld = mesh->subd_params->objecttoworld;
+ Camera* cam = mesh->subd_params->camera;
+
+ float longest_edge = 0.0f;
+
+ for(size_t i = 0; i < level.GetNumEdges(); i++) {
+ Far::ConstIndexArray verts = level.GetEdgeVertices(i);
+
+ float3 a = mesh->verts[verts[0]];
+ float3 b = mesh->verts[verts[1]];
+
+ float edge_len;
+
+ if(cam) {
+ a = transform_point(&objecttoworld, a);
+ b = transform_point(&objecttoworld, b);
+
+ edge_len = len(a - b) / cam->world_to_raster_size((a + b) * 0.5f);
+ }
+ else {
+ edge_len = len(a - b);
+ }
+
+ longest_edge = max(longest_edge, edge_len);
+ }
+
+ /* calculate isolation level */
+ int isolation = (int)(log2f(max(longest_edge / mesh->subd_params->dicing_rate, 1.0f)) + 1.0f);
+
+ return min(isolation, 10);
+ }
+
+ friend struct OsdPatch;
+ friend class Mesh;
+};
+
+/* ccl::Patch implementation that uses OpenSubdiv for eval */
+
+struct OsdPatch : Patch {
+ OsdData* osd_data;
+
+ OsdPatch(OsdData* data) : osd_data(data) {}
+
+ void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v)
+ {
+ const Far::PatchTable::PatchHandle* handle = osd_data->patch_map->FindPatch(patch_index, u, v);
+ assert(handle);
+
+ float p_weights[20], du_weights[20], dv_weights[20];
+ osd_data->patch_table->EvaluateBasis(*handle, u, v, p_weights, du_weights, dv_weights);
+
+ Far::ConstIndexArray cv = osd_data->patch_table->GetPatchVertices(*handle);
+
+ float3 du, dv;
+ if(P) *P = make_float3(0.0f, 0.0f, 0.0f);
+ du = make_float3(0.0f, 0.0f, 0.0f);
+ dv = make_float3(0.0f, 0.0f, 0.0f);
+
+ for(int i = 0; i < cv.size(); i++) {
+ float3 p = osd_data->verts[cv[i]].value;
+
+ if(P) *P += p * p_weights[i];
+ du += p * du_weights[i];
+ dv += p * dv_weights[i];
+ }
+
+ if(dPdu) *dPdu = du;
+ if(dPdv) *dPdv = dv;
+ if(N) {
+ *N = cross(du, dv);
+
+ float t = len(*N);
+ *N = (t != 0.0f) ? *N/t : make_float3(0.0f, 0.0f, 1.0f);
+ }
+ }
+
+ BoundBox bound() { return BoundBox::empty; }
+};
+
+#endif
+
+void Mesh::tessellate(DiagSplit *split)
+{
+#ifdef WITH_OPENSUBDIV
+ OsdData osd_data;
+ bool need_packed_patch_table = false;
+
+ if(subdivision_type == SUBDIVISION_CATMULL_CLARK) {
+ if(subd_faces.size()) {
+ osd_data.build_from_mesh(this);
+ }
+ }
+ else
+#endif
+ {
+ /* force linear subdivision if OpenSubdiv is unavailable to avoid
+ * falling into catmull-clark code paths by accident
+ */
+ subdivision_type = SUBDIVISION_LINEAR;
+
+ /* force disable attribute subdivision for same reason as above */
+ foreach(Attribute& attr, subd_attributes.attributes) {
+ attr.flags &= ~ATTR_SUBDIVIDED;
+ }
+ }
+
+ int num_faces = subd_faces.size();
+
+ Attribute *attr_vN = subd_attributes.find(ATTR_STD_VERTEX_NORMAL);
+ float3* vN = attr_vN->data_float3();
+
+ for(int f = 0; f < num_faces; f++) {
+ SubdFace& face = subd_faces[f];
+
+ if(face.is_quad()) {
+ /* quad */
+ QuadDice::SubPatch subpatch;
+
+ LinearQuadPatch quad_patch;
+#ifdef WITH_OPENSUBDIV
+ OsdPatch osd_patch(&osd_data);
+
+ if(subdivision_type == SUBDIVISION_CATMULL_CLARK) {
+ osd_patch.patch_index = face.ptex_offset;
+
+ subpatch.patch = &osd_patch;
+ }
+ else
+#endif
+ {
+ float3 *hull = quad_patch.hull;
+ float3 *normals = quad_patch.normals;
+
+ quad_patch.patch_index = face.ptex_offset;
+
+ for(int i = 0; i < 4; i++) {
+ hull[i] = verts[subd_face_corners[face.start_corner+i]];
+ }
+
+ if(face.smooth) {
+ for(int i = 0; i < 4; i++) {
+ normals[i] = vN[subd_face_corners[face.start_corner+i]];
+ }
+ }
+ else {
+ float3 N = face.normal(this);
+ for(int i = 0; i < 4; i++) {
+ normals[i] = N;
+ }
+ }
+
+ swap(hull[2], hull[3]);
+ swap(normals[2], normals[3]);
+
+ subpatch.patch = &quad_patch;
+ }
+
+ subpatch.patch->shader = face.shader;
+
+ /* Quad faces need to be split at least once to line up with split ngons, we do this
+ * here in this manner because if we do it later edge factors may end up slightly off.
+ */
+ subpatch.P00 = make_float2(0.0f, 0.0f);
+ subpatch.P10 = make_float2(0.5f, 0.0f);
+ subpatch.P01 = make_float2(0.0f, 0.5f);
+ subpatch.P11 = make_float2(0.5f, 0.5f);
+ split->split_quad(subpatch.patch, &subpatch);
+
+ subpatch.P00 = make_float2(0.5f, 0.0f);
+ subpatch.P10 = make_float2(1.0f, 0.0f);
+ subpatch.P01 = make_float2(0.5f, 0.5f);
+ subpatch.P11 = make_float2(1.0f, 0.5f);
+ split->split_quad(subpatch.patch, &subpatch);
+
+ subpatch.P00 = make_float2(0.0f, 0.5f);
+ subpatch.P10 = make_float2(0.5f, 0.5f);
+ subpatch.P01 = make_float2(0.0f, 1.0f);
+ subpatch.P11 = make_float2(0.5f, 1.0f);
+ split->split_quad(subpatch.patch, &subpatch);
+
+ subpatch.P00 = make_float2(0.5f, 0.5f);
+ subpatch.P10 = make_float2(1.0f, 0.5f);
+ subpatch.P01 = make_float2(0.5f, 1.0f);
+ subpatch.P11 = make_float2(1.0f, 1.0f);
+ split->split_quad(subpatch.patch, &subpatch);
+ }
+ else {
+ /* ngon */
+#ifdef WITH_OPENSUBDIV
+ if(subdivision_type == SUBDIVISION_CATMULL_CLARK) {
+ OsdPatch patch(&osd_data);
+
+ patch.shader = face.shader;
+
+ for(int corner = 0; corner < face.num_corners; corner++) {
+ patch.patch_index = face.ptex_offset + corner;
+
+ split->split_quad(&patch);
+ }
+ }
+ else
+#endif
+ {
+ float3 center_vert = make_float3(0.0f, 0.0f, 0.0f);
+ float3 center_normal = make_float3(0.0f, 0.0f, 0.0f);
+
+ float inv_num_corners = 1.0f/float(face.num_corners);
+ for(int corner = 0; corner < face.num_corners; corner++) {
+ center_vert += verts[subd_face_corners[face.start_corner + corner]] * inv_num_corners;
+ center_normal += vN[subd_face_corners[face.start_corner + corner]] * inv_num_corners;
+ }
+
+ for(int corner = 0; corner < face.num_corners; corner++) {
+ LinearQuadPatch patch;
+ float3 *hull = patch.hull;
+ float3 *normals = patch.normals;
+
+ patch.patch_index = face.ptex_offset + corner;
+
+ patch.shader = face.shader;
+
+ hull[0] = verts[subd_face_corners[face.start_corner + mod(corner + 0, face.num_corners)]];
+ hull[1] = verts[subd_face_corners[face.start_corner + mod(corner + 1, face.num_corners)]];
+ hull[2] = verts[subd_face_corners[face.start_corner + mod(corner - 1, face.num_corners)]];
+ hull[3] = center_vert;
+
+ hull[1] = (hull[1] + hull[0]) * 0.5;
+ hull[2] = (hull[2] + hull[0]) * 0.5;
+
+ if(face.smooth) {
+ normals[0] = vN[subd_face_corners[face.start_corner + mod(corner + 0, face.num_corners)]];
+ normals[1] = vN[subd_face_corners[face.start_corner + mod(corner + 1, face.num_corners)]];
+ normals[2] = vN[subd_face_corners[face.start_corner + mod(corner - 1, face.num_corners)]];
+ normals[3] = center_normal;
+
+ normals[1] = (normals[1] + normals[0]) * 0.5;
+ normals[2] = (normals[2] + normals[0]) * 0.5;
+ }
+ else {
+ float3 N = face.normal(this);
+ for(int i = 0; i < 4; i++) {
+ normals[i] = N;
+ }
+ }
+
+ split->split_quad(&patch);
+ }
+ }
+ }
+ }
+
+ /* interpolate center points for attributes */
+ foreach(Attribute& attr, subd_attributes.attributes) {
+#ifdef WITH_OPENSUBDIV
+ if(subdivision_type == SUBDIVISION_CATMULL_CLARK && attr.flags & ATTR_SUBDIVIDED) {
+ if(attr.element == ATTR_ELEMENT_CORNER || attr.element == ATTR_ELEMENT_CORNER_BYTE) {
+ /* keep subdivision for corner attributes disabled for now */
+ attr.flags &= ~ATTR_SUBDIVIDED;
+ }
+ else if(subd_faces.size()) {
+ osd_data.subdivide_attribute(attr);
+
+ need_packed_patch_table = true;
+ continue;
+ }
+ }
+#endif
+
+ char* data = attr.data();
+ size_t stride = attr.data_sizeof();
+ int ngons = 0;
+
+ switch(attr.element) {
+ case ATTR_ELEMENT_VERTEX: {
+ for(int f = 0; f < num_faces; f++) {
+ SubdFace& face = subd_faces[f];
+
+ if(!face.is_quad()) {
+ char* center = data + (verts.size() - num_subd_verts + ngons) * stride;
+ attr.zero_data(center);
+
+ float inv_num_corners = 1.0f / float(face.num_corners);
+
+ for(int corner = 0; corner < face.num_corners; corner++) {
+ attr.add_with_weight(center,
+ data + subd_face_corners[face.start_corner + corner] * stride,
+ inv_num_corners);
+ }
+
+ ngons++;
+ }
+ }
+ } break;
+ case ATTR_ELEMENT_VERTEX_MOTION: {
+ // TODO(mai): implement
+ } break;
+ case ATTR_ELEMENT_CORNER: {
+ for(int f = 0; f < num_faces; f++) {
+ SubdFace& face = subd_faces[f];
+
+ if(!face.is_quad()) {
+ char* center = data + (subd_face_corners.size() + ngons) * stride;
+ attr.zero_data(center);
+
+ float inv_num_corners = 1.0f / float(face.num_corners);
+
+ for(int corner = 0; corner < face.num_corners; corner++) {
+ attr.add_with_weight(center,
+ data + (face.start_corner + corner) * stride,
+ inv_num_corners);
+ }
+
+ ngons++;
+ }
+ }
+ } break;
+ case ATTR_ELEMENT_CORNER_BYTE: {
+ for(int f = 0; f < num_faces; f++) {
+ SubdFace& face = subd_faces[f];
+
+ if(!face.is_quad()) {
+ uchar* center = (uchar*)data + (subd_face_corners.size() + ngons) * stride;
+
+ float inv_num_corners = 1.0f / float(face.num_corners);
+ float4 val = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+
+ for(int corner = 0; corner < face.num_corners; corner++) {
+ for(int i = 0; i < 4; i++) {
+ val[i] += float(*(data + (face.start_corner + corner) * stride + i)) * inv_num_corners;
+ }
+ }
+
+ for(int i = 0; i < 4; i++) {
+ center[i] = uchar(min(max(val[i], 0.0f), 255.0f));
+ }
+
+ ngons++;
+ }
+ }
+ } break;
+ default: break;
+ }
+ }
+
+#ifdef WITH_OPENSUBDIV
+ /* pack patch tables */
+ if(need_packed_patch_table) {
+ delete patch_table;
+ patch_table = new PackedPatchTable;
+ patch_table->pack(osd_data.patch_table);
+ }
+#endif
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index cd85773b4cf..790547ea567 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -19,8 +19,11 @@
#include "nodes.h"
#include "scene.h"
#include "svm.h"
+#include "svm_color_util.h"
+#include "svm_ramp_util.h"
#include "svm_math_util.h"
#include "osl.h"
+#include "constant_fold.h"
#include "volume.h"
#include "util_sky_model.h"
@@ -31,24 +34,40 @@ CCL_NAMESPACE_BEGIN
/* Texture Mapping */
+#define TEXTURE_MAPPING_DEFINE(TextureNode) \
+ SOCKET_POINT(tex_mapping.translation, "Translation", make_float3(0.0f, 0.0f, 0.0f)); \
+ SOCKET_VECTOR(tex_mapping.rotation, "Rotation", make_float3(0.0f, 0.0f, 0.0f)); \
+ SOCKET_VECTOR(tex_mapping.scale, "Scale", make_float3(1.0f, 1.0f, 1.0f)); \
+ \
+ SOCKET_VECTOR(tex_mapping.min, "Min", make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX)); \
+ SOCKET_VECTOR(tex_mapping.max, "Max", make_float3(FLT_MAX, FLT_MAX, FLT_MAX)); \
+ SOCKET_BOOLEAN(tex_mapping.use_minmax, "Use Min Max", false); \
+ \
+ static NodeEnum mapping_axis_enum; \
+ mapping_axis_enum.insert("none", TextureMapping::NONE); \
+ mapping_axis_enum.insert("x", TextureMapping::X); \
+ mapping_axis_enum.insert("y", TextureMapping::Y); \
+ mapping_axis_enum.insert("z", TextureMapping::Z); \
+ SOCKET_ENUM(tex_mapping.x_mapping, "x_mapping", mapping_axis_enum, TextureMapping::X); \
+ SOCKET_ENUM(tex_mapping.y_mapping, "y_mapping", mapping_axis_enum, TextureMapping::Y); \
+ SOCKET_ENUM(tex_mapping.z_mapping, "z_mapping", mapping_axis_enum, TextureMapping::Z); \
+ \
+ static NodeEnum mapping_type_enum; \
+ mapping_type_enum.insert("point", TextureMapping::POINT); \
+ mapping_type_enum.insert("texture", TextureMapping::TEXTURE); \
+ mapping_type_enum.insert("vector", TextureMapping::VECTOR); \
+ mapping_type_enum.insert("normal", TextureMapping::NORMAL); \
+ SOCKET_ENUM(tex_mapping.type, "Type", mapping_type_enum, TextureMapping::TEXTURE); \
+ \
+ static NodeEnum mapping_projection_enum; \
+ mapping_projection_enum.insert("flat", TextureMapping::FLAT); \
+ mapping_projection_enum.insert("cube", TextureMapping::CUBE); \
+ mapping_projection_enum.insert("tube", TextureMapping::TUBE); \
+ mapping_projection_enum.insert("sphere", TextureMapping::SPHERE); \
+ SOCKET_ENUM(tex_mapping.projection, "Projection", mapping_projection_enum, TextureMapping::FLAT);
+
TextureMapping::TextureMapping()
{
- translation = make_float3(0.0f, 0.0f, 0.0f);
- rotation = make_float3(0.0f, 0.0f, 0.0f);
- scale = make_float3(1.0f, 1.0f, 1.0f);
-
- min = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
- max = make_float3(FLT_MAX, FLT_MAX, FLT_MAX);
-
- use_minmax = false;
-
- x_mapping = X;
- y_mapping = Y;
- z_mapping = Z;
-
- type = TEXTURE;
-
- projection = FLAT;
}
Transform TextureMapping::compute_transform()
@@ -154,7 +173,7 @@ int TextureMapping::compile_begin(SVMCompiler& compiler, ShaderInput *vector_in)
{
if(!skip()) {
int offset_in = compiler.stack_assign(vector_in);
- int offset_out = compiler.stack_find_offset(SHADER_SOCKET_VECTOR);
+ int offset_out = compiler.stack_find_offset(SocketType::VECTOR);
compile(compiler, offset_in, offset_out);
@@ -167,7 +186,7 @@ int TextureMapping::compile_begin(SVMCompiler& compiler, ShaderInput *vector_in)
void TextureMapping::compile_end(SVMCompiler& compiler, ShaderInput *vector_in, int vector_offset)
{
if(!skip()) {
- compiler.stack_clear_offset(vector_in->type, vector_offset);
+ compiler.stack_clear_offset(vector_in->type(), vector_offset);
}
}
@@ -183,72 +202,66 @@ void TextureMapping::compile(OSLCompiler &compiler)
/* Image Texture */
-static ShaderEnum color_space_init()
+NODE_DEFINE(ImageTextureNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("image_texture", create, NodeType::SHADER);
- enm.insert("None", 0);
- enm.insert("Color", 1);
+ TEXTURE_MAPPING_DEFINE(ImageTextureNode);
- return enm;
-}
+ SOCKET_STRING(filename, "Filename", ustring(""));
-static ShaderEnum image_projection_init()
-{
- ShaderEnum enm;
+ static NodeEnum color_space_enum;
+ color_space_enum.insert("none", NODE_COLOR_SPACE_NONE);
+ color_space_enum.insert("color", NODE_COLOR_SPACE_COLOR);
+ SOCKET_ENUM(color_space, "Color Space", color_space_enum, NODE_COLOR_SPACE_COLOR);
- enm.insert("Flat", NODE_IMAGE_PROJ_FLAT);
- enm.insert("Box", NODE_IMAGE_PROJ_BOX);
- enm.insert("Sphere", NODE_IMAGE_PROJ_SPHERE);
- enm.insert("Tube", NODE_IMAGE_PROJ_TUBE);
+ SOCKET_BOOLEAN(use_alpha, "Use Alpha", true);
- return enm;
-}
+ static NodeEnum interpolation_enum;
+ interpolation_enum.insert("closest", INTERPOLATION_CLOSEST);
+ interpolation_enum.insert("linear", INTERPOLATION_LINEAR);
+ interpolation_enum.insert("cubic", INTERPOLATION_CUBIC);
+ interpolation_enum.insert("smart", INTERPOLATION_SMART);
+ SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR);
-static const char* get_osl_interpolation_parameter(InterpolationType interpolation)
-{
- switch(interpolation) {
- case INTERPOLATION_CLOSEST:
- return "closest";
- case INTERPOLATION_CUBIC:
- return "cubic";
- case INTERPOLATION_SMART:
- return "smart";
- case INTERPOLATION_LINEAR:
- default:
- return "linear";
- }
-}
+ static NodeEnum extension_enum;
+ extension_enum.insert("periodic", EXTENSION_REPEAT);
+ extension_enum.insert("clamp", EXTENSION_EXTEND);
+ extension_enum.insert("black", EXTENSION_CLIP);
+ SOCKET_ENUM(extension, "Extension", extension_enum, EXTENSION_REPEAT);
-ShaderEnum ImageTextureNode::color_space_enum = color_space_init();
-ShaderEnum ImageTextureNode::projection_enum = image_projection_init();
+ static NodeEnum projection_enum;
+ projection_enum.insert("flat", NODE_IMAGE_PROJ_FLAT);
+ projection_enum.insert("box", NODE_IMAGE_PROJ_BOX);
+ projection_enum.insert("sphere", NODE_IMAGE_PROJ_SPHERE);
+ projection_enum.insert("tube", NODE_IMAGE_PROJ_TUBE);
+ SOCKET_ENUM(projection, "Projection", projection_enum, NODE_IMAGE_PROJ_FLAT);
+
+ SOCKET_FLOAT(projection_blend, "Projection Blend", 0.0f);
+
+ SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_UV);
+
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(alpha, "Alpha");
+
+ return type;
+}
ImageTextureNode::ImageTextureNode()
-: ImageSlotTextureNode("image_texture")
+: ImageSlotTextureNode(node_type)
{
image_manager = NULL;
slot = -1;
is_float = -1;
is_linear = false;
- use_alpha = true;
- filename = "";
builtin_data = NULL;
- color_space = ustring("Color");
- projection = ustring("Flat");
- interpolation = INTERPOLATION_LINEAR;
- extension = EXTENSION_REPEAT;
- projection_blend = 0.0f;
animated = false;
-
- add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_UV);
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Alpha", SHADER_SOCKET_FLOAT);
}
ImageTextureNode::~ImageTextureNode()
{
if(image_manager) {
- image_manager->remove_image(filename,
+ image_manager->remove_image(filename.string(),
builtin_data,
interpolation,
extension);
@@ -289,7 +302,7 @@ void ImageTextureNode::compile(SVMCompiler& compiler)
image_manager = compiler.image_manager;
if(is_float == -1) {
bool is_float_bool;
- slot = image_manager->add_image(filename,
+ slot = image_manager->add_image(filename.string(),
builtin_data,
animated,
0,
@@ -302,10 +315,10 @@ void ImageTextureNode::compile(SVMCompiler& compiler)
}
if(slot != -1) {
- int srgb = (is_linear || color_space != "Color")? 0: 1;
+ int srgb = (is_linear || color_space != NODE_COLOR_SPACE_COLOR)? 0: 1;
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
- if(projection != "Box") {
+ if(projection != NODE_IMAGE_PROJ_BOX) {
compiler.add_node(NODE_TEX_IMAGE,
slot,
compiler.encode_uchar4(
@@ -313,7 +326,7 @@ void ImageTextureNode::compile(SVMCompiler& compiler)
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(alpha_out),
srgb),
- projection_enum[projection]);
+ projection);
}
else {
compiler.add_node(NODE_TEX_IMAGE_BOX,
@@ -350,11 +363,14 @@ void ImageTextureNode::compile(OSLCompiler& compiler)
image_manager = compiler.image_manager;
if(is_float == -1) {
if(builtin_data == NULL) {
- is_float = (int)image_manager->is_float_image(filename, NULL, is_linear);
+ ImageManager::ImageDataType type;
+ type = image_manager->get_image_metadata(filename.string(), NULL, is_linear);
+ if(type == ImageManager::IMAGE_DATA_TYPE_FLOAT || type == ImageManager::IMAGE_DATA_TYPE_FLOAT4)
+ is_float = 1;
}
else {
bool is_float_bool;
- slot = image_manager->add_image(filename,
+ slot = image_manager->add_image(filename.string(),
builtin_data,
animated,
0,
@@ -368,7 +384,7 @@ void ImageTextureNode::compile(OSLCompiler& compiler)
}
if(slot == -1) {
- compiler.parameter("filename", filename.c_str());
+ compiler.parameter(this, "filename");
}
else {
/* TODO(sergey): It's not so simple to pass custom attribute
@@ -379,71 +395,72 @@ void ImageTextureNode::compile(OSLCompiler& compiler)
*/
compiler.parameter("filename", string_printf("@%d", slot).c_str());
}
- if(is_linear || color_space != "Color")
- compiler.parameter("color_space", "Linear");
+ if(is_linear || color_space != NODE_COLOR_SPACE_COLOR)
+ compiler.parameter("color_space", "linear");
else
compiler.parameter("color_space", "sRGB");
- compiler.parameter("projection", projection);
- compiler.parameter("projection_blend", projection_blend);
+ compiler.parameter(this, "projection");
+ compiler.parameter(this, "projection_blend");
compiler.parameter("is_float", is_float);
compiler.parameter("use_alpha", !alpha_out->links.empty());
- compiler.parameter("interpolation", get_osl_interpolation_parameter(interpolation));
-
- switch(extension) {
- case EXTENSION_EXTEND:
- compiler.parameter("wrap", "clamp");
- break;
- case EXTENSION_CLIP:
- compiler.parameter("wrap", "black");
- break;
- case EXTENSION_REPEAT:
- default:
- compiler.parameter("wrap", "periodic");
- break;
- }
+ compiler.parameter(this, "interpolation");
+ compiler.parameter(this, "extension");
compiler.add(this, "node_image_texture");
}
/* Environment Texture */
-static ShaderEnum env_projection_init()
+NODE_DEFINE(EnvironmentTextureNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("environment_texture", create, NodeType::SHADER);
- enm.insert("Equirectangular", 0);
- enm.insert("Mirror Ball", 1);
+ TEXTURE_MAPPING_DEFINE(EnvironmentTextureNode);
- return enm;
-}
+ SOCKET_STRING(filename, "Filename", ustring(""));
+
+ static NodeEnum color_space_enum;
+ color_space_enum.insert("none", NODE_COLOR_SPACE_NONE);
+ color_space_enum.insert("color", NODE_COLOR_SPACE_COLOR);
+ SOCKET_ENUM(color_space, "Color Space", color_space_enum, NODE_COLOR_SPACE_COLOR);
+
+ SOCKET_BOOLEAN(use_alpha, "Use Alpha", true);
+
+ static NodeEnum interpolation_enum;
+ interpolation_enum.insert("closest", INTERPOLATION_CLOSEST);
+ interpolation_enum.insert("linear", INTERPOLATION_LINEAR);
+ interpolation_enum.insert("cubic", INTERPOLATION_CUBIC);
+ interpolation_enum.insert("smart", INTERPOLATION_SMART);
+ SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR);
+
+ static NodeEnum projection_enum;
+ projection_enum.insert("equirectangular", NODE_ENVIRONMENT_EQUIRECTANGULAR);
+ projection_enum.insert("mirror_ball", NODE_ENVIRONMENT_MIRROR_BALL);
+ SOCKET_ENUM(projection, "Projection", projection_enum, NODE_ENVIRONMENT_EQUIRECTANGULAR);
+
+ SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_POSITION);
-ShaderEnum EnvironmentTextureNode::color_space_enum = color_space_init();
-ShaderEnum EnvironmentTextureNode::projection_enum = env_projection_init();
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(alpha, "Alpha");
+
+ return type;
+}
EnvironmentTextureNode::EnvironmentTextureNode()
-: ImageSlotTextureNode("environment_texture")
+: ImageSlotTextureNode(node_type)
{
image_manager = NULL;
slot = -1;
is_float = -1;
is_linear = false;
- use_alpha = true;
- filename = "";
builtin_data = NULL;
- color_space = ustring("Color");
- interpolation = INTERPOLATION_LINEAR;
- projection = ustring("Equirectangular");
animated = false;
-
- add_input("Vector", SHADER_SOCKET_VECTOR, ShaderInput::POSITION);
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Alpha", SHADER_SOCKET_FLOAT);
}
EnvironmentTextureNode::~EnvironmentTextureNode()
{
if(image_manager) {
- image_manager->remove_image(filename,
+ image_manager->remove_image(filename.string(),
builtin_data,
interpolation,
EXTENSION_REPEAT);
@@ -482,7 +499,7 @@ void EnvironmentTextureNode::compile(SVMCompiler& compiler)
image_manager = compiler.image_manager;
if(slot == -1) {
bool is_float_bool;
- slot = image_manager->add_image(filename,
+ slot = image_manager->add_image(filename.string(),
builtin_data,
animated,
0,
@@ -495,7 +512,7 @@ void EnvironmentTextureNode::compile(SVMCompiler& compiler)
}
if(slot != -1) {
- int srgb = (is_linear || color_space != "Color")? 0: 1;
+ int srgb = (is_linear || color_space != NODE_COLOR_SPACE_COLOR)? 0: 1;
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
compiler.add_node(NODE_TEX_ENVIRONMENT,
@@ -505,7 +522,7 @@ void EnvironmentTextureNode::compile(SVMCompiler& compiler)
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(alpha_out),
srgb),
- projection_enum[projection]);
+ projection);
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
@@ -534,11 +551,14 @@ void EnvironmentTextureNode::compile(OSLCompiler& compiler)
image_manager = compiler.image_manager;
if(is_float == -1) {
if(builtin_data == NULL) {
- is_float = (int)image_manager->is_float_image(filename, NULL, is_linear);
+ ImageManager::ImageDataType type;
+ type = image_manager->get_image_metadata(filename.string(), NULL, is_linear);
+ if(type == ImageManager::IMAGE_DATA_TYPE_FLOAT || type == ImageManager::IMAGE_DATA_TYPE_FLOAT4)
+ is_float = 1;
}
else {
bool is_float_bool;
- slot = image_manager->add_image(filename,
+ slot = image_manager->add_image(filename.string(),
builtin_data,
animated,
0,
@@ -552,19 +572,18 @@ void EnvironmentTextureNode::compile(OSLCompiler& compiler)
}
if(slot == -1) {
- compiler.parameter("filename", filename.c_str());
+ compiler.parameter(this, "filename");
}
else {
compiler.parameter("filename", string_printf("@%d", slot).c_str());
}
- compiler.parameter("projection", projection);
- if(is_linear || color_space != "Color")
- compiler.parameter("color_space", "Linear");
+ compiler.parameter(this, "projection");
+ if(is_linear || color_space != NODE_COLOR_SPACE_COLOR)
+ compiler.parameter("color_space", "linear");
else
compiler.parameter("color_space", "sRGB");
- compiler.parameter("interpolation", get_osl_interpolation_parameter(interpolation));
-
+ compiler.parameter(this, "interpolation");
compiler.parameter("is_float", is_float);
compiler.parameter("use_alpha", !alpha_out->links.empty());
compiler.add(this, "node_environment_texture");
@@ -595,10 +614,10 @@ static float sky_perez_function(float lam[6], float theta, float gamma)
static void sky_texture_precompute_old(SunSky *sunsky, float3 dir, float turbidity)
{
/*
- * We re-use the SunSky struct of the new model, to avoid extra variables
- * zenith_Y/x/y is now radiance_x/y/z
- * perez_Y/x/y is now config_x/y/z
- */
+ * We re-use the SunSky struct of the new model, to avoid extra variables
+ * zenith_Y/x/y is now radiance_x/y/z
+ * perez_Y/x/y is now config_x/y/z
+ */
float2 spherical = sky_spherical_coordinates(dir);
float theta = spherical.x;
@@ -673,11 +692,11 @@ static void sky_texture_precompute_new(SunSky *sunsky, float3 dir, float turbidi
sunsky->theta = theta;
sunsky->phi = phi;
- double solarElevation = M_PI_2_F - theta;
+ float solarElevation = M_PI_2_F - theta;
/* Initialize Sky Model */
ArHosekSkyModelState *sky_state;
- sky_state = arhosek_xyz_skymodelstate_alloc_init(turbidity, ground_albedo, solarElevation);
+ sky_state = arhosek_xyz_skymodelstate_alloc_init((double)turbidity, (double)ground_albedo, (double)solarElevation);
/* Copy values from sky_state to SunSky */
for(int i = 0; i < 9; ++i) {
@@ -693,29 +712,31 @@ static void sky_texture_precompute_new(SunSky *sunsky, float3 dir, float turbidi
arhosekskymodelstate_free(sky_state);
}
-static ShaderEnum sky_type_init()
+NODE_DEFINE(SkyTextureNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("sky_texture", create, NodeType::SHADER);
- enm.insert("Preetham", NODE_SKY_OLD);
- enm.insert("Hosek / Wilkie", NODE_SKY_NEW);
+ TEXTURE_MAPPING_DEFINE(SkyTextureNode);
- return enm;
-}
+ static NodeEnum type_enum;
+ type_enum.insert("preetham", NODE_SKY_OLD);
+ type_enum.insert("hosek_wilkie", NODE_SKY_NEW);
+ SOCKET_ENUM(type, "Type", type_enum, NODE_SKY_NEW);
+
+ SOCKET_VECTOR(sun_direction, "Sun Direction", make_float3(0.0f, 0.0f, 1.0f));
+ SOCKET_FLOAT(turbidity, "Turbidity", 2.2f);
+ SOCKET_FLOAT(ground_albedo, "Ground Albedo", 0.3f);
+
+ SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
-ShaderEnum SkyTextureNode::type_enum = sky_type_init();
+ SOCKET_OUT_COLOR(color, "Color");
+
+ return type;
+}
SkyTextureNode::SkyTextureNode()
-: TextureNode("sky_texture")
+: TextureNode(node_type)
{
- type = ustring("Hosek / Wilkie");
-
- sun_direction = make_float3(0.0f, 0.0f, 1.0f);
- turbidity = 2.2f;
- ground_albedo = 0.3f;
-
- add_input("Vector", SHADER_SOCKET_VECTOR, ShaderInput::POSITION);
- add_output("Color", SHADER_SOCKET_COLOR);
}
void SkyTextureNode::compile(SVMCompiler& compiler)
@@ -724,18 +745,17 @@ void SkyTextureNode::compile(SVMCompiler& compiler)
ShaderOutput *color_out = output("Color");
SunSky sunsky;
- if(type_enum[type] == NODE_SKY_OLD)
+ if(type == NODE_SKY_OLD)
sky_texture_precompute_old(&sunsky, sun_direction, turbidity);
- else if(type_enum[type] == NODE_SKY_NEW)
+ else if(type == NODE_SKY_NEW)
sky_texture_precompute_new(&sunsky, sun_direction, turbidity, ground_albedo);
else
assert(false);
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
- int sky_model = type_enum[type];
compiler.stack_assign(color_out);
- compiler.add_node(NODE_TEX_SKY, vector_offset, compiler.stack_assign(color_out), sky_model);
+ compiler.add_node(NODE_TEX_SKY, vector_offset, compiler.stack_assign(color_out), type);
compiler.add_node(__float_as_uint(sunsky.phi), __float_as_uint(sunsky.theta), __float_as_uint(sunsky.radiance_x), __float_as_uint(sunsky.radiance_y));
compiler.add_node(__float_as_uint(sunsky.radiance_z), __float_as_uint(sunsky.config_x[0]), __float_as_uint(sunsky.config_x[1]), __float_as_uint(sunsky.config_x[2]));
compiler.add_node(__float_as_uint(sunsky.config_x[3]), __float_as_uint(sunsky.config_x[4]), __float_as_uint(sunsky.config_x[5]), __float_as_uint(sunsky.config_x[6]));
@@ -753,15 +773,14 @@ void SkyTextureNode::compile(OSLCompiler& compiler)
tex_mapping.compile(compiler);
SunSky sunsky;
-
- if(type_enum[type] == NODE_SKY_OLD)
+ if(type == NODE_SKY_OLD)
sky_texture_precompute_old(&sunsky, sun_direction, turbidity);
- else if(type_enum[type] == NODE_SKY_NEW)
+ else if(type == NODE_SKY_NEW)
sky_texture_precompute_new(&sunsky, sun_direction, turbidity, ground_albedo);
else
assert(false);
- compiler.parameter("sky_model", type);
+ compiler.parameter(this, "type");
compiler.parameter("theta", sunsky.theta);
compiler.parameter("phi", sunsky.phi);
compiler.parameter_color("radiance", make_float3(sunsky.radiance_x, sunsky.radiance_y, sunsky.radiance_z));
@@ -773,31 +792,33 @@ void SkyTextureNode::compile(OSLCompiler& compiler)
/* Gradient Texture */
-static ShaderEnum gradient_type_init()
+NODE_DEFINE(GradientTextureNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("gradient_texture", create, NodeType::SHADER);
- enm.insert("Linear", NODE_BLEND_LINEAR);
- enm.insert("Quadratic", NODE_BLEND_QUADRATIC);
- enm.insert("Easing", NODE_BLEND_EASING);
- enm.insert("Diagonal", NODE_BLEND_DIAGONAL);
- enm.insert("Radial", NODE_BLEND_RADIAL);
- enm.insert("Quadratic Sphere", NODE_BLEND_QUADRATIC_SPHERE);
- enm.insert("Spherical", NODE_BLEND_SPHERICAL);
+ TEXTURE_MAPPING_DEFINE(GradientTextureNode);
- return enm;
-}
+ static NodeEnum type_enum;
+ type_enum.insert("linear", NODE_BLEND_LINEAR);
+ type_enum.insert("quadratic", NODE_BLEND_QUADRATIC);
+ type_enum.insert("easing", NODE_BLEND_EASING);
+ type_enum.insert("diagonal", NODE_BLEND_DIAGONAL);
+ type_enum.insert("radial", NODE_BLEND_RADIAL);
+ type_enum.insert("quadratic_sphere", NODE_BLEND_QUADRATIC_SPHERE);
+ type_enum.insert("spherical", NODE_BLEND_SPHERICAL);
+ SOCKET_ENUM(type, "Type", type_enum, NODE_BLEND_LINEAR);
-ShaderEnum GradientTextureNode::type_enum = gradient_type_init();
+ SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
+
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(fac, "Fac");
+
+ return type;
+}
GradientTextureNode::GradientTextureNode()
-: TextureNode("gradient_texture")
+: TextureNode(node_type)
{
- type = ustring("Linear");
-
- add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Fac", SHADER_SOCKET_FLOAT);
}
void GradientTextureNode::compile(SVMCompiler& compiler)
@@ -810,7 +831,7 @@ void GradientTextureNode::compile(SVMCompiler& compiler)
compiler.add_node(NODE_TEX_GRADIENT,
compiler.encode_uchar4(
- type_enum[type],
+ type,
vector_offset,
compiler.stack_assign_if_linked(fac_out),
compiler.stack_assign_if_linked(color_out)));
@@ -822,22 +843,32 @@ void GradientTextureNode::compile(OSLCompiler& compiler)
{
tex_mapping.compile(compiler);
- compiler.parameter("Type", type);
+ compiler.parameter(this, "type");
compiler.add(this, "node_gradient_texture");
}
/* Noise Texture */
-NoiseTextureNode::NoiseTextureNode()
-: TextureNode("noise_texture")
+NODE_DEFINE(NoiseTextureNode)
{
- add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
- add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("Detail", SHADER_SOCKET_FLOAT, 2.0f);
- add_input("Distortion", SHADER_SOCKET_FLOAT, 0.0f);
+ NodeType* type = NodeType::add("noise_texture", create, NodeType::SHADER);
+
+ TEXTURE_MAPPING_DEFINE(NoiseTextureNode);
+
+ SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
+ SOCKET_IN_FLOAT(detail, "Detail", 2.0f);
+ SOCKET_IN_FLOAT(distortion, "Distortion", 0.0f);
+ SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
+
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(fac, "Fac");
+
+ return type;
+}
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Fac", SHADER_SOCKET_FLOAT);
+NoiseTextureNode::NoiseTextureNode()
+: TextureNode(node_type)
+{
}
void NoiseTextureNode::compile(SVMCompiler& compiler)
@@ -861,9 +892,9 @@ void NoiseTextureNode::compile(SVMCompiler& compiler)
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(fac_out)));
compiler.add_node(
- __float_as_int(scale_in->value.x),
- __float_as_int(detail_in->value.x),
- __float_as_int(distortion_in->value.x));
+ __float_as_int(scale),
+ __float_as_int(detail),
+ __float_as_int(distortion));
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
@@ -877,28 +908,29 @@ void NoiseTextureNode::compile(OSLCompiler& compiler)
/* Voronoi Texture */
-static ShaderEnum voronoi_coloring_init()
+NODE_DEFINE(VoronoiTextureNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("voronoi_texture", create, NodeType::SHADER);
- enm.insert("Intensity", NODE_VORONOI_INTENSITY);
- enm.insert("Cells", NODE_VORONOI_CELLS);
+ TEXTURE_MAPPING_DEFINE(VoronoiTextureNode);
- return enm;
-}
+ static NodeEnum coloring_enum;
+ coloring_enum.insert("intensity", NODE_VORONOI_INTENSITY);
+ coloring_enum.insert("cells", NODE_VORONOI_CELLS);
+ SOCKET_ENUM(coloring, "Coloring", coloring_enum, NODE_VORONOI_INTENSITY);
-ShaderEnum VoronoiTextureNode::coloring_enum = voronoi_coloring_init();
+ SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
+ SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
-VoronoiTextureNode::VoronoiTextureNode()
-: TextureNode("voronoi_texture")
-{
- coloring = ustring("Intensity");
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(fac, "Fac");
- add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
+ return type;
+}
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Fac", SHADER_SOCKET_FLOAT);
+VoronoiTextureNode::VoronoiTextureNode()
+: TextureNode(node_type)
+{
}
void VoronoiTextureNode::compile(SVMCompiler& compiler)
@@ -911,13 +943,13 @@ void VoronoiTextureNode::compile(SVMCompiler& compiler)
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
compiler.add_node(NODE_TEX_VORONOI,
- coloring_enum[coloring],
+ coloring,
compiler.encode_uchar4(
compiler.stack_assign_if_linked(scale_in),
vector_offset,
compiler.stack_assign(fac_out),
compiler.stack_assign(color_out)),
- __float_as_int(scale_in->value.x));
+ __float_as_int(scale));
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
@@ -926,42 +958,43 @@ void VoronoiTextureNode::compile(OSLCompiler& compiler)
{
tex_mapping.compile(compiler);
- compiler.parameter("Coloring", coloring);
+ compiler.parameter(this, "coloring");
compiler.add(this, "node_voronoi_texture");
}
/* Musgrave Texture */
-static ShaderEnum musgrave_type_init()
+NODE_DEFINE(MusgraveTextureNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("musgrave_texture", create, NodeType::SHADER);
- enm.insert("Multifractal", NODE_MUSGRAVE_MULTIFRACTAL);
- enm.insert("fBM", NODE_MUSGRAVE_FBM);
- enm.insert("Hybrid Multifractal", NODE_MUSGRAVE_HYBRID_MULTIFRACTAL);
- enm.insert("Ridged Multifractal", NODE_MUSGRAVE_RIDGED_MULTIFRACTAL);
- enm.insert("Hetero Terrain", NODE_MUSGRAVE_HETERO_TERRAIN);
+ TEXTURE_MAPPING_DEFINE(MusgraveTextureNode);
- return enm;
-}
+ static NodeEnum type_enum;
+ type_enum.insert("multifractal", NODE_MUSGRAVE_MULTIFRACTAL);
+ type_enum.insert("fBM", NODE_MUSGRAVE_FBM);
+ type_enum.insert("hybrid_multifractal", NODE_MUSGRAVE_HYBRID_MULTIFRACTAL);
+ type_enum.insert("ridged_multifractal", NODE_MUSGRAVE_RIDGED_MULTIFRACTAL);
+ type_enum.insert("hetero_terrain", NODE_MUSGRAVE_HETERO_TERRAIN);
+ SOCKET_ENUM(type, "Type", type_enum, NODE_MUSGRAVE_FBM);
-ShaderEnum MusgraveTextureNode::type_enum = musgrave_type_init();
+ SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
+ SOCKET_IN_FLOAT(detail, "Detail", 2.0f);
+ SOCKET_IN_FLOAT(dimension, "Dimension", 2.0f);
+ SOCKET_IN_FLOAT(lacunarity, "Lacunarity", 1.0f);
+ SOCKET_IN_FLOAT(offset, "Offset", 0.0f);
+ SOCKET_IN_FLOAT(gain, "Gain", 1.0f);
+ SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
-MusgraveTextureNode::MusgraveTextureNode()
-: TextureNode("musgrave_texture")
-{
- type = ustring("fBM");
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(fac, "Fac");
- add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("Detail", SHADER_SOCKET_FLOAT, 2.0f);
- add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
- add_input("Dimension", SHADER_SOCKET_FLOAT, 2.0f);
- add_input("Lacunarity", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("Offset", SHADER_SOCKET_FLOAT, 0.0f);
- add_input("Gain", SHADER_SOCKET_FLOAT, 1.0f);
+ return type;
+}
- add_output("Fac", SHADER_SOCKET_FLOAT);
- add_output("Color", SHADER_SOCKET_COLOR);
+MusgraveTextureNode::MusgraveTextureNode()
+: TextureNode(node_type)
+{
}
void MusgraveTextureNode::compile(SVMCompiler& compiler)
@@ -980,7 +1013,7 @@ void MusgraveTextureNode::compile(SVMCompiler& compiler)
compiler.add_node(NODE_TEX_MUSGRAVE,
compiler.encode_uchar4(
- type_enum[type],
+ type,
vector_offset,
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(fac_out)),
@@ -992,12 +1025,12 @@ void MusgraveTextureNode::compile(SVMCompiler& compiler)
compiler.encode_uchar4(
compiler.stack_assign_if_linked(gain_in),
compiler.stack_assign_if_linked(scale_in)));
- compiler.add_node(__float_as_int(dimension_in->value.x),
- __float_as_int(lacunarity_in->value.x),
- __float_as_int(detail_in->value.x),
- __float_as_int(offset_in->value.x));
- compiler.add_node(__float_as_int(gain_in->value.x),
- __float_as_int(scale_in->value.x));
+ compiler.add_node(__float_as_int(dimension),
+ __float_as_int(lacunarity),
+ __float_as_int(detail),
+ __float_as_int(offset));
+ compiler.add_node(__float_as_int(gain),
+ __float_as_int(scale));
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
@@ -1006,50 +1039,43 @@ void MusgraveTextureNode::compile(OSLCompiler& compiler)
{
tex_mapping.compile(compiler);
- compiler.parameter("Type", type);
-
+ compiler.parameter(this, "type");
compiler.add(this, "node_musgrave_texture");
}
/* Wave Texture */
-static ShaderEnum wave_type_init()
+NODE_DEFINE(WaveTextureNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("wave_texture", create, NodeType::SHADER);
- enm.insert("Bands", NODE_WAVE_BANDS);
- enm.insert("Rings", NODE_WAVE_RINGS);
+ TEXTURE_MAPPING_DEFINE(WaveTextureNode);
- return enm;
-}
+ static NodeEnum type_enum;
+ type_enum.insert("bands", NODE_WAVE_BANDS);
+ type_enum.insert("rings", NODE_WAVE_RINGS);
+ SOCKET_ENUM(type, "Type", type_enum, NODE_WAVE_BANDS);
-static ShaderEnum wave_profile_init()
-{
- ShaderEnum enm;
+ static NodeEnum profile_enum;
+ profile_enum.insert("sine", NODE_WAVE_PROFILE_SIN);
+ profile_enum.insert("saw", NODE_WAVE_PROFILE_SAW);
+ SOCKET_ENUM(profile, "Profile", profile_enum, NODE_WAVE_PROFILE_SIN);
- enm.insert("Sine", NODE_WAVE_PROFILE_SIN);
- enm.insert("Saw", NODE_WAVE_PROFILE_SAW);
+ SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
+ SOCKET_IN_FLOAT(distortion, "Distortion", 0.0f);
+ SOCKET_IN_FLOAT(detail, "Detail", 2.0f);
+ SOCKET_IN_FLOAT(detail_scale, "Detail Scale", 0.0f);
+ SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
- return enm;
-}
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(fac, "Fac");
-ShaderEnum WaveTextureNode::type_enum = wave_type_init();
-ShaderEnum WaveTextureNode::profile_enum = wave_profile_init();
+ return type;
+}
WaveTextureNode::WaveTextureNode()
-: TextureNode("wave_texture")
+: TextureNode(node_type)
{
- type = ustring("Bands");
- profile = ustring("Sine");
-
- add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("Distortion", SHADER_SOCKET_FLOAT, 0.0f);
- add_input("Detail", SHADER_SOCKET_FLOAT, 2.0f);
- add_input("Detail Scale", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
-
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Fac", SHADER_SOCKET_FLOAT);
}
void WaveTextureNode::compile(SVMCompiler& compiler)
@@ -1066,7 +1092,7 @@ void WaveTextureNode::compile(SVMCompiler& compiler)
compiler.add_node(NODE_TEX_WAVE,
compiler.encode_uchar4(
- type_enum[type],
+ type,
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(fac_out),
compiler.stack_assign_if_linked(dscale_in)),
@@ -1075,13 +1101,13 @@ void WaveTextureNode::compile(SVMCompiler& compiler)
compiler.stack_assign_if_linked(scale_in),
compiler.stack_assign_if_linked(detail_in),
compiler.stack_assign_if_linked(distortion_in)),
- profile_enum[profile]);
+ profile);
compiler.add_node(
- __float_as_int(scale_in->value.x),
- __float_as_int(detail_in->value.x),
- __float_as_int(distortion_in->value.x),
- __float_as_int(dscale_in->value.x));
+ __float_as_int(scale),
+ __float_as_int(detail),
+ __float_as_int(distortion),
+ __float_as_int(detail_scale));
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
@@ -1090,25 +1116,35 @@ void WaveTextureNode::compile(OSLCompiler& compiler)
{
tex_mapping.compile(compiler);
- compiler.parameter("Type", type);
- compiler.parameter("Profile", profile);
+ compiler.parameter(this, "type");
+ compiler.parameter(this, "profile");
compiler.add(this, "node_wave_texture");
}
/* Magic Texture */
-MagicTextureNode::MagicTextureNode()
-: TextureNode("magic_texture")
+NODE_DEFINE(MagicTextureNode)
{
- depth = 2;
+ NodeType* type = NodeType::add("magic_texture", create, NodeType::SHADER);
+
+ TEXTURE_MAPPING_DEFINE(MagicTextureNode);
- add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
- add_input("Scale", SHADER_SOCKET_FLOAT, 5.0f);
- add_input("Distortion", SHADER_SOCKET_FLOAT, 1.0f);
+ SOCKET_INT(depth, "Depth", 2);
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Fac", SHADER_SOCKET_FLOAT);
+ SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
+ SOCKET_IN_FLOAT(scale, "Scale", 5.0f);
+ SOCKET_IN_FLOAT(distortion, "Distortion", 1.0f);
+
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(fac, "Fac");
+
+ return type;
+}
+
+MagicTextureNode::MagicTextureNode()
+: TextureNode(node_type)
+{
}
void MagicTextureNode::compile(SVMCompiler& compiler)
@@ -1131,8 +1167,8 @@ void MagicTextureNode::compile(SVMCompiler& compiler)
compiler.stack_assign_if_linked(scale_in),
compiler.stack_assign_if_linked(distortion_in)));
compiler.add_node(
- __float_as_int(scale_in->value.x),
- __float_as_int(distortion_in->value.x));
+ __float_as_int(scale),
+ __float_as_int(distortion));
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
@@ -1141,22 +1177,32 @@ void MagicTextureNode::compile(OSLCompiler& compiler)
{
tex_mapping.compile(compiler);
- compiler.parameter("Depth", depth);
+ compiler.parameter(this, "depth");
compiler.add(this, "node_magic_texture");
}
/* Checker Texture */
-CheckerTextureNode::CheckerTextureNode()
-: TextureNode("checker_texture")
+NODE_DEFINE(CheckerTextureNode)
{
- add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
- add_input("Color1", SHADER_SOCKET_COLOR);
- add_input("Color2", SHADER_SOCKET_COLOR);
- add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f);
+ NodeType* type = NodeType::add("checker_texture", create, NodeType::SHADER);
+
+ TEXTURE_MAPPING_DEFINE(CheckerTextureNode);
+
+ SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
+ SOCKET_IN_COLOR(color1, "Color1", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_IN_COLOR(color2, "Color2", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
+
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(fac, "Fac");
+
+ return type;
+}
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Fac", SHADER_SOCKET_FLOAT);
+CheckerTextureNode::CheckerTextureNode()
+: TextureNode(node_type)
+{
}
void CheckerTextureNode::compile(SVMCompiler& compiler)
@@ -1180,7 +1226,7 @@ void CheckerTextureNode::compile(SVMCompiler& compiler)
compiler.encode_uchar4(
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(fac_out)),
- __float_as_int(scale_in->value.x));
+ __float_as_int(scale));
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
@@ -1194,26 +1240,38 @@ void CheckerTextureNode::compile(OSLCompiler& compiler)
/* Brick Texture */
-BrickTextureNode::BrickTextureNode()
-: TextureNode("brick_texture")
+NODE_DEFINE(BrickTextureNode)
{
- offset = 0.5f;
- offset_frequency = 2;
- squash = 1.0f;
- squash_frequency = 2;
-
- add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
- add_input("Color1", SHADER_SOCKET_COLOR);
- add_input("Color2", SHADER_SOCKET_COLOR);
- add_input("Mortar", SHADER_SOCKET_COLOR);
- add_input("Scale", SHADER_SOCKET_FLOAT, 5.0f);
- add_input("Mortar Size", SHADER_SOCKET_FLOAT, 0.02f);
- add_input("Bias", SHADER_SOCKET_FLOAT, 0.0f);
- add_input("Brick Width", SHADER_SOCKET_FLOAT, 0.5f);
- add_input("Row Height", SHADER_SOCKET_FLOAT, 0.25f);
+ NodeType* type = NodeType::add("brick_texture", create, NodeType::SHADER);
+
+ TEXTURE_MAPPING_DEFINE(BrickTextureNode);
+
+ SOCKET_FLOAT(offset, "Offset", 0.5f);
+ SOCKET_INT(offset_frequency, "Offset Frequency", 2);
+ SOCKET_FLOAT(squash, "Squash", 1.0f);
+ SOCKET_INT(squash_frequency, "Squash Frequency", 2);
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Fac", SHADER_SOCKET_FLOAT);
+ SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
+
+ SOCKET_IN_COLOR(color1, "Color1", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_IN_COLOR(color2, "Color2", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_IN_COLOR(mortar, "Mortar", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_IN_FLOAT(scale, "Scale", 5.0f);
+ SOCKET_IN_FLOAT(mortar_size, "Mortar Size", 0.02f);
+ SOCKET_IN_FLOAT(mortar_smooth, "Mortar Smooth", 0.0f);
+ SOCKET_IN_FLOAT(bias, "Bias", 0.0f);
+ SOCKET_IN_FLOAT(brick_width, "Brick Width", 0.5f);
+ SOCKET_IN_FLOAT(row_height, "Row Height", 0.25f);
+
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(fac, "Fac");
+
+ return type;
+}
+
+BrickTextureNode::BrickTextureNode()
+: TextureNode(node_type)
+{
}
void BrickTextureNode::compile(SVMCompiler& compiler)
@@ -1224,6 +1282,7 @@ void BrickTextureNode::compile(SVMCompiler& compiler)
ShaderInput *mortar_in = input("Mortar");
ShaderInput *scale_in = input("Scale");
ShaderInput *mortar_size_in = input("Mortar Size");
+ ShaderInput *mortar_smooth_in = input("Mortar Smooth");
ShaderInput *bias_in = input("Bias");
ShaderInput *brick_width_in = input("Brick Width");
ShaderInput *row_height_in = input("Row Height");
@@ -1247,18 +1306,24 @@ void BrickTextureNode::compile(SVMCompiler& compiler)
compiler.encode_uchar4(
compiler.stack_assign_if_linked(row_height_in),
compiler.stack_assign_if_linked(color_out),
- compiler.stack_assign_if_linked(fac_out)));
+ compiler.stack_assign_if_linked(fac_out),
+ compiler.stack_assign_if_linked(mortar_smooth_in)));
compiler.add_node(compiler.encode_uchar4(offset_frequency, squash_frequency),
- __float_as_int(scale_in->value.x),
- __float_as_int(mortar_size_in->value.x),
- __float_as_int(bias_in->value.x));
+ __float_as_int(scale),
+ __float_as_int(mortar_size),
+ __float_as_int(bias));
- compiler.add_node(__float_as_int(brick_width_in->value.x),
- __float_as_int(row_height_in->value.x),
+ compiler.add_node(__float_as_int(brick_width),
+ __float_as_int(row_height),
__float_as_int(offset),
__float_as_int(squash));
+ compiler.add_node(__float_as_int(mortar_smooth),
+ SVM_STACK_INVALID,
+ SVM_STACK_INVALID,
+ SVM_STACK_INVALID);
+
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
@@ -1266,48 +1331,55 @@ void BrickTextureNode::compile(OSLCompiler& compiler)
{
tex_mapping.compile(compiler);
- compiler.parameter("Offset", offset);
- compiler.parameter("OffsetFrequency", offset_frequency);
- compiler.parameter("Squash", squash);
- compiler.parameter("SquashFrequency", squash_frequency);
+ compiler.parameter(this, "offset");
+ compiler.parameter(this, "offset_frequency");
+ compiler.parameter(this, "squash");
+ compiler.parameter(this, "squash_frequency");
compiler.add(this, "node_brick_texture");
}
/* Point Density Texture */
-static ShaderEnum point_density_space_init()
+NODE_DEFINE(PointDensityTextureNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("point_density_texture", create, NodeType::SHADER);
- enm.insert("Object", NODE_TEX_VOXEL_SPACE_OBJECT);
- enm.insert("World", NODE_TEX_VOXEL_SPACE_WORLD);
+ SOCKET_STRING(filename, "Filename", ustring(""));
- return enm;
-}
+ static NodeEnum space_enum;
+ space_enum.insert("object", NODE_TEX_VOXEL_SPACE_OBJECT);
+ space_enum.insert("world", NODE_TEX_VOXEL_SPACE_WORLD);
+ SOCKET_ENUM(space, "Space", space_enum, NODE_TEX_VOXEL_SPACE_OBJECT);
+
+ static NodeEnum interpolation_enum;
+ interpolation_enum.insert("closest", INTERPOLATION_CLOSEST);
+ interpolation_enum.insert("linear", INTERPOLATION_LINEAR);
+ interpolation_enum.insert("cubic", INTERPOLATION_CUBIC);
+ interpolation_enum.insert("smart", INTERPOLATION_SMART);
+ SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR);
-ShaderEnum PointDensityTextureNode::space_enum = point_density_space_init();
+ SOCKET_TRANSFORM(tfm, "Transform", transform_identity());
+
+ SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_POSITION);
+
+ SOCKET_OUT_FLOAT(density, "Density");
+ SOCKET_OUT_COLOR(color, "Color");
+
+ return type;
+}
PointDensityTextureNode::PointDensityTextureNode()
-: ShaderNode("point_density")
+: ShaderNode(node_type)
{
image_manager = NULL;
slot = -1;
- filename = "";
- space = ustring("Object");
builtin_data = NULL;
- interpolation = INTERPOLATION_LINEAR;
-
- tfm = transform_identity();
-
- add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::POSITION);
- add_output("Density", SHADER_SOCKET_FLOAT);
- add_output("Color", SHADER_SOCKET_COLOR);
}
PointDensityTextureNode::~PointDensityTextureNode()
{
if(image_manager) {
- image_manager->remove_image(filename,
+ image_manager->remove_image(filename.string(),
builtin_data,
interpolation,
EXTENSION_CLIP);
@@ -1345,7 +1417,7 @@ void PointDensityTextureNode::compile(SVMCompiler& compiler)
if(use_density || use_color) {
if(slot == -1) {
bool is_float, is_linear;
- slot = image_manager->add_image(filename, builtin_data,
+ slot = image_manager->add_image(filename.string(), builtin_data,
false, 0,
is_float, is_linear,
interpolation,
@@ -1360,8 +1432,8 @@ void PointDensityTextureNode::compile(SVMCompiler& compiler)
compiler.encode_uchar4(compiler.stack_assign(vector_in),
compiler.stack_assign_if_linked(density_out),
compiler.stack_assign_if_linked(color_out),
- space_enum[space]));
- if(space == "World") {
+ space));
+ if(space == NODE_TEX_VOXEL_SPACE_WORLD) {
compiler.add_node(tfm.x);
compiler.add_node(tfm.y);
compiler.add_node(tfm.z);
@@ -1374,7 +1446,7 @@ void PointDensityTextureNode::compile(SVMCompiler& compiler)
__float_as_int(0.0f),
compiler.stack_assign(density_out));
}
- if (use_color) {
+ if(use_color) {
compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out));
compiler.add_node(NODE_VALUE_V, make_float3(TEX_IMAGE_MISSING_R,
TEX_IMAGE_MISSING_G,
@@ -1397,7 +1469,7 @@ void PointDensityTextureNode::compile(OSLCompiler& compiler)
if(use_density || use_color) {
if(slot == -1) {
bool is_float, is_linear;
- slot = image_manager->add_image(filename, builtin_data,
+ slot = image_manager->add_image(filename.string(), builtin_data,
false, 0,
is_float, is_linear,
interpolation,
@@ -1408,37 +1480,34 @@ void PointDensityTextureNode::compile(OSLCompiler& compiler)
if(slot != -1) {
compiler.parameter("filename", string_printf("@%d", slot).c_str());
}
- if(space == "World") {
+ if(space == NODE_TEX_VOXEL_SPACE_WORLD) {
compiler.parameter("mapping", transform_transpose(tfm));
compiler.parameter("use_mapping", 1);
}
- switch(interpolation) {
- case INTERPOLATION_CLOSEST:
- compiler.parameter("interpolation", "closest");
- break;
- case INTERPOLATION_CUBIC:
- compiler.parameter("interpolation", "cubic");
- break;
- case INTERPOLATION_LINEAR:
- default:
- compiler.parameter("interpolation", "linear");
- break;
- }
-
+ compiler.parameter(this, "interpolation");
compiler.add(this, "node_voxel_texture");
}
}
/* Normal */
-NormalNode::NormalNode()
-: ShaderNode("normal")
+NODE_DEFINE(NormalNode)
{
- direction = make_float3(0.0f, 0.0f, 1.0f);
+ NodeType* type = NodeType::add("normal", create, NodeType::SHADER);
+
+ SOCKET_VECTOR(direction, "direction", make_float3(0.0f, 0.0f, 0.0f));
+
+ SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f));
- add_input("Normal", SHADER_SOCKET_NORMAL);
- add_output("Normal", SHADER_SOCKET_NORMAL);
- add_output("Dot", SHADER_SOCKET_FLOAT);
+ SOCKET_OUT_NORMAL(normal, "Normal");
+ SOCKET_OUT_FLOAT(dot, "Dot");
+
+ return type;
+}
+
+NormalNode::NormalNode()
+: ShaderNode(node_type)
+{
}
void NormalNode::compile(SVMCompiler& compiler)
@@ -1459,17 +1528,27 @@ void NormalNode::compile(SVMCompiler& compiler)
void NormalNode::compile(OSLCompiler& compiler)
{
- compiler.parameter_normal("Direction", direction);
+ compiler.parameter(this, "direction");
compiler.add(this, "node_normal");
}
/* Mapping */
+NODE_DEFINE(MappingNode)
+{
+ NodeType* type = NodeType::add("mapping", create, NodeType::SHADER);
+
+ TEXTURE_MAPPING_DEFINE(MappingNode);
+
+ SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_OUT_POINT(vector, "Vector");
+
+ return type;
+}
+
MappingNode::MappingNode()
-: ShaderNode("mapping")
+: ShaderNode(node_type)
{
- add_input("Vector", SHADER_SOCKET_POINT);
- add_output("Vector", SHADER_SOCKET_POINT);
}
void MappingNode::compile(SVMCompiler& compiler)
@@ -1491,146 +1570,183 @@ void MappingNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_mapping");
}
+/* RGBToBW */
+
+NODE_DEFINE(RGBToBWNode)
+{
+ NodeType* type = NodeType::add("rgb_to_bw", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_OUT_FLOAT(val, "Val");
+
+ return type;
+}
+
+RGBToBWNode::RGBToBWNode()
+: ShaderNode(node_type)
+{
+}
+
+void RGBToBWNode::constant_fold(const ConstantFolder& folder)
+{
+ if(folder.all_inputs_constant()) {
+ folder.make_constant(linear_rgb_to_gray(color));
+ }
+}
+
+void RGBToBWNode::compile(SVMCompiler& compiler)
+{
+ compiler.add_node(NODE_CONVERT,
+ NODE_CONVERT_CF,
+ compiler.stack_assign(inputs[0]),
+ compiler.stack_assign(outputs[0]));
+}
+
+void RGBToBWNode::compile(OSLCompiler& compiler)
+{
+ compiler.add(this, "node_rgb_to_bw");
+}
+
/* Convert */
-ConvertNode::ConvertNode(ShaderSocketType from_, ShaderSocketType to_, bool autoconvert)
-: ShaderNode("convert")
+const NodeType* ConvertNode::node_types[ConvertNode::MAX_TYPE][ConvertNode::MAX_TYPE];
+bool ConvertNode::initialized = ConvertNode::register_types();
+
+Node* ConvertNode::create(const NodeType *type)
+{
+ return new ConvertNode(type->inputs[0].type, type->outputs[0].type);
+}
+
+bool ConvertNode::register_types()
+{
+ const int num_types = 8;
+ SocketType::Type types[num_types] = {SocketType::FLOAT,
+ SocketType::INT,
+ SocketType::COLOR,
+ SocketType::VECTOR,
+ SocketType::POINT,
+ SocketType::NORMAL,
+ SocketType::STRING,
+ SocketType::CLOSURE};
+
+ for(size_t i = 0; i < num_types; i++) {
+ SocketType::Type from = types[i];
+ ustring from_name(SocketType::type_name(from));
+ ustring from_value_name("value_" + from_name.string());
+
+ for(size_t j = 0; j < num_types; j++) {
+ SocketType::Type to = types[j];
+ ustring to_name(SocketType::type_name(to));
+ ustring to_value_name("value_" + to_name.string());
+
+ string node_name = "convert_" + from_name.string() + "_to_" + to_name.string();
+ NodeType* type = NodeType::add(node_name.c_str(), create, NodeType::SHADER);
+
+ type->register_input(from_value_name, from_value_name, from,
+ SOCKET_OFFSETOF(ConvertNode, value_float), SocketType::zero_default_value(),
+ NULL, NULL, SocketType::LINKABLE);
+ type->register_output(to_value_name, to_value_name, to);
+
+ assert(from < MAX_TYPE);
+ assert(to < MAX_TYPE);
+
+ node_types[from][to] = type;
+ }
+ }
+
+ return true;
+}
+
+ConvertNode::ConvertNode(SocketType::Type from_, SocketType::Type to_, bool autoconvert)
+: ShaderNode(node_types[from_][to_])
{
from = from_;
to = to_;
- if(autoconvert) {
- if(from == to)
- special_type = SHADER_SPECIAL_TYPE_PROXY;
- else
- special_type = SHADER_SPECIAL_TYPE_AUTOCONVERT;
- }
-
- if(from == SHADER_SOCKET_FLOAT)
- add_input("Val", SHADER_SOCKET_FLOAT);
- else if(from == SHADER_SOCKET_INT)
- add_input("ValInt", SHADER_SOCKET_INT);
- else if(from == SHADER_SOCKET_COLOR)
- add_input("Color", SHADER_SOCKET_COLOR);
- else if(from == SHADER_SOCKET_VECTOR)
- add_input("Vector", SHADER_SOCKET_VECTOR);
- else if(from == SHADER_SOCKET_POINT)
- add_input("Point", SHADER_SOCKET_POINT);
- else if(from == SHADER_SOCKET_NORMAL)
- add_input("Normal", SHADER_SOCKET_NORMAL);
- else if(from == SHADER_SOCKET_STRING)
- add_input("String", SHADER_SOCKET_STRING);
- else if(from == SHADER_SOCKET_CLOSURE)
- add_input("Closure", SHADER_SOCKET_CLOSURE);
- else
- assert(0);
-
- if(to == SHADER_SOCKET_FLOAT)
- add_output("Val", SHADER_SOCKET_FLOAT);
- else if(to == SHADER_SOCKET_INT)
- add_output("ValInt", SHADER_SOCKET_INT);
- else if(to == SHADER_SOCKET_COLOR)
- add_output("Color", SHADER_SOCKET_COLOR);
- else if(to == SHADER_SOCKET_VECTOR)
- add_output("Vector", SHADER_SOCKET_VECTOR);
- else if(to == SHADER_SOCKET_POINT)
- add_output("Point", SHADER_SOCKET_POINT);
- else if(to == SHADER_SOCKET_NORMAL)
- add_output("Normal", SHADER_SOCKET_NORMAL);
- else if(to == SHADER_SOCKET_STRING)
- add_output("String", SHADER_SOCKET_STRING);
- else if(to == SHADER_SOCKET_CLOSURE)
- add_output("Closure", SHADER_SOCKET_CLOSURE);
- else
- assert(0);
+ if(from == to)
+ special_type = SHADER_SPECIAL_TYPE_PROXY;
+ else if(autoconvert)
+ special_type = SHADER_SPECIAL_TYPE_AUTOCONVERT;
}
-bool ConvertNode::constant_fold(ShaderGraph * /*graph*/,
- ShaderOutput * /*socket*/,
- float3 *optimized_value)
+void ConvertNode::constant_fold(const ConstantFolder& folder)
{
- ShaderInput *in = inputs[0];
- float3 value = in->value;
+ /* proxy nodes should have been removed at this point */
+ assert(special_type != SHADER_SPECIAL_TYPE_PROXY);
/* TODO(DingTo): conversion from/to int is not supported yet, don't fold in that case */
- if(in->link == NULL) {
- if(from == SHADER_SOCKET_FLOAT) {
- if(to == SHADER_SOCKET_INT)
- /* float to int */
- return false;
- else
- /* float to float3 */
- *optimized_value = make_float3(value.x, value.x, value.x);
- }
- else if(from == SHADER_SOCKET_INT) {
- if(to == SHADER_SOCKET_FLOAT)
- /* int to float */
- return false;
- else
- /* int to vector/point/normal */
- return false;
- }
- else if(to == SHADER_SOCKET_FLOAT) {
- if(from == SHADER_SOCKET_COLOR)
- /* color to float */
- optimized_value->x = linear_rgb_to_gray(value);
- else
- /* vector/point/normal to float */
- optimized_value->x = average(value);
- }
- else if(to == SHADER_SOCKET_INT) {
- if(from == SHADER_SOCKET_COLOR)
- /* color to int */
- return false;
- else
- /* vector/point/normal to int */
- return false;
+ if(folder.all_inputs_constant()) {
+ if(from == SocketType::FLOAT) {
+ if(SocketType::is_float3(to)) {
+ folder.make_constant(make_float3(value_float, value_float, value_float));
+ }
}
- else {
- *optimized_value = value;
+ else if(SocketType::is_float3(from)) {
+ if(to == SocketType::FLOAT) {
+ if(from == SocketType::COLOR) {
+ /* color to float */
+ folder.make_constant(linear_rgb_to_gray(value_color));
+ }
+ else {
+ /* vector/point/normal to float */
+ folder.make_constant(average(value_vector));
+ }
+ }
+ else if(SocketType::is_float3(to)) {
+ folder.make_constant(value_color);
+ }
}
-
- return true;
}
+ else {
+ ShaderInput *in = inputs[0];
+ ShaderNode *prev = in->link->parent;
+
+ /* no-op conversion of A to B to A */
+ if(prev->type == node_types[to][from]) {
+ ShaderInput *prev_in = prev->inputs[0];
- return false;
+ if(SocketType::is_float3(from) && (to == SocketType::FLOAT || SocketType::is_float3(to)) && prev_in->link) {
+ folder.bypass(prev_in->link);
+ }
+ }
+ }
}
void ConvertNode::compile(SVMCompiler& compiler)
{
- /* constant folding should eliminate proxy nodes */
- assert(from != to);
+ /* proxy nodes should have been removed at this point */
+ assert(special_type != SHADER_SPECIAL_TYPE_PROXY);
ShaderInput *in = inputs[0];
ShaderOutput *out = outputs[0];
- if(from == SHADER_SOCKET_FLOAT) {
- if(to == SHADER_SOCKET_INT)
+ if(from == SocketType::FLOAT) {
+ if(to == SocketType::INT)
/* float to int */
compiler.add_node(NODE_CONVERT, NODE_CONVERT_FI, compiler.stack_assign(in), compiler.stack_assign(out));
else
/* float to float3 */
compiler.add_node(NODE_CONVERT, NODE_CONVERT_FV, compiler.stack_assign(in), compiler.stack_assign(out));
}
- else if(from == SHADER_SOCKET_INT) {
- if(to == SHADER_SOCKET_FLOAT)
+ else if(from == SocketType::INT) {
+ if(to == SocketType::FLOAT)
/* int to float */
compiler.add_node(NODE_CONVERT, NODE_CONVERT_IF, compiler.stack_assign(in), compiler.stack_assign(out));
else
/* int to vector/point/normal */
compiler.add_node(NODE_CONVERT, NODE_CONVERT_IV, compiler.stack_assign(in), compiler.stack_assign(out));
}
- else if(to == SHADER_SOCKET_FLOAT) {
- if(from == SHADER_SOCKET_COLOR)
+ else if(to == SocketType::FLOAT) {
+ if(from == SocketType::COLOR)
/* color to float */
compiler.add_node(NODE_CONVERT, NODE_CONVERT_CF, compiler.stack_assign(in), compiler.stack_assign(out));
else
/* vector/point/normal to float */
compiler.add_node(NODE_CONVERT, NODE_CONVERT_VF, compiler.stack_assign(in), compiler.stack_assign(out));
}
- else if(to == SHADER_SOCKET_INT) {
- if(from == SHADER_SOCKET_COLOR)
+ else if(to == SocketType::INT) {
+ if(from == SocketType::COLOR)
/* color to int */
compiler.add_node(NODE_CONVERT, NODE_CONVERT_CI, compiler.stack_assign(in), compiler.stack_assign(out));
else
@@ -1646,27 +1762,27 @@ void ConvertNode::compile(SVMCompiler& compiler)
else {
/* set 0,0,0 value */
compiler.add_node(NODE_VALUE_V, compiler.stack_assign(out));
- compiler.add_node(NODE_VALUE_V, in->value);
+ compiler.add_node(NODE_VALUE_V, value_color);
}
}
}
void ConvertNode::compile(OSLCompiler& compiler)
{
- /* constant folding should eliminate proxy nodes */
- assert(from != to);
+ /* proxy nodes should have been removed at this point */
+ assert(special_type != SHADER_SPECIAL_TYPE_PROXY);
- if(from == SHADER_SOCKET_FLOAT)
+ if(from == SocketType::FLOAT)
compiler.add(this, "node_convert_from_float");
- else if(from == SHADER_SOCKET_INT)
+ else if(from == SocketType::INT)
compiler.add(this, "node_convert_from_int");
- else if(from == SHADER_SOCKET_COLOR)
+ else if(from == SocketType::COLOR)
compiler.add(this, "node_convert_from_color");
- else if(from == SHADER_SOCKET_VECTOR)
+ else if(from == SocketType::VECTOR)
compiler.add(this, "node_convert_from_vector");
- else if(from == SHADER_SOCKET_POINT)
+ else if(from == SocketType::POINT)
compiler.add(this, "node_convert_from_point");
- else if(from == SHADER_SOCKET_NORMAL)
+ else if(from == SocketType::NORMAL)
compiler.add(this, "node_convert_from_normal");
else
assert(0);
@@ -1674,23 +1790,10 @@ void ConvertNode::compile(OSLCompiler& compiler)
/* BSDF Closure */
-BsdfNode::BsdfNode(bool scattering_)
-: ShaderNode("bsdf"), scattering(scattering_)
+BsdfNode::BsdfNode(const NodeType *node_type)
+: ShaderNode(node_type)
{
special_type = SHADER_SPECIAL_TYPE_CLOSURE;
-
- add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f));
- add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL);
- add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
-
- if(scattering) {
- closure = CLOSURE_BSSRDF_CUBIC_ID;
- add_output("BSSRDF", SHADER_SOCKET_CLOSURE);
- }
- else {
- closure = CLOSURE_BSDF_DIFFUSE_ID;
- add_output("BSDF", SHADER_SOCKET_CLOSURE);
- }
}
void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2, ShaderInput *param3, ShaderInput *param4)
@@ -1702,9 +1805,9 @@ void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *
if(color_in->link)
compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in));
else
- compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value);
+ compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color);
- int normal_offset = compiler.stack_assign_if_linked(normal_in);
+ int normal_offset = (normal_in) ? compiler.stack_assign_if_linked(normal_in) : SVM_STACK_INVALID;
int tangent_offset = (tangent_in) ? compiler.stack_assign_if_linked(tangent_in) : SVM_STACK_INVALID;
int param3_offset = (param3) ? compiler.stack_assign(param3) : SVM_STACK_INVALID;
int param4_offset = (param4) ? compiler.stack_assign(param4) : SVM_STACK_INVALID;
@@ -1714,8 +1817,8 @@ void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *
(param1)? compiler.stack_assign(param1): SVM_STACK_INVALID,
(param2)? compiler.stack_assign(param2): SVM_STACK_INVALID,
compiler.closure_mix_weight_offset()),
- __float_as_int((param1)? param1->value.x: 0.0f),
- __float_as_int((param2)? param2->value.x: 0.0f));
+ __float_as_int((param1)? get_float(param1->socket_type): 0.0f),
+ __float_as_int((param2)? get_float(param2->socket_type): 0.0f));
compiler.add_node(normal_offset, tangent_offset, param3_offset, param4_offset);
}
@@ -1732,29 +1835,36 @@ void BsdfNode::compile(OSLCompiler& /*compiler*/)
/* Anisotropic BSDF Closure */
-static ShaderEnum aniso_distribution_init()
+NODE_DEFINE(AnisotropicBsdfNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("anisotropic_bsdf", create, NodeType::SHADER);
- enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID);
- enm.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID);
- enm.insert("Ashikhmin-Shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID);
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
+ SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
- return enm;
-}
+ static NodeEnum distribution_enum;
+ distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID);
+ distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID);
+ distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID);
+ distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID);
+ SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID);
+
+ SOCKET_IN_VECTOR(tangent, "Tangent", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TANGENT);
-ShaderEnum AnisotropicBsdfNode::distribution_enum = aniso_distribution_init();
+ SOCKET_IN_FLOAT(roughness, "Roughness", 0.2f);
+ SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.5f);
+ SOCKET_IN_FLOAT(rotation, "Rotation", 0.0f);
+
+ SOCKET_OUT_CLOSURE(BSDF, "BSDF");
+
+ return type;
+}
AnisotropicBsdfNode::AnisotropicBsdfNode()
+: BsdfNode(node_type)
{
closure = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID;
- distribution = ustring("GGX");
-
- add_input("Tangent", SHADER_SOCKET_VECTOR, ShaderInput::TANGENT);
-
- add_input("Roughness", SHADER_SOCKET_FLOAT, 0.2f);
- add_input("Anisotropy", SHADER_SOCKET_FLOAT, 0.5f);
- add_input("Rotation", SHADER_SOCKET_FLOAT, 0.0f);
}
void AnisotropicBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -1771,45 +1881,54 @@ void AnisotropicBsdfNode::attributes(Shader *shader, AttributeRequestSet *attrib
void AnisotropicBsdfNode::compile(SVMCompiler& compiler)
{
- closure = (ClosureType)distribution_enum[distribution];
+ closure = distribution;
- BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation"));
+ if(closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID)
+ BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation"), input("Color"));
+ else
+ BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation"));
}
void AnisotropicBsdfNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("distribution", distribution);
+ compiler.parameter(this, "distribution");
compiler.add(this, "node_anisotropic_bsdf");
}
/* Glossy BSDF Closure */
-static ShaderEnum glossy_distribution_init()
+NODE_DEFINE(GlossyBsdfNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("glossy_bsdf", create, NodeType::SHADER);
- enm.insert("Sharp", CLOSURE_BSDF_REFLECTION_ID);
- enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
- enm.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ID);
- enm.insert("Ashikhmin-Shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID);
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
+ SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
- return enm;
-}
+ static NodeEnum distribution_enum;
+ distribution_enum.insert("sharp", CLOSURE_BSDF_REFLECTION_ID);
+ distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
+ distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ID);
+ distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID);
+ distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
+ SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ID);
+ SOCKET_IN_FLOAT(roughness, "Roughness", 0.2f);
+
+ SOCKET_OUT_CLOSURE(BSDF, "BSDF");
-ShaderEnum GlossyBsdfNode::distribution_enum = glossy_distribution_init();
+ return type;
+}
GlossyBsdfNode::GlossyBsdfNode()
+: BsdfNode(node_type)
{
closure = CLOSURE_BSDF_MICROFACET_GGX_ID;
- distribution = ustring("GGX");
- distribution_orig = ustring("");
-
- add_input("Roughness", SHADER_SOCKET_FLOAT, 0.2f);
+ distribution_orig = NBUILTIN_CLOSURES;
}
void GlossyBsdfNode::simplify_settings(Scene *scene)
{
- if(distribution_orig == "") {
+ if(distribution_orig == NBUILTIN_CLOSURES) {
distribution_orig = distribution;
}
Integrator *integrator = scene->integrator;
@@ -1818,67 +1937,75 @@ void GlossyBsdfNode::simplify_settings(Scene *scene)
* Note: Keep the epsilon in sync with kernel!
*/
ShaderInput *roughness_input = input("Roughness");
- if(!roughness_input->link && roughness_input->value.x <= 1e-4f) {
- distribution = ustring("Sharp");
+ if(!roughness_input->link && roughness <= 1e-4f) {
+ distribution = CLOSURE_BSDF_REFLECTION_ID;
}
}
else {
/* Rollback to original distribution when filter glossy is used. */
distribution = distribution_orig;
}
- closure = (ClosureType)distribution_enum[distribution];
+ closure = distribution;
}
bool GlossyBsdfNode::has_integrator_dependency()
{
ShaderInput *roughness_input = input("Roughness");
- return !roughness_input->link && roughness_input->value.x <= 1e-4f;
+ return !roughness_input->link && roughness <= 1e-4f;
}
void GlossyBsdfNode::compile(SVMCompiler& compiler)
{
- closure = (ClosureType)distribution_enum[distribution];
+ closure = distribution;
if(closure == CLOSURE_BSDF_REFLECTION_ID)
BsdfNode::compile(compiler, NULL, NULL);
+ else if(closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID)
+ BsdfNode::compile(compiler, input("Roughness"), NULL, input("Color"));
else
BsdfNode::compile(compiler, input("Roughness"), NULL);
}
void GlossyBsdfNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("distribution", distribution);
+ compiler.parameter(this, "distribution");
compiler.add(this, "node_glossy_bsdf");
}
/* Glass BSDF Closure */
-static ShaderEnum glass_distribution_init()
+NODE_DEFINE(GlassBsdfNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("glass_bsdf", create, NodeType::SHADER);
- enm.insert("Sharp", CLOSURE_BSDF_SHARP_GLASS_ID);
- enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID);
- enm.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
+ SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
- return enm;
-}
+ static NodeEnum distribution_enum;
+ distribution_enum.insert("sharp", CLOSURE_BSDF_SHARP_GLASS_ID);
+ distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID);
+ distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
+ distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
+ SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
+ SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f);
+ SOCKET_IN_FLOAT(IOR, "IOR", 0.3f);
+
+ SOCKET_OUT_CLOSURE(BSDF, "BSDF");
-ShaderEnum GlassBsdfNode::distribution_enum = glass_distribution_init();
+ return type;
+}
GlassBsdfNode::GlassBsdfNode()
+: BsdfNode(node_type)
{
closure = CLOSURE_BSDF_SHARP_GLASS_ID;
- distribution = ustring("Sharp");
- distribution_orig = ustring("");
-
- add_input("Roughness", SHADER_SOCKET_FLOAT, 0.0f);
- add_input("IOR", SHADER_SOCKET_FLOAT, 0.3f);
+ distribution_orig = NBUILTIN_CLOSURES;
}
void GlassBsdfNode::simplify_settings(Scene *scene)
{
- if(distribution_orig == "") {
+ if(distribution_orig == NBUILTIN_CLOSURES) {
distribution_orig = distribution;
}
Integrator *integrator = scene->integrator;
@@ -1887,67 +2014,75 @@ void GlassBsdfNode::simplify_settings(Scene *scene)
* Note: Keep the epsilon in sync with kernel!
*/
ShaderInput *roughness_input = input("Roughness");
- if(!roughness_input->link && roughness_input->value.x <= 1e-4f) {
- distribution = ustring("Sharp");
+ if(!roughness_input->link && roughness <= 1e-4f) {
+ distribution = CLOSURE_BSDF_SHARP_GLASS_ID;
}
}
else {
/* Rollback to original distribution when filter glossy is used. */
distribution = distribution_orig;
}
- closure = (ClosureType)distribution_enum[distribution];
+ closure = distribution;
}
bool GlassBsdfNode::has_integrator_dependency()
{
ShaderInput *roughness_input = input("Roughness");
- return !roughness_input->link && roughness_input->value.x <= 1e-4f;
+ return !roughness_input->link && roughness <= 1e-4f;
}
void GlassBsdfNode::compile(SVMCompiler& compiler)
{
- closure = (ClosureType)distribution_enum[distribution];
+ closure = distribution;
if(closure == CLOSURE_BSDF_SHARP_GLASS_ID)
BsdfNode::compile(compiler, NULL, input("IOR"));
+ else if(closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID)
+ BsdfNode::compile(compiler, input("Roughness"), input("IOR"), input("Color"));
else
BsdfNode::compile(compiler, input("Roughness"), input("IOR"));
}
void GlassBsdfNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("distribution", distribution);
+ compiler.parameter(this, "distribution");
compiler.add(this, "node_glass_bsdf");
}
/* Refraction BSDF Closure */
-static ShaderEnum refraction_distribution_init()
+NODE_DEFINE(RefractionBsdfNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("refraction_bsdf", create, NodeType::SHADER);
- enm.insert("Sharp", CLOSURE_BSDF_REFRACTION_ID);
- enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID);
- enm.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID);
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
+ SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
- return enm;
-}
+ static NodeEnum distribution_enum;
+ distribution_enum.insert("sharp", CLOSURE_BSDF_REFRACTION_ID);
+ distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID);
+ distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID);
+ SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID);
-ShaderEnum RefractionBsdfNode::distribution_enum = refraction_distribution_init();
+ SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f);
+ SOCKET_IN_FLOAT(IOR, "IOR", 0.3f);
+
+ SOCKET_OUT_CLOSURE(BSDF, "BSDF");
+
+ return type;
+}
RefractionBsdfNode::RefractionBsdfNode()
+: BsdfNode(node_type)
{
closure = CLOSURE_BSDF_REFRACTION_ID;
- distribution = ustring("Sharp");
- distribution_orig = ustring("");
-
- add_input("Roughness", SHADER_SOCKET_FLOAT, 0.0f);
- add_input("IOR", SHADER_SOCKET_FLOAT, 0.3f);
+ distribution_orig = NBUILTIN_CLOSURES;
}
void RefractionBsdfNode::simplify_settings(Scene *scene)
{
- if(distribution_orig == "") {
+ if(distribution_orig == NBUILTIN_CLOSURES) {
distribution_orig = distribution;
}
Integrator *integrator = scene->integrator;
@@ -1956,26 +2091,26 @@ void RefractionBsdfNode::simplify_settings(Scene *scene)
* Note: Keep the epsilon in sync with kernel!
*/
ShaderInput *roughness_input = input("Roughness");
- if(!roughness_input->link && roughness_input->value.x <= 1e-4f) {
- distribution = ustring("Sharp");
+ if(!roughness_input->link && roughness <= 1e-4f) {
+ distribution = CLOSURE_BSDF_REFRACTION_ID;
}
}
else {
/* Rollback to original distribution when filter glossy is used. */
distribution = distribution_orig;
}
- closure = (ClosureType)distribution_enum[distribution];
+ closure = distribution;
}
bool RefractionBsdfNode::has_integrator_dependency()
{
ShaderInput *roughness_input = input("Roughness");
- return !roughness_input->link && roughness_input->value.x <= 1e-4f;
+ return !roughness_input->link && roughness <= 1e-4f;
}
void RefractionBsdfNode::compile(SVMCompiler& compiler)
{
- closure = (ClosureType)distribution_enum[distribution];
+ closure = distribution;
if(closure == CLOSURE_BSDF_REFRACTION_ID)
BsdfNode::compile(compiler, NULL, input("IOR"));
@@ -1985,53 +2120,71 @@ void RefractionBsdfNode::compile(SVMCompiler& compiler)
void RefractionBsdfNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("distribution", distribution);
+ compiler.parameter(this, "distribution");
compiler.add(this, "node_refraction_bsdf");
}
/* Toon BSDF Closure */
-static ShaderEnum toon_component_init()
+NODE_DEFINE(ToonBsdfNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("toon_bsdf", create, NodeType::SHADER);
- enm.insert("Diffuse", CLOSURE_BSDF_DIFFUSE_TOON_ID);
- enm.insert("Glossy", CLOSURE_BSDF_GLOSSY_TOON_ID);
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
+ SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
- return enm;
-}
+ static NodeEnum component_enum;
+ component_enum.insert("diffuse", CLOSURE_BSDF_DIFFUSE_TOON_ID);
+ component_enum.insert("glossy", CLOSURE_BSDF_GLOSSY_TOON_ID);
+ SOCKET_ENUM(component, "Component", component_enum, CLOSURE_BSDF_DIFFUSE_TOON_ID);
+ SOCKET_IN_FLOAT(size, "Size", 0.5f);
+ SOCKET_IN_FLOAT(smooth, "Smooth", 0.0f);
+
+ SOCKET_OUT_CLOSURE(BSDF, "BSDF");
-ShaderEnum ToonBsdfNode::component_enum = toon_component_init();
+ return type;
+}
ToonBsdfNode::ToonBsdfNode()
+: BsdfNode(node_type)
{
closure = CLOSURE_BSDF_DIFFUSE_TOON_ID;
- component = ustring("Diffuse");
-
- add_input("Size", SHADER_SOCKET_FLOAT, 0.5f);
- add_input("Smooth", SHADER_SOCKET_FLOAT, 0.0f);
}
void ToonBsdfNode::compile(SVMCompiler& compiler)
{
- closure = (ClosureType)component_enum[component];
+ closure = component;
BsdfNode::compile(compiler, input("Size"), input("Smooth"));
}
void ToonBsdfNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("component", component);
+ compiler.parameter(this, "component");
compiler.add(this, "node_toon_bsdf");
}
/* Velvet BSDF Closure */
+NODE_DEFINE(VelvetBsdfNode)
+{
+ NodeType* type = NodeType::add("velvet_bsdf", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
+ SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+ SOCKET_IN_FLOAT(sigma, "Sigma", 1.0f);
+
+ SOCKET_OUT_CLOSURE(BSDF, "BSDF");
+
+ return type;
+}
+
VelvetBsdfNode::VelvetBsdfNode()
+: BsdfNode(node_type)
{
closure = CLOSURE_BSDF_ASHIKHMIN_VELVET_ID;
-
- add_input("Sigma", SHADER_SOCKET_FLOAT, 1.0f);
}
void VelvetBsdfNode::compile(SVMCompiler& compiler)
@@ -2046,10 +2199,24 @@ void VelvetBsdfNode::compile(OSLCompiler& compiler)
/* Diffuse BSDF Closure */
+NODE_DEFINE(DiffuseBsdfNode)
+{
+ NodeType* type = NodeType::add("diffuse_bsdf", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
+ SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+ SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f);
+
+ SOCKET_OUT_CLOSURE(BSDF, "BSDF");
+
+ return type;
+}
+
DiffuseBsdfNode::DiffuseBsdfNode()
+: BsdfNode(node_type)
{
closure = CLOSURE_BSDF_DIFFUSE_ID;
- add_input("Roughness", SHADER_SOCKET_FLOAT, 0.0f);
}
void DiffuseBsdfNode::compile(SVMCompiler& compiler)
@@ -2064,7 +2231,21 @@ void DiffuseBsdfNode::compile(OSLCompiler& compiler)
/* Translucent BSDF Closure */
+NODE_DEFINE(TranslucentBsdfNode)
+{
+ NodeType* type = NodeType::add("translucent_bsdf", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
+ SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+
+ SOCKET_OUT_CLOSURE(BSDF, "BSDF");
+
+ return type;
+}
+
TranslucentBsdfNode::TranslucentBsdfNode()
+: BsdfNode(node_type)
{
closure = CLOSURE_BSDF_TRANSLUCENT_ID;
}
@@ -2081,9 +2262,21 @@ void TranslucentBsdfNode::compile(OSLCompiler& compiler)
/* Transparent BSDF Closure */
+NODE_DEFINE(TransparentBsdfNode)
+{
+ NodeType* type = NodeType::add("transparent_bsdf", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+
+ SOCKET_OUT_CLOSURE(BSDF, "BSDF");
+
+ return type;
+}
+
TransparentBsdfNode::TransparentBsdfNode()
+: BsdfNode(node_type)
{
- name = "transparent";
closure = CLOSURE_BSDF_TRANSPARENT_ID;
}
@@ -2099,39 +2292,45 @@ void TransparentBsdfNode::compile(OSLCompiler& compiler)
/* Subsurface Scattering Closure */
-static ShaderEnum subsurface_falloff_init()
+NODE_DEFINE(SubsurfaceScatteringNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("subsurface_scattering", create, NodeType::SHADER);
- enm.insert("Cubic", CLOSURE_BSSRDF_CUBIC_ID);
- enm.insert("Gaussian", CLOSURE_BSSRDF_GAUSSIAN_ID);
- enm.insert("Burley", CLOSURE_BSSRDF_BURLEY_ID);
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
+ SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
- return enm;
-}
+ static NodeEnum falloff_enum;
+ falloff_enum.insert("cubic", CLOSURE_BSSRDF_CUBIC_ID);
+ falloff_enum.insert("gaussian", CLOSURE_BSSRDF_GAUSSIAN_ID);
+ falloff_enum.insert("burley", CLOSURE_BSSRDF_BURLEY_ID);
+ SOCKET_ENUM(falloff, "Falloff", falloff_enum, CLOSURE_BSSRDF_BURLEY_ID);
+ SOCKET_IN_FLOAT(scale, "Scale", 0.01f);
+ SOCKET_IN_VECTOR(radius, "Radius", make_float3(0.1f, 0.1f, 0.1f));
+ SOCKET_IN_FLOAT(sharpness, "Sharpness", 0.0f);
+ SOCKET_IN_FLOAT(texture_blur, "Texture Blur", 1.0f);
+
+ SOCKET_OUT_CLOSURE(BSSRDF, "BSSRDF");
-ShaderEnum SubsurfaceScatteringNode::falloff_enum = subsurface_falloff_init();
+ return type;
+}
SubsurfaceScatteringNode::SubsurfaceScatteringNode()
-: BsdfNode(true)
+: BsdfNode(node_type)
{
- name = "subsurface_scattering";
- closure = CLOSURE_BSSRDF_CUBIC_ID;
-
- add_input("Scale", SHADER_SOCKET_FLOAT, 0.01f);
- add_input("Radius", SHADER_SOCKET_VECTOR, make_float3(0.1f, 0.1f, 0.1f));
- add_input("Sharpness", SHADER_SOCKET_FLOAT, 0.0f);
- add_input("Texture Blur", SHADER_SOCKET_FLOAT, 1.0f);
+ closure = falloff;
}
void SubsurfaceScatteringNode::compile(SVMCompiler& compiler)
{
+ closure = falloff;
BsdfNode::compile(compiler, input("Scale"), input("Texture Blur"), input("Radius"), input("Sharpness"));
}
void SubsurfaceScatteringNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("Falloff", falloff_enum[closure]);
+ closure = falloff;
+ compiler.parameter(this, "falloff");
compiler.add(this, "node_subsurface_scattering");
}
@@ -2144,14 +2343,22 @@ bool SubsurfaceScatteringNode::has_bssrdf_bump()
/* Emissive Closure */
-EmissionNode::EmissionNode()
-: ShaderNode("emission")
+NODE_DEFINE(EmissionNode)
{
- add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f));
- add_input("Strength", SHADER_SOCKET_FLOAT, 10.0f);
- add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
+ NodeType* type = NodeType::add("emission", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_FLOAT(strength, "Strength", 10.0f);
+ SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
- add_output("Emission", SHADER_SOCKET_CLOSURE);
+ SOCKET_OUT_CLOSURE(emission, "Emission");
+
+ return type;
+}
+
+EmissionNode::EmissionNode()
+: ShaderNode(node_type)
+{
}
void EmissionNode::compile(SVMCompiler& compiler)
@@ -2162,10 +2369,10 @@ void EmissionNode::compile(SVMCompiler& compiler)
if(color_in->link || strength_in->link) {
compiler.add_node(NODE_EMISSION_WEIGHT,
compiler.stack_assign(color_in),
- compiler.stack_assign(strength_in));
+ compiler.stack_assign(strength_in));
}
else
- compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value * strength_in->value.x);
+ compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color * strength);
compiler.add_node(NODE_CLOSURE_EMISSION, compiler.closure_mix_weight_offset());
}
@@ -2175,25 +2382,36 @@ void EmissionNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_emission");
}
-bool EmissionNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, float3 * /*optimized_value*/)
+void EmissionNode::constant_fold(const ConstantFolder& folder)
{
ShaderInput *color_in = input("Color");
ShaderInput *strength_in = input("Strength");
- return ((!color_in->link && color_in->value == make_float3(0.0f, 0.0f, 0.0f)) ||
- (!strength_in->link && strength_in->value.x == 0.0f));
+ if((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) ||
+ (!strength_in->link && strength == 0.0f))
+ {
+ folder.discard();
+ }
}
/* Background Closure */
-BackgroundNode::BackgroundNode()
-: ShaderNode("background")
+NODE_DEFINE(BackgroundNode)
{
- add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f));
- add_input("Strength", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
+ NodeType* type = NodeType::add("background_shader", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_FLOAT(strength, "Strength", 1.0f);
+ SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+
+ SOCKET_OUT_CLOSURE(background, "Background");
+
+ return type;
+}
- add_output("Background", SHADER_SOCKET_CLOSURE);
+BackgroundNode::BackgroundNode()
+: ShaderNode(node_type)
+{
}
void BackgroundNode::compile(SVMCompiler& compiler)
@@ -2207,7 +2425,7 @@ void BackgroundNode::compile(SVMCompiler& compiler)
compiler.stack_assign(strength_in));
}
else
- compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value*strength_in->value.x);
+ compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color*strength);
compiler.add_node(NODE_CLOSURE_BACKGROUND, compiler.closure_mix_weight_offset());
}
@@ -2217,24 +2435,35 @@ void BackgroundNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_background");
}
-bool BackgroundNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, float3 * /*optimized_value*/)
+void BackgroundNode::constant_fold(const ConstantFolder& folder)
{
ShaderInput *color_in = input("Color");
ShaderInput *strength_in = input("Strength");
- return ((!color_in->link && color_in->value == make_float3(0.0f, 0.0f, 0.0f)) ||
- (!strength_in->link && strength_in->value.x == 0.0f));
+ if((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) ||
+ (!strength_in->link && strength == 0.0f))
+ {
+ folder.discard();
+ }
}
/* Holdout Closure */
-HoldoutNode::HoldoutNode()
-: ShaderNode("holdout")
+NODE_DEFINE(HoldoutNode)
{
- add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
- add_input("VolumeMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
+ NodeType* type = NodeType::add("holdout", create, NodeType::SHADER);
+
+ SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+ SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+
+ SOCKET_OUT_CLOSURE(holdout, "Holdout");
- add_output("Holdout", SHADER_SOCKET_CLOSURE);
+ return type;
+}
+
+HoldoutNode::HoldoutNode()
+: ShaderNode(node_type)
+{
}
void HoldoutNode::compile(SVMCompiler& compiler)
@@ -2252,14 +2481,22 @@ void HoldoutNode::compile(OSLCompiler& compiler)
/* Ambient Occlusion */
-AmbientOcclusionNode::AmbientOcclusionNode()
-: ShaderNode("ambient_occlusion")
+NODE_DEFINE(AmbientOcclusionNode)
{
- add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL);
- add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f));
- add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
+ NodeType* type = NodeType::add("ambient_occlusion", create, NodeType::SHADER);
+
+ SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
- add_output("AO", SHADER_SOCKET_CLOSURE);
+ SOCKET_OUT_CLOSURE(AO, "AO");
+
+ return type;
+}
+
+AmbientOcclusionNode::AmbientOcclusionNode()
+: ShaderNode(node_type)
+{
}
void AmbientOcclusionNode::compile(SVMCompiler& compiler)
@@ -2269,7 +2506,7 @@ void AmbientOcclusionNode::compile(SVMCompiler& compiler)
if(color_in->link)
compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in));
else
- compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value);
+ compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color);
compiler.add_node(NODE_CLOSURE_AMBIENT_OCCLUSION, compiler.closure_mix_weight_offset());
}
@@ -2281,16 +2518,10 @@ void AmbientOcclusionNode::compile(OSLCompiler& compiler)
/* Volume Closure */
-VolumeNode::VolumeNode()
-: ShaderNode("volume")
+VolumeNode::VolumeNode(const NodeType *node_type)
+: ShaderNode(node_type)
{
closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
-
- add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f));
- add_input("Density", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("VolumeMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
-
- add_output("Volume", SHADER_SOCKET_CLOSURE);
}
void VolumeNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2)
@@ -2300,15 +2531,15 @@ void VolumeNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput
if(color_in->link)
compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in));
else
- compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value);
+ compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color);
compiler.add_node(NODE_CLOSURE_VOLUME,
compiler.encode_uchar4(closure,
(param1)? compiler.stack_assign(param1): SVM_STACK_INVALID,
(param2)? compiler.stack_assign(param2): SVM_STACK_INVALID,
compiler.closure_mix_weight_offset()),
- __float_as_int((param1)? param1->value.x: 0.0f),
- __float_as_int((param2)? param2->value.x: 0.0f));
+ __float_as_int((param1)? get_float(param1->socket_type): 0.0f),
+ __float_as_int((param2)? get_float(param2->socket_type): 0.0f));
}
void VolumeNode::compile(SVMCompiler& compiler)
@@ -2323,7 +2554,21 @@ void VolumeNode::compile(OSLCompiler& /*compiler*/)
/* Absorption Volume Closure */
+NODE_DEFINE(AbsorptionVolumeNode)
+{
+ NodeType* type = NodeType::add("absorption_volume", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_FLOAT(density, "Density", 1.0f);
+ SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+
+ SOCKET_OUT_CLOSURE(volume, "Volume");
+
+ return type;
+}
+
AbsorptionVolumeNode::AbsorptionVolumeNode()
+: VolumeNode(node_type)
{
closure = CLOSURE_VOLUME_ABSORPTION_ID;
}
@@ -2340,11 +2585,24 @@ void AbsorptionVolumeNode::compile(OSLCompiler& compiler)
/* Scatter Volume Closure */
+NODE_DEFINE(ScatterVolumeNode)
+{
+ NodeType* type = NodeType::add("scatter_volume", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_FLOAT(density, "Density", 1.0f);
+ SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.0f);
+ SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+
+ SOCKET_OUT_CLOSURE(volume, "Volume");
+
+ return type;
+}
+
ScatterVolumeNode::ScatterVolumeNode()
+: VolumeNode(node_type)
{
closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
-
- add_input("Anisotropy", SHADER_SOCKET_FLOAT, 0.0f);
}
void ScatterVolumeNode::compile(SVMCompiler& compiler)
@@ -2359,59 +2617,71 @@ void ScatterVolumeNode::compile(OSLCompiler& compiler)
/* Hair BSDF Closure */
-static ShaderEnum hair_component_init()
+NODE_DEFINE(HairBsdfNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("hair_bsdf", create, NodeType::SHADER);
- enm.insert("Reflection", CLOSURE_BSDF_HAIR_REFLECTION_ID);
- enm.insert("Transmission", CLOSURE_BSDF_HAIR_TRANSMISSION_ID);
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
+ SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
- return enm;
-}
+ static NodeEnum component_enum;
+ component_enum.insert("reflection", CLOSURE_BSDF_HAIR_REFLECTION_ID);
+ component_enum.insert("transmission", CLOSURE_BSDF_HAIR_TRANSMISSION_ID);
+ SOCKET_ENUM(component, "Component", component_enum, CLOSURE_BSDF_HAIR_REFLECTION_ID);
+ SOCKET_IN_FLOAT(offset, "Offset", 0.0f);
+ SOCKET_IN_FLOAT(roughness_u, "RoughnessU", 0.2f);
+ SOCKET_IN_FLOAT(roughness_v, "RoughnessV", 0.2f);
+ SOCKET_IN_VECTOR(tangent, "Tangent", make_float3(0.0f, 0.0f, 0.0f));
-ShaderEnum HairBsdfNode::component_enum = hair_component_init();
+ SOCKET_OUT_CLOSURE(BSDF, "BSDF");
+
+ return type;
+}
HairBsdfNode::HairBsdfNode()
+: BsdfNode(node_type)
{
closure = CLOSURE_BSDF_HAIR_REFLECTION_ID;
- component = ustring("Reflection");
-
- add_input("Offset", SHADER_SOCKET_FLOAT);
- add_input("RoughnessU", SHADER_SOCKET_FLOAT);
- add_input("RoughnessV", SHADER_SOCKET_FLOAT);
- add_input("Tangent", SHADER_SOCKET_VECTOR);
}
void HairBsdfNode::compile(SVMCompiler& compiler)
{
- closure = (ClosureType)component_enum[component];
+ closure = component;
BsdfNode::compile(compiler, input("RoughnessU"), input("RoughnessV"), input("Offset"));
}
void HairBsdfNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("component", component);
-
+ compiler.parameter(this, "component");
compiler.add(this, "node_hair_bsdf");
}
/* Geometry */
+NODE_DEFINE(GeometryNode)
+{
+ NodeType* type = NodeType::add("geometry", create, NodeType::SHADER);
+
+ SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
+
+ SOCKET_OUT_POINT(position, "Position");
+ SOCKET_OUT_NORMAL(normal, "Normal");
+ SOCKET_OUT_NORMAL(tangent, "Tangent");
+ SOCKET_OUT_NORMAL(true_normal, "True Normal");
+ SOCKET_OUT_VECTOR(incoming, "Incoming");
+ SOCKET_OUT_POINT(parametric, "Parametric");
+ SOCKET_OUT_FLOAT(backfacing, "Backfacing");
+ SOCKET_OUT_FLOAT(pointiness, "Pointiness");
+
+ return type;
+}
+
GeometryNode::GeometryNode()
-: ShaderNode("geometry")
+: ShaderNode(node_type)
{
special_type = SHADER_SPECIAL_TYPE_GEOMETRY;
-
- add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL);
- add_output("Position", SHADER_SOCKET_POINT);
- add_output("Normal", SHADER_SOCKET_NORMAL);
- add_output("Tangent", SHADER_SOCKET_NORMAL);
- add_output("True Normal", SHADER_SOCKET_NORMAL);
- add_output("Incoming", SHADER_SOCKET_VECTOR);
- add_output("Parametric", SHADER_SOCKET_POINT);
- add_output("Backfacing", SHADER_SOCKET_FLOAT);
- add_output("Pointiness", SHADER_SOCKET_FLOAT);
}
void GeometryNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -2431,8 +2701,8 @@ void GeometryNode::attributes(Shader *shader, AttributeRequestSet *attributes)
void GeometryNode::compile(SVMCompiler& compiler)
{
ShaderOutput *out;
- NodeType geom_node = NODE_GEOMETRY;
- NodeType attr_node = NODE_ATTR;
+ ShaderNodeType geom_node = NODE_GEOMETRY;
+ ShaderNodeType attr_node = NODE_ATTR;
if(bump == SHADER_BUMP_DX) {
geom_node = NODE_GEOMETRY_BUMP_DX;
@@ -2506,21 +2776,30 @@ void GeometryNode::compile(OSLCompiler& compiler)
/* TextureCoordinate */
-TextureCoordinateNode::TextureCoordinateNode()
-: ShaderNode("texture_coordinate")
+NODE_DEFINE(TextureCoordinateNode)
{
- add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL);
- add_output("Generated", SHADER_SOCKET_POINT);
- add_output("Normal", SHADER_SOCKET_NORMAL);
- add_output("UV", SHADER_SOCKET_POINT);
- add_output("Object", SHADER_SOCKET_POINT);
- add_output("Camera", SHADER_SOCKET_POINT);
- add_output("Window", SHADER_SOCKET_POINT);
- add_output("Reflection", SHADER_SOCKET_NORMAL);
+ NodeType* type = NodeType::add("texture_coordinate", create, NodeType::SHADER);
+
+ SOCKET_BOOLEAN(from_dupli, "From Dupli", false);
+ SOCKET_BOOLEAN(use_transform, "Use Transform", false);
+ SOCKET_TRANSFORM(ob_tfm, "Object Transform", transform_identity());
+
+ SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
+
+ SOCKET_OUT_POINT(generated, "Generated");
+ SOCKET_OUT_NORMAL(normal, "Normal");
+ SOCKET_OUT_POINT(UV, "UV");
+ SOCKET_OUT_POINT(object, "Object");
+ SOCKET_OUT_POINT(camera, "Camera");
+ SOCKET_OUT_POINT(window, "Window");
+ SOCKET_OUT_NORMAL(reflection, "Reflection");
- from_dupli = false;
- use_transform = false;
- ob_tfm = transform_identity();
+ return type;
+}
+
+TextureCoordinateNode::TextureCoordinateNode()
+: ShaderNode(node_type)
+{
}
void TextureCoordinateNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -2548,9 +2827,9 @@ void TextureCoordinateNode::attributes(Shader *shader, AttributeRequestSet *attr
void TextureCoordinateNode::compile(SVMCompiler& compiler)
{
ShaderOutput *out;
- NodeType texco_node = NODE_TEX_COORD;
- NodeType attr_node = NODE_ATTR;
- NodeType geom_node = NODE_GEOMETRY;
+ ShaderNodeType texco_node = NODE_TEX_COORD;
+ ShaderNodeType attr_node = NODE_ATTR;
+ ShaderNodeType geom_node = NODE_GEOMETRY;
if(bump == SHADER_BUMP_DX) {
texco_node = NODE_TEX_COORD_BUMP_DX;
@@ -2644,22 +2923,32 @@ void TextureCoordinateNode::compile(OSLCompiler& compiler)
compiler.parameter("is_background", true);
if(compiler.output_type() == SHADER_TYPE_VOLUME)
compiler.parameter("is_volume", true);
- compiler.parameter("use_transform", use_transform);
+ compiler.parameter(this, "use_transform");
Transform ob_itfm = transform_transpose(transform_inverse(ob_tfm));
compiler.parameter("object_itfm", ob_itfm);
- compiler.parameter("from_dupli", from_dupli);
+ compiler.parameter(this, "from_dupli");
compiler.add(this, "node_texture_coordinate");
}
-UVMapNode::UVMapNode()
-: ShaderNode("uvmap")
+/* UV Map */
+
+NODE_DEFINE(UVMapNode)
{
- attribute = "";
- from_dupli = false;
+ NodeType* type = NodeType::add("uvmap", create, NodeType::SHADER);
- add_output("UV", SHADER_SOCKET_POINT);
+ SOCKET_IN_STRING(attribute, "attribute", ustring(""));
+ SOCKET_IN_BOOLEAN(from_dupli, "from dupli", false);
+
+ SOCKET_OUT_POINT(UV, "UV");
+
+ return type;
+}
+
+UVMapNode::UVMapNode()
+: ShaderNode(node_type)
+{
}
void UVMapNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -2681,8 +2970,8 @@ void UVMapNode::attributes(Shader *shader, AttributeRequestSet *attributes)
void UVMapNode::compile(SVMCompiler& compiler)
{
ShaderOutput *out = output("UV");
- NodeType texco_node = NODE_TEX_COORD;
- NodeType attr_node = NODE_ATTR;
+ ShaderNodeType texco_node = NODE_TEX_COORD;
+ ShaderNodeType attr_node = NODE_ATTR;
int attr;
if(bump == SHADER_BUMP_DX) {
@@ -2718,28 +3007,36 @@ void UVMapNode::compile(OSLCompiler& compiler)
else
compiler.parameter("bump_offset", "center");
- compiler.parameter("from_dupli", from_dupli);
- compiler.parameter("name", attribute.c_str());
+ compiler.parameter(this, "from_dupli");
+ compiler.parameter(this, "attribute");
compiler.add(this, "node_uv_map");
}
/* Light Path */
+NODE_DEFINE(LightPathNode)
+{
+ NodeType* type = NodeType::add("light_path", create, NodeType::SHADER);
+
+ SOCKET_OUT_FLOAT(is_camera_ray, "Is Camera Ray");
+ SOCKET_OUT_FLOAT(is_shadow_ray, "Is Shadow Ray");
+ SOCKET_OUT_FLOAT(is_diffuse_ray, "Is Diffuse Ray");
+ SOCKET_OUT_FLOAT(is_glossy_ray, "Is Glossy Ray");
+ SOCKET_OUT_FLOAT(is_singular_ray, "Is Singular Ray");
+ SOCKET_OUT_FLOAT(is_reflection_ray, "Is Reflection Ray");
+ SOCKET_OUT_FLOAT(is_transmission_ray, "Is Transmission Ray");
+ SOCKET_OUT_FLOAT(is_volume_scatter_ray, "Is Volume Scatter Ray");
+ SOCKET_OUT_FLOAT(ray_length, "Ray Length");
+ SOCKET_OUT_FLOAT(ray_depth, "Ray Depth");
+ SOCKET_OUT_FLOAT(transparent_depth, "Transparent Depth");
+ SOCKET_OUT_FLOAT(transmission_depth, "Transmission Depth");
+
+ return type;
+}
+
LightPathNode::LightPathNode()
-: ShaderNode("light_path")
-{
- add_output("Is Camera Ray", SHADER_SOCKET_FLOAT);
- add_output("Is Shadow Ray", SHADER_SOCKET_FLOAT);
- add_output("Is Diffuse Ray", SHADER_SOCKET_FLOAT);
- add_output("Is Glossy Ray", SHADER_SOCKET_FLOAT);
- add_output("Is Singular Ray", SHADER_SOCKET_FLOAT);
- add_output("Is Reflection Ray", SHADER_SOCKET_FLOAT);
- add_output("Is Transmission Ray", SHADER_SOCKET_FLOAT);
- add_output("Is Volume Scatter Ray", SHADER_SOCKET_FLOAT);
- add_output("Ray Length", SHADER_SOCKET_FLOAT);
- add_output("Ray Depth", SHADER_SOCKET_FLOAT);
- add_output("Transparent Depth", SHADER_SOCKET_FLOAT);
- add_output("Transmission Depth", SHADER_SOCKET_FLOAT);
+: ShaderNode(node_type)
+{
}
void LightPathNode::compile(SVMCompiler& compiler)
@@ -2815,14 +3112,23 @@ void LightPathNode::compile(OSLCompiler& compiler)
/* Light Falloff */
+NODE_DEFINE(LightFalloffNode)
+{
+ NodeType* type = NodeType::add("light_fallof", create, NodeType::SHADER);
+
+ SOCKET_IN_FLOAT(strength, "Strength", 100.0f);
+ SOCKET_IN_FLOAT(smooth, "Smooth", 0.0f);
+
+ SOCKET_OUT_FLOAT(quadratic, "Quadratic");
+ SOCKET_OUT_FLOAT(linear, "Linear");
+ SOCKET_OUT_FLOAT(constant, "Constant");
+
+ return type;
+}
+
LightFalloffNode::LightFalloffNode()
-: ShaderNode("light_fallof")
+: ShaderNode(node_type)
{
- add_input("Strength", SHADER_SOCKET_FLOAT, 100.0f);
- add_input("Smooth", SHADER_SOCKET_FLOAT, 0.0f);
- add_output("Quadratic", SHADER_SOCKET_FLOAT);
- add_output("Linear", SHADER_SOCKET_FLOAT);
- add_output("Constant", SHADER_SOCKET_FLOAT);
}
void LightFalloffNode::compile(SVMCompiler& compiler)
@@ -2865,13 +3171,21 @@ void LightFalloffNode::compile(OSLCompiler& compiler)
/* Object Info */
+NODE_DEFINE(ObjectInfoNode)
+{
+ NodeType* type = NodeType::add("object_info", create, NodeType::SHADER);
+
+ SOCKET_OUT_VECTOR(location, "Location");
+ SOCKET_OUT_FLOAT(object_index, "Object Index");
+ SOCKET_OUT_FLOAT(material_index, "Material Index");
+ SOCKET_OUT_FLOAT(random, "Random");
+
+ return type;
+}
+
ObjectInfoNode::ObjectInfoNode()
-: ShaderNode("object_info")
+: ShaderNode(node_type)
{
- add_output("Location", SHADER_SOCKET_VECTOR);
- add_output("Object Index", SHADER_SOCKET_FLOAT);
- add_output("Material Index", SHADER_SOCKET_FLOAT);
- add_output("Random", SHADER_SOCKET_FLOAT);
}
void ObjectInfoNode::compile(SVMCompiler& compiler)
@@ -2904,19 +3218,27 @@ void ObjectInfoNode::compile(OSLCompiler& compiler)
/* Particle Info */
-ParticleInfoNode::ParticleInfoNode()
-: ShaderNode("particle_info")
+NODE_DEFINE(ParticleInfoNode)
{
- add_output("Index", SHADER_SOCKET_FLOAT);
- add_output("Age", SHADER_SOCKET_FLOAT);
- add_output("Lifetime", SHADER_SOCKET_FLOAT);
- add_output("Location", SHADER_SOCKET_POINT);
+ NodeType* type = NodeType::add("particle_info", create, NodeType::SHADER);
+
+ SOCKET_OUT_FLOAT(index, "Index");
+ SOCKET_OUT_FLOAT(age, "Age");
+ SOCKET_OUT_FLOAT(lifetime, "Lifetime");
+ SOCKET_OUT_POINT(location, "Location");
#if 0 /* not yet supported */
- add_output("Rotation", SHADER_SOCKET_QUATERNION);
+ SOCKET_OUT_QUATERNION(rotation, "Rotation");
#endif
- add_output("Size", SHADER_SOCKET_FLOAT);
- add_output("Velocity", SHADER_SOCKET_VECTOR);
- add_output("Angular Velocity", SHADER_SOCKET_VECTOR);
+ SOCKET_OUT_FLOAT(size, "Size");
+ SOCKET_OUT_VECTOR(velocity, "Velocity");
+ SOCKET_OUT_VECTOR(angular_velocity, "Angular Velocity");
+
+ return type;
+}
+
+ParticleInfoNode::ParticleInfoNode()
+: ShaderNode(node_type)
+{
}
void ParticleInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -2998,15 +3320,24 @@ void ParticleInfoNode::compile(OSLCompiler& compiler)
/* Hair Info */
+NODE_DEFINE(HairInfoNode)
+{
+ NodeType* type = NodeType::add("hair_info", create, NodeType::SHADER);
+
+ SOCKET_OUT_FLOAT(is_strand, "Is Strand");
+ SOCKET_OUT_FLOAT(intercept, "Intercept");
+ SOCKET_OUT_FLOAT(thickness, "Thickness");
+ SOCKET_OUT_NORMAL(tangent Normal, "Tangent Normal");
+#if 0 /*output for minimum hair width transparency - deactivated */
+ SOCKET_OUT_FLOAT(fade, "Fade");
+#endif
+
+ return type;
+}
+
HairInfoNode::HairInfoNode()
-: ShaderNode("hair_info")
+: ShaderNode(node_type)
{
- add_output("Is Strand", SHADER_SOCKET_FLOAT);
- add_output("Intercept", SHADER_SOCKET_FLOAT);
- add_output("Thickness", SHADER_SOCKET_FLOAT);
- add_output("Tangent Normal", SHADER_SOCKET_NORMAL);
- /*output for minimum hair width transparency - deactivated*/
- /*add_output("Fade", SHADER_SOCKET_FLOAT);*/
}
void HairInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -3060,19 +3391,24 @@ void HairInfoNode::compile(OSLCompiler& compiler)
/* Value */
-ValueNode::ValueNode()
-: ShaderNode("value")
+NODE_DEFINE(ValueNode)
{
- value = 0.0f;
+ NodeType* type = NodeType::add("value", create, NodeType::SHADER);
+
+ SOCKET_FLOAT(value, "Value", 0.0f);
+ SOCKET_OUT_FLOAT(value, "Value");
- add_output("Value", SHADER_SOCKET_FLOAT);
+ return type;
}
-bool ValueNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/,
- float3 *optimized_value)
+ValueNode::ValueNode()
+: ShaderNode(node_type)
{
- *optimized_value = make_float3(value, value, value);
- return true;
+}
+
+void ValueNode::constant_fold(const ConstantFolder& folder)
+{
+ folder.make_constant(value);
}
void ValueNode::compile(SVMCompiler& compiler)
@@ -3090,19 +3426,24 @@ void ValueNode::compile(OSLCompiler& compiler)
/* Color */
-ColorNode::ColorNode()
-: ShaderNode("color")
+NODE_DEFINE(ColorNode)
{
- value = make_float3(0.0f, 0.0f, 0.0f);
+ NodeType* type = NodeType::add("color", create, NodeType::SHADER);
+
+ SOCKET_COLOR(value, "Value", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_OUT_COLOR(color, "Color");
- add_output("Color", SHADER_SOCKET_COLOR);
+ return type;
}
-bool ColorNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/,
- float3 *optimized_value)
+ColorNode::ColorNode()
+: ShaderNode(node_type)
{
- *optimized_value = value;
- return true;
+}
+
+void ColorNode::constant_fold(const ConstantFolder& folder)
+{
+ folder.make_constant(value);
}
void ColorNode::compile(SVMCompiler& compiler)
@@ -3124,14 +3465,21 @@ void ColorNode::compile(OSLCompiler& compiler)
/* Add Closure */
+NODE_DEFINE(AddClosureNode)
+{
+ NodeType* type = NodeType::add("add_closure", create, NodeType::SHADER);
+
+ SOCKET_IN_CLOSURE(closure1, "Closure1");
+ SOCKET_IN_CLOSURE(closure2, "Closure2");
+ SOCKET_OUT_CLOSURE(closure, "Closure");
+
+ return type;
+}
+
AddClosureNode::AddClosureNode()
-: ShaderNode("add_closure")
+: ShaderNode(node_type)
{
special_type = SHADER_SPECIAL_TYPE_COMBINE_CLOSURE;
-
- add_input("Closure1", SHADER_SOCKET_CLOSURE);
- add_input("Closure2", SHADER_SOCKET_CLOSURE);
- add_output("Closure", SHADER_SOCKET_CLOSURE);
}
void AddClosureNode::compile(SVMCompiler& /*compiler*/)
@@ -3144,17 +3492,39 @@ void AddClosureNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_add_closure");
}
+void AddClosureNode::constant_fold(const ConstantFolder& folder)
+{
+ ShaderInput *closure1_in = input("Closure1");
+ ShaderInput *closure2_in = input("Closure2");
+
+ /* remove useless add closures nodes */
+ if(!closure1_in->link) {
+ folder.bypass_or_discard(closure2_in);
+ }
+ else if(!closure2_in->link) {
+ folder.bypass_or_discard(closure1_in);
+ }
+}
+
/* Mix Closure */
+NODE_DEFINE(MixClosureNode)
+{
+ NodeType* type = NodeType::add("mix_closure", create, NodeType::SHADER);
+
+ SOCKET_IN_FLOAT(fac, "Fac", 0.5f);
+ SOCKET_IN_CLOSURE(closure1, "Closure1");
+ SOCKET_IN_CLOSURE(closure2, "Closure2");
+
+ SOCKET_OUT_CLOSURE(closure, "Closure");
+
+ return type;
+}
+
MixClosureNode::MixClosureNode()
-: ShaderNode("mix_closure")
+: ShaderNode(node_type)
{
special_type = SHADER_SPECIAL_TYPE_COMBINE_CLOSURE;
-
- add_input("Fac", SHADER_SOCKET_FLOAT, 0.5f);
- add_input("Closure1", SHADER_SOCKET_CLOSURE);
- add_input("Closure2", SHADER_SOCKET_CLOSURE);
- add_output("Closure", SHADER_SOCKET_CLOSURE);
}
void MixClosureNode::compile(SVMCompiler& /*compiler*/)
@@ -3167,46 +3537,48 @@ void MixClosureNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_mix_closure");
}
-bool MixClosureNode::constant_fold(ShaderGraph *graph, ShaderOutput * /*socket*/, float3 * /*optimized_value*/)
+void MixClosureNode::constant_fold(const ConstantFolder& folder)
{
ShaderInput *fac_in = input("Fac");
ShaderInput *closure1_in = input("Closure1");
ShaderInput *closure2_in = input("Closure2");
- ShaderOutput *closure_out = output("Closure");
/* remove useless mix closures nodes */
if(closure1_in->link == closure2_in->link) {
- graph->relink(this, closure_out, closure1_in->link);
- return true;
+ folder.bypass_or_discard(closure1_in);
}
-
- /* remove unused mix closure input when factor is 0.0 or 1.0 */
- /* check for closure links and make sure factor link is disconnected */
- if(closure1_in->link && closure2_in->link && !fac_in->link) {
+ /* remove unused mix closure input when factor is 0.0 or 1.0
+ * check for closure links and make sure factor link is disconnected */
+ else if(!fac_in->link) {
/* factor 0.0 */
- if(fac_in->value.x == 0.0f) {
- graph->relink(this, closure_out, closure1_in->link);
- return true;
+ if(fac <= 0.0f) {
+ folder.bypass_or_discard(closure1_in);
}
/* factor 1.0 */
- else if(fac_in->value.x == 1.0f) {
- graph->relink(this, closure_out, closure2_in->link);
- return true;
+ else if(fac >= 1.0f) {
+ folder.bypass_or_discard(closure2_in);
}
}
-
- return false;
}
/* Mix Closure */
+NODE_DEFINE(MixClosureWeightNode)
+{
+ NodeType* type = NodeType::add("mix_closure_weight", create, NodeType::SHADER);
+
+ SOCKET_IN_FLOAT(weight, "Weight", 1.0f);
+ SOCKET_IN_FLOAT(fac, "Fac", 1.0f);
+
+ SOCKET_OUT_FLOAT(weight1, "Weight1");
+ SOCKET_OUT_FLOAT(weight2, "Weight2");
+
+ return type;
+}
+
MixClosureWeightNode::MixClosureWeightNode()
-: ShaderNode("mix_closure_weight")
+: ShaderNode(node_type)
{
- add_input("Weight", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("Fac", SHADER_SOCKET_FLOAT, 1.0f);
- add_output("Weight1", SHADER_SOCKET_FLOAT);
- add_output("Weight2", SHADER_SOCKET_FLOAT);
}
void MixClosureWeightNode::compile(SVMCompiler& compiler)
@@ -3231,12 +3603,38 @@ void MixClosureWeightNode::compile(OSLCompiler& /*compiler*/)
/* Invert */
+NODE_DEFINE(InvertNode)
+{
+ NodeType* type = NodeType::add("invert", create, NodeType::SHADER);
+
+ SOCKET_IN_FLOAT(fac, "Fac", 1.0f);
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f));
+
+ SOCKET_OUT_COLOR(color, "Color");
+
+ return type;
+}
+
InvertNode::InvertNode()
-: ShaderNode("invert")
+: ShaderNode(node_type)
+{
+}
+
+void InvertNode::constant_fold(const ConstantFolder& folder)
{
- add_input("Fac", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("Color", SHADER_SOCKET_COLOR);
- add_output("Color", SHADER_SOCKET_COLOR);
+ ShaderInput *fac_in = input("Fac");
+ ShaderInput *color_in = input("Color");
+
+ if(!fac_in->link) {
+ /* evaluate fully constant node */
+ if(!color_in->link) {
+ folder.make_constant(interp(color, make_float3(1.0f, 1.0f, 1.0f) - color, fac));
+ }
+ /* remove no-op node */
+ else if(fac == 0.0f) {
+ folder.bypass(color_in->link);
+ }
+ }
}
void InvertNode::compile(SVMCompiler& compiler)
@@ -3258,46 +3656,46 @@ void InvertNode::compile(OSLCompiler& compiler)
/* Mix */
-MixNode::MixNode()
-: ShaderNode("mix")
+NODE_DEFINE(MixNode)
{
- type = ustring("Mix");
+ NodeType* type = NodeType::add("mix", create, NodeType::SHADER);
- use_clamp = false;
+ static NodeEnum type_enum;
+ type_enum.insert("mix", NODE_MIX_BLEND);
+ type_enum.insert("add", NODE_MIX_ADD);
+ type_enum.insert("multiply", NODE_MIX_MUL);
+ type_enum.insert("screen", NODE_MIX_SCREEN);
+ type_enum.insert("overlay", NODE_MIX_OVERLAY);
+ type_enum.insert("subtract", NODE_MIX_SUB);
+ type_enum.insert("divide", NODE_MIX_DIV);
+ type_enum.insert("difference", NODE_MIX_DIFF);
+ type_enum.insert("darken", NODE_MIX_DARK);
+ type_enum.insert("lighten", NODE_MIX_LIGHT);
+ type_enum.insert("dodge", NODE_MIX_DODGE);
+ type_enum.insert("burn", NODE_MIX_BURN);
+ type_enum.insert("hue", NODE_MIX_HUE);
+ type_enum.insert("saturation", NODE_MIX_SAT);
+ type_enum.insert("value", NODE_MIX_VAL);
+ type_enum.insert("color", NODE_MIX_COLOR);
+ type_enum.insert("soft_light", NODE_MIX_SOFT);
+ type_enum.insert("linear_light", NODE_MIX_LINEAR);
+ SOCKET_ENUM(type, "Type", type_enum, NODE_MIX_BLEND);
- add_input("Fac", SHADER_SOCKET_FLOAT, 0.5f);
- add_input("Color1", SHADER_SOCKET_COLOR);
- add_input("Color2", SHADER_SOCKET_COLOR);
- add_output("Color", SHADER_SOCKET_COLOR);
-}
+ SOCKET_BOOLEAN(use_clamp, "Use Clamp", false);
-static ShaderEnum mix_type_init()
-{
- ShaderEnum enm;
+ SOCKET_IN_FLOAT(fac, "Fac", 0.5f);
+ SOCKET_IN_COLOR(color1, "Color1", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_IN_COLOR(color2, "Color2", make_float3(0.0f, 0.0f, 0.0f));
- enm.insert("Mix", NODE_MIX_BLEND);
- enm.insert("Add", NODE_MIX_ADD);
- enm.insert("Multiply", NODE_MIX_MUL);
- enm.insert("Screen", NODE_MIX_SCREEN);
- enm.insert("Overlay", NODE_MIX_OVERLAY);
- enm.insert("Subtract", NODE_MIX_SUB);
- enm.insert("Divide", NODE_MIX_DIV);
- enm.insert("Difference", NODE_MIX_DIFF);
- enm.insert("Darken", NODE_MIX_DARK);
- enm.insert("Lighten", NODE_MIX_LIGHT);
- enm.insert("Dodge", NODE_MIX_DODGE);
- enm.insert("Burn", NODE_MIX_BURN);
- enm.insert("Hue", NODE_MIX_HUE);
- enm.insert("Saturation", NODE_MIX_SAT);
- enm.insert("Value", NODE_MIX_VAL);
- enm.insert("Color", NODE_MIX_COLOR);
- enm.insert("Soft Light", NODE_MIX_SOFT);
- enm.insert("Linear Light", NODE_MIX_LINEAR);
+ SOCKET_OUT_COLOR(color, "Color");
- return enm;
+ return type;
}
-ShaderEnum MixNode::type_enum = mix_type_init();
+MixNode::MixNode()
+: ShaderNode(node_type)
+{
+}
void MixNode::compile(SVMCompiler& compiler)
{
@@ -3310,7 +3708,7 @@ void MixNode::compile(SVMCompiler& compiler)
compiler.stack_assign(fac_in),
compiler.stack_assign(color1_in),
compiler.stack_assign(color2_in));
- compiler.add_node(NODE_MIX, type_enum[type], compiler.stack_assign(color_out));
+ compiler.add_node(NODE_MIX, type, compiler.stack_assign(color_out));
if(use_clamp) {
compiler.add_node(NODE_MIX, 0, compiler.stack_assign(color_out));
@@ -3320,59 +3718,46 @@ void MixNode::compile(SVMCompiler& compiler)
void MixNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("type", type);
- compiler.parameter("Clamp", use_clamp);
+ compiler.parameter(this, "type");
+ compiler.parameter(this, "use_clamp");
compiler.add(this, "node_mix");
}
-bool MixNode::constant_fold(ShaderGraph *graph, ShaderOutput * /*socket*/, float3 * optimized_value)
+void MixNode::constant_fold(const ConstantFolder& folder)
{
- if(type != ustring("Mix")) {
- return false;
+ if(folder.all_inputs_constant()) {
+ folder.make_constant_clamp(svm_mix(type, fac, color1, color2), use_clamp);
+ }
+ else {
+ folder.fold_mix(type, use_clamp);
}
+}
- ShaderInput *fac_in = input("Fac");
- ShaderInput *color1_in = input("Color1");
- ShaderInput *color2_in = input("Color2");
- ShaderOutput *color_out = output("Color");
+/* Combine RGB */
- /* remove useless mix colors nodes */
- if(color1_in->link && color1_in->link == color2_in->link) {
- graph->relink(this, color_out, color1_in->link);
- return true;
- }
+NODE_DEFINE(CombineRGBNode)
+{
+ NodeType* type = NodeType::add("combine_rgb", create, NodeType::SHADER);
- /* remove unused mix color input when factor is 0.0 or 1.0 */
- if(!fac_in->link) {
- /* factor 0.0 */
- if(fac_in->value.x == 0.0f) {
- if (color1_in->link)
- graph->relink(this, color_out, color1_in->link);
- else
- *optimized_value = color1_in->value;
- return true;
- }
- /* factor 1.0 */
- else if(fac_in->value.x == 1.0f) {
- if (color2_in->link)
- graph->relink(this, color_out, color2_in->link);
- else
- *optimized_value = color2_in->value;
- return true;
- }
- }
+ SOCKET_IN_FLOAT(r, "R", 0.0f);
+ SOCKET_IN_FLOAT(g, "G", 0.0f);
+ SOCKET_IN_FLOAT(b, "B", 0.0f);
+
+ SOCKET_OUT_COLOR(image, "Image");
- return false;
+ return type;
}
-/* Combine RGB */
CombineRGBNode::CombineRGBNode()
-: ShaderNode("combine_rgb")
+: ShaderNode(node_type)
+{
+}
+
+void CombineRGBNode::constant_fold(const ConstantFolder& folder)
{
- add_input("R", SHADER_SOCKET_FLOAT);
- add_input("G", SHADER_SOCKET_FLOAT);
- add_input("B", SHADER_SOCKET_FLOAT);
- add_output("Image", SHADER_SOCKET_COLOR);
+ if(folder.all_inputs_constant()) {
+ folder.make_constant(make_float3(r, g, b));
+ }
}
void CombineRGBNode::compile(SVMCompiler& compiler)
@@ -3401,13 +3786,30 @@ void CombineRGBNode::compile(OSLCompiler& compiler)
}
/* Combine XYZ */
+
+NODE_DEFINE(CombineXYZNode)
+{
+ NodeType* type = NodeType::add("combine_xyz", create, NodeType::SHADER);
+
+ SOCKET_IN_FLOAT(x, "X", 0.0f);
+ SOCKET_IN_FLOAT(y, "Y", 0.0f);
+ SOCKET_IN_FLOAT(z, "Z", 0.0f);
+
+ SOCKET_OUT_VECTOR(vector, "Vector");
+
+ return type;
+}
+
CombineXYZNode::CombineXYZNode()
-: ShaderNode("combine_xyz")
+: ShaderNode(node_type)
+{
+}
+
+void CombineXYZNode::constant_fold(const ConstantFolder& folder)
{
- add_input("X", SHADER_SOCKET_FLOAT);
- add_input("Y", SHADER_SOCKET_FLOAT);
- add_input("Z", SHADER_SOCKET_FLOAT);
- add_output("Vector", SHADER_SOCKET_VECTOR);
+ if(folder.all_inputs_constant()) {
+ folder.make_constant(make_float3(x, y, z));
+ }
}
void CombineXYZNode::compile(SVMCompiler& compiler)
@@ -3436,13 +3838,30 @@ void CombineXYZNode::compile(OSLCompiler& compiler)
}
/* Combine HSV */
+
+NODE_DEFINE(CombineHSVNode)
+{
+ NodeType* type = NodeType::add("combine_hsv", create, NodeType::SHADER);
+
+ SOCKET_IN_FLOAT(h, "H", 0.0f);
+ SOCKET_IN_FLOAT(s, "S", 0.0f);
+ SOCKET_IN_FLOAT(v, "V", 0.0f);
+
+ SOCKET_OUT_COLOR(color, "Color");
+
+ return type;
+}
+
CombineHSVNode::CombineHSVNode()
-: ShaderNode("combine_hsv")
+: ShaderNode(node_type)
+{
+}
+
+void CombineHSVNode::constant_fold(const ConstantFolder& folder)
{
- add_input("H", SHADER_SOCKET_FLOAT);
- add_input("S", SHADER_SOCKET_FLOAT);
- add_input("V", SHADER_SOCKET_FLOAT);
- add_output("Color", SHADER_SOCKET_COLOR);
+ if(folder.all_inputs_constant()) {
+ folder.make_constant(hsv_to_rgb(make_float3(h, s, v)));
+ }
}
void CombineHSVNode::compile(SVMCompiler& compiler)
@@ -3466,28 +3885,41 @@ void CombineHSVNode::compile(OSLCompiler& compiler)
}
/* Gamma */
+
+NODE_DEFINE(GammaNode)
+{
+ NodeType* type = NodeType::add("gamma", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_IN_FLOAT(gamma, "Gamma", 1.0f);
+ SOCKET_OUT_COLOR(color, "Color");
+
+ return type;
+}
+
GammaNode::GammaNode()
-: ShaderNode("gamma")
+: ShaderNode(node_type)
{
- add_input("Color", SHADER_SOCKET_COLOR);
- add_input("Gamma", SHADER_SOCKET_FLOAT);
- add_output("Color", SHADER_SOCKET_COLOR);
}
-bool GammaNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput *socket, float3 *optimized_value)
+void GammaNode::constant_fold(const ConstantFolder& folder)
{
- ShaderInput *color_in = input("Color");
- ShaderInput *gamma_in = input("Gamma");
+ if(folder.all_inputs_constant()) {
+ folder.make_constant(svm_math_gamma_color(color, gamma));
+ }
+ else {
+ ShaderInput *color_in = input("Color");
+ ShaderInput *gamma_in = input("Gamma");
- if(socket == output("Color")) {
- if(color_in->link == NULL && gamma_in->link == NULL) {
- *optimized_value = svm_math_gamma_color(color_in->value,
- gamma_in->value.x);
- return true;
+ /* 1 ^ X == X ^ 0 == 1 */
+ if(folder.is_one(color_in) || folder.is_zero(gamma_in)) {
+ folder.make_one();
+ }
+ /* X ^ 1 == X */
+ else if(folder.is_one(gamma_in)) {
+ folder.try_bypass_or_make_constant(color_in, false);
}
}
-
- return false;
}
void GammaNode::compile(SVMCompiler& compiler)
@@ -3508,13 +3940,30 @@ void GammaNode::compile(OSLCompiler& compiler)
}
/* Bright Contrast */
+
+NODE_DEFINE(BrightContrastNode)
+{
+ NodeType* type = NodeType::add("brightness_contrast", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_IN_FLOAT(bright, "Bright", 0.0f);
+ SOCKET_IN_FLOAT(contrast, "Contrast", 0.0f);
+
+ SOCKET_OUT_COLOR(color, "Color");
+
+ return type;
+}
+
BrightContrastNode::BrightContrastNode()
-: ShaderNode("brightness")
+: ShaderNode(node_type)
{
- add_input("Color", SHADER_SOCKET_COLOR);
- add_input("Bright", SHADER_SOCKET_FLOAT);
- add_input("Contrast", SHADER_SOCKET_FLOAT);
- add_output("Color", SHADER_SOCKET_COLOR);
+}
+
+void BrightContrastNode::constant_fold(const ConstantFolder& folder)
+{
+ if(folder.all_inputs_constant()) {
+ folder.make_constant(svm_brightness_contrast(color, bright, contrast));
+ }
}
void BrightContrastNode::compile(SVMCompiler& compiler)
@@ -3538,13 +3987,35 @@ void BrightContrastNode::compile(OSLCompiler& compiler)
}
/* Separate RGB */
+
+NODE_DEFINE(SeparateRGBNode)
+{
+ NodeType* type = NodeType::add("separate_rgb", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Image", make_float3(0.0f, 0.0f, 0.0f));
+
+ SOCKET_OUT_FLOAT(g, "R");
+ SOCKET_OUT_FLOAT(g, "G");
+ SOCKET_OUT_FLOAT(b, "B");
+
+ return type;
+}
+
SeparateRGBNode::SeparateRGBNode()
-: ShaderNode("separate_rgb")
+: ShaderNode(node_type)
+{
+}
+
+void SeparateRGBNode::constant_fold(const ConstantFolder& folder)
{
- add_input("Image", SHADER_SOCKET_COLOR);
- add_output("R", SHADER_SOCKET_FLOAT);
- add_output("G", SHADER_SOCKET_FLOAT);
- add_output("B", SHADER_SOCKET_FLOAT);
+ if(folder.all_inputs_constant()) {
+ for(int channel = 0; channel < 3; channel++) {
+ if(outputs[channel] == folder.output) {
+ folder.make_constant(color[channel]);
+ return;
+ }
+ }
+ }
}
void SeparateRGBNode::compile(SVMCompiler& compiler)
@@ -3573,13 +4044,35 @@ void SeparateRGBNode::compile(OSLCompiler& compiler)
}
/* Separate XYZ */
+
+NODE_DEFINE(SeparateXYZNode)
+{
+ NodeType* type = NodeType::add("separate_xyz", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f));
+
+ SOCKET_OUT_FLOAT(x, "X");
+ SOCKET_OUT_FLOAT(y, "Y");
+ SOCKET_OUT_FLOAT(z, "Z");
+
+ return type;
+}
+
SeparateXYZNode::SeparateXYZNode()
-: ShaderNode("separate_xyz")
+: ShaderNode(node_type)
{
- add_input("Vector", SHADER_SOCKET_VECTOR);
- add_output("X", SHADER_SOCKET_FLOAT);
- add_output("Y", SHADER_SOCKET_FLOAT);
- add_output("Z", SHADER_SOCKET_FLOAT);
+}
+
+void SeparateXYZNode::constant_fold(const ConstantFolder& folder)
+{
+ if(folder.all_inputs_constant()) {
+ for(int channel = 0; channel < 3; channel++) {
+ if(outputs[channel] == folder.output) {
+ folder.make_constant(vector[channel]);
+ return;
+ }
+ }
+ }
}
void SeparateXYZNode::compile(SVMCompiler& compiler)
@@ -3608,13 +4101,37 @@ void SeparateXYZNode::compile(OSLCompiler& compiler)
}
/* Separate HSV */
+
+NODE_DEFINE(SeparateHSVNode)
+{
+ NodeType* type = NodeType::add("separate_hsv", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f));
+
+ SOCKET_OUT_FLOAT(h, "H");
+ SOCKET_OUT_FLOAT(s, "S");
+ SOCKET_OUT_FLOAT(v, "V");
+
+ return type;
+}
+
SeparateHSVNode::SeparateHSVNode()
-: ShaderNode("separate_hsv")
+: ShaderNode(node_type)
{
- add_input("Color", SHADER_SOCKET_COLOR);
- add_output("H", SHADER_SOCKET_FLOAT);
- add_output("S", SHADER_SOCKET_FLOAT);
- add_output("V", SHADER_SOCKET_FLOAT);
+}
+
+void SeparateHSVNode::constant_fold(const ConstantFolder& folder)
+{
+ if(folder.all_inputs_constant()) {
+ float3 hsv = rgb_to_hsv(color);
+
+ for(int channel = 0; channel < 3; channel++) {
+ if(outputs[channel] == folder.output) {
+ folder.make_constant(hsv[channel]);
+ return;
+ }
+ }
+ }
}
void SeparateHSVNode::compile(SVMCompiler& compiler)
@@ -3638,15 +4155,25 @@ void SeparateHSVNode::compile(OSLCompiler& compiler)
}
/* Hue Saturation Value */
+
+NODE_DEFINE(HSVNode)
+{
+ NodeType* type = NodeType::add("hsv", create, NodeType::SHADER);
+
+ SOCKET_IN_FLOAT(hue, "Hue", 0.5f);
+ SOCKET_IN_FLOAT(saturation, "Saturation", 1.0f);
+ SOCKET_IN_FLOAT(value, "Value", 1.0f);
+ SOCKET_IN_FLOAT(fac, "Fac", 1.0f);
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f));
+
+ SOCKET_OUT_COLOR(color, "Color");
+
+ return type;
+}
+
HSVNode::HSVNode()
-: ShaderNode("hsv")
+: ShaderNode(node_type)
{
- add_input("Hue", SHADER_SOCKET_FLOAT);
- add_input("Saturation", SHADER_SOCKET_FLOAT);
- add_input("Value", SHADER_SOCKET_FLOAT);
- add_input("Fac", SHADER_SOCKET_FLOAT);
- add_input("Color", SHADER_SOCKET_COLOR);
- add_output("Color", SHADER_SOCKET_COLOR);
}
void HSVNode::compile(SVMCompiler& compiler)
@@ -3676,14 +4203,22 @@ void HSVNode::compile(OSLCompiler& compiler)
/* Attribute */
-AttributeNode::AttributeNode()
-: ShaderNode("attribute")
+NODE_DEFINE(AttributeNode)
{
- attribute = "";
+ NodeType* type = NodeType::add("attribute", create, NodeType::SHADER);
+
+ SOCKET_STRING(attribute, "Attribute", ustring(""));
+
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_VECTOR(vector, "Vector");
+ SOCKET_OUT_FLOAT(fac, "Fac");
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Vector", SHADER_SOCKET_VECTOR);
- add_output("Fac", SHADER_SOCKET_FLOAT);
+ return type;
+}
+
+AttributeNode::AttributeNode()
+: ShaderNode(node_type)
+{
}
void AttributeNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -3712,7 +4247,7 @@ void AttributeNode::compile(SVMCompiler& compiler)
ShaderOutput *color_out = output("Color");
ShaderOutput *vector_out = output("Vector");
ShaderOutput *fac_out = output("Fac");
- NodeType attr_node = NODE_ATTR;
+ ShaderNodeType attr_node = NODE_ATTR;
AttributeStandard std = Attribute::name_standard(attribute.c_str());
int attr;
@@ -3759,12 +4294,20 @@ void AttributeNode::compile(OSLCompiler& compiler)
/* Camera */
+NODE_DEFINE(CameraNode)
+{
+ NodeType* type = NodeType::add("camera_info", create, NodeType::SHADER);
+
+ SOCKET_OUT_VECTOR(view_vector, "View Vector");
+ SOCKET_OUT_FLOAT(view_z_depth, "View Z Depth");
+ SOCKET_OUT_FLOAT(view_distance, "View Distance");
+
+ return type;
+}
+
CameraNode::CameraNode()
-: ShaderNode("camera")
+: ShaderNode(node_type)
{
- add_output("View Vector", SHADER_SOCKET_VECTOR);
- add_output("View Z Depth", SHADER_SOCKET_FLOAT);
- add_output("View Distance", SHADER_SOCKET_FLOAT);
}
void CameraNode::compile(SVMCompiler& compiler)
@@ -3786,12 +4329,21 @@ void CameraNode::compile(OSLCompiler& compiler)
/* Fresnel */
+NODE_DEFINE(FresnelNode)
+{
+ NodeType* type = NodeType::add("fresnel", create, NodeType::SHADER);
+
+ SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
+ SOCKET_IN_FLOAT(IOR, "IOR", 1.45f);
+
+ SOCKET_OUT_FLOAT(fac, "Fac");
+
+ return type;
+}
+
FresnelNode::FresnelNode()
-: ShaderNode("fresnel")
+: ShaderNode(node_type)
{
- add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL);
- add_input("IOR", SHADER_SOCKET_FLOAT, 1.45f);
- add_output("Fac", SHADER_SOCKET_FLOAT);
}
void FresnelNode::compile(SVMCompiler& compiler)
@@ -3802,7 +4354,7 @@ void FresnelNode::compile(SVMCompiler& compiler)
compiler.add_node(NODE_FRESNEL,
compiler.stack_assign(IOR_in),
- __float_as_int(IOR_in->value.x),
+ __float_as_int(IOR),
compiler.encode_uchar4(
compiler.stack_assign_if_linked(normal_in),
compiler.stack_assign(fac_out)));
@@ -3815,14 +4367,22 @@ void FresnelNode::compile(OSLCompiler& compiler)
/* Layer Weight */
-LayerWeightNode::LayerWeightNode()
-: ShaderNode("layer_weight")
+NODE_DEFINE(LayerWeightNode)
{
- add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL);
- add_input("Blend", SHADER_SOCKET_FLOAT, 0.5f);
+ NodeType* type = NodeType::add("layer_weight", create, NodeType::SHADER);
+
+ SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
+ SOCKET_IN_FLOAT(blend, "Blend", 0.5f);
+
+ SOCKET_OUT_FLOAT(fresnel, "Fresnel");
+ SOCKET_OUT_FLOAT(facing, "Facing");
- add_output("Fresnel", SHADER_SOCKET_FLOAT);
- add_output("Facing", SHADER_SOCKET_FLOAT);
+ return type;
+}
+
+LayerWeightNode::LayerWeightNode()
+: ShaderNode(node_type)
+{
}
void LayerWeightNode::compile(SVMCompiler& compiler)
@@ -3835,7 +4395,7 @@ void LayerWeightNode::compile(SVMCompiler& compiler)
if(!fresnel_out->links.empty()) {
compiler.add_node(NODE_LAYER_WEIGHT,
compiler.stack_assign_if_linked(blend_in),
- __float_as_int(blend_in->value.x),
+ __float_as_int(blend),
compiler.encode_uchar4(NODE_LAYER_WEIGHT_FRESNEL,
compiler.stack_assign_if_linked(normal_in),
compiler.stack_assign(fresnel_out)));
@@ -3844,7 +4404,7 @@ void LayerWeightNode::compile(SVMCompiler& compiler)
if(!facing_out->links.empty()) {
compiler.add_node(NODE_LAYER_WEIGHT,
compiler.stack_assign_if_linked(blend_in),
- __float_as_int(blend_in->value.x),
+ __float_as_int(blend),
compiler.encode_uchar4(NODE_LAYER_WEIGHT_FACING,
compiler.stack_assign_if_linked(normal_in),
compiler.stack_assign(facing_out)));
@@ -3858,13 +4418,20 @@ void LayerWeightNode::compile(OSLCompiler& compiler)
/* Wireframe */
+NODE_DEFINE(WireframeNode)
+{
+ NodeType* type = NodeType::add("wireframe", create, NodeType::SHADER);
+
+ SOCKET_BOOLEAN(use_pixel_size, "Use Pixel Size", false);
+ SOCKET_IN_FLOAT(size, "Size", 0.01f);
+ SOCKET_OUT_FLOAT(fac, "Fac");
+
+ return type;
+}
+
WireframeNode::WireframeNode()
-: ShaderNode("wireframe")
+: ShaderNode(node_type)
{
- add_input("Size", SHADER_SOCKET_FLOAT, 0.01f);
- add_output("Fac", SHADER_SOCKET_FLOAT);
-
- use_pixel_size = false;
}
void WireframeNode::compile(SVMCompiler& compiler)
@@ -3897,17 +4464,25 @@ void WireframeNode::compile(OSLCompiler& compiler)
else {
compiler.parameter("bump_offset", "center");
}
- compiler.parameter("use_pixel_size", use_pixel_size);
+ compiler.parameter(this, "use_pixel_size");
compiler.add(this, "node_wireframe");
}
/* Wavelength */
+NODE_DEFINE(WavelengthNode)
+{
+ NodeType* type = NodeType::add("wavelength", create, NodeType::SHADER);
+
+ SOCKET_IN_FLOAT(wavelength, "Wavelength", 500.0f);
+ SOCKET_OUT_COLOR(color, "Color");
+
+ return type;
+}
+
WavelengthNode::WavelengthNode()
-: ShaderNode("wavelength")
+: ShaderNode(node_type)
{
- add_input("Wavelength", SHADER_SOCKET_FLOAT, 500.0f);
- add_output("Color", SHADER_SOCKET_COLOR);
}
void WavelengthNode::compile(SVMCompiler& compiler)
@@ -3927,25 +4502,26 @@ void WavelengthNode::compile(OSLCompiler& compiler)
/* Blackbody */
-BlackbodyNode::BlackbodyNode()
-: ShaderNode("blackbody")
+NODE_DEFINE(BlackbodyNode)
{
- add_input("Temperature", SHADER_SOCKET_FLOAT, 1200.0f);
- add_output("Color", SHADER_SOCKET_COLOR);
+ NodeType* type = NodeType::add("blackbody", create, NodeType::SHADER);
+
+ SOCKET_IN_FLOAT(temperature, "Temperature", 1200.0f);
+ SOCKET_OUT_COLOR(color, "Color");
+
+ return type;
}
-bool BlackbodyNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput *socket, float3 *optimized_value)
+BlackbodyNode::BlackbodyNode()
+: ShaderNode(node_type)
{
- ShaderInput *temperature_in = input("Temperature");
+}
- if(socket == output("Color")) {
- if(temperature_in->link == NULL) {
- *optimized_value = svm_math_blackbody_color(temperature_in->value.x);
- return true;
- }
+void BlackbodyNode::constant_fold(const ConstantFolder& folder)
+{
+ if(folder.all_inputs_constant()) {
+ folder.make_constant(svm_math_blackbody_color(temperature));
}
-
- return false;
}
void BlackbodyNode::compile(SVMCompiler& compiler)
@@ -3965,15 +4541,22 @@ void BlackbodyNode::compile(OSLCompiler& compiler)
/* Output */
+NODE_DEFINE(OutputNode)
+{
+ NodeType* type = NodeType::add("output", create, NodeType::SHADER);
+
+ SOCKET_IN_CLOSURE(surface, "Surface");
+ SOCKET_IN_CLOSURE(volume, "Volume");
+ SOCKET_IN_FLOAT(displacement, "Displacement", 0.0f);
+ SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f));
+
+ return type;
+}
+
OutputNode::OutputNode()
-: ShaderNode("output")
+: ShaderNode(node_type)
{
special_type = SHADER_SPECIAL_TYPE_OUTPUT;
-
- add_input("Surface", SHADER_SOCKET_CLOSURE);
- add_input("Volume", SHADER_SOCKET_CLOSURE);
- add_input("Displacement", SHADER_SOCKET_FLOAT);
- add_input("Normal", SHADER_SOCKET_NORMAL);
}
void OutputNode::compile(SVMCompiler& compiler)
@@ -3999,67 +4582,55 @@ void OutputNode::compile(OSLCompiler& compiler)
/* Math */
-MathNode::MathNode()
-: ShaderNode("math")
+NODE_DEFINE(MathNode)
{
- type = ustring("Add");
+ NodeType* type = NodeType::add("math", create, NodeType::SHADER);
- use_clamp = false;
+ static NodeEnum type_enum;
+ type_enum.insert("add", NODE_MATH_ADD);
+ type_enum.insert("subtract", NODE_MATH_SUBTRACT);
+ type_enum.insert("multiply", NODE_MATH_MULTIPLY);
+ type_enum.insert("divide", NODE_MATH_DIVIDE);
+ type_enum.insert("sine", NODE_MATH_SINE);
+ type_enum.insert("cosine", NODE_MATH_COSINE);
+ type_enum.insert("tangent", NODE_MATH_TANGENT);
+ type_enum.insert("arcsine", NODE_MATH_ARCSINE);
+ type_enum.insert("arccosine", NODE_MATH_ARCCOSINE);
+ type_enum.insert("arctangent", NODE_MATH_ARCTANGENT);
+ type_enum.insert("power", NODE_MATH_POWER);
+ type_enum.insert("logarithm", NODE_MATH_LOGARITHM);
+ type_enum.insert("minimum", NODE_MATH_MINIMUM);
+ type_enum.insert("maximum", NODE_MATH_MAXIMUM);
+ type_enum.insert("round", NODE_MATH_ROUND);
+ type_enum.insert("less_than", NODE_MATH_LESS_THAN);
+ type_enum.insert("greater_than", NODE_MATH_GREATER_THAN);
+ type_enum.insert("modulo", NODE_MATH_MODULO);
+ type_enum.insert("absolute", NODE_MATH_ABSOLUTE);
+ SOCKET_ENUM(type, "Type", type_enum, NODE_MATH_ADD);
- add_input("Value1", SHADER_SOCKET_FLOAT);
- add_input("Value2", SHADER_SOCKET_FLOAT);
- add_output("Value", SHADER_SOCKET_FLOAT);
-}
+ SOCKET_BOOLEAN(use_clamp, "Use Clamp", false);
-static ShaderEnum math_type_init()
-{
- ShaderEnum enm;
+ SOCKET_IN_FLOAT(value1, "Value1", 0.0f);
+ SOCKET_IN_FLOAT(value2, "Value2", 0.0f);
- enm.insert("Add", NODE_MATH_ADD);
- enm.insert("Subtract", NODE_MATH_SUBTRACT);
- enm.insert("Multiply", NODE_MATH_MULTIPLY);
- enm.insert("Divide", NODE_MATH_DIVIDE);
- enm.insert("Sine", NODE_MATH_SINE);
- enm.insert("Cosine", NODE_MATH_COSINE);
- enm.insert("Tangent", NODE_MATH_TANGENT);
- enm.insert("Arcsine", NODE_MATH_ARCSINE);
- enm.insert("Arccosine", NODE_MATH_ARCCOSINE);
- enm.insert("Arctangent", NODE_MATH_ARCTANGENT);
- enm.insert("Power", NODE_MATH_POWER);
- enm.insert("Logarithm", NODE_MATH_LOGARITHM);
- enm.insert("Minimum", NODE_MATH_MINIMUM);
- enm.insert("Maximum", NODE_MATH_MAXIMUM);
- enm.insert("Round", NODE_MATH_ROUND);
- enm.insert("Less Than", NODE_MATH_LESS_THAN);
- enm.insert("Greater Than", NODE_MATH_GREATER_THAN);
- enm.insert("Modulo", NODE_MATH_MODULO);
- enm.insert("Absolute", NODE_MATH_ABSOLUTE);
+ SOCKET_OUT_FLOAT(value, "Value");
- return enm;
+ return type;
}
-ShaderEnum MathNode::type_enum = math_type_init();
-
-bool MathNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput *socket, float3 *optimized_value)
+MathNode::MathNode()
+: ShaderNode(node_type)
{
- ShaderInput *value1_in = input("Value1");
- ShaderInput *value2_in = input("Value2");
-
- if(socket == output("Value")) {
- if(value1_in->link == NULL && value2_in->link == NULL) {
- optimized_value->x = svm_math((NodeMath)type_enum[type],
- value1_in->value.x,
- value2_in->value.x);
-
- if(use_clamp) {
- optimized_value->x = saturate(optimized_value->x);
- }
+}
- return true;
- }
+void MathNode::constant_fold(const ConstantFolder& folder)
+{
+ if(folder.all_inputs_constant()) {
+ folder.make_constant_clamp(svm_math(type, value1, value2), use_clamp);
+ }
+ else {
+ folder.fold_math(type, use_clamp);
}
-
- return false;
}
void MathNode::compile(SVMCompiler& compiler)
@@ -4068,10 +4639,7 @@ void MathNode::compile(SVMCompiler& compiler)
ShaderInput *value2_in = input("Value2");
ShaderOutput *value_out = output("Value");
- compiler.add_node(NODE_MATH,
- type_enum[type],
- compiler.stack_assign(value1_in),
- compiler.stack_assign(value2_in));
+ compiler.add_node(NODE_MATH, type, compiler.stack_assign(value1_in), compiler.stack_assign(value2_in));
compiler.add_node(NODE_MATH, compiler.stack_assign(value_out));
if(use_clamp) {
@@ -4082,66 +4650,62 @@ void MathNode::compile(SVMCompiler& compiler)
void MathNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("type", type);
- compiler.parameter("Clamp", use_clamp);
+ compiler.parameter(this, "type");
+ compiler.parameter(this, "use_clamp");
compiler.add(this, "node_math");
}
/* VectorMath */
-VectorMathNode::VectorMathNode()
-: ShaderNode("vector_math")
+NODE_DEFINE(VectorMathNode)
{
- type = ustring("Add");
+ NodeType* type = NodeType::add("vector_math", create, NodeType::SHADER);
- add_input("Vector1", SHADER_SOCKET_VECTOR);
- add_input("Vector2", SHADER_SOCKET_VECTOR);
- add_output("Value", SHADER_SOCKET_FLOAT);
- add_output("Vector", SHADER_SOCKET_VECTOR);
-}
+ static NodeEnum type_enum;
+ type_enum.insert("add", NODE_VECTOR_MATH_ADD);
+ type_enum.insert("subtract", NODE_VECTOR_MATH_SUBTRACT);
+ type_enum.insert("average", NODE_VECTOR_MATH_AVERAGE);
+ type_enum.insert("dot_product", NODE_VECTOR_MATH_DOT_PRODUCT);
+ type_enum.insert("cross_product", NODE_VECTOR_MATH_CROSS_PRODUCT);
+ type_enum.insert("normalize", NODE_VECTOR_MATH_NORMALIZE);
+ SOCKET_ENUM(type, "Type", type_enum, NODE_VECTOR_MATH_ADD);
-static ShaderEnum vector_math_type_init()
-{
- ShaderEnum enm;
+ SOCKET_IN_VECTOR(vector1, "Vector1", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_IN_VECTOR(vector2, "Vector2", make_float3(0.0f, 0.0f, 0.0f));
- enm.insert("Add", NODE_VECTOR_MATH_ADD);
- enm.insert("Subtract", NODE_VECTOR_MATH_SUBTRACT);
- enm.insert("Average", NODE_VECTOR_MATH_AVERAGE);
- enm.insert("Dot Product", NODE_VECTOR_MATH_DOT_PRODUCT);
- enm.insert("Cross Product", NODE_VECTOR_MATH_CROSS_PRODUCT);
- enm.insert("Normalize", NODE_VECTOR_MATH_NORMALIZE);
+ SOCKET_OUT_FLOAT(value, "Value");
+ SOCKET_OUT_VECTOR(vector, "Vector");
- return enm;
+ return type;
}
-ShaderEnum VectorMathNode::type_enum = vector_math_type_init();
-
-bool VectorMathNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput *socket, float3 *optimized_value)
+VectorMathNode::VectorMathNode()
+: ShaderNode(node_type)
{
- ShaderInput *vector1_in = input("Vector1");
- ShaderInput *vector2_in = input("Vector2");
+}
+void VectorMathNode::constant_fold(const ConstantFolder& folder)
+{
float value;
float3 vector;
- if(vector1_in->link == NULL && vector2_in->link == NULL) {
+ if(folder.all_inputs_constant()) {
svm_vector_math(&value,
&vector,
- (NodeVectorMath)type_enum[type],
- vector1_in->value,
- vector2_in->value);
+ type,
+ vector1,
+ vector2);
- if(socket == output("Value")) {
- optimized_value->x = value;
- return true;
+ if(folder.output == output("Value")) {
+ folder.make_constant(value);
}
- else if(socket == output("Vector")) {
- *optimized_value = vector;
- return true;
+ else if(folder.output == output("Vector")) {
+ folder.make_constant(vector);
}
}
-
- return false;
+ else {
+ folder.fold_vector_math(type);
+ }
}
void VectorMathNode::compile(SVMCompiler& compiler)
@@ -4152,7 +4716,7 @@ void VectorMathNode::compile(SVMCompiler& compiler)
ShaderOutput *vector_out = output("Vector");
compiler.add_node(NODE_VECTOR_MATH,
- type_enum[type],
+ type,
compiler.stack_assign(vector1_in),
compiler.stack_assign(vector2_in));
compiler.add_node(NODE_VECTOR_MATH,
@@ -4162,90 +4726,88 @@ void VectorMathNode::compile(SVMCompiler& compiler)
void VectorMathNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("type", type);
+ compiler.parameter(this, "type");
compiler.add(this, "node_vector_math");
}
/* VectorTransform */
-VectorTransformNode::VectorTransformNode()
-: ShaderNode("vector_transform")
+NODE_DEFINE(VectorTransformNode)
{
- type = ustring("Vector");
- convert_from = ustring("world");
- convert_to = ustring("object");
+ NodeType* type = NodeType::add("vector_transform", create, NodeType::SHADER);
- add_input("Vector", SHADER_SOCKET_VECTOR);
- add_output("Vector", SHADER_SOCKET_VECTOR);
-}
+ static NodeEnum type_enum;
+ type_enum.insert("vector", NODE_VECTOR_TRANSFORM_TYPE_VECTOR);
+ type_enum.insert("point", NODE_VECTOR_TRANSFORM_TYPE_POINT);
+ type_enum.insert("normal", NODE_VECTOR_TRANSFORM_TYPE_NORMAL);
+ SOCKET_ENUM(type, "Type", type_enum, NODE_VECTOR_TRANSFORM_TYPE_VECTOR);
-static ShaderEnum vector_transform_type_init()
-{
- ShaderEnum enm;
+ static NodeEnum space_enum;
+ space_enum.insert("world", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD);
+ space_enum.insert("object", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT);
+ space_enum.insert("camera", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA);
+ SOCKET_ENUM(convert_from, "Convert From", space_enum, NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD);
+ SOCKET_ENUM(convert_to, "Convert To", space_enum, NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT);
- enm.insert("Vector", NODE_VECTOR_TRANSFORM_TYPE_VECTOR);
- enm.insert("Point", NODE_VECTOR_TRANSFORM_TYPE_POINT);
- enm.insert("Normal", NODE_VECTOR_TRANSFORM_TYPE_NORMAL);
+ SOCKET_IN_VECTOR(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_OUT_VECTOR(vector, "Vector");
- return enm;
+ return type;
}
-static ShaderEnum vector_transform_convert_space_init()
+VectorTransformNode::VectorTransformNode()
+: ShaderNode(node_type)
{
- ShaderEnum enm;
-
- enm.insert("world", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD);
- enm.insert("object", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT);
- enm.insert("camera", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA);
-
- return enm;
}
-ShaderEnum VectorTransformNode::type_enum = vector_transform_type_init();
-ShaderEnum VectorTransformNode::convert_space_enum = vector_transform_convert_space_init();
-
void VectorTransformNode::compile(SVMCompiler& compiler)
{
ShaderInput *vector_in = input("Vector");
ShaderOutput *vector_out = output("Vector");
compiler.add_node(NODE_VECTOR_TRANSFORM,
- compiler.encode_uchar4(type_enum[type],
- convert_space_enum[convert_from],
- convert_space_enum[convert_to]),
+ compiler.encode_uchar4(type, convert_from, convert_to),
compiler.encode_uchar4(compiler.stack_assign(vector_in),
compiler.stack_assign(vector_out)));
}
void VectorTransformNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("type", type);
- compiler.parameter("convert_from", convert_from);
- compiler.parameter("convert_to", convert_to);
+ compiler.parameter(this, "type");
+ compiler.parameter(this, "convert_from");
+ compiler.parameter(this, "convert_to");
compiler.add(this, "node_vector_transform");
}
/* BumpNode */
-BumpNode::BumpNode()
-: ShaderNode("bump")
+NODE_DEFINE(BumpNode)
{
- invert = false;
+ NodeType* type = NodeType::add("bump", create, NodeType::SHADER);
- special_type = SHADER_SPECIAL_TYPE_BUMP;
+ SOCKET_BOOLEAN(invert, "Invert", false);
+ SOCKET_BOOLEAN(use_object_space, "UseObjectSpace", false);
/* this input is used by the user, but after graph transform it is no longer
* used and moved to sampler center/x/y instead */
- add_input("Height", SHADER_SOCKET_FLOAT);
+ SOCKET_IN_FLOAT(height, "Height", 1.0f);
+
+ SOCKET_IN_FLOAT(sample_center, "SampleCenter", 0.0f);
+ SOCKET_IN_FLOAT(sample_x, "SampleX", 0.0f);
+ SOCKET_IN_FLOAT(sample_y, "SampleY", 0.0f);
+ SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
+ SOCKET_IN_FLOAT(strength, "Strength", 1.0f);
+ SOCKET_IN_FLOAT(distance, "Distance", 0.1f);
- add_input("SampleCenter", SHADER_SOCKET_FLOAT);
- add_input("SampleX", SHADER_SOCKET_FLOAT);
- add_input("SampleY", SHADER_SOCKET_FLOAT);
- add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL);
- add_input("Strength", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("Distance", SHADER_SOCKET_FLOAT, 0.1f);
+ SOCKET_OUT_NORMAL(normal, "Normal");
- add_output("Normal", SHADER_SOCKET_NORMAL);
+ return type;
+}
+
+BumpNode::BumpNode()
+: ShaderNode(node_type)
+{
+ special_type = SHADER_SPECIAL_TYPE_BUMP;
}
void BumpNode::compile(SVMCompiler& compiler)
@@ -4263,7 +4825,8 @@ void BumpNode::compile(SVMCompiler& compiler)
compiler.encode_uchar4(
compiler.stack_assign_if_linked(normal_in),
compiler.stack_assign(distance_in),
- invert),
+ invert,
+ use_object_space),
compiler.encode_uchar4(
compiler.stack_assign(center_in),
compiler.stack_assign(dx_in),
@@ -4274,13 +4837,12 @@ void BumpNode::compile(SVMCompiler& compiler)
void BumpNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("invert", invert);
+ compiler.parameter(this, "invert");
+ compiler.parameter(this, "use_object_space");
compiler.add(this, "node_bump");
}
-bool BumpNode::constant_fold(ShaderGraph *graph,
- ShaderOutput * /*socket*/,
- float3 * /*optimized_value*/)
+void BumpNode::constant_fold(const ConstantFolder& folder)
{
ShaderInput *height_in = input("Height");
ShaderInput *normal_in = input("Normal");
@@ -4288,122 +4850,220 @@ bool BumpNode::constant_fold(ShaderGraph *graph,
if(height_in->link == NULL) {
if(normal_in->link == NULL) {
GeometryNode *geom = new GeometryNode();
- graph->add(geom);
- graph->relink(this, outputs[0], geom->output("Normal"));
+ folder.graph->add(geom);
+ folder.bypass(geom->output("Normal"));
}
else {
- graph->relink(this, outputs[0], normal_in->link);
+ folder.bypass(normal_in->link);
}
- return true;
}
/* TODO(sergey): Ignore bump with zero strength. */
-
- return false;
}
-/* RGBCurvesNode */
-RGBCurvesNode::RGBCurvesNode()
-: ShaderNode("rgb_curves")
+/* Curve node */
+
+CurvesNode::CurvesNode(const NodeType *node_type)
+: ShaderNode(node_type)
{
- add_input("Fac", SHADER_SOCKET_FLOAT);
- add_input("Color", SHADER_SOCKET_COLOR);
- add_output("Color", SHADER_SOCKET_COLOR);
+}
+
+void CurvesNode::constant_fold(const ConstantFolder& folder, ShaderInput *value_in)
+{
+ ShaderInput *fac_in = input("Fac");
+
+ /* evaluate fully constant node */
+ if(folder.all_inputs_constant()) {
+ if(curves.size() == 0) {
+ return;
+ }
- min_x = 0.0f;
- max_x = 1.0f;
+ float3 pos = (value - make_float3(min_x, min_x, min_x)) / (max_x - min_x);
+ float3 result;
+
+ result[0] = rgb_ramp_lookup(curves.data(), pos[0], true, true, curves.size()).x;
+ result[1] = rgb_ramp_lookup(curves.data(), pos[1], true, true, curves.size()).y;
+ result[2] = rgb_ramp_lookup(curves.data(), pos[2], true, true, curves.size()).z;
+
+ folder.make_constant(interp(value, result, fac));
+ }
+ /* remove no-op node */
+ else if(!fac_in->link && fac == 0.0f) {
+ /* link is not null because otherwise all inputs are constant */
+ folder.bypass(value_in->link);
+ }
}
-void RGBCurvesNode::compile(SVMCompiler& compiler)
+void CurvesNode::compile(SVMCompiler& compiler, int type, ShaderInput *value_in, ShaderOutput *value_out)
{
+ if(curves.size() == 0)
+ return;
+
ShaderInput *fac_in = input("Fac");
- ShaderInput *color_in = input("Color");
- ShaderOutput *color_out = output("Color");
- compiler.add_node(NODE_RGB_CURVES,
+ compiler.add_node(type,
compiler.encode_uchar4(compiler.stack_assign(fac_in),
- compiler.stack_assign(color_in),
- compiler.stack_assign(color_out)),
+ compiler.stack_assign(value_in),
+ compiler.stack_assign(value_out)),
__float_as_int(min_x),
__float_as_int(max_x));
- compiler.add_array(curves, RAMP_TABLE_SIZE);
+
+ compiler.add_node(curves.size());
+ for(int i = 0; i < curves.size(); i++)
+ compiler.add_node(float3_to_float4(curves[i]));
}
-void RGBCurvesNode::compile(OSLCompiler& compiler)
+void CurvesNode::compile(OSLCompiler& compiler, const char* name)
{
- float ramp[RAMP_TABLE_SIZE][3];
+ if(curves.size() == 0)
+ return;
- for(int i = 0; i < RAMP_TABLE_SIZE; ++i) {
- ramp[i][0] = curves[i].x;
- ramp[i][1] = curves[i].y;
- ramp[i][2] = curves[i].z;
- }
+ compiler.parameter_color_array("ramp", curves);
+ compiler.parameter(this, "min_x");
+ compiler.parameter(this, "max_x");
+ compiler.add(this, name);
+}
+
+void CurvesNode::compile(SVMCompiler& /*compiler*/)
+{
+ assert(0);
+}
+
+void CurvesNode::compile(OSLCompiler& /*compiler*/)
+{
+ assert(0);
+}
+
+/* RGBCurvesNode */
+
+NODE_DEFINE(RGBCurvesNode)
+{
+ NodeType* type = NodeType::add("rgb_curves", create, NodeType::SHADER);
- compiler.parameter_color_array("ramp", ramp, RAMP_TABLE_SIZE);
- compiler.parameter("min_x", min_x);
- compiler.parameter("max_x", max_x);
- compiler.add(this, "node_rgb_curves");
+ SOCKET_COLOR_ARRAY(curves, "Curves", array<float3>());
+ SOCKET_FLOAT(min_x, "Min X", 0.0f);
+ SOCKET_FLOAT(max_x, "Max X", 1.0f);
+
+ SOCKET_IN_FLOAT(fac, "Fac", 0.0f);
+ SOCKET_IN_COLOR(value, "Color", make_float3(0.0f, 0.0f, 0.0f));
+
+ SOCKET_OUT_COLOR(value, "Color");
+
+ return type;
+}
+
+RGBCurvesNode::RGBCurvesNode()
+: CurvesNode(node_type)
+{
+}
+
+void RGBCurvesNode::constant_fold(const ConstantFolder& folder)
+{
+ CurvesNode::constant_fold(folder, input("Color"));
+}
+
+void RGBCurvesNode::compile(SVMCompiler& compiler)
+{
+ CurvesNode::compile(compiler, NODE_RGB_CURVES, input("Color"), output("Color"));
+}
+
+void RGBCurvesNode::compile(OSLCompiler& compiler)
+{
+ CurvesNode::compile(compiler, "node_rgb_curves");
}
/* VectorCurvesNode */
+NODE_DEFINE(VectorCurvesNode)
+{
+ NodeType* type = NodeType::add("vector_curves", create, NodeType::SHADER);
+
+ SOCKET_VECTOR_ARRAY(curves, "Curves", array<float3>());
+ SOCKET_FLOAT(min_x, "Min X", 0.0f);
+ SOCKET_FLOAT(max_x, "Max X", 1.0f);
+
+ SOCKET_IN_FLOAT(fac, "Fac", 0.0f);
+ SOCKET_IN_VECTOR(value, "Vector", make_float3(0.0f, 0.0f, 0.0f));
+
+ SOCKET_OUT_VECTOR(value, "Vector");
+
+ return type;
+}
+
VectorCurvesNode::VectorCurvesNode()
-: ShaderNode("vector_curves")
+: CurvesNode(node_type)
{
- add_input("Fac", SHADER_SOCKET_FLOAT);
- add_input("Vector", SHADER_SOCKET_VECTOR);
- add_output("Vector", SHADER_SOCKET_VECTOR);
+}
- min_x = 0.0f;
- max_x = 1.0f;
+void VectorCurvesNode::constant_fold(const ConstantFolder& folder)
+{
+ CurvesNode::constant_fold(folder, input("Vector"));
}
void VectorCurvesNode::compile(SVMCompiler& compiler)
{
- ShaderInput *fac_in = input("Fac");
- ShaderInput *vector_in = input("Vector");
- ShaderOutput *vector_out = output("Vector");
-
- compiler.add_node(NODE_VECTOR_CURVES,
- compiler.encode_uchar4(compiler.stack_assign(fac_in),
- compiler.stack_assign(vector_in),
- compiler.stack_assign(vector_out)),
- __float_as_int(min_x),
- __float_as_int(max_x));
- compiler.add_array(curves, RAMP_TABLE_SIZE);
+ CurvesNode::compile(compiler, NODE_VECTOR_CURVES, input("Vector"), output("Vector"));
}
void VectorCurvesNode::compile(OSLCompiler& compiler)
{
- float ramp[RAMP_TABLE_SIZE][3];
-
- for(int i = 0; i < RAMP_TABLE_SIZE; ++i) {
- ramp[i][0] = curves[i].x;
- ramp[i][1] = curves[i].y;
- ramp[i][2] = curves[i].z;
- }
-
- compiler.parameter_color_array("ramp", ramp, RAMP_TABLE_SIZE);
- compiler.parameter("min_x", min_x);
- compiler.parameter("max_x", max_x);
- compiler.add(this, "node_vector_curves");
+ CurvesNode::compile(compiler, "node_vector_curves");
}
/* RGBRampNode */
+NODE_DEFINE(RGBRampNode)
+{
+ NodeType* type = NodeType::add("rgb_ramp", create, NodeType::SHADER);
+
+ SOCKET_COLOR_ARRAY(ramp, "Ramp", array<float3>());
+ SOCKET_FLOAT_ARRAY(ramp_alpha, "Ramp Alpha", array<float>());
+ SOCKET_BOOLEAN(interpolate, "Interpolate", true);
+
+ SOCKET_IN_FLOAT(fac, "Fac", 0.0f);
+
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(alpha, "Alpha");
+
+ return type;
+}
+
RGBRampNode::RGBRampNode()
-: ShaderNode("rgb_ramp")
+: ShaderNode(node_type)
+{
+}
+
+void RGBRampNode::constant_fold(const ConstantFolder& folder)
{
- add_input("Fac", SHADER_SOCKET_FLOAT);
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Alpha", SHADER_SOCKET_FLOAT);
+ if(ramp.size() == 0 || ramp.size() != ramp_alpha.size())
+ return;
+
+ if(folder.all_inputs_constant()) {
+ float f = clamp(fac, 0.0f, 1.0f) * (ramp.size() - 1);
- interpolate = true;
+ /* clamp int as well in case of NaN */
+ int i = clamp((int)f, 0, ramp.size()-1);
+ float t = f - (float)i;
+
+ bool use_lerp = interpolate && t > 0.0f;
+
+ if(folder.output == output("Color")) {
+ float3 color = rgb_ramp_lookup(ramp.data(), fac, use_lerp, false, ramp.size());
+ folder.make_constant(color);
+ }
+ else if(folder.output == output("Alpha")) {
+ float alpha = float_ramp_lookup(ramp_alpha.data(), fac, use_lerp, false, ramp_alpha.size());
+ folder.make_constant(alpha);
+ }
+ }
}
void RGBRampNode::compile(SVMCompiler& compiler)
{
+ if(ramp.size() == 0 || ramp.size() != ramp_alpha.size())
+ return;
+
ShaderInput *fac_in = input("Fac");
ShaderOutput *color_out = output("Color");
ShaderOutput *alpha_out = output("Alpha");
@@ -4414,37 +5074,39 @@ void RGBRampNode::compile(SVMCompiler& compiler)
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(alpha_out)),
interpolate);
- compiler.add_array(ramp, RAMP_TABLE_SIZE);
+
+ compiler.add_node(ramp.size());
+ for(int i = 0; i < ramp.size(); i++)
+ compiler.add_node(make_float4(ramp[i].x, ramp[i].y, ramp[i].z, ramp_alpha[i]));
}
void RGBRampNode::compile(OSLCompiler& compiler)
{
- /* OSL shader only takes separate RGB and A array, split the RGBA base array */
- /* NB: cycles float3 type is actually 4 floats! need to use an explicit array */
- float ramp_color[RAMP_TABLE_SIZE][3];
- float ramp_alpha[RAMP_TABLE_SIZE];
-
- for(int i = 0; i < RAMP_TABLE_SIZE; ++i) {
- ramp_color[i][0] = ramp[i].x;
- ramp_color[i][1] = ramp[i].y;
- ramp_color[i][2] = ramp[i].z;
- ramp_alpha[i] = ramp[i].w;
- }
+ if(ramp.size() == 0 || ramp.size() != ramp_alpha.size())
+ return;
- compiler.parameter_color_array("ramp_color", ramp_color, RAMP_TABLE_SIZE);
- compiler.parameter_array("ramp_alpha", ramp_alpha, RAMP_TABLE_SIZE);
- compiler.parameter("ramp_interpolate", interpolate);
+ compiler.parameter_color_array("ramp_color", ramp);
+ compiler.parameter_array("ramp_alpha", ramp_alpha.data(), ramp_alpha.size());
+ compiler.parameter(this, "interpolate");
compiler.add(this, "node_rgb_ramp");
}
/* Set Normal Node */
+NODE_DEFINE(SetNormalNode)
+{
+ NodeType* type = NodeType::add("set_normal", create, NodeType::SHADER);
+
+ SOCKET_IN_VECTOR(direction, "Direction", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_OUT_NORMAL(normal, "Normal");
+
+ return type;
+}
+
SetNormalNode::SetNormalNode()
-: ShaderNode("set_normal")
+: ShaderNode(node_type)
{
- add_input("Direction", SHADER_SOCKET_VECTOR);
- add_output("Normal", SHADER_SOCKET_NORMAL);
}
void SetNormalNode::compile(SVMCompiler& compiler)
@@ -4462,20 +5124,73 @@ void SetNormalNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_set_normal");
}
-/* OSLScriptNode */
+/* OSLNode */
-OSLScriptNode::OSLScriptNode()
-: ShaderNode("osl_script")
+OSLNode::OSLNode()
+: ShaderNode(new NodeType(NodeType::SHADER))
{
special_type = SHADER_SPECIAL_TYPE_SCRIPT;
}
-void OSLScriptNode::compile(SVMCompiler& /*compiler*/)
+OSLNode::~OSLNode()
+{
+ delete type;
+}
+
+ShaderNode *OSLNode::clone() const
+{
+ return OSLNode::create(this->inputs.size(), this);
+}
+
+OSLNode* OSLNode::create(size_t num_inputs, const OSLNode *from)
+{
+ /* allocate space for the node itself and parameters, aligned to 16 bytes
+ * assuming that's the most parameter types need */
+ size_t node_size = align_up(sizeof(OSLNode), 16);
+ size_t inputs_size = align_up(SocketType::max_size(), 16) * num_inputs;
+
+ char *node_memory = (char*) operator new(node_size + inputs_size);
+ memset(node_memory, 0, node_size + inputs_size);
+
+ if(!from) {
+ return new(node_memory) OSLNode();
+ }
+ else {
+ /* copy input default values and node type for cloning */
+ memcpy(node_memory + node_size, (char*)from + node_size, inputs_size);
+
+ OSLNode *node = new(node_memory) OSLNode(*from);
+ node->type = new NodeType(*(from->type));
+ return node;
+ }
+}
+
+char* OSLNode::input_default_value()
+{
+ /* pointer to default value storage, which is the same as our actual value */
+ size_t num_inputs = type->inputs.size();
+ size_t inputs_size = align_up(SocketType::max_size(), 16) * num_inputs;
+ return (char*)this + align_up(sizeof(OSLNode), 16) + inputs_size;
+}
+
+void OSLNode::add_input(ustring name, SocketType::Type socket_type)
+{
+ char *memory = input_default_value();
+ size_t offset = memory - (char*)this;
+ const_cast<NodeType*>(type)->register_input(name, name, socket_type, offset, memory, NULL, NULL, SocketType::LINKABLE);
+}
+
+void OSLNode::add_output(ustring name, SocketType::Type socket_type)
+{
+ const_cast<NodeType*>(type)->register_output(name, name, socket_type);
+}
+
+void OSLNode::compile(SVMCompiler&)
{
/* doesn't work for SVM, obviously ... */
}
-void OSLScriptNode::compile(OSLCompiler& compiler)
+void OSLNode::compile(OSLCompiler& compiler)
{
if(!filepath.empty())
compiler.add(this, filepath.c_str(), true);
@@ -4485,37 +5200,37 @@ void OSLScriptNode::compile(OSLCompiler& compiler)
/* Normal Map */
-static ShaderEnum normal_map_space_init()
+NODE_DEFINE(NormalMapNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("normal_map", create, NodeType::SHADER);
- enm.insert("Tangent", NODE_NORMAL_MAP_TANGENT);
- enm.insert("Object", NODE_NORMAL_MAP_OBJECT);
- enm.insert("World", NODE_NORMAL_MAP_WORLD);
- enm.insert("Blender Object", NODE_NORMAL_MAP_BLENDER_OBJECT);
- enm.insert("Blender World", NODE_NORMAL_MAP_BLENDER_WORLD);
+ static NodeEnum space_enum;
+ space_enum.insert("tangent", NODE_NORMAL_MAP_TANGENT);
+ space_enum.insert("object", NODE_NORMAL_MAP_OBJECT);
+ space_enum.insert("world", NODE_NORMAL_MAP_WORLD);
+ space_enum.insert("blender_object", NODE_NORMAL_MAP_BLENDER_OBJECT);
+ space_enum.insert("blender_world", NODE_NORMAL_MAP_BLENDER_WORLD);
+ SOCKET_ENUM(space, "Space", space_enum, NODE_TANGENT_RADIAL);
- return enm;
-}
+ SOCKET_STRING(attribute, "Attribute", ustring(""));
-ShaderEnum NormalMapNode::space_enum = normal_map_space_init();
+ SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
+ SOCKET_IN_FLOAT(strength, "Strength", 1.0f);
+ SOCKET_IN_COLOR(color, "Color", make_float3(0.5f, 0.5f, 1.0f));
-NormalMapNode::NormalMapNode()
-: ShaderNode("normal_map")
-{
- space = ustring("Tangent");
- attribute = ustring("");
+ SOCKET_OUT_NORMAL(normal, "Normal");
- add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL);
- add_input("Strength", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("Color", SHADER_SOCKET_COLOR);
+ return type;
+}
- add_output("Normal", SHADER_SOCKET_NORMAL);
+NormalMapNode::NormalMapNode()
+: ShaderNode(node_type)
+{
}
void NormalMapNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
- if(shader->has_surface && space == ustring("Tangent")) {
+ if(shader->has_surface && space == NODE_NORMAL_MAP_TANGENT) {
if(attribute == ustring("")) {
attributes->add(ATTR_STD_UV_TANGENT);
attributes->add(ATTR_STD_UV_TANGENT_SIGN);
@@ -4538,7 +5253,7 @@ void NormalMapNode::compile(SVMCompiler& compiler)
ShaderOutput *normal_out = output("Normal");
int attr = 0, attr_sign = 0;
- if(space == ustring("Tangent")) {
+ if(space == NODE_NORMAL_MAP_TANGENT) {
if(attribute == ustring("")) {
attr = compiler.attribute(ATTR_STD_UV_TANGENT);
attr_sign = compiler.attribute(ATTR_STD_UV_TANGENT_SIGN);
@@ -4554,13 +5269,13 @@ void NormalMapNode::compile(SVMCompiler& compiler)
compiler.stack_assign(color_in),
compiler.stack_assign(strength_in),
compiler.stack_assign(normal_out),
- space_enum[space]),
+ space),
attr, attr_sign);
}
void NormalMapNode::compile(OSLCompiler& compiler)
{
- if(space == ustring("Tangent")) {
+ if(space == NODE_NORMAL_MAP_TANGENT) {
if(attribute == ustring("")) {
compiler.parameter("attr_name", ustring("geom:tangent"));
compiler.parameter("attr_sign_name", ustring("geom:tangent_sign"));
@@ -4571,52 +5286,44 @@ void NormalMapNode::compile(OSLCompiler& compiler)
}
}
- compiler.parameter("space", space);
-
+ compiler.parameter(this, "space");
compiler.add(this, "node_normal_map");
}
/* Tangent */
-static ShaderEnum tangent_direction_type_init()
+NODE_DEFINE(TangentNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("tangent", create, NodeType::SHADER);
- enm.insert("Radial", NODE_TANGENT_RADIAL);
- enm.insert("UV Map", NODE_TANGENT_UVMAP);
+ static NodeEnum direction_type_enum;
+ direction_type_enum.insert("radial", NODE_TANGENT_RADIAL);
+ direction_type_enum.insert("uv_map", NODE_TANGENT_UVMAP);
+ SOCKET_ENUM(direction_type, "Direction Type", direction_type_enum, NODE_TANGENT_RADIAL);
- return enm;
-}
+ static NodeEnum axis_enum;
+ axis_enum.insert("x", NODE_TANGENT_AXIS_X);
+ axis_enum.insert("y", NODE_TANGENT_AXIS_Y);
+ axis_enum.insert("z", NODE_TANGENT_AXIS_Z);
+ SOCKET_ENUM(axis, "Axis", axis_enum, NODE_TANGENT_AXIS_X);
-static ShaderEnum tangent_axis_init()
-{
- ShaderEnum enm;
+ SOCKET_STRING(attribute, "Attribute", ustring(""));
- enm.insert("X", NODE_TANGENT_AXIS_X);
- enm.insert("Y", NODE_TANGENT_AXIS_Y);
- enm.insert("Z", NODE_TANGENT_AXIS_Z);
+ SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
+ SOCKET_OUT_NORMAL(tangent, "Tangent");
- return enm;
+ return type;
}
-ShaderEnum TangentNode::direction_type_enum = tangent_direction_type_init();
-ShaderEnum TangentNode::axis_enum = tangent_axis_init();
-
TangentNode::TangentNode()
-: ShaderNode("tangent")
+: ShaderNode(node_type)
{
- direction_type = ustring("Radial");
- axis = ustring("X");
- attribute = ustring("");
-
- add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL);
- add_output("Tangent", SHADER_SOCKET_NORMAL);
}
void TangentNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
if(shader->has_surface) {
- if(direction_type == ustring("UV Map")) {
+ if(direction_type == NODE_TANGENT_UVMAP) {
if(attribute == ustring(""))
attributes->add(ATTR_STD_UV_TANGENT);
else
@@ -4634,7 +5341,7 @@ void TangentNode::compile(SVMCompiler& compiler)
ShaderOutput *tangent_out = output("Tangent");
int attr;
- if(direction_type == ustring("UV Map")) {
+ if(direction_type == NODE_TANGENT_UVMAP) {
if(attribute == ustring(""))
attr = compiler.attribute(ATTR_STD_UV_TANGENT);
else
@@ -4646,26 +5353,33 @@ void TangentNode::compile(SVMCompiler& compiler)
compiler.add_node(NODE_TANGENT,
compiler.encode_uchar4(
compiler.stack_assign(tangent_out),
- direction_type_enum[direction_type],
- axis_enum[axis]), attr);
+ direction_type,
+ axis), attr);
}
void TangentNode::compile(OSLCompiler& compiler)
{
- if(direction_type == ustring("UV Map")) {
+ if(direction_type == NODE_TANGENT_UVMAP) {
if(attribute == ustring(""))
compiler.parameter("attr_name", ustring("geom:tangent"));
else
compiler.parameter("attr_name", ustring((string(attribute.c_str()) + ".tangent").c_str()));
}
- compiler.parameter("direction_type", direction_type);
- compiler.parameter("axis", axis);
+ compiler.parameter(this, "direction_type");
+ compiler.parameter(this, "axis");
compiler.add(this, "node_tangent");
}
+NODE_DEFINE(OpenVDBNode)
+{
+ NodeType* type = NodeType::add("openvdb", create, NodeType::SHADER);
+
+ return type;
+}
+
OpenVDBNode::OpenVDBNode()
-: ShaderNode("openvdb")
+: ShaderNode(node_type)
{
filename = "";
volume_manager = NULL;
@@ -4690,12 +5404,12 @@ void OpenVDBNode::compile(SVMCompiler& compiler)
int type = NODE_VDB_FLOAT;
- if(out->type == SHADER_SOCKET_VECTOR || out->type == SHADER_SOCKET_COLOR) {
+ if(out->type() == SocketType::VECTOR || out->type() == SocketType::COLOR) {
type = NODE_VDB_FLOAT3;
}
grid_slot = volume_manager->add_volume(filename.string(),
- output_names[i].string(),
+ output_sockets[i].name.string(),
sampling, type);
if(grid_slot == -1) {
diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h
index de1d9fde69d..73c02bbb3ba 100644
--- a/intern/cycles/render/nodes.h
+++ b/intern/cycles/render/nodes.h
@@ -18,6 +18,7 @@
#define __NODES_H__
#include "graph.h"
+#include "node.h"
#include "util_string.h"
@@ -36,6 +37,7 @@ public:
Transform compute_transform();
bool skip();
void compile(SVMCompiler& compiler, int offset_in, int offset_out);
+ int compile(SVMCompiler& compiler, ShaderInput *vector_in);
void compile(OSLCompiler &compiler);
int compile_begin(SVMCompiler& compiler, ShaderInput *vector_in);
@@ -56,39 +58,20 @@ public:
enum Projection { FLAT, CUBE, TUBE, SPHERE };
Projection projection;
-
- bool equals(const TextureMapping& other) {
- return translation == other.translation &&
- rotation == other.rotation &&
- scale == other.scale &&
- use_minmax == other.use_minmax &&
- min == other.min &&
- max == other.max &&
- type == other.type &&
- x_mapping == other.x_mapping &&
- y_mapping == other.y_mapping &&
- z_mapping == other.z_mapping &&
- projection == other.projection;
- }
};
/* Nodes */
class TextureNode : public ShaderNode {
public:
- TextureNode(const char *name_) : ShaderNode(name_) {}
+ explicit TextureNode(const NodeType *node_type) : ShaderNode(node_type) {}
TextureMapping tex_mapping;
-
- virtual bool equals(const ShaderNode *other) {
- return ShaderNode::equals(other) &&
- tex_mapping.equals(((const TextureNode*)other)->tex_mapping);
- }
};
/* Any node which uses image manager's slot should be a subclass of this one. */
class ImageSlotTextureNode : public TextureNode {
public:
- ImageSlotTextureNode(const char *name_) : TextureNode(name_) {
+ explicit ImageSlotTextureNode(const NodeType *node_type) : TextureNode(node_type) {
special_type = SHADER_SPECIAL_TYPE_IMAGE_SLOT;
}
int slot;
@@ -105,30 +88,22 @@ public:
int is_float;
bool is_linear;
bool use_alpha;
- string filename;
+ ustring filename;
void *builtin_data;
- ustring color_space;
- ustring projection;
+ NodeImageColorSpace color_space;
+ NodeImageProjection projection;
InterpolationType interpolation;
ExtensionType extension;
float projection_blend;
bool animated;
+ float3 vector;
- static ShaderEnum color_space_enum;
- static ShaderEnum projection_enum;
-
- virtual bool equals(const ShaderNode *other) {
- const ImageTextureNode *image_node = (const ImageTextureNode*)other;
+ virtual bool equals(const ShaderNode& other)
+ {
+ const ImageTextureNode& image_node = (const ImageTextureNode&)other;
return ImageSlotTextureNode::equals(other) &&
- use_alpha == image_node->use_alpha &&
- filename == image_node->filename &&
- builtin_data == image_node->builtin_data &&
- color_space == image_node->color_space &&
- projection == image_node->projection &&
- interpolation == image_node->interpolation &&
- extension == image_node->extension &&
- projection_blend == image_node->projection_blend &&
- animated == image_node->animated;
+ builtin_data == image_node.builtin_data &&
+ animated == image_node.animated;
}
};
@@ -144,26 +119,20 @@ public:
int is_float;
bool is_linear;
bool use_alpha;
- string filename;
+ ustring filename;
void *builtin_data;
- ustring color_space;
- ustring projection;
+ NodeImageColorSpace color_space;
+ NodeEnvironmentProjection projection;
InterpolationType interpolation;
bool animated;
+ float3 vector;
- static ShaderEnum color_space_enum;
- static ShaderEnum projection_enum;
-
- virtual bool equals(const ShaderNode *other) {
- const EnvironmentTextureNode *env_node = (const EnvironmentTextureNode*)other;
+ virtual bool equals(const ShaderNode& other)
+ {
+ const EnvironmentTextureNode& env_node = (const EnvironmentTextureNode&)other;
return ImageSlotTextureNode::equals(other) &&
- use_alpha == env_node->use_alpha &&
- filename == env_node->filename &&
- builtin_data == env_node->builtin_data &&
- color_space == env_node->color_space &&
- projection == env_node->projection &&
- interpolation == env_node->interpolation &&
- animated == env_node->animated;
+ builtin_data == env_node.builtin_data &&
+ animated == env_node.animated;
}
};
@@ -173,29 +142,24 @@ public:
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
+ NodeSkyType type;
float3 sun_direction;
float turbidity;
float ground_albedo;
-
- ustring type;
- static ShaderEnum type_enum;
-
- virtual bool equals(const ShaderNode *other) {
- const SkyTextureNode *sky_node = (const SkyTextureNode*)other;
- return TextureNode::equals(other) &&
- sun_direction == sky_node->sun_direction &&
- turbidity == sky_node->turbidity &&
- ground_albedo == sky_node->ground_albedo &&
- type == sky_node->type;
- }
+ float3 vector;
};
class OutputNode : public ShaderNode {
public:
SHADER_NODE_CLASS(OutputNode)
+ void *surface;
+ void *volume;
+ float displacement;
+ float3 normal;
+
/* Don't allow output node de-duplication. */
- virtual bool equals(const ShaderNode * /*other*/) { return false; }
+ virtual bool equals(const ShaderNode& /*other*/) { return false; }
};
class GradientTextureNode : public TextureNode {
@@ -204,19 +168,16 @@ public:
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
- ustring type;
- static ShaderEnum type_enum;
-
- virtual bool equals(const ShaderNode *other) {
- const GradientTextureNode *gradient_node = (const GradientTextureNode*)other;
- return TextureNode::equals(other) &&
- type == gradient_node->type;
- }
+ NodeGradientType type;
+ float3 vector;
};
class NoiseTextureNode : public TextureNode {
public:
SHADER_NODE_CLASS(NoiseTextureNode)
+
+ float scale, detail, distortion;
+ float3 vector;
};
class VoronoiTextureNode : public TextureNode {
@@ -225,15 +186,9 @@ public:
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
- ustring coloring;
-
- static ShaderEnum coloring_enum;
-
- virtual bool equals(const ShaderNode *other) {
- const VoronoiTextureNode *voronoi_node = (const VoronoiTextureNode*)other;
- return TextureNode::equals(other) &&
- coloring == voronoi_node->coloring;
- }
+ NodeVoronoiColoring coloring;
+ float scale;
+ float3 vector;
};
class MusgraveTextureNode : public TextureNode {
@@ -242,15 +197,9 @@ public:
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
- ustring type;
-
- static ShaderEnum type_enum;
-
- virtual bool equals(const ShaderNode *other) {
- const MusgraveTextureNode *musgrave_node = (const MusgraveTextureNode*)other;
- return TextureNode::equals(other) &&
- type == musgrave_node->type;
- }
+ NodeMusgraveType type;
+ float scale, detail, dimension, lacunarity, offset, gain;
+ float3 vector;
};
class WaveTextureNode : public TextureNode {
@@ -259,17 +208,11 @@ public:
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
- ustring type;
- ustring profile;
- static ShaderEnum type_enum;
- static ShaderEnum profile_enum;
+ NodeWaveType type;
+ NodeWaveProfile profile;
- virtual bool equals(const ShaderNode *other) {
- const WaveTextureNode *wave_node = (const WaveTextureNode*)other;
- return TextureNode::equals(other) &&
- type == wave_node->type &&
- profile == wave_node->profile;
- }
+ float scale, distortion, detail, detail_scale;
+ float3 vector;
};
class MagicTextureNode : public TextureNode {
@@ -279,18 +222,17 @@ public:
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
int depth;
-
- virtual bool equals(const ShaderNode *other) {
- const MagicTextureNode *magic_node = (const MagicTextureNode*)other;
- return TextureNode::equals(other) &&
- depth == magic_node->depth;
- }
+ float3 vector;
+ float scale, distortion;
};
class CheckerTextureNode : public TextureNode {
public:
SHADER_NODE_CLASS(CheckerTextureNode)
+ float3 vector, color1, color2;
+ float scale;
+
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
};
@@ -301,16 +243,11 @@ public:
float offset, squash;
int offset_frequency, squash_frequency;
- virtual int get_group() { return NODE_GROUP_LEVEL_2; }
+ float3 color1, color2, mortar;
+ float scale, mortar_size, mortar_smooth, bias, brick_width, row_height;
+ float3 vector;
- virtual bool equals(const ShaderNode *other) {
- const BrickTextureNode *brick_node = (const BrickTextureNode*)other;
- return TextureNode::equals(other) &&
- offset == brick_node->offset &&
- squash == brick_node->squash &&
- offset_frequency == brick_node->offset_frequency &&
- squash_frequency == brick_node->squash_frequency;
- }
+ virtual int get_group() { return NODE_GROUP_LEVEL_2; }
};
class PointDensityTextureNode : public ShaderNode {
@@ -324,25 +261,20 @@ public:
bool has_spatial_varying() { return true; }
bool has_object_dependency() { return true; }
- ImageManager *image_manager;
- int slot;
- string filename;
- ustring space;
- void *builtin_data;
+ ustring filename;
+ NodeTexVoxelSpace space;
InterpolationType interpolation;
-
Transform tfm;
+ float3 vector;
- static ShaderEnum space_enum;
+ ImageManager *image_manager;
+ int slot;
+ void *builtin_data;
- virtual bool equals(const ShaderNode *other) {
- const PointDensityTextureNode *point_dendity_node = (const PointDensityTextureNode*)other;
+ virtual bool equals(const ShaderNode& other) {
+ const PointDensityTextureNode& point_dendity_node = (const PointDensityTextureNode&)other;
return ShaderNode::equals(other) &&
- filename == point_dendity_node->filename &&
- space == point_dendity_node->space &&
- builtin_data == point_dendity_node->builtin_data &&
- interpolation == point_dendity_node->interpolation &&
- tfm == point_dendity_node->tfm;
+ builtin_data == point_dendity_node.builtin_data;
}
};
@@ -351,45 +283,60 @@ public:
SHADER_NODE_CLASS(MappingNode)
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
+ float3 vector;
TextureMapping tex_mapping;
+};
- virtual bool equals(const ShaderNode *other) {
- const MappingNode *mapping_node = (const MappingNode*)other;
- return ShaderNode::equals(other) &&
- tex_mapping.equals(mapping_node->tex_mapping);
- }
+class RGBToBWNode : public ShaderNode {
+public:
+ SHADER_NODE_CLASS(RGBToBWNode)
+ void constant_fold(const ConstantFolder& folder);
+
+ float3 color;
};
class ConvertNode : public ShaderNode {
public:
- ConvertNode(ShaderSocketType from, ShaderSocketType to, bool autoconvert = false);
+ ConvertNode(SocketType::Type from, SocketType::Type to, bool autoconvert = false);
SHADER_NODE_BASE_CLASS(ConvertNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ void constant_fold(const ConstantFolder& folder);
- ShaderSocketType from, to;
+ SocketType::Type from, to;
- virtual bool equals(const ShaderNode *other)
- {
- const ConvertNode *convert_node = (const ConvertNode*)other;
- return ShaderNode::equals(other) &&
- from == convert_node->from &&
- to == convert_node->to;
- }
+ union {
+ float value_float;
+ int value_int;
+ float3 value_color;
+ float3 value_vector;
+ float3 value_point;
+ float3 value_normal;
+ };
+ ustring value_string;
+
+private:
+ static const int MAX_TYPE = 12;
+ static bool register_types();
+ static Node* create(const NodeType *type);
+ static const NodeType *node_types[MAX_TYPE][MAX_TYPE];
+ static bool initialized;
};
class BsdfNode : public ShaderNode {
public:
- BsdfNode(bool scattering = false);
+ explicit BsdfNode(const NodeType *node_type);
SHADER_NODE_BASE_CLASS(BsdfNode);
bool has_spatial_varying() { return true; }
void compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2, ShaderInput *param3 = NULL, ShaderInput *param4 = NULL);
+ virtual ClosureType get_closure_type() { return closure; }
+ float3 color;
+ float3 normal;
+ float surface_mix_weight;
ClosureType closure;
- bool scattering;
- virtual bool equals(const ShaderNode * /*other*/)
+ virtual bool equals(const ShaderNode& /*other*/)
{
/* TODO(sergey): With some care BSDF nodes can be de-duplicated. */
return false;
@@ -400,15 +347,19 @@ class AnisotropicBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(AnisotropicBsdfNode)
- ustring distribution;
- static ShaderEnum distribution_enum;
+ float3 tangent;
+ float roughness, anisotropy, rotation;
+ ClosureType distribution;
+ ClosureType get_closure_type() { return distribution; }
void attributes(Shader *shader, AttributeRequestSet *attributes);
};
class DiffuseBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(DiffuseBsdfNode)
+
+ float roughness;
};
class TranslucentBsdfNode : public BsdfNode {
@@ -426,6 +377,8 @@ public:
class VelvetBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(VelvetBsdfNode)
+
+ float sigma;
};
class GlossyBsdfNode : public BsdfNode {
@@ -434,9 +387,10 @@ public:
void simplify_settings(Scene *scene);
bool has_integrator_dependency();
+ ClosureType get_closure_type() { return distribution; }
- ustring distribution, distribution_orig;
- static ShaderEnum distribution_enum;
+ float roughness;
+ ClosureType distribution, distribution_orig;
};
class GlassBsdfNode : public BsdfNode {
@@ -445,9 +399,10 @@ public:
void simplify_settings(Scene *scene);
bool has_integrator_dependency();
+ ClosureType get_closure_type() { return distribution; }
- ustring distribution, distribution_orig;
- static ShaderEnum distribution_enum;
+ float roughness, IOR;
+ ClosureType distribution, distribution_orig;
};
class RefractionBsdfNode : public BsdfNode {
@@ -456,17 +411,18 @@ public:
void simplify_settings(Scene *scene);
bool has_integrator_dependency();
+ ClosureType get_closure_type() { return distribution; }
- ustring distribution, distribution_orig;
- static ShaderEnum distribution_enum;
+ float roughness, IOR;
+ ClosureType distribution, distribution_orig;
};
class ToonBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(ToonBsdfNode)
- ustring component;
- static ShaderEnum component_enum;
+ float smooth, size;
+ ClosureType component;
};
class SubsurfaceScatteringNode : public BsdfNode {
@@ -474,28 +430,47 @@ public:
SHADER_NODE_CLASS(SubsurfaceScatteringNode)
bool has_surface_bssrdf() { return true; }
bool has_bssrdf_bump();
+ ClosureType get_closure_type() { return falloff; }
- static ShaderEnum falloff_enum;
+ float scale;
+ float3 radius;
+ float sharpness;
+ float texture_blur;
+ ClosureType falloff;
};
class EmissionNode : public ShaderNode {
public:
SHADER_NODE_CLASS(EmissionNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ void constant_fold(const ConstantFolder& folder);
+ virtual ClosureType get_closure_type() { return CLOSURE_EMISSION_ID; }
bool has_surface_emission() { return true; }
+
+ float3 color;
+ float strength;
+ float surface_mix_weight;
};
class BackgroundNode : public ShaderNode {
public:
SHADER_NODE_CLASS(BackgroundNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ void constant_fold(const ConstantFolder& folder);
+ virtual ClosureType get_closure_type() { return CLOSURE_BACKGROUND_ID; }
+
+ float3 color;
+ float strength;
+ float surface_mix_weight;
};
class HoldoutNode : public ShaderNode {
public:
SHADER_NODE_CLASS(HoldoutNode)
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
+ virtual ClosureType get_closure_type() { return CLOSURE_HOLDOUT_ID; }
+
+ float surface_mix_weight;
+ float volume_mix_weight;
};
class AmbientOcclusionNode : public ShaderNode {
@@ -504,18 +479,31 @@ public:
bool has_spatial_varying() { return true; }
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
+ virtual ClosureType get_closure_type() { return CLOSURE_AMBIENT_OCCLUSION_ID; }
+
+ float3 normal_osl;
+ float3 color;
+ float surface_mix_weight;
};
class VolumeNode : public ShaderNode {
public:
- SHADER_NODE_CLASS(VolumeNode)
+ VolumeNode(const NodeType *node_type);
+ SHADER_NODE_BASE_CLASS(VolumeNode)
void compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2);
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
+ virtual int get_feature() {
+ return ShaderNode::get_feature() | NODE_FEATURE_VOLUME;
+ }
+ virtual ClosureType get_closure_type() { return closure; }
+ float3 color;
+ float density;
+ float volume_mix_weight;
ClosureType closure;
- virtual bool equals(const ShaderNode * /*other*/)
+ virtual bool equals(const ShaderNode& /*other*/)
{
/* TODO(sergey): With some care Volume nodes can be de-duplicated. */
return false;
@@ -530,15 +518,20 @@ public:
class ScatterVolumeNode : public VolumeNode {
public:
SHADER_NODE_CLASS(ScatterVolumeNode)
+
+ float anisotropy;
};
class HairBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(HairBsdfNode)
+ ClosureType get_closure_type() { return component; }
- ustring component;
- static ShaderEnum component_enum;
-
+ ClosureType component;
+ float offset;
+ float roughness_u;
+ float roughness_v;
+ float3 tangent;
};
class GeometryNode : public ShaderNode {
@@ -546,6 +539,8 @@ public:
SHADER_NODE_CLASS(GeometryNode)
void attributes(Shader *shader, AttributeRequestSet *attributes);
bool has_spatial_varying() { return true; }
+
+ float3 normal_osl;
};
class TextureCoordinateNode : public ShaderNode {
@@ -555,17 +550,10 @@ public:
bool has_spatial_varying() { return true; }
bool has_object_dependency() { return use_transform; }
+ float3 normal_osl;
bool from_dupli;
bool use_transform;
Transform ob_tfm;
-
- virtual bool equals(const ShaderNode *other) {
- const TextureCoordinateNode *texco_node = (const TextureCoordinateNode*)other;
- return ShaderNode::equals(other) &&
- from_dupli == texco_node->from_dupli &&
- use_transform == texco_node->use_transform &&
- ob_tfm == texco_node->ob_tfm;
- }
};
class UVMapNode : public ShaderNode {
@@ -577,13 +565,6 @@ public:
ustring attribute;
bool from_dupli;
-
- virtual bool equals(const ShaderNode *other) {
- const UVMapNode *uv_map_node = (const UVMapNode*)other;
- return ShaderNode::equals(other) &&
- attribute == uv_map_node->attribute &&
- from_dupli == uv_map_node->from_dupli;
- }
};
class LightPathNode : public ShaderNode {
@@ -597,6 +578,9 @@ public:
SHADER_NODE_CLASS(LightFalloffNode)
bool has_spatial_varying() { return true; }
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
+
+ float strength;
+ float smooth;
};
class ObjectInfoNode : public ShaderNode {
@@ -628,136 +612,150 @@ class ValueNode : public ShaderNode {
public:
SHADER_NODE_CLASS(ValueNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ void constant_fold(const ConstantFolder& folder);
float value;
-
- virtual bool equals(const ShaderNode *other) {
- const ValueNode *value_node = (const ValueNode*)other;
- return ShaderNode::equals(other) &&
- value == value_node->value;
- }
};
class ColorNode : public ShaderNode {
public:
SHADER_NODE_CLASS(ColorNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ void constant_fold(const ConstantFolder& folder);
float3 value;
-
- virtual bool equals(const ShaderNode *other) {
- const ColorNode *color_node = (const ColorNode*)other;
- return ShaderNode::equals(other) &&
- value == color_node->value;
- }
};
class AddClosureNode : public ShaderNode {
public:
SHADER_NODE_CLASS(AddClosureNode)
+ void constant_fold(const ConstantFolder& folder);
};
class MixClosureNode : public ShaderNode {
public:
SHADER_NODE_CLASS(MixClosureNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ void constant_fold(const ConstantFolder& folder);
+
+ float fac;
};
class MixClosureWeightNode : public ShaderNode {
public:
SHADER_NODE_CLASS(MixClosureWeightNode);
+
+ float weight;
+ float fac;
};
class InvertNode : public ShaderNode {
public:
SHADER_NODE_CLASS(InvertNode)
-
+ void constant_fold(const ConstantFolder& folder);
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
+
+ float fac;
+ float3 color;
};
class MixNode : public ShaderNode {
public:
SHADER_NODE_CLASS(MixNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ void constant_fold(const ConstantFolder& folder);
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
+ NodeMix type;
bool use_clamp;
-
- ustring type;
- static ShaderEnum type_enum;
-
- virtual bool equals(const ShaderNode *other)
- {
- const MixNode *mix_node = (const MixNode*)other;
- return ShaderNode::equals(other) &&
- use_clamp == mix_node->use_clamp &&
- type == mix_node->type;
- }
+ float3 color1;
+ float3 color2;
+ float fac;
};
class CombineRGBNode : public ShaderNode {
public:
SHADER_NODE_CLASS(CombineRGBNode)
-
+ void constant_fold(const ConstantFolder& folder);
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
+
+ float r, g, b;
};
class CombineHSVNode : public ShaderNode {
public:
SHADER_NODE_CLASS(CombineHSVNode)
-
+ void constant_fold(const ConstantFolder& folder);
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
+
+ float h, s, v;
};
class CombineXYZNode : public ShaderNode {
public:
SHADER_NODE_CLASS(CombineXYZNode)
-
+ void constant_fold(const ConstantFolder& folder);
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
+
+ float x, y, z;
};
class GammaNode : public ShaderNode {
public:
SHADER_NODE_CLASS(GammaNode)
-
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
-
+ void constant_fold(const ConstantFolder& folder);
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
+
+ float3 color;
+ float gamma;
};
class BrightContrastNode : public ShaderNode {
public:
SHADER_NODE_CLASS(BrightContrastNode)
+ void constant_fold(const ConstantFolder& folder);
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
+
+ float3 color;
+ float bright;
+ float contrast;
};
class SeparateRGBNode : public ShaderNode {
public:
SHADER_NODE_CLASS(SeparateRGBNode)
-
+ void constant_fold(const ConstantFolder& folder);
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
+
+ float3 color;
};
class SeparateHSVNode : public ShaderNode {
public:
SHADER_NODE_CLASS(SeparateHSVNode)
-
+ void constant_fold(const ConstantFolder& folder);
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
+
+ float3 color;
};
class SeparateXYZNode : public ShaderNode {
public:
SHADER_NODE_CLASS(SeparateXYZNode)
-
+ void constant_fold(const ConstantFolder& folder);
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
+
+ float3 vector;
};
class HSVNode : public ShaderNode {
public:
SHADER_NODE_CLASS(HSVNode)
+
+ float hue;
+ float saturation;
+ float value;
+ float fac;
+ float3 color;
};
class AttributeNode : public ShaderNode {
@@ -767,18 +765,13 @@ public:
bool has_spatial_varying() { return true; }
ustring attribute;
-
- virtual bool equals(const ShaderNode *other) {
- const AttributeNode *color_node = (const AttributeNode*)other;
- return ShaderNode::equals(other) &&
- attribute == color_node->attribute;
- }
};
class CameraNode : public ShaderNode {
public:
SHADER_NODE_CLASS(CameraNode)
bool has_spatial_varying() { return true; }
+ virtual int get_group() { return NODE_GROUP_LEVEL_2; }
};
class FresnelNode : public ShaderNode {
@@ -786,6 +779,9 @@ public:
SHADER_NODE_CLASS(FresnelNode)
bool has_spatial_varying() { return true; }
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
+
+ float3 normal;
+ float IOR;
};
class LayerWeightNode : public ShaderNode {
@@ -793,6 +789,9 @@ public:
SHADER_NODE_CLASS(LayerWeightNode)
bool has_spatial_varying() { return true; }
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
+
+ float3 normal;
+ float blend;
};
class WireframeNode : public ShaderNode {
@@ -801,42 +800,37 @@ public:
bool has_spatial_varying() { return true; }
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
+ float size;
bool use_pixel_size;
};
class WavelengthNode : public ShaderNode {
public:
SHADER_NODE_CLASS(WavelengthNode)
-
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
+
+ float wavelength;
};
class BlackbodyNode : public ShaderNode {
public:
SHADER_NODE_CLASS(BlackbodyNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
-
+ void constant_fold(const ConstantFolder& folder);
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
+
+ float temperature;
};
class MathNode : public ShaderNode {
public:
SHADER_NODE_CLASS(MathNode)
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ void constant_fold(const ConstantFolder& folder);
+ float value1;
+ float value2;
+ NodeMath type;
bool use_clamp;
-
- ustring type;
- static ShaderEnum type_enum;
-
- virtual bool equals(const ShaderNode *other)
- {
- const MathNode *math_node = (const MathNode*)other;
- return ShaderNode::equals(other) &&
- use_clamp == math_node->use_clamp &&
- type == math_node->type;
- }
};
class NormalNode : public ShaderNode {
@@ -845,30 +839,18 @@ public:
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
float3 direction;
-
- virtual bool equals(const ShaderNode *other)
- {
- const NormalNode *normal_node = (const NormalNode*)other;
- return ShaderNode::equals(other) &&
- direction == normal_node->direction;
- }
+ float3 normal;
};
class VectorMathNode : public ShaderNode {
public:
SHADER_NODE_CLASS(VectorMathNode)
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ void constant_fold(const ConstantFolder& folder);
- ustring type;
- static ShaderEnum type_enum;
-
- virtual bool equals(const ShaderNode *other)
- {
- const MathNode *math_node = (const MathNode*)other;
- return ShaderNode::equals(other) &&
- type == math_node->type;
- }
+ float3 vector1;
+ float3 vector2;
+ NodeVectorMath type;
};
class VectorTransformNode : public ShaderNode {
@@ -877,87 +859,98 @@ public:
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
- ustring type;
- ustring convert_from;
- ustring convert_to;
-
- static ShaderEnum type_enum;
- static ShaderEnum convert_space_enum;
-
- virtual bool equals(const ShaderNode *other) {
- const VectorTransformNode *vector_transform_node = (const VectorTransformNode*)other;
- return ShaderNode::equals(other) &&
- type == vector_transform_node->type &&
- convert_from == vector_transform_node->convert_from &&
- convert_to == vector_transform_node->convert_to;
- }
+ NodeVectorTransformType type;
+ NodeVectorTransformConvertSpace convert_from;
+ NodeVectorTransformConvertSpace convert_to;
+ float3 vector;
};
class BumpNode : public ShaderNode {
public:
SHADER_NODE_CLASS(BumpNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ void constant_fold(const ConstantFolder& folder);
bool has_spatial_varying() { return true; }
virtual int get_feature() {
return NODE_FEATURE_BUMP;
}
bool invert;
-
- virtual bool equals(const ShaderNode *other) {
- const BumpNode *bump_node = (const BumpNode*)other;
- return ShaderNode::equals(other) &&
- invert == bump_node->invert;
- }
+ bool use_object_space;
+ float height;
+ float sample_center;
+ float sample_x;
+ float sample_y;
+ float3 normal;
+ float strength;
+ float distance;
};
-class RGBCurvesNode : public ShaderNode {
+class CurvesNode : public ShaderNode {
public:
- SHADER_NODE_CLASS(RGBCurvesNode)
+ explicit CurvesNode(const NodeType *node_type);
+ SHADER_NODE_BASE_CLASS(CurvesNode);
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
- virtual bool equals(const ShaderNode * /*other*/) { return false; }
- float4 curves[RAMP_TABLE_SIZE];
- float min_x, max_x;
+ array<float3> curves;
+ float min_x, max_x, fac;
+ float3 value;
+
+protected:
+ void constant_fold(const ConstantFolder& folder, ShaderInput *value_in);
+ void compile(SVMCompiler& compiler, int type, ShaderInput *value_in, ShaderOutput *value_out);
+ void compile(OSLCompiler& compiler, const char *name);
};
-class VectorCurvesNode : public ShaderNode {
+class RGBCurvesNode : public CurvesNode {
public:
- SHADER_NODE_CLASS(VectorCurvesNode)
-
- virtual int get_group() { return NODE_GROUP_LEVEL_3; }
- virtual bool equals(const ShaderNode * /*other*/) { return false; }
+ SHADER_NODE_CLASS(RGBCurvesNode)
+ void constant_fold(const ConstantFolder& folder);
+};
- float4 curves[RAMP_TABLE_SIZE];
- float min_x, max_x;
+class VectorCurvesNode : public CurvesNode {
+public:
+ SHADER_NODE_CLASS(VectorCurvesNode)
+ void constant_fold(const ConstantFolder& folder);
};
class RGBRampNode : public ShaderNode {
public:
SHADER_NODE_CLASS(RGBRampNode)
- float4 ramp[RAMP_TABLE_SIZE];
- bool interpolate;
+ void constant_fold(const ConstantFolder& folder);
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
- virtual bool equals(const ShaderNode * /*other*/) { return false; }
+
+ array<float3> ramp;
+ array<float> ramp_alpha;
+ float fac;
+ bool interpolate;
};
class SetNormalNode : public ShaderNode {
public:
SHADER_NODE_CLASS(SetNormalNode)
+ float3 direction;
};
-class OSLScriptNode : public ShaderNode {
+class OSLNode : public ShaderNode {
public:
- SHADER_NODE_CLASS(OSLScriptNode)
+ static OSLNode *create(size_t num_inputs, const OSLNode *from = NULL);
+ ~OSLNode();
+
+ ShaderNode *clone() const;
+
+ char* input_default_value();
+ void add_input(ustring name, SocketType::Type type);
+ void add_output(ustring name, SocketType::Type type);
+
+ SHADER_NODE_NO_CLONE_CLASS(OSLNode)
/* ideally we could beter detect this, but we can't query this now */
bool has_spatial_varying() { return true; }
+ virtual bool equals(const ShaderNode& /*other*/) { return false; }
string filepath;
string bytecode_hash;
-
- virtual bool equals(const ShaderNode * /*other*/) { return false; }
};
class NormalMapNode : public ShaderNode {
@@ -967,18 +960,11 @@ public:
bool has_spatial_varying() { return true; }
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
- ustring space;
- static ShaderEnum space_enum;
-
+ NodeNormalMapSpace space;
ustring attribute;
-
- virtual bool equals(const ShaderNode *other)
- {
- const NormalMapNode *normal_map_node = (const NormalMapNode*)other;
- return ShaderNode::equals(other) &&
- space == normal_map_node->space &&
- attribute == normal_map_node->attribute;
- }
+ float strength;
+ float3 color;
+ float3 normal_osl;
};
class TangentNode : public ShaderNode {
@@ -988,22 +974,10 @@ public:
bool has_spatial_varying() { return true; }
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
- ustring direction_type;
- static ShaderEnum direction_type_enum;
-
- ustring axis;
- static ShaderEnum axis_enum;
-
+ NodeTangentDirectionType direction_type;
+ NodeTangentAxis axis;
ustring attribute;
-
- virtual bool equals(const ShaderNode *other)
- {
- const TangentNode *tangent_node = (const TangentNode*)other;
- return ShaderNode::equals(other) &&
- direction_type == tangent_node->direction_type &&
- axis == tangent_node->axis &&
- attribute == tangent_node->attribute;
- }
+ float3 normal_osl;
};
class OpenVDBNode : public ShaderNode {
@@ -1017,7 +991,7 @@ public:
int grid_slot;
int sampling;
- vector<ustring> output_names;
+ vector<SocketType> output_sockets;
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp
index a7ea75820ea..8b8b988b969 100644
--- a/intern/cycles/render/object.cpp
+++ b/intern/cycles/render/object.cpp
@@ -29,28 +29,39 @@
#include "util_progress.h"
#include "util_vector.h"
+#include "subd_patch_table.h"
+
CCL_NAMESPACE_BEGIN
/* Object */
+NODE_DEFINE(Object)
+{
+ NodeType* type = NodeType::add("object", create);
+
+ SOCKET_NODE(mesh, "Mesh", &Mesh::node_type);
+ SOCKET_TRANSFORM(tfm, "Transform", transform_identity());
+ SOCKET_UINT(visibility, "Visibility", ~0);
+ SOCKET_UINT(random_id, "Random ID", 0);
+ SOCKET_INT(pass_id, "Pass ID", 0);
+ SOCKET_BOOLEAN(use_holdout, "Use Holdout", false);
+ SOCKET_BOOLEAN(hide_on_missing_motion, "Hide on Missing Motion", false);
+ SOCKET_POINT(dupli_generated, "Dupli Generated", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_POINT2(dupli_uv, "Dupli UV", make_float2(0.0f, 0.0f));
+
+ return type;
+}
+
Object::Object()
+: Node(node_type)
{
- name = "";
- mesh = NULL;
- tfm = transform_identity();
- visibility = ~0;
- random_id = 0;
- pass_id = 0;
particle_system = NULL;
particle_index = 0;
bounds = BoundBox::empty;
- motion.pre = transform_identity();
- motion.mid = transform_identity();
- motion.post = transform_identity();
+ motion.pre = transform_empty();
+ motion.mid = transform_empty();
+ motion.post = transform_empty();
use_motion = false;
- use_holdout = false;
- dupli_generated = make_float3(0.0f, 0.0f, 0.0f);
- dupli_uv = make_float2(0.0f, 0.0f);
}
Object::~Object()
@@ -62,8 +73,30 @@ void Object::compute_bounds(bool motion_blur)
BoundBox mbounds = mesh->bounds;
if(motion_blur && use_motion) {
+ MotionTransform mtfm = motion;
+
+ if(hide_on_missing_motion) {
+ /* Hide objects that have no valid previous or next transform, for
+ * example particle that stop existing. TODO: add support for this
+ * case in the kernel so we don't get render artifacts. */
+ if(mtfm.pre == transform_empty() ||
+ mtfm.post == transform_empty()) {
+ bounds = BoundBox::empty;
+ return;
+ }
+ }
+
+ /* In case of missing motion information for previous/next frame,
+ * assume there is no motion. */
+ if(mtfm.pre == transform_empty()) {
+ mtfm.pre = tfm;
+ }
+ if(mtfm.post == transform_empty()) {
+ mtfm.post = tfm;
+ }
+
DecompMotionTransform decomp;
- transform_motion_decompose(&decomp, &motion, &tfm);
+ transform_motion_decompose(&decomp, &mtfm, &tfm);
bounds = BoundBox::empty;
@@ -137,12 +170,12 @@ void Object::apply_transform(bool apply_to_motion)
/* apply transform to curve keys */
for(size_t i = 0; i < mesh->curve_keys.size(); i++) {
- float3 co = transform_point(&tfm, float4_to_float3(mesh->curve_keys[i]));
- float radius = mesh->curve_keys[i].w * scalar;
+ float3 co = transform_point(&tfm, mesh->curve_keys[i]);
+ float radius = mesh->curve_radius[i] * scalar;
/* scale for curve radius is only correct for uniform scale */
- mesh->curve_keys[i] = float3_to_float4(co);
- mesh->curve_keys[i].w = radius;
+ mesh->curve_keys[i] = co;
+ mesh->curve_radius[i] = radius;
}
if(apply_to_motion) {
@@ -176,7 +209,7 @@ void Object::apply_transform(bool apply_to_motion)
}
/* tfm is not reset to identity, all code that uses it needs to check the
- transform_applied boolean */
+ * transform_applied boolean */
}
void Object::tag_update(Scene *scene)
@@ -185,9 +218,7 @@ void Object::tag_update(Scene *scene)
if(mesh->transform_applied)
mesh->need_update = true;
- foreach(uint sindex, mesh->used_shaders) {
- Shader *shader = scene->shaders[sindex];
-
+ foreach(Shader *shader, mesh->used_shaders) {
if(shader->use_mis && shader->has_surface_emission)
scene->light_manager->need_update = true;
}
@@ -219,6 +250,16 @@ vector<float> Object::motion_times()
return times;
}
+bool Object::is_traceable()
+{
+ /* Mesh itself can be empty,can skip all such objects. */
+ if(!bounds.valid() || bounds.size() == make_float3(0.0f, 0.0f, 0.0f)) {
+ return false;
+ }
+ /* TODO(sergey): Check for mesh vertices/curves. visibility flags. */
+ return true;
+}
+
/* Object Manager */
ObjectManager::ObjectManager()
@@ -271,7 +312,9 @@ void ObjectManager::device_update_object_transform(UpdateObejctTransformState *s
state->surface_area_lock.unlock();
if(it == state->surface_area_map.end()) {
- foreach(Mesh::Triangle& t, mesh->triangles) {
+ size_t num_triangles = mesh->num_triangles();
+ for(size_t j = 0; j < num_triangles; j++) {
+ Mesh::Triangle t = mesh->get_triangle(j);
float3 p1 = mesh->verts[t.v[0]];
float3 p2 = mesh->verts[t.v[1]];
float3 p3 = mesh->verts[t.v[2]];
@@ -290,7 +333,9 @@ void ObjectManager::device_update_object_transform(UpdateObejctTransformState *s
surface_area *= uniform_scale;
}
else {
- foreach(Mesh::Triangle& t, mesh->triangles) {
+ size_t num_triangles = mesh->num_triangles();
+ for(size_t j = 0; j < num_triangles; j++) {
+ Mesh::Triangle t = mesh->get_triangle(j);
float3 p1 = transform_point(&tfm, mesh->verts[t.v[0]]);
float3 p2 = transform_point(&tfm, mesh->verts[t.v[1]]);
float3 p3 = transform_point(&tfm, mesh->verts[t.v[2]]);
@@ -314,19 +359,27 @@ void ObjectManager::device_update_object_transform(UpdateObejctTransformState *s
* comes with deformed position in object space, or if we transform
* the shading point in world space.
*/
- Transform mtfm_pre = ob->motion.pre;
- Transform mtfm_post = ob->motion.post;
+ MotionTransform mtfm = ob->motion;
+
+ /* In case of missing motion information for previous/next frame,
+ * assume there is no motion. */
+ if(!ob->use_motion || mtfm.pre == transform_empty()) {
+ mtfm.pre = ob->tfm;
+ }
+ if(!ob->use_motion || mtfm.post == transform_empty()) {
+ mtfm.post = ob->tfm;
+ }
if(!mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) {
- mtfm_pre = mtfm_pre * itfm;
- mtfm_post = mtfm_post * itfm;
+ mtfm.pre = mtfm.pre * itfm;
+ mtfm.post = mtfm.post * itfm;
}
else {
flag |= SD_OBJECT_HAS_VERTEX_MOTION;
}
- memcpy(&objects_vector[object_index*OBJECT_VECTOR_SIZE+0], &mtfm_pre, sizeof(float4)*3);
- memcpy(&objects_vector[object_index*OBJECT_VECTOR_SIZE+3], &mtfm_post, sizeof(float4)*3);
+ memcpy(&objects_vector[object_index*OBJECT_VECTOR_SIZE+0], &mtfm.pre, sizeof(float4)*3);
+ memcpy(&objects_vector[object_index*OBJECT_VECTOR_SIZE+3], &mtfm.post, sizeof(float4)*3);
}
#ifdef __OBJECT_MOTION__
else if(state->need_motion == Scene::MOTION_BLUR) {
@@ -362,7 +415,7 @@ void ObjectManager::device_update_object_transform(UpdateObejctTransformState *s
state->object_flag[object_index] = flag;
/* Have curves. */
- if(mesh->curves.size()) {
+ if(mesh->num_curves()) {
state->have_curves = true;
}
}
@@ -569,6 +622,41 @@ void ObjectManager::device_update_flags(Device *device,
device->tex_alloc("__object_flag", dscene->object_flag);
}
+void ObjectManager::device_update_patch_map_offsets(Device *device, DeviceScene *dscene, Scene *scene)
+{
+ if(scene->objects.size() == 0) {
+ return;
+ }
+
+ uint4* objects = (uint4*)dscene->objects.get_data();
+
+ bool update = false;
+
+ int object_index = 0;
+ foreach(Object *object, scene->objects) {
+ int offset = object_index*OBJECT_SIZE + 11;
+
+ Mesh* mesh = object->mesh;
+
+ if(mesh->patch_table) {
+ uint patch_map_offset = 2*(mesh->patch_table_offset + mesh->patch_table->total_size() -
+ mesh->patch_table->num_nodes * PATCH_NODE_SIZE) - mesh->patch_offset;
+
+ if(objects[offset].x != patch_map_offset) {
+ objects[offset].x = patch_map_offset;
+ update = true;
+ }
+ }
+
+ object_index++;
+ }
+
+ if(update) {
+ device->tex_free(dscene->objects);
+ device->tex_alloc("__objects", dscene->objects);
+ }
+}
+
void ObjectManager::device_free(Device *device, DeviceScene *dscene)
{
device->tex_free(dscene->objects);
@@ -618,7 +706,7 @@ void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, u
* Could be solved by moving reference counter to Mesh.
*/
if((mesh_users[object->mesh] == 1 && !object->mesh->has_surface_bssrdf) &&
- object->mesh->displacement_method == Mesh::DISPLACE_BUMP)
+ !object->mesh->has_true_displacement() && object->mesh->subdivision_type == Mesh::SUBDIVISION_NONE)
{
if(!(motion_blur && object->use_motion)) {
if(!object->mesh->transform_applied) {
diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h
index c2a79ca8dc4..7e306fab2a8 100644
--- a/intern/cycles/render/object.h
+++ b/intern/cycles/render/object.h
@@ -17,6 +17,7 @@
#ifndef __OBJECT_H__
#define __OBJECT_H__
+#include "node.h"
#include "scene.h"
#include "util_boundbox.h"
@@ -37,18 +38,20 @@ struct Transform;
/* Object */
-class Object {
+class Object : public Node {
public:
+ NODE_DECLARE;
+
Mesh *mesh;
Transform tfm;
BoundBox bounds;
- ustring name;
uint random_id;
int pass_id;
vector<ParamValue> attributes;
uint visibility;
MotionTransform motion;
bool use_motion;
+ bool hide_on_missing_motion;
bool use_holdout;
float3 dupli_generated;
@@ -66,6 +69,11 @@ public:
void apply_transform(bool apply_to_motion);
vector<float> motion_times();
+
+ /* Check whether object is traceable and it worth adding it to
+ * kernel scene.
+ */
+ bool is_traceable();
};
/* Object Manager */
@@ -90,6 +98,8 @@ public:
Scene *scene,
Progress& progress,
bool bounds_valid = true);
+ void device_update_patch_map_offsets(Device *device, DeviceScene *dscene, Scene *scene);
+
void device_free(Device *device, DeviceScene *dscene);
void tag_update(Scene *scene);
diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp
index 78215af8375..67b68e63cb2 100644
--- a/intern/cycles/render/osl.cpp
+++ b/intern/cycles/render/osl.cpp
@@ -99,7 +99,7 @@ void OSLShaderManager::device_update(Device *device, DeviceScene *dscene, Scene
thread_scoped_lock lock(ss_mutex);
OSLCompiler compiler((void*)this, (void*)ss, scene->image_manager);
- compiler.background = (shader == scene->shaders[scene->default_background]);
+ compiler.background = (shader == scene->default_background);
compiler.compile(scene, og, shader);
if(shader->use_mis && shader->has_surface_emission)
@@ -394,16 +394,145 @@ const char *OSLShaderManager::shader_load_bytecode(const string& hash, const str
{
ss->LoadMemoryCompiledShader(hash.c_str(), bytecode.c_str());
- /* this is a bit weak, but works */
OSLShaderInfo info;
+
+ if(!info.query.open_bytecode(bytecode)) {
+ fprintf(stderr, "OSL query error: %s\n", info.query.geterror().c_str());
+ }
+
+ /* this is a bit weak, but works */
info.has_surface_emission = (bytecode.find("\"emission\"") != string::npos);
info.has_surface_transparent = (bytecode.find("\"transparent\"") != string::npos);
info.has_surface_bssrdf = (bytecode.find("\"bssrdf\"") != string::npos);
+
loaded_shaders[hash] = info;
return loaded_shaders.find(hash)->first.c_str();
}
+OSLNode *OSLShaderManager::osl_node(const std::string& filepath,
+ const std::string& bytecode_hash,
+ const std::string& bytecode)
+{
+ /* create query */
+ const char *hash;
+
+ if(!filepath.empty()) {
+ hash = shader_load_filepath(filepath);
+ }
+ else {
+ hash = shader_test_loaded(bytecode_hash);
+ if(!hash)
+ hash = shader_load_bytecode(bytecode_hash, bytecode);
+ }
+
+ if(!hash) {
+ return NULL;
+ }
+
+ OSLShaderInfo *info = shader_loaded_info(hash);
+
+ /* count number of inputs */
+ size_t num_inputs = 0;
+
+ for(int i = 0; i < info->query.nparams(); i++) {
+ const OSL::OSLQuery::Parameter *param = info->query.getparam(i);
+
+ /* skip unsupported types */
+ if(param->varlenarray || param->isstruct || param->type.arraylen > 1)
+ continue;
+
+ if(!param->isoutput)
+ num_inputs++;
+ }
+
+ /* create node */
+ OSLNode *node = OSLNode::create(num_inputs);
+
+ /* add new sockets from parameters */
+ set<void*> used_sockets;
+
+ for(int i = 0; i < info->query.nparams(); i++) {
+ const OSL::OSLQuery::Parameter *param = info->query.getparam(i);
+
+ /* skip unsupported types */
+ if(param->varlenarray || param->isstruct || param->type.arraylen > 1)
+ continue;
+
+ SocketType::Type socket_type;
+
+ if(param->isclosure) {
+ socket_type = SocketType::CLOSURE;
+ }
+ else if(param->type.vecsemantics != TypeDesc::NOSEMANTICS) {
+ if(param->type.vecsemantics == TypeDesc::COLOR)
+ socket_type = SocketType::COLOR;
+ else if(param->type.vecsemantics == TypeDesc::POINT)
+ socket_type = SocketType::POINT;
+ else if(param->type.vecsemantics == TypeDesc::VECTOR)
+ socket_type = SocketType::VECTOR;
+ else if(param->type.vecsemantics == TypeDesc::NORMAL)
+ socket_type = SocketType::NORMAL;
+ else
+ continue;
+
+ if(!param->isoutput && param->validdefault) {
+ float3 *default_value = (float3*)node->input_default_value();
+ default_value->x = param->fdefault[0];
+ default_value->y = param->fdefault[1];
+ default_value->z = param->fdefault[2];
+ }
+ }
+ else if(param->type.aggregate == TypeDesc::SCALAR) {
+ if(param->type.basetype == TypeDesc::INT) {
+ socket_type = SocketType::INT;
+
+ if(!param->isoutput && param->validdefault) {
+ *(int*)node->input_default_value() = param->idefault[0];
+ }
+ }
+ else if(param->type.basetype == TypeDesc::FLOAT) {
+ socket_type = SocketType::FLOAT;
+
+ if(!param->isoutput && param->validdefault) {
+ *(float*)node->input_default_value() = param->fdefault[0];
+ }
+ }
+ else if(param->type.basetype == TypeDesc::STRING) {
+ socket_type = SocketType::STRING;
+
+ if(!param->isoutput && param->validdefault) {
+ *(ustring*)node->input_default_value() = param->sdefault[0];
+ }
+ }
+ else
+ continue;
+ }
+ else
+ continue;
+
+ if(param->isoutput) {
+ node->add_output(param->name, socket_type);
+ }
+ else {
+ node->add_input(param->name, socket_type);
+ }
+ }
+
+ /* set bytcode hash or filepath */
+ if(!bytecode_hash.empty()) {
+ node->bytecode_hash = bytecode_hash;
+ }
+ else {
+ node->filepath = filepath;
+ }
+
+ /* Generate inputs and outputs */
+ node->create_inputs_outputs(node->type);
+
+ return node;
+}
+
/* Graph Compiler */
OSLCompiler::OSLCompiler(void *manager_, void *shadingsys_, ImageManager *image_manager_)
@@ -420,14 +549,14 @@ string OSLCompiler::id(ShaderNode *node)
{
/* assign layer unique name based on pointer address + bump mode */
stringstream stream;
- stream << "node_" << node->name << "_" << node;
+ stream << "node_" << node->type->name << "_" << node;
return stream.str();
}
string OSLCompiler::compatible_name(ShaderNode *node, ShaderInput *input)
{
- string sname(input->name);
+ string sname(input->name().string());
size_t i;
/* strip whitespace */
@@ -436,7 +565,7 @@ string OSLCompiler::compatible_name(ShaderNode *node, ShaderInput *input)
/* if output exists with the same name, add "In" suffix */
foreach(ShaderOutput *output, node->outputs) {
- if(strcmp(input->name, output->name)==0) {
+ if(input->name() == output->name()) {
sname += "In";
break;
}
@@ -447,7 +576,7 @@ string OSLCompiler::compatible_name(ShaderNode *node, ShaderInput *input)
string OSLCompiler::compatible_name(ShaderNode *node, ShaderOutput *output)
{
- string sname(output->name);
+ string sname(output->name().string());
size_t i;
/* strip whitespace */
@@ -456,7 +585,7 @@ string OSLCompiler::compatible_name(ShaderNode *node, ShaderOutput *output)
/* if input exists with the same name, add "Out" suffix */
foreach(ShaderInput *input, node->inputs) {
- if(strcmp(input->name, output->name)==0) {
+ if(input->name() == output->name()) {
sname += "Out";
break;
}
@@ -470,21 +599,21 @@ bool OSLCompiler::node_skip_input(ShaderNode *node, ShaderInput *input)
/* exception for output node, only one input is actually used
* depending on the current shader type */
- if(!(input->usage & ShaderInput::USE_OSL))
+ if(input->flags() & SocketType::SVM_INTERNAL)
return true;
if(node->special_type == SHADER_SPECIAL_TYPE_OUTPUT) {
- if(strcmp(input->name, "Surface") == 0 && current_type != SHADER_TYPE_SURFACE)
+ if(input->name() == "Surface" && current_type != SHADER_TYPE_SURFACE)
return true;
- if(strcmp(input->name, "Volume") == 0 && current_type != SHADER_TYPE_VOLUME)
+ if(input->name() == "Volume" && current_type != SHADER_TYPE_VOLUME)
return true;
- if(strcmp(input->name, "Displacement") == 0 && current_type != SHADER_TYPE_DISPLACEMENT)
+ if(input->name() == "Displacement" && current_type != SHADER_TYPE_DISPLACEMENT)
return true;
- if(strcmp(input->name, "Normal") == 0)
+ if(input->name() == "Normal" && current_type != SHADER_TYPE_BUMP)
return true;
}
else if(node->special_type == SHADER_SPECIAL_TYPE_BUMP) {
- if(strcmp(input->name, "Height") == 0)
+ if(input->name() == "Height")
return true;
}
else if(current_type == SHADER_TYPE_DISPLACEMENT && input->link && input->link->parent->special_type == SHADER_SPECIAL_TYPE_BUMP)
@@ -512,34 +641,36 @@ void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath)
if(node_skip_input(node, input))
continue;
/* already has default value assigned */
- else if(input->default_value != ShaderInput::NONE)
+ else if(input->flags() & SocketType::DEFAULT_LINK_MASK)
continue;
string param_name = compatible_name(node, input);
- switch(input->type) {
- case SHADER_SOCKET_COLOR:
- parameter_color(param_name.c_str(), input->value);
+ const SocketType& socket = input->socket_type;
+ switch(input->type()) {
+ case SocketType::COLOR:
+ parameter_color(param_name.c_str(), node->get_float3(socket));
break;
- case SHADER_SOCKET_POINT:
- parameter_point(param_name.c_str(), input->value);
+ case SocketType::POINT:
+ parameter_point(param_name.c_str(), node->get_float3(socket));
break;
- case SHADER_SOCKET_VECTOR:
- parameter_vector(param_name.c_str(), input->value);
+ case SocketType::VECTOR:
+ parameter_vector(param_name.c_str(), node->get_float3(socket));
break;
- case SHADER_SOCKET_NORMAL:
- parameter_normal(param_name.c_str(), input->value);
+ case SocketType::NORMAL:
+ parameter_normal(param_name.c_str(), node->get_float3(socket));
break;
- case SHADER_SOCKET_FLOAT:
- parameter(param_name.c_str(), input->value.x);
+ case SocketType::FLOAT:
+ parameter(param_name.c_str(), node->get_float(socket));
break;
- case SHADER_SOCKET_INT:
- parameter(param_name.c_str(), (int)input->value.x);
+ case SocketType::INT:
+ parameter(param_name.c_str(), node->get_int(socket));
break;
- case SHADER_SOCKET_STRING:
- parameter(param_name.c_str(), input->value_string);
+ case SocketType::STRING:
+ parameter(param_name.c_str(), node->get_string(socket));
break;
- case SHADER_SOCKET_CLOSURE:
- case SHADER_SOCKET_UNDEFINED:
+ case SocketType::CLOSURE:
+ case SocketType::UNDEFINED:
+ default:
break;
}
}
@@ -553,6 +684,8 @@ void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath)
ss->Shader("surface", name, id(node).c_str());
else if(current_type == SHADER_TYPE_DISPLACEMENT)
ss->Shader("displacement", name, id(node).c_str());
+ else if(current_type == SHADER_TYPE_BUMP)
+ ss->Shader("displacement", name, id(node).c_str());
else
assert(0);
@@ -605,6 +738,168 @@ void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath)
}
}
+static TypeDesc array_typedesc(TypeDesc typedesc, int arraylength)
+{
+ return TypeDesc((TypeDesc::BASETYPE)typedesc.basetype,
+ (TypeDesc::AGGREGATE)typedesc.aggregate,
+ (TypeDesc::VECSEMANTICS)typedesc.vecsemantics,
+ arraylength);
+}
+
+void OSLCompiler::parameter(ShaderNode* node, const char *name)
+{
+ OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
+ ustring uname = ustring(name);
+ const SocketType& socket = *(node->type->find_input(uname));
+
+ switch(socket.type)
+ {
+ case SocketType::BOOLEAN:
+ {
+ int value = node->get_bool(socket);
+ ss->Parameter(name, TypeDesc::TypeInt, &value);
+ break;
+ }
+ case SocketType::FLOAT:
+ {
+ float value = node->get_float(socket);
+ ss->Parameter(uname, TypeDesc::TypeFloat, &value);
+ break;
+ }
+ case SocketType::INT:
+ {
+ int value = node->get_int(socket);
+ ss->Parameter(uname, TypeDesc::TypeInt, &value);
+ break;
+ }
+ case SocketType::COLOR:
+ {
+ float3 value = node->get_float3(socket);
+ ss->Parameter(uname, TypeDesc::TypeColor, &value);
+ break;
+ }
+ case SocketType::VECTOR:
+ {
+ float3 value = node->get_float3(socket);
+ ss->Parameter(uname, TypeDesc::TypeVector, &value);
+ break;
+ }
+ case SocketType::POINT:
+ {
+ float3 value = node->get_float3(socket);
+ ss->Parameter(uname, TypeDesc::TypePoint, &value);
+ break;
+ }
+ case SocketType::NORMAL:
+ {
+ float3 value = node->get_float3(socket);
+ ss->Parameter(uname, TypeDesc::TypeNormal, &value);
+ break;
+ }
+ case SocketType::POINT2:
+ {
+ float2 value = node->get_float2(socket);
+ ss->Parameter(uname, TypeDesc(TypeDesc::FLOAT, TypeDesc::VEC2, TypeDesc::POINT), &value);
+ break;
+ }
+ case SocketType::STRING:
+ {
+ ustring value = node->get_string(socket);
+ ss->Parameter(uname, TypeDesc::TypeString, &value);
+ break;
+ }
+ case SocketType::ENUM:
+ {
+ ustring value = node->get_string(socket);
+ ss->Parameter(uname, TypeDesc::TypeString, &value);
+ break;
+ }
+ case SocketType::TRANSFORM:
+ {
+ Transform value = node->get_transform(socket);
+ ss->Parameter(uname, TypeDesc::TypeMatrix, &value);
+ break;
+ }
+ case SocketType::BOOLEAN_ARRAY:
+ {
+ // OSL does not support booleans, so convert to int
+ const array<bool>& value = node->get_bool_array(socket);
+ array<int> intvalue(value.size());
+ for(size_t i = 0; i < value.size(); i++)
+ intvalue[i] = value[i];
+ ss->Parameter(uname, array_typedesc(TypeDesc::TypeInt, value.size()), intvalue.data());
+ break;
+ }
+ case SocketType::FLOAT_ARRAY:
+ {
+ const array<float>& value = node->get_float_array(socket);
+ ss->Parameter(uname, array_typedesc(TypeDesc::TypeFloat, value.size()), value.data());
+ break;
+ }
+ case SocketType::INT_ARRAY:
+ {
+ const array<int>& value = node->get_int_array(socket);
+ ss->Parameter(uname, array_typedesc(TypeDesc::TypeInt, value.size()), value.data());
+ break;
+ }
+ case SocketType::COLOR_ARRAY:
+ case SocketType::VECTOR_ARRAY:
+ case SocketType::POINT_ARRAY:
+ case SocketType::NORMAL_ARRAY:
+ {
+ TypeDesc typedesc;
+
+ switch(socket.type)
+ {
+ case SocketType::COLOR_ARRAY: typedesc = TypeDesc::TypeColor; break;
+ case SocketType::VECTOR_ARRAY: typedesc = TypeDesc::TypeVector; break;
+ case SocketType::POINT_ARRAY: typedesc = TypeDesc::TypePoint; break;
+ case SocketType::NORMAL_ARRAY: typedesc = TypeDesc::TypeNormal; break;
+ default: assert(0); break;
+ }
+
+ // convert to tightly packed array since float3 has padding
+ const array<float3>& value = node->get_float3_array(socket);
+ array<float> fvalue(value.size() * 3);
+ for(size_t i = 0, j = 0; i < value.size(); i++) {
+ fvalue[j++] = value[i].x;
+ fvalue[j++] = value[i].y;
+ fvalue[j++] = value[i].z;
+ }
+
+ ss->Parameter(uname, array_typedesc(typedesc, value.size()), fvalue.data());
+ break;
+ }
+ case SocketType::POINT2_ARRAY:
+ {
+ const array<float2>& value = node->get_float2_array(socket);
+ ss->Parameter(uname, array_typedesc(TypeDesc(TypeDesc::FLOAT, TypeDesc::VEC2, TypeDesc::POINT), value.size()), value.data());
+ break;
+ }
+ case SocketType::STRING_ARRAY:
+ {
+ const array<ustring>& value = node->get_string_array(socket);
+ ss->Parameter(uname, array_typedesc(TypeDesc::TypeString, value.size()), value.data());
+ break;
+ }
+ case SocketType::TRANSFORM_ARRAY:
+ {
+ const array<Transform>& value = node->get_transform_array(socket);
+ ss->Parameter(uname, array_typedesc(TypeDesc::TypeMatrix, value.size()), value.data());
+ break;
+ }
+ case SocketType::CLOSURE:
+ case SocketType::NODE:
+ case SocketType::NODE_ARRAY:
+ case SocketType::UNDEFINED:
+ case SocketType::UINT:
+ {
+ assert(0);
+ break;
+ }
+ }
+}
+
void OSLCompiler::parameter(const char *name, float f)
{
OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
@@ -668,60 +963,21 @@ void OSLCompiler::parameter_array(const char *name, const float f[], int arrayle
ss->Parameter(name, type, f);
}
-void OSLCompiler::parameter_color_array(const char *name, const float f[][3], int arraylen)
-{
- OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
- TypeDesc type = TypeDesc::TypeColor;
- type.arraylen = arraylen;
- ss->Parameter(name, type, f);
-}
-
-void OSLCompiler::parameter_vector_array(const char *name, const float f[][3], int arraylen)
-{
- OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
- TypeDesc type = TypeDesc::TypeVector;
- type.arraylen = arraylen;
- ss->Parameter(name, type, f);
-}
-
-void OSLCompiler::parameter_normal_array(const char *name, const float f[][3], int arraylen)
-{
- OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
- TypeDesc type = TypeDesc::TypeNormal;
- type.arraylen = arraylen;
- ss->Parameter(name, type, f);
-}
-
-void OSLCompiler::parameter_point_array(const char *name, const float f[][3], int arraylen)
-{
- OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
- TypeDesc type = TypeDesc::TypePoint;
- type.arraylen = arraylen;
- ss->Parameter(name, type, f);
-}
-
-void OSLCompiler::parameter_array(const char *name, const int f[], int arraylen)
+void OSLCompiler::parameter_color_array(const char *name, const array<float3>& f)
{
- OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
- TypeDesc type = TypeDesc::TypeInt;
- type.arraylen = arraylen;
- ss->Parameter(name, type, f);
-}
+ /* NB: cycles float3 type is actually 4 floats! need to use an explicit array */
+ array<float[3]> table(f.size());
-void OSLCompiler::parameter_array(const char *name, const char * const s[], int arraylen)
-{
- OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
- TypeDesc type = TypeDesc::TypeString;
- type.arraylen = arraylen;
- ss->Parameter(name, type, s);
-}
+ for(int i = 0; i < f.size(); ++i) {
+ table[i][0] = f[i].x;
+ table[i][1] = f[i].y;
+ table[i][2] = f[i].z;
+ }
-void OSLCompiler::parameter_array(const char *name, const Transform tfm[], int arraylen)
-{
OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
- TypeDesc type = TypeDesc::TypeMatrix;
- type.arraylen = arraylen;
- ss->Parameter(name, type, (const float *)tfm);
+ TypeDesc type = TypeDesc::TypeColor;
+ type.arraylen = table.size();
+ ss->Parameter(name, type, table.data());
}
void OSLCompiler::find_dependencies(ShaderNodeSet& dependencies, ShaderInput *input)
@@ -800,6 +1056,12 @@ OSL::ShaderGroupRef OSLCompiler::compile_type(Shader *shader, ShaderGraph *graph
generate_nodes(dependencies);
output->compile(*this);
}
+ else if(type == SHADER_TYPE_BUMP) {
+ /* generate bump shader */
+ find_dependencies(dependencies, output->input("Normal"));
+ generate_nodes(dependencies);
+ output->compile(*this);
+ }
else if(type == SHADER_TYPE_VOLUME) {
/* generate volume shader */
find_dependencies(dependencies, output->input("Volume"));
@@ -840,7 +1102,8 @@ void OSLCompiler::compile(Scene *scene, OSLGlobals *og, Shader *shader)
shader->graph_bump->finalize(scene,
true,
true,
- shader->has_integrator_dependency);
+ shader->has_integrator_dependency,
+ shader->displacement_method == DISPLACE_BOTH);
}
current_shader = shader;
@@ -861,10 +1124,10 @@ void OSLCompiler::compile(Scene *scene, OSLGlobals *og, Shader *shader)
if(shader->used && graph && output->input("Surface")->link) {
shader->osl_surface_ref = compile_type(shader, shader->graph, SHADER_TYPE_SURFACE);
- if(shader->graph_bump)
- shader->osl_surface_bump_ref = compile_type(shader, shader->graph_bump, SHADER_TYPE_SURFACE);
+ if(shader->graph_bump && shader->displacement_method != DISPLACE_TRUE)
+ shader->osl_surface_bump_ref = compile_type(shader, shader->graph_bump, SHADER_TYPE_BUMP);
else
- shader->osl_surface_bump_ref = shader->osl_surface_ref;
+ shader->osl_surface_bump_ref = OSL::ShaderGroupRef();
shader->has_surface = true;
}
@@ -892,13 +1155,9 @@ void OSLCompiler::compile(Scene *scene, OSLGlobals *og, Shader *shader)
/* push state to array for lookup */
og->surface_state.push_back(shader->osl_surface_ref);
- og->surface_state.push_back(shader->osl_surface_bump_ref);
-
og->volume_state.push_back(shader->osl_volume_ref);
- og->volume_state.push_back(shader->osl_volume_ref);
-
- og->displacement_state.push_back(shader->osl_displacement_ref);
og->displacement_state.push_back(shader->osl_displacement_ref);
+ og->bump_state.push_back(shader->osl_surface_bump_ref);
}
#else
@@ -907,6 +1166,10 @@ void OSLCompiler::add(ShaderNode * /*node*/, const char * /*name*/, bool /*isfil
{
}
+void OSLCompiler::parameter(ShaderNode * /*node*/, const char * /*name*/)
+{
+}
+
void OSLCompiler::parameter(const char * /*name*/, float /*f*/)
{
}
@@ -947,31 +1210,7 @@ void OSLCompiler::parameter_array(const char * /*name*/, const float /*f*/[], in
{
}
-void OSLCompiler::parameter_color_array(const char * /*name*/, const float /*f*/[][3], int /*arraylen*/)
-{
-}
-
-void OSLCompiler::parameter_vector_array(const char * /*name*/, const float /*f*/[][3], int /*arraylen*/)
-{
-}
-
-void OSLCompiler::parameter_normal_array(const char * /*name*/, const float /*f*/[][3], int /*arraylen*/)
-{
-}
-
-void OSLCompiler::parameter_point_array(const char * /*name*/, const float /*f*/[][3], int /*arraylen*/)
-{
-}
-
-void OSLCompiler::parameter_array(const char * /*name*/, const int /*f*/[], int /*arraylen*/)
-{
-}
-
-void OSLCompiler::parameter_array(const char * /*name*/, const char * const /*s*/[], int /*arraylen*/)
-{
-}
-
-void OSLCompiler::parameter_array(const char * /*name*/, const Transform /*tfm*/[], int /*arraylen*/)
+void OSLCompiler::parameter_color_array(const char * /*name*/, const array<float3>& /*f*/)
{
}
diff --git a/intern/cycles/render/osl.h b/intern/cycles/render/osl.h
index ac985a84eef..b131b672b8c 100644
--- a/intern/cycles/render/osl.h
+++ b/intern/cycles/render/osl.h
@@ -22,6 +22,7 @@
#include "util_thread.h"
#include "graph.h"
+#include "nodes.h"
#include "shader.h"
#ifdef WITH_OSL
@@ -54,6 +55,7 @@ struct OSLShaderInfo {
has_surface_bssrdf(false)
{}
+ OSL::OSLQuery query;
bool has_surface_emission;
bool has_surface_transparent;
bool has_surface_bssrdf;
@@ -83,6 +85,11 @@ public:
const char *shader_load_filepath(string filepath);
OSLShaderInfo *shader_loaded_info(const string& hash);
+ /* create OSL node using OSLQuery */
+ OSLNode *osl_node(const std::string& filepath,
+ const std::string& bytecode_hash = "",
+ const std::string& bytecode = "");
+
protected:
void texture_system_init();
void texture_system_free();
@@ -118,6 +125,8 @@ public:
void add(ShaderNode *node, const char *name, bool isfilepath = false);
+ void parameter(ShaderNode *node, const char *name);
+
void parameter(const char *name, float f);
void parameter_color(const char *name, float3 f);
void parameter_vector(const char *name, float3 f);
@@ -129,13 +138,7 @@ public:
void parameter(const char *name, const Transform& tfm);
void parameter_array(const char *name, const float f[], int arraylen);
- void parameter_color_array(const char *name, const float f[][3], int arraylen);
- void parameter_vector_array(const char *name, const float f[][3], int arraylen);
- void parameter_normal_array(const char *name, const float f[][3], int arraylen);
- void parameter_point_array(const char *name, const float f[][3], int arraylen);
- void parameter_array(const char *name, const int f[], int arraylen);
- void parameter_array(const char *name, const char * const s[], int arraylen);
- void parameter_array(const char *name, const Transform tfm[], int arraylen);
+ void parameter_color_array(const char *name, const array<float3>& f);
ShaderType output_type() { return current_type; }
diff --git a/intern/cycles/render/particles.cpp b/intern/cycles/render/particles.cpp
index 50726bb4574..1a35d60fb4b 100644
--- a/intern/cycles/render/particles.cpp
+++ b/intern/cycles/render/particles.cpp
@@ -58,8 +58,8 @@ void ParticleSystemManager::device_update_particles(Device *device, DeviceScene
* adds one dummy particle at the beginning to avoid invalid lookups,
* in case a shader uses particle info without actual particle data. */
int num_particles = 1;
- foreach(ParticleSystem *psys, scene->particle_systems)
- num_particles += psys->particles.size();
+ for(size_t j = 0; j < scene->particle_systems.size(); j++)
+ num_particles += scene->particle_systems[j]->particles.size();
float4 *particles = dscene->particles.resize(PARTICLE_SIZE*num_particles);
@@ -71,9 +71,12 @@ void ParticleSystemManager::device_update_particles(Device *device, DeviceScene
particles[4] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
int i = 1;
- foreach(ParticleSystem *psys, scene->particle_systems) {
- foreach(Particle &pa, psys->particles) {
+ for(size_t j = 0; j < scene->particle_systems.size(); j++) {
+ ParticleSystem *psys = scene->particle_systems[j];
+
+ for(size_t k = 0; k < psys->particles.size(); k++) {
/* pack in texture */
+ Particle& pa = psys->particles[k];
int offset = i*PARTICLE_SIZE;
particles[offset] = make_float4(pa.index, pa.age, pa.lifetime, pa.size);
diff --git a/intern/cycles/render/particles.h b/intern/cycles/render/particles.h
index bf2b6b77015..2509e27b44b 100644
--- a/intern/cycles/render/particles.h
+++ b/intern/cycles/render/particles.h
@@ -47,7 +47,7 @@ public:
void tag_update(Scene *scene);
- vector<Particle> particles;
+ array<Particle> particles;
};
/* ParticleSystem Manager */
diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp
index cf4c8749e2f..cb057beb40a 100644
--- a/intern/cycles/render/scene.cpp
+++ b/intern/cycles/render/scene.cpp
@@ -251,9 +251,14 @@ void Scene::device_update(Device *device_, Progress& progress)
}
if(print_stats) {
+ size_t mem_used = util_guarded_get_mem_used();
+ size_t mem_peak = util_guarded_get_mem_peak();
+
VLOG(1) << "System memory statistics after full device sync:\n"
- << " Usage: " << util_guarded_get_mem_used() << "\n"
- << " Peak: " << util_guarded_get_mem_peak();
+ << " Usage: " << string_human_readable_number(mem_used)
+ << " (" << string_human_readable_size(mem_used) << ")\n"
+ << " Peak: " << string_human_readable_number(mem_peak)
+ << " (" << string_human_readable_size(mem_peak) << ")";
}
}
@@ -267,6 +272,14 @@ Scene::MotionType Scene::need_motion(bool advanced_shading)
return MOTION_NONE;
}
+float Scene::motion_shutter_time()
+{
+ if(need_motion() == Scene::MOTION_PASS)
+ return 2.0f;
+ else
+ return camera->shuttertime;
+}
+
bool Scene::need_global_attribute(AttributeStandard std)
{
if(std == ATTR_STD_UV)
diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h
index be79e40fbb9..3ac7b3b1c40 100644
--- a/intern/cycles/render/scene.h
+++ b/intern/cycles/render/scene.h
@@ -64,7 +64,8 @@ public:
device_vector<float4> bvh_nodes;
device_vector<float4> bvh_leaf_nodes;
device_vector<uint> object_node;
- device_vector<float4> tri_storage;
+ device_vector<uint> prim_tri_index;
+ device_vector<float4> prim_tri_verts;
device_vector<uint> prim_type;
device_vector<uint> prim_visibility;
device_vector<uint> prim_index;
@@ -73,12 +74,15 @@ public:
/* mesh */
device_vector<uint> tri_shader;
device_vector<float4> tri_vnormal;
- device_vector<float4> tri_vindex;
- device_vector<float4> tri_verts;
+ device_vector<uint4> tri_vindex;
+ device_vector<uint> tri_patch;
+ device_vector<float2> tri_patch_uv;
device_vector<float4> curves;
device_vector<float4> curve_keys;
+ device_vector<uint> patches;
+
/* objects */
device_vector<float4> objects;
device_vector<float4> objects_vector;
@@ -110,12 +114,18 @@ public:
device_vector<uint> sobol_directions;
/* cpu images */
- device_vector<uchar4> tex_byte4_image[TEX_NUM_BYTE4_IMAGES_CPU];
- device_vector<float4> tex_float4_image[TEX_NUM_FLOAT4_IMAGES_CPU];
+ device_vector<uchar4> tex_byte4_image[TEX_NUM_BYTE4_CPU];
+ device_vector<float4> tex_float4_image[TEX_NUM_FLOAT4_CPU];
+ device_vector<float> tex_float_image[TEX_NUM_FLOAT_CPU];
+ device_vector<uchar> tex_byte_image[TEX_NUM_BYTE_CPU];
+ device_vector<half4> tex_half4_image[TEX_NUM_HALF4_CPU];
+ device_vector<half> tex_half_image[TEX_NUM_HALF_CPU];
/* opencl images */
device_vector<uchar4> tex_image_byte4_packed;
device_vector<float4> tex_image_float4_packed;
+ device_vector<uchar> tex_image_byte_packed;
+ device_vector<float> tex_image_float_packed;
device_vector<uint4> tex_image_packed_info;
KernelData data;
@@ -133,6 +143,7 @@ public:
BVH_NUM_TYPES,
} bvh_type;
bool use_bvh_spatial_split;
+ bool use_bvh_unaligned_nodes;
bool use_qbvh;
bool persistent_data;
@@ -141,6 +152,7 @@ public:
shadingsystem = SHADINGSYSTEM_SVM;
bvh_type = BVH_DYNAMIC;
use_bvh_spatial_split = false;
+ use_bvh_unaligned_nodes = true;
use_qbvh = false;
persistent_data = false;
}
@@ -149,6 +161,7 @@ public:
{ return !(shadingsystem == params.shadingsystem
&& bvh_type == params.bvh_type
&& use_bvh_spatial_split == params.use_bvh_spatial_split
+ && use_bvh_unaligned_nodes == params.use_bvh_unaligned_nodes
&& use_qbvh == params.use_qbvh
&& persistent_data == params.persistent_data); }
};
@@ -183,10 +196,10 @@ public:
VolumeManager *volume_manager;
/* default shaders */
- int default_surface;
- int default_light;
- int default_background;
- int default_empty;
+ Shader *default_surface;
+ Shader *default_light;
+ Shader *default_background;
+ Shader *default_empty;
/* device */
Device *device;
@@ -208,6 +221,7 @@ public:
enum MotionType { MOTION_NONE = 0, MOTION_PASS, MOTION_BLUR };
MotionType need_motion(bool advanced_shading = true);
+ float motion_shutter_time();
bool need_update();
bool need_reset();
diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp
index 63037311889..9d8c9fed7af 100644
--- a/intern/cycles/render/session.cpp
+++ b/intern/cycles/render/session.cpp
@@ -610,17 +610,17 @@ DeviceRequestedFeatures Session::get_requested_device_features()
/* TODO(sergey): Consider moving this to the Scene level. */
DeviceRequestedFeatures requested_features;
requested_features.experimental = params.experimental;
+
+ requested_features.max_closure = get_max_closure_count();
+ scene->shader_manager->get_requested_features(
+ scene,
+ &requested_features);
if(!params.background) {
+ /* Avoid too much re-compilations for viewport render. */
requested_features.max_closure = 64;
requested_features.max_nodes_group = NODE_GROUP_LEVEL_MAX;
requested_features.nodes_features = NODE_FEATURE_ALL;
}
- else {
- requested_features.max_closure = get_max_closure_count();
- scene->shader_manager->get_requested_features(
- scene,
- &requested_features);
- }
/* This features are not being tweaked as often as shaders,
* so could be done selective magic for the viewport as well.
@@ -630,11 +630,16 @@ DeviceRequestedFeatures Session::get_requested_device_features()
requested_features.use_camera_motion = scene->camera->use_motion;
foreach(Object *object, scene->objects) {
Mesh *mesh = object->mesh;
- if(mesh->curves.size() > 0) {
+ if(mesh->num_curves()) {
requested_features.use_hair = true;
}
requested_features.use_object_motion |= object->use_motion | mesh->use_motion_blur;
requested_features.use_camera_motion |= mesh->use_motion_blur;
+#ifdef WITH_OPENSUBDIV
+ if(mesh->subdivision_type != Mesh::SUBDIVISION_NONE) {
+ requested_features.use_patch_evaluation = true;
+ }
+#endif
}
BakeManager *bake_manager = scene->bake_manager;
diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h
index 02d97ce9a87..8bff0f9ed15 100644
--- a/intern/cycles/render/session.h
+++ b/intern/cycles/render/session.h
@@ -129,7 +129,7 @@ public:
function<void(RenderTile&)> write_render_tile_cb;
function<void(RenderTile&)> update_render_tile_cb;
- Session(const SessionParams& params);
+ explicit Session(const SessionParams& params);
~Session();
void start();
diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp
index 82b607563ed..06b6dd969d8 100644
--- a/intern/cycles/render/shader.cpp
+++ b/intern/cycles/render/shader.cpp
@@ -69,12 +69,12 @@ static void beckmann_table_rows(float *table, int row_from, int row_to)
/* for a given incident vector
* integrate P22_{omega_i}(x_slope, 1, 1), Eq. (10) */
- slope_x[0] = -beckmann_table_slope_max();
+ slope_x[0] = (double)-beckmann_table_slope_max();
CDF_P22_omega_i[0] = 0;
for(int index_slope_x = 1; index_slope_x < DATA_TMP_SIZE; ++index_slope_x) {
/* slope_x */
- slope_x[index_slope_x] = -beckmann_table_slope_max() + 2.0f * beckmann_table_slope_max() * index_slope_x/(DATA_TMP_SIZE - 1.0f);
+ slope_x[index_slope_x] = (double)(-beckmann_table_slope_max() + 2.0f * beckmann_table_slope_max() * index_slope_x/(DATA_TMP_SIZE - 1.0f));
/* dot product with incident vector */
float dot_product = fmaxf(0.0f, -(float)slope_x[index_slope_x]*sin_theta + cos_theta);
@@ -131,20 +131,42 @@ static void beckmann_table_build(vector<float>& table)
/* Shader */
+NODE_DEFINE(Shader)
+{
+ NodeType* type = NodeType::add("shader", create);
+
+ SOCKET_BOOLEAN(use_mis, "Use MIS", true);
+ SOCKET_BOOLEAN(use_transparent_shadow, "Use Transparent Shadow", true);
+ SOCKET_BOOLEAN(heterogeneous_volume, "Heterogeneous Volume", true);
+
+ static NodeEnum volume_sampling_method_enum;
+ volume_sampling_method_enum.insert("distance", VOLUME_SAMPLING_DISTANCE);
+ volume_sampling_method_enum.insert("equiangular", VOLUME_SAMPLING_EQUIANGULAR);
+ volume_sampling_method_enum.insert("multiple_importance", VOLUME_SAMPLING_MULTIPLE_IMPORTANCE);
+ SOCKET_ENUM(volume_sampling_method, "Volume Sampling Method", volume_sampling_method_enum, VOLUME_SAMPLING_DISTANCE);
+
+ static NodeEnum volume_interpolation_method_enum;
+ volume_interpolation_method_enum.insert("linear", VOLUME_INTERPOLATION_LINEAR);
+ volume_interpolation_method_enum.insert("cubic", VOLUME_INTERPOLATION_CUBIC);
+ SOCKET_ENUM(volume_interpolation_method, "Volume Interpolation Method", volume_interpolation_method_enum, VOLUME_INTERPOLATION_LINEAR);
+
+ static NodeEnum displacement_method_enum;
+ displacement_method_enum.insert("bump", DISPLACE_BUMP);
+ displacement_method_enum.insert("true", DISPLACE_TRUE);
+ displacement_method_enum.insert("both", DISPLACE_BOTH);
+ SOCKET_ENUM(displacement_method, "Displacement Method", displacement_method_enum, DISPLACE_BUMP);
+
+ return type;
+}
+
Shader::Shader()
+: Node(node_type)
{
- name = "";
pass_id = 0;
graph = NULL;
graph_bump = NULL;
- use_mis = true;
- use_transparent_shadow = true;
- heterogeneous_volume = true;
- volume_sampling_method = VOLUME_SAMPLING_DISTANCE;
- volume_interpolation_method = VOLUME_INTERPOLATION_LINEAR;
-
has_surface = false;
has_surface_transparent = false;
has_surface_emission = false;
@@ -157,6 +179,9 @@ Shader::Shader()
has_object_dependency = false;
has_integrator_dependency = false;
+ displacement_method = DISPLACE_BUMP;
+
+ id = -1;
used = false;
need_update = true;
@@ -169,6 +194,28 @@ Shader::~Shader()
delete graph_bump;
}
+bool Shader::is_constant_emission(float3 *emission)
+{
+ ShaderInput *surf = graph->output()->input("Surface");
+
+ if(!surf->link || surf->link->parent->type != EmissionNode::node_type) {
+ return false;
+ }
+
+ EmissionNode *node = (EmissionNode*) surf->link->parent;
+
+ assert(node->input("Color"));
+ assert(node->input("Strength"));
+
+ if(node->input("Color")->link || node->input("Strength")->link) {
+ return false;
+ }
+
+ *emission = node->color*node->strength;
+
+ return true;
+}
+
void Shader::set_graph(ShaderGraph *graph_)
{
/* do this here already so that we can detect if mesh or object attributes
@@ -196,6 +243,16 @@ void Shader::tag_update(Scene *scene)
if(use_mis && has_surface_emission)
scene->light_manager->need_update = true;
+ /* Special handle of background MIS light for now: for some reason it
+ * has use_mis set to false. We are quite close to release now, so
+ * better to be safe.
+ */
+ if(this == scene->default_background &&
+ scene->light_manager->has_background_light(scene))
+ {
+ scene->light_manager->need_update = true;
+ }
+
/* quick detection of which kind of shaders we have to avoid loading
* e.g. surface attributes when there is only a volume shader. this could
* be more fine grained but it's better than nothing */
@@ -215,6 +272,10 @@ void Shader::tag_update(Scene *scene)
attributes.clear();
foreach(ShaderNode *node, graph->nodes)
node->attributes(this, &attributes);
+
+ if(has_displacement && displacement_method == DISPLACE_BOTH) {
+ attributes.add(ATTR_STD_POSITION_UNDISPLACED);
+ }
/* compare if the attributes changed, mesh manager will check
* need_update_attributes, update the relevant meshes and clear it. */
@@ -287,14 +348,11 @@ uint ShaderManager::get_attribute_id(AttributeStandard std)
return (uint)std;
}
-int ShaderManager::get_shader_id(uint shader, Mesh *mesh, bool smooth)
+int ShaderManager::get_shader_id(Shader *shader, bool smooth)
{
/* get a shader id to pass to the kernel */
- int id = shader*2;
-
- /* index depends bump since this setting is not in the shader */
- if(mesh && mesh->displacement_method != Mesh::DISPLACE_TRUE)
- id += 1;
+ int id = shader->id;
+
/* smooth flag */
if(smooth)
id |= SHADER_SMOOTH_NORMAL;
@@ -309,21 +367,27 @@ void ShaderManager::device_update_shaders_used(Scene *scene)
{
/* figure out which shaders are in use, so SVM/OSL can skip compiling them
* for speed and avoid loading image textures into memory */
- foreach(Shader *shader, scene->shaders)
+ uint id = 0;
+ foreach(Shader *shader, scene->shaders) {
shader->used = false;
+ shader->id = id++;
+ }
+
+ scene->default_surface->used = true;
+ scene->default_light->used = true;
+ scene->default_background->used = true;
+ scene->default_empty->used = true;
- scene->shaders[scene->background->shader]->used = true;
- scene->shaders[scene->default_surface]->used = true;
- scene->shaders[scene->default_light]->used = true;
- scene->shaders[scene->default_background]->used = true;
- scene->shaders[scene->default_empty]->used = true;
+ if(scene->background->shader)
+ scene->background->shader->used = true;
foreach(Mesh *mesh, scene->meshes)
- foreach(uint shader, mesh->used_shaders)
- scene->shaders[shader]->used = true;
+ foreach(Shader *shader, mesh->used_shaders)
+ shader->used = true;
foreach(Light *light, scene->lights)
- scene->shaders[light->shader]->used = true;
+ if(light->shader)
+ light->shader->used = true;
}
void ShaderManager::device_update_common(Device *device,
@@ -337,7 +401,7 @@ void ShaderManager::device_update_common(Device *device,
if(scene->shaders.size() == 0)
return;
- uint shader_flag_size = scene->shaders.size()*4;
+ uint shader_flag_size = scene->shaders.size()*SHADER_SIZE;
uint *shader_flag = dscene->shader_flag.resize(shader_flag_size);
uint i = 0;
bool has_volumes = false;
@@ -375,17 +439,24 @@ void ShaderManager::device_update_common(Device *device,
flag |= SD_VOLUME_CUBIC;
if(shader->graph_bump)
flag |= SD_HAS_BUMP;
-
- /* regular shader */
- shader_flag[i++] = flag;
- shader_flag[i++] = shader->pass_id;
+ if(shader->displacement_method != DISPLACE_BUMP)
+ flag |= SD_HAS_DISPLACEMENT;
/* shader with bump mapping */
- if(shader->graph_bump)
+ if(shader->displacement_method != DISPLACE_TRUE && shader->graph_bump)
flag |= SD_HAS_BSSRDF_BUMP;
+ /* constant emission check */
+ float3 constant_emission = make_float3(0.0f, 0.0f, 0.0f);
+ if(shader->is_constant_emission(&constant_emission))
+ flag |= SD_HAS_CONSTANT_EMISSION;
+
+ /* regular shader */
shader_flag[i++] = flag;
shader_flag[i++] = shader->pass_id;
+ shader_flag[i++] = __float_as_int(constant_emission.x);
+ shader_flag[i++] = __float_as_int(constant_emission.y);
+ shader_flag[i++] = __float_as_int(constant_emission.z);
has_transparent_shadow |= (flag & SD_HAS_TRANSPARENT_SHADOW) != 0;
}
@@ -426,65 +497,61 @@ void ShaderManager::device_free_common(Device *device, DeviceScene *dscene, Scen
void ShaderManager::add_default(Scene *scene)
{
- Shader *shader;
- ShaderGraph *graph;
- ShaderNode *closure, *out;
-
/* default surface */
{
- graph = new ShaderGraph();
+ ShaderGraph *graph = new ShaderGraph();
- closure = graph->add(new DiffuseBsdfNode());
- closure->input("Color")->value = make_float3(0.8f, 0.8f, 0.8f);
- out = graph->output();
+ DiffuseBsdfNode *diffuse = new DiffuseBsdfNode();
+ diffuse->color = make_float3(0.8f, 0.8f, 0.8f);
+ graph->add(diffuse);
- graph->connect(closure->output("BSDF"), out->input("Surface"));
+ graph->connect(diffuse->output("BSDF"), graph->output()->input("Surface"));
- shader = new Shader();
+ Shader *shader = new Shader();
shader->name = "default_surface";
shader->graph = graph;
scene->shaders.push_back(shader);
- scene->default_surface = scene->shaders.size() - 1;
+ scene->default_surface = shader;
}
/* default light */
{
- graph = new ShaderGraph();
+ ShaderGraph *graph = new ShaderGraph();
- closure = graph->add(new EmissionNode());
- closure->input("Color")->value = make_float3(0.8f, 0.8f, 0.8f);
- closure->input("Strength")->value.x = 0.0f;
- out = graph->output();
+ EmissionNode *emission = new EmissionNode();
+ emission->color = make_float3(0.8f, 0.8f, 0.8f);
+ emission->strength = 0.0f;
+ graph->add(emission);
- graph->connect(closure->output("Emission"), out->input("Surface"));
+ graph->connect(emission->output("Emission"), graph->output()->input("Surface"));
- shader = new Shader();
+ Shader *shader = new Shader();
shader->name = "default_light";
shader->graph = graph;
scene->shaders.push_back(shader);
- scene->default_light = scene->shaders.size() - 1;
+ scene->default_light = shader;
}
/* default background */
{
- graph = new ShaderGraph();
+ ShaderGraph *graph = new ShaderGraph();
- shader = new Shader();
+ Shader *shader = new Shader();
shader->name = "default_background";
shader->graph = graph;
scene->shaders.push_back(shader);
- scene->default_background = scene->shaders.size() - 1;
+ scene->default_background = shader;
}
/* default empty */
{
- graph = new ShaderGraph();
+ ShaderGraph *graph = new ShaderGraph();
- shader = new Shader();
+ Shader *shader = new Shader();
shader->name = "default_empty";
shader->graph = graph;
scene->shaders.push_back(shader);
- scene->default_empty = scene->shaders.size() - 1;
+ scene->default_empty = shader;
}
}
@@ -524,6 +591,9 @@ void ShaderManager::get_requested_features(Scene *scene,
ShaderNode *output_node = shader->graph->output();
if(output_node->input("Displacement")->link != NULL) {
requested_features->nodes_features |= NODE_FEATURE_BUMP;
+ if(shader->displacement_method == DISPLACE_BOTH && requested_features->experimental) {
+ requested_features->nodes_features |= NODE_FEATURE_BUMP_STATE;
+ }
}
/* On top of volume nodes, also check if we need volume sampling because
* e.g. an Emission node would slip through the NODE_FEATURE_VOLUME check */
diff --git a/intern/cycles/render/shader.h b/intern/cycles/render/shader.h
index d7692a2b6f5..7d896652196 100644
--- a/intern/cycles/render/shader.h
+++ b/intern/cycles/render/shader.h
@@ -26,6 +26,8 @@
#include "attribute.h"
#include "kernel_types.h"
+#include "node.h"
+
#include "util_map.h"
#include "util_param.h"
#include "util_string.h"
@@ -64,16 +66,24 @@ enum VolumeInterpolation {
VOLUME_NUM_INTERPOLATION,
};
+enum DisplacementMethod {
+ DISPLACE_BUMP = 0,
+ DISPLACE_TRUE = 1,
+ DISPLACE_BOTH = 2,
+
+ DISPLACE_NUM_METHODS,
+};
+
/* Shader describing the appearance of a Mesh, Light or Background.
*
* While there is only a single shader graph, it has three outputs: surface,
* volume and displacement, that the shader manager will compile and execute
* separately. */
-class Shader {
+class Shader : public Node {
public:
- /* name */
- string name;
+ NODE_DECLARE;
+
int pass_id;
/* shader graph */
@@ -108,10 +118,14 @@ public:
bool has_object_dependency;
bool has_integrator_dependency;
+ /* displacement */
+ DisplacementMethod displacement_method;
+
/* requested mesh attributes */
AttributeRequestSet attributes;
/* determined before compiling */
+ uint id;
bool used;
#ifdef WITH_OSL
@@ -125,6 +139,10 @@ public:
Shader();
~Shader();
+ /* Checks whether the shader consists of just a emission node with fixed inputs that's connected directly to the output.
+ * If yes, it sets the content of emission to the constant value (color * strength), which is then used for speeding up light evaluation. */
+ bool is_constant_emission(float3* emission);
+
void set_graph(ShaderGraph *graph);
void tag_update(Scene *scene);
void tag_used(Scene *scene);
@@ -159,7 +177,7 @@ public:
uint get_attribute_id(AttributeStandard std);
/* get shader id for mesh faces */
- int get_shader_id(uint shader, Mesh *mesh = NULL, bool smooth = false);
+ int get_shader_id(Shader *shader, bool smooth = false);
/* add default shaders to scene, to use as default for things that don't
* have any shader assigned explicitly */
diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp
index 8179a30f168..4a7c4ffc0a0 100644
--- a/intern/cycles/render/svm.cpp
+++ b/intern/cycles/render/svm.cpp
@@ -27,6 +27,7 @@
#include "util_logging.h"
#include "util_foreach.h"
#include "util_progress.h"
+#include "util_task.h"
CCL_NAMESPACE_BEGIN
@@ -44,6 +45,51 @@ void SVMShaderManager::reset(Scene * /*scene*/)
{
}
+void SVMShaderManager::device_update_shader(Scene *scene,
+ Shader *shader,
+ Progress *progress,
+ vector<int4> *global_svm_nodes)
+{
+ if(progress->get_cancel()) {
+ return;
+ }
+ assert(shader->graph);
+
+ vector<int4> svm_nodes;
+ svm_nodes.push_back(make_int4(NODE_SHADER_JUMP, 0, 0, 0));
+
+ SVMCompiler::Summary summary;
+ SVMCompiler compiler(scene->shader_manager, scene->image_manager, scene->volume_manager);
+ compiler.background = (shader == scene->default_background);
+ compiler.compile(scene, shader, svm_nodes, 0, &summary);
+
+ VLOG(2) << "Compilation summary:\n"
+ << "Shader name: " << shader->name << "\n"
+ << summary.full_report();
+
+ if(shader->use_mis && shader->has_surface_emission) {
+ scene->light_manager->need_update = true;
+ }
+
+ /* We only calculate offset and do re-allocation from the locked block,
+ * actual copy we do after the lock is releases to hopefully gain some
+ * percent of performance.
+ */
+ nodes_lock_.lock();
+ size_t global_nodes_size = global_svm_nodes->size();
+ global_svm_nodes->resize(global_nodes_size + svm_nodes.size());
+ nodes_lock_.unlock();
+ /* Offset local SVM nodes to a global address space. */
+ int4& jump_node = global_svm_nodes->at(shader->id);
+ jump_node.y = svm_nodes[0].y + global_nodes_size - 1;
+ jump_node.z = svm_nodes[0].z + global_nodes_size - 1;
+ jump_node.w = svm_nodes[0].w + global_nodes_size - 1;
+ /* Copy new nodes to global storage. */
+ memcpy(&global_svm_nodes->at(global_nodes_size),
+ &svm_nodes[1],
+ sizeof(int4) * (svm_nodes.size() - 1));
+}
+
void SVMShaderManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
{
if(!need_update)
@@ -51,6 +97,8 @@ void SVMShaderManager::device_update(Device *device, DeviceScene *dscene, Scene
VLOG(1) << "Total " << scene->shaders.size() << " shaders.";
+ double start_time = time_dt();
+
/* test if we need to update */
device_free(device, dscene, scene);
@@ -63,27 +111,22 @@ void SVMShaderManager::device_update(Device *device, DeviceScene *dscene, Scene
for(i = 0; i < scene->shaders.size(); i++) {
svm_nodes.push_back(make_int4(NODE_SHADER_JUMP, 0, 0, 0));
- svm_nodes.push_back(make_int4(NODE_SHADER_JUMP, 0, 0, 0));
}
-
- for(i = 0; i < scene->shaders.size(); i++) {
- Shader *shader = scene->shaders[i];
- if(progress.get_cancel()) return;
-
- assert(shader->graph);
-
- if(shader->use_mis && shader->has_surface_emission)
- scene->light_manager->need_update = true;
-
- SVMCompiler::Summary summary;
- SVMCompiler compiler(scene->shader_manager, scene->image_manager, scene->volume_manager);
- compiler.background = ((int)i == scene->default_background);
- compiler.compile(scene, shader, svm_nodes, i, &summary);
+ TaskPool task_pool;
+ foreach(Shader *shader, scene->shaders) {
+ task_pool.push(function_bind(&SVMShaderManager::device_update_shader,
+ this,
+ scene,
+ shader,
+ &progress,
+ &svm_nodes),
+ false);
+ }
+ task_pool.wait_work();
- VLOG(2) << "Compilation summary:\n"
- << "Shader name: " << shader->name << "\n"
- << summary.full_report();
+ if(progress.get_cancel()) {
+ return;
}
dscene->svm_nodes.copy((uint4*)&svm_nodes[0], svm_nodes.size());
@@ -97,6 +140,10 @@ void SVMShaderManager::device_update(Device *device, DeviceScene *dscene, Scene
device_update_common(device, dscene, scene, progress);
need_update = false;
+
+ VLOG(1) << "Shader manager updated "
+ << scene->shaders.size() << " shaders in "
+ << time_dt() - start_time << " seconds.";
}
void SVMShaderManager::device_free(Device *device, DeviceScene *dscene, Scene *scene)
@@ -123,22 +170,22 @@ SVMCompiler::SVMCompiler(ShaderManager *shader_manager_, ImageManager *image_man
compile_failed = false;
}
-int SVMCompiler::stack_size(ShaderSocketType type)
+int SVMCompiler::stack_size(SocketType::Type type)
{
int size = 0;
switch(type) {
- case SHADER_SOCKET_FLOAT:
- case SHADER_SOCKET_INT:
+ case SocketType::FLOAT:
+ case SocketType::INT:
size = 1;
break;
- case SHADER_SOCKET_COLOR:
- case SHADER_SOCKET_VECTOR:
- case SHADER_SOCKET_NORMAL:
- case SHADER_SOCKET_POINT:
+ case SocketType::COLOR:
+ case SocketType::VECTOR:
+ case SocketType::NORMAL:
+ case SocketType::POINT:
size = 3;
break;
- case SHADER_SOCKET_CLOSURE:
+ case SocketType::CLOSURE:
size = 0;
break;
default:
@@ -149,9 +196,8 @@ int SVMCompiler::stack_size(ShaderSocketType type)
return size;
}
-int SVMCompiler::stack_find_offset(ShaderSocketType type)
+int SVMCompiler::stack_find_offset(int size)
{
- int size = stack_size(type);
int offset = -1;
/* find free space in stack & mark as used */
@@ -178,7 +224,12 @@ int SVMCompiler::stack_find_offset(ShaderSocketType type)
return 0;
}
-void SVMCompiler::stack_clear_offset(ShaderSocketType type, int offset)
+int SVMCompiler::stack_find_offset(SocketType::Type type)
+{
+ return stack_find_offset(stack_size(type));
+}
+
+void SVMCompiler::stack_clear_offset(SocketType::Type type, int offset)
{
int size = stack_size(type);
@@ -195,23 +246,25 @@ int SVMCompiler::stack_assign(ShaderInput *input)
input->stack_offset = input->link->stack_offset;
}
else {
+ Node *node = input->parent;
+
/* not linked to output -> add nodes to load default value */
- input->stack_offset = stack_find_offset(input->type);
+ input->stack_offset = stack_find_offset(input->type());
- if(input->type == SHADER_SOCKET_FLOAT) {
- add_node(NODE_VALUE_F, __float_as_int(input->value.x), input->stack_offset);
+ if(input->type() == SocketType::FLOAT) {
+ add_node(NODE_VALUE_F, __float_as_int(node->get_float(input->socket_type)), input->stack_offset);
}
- else if(input->type == SHADER_SOCKET_INT) {
- add_node(NODE_VALUE_F, (int)input->value.x, input->stack_offset);
+ else if(input->type() == SocketType::INT) {
+ add_node(NODE_VALUE_F, node->get_int(input->socket_type), input->stack_offset);
}
- else if(input->type == SHADER_SOCKET_VECTOR ||
- input->type == SHADER_SOCKET_NORMAL ||
- input->type == SHADER_SOCKET_POINT ||
- input->type == SHADER_SOCKET_COLOR)
+ else if(input->type() == SocketType::VECTOR ||
+ input->type() == SocketType::NORMAL ||
+ input->type() == SocketType::POINT ||
+ input->type() == SocketType::COLOR)
{
add_node(NODE_VALUE_V, input->stack_offset);
- add_node(NODE_VALUE_V, input->value);
+ add_node(NODE_VALUE_V, node->get_float3(input->socket_type));
}
else /* should not get called for closure */
assert(0);
@@ -225,7 +278,7 @@ int SVMCompiler::stack_assign(ShaderOutput *output)
{
/* if no stack offset assigned yet, find one */
if(output->stack_offset == SVM_STACK_INVALID)
- output->stack_offset = stack_find_offset(output->type);
+ output->stack_offset = stack_find_offset(output->type());
return output->stack_offset;
}
@@ -250,11 +303,11 @@ void SVMCompiler::stack_link(ShaderInput *input, ShaderOutput *output)
{
if(output->stack_offset == SVM_STACK_INVALID) {
assert(input->link);
- assert(stack_size(output->type) == stack_size(input->link->type));
+ assert(stack_size(output->type()) == stack_size(input->link->type()));
output->stack_offset = input->link->stack_offset;
- int size = stack_size(output->type);
+ int size = stack_size(output->type());
for(int i = 0; i < size; i++)
active_stack.users[output->stack_offset + i]++;
@@ -282,7 +335,7 @@ void SVMCompiler::stack_clear_users(ShaderNode *node, ShaderNodeSet& done)
all_done = false;
if(all_done) {
- stack_clear_offset(output->type, output->stack_offset);
+ stack_clear_offset(output->type(), output->stack_offset);
output->stack_offset = SVM_STACK_INVALID;
foreach(ShaderInput *in, output->links)
@@ -296,7 +349,7 @@ void SVMCompiler::stack_clear_temporary(ShaderNode *node)
{
foreach(ShaderInput *input, node->inputs) {
if(!input->link && input->stack_offset != SVM_STACK_INVALID) {
- stack_clear_offset(input->type, input->stack_offset);
+ stack_clear_offset(input->type(), input->stack_offset);
input->stack_offset = SVM_STACK_INVALID;
}
}
@@ -314,17 +367,17 @@ uint SVMCompiler::encode_uchar4(uint x, uint y, uint z, uint w)
void SVMCompiler::add_node(int a, int b, int c, int d)
{
- svm_nodes.push_back(make_int4(a, b, c, d));
+ current_svm_nodes.push_back(make_int4(a, b, c, d));
}
-void SVMCompiler::add_node(NodeType type, int a, int b, int c)
+void SVMCompiler::add_node(ShaderNodeType type, int a, int b, int c)
{
- svm_nodes.push_back(make_int4(type, a, b, c));
+ current_svm_nodes.push_back(make_int4(type, a, b, c));
}
-void SVMCompiler::add_node(NodeType type, const float3& f)
+void SVMCompiler::add_node(ShaderNodeType type, const float3& f)
{
- svm_nodes.push_back(make_int4(type,
+ current_svm_nodes.push_back(make_int4(type,
__float_as_int(f.x),
__float_as_int(f.y),
__float_as_int(f.z)));
@@ -332,19 +385,13 @@ void SVMCompiler::add_node(NodeType type, const float3& f)
void SVMCompiler::add_node(const float4& f)
{
- svm_nodes.push_back(make_int4(
+ current_svm_nodes.push_back(make_int4(
__float_as_int(f.x),
__float_as_int(f.y),
__float_as_int(f.z),
__float_as_int(f.w)));
}
-void SVMCompiler::add_array(float4 *f, int num)
-{
- for(int i = 0; i < num; i++)
- add_node(f[i]);
-}
-
uint SVMCompiler::attribute(ustring name)
{
return shader_manager->get_attribute_id(name);
@@ -455,7 +502,7 @@ void SVMCompiler::generate_closure_node(ShaderNode *node,
const char *weight_name = (current_type == SHADER_TYPE_VOLUME)? "VolumeMixWeight": "SurfaceMixWeight";
ShaderInput *weight_in = node->input(weight_name);
- if(weight_in && (weight_in->link || weight_in->value.x != 1.0f))
+ if(weight_in && (weight_in->link || node->get_float(weight_in->socket_type) != 1.0f))
mix_weight_offset = stack_assign(weight_in);
else
mix_weight_offset = SVM_STACK_INVALID;
@@ -488,7 +535,7 @@ void SVMCompiler::generated_shared_closure_nodes(ShaderNode *root_node,
}
else {
foreach(ShaderInput *in, node->inputs) {
- if(in->type == SHADER_SOCKET_CLOSURE && in->link)
+ if(in->type() == SocketType::CLOSURE && in->link)
generated_shared_closure_nodes(root_node,
in->link->parent,
state,
@@ -575,26 +622,38 @@ void SVMCompiler::generate_multi_closure(ShaderNode *root_node,
/* generate instructions for input closure 1 */
if(cl1in->link) {
- /* add instruction to skip closure and its dependencies if mix weight is zero */
- svm_nodes.push_back(make_int4(NODE_JUMP_IF_ONE, 0, stack_assign(facin), 0));
- int node_jump_skip_index = svm_nodes.size() - 1;
+ /* Add instruction to skip closure and its dependencies if mix
+ * weight is zero.
+ */
+ current_svm_nodes.push_back(make_int4(NODE_JUMP_IF_ONE,
+ 0,
+ stack_assign(facin),
+ 0));
+ int node_jump_skip_index = current_svm_nodes.size() - 1;
generate_multi_closure(root_node, cl1in->link->parent, state);
- /* fill in jump instruction location to be after closure */
- svm_nodes[node_jump_skip_index].y = svm_nodes.size() - node_jump_skip_index - 1;
+ /* Fill in jump instruction location to be after closure. */
+ current_svm_nodes[node_jump_skip_index].y =
+ current_svm_nodes.size() - node_jump_skip_index - 1;
}
/* generate instructions for input closure 2 */
if(cl2in->link) {
- /* add instruction to skip closure and its dependencies if mix weight is zero */
- svm_nodes.push_back(make_int4(NODE_JUMP_IF_ZERO, 0, stack_assign(facin), 0));
- int node_jump_skip_index = svm_nodes.size() - 1;
+ /* Add instruction to skip closure and its dependencies if mix
+ * weight is zero.
+ */
+ current_svm_nodes.push_back(make_int4(NODE_JUMP_IF_ZERO,
+ 0,
+ stack_assign(facin),
+ 0));
+ int node_jump_skip_index = current_svm_nodes.size() - 1;
generate_multi_closure(root_node, cl2in->link->parent, state);
- /* fill in jump instruction location to be after closure */
- svm_nodes[node_jump_skip_index].y = svm_nodes.size() - node_jump_skip_index - 1;
+ /* Fill in jump instruction location to be after closure. */
+ current_svm_nodes[node_jump_skip_index].y =
+ current_svm_nodes.size() - node_jump_skip_index - 1;
}
/* unassign */
@@ -654,6 +713,9 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
case SHADER_TYPE_DISPLACEMENT:
clin = node->input("Displacement");
break;
+ case SHADER_TYPE_BUMP:
+ clin = node->input("Normal");
+ break;
default:
assert(0);
break;
@@ -661,7 +723,7 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
/* clear all compiler state */
memset(&active_stack, 0, sizeof(active_stack));
- svm_nodes.clear();
+ current_svm_nodes.clear();
foreach(ShaderNode *node_iter, graph->nodes) {
foreach(ShaderInput *input, node_iter->inputs)
@@ -670,6 +732,14 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
output->stack_offset = SVM_STACK_INVALID;
}
+ /* for the bump shader we need add a node to store the shader state */
+ bool need_bump_state = (type == SHADER_TYPE_BUMP) && (shader->displacement_method == DISPLACE_BOTH);
+ int bump_state_offset = SVM_STACK_INVALID;
+ if(need_bump_state) {
+ bump_state_offset = stack_find_offset(SVM_BUMP_EVAL_STATE_SIZE);
+ add_node(NODE_ENTER_BUMP_EVAL, bump_state_offset);
+ }
+
if(shader->used) {
if(clin->link) {
bool generate = false;
@@ -687,6 +757,9 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
generate = true;
shader->has_displacement = true;
break;
+ case SHADER_TYPE_BUMP: /* generate bump shader */
+ generate = true;
+ break;
default:
break;
}
@@ -703,24 +776,32 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
node->compile(*this);
}
+ /* add node to restore state after bump shader has finished */
+ if(need_bump_state) {
+ add_node(NODE_LEAVE_BUMP_EVAL, bump_state_offset);
+ }
+
/* if compile failed, generate empty shader */
if(compile_failed) {
- svm_nodes.clear();
+ current_svm_nodes.clear();
compile_failed = false;
}
- add_node(NODE_END, 0, 0, 0);
+ /* for bump shaders we fall thru to the surface shader, but if this is any other kind of shader it ends here */
+ if(type != SHADER_TYPE_BUMP) {
+ add_node(NODE_END, 0, 0, 0);
+ }
}
void SVMCompiler::compile(Scene *scene,
Shader *shader,
- vector<int4>& global_svm_nodes,
+ vector<int4>& svm_nodes,
int index,
Summary *summary)
{
/* copy graph for shader with bump mapping */
ShaderNode *node = shader->graph->output();
- int start_num_svm_nodes = global_svm_nodes.size();
+ int start_num_svm_nodes = svm_nodes.size();
const double time_start = time_dt();
@@ -742,7 +823,8 @@ void SVMCompiler::compile(Scene *scene,
shader->graph_bump->finalize(scene,
true,
false,
- shader->has_integrator_dependency);
+ shader->has_integrator_dependency,
+ shader->displacement_method == DISPLACE_BOTH);
}
current_shader = shader;
@@ -759,45 +841,54 @@ void SVMCompiler::compile(Scene *scene,
shader->has_object_dependency = false;
shader->has_integrator_dependency = false;
+ /* generate bump shader */
+ if(shader->displacement_method != DISPLACE_TRUE && shader->graph_bump) {
+ scoped_timer timer((summary != NULL)? &summary->time_generate_bump: NULL);
+ compile_type(shader, shader->graph_bump, SHADER_TYPE_BUMP);
+ svm_nodes[index].y = svm_nodes.size();
+ svm_nodes.insert(svm_nodes.end(),
+ current_svm_nodes.begin(),
+ current_svm_nodes.end());
+ }
+
/* generate surface shader */
{
scoped_timer timer((summary != NULL)? &summary->time_generate_surface: NULL);
compile_type(shader, shader->graph, SHADER_TYPE_SURFACE);
- global_svm_nodes[index*2 + 0].y = global_svm_nodes.size();
- global_svm_nodes[index*2 + 1].y = global_svm_nodes.size();
- global_svm_nodes.insert(global_svm_nodes.end(), svm_nodes.begin(), svm_nodes.end());
- }
-
- if(shader->graph_bump) {
- scoped_timer timer((summary != NULL)? &summary->time_generate_bump: NULL);
- compile_type(shader, shader->graph_bump, SHADER_TYPE_SURFACE);
- global_svm_nodes[index*2 + 1].y = global_svm_nodes.size();
- global_svm_nodes.insert(global_svm_nodes.end(), svm_nodes.begin(), svm_nodes.end());
+ /* only set jump offset if there's no bump shader, as the bump shader will fall thru to this one if it exists */
+ if(shader->displacement_method == DISPLACE_TRUE || !shader->graph_bump) {
+ svm_nodes[index].y = svm_nodes.size();
+ }
+ svm_nodes.insert(svm_nodes.end(),
+ current_svm_nodes.begin(),
+ current_svm_nodes.end());
}
/* generate volume shader */
{
scoped_timer timer((summary != NULL)? &summary->time_generate_volume: NULL);
compile_type(shader, shader->graph, SHADER_TYPE_VOLUME);
- global_svm_nodes[index*2 + 0].z = global_svm_nodes.size();
- global_svm_nodes[index*2 + 1].z = global_svm_nodes.size();
- global_svm_nodes.insert(global_svm_nodes.end(), svm_nodes.begin(), svm_nodes.end());
+ svm_nodes[index].z = svm_nodes.size();
+ svm_nodes.insert(svm_nodes.end(),
+ current_svm_nodes.begin(),
+ current_svm_nodes.end());
}
/* generate displacement shader */
{
scoped_timer timer((summary != NULL)? &summary->time_generate_displacement: NULL);
compile_type(shader, shader->graph, SHADER_TYPE_DISPLACEMENT);
- global_svm_nodes[index*2 + 0].w = global_svm_nodes.size();
- global_svm_nodes[index*2 + 1].w = global_svm_nodes.size();
- global_svm_nodes.insert(global_svm_nodes.end(), svm_nodes.begin(), svm_nodes.end());
+ svm_nodes[index].w = svm_nodes.size();
+ svm_nodes.insert(svm_nodes.end(),
+ current_svm_nodes.begin(),
+ current_svm_nodes.end());
}
/* Fill in summary information. */
if(summary != NULL) {
summary->time_total = time_dt() - time_start;
summary->peak_stack_usage = max_stack_use;
- summary->num_svm_nodes = global_svm_nodes.size() - start_num_svm_nodes;
+ summary->num_svm_nodes = svm_nodes.size() - start_num_svm_nodes;
}
}
diff --git a/intern/cycles/render/svm.h b/intern/cycles/render/svm.h
index 57c15fe6b0f..eee8ba4ded8 100644
--- a/intern/cycles/render/svm.h
+++ b/intern/cycles/render/svm.h
@@ -23,6 +23,7 @@
#include "util_set.h"
#include "util_string.h"
+#include "util_thread.h"
CCL_NAMESPACE_BEGIN
@@ -47,6 +48,15 @@ public:
void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
void device_free(Device *device, DeviceScene *dscene, Scene *scene);
+
+protected:
+ /* Lock used to synchronize threaded nodes compilation. */
+ thread_spin_lock nodes_lock_;
+
+ void device_update_shader(Scene *scene,
+ Shader *shader,
+ Progress *progress,
+ vector<int4> *global_svm_nodes);
};
/* Graph Compiler */
@@ -101,15 +111,15 @@ public:
int stack_assign(ShaderInput *input);
int stack_assign_if_linked(ShaderInput *input);
int stack_assign_if_linked(ShaderOutput *output);
- int stack_find_offset(ShaderSocketType type);
- void stack_clear_offset(ShaderSocketType type, int offset);
+ int stack_find_offset(int size);
+ int stack_find_offset(SocketType::Type type);
+ void stack_clear_offset(SocketType::Type type, int offset);
void stack_link(ShaderInput *input, ShaderOutput *output);
- void add_node(NodeType type, int a = 0, int b = 0, int c = 0);
+ void add_node(ShaderNodeType type, int a = 0, int b = 0, int c = 0);
void add_node(int a = 0, int b = 0, int c = 0, int d = 0);
- void add_node(NodeType type, const float3& f);
+ void add_node(ShaderNodeType type, const float3& f);
void add_node(const float4& f);
- void add_array(float4 *f, int num);
uint attribute(ustring name);
uint attribute(AttributeStandard std);
uint encode_uchar4(uint x, uint y = 0, uint z = 0, uint w = 0);
@@ -153,7 +163,7 @@ protected:
/* Global state of the compiler accessible from the compilation routines. */
struct CompilerState {
- CompilerState(ShaderGraph *graph);
+ explicit CompilerState(ShaderGraph *graph);
/* ** Global state, used by various compilation steps. ** */
@@ -176,7 +186,7 @@ protected:
};
void stack_clear_temporary(ShaderNode *node);
- int stack_size(ShaderSocketType type);
+ int stack_size(SocketType::Type type);
void stack_clear_users(ShaderNode *node, ShaderNodeSet& done);
bool node_skip_input(ShaderNode *node, ShaderInput *input);
@@ -203,7 +213,7 @@ protected:
/* compile */
void compile_type(Shader *shader, ShaderGraph *graph, ShaderType type);
- vector<int4> svm_nodes;
+ vector<int4> current_svm_nodes;
ShaderType current_type;
Shader *current_shader;
ShaderGraph *current_graph;
diff --git a/intern/cycles/subd/CMakeLists.txt b/intern/cycles/subd/CMakeLists.txt
index 1ccf80d9457..dafb807bdf3 100644
--- a/intern/cycles/subd/CMakeLists.txt
+++ b/intern/cycles/subd/CMakeLists.txt
@@ -1,10 +1,11 @@
set(INC
.
- ../util
+ ../graph
../kernel
../kernel/svm
../render
+ ../util
)
set(INC_SYS
@@ -13,22 +14,18 @@ set(INC_SYS
set(SRC
subd_dice.cpp
- subd_mesh.cpp
subd_patch.cpp
subd_split.cpp
+ subd_patch_table.cpp
)
set(SRC_HEADERS
subd_dice.h
- subd_mesh.h
subd_patch.h
+ subd_patch_table.h
subd_split.h
)
-if(WITH_CYCLES_OPENSUBDIV)
- add_definitions(-DWITH_OPENSUBDIV)
-endif()
-
include_directories(${INC})
include_directories(SYSTEM ${INC_SYS})
diff --git a/intern/cycles/subd/subd_dice.cpp b/intern/cycles/subd/subd_dice.cpp
index a5dfcd21ceb..a1bd349b167 100644
--- a/intern/cycles/subd/subd_dice.cpp
+++ b/intern/cycles/subd/subd_dice.cpp
@@ -41,18 +41,23 @@ EdgeDice::EdgeDice(const SubdParams& params_)
}
}
-void EdgeDice::reserve(int num_verts, int num_tris)
+void EdgeDice::reserve(int num_verts)
{
Mesh *mesh = params.mesh;
vert_offset = mesh->verts.size();
- tri_offset = mesh->triangles.size();
+ tri_offset = mesh->num_triangles();
- mesh->reserve(vert_offset + num_verts, tri_offset + num_tris, 0, 0);
+ /* todo: optimize so we can reserve in advance, this is like push_back_slow() */
+ if(vert_offset + num_verts > mesh->verts.capacity()) {
+ mesh->reserve_mesh(size_t((vert_offset + num_verts) * 1.2), mesh->num_triangles());
+ }
+
+ mesh->resize_mesh(vert_offset + num_verts, tri_offset);
Attribute *attr_vN = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL);
- mesh_P = &mesh->verts[0];
+ mesh_P = mesh->verts.data();
mesh_N = attr_vN->data_float3();
}
@@ -66,25 +71,35 @@ int EdgeDice::add_vert(Patch *patch, float2 uv)
mesh_P[vert_offset] = P;
mesh_N[vert_offset] = N;
+ params.mesh->vert_patch_uv[vert_offset] = make_float2(uv.x, uv.y);
if(params.ptex) {
Attribute *attr_ptex_uv = params.mesh->attributes.add(ATTR_STD_PTEX_UV);
- params.mesh->attributes.reserve();
+ params.mesh->attributes.resize();
float3 *ptex_uv = attr_ptex_uv->data_float3();
ptex_uv[vert_offset] = make_float3(uv.x, uv.y, 0.0f);
}
+ params.mesh->num_subd_verts++;
+
return vert_offset++;
}
void EdgeDice::add_triangle(Patch *patch, int v0, int v1, int v2)
{
- params.mesh->add_triangle(v0, v1, v2, params.shader, params.smooth, false);
+ Mesh *mesh = params.mesh;
+
+ /* todo: optimize so we can reserve in advance, this is like push_back_slow() */
+ if(mesh->triangles.size() == mesh->triangles.capacity())
+ mesh->reserve_mesh(mesh->verts.size(), size_t(max(mesh->num_triangles() + 1, 1) * 1.2));
+
+ mesh->add_triangle(v0, v1, v2, patch->shader, true);
+ params.mesh->triangle_patch[params.mesh->num_triangles()-1] = patch->patch_index;
if(params.ptex) {
Attribute *attr_ptex_face_id = params.mesh->attributes.add(ATTR_STD_PTEX_FACE_ID);
- params.mesh->attributes.reserve();
+ params.mesh->attributes.resize();
float *ptex_face_id = attr_ptex_face_id->data_float();
ptex_face_id[tri_offset] = (float)patch->ptex_face_id();
@@ -141,8 +156,7 @@ void QuadDice::reserve(EdgeFactors& ef, int Mu, int Mv)
{
/* XXX need to make this also work for edge factor 0 and 1 */
int num_verts = (ef.tu0 + ef.tu1 + ef.tv0 + ef.tv1) + (Mu - 1)*(Mv - 1);
- int num_tris = 0;
- EdgeDice::reserve(num_verts, num_tris);
+ EdgeDice::reserve(num_verts);
}
float2 QuadDice::map_uv(SubPatch& sub, float u, float v)
@@ -335,160 +349,5 @@ void QuadDice::dice(SubPatch& sub, EdgeFactors& ef)
assert(vert_offset == params.mesh->verts.size());
}
-/* TriangleDice */
-
-TriangleDice::TriangleDice(const SubdParams& params_)
-: EdgeDice(params_)
-{
-}
-
-void TriangleDice::reserve(EdgeFactors& ef, int M)
-{
- int num_verts = ef.tu + ef.tv + ef.tw;
-
- for(int m = M-2; m > 0; m -= 2)
- num_verts += 3 + (m-1)*3;
-
- if(!(M & 1))
- num_verts++;
-
- EdgeDice::reserve(num_verts, 0);
-}
-
-float2 TriangleDice::map_uv(SubPatch& sub, float2 uv)
-{
- /* map UV from subpatch to patch parametric coordinates */
- return uv.x*sub.Pu + uv.y*sub.Pv + (1.0f - uv.x - uv.y)*sub.Pw;
-}
-
-int TriangleDice::add_vert(SubPatch& sub, float2 uv)
-{
- return EdgeDice::add_vert(sub.patch, map_uv(sub, uv));
-}
-
-void TriangleDice::add_grid(SubPatch& sub, EdgeFactors& ef, int M)
-{
- // XXX normals are flipped, why?
-
- /* grid is constructed starting from the outside edges, and adding
- * progressively smaller inner triangles that connected to the outer
- * one, until M = 1 or 2, the we fill up the last part. */
- vector<int> outer_u, outer_v, outer_w;
- int m;
-
- /* add outer corners vertices */
- {
- float2 p_u = make_float2(1.0f, 0.0f);
- float2 p_v = make_float2(0.0f, 1.0f);
- float2 p_w = make_float2(0.0f, 0.0f);
-
- int corner_u = add_vert(sub, p_u);
- int corner_v = add_vert(sub, p_v);
- int corner_w = add_vert(sub, p_w);
-
- outer_u.push_back(corner_v);
- outer_v.push_back(corner_w);
- outer_w.push_back(corner_u);
-
- for(int i = 1; i < ef.tu; i++)
- outer_u.push_back(add_vert(sub, interp(p_v, p_w, i/(float)ef.tu)));
- for(int i = 1; i < ef.tv; i++)
- outer_v.push_back(add_vert(sub, interp(p_w, p_u, i/(float)ef.tv)));
- for(int i = 1; i < ef.tw; i++)
- outer_w.push_back(add_vert(sub, interp(p_u, p_v, i/(float)ef.tw)));
-
- outer_u.push_back(corner_w);
- outer_v.push_back(corner_u);
- outer_w.push_back(corner_v);
- }
-
- for(m = M-2; m > 0; m -= 2) {
- vector<int> inner_u, inner_v, inner_w;
-
- const float t0 = m / (float)M;
- float2 center = make_float2(1.0f/3.0f, 1.0f/3.0f);
-
- /* 3 corner vertices */
- float2 p_u = interp(center, make_float2(1.0f, 0.0f), t0);
- float2 p_v = interp(center, make_float2(0.0f, 1.0f), t0);
- float2 p_w = interp(center, make_float2(0.0f, 0.0f), t0);
-
- int corner_u = add_vert(sub, p_u);
- int corner_v = add_vert(sub, p_v);
- int corner_w = add_vert(sub, p_w);
-
- /* construct array of vertex indices for each side */
- inner_u.push_back(corner_v);
- inner_v.push_back(corner_w);
- inner_w.push_back(corner_u);
-
- for(int i = 1; i < m; i++) {
- /* add vertices between corners */
- const float t1 = i / (float)m;
-
- inner_u.push_back(add_vert(sub, interp(p_v, p_w, t1)));
- inner_v.push_back(add_vert(sub, interp(p_w, p_u, t1)));
- inner_w.push_back(add_vert(sub, interp(p_u, p_v, t1)));
- }
-
- inner_u.push_back(corner_w);
- inner_v.push_back(corner_u);
- inner_w.push_back(corner_v);
-
- /* stitch together inner/outer with triangles */
- stitch_triangles(sub.patch, outer_u, inner_u);
- stitch_triangles(sub.patch, outer_v, inner_v);
- stitch_triangles(sub.patch, outer_w, inner_w);
-
- outer_u = inner_u;
- outer_v = inner_v;
- outer_w = inner_w;
- }
-
- /* fill up last part */
- if(m == -1) {
- /* single triangle */
- add_triangle(sub.patch, outer_w[0], outer_u[0], outer_v[0]);
- }
- else {
- /* center vertex + up to 6 triangles */
- int center = add_vert(sub, make_float2(1.0f/3.0f, 1.0f/3.0f));
-
- add_triangle(sub.patch, outer_w[0], outer_w[1], center);
- /* if this is false then there is only one triangle on this side */
- if(outer_w.size() > 2)
- add_triangle(sub.patch, outer_w[1], outer_w[2], center);
-
- add_triangle(sub.patch, outer_u[0], outer_u[1], center);
- if(outer_u.size() > 2)
- add_triangle(sub.patch, outer_u[1], outer_u[2], center);
-
- add_triangle(sub.patch, outer_v[0], outer_v[1], center);
- if(outer_v.size() > 2)
- add_triangle(sub.patch, outer_v[1], outer_v[2], center);
- }
-}
-
-void TriangleDice::dice(SubPatch& sub, EdgeFactors& ef)
-{
- /* todo: handle 2 1 1 resolution */
- int M = max(ef.tu, max(ef.tv, ef.tw));
-
- /* Due to the "slant" of the edges of a triangle compared to a quad, the internal
- * triangles end up smaller, causing over-tessellation. This is to correct for this
- * difference in area. Technically its only correct for equilateral triangles, but
- * its better than how it was.
- *
- * (2*cos(radians(30))/3)**0.5
- */
- float S = 0.7598356856515927f;
- M = max((int)ceil(S*M), 1);
-
- reserve(ef, M);
- add_grid(sub, ef, M);
-
- assert(vert_offset == params.mesh->verts.size());
-}
-
CCL_NAMESPACE_END
diff --git a/intern/cycles/subd/subd_dice.h b/intern/cycles/subd/subd_dice.h
index 8450a43129e..33d13a4ab3a 100644
--- a/intern/cycles/subd/subd_dice.h
+++ b/intern/cycles/subd/subd_dice.h
@@ -33,8 +33,6 @@ class Patch;
struct SubdParams {
Mesh *mesh;
- int shader;
- bool smooth;
bool ptex;
int test_steps;
@@ -44,16 +42,14 @@ struct SubdParams {
Camera *camera;
Transform objecttoworld;
- SubdParams(Mesh *mesh_, int shader_, bool smooth_ = true, bool ptex_ = false)
+ SubdParams(Mesh *mesh_, bool ptex_ = false)
{
mesh = mesh_;
- shader = shader_;
- smooth = smooth_;
ptex = ptex_;
test_steps = 3;
split_threshold = 1;
- dicing_rate = 0.1f;
+ dicing_rate = 1.0f;
max_level = 12;
camera = NULL;
}
@@ -70,9 +66,9 @@ public:
size_t vert_offset;
size_t tri_offset;
- EdgeDice(const SubdParams& params);
+ explicit EdgeDice(const SubdParams& params);
- void reserve(int num_verts, int num_tris);
+ void reserve(int num_verts);
int add_vert(Patch *patch, float2 uv);
void add_triangle(Patch *patch, int v0, int v1, int v2);
@@ -111,7 +107,7 @@ public:
int tv1;
};
- QuadDice(const SubdParams& params);
+ explicit QuadDice(const SubdParams& params);
void reserve(EdgeFactors& ef, int Mu, int Mv);
float3 eval_projected(SubPatch& sub, float u, float v);
@@ -136,46 +132,6 @@ public:
void dice(SubPatch& sub, EdgeFactors& ef);
};
-/* Triangle EdgeDice
- *
- * Edge tessellation factors and subpatch coordinates are as follows:
- *
- * Pw
- * /\
- * tv / \ tu
- * / \
- * / \
- * Pu -------- Pv
- * tw
- */
-
-class TriangleDice : public EdgeDice {
-public:
- struct SubPatch {
- Patch *patch;
-
- float2 Pu;
- float2 Pv;
- float2 Pw;
- };
-
- struct EdgeFactors {
- int tu;
- int tv;
- int tw;
- };
-
- TriangleDice(const SubdParams& params);
-
- void reserve(EdgeFactors& ef, int M);
-
- float2 map_uv(SubPatch& sub, float2 uv);
- int add_vert(SubPatch& sub, float2 uv);
-
- void add_grid(SubPatch& sub, EdgeFactors& ef, int M);
- void dice(SubPatch& sub, EdgeFactors& ef);
-};
-
CCL_NAMESPACE_END
#endif /* __SUBD_DICE_H__ */
diff --git a/intern/cycles/subd/subd_mesh.cpp b/intern/cycles/subd/subd_mesh.cpp
deleted file mode 100644
index d7cb7b921ee..00000000000
--- a/intern/cycles/subd/subd_mesh.cpp
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- * Original code in the public domain -- castanyo@yahoo.es
- *
- * Modifications copyright (c) 2011, Blender Foundation.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-
-#include "subd_mesh.h"
-#include "subd_patch.h"
-#include "subd_split.h"
-
-#include "util_debug.h"
-#include "util_foreach.h"
-
-#ifdef WITH_OPENSUBDIV
-
-#include <osd/vertex.h>
-#include <osd/mesh.h>
-#include <osd/cpuComputeController.h>
-#include <osd/cpuVertexBuffer.h>
-#include <osd/cpuEvalLimitController.h>
-#include <osd/evalLimitContext.h>
-
-CCL_NAMESPACE_BEGIN
-
-/* typedefs */
-typedef OpenSubdiv::OsdVertex OsdVertex;
-typedef OpenSubdiv::FarMesh<OsdVertex> OsdFarMesh;
-typedef OpenSubdiv::FarMeshFactory<OsdVertex> OsdFarMeshFactory;
-typedef OpenSubdiv::HbrCatmarkSubdivision<OsdVertex> OsdHbrCatmarkSubdivision;
-typedef OpenSubdiv::HbrFace<OsdVertex> OsdHbrFace;
-typedef OpenSubdiv::HbrHalfedge<OsdVertex> OsdHbrHalfEdge;
-typedef OpenSubdiv::HbrMesh<OsdVertex> OsdHbrMesh;
-typedef OpenSubdiv::HbrVertex<OsdVertex> OsdHbrVertex;
-typedef OpenSubdiv::OsdCpuComputeContext OsdCpuComputeContext;
-typedef OpenSubdiv::OsdCpuComputeController OsdCpuComputeController;
-typedef OpenSubdiv::OsdCpuEvalLimitContext OsdCpuEvalLimitContext;
-typedef OpenSubdiv::OsdCpuEvalLimitController OsdCpuEvalLimitController;
-typedef OpenSubdiv::OsdCpuVertexBuffer OsdCpuVertexBuffer;
-typedef OpenSubdiv::OsdEvalCoords OsdEvalCoords;
-typedef OpenSubdiv::OsdVertexBufferDescriptor OsdVertexBufferDescriptor;
-
-/* OpenSubdiv Patch */
-
-class OpenSubdPatch : public Patch {
-public:
- int face_id;
-
- OpenSubdPatch(OsdFarMesh *farmesh, OsdCpuVertexBuffer *vbuf_base)
- {
- face_id = 0;
-
- /* create buffers for evaluation */
- vbuf_P = OsdCpuVertexBuffer::Create(3, 1);
- vbuf_dPdu = OsdCpuVertexBuffer::Create(3, 1);
- vbuf_dPdv = OsdCpuVertexBuffer::Create(3, 1);
-
- P = vbuf_P->BindCpuBuffer();
- dPdu = vbuf_dPdu->BindCpuBuffer();
- dPdv = vbuf_dPdv->BindCpuBuffer();
-
- /* setup evaluation context */
- OsdVertexBufferDescriptor in_desc(0, 3, 3), out_desc(0, 3, 3); /* offset, length, stride */
-
- evalctx = OsdCpuEvalLimitContext::Create(farmesh, false);
- evalctx->GetVertexData().Bind(in_desc, vbuf_base, out_desc, vbuf_P, vbuf_dPdu, vbuf_dPdv);
- }
-
- ~OpenSubdPatch()
- {
- evalctx->GetVertexData().Unbind();
-
- delete evalctx;
- delete vbuf_P;
- delete vbuf_dPdu;
- delete vbuf_dPdv;
- }
-
- void eval(float3 *P_, float3 *dPdu_, float3 *dPdv_, float u, float v)
- {
- OsdEvalCoords coords;
- coords.u = u;
- coords.v = v;
- coords.face = face_id;
-
- evalctrl.EvalLimitSample<OsdCpuVertexBuffer,OsdCpuVertexBuffer>(coords, evalctx, 0);
-
- *P_ = make_float3(P[0], P[1], P[2]);
- if(dPdu_) *dPdu_ = make_float3(dPdv[0], dPdv[1], dPdv[2]);
- if(dPdv_) *dPdv_ = make_float3(dPdu[0], dPdu[1], dPdu[2]);
-
- /* optimize: skip evaluating derivatives when not needed */
- /* todo: swapped derivatives, different winding convention? */
- }
-
- BoundBox bound()
- {
- /* not implemented */
- BoundBox bbox = BoundBox::empty;
- return bbox;
- }
-
- int ptex_face_id()
- {
- return face_id;
- }
-
-protected:
- OsdCpuEvalLimitController evalctrl;
- OsdCpuEvalLimitContext *evalctx;
- OsdCpuVertexBuffer *vbuf_P;
- OsdCpuVertexBuffer *vbuf_dPdu;
- OsdCpuVertexBuffer *vbuf_dPdv;
- float *P;
- float *dPdu;
- float *dPdv;
-};
-
-/* OpenSubdiv Mesh */
-
-OpenSubdMesh::OpenSubdMesh()
-{
- /* create osd mesh */
- static OsdHbrCatmarkSubdivision catmark;
- OsdHbrMesh *hbrmesh = new OsdHbrMesh(&catmark);
-
- /* initialize class */
- num_verts = 0;
- num_ptex_faces = 0;
- _hbrmesh = (void*)hbrmesh;
-}
-
-OpenSubdMesh::~OpenSubdMesh()
-{
- OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh;
-
- if(hbrmesh)
- delete hbrmesh;
-}
-
-void OpenSubdMesh::add_vert(const float3& co)
-{
- OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh;
-
- OsdVertex v;
- positions.push_back(co.x);
- positions.push_back(co.y);
- positions.push_back(co.z);
- hbrmesh->NewVertex(num_verts++, v);
-}
-
-void OpenSubdMesh::add_face(int v0, int v1, int v2)
-{
- int index[3] = {v0, v1, v2};
- return add_face(index, 3);
-}
-
-void OpenSubdMesh::add_face(int v0, int v1, int v2, int v3)
-{
- int index[4] = {v0, v1, v2, v3};
- add_face(index, 4);
-}
-
-void OpenSubdMesh::add_face(int *index, int num)
-{
- OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh;
-
-#ifndef NDEBUG
- /* sanity checks */
- for(int j = 0; j < num; j++) {
- OsdHbrVertex *origin = hbrmesh->GetVertex(index[j]);
- OsdHbrVertex *destination = hbrmesh->GetVertex(index[(j+1)%num]);
- OsdHbrHalfEdge *opposite = destination->GetEdge(origin);
-
- if(origin==NULL || destination==NULL)
- assert(!"An edge was specified that connected a nonexistent vertex\n");
-
- if(origin == destination)
- assert(!"An edge was specified that connected a vertex to itself\n");
-
- if(opposite && opposite->GetOpposite())
- assert(!"A non-manifold edge incident to more than 2 faces was found\n");
-
- if(origin->GetEdge(destination)) {
- assert(!"An edge connecting two vertices was specified more than once."
- "It's likely that an incident face was flipped\n");
- }
- }
-#endif
-
- OsdHbrFace *face = hbrmesh->NewFace(num, index, 0);
-
- /* this is required for limit eval patch table? */
- face->SetPtexIndex(num_ptex_faces);
-
- if(num == 4)
- num_ptex_faces++;
- else
- num_ptex_faces += num;
-}
-
-bool OpenSubdMesh::finish()
-{
- OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh;
-
- /* finish hbr mesh construction */
- hbrmesh->SetInterpolateBoundaryMethod(OsdHbrMesh::k_InterpolateBoundaryEdgeOnly);
- hbrmesh->Finish();
-
- return true;
-}
-
-void OpenSubdMesh::tessellate(DiagSplit *split)
-{
- if(num_ptex_faces == 0)
- return;
-
- const int level = 3;
- const bool requirefvar = false;
-
- /* convert HRB to FAR mesh */
- OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh;
-
- OsdFarMeshFactory meshFactory(hbrmesh, level, true);
- OsdFarMesh *farmesh = meshFactory.Create(requirefvar);
- int num_hbr_verts = hbrmesh->GetNumVertices();
-
- delete hbrmesh;
- hbrmesh = NULL;
- _hbrmesh = NULL;
-
- /* refine HBR mesh with vertex coordinates */
- OsdCpuComputeController *compute_controller = new OsdCpuComputeController();
- OsdCpuComputeContext *compute_context = OsdCpuComputeContext::Create(farmesh);
-
- OsdCpuVertexBuffer *vbuf_base = OsdCpuVertexBuffer::Create(3, num_hbr_verts);
- vbuf_base->UpdateData(&positions[0], 0, num_verts);
-
- compute_controller->Refine(compute_context, farmesh->GetKernelBatches(), vbuf_base);
- compute_controller->Synchronize();
-
- /* split & dice patches */
- OpenSubdPatch patch(farmesh, vbuf_base);
-
- for(int f = 0; f < num_ptex_faces; f++) {
- patch.face_id = f;
- split->split_quad(&patch);
- }
-
- /* clean up */
- delete farmesh;
- delete compute_controller;
- delete compute_context;
- delete vbuf_base;
-}
-
-CCL_NAMESPACE_END
-
-#else /* WITH_OPENSUBDIV */
-
-CCL_NAMESPACE_BEGIN
-
-/* Subd Vertex */
-
-class SubdVert
-{
-public:
- int id;
- float3 co;
-
- SubdVert(int id_)
- {
- id = id_;
- co = make_float3(0.0f, 0.0f, 0.0f);
- }
-};
-
-/* Subd Face */
-
-class SubdFace
-{
-public:
- int id;
- int numverts;
- int verts[4];
-
- SubdFace(int id_)
- {
- id = id_;
- numverts = 0;
- }
-};
-
-/* Subd Mesh */
-
-SubdMesh::SubdMesh()
-{
-}
-
-SubdMesh::~SubdMesh()
-{
- foreach(SubdVert *vertex, verts)
- delete vertex;
- foreach(SubdFace *face, faces)
- delete face;
-
- verts.clear();
- faces.clear();
-}
-
-SubdVert *SubdMesh::add_vert(const float3& co)
-{
- SubdVert *v = new SubdVert(verts.size());
- v->co = co;
- verts.push_back(v);
-
- return v;
-}
-
-SubdFace *SubdMesh::add_face(int v0, int v1, int v2)
-{
- int index[3] = {v0, v1, v2};
- return add_face(index, 3);
-}
-
-SubdFace *SubdMesh::add_face(int v0, int v1, int v2, int v3)
-{
- int index[4] = {v0, v1, v2, v3};
- return add_face(index, 4);
-}
-
-SubdFace *SubdMesh::add_face(int *index, int num)
-{
- /* skip ngons */
- if(num < 3 || num > 4)
- return NULL;
-
- SubdFace *f = new SubdFace(faces.size());
-
- for(int i = 0; i < num; i++)
- f->verts[i] = index[i];
-
- f->numverts = num;
- faces.push_back(f);
-
- return f;
-}
-
-bool SubdMesh::finish()
-{
- return true;
-}
-
-void SubdMesh::tessellate(DiagSplit *split)
-{
- int num_faces = faces.size();
-
- for(int f = 0; f < num_faces; f++) {
- SubdFace *face = faces[f];
- Patch *patch;
- float3 *hull;
-
- if(face->numverts == 3) {
- LinearTrianglePatch *lpatch = new LinearTrianglePatch();
- hull = lpatch->hull;
- patch = lpatch;
- }
- else if(face->numverts == 4) {
- LinearQuadPatch *lpatch = new LinearQuadPatch();
- hull = lpatch->hull;
- patch = lpatch;
- }
- else {
- assert(0); /* n-gons should have been split already */
- continue;
- }
-
- for(int i = 0; i < face->numverts; i++)
- hull[i] = verts[face->verts[i]]->co;
-
- if(face->numverts == 4)
- swap(hull[2], hull[3]);
-
- if(patch->is_triangle())
- split->split_triangle(patch);
- else
- split->split_quad(patch);
-
- delete patch;
- }
-}
-
-CCL_NAMESPACE_END
-
-#endif /* WITH_OPENSUBDIV */
-
diff --git a/intern/cycles/subd/subd_mesh.h b/intern/cycles/subd/subd_mesh.h
deleted file mode 100644
index f6aefc20318..00000000000
--- a/intern/cycles/subd/subd_mesh.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Original code in the public domain -- castanyo@yahoo.es
- *
- * Modifications copyright (c) 2011, Blender Foundation.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef __SUBD_MESH_H__
-#define __SUBD_MESH_H__
-
-#include "util_map.h"
-#include "util_types.h"
-#include "util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef WITH_OPENSUBDIV
-class SubdVert;
-class SubdFace;
-#endif
-
-class DiagSplit;
-class Mesh;
-
-/* Subd Mesh with simple linear subdivision */
-
-class SubdMesh
-{
-public:
- SubdMesh();
- ~SubdMesh();
-
- SubdVert *add_vert(const float3& co);
-
- SubdFace *add_face(int v0, int v1, int v2);
- SubdFace *add_face(int v0, int v1, int v2, int v3);
- SubdFace *add_face(int *index, int num);
-
- bool finish();
- void tessellate(DiagSplit *split);
-
-protected:
-#ifdef WITH_OPENSUBDIV
- void *_hbrmesh;
- vector<float> positions;
- int num_verts, num_ptex_faces;
-#else
- vector<SubdVert*> verts;
- vector<SubdFace*> faces;
-#endif
-
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __SUBD_MESH_H__ */
-
diff --git a/intern/cycles/subd/subd_patch.cpp b/intern/cycles/subd/subd_patch.cpp
index 60a78016054..d3319c5ccf5 100644
--- a/intern/cycles/subd/subd_patch.cpp
+++ b/intern/cycles/subd/subd_patch.cpp
@@ -84,32 +84,6 @@ BoundBox LinearQuadPatch::bound()
return bbox;
}
-/* Linear Triangle Patch */
-
-void LinearTrianglePatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v)
-{
- *P = u*hull[0] + v*hull[1] + (1.0f - u - v)*hull[2];
-
- if(dPdu && dPdv) {
- *dPdu = hull[0] - hull[2];
- *dPdv = hull[1] - hull[2];
- }
-
- if(N) {
- *N = normalize(u*normals[0] + v*normals[1] + (1.0f - u - v)*normals[2]);
- }
-}
-
-BoundBox LinearTrianglePatch::bound()
-{
- BoundBox bbox = BoundBox::empty;
-
- for(int i = 0; i < 3; i++)
- bbox.grow(hull[i]);
-
- return bbox;
-}
-
/* Bicubic Patch */
void BicubicPatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v)
diff --git a/intern/cycles/subd/subd_patch.h b/intern/cycles/subd/subd_patch.h
index bfa04412c66..360c1abf27b 100644
--- a/intern/cycles/subd/subd_patch.h
+++ b/intern/cycles/subd/subd_patch.h
@@ -26,9 +26,11 @@ class Patch {
public:
virtual ~Patch() {}
virtual void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v) = 0;
- virtual bool is_triangle() { return false; }
virtual BoundBox bound() = 0;
virtual int ptex_face_id() { return -1; }
+
+ int patch_index;
+ int shader;
};
/* Linear Quad Patch */
@@ -39,19 +41,6 @@ public:
float3 normals[4];
void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v);
- bool is_triangle() { return false; }
- BoundBox bound();
-};
-
-/* Linear Triangle Patch */
-
-class LinearTrianglePatch : public Patch {
-public:
- float3 hull[3];
- float3 normals[3];
-
- void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v);
- bool is_triangle() { return true; }
BoundBox bound();
};
@@ -62,7 +51,6 @@ public:
float3 hull[16];
void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v);
- bool is_triangle() { return false; }
BoundBox bound();
};
diff --git a/intern/cycles/subd/subd_patch_table.cpp b/intern/cycles/subd/subd_patch_table.cpp
new file mode 100644
index 00000000000..d437b045c07
--- /dev/null
+++ b/intern/cycles/subd/subd_patch_table.cpp
@@ -0,0 +1,297 @@
+/*
+ * Based on code from OpenSubdiv released under this license:
+ *
+ * Copyright 2014 DreamWorks Animation LLC.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "Apache License")
+ * with the following modification; you may not use this file except in
+ * compliance with the Apache License and the following modification to it:
+ * Section 6. Trademarks. is deleted and replaced with:
+ *
+ * 6. Trademarks. This License does not grant permission to use the trade
+ * names, trademarks, service marks, or product names of the Licensor
+ * and its affiliates, except as required to comply with Section 4(c) of
+ * the License and to reproduce the content of the NOTICE file.
+ *
+ * You may obtain a copy of the Apache License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Apache License with the above modification is
+ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the Apache License for the specific
+ * language governing permissions and limitations under the Apache License.
+ *
+ */
+
+#include "subd_patch_table.h"
+#include "kernel_types.h"
+
+#include "util_math.h"
+
+#ifdef WITH_OPENSUBDIV
+#include <opensubdiv/far/patchTable.h>
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifdef WITH_OPENSUBDIV
+
+using namespace OpenSubdiv;
+
+/* functions for building patch maps */
+
+struct PatchMapQuadNode {
+ /* sets all the children to point to the patch of index */
+ void set_child(int index)
+ {
+ for(int i = 0; i < 4; i++) {
+ children[i] = index | PATCH_MAP_NODE_IS_SET | PATCH_MAP_NODE_IS_LEAF;
+ }
+ }
+
+ /* sets the child in quadrant to point to the node or patch of the given index */
+ void set_child(unsigned char quadrant, int index, bool is_leaf=true)
+ {
+ assert(quadrant < 4);
+ children[quadrant] = index | PATCH_MAP_NODE_IS_SET | (is_leaf ? PATCH_MAP_NODE_IS_LEAF : 0);
+ }
+
+ uint children[4];
+};
+
+template<class T>
+static int resolve_quadrant(T& median, T& u, T& v)
+{
+ int quadrant = -1;
+
+ if(u < median) {
+ if(v < median) {
+ quadrant = 0;
+ }
+ else {
+ quadrant = 1;
+ v -= median;
+ }
+ }
+ else {
+ if(v < median) {
+ quadrant = 3;
+ }
+ else {
+ quadrant = 2;
+ v -= median;
+ }
+ u -= median;
+ }
+
+ return quadrant;
+}
+
+static void build_patch_map(PackedPatchTable& table, OpenSubdiv::Far::PatchTable* patch_table, int offset)
+{
+ int num_faces = 0;
+
+ for(int array = 0; array < table.num_arrays; array++) {
+ Far::ConstPatchParamArray params = patch_table->GetPatchParams(array);
+
+ for(int j = 0; j < patch_table->GetNumPatches(array); j++) {
+ num_faces = max(num_faces, (int)params[j].GetFaceId());
+ }
+ }
+ num_faces++;
+
+ vector<PatchMapQuadNode> quadtree;
+ quadtree.reserve(num_faces + table.num_patches);
+ quadtree.resize(num_faces);
+
+ /* adjust offsets to make indices relative to the table */
+ int handle_index = -(table.num_patches * PATCH_HANDLE_SIZE);
+ offset += table.total_size();
+
+ /* populate the quadtree from the FarPatchArrays sub-patches */
+ for(int array = 0; array < table.num_arrays; array++) {
+ Far::ConstPatchParamArray params = patch_table->GetPatchParams(array);
+
+ for(int i = 0; i < patch_table->GetNumPatches(array); i++, handle_index += PATCH_HANDLE_SIZE) {
+ const Far::PatchParam& param = params[i];
+ unsigned short depth = param.GetDepth();
+
+ PatchMapQuadNode* node = &quadtree[params[i].GetFaceId()];
+
+ if(depth == (param.NonQuadRoot() ? 1 : 0)) {
+ /* special case : regular BSpline face w/ no sub-patches */
+ node->set_child(handle_index + offset);
+ continue;
+ }
+
+ int u = param.GetU();
+ int v = param.GetV();
+ int pdepth = param.NonQuadRoot() ? depth-2 : depth-1;
+ int half = 1 << pdepth;
+
+ for(int j = 0; j < depth; j++) {
+ int delta = half >> 1;
+
+ int quadrant = resolve_quadrant(half, u, v);
+ assert(quadrant >= 0);
+
+ half = delta;
+
+ if(j == pdepth) {
+ /* we have reached the depth of the sub-patch : add a leaf */
+ assert(!(node->children[quadrant] & PATCH_MAP_NODE_IS_SET));
+ node->set_child(quadrant, handle_index + offset, true);
+ break;
+ }
+ else {
+ /* travel down the child node of the corresponding quadrant */
+ if(!(node->children[quadrant] & PATCH_MAP_NODE_IS_SET)) {
+ /* create a new branch in the quadrant */
+ quadtree.push_back(PatchMapQuadNode());
+
+ int idx = (int)quadtree.size() - 1;
+ node->set_child(quadrant, idx*4 + offset, false);
+
+ node = &quadtree[idx];
+ }
+ else {
+ /* travel down an existing branch */
+ uint idx = node->children[quadrant] & PATCH_MAP_NODE_INDEX_MASK;
+ node = &(quadtree[(idx - offset)/4]);
+ }
+ }
+ }
+ }
+ }
+
+ /* copy into table */
+ assert(table.table.size() == table.total_size());
+ uint map_offset = table.total_size();
+
+ table.num_nodes = quadtree.size() * 4;
+ table.table.resize(table.total_size());
+
+ uint* data = &table.table[map_offset];
+
+ for(int i = 0; i < quadtree.size(); i++) {
+ for(int j = 0; j < 4; j++) {
+ assert(quadtree[i].children[j] & PATCH_MAP_NODE_IS_SET);
+ *(data++) = quadtree[i].children[j];
+ }
+ }
+}
+
+#endif
+
+/* packed patch table functions */
+
+size_t PackedPatchTable::total_size()
+{
+ return num_arrays * PATCH_ARRAY_SIZE +
+ num_indices +
+ num_patches * (PATCH_PARAM_SIZE + PATCH_HANDLE_SIZE) +
+ num_nodes * PATCH_NODE_SIZE;
+}
+
+void PackedPatchTable::pack(Far::PatchTable* patch_table, int offset)
+{
+ num_arrays = 0;
+ num_patches = 0;
+ num_indices = 0;
+ num_nodes = 0;
+
+#ifdef WITH_OPENSUBDIV
+ num_arrays = patch_table->GetNumPatchArrays();
+
+ for(int i = 0; i < num_arrays; i++) {
+ int patches = patch_table->GetNumPatches(i);
+ int num_control = patch_table->GetPatchArrayDescriptor(i).GetNumControlVertices();
+
+ num_patches += patches;
+ num_indices += patches * num_control;
+ }
+
+ table.resize(total_size());
+ uint* data = table.data();
+
+ uint* array = data;
+ uint* index = array + num_arrays * PATCH_ARRAY_SIZE;
+ uint* param = index + num_indices;
+ uint* handle = param + num_patches * PATCH_PARAM_SIZE;
+
+ uint current_param = 0;
+
+ for(int i = 0; i < num_arrays; i++) {
+ *(array++) = patch_table->GetPatchArrayDescriptor(i).GetType();
+ *(array++) = patch_table->GetNumPatches(i);
+ *(array++) = (index - data) + offset;
+ *(array++) = (param - data) + offset;
+
+ Far::ConstIndexArray indices = patch_table->GetPatchArrayVertices(i);
+
+ for(int j = 0; j < indices.size(); j++) {
+ *(index++) = indices[j];
+ }
+
+ const Far::PatchParamTable& param_table = patch_table->GetPatchParamTable();
+
+ int num_control = patch_table->GetPatchArrayDescriptor(i).GetNumControlVertices();
+ int patches = patch_table->GetNumPatches(i);
+
+ for(int j = 0; j < patches; j++, current_param++) {
+ *(param++) = param_table[current_param].field0;
+ *(param++) = param_table[current_param].field1;
+
+ *(handle++) = (array - data) - PATCH_ARRAY_SIZE + offset;
+ *(handle++) = (param - data) - PATCH_PARAM_SIZE + offset;
+ *(handle++) = j * num_control;
+ }
+ }
+
+ build_patch_map(*this, patch_table, offset);
+#else
+ (void)patch_table;
+ (void)offset;
+#endif
+}
+
+void PackedPatchTable::copy_adjusting_offsets(uint* dest, int doffset)
+{
+ uint* src = table.data();
+
+ /* arrays */
+ for(int i = 0; i < num_arrays; i++) {
+ *(dest++) = *(src++);
+ *(dest++) = *(src++);
+ *(dest++) = *(src++) + doffset;
+ *(dest++) = *(src++) + doffset;
+ }
+
+ /* indices */
+ for(int i = 0; i < num_indices; i++) {
+ *(dest++) = *(src++);
+ }
+
+ /* params */
+ for(int i = 0; i < num_patches; i++) {
+ *(dest++) = *(src++);
+ *(dest++) = *(src++);
+ }
+
+ /* handles */
+ for(int i = 0; i < num_patches; i++) {
+ *(dest++) = *(src++) + doffset;
+ *(dest++) = *(src++) + doffset;
+ *(dest++) = *(src++);
+ }
+
+ /* nodes */
+ for(int i = 0; i < num_nodes; i++) {
+ *(dest++) = *(src++) + doffset;
+ }
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/subd/subd_patch_table.h b/intern/cycles/subd/subd_patch_table.h
new file mode 100644
index 00000000000..3166a1691d8
--- /dev/null
+++ b/intern/cycles/subd/subd_patch_table.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __SUBD_PATCH_TABLE_H__
+#define __SUBD_PATCH_TABLE_H__
+
+#include "util_types.h"
+#include "util_vector.h"
+
+#ifdef WITH_OPENSUBDIV
+#ifdef _MSC_VER
+# include "iso646.h"
+#endif
+
+#include <opensubdiv/far/patchTable.h>
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#ifdef WITH_OPENSUBDIV
+using namespace OpenSubdiv;
+#else
+/* forward declare for when OpenSubdiv is unavailable */
+namespace Far { struct PatchTable; }
+#endif
+
+#define PATCH_ARRAY_SIZE 4
+#define PATCH_PARAM_SIZE 2
+#define PATCH_HANDLE_SIZE 3
+#define PATCH_NODE_SIZE 1
+
+struct PackedPatchTable {
+ array<uint> table;
+
+ size_t num_arrays;
+ size_t num_indices;
+ size_t num_patches;
+ size_t num_nodes;
+
+ /* calculated size from num_* members */
+ size_t total_size();
+
+ void pack(Far::PatchTable* patch_table, int offset = 0);
+ void copy_adjusting_offsets(uint* dest, int doffset);
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __SUBD_PATCH_TABLE_H__ */
+
diff --git a/intern/cycles/subd/subd_split.cpp b/intern/cycles/subd/subd_split.cpp
index c4af8cc8c43..3c91ad8ab0d 100644
--- a/intern/cycles/subd/subd_split.cpp
+++ b/intern/cycles/subd/subd_split.cpp
@@ -40,12 +40,6 @@ void DiagSplit::dispatch(QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef)
edgefactors_quad.push_back(ef);
}
-void DiagSplit::dispatch(TriangleDice::SubPatch& sub, TriangleDice::EdgeFactors& ef)
-{
- subpatches_triangle.push_back(sub);
- edgefactors_triangle.push_back(ef);
-}
-
float3 DiagSplit::to_world(Patch *patch, float2 uv)
{
float3 P;
@@ -112,34 +106,6 @@ void DiagSplit::partition_edge(Patch *patch, float2 *P, int *t0, int *t1, float2
}
}
-static float2 right_to_equilateral(float2 P)
-{
- static const float2 A = make_float2(1.0f, 0.5f);
- static const float2 B = make_float2(0.0f, sinf(M_PI_F/3.0f));
- return make_float2(dot(P, A), dot(P, B));
-}
-
-static void limit_edge_factors(const TriangleDice::SubPatch& sub, TriangleDice::EdgeFactors& ef, int max_t)
-{
- float2 Pu = sub.Pu;
- float2 Pv = sub.Pv;
- float2 Pw = sub.Pw;
-
- if(sub.patch->is_triangle()) {
- Pu = right_to_equilateral(Pu);
- Pv = right_to_equilateral(Pv);
- Pw = right_to_equilateral(Pw);
- }
-
- int tu = int(max_t * len(Pw - Pv));
- int tv = int(max_t * len(Pw - Pu));
- int tw = int(max_t * len(Pv - Pu));
-
- ef.tu = tu <= 1 ? 1 : min(ef.tu, tu);
- ef.tv = tv <= 1 ? 1 : min(ef.tv, tv);
- ef.tw = tw <= 1 ? 1 : min(ef.tw, tw);
-}
-
static void limit_edge_factors(const QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef, int max_t)
{
float2 P00 = sub.P00;
@@ -147,13 +113,6 @@ static void limit_edge_factors(const QuadDice::SubPatch& sub, QuadDice::EdgeFact
float2 P10 = sub.P10;
float2 P11 = sub.P11;
- if(sub.patch->is_triangle()) {
- P00 = right_to_equilateral(P00);
- P01 = right_to_equilateral(P01);
- P10 = right_to_equilateral(P10);
- P11 = right_to_equilateral(P11);
- }
-
int tu0 = int(max_t * len(P10 - P00));
int tu1 = int(max_t * len(P11 - P01));
int tv0 = int(max_t * len(P01 - P00));
@@ -165,84 +124,6 @@ static void limit_edge_factors(const QuadDice::SubPatch& sub, QuadDice::EdgeFact
ef.tv1 = tv1 <= 1 ? 1 : min(ef.tv1, tv1);
}
-void DiagSplit::split(TriangleDice::SubPatch& sub, TriangleDice::EdgeFactors& ef, int depth)
-{
- if(depth > 32) {
- /* We should never get here, but just in case end recursion safely. */
- ef.tu = 1;
- ef.tv = 1;
- ef.tw = 1;
-
- dispatch(sub, ef);
- return;
- }
-
- assert(ef.tu == T(sub.patch, sub.Pv, sub.Pw));
- assert(ef.tv == T(sub.patch, sub.Pw, sub.Pu));
- assert(ef.tw == T(sub.patch, sub.Pu, sub.Pv));
-
- int non_uniform_count = int(ef.tu == DSPLIT_NON_UNIFORM) +
- int(ef.tv == DSPLIT_NON_UNIFORM) +
- int(ef.tw == DSPLIT_NON_UNIFORM);
-
- switch(non_uniform_count) {
- case 1: {
- /* TODO(mai): one edge is non-uniform, split into two triangles */
- // fallthru
- }
- case 2: {
- /* TODO(mai): two edges are non-uniform, split into triangle and quad */
- // fallthru
- }
- case 3: {
- /* all three edges are non-uniform, split into three quads */
-
- /* partition edges */
- QuadDice::EdgeFactors ef0, ef1, ef2;
- float2 Pu, Pv, Pw, Pcenter;
-
- partition_edge(sub.patch, &Pu, &ef1.tv0, &ef2.tu0, sub.Pw, sub.Pv, ef.tu);
- partition_edge(sub.patch, &Pv, &ef0.tv0, &ef1.tu0, sub.Pu, sub.Pw, ef.tv);
- partition_edge(sub.patch, &Pw, &ef2.tv0, &ef0.tu0, sub.Pv, sub.Pu, ef.tw);
- Pcenter = (Pu + Pv + Pw) * (1.0f / 3.0f);
-
- /* split */
- int tsplit01 = T(sub.patch, Pv, Pcenter);
- int tsplit12 = T(sub.patch, Pu, Pcenter);
- int tsplit20 = T(sub.patch, Pw, Pcenter);
-
- ef0.tu1 = tsplit01;
- ef0.tv1 = tsplit20;
-
- ef1.tu1 = tsplit12;
- ef1.tv1 = tsplit01;
-
- ef2.tu1 = tsplit20;
- ef2.tv1 = tsplit12;
-
- /* create subpatches */
- QuadDice::SubPatch sub0 = {sub.patch, sub.Pu, Pw, Pv, Pcenter};
- QuadDice::SubPatch sub1 = {sub.patch, sub.Pw, Pv, Pu, Pcenter};
- QuadDice::SubPatch sub2 = {sub.patch, sub.Pv, Pu, Pw, Pcenter};
-
- limit_edge_factors(sub0, ef0, 1 << params.max_level);
- limit_edge_factors(sub1, ef1, 1 << params.max_level);
- limit_edge_factors(sub2, ef2, 1 << params.max_level);
-
- split(sub0, ef0, depth+1);
- split(sub1, ef1, depth+1);
- split(sub2, ef2, depth+1);
-
- break;
- }
- default: {
- /* all edges uniform, no splitting needed */
- dispatch(sub, ef);
- break;
- }
- }
-}
-
void DiagSplit::split(QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef, int depth)
{
if(depth > 32) {
@@ -259,6 +140,16 @@ void DiagSplit::split(QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef, int de
bool split_u = (ef.tu0 == DSPLIT_NON_UNIFORM || ef.tu1 == DSPLIT_NON_UNIFORM);
bool split_v = (ef.tv0 == DSPLIT_NON_UNIFORM || ef.tv1 == DSPLIT_NON_UNIFORM);
+ /* Split subpatches such that the ratio of T for opposite edges doesn't
+ * exceed 1.5, this reduces over tessellation for some patches
+ */
+ bool tmp_split_v = split_v;
+ if(!split_u && min(ef.tu0, ef.tu1) > 8 && min(ef.tu0, ef.tu1)*1.5f < max(ef.tu0, ef.tu1))
+ split_v = true;
+ if(!tmp_split_v && min(ef.tu0, ef.tu1) > 8 && min(ef.tv0, ef.tv1)*1.5f < max(ef.tv0, ef.tv1))
+ split_u = true;
+
+ /* alternate axis */
if(split_u && split_v) {
split_u = depth % 2;
}
@@ -324,69 +215,21 @@ void DiagSplit::split(QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef, int de
}
}
-void DiagSplit::split_triangle(Patch *patch)
-{
- TriangleDice::SubPatch sub_split;
- TriangleDice::EdgeFactors ef_split;
-
- sub_split.patch = patch;
- sub_split.Pu = make_float2(1.0f, 0.0f);
- sub_split.Pv = make_float2(0.0f, 1.0f);
- sub_split.Pw = make_float2(0.0f, 0.0f);
-
- ef_split.tu = T(patch, sub_split.Pv, sub_split.Pw);
- ef_split.tv = T(patch, sub_split.Pw, sub_split.Pu);
- ef_split.tw = T(patch, sub_split.Pu, sub_split.Pv);
-
- limit_edge_factors(sub_split, ef_split, 1 << params.max_level);
-
- split(sub_split, ef_split);
-
- TriangleDice dice(params);
-
- for(size_t i = 0; i < subpatches_triangle.size(); i++) {
- TriangleDice::SubPatch& sub = subpatches_triangle[i];
- TriangleDice::EdgeFactors& ef = edgefactors_triangle[i];
-
- ef.tu = max(ef.tu, 1);
- ef.tv = max(ef.tv, 1);
- ef.tw = max(ef.tw, 1);
-
- dice.dice(sub, ef);
- }
-
- subpatches_triangle.clear();
- edgefactors_triangle.clear();
-
- /* triangle might be split into quads so dice quad subpatches as well */
- QuadDice qdice(params);
-
- for(size_t i = 0; i < subpatches_quad.size(); i++) {
- QuadDice::SubPatch& sub = subpatches_quad[i];
- QuadDice::EdgeFactors& ef = edgefactors_quad[i];
-
- ef.tu0 = max(ef.tu0, 1);
- ef.tu1 = max(ef.tu1, 1);
- ef.tv0 = max(ef.tv0, 1);
- ef.tv1 = max(ef.tv1, 1);
-
- qdice.dice(sub, ef);
- }
-
- subpatches_quad.clear();
- edgefactors_quad.clear();
-}
-
-void DiagSplit::split_quad(Patch *patch)
+void DiagSplit::split_quad(Patch *patch, QuadDice::SubPatch *subpatch)
{
QuadDice::SubPatch sub_split;
QuadDice::EdgeFactors ef_split;
- sub_split.patch = patch;
- sub_split.P00 = make_float2(0.0f, 0.0f);
- sub_split.P10 = make_float2(1.0f, 0.0f);
- sub_split.P01 = make_float2(0.0f, 1.0f);
- sub_split.P11 = make_float2(1.0f, 1.0f);
+ if(subpatch) {
+ sub_split = *subpatch;
+ }
+ else {
+ sub_split.patch = patch;
+ sub_split.P00 = make_float2(0.0f, 0.0f);
+ sub_split.P10 = make_float2(1.0f, 0.0f);
+ sub_split.P01 = make_float2(0.0f, 1.0f);
+ sub_split.P11 = make_float2(1.0f, 1.0f);
+ }
ef_split.tu0 = T(patch, sub_split.P00, sub_split.P10);
ef_split.tu1 = T(patch, sub_split.P01, sub_split.P11);
diff --git a/intern/cycles/subd/subd_split.h b/intern/cycles/subd/subd_split.h
index f04c51dedfe..a2f76dd2e03 100644
--- a/intern/cycles/subd/subd_split.h
+++ b/intern/cycles/subd/subd_split.h
@@ -38,12 +38,10 @@ class DiagSplit {
public:
vector<QuadDice::SubPatch> subpatches_quad;
vector<QuadDice::EdgeFactors> edgefactors_quad;
- vector<TriangleDice::SubPatch> subpatches_triangle;
- vector<TriangleDice::EdgeFactors> edgefactors_triangle;
SubdParams params;
- DiagSplit(const SubdParams& params);
+ explicit DiagSplit(const SubdParams& params);
float3 to_world(Patch *patch, float2 uv);
int T(Patch *patch, float2 Pstart, float2 Pend);
@@ -53,11 +51,7 @@ public:
void dispatch(QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef);
void split(QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef, int depth=0);
- void dispatch(TriangleDice::SubPatch& sub, TriangleDice::EdgeFactors& ef);
- void split(TriangleDice::SubPatch& sub, TriangleDice::EdgeFactors& ef, int depth=0);
-
- void split_triangle(Patch *patch);
- void split_quad(Patch *patch);
+ void split_quad(Patch *patch, QuadDice::SubPatch *subpatch=NULL);
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/test/CMakeLists.txt b/intern/cycles/test/CMakeLists.txt
index 2f3a4d0b1df..9af777fb9dd 100644
--- a/intern/cycles/test/CMakeLists.txt
+++ b/intern/cycles/test/CMakeLists.txt
@@ -14,9 +14,48 @@ endmacro()
set(INC
.
..
+ ../device
+ ../graph
+ ../kernel
+ ../render
../util
)
+set(ALL_CYCLES_LIBRARIES
+ cycles_render
+ cycles_device
+ cycles_bvh
+ cycles_graph
+ cycles_subd
+ cycles_util
+ ${OPENIMAGEIO_LIBRARIES}
+)
+if(WITH_CYCLES_OSL)
+ list(APPEND ALL_CYCLES_LIBRARIES
+ cycles_kernel_osl
+ ${OSL_LIBRARIES}
+ ${LLVM_LIBRARIES}
+ )
+endif()
+if(WITH_IMAGE_OPENJPEG AND NOT WITH_SYSTEM_OPENJPEG)
+ list(APPEND ALL_CYCLES_LIBRARIES
+ extern_openjpeg
+ )
+endif()
+if(WITH_CYCLES_OPENSUBDIV)
+ add_definitions(-DWITH_OPENSUBDIV)
+ include_directories(
+ SYSTEM
+ ${OPENSUBDIV_INCLUDE_DIR}
+ )
+ list(APPEND ALL_CYCLES_LIBRARIES
+ ${OPENSUBDIV_LIBRARIES}
+ )
+endif()
+list(APPEND ALL_CYCLES_LIBRARIES
+ ${BOOST_LIBRARIES}
+)
+
include_directories(${INC})
link_directories(${BOOST_LIBPATH})
@@ -25,6 +64,7 @@ link_directories(${OPENIMAGEIO_LIBPATH})
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PLATFORM_LINKFLAGS}")
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${PLATFORM_LINKFLAGS_DEBUG}")
+CYCLES_TEST(render_graph_finalize "${ALL_CYCLES_LIBRARIES}")
CYCLES_TEST(util_aligned_malloc "cycles_util")
CYCLES_TEST(util_path "cycles_util;${BOOST_LIBRARIES};${OPENIMAGEIO_LIBRARIES}")
CYCLES_TEST(util_string "cycles_util;${BOOST_LIBRARIES}")
diff --git a/intern/cycles/test/render_graph_finalize_test.cpp b/intern/cycles/test/render_graph_finalize_test.cpp
new file mode 100644
index 00000000000..32b4c7265ee
--- /dev/null
+++ b/intern/cycles/test/render_graph_finalize_test.cpp
@@ -0,0 +1,1680 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "testing/testing.h"
+#include "testing/mock_log.h"
+
+#include "render/graph.h"
+#include "render/scene.h"
+#include "render/nodes.h"
+#include "util/util_logging.h"
+#include "util/util_string.h"
+#include "util/util_vector.h"
+
+using testing::AnyNumber;
+using testing::HasSubstr;
+using testing::ScopedMockLog;
+using testing::_;
+
+CCL_NAMESPACE_BEGIN
+
+namespace {
+
+template<typename T>
+class ShaderNodeBuilder {
+public:
+ ShaderNodeBuilder(const string& name)
+ : name_(name)
+ {
+ node_ = new T();
+ node_->name = name;
+ }
+
+ const string& name() const {
+ return name_;
+ }
+
+ ShaderNode *node() const {
+ return node_;
+ }
+
+ template<typename V>
+ ShaderNodeBuilder& set(const string& input_name, V value)
+ {
+ ShaderInput *input_socket = node_->input(input_name.c_str());
+ EXPECT_NE((void*)NULL, input_socket);
+ input_socket->set(value);
+ return *this;
+ }
+
+ template<typename T2, typename V>
+ ShaderNodeBuilder& set(V T2::*pfield, V value)
+ {
+ static_cast<T*>(node_)->*pfield = value;
+ return *this;
+ }
+
+protected:
+ string name_;
+ ShaderNode *node_;
+};
+
+class ShaderGraphBuilder {
+public:
+ explicit ShaderGraphBuilder(ShaderGraph *graph)
+ : graph_(graph)
+ {
+ node_map_["Output"] = graph->output();
+ }
+
+ ShaderNode *find_node(const string& name)
+ {
+ map<string, ShaderNode *>::iterator it = node_map_.find(name);
+ if(it == node_map_.end()) {
+ return NULL;
+ }
+ return it->second;
+ }
+
+ template<typename T>
+ ShaderGraphBuilder& add_node(const T& node)
+ {
+ EXPECT_EQ(NULL, find_node(node.name()));
+ graph_->add(node.node());
+ node_map_[node.name()] = node.node();
+ return *this;
+ }
+
+ ShaderGraphBuilder& add_connection(const string& from,
+ const string& to)
+ {
+ vector<string> tokens_from, tokens_to;
+ string_split(tokens_from, from, "::");
+ string_split(tokens_to, to, "::");
+ EXPECT_EQ(2, tokens_from.size());
+ EXPECT_EQ(2, tokens_to.size());
+ ShaderNode *node_from = find_node(tokens_from[0]),
+ *node_to = find_node(tokens_to[0]);
+ EXPECT_NE((void*)NULL, node_from);
+ EXPECT_NE((void*)NULL, node_to);
+ EXPECT_NE(node_from, node_to);
+ ShaderOutput *socket_from = node_from->output(tokens_from[1].c_str());
+ ShaderInput *socket_to = node_to->input(tokens_to[1].c_str());
+ EXPECT_NE((void*)NULL, socket_from);
+ EXPECT_NE((void*)NULL, socket_to);
+ graph_->connect(socket_from, socket_to);
+ return *this;
+ }
+
+ /* Common input/output boilerplate. */
+ ShaderGraphBuilder& add_attribute(const string &name)
+ {
+ return (*this)
+ .add_node(ShaderNodeBuilder<AttributeNode>(name)
+ .set(&AttributeNode::attribute, ustring(name)));
+ }
+
+ ShaderGraphBuilder& output_closure(const string& from)
+ {
+ return (*this).add_connection(from, "Output::Surface");
+ }
+
+ ShaderGraphBuilder& output_color(const string& from)
+ {
+ return (*this)
+ .add_node(ShaderNodeBuilder<EmissionNode>("EmissionNode"))
+ .add_connection(from, "EmissionNode::Color")
+ .output_closure("EmissionNode::Emission");
+ }
+
+ ShaderGraphBuilder& output_value(const string& from)
+ {
+ return (*this)
+ .add_node(ShaderNodeBuilder<EmissionNode>("EmissionNode"))
+ .add_connection(from, "EmissionNode::Strength")
+ .output_closure("EmissionNode::Emission");
+ }
+
+protected:
+ ShaderGraph *graph_;
+ map<string, ShaderNode *> node_map_;
+};
+
+} // namespace
+
+#define DEFINE_COMMON_VARIABLES(builder_name, mock_log_name) \
+ util_logging_start(); \
+ util_logging_verbosity_set(1); \
+ ScopedMockLog mock_log_name; \
+ DeviceInfo device_info; \
+ SceneParams scene_params; \
+ Scene scene(scene_params, device_info); \
+ ShaderGraph graph; \
+ ShaderGraphBuilder builder(&graph); \
+
+#define EXPECT_ANY_MESSAGE(log) \
+ EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); \
+
+#define CORRECT_INFO_MESSAGE(log, message) \
+ EXPECT_CALL(log, Log(google::INFO, _, HasSubstr(message)));
+
+#define INVALID_INFO_MESSAGE(log, message) \
+ EXPECT_CALL(log, Log(google::INFO, _, HasSubstr(message))).Times(0);
+
+/*
+ * Test deduplication of nodes that have inputs, some of them folded.
+ */
+TEST(render_graph, deduplicate_deep)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding Value1::Value to constant (0.8).");
+ CORRECT_INFO_MESSAGE(log, "Folding Value2::Value to constant (0.8).");
+ CORRECT_INFO_MESSAGE(log, "Deduplicated 2 nodes.");
+
+ builder
+ .add_node(ShaderNodeBuilder<GeometryNode>("Geometry1"))
+ .add_node(ShaderNodeBuilder<GeometryNode>("Geometry2"))
+ .add_node(ShaderNodeBuilder<ValueNode>("Value1")
+ .set(&ValueNode::value, 0.8f))
+ .add_node(ShaderNodeBuilder<ValueNode>("Value2")
+ .set(&ValueNode::value, 0.8f))
+ .add_node(ShaderNodeBuilder<NoiseTextureNode>("Noise1"))
+ .add_node(ShaderNodeBuilder<NoiseTextureNode>("Noise2"))
+ .add_node(ShaderNodeBuilder<MixNode>("Mix")
+ .set(&MixNode::type, NODE_MIX_BLEND)
+ .set("Fac", 0.5f))
+ .add_connection("Geometry1::Parametric", "Noise1::Vector")
+ .add_connection("Value1::Value", "Noise1::Scale")
+ .add_connection("Noise1::Color", "Mix::Color1")
+ .add_connection("Geometry2::Parametric", "Noise2::Vector")
+ .add_connection("Value2::Value", "Noise2::Scale")
+ .add_connection("Noise2::Color", "Mix::Color2")
+ .output_color("Mix::Color");
+
+ graph.finalize(&scene);
+
+ EXPECT_EQ(graph.nodes.size(), 5);
+}
+
+/*
+ * Test RGB to BW node.
+ */
+TEST(render_graph, constant_fold_rgb_to_bw)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding RGBToBWNodeNode::Val to constant (0.8).");
+ CORRECT_INFO_MESSAGE(log, "Folding convert_float_to_color::value_color to constant (0.8, 0.8, 0.8).");
+
+ builder
+ .add_node(ShaderNodeBuilder<RGBToBWNode>("RGBToBWNodeNode")
+ .set("Color", make_float3(0.8f, 0.8f, 0.8f)))
+ .output_color("RGBToBWNodeNode::Val");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests:
+ * - folding of Emission nodes that don't emit to nothing.
+ */
+TEST(render_graph, constant_fold_emission1)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Discarding closure Emission.");
+
+ builder
+ .add_node(ShaderNodeBuilder<EmissionNode>("Emission")
+ .set("Color", make_float3(0.0f, 0.0f, 0.0f)))
+ .output_closure("Emission::Emission");
+
+ graph.finalize(&scene);
+}
+
+TEST(render_graph, constant_fold_emission2)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Discarding closure Emission.");
+
+ builder
+ .add_node(ShaderNodeBuilder<EmissionNode>("Emission")
+ .set("Strength", 0.0f))
+ .output_closure("Emission::Emission");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests:
+ * - folding of Background nodes that don't emit to nothing.
+ */
+TEST(render_graph, constant_fold_background1)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Discarding closure Background.");
+
+ builder
+ .add_node(ShaderNodeBuilder<BackgroundNode>("Background")
+ .set("Color", make_float3(0.0f, 0.0f, 0.0f)))
+ .output_closure("Background::Background");
+
+ graph.finalize(&scene);
+}
+
+TEST(render_graph, constant_fold_background2)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Discarding closure Background.");
+
+ builder
+ .add_node(ShaderNodeBuilder<BackgroundNode>("Background")
+ .set("Strength", 0.0f))
+ .output_closure("Background::Background");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests:
+ * - Folding of Add Closure with only one input.
+ */
+TEST(render_graph, constant_fold_shader_add)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding AddClosure1::Closure to socket Diffuse::BSDF.");
+ CORRECT_INFO_MESSAGE(log, "Folding AddClosure2::Closure to socket Diffuse::BSDF.");
+ INVALID_INFO_MESSAGE(log, "Folding AddClosure3");
+
+ builder
+ .add_node(ShaderNodeBuilder<DiffuseBsdfNode>("Diffuse"))
+ .add_node(ShaderNodeBuilder<AddClosureNode>("AddClosure1"))
+ .add_node(ShaderNodeBuilder<AddClosureNode>("AddClosure2"))
+ .add_node(ShaderNodeBuilder<AddClosureNode>("AddClosure3"))
+ .add_connection("Diffuse::BSDF", "AddClosure1::Closure1")
+ .add_connection("Diffuse::BSDF", "AddClosure2::Closure2")
+ .add_connection("AddClosure1::Closure", "AddClosure3::Closure1")
+ .add_connection("AddClosure2::Closure", "AddClosure3::Closure2")
+ .output_closure("AddClosure3::Closure");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests:
+ * - Folding of Mix Closure with 0 or 1 fac.
+ * - Folding of Mix Closure with both inputs folded to the same node.
+ */
+TEST(render_graph, constant_fold_shader_mix)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding MixClosure1::Closure to socket Diffuse::BSDF.");
+ CORRECT_INFO_MESSAGE(log, "Folding MixClosure2::Closure to socket Diffuse::BSDF.");
+ CORRECT_INFO_MESSAGE(log, "Folding MixClosure3::Closure to socket Diffuse::BSDF.");
+
+ builder
+ .add_attribute("Attribute")
+ .add_node(ShaderNodeBuilder<DiffuseBsdfNode>("Diffuse"))
+ /* choose left */
+ .add_node(ShaderNodeBuilder<MixClosureNode>("MixClosure1")
+ .set("Fac", 0.0f))
+ .add_connection("Diffuse::BSDF", "MixClosure1::Closure1")
+ /* choose right */
+ .add_node(ShaderNodeBuilder<MixClosureNode>("MixClosure2")
+ .set("Fac", 1.0f))
+ .add_connection("Diffuse::BSDF", "MixClosure2::Closure2")
+ /* both inputs folded the same */
+ .add_node(ShaderNodeBuilder<MixClosureNode>("MixClosure3"))
+ .add_connection("Attribute::Fac", "MixClosure3::Fac")
+ .add_connection("MixClosure1::Closure", "MixClosure3::Closure1")
+ .add_connection("MixClosure2::Closure", "MixClosure3::Closure2")
+ .output_closure("MixClosure3::Closure");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests:
+ * - Folding of Invert with all constant inputs.
+ */
+TEST(render_graph, constant_fold_invert)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding Invert::Color to constant (0.68, 0.5, 0.32).");
+
+ builder
+ .add_node(ShaderNodeBuilder<InvertNode>("Invert")
+ .set("Fac", 0.8f)
+ .set("Color", make_float3(0.2f, 0.5f, 0.8f)))
+ .output_color("Invert::Color");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests:
+ * - Folding of Invert with zero Fac.
+ */
+TEST(render_graph, constant_fold_invert_fac_0)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding Invert::Color to socket Attribute::Color.");
+
+ builder
+ .add_attribute("Attribute")
+ .add_node(ShaderNodeBuilder<InvertNode>("Invert")
+ .set("Fac", 0.0f))
+ .add_connection("Attribute::Color", "Invert::Color")
+ .output_color("Invert::Color");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests:
+ * - Folding of Invert with zero Fac and constant input.
+ */
+TEST(render_graph, constant_fold_invert_fac_0_const)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding Invert::Color to constant (0.2, 0.5, 0.8).");
+
+ builder
+ .add_node(ShaderNodeBuilder<InvertNode>("Invert")
+ .set("Fac", 0.0f)
+ .set("Color", make_float3(0.2f, 0.5f, 0.8f)))
+ .output_color("Invert::Color");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests:
+ * - Folding of MixRGB Add with all constant inputs (clamp false).
+ */
+TEST(render_graph, constant_fold_mix_add)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding MixAdd::Color to constant (0.62, 1.14, 1.42).");
+
+ builder
+ .add_node(ShaderNodeBuilder<MixNode>("MixAdd")
+ .set(&MixNode::type, NODE_MIX_ADD)
+ .set(&MixNode::use_clamp, false)
+ .set("Fac", 0.8f)
+ .set("Color1", make_float3(0.3, 0.5, 0.7))
+ .set("Color2", make_float3(0.4, 0.8, 0.9)))
+ .output_color("MixAdd::Color");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests:
+ * - Folding of MixRGB Add with all constant inputs (clamp true).
+ */
+TEST(render_graph, constant_fold_mix_add_clamp)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding MixAdd::Color to constant (0.62, 1, 1).");
+
+ builder
+ .add_node(ShaderNodeBuilder<MixNode>("MixAdd")
+ .set(&MixNode::type, NODE_MIX_ADD)
+ .set(&MixNode::use_clamp, true)
+ .set("Fac", 0.8f)
+ .set("Color1", make_float3(0.3, 0.5, 0.7))
+ .set("Color2", make_float3(0.4, 0.8, 0.9)))
+ .output_color("MixAdd::Color");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests:
+ * - No folding on fac 0 for dodge.
+ */
+TEST(render_graph, constant_fold_part_mix_dodge_no_fac_0)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ INVALID_INFO_MESSAGE(log, "Folding ");
+
+ builder
+ .add_attribute("Attribute1")
+ .add_attribute("Attribute2")
+ .add_node(ShaderNodeBuilder<MixNode>("Mix")
+ .set(&MixNode::type, NODE_MIX_DODGE)
+ .set(&MixNode::use_clamp, false)
+ .set("Fac", 0.0f))
+ .add_connection("Attribute1::Color", "Mix::Color1")
+ .add_connection("Attribute2::Color", "Mix::Color2")
+ .output_color("Mix::Color");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests:
+ * - No folding on fac 0 for light.
+ */
+TEST(render_graph, constant_fold_part_mix_light_no_fac_0)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ INVALID_INFO_MESSAGE(log, "Folding ");
+
+ builder
+ .add_attribute("Attribute1")
+ .add_attribute("Attribute2")
+ .add_node(ShaderNodeBuilder<MixNode>("Mix")
+ .set(&MixNode::type, NODE_MIX_LIGHT)
+ .set(&MixNode::use_clamp, false)
+ .set("Fac", 0.0f))
+ .add_connection("Attribute1::Color", "Mix::Color1")
+ .add_connection("Attribute2::Color", "Mix::Color2")
+ .output_color("Mix::Color");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests:
+ * - No folding on fac 0 for burn.
+ */
+TEST(render_graph, constant_fold_part_mix_burn_no_fac_0)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ INVALID_INFO_MESSAGE(log, "Folding ");
+
+ builder
+ .add_attribute("Attribute1")
+ .add_attribute("Attribute2")
+ .add_node(ShaderNodeBuilder<MixNode>("Mix")
+ .set(&MixNode::type, NODE_MIX_BURN)
+ .set(&MixNode::use_clamp, false)
+ .set("Fac", 0.0f))
+ .add_connection("Attribute1::Color", "Mix::Color1")
+ .add_connection("Attribute2::Color", "Mix::Color2")
+ .output_color("Mix::Color");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests:
+ * - No folding on fac 0 for clamped blend.
+ */
+TEST(render_graph, constant_fold_part_mix_blend_clamped_no_fac_0)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ INVALID_INFO_MESSAGE(log, "Folding ");
+
+ builder
+ .add_attribute("Attribute1")
+ .add_attribute("Attribute2")
+ .add_node(ShaderNodeBuilder<MixNode>("Mix")
+ .set(&MixNode::type, NODE_MIX_BLEND)
+ .set(&MixNode::use_clamp, true)
+ .set("Fac", 0.0f))
+ .add_connection("Attribute1::Color", "Mix::Color1")
+ .add_connection("Attribute2::Color", "Mix::Color2")
+ .output_color("Mix::Color");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests:
+ * - Folding of Mix with 0 or 1 Fac.
+ * - Folding of Mix with both inputs folded to the same node.
+ */
+TEST(render_graph, constant_fold_part_mix_blend)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding MixBlend1::Color to socket Attribute1::Color.");
+ CORRECT_INFO_MESSAGE(log, "Folding MixBlend2::Color to socket Attribute1::Color.");
+ CORRECT_INFO_MESSAGE(log, "Folding MixBlend3::Color to socket Attribute1::Color.");
+
+ builder
+ .add_attribute("Attribute1")
+ .add_attribute("Attribute2")
+ /* choose left */
+ .add_node(ShaderNodeBuilder<MixNode>("MixBlend1")
+ .set(&MixNode::type, NODE_MIX_BLEND)
+ .set(&MixNode::use_clamp, false)
+ .set("Fac", 0.0f))
+ .add_connection("Attribute1::Color", "MixBlend1::Color1")
+ .add_connection("Attribute2::Color", "MixBlend1::Color2")
+ /* choose right */
+ .add_node(ShaderNodeBuilder<MixNode>("MixBlend2")
+ .set(&MixNode::type, NODE_MIX_BLEND)
+ .set(&MixNode::use_clamp, false)
+ .set("Fac", 1.0f))
+ .add_connection("Attribute1::Color", "MixBlend2::Color2")
+ .add_connection("Attribute2::Color", "MixBlend2::Color1")
+ /* both inputs folded to Attribute1 */
+ .add_node(ShaderNodeBuilder<MixNode>("MixBlend3")
+ .set(&MixNode::type, NODE_MIX_BLEND)
+ .set(&MixNode::use_clamp, false))
+ .add_connection("Attribute1::Fac", "MixBlend3::Fac")
+ .add_connection("MixBlend1::Color", "MixBlend3::Color1")
+ .add_connection("MixBlend2::Color", "MixBlend3::Color2")
+ .output_color("MixBlend3::Color");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests:
+ * - NOT folding of MixRGB Sub with the same inputs and fac NOT 1.
+ */
+TEST(render_graph, constant_fold_part_mix_sub_same_fac_bad)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ INVALID_INFO_MESSAGE(log, "Folding Mix::");
+
+ builder
+ .add_attribute("Attribute")
+ .add_node(ShaderNodeBuilder<MixNode>("Mix")
+ .set(&MixNode::type, NODE_MIX_SUB)
+ .set(&MixNode::use_clamp, true)
+ .set("Fac", 0.5f))
+ .add_connection("Attribute::Color", "Mix::Color1")
+ .add_connection("Attribute::Color", "Mix::Color2")
+ .output_color("Mix::Color");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests:
+ * - Folding of MixRGB Sub with the same inputs and fac 1.
+ */
+TEST(render_graph, constant_fold_part_mix_sub_same_fac_1)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding Mix::Color to constant (0, 0, 0).");
+
+ builder
+ .add_attribute("Attribute")
+ .add_node(ShaderNodeBuilder<MixNode>("Mix")
+ .set(&MixNode::type, NODE_MIX_SUB)
+ .set(&MixNode::use_clamp, true)
+ .set("Fac", 1.0f))
+ .add_connection("Attribute::Color", "Mix::Color1")
+ .add_connection("Attribute::Color", "Mix::Color2")
+ .output_color("Mix::Color");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Graph for testing partial folds of MixRGB with one constant argument.
+ * Includes 4 tests: constant on each side with fac either unknown or 1.
+ */
+static void build_mix_partial_test_graph(ShaderGraphBuilder &builder, NodeMix type, float3 constval)
+{
+ builder
+ .add_attribute("Attribute")
+ /* constant on the left */
+ .add_node(ShaderNodeBuilder<MixNode>("Mix_Cx_Fx")
+ .set(&MixNode::type, type)
+ .set(&MixNode::use_clamp, false)
+ .set("Color1", constval))
+ .add_node(ShaderNodeBuilder<MixNode>("Mix_Cx_F1")
+ .set(&MixNode::type, type)
+ .set(&MixNode::use_clamp, false)
+ .set("Color1", constval)
+ .set("Fac", 1.0f))
+ .add_connection("Attribute::Fac", "Mix_Cx_Fx::Fac")
+ .add_connection("Attribute::Color", "Mix_Cx_Fx::Color2")
+ .add_connection("Attribute::Color", "Mix_Cx_F1::Color2")
+ /* constant on the right */
+ .add_node(ShaderNodeBuilder<MixNode>("Mix_xC_Fx")
+ .set(&MixNode::type, type)
+ .set(&MixNode::use_clamp, false)
+ .set("Color2", constval))
+ .add_node(ShaderNodeBuilder<MixNode>("Mix_xC_F1")
+ .set(&MixNode::type, type)
+ .set(&MixNode::use_clamp, false)
+ .set("Color2", constval)
+ .set("Fac", 1.0f))
+ .add_connection("Attribute::Fac", "Mix_xC_Fx::Fac")
+ .add_connection("Attribute::Color", "Mix_xC_Fx::Color1")
+ .add_connection("Attribute::Color", "Mix_xC_F1::Color1")
+ /* results of actual tests simply added up to connect to output */
+ .add_node(ShaderNodeBuilder<MixNode>("Out12")
+ .set(&MixNode::type, NODE_MIX_ADD)
+ .set(&MixNode::use_clamp, true)
+ .set("Fac", 1.0f))
+ .add_node(ShaderNodeBuilder<MixNode>("Out34")
+ .set(&MixNode::type, NODE_MIX_ADD)
+ .set(&MixNode::use_clamp, true)
+ .set("Fac", 1.0f))
+ .add_node(ShaderNodeBuilder<MixNode>("Out1234")
+ .set(&MixNode::type, NODE_MIX_ADD)
+ .set(&MixNode::use_clamp, true)
+ .set("Fac", 1.0f))
+ .add_connection("Mix_Cx_Fx::Color", "Out12::Color1")
+ .add_connection("Mix_Cx_F1::Color", "Out12::Color2")
+ .add_connection("Mix_xC_Fx::Color", "Out34::Color1")
+ .add_connection("Mix_xC_F1::Color", "Out34::Color2")
+ .add_connection("Out12::Color", "Out1234::Color1")
+ .add_connection("Out34::Color", "Out1234::Color2")
+ .output_color("Out1234::Color");
+}
+
+/*
+ * Tests: partial folding for RGB Add with known 0.
+ */
+TEST(render_graph, constant_fold_part_mix_add_0)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ /* 0 + X (fac 1) == X */
+ INVALID_INFO_MESSAGE(log, "Folding Mix_Cx_Fx::Color");
+ CORRECT_INFO_MESSAGE(log, "Folding Mix_Cx_F1::Color to socket Attribute::Color.");
+ /* X + 0 (fac ?) == X */
+ CORRECT_INFO_MESSAGE(log, "Folding Mix_xC_Fx::Color to socket Attribute::Color.");
+ CORRECT_INFO_MESSAGE(log, "Folding Mix_xC_F1::Color to socket Attribute::Color.");
+ INVALID_INFO_MESSAGE(log, "Folding Out");
+
+ build_mix_partial_test_graph(builder, NODE_MIX_ADD, make_float3(0, 0, 0));
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests: partial folding for RGB Sub with known 0.
+ */
+TEST(render_graph, constant_fold_part_mix_sub_0)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ INVALID_INFO_MESSAGE(log, "Folding Mix_Cx_Fx::Color");
+ INVALID_INFO_MESSAGE(log, "Folding Mix_Cx_F1::Color");
+ /* X - 0 (fac ?) == X */
+ CORRECT_INFO_MESSAGE(log, "Folding Mix_xC_Fx::Color to socket Attribute::Color.");
+ CORRECT_INFO_MESSAGE(log, "Folding Mix_xC_F1::Color to socket Attribute::Color.");
+ INVALID_INFO_MESSAGE(log, "Folding Out");
+
+ build_mix_partial_test_graph(builder, NODE_MIX_SUB, make_float3(0, 0, 0));
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests: partial folding for RGB Mul with known 1.
+ */
+TEST(render_graph, constant_fold_part_mix_mul_1)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ /* 1 * X (fac 1) == X */
+ INVALID_INFO_MESSAGE(log, "Folding Mix_Cx_Fx::Color");
+ CORRECT_INFO_MESSAGE(log, "Folding Mix_Cx_F1::Color to socket Attribute::Color.");
+ /* X * 1 (fac ?) == X */
+ CORRECT_INFO_MESSAGE(log, "Folding Mix_xC_Fx::Color to socket Attribute::Color.");
+ CORRECT_INFO_MESSAGE(log, "Folding Mix_xC_F1::Color to socket Attribute::Color.");
+ INVALID_INFO_MESSAGE(log, "Folding Out");
+
+ build_mix_partial_test_graph(builder, NODE_MIX_MUL, make_float3(1, 1, 1));
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests: partial folding for RGB Div with known 1.
+ */
+TEST(render_graph, constant_fold_part_mix_div_1)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ INVALID_INFO_MESSAGE(log, "Folding Mix_Cx_Fx::Color");
+ INVALID_INFO_MESSAGE(log, "Folding Mix_Cx_F1::Color");
+ /* X / 1 (fac ?) == X */
+ CORRECT_INFO_MESSAGE(log, "Folding Mix_xC_Fx::Color to socket Attribute::Color.");
+ CORRECT_INFO_MESSAGE(log, "Folding Mix_xC_F1::Color to socket Attribute::Color.");
+ INVALID_INFO_MESSAGE(log, "Folding Out");
+
+ build_mix_partial_test_graph(builder, NODE_MIX_DIV, make_float3(1, 1, 1));
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests: partial folding for RGB Mul with known 0.
+ */
+TEST(render_graph, constant_fold_part_mix_mul_0)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ /* 0 * ? (fac ?) == 0 */
+ CORRECT_INFO_MESSAGE(log, "Folding Mix_Cx_Fx::Color to constant (0, 0, 0).");
+ CORRECT_INFO_MESSAGE(log, "Folding Mix_Cx_F1::Color to constant (0, 0, 0).");
+ /* ? * 0 (fac 1) == 0 */
+ INVALID_INFO_MESSAGE(log, "Folding Mix_xC_Fx::Color");
+ CORRECT_INFO_MESSAGE(log, "Folding Mix_xC_F1::Color to constant (0, 0, 0).");
+
+ CORRECT_INFO_MESSAGE(log, "Folding Out12::Color to constant (0, 0, 0).");
+ INVALID_INFO_MESSAGE(log, "Folding Out1234");
+
+ build_mix_partial_test_graph(builder, NODE_MIX_MUL, make_float3(0, 0, 0));
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests: partial folding for RGB Div with known 0.
+ */
+TEST(render_graph, constant_fold_part_mix_div_0)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ /* 0 / ? (fac ?) == 0 */
+ CORRECT_INFO_MESSAGE(log, "Folding Mix_Cx_Fx::Color to constant (0, 0, 0).");
+ CORRECT_INFO_MESSAGE(log, "Folding Mix_Cx_F1::Color to constant (0, 0, 0).");
+ INVALID_INFO_MESSAGE(log, "Folding Mix_xC_Fx::Color");
+ INVALID_INFO_MESSAGE(log, "Folding Mix_xC_F1::Color");
+
+ CORRECT_INFO_MESSAGE(log, "Folding Out12::Color to constant (0, 0, 0).");
+ INVALID_INFO_MESSAGE(log, "Folding Out1234");
+
+ build_mix_partial_test_graph(builder, NODE_MIX_DIV, make_float3(0, 0, 0));
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests: Separate/Combine RGB with all constant inputs.
+ */
+TEST(render_graph, constant_fold_separate_combine_rgb)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding SeparateRGB::R to constant (0.3).");
+ CORRECT_INFO_MESSAGE(log, "Folding SeparateRGB::G to constant (0.5).");
+ CORRECT_INFO_MESSAGE(log, "Folding SeparateRGB::B to constant (0.7).");
+ CORRECT_INFO_MESSAGE(log, "Folding CombineRGB::Image to constant (0.3, 0.5, 0.7).");
+
+ builder
+ .add_node(ShaderNodeBuilder<SeparateRGBNode>("SeparateRGB")
+ .set("Image", make_float3(0.3f, 0.5f, 0.7f)))
+ .add_node(ShaderNodeBuilder<CombineRGBNode>("CombineRGB"))
+ .add_connection("SeparateRGB::R", "CombineRGB::R")
+ .add_connection("SeparateRGB::G", "CombineRGB::G")
+ .add_connection("SeparateRGB::B", "CombineRGB::B")
+ .output_color("CombineRGB::Image");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests: Separate/Combine XYZ with all constant inputs.
+ */
+TEST(render_graph, constant_fold_separate_combine_xyz)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding SeparateXYZ::X to constant (0.3).");
+ CORRECT_INFO_MESSAGE(log, "Folding SeparateXYZ::Y to constant (0.5).");
+ CORRECT_INFO_MESSAGE(log, "Folding SeparateXYZ::Z to constant (0.7).");
+ CORRECT_INFO_MESSAGE(log, "Folding CombineXYZ::Vector to constant (0.3, 0.5, 0.7).");
+ CORRECT_INFO_MESSAGE(log, "Folding convert_vector_to_color::value_color to constant (0.3, 0.5, 0.7).");
+
+ builder
+ .add_node(ShaderNodeBuilder<SeparateXYZNode>("SeparateXYZ")
+ .set("Vector", make_float3(0.3f, 0.5f, 0.7f)))
+ .add_node(ShaderNodeBuilder<CombineXYZNode>("CombineXYZ"))
+ .add_connection("SeparateXYZ::X", "CombineXYZ::X")
+ .add_connection("SeparateXYZ::Y", "CombineXYZ::Y")
+ .add_connection("SeparateXYZ::Z", "CombineXYZ::Z")
+ .output_color("CombineXYZ::Vector");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests: Separate/Combine HSV with all constant inputs.
+ */
+TEST(render_graph, constant_fold_separate_combine_hsv)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding SeparateHSV::H to constant (0.583333).");
+ CORRECT_INFO_MESSAGE(log, "Folding SeparateHSV::S to constant (0.571429).");
+ CORRECT_INFO_MESSAGE(log, "Folding SeparateHSV::V to constant (0.7).");
+ CORRECT_INFO_MESSAGE(log, "Folding CombineHSV::Color to constant (0.3, 0.5, 0.7).");
+
+ builder
+ .add_node(ShaderNodeBuilder<SeparateHSVNode>("SeparateHSV")
+ .set("Color", make_float3(0.3f, 0.5f, 0.7f)))
+ .add_node(ShaderNodeBuilder<CombineHSVNode>("CombineHSV"))
+ .add_connection("SeparateHSV::H", "CombineHSV::H")
+ .add_connection("SeparateHSV::S", "CombineHSV::S")
+ .add_connection("SeparateHSV::V", "CombineHSV::V")
+ .output_color("CombineHSV::Color");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests: Gamma with all constant inputs.
+ */
+TEST(render_graph, constant_fold_gamma)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding Gamma::Color to constant (0.164317, 0.353553, 0.585662).");
+
+ builder
+ .add_node(ShaderNodeBuilder<GammaNode>("Gamma")
+ .set("Color", make_float3(0.3f, 0.5f, 0.7f))
+ .set("Gamma", 1.5f))
+ .output_color("Gamma::Color");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests: Gamma with one constant 0 input.
+ */
+TEST(render_graph, constant_fold_gamma_part_0)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ INVALID_INFO_MESSAGE(log, "Folding Gamma_Cx::");
+ CORRECT_INFO_MESSAGE(log, "Folding Gamma_xC::Color to constant (1, 1, 1).");
+
+ builder
+ .add_attribute("Attribute")
+ /* constant on the left */
+ .add_node(ShaderNodeBuilder<GammaNode>("Gamma_Cx")
+ .set("Color", make_float3(0.0f, 0.0f, 0.0f)))
+ .add_connection("Attribute::Fac", "Gamma_Cx::Gamma")
+ /* constant on the right */
+ .add_node(ShaderNodeBuilder<GammaNode>("Gamma_xC")
+ .set("Gamma", 0.0f))
+ .add_connection("Attribute::Color", "Gamma_xC::Color")
+ /* output sum */
+ .add_node(ShaderNodeBuilder<MixNode>("Out")
+ .set(&MixNode::type, NODE_MIX_ADD)
+ .set(&MixNode::use_clamp, true)
+ .set("Fac", 1.0f))
+ .add_connection("Gamma_Cx::Color", "Out::Color1")
+ .add_connection("Gamma_xC::Color", "Out::Color2")
+ .output_color("Out::Color");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests: Gamma with one constant 1 input.
+ */
+TEST(render_graph, constant_fold_gamma_part_1)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding Gamma_Cx::Color to constant (1, 1, 1).");
+ CORRECT_INFO_MESSAGE(log, "Folding Gamma_xC::Color to socket Attribute::Color.");
+
+ builder
+ .add_attribute("Attribute")
+ /* constant on the left */
+ .add_node(ShaderNodeBuilder<GammaNode>("Gamma_Cx")
+ .set("Color", make_float3(1.0f, 1.0f, 1.0f)))
+ .add_connection("Attribute::Fac", "Gamma_Cx::Gamma")
+ /* constant on the right */
+ .add_node(ShaderNodeBuilder<GammaNode>("Gamma_xC")
+ .set("Gamma", 1.0f))
+ .add_connection("Attribute::Color", "Gamma_xC::Color")
+ /* output sum */
+ .add_node(ShaderNodeBuilder<MixNode>("Out")
+ .set(&MixNode::type, NODE_MIX_ADD)
+ .set(&MixNode::use_clamp, true)
+ .set("Fac", 1.0f))
+ .add_connection("Gamma_Cx::Color", "Out::Color1")
+ .add_connection("Gamma_xC::Color", "Out::Color2")
+ .output_color("Out::Color");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests: BrightnessContrast with all constant inputs.
+ */
+TEST(render_graph, constant_fold_bright_contrast)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding BrightContrast::Color to constant (0.16, 0.6, 1.04).");
+
+ builder
+ .add_node(ShaderNodeBuilder<BrightContrastNode>("BrightContrast")
+ .set("Color", make_float3(0.3f, 0.5f, 0.7f))
+ .set("Bright", 0.1f)
+ .set("Contrast", 1.2f))
+ .output_color("BrightContrast::Color");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests: blackbody with all constant inputs.
+ */
+TEST(render_graph, constant_fold_blackbody)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding Blackbody::Color to constant (3.94163, 0.226523, 0).");
+
+ builder
+ .add_node(ShaderNodeBuilder<BlackbodyNode>("Blackbody")
+ .set("Temperature", 1200.0f))
+ .output_color("Blackbody::Color");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests: Math with all constant inputs (clamp false).
+ */
+TEST(render_graph, constant_fold_math)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding Math::Value to constant (1.6).");
+
+ builder
+ .add_node(ShaderNodeBuilder<MathNode>("Math")
+ .set(&MathNode::type, NODE_MATH_ADD)
+ .set(&MathNode::use_clamp, false)
+ .set("Value1", 0.7f)
+ .set("Value2", 0.9f))
+ .output_value("Math::Value");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests: Math with all constant inputs (clamp true).
+ */
+TEST(render_graph, constant_fold_math_clamp)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding Math::Value to constant (1).");
+
+ builder
+ .add_node(ShaderNodeBuilder<MathNode>("Math")
+ .set(&MathNode::type, NODE_MATH_ADD)
+ .set(&MathNode::use_clamp, true)
+ .set("Value1", 0.7f)
+ .set("Value2", 0.9f))
+ .output_value("Math::Value");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Graph for testing partial folds of Math with one constant argument.
+ * Includes 2 tests: constant on each side.
+ */
+static void build_math_partial_test_graph(ShaderGraphBuilder &builder, NodeMath type, float constval)
+{
+ builder
+ .add_attribute("Attribute")
+ /* constant on the left */
+ .add_node(ShaderNodeBuilder<MathNode>("Math_Cx")
+ .set(&MathNode::type, type)
+ .set(&MathNode::use_clamp, false)
+ .set("Value1", constval))
+ .add_connection("Attribute::Fac", "Math_Cx::Value2")
+ /* constant on the right */
+ .add_node(ShaderNodeBuilder<MathNode>("Math_xC")
+ .set(&MathNode::type, type)
+ .set(&MathNode::use_clamp, false)
+ .set("Value2", constval))
+ .add_connection("Attribute::Fac", "Math_xC::Value1")
+ /* output sum */
+ .add_node(ShaderNodeBuilder<MathNode>("Out")
+ .set(&MathNode::type, NODE_MATH_ADD)
+ .set(&MathNode::use_clamp, true))
+ .add_connection("Math_Cx::Value", "Out::Value1")
+ .add_connection("Math_xC::Value", "Out::Value2")
+ .output_value("Out::Value");
+}
+
+/*
+ * Tests: partial folding for Math Add with known 0.
+ */
+TEST(render_graph, constant_fold_part_math_add_0)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ /* X + 0 == 0 + X == X */
+ CORRECT_INFO_MESSAGE(log, "Folding Math_Cx::Value to socket Attribute::Fac.");
+ CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Value to socket Attribute::Fac.");
+ INVALID_INFO_MESSAGE(log, "Folding Out::");
+
+ build_math_partial_test_graph(builder, NODE_MATH_ADD, 0.0f);
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests: partial folding for Math Sub with known 0.
+ */
+TEST(render_graph, constant_fold_part_math_sub_0)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ /* X - 0 == X */
+ INVALID_INFO_MESSAGE(log, "Folding Math_Cx::");
+ CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Value to socket Attribute::Fac.");
+ INVALID_INFO_MESSAGE(log, "Folding Out::");
+
+ build_math_partial_test_graph(builder, NODE_MATH_SUBTRACT, 0.0f);
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests: partial folding for Math Mul with known 1.
+ */
+TEST(render_graph, constant_fold_part_math_mul_1)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ /* X * 1 == 1 * X == X */
+ CORRECT_INFO_MESSAGE(log, "Folding Math_Cx::Value to socket Attribute::Fac.");
+ CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Value to socket Attribute::Fac.");
+ INVALID_INFO_MESSAGE(log, "Folding Out::");
+
+ build_math_partial_test_graph(builder, NODE_MATH_MULTIPLY, 1.0f);
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests: partial folding for Math Div with known 1.
+ */
+TEST(render_graph, constant_fold_part_math_div_1)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ /* X / 1 == X */
+ INVALID_INFO_MESSAGE(log, "Folding Math_Cx::");
+ CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Value to socket Attribute::Fac.");
+ INVALID_INFO_MESSAGE(log, "Folding Out::");
+
+ build_math_partial_test_graph(builder, NODE_MATH_DIVIDE, 1.0f);
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests: partial folding for Math Mul with known 0.
+ */
+TEST(render_graph, constant_fold_part_math_mul_0)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ /* X * 0 == 0 * X == 0 */
+ CORRECT_INFO_MESSAGE(log, "Folding Math_Cx::Value to constant (0).");
+ CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Value to constant (0).");
+ CORRECT_INFO_MESSAGE(log, "Folding Out::Value to constant (0)");
+ CORRECT_INFO_MESSAGE(log, "Discarding closure EmissionNode.");
+
+ build_math_partial_test_graph(builder, NODE_MATH_MULTIPLY, 0.0f);
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests: partial folding for Math Div with known 0.
+ */
+TEST(render_graph, constant_fold_part_math_div_0)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ /* 0 / X == 0 */
+ CORRECT_INFO_MESSAGE(log, "Folding Math_Cx::Value to constant (0).");
+ INVALID_INFO_MESSAGE(log, "Folding Math_xC::");
+ INVALID_INFO_MESSAGE(log, "Folding Out::");
+
+ build_math_partial_test_graph(builder, NODE_MATH_DIVIDE, 0.0f);
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests: partial folding for Math Power with known 0.
+ */
+TEST(render_graph, constant_fold_part_math_pow_0)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ /* X ^ 0 == 1 */
+ INVALID_INFO_MESSAGE(log, "Folding Math_Cx::");
+ CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Value to constant (1).");
+ INVALID_INFO_MESSAGE(log, "Folding Out::");
+
+ build_math_partial_test_graph(builder, NODE_MATH_POWER, 0.0f);
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests: partial folding for Math Power with known 1.
+ */
+TEST(render_graph, constant_fold_part_math_pow_1)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ /* 1 ^ X == 1; X ^ 1 == X */
+ CORRECT_INFO_MESSAGE(log, "Folding Math_Cx::Value to constant (1)");
+ CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Value to socket Attribute::Fac.");
+ INVALID_INFO_MESSAGE(log, "Folding Out::");
+
+ build_math_partial_test_graph(builder, NODE_MATH_POWER, 1.0f);
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests: Vector Math with all constant inputs.
+ */
+TEST(render_graph, constant_fold_vector_math)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding VectorMath::Value to constant (1).");
+ CORRECT_INFO_MESSAGE(log, "Folding VectorMath::Vector to constant (3, 0, 0).");
+ CORRECT_INFO_MESSAGE(log, "Folding convert_vector_to_float::value_float to constant (1).");
+ CORRECT_INFO_MESSAGE(log, "Folding Math::Value to constant (2).");
+ CORRECT_INFO_MESSAGE(log, "Folding convert_float_to_color::value_color to constant (2, 2, 2).");
+
+ builder
+ .add_node(ShaderNodeBuilder<VectorMathNode>("VectorMath")
+ .set(&VectorMathNode::type, NODE_VECTOR_MATH_SUBTRACT)
+ .set("Vector1", make_float3(1.3f, 0.5f, 0.7f))
+ .set("Vector2", make_float3(-1.7f, 0.5f, 0.7f)))
+ .add_node(ShaderNodeBuilder<MathNode>("Math")
+ .set(&MathNode::type, NODE_MATH_ADD))
+ .add_connection("VectorMath::Vector", "Math::Value1")
+ .add_connection("VectorMath::Value", "Math::Value2")
+ .output_color("Math::Value");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Graph for testing partial folds of Vector Math with one constant argument.
+ * Includes 2 tests: constant on each side.
+ */
+static void build_vecmath_partial_test_graph(ShaderGraphBuilder &builder, NodeVectorMath type, float3 constval)
+{
+ builder
+ .add_attribute("Attribute")
+ /* constant on the left */
+ .add_node(ShaderNodeBuilder<VectorMathNode>("Math_Cx")
+ .set(&VectorMathNode::type, type)
+ .set("Vector1", constval))
+ .add_connection("Attribute::Vector", "Math_Cx::Vector2")
+ /* constant on the right */
+ .add_node(ShaderNodeBuilder<VectorMathNode>("Math_xC")
+ .set(&VectorMathNode::type, type)
+ .set("Vector2", constval))
+ .add_connection("Attribute::Vector", "Math_xC::Vector1")
+ /* output sum */
+ .add_node(ShaderNodeBuilder<VectorMathNode>("Out")
+ .set(&VectorMathNode::type, NODE_VECTOR_MATH_ADD))
+ .add_connection("Math_Cx::Vector", "Out::Vector1")
+ .add_connection("Math_xC::Vector", "Out::Vector2")
+ .output_color("Out::Vector");
+}
+
+/*
+ * Tests: partial folding for Vector Math Add with known 0.
+ */
+TEST(render_graph, constant_fold_part_vecmath_add_0)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ /* X + 0 == 0 + X == X */
+ CORRECT_INFO_MESSAGE(log, "Folding Math_Cx::Vector to socket Attribute::Vector.");
+ CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Vector to socket Attribute::Vector.");
+ INVALID_INFO_MESSAGE(log, "Folding Out::");
+
+ build_vecmath_partial_test_graph(builder, NODE_VECTOR_MATH_ADD, make_float3(0,0,0));
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests: partial folding for Vector Math Sub with known 0.
+ */
+TEST(render_graph, constant_fold_part_vecmath_sub_0)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ /* X - 0 == X */
+ INVALID_INFO_MESSAGE(log, "Folding Math_Cx::");
+ CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Vector to socket Attribute::Vector.");
+ INVALID_INFO_MESSAGE(log, "Folding Out::");
+
+ build_vecmath_partial_test_graph(builder, NODE_VECTOR_MATH_SUBTRACT, make_float3(0,0,0));
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests: partial folding for Vector Math Dot Product with known 0.
+ */
+TEST(render_graph, constant_fold_part_vecmath_dot_0)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ /* X * 0 == 0 * X == X */
+ CORRECT_INFO_MESSAGE(log, "Folding Math_Cx::Vector to constant (0, 0, 0).");
+ CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Vector to constant (0, 0, 0).");
+ CORRECT_INFO_MESSAGE(log, "Folding Out::Vector to constant (0, 0, 0).");
+ CORRECT_INFO_MESSAGE(log, "Discarding closure EmissionNode.");
+
+ build_vecmath_partial_test_graph(builder, NODE_VECTOR_MATH_DOT_PRODUCT, make_float3(0,0,0));
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests: partial folding for Vector Math Cross Product with known 0.
+ */
+TEST(render_graph, constant_fold_part_vecmath_cross_0)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ /* X * 0 == 0 * X == X */
+ CORRECT_INFO_MESSAGE(log, "Folding Math_Cx::Vector to constant (0, 0, 0).");
+ CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Vector to constant (0, 0, 0).");
+ CORRECT_INFO_MESSAGE(log, "Folding Out::Vector to constant (0, 0, 0).");
+ CORRECT_INFO_MESSAGE(log, "Discarding closure EmissionNode.");
+
+ build_vecmath_partial_test_graph(builder, NODE_VECTOR_MATH_CROSS_PRODUCT, make_float3(0,0,0));
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests: Bump with no height input folded to Normal input.
+ */
+TEST(render_graph, constant_fold_bump)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding Bump::Normal to socket Geometry1::Normal.");
+
+ builder
+ .add_node(ShaderNodeBuilder<GeometryNode>("Geometry1"))
+ .add_node(ShaderNodeBuilder<BumpNode>("Bump"))
+ .add_connection("Geometry1::Normal", "Bump::Normal")
+ .output_color("Bump::Normal");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests: Bump with no inputs folded to Geometry::Normal.
+ */
+TEST(render_graph, constant_fold_bump_no_input)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding Bump::Normal to socket geometry::Normal.");
+
+ builder
+ .add_node(ShaderNodeBuilder<BumpNode>("Bump"))
+ .output_color("Bump::Normal");
+
+ graph.finalize(&scene);
+}
+
+template<class T>
+void init_test_curve(array<T> &buffer, T start, T end, int steps)
+{
+ buffer.resize(steps);
+
+ for(int i = 0; i < steps; i++) {
+ buffer[i] = lerp(start, end, float(i)/(steps-1));
+ }
+}
+
+/*
+ * Tests:
+ * - Folding of RGB Curves with all constant inputs.
+ */
+TEST(render_graph, constant_fold_rgb_curves)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding Curves::Color to constant (0.275, 0.5, 0.475).");
+
+ array<float3> curve;
+ init_test_curve(curve, make_float3(0.0f, 0.25f, 1.0f), make_float3(1.0f, 0.75f, 0.0f), 257);
+
+ builder
+ .add_node(ShaderNodeBuilder<RGBCurvesNode>("Curves")
+ .set(&CurvesNode::curves, curve)
+ .set(&CurvesNode::min_x, 0.1f)
+ .set(&CurvesNode::max_x, 0.9f)
+ .set("Fac", 0.5f)
+ .set("Color", make_float3(0.3f, 0.5f, 0.7f)))
+ .output_color("Curves::Color");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests:
+ * - Folding of RGB Curves with zero Fac.
+ */
+TEST(render_graph, constant_fold_rgb_curves_fac_0)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding Curves::Color to socket Attribute::Color.");
+
+ array<float3> curve;
+ init_test_curve(curve, make_float3(0.0f, 0.25f, 1.0f), make_float3(1.0f, 0.75f, 0.0f), 257);
+
+ builder
+ .add_attribute("Attribute")
+ .add_node(ShaderNodeBuilder<RGBCurvesNode>("Curves")
+ .set(&CurvesNode::curves, curve)
+ .set(&CurvesNode::min_x, 0.1f)
+ .set(&CurvesNode::max_x, 0.9f)
+ .set("Fac", 0.0f))
+ .add_connection("Attribute::Color", "Curves::Color")
+ .output_color("Curves::Color");
+
+ graph.finalize(&scene);
+}
+
+
+/*
+ * Tests:
+ * - Folding of RGB Curves with zero Fac and all constant inputs.
+ */
+TEST(render_graph, constant_fold_rgb_curves_fac_0_const)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding Curves::Color to constant (0.3, 0.5, 0.7).");
+
+ array<float3> curve;
+ init_test_curve(curve, make_float3(0.0f, 0.25f, 1.0f), make_float3(1.0f, 0.75f, 0.0f), 257);
+
+ builder
+ .add_node(ShaderNodeBuilder<RGBCurvesNode>("Curves")
+ .set(&CurvesNode::curves, curve)
+ .set(&CurvesNode::min_x, 0.1f)
+ .set(&CurvesNode::max_x, 0.9f)
+ .set("Fac", 0.0f)
+ .set("Color", make_float3(0.3f, 0.5f, 0.7f)))
+ .output_color("Curves::Color");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests:
+ * - Folding of Vector Curves with all constant inputs.
+ */
+TEST(render_graph, constant_fold_vector_curves)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding Curves::Vector to constant (0.275, 0.5, 0.475).");
+
+ array<float3> curve;
+ init_test_curve(curve, make_float3(0.0f, 0.25f, 1.0f), make_float3(1.0f, 0.75f, 0.0f), 257);
+
+ builder
+ .add_node(ShaderNodeBuilder<VectorCurvesNode>("Curves")
+ .set(&CurvesNode::curves, curve)
+ .set(&CurvesNode::min_x, 0.1f)
+ .set(&CurvesNode::max_x, 0.9f)
+ .set("Fac", 0.5f)
+ .set("Vector", make_float3(0.3f, 0.5f, 0.7f)))
+ .output_color("Curves::Vector");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests:
+ * - Folding of Vector Curves with zero Fac.
+ */
+TEST(render_graph, constant_fold_vector_curves_fac_0)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding Curves::Vector to socket Attribute::Vector.");
+
+ array<float3> curve;
+ init_test_curve(curve, make_float3(0.0f, 0.25f, 1.0f), make_float3(1.0f, 0.75f, 0.0f), 257);
+
+ builder
+ .add_attribute("Attribute")
+ .add_node(ShaderNodeBuilder<VectorCurvesNode>("Curves")
+ .set(&CurvesNode::curves, curve)
+ .set(&CurvesNode::min_x, 0.1f)
+ .set(&CurvesNode::max_x, 0.9f)
+ .set("Fac", 0.0f))
+ .add_connection("Attribute::Vector", "Curves::Vector")
+ .output_color("Curves::Vector");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests:
+ * - Folding of Color Ramp with all constant inputs.
+ */
+TEST(render_graph, constant_fold_rgb_ramp)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding Ramp::Color to constant (0.14, 0.39, 0.64).");
+ CORRECT_INFO_MESSAGE(log, "Folding Ramp::Alpha to constant (0.89).");
+
+ array<float3> curve;
+ array<float> alpha;
+ init_test_curve(curve, make_float3(0.0f, 0.25f, 0.5f), make_float3(0.25f, 0.5f, 0.75f), 9);
+ init_test_curve(alpha, 0.75f, 1.0f, 9);
+
+ builder
+ .add_node(ShaderNodeBuilder<RGBRampNode>("Ramp")
+ .set(&RGBRampNode::ramp, curve)
+ .set(&RGBRampNode::ramp_alpha, alpha)
+ .set(&RGBRampNode::interpolate, true)
+ .set("Fac", 0.56f))
+ .add_node(ShaderNodeBuilder<MixNode>("Mix")
+ .set(&MixNode::type, NODE_MIX_ADD))
+ .add_connection("Ramp::Color", "Mix::Color1")
+ .add_connection("Ramp::Alpha", "Mix::Color2")
+ .output_color("Mix::Color");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests:
+ * - Folding of Color Ramp with all constant inputs (interpolate false).
+ */
+TEST(render_graph, constant_fold_rgb_ramp_flat)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding Ramp::Color to constant (0.125, 0.375, 0.625).");
+ CORRECT_INFO_MESSAGE(log, "Folding Ramp::Alpha to constant (0.875).");
+
+ array<float3> curve;
+ array<float> alpha;
+ init_test_curve(curve, make_float3(0.0f, 0.25f, 0.5f), make_float3(0.25f, 0.5f, 0.75f), 9);
+ init_test_curve(alpha, 0.75f, 1.0f, 9);
+
+ builder
+ .add_node(ShaderNodeBuilder<RGBRampNode>("Ramp")
+ .set(&RGBRampNode::ramp, curve)
+ .set(&RGBRampNode::ramp_alpha, alpha)
+ .set(&RGBRampNode::interpolate, false)
+ .set("Fac", 0.56f))
+ .add_node(ShaderNodeBuilder<MixNode>("Mix")
+ .set(&MixNode::type, NODE_MIX_ADD))
+ .add_connection("Ramp::Color", "Mix::Color1")
+ .add_connection("Ramp::Alpha", "Mix::Color2")
+ .output_color("Mix::Color");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests:
+ * - Folding of redundant conversion of float to color to float.
+ */
+TEST(render_graph, constant_fold_convert_float_color_float)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding Invert::Color to socket convert_float_to_color::value_color.");
+ CORRECT_INFO_MESSAGE(log, "Folding convert_color_to_float::value_float to socket Attribute::Fac.");
+
+ builder
+ .add_attribute("Attribute")
+ .add_node(ShaderNodeBuilder<InvertNode>("Invert")
+ .set("Fac", 0.0f))
+ .add_connection("Attribute::Fac", "Invert::Color")
+ .output_value("Invert::Color");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests:
+ * - Folding of redundant conversion of color to vector to color.
+ */
+TEST(render_graph, constant_fold_convert_color_vector_color)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding VecAdd::Vector to socket convert_color_to_vector::value_vector.");
+ CORRECT_INFO_MESSAGE(log, "Folding convert_vector_to_color::value_color to socket Attribute::Color.");
+
+ builder
+ .add_attribute("Attribute")
+ .add_node(ShaderNodeBuilder<VectorMathNode>("VecAdd")
+ .set(&VectorMathNode::type, NODE_VECTOR_MATH_ADD)
+ .set("Vector2", make_float3(0,0,0)))
+ .add_connection("Attribute::Color", "VecAdd::Vector1")
+ .output_color("VecAdd::Vector");
+
+ graph.finalize(&scene);
+}
+
+/*
+ * Tests:
+ * - NOT folding conversion of color to float to color.
+ */
+TEST(render_graph, constant_fold_convert_color_float_color)
+{
+ DEFINE_COMMON_VARIABLES(builder, log);
+
+ EXPECT_ANY_MESSAGE(log);
+ CORRECT_INFO_MESSAGE(log, "Folding MathAdd::Value to socket convert_color_to_float::value_float.");
+ INVALID_INFO_MESSAGE(log, "Folding convert_float_to_color::");
+
+ builder
+ .add_attribute("Attribute")
+ .add_node(ShaderNodeBuilder<MathNode>("MathAdd")
+ .set(&MathNode::type, NODE_MATH_ADD)
+ .set("Value2", 0.0f))
+ .add_connection("Attribute::Color", "MathAdd::Value1")
+ .output_color("MathAdd::Value");
+
+ graph.finalize(&scene);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/util/CMakeLists.txt b/intern/cycles/util/CMakeLists.txt
index bfe26594e82..f9c7c7350e2 100644
--- a/intern/cycles/util/CMakeLists.txt
+++ b/intern/cycles/util/CMakeLists.txt
@@ -19,14 +19,12 @@ set(SRC
util_simd.cpp
util_system.cpp
util_task.cpp
+ util_thread.cpp
util_time.cpp
util_transform.cpp
+ util_windows.cpp
)
-if(NOT CYCLES_STANDALONE_REPOSITORY)
- add_definitions(-DWITH_GLEW_MX)
-endif()
-
if(WITH_CYCLES_STANDALONE AND WITH_CYCLES_STANDALONE_GUI)
list(APPEND SRC
util_view.cpp
@@ -65,10 +63,12 @@ set(SRC_HEADERS
util_sky_model.cpp
util_sky_model.h
util_sky_model_data.h
+ util_avxf.h
util_sseb.h
util_ssef.h
util_ssei.h
util_stack_allocator.h
+ util_static_assert.h
util_stats.h
util_string.h
util_system.h
diff --git a/intern/cycles/util/util_avxf.h b/intern/cycles/util/util_avxf.h
new file mode 100644
index 00000000000..2db2c4dad1a
--- /dev/null
+++ b/intern/cycles/util/util_avxf.h
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2016 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0(the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_AVXF_H__
+#define __UTIL_AVXF_H__
+
+CCL_NAMESPACE_BEGIN
+
+#ifdef __KERNEL_AVX__
+struct avxf
+{
+ typedef avxf Float;
+
+ enum { size = 8 }; /* Number of SIMD elements. */
+
+ union {
+ __m256 m256;
+ float f[8];
+ int i[8];
+ };
+
+ __forceinline avxf () {}
+ __forceinline avxf (const avxf& other) { m256 = other.m256; }
+ __forceinline avxf& operator=(const avxf& other) { m256 = other.m256; return *this; }
+
+ __forceinline avxf(const __m256 a) : m256(a) {}
+ __forceinline avxf(const __m256i a) : m256(_mm256_castsi256_ps (a)) {}
+
+ __forceinline operator const __m256&(void) const { return m256; }
+ __forceinline operator __m256&(void) { return m256; }
+
+ __forceinline avxf (float a) : m256(_mm256_set1_ps(a)) {}
+
+ __forceinline avxf(float high32x4, float low32x4) :
+ m256(_mm256_set_ps(high32x4, high32x4, high32x4, high32x4, low32x4, low32x4, low32x4, low32x4)) {}
+
+ __forceinline avxf(float a3, float a2, float a1, float a0) :
+ m256(_mm256_set_ps(a3, a2, a1, a0, a3, a2, a1, a0)) {}
+
+ __forceinline avxf(float a7, float a6, float a5, float a4, float a3, float a2, float a1, float a0) :
+ m256(_mm256_set_ps(a7, a6, a5, a4, a3, a2, a1, a0)) {}
+
+
+ __forceinline avxf(int a3, int a2, int a1, int a0)
+ {
+ const __m256i foo = _mm256_set_epi32(a3, a2, a1, a0, a3, a2, a1, a0);
+ m256 = _mm256_castsi256_ps(foo);
+ }
+
+
+ __forceinline avxf(int a7, int a6, int a5, int a4, int a3, int a2, int a1, int a0)
+ {
+ const __m256i foo = _mm256_set_epi32(a7, a6, a5, a4, a3, a2, a1, a0);
+ m256 = _mm256_castsi256_ps(foo);
+ }
+
+ __forceinline avxf(__m128 a, __m128 b)
+ {
+ const __m256 foo = _mm256_castps128_ps256(a);
+ m256 = _mm256_insertf128_ps(foo, b, 1);
+ }
+
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// Unary Operators
+////////////////////////////////////////////////////////////////////////////////
+
+__forceinline const avxf mm256_sqrt(const avxf& a) { return _mm256_sqrt_ps(a.m256); }
+
+////////////////////////////////////////////////////////////////////////////////
+/// Binary Operators
+////////////////////////////////////////////////////////////////////////////////
+
+__forceinline const avxf operator +(const avxf& a, const avxf& b) { return _mm256_add_ps(a.m256, b.m256); }
+__forceinline const avxf operator +(const avxf& a, const float& b) { return a + avxf(b); }
+__forceinline const avxf operator +(const float& a, const avxf& b) { return avxf(a) + b; }
+
+__forceinline const avxf operator -(const avxf& a, const avxf& b) { return _mm256_sub_ps(a.m256, b.m256); }
+__forceinline const avxf operator -(const avxf& a, const float& b) { return a - avxf(b); }
+__forceinline const avxf operator -(const float& a, const avxf& b) { return avxf(a) - b; }
+
+__forceinline const avxf operator *(const avxf& a, const avxf& b) { return _mm256_mul_ps(a.m256, b.m256); }
+__forceinline const avxf operator *(const avxf& a, const float& b) { return a * avxf(b); }
+__forceinline const avxf operator *(const float& a, const avxf& b) { return avxf(a) * b; }
+
+__forceinline const avxf operator /(const avxf& a, const avxf& b) { return _mm256_div_ps(a.m256,b.m256); }
+__forceinline const avxf operator /(const avxf& a, const float& b) { return a/avxf(b); }
+__forceinline const avxf operator /(const float& a, const avxf& b) { return avxf(a)/b; }
+
+__forceinline const avxf operator|(const avxf& a, const avxf& b) { return _mm256_or_ps(a.m256,b.m256); }
+
+__forceinline const avxf operator^(const avxf& a, const avxf& b) { return _mm256_xor_ps(a.m256,b.m256); }
+
+__forceinline const avxf operator&(const avxf& a, const avxf& b) { return _mm256_and_ps(a.m256,b.m256); }
+
+////////////////////////////////////////////////////////////////////////////////
+/// Movement/Shifting/Shuffling Functions
+////////////////////////////////////////////////////////////////////////////////
+
+__forceinline const avxf shuffle(const avxf& a, const __m256i &shuf) {
+ return _mm256_permutevar_ps(a, shuf);
+}
+
+template<int i0, int i1, int i2, int i3, int i4, int i5, int i6, int i7> __forceinline const avxf shuffle(const avxf& a) {
+ return _mm256_permutevar_ps(a, _mm256_set_epi32( i7,i6,i5,i4 ,i3,i2,i1,i0));
+}
+
+template<size_t i0, size_t i1, size_t i2, size_t i3> __forceinline const avxf shuffle(const avxf& a, const avxf& b) {
+ return _mm256_shuffle_ps(a, b, _MM_SHUFFLE(i3, i2, i1, i0));
+}
+template<size_t i0, size_t i1, size_t i2, size_t i3> __forceinline const avxf shuffle(const avxf& a) {
+ return shuffle<i0,i1,i2,i3>(a,a);
+}
+template<size_t i0> __forceinline const avxf shuffle(const avxf& a, const avxf& b) {
+ return shuffle<i0,i0,i0,i0>(a, b);
+}
+template<size_t i0> __forceinline const avxf shuffle(const avxf& a) {
+ return shuffle<i0>(a,a);
+}
+
+template<int i0, int i1, int i2, int i3, int i4, int i5, int i6, int i7> __forceinline const avxf permute(const avxf& a) {
+#ifdef __KERNEL_AVX2__
+ return _mm256_permutevar8x32_ps(a,_mm256_set_epi32( i7,i6,i5,i4 ,i3,i2,i1,i0));
+#else
+ float temp[8];
+ _mm256_storeu_ps((float*)&temp, a);
+ return avxf(temp[i7], temp[i6], temp[i5], temp[i4], temp[i3], temp[i2], temp[i1], temp[i0]);
+#endif
+}
+
+template<int S0, int S1, int S2, int S3,int S4,int S5,int S6, int S7>
+ccl_device_inline const avxf set_sign_bit(const avxf &a)
+{
+ return a ^ avxf(S7 << 31, S6 << 31, S5 << 31, S4 << 31, S3 << 31,S2 << 31,S1 << 31,S0 << 31);
+}
+
+template<size_t S0, size_t S1, size_t S2, size_t S3,size_t S4,size_t S5,size_t S6, size_t S7>
+ccl_device_inline const avxf blend(const avxf &a, const avxf &b)
+{
+ return _mm256_blend_ps(a,b,S7 << 0 | S6 << 1 | S5 << 2 | S4 << 3 | S3 << 4 | S2 << 5 | S1 << 6 | S0 << 7);
+}
+
+template<size_t S0, size_t S1, size_t S2, size_t S3 >
+ccl_device_inline const avxf blend(const avxf &a, const avxf &b)
+{
+ return blend<S0,S1,S2,S3,S0,S1,S2,S3>(a,b);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Ternary Operators
+////////////////////////////////////////////////////////////////////////////////
+__forceinline const avxf madd (const avxf& a, const avxf& b, const avxf& c) {
+#ifdef __KERNEL_AVX2__
+ return _mm256_fmadd_ps(a,b,c);
+#else
+ return c+(a*b);
+#endif
+}
+
+__forceinline const avxf nmadd(const avxf& a, const avxf& b, const avxf& c) {
+#ifdef __KERNEL_AVX2__
+ return _mm256_fnmadd_ps(a, b, c);
+#else
+ return c-(a*b);
+#endif
+}
+#endif
+
+CCL_NAMESPACE_END
+
+#endif
diff --git a/intern/cycles/util/util_boundbox.h b/intern/cycles/util/util_boundbox.h
index cef5adc0a61..599222da9c5 100644
--- a/intern/cycles/util/util_boundbox.h
+++ b/intern/cycles/util/util_boundbox.h
@@ -151,7 +151,7 @@ public:
(isfinite(max.x) && isfinite(max.y) && isfinite(max.z));
}
- BoundBox transformed(const Transform *tfm)
+ BoundBox transformed(const Transform *tfm) const
{
BoundBox result = BoundBox::empty;
diff --git a/intern/cycles/util/util_debug.h b/intern/cycles/util/util_debug.h
index 641abcc0668..73fd228b5d9 100644
--- a/intern/cycles/util/util_debug.h
+++ b/intern/cycles/util/util_debug.h
@@ -20,6 +20,8 @@
#include <cassert>
#include <iostream>
+#include "util_static_assert.h"
+
CCL_NAMESPACE_BEGIN
/* Global storage for all sort of flags used to fine-tune behavior of particular
@@ -130,11 +132,11 @@ private:
#if (__cplusplus > 199711L)
public:
- DebugFlags(DebugFlags const& /*other*/) = delete;
+ explicit DebugFlags(DebugFlags const& /*other*/) = delete;
void operator=(DebugFlags const& /*other*/) = delete;
#else
private:
- DebugFlags(DebugFlags const& /*other*/);
+ explicit DebugFlags(DebugFlags const& /*other*/);
void operator=(DebugFlags const& /*other*/);
#endif
};
diff --git a/intern/cycles/util/util_guarded_allocator.cpp b/intern/cycles/util/util_guarded_allocator.cpp
index 8de6e254cbf..615ac95f324 100644
--- a/intern/cycles/util/util_guarded_allocator.cpp
+++ b/intern/cycles/util/util_guarded_allocator.cpp
@@ -19,7 +19,7 @@
CCL_NAMESPACE_BEGIN
-static Stats global_stats;
+static Stats global_stats(Stats::static_init);
/* Internal API. */
diff --git a/intern/cycles/util/util_half.h b/intern/cycles/util/util_half.h
index f4bac9888a5..5db3384cda4 100644
--- a/intern/cycles/util/util_half.h
+++ b/intern/cycles/util/util_half.h
@@ -33,17 +33,21 @@ CCL_NAMESPACE_BEGIN
#else
+/* CUDA has its own half data type, no need to define then */
+#ifndef __KERNEL_CUDA__
typedef unsigned short half;
+#endif
+
struct half4 { half x, y, z, w; };
#ifdef __KERNEL_CUDA__
ccl_device_inline void float4_store_half(half *h, float4 f, float scale)
{
- h[0] = __float2half_rn(f.x * scale);
- h[1] = __float2half_rn(f.y * scale);
- h[2] = __float2half_rn(f.z * scale);
- h[3] = __float2half_rn(f.w * scale);
+ h[0] = __float2half(f.x * scale);
+ h[1] = __float2half(f.y * scale);
+ h[2] = __float2half(f.z * scale);
+ h[3] = __float2half(f.w * scale);
}
#else
@@ -85,6 +89,27 @@ ccl_device_inline void float4_store_half(half *h, float4 f, float scale)
#endif
}
+ccl_device_inline float half_to_float(half h)
+{
+ float f;
+
+ *((int*) &f) = ((h & 0x8000) << 16) | (((h & 0x7c00) + 0x1C000) << 13) | ((h & 0x03FF) << 13);
+
+ return f;
+}
+
+ccl_device_inline float4 half4_to_float4(half4 h)
+{
+ float4 f;
+
+ f.x = half_to_float(h.x);
+ f.y = half_to_float(h.y);
+ f.z = half_to_float(h.z);
+ f.w = half_to_float(h.w);
+
+ return f;
+}
+
#endif
#endif
diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h
index 32924f9a8c2..e2abfcde702 100644
--- a/intern/cycles/util/util_math.h
+++ b/intern/cycles/util/util_math.h
@@ -174,6 +174,11 @@ ccl_device_inline float clamp(float a, float mn, float mx)
return min(max(a, mn), mx);
}
+ccl_device_inline float mix(float a, float b, float t)
+{
+ return a + t*(b - a);
+}
+
#endif
#ifndef __KERNEL_CUDA__
@@ -219,11 +224,16 @@ ccl_device_inline float smoothstepf(float f)
return (3.0f*ff - 2.0f*ff*f);
}
+ccl_device_inline int mod(int x, int m)
+{
+ return (x % m + m) % m;
+}
+
/* Float2 Vector */
#ifndef __KERNEL_OPENCL__
-ccl_device_inline bool is_zero(const float2 a)
+ccl_device_inline bool is_zero(const float2& a)
{
return (a.x == 0.0f && a.y == 0.0f);
}
@@ -232,7 +242,7 @@ ccl_device_inline bool is_zero(const float2 a)
#ifndef __KERNEL_OPENCL__
-ccl_device_inline float average(const float2 a)
+ccl_device_inline float average(const float2& a)
{
return (a.x + a.y)*(1.0f/2.0f);
}
@@ -241,58 +251,58 @@ ccl_device_inline float average(const float2 a)
#ifndef __KERNEL_OPENCL__
-ccl_device_inline float2 operator-(const float2 a)
+ccl_device_inline float2 operator-(const float2& a)
{
return make_float2(-a.x, -a.y);
}
-ccl_device_inline float2 operator*(const float2 a, const float2 b)
+ccl_device_inline float2 operator*(const float2& a, const float2& b)
{
return make_float2(a.x*b.x, a.y*b.y);
}
-ccl_device_inline float2 operator*(const float2 a, float f)
+ccl_device_inline float2 operator*(const float2& a, float f)
{
return make_float2(a.x*f, a.y*f);
}
-ccl_device_inline float2 operator*(float f, const float2 a)
+ccl_device_inline float2 operator*(float f, const float2& a)
{
return make_float2(a.x*f, a.y*f);
}
-ccl_device_inline float2 operator/(float f, const float2 a)
+ccl_device_inline float2 operator/(float f, const float2& a)
{
return make_float2(f/a.x, f/a.y);
}
-ccl_device_inline float2 operator/(const float2 a, float f)
+ccl_device_inline float2 operator/(const float2& a, float f)
{
float invf = 1.0f/f;
return make_float2(a.x*invf, a.y*invf);
}
-ccl_device_inline float2 operator/(const float2 a, const float2 b)
+ccl_device_inline float2 operator/(const float2& a, const float2& b)
{
return make_float2(a.x/b.x, a.y/b.y);
}
-ccl_device_inline float2 operator+(const float2 a, const float2 b)
+ccl_device_inline float2 operator+(const float2& a, const float2& b)
{
return make_float2(a.x+b.x, a.y+b.y);
}
-ccl_device_inline float2 operator-(const float2 a, const float2 b)
+ccl_device_inline float2 operator-(const float2& a, const float2& b)
{
return make_float2(a.x-b.x, a.y-b.y);
}
-ccl_device_inline float2 operator+=(float2& a, const float2 b)
+ccl_device_inline float2 operator+=(float2& a, const float2& b)
{
return a = a + b;
}
-ccl_device_inline float2 operator*=(float2& a, const float2 b)
+ccl_device_inline float2 operator*=(float2& a, const float2& b)
{
return a = a * b;
}
@@ -302,7 +312,7 @@ ccl_device_inline float2 operator*=(float2& a, float f)
return a = a * f;
}
-ccl_device_inline float2 operator/=(float2& a, const float2 b)
+ccl_device_inline float2 operator/=(float2& a, const float2& b)
{
return a = a / b;
}
@@ -314,12 +324,12 @@ ccl_device_inline float2 operator/=(float2& a, float f)
}
-ccl_device_inline float dot(const float2 a, const float2 b)
+ccl_device_inline float dot(const float2& a, const float2& b)
{
return a.x*b.x + a.y*b.y;
}
-ccl_device_inline float cross(const float2 a, const float2 b)
+ccl_device_inline float cross(const float2& a, const float2& b)
{
return (a.x*b.y - a.y*b.x);
}
@@ -333,59 +343,59 @@ ccl_device_inline bool operator==(const int2 a, const int2 b)
return (a.x == b.x && a.y == b.y);
}
-ccl_device_inline float len(const float2 a)
+ccl_device_inline float len(const float2& a)
{
return sqrtf(dot(a, a));
}
-ccl_device_inline float2 normalize(const float2 a)
+ccl_device_inline float2 normalize(const float2& a)
{
return a/len(a);
}
-ccl_device_inline float2 normalize_len(const float2 a, float *t)
+ccl_device_inline float2 normalize_len(const float2& a, float *t)
{
*t = len(a);
return a/(*t);
}
-ccl_device_inline float2 safe_normalize(const float2 a)
+ccl_device_inline float2 safe_normalize(const float2& a)
{
float t = len(a);
return (t != 0.0f)? a/t: a;
}
-ccl_device_inline bool operator==(const float2 a, const float2 b)
+ccl_device_inline bool operator==(const float2& a, const float2& b)
{
return (a.x == b.x && a.y == b.y);
}
-ccl_device_inline bool operator!=(const float2 a, const float2 b)
+ccl_device_inline bool operator!=(const float2& a, const float2& b)
{
return !(a == b);
}
-ccl_device_inline float2 min(float2 a, float2 b)
+ccl_device_inline float2 min(const float2& a, const float2& b)
{
return make_float2(min(a.x, b.x), min(a.y, b.y));
}
-ccl_device_inline float2 max(float2 a, float2 b)
+ccl_device_inline float2 max(const float2& a, const float2& b)
{
return make_float2(max(a.x, b.x), max(a.y, b.y));
}
-ccl_device_inline float2 clamp(float2 a, float2 mn, float2 mx)
+ccl_device_inline float2 clamp(const float2& a, const float2& mn, const float2& mx)
{
return min(max(a, mn), mx);
}
-ccl_device_inline float2 fabs(float2 a)
+ccl_device_inline float2 fabs(const float2& a)
{
return make_float2(fabsf(a.x), fabsf(a.y));
}
-ccl_device_inline float2 as_float2(const float4 a)
+ccl_device_inline float2 as_float2(const float4& a)
{
return make_float2(a.x, a.y);
}
@@ -403,7 +413,7 @@ ccl_device_inline void print_float2(const char *label, const float2& a)
#ifndef __KERNEL_OPENCL__
-ccl_device_inline float2 interp(float2 a, float2 b, float t)
+ccl_device_inline float2 interp(const float2& a, const float2& b, float t)
{
return a + t*(b - a);
}
@@ -414,58 +424,95 @@ ccl_device_inline float2 interp(float2 a, float2 b, float t)
#ifndef __KERNEL_OPENCL__
-ccl_device_inline float3 operator-(const float3 a)
+ccl_device_inline float3 operator-(const float3& a)
{
+#ifdef __KERNEL_SSE__
+ return float3(_mm_xor_ps(a.m128, _mm_castsi128_ps(_mm_set1_epi32(0x80000000))));
+#else
return make_float3(-a.x, -a.y, -a.z);
+#endif
}
-ccl_device_inline float3 operator*(const float3 a, const float3 b)
+ccl_device_inline float3 operator*(const float3& a, const float3& b)
{
+#ifdef __KERNEL_SSE__
+ return float3(_mm_mul_ps(a.m128,b.m128));
+#else
return make_float3(a.x*b.x, a.y*b.y, a.z*b.z);
+#endif
}
-ccl_device_inline float3 operator*(const float3 a, float f)
+ccl_device_inline float3 operator*(const float3& a, const float f)
{
+#ifdef __KERNEL_SSE__
+ return float3(_mm_mul_ps(a.m128,_mm_set1_ps(f)));
+#else
return make_float3(a.x*f, a.y*f, a.z*f);
+#endif
}
-ccl_device_inline float3 operator*(float f, const float3 a)
+ccl_device_inline float3 operator*(const float f, const float3& a)
{
+ /* TODO(sergey): Currently disabled, gives speedup but causes precision issues. */
+#if defined(__KERNEL_SSE__) && 0
+ return float3(_mm_mul_ps(_mm_set1_ps(f), a.m128));
+#else
return make_float3(a.x*f, a.y*f, a.z*f);
+#endif
}
-ccl_device_inline float3 operator/(float f, const float3 a)
+ccl_device_inline float3 operator/(const float f, const float3& a)
{
- return make_float3(f/a.x, f/a.y, f/a.z);
+ /* TODO(sergey): Currently disabled, gives speedup but causes precision issues. */
+#if defined(__KERNEL_SSE__) && 0
+ __m128 rc = _mm_rcp_ps(a.m128);
+ return float3(_mm_mul_ps(_mm_set1_ps(f),rc));
+#else
+ return make_float3(f / a.x, f / a.y, f / a.z);
+#endif
}
-ccl_device_inline float3 operator/(const float3 a, float f)
+ccl_device_inline float3 operator/(const float3& a, const float f)
{
float invf = 1.0f/f;
- return make_float3(a.x*invf, a.y*invf, a.z*invf);
+ return a * invf;
}
-ccl_device_inline float3 operator/(const float3 a, const float3 b)
+ccl_device_inline float3 operator/(const float3& a, const float3& b)
{
- return make_float3(a.x/b.x, a.y/b.y, a.z/b.z);
+ /* TODO(sergey): Currently disabled, gives speedup but causes precision issues. */
+#if defined(__KERNEL_SSE__) && 0
+ __m128 rc = _mm_rcp_ps(b.m128);
+ return float3(_mm_mul_ps(a, rc));
+#else
+ return make_float3(a.x / b.x, a.y / b.y, a.z / b.z);
+#endif
}
-ccl_device_inline float3 operator+(const float3 a, const float3 b)
+ccl_device_inline float3 operator+(const float3& a, const float3& b)
{
- return make_float3(a.x+b.x, a.y+b.y, a.z+b.z);
+#ifdef __KERNEL_SSE__
+ return float3(_mm_add_ps(a.m128, b.m128));
+#else
+ return make_float3(a.x + b.x, a.y + b.y, a.z + b.z);
+#endif
}
-ccl_device_inline float3 operator-(const float3 a, const float3 b)
+ccl_device_inline float3 operator-(const float3& a, const float3& b)
{
- return make_float3(a.x-b.x, a.y-b.y, a.z-b.z);
+#ifdef __KERNEL_SSE__
+ return float3(_mm_sub_ps(a.m128, b.m128));
+#else
+ return make_float3(a.x - b.x, a.y - b.y, a.z - b.z);
+#endif
}
-ccl_device_inline float3 operator+=(float3& a, const float3 b)
+ccl_device_inline float3 operator+=(float3& a, const float3& b)
{
return a = a + b;
}
-ccl_device_inline float3 operator*=(float3& a, const float3 b)
+ccl_device_inline float3 operator*=(float3& a, const float3& b)
{
return a = a * b;
}
@@ -475,7 +522,7 @@ ccl_device_inline float3 operator*=(float3& a, float f)
return a = a * f;
}
-ccl_device_inline float3 operator/=(float3& a, const float3 b)
+ccl_device_inline float3 operator/=(float3& a, const float3& b)
{
return a = a / b;
}
@@ -486,7 +533,7 @@ ccl_device_inline float3 operator/=(float3& a, float f)
return a = a * invf;
}
-ccl_device_inline float dot(const float3 a, const float3 b)
+ccl_device_inline float dot(const float3& a, const float3& b)
{
#if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__)
return _mm_cvtss_f32(_mm_dp_ps(a, b, 0x7F));
@@ -495,7 +542,16 @@ ccl_device_inline float dot(const float3 a, const float3 b)
#endif
}
-ccl_device_inline float dot(const float4 a, const float4 b)
+ccl_device_inline float dot_xy(const float3& a, const float3& b)
+{
+#if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__)
+ return _mm_cvtss_f32(_mm_hadd_ps(_mm_mul_ps(a,b),b));
+#else
+ return a.x*b.x + a.y*b.y;
+#endif
+}
+
+ccl_device_inline float dot(const float4& a, const float4& b)
{
#if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__)
return _mm_cvtss_f32(_mm_dp_ps(a, b, 0xFF));
@@ -504,7 +560,7 @@ ccl_device_inline float dot(const float4 a, const float4 b)
#endif
}
-ccl_device_inline float3 cross(const float3 a, const float3 b)
+ccl_device_inline float3 cross(const float3& a, const float3& b)
{
float3 r = make_float3(a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x);
return r;
@@ -528,14 +584,15 @@ ccl_device_inline float len_squared(const float3 a)
#ifndef __KERNEL_OPENCL__
-ccl_device_inline float len_squared(const float4 a)
+ccl_device_inline float len_squared(const float4& a)
{
return dot(a, a);
}
-ccl_device_inline float3 normalize(const float3 a)
+ccl_device_inline float3 normalize(const float3& a)
{
-#if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__)
+ /* TODO(sergey): Disabled for now, causes crashes in certain cases. */
+#if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__) && 0
__m128 norm = _mm_sqrt_ps(_mm_dp_ps(a.m128, a.m128, 0x7F));
return _mm_div_ps(a.m128, norm);
#else
@@ -545,21 +602,33 @@ ccl_device_inline float3 normalize(const float3 a)
#endif
+ccl_device_inline float3 saturate3(float3 a)
+{
+ return make_float3(saturate(a.x), saturate(a.y), saturate(a.z));
+}
+
ccl_device_inline float3 normalize_len(const float3 a, float *t)
{
*t = len(a);
- return a/(*t);
+ float x = 1.0f / *t;
+ return a*x;
}
ccl_device_inline float3 safe_normalize(const float3 a)
{
float t = len(a);
- return (t != 0.0f)? a/t: a;
+ return (t != 0.0f)? a * (1.0f/t) : a;
+}
+
+ccl_device_inline float3 safe_normalize_len(const float3 a, float *t)
+{
+ *t = len(a);
+ return (*t != 0.0f)? a/(*t): a;
}
#ifndef __KERNEL_OPENCL__
-ccl_device_inline bool operator==(const float3 a, const float3 b)
+ccl_device_inline bool operator==(const float3& a, const float3& b)
{
#ifdef __KERNEL_SSE__
return (_mm_movemask_ps(_mm_cmpeq_ps(a.m128, b.m128)) & 7) == 7;
@@ -568,12 +637,12 @@ ccl_device_inline bool operator==(const float3 a, const float3 b)
#endif
}
-ccl_device_inline bool operator!=(const float3 a, const float3 b)
+ccl_device_inline bool operator!=(const float3& a, const float3& b)
{
return !(a == b);
}
-ccl_device_inline float3 min(float3 a, float3 b)
+ccl_device_inline float3 min(const float3& a, const float3& b)
{
#ifdef __KERNEL_SSE__
return _mm_min_ps(a.m128, b.m128);
@@ -582,7 +651,7 @@ ccl_device_inline float3 min(float3 a, float3 b)
#endif
}
-ccl_device_inline float3 max(float3 a, float3 b)
+ccl_device_inline float3 max(const float3& a, const float3& b)
{
#ifdef __KERNEL_SSE__
return _mm_max_ps(a.m128, b.m128);
@@ -591,12 +660,12 @@ ccl_device_inline float3 max(float3 a, float3 b)
#endif
}
-ccl_device_inline float3 clamp(float3 a, float3 mn, float3 mx)
+ccl_device_inline float3 clamp(const float3& a, const float3& mn, const float3& mx)
{
return min(max(a, mn), mx);
}
-ccl_device_inline float3 fabs(float3 a)
+ccl_device_inline float3 fabs(const float3& a)
{
#ifdef __KERNEL_SSE__
__m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff));
@@ -647,6 +716,15 @@ ccl_device_inline float3 interp(float3 a, float3 b, float t)
return a + t*(b - a);
}
+#ifndef __KERNEL_OPENCL__
+
+ccl_device_inline float3 mix(const float3& a, const float3& b, float t)
+{
+ return a + t*(b - a);
+}
+
+#endif
+
ccl_device_inline bool is_zero(const float3 a)
{
#ifdef __KERNEL_SSE__
@@ -666,6 +744,15 @@ ccl_device_inline float average(const float3 a)
return reduce_add(a)*(1.0f/3.0f);
}
+ccl_device_inline bool isequal_float3(const float3 a, const float3 b)
+{
+#ifdef __KERNEL_OPENCL__
+ return all(a == b);
+#else
+ return a == b;
+#endif
+}
+
/* Float4 Vector */
#ifdef __KERNEL_SSE__
@@ -706,7 +793,8 @@ ccl_device_inline float4 operator-(const float4& a)
ccl_device_inline float4 operator*(const float4& a, const float4& b)
{
-#ifdef __KERNEL_SSE__
+ /* TODO(sergey): Disabled for now, causes crashes in certain cases. */
+#if defined(__KERNEL_SSE__) && 0
return _mm_mul_ps(a.m128, b.m128);
#else
return make_float4(a.x*b.x, a.y*b.y, a.z*b.z, a.w*b.w);
@@ -715,7 +803,7 @@ ccl_device_inline float4 operator*(const float4& a, const float4& b)
ccl_device_inline float4 operator*(const float4& a, float f)
{
-#ifdef __KERNEL_SSE__
+#if defined(__KERNEL_SSE__)
return a * make_float4(f);
#else
return make_float4(a.x*f, a.y*f, a.z*f, a.w*f);
@@ -754,7 +842,8 @@ ccl_device_inline float4 operator/(const float4& a, const float4& b)
ccl_device_inline float4 operator+(const float4& a, const float4& b)
{
-#ifdef __KERNEL_SSE__
+ /* TODO(sergey): Disabled for now, causes crashes in certain cases. */
+#if defined(__KERNEL_SSE__) && 0
return _mm_add_ps(a.m128, b.m128);
#else
return make_float4(a.x+b.x, a.y+b.y, a.z+b.z, a.w+b.w);
@@ -794,7 +883,7 @@ ccl_device_inline int4 operator<(const float4& a, const float4& b)
#endif
}
-ccl_device_inline int4 operator>=(float4 a, float4 b)
+ccl_device_inline int4 operator>=(const float4& a, const float4& b)
{
#ifdef __KERNEL_SSE__
return _mm_cvtps_epi32(_mm_cmpge_ps(a.m128, b.m128)); /* todo: avoid cvt */
@@ -812,7 +901,7 @@ ccl_device_inline int4 operator<=(const float4& a, const float4& b)
#endif
}
-ccl_device_inline bool operator==(const float4 a, const float4 b)
+ccl_device_inline bool operator==(const float4& a, const float4& b)
{
#ifdef __KERNEL_SSE__
return (_mm_movemask_ps(_mm_cmpeq_ps(a.m128, b.m128)) & 15) == 15;
@@ -854,23 +943,23 @@ ccl_device_inline float average(const float4& a)
return reduce_add(a) * 0.25f;
}
-ccl_device_inline float len(const float4 a)
+ccl_device_inline float len(const float4& a)
{
return sqrtf(dot(a, a));
}
-ccl_device_inline float4 normalize(const float4 a)
+ccl_device_inline float4 normalize(const float4& a)
{
return a/len(a);
}
-ccl_device_inline float4 safe_normalize(const float4 a)
+ccl_device_inline float4 safe_normalize(const float4& a)
{
float t = len(a);
return (t != 0.0f)? a/t: a;
}
-ccl_device_inline float4 min(float4 a, float4 b)
+ccl_device_inline float4 min(const float4& a, const float4& b)
{
#ifdef __KERNEL_SSE__
return _mm_min_ps(a.m128, b.m128);
@@ -879,7 +968,7 @@ ccl_device_inline float4 min(float4 a, float4 b)
#endif
}
-ccl_device_inline float4 max(float4 a, float4 b)
+ccl_device_inline float4 max(const float4& a, const float4& b)
{
#ifdef __KERNEL_SSE__
return _mm_max_ps(a.m128, b.m128);
@@ -1151,7 +1240,7 @@ template<class A, class B> A lerp(const A& a, const A& b, const B& t)
/* Triangle */
-ccl_device_inline float triangle_area(const float3 v1, const float3 v2, const float3 v3)
+ccl_device_inline float triangle_area(const float3& v1, const float3& v2, const float3& v3)
{
return len(cross(v3 - v2, v1 - v2))*0.5f;
}
@@ -1329,6 +1418,15 @@ ccl_device float safe_modulo(float a, float b)
return (b != 0.0f)? fmodf(a, b): 0.0f;
}
+ccl_device_inline float beta(float x, float y)
+{
+#ifndef __KERNEL_OPENCL__
+ return expf(lgammaf(x) + lgammaf(y) - lgammaf(x+y));
+#else
+ return expf(lgamma(x) + lgamma(y) - lgamma(x+y));
+#endif
+}
+
/* Ray Intersection */
ccl_device bool ray_sphere_intersect(
@@ -1435,10 +1533,10 @@ ccl_device bool ray_triangle_intersect(
return true;
}
-ccl_device bool ray_triangle_intersect_uv(
- float3 ray_P, float3 ray_D, float ray_t,
- float3 v0, float3 v1, float3 v2,
- float *isect_u, float *isect_v, float *isect_t)
+ccl_device_inline bool ray_triangle_intersect_uv(
+ float3 ray_P, float3 ray_D, float ray_t,
+ float3 v0, float3 v1, float3 v2,
+ float *isect_u, float *isect_v, float *isect_t)
{
/* Calculate intersection */
float3 e1 = v1 - v0;
@@ -1479,21 +1577,31 @@ ccl_device bool ray_triangle_intersect_uv(
return true;
}
-ccl_device bool ray_quad_intersect(float3 ray_P, float3 ray_D, float ray_t,
- float3 quad_P, float3 quad_u, float3 quad_v,
- float3 *isect_P, float *isect_t)
+ccl_device bool ray_quad_intersect(float3 ray_P, float3 ray_D, float ray_mint, float ray_maxt,
+ float3 quad_P, float3 quad_u, float3 quad_v, float3 quad_n,
+ float3 *isect_P, float *isect_t, float *isect_u, float *isect_v)
{
- float3 v0 = quad_P - quad_u*0.5f - quad_v*0.5f;
- float3 v1 = quad_P + quad_u*0.5f - quad_v*0.5f;
- float3 v2 = quad_P + quad_u*0.5f + quad_v*0.5f;
- float3 v3 = quad_P - quad_u*0.5f + quad_v*0.5f;
+ float t = -(dot(ray_P, quad_n) - dot(quad_P, quad_n)) / dot(ray_D, quad_n);
+ if(t < ray_mint || t > ray_maxt)
+ return false;
- if(ray_triangle_intersect(ray_P, ray_D, ray_t, v0, v1, v2, isect_P, isect_t))
- return true;
- else if(ray_triangle_intersect(ray_P, ray_D, ray_t, v0, v2, v3, isect_P, isect_t))
- return true;
-
- return false;
+ float3 hit = ray_P + t*ray_D;
+ float3 inplane = hit - quad_P;
+
+ float u = dot(inplane, quad_u) / dot(quad_u, quad_u) + 0.5f;
+ if(u < 0.0f || u > 1.0f)
+ return false;
+
+ float v = dot(inplane, quad_v) / dot(quad_v, quad_v) + 0.5f;
+ if(v < 0.0f || v > 1.0f)
+ return false;
+
+ if(isect_P) *isect_P = hit;
+ if(isect_t) *isect_t = t;
+ if(isect_u) *isect_u = u;
+ if(isect_v) *isect_v = v;
+
+ return true;
}
/* projections */
@@ -1532,6 +1640,14 @@ ccl_device_inline float2 map_to_sphere(const float3 co)
ccl_device_inline int util_max_axis(float3 vec)
{
+#ifdef __KERNEL_SSE__
+ __m128 a = shuffle<0,0,1,1>(vec.m128);
+ __m128 b = shuffle<1,2,2,1>(vec.m128);
+ __m128 c = _mm_cmpgt_ps(a, b);
+ int mask = _mm_movemask_ps(c) & 0x7;
+ static const char tab[8] = {2, 2, 2, 0, 1, 2, 1, 0};
+ return tab[mask];
+#else
if(vec.x > vec.y) {
if(vec.x > vec.z)
return 0;
@@ -1544,6 +1660,7 @@ ccl_device_inline int util_max_axis(float3 vec)
else
return 2;
}
+#endif
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_math_fast.h b/intern/cycles/util/util_math_fast.h
index deb2013daae..d3960deb3b4 100644
--- a/intern/cycles/util/util_math_fast.h
+++ b/intern/cycles/util/util_math_fast.h
@@ -547,6 +547,9 @@ ccl_device_inline float fast_erff(float x)
const float a5 = 0.0002765672f;
const float a6 = 0.0000430638f;
const float a = fabsf(x);
+ if(a >= 12.3f) {
+ return copysignf(1.0f, x);
+ }
const float b = 1.0f - (1.0f - a); /* Crush denormals. */
const float r = madd(madd(madd(madd(madd(madd(a6, b, a5), b, a4), b, a3), b, a2), b, a1), b, 1.0f);
const float s = r * r; /* ^2 */
diff --git a/intern/cycles/util/util_path.cpp b/intern/cycles/util/util_path.cpp
index 83754728dbe..62ef8fc0b48 100644
--- a/intern/cycles/util/util_path.cpp
+++ b/intern/cycles/util/util_path.cpp
@@ -36,6 +36,9 @@ OIIO_NAMESPACE_USING
#else
# define DIR_SEP '/'
# include <dirent.h>
+# include <pwd.h>
+# include <unistd.h>
+# include <sys/types.h>
#endif
#ifdef HAVE_SHLWAPI_H
@@ -63,6 +66,7 @@ typedef struct stat path_stat_t;
static string cached_path = "";
static string cached_user_path = "";
+static string cached_xdg_cache_path = "";
namespace {
@@ -92,7 +96,7 @@ public:
{
}
- directory_iterator(const string& path)
+ explicit directory_iterator(const string& path)
: path_(path),
path_info_(path, find_data_)
{
@@ -176,7 +180,7 @@ class directory_iterator {
public:
class path_info {
public:
- path_info(const string& path)
+ explicit path_info(const string& path)
: path_(path),
entry_(NULL)
{
@@ -203,7 +207,7 @@ public:
{
}
- directory_iterator(const string& path)
+ explicit directory_iterator(const string& path)
: path_(path),
path_info_(path_),
cur_entry_(0)
@@ -331,6 +335,23 @@ static char *path_specials(const string& sub)
return NULL;
}
+#if defined(__linux__) || defined(__APPLE__)
+static string path_xdg_cache_get()
+{
+ const char *home = getenv("XDG_CACHE_HOME");
+ if(home) {
+ return string(home);
+ }
+ else {
+ home = getenv("HOME");
+ if(home == NULL) {
+ home = getpwuid(getuid())->pw_dir;
+ }
+ return path_join(string(home), ".cache");
+ }
+}
+#endif
+
void path_init(const string& path, const string& user_path)
{
cached_path = path;
@@ -364,6 +385,24 @@ string path_user_get(const string& sub)
return path_join(cached_user_path, sub);
}
+string path_cache_get(const string& sub)
+{
+#if defined(__linux__) || defined(__APPLE__)
+ if(cached_xdg_cache_path == "") {
+ cached_xdg_cache_path = path_xdg_cache_get();
+ }
+ string result = path_join(cached_xdg_cache_path, "cycles");
+ return path_join(result, sub);
+#else
+ /* TODO(sergey): What that should be on Windows? */
+ return path_user_get(path_join("cache", sub));
+#endif
+}
+
+#if defined(__linux__) || defined(__APPLE__)
+string path_xdg_home_get(const string& sub = "");
+#endif
+
string path_filename(const string& path)
{
size_t index = find_last_slash(path);
@@ -728,7 +767,20 @@ bool path_remove(const string& path)
return remove(path.c_str()) == 0;
}
-string path_source_replace_includes(const string& source, const string& path)
+static string line_directive(const string& path, int line)
+{
+ string escaped_path = path;
+ string_replace(escaped_path, "\"", "\\\"");
+ string_replace(escaped_path, "\'", "\\\'");
+ string_replace(escaped_path, "\?", "\\\?");
+ string_replace(escaped_path, "\\", "\\\\");
+ return string_printf("#line %d \"%s\"", line, escaped_path.c_str());
+}
+
+
+string path_source_replace_includes(const string& source,
+ const string& path,
+ const string& source_filename)
{
/* Our own little c preprocessor that replaces #includes with the file
* contents, to work around issue of opencl drivers not supporting
@@ -737,7 +789,7 @@ string path_source_replace_includes(const string& source, const string& path)
string result = "";
vector<string> lines;
- string_split(lines, source, "\n");
+ string_split(lines, source, "\n", false);
for(size_t i = 0; i < lines.size(); ++i) {
string line = lines[i];
@@ -757,9 +809,12 @@ string path_source_replace_includes(const string& source, const string& path)
* and avoids having list of include directories.x
*/
text = path_source_replace_includes(
- text, path_dirname(filepath));
- text = path_source_replace_includes(text, path);
- line = token.replace(0, n_end + 1, "\n" + text + "\n");
+ text, path_dirname(filepath), filename);
+ text = path_source_replace_includes(text, path, filename);
+ /* Use line directives for better error messages. */
+ line = line_directive(filepath, 1)
+ + token.replace(0, n_end + 1, "\n" + text + "\n")
+ + line_directive(path_join(path, source_filename), i);
}
}
}
diff --git a/intern/cycles/util/util_path.h b/intern/cycles/util/util_path.h
index c80247f3837..70dbb5ae403 100644
--- a/intern/cycles/util/util_path.h
+++ b/intern/cycles/util/util_path.h
@@ -35,6 +35,7 @@ CCL_NAMESPACE_BEGIN
void path_init(const string& path = "", const string& user_path = "");
string path_get(const string& sub = "");
string path_user_get(const string& sub = "");
+string path_cache_get(const string& sub = "");
/* path string manipulation */
string path_filename(const string& path);
@@ -65,7 +66,9 @@ bool path_read_text(const string& path, string& text);
bool path_remove(const string& path);
/* source code utility */
-string path_source_replace_includes(const string& source, const string& path);
+string path_source_replace_includes(const string& source,
+ const string& path,
+ const string& source_filename="");
/* cache utility */
void path_cache_clear_except(const string& name, const set<string>& except);
diff --git a/intern/cycles/util/util_progress.h b/intern/cycles/util/util_progress.h
index 0b35142ddb3..4ae1d61dd17 100644
--- a/intern/cycles/util/util_progress.h
+++ b/intern/cycles/util/util_progress.h
@@ -37,9 +37,9 @@ public:
tile = 0;
sample = 0;
start_time = time_dt();
- total_time = 0.0f;
- render_time = 0.0f;
- tile_time = 0.0f;
+ total_time = 0.0;
+ render_time = 0.0;
+ tile_time = 0.0;
status = "Initializing";
substatus = "";
sync_status = "";
@@ -75,9 +75,9 @@ public:
sample = 0;
start_time = time_dt();
render_start_time = time_dt();
- total_time = 0.0f;
- render_time = 0.0f;
- tile_time = 0.0f;
+ total_time = 0.0;
+ render_time = 0.0;
+ tile_time = 0.0;
status = "Initializing";
substatus = "";
sync_status = "";
diff --git a/intern/cycles/util/util_simd.h b/intern/cycles/util/util_simd.h
index 36da1550a94..f4f460d6cf6 100644
--- a/intern/cycles/util/util_simd.h
+++ b/intern/cycles/util/util_simd.h
@@ -71,7 +71,7 @@ __forceinline operator int ( ) const { return std::numeric_limits<
#define _lzcnt_u64 __lzcnt64
#endif
-#if defined(_WIN32) && !defined(__MINGW32__)
+#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__clang__)
__forceinline int __popcnt(int in) {
return _mm_popcnt_u32(in);
@@ -455,6 +455,7 @@ CCL_NAMESPACE_END
#include "util_sseb.h"
#include "util_ssei.h"
#include "util_ssef.h"
+#include "util_avxf.h"
#endif /* __UTIL_SIMD_TYPES_H__ */
diff --git a/intern/cycles/util/util_sky_model.cpp b/intern/cycles/util/util_sky_model.cpp
index a53c2ce1bb6..5730986cc4f 100644
--- a/intern/cycles/util/util_sky_model.cpp
+++ b/intern/cycles/util/util_sky_model.cpp
@@ -301,7 +301,7 @@ double arhosekskymodel_radiance(ArHosekSkyModelState *state,
int low_wl = (int)((wavelength - 320.0) / 40.0);
if(low_wl < 0 || low_wl >= 11)
- return 0.0f;
+ return 0.0;
double interp = fmod((wavelength - 320.0 ) / 40.0, 1.0);
diff --git a/intern/cycles/util/util_static_assert.h b/intern/cycles/util/util_static_assert.h
new file mode 100644
index 00000000000..033d85e8ec6
--- /dev/null
+++ b/intern/cycles/util/util_static_assert.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_STATIC_ASSERT_H__
+#define __UTIL_STATIC_ASSERT_H__
+
+CCL_NAMESPACE_BEGIN
+
+/* TODO(sergey): In theory CUDA might work with own static assert
+ * implementation since it's just pure C++.
+ */
+#ifndef __KERNEL_GPU__
+# if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
+/* C++11 has built-in static_assert() */
+# elif defined(static_assert)
+/* Some platforms might have static_assert() defined even tho their
+ * C++ support wouldn't be declared to be C++11.
+ */
+# else /* C++11 or MSVC2015 */
+template <bool Test> class StaticAssertFailure;
+template <> class StaticAssertFailure<true> {};
+# define _static_assert_private_glue_impl(A, B) A ## B
+# define _static_assert_glue(A, B) _static_assert_private_glue_impl(A, B)
+# ifdef __COUNTER__
+# define static_assert(condition, message) \
+ enum {_static_assert_glue(q_static_assert_result, __COUNTER__) = sizeof(StaticAssertFailure<!!(condition)>)} // NOLINT
+# else /* __COUNTER__ */
+# define static_assert(condition, message) \
+ enum {_static_assert_glue(q_static_assert_result, __LINE__) = sizeof(StaticAssertFailure<!!(condition)>)} // NOLINT
+# endif /* __COUNTER__ */
+# endif /* C++11 or MSVC2015 */
+#else /* __KERNEL_GPU__ */
+# define static_assert(statement, message)
+#endif /* __KERNEL_GPU__ */
+
+/* TODO(sergey): For until C++11 is a bare minimum for us,
+ * we do a bit of a trickery to show meaningful message so
+ * it's more or less clear what's wrong when building without
+ * C++11.
+ *
+ * The thing here is: our non-C++11 implementation doesn't
+ * have a way to print any message after preprocessor
+ * substitution so we rely on the message which is passed to
+ * static_assert() since that's the only message visible when
+ * compilation fails.
+ *
+ * After C++11 bump it should be possible to glue structure
+ * name to the error message,
+ */
+# define static_assert_align(st, align) \
+ static_assert((sizeof(st) % (align) == 0), "Structure must be strictly aligned") // NOLINT
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_STATIC_ASSERT_H__ */
diff --git a/intern/cycles/util/util_stats.h b/intern/cycles/util/util_stats.h
index ce27067dc5e..b970b017270 100644
--- a/intern/cycles/util/util_stats.h
+++ b/intern/cycles/util/util_stats.h
@@ -23,7 +23,10 @@ CCL_NAMESPACE_BEGIN
class Stats {
public:
+ enum static_init_t { static_init = 0 };
+
Stats() : mem_used(0), mem_peak(0) {}
+ explicit Stats(static_init_t) {}
void mem_alloc(size_t size) {
atomic_add_z(&mem_used, size);
diff --git a/intern/cycles/util/util_string.cpp b/intern/cycles/util/util_string.cpp
index b3a8c6d7c2e..5594aa8edb6 100644
--- a/intern/cycles/util/util_string.cpp
+++ b/intern/cycles/util/util_string.cpp
@@ -74,7 +74,10 @@ bool string_iequals(const string& a, const string& b)
return false;
}
-void string_split(vector<string>& tokens, const string& str, const string& separators)
+void string_split(vector<string>& tokens,
+ const string& str,
+ const string& separators,
+ bool skip_empty_tokens)
{
size_t token_start = 0, token_length = 0;
for(size_t i = 0; i < str.size(); ++i) {
@@ -87,9 +90,9 @@ void string_split(vector<string>& tokens, const string& str, const string& separ
}
else {
/* Current character is a separator,
- * append current token to the list (if token is not empty).
+ * append current token to the list.
*/
- if(token_length > 0) {
+ if(!skip_empty_tokens || token_length > 0) {
string token = str.substr(token_start, token_length);
tokens.push_back(token);
}
@@ -239,5 +242,49 @@ string string_to_ansi(const string& str)
#endif /* _WIN32 */
+string string_human_readable_size(size_t size)
+{
+ static const char suffixes[] = "BKMGTPEZY";
+
+ const char* suffix = suffixes;
+ size_t r = 0;
+
+ while(size >= 1024) {
+ r = size % 1024;
+ size /= 1024;
+ suffix++;
+ }
+
+ if(*suffix != 'B')
+ return string_printf("%.2f%c", double(size*1024+r)/1024.0, *suffix);
+ else
+ return string_printf("%zu", size);
+}
+
+string string_human_readable_number(size_t num)
+{
+ if(num == 0) {
+ return "0";
+ }
+
+ /* Add thousands separators. */
+ char buf[32];
+
+ char* p = buf+31;
+ *p = '\0';
+
+ int i = -1;
+ while(num) {
+ if(++i && i % 3 == 0)
+ *(--p) = ',';
+
+ *(--p) = '0' + (num % 10);
+
+ num /= 10;
+ }
+
+ return p;
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_string.h b/intern/cycles/util/util_string.h
index c4b51bda432..7aeed96f00b 100644
--- a/intern/cycles/util/util_string.h
+++ b/intern/cycles/util/util_string.h
@@ -39,7 +39,10 @@ using std::istringstream;
string string_printf(const char *format, ...) PRINTF_ATTRIBUTE;
bool string_iequals(const string& a, const string& b);
-void string_split(vector<string>& tokens, const string& str, const string& separators = "\t ");
+void string_split(vector<string>& tokens,
+ const string& str,
+ const string& separators = "\t ",
+ bool skip_empty_tokens = true);
void string_replace(string& haystack, const string& needle, const string& other);
bool string_startswith(const string& s, const char *start);
bool string_endswith(const string& s, const char *end);
@@ -62,6 +65,11 @@ string string_from_wstring(const wstring& path);
string string_to_ansi(const string& str);
#endif
+/* Make a string from a size in bytes in human readable form */
+string string_human_readable_size(size_t size);
+/* Make a string from a unitless quantity in human readable form */
+string string_human_readable_number(size_t num);
+
CCL_NAMESPACE_END
#endif /* __UTIL_STRING_H__ */
diff --git a/intern/cycles/util/util_system.cpp b/intern/cycles/util/util_system.cpp
index 4ff0ee91d73..d5fac9a0e34 100644
--- a/intern/cycles/util/util_system.cpp
+++ b/intern/cycles/util/util_system.cpp
@@ -15,7 +15,9 @@
*/
#include "util_system.h"
+
#include "util_debug.h"
+#include "util_logging.h"
#include "util_types.h"
#include "util_string.h"
@@ -33,28 +35,56 @@
CCL_NAMESPACE_BEGIN
-int system_cpu_thread_count()
+int system_cpu_group_count()
{
- static uint count = 0;
-
- if(count > 0)
- return count;
+#ifdef _WIN32
+ util_windows_init_numa_groups();
+ return GetActiveProcessorGroupCount();
+#else
+ /* TODO(sergey): Need to adopt for other platforms. */
+ return 1;
+#endif
+}
+int system_cpu_group_thread_count(int group)
+{
+ /* TODO(sergey): Need make other platforms aware of groups. */
#ifdef _WIN32
- SYSTEM_INFO info;
- GetSystemInfo(&info);
- count = (uint)info.dwNumberOfProcessors;
+ util_windows_init_numa_groups();
+ return GetActiveProcessorCount(group);
#elif defined(__APPLE__)
+ (void)group;
+ int count;
size_t len = sizeof(count);
int mib[2] = { CTL_HW, HW_NCPU };
-
sysctl(mib, 2, &count, &len, NULL, 0);
+ return count;
#else
- count = (uint)sysconf(_SC_NPROCESSORS_ONLN);
+ (void)group;
+ return sysconf(_SC_NPROCESSORS_ONLN);
#endif
+}
+
+int system_cpu_thread_count()
+{
+ static uint count = 0;
- if(count < 1)
+ if(count > 0) {
+ return count;
+ }
+
+ int max_group = system_cpu_group_count();
+ VLOG(1) << "Detected " << max_group << " CPU groups.";
+ for(int group = 0; group < max_group; ++group) {
+ int num_threads = system_cpu_group_thread_count(group);
+ VLOG(1) << "Group " << group
+ << " has " << num_threads << " threads.";
+ count += num_threads;
+ }
+
+ if(count < 1) {
count = 1;
+ }
return count;
}
diff --git a/intern/cycles/util/util_system.h b/intern/cycles/util/util_system.h
index 4e7e00f85fd..557aab6cbae 100644
--- a/intern/cycles/util/util_system.h
+++ b/intern/cycles/util/util_system.h
@@ -21,7 +21,15 @@
CCL_NAMESPACE_BEGIN
+/* Get number of available CPU groups. */
+int system_cpu_group_count();
+
+/* Get number of threads/processors in the specified group. */
+int system_cpu_group_thread_count(int group);
+
+/* Get total number of threads in all groups. */
int system_cpu_thread_count();
+
string system_cpu_brand_string();
int system_cpu_bits();
bool system_cpu_support_sse2();
diff --git a/intern/cycles/util/util_task.cpp b/intern/cycles/util/util_task.cpp
index 6f0100d8596..2e92916d659 100644
--- a/intern/cycles/util/util_task.cpp
+++ b/intern/cycles/util/util_task.cpp
@@ -16,6 +16,7 @@
#include "util_debug.h"
#include "util_foreach.h"
+#include "util_logging.h"
#include "util_system.h"
#include "util_task.h"
#include "util_time.h"
@@ -199,14 +200,31 @@ void TaskScheduler::init(int num_threads)
/* automatic number of threads */
num_threads = system_cpu_thread_count();
}
+ VLOG(1) << "Creating pool of " << num_threads << " threads.";
/* launch threads that will be waiting for work */
threads.resize(num_threads);
threads_ids.resize(num_threads);
- for(size_t i = 0; i < threads.size(); i++) {
- threads[i] = new thread(function_bind(&TaskScheduler::thread_run, i + 1));
- threads_ids.push_back(threads[i]->id());
+ int num_groups = system_cpu_group_count();
+ int thread_index = 0;
+ for(int group = 0; group < num_groups; ++group) {
+ /* NOTE: That's not really efficient from threading point of view,
+ * but it is simple to read and it doesn't make sense to use more
+ * user-specified threads than logical threads anyway.
+ */
+ int num_group_threads = (group == num_groups - 1)
+ ? (threads.size() - thread_index)
+ : system_cpu_group_thread_count(group);
+ for(int group_thread = 0;
+ group_thread < num_group_threads && thread_index < threads.size();
+ ++group_thread, ++thread_index)
+ {
+ threads[thread_index] = new thread(function_bind(&TaskScheduler::thread_run,
+ thread_index + 1),
+ group);
+ threads_ids[thread_index] = threads[thread_index]->id();
+ }
}
}
diff --git a/intern/cycles/util/util_task.h b/intern/cycles/util/util_task.h
index 09d6be973b0..528602fc332 100644
--- a/intern/cycles/util/util_task.h
+++ b/intern/cycles/util/util_task.h
@@ -52,7 +52,7 @@ class Task
{
public:
Task() {};
- Task(const TaskRunFunction& run_) : run(run_) {}
+ explicit Task(const TaskRunFunction& run_) : run(run_) {}
virtual ~Task() {}
diff --git a/intern/cycles/util/util_texture.h b/intern/cycles/util/util_texture.h
index 346ccd8ac63..aff928ea2ee 100644
--- a/intern/cycles/util/util_texture.h
+++ b/intern/cycles/util/util_texture.h
@@ -19,27 +19,63 @@
CCL_NAMESPACE_BEGIN
-/* Texture limits on various devices. */
+/* Texture limits on devices. */
/* CPU */
-#define TEX_NUM_BYTE4_IMAGES_CPU 1024
-#define TEX_NUM_FLOAT4_IMAGES_CPU 1024
-#define TEX_IMAGE_BYTE4_START_CPU TEX_NUM_FLOAT4_IMAGES_CPU
+#define TEX_NUM_FLOAT4_CPU 1024
+#define TEX_NUM_BYTE4_CPU 1024
+#define TEX_NUM_HALF4_CPU 1024
+#define TEX_NUM_FLOAT_CPU 1024
+#define TEX_NUM_BYTE_CPU 1024
+#define TEX_NUM_HALF_CPU 1024
+#define TEX_START_FLOAT4_CPU 0
+#define TEX_START_BYTE4_CPU TEX_NUM_FLOAT4_CPU
+#define TEX_START_HALF4_CPU (TEX_NUM_FLOAT4_CPU + TEX_NUM_BYTE4_CPU)
+#define TEX_START_FLOAT_CPU (TEX_NUM_FLOAT4_CPU + TEX_NUM_BYTE4_CPU + TEX_NUM_HALF4_CPU)
+#define TEX_START_BYTE_CPU (TEX_NUM_FLOAT4_CPU + TEX_NUM_BYTE4_CPU + TEX_NUM_HALF4_CPU + TEX_NUM_FLOAT_CPU)
+#define TEX_START_HALF_CPU (TEX_NUM_FLOAT4_CPU + TEX_NUM_BYTE4_CPU + TEX_NUM_HALF4_CPU + TEX_NUM_FLOAT_CPU + TEX_NUM_BYTE_CPU)
-/* CUDA (Fermi) */
-#define TEX_NUM_BYTE4_IMAGES_CUDA 88
-#define TEX_NUM_FLOAT4_IMAGES_CUDA 5
-#define TEX_IMAGE_BYTE4_START_CUDA TEX_NUM_FLOAT4_IMAGES_CUDA
+/* CUDA (Geforce 4xx and 5xx) */
+#define TEX_NUM_FLOAT4_CUDA 5
+#define TEX_NUM_BYTE4_CUDA 85
+#define TEX_NUM_HALF4_CUDA 0
+#define TEX_NUM_FLOAT_CUDA 0
+#define TEX_NUM_BYTE_CUDA 0
+#define TEX_NUM_HALF_CUDA 0
+#define TEX_START_FLOAT4_CUDA 0
+#define TEX_START_BYTE4_CUDA TEX_NUM_FLOAT4_CUDA
+#define TEX_START_HALF4_CUDA (TEX_NUM_FLOAT4_CUDA + TEX_NUM_BYTE4_CUDA)
+#define TEX_START_FLOAT_CUDA (TEX_NUM_FLOAT4_CUDA + TEX_NUM_BYTE4_CUDA + TEX_NUM_HALF4_CUDA)
+#define TEX_START_BYTE_CUDA (TEX_NUM_FLOAT4_CUDA + TEX_NUM_BYTE4_CUDA + TEX_NUM_HALF4_CUDA + TEX_NUM_FLOAT_CUDA)
+#define TEX_START_HALF_CUDA (TEX_NUM_FLOAT4_CUDA + TEX_NUM_BYTE4_CUDA + TEX_NUM_HALF4_CUDA + TEX_NUM_FLOAT_CUDA + TEX_NUM_BYTE_CUDA)
-/* CUDA (KEPLER and above) */
-#define TEX_NUM_BYTE4_IMAGES_CUDA_KEPLER 145
-#define TEX_NUM_FLOAT4_IMAGES_CUDA_KEPLER 5
-#define TEX_IMAGE_BYTE4_START_CUDA_KELPER TEX_NUM_FLOAT4_IMAGES_CUDA_KEPLER
+/* CUDA (Kepler, Geforce 6xx and above) */
+#define TEX_NUM_FLOAT4_CUDA_KEPLER 1024
+#define TEX_NUM_BYTE4_CUDA_KEPLER 1024
+#define TEX_NUM_HALF4_CUDA_KEPLER 1024
+#define TEX_NUM_FLOAT_CUDA_KEPLER 1024
+#define TEX_NUM_BYTE_CUDA_KEPLER 1024
+#define TEX_NUM_HALF_CUDA_KEPLER 1024
+#define TEX_START_FLOAT4_CUDA_KEPLER 0
+#define TEX_START_BYTE4_CUDA_KEPLER TEX_NUM_FLOAT4_CUDA_KEPLER
+#define TEX_START_HALF4_CUDA_KEPLER (TEX_NUM_FLOAT4_CUDA_KEPLER + TEX_NUM_BYTE4_CUDA_KEPLER)
+#define TEX_START_FLOAT_CUDA_KEPLER (TEX_NUM_FLOAT4_CUDA_KEPLER + TEX_NUM_BYTE4_CUDA_KEPLER + TEX_NUM_HALF4_CUDA_KEPLER)
+#define TEX_START_BYTE_CUDA_KEPLER (TEX_NUM_FLOAT4_CUDA_KEPLER + TEX_NUM_BYTE4_CUDA_KEPLER + TEX_NUM_HALF4_CUDA_KEPLER + TEX_NUM_FLOAT_CUDA_KEPLER)
+#define TEX_START_HALF_CUDA_KEPLER (TEX_NUM_FLOAT4_CUDA_KEPLER + TEX_NUM_BYTE4_CUDA_KEPLER + TEX_NUM_HALF4_CUDA_KEPLER + TEX_NUM_FLOAT_CUDA_KEPLER + TEX_NUM_BYTE_CUDA_KEPLER)
/* OpenCL */
-#define TEX_NUM_BYTE4_IMAGES_OPENCL 1024
-#define TEX_NUM_FLOAT4_IMAGES_OPENCL 1024
-#define TEX_IMAGE_BYTE4_START_OPENCL TEX_NUM_FLOAT4_IMAGES_OPENCL
+#define TEX_NUM_FLOAT4_OPENCL 1024
+#define TEX_NUM_BYTE4_OPENCL 1024
+#define TEX_NUM_HALF4_OPENCL 0
+#define TEX_NUM_FLOAT_OPENCL 1024
+#define TEX_NUM_BYTE_OPENCL 1024
+#define TEX_NUM_HALF_OPENCL 0
+#define TEX_START_FLOAT4_OPENCL 0
+#define TEX_START_BYTE4_OPENCL TEX_NUM_FLOAT4_OPENCL
+#define TEX_START_HALF4_OPENCL (TEX_NUM_FLOAT4_OPENCL + TEX_NUM_BYTE4_OPENCL)
+#define TEX_START_FLOAT_OPENCL (TEX_NUM_FLOAT4_OPENCL + TEX_NUM_BYTE4_OPENCL + TEX_NUM_HALF4_OPENCL)
+#define TEX_START_BYTE_OPENCL (TEX_NUM_FLOAT4_OPENCL + TEX_NUM_BYTE4_OPENCL + TEX_NUM_HALF4_OPENCL + TEX_NUM_FLOAT_OPENCL)
+#define TEX_START_HALF_OPENCL (TEX_NUM_FLOAT4_OPENCL + TEX_NUM_BYTE4_OPENCL + TEX_NUM_HALF4_OPENCL + TEX_NUM_FLOAT_OPENCL + TEX_NUM_BYTE_OPENCL)
/* Color to use when textures are not found. */
diff --git a/intern/cycles/util/util_thread.cpp b/intern/cycles/util/util_thread.cpp
new file mode 100644
index 00000000000..3db8b4bd197
--- /dev/null
+++ b/intern/cycles/util/util_thread.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util_thread.h"
+
+#include "util_system.h"
+#include "util_windows.h"
+
+CCL_NAMESPACE_BEGIN
+
+thread::thread(function<void(void)> run_cb, int group)
+ : run_cb_(run_cb),
+ joined_(false),
+ group_(group)
+{
+ pthread_create(&pthread_id_, NULL, run, (void*)this);
+}
+
+thread::~thread()
+{
+ if(!joined_) {
+ join();
+ }
+}
+
+void *thread::run(void *arg)
+{
+ thread *self = (thread*)(arg);
+ if(self->group_ != -1) {
+#ifdef _WIN32
+ HANDLE thread_handle = GetCurrentThread();
+ GROUP_AFFINITY group_affinity = { 0 };
+ int num_threads = system_cpu_group_thread_count(self->group_);
+ group_affinity.Group = self->group_;
+ group_affinity.Mask = (num_threads == 64)
+ ? -1
+ : (1ull << num_threads) - 1;
+ if(SetThreadGroupAffinity(thread_handle, &group_affinity, NULL) == 0) {
+ fprintf(stderr, "Error setting thread affinity.\n");
+ }
+#endif
+ }
+ self->run_cb_();
+ return NULL;
+}
+
+bool thread::join()
+{
+ joined_ = true;
+ return pthread_join(pthread_id_, NULL) == 0;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_thread.h b/intern/cycles/util/util_thread.h
index b43ae2956f3..5d0020aeea2 100644
--- a/intern/cycles/util/util_thread.h
+++ b/intern/cycles/util/util_thread.h
@@ -52,42 +52,22 @@ typedef boost::condition_variable thread_condition_variable;
class thread {
public:
- thread(function<void(void)> run_cb_)
+ thread(function<void(void)> run_cb, int group = -1);
+ ~thread();
- {
- joined = false;
- run_cb = run_cb_;
-
- pthread_create(&pthread_id, NULL, run, (void*)this);
- }
-
- ~thread()
- {
- if(!joined)
- join();
- }
-
- static void *run(void *arg)
- {
- ((thread*)arg)->run_cb();
- return NULL;
- }
-
- bool join()
- {
- joined = true;
- return pthread_join(pthread_id, NULL) == 0;
- }
+ static void *run(void *arg);
+ bool join();
pthread_t id() const
{
- return pthread_id;
+ return pthread_id_;
}
protected:
- function<void(void)> run_cb;
- pthread_t pthread_id;
- bool joined;
+ function<void(void)> run_cb_;
+ pthread_t pthread_id_;
+ bool joined_;
+ int group_;
};
/* Own wrapper around pthread's spin lock to make it's use easier. */
diff --git a/intern/cycles/util/util_time.h b/intern/cycles/util/util_time.h
index 9cd52d5f11a..a5b074bffa0 100644
--- a/intern/cycles/util/util_time.h
+++ b/intern/cycles/util/util_time.h
@@ -29,7 +29,7 @@ void time_sleep(double t);
class scoped_timer {
public:
- scoped_timer(double *value) : value_(value)
+ explicit scoped_timer(double *value) : value_(value)
{
time_start_ = time_dt();
}
diff --git a/intern/cycles/util/util_transform.cpp b/intern/cycles/util/util_transform.cpp
index 79e1137d238..2f10540c94e 100644
--- a/intern/cycles/util/util_transform.cpp
+++ b/intern/cycles/util/util_transform.cpp
@@ -158,7 +158,7 @@ Transform transform_inverse(const Transform& tfm)
float4 transform_to_quat(const Transform& tfm)
{
- double trace = tfm[0][0] + tfm[1][1] + tfm[2][2];
+ double trace = (double)(tfm[0][0] + tfm[1][1] + tfm[2][2]);
float4 qt;
if(trace > 0.0) {
diff --git a/intern/cycles/util/util_transform.h b/intern/cycles/util/util_transform.h
index f01db64a79b..ea5eb3b25b0 100644
--- a/intern/cycles/util/util_transform.h
+++ b/intern/cycles/util/util_transform.h
@@ -73,22 +73,60 @@ ccl_device_inline float3 transform_perspective(const Transform *t, const float3
ccl_device_inline float3 transform_point(const Transform *t, const float3 a)
{
+ /* TODO(sergey): Disabled for now, causes crashes in certain cases. */
+#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__) && 0
+ ssef x, y, z, w, aa;
+ aa = a.m128;
+
+ x = _mm_loadu_ps(&t->x.x);
+ y = _mm_loadu_ps(&t->y.x);
+ z = _mm_loadu_ps(&t->z.x);
+ w = _mm_loadu_ps(&t->w.x);
+
+ _MM_TRANSPOSE4_PS(x, y, z, w);
+
+ ssef tmp = shuffle<0>(aa) * x;
+ tmp = madd(shuffle<1>(aa), y, tmp);
+ tmp = madd(shuffle<2>(aa), z, tmp);
+ tmp += w;
+
+ return float3(tmp.m128);
+#else
float3 c = make_float3(
a.x*t->x.x + a.y*t->x.y + a.z*t->x.z + t->x.w,
a.x*t->y.x + a.y*t->y.y + a.z*t->y.z + t->y.w,
a.x*t->z.x + a.y*t->z.y + a.z*t->z.z + t->z.w);
return c;
+#endif
}
ccl_device_inline float3 transform_direction(const Transform *t, const float3 a)
{
+ /* TODO(sergey): Disabled for now, causes crashes in certain cases. */
+#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__) && 0
+ ssef x, y, z, w, aa;
+ aa = a.m128;
+ x = _mm_loadu_ps(&t->x.x);
+ y = _mm_loadu_ps(&t->y.x);
+ z = _mm_loadu_ps(&t->z.x);
+ w = _mm_setzero_ps();
+
+ _MM_TRANSPOSE4_PS(x, y, z, w);
+
+ ssef tmp = shuffle<0>(aa) * x;
+ tmp = madd(shuffle<1>(aa), y, tmp);
+ tmp = madd(shuffle<2>(aa), z, tmp);
+
+ return float3(tmp.m128);
+#else
float3 c = make_float3(
a.x*t->x.x + a.y*t->x.y + a.z*t->x.z,
a.x*t->y.x + a.y*t->y.y + a.z*t->y.z,
a.x*t->z.x + a.y*t->z.y + a.z*t->z.z);
return c;
+#endif
}
ccl_device_inline float3 transform_direction_transposed(const Transform *t, const float3 a)
@@ -127,6 +165,19 @@ ccl_device_inline Transform make_transform(float a, float b, float c, float d,
return t;
}
+/* Constructs a coordinate frame from a normalized normal. */
+ccl_device_inline Transform make_transform_frame(float3 N)
+{
+ const float3 dx0 = cross(make_float3(1.0f, 0.0f, 0.0f), N);
+ const float3 dx1 = cross(make_float3(0.0f, 1.0f, 0.0f), N);
+ const float3 dx = normalize((dot(dx0,dx0) > dot(dx1,dx1))? dx0: dx1);
+ const float3 dy = normalize(cross(N, dx));
+ return make_transform(dx.x, dx.y, dx.z, 0.0f,
+ dy.x, dy.y, dy.z, 0.0f,
+ N.x , N.y, N.z, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f);
+}
+
#ifndef __KERNEL_GPU__
ccl_device_inline Transform operator*(const Transform a, const Transform b)
@@ -310,6 +361,15 @@ ccl_device_inline Transform transform_clear_scale(const Transform& tfm)
return ntfm;
}
+ccl_device_inline Transform transform_empty()
+{
+ return make_transform(
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0);
+}
+
#endif
/* Motion Transform */
diff --git a/intern/cycles/util/util_types.h b/intern/cycles/util/util_types.h
index 972befa185b..a000fae4bd6 100644
--- a/intern/cycles/util/util_types.h
+++ b/intern/cycles/util/util_types.h
@@ -37,10 +37,12 @@
#define ccl_device_noinline static
#define ccl_global
#define ccl_constant
+#define ccl_restrict __restrict
#define __KERNEL_WITH_SSE_ALIGN__
#if defined(_WIN32) && !defined(FREE_WINDOWS)
#define ccl_device_inline static __forceinline
+#define ccl_device_forceinline static __forceinline
#define ccl_align(...) __declspec(align(__VA_ARGS__))
#ifdef __KERNEL_64_BIT__
#define ccl_try_align(...) __declspec(align(__VA_ARGS__))
@@ -55,6 +57,7 @@
#else
#define ccl_device_inline static inline __attribute__((always_inline))
+#define ccl_device_forceinline static inline __attribute__((always_inline))
#define ccl_align(...) __attribute__((aligned(__VA_ARGS__)))
#ifndef FREE_WINDOWS64
#define __forceinline inline __attribute__((always_inline))
@@ -171,6 +174,9 @@ struct ccl_try_align(16) int3 {
__forceinline int3(const __m128i a) : m128(a) {}
__forceinline operator const __m128i&(void) const { return m128; }
__forceinline operator __m128i&(void) { return m128; }
+
+ int3(const int3& a) { m128 = a.m128; }
+ int3& operator =(const int3& a) { m128 = a.m128; return *this; }
#else
int x, y, z, w;
#endif
@@ -190,6 +196,9 @@ struct ccl_try_align(16) int4 {
__forceinline int4(const __m128i a) : m128(a) {}
__forceinline operator const __m128i&(void) const { return m128; }
__forceinline operator __m128i&(void) { return m128; }
+
+ int4(const int4& a) : m128(a.m128) {}
+ int4& operator=(const int4& a) { m128 = a.m128; return *this; }
#else
int x, y, z, w;
#endif
@@ -234,9 +243,12 @@ struct ccl_try_align(16) float3 {
};
__forceinline float3() {}
- __forceinline float3(const __m128 a) : m128(a) {}
+ __forceinline float3(const __m128& a) : m128(a) {}
__forceinline operator const __m128&(void) const { return m128; }
__forceinline operator __m128&(void) { return m128; }
+
+ __forceinline float3(const float3& a) : m128(a.m128) {}
+ __forceinline float3& operator =(const float3& a) { m128 = a.m128; return *this; }
#else
float x, y, z, w;
#endif
@@ -256,6 +268,10 @@ struct ccl_try_align(16) float4 {
__forceinline float4(const __m128 a) : m128(a) {}
__forceinline operator const __m128&(void) const { return m128; }
__forceinline operator __m128&(void) { return m128; }
+
+ __forceinline float4(const float4& a) : m128(a.m128) {}
+ __forceinline float4& operator =(const float4& a) { m128 = a.m128; return *this; }
+
#else
float x, y, z, w;
#endif
diff --git a/intern/cycles/util/util_vector.h b/intern/cycles/util/util_vector.h
index ad579da2d2e..546b17570bb 100644
--- a/intern/cycles/util/util_vector.h
+++ b/intern/cycles/util/util_vector.h
@@ -98,7 +98,7 @@ public:
capacity_(0)
{}
- array(size_t newsize)
+ explicit array(size_t newsize)
{
if(newsize == 0) {
data_ = NULL;
@@ -114,34 +114,34 @@ public:
array(const array& from)
{
- *this = from;
- }
-
- array& operator=(const array& from)
- {
- if(from.datasize == 0) {
+ if(from.datasize_ == 0) {
data_ = NULL;
datasize_ = 0;
capacity_ = 0;
}
else {
- data_ = mem_allocate(from.datasize);
- memcpy(data_, from.data, from.datasize*sizeof(T));
+ data_ = mem_allocate(from.datasize_);
+ memcpy(data_, from.data_, from.datasize_*sizeof(T));
datasize_ = from.datasize_;
capacity_ = datasize_;
}
+ }
+
+ array& operator=(const array& from)
+ {
+ if(this != &from) {
+ resize(from.size());
+ memcpy(data_, from.data_, datasize_*sizeof(T));
+ }
return *this;
}
array& operator=(const vector<T>& from)
{
- datasize_ = from.size();
- capacity_ = datasize_;
- data_ = NULL;
+ resize(from.size());
- if(datasize_ > 0) {
- data_ = mem_allocate(datasize_);
+ if(from.size() > 0) {
memcpy(data_, &from[0], datasize_*sizeof(T));
}
@@ -153,6 +153,30 @@ public:
mem_free(data_, capacity_);
}
+ bool operator==(const array<T>& other) const
+ {
+ if(datasize_ != other.datasize_) {
+ return false;
+ }
+
+ return memcmp(data_, other.data_, datasize_*sizeof(T)) == 0;
+ }
+
+ void steal_data(array& from)
+ {
+ if(this != &from) {
+ clear();
+
+ data_ = from.data_;
+ datasize_ = from.datasize_;
+ capacity_ = from.capacity_;
+
+ from.data_ = NULL;
+ from.datasize_ = 0;
+ from.capacity_ = 0;
+ }
+ }
+
T* resize(size_t newsize)
{
if(newsize == 0) {
@@ -188,18 +212,34 @@ public:
capacity_ = 0;
}
+ size_t empty() const
+ {
+ return datasize_ == 0;
+ }
+
size_t size() const
{
return datasize_;
}
+ T* data()
+ {
+ return data_;
+ }
+
+ const T* data() const
+ {
+ return data_;
+ }
+
T& operator[](size_t i) const
{
assert(i < datasize_);
return data_[i];
}
- void reserve(size_t newcapacity) {
+ void reserve(size_t newcapacity)
+ {
if(newcapacity > capacity_) {
T *newdata = mem_allocate(newcapacity);
if(data_ != NULL) {
@@ -211,10 +251,28 @@ public:
}
}
- size_t capacity() const {
+ size_t capacity() const
+ {
return capacity_;
}
+ // do not use this method unless you are sure the code is not performance critical
+ void push_back_slow(const T& t)
+ {
+ if(capacity_ == datasize_)
+ {
+ reserve(datasize_ == 0 ? 1 : (size_t)((datasize_ + 1) * 1.2));
+ }
+
+ data_[datasize_++] = t;
+ }
+
+ void push_back_reserved(const T& t)
+ {
+ assert(datasize_ < capacity_);
+ push_back_slow(t);
+ }
+
protected:
inline T* mem_allocate(size_t N)
{
diff --git a/intern/cycles/util/util_view.cpp b/intern/cycles/util/util_view.cpp
index 4d2adf33a7a..9796a5f896d 100644
--- a/intern/cycles/util/util_view.cpp
+++ b/intern/cycles/util/util_view.cpp
@@ -222,7 +222,7 @@ static void view_idle(void)
glutPostRedisplay();
}
- time_sleep(0.1f);
+ time_sleep(0.1);
}
void view_main_loop(const char *title, int width, int height,
diff --git a/intern/cycles/util/util_windows.cpp b/intern/cycles/util/util_windows.cpp
new file mode 100644
index 00000000000..ee5b3fd73c0
--- /dev/null
+++ b/intern/cycles/util/util_windows.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util_windows.h"
+
+#ifdef _WIN32
+
+CCL_NAMESPACE_BEGIN
+
+#ifdef _M_X64
+# include <VersionHelpers.h>
+#endif
+
+#if _WIN32_WINNT < 0x0601
+tGetActiveProcessorGroupCount *GetActiveProcessorGroupCount;
+tGetActiveProcessorCount *GetActiveProcessorCount;
+tSetThreadGroupAffinity *SetThreadGroupAffinity;
+#endif
+
+static WORD GetActiveProcessorGroupCount_stub()
+{
+ return 1;
+}
+
+static DWORD GetActiveProcessorCount_stub(WORD /*GroupNumber*/)
+{
+ SYSTEM_INFO info;
+ GetSystemInfo(&info);
+ return info.dwNumberOfProcessors;
+}
+
+static BOOL SetThreadGroupAffinity_stub(
+ HANDLE /*hThread*/,
+ const GROUP_AFFINITY * /*GroupAffinity*/,
+ PGROUP_AFFINITY /*PreviousGroupAffinity*/)
+{
+ return TRUE;
+}
+
+static bool supports_numa()
+{
+#ifndef _M_X64
+ return false;
+#else
+ return IsWindows7OrGreater();
+#endif
+}
+
+void util_windows_init_numa_groups()
+{
+ static bool initialized = false;
+ if(initialized) {
+ return;
+ }
+ initialized = true;
+#if _WIN32_WINNT < 0x0601
+ if(!supports_numa()) {
+ /* Use stubs on platforms which doesn't have rean NUMA/Groups. */
+ GetActiveProcessorGroupCount = GetActiveProcessorGroupCount_stub;
+ GetActiveProcessorCount = GetActiveProcessorCount_stub;
+ SetThreadGroupAffinity = SetThreadGroupAffinity_stub;
+ return;
+ }
+ HMODULE kernel = GetModuleHandleA("kernel32.dll");
+# define READ_SYMBOL(sym) sym = (t##sym*)GetProcAddress(kernel, #sym)
+ READ_SYMBOL(GetActiveProcessorGroupCount);
+ READ_SYMBOL(GetActiveProcessorCount);
+ READ_SYMBOL(SetThreadGroupAffinity);
+# undef READ_SUMBOL
+#endif
+}
+
+CCL_NAMESPACE_END
+
+#endif /* _WIN32 */
diff --git a/intern/cycles/util/util_windows.h b/intern/cycles/util/util_windows.h
index f67e34d0f31..ac61d5348c3 100644
--- a/intern/cycles/util/util_windows.h
+++ b/intern/cycles/util/util_windows.h
@@ -31,6 +31,25 @@
#include <windows.h>
+CCL_NAMESPACE_BEGIN
+
+#if _WIN32_WINNT < 0x0601
+typedef WORD tGetActiveProcessorGroupCount();
+typedef DWORD tGetActiveProcessorCount(WORD GroupNumber);
+typedef BOOL tSetThreadGroupAffinity(HANDLE hThread,
+ const GROUP_AFFINITY *GroupAffinity,
+ PGROUP_AFFINITY PreviousGroupAffinity);
+
+extern tGetActiveProcessorGroupCount *GetActiveProcessorGroupCount;
+extern tGetActiveProcessorCount *GetActiveProcessorCount;
+extern tSetThreadGroupAffinity *SetThreadGroupAffinity;
+#endif
+
+/* Make sure NUMA and processor groups API is initialized. */
+void util_windows_init_numa_groups();
+
+CCL_NAMESPACE_END
+
#endif /* WIN32 */
#endif /* __UTIL_WINDOWS_H__ */
diff --git a/intern/decklink/CMakeLists.txt b/intern/decklink/CMakeLists.txt
new file mode 100644
index 00000000000..fbef65cdba4
--- /dev/null
+++ b/intern/decklink/CMakeLists.txt
@@ -0,0 +1,58 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2015, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Blender Foundation.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+)
+
+set(INC_SYS
+)
+
+set(SRC
+ DeckLinkAPI.cpp
+ DeckLinkAPI.h
+)
+
+if (WIN32)
+ list(APPEND SRC
+ win/DeckLinkAPI_h.h
+ win/DeckLinkAPI_i.c
+ )
+endif()
+
+if (UNIX AND NOT APPLE)
+ list(APPEND SRC
+ linux/DeckLinkAPI.h
+ linux/DeckLinkAPIConfiguration.h
+ linux/DeckLinkAPIDeckControl.h
+ linux/DeckLinkAPIDiscovery.h
+ linux/DeckLinkAPIDispatch.cpp
+ linux/DeckLinkAPIModes.h
+ linux/DeckLinkAPIVersion.h
+ linux/DeckLinkAPITypes.h
+ linux/LinuxCOM.h
+ )
+endif()
+
+blender_add_lib(bf_intern_decklink "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/intern/decklink/DeckLinkAPI.cpp b/intern/decklink/DeckLinkAPI.cpp
new file mode 100644
index 00000000000..aff25af70eb
--- /dev/null
+++ b/intern/decklink/DeckLinkAPI.cpp
@@ -0,0 +1,50 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file decklink/DeckLinkAPI.cpp
+ * \ingroup decklink
+ */
+
+#include "DeckLinkAPI.h"
+
+#ifdef WIN32
+IDeckLinkIterator* BMD_CreateDeckLinkIterator(void)
+{
+ HRESULT result;
+ IDeckLinkIterator* pDLIterator = NULL;
+
+ result = CoCreateInstance(CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL, IID_IDeckLinkIterator, (void**)&pDLIterator);
+ if (FAILED(result))
+ return NULL;
+ return pDLIterator;
+}
+#else
+IDeckLinkIterator* BMD_CreateDeckLinkIterator(void)
+{
+ return CreateDeckLinkIteratorInstance();
+}
+#endif // WIN32
diff --git a/intern/decklink/DeckLinkAPI.h b/intern/decklink/DeckLinkAPI.h
new file mode 100644
index 00000000000..2a429c18c3c
--- /dev/null
+++ b/intern/decklink/DeckLinkAPI.h
@@ -0,0 +1,56 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file decklink/DeckLinkAPI.h
+ * \ingroup decklink
+ */
+
+#ifndef __DECKLINKAPI_H__
+#define __DECKLINKAPI_H__
+
+/* Include the OS specific Declink headers */
+
+#ifdef WIN32
+# include <windows.h>
+# include <objbase.h>
+# include <comutil.h>
+# include "win/DeckLinkAPI_h.h"
+ typedef unsigned int dl_size_t;
+#elif defined(__APPLE__)
+# error "Decklink not supported in OSX"
+#else
+# include "linux/DeckLinkAPI.h"
+ /* Windows COM API uses BOOL, linux uses bool */
+# define BOOL bool
+ typedef uint32_t dl_size_t;
+#endif
+
+
+/* OS independent function to get the device iterator */
+IDeckLinkIterator* BMD_CreateDeckLinkIterator(void);
+
+#endif /* __DECKLINKAPI_H__ */
diff --git a/intern/decklink/linux/DeckLinkAPI.h b/intern/decklink/linux/DeckLinkAPI.h
new file mode 100644
index 00000000000..08bfba39994
--- /dev/null
+++ b/intern/decklink/linux/DeckLinkAPI.h
@@ -0,0 +1,767 @@
+/* -LICENSE-START-
+** Copyright (c) 2014 Blackmagic Design
+**
+** Permission is hereby granted, free of charge, to any person or organization
+** obtaining a copy of the software and accompanying documentation covered by
+** this license (the "Software") to use, reproduce, display, distribute,
+** execute, and transmit the Software, and to prepare derivative works of the
+** Software, and to permit third-parties to whom the Software is furnished to
+** do so, all subject to the following:
+**
+** The copyright notices in the Software and this entire statement, including
+** the above license grant, this restriction and the following disclaimer,
+** must be included in all copies of the Software, in whole or in part, and
+** all derivative works of the Software, unless such copies or derivative
+** works are solely in the form of machine-executable object code generated by
+** a source language processor.
+**
+** 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+** DEALINGS IN THE SOFTWARE.
+** -LICENSE-END-
+*/
+
+#ifndef BMD_DECKLINKAPI_H
+#define BMD_DECKLINKAPI_H
+
+
+#ifndef BMD_CONST
+ #if defined(_MSC_VER)
+ #define BMD_CONST __declspec(selectany) static const
+ #else
+ #define BMD_CONST static const
+ #endif
+#endif
+
+/* DeckLink API */
+
+#include <stdint.h>
+#include "LinuxCOM.h"
+
+#include "DeckLinkAPITypes.h"
+#include "DeckLinkAPIModes.h"
+#include "DeckLinkAPIDiscovery.h"
+#include "DeckLinkAPIConfiguration.h"
+#include "DeckLinkAPIDeckControl.h"
+
+#define BLACKMAGIC_DECKLINK_API_MAGIC 1
+
+// Type Declarations
+
+
+// Interface ID Declarations
+
+BMD_CONST REFIID IID_IDeckLinkVideoOutputCallback = /* 20AA5225-1958-47CB-820B-80A8D521A6EE */ {0x20,0xAA,0x52,0x25,0x19,0x58,0x47,0xCB,0x82,0x0B,0x80,0xA8,0xD5,0x21,0xA6,0xEE};
+BMD_CONST REFIID IID_IDeckLinkInputCallback = /* DD04E5EC-7415-42AB-AE4A-E80C4DFC044A */ {0xDD,0x04,0xE5,0xEC,0x74,0x15,0x42,0xAB,0xAE,0x4A,0xE8,0x0C,0x4D,0xFC,0x04,0x4A};
+BMD_CONST REFIID IID_IDeckLinkMemoryAllocator = /* B36EB6E7-9D29-4AA8-92EF-843B87A289E8 */ {0xB3,0x6E,0xB6,0xE7,0x9D,0x29,0x4A,0xA8,0x92,0xEF,0x84,0x3B,0x87,0xA2,0x89,0xE8};
+BMD_CONST REFIID IID_IDeckLinkAudioOutputCallback = /* 403C681B-7F46-4A12-B993-2BB127084EE6 */ {0x40,0x3C,0x68,0x1B,0x7F,0x46,0x4A,0x12,0xB9,0x93,0x2B,0xB1,0x27,0x08,0x4E,0xE6};
+BMD_CONST REFIID IID_IDeckLinkIterator = /* 50FB36CD-3063-4B73-BDBB-958087F2D8BA */ {0x50,0xFB,0x36,0xCD,0x30,0x63,0x4B,0x73,0xBD,0xBB,0x95,0x80,0x87,0xF2,0xD8,0xBA};
+BMD_CONST REFIID IID_IDeckLinkAPIInformation = /* 7BEA3C68-730D-4322-AF34-8A7152B532A4 */ {0x7B,0xEA,0x3C,0x68,0x73,0x0D,0x43,0x22,0xAF,0x34,0x8A,0x71,0x52,0xB5,0x32,0xA4};
+BMD_CONST REFIID IID_IDeckLinkOutput = /* CC5C8A6E-3F2F-4B3A-87EA-FD78AF300564 */ {0xCC,0x5C,0x8A,0x6E,0x3F,0x2F,0x4B,0x3A,0x87,0xEA,0xFD,0x78,0xAF,0x30,0x05,0x64};
+BMD_CONST REFIID IID_IDeckLinkInput = /* AF22762B-DFAC-4846-AA79-FA8883560995 */ {0xAF,0x22,0x76,0x2B,0xDF,0xAC,0x48,0x46,0xAA,0x79,0xFA,0x88,0x83,0x56,0x09,0x95};
+BMD_CONST REFIID IID_IDeckLinkVideoFrame = /* 3F716FE0-F023-4111-BE5D-EF4414C05B17 */ {0x3F,0x71,0x6F,0xE0,0xF0,0x23,0x41,0x11,0xBE,0x5D,0xEF,0x44,0x14,0xC0,0x5B,0x17};
+BMD_CONST REFIID IID_IDeckLinkMutableVideoFrame = /* 69E2639F-40DA-4E19-B6F2-20ACE815C390 */ {0x69,0xE2,0x63,0x9F,0x40,0xDA,0x4E,0x19,0xB6,0xF2,0x20,0xAC,0xE8,0x15,0xC3,0x90};
+BMD_CONST REFIID IID_IDeckLinkVideoFrame3DExtensions = /* DA0F7E4A-EDC7-48A8-9CDD-2DB51C729CD7 */ {0xDA,0x0F,0x7E,0x4A,0xED,0xC7,0x48,0xA8,0x9C,0xDD,0x2D,0xB5,0x1C,0x72,0x9C,0xD7};
+BMD_CONST REFIID IID_IDeckLinkVideoInputFrame = /* 05CFE374-537C-4094-9A57-680525118F44 */ {0x05,0xCF,0xE3,0x74,0x53,0x7C,0x40,0x94,0x9A,0x57,0x68,0x05,0x25,0x11,0x8F,0x44};
+BMD_CONST REFIID IID_IDeckLinkVideoFrameAncillary = /* 732E723C-D1A4-4E29-9E8E-4A88797A0004 */ {0x73,0x2E,0x72,0x3C,0xD1,0xA4,0x4E,0x29,0x9E,0x8E,0x4A,0x88,0x79,0x7A,0x00,0x04};
+BMD_CONST REFIID IID_IDeckLinkAudioInputPacket = /* E43D5870-2894-11DE-8C30-0800200C9A66 */ {0xE4,0x3D,0x58,0x70,0x28,0x94,0x11,0xDE,0x8C,0x30,0x08,0x00,0x20,0x0C,0x9A,0x66};
+BMD_CONST REFIID IID_IDeckLinkScreenPreviewCallback = /* B1D3F49A-85FE-4C5D-95C8-0B5D5DCCD438 */ {0xB1,0xD3,0xF4,0x9A,0x85,0xFE,0x4C,0x5D,0x95,0xC8,0x0B,0x5D,0x5D,0xCC,0xD4,0x38};
+BMD_CONST REFIID IID_IDeckLinkGLScreenPreviewHelper = /* 504E2209-CAC7-4C1A-9FB4-C5BB6274D22F */ {0x50,0x4E,0x22,0x09,0xCA,0xC7,0x4C,0x1A,0x9F,0xB4,0xC5,0xBB,0x62,0x74,0xD2,0x2F};
+BMD_CONST REFIID IID_IDeckLinkNotificationCallback = /* B002A1EC-070D-4288-8289-BD5D36E5FF0D */ {0xB0,0x02,0xA1,0xEC,0x07,0x0D,0x42,0x88,0x82,0x89,0xBD,0x5D,0x36,0xE5,0xFF,0x0D};
+BMD_CONST REFIID IID_IDeckLinkNotification = /* 0A1FB207-E215-441B-9B19-6FA1575946C5 */ {0x0A,0x1F,0xB2,0x07,0xE2,0x15,0x44,0x1B,0x9B,0x19,0x6F,0xA1,0x57,0x59,0x46,0xC5};
+BMD_CONST REFIID IID_IDeckLinkAttributes = /* ABC11843-D966-44CB-96E2-A1CB5D3135C4 */ {0xAB,0xC1,0x18,0x43,0xD9,0x66,0x44,0xCB,0x96,0xE2,0xA1,0xCB,0x5D,0x31,0x35,0xC4};
+BMD_CONST REFIID IID_IDeckLinkKeyer = /* 89AFCAF5-65F8-421E-98F7-96FE5F5BFBA3 */ {0x89,0xAF,0xCA,0xF5,0x65,0xF8,0x42,0x1E,0x98,0xF7,0x96,0xFE,0x5F,0x5B,0xFB,0xA3};
+BMD_CONST REFIID IID_IDeckLinkVideoConversion = /* 3BBCB8A2-DA2C-42D9-B5D8-88083644E99A */ {0x3B,0xBC,0xB8,0xA2,0xDA,0x2C,0x42,0xD9,0xB5,0xD8,0x88,0x08,0x36,0x44,0xE9,0x9A};
+BMD_CONST REFIID IID_IDeckLinkDeviceNotificationCallback = /* 4997053B-0ADF-4CC8-AC70-7A50C4BE728F */ {0x49,0x97,0x05,0x3B,0x0A,0xDF,0x4C,0xC8,0xAC,0x70,0x7A,0x50,0xC4,0xBE,0x72,0x8F};
+BMD_CONST REFIID IID_IDeckLinkDiscovery = /* CDBF631C-BC76-45FA-B44D-C55059BC6101 */ {0xCD,0xBF,0x63,0x1C,0xBC,0x76,0x45,0xFA,0xB4,0x4D,0xC5,0x50,0x59,0xBC,0x61,0x01};
+
+/* Enum BMDVideoOutputFlags - Flags to control the output of ancillary data along with video. */
+
+typedef uint32_t BMDVideoOutputFlags;
+enum _BMDVideoOutputFlags {
+ bmdVideoOutputFlagDefault = 0,
+ bmdVideoOutputVANC = 1 << 0,
+ bmdVideoOutputVITC = 1 << 1,
+ bmdVideoOutputRP188 = 1 << 2,
+ bmdVideoOutputDualStream3D = 1 << 4
+};
+
+/* Enum BMDFrameFlags - Frame flags */
+
+typedef uint32_t BMDFrameFlags;
+enum _BMDFrameFlags {
+ bmdFrameFlagDefault = 0,
+ bmdFrameFlagFlipVertical = 1 << 0,
+
+ /* Flags that are applicable only to instances of IDeckLinkVideoInputFrame */
+
+ bmdFrameHasNoInputSource = 1 << 31
+};
+
+/* Enum BMDVideoInputFlags - Flags applicable to video input */
+
+typedef uint32_t BMDVideoInputFlags;
+enum _BMDVideoInputFlags {
+ bmdVideoInputFlagDefault = 0,
+ bmdVideoInputEnableFormatDetection = 1 << 0,
+ bmdVideoInputDualStream3D = 1 << 1
+};
+
+/* Enum BMDVideoInputFormatChangedEvents - Bitmask passed to the VideoInputFormatChanged notification to identify the properties of the input signal that have changed */
+
+typedef uint32_t BMDVideoInputFormatChangedEvents;
+enum _BMDVideoInputFormatChangedEvents {
+ bmdVideoInputDisplayModeChanged = 1 << 0,
+ bmdVideoInputFieldDominanceChanged = 1 << 1,
+ bmdVideoInputColorspaceChanged = 1 << 2
+};
+
+/* Enum BMDDetectedVideoInputFormatFlags - Flags passed to the VideoInputFormatChanged notification to describe the detected video input signal */
+
+typedef uint32_t BMDDetectedVideoInputFormatFlags;
+enum _BMDDetectedVideoInputFormatFlags {
+ bmdDetectedVideoInputYCbCr422 = 1 << 0,
+ bmdDetectedVideoInputRGB444 = 1 << 1,
+ bmdDetectedVideoInputDualStream3D = 1 << 2
+};
+
+/* Enum BMDDeckLinkCapturePassthroughMode - Enumerates whether the video output is electrically connected to the video input or if the clean switching mode is enabled */
+
+typedef uint32_t BMDDeckLinkCapturePassthroughMode;
+enum _BMDDeckLinkCapturePassthroughMode {
+ bmdDeckLinkCapturePassthroughModeDirect = /* 'pdir' */ 0x70646972,
+ bmdDeckLinkCapturePassthroughModeCleanSwitch = /* 'pcln' */ 0x70636C6E
+};
+
+/* Enum BMDOutputFrameCompletionResult - Frame Completion Callback */
+
+typedef uint32_t BMDOutputFrameCompletionResult;
+enum _BMDOutputFrameCompletionResult {
+ bmdOutputFrameCompleted,
+ bmdOutputFrameDisplayedLate,
+ bmdOutputFrameDropped,
+ bmdOutputFrameFlushed
+};
+
+/* Enum BMDReferenceStatus - GenLock input status */
+
+typedef uint32_t BMDReferenceStatus;
+enum _BMDReferenceStatus {
+ bmdReferenceNotSupportedByHardware = 1 << 0,
+ bmdReferenceLocked = 1 << 1
+};
+
+/* Enum BMDAudioSampleRate - Audio sample rates supported for output/input */
+
+typedef uint32_t BMDAudioSampleRate;
+enum _BMDAudioSampleRate {
+ bmdAudioSampleRate48kHz = 48000
+};
+
+/* Enum BMDAudioSampleType - Audio sample sizes supported for output/input */
+
+typedef uint32_t BMDAudioSampleType;
+enum _BMDAudioSampleType {
+ bmdAudioSampleType16bitInteger = 16,
+ bmdAudioSampleType32bitInteger = 32
+};
+
+/* Enum BMDAudioOutputStreamType - Audio output stream type */
+
+typedef uint32_t BMDAudioOutputStreamType;
+enum _BMDAudioOutputStreamType {
+ bmdAudioOutputStreamContinuous,
+ bmdAudioOutputStreamContinuousDontResample,
+ bmdAudioOutputStreamTimestamped
+};
+
+/* Enum BMDDisplayModeSupport - Output mode supported flags */
+
+typedef uint32_t BMDDisplayModeSupport;
+enum _BMDDisplayModeSupport {
+ bmdDisplayModeNotSupported = 0,
+ bmdDisplayModeSupported,
+ bmdDisplayModeSupportedWithConversion
+};
+
+/* Enum BMDTimecodeFormat - Timecode formats for frame metadata */
+
+typedef uint32_t BMDTimecodeFormat;
+enum _BMDTimecodeFormat {
+ bmdTimecodeRP188VITC1 = /* 'rpv1' */ 0x72707631, // RP188 timecode where DBB1 equals VITC1 (line 9)
+ bmdTimecodeRP188VITC2 = /* 'rp12' */ 0x72703132, // RP188 timecode where DBB1 equals VITC2 (line 9 for progressive or line 571 for interlaced/PsF)
+ bmdTimecodeRP188LTC = /* 'rplt' */ 0x72706C74, // RP188 timecode where DBB1 equals LTC (line 10)
+ bmdTimecodeRP188Any = /* 'rp18' */ 0x72703138, // For capture: return the first valid timecode in {VITC1, LTC ,VITC2} - For playback: set the timecode as VITC1
+ bmdTimecodeVITC = /* 'vitc' */ 0x76697463,
+ bmdTimecodeVITCField2 = /* 'vit2' */ 0x76697432,
+ bmdTimecodeSerial = /* 'seri' */ 0x73657269
+};
+
+/* Enum BMDAnalogVideoFlags - Analog video display flags */
+
+typedef uint32_t BMDAnalogVideoFlags;
+enum _BMDAnalogVideoFlags {
+ bmdAnalogVideoFlagCompositeSetup75 = 1 << 0,
+ bmdAnalogVideoFlagComponentBetacamLevels = 1 << 1
+};
+
+/* Enum BMDAudioOutputAnalogAESSwitch - Audio output Analog/AESEBU switch */
+
+typedef uint32_t BMDAudioOutputAnalogAESSwitch;
+enum _BMDAudioOutputAnalogAESSwitch {
+ bmdAudioOutputSwitchAESEBU = /* 'aes ' */ 0x61657320,
+ bmdAudioOutputSwitchAnalog = /* 'anlg' */ 0x616E6C67
+};
+
+/* Enum BMDVideoOutputConversionMode - Video/audio conversion mode */
+
+typedef uint32_t BMDVideoOutputConversionMode;
+enum _BMDVideoOutputConversionMode {
+ bmdNoVideoOutputConversion = /* 'none' */ 0x6E6F6E65,
+ bmdVideoOutputLetterboxDownconversion = /* 'ltbx' */ 0x6C746278,
+ bmdVideoOutputAnamorphicDownconversion = /* 'amph' */ 0x616D7068,
+ bmdVideoOutputHD720toHD1080Conversion = /* '720c' */ 0x37323063,
+ bmdVideoOutputHardwareLetterboxDownconversion = /* 'HWlb' */ 0x48576C62,
+ bmdVideoOutputHardwareAnamorphicDownconversion = /* 'HWam' */ 0x4857616D,
+ bmdVideoOutputHardwareCenterCutDownconversion = /* 'HWcc' */ 0x48576363,
+ bmdVideoOutputHardware720p1080pCrossconversion = /* 'xcap' */ 0x78636170,
+ bmdVideoOutputHardwareAnamorphic720pUpconversion = /* 'ua7p' */ 0x75613770,
+ bmdVideoOutputHardwareAnamorphic1080iUpconversion = /* 'ua1i' */ 0x75613169,
+ bmdVideoOutputHardwareAnamorphic149To720pUpconversion = /* 'u47p' */ 0x75343770,
+ bmdVideoOutputHardwareAnamorphic149To1080iUpconversion = /* 'u41i' */ 0x75343169,
+ bmdVideoOutputHardwarePillarbox720pUpconversion = /* 'up7p' */ 0x75703770,
+ bmdVideoOutputHardwarePillarbox1080iUpconversion = /* 'up1i' */ 0x75703169
+};
+
+/* Enum BMDVideoInputConversionMode - Video input conversion mode */
+
+typedef uint32_t BMDVideoInputConversionMode;
+enum _BMDVideoInputConversionMode {
+ bmdNoVideoInputConversion = /* 'none' */ 0x6E6F6E65,
+ bmdVideoInputLetterboxDownconversionFromHD1080 = /* '10lb' */ 0x31306C62,
+ bmdVideoInputAnamorphicDownconversionFromHD1080 = /* '10am' */ 0x3130616D,
+ bmdVideoInputLetterboxDownconversionFromHD720 = /* '72lb' */ 0x37326C62,
+ bmdVideoInputAnamorphicDownconversionFromHD720 = /* '72am' */ 0x3732616D,
+ bmdVideoInputLetterboxUpconversion = /* 'lbup' */ 0x6C627570,
+ bmdVideoInputAnamorphicUpconversion = /* 'amup' */ 0x616D7570
+};
+
+/* Enum BMDVideo3DPackingFormat - Video 3D packing format */
+
+typedef uint32_t BMDVideo3DPackingFormat;
+enum _BMDVideo3DPackingFormat {
+ bmdVideo3DPackingSidebySideHalf = /* 'sbsh' */ 0x73627368,
+ bmdVideo3DPackingLinebyLine = /* 'lbyl' */ 0x6C62796C,
+ bmdVideo3DPackingTopAndBottom = /* 'tabo' */ 0x7461626F,
+ bmdVideo3DPackingFramePacking = /* 'frpk' */ 0x6672706B,
+ bmdVideo3DPackingLeftOnly = /* 'left' */ 0x6C656674,
+ bmdVideo3DPackingRightOnly = /* 'righ' */ 0x72696768
+};
+
+/* Enum BMDIdleVideoOutputOperation - Video output operation when not playing video */
+
+typedef uint32_t BMDIdleVideoOutputOperation;
+enum _BMDIdleVideoOutputOperation {
+ bmdIdleVideoOutputBlack = /* 'blac' */ 0x626C6163,
+ bmdIdleVideoOutputLastFrame = /* 'lafa' */ 0x6C616661,
+ bmdIdleVideoOutputDesktop = /* 'desk' */ 0x6465736B
+};
+
+/* Enum BMDDeckLinkAttributeID - DeckLink Attribute ID */
+
+typedef uint32_t BMDDeckLinkAttributeID;
+enum _BMDDeckLinkAttributeID {
+
+ /* Flags */
+
+ BMDDeckLinkSupportsInternalKeying = /* 'keyi' */ 0x6B657969,
+ BMDDeckLinkSupportsExternalKeying = /* 'keye' */ 0x6B657965,
+ BMDDeckLinkSupportsHDKeying = /* 'keyh' */ 0x6B657968,
+ BMDDeckLinkSupportsInputFormatDetection = /* 'infd' */ 0x696E6664,
+ BMDDeckLinkHasReferenceInput = /* 'hrin' */ 0x6872696E,
+ BMDDeckLinkHasSerialPort = /* 'hspt' */ 0x68737074,
+ BMDDeckLinkHasAnalogVideoOutputGain = /* 'avog' */ 0x61766F67,
+ BMDDeckLinkCanOnlyAdjustOverallVideoOutputGain = /* 'ovog' */ 0x6F766F67,
+ BMDDeckLinkHasVideoInputAntiAliasingFilter = /* 'aafl' */ 0x6161666C,
+ BMDDeckLinkHasBypass = /* 'byps' */ 0x62797073,
+ BMDDeckLinkSupportsDesktopDisplay = /* 'extd' */ 0x65787464,
+ BMDDeckLinkSupportsClockTimingAdjustment = /* 'ctad' */ 0x63746164,
+ BMDDeckLinkSupportsFullDuplex = /* 'fdup' */ 0x66647570,
+ BMDDeckLinkSupportsFullFrameReferenceInputTimingOffset = /* 'frin' */ 0x6672696E,
+ BMDDeckLinkSupportsSMPTELevelAOutput = /* 'lvla' */ 0x6C766C61,
+ BMDDeckLinkSupportsDualLinkSDI = /* 'sdls' */ 0x73646C73,
+ BMDDeckLinkSupportsIdleOutput = /* 'idou' */ 0x69646F75,
+
+ /* Integers */
+
+ BMDDeckLinkMaximumAudioChannels = /* 'mach' */ 0x6D616368,
+ BMDDeckLinkMaximumAnalogAudioChannels = /* 'aach' */ 0x61616368,
+ BMDDeckLinkNumberOfSubDevices = /* 'nsbd' */ 0x6E736264,
+ BMDDeckLinkSubDeviceIndex = /* 'subi' */ 0x73756269,
+ BMDDeckLinkPersistentID = /* 'peid' */ 0x70656964,
+ BMDDeckLinkTopologicalID = /* 'toid' */ 0x746F6964,
+ BMDDeckLinkVideoOutputConnections = /* 'vocn' */ 0x766F636E,
+ BMDDeckLinkVideoInputConnections = /* 'vicn' */ 0x7669636E,
+ BMDDeckLinkAudioOutputConnections = /* 'aocn' */ 0x616F636E,
+ BMDDeckLinkAudioInputConnections = /* 'aicn' */ 0x6169636E,
+ BMDDeckLinkDeviceBusyState = /* 'dbst' */ 0x64627374,
+ BMDDeckLinkVideoIOSupport = /* 'vios' */ 0x76696F73, // Returns a BMDVideoIOSupport bit field
+
+ /* Floats */
+
+ BMDDeckLinkVideoInputGainMinimum = /* 'vigm' */ 0x7669676D,
+ BMDDeckLinkVideoInputGainMaximum = /* 'vigx' */ 0x76696778,
+ BMDDeckLinkVideoOutputGainMinimum = /* 'vogm' */ 0x766F676D,
+ BMDDeckLinkVideoOutputGainMaximum = /* 'vogx' */ 0x766F6778,
+
+ /* Strings */
+
+ BMDDeckLinkSerialPortDeviceName = /* 'slpn' */ 0x736C706E
+};
+
+/* Enum BMDDeckLinkAPIInformationID - DeckLinkAPI information ID */
+
+typedef uint32_t BMDDeckLinkAPIInformationID;
+enum _BMDDeckLinkAPIInformationID {
+ BMDDeckLinkAPIVersion = /* 'vers' */ 0x76657273
+};
+
+/* Enum BMDDeviceBusyState - Current device busy state */
+
+typedef uint32_t BMDDeviceBusyState;
+enum _BMDDeviceBusyState {
+ bmdDeviceCaptureBusy = 1 << 0,
+ bmdDevicePlaybackBusy = 1 << 1,
+ bmdDeviceSerialPortBusy = 1 << 2
+};
+
+/* Enum BMDVideoIOSupport - Device video input/output support */
+
+typedef uint32_t BMDVideoIOSupport;
+enum _BMDVideoIOSupport {
+ bmdDeviceSupportsCapture = 1 << 0,
+ bmdDeviceSupportsPlayback = 1 << 1
+};
+
+/* Enum BMD3DPreviewFormat - Linked Frame preview format */
+
+typedef uint32_t BMD3DPreviewFormat;
+enum _BMD3DPreviewFormat {
+ bmd3DPreviewFormatDefault = /* 'defa' */ 0x64656661,
+ bmd3DPreviewFormatLeftOnly = /* 'left' */ 0x6C656674,
+ bmd3DPreviewFormatRightOnly = /* 'righ' */ 0x72696768,
+ bmd3DPreviewFormatSideBySide = /* 'side' */ 0x73696465,
+ bmd3DPreviewFormatTopBottom = /* 'topb' */ 0x746F7062
+};
+
+/* Enum BMDNotifications - Events that can be subscribed through IDeckLinkNotification */
+
+typedef uint32_t BMDNotifications;
+enum _BMDNotifications {
+ bmdPreferencesChanged = /* 'pref' */ 0x70726566
+};
+
+#if defined(__cplusplus)
+
+// Forward Declarations
+
+class IDeckLinkVideoOutputCallback;
+class IDeckLinkInputCallback;
+class IDeckLinkMemoryAllocator;
+class IDeckLinkAudioOutputCallback;
+class IDeckLinkIterator;
+class IDeckLinkAPIInformation;
+class IDeckLinkOutput;
+class IDeckLinkInput;
+class IDeckLinkVideoFrame;
+class IDeckLinkMutableVideoFrame;
+class IDeckLinkVideoFrame3DExtensions;
+class IDeckLinkVideoInputFrame;
+class IDeckLinkVideoFrameAncillary;
+class IDeckLinkAudioInputPacket;
+class IDeckLinkScreenPreviewCallback;
+class IDeckLinkGLScreenPreviewHelper;
+class IDeckLinkNotificationCallback;
+class IDeckLinkNotification;
+class IDeckLinkAttributes;
+class IDeckLinkKeyer;
+class IDeckLinkVideoConversion;
+class IDeckLinkDeviceNotificationCallback;
+class IDeckLinkDiscovery;
+
+/* Interface IDeckLinkVideoOutputCallback - Frame completion callback. */
+
+class IDeckLinkVideoOutputCallback : public IUnknown
+{
+public:
+ virtual HRESULT ScheduledFrameCompleted (/* in */ IDeckLinkVideoFrame *completedFrame, /* in */ BMDOutputFrameCompletionResult result) = 0;
+ virtual HRESULT ScheduledPlaybackHasStopped (void) = 0;
+
+protected:
+ virtual ~IDeckLinkVideoOutputCallback () {} // call Release method to drop reference count
+};
+
+/* Interface IDeckLinkInputCallback - Frame arrival callback. */
+
+class IDeckLinkInputCallback : public IUnknown
+{
+public:
+ virtual HRESULT VideoInputFormatChanged (/* in */ BMDVideoInputFormatChangedEvents notificationEvents, /* in */ IDeckLinkDisplayMode *newDisplayMode, /* in */ BMDDetectedVideoInputFormatFlags detectedSignalFlags) = 0;
+ virtual HRESULT VideoInputFrameArrived (/* in */ IDeckLinkVideoInputFrame* videoFrame, /* in */ IDeckLinkAudioInputPacket* audioPacket) = 0;
+
+protected:
+ virtual ~IDeckLinkInputCallback () {} // call Release method to drop reference count
+};
+
+/* Interface IDeckLinkMemoryAllocator - Memory allocator for video frames. */
+
+class IDeckLinkMemoryAllocator : public IUnknown
+{
+public:
+ virtual HRESULT AllocateBuffer (/* in */ uint32_t bufferSize, /* out */ void **allocatedBuffer) = 0;
+ virtual HRESULT ReleaseBuffer (/* in */ void *buffer) = 0;
+
+ virtual HRESULT Commit (void) = 0;
+ virtual HRESULT Decommit (void) = 0;
+};
+
+/* Interface IDeckLinkAudioOutputCallback - Optional callback to allow audio samples to be pulled as required. */
+
+class IDeckLinkAudioOutputCallback : public IUnknown
+{
+public:
+ virtual HRESULT RenderAudioSamples (/* in */ bool preroll) = 0;
+};
+
+/* Interface IDeckLinkIterator - enumerates installed DeckLink hardware */
+
+class IDeckLinkIterator : public IUnknown
+{
+public:
+ virtual HRESULT Next (/* out */ IDeckLink **deckLinkInstance) = 0;
+};
+
+/* Interface IDeckLinkAPIInformation - DeckLinkAPI attribute interface */
+
+class IDeckLinkAPIInformation : public IUnknown
+{
+public:
+ virtual HRESULT GetFlag (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ bool *value) = 0;
+ virtual HRESULT GetInt (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ int64_t *value) = 0;
+ virtual HRESULT GetFloat (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ double *value) = 0;
+ virtual HRESULT GetString (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ const char **value) = 0;
+
+protected:
+ virtual ~IDeckLinkAPIInformation () {} // call Release method to drop reference count
+};
+
+/* Interface IDeckLinkOutput - Created by QueryInterface from IDeckLink. */
+
+class IDeckLinkOutput : public IUnknown
+{
+public:
+ virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoOutputFlags flags, /* out */ BMDDisplayModeSupport *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0;
+ virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator **iterator) = 0;
+
+ virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback *previewCallback) = 0;
+
+ /* Video Output */
+
+ virtual HRESULT EnableVideoOutput (/* in */ BMDDisplayMode displayMode, /* in */ BMDVideoOutputFlags flags) = 0;
+ virtual HRESULT DisableVideoOutput (void) = 0;
+
+ virtual HRESULT SetVideoOutputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator *theAllocator) = 0;
+ virtual HRESULT CreateVideoFrame (/* in */ int32_t width, /* in */ int32_t height, /* in */ int32_t rowBytes, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDFrameFlags flags, /* out */ IDeckLinkMutableVideoFrame **outFrame) = 0;
+ virtual HRESULT CreateAncillaryData (/* in */ BMDPixelFormat pixelFormat, /* out */ IDeckLinkVideoFrameAncillary **outBuffer) = 0;
+
+ virtual HRESULT DisplayVideoFrameSync (/* in */ IDeckLinkVideoFrame *theFrame) = 0;
+ virtual HRESULT ScheduleVideoFrame (/* in */ IDeckLinkVideoFrame *theFrame, /* in */ BMDTimeValue displayTime, /* in */ BMDTimeValue displayDuration, /* in */ BMDTimeScale timeScale) = 0;
+ virtual HRESULT SetScheduledFrameCompletionCallback (/* in */ IDeckLinkVideoOutputCallback *theCallback) = 0;
+ virtual HRESULT GetBufferedVideoFrameCount (/* out */ uint32_t *bufferedFrameCount) = 0;
+
+ /* Audio Output */
+
+ virtual HRESULT EnableAudioOutput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount, /* in */ BMDAudioOutputStreamType streamType) = 0;
+ virtual HRESULT DisableAudioOutput (void) = 0;
+
+ virtual HRESULT WriteAudioSamplesSync (/* in */ void *buffer, /* in */ uint32_t sampleFrameCount, /* out */ uint32_t *sampleFramesWritten) = 0;
+
+ virtual HRESULT BeginAudioPreroll (void) = 0;
+ virtual HRESULT EndAudioPreroll (void) = 0;
+ virtual HRESULT ScheduleAudioSamples (/* in */ void *buffer, /* in */ uint32_t sampleFrameCount, /* in */ BMDTimeValue streamTime, /* in */ BMDTimeScale timeScale, /* out */ uint32_t *sampleFramesWritten) = 0;
+
+ virtual HRESULT GetBufferedAudioSampleFrameCount (/* out */ uint32_t *bufferedSampleFrameCount) = 0;
+ virtual HRESULT FlushBufferedAudioSamples (void) = 0;
+
+ virtual HRESULT SetAudioCallback (/* in */ IDeckLinkAudioOutputCallback *theCallback) = 0;
+
+ /* Output Control */
+
+ virtual HRESULT StartScheduledPlayback (/* in */ BMDTimeValue playbackStartTime, /* in */ BMDTimeScale timeScale, /* in */ double playbackSpeed) = 0;
+ virtual HRESULT StopScheduledPlayback (/* in */ BMDTimeValue stopPlaybackAtTime, /* out */ BMDTimeValue *actualStopTime, /* in */ BMDTimeScale timeScale) = 0;
+ virtual HRESULT IsScheduledPlaybackRunning (/* out */ bool *active) = 0;
+ virtual HRESULT GetScheduledStreamTime (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *streamTime, /* out */ double *playbackSpeed) = 0;
+ virtual HRESULT GetReferenceStatus (/* out */ BMDReferenceStatus *referenceStatus) = 0;
+
+ /* Hardware Timing */
+
+ virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *hardwareTime, /* out */ BMDTimeValue *timeInFrame, /* out */ BMDTimeValue *ticksPerFrame) = 0;
+ virtual HRESULT GetFrameCompletionReferenceTimestamp (/* in */ IDeckLinkVideoFrame *theFrame, /* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *frameCompletionTimestamp) = 0;
+
+protected:
+ virtual ~IDeckLinkOutput () {} // call Release method to drop reference count
+};
+
+/* Interface IDeckLinkInput - Created by QueryInterface from IDeckLink. */
+
+class IDeckLinkInput : public IUnknown
+{
+public:
+ virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags, /* out */ BMDDisplayModeSupport *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0;
+ virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator **iterator) = 0;
+
+ virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback *previewCallback) = 0;
+
+ /* Video Input */
+
+ virtual HRESULT EnableVideoInput (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags) = 0;
+ virtual HRESULT DisableVideoInput (void) = 0;
+ virtual HRESULT GetAvailableVideoFrameCount (/* out */ uint32_t *availableFrameCount) = 0;
+ virtual HRESULT SetVideoInputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator *theAllocator) = 0;
+
+ /* Audio Input */
+
+ virtual HRESULT EnableAudioInput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount) = 0;
+ virtual HRESULT DisableAudioInput (void) = 0;
+ virtual HRESULT GetAvailableAudioSampleFrameCount (/* out */ uint32_t *availableSampleFrameCount) = 0;
+
+ /* Input Control */
+
+ virtual HRESULT StartStreams (void) = 0;
+ virtual HRESULT StopStreams (void) = 0;
+ virtual HRESULT PauseStreams (void) = 0;
+ virtual HRESULT FlushStreams (void) = 0;
+ virtual HRESULT SetCallback (/* in */ IDeckLinkInputCallback *theCallback) = 0;
+
+ /* Hardware Timing */
+
+ virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *hardwareTime, /* out */ BMDTimeValue *timeInFrame, /* out */ BMDTimeValue *ticksPerFrame) = 0;
+
+protected:
+ virtual ~IDeckLinkInput () {} // call Release method to drop reference count
+};
+
+/* Interface IDeckLinkVideoFrame - Interface to encapsulate a video frame; can be caller-implemented. */
+
+class IDeckLinkVideoFrame : public IUnknown
+{
+public:
+ virtual long GetWidth (void) = 0;
+ virtual long GetHeight (void) = 0;
+ virtual long GetRowBytes (void) = 0;
+ virtual BMDPixelFormat GetPixelFormat (void) = 0;
+ virtual BMDFrameFlags GetFlags (void) = 0;
+ virtual HRESULT GetBytes (/* out */ void **buffer) = 0;
+
+ virtual HRESULT GetTimecode (/* in */ BMDTimecodeFormat format, /* out */ IDeckLinkTimecode **timecode) = 0;
+ virtual HRESULT GetAncillaryData (/* out */ IDeckLinkVideoFrameAncillary **ancillary) = 0;
+
+protected:
+ virtual ~IDeckLinkVideoFrame () {} // call Release method to drop reference count
+};
+
+/* Interface IDeckLinkMutableVideoFrame - Created by IDeckLinkOutput::CreateVideoFrame. */
+
+class IDeckLinkMutableVideoFrame : public IDeckLinkVideoFrame
+{
+public:
+ virtual HRESULT SetFlags (/* in */ BMDFrameFlags newFlags) = 0;
+
+ virtual HRESULT SetTimecode (/* in */ BMDTimecodeFormat format, /* in */ IDeckLinkTimecode *timecode) = 0;
+ virtual HRESULT SetTimecodeFromComponents (/* in */ BMDTimecodeFormat format, /* in */ uint8_t hours, /* in */ uint8_t minutes, /* in */ uint8_t seconds, /* in */ uint8_t frames, /* in */ BMDTimecodeFlags flags) = 0;
+ virtual HRESULT SetAncillaryData (/* in */ IDeckLinkVideoFrameAncillary *ancillary) = 0;
+ virtual HRESULT SetTimecodeUserBits (/* in */ BMDTimecodeFormat format, /* in */ BMDTimecodeUserBits userBits) = 0;
+
+protected:
+ virtual ~IDeckLinkMutableVideoFrame () {} // call Release method to drop reference count
+};
+
+/* Interface IDeckLinkVideoFrame3DExtensions - Optional interface implemented on IDeckLinkVideoFrame to support 3D frames */
+
+class IDeckLinkVideoFrame3DExtensions : public IUnknown
+{
+public:
+ virtual BMDVideo3DPackingFormat Get3DPackingFormat (void) = 0;
+ virtual HRESULT GetFrameForRightEye (/* out */ IDeckLinkVideoFrame* *rightEyeFrame) = 0;
+
+protected:
+ virtual ~IDeckLinkVideoFrame3DExtensions () {} // call Release method to drop reference count
+};
+
+/* Interface IDeckLinkVideoInputFrame - Provided by the IDeckLinkVideoInput frame arrival callback. */
+
+class IDeckLinkVideoInputFrame : public IDeckLinkVideoFrame
+{
+public:
+ virtual HRESULT GetStreamTime (/* out */ BMDTimeValue *frameTime, /* out */ BMDTimeValue *frameDuration, /* in */ BMDTimeScale timeScale) = 0;
+ virtual HRESULT GetHardwareReferenceTimestamp (/* in */ BMDTimeScale timeScale, /* out */ BMDTimeValue *frameTime, /* out */ BMDTimeValue *frameDuration) = 0;
+
+protected:
+ virtual ~IDeckLinkVideoInputFrame () {} // call Release method to drop reference count
+};
+
+/* Interface IDeckLinkVideoFrameAncillary - Obtained through QueryInterface() on an IDeckLinkVideoFrame object. */
+
+class IDeckLinkVideoFrameAncillary : public IUnknown
+{
+public:
+
+ virtual HRESULT GetBufferForVerticalBlankingLine (/* in */ uint32_t lineNumber, /* out */ void **buffer) = 0;
+ virtual BMDPixelFormat GetPixelFormat (void) = 0;
+ virtual BMDDisplayMode GetDisplayMode (void) = 0;
+
+protected:
+ virtual ~IDeckLinkVideoFrameAncillary () {} // call Release method to drop reference count
+};
+
+/* Interface IDeckLinkAudioInputPacket - Provided by the IDeckLinkInput callback. */
+
+class IDeckLinkAudioInputPacket : public IUnknown
+{
+public:
+ virtual long GetSampleFrameCount (void) = 0;
+ virtual HRESULT GetBytes (/* out */ void **buffer) = 0;
+ virtual HRESULT GetPacketTime (/* out */ BMDTimeValue *packetTime, /* in */ BMDTimeScale timeScale) = 0;
+
+protected:
+ virtual ~IDeckLinkAudioInputPacket () {} // call Release method to drop reference count
+};
+
+/* Interface IDeckLinkScreenPreviewCallback - Screen preview callback */
+
+class IDeckLinkScreenPreviewCallback : public IUnknown
+{
+public:
+ virtual HRESULT DrawFrame (/* in */ IDeckLinkVideoFrame *theFrame) = 0;
+
+protected:
+ virtual ~IDeckLinkScreenPreviewCallback () {} // call Release method to drop reference count
+};
+
+/* Interface IDeckLinkGLScreenPreviewHelper - Created with CoCreateInstance(). */
+
+class IDeckLinkGLScreenPreviewHelper : public IUnknown
+{
+public:
+
+ /* Methods must be called with OpenGL context set */
+
+ virtual HRESULT InitializeGL (void) = 0;
+ virtual HRESULT PaintGL (void) = 0;
+ virtual HRESULT SetFrame (/* in */ IDeckLinkVideoFrame *theFrame) = 0;
+ virtual HRESULT Set3DPreviewFormat (/* in */ BMD3DPreviewFormat previewFormat) = 0;
+
+protected:
+ virtual ~IDeckLinkGLScreenPreviewHelper () {} // call Release method to drop reference count
+};
+
+/* Interface IDeckLinkNotificationCallback - DeckLink Notification Callback Interface */
+
+class IDeckLinkNotificationCallback : public IUnknown
+{
+public:
+ virtual HRESULT Notify (/* in */ BMDNotifications topic, /* in */ uint64_t param1, /* in */ uint64_t param2) = 0;
+};
+
+/* Interface IDeckLinkNotification - DeckLink Notification interface */
+
+class IDeckLinkNotification : public IUnknown
+{
+public:
+ virtual HRESULT Subscribe (/* in */ BMDNotifications topic, /* in */ IDeckLinkNotificationCallback *theCallback) = 0;
+ virtual HRESULT Unsubscribe (/* in */ BMDNotifications topic, /* in */ IDeckLinkNotificationCallback *theCallback) = 0;
+};
+
+/* Interface IDeckLinkAttributes - DeckLink Attribute interface */
+
+class IDeckLinkAttributes : public IUnknown
+{
+public:
+ virtual HRESULT GetFlag (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ bool *value) = 0;
+ virtual HRESULT GetInt (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ int64_t *value) = 0;
+ virtual HRESULT GetFloat (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ double *value) = 0;
+ virtual HRESULT GetString (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ const char **value) = 0;
+
+protected:
+ virtual ~IDeckLinkAttributes () {} // call Release method to drop reference count
+};
+
+/* Interface IDeckLinkKeyer - DeckLink Keyer interface */
+
+class IDeckLinkKeyer : public IUnknown
+{
+public:
+ virtual HRESULT Enable (/* in */ bool isExternal) = 0;
+ virtual HRESULT SetLevel (/* in */ uint8_t level) = 0;
+ virtual HRESULT RampUp (/* in */ uint32_t numberOfFrames) = 0;
+ virtual HRESULT RampDown (/* in */ uint32_t numberOfFrames) = 0;
+ virtual HRESULT Disable (void) = 0;
+
+protected:
+ virtual ~IDeckLinkKeyer () {} // call Release method to drop reference count
+};
+
+/* Interface IDeckLinkVideoConversion - Created with CoCreateInstance(). */
+
+class IDeckLinkVideoConversion : public IUnknown
+{
+public:
+ virtual HRESULT ConvertFrame (/* in */ IDeckLinkVideoFrame* srcFrame, /* in */ IDeckLinkVideoFrame* dstFrame) = 0;
+
+protected:
+ virtual ~IDeckLinkVideoConversion () {} // call Release method to drop reference count
+};
+
+/* Interface IDeckLinkDeviceNotificationCallback - DeckLink device arrival/removal notification callbacks */
+
+class IDeckLinkDeviceNotificationCallback : public IUnknown
+{
+public:
+ virtual HRESULT DeckLinkDeviceArrived (/* in */ IDeckLink* deckLinkDevice) = 0;
+ virtual HRESULT DeckLinkDeviceRemoved (/* in */ IDeckLink* deckLinkDevice) = 0;
+
+protected:
+ virtual ~IDeckLinkDeviceNotificationCallback () {} // call Release method to drop reference count
+};
+
+/* Interface IDeckLinkDiscovery - DeckLink device discovery */
+
+class IDeckLinkDiscovery : public IUnknown
+{
+public:
+ virtual HRESULT InstallDeviceNotifications (/* in */ IDeckLinkDeviceNotificationCallback* deviceNotificationCallback) = 0;
+ virtual HRESULT UninstallDeviceNotifications (void) = 0;
+
+protected:
+ virtual ~IDeckLinkDiscovery () {} // call Release method to drop reference count
+};
+
+/* Functions */
+
+extern "C" {
+
+ IDeckLinkIterator* CreateDeckLinkIteratorInstance (void);
+ IDeckLinkDiscovery* CreateDeckLinkDiscoveryInstance (void);
+ IDeckLinkAPIInformation* CreateDeckLinkAPIInformationInstance (void);
+ IDeckLinkGLScreenPreviewHelper* CreateOpenGLScreenPreviewHelper (void);
+ IDeckLinkVideoConversion* CreateVideoConversionInstance (void);
+ bool IsDeckLinkAPIPresent (void);
+}
+
+
+#endif // defined(__cplusplus)
+#endif /* defined(BMD_DECKLINKAPI_H) */
diff --git a/intern/decklink/linux/DeckLinkAPIConfiguration.h b/intern/decklink/linux/DeckLinkAPIConfiguration.h
new file mode 100644
index 00000000000..9d5bc9a9e1b
--- /dev/null
+++ b/intern/decklink/linux/DeckLinkAPIConfiguration.h
@@ -0,0 +1,192 @@
+/* -LICENSE-START-
+** Copyright (c) 2014 Blackmagic Design
+**
+** Permission is hereby granted, free of charge, to any person or organization
+** obtaining a copy of the software and accompanying documentation covered by
+** this license (the "Software") to use, reproduce, display, distribute,
+** execute, and transmit the Software, and to prepare derivative works of the
+** Software, and to permit third-parties to whom the Software is furnished to
+** do so, all subject to the following:
+**
+** The copyright notices in the Software and this entire statement, including
+** the above license grant, this restriction and the following disclaimer,
+** must be included in all copies of the Software, in whole or in part, and
+** all derivative works of the Software, unless such copies or derivative
+** works are solely in the form of machine-executable object code generated by
+** a source language processor.
+**
+** 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+** DEALINGS IN THE SOFTWARE.
+** -LICENSE-END-
+*/
+
+#ifndef BMD_DECKLINKAPICONFIGURATION_H
+#define BMD_DECKLINKAPICONFIGURATION_H
+
+
+#ifndef BMD_CONST
+ #if defined(_MSC_VER)
+ #define BMD_CONST __declspec(selectany) static const
+ #else
+ #define BMD_CONST static const
+ #endif
+#endif
+
+// Type Declarations
+
+
+// Interface ID Declarations
+
+BMD_CONST REFIID IID_IDeckLinkConfiguration = /* 1E69FCF6-4203-4936-8076-2A9F4CFD50CB */ {0x1E,0x69,0xFC,0xF6,0x42,0x03,0x49,0x36,0x80,0x76,0x2A,0x9F,0x4C,0xFD,0x50,0xCB};
+
+/* Enum BMDDeckLinkConfigurationID - DeckLink Configuration ID */
+
+typedef uint32_t BMDDeckLinkConfigurationID;
+enum _BMDDeckLinkConfigurationID {
+
+ /* Serial port Flags */
+
+ bmdDeckLinkConfigSwapSerialRxTx = /* 'ssrt' */ 0x73737274,
+
+ /* Video Input/Output Flags */
+
+ bmdDeckLinkConfigUse1080pNotPsF = /* 'fpro' */ 0x6670726F,
+
+ /* Video Input/Output Integers */
+
+ bmdDeckLinkConfigHDMI3DPackingFormat = /* '3dpf' */ 0x33647066,
+ bmdDeckLinkConfigBypass = /* 'byps' */ 0x62797073,
+ bmdDeckLinkConfigClockTimingAdjustment = /* 'ctad' */ 0x63746164,
+
+ /* Audio Input/Output Flags */
+
+ bmdDeckLinkConfigAnalogAudioConsumerLevels = /* 'aacl' */ 0x6161636C,
+
+ /* Video output flags */
+
+ bmdDeckLinkConfigFieldFlickerRemoval = /* 'fdfr' */ 0x66646672,
+ bmdDeckLinkConfigHD1080p24ToHD1080i5994Conversion = /* 'to59' */ 0x746F3539,
+ bmdDeckLinkConfig444SDIVideoOutput = /* '444o' */ 0x3434346F,
+ bmdDeckLinkConfigSingleLinkVideoOutput = /* 'sglo' */ 0x73676C6F,
+ bmdDeckLinkConfigBlackVideoOutputDuringCapture = /* 'bvoc' */ 0x62766F63,
+ bmdDeckLinkConfigLowLatencyVideoOutput = /* 'llvo' */ 0x6C6C766F,
+ bmdDeckLinkConfigDownConversionOnAllAnalogOutput = /* 'caao' */ 0x6361616F,
+ bmdDeckLinkConfigSMPTELevelAOutput = /* 'smta' */ 0x736D7461,
+
+ /* Video Output Integers */
+
+ bmdDeckLinkConfigVideoOutputConnection = /* 'vocn' */ 0x766F636E,
+ bmdDeckLinkConfigVideoOutputConversionMode = /* 'vocm' */ 0x766F636D,
+ bmdDeckLinkConfigAnalogVideoOutputFlags = /* 'avof' */ 0x61766F66,
+ bmdDeckLinkConfigReferenceInputTimingOffset = /* 'glot' */ 0x676C6F74,
+ bmdDeckLinkConfigVideoOutputIdleOperation = /* 'voio' */ 0x766F696F,
+ bmdDeckLinkConfigDefaultVideoOutputMode = /* 'dvom' */ 0x64766F6D,
+ bmdDeckLinkConfigDefaultVideoOutputModeFlags = /* 'dvof' */ 0x64766F66,
+
+ /* Video Output Floats */
+
+ bmdDeckLinkConfigVideoOutputComponentLumaGain = /* 'oclg' */ 0x6F636C67,
+ bmdDeckLinkConfigVideoOutputComponentChromaBlueGain = /* 'occb' */ 0x6F636362,
+ bmdDeckLinkConfigVideoOutputComponentChromaRedGain = /* 'occr' */ 0x6F636372,
+ bmdDeckLinkConfigVideoOutputCompositeLumaGain = /* 'oilg' */ 0x6F696C67,
+ bmdDeckLinkConfigVideoOutputCompositeChromaGain = /* 'oicg' */ 0x6F696367,
+ bmdDeckLinkConfigVideoOutputSVideoLumaGain = /* 'oslg' */ 0x6F736C67,
+ bmdDeckLinkConfigVideoOutputSVideoChromaGain = /* 'oscg' */ 0x6F736367,
+
+ /* Video Input Flags */
+
+ bmdDeckLinkConfigVideoInputScanning = /* 'visc' */ 0x76697363, // Applicable to H264 Pro Recorder only
+ bmdDeckLinkConfigUseDedicatedLTCInput = /* 'dltc' */ 0x646C7463, // Use timecode from LTC input instead of SDI stream
+
+ /* Video Input Integers */
+
+ bmdDeckLinkConfigVideoInputConnection = /* 'vicn' */ 0x7669636E,
+ bmdDeckLinkConfigAnalogVideoInputFlags = /* 'avif' */ 0x61766966,
+ bmdDeckLinkConfigVideoInputConversionMode = /* 'vicm' */ 0x7669636D,
+ bmdDeckLinkConfig32PulldownSequenceInitialTimecodeFrame = /* 'pdif' */ 0x70646966,
+ bmdDeckLinkConfigVANCSourceLine1Mapping = /* 'vsl1' */ 0x76736C31,
+ bmdDeckLinkConfigVANCSourceLine2Mapping = /* 'vsl2' */ 0x76736C32,
+ bmdDeckLinkConfigVANCSourceLine3Mapping = /* 'vsl3' */ 0x76736C33,
+ bmdDeckLinkConfigCapturePassThroughMode = /* 'cptm' */ 0x6370746D,
+
+ /* Video Input Floats */
+
+ bmdDeckLinkConfigVideoInputComponentLumaGain = /* 'iclg' */ 0x69636C67,
+ bmdDeckLinkConfigVideoInputComponentChromaBlueGain = /* 'iccb' */ 0x69636362,
+ bmdDeckLinkConfigVideoInputComponentChromaRedGain = /* 'iccr' */ 0x69636372,
+ bmdDeckLinkConfigVideoInputCompositeLumaGain = /* 'iilg' */ 0x69696C67,
+ bmdDeckLinkConfigVideoInputCompositeChromaGain = /* 'iicg' */ 0x69696367,
+ bmdDeckLinkConfigVideoInputSVideoLumaGain = /* 'islg' */ 0x69736C67,
+ bmdDeckLinkConfigVideoInputSVideoChromaGain = /* 'iscg' */ 0x69736367,
+
+ /* Audio Input Integers */
+
+ bmdDeckLinkConfigAudioInputConnection = /* 'aicn' */ 0x6169636E,
+
+ /* Audio Input Floats */
+
+ bmdDeckLinkConfigAnalogAudioInputScaleChannel1 = /* 'ais1' */ 0x61697331,
+ bmdDeckLinkConfigAnalogAudioInputScaleChannel2 = /* 'ais2' */ 0x61697332,
+ bmdDeckLinkConfigAnalogAudioInputScaleChannel3 = /* 'ais3' */ 0x61697333,
+ bmdDeckLinkConfigAnalogAudioInputScaleChannel4 = /* 'ais4' */ 0x61697334,
+ bmdDeckLinkConfigDigitalAudioInputScale = /* 'dais' */ 0x64616973,
+
+ /* Audio Output Integers */
+
+ bmdDeckLinkConfigAudioOutputAESAnalogSwitch = /* 'aoaa' */ 0x616F6161,
+
+ /* Audio Output Floats */
+
+ bmdDeckLinkConfigAnalogAudioOutputScaleChannel1 = /* 'aos1' */ 0x616F7331,
+ bmdDeckLinkConfigAnalogAudioOutputScaleChannel2 = /* 'aos2' */ 0x616F7332,
+ bmdDeckLinkConfigAnalogAudioOutputScaleChannel3 = /* 'aos3' */ 0x616F7333,
+ bmdDeckLinkConfigAnalogAudioOutputScaleChannel4 = /* 'aos4' */ 0x616F7334,
+ bmdDeckLinkConfigDigitalAudioOutputScale = /* 'daos' */ 0x64616F73,
+
+ /* Device Information Strings */
+
+ bmdDeckLinkConfigDeviceInformationLabel = /* 'dila' */ 0x64696C61,
+ bmdDeckLinkConfigDeviceInformationSerialNumber = /* 'disn' */ 0x6469736E,
+ bmdDeckLinkConfigDeviceInformationCompany = /* 'dico' */ 0x6469636F,
+ bmdDeckLinkConfigDeviceInformationPhone = /* 'diph' */ 0x64697068,
+ bmdDeckLinkConfigDeviceInformationEmail = /* 'diem' */ 0x6469656D,
+ bmdDeckLinkConfigDeviceInformationDate = /* 'dida' */ 0x64696461
+};
+
+// Forward Declarations
+
+class IDeckLinkConfiguration;
+
+/* Interface IDeckLinkConfiguration - DeckLink Configuration interface */
+
+class IDeckLinkConfiguration : public IUnknown
+{
+public:
+ virtual HRESULT SetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ bool value) = 0;
+ virtual HRESULT GetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ bool *value) = 0;
+ virtual HRESULT SetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ int64_t value) = 0;
+ virtual HRESULT GetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ int64_t *value) = 0;
+ virtual HRESULT SetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ double value) = 0;
+ virtual HRESULT GetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ double *value) = 0;
+ virtual HRESULT SetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ const char *value) = 0;
+ virtual HRESULT GetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ const char **value) = 0;
+ virtual HRESULT WriteConfigurationToPreferences (void) = 0;
+
+protected:
+ virtual ~IDeckLinkConfiguration () {} // call Release method to drop reference count
+};
+
+/* Functions */
+
+extern "C" {
+
+
+}
+
+
+#endif /* defined(BMD_DECKLINKAPICONFIGURATION_H) */
diff --git a/intern/decklink/linux/DeckLinkAPIDeckControl.h b/intern/decklink/linux/DeckLinkAPIDeckControl.h
new file mode 100644
index 00000000000..b83d013129e
--- /dev/null
+++ b/intern/decklink/linux/DeckLinkAPIDeckControl.h
@@ -0,0 +1,215 @@
+/* -LICENSE-START-
+** Copyright (c) 2014 Blackmagic Design
+**
+** Permission is hereby granted, free of charge, to any person or organization
+** obtaining a copy of the software and accompanying documentation covered by
+** this license (the "Software") to use, reproduce, display, distribute,
+** execute, and transmit the Software, and to prepare derivative works of the
+** Software, and to permit third-parties to whom the Software is furnished to
+** do so, all subject to the following:
+**
+** The copyright notices in the Software and this entire statement, including
+** the above license grant, this restriction and the following disclaimer,
+** must be included in all copies of the Software, in whole or in part, and
+** all derivative works of the Software, unless such copies or derivative
+** works are solely in the form of machine-executable object code generated by
+** a source language processor.
+**
+** 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+** DEALINGS IN THE SOFTWARE.
+** -LICENSE-END-
+*/
+
+#ifndef BMD_DECKLINKAPIDECKCONTROL_H
+#define BMD_DECKLINKAPIDECKCONTROL_H
+
+
+#ifndef BMD_CONST
+ #if defined(_MSC_VER)
+ #define BMD_CONST __declspec(selectany) static const
+ #else
+ #define BMD_CONST static const
+ #endif
+#endif
+
+// Type Declarations
+
+
+// Interface ID Declarations
+
+BMD_CONST REFIID IID_IDeckLinkDeckControlStatusCallback = /* 53436FFB-B434-4906-BADC-AE3060FFE8EF */ {0x53,0x43,0x6F,0xFB,0xB4,0x34,0x49,0x06,0xBA,0xDC,0xAE,0x30,0x60,0xFF,0xE8,0xEF};
+BMD_CONST REFIID IID_IDeckLinkDeckControl = /* 8E1C3ACE-19C7-4E00-8B92-D80431D958BE */ {0x8E,0x1C,0x3A,0xCE,0x19,0xC7,0x4E,0x00,0x8B,0x92,0xD8,0x04,0x31,0xD9,0x58,0xBE};
+
+/* Enum BMDDeckControlMode - DeckControl mode */
+
+typedef uint32_t BMDDeckControlMode;
+enum _BMDDeckControlMode {
+ bmdDeckControlNotOpened = /* 'ntop' */ 0x6E746F70,
+ bmdDeckControlVTRControlMode = /* 'vtrc' */ 0x76747263,
+ bmdDeckControlExportMode = /* 'expm' */ 0x6578706D,
+ bmdDeckControlCaptureMode = /* 'capm' */ 0x6361706D
+};
+
+/* Enum BMDDeckControlEvent - DeckControl event */
+
+typedef uint32_t BMDDeckControlEvent;
+enum _BMDDeckControlEvent {
+ bmdDeckControlAbortedEvent = /* 'abte' */ 0x61627465, // This event is triggered when a capture or edit-to-tape operation is aborted.
+
+ /* Export-To-Tape events */
+
+ bmdDeckControlPrepareForExportEvent = /* 'pfee' */ 0x70666565, // This event is triggered a few frames before reaching the in-point. IDeckLinkInput::StartScheduledPlayback() should be called at this point.
+ bmdDeckControlExportCompleteEvent = /* 'exce' */ 0x65786365, // This event is triggered a few frames after reaching the out-point. At this point, it is safe to stop playback.
+
+ /* Capture events */
+
+ bmdDeckControlPrepareForCaptureEvent = /* 'pfce' */ 0x70666365, // This event is triggered a few frames before reaching the in-point. The serial timecode attached to IDeckLinkVideoInputFrames is now valid.
+ bmdDeckControlCaptureCompleteEvent = /* 'ccev' */ 0x63636576 // This event is triggered a few frames after reaching the out-point.
+};
+
+/* Enum BMDDeckControlVTRControlState - VTR Control state */
+
+typedef uint32_t BMDDeckControlVTRControlState;
+enum _BMDDeckControlVTRControlState {
+ bmdDeckControlNotInVTRControlMode = /* 'nvcm' */ 0x6E76636D,
+ bmdDeckControlVTRControlPlaying = /* 'vtrp' */ 0x76747270,
+ bmdDeckControlVTRControlRecording = /* 'vtrr' */ 0x76747272,
+ bmdDeckControlVTRControlStill = /* 'vtra' */ 0x76747261,
+ bmdDeckControlVTRControlShuttleForward = /* 'vtsf' */ 0x76747366,
+ bmdDeckControlVTRControlShuttleReverse = /* 'vtsr' */ 0x76747372,
+ bmdDeckControlVTRControlJogForward = /* 'vtjf' */ 0x76746A66,
+ bmdDeckControlVTRControlJogReverse = /* 'vtjr' */ 0x76746A72,
+ bmdDeckControlVTRControlStopped = /* 'vtro' */ 0x7674726F
+};
+
+/* Enum BMDDeckControlStatusFlags - Deck Control status flags */
+
+typedef uint32_t BMDDeckControlStatusFlags;
+enum _BMDDeckControlStatusFlags {
+ bmdDeckControlStatusDeckConnected = 1 << 0,
+ bmdDeckControlStatusRemoteMode = 1 << 1,
+ bmdDeckControlStatusRecordInhibited = 1 << 2,
+ bmdDeckControlStatusCassetteOut = 1 << 3
+};
+
+/* Enum BMDDeckControlExportModeOpsFlags - Export mode flags */
+
+typedef uint32_t BMDDeckControlExportModeOpsFlags;
+enum _BMDDeckControlExportModeOpsFlags {
+ bmdDeckControlExportModeInsertVideo = 1 << 0,
+ bmdDeckControlExportModeInsertAudio1 = 1 << 1,
+ bmdDeckControlExportModeInsertAudio2 = 1 << 2,
+ bmdDeckControlExportModeInsertAudio3 = 1 << 3,
+ bmdDeckControlExportModeInsertAudio4 = 1 << 4,
+ bmdDeckControlExportModeInsertAudio5 = 1 << 5,
+ bmdDeckControlExportModeInsertAudio6 = 1 << 6,
+ bmdDeckControlExportModeInsertAudio7 = 1 << 7,
+ bmdDeckControlExportModeInsertAudio8 = 1 << 8,
+ bmdDeckControlExportModeInsertAudio9 = 1 << 9,
+ bmdDeckControlExportModeInsertAudio10 = 1 << 10,
+ bmdDeckControlExportModeInsertAudio11 = 1 << 11,
+ bmdDeckControlExportModeInsertAudio12 = 1 << 12,
+ bmdDeckControlExportModeInsertTimeCode = 1 << 13,
+ bmdDeckControlExportModeInsertAssemble = 1 << 14,
+ bmdDeckControlExportModeInsertPreview = 1 << 15,
+ bmdDeckControlUseManualExport = 1 << 16
+};
+
+/* Enum BMDDeckControlError - Deck Control error */
+
+typedef uint32_t BMDDeckControlError;
+enum _BMDDeckControlError {
+ bmdDeckControlNoError = /* 'noer' */ 0x6E6F6572,
+ bmdDeckControlModeError = /* 'moer' */ 0x6D6F6572,
+ bmdDeckControlMissedInPointError = /* 'mier' */ 0x6D696572,
+ bmdDeckControlDeckTimeoutError = /* 'dter' */ 0x64746572,
+ bmdDeckControlCommandFailedError = /* 'cfer' */ 0x63666572,
+ bmdDeckControlDeviceAlreadyOpenedError = /* 'dalo' */ 0x64616C6F,
+ bmdDeckControlFailedToOpenDeviceError = /* 'fder' */ 0x66646572,
+ bmdDeckControlInLocalModeError = /* 'lmer' */ 0x6C6D6572,
+ bmdDeckControlEndOfTapeError = /* 'eter' */ 0x65746572,
+ bmdDeckControlUserAbortError = /* 'uaer' */ 0x75616572,
+ bmdDeckControlNoTapeInDeckError = /* 'nter' */ 0x6E746572,
+ bmdDeckControlNoVideoFromCardError = /* 'nvfc' */ 0x6E766663,
+ bmdDeckControlNoCommunicationError = /* 'ncom' */ 0x6E636F6D,
+ bmdDeckControlBufferTooSmallError = /* 'btsm' */ 0x6274736D,
+ bmdDeckControlBadChecksumError = /* 'chks' */ 0x63686B73,
+ bmdDeckControlUnknownError = /* 'uner' */ 0x756E6572
+};
+
+// Forward Declarations
+
+class IDeckLinkDeckControlStatusCallback;
+class IDeckLinkDeckControl;
+
+/* Interface IDeckLinkDeckControlStatusCallback - Deck control state change callback. */
+
+class IDeckLinkDeckControlStatusCallback : public IUnknown
+{
+public:
+ virtual HRESULT TimecodeUpdate (/* in */ BMDTimecodeBCD currentTimecode) = 0;
+ virtual HRESULT VTRControlStateChanged (/* in */ BMDDeckControlVTRControlState newState, /* in */ BMDDeckControlError error) = 0;
+ virtual HRESULT DeckControlEventReceived (/* in */ BMDDeckControlEvent event, /* in */ BMDDeckControlError error) = 0;
+ virtual HRESULT DeckControlStatusChanged (/* in */ BMDDeckControlStatusFlags flags, /* in */ uint32_t mask) = 0;
+
+protected:
+ virtual ~IDeckLinkDeckControlStatusCallback () {} // call Release method to drop reference count
+};
+
+/* Interface IDeckLinkDeckControl - Deck Control main interface */
+
+class IDeckLinkDeckControl : public IUnknown
+{
+public:
+ virtual HRESULT Open (/* in */ BMDTimeScale timeScale, /* in */ BMDTimeValue timeValue, /* in */ bool timecodeIsDropFrame, /* out */ BMDDeckControlError *error) = 0;
+ virtual HRESULT Close (/* in */ bool standbyOn) = 0;
+ virtual HRESULT GetCurrentState (/* out */ BMDDeckControlMode *mode, /* out */ BMDDeckControlVTRControlState *vtrControlState, /* out */ BMDDeckControlStatusFlags *flags) = 0;
+ virtual HRESULT SetStandby (/* in */ bool standbyOn) = 0;
+ virtual HRESULT SendCommand (/* in */ uint8_t *inBuffer, /* in */ uint32_t inBufferSize, /* out */ uint8_t *outBuffer, /* out */ uint32_t *outDataSize, /* in */ uint32_t outBufferSize, /* out */ BMDDeckControlError *error) = 0;
+ virtual HRESULT Play (/* out */ BMDDeckControlError *error) = 0;
+ virtual HRESULT Stop (/* out */ BMDDeckControlError *error) = 0;
+ virtual HRESULT TogglePlayStop (/* out */ BMDDeckControlError *error) = 0;
+ virtual HRESULT Eject (/* out */ BMDDeckControlError *error) = 0;
+ virtual HRESULT GoToTimecode (/* in */ BMDTimecodeBCD timecode, /* out */ BMDDeckControlError *error) = 0;
+ virtual HRESULT FastForward (/* in */ bool viewTape, /* out */ BMDDeckControlError *error) = 0;
+ virtual HRESULT Rewind (/* in */ bool viewTape, /* out */ BMDDeckControlError *error) = 0;
+ virtual HRESULT StepForward (/* out */ BMDDeckControlError *error) = 0;
+ virtual HRESULT StepBack (/* out */ BMDDeckControlError *error) = 0;
+ virtual HRESULT Jog (/* in */ double rate, /* out */ BMDDeckControlError *error) = 0;
+ virtual HRESULT Shuttle (/* in */ double rate, /* out */ BMDDeckControlError *error) = 0;
+ virtual HRESULT GetTimecodeString (/* out */ const char **currentTimeCode, /* out */ BMDDeckControlError *error) = 0;
+ virtual HRESULT GetTimecode (/* out */ IDeckLinkTimecode **currentTimecode, /* out */ BMDDeckControlError *error) = 0;
+ virtual HRESULT GetTimecodeBCD (/* out */ BMDTimecodeBCD *currentTimecode, /* out */ BMDDeckControlError *error) = 0;
+ virtual HRESULT SetPreroll (/* in */ uint32_t prerollSeconds) = 0;
+ virtual HRESULT GetPreroll (/* out */ uint32_t *prerollSeconds) = 0;
+ virtual HRESULT SetExportOffset (/* in */ int32_t exportOffsetFields) = 0;
+ virtual HRESULT GetExportOffset (/* out */ int32_t *exportOffsetFields) = 0;
+ virtual HRESULT GetManualExportOffset (/* out */ int32_t *deckManualExportOffsetFields) = 0;
+ virtual HRESULT SetCaptureOffset (/* in */ int32_t captureOffsetFields) = 0;
+ virtual HRESULT GetCaptureOffset (/* out */ int32_t *captureOffsetFields) = 0;
+ virtual HRESULT StartExport (/* in */ BMDTimecodeBCD inTimecode, /* in */ BMDTimecodeBCD outTimecode, /* in */ BMDDeckControlExportModeOpsFlags exportModeOps, /* out */ BMDDeckControlError *error) = 0;
+ virtual HRESULT StartCapture (/* in */ bool useVITC, /* in */ BMDTimecodeBCD inTimecode, /* in */ BMDTimecodeBCD outTimecode, /* out */ BMDDeckControlError *error) = 0;
+ virtual HRESULT GetDeviceID (/* out */ uint16_t *deviceId, /* out */ BMDDeckControlError *error) = 0;
+ virtual HRESULT Abort (void) = 0;
+ virtual HRESULT CrashRecordStart (/* out */ BMDDeckControlError *error) = 0;
+ virtual HRESULT CrashRecordStop (/* out */ BMDDeckControlError *error) = 0;
+ virtual HRESULT SetCallback (/* in */ IDeckLinkDeckControlStatusCallback *callback) = 0;
+
+protected:
+ virtual ~IDeckLinkDeckControl () {} // call Release method to drop reference count
+};
+
+/* Functions */
+
+extern "C" {
+
+
+}
+
+
+#endif /* defined(BMD_DECKLINKAPIDECKCONTROL_H) */
diff --git a/intern/decklink/linux/DeckLinkAPIDiscovery.h b/intern/decklink/linux/DeckLinkAPIDiscovery.h
new file mode 100644
index 00000000000..424d9d54b39
--- /dev/null
+++ b/intern/decklink/linux/DeckLinkAPIDiscovery.h
@@ -0,0 +1,71 @@
+/* -LICENSE-START-
+** Copyright (c) 2014 Blackmagic Design
+**
+** Permission is hereby granted, free of charge, to any person or organization
+** obtaining a copy of the software and accompanying documentation covered by
+** this license (the "Software") to use, reproduce, display, distribute,
+** execute, and transmit the Software, and to prepare derivative works of the
+** Software, and to permit third-parties to whom the Software is furnished to
+** do so, all subject to the following:
+**
+** The copyright notices in the Software and this entire statement, including
+** the above license grant, this restriction and the following disclaimer,
+** must be included in all copies of the Software, in whole or in part, and
+** all derivative works of the Software, unless such copies or derivative
+** works are solely in the form of machine-executable object code generated by
+** a source language processor.
+**
+** 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+** DEALINGS IN THE SOFTWARE.
+** -LICENSE-END-
+*/
+
+#ifndef BMD_DECKLINKAPIDISCOVERY_H
+#define BMD_DECKLINKAPIDISCOVERY_H
+
+
+#ifndef BMD_CONST
+ #if defined(_MSC_VER)
+ #define BMD_CONST __declspec(selectany) static const
+ #else
+ #define BMD_CONST static const
+ #endif
+#endif
+
+// Type Declarations
+
+
+// Interface ID Declarations
+
+BMD_CONST REFIID IID_IDeckLink = /* C418FBDD-0587-48ED-8FE5-640F0A14AF91 */ {0xC4,0x18,0xFB,0xDD,0x05,0x87,0x48,0xED,0x8F,0xE5,0x64,0x0F,0x0A,0x14,0xAF,0x91};
+
+// Forward Declarations
+
+class IDeckLink;
+
+/* Interface IDeckLink - represents a DeckLink device */
+
+class IDeckLink : public IUnknown
+{
+public:
+ virtual HRESULT GetModelName (/* out */ const char **modelName) = 0;
+ virtual HRESULT GetDisplayName (/* out */ const char **displayName) = 0;
+
+protected:
+ virtual ~IDeckLink () {} // call Release method to drop reference count
+};
+
+/* Functions */
+
+extern "C" {
+
+
+}
+
+
+#endif /* defined(BMD_DECKLINKAPIDISCOVERY_H) */
diff --git a/intern/decklink/linux/DeckLinkAPIDispatch.cpp b/intern/decklink/linux/DeckLinkAPIDispatch.cpp
new file mode 100644
index 00000000000..3cf53f109ac
--- /dev/null
+++ b/intern/decklink/linux/DeckLinkAPIDispatch.cpp
@@ -0,0 +1,148 @@
+/* -LICENSE-START-
+** Copyright (c) 2009 Blackmagic Design
+**
+** Permission is hereby granted, free of charge, to any person or organization
+** obtaining a copy of the software and accompanying documentation covered by
+** this license (the "Software") to use, reproduce, display, distribute,
+** execute, and transmit the Software, and to prepare derivative works of the
+** Software, and to permit third-parties to whom the Software is furnished to
+** do so, all subject to the following:
+**
+** The copyright notices in the Software and this entire statement, including
+** the above license grant, this restriction and the following disclaimer,
+** must be included in all copies of the Software, in whole or in part, and
+** all derivative works of the Software, unless such copies or derivative
+** works are solely in the form of machine-executable object code generated by
+** a source language processor.
+**
+** 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+** DEALINGS IN THE SOFTWARE.
+** -LICENSE-END-
+**/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <dlfcn.h>
+#include <ctype.h>
+
+#include "DeckLinkAPI.h"
+
+#define kDeckLinkAPI_Name "libDeckLinkAPI.so"
+#define KDeckLinkPreviewAPI_Name "libDeckLinkPreviewAPI.so"
+
+typedef IDeckLinkIterator* (*CreateIteratorFunc)(void);
+typedef IDeckLinkAPIInformation* (*CreateAPIInformationFunc)(void);
+typedef IDeckLinkGLScreenPreviewHelper* (*CreateOpenGLScreenPreviewHelperFunc)(void);
+typedef IDeckLinkVideoConversion* (*CreateVideoConversionInstanceFunc)(void);
+typedef IDeckLinkDiscovery* (*CreateDeckLinkDiscoveryInstanceFunc)(void);
+
+static pthread_once_t gDeckLinkOnceControl = PTHREAD_ONCE_INIT;
+static pthread_once_t gPreviewOnceControl = PTHREAD_ONCE_INIT;
+
+static bool gLoadedDeckLinkAPI = false;
+
+static CreateIteratorFunc gCreateIteratorFunc = NULL;
+static CreateAPIInformationFunc gCreateAPIInformationFunc = NULL;
+static CreateOpenGLScreenPreviewHelperFunc gCreateOpenGLPreviewFunc = NULL;
+static CreateVideoConversionInstanceFunc gCreateVideoConversionFunc = NULL;
+static CreateDeckLinkDiscoveryInstanceFunc gCreateDeckLinkDiscoveryFunc = NULL;
+
+static void InitDeckLinkAPI (void)
+{
+ void *libraryHandle;
+
+ libraryHandle = dlopen(kDeckLinkAPI_Name, RTLD_NOW|RTLD_GLOBAL);
+ if (!libraryHandle)
+ {
+ fprintf(stderr, "%s\n", dlerror());
+ return;
+ }
+
+ gLoadedDeckLinkAPI = true;
+
+ gCreateIteratorFunc = (CreateIteratorFunc)dlsym(libraryHandle, "CreateDeckLinkIteratorInstance_0002");
+ if (!gCreateIteratorFunc)
+ fprintf(stderr, "%s\n", dlerror());
+ gCreateAPIInformationFunc = (CreateAPIInformationFunc)dlsym(libraryHandle, "CreateDeckLinkAPIInformationInstance_0001");
+ if (!gCreateAPIInformationFunc)
+ fprintf(stderr, "%s\n", dlerror());
+ gCreateVideoConversionFunc = (CreateVideoConversionInstanceFunc)dlsym(libraryHandle, "CreateVideoConversionInstance_0001");
+ if (!gCreateVideoConversionFunc)
+ fprintf(stderr, "%s\n", dlerror());
+ gCreateDeckLinkDiscoveryFunc = (CreateDeckLinkDiscoveryInstanceFunc)dlsym(libraryHandle, "CreateDeckLinkDiscoveryInstance_0001");
+ if (!gCreateDeckLinkDiscoveryFunc)
+ fprintf(stderr, "%s\n", dlerror());
+}
+
+static void InitDeckLinkPreviewAPI (void)
+{
+ void *libraryHandle;
+
+ libraryHandle = dlopen(KDeckLinkPreviewAPI_Name, RTLD_NOW|RTLD_GLOBAL);
+ if (!libraryHandle)
+ {
+ fprintf(stderr, "%s\n", dlerror());
+ return;
+ }
+ gCreateOpenGLPreviewFunc = (CreateOpenGLScreenPreviewHelperFunc)dlsym(libraryHandle, "CreateOpenGLScreenPreviewHelper_0001");
+ if (!gCreateOpenGLPreviewFunc)
+ fprintf(stderr, "%s\n", dlerror());
+}
+
+bool IsDeckLinkAPIPresent (void)
+{
+ // If the DeckLink API dynamic library was successfully loaded, return this knowledge to the caller
+ return gLoadedDeckLinkAPI;
+}
+
+IDeckLinkIterator* CreateDeckLinkIteratorInstance (void)
+{
+ pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
+
+ if (gCreateIteratorFunc == NULL)
+ return NULL;
+ return gCreateIteratorFunc();
+}
+
+IDeckLinkAPIInformation* CreateDeckLinkAPIInformationInstance (void)
+{
+ pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
+
+ if (gCreateAPIInformationFunc == NULL)
+ return NULL;
+ return gCreateAPIInformationFunc();
+}
+
+IDeckLinkGLScreenPreviewHelper* CreateOpenGLScreenPreviewHelper (void)
+{
+ pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
+ pthread_once(&gPreviewOnceControl, InitDeckLinkPreviewAPI);
+
+ if (gCreateOpenGLPreviewFunc == NULL)
+ return NULL;
+ return gCreateOpenGLPreviewFunc();
+}
+
+IDeckLinkVideoConversion* CreateVideoConversionInstance (void)
+{
+ pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
+
+ if (gCreateVideoConversionFunc == NULL)
+ return NULL;
+ return gCreateVideoConversionFunc();
+}
+
+IDeckLinkDiscovery* CreateDeckLinkDiscoveryInstance (void)
+{
+ pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
+
+ if (gCreateDeckLinkDiscoveryFunc == NULL)
+ return NULL;
+ return gCreateDeckLinkDiscoveryFunc();
+}
diff --git a/intern/decklink/linux/DeckLinkAPIModes.h b/intern/decklink/linux/DeckLinkAPIModes.h
new file mode 100644
index 00000000000..394d68c3078
--- /dev/null
+++ b/intern/decklink/linux/DeckLinkAPIModes.h
@@ -0,0 +1,191 @@
+/* -LICENSE-START-
+** Copyright (c) 2014 Blackmagic Design
+**
+** Permission is hereby granted, free of charge, to any person or organization
+** obtaining a copy of the software and accompanying documentation covered by
+** this license (the "Software") to use, reproduce, display, distribute,
+** execute, and transmit the Software, and to prepare derivative works of the
+** Software, and to permit third-parties to whom the Software is furnished to
+** do so, all subject to the following:
+**
+** The copyright notices in the Software and this entire statement, including
+** the above license grant, this restriction and the following disclaimer,
+** must be included in all copies of the Software, in whole or in part, and
+** all derivative works of the Software, unless such copies or derivative
+** works are solely in the form of machine-executable object code generated by
+** a source language processor.
+**
+** 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+** DEALINGS IN THE SOFTWARE.
+** -LICENSE-END-
+*/
+
+#ifndef BMD_DECKLINKAPIMODES_H
+#define BMD_DECKLINKAPIMODES_H
+
+
+#ifndef BMD_CONST
+ #if defined(_MSC_VER)
+ #define BMD_CONST __declspec(selectany) static const
+ #else
+ #define BMD_CONST static const
+ #endif
+#endif
+
+// Type Declarations
+
+
+// Interface ID Declarations
+
+BMD_CONST REFIID IID_IDeckLinkDisplayModeIterator = /* 9C88499F-F601-4021-B80B-032E4EB41C35 */ {0x9C,0x88,0x49,0x9F,0xF6,0x01,0x40,0x21,0xB8,0x0B,0x03,0x2E,0x4E,0xB4,0x1C,0x35};
+BMD_CONST REFIID IID_IDeckLinkDisplayMode = /* 3EB2C1AB-0A3D-4523-A3AD-F40D7FB14E78 */ {0x3E,0xB2,0xC1,0xAB,0x0A,0x3D,0x45,0x23,0xA3,0xAD,0xF4,0x0D,0x7F,0xB1,0x4E,0x78};
+
+/* Enum BMDDisplayMode - Video display modes */
+
+typedef uint32_t BMDDisplayMode;
+enum _BMDDisplayMode {
+
+ /* SD Modes */
+
+ bmdModeNTSC = /* 'ntsc' */ 0x6E747363,
+ bmdModeNTSC2398 = /* 'nt23' */ 0x6E743233, // 3:2 pulldown
+ bmdModePAL = /* 'pal ' */ 0x70616C20,
+ bmdModeNTSCp = /* 'ntsp' */ 0x6E747370,
+ bmdModePALp = /* 'palp' */ 0x70616C70,
+
+ /* HD 1080 Modes */
+
+ bmdModeHD1080p2398 = /* '23ps' */ 0x32337073,
+ bmdModeHD1080p24 = /* '24ps' */ 0x32347073,
+ bmdModeHD1080p25 = /* 'Hp25' */ 0x48703235,
+ bmdModeHD1080p2997 = /* 'Hp29' */ 0x48703239,
+ bmdModeHD1080p30 = /* 'Hp30' */ 0x48703330,
+ bmdModeHD1080i50 = /* 'Hi50' */ 0x48693530,
+ bmdModeHD1080i5994 = /* 'Hi59' */ 0x48693539,
+ bmdModeHD1080i6000 = /* 'Hi60' */ 0x48693630, // N.B. This _really_ is 60.00 Hz.
+ bmdModeHD1080p50 = /* 'Hp50' */ 0x48703530,
+ bmdModeHD1080p5994 = /* 'Hp59' */ 0x48703539,
+ bmdModeHD1080p6000 = /* 'Hp60' */ 0x48703630, // N.B. This _really_ is 60.00 Hz.
+
+ /* HD 720 Modes */
+
+ bmdModeHD720p50 = /* 'hp50' */ 0x68703530,
+ bmdModeHD720p5994 = /* 'hp59' */ 0x68703539,
+ bmdModeHD720p60 = /* 'hp60' */ 0x68703630,
+
+ /* 2k Modes */
+
+ bmdMode2k2398 = /* '2k23' */ 0x326B3233,
+ bmdMode2k24 = /* '2k24' */ 0x326B3234,
+ bmdMode2k25 = /* '2k25' */ 0x326B3235,
+
+ /* DCI Modes (output only) */
+
+ bmdMode2kDCI2398 = /* '2d23' */ 0x32643233,
+ bmdMode2kDCI24 = /* '2d24' */ 0x32643234,
+ bmdMode2kDCI25 = /* '2d25' */ 0x32643235,
+
+ /* 4k Modes */
+
+ bmdMode4K2160p2398 = /* '4k23' */ 0x346B3233,
+ bmdMode4K2160p24 = /* '4k24' */ 0x346B3234,
+ bmdMode4K2160p25 = /* '4k25' */ 0x346B3235,
+ bmdMode4K2160p2997 = /* '4k29' */ 0x346B3239,
+ bmdMode4K2160p30 = /* '4k30' */ 0x346B3330,
+ bmdMode4K2160p50 = /* '4k50' */ 0x346B3530,
+ bmdMode4K2160p5994 = /* '4k59' */ 0x346B3539,
+ bmdMode4K2160p60 = /* '4k60' */ 0x346B3630,
+
+ /* DCI Modes (output only) */
+
+ bmdMode4kDCI2398 = /* '4d23' */ 0x34643233,
+ bmdMode4kDCI24 = /* '4d24' */ 0x34643234,
+ bmdMode4kDCI25 = /* '4d25' */ 0x34643235,
+
+ /* Special Modes */
+
+ bmdModeUnknown = /* 'iunk' */ 0x69756E6B
+};
+
+/* Enum BMDFieldDominance - Video field dominance */
+
+typedef uint32_t BMDFieldDominance;
+enum _BMDFieldDominance {
+ bmdUnknownFieldDominance = 0,
+ bmdLowerFieldFirst = /* 'lowr' */ 0x6C6F7772,
+ bmdUpperFieldFirst = /* 'uppr' */ 0x75707072,
+ bmdProgressiveFrame = /* 'prog' */ 0x70726F67,
+ bmdProgressiveSegmentedFrame = /* 'psf ' */ 0x70736620
+};
+
+/* Enum BMDPixelFormat - Video pixel formats supported for output/input */
+
+typedef uint32_t BMDPixelFormat;
+enum _BMDPixelFormat {
+ bmdFormat8BitYUV = /* '2vuy' */ 0x32767579,
+ bmdFormat10BitYUV = /* 'v210' */ 0x76323130,
+ bmdFormat8BitARGB = 32,
+ bmdFormat8BitBGRA = /* 'BGRA' */ 0x42475241,
+ bmdFormat10BitRGB = /* 'r210' */ 0x72323130, // Big-endian RGB 10-bit per component with SMPTE video levels (64-960). Packed as 2:10:10:10
+ bmdFormat12BitRGB = /* 'R12B' */ 0x52313242, // Big-endian RGB 12-bit per component with full range (0-4095). Packed as 12-bit per component
+ bmdFormat12BitRGBLE = /* 'R12L' */ 0x5231324C, // Little-endian RGB 12-bit per component with full range (0-4095). Packed as 12-bit per component
+ bmdFormat10BitRGBXLE = /* 'R10l' */ 0x5231306C, // Little-endian 10-bit RGB with SMPTE video levels (64-940)
+ bmdFormat10BitRGBX = /* 'R10b' */ 0x52313062 // Big-endian 10-bit RGB with SMPTE video levels (64-940)
+};
+
+/* Enum BMDDisplayModeFlags - Flags to describe the characteristics of an IDeckLinkDisplayMode. */
+
+typedef uint32_t BMDDisplayModeFlags;
+enum _BMDDisplayModeFlags {
+ bmdDisplayModeSupports3D = 1 << 0,
+ bmdDisplayModeColorspaceRec601 = 1 << 1,
+ bmdDisplayModeColorspaceRec709 = 1 << 2
+};
+
+// Forward Declarations
+
+class IDeckLinkDisplayModeIterator;
+class IDeckLinkDisplayMode;
+
+/* Interface IDeckLinkDisplayModeIterator - enumerates over supported input/output display modes. */
+
+class IDeckLinkDisplayModeIterator : public IUnknown
+{
+public:
+ virtual HRESULT Next (/* out */ IDeckLinkDisplayMode **deckLinkDisplayMode) = 0;
+
+protected:
+ virtual ~IDeckLinkDisplayModeIterator () {} // call Release method to drop reference count
+};
+
+/* Interface IDeckLinkDisplayMode - represents a display mode */
+
+class IDeckLinkDisplayMode : public IUnknown
+{
+public:
+ virtual HRESULT GetName (/* out */ const char **name) = 0;
+ virtual BMDDisplayMode GetDisplayMode (void) = 0;
+ virtual long GetWidth (void) = 0;
+ virtual long GetHeight (void) = 0;
+ virtual HRESULT GetFrameRate (/* out */ BMDTimeValue *frameDuration, /* out */ BMDTimeScale *timeScale) = 0;
+ virtual BMDFieldDominance GetFieldDominance (void) = 0;
+ virtual BMDDisplayModeFlags GetFlags (void) = 0;
+
+protected:
+ virtual ~IDeckLinkDisplayMode () {} // call Release method to drop reference count
+};
+
+/* Functions */
+
+extern "C" {
+
+
+}
+
+
+#endif /* defined(BMD_DECKLINKAPIMODES_H) */
diff --git a/intern/decklink/linux/DeckLinkAPITypes.h b/intern/decklink/linux/DeckLinkAPITypes.h
new file mode 100644
index 00000000000..55e015f2a3c
--- /dev/null
+++ b/intern/decklink/linux/DeckLinkAPITypes.h
@@ -0,0 +1,110 @@
+/* -LICENSE-START-
+** Copyright (c) 2014 Blackmagic Design
+**
+** Permission is hereby granted, free of charge, to any person or organization
+** obtaining a copy of the software and accompanying documentation covered by
+** this license (the "Software") to use, reproduce, display, distribute,
+** execute, and transmit the Software, and to prepare derivative works of the
+** Software, and to permit third-parties to whom the Software is furnished to
+** do so, all subject to the following:
+**
+** The copyright notices in the Software and this entire statement, including
+** the above license grant, this restriction and the following disclaimer,
+** must be included in all copies of the Software, in whole or in part, and
+** all derivative works of the Software, unless such copies or derivative
+** works are solely in the form of machine-executable object code generated by
+** a source language processor.
+**
+** 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+** DEALINGS IN THE SOFTWARE.
+** -LICENSE-END-
+*/
+
+#ifndef BMD_DECKLINKAPITYPES_H
+#define BMD_DECKLINKAPITYPES_H
+
+
+#ifndef BMD_CONST
+ #if defined(_MSC_VER)
+ #define BMD_CONST __declspec(selectany) static const
+ #else
+ #define BMD_CONST static const
+ #endif
+#endif
+
+// Type Declarations
+
+typedef int64_t BMDTimeValue;
+typedef int64_t BMDTimeScale;
+typedef uint32_t BMDTimecodeBCD;
+typedef uint32_t BMDTimecodeUserBits;
+
+// Interface ID Declarations
+
+BMD_CONST REFIID IID_IDeckLinkTimecode = /* BC6CFBD3-8317-4325-AC1C-1216391E9340 */ {0xBC,0x6C,0xFB,0xD3,0x83,0x17,0x43,0x25,0xAC,0x1C,0x12,0x16,0x39,0x1E,0x93,0x40};
+
+/* Enum BMDTimecodeFlags - Timecode flags */
+
+typedef uint32_t BMDTimecodeFlags;
+enum _BMDTimecodeFlags {
+ bmdTimecodeFlagDefault = 0,
+ bmdTimecodeIsDropFrame = 1 << 0,
+ bmdTimecodeFieldMark = 1 << 1
+};
+
+/* Enum BMDVideoConnection - Video connection types */
+
+typedef uint32_t BMDVideoConnection;
+enum _BMDVideoConnection {
+ bmdVideoConnectionSDI = 1 << 0,
+ bmdVideoConnectionHDMI = 1 << 1,
+ bmdVideoConnectionOpticalSDI = 1 << 2,
+ bmdVideoConnectionComponent = 1 << 3,
+ bmdVideoConnectionComposite = 1 << 4,
+ bmdVideoConnectionSVideo = 1 << 5
+};
+
+/* Enum BMDAudioConnection - Audio connection types */
+
+typedef uint32_t BMDAudioConnection;
+enum _BMDAudioConnection {
+ bmdAudioConnectionEmbedded = 1 << 0,
+ bmdAudioConnectionAESEBU = 1 << 1,
+ bmdAudioConnectionAnalog = 1 << 2,
+ bmdAudioConnectionAnalogXLR = 1 << 3,
+ bmdAudioConnectionAnalogRCA = 1 << 4
+};
+
+// Forward Declarations
+
+class IDeckLinkTimecode;
+
+/* Interface IDeckLinkTimecode - Used for video frame timecode representation. */
+
+class IDeckLinkTimecode : public IUnknown
+{
+public:
+ virtual BMDTimecodeBCD GetBCD (void) = 0;
+ virtual HRESULT GetComponents (/* out */ uint8_t *hours, /* out */ uint8_t *minutes, /* out */ uint8_t *seconds, /* out */ uint8_t *frames) = 0;
+ virtual HRESULT GetString (/* out */ const char **timecode) = 0;
+ virtual BMDTimecodeFlags GetFlags (void) = 0;
+ virtual HRESULT GetTimecodeUserBits (/* out */ BMDTimecodeUserBits *userBits) = 0;
+
+protected:
+ virtual ~IDeckLinkTimecode () {} // call Release method to drop reference count
+};
+
+/* Functions */
+
+extern "C" {
+
+
+}
+
+
+#endif /* defined(BMD_DECKLINKAPITYPES_H) */
diff --git a/intern/decklink/linux/DeckLinkAPIVersion.h b/intern/decklink/linux/DeckLinkAPIVersion.h
new file mode 100644
index 00000000000..cfcc701c427
--- /dev/null
+++ b/intern/decklink/linux/DeckLinkAPIVersion.h
@@ -0,0 +1,37 @@
+/* -LICENSE-START-
+ * ** Copyright (c) 2014 Blackmagic Design
+ * **
+ * ** Permission is hereby granted, free of charge, to any person or organization
+ * ** obtaining a copy of the software and accompanying documentation covered by
+ * ** this license (the "Software") to use, reproduce, display, distribute,
+ * ** execute, and transmit the Software, and to prepare derivative works of the
+ * ** Software, and to permit third-parties to whom the Software is furnished to
+ * ** do so, all subject to the following:
+ * **
+ * ** The copyright notices in the Software and this entire statement, including
+ * ** the above license grant, this restriction and the following disclaimer,
+ * ** must be included in all copies of the Software, in whole or in part, and
+ * ** all derivative works of the Software, unless such copies or derivative
+ * ** works are solely in the form of machine-executable object code generated by
+ * ** a source language processor.
+ * **
+ * ** 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * ** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * ** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * ** DEALINGS IN THE SOFTWARE.
+ * ** -LICENSE-END-
+ * */
+
+/* DeckLinkAPIVersion.h */
+
+#ifndef __DeckLink_API_Version_h__
+#define __DeckLink_API_Version_h__
+
+#define BLACKMAGIC_DECKLINK_API_VERSION 0x0a040000
+#define BLACKMAGIC_DECKLINK_API_VERSION_STRING "10.4"
+
+#endif // __DeckLink_API_Version_h__
+
diff --git a/intern/decklink/linux/LinuxCOM.h b/intern/decklink/linux/LinuxCOM.h
new file mode 100644
index 00000000000..ee783bbd58f
--- /dev/null
+++ b/intern/decklink/linux/LinuxCOM.h
@@ -0,0 +1,100 @@
+/* -LICENSE-START-
+** Copyright (c) 2009 Blackmagic Design
+**
+** Permission is hereby granted, free of charge, to any person or organization
+** obtaining a copy of the software and accompanying documentation covered by
+** this license (the "Software") to use, reproduce, display, distribute,
+** execute, and transmit the Software, and to prepare derivative works of the
+** Software, and to permit third-parties to whom the Software is furnished to
+** do so, all subject to the following:
+**
+** The copyright notices in the Software and this entire statement, including
+** the above license grant, this restriction and the following disclaimer,
+** must be included in all copies of the Software, in whole or in part, and
+** all derivative works of the Software, unless such copies or derivative
+** works are solely in the form of machine-executable object code generated by
+** a source language processor.
+**
+** 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+** DEALINGS IN THE SOFTWARE.
+** -LICENSE-END-
+*/
+
+#ifndef __LINUX_COM_H_
+#define __LINUX_COM_H_
+
+struct REFIID
+{
+ unsigned char byte0;
+ unsigned char byte1;
+ unsigned char byte2;
+ unsigned char byte3;
+ unsigned char byte4;
+ unsigned char byte5;
+ unsigned char byte6;
+ unsigned char byte7;
+ unsigned char byte8;
+ unsigned char byte9;
+ unsigned char byte10;
+ unsigned char byte11;
+ unsigned char byte12;
+ unsigned char byte13;
+ unsigned char byte14;
+ unsigned char byte15;
+};
+
+typedef REFIID CFUUIDBytes;
+#define CFUUIDGetUUIDBytes(x) x
+
+#define _HRESULT_DEFINED
+typedef int HRESULT;
+typedef unsigned long ULONG;
+typedef void *LPVOID;
+
+#define SUCCEEDED(Status) ((HRESULT)(Status) >= 0)
+#define FAILED(Status) ((HRESULT)(Status)<0)
+
+#define IS_ERROR(Status) ((unsigned long)(Status) >> 31 == SEVERITY_ERROR)
+#define HRESULT_CODE(hr) ((hr) & 0xFFFF)
+#define HRESULT_FACILITY(hr) (((hr) >> 16) & 0x1fff)
+#define HRESULT_SEVERITY(hr) (((hr) >> 31) & 0x1)
+#define SEVERITY_SUCCESS 0
+#define SEVERITY_ERROR 1
+
+#define MAKE_HRESULT(sev,fac,code) ((HRESULT) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code))) )
+
+#define S_OK ((HRESULT)0x00000000L)
+#define S_FALSE ((HRESULT)0x00000001L)
+#define E_UNEXPECTED ((HRESULT)0x8000FFFFL)
+#define E_NOTIMPL ((HRESULT)0x80000001L)
+#define E_OUTOFMEMORY ((HRESULT)0x80000002L)
+#define E_INVALIDARG ((HRESULT)0x80000003L)
+#define E_NOINTERFACE ((HRESULT)0x80000004L)
+#define E_POINTER ((HRESULT)0x80000005L)
+#define E_HANDLE ((HRESULT)0x80000006L)
+#define E_ABORT ((HRESULT)0x80000007L)
+#define E_FAIL ((HRESULT)0x80000008L)
+#define E_ACCESSDENIED ((HRESULT)0x80000009L)
+
+#define STDMETHODCALLTYPE
+
+#define IID_IUnknown (REFIID){0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}
+#define IUnknownUUID IID_IUnknown
+
+#ifdef __cplusplus
+class IUnknown
+{
+ public:
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) = 0;
+ virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0;
+ virtual ULONG STDMETHODCALLTYPE Release(void) = 0;
+};
+#endif
+
+#endif
+
diff --git a/intern/decklink/win/DeckLinkAPI_h.h b/intern/decklink/win/DeckLinkAPI_h.h
new file mode 100644
index 00000000000..1bd80b6dc95
--- /dev/null
+++ b/intern/decklink/win/DeckLinkAPI_h.h
@@ -0,0 +1,13323 @@
+
+
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* at Mon Apr 13 20:57:05 2015
+ */
+/* Compiler settings for ..\..\include\DeckLinkAPI.idl:
+ Oicf, W1, Zp8, env=Win64 (32b run), target_arch=AMD64 8.00.0603
+ protocol : dce , ms_ext, c_ext, robust
+ error checks: allocation ref bounds_check enum stub_data
+ VC __declspec() decoration level:
+ __declspec(uuid()), __declspec(selectany), __declspec(novtable)
+ DECLSPEC_UUID(), MIDL_INTERFACE()
+*/
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+/* verify that the <rpcndr.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __RPCNDR_H_VERSION__
+#error this stub requires an updated version of <rpcndr.h>
+#endif // __RPCNDR_H_VERSION__
+
+
+#ifndef __DeckLinkAPI_h_h__
+#define __DeckLinkAPI_h_h__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+/* Forward Declarations */
+
+#ifndef __IDeckLinkTimecode_FWD_DEFINED__
+#define __IDeckLinkTimecode_FWD_DEFINED__
+typedef interface IDeckLinkTimecode IDeckLinkTimecode;
+
+#endif /* __IDeckLinkTimecode_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkDisplayModeIterator_FWD_DEFINED__
+#define __IDeckLinkDisplayModeIterator_FWD_DEFINED__
+typedef interface IDeckLinkDisplayModeIterator IDeckLinkDisplayModeIterator;
+
+#endif /* __IDeckLinkDisplayModeIterator_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkDisplayMode_FWD_DEFINED__
+#define __IDeckLinkDisplayMode_FWD_DEFINED__
+typedef interface IDeckLinkDisplayMode IDeckLinkDisplayMode;
+
+#endif /* __IDeckLinkDisplayMode_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLink_FWD_DEFINED__
+#define __IDeckLink_FWD_DEFINED__
+typedef interface IDeckLink IDeckLink;
+
+#endif /* __IDeckLink_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkConfiguration_FWD_DEFINED__
+#define __IDeckLinkConfiguration_FWD_DEFINED__
+typedef interface IDeckLinkConfiguration IDeckLinkConfiguration;
+
+#endif /* __IDeckLinkConfiguration_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkDeckControlStatusCallback_FWD_DEFINED__
+#define __IDeckLinkDeckControlStatusCallback_FWD_DEFINED__
+typedef interface IDeckLinkDeckControlStatusCallback IDeckLinkDeckControlStatusCallback;
+
+#endif /* __IDeckLinkDeckControlStatusCallback_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkDeckControl_FWD_DEFINED__
+#define __IDeckLinkDeckControl_FWD_DEFINED__
+typedef interface IDeckLinkDeckControl IDeckLinkDeckControl;
+
+#endif /* __IDeckLinkDeckControl_FWD_DEFINED__ */
+
+
+#ifndef __IBMDStreamingDeviceNotificationCallback_FWD_DEFINED__
+#define __IBMDStreamingDeviceNotificationCallback_FWD_DEFINED__
+typedef interface IBMDStreamingDeviceNotificationCallback IBMDStreamingDeviceNotificationCallback;
+
+#endif /* __IBMDStreamingDeviceNotificationCallback_FWD_DEFINED__ */
+
+
+#ifndef __IBMDStreamingH264InputCallback_FWD_DEFINED__
+#define __IBMDStreamingH264InputCallback_FWD_DEFINED__
+typedef interface IBMDStreamingH264InputCallback IBMDStreamingH264InputCallback;
+
+#endif /* __IBMDStreamingH264InputCallback_FWD_DEFINED__ */
+
+
+#ifndef __IBMDStreamingDiscovery_FWD_DEFINED__
+#define __IBMDStreamingDiscovery_FWD_DEFINED__
+typedef interface IBMDStreamingDiscovery IBMDStreamingDiscovery;
+
+#endif /* __IBMDStreamingDiscovery_FWD_DEFINED__ */
+
+
+#ifndef __IBMDStreamingVideoEncodingMode_FWD_DEFINED__
+#define __IBMDStreamingVideoEncodingMode_FWD_DEFINED__
+typedef interface IBMDStreamingVideoEncodingMode IBMDStreamingVideoEncodingMode;
+
+#endif /* __IBMDStreamingVideoEncodingMode_FWD_DEFINED__ */
+
+
+#ifndef __IBMDStreamingMutableVideoEncodingMode_FWD_DEFINED__
+#define __IBMDStreamingMutableVideoEncodingMode_FWD_DEFINED__
+typedef interface IBMDStreamingMutableVideoEncodingMode IBMDStreamingMutableVideoEncodingMode;
+
+#endif /* __IBMDStreamingMutableVideoEncodingMode_FWD_DEFINED__ */
+
+
+#ifndef __IBMDStreamingVideoEncodingModePresetIterator_FWD_DEFINED__
+#define __IBMDStreamingVideoEncodingModePresetIterator_FWD_DEFINED__
+typedef interface IBMDStreamingVideoEncodingModePresetIterator IBMDStreamingVideoEncodingModePresetIterator;
+
+#endif /* __IBMDStreamingVideoEncodingModePresetIterator_FWD_DEFINED__ */
+
+
+#ifndef __IBMDStreamingDeviceInput_FWD_DEFINED__
+#define __IBMDStreamingDeviceInput_FWD_DEFINED__
+typedef interface IBMDStreamingDeviceInput IBMDStreamingDeviceInput;
+
+#endif /* __IBMDStreamingDeviceInput_FWD_DEFINED__ */
+
+
+#ifndef __IBMDStreamingH264NALPacket_FWD_DEFINED__
+#define __IBMDStreamingH264NALPacket_FWD_DEFINED__
+typedef interface IBMDStreamingH264NALPacket IBMDStreamingH264NALPacket;
+
+#endif /* __IBMDStreamingH264NALPacket_FWD_DEFINED__ */
+
+
+#ifndef __IBMDStreamingAudioPacket_FWD_DEFINED__
+#define __IBMDStreamingAudioPacket_FWD_DEFINED__
+typedef interface IBMDStreamingAudioPacket IBMDStreamingAudioPacket;
+
+#endif /* __IBMDStreamingAudioPacket_FWD_DEFINED__ */
+
+
+#ifndef __IBMDStreamingMPEG2TSPacket_FWD_DEFINED__
+#define __IBMDStreamingMPEG2TSPacket_FWD_DEFINED__
+typedef interface IBMDStreamingMPEG2TSPacket IBMDStreamingMPEG2TSPacket;
+
+#endif /* __IBMDStreamingMPEG2TSPacket_FWD_DEFINED__ */
+
+
+#ifndef __IBMDStreamingH264NALParser_FWD_DEFINED__
+#define __IBMDStreamingH264NALParser_FWD_DEFINED__
+typedef interface IBMDStreamingH264NALParser IBMDStreamingH264NALParser;
+
+#endif /* __IBMDStreamingH264NALParser_FWD_DEFINED__ */
+
+
+#ifndef __CBMDStreamingDiscovery_FWD_DEFINED__
+#define __CBMDStreamingDiscovery_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class CBMDStreamingDiscovery CBMDStreamingDiscovery;
+#else
+typedef struct CBMDStreamingDiscovery CBMDStreamingDiscovery;
+#endif /* __cplusplus */
+
+#endif /* __CBMDStreamingDiscovery_FWD_DEFINED__ */
+
+
+#ifndef __CBMDStreamingH264NALParser_FWD_DEFINED__
+#define __CBMDStreamingH264NALParser_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class CBMDStreamingH264NALParser CBMDStreamingH264NALParser;
+#else
+typedef struct CBMDStreamingH264NALParser CBMDStreamingH264NALParser;
+#endif /* __cplusplus */
+
+#endif /* __CBMDStreamingH264NALParser_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkVideoOutputCallback_FWD_DEFINED__
+#define __IDeckLinkVideoOutputCallback_FWD_DEFINED__
+typedef interface IDeckLinkVideoOutputCallback IDeckLinkVideoOutputCallback;
+
+#endif /* __IDeckLinkVideoOutputCallback_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkInputCallback_FWD_DEFINED__
+#define __IDeckLinkInputCallback_FWD_DEFINED__
+typedef interface IDeckLinkInputCallback IDeckLinkInputCallback;
+
+#endif /* __IDeckLinkInputCallback_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkMemoryAllocator_FWD_DEFINED__
+#define __IDeckLinkMemoryAllocator_FWD_DEFINED__
+typedef interface IDeckLinkMemoryAllocator IDeckLinkMemoryAllocator;
+
+#endif /* __IDeckLinkMemoryAllocator_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkAudioOutputCallback_FWD_DEFINED__
+#define __IDeckLinkAudioOutputCallback_FWD_DEFINED__
+typedef interface IDeckLinkAudioOutputCallback IDeckLinkAudioOutputCallback;
+
+#endif /* __IDeckLinkAudioOutputCallback_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkIterator_FWD_DEFINED__
+#define __IDeckLinkIterator_FWD_DEFINED__
+typedef interface IDeckLinkIterator IDeckLinkIterator;
+
+#endif /* __IDeckLinkIterator_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkAPIInformation_FWD_DEFINED__
+#define __IDeckLinkAPIInformation_FWD_DEFINED__
+typedef interface IDeckLinkAPIInformation IDeckLinkAPIInformation;
+
+#endif /* __IDeckLinkAPIInformation_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkOutput_FWD_DEFINED__
+#define __IDeckLinkOutput_FWD_DEFINED__
+typedef interface IDeckLinkOutput IDeckLinkOutput;
+
+#endif /* __IDeckLinkOutput_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkInput_FWD_DEFINED__
+#define __IDeckLinkInput_FWD_DEFINED__
+typedef interface IDeckLinkInput IDeckLinkInput;
+
+#endif /* __IDeckLinkInput_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkVideoFrame_FWD_DEFINED__
+#define __IDeckLinkVideoFrame_FWD_DEFINED__
+typedef interface IDeckLinkVideoFrame IDeckLinkVideoFrame;
+
+#endif /* __IDeckLinkVideoFrame_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkMutableVideoFrame_FWD_DEFINED__
+#define __IDeckLinkMutableVideoFrame_FWD_DEFINED__
+typedef interface IDeckLinkMutableVideoFrame IDeckLinkMutableVideoFrame;
+
+#endif /* __IDeckLinkMutableVideoFrame_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkVideoFrame3DExtensions_FWD_DEFINED__
+#define __IDeckLinkVideoFrame3DExtensions_FWD_DEFINED__
+typedef interface IDeckLinkVideoFrame3DExtensions IDeckLinkVideoFrame3DExtensions;
+
+#endif /* __IDeckLinkVideoFrame3DExtensions_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkVideoInputFrame_FWD_DEFINED__
+#define __IDeckLinkVideoInputFrame_FWD_DEFINED__
+typedef interface IDeckLinkVideoInputFrame IDeckLinkVideoInputFrame;
+
+#endif /* __IDeckLinkVideoInputFrame_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkVideoFrameAncillary_FWD_DEFINED__
+#define __IDeckLinkVideoFrameAncillary_FWD_DEFINED__
+typedef interface IDeckLinkVideoFrameAncillary IDeckLinkVideoFrameAncillary;
+
+#endif /* __IDeckLinkVideoFrameAncillary_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkAudioInputPacket_FWD_DEFINED__
+#define __IDeckLinkAudioInputPacket_FWD_DEFINED__
+typedef interface IDeckLinkAudioInputPacket IDeckLinkAudioInputPacket;
+
+#endif /* __IDeckLinkAudioInputPacket_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkScreenPreviewCallback_FWD_DEFINED__
+#define __IDeckLinkScreenPreviewCallback_FWD_DEFINED__
+typedef interface IDeckLinkScreenPreviewCallback IDeckLinkScreenPreviewCallback;
+
+#endif /* __IDeckLinkScreenPreviewCallback_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkGLScreenPreviewHelper_FWD_DEFINED__
+#define __IDeckLinkGLScreenPreviewHelper_FWD_DEFINED__
+typedef interface IDeckLinkGLScreenPreviewHelper IDeckLinkGLScreenPreviewHelper;
+
+#endif /* __IDeckLinkGLScreenPreviewHelper_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkDX9ScreenPreviewHelper_FWD_DEFINED__
+#define __IDeckLinkDX9ScreenPreviewHelper_FWD_DEFINED__
+typedef interface IDeckLinkDX9ScreenPreviewHelper IDeckLinkDX9ScreenPreviewHelper;
+
+#endif /* __IDeckLinkDX9ScreenPreviewHelper_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkNotificationCallback_FWD_DEFINED__
+#define __IDeckLinkNotificationCallback_FWD_DEFINED__
+typedef interface IDeckLinkNotificationCallback IDeckLinkNotificationCallback;
+
+#endif /* __IDeckLinkNotificationCallback_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkNotification_FWD_DEFINED__
+#define __IDeckLinkNotification_FWD_DEFINED__
+typedef interface IDeckLinkNotification IDeckLinkNotification;
+
+#endif /* __IDeckLinkNotification_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkAttributes_FWD_DEFINED__
+#define __IDeckLinkAttributes_FWD_DEFINED__
+typedef interface IDeckLinkAttributes IDeckLinkAttributes;
+
+#endif /* __IDeckLinkAttributes_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkKeyer_FWD_DEFINED__
+#define __IDeckLinkKeyer_FWD_DEFINED__
+typedef interface IDeckLinkKeyer IDeckLinkKeyer;
+
+#endif /* __IDeckLinkKeyer_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkVideoConversion_FWD_DEFINED__
+#define __IDeckLinkVideoConversion_FWD_DEFINED__
+typedef interface IDeckLinkVideoConversion IDeckLinkVideoConversion;
+
+#endif /* __IDeckLinkVideoConversion_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkDeviceNotificationCallback_FWD_DEFINED__
+#define __IDeckLinkDeviceNotificationCallback_FWD_DEFINED__
+typedef interface IDeckLinkDeviceNotificationCallback IDeckLinkDeviceNotificationCallback;
+
+#endif /* __IDeckLinkDeviceNotificationCallback_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkDiscovery_FWD_DEFINED__
+#define __IDeckLinkDiscovery_FWD_DEFINED__
+typedef interface IDeckLinkDiscovery IDeckLinkDiscovery;
+
+#endif /* __IDeckLinkDiscovery_FWD_DEFINED__ */
+
+
+#ifndef __CDeckLinkIterator_FWD_DEFINED__
+#define __CDeckLinkIterator_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class CDeckLinkIterator CDeckLinkIterator;
+#else
+typedef struct CDeckLinkIterator CDeckLinkIterator;
+#endif /* __cplusplus */
+
+#endif /* __CDeckLinkIterator_FWD_DEFINED__ */
+
+
+#ifndef __CDeckLinkAPIInformation_FWD_DEFINED__
+#define __CDeckLinkAPIInformation_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class CDeckLinkAPIInformation CDeckLinkAPIInformation;
+#else
+typedef struct CDeckLinkAPIInformation CDeckLinkAPIInformation;
+#endif /* __cplusplus */
+
+#endif /* __CDeckLinkAPIInformation_FWD_DEFINED__ */
+
+
+#ifndef __CDeckLinkGLScreenPreviewHelper_FWD_DEFINED__
+#define __CDeckLinkGLScreenPreviewHelper_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class CDeckLinkGLScreenPreviewHelper CDeckLinkGLScreenPreviewHelper;
+#else
+typedef struct CDeckLinkGLScreenPreviewHelper CDeckLinkGLScreenPreviewHelper;
+#endif /* __cplusplus */
+
+#endif /* __CDeckLinkGLScreenPreviewHelper_FWD_DEFINED__ */
+
+
+#ifndef __CDeckLinkDX9ScreenPreviewHelper_FWD_DEFINED__
+#define __CDeckLinkDX9ScreenPreviewHelper_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class CDeckLinkDX9ScreenPreviewHelper CDeckLinkDX9ScreenPreviewHelper;
+#else
+typedef struct CDeckLinkDX9ScreenPreviewHelper CDeckLinkDX9ScreenPreviewHelper;
+#endif /* __cplusplus */
+
+#endif /* __CDeckLinkDX9ScreenPreviewHelper_FWD_DEFINED__ */
+
+
+#ifndef __CDeckLinkVideoConversion_FWD_DEFINED__
+#define __CDeckLinkVideoConversion_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class CDeckLinkVideoConversion CDeckLinkVideoConversion;
+#else
+typedef struct CDeckLinkVideoConversion CDeckLinkVideoConversion;
+#endif /* __cplusplus */
+
+#endif /* __CDeckLinkVideoConversion_FWD_DEFINED__ */
+
+
+#ifndef __CDeckLinkDiscovery_FWD_DEFINED__
+#define __CDeckLinkDiscovery_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class CDeckLinkDiscovery CDeckLinkDiscovery;
+#else
+typedef struct CDeckLinkDiscovery CDeckLinkDiscovery;
+#endif /* __cplusplus */
+
+#endif /* __CDeckLinkDiscovery_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkConfiguration_v10_2_FWD_DEFINED__
+#define __IDeckLinkConfiguration_v10_2_FWD_DEFINED__
+typedef interface IDeckLinkConfiguration_v10_2 IDeckLinkConfiguration_v10_2;
+
+#endif /* __IDeckLinkConfiguration_v10_2_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkOutput_v9_9_FWD_DEFINED__
+#define __IDeckLinkOutput_v9_9_FWD_DEFINED__
+typedef interface IDeckLinkOutput_v9_9 IDeckLinkOutput_v9_9;
+
+#endif /* __IDeckLinkOutput_v9_9_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkInput_v9_2_FWD_DEFINED__
+#define __IDeckLinkInput_v9_2_FWD_DEFINED__
+typedef interface IDeckLinkInput_v9_2 IDeckLinkInput_v9_2;
+
+#endif /* __IDeckLinkInput_v9_2_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkDeckControlStatusCallback_v8_1_FWD_DEFINED__
+#define __IDeckLinkDeckControlStatusCallback_v8_1_FWD_DEFINED__
+typedef interface IDeckLinkDeckControlStatusCallback_v8_1 IDeckLinkDeckControlStatusCallback_v8_1;
+
+#endif /* __IDeckLinkDeckControlStatusCallback_v8_1_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkDeckControl_v8_1_FWD_DEFINED__
+#define __IDeckLinkDeckControl_v8_1_FWD_DEFINED__
+typedef interface IDeckLinkDeckControl_v8_1 IDeckLinkDeckControl_v8_1;
+
+#endif /* __IDeckLinkDeckControl_v8_1_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLink_v8_0_FWD_DEFINED__
+#define __IDeckLink_v8_0_FWD_DEFINED__
+typedef interface IDeckLink_v8_0 IDeckLink_v8_0;
+
+#endif /* __IDeckLink_v8_0_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkIterator_v8_0_FWD_DEFINED__
+#define __IDeckLinkIterator_v8_0_FWD_DEFINED__
+typedef interface IDeckLinkIterator_v8_0 IDeckLinkIterator_v8_0;
+
+#endif /* __IDeckLinkIterator_v8_0_FWD_DEFINED__ */
+
+
+#ifndef __CDeckLinkIterator_v8_0_FWD_DEFINED__
+#define __CDeckLinkIterator_v8_0_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class CDeckLinkIterator_v8_0 CDeckLinkIterator_v8_0;
+#else
+typedef struct CDeckLinkIterator_v8_0 CDeckLinkIterator_v8_0;
+#endif /* __cplusplus */
+
+#endif /* __CDeckLinkIterator_v8_0_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkDeckControl_v7_9_FWD_DEFINED__
+#define __IDeckLinkDeckControl_v7_9_FWD_DEFINED__
+typedef interface IDeckLinkDeckControl_v7_9 IDeckLinkDeckControl_v7_9;
+
+#endif /* __IDeckLinkDeckControl_v7_9_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkDisplayModeIterator_v7_6_FWD_DEFINED__
+#define __IDeckLinkDisplayModeIterator_v7_6_FWD_DEFINED__
+typedef interface IDeckLinkDisplayModeIterator_v7_6 IDeckLinkDisplayModeIterator_v7_6;
+
+#endif /* __IDeckLinkDisplayModeIterator_v7_6_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkDisplayMode_v7_6_FWD_DEFINED__
+#define __IDeckLinkDisplayMode_v7_6_FWD_DEFINED__
+typedef interface IDeckLinkDisplayMode_v7_6 IDeckLinkDisplayMode_v7_6;
+
+#endif /* __IDeckLinkDisplayMode_v7_6_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkOutput_v7_6_FWD_DEFINED__
+#define __IDeckLinkOutput_v7_6_FWD_DEFINED__
+typedef interface IDeckLinkOutput_v7_6 IDeckLinkOutput_v7_6;
+
+#endif /* __IDeckLinkOutput_v7_6_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkInput_v7_6_FWD_DEFINED__
+#define __IDeckLinkInput_v7_6_FWD_DEFINED__
+typedef interface IDeckLinkInput_v7_6 IDeckLinkInput_v7_6;
+
+#endif /* __IDeckLinkInput_v7_6_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkTimecode_v7_6_FWD_DEFINED__
+#define __IDeckLinkTimecode_v7_6_FWD_DEFINED__
+typedef interface IDeckLinkTimecode_v7_6 IDeckLinkTimecode_v7_6;
+
+#endif /* __IDeckLinkTimecode_v7_6_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkVideoFrame_v7_6_FWD_DEFINED__
+#define __IDeckLinkVideoFrame_v7_6_FWD_DEFINED__
+typedef interface IDeckLinkVideoFrame_v7_6 IDeckLinkVideoFrame_v7_6;
+
+#endif /* __IDeckLinkVideoFrame_v7_6_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkMutableVideoFrame_v7_6_FWD_DEFINED__
+#define __IDeckLinkMutableVideoFrame_v7_6_FWD_DEFINED__
+typedef interface IDeckLinkMutableVideoFrame_v7_6 IDeckLinkMutableVideoFrame_v7_6;
+
+#endif /* __IDeckLinkMutableVideoFrame_v7_6_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkVideoInputFrame_v7_6_FWD_DEFINED__
+#define __IDeckLinkVideoInputFrame_v7_6_FWD_DEFINED__
+typedef interface IDeckLinkVideoInputFrame_v7_6 IDeckLinkVideoInputFrame_v7_6;
+
+#endif /* __IDeckLinkVideoInputFrame_v7_6_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkScreenPreviewCallback_v7_6_FWD_DEFINED__
+#define __IDeckLinkScreenPreviewCallback_v7_6_FWD_DEFINED__
+typedef interface IDeckLinkScreenPreviewCallback_v7_6 IDeckLinkScreenPreviewCallback_v7_6;
+
+#endif /* __IDeckLinkScreenPreviewCallback_v7_6_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkGLScreenPreviewHelper_v7_6_FWD_DEFINED__
+#define __IDeckLinkGLScreenPreviewHelper_v7_6_FWD_DEFINED__
+typedef interface IDeckLinkGLScreenPreviewHelper_v7_6 IDeckLinkGLScreenPreviewHelper_v7_6;
+
+#endif /* __IDeckLinkGLScreenPreviewHelper_v7_6_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkVideoConversion_v7_6_FWD_DEFINED__
+#define __IDeckLinkVideoConversion_v7_6_FWD_DEFINED__
+typedef interface IDeckLinkVideoConversion_v7_6 IDeckLinkVideoConversion_v7_6;
+
+#endif /* __IDeckLinkVideoConversion_v7_6_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkConfiguration_v7_6_FWD_DEFINED__
+#define __IDeckLinkConfiguration_v7_6_FWD_DEFINED__
+typedef interface IDeckLinkConfiguration_v7_6 IDeckLinkConfiguration_v7_6;
+
+#endif /* __IDeckLinkConfiguration_v7_6_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkVideoOutputCallback_v7_6_FWD_DEFINED__
+#define __IDeckLinkVideoOutputCallback_v7_6_FWD_DEFINED__
+typedef interface IDeckLinkVideoOutputCallback_v7_6 IDeckLinkVideoOutputCallback_v7_6;
+
+#endif /* __IDeckLinkVideoOutputCallback_v7_6_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkInputCallback_v7_6_FWD_DEFINED__
+#define __IDeckLinkInputCallback_v7_6_FWD_DEFINED__
+typedef interface IDeckLinkInputCallback_v7_6 IDeckLinkInputCallback_v7_6;
+
+#endif /* __IDeckLinkInputCallback_v7_6_FWD_DEFINED__ */
+
+
+#ifndef __CDeckLinkGLScreenPreviewHelper_v7_6_FWD_DEFINED__
+#define __CDeckLinkGLScreenPreviewHelper_v7_6_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class CDeckLinkGLScreenPreviewHelper_v7_6 CDeckLinkGLScreenPreviewHelper_v7_6;
+#else
+typedef struct CDeckLinkGLScreenPreviewHelper_v7_6 CDeckLinkGLScreenPreviewHelper_v7_6;
+#endif /* __cplusplus */
+
+#endif /* __CDeckLinkGLScreenPreviewHelper_v7_6_FWD_DEFINED__ */
+
+
+#ifndef __CDeckLinkVideoConversion_v7_6_FWD_DEFINED__
+#define __CDeckLinkVideoConversion_v7_6_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class CDeckLinkVideoConversion_v7_6 CDeckLinkVideoConversion_v7_6;
+#else
+typedef struct CDeckLinkVideoConversion_v7_6 CDeckLinkVideoConversion_v7_6;
+#endif /* __cplusplus */
+
+#endif /* __CDeckLinkVideoConversion_v7_6_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkInputCallback_v7_3_FWD_DEFINED__
+#define __IDeckLinkInputCallback_v7_3_FWD_DEFINED__
+typedef interface IDeckLinkInputCallback_v7_3 IDeckLinkInputCallback_v7_3;
+
+#endif /* __IDeckLinkInputCallback_v7_3_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkOutput_v7_3_FWD_DEFINED__
+#define __IDeckLinkOutput_v7_3_FWD_DEFINED__
+typedef interface IDeckLinkOutput_v7_3 IDeckLinkOutput_v7_3;
+
+#endif /* __IDeckLinkOutput_v7_3_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkInput_v7_3_FWD_DEFINED__
+#define __IDeckLinkInput_v7_3_FWD_DEFINED__
+typedef interface IDeckLinkInput_v7_3 IDeckLinkInput_v7_3;
+
+#endif /* __IDeckLinkInput_v7_3_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkVideoInputFrame_v7_3_FWD_DEFINED__
+#define __IDeckLinkVideoInputFrame_v7_3_FWD_DEFINED__
+typedef interface IDeckLinkVideoInputFrame_v7_3 IDeckLinkVideoInputFrame_v7_3;
+
+#endif /* __IDeckLinkVideoInputFrame_v7_3_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkDisplayModeIterator_v7_1_FWD_DEFINED__
+#define __IDeckLinkDisplayModeIterator_v7_1_FWD_DEFINED__
+typedef interface IDeckLinkDisplayModeIterator_v7_1 IDeckLinkDisplayModeIterator_v7_1;
+
+#endif /* __IDeckLinkDisplayModeIterator_v7_1_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkDisplayMode_v7_1_FWD_DEFINED__
+#define __IDeckLinkDisplayMode_v7_1_FWD_DEFINED__
+typedef interface IDeckLinkDisplayMode_v7_1 IDeckLinkDisplayMode_v7_1;
+
+#endif /* __IDeckLinkDisplayMode_v7_1_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkVideoFrame_v7_1_FWD_DEFINED__
+#define __IDeckLinkVideoFrame_v7_1_FWD_DEFINED__
+typedef interface IDeckLinkVideoFrame_v7_1 IDeckLinkVideoFrame_v7_1;
+
+#endif /* __IDeckLinkVideoFrame_v7_1_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkVideoInputFrame_v7_1_FWD_DEFINED__
+#define __IDeckLinkVideoInputFrame_v7_1_FWD_DEFINED__
+typedef interface IDeckLinkVideoInputFrame_v7_1 IDeckLinkVideoInputFrame_v7_1;
+
+#endif /* __IDeckLinkVideoInputFrame_v7_1_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkAudioInputPacket_v7_1_FWD_DEFINED__
+#define __IDeckLinkAudioInputPacket_v7_1_FWD_DEFINED__
+typedef interface IDeckLinkAudioInputPacket_v7_1 IDeckLinkAudioInputPacket_v7_1;
+
+#endif /* __IDeckLinkAudioInputPacket_v7_1_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkVideoOutputCallback_v7_1_FWD_DEFINED__
+#define __IDeckLinkVideoOutputCallback_v7_1_FWD_DEFINED__
+typedef interface IDeckLinkVideoOutputCallback_v7_1 IDeckLinkVideoOutputCallback_v7_1;
+
+#endif /* __IDeckLinkVideoOutputCallback_v7_1_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkInputCallback_v7_1_FWD_DEFINED__
+#define __IDeckLinkInputCallback_v7_1_FWD_DEFINED__
+typedef interface IDeckLinkInputCallback_v7_1 IDeckLinkInputCallback_v7_1;
+
+#endif /* __IDeckLinkInputCallback_v7_1_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkOutput_v7_1_FWD_DEFINED__
+#define __IDeckLinkOutput_v7_1_FWD_DEFINED__
+typedef interface IDeckLinkOutput_v7_1 IDeckLinkOutput_v7_1;
+
+#endif /* __IDeckLinkOutput_v7_1_FWD_DEFINED__ */
+
+
+#ifndef __IDeckLinkInput_v7_1_FWD_DEFINED__
+#define __IDeckLinkInput_v7_1_FWD_DEFINED__
+typedef interface IDeckLinkInput_v7_1 IDeckLinkInput_v7_1;
+
+#endif /* __IDeckLinkInput_v7_1_FWD_DEFINED__ */
+
+
+/* header files for imported files */
+#include "unknwn.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+
+#ifndef __DeckLinkAPI_LIBRARY_DEFINED__
+#define __DeckLinkAPI_LIBRARY_DEFINED__
+
+/* library DeckLinkAPI */
+/* [helpstring][version][uuid] */
+
+typedef LONGLONG BMDTimeValue;
+
+typedef LONGLONG BMDTimeScale;
+
+typedef unsigned int BMDTimecodeBCD;
+
+typedef unsigned int BMDTimecodeUserBits;
+
+typedef unsigned int BMDTimecodeFlags;
+#if 0
+typedef enum _BMDTimecodeFlags BMDTimecodeFlags;
+
+#endif
+/* [v1_enum] */
+enum _BMDTimecodeFlags
+ {
+ bmdTimecodeFlagDefault = 0,
+ bmdTimecodeIsDropFrame = ( 1 << 0 ) ,
+ bmdTimecodeFieldMark = ( 1 << 1 )
+ } ;
+typedef /* [v1_enum] */
+enum _BMDVideoConnection
+ {
+ bmdVideoConnectionSDI = ( 1 << 0 ) ,
+ bmdVideoConnectionHDMI = ( 1 << 1 ) ,
+ bmdVideoConnectionOpticalSDI = ( 1 << 2 ) ,
+ bmdVideoConnectionComponent = ( 1 << 3 ) ,
+ bmdVideoConnectionComposite = ( 1 << 4 ) ,
+ bmdVideoConnectionSVideo = ( 1 << 5 )
+ } BMDVideoConnection;
+
+typedef /* [v1_enum] */
+enum _BMDAudioConnection
+ {
+ bmdAudioConnectionEmbedded = ( 1 << 0 ) ,
+ bmdAudioConnectionAESEBU = ( 1 << 1 ) ,
+ bmdAudioConnectionAnalog = ( 1 << 2 ) ,
+ bmdAudioConnectionAnalogXLR = ( 1 << 3 ) ,
+ bmdAudioConnectionAnalogRCA = ( 1 << 4 )
+ } BMDAudioConnection;
+
+
+typedef unsigned int BMDDisplayModeFlags;
+#if 0
+typedef enum _BMDDisplayModeFlags BMDDisplayModeFlags;
+
+#endif
+typedef /* [v1_enum] */
+enum _BMDDisplayMode
+ {
+ bmdModeNTSC = 0x6e747363,
+ bmdModeNTSC2398 = 0x6e743233,
+ bmdModePAL = 0x70616c20,
+ bmdModeNTSCp = 0x6e747370,
+ bmdModePALp = 0x70616c70,
+ bmdModeHD1080p2398 = 0x32337073,
+ bmdModeHD1080p24 = 0x32347073,
+ bmdModeHD1080p25 = 0x48703235,
+ bmdModeHD1080p2997 = 0x48703239,
+ bmdModeHD1080p30 = 0x48703330,
+ bmdModeHD1080i50 = 0x48693530,
+ bmdModeHD1080i5994 = 0x48693539,
+ bmdModeHD1080i6000 = 0x48693630,
+ bmdModeHD1080p50 = 0x48703530,
+ bmdModeHD1080p5994 = 0x48703539,
+ bmdModeHD1080p6000 = 0x48703630,
+ bmdModeHD720p50 = 0x68703530,
+ bmdModeHD720p5994 = 0x68703539,
+ bmdModeHD720p60 = 0x68703630,
+ bmdMode2k2398 = 0x326b3233,
+ bmdMode2k24 = 0x326b3234,
+ bmdMode2k25 = 0x326b3235,
+ bmdMode2kDCI2398 = 0x32643233,
+ bmdMode2kDCI24 = 0x32643234,
+ bmdMode2kDCI25 = 0x32643235,
+ bmdMode4K2160p2398 = 0x346b3233,
+ bmdMode4K2160p24 = 0x346b3234,
+ bmdMode4K2160p25 = 0x346b3235,
+ bmdMode4K2160p2997 = 0x346b3239,
+ bmdMode4K2160p30 = 0x346b3330,
+ bmdMode4K2160p50 = 0x346b3530,
+ bmdMode4K2160p5994 = 0x346b3539,
+ bmdMode4K2160p60 = 0x346b3630,
+ bmdMode4kDCI2398 = 0x34643233,
+ bmdMode4kDCI24 = 0x34643234,
+ bmdMode4kDCI25 = 0x34643235,
+ bmdModeUnknown = 0x69756e6b
+ } BMDDisplayMode;
+
+typedef /* [v1_enum] */
+enum _BMDFieldDominance
+ {
+ bmdUnknownFieldDominance = 0,
+ bmdLowerFieldFirst = 0x6c6f7772,
+ bmdUpperFieldFirst = 0x75707072,
+ bmdProgressiveFrame = 0x70726f67,
+ bmdProgressiveSegmentedFrame = 0x70736620
+ } BMDFieldDominance;
+
+typedef /* [v1_enum] */
+enum _BMDPixelFormat
+ {
+ bmdFormat8BitYUV = 0x32767579,
+ bmdFormat10BitYUV = 0x76323130,
+ bmdFormat8BitARGB = 32,
+ bmdFormat8BitBGRA = 0x42475241,
+ bmdFormat10BitRGB = 0x72323130,
+ bmdFormat12BitRGB = 0x52313242,
+ bmdFormat12BitRGBLE = 0x5231324c,
+ bmdFormat10BitRGBXLE = 0x5231306c,
+ bmdFormat10BitRGBX = 0x52313062
+ } BMDPixelFormat;
+
+/* [v1_enum] */
+enum _BMDDisplayModeFlags
+ {
+ bmdDisplayModeSupports3D = ( 1 << 0 ) ,
+ bmdDisplayModeColorspaceRec601 = ( 1 << 1 ) ,
+ bmdDisplayModeColorspaceRec709 = ( 1 << 2 )
+ } ;
+
+
+#if 0
+#endif
+
+#if 0
+#endif
+typedef /* [v1_enum] */
+enum _BMDDeckLinkConfigurationID
+ {
+ bmdDeckLinkConfigSwapSerialRxTx = 0x73737274,
+ bmdDeckLinkConfigUse1080pNotPsF = 0x6670726f,
+ bmdDeckLinkConfigHDMI3DPackingFormat = 0x33647066,
+ bmdDeckLinkConfigBypass = 0x62797073,
+ bmdDeckLinkConfigClockTimingAdjustment = 0x63746164,
+ bmdDeckLinkConfigAnalogAudioConsumerLevels = 0x6161636c,
+ bmdDeckLinkConfigFieldFlickerRemoval = 0x66646672,
+ bmdDeckLinkConfigHD1080p24ToHD1080i5994Conversion = 0x746f3539,
+ bmdDeckLinkConfig444SDIVideoOutput = 0x3434346f,
+ bmdDeckLinkConfigSingleLinkVideoOutput = 0x73676c6f,
+ bmdDeckLinkConfigBlackVideoOutputDuringCapture = 0x62766f63,
+ bmdDeckLinkConfigLowLatencyVideoOutput = 0x6c6c766f,
+ bmdDeckLinkConfigDownConversionOnAllAnalogOutput = 0x6361616f,
+ bmdDeckLinkConfigSMPTELevelAOutput = 0x736d7461,
+ bmdDeckLinkConfigVideoOutputConnection = 0x766f636e,
+ bmdDeckLinkConfigVideoOutputConversionMode = 0x766f636d,
+ bmdDeckLinkConfigAnalogVideoOutputFlags = 0x61766f66,
+ bmdDeckLinkConfigReferenceInputTimingOffset = 0x676c6f74,
+ bmdDeckLinkConfigVideoOutputIdleOperation = 0x766f696f,
+ bmdDeckLinkConfigDefaultVideoOutputMode = 0x64766f6d,
+ bmdDeckLinkConfigDefaultVideoOutputModeFlags = 0x64766f66,
+ bmdDeckLinkConfigVideoOutputComponentLumaGain = 0x6f636c67,
+ bmdDeckLinkConfigVideoOutputComponentChromaBlueGain = 0x6f636362,
+ bmdDeckLinkConfigVideoOutputComponentChromaRedGain = 0x6f636372,
+ bmdDeckLinkConfigVideoOutputCompositeLumaGain = 0x6f696c67,
+ bmdDeckLinkConfigVideoOutputCompositeChromaGain = 0x6f696367,
+ bmdDeckLinkConfigVideoOutputSVideoLumaGain = 0x6f736c67,
+ bmdDeckLinkConfigVideoOutputSVideoChromaGain = 0x6f736367,
+ bmdDeckLinkConfigVideoInputScanning = 0x76697363,
+ bmdDeckLinkConfigUseDedicatedLTCInput = 0x646c7463,
+ bmdDeckLinkConfigVideoInputConnection = 0x7669636e,
+ bmdDeckLinkConfigAnalogVideoInputFlags = 0x61766966,
+ bmdDeckLinkConfigVideoInputConversionMode = 0x7669636d,
+ bmdDeckLinkConfig32PulldownSequenceInitialTimecodeFrame = 0x70646966,
+ bmdDeckLinkConfigVANCSourceLine1Mapping = 0x76736c31,
+ bmdDeckLinkConfigVANCSourceLine2Mapping = 0x76736c32,
+ bmdDeckLinkConfigVANCSourceLine3Mapping = 0x76736c33,
+ bmdDeckLinkConfigCapturePassThroughMode = 0x6370746d,
+ bmdDeckLinkConfigVideoInputComponentLumaGain = 0x69636c67,
+ bmdDeckLinkConfigVideoInputComponentChromaBlueGain = 0x69636362,
+ bmdDeckLinkConfigVideoInputComponentChromaRedGain = 0x69636372,
+ bmdDeckLinkConfigVideoInputCompositeLumaGain = 0x69696c67,
+ bmdDeckLinkConfigVideoInputCompositeChromaGain = 0x69696367,
+ bmdDeckLinkConfigVideoInputSVideoLumaGain = 0x69736c67,
+ bmdDeckLinkConfigVideoInputSVideoChromaGain = 0x69736367,
+ bmdDeckLinkConfigAudioInputConnection = 0x6169636e,
+ bmdDeckLinkConfigAnalogAudioInputScaleChannel1 = 0x61697331,
+ bmdDeckLinkConfigAnalogAudioInputScaleChannel2 = 0x61697332,
+ bmdDeckLinkConfigAnalogAudioInputScaleChannel3 = 0x61697333,
+ bmdDeckLinkConfigAnalogAudioInputScaleChannel4 = 0x61697334,
+ bmdDeckLinkConfigDigitalAudioInputScale = 0x64616973,
+ bmdDeckLinkConfigAudioOutputAESAnalogSwitch = 0x616f6161,
+ bmdDeckLinkConfigAnalogAudioOutputScaleChannel1 = 0x616f7331,
+ bmdDeckLinkConfigAnalogAudioOutputScaleChannel2 = 0x616f7332,
+ bmdDeckLinkConfigAnalogAudioOutputScaleChannel3 = 0x616f7333,
+ bmdDeckLinkConfigAnalogAudioOutputScaleChannel4 = 0x616f7334,
+ bmdDeckLinkConfigDigitalAudioOutputScale = 0x64616f73,
+ bmdDeckLinkConfigDeviceInformationLabel = 0x64696c61,
+ bmdDeckLinkConfigDeviceInformationSerialNumber = 0x6469736e,
+ bmdDeckLinkConfigDeviceInformationCompany = 0x6469636f,
+ bmdDeckLinkConfigDeviceInformationPhone = 0x64697068,
+ bmdDeckLinkConfigDeviceInformationEmail = 0x6469656d,
+ bmdDeckLinkConfigDeviceInformationDate = 0x64696461
+ } BMDDeckLinkConfigurationID;
+
+
+typedef unsigned int BMDDeckControlStatusFlags;
+typedef unsigned int BMDDeckControlExportModeOpsFlags;
+#if 0
+typedef enum _BMDDeckControlStatusFlags BMDDeckControlStatusFlags;
+
+typedef enum _BMDDeckControlExportModeOpsFlags BMDDeckControlExportModeOpsFlags;
+
+#endif
+typedef /* [v1_enum] */
+enum _BMDDeckControlMode
+ {
+ bmdDeckControlNotOpened = 0x6e746f70,
+ bmdDeckControlVTRControlMode = 0x76747263,
+ bmdDeckControlExportMode = 0x6578706d,
+ bmdDeckControlCaptureMode = 0x6361706d
+ } BMDDeckControlMode;
+
+typedef /* [v1_enum] */
+enum _BMDDeckControlEvent
+ {
+ bmdDeckControlAbortedEvent = 0x61627465,
+ bmdDeckControlPrepareForExportEvent = 0x70666565,
+ bmdDeckControlExportCompleteEvent = 0x65786365,
+ bmdDeckControlPrepareForCaptureEvent = 0x70666365,
+ bmdDeckControlCaptureCompleteEvent = 0x63636576
+ } BMDDeckControlEvent;
+
+typedef /* [v1_enum] */
+enum _BMDDeckControlVTRControlState
+ {
+ bmdDeckControlNotInVTRControlMode = 0x6e76636d,
+ bmdDeckControlVTRControlPlaying = 0x76747270,
+ bmdDeckControlVTRControlRecording = 0x76747272,
+ bmdDeckControlVTRControlStill = 0x76747261,
+ bmdDeckControlVTRControlShuttleForward = 0x76747366,
+ bmdDeckControlVTRControlShuttleReverse = 0x76747372,
+ bmdDeckControlVTRControlJogForward = 0x76746a66,
+ bmdDeckControlVTRControlJogReverse = 0x76746a72,
+ bmdDeckControlVTRControlStopped = 0x7674726f
+ } BMDDeckControlVTRControlState;
+
+/* [v1_enum] */
+enum _BMDDeckControlStatusFlags
+ {
+ bmdDeckControlStatusDeckConnected = ( 1 << 0 ) ,
+ bmdDeckControlStatusRemoteMode = ( 1 << 1 ) ,
+ bmdDeckControlStatusRecordInhibited = ( 1 << 2 ) ,
+ bmdDeckControlStatusCassetteOut = ( 1 << 3 )
+ } ;
+/* [v1_enum] */
+enum _BMDDeckControlExportModeOpsFlags
+ {
+ bmdDeckControlExportModeInsertVideo = ( 1 << 0 ) ,
+ bmdDeckControlExportModeInsertAudio1 = ( 1 << 1 ) ,
+ bmdDeckControlExportModeInsertAudio2 = ( 1 << 2 ) ,
+ bmdDeckControlExportModeInsertAudio3 = ( 1 << 3 ) ,
+ bmdDeckControlExportModeInsertAudio4 = ( 1 << 4 ) ,
+ bmdDeckControlExportModeInsertAudio5 = ( 1 << 5 ) ,
+ bmdDeckControlExportModeInsertAudio6 = ( 1 << 6 ) ,
+ bmdDeckControlExportModeInsertAudio7 = ( 1 << 7 ) ,
+ bmdDeckControlExportModeInsertAudio8 = ( 1 << 8 ) ,
+ bmdDeckControlExportModeInsertAudio9 = ( 1 << 9 ) ,
+ bmdDeckControlExportModeInsertAudio10 = ( 1 << 10 ) ,
+ bmdDeckControlExportModeInsertAudio11 = ( 1 << 11 ) ,
+ bmdDeckControlExportModeInsertAudio12 = ( 1 << 12 ) ,
+ bmdDeckControlExportModeInsertTimeCode = ( 1 << 13 ) ,
+ bmdDeckControlExportModeInsertAssemble = ( 1 << 14 ) ,
+ bmdDeckControlExportModeInsertPreview = ( 1 << 15 ) ,
+ bmdDeckControlUseManualExport = ( 1 << 16 )
+ } ;
+typedef /* [v1_enum] */
+enum _BMDDeckControlError
+ {
+ bmdDeckControlNoError = 0x6e6f6572,
+ bmdDeckControlModeError = 0x6d6f6572,
+ bmdDeckControlMissedInPointError = 0x6d696572,
+ bmdDeckControlDeckTimeoutError = 0x64746572,
+ bmdDeckControlCommandFailedError = 0x63666572,
+ bmdDeckControlDeviceAlreadyOpenedError = 0x64616c6f,
+ bmdDeckControlFailedToOpenDeviceError = 0x66646572,
+ bmdDeckControlInLocalModeError = 0x6c6d6572,
+ bmdDeckControlEndOfTapeError = 0x65746572,
+ bmdDeckControlUserAbortError = 0x75616572,
+ bmdDeckControlNoTapeInDeckError = 0x6e746572,
+ bmdDeckControlNoVideoFromCardError = 0x6e766663,
+ bmdDeckControlNoCommunicationError = 0x6e636f6d,
+ bmdDeckControlBufferTooSmallError = 0x6274736d,
+ bmdDeckControlBadChecksumError = 0x63686b73,
+ bmdDeckControlUnknownError = 0x756e6572
+ } BMDDeckControlError;
+
+
+
+#if 0
+#endif
+typedef /* [v1_enum] */
+enum _BMDStreamingDeviceMode
+ {
+ bmdStreamingDeviceIdle = 0x69646c65,
+ bmdStreamingDeviceEncoding = 0x656e636f,
+ bmdStreamingDeviceStopping = 0x73746f70,
+ bmdStreamingDeviceUnknown = 0x6d756e6b
+ } BMDStreamingDeviceMode;
+
+typedef /* [v1_enum] */
+enum _BMDStreamingEncodingFrameRate
+ {
+ bmdStreamingEncodedFrameRate50i = 0x65353069,
+ bmdStreamingEncodedFrameRate5994i = 0x65353969,
+ bmdStreamingEncodedFrameRate60i = 0x65363069,
+ bmdStreamingEncodedFrameRate2398p = 0x65323370,
+ bmdStreamingEncodedFrameRate24p = 0x65323470,
+ bmdStreamingEncodedFrameRate25p = 0x65323570,
+ bmdStreamingEncodedFrameRate2997p = 0x65323970,
+ bmdStreamingEncodedFrameRate30p = 0x65333070,
+ bmdStreamingEncodedFrameRate50p = 0x65353070,
+ bmdStreamingEncodedFrameRate5994p = 0x65353970,
+ bmdStreamingEncodedFrameRate60p = 0x65363070
+ } BMDStreamingEncodingFrameRate;
+
+typedef /* [v1_enum] */
+enum _BMDStreamingEncodingSupport
+ {
+ bmdStreamingEncodingModeNotSupported = 0,
+ bmdStreamingEncodingModeSupported = ( bmdStreamingEncodingModeNotSupported + 1 ) ,
+ bmdStreamingEncodingModeSupportedWithChanges = ( bmdStreamingEncodingModeSupported + 1 )
+ } BMDStreamingEncodingSupport;
+
+typedef /* [v1_enum] */
+enum _BMDStreamingVideoCodec
+ {
+ bmdStreamingVideoCodecH264 = 0x48323634
+ } BMDStreamingVideoCodec;
+
+typedef /* [v1_enum] */
+enum _BMDStreamingH264Profile
+ {
+ bmdStreamingH264ProfileHigh = 0x68696768,
+ bmdStreamingH264ProfileMain = 0x6d61696e,
+ bmdStreamingH264ProfileBaseline = 0x62617365
+ } BMDStreamingH264Profile;
+
+typedef /* [v1_enum] */
+enum _BMDStreamingH264Level
+ {
+ bmdStreamingH264Level12 = 0x6c763132,
+ bmdStreamingH264Level13 = 0x6c763133,
+ bmdStreamingH264Level2 = 0x6c763220,
+ bmdStreamingH264Level21 = 0x6c763231,
+ bmdStreamingH264Level22 = 0x6c763232,
+ bmdStreamingH264Level3 = 0x6c763320,
+ bmdStreamingH264Level31 = 0x6c763331,
+ bmdStreamingH264Level32 = 0x6c763332,
+ bmdStreamingH264Level4 = 0x6c763420,
+ bmdStreamingH264Level41 = 0x6c763431,
+ bmdStreamingH264Level42 = 0x6c763432
+ } BMDStreamingH264Level;
+
+typedef /* [v1_enum] */
+enum _BMDStreamingH264EntropyCoding
+ {
+ bmdStreamingH264EntropyCodingCAVLC = 0x45564c43,
+ bmdStreamingH264EntropyCodingCABAC = 0x45424143
+ } BMDStreamingH264EntropyCoding;
+
+typedef /* [v1_enum] */
+enum _BMDStreamingAudioCodec
+ {
+ bmdStreamingAudioCodecAAC = 0x41414320
+ } BMDStreamingAudioCodec;
+
+typedef /* [v1_enum] */
+enum _BMDStreamingEncodingModePropertyID
+ {
+ bmdStreamingEncodingPropertyVideoFrameRate = 0x76667274,
+ bmdStreamingEncodingPropertyVideoBitRateKbps = 0x76627274,
+ bmdStreamingEncodingPropertyH264Profile = 0x68707266,
+ bmdStreamingEncodingPropertyH264Level = 0x686c766c,
+ bmdStreamingEncodingPropertyH264EntropyCoding = 0x68656e74,
+ bmdStreamingEncodingPropertyH264HasBFrames = 0x68426672,
+ bmdStreamingEncodingPropertyAudioCodec = 0x61636463,
+ bmdStreamingEncodingPropertyAudioSampleRate = 0x61737274,
+ bmdStreamingEncodingPropertyAudioChannelCount = 0x61636863,
+ bmdStreamingEncodingPropertyAudioBitRateKbps = 0x61627274
+ } BMDStreamingEncodingModePropertyID;
+
+
+
+
+
+
+
+
+
+
+
+
+typedef unsigned int BMDFrameFlags;
+typedef unsigned int BMDVideoInputFlags;
+typedef unsigned int BMDVideoInputFormatChangedEvents;
+typedef unsigned int BMDDetectedVideoInputFormatFlags;
+typedef unsigned int BMDDeckLinkCapturePassthroughMode;
+typedef unsigned int BMDAnalogVideoFlags;
+typedef unsigned int BMDDeviceBusyState;
+#if 0
+typedef enum _BMDFrameFlags BMDFrameFlags;
+
+typedef enum _BMDVideoInputFlags BMDVideoInputFlags;
+
+typedef enum _BMDVideoInputFormatChangedEvents BMDVideoInputFormatChangedEvents;
+
+typedef enum _BMDDetectedVideoInputFormatFlags BMDDetectedVideoInputFormatFlags;
+
+typedef enum _BMDDeckLinkCapturePassthroughMode BMDDeckLinkCapturePassthroughMode;
+
+typedef enum _BMDAnalogVideoFlags BMDAnalogVideoFlags;
+
+typedef enum _BMDDeviceBusyState BMDDeviceBusyState;
+
+#endif
+typedef /* [v1_enum] */
+enum _BMDVideoOutputFlags
+ {
+ bmdVideoOutputFlagDefault = 0,
+ bmdVideoOutputVANC = ( 1 << 0 ) ,
+ bmdVideoOutputVITC = ( 1 << 1 ) ,
+ bmdVideoOutputRP188 = ( 1 << 2 ) ,
+ bmdVideoOutputDualStream3D = ( 1 << 4 )
+ } BMDVideoOutputFlags;
+
+/* [v1_enum] */
+enum _BMDFrameFlags
+ {
+ bmdFrameFlagDefault = 0,
+ bmdFrameFlagFlipVertical = ( 1 << 0 ) ,
+ bmdFrameHasNoInputSource = ( 1 << 31 )
+ } ;
+/* [v1_enum] */
+enum _BMDVideoInputFlags
+ {
+ bmdVideoInputFlagDefault = 0,
+ bmdVideoInputEnableFormatDetection = ( 1 << 0 ) ,
+ bmdVideoInputDualStream3D = ( 1 << 1 )
+ } ;
+/* [v1_enum] */
+enum _BMDVideoInputFormatChangedEvents
+ {
+ bmdVideoInputDisplayModeChanged = ( 1 << 0 ) ,
+ bmdVideoInputFieldDominanceChanged = ( 1 << 1 ) ,
+ bmdVideoInputColorspaceChanged = ( 1 << 2 )
+ } ;
+/* [v1_enum] */
+enum _BMDDetectedVideoInputFormatFlags
+ {
+ bmdDetectedVideoInputYCbCr422 = ( 1 << 0 ) ,
+ bmdDetectedVideoInputRGB444 = ( 1 << 1 ) ,
+ bmdDetectedVideoInputDualStream3D = ( 1 << 2 )
+ } ;
+/* [v1_enum] */
+enum _BMDDeckLinkCapturePassthroughMode
+ {
+ bmdDeckLinkCapturePassthroughModeDirect = 0x70646972,
+ bmdDeckLinkCapturePassthroughModeCleanSwitch = 0x70636c6e
+ } ;
+typedef /* [v1_enum] */
+enum _BMDOutputFrameCompletionResult
+ {
+ bmdOutputFrameCompleted = 0,
+ bmdOutputFrameDisplayedLate = ( bmdOutputFrameCompleted + 1 ) ,
+ bmdOutputFrameDropped = ( bmdOutputFrameDisplayedLate + 1 ) ,
+ bmdOutputFrameFlushed = ( bmdOutputFrameDropped + 1 )
+ } BMDOutputFrameCompletionResult;
+
+typedef /* [v1_enum] */
+enum _BMDReferenceStatus
+ {
+ bmdReferenceNotSupportedByHardware = ( 1 << 0 ) ,
+ bmdReferenceLocked = ( 1 << 1 )
+ } BMDReferenceStatus;
+
+typedef /* [v1_enum] */
+enum _BMDAudioSampleRate
+ {
+ bmdAudioSampleRate48kHz = 48000
+ } BMDAudioSampleRate;
+
+typedef /* [v1_enum] */
+enum _BMDAudioSampleType
+ {
+ bmdAudioSampleType16bitInteger = 16,
+ bmdAudioSampleType32bitInteger = 32
+ } BMDAudioSampleType;
+
+typedef /* [v1_enum] */
+enum _BMDAudioOutputStreamType
+ {
+ bmdAudioOutputStreamContinuous = 0,
+ bmdAudioOutputStreamContinuousDontResample = ( bmdAudioOutputStreamContinuous + 1 ) ,
+ bmdAudioOutputStreamTimestamped = ( bmdAudioOutputStreamContinuousDontResample + 1 )
+ } BMDAudioOutputStreamType;
+
+typedef /* [v1_enum] */
+enum _BMDDisplayModeSupport
+ {
+ bmdDisplayModeNotSupported = 0,
+ bmdDisplayModeSupported = ( bmdDisplayModeNotSupported + 1 ) ,
+ bmdDisplayModeSupportedWithConversion = ( bmdDisplayModeSupported + 1 )
+ } BMDDisplayModeSupport;
+
+typedef /* [v1_enum] */
+enum _BMDTimecodeFormat
+ {
+ bmdTimecodeRP188VITC1 = 0x72707631,
+ bmdTimecodeRP188VITC2 = 0x72703132,
+ bmdTimecodeRP188LTC = 0x72706c74,
+ bmdTimecodeRP188Any = 0x72703138,
+ bmdTimecodeVITC = 0x76697463,
+ bmdTimecodeVITCField2 = 0x76697432,
+ bmdTimecodeSerial = 0x73657269
+ } BMDTimecodeFormat;
+
+/* [v1_enum] */
+enum _BMDAnalogVideoFlags
+ {
+ bmdAnalogVideoFlagCompositeSetup75 = ( 1 << 0 ) ,
+ bmdAnalogVideoFlagComponentBetacamLevels = ( 1 << 1 )
+ } ;
+typedef /* [v1_enum] */
+enum _BMDAudioOutputAnalogAESSwitch
+ {
+ bmdAudioOutputSwitchAESEBU = 0x61657320,
+ bmdAudioOutputSwitchAnalog = 0x616e6c67
+ } BMDAudioOutputAnalogAESSwitch;
+
+typedef /* [v1_enum] */
+enum _BMDVideoOutputConversionMode
+ {
+ bmdNoVideoOutputConversion = 0x6e6f6e65,
+ bmdVideoOutputLetterboxDownconversion = 0x6c746278,
+ bmdVideoOutputAnamorphicDownconversion = 0x616d7068,
+ bmdVideoOutputHD720toHD1080Conversion = 0x37323063,
+ bmdVideoOutputHardwareLetterboxDownconversion = 0x48576c62,
+ bmdVideoOutputHardwareAnamorphicDownconversion = 0x4857616d,
+ bmdVideoOutputHardwareCenterCutDownconversion = 0x48576363,
+ bmdVideoOutputHardware720p1080pCrossconversion = 0x78636170,
+ bmdVideoOutputHardwareAnamorphic720pUpconversion = 0x75613770,
+ bmdVideoOutputHardwareAnamorphic1080iUpconversion = 0x75613169,
+ bmdVideoOutputHardwareAnamorphic149To720pUpconversion = 0x75343770,
+ bmdVideoOutputHardwareAnamorphic149To1080iUpconversion = 0x75343169,
+ bmdVideoOutputHardwarePillarbox720pUpconversion = 0x75703770,
+ bmdVideoOutputHardwarePillarbox1080iUpconversion = 0x75703169
+ } BMDVideoOutputConversionMode;
+
+typedef /* [v1_enum] */
+enum _BMDVideoInputConversionMode
+ {
+ bmdNoVideoInputConversion = 0x6e6f6e65,
+ bmdVideoInputLetterboxDownconversionFromHD1080 = 0x31306c62,
+ bmdVideoInputAnamorphicDownconversionFromHD1080 = 0x3130616d,
+ bmdVideoInputLetterboxDownconversionFromHD720 = 0x37326c62,
+ bmdVideoInputAnamorphicDownconversionFromHD720 = 0x3732616d,
+ bmdVideoInputLetterboxUpconversion = 0x6c627570,
+ bmdVideoInputAnamorphicUpconversion = 0x616d7570
+ } BMDVideoInputConversionMode;
+
+typedef /* [v1_enum] */
+enum _BMDVideo3DPackingFormat
+ {
+ bmdVideo3DPackingSidebySideHalf = 0x73627368,
+ bmdVideo3DPackingLinebyLine = 0x6c62796c,
+ bmdVideo3DPackingTopAndBottom = 0x7461626f,
+ bmdVideo3DPackingFramePacking = 0x6672706b,
+ bmdVideo3DPackingLeftOnly = 0x6c656674,
+ bmdVideo3DPackingRightOnly = 0x72696768
+ } BMDVideo3DPackingFormat;
+
+typedef /* [v1_enum] */
+enum _BMDIdleVideoOutputOperation
+ {
+ bmdIdleVideoOutputBlack = 0x626c6163,
+ bmdIdleVideoOutputLastFrame = 0x6c616661,
+ bmdIdleVideoOutputDesktop = 0x6465736b
+ } BMDIdleVideoOutputOperation;
+
+typedef /* [v1_enum] */
+enum _BMDDeckLinkAttributeID
+ {
+ BMDDeckLinkSupportsInternalKeying = 0x6b657969,
+ BMDDeckLinkSupportsExternalKeying = 0x6b657965,
+ BMDDeckLinkSupportsHDKeying = 0x6b657968,
+ BMDDeckLinkSupportsInputFormatDetection = 0x696e6664,
+ BMDDeckLinkHasReferenceInput = 0x6872696e,
+ BMDDeckLinkHasSerialPort = 0x68737074,
+ BMDDeckLinkHasAnalogVideoOutputGain = 0x61766f67,
+ BMDDeckLinkCanOnlyAdjustOverallVideoOutputGain = 0x6f766f67,
+ BMDDeckLinkHasVideoInputAntiAliasingFilter = 0x6161666c,
+ BMDDeckLinkHasBypass = 0x62797073,
+ BMDDeckLinkSupportsDesktopDisplay = 0x65787464,
+ BMDDeckLinkSupportsClockTimingAdjustment = 0x63746164,
+ BMDDeckLinkSupportsFullDuplex = 0x66647570,
+ BMDDeckLinkSupportsFullFrameReferenceInputTimingOffset = 0x6672696e,
+ BMDDeckLinkSupportsSMPTELevelAOutput = 0x6c766c61,
+ BMDDeckLinkSupportsDualLinkSDI = 0x73646c73,
+ BMDDeckLinkSupportsIdleOutput = 0x69646f75,
+ BMDDeckLinkMaximumAudioChannels = 0x6d616368,
+ BMDDeckLinkMaximumAnalogAudioChannels = 0x61616368,
+ BMDDeckLinkNumberOfSubDevices = 0x6e736264,
+ BMDDeckLinkSubDeviceIndex = 0x73756269,
+ BMDDeckLinkPersistentID = 0x70656964,
+ BMDDeckLinkTopologicalID = 0x746f6964,
+ BMDDeckLinkVideoOutputConnections = 0x766f636e,
+ BMDDeckLinkVideoInputConnections = 0x7669636e,
+ BMDDeckLinkAudioOutputConnections = 0x616f636e,
+ BMDDeckLinkAudioInputConnections = 0x6169636e,
+ BMDDeckLinkDeviceBusyState = 0x64627374,
+ BMDDeckLinkVideoIOSupport = 0x76696f73,
+ BMDDeckLinkVideoInputGainMinimum = 0x7669676d,
+ BMDDeckLinkVideoInputGainMaximum = 0x76696778,
+ BMDDeckLinkVideoOutputGainMinimum = 0x766f676d,
+ BMDDeckLinkVideoOutputGainMaximum = 0x766f6778,
+ BMDDeckLinkSerialPortDeviceName = 0x736c706e
+ } BMDDeckLinkAttributeID;
+
+typedef /* [v1_enum] */
+enum _BMDDeckLinkAPIInformationID
+ {
+ BMDDeckLinkAPIVersion = 0x76657273
+ } BMDDeckLinkAPIInformationID;
+
+/* [v1_enum] */
+enum _BMDDeviceBusyState
+ {
+ bmdDeviceCaptureBusy = ( 1 << 0 ) ,
+ bmdDevicePlaybackBusy = ( 1 << 1 ) ,
+ bmdDeviceSerialPortBusy = ( 1 << 2 )
+ } ;
+typedef /* [v1_enum] */
+enum _BMDVideoIOSupport
+ {
+ bmdDeviceSupportsCapture = ( 1 << 0 ) ,
+ bmdDeviceSupportsPlayback = ( 1 << 1 )
+ } BMDVideoIOSupport;
+
+typedef /* [v1_enum] */
+enum _BMD3DPreviewFormat
+ {
+ bmd3DPreviewFormatDefault = 0x64656661,
+ bmd3DPreviewFormatLeftOnly = 0x6c656674,
+ bmd3DPreviewFormatRightOnly = 0x72696768,
+ bmd3DPreviewFormatSideBySide = 0x73696465,
+ bmd3DPreviewFormatTopBottom = 0x746f7062
+ } BMD3DPreviewFormat;
+
+typedef /* [v1_enum] */
+enum _BMDNotifications
+ {
+ bmdPreferencesChanged = 0x70726566
+ } BMDNotifications;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+typedef /* [v1_enum] */
+enum _BMDDeckLinkConfigurationID_v10_2
+ {
+ bmdDeckLinkConfig3GBpsVideoOutput_v10_2 = 0x33676273
+ } BMDDeckLinkConfigurationID_v10_2;
+
+typedef /* [v1_enum] */
+enum _BMDAudioConnection_v10_2
+ {
+ bmdAudioConnectionEmbedded_v10_2 = 0x656d6264,
+ bmdAudioConnectionAESEBU_v10_2 = 0x61657320,
+ bmdAudioConnectionAnalog_v10_2 = 0x616e6c67,
+ bmdAudioConnectionAnalogXLR_v10_2 = 0x61786c72,
+ bmdAudioConnectionAnalogRCA_v10_2 = 0x61726361
+ } BMDAudioConnection_v10_2;
+
+
+typedef /* [v1_enum] */
+enum _BMDDeckControlVTRControlState_v8_1
+ {
+ bmdDeckControlNotInVTRControlMode_v8_1 = 0x6e76636d,
+ bmdDeckControlVTRControlPlaying_v8_1 = 0x76747270,
+ bmdDeckControlVTRControlRecording_v8_1 = 0x76747272,
+ bmdDeckControlVTRControlStill_v8_1 = 0x76747261,
+ bmdDeckControlVTRControlSeeking_v8_1 = 0x76747273,
+ bmdDeckControlVTRControlStopped_v8_1 = 0x7674726f
+ } BMDDeckControlVTRControlState_v8_1;
+
+
+
+typedef /* [v1_enum] */
+enum _BMDVideoConnection_v7_6
+ {
+ bmdVideoConnectionSDI_v7_6 = 0x73646920,
+ bmdVideoConnectionHDMI_v7_6 = 0x68646d69,
+ bmdVideoConnectionOpticalSDI_v7_6 = 0x6f707469,
+ bmdVideoConnectionComponent_v7_6 = 0x63706e74,
+ bmdVideoConnectionComposite_v7_6 = 0x636d7374,
+ bmdVideoConnectionSVideo_v7_6 = 0x73766964
+ } BMDVideoConnection_v7_6;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+EXTERN_C const IID LIBID_DeckLinkAPI;
+
+#ifndef __IDeckLinkTimecode_INTERFACE_DEFINED__
+#define __IDeckLinkTimecode_INTERFACE_DEFINED__
+
+/* interface IDeckLinkTimecode */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkTimecode;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("BC6CFBD3-8317-4325-AC1C-1216391E9340")
+ IDeckLinkTimecode : public IUnknown
+ {
+ public:
+ virtual BMDTimecodeBCD STDMETHODCALLTYPE GetBCD( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetComponents(
+ /* [out] */ unsigned char *hours,
+ /* [out] */ unsigned char *minutes,
+ /* [out] */ unsigned char *seconds,
+ /* [out] */ unsigned char *frames) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetString(
+ /* [out] */ BSTR *timecode) = 0;
+
+ virtual BMDTimecodeFlags STDMETHODCALLTYPE GetFlags( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTimecodeUserBits(
+ /* [out] */ BMDTimecodeUserBits *userBits) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkTimecodeVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkTimecode * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkTimecode * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkTimecode * This);
+
+ BMDTimecodeBCD ( STDMETHODCALLTYPE *GetBCD )(
+ IDeckLinkTimecode * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetComponents )(
+ IDeckLinkTimecode * This,
+ /* [out] */ unsigned char *hours,
+ /* [out] */ unsigned char *minutes,
+ /* [out] */ unsigned char *seconds,
+ /* [out] */ unsigned char *frames);
+
+ HRESULT ( STDMETHODCALLTYPE *GetString )(
+ IDeckLinkTimecode * This,
+ /* [out] */ BSTR *timecode);
+
+ BMDTimecodeFlags ( STDMETHODCALLTYPE *GetFlags )(
+ IDeckLinkTimecode * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTimecodeUserBits )(
+ IDeckLinkTimecode * This,
+ /* [out] */ BMDTimecodeUserBits *userBits);
+
+ END_INTERFACE
+ } IDeckLinkTimecodeVtbl;
+
+ interface IDeckLinkTimecode
+ {
+ CONST_VTBL struct IDeckLinkTimecodeVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkTimecode_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkTimecode_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkTimecode_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkTimecode_GetBCD(This) \
+ ( (This)->lpVtbl -> GetBCD(This) )
+
+#define IDeckLinkTimecode_GetComponents(This,hours,minutes,seconds,frames) \
+ ( (This)->lpVtbl -> GetComponents(This,hours,minutes,seconds,frames) )
+
+#define IDeckLinkTimecode_GetString(This,timecode) \
+ ( (This)->lpVtbl -> GetString(This,timecode) )
+
+#define IDeckLinkTimecode_GetFlags(This) \
+ ( (This)->lpVtbl -> GetFlags(This) )
+
+#define IDeckLinkTimecode_GetTimecodeUserBits(This,userBits) \
+ ( (This)->lpVtbl -> GetTimecodeUserBits(This,userBits) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkTimecode_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkDisplayModeIterator_INTERFACE_DEFINED__
+#define __IDeckLinkDisplayModeIterator_INTERFACE_DEFINED__
+
+/* interface IDeckLinkDisplayModeIterator */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkDisplayModeIterator;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("9C88499F-F601-4021-B80B-032E4EB41C35")
+ IDeckLinkDisplayModeIterator : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [out] */ IDeckLinkDisplayMode **deckLinkDisplayMode) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkDisplayModeIteratorVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkDisplayModeIterator * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkDisplayModeIterator * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkDisplayModeIterator * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ IDeckLinkDisplayModeIterator * This,
+ /* [out] */ IDeckLinkDisplayMode **deckLinkDisplayMode);
+
+ END_INTERFACE
+ } IDeckLinkDisplayModeIteratorVtbl;
+
+ interface IDeckLinkDisplayModeIterator
+ {
+ CONST_VTBL struct IDeckLinkDisplayModeIteratorVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkDisplayModeIterator_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkDisplayModeIterator_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkDisplayModeIterator_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkDisplayModeIterator_Next(This,deckLinkDisplayMode) \
+ ( (This)->lpVtbl -> Next(This,deckLinkDisplayMode) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkDisplayModeIterator_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkDisplayMode_INTERFACE_DEFINED__
+#define __IDeckLinkDisplayMode_INTERFACE_DEFINED__
+
+/* interface IDeckLinkDisplayMode */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkDisplayMode;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("3EB2C1AB-0A3D-4523-A3AD-F40D7FB14E78")
+ IDeckLinkDisplayMode : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetName(
+ /* [out] */ BSTR *name) = 0;
+
+ virtual BMDDisplayMode STDMETHODCALLTYPE GetDisplayMode( void) = 0;
+
+ virtual long STDMETHODCALLTYPE GetWidth( void) = 0;
+
+ virtual long STDMETHODCALLTYPE GetHeight( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFrameRate(
+ /* [out] */ BMDTimeValue *frameDuration,
+ /* [out] */ BMDTimeScale *timeScale) = 0;
+
+ virtual BMDFieldDominance STDMETHODCALLTYPE GetFieldDominance( void) = 0;
+
+ virtual BMDDisplayModeFlags STDMETHODCALLTYPE GetFlags( void) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkDisplayModeVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkDisplayMode * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkDisplayMode * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkDisplayMode * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ IDeckLinkDisplayMode * This,
+ /* [out] */ BSTR *name);
+
+ BMDDisplayMode ( STDMETHODCALLTYPE *GetDisplayMode )(
+ IDeckLinkDisplayMode * This);
+
+ long ( STDMETHODCALLTYPE *GetWidth )(
+ IDeckLinkDisplayMode * This);
+
+ long ( STDMETHODCALLTYPE *GetHeight )(
+ IDeckLinkDisplayMode * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFrameRate )(
+ IDeckLinkDisplayMode * This,
+ /* [out] */ BMDTimeValue *frameDuration,
+ /* [out] */ BMDTimeScale *timeScale);
+
+ BMDFieldDominance ( STDMETHODCALLTYPE *GetFieldDominance )(
+ IDeckLinkDisplayMode * This);
+
+ BMDDisplayModeFlags ( STDMETHODCALLTYPE *GetFlags )(
+ IDeckLinkDisplayMode * This);
+
+ END_INTERFACE
+ } IDeckLinkDisplayModeVtbl;
+
+ interface IDeckLinkDisplayMode
+ {
+ CONST_VTBL struct IDeckLinkDisplayModeVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkDisplayMode_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkDisplayMode_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkDisplayMode_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkDisplayMode_GetName(This,name) \
+ ( (This)->lpVtbl -> GetName(This,name) )
+
+#define IDeckLinkDisplayMode_GetDisplayMode(This) \
+ ( (This)->lpVtbl -> GetDisplayMode(This) )
+
+#define IDeckLinkDisplayMode_GetWidth(This) \
+ ( (This)->lpVtbl -> GetWidth(This) )
+
+#define IDeckLinkDisplayMode_GetHeight(This) \
+ ( (This)->lpVtbl -> GetHeight(This) )
+
+#define IDeckLinkDisplayMode_GetFrameRate(This,frameDuration,timeScale) \
+ ( (This)->lpVtbl -> GetFrameRate(This,frameDuration,timeScale) )
+
+#define IDeckLinkDisplayMode_GetFieldDominance(This) \
+ ( (This)->lpVtbl -> GetFieldDominance(This) )
+
+#define IDeckLinkDisplayMode_GetFlags(This) \
+ ( (This)->lpVtbl -> GetFlags(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkDisplayMode_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLink_INTERFACE_DEFINED__
+#define __IDeckLink_INTERFACE_DEFINED__
+
+/* interface IDeckLink */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLink;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("C418FBDD-0587-48ED-8FE5-640F0A14AF91")
+ IDeckLink : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetModelName(
+ /* [out] */ BSTR *modelName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDisplayName(
+ /* [out] */ BSTR *displayName) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLink * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLink * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLink * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModelName )(
+ IDeckLink * This,
+ /* [out] */ BSTR *modelName);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDisplayName )(
+ IDeckLink * This,
+ /* [out] */ BSTR *displayName);
+
+ END_INTERFACE
+ } IDeckLinkVtbl;
+
+ interface IDeckLink
+ {
+ CONST_VTBL struct IDeckLinkVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLink_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLink_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLink_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLink_GetModelName(This,modelName) \
+ ( (This)->lpVtbl -> GetModelName(This,modelName) )
+
+#define IDeckLink_GetDisplayName(This,displayName) \
+ ( (This)->lpVtbl -> GetDisplayName(This,displayName) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLink_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkConfiguration_INTERFACE_DEFINED__
+#define __IDeckLinkConfiguration_INTERFACE_DEFINED__
+
+/* interface IDeckLinkConfiguration */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkConfiguration;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1E69FCF6-4203-4936-8076-2A9F4CFD50CB")
+ IDeckLinkConfiguration : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetFlag(
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [in] */ BOOL value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFlag(
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [out] */ BOOL *value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetInt(
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [in] */ LONGLONG value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetInt(
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [out] */ LONGLONG *value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetFloat(
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [in] */ double value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFloat(
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [out] */ double *value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetString(
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [in] */ BSTR value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetString(
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [out] */ BSTR *value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteConfigurationToPreferences( void) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkConfigurationVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkConfiguration * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkConfiguration * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkConfiguration * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFlag )(
+ IDeckLinkConfiguration * This,
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [in] */ BOOL value);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFlag )(
+ IDeckLinkConfiguration * This,
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [out] */ BOOL *value);
+
+ HRESULT ( STDMETHODCALLTYPE *SetInt )(
+ IDeckLinkConfiguration * This,
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [in] */ LONGLONG value);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInt )(
+ IDeckLinkConfiguration * This,
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [out] */ LONGLONG *value);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFloat )(
+ IDeckLinkConfiguration * This,
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [in] */ double value);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFloat )(
+ IDeckLinkConfiguration * This,
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [out] */ double *value);
+
+ HRESULT ( STDMETHODCALLTYPE *SetString )(
+ IDeckLinkConfiguration * This,
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [in] */ BSTR value);
+
+ HRESULT ( STDMETHODCALLTYPE *GetString )(
+ IDeckLinkConfiguration * This,
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [out] */ BSTR *value);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteConfigurationToPreferences )(
+ IDeckLinkConfiguration * This);
+
+ END_INTERFACE
+ } IDeckLinkConfigurationVtbl;
+
+ interface IDeckLinkConfiguration
+ {
+ CONST_VTBL struct IDeckLinkConfigurationVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkConfiguration_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkConfiguration_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkConfiguration_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkConfiguration_SetFlag(This,cfgID,value) \
+ ( (This)->lpVtbl -> SetFlag(This,cfgID,value) )
+
+#define IDeckLinkConfiguration_GetFlag(This,cfgID,value) \
+ ( (This)->lpVtbl -> GetFlag(This,cfgID,value) )
+
+#define IDeckLinkConfiguration_SetInt(This,cfgID,value) \
+ ( (This)->lpVtbl -> SetInt(This,cfgID,value) )
+
+#define IDeckLinkConfiguration_GetInt(This,cfgID,value) \
+ ( (This)->lpVtbl -> GetInt(This,cfgID,value) )
+
+#define IDeckLinkConfiguration_SetFloat(This,cfgID,value) \
+ ( (This)->lpVtbl -> SetFloat(This,cfgID,value) )
+
+#define IDeckLinkConfiguration_GetFloat(This,cfgID,value) \
+ ( (This)->lpVtbl -> GetFloat(This,cfgID,value) )
+
+#define IDeckLinkConfiguration_SetString(This,cfgID,value) \
+ ( (This)->lpVtbl -> SetString(This,cfgID,value) )
+
+#define IDeckLinkConfiguration_GetString(This,cfgID,value) \
+ ( (This)->lpVtbl -> GetString(This,cfgID,value) )
+
+#define IDeckLinkConfiguration_WriteConfigurationToPreferences(This) \
+ ( (This)->lpVtbl -> WriteConfigurationToPreferences(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkConfiguration_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkDeckControlStatusCallback_INTERFACE_DEFINED__
+#define __IDeckLinkDeckControlStatusCallback_INTERFACE_DEFINED__
+
+/* interface IDeckLinkDeckControlStatusCallback */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkDeckControlStatusCallback;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("53436FFB-B434-4906-BADC-AE3060FFE8EF")
+ IDeckLinkDeckControlStatusCallback : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE TimecodeUpdate(
+ /* [in] */ BMDTimecodeBCD currentTimecode) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE VTRControlStateChanged(
+ /* [in] */ BMDDeckControlVTRControlState newState,
+ /* [in] */ BMDDeckControlError error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DeckControlEventReceived(
+ /* [in] */ BMDDeckControlEvent event,
+ /* [in] */ BMDDeckControlError error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DeckControlStatusChanged(
+ /* [in] */ BMDDeckControlStatusFlags flags,
+ /* [in] */ unsigned int mask) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkDeckControlStatusCallbackVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkDeckControlStatusCallback * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkDeckControlStatusCallback * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkDeckControlStatusCallback * This);
+
+ HRESULT ( STDMETHODCALLTYPE *TimecodeUpdate )(
+ IDeckLinkDeckControlStatusCallback * This,
+ /* [in] */ BMDTimecodeBCD currentTimecode);
+
+ HRESULT ( STDMETHODCALLTYPE *VTRControlStateChanged )(
+ IDeckLinkDeckControlStatusCallback * This,
+ /* [in] */ BMDDeckControlVTRControlState newState,
+ /* [in] */ BMDDeckControlError error);
+
+ HRESULT ( STDMETHODCALLTYPE *DeckControlEventReceived )(
+ IDeckLinkDeckControlStatusCallback * This,
+ /* [in] */ BMDDeckControlEvent event,
+ /* [in] */ BMDDeckControlError error);
+
+ HRESULT ( STDMETHODCALLTYPE *DeckControlStatusChanged )(
+ IDeckLinkDeckControlStatusCallback * This,
+ /* [in] */ BMDDeckControlStatusFlags flags,
+ /* [in] */ unsigned int mask);
+
+ END_INTERFACE
+ } IDeckLinkDeckControlStatusCallbackVtbl;
+
+ interface IDeckLinkDeckControlStatusCallback
+ {
+ CONST_VTBL struct IDeckLinkDeckControlStatusCallbackVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkDeckControlStatusCallback_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkDeckControlStatusCallback_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkDeckControlStatusCallback_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkDeckControlStatusCallback_TimecodeUpdate(This,currentTimecode) \
+ ( (This)->lpVtbl -> TimecodeUpdate(This,currentTimecode) )
+
+#define IDeckLinkDeckControlStatusCallback_VTRControlStateChanged(This,newState,error) \
+ ( (This)->lpVtbl -> VTRControlStateChanged(This,newState,error) )
+
+#define IDeckLinkDeckControlStatusCallback_DeckControlEventReceived(This,event,error) \
+ ( (This)->lpVtbl -> DeckControlEventReceived(This,event,error) )
+
+#define IDeckLinkDeckControlStatusCallback_DeckControlStatusChanged(This,flags,mask) \
+ ( (This)->lpVtbl -> DeckControlStatusChanged(This,flags,mask) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkDeckControlStatusCallback_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkDeckControl_INTERFACE_DEFINED__
+#define __IDeckLinkDeckControl_INTERFACE_DEFINED__
+
+/* interface IDeckLinkDeckControl */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkDeckControl;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("8E1C3ACE-19C7-4E00-8B92-D80431D958BE")
+ IDeckLinkDeckControl : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Open(
+ /* [in] */ BMDTimeScale timeScale,
+ /* [in] */ BMDTimeValue timeValue,
+ /* [in] */ BOOL timecodeIsDropFrame,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Close(
+ /* [in] */ BOOL standbyOn) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCurrentState(
+ /* [out] */ BMDDeckControlMode *mode,
+ /* [out] */ BMDDeckControlVTRControlState *vtrControlState,
+ /* [out] */ BMDDeckControlStatusFlags *flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetStandby(
+ /* [in] */ BOOL standbyOn) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SendCommand(
+ /* [in] */ unsigned char *inBuffer,
+ /* [in] */ unsigned int inBufferSize,
+ /* [out] */ unsigned char *outBuffer,
+ /* [out] */ unsigned int *outDataSize,
+ /* [in] */ unsigned int outBufferSize,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Play(
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Stop(
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE TogglePlayStop(
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Eject(
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GoToTimecode(
+ /* [in] */ BMDTimecodeBCD timecode,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FastForward(
+ /* [in] */ BOOL viewTape,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Rewind(
+ /* [in] */ BOOL viewTape,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StepForward(
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StepBack(
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Jog(
+ /* [in] */ double rate,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Shuttle(
+ /* [in] */ double rate,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTimecodeString(
+ /* [out] */ BSTR *currentTimeCode,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTimecode(
+ /* [out] */ IDeckLinkTimecode **currentTimecode,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTimecodeBCD(
+ /* [out] */ BMDTimecodeBCD *currentTimecode,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetPreroll(
+ /* [in] */ unsigned int prerollSeconds) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetPreroll(
+ /* [out] */ unsigned int *prerollSeconds) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetExportOffset(
+ /* [in] */ int exportOffsetFields) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetExportOffset(
+ /* [out] */ int *exportOffsetFields) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetManualExportOffset(
+ /* [out] */ int *deckManualExportOffsetFields) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetCaptureOffset(
+ /* [in] */ int captureOffsetFields) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCaptureOffset(
+ /* [out] */ int *captureOffsetFields) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartExport(
+ /* [in] */ BMDTimecodeBCD inTimecode,
+ /* [in] */ BMDTimecodeBCD outTimecode,
+ /* [in] */ BMDDeckControlExportModeOpsFlags exportModeOps,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartCapture(
+ /* [in] */ BOOL useVITC,
+ /* [in] */ BMDTimecodeBCD inTimecode,
+ /* [in] */ BMDTimecodeBCD outTimecode,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDeviceID(
+ /* [out] */ unsigned short *deviceId,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Abort( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CrashRecordStart(
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CrashRecordStop(
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetCallback(
+ /* [in] */ IDeckLinkDeckControlStatusCallback *callback) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkDeckControlVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkDeckControl * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkDeckControl * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkDeckControl * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Open )(
+ IDeckLinkDeckControl * This,
+ /* [in] */ BMDTimeScale timeScale,
+ /* [in] */ BMDTimeValue timeValue,
+ /* [in] */ BOOL timecodeIsDropFrame,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *Close )(
+ IDeckLinkDeckControl * This,
+ /* [in] */ BOOL standbyOn);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCurrentState )(
+ IDeckLinkDeckControl * This,
+ /* [out] */ BMDDeckControlMode *mode,
+ /* [out] */ BMDDeckControlVTRControlState *vtrControlState,
+ /* [out] */ BMDDeckControlStatusFlags *flags);
+
+ HRESULT ( STDMETHODCALLTYPE *SetStandby )(
+ IDeckLinkDeckControl * This,
+ /* [in] */ BOOL standbyOn);
+
+ HRESULT ( STDMETHODCALLTYPE *SendCommand )(
+ IDeckLinkDeckControl * This,
+ /* [in] */ unsigned char *inBuffer,
+ /* [in] */ unsigned int inBufferSize,
+ /* [out] */ unsigned char *outBuffer,
+ /* [out] */ unsigned int *outDataSize,
+ /* [in] */ unsigned int outBufferSize,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *Play )(
+ IDeckLinkDeckControl * This,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *Stop )(
+ IDeckLinkDeckControl * This,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *TogglePlayStop )(
+ IDeckLinkDeckControl * This,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *Eject )(
+ IDeckLinkDeckControl * This,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *GoToTimecode )(
+ IDeckLinkDeckControl * This,
+ /* [in] */ BMDTimecodeBCD timecode,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *FastForward )(
+ IDeckLinkDeckControl * This,
+ /* [in] */ BOOL viewTape,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *Rewind )(
+ IDeckLinkDeckControl * This,
+ /* [in] */ BOOL viewTape,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *StepForward )(
+ IDeckLinkDeckControl * This,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *StepBack )(
+ IDeckLinkDeckControl * This,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *Jog )(
+ IDeckLinkDeckControl * This,
+ /* [in] */ double rate,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *Shuttle )(
+ IDeckLinkDeckControl * This,
+ /* [in] */ double rate,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTimecodeString )(
+ IDeckLinkDeckControl * This,
+ /* [out] */ BSTR *currentTimeCode,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTimecode )(
+ IDeckLinkDeckControl * This,
+ /* [out] */ IDeckLinkTimecode **currentTimecode,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTimecodeBCD )(
+ IDeckLinkDeckControl * This,
+ /* [out] */ BMDTimecodeBCD *currentTimecode,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *SetPreroll )(
+ IDeckLinkDeckControl * This,
+ /* [in] */ unsigned int prerollSeconds);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPreroll )(
+ IDeckLinkDeckControl * This,
+ /* [out] */ unsigned int *prerollSeconds);
+
+ HRESULT ( STDMETHODCALLTYPE *SetExportOffset )(
+ IDeckLinkDeckControl * This,
+ /* [in] */ int exportOffsetFields);
+
+ HRESULT ( STDMETHODCALLTYPE *GetExportOffset )(
+ IDeckLinkDeckControl * This,
+ /* [out] */ int *exportOffsetFields);
+
+ HRESULT ( STDMETHODCALLTYPE *GetManualExportOffset )(
+ IDeckLinkDeckControl * This,
+ /* [out] */ int *deckManualExportOffsetFields);
+
+ HRESULT ( STDMETHODCALLTYPE *SetCaptureOffset )(
+ IDeckLinkDeckControl * This,
+ /* [in] */ int captureOffsetFields);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCaptureOffset )(
+ IDeckLinkDeckControl * This,
+ /* [out] */ int *captureOffsetFields);
+
+ HRESULT ( STDMETHODCALLTYPE *StartExport )(
+ IDeckLinkDeckControl * This,
+ /* [in] */ BMDTimecodeBCD inTimecode,
+ /* [in] */ BMDTimecodeBCD outTimecode,
+ /* [in] */ BMDDeckControlExportModeOpsFlags exportModeOps,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *StartCapture )(
+ IDeckLinkDeckControl * This,
+ /* [in] */ BOOL useVITC,
+ /* [in] */ BMDTimecodeBCD inTimecode,
+ /* [in] */ BMDTimecodeBCD outTimecode,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDeviceID )(
+ IDeckLinkDeckControl * This,
+ /* [out] */ unsigned short *deviceId,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *Abort )(
+ IDeckLinkDeckControl * This);
+
+ HRESULT ( STDMETHODCALLTYPE *CrashRecordStart )(
+ IDeckLinkDeckControl * This,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *CrashRecordStop )(
+ IDeckLinkDeckControl * This,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *SetCallback )(
+ IDeckLinkDeckControl * This,
+ /* [in] */ IDeckLinkDeckControlStatusCallback *callback);
+
+ END_INTERFACE
+ } IDeckLinkDeckControlVtbl;
+
+ interface IDeckLinkDeckControl
+ {
+ CONST_VTBL struct IDeckLinkDeckControlVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkDeckControl_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkDeckControl_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkDeckControl_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkDeckControl_Open(This,timeScale,timeValue,timecodeIsDropFrame,error) \
+ ( (This)->lpVtbl -> Open(This,timeScale,timeValue,timecodeIsDropFrame,error) )
+
+#define IDeckLinkDeckControl_Close(This,standbyOn) \
+ ( (This)->lpVtbl -> Close(This,standbyOn) )
+
+#define IDeckLinkDeckControl_GetCurrentState(This,mode,vtrControlState,flags) \
+ ( (This)->lpVtbl -> GetCurrentState(This,mode,vtrControlState,flags) )
+
+#define IDeckLinkDeckControl_SetStandby(This,standbyOn) \
+ ( (This)->lpVtbl -> SetStandby(This,standbyOn) )
+
+#define IDeckLinkDeckControl_SendCommand(This,inBuffer,inBufferSize,outBuffer,outDataSize,outBufferSize,error) \
+ ( (This)->lpVtbl -> SendCommand(This,inBuffer,inBufferSize,outBuffer,outDataSize,outBufferSize,error) )
+
+#define IDeckLinkDeckControl_Play(This,error) \
+ ( (This)->lpVtbl -> Play(This,error) )
+
+#define IDeckLinkDeckControl_Stop(This,error) \
+ ( (This)->lpVtbl -> Stop(This,error) )
+
+#define IDeckLinkDeckControl_TogglePlayStop(This,error) \
+ ( (This)->lpVtbl -> TogglePlayStop(This,error) )
+
+#define IDeckLinkDeckControl_Eject(This,error) \
+ ( (This)->lpVtbl -> Eject(This,error) )
+
+#define IDeckLinkDeckControl_GoToTimecode(This,timecode,error) \
+ ( (This)->lpVtbl -> GoToTimecode(This,timecode,error) )
+
+#define IDeckLinkDeckControl_FastForward(This,viewTape,error) \
+ ( (This)->lpVtbl -> FastForward(This,viewTape,error) )
+
+#define IDeckLinkDeckControl_Rewind(This,viewTape,error) \
+ ( (This)->lpVtbl -> Rewind(This,viewTape,error) )
+
+#define IDeckLinkDeckControl_StepForward(This,error) \
+ ( (This)->lpVtbl -> StepForward(This,error) )
+
+#define IDeckLinkDeckControl_StepBack(This,error) \
+ ( (This)->lpVtbl -> StepBack(This,error) )
+
+#define IDeckLinkDeckControl_Jog(This,rate,error) \
+ ( (This)->lpVtbl -> Jog(This,rate,error) )
+
+#define IDeckLinkDeckControl_Shuttle(This,rate,error) \
+ ( (This)->lpVtbl -> Shuttle(This,rate,error) )
+
+#define IDeckLinkDeckControl_GetTimecodeString(This,currentTimeCode,error) \
+ ( (This)->lpVtbl -> GetTimecodeString(This,currentTimeCode,error) )
+
+#define IDeckLinkDeckControl_GetTimecode(This,currentTimecode,error) \
+ ( (This)->lpVtbl -> GetTimecode(This,currentTimecode,error) )
+
+#define IDeckLinkDeckControl_GetTimecodeBCD(This,currentTimecode,error) \
+ ( (This)->lpVtbl -> GetTimecodeBCD(This,currentTimecode,error) )
+
+#define IDeckLinkDeckControl_SetPreroll(This,prerollSeconds) \
+ ( (This)->lpVtbl -> SetPreroll(This,prerollSeconds) )
+
+#define IDeckLinkDeckControl_GetPreroll(This,prerollSeconds) \
+ ( (This)->lpVtbl -> GetPreroll(This,prerollSeconds) )
+
+#define IDeckLinkDeckControl_SetExportOffset(This,exportOffsetFields) \
+ ( (This)->lpVtbl -> SetExportOffset(This,exportOffsetFields) )
+
+#define IDeckLinkDeckControl_GetExportOffset(This,exportOffsetFields) \
+ ( (This)->lpVtbl -> GetExportOffset(This,exportOffsetFields) )
+
+#define IDeckLinkDeckControl_GetManualExportOffset(This,deckManualExportOffsetFields) \
+ ( (This)->lpVtbl -> GetManualExportOffset(This,deckManualExportOffsetFields) )
+
+#define IDeckLinkDeckControl_SetCaptureOffset(This,captureOffsetFields) \
+ ( (This)->lpVtbl -> SetCaptureOffset(This,captureOffsetFields) )
+
+#define IDeckLinkDeckControl_GetCaptureOffset(This,captureOffsetFields) \
+ ( (This)->lpVtbl -> GetCaptureOffset(This,captureOffsetFields) )
+
+#define IDeckLinkDeckControl_StartExport(This,inTimecode,outTimecode,exportModeOps,error) \
+ ( (This)->lpVtbl -> StartExport(This,inTimecode,outTimecode,exportModeOps,error) )
+
+#define IDeckLinkDeckControl_StartCapture(This,useVITC,inTimecode,outTimecode,error) \
+ ( (This)->lpVtbl -> StartCapture(This,useVITC,inTimecode,outTimecode,error) )
+
+#define IDeckLinkDeckControl_GetDeviceID(This,deviceId,error) \
+ ( (This)->lpVtbl -> GetDeviceID(This,deviceId,error) )
+
+#define IDeckLinkDeckControl_Abort(This) \
+ ( (This)->lpVtbl -> Abort(This) )
+
+#define IDeckLinkDeckControl_CrashRecordStart(This,error) \
+ ( (This)->lpVtbl -> CrashRecordStart(This,error) )
+
+#define IDeckLinkDeckControl_CrashRecordStop(This,error) \
+ ( (This)->lpVtbl -> CrashRecordStop(This,error) )
+
+#define IDeckLinkDeckControl_SetCallback(This,callback) \
+ ( (This)->lpVtbl -> SetCallback(This,callback) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkDeckControl_INTERFACE_DEFINED__ */
+
+
+#ifndef __IBMDStreamingDeviceNotificationCallback_INTERFACE_DEFINED__
+#define __IBMDStreamingDeviceNotificationCallback_INTERFACE_DEFINED__
+
+/* interface IBMDStreamingDeviceNotificationCallback */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IBMDStreamingDeviceNotificationCallback;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("F9531D64-3305-4B29-A387-7F74BB0D0E84")
+ IBMDStreamingDeviceNotificationCallback : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE StreamingDeviceArrived(
+ /* [in] */ IDeckLink *device) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StreamingDeviceRemoved(
+ /* [in] */ IDeckLink *device) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StreamingDeviceModeChanged(
+ /* [in] */ IDeckLink *device,
+ /* [in] */ BMDStreamingDeviceMode mode) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IBMDStreamingDeviceNotificationCallbackVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IBMDStreamingDeviceNotificationCallback * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IBMDStreamingDeviceNotificationCallback * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IBMDStreamingDeviceNotificationCallback * This);
+
+ HRESULT ( STDMETHODCALLTYPE *StreamingDeviceArrived )(
+ IBMDStreamingDeviceNotificationCallback * This,
+ /* [in] */ IDeckLink *device);
+
+ HRESULT ( STDMETHODCALLTYPE *StreamingDeviceRemoved )(
+ IBMDStreamingDeviceNotificationCallback * This,
+ /* [in] */ IDeckLink *device);
+
+ HRESULT ( STDMETHODCALLTYPE *StreamingDeviceModeChanged )(
+ IBMDStreamingDeviceNotificationCallback * This,
+ /* [in] */ IDeckLink *device,
+ /* [in] */ BMDStreamingDeviceMode mode);
+
+ END_INTERFACE
+ } IBMDStreamingDeviceNotificationCallbackVtbl;
+
+ interface IBMDStreamingDeviceNotificationCallback
+ {
+ CONST_VTBL struct IBMDStreamingDeviceNotificationCallbackVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IBMDStreamingDeviceNotificationCallback_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IBMDStreamingDeviceNotificationCallback_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IBMDStreamingDeviceNotificationCallback_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IBMDStreamingDeviceNotificationCallback_StreamingDeviceArrived(This,device) \
+ ( (This)->lpVtbl -> StreamingDeviceArrived(This,device) )
+
+#define IBMDStreamingDeviceNotificationCallback_StreamingDeviceRemoved(This,device) \
+ ( (This)->lpVtbl -> StreamingDeviceRemoved(This,device) )
+
+#define IBMDStreamingDeviceNotificationCallback_StreamingDeviceModeChanged(This,device,mode) \
+ ( (This)->lpVtbl -> StreamingDeviceModeChanged(This,device,mode) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IBMDStreamingDeviceNotificationCallback_INTERFACE_DEFINED__ */
+
+
+#ifndef __IBMDStreamingH264InputCallback_INTERFACE_DEFINED__
+#define __IBMDStreamingH264InputCallback_INTERFACE_DEFINED__
+
+/* interface IBMDStreamingH264InputCallback */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IBMDStreamingH264InputCallback;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("823C475F-55AE-46F9-890C-537CC5CEDCCA")
+ IBMDStreamingH264InputCallback : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE H264NALPacketArrived(
+ /* [in] */ IBMDStreamingH264NALPacket *nalPacket) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE H264AudioPacketArrived(
+ /* [in] */ IBMDStreamingAudioPacket *audioPacket) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE MPEG2TSPacketArrived(
+ /* [in] */ IBMDStreamingMPEG2TSPacket *tsPacket) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE H264VideoInputConnectorScanningChanged( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE H264VideoInputConnectorChanged( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE H264VideoInputModeChanged( void) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IBMDStreamingH264InputCallbackVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IBMDStreamingH264InputCallback * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IBMDStreamingH264InputCallback * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IBMDStreamingH264InputCallback * This);
+
+ HRESULT ( STDMETHODCALLTYPE *H264NALPacketArrived )(
+ IBMDStreamingH264InputCallback * This,
+ /* [in] */ IBMDStreamingH264NALPacket *nalPacket);
+
+ HRESULT ( STDMETHODCALLTYPE *H264AudioPacketArrived )(
+ IBMDStreamingH264InputCallback * This,
+ /* [in] */ IBMDStreamingAudioPacket *audioPacket);
+
+ HRESULT ( STDMETHODCALLTYPE *MPEG2TSPacketArrived )(
+ IBMDStreamingH264InputCallback * This,
+ /* [in] */ IBMDStreamingMPEG2TSPacket *tsPacket);
+
+ HRESULT ( STDMETHODCALLTYPE *H264VideoInputConnectorScanningChanged )(
+ IBMDStreamingH264InputCallback * This);
+
+ HRESULT ( STDMETHODCALLTYPE *H264VideoInputConnectorChanged )(
+ IBMDStreamingH264InputCallback * This);
+
+ HRESULT ( STDMETHODCALLTYPE *H264VideoInputModeChanged )(
+ IBMDStreamingH264InputCallback * This);
+
+ END_INTERFACE
+ } IBMDStreamingH264InputCallbackVtbl;
+
+ interface IBMDStreamingH264InputCallback
+ {
+ CONST_VTBL struct IBMDStreamingH264InputCallbackVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IBMDStreamingH264InputCallback_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IBMDStreamingH264InputCallback_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IBMDStreamingH264InputCallback_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IBMDStreamingH264InputCallback_H264NALPacketArrived(This,nalPacket) \
+ ( (This)->lpVtbl -> H264NALPacketArrived(This,nalPacket) )
+
+#define IBMDStreamingH264InputCallback_H264AudioPacketArrived(This,audioPacket) \
+ ( (This)->lpVtbl -> H264AudioPacketArrived(This,audioPacket) )
+
+#define IBMDStreamingH264InputCallback_MPEG2TSPacketArrived(This,tsPacket) \
+ ( (This)->lpVtbl -> MPEG2TSPacketArrived(This,tsPacket) )
+
+#define IBMDStreamingH264InputCallback_H264VideoInputConnectorScanningChanged(This) \
+ ( (This)->lpVtbl -> H264VideoInputConnectorScanningChanged(This) )
+
+#define IBMDStreamingH264InputCallback_H264VideoInputConnectorChanged(This) \
+ ( (This)->lpVtbl -> H264VideoInputConnectorChanged(This) )
+
+#define IBMDStreamingH264InputCallback_H264VideoInputModeChanged(This) \
+ ( (This)->lpVtbl -> H264VideoInputModeChanged(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IBMDStreamingH264InputCallback_INTERFACE_DEFINED__ */
+
+
+#ifndef __IBMDStreamingDiscovery_INTERFACE_DEFINED__
+#define __IBMDStreamingDiscovery_INTERFACE_DEFINED__
+
+/* interface IBMDStreamingDiscovery */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IBMDStreamingDiscovery;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("2C837444-F989-4D87-901A-47C8A36D096D")
+ IBMDStreamingDiscovery : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE InstallDeviceNotifications(
+ /* [in] */ IBMDStreamingDeviceNotificationCallback *theCallback) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE UninstallDeviceNotifications( void) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IBMDStreamingDiscoveryVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IBMDStreamingDiscovery * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IBMDStreamingDiscovery * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IBMDStreamingDiscovery * This);
+
+ HRESULT ( STDMETHODCALLTYPE *InstallDeviceNotifications )(
+ IBMDStreamingDiscovery * This,
+ /* [in] */ IBMDStreamingDeviceNotificationCallback *theCallback);
+
+ HRESULT ( STDMETHODCALLTYPE *UninstallDeviceNotifications )(
+ IBMDStreamingDiscovery * This);
+
+ END_INTERFACE
+ } IBMDStreamingDiscoveryVtbl;
+
+ interface IBMDStreamingDiscovery
+ {
+ CONST_VTBL struct IBMDStreamingDiscoveryVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IBMDStreamingDiscovery_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IBMDStreamingDiscovery_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IBMDStreamingDiscovery_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IBMDStreamingDiscovery_InstallDeviceNotifications(This,theCallback) \
+ ( (This)->lpVtbl -> InstallDeviceNotifications(This,theCallback) )
+
+#define IBMDStreamingDiscovery_UninstallDeviceNotifications(This) \
+ ( (This)->lpVtbl -> UninstallDeviceNotifications(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IBMDStreamingDiscovery_INTERFACE_DEFINED__ */
+
+
+#ifndef __IBMDStreamingVideoEncodingMode_INTERFACE_DEFINED__
+#define __IBMDStreamingVideoEncodingMode_INTERFACE_DEFINED__
+
+/* interface IBMDStreamingVideoEncodingMode */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IBMDStreamingVideoEncodingMode;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1AB8035B-CD13-458D-B6DF-5E8F7C2141D9")
+ IBMDStreamingVideoEncodingMode : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetName(
+ /* [out] */ BSTR *name) = 0;
+
+ virtual unsigned int STDMETHODCALLTYPE GetPresetID( void) = 0;
+
+ virtual unsigned int STDMETHODCALLTYPE GetSourcePositionX( void) = 0;
+
+ virtual unsigned int STDMETHODCALLTYPE GetSourcePositionY( void) = 0;
+
+ virtual unsigned int STDMETHODCALLTYPE GetSourceWidth( void) = 0;
+
+ virtual unsigned int STDMETHODCALLTYPE GetSourceHeight( void) = 0;
+
+ virtual unsigned int STDMETHODCALLTYPE GetDestWidth( void) = 0;
+
+ virtual unsigned int STDMETHODCALLTYPE GetDestHeight( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFlag(
+ /* [in] */ BMDStreamingEncodingModePropertyID cfgID,
+ /* [out] */ BOOL *value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetInt(
+ /* [in] */ BMDStreamingEncodingModePropertyID cfgID,
+ /* [out] */ LONGLONG *value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFloat(
+ /* [in] */ BMDStreamingEncodingModePropertyID cfgID,
+ /* [out] */ double *value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetString(
+ /* [in] */ BMDStreamingEncodingModePropertyID cfgID,
+ /* [out] */ BSTR *value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateMutableVideoEncodingMode(
+ /* [out] */ IBMDStreamingMutableVideoEncodingMode **newEncodingMode) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IBMDStreamingVideoEncodingModeVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IBMDStreamingVideoEncodingMode * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IBMDStreamingVideoEncodingMode * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IBMDStreamingVideoEncodingMode * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ IBMDStreamingVideoEncodingMode * This,
+ /* [out] */ BSTR *name);
+
+ unsigned int ( STDMETHODCALLTYPE *GetPresetID )(
+ IBMDStreamingVideoEncodingMode * This);
+
+ unsigned int ( STDMETHODCALLTYPE *GetSourcePositionX )(
+ IBMDStreamingVideoEncodingMode * This);
+
+ unsigned int ( STDMETHODCALLTYPE *GetSourcePositionY )(
+ IBMDStreamingVideoEncodingMode * This);
+
+ unsigned int ( STDMETHODCALLTYPE *GetSourceWidth )(
+ IBMDStreamingVideoEncodingMode * This);
+
+ unsigned int ( STDMETHODCALLTYPE *GetSourceHeight )(
+ IBMDStreamingVideoEncodingMode * This);
+
+ unsigned int ( STDMETHODCALLTYPE *GetDestWidth )(
+ IBMDStreamingVideoEncodingMode * This);
+
+ unsigned int ( STDMETHODCALLTYPE *GetDestHeight )(
+ IBMDStreamingVideoEncodingMode * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFlag )(
+ IBMDStreamingVideoEncodingMode * This,
+ /* [in] */ BMDStreamingEncodingModePropertyID cfgID,
+ /* [out] */ BOOL *value);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInt )(
+ IBMDStreamingVideoEncodingMode * This,
+ /* [in] */ BMDStreamingEncodingModePropertyID cfgID,
+ /* [out] */ LONGLONG *value);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFloat )(
+ IBMDStreamingVideoEncodingMode * This,
+ /* [in] */ BMDStreamingEncodingModePropertyID cfgID,
+ /* [out] */ double *value);
+
+ HRESULT ( STDMETHODCALLTYPE *GetString )(
+ IBMDStreamingVideoEncodingMode * This,
+ /* [in] */ BMDStreamingEncodingModePropertyID cfgID,
+ /* [out] */ BSTR *value);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateMutableVideoEncodingMode )(
+ IBMDStreamingVideoEncodingMode * This,
+ /* [out] */ IBMDStreamingMutableVideoEncodingMode **newEncodingMode);
+
+ END_INTERFACE
+ } IBMDStreamingVideoEncodingModeVtbl;
+
+ interface IBMDStreamingVideoEncodingMode
+ {
+ CONST_VTBL struct IBMDStreamingVideoEncodingModeVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IBMDStreamingVideoEncodingMode_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IBMDStreamingVideoEncodingMode_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IBMDStreamingVideoEncodingMode_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IBMDStreamingVideoEncodingMode_GetName(This,name) \
+ ( (This)->lpVtbl -> GetName(This,name) )
+
+#define IBMDStreamingVideoEncodingMode_GetPresetID(This) \
+ ( (This)->lpVtbl -> GetPresetID(This) )
+
+#define IBMDStreamingVideoEncodingMode_GetSourcePositionX(This) \
+ ( (This)->lpVtbl -> GetSourcePositionX(This) )
+
+#define IBMDStreamingVideoEncodingMode_GetSourcePositionY(This) \
+ ( (This)->lpVtbl -> GetSourcePositionY(This) )
+
+#define IBMDStreamingVideoEncodingMode_GetSourceWidth(This) \
+ ( (This)->lpVtbl -> GetSourceWidth(This) )
+
+#define IBMDStreamingVideoEncodingMode_GetSourceHeight(This) \
+ ( (This)->lpVtbl -> GetSourceHeight(This) )
+
+#define IBMDStreamingVideoEncodingMode_GetDestWidth(This) \
+ ( (This)->lpVtbl -> GetDestWidth(This) )
+
+#define IBMDStreamingVideoEncodingMode_GetDestHeight(This) \
+ ( (This)->lpVtbl -> GetDestHeight(This) )
+
+#define IBMDStreamingVideoEncodingMode_GetFlag(This,cfgID,value) \
+ ( (This)->lpVtbl -> GetFlag(This,cfgID,value) )
+
+#define IBMDStreamingVideoEncodingMode_GetInt(This,cfgID,value) \
+ ( (This)->lpVtbl -> GetInt(This,cfgID,value) )
+
+#define IBMDStreamingVideoEncodingMode_GetFloat(This,cfgID,value) \
+ ( (This)->lpVtbl -> GetFloat(This,cfgID,value) )
+
+#define IBMDStreamingVideoEncodingMode_GetString(This,cfgID,value) \
+ ( (This)->lpVtbl -> GetString(This,cfgID,value) )
+
+#define IBMDStreamingVideoEncodingMode_CreateMutableVideoEncodingMode(This,newEncodingMode) \
+ ( (This)->lpVtbl -> CreateMutableVideoEncodingMode(This,newEncodingMode) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IBMDStreamingVideoEncodingMode_INTERFACE_DEFINED__ */
+
+
+#ifndef __IBMDStreamingMutableVideoEncodingMode_INTERFACE_DEFINED__
+#define __IBMDStreamingMutableVideoEncodingMode_INTERFACE_DEFINED__
+
+/* interface IBMDStreamingMutableVideoEncodingMode */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IBMDStreamingMutableVideoEncodingMode;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("19BF7D90-1E0A-400D-B2C6-FFC4E78AD49D")
+ IBMDStreamingMutableVideoEncodingMode : public IBMDStreamingVideoEncodingMode
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetSourceRect(
+ /* [in] */ unsigned int posX,
+ /* [in] */ unsigned int posY,
+ /* [in] */ unsigned int width,
+ /* [in] */ unsigned int height) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetDestSize(
+ /* [in] */ unsigned int width,
+ /* [in] */ unsigned int height) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetFlag(
+ /* [in] */ BMDStreamingEncodingModePropertyID cfgID,
+ /* [in] */ BOOL value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetInt(
+ /* [in] */ BMDStreamingEncodingModePropertyID cfgID,
+ /* [in] */ LONGLONG value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetFloat(
+ /* [in] */ BMDStreamingEncodingModePropertyID cfgID,
+ /* [in] */ double value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetString(
+ /* [in] */ BMDStreamingEncodingModePropertyID cfgID,
+ /* [in] */ BSTR value) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IBMDStreamingMutableVideoEncodingModeVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IBMDStreamingMutableVideoEncodingMode * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IBMDStreamingMutableVideoEncodingMode * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IBMDStreamingMutableVideoEncodingMode * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ IBMDStreamingMutableVideoEncodingMode * This,
+ /* [out] */ BSTR *name);
+
+ unsigned int ( STDMETHODCALLTYPE *GetPresetID )(
+ IBMDStreamingMutableVideoEncodingMode * This);
+
+ unsigned int ( STDMETHODCALLTYPE *GetSourcePositionX )(
+ IBMDStreamingMutableVideoEncodingMode * This);
+
+ unsigned int ( STDMETHODCALLTYPE *GetSourcePositionY )(
+ IBMDStreamingMutableVideoEncodingMode * This);
+
+ unsigned int ( STDMETHODCALLTYPE *GetSourceWidth )(
+ IBMDStreamingMutableVideoEncodingMode * This);
+
+ unsigned int ( STDMETHODCALLTYPE *GetSourceHeight )(
+ IBMDStreamingMutableVideoEncodingMode * This);
+
+ unsigned int ( STDMETHODCALLTYPE *GetDestWidth )(
+ IBMDStreamingMutableVideoEncodingMode * This);
+
+ unsigned int ( STDMETHODCALLTYPE *GetDestHeight )(
+ IBMDStreamingMutableVideoEncodingMode * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFlag )(
+ IBMDStreamingMutableVideoEncodingMode * This,
+ /* [in] */ BMDStreamingEncodingModePropertyID cfgID,
+ /* [out] */ BOOL *value);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInt )(
+ IBMDStreamingMutableVideoEncodingMode * This,
+ /* [in] */ BMDStreamingEncodingModePropertyID cfgID,
+ /* [out] */ LONGLONG *value);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFloat )(
+ IBMDStreamingMutableVideoEncodingMode * This,
+ /* [in] */ BMDStreamingEncodingModePropertyID cfgID,
+ /* [out] */ double *value);
+
+ HRESULT ( STDMETHODCALLTYPE *GetString )(
+ IBMDStreamingMutableVideoEncodingMode * This,
+ /* [in] */ BMDStreamingEncodingModePropertyID cfgID,
+ /* [out] */ BSTR *value);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateMutableVideoEncodingMode )(
+ IBMDStreamingMutableVideoEncodingMode * This,
+ /* [out] */ IBMDStreamingMutableVideoEncodingMode **newEncodingMode);
+
+ HRESULT ( STDMETHODCALLTYPE *SetSourceRect )(
+ IBMDStreamingMutableVideoEncodingMode * This,
+ /* [in] */ unsigned int posX,
+ /* [in] */ unsigned int posY,
+ /* [in] */ unsigned int width,
+ /* [in] */ unsigned int height);
+
+ HRESULT ( STDMETHODCALLTYPE *SetDestSize )(
+ IBMDStreamingMutableVideoEncodingMode * This,
+ /* [in] */ unsigned int width,
+ /* [in] */ unsigned int height);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFlag )(
+ IBMDStreamingMutableVideoEncodingMode * This,
+ /* [in] */ BMDStreamingEncodingModePropertyID cfgID,
+ /* [in] */ BOOL value);
+
+ HRESULT ( STDMETHODCALLTYPE *SetInt )(
+ IBMDStreamingMutableVideoEncodingMode * This,
+ /* [in] */ BMDStreamingEncodingModePropertyID cfgID,
+ /* [in] */ LONGLONG value);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFloat )(
+ IBMDStreamingMutableVideoEncodingMode * This,
+ /* [in] */ BMDStreamingEncodingModePropertyID cfgID,
+ /* [in] */ double value);
+
+ HRESULT ( STDMETHODCALLTYPE *SetString )(
+ IBMDStreamingMutableVideoEncodingMode * This,
+ /* [in] */ BMDStreamingEncodingModePropertyID cfgID,
+ /* [in] */ BSTR value);
+
+ END_INTERFACE
+ } IBMDStreamingMutableVideoEncodingModeVtbl;
+
+ interface IBMDStreamingMutableVideoEncodingMode
+ {
+ CONST_VTBL struct IBMDStreamingMutableVideoEncodingModeVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IBMDStreamingMutableVideoEncodingMode_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IBMDStreamingMutableVideoEncodingMode_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IBMDStreamingMutableVideoEncodingMode_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IBMDStreamingMutableVideoEncodingMode_GetName(This,name) \
+ ( (This)->lpVtbl -> GetName(This,name) )
+
+#define IBMDStreamingMutableVideoEncodingMode_GetPresetID(This) \
+ ( (This)->lpVtbl -> GetPresetID(This) )
+
+#define IBMDStreamingMutableVideoEncodingMode_GetSourcePositionX(This) \
+ ( (This)->lpVtbl -> GetSourcePositionX(This) )
+
+#define IBMDStreamingMutableVideoEncodingMode_GetSourcePositionY(This) \
+ ( (This)->lpVtbl -> GetSourcePositionY(This) )
+
+#define IBMDStreamingMutableVideoEncodingMode_GetSourceWidth(This) \
+ ( (This)->lpVtbl -> GetSourceWidth(This) )
+
+#define IBMDStreamingMutableVideoEncodingMode_GetSourceHeight(This) \
+ ( (This)->lpVtbl -> GetSourceHeight(This) )
+
+#define IBMDStreamingMutableVideoEncodingMode_GetDestWidth(This) \
+ ( (This)->lpVtbl -> GetDestWidth(This) )
+
+#define IBMDStreamingMutableVideoEncodingMode_GetDestHeight(This) \
+ ( (This)->lpVtbl -> GetDestHeight(This) )
+
+#define IBMDStreamingMutableVideoEncodingMode_GetFlag(This,cfgID,value) \
+ ( (This)->lpVtbl -> GetFlag(This,cfgID,value) )
+
+#define IBMDStreamingMutableVideoEncodingMode_GetInt(This,cfgID,value) \
+ ( (This)->lpVtbl -> GetInt(This,cfgID,value) )
+
+#define IBMDStreamingMutableVideoEncodingMode_GetFloat(This,cfgID,value) \
+ ( (This)->lpVtbl -> GetFloat(This,cfgID,value) )
+
+#define IBMDStreamingMutableVideoEncodingMode_GetString(This,cfgID,value) \
+ ( (This)->lpVtbl -> GetString(This,cfgID,value) )
+
+#define IBMDStreamingMutableVideoEncodingMode_CreateMutableVideoEncodingMode(This,newEncodingMode) \
+ ( (This)->lpVtbl -> CreateMutableVideoEncodingMode(This,newEncodingMode) )
+
+
+#define IBMDStreamingMutableVideoEncodingMode_SetSourceRect(This,posX,posY,width,height) \
+ ( (This)->lpVtbl -> SetSourceRect(This,posX,posY,width,height) )
+
+#define IBMDStreamingMutableVideoEncodingMode_SetDestSize(This,width,height) \
+ ( (This)->lpVtbl -> SetDestSize(This,width,height) )
+
+#define IBMDStreamingMutableVideoEncodingMode_SetFlag(This,cfgID,value) \
+ ( (This)->lpVtbl -> SetFlag(This,cfgID,value) )
+
+#define IBMDStreamingMutableVideoEncodingMode_SetInt(This,cfgID,value) \
+ ( (This)->lpVtbl -> SetInt(This,cfgID,value) )
+
+#define IBMDStreamingMutableVideoEncodingMode_SetFloat(This,cfgID,value) \
+ ( (This)->lpVtbl -> SetFloat(This,cfgID,value) )
+
+#define IBMDStreamingMutableVideoEncodingMode_SetString(This,cfgID,value) \
+ ( (This)->lpVtbl -> SetString(This,cfgID,value) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IBMDStreamingMutableVideoEncodingMode_INTERFACE_DEFINED__ */
+
+
+#ifndef __IBMDStreamingVideoEncodingModePresetIterator_INTERFACE_DEFINED__
+#define __IBMDStreamingVideoEncodingModePresetIterator_INTERFACE_DEFINED__
+
+/* interface IBMDStreamingVideoEncodingModePresetIterator */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IBMDStreamingVideoEncodingModePresetIterator;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("7AC731A3-C950-4AD0-804A-8377AA51C6C4")
+ IBMDStreamingVideoEncodingModePresetIterator : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [out] */ IBMDStreamingVideoEncodingMode **videoEncodingMode) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IBMDStreamingVideoEncodingModePresetIteratorVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IBMDStreamingVideoEncodingModePresetIterator * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IBMDStreamingVideoEncodingModePresetIterator * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IBMDStreamingVideoEncodingModePresetIterator * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ IBMDStreamingVideoEncodingModePresetIterator * This,
+ /* [out] */ IBMDStreamingVideoEncodingMode **videoEncodingMode);
+
+ END_INTERFACE
+ } IBMDStreamingVideoEncodingModePresetIteratorVtbl;
+
+ interface IBMDStreamingVideoEncodingModePresetIterator
+ {
+ CONST_VTBL struct IBMDStreamingVideoEncodingModePresetIteratorVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IBMDStreamingVideoEncodingModePresetIterator_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IBMDStreamingVideoEncodingModePresetIterator_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IBMDStreamingVideoEncodingModePresetIterator_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IBMDStreamingVideoEncodingModePresetIterator_Next(This,videoEncodingMode) \
+ ( (This)->lpVtbl -> Next(This,videoEncodingMode) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IBMDStreamingVideoEncodingModePresetIterator_INTERFACE_DEFINED__ */
+
+
+#ifndef __IBMDStreamingDeviceInput_INTERFACE_DEFINED__
+#define __IBMDStreamingDeviceInput_INTERFACE_DEFINED__
+
+/* interface IBMDStreamingDeviceInput */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IBMDStreamingDeviceInput;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("24B6B6EC-1727-44BB-9818-34FF086ACF98")
+ IBMDStreamingDeviceInput : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoInputMode(
+ /* [in] */ BMDDisplayMode inputMode,
+ /* [out] */ BOOL *result) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetVideoInputModeIterator(
+ /* [out] */ IDeckLinkDisplayModeIterator **iterator) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetVideoInputMode(
+ /* [in] */ BMDDisplayMode inputMode) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCurrentDetectedVideoInputMode(
+ /* [out] */ BMDDisplayMode *detectedMode) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetVideoEncodingMode(
+ /* [out] */ IBMDStreamingVideoEncodingMode **encodingMode) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetVideoEncodingModePresetIterator(
+ /* [in] */ BMDDisplayMode inputMode,
+ /* [out] */ IBMDStreamingVideoEncodingModePresetIterator **iterator) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoEncodingMode(
+ /* [in] */ BMDDisplayMode inputMode,
+ /* [in] */ IBMDStreamingVideoEncodingMode *encodingMode,
+ /* [out] */ BMDStreamingEncodingSupport *result,
+ /* [out] */ IBMDStreamingVideoEncodingMode **changedEncodingMode) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetVideoEncodingMode(
+ /* [in] */ IBMDStreamingVideoEncodingMode *encodingMode) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartCapture( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StopCapture( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetCallback(
+ /* [in] */ IUnknown *theCallback) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IBMDStreamingDeviceInputVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IBMDStreamingDeviceInput * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IBMDStreamingDeviceInput * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IBMDStreamingDeviceInput * This);
+
+ HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoInputMode )(
+ IBMDStreamingDeviceInput * This,
+ /* [in] */ BMDDisplayMode inputMode,
+ /* [out] */ BOOL *result);
+
+ HRESULT ( STDMETHODCALLTYPE *GetVideoInputModeIterator )(
+ IBMDStreamingDeviceInput * This,
+ /* [out] */ IDeckLinkDisplayModeIterator **iterator);
+
+ HRESULT ( STDMETHODCALLTYPE *SetVideoInputMode )(
+ IBMDStreamingDeviceInput * This,
+ /* [in] */ BMDDisplayMode inputMode);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCurrentDetectedVideoInputMode )(
+ IBMDStreamingDeviceInput * This,
+ /* [out] */ BMDDisplayMode *detectedMode);
+
+ HRESULT ( STDMETHODCALLTYPE *GetVideoEncodingMode )(
+ IBMDStreamingDeviceInput * This,
+ /* [out] */ IBMDStreamingVideoEncodingMode **encodingMode);
+
+ HRESULT ( STDMETHODCALLTYPE *GetVideoEncodingModePresetIterator )(
+ IBMDStreamingDeviceInput * This,
+ /* [in] */ BMDDisplayMode inputMode,
+ /* [out] */ IBMDStreamingVideoEncodingModePresetIterator **iterator);
+
+ HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoEncodingMode )(
+ IBMDStreamingDeviceInput * This,
+ /* [in] */ BMDDisplayMode inputMode,
+ /* [in] */ IBMDStreamingVideoEncodingMode *encodingMode,
+ /* [out] */ BMDStreamingEncodingSupport *result,
+ /* [out] */ IBMDStreamingVideoEncodingMode **changedEncodingMode);
+
+ HRESULT ( STDMETHODCALLTYPE *SetVideoEncodingMode )(
+ IBMDStreamingDeviceInput * This,
+ /* [in] */ IBMDStreamingVideoEncodingMode *encodingMode);
+
+ HRESULT ( STDMETHODCALLTYPE *StartCapture )(
+ IBMDStreamingDeviceInput * This);
+
+ HRESULT ( STDMETHODCALLTYPE *StopCapture )(
+ IBMDStreamingDeviceInput * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetCallback )(
+ IBMDStreamingDeviceInput * This,
+ /* [in] */ IUnknown *theCallback);
+
+ END_INTERFACE
+ } IBMDStreamingDeviceInputVtbl;
+
+ interface IBMDStreamingDeviceInput
+ {
+ CONST_VTBL struct IBMDStreamingDeviceInputVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IBMDStreamingDeviceInput_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IBMDStreamingDeviceInput_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IBMDStreamingDeviceInput_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IBMDStreamingDeviceInput_DoesSupportVideoInputMode(This,inputMode,result) \
+ ( (This)->lpVtbl -> DoesSupportVideoInputMode(This,inputMode,result) )
+
+#define IBMDStreamingDeviceInput_GetVideoInputModeIterator(This,iterator) \
+ ( (This)->lpVtbl -> GetVideoInputModeIterator(This,iterator) )
+
+#define IBMDStreamingDeviceInput_SetVideoInputMode(This,inputMode) \
+ ( (This)->lpVtbl -> SetVideoInputMode(This,inputMode) )
+
+#define IBMDStreamingDeviceInput_GetCurrentDetectedVideoInputMode(This,detectedMode) \
+ ( (This)->lpVtbl -> GetCurrentDetectedVideoInputMode(This,detectedMode) )
+
+#define IBMDStreamingDeviceInput_GetVideoEncodingMode(This,encodingMode) \
+ ( (This)->lpVtbl -> GetVideoEncodingMode(This,encodingMode) )
+
+#define IBMDStreamingDeviceInput_GetVideoEncodingModePresetIterator(This,inputMode,iterator) \
+ ( (This)->lpVtbl -> GetVideoEncodingModePresetIterator(This,inputMode,iterator) )
+
+#define IBMDStreamingDeviceInput_DoesSupportVideoEncodingMode(This,inputMode,encodingMode,result,changedEncodingMode) \
+ ( (This)->lpVtbl -> DoesSupportVideoEncodingMode(This,inputMode,encodingMode,result,changedEncodingMode) )
+
+#define IBMDStreamingDeviceInput_SetVideoEncodingMode(This,encodingMode) \
+ ( (This)->lpVtbl -> SetVideoEncodingMode(This,encodingMode) )
+
+#define IBMDStreamingDeviceInput_StartCapture(This) \
+ ( (This)->lpVtbl -> StartCapture(This) )
+
+#define IBMDStreamingDeviceInput_StopCapture(This) \
+ ( (This)->lpVtbl -> StopCapture(This) )
+
+#define IBMDStreamingDeviceInput_SetCallback(This,theCallback) \
+ ( (This)->lpVtbl -> SetCallback(This,theCallback) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IBMDStreamingDeviceInput_INTERFACE_DEFINED__ */
+
+
+#ifndef __IBMDStreamingH264NALPacket_INTERFACE_DEFINED__
+#define __IBMDStreamingH264NALPacket_INTERFACE_DEFINED__
+
+/* interface IBMDStreamingH264NALPacket */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IBMDStreamingH264NALPacket;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("E260E955-14BE-4395-9775-9F02CC0A9D89")
+ IBMDStreamingH264NALPacket : public IUnknown
+ {
+ public:
+ virtual long STDMETHODCALLTYPE GetPayloadSize( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBytes(
+ /* [out] */ void **buffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBytesWithSizePrefix(
+ /* [out] */ void **buffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDisplayTime(
+ /* [in] */ ULONGLONG requestedTimeScale,
+ /* [out] */ ULONGLONG *displayTime) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetPacketIndex(
+ /* [out] */ unsigned int *packetIndex) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IBMDStreamingH264NALPacketVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IBMDStreamingH264NALPacket * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IBMDStreamingH264NALPacket * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IBMDStreamingH264NALPacket * This);
+
+ long ( STDMETHODCALLTYPE *GetPayloadSize )(
+ IBMDStreamingH264NALPacket * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBytes )(
+ IBMDStreamingH264NALPacket * This,
+ /* [out] */ void **buffer);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBytesWithSizePrefix )(
+ IBMDStreamingH264NALPacket * This,
+ /* [out] */ void **buffer);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDisplayTime )(
+ IBMDStreamingH264NALPacket * This,
+ /* [in] */ ULONGLONG requestedTimeScale,
+ /* [out] */ ULONGLONG *displayTime);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPacketIndex )(
+ IBMDStreamingH264NALPacket * This,
+ /* [out] */ unsigned int *packetIndex);
+
+ END_INTERFACE
+ } IBMDStreamingH264NALPacketVtbl;
+
+ interface IBMDStreamingH264NALPacket
+ {
+ CONST_VTBL struct IBMDStreamingH264NALPacketVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IBMDStreamingH264NALPacket_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IBMDStreamingH264NALPacket_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IBMDStreamingH264NALPacket_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IBMDStreamingH264NALPacket_GetPayloadSize(This) \
+ ( (This)->lpVtbl -> GetPayloadSize(This) )
+
+#define IBMDStreamingH264NALPacket_GetBytes(This,buffer) \
+ ( (This)->lpVtbl -> GetBytes(This,buffer) )
+
+#define IBMDStreamingH264NALPacket_GetBytesWithSizePrefix(This,buffer) \
+ ( (This)->lpVtbl -> GetBytesWithSizePrefix(This,buffer) )
+
+#define IBMDStreamingH264NALPacket_GetDisplayTime(This,requestedTimeScale,displayTime) \
+ ( (This)->lpVtbl -> GetDisplayTime(This,requestedTimeScale,displayTime) )
+
+#define IBMDStreamingH264NALPacket_GetPacketIndex(This,packetIndex) \
+ ( (This)->lpVtbl -> GetPacketIndex(This,packetIndex) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IBMDStreamingH264NALPacket_INTERFACE_DEFINED__ */
+
+
+#ifndef __IBMDStreamingAudioPacket_INTERFACE_DEFINED__
+#define __IBMDStreamingAudioPacket_INTERFACE_DEFINED__
+
+/* interface IBMDStreamingAudioPacket */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IBMDStreamingAudioPacket;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("D9EB5902-1AD2-43F4-9E2C-3CFA50B5EE19")
+ IBMDStreamingAudioPacket : public IUnknown
+ {
+ public:
+ virtual BMDStreamingAudioCodec STDMETHODCALLTYPE GetCodec( void) = 0;
+
+ virtual long STDMETHODCALLTYPE GetPayloadSize( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBytes(
+ /* [out] */ void **buffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetPlayTime(
+ /* [in] */ ULONGLONG requestedTimeScale,
+ /* [out] */ ULONGLONG *playTime) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetPacketIndex(
+ /* [out] */ unsigned int *packetIndex) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IBMDStreamingAudioPacketVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IBMDStreamingAudioPacket * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IBMDStreamingAudioPacket * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IBMDStreamingAudioPacket * This);
+
+ BMDStreamingAudioCodec ( STDMETHODCALLTYPE *GetCodec )(
+ IBMDStreamingAudioPacket * This);
+
+ long ( STDMETHODCALLTYPE *GetPayloadSize )(
+ IBMDStreamingAudioPacket * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBytes )(
+ IBMDStreamingAudioPacket * This,
+ /* [out] */ void **buffer);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPlayTime )(
+ IBMDStreamingAudioPacket * This,
+ /* [in] */ ULONGLONG requestedTimeScale,
+ /* [out] */ ULONGLONG *playTime);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPacketIndex )(
+ IBMDStreamingAudioPacket * This,
+ /* [out] */ unsigned int *packetIndex);
+
+ END_INTERFACE
+ } IBMDStreamingAudioPacketVtbl;
+
+ interface IBMDStreamingAudioPacket
+ {
+ CONST_VTBL struct IBMDStreamingAudioPacketVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IBMDStreamingAudioPacket_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IBMDStreamingAudioPacket_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IBMDStreamingAudioPacket_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IBMDStreamingAudioPacket_GetCodec(This) \
+ ( (This)->lpVtbl -> GetCodec(This) )
+
+#define IBMDStreamingAudioPacket_GetPayloadSize(This) \
+ ( (This)->lpVtbl -> GetPayloadSize(This) )
+
+#define IBMDStreamingAudioPacket_GetBytes(This,buffer) \
+ ( (This)->lpVtbl -> GetBytes(This,buffer) )
+
+#define IBMDStreamingAudioPacket_GetPlayTime(This,requestedTimeScale,playTime) \
+ ( (This)->lpVtbl -> GetPlayTime(This,requestedTimeScale,playTime) )
+
+#define IBMDStreamingAudioPacket_GetPacketIndex(This,packetIndex) \
+ ( (This)->lpVtbl -> GetPacketIndex(This,packetIndex) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IBMDStreamingAudioPacket_INTERFACE_DEFINED__ */
+
+
+#ifndef __IBMDStreamingMPEG2TSPacket_INTERFACE_DEFINED__
+#define __IBMDStreamingMPEG2TSPacket_INTERFACE_DEFINED__
+
+/* interface IBMDStreamingMPEG2TSPacket */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IBMDStreamingMPEG2TSPacket;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("91810D1C-4FB3-4AAA-AE56-FA301D3DFA4C")
+ IBMDStreamingMPEG2TSPacket : public IUnknown
+ {
+ public:
+ virtual long STDMETHODCALLTYPE GetPayloadSize( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBytes(
+ /* [out] */ void **buffer) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IBMDStreamingMPEG2TSPacketVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IBMDStreamingMPEG2TSPacket * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IBMDStreamingMPEG2TSPacket * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IBMDStreamingMPEG2TSPacket * This);
+
+ long ( STDMETHODCALLTYPE *GetPayloadSize )(
+ IBMDStreamingMPEG2TSPacket * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBytes )(
+ IBMDStreamingMPEG2TSPacket * This,
+ /* [out] */ void **buffer);
+
+ END_INTERFACE
+ } IBMDStreamingMPEG2TSPacketVtbl;
+
+ interface IBMDStreamingMPEG2TSPacket
+ {
+ CONST_VTBL struct IBMDStreamingMPEG2TSPacketVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IBMDStreamingMPEG2TSPacket_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IBMDStreamingMPEG2TSPacket_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IBMDStreamingMPEG2TSPacket_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IBMDStreamingMPEG2TSPacket_GetPayloadSize(This) \
+ ( (This)->lpVtbl -> GetPayloadSize(This) )
+
+#define IBMDStreamingMPEG2TSPacket_GetBytes(This,buffer) \
+ ( (This)->lpVtbl -> GetBytes(This,buffer) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IBMDStreamingMPEG2TSPacket_INTERFACE_DEFINED__ */
+
+
+#ifndef __IBMDStreamingH264NALParser_INTERFACE_DEFINED__
+#define __IBMDStreamingH264NALParser_INTERFACE_DEFINED__
+
+/* interface IBMDStreamingH264NALParser */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IBMDStreamingH264NALParser;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("5867F18C-5BFA-4CCC-B2A7-9DFD140417D2")
+ IBMDStreamingH264NALParser : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE IsNALSequenceParameterSet(
+ /* [in] */ IBMDStreamingH264NALPacket *nal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsNALPictureParameterSet(
+ /* [in] */ IBMDStreamingH264NALPacket *nal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetProfileAndLevelFromSPS(
+ /* [in] */ IBMDStreamingH264NALPacket *nal,
+ /* [out] */ unsigned int *profileIdc,
+ /* [out] */ unsigned int *profileCompatability,
+ /* [out] */ unsigned int *levelIdc) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IBMDStreamingH264NALParserVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IBMDStreamingH264NALParser * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IBMDStreamingH264NALParser * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IBMDStreamingH264NALParser * This);
+
+ HRESULT ( STDMETHODCALLTYPE *IsNALSequenceParameterSet )(
+ IBMDStreamingH264NALParser * This,
+ /* [in] */ IBMDStreamingH264NALPacket *nal);
+
+ HRESULT ( STDMETHODCALLTYPE *IsNALPictureParameterSet )(
+ IBMDStreamingH264NALParser * This,
+ /* [in] */ IBMDStreamingH264NALPacket *nal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetProfileAndLevelFromSPS )(
+ IBMDStreamingH264NALParser * This,
+ /* [in] */ IBMDStreamingH264NALPacket *nal,
+ /* [out] */ unsigned int *profileIdc,
+ /* [out] */ unsigned int *profileCompatability,
+ /* [out] */ unsigned int *levelIdc);
+
+ END_INTERFACE
+ } IBMDStreamingH264NALParserVtbl;
+
+ interface IBMDStreamingH264NALParser
+ {
+ CONST_VTBL struct IBMDStreamingH264NALParserVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IBMDStreamingH264NALParser_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IBMDStreamingH264NALParser_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IBMDStreamingH264NALParser_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IBMDStreamingH264NALParser_IsNALSequenceParameterSet(This,nal) \
+ ( (This)->lpVtbl -> IsNALSequenceParameterSet(This,nal) )
+
+#define IBMDStreamingH264NALParser_IsNALPictureParameterSet(This,nal) \
+ ( (This)->lpVtbl -> IsNALPictureParameterSet(This,nal) )
+
+#define IBMDStreamingH264NALParser_GetProfileAndLevelFromSPS(This,nal,profileIdc,profileCompatability,levelIdc) \
+ ( (This)->lpVtbl -> GetProfileAndLevelFromSPS(This,nal,profileIdc,profileCompatability,levelIdc) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IBMDStreamingH264NALParser_INTERFACE_DEFINED__ */
+
+
+EXTERN_C const CLSID CLSID_CBMDStreamingDiscovery;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("0CAA31F6-8A26-40B0-86A4-BF58DCCA710C")
+CBMDStreamingDiscovery;
+#endif
+
+EXTERN_C const CLSID CLSID_CBMDStreamingH264NALParser;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("7753EFBD-951C-407C-97A5-23C737B73B52")
+CBMDStreamingH264NALParser;
+#endif
+
+#ifndef __IDeckLinkVideoOutputCallback_INTERFACE_DEFINED__
+#define __IDeckLinkVideoOutputCallback_INTERFACE_DEFINED__
+
+/* interface IDeckLinkVideoOutputCallback */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkVideoOutputCallback;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("20AA5225-1958-47CB-820B-80A8D521A6EE")
+ IDeckLinkVideoOutputCallback : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE ScheduledFrameCompleted(
+ /* [in] */ IDeckLinkVideoFrame *completedFrame,
+ /* [in] */ BMDOutputFrameCompletionResult result) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ScheduledPlaybackHasStopped( void) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkVideoOutputCallbackVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkVideoOutputCallback * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkVideoOutputCallback * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkVideoOutputCallback * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ScheduledFrameCompleted )(
+ IDeckLinkVideoOutputCallback * This,
+ /* [in] */ IDeckLinkVideoFrame *completedFrame,
+ /* [in] */ BMDOutputFrameCompletionResult result);
+
+ HRESULT ( STDMETHODCALLTYPE *ScheduledPlaybackHasStopped )(
+ IDeckLinkVideoOutputCallback * This);
+
+ END_INTERFACE
+ } IDeckLinkVideoOutputCallbackVtbl;
+
+ interface IDeckLinkVideoOutputCallback
+ {
+ CONST_VTBL struct IDeckLinkVideoOutputCallbackVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkVideoOutputCallback_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkVideoOutputCallback_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkVideoOutputCallback_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkVideoOutputCallback_ScheduledFrameCompleted(This,completedFrame,result) \
+ ( (This)->lpVtbl -> ScheduledFrameCompleted(This,completedFrame,result) )
+
+#define IDeckLinkVideoOutputCallback_ScheduledPlaybackHasStopped(This) \
+ ( (This)->lpVtbl -> ScheduledPlaybackHasStopped(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkVideoOutputCallback_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkInputCallback_INTERFACE_DEFINED__
+#define __IDeckLinkInputCallback_INTERFACE_DEFINED__
+
+/* interface IDeckLinkInputCallback */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkInputCallback;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("DD04E5EC-7415-42AB-AE4A-E80C4DFC044A")
+ IDeckLinkInputCallback : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(
+ /* [in] */ BMDVideoInputFormatChangedEvents notificationEvents,
+ /* [in] */ IDeckLinkDisplayMode *newDisplayMode,
+ /* [in] */ BMDDetectedVideoInputFormatFlags detectedSignalFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(
+ /* [in] */ IDeckLinkVideoInputFrame *videoFrame,
+ /* [in] */ IDeckLinkAudioInputPacket *audioPacket) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkInputCallbackVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkInputCallback * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkInputCallback * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkInputCallback * This);
+
+ HRESULT ( STDMETHODCALLTYPE *VideoInputFormatChanged )(
+ IDeckLinkInputCallback * This,
+ /* [in] */ BMDVideoInputFormatChangedEvents notificationEvents,
+ /* [in] */ IDeckLinkDisplayMode *newDisplayMode,
+ /* [in] */ BMDDetectedVideoInputFormatFlags detectedSignalFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *VideoInputFrameArrived )(
+ IDeckLinkInputCallback * This,
+ /* [in] */ IDeckLinkVideoInputFrame *videoFrame,
+ /* [in] */ IDeckLinkAudioInputPacket *audioPacket);
+
+ END_INTERFACE
+ } IDeckLinkInputCallbackVtbl;
+
+ interface IDeckLinkInputCallback
+ {
+ CONST_VTBL struct IDeckLinkInputCallbackVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkInputCallback_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkInputCallback_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkInputCallback_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkInputCallback_VideoInputFormatChanged(This,notificationEvents,newDisplayMode,detectedSignalFlags) \
+ ( (This)->lpVtbl -> VideoInputFormatChanged(This,notificationEvents,newDisplayMode,detectedSignalFlags) )
+
+#define IDeckLinkInputCallback_VideoInputFrameArrived(This,videoFrame,audioPacket) \
+ ( (This)->lpVtbl -> VideoInputFrameArrived(This,videoFrame,audioPacket) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkInputCallback_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkMemoryAllocator_INTERFACE_DEFINED__
+#define __IDeckLinkMemoryAllocator_INTERFACE_DEFINED__
+
+/* interface IDeckLinkMemoryAllocator */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkMemoryAllocator;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("B36EB6E7-9D29-4AA8-92EF-843B87A289E8")
+ IDeckLinkMemoryAllocator : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE AllocateBuffer(
+ /* [in] */ unsigned int bufferSize,
+ /* [out] */ void **allocatedBuffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ReleaseBuffer(
+ /* [in] */ void *buffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Commit( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Decommit( void) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkMemoryAllocatorVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkMemoryAllocator * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkMemoryAllocator * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkMemoryAllocator * This);
+
+ HRESULT ( STDMETHODCALLTYPE *AllocateBuffer )(
+ IDeckLinkMemoryAllocator * This,
+ /* [in] */ unsigned int bufferSize,
+ /* [out] */ void **allocatedBuffer);
+
+ HRESULT ( STDMETHODCALLTYPE *ReleaseBuffer )(
+ IDeckLinkMemoryAllocator * This,
+ /* [in] */ void *buffer);
+
+ HRESULT ( STDMETHODCALLTYPE *Commit )(
+ IDeckLinkMemoryAllocator * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Decommit )(
+ IDeckLinkMemoryAllocator * This);
+
+ END_INTERFACE
+ } IDeckLinkMemoryAllocatorVtbl;
+
+ interface IDeckLinkMemoryAllocator
+ {
+ CONST_VTBL struct IDeckLinkMemoryAllocatorVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkMemoryAllocator_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkMemoryAllocator_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkMemoryAllocator_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkMemoryAllocator_AllocateBuffer(This,bufferSize,allocatedBuffer) \
+ ( (This)->lpVtbl -> AllocateBuffer(This,bufferSize,allocatedBuffer) )
+
+#define IDeckLinkMemoryAllocator_ReleaseBuffer(This,buffer) \
+ ( (This)->lpVtbl -> ReleaseBuffer(This,buffer) )
+
+#define IDeckLinkMemoryAllocator_Commit(This) \
+ ( (This)->lpVtbl -> Commit(This) )
+
+#define IDeckLinkMemoryAllocator_Decommit(This) \
+ ( (This)->lpVtbl -> Decommit(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkMemoryAllocator_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkAudioOutputCallback_INTERFACE_DEFINED__
+#define __IDeckLinkAudioOutputCallback_INTERFACE_DEFINED__
+
+/* interface IDeckLinkAudioOutputCallback */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkAudioOutputCallback;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("403C681B-7F46-4A12-B993-2BB127084EE6")
+ IDeckLinkAudioOutputCallback : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE RenderAudioSamples(
+ /* [in] */ BOOL preroll) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkAudioOutputCallbackVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkAudioOutputCallback * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkAudioOutputCallback * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkAudioOutputCallback * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RenderAudioSamples )(
+ IDeckLinkAudioOutputCallback * This,
+ /* [in] */ BOOL preroll);
+
+ END_INTERFACE
+ } IDeckLinkAudioOutputCallbackVtbl;
+
+ interface IDeckLinkAudioOutputCallback
+ {
+ CONST_VTBL struct IDeckLinkAudioOutputCallbackVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkAudioOutputCallback_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkAudioOutputCallback_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkAudioOutputCallback_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkAudioOutputCallback_RenderAudioSamples(This,preroll) \
+ ( (This)->lpVtbl -> RenderAudioSamples(This,preroll) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkAudioOutputCallback_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkIterator_INTERFACE_DEFINED__
+#define __IDeckLinkIterator_INTERFACE_DEFINED__
+
+/* interface IDeckLinkIterator */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkIterator;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("50FB36CD-3063-4B73-BDBB-958087F2D8BA")
+ IDeckLinkIterator : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [out] */ IDeckLink **deckLinkInstance) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkIteratorVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkIterator * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkIterator * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkIterator * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ IDeckLinkIterator * This,
+ /* [out] */ IDeckLink **deckLinkInstance);
+
+ END_INTERFACE
+ } IDeckLinkIteratorVtbl;
+
+ interface IDeckLinkIterator
+ {
+ CONST_VTBL struct IDeckLinkIteratorVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkIterator_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkIterator_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkIterator_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkIterator_Next(This,deckLinkInstance) \
+ ( (This)->lpVtbl -> Next(This,deckLinkInstance) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkIterator_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkAPIInformation_INTERFACE_DEFINED__
+#define __IDeckLinkAPIInformation_INTERFACE_DEFINED__
+
+/* interface IDeckLinkAPIInformation */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkAPIInformation;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("7BEA3C68-730D-4322-AF34-8A7152B532A4")
+ IDeckLinkAPIInformation : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetFlag(
+ /* [in] */ BMDDeckLinkAPIInformationID cfgID,
+ /* [out] */ BOOL *value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetInt(
+ /* [in] */ BMDDeckLinkAPIInformationID cfgID,
+ /* [out] */ LONGLONG *value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFloat(
+ /* [in] */ BMDDeckLinkAPIInformationID cfgID,
+ /* [out] */ double *value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetString(
+ /* [in] */ BMDDeckLinkAPIInformationID cfgID,
+ /* [out] */ BSTR *value) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkAPIInformationVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkAPIInformation * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkAPIInformation * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkAPIInformation * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFlag )(
+ IDeckLinkAPIInformation * This,
+ /* [in] */ BMDDeckLinkAPIInformationID cfgID,
+ /* [out] */ BOOL *value);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInt )(
+ IDeckLinkAPIInformation * This,
+ /* [in] */ BMDDeckLinkAPIInformationID cfgID,
+ /* [out] */ LONGLONG *value);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFloat )(
+ IDeckLinkAPIInformation * This,
+ /* [in] */ BMDDeckLinkAPIInformationID cfgID,
+ /* [out] */ double *value);
+
+ HRESULT ( STDMETHODCALLTYPE *GetString )(
+ IDeckLinkAPIInformation * This,
+ /* [in] */ BMDDeckLinkAPIInformationID cfgID,
+ /* [out] */ BSTR *value);
+
+ END_INTERFACE
+ } IDeckLinkAPIInformationVtbl;
+
+ interface IDeckLinkAPIInformation
+ {
+ CONST_VTBL struct IDeckLinkAPIInformationVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkAPIInformation_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkAPIInformation_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkAPIInformation_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkAPIInformation_GetFlag(This,cfgID,value) \
+ ( (This)->lpVtbl -> GetFlag(This,cfgID,value) )
+
+#define IDeckLinkAPIInformation_GetInt(This,cfgID,value) \
+ ( (This)->lpVtbl -> GetInt(This,cfgID,value) )
+
+#define IDeckLinkAPIInformation_GetFloat(This,cfgID,value) \
+ ( (This)->lpVtbl -> GetFloat(This,cfgID,value) )
+
+#define IDeckLinkAPIInformation_GetString(This,cfgID,value) \
+ ( (This)->lpVtbl -> GetString(This,cfgID,value) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkAPIInformation_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkOutput_INTERFACE_DEFINED__
+#define __IDeckLinkOutput_INTERFACE_DEFINED__
+
+/* interface IDeckLinkOutput */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkOutput;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC5C8A6E-3F2F-4B3A-87EA-FD78AF300564")
+ IDeckLinkOutput : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode(
+ /* [in] */ BMDDisplayMode displayMode,
+ /* [in] */ BMDPixelFormat pixelFormat,
+ /* [in] */ BMDVideoOutputFlags flags,
+ /* [out] */ BMDDisplayModeSupport *result,
+ /* [out] */ IDeckLinkDisplayMode **resultDisplayMode) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator(
+ /* [out] */ IDeckLinkDisplayModeIterator **iterator) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetScreenPreviewCallback(
+ /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnableVideoOutput(
+ /* [in] */ BMDDisplayMode displayMode,
+ /* [in] */ BMDVideoOutputFlags flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DisableVideoOutput( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetVideoOutputFrameMemoryAllocator(
+ /* [in] */ IDeckLinkMemoryAllocator *theAllocator) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateVideoFrame(
+ /* [in] */ int width,
+ /* [in] */ int height,
+ /* [in] */ int rowBytes,
+ /* [in] */ BMDPixelFormat pixelFormat,
+ /* [in] */ BMDFrameFlags flags,
+ /* [out] */ IDeckLinkMutableVideoFrame **outFrame) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateAncillaryData(
+ /* [in] */ BMDPixelFormat pixelFormat,
+ /* [out] */ IDeckLinkVideoFrameAncillary **outBuffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DisplayVideoFrameSync(
+ /* [in] */ IDeckLinkVideoFrame *theFrame) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ScheduleVideoFrame(
+ /* [in] */ IDeckLinkVideoFrame *theFrame,
+ /* [in] */ BMDTimeValue displayTime,
+ /* [in] */ BMDTimeValue displayDuration,
+ /* [in] */ BMDTimeScale timeScale) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetScheduledFrameCompletionCallback(
+ /* [in] */ IDeckLinkVideoOutputCallback *theCallback) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBufferedVideoFrameCount(
+ /* [out] */ unsigned int *bufferedFrameCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnableAudioOutput(
+ /* [in] */ BMDAudioSampleRate sampleRate,
+ /* [in] */ BMDAudioSampleType sampleType,
+ /* [in] */ unsigned int channelCount,
+ /* [in] */ BMDAudioOutputStreamType streamType) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DisableAudioOutput( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteAudioSamplesSync(
+ /* [in] */ void *buffer,
+ /* [in] */ unsigned int sampleFrameCount,
+ /* [out] */ unsigned int *sampleFramesWritten) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE BeginAudioPreroll( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndAudioPreroll( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ScheduleAudioSamples(
+ /* [in] */ void *buffer,
+ /* [in] */ unsigned int sampleFrameCount,
+ /* [in] */ BMDTimeValue streamTime,
+ /* [in] */ BMDTimeScale timeScale,
+ /* [out] */ unsigned int *sampleFramesWritten) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBufferedAudioSampleFrameCount(
+ /* [out] */ unsigned int *bufferedSampleFrameCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FlushBufferedAudioSamples( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetAudioCallback(
+ /* [in] */ IDeckLinkAudioOutputCallback *theCallback) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartScheduledPlayback(
+ /* [in] */ BMDTimeValue playbackStartTime,
+ /* [in] */ BMDTimeScale timeScale,
+ /* [in] */ double playbackSpeed) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StopScheduledPlayback(
+ /* [in] */ BMDTimeValue stopPlaybackAtTime,
+ /* [out] */ BMDTimeValue *actualStopTime,
+ /* [in] */ BMDTimeScale timeScale) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsScheduledPlaybackRunning(
+ /* [out] */ BOOL *active) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetScheduledStreamTime(
+ /* [in] */ BMDTimeScale desiredTimeScale,
+ /* [out] */ BMDTimeValue *streamTime,
+ /* [out] */ double *playbackSpeed) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetReferenceStatus(
+ /* [out] */ BMDReferenceStatus *referenceStatus) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceClock(
+ /* [in] */ BMDTimeScale desiredTimeScale,
+ /* [out] */ BMDTimeValue *hardwareTime,
+ /* [out] */ BMDTimeValue *timeInFrame,
+ /* [out] */ BMDTimeValue *ticksPerFrame) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFrameCompletionReferenceTimestamp(
+ /* [in] */ IDeckLinkVideoFrame *theFrame,
+ /* [in] */ BMDTimeScale desiredTimeScale,
+ /* [out] */ BMDTimeValue *frameCompletionTimestamp) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkOutputVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkOutput * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkOutput * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkOutput * This);
+
+ HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )(
+ IDeckLinkOutput * This,
+ /* [in] */ BMDDisplayMode displayMode,
+ /* [in] */ BMDPixelFormat pixelFormat,
+ /* [in] */ BMDVideoOutputFlags flags,
+ /* [out] */ BMDDisplayModeSupport *result,
+ /* [out] */ IDeckLinkDisplayMode **resultDisplayMode);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )(
+ IDeckLinkOutput * This,
+ /* [out] */ IDeckLinkDisplayModeIterator **iterator);
+
+ HRESULT ( STDMETHODCALLTYPE *SetScreenPreviewCallback )(
+ IDeckLinkOutput * This,
+ /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback);
+
+ HRESULT ( STDMETHODCALLTYPE *EnableVideoOutput )(
+ IDeckLinkOutput * This,
+ /* [in] */ BMDDisplayMode displayMode,
+ /* [in] */ BMDVideoOutputFlags flags);
+
+ HRESULT ( STDMETHODCALLTYPE *DisableVideoOutput )(
+ IDeckLinkOutput * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetVideoOutputFrameMemoryAllocator )(
+ IDeckLinkOutput * This,
+ /* [in] */ IDeckLinkMemoryAllocator *theAllocator);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateVideoFrame )(
+ IDeckLinkOutput * This,
+ /* [in] */ int width,
+ /* [in] */ int height,
+ /* [in] */ int rowBytes,
+ /* [in] */ BMDPixelFormat pixelFormat,
+ /* [in] */ BMDFrameFlags flags,
+ /* [out] */ IDeckLinkMutableVideoFrame **outFrame);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateAncillaryData )(
+ IDeckLinkOutput * This,
+ /* [in] */ BMDPixelFormat pixelFormat,
+ /* [out] */ IDeckLinkVideoFrameAncillary **outBuffer);
+
+ HRESULT ( STDMETHODCALLTYPE *DisplayVideoFrameSync )(
+ IDeckLinkOutput * This,
+ /* [in] */ IDeckLinkVideoFrame *theFrame);
+
+ HRESULT ( STDMETHODCALLTYPE *ScheduleVideoFrame )(
+ IDeckLinkOutput * This,
+ /* [in] */ IDeckLinkVideoFrame *theFrame,
+ /* [in] */ BMDTimeValue displayTime,
+ /* [in] */ BMDTimeValue displayDuration,
+ /* [in] */ BMDTimeScale timeScale);
+
+ HRESULT ( STDMETHODCALLTYPE *SetScheduledFrameCompletionCallback )(
+ IDeckLinkOutput * This,
+ /* [in] */ IDeckLinkVideoOutputCallback *theCallback);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBufferedVideoFrameCount )(
+ IDeckLinkOutput * This,
+ /* [out] */ unsigned int *bufferedFrameCount);
+
+ HRESULT ( STDMETHODCALLTYPE *EnableAudioOutput )(
+ IDeckLinkOutput * This,
+ /* [in] */ BMDAudioSampleRate sampleRate,
+ /* [in] */ BMDAudioSampleType sampleType,
+ /* [in] */ unsigned int channelCount,
+ /* [in] */ BMDAudioOutputStreamType streamType);
+
+ HRESULT ( STDMETHODCALLTYPE *DisableAudioOutput )(
+ IDeckLinkOutput * This);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteAudioSamplesSync )(
+ IDeckLinkOutput * This,
+ /* [in] */ void *buffer,
+ /* [in] */ unsigned int sampleFrameCount,
+ /* [out] */ unsigned int *sampleFramesWritten);
+
+ HRESULT ( STDMETHODCALLTYPE *BeginAudioPreroll )(
+ IDeckLinkOutput * This);
+
+ HRESULT ( STDMETHODCALLTYPE *EndAudioPreroll )(
+ IDeckLinkOutput * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ScheduleAudioSamples )(
+ IDeckLinkOutput * This,
+ /* [in] */ void *buffer,
+ /* [in] */ unsigned int sampleFrameCount,
+ /* [in] */ BMDTimeValue streamTime,
+ /* [in] */ BMDTimeScale timeScale,
+ /* [out] */ unsigned int *sampleFramesWritten);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBufferedAudioSampleFrameCount )(
+ IDeckLinkOutput * This,
+ /* [out] */ unsigned int *bufferedSampleFrameCount);
+
+ HRESULT ( STDMETHODCALLTYPE *FlushBufferedAudioSamples )(
+ IDeckLinkOutput * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAudioCallback )(
+ IDeckLinkOutput * This,
+ /* [in] */ IDeckLinkAudioOutputCallback *theCallback);
+
+ HRESULT ( STDMETHODCALLTYPE *StartScheduledPlayback )(
+ IDeckLinkOutput * This,
+ /* [in] */ BMDTimeValue playbackStartTime,
+ /* [in] */ BMDTimeScale timeScale,
+ /* [in] */ double playbackSpeed);
+
+ HRESULT ( STDMETHODCALLTYPE *StopScheduledPlayback )(
+ IDeckLinkOutput * This,
+ /* [in] */ BMDTimeValue stopPlaybackAtTime,
+ /* [out] */ BMDTimeValue *actualStopTime,
+ /* [in] */ BMDTimeScale timeScale);
+
+ HRESULT ( STDMETHODCALLTYPE *IsScheduledPlaybackRunning )(
+ IDeckLinkOutput * This,
+ /* [out] */ BOOL *active);
+
+ HRESULT ( STDMETHODCALLTYPE *GetScheduledStreamTime )(
+ IDeckLinkOutput * This,
+ /* [in] */ BMDTimeScale desiredTimeScale,
+ /* [out] */ BMDTimeValue *streamTime,
+ /* [out] */ double *playbackSpeed);
+
+ HRESULT ( STDMETHODCALLTYPE *GetReferenceStatus )(
+ IDeckLinkOutput * This,
+ /* [out] */ BMDReferenceStatus *referenceStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceClock )(
+ IDeckLinkOutput * This,
+ /* [in] */ BMDTimeScale desiredTimeScale,
+ /* [out] */ BMDTimeValue *hardwareTime,
+ /* [out] */ BMDTimeValue *timeInFrame,
+ /* [out] */ BMDTimeValue *ticksPerFrame);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFrameCompletionReferenceTimestamp )(
+ IDeckLinkOutput * This,
+ /* [in] */ IDeckLinkVideoFrame *theFrame,
+ /* [in] */ BMDTimeScale desiredTimeScale,
+ /* [out] */ BMDTimeValue *frameCompletionTimestamp);
+
+ END_INTERFACE
+ } IDeckLinkOutputVtbl;
+
+ interface IDeckLinkOutput
+ {
+ CONST_VTBL struct IDeckLinkOutputVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkOutput_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkOutput_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkOutput_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkOutput_DoesSupportVideoMode(This,displayMode,pixelFormat,flags,result,resultDisplayMode) \
+ ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,flags,result,resultDisplayMode) )
+
+#define IDeckLinkOutput_GetDisplayModeIterator(This,iterator) \
+ ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) )
+
+#define IDeckLinkOutput_SetScreenPreviewCallback(This,previewCallback) \
+ ( (This)->lpVtbl -> SetScreenPreviewCallback(This,previewCallback) )
+
+#define IDeckLinkOutput_EnableVideoOutput(This,displayMode,flags) \
+ ( (This)->lpVtbl -> EnableVideoOutput(This,displayMode,flags) )
+
+#define IDeckLinkOutput_DisableVideoOutput(This) \
+ ( (This)->lpVtbl -> DisableVideoOutput(This) )
+
+#define IDeckLinkOutput_SetVideoOutputFrameMemoryAllocator(This,theAllocator) \
+ ( (This)->lpVtbl -> SetVideoOutputFrameMemoryAllocator(This,theAllocator) )
+
+#define IDeckLinkOutput_CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) \
+ ( (This)->lpVtbl -> CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) )
+
+#define IDeckLinkOutput_CreateAncillaryData(This,pixelFormat,outBuffer) \
+ ( (This)->lpVtbl -> CreateAncillaryData(This,pixelFormat,outBuffer) )
+
+#define IDeckLinkOutput_DisplayVideoFrameSync(This,theFrame) \
+ ( (This)->lpVtbl -> DisplayVideoFrameSync(This,theFrame) )
+
+#define IDeckLinkOutput_ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) \
+ ( (This)->lpVtbl -> ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) )
+
+#define IDeckLinkOutput_SetScheduledFrameCompletionCallback(This,theCallback) \
+ ( (This)->lpVtbl -> SetScheduledFrameCompletionCallback(This,theCallback) )
+
+#define IDeckLinkOutput_GetBufferedVideoFrameCount(This,bufferedFrameCount) \
+ ( (This)->lpVtbl -> GetBufferedVideoFrameCount(This,bufferedFrameCount) )
+
+#define IDeckLinkOutput_EnableAudioOutput(This,sampleRate,sampleType,channelCount,streamType) \
+ ( (This)->lpVtbl -> EnableAudioOutput(This,sampleRate,sampleType,channelCount,streamType) )
+
+#define IDeckLinkOutput_DisableAudioOutput(This) \
+ ( (This)->lpVtbl -> DisableAudioOutput(This) )
+
+#define IDeckLinkOutput_WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) \
+ ( (This)->lpVtbl -> WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) )
+
+#define IDeckLinkOutput_BeginAudioPreroll(This) \
+ ( (This)->lpVtbl -> BeginAudioPreroll(This) )
+
+#define IDeckLinkOutput_EndAudioPreroll(This) \
+ ( (This)->lpVtbl -> EndAudioPreroll(This) )
+
+#define IDeckLinkOutput_ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) \
+ ( (This)->lpVtbl -> ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) )
+
+#define IDeckLinkOutput_GetBufferedAudioSampleFrameCount(This,bufferedSampleFrameCount) \
+ ( (This)->lpVtbl -> GetBufferedAudioSampleFrameCount(This,bufferedSampleFrameCount) )
+
+#define IDeckLinkOutput_FlushBufferedAudioSamples(This) \
+ ( (This)->lpVtbl -> FlushBufferedAudioSamples(This) )
+
+#define IDeckLinkOutput_SetAudioCallback(This,theCallback) \
+ ( (This)->lpVtbl -> SetAudioCallback(This,theCallback) )
+
+#define IDeckLinkOutput_StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) \
+ ( (This)->lpVtbl -> StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) )
+
+#define IDeckLinkOutput_StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) \
+ ( (This)->lpVtbl -> StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) )
+
+#define IDeckLinkOutput_IsScheduledPlaybackRunning(This,active) \
+ ( (This)->lpVtbl -> IsScheduledPlaybackRunning(This,active) )
+
+#define IDeckLinkOutput_GetScheduledStreamTime(This,desiredTimeScale,streamTime,playbackSpeed) \
+ ( (This)->lpVtbl -> GetScheduledStreamTime(This,desiredTimeScale,streamTime,playbackSpeed) )
+
+#define IDeckLinkOutput_GetReferenceStatus(This,referenceStatus) \
+ ( (This)->lpVtbl -> GetReferenceStatus(This,referenceStatus) )
+
+#define IDeckLinkOutput_GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) \
+ ( (This)->lpVtbl -> GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) )
+
+#define IDeckLinkOutput_GetFrameCompletionReferenceTimestamp(This,theFrame,desiredTimeScale,frameCompletionTimestamp) \
+ ( (This)->lpVtbl -> GetFrameCompletionReferenceTimestamp(This,theFrame,desiredTimeScale,frameCompletionTimestamp) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkOutput_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkInput_INTERFACE_DEFINED__
+#define __IDeckLinkInput_INTERFACE_DEFINED__
+
+/* interface IDeckLinkInput */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkInput;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("AF22762B-DFAC-4846-AA79-FA8883560995")
+ IDeckLinkInput : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode(
+ /* [in] */ BMDDisplayMode displayMode,
+ /* [in] */ BMDPixelFormat pixelFormat,
+ /* [in] */ BMDVideoInputFlags flags,
+ /* [out] */ BMDDisplayModeSupport *result,
+ /* [out] */ IDeckLinkDisplayMode **resultDisplayMode) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator(
+ /* [out] */ IDeckLinkDisplayModeIterator **iterator) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetScreenPreviewCallback(
+ /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnableVideoInput(
+ /* [in] */ BMDDisplayMode displayMode,
+ /* [in] */ BMDPixelFormat pixelFormat,
+ /* [in] */ BMDVideoInputFlags flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DisableVideoInput( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAvailableVideoFrameCount(
+ /* [out] */ unsigned int *availableFrameCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetVideoInputFrameMemoryAllocator(
+ /* [in] */ IDeckLinkMemoryAllocator *theAllocator) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnableAudioInput(
+ /* [in] */ BMDAudioSampleRate sampleRate,
+ /* [in] */ BMDAudioSampleType sampleType,
+ /* [in] */ unsigned int channelCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DisableAudioInput( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAvailableAudioSampleFrameCount(
+ /* [out] */ unsigned int *availableSampleFrameCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartStreams( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StopStreams( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE PauseStreams( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FlushStreams( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetCallback(
+ /* [in] */ IDeckLinkInputCallback *theCallback) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceClock(
+ /* [in] */ BMDTimeScale desiredTimeScale,
+ /* [out] */ BMDTimeValue *hardwareTime,
+ /* [out] */ BMDTimeValue *timeInFrame,
+ /* [out] */ BMDTimeValue *ticksPerFrame) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkInputVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkInput * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkInput * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkInput * This);
+
+ HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )(
+ IDeckLinkInput * This,
+ /* [in] */ BMDDisplayMode displayMode,
+ /* [in] */ BMDPixelFormat pixelFormat,
+ /* [in] */ BMDVideoInputFlags flags,
+ /* [out] */ BMDDisplayModeSupport *result,
+ /* [out] */ IDeckLinkDisplayMode **resultDisplayMode);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )(
+ IDeckLinkInput * This,
+ /* [out] */ IDeckLinkDisplayModeIterator **iterator);
+
+ HRESULT ( STDMETHODCALLTYPE *SetScreenPreviewCallback )(
+ IDeckLinkInput * This,
+ /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback);
+
+ HRESULT ( STDMETHODCALLTYPE *EnableVideoInput )(
+ IDeckLinkInput * This,
+ /* [in] */ BMDDisplayMode displayMode,
+ /* [in] */ BMDPixelFormat pixelFormat,
+ /* [in] */ BMDVideoInputFlags flags);
+
+ HRESULT ( STDMETHODCALLTYPE *DisableVideoInput )(
+ IDeckLinkInput * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAvailableVideoFrameCount )(
+ IDeckLinkInput * This,
+ /* [out] */ unsigned int *availableFrameCount);
+
+ HRESULT ( STDMETHODCALLTYPE *SetVideoInputFrameMemoryAllocator )(
+ IDeckLinkInput * This,
+ /* [in] */ IDeckLinkMemoryAllocator *theAllocator);
+
+ HRESULT ( STDMETHODCALLTYPE *EnableAudioInput )(
+ IDeckLinkInput * This,
+ /* [in] */ BMDAudioSampleRate sampleRate,
+ /* [in] */ BMDAudioSampleType sampleType,
+ /* [in] */ unsigned int channelCount);
+
+ HRESULT ( STDMETHODCALLTYPE *DisableAudioInput )(
+ IDeckLinkInput * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAvailableAudioSampleFrameCount )(
+ IDeckLinkInput * This,
+ /* [out] */ unsigned int *availableSampleFrameCount);
+
+ HRESULT ( STDMETHODCALLTYPE *StartStreams )(
+ IDeckLinkInput * This);
+
+ HRESULT ( STDMETHODCALLTYPE *StopStreams )(
+ IDeckLinkInput * This);
+
+ HRESULT ( STDMETHODCALLTYPE *PauseStreams )(
+ IDeckLinkInput * This);
+
+ HRESULT ( STDMETHODCALLTYPE *FlushStreams )(
+ IDeckLinkInput * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetCallback )(
+ IDeckLinkInput * This,
+ /* [in] */ IDeckLinkInputCallback *theCallback);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceClock )(
+ IDeckLinkInput * This,
+ /* [in] */ BMDTimeScale desiredTimeScale,
+ /* [out] */ BMDTimeValue *hardwareTime,
+ /* [out] */ BMDTimeValue *timeInFrame,
+ /* [out] */ BMDTimeValue *ticksPerFrame);
+
+ END_INTERFACE
+ } IDeckLinkInputVtbl;
+
+ interface IDeckLinkInput
+ {
+ CONST_VTBL struct IDeckLinkInputVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkInput_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkInput_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkInput_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkInput_DoesSupportVideoMode(This,displayMode,pixelFormat,flags,result,resultDisplayMode) \
+ ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,flags,result,resultDisplayMode) )
+
+#define IDeckLinkInput_GetDisplayModeIterator(This,iterator) \
+ ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) )
+
+#define IDeckLinkInput_SetScreenPreviewCallback(This,previewCallback) \
+ ( (This)->lpVtbl -> SetScreenPreviewCallback(This,previewCallback) )
+
+#define IDeckLinkInput_EnableVideoInput(This,displayMode,pixelFormat,flags) \
+ ( (This)->lpVtbl -> EnableVideoInput(This,displayMode,pixelFormat,flags) )
+
+#define IDeckLinkInput_DisableVideoInput(This) \
+ ( (This)->lpVtbl -> DisableVideoInput(This) )
+
+#define IDeckLinkInput_GetAvailableVideoFrameCount(This,availableFrameCount) \
+ ( (This)->lpVtbl -> GetAvailableVideoFrameCount(This,availableFrameCount) )
+
+#define IDeckLinkInput_SetVideoInputFrameMemoryAllocator(This,theAllocator) \
+ ( (This)->lpVtbl -> SetVideoInputFrameMemoryAllocator(This,theAllocator) )
+
+#define IDeckLinkInput_EnableAudioInput(This,sampleRate,sampleType,channelCount) \
+ ( (This)->lpVtbl -> EnableAudioInput(This,sampleRate,sampleType,channelCount) )
+
+#define IDeckLinkInput_DisableAudioInput(This) \
+ ( (This)->lpVtbl -> DisableAudioInput(This) )
+
+#define IDeckLinkInput_GetAvailableAudioSampleFrameCount(This,availableSampleFrameCount) \
+ ( (This)->lpVtbl -> GetAvailableAudioSampleFrameCount(This,availableSampleFrameCount) )
+
+#define IDeckLinkInput_StartStreams(This) \
+ ( (This)->lpVtbl -> StartStreams(This) )
+
+#define IDeckLinkInput_StopStreams(This) \
+ ( (This)->lpVtbl -> StopStreams(This) )
+
+#define IDeckLinkInput_PauseStreams(This) \
+ ( (This)->lpVtbl -> PauseStreams(This) )
+
+#define IDeckLinkInput_FlushStreams(This) \
+ ( (This)->lpVtbl -> FlushStreams(This) )
+
+#define IDeckLinkInput_SetCallback(This,theCallback) \
+ ( (This)->lpVtbl -> SetCallback(This,theCallback) )
+
+#define IDeckLinkInput_GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) \
+ ( (This)->lpVtbl -> GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkInput_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkVideoFrame_INTERFACE_DEFINED__
+#define __IDeckLinkVideoFrame_INTERFACE_DEFINED__
+
+/* interface IDeckLinkVideoFrame */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkVideoFrame;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("3F716FE0-F023-4111-BE5D-EF4414C05B17")
+ IDeckLinkVideoFrame : public IUnknown
+ {
+ public:
+ virtual long STDMETHODCALLTYPE GetWidth( void) = 0;
+
+ virtual long STDMETHODCALLTYPE GetHeight( void) = 0;
+
+ virtual long STDMETHODCALLTYPE GetRowBytes( void) = 0;
+
+ virtual BMDPixelFormat STDMETHODCALLTYPE GetPixelFormat( void) = 0;
+
+ virtual BMDFrameFlags STDMETHODCALLTYPE GetFlags( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBytes(
+ /* [out] */ void **buffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTimecode(
+ /* [in] */ BMDTimecodeFormat format,
+ /* [out] */ IDeckLinkTimecode **timecode) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAncillaryData(
+ /* [out] */ IDeckLinkVideoFrameAncillary **ancillary) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkVideoFrameVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkVideoFrame * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkVideoFrame * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkVideoFrame * This);
+
+ long ( STDMETHODCALLTYPE *GetWidth )(
+ IDeckLinkVideoFrame * This);
+
+ long ( STDMETHODCALLTYPE *GetHeight )(
+ IDeckLinkVideoFrame * This);
+
+ long ( STDMETHODCALLTYPE *GetRowBytes )(
+ IDeckLinkVideoFrame * This);
+
+ BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )(
+ IDeckLinkVideoFrame * This);
+
+ BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )(
+ IDeckLinkVideoFrame * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBytes )(
+ IDeckLinkVideoFrame * This,
+ /* [out] */ void **buffer);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTimecode )(
+ IDeckLinkVideoFrame * This,
+ /* [in] */ BMDTimecodeFormat format,
+ /* [out] */ IDeckLinkTimecode **timecode);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAncillaryData )(
+ IDeckLinkVideoFrame * This,
+ /* [out] */ IDeckLinkVideoFrameAncillary **ancillary);
+
+ END_INTERFACE
+ } IDeckLinkVideoFrameVtbl;
+
+ interface IDeckLinkVideoFrame
+ {
+ CONST_VTBL struct IDeckLinkVideoFrameVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkVideoFrame_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkVideoFrame_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkVideoFrame_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkVideoFrame_GetWidth(This) \
+ ( (This)->lpVtbl -> GetWidth(This) )
+
+#define IDeckLinkVideoFrame_GetHeight(This) \
+ ( (This)->lpVtbl -> GetHeight(This) )
+
+#define IDeckLinkVideoFrame_GetRowBytes(This) \
+ ( (This)->lpVtbl -> GetRowBytes(This) )
+
+#define IDeckLinkVideoFrame_GetPixelFormat(This) \
+ ( (This)->lpVtbl -> GetPixelFormat(This) )
+
+#define IDeckLinkVideoFrame_GetFlags(This) \
+ ( (This)->lpVtbl -> GetFlags(This) )
+
+#define IDeckLinkVideoFrame_GetBytes(This,buffer) \
+ ( (This)->lpVtbl -> GetBytes(This,buffer) )
+
+#define IDeckLinkVideoFrame_GetTimecode(This,format,timecode) \
+ ( (This)->lpVtbl -> GetTimecode(This,format,timecode) )
+
+#define IDeckLinkVideoFrame_GetAncillaryData(This,ancillary) \
+ ( (This)->lpVtbl -> GetAncillaryData(This,ancillary) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkVideoFrame_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkMutableVideoFrame_INTERFACE_DEFINED__
+#define __IDeckLinkMutableVideoFrame_INTERFACE_DEFINED__
+
+/* interface IDeckLinkMutableVideoFrame */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkMutableVideoFrame;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("69E2639F-40DA-4E19-B6F2-20ACE815C390")
+ IDeckLinkMutableVideoFrame : public IDeckLinkVideoFrame
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetFlags(
+ /* [in] */ BMDFrameFlags newFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetTimecode(
+ /* [in] */ BMDTimecodeFormat format,
+ /* [in] */ IDeckLinkTimecode *timecode) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetTimecodeFromComponents(
+ /* [in] */ BMDTimecodeFormat format,
+ /* [in] */ unsigned char hours,
+ /* [in] */ unsigned char minutes,
+ /* [in] */ unsigned char seconds,
+ /* [in] */ unsigned char frames,
+ /* [in] */ BMDTimecodeFlags flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetAncillaryData(
+ /* [in] */ IDeckLinkVideoFrameAncillary *ancillary) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetTimecodeUserBits(
+ /* [in] */ BMDTimecodeFormat format,
+ /* [in] */ BMDTimecodeUserBits userBits) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkMutableVideoFrameVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkMutableVideoFrame * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkMutableVideoFrame * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkMutableVideoFrame * This);
+
+ long ( STDMETHODCALLTYPE *GetWidth )(
+ IDeckLinkMutableVideoFrame * This);
+
+ long ( STDMETHODCALLTYPE *GetHeight )(
+ IDeckLinkMutableVideoFrame * This);
+
+ long ( STDMETHODCALLTYPE *GetRowBytes )(
+ IDeckLinkMutableVideoFrame * This);
+
+ BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )(
+ IDeckLinkMutableVideoFrame * This);
+
+ BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )(
+ IDeckLinkMutableVideoFrame * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBytes )(
+ IDeckLinkMutableVideoFrame * This,
+ /* [out] */ void **buffer);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTimecode )(
+ IDeckLinkMutableVideoFrame * This,
+ /* [in] */ BMDTimecodeFormat format,
+ /* [out] */ IDeckLinkTimecode **timecode);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAncillaryData )(
+ IDeckLinkMutableVideoFrame * This,
+ /* [out] */ IDeckLinkVideoFrameAncillary **ancillary);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFlags )(
+ IDeckLinkMutableVideoFrame * This,
+ /* [in] */ BMDFrameFlags newFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *SetTimecode )(
+ IDeckLinkMutableVideoFrame * This,
+ /* [in] */ BMDTimecodeFormat format,
+ /* [in] */ IDeckLinkTimecode *timecode);
+
+ HRESULT ( STDMETHODCALLTYPE *SetTimecodeFromComponents )(
+ IDeckLinkMutableVideoFrame * This,
+ /* [in] */ BMDTimecodeFormat format,
+ /* [in] */ unsigned char hours,
+ /* [in] */ unsigned char minutes,
+ /* [in] */ unsigned char seconds,
+ /* [in] */ unsigned char frames,
+ /* [in] */ BMDTimecodeFlags flags);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAncillaryData )(
+ IDeckLinkMutableVideoFrame * This,
+ /* [in] */ IDeckLinkVideoFrameAncillary *ancillary);
+
+ HRESULT ( STDMETHODCALLTYPE *SetTimecodeUserBits )(
+ IDeckLinkMutableVideoFrame * This,
+ /* [in] */ BMDTimecodeFormat format,
+ /* [in] */ BMDTimecodeUserBits userBits);
+
+ END_INTERFACE
+ } IDeckLinkMutableVideoFrameVtbl;
+
+ interface IDeckLinkMutableVideoFrame
+ {
+ CONST_VTBL struct IDeckLinkMutableVideoFrameVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkMutableVideoFrame_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkMutableVideoFrame_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkMutableVideoFrame_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkMutableVideoFrame_GetWidth(This) \
+ ( (This)->lpVtbl -> GetWidth(This) )
+
+#define IDeckLinkMutableVideoFrame_GetHeight(This) \
+ ( (This)->lpVtbl -> GetHeight(This) )
+
+#define IDeckLinkMutableVideoFrame_GetRowBytes(This) \
+ ( (This)->lpVtbl -> GetRowBytes(This) )
+
+#define IDeckLinkMutableVideoFrame_GetPixelFormat(This) \
+ ( (This)->lpVtbl -> GetPixelFormat(This) )
+
+#define IDeckLinkMutableVideoFrame_GetFlags(This) \
+ ( (This)->lpVtbl -> GetFlags(This) )
+
+#define IDeckLinkMutableVideoFrame_GetBytes(This,buffer) \
+ ( (This)->lpVtbl -> GetBytes(This,buffer) )
+
+#define IDeckLinkMutableVideoFrame_GetTimecode(This,format,timecode) \
+ ( (This)->lpVtbl -> GetTimecode(This,format,timecode) )
+
+#define IDeckLinkMutableVideoFrame_GetAncillaryData(This,ancillary) \
+ ( (This)->lpVtbl -> GetAncillaryData(This,ancillary) )
+
+
+#define IDeckLinkMutableVideoFrame_SetFlags(This,newFlags) \
+ ( (This)->lpVtbl -> SetFlags(This,newFlags) )
+
+#define IDeckLinkMutableVideoFrame_SetTimecode(This,format,timecode) \
+ ( (This)->lpVtbl -> SetTimecode(This,format,timecode) )
+
+#define IDeckLinkMutableVideoFrame_SetTimecodeFromComponents(This,format,hours,minutes,seconds,frames,flags) \
+ ( (This)->lpVtbl -> SetTimecodeFromComponents(This,format,hours,minutes,seconds,frames,flags) )
+
+#define IDeckLinkMutableVideoFrame_SetAncillaryData(This,ancillary) \
+ ( (This)->lpVtbl -> SetAncillaryData(This,ancillary) )
+
+#define IDeckLinkMutableVideoFrame_SetTimecodeUserBits(This,format,userBits) \
+ ( (This)->lpVtbl -> SetTimecodeUserBits(This,format,userBits) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkMutableVideoFrame_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkVideoFrame3DExtensions_INTERFACE_DEFINED__
+#define __IDeckLinkVideoFrame3DExtensions_INTERFACE_DEFINED__
+
+/* interface IDeckLinkVideoFrame3DExtensions */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkVideoFrame3DExtensions;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("DA0F7E4A-EDC7-48A8-9CDD-2DB51C729CD7")
+ IDeckLinkVideoFrame3DExtensions : public IUnknown
+ {
+ public:
+ virtual BMDVideo3DPackingFormat STDMETHODCALLTYPE Get3DPackingFormat( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFrameForRightEye(
+ /* [out] */ IDeckLinkVideoFrame **rightEyeFrame) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkVideoFrame3DExtensionsVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkVideoFrame3DExtensions * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkVideoFrame3DExtensions * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkVideoFrame3DExtensions * This);
+
+ BMDVideo3DPackingFormat ( STDMETHODCALLTYPE *Get3DPackingFormat )(
+ IDeckLinkVideoFrame3DExtensions * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFrameForRightEye )(
+ IDeckLinkVideoFrame3DExtensions * This,
+ /* [out] */ IDeckLinkVideoFrame **rightEyeFrame);
+
+ END_INTERFACE
+ } IDeckLinkVideoFrame3DExtensionsVtbl;
+
+ interface IDeckLinkVideoFrame3DExtensions
+ {
+ CONST_VTBL struct IDeckLinkVideoFrame3DExtensionsVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkVideoFrame3DExtensions_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkVideoFrame3DExtensions_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkVideoFrame3DExtensions_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkVideoFrame3DExtensions_Get3DPackingFormat(This) \
+ ( (This)->lpVtbl -> Get3DPackingFormat(This) )
+
+#define IDeckLinkVideoFrame3DExtensions_GetFrameForRightEye(This,rightEyeFrame) \
+ ( (This)->lpVtbl -> GetFrameForRightEye(This,rightEyeFrame) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkVideoFrame3DExtensions_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkVideoInputFrame_INTERFACE_DEFINED__
+#define __IDeckLinkVideoInputFrame_INTERFACE_DEFINED__
+
+/* interface IDeckLinkVideoInputFrame */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkVideoInputFrame;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("05CFE374-537C-4094-9A57-680525118F44")
+ IDeckLinkVideoInputFrame : public IDeckLinkVideoFrame
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetStreamTime(
+ /* [out] */ BMDTimeValue *frameTime,
+ /* [out] */ BMDTimeValue *frameDuration,
+ /* [in] */ BMDTimeScale timeScale) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceTimestamp(
+ /* [in] */ BMDTimeScale timeScale,
+ /* [out] */ BMDTimeValue *frameTime,
+ /* [out] */ BMDTimeValue *frameDuration) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkVideoInputFrameVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkVideoInputFrame * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkVideoInputFrame * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkVideoInputFrame * This);
+
+ long ( STDMETHODCALLTYPE *GetWidth )(
+ IDeckLinkVideoInputFrame * This);
+
+ long ( STDMETHODCALLTYPE *GetHeight )(
+ IDeckLinkVideoInputFrame * This);
+
+ long ( STDMETHODCALLTYPE *GetRowBytes )(
+ IDeckLinkVideoInputFrame * This);
+
+ BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )(
+ IDeckLinkVideoInputFrame * This);
+
+ BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )(
+ IDeckLinkVideoInputFrame * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBytes )(
+ IDeckLinkVideoInputFrame * This,
+ /* [out] */ void **buffer);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTimecode )(
+ IDeckLinkVideoInputFrame * This,
+ /* [in] */ BMDTimecodeFormat format,
+ /* [out] */ IDeckLinkTimecode **timecode);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAncillaryData )(
+ IDeckLinkVideoInputFrame * This,
+ /* [out] */ IDeckLinkVideoFrameAncillary **ancillary);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStreamTime )(
+ IDeckLinkVideoInputFrame * This,
+ /* [out] */ BMDTimeValue *frameTime,
+ /* [out] */ BMDTimeValue *frameDuration,
+ /* [in] */ BMDTimeScale timeScale);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceTimestamp )(
+ IDeckLinkVideoInputFrame * This,
+ /* [in] */ BMDTimeScale timeScale,
+ /* [out] */ BMDTimeValue *frameTime,
+ /* [out] */ BMDTimeValue *frameDuration);
+
+ END_INTERFACE
+ } IDeckLinkVideoInputFrameVtbl;
+
+ interface IDeckLinkVideoInputFrame
+ {
+ CONST_VTBL struct IDeckLinkVideoInputFrameVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkVideoInputFrame_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkVideoInputFrame_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkVideoInputFrame_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkVideoInputFrame_GetWidth(This) \
+ ( (This)->lpVtbl -> GetWidth(This) )
+
+#define IDeckLinkVideoInputFrame_GetHeight(This) \
+ ( (This)->lpVtbl -> GetHeight(This) )
+
+#define IDeckLinkVideoInputFrame_GetRowBytes(This) \
+ ( (This)->lpVtbl -> GetRowBytes(This) )
+
+#define IDeckLinkVideoInputFrame_GetPixelFormat(This) \
+ ( (This)->lpVtbl -> GetPixelFormat(This) )
+
+#define IDeckLinkVideoInputFrame_GetFlags(This) \
+ ( (This)->lpVtbl -> GetFlags(This) )
+
+#define IDeckLinkVideoInputFrame_GetBytes(This,buffer) \
+ ( (This)->lpVtbl -> GetBytes(This,buffer) )
+
+#define IDeckLinkVideoInputFrame_GetTimecode(This,format,timecode) \
+ ( (This)->lpVtbl -> GetTimecode(This,format,timecode) )
+
+#define IDeckLinkVideoInputFrame_GetAncillaryData(This,ancillary) \
+ ( (This)->lpVtbl -> GetAncillaryData(This,ancillary) )
+
+
+#define IDeckLinkVideoInputFrame_GetStreamTime(This,frameTime,frameDuration,timeScale) \
+ ( (This)->lpVtbl -> GetStreamTime(This,frameTime,frameDuration,timeScale) )
+
+#define IDeckLinkVideoInputFrame_GetHardwareReferenceTimestamp(This,timeScale,frameTime,frameDuration) \
+ ( (This)->lpVtbl -> GetHardwareReferenceTimestamp(This,timeScale,frameTime,frameDuration) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkVideoInputFrame_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkVideoFrameAncillary_INTERFACE_DEFINED__
+#define __IDeckLinkVideoFrameAncillary_INTERFACE_DEFINED__
+
+/* interface IDeckLinkVideoFrameAncillary */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkVideoFrameAncillary;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("732E723C-D1A4-4E29-9E8E-4A88797A0004")
+ IDeckLinkVideoFrameAncillary : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetBufferForVerticalBlankingLine(
+ /* [in] */ unsigned int lineNumber,
+ /* [out] */ void **buffer) = 0;
+
+ virtual BMDPixelFormat STDMETHODCALLTYPE GetPixelFormat( void) = 0;
+
+ virtual BMDDisplayMode STDMETHODCALLTYPE GetDisplayMode( void) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkVideoFrameAncillaryVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkVideoFrameAncillary * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkVideoFrameAncillary * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkVideoFrameAncillary * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBufferForVerticalBlankingLine )(
+ IDeckLinkVideoFrameAncillary * This,
+ /* [in] */ unsigned int lineNumber,
+ /* [out] */ void **buffer);
+
+ BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )(
+ IDeckLinkVideoFrameAncillary * This);
+
+ BMDDisplayMode ( STDMETHODCALLTYPE *GetDisplayMode )(
+ IDeckLinkVideoFrameAncillary * This);
+
+ END_INTERFACE
+ } IDeckLinkVideoFrameAncillaryVtbl;
+
+ interface IDeckLinkVideoFrameAncillary
+ {
+ CONST_VTBL struct IDeckLinkVideoFrameAncillaryVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkVideoFrameAncillary_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkVideoFrameAncillary_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkVideoFrameAncillary_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkVideoFrameAncillary_GetBufferForVerticalBlankingLine(This,lineNumber,buffer) \
+ ( (This)->lpVtbl -> GetBufferForVerticalBlankingLine(This,lineNumber,buffer) )
+
+#define IDeckLinkVideoFrameAncillary_GetPixelFormat(This) \
+ ( (This)->lpVtbl -> GetPixelFormat(This) )
+
+#define IDeckLinkVideoFrameAncillary_GetDisplayMode(This) \
+ ( (This)->lpVtbl -> GetDisplayMode(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkVideoFrameAncillary_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkAudioInputPacket_INTERFACE_DEFINED__
+#define __IDeckLinkAudioInputPacket_INTERFACE_DEFINED__
+
+/* interface IDeckLinkAudioInputPacket */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkAudioInputPacket;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("E43D5870-2894-11DE-8C30-0800200C9A66")
+ IDeckLinkAudioInputPacket : public IUnknown
+ {
+ public:
+ virtual long STDMETHODCALLTYPE GetSampleFrameCount( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBytes(
+ /* [out] */ void **buffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetPacketTime(
+ /* [out] */ BMDTimeValue *packetTime,
+ /* [in] */ BMDTimeScale timeScale) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkAudioInputPacketVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkAudioInputPacket * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkAudioInputPacket * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkAudioInputPacket * This);
+
+ long ( STDMETHODCALLTYPE *GetSampleFrameCount )(
+ IDeckLinkAudioInputPacket * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBytes )(
+ IDeckLinkAudioInputPacket * This,
+ /* [out] */ void **buffer);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPacketTime )(
+ IDeckLinkAudioInputPacket * This,
+ /* [out] */ BMDTimeValue *packetTime,
+ /* [in] */ BMDTimeScale timeScale);
+
+ END_INTERFACE
+ } IDeckLinkAudioInputPacketVtbl;
+
+ interface IDeckLinkAudioInputPacket
+ {
+ CONST_VTBL struct IDeckLinkAudioInputPacketVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkAudioInputPacket_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkAudioInputPacket_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkAudioInputPacket_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkAudioInputPacket_GetSampleFrameCount(This) \
+ ( (This)->lpVtbl -> GetSampleFrameCount(This) )
+
+#define IDeckLinkAudioInputPacket_GetBytes(This,buffer) \
+ ( (This)->lpVtbl -> GetBytes(This,buffer) )
+
+#define IDeckLinkAudioInputPacket_GetPacketTime(This,packetTime,timeScale) \
+ ( (This)->lpVtbl -> GetPacketTime(This,packetTime,timeScale) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkAudioInputPacket_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkScreenPreviewCallback_INTERFACE_DEFINED__
+#define __IDeckLinkScreenPreviewCallback_INTERFACE_DEFINED__
+
+/* interface IDeckLinkScreenPreviewCallback */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkScreenPreviewCallback;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("B1D3F49A-85FE-4C5D-95C8-0B5D5DCCD438")
+ IDeckLinkScreenPreviewCallback : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE DrawFrame(
+ /* [in] */ IDeckLinkVideoFrame *theFrame) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkScreenPreviewCallbackVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkScreenPreviewCallback * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkScreenPreviewCallback * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkScreenPreviewCallback * This);
+
+ HRESULT ( STDMETHODCALLTYPE *DrawFrame )(
+ IDeckLinkScreenPreviewCallback * This,
+ /* [in] */ IDeckLinkVideoFrame *theFrame);
+
+ END_INTERFACE
+ } IDeckLinkScreenPreviewCallbackVtbl;
+
+ interface IDeckLinkScreenPreviewCallback
+ {
+ CONST_VTBL struct IDeckLinkScreenPreviewCallbackVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkScreenPreviewCallback_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkScreenPreviewCallback_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkScreenPreviewCallback_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkScreenPreviewCallback_DrawFrame(This,theFrame) \
+ ( (This)->lpVtbl -> DrawFrame(This,theFrame) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkScreenPreviewCallback_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkGLScreenPreviewHelper_INTERFACE_DEFINED__
+#define __IDeckLinkGLScreenPreviewHelper_INTERFACE_DEFINED__
+
+/* interface IDeckLinkGLScreenPreviewHelper */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkGLScreenPreviewHelper;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("504E2209-CAC7-4C1A-9FB4-C5BB6274D22F")
+ IDeckLinkGLScreenPreviewHelper : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE InitializeGL( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE PaintGL( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetFrame(
+ /* [in] */ IDeckLinkVideoFrame *theFrame) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Set3DPreviewFormat(
+ /* [in] */ BMD3DPreviewFormat previewFormat) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkGLScreenPreviewHelperVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkGLScreenPreviewHelper * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkGLScreenPreviewHelper * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkGLScreenPreviewHelper * This);
+
+ HRESULT ( STDMETHODCALLTYPE *InitializeGL )(
+ IDeckLinkGLScreenPreviewHelper * This);
+
+ HRESULT ( STDMETHODCALLTYPE *PaintGL )(
+ IDeckLinkGLScreenPreviewHelper * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFrame )(
+ IDeckLinkGLScreenPreviewHelper * This,
+ /* [in] */ IDeckLinkVideoFrame *theFrame);
+
+ HRESULT ( STDMETHODCALLTYPE *Set3DPreviewFormat )(
+ IDeckLinkGLScreenPreviewHelper * This,
+ /* [in] */ BMD3DPreviewFormat previewFormat);
+
+ END_INTERFACE
+ } IDeckLinkGLScreenPreviewHelperVtbl;
+
+ interface IDeckLinkGLScreenPreviewHelper
+ {
+ CONST_VTBL struct IDeckLinkGLScreenPreviewHelperVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkGLScreenPreviewHelper_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkGLScreenPreviewHelper_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkGLScreenPreviewHelper_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkGLScreenPreviewHelper_InitializeGL(This) \
+ ( (This)->lpVtbl -> InitializeGL(This) )
+
+#define IDeckLinkGLScreenPreviewHelper_PaintGL(This) \
+ ( (This)->lpVtbl -> PaintGL(This) )
+
+#define IDeckLinkGLScreenPreviewHelper_SetFrame(This,theFrame) \
+ ( (This)->lpVtbl -> SetFrame(This,theFrame) )
+
+#define IDeckLinkGLScreenPreviewHelper_Set3DPreviewFormat(This,previewFormat) \
+ ( (This)->lpVtbl -> Set3DPreviewFormat(This,previewFormat) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkGLScreenPreviewHelper_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkDX9ScreenPreviewHelper_INTERFACE_DEFINED__
+#define __IDeckLinkDX9ScreenPreviewHelper_INTERFACE_DEFINED__
+
+/* interface IDeckLinkDX9ScreenPreviewHelper */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkDX9ScreenPreviewHelper;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("2094B522-D1A1-40C0-9AC7-1C012218EF02")
+ IDeckLinkDX9ScreenPreviewHelper : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Initialize(
+ /* [in] */ void *device) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Render(
+ /* [in] */ RECT *rc) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetFrame(
+ /* [in] */ IDeckLinkVideoFrame *theFrame) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Set3DPreviewFormat(
+ /* [in] */ BMD3DPreviewFormat previewFormat) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkDX9ScreenPreviewHelperVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkDX9ScreenPreviewHelper * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkDX9ScreenPreviewHelper * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkDX9ScreenPreviewHelper * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Initialize )(
+ IDeckLinkDX9ScreenPreviewHelper * This,
+ /* [in] */ void *device);
+
+ HRESULT ( STDMETHODCALLTYPE *Render )(
+ IDeckLinkDX9ScreenPreviewHelper * This,
+ /* [in] */ RECT *rc);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFrame )(
+ IDeckLinkDX9ScreenPreviewHelper * This,
+ /* [in] */ IDeckLinkVideoFrame *theFrame);
+
+ HRESULT ( STDMETHODCALLTYPE *Set3DPreviewFormat )(
+ IDeckLinkDX9ScreenPreviewHelper * This,
+ /* [in] */ BMD3DPreviewFormat previewFormat);
+
+ END_INTERFACE
+ } IDeckLinkDX9ScreenPreviewHelperVtbl;
+
+ interface IDeckLinkDX9ScreenPreviewHelper
+ {
+ CONST_VTBL struct IDeckLinkDX9ScreenPreviewHelperVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkDX9ScreenPreviewHelper_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkDX9ScreenPreviewHelper_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkDX9ScreenPreviewHelper_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkDX9ScreenPreviewHelper_Initialize(This,device) \
+ ( (This)->lpVtbl -> Initialize(This,device) )
+
+#define IDeckLinkDX9ScreenPreviewHelper_Render(This,rc) \
+ ( (This)->lpVtbl -> Render(This,rc) )
+
+#define IDeckLinkDX9ScreenPreviewHelper_SetFrame(This,theFrame) \
+ ( (This)->lpVtbl -> SetFrame(This,theFrame) )
+
+#define IDeckLinkDX9ScreenPreviewHelper_Set3DPreviewFormat(This,previewFormat) \
+ ( (This)->lpVtbl -> Set3DPreviewFormat(This,previewFormat) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkDX9ScreenPreviewHelper_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkNotificationCallback_INTERFACE_DEFINED__
+#define __IDeckLinkNotificationCallback_INTERFACE_DEFINED__
+
+/* interface IDeckLinkNotificationCallback */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkNotificationCallback;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("b002a1ec-070d-4288-8289-bd5d36e5ff0d")
+ IDeckLinkNotificationCallback : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Notify(
+ /* [in] */ BMDNotifications topic,
+ /* [in] */ ULONGLONG param1,
+ /* [in] */ ULONGLONG param2) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkNotificationCallbackVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkNotificationCallback * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkNotificationCallback * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkNotificationCallback * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Notify )(
+ IDeckLinkNotificationCallback * This,
+ /* [in] */ BMDNotifications topic,
+ /* [in] */ ULONGLONG param1,
+ /* [in] */ ULONGLONG param2);
+
+ END_INTERFACE
+ } IDeckLinkNotificationCallbackVtbl;
+
+ interface IDeckLinkNotificationCallback
+ {
+ CONST_VTBL struct IDeckLinkNotificationCallbackVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkNotificationCallback_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkNotificationCallback_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkNotificationCallback_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkNotificationCallback_Notify(This,topic,param1,param2) \
+ ( (This)->lpVtbl -> Notify(This,topic,param1,param2) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkNotificationCallback_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkNotification_INTERFACE_DEFINED__
+#define __IDeckLinkNotification_INTERFACE_DEFINED__
+
+/* interface IDeckLinkNotification */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkNotification;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("0a1fb207-e215-441b-9b19-6fa1575946c5")
+ IDeckLinkNotification : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Subscribe(
+ /* [in] */ BMDNotifications topic,
+ /* [in] */ IDeckLinkNotificationCallback *theCallback) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Unsubscribe(
+ /* [in] */ BMDNotifications topic,
+ /* [in] */ IDeckLinkNotificationCallback *theCallback) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkNotificationVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkNotification * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkNotification * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkNotification * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Subscribe )(
+ IDeckLinkNotification * This,
+ /* [in] */ BMDNotifications topic,
+ /* [in] */ IDeckLinkNotificationCallback *theCallback);
+
+ HRESULT ( STDMETHODCALLTYPE *Unsubscribe )(
+ IDeckLinkNotification * This,
+ /* [in] */ BMDNotifications topic,
+ /* [in] */ IDeckLinkNotificationCallback *theCallback);
+
+ END_INTERFACE
+ } IDeckLinkNotificationVtbl;
+
+ interface IDeckLinkNotification
+ {
+ CONST_VTBL struct IDeckLinkNotificationVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkNotification_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkNotification_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkNotification_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkNotification_Subscribe(This,topic,theCallback) \
+ ( (This)->lpVtbl -> Subscribe(This,topic,theCallback) )
+
+#define IDeckLinkNotification_Unsubscribe(This,topic,theCallback) \
+ ( (This)->lpVtbl -> Unsubscribe(This,topic,theCallback) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkNotification_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkAttributes_INTERFACE_DEFINED__
+#define __IDeckLinkAttributes_INTERFACE_DEFINED__
+
+/* interface IDeckLinkAttributes */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkAttributes;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("ABC11843-D966-44CB-96E2-A1CB5D3135C4")
+ IDeckLinkAttributes : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetFlag(
+ /* [in] */ BMDDeckLinkAttributeID cfgID,
+ /* [out] */ BOOL *value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetInt(
+ /* [in] */ BMDDeckLinkAttributeID cfgID,
+ /* [out] */ LONGLONG *value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFloat(
+ /* [in] */ BMDDeckLinkAttributeID cfgID,
+ /* [out] */ double *value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetString(
+ /* [in] */ BMDDeckLinkAttributeID cfgID,
+ /* [out] */ BSTR *value) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkAttributesVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkAttributes * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkAttributes * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkAttributes * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFlag )(
+ IDeckLinkAttributes * This,
+ /* [in] */ BMDDeckLinkAttributeID cfgID,
+ /* [out] */ BOOL *value);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInt )(
+ IDeckLinkAttributes * This,
+ /* [in] */ BMDDeckLinkAttributeID cfgID,
+ /* [out] */ LONGLONG *value);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFloat )(
+ IDeckLinkAttributes * This,
+ /* [in] */ BMDDeckLinkAttributeID cfgID,
+ /* [out] */ double *value);
+
+ HRESULT ( STDMETHODCALLTYPE *GetString )(
+ IDeckLinkAttributes * This,
+ /* [in] */ BMDDeckLinkAttributeID cfgID,
+ /* [out] */ BSTR *value);
+
+ END_INTERFACE
+ } IDeckLinkAttributesVtbl;
+
+ interface IDeckLinkAttributes
+ {
+ CONST_VTBL struct IDeckLinkAttributesVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkAttributes_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkAttributes_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkAttributes_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkAttributes_GetFlag(This,cfgID,value) \
+ ( (This)->lpVtbl -> GetFlag(This,cfgID,value) )
+
+#define IDeckLinkAttributes_GetInt(This,cfgID,value) \
+ ( (This)->lpVtbl -> GetInt(This,cfgID,value) )
+
+#define IDeckLinkAttributes_GetFloat(This,cfgID,value) \
+ ( (This)->lpVtbl -> GetFloat(This,cfgID,value) )
+
+#define IDeckLinkAttributes_GetString(This,cfgID,value) \
+ ( (This)->lpVtbl -> GetString(This,cfgID,value) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkAttributes_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkKeyer_INTERFACE_DEFINED__
+#define __IDeckLinkKeyer_INTERFACE_DEFINED__
+
+/* interface IDeckLinkKeyer */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkKeyer;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("89AFCAF5-65F8-421E-98F7-96FE5F5BFBA3")
+ IDeckLinkKeyer : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Enable(
+ /* [in] */ BOOL isExternal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetLevel(
+ /* [in] */ unsigned char level) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RampUp(
+ /* [in] */ unsigned int numberOfFrames) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RampDown(
+ /* [in] */ unsigned int numberOfFrames) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Disable( void) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkKeyerVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkKeyer * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkKeyer * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkKeyer * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Enable )(
+ IDeckLinkKeyer * This,
+ /* [in] */ BOOL isExternal);
+
+ HRESULT ( STDMETHODCALLTYPE *SetLevel )(
+ IDeckLinkKeyer * This,
+ /* [in] */ unsigned char level);
+
+ HRESULT ( STDMETHODCALLTYPE *RampUp )(
+ IDeckLinkKeyer * This,
+ /* [in] */ unsigned int numberOfFrames);
+
+ HRESULT ( STDMETHODCALLTYPE *RampDown )(
+ IDeckLinkKeyer * This,
+ /* [in] */ unsigned int numberOfFrames);
+
+ HRESULT ( STDMETHODCALLTYPE *Disable )(
+ IDeckLinkKeyer * This);
+
+ END_INTERFACE
+ } IDeckLinkKeyerVtbl;
+
+ interface IDeckLinkKeyer
+ {
+ CONST_VTBL struct IDeckLinkKeyerVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkKeyer_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkKeyer_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkKeyer_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkKeyer_Enable(This,isExternal) \
+ ( (This)->lpVtbl -> Enable(This,isExternal) )
+
+#define IDeckLinkKeyer_SetLevel(This,level) \
+ ( (This)->lpVtbl -> SetLevel(This,level) )
+
+#define IDeckLinkKeyer_RampUp(This,numberOfFrames) \
+ ( (This)->lpVtbl -> RampUp(This,numberOfFrames) )
+
+#define IDeckLinkKeyer_RampDown(This,numberOfFrames) \
+ ( (This)->lpVtbl -> RampDown(This,numberOfFrames) )
+
+#define IDeckLinkKeyer_Disable(This) \
+ ( (This)->lpVtbl -> Disable(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkKeyer_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkVideoConversion_INTERFACE_DEFINED__
+#define __IDeckLinkVideoConversion_INTERFACE_DEFINED__
+
+/* interface IDeckLinkVideoConversion */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkVideoConversion;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("3BBCB8A2-DA2C-42D9-B5D8-88083644E99A")
+ IDeckLinkVideoConversion : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE ConvertFrame(
+ /* [in] */ IDeckLinkVideoFrame *srcFrame,
+ /* [in] */ IDeckLinkVideoFrame *dstFrame) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkVideoConversionVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkVideoConversion * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkVideoConversion * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkVideoConversion * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ConvertFrame )(
+ IDeckLinkVideoConversion * This,
+ /* [in] */ IDeckLinkVideoFrame *srcFrame,
+ /* [in] */ IDeckLinkVideoFrame *dstFrame);
+
+ END_INTERFACE
+ } IDeckLinkVideoConversionVtbl;
+
+ interface IDeckLinkVideoConversion
+ {
+ CONST_VTBL struct IDeckLinkVideoConversionVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkVideoConversion_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkVideoConversion_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkVideoConversion_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkVideoConversion_ConvertFrame(This,srcFrame,dstFrame) \
+ ( (This)->lpVtbl -> ConvertFrame(This,srcFrame,dstFrame) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkVideoConversion_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkDeviceNotificationCallback_INTERFACE_DEFINED__
+#define __IDeckLinkDeviceNotificationCallback_INTERFACE_DEFINED__
+
+/* interface IDeckLinkDeviceNotificationCallback */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkDeviceNotificationCallback;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("4997053B-0ADF-4CC8-AC70-7A50C4BE728F")
+ IDeckLinkDeviceNotificationCallback : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE DeckLinkDeviceArrived(
+ /* [in] */ IDeckLink *deckLinkDevice) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DeckLinkDeviceRemoved(
+ /* [in] */ IDeckLink *deckLinkDevice) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkDeviceNotificationCallbackVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkDeviceNotificationCallback * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkDeviceNotificationCallback * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkDeviceNotificationCallback * This);
+
+ HRESULT ( STDMETHODCALLTYPE *DeckLinkDeviceArrived )(
+ IDeckLinkDeviceNotificationCallback * This,
+ /* [in] */ IDeckLink *deckLinkDevice);
+
+ HRESULT ( STDMETHODCALLTYPE *DeckLinkDeviceRemoved )(
+ IDeckLinkDeviceNotificationCallback * This,
+ /* [in] */ IDeckLink *deckLinkDevice);
+
+ END_INTERFACE
+ } IDeckLinkDeviceNotificationCallbackVtbl;
+
+ interface IDeckLinkDeviceNotificationCallback
+ {
+ CONST_VTBL struct IDeckLinkDeviceNotificationCallbackVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkDeviceNotificationCallback_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkDeviceNotificationCallback_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkDeviceNotificationCallback_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkDeviceNotificationCallback_DeckLinkDeviceArrived(This,deckLinkDevice) \
+ ( (This)->lpVtbl -> DeckLinkDeviceArrived(This,deckLinkDevice) )
+
+#define IDeckLinkDeviceNotificationCallback_DeckLinkDeviceRemoved(This,deckLinkDevice) \
+ ( (This)->lpVtbl -> DeckLinkDeviceRemoved(This,deckLinkDevice) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkDeviceNotificationCallback_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkDiscovery_INTERFACE_DEFINED__
+#define __IDeckLinkDiscovery_INTERFACE_DEFINED__
+
+/* interface IDeckLinkDiscovery */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkDiscovery;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CDBF631C-BC76-45FA-B44D-C55059BC6101")
+ IDeckLinkDiscovery : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE InstallDeviceNotifications(
+ /* [in] */ IDeckLinkDeviceNotificationCallback *deviceNotificationCallback) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE UninstallDeviceNotifications( void) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkDiscoveryVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkDiscovery * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkDiscovery * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkDiscovery * This);
+
+ HRESULT ( STDMETHODCALLTYPE *InstallDeviceNotifications )(
+ IDeckLinkDiscovery * This,
+ /* [in] */ IDeckLinkDeviceNotificationCallback *deviceNotificationCallback);
+
+ HRESULT ( STDMETHODCALLTYPE *UninstallDeviceNotifications )(
+ IDeckLinkDiscovery * This);
+
+ END_INTERFACE
+ } IDeckLinkDiscoveryVtbl;
+
+ interface IDeckLinkDiscovery
+ {
+ CONST_VTBL struct IDeckLinkDiscoveryVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkDiscovery_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkDiscovery_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkDiscovery_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkDiscovery_InstallDeviceNotifications(This,deviceNotificationCallback) \
+ ( (This)->lpVtbl -> InstallDeviceNotifications(This,deviceNotificationCallback) )
+
+#define IDeckLinkDiscovery_UninstallDeviceNotifications(This) \
+ ( (This)->lpVtbl -> UninstallDeviceNotifications(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkDiscovery_INTERFACE_DEFINED__ */
+
+
+EXTERN_C const CLSID CLSID_CDeckLinkIterator;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("1F2E109A-8F4F-49E4-9203-135595CB6FA5")
+CDeckLinkIterator;
+#endif
+
+EXTERN_C const CLSID CLSID_CDeckLinkAPIInformation;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("263CA19F-ED09-482E-9F9D-84005783A237")
+CDeckLinkAPIInformation;
+#endif
+
+EXTERN_C const CLSID CLSID_CDeckLinkGLScreenPreviewHelper;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("F63E77C7-B655-4A4A-9AD0-3CA85D394343")
+CDeckLinkGLScreenPreviewHelper;
+#endif
+
+EXTERN_C const CLSID CLSID_CDeckLinkDX9ScreenPreviewHelper;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("CC010023-E01D-4525-9D59-80C8AB3DC7A0")
+CDeckLinkDX9ScreenPreviewHelper;
+#endif
+
+EXTERN_C const CLSID CLSID_CDeckLinkVideoConversion;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("7DBBBB11-5B7B-467D-AEA4-CEA468FD368C")
+CDeckLinkVideoConversion;
+#endif
+
+EXTERN_C const CLSID CLSID_CDeckLinkDiscovery;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("1073A05C-D885-47E9-B3C6-129B3F9F648B")
+CDeckLinkDiscovery;
+#endif
+
+#ifndef __IDeckLinkConfiguration_v10_2_INTERFACE_DEFINED__
+#define __IDeckLinkConfiguration_v10_2_INTERFACE_DEFINED__
+
+/* interface IDeckLinkConfiguration_v10_2 */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkConfiguration_v10_2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("C679A35B-610C-4D09-B748-1D0478100FC0")
+ IDeckLinkConfiguration_v10_2 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetFlag(
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [in] */ BOOL value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFlag(
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [out] */ BOOL *value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetInt(
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [in] */ LONGLONG value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetInt(
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [out] */ LONGLONG *value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetFloat(
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [in] */ double value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFloat(
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [out] */ double *value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetString(
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [in] */ BSTR value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetString(
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [out] */ BSTR *value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteConfigurationToPreferences( void) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkConfiguration_v10_2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkConfiguration_v10_2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkConfiguration_v10_2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkConfiguration_v10_2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFlag )(
+ IDeckLinkConfiguration_v10_2 * This,
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [in] */ BOOL value);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFlag )(
+ IDeckLinkConfiguration_v10_2 * This,
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [out] */ BOOL *value);
+
+ HRESULT ( STDMETHODCALLTYPE *SetInt )(
+ IDeckLinkConfiguration_v10_2 * This,
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [in] */ LONGLONG value);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInt )(
+ IDeckLinkConfiguration_v10_2 * This,
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [out] */ LONGLONG *value);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFloat )(
+ IDeckLinkConfiguration_v10_2 * This,
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [in] */ double value);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFloat )(
+ IDeckLinkConfiguration_v10_2 * This,
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [out] */ double *value);
+
+ HRESULT ( STDMETHODCALLTYPE *SetString )(
+ IDeckLinkConfiguration_v10_2 * This,
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [in] */ BSTR value);
+
+ HRESULT ( STDMETHODCALLTYPE *GetString )(
+ IDeckLinkConfiguration_v10_2 * This,
+ /* [in] */ BMDDeckLinkConfigurationID cfgID,
+ /* [out] */ BSTR *value);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteConfigurationToPreferences )(
+ IDeckLinkConfiguration_v10_2 * This);
+
+ END_INTERFACE
+ } IDeckLinkConfiguration_v10_2Vtbl;
+
+ interface IDeckLinkConfiguration_v10_2
+ {
+ CONST_VTBL struct IDeckLinkConfiguration_v10_2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkConfiguration_v10_2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkConfiguration_v10_2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkConfiguration_v10_2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkConfiguration_v10_2_SetFlag(This,cfgID,value) \
+ ( (This)->lpVtbl -> SetFlag(This,cfgID,value) )
+
+#define IDeckLinkConfiguration_v10_2_GetFlag(This,cfgID,value) \
+ ( (This)->lpVtbl -> GetFlag(This,cfgID,value) )
+
+#define IDeckLinkConfiguration_v10_2_SetInt(This,cfgID,value) \
+ ( (This)->lpVtbl -> SetInt(This,cfgID,value) )
+
+#define IDeckLinkConfiguration_v10_2_GetInt(This,cfgID,value) \
+ ( (This)->lpVtbl -> GetInt(This,cfgID,value) )
+
+#define IDeckLinkConfiguration_v10_2_SetFloat(This,cfgID,value) \
+ ( (This)->lpVtbl -> SetFloat(This,cfgID,value) )
+
+#define IDeckLinkConfiguration_v10_2_GetFloat(This,cfgID,value) \
+ ( (This)->lpVtbl -> GetFloat(This,cfgID,value) )
+
+#define IDeckLinkConfiguration_v10_2_SetString(This,cfgID,value) \
+ ( (This)->lpVtbl -> SetString(This,cfgID,value) )
+
+#define IDeckLinkConfiguration_v10_2_GetString(This,cfgID,value) \
+ ( (This)->lpVtbl -> GetString(This,cfgID,value) )
+
+#define IDeckLinkConfiguration_v10_2_WriteConfigurationToPreferences(This) \
+ ( (This)->lpVtbl -> WriteConfigurationToPreferences(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkConfiguration_v10_2_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkOutput_v9_9_INTERFACE_DEFINED__
+#define __IDeckLinkOutput_v9_9_INTERFACE_DEFINED__
+
+/* interface IDeckLinkOutput_v9_9 */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkOutput_v9_9;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("A3EF0963-0862-44ED-92A9-EE89ABF431C7")
+ IDeckLinkOutput_v9_9 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode(
+ /* [in] */ BMDDisplayMode displayMode,
+ /* [in] */ BMDPixelFormat pixelFormat,
+ /* [in] */ BMDVideoOutputFlags flags,
+ /* [out] */ BMDDisplayModeSupport *result,
+ /* [out] */ IDeckLinkDisplayMode **resultDisplayMode) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator(
+ /* [out] */ IDeckLinkDisplayModeIterator **iterator) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetScreenPreviewCallback(
+ /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnableVideoOutput(
+ /* [in] */ BMDDisplayMode displayMode,
+ /* [in] */ BMDVideoOutputFlags flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DisableVideoOutput( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetVideoOutputFrameMemoryAllocator(
+ /* [in] */ IDeckLinkMemoryAllocator *theAllocator) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateVideoFrame(
+ /* [in] */ int width,
+ /* [in] */ int height,
+ /* [in] */ int rowBytes,
+ /* [in] */ BMDPixelFormat pixelFormat,
+ /* [in] */ BMDFrameFlags flags,
+ /* [out] */ IDeckLinkMutableVideoFrame **outFrame) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateAncillaryData(
+ /* [in] */ BMDPixelFormat pixelFormat,
+ /* [out] */ IDeckLinkVideoFrameAncillary **outBuffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DisplayVideoFrameSync(
+ /* [in] */ IDeckLinkVideoFrame *theFrame) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ScheduleVideoFrame(
+ /* [in] */ IDeckLinkVideoFrame *theFrame,
+ /* [in] */ BMDTimeValue displayTime,
+ /* [in] */ BMDTimeValue displayDuration,
+ /* [in] */ BMDTimeScale timeScale) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetScheduledFrameCompletionCallback(
+ /* [in] */ IDeckLinkVideoOutputCallback *theCallback) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBufferedVideoFrameCount(
+ /* [out] */ unsigned int *bufferedFrameCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnableAudioOutput(
+ /* [in] */ BMDAudioSampleRate sampleRate,
+ /* [in] */ BMDAudioSampleType sampleType,
+ /* [in] */ unsigned int channelCount,
+ /* [in] */ BMDAudioOutputStreamType streamType) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DisableAudioOutput( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteAudioSamplesSync(
+ /* [in] */ void *buffer,
+ /* [in] */ unsigned int sampleFrameCount,
+ /* [out] */ unsigned int *sampleFramesWritten) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE BeginAudioPreroll( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndAudioPreroll( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ScheduleAudioSamples(
+ /* [in] */ void *buffer,
+ /* [in] */ unsigned int sampleFrameCount,
+ /* [in] */ BMDTimeValue streamTime,
+ /* [in] */ BMDTimeScale timeScale,
+ /* [out] */ unsigned int *sampleFramesWritten) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBufferedAudioSampleFrameCount(
+ /* [out] */ unsigned int *bufferedSampleFrameCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FlushBufferedAudioSamples( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetAudioCallback(
+ /* [in] */ IDeckLinkAudioOutputCallback *theCallback) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartScheduledPlayback(
+ /* [in] */ BMDTimeValue playbackStartTime,
+ /* [in] */ BMDTimeScale timeScale,
+ /* [in] */ double playbackSpeed) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StopScheduledPlayback(
+ /* [in] */ BMDTimeValue stopPlaybackAtTime,
+ /* [out] */ BMDTimeValue *actualStopTime,
+ /* [in] */ BMDTimeScale timeScale) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsScheduledPlaybackRunning(
+ /* [out] */ BOOL *active) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetScheduledStreamTime(
+ /* [in] */ BMDTimeScale desiredTimeScale,
+ /* [out] */ BMDTimeValue *streamTime,
+ /* [out] */ double *playbackSpeed) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetReferenceStatus(
+ /* [out] */ BMDReferenceStatus *referenceStatus) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceClock(
+ /* [in] */ BMDTimeScale desiredTimeScale,
+ /* [out] */ BMDTimeValue *hardwareTime,
+ /* [out] */ BMDTimeValue *timeInFrame,
+ /* [out] */ BMDTimeValue *ticksPerFrame) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkOutput_v9_9Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkOutput_v9_9 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkOutput_v9_9 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkOutput_v9_9 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )(
+ IDeckLinkOutput_v9_9 * This,
+ /* [in] */ BMDDisplayMode displayMode,
+ /* [in] */ BMDPixelFormat pixelFormat,
+ /* [in] */ BMDVideoOutputFlags flags,
+ /* [out] */ BMDDisplayModeSupport *result,
+ /* [out] */ IDeckLinkDisplayMode **resultDisplayMode);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )(
+ IDeckLinkOutput_v9_9 * This,
+ /* [out] */ IDeckLinkDisplayModeIterator **iterator);
+
+ HRESULT ( STDMETHODCALLTYPE *SetScreenPreviewCallback )(
+ IDeckLinkOutput_v9_9 * This,
+ /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback);
+
+ HRESULT ( STDMETHODCALLTYPE *EnableVideoOutput )(
+ IDeckLinkOutput_v9_9 * This,
+ /* [in] */ BMDDisplayMode displayMode,
+ /* [in] */ BMDVideoOutputFlags flags);
+
+ HRESULT ( STDMETHODCALLTYPE *DisableVideoOutput )(
+ IDeckLinkOutput_v9_9 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetVideoOutputFrameMemoryAllocator )(
+ IDeckLinkOutput_v9_9 * This,
+ /* [in] */ IDeckLinkMemoryAllocator *theAllocator);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateVideoFrame )(
+ IDeckLinkOutput_v9_9 * This,
+ /* [in] */ int width,
+ /* [in] */ int height,
+ /* [in] */ int rowBytes,
+ /* [in] */ BMDPixelFormat pixelFormat,
+ /* [in] */ BMDFrameFlags flags,
+ /* [out] */ IDeckLinkMutableVideoFrame **outFrame);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateAncillaryData )(
+ IDeckLinkOutput_v9_9 * This,
+ /* [in] */ BMDPixelFormat pixelFormat,
+ /* [out] */ IDeckLinkVideoFrameAncillary **outBuffer);
+
+ HRESULT ( STDMETHODCALLTYPE *DisplayVideoFrameSync )(
+ IDeckLinkOutput_v9_9 * This,
+ /* [in] */ IDeckLinkVideoFrame *theFrame);
+
+ HRESULT ( STDMETHODCALLTYPE *ScheduleVideoFrame )(
+ IDeckLinkOutput_v9_9 * This,
+ /* [in] */ IDeckLinkVideoFrame *theFrame,
+ /* [in] */ BMDTimeValue displayTime,
+ /* [in] */ BMDTimeValue displayDuration,
+ /* [in] */ BMDTimeScale timeScale);
+
+ HRESULT ( STDMETHODCALLTYPE *SetScheduledFrameCompletionCallback )(
+ IDeckLinkOutput_v9_9 * This,
+ /* [in] */ IDeckLinkVideoOutputCallback *theCallback);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBufferedVideoFrameCount )(
+ IDeckLinkOutput_v9_9 * This,
+ /* [out] */ unsigned int *bufferedFrameCount);
+
+ HRESULT ( STDMETHODCALLTYPE *EnableAudioOutput )(
+ IDeckLinkOutput_v9_9 * This,
+ /* [in] */ BMDAudioSampleRate sampleRate,
+ /* [in] */ BMDAudioSampleType sampleType,
+ /* [in] */ unsigned int channelCount,
+ /* [in] */ BMDAudioOutputStreamType streamType);
+
+ HRESULT ( STDMETHODCALLTYPE *DisableAudioOutput )(
+ IDeckLinkOutput_v9_9 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteAudioSamplesSync )(
+ IDeckLinkOutput_v9_9 * This,
+ /* [in] */ void *buffer,
+ /* [in] */ unsigned int sampleFrameCount,
+ /* [out] */ unsigned int *sampleFramesWritten);
+
+ HRESULT ( STDMETHODCALLTYPE *BeginAudioPreroll )(
+ IDeckLinkOutput_v9_9 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *EndAudioPreroll )(
+ IDeckLinkOutput_v9_9 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ScheduleAudioSamples )(
+ IDeckLinkOutput_v9_9 * This,
+ /* [in] */ void *buffer,
+ /* [in] */ unsigned int sampleFrameCount,
+ /* [in] */ BMDTimeValue streamTime,
+ /* [in] */ BMDTimeScale timeScale,
+ /* [out] */ unsigned int *sampleFramesWritten);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBufferedAudioSampleFrameCount )(
+ IDeckLinkOutput_v9_9 * This,
+ /* [out] */ unsigned int *bufferedSampleFrameCount);
+
+ HRESULT ( STDMETHODCALLTYPE *FlushBufferedAudioSamples )(
+ IDeckLinkOutput_v9_9 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAudioCallback )(
+ IDeckLinkOutput_v9_9 * This,
+ /* [in] */ IDeckLinkAudioOutputCallback *theCallback);
+
+ HRESULT ( STDMETHODCALLTYPE *StartScheduledPlayback )(
+ IDeckLinkOutput_v9_9 * This,
+ /* [in] */ BMDTimeValue playbackStartTime,
+ /* [in] */ BMDTimeScale timeScale,
+ /* [in] */ double playbackSpeed);
+
+ HRESULT ( STDMETHODCALLTYPE *StopScheduledPlayback )(
+ IDeckLinkOutput_v9_9 * This,
+ /* [in] */ BMDTimeValue stopPlaybackAtTime,
+ /* [out] */ BMDTimeValue *actualStopTime,
+ /* [in] */ BMDTimeScale timeScale);
+
+ HRESULT ( STDMETHODCALLTYPE *IsScheduledPlaybackRunning )(
+ IDeckLinkOutput_v9_9 * This,
+ /* [out] */ BOOL *active);
+
+ HRESULT ( STDMETHODCALLTYPE *GetScheduledStreamTime )(
+ IDeckLinkOutput_v9_9 * This,
+ /* [in] */ BMDTimeScale desiredTimeScale,
+ /* [out] */ BMDTimeValue *streamTime,
+ /* [out] */ double *playbackSpeed);
+
+ HRESULT ( STDMETHODCALLTYPE *GetReferenceStatus )(
+ IDeckLinkOutput_v9_9 * This,
+ /* [out] */ BMDReferenceStatus *referenceStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceClock )(
+ IDeckLinkOutput_v9_9 * This,
+ /* [in] */ BMDTimeScale desiredTimeScale,
+ /* [out] */ BMDTimeValue *hardwareTime,
+ /* [out] */ BMDTimeValue *timeInFrame,
+ /* [out] */ BMDTimeValue *ticksPerFrame);
+
+ END_INTERFACE
+ } IDeckLinkOutput_v9_9Vtbl;
+
+ interface IDeckLinkOutput_v9_9
+ {
+ CONST_VTBL struct IDeckLinkOutput_v9_9Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkOutput_v9_9_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkOutput_v9_9_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkOutput_v9_9_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkOutput_v9_9_DoesSupportVideoMode(This,displayMode,pixelFormat,flags,result,resultDisplayMode) \
+ ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,flags,result,resultDisplayMode) )
+
+#define IDeckLinkOutput_v9_9_GetDisplayModeIterator(This,iterator) \
+ ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) )
+
+#define IDeckLinkOutput_v9_9_SetScreenPreviewCallback(This,previewCallback) \
+ ( (This)->lpVtbl -> SetScreenPreviewCallback(This,previewCallback) )
+
+#define IDeckLinkOutput_v9_9_EnableVideoOutput(This,displayMode,flags) \
+ ( (This)->lpVtbl -> EnableVideoOutput(This,displayMode,flags) )
+
+#define IDeckLinkOutput_v9_9_DisableVideoOutput(This) \
+ ( (This)->lpVtbl -> DisableVideoOutput(This) )
+
+#define IDeckLinkOutput_v9_9_SetVideoOutputFrameMemoryAllocator(This,theAllocator) \
+ ( (This)->lpVtbl -> SetVideoOutputFrameMemoryAllocator(This,theAllocator) )
+
+#define IDeckLinkOutput_v9_9_CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) \
+ ( (This)->lpVtbl -> CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) )
+
+#define IDeckLinkOutput_v9_9_CreateAncillaryData(This,pixelFormat,outBuffer) \
+ ( (This)->lpVtbl -> CreateAncillaryData(This,pixelFormat,outBuffer) )
+
+#define IDeckLinkOutput_v9_9_DisplayVideoFrameSync(This,theFrame) \
+ ( (This)->lpVtbl -> DisplayVideoFrameSync(This,theFrame) )
+
+#define IDeckLinkOutput_v9_9_ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) \
+ ( (This)->lpVtbl -> ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) )
+
+#define IDeckLinkOutput_v9_9_SetScheduledFrameCompletionCallback(This,theCallback) \
+ ( (This)->lpVtbl -> SetScheduledFrameCompletionCallback(This,theCallback) )
+
+#define IDeckLinkOutput_v9_9_GetBufferedVideoFrameCount(This,bufferedFrameCount) \
+ ( (This)->lpVtbl -> GetBufferedVideoFrameCount(This,bufferedFrameCount) )
+
+#define IDeckLinkOutput_v9_9_EnableAudioOutput(This,sampleRate,sampleType,channelCount,streamType) \
+ ( (This)->lpVtbl -> EnableAudioOutput(This,sampleRate,sampleType,channelCount,streamType) )
+
+#define IDeckLinkOutput_v9_9_DisableAudioOutput(This) \
+ ( (This)->lpVtbl -> DisableAudioOutput(This) )
+
+#define IDeckLinkOutput_v9_9_WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) \
+ ( (This)->lpVtbl -> WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) )
+
+#define IDeckLinkOutput_v9_9_BeginAudioPreroll(This) \
+ ( (This)->lpVtbl -> BeginAudioPreroll(This) )
+
+#define IDeckLinkOutput_v9_9_EndAudioPreroll(This) \
+ ( (This)->lpVtbl -> EndAudioPreroll(This) )
+
+#define IDeckLinkOutput_v9_9_ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) \
+ ( (This)->lpVtbl -> ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) )
+
+#define IDeckLinkOutput_v9_9_GetBufferedAudioSampleFrameCount(This,bufferedSampleFrameCount) \
+ ( (This)->lpVtbl -> GetBufferedAudioSampleFrameCount(This,bufferedSampleFrameCount) )
+
+#define IDeckLinkOutput_v9_9_FlushBufferedAudioSamples(This) \
+ ( (This)->lpVtbl -> FlushBufferedAudioSamples(This) )
+
+#define IDeckLinkOutput_v9_9_SetAudioCallback(This,theCallback) \
+ ( (This)->lpVtbl -> SetAudioCallback(This,theCallback) )
+
+#define IDeckLinkOutput_v9_9_StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) \
+ ( (This)->lpVtbl -> StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) )
+
+#define IDeckLinkOutput_v9_9_StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) \
+ ( (This)->lpVtbl -> StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) )
+
+#define IDeckLinkOutput_v9_9_IsScheduledPlaybackRunning(This,active) \
+ ( (This)->lpVtbl -> IsScheduledPlaybackRunning(This,active) )
+
+#define IDeckLinkOutput_v9_9_GetScheduledStreamTime(This,desiredTimeScale,streamTime,playbackSpeed) \
+ ( (This)->lpVtbl -> GetScheduledStreamTime(This,desiredTimeScale,streamTime,playbackSpeed) )
+
+#define IDeckLinkOutput_v9_9_GetReferenceStatus(This,referenceStatus) \
+ ( (This)->lpVtbl -> GetReferenceStatus(This,referenceStatus) )
+
+#define IDeckLinkOutput_v9_9_GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) \
+ ( (This)->lpVtbl -> GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkOutput_v9_9_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkInput_v9_2_INTERFACE_DEFINED__
+#define __IDeckLinkInput_v9_2_INTERFACE_DEFINED__
+
+/* interface IDeckLinkInput_v9_2 */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkInput_v9_2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("6D40EF78-28B9-4E21-990D-95BB7750A04F")
+ IDeckLinkInput_v9_2 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode(
+ /* [in] */ BMDDisplayMode displayMode,
+ /* [in] */ BMDPixelFormat pixelFormat,
+ /* [in] */ BMDVideoInputFlags flags,
+ /* [out] */ BMDDisplayModeSupport *result,
+ /* [out] */ IDeckLinkDisplayMode **resultDisplayMode) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator(
+ /* [out] */ IDeckLinkDisplayModeIterator **iterator) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetScreenPreviewCallback(
+ /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnableVideoInput(
+ /* [in] */ BMDDisplayMode displayMode,
+ /* [in] */ BMDPixelFormat pixelFormat,
+ /* [in] */ BMDVideoInputFlags flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DisableVideoInput( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAvailableVideoFrameCount(
+ /* [out] */ unsigned int *availableFrameCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnableAudioInput(
+ /* [in] */ BMDAudioSampleRate sampleRate,
+ /* [in] */ BMDAudioSampleType sampleType,
+ /* [in] */ unsigned int channelCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DisableAudioInput( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAvailableAudioSampleFrameCount(
+ /* [out] */ unsigned int *availableSampleFrameCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartStreams( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StopStreams( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE PauseStreams( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FlushStreams( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetCallback(
+ /* [in] */ IDeckLinkInputCallback *theCallback) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceClock(
+ /* [in] */ BMDTimeScale desiredTimeScale,
+ /* [out] */ BMDTimeValue *hardwareTime,
+ /* [out] */ BMDTimeValue *timeInFrame,
+ /* [out] */ BMDTimeValue *ticksPerFrame) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkInput_v9_2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkInput_v9_2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkInput_v9_2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkInput_v9_2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )(
+ IDeckLinkInput_v9_2 * This,
+ /* [in] */ BMDDisplayMode displayMode,
+ /* [in] */ BMDPixelFormat pixelFormat,
+ /* [in] */ BMDVideoInputFlags flags,
+ /* [out] */ BMDDisplayModeSupport *result,
+ /* [out] */ IDeckLinkDisplayMode **resultDisplayMode);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )(
+ IDeckLinkInput_v9_2 * This,
+ /* [out] */ IDeckLinkDisplayModeIterator **iterator);
+
+ HRESULT ( STDMETHODCALLTYPE *SetScreenPreviewCallback )(
+ IDeckLinkInput_v9_2 * This,
+ /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback);
+
+ HRESULT ( STDMETHODCALLTYPE *EnableVideoInput )(
+ IDeckLinkInput_v9_2 * This,
+ /* [in] */ BMDDisplayMode displayMode,
+ /* [in] */ BMDPixelFormat pixelFormat,
+ /* [in] */ BMDVideoInputFlags flags);
+
+ HRESULT ( STDMETHODCALLTYPE *DisableVideoInput )(
+ IDeckLinkInput_v9_2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAvailableVideoFrameCount )(
+ IDeckLinkInput_v9_2 * This,
+ /* [out] */ unsigned int *availableFrameCount);
+
+ HRESULT ( STDMETHODCALLTYPE *EnableAudioInput )(
+ IDeckLinkInput_v9_2 * This,
+ /* [in] */ BMDAudioSampleRate sampleRate,
+ /* [in] */ BMDAudioSampleType sampleType,
+ /* [in] */ unsigned int channelCount);
+
+ HRESULT ( STDMETHODCALLTYPE *DisableAudioInput )(
+ IDeckLinkInput_v9_2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAvailableAudioSampleFrameCount )(
+ IDeckLinkInput_v9_2 * This,
+ /* [out] */ unsigned int *availableSampleFrameCount);
+
+ HRESULT ( STDMETHODCALLTYPE *StartStreams )(
+ IDeckLinkInput_v9_2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *StopStreams )(
+ IDeckLinkInput_v9_2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *PauseStreams )(
+ IDeckLinkInput_v9_2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *FlushStreams )(
+ IDeckLinkInput_v9_2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetCallback )(
+ IDeckLinkInput_v9_2 * This,
+ /* [in] */ IDeckLinkInputCallback *theCallback);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceClock )(
+ IDeckLinkInput_v9_2 * This,
+ /* [in] */ BMDTimeScale desiredTimeScale,
+ /* [out] */ BMDTimeValue *hardwareTime,
+ /* [out] */ BMDTimeValue *timeInFrame,
+ /* [out] */ BMDTimeValue *ticksPerFrame);
+
+ END_INTERFACE
+ } IDeckLinkInput_v9_2Vtbl;
+
+ interface IDeckLinkInput_v9_2
+ {
+ CONST_VTBL struct IDeckLinkInput_v9_2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkInput_v9_2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkInput_v9_2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkInput_v9_2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkInput_v9_2_DoesSupportVideoMode(This,displayMode,pixelFormat,flags,result,resultDisplayMode) \
+ ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,flags,result,resultDisplayMode) )
+
+#define IDeckLinkInput_v9_2_GetDisplayModeIterator(This,iterator) \
+ ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) )
+
+#define IDeckLinkInput_v9_2_SetScreenPreviewCallback(This,previewCallback) \
+ ( (This)->lpVtbl -> SetScreenPreviewCallback(This,previewCallback) )
+
+#define IDeckLinkInput_v9_2_EnableVideoInput(This,displayMode,pixelFormat,flags) \
+ ( (This)->lpVtbl -> EnableVideoInput(This,displayMode,pixelFormat,flags) )
+
+#define IDeckLinkInput_v9_2_DisableVideoInput(This) \
+ ( (This)->lpVtbl -> DisableVideoInput(This) )
+
+#define IDeckLinkInput_v9_2_GetAvailableVideoFrameCount(This,availableFrameCount) \
+ ( (This)->lpVtbl -> GetAvailableVideoFrameCount(This,availableFrameCount) )
+
+#define IDeckLinkInput_v9_2_EnableAudioInput(This,sampleRate,sampleType,channelCount) \
+ ( (This)->lpVtbl -> EnableAudioInput(This,sampleRate,sampleType,channelCount) )
+
+#define IDeckLinkInput_v9_2_DisableAudioInput(This) \
+ ( (This)->lpVtbl -> DisableAudioInput(This) )
+
+#define IDeckLinkInput_v9_2_GetAvailableAudioSampleFrameCount(This,availableSampleFrameCount) \
+ ( (This)->lpVtbl -> GetAvailableAudioSampleFrameCount(This,availableSampleFrameCount) )
+
+#define IDeckLinkInput_v9_2_StartStreams(This) \
+ ( (This)->lpVtbl -> StartStreams(This) )
+
+#define IDeckLinkInput_v9_2_StopStreams(This) \
+ ( (This)->lpVtbl -> StopStreams(This) )
+
+#define IDeckLinkInput_v9_2_PauseStreams(This) \
+ ( (This)->lpVtbl -> PauseStreams(This) )
+
+#define IDeckLinkInput_v9_2_FlushStreams(This) \
+ ( (This)->lpVtbl -> FlushStreams(This) )
+
+#define IDeckLinkInput_v9_2_SetCallback(This,theCallback) \
+ ( (This)->lpVtbl -> SetCallback(This,theCallback) )
+
+#define IDeckLinkInput_v9_2_GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) \
+ ( (This)->lpVtbl -> GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkInput_v9_2_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkDeckControlStatusCallback_v8_1_INTERFACE_DEFINED__
+#define __IDeckLinkDeckControlStatusCallback_v8_1_INTERFACE_DEFINED__
+
+/* interface IDeckLinkDeckControlStatusCallback_v8_1 */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkDeckControlStatusCallback_v8_1;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("E5F693C1-4283-4716-B18F-C1431521955B")
+ IDeckLinkDeckControlStatusCallback_v8_1 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE TimecodeUpdate(
+ /* [in] */ BMDTimecodeBCD currentTimecode) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE VTRControlStateChanged(
+ /* [in] */ BMDDeckControlVTRControlState_v8_1 newState,
+ /* [in] */ BMDDeckControlError error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DeckControlEventReceived(
+ /* [in] */ BMDDeckControlEvent event,
+ /* [in] */ BMDDeckControlError error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DeckControlStatusChanged(
+ /* [in] */ BMDDeckControlStatusFlags flags,
+ /* [in] */ unsigned int mask) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkDeckControlStatusCallback_v8_1Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkDeckControlStatusCallback_v8_1 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkDeckControlStatusCallback_v8_1 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkDeckControlStatusCallback_v8_1 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *TimecodeUpdate )(
+ IDeckLinkDeckControlStatusCallback_v8_1 * This,
+ /* [in] */ BMDTimecodeBCD currentTimecode);
+
+ HRESULT ( STDMETHODCALLTYPE *VTRControlStateChanged )(
+ IDeckLinkDeckControlStatusCallback_v8_1 * This,
+ /* [in] */ BMDDeckControlVTRControlState_v8_1 newState,
+ /* [in] */ BMDDeckControlError error);
+
+ HRESULT ( STDMETHODCALLTYPE *DeckControlEventReceived )(
+ IDeckLinkDeckControlStatusCallback_v8_1 * This,
+ /* [in] */ BMDDeckControlEvent event,
+ /* [in] */ BMDDeckControlError error);
+
+ HRESULT ( STDMETHODCALLTYPE *DeckControlStatusChanged )(
+ IDeckLinkDeckControlStatusCallback_v8_1 * This,
+ /* [in] */ BMDDeckControlStatusFlags flags,
+ /* [in] */ unsigned int mask);
+
+ END_INTERFACE
+ } IDeckLinkDeckControlStatusCallback_v8_1Vtbl;
+
+ interface IDeckLinkDeckControlStatusCallback_v8_1
+ {
+ CONST_VTBL struct IDeckLinkDeckControlStatusCallback_v8_1Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkDeckControlStatusCallback_v8_1_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkDeckControlStatusCallback_v8_1_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkDeckControlStatusCallback_v8_1_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkDeckControlStatusCallback_v8_1_TimecodeUpdate(This,currentTimecode) \
+ ( (This)->lpVtbl -> TimecodeUpdate(This,currentTimecode) )
+
+#define IDeckLinkDeckControlStatusCallback_v8_1_VTRControlStateChanged(This,newState,error) \
+ ( (This)->lpVtbl -> VTRControlStateChanged(This,newState,error) )
+
+#define IDeckLinkDeckControlStatusCallback_v8_1_DeckControlEventReceived(This,event,error) \
+ ( (This)->lpVtbl -> DeckControlEventReceived(This,event,error) )
+
+#define IDeckLinkDeckControlStatusCallback_v8_1_DeckControlStatusChanged(This,flags,mask) \
+ ( (This)->lpVtbl -> DeckControlStatusChanged(This,flags,mask) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkDeckControlStatusCallback_v8_1_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkDeckControl_v8_1_INTERFACE_DEFINED__
+#define __IDeckLinkDeckControl_v8_1_INTERFACE_DEFINED__
+
+/* interface IDeckLinkDeckControl_v8_1 */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkDeckControl_v8_1;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("522A9E39-0F3C-4742-94EE-D80DE335DA1D")
+ IDeckLinkDeckControl_v8_1 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Open(
+ /* [in] */ BMDTimeScale timeScale,
+ /* [in] */ BMDTimeValue timeValue,
+ /* [in] */ BOOL timecodeIsDropFrame,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Close(
+ /* [in] */ BOOL standbyOn) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCurrentState(
+ /* [out] */ BMDDeckControlMode *mode,
+ /* [out] */ BMDDeckControlVTRControlState_v8_1 *vtrControlState,
+ /* [out] */ BMDDeckControlStatusFlags *flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetStandby(
+ /* [in] */ BOOL standbyOn) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SendCommand(
+ /* [in] */ unsigned char *inBuffer,
+ /* [in] */ unsigned int inBufferSize,
+ /* [out] */ unsigned char *outBuffer,
+ /* [out] */ unsigned int *outDataSize,
+ /* [in] */ unsigned int outBufferSize,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Play(
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Stop(
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE TogglePlayStop(
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Eject(
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GoToTimecode(
+ /* [in] */ BMDTimecodeBCD timecode,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FastForward(
+ /* [in] */ BOOL viewTape,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Rewind(
+ /* [in] */ BOOL viewTape,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StepForward(
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StepBack(
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Jog(
+ /* [in] */ double rate,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Shuttle(
+ /* [in] */ double rate,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTimecodeString(
+ /* [out] */ BSTR *currentTimeCode,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTimecode(
+ /* [out] */ IDeckLinkTimecode **currentTimecode,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTimecodeBCD(
+ /* [out] */ BMDTimecodeBCD *currentTimecode,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetPreroll(
+ /* [in] */ unsigned int prerollSeconds) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetPreroll(
+ /* [out] */ unsigned int *prerollSeconds) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetExportOffset(
+ /* [in] */ int exportOffsetFields) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetExportOffset(
+ /* [out] */ int *exportOffsetFields) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetManualExportOffset(
+ /* [out] */ int *deckManualExportOffsetFields) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetCaptureOffset(
+ /* [in] */ int captureOffsetFields) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCaptureOffset(
+ /* [out] */ int *captureOffsetFields) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartExport(
+ /* [in] */ BMDTimecodeBCD inTimecode,
+ /* [in] */ BMDTimecodeBCD outTimecode,
+ /* [in] */ BMDDeckControlExportModeOpsFlags exportModeOps,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartCapture(
+ /* [in] */ BOOL useVITC,
+ /* [in] */ BMDTimecodeBCD inTimecode,
+ /* [in] */ BMDTimecodeBCD outTimecode,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDeviceID(
+ /* [out] */ unsigned short *deviceId,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Abort( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CrashRecordStart(
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CrashRecordStop(
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetCallback(
+ /* [in] */ IDeckLinkDeckControlStatusCallback_v8_1 *callback) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkDeckControl_v8_1Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkDeckControl_v8_1 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkDeckControl_v8_1 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Open )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [in] */ BMDTimeScale timeScale,
+ /* [in] */ BMDTimeValue timeValue,
+ /* [in] */ BOOL timecodeIsDropFrame,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *Close )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [in] */ BOOL standbyOn);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCurrentState )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [out] */ BMDDeckControlMode *mode,
+ /* [out] */ BMDDeckControlVTRControlState_v8_1 *vtrControlState,
+ /* [out] */ BMDDeckControlStatusFlags *flags);
+
+ HRESULT ( STDMETHODCALLTYPE *SetStandby )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [in] */ BOOL standbyOn);
+
+ HRESULT ( STDMETHODCALLTYPE *SendCommand )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [in] */ unsigned char *inBuffer,
+ /* [in] */ unsigned int inBufferSize,
+ /* [out] */ unsigned char *outBuffer,
+ /* [out] */ unsigned int *outDataSize,
+ /* [in] */ unsigned int outBufferSize,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *Play )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *Stop )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *TogglePlayStop )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *Eject )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *GoToTimecode )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [in] */ BMDTimecodeBCD timecode,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *FastForward )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [in] */ BOOL viewTape,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *Rewind )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [in] */ BOOL viewTape,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *StepForward )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *StepBack )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *Jog )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [in] */ double rate,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *Shuttle )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [in] */ double rate,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTimecodeString )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [out] */ BSTR *currentTimeCode,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTimecode )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [out] */ IDeckLinkTimecode **currentTimecode,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTimecodeBCD )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [out] */ BMDTimecodeBCD *currentTimecode,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *SetPreroll )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [in] */ unsigned int prerollSeconds);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPreroll )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [out] */ unsigned int *prerollSeconds);
+
+ HRESULT ( STDMETHODCALLTYPE *SetExportOffset )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [in] */ int exportOffsetFields);
+
+ HRESULT ( STDMETHODCALLTYPE *GetExportOffset )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [out] */ int *exportOffsetFields);
+
+ HRESULT ( STDMETHODCALLTYPE *GetManualExportOffset )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [out] */ int *deckManualExportOffsetFields);
+
+ HRESULT ( STDMETHODCALLTYPE *SetCaptureOffset )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [in] */ int captureOffsetFields);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCaptureOffset )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [out] */ int *captureOffsetFields);
+
+ HRESULT ( STDMETHODCALLTYPE *StartExport )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [in] */ BMDTimecodeBCD inTimecode,
+ /* [in] */ BMDTimecodeBCD outTimecode,
+ /* [in] */ BMDDeckControlExportModeOpsFlags exportModeOps,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *StartCapture )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [in] */ BOOL useVITC,
+ /* [in] */ BMDTimecodeBCD inTimecode,
+ /* [in] */ BMDTimecodeBCD outTimecode,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDeviceID )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [out] */ unsigned short *deviceId,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *Abort )(
+ IDeckLinkDeckControl_v8_1 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *CrashRecordStart )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *CrashRecordStop )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *SetCallback )(
+ IDeckLinkDeckControl_v8_1 * This,
+ /* [in] */ IDeckLinkDeckControlStatusCallback_v8_1 *callback);
+
+ END_INTERFACE
+ } IDeckLinkDeckControl_v8_1Vtbl;
+
+ interface IDeckLinkDeckControl_v8_1
+ {
+ CONST_VTBL struct IDeckLinkDeckControl_v8_1Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkDeckControl_v8_1_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkDeckControl_v8_1_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkDeckControl_v8_1_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkDeckControl_v8_1_Open(This,timeScale,timeValue,timecodeIsDropFrame,error) \
+ ( (This)->lpVtbl -> Open(This,timeScale,timeValue,timecodeIsDropFrame,error) )
+
+#define IDeckLinkDeckControl_v8_1_Close(This,standbyOn) \
+ ( (This)->lpVtbl -> Close(This,standbyOn) )
+
+#define IDeckLinkDeckControl_v8_1_GetCurrentState(This,mode,vtrControlState,flags) \
+ ( (This)->lpVtbl -> GetCurrentState(This,mode,vtrControlState,flags) )
+
+#define IDeckLinkDeckControl_v8_1_SetStandby(This,standbyOn) \
+ ( (This)->lpVtbl -> SetStandby(This,standbyOn) )
+
+#define IDeckLinkDeckControl_v8_1_SendCommand(This,inBuffer,inBufferSize,outBuffer,outDataSize,outBufferSize,error) \
+ ( (This)->lpVtbl -> SendCommand(This,inBuffer,inBufferSize,outBuffer,outDataSize,outBufferSize,error) )
+
+#define IDeckLinkDeckControl_v8_1_Play(This,error) \
+ ( (This)->lpVtbl -> Play(This,error) )
+
+#define IDeckLinkDeckControl_v8_1_Stop(This,error) \
+ ( (This)->lpVtbl -> Stop(This,error) )
+
+#define IDeckLinkDeckControl_v8_1_TogglePlayStop(This,error) \
+ ( (This)->lpVtbl -> TogglePlayStop(This,error) )
+
+#define IDeckLinkDeckControl_v8_1_Eject(This,error) \
+ ( (This)->lpVtbl -> Eject(This,error) )
+
+#define IDeckLinkDeckControl_v8_1_GoToTimecode(This,timecode,error) \
+ ( (This)->lpVtbl -> GoToTimecode(This,timecode,error) )
+
+#define IDeckLinkDeckControl_v8_1_FastForward(This,viewTape,error) \
+ ( (This)->lpVtbl -> FastForward(This,viewTape,error) )
+
+#define IDeckLinkDeckControl_v8_1_Rewind(This,viewTape,error) \
+ ( (This)->lpVtbl -> Rewind(This,viewTape,error) )
+
+#define IDeckLinkDeckControl_v8_1_StepForward(This,error) \
+ ( (This)->lpVtbl -> StepForward(This,error) )
+
+#define IDeckLinkDeckControl_v8_1_StepBack(This,error) \
+ ( (This)->lpVtbl -> StepBack(This,error) )
+
+#define IDeckLinkDeckControl_v8_1_Jog(This,rate,error) \
+ ( (This)->lpVtbl -> Jog(This,rate,error) )
+
+#define IDeckLinkDeckControl_v8_1_Shuttle(This,rate,error) \
+ ( (This)->lpVtbl -> Shuttle(This,rate,error) )
+
+#define IDeckLinkDeckControl_v8_1_GetTimecodeString(This,currentTimeCode,error) \
+ ( (This)->lpVtbl -> GetTimecodeString(This,currentTimeCode,error) )
+
+#define IDeckLinkDeckControl_v8_1_GetTimecode(This,currentTimecode,error) \
+ ( (This)->lpVtbl -> GetTimecode(This,currentTimecode,error) )
+
+#define IDeckLinkDeckControl_v8_1_GetTimecodeBCD(This,currentTimecode,error) \
+ ( (This)->lpVtbl -> GetTimecodeBCD(This,currentTimecode,error) )
+
+#define IDeckLinkDeckControl_v8_1_SetPreroll(This,prerollSeconds) \
+ ( (This)->lpVtbl -> SetPreroll(This,prerollSeconds) )
+
+#define IDeckLinkDeckControl_v8_1_GetPreroll(This,prerollSeconds) \
+ ( (This)->lpVtbl -> GetPreroll(This,prerollSeconds) )
+
+#define IDeckLinkDeckControl_v8_1_SetExportOffset(This,exportOffsetFields) \
+ ( (This)->lpVtbl -> SetExportOffset(This,exportOffsetFields) )
+
+#define IDeckLinkDeckControl_v8_1_GetExportOffset(This,exportOffsetFields) \
+ ( (This)->lpVtbl -> GetExportOffset(This,exportOffsetFields) )
+
+#define IDeckLinkDeckControl_v8_1_GetManualExportOffset(This,deckManualExportOffsetFields) \
+ ( (This)->lpVtbl -> GetManualExportOffset(This,deckManualExportOffsetFields) )
+
+#define IDeckLinkDeckControl_v8_1_SetCaptureOffset(This,captureOffsetFields) \
+ ( (This)->lpVtbl -> SetCaptureOffset(This,captureOffsetFields) )
+
+#define IDeckLinkDeckControl_v8_1_GetCaptureOffset(This,captureOffsetFields) \
+ ( (This)->lpVtbl -> GetCaptureOffset(This,captureOffsetFields) )
+
+#define IDeckLinkDeckControl_v8_1_StartExport(This,inTimecode,outTimecode,exportModeOps,error) \
+ ( (This)->lpVtbl -> StartExport(This,inTimecode,outTimecode,exportModeOps,error) )
+
+#define IDeckLinkDeckControl_v8_1_StartCapture(This,useVITC,inTimecode,outTimecode,error) \
+ ( (This)->lpVtbl -> StartCapture(This,useVITC,inTimecode,outTimecode,error) )
+
+#define IDeckLinkDeckControl_v8_1_GetDeviceID(This,deviceId,error) \
+ ( (This)->lpVtbl -> GetDeviceID(This,deviceId,error) )
+
+#define IDeckLinkDeckControl_v8_1_Abort(This) \
+ ( (This)->lpVtbl -> Abort(This) )
+
+#define IDeckLinkDeckControl_v8_1_CrashRecordStart(This,error) \
+ ( (This)->lpVtbl -> CrashRecordStart(This,error) )
+
+#define IDeckLinkDeckControl_v8_1_CrashRecordStop(This,error) \
+ ( (This)->lpVtbl -> CrashRecordStop(This,error) )
+
+#define IDeckLinkDeckControl_v8_1_SetCallback(This,callback) \
+ ( (This)->lpVtbl -> SetCallback(This,callback) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkDeckControl_v8_1_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLink_v8_0_INTERFACE_DEFINED__
+#define __IDeckLink_v8_0_INTERFACE_DEFINED__
+
+/* interface IDeckLink_v8_0 */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLink_v8_0;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("62BFF75D-6569-4E55-8D4D-66AA03829ABC")
+ IDeckLink_v8_0 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetModelName(
+ /* [out] */ BSTR *modelName) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLink_v8_0Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLink_v8_0 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLink_v8_0 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLink_v8_0 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModelName )(
+ IDeckLink_v8_0 * This,
+ /* [out] */ BSTR *modelName);
+
+ END_INTERFACE
+ } IDeckLink_v8_0Vtbl;
+
+ interface IDeckLink_v8_0
+ {
+ CONST_VTBL struct IDeckLink_v8_0Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLink_v8_0_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLink_v8_0_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLink_v8_0_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLink_v8_0_GetModelName(This,modelName) \
+ ( (This)->lpVtbl -> GetModelName(This,modelName) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLink_v8_0_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkIterator_v8_0_INTERFACE_DEFINED__
+#define __IDeckLinkIterator_v8_0_INTERFACE_DEFINED__
+
+/* interface IDeckLinkIterator_v8_0 */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkIterator_v8_0;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("74E936FC-CC28-4A67-81A0-1E94E52D4E69")
+ IDeckLinkIterator_v8_0 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [out] */ IDeckLink_v8_0 **deckLinkInstance) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkIterator_v8_0Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkIterator_v8_0 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkIterator_v8_0 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkIterator_v8_0 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ IDeckLinkIterator_v8_0 * This,
+ /* [out] */ IDeckLink_v8_0 **deckLinkInstance);
+
+ END_INTERFACE
+ } IDeckLinkIterator_v8_0Vtbl;
+
+ interface IDeckLinkIterator_v8_0
+ {
+ CONST_VTBL struct IDeckLinkIterator_v8_0Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkIterator_v8_0_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkIterator_v8_0_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkIterator_v8_0_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkIterator_v8_0_Next(This,deckLinkInstance) \
+ ( (This)->lpVtbl -> Next(This,deckLinkInstance) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkIterator_v8_0_INTERFACE_DEFINED__ */
+
+
+EXTERN_C const CLSID CLSID_CDeckLinkIterator_v8_0;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("D9EDA3B3-2887-41FA-B724-017CF1EB1D37")
+CDeckLinkIterator_v8_0;
+#endif
+
+#ifndef __IDeckLinkDeckControl_v7_9_INTERFACE_DEFINED__
+#define __IDeckLinkDeckControl_v7_9_INTERFACE_DEFINED__
+
+/* interface IDeckLinkDeckControl_v7_9 */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkDeckControl_v7_9;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("A4D81043-0619-42B7-8ED6-602D29041DF7")
+ IDeckLinkDeckControl_v7_9 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Open(
+ /* [in] */ BMDTimeScale timeScale,
+ /* [in] */ BMDTimeValue timeValue,
+ /* [in] */ BOOL timecodeIsDropFrame,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Close(
+ /* [in] */ BOOL standbyOn) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCurrentState(
+ /* [out] */ BMDDeckControlMode *mode,
+ /* [out] */ BMDDeckControlVTRControlState *vtrControlState,
+ /* [out] */ BMDDeckControlStatusFlags *flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetStandby(
+ /* [in] */ BOOL standbyOn) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Play(
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Stop(
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE TogglePlayStop(
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Eject(
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GoToTimecode(
+ /* [in] */ BMDTimecodeBCD timecode,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FastForward(
+ /* [in] */ BOOL viewTape,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Rewind(
+ /* [in] */ BOOL viewTape,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StepForward(
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StepBack(
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Jog(
+ /* [in] */ double rate,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Shuttle(
+ /* [in] */ double rate,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTimecodeString(
+ /* [out] */ BSTR *currentTimeCode,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTimecode(
+ /* [out] */ IDeckLinkTimecode **currentTimecode,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTimecodeBCD(
+ /* [out] */ BMDTimecodeBCD *currentTimecode,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetPreroll(
+ /* [in] */ unsigned int prerollSeconds) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetPreroll(
+ /* [out] */ unsigned int *prerollSeconds) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetExportOffset(
+ /* [in] */ int exportOffsetFields) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetExportOffset(
+ /* [out] */ int *exportOffsetFields) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetManualExportOffset(
+ /* [out] */ int *deckManualExportOffsetFields) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetCaptureOffset(
+ /* [in] */ int captureOffsetFields) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCaptureOffset(
+ /* [out] */ int *captureOffsetFields) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartExport(
+ /* [in] */ BMDTimecodeBCD inTimecode,
+ /* [in] */ BMDTimecodeBCD outTimecode,
+ /* [in] */ BMDDeckControlExportModeOpsFlags exportModeOps,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartCapture(
+ /* [in] */ BOOL useVITC,
+ /* [in] */ BMDTimecodeBCD inTimecode,
+ /* [in] */ BMDTimecodeBCD outTimecode,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDeviceID(
+ /* [out] */ unsigned short *deviceId,
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Abort( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CrashRecordStart(
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CrashRecordStop(
+ /* [out] */ BMDDeckControlError *error) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetCallback(
+ /* [in] */ IDeckLinkDeckControlStatusCallback *callback) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkDeckControl_v7_9Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkDeckControl_v7_9 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkDeckControl_v7_9 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Open )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [in] */ BMDTimeScale timeScale,
+ /* [in] */ BMDTimeValue timeValue,
+ /* [in] */ BOOL timecodeIsDropFrame,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *Close )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [in] */ BOOL standbyOn);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCurrentState )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [out] */ BMDDeckControlMode *mode,
+ /* [out] */ BMDDeckControlVTRControlState *vtrControlState,
+ /* [out] */ BMDDeckControlStatusFlags *flags);
+
+ HRESULT ( STDMETHODCALLTYPE *SetStandby )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [in] */ BOOL standbyOn);
+
+ HRESULT ( STDMETHODCALLTYPE *Play )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *Stop )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *TogglePlayStop )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *Eject )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *GoToTimecode )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [in] */ BMDTimecodeBCD timecode,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *FastForward )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [in] */ BOOL viewTape,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *Rewind )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [in] */ BOOL viewTape,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *StepForward )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *StepBack )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *Jog )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [in] */ double rate,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *Shuttle )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [in] */ double rate,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTimecodeString )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [out] */ BSTR *currentTimeCode,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTimecode )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [out] */ IDeckLinkTimecode **currentTimecode,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTimecodeBCD )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [out] */ BMDTimecodeBCD *currentTimecode,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *SetPreroll )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [in] */ unsigned int prerollSeconds);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPreroll )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [out] */ unsigned int *prerollSeconds);
+
+ HRESULT ( STDMETHODCALLTYPE *SetExportOffset )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [in] */ int exportOffsetFields);
+
+ HRESULT ( STDMETHODCALLTYPE *GetExportOffset )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [out] */ int *exportOffsetFields);
+
+ HRESULT ( STDMETHODCALLTYPE *GetManualExportOffset )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [out] */ int *deckManualExportOffsetFields);
+
+ HRESULT ( STDMETHODCALLTYPE *SetCaptureOffset )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [in] */ int captureOffsetFields);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCaptureOffset )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [out] */ int *captureOffsetFields);
+
+ HRESULT ( STDMETHODCALLTYPE *StartExport )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [in] */ BMDTimecodeBCD inTimecode,
+ /* [in] */ BMDTimecodeBCD outTimecode,
+ /* [in] */ BMDDeckControlExportModeOpsFlags exportModeOps,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *StartCapture )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [in] */ BOOL useVITC,
+ /* [in] */ BMDTimecodeBCD inTimecode,
+ /* [in] */ BMDTimecodeBCD outTimecode,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDeviceID )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [out] */ unsigned short *deviceId,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *Abort )(
+ IDeckLinkDeckControl_v7_9 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *CrashRecordStart )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *CrashRecordStop )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [out] */ BMDDeckControlError *error);
+
+ HRESULT ( STDMETHODCALLTYPE *SetCallback )(
+ IDeckLinkDeckControl_v7_9 * This,
+ /* [in] */ IDeckLinkDeckControlStatusCallback *callback);
+
+ END_INTERFACE
+ } IDeckLinkDeckControl_v7_9Vtbl;
+
+ interface IDeckLinkDeckControl_v7_9
+ {
+ CONST_VTBL struct IDeckLinkDeckControl_v7_9Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkDeckControl_v7_9_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkDeckControl_v7_9_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkDeckControl_v7_9_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkDeckControl_v7_9_Open(This,timeScale,timeValue,timecodeIsDropFrame,error) \
+ ( (This)->lpVtbl -> Open(This,timeScale,timeValue,timecodeIsDropFrame,error) )
+
+#define IDeckLinkDeckControl_v7_9_Close(This,standbyOn) \
+ ( (This)->lpVtbl -> Close(This,standbyOn) )
+
+#define IDeckLinkDeckControl_v7_9_GetCurrentState(This,mode,vtrControlState,flags) \
+ ( (This)->lpVtbl -> GetCurrentState(This,mode,vtrControlState,flags) )
+
+#define IDeckLinkDeckControl_v7_9_SetStandby(This,standbyOn) \
+ ( (This)->lpVtbl -> SetStandby(This,standbyOn) )
+
+#define IDeckLinkDeckControl_v7_9_Play(This,error) \
+ ( (This)->lpVtbl -> Play(This,error) )
+
+#define IDeckLinkDeckControl_v7_9_Stop(This,error) \
+ ( (This)->lpVtbl -> Stop(This,error) )
+
+#define IDeckLinkDeckControl_v7_9_TogglePlayStop(This,error) \
+ ( (This)->lpVtbl -> TogglePlayStop(This,error) )
+
+#define IDeckLinkDeckControl_v7_9_Eject(This,error) \
+ ( (This)->lpVtbl -> Eject(This,error) )
+
+#define IDeckLinkDeckControl_v7_9_GoToTimecode(This,timecode,error) \
+ ( (This)->lpVtbl -> GoToTimecode(This,timecode,error) )
+
+#define IDeckLinkDeckControl_v7_9_FastForward(This,viewTape,error) \
+ ( (This)->lpVtbl -> FastForward(This,viewTape,error) )
+
+#define IDeckLinkDeckControl_v7_9_Rewind(This,viewTape,error) \
+ ( (This)->lpVtbl -> Rewind(This,viewTape,error) )
+
+#define IDeckLinkDeckControl_v7_9_StepForward(This,error) \
+ ( (This)->lpVtbl -> StepForward(This,error) )
+
+#define IDeckLinkDeckControl_v7_9_StepBack(This,error) \
+ ( (This)->lpVtbl -> StepBack(This,error) )
+
+#define IDeckLinkDeckControl_v7_9_Jog(This,rate,error) \
+ ( (This)->lpVtbl -> Jog(This,rate,error) )
+
+#define IDeckLinkDeckControl_v7_9_Shuttle(This,rate,error) \
+ ( (This)->lpVtbl -> Shuttle(This,rate,error) )
+
+#define IDeckLinkDeckControl_v7_9_GetTimecodeString(This,currentTimeCode,error) \
+ ( (This)->lpVtbl -> GetTimecodeString(This,currentTimeCode,error) )
+
+#define IDeckLinkDeckControl_v7_9_GetTimecode(This,currentTimecode,error) \
+ ( (This)->lpVtbl -> GetTimecode(This,currentTimecode,error) )
+
+#define IDeckLinkDeckControl_v7_9_GetTimecodeBCD(This,currentTimecode,error) \
+ ( (This)->lpVtbl -> GetTimecodeBCD(This,currentTimecode,error) )
+
+#define IDeckLinkDeckControl_v7_9_SetPreroll(This,prerollSeconds) \
+ ( (This)->lpVtbl -> SetPreroll(This,prerollSeconds) )
+
+#define IDeckLinkDeckControl_v7_9_GetPreroll(This,prerollSeconds) \
+ ( (This)->lpVtbl -> GetPreroll(This,prerollSeconds) )
+
+#define IDeckLinkDeckControl_v7_9_SetExportOffset(This,exportOffsetFields) \
+ ( (This)->lpVtbl -> SetExportOffset(This,exportOffsetFields) )
+
+#define IDeckLinkDeckControl_v7_9_GetExportOffset(This,exportOffsetFields) \
+ ( (This)->lpVtbl -> GetExportOffset(This,exportOffsetFields) )
+
+#define IDeckLinkDeckControl_v7_9_GetManualExportOffset(This,deckManualExportOffsetFields) \
+ ( (This)->lpVtbl -> GetManualExportOffset(This,deckManualExportOffsetFields) )
+
+#define IDeckLinkDeckControl_v7_9_SetCaptureOffset(This,captureOffsetFields) \
+ ( (This)->lpVtbl -> SetCaptureOffset(This,captureOffsetFields) )
+
+#define IDeckLinkDeckControl_v7_9_GetCaptureOffset(This,captureOffsetFields) \
+ ( (This)->lpVtbl -> GetCaptureOffset(This,captureOffsetFields) )
+
+#define IDeckLinkDeckControl_v7_9_StartExport(This,inTimecode,outTimecode,exportModeOps,error) \
+ ( (This)->lpVtbl -> StartExport(This,inTimecode,outTimecode,exportModeOps,error) )
+
+#define IDeckLinkDeckControl_v7_9_StartCapture(This,useVITC,inTimecode,outTimecode,error) \
+ ( (This)->lpVtbl -> StartCapture(This,useVITC,inTimecode,outTimecode,error) )
+
+#define IDeckLinkDeckControl_v7_9_GetDeviceID(This,deviceId,error) \
+ ( (This)->lpVtbl -> GetDeviceID(This,deviceId,error) )
+
+#define IDeckLinkDeckControl_v7_9_Abort(This) \
+ ( (This)->lpVtbl -> Abort(This) )
+
+#define IDeckLinkDeckControl_v7_9_CrashRecordStart(This,error) \
+ ( (This)->lpVtbl -> CrashRecordStart(This,error) )
+
+#define IDeckLinkDeckControl_v7_9_CrashRecordStop(This,error) \
+ ( (This)->lpVtbl -> CrashRecordStop(This,error) )
+
+#define IDeckLinkDeckControl_v7_9_SetCallback(This,callback) \
+ ( (This)->lpVtbl -> SetCallback(This,callback) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkDeckControl_v7_9_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkDisplayModeIterator_v7_6_INTERFACE_DEFINED__
+#define __IDeckLinkDisplayModeIterator_v7_6_INTERFACE_DEFINED__
+
+/* interface IDeckLinkDisplayModeIterator_v7_6 */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkDisplayModeIterator_v7_6;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("455D741F-1779-4800-86F5-0B5D13D79751")
+ IDeckLinkDisplayModeIterator_v7_6 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [out] */ IDeckLinkDisplayMode_v7_6 **deckLinkDisplayMode) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkDisplayModeIterator_v7_6Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkDisplayModeIterator_v7_6 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkDisplayModeIterator_v7_6 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkDisplayModeIterator_v7_6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ IDeckLinkDisplayModeIterator_v7_6 * This,
+ /* [out] */ IDeckLinkDisplayMode_v7_6 **deckLinkDisplayMode);
+
+ END_INTERFACE
+ } IDeckLinkDisplayModeIterator_v7_6Vtbl;
+
+ interface IDeckLinkDisplayModeIterator_v7_6
+ {
+ CONST_VTBL struct IDeckLinkDisplayModeIterator_v7_6Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkDisplayModeIterator_v7_6_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkDisplayModeIterator_v7_6_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkDisplayModeIterator_v7_6_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkDisplayModeIterator_v7_6_Next(This,deckLinkDisplayMode) \
+ ( (This)->lpVtbl -> Next(This,deckLinkDisplayMode) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkDisplayModeIterator_v7_6_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkDisplayMode_v7_6_INTERFACE_DEFINED__
+#define __IDeckLinkDisplayMode_v7_6_INTERFACE_DEFINED__
+
+/* interface IDeckLinkDisplayMode_v7_6 */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkDisplayMode_v7_6;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("87451E84-2B7E-439E-A629-4393EA4A8550")
+ IDeckLinkDisplayMode_v7_6 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetName(
+ /* [out] */ BSTR *name) = 0;
+
+ virtual BMDDisplayMode STDMETHODCALLTYPE GetDisplayMode( void) = 0;
+
+ virtual long STDMETHODCALLTYPE GetWidth( void) = 0;
+
+ virtual long STDMETHODCALLTYPE GetHeight( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFrameRate(
+ /* [out] */ BMDTimeValue *frameDuration,
+ /* [out] */ BMDTimeScale *timeScale) = 0;
+
+ virtual BMDFieldDominance STDMETHODCALLTYPE GetFieldDominance( void) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkDisplayMode_v7_6Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkDisplayMode_v7_6 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkDisplayMode_v7_6 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkDisplayMode_v7_6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ IDeckLinkDisplayMode_v7_6 * This,
+ /* [out] */ BSTR *name);
+
+ BMDDisplayMode ( STDMETHODCALLTYPE *GetDisplayMode )(
+ IDeckLinkDisplayMode_v7_6 * This);
+
+ long ( STDMETHODCALLTYPE *GetWidth )(
+ IDeckLinkDisplayMode_v7_6 * This);
+
+ long ( STDMETHODCALLTYPE *GetHeight )(
+ IDeckLinkDisplayMode_v7_6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFrameRate )(
+ IDeckLinkDisplayMode_v7_6 * This,
+ /* [out] */ BMDTimeValue *frameDuration,
+ /* [out] */ BMDTimeScale *timeScale);
+
+ BMDFieldDominance ( STDMETHODCALLTYPE *GetFieldDominance )(
+ IDeckLinkDisplayMode_v7_6 * This);
+
+ END_INTERFACE
+ } IDeckLinkDisplayMode_v7_6Vtbl;
+
+ interface IDeckLinkDisplayMode_v7_6
+ {
+ CONST_VTBL struct IDeckLinkDisplayMode_v7_6Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkDisplayMode_v7_6_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkDisplayMode_v7_6_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkDisplayMode_v7_6_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkDisplayMode_v7_6_GetName(This,name) \
+ ( (This)->lpVtbl -> GetName(This,name) )
+
+#define IDeckLinkDisplayMode_v7_6_GetDisplayMode(This) \
+ ( (This)->lpVtbl -> GetDisplayMode(This) )
+
+#define IDeckLinkDisplayMode_v7_6_GetWidth(This) \
+ ( (This)->lpVtbl -> GetWidth(This) )
+
+#define IDeckLinkDisplayMode_v7_6_GetHeight(This) \
+ ( (This)->lpVtbl -> GetHeight(This) )
+
+#define IDeckLinkDisplayMode_v7_6_GetFrameRate(This,frameDuration,timeScale) \
+ ( (This)->lpVtbl -> GetFrameRate(This,frameDuration,timeScale) )
+
+#define IDeckLinkDisplayMode_v7_6_GetFieldDominance(This) \
+ ( (This)->lpVtbl -> GetFieldDominance(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkDisplayMode_v7_6_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkOutput_v7_6_INTERFACE_DEFINED__
+#define __IDeckLinkOutput_v7_6_INTERFACE_DEFINED__
+
+/* interface IDeckLinkOutput_v7_6 */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkOutput_v7_6;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("29228142-EB8C-4141-A621-F74026450955")
+ IDeckLinkOutput_v7_6 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode(
+ BMDDisplayMode displayMode,
+ BMDPixelFormat pixelFormat,
+ /* [out] */ BMDDisplayModeSupport *result) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator(
+ /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetScreenPreviewCallback(
+ /* [in] */ IDeckLinkScreenPreviewCallback_v7_6 *previewCallback) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnableVideoOutput(
+ BMDDisplayMode displayMode,
+ BMDVideoOutputFlags flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DisableVideoOutput( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetVideoOutputFrameMemoryAllocator(
+ /* [in] */ IDeckLinkMemoryAllocator *theAllocator) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateVideoFrame(
+ int width,
+ int height,
+ int rowBytes,
+ BMDPixelFormat pixelFormat,
+ BMDFrameFlags flags,
+ /* [out] */ IDeckLinkMutableVideoFrame_v7_6 **outFrame) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateAncillaryData(
+ BMDPixelFormat pixelFormat,
+ /* [out] */ IDeckLinkVideoFrameAncillary **outBuffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DisplayVideoFrameSync(
+ /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ScheduleVideoFrame(
+ /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame,
+ BMDTimeValue displayTime,
+ BMDTimeValue displayDuration,
+ BMDTimeScale timeScale) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetScheduledFrameCompletionCallback(
+ /* [in] */ IDeckLinkVideoOutputCallback_v7_6 *theCallback) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBufferedVideoFrameCount(
+ /* [out] */ unsigned int *bufferedFrameCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnableAudioOutput(
+ BMDAudioSampleRate sampleRate,
+ BMDAudioSampleType sampleType,
+ unsigned int channelCount,
+ BMDAudioOutputStreamType streamType) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DisableAudioOutput( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteAudioSamplesSync(
+ /* [in] */ void *buffer,
+ unsigned int sampleFrameCount,
+ /* [out] */ unsigned int *sampleFramesWritten) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE BeginAudioPreroll( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndAudioPreroll( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ScheduleAudioSamples(
+ /* [in] */ void *buffer,
+ unsigned int sampleFrameCount,
+ BMDTimeValue streamTime,
+ BMDTimeScale timeScale,
+ /* [out] */ unsigned int *sampleFramesWritten) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBufferedAudioSampleFrameCount(
+ /* [out] */ unsigned int *bufferedSampleFrameCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FlushBufferedAudioSamples( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetAudioCallback(
+ /* [in] */ IDeckLinkAudioOutputCallback *theCallback) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartScheduledPlayback(
+ BMDTimeValue playbackStartTime,
+ BMDTimeScale timeScale,
+ double playbackSpeed) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StopScheduledPlayback(
+ BMDTimeValue stopPlaybackAtTime,
+ /* [out] */ BMDTimeValue *actualStopTime,
+ BMDTimeScale timeScale) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsScheduledPlaybackRunning(
+ /* [out] */ BOOL *active) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetScheduledStreamTime(
+ BMDTimeScale desiredTimeScale,
+ /* [out] */ BMDTimeValue *streamTime,
+ /* [out] */ double *playbackSpeed) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceClock(
+ BMDTimeScale desiredTimeScale,
+ /* [out] */ BMDTimeValue *hardwareTime,
+ /* [out] */ BMDTimeValue *timeInFrame,
+ /* [out] */ BMDTimeValue *ticksPerFrame) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkOutput_v7_6Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkOutput_v7_6 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkOutput_v7_6 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkOutput_v7_6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )(
+ IDeckLinkOutput_v7_6 * This,
+ BMDDisplayMode displayMode,
+ BMDPixelFormat pixelFormat,
+ /* [out] */ BMDDisplayModeSupport *result);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )(
+ IDeckLinkOutput_v7_6 * This,
+ /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator);
+
+ HRESULT ( STDMETHODCALLTYPE *SetScreenPreviewCallback )(
+ IDeckLinkOutput_v7_6 * This,
+ /* [in] */ IDeckLinkScreenPreviewCallback_v7_6 *previewCallback);
+
+ HRESULT ( STDMETHODCALLTYPE *EnableVideoOutput )(
+ IDeckLinkOutput_v7_6 * This,
+ BMDDisplayMode displayMode,
+ BMDVideoOutputFlags flags);
+
+ HRESULT ( STDMETHODCALLTYPE *DisableVideoOutput )(
+ IDeckLinkOutput_v7_6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetVideoOutputFrameMemoryAllocator )(
+ IDeckLinkOutput_v7_6 * This,
+ /* [in] */ IDeckLinkMemoryAllocator *theAllocator);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateVideoFrame )(
+ IDeckLinkOutput_v7_6 * This,
+ int width,
+ int height,
+ int rowBytes,
+ BMDPixelFormat pixelFormat,
+ BMDFrameFlags flags,
+ /* [out] */ IDeckLinkMutableVideoFrame_v7_6 **outFrame);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateAncillaryData )(
+ IDeckLinkOutput_v7_6 * This,
+ BMDPixelFormat pixelFormat,
+ /* [out] */ IDeckLinkVideoFrameAncillary **outBuffer);
+
+ HRESULT ( STDMETHODCALLTYPE *DisplayVideoFrameSync )(
+ IDeckLinkOutput_v7_6 * This,
+ /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame);
+
+ HRESULT ( STDMETHODCALLTYPE *ScheduleVideoFrame )(
+ IDeckLinkOutput_v7_6 * This,
+ /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame,
+ BMDTimeValue displayTime,
+ BMDTimeValue displayDuration,
+ BMDTimeScale timeScale);
+
+ HRESULT ( STDMETHODCALLTYPE *SetScheduledFrameCompletionCallback )(
+ IDeckLinkOutput_v7_6 * This,
+ /* [in] */ IDeckLinkVideoOutputCallback_v7_6 *theCallback);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBufferedVideoFrameCount )(
+ IDeckLinkOutput_v7_6 * This,
+ /* [out] */ unsigned int *bufferedFrameCount);
+
+ HRESULT ( STDMETHODCALLTYPE *EnableAudioOutput )(
+ IDeckLinkOutput_v7_6 * This,
+ BMDAudioSampleRate sampleRate,
+ BMDAudioSampleType sampleType,
+ unsigned int channelCount,
+ BMDAudioOutputStreamType streamType);
+
+ HRESULT ( STDMETHODCALLTYPE *DisableAudioOutput )(
+ IDeckLinkOutput_v7_6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteAudioSamplesSync )(
+ IDeckLinkOutput_v7_6 * This,
+ /* [in] */ void *buffer,
+ unsigned int sampleFrameCount,
+ /* [out] */ unsigned int *sampleFramesWritten);
+
+ HRESULT ( STDMETHODCALLTYPE *BeginAudioPreroll )(
+ IDeckLinkOutput_v7_6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *EndAudioPreroll )(
+ IDeckLinkOutput_v7_6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ScheduleAudioSamples )(
+ IDeckLinkOutput_v7_6 * This,
+ /* [in] */ void *buffer,
+ unsigned int sampleFrameCount,
+ BMDTimeValue streamTime,
+ BMDTimeScale timeScale,
+ /* [out] */ unsigned int *sampleFramesWritten);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBufferedAudioSampleFrameCount )(
+ IDeckLinkOutput_v7_6 * This,
+ /* [out] */ unsigned int *bufferedSampleFrameCount);
+
+ HRESULT ( STDMETHODCALLTYPE *FlushBufferedAudioSamples )(
+ IDeckLinkOutput_v7_6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAudioCallback )(
+ IDeckLinkOutput_v7_6 * This,
+ /* [in] */ IDeckLinkAudioOutputCallback *theCallback);
+
+ HRESULT ( STDMETHODCALLTYPE *StartScheduledPlayback )(
+ IDeckLinkOutput_v7_6 * This,
+ BMDTimeValue playbackStartTime,
+ BMDTimeScale timeScale,
+ double playbackSpeed);
+
+ HRESULT ( STDMETHODCALLTYPE *StopScheduledPlayback )(
+ IDeckLinkOutput_v7_6 * This,
+ BMDTimeValue stopPlaybackAtTime,
+ /* [out] */ BMDTimeValue *actualStopTime,
+ BMDTimeScale timeScale);
+
+ HRESULT ( STDMETHODCALLTYPE *IsScheduledPlaybackRunning )(
+ IDeckLinkOutput_v7_6 * This,
+ /* [out] */ BOOL *active);
+
+ HRESULT ( STDMETHODCALLTYPE *GetScheduledStreamTime )(
+ IDeckLinkOutput_v7_6 * This,
+ BMDTimeScale desiredTimeScale,
+ /* [out] */ BMDTimeValue *streamTime,
+ /* [out] */ double *playbackSpeed);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceClock )(
+ IDeckLinkOutput_v7_6 * This,
+ BMDTimeScale desiredTimeScale,
+ /* [out] */ BMDTimeValue *hardwareTime,
+ /* [out] */ BMDTimeValue *timeInFrame,
+ /* [out] */ BMDTimeValue *ticksPerFrame);
+
+ END_INTERFACE
+ } IDeckLinkOutput_v7_6Vtbl;
+
+ interface IDeckLinkOutput_v7_6
+ {
+ CONST_VTBL struct IDeckLinkOutput_v7_6Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkOutput_v7_6_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkOutput_v7_6_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkOutput_v7_6_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkOutput_v7_6_DoesSupportVideoMode(This,displayMode,pixelFormat,result) \
+ ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,result) )
+
+#define IDeckLinkOutput_v7_6_GetDisplayModeIterator(This,iterator) \
+ ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) )
+
+#define IDeckLinkOutput_v7_6_SetScreenPreviewCallback(This,previewCallback) \
+ ( (This)->lpVtbl -> SetScreenPreviewCallback(This,previewCallback) )
+
+#define IDeckLinkOutput_v7_6_EnableVideoOutput(This,displayMode,flags) \
+ ( (This)->lpVtbl -> EnableVideoOutput(This,displayMode,flags) )
+
+#define IDeckLinkOutput_v7_6_DisableVideoOutput(This) \
+ ( (This)->lpVtbl -> DisableVideoOutput(This) )
+
+#define IDeckLinkOutput_v7_6_SetVideoOutputFrameMemoryAllocator(This,theAllocator) \
+ ( (This)->lpVtbl -> SetVideoOutputFrameMemoryAllocator(This,theAllocator) )
+
+#define IDeckLinkOutput_v7_6_CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) \
+ ( (This)->lpVtbl -> CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) )
+
+#define IDeckLinkOutput_v7_6_CreateAncillaryData(This,pixelFormat,outBuffer) \
+ ( (This)->lpVtbl -> CreateAncillaryData(This,pixelFormat,outBuffer) )
+
+#define IDeckLinkOutput_v7_6_DisplayVideoFrameSync(This,theFrame) \
+ ( (This)->lpVtbl -> DisplayVideoFrameSync(This,theFrame) )
+
+#define IDeckLinkOutput_v7_6_ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) \
+ ( (This)->lpVtbl -> ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) )
+
+#define IDeckLinkOutput_v7_6_SetScheduledFrameCompletionCallback(This,theCallback) \
+ ( (This)->lpVtbl -> SetScheduledFrameCompletionCallback(This,theCallback) )
+
+#define IDeckLinkOutput_v7_6_GetBufferedVideoFrameCount(This,bufferedFrameCount) \
+ ( (This)->lpVtbl -> GetBufferedVideoFrameCount(This,bufferedFrameCount) )
+
+#define IDeckLinkOutput_v7_6_EnableAudioOutput(This,sampleRate,sampleType,channelCount,streamType) \
+ ( (This)->lpVtbl -> EnableAudioOutput(This,sampleRate,sampleType,channelCount,streamType) )
+
+#define IDeckLinkOutput_v7_6_DisableAudioOutput(This) \
+ ( (This)->lpVtbl -> DisableAudioOutput(This) )
+
+#define IDeckLinkOutput_v7_6_WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) \
+ ( (This)->lpVtbl -> WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) )
+
+#define IDeckLinkOutput_v7_6_BeginAudioPreroll(This) \
+ ( (This)->lpVtbl -> BeginAudioPreroll(This) )
+
+#define IDeckLinkOutput_v7_6_EndAudioPreroll(This) \
+ ( (This)->lpVtbl -> EndAudioPreroll(This) )
+
+#define IDeckLinkOutput_v7_6_ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) \
+ ( (This)->lpVtbl -> ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) )
+
+#define IDeckLinkOutput_v7_6_GetBufferedAudioSampleFrameCount(This,bufferedSampleFrameCount) \
+ ( (This)->lpVtbl -> GetBufferedAudioSampleFrameCount(This,bufferedSampleFrameCount) )
+
+#define IDeckLinkOutput_v7_6_FlushBufferedAudioSamples(This) \
+ ( (This)->lpVtbl -> FlushBufferedAudioSamples(This) )
+
+#define IDeckLinkOutput_v7_6_SetAudioCallback(This,theCallback) \
+ ( (This)->lpVtbl -> SetAudioCallback(This,theCallback) )
+
+#define IDeckLinkOutput_v7_6_StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) \
+ ( (This)->lpVtbl -> StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) )
+
+#define IDeckLinkOutput_v7_6_StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) \
+ ( (This)->lpVtbl -> StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) )
+
+#define IDeckLinkOutput_v7_6_IsScheduledPlaybackRunning(This,active) \
+ ( (This)->lpVtbl -> IsScheduledPlaybackRunning(This,active) )
+
+#define IDeckLinkOutput_v7_6_GetScheduledStreamTime(This,desiredTimeScale,streamTime,playbackSpeed) \
+ ( (This)->lpVtbl -> GetScheduledStreamTime(This,desiredTimeScale,streamTime,playbackSpeed) )
+
+#define IDeckLinkOutput_v7_6_GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) \
+ ( (This)->lpVtbl -> GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkOutput_v7_6_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkInput_v7_6_INTERFACE_DEFINED__
+#define __IDeckLinkInput_v7_6_INTERFACE_DEFINED__
+
+/* interface IDeckLinkInput_v7_6 */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkInput_v7_6;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("300C135A-9F43-48E2-9906-6D7911D93CF1")
+ IDeckLinkInput_v7_6 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode(
+ BMDDisplayMode displayMode,
+ BMDPixelFormat pixelFormat,
+ /* [out] */ BMDDisplayModeSupport *result) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator(
+ /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetScreenPreviewCallback(
+ /* [in] */ IDeckLinkScreenPreviewCallback_v7_6 *previewCallback) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnableVideoInput(
+ BMDDisplayMode displayMode,
+ BMDPixelFormat pixelFormat,
+ BMDVideoInputFlags flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DisableVideoInput( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAvailableVideoFrameCount(
+ /* [out] */ unsigned int *availableFrameCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnableAudioInput(
+ BMDAudioSampleRate sampleRate,
+ BMDAudioSampleType sampleType,
+ unsigned int channelCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DisableAudioInput( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAvailableAudioSampleFrameCount(
+ /* [out] */ unsigned int *availableSampleFrameCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartStreams( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StopStreams( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE PauseStreams( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FlushStreams( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetCallback(
+ /* [in] */ IDeckLinkInputCallback_v7_6 *theCallback) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceClock(
+ BMDTimeScale desiredTimeScale,
+ /* [out] */ BMDTimeValue *hardwareTime,
+ /* [out] */ BMDTimeValue *timeInFrame,
+ /* [out] */ BMDTimeValue *ticksPerFrame) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkInput_v7_6Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkInput_v7_6 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkInput_v7_6 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkInput_v7_6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )(
+ IDeckLinkInput_v7_6 * This,
+ BMDDisplayMode displayMode,
+ BMDPixelFormat pixelFormat,
+ /* [out] */ BMDDisplayModeSupport *result);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )(
+ IDeckLinkInput_v7_6 * This,
+ /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator);
+
+ HRESULT ( STDMETHODCALLTYPE *SetScreenPreviewCallback )(
+ IDeckLinkInput_v7_6 * This,
+ /* [in] */ IDeckLinkScreenPreviewCallback_v7_6 *previewCallback);
+
+ HRESULT ( STDMETHODCALLTYPE *EnableVideoInput )(
+ IDeckLinkInput_v7_6 * This,
+ BMDDisplayMode displayMode,
+ BMDPixelFormat pixelFormat,
+ BMDVideoInputFlags flags);
+
+ HRESULT ( STDMETHODCALLTYPE *DisableVideoInput )(
+ IDeckLinkInput_v7_6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAvailableVideoFrameCount )(
+ IDeckLinkInput_v7_6 * This,
+ /* [out] */ unsigned int *availableFrameCount);
+
+ HRESULT ( STDMETHODCALLTYPE *EnableAudioInput )(
+ IDeckLinkInput_v7_6 * This,
+ BMDAudioSampleRate sampleRate,
+ BMDAudioSampleType sampleType,
+ unsigned int channelCount);
+
+ HRESULT ( STDMETHODCALLTYPE *DisableAudioInput )(
+ IDeckLinkInput_v7_6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAvailableAudioSampleFrameCount )(
+ IDeckLinkInput_v7_6 * This,
+ /* [out] */ unsigned int *availableSampleFrameCount);
+
+ HRESULT ( STDMETHODCALLTYPE *StartStreams )(
+ IDeckLinkInput_v7_6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *StopStreams )(
+ IDeckLinkInput_v7_6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *PauseStreams )(
+ IDeckLinkInput_v7_6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *FlushStreams )(
+ IDeckLinkInput_v7_6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetCallback )(
+ IDeckLinkInput_v7_6 * This,
+ /* [in] */ IDeckLinkInputCallback_v7_6 *theCallback);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceClock )(
+ IDeckLinkInput_v7_6 * This,
+ BMDTimeScale desiredTimeScale,
+ /* [out] */ BMDTimeValue *hardwareTime,
+ /* [out] */ BMDTimeValue *timeInFrame,
+ /* [out] */ BMDTimeValue *ticksPerFrame);
+
+ END_INTERFACE
+ } IDeckLinkInput_v7_6Vtbl;
+
+ interface IDeckLinkInput_v7_6
+ {
+ CONST_VTBL struct IDeckLinkInput_v7_6Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkInput_v7_6_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkInput_v7_6_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkInput_v7_6_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkInput_v7_6_DoesSupportVideoMode(This,displayMode,pixelFormat,result) \
+ ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,result) )
+
+#define IDeckLinkInput_v7_6_GetDisplayModeIterator(This,iterator) \
+ ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) )
+
+#define IDeckLinkInput_v7_6_SetScreenPreviewCallback(This,previewCallback) \
+ ( (This)->lpVtbl -> SetScreenPreviewCallback(This,previewCallback) )
+
+#define IDeckLinkInput_v7_6_EnableVideoInput(This,displayMode,pixelFormat,flags) \
+ ( (This)->lpVtbl -> EnableVideoInput(This,displayMode,pixelFormat,flags) )
+
+#define IDeckLinkInput_v7_6_DisableVideoInput(This) \
+ ( (This)->lpVtbl -> DisableVideoInput(This) )
+
+#define IDeckLinkInput_v7_6_GetAvailableVideoFrameCount(This,availableFrameCount) \
+ ( (This)->lpVtbl -> GetAvailableVideoFrameCount(This,availableFrameCount) )
+
+#define IDeckLinkInput_v7_6_EnableAudioInput(This,sampleRate,sampleType,channelCount) \
+ ( (This)->lpVtbl -> EnableAudioInput(This,sampleRate,sampleType,channelCount) )
+
+#define IDeckLinkInput_v7_6_DisableAudioInput(This) \
+ ( (This)->lpVtbl -> DisableAudioInput(This) )
+
+#define IDeckLinkInput_v7_6_GetAvailableAudioSampleFrameCount(This,availableSampleFrameCount) \
+ ( (This)->lpVtbl -> GetAvailableAudioSampleFrameCount(This,availableSampleFrameCount) )
+
+#define IDeckLinkInput_v7_6_StartStreams(This) \
+ ( (This)->lpVtbl -> StartStreams(This) )
+
+#define IDeckLinkInput_v7_6_StopStreams(This) \
+ ( (This)->lpVtbl -> StopStreams(This) )
+
+#define IDeckLinkInput_v7_6_PauseStreams(This) \
+ ( (This)->lpVtbl -> PauseStreams(This) )
+
+#define IDeckLinkInput_v7_6_FlushStreams(This) \
+ ( (This)->lpVtbl -> FlushStreams(This) )
+
+#define IDeckLinkInput_v7_6_SetCallback(This,theCallback) \
+ ( (This)->lpVtbl -> SetCallback(This,theCallback) )
+
+#define IDeckLinkInput_v7_6_GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) \
+ ( (This)->lpVtbl -> GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkInput_v7_6_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkTimecode_v7_6_INTERFACE_DEFINED__
+#define __IDeckLinkTimecode_v7_6_INTERFACE_DEFINED__
+
+/* interface IDeckLinkTimecode_v7_6 */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkTimecode_v7_6;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("EFB9BCA6-A521-44F7-BD69-2332F24D9EE6")
+ IDeckLinkTimecode_v7_6 : public IUnknown
+ {
+ public:
+ virtual BMDTimecodeBCD STDMETHODCALLTYPE GetBCD( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetComponents(
+ /* [out] */ unsigned char *hours,
+ /* [out] */ unsigned char *minutes,
+ /* [out] */ unsigned char *seconds,
+ /* [out] */ unsigned char *frames) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetString(
+ /* [out] */ BSTR *timecode) = 0;
+
+ virtual BMDTimecodeFlags STDMETHODCALLTYPE GetFlags( void) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkTimecode_v7_6Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkTimecode_v7_6 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkTimecode_v7_6 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkTimecode_v7_6 * This);
+
+ BMDTimecodeBCD ( STDMETHODCALLTYPE *GetBCD )(
+ IDeckLinkTimecode_v7_6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetComponents )(
+ IDeckLinkTimecode_v7_6 * This,
+ /* [out] */ unsigned char *hours,
+ /* [out] */ unsigned char *minutes,
+ /* [out] */ unsigned char *seconds,
+ /* [out] */ unsigned char *frames);
+
+ HRESULT ( STDMETHODCALLTYPE *GetString )(
+ IDeckLinkTimecode_v7_6 * This,
+ /* [out] */ BSTR *timecode);
+
+ BMDTimecodeFlags ( STDMETHODCALLTYPE *GetFlags )(
+ IDeckLinkTimecode_v7_6 * This);
+
+ END_INTERFACE
+ } IDeckLinkTimecode_v7_6Vtbl;
+
+ interface IDeckLinkTimecode_v7_6
+ {
+ CONST_VTBL struct IDeckLinkTimecode_v7_6Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkTimecode_v7_6_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkTimecode_v7_6_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkTimecode_v7_6_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkTimecode_v7_6_GetBCD(This) \
+ ( (This)->lpVtbl -> GetBCD(This) )
+
+#define IDeckLinkTimecode_v7_6_GetComponents(This,hours,minutes,seconds,frames) \
+ ( (This)->lpVtbl -> GetComponents(This,hours,minutes,seconds,frames) )
+
+#define IDeckLinkTimecode_v7_6_GetString(This,timecode) \
+ ( (This)->lpVtbl -> GetString(This,timecode) )
+
+#define IDeckLinkTimecode_v7_6_GetFlags(This) \
+ ( (This)->lpVtbl -> GetFlags(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkTimecode_v7_6_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkVideoFrame_v7_6_INTERFACE_DEFINED__
+#define __IDeckLinkVideoFrame_v7_6_INTERFACE_DEFINED__
+
+/* interface IDeckLinkVideoFrame_v7_6 */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkVideoFrame_v7_6;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("A8D8238E-6B18-4196-99E1-5AF717B83D32")
+ IDeckLinkVideoFrame_v7_6 : public IUnknown
+ {
+ public:
+ virtual long STDMETHODCALLTYPE GetWidth( void) = 0;
+
+ virtual long STDMETHODCALLTYPE GetHeight( void) = 0;
+
+ virtual long STDMETHODCALLTYPE GetRowBytes( void) = 0;
+
+ virtual BMDPixelFormat STDMETHODCALLTYPE GetPixelFormat( void) = 0;
+
+ virtual BMDFrameFlags STDMETHODCALLTYPE GetFlags( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBytes(
+ /* [out] */ void **buffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTimecode(
+ BMDTimecodeFormat format,
+ /* [out] */ IDeckLinkTimecode_v7_6 **timecode) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAncillaryData(
+ /* [out] */ IDeckLinkVideoFrameAncillary **ancillary) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkVideoFrame_v7_6Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkVideoFrame_v7_6 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkVideoFrame_v7_6 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkVideoFrame_v7_6 * This);
+
+ long ( STDMETHODCALLTYPE *GetWidth )(
+ IDeckLinkVideoFrame_v7_6 * This);
+
+ long ( STDMETHODCALLTYPE *GetHeight )(
+ IDeckLinkVideoFrame_v7_6 * This);
+
+ long ( STDMETHODCALLTYPE *GetRowBytes )(
+ IDeckLinkVideoFrame_v7_6 * This);
+
+ BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )(
+ IDeckLinkVideoFrame_v7_6 * This);
+
+ BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )(
+ IDeckLinkVideoFrame_v7_6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBytes )(
+ IDeckLinkVideoFrame_v7_6 * This,
+ /* [out] */ void **buffer);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTimecode )(
+ IDeckLinkVideoFrame_v7_6 * This,
+ BMDTimecodeFormat format,
+ /* [out] */ IDeckLinkTimecode_v7_6 **timecode);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAncillaryData )(
+ IDeckLinkVideoFrame_v7_6 * This,
+ /* [out] */ IDeckLinkVideoFrameAncillary **ancillary);
+
+ END_INTERFACE
+ } IDeckLinkVideoFrame_v7_6Vtbl;
+
+ interface IDeckLinkVideoFrame_v7_6
+ {
+ CONST_VTBL struct IDeckLinkVideoFrame_v7_6Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkVideoFrame_v7_6_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkVideoFrame_v7_6_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkVideoFrame_v7_6_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkVideoFrame_v7_6_GetWidth(This) \
+ ( (This)->lpVtbl -> GetWidth(This) )
+
+#define IDeckLinkVideoFrame_v7_6_GetHeight(This) \
+ ( (This)->lpVtbl -> GetHeight(This) )
+
+#define IDeckLinkVideoFrame_v7_6_GetRowBytes(This) \
+ ( (This)->lpVtbl -> GetRowBytes(This) )
+
+#define IDeckLinkVideoFrame_v7_6_GetPixelFormat(This) \
+ ( (This)->lpVtbl -> GetPixelFormat(This) )
+
+#define IDeckLinkVideoFrame_v7_6_GetFlags(This) \
+ ( (This)->lpVtbl -> GetFlags(This) )
+
+#define IDeckLinkVideoFrame_v7_6_GetBytes(This,buffer) \
+ ( (This)->lpVtbl -> GetBytes(This,buffer) )
+
+#define IDeckLinkVideoFrame_v7_6_GetTimecode(This,format,timecode) \
+ ( (This)->lpVtbl -> GetTimecode(This,format,timecode) )
+
+#define IDeckLinkVideoFrame_v7_6_GetAncillaryData(This,ancillary) \
+ ( (This)->lpVtbl -> GetAncillaryData(This,ancillary) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkVideoFrame_v7_6_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkMutableVideoFrame_v7_6_INTERFACE_DEFINED__
+#define __IDeckLinkMutableVideoFrame_v7_6_INTERFACE_DEFINED__
+
+/* interface IDeckLinkMutableVideoFrame_v7_6 */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkMutableVideoFrame_v7_6;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("46FCEE00-B4E6-43D0-91C0-023A7FCEB34F")
+ IDeckLinkMutableVideoFrame_v7_6 : public IDeckLinkVideoFrame_v7_6
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetFlags(
+ BMDFrameFlags newFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetTimecode(
+ BMDTimecodeFormat format,
+ /* [in] */ IDeckLinkTimecode_v7_6 *timecode) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetTimecodeFromComponents(
+ BMDTimecodeFormat format,
+ unsigned char hours,
+ unsigned char minutes,
+ unsigned char seconds,
+ unsigned char frames,
+ BMDTimecodeFlags flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetAncillaryData(
+ /* [in] */ IDeckLinkVideoFrameAncillary *ancillary) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkMutableVideoFrame_v7_6Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkMutableVideoFrame_v7_6 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkMutableVideoFrame_v7_6 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkMutableVideoFrame_v7_6 * This);
+
+ long ( STDMETHODCALLTYPE *GetWidth )(
+ IDeckLinkMutableVideoFrame_v7_6 * This);
+
+ long ( STDMETHODCALLTYPE *GetHeight )(
+ IDeckLinkMutableVideoFrame_v7_6 * This);
+
+ long ( STDMETHODCALLTYPE *GetRowBytes )(
+ IDeckLinkMutableVideoFrame_v7_6 * This);
+
+ BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )(
+ IDeckLinkMutableVideoFrame_v7_6 * This);
+
+ BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )(
+ IDeckLinkMutableVideoFrame_v7_6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBytes )(
+ IDeckLinkMutableVideoFrame_v7_6 * This,
+ /* [out] */ void **buffer);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTimecode )(
+ IDeckLinkMutableVideoFrame_v7_6 * This,
+ BMDTimecodeFormat format,
+ /* [out] */ IDeckLinkTimecode_v7_6 **timecode);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAncillaryData )(
+ IDeckLinkMutableVideoFrame_v7_6 * This,
+ /* [out] */ IDeckLinkVideoFrameAncillary **ancillary);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFlags )(
+ IDeckLinkMutableVideoFrame_v7_6 * This,
+ BMDFrameFlags newFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *SetTimecode )(
+ IDeckLinkMutableVideoFrame_v7_6 * This,
+ BMDTimecodeFormat format,
+ /* [in] */ IDeckLinkTimecode_v7_6 *timecode);
+
+ HRESULT ( STDMETHODCALLTYPE *SetTimecodeFromComponents )(
+ IDeckLinkMutableVideoFrame_v7_6 * This,
+ BMDTimecodeFormat format,
+ unsigned char hours,
+ unsigned char minutes,
+ unsigned char seconds,
+ unsigned char frames,
+ BMDTimecodeFlags flags);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAncillaryData )(
+ IDeckLinkMutableVideoFrame_v7_6 * This,
+ /* [in] */ IDeckLinkVideoFrameAncillary *ancillary);
+
+ END_INTERFACE
+ } IDeckLinkMutableVideoFrame_v7_6Vtbl;
+
+ interface IDeckLinkMutableVideoFrame_v7_6
+ {
+ CONST_VTBL struct IDeckLinkMutableVideoFrame_v7_6Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkMutableVideoFrame_v7_6_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkMutableVideoFrame_v7_6_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkMutableVideoFrame_v7_6_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkMutableVideoFrame_v7_6_GetWidth(This) \
+ ( (This)->lpVtbl -> GetWidth(This) )
+
+#define IDeckLinkMutableVideoFrame_v7_6_GetHeight(This) \
+ ( (This)->lpVtbl -> GetHeight(This) )
+
+#define IDeckLinkMutableVideoFrame_v7_6_GetRowBytes(This) \
+ ( (This)->lpVtbl -> GetRowBytes(This) )
+
+#define IDeckLinkMutableVideoFrame_v7_6_GetPixelFormat(This) \
+ ( (This)->lpVtbl -> GetPixelFormat(This) )
+
+#define IDeckLinkMutableVideoFrame_v7_6_GetFlags(This) \
+ ( (This)->lpVtbl -> GetFlags(This) )
+
+#define IDeckLinkMutableVideoFrame_v7_6_GetBytes(This,buffer) \
+ ( (This)->lpVtbl -> GetBytes(This,buffer) )
+
+#define IDeckLinkMutableVideoFrame_v7_6_GetTimecode(This,format,timecode) \
+ ( (This)->lpVtbl -> GetTimecode(This,format,timecode) )
+
+#define IDeckLinkMutableVideoFrame_v7_6_GetAncillaryData(This,ancillary) \
+ ( (This)->lpVtbl -> GetAncillaryData(This,ancillary) )
+
+
+#define IDeckLinkMutableVideoFrame_v7_6_SetFlags(This,newFlags) \
+ ( (This)->lpVtbl -> SetFlags(This,newFlags) )
+
+#define IDeckLinkMutableVideoFrame_v7_6_SetTimecode(This,format,timecode) \
+ ( (This)->lpVtbl -> SetTimecode(This,format,timecode) )
+
+#define IDeckLinkMutableVideoFrame_v7_6_SetTimecodeFromComponents(This,format,hours,minutes,seconds,frames,flags) \
+ ( (This)->lpVtbl -> SetTimecodeFromComponents(This,format,hours,minutes,seconds,frames,flags) )
+
+#define IDeckLinkMutableVideoFrame_v7_6_SetAncillaryData(This,ancillary) \
+ ( (This)->lpVtbl -> SetAncillaryData(This,ancillary) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkMutableVideoFrame_v7_6_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkVideoInputFrame_v7_6_INTERFACE_DEFINED__
+#define __IDeckLinkVideoInputFrame_v7_6_INTERFACE_DEFINED__
+
+/* interface IDeckLinkVideoInputFrame_v7_6 */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkVideoInputFrame_v7_6;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("9A74FA41-AE9F-47AC-8CF4-01F42DD59965")
+ IDeckLinkVideoInputFrame_v7_6 : public IDeckLinkVideoFrame_v7_6
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetStreamTime(
+ /* [out] */ BMDTimeValue *frameTime,
+ /* [out] */ BMDTimeValue *frameDuration,
+ BMDTimeScale timeScale) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceTimestamp(
+ BMDTimeScale timeScale,
+ /* [out] */ BMDTimeValue *frameTime,
+ /* [out] */ BMDTimeValue *frameDuration) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkVideoInputFrame_v7_6Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkVideoInputFrame_v7_6 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkVideoInputFrame_v7_6 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkVideoInputFrame_v7_6 * This);
+
+ long ( STDMETHODCALLTYPE *GetWidth )(
+ IDeckLinkVideoInputFrame_v7_6 * This);
+
+ long ( STDMETHODCALLTYPE *GetHeight )(
+ IDeckLinkVideoInputFrame_v7_6 * This);
+
+ long ( STDMETHODCALLTYPE *GetRowBytes )(
+ IDeckLinkVideoInputFrame_v7_6 * This);
+
+ BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )(
+ IDeckLinkVideoInputFrame_v7_6 * This);
+
+ BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )(
+ IDeckLinkVideoInputFrame_v7_6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBytes )(
+ IDeckLinkVideoInputFrame_v7_6 * This,
+ /* [out] */ void **buffer);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTimecode )(
+ IDeckLinkVideoInputFrame_v7_6 * This,
+ BMDTimecodeFormat format,
+ /* [out] */ IDeckLinkTimecode_v7_6 **timecode);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAncillaryData )(
+ IDeckLinkVideoInputFrame_v7_6 * This,
+ /* [out] */ IDeckLinkVideoFrameAncillary **ancillary);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStreamTime )(
+ IDeckLinkVideoInputFrame_v7_6 * This,
+ /* [out] */ BMDTimeValue *frameTime,
+ /* [out] */ BMDTimeValue *frameDuration,
+ BMDTimeScale timeScale);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceTimestamp )(
+ IDeckLinkVideoInputFrame_v7_6 * This,
+ BMDTimeScale timeScale,
+ /* [out] */ BMDTimeValue *frameTime,
+ /* [out] */ BMDTimeValue *frameDuration);
+
+ END_INTERFACE
+ } IDeckLinkVideoInputFrame_v7_6Vtbl;
+
+ interface IDeckLinkVideoInputFrame_v7_6
+ {
+ CONST_VTBL struct IDeckLinkVideoInputFrame_v7_6Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkVideoInputFrame_v7_6_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkVideoInputFrame_v7_6_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkVideoInputFrame_v7_6_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkVideoInputFrame_v7_6_GetWidth(This) \
+ ( (This)->lpVtbl -> GetWidth(This) )
+
+#define IDeckLinkVideoInputFrame_v7_6_GetHeight(This) \
+ ( (This)->lpVtbl -> GetHeight(This) )
+
+#define IDeckLinkVideoInputFrame_v7_6_GetRowBytes(This) \
+ ( (This)->lpVtbl -> GetRowBytes(This) )
+
+#define IDeckLinkVideoInputFrame_v7_6_GetPixelFormat(This) \
+ ( (This)->lpVtbl -> GetPixelFormat(This) )
+
+#define IDeckLinkVideoInputFrame_v7_6_GetFlags(This) \
+ ( (This)->lpVtbl -> GetFlags(This) )
+
+#define IDeckLinkVideoInputFrame_v7_6_GetBytes(This,buffer) \
+ ( (This)->lpVtbl -> GetBytes(This,buffer) )
+
+#define IDeckLinkVideoInputFrame_v7_6_GetTimecode(This,format,timecode) \
+ ( (This)->lpVtbl -> GetTimecode(This,format,timecode) )
+
+#define IDeckLinkVideoInputFrame_v7_6_GetAncillaryData(This,ancillary) \
+ ( (This)->lpVtbl -> GetAncillaryData(This,ancillary) )
+
+
+#define IDeckLinkVideoInputFrame_v7_6_GetStreamTime(This,frameTime,frameDuration,timeScale) \
+ ( (This)->lpVtbl -> GetStreamTime(This,frameTime,frameDuration,timeScale) )
+
+#define IDeckLinkVideoInputFrame_v7_6_GetHardwareReferenceTimestamp(This,timeScale,frameTime,frameDuration) \
+ ( (This)->lpVtbl -> GetHardwareReferenceTimestamp(This,timeScale,frameTime,frameDuration) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkVideoInputFrame_v7_6_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkScreenPreviewCallback_v7_6_INTERFACE_DEFINED__
+#define __IDeckLinkScreenPreviewCallback_v7_6_INTERFACE_DEFINED__
+
+/* interface IDeckLinkScreenPreviewCallback_v7_6 */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkScreenPreviewCallback_v7_6;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("373F499D-4B4D-4518-AD22-6354E5A5825E")
+ IDeckLinkScreenPreviewCallback_v7_6 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE DrawFrame(
+ /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkScreenPreviewCallback_v7_6Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkScreenPreviewCallback_v7_6 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkScreenPreviewCallback_v7_6 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkScreenPreviewCallback_v7_6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *DrawFrame )(
+ IDeckLinkScreenPreviewCallback_v7_6 * This,
+ /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame);
+
+ END_INTERFACE
+ } IDeckLinkScreenPreviewCallback_v7_6Vtbl;
+
+ interface IDeckLinkScreenPreviewCallback_v7_6
+ {
+ CONST_VTBL struct IDeckLinkScreenPreviewCallback_v7_6Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkScreenPreviewCallback_v7_6_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkScreenPreviewCallback_v7_6_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkScreenPreviewCallback_v7_6_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkScreenPreviewCallback_v7_6_DrawFrame(This,theFrame) \
+ ( (This)->lpVtbl -> DrawFrame(This,theFrame) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkScreenPreviewCallback_v7_6_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkGLScreenPreviewHelper_v7_6_INTERFACE_DEFINED__
+#define __IDeckLinkGLScreenPreviewHelper_v7_6_INTERFACE_DEFINED__
+
+/* interface IDeckLinkGLScreenPreviewHelper_v7_6 */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkGLScreenPreviewHelper_v7_6;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("BA575CD9-A15E-497B-B2C2-F9AFE7BE4EBA")
+ IDeckLinkGLScreenPreviewHelper_v7_6 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE InitializeGL( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE PaintGL( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetFrame(
+ /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkGLScreenPreviewHelper_v7_6Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkGLScreenPreviewHelper_v7_6 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkGLScreenPreviewHelper_v7_6 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkGLScreenPreviewHelper_v7_6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *InitializeGL )(
+ IDeckLinkGLScreenPreviewHelper_v7_6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *PaintGL )(
+ IDeckLinkGLScreenPreviewHelper_v7_6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFrame )(
+ IDeckLinkGLScreenPreviewHelper_v7_6 * This,
+ /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame);
+
+ END_INTERFACE
+ } IDeckLinkGLScreenPreviewHelper_v7_6Vtbl;
+
+ interface IDeckLinkGLScreenPreviewHelper_v7_6
+ {
+ CONST_VTBL struct IDeckLinkGLScreenPreviewHelper_v7_6Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkGLScreenPreviewHelper_v7_6_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkGLScreenPreviewHelper_v7_6_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkGLScreenPreviewHelper_v7_6_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkGLScreenPreviewHelper_v7_6_InitializeGL(This) \
+ ( (This)->lpVtbl -> InitializeGL(This) )
+
+#define IDeckLinkGLScreenPreviewHelper_v7_6_PaintGL(This) \
+ ( (This)->lpVtbl -> PaintGL(This) )
+
+#define IDeckLinkGLScreenPreviewHelper_v7_6_SetFrame(This,theFrame) \
+ ( (This)->lpVtbl -> SetFrame(This,theFrame) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkGLScreenPreviewHelper_v7_6_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkVideoConversion_v7_6_INTERFACE_DEFINED__
+#define __IDeckLinkVideoConversion_v7_6_INTERFACE_DEFINED__
+
+/* interface IDeckLinkVideoConversion_v7_6 */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkVideoConversion_v7_6;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("3EB504C9-F97D-40FE-A158-D407D48CB53B")
+ IDeckLinkVideoConversion_v7_6 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE ConvertFrame(
+ /* [in] */ IDeckLinkVideoFrame_v7_6 *srcFrame,
+ /* [in] */ IDeckLinkVideoFrame_v7_6 *dstFrame) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkVideoConversion_v7_6Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkVideoConversion_v7_6 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkVideoConversion_v7_6 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkVideoConversion_v7_6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ConvertFrame )(
+ IDeckLinkVideoConversion_v7_6 * This,
+ /* [in] */ IDeckLinkVideoFrame_v7_6 *srcFrame,
+ /* [in] */ IDeckLinkVideoFrame_v7_6 *dstFrame);
+
+ END_INTERFACE
+ } IDeckLinkVideoConversion_v7_6Vtbl;
+
+ interface IDeckLinkVideoConversion_v7_6
+ {
+ CONST_VTBL struct IDeckLinkVideoConversion_v7_6Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkVideoConversion_v7_6_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkVideoConversion_v7_6_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkVideoConversion_v7_6_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkVideoConversion_v7_6_ConvertFrame(This,srcFrame,dstFrame) \
+ ( (This)->lpVtbl -> ConvertFrame(This,srcFrame,dstFrame) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkVideoConversion_v7_6_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkConfiguration_v7_6_INTERFACE_DEFINED__
+#define __IDeckLinkConfiguration_v7_6_INTERFACE_DEFINED__
+
+/* interface IDeckLinkConfiguration_v7_6 */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkConfiguration_v7_6;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("B8EAD569-B764-47F0-A73F-AE40DF6CBF10")
+ IDeckLinkConfiguration_v7_6 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetConfigurationValidator(
+ /* [out] */ IDeckLinkConfiguration_v7_6 **configObject) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteConfigurationToPreferences( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetVideoOutputFormat(
+ /* [in] */ BMDVideoConnection_v7_6 videoOutputConnection) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsVideoOutputActive(
+ /* [in] */ BMDVideoConnection_v7_6 videoOutputConnection,
+ /* [out] */ BOOL *active) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetAnalogVideoOutputFlags(
+ /* [in] */ BMDAnalogVideoFlags analogVideoFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAnalogVideoOutputFlags(
+ /* [out] */ BMDAnalogVideoFlags *analogVideoFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnableFieldFlickerRemovalWhenPaused(
+ /* [in] */ BOOL enable) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsEnabledFieldFlickerRemovalWhenPaused(
+ /* [out] */ BOOL *enabled) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Set444And3GBpsVideoOutput(
+ /* [in] */ BOOL enable444VideoOutput,
+ /* [in] */ BOOL enable3GbsOutput) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Get444And3GBpsVideoOutput(
+ /* [out] */ BOOL *is444VideoOutputEnabled,
+ /* [out] */ BOOL *threeGbsOutputEnabled) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetVideoOutputConversionMode(
+ /* [in] */ BMDVideoOutputConversionMode conversionMode) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetVideoOutputConversionMode(
+ /* [out] */ BMDVideoOutputConversionMode *conversionMode) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Set_HD1080p24_to_HD1080i5994_Conversion(
+ /* [in] */ BOOL enable) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Get_HD1080p24_to_HD1080i5994_Conversion(
+ /* [out] */ BOOL *enabled) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetVideoInputFormat(
+ /* [in] */ BMDVideoConnection_v7_6 videoInputFormat) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetVideoInputFormat(
+ /* [out] */ BMDVideoConnection_v7_6 *videoInputFormat) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetAnalogVideoInputFlags(
+ /* [in] */ BMDAnalogVideoFlags analogVideoFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAnalogVideoInputFlags(
+ /* [out] */ BMDAnalogVideoFlags *analogVideoFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetVideoInputConversionMode(
+ /* [in] */ BMDVideoInputConversionMode conversionMode) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetVideoInputConversionMode(
+ /* [out] */ BMDVideoInputConversionMode *conversionMode) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetBlackVideoOutputDuringCapture(
+ /* [in] */ BOOL blackOutInCapture) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBlackVideoOutputDuringCapture(
+ /* [out] */ BOOL *blackOutInCapture) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Set32PulldownSequenceInitialTimecodeFrame(
+ /* [in] */ unsigned int aFrameTimecode) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Get32PulldownSequenceInitialTimecodeFrame(
+ /* [out] */ unsigned int *aFrameTimecode) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetVancSourceLineMapping(
+ /* [in] */ unsigned int activeLine1VANCsource,
+ /* [in] */ unsigned int activeLine2VANCsource,
+ /* [in] */ unsigned int activeLine3VANCsource) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetVancSourceLineMapping(
+ /* [out] */ unsigned int *activeLine1VANCsource,
+ /* [out] */ unsigned int *activeLine2VANCsource,
+ /* [out] */ unsigned int *activeLine3VANCsource) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetAudioInputFormat(
+ /* [in] */ BMDAudioConnection_v10_2 audioInputFormat) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAudioInputFormat(
+ /* [out] */ BMDAudioConnection_v10_2 *audioInputFormat) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkConfiguration_v7_6Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkConfiguration_v7_6 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkConfiguration_v7_6 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkConfiguration_v7_6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetConfigurationValidator )(
+ IDeckLinkConfiguration_v7_6 * This,
+ /* [out] */ IDeckLinkConfiguration_v7_6 **configObject);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteConfigurationToPreferences )(
+ IDeckLinkConfiguration_v7_6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetVideoOutputFormat )(
+ IDeckLinkConfiguration_v7_6 * This,
+ /* [in] */ BMDVideoConnection_v7_6 videoOutputConnection);
+
+ HRESULT ( STDMETHODCALLTYPE *IsVideoOutputActive )(
+ IDeckLinkConfiguration_v7_6 * This,
+ /* [in] */ BMDVideoConnection_v7_6 videoOutputConnection,
+ /* [out] */ BOOL *active);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAnalogVideoOutputFlags )(
+ IDeckLinkConfiguration_v7_6 * This,
+ /* [in] */ BMDAnalogVideoFlags analogVideoFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAnalogVideoOutputFlags )(
+ IDeckLinkConfiguration_v7_6 * This,
+ /* [out] */ BMDAnalogVideoFlags *analogVideoFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *EnableFieldFlickerRemovalWhenPaused )(
+ IDeckLinkConfiguration_v7_6 * This,
+ /* [in] */ BOOL enable);
+
+ HRESULT ( STDMETHODCALLTYPE *IsEnabledFieldFlickerRemovalWhenPaused )(
+ IDeckLinkConfiguration_v7_6 * This,
+ /* [out] */ BOOL *enabled);
+
+ HRESULT ( STDMETHODCALLTYPE *Set444And3GBpsVideoOutput )(
+ IDeckLinkConfiguration_v7_6 * This,
+ /* [in] */ BOOL enable444VideoOutput,
+ /* [in] */ BOOL enable3GbsOutput);
+
+ HRESULT ( STDMETHODCALLTYPE *Get444And3GBpsVideoOutput )(
+ IDeckLinkConfiguration_v7_6 * This,
+ /* [out] */ BOOL *is444VideoOutputEnabled,
+ /* [out] */ BOOL *threeGbsOutputEnabled);
+
+ HRESULT ( STDMETHODCALLTYPE *SetVideoOutputConversionMode )(
+ IDeckLinkConfiguration_v7_6 * This,
+ /* [in] */ BMDVideoOutputConversionMode conversionMode);
+
+ HRESULT ( STDMETHODCALLTYPE *GetVideoOutputConversionMode )(
+ IDeckLinkConfiguration_v7_6 * This,
+ /* [out] */ BMDVideoOutputConversionMode *conversionMode);
+
+ HRESULT ( STDMETHODCALLTYPE *Set_HD1080p24_to_HD1080i5994_Conversion )(
+ IDeckLinkConfiguration_v7_6 * This,
+ /* [in] */ BOOL enable);
+
+ HRESULT ( STDMETHODCALLTYPE *Get_HD1080p24_to_HD1080i5994_Conversion )(
+ IDeckLinkConfiguration_v7_6 * This,
+ /* [out] */ BOOL *enabled);
+
+ HRESULT ( STDMETHODCALLTYPE *SetVideoInputFormat )(
+ IDeckLinkConfiguration_v7_6 * This,
+ /* [in] */ BMDVideoConnection_v7_6 videoInputFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetVideoInputFormat )(
+ IDeckLinkConfiguration_v7_6 * This,
+ /* [out] */ BMDVideoConnection_v7_6 *videoInputFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAnalogVideoInputFlags )(
+ IDeckLinkConfiguration_v7_6 * This,
+ /* [in] */ BMDAnalogVideoFlags analogVideoFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAnalogVideoInputFlags )(
+ IDeckLinkConfiguration_v7_6 * This,
+ /* [out] */ BMDAnalogVideoFlags *analogVideoFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *SetVideoInputConversionMode )(
+ IDeckLinkConfiguration_v7_6 * This,
+ /* [in] */ BMDVideoInputConversionMode conversionMode);
+
+ HRESULT ( STDMETHODCALLTYPE *GetVideoInputConversionMode )(
+ IDeckLinkConfiguration_v7_6 * This,
+ /* [out] */ BMDVideoInputConversionMode *conversionMode);
+
+ HRESULT ( STDMETHODCALLTYPE *SetBlackVideoOutputDuringCapture )(
+ IDeckLinkConfiguration_v7_6 * This,
+ /* [in] */ BOOL blackOutInCapture);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBlackVideoOutputDuringCapture )(
+ IDeckLinkConfiguration_v7_6 * This,
+ /* [out] */ BOOL *blackOutInCapture);
+
+ HRESULT ( STDMETHODCALLTYPE *Set32PulldownSequenceInitialTimecodeFrame )(
+ IDeckLinkConfiguration_v7_6 * This,
+ /* [in] */ unsigned int aFrameTimecode);
+
+ HRESULT ( STDMETHODCALLTYPE *Get32PulldownSequenceInitialTimecodeFrame )(
+ IDeckLinkConfiguration_v7_6 * This,
+ /* [out] */ unsigned int *aFrameTimecode);
+
+ HRESULT ( STDMETHODCALLTYPE *SetVancSourceLineMapping )(
+ IDeckLinkConfiguration_v7_6 * This,
+ /* [in] */ unsigned int activeLine1VANCsource,
+ /* [in] */ unsigned int activeLine2VANCsource,
+ /* [in] */ unsigned int activeLine3VANCsource);
+
+ HRESULT ( STDMETHODCALLTYPE *GetVancSourceLineMapping )(
+ IDeckLinkConfiguration_v7_6 * This,
+ /* [out] */ unsigned int *activeLine1VANCsource,
+ /* [out] */ unsigned int *activeLine2VANCsource,
+ /* [out] */ unsigned int *activeLine3VANCsource);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAudioInputFormat )(
+ IDeckLinkConfiguration_v7_6 * This,
+ /* [in] */ BMDAudioConnection_v10_2 audioInputFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAudioInputFormat )(
+ IDeckLinkConfiguration_v7_6 * This,
+ /* [out] */ BMDAudioConnection_v10_2 *audioInputFormat);
+
+ END_INTERFACE
+ } IDeckLinkConfiguration_v7_6Vtbl;
+
+ interface IDeckLinkConfiguration_v7_6
+ {
+ CONST_VTBL struct IDeckLinkConfiguration_v7_6Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkConfiguration_v7_6_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkConfiguration_v7_6_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkConfiguration_v7_6_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkConfiguration_v7_6_GetConfigurationValidator(This,configObject) \
+ ( (This)->lpVtbl -> GetConfigurationValidator(This,configObject) )
+
+#define IDeckLinkConfiguration_v7_6_WriteConfigurationToPreferences(This) \
+ ( (This)->lpVtbl -> WriteConfigurationToPreferences(This) )
+
+#define IDeckLinkConfiguration_v7_6_SetVideoOutputFormat(This,videoOutputConnection) \
+ ( (This)->lpVtbl -> SetVideoOutputFormat(This,videoOutputConnection) )
+
+#define IDeckLinkConfiguration_v7_6_IsVideoOutputActive(This,videoOutputConnection,active) \
+ ( (This)->lpVtbl -> IsVideoOutputActive(This,videoOutputConnection,active) )
+
+#define IDeckLinkConfiguration_v7_6_SetAnalogVideoOutputFlags(This,analogVideoFlags) \
+ ( (This)->lpVtbl -> SetAnalogVideoOutputFlags(This,analogVideoFlags) )
+
+#define IDeckLinkConfiguration_v7_6_GetAnalogVideoOutputFlags(This,analogVideoFlags) \
+ ( (This)->lpVtbl -> GetAnalogVideoOutputFlags(This,analogVideoFlags) )
+
+#define IDeckLinkConfiguration_v7_6_EnableFieldFlickerRemovalWhenPaused(This,enable) \
+ ( (This)->lpVtbl -> EnableFieldFlickerRemovalWhenPaused(This,enable) )
+
+#define IDeckLinkConfiguration_v7_6_IsEnabledFieldFlickerRemovalWhenPaused(This,enabled) \
+ ( (This)->lpVtbl -> IsEnabledFieldFlickerRemovalWhenPaused(This,enabled) )
+
+#define IDeckLinkConfiguration_v7_6_Set444And3GBpsVideoOutput(This,enable444VideoOutput,enable3GbsOutput) \
+ ( (This)->lpVtbl -> Set444And3GBpsVideoOutput(This,enable444VideoOutput,enable3GbsOutput) )
+
+#define IDeckLinkConfiguration_v7_6_Get444And3GBpsVideoOutput(This,is444VideoOutputEnabled,threeGbsOutputEnabled) \
+ ( (This)->lpVtbl -> Get444And3GBpsVideoOutput(This,is444VideoOutputEnabled,threeGbsOutputEnabled) )
+
+#define IDeckLinkConfiguration_v7_6_SetVideoOutputConversionMode(This,conversionMode) \
+ ( (This)->lpVtbl -> SetVideoOutputConversionMode(This,conversionMode) )
+
+#define IDeckLinkConfiguration_v7_6_GetVideoOutputConversionMode(This,conversionMode) \
+ ( (This)->lpVtbl -> GetVideoOutputConversionMode(This,conversionMode) )
+
+#define IDeckLinkConfiguration_v7_6_Set_HD1080p24_to_HD1080i5994_Conversion(This,enable) \
+ ( (This)->lpVtbl -> Set_HD1080p24_to_HD1080i5994_Conversion(This,enable) )
+
+#define IDeckLinkConfiguration_v7_6_Get_HD1080p24_to_HD1080i5994_Conversion(This,enabled) \
+ ( (This)->lpVtbl -> Get_HD1080p24_to_HD1080i5994_Conversion(This,enabled) )
+
+#define IDeckLinkConfiguration_v7_6_SetVideoInputFormat(This,videoInputFormat) \
+ ( (This)->lpVtbl -> SetVideoInputFormat(This,videoInputFormat) )
+
+#define IDeckLinkConfiguration_v7_6_GetVideoInputFormat(This,videoInputFormat) \
+ ( (This)->lpVtbl -> GetVideoInputFormat(This,videoInputFormat) )
+
+#define IDeckLinkConfiguration_v7_6_SetAnalogVideoInputFlags(This,analogVideoFlags) \
+ ( (This)->lpVtbl -> SetAnalogVideoInputFlags(This,analogVideoFlags) )
+
+#define IDeckLinkConfiguration_v7_6_GetAnalogVideoInputFlags(This,analogVideoFlags) \
+ ( (This)->lpVtbl -> GetAnalogVideoInputFlags(This,analogVideoFlags) )
+
+#define IDeckLinkConfiguration_v7_6_SetVideoInputConversionMode(This,conversionMode) \
+ ( (This)->lpVtbl -> SetVideoInputConversionMode(This,conversionMode) )
+
+#define IDeckLinkConfiguration_v7_6_GetVideoInputConversionMode(This,conversionMode) \
+ ( (This)->lpVtbl -> GetVideoInputConversionMode(This,conversionMode) )
+
+#define IDeckLinkConfiguration_v7_6_SetBlackVideoOutputDuringCapture(This,blackOutInCapture) \
+ ( (This)->lpVtbl -> SetBlackVideoOutputDuringCapture(This,blackOutInCapture) )
+
+#define IDeckLinkConfiguration_v7_6_GetBlackVideoOutputDuringCapture(This,blackOutInCapture) \
+ ( (This)->lpVtbl -> GetBlackVideoOutputDuringCapture(This,blackOutInCapture) )
+
+#define IDeckLinkConfiguration_v7_6_Set32PulldownSequenceInitialTimecodeFrame(This,aFrameTimecode) \
+ ( (This)->lpVtbl -> Set32PulldownSequenceInitialTimecodeFrame(This,aFrameTimecode) )
+
+#define IDeckLinkConfiguration_v7_6_Get32PulldownSequenceInitialTimecodeFrame(This,aFrameTimecode) \
+ ( (This)->lpVtbl -> Get32PulldownSequenceInitialTimecodeFrame(This,aFrameTimecode) )
+
+#define IDeckLinkConfiguration_v7_6_SetVancSourceLineMapping(This,activeLine1VANCsource,activeLine2VANCsource,activeLine3VANCsource) \
+ ( (This)->lpVtbl -> SetVancSourceLineMapping(This,activeLine1VANCsource,activeLine2VANCsource,activeLine3VANCsource) )
+
+#define IDeckLinkConfiguration_v7_6_GetVancSourceLineMapping(This,activeLine1VANCsource,activeLine2VANCsource,activeLine3VANCsource) \
+ ( (This)->lpVtbl -> GetVancSourceLineMapping(This,activeLine1VANCsource,activeLine2VANCsource,activeLine3VANCsource) )
+
+#define IDeckLinkConfiguration_v7_6_SetAudioInputFormat(This,audioInputFormat) \
+ ( (This)->lpVtbl -> SetAudioInputFormat(This,audioInputFormat) )
+
+#define IDeckLinkConfiguration_v7_6_GetAudioInputFormat(This,audioInputFormat) \
+ ( (This)->lpVtbl -> GetAudioInputFormat(This,audioInputFormat) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkConfiguration_v7_6_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkVideoOutputCallback_v7_6_INTERFACE_DEFINED__
+#define __IDeckLinkVideoOutputCallback_v7_6_INTERFACE_DEFINED__
+
+/* interface IDeckLinkVideoOutputCallback_v7_6 */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkVideoOutputCallback_v7_6;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("E763A626-4A3C-49D1-BF13-E7AD3692AE52")
+ IDeckLinkVideoOutputCallback_v7_6 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE ScheduledFrameCompleted(
+ /* [in] */ IDeckLinkVideoFrame_v7_6 *completedFrame,
+ /* [in] */ BMDOutputFrameCompletionResult result) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ScheduledPlaybackHasStopped( void) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkVideoOutputCallback_v7_6Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkVideoOutputCallback_v7_6 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkVideoOutputCallback_v7_6 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkVideoOutputCallback_v7_6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ScheduledFrameCompleted )(
+ IDeckLinkVideoOutputCallback_v7_6 * This,
+ /* [in] */ IDeckLinkVideoFrame_v7_6 *completedFrame,
+ /* [in] */ BMDOutputFrameCompletionResult result);
+
+ HRESULT ( STDMETHODCALLTYPE *ScheduledPlaybackHasStopped )(
+ IDeckLinkVideoOutputCallback_v7_6 * This);
+
+ END_INTERFACE
+ } IDeckLinkVideoOutputCallback_v7_6Vtbl;
+
+ interface IDeckLinkVideoOutputCallback_v7_6
+ {
+ CONST_VTBL struct IDeckLinkVideoOutputCallback_v7_6Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkVideoOutputCallback_v7_6_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkVideoOutputCallback_v7_6_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkVideoOutputCallback_v7_6_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkVideoOutputCallback_v7_6_ScheduledFrameCompleted(This,completedFrame,result) \
+ ( (This)->lpVtbl -> ScheduledFrameCompleted(This,completedFrame,result) )
+
+#define IDeckLinkVideoOutputCallback_v7_6_ScheduledPlaybackHasStopped(This) \
+ ( (This)->lpVtbl -> ScheduledPlaybackHasStopped(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkVideoOutputCallback_v7_6_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkInputCallback_v7_6_INTERFACE_DEFINED__
+#define __IDeckLinkInputCallback_v7_6_INTERFACE_DEFINED__
+
+/* interface IDeckLinkInputCallback_v7_6 */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkInputCallback_v7_6;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("31D28EE7-88B6-4CB1-897A-CDBF79A26414")
+ IDeckLinkInputCallback_v7_6 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(
+ /* [in] */ BMDVideoInputFormatChangedEvents notificationEvents,
+ /* [in] */ IDeckLinkDisplayMode_v7_6 *newDisplayMode,
+ /* [in] */ BMDDetectedVideoInputFormatFlags detectedSignalFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(
+ /* [in] */ IDeckLinkVideoInputFrame_v7_6 *videoFrame,
+ /* [in] */ IDeckLinkAudioInputPacket *audioPacket) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkInputCallback_v7_6Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkInputCallback_v7_6 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkInputCallback_v7_6 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkInputCallback_v7_6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *VideoInputFormatChanged )(
+ IDeckLinkInputCallback_v7_6 * This,
+ /* [in] */ BMDVideoInputFormatChangedEvents notificationEvents,
+ /* [in] */ IDeckLinkDisplayMode_v7_6 *newDisplayMode,
+ /* [in] */ BMDDetectedVideoInputFormatFlags detectedSignalFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *VideoInputFrameArrived )(
+ IDeckLinkInputCallback_v7_6 * This,
+ /* [in] */ IDeckLinkVideoInputFrame_v7_6 *videoFrame,
+ /* [in] */ IDeckLinkAudioInputPacket *audioPacket);
+
+ END_INTERFACE
+ } IDeckLinkInputCallback_v7_6Vtbl;
+
+ interface IDeckLinkInputCallback_v7_6
+ {
+ CONST_VTBL struct IDeckLinkInputCallback_v7_6Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkInputCallback_v7_6_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkInputCallback_v7_6_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkInputCallback_v7_6_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkInputCallback_v7_6_VideoInputFormatChanged(This,notificationEvents,newDisplayMode,detectedSignalFlags) \
+ ( (This)->lpVtbl -> VideoInputFormatChanged(This,notificationEvents,newDisplayMode,detectedSignalFlags) )
+
+#define IDeckLinkInputCallback_v7_6_VideoInputFrameArrived(This,videoFrame,audioPacket) \
+ ( (This)->lpVtbl -> VideoInputFrameArrived(This,videoFrame,audioPacket) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkInputCallback_v7_6_INTERFACE_DEFINED__ */
+
+
+EXTERN_C const CLSID CLSID_CDeckLinkGLScreenPreviewHelper_v7_6;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("D398CEE7-4434-4CA3-9BA6-5AE34556B905")
+CDeckLinkGLScreenPreviewHelper_v7_6;
+#endif
+
+EXTERN_C const CLSID CLSID_CDeckLinkVideoConversion_v7_6;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("FFA84F77-73BE-4FB7-B03E-B5E44B9F759B")
+CDeckLinkVideoConversion_v7_6;
+#endif
+
+#ifndef __IDeckLinkInputCallback_v7_3_INTERFACE_DEFINED__
+#define __IDeckLinkInputCallback_v7_3_INTERFACE_DEFINED__
+
+/* interface IDeckLinkInputCallback_v7_3 */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkInputCallback_v7_3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("FD6F311D-4D00-444B-9ED4-1F25B5730AD0")
+ IDeckLinkInputCallback_v7_3 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(
+ /* [in] */ BMDVideoInputFormatChangedEvents notificationEvents,
+ /* [in] */ IDeckLinkDisplayMode_v7_6 *newDisplayMode,
+ /* [in] */ BMDDetectedVideoInputFormatFlags detectedSignalFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(
+ /* [in] */ IDeckLinkVideoInputFrame_v7_3 *videoFrame,
+ /* [in] */ IDeckLinkAudioInputPacket *audioPacket) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkInputCallback_v7_3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkInputCallback_v7_3 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkInputCallback_v7_3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkInputCallback_v7_3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *VideoInputFormatChanged )(
+ IDeckLinkInputCallback_v7_3 * This,
+ /* [in] */ BMDVideoInputFormatChangedEvents notificationEvents,
+ /* [in] */ IDeckLinkDisplayMode_v7_6 *newDisplayMode,
+ /* [in] */ BMDDetectedVideoInputFormatFlags detectedSignalFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *VideoInputFrameArrived )(
+ IDeckLinkInputCallback_v7_3 * This,
+ /* [in] */ IDeckLinkVideoInputFrame_v7_3 *videoFrame,
+ /* [in] */ IDeckLinkAudioInputPacket *audioPacket);
+
+ END_INTERFACE
+ } IDeckLinkInputCallback_v7_3Vtbl;
+
+ interface IDeckLinkInputCallback_v7_3
+ {
+ CONST_VTBL struct IDeckLinkInputCallback_v7_3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkInputCallback_v7_3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkInputCallback_v7_3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkInputCallback_v7_3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkInputCallback_v7_3_VideoInputFormatChanged(This,notificationEvents,newDisplayMode,detectedSignalFlags) \
+ ( (This)->lpVtbl -> VideoInputFormatChanged(This,notificationEvents,newDisplayMode,detectedSignalFlags) )
+
+#define IDeckLinkInputCallback_v7_3_VideoInputFrameArrived(This,videoFrame,audioPacket) \
+ ( (This)->lpVtbl -> VideoInputFrameArrived(This,videoFrame,audioPacket) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkInputCallback_v7_3_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkOutput_v7_3_INTERFACE_DEFINED__
+#define __IDeckLinkOutput_v7_3_INTERFACE_DEFINED__
+
+/* interface IDeckLinkOutput_v7_3 */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkOutput_v7_3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("271C65E3-C323-4344-A30F-D908BCB20AA3")
+ IDeckLinkOutput_v7_3 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode(
+ BMDDisplayMode displayMode,
+ BMDPixelFormat pixelFormat,
+ /* [out] */ BMDDisplayModeSupport *result) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator(
+ /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetScreenPreviewCallback(
+ /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnableVideoOutput(
+ BMDDisplayMode displayMode,
+ BMDVideoOutputFlags flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DisableVideoOutput( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetVideoOutputFrameMemoryAllocator(
+ /* [in] */ IDeckLinkMemoryAllocator *theAllocator) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateVideoFrame(
+ int width,
+ int height,
+ int rowBytes,
+ BMDPixelFormat pixelFormat,
+ BMDFrameFlags flags,
+ /* [out] */ IDeckLinkMutableVideoFrame_v7_6 **outFrame) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateAncillaryData(
+ BMDPixelFormat pixelFormat,
+ /* [out] */ IDeckLinkVideoFrameAncillary **outBuffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DisplayVideoFrameSync(
+ /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ScheduleVideoFrame(
+ /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame,
+ BMDTimeValue displayTime,
+ BMDTimeValue displayDuration,
+ BMDTimeScale timeScale) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetScheduledFrameCompletionCallback(
+ /* [in] */ IDeckLinkVideoOutputCallback *theCallback) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBufferedVideoFrameCount(
+ /* [out] */ unsigned int *bufferedFrameCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnableAudioOutput(
+ BMDAudioSampleRate sampleRate,
+ BMDAudioSampleType sampleType,
+ unsigned int channelCount,
+ BMDAudioOutputStreamType streamType) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DisableAudioOutput( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteAudioSamplesSync(
+ /* [in] */ void *buffer,
+ unsigned int sampleFrameCount,
+ /* [out] */ unsigned int *sampleFramesWritten) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE BeginAudioPreroll( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndAudioPreroll( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ScheduleAudioSamples(
+ /* [in] */ void *buffer,
+ unsigned int sampleFrameCount,
+ BMDTimeValue streamTime,
+ BMDTimeScale timeScale,
+ /* [out] */ unsigned int *sampleFramesWritten) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBufferedAudioSampleFrameCount(
+ /* [out] */ unsigned int *bufferedSampleFrameCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FlushBufferedAudioSamples( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetAudioCallback(
+ /* [in] */ IDeckLinkAudioOutputCallback *theCallback) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartScheduledPlayback(
+ BMDTimeValue playbackStartTime,
+ BMDTimeScale timeScale,
+ double playbackSpeed) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StopScheduledPlayback(
+ BMDTimeValue stopPlaybackAtTime,
+ /* [out] */ BMDTimeValue *actualStopTime,
+ BMDTimeScale timeScale) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsScheduledPlaybackRunning(
+ /* [out] */ BOOL *active) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceClock(
+ BMDTimeScale desiredTimeScale,
+ /* [out] */ BMDTimeValue *elapsedTimeSinceSchedulerBegan) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkOutput_v7_3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkOutput_v7_3 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkOutput_v7_3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkOutput_v7_3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )(
+ IDeckLinkOutput_v7_3 * This,
+ BMDDisplayMode displayMode,
+ BMDPixelFormat pixelFormat,
+ /* [out] */ BMDDisplayModeSupport *result);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )(
+ IDeckLinkOutput_v7_3 * This,
+ /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator);
+
+ HRESULT ( STDMETHODCALLTYPE *SetScreenPreviewCallback )(
+ IDeckLinkOutput_v7_3 * This,
+ /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback);
+
+ HRESULT ( STDMETHODCALLTYPE *EnableVideoOutput )(
+ IDeckLinkOutput_v7_3 * This,
+ BMDDisplayMode displayMode,
+ BMDVideoOutputFlags flags);
+
+ HRESULT ( STDMETHODCALLTYPE *DisableVideoOutput )(
+ IDeckLinkOutput_v7_3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetVideoOutputFrameMemoryAllocator )(
+ IDeckLinkOutput_v7_3 * This,
+ /* [in] */ IDeckLinkMemoryAllocator *theAllocator);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateVideoFrame )(
+ IDeckLinkOutput_v7_3 * This,
+ int width,
+ int height,
+ int rowBytes,
+ BMDPixelFormat pixelFormat,
+ BMDFrameFlags flags,
+ /* [out] */ IDeckLinkMutableVideoFrame_v7_6 **outFrame);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateAncillaryData )(
+ IDeckLinkOutput_v7_3 * This,
+ BMDPixelFormat pixelFormat,
+ /* [out] */ IDeckLinkVideoFrameAncillary **outBuffer);
+
+ HRESULT ( STDMETHODCALLTYPE *DisplayVideoFrameSync )(
+ IDeckLinkOutput_v7_3 * This,
+ /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame);
+
+ HRESULT ( STDMETHODCALLTYPE *ScheduleVideoFrame )(
+ IDeckLinkOutput_v7_3 * This,
+ /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame,
+ BMDTimeValue displayTime,
+ BMDTimeValue displayDuration,
+ BMDTimeScale timeScale);
+
+ HRESULT ( STDMETHODCALLTYPE *SetScheduledFrameCompletionCallback )(
+ IDeckLinkOutput_v7_3 * This,
+ /* [in] */ IDeckLinkVideoOutputCallback *theCallback);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBufferedVideoFrameCount )(
+ IDeckLinkOutput_v7_3 * This,
+ /* [out] */ unsigned int *bufferedFrameCount);
+
+ HRESULT ( STDMETHODCALLTYPE *EnableAudioOutput )(
+ IDeckLinkOutput_v7_3 * This,
+ BMDAudioSampleRate sampleRate,
+ BMDAudioSampleType sampleType,
+ unsigned int channelCount,
+ BMDAudioOutputStreamType streamType);
+
+ HRESULT ( STDMETHODCALLTYPE *DisableAudioOutput )(
+ IDeckLinkOutput_v7_3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteAudioSamplesSync )(
+ IDeckLinkOutput_v7_3 * This,
+ /* [in] */ void *buffer,
+ unsigned int sampleFrameCount,
+ /* [out] */ unsigned int *sampleFramesWritten);
+
+ HRESULT ( STDMETHODCALLTYPE *BeginAudioPreroll )(
+ IDeckLinkOutput_v7_3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *EndAudioPreroll )(
+ IDeckLinkOutput_v7_3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ScheduleAudioSamples )(
+ IDeckLinkOutput_v7_3 * This,
+ /* [in] */ void *buffer,
+ unsigned int sampleFrameCount,
+ BMDTimeValue streamTime,
+ BMDTimeScale timeScale,
+ /* [out] */ unsigned int *sampleFramesWritten);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBufferedAudioSampleFrameCount )(
+ IDeckLinkOutput_v7_3 * This,
+ /* [out] */ unsigned int *bufferedSampleFrameCount);
+
+ HRESULT ( STDMETHODCALLTYPE *FlushBufferedAudioSamples )(
+ IDeckLinkOutput_v7_3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAudioCallback )(
+ IDeckLinkOutput_v7_3 * This,
+ /* [in] */ IDeckLinkAudioOutputCallback *theCallback);
+
+ HRESULT ( STDMETHODCALLTYPE *StartScheduledPlayback )(
+ IDeckLinkOutput_v7_3 * This,
+ BMDTimeValue playbackStartTime,
+ BMDTimeScale timeScale,
+ double playbackSpeed);
+
+ HRESULT ( STDMETHODCALLTYPE *StopScheduledPlayback )(
+ IDeckLinkOutput_v7_3 * This,
+ BMDTimeValue stopPlaybackAtTime,
+ /* [out] */ BMDTimeValue *actualStopTime,
+ BMDTimeScale timeScale);
+
+ HRESULT ( STDMETHODCALLTYPE *IsScheduledPlaybackRunning )(
+ IDeckLinkOutput_v7_3 * This,
+ /* [out] */ BOOL *active);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceClock )(
+ IDeckLinkOutput_v7_3 * This,
+ BMDTimeScale desiredTimeScale,
+ /* [out] */ BMDTimeValue *elapsedTimeSinceSchedulerBegan);
+
+ END_INTERFACE
+ } IDeckLinkOutput_v7_3Vtbl;
+
+ interface IDeckLinkOutput_v7_3
+ {
+ CONST_VTBL struct IDeckLinkOutput_v7_3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkOutput_v7_3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkOutput_v7_3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkOutput_v7_3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkOutput_v7_3_DoesSupportVideoMode(This,displayMode,pixelFormat,result) \
+ ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,result) )
+
+#define IDeckLinkOutput_v7_3_GetDisplayModeIterator(This,iterator) \
+ ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) )
+
+#define IDeckLinkOutput_v7_3_SetScreenPreviewCallback(This,previewCallback) \
+ ( (This)->lpVtbl -> SetScreenPreviewCallback(This,previewCallback) )
+
+#define IDeckLinkOutput_v7_3_EnableVideoOutput(This,displayMode,flags) \
+ ( (This)->lpVtbl -> EnableVideoOutput(This,displayMode,flags) )
+
+#define IDeckLinkOutput_v7_3_DisableVideoOutput(This) \
+ ( (This)->lpVtbl -> DisableVideoOutput(This) )
+
+#define IDeckLinkOutput_v7_3_SetVideoOutputFrameMemoryAllocator(This,theAllocator) \
+ ( (This)->lpVtbl -> SetVideoOutputFrameMemoryAllocator(This,theAllocator) )
+
+#define IDeckLinkOutput_v7_3_CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) \
+ ( (This)->lpVtbl -> CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) )
+
+#define IDeckLinkOutput_v7_3_CreateAncillaryData(This,pixelFormat,outBuffer) \
+ ( (This)->lpVtbl -> CreateAncillaryData(This,pixelFormat,outBuffer) )
+
+#define IDeckLinkOutput_v7_3_DisplayVideoFrameSync(This,theFrame) \
+ ( (This)->lpVtbl -> DisplayVideoFrameSync(This,theFrame) )
+
+#define IDeckLinkOutput_v7_3_ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) \
+ ( (This)->lpVtbl -> ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) )
+
+#define IDeckLinkOutput_v7_3_SetScheduledFrameCompletionCallback(This,theCallback) \
+ ( (This)->lpVtbl -> SetScheduledFrameCompletionCallback(This,theCallback) )
+
+#define IDeckLinkOutput_v7_3_GetBufferedVideoFrameCount(This,bufferedFrameCount) \
+ ( (This)->lpVtbl -> GetBufferedVideoFrameCount(This,bufferedFrameCount) )
+
+#define IDeckLinkOutput_v7_3_EnableAudioOutput(This,sampleRate,sampleType,channelCount,streamType) \
+ ( (This)->lpVtbl -> EnableAudioOutput(This,sampleRate,sampleType,channelCount,streamType) )
+
+#define IDeckLinkOutput_v7_3_DisableAudioOutput(This) \
+ ( (This)->lpVtbl -> DisableAudioOutput(This) )
+
+#define IDeckLinkOutput_v7_3_WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) \
+ ( (This)->lpVtbl -> WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) )
+
+#define IDeckLinkOutput_v7_3_BeginAudioPreroll(This) \
+ ( (This)->lpVtbl -> BeginAudioPreroll(This) )
+
+#define IDeckLinkOutput_v7_3_EndAudioPreroll(This) \
+ ( (This)->lpVtbl -> EndAudioPreroll(This) )
+
+#define IDeckLinkOutput_v7_3_ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) \
+ ( (This)->lpVtbl -> ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) )
+
+#define IDeckLinkOutput_v7_3_GetBufferedAudioSampleFrameCount(This,bufferedSampleFrameCount) \
+ ( (This)->lpVtbl -> GetBufferedAudioSampleFrameCount(This,bufferedSampleFrameCount) )
+
+#define IDeckLinkOutput_v7_3_FlushBufferedAudioSamples(This) \
+ ( (This)->lpVtbl -> FlushBufferedAudioSamples(This) )
+
+#define IDeckLinkOutput_v7_3_SetAudioCallback(This,theCallback) \
+ ( (This)->lpVtbl -> SetAudioCallback(This,theCallback) )
+
+#define IDeckLinkOutput_v7_3_StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) \
+ ( (This)->lpVtbl -> StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) )
+
+#define IDeckLinkOutput_v7_3_StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) \
+ ( (This)->lpVtbl -> StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) )
+
+#define IDeckLinkOutput_v7_3_IsScheduledPlaybackRunning(This,active) \
+ ( (This)->lpVtbl -> IsScheduledPlaybackRunning(This,active) )
+
+#define IDeckLinkOutput_v7_3_GetHardwareReferenceClock(This,desiredTimeScale,elapsedTimeSinceSchedulerBegan) \
+ ( (This)->lpVtbl -> GetHardwareReferenceClock(This,desiredTimeScale,elapsedTimeSinceSchedulerBegan) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkOutput_v7_3_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkInput_v7_3_INTERFACE_DEFINED__
+#define __IDeckLinkInput_v7_3_INTERFACE_DEFINED__
+
+/* interface IDeckLinkInput_v7_3 */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkInput_v7_3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("4973F012-9925-458C-871C-18774CDBBECB")
+ IDeckLinkInput_v7_3 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode(
+ BMDDisplayMode displayMode,
+ BMDPixelFormat pixelFormat,
+ /* [out] */ BMDDisplayModeSupport *result) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator(
+ /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetScreenPreviewCallback(
+ /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnableVideoInput(
+ BMDDisplayMode displayMode,
+ BMDPixelFormat pixelFormat,
+ BMDVideoInputFlags flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DisableVideoInput( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAvailableVideoFrameCount(
+ /* [out] */ unsigned int *availableFrameCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnableAudioInput(
+ BMDAudioSampleRate sampleRate,
+ BMDAudioSampleType sampleType,
+ unsigned int channelCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DisableAudioInput( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAvailableAudioSampleFrameCount(
+ /* [out] */ unsigned int *availableSampleFrameCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartStreams( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StopStreams( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE PauseStreams( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FlushStreams( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetCallback(
+ /* [in] */ IDeckLinkInputCallback_v7_3 *theCallback) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkInput_v7_3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkInput_v7_3 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkInput_v7_3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkInput_v7_3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )(
+ IDeckLinkInput_v7_3 * This,
+ BMDDisplayMode displayMode,
+ BMDPixelFormat pixelFormat,
+ /* [out] */ BMDDisplayModeSupport *result);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )(
+ IDeckLinkInput_v7_3 * This,
+ /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator);
+
+ HRESULT ( STDMETHODCALLTYPE *SetScreenPreviewCallback )(
+ IDeckLinkInput_v7_3 * This,
+ /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback);
+
+ HRESULT ( STDMETHODCALLTYPE *EnableVideoInput )(
+ IDeckLinkInput_v7_3 * This,
+ BMDDisplayMode displayMode,
+ BMDPixelFormat pixelFormat,
+ BMDVideoInputFlags flags);
+
+ HRESULT ( STDMETHODCALLTYPE *DisableVideoInput )(
+ IDeckLinkInput_v7_3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAvailableVideoFrameCount )(
+ IDeckLinkInput_v7_3 * This,
+ /* [out] */ unsigned int *availableFrameCount);
+
+ HRESULT ( STDMETHODCALLTYPE *EnableAudioInput )(
+ IDeckLinkInput_v7_3 * This,
+ BMDAudioSampleRate sampleRate,
+ BMDAudioSampleType sampleType,
+ unsigned int channelCount);
+
+ HRESULT ( STDMETHODCALLTYPE *DisableAudioInput )(
+ IDeckLinkInput_v7_3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAvailableAudioSampleFrameCount )(
+ IDeckLinkInput_v7_3 * This,
+ /* [out] */ unsigned int *availableSampleFrameCount);
+
+ HRESULT ( STDMETHODCALLTYPE *StartStreams )(
+ IDeckLinkInput_v7_3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *StopStreams )(
+ IDeckLinkInput_v7_3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *PauseStreams )(
+ IDeckLinkInput_v7_3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *FlushStreams )(
+ IDeckLinkInput_v7_3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetCallback )(
+ IDeckLinkInput_v7_3 * This,
+ /* [in] */ IDeckLinkInputCallback_v7_3 *theCallback);
+
+ END_INTERFACE
+ } IDeckLinkInput_v7_3Vtbl;
+
+ interface IDeckLinkInput_v7_3
+ {
+ CONST_VTBL struct IDeckLinkInput_v7_3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkInput_v7_3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkInput_v7_3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkInput_v7_3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkInput_v7_3_DoesSupportVideoMode(This,displayMode,pixelFormat,result) \
+ ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,result) )
+
+#define IDeckLinkInput_v7_3_GetDisplayModeIterator(This,iterator) \
+ ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) )
+
+#define IDeckLinkInput_v7_3_SetScreenPreviewCallback(This,previewCallback) \
+ ( (This)->lpVtbl -> SetScreenPreviewCallback(This,previewCallback) )
+
+#define IDeckLinkInput_v7_3_EnableVideoInput(This,displayMode,pixelFormat,flags) \
+ ( (This)->lpVtbl -> EnableVideoInput(This,displayMode,pixelFormat,flags) )
+
+#define IDeckLinkInput_v7_3_DisableVideoInput(This) \
+ ( (This)->lpVtbl -> DisableVideoInput(This) )
+
+#define IDeckLinkInput_v7_3_GetAvailableVideoFrameCount(This,availableFrameCount) \
+ ( (This)->lpVtbl -> GetAvailableVideoFrameCount(This,availableFrameCount) )
+
+#define IDeckLinkInput_v7_3_EnableAudioInput(This,sampleRate,sampleType,channelCount) \
+ ( (This)->lpVtbl -> EnableAudioInput(This,sampleRate,sampleType,channelCount) )
+
+#define IDeckLinkInput_v7_3_DisableAudioInput(This) \
+ ( (This)->lpVtbl -> DisableAudioInput(This) )
+
+#define IDeckLinkInput_v7_3_GetAvailableAudioSampleFrameCount(This,availableSampleFrameCount) \
+ ( (This)->lpVtbl -> GetAvailableAudioSampleFrameCount(This,availableSampleFrameCount) )
+
+#define IDeckLinkInput_v7_3_StartStreams(This) \
+ ( (This)->lpVtbl -> StartStreams(This) )
+
+#define IDeckLinkInput_v7_3_StopStreams(This) \
+ ( (This)->lpVtbl -> StopStreams(This) )
+
+#define IDeckLinkInput_v7_3_PauseStreams(This) \
+ ( (This)->lpVtbl -> PauseStreams(This) )
+
+#define IDeckLinkInput_v7_3_FlushStreams(This) \
+ ( (This)->lpVtbl -> FlushStreams(This) )
+
+#define IDeckLinkInput_v7_3_SetCallback(This,theCallback) \
+ ( (This)->lpVtbl -> SetCallback(This,theCallback) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkInput_v7_3_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkVideoInputFrame_v7_3_INTERFACE_DEFINED__
+#define __IDeckLinkVideoInputFrame_v7_3_INTERFACE_DEFINED__
+
+/* interface IDeckLinkVideoInputFrame_v7_3 */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkVideoInputFrame_v7_3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CF317790-2894-11DE-8C30-0800200C9A66")
+ IDeckLinkVideoInputFrame_v7_3 : public IDeckLinkVideoFrame_v7_6
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetStreamTime(
+ /* [out] */ BMDTimeValue *frameTime,
+ /* [out] */ BMDTimeValue *frameDuration,
+ BMDTimeScale timeScale) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkVideoInputFrame_v7_3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkVideoInputFrame_v7_3 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkVideoInputFrame_v7_3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkVideoInputFrame_v7_3 * This);
+
+ long ( STDMETHODCALLTYPE *GetWidth )(
+ IDeckLinkVideoInputFrame_v7_3 * This);
+
+ long ( STDMETHODCALLTYPE *GetHeight )(
+ IDeckLinkVideoInputFrame_v7_3 * This);
+
+ long ( STDMETHODCALLTYPE *GetRowBytes )(
+ IDeckLinkVideoInputFrame_v7_3 * This);
+
+ BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )(
+ IDeckLinkVideoInputFrame_v7_3 * This);
+
+ BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )(
+ IDeckLinkVideoInputFrame_v7_3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBytes )(
+ IDeckLinkVideoInputFrame_v7_3 * This,
+ /* [out] */ void **buffer);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTimecode )(
+ IDeckLinkVideoInputFrame_v7_3 * This,
+ BMDTimecodeFormat format,
+ /* [out] */ IDeckLinkTimecode_v7_6 **timecode);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAncillaryData )(
+ IDeckLinkVideoInputFrame_v7_3 * This,
+ /* [out] */ IDeckLinkVideoFrameAncillary **ancillary);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStreamTime )(
+ IDeckLinkVideoInputFrame_v7_3 * This,
+ /* [out] */ BMDTimeValue *frameTime,
+ /* [out] */ BMDTimeValue *frameDuration,
+ BMDTimeScale timeScale);
+
+ END_INTERFACE
+ } IDeckLinkVideoInputFrame_v7_3Vtbl;
+
+ interface IDeckLinkVideoInputFrame_v7_3
+ {
+ CONST_VTBL struct IDeckLinkVideoInputFrame_v7_3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkVideoInputFrame_v7_3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkVideoInputFrame_v7_3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkVideoInputFrame_v7_3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkVideoInputFrame_v7_3_GetWidth(This) \
+ ( (This)->lpVtbl -> GetWidth(This) )
+
+#define IDeckLinkVideoInputFrame_v7_3_GetHeight(This) \
+ ( (This)->lpVtbl -> GetHeight(This) )
+
+#define IDeckLinkVideoInputFrame_v7_3_GetRowBytes(This) \
+ ( (This)->lpVtbl -> GetRowBytes(This) )
+
+#define IDeckLinkVideoInputFrame_v7_3_GetPixelFormat(This) \
+ ( (This)->lpVtbl -> GetPixelFormat(This) )
+
+#define IDeckLinkVideoInputFrame_v7_3_GetFlags(This) \
+ ( (This)->lpVtbl -> GetFlags(This) )
+
+#define IDeckLinkVideoInputFrame_v7_3_GetBytes(This,buffer) \
+ ( (This)->lpVtbl -> GetBytes(This,buffer) )
+
+#define IDeckLinkVideoInputFrame_v7_3_GetTimecode(This,format,timecode) \
+ ( (This)->lpVtbl -> GetTimecode(This,format,timecode) )
+
+#define IDeckLinkVideoInputFrame_v7_3_GetAncillaryData(This,ancillary) \
+ ( (This)->lpVtbl -> GetAncillaryData(This,ancillary) )
+
+
+#define IDeckLinkVideoInputFrame_v7_3_GetStreamTime(This,frameTime,frameDuration,timeScale) \
+ ( (This)->lpVtbl -> GetStreamTime(This,frameTime,frameDuration,timeScale) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkVideoInputFrame_v7_3_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkDisplayModeIterator_v7_1_INTERFACE_DEFINED__
+#define __IDeckLinkDisplayModeIterator_v7_1_INTERFACE_DEFINED__
+
+/* interface IDeckLinkDisplayModeIterator_v7_1 */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkDisplayModeIterator_v7_1;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("B28131B6-59AC-4857-B5AC-CD75D5883E2F")
+ IDeckLinkDisplayModeIterator_v7_1 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [out] */ IDeckLinkDisplayMode_v7_1 **deckLinkDisplayMode) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkDisplayModeIterator_v7_1Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkDisplayModeIterator_v7_1 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkDisplayModeIterator_v7_1 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkDisplayModeIterator_v7_1 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ IDeckLinkDisplayModeIterator_v7_1 * This,
+ /* [out] */ IDeckLinkDisplayMode_v7_1 **deckLinkDisplayMode);
+
+ END_INTERFACE
+ } IDeckLinkDisplayModeIterator_v7_1Vtbl;
+
+ interface IDeckLinkDisplayModeIterator_v7_1
+ {
+ CONST_VTBL struct IDeckLinkDisplayModeIterator_v7_1Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkDisplayModeIterator_v7_1_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkDisplayModeIterator_v7_1_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkDisplayModeIterator_v7_1_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkDisplayModeIterator_v7_1_Next(This,deckLinkDisplayMode) \
+ ( (This)->lpVtbl -> Next(This,deckLinkDisplayMode) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkDisplayModeIterator_v7_1_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkDisplayMode_v7_1_INTERFACE_DEFINED__
+#define __IDeckLinkDisplayMode_v7_1_INTERFACE_DEFINED__
+
+/* interface IDeckLinkDisplayMode_v7_1 */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkDisplayMode_v7_1;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("AF0CD6D5-8376-435E-8433-54F9DD530AC3")
+ IDeckLinkDisplayMode_v7_1 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetName(
+ /* [out] */ BSTR *name) = 0;
+
+ virtual BMDDisplayMode STDMETHODCALLTYPE GetDisplayMode( void) = 0;
+
+ virtual long STDMETHODCALLTYPE GetWidth( void) = 0;
+
+ virtual long STDMETHODCALLTYPE GetHeight( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFrameRate(
+ /* [out] */ BMDTimeValue *frameDuration,
+ /* [out] */ BMDTimeScale *timeScale) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkDisplayMode_v7_1Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkDisplayMode_v7_1 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkDisplayMode_v7_1 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkDisplayMode_v7_1 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ IDeckLinkDisplayMode_v7_1 * This,
+ /* [out] */ BSTR *name);
+
+ BMDDisplayMode ( STDMETHODCALLTYPE *GetDisplayMode )(
+ IDeckLinkDisplayMode_v7_1 * This);
+
+ long ( STDMETHODCALLTYPE *GetWidth )(
+ IDeckLinkDisplayMode_v7_1 * This);
+
+ long ( STDMETHODCALLTYPE *GetHeight )(
+ IDeckLinkDisplayMode_v7_1 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFrameRate )(
+ IDeckLinkDisplayMode_v7_1 * This,
+ /* [out] */ BMDTimeValue *frameDuration,
+ /* [out] */ BMDTimeScale *timeScale);
+
+ END_INTERFACE
+ } IDeckLinkDisplayMode_v7_1Vtbl;
+
+ interface IDeckLinkDisplayMode_v7_1
+ {
+ CONST_VTBL struct IDeckLinkDisplayMode_v7_1Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkDisplayMode_v7_1_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkDisplayMode_v7_1_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkDisplayMode_v7_1_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkDisplayMode_v7_1_GetName(This,name) \
+ ( (This)->lpVtbl -> GetName(This,name) )
+
+#define IDeckLinkDisplayMode_v7_1_GetDisplayMode(This) \
+ ( (This)->lpVtbl -> GetDisplayMode(This) )
+
+#define IDeckLinkDisplayMode_v7_1_GetWidth(This) \
+ ( (This)->lpVtbl -> GetWidth(This) )
+
+#define IDeckLinkDisplayMode_v7_1_GetHeight(This) \
+ ( (This)->lpVtbl -> GetHeight(This) )
+
+#define IDeckLinkDisplayMode_v7_1_GetFrameRate(This,frameDuration,timeScale) \
+ ( (This)->lpVtbl -> GetFrameRate(This,frameDuration,timeScale) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkDisplayMode_v7_1_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkVideoFrame_v7_1_INTERFACE_DEFINED__
+#define __IDeckLinkVideoFrame_v7_1_INTERFACE_DEFINED__
+
+/* interface IDeckLinkVideoFrame_v7_1 */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkVideoFrame_v7_1;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("333F3A10-8C2D-43CF-B79D-46560FEEA1CE")
+ IDeckLinkVideoFrame_v7_1 : public IUnknown
+ {
+ public:
+ virtual long STDMETHODCALLTYPE GetWidth( void) = 0;
+
+ virtual long STDMETHODCALLTYPE GetHeight( void) = 0;
+
+ virtual long STDMETHODCALLTYPE GetRowBytes( void) = 0;
+
+ virtual BMDPixelFormat STDMETHODCALLTYPE GetPixelFormat( void) = 0;
+
+ virtual BMDFrameFlags STDMETHODCALLTYPE GetFlags( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBytes(
+ void **buffer) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkVideoFrame_v7_1Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkVideoFrame_v7_1 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkVideoFrame_v7_1 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkVideoFrame_v7_1 * This);
+
+ long ( STDMETHODCALLTYPE *GetWidth )(
+ IDeckLinkVideoFrame_v7_1 * This);
+
+ long ( STDMETHODCALLTYPE *GetHeight )(
+ IDeckLinkVideoFrame_v7_1 * This);
+
+ long ( STDMETHODCALLTYPE *GetRowBytes )(
+ IDeckLinkVideoFrame_v7_1 * This);
+
+ BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )(
+ IDeckLinkVideoFrame_v7_1 * This);
+
+ BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )(
+ IDeckLinkVideoFrame_v7_1 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBytes )(
+ IDeckLinkVideoFrame_v7_1 * This,
+ void **buffer);
+
+ END_INTERFACE
+ } IDeckLinkVideoFrame_v7_1Vtbl;
+
+ interface IDeckLinkVideoFrame_v7_1
+ {
+ CONST_VTBL struct IDeckLinkVideoFrame_v7_1Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkVideoFrame_v7_1_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkVideoFrame_v7_1_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkVideoFrame_v7_1_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkVideoFrame_v7_1_GetWidth(This) \
+ ( (This)->lpVtbl -> GetWidth(This) )
+
+#define IDeckLinkVideoFrame_v7_1_GetHeight(This) \
+ ( (This)->lpVtbl -> GetHeight(This) )
+
+#define IDeckLinkVideoFrame_v7_1_GetRowBytes(This) \
+ ( (This)->lpVtbl -> GetRowBytes(This) )
+
+#define IDeckLinkVideoFrame_v7_1_GetPixelFormat(This) \
+ ( (This)->lpVtbl -> GetPixelFormat(This) )
+
+#define IDeckLinkVideoFrame_v7_1_GetFlags(This) \
+ ( (This)->lpVtbl -> GetFlags(This) )
+
+#define IDeckLinkVideoFrame_v7_1_GetBytes(This,buffer) \
+ ( (This)->lpVtbl -> GetBytes(This,buffer) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkVideoFrame_v7_1_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkVideoInputFrame_v7_1_INTERFACE_DEFINED__
+#define __IDeckLinkVideoInputFrame_v7_1_INTERFACE_DEFINED__
+
+/* interface IDeckLinkVideoInputFrame_v7_1 */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkVideoInputFrame_v7_1;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("C8B41D95-8848-40EE-9B37-6E3417FB114B")
+ IDeckLinkVideoInputFrame_v7_1 : public IDeckLinkVideoFrame_v7_1
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetFrameTime(
+ BMDTimeValue *frameTime,
+ BMDTimeValue *frameDuration,
+ BMDTimeScale timeScale) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkVideoInputFrame_v7_1Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkVideoInputFrame_v7_1 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkVideoInputFrame_v7_1 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkVideoInputFrame_v7_1 * This);
+
+ long ( STDMETHODCALLTYPE *GetWidth )(
+ IDeckLinkVideoInputFrame_v7_1 * This);
+
+ long ( STDMETHODCALLTYPE *GetHeight )(
+ IDeckLinkVideoInputFrame_v7_1 * This);
+
+ long ( STDMETHODCALLTYPE *GetRowBytes )(
+ IDeckLinkVideoInputFrame_v7_1 * This);
+
+ BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )(
+ IDeckLinkVideoInputFrame_v7_1 * This);
+
+ BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )(
+ IDeckLinkVideoInputFrame_v7_1 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBytes )(
+ IDeckLinkVideoInputFrame_v7_1 * This,
+ void **buffer);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFrameTime )(
+ IDeckLinkVideoInputFrame_v7_1 * This,
+ BMDTimeValue *frameTime,
+ BMDTimeValue *frameDuration,
+ BMDTimeScale timeScale);
+
+ END_INTERFACE
+ } IDeckLinkVideoInputFrame_v7_1Vtbl;
+
+ interface IDeckLinkVideoInputFrame_v7_1
+ {
+ CONST_VTBL struct IDeckLinkVideoInputFrame_v7_1Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkVideoInputFrame_v7_1_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkVideoInputFrame_v7_1_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkVideoInputFrame_v7_1_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkVideoInputFrame_v7_1_GetWidth(This) \
+ ( (This)->lpVtbl -> GetWidth(This) )
+
+#define IDeckLinkVideoInputFrame_v7_1_GetHeight(This) \
+ ( (This)->lpVtbl -> GetHeight(This) )
+
+#define IDeckLinkVideoInputFrame_v7_1_GetRowBytes(This) \
+ ( (This)->lpVtbl -> GetRowBytes(This) )
+
+#define IDeckLinkVideoInputFrame_v7_1_GetPixelFormat(This) \
+ ( (This)->lpVtbl -> GetPixelFormat(This) )
+
+#define IDeckLinkVideoInputFrame_v7_1_GetFlags(This) \
+ ( (This)->lpVtbl -> GetFlags(This) )
+
+#define IDeckLinkVideoInputFrame_v7_1_GetBytes(This,buffer) \
+ ( (This)->lpVtbl -> GetBytes(This,buffer) )
+
+
+#define IDeckLinkVideoInputFrame_v7_1_GetFrameTime(This,frameTime,frameDuration,timeScale) \
+ ( (This)->lpVtbl -> GetFrameTime(This,frameTime,frameDuration,timeScale) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkVideoInputFrame_v7_1_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkAudioInputPacket_v7_1_INTERFACE_DEFINED__
+#define __IDeckLinkAudioInputPacket_v7_1_INTERFACE_DEFINED__
+
+/* interface IDeckLinkAudioInputPacket_v7_1 */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkAudioInputPacket_v7_1;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("C86DE4F6-A29F-42E3-AB3A-1363E29F0788")
+ IDeckLinkAudioInputPacket_v7_1 : public IUnknown
+ {
+ public:
+ virtual long STDMETHODCALLTYPE GetSampleCount( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBytes(
+ void **buffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAudioPacketTime(
+ BMDTimeValue *packetTime,
+ BMDTimeScale timeScale) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkAudioInputPacket_v7_1Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkAudioInputPacket_v7_1 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkAudioInputPacket_v7_1 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkAudioInputPacket_v7_1 * This);
+
+ long ( STDMETHODCALLTYPE *GetSampleCount )(
+ IDeckLinkAudioInputPacket_v7_1 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBytes )(
+ IDeckLinkAudioInputPacket_v7_1 * This,
+ void **buffer);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAudioPacketTime )(
+ IDeckLinkAudioInputPacket_v7_1 * This,
+ BMDTimeValue *packetTime,
+ BMDTimeScale timeScale);
+
+ END_INTERFACE
+ } IDeckLinkAudioInputPacket_v7_1Vtbl;
+
+ interface IDeckLinkAudioInputPacket_v7_1
+ {
+ CONST_VTBL struct IDeckLinkAudioInputPacket_v7_1Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkAudioInputPacket_v7_1_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkAudioInputPacket_v7_1_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkAudioInputPacket_v7_1_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkAudioInputPacket_v7_1_GetSampleCount(This) \
+ ( (This)->lpVtbl -> GetSampleCount(This) )
+
+#define IDeckLinkAudioInputPacket_v7_1_GetBytes(This,buffer) \
+ ( (This)->lpVtbl -> GetBytes(This,buffer) )
+
+#define IDeckLinkAudioInputPacket_v7_1_GetAudioPacketTime(This,packetTime,timeScale) \
+ ( (This)->lpVtbl -> GetAudioPacketTime(This,packetTime,timeScale) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkAudioInputPacket_v7_1_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkVideoOutputCallback_v7_1_INTERFACE_DEFINED__
+#define __IDeckLinkVideoOutputCallback_v7_1_INTERFACE_DEFINED__
+
+/* interface IDeckLinkVideoOutputCallback_v7_1 */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkVideoOutputCallback_v7_1;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("EBD01AFA-E4B0-49C6-A01D-EDB9D1B55FD9")
+ IDeckLinkVideoOutputCallback_v7_1 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE ScheduledFrameCompleted(
+ /* [in] */ IDeckLinkVideoFrame_v7_1 *completedFrame,
+ /* [in] */ BMDOutputFrameCompletionResult result) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkVideoOutputCallback_v7_1Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkVideoOutputCallback_v7_1 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkVideoOutputCallback_v7_1 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkVideoOutputCallback_v7_1 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ScheduledFrameCompleted )(
+ IDeckLinkVideoOutputCallback_v7_1 * This,
+ /* [in] */ IDeckLinkVideoFrame_v7_1 *completedFrame,
+ /* [in] */ BMDOutputFrameCompletionResult result);
+
+ END_INTERFACE
+ } IDeckLinkVideoOutputCallback_v7_1Vtbl;
+
+ interface IDeckLinkVideoOutputCallback_v7_1
+ {
+ CONST_VTBL struct IDeckLinkVideoOutputCallback_v7_1Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkVideoOutputCallback_v7_1_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkVideoOutputCallback_v7_1_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkVideoOutputCallback_v7_1_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkVideoOutputCallback_v7_1_ScheduledFrameCompleted(This,completedFrame,result) \
+ ( (This)->lpVtbl -> ScheduledFrameCompleted(This,completedFrame,result) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkVideoOutputCallback_v7_1_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkInputCallback_v7_1_INTERFACE_DEFINED__
+#define __IDeckLinkInputCallback_v7_1_INTERFACE_DEFINED__
+
+/* interface IDeckLinkInputCallback_v7_1 */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkInputCallback_v7_1;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("7F94F328-5ED4-4E9F-9729-76A86BDC99CC")
+ IDeckLinkInputCallback_v7_1 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(
+ /* [in] */ IDeckLinkVideoInputFrame_v7_1 *videoFrame,
+ /* [in] */ IDeckLinkAudioInputPacket_v7_1 *audioPacket) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkInputCallback_v7_1Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkInputCallback_v7_1 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkInputCallback_v7_1 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkInputCallback_v7_1 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *VideoInputFrameArrived )(
+ IDeckLinkInputCallback_v7_1 * This,
+ /* [in] */ IDeckLinkVideoInputFrame_v7_1 *videoFrame,
+ /* [in] */ IDeckLinkAudioInputPacket_v7_1 *audioPacket);
+
+ END_INTERFACE
+ } IDeckLinkInputCallback_v7_1Vtbl;
+
+ interface IDeckLinkInputCallback_v7_1
+ {
+ CONST_VTBL struct IDeckLinkInputCallback_v7_1Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkInputCallback_v7_1_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkInputCallback_v7_1_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkInputCallback_v7_1_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkInputCallback_v7_1_VideoInputFrameArrived(This,videoFrame,audioPacket) \
+ ( (This)->lpVtbl -> VideoInputFrameArrived(This,videoFrame,audioPacket) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkInputCallback_v7_1_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkOutput_v7_1_INTERFACE_DEFINED__
+#define __IDeckLinkOutput_v7_1_INTERFACE_DEFINED__
+
+/* interface IDeckLinkOutput_v7_1 */
+/* [helpstring][local][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkOutput_v7_1;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("AE5B3E9B-4E1E-4535-B6E8-480FF52F6CE5")
+ IDeckLinkOutput_v7_1 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode(
+ BMDDisplayMode displayMode,
+ BMDPixelFormat pixelFormat,
+ /* [out] */ BMDDisplayModeSupport *result) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator(
+ /* [out] */ IDeckLinkDisplayModeIterator_v7_1 **iterator) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnableVideoOutput(
+ BMDDisplayMode displayMode) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DisableVideoOutput( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetVideoOutputFrameMemoryAllocator(
+ /* [in] */ IDeckLinkMemoryAllocator *theAllocator) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateVideoFrame(
+ int width,
+ int height,
+ int rowBytes,
+ BMDPixelFormat pixelFormat,
+ BMDFrameFlags flags,
+ IDeckLinkVideoFrame_v7_1 **outFrame) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateVideoFrameFromBuffer(
+ void *buffer,
+ int width,
+ int height,
+ int rowBytes,
+ BMDPixelFormat pixelFormat,
+ BMDFrameFlags flags,
+ IDeckLinkVideoFrame_v7_1 **outFrame) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DisplayVideoFrameSync(
+ IDeckLinkVideoFrame_v7_1 *theFrame) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ScheduleVideoFrame(
+ IDeckLinkVideoFrame_v7_1 *theFrame,
+ BMDTimeValue displayTime,
+ BMDTimeValue displayDuration,
+ BMDTimeScale timeScale) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetScheduledFrameCompletionCallback(
+ /* [in] */ IDeckLinkVideoOutputCallback_v7_1 *theCallback) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnableAudioOutput(
+ BMDAudioSampleRate sampleRate,
+ BMDAudioSampleType sampleType,
+ unsigned int channelCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DisableAudioOutput( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteAudioSamplesSync(
+ void *buffer,
+ unsigned int sampleFrameCount,
+ /* [out] */ unsigned int *sampleFramesWritten) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE BeginAudioPreroll( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndAudioPreroll( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ScheduleAudioSamples(
+ void *buffer,
+ unsigned int sampleFrameCount,
+ BMDTimeValue streamTime,
+ BMDTimeScale timeScale,
+ /* [out] */ unsigned int *sampleFramesWritten) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBufferedAudioSampleFrameCount(
+ /* [out] */ unsigned int *bufferedSampleCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FlushBufferedAudioSamples( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetAudioCallback(
+ /* [in] */ IDeckLinkAudioOutputCallback *theCallback) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartScheduledPlayback(
+ BMDTimeValue playbackStartTime,
+ BMDTimeScale timeScale,
+ double playbackSpeed) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StopScheduledPlayback(
+ BMDTimeValue stopPlaybackAtTime,
+ BMDTimeValue *actualStopTime,
+ BMDTimeScale timeScale) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceClock(
+ BMDTimeScale desiredTimeScale,
+ BMDTimeValue *elapsedTimeSinceSchedulerBegan) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkOutput_v7_1Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkOutput_v7_1 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkOutput_v7_1 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkOutput_v7_1 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )(
+ IDeckLinkOutput_v7_1 * This,
+ BMDDisplayMode displayMode,
+ BMDPixelFormat pixelFormat,
+ /* [out] */ BMDDisplayModeSupport *result);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )(
+ IDeckLinkOutput_v7_1 * This,
+ /* [out] */ IDeckLinkDisplayModeIterator_v7_1 **iterator);
+
+ HRESULT ( STDMETHODCALLTYPE *EnableVideoOutput )(
+ IDeckLinkOutput_v7_1 * This,
+ BMDDisplayMode displayMode);
+
+ HRESULT ( STDMETHODCALLTYPE *DisableVideoOutput )(
+ IDeckLinkOutput_v7_1 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetVideoOutputFrameMemoryAllocator )(
+ IDeckLinkOutput_v7_1 * This,
+ /* [in] */ IDeckLinkMemoryAllocator *theAllocator);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateVideoFrame )(
+ IDeckLinkOutput_v7_1 * This,
+ int width,
+ int height,
+ int rowBytes,
+ BMDPixelFormat pixelFormat,
+ BMDFrameFlags flags,
+ IDeckLinkVideoFrame_v7_1 **outFrame);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateVideoFrameFromBuffer )(
+ IDeckLinkOutput_v7_1 * This,
+ void *buffer,
+ int width,
+ int height,
+ int rowBytes,
+ BMDPixelFormat pixelFormat,
+ BMDFrameFlags flags,
+ IDeckLinkVideoFrame_v7_1 **outFrame);
+
+ HRESULT ( STDMETHODCALLTYPE *DisplayVideoFrameSync )(
+ IDeckLinkOutput_v7_1 * This,
+ IDeckLinkVideoFrame_v7_1 *theFrame);
+
+ HRESULT ( STDMETHODCALLTYPE *ScheduleVideoFrame )(
+ IDeckLinkOutput_v7_1 * This,
+ IDeckLinkVideoFrame_v7_1 *theFrame,
+ BMDTimeValue displayTime,
+ BMDTimeValue displayDuration,
+ BMDTimeScale timeScale);
+
+ HRESULT ( STDMETHODCALLTYPE *SetScheduledFrameCompletionCallback )(
+ IDeckLinkOutput_v7_1 * This,
+ /* [in] */ IDeckLinkVideoOutputCallback_v7_1 *theCallback);
+
+ HRESULT ( STDMETHODCALLTYPE *EnableAudioOutput )(
+ IDeckLinkOutput_v7_1 * This,
+ BMDAudioSampleRate sampleRate,
+ BMDAudioSampleType sampleType,
+ unsigned int channelCount);
+
+ HRESULT ( STDMETHODCALLTYPE *DisableAudioOutput )(
+ IDeckLinkOutput_v7_1 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteAudioSamplesSync )(
+ IDeckLinkOutput_v7_1 * This,
+ void *buffer,
+ unsigned int sampleFrameCount,
+ /* [out] */ unsigned int *sampleFramesWritten);
+
+ HRESULT ( STDMETHODCALLTYPE *BeginAudioPreroll )(
+ IDeckLinkOutput_v7_1 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *EndAudioPreroll )(
+ IDeckLinkOutput_v7_1 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ScheduleAudioSamples )(
+ IDeckLinkOutput_v7_1 * This,
+ void *buffer,
+ unsigned int sampleFrameCount,
+ BMDTimeValue streamTime,
+ BMDTimeScale timeScale,
+ /* [out] */ unsigned int *sampleFramesWritten);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBufferedAudioSampleFrameCount )(
+ IDeckLinkOutput_v7_1 * This,
+ /* [out] */ unsigned int *bufferedSampleCount);
+
+ HRESULT ( STDMETHODCALLTYPE *FlushBufferedAudioSamples )(
+ IDeckLinkOutput_v7_1 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAudioCallback )(
+ IDeckLinkOutput_v7_1 * This,
+ /* [in] */ IDeckLinkAudioOutputCallback *theCallback);
+
+ HRESULT ( STDMETHODCALLTYPE *StartScheduledPlayback )(
+ IDeckLinkOutput_v7_1 * This,
+ BMDTimeValue playbackStartTime,
+ BMDTimeScale timeScale,
+ double playbackSpeed);
+
+ HRESULT ( STDMETHODCALLTYPE *StopScheduledPlayback )(
+ IDeckLinkOutput_v7_1 * This,
+ BMDTimeValue stopPlaybackAtTime,
+ BMDTimeValue *actualStopTime,
+ BMDTimeScale timeScale);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceClock )(
+ IDeckLinkOutput_v7_1 * This,
+ BMDTimeScale desiredTimeScale,
+ BMDTimeValue *elapsedTimeSinceSchedulerBegan);
+
+ END_INTERFACE
+ } IDeckLinkOutput_v7_1Vtbl;
+
+ interface IDeckLinkOutput_v7_1
+ {
+ CONST_VTBL struct IDeckLinkOutput_v7_1Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkOutput_v7_1_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkOutput_v7_1_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkOutput_v7_1_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkOutput_v7_1_DoesSupportVideoMode(This,displayMode,pixelFormat,result) \
+ ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,result) )
+
+#define IDeckLinkOutput_v7_1_GetDisplayModeIterator(This,iterator) \
+ ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) )
+
+#define IDeckLinkOutput_v7_1_EnableVideoOutput(This,displayMode) \
+ ( (This)->lpVtbl -> EnableVideoOutput(This,displayMode) )
+
+#define IDeckLinkOutput_v7_1_DisableVideoOutput(This) \
+ ( (This)->lpVtbl -> DisableVideoOutput(This) )
+
+#define IDeckLinkOutput_v7_1_SetVideoOutputFrameMemoryAllocator(This,theAllocator) \
+ ( (This)->lpVtbl -> SetVideoOutputFrameMemoryAllocator(This,theAllocator) )
+
+#define IDeckLinkOutput_v7_1_CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) \
+ ( (This)->lpVtbl -> CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) )
+
+#define IDeckLinkOutput_v7_1_CreateVideoFrameFromBuffer(This,buffer,width,height,rowBytes,pixelFormat,flags,outFrame) \
+ ( (This)->lpVtbl -> CreateVideoFrameFromBuffer(This,buffer,width,height,rowBytes,pixelFormat,flags,outFrame) )
+
+#define IDeckLinkOutput_v7_1_DisplayVideoFrameSync(This,theFrame) \
+ ( (This)->lpVtbl -> DisplayVideoFrameSync(This,theFrame) )
+
+#define IDeckLinkOutput_v7_1_ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) \
+ ( (This)->lpVtbl -> ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) )
+
+#define IDeckLinkOutput_v7_1_SetScheduledFrameCompletionCallback(This,theCallback) \
+ ( (This)->lpVtbl -> SetScheduledFrameCompletionCallback(This,theCallback) )
+
+#define IDeckLinkOutput_v7_1_EnableAudioOutput(This,sampleRate,sampleType,channelCount) \
+ ( (This)->lpVtbl -> EnableAudioOutput(This,sampleRate,sampleType,channelCount) )
+
+#define IDeckLinkOutput_v7_1_DisableAudioOutput(This) \
+ ( (This)->lpVtbl -> DisableAudioOutput(This) )
+
+#define IDeckLinkOutput_v7_1_WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) \
+ ( (This)->lpVtbl -> WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) )
+
+#define IDeckLinkOutput_v7_1_BeginAudioPreroll(This) \
+ ( (This)->lpVtbl -> BeginAudioPreroll(This) )
+
+#define IDeckLinkOutput_v7_1_EndAudioPreroll(This) \
+ ( (This)->lpVtbl -> EndAudioPreroll(This) )
+
+#define IDeckLinkOutput_v7_1_ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) \
+ ( (This)->lpVtbl -> ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) )
+
+#define IDeckLinkOutput_v7_1_GetBufferedAudioSampleFrameCount(This,bufferedSampleCount) \
+ ( (This)->lpVtbl -> GetBufferedAudioSampleFrameCount(This,bufferedSampleCount) )
+
+#define IDeckLinkOutput_v7_1_FlushBufferedAudioSamples(This) \
+ ( (This)->lpVtbl -> FlushBufferedAudioSamples(This) )
+
+#define IDeckLinkOutput_v7_1_SetAudioCallback(This,theCallback) \
+ ( (This)->lpVtbl -> SetAudioCallback(This,theCallback) )
+
+#define IDeckLinkOutput_v7_1_StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) \
+ ( (This)->lpVtbl -> StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) )
+
+#define IDeckLinkOutput_v7_1_StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) \
+ ( (This)->lpVtbl -> StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) )
+
+#define IDeckLinkOutput_v7_1_GetHardwareReferenceClock(This,desiredTimeScale,elapsedTimeSinceSchedulerBegan) \
+ ( (This)->lpVtbl -> GetHardwareReferenceClock(This,desiredTimeScale,elapsedTimeSinceSchedulerBegan) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkOutput_v7_1_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDeckLinkInput_v7_1_INTERFACE_DEFINED__
+#define __IDeckLinkInput_v7_1_INTERFACE_DEFINED__
+
+/* interface IDeckLinkInput_v7_1 */
+/* [helpstring][uuid][object] */
+
+
+EXTERN_C const IID IID_IDeckLinkInput_v7_1;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("2B54EDEF-5B32-429F-BA11-BB990596EACD")
+ IDeckLinkInput_v7_1 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode(
+ BMDDisplayMode displayMode,
+ BMDPixelFormat pixelFormat,
+ /* [out] */ BMDDisplayModeSupport *result) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator(
+ /* [out] */ IDeckLinkDisplayModeIterator_v7_1 **iterator) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnableVideoInput(
+ BMDDisplayMode displayMode,
+ BMDPixelFormat pixelFormat,
+ BMDVideoInputFlags flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DisableVideoInput( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnableAudioInput(
+ BMDAudioSampleRate sampleRate,
+ BMDAudioSampleType sampleType,
+ unsigned int channelCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DisableAudioInput( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ReadAudioSamples(
+ void *buffer,
+ unsigned int sampleFrameCount,
+ /* [out] */ unsigned int *sampleFramesRead,
+ /* [out] */ BMDTimeValue *audioPacketTime,
+ BMDTimeScale timeScale) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBufferedAudioSampleFrameCount(
+ /* [out] */ unsigned int *bufferedSampleCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartStreams( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StopStreams( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE PauseStreams( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetCallback(
+ /* [in] */ IDeckLinkInputCallback_v7_1 *theCallback) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDeckLinkInput_v7_1Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDeckLinkInput_v7_1 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDeckLinkInput_v7_1 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDeckLinkInput_v7_1 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )(
+ IDeckLinkInput_v7_1 * This,
+ BMDDisplayMode displayMode,
+ BMDPixelFormat pixelFormat,
+ /* [out] */ BMDDisplayModeSupport *result);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )(
+ IDeckLinkInput_v7_1 * This,
+ /* [out] */ IDeckLinkDisplayModeIterator_v7_1 **iterator);
+
+ HRESULT ( STDMETHODCALLTYPE *EnableVideoInput )(
+ IDeckLinkInput_v7_1 * This,
+ BMDDisplayMode displayMode,
+ BMDPixelFormat pixelFormat,
+ BMDVideoInputFlags flags);
+
+ HRESULT ( STDMETHODCALLTYPE *DisableVideoInput )(
+ IDeckLinkInput_v7_1 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *EnableAudioInput )(
+ IDeckLinkInput_v7_1 * This,
+ BMDAudioSampleRate sampleRate,
+ BMDAudioSampleType sampleType,
+ unsigned int channelCount);
+
+ HRESULT ( STDMETHODCALLTYPE *DisableAudioInput )(
+ IDeckLinkInput_v7_1 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ReadAudioSamples )(
+ IDeckLinkInput_v7_1 * This,
+ void *buffer,
+ unsigned int sampleFrameCount,
+ /* [out] */ unsigned int *sampleFramesRead,
+ /* [out] */ BMDTimeValue *audioPacketTime,
+ BMDTimeScale timeScale);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBufferedAudioSampleFrameCount )(
+ IDeckLinkInput_v7_1 * This,
+ /* [out] */ unsigned int *bufferedSampleCount);
+
+ HRESULT ( STDMETHODCALLTYPE *StartStreams )(
+ IDeckLinkInput_v7_1 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *StopStreams )(
+ IDeckLinkInput_v7_1 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *PauseStreams )(
+ IDeckLinkInput_v7_1 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetCallback )(
+ IDeckLinkInput_v7_1 * This,
+ /* [in] */ IDeckLinkInputCallback_v7_1 *theCallback);
+
+ END_INTERFACE
+ } IDeckLinkInput_v7_1Vtbl;
+
+ interface IDeckLinkInput_v7_1
+ {
+ CONST_VTBL struct IDeckLinkInput_v7_1Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDeckLinkInput_v7_1_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDeckLinkInput_v7_1_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDeckLinkInput_v7_1_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDeckLinkInput_v7_1_DoesSupportVideoMode(This,displayMode,pixelFormat,result) \
+ ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,result) )
+
+#define IDeckLinkInput_v7_1_GetDisplayModeIterator(This,iterator) \
+ ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) )
+
+#define IDeckLinkInput_v7_1_EnableVideoInput(This,displayMode,pixelFormat,flags) \
+ ( (This)->lpVtbl -> EnableVideoInput(This,displayMode,pixelFormat,flags) )
+
+#define IDeckLinkInput_v7_1_DisableVideoInput(This) \
+ ( (This)->lpVtbl -> DisableVideoInput(This) )
+
+#define IDeckLinkInput_v7_1_EnableAudioInput(This,sampleRate,sampleType,channelCount) \
+ ( (This)->lpVtbl -> EnableAudioInput(This,sampleRate,sampleType,channelCount) )
+
+#define IDeckLinkInput_v7_1_DisableAudioInput(This) \
+ ( (This)->lpVtbl -> DisableAudioInput(This) )
+
+#define IDeckLinkInput_v7_1_ReadAudioSamples(This,buffer,sampleFrameCount,sampleFramesRead,audioPacketTime,timeScale) \
+ ( (This)->lpVtbl -> ReadAudioSamples(This,buffer,sampleFrameCount,sampleFramesRead,audioPacketTime,timeScale) )
+
+#define IDeckLinkInput_v7_1_GetBufferedAudioSampleFrameCount(This,bufferedSampleCount) \
+ ( (This)->lpVtbl -> GetBufferedAudioSampleFrameCount(This,bufferedSampleCount) )
+
+#define IDeckLinkInput_v7_1_StartStreams(This) \
+ ( (This)->lpVtbl -> StartStreams(This) )
+
+#define IDeckLinkInput_v7_1_StopStreams(This) \
+ ( (This)->lpVtbl -> StopStreams(This) )
+
+#define IDeckLinkInput_v7_1_PauseStreams(This) \
+ ( (This)->lpVtbl -> PauseStreams(This) )
+
+#define IDeckLinkInput_v7_1_SetCallback(This,theCallback) \
+ ( (This)->lpVtbl -> SetCallback(This,theCallback) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDeckLinkInput_v7_1_INTERFACE_DEFINED__ */
+
+#endif /* __DeckLinkAPI_LIBRARY_DEFINED__ */
+
+/* Additional Prototypes for ALL interfaces */
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/intern/decklink/win/DeckLinkAPI_i.c b/intern/decklink/win/DeckLinkAPI_i.c
new file mode 100644
index 00000000000..a13d486aae8
--- /dev/null
+++ b/intern/decklink/win/DeckLinkAPI_i.c
@@ -0,0 +1,343 @@
+
+
+/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */
+
+/* link this file in with the server and any clients */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* at Mon Apr 13 20:57:05 2015
+ */
+/* Compiler settings for ..\..\include\DeckLinkAPI.idl:
+ Oicf, W1, Zp8, env=Win64 (32b run), target_arch=AMD64 8.00.0603
+ protocol : dce , ms_ext, c_ext, robust
+ error checks: allocation ref bounds_check enum stub_data
+ VC __declspec() decoration level:
+ __declspec(uuid()), __declspec(selectany), __declspec(novtable)
+ DECLSPEC_UUID(), MIDL_INTERFACE()
+*/
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+#include <rpc.h>
+#include <rpcndr.h>
+
+#ifdef _MIDL_USE_GUIDDEF_
+
+#ifndef INITGUID
+#define INITGUID
+#include <guiddef.h>
+#undef INITGUID
+#else
+#include <guiddef.h>
+#endif
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
+
+#else // !_MIDL_USE_GUIDDEF_
+
+#ifndef __IID_DEFINED__
+#define __IID_DEFINED__
+
+typedef struct _IID
+{
+ unsigned long x;
+ unsigned short s1;
+ unsigned short s2;
+ unsigned char c[8];
+} IID;
+
+#endif // __IID_DEFINED__
+
+#ifndef CLSID_DEFINED
+#define CLSID_DEFINED
+typedef IID CLSID;
+#endif // CLSID_DEFINED
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
+
+#endif !_MIDL_USE_GUIDDEF_
+
+MIDL_DEFINE_GUID(IID, LIBID_DeckLinkAPI,0xD864517A,0xEDD5,0x466D,0x86,0x7D,0xC8,0x19,0xF1,0xC0,0x52,0xBB);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkTimecode,0xBC6CFBD3,0x8317,0x4325,0xAC,0x1C,0x12,0x16,0x39,0x1E,0x93,0x40);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkDisplayModeIterator,0x9C88499F,0xF601,0x4021,0xB8,0x0B,0x03,0x2E,0x4E,0xB4,0x1C,0x35);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkDisplayMode,0x3EB2C1AB,0x0A3D,0x4523,0xA3,0xAD,0xF4,0x0D,0x7F,0xB1,0x4E,0x78);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLink,0xC418FBDD,0x0587,0x48ED,0x8F,0xE5,0x64,0x0F,0x0A,0x14,0xAF,0x91);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkConfiguration,0x1E69FCF6,0x4203,0x4936,0x80,0x76,0x2A,0x9F,0x4C,0xFD,0x50,0xCB);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkDeckControlStatusCallback,0x53436FFB,0xB434,0x4906,0xBA,0xDC,0xAE,0x30,0x60,0xFF,0xE8,0xEF);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkDeckControl,0x8E1C3ACE,0x19C7,0x4E00,0x8B,0x92,0xD8,0x04,0x31,0xD9,0x58,0xBE);
+
+
+MIDL_DEFINE_GUID(IID, IID_IBMDStreamingDeviceNotificationCallback,0xF9531D64,0x3305,0x4B29,0xA3,0x87,0x7F,0x74,0xBB,0x0D,0x0E,0x84);
+
+
+MIDL_DEFINE_GUID(IID, IID_IBMDStreamingH264InputCallback,0x823C475F,0x55AE,0x46F9,0x89,0x0C,0x53,0x7C,0xC5,0xCE,0xDC,0xCA);
+
+
+MIDL_DEFINE_GUID(IID, IID_IBMDStreamingDiscovery,0x2C837444,0xF989,0x4D87,0x90,0x1A,0x47,0xC8,0xA3,0x6D,0x09,0x6D);
+
+
+MIDL_DEFINE_GUID(IID, IID_IBMDStreamingVideoEncodingMode,0x1AB8035B,0xCD13,0x458D,0xB6,0xDF,0x5E,0x8F,0x7C,0x21,0x41,0xD9);
+
+
+MIDL_DEFINE_GUID(IID, IID_IBMDStreamingMutableVideoEncodingMode,0x19BF7D90,0x1E0A,0x400D,0xB2,0xC6,0xFF,0xC4,0xE7,0x8A,0xD4,0x9D);
+
+
+MIDL_DEFINE_GUID(IID, IID_IBMDStreamingVideoEncodingModePresetIterator,0x7AC731A3,0xC950,0x4AD0,0x80,0x4A,0x83,0x77,0xAA,0x51,0xC6,0xC4);
+
+
+MIDL_DEFINE_GUID(IID, IID_IBMDStreamingDeviceInput,0x24B6B6EC,0x1727,0x44BB,0x98,0x18,0x34,0xFF,0x08,0x6A,0xCF,0x98);
+
+
+MIDL_DEFINE_GUID(IID, IID_IBMDStreamingH264NALPacket,0xE260E955,0x14BE,0x4395,0x97,0x75,0x9F,0x02,0xCC,0x0A,0x9D,0x89);
+
+
+MIDL_DEFINE_GUID(IID, IID_IBMDStreamingAudioPacket,0xD9EB5902,0x1AD2,0x43F4,0x9E,0x2C,0x3C,0xFA,0x50,0xB5,0xEE,0x19);
+
+
+MIDL_DEFINE_GUID(IID, IID_IBMDStreamingMPEG2TSPacket,0x91810D1C,0x4FB3,0x4AAA,0xAE,0x56,0xFA,0x30,0x1D,0x3D,0xFA,0x4C);
+
+
+MIDL_DEFINE_GUID(IID, IID_IBMDStreamingH264NALParser,0x5867F18C,0x5BFA,0x4CCC,0xB2,0xA7,0x9D,0xFD,0x14,0x04,0x17,0xD2);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_CBMDStreamingDiscovery,0x0CAA31F6,0x8A26,0x40B0,0x86,0xA4,0xBF,0x58,0xDC,0xCA,0x71,0x0C);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_CBMDStreamingH264NALParser,0x7753EFBD,0x951C,0x407C,0x97,0xA5,0x23,0xC7,0x37,0xB7,0x3B,0x52);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoOutputCallback,0x20AA5225,0x1958,0x47CB,0x82,0x0B,0x80,0xA8,0xD5,0x21,0xA6,0xEE);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkInputCallback,0xDD04E5EC,0x7415,0x42AB,0xAE,0x4A,0xE8,0x0C,0x4D,0xFC,0x04,0x4A);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkMemoryAllocator,0xB36EB6E7,0x9D29,0x4AA8,0x92,0xEF,0x84,0x3B,0x87,0xA2,0x89,0xE8);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkAudioOutputCallback,0x403C681B,0x7F46,0x4A12,0xB9,0x93,0x2B,0xB1,0x27,0x08,0x4E,0xE6);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkIterator,0x50FB36CD,0x3063,0x4B73,0xBD,0xBB,0x95,0x80,0x87,0xF2,0xD8,0xBA);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkAPIInformation,0x7BEA3C68,0x730D,0x4322,0xAF,0x34,0x8A,0x71,0x52,0xB5,0x32,0xA4);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkOutput,0xCC5C8A6E,0x3F2F,0x4B3A,0x87,0xEA,0xFD,0x78,0xAF,0x30,0x05,0x64);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkInput,0xAF22762B,0xDFAC,0x4846,0xAA,0x79,0xFA,0x88,0x83,0x56,0x09,0x95);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoFrame,0x3F716FE0,0xF023,0x4111,0xBE,0x5D,0xEF,0x44,0x14,0xC0,0x5B,0x17);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkMutableVideoFrame,0x69E2639F,0x40DA,0x4E19,0xB6,0xF2,0x20,0xAC,0xE8,0x15,0xC3,0x90);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoFrame3DExtensions,0xDA0F7E4A,0xEDC7,0x48A8,0x9C,0xDD,0x2D,0xB5,0x1C,0x72,0x9C,0xD7);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoInputFrame,0x05CFE374,0x537C,0x4094,0x9A,0x57,0x68,0x05,0x25,0x11,0x8F,0x44);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoFrameAncillary,0x732E723C,0xD1A4,0x4E29,0x9E,0x8E,0x4A,0x88,0x79,0x7A,0x00,0x04);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkAudioInputPacket,0xE43D5870,0x2894,0x11DE,0x8C,0x30,0x08,0x00,0x20,0x0C,0x9A,0x66);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkScreenPreviewCallback,0xB1D3F49A,0x85FE,0x4C5D,0x95,0xC8,0x0B,0x5D,0x5D,0xCC,0xD4,0x38);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkGLScreenPreviewHelper,0x504E2209,0xCAC7,0x4C1A,0x9F,0xB4,0xC5,0xBB,0x62,0x74,0xD2,0x2F);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkDX9ScreenPreviewHelper,0x2094B522,0xD1A1,0x40C0,0x9A,0xC7,0x1C,0x01,0x22,0x18,0xEF,0x02);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkNotificationCallback,0xb002a1ec,0x070d,0x4288,0x82,0x89,0xbd,0x5d,0x36,0xe5,0xff,0x0d);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkNotification,0x0a1fb207,0xe215,0x441b,0x9b,0x19,0x6f,0xa1,0x57,0x59,0x46,0xc5);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkAttributes,0xABC11843,0xD966,0x44CB,0x96,0xE2,0xA1,0xCB,0x5D,0x31,0x35,0xC4);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkKeyer,0x89AFCAF5,0x65F8,0x421E,0x98,0xF7,0x96,0xFE,0x5F,0x5B,0xFB,0xA3);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoConversion,0x3BBCB8A2,0xDA2C,0x42D9,0xB5,0xD8,0x88,0x08,0x36,0x44,0xE9,0x9A);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkDeviceNotificationCallback,0x4997053B,0x0ADF,0x4CC8,0xAC,0x70,0x7A,0x50,0xC4,0xBE,0x72,0x8F);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkDiscovery,0xCDBF631C,0xBC76,0x45FA,0xB4,0x4D,0xC5,0x50,0x59,0xBC,0x61,0x01);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkIterator,0x1F2E109A,0x8F4F,0x49E4,0x92,0x03,0x13,0x55,0x95,0xCB,0x6F,0xA5);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkAPIInformation,0x263CA19F,0xED09,0x482E,0x9F,0x9D,0x84,0x00,0x57,0x83,0xA2,0x37);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkGLScreenPreviewHelper,0xF63E77C7,0xB655,0x4A4A,0x9A,0xD0,0x3C,0xA8,0x5D,0x39,0x43,0x43);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkDX9ScreenPreviewHelper,0xCC010023,0xE01D,0x4525,0x9D,0x59,0x80,0xC8,0xAB,0x3D,0xC7,0xA0);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkVideoConversion,0x7DBBBB11,0x5B7B,0x467D,0xAE,0xA4,0xCE,0xA4,0x68,0xFD,0x36,0x8C);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkDiscovery,0x1073A05C,0xD885,0x47E9,0xB3,0xC6,0x12,0x9B,0x3F,0x9F,0x64,0x8B);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkConfiguration_v10_2,0xC679A35B,0x610C,0x4D09,0xB7,0x48,0x1D,0x04,0x78,0x10,0x0F,0xC0);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkOutput_v9_9,0xA3EF0963,0x0862,0x44ED,0x92,0xA9,0xEE,0x89,0xAB,0xF4,0x31,0xC7);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkInput_v9_2,0x6D40EF78,0x28B9,0x4E21,0x99,0x0D,0x95,0xBB,0x77,0x50,0xA0,0x4F);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkDeckControlStatusCallback_v8_1,0xE5F693C1,0x4283,0x4716,0xB1,0x8F,0xC1,0x43,0x15,0x21,0x95,0x5B);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkDeckControl_v8_1,0x522A9E39,0x0F3C,0x4742,0x94,0xEE,0xD8,0x0D,0xE3,0x35,0xDA,0x1D);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLink_v8_0,0x62BFF75D,0x6569,0x4E55,0x8D,0x4D,0x66,0xAA,0x03,0x82,0x9A,0xBC);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkIterator_v8_0,0x74E936FC,0xCC28,0x4A67,0x81,0xA0,0x1E,0x94,0xE5,0x2D,0x4E,0x69);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkIterator_v8_0,0xD9EDA3B3,0x2887,0x41FA,0xB7,0x24,0x01,0x7C,0xF1,0xEB,0x1D,0x37);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkDeckControl_v7_9,0xA4D81043,0x0619,0x42B7,0x8E,0xD6,0x60,0x2D,0x29,0x04,0x1D,0xF7);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkDisplayModeIterator_v7_6,0x455D741F,0x1779,0x4800,0x86,0xF5,0x0B,0x5D,0x13,0xD7,0x97,0x51);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkDisplayMode_v7_6,0x87451E84,0x2B7E,0x439E,0xA6,0x29,0x43,0x93,0xEA,0x4A,0x85,0x50);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkOutput_v7_6,0x29228142,0xEB8C,0x4141,0xA6,0x21,0xF7,0x40,0x26,0x45,0x09,0x55);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkInput_v7_6,0x300C135A,0x9F43,0x48E2,0x99,0x06,0x6D,0x79,0x11,0xD9,0x3C,0xF1);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkTimecode_v7_6,0xEFB9BCA6,0xA521,0x44F7,0xBD,0x69,0x23,0x32,0xF2,0x4D,0x9E,0xE6);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoFrame_v7_6,0xA8D8238E,0x6B18,0x4196,0x99,0xE1,0x5A,0xF7,0x17,0xB8,0x3D,0x32);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkMutableVideoFrame_v7_6,0x46FCEE00,0xB4E6,0x43D0,0x91,0xC0,0x02,0x3A,0x7F,0xCE,0xB3,0x4F);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoInputFrame_v7_6,0x9A74FA41,0xAE9F,0x47AC,0x8C,0xF4,0x01,0xF4,0x2D,0xD5,0x99,0x65);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkScreenPreviewCallback_v7_6,0x373F499D,0x4B4D,0x4518,0xAD,0x22,0x63,0x54,0xE5,0xA5,0x82,0x5E);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkGLScreenPreviewHelper_v7_6,0xBA575CD9,0xA15E,0x497B,0xB2,0xC2,0xF9,0xAF,0xE7,0xBE,0x4E,0xBA);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoConversion_v7_6,0x3EB504C9,0xF97D,0x40FE,0xA1,0x58,0xD4,0x07,0xD4,0x8C,0xB5,0x3B);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkConfiguration_v7_6,0xB8EAD569,0xB764,0x47F0,0xA7,0x3F,0xAE,0x40,0xDF,0x6C,0xBF,0x10);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoOutputCallback_v7_6,0xE763A626,0x4A3C,0x49D1,0xBF,0x13,0xE7,0xAD,0x36,0x92,0xAE,0x52);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkInputCallback_v7_6,0x31D28EE7,0x88B6,0x4CB1,0x89,0x7A,0xCD,0xBF,0x79,0xA2,0x64,0x14);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkGLScreenPreviewHelper_v7_6,0xD398CEE7,0x4434,0x4CA3,0x9B,0xA6,0x5A,0xE3,0x45,0x56,0xB9,0x05);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkVideoConversion_v7_6,0xFFA84F77,0x73BE,0x4FB7,0xB0,0x3E,0xB5,0xE4,0x4B,0x9F,0x75,0x9B);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkInputCallback_v7_3,0xFD6F311D,0x4D00,0x444B,0x9E,0xD4,0x1F,0x25,0xB5,0x73,0x0A,0xD0);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkOutput_v7_3,0x271C65E3,0xC323,0x4344,0xA3,0x0F,0xD9,0x08,0xBC,0xB2,0x0A,0xA3);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkInput_v7_3,0x4973F012,0x9925,0x458C,0x87,0x1C,0x18,0x77,0x4C,0xDB,0xBE,0xCB);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoInputFrame_v7_3,0xCF317790,0x2894,0x11DE,0x8C,0x30,0x08,0x00,0x20,0x0C,0x9A,0x66);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkDisplayModeIterator_v7_1,0xB28131B6,0x59AC,0x4857,0xB5,0xAC,0xCD,0x75,0xD5,0x88,0x3E,0x2F);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkDisplayMode_v7_1,0xAF0CD6D5,0x8376,0x435E,0x84,0x33,0x54,0xF9,0xDD,0x53,0x0A,0xC3);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoFrame_v7_1,0x333F3A10,0x8C2D,0x43CF,0xB7,0x9D,0x46,0x56,0x0F,0xEE,0xA1,0xCE);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoInputFrame_v7_1,0xC8B41D95,0x8848,0x40EE,0x9B,0x37,0x6E,0x34,0x17,0xFB,0x11,0x4B);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkAudioInputPacket_v7_1,0xC86DE4F6,0xA29F,0x42E3,0xAB,0x3A,0x13,0x63,0xE2,0x9F,0x07,0x88);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoOutputCallback_v7_1,0xEBD01AFA,0xE4B0,0x49C6,0xA0,0x1D,0xED,0xB9,0xD1,0xB5,0x5F,0xD9);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkInputCallback_v7_1,0x7F94F328,0x5ED4,0x4E9F,0x97,0x29,0x76,0xA8,0x6B,0xDC,0x99,0xCC);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkOutput_v7_1,0xAE5B3E9B,0x4E1E,0x4535,0xB6,0xE8,0x48,0x0F,0xF5,0x2F,0x6C,0xE5);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDeckLinkInput_v7_1,0x2B54EDEF,0x5B32,0x429F,0xBA,0x11,0xBB,0x99,0x05,0x96,0xEA,0xCD);
+
+#undef MIDL_DEFINE_GUID
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
diff --git a/intern/elbeem/intern/controlparticles.cpp b/intern/elbeem/intern/controlparticles.cpp
index 526fac0cc6b..f6329ad4b67 100644
--- a/intern/elbeem/intern/controlparticles.cpp
+++ b/intern/elbeem/intern/controlparticles.cpp
@@ -1316,7 +1316,8 @@ void ControlParticles::finishControl(std::vector<ControlForces> &forces, LbmFloa
if(cvweight>1.) { cvweight = 1.; }
// thus cvweight is in the range of 0..influenceVelocity, currently not normalized by numCParts
cvweight *= ivel;
- if(cvweight<0.) cvweight=0.; if(cvweight>1.) cvweight=1.;
+ if(cvweight<0.) cvweight=0.;
+ if(cvweight>1.) cvweight=1.;
// LBM, FIXME todo use relaxation factor
//pvel = (cvel*0.5 * cvweight) + (pvel * (1.0-cvweight));
forces[i].weightVel = cvweight;
diff --git a/intern/elbeem/intern/isosurface.h b/intern/elbeem/intern/isosurface.h
index 15b923866d3..30fd9adfee1 100644
--- a/intern/elbeem/intern/isosurface.h
+++ b/intern/elbeem/intern/isosurface.h
@@ -67,8 +67,10 @@ class IsoSurface :
/*! set # of subdivisions, this has to be done before init! */
void setSubdivs(int s) {
if(mInitDone) errFatal("IsoSurface::setSubdivs","Changing subdivs after init!", SIMWORLD_INITERROR);
- if(s<1) s=1; if(s>10) s=10;
- mSubdivs = s; }
+ if(s<1) s=1;
+ if(s>10) s=10;
+ mSubdivs = s;
+ }
int getSubdivs() { return mSubdivs;}
/*! set full edge settings, this has to be done before init! */
void setUseFulledgeArrays(bool set) {
diff --git a/intern/elbeem/intern/solver_class.h b/intern/elbeem/intern/solver_class.h
index 593fea1b998..2b2e214458d 100644
--- a/intern/elbeem/intern/solver_class.h
+++ b/intern/elbeem/intern/solver_class.h
@@ -332,7 +332,7 @@ class LbmFsgrSolver :
void debugMarkCellCall(int level, int vi,int vj,int vk);
// loop over grid, stream&collide update
- void mainLoop(int lev);
+ void mainLoop(const int lev);
// change time step size
void adaptTimestep();
//! init mObjectSpeeds for current parametrization
diff --git a/intern/elbeem/intern/solver_main.cpp b/intern/elbeem/intern/solver_main.cpp
index 55a8d3eb4aa..68f7c04cd54 100644
--- a/intern/elbeem/intern/solver_main.cpp
+++ b/intern/elbeem/intern/solver_main.cpp
@@ -355,7 +355,7 @@ void LbmFsgrSolver::fineAdvance()
//! fine step function
/*****************************************************************************/
void
-LbmFsgrSolver::mainLoop(int lev)
+LbmFsgrSolver::mainLoop(const int lev)
{
// loops over _only inner_ cells -----------------------------------------------------------------------------------
@@ -376,13 +376,16 @@ LbmFsgrSolver::mainLoop(int lev)
// main loop region
const bool doReduce = true;
const int gridLoopBound=1;
+ int calcNumInvIfCells = 0;
+ LbmFloat calcInitialMass = 0;
GRID_REGION_INIT();
#if PARALLEL==1
-#pragma omp parallel default(shared) num_threads(mNumOMPThreads) \
+ const int gDebugLevel = ::gDebugLevel;
+#pragma omp parallel default(none) num_threads(mNumOMPThreads) \
reduction(+: \
calcCurrentMass,calcCurrentVolume, \
calcCellsFilled,calcCellsEmptied, \
- calcNumUsedCells )
+ calcNumUsedCells,calcNumInvIfCells,calcInitialMass)
GRID_REGION_START();
#else // PARALLEL==1
GRID_REGION_START();
@@ -468,7 +471,7 @@ LbmFsgrSolver::mainLoop(int lev)
calcCurrentMass += iniRho;
calcCurrentVolume += 1.0;
calcNumUsedCells++;
- mInitialMass += iniRho;
+ calcInitialMass += iniRho;
// dont treat cell until next step
continue;
}
@@ -479,7 +482,7 @@ LbmFsgrSolver::mainLoop(int lev)
if(isnotValid) {
// remove fluid cells, shouldnt be here anyway
LbmFloat fluidRho = m[0]; FORDF1 { fluidRho += m[l]; }
- mInitialMass -= fluidRho;
+ calcInitialMass -= fluidRho;
const LbmFloat iniRho = 0.0;
RAC(tcel, dMass) = RAC(tcel, dFfrac) = iniRho;
RAC(tcel, dFlux) = FLUX_INIT;
@@ -608,8 +611,8 @@ LbmFsgrSolver::mainLoop(int lev)
// read distribution funtions of adjacent cells = stream step
DEFAULT_STREAM;
- if((nbored & CFFluid)==0) { newFlag |= CFNoNbFluid; mNumInvIfCells++; }
- if((nbored & CFEmpty)==0) { newFlag |= CFNoNbEmpty; mNumInvIfCells++; }
+ if((nbored & CFFluid)==0) { newFlag |= CFNoNbFluid; calcNumInvIfCells++; }
+ if((nbored & CFEmpty)==0) { newFlag |= CFNoNbEmpty; calcNumInvIfCells++; }
// calculate mass exchange for interface cells
LbmFloat myfrac = RAC(ccel,dFfrac);
@@ -809,7 +812,7 @@ LbmFsgrSolver::mainLoop(int lev)
// fill if cells in inflow region
if(myfrac<0.5) {
mass += 0.25;
- mInitialMass += 0.25;
+ calcInitialMass += 0.25;
}
const int OId = oldFlag>>24;
const LbmVec vel(mObjectSpeeds[OId]);
@@ -865,10 +868,8 @@ LbmFsgrSolver::mainLoop(int lev)
// physical drop model
if(mPartUsePhysModel) {
LbmFloat realWorldFac = (mLevel[lev].simCellSize / mLevel[lev].timestep);
- LbmFloat rux = (ux * realWorldFac);
- LbmFloat ruy = (uy * realWorldFac);
- LbmFloat ruz = (uz * realWorldFac);
- LbmFloat rl = norm(ntlVec3Gfx(rux,ruy,ruz));
+ LbmVec ru(ux * realWorldFac, uy * realWorldFac, uz * realWorldFac);
+ LbmFloat rl = norm(ru);
basethresh *= rl;
// reduce probability in outer region?
@@ -960,14 +961,15 @@ LbmFsgrSolver::mainLoop(int lev)
// average normal & velocity
// -> mostly along velocity dir, many into surface
// fluid velocity (not normalized!)
- LbmVec flvelVel = LbmVec(ux,uy,uz);
+ LbmVec flvelVel(ux,uy,uz);
LbmFloat flvelLen = norm(flvelVel);
// surface normal
- LbmVec normVel = LbmVec(surfaceNormal[0],surfaceNormal[1],surfaceNormal[2]);
+ LbmVec normVel(surfaceNormal[0],surfaceNormal[1],surfaceNormal[2]);
normalize(normVel);
LbmFloat normScale = (0.01+flvelLen);
// jitter vector, 0.2 * flvel
- LbmVec jittVel = LbmVec(jx,jy,jz)*(0.05+flvelLen)*0.1;
+ LbmVec jittVel(jx,jy,jz);
+ jittVel *= (0.05+flvelLen)*0.1;
// weighten velocities
const LbmFloat flvelWeight = 0.9;
LbmVec newpartVel = normVel*normScale*(1.-flvelWeight) + flvelVel*(flvelWeight) + jittVel;
@@ -1013,7 +1015,7 @@ LbmFsgrSolver::mainLoop(int lev)
if( (mass) <= (rho * ( -FSGR_MAGICNR)) ) { ifemptied = 1; }
if(oldFlag & (CFMbndOutflow)) {
- mInitialMass -= mass;
+ calcInitialMass -= mass;
mass = myfrac = 0.0;
iffilled = 0; ifemptied = 1;
}
@@ -1105,6 +1107,8 @@ LbmFsgrSolver::mainLoop(int lev)
mNumFilledCells = calcCellsFilled;
mNumEmptiedCells = calcCellsEmptied;
mNumUsedCells = calcNumUsedCells;
+ mNumInvIfCells += calcNumInvIfCells;
+ mInitialMass += calcInitialMass;
}
@@ -1121,7 +1125,8 @@ LbmFsgrSolver::preinitGrids()
GRID_REGION_INIT();
#if PARALLEL==1
-#pragma omp parallel default(shared) num_threads(mNumOMPThreads) \
+ const int gDebugLevel = ::gDebugLevel;
+#pragma omp parallel default(none) num_threads(mNumOMPThreads) \
reduction(+: \
calcCurrentMass,calcCurrentVolume, \
calcCellsFilled,calcCellsEmptied, \
@@ -1158,7 +1163,8 @@ LbmFsgrSolver::standingFluidPreinit()
GRID_REGION_INIT();
#if PARALLEL==1
-#pragma omp parallel default(shared) num_threads(mNumOMPThreads) \
+ const int gDebugLevel = ::gDebugLevel;
+#pragma omp parallel default(none) num_threads(mNumOMPThreads) \
reduction(+: \
calcCurrentMass,calcCurrentVolume, \
calcCellsFilled,calcCellsEmptied, \
diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt
index d31e9472168..e549a48d4b9 100644
--- a/intern/ghost/CMakeLists.txt
+++ b/intern/ghost/CMakeLists.txt
@@ -223,6 +223,10 @@ elseif(WITH_X11)
)
endif()
+ if(WITH_X11_ALPHA)
+ add_definitions(-DWITH_X11_ALPHA)
+ endif()
+
if(WITH_INPUT_NDOF)
list(APPEND SRC
intern/GHOST_NDOFManagerUnix.cpp
diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h
index f1484a298d3..ff1922af4f3 100644
--- a/intern/ghost/GHOST_C-api.h
+++ b/intern/ghost/GHOST_C-api.h
@@ -433,6 +433,7 @@ extern GHOST_TSuccess GHOST_GetButtonState(GHOST_SystemHandle systemhandle,
GHOST_TButtonMask mask,
int *isDown);
+#ifdef WITH_INPUT_NDOF
/***************************************************************************************
* Access to 3D mouse.
***************************************************************************************/
@@ -442,6 +443,7 @@ extern GHOST_TSuccess GHOST_GetButtonState(GHOST_SystemHandle systemhandle,
* \param deadzone Deadzone of the 3D mouse (both for rotation and pan) relative to full range
*/
extern void GHOST_setNDOFDeadZone(float deadzone);
+#endif
/***************************************************************************************
diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h
index 4c48473c7b8..03193d6e1da 100644
--- a/intern/ghost/GHOST_ISystem.h
+++ b/intern/ghost/GHOST_ISystem.h
@@ -277,7 +277,7 @@ public:
*/
virtual GHOST_TSuccess beginFullScreen(
const GHOST_DisplaySetting& setting, GHOST_IWindow **window,
- const bool stereoVisual, const GHOST_TUns16 numOfAASamples = 0) = 0;
+ const bool stereoVisual, const bool alphaBackground = 0, const GHOST_TUns16 numOfAASamples = 0) = 0;
/**
* Updates the resolution while in fullscreen mode.
@@ -377,11 +377,13 @@ public:
*/
virtual GHOST_TSuccess getButtonState(GHOST_TButtonMask mask, bool& isDown) const = 0;
+#ifdef WITH_INPUT_NDOF
/**
* Sets 3D mouse deadzone
* \param deadzone: Deadzone of the 3D mouse (both for rotation and pan) relative to full range
*/
virtual void setNDOFDeadZone(float deadzone) = 0;
+#endif
/**
* Toggles console
diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index b3e560ab4b4..9ee4599a4a6 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -57,7 +57,8 @@ typedef struct {
typedef enum {
GHOST_glStereoVisual = (1 << 0),
- GHOST_glDebugContext = (1 << 1)
+ GHOST_glDebugContext = (1 << 1),
+ GHOST_glAlphaBackground = (1 << 2),
} GHOST_GLFlags;
@@ -171,8 +172,10 @@ typedef enum {
GHOST_kEventWheel, /// Mouse wheel event
GHOST_kEventTrackpad, /// Trackpad event
+#ifdef WITH_INPUT_NDOF
GHOST_kEventNDOFMotion, /// N degree of freedom device motion event
GHOST_kEventNDOFButton, /// N degree of freedom device button event
+#endif
GHOST_kEventKeyDown,
GHOST_kEventKeyUp,
@@ -477,6 +480,7 @@ typedef enum {
GHOST_kFinished
} GHOST_TProgress;
+#ifdef WITH_INPUT_NDOF
typedef struct {
/** N-degree of freedom device data v3 [GSoC 2010] */
// Each component normally ranges from -1 to +1, but can exceed that.
@@ -496,6 +500,7 @@ typedef struct {
GHOST_TButtonAction action;
short button;
} GHOST_TEventNDOFButtonData;
+#endif // WITH_INPUT_NDOF
typedef struct {
/** The key code. */
@@ -529,7 +534,7 @@ typedef struct {
#ifdef _WIN32
-typedef long GHOST_TEmbedderWindowID;
+typedef void* GHOST_TEmbedderWindowID;
#endif // _WIN32
#ifndef _WIN32
diff --git a/intern/ghost/doc/ghost_interface.cfg b/intern/ghost/doc/ghost_interface.cfg
deleted file mode 100644
index ebe4153ea3b..00000000000
--- a/intern/ghost/doc/ghost_interface.cfg
+++ /dev/null
@@ -1,626 +0,0 @@
-#---------------------------------------------------------------------------
-# General configuration options
-#---------------------------------------------------------------------------
-
-# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
-# by quotes) that should identify the project.
-PROJECT_NAME = "GHOST (Generic Handy Operating System Toolkit)"
-
-# The PROJECT_NUMBER tag can be used to enter a project or revision number.
-# This could be handy for archiving the generated documentation or
-# if some version control system is used.
-PROJECT_NUMBER = 1.0
-
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
-# base path where the generated documentation will be put.
-# If a relative path is entered, it will be relative to the location
-# where doxygen was started. If left blank the current directory will be used.
-OUTPUT_DIRECTORY = ./interface
-
-# The OUTPUT_LANGUAGE tag is used to specify the language in which all
-# documentation generated by doxygen is written. Doxygen will use this
-# information to generate all constant output in the proper language.
-# The default language is English, other supported languages are:
-# Dutch, French, Italian, Czech, Swedish, German, Finnish, Japanese,
-# Korean, Hungarian, Norwegian, Spanish, Romanian, Russian, Croatian,
-# Polish, Portuguese and Slovene.
-OUTPUT_LANGUAGE = English
-
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
-# documentation are documented, even if no documentation was available.
-# Private class members and static file members will be hidden unless
-# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
-EXTRACT_ALL = YES
-
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
-# will be included in the documentation.
-EXTRACT_PRIVATE = NO
-
-# If the EXTRACT_STATIC tag is set to YES all static members of a file
-# will be included in the documentation.
-EXTRACT_STATIC = YES
-
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
-# undocumented members of documented classes, files or namespaces.
-# If set to NO (the default) these members will be included in the
-# various overviews, but no documentation section is generated.
-# This option has no effect if EXTRACT_ALL is enabled.
-HIDE_UNDOC_MEMBERS = NO
-
-# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
-# undocumented classes that are normally visible in the class hierarchy.
-# If set to NO (the default) these class will be included in the various
-# overviews. This option has no effect if EXTRACT_ALL is enabled.
-HIDE_UNDOC_CLASSES = NO
-
-# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
-# include brief member descriptions after the members that are listed in
-# the file and class documentation (similar to JavaDoc).
-# Set to NO to disable this.
-BRIEF_MEMBER_DESC = YES
-
-# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
-# the brief description of a member or function before the detailed description.
-# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
-# brief descriptions will be completely suppressed.
-REPEAT_BRIEF = YES
-
-# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
-# Doxygen will generate a detailed section even if there is only a brief
-# description.
-ALWAYS_DETAILED_SEC = YES
-
-# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
-# path before files name in the file list and in the header files. If set
-# to NO the shortest path that makes the file name unique will be used.
-FULL_PATH_NAMES = NO
-
-# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
-# can be used to strip a user defined part of the path. Stripping is
-# only done if one of the specified strings matches the left-hand part of
-# the path. It is allowed to use relative paths in the argument list.
-STRIP_FROM_PATH =
-
-# The INTERNAL_DOCS tag determines if documentation
-# that is typed after a \internal command is included. If the tag is set
-# to NO (the default) then the documentation will be excluded.
-# Set it to YES to include the internal documentation.
-INTERNAL_DOCS = NO
-
-# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
-# generate a class diagram (in Html and LaTeX) for classes with base or
-# super classes. Setting the tag to NO turns the diagrams off.
-CLASS_DIAGRAMS = YES
-
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will
-# be generated. Documented entities will be cross-referenced with these sources.
-SOURCE_BROWSER = YES
-
-# Setting the INLINE_SOURCES tag to YES will include the body
-# of functions and classes directly in the documentation.
-INLINE_SOURCES = NO
-
-# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
-# doxygen to hide any special comment blocks from generated source code
-# fragments. Normal C and C++ comments will always remain visible.
-STRIP_CODE_COMMENTS = YES
-
-# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
-# file names in lower case letters. If set to YES upper case letters are also
-# allowed. This is useful if you have classes or files whose names only differ
-# in case and if your file system supports case sensitive file names. Windows
-# users are adviced to set this option to NO.
-CASE_SENSE_NAMES = YES
-
-# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
-# will show members with their full class and namespace scopes in the
-# documentation. If set to YES the scope will be hidden.
-HIDE_SCOPE_NAMES = NO
-
-# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
-# will generate a verbatim copy of the header file for each class for
-# which an include is specified. Set to NO to disable this.
-VERBATIM_HEADERS = YES
-
-# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
-# will put list of the files that are included by a file in the documentation
-# of that file.
-SHOW_INCLUDE_FILES = YES
-
-# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
-# will interpret the first line (until the first dot) of a JavaDoc-style
-# comment as the brief description. If set to NO, the JavaDoc
-# comments will behave just like the Qt-style comments (thus requiring an
-# explict @brief command for a brief description.
-JAVADOC_AUTOBRIEF = YES
-
-# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
-# member inherits the documentation from any documented member that it
-# reimplements.
-INHERIT_DOCS = YES
-
-# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
-# is inserted in the documentation for inline members.
-INLINE_INFO = YES
-
-# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
-# will sort the (detailed) documentation of file and class members
-# alphabetically by member name. If set to NO the members will appear in
-# declaration order.
-SORT_MEMBER_DOCS = YES
-
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES, then doxygen will reuse the documentation of the first
-# member in the group (if any) for the other members of the group. By default
-# all members of a group must be documented explicitly.
-DISTRIBUTE_GROUP_DOC = NO
-
-# The TAB_SIZE tag can be used to set the number of spaces in a tab.
-# Doxygen uses this value to replace tabs by spaces in code fragments.
-TAB_SIZE = 4
-
-# The ENABLE_SECTIONS tag can be used to enable conditional
-# documentation sections, marked by \if sectionname ... \endif.
-ENABLED_SECTION =
-
-# The GENERATE_TODOLIST tag can be used to enable (YES) or
-# disable (NO) the todo list. This list is created by putting \todo
-# commands in the documentation
-GENERATE_TODOLIST = YES
-
-# The GENERATE_TESTLIST tag can be used to enable (YES) or
-# disable (NO) the test list. This list is created by putting \test
-# commands in the documentation.
-GENERATE_TESTLIST = YES
-
-# This tag can be used to specify a number of aliases that acts
-# as commands in the documentation. An alias has the form "name=value".
-# For example adding "sideeffect=\par Side Effects:\n" will allow you to
-# put the command \sideeffect (or @sideeffect) in the documentation, which
-# will result in a user defined paragraph with heading "Side Effects:".
-# You can put \n's in the value part of an alias to insert newlines.
-ALIASES =
-
-#---------------------------------------------------------------------------
-# configuration options related to warning and progress messages
-#---------------------------------------------------------------------------
-
-# The QUIET tag can be used to turn on/off the messages that are generated
-# by doxygen. Possible values are YES and NO. If left blank NO is used.
-QUIET = NO
-
-# The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated by doxygen. Possible values are YES and NO. If left blank
-# NO is used.
-WARNINGS = YES
-
-# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
-# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
-# automatically be disabled.
-WARN_IF_UNDOCUMENTED = YES
-
-# The WARN_FORMAT tag determines the format of the warning messages that
-# doxygen can produce. The string should contain the $file, $line, and $text
-# tags, which will be replaced by the file and line number from which the
-# warning originated and the warning text.
-WARN_FORMAT = "$file:$line: $text"
-
-# The WARN_LOGFILE tag can be used to specify a file to which warning
-# and error messages should be written. If left blank the output is written
-# to stderr.
-WARN_LOGFILE =
-
-#---------------------------------------------------------------------------
-# configuration options related to the input files
-#---------------------------------------------------------------------------
-
-# The INPUT tag can be used to specify the files and/or directories that contain
-# documented source files. You may enter file names like "myfile.cpp" or
-# directories like "/usr/src/myproject". Separate the files or directories
-# with spaces.
-INPUT = ..
-
-# If the value of the INPUT tag contains directories, you can use the
-# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank all files are included.
-FILE_PATTERNS = *.h *.cpp *.c
-
-# The RECURSIVE tag can be used to turn specify whether or not subdirectories
-# should be searched for input files as well. Possible values are YES and NO.
-# If left blank NO is used.
-RECURSIVE = NO
-
-# The EXCLUDE tag can be used to specify files and/or directories that should
-# excluded from the INPUT source files. This way you can easily exclude a
-# subdirectory from a directory tree whose root is specified with the INPUT tag.
-EXCLUDE =
-
-# If the value of the INPUT tag contains directories, you can use the
-# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories.
-EXCLUDE_PATTERNS =
-
-# The EXAMPLE_PATH tag can be used to specify one or more files or
-# directories that contain example code fragments that are included (see
-# the \include command).
-EXAMPLE_PATH = ../test
-
-# If the value of the EXAMPLE_PATH tag contains directories, you can use the
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank all files are included.
-EXAMPLE_PATTERNS = *.h *.cpp *.c
-
-# The IMAGE_PATH tag can be used to specify one or more files or
-# directories that contain image that are included in the documentation (see
-# the \image command).
-IMAGE_PATH =
-
-# The INPUT_FILTER tag can be used to specify a program that doxygen should
-# invoke to filter for each input file. Doxygen will invoke the filter program
-# by executing (via popen()) the command <filter> <input-file>, where <filter>
-# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
-# input file. Doxygen will then use the output that the filter program writes
-# to standard output.
-INPUT_FILTER =
-
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER) will be used to filter the input files when producing source
-# files to browse.
-FILTER_SOURCE_FILES = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the alphabetical class index
-#---------------------------------------------------------------------------
-
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
-# of all compounds will be generated. Enable this if the project
-# contains a lot of classes, structs, unions or interfaces.
-ALPHABETICAL_INDEX = YES
-
-# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
-# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
-# in which this list will be split (can be a number in the range [1..20])
-COLS_IN_ALPHA_INDEX = 5
-
-# In case all classes in a project start with a common prefix, all
-# classes will be put under the same header in the alphabetical index.
-# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
-# should be ignored while generating the index headers.
-IGNORE_PREFIX =
-
-#---------------------------------------------------------------------------
-# configuration options related to the HTML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
-# generate HTML output.
-GENERATE_HTML = YES
-
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `html' will be used as the default path.
-HTML_OUTPUT = html
-
-# The HTML_HEADER tag can be used to specify a personal HTML header for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard header.
-HTML_HEADER =
-
-# The HTML_FOOTER tag can be used to specify a personal HTML footer for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard footer.
-HTML_FOOTER =
-
-# The HTML_STYLESHEET tag can be used to specify a user defined cascading
-# style sheet that is used by each HTML page. It can be used to
-# fine-tune the look of the HTML output. If the tag is left blank doxygen
-# will generate a default style sheet
-HTML_STYLESHEET =
-
-# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
-# files or namespaces will be aligned in HTML using tables. If set to
-# NO a bullet list will be used.
-HTML_ALIGN_MEMBERS = YES
-
-# If the GENERATE_HTMLHELP tag is set to YES, additional index files
-# will be generated that can be used as input for tools like the
-# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
-# of the generated HTML documentation.
-GENERATE_HTMLHELP = YES
-
-# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
-# top of each HTML page. The value NO (the default) enables the index and
-# the value YES disables it.
-DISABLE_INDEX = NO
-
-# This tag can be used to set the number of enum values (range [1..20])
-# that doxygen will group on one line in the generated HTML documentation.
-ENUM_VALUES_PER_LINE = 4
-
-# If the GENERATE_TREEVIEW tag is set to YES, a side pannel will be
-# generated containing a tree-like index structure (just like the one that
-# is generated for HTML Help). For this to work a browser that supports
-# JavaScript and frames is required (for instance Netscape 4.0+
-# or Internet explorer 4.0+).
-GENERATE_TREEVIEW = YES
-
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
-# used to set the initial width (in pixels) of the frame in which the tree
-# is shown.
-TREEVIEW_WIDTH = 250
-
-#---------------------------------------------------------------------------
-# configuration options related to the LaTeX output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
-# generate Latex output.
-GENERATE_LATEX = NO
-
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `latex' will be used as the default path.
-LATEX_OUTPUT = latex
-
-# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
-# LaTeX documents. This may be useful for small projects and may help to
-# save some trees in general.
-COMPACT_LATEX = NO
-
-# The PAPER_TYPE tag can be used to set the paper type that is used
-# by the printer. Possible values are: a4, a4wide, letter, legal and
-# executive. If left blank a4wide will be used.
-PAPER_TYPE = a4wide
-
-# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
-# packages that should be included in the LaTeX output.
-EXTRA_PACKAGES =
-
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
-# the generated latex document. The header should contain everything until
-# the first chapter. If it is left blank doxygen will generate a
-# standard header. Notice: only use this tag if you know what you are doing!
-LATEX_HEADER =
-
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
-# is prepared for conversion to pdf (using ps2pdf). The pdf file will
-# contain links (just like the HTML output) instead of page references
-# This makes the output suitable for online browsing using a pdf viewer.
-PDF_HYPERLINKS = NO
-
-# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
-# plain latex in the generated Makefile. Set this option to YES to get a
-# higher quality PDF documentation.
-USE_PDFLATEX = NO
-
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
-# command to the generated LaTeX files. This will instruct LaTeX to keep
-# running if errors occur, instead of asking the user for help.
-# This option is also used when generating formulas in HTML.
-LATEX_BATCHMODE = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the RTF output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
-# The RTF output is optimised for Word 97 and may not look very pretty with
-# other RTF readers or editors.
-GENERATE_RTF = NO
-
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `rtf' will be used as the default path.
-RTF_OUTPUT = rtf
-
-# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
-# RTF documents. This may be useful for small projects and may help to
-# save some trees in general.
-COMPACT_RTF = NO
-
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
-# will contain hyperlink fields. The RTF file will
-# contain links (just like the HTML output) instead of page references.
-# This makes the output suitable for online browsing using a WORD or other.
-# programs which support those fields.
-# Note: wordpad (write) and others do not support links.
-RTF_HYPERLINKS = NO
-
-# Load stylesheet definitions from file. Syntax is similar to doxygen's
-# config file, i.e. a series of assigments. You only have to provide
-# replacements, missing definitions are set to their default value.
-RTF_STYLESHEET_FILE =
-
-#---------------------------------------------------------------------------
-# configuration options related to the man page output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
-# generate man pages
-GENERATE_MAN = NO
-
-# The MAN_OUTPUT tag is used to specify where the man pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `man' will be used as the default path.
-MAN_OUTPUT = man
-
-# The MAN_EXTENSION tag determines the extension that is added to
-# the generated man pages (default is the subroutine's section .3)
-MAN_EXTENSION = .3
-
-#---------------------------------------------------------------------------
-# configuration options related to the XML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_XML tag is set to YES Doxygen will
-# generate an XML file that captures the structure of
-# the code including all documentation. Warning: This feature
-# is still experimental and very incomplete.
-GENERATE_XML = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the preprocessor
-#---------------------------------------------------------------------------
-
-# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
-# evaluate all C-preprocessor directives found in the sources and include
-# files.
-ENABLE_PREPROCESSING = YES
-
-# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
-# names in the source code. If set to NO (the default) only conditional
-# compilation will be performed. Macro expansion can be done in a controlled
-# way by setting EXPAND_ONLY_PREDEF to YES.
-MACRO_EXPANSION = NO
-
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
-# then the macro expansion is limited to the macros specified with the
-# PREDEFINED and EXPAND_AS_PREDEFINED tags.
-EXPAND_ONLY_PREDEF = NO
-
-# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
-# in the INCLUDE_PATH (see below) will be search if a #include is found.
-SEARCH_INCLUDES = YES
-
-# The INCLUDE_PATH tag can be used to specify one or more directories that
-# contain include files that are not input files but should be processed by
-# the preprocessor.
-INCLUDE_PATH =
-
-# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
-# patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will
-# be used.
-INCLUDE_FILE_PATTERNS =
-
-# The PREDEFINED tag can be used to specify one or more macro names that
-# are defined before the preprocessor is started (similar to the -D option of
-# gcc). The argument of the tag is a list of macros of the form: name
-# or name=definition (no spaces). If the definition and the = are
-# omitted =1 is assumed.
-PREDEFINED =
-
-# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then
-# this tag can be used to specify a list of macro names that should be expanded.
-# The macro definition that is found in the sources will be used.
-# Use the PREDEFINED tag if you want to use a different macro definition.
-EXPAND_AS_DEFINED =
-
-#---------------------------------------------------------------------------
-# Configuration::additions related to external references
-#---------------------------------------------------------------------------
-
-# The TAGFILES tag can be used to specify one or more tagfiles.
-TAGFILES =
-
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create
-# a tag file that is based on the input files it reads.
-GENERATE_TAGFILE =
-
-# If the ALLEXTERNALS tag is set to YES all external classes will be listed
-# in the class index. If set to NO only the inherited external classes
-# will be listed.
-ALLEXTERNALS =
-
-# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of `which perl').
-PERL_PATH = /usr/bin/perl
-
-#---------------------------------------------------------------------------
-# Configuration options related to the dot tool
-#---------------------------------------------------------------------------
-
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
-# available from the path. This tool is part of Graphviz, a graph visualization
-# toolkit from AT&T and Lucent Bell Labs. The other options in this section
-# have no effect if this option is set to NO (the default)
-HAVE_DOT = YES
-
-# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect inheritance relations. Setting this tag to YES will force the
-# the CLASS_DIAGRAMS tag to NO.
-CLASS_GRAPH = YES
-
-# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect implementation dependencies (inheritance, containment, and
-# class references variables) of the class with other documented classes.
-COLLABORATION_GRAPH = YES
-
-# If the ENABLE_PREPROCESSING, INCLUDE_GRAPH, and HAVE_DOT tags are set to
-# YES then doxygen will generate a graph for each documented file showing
-# the direct and indirect include dependencies of the file with other
-# documented files.
-INCLUDE_GRAPH = YES
-
-# If the ENABLE_PREPROCESSING, INCLUDED_BY_GRAPH, and HAVE_DOT tags are set to
-# YES then doxygen will generate a graph for each documented header file showing
-# the documented files that directly or indirectly include this file
-INCLUDED_BY_GRAPH = YES
-
-# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
-# will graphical hierarchy of all classes instead of a textual one.
-GRAPHICAL_HIERARCHY = YES
-
-# The tag DOT_PATH can be used to specify the path where the dot tool can be
-# found. If left blank, it is assumed the dot tool can be found on the path.
-DOT_PATH =
-
-# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
-# (in pixels) of the graphs generated by dot. If a graph becomes larger than
-# this value, doxygen will try to truncate the graph, so that it fits within
-# the specified constraint. Beware that most browsers cannot cope with very
-# large images.
-MAX_DOT_GRAPH_WIDTH = 1024
-
-# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
-# (in pixels) of the graphs generated by dot. If a graph becomes larger than
-# this value, doxygen will try to truncate the graph, so that it fits within
-# the specified constraint. Beware that most browsers cannot cope with very
-# large images.
-MAX_DOT_GRAPH_HEIGHT = 1024
-
-# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
-# generate a legend page explaining the meaning of the various boxes and
-# arrows in the dot generated graphs.
-GENERATE_LEGEND = YES
-
-#---------------------------------------------------------------------------
-# Configuration::addtions related to the search engine
-#---------------------------------------------------------------------------
-
-# The SEARCHENGINE tag specifies whether or not a search engine should be
-# used. If set to NO the values of all tags below this one will be ignored.
-SEARCHENGINE = NO
-
-# The CGI_NAME tag should be the name of the CGI script that
-# starts the search engine (doxysearch) with the correct parameters.
-# A script with this name will be generated by doxygen.
-CGI_NAME= search.cgi
-
-# The CGI_URL tag should be the absolute URL to the directory where the
-# cgi binaries are located. See the documentation of your http daemon for
-# details.
-CGI_URL=
-
-# The DOC_URL tag should be the absolute URL to the directory where the
-# documentation is located. If left blank the absolute path to the
-# documentation, with file:// prepended to it, will be used.
-DOC_URL=
-
-# The DOC_ABSPATH tag should be the absolute path to the directory where the
-# documentation is located. If left blank the directory on the local machine
-# will be used.
-DOC_ABSPATH=
-
-# The BIN_ABSPATH tag must point to the directory where the doxysearch binary
-# is installed.
-BIN_ABSPATH= /bin
-
-# The EXT_DOC_PATHS tag can be used to specify one or more paths to
-# documentation generated for other projects. This allows doxysearch to search
-# the documentation for these projects as well.
-EXT_DOC_PATHS=
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index ccd7f57f9a4..41bc735e1e2 100644
--- a/intern/ghost/intern/GHOST_C-api.cpp
+++ b/intern/ghost/intern/GHOST_C-api.cpp
@@ -406,12 +406,13 @@ GHOST_TSuccess GHOST_GetButtonState(GHOST_SystemHandle systemhandle,
}
+#ifdef WITH_INPUT_NDOF
void GHOST_setNDOFDeadZone(float deadzone)
{
GHOST_ISystem *system = GHOST_ISystem::getSystem();
system->setNDOFDeadZone(deadzone);
}
-
+#endif
void GHOST_setAcceptDragOperation(GHOST_WindowHandle windowhandle, GHOST_TInt8 canAccept)
{
diff --git a/intern/ghost/intern/GHOST_ContextCGL.h b/intern/ghost/intern/GHOST_ContextCGL.h
index 953235669a8..dd49b81b561 100644
--- a/intern/ghost/intern/GHOST_ContextCGL.h
+++ b/intern/ghost/intern/GHOST_ContextCGL.h
@@ -136,6 +136,8 @@ private:
//static CGLEWContext *s_cglewContext;
+ const bool m_debug;
+
/** The first created OpenGL context (for sharing display lists) */
static NSOpenGLContext *s_sharedOpenGLContext;
static int s_sharedCount;
diff --git a/intern/ghost/intern/GHOST_ContextCGL.mm b/intern/ghost/intern/GHOST_ContextCGL.mm
index e09de4be143..03c45f9945b 100644
--- a/intern/ghost/intern/GHOST_ContextCGL.mm
+++ b/intern/ghost/intern/GHOST_ContextCGL.mm
@@ -59,7 +59,8 @@ GHOST_ContextCGL::GHOST_ContextCGL(
int contextResetNotificationStrategy)
: GHOST_Context(stereoVisual, numOfAASamples),
m_openGLView(openGLView),
- m_openGLContext(nil)
+ m_openGLContext(nil),
+ m_debug(contextFlags)
{
assert(openGLView != nil);
}
@@ -172,20 +173,21 @@ static void makeAttribList(
bool stereoVisual,
int numOfAASamples,
bool needAlpha,
- bool needStencil)
+ bool needStencil,
+ bool softwareGL)
{
+ attribs.clear();
+
// Pixel Format Attributes for the windowed NSOpenGLContext
attribs.push_back(NSOpenGLPFADoubleBuffer);
- // Force software OpenGL, for debugging
- /* XXX jwilkins: fixed this to work on Intel macs? useful feature for Windows and Linux too?
- * Maybe a command line flag is better... */
- if (getenv("BLENDER_SOFTWAREGL")) {
+ if (softwareGL) {
attribs.push_back(NSOpenGLPFARendererID);
attribs.push_back(kCGLRendererGenericFloatID);
}
else {
attribs.push_back(NSOpenGLPFAAccelerated);
+ attribs.push_back(NSOpenGLPFANoRecovery);
}
/* Removed to allow 10.4 builds, and 2 GPUs rendering is not used anyway */
@@ -219,13 +221,21 @@ static void makeAttribList(
attribs.push_back(NSOpenGLPFASamples);
attribs.push_back((NSOpenGLPixelFormatAttribute) numOfAASamples);
-
- attribs.push_back(NSOpenGLPFANoRecovery);
}
attribs.push_back((NSOpenGLPixelFormatAttribute) 0);
}
+// TODO(merwin): make this available to all platforms
+static void getVersion(int *major, int *minor)
+{
+#if 1 // legacy GL
+ sscanf((const char*)glGetString(GL_VERSION), "%d.%d", major, minor);
+#else // 3.0+
+ glGetIntegerv(GL_MAJOR_VERSION, major);
+ glGetIntegerv(GL_MINOR_VERSION, minor);
+#endif
+}
GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
{
@@ -248,9 +258,12 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
static const bool needStencil = false;
#endif
- makeAttribList(attribs, m_stereoVisual, m_numOfAASamples, needAlpha, needStencil);
-
+ static bool softwareGL = getenv("BLENDER_SOFTWAREGL"); // command-line argument would be better
+ GLint major = 0, minor = 0;
NSOpenGLPixelFormat *pixelFormat;
+ // TODO: keep pixel format for subsequent windows/contexts instead of recreating each time
+
+ makeAttribList(attribs, m_stereoVisual, m_numOfAASamples, needAlpha, needStencil, softwareGL);
pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:&attribs[0]];
@@ -261,7 +274,7 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
// (Now that I think about it, does WGL really require the code that it has for finding a lesser match?)
attribs.clear();
- makeAttribList(attribs, m_stereoVisual, 0, needAlpha, needStencil);
+ makeAttribList(attribs, m_stereoVisual, 0, needAlpha, needStencil, softwareGL);
pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:&attribs[0]];
}
@@ -282,25 +295,47 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
}
}
- [m_openGLView setPixelFormat:pixelFormat];
+ m_openGLContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:s_sharedOpenGLContext];
+ [pixelFormat release];
- m_openGLContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:s_sharedOpenGLContext]; // +1 refCount to pixelFormat
+ [m_openGLContext makeCurrentContext];
- if (m_openGLContext == nil)
- goto error;
+ getVersion(&major, &minor);
+ if (m_debug) {
+ fprintf(stderr, "OpenGL version %d.%d%s\n", major, minor, softwareGL ? " (software)" : "");
+ fprintf(stderr, "Renderer: %s\n", glGetString(GL_RENDERER));
+ }
- if (s_sharedCount == 0)
- s_sharedOpenGLContext = m_openGLContext;
-
- [pixelFormat release]; // -1 refCount to pixelFormat
-
- s_sharedCount++;
+ if (major < 2 || (major == 2 && minor < 1)) {
+ // fall back to software renderer if GL < 2.1
+ fprintf(stderr, "OpenGL 2.1 is not supported on your hardware, falling back to software");
+ softwareGL = true;
+
+ // discard hardware GL context
+ [NSOpenGLContext clearCurrentContext];
+ [m_openGLContext release];
+
+ // create software GL context
+ makeAttribList(attribs, m_stereoVisual, m_numOfAASamples, needAlpha, needStencil, softwareGL);
+ pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:&attribs[0]];
+ m_openGLContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:s_sharedOpenGLContext];
+ [pixelFormat release];
+
+ [m_openGLContext makeCurrentContext];
+
+ getVersion(&major, &minor);
+ if (m_debug) {
+ fprintf(stderr, "OpenGL version %d.%d%s\n", major, minor, softwareGL ? " (software)" : "");
+ fprintf(stderr, "Renderer: %s\n", glGetString(GL_RENDERER));
+ }
+ }
#ifdef GHOST_MULTITHREADED_OPENGL
//Switch openGL to multhreaded mode
CGLContextObj cglCtx = (CGLContextObj)[tmpOpenGLContext CGLContextObj];
if (CGLEnable(cglCtx, kCGLCEMPEngine) == kCGLNoError)
- printf("\nSwitched openGL to multithreaded mode\n");
+ if (m_debug)
+ fprintf(stderr, "\nSwitched OpenGL to multithreaded mode\n");
#endif
#ifdef GHOST_WAIT_FOR_VSYNC
@@ -311,10 +346,16 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
}
#endif
+ initContextGLEW();
+
[m_openGLView setOpenGLContext:m_openGLContext];
[m_openGLContext setView:m_openGLView];
- initContextGLEW();
+ if (s_sharedCount == 0)
+ s_sharedOpenGLContext = m_openGLContext;
+
+ s_sharedCount++;
+
initClearGL();
[m_openGLContext flushBuffer];
diff --git a/intern/ghost/intern/GHOST_ContextGLX.cpp b/intern/ghost/intern/GHOST_ContextGLX.cpp
index 90d810b7986..9ac61db4041 100644
--- a/intern/ghost/intern/GHOST_ContextGLX.cpp
+++ b/intern/ghost/intern/GHOST_ContextGLX.cpp
@@ -62,6 +62,7 @@ GHOST_ContextGLX::GHOST_ContextGLX(
Window window,
Display *display,
XVisualInfo *visualInfo,
+ GLXFBConfig fbconfig,
int contextProfileMask,
int contextMajorVersion,
int contextMinorVersion,
@@ -70,6 +71,7 @@ GHOST_ContextGLX::GHOST_ContextGLX(
: GHOST_Context(stereoVisual, numOfAASamples),
m_display(display),
m_visualInfo(visualInfo),
+ m_fbconfig(fbconfig),
m_window(window),
m_contextProfileMask(contextProfileMask),
m_contextMajorVersion(contextMajorVersion),
@@ -153,15 +155,7 @@ void GHOST_ContextGLX::initContextGLXEW()
GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext()
{
-#ifdef WITH_X11_XINPUT
- /* use our own event handlers to avoid exiting blender,
- * this would happen for eg:
- * if you open blender, unplug a tablet, then open a new window. */
- XErrorHandler old_handler = XSetErrorHandler (GHOST_X11_ApplicationErrorHandler );
- XIOErrorHandler old_handler_io = XSetIOErrorHandler(GHOST_X11_ApplicationIOErrorHandler);
-#endif
-
-
+ GHOST_X11_ERROR_HANDLERS_OVERRIDE(handler_store);
/* -------------------------------------------------------------------- */
/* Begin Inline Glew */
@@ -285,19 +279,24 @@ const bool GLXEW_ARB_create_context_robustness =
attribs[i++] = 0;
/* Create a GL 3.x context */
- GLXFBConfig *framebuffer_config = NULL;
- {
- int glx_attribs[64];
- int fbcount = 0;
+ if (m_fbconfig) {
+ m_context = glXCreateContextAttribsARB(m_display, m_fbconfig, s_sharedContext, true, attribs);
+ }
+ else {
+ GLXFBConfig *framebuffer_config = NULL;
+ {
+ int glx_attribs[64];
+ int fbcount = 0;
- GHOST_X11_GL_GetAttributes(glx_attribs, 64, m_numOfAASamples, m_stereoVisual, true);
+ GHOST_X11_GL_GetAttributes(glx_attribs, 64, m_numOfAASamples, m_stereoVisual, false, true);
- framebuffer_config = glXChooseFBConfig(m_display, DefaultScreen(m_display), glx_attribs, &fbcount);
- }
+ framebuffer_config = glXChooseFBConfig(m_display, DefaultScreen(m_display), glx_attribs, &fbcount);
+ }
- if (framebuffer_config) {
- m_context = glXCreateContextAttribsARB(m_display, framebuffer_config[0], s_sharedContext, True, attribs);
- XFree(framebuffer_config);
+ if (framebuffer_config) {
+ m_context = glXCreateContextAttribsARB(m_display, framebuffer_config[0], s_sharedContext, True, attribs);
+ XFree(framebuffer_config);
+ }
}
}
else {
@@ -343,11 +342,8 @@ const bool GLXEW_ARB_create_context_robustness =
success = GHOST_kFailure;
}
-#ifdef WITH_X11_XINPUT
- /* Restore handler */
- XSetErrorHandler (old_handler);
- XSetIOErrorHandler(old_handler_io);
-#endif
+
+ GHOST_X11_ERROR_HANDLERS_RESTORE(handler_store);
return success;
}
@@ -401,16 +397,11 @@ GHOST_TSuccess GHOST_ContextGLX::getSwapInterval(int &intervalOut)
int GHOST_X11_GL_GetAttributes(
int *attribs, int attribs_max,
int samples, bool is_stereo_visual,
+ bool need_alpha,
bool for_fb_config)
{
int i = 0;
-#ifdef GHOST_OPENGL_ALPHA
- const bool need_alpha = true;
-#else
- const bool need_alpha = false;
-#endif
-
#ifdef GHOST_OPENGL_STENCIL
const bool need_stencil = true;
#else
diff --git a/intern/ghost/intern/GHOST_ContextGLX.h b/intern/ghost/intern/GHOST_ContextGLX.h
index 8c2231a0b01..f0f010d1942 100644
--- a/intern/ghost/intern/GHOST_ContextGLX.h
+++ b/intern/ghost/intern/GHOST_ContextGLX.h
@@ -66,6 +66,7 @@ public:
Window window,
Display *display,
XVisualInfo *visualInfo,
+ GLXFBConfig fbconfig,
int contextProfileMask,
int contextMajorVersion,
int contextMinorVersion,
@@ -128,6 +129,7 @@ private:
Display *m_display;
XVisualInfo *m_visualInfo;
+ GLXFBConfig m_fbconfig;
Window m_window;
const int m_contextProfileMask;
@@ -151,6 +153,7 @@ private:
int GHOST_X11_GL_GetAttributes(
int *attribs, int attribs_max,
int samples, bool is_stereo_visual,
+ bool need_alpha,
bool for_fb_config);
#endif // __GHOST_CONTEXTGLX_H__
diff --git a/intern/ghost/intern/GHOST_ContextSDL.cpp b/intern/ghost/intern/GHOST_ContextSDL.cpp
index d80a638818c..39627fac899 100644
--- a/intern/ghost/intern/GHOST_ContextSDL.cpp
+++ b/intern/ghost/intern/GHOST_ContextSDL.cpp
@@ -69,7 +69,7 @@ GHOST_ContextSDL::GHOST_ContextSDL(
GHOST_ContextSDL::~GHOST_ContextSDL()
{
if (m_context != NULL) {
- if (m_window != 0 && m_context == SDL_GL_GetCurrentContext())
+ if (m_window != NULL && m_context == SDL_GL_GetCurrentContext())
SDL_GL_MakeCurrent(m_window, m_context);
if (m_context != s_sharedContext || s_sharedCount == 1) {
diff --git a/intern/ghost/intern/GHOST_ContextWGL.cpp b/intern/ghost/intern/GHOST_ContextWGL.cpp
index cb580f60bd7..64ee692797b 100644
--- a/intern/ghost/intern/GHOST_ContextWGL.cpp
+++ b/intern/ghost/intern/GHOST_ContextWGL.cpp
@@ -63,6 +63,7 @@ static bool is_crappy_intel_card()
GHOST_ContextWGL::GHOST_ContextWGL(
bool stereoVisual,
+ bool alphaBackground,
GHOST_TUns16 numOfAASamples,
HWND hWnd,
HDC hDC,
@@ -78,6 +79,7 @@ GHOST_ContextWGL::GHOST_ContextWGL(
m_contextMajorVersion(contextMajorVersion),
m_contextMinorVersion(contextMinorVersion),
m_contextFlags(contextFlags),
+ m_alphaBackground(alphaBackground),
m_contextResetNotificationStrategy(contextResetNotificationStrategy),
m_hGLRC(NULL)
#ifdef WITH_GLEW_MX
@@ -168,7 +170,7 @@ GHOST_TSuccess GHOST_ContextWGL::activateDrawingContext()
/* Ron Fosner's code for weighting pixel formats and forcing software.
* See http://www.opengl.org/resources/faq/technical/weight.cpp
*/
-static int weight_pixel_format(PIXELFORMATDESCRIPTOR &pfd)
+static int weight_pixel_format(PIXELFORMATDESCRIPTOR &pfd, PIXELFORMATDESCRIPTOR &preferredPFD)
{
int weight = 0;
@@ -181,6 +183,7 @@ static int weight_pixel_format(PIXELFORMATDESCRIPTOR &pfd)
!(pfd.dwFlags & PFD_DOUBLEBUFFER) || /* Blender _needs_ this */
!(pfd.iPixelType == PFD_TYPE_RGBA) ||
(pfd.cDepthBits < 16) ||
+ (pfd.cColorBits > 32) || /* 64 bit formats disable aero */
(pfd.dwFlags & PFD_GENERIC_FORMAT)) /* no software renderers */
{
return 0;
@@ -194,11 +197,12 @@ static int weight_pixel_format(PIXELFORMATDESCRIPTOR &pfd)
weight += pfd.cColorBits - 8;
-#ifdef GHOST_OPENGL_ALPHA
- if (pfd.cAlphaBits > 0)
+ if (preferredPFD.cAlphaBits > 0 && pfd.cAlphaBits > 0)
+ weight++;
+#ifdef WIN32_COMPOSITING
+ if ((preferredPFD.dwFlags & PFD_SUPPORT_COMPOSITION) && (pfd.dwFlags & PFD_SUPPORT_COMPOSITION))
weight++;
#endif
-
#ifdef GHOST_OPENGL_STENCIL
if (pfd.cStencilBits >= 8)
weight++;
@@ -239,7 +243,7 @@ static int choose_pixel_format_legacy(HDC hDC, PIXELFORMATDESCRIPTOR &preferredP
WIN32_CHK(check == lastPFD);
- int w = weight_pixel_format(pfd);
+ int w = weight_pixel_format(pfd, preferredPFD);
if (w > weight) {
weight = w;
@@ -496,7 +500,10 @@ int GHOST_ContextWGL::_choose_pixel_format_arb_2(
{
std::vector<int> iAttributes;
+#define _MAX_PIXEL_FORMATS 32
+
int iPixelFormat = 0;
+ int iPixelFormats[_MAX_PIXEL_FORMATS];
int samples;
@@ -521,8 +528,31 @@ int GHOST_ContextWGL::_choose_pixel_format_arb_2(
sRGB);
UINT nNumFormats;
- WIN32_CHK(wglChoosePixelFormatARB(m_hDC, &(iAttributes[0]), NULL, 1, &iPixelFormat, &nNumFormats));
-
+ WIN32_CHK(wglChoosePixelFormatARB(m_hDC, &(iAttributes[0]), NULL, _MAX_PIXEL_FORMATS, iPixelFormats, &nNumFormats));
+
+#ifdef WIN32_COMPOSITING
+ if (needAlpha && nNumFormats) {
+ // scan through all pixel format to make sure one supports compositing
+ PIXELFORMATDESCRIPTOR pfd;
+ int i;
+
+ for (i = 0; i < nNumFormats; i++) {
+ if (DescribePixelFormat(m_hDC, iPixelFormats[i], sizeof(PIXELFORMATDESCRIPTOR), &pfd)) {
+ if (pfd.dwFlags & PFD_SUPPORT_COMPOSITION) {
+ iPixelFormat = iPixelFormats[i];
+ break;
+ }
+ }
+ }
+ if (i == nNumFormats) {
+ fprintf(stderr,
+ "Warning! Unable to find a pixel format with compositing capability.\n");
+ iPixelFormat = iPixelFormats[0];
+ }
+ }
+ else
+#endif
+ iPixelFormat = iPixelFormats[0];
/* total number of formats that match (regardless of size of iPixelFormat array)
* see: WGL_ARB_pixel_format extension spec */
if (nNumFormats > 0)
@@ -538,7 +568,7 @@ int GHOST_ContextWGL::_choose_pixel_format_arb_2(
// check how many samples were actually gotten
if (iPixelFormat != 0) {
int iQuery[] = { WGL_SAMPLES_ARB };
- int actualSamples;
+ int actualSamples, alphaBits;
wglGetPixelFormatAttribivARB(m_hDC, iPixelFormat, 0, 1, iQuery, &actualSamples);
if (actualSamples != *numOfAASamples) {
@@ -549,6 +579,14 @@ int GHOST_ContextWGL::_choose_pixel_format_arb_2(
*numOfAASamples = actualSamples; // set context property to actual value
}
+ if (needAlpha) {
+ iQuery[0] = WGL_ALPHA_BITS_ARB;
+ wglGetPixelFormatAttribivARB(m_hDC, iPixelFormat, 0, 1, iQuery, &alphaBits);
+ if (alphaBits == 0) {
+ fprintf(stderr,
+ "Warning! Unable to find a frame buffer with alpha channel.\n");
+ }
+ }
}
else {
*numOfAASamples = 0;
@@ -670,20 +708,27 @@ int GHOST_ContextWGL::choose_pixel_format(
PIXELFORMATDESCRIPTOR preferredPFD = {
sizeof(PIXELFORMATDESCRIPTOR), /* size */
1, /* version */
+ (DWORD) (
PFD_SUPPORT_OPENGL |
PFD_DRAW_TO_WINDOW |
PFD_SWAP_COPY | /* support swap copy */
PFD_DOUBLEBUFFER | /* support double-buffering */
- (stereoVisual ? PFD_STEREO : 0), /* support stereo */
+ (stereoVisual ? PFD_STEREO : 0) |/* support stereo */
+ (
+#ifdef WIN32_COMPOSITING
+ needAlpha ? PFD_SUPPORT_COMPOSITION : /* support composition for transparent background */
+#endif
+ 0
+ )),
PFD_TYPE_RGBA, /* color type */
- 24, /* preferred color depth */
+ (BYTE) (needAlpha ? 32 : 24), /* preferred color depth */
0, 0, 0, 0, 0, 0, /* color bits (ignored) */
- needAlpha ? 8 : 0, /* alpha buffer */
+ (BYTE) (needAlpha ? 8 : 0), /* alpha buffer */
0, /* alpha shift (ignored) */
0, /* no accumulation buffer */
0, 0, 0, 0, /* accum bits (ignored) */
24, /* depth buffer */
- needStencil ? 8 : 0, /* stencil buffer */
+ (BYTE) (needStencil ? 8 : 0), /* stencil buffer */
0, /* no auxiliary buffers */
PFD_MAIN_PLANE, /* main layer */
0, /* reserved */
@@ -727,11 +772,7 @@ static void reportContextString(const char *name, const char *dummy, const char
GHOST_TSuccess GHOST_ContextWGL::initializeDrawingContext()
{
-#ifdef GHOST_OPENGL_ALPHA
- const bool needAlpha = true;
-#else
- const bool needAlpha = false;
-#endif
+ const bool needAlpha = m_alphaBackground;
#ifdef GHOST_OPENGL_STENCIL
const bool needStencil = true;
diff --git a/intern/ghost/intern/GHOST_ContextWGL.h b/intern/ghost/intern/GHOST_ContextWGL.h
index 3b04a33b662..580b4dcb82f 100644
--- a/intern/ghost/intern/GHOST_ContextWGL.h
+++ b/intern/ghost/intern/GHOST_ContextWGL.h
@@ -32,6 +32,8 @@
#ifndef __GHOST_CONTEXTWGL_H__
#define __GHOST_CONTEXTWGL_H__
+//#define WIN32_COMPOSITING
+
#include "GHOST_Context.h"
#ifdef WITH_GLEW_MX
@@ -65,6 +67,7 @@ public:
*/
GHOST_ContextWGL(
bool stereoVisual,
+ bool alphaBackground,
GHOST_TUns16 numOfAASamples,
HWND hWnd,
HDC hDC,
@@ -164,6 +167,7 @@ private:
const int m_contextMajorVersion;
const int m_contextMinorVersion;
const int m_contextFlags;
+ const bool m_alphaBackground;
const int m_contextResetNotificationStrategy;
HGLRC m_hGLRC;
diff --git a/intern/ghost/intern/GHOST_DropTargetWin32.cpp b/intern/ghost/intern/GHOST_DropTargetWin32.cpp
index fd9abce96b7..cbf37bf1b16 100644
--- a/intern/ghost/intern/GHOST_DropTargetWin32.cpp
+++ b/intern/ghost/intern/GHOST_DropTargetWin32.cpp
@@ -75,7 +75,7 @@ HRESULT __stdcall GHOST_DropTargetWin32::QueryInterface(REFIID riid, void **ppvO
return S_OK;
}
else {
- *ppvObj = 0;
+ *ppvObj = NULL;
return E_NOINTERFACE;
}
}
@@ -97,8 +97,7 @@ ULONG __stdcall GHOST_DropTargetWin32::Release(void)
{
ULONG refs = ::InterlockedDecrement(&m_cRef);
- if (refs == 0)
- {
+ if (refs == 0) {
delete this;
return 0;
}
@@ -126,8 +125,7 @@ HRESULT __stdcall GHOST_DropTargetWin32::DragEnter(IDataObject *pDataObject, DWO
*/
HRESULT __stdcall GHOST_DropTargetWin32::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
{
- if (m_window->canAcceptDragOperation())
- {
+ if (m_window->canAcceptDragOperation()) {
*pdwEffect = allowedDropEffect(*pdwEffect);
}
else {
@@ -155,8 +153,7 @@ HRESULT __stdcall GHOST_DropTargetWin32::DragLeave(void)
HRESULT __stdcall GHOST_DropTargetWin32::Drop(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
{
void *data = getGhostData(pDataObject);
- if (m_window->canAcceptDragOperation())
- {
+ if (m_window->canAcceptDragOperation()) {
*pdwEffect = allowedDropEffect(*pdwEffect);
}
@@ -190,15 +187,13 @@ GHOST_TDragnDropTypes GHOST_DropTargetWin32::getGhostType(IDataObject *pDataObje
* conversion, but we do the conversion ourself with WC_NO_BEST_FIT_CHARS.
*/
FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
- if (pDataObject->QueryGetData(&fmtetc) == S_OK)
- {
+ if (pDataObject->QueryGetData(&fmtetc) == S_OK) {
return GHOST_kDragnDropTypeString;
}
// Filesnames
fmtetc.cfFormat = CF_HDROP;
- if (pDataObject->QueryGetData(&fmtetc) == S_OK)
- {
+ if (pDataObject->QueryGetData(&fmtetc) == S_OK) {
return GHOST_kDragnDropTypeFilenames;
}
diff --git a/intern/ghost/intern/GHOST_EventManager.cpp b/intern/ghost/intern/GHOST_EventManager.cpp
index bc531bd515b..0675ac734ed 100644
--- a/intern/ghost/intern/GHOST_EventManager.cpp
+++ b/intern/ghost/intern/GHOST_EventManager.cpp
@@ -167,11 +167,9 @@ void GHOST_EventManager::removeWindowEvents(GHOST_IWindow *window)
{
TEventStack::iterator iter;
iter = m_events.begin();
- while (iter != m_events.end())
- {
+ while (iter != m_events.end()) {
GHOST_IEvent *event = *iter;
- if (event->getWindow() == window)
- {
+ if (event->getWindow() == window) {
GHOST_PRINT("GHOST_EventManager::removeWindowEvents(): removing event\n");
/*
* Found an event for this window, remove it.
@@ -191,11 +189,9 @@ void GHOST_EventManager::removeTypeEvents(GHOST_TEventType type, GHOST_IWindow *
{
TEventStack::iterator iter;
iter = m_events.begin();
- while (iter != m_events.end())
- {
+ while (iter != m_events.end()) {
GHOST_IEvent *event = *iter;
- if ((event->getType() == type) && (!window || (event->getWindow() == window)))
- {
+ if ((event->getType() == type) && (!window || (event->getWindow() == window))) {
GHOST_PRINT("GHOST_EventManager::removeTypeEvents(): removing event\n");
/*
* Found an event of this type for the window, remove it.
diff --git a/intern/ghost/intern/GHOST_EventNDOF.h b/intern/ghost/intern/GHOST_EventNDOF.h
index b4037896b93..754e1091860 100644
--- a/intern/ghost/intern/GHOST_EventNDOF.h
+++ b/intern/ghost/intern/GHOST_EventNDOF.h
@@ -22,9 +22,12 @@
/** \file ghost/intern/GHOST_EventNDOF.h
* \ingroup GHOST
- * Declaration of GHOST_EventManager class.
*/
+#ifndef WITH_INPUT_NDOF
+# error NDOF code included in non-NDOF-enabled build
+#endif
+
#ifndef __GHOST_EVENTNDOF_H__
#define __GHOST_EVENTNDOF_H__
diff --git a/intern/ghost/intern/GHOST_ISystem.cpp b/intern/ghost/intern/GHOST_ISystem.cpp
index d7dd2b1cde1..37d5926ffc2 100644
--- a/intern/ghost/intern/GHOST_ISystem.cpp
+++ b/intern/ghost/intern/GHOST_ISystem.cpp
@@ -54,7 +54,7 @@
# endif
#endif
-GHOST_ISystem *GHOST_ISystem::m_system = 0;
+GHOST_ISystem *GHOST_ISystem::m_system = NULL;
GHOST_TSuccess GHOST_ISystem::createSystem()
@@ -76,7 +76,7 @@ GHOST_TSuccess GHOST_ISystem::createSystem()
# endif
# endif
#endif
- success = m_system != 0 ? GHOST_kSuccess : GHOST_kFailure;
+ success = m_system != NULL ? GHOST_kSuccess : GHOST_kFailure;
}
else {
success = GHOST_kFailure;
@@ -92,7 +92,7 @@ GHOST_TSuccess GHOST_ISystem::disposeSystem()
GHOST_TSuccess success = GHOST_kSuccess;
if (m_system) {
delete m_system;
- m_system = 0;
+ m_system = NULL;
}
else {
success = GHOST_kFailure;
diff --git a/intern/ghost/intern/GHOST_ISystemPaths.cpp b/intern/ghost/intern/GHOST_ISystemPaths.cpp
index 6ebcb37ba06..93ca0bc3880 100644
--- a/intern/ghost/intern/GHOST_ISystemPaths.cpp
+++ b/intern/ghost/intern/GHOST_ISystemPaths.cpp
@@ -36,6 +36,9 @@
* \date May 7, 2001
*/
+
+#include <stdio.h> /* just for NULL */
+
#include "GHOST_ISystemPaths.h"
#ifdef WIN32
@@ -49,7 +52,7 @@
#endif
-GHOST_ISystemPaths *GHOST_ISystemPaths::m_systemPaths = 0;
+GHOST_ISystemPaths *GHOST_ISystemPaths::m_systemPaths = NULL;
GHOST_TSuccess GHOST_ISystemPaths::create()
@@ -65,7 +68,7 @@ GHOST_TSuccess GHOST_ISystemPaths::create()
m_systemPaths = new GHOST_SystemPathsUnix();
# endif
#endif
- success = m_systemPaths != 0 ? GHOST_kSuccess : GHOST_kFailure;
+ success = m_systemPaths != NULL ? GHOST_kSuccess : GHOST_kFailure;
}
else {
success = GHOST_kFailure;
@@ -78,7 +81,7 @@ GHOST_TSuccess GHOST_ISystemPaths::dispose()
GHOST_TSuccess success = GHOST_kSuccess;
if (m_systemPaths) {
delete m_systemPaths;
- m_systemPaths = 0;
+ m_systemPaths = NULL;
}
else {
success = GHOST_kFailure;
diff --git a/intern/ghost/intern/GHOST_ImeWin32.cpp b/intern/ghost/intern/GHOST_ImeWin32.cpp
index af5a2ed7097..96bd12faef8 100644
--- a/intern/ghost/intern/GHOST_ImeWin32.cpp
+++ b/intern/ghost/intern/GHOST_ImeWin32.cpp
@@ -64,7 +64,7 @@ bool GHOST_ImeWin32::SetInputLanguage()
* while composing a text.
*/
HKL keyboard_layout = ::GetKeyboardLayout(0);
- input_language_id_ = reinterpret_cast<LANGID>(keyboard_layout);
+ input_language_id_ = LOWORD(keyboard_layout);
ime_status_ = ::ImmIsIME(keyboard_layout);
return ime_status_;
}
diff --git a/intern/ghost/intern/GHOST_NDOFManager.cpp b/intern/ghost/intern/GHOST_NDOFManager.cpp
index 27285e49e9e..cab9bf45b80 100644
--- a/intern/ghost/intern/GHOST_NDOFManager.cpp
+++ b/intern/ghost/intern/GHOST_NDOFManager.cpp
@@ -299,6 +299,12 @@ bool GHOST_NDOFManager::setDevice(unsigned short vendor_id, unsigned short produ
m_buttonMask = 0x07C0F137;
m_hidMap = Modern3Dx_HID_map;
break;
+ case 0xC633:
+ puts("ndof: using SpaceMouse Enterprise");
+ m_deviceType = NDOF_SpaceMouseEnterprise;
+ m_buttonCount = 31;
+ m_hidMap = Modern3Dx_HID_map;
+ break;
default:
printf("ndof: unknown 3Dconnexion product %04hx\n", product_id);
@@ -318,14 +324,14 @@ bool GHOST_NDOFManager::setDevice(unsigned short vendor_id, unsigned short produ
return m_deviceType != NDOF_UnknownDevice;
}
-void GHOST_NDOFManager::updateTranslation(const short t[3], GHOST_TUns64 time)
+void GHOST_NDOFManager::updateTranslation(const int t[3], GHOST_TUns64 time)
{
memcpy(m_translation, t, sizeof(m_translation));
m_motionTime = time;
m_motionEventPending = true;
}
-void GHOST_NDOFManager::updateRotation(const short r[3], GHOST_TUns64 time)
+void GHOST_NDOFManager::updateRotation(const int r[3], GHOST_TUns64 time)
{
memcpy(m_rotation, r, sizeof(m_rotation));
m_motionTime = time;
@@ -372,8 +378,7 @@ void GHOST_NDOFManager::updateButton(int button_number, bool press, GHOST_TUns64
NDOF_ButtonT button = (button_number < m_buttonCount) ? m_hidMap[button_number] : NDOF_BUTTON_NONE;
- switch (button)
- {
+ switch (button) {
case NDOF_BUTTON_NONE:
#ifdef DEBUG_NDOF_BUTTONS
printf("discarded\n");
diff --git a/intern/ghost/intern/GHOST_NDOFManager.h b/intern/ghost/intern/GHOST_NDOFManager.h
index ba82f37bb2a..0c0b945d548 100644
--- a/intern/ghost/intern/GHOST_NDOFManager.h
+++ b/intern/ghost/intern/GHOST_NDOFManager.h
@@ -21,6 +21,10 @@
* ***** END GPL LICENSE BLOCK *****
*/
+#ifndef WITH_INPUT_NDOF
+# error NDOF code included in non-NDOF-enabled build
+#endif
+
#ifndef __GHOST_NDOFMANAGER_H__
#define __GHOST_NDOFMANAGER_H__
@@ -40,6 +44,7 @@ typedef enum {
NDOF_SpaceMousePro,
NDOF_SpaceMouseWireless,
NDOF_SpaceMouseProWireless,
+ NDOF_SpaceMouseEnterprise,
// older devices
NDOF_SpacePilot,
@@ -133,8 +138,8 @@ public:
// rotations are + when CCW, - when CW
// each platform is responsible for getting axis data into this form
// these values should not be scaled (just shuffled or flipped)
- void updateTranslation(const short t[3], GHOST_TUns64 time);
- void updateRotation(const short r[3], GHOST_TUns64 time);
+ void updateTranslation(const int t[3], GHOST_TUns64 time);
+ void updateRotation(const int r[3], GHOST_TUns64 time);
// the latest raw button data from the device
// use HID button encoding (not NDOF_ButtonT)
@@ -158,8 +163,8 @@ private:
int m_buttonMask;
const NDOF_ButtonT *m_hidMap;
- short m_translation[3];
- short m_rotation[3];
+ int m_translation[3];
+ int m_rotation[3];
int m_buttons; // bit field
GHOST_TUns64 m_motionTime; // in milliseconds
diff --git a/intern/ghost/intern/GHOST_NDOFManagerCocoa.h b/intern/ghost/intern/GHOST_NDOFManagerCocoa.h
index 464ba48145e..3f1bfcf57fc 100644
--- a/intern/ghost/intern/GHOST_NDOFManagerCocoa.h
+++ b/intern/ghost/intern/GHOST_NDOFManagerCocoa.h
@@ -24,8 +24,6 @@
#ifndef __GHOST_NDOFMANAGERCOCOA_H__
#define __GHOST_NDOFMANAGERCOCOA_H__
-#ifdef WITH_INPUT_NDOF
-
#include "GHOST_NDOFManager.h"
// Event capture is handled within the NDOF manager on Macintosh,
@@ -40,6 +38,4 @@ public:
bool available();
};
-
-#endif // WITH_INPUT_NDOF
#endif // #include guard
diff --git a/intern/ghost/intern/GHOST_NDOFManagerCocoa.mm b/intern/ghost/intern/GHOST_NDOFManagerCocoa.mm
index 6fee39dcb82..e6fbc96ae7a 100644
--- a/intern/ghost/intern/GHOST_NDOFManagerCocoa.mm
+++ b/intern/ghost/intern/GHOST_NDOFManagerCocoa.mm
@@ -21,8 +21,6 @@
* ***** END GPL LICENSE BLOCK *****
*/
-#ifdef WITH_INPUT_NDOF
-
#define DEBUG_NDOF_DRIVER false
#include "GHOST_NDOFManagerCocoa.h"
@@ -115,13 +113,15 @@ static void* load_func(void* module, const char* func_name)
#define LOAD_FUNC(name) name = (name##_ptr) load_func(module, #name)
+static void* module; // handle to the whole driver
+
static bool load_driver_functions()
{
if (driver_loaded) {
return true;
}
- void* module = dlopen("3DconnexionClient.framework/3DconnexionClient", RTLD_LAZY | RTLD_LOCAL);
+ module = dlopen("3DconnexionClient.framework/3DconnexionClient", RTLD_LAZY | RTLD_LOCAL);
if (module) {
LOAD_FUNC(SetConnexionHandlers);
@@ -145,8 +145,6 @@ static bool load_driver_functions()
has_old_driver = (SetConnexionClientButtonMask == NULL);
}
-
- dlclose(module); // functions will remain loaded
}
#if DEBUG_NDOF_DRIVER
else {
@@ -161,6 +159,10 @@ static bool load_driver_functions()
return driver_loaded;
}
+static void unload_driver()
+{
+ dlclose(module);
+}
static void DeviceAdded(uint32_t unused)
{
@@ -198,8 +200,8 @@ static void DeviceEvent(uint32_t unused, uint32_t msg_type, void* msg_arg)
case kConnexionCmdHandleAxis:
{
// convert to blender view coordinates
- const short t[3] = {s->axis[0], -(s->axis[2]), s->axis[1]};
- const short r[3] = {-(s->axis[3]), s->axis[5], -(s->axis[4])};
+ const int t[3] = {s->axis[0], -(s->axis[2]), s->axis[1]};
+ const int r[3] = {-(s->axis[3]), s->axis[5], -(s->axis[4])};
ndof_manager->updateTranslation(t, now);
ndof_manager->updateRotation(r, now);
@@ -210,7 +212,9 @@ static void DeviceEvent(uint32_t unused, uint32_t msg_type, void* msg_arg)
case kConnexionCmdHandleButtons:
{
int button_bits = has_old_driver ? s->buttons8 : s->buttons;
+#ifdef DEBUG_NDOF_BUTTONS
printf("button bits: 0x%08x\n", button_bits);
+#endif
ndof_manager->updateButtons(button_bits, now);
ghost_system->notifyExternalEventProcessed();
break;
@@ -266,6 +270,7 @@ GHOST_NDOFManagerCocoa::~GHOST_NDOFManagerCocoa()
if (driver_loaded) {
UnregisterConnexionClient(clientID);
CleanupConnexionHandlers();
+ unload_driver();
ghost_system = NULL;
ndof_manager = NULL;
@@ -276,5 +281,3 @@ bool GHOST_NDOFManagerCocoa::available()
{
return driver_loaded;
}
-
-#endif // WITH_INPUT_NDOF
diff --git a/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp b/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp
index 8fea2a0261b..fff5aba6f9e 100644
--- a/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp
+++ b/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp
@@ -21,8 +21,6 @@
* ***** END GPL LICENSE BLOCK *****
*/
-#ifdef WITH_INPUT_NDOF
-
#include "GHOST_NDOFManagerUnix.h"
#include "GHOST_System.h"
@@ -109,8 +107,8 @@ bool GHOST_NDOFManagerUnix::processEvents()
{
/* convert to blender view coords */
GHOST_TUns64 now = m_system.getMilliSeconds();
- const short t[3] = {(short)e.motion.x, (short)e.motion.y, (short)-e.motion.z};
- const short r[3] = {(short)-e.motion.rx, (short)-e.motion.ry, (short)e.motion.rz};
+ const int t[3] = {(int)e.motion.x, (int)e.motion.y, (int)-e.motion.z};
+ const int r[3] = {(int)-e.motion.rx, (int)-e.motion.ry, (int)e.motion.rz};
updateTranslation(t, now);
updateRotation(r, now);
@@ -130,7 +128,7 @@ bool GHOST_NDOFManagerUnix::processEvents()
#ifdef USE_FINISH_GLITCH_WORKAROUND
if (motion_test_prev == true && motion_test == false) {
GHOST_TUns64 now = m_system.getMilliSeconds();
- const short v[3] = {0, 0, 0};
+ const int v[3] = {0, 0, 0};
updateTranslation(v, now);
updateRotation(v, now);
@@ -144,5 +142,3 @@ bool GHOST_NDOFManagerUnix::processEvents()
return anyProcessed;
}
-
-#endif /* WITH_INPUT_NDOF */
diff --git a/intern/ghost/intern/GHOST_NDOFManagerUnix.h b/intern/ghost/intern/GHOST_NDOFManagerUnix.h
index 278a8cb6fe0..3fd171d9e76 100644
--- a/intern/ghost/intern/GHOST_NDOFManagerUnix.h
+++ b/intern/ghost/intern/GHOST_NDOFManagerUnix.h
@@ -24,8 +24,6 @@
#ifndef __GHOST_NDOFMANAGERUNIX_H__
#define __GHOST_NDOFMANAGERUNIX_H__
-#ifdef WITH_INPUT_NDOF
-
#include "GHOST_NDOFManager.h"
/* Event capture is handled within the NDOF manager on Linux,
@@ -43,5 +41,4 @@ private:
bool m_available;
};
-#endif /* WITH_INPUT_NDOF */
#endif /* __GHOST_NDOFMANAGERUNIX_H__ */
diff --git a/intern/ghost/intern/GHOST_NDOFManagerWin32.cpp b/intern/ghost/intern/GHOST_NDOFManagerWin32.cpp
index 7ccd2e602b4..0023ee7e1d0 100644
--- a/intern/ghost/intern/GHOST_NDOFManagerWin32.cpp
+++ b/intern/ghost/intern/GHOST_NDOFManagerWin32.cpp
@@ -22,8 +22,6 @@
* ***** END GPL LICENSE BLOCK *****
*/
-#ifdef WITH_INPUT_NDOF // use contents of this file
-
#include "GHOST_NDOFManagerWin32.h"
@@ -40,5 +38,3 @@ bool GHOST_NDOFManagerWin32::available()
// always available since RawInput is built into Windows
return true;
}
-
-#endif // WITH_INPUT_NDOF
diff --git a/intern/ghost/intern/GHOST_NDOFManagerWin32.h b/intern/ghost/intern/GHOST_NDOFManagerWin32.h
index 9b5192817eb..2f7bc9ee732 100644
--- a/intern/ghost/intern/GHOST_NDOFManagerWin32.h
+++ b/intern/ghost/intern/GHOST_NDOFManagerWin32.h
@@ -25,8 +25,6 @@
#ifndef __GHOST_NDOFMANAGERWIN32_H__
#define __GHOST_NDOFMANAGERWIN32_H__
-#ifdef WITH_INPUT_NDOF
-
#include "GHOST_NDOFManager.h"
@@ -37,6 +35,4 @@ public:
bool available();
};
-
-#endif // WITH_INPUT_NDOF
#endif // #include guard
diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp
index 0f5c822f4b6..56d68b98ce0 100644
--- a/intern/ghost/intern/GHOST_System.cpp
+++ b/intern/ghost/intern/GHOST_System.cpp
@@ -38,11 +38,13 @@
#include "GHOST_DisplayManager.h"
#include "GHOST_EventManager.h"
-#include "GHOST_NDOFManager.h"
#include "GHOST_TimerTask.h"
#include "GHOST_TimerManager.h"
#include "GHOST_WindowManager.h"
+#ifdef WITH_INPUT_NDOF
+# include "GHOST_NDOFManager.h"
+#endif
GHOST_System::GHOST_System()
: m_nativePixel(false),
@@ -88,7 +90,7 @@ GHOST_ITimerTask *GHOST_System::installTimer(GHOST_TUns64 delay,
}
else {
delete timer;
- timer = 0;
+ timer = NULL;
}
}
return timer;
@@ -140,7 +142,7 @@ bool GHOST_System::validWindow(GHOST_IWindow *window)
GHOST_TSuccess GHOST_System::beginFullScreen(const GHOST_DisplaySetting& setting, GHOST_IWindow **window,
- const bool stereoVisual, const GHOST_TUns16 numOfAASamples)
+ const bool stereoVisual, const bool alphaBackground, const GHOST_TUns16 numOfAASamples)
{
GHOST_TSuccess success = GHOST_kFailure;
GHOST_ASSERT(m_windowManager, "GHOST_System::beginFullScreen(): invalid window manager");
@@ -152,7 +154,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, setting, stereoVisual, numOfAASamples);
+ success = createFullScreenWindow((GHOST_Window **)window, setting, stereoVisual, alphaBackground, numOfAASamples);
if (success == GHOST_kSuccess) {
m_windowManager->beginFullScreen(*window, stereoVisual);
}
@@ -292,14 +294,12 @@ GHOST_TSuccess GHOST_System::getButtonState(GHOST_TButtonMask mask, bool& isDown
return success;
}
+#ifdef WITH_INPUT_NDOF
void GHOST_System::setNDOFDeadZone(float deadzone)
{
-#ifdef WITH_INPUT_NDOF
this->m_ndofManager->setDeadZone(deadzone);
-#else
- (void)deadzone;
-#endif
}
+#endif
GHOST_TSuccess GHOST_System::init()
{
@@ -328,38 +328,36 @@ GHOST_TSuccess GHOST_System::exit()
if (getFullScreen()) {
endFullScreen();
}
- if (m_displayManager) {
- delete m_displayManager;
- m_displayManager = NULL;
- }
- if (m_windowManager) {
- delete m_windowManager;
- m_windowManager = NULL;
- }
- if (m_timerManager) {
- delete m_timerManager;
- m_timerManager = NULL;
- }
- if (m_eventManager) {
- delete m_eventManager;
- m_eventManager = NULL;
- }
+
+ delete m_displayManager;
+ m_displayManager = NULL;
+
+ delete m_windowManager;
+ m_windowManager = NULL;
+
+ delete m_timerManager;
+ m_timerManager = NULL;
+
+ delete m_eventManager;
+ m_eventManager = NULL;
+
#ifdef WITH_INPUT_NDOF
- if (m_ndofManager) {
- delete m_ndofManager;
- m_ndofManager = 0;
- }
+ delete m_ndofManager;
+ m_ndofManager = NULL;
#endif
+
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window **window, const GHOST_DisplaySetting &settings,
- const bool stereoVisual, const GHOST_TUns16 numOfAASamples)
+ const bool stereoVisual, const bool alphaBackground, const GHOST_TUns16 numOfAASamples)
{
GHOST_GLSettings glSettings = {0};
if (stereoVisual)
glSettings.flags |= GHOST_glStereoVisual;
+ if (alphaBackground)
+ glSettings.flags |= GHOST_glAlphaBackground;
glSettings.numOfAASamples = numOfAASamples;
/* note: don't use getCurrentDisplaySetting() because on X11 we may
diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h
index c4951adb4fd..af083996d91 100644
--- a/intern/ghost/intern/GHOST_System.h
+++ b/intern/ghost/intern/GHOST_System.h
@@ -48,7 +48,9 @@ class GHOST_Event;
class GHOST_TimerManager;
class GHOST_Window;
class GHOST_WindowManager;
+#ifdef WITH_INPUT_NDOF
class GHOST_NDOFManager;
+#endif
/**
* Implementation of platform independent functionality of the GHOST_ISystem
@@ -144,8 +146,8 @@ public:
* \return Indication of success.
*/
GHOST_TSuccess beginFullScreen(const GHOST_DisplaySetting& setting, GHOST_IWindow **window,
- const bool stereoVisual, const GHOST_TUns16 numOfAASamples = 0);
-
+ const bool stereoVisual, const bool alphaBackground, const GHOST_TUns16 numOfAASamples = 0);
+
/**
* Updates the resolution while in fullscreen mode.
* \param setting The new setting of the display.
@@ -236,6 +238,7 @@ public:
*/
GHOST_TSuccess getButtonState(GHOST_TButtonMask mask, bool& isDown) const;
+#ifdef WITH_INPUT_NDOF
/***************************************************************************************
* Access to 3D mouse.
***************************************************************************************/
@@ -245,6 +248,7 @@ public:
* \param deadzone: Deadzone of the 3D mouse (both for rotation and pan) relative to full range
*/
void setNDOFDeadZone(float deadzone);
+#endif
/***************************************************************************************
* Other (internal) functionality.
@@ -336,7 +340,7 @@ protected:
* \return Indication of success.
*/
GHOST_TSuccess createFullScreenWindow(GHOST_Window **window, const GHOST_DisplaySetting &settings,
- const bool stereoVisual, const GHOST_TUns16 numOfAASamples = 0);
+ const bool stereoVisual, const bool alphaBackground = 0, const GHOST_TUns16 numOfAASamples = 0);
/** The display manager (platform dependent). */
GHOST_DisplayManager *m_displayManager;
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm
index bf44d938a47..173f59c9c8f 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.mm
+++ b/intern/ghost/intern/GHOST_SystemCocoa.mm
@@ -90,8 +90,7 @@ static GHOST_TButtonMask convertButton(int button)
* \return Ghost key code
*/
static GHOST_TKey convertKey(int rawCode, unichar recvChar, UInt16 keyAction)
-{
-
+{
//printf("\nrecvchar %c 0x%x",recvChar,recvChar);
switch (rawCode) {
/*Physical keycodes not used due to map changes in int'l keyboards
@@ -121,7 +120,7 @@ static GHOST_TKey convertKey(int rawCode, unichar recvChar, UInt16 keyAction)
case kVK_ANSI_X: return GHOST_kKeyX;
case kVK_ANSI_Y: return GHOST_kKeyY;
case kVK_ANSI_Z: return GHOST_kKeyZ;*/
-
+
/* Numbers keys mapped to handle some int'l keyboard (e.g. French)*/
case kVK_ISO_Section: return GHOST_kKeyUnknown;
case kVK_ANSI_1: return GHOST_kKey1;
@@ -134,7 +133,7 @@ static GHOST_TKey convertKey(int rawCode, unichar recvChar, UInt16 keyAction)
case kVK_ANSI_8: return GHOST_kKey8;
case kVK_ANSI_9: return GHOST_kKey9;
case kVK_ANSI_0: return GHOST_kKey0;
-
+
case kVK_ANSI_Keypad0: return GHOST_kKeyNumpad0;
case kVK_ANSI_Keypad1: return GHOST_kKeyNumpad1;
case kVK_ANSI_Keypad2: return GHOST_kKeyNumpad2;
@@ -173,24 +172,24 @@ static GHOST_TKey convertKey(int rawCode, unichar recvChar, UInt16 keyAction)
case kVK_F18: return GHOST_kKeyF18;
case kVK_F19: return GHOST_kKeyF19;
case kVK_F20: return GHOST_kKeyF20;
-
+
case kVK_UpArrow: return GHOST_kKeyUpArrow;
case kVK_DownArrow: return GHOST_kKeyDownArrow;
case kVK_LeftArrow: return GHOST_kKeyLeftArrow;
case kVK_RightArrow: return GHOST_kKeyRightArrow;
-
+
case kVK_Return: return GHOST_kKeyEnter;
case kVK_Delete: return GHOST_kKeyBackSpace;
case kVK_ForwardDelete: return GHOST_kKeyDelete;
case kVK_Escape: return GHOST_kKeyEsc;
case kVK_Tab: return GHOST_kKeyTab;
case kVK_Space: return GHOST_kKeySpace;
-
+
case kVK_Home: return GHOST_kKeyHome;
case kVK_End: return GHOST_kKeyEnd;
case kVK_PageUp: return GHOST_kKeyUpPage;
case kVK_PageDown: return GHOST_kKeyDownPage;
-
+
/*case kVK_ANSI_Minus: return GHOST_kKeyMinus;
case kVK_ANSI_Equal: return GHOST_kKeyEqual;
case kVK_ANSI_Comma: return GHOST_kKeyComma;
@@ -202,12 +201,12 @@ static GHOST_TKey convertKey(int rawCode, unichar recvChar, UInt16 keyAction)
case kVK_ANSI_LeftBracket: return GHOST_kKeyLeftBracket;
case kVK_ANSI_RightBracket: return GHOST_kKeyRightBracket;
case kVK_ANSI_Grave: return GHOST_kKeyAccentGrave;*/
-
+
case kVK_VolumeUp:
case kVK_VolumeDown:
case kVK_Mute:
return GHOST_kKeyUnknown;
-
+
default:
{
/* alphanumerical or punctuation key that is remappable in int'l keyboards */
@@ -221,11 +220,11 @@ static GHOST_TKey convertKey(int rawCode, unichar recvChar, UInt16 keyAction)
/* Leopard and Snow Leopard 64bit compatible API*/
CFDataRef uchrHandle; /*the keyboard layout*/
TISInputSourceRef kbdTISHandle;
-
+
kbdTISHandle = TISCopyCurrentKeyboardLayoutInputSource();
uchrHandle = (CFDataRef)TISGetInputSourceProperty(kbdTISHandle,kTISPropertyUnicodeKeyLayoutData);
CFRelease(kbdTISHandle);
-
+
/*get actual character value of the "remappable" keys in int'l keyboards,
if keyboard layout is not correctly reported (e.g. some non Apple keyboards in Tiger),
then fallback on using the received charactersIgnoringModifiers */
@@ -235,7 +234,6 @@ static GHOST_TKey convertKey(int rawCode, unichar recvChar, UInt16 keyAction)
UCKeyTranslate((UCKeyboardLayout*)CFDataGetBytePtr(uchrHandle), rawCode, keyAction, 0,
LMGetKbdType(), kUCKeyTranslateNoDeadKeysBit, &deadKeyState, 1, &actualStrLength, &recvChar);
-
}
switch (recvChar) {
@@ -285,10 +283,21 @@ extern "C" int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG])
* CocoaAppDelegate
* ObjC object to capture applicationShouldTerminate, and send quit event
**/
+#if defined(__clang_major__) && __clang_major__ <= 7
+/* FIXME(merwin & Juicyfruit): long-term fix for proper protocol to use
+ * merwin thinks NSApplicationDelegate is the correct protocol here. Has been around since 10.6 so we should be good... what's the problem?
+ * https://developer.apple.com/reference/appkit/nsapplicationdelegate?language=objc
+ */
@interface CocoaAppDelegate : NSObject <NSFileManagerDelegate> {
+#else
+/* for Xcode 8 */
+@interface CocoaAppDelegate : NSObject <NSApplicationDelegate> {
+#endif
+
GHOST_SystemCocoa *systemCocoa;
}
- (void)setSystemCocoa:(GHOST_SystemCocoa *)sysCocoa;
+- (void)applicationDidFinishLaunching:(NSNotification *)aNotification;
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename;
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
- (void)applicationWillTerminate:(NSNotification *)aNotification;
@@ -302,6 +311,15 @@ extern "C" int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG])
systemCocoa = sysCocoa;
}
+- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
+{
+ // raise application to front, convenient when starting from the terminal
+ // and important for launching the animation player. we call this after the
+ // application finishes launching, as doing it earlier can make us end up
+ // with a frontmost window but an inactive application
+ [NSApp activateIgnoringOtherApps:YES];
+}
+
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
{
return systemCocoa->handleOpenDocumentRequest(filename);
@@ -311,7 +329,7 @@ extern "C" int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG])
{
//TODO: implement graceful termination through Cocoa mechanism to avoid session log off to be canceled
//Note that Cmd+Q is already handled by keyhandler
- if (systemCocoa->handleQuitRequest() == GHOST_kExitNow)
+ if (systemCocoa->handleQuitRequest() == GHOST_kExitNow)
return NSTerminateCancel;//NSTerminateNow;
else
return NSTerminateCancel;
@@ -346,7 +364,7 @@ GHOST_SystemCocoa::GHOST_SystemCocoa()
struct timeval boottime;
size_t len;
char *rstring = NULL;
-
+
m_modifierMask =0;
m_cursorDelta_x=0;
m_cursorDelta_y=0;
@@ -360,20 +378,20 @@ GHOST_SystemCocoa::GHOST_SystemCocoa()
mib[0] = CTL_KERN;
mib[1] = KERN_BOOTTIME;
len = sizeof(struct timeval);
-
+
sysctl(mib, 2, &boottime, &len, NULL, 0);
m_start_time = ((boottime.tv_sec*1000)+(boottime.tv_usec/1000));
-
+
//Detect multitouch trackpad
mib[0] = CTL_HW;
mib[1] = HW_MODEL;
sysctl( mib, 2, NULL, &len, NULL, 0 );
rstring = (char*)malloc( len );
sysctl( mib, 2, rstring, &len, NULL, 0 );
-
+
free( rstring );
rstring = NULL;
-
+
m_ignoreWindowSizedMessages = false;
m_ignoreMomentumScroll = false;
m_multiTouchScroll = false;
@@ -394,79 +412,78 @@ GHOST_TSuccess GHOST_SystemCocoa::init()
#endif
//ProcessSerialNumber psn;
-
+
//Carbon stuff to move window & menu to foreground
/*if (!GetCurrentProcess(&psn)) {
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
SetFrontProcess(&psn);
}*/
-
+
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- if (NSApp == nil) {
- [NSApplication sharedApplication];
-
- if ([NSApp mainMenu] == nil) {
- NSMenu *mainMenubar = [[NSMenu alloc] init];
- NSMenuItem *menuItem;
- NSMenu *windowMenu;
- NSMenu *appMenu;
-
- //Create the application menu
- appMenu = [[NSMenu alloc] initWithTitle:@"Blender"];
-
- [appMenu addItemWithTitle:@"About Blender" action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
- [appMenu addItem:[NSMenuItem separatorItem]];
-
- menuItem = [appMenu addItemWithTitle:@"Hide Blender" action:@selector(hide:) keyEquivalent:@"h"];
- [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
-
- menuItem = [appMenu addItemWithTitle:@"Hide others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
- [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask | NSCommandKeyMask)];
-
- [appMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
-
- menuItem = [appMenu addItemWithTitle:@"Quit Blender" action:@selector(terminate:) keyEquivalent:@"q"];
- [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
-
- menuItem = [[NSMenuItem alloc] init];
- [menuItem setSubmenu:appMenu];
-
- [mainMenubar addItem:menuItem];
- [menuItem release];
- [NSApp performSelector:@selector(setAppleMenu:) withObject:appMenu]; //Needed for 10.5
- [appMenu release];
-
- //Create the window menu
- windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
-
- menuItem = [windowMenu addItemWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
- [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
-
- [windowMenu addItemWithTitle:@"Zoom" action:@selector(performZoom:) keyEquivalent:@""];
-
- menuItem = [windowMenu addItemWithTitle:@"Enter Full Screen" action:@selector(toggleFullScreen:) keyEquivalent:@"f" ];
- [menuItem setKeyEquivalentModifierMask:NSControlKeyMask | NSCommandKeyMask];
-
- menuItem = [windowMenu addItemWithTitle:@"Close" action:@selector(performClose:) keyEquivalent:@"w"];
- [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
-
- menuItem = [[NSMenuItem alloc] init];
- [menuItem setSubmenu:windowMenu];
-
- [mainMenubar addItem:menuItem];
- [menuItem release];
-
- [NSApp setMainMenu:mainMenubar];
- [NSApp setWindowsMenu:windowMenu];
- [windowMenu release];
- }
+ [NSApplication sharedApplication]; // initializes NSApp
+
+ if ([NSApp mainMenu] == nil) {
+ NSMenu *mainMenubar = [[NSMenu alloc] init];
+ NSMenuItem *menuItem;
+ NSMenu *windowMenu;
+ NSMenu *appMenu;
+
+ //Create the application menu
+ appMenu = [[NSMenu alloc] initWithTitle:@"Blender"];
+
+ [appMenu addItemWithTitle:@"About Blender" action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
+ [appMenu addItem:[NSMenuItem separatorItem]];
+
+ menuItem = [appMenu addItemWithTitle:@"Hide Blender" action:@selector(hide:) keyEquivalent:@"h"];
+ [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
+
+ menuItem = [appMenu addItemWithTitle:@"Hide others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
+ [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask | NSCommandKeyMask)];
+
+ [appMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
+
+ menuItem = [appMenu addItemWithTitle:@"Quit Blender" action:@selector(terminate:) keyEquivalent:@"q"];
+ [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
+
+ menuItem = [[NSMenuItem alloc] init];
+ [menuItem setSubmenu:appMenu];
+
+ [mainMenubar addItem:menuItem];
+ [menuItem release];
+ [NSApp performSelector:@selector(setAppleMenu:) withObject:appMenu]; //Needed for 10.5
+ [appMenu release];
+
+ //Create the window menu
+ windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
+
+ menuItem = [windowMenu addItemWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
+ [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
+
+ [windowMenu addItemWithTitle:@"Zoom" action:@selector(performZoom:) keyEquivalent:@""];
+
+ menuItem = [windowMenu addItemWithTitle:@"Enter Full Screen" action:@selector(toggleFullScreen:) keyEquivalent:@"f" ];
+ [menuItem setKeyEquivalentModifierMask:NSControlKeyMask | NSCommandKeyMask];
+
+ menuItem = [windowMenu addItemWithTitle:@"Close" action:@selector(performClose:) keyEquivalent:@"w"];
+ [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
+
+ menuItem = [[NSMenuItem alloc] init];
+ [menuItem setSubmenu:windowMenu];
+
+ [mainMenubar addItem:menuItem];
+ [menuItem release];
+
+ [NSApp setMainMenu:mainMenubar];
+ [NSApp setWindowsMenu:windowMenu];
+ [windowMenu release];
}
+
if ([NSApp delegate] == nil) {
CocoaAppDelegate *appDelegate = [[CocoaAppDelegate alloc] init];
[appDelegate setSystemCocoa:this];
[NSApp setDelegate:appDelegate];
}
-
+
[NSApp finishLaunching];
[pool drain];
@@ -481,11 +498,11 @@ GHOST_TUns64 GHOST_SystemCocoa::getMilliSeconds() const
{
//Cocoa equivalent exists in 10.6 ([[NSProcessInfo processInfo] systemUptime])
struct timeval currentTime;
-
+
gettimeofday(&currentTime, NULL);
-
+
//Return timestamp of system uptime
-
+
return ((currentTime.tv_sec*1000)+(currentTime.tv_usec/1000)-m_start_time);
}
@@ -508,11 +525,11 @@ void GHOST_SystemCocoa::getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//Get visible frame, that is frame excluding dock and top menu bar
NSRect frame = [[NSScreen mainScreen] visibleFrame];
-
+
//Returns max window contents (excluding title bar...)
NSRect contentRect = [NSWindow contentRectForFrameRect:frame
styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask)];
-
+
width = contentRect.size.width;
height = contentRect.size.height;
@@ -539,13 +556,13 @@ GHOST_IWindow* GHOST_SystemCocoa::createWindow(
)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- GHOST_IWindow* window = 0;
-
+ GHOST_IWindow* window = NULL;
+
//Get the available rect for including window contents
NSRect frame = [[NSScreen mainScreen] visibleFrame];
NSRect contentRect = [NSWindow contentRectForFrameRect:frame
styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask)];
-
+
GHOST_TInt32 bottom = (contentRect.size.height - 1) - height - top;
//Ensures window top left is inside this available rect
@@ -553,7 +570,7 @@ GHOST_IWindow* GHOST_SystemCocoa::createWindow(
// Add contentRect.origin.y to respect docksize
bottom = bottom > contentRect.origin.y ? bottom + contentRect.origin.y : contentRect.origin.y;
- window = new GHOST_WindowCocoa (this, title, left, bottom, width, height, state, type, ((glSettings.flags & GHOST_glStereoVisual) != 0), glSettings.numOfAASamples);
+ window = new GHOST_WindowCocoa(this, title, left, bottom, width, height, state, type, glSettings.flags & GHOST_glStereoVisual, glSettings.numOfAASamples, glSettings.flags & GHOST_glDebugContext);
if (window->getValid()) {
// Store the pointer to the window
@@ -567,9 +584,9 @@ GHOST_IWindow* GHOST_SystemCocoa::createWindow(
else {
GHOST_PRINT("GHOST_SystemCocoa::createWindow(): window invalid\n");
delete window;
- window = 0;
+ window = NULL;
}
-
+
[pool drain];
return window;
}
@@ -580,7 +597,7 @@ GHOST_IWindow* GHOST_SystemCocoa::createWindow(
GHOST_TSuccess GHOST_SystemCocoa::getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const
{
NSPoint mouseLoc = [NSEvent mouseLocation];
-
+
// Returns the mouse location in screen coordinates
x = (GHOST_TInt32)mouseLoc.x;
y = (GHOST_TInt32)mouseLoc.y;
@@ -600,11 +617,11 @@ GHOST_TSuccess GHOST_SystemCocoa::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32
CGAssociateMouseAndMouseCursorPosition(false);
setMouseCursorPosition(x, y);
CGAssociateMouseAndMouseCursorPosition(true);
-
+
//Force mouse move event (not pushed by Cocoa)
pushEvent(new GHOST_EventCursor(getMilliSeconds(), GHOST_kEventCursorMove, window, x, y));
m_outsideLoopEventProcessed = true;
-
+
return GHOST_kSuccess;
}
@@ -617,11 +634,11 @@ GHOST_TSuccess GHOST_SystemCocoa::setMouseCursorPosition(GHOST_TInt32 x, GHOST_T
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSScreen *windowScreen = window->getScreen();
NSRect screenRect = [windowScreen frame];
-
+
//Set position relative to current screen
xf -= screenRect.origin.x;
yf -= screenRect.origin.y;
-
+
//Quartz Display Services uses the old coordinates (top left origin)
yf = screenRect.size.height -yf;
@@ -638,7 +655,7 @@ GHOST_TSuccess GHOST_SystemCocoa::getModifierKeys(GHOST_ModifierKeys& keys) cons
keys.set(GHOST_kModifierKeyLeftAlt, (m_modifierMask & NSAlternateKeyMask) ? true : false);
keys.set(GHOST_kModifierKeyLeftShift, (m_modifierMask & NSShiftKeyMask) ? true : false);
keys.set(GHOST_kModifierKeyLeftControl, (m_modifierMask & NSControlKeyMask) ? true : false);
-
+
return GHOST_kSuccess;
}
@@ -665,13 +682,13 @@ bool GHOST_SystemCocoa::processEvents(bool waitForEvent)
{
bool anyProcessed = false;
NSEvent *event;
-
+
// SetMouseCoalescingEnabled(false, NULL);
//TODO : implement timer ??
#if 0
do {
GHOST_TimerManager* timerMgr = getTimerManager();
-
+
if (waitForEvent) {
GHOST_TUns64 next = timerMgr->nextFireTime();
double timeOut;
@@ -692,20 +709,19 @@ bool GHOST_SystemCocoa::processEvents(bool waitForEvent)
anyProcessed = true;
}
#endif
-
do {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
event = [NSApp nextEventMatchingMask:NSAnyEventMask
- untilDate:[NSDate distantPast]
- inMode:NSDefaultRunLoopMode
- dequeue:YES];
+ untilDate:[NSDate distantPast]
+ inMode:NSDefaultRunLoopMode
+ dequeue:YES];
if (event==nil) {
[pool drain];
break;
}
-
+
anyProcessed = true;
-
+
// Send event to NSApp to ensure Mac wide events are handled,
// this will send events to CocoaWindow which will call back
// to handleKeyEvent, handleMouseEvent and handleTabletEvent
@@ -734,16 +750,16 @@ bool GHOST_SystemCocoa::processEvents(bool waitForEvent)
#if 0
} while (waitForEvent && !anyProcessed); // Needed only for timer implementation
#endif
-
+
if (m_needDelayedApplicationBecomeActiveEventProcessing) handleApplicationBecomeActiveEvent();
-
+
if (m_outsideLoopEventProcessed) {
m_outsideLoopEventProcessed = false;
return true;
}
-
+
m_ignoreWindowSizedMessages = false;
-
+
return anyProcessed;
}
@@ -754,7 +770,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleApplicationBecomeActiveEvent()
//(that is when update events are sent to another application)
unsigned int modifiers;
GHOST_IWindow* window = m_windowManager->getActiveWindow();
-
+
if (!window) {
m_needDelayedApplicationBecomeActiveEventProcessing = true;
return GHOST_kFailure;
@@ -762,7 +778,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleApplicationBecomeActiveEvent()
else m_needDelayedApplicationBecomeActiveEventProcessing = false;
modifiers = [[[NSApplication sharedApplication] currentEvent] modifierFlags];
-
+
if ((modifiers & NSShiftKeyMask) != (m_modifierMask & NSShiftKeyMask)) {
pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & NSShiftKeyMask) ? GHOST_kEventKeyDown : GHOST_kEventKeyUp, window, GHOST_kKeyLeftShift));
}
@@ -775,9 +791,9 @@ GHOST_TSuccess GHOST_SystemCocoa::handleApplicationBecomeActiveEvent()
if ((modifiers & NSCommandKeyMask) != (m_modifierMask & NSCommandKeyMask)) {
pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & NSCommandKeyMask) ? GHOST_kEventKeyDown : GHOST_kEventKeyUp, window, GHOST_kKeyOS));
}
-
+
m_modifierMask = modifiers;
-
+
m_outsideLoopEventProcessed = true;
return GHOST_kSuccess;
}
@@ -830,7 +846,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(GHOST_TEventType eventType,
window->updateDrawingContext();
pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window) );
//Mouse up event is trapped by the resizing event loop, so send it anyway to the window manager
- pushEvent(new GHOST_EventButton(getMilliSeconds(), GHOST_kEventButtonUp, window, convertButton(0)));
+ pushEvent(new GHOST_EventButton(getMilliSeconds(), GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft));
//m_ignoreWindowSizedMessages = true;
}
break;
@@ -852,7 +868,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(GHOST_TEventType eventType,
//Note: called from NSWindow subclass
GHOST_TSuccess GHOST_SystemCocoa::handleDraggingEvent(GHOST_TEventType eventType, GHOST_TDragnDropTypes draggedObjectType,
- GHOST_WindowCocoa* window, int mouseX, int mouseY, void* data)
+ GHOST_WindowCocoa* window, int mouseX, int mouseY, void* data)
{
if (!validWindow(window)) {
return GHOST_kFailure;
@@ -863,7 +879,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleDraggingEvent(GHOST_TEventType eventType
case GHOST_kEventDraggingExited:
pushEvent(new GHOST_EventDragnDrop(getMilliSeconds(),eventType,draggedObjectType,window,mouseX,mouseY,NULL));
break;
-
+
case GHOST_kEventDraggingDropDone:
{
GHOST_TUns8 * temp_buff;
@@ -875,60 +891,60 @@ GHOST_TSuccess GHOST_SystemCocoa::handleDraggingEvent(GHOST_TEventType eventType
int i;
if (!data) return GHOST_kFailure;
-
+
switch (draggedObjectType) {
case GHOST_kDragnDropTypeFilenames:
droppedArray = (NSArray*)data;
-
+
strArray = (GHOST_TStringArray*)malloc(sizeof(GHOST_TStringArray));
if (!strArray) return GHOST_kFailure;
-
+
strArray->count = [droppedArray count];
if (strArray->count == 0) {
free(strArray);
return GHOST_kFailure;
}
-
+
strArray->strings = (GHOST_TUns8**) malloc(strArray->count*sizeof(GHOST_TUns8*));
-
+
for (i=0;i<strArray->count;i++)
{
droppedStr = [droppedArray objectAtIndex:i];
-
+
pastedTextSize = [droppedStr lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
temp_buff = (GHOST_TUns8*) malloc(pastedTextSize+1);
-
+
if (!temp_buff) {
strArray->count = i;
break;
}
-
+
strncpy((char*)temp_buff, [droppedStr cStringUsingEncoding:NSUTF8StringEncoding], pastedTextSize);
temp_buff[pastedTextSize] = '\0';
-
+
strArray->strings[i] = temp_buff;
}
eventData = (GHOST_TEventDataPtr) strArray;
break;
-
+
case GHOST_kDragnDropTypeString:
droppedStr = (NSString*)data;
pastedTextSize = [droppedStr lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
-
+
temp_buff = (GHOST_TUns8*) malloc(pastedTextSize+1);
-
+
if (temp_buff == NULL) {
return GHOST_kFailure;
}
-
+
strncpy((char*)temp_buff, [droppedStr cStringUsingEncoding:NSUTF8StringEncoding], pastedTextSize);
-
+
temp_buff[pastedTextSize] = '\0';
-
+
eventData = (GHOST_TEventDataPtr) temp_buff;
break;
-
+
case GHOST_kDragnDropTypeBitmap:
{
NSImage *droppedImg = (NSImage*)data;
@@ -941,13 +957,13 @@ GHOST_TSuccess GHOST_SystemCocoa::handleDraggingEvent(GHOST_TEventType eventType
NSBitmapImageRep *blBitmapFormatImageRGB,*blBitmapFormatImageRGBA,*bitmapImage=nil;
NSEnumerator *enumerator;
NSImageRep *representation;
-
+
ibuf = IMB_allocImBuf (imgSize.width, imgSize.height, 32, IB_rect);
if (!ibuf) {
[droppedImg release];
return GHOST_kFailure;
}
-
+
/*Get the bitmap of the image*/
enumerator = [[droppedImg representations] objectEnumerator];
while ((representation = [enumerator nextObject])) {
@@ -957,7 +973,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleDraggingEvent(GHOST_TEventType eventType
}
}
if (bitmapImage == nil) return GHOST_kFailure;
-
+
if (([bitmapImage bitsPerPixel] == 32) && (([bitmapImage bitmapFormat] & 0x5) == 0)
&& ![bitmapImage isPlanar]) {
/* Try a fast copy if the image is a meshed RGBA 32bit bitmap*/
@@ -972,26 +988,26 @@ GHOST_TSuccess GHOST_SystemCocoa::handleDraggingEvent(GHOST_TEventType eventType
else {
/* Tell cocoa image resolution is same as current system one */
[bitmapImage setSize:imgSize];
-
+
/* Convert the image in a RGBA 32bit format */
/* As Core Graphics does not support contextes with non premutliplied alpha,
we need to get alpha key values in a separate batch */
-
+
/* First get RGB values w/o Alpha to avoid pre-multiplication, 32bit but last byte is unused */
blBitmapFormatImageRGB = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
- pixelsWide:imgSize.width
- pixelsHigh:imgSize.height
- bitsPerSample:8 samplesPerPixel:3 hasAlpha:NO isPlanar:NO
- colorSpaceName:NSDeviceRGBColorSpace
- bitmapFormat:(NSBitmapFormat)0
- bytesPerRow:4*imgSize.width
- bitsPerPixel:32/*RGB format padded to 32bits*/];
-
+ pixelsWide:imgSize.width
+ pixelsHigh:imgSize.height
+ bitsPerSample:8 samplesPerPixel:3 hasAlpha:NO isPlanar:NO
+ colorSpaceName:NSDeviceRGBColorSpace
+ bitmapFormat:(NSBitmapFormat)0
+ bytesPerRow:4*imgSize.width
+ bitsPerPixel:32/*RGB format padded to 32bits*/];
+
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:blBitmapFormatImageRGB]];
[bitmapImage draw];
[NSGraphicsContext restoreGraphicsState];
-
+
rasterRGB = (GHOST_TUns8*)[blBitmapFormatImageRGB bitmapData];
if (rasterRGB == NULL) {
[bitmapImage release];
@@ -999,22 +1015,22 @@ GHOST_TSuccess GHOST_SystemCocoa::handleDraggingEvent(GHOST_TEventType eventType
[droppedImg release];
return GHOST_kFailure;
}
-
+
/* Then get Alpha values by getting the RGBA image (that is premultiplied btw) */
blBitmapFormatImageRGBA = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
- pixelsWide:imgSize.width
- pixelsHigh:imgSize.height
- bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO
- colorSpaceName:NSDeviceRGBColorSpace
- bitmapFormat:(NSBitmapFormat)0
- bytesPerRow:4*imgSize.width
- bitsPerPixel:32/* RGBA */];
-
+ pixelsWide:imgSize.width
+ pixelsHigh:imgSize.height
+ bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO
+ colorSpaceName:NSDeviceRGBColorSpace
+ bitmapFormat:(NSBitmapFormat)0
+ bytesPerRow:4*imgSize.width
+ bitsPerPixel:32/* RGBA */];
+
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:blBitmapFormatImageRGBA]];
[bitmapImage draw];
[NSGraphicsContext restoreGraphicsState];
-
+
rasterRGBA = (GHOST_TUns8*)[blBitmapFormatImageRGBA bitmapData];
if (rasterRGBA == NULL) {
[bitmapImage release];
@@ -1023,26 +1039,26 @@ GHOST_TSuccess GHOST_SystemCocoa::handleDraggingEvent(GHOST_TEventType eventType
[droppedImg release];
return GHOST_kFailure;
}
-
+
/*Copy the image to ibuf, flipping it vertically*/
toIBuf = (GHOST_TUns8*)ibuf->rect;
for (y = 0; y < imgSize.height; y++) {
for (x = 0; x < imgSize.width; x++) {
to_i = (imgSize.height-y-1)*imgSize.width + x;
from_i = y*imgSize.width + x;
-
+
toIBuf[4*to_i] = rasterRGB[4*from_i]; /* R */
toIBuf[4*to_i+1] = rasterRGB[4*from_i+1]; /* G */
toIBuf[4*to_i+2] = rasterRGB[4*from_i+2]; /* B */
toIBuf[4*to_i+3] = rasterRGBA[4*from_i+3]; /* A */
}
}
-
+
[blBitmapFormatImageRGB release];
[blBitmapFormatImageRGBA release];
[droppedImg release];
}
-
+
eventData = (GHOST_TEventDataPtr) ibuf;
break;
@@ -1066,11 +1082,11 @@ GHOST_TSuccess GHOST_SystemCocoa::handleDraggingEvent(GHOST_TEventType eventType
GHOST_TUns8 GHOST_SystemCocoa::handleQuitRequest()
{
GHOST_Window* window = (GHOST_Window*)m_windowManager->getActiveWindow();
-
+
//Discard quit event if we are in cursor grab sequence
if (window && window->getCursorGrabModeIsWarp())
return GHOST_kExitCancel;
-
+
//Check open windows if some changes are not saved
if (m_windowManager->getAnyModifiedState())
{
@@ -1093,14 +1109,13 @@ GHOST_TUns8 GHOST_SystemCocoa::handleQuitRequest()
handleApplicationBecomeActiveEvent();
}
}
-
}
else {
pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventQuit, NULL) );
m_outsideLoopEventProcessed = true;
return GHOST_kExitNow;
}
-
+
return GHOST_kExitCancel;
}
@@ -1112,11 +1127,11 @@ bool GHOST_SystemCocoa::handleOpenDocumentRequest(void *filepathStr)
char * temp_buff;
size_t filenameTextSize;
GHOST_Window* window= (GHOST_Window*)m_windowManager->getActiveWindow();
-
+
if (!window) {
return NO;
}
-
+
//Discard event if we are in cursor grab sequence, it'll lead to "stuck cursor" situation if the alert panel is raised
if (window && window->getCursorGrabModeIsWarp())
return GHOST_kExitCancel;
@@ -1125,8 +1140,8 @@ bool GHOST_SystemCocoa::handleOpenDocumentRequest(void *filepathStr)
if (m_windowManager->getAnyModifiedState())
{
confirmOpen = NSRunAlertPanel([NSString stringWithFormat:@"Opening %@",[filepath lastPathComponent]],
- @"Current document has not been saved.\nDo you really want to proceed?",
- @"Cancel", @"Open", nil);
+ @"Current document has not been saved.\nDo you really want to proceed?",
+ @"Cancel", @"Open", nil);
}
//Give back focus to the blender window
@@ -1138,15 +1153,15 @@ bool GHOST_SystemCocoa::handleOpenDocumentRequest(void *filepathStr)
if (confirmOpen == NSAlertAlternateReturn)
{
filenameTextSize = [filepath lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
-
+
temp_buff = (char*) malloc(filenameTextSize+1);
-
+
if (temp_buff == NULL) {
return GHOST_kFailure;
}
-
+
strncpy(temp_buff, [filepath cStringUsingEncoding:NSUTF8StringEncoding], filenameTextSize);
-
+
temp_buff[filenameTextSize] = '\0';
pushEvent(new GHOST_EventString(getMilliSeconds(),GHOST_kEventOpenMainFile,window,(GHOST_TEventDataPtr) temp_buff));
@@ -1160,15 +1175,15 @@ GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr, short eventT
{
NSEvent *event = (NSEvent *)eventPtr;
GHOST_IWindow* window;
-
+
window = m_windowManager->getWindowAssociatedWithOSWindow((void*)[event window]);
if (!window) {
//printf("\nW failure for event 0x%x",[event type]);
return GHOST_kFailure;
}
-
+
GHOST_TabletData& ct=((GHOST_WindowCocoa*)window)->GetCocoaTabletData();
-
+
switch (eventType) {
case NSTabletPoint:
// workaround 2 cornercases:
@@ -1181,7 +1196,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr, short eventT
ct.Xtilt = [event tilt].x;
ct.Ytilt = [event tilt].y;
break;
-
+
case NSTabletProximity:
ct.Pressure = 0;
ct.Xtilt = 0;
@@ -1232,7 +1247,6 @@ bool GHOST_SystemCocoa::handleTabletEvent(void *eventPtr)
//No tablet event included : do nothing
return false;
}
-
}
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1070
@@ -1261,7 +1275,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
NSEvent *event = (NSEvent *)eventPtr;
GHOST_WindowCocoa* window;
CocoaWindow *cocoawindow;
-
+
/* [event window] returns other windows if mouse-over, that's OSX input standard
however, if mouse exits window(s), the windows become inactive, until you click.
We then fall back to the active window from ghost */
@@ -1275,30 +1289,40 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
}
cocoawindow = (CocoaWindow *)window->getOSWindow();
-
+
switch ([event type]) {
case NSLeftMouseDown:
+ pushEvent(new GHOST_EventButton([event timestamp] * 1000, GHOST_kEventButtonDown, window, GHOST_kButtonMaskLeft));
+ handleTabletEvent(event); //Handle tablet events combined with mouse events
+ break;
case NSRightMouseDown:
+ pushEvent(new GHOST_EventButton([event timestamp] * 1000, GHOST_kEventButtonDown, window, GHOST_kButtonMaskRight));
+ handleTabletEvent(event); //Handle tablet events combined with mouse events
+ break;
case NSOtherMouseDown:
pushEvent(new GHOST_EventButton([event timestamp] * 1000, GHOST_kEventButtonDown, window, convertButton([event buttonNumber])));
- //Handle tablet events combined with mouse events
- handleTabletEvent(event);
+ handleTabletEvent(event); //Handle tablet events combined with mouse events
break;
case NSLeftMouseUp:
+ pushEvent(new GHOST_EventButton([event timestamp] * 1000, GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft));
+ handleTabletEvent(event); //Handle tablet events combined with mouse events
+ break;
case NSRightMouseUp:
+ pushEvent(new GHOST_EventButton([event timestamp] * 1000, GHOST_kEventButtonUp, window, GHOST_kButtonMaskRight));
+ handleTabletEvent(event); //Handle tablet events combined with mouse events
+ break;
case NSOtherMouseUp:
pushEvent(new GHOST_EventButton([event timestamp] * 1000, GHOST_kEventButtonUp, window, convertButton([event buttonNumber])));
- //Handle tablet events combined with mouse events
- handleTabletEvent(event);
+ handleTabletEvent(event); //Handle tablet events combined with mouse events
break;
-
+
case NSLeftMouseDragged:
case NSRightMouseDragged:
case NSOtherMouseDragged:
//Handle tablet events combined with mouse events
handleTabletEvent(event);
-
+
case NSMouseMoved:
{
GHOST_TGrabCursorMode grab_mode = window->getCursorGrabMode();
@@ -1314,15 +1338,15 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
case GHOST_kGrabHide: //Cursor hidden grab operation : no cursor move
{
GHOST_TInt32 x_warp, y_warp, x_accum, y_accum, x, y;
-
+
window->getCursorGrabInitPos(x_warp, y_warp);
window->screenToClientIntern(x_warp, y_warp, x_warp, y_warp);
-
+
window->getCursorGrabAccum(x_accum, y_accum);
x_accum += [event deltaX];
y_accum += -[event deltaY]; //Strange Apple implementation (inverted coordinates for the deltaY) ...
window->setCursorGrabAccum(x_accum, y_accum);
-
+
window->clientToScreenIntern(x_warp+x_accum, y_warp+y_accum, x, y);
pushEvent(new GHOST_EventCursor([event timestamp] * 1000, GHOST_kEventCursorMove, window, x, y));
break;
@@ -1334,38 +1358,37 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
GHOST_TInt32 y_mouse= mousePos.y;
GHOST_TInt32 x_accum, y_accum, x_cur, y_cur, x, y;
GHOST_Rect bounds, windowBounds, correctedBounds;
-
+
/* fallback to window bounds */
if (window->getCursorGrabBounds(bounds) == GHOST_kFailure)
window->getClientBounds(bounds);
-
+
//Switch back to Cocoa coordinates orientation (y=0 at botton,the same as blender internal btw!), and to client coordinates
window->getClientBounds(windowBounds);
window->screenToClient(bounds.m_l, bounds.m_b, correctedBounds.m_l, correctedBounds.m_t);
window->screenToClient(bounds.m_r, bounds.m_t, correctedBounds.m_r, correctedBounds.m_b);
correctedBounds.m_b = (windowBounds.m_b - windowBounds.m_t) - correctedBounds.m_b;
correctedBounds.m_t = (windowBounds.m_b - windowBounds.m_t) - correctedBounds.m_t;
-
+
//Update accumulation counts
window->getCursorGrabAccum(x_accum, y_accum);
x_accum += [event deltaX]-m_cursorDelta_x;
y_accum += -[event deltaY]-m_cursorDelta_y; //Strange Apple implementation (inverted coordinates for the deltaY) ...
window->setCursorGrabAccum(x_accum, y_accum);
-
-
+
//Warp mouse cursor if needed
x_mouse += [event deltaX]-m_cursorDelta_x;
y_mouse += -[event deltaY]-m_cursorDelta_y;
correctedBounds.wrapPoint(x_mouse, y_mouse, 2);
-
+
//Compensate for mouse moved event taking cursor position set into account
m_cursorDelta_x = x_mouse-mousePos.x;
m_cursorDelta_y = y_mouse-mousePos.y;
-
+
//Set new cursor position
window->clientToScreenIntern(x_mouse, y_mouse, x_cur, y_cur);
setMouseCursorPosition(x_cur, y_cur); /* wrap */
-
+
//Post event
window->getCursorGrabInitPos(x_cur, y_cur);
window->screenToClientIntern(x_cur, y_cur, x_cur, y_cur);
@@ -1378,7 +1401,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
//Normal cursor operation: send mouse position in window
NSPoint mousePos = [cocoawindow mouseLocationOutsideOfEventStream];
GHOST_TInt32 x, y;
-
+
window->clientToScreenIntern(mousePos.x, mousePos.y, x, y);
pushEvent(new GHOST_EventCursor([event timestamp] * 1000, GHOST_kEventCursorMove, window, x, y));
@@ -1394,7 +1417,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
{
NSEventPhase momentumPhase = NSEventPhaseNone;
NSEventPhase phase = NSEventPhaseNone;
-
+
if ([event respondsToSelector:@selector(momentumPhase)])
momentumPhase = [event momentumPhase];
if ([event respondsToSelector:@selector(phase)])
@@ -1423,12 +1446,12 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
/* standard scrollwheel case, if no swiping happened, and no momentum (kinetic scroll) works */
if (!m_multiTouchScroll && momentumPhase == NSEventPhaseNone) {
GHOST_TInt32 delta;
-
+
double deltaF = [event deltaY];
if (deltaF == 0.0) deltaF = [event deltaX]; // make blender decide if it's horizontal scroll
if (deltaF == 0.0) break; //discard trackpad delta=0 events
-
+
delta = deltaF > 0.0 ? 1 : -1;
pushEvent(new GHOST_EventWheel([event timestamp] * 1000, window, delta));
}
@@ -1442,34 +1465,33 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
/* with 10.7 nice scrolling deltas are supported */
dx = [event scrollingDeltaX];
dy = [event scrollingDeltaY];
-
+
/* however, wacom tablet (intuos5) needs old deltas, it then has momentum and phase at zero */
if (phase == NSEventPhaseNone && momentumPhase == NSEventPhaseNone) {
dx = [event deltaX];
dy = [event deltaY];
}
-
#else
/* trying to pretend you have nice scrolls... */
dx = [event deltaX];
dy = -[event deltaY];
const double deltaMax = 50.0;
-
+
if ((dx == 0) && (dy == 0)) break;
-
+
/* Quadratic acceleration */
dx = dx*(fabs(dx) + 0.5);
if (dx < 0.0) dx -= 0.5;
else dx += 0.5;
if (dx < -deltaMax) dx = -deltaMax;
else if (dx > deltaMax) dx = deltaMax;
-
+
dy = dy*(fabs(dy) + 0.5);
if (dy < 0.0) dy -= 0.5;
else dy += 0.5;
if (dy < -deltaMax) dy= -deltaMax;
else if (dy > deltaMax) dy= deltaMax;
-
+
dy = -dy;
#endif
window->clientToScreenIntern(mousePos.x, mousePos.y, x, y);
@@ -1478,7 +1500,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
}
}
break;
-
+
case NSEventTypeMagnify:
{
NSPoint mousePos = [cocoawindow mouseLocationOutsideOfEventStream];
@@ -1495,13 +1517,13 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
GHOST_TInt32 x, y;
window->clientToScreenIntern(mousePos.x, mousePos.y, x, y);
pushEvent(new GHOST_EventTrackpad([event timestamp] * 1000, window, GHOST_kTrackpadEventRotate, x, y,
- -[event rotation] * 5.0, 0));
+ [event rotation] * 5.0, 0));
}
default:
return GHOST_kFailure;
break;
}
-
+
return GHOST_kSuccess;
}
@@ -1525,7 +1547,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
char utf8_buf[6]= {'\0'};
ascii = 0;
-
+
switch ([event type]) {
case NSKeyDown:
@@ -1533,19 +1555,19 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
charsIgnoringModifiers = [event charactersIgnoringModifiers];
if ([charsIgnoringModifiers length] > 0) {
keyCode = convertKey([event keyCode],
- [charsIgnoringModifiers characterAtIndex:0],
- [event type] == NSKeyDown?kUCKeyActionDown:kUCKeyActionUp);
+ [charsIgnoringModifiers characterAtIndex:0],
+ [event type] == NSKeyDown?kUCKeyActionDown:kUCKeyActionUp);
}
else {
keyCode = convertKey([event keyCode],0,
- [event type] == NSKeyDown?kUCKeyActionDown:kUCKeyActionUp);
+ [event type] == NSKeyDown?kUCKeyActionDown:kUCKeyActionUp);
}
/* handling both unicode or ascii */
characters = [event characters];
if ([characters length] > 0) {
convertedCharacters = [characters dataUsingEncoding:NSUTF8StringEncoding];
-
+
for (int x = 0; x < [convertedCharacters length]; x++) {
utf8_buf[x] = ((char*)[convertedCharacters bytes])[x];
}
@@ -1572,16 +1594,16 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
}
if ([event type] == NSKeyDown) {
- pushEvent( new GHOST_EventKey([event timestamp] * 1000, GHOST_kEventKeyDown, window, keyCode, ascii, utf8_buf) );
+ pushEvent(new GHOST_EventKey([event timestamp] * 1000, GHOST_kEventKeyDown, window, keyCode, ascii, utf8_buf));
//printf("Key down rawCode=0x%x charsIgnoringModifiers=%c keyCode=%u ascii=%i %c utf8=%s\n",[event keyCode],[charsIgnoringModifiers length]>0?[charsIgnoringModifiers characterAtIndex:0]:' ',keyCode,ascii,ascii, utf8_buf);
}
else {
- pushEvent( new GHOST_EventKey([event timestamp] * 1000, GHOST_kEventKeyUp, window, keyCode, 0, NULL) );
+ pushEvent(new GHOST_EventKey([event timestamp] * 1000, GHOST_kEventKeyUp, window, keyCode, 0, NULL));
//printf("Key up rawCode=0x%x charsIgnoringModifiers=%c keyCode=%u ascii=%i %c utf8=%s\n",[event keyCode],[charsIgnoringModifiers length]>0?[charsIgnoringModifiers characterAtIndex:0]:' ',keyCode,ascii,ascii, utf8_buf);
}
m_ignoreMomentumScroll = true;
break;
-
+
case NSFlagsChanged:
modifiers = [event modifierFlags];
@@ -1597,16 +1619,16 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
if ((modifiers & NSCommandKeyMask) != (m_modifierMask & NSCommandKeyMask)) {
pushEvent(new GHOST_EventKey([event timestamp] * 1000, (modifiers & NSCommandKeyMask) ? GHOST_kEventKeyDown : GHOST_kEventKeyUp, window, GHOST_kKeyOS));
}
-
+
m_modifierMask = modifiers;
m_ignoreMomentumScroll = true;
break;
-
+
default:
return GHOST_kFailure;
break;
}
-
+
return GHOST_kSuccess;
}
@@ -1617,47 +1639,46 @@ GHOST_TUns8* GHOST_SystemCocoa::getClipboard(bool selection) const
{
GHOST_TUns8 * temp_buff;
size_t pastedTextSize;
-
+
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
+
NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard];
-
+
if (pasteBoard == nil) {
[pool drain];
return NULL;
}
-
+
NSArray *supportedTypes =
[NSArray arrayWithObjects: NSStringPboardType, nil];
-
- NSString *bestType = [[NSPasteboard generalPasteboard]
- availableTypeFromArray:supportedTypes];
-
+
+ NSString *bestType = [[NSPasteboard generalPasteboard] availableTypeFromArray:supportedTypes];
+
if (bestType == nil) {
[pool drain];
return NULL;
}
-
- NSString * textPasted = [pasteBoard stringForType:NSStringPboardType];
+
+ NSString *textPasted = [pasteBoard stringForType:NSStringPboardType];
if (textPasted == nil) {
[pool drain];
return NULL;
}
-
+
pastedTextSize = [textPasted lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
-
+
temp_buff = (GHOST_TUns8*) malloc(pastedTextSize+1);
if (temp_buff == NULL) {
[pool drain];
return NULL;
}
-
+
strncpy((char*)temp_buff, [textPasted cStringUsingEncoding:NSUTF8StringEncoding], pastedTextSize);
-
+
temp_buff[pastedTextSize] = '\0';
-
+
[pool drain];
if (temp_buff) {
@@ -1671,26 +1692,25 @@ GHOST_TUns8* GHOST_SystemCocoa::getClipboard(bool selection) const
void GHOST_SystemCocoa::putClipboard(GHOST_TInt8 *buffer, bool selection) const
{
NSString *textToCopy;
-
+
if (selection) return; // for copying the selection, used on X11
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
+
NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard];
-
+
if (pasteBoard == nil) {
[pool drain];
return;
}
-
+
NSArray *supportedTypes = [NSArray arrayWithObject:NSStringPboardType];
-
+
[pasteBoard declareTypes:supportedTypes owner:nil];
-
+
textToCopy = [NSString stringWithCString:buffer encoding:NSUTF8StringEncoding];
-
+
[pasteBoard setString:textToCopy forType:NSStringPboardType];
-
+
[pool drain];
}
-
diff --git a/intern/ghost/intern/GHOST_SystemPathsWin32.cpp b/intern/ghost/intern/GHOST_SystemPathsWin32.cpp
index 2bd380050f1..7d0ce5158fe 100644
--- a/intern/ghost/intern/GHOST_SystemPathsWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemPathsWin32.cpp
@@ -76,8 +76,7 @@ const GHOST_TUns8 *GHOST_SystemPathsWin32::getSystemDir(int, const char *version
HRESULT hResult = SHGetFolderPathW(NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_CURRENT, knownpath_16);
- if (hResult == S_OK)
- {
+ if (hResult == S_OK) {
conv_utf_16_to_8(knownpath_16, knownpath, MAX_PATH * 3);
strcat(knownpath, "\\Blender Foundation\\Blender\\");
strcat(knownpath, versionstr);
@@ -94,8 +93,7 @@ const GHOST_TUns8 *GHOST_SystemPathsWin32::getUserDir(int, const char *versionst
HRESULT hResult = SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, knownpath_16);
- if (hResult == S_OK)
- {
+ if (hResult == S_OK) {
conv_utf_16_to_8(knownpath_16, knownpath, MAX_PATH * 3);
strcat(knownpath, "\\Blender Foundation\\Blender\\");
strcat(knownpath, versionstr);
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index d8ec827a946..7d55a973f91 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -41,7 +41,7 @@
#include <shlobj.h>
#include <tlhelp32.h>
-#include <Psapi.h>
+#include <psapi.h>
#include <windowsx.h>
#include "utfconv.h"
@@ -57,7 +57,7 @@
#include "GHOST_WindowWin32.h"
#ifdef WITH_INPUT_NDOF
-#include "GHOST_NDOFManagerWin32.h"
+ #include "GHOST_NDOFManagerWin32.h"
#endif
// Key code values not found in winuser.h
@@ -125,9 +125,9 @@
static void initRawInput()
{
#ifdef WITH_INPUT_NDOF
-#define DEVICE_COUNT 2
+ #define DEVICE_COUNT 2
#else
-#define DEVICE_COUNT 1
+ #define DEVICE_COUNT 1
#endif
RAWINPUTDEVICE devices[DEVICE_COUNT];
@@ -241,6 +241,7 @@ GHOST_IWindow *GHOST_SystemWin32::createWindow(
state,
type,
((glSettings.flags & GHOST_glStereoVisual) != 0),
+ ((glSettings.flags & GHOST_glAlphaBackground) != 0),
glSettings.numOfAASamples,
parentWindow,
((glSettings.flags & GHOST_glDebugContext) != 0));
@@ -253,7 +254,7 @@ GHOST_IWindow *GHOST_SystemWin32::createWindow(
else {
GHOST_PRINT("GHOST_SystemWin32::createWindow(): window invalid\n");
delete window;
- window = 0;
+ window = NULL;
}
return window;
@@ -408,7 +409,11 @@ GHOST_TSuccess GHOST_SystemWin32::init()
::LoadIcon(NULL, IDI_APPLICATION);
}
wc.hCursor = ::LoadCursor(0, IDC_ARROW);
- wc.hbrBackground = 0;
+ wc.hbrBackground =
+#ifdef INW32_COMPISITING
+ (HBRUSH)CreateSolidBrush
+#endif
+ (0x00000000);
wc.lpszMenuName = 0;
wc.lpszClassName = L"GHOST_WindowClass";
@@ -707,18 +712,26 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_TEventType type,
}
-GHOST_EventWheel *GHOST_SystemWin32::processWheelEvent(GHOST_WindowWin32 *window, WPARAM wParam, LPARAM lParam)
+void GHOST_SystemWin32::processWheelEvent(GHOST_WindowWin32 *window, WPARAM wParam, LPARAM lParam)
{
- // short fwKeys = LOWORD(wParam); // key flags
- int zDelta = (short) HIWORD(wParam); // wheel rotation
-
- // zDelta /= WHEEL_DELTA;
- // temporary fix below: microsoft now has added more precision, making the above division not work
- zDelta = (zDelta <= 0) ? -1 : 1;
+ GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
- // short xPos = (short) LOWORD(lParam); // horizontal position of pointer
- // short yPos = (short) HIWORD(lParam); // vertical position of pointer
- return new GHOST_EventWheel(getSystem()->getMilliSeconds(), window, zDelta);
+ int acc = system->m_wheelDeltaAccum;
+ int delta = GET_WHEEL_DELTA_WPARAM(wParam);
+
+ if (acc * delta < 0) {
+ // scroll direction reversed.
+ acc = 0;
+ }
+ acc += delta;
+ int direction = (acc >= 0) ? 1 : -1;
+ acc = abs(acc);
+
+ while (acc >= WHEEL_DELTA) {
+ system->pushEvent(new GHOST_EventWheel(system->getMilliSeconds(), window, direction));
+ acc -= WHEEL_DELTA;
+ }
+ system->m_wheelDeltaAccum = acc * direction;
}
@@ -766,7 +779,7 @@ GHOST_EventKey *GHOST_SystemWin32::processKeyEvent(GHOST_WindowWin32 *window, RA
// GHOST_PRINTF("%c\n", ascii); // we already get this info via EventPrinter
}
else {
- event = 0;
+ event = NULL;
}
return event;
}
@@ -866,12 +879,12 @@ bool GHOST_SystemWin32::processNDOF(RAWINPUT const &raw)
{
const short *axis = (short *)(data + 1);
// massage into blender view coords (same goes for rotation)
- const short t[3] = {axis[0], -axis[2], axis[1]};
+ const int t[3] = {axis[0], -axis[2], axis[1]};
m_ndofManager->updateTranslation(t, now);
if (raw.data.hid.dwSizeHid == 13) {
// this report also includes rotation
- const short r[3] = {-axis[3], axis[5], -axis[4]};
+ const int r[3] = {-axis[3], axis[5], -axis[4]};
m_ndofManager->updateRotation(r, now);
// I've never gotten one of these, has anyone else?
@@ -882,7 +895,7 @@ bool GHOST_SystemWin32::processNDOF(RAWINPUT const &raw)
case 2: // rotation
{
const short *axis = (short *)(data + 1);
- const short r[3] = {-axis[0], axis[2], -axis[1]};
+ const int r[3] = {-axis[0], axis[2], -axis[1]};
m_ndofManager->updateRotation(r, now);
break;
}
@@ -900,7 +913,7 @@ bool GHOST_SystemWin32::processNDOF(RAWINPUT const &raw)
LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
- GHOST_Event *event = 0;
+ GHOST_Event *event = NULL;
bool eventHandled = false;
LRESULT lResult = 0;
@@ -1132,14 +1145,9 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
POINT mouse_pos = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
HWND mouse_hwnd = ChildWindowFromPoint(HWND_DESKTOP, mouse_pos);
GHOST_WindowWin32 *mouse_window = (GHOST_WindowWin32 *)::GetWindowLongPtr(mouse_hwnd, GWLP_USERDATA);
- if (mouse_window != NULL) {
- event = processWheelEvent(mouse_window, wParam, lParam);
- }
- else {
- /* Happens when mouse is not over any of blender's windows. */
- event = processWheelEvent(window, wParam, lParam);
- }
-
+
+ processWheelEvent(mouse_window ? mouse_window : window , wParam, lParam);
+ eventHandled = true;
#ifdef BROKEN_PEEK_TOUCHPAD
PostMessage(hwnd, WM_USER, 0, 0);
#endif
@@ -1198,6 +1206,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
GHOST_ModifierKeys modifiers;
modifiers.clear();
system->storeModifierKeys(modifiers);
+ system->m_wheelDeltaAccum = 0;
event = processWindowEvent(LOWORD(wParam) ? GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate, window);
/* WARNING: Let DefWindowProc handle WM_ACTIVATE, otherwise WM_MOUSEWHEEL
* will not be dispatched to OUR active window if we minimize one of OUR windows. */
@@ -1540,8 +1549,7 @@ static bool isStartedFromCommandPrompt()
int GHOST_SystemWin32::toggleConsole(int action)
{
- switch (action)
- {
+ switch (action) {
case 3: // startup: hide if not started from command prompt
{
if (isStartedFromCommandPrompt()) {
diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h
index 3085fde610b..d534a300b35 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.h
+++ b/intern/ghost/intern/GHOST_SystemWin32.h
@@ -264,12 +264,12 @@ protected:
static GHOST_EventCursor *processCursorEvent(GHOST_TEventType type, GHOST_WindowWin32 *window);
/**
- * Creates a mouse wheel event.
+ * Handles a mouse wheel event.
* \param window The window receiving the event (the active window).
* \param wParam The wParam from the wndproc
* \param lParam The lParam from the wndproc
*/
- static GHOST_EventWheel *processWheelEvent(GHOST_WindowWin32 *window, WPARAM wParam, LPARAM lParam);
+ static void processWheelEvent(GHOST_WindowWin32 *window, WPARAM wParam, LPARAM lParam);
/**
* Creates a key event and updates the key data stored locally (m_modifierKeys).
@@ -376,6 +376,9 @@ protected:
/** Console status */
int m_consoleStatus;
+
+ /** Wheel delta accumulator **/
+ int m_wheelDeltaAccum;
};
inline void GHOST_SystemWin32::retrieveModifierKeys(GHOST_ModifierKeys& keys) const
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp
index dde63badb91..30cfac08153 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -61,6 +61,11 @@
#include <X11/XF86keysym.h>
#endif
+/* for XIWarpPointer */
+#ifdef WITH_X11_XINPUT
+# include <X11/extensions/XInput2.h>
+#endif
+
/* For timing */
#include <sys/time.h>
#include <unistd.h>
@@ -73,6 +78,10 @@
/* for debugging - so we can breakpoint X11 errors */
// #define USE_X11_ERROR_HANDLERS
+#ifdef WITH_X11_XINPUT
+# define USE_XINPUT_HOTPLUG
+#endif
+
/* see [#34039] Fix Alt key glitch on Unity desktop */
#define USE_UNITY_WORKAROUND
@@ -169,11 +178,36 @@ GHOST_SystemX11(
}
#ifdef WITH_X11_XINPUT
+ /* detect if we have xinput (for reuse) */
+ {
+ memset(&m_xinput_version, 0, sizeof(m_xinput_version));
+ XExtensionVersion *version = XGetExtensionVersion(m_display, INAME);
+ if (version && (version != (XExtensionVersion *)NoSuchExtension)) {
+ if (version->present) {
+ m_xinput_version = *version;
+ }
+ XFree(version);
+ }
+ }
+
+#ifdef USE_XINPUT_HOTPLUG
+ if (m_xinput_version.present) {
+ XEventClass class_presence;
+ int xi_presence;
+ DevicePresence(m_display, xi_presence, class_presence);
+ XSelectExtensionEvent(
+ m_display,
+ RootWindow(m_display, DefaultScreen(m_display)),
+ &class_presence, 1);
+ (void)xi_presence;
+ }
+#endif /* USE_XINPUT_HOTPLUG */
+
/* initialize incase X11 fails to load */
memset(&m_xtablet, 0, sizeof(m_xtablet));
- initXInputDevices();
-#endif
+ refreshXInputDevices();
+#endif /* WITH_X11_XINPUT */
}
GHOST_SystemX11::
@@ -302,7 +336,7 @@ createWindow(const STR_String& title,
const bool exclusive,
const GHOST_TEmbedderWindowID parentWindow)
{
- GHOST_WindowX11 *window = 0;
+ GHOST_WindowX11 *window = NULL;
if (!m_display) return 0;
@@ -310,6 +344,7 @@ createWindow(const STR_String& title,
left, top, width, height,
state, parentWindow, type,
((glSettings.flags & GHOST_glStereoVisual) != 0), exclusive,
+ ((glSettings.flags & GHOST_glAlphaBackground) != 0),
glSettings.numOfAASamples, (glSettings.flags & GHOST_glDebugContext) != 0);
if (window) {
@@ -324,7 +359,7 @@ createWindow(const STR_String& title,
}
else {
delete window;
- window = 0;
+ window = NULL;
}
}
return window;
@@ -419,8 +454,7 @@ static Bool init_timestamp_scanner(Display *, XEvent *event, XPointer arg)
{
init_timestamp_data *data =
reinterpret_cast<init_timestamp_data *>(arg);
- switch (event->type)
- {
+ switch (event->type) {
case ButtonPress:
case ButtonRelease:
data->timestamp = event->xbutton.time;
@@ -627,8 +661,13 @@ static bool checkTabletProximity(Display *display, XDevice *device)
return false;
}
+ /* needed since unplugging will abort() without this */
+ GHOST_X11_ERROR_HANDLERS_OVERRIDE(handler_store);
+
state = XQueryDeviceState(display, device);
+ GHOST_X11_ERROR_HANDLERS_RESTORE(handler_store);
+
if (state) {
XInputClass *cls = state->data;
// printf("%d class%s :\n", state->num_classes,
@@ -661,6 +700,41 @@ GHOST_SystemX11::processEvent(XEvent *xe)
GHOST_WindowX11 *window = findGhostWindow(xe->xany.window);
GHOST_Event *g_event = NULL;
+#ifdef USE_XINPUT_HOTPLUG
+ /* Hot-Plug support */
+ if (m_xinput_version.present) {
+ XEventClass class_presence;
+ int xi_presence;
+
+ DevicePresence(m_display, xi_presence, class_presence);
+ (void)class_presence;
+
+ if (xe->type == xi_presence) {
+ XDevicePresenceNotifyEvent *notify_event = (XDevicePresenceNotifyEvent *)xe;
+ if ((notify_event->devchange == DeviceEnabled) ||
+ (notify_event->devchange == DeviceDisabled) ||
+ (notify_event->devchange == DeviceAdded) ||
+ (notify_event->devchange == DeviceRemoved))
+ {
+ refreshXInputDevices();
+
+ /* update all window events */
+ {
+ vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
+ vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
+ vector<GHOST_IWindow *>::const_iterator win_end = win_vec.end();
+
+ for (; win_it != win_end; ++win_it) {
+ GHOST_WindowX11 *window = static_cast<GHOST_WindowX11 *>(*win_it);
+ window->refreshXInputDevices();
+ }
+ }
+ }
+ }
+ }
+#endif /* USE_XINPUT_HOTPLUG */
+
+
if (!window) {
return;
}
@@ -680,7 +754,6 @@ GHOST_SystemX11::processEvent(XEvent *xe)
}
}
#endif /* WITH_X11_XINPUT */
-
switch (xe->type) {
case Expose:
{
@@ -797,18 +870,25 @@ GHOST_SystemX11::processEvent(XEvent *xe)
*
* To address this, we:
*
- * - Try to get a 'number' key_sym using XLookupKeysym (with or without shift modifier).
+ * - Try to get a 'number' key_sym using XLookupKeysym (with virtual shift modifier),
+ * in a very restrictive set of cases.
* - Fallback to XLookupString to get a key_sym from active user-defined keymap.
*
- * Note that this enforces users to use an ascii-compatible keymap with Blender - but at least it gives
- * predictable and consistent results.
+ * Note that:
+ * - This effectively 'lock' main number keys to always output number events (except when using alt-gr).
+ * - This enforces users to use an ascii-compatible keymap with Blender - but at least it gives
+ * predictable and consistent results.
*
* Also, note that nothing in XLib sources [1] makes it obvious why those two functions give different
* key_sym results...
*
* [1] http://cgit.freedesktop.org/xorg/lib/libX11/tree/src/KeyBind.c
*/
- if ((xke->keycode >= 10 && xke->keycode < 20)) {
+ /* Mode_switch 'modifier' is AltGr - when this one or Shift are enabled, we do not want to apply
+ * that 'forced number' hack. */
+ const unsigned int mode_switch_mask = XkbKeysymToModifiers(xke->display, XK_Mode_switch);
+ const unsigned int number_hack_forbidden_kmods_mask = mode_switch_mask | ShiftMask;
+ if ((xke->keycode >= 10 && xke->keycode < 20) && ((xke->state & number_hack_forbidden_kmods_mask) == 0)) {
key_sym = XLookupKeysym(xke, ShiftMask);
if (!((key_sym >= XK_0) && (key_sym <= XK_9))) {
key_sym = XLookupKeysym(xke, 0);
@@ -822,8 +902,49 @@ GHOST_SystemX11::processEvent(XEvent *xe)
ascii = '\0';
}
- if ((gkey = convertXKey(key_sym)) == GHOST_kKeyUnknown) {
- gkey = convertXKey(key_sym_str);
+ /* Only allow a limited set of keys from XLookupKeysym, all others we take from XLookupString,
+ * unless it gives unknown key... */
+ gkey = convertXKey(key_sym);
+ switch (gkey) {
+ case GHOST_kKeyRightAlt:
+ case GHOST_kKeyLeftAlt:
+ case GHOST_kKeyRightShift:
+ case GHOST_kKeyLeftShift:
+ case GHOST_kKeyRightControl:
+ case GHOST_kKeyLeftControl:
+ case GHOST_kKeyOS:
+ case GHOST_kKey0:
+ case GHOST_kKey1:
+ case GHOST_kKey2:
+ case GHOST_kKey3:
+ case GHOST_kKey4:
+ case GHOST_kKey5:
+ case GHOST_kKey6:
+ case GHOST_kKey7:
+ case GHOST_kKey8:
+ case GHOST_kKey9:
+ case GHOST_kKeyNumpad0:
+ case GHOST_kKeyNumpad1:
+ case GHOST_kKeyNumpad2:
+ case GHOST_kKeyNumpad3:
+ case GHOST_kKeyNumpad4:
+ case GHOST_kKeyNumpad5:
+ case GHOST_kKeyNumpad6:
+ case GHOST_kKeyNumpad7:
+ case GHOST_kKeyNumpad8:
+ case GHOST_kKeyNumpad9:
+ case GHOST_kKeyNumpadPeriod:
+ case GHOST_kKeyNumpadEnter:
+ case GHOST_kKeyNumpadPlus:
+ case GHOST_kKeyNumpadMinus:
+ case GHOST_kKeyNumpadAsterisk:
+ case GHOST_kKeyNumpadSlash:
+ break;
+ default:
+ GHOST_TKey gkey_str = convertXKey(key_sym_str);
+ if (gkey_str != GHOST_kKeyUnknown) {
+ gkey = gkey_str;
+ }
}
#else
/* In keyboards like latin ones,
@@ -1239,7 +1360,8 @@ GHOST_SystemX11::processEvent(XEvent *xe)
* events). So we have to check which values this event actually contains!
*/
-#define AXIS_VALUE_GET(axis, val) ((axis_first <= axis && axes_end > axis) && ((void)(val = data->axis_data[axis]), true))
+#define AXIS_VALUE_GET(axis, val) \
+ ((axis_first <= axis && axes_end > axis) && ((void)(val = data->axis_data[axis - axis_first]), true))
if (AXIS_VALUE_GET(2, axis_value)) {
window->GetTabletData()->Pressure = axis_value / ((float)m_xtablet.PressureLevels);
@@ -1400,7 +1522,22 @@ setCursorPosition(
int relx = x - cx;
int rely = y - cy;
- XWarpPointer(m_display, None, None, 0, 0, 0, 0, relx, rely);
+#ifdef WITH_X11_XINPUT
+ if ((m_xinput_version.present) &&
+ (m_xinput_version.major_version >= 2))
+ {
+ /* Needed to account for XInput "Coordinate Transformation Matrix", see T48901 */
+ int device_id;
+ if (XIGetClientPointer(m_display, None, &device_id) != False) {
+ XIWarpPointer(m_display, device_id, None, None, 0, 0, 0, 0, relx, rely);
+ }
+ }
+ else
+#endif
+ {
+ XWarpPointer(m_display, None, None, 0, 0, 0, 0, relx, rely);
+ }
+
XSync(m_display, 0); /* Sync to process all requests */
return GHOST_kSuccess;
@@ -1489,6 +1626,7 @@ convertXKey(KeySym key)
switch (key) {
GXMAP(type, XK_BackSpace, GHOST_kKeyBackSpace);
GXMAP(type, XK_Tab, GHOST_kKeyTab);
+ GXMAP(type, XK_ISO_Left_Tab, GHOST_kKeyTab);
GXMAP(type, XK_Return, GHOST_kKeyEnter);
GXMAP(type, XK_Escape, GHOST_kKeyEsc);
GXMAP(type, XK_space, GHOST_kKeySpace);
@@ -1916,11 +2054,8 @@ GHOST_TSuccess GHOST_SystemX11::pushDragDropEvent(GHOST_TEventType eventType,
);
}
#endif
-
-#if defined(USE_X11_ERROR_HANDLERS) || defined(WITH_X11_XINPUT)
-/*
+/**
* These callbacks can be used for debugging, so we can breakpoint on an X11 error.
-
*
* Dummy function to get around IO Handler exiting if device invalid
* Basically it will not crash blender now if you have a X device that
@@ -1951,7 +2086,6 @@ int GHOST_X11_ApplicationIOErrorHandler(Display * /*display*/)
/* No exit! - but keep lint happy */
return 0;
}
-#endif
#ifdef WITH_X11_XINPUT
/* These C functions are copied from Wine 1.1.13's wintab.c */
@@ -1962,8 +2096,7 @@ int GHOST_X11_ApplicationIOErrorHandler(Display * /*display*/)
static bool match_token(const char *haystack, const char *needle)
{
const char *p, *q;
- for (p = haystack; *p; )
- {
+ for (p = haystack; *p; ) {
while (*p && isspace(*p))
p++;
if (!*p)
@@ -2049,23 +2182,27 @@ static BOOL is_eraser(const char *name, const char *type)
#undef FALSE
/* end code copied from wine */
-void GHOST_SystemX11::initXInputDevices()
+void GHOST_SystemX11::refreshXInputDevices()
{
- static XErrorHandler old_handler = (XErrorHandler) 0;
- static XIOErrorHandler old_handler_io = (XIOErrorHandler) 0;
+ if (m_xinput_version.present) {
+
+ if (m_xtablet.StylusDevice) {
+ XCloseDevice(m_display, m_xtablet.StylusDevice);
+ m_xtablet.StylusDevice = NULL;
+ }
+
+ if (m_xtablet.EraserDevice) {
+ XCloseDevice(m_display, m_xtablet.EraserDevice);
+ m_xtablet.EraserDevice = NULL;
+ }
- XExtensionVersion *version = XGetExtensionVersion(m_display, INAME);
+ /* Install our error handler to override Xlib's termination behavior */
+ GHOST_X11_ERROR_HANDLERS_OVERRIDE(handler_store);
- if (version && (version != (XExtensionVersion *)NoSuchExtension)) {
- if (version->present) {
+ {
int device_count;
XDeviceInfo *device_info = XListInputDevices(m_display, &device_count);
- m_xtablet.StylusDevice = NULL;
- m_xtablet.EraserDevice = NULL;
- /* Install our error handler to override Xlib's termination behavior */
- old_handler = XSetErrorHandler(GHOST_X11_ApplicationErrorHandler);
- old_handler_io = XSetIOErrorHandler(GHOST_X11_ApplicationIOErrorHandler);
for (int i = 0; i < device_count; ++i) {
char *device_type = device_info[i].type ? XGetAtomName(m_display, device_info[i].type) : NULL;
@@ -2124,13 +2261,10 @@ void GHOST_SystemX11::initXInputDevices()
}
}
- /* Restore handler */
- (void) XSetErrorHandler(old_handler);
- (void) XSetIOErrorHandler(old_handler_io);
-
XFreeDeviceList(device_info);
}
- XFree(version);
+
+ GHOST_X11_ERROR_HANDLERS_RESTORE(handler_store);
}
}
diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h
index a0088dbe8f0..e60cab6a194 100644
--- a/intern/ghost/intern/GHOST_SystemX11.h
+++ b/intern/ghost/intern/GHOST_SystemX11.h
@@ -52,6 +52,20 @@
int GHOST_X11_ApplicationErrorHandler(Display *display, XErrorEvent *theEvent);
int GHOST_X11_ApplicationIOErrorHandler(Display *display);
+#define GHOST_X11_ERROR_HANDLERS_OVERRIDE(var) \
+ struct { \
+ XErrorHandler handler; \
+ XIOErrorHandler handler_io; \
+ } var = { \
+ XSetErrorHandler(GHOST_X11_ApplicationErrorHandler), \
+ XSetIOErrorHandler(GHOST_X11_ApplicationIOErrorHandler), \
+ }
+
+#define GHOST_X11_ERROR_HANDLERS_RESTORE(var) \
+ { \
+ (void)XSetErrorHandler(var.handler); \
+ (void)XSetIOErrorHandler(var.handler_io); \
+ } ((void)0)
class GHOST_WindowX11;
@@ -328,6 +342,10 @@ public:
#endif
} m_atom;
+#ifdef WITH_X11_XINPUT
+ XExtensionVersion m_xinput_version;
+#endif
+
private:
Display *m_display;
@@ -367,7 +385,7 @@ private:
#endif
#ifdef WITH_X11_XINPUT
- void initXInputDevices();
+ void refreshXInputDevices();
#endif
GHOST_WindowX11 *
diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h
index 52cb9cbf54b..d778628ea37 100644
--- a/intern/ghost/intern/GHOST_Window.h
+++ b/intern/ghost/intern/GHOST_Window.h
@@ -106,7 +106,7 @@ public:
* \return The validity of the window.
*/
virtual bool getValid() const {
- return m_context != 0;
+ return m_context != NULL;
}
/**
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.h b/intern/ghost/intern/GHOST_WindowCocoa.h
index 3ed88086184..b234291396b 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.h
+++ b/intern/ghost/intern/GHOST_WindowCocoa.h
@@ -74,7 +74,8 @@ public:
GHOST_TWindowState state,
GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone,
const bool stereoVisual = false,
- const GHOST_TUns16 numOfAASamples = 0
+ const GHOST_TUns16 numOfAASamples = 0,
+ bool is_debug = false
);
/**
@@ -305,6 +306,7 @@ protected:
bool m_lionStyleFullScreen;
bool m_immediateDraw;
+ bool m_debug_context; // for debug messages during context setup
};
#endif // __GHOST_WINDOWCOCOA_H__
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm
index b3fc8efbab1..97615dcea96 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.mm
+++ b/intern/ghost/intern/GHOST_WindowCocoa.mm
@@ -528,10 +528,11 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(
GHOST_TUns32 height,
GHOST_TWindowState state,
GHOST_TDrawingContextType type,
- const bool stereoVisual, const GHOST_TUns16 numOfAASamples
+ const bool stereoVisual, const GHOST_TUns16 numOfAASamples, bool is_debug
) :
GHOST_Window(width, height, state, stereoVisual, false, numOfAASamples),
- m_customCursor(0)
+ m_customCursor(0),
+ m_debug_context(is_debug)
{
m_systemCocoa = systemCocoa;
m_fullScreen = false;
@@ -622,8 +623,6 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(
m_lionStyleFullScreen = true;
}
- [NSApp activateIgnoringOtherApps:YES]; // raise application to front, important for new blender instance animation play case
-
[pool drain];
}
@@ -663,7 +662,7 @@ GHOST_WindowCocoa::~GHOST_WindowCocoa()
bool GHOST_WindowCocoa::getValid() const
{
- return GHOST_Window::getValid() && m_window != 0 && m_openGLView != 0;
+ return GHOST_Window::getValid() && m_window != NULL && m_openGLView != NULL;
}
void* GHOST_WindowCocoa::getOSWindow() const
@@ -1117,7 +1116,7 @@ GHOST_Context *GHOST_WindowCocoa::newDrawingContext(GHOST_TDrawingContextType ty
m_openGLView,
0, // profile bit
0, 0,
- GHOST_OPENGL_CGL_CONTEXT_FLAGS,
+ m_debug_context,
GHOST_OPENGL_CGL_RESET_NOTIFICATION_STRATEGY);
#else
# error
diff --git a/intern/ghost/intern/GHOST_WindowManager.cpp b/intern/ghost/intern/GHOST_WindowManager.cpp
index 83490cecce5..790c73deca5 100644
--- a/intern/ghost/intern/GHOST_WindowManager.cpp
+++ b/intern/ghost/intern/GHOST_WindowManager.cpp
@@ -110,7 +110,7 @@ bool GHOST_WindowManager::getWindowFound(const GHOST_IWindow *window) const
bool GHOST_WindowManager::getFullScreen(void) const
{
- return m_fullScreenWindow != 0;
+ return m_fullScreenWindow != NULL;
}
@@ -140,13 +140,13 @@ GHOST_TSuccess GHOST_WindowManager::endFullScreen(void)
{
GHOST_TSuccess success = GHOST_kFailure;
if (getFullScreen()) {
- if (m_fullScreenWindow != 0) {
+ if (m_fullScreenWindow != NULL) {
//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;
+ m_fullScreenWindow = NULL;
if (m_activeWindowBeforeFullScreen) {
setActiveWindow(m_activeWindowBeforeFullScreen);
}
@@ -181,7 +181,7 @@ GHOST_IWindow *GHOST_WindowManager::getActiveWindow(void) const
void GHOST_WindowManager::setWindowInactive(const GHOST_IWindow *window)
{
if (window == m_activeWindow) {
- m_activeWindow = 0;
+ m_activeWindow = NULL;
}
}
diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp
index 7247753c655..2aa950f8278 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.cpp
+++ b/intern/ghost/intern/GHOST_WindowWin32.cpp
@@ -43,7 +43,9 @@
#else
# include "GHOST_ContextWGL.h"
#endif
-
+#ifdef WIN32_COMPOSITING
+#include <Dwmapi.h>
+#endif
#include <math.h>
#include <string.h>
@@ -70,7 +72,8 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
GHOST_TUns32 height,
GHOST_TWindowState state,
GHOST_TDrawingContextType type,
- bool wantStereoVisual,
+ bool wantStereoVisual,
+ bool alphaBackground,
GHOST_TUns16 wantNumOfAASamples,
GHOST_TEmbedderWindowID parentwindowhwnd,
bool is_debug)
@@ -83,6 +86,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
m_hasGrabMouse(false),
m_nPressedButtons(0),
m_customCursor(0),
+ m_wantAlphaBackground(alphaBackground),
m_wintab(NULL),
m_tabletData(NULL),
m_tablet(0),
@@ -91,31 +95,6 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
m_parentWindowHwnd(parentwindowhwnd),
m_debug_context(is_debug)
{
- OSVERSIONINFOEX versionInfo;
- bool hasMinVersionForTaskbar = false;
-
- ZeroMemory(&versionInfo, sizeof(OSVERSIONINFOEX));
-
- versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
-
- if (!GetVersionEx((OSVERSIONINFO *)&versionInfo)) {
- versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
- if (GetVersionEx((OSVERSIONINFO *)&versionInfo)) {
- if ((versionInfo.dwMajorVersion == 6 && versionInfo.dwMinorVersion >= 1) ||
- (versionInfo.dwMajorVersion >= 7))
- {
- hasMinVersionForTaskbar = true;
- }
- }
- }
- else {
- if ((versionInfo.dwMajorVersion == 6 && versionInfo.dwMinorVersion >= 1) ||
- (versionInfo.dwMajorVersion >= 7))
- {
- hasMinVersionForTaskbar = true;
- }
- }
-
if (state != GHOST_kWindowStateFullScreen) {
RECT rect;
MONITORINFO monitor;
@@ -181,17 +160,17 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
wchar_t *title_16 = alloc_utf16_from_8((char *)(const char *)title, 0);
m_hWnd = ::CreateWindowW(
- s_windowClassName, // pointer to registered class name
- title_16, // pointer to window name
- wintype, // window style
- left, // horizontal position of window
- top, // vertical position of window
- width, // window width
- height, // window height
- (HWND) m_parentWindowHwnd, // handle to parent or owner window
- 0, // handle to menu or child-window identifier
- ::GetModuleHandle(0), // handle to application instance
- 0); // pointer to window-creation data
+ s_windowClassName, // pointer to registered class name
+ title_16, // pointer to window name
+ wintype, // window style
+ left, // horizontal position of window
+ top, // vertical position of window
+ width, // window width
+ height, // window height
+ (HWND)m_parentWindowHwnd, // handle to parent or owner window
+ 0, // handle to menu or child-window identifier
+ ::GetModuleHandle(0), // handle to application instance
+ 0); // pointer to window-creation data
free(title_16);
}
else {
@@ -243,6 +222,24 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
}
::ShowWindow(m_hWnd, nCmdShow);
+#ifdef WIN32_COMPOSITING
+ if (alphaBackground && parentwindowhwnd == 0) {
+
+ HRESULT hr = S_OK;
+
+ // Create and populate the Blur Behind structure
+ DWM_BLURBEHIND bb = { 0 };
+
+ // Enable Blur Behind and apply to the entire client area
+ bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
+ bb.fEnable = true;
+ bb.hRgnBlur = CreateRectRgn(0, 0, -1, -1);
+
+ // Apply Blur Behind
+ hr = DwmEnableBlurBehindWindow(m_hWnd, &bb);
+ DeleteObject(bb.hRgnBlur);
+ }
+#endif
// Force an initial paint of the window
::UpdateWindow(m_hWnd);
}
@@ -319,11 +316,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
}
}
}
-
- if (hasMinVersionForTaskbar)
- CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList, (LPVOID *)&m_Bar);
- else
- m_Bar = NULL;
+ CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (LPVOID *)&m_Bar);
}
@@ -339,8 +332,7 @@ GHOST_WindowWin32::~GHOST_WindowWin32()
if (fpWTClose) {
if (m_tablet)
fpWTClose(m_tablet);
- if (m_tabletData)
- delete m_tabletData;
+ delete m_tabletData;
m_tabletData = NULL;
}
}
@@ -623,6 +615,7 @@ GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType ty
#if defined(WITH_GL_PROFILE_CORE)
GHOST_Context *context = new GHOST_ContextWGL(
m_wantStereoVisual,
+ m_wantAlphaBackground,
m_wantNumOfAASamples,
m_hWnd,
m_hDC,
@@ -633,6 +626,7 @@ GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType ty
#elif defined(WITH_GL_PROFILE_ES20)
GHOST_Context *context = new GHOST_ContextWGL(
m_wantStereoVisual,
+ m_wantAlphaBackground,
m_wantNumOfAASamples,
m_hWnd,
m_hDC,
@@ -643,6 +637,7 @@ GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType ty
#elif defined(WITH_GL_PROFILE_COMPAT)
GHOST_Context *context = new GHOST_ContextWGL(
m_wantStereoVisual,
+ m_wantAlphaBackground,
m_wantNumOfAASamples,
m_hWnd,
m_hDC,
@@ -654,7 +649,7 @@ GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType ty
WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
3, 2,
#endif
- GHOST_OPENGL_WGL_CONTEXT_FLAGS,
+ (m_debug_context ? WGL_CONTEXT_DEBUG_BIT_ARB : 0),
GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY);
#else
# error
diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h
index b508c2f37df..a1cf58c9ceb 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.h
+++ b/intern/ghost/intern/GHOST_WindowWin32.h
@@ -89,6 +89,7 @@ public:
GHOST_TWindowState state,
GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone,
bool wantStereoVisual = false,
+ bool alphaBackground = false,
GHOST_TUns16 wantNumOfAASamples = 0,
GHOST_TEmbedderWindowID parentWindowHwnd = 0,
bool is_debug = false);
@@ -328,6 +329,8 @@ private:
int m_nPressedButtons;
/** HCURSOR structure of the custom cursor */
HCURSOR m_customCursor;
+ /** request GL context aith alpha channel */
+ bool m_wantAlphaBackground;
/** ITaskbarList3 structure for progress bar*/
ITaskbarList3 *m_Bar;
diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp
index e68e0901dab..ec2b65e67d0 100644
--- a/intern/ghost/intern/GHOST_WindowX11.cpp
+++ b/intern/ghost/intern/GHOST_WindowX11.cpp
@@ -33,7 +33,9 @@
#include <X11/cursorfont.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
-
+#ifdef WITH_X11_ALPHA
+#include <X11/extensions/Xrender.h>
+#endif
#include "GHOST_WindowX11.h"
#include "GHOST_SystemX11.h"
#include "STR_String.h"
@@ -49,6 +51,11 @@
# include "GHOST_ContextGLX.h"
#endif
+/* for XIWarpPointer */
+#ifdef WITH_X11_XINPUT
+# include <X11/extensions/XInput2.h>
+#endif
+
#if defined(__sun__) || defined(__sun) || defined(__sparc) || defined(__sparc__) || defined(_AIX)
# include <strings.h>
#endif
@@ -164,15 +171,21 @@ static const unsigned long BLENDER_ICON_48x48x32[] = {
static XVisualInfo *x11_visualinfo_from_glx(
Display *display,
- bool stereoVisual, GHOST_TUns16 *r_numOfAASamples)
+ bool stereoVisual,
+ GHOST_TUns16 *r_numOfAASamples,
+ bool needAlpha,
+ GLXFBConfig *fbconfig)
{
- XVisualInfo *visualInfo = NULL;
+ XVisualInfo *visual = NULL;
GHOST_TUns16 numOfAASamples = *r_numOfAASamples;
+ int glx_major, glx_minor, glx_version; /* GLX version: major.minor */
GHOST_TUns16 actualSamples;
+ int glx_attribs[64];
+
+ *fbconfig = NULL;
/* Set up the minimum attributes that we require and see if
* X can find us a visual matching those requirements. */
- int glx_major, glx_minor; /* GLX version: major.minor */
if (!glXQueryVersion(display, &glx_major, &glx_minor)) {
fprintf(stderr,
@@ -182,53 +195,118 @@ static XVisualInfo *x11_visualinfo_from_glx(
return NULL;
}
+ glx_version = glx_major*100 + glx_minor;
- /* GLX >= 1.4 required for multi-sample */
- if ((glx_major > 1) || (glx_major == 1 && glx_minor >= 4)) {
+ if (glx_version >= 104) {
actualSamples = numOfAASamples;
}
else {
numOfAASamples = 0;
actualSamples = 0;
}
+
+#ifdef WITH_X11_ALPHA
+ if ( needAlpha
+ && glx_version >= 103
+ && (glXChooseFBConfig ||
+ (glXChooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC)glXGetProcAddressARB((const GLubyte *)"glXChooseFBConfig")) != NULL)
+ && (glXGetVisualFromFBConfig ||
+ (glXGetVisualFromFBConfig = (PFNGLXGETVISUALFROMFBCONFIGPROC)glXGetProcAddressARB((const GLubyte *)"glXGetVisualFromFBConfig")) != NULL)
+ ) {
+ GLXFBConfig *fbconfigs;
+ int nbfbconfig;
+ int i;
+
+ for (;;) {
+
+ GHOST_X11_GL_GetAttributes(glx_attribs, 64, actualSamples, stereoVisual, needAlpha, true);
+
+ fbconfigs = glXChooseFBConfig(display, DefaultScreen(display), glx_attribs, &nbfbconfig);
+
+ /* Any sample level or even zero, which means oversampling disabled, is good
+ * but we need a valid visual to continue */
+ if (nbfbconfig > 0) {
+ /* take a frame buffer config that has alpha cap */
+ for (i=0 ;i<nbfbconfig; i++) {
+ visual = (XVisualInfo*)glXGetVisualFromFBConfig(display, fbconfigs[i]);
+ if (!visual)
+ continue;
+ /* if we don't need a alpha background, the first config will do, otherwise
+ * test the alphaMask as it won't necessarily be present */
+ if (needAlpha) {
+ XRenderPictFormat *pict_format = XRenderFindVisualFormat(display, visual->visual);
+ if (!pict_format)
+ continue;
+ if (pict_format->direct.alphaMask <= 0)
+ continue;
+ }
+ *fbconfig = fbconfigs[i];
+ break;
+ }
+ XFree(fbconfigs);
+ if (i<nbfbconfig) {
+ if (actualSamples < numOfAASamples) {
+ fprintf(stderr,
+ "Warning! Unable to find a multisample pixel format that supports exactly %d samples. "
+ "Substituting one that uses %d samples.\n",
+ numOfAASamples, actualSamples);
+ }
+ break;
+ }
+ visual = NULL;
+ }
- /* Find the display with highest samples, starting at level requested */
- for (;;) {
- int glx_attribs[64];
-
- GHOST_X11_GL_GetAttributes(glx_attribs, 64, actualSamples, stereoVisual, false);
-
- visualInfo = glXChooseVisual(display, DefaultScreen(display), glx_attribs);
-
- /* Any sample level or even zero, which means oversampling disabled, is good
- * but we need a valid visual to continue */
- if (visualInfo != NULL) {
- if (actualSamples < numOfAASamples) {
+ if (actualSamples == 0) {
+ /* All options exhausted, cannot continue */
fprintf(stderr,
- "Warning! Unable to find a multisample pixel format that supports exactly %d samples. "
- "Substituting one that uses %d samples.\n",
- numOfAASamples, actualSamples);
+ "%s:%d: X11 glXChooseVisual() failed, "
+ "verify working openGL system!\n",
+ __FILE__, __LINE__);
+
+ return NULL;
+ }
+ else {
+ --actualSamples;
}
- break;
}
+ }
+ else
+#endif
+ {
+ /* legacy, don't use extension */
+ for (;;) {
+ GHOST_X11_GL_GetAttributes(glx_attribs, 64, actualSamples, stereoVisual, needAlpha, false);
+
+ visual = glXChooseVisual(display, DefaultScreen(display), glx_attribs);
+
+ /* Any sample level or even zero, which means oversampling disabled, is good
+ * but we need a valid visual to continue */
+ if (visual != NULL) {
+ if (actualSamples < numOfAASamples) {
+ fprintf(stderr,
+ "Warning! Unable to find a multisample pixel format that supports exactly %d samples. "
+ "Substituting one that uses %d samples.\n",
+ numOfAASamples, actualSamples);
+ }
+ break;
+ }
- if (actualSamples == 0) {
- /* All options exhausted, cannot continue */
- fprintf(stderr,
- "%s:%d: X11 glXChooseVisual() failed, "
- "verify working openGL system!\n",
- __FILE__, __LINE__);
+ if (actualSamples == 0) {
+ /* All options exhausted, cannot continue */
+ fprintf(stderr,
+ "%s:%d: X11 glXChooseVisual() failed, "
+ "verify working openGL system!\n",
+ __FILE__, __LINE__);
- return NULL;
- }
- else {
- --actualSamples;
+ return NULL;
+ }
+ else {
+ --actualSamples;
+ }
}
}
-
*r_numOfAASamples = actualSamples;
-
- return visualInfo;
+ return visual;
}
GHOST_WindowX11::
@@ -244,10 +322,12 @@ GHOST_WindowX11(GHOST_SystemX11 *system,
GHOST_TDrawingContextType type,
const bool stereoVisual,
const bool exclusive,
+ const bool alphaBackground,
const GHOST_TUns16 numOfAASamples, const bool is_debug)
: GHOST_Window(width, height, state, stereoVisual, exclusive, numOfAASamples),
m_display(display),
m_visualInfo(NULL),
+ m_fbconfig(NULL),
m_normal_state(GHOST_kWindowStateNormal),
m_system(system),
m_invalid_window(false),
@@ -264,7 +344,7 @@ GHOST_WindowX11(GHOST_SystemX11 *system,
m_is_debug_context(is_debug)
{
if (type == GHOST_kDrawingContextTypeOpenGL) {
- m_visualInfo = x11_visualinfo_from_glx(m_display, stereoVisual, &m_wantNumOfAASamples);
+ m_visualInfo = x11_visualinfo_from_glx(m_display, stereoVisual, &m_wantNumOfAASamples, alphaBackground, (GLXFBConfig*)&m_fbconfig);
}
else {
XVisualInfo tmp = {0};
@@ -491,7 +571,7 @@ GHOST_WindowX11(GHOST_SystemX11 *system,
}
#ifdef WITH_X11_XINPUT
- initXInputDevices();
+ refreshXInputDevices();
m_tabletData.Active = GHOST_kTabletModeNone;
#endif
@@ -558,45 +638,40 @@ bool GHOST_WindowX11::createX11_XIC()
#endif
#ifdef WITH_X11_XINPUT
-void GHOST_WindowX11::initXInputDevices()
+void GHOST_WindowX11::refreshXInputDevices()
{
- XExtensionVersion *version = XGetExtensionVersion(m_display, INAME);
-
- if (version && (version != (XExtensionVersion *)NoSuchExtension)) {
- if (version->present) {
- GHOST_SystemX11::GHOST_TabletX11 &xtablet = m_system->GetXTablet();
- XEventClass xevents[8], ev;
- int dcount = 0;
-
- /* With modern XInput (xlib 1.6.2 at least and/or evdev 2.9.0) and some 'no-name' tablets
- * like 'UC-LOGIC Tablet WP5540U', we also need to 'select' ButtonPress for motion event,
- * otherwise we do not get any tablet motion event once pen is pressed... See T43367.
- */
-
- if (xtablet.StylusDevice) {
- DeviceMotionNotify(xtablet.StylusDevice, xtablet.MotionEvent, ev);
- if (ev) xevents[dcount++] = ev;
- DeviceButtonPress(xtablet.StylusDevice, xtablet.PressEvent, ev);
- if (ev) xevents[dcount++] = ev;
- ProximityIn(xtablet.StylusDevice, xtablet.ProxInEvent, ev);
- if (ev) xevents[dcount++] = ev;
- ProximityOut(xtablet.StylusDevice, xtablet.ProxOutEvent, ev);
- if (ev) xevents[dcount++] = ev;
- }
- if (xtablet.EraserDevice) {
- DeviceMotionNotify(xtablet.EraserDevice, xtablet.MotionEventEraser, ev);
- if (ev) xevents[dcount++] = ev;
- DeviceButtonPress(xtablet.EraserDevice, xtablet.PressEventEraser, ev);
- if (ev) xevents[dcount++] = ev;
- ProximityIn(xtablet.EraserDevice, xtablet.ProxInEventEraser, ev);
- if (ev) xevents[dcount++] = ev;
- ProximityOut(xtablet.EraserDevice, xtablet.ProxOutEventEraser, ev);
- if (ev) xevents[dcount++] = ev;
- }
+ if (m_system->m_xinput_version.present) {
+ GHOST_SystemX11::GHOST_TabletX11 &xtablet = m_system->GetXTablet();
+ XEventClass xevents[8], ev;
+ int dcount = 0;
+
+ /* With modern XInput (xlib 1.6.2 at least and/or evdev 2.9.0) and some 'no-name' tablets
+ * like 'UC-LOGIC Tablet WP5540U', we also need to 'select' ButtonPress for motion event,
+ * otherwise we do not get any tablet motion event once pen is pressed... See T43367.
+ */
- XSelectExtensionEvent(m_display, m_window, xevents, dcount);
+ if (xtablet.StylusDevice) {
+ DeviceMotionNotify(xtablet.StylusDevice, xtablet.MotionEvent, ev);
+ if (ev) xevents[dcount++] = ev;
+ DeviceButtonPress(xtablet.StylusDevice, xtablet.PressEvent, ev);
+ if (ev) xevents[dcount++] = ev;
+ ProximityIn(xtablet.StylusDevice, xtablet.ProxInEvent, ev);
+ if (ev) xevents[dcount++] = ev;
+ ProximityOut(xtablet.StylusDevice, xtablet.ProxOutEvent, ev);
+ if (ev) xevents[dcount++] = ev;
+ }
+ if (xtablet.EraserDevice) {
+ DeviceMotionNotify(xtablet.EraserDevice, xtablet.MotionEventEraser, ev);
+ if (ev) xevents[dcount++] = ev;
+ DeviceButtonPress(xtablet.EraserDevice, xtablet.PressEventEraser, ev);
+ if (ev) xevents[dcount++] = ev;
+ ProximityIn(xtablet.EraserDevice, xtablet.ProxInEventEraser, ev);
+ if (ev) xevents[dcount++] = ev;
+ ProximityOut(xtablet.EraserDevice, xtablet.ProxOutEventEraser, ev);
+ if (ev) xevents[dcount++] = ev;
}
- XFree(version);
+
+ XSelectExtensionEvent(m_display, m_window, xevents, dcount);
}
}
@@ -1240,6 +1315,7 @@ GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type
m_window,
m_display,
m_visualInfo,
+ (GLXFBConfig)m_fbconfig,
GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
3, 2,
GHOST_OPENGL_GLX_CONTEXT_FLAGS | (m_is_debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0),
@@ -1251,6 +1327,7 @@ GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type
m_window,
m_display,
m_visualInfo,
+ (GLXFBConfig)m_fbconfig,
GLX_CONTEXT_ES2_PROFILE_BIT_EXT,
2, 0,
GHOST_OPENGL_GLX_CONTEXT_FLAGS | (m_is_debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0),
@@ -1262,6 +1339,7 @@ GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type
m_window,
m_display,
m_visualInfo,
+ (GLXFBConfig)m_fbconfig,
0, // profile bit
0, 0,
GHOST_OPENGL_GLX_CONTEXT_FLAGS | (m_is_debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0),
@@ -1447,7 +1525,21 @@ setWindowCursorGrab(
/* use to generate a mouse move event, otherwise the last event
* blender gets can be outside the screen causing menus not to show
* properly unless the user moves the mouse */
- XWarpPointer(m_display, None, None, 0, 0, 0, 0, 0, 0);
+
+#ifdef WITH_X11_XINPUT
+ if ((m_system->m_xinput_version.present) &&
+ (m_system->m_xinput_version.major_version >= 2))
+ {
+ int device_id;
+ if (XIGetClientPointer(m_display, None, &device_id) != False) {
+ XIWarpPointer(m_display, device_id, None, None, 0, 0, 0, 0, 0, 0);
+ }
+ }
+ else
+#endif
+ {
+ XWarpPointer(m_display, None, None, 0, 0, 0, 0, 0, 0);
+ }
}
/* Almost works without but important otherwise the mouse GHOST location can be incorrect on exit */
diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h
index 5beb7b43032..9380aa9d631 100644
--- a/intern/ghost/intern/GHOST_WindowX11.h
+++ b/intern/ghost/intern/GHOST_WindowX11.h
@@ -73,6 +73,7 @@ public:
* \param parentWindow Parent (embedder) window
* \param type The type of drawing context installed in this window.
* \param stereoVisual Stereo visual for quad buffered stereo.
+ * \param alphaBackground Enable alpha blending of window with display background
* \param numOfAASamples Number of samples used for AA (zero if no AA)
*/
GHOST_WindowX11(
@@ -88,6 +89,7 @@ public:
GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone,
const bool stereoVisual = false,
const bool exclusive = false,
+ const bool alphaBackground = false,
const GHOST_TUns16 numOfAASamples = 0,
const bool is_debug = false
);
@@ -210,6 +212,10 @@ public:
bool createX11_XIC();
#endif
+#ifdef WITH_X11_XINPUT
+ void refreshXInputDevices();
+#endif
+
#ifdef WITH_XDND
GHOST_DropTargetX11 *getDropTarget()
{
@@ -313,14 +319,11 @@ private:
Cursor
getEmptyCursor(
);
-
-#ifdef WITH_X11_XINPUT
- void initXInputDevices();
-#endif
Window m_window;
Display *m_display;
XVisualInfo *m_visualInfo;
+ void *m_fbconfig;
GHOST_TWindowState m_normal_state;
diff --git a/intern/gpudirect/CMakeLists.txt b/intern/gpudirect/CMakeLists.txt
new file mode 100644
index 00000000000..88c09a663b8
--- /dev/null
+++ b/intern/gpudirect/CMakeLists.txt
@@ -0,0 +1,41 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2015, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Blender Foundation.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ # XXX, bad level include!
+ ../../source/blender/blenlib
+)
+
+set(INC_SYS
+ ${GLEW_INCLUDE_PATH}
+)
+
+set(SRC
+ dvpapi.cpp
+ dvpapi.h
+)
+
+blender_add_lib(bf_intern_gpudirect "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/intern/gpudirect/dvpapi.cpp b/intern/gpudirect/dvpapi.cpp
new file mode 100644
index 00000000000..56b58e0a348
--- /dev/null
+++ b/intern/gpudirect/dvpapi.cpp
@@ -0,0 +1,147 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file gpudirect/dvpapi.c
+ * \ingroup gpudirect
+ */
+
+#ifdef WIN32
+
+#include <stdlib.h>
+#include "dvpapi.h"
+
+extern "C" {
+#include "BLI_dynlib.h"
+}
+
+#define KDVPAPI_Name "dvp.dll"
+
+typedef DVPStatus (DVPAPIENTRY * PFNDVPINITGLCONTEXT) (uint32_t flags);
+typedef DVPStatus (DVPAPIENTRY * PFNDVPCLOSEGLCONTEXT) (void);
+typedef DVPStatus (DVPAPIENTRY * PFNDVPGETLIBRARYVERSION)(uint32_t *major, uint32_t *minor);
+
+static uint32_t __dvpMajorVersion = 0;
+static uint32_t __dvpMinorVersion = 0;
+static PFNDVPGETLIBRARYVERSION __dvpGetLibrayVersion = NULL;
+static PFNDVPINITGLCONTEXT __dvpInitGLContext = NULL;
+static PFNDVPCLOSEGLCONTEXT __dvpCloseGLContext = NULL;
+PFNDVPBEGIN __dvpBegin = NULL;
+PFNDVPEND __dvpEnd = NULL;
+PFNDVPCREATEBUFFER __dvpCreateBuffer = NULL;
+PFNDVPDESTROYBUFFER __dvpDestroyBuffer = NULL;
+PFNDVPFREEBUFFER __dvpFreeBuffer = NULL;
+PFNDVPMEMCPYLINED __dvpMemcpyLined = NULL;
+PFNDVPMEMCPY __dvpMemcpy = NULL;
+PFNDVPIMPORTSYNCOBJECT __dvpImportSyncObject = NULL;
+PFNDVPFREESYNCOBJECT __dvpFreeSyncObject = NULL;
+PFNDVPMAPBUFFERENDAPI __dvpMapBufferEndAPI = NULL;
+PFNDVPMAPBUFFERWAITDVP __dvpMapBufferWaitDVP = NULL;
+PFNDVPMAPBUFFERENDDVP __dvpMapBufferEndDVP = NULL;
+PFNDVPMAPBUFFERWAITAPI __dvpMapBufferWaitAPI = NULL;
+PFNDVPBINDTOGLCTX __dvpBindToGLCtx = NULL;
+PFNDVPGETREQUIREDCONSTANTSGLCTX __dvpGetRequiredConstantsGLCtx = NULL;
+PFNDVPCREATEGPUTEXTUREGL __dvpCreateGPUTextureGL = NULL;
+PFNDVPUNBINDFROMGLCTX __dvpUnbindFromGLCtx = NULL;
+
+static DynamicLibrary *__dvpLibrary = NULL;
+
+DVPStatus dvpGetLibrayVersion(uint32_t *major, uint32_t *minor)
+{
+ if (!__dvpLibrary)
+ return DVP_STATUS_ERROR;
+ *major = __dvpMajorVersion;
+ *minor = __dvpMinorVersion;
+ return DVP_STATUS_OK;
+}
+
+DVPStatus dvpInitGLContext(uint32_t flags)
+{
+ DVPStatus status;
+ if (!__dvpLibrary) {
+ __dvpLibrary = BLI_dynlib_open(KDVPAPI_Name);
+ if (!__dvpLibrary) {
+ return DVP_STATUS_ERROR;
+ }
+// "?dvpInitGLContext@@YA?AW4DVPStatus@@I@Z";
+ __dvpInitGLContext = (PFNDVPINITGLCONTEXT)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpInitGLContext@@YA?AW4DVPStatus@@I@Z");
+ __dvpCloseGLContext = (PFNDVPCLOSEGLCONTEXT)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpCloseGLContext@@YA?AW4DVPStatus@@XZ");
+ __dvpGetLibrayVersion = (PFNDVPGETLIBRARYVERSION)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpGetLibrayVersion@@YA?AW4DVPStatus@@PEAI0@Z");
+ __dvpBegin = (PFNDVPBEGIN)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpBegin@@YA?AW4DVPStatus@@XZ");
+ __dvpEnd = (PFNDVPEND)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpEnd@@YA?AW4DVPStatus@@XZ");
+ __dvpCreateBuffer = (PFNDVPCREATEBUFFER)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpCreateBuffer@@YA?AW4DVPStatus@@PEAUDVPSysmemBufferDescRec@@PEA_K@Z");
+ __dvpDestroyBuffer = (PFNDVPDESTROYBUFFER)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpDestroyBuffer@@YA?AW4DVPStatus@@_K@Z");
+ __dvpFreeBuffer = (PFNDVPFREEBUFFER)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpFreeBuffer@@YA?AW4DVPStatus@@_K@Z");
+ __dvpMemcpyLined = (PFNDVPMEMCPYLINED)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpMemcpyLined@@YA?AW4DVPStatus@@_K0I000III@Z");
+ __dvpMemcpy = (PFNDVPMEMCPY)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpMemcpy2D@@YA?AW4DVPStatus@@_K0I000IIIII@Z");
+ __dvpImportSyncObject = (PFNDVPIMPORTSYNCOBJECT)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpImportSyncObject@@YA?AW4DVPStatus@@PEAUDVPSyncObjectDescRec@@PEA_K@Z");
+ __dvpFreeSyncObject = (PFNDVPFREESYNCOBJECT)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpFreeSyncObject@@YA?AW4DVPStatus@@_K@Z");
+ __dvpMapBufferEndAPI = (PFNDVPMAPBUFFERENDAPI)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpMapBufferEndAPI@@YA?AW4DVPStatus@@_K@Z");
+ __dvpMapBufferWaitDVP = (PFNDVPMAPBUFFERWAITDVP)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpMapBufferWaitDVP@@YA?AW4DVPStatus@@_K@Z");
+ __dvpMapBufferEndDVP = (PFNDVPMAPBUFFERENDDVP)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpMapBufferEndDVP@@YA?AW4DVPStatus@@_K@Z");
+ __dvpMapBufferWaitAPI = (PFNDVPMAPBUFFERWAITAPI)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpMapBufferWaitAPI@@YA?AW4DVPStatus@@_K@Z");
+ __dvpBindToGLCtx = (PFNDVPBINDTOGLCTX)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpBindToGLCtx@@YA?AW4DVPStatus@@_K@Z");
+ __dvpGetRequiredConstantsGLCtx = (PFNDVPGETREQUIREDCONSTANTSGLCTX)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpGetRequiredConstantsGLCtx@@YA?AW4DVPStatus@@PEAI00000@Z");
+ __dvpCreateGPUTextureGL = (PFNDVPCREATEGPUTEXTUREGL)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpCreateGPUTextureGL@@YA?AW4DVPStatus@@IPEA_K@Z");
+ __dvpUnbindFromGLCtx = (PFNDVPUNBINDFROMGLCTX)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpUnbindFromGLCtx@@YA?AW4DVPStatus@@_K@Z");
+ if (!__dvpInitGLContext ||
+ !__dvpCloseGLContext ||
+ !__dvpGetLibrayVersion ||
+ !__dvpBegin ||
+ !__dvpEnd ||
+ !__dvpCreateBuffer ||
+ !__dvpDestroyBuffer ||
+ !__dvpFreeBuffer ||
+ !__dvpMemcpyLined ||
+ !__dvpMemcpy ||
+ !__dvpImportSyncObject ||
+ !__dvpFreeSyncObject ||
+ !__dvpMapBufferEndAPI ||
+ !__dvpMapBufferWaitDVP ||
+ !__dvpMapBufferEndDVP ||
+ !__dvpMapBufferWaitAPI ||
+ !__dvpBindToGLCtx ||
+ !__dvpGetRequiredConstantsGLCtx ||
+ !__dvpCreateGPUTextureGL ||
+ !__dvpUnbindFromGLCtx)
+ {
+ return DVP_STATUS_ERROR;
+ }
+ // check that the library version is what we want
+ if ((status = __dvpGetLibrayVersion(&__dvpMajorVersion, &__dvpMinorVersion)) != DVP_STATUS_OK)
+ return status;
+ if (__dvpMajorVersion != DVP_MAJOR_VERSION || __dvpMinorVersion < DVP_MINOR_VERSION)
+ return DVP_STATUS_ERROR;
+ }
+ return (!__dvpInitGLContext) ? DVP_STATUS_ERROR : __dvpInitGLContext(flags);
+}
+
+DVPStatus dvpCloseGLContext(void)
+{
+ return (!__dvpCloseGLContext) ? DVP_STATUS_ERROR : __dvpCloseGLContext();
+}
+
+#endif // WIN32
diff --git a/intern/gpudirect/dvpapi.h b/intern/gpudirect/dvpapi.h
new file mode 100644
index 00000000000..cafc4e862ae
--- /dev/null
+++ b/intern/gpudirect/dvpapi.h
@@ -0,0 +1,667 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file gpudirect/dvpapi.h
+ * \ingroup gpudirect
+ */
+
+#ifndef __DVPAPI_H__
+#define __DVPAPI_H__
+
+#ifdef WIN32
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "GL/glew.h"
+
+#if defined(__GNUC__) && __GNUC__>=4
+# define DVPAPI extern __attribute__ ((visibility("default")))
+#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+# define DVPAPI extern __global
+#else
+# define DVPAPI extern
+#endif
+
+#define DVPAPIENTRY
+#define DVP_MAJOR_VERSION 1
+#define DVP_MINOR_VERSION 63
+
+typedef uint64_t DVPBufferHandle;
+typedef uint64_t DVPSyncObjectHandle;
+
+typedef enum {
+ DVP_STATUS_OK = 0,
+ DVP_STATUS_INVALID_PARAMETER = 1,
+ DVP_STATUS_UNSUPPORTED = 2,
+ DVP_STATUS_END_ENUMERATION = 3,
+ DVP_STATUS_INVALID_DEVICE = 4,
+ DVP_STATUS_OUT_OF_MEMORY = 5,
+ DVP_STATUS_INVALID_OPERATION = 6,
+ DVP_STATUS_TIMEOUT = 7,
+ DVP_STATUS_INVALID_CONTEXT = 8,
+ DVP_STATUS_INVALID_RESOURCE_TYPE = 9,
+ DVP_STATUS_INVALID_FORMAT_OR_TYPE = 10,
+ DVP_STATUS_DEVICE_UNINITIALIZED = 11,
+ DVP_STATUS_UNSIGNALED = 12,
+ DVP_STATUS_SYNC_ERROR = 13,
+ DVP_STATUS_SYNC_STILL_BOUND = 14,
+ DVP_STATUS_ERROR = -1,
+} DVPStatus;
+
+// Pixel component formats stored in the system memory buffer
+// analogous to those defined in the OpenGL API, except for
+// DVP_BUFFER and the DVP_CUDA_* types. DVP_BUFFER provides
+// an unspecified format type to allow for general interpretation
+// of the bytes at a later stage (in GPU shader). Note that not
+// all paths will achieve optimal speeds due to lack of HW support
+// for the transformation. The CUDA types are to be used when
+// copying to/from a system memory buffer from-to a CUDA array, as the
+// CUDA array implies a memory layout that matches the array.
+typedef enum {
+ DVP_BUFFER, // Buffer treated as a raw buffer
+ // and copied directly into GPU buffer
+ // without any interpretation of the
+ // stored bytes.
+ DVP_DEPTH_COMPONENT,
+ DVP_RGBA,
+ DVP_BGRA,
+ DVP_RED,
+ DVP_GREEN,
+ DVP_BLUE,
+ DVP_ALPHA,
+ DVP_RGB,
+ DVP_BGR,
+ DVP_LUMINANCE,
+ DVP_LUMINANCE_ALPHA,
+ DVP_CUDA_1_CHANNEL,
+ DVP_CUDA_2_CHANNELS,
+ DVP_CUDA_4_CHANNELS,
+ DVP_RGBA_INTEGER,
+ DVP_BGRA_INTEGER,
+ DVP_RED_INTEGER,
+ DVP_GREEN_INTEGER,
+ DVP_BLUE_INTEGER,
+ DVP_ALPHA_INTEGER,
+ DVP_RGB_INTEGER,
+ DVP_BGR_INTEGER,
+ DVP_LUMINANCE_INTEGER,
+ DVP_LUMINANCE_ALPHA_INTEGER,
+} DVPBufferFormats;
+
+// Possible pixel component storage types for system memory buffers
+typedef enum {
+ DVP_UNSIGNED_BYTE,
+ DVP_BYTE,
+ DVP_UNSIGNED_SHORT,
+ DVP_SHORT,
+ DVP_UNSIGNED_INT,
+ DVP_INT,
+ DVP_FLOAT,
+ DVP_HALF_FLOAT,
+ DVP_UNSIGNED_BYTE_3_3_2,
+ DVP_UNSIGNED_BYTE_2_3_3_REV,
+ DVP_UNSIGNED_SHORT_5_6_5,
+ DVP_UNSIGNED_SHORT_5_6_5_REV,
+ DVP_UNSIGNED_SHORT_4_4_4_4,
+ DVP_UNSIGNED_SHORT_4_4_4_4_REV,
+ DVP_UNSIGNED_SHORT_5_5_5_1,
+ DVP_UNSIGNED_SHORT_1_5_5_5_REV,
+ DVP_UNSIGNED_INT_8_8_8_8,
+ DVP_UNSIGNED_INT_8_8_8_8_REV,
+ DVP_UNSIGNED_INT_10_10_10_2,
+ DVP_UNSIGNED_INT_2_10_10_10_REV,
+} DVPBufferTypes;
+
+// System memory descriptor describing the size and storage formats
+// of the buffer
+typedef struct DVPSysmemBufferDescRec {
+ uint32_t width; // Buffer Width
+ uint32_t height; // Buffer Height
+ uint32_t stride; // Stride
+ uint32_t size; // Specifies the surface size if
+ // format == DVP_BUFFER
+ DVPBufferFormats format; // see enum above
+ DVPBufferTypes type; // see enum above
+ void *bufAddr; // Buffer memory address
+} DVPSysmemBufferDesc;
+
+// Flags specified at sync object creation:
+// ----------------------------------------
+// Tells the implementation to use events wherever
+// possible instead of software spin loops. Note if HW
+// wait operations are supported by the implementation
+// then events will not be used in the dvpMemcpy*
+// functions. In such a case, events may still be used
+// in dvpSyncObjClientWait* functions.
+#define DVP_SYNC_OBJECT_FLAGS_USE_EVENTS 0x00000001
+
+typedef struct DVPSyncObjectDescRec {
+ uint32_t *sem; // Location to write semaphore value
+ uint32_t flags; // See above DVP_SYNC_OBJECT_FLAGS_* bits
+ DVPStatus (*externalClientWaitFunc) (DVPSyncObjectHandle sync,
+ uint32_t value,
+ bool GEQ, // If true then the function should wait for the sync value to be
+ // greater than or equal to the value parameter. Otherwise just a
+ // straight forward equality comparison should be performed.
+ uint64_t timeout);
+ // If non-null, externalClientWaitFunc allows the DVP library
+ // to call the application to wait for a sync object to be
+ // released. This allows the application to create events,
+ // which can be triggered on device interrupts instead of
+ // using spin loops inside the DVP library. Upon succeeding
+ // the function must return DVP_STATUS_OK, non-zero for failure
+ // and DVP_STATUS_TIMEOUT on timeout. The externalClientWaitFunc should
+ // not alter the current GL or CUDA context state
+} DVPSyncObjectDesc;
+
+// Time used when event timeouts should be ignored
+#define DVP_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull
+
+typedef DVPStatus (DVPAPIENTRY * PFNDVPBEGIN) (void);
+typedef DVPStatus (DVPAPIENTRY * PFNDVPEND) (void);
+typedef DVPStatus (DVPAPIENTRY * PFNDVPCREATEBUFFER)(DVPSysmemBufferDesc *desc, DVPBufferHandle *hBuf);
+typedef DVPStatus (DVPAPIENTRY * PFNDVPDESTROYBUFFER)(DVPBufferHandle hBuf);
+typedef DVPStatus (DVPAPIENTRY * PFNDVPFREEBUFFER)(DVPBufferHandle gpuBufferHandle);
+typedef DVPStatus (DVPAPIENTRY * PFNDVPMEMCPYLINED)(DVPBufferHandle srcBuffer,
+ DVPSyncObjectHandle srcSync,
+ uint32_t srcAcquireValue,
+ uint64_t timeout,
+ DVPBufferHandle dstBuffer,
+ DVPSyncObjectHandle dstSync,
+ uint32_t dstReleaseValue,
+ uint32_t startingLine,
+ uint32_t numberOfLines);
+typedef DVPStatus (DVPAPIENTRY * PFNDVPMEMCPY)(DVPBufferHandle srcBuffer,
+ DVPSyncObjectHandle srcSync,
+ uint32_t srcAcquireValue,
+ uint64_t timeout,
+ DVPBufferHandle dstBuffer,
+ DVPSyncObjectHandle dstSync,
+ uint32_t dstReleaseValue,
+ uint32_t srcOffset,
+ uint32_t dstOffset,
+ uint32_t count);
+typedef DVPStatus (DVPAPIENTRY * PFNDVPIMPORTSYNCOBJECT)(DVPSyncObjectDesc *desc,
+ DVPSyncObjectHandle *syncObject);
+typedef DVPStatus (DVPAPIENTRY * PFNDVPFREESYNCOBJECT)(DVPSyncObjectHandle syncObject);
+typedef DVPStatus (DVPAPIENTRY * PFNDVPGETREQUIREDCONSTANTSGLCTX)(uint32_t *bufferAddrAlignment,
+ uint32_t *bufferGPUStrideAlignment,
+ uint32_t *semaphoreAddrAlignment,
+ uint32_t *semaphoreAllocSize,
+ uint32_t *semaphorePayloadOffset,
+ uint32_t *semaphorePayloadSize);
+typedef DVPStatus (DVPAPIENTRY * PFNDVPBINDTOGLCTX)(DVPBufferHandle hBuf);
+typedef DVPStatus (DVPAPIENTRY * PFNDVPUNBINDFROMGLCTX)(DVPBufferHandle hBuf);
+typedef DVPStatus (DVPAPIENTRY * PFNDVPMAPBUFFERENDAPI)(DVPBufferHandle gpuBufferHandle);
+typedef DVPStatus (DVPAPIENTRY * PFNDVPMAPBUFFERWAITDVP)(DVPBufferHandle gpuBufferHandle);
+typedef DVPStatus (DVPAPIENTRY * PFNDVPMAPBUFFERENDDVP)(DVPBufferHandle gpuBufferHandle);
+typedef DVPStatus (DVPAPIENTRY * PFNDVPMAPBUFFERWAITAPI)(DVPBufferHandle gpuBufferHandle);
+typedef DVPStatus (DVPAPIENTRY * PFNDVPCREATEGPUTEXTUREGL)(GLuint texID,
+ DVPBufferHandle *bufferHandle);
+
+// Flags supplied to the dvpInit* functions:
+//
+// DVP_DEVICE_FLAGS_SHARE_APP_CONTEXT is only supported for OpenGL
+// contexts and is the only supported flag for CUDA. It allows for
+// certain cases to be optimized by sharing the context
+// of the application for the DVP operations. This removes the
+// need to do certain synchronizations. See issue 5 for parallel
+// issues. When used, the app's GL context must be current for all calls
+// to the DVP library.
+// the DVP library.
+#define DVP_DEVICE_FLAGS_SHARE_APP_CONTEXT 0x000000001
+
+//------------------------------------------------------------------------
+// Function: dvpInitGLContext
+//
+// To be called before any DVP resources are allocated.
+// This call allows for specification of flags that may
+// change the way DVP operations are performed. See above
+// for the list of flags.
+//
+// The OpenGL context must be current at time of call.
+//
+// Parameters: flags[IN] - Buffer description structure
+//
+// Returns: DVP_STATUS_OK
+// DVP_STATUS_INVALID_PARAMETER
+// DVP_STATUS_ERROR
+//------------------------------------------------------------------------
+extern DVPStatus dvpInitGLContext(uint32_t flags);
+
+//------------------------------------------------------------------------
+// Function: dvpCloseGLContext
+//
+// Function to be called when app closes to allow freeing
+// of any DVP library allocated resources.
+//
+// The OpenGL context must be current at time of call.
+//
+// Parameters: none
+//
+// Returns: DVP_STATUS_OK
+// DVP_STATUS_INVALID_PARAMETER
+// DVP_STATUS_ERROR
+//------------------------------------------------------------------------
+extern DVPStatus dvpCloseGLContext();
+
+//------------------------------------------------------------------------
+// Function: dvpGetLibrayVersion
+//
+// Description: Returns the current version of the library
+//
+// Parameters: major[OUT] - returned major version
+// minor[OUT] - returned minor version
+//
+// Returns: DVP_STATUS_OK
+//------------------------------------------------------------------------
+extern DVPStatus dvpGetLibrayVersion(uint32_t *major, uint32_t *minor);
+
+//------------------------------------------------------------------------
+// Function: dvpBegin
+//
+// Description: dvpBegin must be called before any combination of DVP
+// function calls dvpMemCpy*, dvpMapBufferWaitDVP,
+// dvpSyncObjClientWait*, and dvpMapBufferEndDVP. After
+// the last of these functions has been called is dvpEnd
+// must be called. This allows for more efficient batched
+// DVP operations.
+//
+// Parameters: none
+//
+// Returns: DVP_STATUS_OK
+// DVP_STATUS_ERROR
+//------------------------------------------------------------------------
+#define dvpBegin DVPAPI_GET_FUN(__dvpBegin)
+
+//------------------------------------------------------------------------
+// Function: dvpEnd
+//
+// Description: dvpEnd signals the end of a batch of DVP function calls
+// that began with dvpBegin
+//
+// Parameters: none
+//
+// Returns: DVP_STATUS_OK
+// DVP_STATUS_ERROR
+//------------------------------------------------------------------------
+#define dvpEnd DVPAPI_GET_FUN(__dvpEnd)
+
+
+//------------------------------------------------------------------------
+// Function: dvpCreateBuffer
+//
+// Description: Create a DVP buffer using system memory, wrapping a user
+// passed pointer. The pointer must be aligned
+// to values returned by dvpGetRequiredAlignments*
+//
+// Parameters: desc[IN] - Buffer description structure
+// hBuf[OUT] - DVP Buffer handle
+//
+// Returns: DVP_STATUS_OK
+// DVP_STATUS_INVALID_PARAMETER
+// DVP_STATUS_ERROR
+//------------------------------------------------------------------------
+#define dvpCreateBuffer DVPAPI_GET_FUN(__dvpCreateBuffer)
+
+
+//------------------------------------------------------------------------
+// Function: dvpDestroyBuffer
+//
+// Description: Destroy a previously created DVP buffer.
+//
+// Parameters: hBuf[IN] - DVP Buffer handle
+//
+// Returns: DVP_STATUS_OK
+// DVP_STATUS_INVALID_PARAMETER
+// DVP_STATUS_ERROR
+//------------------------------------------------------------------------
+#define dvpDestroyBuffer DVPAPI_GET_FUN(__dvpDestroyBuffer)
+
+//------------------------------------------------------------------------
+// Function: dvpFreeBuffer
+//
+// Description: dvpFreeBuffer frees the DVP buffer reference
+//
+// Parameters: gpuBufferHandle[IN] - DVP Buffer handle
+//
+// Returns: DVP_STATUS_OK
+// DVP_STATUS_INVALID_PARAMETER
+// DVP_STATUS_ERROR
+//------------------------------------------------------------------------
+#define dvpFreeBuffer DVPAPI_GET_FUN(__dvpFreeBuffer)
+
+//------------------------------------------------------------------------
+// Function: dvpMemcpyLined
+//
+// Description: dvpMemcpyLined provides buffer copies between a
+// DVP sysmem buffer and a graphics API texture (as opposed to
+// a buffer type). Other buffer types (such
+// as graphics API buffers) return DVP_STATUS_INVALID_PARAMETER.
+//
+// In addition, see "dvpMemcpy* general comments" above.
+//
+// Parameters: srcBuffer[IN] - src buffer handle
+// srcSync[IN] - sync to acquire on before transfer
+// srcAcquireValue[IN] - value to acquire on before transfer
+// timeout[IN] - time out value in nanoseconds.
+// dstBuffer[IN] - src buffer handle
+// dstSync[IN] - sync to release on transfer completion
+// dstReleaseValue[IN] - value to release on completion
+// startingLine[IN] - starting line of buffer
+// numberOfLines[IN] - number of lines to copy
+//
+// Returns: DVP_STATUS_OK
+// DVP_STATUS_INVALID_PARAMETER
+// DVP_STATUS_ERROR
+//
+// GL state effected: The following GL state may be altered by this
+// function (not relevant if no GL source or destination
+// is used):
+// -GL_PACK_SKIP_ROWS, GL_PACK_SKIP_PIXELS,
+// GL_PACK_ROW_LENGTH
+// -The buffer bound to GL_PIXEL_PACK_BUFFER
+// -The current bound framebuffer (GL_FRAMEBUFFER_EXT)
+// -GL_UNPACK_SKIP_ROWS, GL_UNPACK_SKIP_PIXELS,
+// GL_UNPACK_ROW_LENGTH
+// -The buffer bound to GL_PIXEL_UNPACK_BUFFER
+// -The texture bound to GL_TEXTURE_2D
+//------------------------------------------------------------------------
+#define dvpMemcpyLined DVPAPI_GET_FUN(__dvpMemcpyLined)
+
+
+//------------------------------------------------------------------------
+// Function: dvpMemcpy
+//
+// Description: dvpMemcpy provides buffer copies between a
+// DVP sysmem buffer and a graphics API pure buffer (as
+// opposed to a texture type). Other buffer types (such
+// as graphics API textures) return
+// DVP_STATUS_INVALID_PARAMETER.
+//
+// The start address of the srcBuffer is given by srcOffset
+// and the dstBuffer start address is given by dstOffset.
+//
+// In addition, see "dvpMemcpy* general comments" above.
+//
+// Parameters: srcBuffer[IN] - src buffer handle
+// srcSync[IN] - sync to acquire on before transfer
+// srcAcquireValue[IN] - value to acquire on before transfer
+// timeout[IN] - time out value in nanoseconds.
+// dstBuffer[IN] - src buffer handle
+// dstSync[IN] - sync to release on completion
+// dstReleaseValue[IN] - value to release on completion
+// uint32_t srcOffset[IN] - byte offset of srcBuffer
+// uint32_t dstOffset[IN] - byte offset of dstBuffer
+// uint32_t count[IN] - number of bytes to copy
+//
+// Returns: DVP_STATUS_OK
+// DVP_STATUS_INVALID_PARAMETER
+// DVP_STATUS_ERROR
+//
+// GL state effected: The following GL state may be altered by this
+// function (not relevant if no GL source or destination
+// is used):
+// - The buffer bound to GL_COPY_WRITE_BUFFER
+// - The buffer bound to GL_COPY_READ_BUFFER
+//
+//------------------------------------------------------------------------
+#define dvpMemcpy DVPAPI_GET_FUN(__dvpMemcpy)
+
+//------------------------------------------------------------------------
+// Function: dvpImportSyncObject
+//
+// Description: dvpImportSyncObject creates a DVPSyncObject from the
+// DVPSyncObjectDesc. Note that a sync object is not
+// supported for copy operations targeting different APIs.
+// This means, for example, it is illegal to call dvpMemCpy*
+// for source or target GL texture with sync object A and
+// then later use that same sync object in dvpMemCpy*
+// operation for a source or target CUDA buffer. The same
+// semaphore memory can still be used for two different sync
+// objects.
+//
+// Parameters: desc[IN] - data describing the sync object
+// syncObject[OUT] - handle to sync object
+//
+// Returns: DVP_STATUS_OK
+// DVP_STATUS_INVALID_PARAMETER
+// DVP_STATUS_ERROR
+//------------------------------------------------------------------------
+#define dvpImportSyncObject DVPAPI_GET_FUN(__dvpImportSyncObject)
+
+//------------------------------------------------------------------------
+// Function: dvpFreeSyncObject
+//
+// Description: dvpFreeSyncObject waits for any outstanding releases on
+// this sync object before freeing the resources allocated for
+// the specified sync object. The application must make sure
+// any outstanding acquire operations have already been
+// completed.
+//
+// If OpenGL is being used and the app's GL context is being
+// shared (via the DVP_DEVICE_FLAGS_SHARE_APP_CONTEXT flag),
+// then dvpFreeSyncObject needs to be called while each context,
+// on which the sync object was used, is current. If
+// DVP_DEVICE_FLAGS_SHARE_APP_CONTEXT is used and there are out
+// standing contexts from which this sync object must be free'd
+// then dvpFreeSyncObject will return DVP_STATUS_SYNC_STILL_BOUND.
+//
+// Parameters: syncObject[IN] - handle to sync object to be free'd
+//
+// Returns: DVP_STATUS_OK
+// DVP_STATUS_INVALID_PARAMETER
+// DVP_STATUS_ERROR
+// DVP_STATUS_SYNC_STILL_BOUND
+//------------------------------------------------------------------------
+#define dvpFreeSyncObject DVPAPI_GET_FUN(__dvpFreeSyncObject)
+
+
+//------------------------------------------------------------------------
+// Function: dvpMapBufferEndAPI
+//
+// Description: Tells DVP to setup a signal for this buffer in the
+// callers API context or device. The signal follows all
+// previous API operations up to this point and, thus,
+// allows subsequent DVP calls to know when then this buffer
+// is ready for use within the DVP library. This function
+// would be followed by a call to dvpMapBufferWaitDVP to
+// synchronize rendering in the API stream and the DVP
+// stream.
+//
+// If OpenGL or CUDA is used, the OpenGL/CUDA context
+// must be current at time of call.
+//
+// The use of dvpMapBufferEndAPI is NOT recommended for
+// CUDA synchronisation, as it is more optimal to use a
+// applcation CUDA stream in conjunction with
+// dvpMapBufferEndCUDAStream. This allows the driver to
+// do optimisations, such as parllelise the copy operations
+// and compute.
+//
+// This must be called outside the dvpBegin/dvpEnd pair. In
+// addition, this call is not thread safe and must be called
+// from or fenced against the rendering thread associated with
+// the context or device.
+//
+// Parameters: gpuBufferHandle[IN] - buffer to track
+//
+// Returns: DVP_STATUS_OK
+// DVP_STATUS_INVALID_PARAMETER
+// DVP_STATUS_ERROR
+// DVP_STATUS_UNSIGNALED - returned if the API is
+// unable to place a signal in the API context queue
+//------------------------------------------------------------------------
+#define dvpMapBufferEndAPI DVPAPI_GET_FUN(__dvpMapBufferEndAPI)
+
+//------------------------------------------------------------------------
+// Function: dvpMapBufferEndAPI
+//
+// Description: Tells DVP to setup a signal for this buffer in the
+// callers API context or device. The signal follows all
+// previous API operations up to this point and, thus,
+// allows subsequent DVP calls to know when then this buffer
+// is ready for use within the DVP library. This function
+// would be followed by a call to dvpMapBufferWaitDVP to
+// synchronize rendering in the API stream and the DVP
+// stream.
+//
+// If OpenGL or CUDA is used, the OpenGL/CUDA context
+// must be current at time of call.
+//
+// The use of dvpMapBufferEndAPI is NOT recommended for
+// CUDA synchronisation, as it is more optimal to use a
+// applcation CUDA stream in conjunction with
+// dvpMapBufferEndCUDAStream. This allows the driver to
+// do optimisations, such as parllelise the copy operations
+// and compute.
+//
+// This must be called outside the dvpBegin/dvpEnd pair. In
+// addition, this call is not thread safe and must be called
+// from or fenced against the rendering thread associated with
+// the context or device.
+//
+// Parameters: gpuBufferHandle[IN] - buffer to track
+//
+// Returns: DVP_STATUS_OK
+// DVP_STATUS_INVALID_PARAMETER
+// DVP_STATUS_ERROR
+// DVP_STATUS_UNSIGNALED - returned if the API is
+// unable to place a signal in the API context queue
+//------------------------------------------------------------------------
+#define dvpMapBufferEndAPI DVPAPI_GET_FUN(__dvpMapBufferEndAPI)
+
+//------------------------------------------------------------------------
+// Function: dvpMapBufferWaitDVP
+//
+// Description: Tells DVP to make the DVP stream wait for a previous
+// signal triggered by a dvpMapBufferEndAPI call.
+//
+// This must be called inside the dvpBegin/dvpEnd pair.
+//
+// Parameters: gpuBufferHandle[IN] - buffer to track
+//
+// Returns: DVP_STATUS_OK
+// DVP_STATUS_INVALID_PARAMETER
+// DVP_STATUS_ERROR
+//------------------------------------------------------------------------
+#define dvpMapBufferWaitDVP DVPAPI_GET_FUN(__dvpMapBufferWaitDVP)
+
+//------------------------------------------------------------------------
+// Function: dvpMapBufferEndDVP
+//
+// Description: Tells DVP to setup a signal for this buffer after
+// DVP operations are complete. The signal allows
+// the API to know when then this buffer is
+// ready for use within a API stream. This function would
+// be followed by a call to dvpMapBufferWaitAPI to
+// synchronize copies in the DVP stream and the API
+// rendering stream.
+//
+// This must be called inside the dvpBegin/dvpEnd pair.
+//
+// Parameters: gpuBufferHandle[IN] - buffer to track
+//
+// Returns: DVP_STATUS_OK
+// DVP_STATUS_INVALID_PARAMETER
+// DVP_STATUS_ERROR
+//------------------------------------------------------------------------
+#define dvpMapBufferEndDVP DVPAPI_GET_FUN(__dvpMapBufferEndDVP)
+
+//------------------------------------------------------------------------
+// Function: dvpMapBufferWaitAPI
+//
+// Description: Tells DVP to make the current API context or device to
+// wait for a previous signal triggered by a
+// dvpMapBufferEndDVP call.
+//
+// The use of dvpMapBufferWaitCUDAStream is NOT recommended for
+// CUDA synchronisation, as it is more optimal to use a
+// applcation CUDA stream in conjunction with
+// dvpMapBufferEndCUDAStream. This allows the driver to
+// do optimisations, such as parllelise the copy operations
+// and compute.
+//
+// If OpenGL or CUDA is used, the OpenGL/CUDA context
+// must be current at time of call.
+//
+// This must be called outside the dvpBegin/dvpEnd pair. In
+// addition, this call is not thread safe and must be called
+// from or fenced against the rendering thread associated with
+// the context or device.
+//
+// Parameters: gpuBufferHandle[IN] - buffer to track
+//
+// Returns: DVP_STATUS_OK
+// DVP_STATUS_INVALID_PARAMETER
+// DVP_STATUS_ERROR
+//------------------------------------------------------------------------
+#define dvpMapBufferWaitAPI DVPAPI_GET_FUN(__dvpMapBufferWaitAPI)
+
+//------------------------------------------------------------------------
+// If the multiple GL contexts used in the application access the same
+// sysmem buffers, then application must create those GL contexts with
+// display list shared.
+//------------------------------------------------------------------------
+#define dvpBindToGLCtx DVPAPI_GET_FUN(__dvpBindToGLCtx)
+#define dvpGetRequiredConstantsGLCtx DVPAPI_GET_FUN(__dvpGetRequiredConstantsGLCtx)
+#define dvpCreateGPUTextureGL DVPAPI_GET_FUN(__dvpCreateGPUTextureGL)
+#define dvpUnbindFromGLCtx DVPAPI_GET_FUN(__dvpUnbindFromGLCtx)
+
+
+DVPAPI PFNDVPBEGIN __dvpBegin;
+DVPAPI PFNDVPEND __dvpEnd;
+DVPAPI PFNDVPCREATEBUFFER __dvpCreateBuffer;
+DVPAPI PFNDVPDESTROYBUFFER __dvpDestroyBuffer;
+DVPAPI PFNDVPFREEBUFFER __dvpFreeBuffer;
+DVPAPI PFNDVPMEMCPYLINED __dvpMemcpyLined;
+DVPAPI PFNDVPMEMCPY __dvpMemcpy;
+DVPAPI PFNDVPIMPORTSYNCOBJECT __dvpImportSyncObject;
+DVPAPI PFNDVPFREESYNCOBJECT __dvpFreeSyncObject;
+DVPAPI PFNDVPMAPBUFFERENDAPI __dvpMapBufferEndAPI;
+DVPAPI PFNDVPMAPBUFFERWAITDVP __dvpMapBufferWaitDVP;
+DVPAPI PFNDVPMAPBUFFERENDDVP __dvpMapBufferEndDVP;
+DVPAPI PFNDVPMAPBUFFERWAITAPI __dvpMapBufferWaitAPI;
+
+
+//------------------------------------------------------------------------
+// If the multiple GL contexts used in the application access the same
+// sysmem buffers, then application must create those GL contexts with
+// display list shared.
+//------------------------------------------------------------------------
+DVPAPI PFNDVPBINDTOGLCTX __dvpBindToGLCtx;
+DVPAPI PFNDVPGETREQUIREDCONSTANTSGLCTX __dvpGetRequiredConstantsGLCtx;
+DVPAPI PFNDVPCREATEGPUTEXTUREGL __dvpCreateGPUTextureGL;
+DVPAPI PFNDVPUNBINDFROMGLCTX __dvpUnbindFromGLCtx;
+
+#define DVPAPI_GET_FUN(x) x
+
+#endif // WIN32
+
+#endif // __DVPAPI_H__
+
diff --git a/intern/guardedalloc/test/simpletest/memtest.c b/intern/guardedalloc/test/simpletest/memtest.c
index 841b47bd4f1..79d55dd02cc 100644
--- a/intern/guardedalloc/test/simpletest/memtest.c
+++ b/intern/guardedalloc/test/simpletest/memtest.c
@@ -26,7 +26,6 @@
*/
/**
-
* Copyright (C) 2001 NaN Technologies B.V.
* Simple test of memory.
*/
diff --git a/intern/itasc/ConstraintSet.cpp b/intern/itasc/ConstraintSet.cpp
index e21cd36e4c8..0baf580ca68 100644
--- a/intern/itasc/ConstraintSet.cpp
+++ b/intern/itasc/ConstraintSet.cpp
@@ -145,27 +145,29 @@ bool ConstraintSet::closeLoop(){
//toggle=!toggle;
//svd_boost_Macie(Jf,U,S,V,B,temp,1e-3*threshold,toggle);
int ret = KDL::svd_eigen_HH(m_Jf,m_U,m_S,m_V,m_temp);
- if(ret<0)
- return false;
+ if(ret<0)
+ return false;
// the reference point and frame of the jacobian is the base frame
// m_externalPose-m_internalPose is the twist to extend the end effector
// to get the required pose => change the reference point to the base frame
Twist twist_delta(diff(m_internalPose,m_externalPose));
twist_delta=twist_delta.RefPoint(-m_internalPose.p);
- for(unsigned int i=0;i<6;i++)
- m_tdelta(i)=twist_delta(i);
- //TODO: use damping in constraintset inversion?
- for(unsigned int i=0;i<6;i++)
- if(m_S(i)<m_threshold){
+ for(unsigned int i=0;i<6;i++)
+ m_tdelta(i)=twist_delta(i);
+ //TODO: use damping in constraintset inversion?
+ for(unsigned int i=0;i<6;i++) {
+ if(m_S(i)<m_threshold){
m_B.row(i).setConstant(0.0);
- }else
- m_B.row(i) = m_U.col(i)/m_S(i);
+ } else {
+ m_B.row(i) = m_U.col(i)/m_S(i);
+ }
+ }
- m_Jf_inv.noalias()=m_V*m_B;
+ m_Jf_inv.noalias()=m_V*m_B;
- m_chi.noalias()+=m_Jf_inv*m_tdelta;
- updateJacobian();
+ m_chi.noalias()+=m_Jf_inv*m_tdelta;
+ updateJacobian();
// m_externalPose-m_internalPose in end effector frame
// this is just to compare the pose, a different formula would work too
return Equal(m_internalPose.Inverse()*m_externalPose,F_identity,m_threshold);
diff --git a/intern/itasc/Scene.cpp b/intern/itasc/Scene.cpp
index 7ed8fc4e63c..5768a994970 100644
--- a/intern/itasc/Scene.cpp
+++ b/intern/itasc/Scene.cpp
@@ -146,11 +146,11 @@ bool Scene::addObject(const std::string& name, Object* object, UncontrolledObjec
bool Scene::addConstraintSet(const std::string& name,ConstraintSet* task,const std::string& object1,const std::string& object2, const std::string& ee1, const std::string& ee2)
{
- //Check if objects exist:
- ObjectMap::iterator object1_it = objects.find(object1);
- ObjectMap::iterator object2_it = objects.find(object2);
- if(object1_it==objects.end()||object2_it==objects.end())
- return false;
+ //Check if objects exist:
+ ObjectMap::iterator object1_it = objects.find(object1);
+ ObjectMap::iterator object2_it = objects.find(object2);
+ if(object1_it==objects.end()||object2_it==objects.end())
+ return false;
int ee1_index = object1_it->second->object->addEndEffector(ee1);
int ee2_index = object2_it->second->object->addEndEffector(ee2);
if (ee1_index < 0 || ee2_index < 0)
@@ -159,11 +159,11 @@ bool Scene::addConstraintSet(const std::string& name,ConstraintSet* task,const s
constraints.insert(ConstraintMap::value_type(name,new ConstraintSet_struct(
task,object1_it,ee1_index,object2_it,ee2_index,
Range(m_ncTotal,task->getNrOfConstraints()),Range(6*m_nsets,6))));
- if(!result.second)
- return false;
- m_ncTotal+=task->getNrOfConstraints();
- m_nsets+=1;
- return true;
+ if(!result.second)
+ return false;
+ m_ncTotal+=task->getNrOfConstraints();
+ m_nsets+=1;
+ return true;
}
bool Scene::addSolver(Solver* _solver){
diff --git a/intern/itasc/WSDLSSolver.cpp b/intern/itasc/WSDLSSolver.cpp
index 6fdd8e6e06c..2514dbb9041 100644
--- a/intern/itasc/WSDLSSolver.cpp
+++ b/intern/itasc/WSDLSSolver.cpp
@@ -60,7 +60,7 @@ bool WSDLSSolver::solve(const e_matrix& A, const e_vector& Wy, const e_vector& y
e_scalar N, M;
// Create the Weighted jacobian
- m_AWq.noalias() = A*Wq;
+ m_AWq.noalias() = A*Wq;
for (i=0; i<m_nc; i++)
m_WyAWq.row(i) = Wy(i)*m_AWq.row(i);
@@ -72,11 +72,11 @@ bool WSDLSSolver::solve(const e_matrix& A, const e_vector& Wy, const e_vector& y
} else {
ret = KDL::svd_eigen_HH(m_WyAWq,m_U,m_S,m_V,m_temp);
}
- if(ret<0)
- return false;
+ if(ret<0)
+ return false;
m_Wy_ydot = Wy.array() * ydot.array();
- m_WqV.noalias() = Wq*m_V;
+ m_WqV.noalias() = Wq*m_V;
qdot.setZero();
e_scalar maxDeltaS = e_scalar(0.0);
e_scalar prevS = e_scalar(0.0);
diff --git a/intern/libmv/intern/autotrack.cc b/intern/libmv/intern/autotrack.cc
index f0cbc68f11e..3b7c9c5a010 100644
--- a/intern/libmv/intern/autotrack.cc
+++ b/intern/libmv/intern/autotrack.cc
@@ -67,12 +67,12 @@ int libmv_autoTrackMarker(libmv_AutoTrack* libmv_autotrack,
libmv_apiMarkerToMarker(*libmv_tracked_marker, &tracked_marker);
libmv_configureTrackRegionOptions(*libmv_options,
&options);
- (((AutoTrack*) libmv_autotrack)->TrackMarker(&tracked_marker,
- &result,
- &options));
+ bool ok = (((AutoTrack*) libmv_autotrack)->TrackMarker(&tracked_marker,
+ &result,
+ &options));
libmv_markerToApiMarker(tracked_marker, libmv_tracked_marker);
libmv_regionTrackergetResult(result, libmv_result);
- return result.is_usable();
+ return ok && result.is_usable();
}
void libmv_autoTrackAddMarker(libmv_AutoTrack* libmv_autotrack,
diff --git a/intern/libmv/libmv/multiview/projection.h b/intern/libmv/libmv/multiview/projection.h
index 3220bc2dbbc..8f304f31ec6 100644
--- a/intern/libmv/libmv/multiview/projection.h
+++ b/intern/libmv/libmv/multiview/projection.h
@@ -122,7 +122,7 @@ inline void Project(const Mat34 &P, const Vec3 &X, Vec3 *x) {
inline void Project(const Mat34 &P, const Vec3 &X, Vec2 *x) {
Vec3 hx;
- Project(P, X, x);
+ Project(P, X, &hx);
*x = hx.head<2>() / hx(2);
}
diff --git a/intern/libmv/libmv/numeric/numeric.cc b/intern/libmv/libmv/numeric/numeric.cc
index 9007663c8e2..3fc1e3b2bfd 100644
--- a/intern/libmv/libmv/numeric/numeric.cc
+++ b/intern/libmv/libmv/numeric/numeric.cc
@@ -109,7 +109,7 @@ void MeanAndVarianceAlongRows(const Mat &A,
}
void HorizontalStack(const Mat &left, const Mat &right, Mat *stacked) {
- assert(left.rows() == left.rows());
+ assert(left.rows() == right.rows());
int n = left.rows();
int m1 = left.cols();
int m2 = right.cols();
diff --git a/intern/libmv/libmv/numeric/numeric.h b/intern/libmv/libmv/numeric/numeric.h
index 20a4a29e5ba..a42dab8c7a2 100644
--- a/intern/libmv/libmv/numeric/numeric.h
+++ b/intern/libmv/libmv/numeric/numeric.h
@@ -148,7 +148,7 @@ using Eigen::Matrix;
// A = U * diag(s) * VT
//
template <typename TMat, typename TVec>
-inline void SVD(TMat *A, Vec *s, Mat *U, Mat *VT) {
+inline void SVD(TMat * /*A*/, Vec * /*s*/, Mat * /*U*/, Mat * /*VT*/) {
assert(0);
}
diff --git a/intern/mikktspace/mikktspace.c b/intern/mikktspace/mikktspace.c
index 7e5861ea9ed..0342ae0146f 100644
--- a/intern/mikktspace/mikktspace.c
+++ b/intern/mikktspace/mikktspace.c
@@ -583,10 +583,12 @@ static void MergeVertsFast(int piTriList_in_and_out[], STmpVert pTmpVert[], cons
float dx=0, dy=0, dz=0, fSep=0;
for (c=0; c<3; c++)
{ fvMin[c]=pTmpVert[iL_in].vert[c]; fvMax[c]=fvMin[c]; }
- for (l=(iL_in+1); l<=iR_in; l++)
- for (c=0; c<3; c++)
+ for (l=(iL_in+1); l<=iR_in; l++) {
+ for (c=0; c<3; c++) {
if (fvMin[c]>pTmpVert[l].vert[c]) fvMin[c]=pTmpVert[l].vert[c];
- else if (fvMax[c]<pTmpVert[l].vert[c]) fvMax[c]=pTmpVert[l].vert[c];
+ if (fvMax[c]<pTmpVert[l].vert[c]) fvMax[c]=pTmpVert[l].vert[c];
+ }
+ }
dx = fvMax[0]-fvMin[0];
dy = fvMax[1]-fvMin[1];
@@ -598,6 +600,10 @@ static void MergeVertsFast(int piTriList_in_and_out[], STmpVert pTmpVert[], cons
fSep = 0.5f*(fvMax[channel]+fvMin[channel]);
+ // stop if all vertices are NaNs
+ if (!isfinite(fSep))
+ return;
+
// terminate recursion when the separation/average value
// is no longer strictly between fMin and fMax values.
if (fSep>=fvMax[channel] || fSep<=fvMin[channel])
diff --git a/intern/moto/include/MT_Matrix4x4.h b/intern/moto/include/MT_Matrix4x4.h
index 045cc3b8361..2ecac81ea6f 100644
--- a/intern/moto/include/MT_Matrix4x4.h
+++ b/intern/moto/include/MT_Matrix4x4.h
@@ -144,6 +144,16 @@ public:
}
/**
+ * Scale the rows of this matrix with x, y, z, w respectively.
+ */
+ void tscale(MT_Scalar x, MT_Scalar y, MT_Scalar z, MT_Scalar w) {
+ m_el[0][0] *= x; m_el[1][0] *= y; m_el[2][0] *= z; m_el[3][0] *= w;
+ m_el[0][1] *= x; m_el[1][1] *= y; m_el[2][1] *= z; m_el[3][1] *= w;
+ m_el[0][2] *= x; m_el[1][2] *= y; m_el[2][2] *= z; m_el[3][2] *= w;
+ m_el[0][3] *= x; m_el[1][3] *= y; m_el[2][3] *= z; m_el[3][3] *= w;
+ }
+
+ /**
* Return a column-scaled version of this matrix.
*/
MT_Matrix4x4 scaled(MT_Scalar x, MT_Scalar y, MT_Scalar z, MT_Scalar w) const {
diff --git a/intern/opencolorio/gpu_shader_display_transform.glsl b/intern/opencolorio/gpu_shader_display_transform.glsl
index 5921d6d9c73..853bf575582 100644
--- a/intern/opencolorio/gpu_shader_display_transform.glsl
+++ b/intern/opencolorio/gpu_shader_display_transform.glsl
@@ -38,7 +38,7 @@ float read_curve_mapping(int table, int index)
* But is it actually correct to subtract 1 here?
*/
float texture_index = float(index) / float(curve_mapping_lut_size - 1);
- return texture1D(curve_mapping_texture, texture_index) [table];
+ return texture1D(curve_mapping_texture, texture_index)[table];
}
float curvemap_calc_extend(int table, float x, vec2 first, vec2 last)
diff --git a/intern/opensubdiv/CMakeLists.txt b/intern/opensubdiv/CMakeLists.txt
index 311b89b97cf..876b5c0181f 100644
--- a/intern/opensubdiv/CMakeLists.txt
+++ b/intern/opensubdiv/CMakeLists.txt
@@ -47,6 +47,7 @@ set(SRC
opensubdiv_device_context_cuda.h
opensubdiv_device_context_opencl.h
opensubdiv_intern.h
+ opensubdiv_topology_refiner.h
)
macro(OPENSUBDIV_DEFINE_COMPONENT component)
@@ -63,12 +64,15 @@ OPENSUBDIV_DEFINE_COMPONENT(OPENSUBDIV_HAS_OPENMP)
OPENSUBDIV_DEFINE_COMPONENT(OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK)
OPENSUBDIV_DEFINE_COMPONENT(OPENSUBDIV_HAS_GLSL_COMPUTE)
-data_to_c_simple(gpu_shader_opensubd_display.glsl SRC)
+data_to_c_simple(gpu_shader_opensubdiv_vertex.glsl SRC)
+data_to_c_simple(gpu_shader_opensubdiv_geometry.glsl SRC)
+data_to_c_simple(gpu_shader_opensubdiv_fragment.glsl SRC)
add_definitions(-DGLEW_STATIC)
if(WIN32)
add_definitions(-DNOMINMAX)
+ add_definitions(-D_USE_MATH_DEFINES)
endif()
# TODO(sergey): Put CUEW back when CUDA is officially supported by OSD.
diff --git a/intern/opensubdiv/gpu_shader_opensubd_display.glsl b/intern/opensubdiv/gpu_shader_opensubdiv_fragment.glsl
index 51e8ed46c34..1e36d549360 100644
--- a/intern/opensubdiv/gpu_shader_opensubd_display.glsl
+++ b/intern/opensubdiv/gpu_shader_opensubdiv_fragment.glsl
@@ -29,169 +29,6 @@ struct VertexData {
vec2 uv;
};
-#ifdef VERTEX_SHADER // ---------------------
-
-in vec3 normal;
-in vec4 position;
-
-uniform mat4 modelViewMatrix;
-uniform mat3 normalMatrix;
-
-out block {
- VertexData v;
-} outpt;
-
-void main()
-{
- outpt.v.position = modelViewMatrix * position;
- outpt.v.normal = normalize(normalMatrix * normal);
-
-#if __VERSION__ < 140
- /* Some compilers expects gl_Position to be written.
- * It's not needed once we explicitly switch to GLSL 1.40 or above.
- */
- gl_Position = outpt.v.position;
-#endif
-}
-
-#elif defined GEOMETRY_SHADER // ---------------------
-
-#if __VERSION__ >= 150
- layout(lines_adjacency) in;
- #ifdef WIREFRAME
- layout(line_strip, max_vertices = 8) out;
- #else
- layout(triangle_strip, max_vertices = 4) out;
- #endif
-#else
- #extension GL_EXT_geometry_shader4: require
- /* application provides input/output layout info */
-#endif
-
-#if __VERSION__ < 140
- #extension GL_ARB_uniform_buffer_object: require
- #extension GL_ARB_texture_buffer_object: enable
- #extension GL_EXT_texture_buffer_object: enable
-#endif
-
-uniform mat4 modelViewMatrix;
-uniform mat4 projectionMatrix;
-uniform int PrimitiveIdBase;
-uniform int osd_fvar_count;
-uniform int osd_active_uv_offset;
-
-in block {
- VertexData v;
-} inpt[];
-
-#define INTERP_FACE_VARYING_2(result, fvarOffset, tessCoord) \
- { \
- vec2 v[4]; \
- int primOffset = (gl_PrimitiveID + PrimitiveIdBase) * 4; \
- for (int i = 0; i < 4; ++i) { \
- int index = (primOffset + i) * osd_fvar_count + fvarOffset; \
- v[i] = vec2(texelFetch(FVarDataBuffer, index).s, \
- texelFetch(FVarDataBuffer, index + 1).s); \
- } \
- result = mix(mix(v[0], v[1], tessCoord.s), \
- mix(v[3], v[2], tessCoord.s), \
- tessCoord.t); \
- }
-
-uniform samplerBuffer FVarDataBuffer;
-
-out block {
- VertexData v;
-} outpt;
-
-#ifdef FLAT_SHADING
-void emit(int index, vec3 normal)
-{
- outpt.v.position = inpt[index].v.position;
- outpt.v.normal = normal;
-
- /* TODO(sergey): Only uniform subdivisions atm. */
- vec2 quadst[4] = vec2[](vec2(0,0), vec2(1,0), vec2(1,1), vec2(0,1));
- vec2 st = quadst[index];
-
- INTERP_FACE_VARYING_2(outpt.v.uv, osd_active_uv_offset, st);
-
- gl_Position = projectionMatrix * inpt[index].v.position;
- EmitVertex();
-}
-
-# ifdef WIREFRAME
-void emit_edge(int v0, int v1, vec3 normal)
-{
- emit(v0, normal);
- emit(v1, normal);
-}
-# endif
-
-#else
-void emit(int index)
-{
- outpt.v.position = inpt[index].v.position;
- outpt.v.normal = inpt[index].v.normal;
-
- /* TODO(sergey): Only uniform subdivisions atm. */
- vec2 quadst[4] = vec2[](vec2(0,0), vec2(1,0), vec2(1,1), vec2(0,1));
- vec2 st = quadst[index];
-
- INTERP_FACE_VARYING_2(outpt.v.uv, osd_active_uv_offset, st);
-
- gl_Position = projectionMatrix * inpt[index].v.position;
- EmitVertex();
-}
-
-# ifdef WIREFRAME
-void emit_edge(int v0, int v1)
-{
- emit(v0);
- emit(v1);
-}
-# endif
-
-#endif
-
-void main()
-{
- gl_PrimitiveID = gl_PrimitiveIDIn;
-
-#ifdef FLAT_SHADING
- vec3 A = (inpt[0].v.position - inpt[1].v.position).xyz;
- vec3 B = (inpt[3].v.position - inpt[1].v.position).xyz;
- vec3 flat_normal = normalize(cross(B, A));
-# ifndef WIREFRAME
- emit(0, flat_normal);
- emit(1, flat_normal);
- emit(3, flat_normal);
- emit(2, flat_normal);
-# else
- emit_edge(0, 1, flat_normal);
- emit_edge(1, 2, flat_normal);
- emit_edge(2, 3, flat_normal);
- emit_edge(3, 0, flat_normal);
-# endif
-#else
-# ifndef WIREFRAME
- emit(0);
- emit(1);
- emit(3);
- emit(2);
-# else
- emit_edge(0, 1);
- emit_edge(1, 2);
- emit_edge(2, 3);
- emit_edge(3, 0);
-# endif
-#endif
-
- EndPrimitive();
-}
-
-#elif defined FRAGMENT_SHADER // ---------------------
-
#define MAX_LIGHTS 8
#define NUM_SOLID_LIGHTS 3
@@ -208,6 +45,7 @@ struct LightSource {
float spotCutoff;
float spotExponent;
float spotCosCutoff;
+ float pad, pad2;
#endif
};
@@ -240,6 +78,7 @@ void main()
vec3 L_diffuse = vec3(0.0);
vec3 L_specular = vec3(0.0);
+#ifdef USE_LIGHTING
#ifndef USE_COLOR_MATERIAL
/* Assume NUM_SOLID_LIGHTS directional lights. */
for (int i = 0; i < NUM_SOLID_LIGHTS; i++) {
@@ -261,7 +100,7 @@ void main()
#else /* USE_COLOR_MATERIAL */
vec3 varying_position = inpt.v.position.xyz;
vec3 V = (gl_ProjectionMatrix[3][3] == 0.0) ?
- normalize(varying_position): vec3(0.0, 0.0, -1.0);
+ normalize(varying_position) : vec3(0.0, 0.0, -1.0);
for (int i = 0; i < num_enabled_lights; i++) {
/* todo: this is a slow check for disabled lights */
if (lightSource[i].specular.a == 0.0)
@@ -299,7 +138,7 @@ void main()
/* diffuse light */
vec3 light_diffuse = lightSource[i].diffuse.rgb;
float diffuse_bsdf = max(dot(N, light_direction), 0.0);
- L_diffuse += light_diffuse*diffuse_bsdf*intensity;
+ L_diffuse += light_diffuse * diffuse_bsdf * intensity;
/* specular light */
vec3 light_specular = lightSource[i].specular.rgb;
@@ -307,9 +146,12 @@ void main()
float specular_bsdf = pow(max(dot(N, H), 0.0),
gl_FrontMaterial.shininess);
- L_specular += light_specular*specular_bsdf * intensity;
+ L_specular += light_specular * specular_bsdf * intensity;
}
#endif /* USE_COLOR_MATERIAL */
+#else /* USE_LIGHTING */
+ L_diffuse = vec3(1.0);
+#endif
/* Compute diffuse color. */
#ifdef USE_TEXTURE_2D
@@ -328,5 +170,3 @@ void main()
gl_FragColor = vec4(L, diffuse.a);
#endif
}
-
-#endif // ---------------------
diff --git a/intern/opensubdiv/gpu_shader_opensubdiv_geometry.glsl b/intern/opensubdiv/gpu_shader_opensubdiv_geometry.glsl
new file mode 100644
index 00000000000..3a83d44a8be
--- /dev/null
+++ b/intern/opensubdiv/gpu_shader_opensubdiv_geometry.glsl
@@ -0,0 +1,165 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+struct VertexData {
+ vec4 position;
+ vec3 normal;
+ vec2 uv;
+};
+
+#if __VERSION__ >= 150
+layout(lines_adjacency) in;
+ #ifdef WIREFRAME
+layout(line_strip, max_vertices = 8) out;
+ #else
+layout(triangle_strip, max_vertices = 4) out;
+ #endif
+#else
+ #extension GL_EXT_geometry_shader4: require
+ /* application provides input/output layout info */
+#endif
+
+#if __VERSION__ < 140
+ #extension GL_ARB_uniform_buffer_object: require
+ #extension GL_ARB_texture_buffer_object: enable
+ #extension GL_EXT_texture_buffer_object: enable
+#endif
+
+uniform mat4 modelViewMatrix;
+uniform mat4 projectionMatrix;
+uniform int PrimitiveIdBase;
+uniform int osd_fvar_count;
+uniform int osd_active_uv_offset;
+
+in block {
+ VertexData v;
+} inpt[];
+
+#define INTERP_FACE_VARYING_2(result, fvarOffset, tessCoord) \
+ { \
+ vec2 v[4]; \
+ int primOffset = (gl_PrimitiveID + PrimitiveIdBase) * 4; \
+ for (int i = 0; i < 4; ++i) { \
+ int index = (primOffset + i) * osd_fvar_count + fvarOffset; \
+ v[i] = vec2(texelFetch(FVarDataBuffer, index).s, \
+ texelFetch(FVarDataBuffer, index + 1).s); \
+ } \
+ result = mix(mix(v[0], v[1], tessCoord.s), \
+ mix(v[3], v[2], tessCoord.s), \
+ tessCoord.t); \
+ }
+
+uniform samplerBuffer FVarDataBuffer;
+uniform isamplerBuffer FVarDataOffsetBuffer;
+
+out block {
+ VertexData v;
+} outpt;
+
+#ifdef FLAT_SHADING
+void emit(int index, vec3 normal)
+{
+ outpt.v.position = inpt[index].v.position;
+ outpt.v.normal = normal;
+
+ /* TODO(sergey): Only uniform subdivisions atm. */
+ vec2 quadst[4] = vec2[](vec2(0, 0), vec2(1, 0), vec2(1, 1), vec2(0, 1));
+ vec2 st = quadst[index];
+
+ INTERP_FACE_VARYING_2(outpt.v.uv, osd_active_uv_offset, st);
+
+ gl_Position = projectionMatrix * inpt[index].v.position;
+ EmitVertex();
+}
+
+# ifdef WIREFRAME
+void emit_edge(int v0, int v1, vec3 normal)
+{
+ emit(v0, normal);
+ emit(v1, normal);
+}
+# endif
+
+#else
+void emit(int index)
+{
+ outpt.v.position = inpt[index].v.position;
+ outpt.v.normal = inpt[index].v.normal;
+
+ /* TODO(sergey): Only uniform subdivisions atm. */
+ vec2 quadst[4] = vec2[](vec2(0, 0), vec2(1, 0), vec2(1, 1), vec2(0, 1));
+ vec2 st = quadst[index];
+
+ INTERP_FACE_VARYING_2(outpt.v.uv, osd_active_uv_offset, st);
+
+ gl_Position = projectionMatrix * inpt[index].v.position;
+ EmitVertex();
+}
+
+# ifdef WIREFRAME
+void emit_edge(int v0, int v1)
+{
+ emit(v0);
+ emit(v1);
+}
+# endif
+
+#endif
+
+void main()
+{
+ gl_PrimitiveID = gl_PrimitiveIDIn;
+
+#ifdef FLAT_SHADING
+ vec3 A = (inpt[0].v.position - inpt[1].v.position).xyz;
+ vec3 B = (inpt[3].v.position - inpt[1].v.position).xyz;
+ vec3 flat_normal = normalize(cross(B, A));
+# ifndef WIREFRAME
+ emit(0, flat_normal);
+ emit(1, flat_normal);
+ emit(3, flat_normal);
+ emit(2, flat_normal);
+# else
+ emit_edge(0, 1, flat_normal);
+ emit_edge(1, 2, flat_normal);
+ emit_edge(2, 3, flat_normal);
+ emit_edge(3, 0, flat_normal);
+# endif
+#else
+# ifndef WIREFRAME
+ emit(0);
+ emit(1);
+ emit(3);
+ emit(2);
+# else
+ emit_edge(0, 1);
+ emit_edge(1, 2);
+ emit_edge(2, 3);
+ emit_edge(3, 0);
+# endif
+#endif
+
+ EndPrimitive();
+}
diff --git a/intern/opensubdiv/gpu_shader_opensubdiv_vertex.glsl b/intern/opensubdiv/gpu_shader_opensubdiv_vertex.glsl
new file mode 100644
index 00000000000..6d3c06f59c9
--- /dev/null
+++ b/intern/opensubdiv/gpu_shader_opensubdiv_vertex.glsl
@@ -0,0 +1,53 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+struct VertexData {
+ vec4 position;
+ vec3 normal;
+ vec2 uv;
+};
+
+in vec3 normal;
+in vec4 position;
+
+uniform mat4 modelViewMatrix;
+uniform mat3 normalMatrix;
+
+out block {
+ VertexData v;
+} outpt;
+
+void main()
+{
+ outpt.v.position = modelViewMatrix * position;
+ outpt.v.normal = normalize(normalMatrix * normal);
+
+#if __VERSION__ < 140
+ /* Some compilers expects gl_Position to be written.
+ * It's not needed once we explicitly switch to GLSL 1.40 or above.
+ */
+ gl_Position = outpt.v.position;
+#endif
+}
diff --git a/intern/opensubdiv/opensubdiv_capi.cc b/intern/opensubdiv/opensubdiv_capi.cc
index 9b9f4baa39e..52ce98fe74b 100644
--- a/intern/opensubdiv/opensubdiv_capi.cc
+++ b/intern/opensubdiv/opensubdiv_capi.cc
@@ -67,8 +67,10 @@
#include <opensubdiv/osd/glPatchTable.h>
#include <opensubdiv/far/stencilTable.h>
+#include <opensubdiv/far/primvarRefiner.h>
#include "opensubdiv_intern.h"
+#include "opensubdiv_topology_refiner.h"
#include "MEM_guardedalloc.h"
@@ -142,11 +144,73 @@ typedef Mesh<GLVertexBuffer,
GLPatchTable> OsdGLSLComputeMesh;
#endif
+namespace {
+
+struct FVarVertex {
+ float u, v;
+ void Clear() {
+ u = v = 0.0f;
+ }
+ void AddWithWeight(FVarVertex const & src, float weight) {
+ u += weight * src.u;
+ v += weight * src.v;
+ }
+};
+
+static void interpolate_fvar_data(OpenSubdiv::Far::TopologyRefiner& refiner,
+ const std::vector<float> uvs,
+ std::vector<float> &fvar_data) {
+ /* TODO(sergey): Make it somehow more generic way. */
+ const int fvar_width = 2;
+ const int max_level = refiner.GetMaxLevel();
+ size_t fvar_data_offset = 0, values_offset = 0;
+ for (int channel = 0; channel < refiner.GetNumFVarChannels(); ++channel) {
+ const int num_values = refiner.GetLevel(0).GetNumFVarValues(channel) * 2,
+ num_values_max = refiner.GetLevel(max_level).GetNumFVarValues(channel),
+ num_values_total = refiner.GetNumFVarValuesTotal(channel);
+ if (num_values_total <= 0) {
+ continue;
+ }
+ OpenSubdiv::Far::PrimvarRefiner primvar_refiner(refiner);
+ if (refiner.IsUniform()) {
+ /* For uniform we only keep the highest level of refinement. */
+ fvar_data.resize(fvar_data.size() + num_values_max * fvar_width);
+ std::vector<FVarVertex> buffer(num_values_total - num_values_max);
+ FVarVertex *src = &buffer[0];
+ memcpy(src, &uvs[values_offset], num_values * sizeof(float));
+ /* Defer the last level to treat separately with its alternate
+ * destination.
+ */
+ for (int level = 1; level < max_level; ++level) {
+ FVarVertex *dst = src + refiner.GetLevel(level-1).GetNumFVarValues(channel);
+ primvar_refiner.InterpolateFaceVarying(level, src, dst, channel);
+ src = dst;
+ }
+ FVarVertex *dst = reinterpret_cast<FVarVertex *>(&fvar_data[fvar_data_offset]);
+ primvar_refiner.InterpolateFaceVarying(max_level, src, dst, channel);
+ fvar_data_offset += num_values_max * fvar_width;
+ } else {
+ /* For adaptive we keep all levels. */
+ fvar_data.resize(fvar_data.size() + num_values_total * fvar_width);
+ FVarVertex *src = reinterpret_cast<FVarVertex *>(&fvar_data[fvar_data_offset]);
+ memcpy(src, &uvs[values_offset], num_values * sizeof(float));
+ for (int level = 1; level <= max_level; ++level) {
+ FVarVertex *dst = src + refiner.GetLevel(level-1).GetNumFVarValues(channel);
+ primvar_refiner.InterpolateFaceVarying(level, src, dst, channel);
+ src = dst;
+ }
+ fvar_data_offset += num_values_total * fvar_width;
+ }
+ values_offset += num_values;
+ }
+}
+
+} // namespace
+
struct OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner(
OpenSubdiv_TopologyRefinerDescr *topology_refiner,
int evaluator_type,
- int level,
- int /*subdivide_uvs*/)
+ int level)
{
using OpenSubdiv::Far::TopologyRefiner;
@@ -164,7 +228,7 @@ struct OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner(
const int num_varying_elements = 3;
GLMeshInterface *mesh = NULL;
- TopologyRefiner *refiner = (TopologyRefiner*)topology_refiner;
+ TopologyRefiner *refiner = topology_refiner->osd_refiner;
switch(evaluator_type) {
#define CHECK_EVALUATOR_TYPE(type, class) \
@@ -210,13 +274,23 @@ struct OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner(
(OpenSubdiv_GLMesh *) OBJECT_GUARDED_NEW(OpenSubdiv_GLMesh);
gl_mesh->evaluator_type = evaluator_type;
gl_mesh->descriptor = (OpenSubdiv_GLMeshDescr *) mesh;
- gl_mesh->topology_refiner = (OpenSubdiv_TopologyRefinerDescr*)refiner;
+ gl_mesh->topology_refiner = topology_refiner;
+
+ if (refiner->GetNumFVarChannels() > 0) {
+ std::vector<float> fvar_data;
+ interpolate_fvar_data(*refiner, topology_refiner->uvs, fvar_data);
+ openSubdiv_osdGLAllocFVar(topology_refiner, gl_mesh, &fvar_data[0]);
+ }
+ else {
+ gl_mesh->fvar_data = NULL;
+ }
return gl_mesh;
}
void openSubdiv_deleteOsdGLMesh(struct OpenSubdiv_GLMesh *gl_mesh)
{
+ openSubdiv_osdGLDestroyFVar(gl_mesh);
switch (gl_mesh->evaluator_type) {
#define CHECK_EVALUATOR_TYPE(type, class) \
case OPENSUBDIV_EVALUATOR_ ## type: \
@@ -249,6 +323,8 @@ void openSubdiv_deleteOsdGLMesh(struct OpenSubdiv_GLMesh *gl_mesh)
#undef CHECK_EVALUATOR_TYPE
}
+ /* NOTE: OSD refiner was owned by gl_mesh, no need to free it here. */
+ OBJECT_GUARDED_DELETE(gl_mesh->topology_refiner, OpenSubdiv_TopologyRefinerDescr);
OBJECT_GUARDED_DELETE(gl_mesh, OpenSubdiv_GLMesh);
}
@@ -299,6 +375,9 @@ int openSubdiv_supportGPUDisplay(void)
return openSubdiv_gpu_legacy_support() &&
(GLEW_VERSION_3_2 ||
(GLEW_VERSION_3_1 && GLEW_EXT_geometry_shader4) ||
- (GLEW_VERSION_3_0 && GLEW_EXT_geometry_shader4 && GLEW_ARB_uniform_buffer_object && (GLEW_ARB_texture_buffer_object || GLEW_EXT_texture_buffer_object)));
+ (GLEW_VERSION_3_0 &&
+ GLEW_EXT_geometry_shader4 &&
+ GLEW_ARB_uniform_buffer_object &&
+ (GLEW_ARB_texture_buffer_object || GLEW_EXT_texture_buffer_object)));
/* also ARB_explicit_attrib_location? */
}
diff --git a/intern/opensubdiv/opensubdiv_capi.h b/intern/opensubdiv/opensubdiv_capi.h
index b40505b197d..c3a194813e6 100644
--- a/intern/opensubdiv/opensubdiv_capi.h
+++ b/intern/opensubdiv/opensubdiv_capi.h
@@ -32,16 +32,19 @@ extern "C" {
// Types declaration.
struct OpenSubdiv_GLMesh;
+struct OpenSubdiv_GLMeshFVarData;
struct OpenSubdiv_TopologyRefinerDescr;
typedef struct OpenSubdiv_GLMesh OpenSubdiv_GLMesh;
#ifdef __cplusplus
struct OpenSubdiv_GLMeshDescr;
+
typedef struct OpenSubdiv_GLMesh {
int evaluator_type;
OpenSubdiv_GLMeshDescr *descriptor;
OpenSubdiv_TopologyRefinerDescr *topology_refiner;
+ OpenSubdiv_GLMeshFVarData *fvar_data;
} OpenSubdiv_GLMesh;
#endif
@@ -66,8 +69,7 @@ enum {
OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner(
struct OpenSubdiv_TopologyRefinerDescr *topology_refiner,
int evaluator_type,
- int level,
- int subdivide_uvs);
+ int level);
void openSubdiv_deleteOsdGLMesh(OpenSubdiv_GLMesh *gl_mesh);
unsigned int openSubdiv_getOsdGLMeshPatchIndexBuffer(
@@ -138,6 +140,11 @@ void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh,
int start_patch,
int num_patches);
+void openSubdiv_osdGLAllocFVar(struct OpenSubdiv_TopologyRefinerDescr *topology_refiner,
+ OpenSubdiv_GLMesh *gl_mesh,
+ const float *fvar_data);
+void openSubdiv_osdGLDestroyFVar(OpenSubdiv_GLMesh *gl_mesh);
+
/* ** Utility functions ** */
int openSubdiv_supportGPUDisplay(void);
int openSubdiv_getAvailableEvaluators(void);
diff --git a/intern/opensubdiv/opensubdiv_converter.cc b/intern/opensubdiv/opensubdiv_converter.cc
index 3fadde68d32..ea41a56768f 100644
--- a/intern/opensubdiv/opensubdiv_converter.cc
+++ b/intern/opensubdiv/opensubdiv_converter.cc
@@ -32,8 +32,12 @@
#include <opensubdiv/far/topologyRefinerFactory.h>
+#include "MEM_guardedalloc.h"
+
#include "opensubdiv_converter_capi.h"
#include "opensubdiv_intern.h"
+#include "opensubdiv_topology_refiner.h"
+
#include <stack>
@@ -49,6 +53,11 @@ inline void reverse_face_verts(int *face_verts, int num_verts)
face_verts[0] = last_vert;
}
+struct TopologyRefinerData {
+ const OpenSubdiv_Converter& conv;
+ std::vector<float> *uvs;
+};
+
} /* namespace */
#endif /* OPENSUBDIV_ORIENT_TOPOLOGY */
@@ -137,10 +146,11 @@ inline void check_oriented_vert_connectivity(const int num_vert_edges,
} /* namespace */
template <>
-inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::resizeComponentTopology(
+inline bool TopologyRefinerFactory<TopologyRefinerData>::resizeComponentTopology(
TopologyRefiner& refiner,
- const OpenSubdiv_Converter& conv)
+ const TopologyRefinerData& cb_data)
{
+ const OpenSubdiv_Converter& conv = cb_data.conv;
/* Faces and face-verts */
const int num_faces = conv.get_num_faces(&conv);
setNumBaseFaces(refiner, num_faces);
@@ -168,10 +178,11 @@ inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::resizeComponentTopolog
}
template <>
-inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignComponentTopology(
+inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTopology(
TopologyRefiner& refiner,
- const OpenSubdiv_Converter& conv)
+ const TopologyRefinerData &cb_data)
{
+ const OpenSubdiv_Converter& conv = cb_data.conv;
using Far::IndexArray;
/* Face relations. */
const int num_faces = conv.get_num_faces(&conv);
@@ -332,7 +343,6 @@ inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignComponentTopolog
else {
/* Special handle of non-manifold vertex. */
for (int i = 0; i < num_vert_edges; ++i) {
- bool start_found = false;
edge_start = vert_edges[i];
IndexArray edge_faces = getBaseEdgeFaces(refiner, edge_start);
if (edge_faces.size() == 1) {
@@ -343,14 +353,10 @@ inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignComponentTopolog
face_edges = getBaseFaceEdges(refiner, face_start);
face_vert_start = findInArray(face_verts, vert);
if (edge_start == face_edges[face_vert_start]) {
- start_found = true;
break;
}
}
}
- if (start_found) {
- break;
- }
/* Reset indices for sanity check below. */
face_start = edge_start = face_vert_start = -1;
}
@@ -431,10 +437,11 @@ inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignComponentTopolog
};
template <>
-inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignComponentTags(
+inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTags(
TopologyRefiner& refiner,
- const OpenSubdiv_Converter& conv)
+ const TopologyRefinerData& cb_data)
{
+ const OpenSubdiv_Converter& conv = cb_data.conv;
typedef OpenSubdiv::Sdc::Crease Crease;
int num_edges = conv.get_num_edges(&conv);
@@ -481,14 +488,52 @@ inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignComponentTags(
}
template <>
-inline void TopologyRefinerFactory<OpenSubdiv_Converter>::reportInvalidTopology(
+inline void TopologyRefinerFactory<TopologyRefinerData>::reportInvalidTopology(
TopologyError /*errCode*/,
const char *msg,
- const OpenSubdiv_Converter& /*mesh*/)
+ const TopologyRefinerData& /*mesh*/)
{
printf("OpenSubdiv Error: %s\n", msg);
}
+template <>
+inline bool TopologyRefinerFactory<TopologyRefinerData>::assignFaceVaryingTopology(
+ TopologyRefiner& refiner,
+ const TopologyRefinerData& cb_data)
+{
+ const OpenSubdiv_Converter& conv = cb_data.conv;
+ const int num_layers = conv.get_num_uv_layers(&conv);
+ if (num_layers <= 0) {
+ /* No UV maps, we can skip any face-varying data. */
+ return true;
+ }
+ const int num_faces = getNumBaseFaces(refiner);
+ size_t uvs_offset = 0;
+ for (int layer = 0; layer < num_layers; ++layer) {
+ conv.precalc_uv_layer(&conv, layer);
+ const int num_uvs = conv.get_num_uvs(&conv);
+ /* Fill in UV coordinates. */
+ cb_data.uvs->resize(cb_data.uvs->size() + num_uvs * 2);
+ conv.get_uvs(&conv, &cb_data.uvs->at(uvs_offset));
+ uvs_offset += num_uvs * 2;
+ /* Fill in per-corner index of the UV. */
+ const int channel = createBaseFVarChannel(refiner, num_uvs);
+ for (int face = 0; face < num_faces; ++face) {
+ Far::IndexArray dst_face_uvs = getBaseFaceFVarValues(refiner,
+ face,
+ channel);
+ for (int corner = 0; corner < dst_face_uvs.size(); ++corner) {
+ const int uv_index = conv.get_face_corner_uv_index(&conv,
+ face,
+ corner);
+ dst_face_uvs[corner] = uv_index;
+ }
+ }
+ conv.finish_uv_layer(&conv);
+ }
+ return true;
+}
+
} /* namespace Far */
} /* namespace OPENSUBDIV_VERSION */
} /* namespace OpenSubdiv */
@@ -522,33 +567,43 @@ struct OpenSubdiv_TopologyRefinerDescr *openSubdiv_createTopologyRefinerDescr(
Options options;
options.SetVtxBoundaryInterpolation(Options::VTX_BOUNDARY_EDGE_ONLY);
options.SetCreasingMethod(Options::CREASE_UNIFORM);
- options.SetFVarLinearInterpolation(Options::FVAR_LINEAR_ALL);
+ if (converter->get_subdiv_uvs(converter)) {
+ options.SetFVarLinearInterpolation(Options::FVAR_LINEAR_CORNERS_ONLY);
+ }
+ else {
+ options.SetFVarLinearInterpolation(Options::FVAR_LINEAR_ALL);
+ }
- TopologyRefinerFactory<OpenSubdiv_Converter>::Options
+ TopologyRefinerFactory<TopologyRefinerData>::Options
topology_options(scheme_type, options);
#ifdef OPENSUBDIV_VALIDATE_TOPOLOGY
topology_options.validateFullTopology = true;
#endif
+ OpenSubdiv_TopologyRefinerDescr *result = OBJECT_GUARDED_NEW(OpenSubdiv_TopologyRefinerDescr);
+ TopologyRefinerData cb_data = {*converter, &result->uvs};
/* We don't use guarded allocation here so we can re-use the refiner
* for GL mesh creation directly.
*/
- return (struct OpenSubdiv_TopologyRefinerDescr*)
- TopologyRefinerFactory<OpenSubdiv_Converter>::Create(
- *converter,
+ result->osd_refiner =
+ TopologyRefinerFactory<TopologyRefinerData>::Create(
+ cb_data,
topology_options);
+
+ return result;
}
void openSubdiv_deleteTopologyRefinerDescr(
OpenSubdiv_TopologyRefinerDescr *topology_refiner)
{
- delete (OpenSubdiv::Far::TopologyRefiner *)topology_refiner;
+ delete topology_refiner->osd_refiner;
+ OBJECT_GUARDED_DELETE(topology_refiner, OpenSubdiv_TopologyRefinerDescr);
}
int openSubdiv_topologyRefinerGetSubdivLevel(
const OpenSubdiv_TopologyRefinerDescr *topology_refiner)
{
using OpenSubdiv::Far::TopologyRefiner;
- const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner;
+ const TopologyRefiner *refiner = topology_refiner->osd_refiner;
return refiner->GetMaxLevel();
}
@@ -557,7 +612,7 @@ int openSubdiv_topologyRefinerGetNumVerts(
{
using OpenSubdiv::Far::TopologyLevel;
using OpenSubdiv::Far::TopologyRefiner;
- const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner;
+ const TopologyRefiner *refiner = topology_refiner->osd_refiner;
const TopologyLevel &base_level = refiner->GetLevel(0);
return base_level.GetNumVertices();
}
@@ -567,7 +622,7 @@ int openSubdiv_topologyRefinerGetNumEdges(
{
using OpenSubdiv::Far::TopologyLevel;
using OpenSubdiv::Far::TopologyRefiner;
- const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner;
+ const TopologyRefiner *refiner = topology_refiner->osd_refiner;
const TopologyLevel &base_level = refiner->GetLevel(0);
return base_level.GetNumEdges();
}
@@ -577,7 +632,7 @@ int openSubdiv_topologyRefinerGetNumFaces(
{
using OpenSubdiv::Far::TopologyLevel;
using OpenSubdiv::Far::TopologyRefiner;
- const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner;
+ const TopologyRefiner *refiner = topology_refiner->osd_refiner;
const TopologyLevel &base_level = refiner->GetLevel(0);
return base_level.GetNumFaces();
}
@@ -588,7 +643,7 @@ int openSubdiv_topologyRefinerGetNumFaceVerts(
{
using OpenSubdiv::Far::TopologyLevel;
using OpenSubdiv::Far::TopologyRefiner;
- const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner;
+ const TopologyRefiner *refiner = topology_refiner->osd_refiner;
const TopologyLevel &base_level = refiner->GetLevel(0);
return base_level.GetFaceVertices(face).size();
}
@@ -597,10 +652,11 @@ int openSubdiv_topologyRefnerCompareConverter(
const OpenSubdiv_TopologyRefinerDescr *topology_refiner,
OpenSubdiv_Converter *converter)
{
+ typedef OpenSubdiv::Sdc::Options Options;
using OpenSubdiv::Far::ConstIndexArray;
using OpenSubdiv::Far::TopologyRefiner;
using OpenSubdiv::Far::TopologyLevel;
- const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner;
+ const TopologyRefiner *refiner = topology_refiner->osd_refiner;
const TopologyLevel &base_level = refiner->GetLevel(0);
const int num_verts = base_level.GetNumVertices();
const int num_edges = base_level.GetNumEdges();
@@ -611,6 +667,12 @@ int openSubdiv_topologyRefnerCompareConverter(
if (scheme_type != refiner->GetSchemeType()) {
return false;
}
+ const Options options = refiner->GetSchemeOptions();
+ Options::FVarLinearInterpolation interp = options.GetFVarLinearInterpolation();
+ const bool subdiv_uvs = (interp != Options::FVAR_LINEAR_ALL);
+ if (converter->get_subdiv_uvs(converter) != subdiv_uvs) {
+ return false;
+ }
if (converter->get_num_verts(converter) != num_verts ||
converter->get_num_edges(converter) != num_edges ||
converter->get_num_faces(converter) != num_faces)
diff --git a/intern/opensubdiv/opensubdiv_converter_capi.h b/intern/opensubdiv/opensubdiv_converter_capi.h
index 1f09fa074d8..6eda6ae5d8a 100644
--- a/intern/opensubdiv/opensubdiv_converter_capi.h
+++ b/intern/opensubdiv/opensubdiv_converter_capi.h
@@ -47,6 +47,8 @@ typedef struct OpenSubdiv_Converter {
OpenSubdiv_SchemeType (*get_type)(const OpenSubdiv_Converter *converter);
+ bool (*get_subdiv_uvs)(const OpenSubdiv_Converter *converter);
+
int (*get_num_faces)(const OpenSubdiv_Converter *converter);
int (*get_num_edges)(const OpenSubdiv_Converter *converter);
int (*get_num_verts)(const OpenSubdiv_Converter *converter);
@@ -83,6 +85,20 @@ typedef struct OpenSubdiv_Converter {
int vert,
int *vert_faces);
+ /* Face-varying data. */
+
+ int (*get_num_uv_layers)(const OpenSubdiv_Converter *converter);
+
+ void (*precalc_uv_layer)(const OpenSubdiv_Converter *converter, int layer);
+ void (*finish_uv_layer)(const OpenSubdiv_Converter *converter);
+
+ int (*get_num_uvs)(const OpenSubdiv_Converter *converter);
+ void (*get_uvs)(const OpenSubdiv_Converter *converter, float *uvs);
+
+ int (*get_face_corner_uv_index)(const OpenSubdiv_Converter *converter,
+ int face,
+ int corner);
+
void (*free_user_data)(const OpenSubdiv_Converter *converter);
void *user_data;
} OpenSubdiv_Converter;
diff --git a/intern/opensubdiv/opensubdiv_gpu_capi.cc b/intern/opensubdiv/opensubdiv_gpu_capi.cc
index 698fdfee00f..c36eaae1c6e 100644
--- a/intern/opensubdiv/opensubdiv_gpu_capi.cc
+++ b/intern/opensubdiv/opensubdiv_gpu_capi.cc
@@ -42,11 +42,31 @@
#include <opensubdiv/osd/cpuGLVertexBuffer.h>
#include <opensubdiv/osd/cpuEvaluator.h>
+#include "MEM_guardedalloc.h"
+
+#include "opensubdiv_capi.h"
+#include "opensubdiv_topology_refiner.h"
+
using OpenSubdiv::Osd::GLMeshInterface;
-extern "C" char datatoc_gpu_shader_opensubd_display_glsl[];
+extern "C" char datatoc_gpu_shader_opensubdiv_vertex_glsl[];
+extern "C" char datatoc_gpu_shader_opensubdiv_geometry_glsl[];
+extern "C" char datatoc_gpu_shader_opensubdiv_fragment_glsl[];
+
+/* TODO(sergey): This is bit of bad level calls :S */
+extern "C" {
+void copy_m3_m3(float m1[3][3], float m2[3][3]);
+void copy_m3_m4(float m1[3][3], float m2[4][4]);
+void adjoint_m3_m3(float m1[3][3], float m[3][3]);
+float determinant_m3_array(float m[3][3]);
+bool invert_m3_m3(float m1[3][3], float m2[3][3]);
+bool invert_m3(float m[3][3]);
+void transpose_m3(float mat[3][3]);
+}
#define MAX_LIGHTS 8
+#define SUPPORT_COLOR_MATERIAL
+
typedef struct Light {
float position[4];
float ambient[4];
@@ -60,6 +80,7 @@ typedef struct Light {
float spot_cutoff;
float spot_exponent;
float spot_cos_cutoff;
+ float pad, pad2;
#endif
} Light;
@@ -75,128 +96,131 @@ typedef struct Transform {
} Transform;
static bool g_use_osd_glsl = false;
-static int g_active_uv_index = -1;
+static int g_active_uv_index = 0;
static GLuint g_flat_fill_solid_program = 0;
static GLuint g_flat_fill_texture2d_program = 0;
static GLuint g_smooth_fill_solid_program = 0;
static GLuint g_smooth_fill_texture2d_program = 0;
+
+static GLuint g_flat_fill_solid_shadeless_program = 0;
+static GLuint g_flat_fill_texture2d_shadeless_program = 0;
+static GLuint g_smooth_fill_solid_shadeless_program = 0;
+static GLuint g_smooth_fill_texture2d_shadeless_program = 0;
+
static GLuint g_wireframe_program = 0;
static GLuint g_lighting_ub = 0;
static Lighting g_lighting_data;
static Transform g_transform;
-/* TODO(sergey): This is actually duplicated code from BLI. */
-namespace {
-void copy_m3_m3(float m1[3][3], float m2[3][3])
-{
- /* destination comes first: */
- memcpy(&m1[0], &m2[0], 9 * sizeof(float));
-}
-
-void copy_m3_m4(float m1[3][3], float m2[4][4])
-{
- m1[0][0] = m2[0][0];
- m1[0][1] = m2[0][1];
- m1[0][2] = m2[0][2];
-
- m1[1][0] = m2[1][0];
- m1[1][1] = m2[1][1];
- m1[1][2] = m2[1][2];
-
- m1[2][0] = m2[2][0];
- m1[2][1] = m2[2][1];
- m1[2][2] = m2[2][2];
-}
-
-void adjoint_m3_m3(float m1[3][3], float m[3][3])
-{
- m1[0][0] = m[1][1] * m[2][2] - m[1][2] * m[2][1];
- m1[0][1] = -m[0][1] * m[2][2] + m[0][2] * m[2][1];
- m1[0][2] = m[0][1] * m[1][2] - m[0][2] * m[1][1];
-
- m1[1][0] = -m[1][0] * m[2][2] + m[1][2] * m[2][0];
- m1[1][1] = m[0][0] * m[2][2] - m[0][2] * m[2][0];
- m1[1][2] = -m[0][0] * m[1][2] + m[0][2] * m[1][0];
-
- m1[2][0] = m[1][0] * m[2][1] - m[1][1] * m[2][0];
- m1[2][1] = -m[0][0] * m[2][1] + m[0][1] * m[2][0];
- m1[2][2] = m[0][0] * m[1][1] - m[0][1] * m[1][0];
-}
-
-float determinant_m3_array(float m[3][3])
+struct OpenSubdiv_GLMeshFVarData
{
- return (m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) -
- m[1][0] * (m[0][1] * m[2][2] - m[0][2] * m[2][1]) +
- m[2][0] * (m[0][1] * m[1][2] - m[0][2] * m[1][1]));
-}
-
-bool invert_m3_m3(float m1[3][3], float m2[3][3])
-{
- float det;
- int a, b;
- bool success;
-
- /* calc adjoint */
- adjoint_m3_m3(m1, m2);
+ OpenSubdiv_GLMeshFVarData() :
+ texture_buffer(0), offset_buffer(0) {
+ }
- /* then determinant old matrix! */
- det = determinant_m3_array(m2);
+ ~OpenSubdiv_GLMeshFVarData()
+ {
+ Release();
+ }
- success = (det != 0.0f);
+ void Release()
+ {
+ if (texture_buffer) {
+ glDeleteTextures(1, &texture_buffer);
+ }
+ if (offset_buffer) {
+ glDeleteTextures(1, &offset_buffer);
+ }
+ texture_buffer = 0;
+ offset_buffer = 0;
+ fvar_width = 0;
+ channel_offsets.clear();
+ }
- if (det != 0.0f) {
- det = 1.0f / det;
- for (a = 0; a < 3; a++) {
- for (b = 0; b < 3; b++) {
- m1[a][b] *= det;
+ void Create(const OpenSubdiv::Far::TopologyRefiner *refiner,
+ const OpenSubdiv::Far::PatchTable *patch_table,
+ int fvar_width,
+ const float *fvar_src_data)
+ {
+ Release();
+
+ this->fvar_width = fvar_width;
+
+ /* Expand fvar data to per-patch array */
+ const int max_level = refiner->GetMaxLevel();
+ const int num_channels = patch_table->GetNumFVarChannels();
+ std::vector<float> data;
+ int fvar_data_offset = 0;
+ channel_offsets.resize(num_channels);
+ for (int channel = 0; channel < num_channels; ++channel) {
+ OpenSubdiv::Far::ConstIndexArray indices =
+ patch_table->GetFVarValues(channel);
+
+ channel_offsets[channel] = data.size();
+ data.reserve(data.size() + indices.size() * fvar_width);
+
+ for (int fvert = 0; fvert < (int)indices.size(); ++fvert) {
+ int index = indices[fvert] * fvar_width;
+ for (int i = 0; i < fvar_width; ++i) {
+ data.push_back(fvar_src_data[fvar_data_offset + index++]);
+ }
+ }
+ if (refiner->IsUniform()) {
+ const int num_values_max = refiner->GetLevel(max_level).GetNumFVarValues(channel);
+ fvar_data_offset += num_values_max * fvar_width;
+ } else {
+ const int num_values_total = refiner->GetNumFVarValuesTotal(channel);
+ fvar_data_offset += num_values_total * fvar_width;
}
}
- }
- return success;
-}
+ GLuint buffer;
+ glGenBuffers(1, &buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, buffer);
+ glBufferData(GL_ARRAY_BUFFER, data.size()*sizeof(float),
+ &data[0], GL_STATIC_DRAW);
-bool invert_m3(float m[3][3])
-{
- float tmp[3][3];
- bool success;
+ glGenTextures(1, &texture_buffer);
+ glBindTexture(GL_TEXTURE_BUFFER, texture_buffer);
+ glTexBuffer(GL_TEXTURE_BUFFER, GL_R32F, buffer);
- success = invert_m3_m3(tmp, m);
- copy_m3_m3(m, tmp);
+ glDeleteBuffers(1, &buffer);
- return success;
-}
+ glGenBuffers(1, &buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, buffer);
+ glBufferData(GL_ARRAY_BUFFER, channel_offsets.size()*sizeof(int),
+ &channel_offsets[0], GL_STATIC_DRAW);
-void transpose_m3(float mat[3][3])
-{
- float t;
-
- t = mat[0][1];
- mat[0][1] = mat[1][0];
- mat[1][0] = t;
- t = mat[0][2];
- mat[0][2] = mat[2][0];
- mat[2][0] = t;
- t = mat[1][2];
- mat[1][2] = mat[2][1];
- mat[2][1] = t;
-}
+ glGenTextures(1, &offset_buffer);
+ glBindTexture(GL_TEXTURE_BUFFER, offset_buffer);
+ glTexBuffer(GL_TEXTURE_BUFFER, GL_R32I, buffer);
+ glBindTexture(GL_TEXTURE_BUFFER, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ }
+ GLuint texture_buffer;
+ GLuint offset_buffer;
+ std::vector<int> channel_offsets;
+ int fvar_width;
+};
+
+namespace {
GLuint compileShader(GLenum shaderType,
- const char *section,
const char *version,
- const char *define)
+ const char *define,
+ const char *source)
{
- char sdefine[64];
- sprintf(sdefine, "#define %s\n", section);
-
const char *sources[] = {
version,
define,
- sdefine,
- datatoc_gpu_shader_opensubd_display_glsl
+#ifdef SUPPORT_COLOR_MATERIAL
+ "#define SUPPORT_COLOR_MATERIAL\n",
+#else
+ "",
+#endif
+ source,
};
GLuint shader = glCreateShader(shaderType);
@@ -208,10 +232,10 @@ GLuint compileShader(GLenum shaderType,
if (status == GL_FALSE) {
GLchar emsg[1024];
glGetShaderInfoLog(shader, sizeof(emsg), 0, emsg);
- fprintf(stderr, "Error compiling GLSL %s: %s\n", section, emsg);
+ fprintf(stderr, "Error compiling GLSL: %s\n", emsg);
fprintf(stderr, "Version: %s\n", version);
fprintf(stderr, "Defines: %s\n", define);
- fprintf(stderr, "Source: %s\n", datatoc_gpu_shader_opensubd_display_glsl);
+ fprintf(stderr, "Source: %s\n", source);
return 0;
}
@@ -221,23 +245,23 @@ GLuint compileShader(GLenum shaderType,
GLuint linkProgram(const char *version, const char *define)
{
GLuint vertexShader = compileShader(GL_VERTEX_SHADER,
- "VERTEX_SHADER",
version,
- define);
+ define,
+ datatoc_gpu_shader_opensubdiv_vertex_glsl);
if (vertexShader == 0) {
return 0;
}
GLuint geometryShader = compileShader(GL_GEOMETRY_SHADER,
- "GEOMETRY_SHADER",
version,
- define);
+ define,
+ datatoc_gpu_shader_opensubdiv_geometry_glsl);
if (geometryShader == 0) {
return 0;
}
GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER,
- "FRAGMENT_SHADER",
version,
- define);
+ define,
+ datatoc_gpu_shader_opensubdiv_fragment_glsl );
if (fragmentShader == 0) {
return 0;
}
@@ -295,14 +319,17 @@ GLuint linkProgram(const char *version, const char *define)
0); /* GL_TEXTURE0 */
glProgramUniform1i(program,
+ glGetUniformLocation(program, "FVarDataOffsetBuffer"),
+ 30); /* GL_TEXTURE30 */
+
+ glProgramUniform1i(program,
glGetUniformLocation(program, "FVarDataBuffer"),
31); /* GL_TEXTURE31 */
return program;
}
-void bindProgram(GLMeshInterface * /*mesh*/,
- int program)
+void bindProgram(OpenSubdiv_GLMesh *gl_mesh, int program)
{
glUseProgram(program);
@@ -346,23 +373,34 @@ void bindProgram(GLMeshInterface * /*mesh*/,
glUniform4fv(glGetUniformLocation(program, "diffuse"), 1, color);
}
- /* TODO(sergey): Bring face varying back. */
-#if 0
/* Face-vertex data */
- if (mesh->GetDrawContext()->GetFvarDataTextureBuffer()) {
- glActiveTexture(GL_TEXTURE31);
- glBindTexture(GL_TEXTURE_BUFFER,
- mesh->GetDrawContext()->GetFvarDataTextureBuffer());
- glActiveTexture(GL_TEXTURE0);
- }
-#endif
+ if (gl_mesh->fvar_data != NULL) {
+ if (gl_mesh->fvar_data->texture_buffer) {
+ glActiveTexture(GL_TEXTURE31);
+ glBindTexture(GL_TEXTURE_BUFFER, gl_mesh->fvar_data->texture_buffer);
+ glActiveTexture(GL_TEXTURE0);
+ }
- /* TODO(sergey): Bring face varying back. */
- glUniform1i(glGetUniformLocation(program, "osd_fvar_count"),
- 0/* * mesh->GetFVarCount()*/);
+ if (gl_mesh->fvar_data->offset_buffer) {
+ glActiveTexture(GL_TEXTURE30);
+ glBindTexture(GL_TEXTURE_BUFFER, gl_mesh->fvar_data->offset_buffer);
+ glActiveTexture(GL_TEXTURE0);
+ }
- glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"),
- g_active_uv_index * 2);
+ glUniform1i(glGetUniformLocation(program, "osd_fvar_count"),
+ gl_mesh->fvar_data->fvar_width);
+ if (gl_mesh->fvar_data->channel_offsets.size() > 0 &&
+ g_active_uv_index >= 0)
+ {
+ glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"),
+ gl_mesh->fvar_data->channel_offsets[g_active_uv_index]);
+ } else {
+ glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0);
+ }
+ } else {
+ glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), 0);
+ glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0);
+ }
}
} /* namespace */
@@ -390,11 +428,51 @@ bool openSubdiv_osdGLDisplayInit(void)
/* minimum supported for OpenSubdiv */
}
- g_flat_fill_solid_program = linkProgram(version, "#define FLAT_SHADING\n");
- g_flat_fill_texture2d_program = linkProgram(version, "#define USE_TEXTURE_2D\n#define FLAT_SHADING\n");
- g_smooth_fill_solid_program = linkProgram(version, "#define SMOOTH_SHADING\n");
- g_smooth_fill_texture2d_program = linkProgram(version, "#define USE_TEXTURE_2D\n#define SMOOTH_SHADING\n");
- g_wireframe_program = linkProgram(version, "#define WIREFRAME\n");
+ g_flat_fill_solid_program = linkProgram(
+ version,
+ "#define USE_COLOR_MATERIAL\n"
+ "#define USE_LIGHTING\n"
+ "#define FLAT_SHADING\n");
+ g_flat_fill_texture2d_program = linkProgram(
+ version,
+ "#define USE_COLOR_MATERIAL\n"
+ "#define USE_LIGHTING\n"
+ "#define USE_TEXTURE_2D\n"
+ "#define FLAT_SHADING\n");
+ g_smooth_fill_solid_program = linkProgram(
+ version,
+ "#define USE_COLOR_MATERIAL\n"
+ "#define USE_LIGHTING\n"
+ "#define SMOOTH_SHADING\n");
+ g_smooth_fill_texture2d_program = linkProgram(
+ version,
+ "#define USE_COLOR_MATERIAL\n"
+ "#define USE_LIGHTING\n"
+ "#define USE_TEXTURE_2D\n"
+ "#define SMOOTH_SHADING\n");
+
+ g_flat_fill_solid_shadeless_program = linkProgram(
+ version,
+ "#define USE_COLOR_MATERIAL\n"
+ "#define FLAT_SHADING\n");
+ g_flat_fill_texture2d_shadeless_program = linkProgram(
+ version,
+ "#define USE_COLOR_MATERIAL\n"
+ "#define USE_TEXTURE_2D\n"
+ "#define FLAT_SHADING\n");
+ g_smooth_fill_solid_shadeless_program = linkProgram(
+ version,
+ "#define USE_COLOR_MATERIAL\n"
+ "#define SMOOTH_SHADING\n");
+ g_smooth_fill_texture2d_shadeless_program = linkProgram(
+ version,
+ "#define USE_COLOR_MATERIAL\n"
+ "#define USE_TEXTURE_2D\n"
+ "#define SMOOTH_SHADING\n");
+
+ g_wireframe_program = linkProgram(
+ version,
+ "#define WIREFRAME\n");
glGenBuffers(1, &g_lighting_ub);
glBindBuffer(GL_UNIFORM_BUFFER, g_lighting_ub);
@@ -416,28 +494,31 @@ void openSubdiv_osdGLDisplayDeinit(void)
if (g_lighting_ub != 0) {
glDeleteBuffers(1, &g_lighting_ub);
}
- if (g_flat_fill_solid_program) {
- glDeleteProgram(g_flat_fill_solid_program);
- }
- if (g_flat_fill_texture2d_program) {
- glDeleteProgram(g_flat_fill_texture2d_program);
- }
- if (g_smooth_fill_solid_program) {
- glDeleteProgram(g_flat_fill_solid_program);
- }
- if (g_smooth_fill_texture2d_program) {
- glDeleteProgram(g_smooth_fill_texture2d_program);
- }
- if (g_wireframe_program) {
- glDeleteProgram(g_wireframe_program);
- }
+#define SAFE_DELETE_PROGRAM(program) \
+ do { \
+ if (program) { \
+ glDeleteProgram(program); \
+ } \
+ } while (false)
+
+ SAFE_DELETE_PROGRAM(g_flat_fill_solid_program);
+ SAFE_DELETE_PROGRAM(g_flat_fill_texture2d_program);
+ SAFE_DELETE_PROGRAM(g_smooth_fill_solid_program);
+ SAFE_DELETE_PROGRAM(g_smooth_fill_texture2d_program);
+ SAFE_DELETE_PROGRAM(g_flat_fill_solid_shadeless_program);
+ SAFE_DELETE_PROGRAM(g_flat_fill_texture2d_shadeless_program);
+ SAFE_DELETE_PROGRAM(g_smooth_fill_solid_shadeless_program);
+ SAFE_DELETE_PROGRAM(g_smooth_fill_texture2d_shadeless_program);
+ SAFE_DELETE_PROGRAM(g_wireframe_program);
+
+#undef SAFE_DELETE_PROGRAM
}
void openSubdiv_osdGLMeshDisplayPrepare(int use_osd_glsl,
int active_uv_index)
{
- g_use_osd_glsl = use_osd_glsl != 0;
g_active_uv_index = active_uv_index;
+ g_use_osd_glsl = (use_osd_glsl != 0);
/* Update transformation matrices. */
glGetFloatv(GL_PROJECTION_MATRIX, g_transform.projection_matrix);
@@ -494,7 +575,7 @@ void openSubdiv_osdGLMeshDisplayPrepare(int use_osd_glsl,
}
}
-static GLuint prepare_patchDraw(GLMeshInterface *mesh,
+static GLuint prepare_patchDraw(OpenSubdiv_GLMesh *gl_mesh,
bool fill_quads)
{
GLint program = 0;
@@ -509,51 +590,74 @@ static GLuint prepare_patchDraw(GLMeshInterface *mesh,
glUniform1i(location, model == GL_FLAT);
}
- /* TODO(sergey): Bring this back. */
-#if 0
/* Face-vertex data */
- if (mesh->GetDrawContext()->GetFvarDataTextureBuffer()) {
- glActiveTexture(GL_TEXTURE31);
- glBindTexture(GL_TEXTURE_BUFFER,
- mesh->GetDrawContext()->GetFvarDataTextureBuffer());
- glActiveTexture(GL_TEXTURE0);
+ if (gl_mesh->fvar_data != NULL) {
+ if (gl_mesh->fvar_data->texture_buffer) {
+ glActiveTexture(GL_TEXTURE31);
+ glBindTexture(GL_TEXTURE_BUFFER,
+ gl_mesh->fvar_data->texture_buffer);
+ glActiveTexture(GL_TEXTURE0);
+ }
+
+ if (gl_mesh->fvar_data->offset_buffer) {
+ glActiveTexture(GL_TEXTURE30);
+ glBindTexture(GL_TEXTURE_BUFFER,
+ gl_mesh->fvar_data->offset_buffer);
+ glActiveTexture(GL_TEXTURE0);
+ }
GLint location = glGetUniformLocation(program, "osd_fvar_count");
if (location != -1) {
- glUniform1i(location, mesh->GetFVarCount());
+ glUniform1i(location, gl_mesh->fvar_data->fvar_width);
}
location = glGetUniformLocation(program, "osd_active_uv_offset");
if (location != -1) {
- glUniform1i(location,
- g_active_uv_index * 2);
+ if (gl_mesh->fvar_data->channel_offsets.size() > 0 &&
+ g_active_uv_index >= 0)
+ {
+ glUniform1i(location,
+ gl_mesh->fvar_data->channel_offsets[g_active_uv_index]);
+ } else {
+ glUniform1i(location, 0);
+ }
}
+ } else {
+ glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), 0);
+ glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0);
}
-#endif
-
}
return program;
}
if (fill_quads) {
int model;
- GLboolean use_texture_2d;
+ GLboolean use_texture_2d, use_lighting;
glGetIntegerv(GL_SHADE_MODEL, &model);
glGetBooleanv(GL_TEXTURE_2D, &use_texture_2d);
+ glGetBooleanv(GL_LIGHTING, &use_lighting);
if (model == GL_FLAT) {
if (use_texture_2d) {
- program = g_flat_fill_texture2d_program;
+ program = use_lighting
+ ? g_flat_fill_texture2d_program
+ : g_flat_fill_texture2d_shadeless_program;
}
else {
- program = g_flat_fill_solid_program;
+ program = use_lighting
+ ? g_flat_fill_solid_program
+ : g_flat_fill_solid_shadeless_program;
}
}
else {
if (use_texture_2d) {
- program = g_smooth_fill_texture2d_program;
+ program = use_lighting
+ ? g_smooth_fill_texture2d_program
+ : g_smooth_fill_texture2d_shadeless_program;
}
else {
- program = g_smooth_fill_solid_program;
+ program = use_lighting
+ ? g_smooth_fill_solid_program
+ : g_smooth_fill_solid_shadeless_program;
}
}
}
@@ -562,7 +666,7 @@ static GLuint prepare_patchDraw(GLMeshInterface *mesh,
program = g_wireframe_program;
}
- bindProgram(mesh, program);
+ bindProgram(gl_mesh, program);
return program;
}
@@ -623,7 +727,7 @@ static void draw_partition_patches_range(GLMeshInterface *mesh,
const int num_draw_patches = std::min(num_remained_patches,
num_block_patches - start_draw_patch);
perform_drawElements(program,
- i,
+ i + start_draw_patch,
num_draw_patches * num_control_verts,
patch.GetIndexBase() + start_draw_patch * num_control_verts);
num_remained_patches -= num_draw_patches;
@@ -669,7 +773,7 @@ void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh,
}
/* Setup GLSL/OpenGL to draw patches in current context. */
- GLuint program = prepare_patchDraw(mesh, fill_quads != 0);
+ GLuint program = prepare_patchDraw(gl_mesh, fill_quads != 0);
if (start_patch != -1) {
draw_partition_patches_range(mesh,
@@ -684,3 +788,23 @@ void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh,
/* Finish patch drawing by restoring all changes to the OpenGL context. */
finish_patchDraw(fill_quads != 0);
}
+
+void openSubdiv_osdGLAllocFVar(OpenSubdiv_TopologyRefinerDescr *topology_refiner,
+ OpenSubdiv_GLMesh *gl_mesh,
+ const float *fvar_data)
+{
+ GLMeshInterface *mesh =
+ (GLMeshInterface *)(gl_mesh->descriptor);
+ gl_mesh->fvar_data = OBJECT_GUARDED_NEW(OpenSubdiv_GLMeshFVarData);
+ gl_mesh->fvar_data->Create(topology_refiner->osd_refiner,
+ mesh->GetFarPatchTable(),
+ 2,
+ fvar_data);
+}
+
+void openSubdiv_osdGLDestroyFVar(OpenSubdiv_GLMesh *gl_mesh)
+{
+ if (gl_mesh->fvar_data != NULL) {
+ OBJECT_GUARDED_DELETE(gl_mesh->fvar_data, OpenSubdiv_GLMeshFVarData);
+ }
+}
diff --git a/intern/opensubdiv/opensubdiv_topology_refiner.h b/intern/opensubdiv/opensubdiv_topology_refiner.h
new file mode 100644
index 00000000000..b00f6a54201
--- /dev/null
+++ b/intern/opensubdiv/opensubdiv_topology_refiner.h
@@ -0,0 +1,41 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __OPENSUBDIV_TOPOLOGY_REFINER_H__
+#define __OPENSUBDIV_TOPOLOGY_REFINER_H__
+
+#include <opensubdiv/far/topologyRefiner.h>
+
+typedef struct OpenSubdiv_TopologyRefinerDescr {
+ OpenSubdiv::Far::TopologyRefiner *osd_refiner;
+
+ /* TODO(sergey): For now only, need to find better place
+ * after revisiting whole OSD drawing pipeline and Blender
+ * integration.
+ */
+ std::vector<float> uvs;
+} OpenSubdiv_TopologyRefinerDescr;
+
+#endif /* __OPENSUBDIV_TOPOLOGY_REFINER_H__ */
diff --git a/intern/smoke/intern/FLUID_3D.cpp b/intern/smoke/intern/FLUID_3D.cpp
index 4faec894801..8a27818ff36 100644
--- a/intern/smoke/intern/FLUID_3D.cpp
+++ b/intern/smoke/intern/FLUID_3D.cpp
@@ -993,6 +993,9 @@ void FLUID_3D::project()
copyBorderAll(_pressure, 0, _zRes);
+ // fix fluid compression caused in isolated components by obstacle movement
+ fixObstacleCompression(_divergence);
+
// solve Poisson equation
solvePressurePre(_pressure, _divergence, _obstacles);
@@ -1291,6 +1294,142 @@ void FLUID_3D::setObstacleBoundaries(float *_pressure, int zBegin, int zEnd)
} // z-loop
}
+void FLUID_3D::floodFillComponent(int *buffer, size_t *queue, size_t limit, size_t pos, int from, int to)
+{
+ /* Flood 'from' cells with 'to' in the grid. Rely on (from != 0 && from != to && edges == 0) to stop. */
+ int offsets[] = { -1, +1, -_xRes, +_xRes, -_slabSize, +_slabSize };
+ size_t qend = 0;
+
+ buffer[pos] = to;
+ queue[qend++] = pos;
+
+ for (size_t qidx = 0; qidx < qend; qidx++)
+ {
+ pos = queue[qidx];
+
+ for (int i = 0; i < 6; i++)
+ {
+ size_t next = pos + offsets[i];
+
+ if (next < limit && buffer[next] == from)
+ {
+ buffer[next] = to;
+ queue[qend++] = next;
+ }
+ }
+ }
+}
+
+void FLUID_3D::mergeComponents(int *buffer, size_t *queue, size_t cur, size_t other)
+{
+ /* Replace higher value with lower. */
+ if (buffer[other] < buffer[cur])
+ {
+ floodFillComponent(buffer, queue, cur, cur, buffer[cur], buffer[other]);
+ }
+ else if (buffer[cur] < buffer[other])
+ {
+ floodFillComponent(buffer, queue, cur, other, buffer[other], buffer[cur]);
+ }
+}
+
+void FLUID_3D::fixObstacleCompression(float *divergence)
+{
+ int x, y, z;
+ size_t index;
+
+ /* Find compartments completely separated by obstacles.
+ * Edge of the domain is automatically component 0. */
+ int *component = new int[_totalCells];
+ size_t *queue = new size_t[_totalCells];
+
+ memset(component, 0, sizeof(int) * _totalCells);
+
+ int next_id = 1;
+
+ for (z = 1, index = _slabSize + _xRes + 1; z < _zRes - 1; z++, index += 2 * _xRes)
+ {
+ for (y = 1; y < _yRes - 1; y++, index += 2)
+ {
+ for (x = 1; x < _xRes - 1; x++, index++)
+ {
+ if(!_obstacles[index])
+ {
+ /* Check for connection to the domain edge at iteration end. */
+ if ((x == _xRes-2 && !_obstacles[index + 1]) ||
+ (y == _yRes-2 && !_obstacles[index + _xRes]) ||
+ (z == _zRes-2 && !_obstacles[index + _slabSize]))
+ {
+ component[index] = 0;
+ }
+ else {
+ component[index] = next_id;
+ }
+
+ if (!_obstacles[index - 1])
+ mergeComponents(component, queue, index, index - 1);
+ if (!_obstacles[index - _xRes])
+ mergeComponents(component, queue, index, index - _xRes);
+ if (!_obstacles[index - _slabSize])
+ mergeComponents(component, queue, index, index - _slabSize);
+
+ if (component[index] == next_id)
+ next_id++;
+ }
+ }
+ }
+ }
+
+ delete[] queue;
+
+ /* Compute average divergence within each component. */
+ float *total_divergence = new float[next_id];
+ int *component_size = new int[next_id];
+
+ memset(total_divergence, 0, sizeof(float) * next_id);
+ memset(component_size, 0, sizeof(int) * next_id);
+
+ for (z = 1, index = _slabSize + _xRes + 1; z < _zRes - 1; z++, index += 2 * _xRes)
+ {
+ for (y = 1; y < _yRes - 1; y++, index += 2)
+ {
+ for (x = 1; x < _xRes - 1; x++, index++)
+ {
+ if(!_obstacles[index])
+ {
+ int ci = component[index];
+
+ component_size[ci]++;
+ total_divergence[ci] += divergence[index];
+ }
+ }
+ }
+ }
+
+ /* Adjust divergence to make the average zero in each component except the edge. */
+ total_divergence[0] = 0.0f;
+
+ for (z = 1, index = _slabSize + _xRes + 1; z < _zRes - 1; z++, index += 2 * _xRes)
+ {
+ for (y = 1; y < _yRes - 1; y++, index += 2)
+ {
+ for (x = 1; x < _xRes - 1; x++, index++)
+ {
+ if(!_obstacles[index])
+ {
+ int ci = component[index];
+
+ divergence[index] -= total_divergence[ci] / component_size[ci];
+ }
+ }
+ }
+ }
+
+ delete[] component;
+ delete[] component_size;
+ delete[] total_divergence;
+}
+
//////////////////////////////////////////////////////////////////////
// add buoyancy forces
//////////////////////////////////////////////////////////////////////
@@ -1650,4 +1789,4 @@ void FLUID_3D::updateFlame(float *react, float *flame, int total_cells)
else
flame[index] = 0.0f;
}
-} \ No newline at end of file
+}
diff --git a/intern/smoke/intern/FLUID_3D.h b/intern/smoke/intern/FLUID_3D.h
index cd2147b2bee..fe20c10d71d 100644
--- a/intern/smoke/intern/FLUID_3D.h
+++ b/intern/smoke/intern/FLUID_3D.h
@@ -195,6 +195,8 @@ struct FLUID_3D
void setObstacleBoundaries(float *_pressure, int zBegin, int zEnd);
void setObstaclePressure(float *_pressure, int zBegin, int zEnd);
+ void fixObstacleCompression(float *divergence);
+
public:
// advection, accessed e.g. by WTURBULENCE class
//void advectMacCormack();
@@ -202,6 +204,9 @@ struct FLUID_3D
void advectMacCormackEnd1(int zBegin, int zEnd);
void advectMacCormackEnd2(int zBegin, int zEnd);
+ void floodFillComponent(int *components, size_t *queue, size_t limit, size_t start, int from, int to);
+ void mergeComponents(int *components, size_t *queue, size_t cur, size_t other);
+
/* burning */
float *_burning_rate; // RNA pointer
float *_flame_smoke; // RNA pointer
diff --git a/make.bat b/make.bat
index b4cbe8c11e9..c7f2dbbf369 100644
--- a/make.bat
+++ b/make.bat
@@ -6,91 +6,76 @@ setlocal ENABLEEXTENSIONS
set BLENDER_DIR=%~dp0
set BUILD_DIR=%BLENDER_DIR%..\build_windows
set BUILD_TYPE=Release
+rem reset all variables so they do not get accidentally get carried over from previous builds
set BUILD_CMAKE_ARGS=
-
-REM Detect MSVC Installation
-if DEFINED VisualStudioVersion goto msvc_detect_finally
-set VALUE_NAME=ProductDir
-REM Check 64 bits
-set KEY_NAME="HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\12.0\Setup\VC"
-for /F "usebackq skip=2 tokens=1-2*" %%A IN (`REG QUERY %KEY_NAME% /v %VALUE_NAME% 2^>nul`) DO set MSVC_VC_DIR=%%C
-if DEFINED MSVC_VC_DIR goto msvc_detect_finally
-REM Check 32 bits
-set KEY_NAME="HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\12.0\Setup\VC"
-for /F "usebackq skip=2 tokens=1-2*" %%A IN (`REG QUERY %KEY_NAME% /v %VALUE_NAME% 2^>nul`) DO set MSVC_VC_DIR=%%C
-if DEFINED MSVC_VC_DIR goto msvc_detect_finally
-:msvc_detect_finally
-if DEFINED MSVC_VC_DIR call "%MSVC_VC_DIR%\vcvarsall.bat"
-
-
-REM Sanity Checks
-where /Q msbuild
-if %ERRORLEVEL% NEQ 0 (
- echo Error: "MSBuild" command not in the PATH.
- echo You must have MSVC installed and run this from the "Developer Command Prompt"
- echo ^(available from Visual Studio's Start menu entry^), aborting!
- goto EOF
-)
-where /Q cmake
-if %ERRORLEVEL% NEQ 0 (
- echo Error: "CMake" command not in the PATH.
- echo You must have CMake installed and added to your PATH, aborting!
- goto EOF
-)
-if NOT EXIST %BLENDER_DIR%..\lib\nul (
- echo Error: Path to libraries not found "%BLENDER_DIR%..\lib\"
- echo This is needed for building, aborting!
- goto EOF
-)
-
+set BUILD_ARCH=
+set BUILD_VS_VER=
+set BUILD_VS_YEAR=
+set KEY_NAME=
+set MSBUILD_PLATFORM=
+set MUST_CLEAN=
+set NOBUILD=
+set TARGET=
+set WINDOWS_ARCH=
:argv_loop
if NOT "%1" == "" (
REM Help Message
if "%1" == "help" (
- echo.
- echo Convenience targets
- echo - debug
- echo - full
- echo - lite
- echo - headless
- echo - cycles
- echo - bpy
- echo.
- echo Utilities ^(not associated with building^)
- echo - clean
- echo - update
- goto EOF
+ goto HELP
)
REM Build Types
if "%1" == "debug" (
- set BUILD_DIR=%BUILD_DIR%_debug
set BUILD_TYPE=Debug
-
REM Build Configurations
) else if "%1" == "full" (
- set BUILD_DIR=%BUILD_DIR%_full
+ set TARGET=Full
set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% ^
-C"%BLENDER_DIR%\build_files\cmake\config\blender_full.cmake"
) else if "%1" == "lite" (
- set BUILD_DIR=%BUILD_DIR%_lite
+ set TARGET=Lite
set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% ^
-C"%BLENDER_DIR%\build_files\cmake\config\blender_lite.cmake"
) else if "%1" == "cycles" (
- set BUILD_DIR=%BUILD_DIR%_cycles
+ set TARGET=Cycles
set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% ^
-C"%BLENDER_DIR%\build_files\cmake\config\cycles_standalone.cmake"
) else if "%1" == "headless" (
- set BUILD_DIR=%BUILD_DIR%_headless
+ set TARGET=Headless
set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% ^
-C"%BLENDER_DIR%\build_files\cmake\config\blender_headless.cmake"
) else if "%1" == "bpy" (
- set BUILD_DIR=%BUILD_DIR%_bpy
+ set TARGET=Bpy
set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% ^
-C"%BLENDER_DIR%\build_files\cmake\config\bpy_module.cmake"
-
+ ) else if "%1" == "release" (
+ set TARGET=Release
+ ) else if "%1" == "x86" (
+ set BUILD_ARCH=x86
+ ) else if "%1" == "x64" (
+ set BUILD_ARCH=x64
+ ) else if "%1" == "2015" (
+ set BUILD_VS_VER=14
+ set BUILD_VS_YEAR=2015
+ ) else if "%1" == "2013" (
+ set BUILD_VS_VER=12
+ set BUILD_VS_YEAR=2013
+ ) else if "%1" == "packagename" (
+ set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -DCPACK_OVERRIDE_PACKAGENAME="%2"
+ shift /1
+ ) else if "%1" == "nobuild" (
+ set NOBUILD=1
+ ) else if "%1" == "showhash" (
+ for /f "delims=" %%i in ('git rev-parse HEAD') do echo Branch_hash=%%i
+ cd release/datafiles/locale
+ for /f "delims=" %%i in ('git rev-parse HEAD') do echo Locale_hash=%%i
+ cd %~dp0
+ cd release/scripts/addons
+ for /f "delims=" %%i in ('git rev-parse HEAD') do echo Addons_Hash=%%i
+ cd %~dp0
+ goto EOF
REM Non-Build Commands
) else if "%1" == "update" (
svn up ../lib/*
@@ -98,15 +83,7 @@ if NOT "%1" == "" (
git submodule foreach git pull --rebase origin master
goto EOF
) else if "%1" == "clean" (
- msbuild ^
- %BUILD_DIR%\Blender.sln ^
- /target:clean ^
- /property:Configuration=%BUILD_TYPE% ^
- /verbosity:minimal
- if %ERRORLEVEL% NEQ 0 (
- echo Cleaned "%BUILD_DIR%"
- )
- goto EOF
+ set MUST_CLEAN=1
) else (
echo Command "%1" unknown, aborting!
goto EOF
@@ -115,22 +92,120 @@ if NOT "%1" == "" (
shift /1
goto argv_loop
)
+if "%BUILD_ARCH%"=="" (
+ if "%PROCESSOR_ARCHITECTURE%" == "AMD64" (
+ set WINDOWS_ARCH= Win64
+ set BUILD_ARCH=x64
+ ) else if "%PROCESSOR_ARCHITEW6432%" == "AMD64" (
+ set WINDOWS_ARCH= Win64
+ set BUILD_ARCH=x64
+ ) else (
+ set WINDOWS_ARCH=
+ set BUILD_ARCH=x86
+ )
+) else if "%BUILD_ARCH%"=="x64" (
+ set WINDOWS_ARCH= Win64
+ ) else if "%BUILD_ARCH%"=="x86" (
+ set WINDOWS_ARCH=
+ )
-if "%PROCESSOR_ARCHITECTURE%" == "AMD64" (
- set WINDOWS_ARCH=Win64
-) else if "%PROCESSOR_ARCHITEW6432%" == "AMD64" (
- set WINDOWS_ARCH=Win64
-) else (
- set WINDOWS_ARCH=
+if "%BUILD_VS_VER%"=="" (
+ set BUILD_VS_VER=12
+ set BUILD_VS_YEAR=2013
)
-set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -G "Visual Studio 12 2013 %WINDOWS_ARCH%"
+if "%BUILD_ARCH%"=="x64" (
+ set MSBUILD_PLATFORM=x64
+ ) else if "%BUILD_ARCH%"=="x86" (
+ set MSBUILD_PLATFORM=win32
+)
+
+
+set BUILD_DIR=%BUILD_DIR%_%TARGET%_%BUILD_ARCH%_vc%BUILD_VS_VER%_%BUILD_TYPE%
+
+
+if "%target%"=="Release" (
+ rem for vc12 check for both cuda 7.5 and 8
+ if "%CUDA_PATH%"=="" (
+ echo Cuda Not found, aborting!
+ goto EOF
+ )
+ set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% ^
+ -C"%BLENDER_DIR%\build_files\cmake\config\blender_release.cmake"
+)
+
+:DetectMSVC
+REM Detect MSVC Installation
+if DEFINED VisualStudioVersion goto msvc_detect_finally
+set VALUE_NAME=ProductDir
+REM Check 64 bits
+set KEY_NAME="HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\%BUILD_VS_VER%.0\Setup\VC"
+for /F "usebackq skip=2 tokens=1-2*" %%A IN (`REG QUERY %KEY_NAME% /v %VALUE_NAME% 2^>nul`) DO set MSVC_VC_DIR=%%C
+if DEFINED MSVC_VC_DIR goto msvc_detect_finally
+REM Check 32 bits
+set KEY_NAME="HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\%BUILD_VS_VER%.0\Setup\VC"
+for /F "usebackq skip=2 tokens=1-2*" %%A IN (`REG QUERY %KEY_NAME% /v %VALUE_NAME% 2^>nul`) DO set MSVC_VC_DIR=%%C
+if DEFINED MSVC_VC_DIR goto msvc_detect_finally
+:msvc_detect_finally
+if DEFINED MSVC_VC_DIR call "%MSVC_VC_DIR%\vcvarsall.bat"
+
+REM Sanity Checks
+where /Q msbuild
+if %ERRORLEVEL% NEQ 0 (
+ if "%BUILD_VS_VER%"=="12" (
+ rem vs12 not found, try vs14
+ echo Visual Studio 2012 not found, trying Visual Studio 2015.
+ set BUILD_VS_VER=14
+ set BUILD_VS_YEAR=2015
+ goto DetectMSVC
+ ) else (
+ echo Error: "MSBuild" command not in the PATH.
+ echo You must have MSVC installed and run this from the "Developer Command Prompt"
+ echo ^(available from Visual Studio's Start menu entry^), aborting!
+ goto EOF
+ )
+)
+where /Q cmake
+if %ERRORLEVEL% NEQ 0 (
+ echo Error: "CMake" command not in the PATH.
+ echo You must have CMake installed and added to your PATH, aborting!
+ goto EOF
+)
+if NOT EXIST %BLENDER_DIR%..\lib\nul (
+ echo Error: Path to libraries not found "%BLENDER_DIR%..\lib\"
+ echo This is needed for building, aborting!
+ goto EOF
+)
+if "%TARGET%"=="" (
+ echo Error: Convenience target not set
+ echo This is required for building, aborting!
+ echo .
+ goto HELP
+)
+
+set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -G "Visual Studio %BUILD_VS_VER% %BUILD_VS_YEAR%%WINDOWS_ARCH%"
if NOT EXIST %BUILD_DIR%\nul (
mkdir %BUILD_DIR%
)
+if "%MUST_CLEAN%"=="1" (
+ echo Cleaning %BUILD_DIR%
+ msbuild ^
+ %BUILD_DIR%\Blender.sln ^
+ /target:clean ^
+ /property:Configuration=%BUILD_TYPE% ^
+ /verbosity:minimal ^
+ /p:platform=%MSBUILD_PLATFORM%
+
+ if %ERRORLEVEL% NEQ 0 (
+ echo Cleaned "%BUILD_DIR%"
+ )
+ goto EOF
+)
+REM Only configure on first run or when called with nobuild
+if NOT EXIST %BUILD_DIR%\Blender.sln set MUST_CONFIGURE=1
+if "%NOBUILD%"=="1" set MUST_CONFIGURE=1
-REM Only configure on first run
-if NOT EXIST %BUILD_DIR%\Blender.sln (
+if "%MUST_CONFIGURE%"=="1" (
cmake ^
%BUILD_CMAKE_ARGS% ^
-H%BLENDER_DIR% ^
@@ -142,13 +217,16 @@ if NOT EXIST %BUILD_DIR%\Blender.sln (
goto EOF
)
)
+if "%NOBUILD%"=="1" goto EOF
msbuild ^
%BUILD_DIR%\Blender.sln ^
/target:build ^
/property:Configuration=%BUILD_TYPE% ^
/maxcpucount ^
- /verbosity:minimal
+ /verbosity:minimal ^
+ /p:platform=%MSBUILD_PLATFORM% ^
+ /flp:Summary;Verbosity=minimal;LogFile=%BUILD_DIR%\Build.log
if %ERRORLEVEL% NEQ 0 (
echo "Build Failed"
@@ -158,7 +236,8 @@ if %ERRORLEVEL% NEQ 0 (
msbuild ^
%BUILD_DIR%\INSTALL.vcxproj ^
/property:Configuration=%BUILD_TYPE% ^
- /verbosity:minimal
+ /verbosity:minimal ^
+ /p:platform=%MSBUILD_PLATFORM%
echo.
echo At any point you can optionally modify your build configuration by editing:
@@ -166,6 +245,31 @@ echo "%BUILD_DIR%\CMakeCache.txt", then run "make" again to build with the chang
echo.
echo Blender successfully built, run from: "%BUILD_DIR%\bin\%BUILD_TYPE%"
echo.
+goto EOF
+:HELP
+ echo.
+ echo Convenience targets
+ echo - release ^(identical to the offical blender.org builds^)
+ echo - full ^(same as release minus the cuda kernels^)
+ echo - lite
+ echo - headless
+ echo - cycles
+ echo - bpy
+ echo.
+ echo Utilities ^(not associated with building^)
+ echo - clean ^(Target must be set^)
+ echo - update
+ echo - nobuild ^(only generate project files^)
+ echo - showhash ^(Show git hashes of source tree^)
+ echo.
+ echo Configuration options
+ echo - debug ^(Build an unoptimized debuggable build^)
+ echo - packagename [newname] ^(override default cpack package name^)
+ echo - x86 ^(override host autodetect and build 32 bit code^)
+ echo - x64 ^(override host autodetect and build 64 bit code^)
+ echo - 2013 ^(build with visual studio 2013^)
+ echo - 2015 ^(build with visual studio 2015^) [EXPERIMENTAL]
+ echo.
:EOF
diff --git a/release/bin/blender-thumbnailer.py b/release/bin/blender-thumbnailer.py
index fe5d462bba9..5d2dd958a92 100755
--- a/release/bin/blender-thumbnailer.py
+++ b/release/bin/blender-thumbnailer.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# ##### BEGIN GPL LICENSE BLOCK #####
#
diff --git a/release/datafiles/LICENSE-droidsans.ttf.txt b/release/datafiles/LICENSE-droidsans.ttf.txt
index cf6f53e8644..6711ad37338 100644
--- a/release/datafiles/LICENSE-droidsans.ttf.txt
+++ b/release/datafiles/LICENSE-droidsans.ttf.txt
@@ -52,6 +52,8 @@ License: GPL-2.1+
(8) tlwg Loma (Thaï)
Copyright: 2003 National Electronics and Computer Technology Center
+Modified to fix and/or adapt kerning to Blender basic layout engine by Hồ Châu in 2016.
+
License: GPL-2+ with Font exception
See Appendices C.
diff --git a/release/datafiles/blender_icons.svg b/release/datafiles/blender_icons.svg
index 40b974661fa..b54cadd40bc 100644
--- a/release/datafiles/blender_icons.svg
+++ b/release/datafiles/blender_icons.svg
@@ -892,18 +892,6 @@
style="stop-color:#ffedd5;stop-opacity:1;" />
</linearGradient>
<linearGradient
- inkscape:collect="always"
- id="linearGradient24735">
- <stop
- style="stop-color:#000000;stop-opacity:1;"
- offset="0"
- id="stop24737" />
- <stop
- style="stop-color:#000000;stop-opacity:0;"
- offset="1"
- id="stop24739" />
- </linearGradient>
- <linearGradient
id="linearGradient24727">
<stop
style="stop-color:#3d361a;stop-opacity:1;"
@@ -1329,30 +1317,6 @@
y1="132.15414"
x2="130.10634"
y2="117.10313" />
- <linearGradient
- id="linearGradient30777"
- inkscape:collect="always">
- <stop
- id="stop30779"
- offset="0"
- style="stop-color:#acacac;stop-opacity:1" />
- <stop
- id="stop30781"
- offset="1"
- style="stop-color:black;stop-opacity:0;" />
- </linearGradient>
- <linearGradient
- inkscape:collect="always"
- id="linearGradient29485">
- <stop
- style="stop-color:black;stop-opacity:1;"
- offset="0"
- id="stop29487" />
- <stop
- style="stop-color:black;stop-opacity:0;"
- offset="1"
- id="stop29489" />
- </linearGradient>
<filter
inkscape:collect="always"
x="-0.55821538"
@@ -1397,19 +1361,6 @@
style="stop-color:#9a9a9a;stop-opacity:1.0000000;"
id="stop15568" />
</radialGradient>
- <filter
- inkscape:collect="always"
- x="-0.45600089"
- width="1.9120018"
- y="-0.50666559"
- height="2.0133312"
- id="filter63011"
- color-interpolation-filters="sRGB">
- <feGaussianBlur
- inkscape:collect="always"
- stdDeviation="1.899998"
- id="feGaussianBlur63013" />
- </filter>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath13106">
@@ -5796,88 +5747,6 @@
x2="256"
y2="459"
gradientUnits="userSpaceOnUse" />
- <radialGradient
- inkscape:collect="always"
- xlink:href="#aigrd2"
- id="radialGradient21565"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(0.2798768,0,0,0.279916,6.0465962,-0.3619733)"
- cx="20.892099"
- cy="114.5684"
- fx="20.892099"
- fy="114.5684"
- r="5.256" />
- <radialGradient
- inkscape:collect="always"
- xlink:href="#aigrd2"
- id="radialGradient21567"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(0.2798768,0,0,0.279916,6.0465962,-0.3619733)"
- cx="20.892099"
- cy="114.5684"
- fx="20.892099"
- fy="114.5684"
- r="5.256" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient1610"
- id="linearGradient21594"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(2.4126967,0,0,2.7035619,-536.07088,379.29465)"
- x1="236.94902"
- y1="-14.103641"
- x2="276.89801"
- y2="32.076183" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient5060"
- id="linearGradient21596"
- gradientUnits="userSpaceOnUse"
- gradientTransform="translate(-47.00001,58.00194)"
- x1="160.14388"
- y1="376.27383"
- x2="174.29811"
- y2="383.69843" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient1610"
- id="linearGradient21647"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(2.4126967,0,0,2.7035619,-536.07088,379.29465)"
- x1="236.94902"
- y1="-14.103641"
- x2="276.89801"
- y2="31.515814" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient5060"
- id="linearGradient21649"
- gradientUnits="userSpaceOnUse"
- gradientTransform="translate(-47.00001,58.00194)"
- x1="160.14388"
- y1="376.27383"
- x2="174.29811"
- y2="383.69843" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient1610"
- id="linearGradient21977"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(2.4126967,0,0,2.7035619,-536.07088,379.29465)"
- x1="236.94902"
- y1="-14.103641"
- x2="276.89801"
- y2="31.515814" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient5060"
- id="linearGradient21979"
- gradientUnits="userSpaceOnUse"
- gradientTransform="translate(-47.00001,58.00194)"
- x1="160.14388"
- y1="376.27383"
- x2="174.29811"
- y2="383.69843" />
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath22590">
@@ -5976,68 +5845,6 @@
style="fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.80000001;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
</clipPath>
<linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient1610"
- id="linearGradient23978"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(2.4126967,0,0,2.7035619,-536.07088,379.29465)"
- x1="236.94902"
- y1="-14.103641"
- x2="276.89801"
- y2="31.515814" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient5060"
- id="linearGradient23980"
- gradientUnits="userSpaceOnUse"
- gradientTransform="translate(-47.00001,58.00194)"
- x1="160.14388"
- y1="376.27383"
- x2="174.29811"
- y2="383.69843" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient31320"
- id="linearGradient23982"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(1,0,0,0.733333,808.99997,-697.8)"
- x1="150.5"
- y1="239.9987"
- x2="150.5"
- y2="237" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient29485"
- id="linearGradient23986"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(0,1,1,0,715,364)"
- x1="147.0625"
- y1="243.76387"
- x2="142.9375"
- y2="243.69914" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient30777"
- id="linearGradient23988"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(1,0,0,1.2857143,364,645.14283)"
- x1="148"
- y1="244.11113"
- x2="144"
- y2="244.11113" />
- <linearGradient
- id="linearGradient3564"
- inkscape:collect="always">
- <stop
- id="stop3566"
- offset="0"
- style="stop-color:white;stop-opacity:1;" />
- <stop
- id="stop3568"
- offset="1"
- style="stop-color:white;stop-opacity:0;" />
- </linearGradient>
- <linearGradient
id="linearGradient39155">
<stop
id="stop39157"
@@ -6049,79 +5856,6 @@
style="stop-color:#dadada;stop-opacity:1;" />
</linearGradient>
<linearGradient
- id="linearGradient39171"
- inkscape:collect="always">
- <stop
- id="stop39173"
- offset="0"
- style="stop-color:white;stop-opacity:1;" />
- <stop
- id="stop39175"
- offset="1"
- style="stop-color:white;stop-opacity:0;" />
- </linearGradient>
- <radialGradient
- inkscape:collect="always"
- xlink:href="#linearGradient18821"
- id="radialGradient21442"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(0.8728692,0.8400852,-1.1671853,1.2200916,594.18579,-173.07738)"
- cx="75.554794"
- cy="500.26215"
- fx="75.554794"
- fy="500.26215"
- r="3.1650217" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient39155"
- id="linearGradient21444"
- gradientUnits="userSpaceOnUse"
- x1="31.1875"
- y1="18.875"
- x2="29.875"
- y2="34.375" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient3564"
- id="linearGradient21446"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(0.06818845,0,0,0.06818845,22.51112,27.02885)"
- x1="185.9903"
- y1="193.33229"
- x2="190.46461"
- y2="-458.05771" />
- <radialGradient
- inkscape:collect="always"
- xlink:href="#linearGradient39171"
- id="radialGradient21448"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(1.647222,0,0,1.26792,-15.47413,-5.79794)"
- cx="26.109201"
- cy="19.668886"
- fx="26.109201"
- fy="19.668886"
- r="20.278975" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient1610"
- id="linearGradient22274"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(2.4126967,0,0,2.7035619,-536.07088,379.29465)"
- x1="236.94902"
- y1="-14.103641"
- x2="276.89801"
- y2="32.076183" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient5060"
- id="linearGradient22276"
- gradientUnits="userSpaceOnUse"
- gradientTransform="translate(-47.00001,58.00194)"
- x1="160.14388"
- y1="376.27383"
- x2="174.29811"
- y2="383.69843" />
- <linearGradient
inkscape:collect="always"
xlink:href="#linearGradient319"
id="linearGradient38718"
@@ -8869,123 +8603,6 @@
y2="287.50357" />
<linearGradient
inkscape:collect="always"
- xlink:href="#linearGradient24727"
- id="linearGradient24809"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(1.043478,0,0,0.956667,765.84783,-274.57833)"
- x1="59.158501"
- y1="437.02835"
- x2="45.021851"
- y2="349.81818" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient24735"
- id="linearGradient24811"
- gradientUnits="userSpaceOnUse"
- x1="807"
- y1="101.5"
- x2="841"
- y2="101.5" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient24711"
- id="linearGradient24813"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(1.043478,0,0,0.956667,767.34783,-275.07833)"
- x1="63.539974"
- y1="421.80756"
- x2="63.407566"
- y2="347.78201" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient16500"
- id="linearGradient24815"
- gradientUnits="userSpaceOnUse"
- gradientTransform="translate(-127,4e-6)"
- x1="954"
- y1="102"
- x2="936"
- y2="114.99999" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient24727"
- id="linearGradient24839"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(1.043478,0,0,0.956667,765.84783,-274.57833)"
- x1="59.158501"
- y1="437.02835"
- x2="45.021851"
- y2="349.81818" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient24735"
- id="linearGradient24841"
- gradientUnits="userSpaceOnUse"
- x1="807"
- y1="101.5"
- x2="841"
- y2="101.5" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient24144"
- id="linearGradient24843"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(1.043478,0,0,0.956667,767.34783,-275.07833)"
- x1="64.019142"
- y1="419.06366"
- x2="63.407566"
- y2="347.78201" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient16500"
- id="linearGradient24845"
- gradientUnits="userSpaceOnUse"
- gradientTransform="translate(-127,4e-6)"
- x1="954"
- y1="102"
- x2="936"
- y2="114.99999" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient24727"
- id="linearGradient24867"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(1.043478,0,0,0.956667,765.84783,-274.57833)"
- x1="59.158501"
- y1="437.02835"
- x2="45.021851"
- y2="349.81818" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient24735"
- id="linearGradient24869"
- gradientUnits="userSpaceOnUse"
- x1="807"
- y1="101.5"
- x2="841"
- y2="101.5" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient24711"
- id="linearGradient24871"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(1.043478,0,0,0.956667,767.34783,-275.07833)"
- x1="63.659767"
- y1="422.46088"
- x2="63.407566"
- y2="347.78201" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient16500"
- id="linearGradient24873"
- gradientUnits="userSpaceOnUse"
- gradientTransform="translate(-127,4e-6)"
- x1="954"
- y1="102"
- x2="936"
- y2="114.99999" />
- <linearGradient
- inkscape:collect="always"
xlink:href="#linearGradient24679"
id="linearGradient25073"
gradientUnits="userSpaceOnUse"
@@ -15527,50 +15144,6 @@
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient44939-8"
- id="linearGradient44402"
- gradientUnits="userSpaceOnUse"
- x1="351.15625"
- y1="108.35222"
- x2="345.40625"
- y2="108.00847" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient44939-8"
- id="linearGradient44404"
- gradientUnits="userSpaceOnUse"
- x1="351.71875"
- y1="106.93575"
- x2="347.1875"
- y2="106.7795" />
- <filter
- inkscape:collect="always"
- id="filter44473"
- x="-0.12578467"
- width="1.2515693"
- y="-0.11472401"
- height="1.229448"
- color-interpolation-filters="sRGB">
- <feGaussianBlur
- inkscape:collect="always"
- stdDeviation="0.81235925"
- id="feGaussianBlur44475" />
- </filter>
- <filter
- inkscape:collect="always"
- id="filter44477"
- x="-0.12176471"
- width="1.2435294"
- y="-0.11828571"
- height="1.2365714"
- color-interpolation-filters="sRGB">
- <feGaussianBlur
- inkscape:collect="always"
- stdDeviation="0.8625"
- id="feGaussianBlur44479" />
- </filter>
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient44939-8"
id="linearGradient44485"
gradientUnits="userSpaceOnUse"
x1="279.75"
@@ -16037,46 +15610,6 @@
r="3.5" />
<linearGradient
inkscape:collect="always"
- xlink:href="#linearGradient1610"
- id="linearGradient30321"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(2.4126967,0,0,2.7035619,-536.07088,379.29465)"
- x1="240.70209"
- y1="-9.4293213"
- x2="276.89801"
- y2="31.515814" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient5060"
- id="linearGradient30323"
- gradientUnits="userSpaceOnUse"
- gradientTransform="translate(-47.00001,58.00194)"
- x1="160.14388"
- y1="376.27383"
- x2="174.29811"
- y2="383.69843" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient1610"
- id="linearGradient30368"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(2.4126967,0,0,2.7035619,-536.07088,379.29465)"
- x1="236.94902"
- y1="-14.103641"
- x2="276.89801"
- y2="31.515814" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient5060"
- id="linearGradient30370"
- gradientUnits="userSpaceOnUse"
- gradientTransform="translate(-47.00001,58.00194)"
- x1="160.14388"
- y1="376.27383"
- x2="174.29811"
- y2="383.69843" />
- <linearGradient
- inkscape:collect="always"
xlink:href="#linearGradient30208"
id="linearGradient25056"
gradientUnits="userSpaceOnUse"
@@ -17453,16 +16986,6 @@
xlink:href="#linearGradient34488-1-8"
inkscape:collect="always" />
<linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient1610-71-6-9-7"
- id="linearGradient21875-7-1-0-1"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(2.4126967,0,0,2.7035619,-536.07088,379.29465)"
- x1="236.94902"
- y1="-14.103641"
- x2="278.34866"
- y2="32.902874" />
- <linearGradient
id="linearGradient1610-71-6-9-7">
<stop
style="stop-color:black;stop-opacity:1;"
@@ -17486,29 +17009,6 @@
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
</clipPath>
- <filter
- inkscape:collect="always"
- x="-0.45600089"
- width="1.9120018"
- y="-0.50666559"
- height="2.0133312"
- id="filter63011-6-7-0-8"
- color-interpolation-filters="sRGB">
- <feGaussianBlur
- inkscape:collect="always"
- stdDeviation="1.899998"
- id="feGaussianBlur63013-0-1-0-8" />
- </filter>
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient5060-6-6-2-4"
- id="linearGradient21877-3-2-7-2"
- gradientUnits="userSpaceOnUse"
- gradientTransform="translate(-47.00001,58.00194)"
- x1="160.14388"
- y1="376.27383"
- x2="174.29811"
- y2="383.69843" />
<linearGradient
id="linearGradient5060-6-6-2-4">
<stop
@@ -17521,16 +17021,6 @@
style="stop-color:#000000;stop-opacity:0;" />
</linearGradient>
<linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient4671-6-4-1-7"
- id="linearGradient34959-9-2-1"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(0.562541,0,0,0.567972,-9.399749,-5.305317)"
- x1="1666.1765"
- y1="639.65356"
- x2="1659.0875"
- y2="629.23273" />
- <linearGradient
id="linearGradient4671-6-4-1-7">
<stop
id="stop4673-7-6-4-1"
@@ -17542,16 +17032,6 @@
style="stop-color:#ffe873;stop-opacity:1" />
</linearGradient>
<linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient4689-1-6-4-2"
- id="linearGradient34961-3-6-5"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(0.562541,0,0,0.567972,-9.399749,-5.305317)"
- x1="1641.4773"
- y1="607.50525"
- x2="1663.2872"
- y2="626.40344" />
- <linearGradient
id="linearGradient4689-1-6-4-2">
<stop
id="stop4691-6-2-6-7"
@@ -17564,95 +17044,6 @@
</linearGradient>
<linearGradient
inkscape:collect="always"
- xlink:href="#linearGradient3966-5-1-4-8-9-88-8-4"
- id="linearGradient34963-5-9-1"
- gradientUnits="userSpaceOnUse"
- x1="922.89703"
- y1="339.66599"
- x2="924.10608"
- y2="344.10001" />
- <linearGradient
- inkscape:collect="always"
- id="linearGradient3966-5-1-4-8-9-88-8-4">
- <stop
- style="stop-color:#ffffff;stop-opacity:1;"
- offset="0"
- id="stop3968-7-9-0-8-2-1-3-2" />
- <stop
- style="stop-color:#ffffff;stop-opacity:0;"
- offset="1"
- id="stop3970-6-6-6-2-8-2-5-3" />
- </linearGradient>
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient3966-5-1-4-8-9-88-8-4"
- id="linearGradient34965-1-5-2"
- gradientUnits="userSpaceOnUse"
- x1="919.09998"
- y1="345.42163"
- x2="922.104"
- y2="355.75" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient3966-5-1-4-8-9-8-9-5-5"
- id="linearGradient34967-4-1-8"
- gradientUnits="userSpaceOnUse"
- x1="922.64624"
- y1="342.71866"
- x2="921.82654"
- y2="341.98108" />
- <linearGradient
- inkscape:collect="always"
- id="linearGradient3966-5-1-4-8-9-8-9-5-5">
- <stop
- style="stop-color:#ffffff;stop-opacity:1;"
- offset="0"
- id="stop3968-7-9-0-8-2-9-8-5-7" />
- <stop
- style="stop-color:#ffffff;stop-opacity:0;"
- offset="1"
- id="stop3970-6-6-6-2-8-0-2-8-6" />
- </linearGradient>
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient3966-5-1-4-8-9-88-8-4"
- id="linearGradient34969-4-4-1"
- gradientUnits="userSpaceOnUse"
- x1="917.75"
- y1="355.5"
- x2="917.25"
- y2="353" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient3966-5-1-4-8-9-88-8-4"
- id="linearGradient34971-5-0-9"
- gradientUnits="userSpaceOnUse"
- x1="923"
- y1="343.75"
- x2="923"
- y2="344.75" />
- <radialGradient
- inkscape:collect="always"
- xlink:href="#linearGradient3966-5-1-4-8-9-88-8-4"
- id="radialGradient34973-2-5-7"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(2.4166677,-7.678944e-6,1.853542e-6,0.58333478,-1309.0016,145.80659)"
- cx="924"
- cy="349.20001"
- fx="924"
- fy="349.20001"
- r="6" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient3966-5-1-4-8-9-88-8-4"
- id="linearGradient34975-9-4-9"
- gradientUnits="userSpaceOnUse"
- x1="921.34045"
- y1="341.34042"
- x2="922.16492"
- y2="342.16492" />
- <linearGradient
- inkscape:collect="always"
id="linearGradient3944-4-6-7-7">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
@@ -21294,16 +20685,6 @@
x2="50.907307"
y2="95.401253" />
<linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient14829"
- id="linearGradient14814"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(2.4126967,0,0,2.7035619,-722.19531,285.57729)"
- x1="236.94902"
- y1="-14.103641"
- x2="276.89801"
- y2="32.076183" />
- <linearGradient
id="linearGradient14829">
<stop
id="stop14831"
@@ -21314,28 +20695,6 @@
offset="1"
style="stop-color:#757575;stop-opacity:1;" />
</linearGradient>
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient14632"
- id="linearGradient14816"
- gradientUnits="userSpaceOnUse"
- gradientTransform="translate(-214.43013,42.779961)"
- x1="148.54834"
- y1="301.96149"
- x2="166.33298"
- y2="317.25269" />
- <linearGradient
- inkscape:collect="always"
- id="linearGradient14632">
- <stop
- style="stop-color:#ffffff;stop-opacity:1;"
- offset="0"
- id="stop14634" />
- <stop
- style="stop-color:#ffffff;stop-opacity:0;"
- offset="1"
- id="stop14636" />
- </linearGradient>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath13106-0">
@@ -21349,29 +20708,6 @@
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
</clipPath>
- <filter
- inkscape:collect="always"
- x="-0.45600089"
- width="1.9120018"
- y="-0.50666559"
- height="2.0133312"
- id="filter63011-8"
- color-interpolation-filters="sRGB">
- <feGaussianBlur
- inkscape:collect="always"
- stdDeviation="1.899998"
- id="feGaussianBlur63013-0" />
- </filter>
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient5060-9"
- id="linearGradient14818"
- gradientUnits="userSpaceOnUse"
- gradientTransform="translate(-233.12445,-35.715412)"
- x1="160.14388"
- y1="376.27383"
- x2="174.29811"
- y2="383.69843" />
<linearGradient
id="linearGradient5060-9">
<stop
@@ -21383,17 +20719,6 @@
offset="1"
style="stop-color:#000000;stop-opacity:0;" />
</linearGradient>
- <radialGradient
- inkscape:collect="always"
- xlink:href="#linearGradient18821-9"
- id="radialGradient14820"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(0.8728692,0.8400852,-1.1671853,1.2200916,594.18579,-173.07738)"
- cx="75.554794"
- cy="500.26215"
- fx="75.554794"
- fy="500.26215"
- r="3.1650217" />
<linearGradient
id="linearGradient18821-9">
<stop
@@ -21406,15 +20731,6 @@
id="stop18825-4" />
</linearGradient>
<linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient39155-5"
- id="linearGradient14822"
- gradientUnits="userSpaceOnUse"
- x1="31.1875"
- y1="18.875"
- x2="29.875"
- y2="34.375" />
- <linearGradient
id="linearGradient39155-5">
<stop
id="stop39157-4"
@@ -21427,51 +20743,6 @@
</linearGradient>
<linearGradient
inkscape:collect="always"
- xlink:href="#linearGradient3564-9"
- id="linearGradient14825"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(0.06818845,0,0,0.06818845,22.51112,27.02885)"
- x1="185.9903"
- y1="193.33229"
- x2="190.46461"
- y2="-458.05771" />
- <linearGradient
- id="linearGradient3564-9"
- inkscape:collect="always">
- <stop
- id="stop3566-9"
- offset="0"
- style="stop-color:white;stop-opacity:1;" />
- <stop
- id="stop3568-2"
- offset="1"
- style="stop-color:white;stop-opacity:0;" />
- </linearGradient>
- <radialGradient
- inkscape:collect="always"
- xlink:href="#linearGradient39171-8"
- id="radialGradient14827"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(1.647222,0,0,1.26792,-15.47413,-5.79794)"
- cx="26.109201"
- cy="19.668886"
- fx="26.109201"
- fy="19.668886"
- r="20.278975" />
- <linearGradient
- id="linearGradient39171-8"
- inkscape:collect="always">
- <stop
- id="stop39173-9"
- offset="0"
- style="stop-color:white;stop-opacity:1;" />
- <stop
- id="stop39175-5"
- offset="1"
- style="stop-color:white;stop-opacity:0;" />
- </linearGradient>
- <linearGradient
- inkscape:collect="always"
xlink:href="#linearGradient14829"
id="linearGradient14800"
gradientUnits="userSpaceOnUse"
@@ -30957,6 +30228,1116 @@
y1="-16"
x2="-93.75"
y2="-16.264704" />
+ <filter
+ inkscape:label="Opacity"
+ style="color-interpolation-filters:sRGB"
+ id="filter17385">
+ <feColorMatrix
+ values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 5 -1 "
+ result="colormatrix"
+ id="feColorMatrix17387" />
+ <feComposite
+ k4="0"
+ k3="0"
+ k1="0"
+ in2="colormatrix"
+ operator="arithmetic"
+ k2="0.24"
+ result="composite"
+ id="feComposite17389" />
+ </filter>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient18134"
+ id="radialGradient37501-3-6-2"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-0.08933014,-0.7764284,0.7350832,-0.08334857,57.410559,233.30156)"
+ cx="135.83771"
+ cy="117.97826"
+ fx="135.83771"
+ fy="117.97826"
+ r="8" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient18134"
+ id="radialGradient37501-3-6"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-0.08933014,-0.7764284,0.7350832,-0.08334857,57.410559,233.30156)"
+ cx="135.83771"
+ cy="117.97826"
+ fx="135.83771"
+ fy="117.97826"
+ r="8" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient18134"
+ id="linearGradient17463"
+ gradientUnits="userSpaceOnUse"
+ x1="121.19734"
+ y1="105.94044"
+ x2="148.06364"
+ y2="137.6748" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient16595"
+ id="linearGradient17281"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(144,188)"
+ x1="209"
+ y1="238"
+ x2="226.625"
+ y2="251.71078" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient18134"
+ id="linearGradient31399"
+ gradientUnits="userSpaceOnUse"
+ x1="62.793919"
+ y1="133.73566"
+ x2="64.109718"
+ y2="135.18265" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient319"
+ id="linearGradient31452"
+ gradientUnits="userSpaceOnUse"
+ x1="121.19734"
+ y1="105.94044"
+ x2="148.06364"
+ y2="137.6748" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient1610-36-6-5"
+ id="linearGradient31454"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(144,188)"
+ x1="209"
+ y1="238"
+ x2="226.625"
+ y2="251.71078" />
+ <linearGradient
+ y2="32.076183"
+ x2="276.89801"
+ y1="-14.103641"
+ x1="236.94902"
+ gradientTransform="matrix(2.4126967,0,0,2.7035619,-536.07088,379.29465)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient22274-8"
+ xlink:href="#linearGradient1610-2"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient1610-2">
+ <stop
+ id="stop1611-8-9"
+ offset="0"
+ style="stop-color:black;stop-opacity:1;" />
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0.5"
+ id="stop6596" />
+ <stop
+ id="stop1612-0-6"
+ offset="1"
+ style="stop-color:#c8c8c8;stop-opacity:1;" />
+ </linearGradient>
+ <clipPath
+ id="clipPath13106-5"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path34850-6-6"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <filter
+ style="color-interpolation-filters:sRGB"
+ id="filter63011-5"
+ height="2.0133312"
+ y="-0.50666559"
+ width="1.9120018"
+ x="-0.45600089"
+ inkscape:collect="always">
+ <feGaussianBlur
+ id="feGaussianBlur63013-8"
+ stdDeviation="1.899998"
+ inkscape:collect="always" />
+ </filter>
+ <linearGradient
+ y2="383.69843"
+ x2="174.29811"
+ y1="376.27383"
+ x1="160.14388"
+ gradientTransform="translate(-47.00001,58.00194)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient22276-5"
+ xlink:href="#linearGradient18495"
+ inkscape:collect="always" />
+ <clipPath
+ id="clipPath6172"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path6174"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <radialGradient
+ r="3.1650217"
+ fy="500.26215"
+ fx="75.554794"
+ cy="500.26215"
+ cx="75.554794"
+ gradientTransform="matrix(0.8728692,0.8400852,-1.1671853,1.2200916,594.18579,-173.07738)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient21442-6-790"
+ xlink:href="#linearGradient18821-1-16"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient18821-1-16">
+ <stop
+ id="stop20589"
+ offset="0"
+ style="stop-color:#e3604f;stop-opacity:1;" />
+ <stop
+ id="stop20591"
+ offset="1"
+ style="stop-color:#e3604f;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ y2="34.375"
+ x2="29.875"
+ y1="18.875"
+ x1="31.1875"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient21444-0-352"
+ xlink:href="#linearGradient39155-0-813"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient39155-0-813">
+ <stop
+ style="stop-color:#e6e6e6;stop-opacity:1;"
+ offset="0"
+ id="stop20595" />
+ <stop
+ style="stop-color:#c4c4c4;stop-opacity:1;"
+ offset="1"
+ id="stop20597" />
+ </linearGradient>
+ <linearGradient
+ y2="-458.05771"
+ x2="190.46461"
+ y1="193.33229"
+ x1="185.9903"
+ gradientTransform="matrix(0.06818845,0,0,0.06818845,22.51112,27.02885)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient21446-3-145"
+ xlink:href="#linearGradient3564-2-380"
+ inkscape:collect="always" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3564-2-380">
+ <stop
+ style="stop-color:#e6e6e6;stop-opacity:1;"
+ offset="0"
+ id="stop20601" />
+ <stop
+ style="stop-color:#e6e6e6;stop-opacity:0;"
+ offset="1"
+ id="stop20603" />
+ </linearGradient>
+ <radialGradient
+ r="20.278975"
+ fy="19.668886"
+ fx="26.109201"
+ cy="19.668886"
+ cx="26.109201"
+ gradientTransform="matrix(1.647222,0,0,1.26792,-15.47413,-5.79794)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient21448-8-143"
+ xlink:href="#linearGradient3564-2-380"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="32.902874"
+ x2="278.34866"
+ y1="-14.103641"
+ x1="236.94902"
+ gradientTransform="matrix(2.4126967,0,0,2.7035619,-536.07088,379.29465)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient21875-7-1-0-1"
+ xlink:href="#linearGradient16595"
+ inkscape:collect="always" />
+ <clipPath
+ id="clipPath13106-9-2-9-9-4"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path34850-4-7-0-4-0"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none"
+ inkscape:connector-curvature="0" />
+ </clipPath>
+ <filter
+ style="color-interpolation-filters:sRGB"
+ id="filter63011-6-7-0-8"
+ height="2.0133312"
+ y="-0.50666559"
+ width="1.9120018"
+ x="-0.45600089"
+ inkscape:collect="always">
+ <feGaussianBlur
+ id="feGaussianBlur63013-0-1-0-8"
+ stdDeviation="1.899998"
+ inkscape:collect="always" />
+ </filter>
+ <linearGradient
+ y2="383.69843"
+ x2="174.29811"
+ y1="376.27383"
+ x1="160.14388"
+ gradientTransform="translate(-47.00001,58.00194)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient21877-3-2-7-2"
+ xlink:href="#linearGradient18495"
+ inkscape:collect="always" />
+ <clipPath
+ id="clipPath6208"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path6210"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none"
+ inkscape:connector-curvature="0" />
+ </clipPath>
+ <linearGradient
+ y2="629.23273"
+ x2="1659.0875"
+ y1="639.65356"
+ x1="1666.1765"
+ gradientTransform="matrix(0.562541,0,0,0.567972,-9.399749,-5.305317)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient34959-9-2-1"
+ xlink:href="#linearGradient4671-6-4-1-7"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="626.40344"
+ x2="1663.2872"
+ y1="607.50525"
+ x1="1641.4773"
+ gradientTransform="matrix(0.562541,0,0,0.567972,-9.399749,-5.305317)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient34961-3-6-5"
+ xlink:href="#linearGradient4689-1-6-4-2"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="344.10001"
+ x2="924.10608"
+ y1="339.66599"
+ x1="922.89703"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient34963-5-9-1"
+ xlink:href="#linearGradient18134"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="355.75"
+ x2="922.104"
+ y1="345.42163"
+ x1="919.09998"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient34965-1-5-2"
+ xlink:href="#linearGradient18134"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="341.98108"
+ x2="921.82654"
+ y1="342.71866"
+ x1="922.64624"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient34967-4-1-8"
+ xlink:href="#linearGradient18134"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="353"
+ x2="917.25"
+ y1="355.5"
+ x1="917.75"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient34969-4-4-1"
+ xlink:href="#linearGradient18134"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="344.75"
+ x2="923"
+ y1="343.75"
+ x1="923"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient34971-5-0-9"
+ xlink:href="#linearGradient18134"
+ inkscape:collect="always" />
+ <radialGradient
+ r="6"
+ fy="349.20001"
+ fx="924"
+ cy="349.20001"
+ cx="924"
+ gradientTransform="matrix(2.4166677,-7.678944e-6,1.853542e-6,0.58333478,-1309.0016,145.80659)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient34973-2-5-7"
+ xlink:href="#linearGradient18134"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="342.16492"
+ x2="922.16492"
+ y1="341.34042"
+ x1="921.34045"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient34975-9-4-9"
+ xlink:href="#linearGradient18134"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="349.81818"
+ x2="45.021851"
+ y1="437.02835"
+ x1="59.158501"
+ gradientTransform="matrix(1.043478,0,0,0.956667,765.84783,-274.57833)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient24867"
+ xlink:href="#linearGradient24727"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="101.5"
+ x2="841"
+ y1="101.5"
+ x1="807"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient24869"
+ xlink:href="#linearGradient18495"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="347.78201"
+ x2="63.407566"
+ y1="422.46088"
+ x1="63.659767"
+ gradientTransform="matrix(1.043478,0,0,0.956667,767.34783,-275.07833)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient24871"
+ xlink:href="#linearGradient24711"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="114.99999"
+ x2="936"
+ y1="102"
+ x1="954"
+ gradientTransform="translate(-127,4e-6)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient24873"
+ xlink:href="#linearGradient18495"
+ inkscape:collect="always" />
+ <filter
+ style="color-interpolation-filters:sRGB"
+ inkscape:label="Drop Shadow"
+ id="filter6146"
+ x="-0.30000001"
+ width="1.35"
+ y="-0.15000001"
+ height="1.4">
+ <feFlood
+ flood-opacity="0.40000000000000002"
+ flood-color="rgb(0,0,0)"
+ result="flood"
+ id="feFlood6148" />
+ <feComposite
+ in="flood"
+ in2="SourceGraphic"
+ operator="in"
+ result="composite1"
+ id="feComposite6150" />
+ <feGaussianBlur
+ in="composite1"
+ stdDeviation="1.5"
+ result="blur"
+ id="feGaussianBlur6152" />
+ <feOffset
+ dx="-2"
+ dy="2"
+ result="offset"
+ id="feOffset6154" />
+ <feComposite
+ in="SourceGraphic"
+ in2="offset"
+ operator="over"
+ result="composite2"
+ id="feComposite6156" />
+ </filter>
+ <linearGradient
+ y2="108.00847"
+ x2="345.40625"
+ y1="108.35222"
+ x1="351.15625"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient44402"
+ xlink:href="#linearGradient18134"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="106.7795"
+ x2="347.1875"
+ y1="106.93575"
+ x1="351.71875"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient44404"
+ xlink:href="#linearGradient18134"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="349.81818"
+ x2="45.021851"
+ y1="437.02835"
+ x1="59.158501"
+ gradientTransform="matrix(1.043478,0,0,0.956667,765.84783,-274.57833)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient24839"
+ xlink:href="#linearGradient24727"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="101.5"
+ x2="841"
+ y1="101.5"
+ x1="807"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient24841"
+ xlink:href="#linearGradient18495"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="347.78201"
+ x2="63.407566"
+ y1="419.06366"
+ x1="64.019142"
+ gradientTransform="matrix(1.043478,0,0,0.956667,767.34783,-275.07833)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient24843"
+ xlink:href="#linearGradient24144"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="114.99999"
+ x2="936"
+ y1="102"
+ x1="954"
+ gradientTransform="translate(-127,4e-6)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient24845"
+ xlink:href="#linearGradient18495"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="349.81818"
+ x2="45.021851"
+ y1="437.02835"
+ x1="59.158501"
+ gradientTransform="matrix(1.043478,0,0,0.956667,765.84783,-274.57833)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient24809"
+ xlink:href="#linearGradient24727"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="101.5"
+ x2="841"
+ y1="101.5"
+ x1="807"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient24811"
+ xlink:href="#linearGradient18495"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="347.78201"
+ x2="63.407566"
+ y1="421.80756"
+ x1="63.539974"
+ gradientTransform="matrix(1.043478,0,0,0.956667,767.34783,-275.07833)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient24813"
+ xlink:href="#linearGradient24711"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="114.99999"
+ x2="936"
+ y1="102"
+ x1="954"
+ gradientTransform="translate(-127,4e-6)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient24815"
+ xlink:href="#linearGradient18495"
+ inkscape:collect="always" />
+ <filter
+ style="color-interpolation-filters:sRGB"
+ inkscape:label="Drop Shadow"
+ id="filter6078"
+ x="-0.30000001"
+ width="1.35"
+ height="1.4"
+ y="-0.15000001">
+ <feFlood
+ flood-opacity="0.40000000000000002"
+ flood-color="rgb(0,0,0)"
+ result="flood"
+ id="feFlood6080" />
+ <feComposite
+ in="flood"
+ in2="SourceGraphic"
+ operator="in"
+ result="composite1"
+ id="feComposite6082" />
+ <feGaussianBlur
+ in="composite1"
+ stdDeviation="1.5"
+ result="blur"
+ id="feGaussianBlur6084" />
+ <feOffset
+ dx="-2"
+ dy="2"
+ result="offset"
+ id="feOffset6086" />
+ <feComposite
+ in="SourceGraphic"
+ in2="offset"
+ operator="over"
+ result="composite2"
+ id="feComposite6088" />
+ </filter>
+ <linearGradient
+ y2="32.076183"
+ x2="276.89801"
+ y1="-14.103641"
+ x1="236.94902"
+ gradientTransform="matrix(2.4126967,0,0,2.7035619,-536.07088,379.29465)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient22274"
+ xlink:href="#linearGradient16595"
+ inkscape:collect="always" />
+ <clipPath
+ id="clipPath13106-7"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path34850-1"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <filter
+ style="color-interpolation-filters:sRGB"
+ id="filter63011"
+ height="2.0133312"
+ y="-0.50666559"
+ width="1.9120018"
+ x="-0.45600089"
+ inkscape:collect="always">
+ <feGaussianBlur
+ id="feGaussianBlur63013"
+ stdDeviation="1.899998"
+ inkscape:collect="always" />
+ </filter>
+ <linearGradient
+ y2="383.69843"
+ x2="174.29811"
+ y1="376.27383"
+ x1="160.14388"
+ gradientTransform="translate(-47.00001,58.00194)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient22276"
+ xlink:href="#linearGradient18495"
+ inkscape:collect="always" />
+ <clipPath
+ id="clipPath6380"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path6382"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <radialGradient
+ r="3.1650217"
+ fy="500.26215"
+ fx="75.554794"
+ cy="500.26215"
+ cx="75.554794"
+ gradientTransform="matrix(0.8728692,0.8400852,-1.1671853,1.2200916,594.18579,-173.07738)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient21442"
+ xlink:href="#linearGradient18821"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="34.375"
+ x2="29.875"
+ y1="18.875"
+ x1="31.1875"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient21444"
+ xlink:href="#linearGradient39155"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="-458.05771"
+ x2="190.46461"
+ y1="193.33229"
+ x1="185.9903"
+ gradientTransform="matrix(0.06818845,0,0,0.06818845,22.51112,27.02885)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient21446"
+ xlink:href="#linearGradient18134"
+ inkscape:collect="always" />
+ <radialGradient
+ r="20.278975"
+ fy="19.668886"
+ fx="26.109201"
+ cy="19.668886"
+ cx="26.109201"
+ gradientTransform="matrix(1.647222,0,0,1.26792,-15.47413,-5.79794)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient21448"
+ xlink:href="#linearGradient18134"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="31.515814"
+ x2="276.89801"
+ y1="-14.103641"
+ x1="236.94902"
+ gradientTransform="matrix(2.4126967,0,0,2.7035619,-536.07088,379.29465)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient23978"
+ xlink:href="#linearGradient16595"
+ inkscape:collect="always" />
+ <clipPath
+ id="clipPath6411"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path6413"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <linearGradient
+ y2="383.69843"
+ x2="174.29811"
+ y1="376.27383"
+ x1="160.14388"
+ gradientTransform="translate(-47.00001,58.00194)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient23980"
+ xlink:href="#linearGradient18495"
+ inkscape:collect="always" />
+ <clipPath
+ id="clipPath6426"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path6428"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <linearGradient
+ y2="237"
+ x2="150.5"
+ y1="239.9987"
+ x1="150.5"
+ gradientTransform="matrix(1,0,0,0.733333,808.99997,-697.8)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient23982"
+ xlink:href="#linearGradient18134"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="243.69914"
+ x2="142.9375"
+ y1="243.76387"
+ x1="147.0625"
+ gradientTransform="matrix(0,1,1,0,715,364)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient23986"
+ xlink:href="#linearGradient18495"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="244.11113"
+ x2="144"
+ y1="244.11113"
+ x1="148"
+ gradientTransform="matrix(1,0,0,1.2857143,364,645.14283)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient23988"
+ xlink:href="#linearGradient30777"
+ inkscape:collect="always" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient30777">
+ <stop
+ style="stop-color:#acacac;stop-opacity:1"
+ offset="0"
+ id="stop30779" />
+ <stop
+ style="stop-color:black;stop-opacity:0;"
+ offset="1"
+ id="stop30781" />
+ </linearGradient>
+ <clipPath
+ id="clipPath23877-4"
+ clipPathUnits="userSpaceOnUse">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.80000001;marker:none;enable-background:accumulate"
+ id="rect23879-6"
+ width="15"
+ height="6"
+ x="952"
+ y="-540"
+ transform="scale(1,-1)" />
+ </clipPath>
+ <linearGradient
+ y2="31.515814"
+ x2="276.89801"
+ y1="-14.103641"
+ x1="236.94902"
+ gradientTransform="matrix(2.4126967,0,0,2.7035619,-536.07088,379.29465)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient30368"
+ xlink:href="#linearGradient16595"
+ inkscape:collect="always" />
+ <clipPath
+ id="clipPath6455"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path6457"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <linearGradient
+ y2="383.69843"
+ x2="174.29811"
+ y1="376.27383"
+ x1="160.14388"
+ gradientTransform="translate(-47.00001,58.00194)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient30370"
+ xlink:href="#linearGradient18495"
+ inkscape:collect="always" />
+ <clipPath
+ id="clipPath6470"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path6472"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <clipPath
+ id="clipPath20586-3"
+ clipPathUnits="userSpaceOnUse">
+ <ellipse
+ ry="2.25"
+ rx="4.5"
+ cy="554"
+ cx="53"
+ transform="matrix(1.870472,0.1894819,-0.6587894,2.4281336,319.59052,-798.11661)"
+ id="path34889-5"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;enable-background:accumulate" />
+ </clipPath>
+ <filter
+ style="color-interpolation-filters:sRGB"
+ id="filter20578-5"
+ height="3.0439126"
+ y="-1.0219563"
+ width="2.1164308"
+ x="-0.55821538"
+ inkscape:collect="always">
+ <feGaussianBlur
+ id="feGaussianBlur20580-2"
+ stdDeviation="2.0410255"
+ inkscape:collect="always" />
+ </filter>
+ <clipPath
+ id="clipPath6482"
+ clipPathUnits="userSpaceOnUse">
+ <ellipse
+ ry="2.25"
+ rx="4.5"
+ cy="554"
+ cx="53"
+ transform="matrix(1.870472,0.1894819,-0.6587894,2.4281336,319.59052,-798.11661)"
+ id="path6484"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;enable-background:accumulate" />
+ </clipPath>
+ <linearGradient
+ y2="32.076183"
+ x2="276.89801"
+ y1="-14.103641"
+ x1="236.94902"
+ gradientTransform="matrix(2.4126967,0,0,2.7035619,-536.07088,379.29465)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient21594"
+ xlink:href="#linearGradient16595"
+ inkscape:collect="always" />
+ <clipPath
+ id="clipPath6497"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path6499"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <linearGradient
+ y2="383.69843"
+ x2="174.29811"
+ y1="376.27383"
+ x1="160.14388"
+ gradientTransform="translate(-47.00001,58.00194)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient21596"
+ xlink:href="#linearGradient18495"
+ inkscape:collect="always" />
+ <clipPath
+ id="clipPath6512"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path6514"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <linearGradient
+ y2="31.515814"
+ x2="276.89801"
+ y1="-14.103641"
+ x1="236.94902"
+ gradientTransform="matrix(2.4126967,0,0,2.7035619,-536.07088,379.29465)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient21647"
+ xlink:href="#linearGradient16595"
+ inkscape:collect="always" />
+ <clipPath
+ id="clipPath6527"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path6529"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <linearGradient
+ y2="383.69843"
+ x2="174.29811"
+ y1="376.27383"
+ x1="160.14388"
+ gradientTransform="translate(-47.00001,58.00194)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient21649"
+ xlink:href="#linearGradient18495"
+ inkscape:collect="always" />
+ <clipPath
+ id="clipPath6542"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path6544"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <radialGradient
+ r="5.256"
+ fy="114.5684"
+ fx="20.892099"
+ cy="114.5684"
+ cx="20.892099"
+ gradientTransform="matrix(0.2798768,0,0,0.279916,6.0465962,-0.3619733)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient21565"
+ xlink:href="#aigrd2-3"
+ inkscape:collect="always" />
+ <radialGradient
+ gradientUnits="userSpaceOnUse"
+ fy="114.5684"
+ fx="20.892099"
+ r="5.256"
+ cy="114.5684"
+ cx="20.892099"
+ id="aigrd2-3">
+ <stop
+ id="stop15566-9"
+ style="stop-color:#F0F0F0"
+ offset="0" />
+ <stop
+ id="stop15568-7"
+ style="stop-color:#9a9a9a;stop-opacity:1.0000000;"
+ offset="1.0000000" />
+ </radialGradient>
+ <radialGradient
+ r="5.256"
+ fy="114.5684"
+ fx="20.892099"
+ cy="114.5684"
+ cx="20.892099"
+ gradientTransform="matrix(0.2798768,0,0,0.279916,6.0465962,-0.3619733)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient21567"
+ xlink:href="#aigrd2-3"
+ inkscape:collect="always" />
+ <radialGradient
+ gradientUnits="userSpaceOnUse"
+ fy="114.5684"
+ fx="20.892099"
+ r="5.256"
+ cy="114.5684"
+ cx="20.892099"
+ id="radialGradient6555">
+ <stop
+ id="stop6557"
+ style="stop-color:#F0F0F0"
+ offset="0" />
+ <stop
+ id="stop6559"
+ style="stop-color:#9a9a9a;stop-opacity:1.0000000;"
+ offset="1.0000000" />
+ </radialGradient>
+ <linearGradient
+ y2="31.515814"
+ x2="276.89801"
+ y1="-9.4293213"
+ x1="240.70209"
+ gradientTransform="matrix(2.4126967,0,0,2.7035619,-536.07088,379.29465)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient30321"
+ xlink:href="#linearGradient16595"
+ inkscape:collect="always" />
+ <clipPath
+ id="clipPath6568"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path6570"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <linearGradient
+ y2="383.69843"
+ x2="174.29811"
+ y1="376.27383"
+ x1="160.14388"
+ gradientTransform="translate(-47.00001,58.00194)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient30323"
+ xlink:href="#linearGradient18495"
+ inkscape:collect="always" />
+ <clipPath
+ id="clipPath6583"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path6585"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <linearGradient
+ y2="31.515814"
+ x2="276.89801"
+ y1="-14.103641"
+ x1="236.94902"
+ gradientTransform="matrix(2.4126967,0,0,2.7035619,-536.07088,379.29465)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient21977"
+ xlink:href="#linearGradient16595"
+ inkscape:collect="always" />
+ <clipPath
+ id="clipPath6599"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path6601"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
+ <linearGradient
+ y2="383.69843"
+ x2="174.29811"
+ y1="376.27383"
+ x1="160.14388"
+ gradientTransform="translate(-47.00001,58.00194)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient21979"
+ xlink:href="#linearGradient18495"
+ inkscape:collect="always" />
+ <clipPath
+ id="clipPath6614"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path6616"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ </clipPath>
</defs>
<sodipodi:namedview
id="base"
@@ -30968,16 +31349,16 @@
objecttolerance="10000"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
- inkscape:zoom="40.768576"
- inkscape:cx="236.56738"
- inkscape:cy="163.14077"
+ inkscape:zoom="1.274018"
+ inkscape:cx="519.70993"
+ inkscape:cy="325.90484"
inkscape:document-units="px"
- inkscape:current-layer="g24024-1"
+ inkscape:current-layer="layer1"
showgrid="true"
inkscape:window-width="1920"
- inkscape:window-height="982"
- inkscape:window-x="0"
- inkscape:window-y="28"
+ inkscape:window-height="1005"
+ inkscape:window-x="-2"
+ inkscape:window-y="27"
inkscape:snap-nodes="false"
inkscape:snap-bbox="true"
showguides="true"
@@ -75911,1951 +76292,6 @@
</g>
</g>
<g
- id="g32752"
- inkscape:export-filename="C:\Documents and Settings\Pracownia\Moje dokumenty\Moje obrazy\BLENDER ICONS redesign\RELEASES\v. 2.5.06\prvicons 2.5.06.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <rect
- y="180"
- x="872"
- height="192"
- width="192"
- id="rect30285"
- style="opacity:0;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:5.39191818;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
- <g
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Pracowniaa\Moje dokumenty\Moje obrazy\BLENDER ICONS redesign\ver 2\IMAGE BROWSER ICONS.png"
- transform="translate(856,-203)"
- id="g21955"
- style="opacity:0.3;display:inline;enable-background:new">
- <rect
- style="opacity:0;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="rect21957"
- width="48"
- height="48"
- x="108"
- y="430"
- rx="2.4004419"
- ry="0" />
- <g
- id="g21959">
- <path
- inkscape:connector-curvature="0"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccccc"
- id="path21961"
- d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
- style="fill:url(#linearGradient21977);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;display:inline" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccc"
- id="path21963"
- style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90" />
- <path
- inkscape:connector-curvature="0"
- style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)"
- d="m 115,444 12,0 -1,-11 -11,11 z"
- id="path21965"
- sodipodi:nodetypes="cccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- clip-path="url(#clipPath13106)" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccc"
- id="path21967"
- style="fill:none;stroke:url(#linearGradient21979);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- d="m 117.5,443.75 9,-2.5 0,-6"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- clip-path="none" />
- <path
- inkscape:connector-curvature="0"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
- style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- id="path21969"
- sodipodi:nodetypes="cccccc" />
- <path
- inkscape:connector-curvature="0"
- style="opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline;filter:url(#filter63011)"
- d="m 116,443 11,1 -2,-10 -9,9 z"
- id="path21971"
- sodipodi:nodetypes="cccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- clip-path="url(#clipPath13106)" />
- <path
- inkscape:connector-curvature="0"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccccc"
- id="path21973"
- d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" />
- <path
- inkscape:connector-curvature="0"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 147.5,435 0,38.5 -30.5,0"
- style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- id="path21975"
- sodipodi:nodetypes="ccc" />
- </g>
- </g>
- <g
- id="g30335">
- <g
- id="g21367"
- transform="translate(760,-202)">
- <path
- inkscape:connector-curvature="0"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccccc"
- id="path21369"
- d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
- style="fill:url(#linearGradient30321);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;display:inline" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccc"
- id="path21371"
- style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90" />
- <path
- inkscape:connector-curvature="0"
- style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)"
- d="m 115,444 12,0 -1,-11 -11,11 z"
- id="path21373"
- sodipodi:nodetypes="cccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- clip-path="url(#clipPath13106)" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccc"
- id="path21375"
- style="fill:none;stroke:url(#linearGradient30323);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- d="m 117.5,443.75 9,-2.5 0,-6"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- clip-path="none" />
- <path
- inkscape:connector-curvature="0"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
- style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- id="path21377"
- sodipodi:nodetypes="cccccc" />
- <path
- inkscape:connector-curvature="0"
- style="opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline;filter:url(#filter63011)"
- d="m 116,443 11,1 -2,-10 -9,9 z"
- id="path21569"
- sodipodi:nodetypes="cccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- clip-path="url(#clipPath13106)" />
- <path
- inkscape:connector-curvature="0"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccccc"
- id="path21379"
- d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" />
- <path
- inkscape:connector-curvature="0"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 147.5,435 0,38.5 -30.5,0"
- style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- id="path21381"
- sodipodi:nodetypes="ccc" />
- </g>
- <path
- inkscape:connector-curvature="0"
- style="font-size:33.49144363px;font-style:normal;font-weight:normal;fill:#214478;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Vera Sans"
- d="m 891.07148,245 -0.0715,9 2.39012,0 C 896,254 896,253 896.5,251 l 0.5,0 0,7 -0.5,0 c -0.5,-2 -0.5,-3 -3.10988,-3 L 891,255 l 0,7 c 0,2.5 1,3.25 3.14146,3.39973 l -0.004,0.60029 L 885,266 l 0.004,-0.60029 C 887,265.25 888,264.5 888.00001,262 L 888,248 c 0,-2.5 -1,-3.25 -3,-3.5 l 0,-0.5 16,0 0,5 -0.5,0 c -0.50001,-1.99999 -1.5,-4 -4.5,-4 l -4.92852,0 z"
- id="text13209"
- sodipodi:nodetypes="ccccccccccccccccccccccc" />
- </g>
- <g
- style="display:inline;enable-background:new"
- id="g21625"
- transform="translate(904,-154)"
- inkscape:export-filename="C:\Documents and Settings\Pracowniaa\Moje dokumenty\Moje obrazy\BLENDER ICONS redesign\ver 2\IMAGE BROWSER ICONS.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <rect
- ry="0"
- rx="2.4004419"
- y="430"
- x="108"
- height="48"
- width="48"
- id="rect21627"
- style="opacity:0;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
- <g
- id="g21629">
- <path
- inkscape:connector-curvature="0"
- style="fill:url(#linearGradient21647);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;display:inline"
- d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
- id="path21631"
- sodipodi:nodetypes="cccccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90" />
- <g
- style="opacity:0.5;fill:#000000;display:inline"
- id="g16261"
- transform="matrix(1.2499985,0,0,1,-87.6203,-147.85351)">
- <rect
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate"
- id="rect35099"
- width="17.600004"
- height="1"
- x="167.69646"
- y="598.85352"
- rx="0.12125195"
- ry="0.065390877" />
- <rect
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate"
- id="rect35101"
- width="17.600004"
- height="1"
- x="167.69646"
- y="600.85352"
- rx="0.12125195"
- ry="0.065390877" />
- <rect
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate"
- id="rect15690"
- width="17.600004"
- height="1"
- x="167.69646"
- y="602.85352"
- rx="0.12125195"
- ry="0.065390877" />
- <rect
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate"
- id="rect15692"
- width="17.600004"
- height="1"
- x="167.69646"
- y="604.85352"
- rx="0.12125195"
- ry="0.065390877" />
- <rect
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate"
- id="rect15694"
- width="17.600004"
- height="1"
- x="167.69646"
- y="606.85352"
- rx="0.12125195"
- ry="0.065390877" />
- <rect
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate"
- id="rect15696"
- width="17.600004"
- height="1"
- x="167.69646"
- y="608.85352"
- rx="0.12125195"
- ry="0.065390877" />
- <rect
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate"
- id="rect15698"
- width="17.600004"
- height="1"
- x="167.69646"
- y="610.85352"
- rx="0.12125195"
- ry="0.065390877" />
- <rect
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate"
- id="rect15700"
- width="17.600004"
- height="1"
- x="167.69646"
- y="612.85352"
- rx="0.12125195"
- ry="0.065390877" />
- <rect
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate"
- id="rect15732"
- width="14.400002"
- height="1"
- x="167.69646"
- y="614.85352"
- rx="0.09920612"
- ry="0.065390877" />
- <g
- transform="translate(150.89645,557.85352)"
- id="g4849"
- style="fill:#000000;display:inline">
- <rect
- ry="0.065390877"
- rx="0.12125195"
- y="29"
- x="16.799992"
- height="1"
- width="17.600004"
- id="rect15736"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate" />
- <rect
- ry="0.065390877"
- rx="0.12125195"
- y="31"
- x="16.799992"
- height="1"
- width="17.600004"
- id="rect15738"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate" />
- <rect
- ry="0.065390877"
- rx="0.12125195"
- y="33"
- x="16.799992"
- height="1"
- width="17.600004"
- id="rect15740"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate" />
- <rect
- ry="0.065390877"
- rx="0.12125195"
- y="35"
- x="16.799992"
- height="1"
- width="17.600004"
- id="rect15742"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate" />
- <rect
- ry="0.065390877"
- rx="0.055114571"
- y="37"
- x="16.799992"
- height="1"
- width="8.0000095"
- id="rect15744"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate" />
- </g>
- <rect
- ry="0.065390304"
- rx="0.0057410933"
- y="617.85352"
- x="184.49646"
- height="0.99999124"
- width="0.83333319"
- id="rect16334"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate" />
- </g>
- <path
- inkscape:connector-curvature="0"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
- style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- id="path21633"
- sodipodi:nodetypes="cccc" />
- <path
- inkscape:connector-curvature="0"
- clip-path="url(#clipPath13106)"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccc"
- id="path21635"
- d="m 115,444 12,0 -1,-11 -11,11 z"
- style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)" />
- <path
- inkscape:connector-curvature="0"
- clip-path="none"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 117.5,443.75 9,-2.5 0,-6"
- style="fill:none;stroke:url(#linearGradient21649);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- id="path21637"
- sodipodi:nodetypes="ccc" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccc"
- id="path21639"
- style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90" />
- <path
- inkscape:connector-curvature="0"
- clip-path="url(#clipPath13106)"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccc"
- id="path21641"
- d="m 116,443 11,1 -2,-10 -9,9 z"
- style="opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline;filter:url(#filter63011)" />
- <path
- inkscape:connector-curvature="0"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
- d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
- id="path21643"
- sodipodi:nodetypes="cccccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90" />
- <g
- id="g35119"
- transform="translate(2,-160.99999)"
- style="display:inline">
- <g
- style="display:inline"
- transform="translate(105.39645,589.71201)"
- id="g16097">
- <g
- id="g16099"
- style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-miterlimit:4"
- transform="matrix(0.229703,0,0,0.229703,4.967081,4.244972)">
- <radialGradient
- id="radialGradient16101"
- cx="20.892099"
- cy="114.5684"
- r="5.256"
- fx="20.892099"
- fy="114.5684"
- gradientUnits="userSpaceOnUse">
- <stop
- offset="0"
- style="stop-color:#F0F0F0"
- id="stop16103" />
- <stop
- offset="1"
- style="stop-color:#474747"
- id="stop16105" />
- </radialGradient>
- <radialGradient
- id="radialGradient16109"
- cx="20.892099"
- cy="64.567902"
- r="5.257"
- fx="20.892099"
- fy="64.567902"
- gradientUnits="userSpaceOnUse">
- <stop
- offset="0"
- style="stop-color:#F0F0F0"
- id="stop16111" />
- <stop
- offset="1"
- style="stop-color:#474747"
- id="stop16113" />
- </radialGradient>
- </g>
- <path
- inkscape:connector-curvature="0"
- style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline"
- d="m 12.85355,31.53813 c 0,0.552274 -0.447803,0.99986 -1,0.99986 -0.552477,0 -1,-0.447865 -1,-0.99986 0,-0.552554 0.447803,-1.00014 1,-1.00014 0.552197,0 1,0.447866 1,1.00014 l 0,0 0,0 0,0 z"
- id="path16107" />
- <path
- inkscape:connector-curvature="0"
- style="fill:url(#radialGradient21565);fill-rule:nonzero;stroke:none"
- d="m 12.60355,31.288131 c 0,0.552274 -0.447803,0.999859 -1,0.999859 -0.552477,0 -1,-0.447865 -1,-0.999859 0,-0.552556 0.447803,-1.000141 1,-1.000141 0.552197,0 1,0.447866 1,1.000141 z"
- id="path16117" />
- </g>
- <g
- id="g16131"
- transform="translate(105.39645,579.71201)"
- style="display:inline">
- <g
- transform="matrix(0.229703,0,0,0.229703,4.967081,4.244972)"
- style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-miterlimit:4"
- id="g16133">
- <radialGradient
- gradientUnits="userSpaceOnUse"
- fy="114.5684"
- fx="20.892099"
- r="5.256"
- cy="114.5684"
- cx="20.892099"
- id="radialGradient16135">
- <stop
- id="stop16137"
- style="stop-color:#F0F0F0"
- offset="0" />
- <stop
- id="stop16140"
- style="stop-color:#474747"
- offset="1" />
- </radialGradient>
- <radialGradient
- gradientUnits="userSpaceOnUse"
- fy="64.567902"
- fx="20.892099"
- r="5.257"
- cy="64.567902"
- cx="20.892099"
- id="radialGradient16142">
- <stop
- id="stop16144"
- style="stop-color:#F0F0F0"
- offset="0" />
- <stop
- id="stop16146"
- style="stop-color:#474747"
- offset="1" />
- </radialGradient>
- </g>
- <path
- inkscape:connector-curvature="0"
- id="path35139"
- d="m 12.85355,31.53813 c 0,0.552274 -0.447803,0.99986 -1,0.99986 -0.552477,0 -1,-0.447865 -1,-0.99986 0,-0.552554 0.447803,-1.00014 1,-1.00014 0.552197,0 1,0.447866 1,1.00014 l 0,0 0,0 0,0 z"
- style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline" />
- <path
- inkscape:connector-curvature="0"
- id="path35141"
- d="m 12.60355,31.288131 c 0,0.552274 -0.447803,0.999859 -1,0.999859 -0.552477,0 -1,-0.447865 -1,-0.999859 0,-0.552556 0.447803,-1.000141 1,-1.000141 0.552197,0 1,0.447866 1,1.000141 z"
- style="fill:url(#radialGradient21567);fill-rule:nonzero;stroke:none" />
- </g>
- </g>
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccc"
- id="path21645"
- style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- d="m 147.5,435 0,38.5 -30.5,0"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90" />
- </g>
- </g>
- <g
- style="display:inline;enable-background:new"
- id="g21572"
- transform="translate(808,-203)"
- inkscape:export-filename="C:\Documents and Settings\Pracowniaa\Moje dokumenty\Moje obrazy\BLENDER ICONS redesign\ver 2\IMAGE BROWSER ICONS.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <rect
- ry="0"
- rx="2.4004419"
- y="430"
- x="108"
- height="48"
- width="48"
- id="rect21574"
- style="opacity:0;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
- <g
- id="g21576">
- <path
- inkscape:connector-curvature="0"
- style="fill:url(#linearGradient21594);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;display:inline"
- d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
- id="path21578"
- sodipodi:nodetypes="cccccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90" />
- <path
- inkscape:connector-curvature="0"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
- style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- id="path21580"
- sodipodi:nodetypes="cccc" />
- <path
- inkscape:connector-curvature="0"
- clip-path="url(#clipPath13106)"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccc"
- id="path21582"
- d="m 115,444 12,0 -1,-11 -11,11 z"
- style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)" />
- <path
- inkscape:connector-curvature="0"
- clip-path="none"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 117.5,443.75 9,-2.5 0,-6"
- style="fill:none;stroke:url(#linearGradient21596);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- id="path21584"
- sodipodi:nodetypes="ccc" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccc"
- id="path21586"
- style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90" />
- <path
- inkscape:connector-curvature="0"
- clip-path="url(#clipPath13106)"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccc"
- id="path21588"
- d="m 116,443 11,1 -2,-10 -9,9 z"
- style="opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline;filter:url(#filter63011)" />
- <path
- inkscape:connector-curvature="0"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
- d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
- id="path21590"
- sodipodi:nodetypes="cccccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccc"
- id="path21592"
- style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- d="m 147.5,435 0,38.5 -30.5,0"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90" />
- </g>
- </g>
- <g
- id="g30382">
- <g
- id="g23655"
- transform="translate(760,-154)">
- <path
- inkscape:connector-curvature="0"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccccc"
- id="path23657"
- d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
- style="fill:url(#linearGradient30368);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;display:inline" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccc"
- id="path23659"
- style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90" />
- <path
- inkscape:connector-curvature="0"
- style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)"
- d="m 115,444 12,0 -1,-11 -11,11 z"
- id="path23661"
- sodipodi:nodetypes="cccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- clip-path="url(#clipPath13106)" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccc"
- id="path23663"
- style="fill:none;stroke:url(#linearGradient30370);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- d="m 117.5,443.75 9,-2.5 0,-6"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- clip-path="none" />
- <path
- inkscape:connector-curvature="0"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
- style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- id="path23665"
- sodipodi:nodetypes="cccccc" />
- <path
- inkscape:connector-curvature="0"
- style="opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline;filter:url(#filter63011)"
- d="m 116,443 11,1 -2,-10 -9,9 z"
- id="path23667"
- sodipodi:nodetypes="cccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- clip-path="url(#clipPath13106)" />
- <path
- inkscape:connector-curvature="0"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccccc"
- id="path23669"
- d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" />
- <path
- inkscape:connector-curvature="0"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 147.5,435 0,38.5 -30.5,0"
- style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- id="path23671"
- sodipodi:nodetypes="ccc" />
- </g>
- <path
- inkscape:connector-curvature="0"
- style="fill:#112b00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- d="m 888,295 1,0 0,14 -1,0 0,-14 z"
- id="path23675"
- sodipodi:nodetypes="ccccc" />
- <path
- inkscape:connector-curvature="0"
- id="path23677"
- d="m 900,294 1.00002,-1 0,14 -1.00002,0 0,-13 z"
- style="fill:#112b00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- sodipodi:nodetypes="ccccc" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccc"
- id="path23679"
- d="m 901.00003,292 0,2.25 -13.00002,2 0,-2.25 13.00002,-2 z"
- style="fill:#112b00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
- <g
- id="g23681"
- transform="matrix(1.1428564,0,0,1.2000001,822.71436,-355.40005)">
- <path
- transform="matrix(0.7630859,-0.2494396,0.2996015,0.9926766,-151.92281,17.77746)"
- d="M 57.5,554 A 4.5,2.25 0 0 1 53,556.25 4.5,2.25 0 0 1 48.5,554 4.5,2.25 0 0 1 53,551.75 4.5,2.25 0 0 1 57.5,554 Z"
- sodipodi:ry="2.25"
- sodipodi:rx="4.5"
- sodipodi:cy="554"
- sodipodi:cx="53"
- id="path23683"
- style="fill:#112b00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- sodipodi:type="arc" />
- <path
- sodipodi:type="arc"
- style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter20578);enable-background:accumulate"
- id="path23685"
- sodipodi:cx="53"
- sodipodi:cy="554"
- sodipodi:rx="4.5"
- sodipodi:ry="2.25"
- d="M 57.5,554 A 4.5,2.25 0 0 1 53,556.25 4.5,2.25 0 0 1 48.5,554 4.5,2.25 0 0 1 53,551.75 4.5,2.25 0 0 1 57.5,554 Z"
- transform="matrix(0.3848865,-0.1700959,0.2278131,0.3626733,-93.107467,361.59408)"
- inkscape:transform-center-y="0.3813435"
- clip-path="url(#clipPath20586)" />
- </g>
- <path
- inkscape:connector-curvature="0"
- style="opacity:0.38999999;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- d="m 901.00003,292 -1e-5,1 -13.00002,2 10e-6,-1 13.00002,-2 z"
- id="path23694"
- sodipodi:nodetypes="ccccc" />
- <g
- transform="matrix(1.1428564,0,0,1.2000001,834.71436,-357.40005)"
- id="g23717">
- <path
- sodipodi:type="arc"
- style="fill:#112b00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="path23724"
- sodipodi:cx="53"
- sodipodi:cy="554"
- sodipodi:rx="4.5"
- sodipodi:ry="2.25"
- d="M 57.5,554 A 4.5,2.25 0 0 1 53,556.25 4.5,2.25 0 0 1 48.5,554 4.5,2.25 0 0 1 53,551.75 4.5,2.25 0 0 1 57.5,554 Z"
- transform="matrix(0.7630859,-0.2494396,0.2996015,0.9926766,-151.92281,17.77746)" />
- <path
- clip-path="url(#clipPath20586)"
- inkscape:transform-center-y="0.3813435"
- transform="matrix(0.3848865,-0.1700959,0.2278131,0.3626733,-93.107467,361.59408)"
- d="M 57.5,554 A 4.5,2.25 0 0 1 53,556.25 4.5,2.25 0 0 1 48.5,554 4.5,2.25 0 0 1 53,551.75 4.5,2.25 0 0 1 57.5,554 Z"
- sodipodi:ry="2.25"
- sodipodi:rx="4.5"
- sodipodi:cy="554"
- sodipodi:cx="53"
- id="path23726"
- style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter20578);enable-background:accumulate"
- sodipodi:type="arc" />
- </g>
- </g>
- <g
- id="g23922"
- transform="translate(-16,-220)"
- style="display:inline;enable-background:new">
- <g
- style="display:inline"
- id="g23924"
- transform="translate(824,66)"
- inkscape:export-filename="C:\Documents and Settings\Pracowniaa\Moje dokumenty\Moje obrazy\BLENDER ICONS redesign\ver 2\IMAGE BROWSER ICONS.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <rect
- ry="0"
- rx="2.4004419"
- y="430"
- x="108"
- height="48"
- width="48"
- id="rect23926"
- style="opacity:0;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
- <g
- id="g23928">
- <path
- inkscape:connector-curvature="0"
- style="fill:url(#linearGradient23978);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;display:inline"
- d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
- id="path23930"
- sodipodi:nodetypes="cccccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90" />
- <path
- inkscape:connector-curvature="0"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
- style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- id="path23932"
- sodipodi:nodetypes="cccc" />
- <path
- inkscape:connector-curvature="0"
- clip-path="url(#clipPath13106)"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccc"
- id="path23934"
- d="m 115,444 12,0 -1,-11 -11,11 z"
- style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)" />
- <path
- inkscape:connector-curvature="0"
- clip-path="none"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 117.5,443.75 9,-2.5 0,-6"
- style="fill:none;stroke:url(#linearGradient23980);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- id="path23936"
- sodipodi:nodetypes="ccc" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccc"
- id="path23938"
- style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90" />
- <path
- inkscape:connector-curvature="0"
- clip-path="url(#clipPath13106)"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccc"
- id="path23940"
- d="m 116,443 11,1 -2,-10 -9,9 z"
- style="opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline;filter:url(#filter63011)" />
- <path
- inkscape:connector-curvature="0"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
- d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
- id="path23942"
- sodipodi:nodetypes="cccccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccc"
- id="path23944"
- style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- d="m 147.5,435 0,38.5 -30.5,0"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90" />
- </g>
- </g>
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccc"
- id="path23946"
- d="m 952,530 0,10 1,0 1,0 11,0 1,0 1,0 0,-10 -15,0 z m 1,2 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z m -12,3 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z m -12,3 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" />
- <rect
- transform="scale(1,-1)"
- style="fill:url(#linearGradient23982);fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="rect23948"
- width="13"
- height="5.5"
- x="953"
- y="-524" />
- <path
- inkscape:connector-curvature="0"
- id="path23952"
- transform="translate(76,0)"
- d="m 876,514 0,17 15,0 0,-17 -1,0 0,1 -1,0 0,-1 -11,0 0,1 -1,0 0,-1 -1,0 z m 1,3 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z m -12,3 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z m -12,3 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z m -12,3 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z m -12,3 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccc"
- style="fill:url(#linearGradient23986);fill-opacity:1;fill-rule:nonzero;stroke:none"
- d="m 952,507 3,0 0,3 9,0 0,-3 3,0 0,7 -15,0 0,-7 z m 1,0 1,0 -1,0 z m 0,1 0,1 1,0 0,-1 -1,0 z m 0,3 0,1 1,0 0,-1 -1,0 z m 12,-4 1,0 -1,0 z m 0,1 0,1 1,0 0,-1 -1,0 z m 0,3 0,1 1,0 0,-1 -1,0 z"
- id="path23954" />
- <rect
- transform="matrix(0,1,1,0,0,0)"
- ry="0"
- y="955"
- x="507"
- height="9"
- width="3"
- id="rect23956"
- style="fill:url(#linearGradient23988);fill-opacity:1;fill-rule:nonzero;stroke:none" />
- <rect
- style="fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="rect23958"
- width="9"
- height="9"
- x="512"
- y="955"
- ry="0"
- transform="matrix(0,1,1,0,0,0)" />
- <rect
- transform="matrix(0,1,1,0,0,0)"
- ry="0"
- y="955"
- x="523"
- height="9"
- width="9"
- id="rect23960"
- style="fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none" />
- <path
- transform="matrix(0,-0.5624971,0.5624971,0,893.12531,590.74965)"
- sodipodi:type="arc"
- style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path23962"
- sodipodi:cx="132"
- sodipodi:cy="118"
- sodipodi:rx="8"
- sodipodi:ry="8"
- d="m 140,118 a 8,8 0 0 1 -8,8 8,8 0 0 1 -8,-8 8,8 0 0 1 8,-8 8,8 0 0 1 8,8 z"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90" />
- <path
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
- d="m 140,118 a 8,8 0 0 1 -8,8 8,8 0 0 1 -8,-8 8,8 0 0 1 8,-8 8,8 0 0 1 8,8 z"
- sodipodi:ry="8"
- sodipodi:rx="8"
- sodipodi:cy="118"
- sodipodi:cx="132"
- id="path23964"
- style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
- sodipodi:type="arc"
- transform="matrix(0,-0.5624964,0.5624964,0,893.12545,601.74956)" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccccccc"
- id="path23966"
- d="m 961.00001,519.00005 -3,0 0,-0.99992 0.99994,0 6e-5,-2.00008 -1,0 0,-1 1,0 0,-1 1.00006,0 0,4.00008 0.99994,0 0,0.99992 z" />
- <path
- inkscape:connector-curvature="0"
- d="m 958,525 0,1 2,0 0,-1 -2,0 z m 2,1 0,1 1,0 0,-1 -1,0 z m 0,1 -1,0 0,1 1,0 0,-1 z m -1,1 -1,0 0,1 0,1 3,0 0,-1 -2,0 0,-1 z"
- id="path23968" />
- <rect
- style="fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="rect23970"
- width="6"
- height="9"
- x="534"
- y="955"
- ry="0"
- transform="matrix(0,1,1,0,0,0)" />
- <g
- clip-path="url(#clipPath23877)"
- id="g23972">
- <path
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
- d="m 140,118 a 8,8 0 0 1 -8,8 8,8 0 0 1 -8,-8 8,8 0 0 1 8,-8 8,8 0 0 1 8,8 z"
- sodipodi:ry="8"
- sodipodi:rx="8"
- sodipodi:cy="118"
- sodipodi:cx="132"
- id="path23974"
- style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
- sodipodi:type="arc"
- transform="matrix(0,-0.5624964,0.5624964,0,893.12545,612.74956)" />
- <path
- inkscape:connector-curvature="0"
- d="m 958,536 0,1 2,0 0,-1 -2,0 z m 2,1 0,1 1,0 0,-1 -1,0 z m 0,1 -1,0 0,1 1,0 0,-1 z m 0,1 0,1 1,0 0,-1 -1,0 z m 0,1 -2,0 0,1 2,0 0,-1 z"
- id="path23976" />
- </g>
- </g>
- <g
- transform="translate(208,88)"
- id="g45475"
- style="display:inline;enable-background:new">
- <g
- style="display:inline"
- id="g22242"
- transform="translate(696,-194)"
- inkscape:export-filename="C:\Documents and Settings\Pracowniaa\Moje dokumenty\Moje obrazy\BLENDER ICONS redesign\ver 2\IMAGE BROWSER ICONS.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <rect
- ry="0"
- rx="2.4004419"
- y="430"
- x="108"
- height="48"
- width="48"
- id="rect22244"
- style="opacity:0;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
- <g
- id="g22246">
- <path
- inkscape:connector-curvature="0"
- style="fill:url(#linearGradient22274);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;display:inline"
- d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
- id="path22249"
- sodipodi:nodetypes="cccccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90" />
- <path
- inkscape:connector-curvature="0"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
- style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- id="path22251"
- sodipodi:nodetypes="cccc" />
- <path
- inkscape:connector-curvature="0"
- clip-path="url(#clipPath13106)"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccc"
- id="path22253"
- d="m 115,444 12,0 -1,-11 -11,11 z"
- style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)" />
- <path
- inkscape:connector-curvature="0"
- clip-path="none"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 117.5,443.75 9,-2.5 0,-6"
- style="fill:none;stroke:url(#linearGradient22276);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- id="path22264"
- sodipodi:nodetypes="ccc" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccc"
- id="path22266"
- style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90" />
- <path
- inkscape:connector-curvature="0"
- clip-path="url(#clipPath13106)"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccc"
- id="path22268"
- d="m 116,443 11,1 -2,-10 -9,9 z"
- style="opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline;filter:url(#filter63011)" />
- <path
- inkscape:connector-curvature="0"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
- d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
- id="path22270"
- sodipodi:nodetypes="cccccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccc"
- id="path22272"
- style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- d="m 147.5,435 0,38.5 -30.5,0"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90" />
- </g>
- </g>
- <g
- id="g21517"
- inkscape:label="Layer 1"
- transform="matrix(0.5406242,0,0,0.5829534,814.13667,247.65542)">
- <path
- transform="matrix(1.274286,0,0,1.377124,-7.569123,-16.70193)"
- d="M 43.487067,38.98439 A 15.467961,5.3033009 0 0 1 28.019106,44.287691 15.467961,5.3033009 0 0 1 12.551145,38.98439 15.467961,5.3033009 0 0 1 28.019106,33.681089 15.467961,5.3033009 0 0 1 43.487067,38.98439 Z"
- sodipodi:ry="5.3033009"
- sodipodi:rx="15.467961"
- sodipodi:cy="38.98439"
- sodipodi:cx="28.019106"
- id="path35486"
- style="opacity:0.54857142;fill:url(#radialGradient21442);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- sodipodi:type="arc" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="csssssssssscccsscccscccssccc"
- d="m 16.048489,28.093447 c 0.0098,0.576682 0.196474,1.697902 0.471116,2.577425 0.581566,1.854137 1.56684,3.572658 2.939126,5.086496 1.407488,1.553118 3.138519,2.803227 5.139315,3.68976 2.105357,0.931573 4.384795,1.407488 6.750134,1.403741 2.365339,-0.005 4.644601,-0.488686 6.74896,-1.427017 2.00002,-0.895288 3.731043,-2.148391 5.13754,-3.705517 1.369207,-1.519844 2.352576,-3.241114 2.934089,-5.096258 0.294262,-0.938353 0.476921,-1.889392 0.553238,-2.845308 0.07331,-0.939306 0.04204,-1.883511 -0.09183,-2.823792 -0.259981,-1.835599 -0.896294,-3.556847 -1.872652,-5.12758 -0.895541,-1.441699 -2.047808,-2.70454 -3.417268,-3.766975 0,0 0.002,-0.002 0.002,-0.002 0,0 -13.828458,-10.6197195 -13.828458,-10.6197195 -0.01176,-0.00978 -0.02252,-0.019551 -0.03529,-0.028344 -0.909003,-0.6959264 -3.879837,-0.7738945 -4.87679,-0.075035 -1.01067,0.7057021 -1.091821,1.8092613 -0.195527,2.5482146 1.899775,1.4997633 2.656207,2.2801589 4.566507,3.7797379 0,0 -14.852491,0.167033 -14.852491,0.167033 -1.994685,0 -3.1682609,0.947915 -3.4153947,2.333683 -0.2180771,1.222836 0.7479213,2.738129 2.4800217,2.738129 2.956573,0.0039 5.942111,-0.0069 8.909215,-0.01272 0,0 -16.01999,12.453223 -16.01999,12.453223 -0.020527,0.01564 -0.041053,0.02933 -0.06158,0.04497 -1.4974197,1.148389 -1.9831951,3.059322 -1.0399808,4.268393 0.9598323,1.22959 2.9977653,1.230588 4.5147288,0.006 0,0 8.677593,-7.102098 8.677593,-7.102098 0,0 -0.12511,0.959824 -0.116333,1.535532 l 1e-6,2.6e-5 0,0 0,0 z"
- id="path2482"
- style="fill:#f57900;fill-rule:evenodd;stroke:#aa4400;stroke-width:1.7812928;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none" />
- <path
- transform="matrix(0.8018194,0,0,0.8471126,6.257567,4.5089892)"
- d="M 42.75,25.75 A 11.5625,10.125 0 0 1 31.1875,35.875 11.5625,10.125 0 0 1 19.625,25.75 11.5625,10.125 0 0 1 31.1875,15.625 11.5625,10.125 0 0 1 42.75,25.75 Z"
- sodipodi:ry="10.125"
- sodipodi:rx="11.5625"
- sodipodi:cy="25.75"
- sodipodi:cx="31.1875"
- id="path39153"
- style="fill:url(#linearGradient21444);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- sodipodi:type="arc" />
- <path
- inkscape:connector-curvature="0"
- style="opacity:0.4857143;fill:none;stroke:url(#linearGradient21446);stroke-width:1.7812928;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1"
- d="m 25.8125,6.40625 c -0.334829,4.572e-4 -0.72202,0.089606 -0.90625,0.21875 4.5e-4,0.010412 4.5e-4,0.020838 0,0.03125 -0.212626,0.1484635 -0.188235,0.1956271 -0.1875,0.1875 0.0092,0.010621 -0.0072,-4.246e-4 0.03125,0.03125 0.01962,0.00828 0.03527,0.012546 0.0625,0.03125 0.01676,0.01151 0.01357,0.014555 0.03125,0.03125 0.193748,0.1576058 4.954976,4.005164 4.954976,4.005164 0.489837,0.39864 0.677395,1.066352 0.46875,1.65625 -0.115662,0.32703 -0.422813,0.541217 -0.6875,0.59375 -0.264687,0.05253 -0.498447,0.03054 -0.71875,0.03125 -5.639658,0.05119 -16.87989,0.03851 -16.87989,0.03851 -0.4102,2.75e-4 -0.935835,0.115997 -1.34375,0.34375 -0.407915,0.227753 -0.6637862,0.523861 -0.6875002,0.90625 -0.024417,0.393728 0.098829,0.605767 0.3437502,0.78125 0.244921,0.175483 0.614978,0.25 0.875,0.25 0,0 8.8125,0 8.8125,0 0.600305,-7.28e-4 1.223895,0.311058 1.4375,0.9375 0.04676,0.137121 0.06335,0.269976 0.0625,0.40625 -8.49e-4,0.136274 -0.02214,0.268794 -0.09375,0.375 -0.143211,0.212412 -0.319507,0.298568 -0.5,0.4375 0,0 -15.7871819,12.746851 -15.856336,12.800078 C 5.0310984,30.500117 5,30.53125 5,30.53125 5.0100745,30.519077 5.000335,30.499512 5,30.5 L 4.8125,30.3125 c 0.012336,0.02165 0.014481,0.03307 0.03125,0.0625 0.063558,0.0774 0.125,0.15625 0.125,0.15625 -0.00585,0.0056 -0.031233,0.03124 -0.03125,0.03125 0,0 -0.043442,-0.09921 -0.09375,-0.1875 0.037843,0.09884 0.06253,0.218739 0.0625,0.21875 -0.4662091,0.37119 -0.7783348,0.889746 -0.875,1.28125 -0.1043319,0.422581 -0.046,0.62455 0.125,0.84375 0.2999827,0.384295 1.3975356,0.595547 2.40625,-0.21875 0,0 8.65625,-7.09375 8.65625,-7.09375 0.473718,-0.387074 1.1446,-0.458625 1.6875,-0.15625 0.544608,0.303331 0.798054,0.927572 0.71875,1.53125 0,0 -0.0626,0.908319 -0.0625,1.25 2e-6,0.0085 -1.19e-4,0.02348 0,0.03125 0.192796,2.523718 1.400736,4.762818 3.03125,6.71875 2.801818,3.089095 6.627659,4.401619 10.75,4.5625 4.113324,-0.043 7.964529,-1.606111 10.75,-4.625 2.546631,-3.125326 3.513872,-6.363859 3.15625,-9.375 C 44.891575,22.325847 43.222923,19.516566 40.4375,17.25 35.951885,13.599946 31.206991,10.168434 26.59375,6.625 26.57515,6.610386 26.56455,6.59802 26.5625,6.59375 26.43835,6.498703 26.144223,6.4057899 25.8125,6.40625 z"
- id="path21414"
- sodipodi:nodetypes="csssssscssscsssccssscscccsccssssccscsscccssssc" />
- <path
- inkscape:connector-curvature="0"
- d="m 25.708956,26.064593 c 0.07649,-1.397943 0.759369,-2.631914 1.78592,-3.505519 1.010226,-0.858782 2.366788,-1.383145 3.848625,-1.383145 1.480894,0 2.837456,0.524363 3.847446,1.383145 1.027685,0.873605 1.709741,2.106651 1.787122,3.504594 0.07927,1.438713 -0.49591,2.77459 -1.504012,3.764001 -1.027686,1.007933 -2.493008,1.640678 -4.130556,1.640678 -1.63849,0 -3.103814,-0.632745 -4.131451,-1.640678 -1.00914,-0.989411 -1.58234,-2.325288 -1.503094,-3.763076 l 0,0 0,0 0,0 z"
- id="path2478"
- style="fill:#3465a4;fill-rule:evenodd;stroke:none" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="csssscsccsscsccssssscsscccsssc"
- id="path39166"
- d="m 25.8125,6.03125 c -0.404852,5.53e-4 -2.204797,-0.059029 -2.48145,0.1349032 -0.280209,0.195652 -0.335403,0.376484 -0.34375,0.46875 -0.0083,0.092266 -0.01539,0.17648 0.1875,0.34375 0.01899,0.015735 0.04457,0.014317 0.0625,0.03125 0.124258,0.101028 4.748869,4.1248618 4.748869,4.1248618 0.373658,0.304091 0.504393,0.795817 0.34375,1.25 -0.160635,0.454191 -0.580748,0.373449 -1.0625,0.375 -5.634142,0.05114 -15.087371,-0.129601 -15.087371,-0.129601 -0.952967,6.38e-4 -2.339958,0.524782 -2.4062504,1.59375 -0.063562,1.024947 0.9247974,1.4375 1.5937504,1.4375 0,-1e-6 8.8125,0 8.8125,0 0.488364,-5.92e-4 0.936141,0.225277 1.09375,0.6875 0.157609,0.462231 -0.01926,0.514621 -0.40625,0.8125 0,0 -16.086298,13.088586 -16.086298,13.088586 -0.00142,0.0014 -0.029829,-0.0014 -0.03125,0 -0.064037,0.04879 -0.054226,0.04875 -0.03125,0.03125 -0.5536758,0.424619 -0.9087886,1.004019 -1.03125,1.5 -0.1224536,0.495981 -0.04661,0.856152 0.1875,1.15625 0.4788333,0.613413 1.777612,0.754857 2.90625,-0.15625 1e-7,10e-7 8.65625,-7.09375 8.65625,-7.09375 0.361955,-0.295753 0.872897,-0.352437 1.28125,-0.125 0.408345,0.227436 0.623381,0.692814 0.5625,1.15625 0,-1e-6 -0.0997,0.953636 -0.09375,1.34375 0.09498,1.301756 0.451616,2.521825 0.989039,3.664234 C 20.799917,36.321089 27.770982,19.392853 44.1875,21.03125 43.339652,19.54368 42.151282,18.185293 40.65625,16.96875 36.159865,13.309932 31.42016,9.882897 26.8125,6.34375 26.805335,6.338858 26.788292,6.317553 26.78125,6.3125 26.570707,6.151312 26.216591,6.030689 25.8125,6.03125 z"
- style="opacity:0.51999996;fill:url(#radialGradient21448);fill-opacity:1;fill-rule:evenodd;stroke:none" />
- </g>
- </g>
- <g
- style="opacity:0.5"
- id="g24847"
- transform="translate(162,248)">
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccssssccc"
- style="fill:url(#linearGradient24867);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="path24849"
- d="m 806.5,114.5 c 0,2.25 2,4 4,4 l 30,0 c 0.4163,0 1,-0.5 1,-1 l 0,-29 c 0,-0.5 -0.5,-1 -1,-1 l -21.02773,0.04419 C 818.98721,87.545209 818.5,87 818.5,86.5 l 0,-3 c 0,-0.5 -0.5,-1 -1,-1 l -10,0 c -0.5,0 -1,0.5 -1,1 l 0,31 z" />
- <path
- inkscape:connector-curvature="0"
- id="path24851"
- style="opacity:0.07999998;fill:url(#linearGradient24869);fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
- d="m 807.5,89.5 33,0 m -33,12 33,0 m -33,-4 33,0 m -33,-6 33,0 m -33,20 33,0 m -33,2 33,0 m -33,-18 33,0 m -33,-2 33,0 m -20,-6 -13,0 m 0,20 33,0 m -33,-2 33,0 m -33,-2 33,0 m -33,-4 33,0 m -33,10 33,0 m -33,6 33,0"
- sodipodi:nodetypes="cccccccccccccccccccccccccccccc" />
- <path
- inkscape:connector-curvature="0"
- inkscape:export-ydpi="74.800003"
- inkscape:export-xdpi="74.800003"
- inkscape:export-filename="/home/jimmac/ximian_art/icons/nautilus/suse93/gnome-fs-directory.png"
- sodipodi:nodetypes="csccsczc"
- id="path24853"
- d="m 844,118.5 c 3.5,0 5.5,-2 5.5,-5.5 l 0,-18.5 c -11.75604,-1.11e-4 -23.91623,0 -35.5,0 l 0,19.5 c 0,4.5 -7,4 -7,0.25 0,2 2.00002,3.73529 3,3.75 l 34,0.5 z"
- style="fill:url(#linearGradient24871);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
- <path
- inkscape:connector-curvature="0"
- d="m 807,87 12,0 0.0385,-3.33333 C 819.04423,83.166705 818.97512,83 818.5,83 l -10.92308,0 c -0.47512,0 -0.53846,0.16667 -0.53846,0.66667 L 807,87 z"
- id="path24855"
- style="opacity:0.7;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
- sodipodi:nodetypes="ccssccc" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cc"
- d="m 840.5,89 0,4.5"
- style="opacity:0.1;fill:none;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
- id="path24857" />
- <path
- inkscape:connector-curvature="0"
- id="path24859"
- style="opacity:0.1;fill:none;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
- d="m 848.5,95.5 0,18 c 0,1.25 0.25,3 -1.25,4"
- sodipodi:nodetypes="ccc" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccsc"
- d="m 818.5,83.5 -11,0 0,30 c 0,5 7,5 7,0 l 0,-18 34,0 m -29,-8 c 0,0.5 0.5286,1 1,1 l 20,0"
- style="opacity:0.75;fill:none;stroke:#ffffff;stroke-width:1.29999995;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
- id="path24861" />
- <path
- inkscape:connector-curvature="0"
- d="m 806.5,113.5 c 0,2.75 2,5 5,5 l 33,0 c 3,0 5,-2 5,-5 l 0,-18 c 0,-0.471405 -0.5286,-1 -1,-1 l -7,0 0,-6 c 0,-0.5 -0.5,-1 -1,-1 l -20.02773,0.04419 C 819.98721,87.54526 819.5,87 819.5,86.5 l 0,-3 c 0,-0.5 -0.5,-1 -1,-1 l -11,0 c -0.5,0 -1,0.5 -1,1 l 0,30 z"
- id="path24863"
- style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- sodipodi:nodetypes="ccccsscccssssccc" />
- <path
- inkscape:connector-curvature="0"
- style="fill:none;stroke:url(#linearGradient24873);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- d="m 841.5,94.5 -27,0 c -0.4714,0 -1,0.528595 -1,1 l 0,18 c 0,2.25 -1.25,3 -2.5,3"
- id="path24865"
- sodipodi:nodetypes="csscc" />
- </g>
- <g
- style="opacity:0.5"
- transform="translate(114,248)"
- id="g24784">
- <path
- inkscape:connector-curvature="0"
- d="m 806.5,114.5 c 0,2.25 2,4 4,4 l 30,0 c 0.4163,0 1,-0.5 1,-1 l 0,-29 c 0,-0.5 -0.5,-1 -1,-1 l -21.02773,0.04419 C 818.98721,87.545209 818.5,87 818.5,86.5 l 0,-3 c 0,-0.5 -0.5,-1 -1,-1 l -10,0 c -0.5,0 -1,0.5 -1,1 l 0,31 z"
- id="path24789"
- style="fill:url(#linearGradient24809);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- sodipodi:nodetypes="ccccccssssccc" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccccccccccccccccc"
- d="m 807.5,89.5 33,0 m -33,12 33,0 m -33,-4 33,0 m -33,-6 33,0 m -33,20 33,0 m -33,2 33,0 m -33,-18 33,0 m -33,-2 33,0 m -20,-6 -13,0 m 0,20 33,0 m -33,-2 33,0 m -33,-2 33,0 m -33,-4 33,0 m -33,10 33,0 m -33,6 33,0"
- style="opacity:0.07999998;fill:url(#linearGradient24811);fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
- id="path24791" />
- <path
- inkscape:connector-curvature="0"
- style="fill:url(#linearGradient24813);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- d="m 844,118.5 c 3.5,0 5.5,-2 5.5,-5.5 l 0,-18.5 c -11.75604,-1.11e-4 -23.91623,0 -35.5,0 l 0,19.5 c 0,4.5 -7,4 -7,0.25 0,2 2.00002,3.73529 3,3.75 l 34,0.5 z"
- id="path24793"
- sodipodi:nodetypes="csccsczc"
- inkscape:export-filename="/home/jimmac/ximian_art/icons/nautilus/suse93/gnome-fs-directory.png"
- inkscape:export-xdpi="74.800003"
- inkscape:export-ydpi="74.800003" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccssccc"
- style="opacity:0.7;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path24796"
- d="m 807,87 12,0 0.0385,-3.33333 C 819.04423,83.166705 818.97512,83 818.5,83 l -10.92308,0 c -0.47512,0 -0.53846,0.16667 -0.53846,0.66667 L 807,87 z" />
- <path
- inkscape:connector-curvature="0"
- id="path24799"
- style="opacity:0.1;fill:none;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
- d="m 840.5,89 0,4.5"
- sodipodi:nodetypes="cc" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccc"
- d="m 848.5,95.5 0,18 c 0,1.25 0.25,3 -1.25,4"
- style="opacity:0.1;fill:none;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
- id="path24801" />
- <path
- inkscape:connector-curvature="0"
- id="path24803"
- style="opacity:0.75;fill:none;stroke:#ffffff;stroke-width:1.29999995;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
- d="m 818.5,83.5 -11,0 0,30 c 0,5 7,5 7,0 l 0,-18 34,0 m -29,-8 c 0,0.5 0.5286,1 1,1 l 20,0"
- sodipodi:nodetypes="cccccccsc" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccsscccssssccc"
- style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="path24805"
- d="m 806.5,113.5 c 0,2.75 2,5 5,5 l 33,0 c 3,0 5,-2 5,-5 l 0,-18 c 0,-0.471405 -0.5286,-1 -1,-1 l -7,0 0,-6 c 0,-0.5 -0.5,-1 -1,-1 l -20.02773,0.04419 C 819.98721,87.54526 819.5,87 819.5,86.5 l 0,-3 c 0,-0.5 -0.5,-1 -1,-1 l -11,0 c -0.5,0 -1,0.5 -1,1 l 0,30 z" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="csscc"
- id="path24807"
- d="m 841.5,94.5 -27,0 c -0.4714,0 -1,0.528595 -1,1 l 0,18 c 0,2.25 -1.25,3 -2.5,3"
- style="fill:none;stroke:url(#linearGradient24815);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
- </g>
- <g
- transform="translate(0,-2)"
- style="opacity:0.4;stroke:#3d361a;filter:url(#filter44473)"
- id="g44424">
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccc"
- id="path44406"
- d="m 950.25,362 -5.25,0 -1,-1 0,-10"
- style="fill:none;stroke:#3d361a;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline;enable-background:new" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccc"
- id="path44408"
- d="M 948.25,354.25 944,350.00563 939.75,354.25"
- style="fill:none;stroke:#3d361a;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline;enable-background:new" />
- </g>
- <g
- transform="translate(617,273)"
- id="g44334"
- style="display:inline;enable-background:new">
- <rect
- style="opacity:0;fill:#1a1a1a;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.20000005;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="rect44336"
- width="16"
- height="16"
- x="320"
- y="73" />
- <g
- transform="translate(0,-21)"
- id="g44338">
- <g
- id="g44340">
- <g
- transform="translate(0,21)"
- id="g44342">
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccc"
- id="path44344"
- d="m 333.25,87 -5.25,0 -1,-1 0,-10"
- style="fill:none;stroke:#000000;stroke-width:3.4000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccc"
- id="path44346"
- d="M 331.25,79.25 327,75.005631 322.75,79.25"
- style="fill:none;stroke:#000000;stroke-width:3.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
- </g>
- <g
- transform="translate(0,21)"
- id="g44348">
- <path
- inkscape:connector-curvature="0"
- style="fill:none;stroke:#e6e6e6;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- d="m 333.25,87 -5.25,0 -1,-1 0,-10"
- id="path44350"
- sodipodi:nodetypes="cccc" />
- <path
- inkscape:connector-curvature="0"
- style="fill:none;stroke:#e6e6e6;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- d="M 331.25,79.25 327,75.005631 322.75,79.25"
- id="path44352"
- sodipodi:nodetypes="ccc" />
- </g>
- </g>
- <path
- inkscape:connector-curvature="0"
- style="fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- d="m 328.5,107.5 5,0 m -7,-9 0,8.5 m -4.25,-7 4.5,-4.5"
- id="path44354"
- sodipodi:nodetypes="cccccc" />
- </g>
- </g>
- <g
- transform="translate(66,248)"
- id="g24818"
- style="display:inline;enable-background:new">
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccssssccc"
- style="fill:url(#linearGradient24839);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="path24821"
- d="m 806.5,114.5 c 0,2.25 2,4 4,4 l 30,0 c 0.4163,0 1,-0.5 1,-1 l 0,-29 c 0,-0.5 -0.5,-1 -1,-1 l -21.02773,0.04419 C 818.98721,87.545209 818.5,87 818.5,86.5 l 0,-3 c 0,-0.5 -0.5,-1 -1,-1 l -10,0 c -0.5,0 -1,0.5 -1,1 l 0,31 z" />
- <path
- inkscape:connector-curvature="0"
- id="path24823"
- style="opacity:0.07999998;fill:url(#linearGradient24841);fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
- d="m 807.5,89.5 33,0 m -33,12 33,0 m -33,-4 33,0 m -33,-6 33,0 m -33,20 33,0 m -33,2 33,0 m -33,-18 33,0 m -33,-2 33,0 m -20,-6 -13,0 m 0,20 33,0 m -33,-2 33,0 m -33,-2 33,0 m -33,-4 33,0 m -33,10 33,0 m -33,6 33,0"
- sodipodi:nodetypes="cccccccccccccccccccccccccccccc" />
- <path
- inkscape:connector-curvature="0"
- inkscape:export-ydpi="74.800003"
- inkscape:export-xdpi="74.800003"
- inkscape:export-filename="/home/jimmac/ximian_art/icons/nautilus/suse93/gnome-fs-directory.png"
- sodipodi:nodetypes="csccsczc"
- id="path24825"
- d="m 844,118.5 c 3.5,0 5.5,-2 5.5,-5.5 l 0,-16 c -11.75604,-1.11e-4 -23.91623,0 -35.5,0 l 0,17 c 0,4.5 -7,4 -7,0.25 0,2 2.00002,3.73529 3,3.75 l 34,0.5 z"
- style="fill:url(#linearGradient24843);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
- <path
- inkscape:connector-curvature="0"
- d="m 807,87 12,0 0.0385,-3.33333 C 819.04423,83.166705 818.97512,83 818.5,83 l -10.92308,0 c -0.47512,0 -0.53846,0.16667 -0.53846,0.66667 L 807,87 z"
- id="path24827"
- style="opacity:0.7;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
- sodipodi:nodetypes="ccssccc" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cc"
- d="m 840.5,89 0,7.5"
- style="opacity:0.1;fill:none;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
- id="path24829" />
- <path
- inkscape:connector-curvature="0"
- id="path24831"
- style="opacity:0.1;fill:none;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
- d="m 848.5,98.75 0,14.75 c 0,1.25 0.25,3 -1.25,4"
- sodipodi:nodetypes="ccc" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccsc"
- d="m 818.5,83.5 -11,0 0,30 c 0,5 7,5 7,0 l 0,-16 34,0 m -29,-10 c 0,0.5 0.5286,1 1,1 l 20,0"
- style="opacity:0.75;fill:none;stroke:#ffffff;stroke-width:1.29999995;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
- id="path24833" />
- <path
- inkscape:connector-curvature="0"
- d="m 806.5,113.5 c 0,2.75 2,5 5,5 l 33,0 c 3,0 5,-2 5,-5 l 0,-16 c 0,-0.471405 -0.5286,-1 -1,-1 l -7,0 0,-8 c 0,-0.5 -0.5,-1 -1,-1 l -20.02773,0.04419 C 819.98721,87.54526 819.5,87 819.5,86.5 l 0,-3 c 0,-0.5 -0.5,-1 -1,-1 l -11,0 c -0.5,0 -1,0.5 -1,1 l 0,30 z"
- id="path24835"
- style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- sodipodi:nodetypes="ccccsscccssssccc" />
- <path
- inkscape:connector-curvature="0"
- style="fill:none;stroke:url(#linearGradient24845);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- d="m 841.5,96.500004 -27,0 c -0.4714,0 -1,0.528595 -1,1 l 0,15.999996 c 0,2.25 -1.25,3 -2.5,3"
- id="path24837"
- sodipodi:nodetypes="csscc" />
- </g>
- <g
- style="opacity:0.4;filter:url(#filter44477)"
- id="g44455">
- <path
- inkscape:connector-curvature="0"
- transform="translate(645,252.05)"
- style="fill:none;stroke:#3d361a;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- d="m 343.5,104.5 1.75,1.75 c 2.3454,2.33848 6.16153,2.34539 8.5,0 l 0.5,-0.5"
- id="path44446"
- sodipodi:nodetypes="cs" />
- <path
- inkscape:connector-curvature="0"
- transform="translate(645,252.05)"
- style="fill:none;stroke:#3d361a;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- d="m 343,108.25 0,-4.25 4.25,0"
- id="path44449"
- sodipodi:nodetypes="ccc" />
- <path
- inkscape:connector-curvature="0"
- transform="matrix(-1,0,0,-1,1343,456.05)"
- sodipodi:nodetypes="cs"
- id="path44451"
- d="m 343.5,104.5 1.75,1.75 c 2.3454,2.33848 6.16153,2.34539 8.5,0 l 0.5,-0.5"
- style="fill:none;stroke:#3d361a;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
- <path
- inkscape:connector-curvature="0"
- transform="matrix(-1,0,0,-1,1343,456.05)"
- sodipodi:nodetypes="ccc"
- id="path44453"
- d="m 343,108.25 0,-4.25 4.25,0"
- style="fill:none;stroke:#3d361a;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
- </g>
- <g
- transform="translate(645,273.05)"
- id="g44356"
- style="display:inline;enable-background:new">
- <rect
- y="73"
- x="341"
- height="16"
- width="16"
- id="rect44358"
- style="opacity:0;fill:#1a1a1a;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.20000005;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
- <g
- transform="translate(0,-21)"
- id="g44360">
- <g
- id="g44362">
- <g
- id="g44364">
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cs"
- id="path44366"
- d="m 343.5,104.5 1.75,1.75 c 2.3454,2.33848 6.16153,2.34539 8.5,0 l 0.5,-0.5"
- style="fill:none;stroke:#000000;stroke-width:3.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccc"
- id="path44368"
- d="m 343,108.25 0,-4.25 4.25,0"
- style="fill:none;stroke:#000000;stroke-width:3.4000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
- </g>
- <g
- id="g44370">
- <path
- inkscape:connector-curvature="0"
- style="fill:none;stroke:#e6e6e6;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- d="m 343,108.25 0,-4.25 4.25,0"
- id="path44372"
- sodipodi:nodetypes="ccc" />
- <path
- inkscape:connector-curvature="0"
- style="fill:none;stroke:#e6e6e6;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- d="m 343.5,104.5 1.75,1.75 c 2.3454,2.33848 6.16153,2.34539 8.5,0 l 0.5,-0.5"
- id="path44374"
- sodipodi:nodetypes="cs" />
- </g>
- <path
- inkscape:connector-curvature="0"
- id="path44376"
- d="m 344,105 0,1 0,1.5 1,0 0,-1.5 1.5,0 0,-1 -1.5,0 -1,0 z"
- style="opacity:0.1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
- </g>
- <g
- id="g44378"
- transform="matrix(-1,0,0,-1,698,204)">
- <g
- id="g44380">
- <path
- inkscape:connector-curvature="0"
- style="fill:none;stroke:#000000;stroke-width:3.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- d="m 343.5,104.5 1.75,1.75 c 2.3454,2.33848 6.16153,2.34539 8.5,0 l 0.5,-0.5"
- id="path44382"
- sodipodi:nodetypes="cs" />
- <path
- inkscape:connector-curvature="0"
- style="fill:none;stroke:#000000;stroke-width:3.4000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- d="m 343,108.25 0,-4.25 4.25,0"
- id="path44384"
- sodipodi:nodetypes="ccc" />
- </g>
- <g
- id="g44386">
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccc"
- id="path44388"
- d="m 343,108.25 0,-4.25 4.25,0"
- style="fill:none;stroke:#e6e6e6;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cs"
- id="path44390"
- d="m 343.5,104.5 1.75,1.75 c 2.3454,2.33848 6.16153,2.34539 8.5,0 l 0.5,-0.5"
- style="fill:none;stroke:#e6e6e6;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
- </g>
- <path
- inkscape:connector-curvature="0"
- style="opacity:0.1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- d="m 344,105 0,1 0,1.5 1,0 0,-1.5 1.5,0 0,-1 -1.5,0 -1,0 z"
- id="path44392" />
- <path
- inkscape:connector-curvature="0"
- style="fill:none;stroke:url(#linearGradient44402);stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- d="m 344.90625,106.59375 c 2.52573,2.51828 6.66805,2.52691 9.1875,0 l 0.5,-0.5"
- id="path44394"
- sodipodi:nodetypes="ccc" />
- </g>
- <path
- inkscape:connector-curvature="0"
- style="fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- d="m 350.5,99.5 4,0 0,-4"
- id="path44396"
- sodipodi:nodetypes="ccc" />
- <path
- inkscape:connector-curvature="0"
- style="fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- d="m 347.5,103.5 -4.5,0 c -0.25,0 -0.5,0.25 -0.5,0.5 l 0,4.5"
- id="path44398"
- sodipodi:nodetypes="cccc" />
- <path
- inkscape:connector-curvature="0"
- style="fill:none;stroke:url(#linearGradient44404);stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- d="m 345.59375,105.90625 c 2.07803,2.0719 5.36384,2.10325 7.53125,0.1875 L 354,105.25"
- id="path44400"
- sodipodi:nodetypes="ccc" />
- </g>
- </g>
- <g
- id="g34977"
- style="display:inline;enable-background:new">
- <g
- style="display:inline"
- id="g21853-3"
- transform="translate(856,-154)"
- inkscape:export-filename="C:\Documents and Settings\Pracowniaa\Moje dokumenty\Moje obrazy\BLENDER ICONS redesign\ver 2\IMAGE BROWSER ICONS.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <rect
- ry="0"
- rx="2.4004419"
- y="430"
- x="108"
- height="48"
- width="48"
- id="rect21855-8"
- style="opacity:0;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
- <g
- id="g21857-6">
- <path
- inkscape:connector-curvature="0"
- style="fill:url(#linearGradient21875-7-1-0-1);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;display:inline"
- d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
- id="path21859-9"
- sodipodi:nodetypes="cccccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90" />
- <path
- inkscape:connector-curvature="0"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
- style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- id="path21861-8"
- sodipodi:nodetypes="cccc" />
- <path
- inkscape:connector-curvature="0"
- clip-path="url(#clipPath13106-9-2-9-9)"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccc"
- id="path21863-6"
- d="m 115,444 12,0 -1,-11 -11,11 z"
- style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011-6-7-0-8)" />
- <path
- inkscape:connector-curvature="0"
- clip-path="none"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 117.5,443.75 9,-2.5 0,-6"
- style="fill:none;stroke:url(#linearGradient21877-3-2-7-2);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- id="path21865-6"
- sodipodi:nodetypes="ccc" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccc"
- id="path21867-2"
- style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90" />
- <path
- inkscape:connector-curvature="0"
- clip-path="url(#clipPath13106-9-2-9-9)"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccc"
- id="path21869-3"
- d="m 116,443 11,1 -2,-10 -9,9 z"
- style="opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline;filter:url(#filter63011-6-7-0-8)" />
- <path
- inkscape:connector-curvature="0"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
- d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
- id="path21871-8"
- sodipodi:nodetypes="cccccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccc"
- id="path21873-2"
- style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- d="m 147.5,435 0,38.5 -30.5,0"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90" />
- </g>
- </g>
- <g
- id="g34938"
- transform="translate(63,-47)">
- <path
- id="path61236"
- style="color:#000000;fill:url(#linearGradient34959-9-2-1);fill-opacity:1;fill-rule:nonzero;stroke:#ff0000;stroke-width:0.17893334;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- d="m 919.5,356.5067 0,-3 c 0,-1.73575 1.26424,-3 3,-3 l 5,0 c 1.73576,0 3,-1.26425 3,-3 l 0,-3.0064 2.5,0.006 c 2,0 3.5,2.5 3.5,6 0,3.5 -1.25,6 -3.5,6 -4.98134,0 -12.77318,0 -2.5,0 l 0,2.75 c 0,2.5 -2,3.24997 -5.5,3.24998 l 0,2e-5 c -3.5,0.0104 -5.5,-0.75 -5.5,-3.25 l 0,-2.7628"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cssssccsscsccsc" />
- <path
- sodipodi:nodetypes="cssssccsscsccsc"
- inkscape:connector-curvature="0"
- d="m 930.5,344.5 0,3 c 0,1.73575 -1.26424,3 -3,3 l -5,0 c -1.73576,0 -3,1.26425 -3,3 l 0,3.0064 -2.5,-0.006 c -2,0 -3.5,-2.5 -3.5,-6 0,-3.5 1.25,-6 3.5,-6 4.98134,0 12.77318,0 2.5,0 l 0,-2.75 c 0,-2.5 2,-3.24997 5.5,-3.24998 l 0,-2e-5 c 3.5,-0.0104 5.5,0.75 5.5,3.25 l 0,2.7628"
- style="color:#000000;fill:url(#linearGradient34961-3-6-5);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.17893334;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="path61233" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccscccsccccsccccc"
- id="path61167"
- d="m 925,338.50002 c -3.5,10e-6 -5.5,0.74998 -5.5,3.24998 l 0,2.75 5.5,0 -8,0 c -2.25,0 -3.5,2.5 -3.5,6 0,3.5 1.5,6 3.5,6 l 2.5,0.0128 0,2.9872 c 0,2 2,3.01281 5.5,3.0128 3.5,-1e-5 5.5,-1.0128 5.5,-3.0128 l 0,-3 -5.5,0 8,0 c 2,0 3.5,-2.5 3.5,-6 0,-3.5 -1.5,-6 -3.5,-6 l -2.5,0.0128 0,-2.7628 c 0,-2.5 -2,-3.26045 -5.5,-3.25 z"
- style="fill:none;stroke:#000000;stroke-width:0.80000001;stroke-miterlimit:4;stroke-opacity:0.8627451;stroke-dasharray:none" />
- <path
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccc"
- id="path61169"
- d="m 930.5,344.5 0,3 c 0,1.73575 -1.26424,3 -3,3 l -5,0 c -1.73576,0 -3,1.26425 -3,3 l 0,3"
- style="fill:none;stroke:#000000;stroke-width:0.80000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.78431373;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
- <path
- d="m 923,342 a 1,1 0 0 1 -1,1 1,1 0 0 1 -1,-1 1,1 0 0 1 1,-1 1,1 0 0 1 1,1 z"
- sodipodi:ry="1"
- sodipodi:rx="1"
- sodipodi:cy="342"
- sodipodi:cx="922"
- id="path61220"
- style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.80000001;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- sodipodi:type="arc" />
- <path
- d="m 929,359 a 1,1 0 0 1 -1,1 1,1 0 0 1 -1,-1 1,1 0 0 1 1,-1 1,1 0 0 1 1,1 z"
- sodipodi:ry="1"
- sodipodi:rx="1"
- sodipodi:cy="359"
- sodipodi:cx="928"
- id="path61222"
- style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.80000001;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- sodipodi:type="arc" />
- <g
- style="opacity:0.4"
- id="g61345">
- <path
- style="fill:none;stroke:url(#linearGradient34963-5-9-1);stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
- d="m 920.5,343.25 0,-1.5 c 0,-1.75 1.5,-2.25 4.5,-2.25 3,0 4.5,0.5 4.5,2.25 l 0,4.75"
- id="path61333"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cszsc" />
- <path
- style="fill:none;stroke:url(#linearGradient34965-1-5-2);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- d="m 925.5,345 0,0.25 -0.25,0.25 -8.25,0 c -1.5,0 -2.5,2 -2.5,5 0,3 1.28917,5 2.5,5 l 1.5,0"
- id="path61335"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccszsc" />
- <path
- style="fill:none;stroke:none"
- d="m 920.75,343.5 4.5,0 0.25,0.25 0,0.5"
- id="path61337"
- inkscape:connector-curvature="0" />
- <path
- style="fill:none;stroke:none"
- d="m 918.5,355.25 0,-1.75 c 0,-2.25 1.75,-4 4,-4 l 4.5,0 c 1.75,0 2.5,-0.75 2.5,-2.5 l 0,-0.5"
- id="path61339"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cssssc" />
- <path
- transform="matrix(1.5161021,0,0,1.5161021,-475.84616,-176.50693)"
- sodipodi:type="arc"
- style="color:#000000;fill:none;stroke:url(#linearGradient34967-4-1-8);stroke-width:0.52766895;stroke-miterlimit:4;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="path61355"
- sodipodi:cx="922"
- sodipodi:cy="342"
- sodipodi:rx="1"
- sodipodi:ry="1"
- d="m 923,342 a 1,1 0 0 1 -1,1 1,1 0 0 1 -1,-1 1,1 0 0 1 1,-1 1,1 0 0 1 1,1 z" />
- </g>
- <g
- style="opacity:0.8;stroke:#ff0000"
- transform="matrix(-1,0,0,-1,1850,701)"
- id="g34104">
- <path
- sodipodi:nodetypes="cszsc"
- inkscape:connector-curvature="0"
- id="path34106"
- d="m 920.5,343.25 0,-1.5 c 0,-1.75 1.5,-2.25 4.5,-2.25 3,0 4.5,0.5 4.5,2.25 l 0,4.75"
- style="fill:none;stroke:none" />
- <path
- sodipodi:nodetypes="csc"
- inkscape:connector-curvature="0"
- id="path34108"
- d="m 914.5,350.5 c 0,3 1.28917,5 2.5,5 l 1.5,0"
- style="fill:none;stroke:url(#linearGradient34969-4-4-1);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
- <path
- inkscape:connector-curvature="0"
- id="path34110"
- d="m 920.75,343.5 4.5,0 0.25,0.25 0,0.5"
- style="fill:none;stroke:url(#linearGradient34971-5-0-9);stroke-linecap:round;stroke-linejoin:round" />
- <path
- sodipodi:nodetypes="cssssc"
- inkscape:connector-curvature="0"
- id="path34113"
- d="m 918.5,355.5 0,-2 c 0,-2.25 1.75,-4 4,-4 l 4.5,0 c 1.75,0 2.5,-0.75 2.5,-2.5 l 0,-0.5"
- style="fill:none;stroke:url(#radialGradient34973-2-5-7);stroke-linecap:round;stroke-linejoin:round" />
- <path
- d="m 923,342 a 1,1 0 0 1 -1,1 1,1 0 0 1 -1,-1 1,1 0 0 1 1,-1 1,1 0 0 1 1,1 z"
- sodipodi:ry="1"
- sodipodi:rx="1"
- sodipodi:cy="342"
- sodipodi:cx="922"
- id="path34115"
- style="color:#000000;fill:none;stroke:url(#linearGradient34975-9-4-9);stroke-width:0.52766895;stroke-miterlimit:4;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- sodipodi:type="arc"
- transform="matrix(1.5161021,0,0,1.5161021,-475.84616,-176.50693)" />
- <path
- style="fill:none;stroke:none"
- d="m 925.5,345 0,0.25 -0.25,0.25 -8.25,0 c -1.5,0 -2.5,2 -2.5,5"
- id="path34901"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccsc" />
- </g>
- </g>
- </g>
- <g
- style="display:inline;enable-background:new"
- id="g14765"
- inkscape:export-filename="/home/georg/Arbeitsfläche/2012/Blender Coding/Patch #2a/icon_big_redone 5a.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- transform="translate(1090.1244,-109.28264)">
- <rect
- ry="0"
- rx="2.4004419"
- y="336.28265"
- x="-78.124435"
- height="48"
- width="48"
- id="rect14767"
- style="opacity:0;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
- <path
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccccc"
- id="path14769"
- d="m -60.624426,339.78264 22.999995,0 0,41 -32.999995,0 0,-31 10,-10 z"
- style="fill:url(#linearGradient14814);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;display:inline"
- inkscape:connector-curvature="0" />
- <path
- sodipodi:nodetypes="cccc"
- id="path14771"
- style="opacity:0.7;fill:none;stroke:url(#linearGradient14816);stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.56470588"
- d="m -38.874431,340.78264 c -4.875,0 -21.749995,0 -21.749995,0 m -8.9447,8.5 -0.0553,30"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- inkscape:connector-curvature="0" />
- <path
- style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011-8)"
- d="m 115,444 12,0 -1,-11 -11,11 z"
- id="path14773"
- sodipodi:nodetypes="cccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- clip-path="url(#clipPath13106-0)"
- inkscape:connector-curvature="0"
- transform="translate(-186.12444,-93.717362)" />
- <path
- sodipodi:nodetypes="ccc"
- id="path14775"
- style="fill:none;stroke:url(#linearGradient14818);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- d="m -68.624426,350.03264 9,-2.5 0,-6"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- clip-path="none"
- inkscape:connector-curvature="0" />
- <path
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m -70.624426,349.03264 0,31.75 32.999995,0 0,-41 -23.749995,0 -9.25,9.25 z"
- style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- id="path14777"
- sodipodi:nodetypes="cccccc"
- inkscape:connector-curvature="0" />
- <path
- style="opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline;filter:url(#filter63011-8)"
- d="m 116,443 11,1 -2,-10 -9,9 z"
- id="path14779"
- sodipodi:nodetypes="cccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- clip-path="url(#clipPath13106-0)"
- inkscape:connector-curvature="0"
- transform="translate(-186.12444,-93.717362)" />
- <path
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccccc"
- id="path14781"
- d="m -70.124426,349.28264 0.0108,0.72434 9.9892,-2.72434 0,-7 -1,0 -9,9 z"
- style="fill:#ffffff;fill-opacity:0.75294118;fill-rule:evenodd;stroke:none"
- inkscape:connector-curvature="0" />
- <path
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m -38.624431,341.28264 0,38.5 -30.499995,0"
- style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- id="path14783"
- sodipodi:nodetypes="ccc"
- inkscape:connector-curvature="0" />
- <g
- transform="matrix(0.5406242,0,0,0.5829534,-67.987756,347.93806)"
- inkscape:label="Layer 1"
- id="g14785">
- <path
- sodipodi:type="arc"
- style="opacity:0.54857142;fill:url(#radialGradient14820);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="path14788"
- sodipodi:cx="28.019106"
- sodipodi:cy="38.98439"
- sodipodi:rx="15.467961"
- sodipodi:ry="5.3033009"
- d="M 43.487067,38.98439 A 15.467961,5.3033009 0 0 1 28.019106,44.287691 15.467961,5.3033009 0 0 1 12.551145,38.98439 15.467961,5.3033009 0 0 1 28.019106,33.681089 15.467961,5.3033009 0 0 1 43.487067,38.98439 Z"
- transform="matrix(1.274286,0,0,1.377124,-7.569123,-16.70193)" />
- <path
- style="fill:#f57900;fill-rule:evenodd;stroke:#aa4400;stroke-width:1.7812928;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
- id="path14790"
- d="m 16.048489,28.093447 c 0.0098,0.576682 0.196474,1.697902 0.471116,2.577425 0.581566,1.854137 1.56684,3.572658 2.939126,5.086496 1.407488,1.553118 3.138519,2.803227 5.139315,3.68976 2.105357,0.931573 4.384795,1.407488 6.750134,1.403741 2.365339,-0.005 4.644601,-0.488686 6.74896,-1.427017 2.00002,-0.895288 3.731043,-2.148391 5.13754,-3.705517 1.369207,-1.519844 2.352576,-3.241114 2.934089,-5.096258 0.294262,-0.938353 0.476921,-1.889392 0.553238,-2.845308 0.07331,-0.939306 0.04204,-1.883511 -0.09183,-2.823792 -0.259981,-1.835599 -0.896294,-3.556847 -1.872652,-5.12758 -0.895541,-1.441699 -2.047808,-2.70454 -3.417268,-3.766975 0,0 0.002,-0.002 0.002,-0.002 0,0 -13.828458,-10.6197195 -13.828458,-10.6197195 -0.01176,-0.00978 -0.02252,-0.019551 -0.03529,-0.028344 -0.909003,-0.6959264 -3.879837,-0.7738945 -4.87679,-0.075035 -1.01067,0.7057021 -1.091821,1.8092613 -0.195527,2.5482146 1.899775,1.4997633 2.656207,2.2801589 4.566507,3.7797379 0,0 -14.852491,0.167033 -14.852491,0.167033 -1.994685,0 -3.1682609,0.947915 -3.4153947,2.333683 -0.2180771,1.222836 0.7479213,2.738129 2.4800217,2.738129 2.956573,0.0039 5.942111,-0.0069 8.909215,-0.01272 0,0 -16.01999,12.453223 -16.01999,12.453223 -0.020527,0.01564 -0.041053,0.02933 -0.06158,0.04497 -1.4974197,1.148389 -1.9831951,3.059322 -1.0399808,4.268393 0.9598323,1.22959 2.9977653,1.230588 4.5147288,0.006 0,0 8.677593,-7.102098 8.677593,-7.102098 0,0 -0.12511,0.959824 -0.116333,1.535532 l 1e-6,2.6e-5 0,0 0,0 z"
- sodipodi:nodetypes="csssssssssscccsscccscccssccc"
- inkscape:connector-curvature="0" />
- <path
- sodipodi:type="arc"
- style="fill:url(#linearGradient14822);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="path14792"
- sodipodi:cx="31.1875"
- sodipodi:cy="25.75"
- sodipodi:rx="11.5625"
- sodipodi:ry="10.125"
- d="M 42.75,25.75 A 11.5625,10.125 0 0 1 31.1875,35.875 11.5625,10.125 0 0 1 19.625,25.75 11.5625,10.125 0 0 1 31.1875,15.625 11.5625,10.125 0 0 1 42.75,25.75 Z"
- transform="matrix(0.8018194,0,0,0.8471126,6.257567,4.5089892)" />
- <path
- sodipodi:nodetypes="csssssscssscsssccssscscccsccssssccscsscccssssc"
- id="path14794"
- d="m 25.8125,6.40625 c -0.334829,4.572e-4 -0.72202,0.089606 -0.90625,0.21875 4.5e-4,0.010412 4.5e-4,0.020838 0,0.03125 -0.212626,0.1484635 -0.188235,0.1956271 -0.1875,0.1875 0.0092,0.010621 -0.0072,-4.246e-4 0.03125,0.03125 0.01962,0.00828 0.03527,0.012546 0.0625,0.03125 0.01676,0.01151 0.01357,0.014555 0.03125,0.03125 0.193748,0.1576058 4.954976,4.005164 4.954976,4.005164 0.489837,0.39864 0.677395,1.066352 0.46875,1.65625 -0.115662,0.32703 -0.422813,0.541217 -0.6875,0.59375 -0.264687,0.05253 -0.498447,0.03054 -0.71875,0.03125 -5.639658,0.05119 -16.87989,0.03851 -16.87989,0.03851 -0.4102,2.75e-4 -0.935835,0.115997 -1.34375,0.34375 -0.407915,0.227753 -0.6637862,0.523861 -0.6875002,0.90625 -0.024417,0.393728 0.098829,0.605767 0.3437502,0.78125 0.244921,0.175483 0.614978,0.25 0.875,0.25 0,0 8.8125,0 8.8125,0 0.600305,-7.28e-4 1.223895,0.311058 1.4375,0.9375 0.04676,0.137121 0.06335,0.269976 0.0625,0.40625 -8.49e-4,0.136274 -0.02214,0.268794 -0.09375,0.375 -0.143211,0.212412 -0.319507,0.298568 -0.5,0.4375 0,0 -15.7871819,12.746851 -15.856336,12.800078 C 5.0310984,30.500117 5,30.53125 5,30.53125 5.0100745,30.519077 5.000335,30.499512 5,30.5 L 4.8125,30.3125 c 0.012336,0.02165 0.014481,0.03307 0.03125,0.0625 0.063558,0.0774 0.125,0.15625 0.125,0.15625 -0.00585,0.0056 -0.031233,0.03124 -0.03125,0.03125 0,0 -0.043442,-0.09921 -0.09375,-0.1875 0.037843,0.09884 0.06253,0.218739 0.0625,0.21875 -0.4662091,0.37119 -0.7783348,0.889746 -0.875,1.28125 -0.1043319,0.422581 -0.046,0.62455 0.125,0.84375 0.2999827,0.384295 1.3975356,0.595547 2.40625,-0.21875 0,0 8.65625,-7.09375 8.65625,-7.09375 0.473718,-0.387074 1.1446,-0.458625 1.6875,-0.15625 0.544608,0.303331 0.798054,0.927572 0.71875,1.53125 0,0 -0.0626,0.908319 -0.0625,1.25 2e-6,0.0085 -1.19e-4,0.02348 0,0.03125 0.192796,2.523718 1.400736,4.762818 3.03125,6.71875 2.801818,3.089095 6.627659,4.401619 10.75,4.5625 4.113324,-0.043 7.964529,-1.606111 10.75,-4.625 2.546631,-3.125326 3.513872,-6.363859 3.15625,-9.375 C 44.891575,22.325847 43.222923,19.516566 40.4375,17.25 35.951885,13.599946 31.206991,10.168434 26.59375,6.625 26.57515,6.610386 26.56455,6.59802 26.5625,6.59375 26.43835,6.498703 26.144223,6.4057899 25.8125,6.40625 z"
- style="opacity:0.4857143;fill:none;stroke:url(#linearGradient14825);stroke-width:1.7812928;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1"
- inkscape:connector-curvature="0" />
- <path
- style="fill:#3465a4;fill-rule:evenodd;stroke:none"
- id="path14796"
- d="m 25.708956,26.064593 c 0.07649,-1.397943 0.759369,-2.631914 1.78592,-3.505519 1.010226,-0.858782 2.366788,-1.383145 3.848625,-1.383145 1.480894,0 2.837456,0.524363 3.847446,1.383145 1.027685,0.873605 1.709741,2.106651 1.787122,3.504594 0.07927,1.438713 -0.49591,2.77459 -1.504012,3.764001 -1.027686,1.007933 -2.493008,1.640678 -4.130556,1.640678 -1.63849,0 -3.103814,-0.632745 -4.131451,-1.640678 -1.00914,-0.989411 -1.58234,-2.325288 -1.503094,-3.763076 l 0,0 0,0 0,0 z"
- inkscape:connector-curvature="0" />
- <path
- style="opacity:0.51999996;fill:url(#radialGradient14827);fill-opacity:1;fill-rule:evenodd;stroke:none"
- d="m 25.8125,6.03125 c -0.404852,5.53e-4 -2.204797,-0.059029 -2.48145,0.1349032 -0.280209,0.195652 -0.335403,0.376484 -0.34375,0.46875 -0.0083,0.092266 -0.01539,0.17648 0.1875,0.34375 0.01899,0.015735 0.04457,0.014317 0.0625,0.03125 0.124258,0.101028 4.748869,4.1248618 4.748869,4.1248618 0.373658,0.304091 0.504393,0.795817 0.34375,1.25 -0.160635,0.454191 -0.580748,0.373449 -1.0625,0.375 -5.634142,0.05114 -15.087371,-0.129601 -15.087371,-0.129601 -0.952967,6.38e-4 -2.339958,0.524782 -2.4062504,1.59375 -0.063562,1.024947 0.9247974,1.4375 1.5937504,1.4375 0,-1e-6 8.8125,0 8.8125,0 0.488364,-5.92e-4 0.936141,0.225277 1.09375,0.6875 0.157609,0.462231 -0.01926,0.514621 -0.40625,0.8125 0,0 -16.086298,13.088586 -16.086298,13.088586 -0.00142,0.0014 -0.029829,-0.0014 -0.03125,0 -0.064037,0.04879 -0.054226,0.04875 -0.03125,0.03125 -0.5536758,0.424619 -0.9087886,1.004019 -1.03125,1.5 -0.1224536,0.495981 -0.04661,0.856152 0.1875,1.15625 0.4788333,0.613413 1.777612,0.754857 2.90625,-0.15625 1e-7,10e-7 8.65625,-7.09375 8.65625,-7.09375 0.361955,-0.295753 0.872897,-0.352437 1.28125,-0.125 0.408345,0.227436 0.623381,0.692814 0.5625,1.15625 0,-1e-6 -0.0997,0.953636 -0.09375,1.34375 0.09498,1.301756 0.451616,2.521825 0.989039,3.664234 C 20.799917,36.321089 27.770982,19.392853 44.1875,21.03125 43.339652,19.54368 42.151282,18.185293 40.65625,16.96875 36.159865,13.309932 31.42016,9.882897 26.8125,6.34375 26.805335,6.338858 26.788292,6.317553 26.78125,6.3125 26.570707,6.151312 26.216591,6.030689 25.8125,6.03125 z"
- id="path14798"
- sodipodi:nodetypes="csssscsccsscsccssssscsscccsssc"
- inkscape:connector-curvature="0" />
- </g>
- </g>
- </g>
- <g
id="ICON_FULLSCREEN_ENTER"
inkscape:export-filename="C:\Documents and Settings\Pracownia\Moje dokumenty\Moje obrazy\BLENDER ICONS redesign\ver 3\fullscreen.png"
inkscape:export-xdpi="90"
@@ -91590,8 +90026,7 @@
cx="304.0946"
cy="242.89087"
rx="0.59120387"
- ry="0.61330098"
- d="m 304.68581,242.89087 c 0,0.33872 -0.26469,0.6133 -0.59121,0.6133 -0.32651,0 -0.5912,-0.27458 -0.5912,-0.6133 0,-0.33872 0.26469,-0.6133 0.5912,-0.6133 0.32652,0 0.59121,0.27458 0.59121,0.6133 z" />
+ ry="0.61330098" />
<ellipse
sodipodi:ry="0.61330098"
sodipodi:rx="0.59120387"
@@ -91602,8 +90037,7 @@
cx="315.98523"
cy="242.95337"
rx="0.59120387"
- ry="0.61330098"
- d="m 316.57643,242.95337 c 0,0.33872 -0.26469,0.6133 -0.5912,0.6133 -0.32651,0 -0.5912,-0.27458 -0.5912,-0.6133 0,-0.33872 0.26469,-0.6133 0.5912,-0.6133 0.32651,0 0.5912,0.27458 0.5912,0.6133 z" />
+ ry="0.61330098" />
</g>
<g
clip-path="url(#clipPath15455-9)"
@@ -91819,8 +90253,7 @@
cy="242.89087"
cx="304.0946"
id="ellipse15366"
- style="opacity:0.51799999;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- d="m 304.68581,242.89087 c 0,0.33872 -0.26469,0.6133 -0.59121,0.6133 -0.32651,0 -0.5912,-0.27458 -0.5912,-0.6133 0,-0.33872 0.26469,-0.6133 0.5912,-0.6133 0.32652,0 0.59121,0.27458 0.59121,0.6133 z" />
+ style="opacity:0.51799999;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<ellipse
sodipodi:ry="0.61330098"
sodipodi:rx="0.59120387"
@@ -91831,8 +90264,7 @@
cy="242.95337"
cx="315.98523"
id="ellipse15368"
- style="opacity:0.51799999;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- d="m 316.57643,242.95337 c 0,0.33872 -0.26469,0.6133 -0.5912,0.6133 -0.32651,0 -0.5912,-0.27458 -0.5912,-0.6133 0,-0.33872 0.26469,-0.6133 0.5912,-0.6133 0.32651,0 0.5912,0.27458 0.5912,0.6133 z" />
+ style="opacity:0.51799999;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
</g>
<g
transform="translate(189.00803,-79.37555)"
@@ -91942,6 +90374,382 @@
style="color:#000000;fill:url(#radialGradient14216);fill-opacity:1;stroke:none;stroke-width:1.20000005;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" />
</g>
</g>
+ <g
+ style="display:inline;enable-background:new"
+ id="g17465"
+ transform="translate(62.844714,-106.93345)">
+ <g
+ transform="matrix(0.7,0,0,0.7,146.7,264.8)"
+ id="ICON_COLOR-1-9"
+ style="display:inline;enable-background:new">
+ <rect
+ y="238"
+ x="341"
+ height="16"
+ width="16"
+ id="rect36341-2-0"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#b3b3b3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate" />
+ <g
+ id="g36343-7-5"
+ transform="translate(0,-12)">
+ <g
+ transform="matrix(1.1658027,0,0,1.1657997,198.71028,-2.0560643)"
+ id="g36345-0-4">
+ <path
+ transform="matrix(0.6969448,0,0,0.6969467,36.918512,140.83126)"
+ sodipodi:type="arc"
+ style="fill:#ff6600;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path36349-4-2"
+ sodipodi:cx="132"
+ sodipodi:cy="118"
+ sodipodi:rx="8"
+ sodipodi:ry="8"
+ d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 Z"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ sodipodi:start="4.712389"
+ sodipodi:end="5.7595865"
+ inkscape:transform-center-x="-2.8145849"
+ inkscape:transform-center-y="-3.2499984" />
+ <path
+ inkscape:transform-center-y="1.6729808e-005"
+ inkscape:transform-center-x="-3.2630798"
+ sodipodi:end="5.7595865"
+ sodipodi:start="4.712389"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+ d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 Z"
+ sodipodi:ry="8"
+ sodipodi:rx="8"
+ sodipodi:cy="118"
+ sodipodi:cx="132"
+ id="path36351-3-6"
+ style="fill:#ad2f94;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ sodipodi:type="arc"
+ transform="matrix(0.3484724,0.6035735,-0.603572,0.3484734,154.13836,102.27942)" />
+ <path
+ transform="matrix(-0.3484724,0.6035735,-0.603572,-0.3484733,246.13507,184.51913)"
+ sodipodi:type="arc"
+ style="fill:#0060f0;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path36353-9-8"
+ sodipodi:cx="132"
+ sodipodi:cy="118"
+ sodipodi:rx="8"
+ sodipodi:ry="8"
+ d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 Z"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ sodipodi:start="4.712389"
+ sodipodi:end="5.7595865"
+ inkscape:transform-center-x="-2.8145756"
+ inkscape:transform-center-y="3.2500173" />
+ <path
+ inkscape:transform-center-y="3.249994"
+ inkscape:transform-center-x="2.8145978"
+ sodipodi:end="5.7595865"
+ sodipodi:start="4.712389"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+ d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 Z"
+ sodipodi:ry="8"
+ sodipodi:rx="8"
+ sodipodi:cy="118"
+ sodipodi:cx="132"
+ id="path36355-6-4"
+ style="fill:#00d4aa;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ sodipodi:type="arc"
+ transform="matrix(-0.6969448,2.2484149e-8,-4.6257528e-8,-0.6969467,220.91956,305.31067)" />
+ <path
+ transform="matrix(-0.3484724,-0.6035734,0.603572,-0.3484734,103.69972,343.86251)"
+ sodipodi:type="arc"
+ style="fill:#ccff00;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path36357-5-2"
+ sodipodi:cx="132"
+ sodipodi:cy="118"
+ sodipodi:rx="8"
+ sodipodi:ry="8"
+ d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 Z"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ sodipodi:start="4.712389"
+ sodipodi:end="5.7595865"
+ inkscape:transform-center-x="3.2630773" />
+ <path
+ inkscape:transform-center-x="2.8145777"
+ sodipodi:end="5.7595865"
+ sodipodi:start="4.712389"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+ d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 Z"
+ sodipodi:ry="8"
+ sodipodi:rx="8"
+ sodipodi:cy="118"
+ sodipodi:cx="132"
+ id="path36359-0-5"
+ style="fill:#ffbf0e;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ sodipodi:type="arc"
+ transform="matrix(0.3484724,-0.6035734,0.603572,0.3484733,11.703006,261.6228)"
+ inkscape:transform-center-y="-3.2500006" />
+ </g>
+ <circle
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+ id="path36361-8-8"
+ style="fill:none;stroke:#000000;stroke-width:0.98948926;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ transform="matrix(0.8124999,0,0,0.8045157,241.75,163.13011)"
+ cx="132"
+ cy="118"
+ r="8" />
+ <circle
+ style="display:inline;opacity:0.3;fill:url(#radialGradient37501-3-6);fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path36363-2-9"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ transform="matrix(-0.7451143,-0.08386971,0.08492794,-0.7396793,437.33358,356.39712)"
+ cx="132"
+ cy="118"
+ r="8" />
+ <circle
+ transform="matrix(0.6860851,0,0,0.6874876,258.44808,176.87656)"
+ style="fill:none;stroke:url(#linearGradient17463);stroke-width:1.45605874;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path36365-2-9"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ cx="132"
+ cy="118"
+ r="8" />
+ </g>
+ </g>
+ <g
+ inkscape:transform-center-y="0.19622957"
+ inkscape:transform-center-x="-1.373607"
+ id="ICON_RESTRICT_SELECT_OFF-9"
+ style="display:inline;enable-background:new"
+ transform="matrix(0.45975513,-0.19653299,0.19653299,0.45975513,138.04837,311.70175)">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient17281);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001;marker:none;enable-background:accumulate"
+ d="m 367.75,440.75 1.75,-1.5 2.5,5.25 1.75,-1 -2.25,-5 2.5,0 -6.25,-6.25 z"
+ id="path45378-1-5-6-6"
+ sodipodi:nodetypes="cccccccc"
+ inkscape:connector-curvature="0" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect45374-0-5-6-1"
+ width="16"
+ height="16"
+ x="362"
+ y="430" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:0.89999998;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 367.5,431.5 7,7.25 -3,0 2.5,4.75 -1.75,1 -2.5,-5 -2.25,2.25 z"
+ id="path17835-7-5"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccc" />
+ <path
+ style="fill:none;stroke:#ffffff;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 368.34375,433.75 0,5.75"
+ id="path17845-9-6"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ </g>
+ </g>
+ <g
+ style="display:inline;filter:url(#filter17385);enable-background:new"
+ id="g17465-0"
+ transform="translate(41.727744,-106.93345)">
+ <g
+ transform="matrix(0.7,0,0,0.7,146.7,264.8)"
+ id="ICON_COLOR-1-9-4"
+ style="display:inline;enable-background:new">
+ <rect
+ y="238"
+ x="341"
+ height="16"
+ width="16"
+ id="rect36341-2-0-1"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#b3b3b3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate" />
+ <g
+ id="g36343-7-5-5"
+ transform="translate(0,-12)">
+ <g
+ transform="matrix(1.1658027,0,0,1.1657997,198.71028,-2.0560643)"
+ id="g36345-0-4-4">
+ <path
+ transform="matrix(0.6969448,0,0,0.6969467,36.918512,140.83126)"
+ sodipodi:type="arc"
+ style="fill:#ff6600;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path36349-4-2-6"
+ sodipodi:cx="132"
+ sodipodi:cy="118"
+ sodipodi:rx="8"
+ sodipodi:ry="8"
+ d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 Z"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ sodipodi:start="4.712389"
+ sodipodi:end="5.7595865"
+ inkscape:transform-center-x="-2.8145849"
+ inkscape:transform-center-y="-3.2499984" />
+ <path
+ inkscape:transform-center-y="1.6729808e-005"
+ inkscape:transform-center-x="-3.2630798"
+ sodipodi:end="5.7595865"
+ sodipodi:start="4.712389"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+ d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 Z"
+ sodipodi:ry="8"
+ sodipodi:rx="8"
+ sodipodi:cy="118"
+ sodipodi:cx="132"
+ id="path36351-3-6-5"
+ style="fill:#ad2f94;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ sodipodi:type="arc"
+ transform="matrix(0.3484724,0.6035735,-0.603572,0.3484734,154.13836,102.27942)" />
+ <path
+ transform="matrix(-0.3484724,0.6035735,-0.603572,-0.3484733,246.13507,184.51913)"
+ sodipodi:type="arc"
+ style="fill:#0060f0;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path36353-9-8-2"
+ sodipodi:cx="132"
+ sodipodi:cy="118"
+ sodipodi:rx="8"
+ sodipodi:ry="8"
+ d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 Z"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ sodipodi:start="4.712389"
+ sodipodi:end="5.7595865"
+ inkscape:transform-center-x="-2.8145756"
+ inkscape:transform-center-y="3.2500173" />
+ <path
+ inkscape:transform-center-y="3.249994"
+ inkscape:transform-center-x="2.8145978"
+ sodipodi:end="5.7595865"
+ sodipodi:start="4.712389"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+ d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 Z"
+ sodipodi:ry="8"
+ sodipodi:rx="8"
+ sodipodi:cy="118"
+ sodipodi:cx="132"
+ id="path36355-6-4-4"
+ style="fill:#00d4aa;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ sodipodi:type="arc"
+ transform="matrix(-0.6969448,2.2484149e-8,-4.6257528e-8,-0.6969467,220.91956,305.31067)" />
+ <path
+ transform="matrix(-0.3484724,-0.6035734,0.603572,-0.3484734,103.69972,343.86251)"
+ sodipodi:type="arc"
+ style="fill:#ccff00;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path36357-5-2-5"
+ sodipodi:cx="132"
+ sodipodi:cy="118"
+ sodipodi:rx="8"
+ sodipodi:ry="8"
+ d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 Z"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ sodipodi:start="4.712389"
+ sodipodi:end="5.7595865"
+ inkscape:transform-center-x="3.2630773" />
+ <path
+ inkscape:transform-center-x="2.8145777"
+ sodipodi:end="5.7595865"
+ sodipodi:start="4.712389"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+ d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 Z"
+ sodipodi:ry="8"
+ sodipodi:rx="8"
+ sodipodi:cy="118"
+ sodipodi:cx="132"
+ id="path36359-0-5-9"
+ style="fill:#ffbf0e;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ sodipodi:type="arc"
+ transform="matrix(0.3484724,-0.6035734,0.603572,0.3484733,11.703006,261.6228)"
+ inkscape:transform-center-y="-3.2500006" />
+ </g>
+ <circle
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+ id="path36361-8-8-0"
+ style="fill:none;stroke:#000000;stroke-width:0.98948926;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ transform="matrix(0.8124999,0,0,0.8045157,241.75,163.13011)"
+ cx="132"
+ cy="118"
+ r="8" />
+ <circle
+ style="display:inline;opacity:0.3;fill:url(#radialGradient37501-3-6-2);fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path36363-2-9-7"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ transform="matrix(-0.7451143,-0.08386971,0.08492794,-0.7396793,437.33358,356.39712)"
+ cx="132"
+ cy="118"
+ r="8" />
+ <circle
+ transform="matrix(0.6860851,0,0,0.6874876,258.44808,176.87656)"
+ style="fill:none;stroke:url(#linearGradient31452);stroke-width:1.45605874;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path36365-2-9-7"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ cx="132"
+ cy="118"
+ r="8" />
+ </g>
+ </g>
+ <g
+ inkscape:transform-center-y="0.19622957"
+ inkscape:transform-center-x="-1.373607"
+ id="ICON_RESTRICT_SELECT_OFF-9-8"
+ style="display:inline;enable-background:new"
+ transform="matrix(0.45975513,-0.19653299,0.19653299,0.45975513,138.04837,311.70175)">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient31454);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001;marker:none;enable-background:accumulate"
+ d="m 367.75,440.75 1.75,-1.5 2.5,5.25 1.75,-1 -2.25,-5 2.5,0 -6.25,-6.25 z"
+ id="path45378-1-5-6-6-9"
+ sodipodi:nodetypes="cccccccc"
+ inkscape:connector-curvature="0" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect45374-0-5-6-1-0"
+ width="16"
+ height="16"
+ x="362"
+ y="430" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:0.89999998;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 367.5,431.5 7,7.25 -3,0 2.5,4.75 -1.75,1 -2.5,-5 -2.25,2.25 z"
+ id="path17835-7-5-7"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccc" />
+ <path
+ style="fill:none;stroke:#ffffff;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 368.34375,433.75 0,5.75"
+ id="path17845-9-6-9"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ </g>
+ </g>
</g>
</g>
<g
@@ -91974,6 +90782,1880 @@
sodipodi:nodetypes="ccsccsc"
inkscape:connector-curvature="0" />
</g>
+ <rect
+ y="180.18372"
+ x="871.95667"
+ height="192"
+ width="192"
+ id="rect30285"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:5.39191818;marker:none;enable-background:accumulate" />
+ <g
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Pracowniaa\Moje dokumenty\Moje obrazy\BLENDER ICONS redesign\ver 2\IMAGE BROWSER ICONS.png"
+ transform="translate(859.95667,-201.81628)"
+ id="g21955"
+ style="display:inline;opacity:0.3;enable-background:new">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;enable-background:accumulate"
+ id="rect21957"
+ width="48"
+ height="48"
+ x="108"
+ y="430"
+ rx="2.4004419"
+ ry="0" />
+ <g
+ id="g21959">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path21961"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ style="display:inline;fill:url(#linearGradient21977);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccc"
+ id="path21963"
+ style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:connector-curvature="0"
+ style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)"
+ d="m 115,444 12,0 -1,-11 -11,11 z"
+ id="path21965"
+ sodipodi:nodetypes="cccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ clip-path="url(#clipPath13106-7)" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc"
+ id="path21967"
+ style="fill:none;stroke:url(#linearGradient21979);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 117.5,443.75 9,-2.5 0,-6"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ clip-path="none" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
+ style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ id="path21969"
+ sodipodi:nodetypes="cccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)"
+ d="m 116,443 11,1 -2,-10 -9,9 z"
+ id="path21971"
+ sodipodi:nodetypes="cccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ clip-path="url(#clipPath13106-7)" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path21973"
+ d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 147.5,435 0,38.5 -30.5,0"
+ style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ id="path21975"
+ sodipodi:nodetypes="ccc" />
+ </g>
+ </g>
+ <g
+ style="display:inline;enable-background:new"
+ transform="translate(3.9566736,0.18371585)"
+ id="g30335">
+ <g
+ id="g21367"
+ transform="translate(760,-202)">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path21369"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ style="display:inline;fill:url(#linearGradient30321);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccc"
+ id="path21371"
+ style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:connector-curvature="0"
+ style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)"
+ d="m 115,444 12,0 -1,-11 -11,11 z"
+ id="path21373"
+ sodipodi:nodetypes="cccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ clip-path="url(#clipPath13106-7)" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc"
+ id="path21375"
+ style="fill:none;stroke:url(#linearGradient30323);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 117.5,443.75 9,-2.5 0,-6"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ clip-path="none" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
+ style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ id="path21377"
+ sodipodi:nodetypes="cccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)"
+ d="m 116,443 11,1 -2,-10 -9,9 z"
+ id="path21569"
+ sodipodi:nodetypes="cccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ clip-path="url(#clipPath13106-7)" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path21379"
+ d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 147.5,435 0,38.5 -30.5,0"
+ style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ id="path21381"
+ sodipodi:nodetypes="ccc" />
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ style="font-style:normal;font-weight:normal;font-size:33.49144363px;font-family:'Bitstream Vera Sans';display:inline;fill:#214478;fill-opacity:1;stroke:none"
+ d="m 891.07148,245 -0.0715,9 2.39012,0 C 896,254 896,253 896.5,251 l 0.5,0 0,7 -0.5,0 c -0.5,-2 -0.5,-3 -3.10988,-3 L 891,255 l 0,7 c 0,2.5 1,3.25 3.14146,3.39973 l -0.004,0.60029 L 885,266 l 0.004,-0.60029 C 887,265.25 888,264.5 888.00001,262 L 888,248 c 0,-2.5 -1,-3.25 -3,-3.5 l 0,-0.5 16,0 0,5 -0.5,0 c -0.50001,-1.99999 -1.5,-4 -4.5,-4 l -4.92852,0 z"
+ id="text13209"
+ sodipodi:nodetypes="ccccccccccccccccccccccc" />
+ </g>
+ <g
+ style="display:inline;enable-background:new"
+ id="g21625"
+ transform="translate(907.95667,-153.81628)"
+ inkscape:export-filename="C:\Documents and Settings\Pracowniaa\Moje dokumenty\Moje obrazy\BLENDER ICONS redesign\ver 2\IMAGE BROWSER ICONS.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <rect
+ ry="0"
+ rx="2.4004419"
+ y="430"
+ x="108"
+ height="48"
+ width="48"
+ id="rect21627"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;enable-background:accumulate" />
+ <g
+ id="g21629">
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;fill:url(#linearGradient21647);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ id="path21631"
+ sodipodi:nodetypes="cccccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <g
+ style="display:inline;opacity:0.5;fill:#000000"
+ id="g16261"
+ transform="matrix(1.2499985,0,0,1,-87.6203,-147.85351)">
+ <rect
+ style="display:block;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect35099"
+ width="17.600004"
+ height="1"
+ x="167.69646"
+ y="598.85352"
+ rx="0.12125195"
+ ry="0.065390877" />
+ <rect
+ style="display:block;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect35101"
+ width="17.600004"
+ height="1"
+ x="167.69646"
+ y="600.85352"
+ rx="0.12125195"
+ ry="0.065390877" />
+ <rect
+ style="display:block;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect15690"
+ width="17.600004"
+ height="1"
+ x="167.69646"
+ y="602.85352"
+ rx="0.12125195"
+ ry="0.065390877" />
+ <rect
+ style="display:block;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect15692"
+ width="17.600004"
+ height="1"
+ x="167.69646"
+ y="604.85352"
+ rx="0.12125195"
+ ry="0.065390877" />
+ <rect
+ style="display:block;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect15694"
+ width="17.600004"
+ height="1"
+ x="167.69646"
+ y="606.85352"
+ rx="0.12125195"
+ ry="0.065390877" />
+ <rect
+ style="display:block;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect15696"
+ width="17.600004"
+ height="1"
+ x="167.69646"
+ y="608.85352"
+ rx="0.12125195"
+ ry="0.065390877" />
+ <rect
+ style="display:block;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect15698"
+ width="17.600004"
+ height="1"
+ x="167.69646"
+ y="610.85352"
+ rx="0.12125195"
+ ry="0.065390877" />
+ <rect
+ style="display:block;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect15700"
+ width="17.600004"
+ height="1"
+ x="167.69646"
+ y="612.85352"
+ rx="0.12125195"
+ ry="0.065390877" />
+ <rect
+ style="display:block;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect15732"
+ width="14.400002"
+ height="1"
+ x="167.69646"
+ y="614.85352"
+ rx="0.09920612"
+ ry="0.065390877" />
+ <g
+ transform="translate(150.89645,557.85352)"
+ id="g4849"
+ style="display:inline;fill:#000000">
+ <rect
+ ry="0.065390877"
+ rx="0.12125195"
+ y="29"
+ x="16.799992"
+ height="1"
+ width="17.600004"
+ id="rect15736"
+ style="display:block;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <rect
+ ry="0.065390877"
+ rx="0.12125195"
+ y="31"
+ x="16.799992"
+ height="1"
+ width="17.600004"
+ id="rect15738"
+ style="display:block;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <rect
+ ry="0.065390877"
+ rx="0.12125195"
+ y="33"
+ x="16.799992"
+ height="1"
+ width="17.600004"
+ id="rect15740"
+ style="display:block;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <rect
+ ry="0.065390877"
+ rx="0.12125195"
+ y="35"
+ x="16.799992"
+ height="1"
+ width="17.600004"
+ id="rect15742"
+ style="display:block;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <rect
+ ry="0.065390877"
+ rx="0.055114571"
+ y="37"
+ x="16.799992"
+ height="1"
+ width="8.0000095"
+ id="rect15744"
+ style="display:block;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ </g>
+ <rect
+ ry="0.065390304"
+ rx="0.0057410933"
+ y="617.85352"
+ x="184.49646"
+ height="0.99999124"
+ width="0.83333319"
+ id="rect16334"
+ style="display:block;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
+ style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ id="path21633"
+ sodipodi:nodetypes="cccc" />
+ <path
+ inkscape:connector-curvature="0"
+ clip-path="url(#clipPath13106-7)"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccc"
+ id="path21635"
+ d="m 115,444 12,0 -1,-11 -11,11 z"
+ style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)" />
+ <path
+ inkscape:connector-curvature="0"
+ clip-path="none"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 117.5,443.75 9,-2.5 0,-6"
+ style="fill:none;stroke:url(#linearGradient21649);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path21637"
+ sodipodi:nodetypes="ccc" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccc"
+ id="path21639"
+ style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:connector-curvature="0"
+ clip-path="url(#clipPath13106-7)"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccc"
+ id="path21641"
+ d="m 116,443 11,1 -2,-10 -9,9 z"
+ style="display:inline;opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
+ id="path21643"
+ sodipodi:nodetypes="cccccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <g
+ id="g35119"
+ transform="translate(2,-160.99999)"
+ style="display:inline">
+ <g
+ style="display:inline"
+ transform="translate(105.39645,589.71201)"
+ id="g16097">
+ <g
+ id="g16099"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-miterlimit:4"
+ transform="matrix(0.229703,0,0,0.229703,4.967081,4.244972)">
+ <radialGradient
+ id="radialGradient16101"
+ cx="20.892099"
+ cy="114.5684"
+ r="5.256"
+ fx="20.892099"
+ fy="114.5684"
+ gradientUnits="userSpaceOnUse">
+ <stop
+ offset="0"
+ style="stop-color:#F0F0F0"
+ id="stop16103" />
+ <stop
+ offset="1"
+ style="stop-color:#474747"
+ id="stop16105" />
+ </radialGradient>
+ <radialGradient
+ id="radialGradient16109"
+ cx="20.892099"
+ cy="64.567902"
+ r="5.257"
+ fx="20.892099"
+ fy="64.567902"
+ gradientUnits="userSpaceOnUse">
+ <stop
+ offset="0"
+ style="stop-color:#F0F0F0"
+ id="stop16111" />
+ <stop
+ offset="1"
+ style="stop-color:#474747"
+ id="stop16113" />
+ </radialGradient>
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 12.85355,31.53813 c 0,0.552274 -0.447803,0.99986 -1,0.99986 -0.552477,0 -1,-0.447865 -1,-0.99986 0,-0.552554 0.447803,-1.00014 1,-1.00014 0.552197,0 1,0.447866 1,1.00014 l 0,0 0,0 0,0 z"
+ id="path16107" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:url(#radialGradient21565);fill-rule:nonzero;stroke:none"
+ d="m 12.60355,31.288131 c 0,0.552274 -0.447803,0.999859 -1,0.999859 -0.552477,0 -1,-0.447865 -1,-0.999859 0,-0.552556 0.447803,-1.000141 1,-1.000141 0.552197,0 1,0.447866 1,1.000141 z"
+ id="path16117" />
+ </g>
+ <g
+ id="g16131"
+ transform="translate(105.39645,579.71201)"
+ style="display:inline">
+ <g
+ transform="matrix(0.229703,0,0,0.229703,4.967081,4.244972)"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-miterlimit:4"
+ id="g16133">
+ <radialGradient
+ gradientUnits="userSpaceOnUse"
+ fy="114.5684"
+ fx="20.892099"
+ r="5.256"
+ cy="114.5684"
+ cx="20.892099"
+ id="radialGradient16135">
+ <stop
+ id="stop16137"
+ style="stop-color:#F0F0F0"
+ offset="0" />
+ <stop
+ id="stop16140"
+ style="stop-color:#474747"
+ offset="1" />
+ </radialGradient>
+ <radialGradient
+ gradientUnits="userSpaceOnUse"
+ fy="64.567902"
+ fx="20.892099"
+ r="5.257"
+ cy="64.567902"
+ cx="20.892099"
+ id="radialGradient16142">
+ <stop
+ id="stop16144"
+ style="stop-color:#F0F0F0"
+ offset="0" />
+ <stop
+ id="stop16146"
+ style="stop-color:#474747"
+ offset="1" />
+ </radialGradient>
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ id="path35139"
+ d="m 12.85355,31.53813 c 0,0.552274 -0.447803,0.99986 -1,0.99986 -0.552477,0 -1,-0.447865 -1,-0.99986 0,-0.552554 0.447803,-1.00014 1,-1.00014 0.552197,0 1,0.447866 1,1.00014 l 0,0 0,0 0,0 z"
+ style="display:inline;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path35141"
+ d="m 12.60355,31.288131 c 0,0.552274 -0.447803,0.999859 -1,0.999859 -0.552477,0 -1,-0.447865 -1,-0.999859 0,-0.552556 0.447803,-1.000141 1,-1.000141 0.552197,0 1,0.447866 1,1.000141 z"
+ style="fill:url(#radialGradient21567);fill-rule:nonzero;stroke:none" />
+ </g>
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc"
+ id="path21645"
+ style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 147.5,435 0,38.5 -30.5,0"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ </g>
+ </g>
+ <g
+ style="display:inline;enable-background:new"
+ id="g21572"
+ transform="translate(811.95667,-201.81628)"
+ inkscape:export-filename="C:\Documents and Settings\Pracowniaa\Moje dokumenty\Moje obrazy\BLENDER ICONS redesign\ver 2\IMAGE BROWSER ICONS.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <rect
+ ry="0"
+ rx="2.4004419"
+ y="430"
+ x="108"
+ height="48"
+ width="48"
+ id="rect21574"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;enable-background:accumulate" />
+ <g
+ id="g21576">
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;fill:url(#linearGradient21594);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ id="path21578"
+ sodipodi:nodetypes="cccccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
+ style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ id="path21580"
+ sodipodi:nodetypes="cccc" />
+ <path
+ inkscape:connector-curvature="0"
+ clip-path="url(#clipPath13106-7)"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccc"
+ id="path21582"
+ d="m 115,444 12,0 -1,-11 -11,11 z"
+ style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)" />
+ <path
+ inkscape:connector-curvature="0"
+ clip-path="none"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 117.5,443.75 9,-2.5 0,-6"
+ style="fill:none;stroke:url(#linearGradient21596);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path21584"
+ sodipodi:nodetypes="ccc" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccc"
+ id="path21586"
+ style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:connector-curvature="0"
+ clip-path="url(#clipPath13106-7)"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccc"
+ id="path21588"
+ d="m 116,443 11,1 -2,-10 -9,9 z"
+ style="display:inline;opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
+ id="path21590"
+ sodipodi:nodetypes="cccccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc"
+ id="path21592"
+ style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 147.5,435 0,38.5 -30.5,0"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ </g>
+ </g>
+ <g
+ style="display:inline;enable-background:new"
+ transform="translate(3.9566736,0.18371585)"
+ id="g30382">
+ <g
+ id="g23655"
+ transform="translate(760,-154)">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path23657"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ style="display:inline;fill:url(#linearGradient30368);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccc"
+ id="path23659"
+ style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:connector-curvature="0"
+ style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)"
+ d="m 115,444 12,0 -1,-11 -11,11 z"
+ id="path23661"
+ sodipodi:nodetypes="cccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ clip-path="url(#clipPath13106-7)" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc"
+ id="path23663"
+ style="fill:none;stroke:url(#linearGradient30370);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 117.5,443.75 9,-2.5 0,-6"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ clip-path="none" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
+ style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ id="path23665"
+ sodipodi:nodetypes="cccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)"
+ d="m 116,443 11,1 -2,-10 -9,9 z"
+ id="path23667"
+ sodipodi:nodetypes="cccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ clip-path="url(#clipPath13106-7)" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path23669"
+ d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 147.5,435 0,38.5 -30.5,0"
+ style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ id="path23671"
+ sodipodi:nodetypes="ccc" />
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#112b00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;enable-background:accumulate"
+ d="m 888,295 1,0 0,14 -1,0 0,-14 z"
+ id="path23675"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path23677"
+ d="m 900,294 1.00002,-1 0,14 -1.00002,0 0,-13 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#112b00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;enable-background:accumulate"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc"
+ id="path23679"
+ d="m 901.00003,292 0,2.25 -13.00002,2 0,-2.25 13.00002,-2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#112b00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;enable-background:accumulate" />
+ <g
+ id="g23681"
+ transform="matrix(1.1428564,0,0,1.2000001,822.71436,-355.40005)">
+ <ellipse
+ ry="2.25"
+ rx="4.5"
+ cy="554"
+ cx="53"
+ transform="matrix(0.7630859,-0.2494396,0.2996015,0.9926766,-151.92281,17.77746)"
+ id="path23683"
+ style="display:inline;overflow:visible;visibility:visible;fill:#112b00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;enable-background:accumulate" />
+ <ellipse
+ ry="2.25"
+ rx="4.5"
+ cy="554"
+ cx="53"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;filter:url(#filter20578-5);enable-background:accumulate"
+ id="path23685"
+ transform="matrix(0.3848865,-0.1700959,0.2278131,0.3626733,-93.107467,361.59408)"
+ inkscape:transform-center-y="0.3813435"
+ clip-path="url(#clipPath20586-3)" />
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.38999999;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;enable-background:accumulate"
+ d="m 901.00003,292 -1e-5,1 -13.00002,2 10e-6,-1 13.00002,-2 z"
+ id="path23694"
+ sodipodi:nodetypes="ccccc" />
+ <g
+ transform="matrix(1.1428564,0,0,1.2000001,834.71436,-357.40005)"
+ id="g23717">
+ <ellipse
+ ry="2.25"
+ rx="4.5"
+ cy="554"
+ cx="53"
+ style="display:inline;overflow:visible;visibility:visible;fill:#112b00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;enable-background:accumulate"
+ id="path23724"
+ transform="matrix(0.7630859,-0.2494396,0.2996015,0.9926766,-151.92281,17.77746)" />
+ <ellipse
+ ry="2.25"
+ rx="4.5"
+ cy="554"
+ cx="53"
+ clip-path="url(#clipPath20586-3)"
+ inkscape:transform-center-y="0.3813435"
+ transform="matrix(0.3848865,-0.1700959,0.2278131,0.3626733,-93.107467,361.59408)"
+ id="path23726"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;filter:url(#filter20578-5);enable-background:accumulate" />
+ </g>
+ </g>
+ <g
+ id="g23922"
+ transform="translate(-12.043326,-219.81628)"
+ style="display:inline;enable-background:new">
+ <g
+ style="display:inline"
+ id="g23924"
+ transform="translate(824,66)"
+ inkscape:export-filename="C:\Documents and Settings\Pracowniaa\Moje dokumenty\Moje obrazy\BLENDER ICONS redesign\ver 2\IMAGE BROWSER ICONS.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <rect
+ ry="0"
+ rx="2.4004419"
+ y="430"
+ x="108"
+ height="48"
+ width="48"
+ id="rect23926"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;enable-background:accumulate" />
+ <g
+ id="g23928">
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;fill:url(#linearGradient23978);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ id="path23930"
+ sodipodi:nodetypes="cccccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
+ style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ id="path23932"
+ sodipodi:nodetypes="cccc" />
+ <path
+ inkscape:connector-curvature="0"
+ clip-path="url(#clipPath13106-7)"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccc"
+ id="path23934"
+ d="m 115,444 12,0 -1,-11 -11,11 z"
+ style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)" />
+ <path
+ inkscape:connector-curvature="0"
+ clip-path="none"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 117.5,443.75 9,-2.5 0,-6"
+ style="fill:none;stroke:url(#linearGradient23980);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path23936"
+ sodipodi:nodetypes="ccc" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccc"
+ id="path23938"
+ style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:connector-curvature="0"
+ clip-path="url(#clipPath13106-7)"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccc"
+ id="path23940"
+ d="m 116,443 11,1 -2,-10 -9,9 z"
+ style="display:inline;opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
+ id="path23942"
+ sodipodi:nodetypes="cccccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc"
+ id="path23944"
+ style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 147.5,435 0,38.5 -30.5,0"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ </g>
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccc"
+ id="path23946"
+ d="m 952,530 0,10 1,0 1,0 11,0 1,0 1,0 0,-10 -15,0 z m 1,2 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z m -12,3 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z m -12,3 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z"
+ style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" />
+ <rect
+ transform="scale(1,-1)"
+ style="fill:url(#linearGradient23982);fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="rect23948"
+ width="13"
+ height="5.5"
+ x="953"
+ y="-524" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path23952"
+ transform="translate(76,0)"
+ d="m 876,514 0,17 15,0 0,-17 -1,0 0,1 -1,0 0,-1 -11,0 0,1 -1,0 0,-1 -1,0 z m 1,3 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z m -12,3 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z m -12,3 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z m -12,3 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z m -12,3 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z"
+ style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccc"
+ style="fill:url(#linearGradient23986);fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 952,507 3,0 0,3 9,0 0,-3 3,0 0,7 -15,0 0,-7 z m 1,0 1,0 -1,0 z m 0,1 0,1 1,0 0,-1 -1,0 z m 0,3 0,1 1,0 0,-1 -1,0 z m 12,-4 1,0 -1,0 z m 0,1 0,1 1,0 0,-1 -1,0 z m 0,3 0,1 1,0 0,-1 -1,0 z"
+ id="path23954" />
+ <rect
+ transform="matrix(0,1,1,0,0,0)"
+ ry="0"
+ y="955"
+ x="507"
+ height="9"
+ width="3"
+ id="rect23956"
+ style="fill:url(#linearGradient23988);fill-opacity:1;fill-rule:nonzero;stroke:none" />
+ <rect
+ style="fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="rect23958"
+ width="9"
+ height="9"
+ x="512"
+ y="955"
+ ry="0"
+ transform="matrix(0,1,1,0,0,0)" />
+ <rect
+ transform="matrix(0,1,1,0,0,0)"
+ ry="0"
+ y="955"
+ x="523"
+ height="9"
+ width="9"
+ id="rect23960"
+ style="fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none" />
+ <circle
+ r="8"
+ cy="118"
+ cx="132"
+ transform="matrix(0,-0.5624971,0.5624971,0,893.12531,590.74965)"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path23962"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <circle
+ r="8"
+ cy="118"
+ cx="132"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+ id="path23964"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ transform="matrix(0,-0.5624964,0.5624964,0,893.12545,601.74956)" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccc"
+ id="path23966"
+ d="m 961.00001,519.00005 -3,0 0,-0.99992 0.99994,0 6e-5,-2.00008 -1,0 0,-1 1,0 0,-1 1.00006,0 0,4.00008 0.99994,0 0,0.99992 z" />
+ <path
+ inkscape:connector-curvature="0"
+ d="m 958,525 0,1 2,0 0,-1 -2,0 z m 2,1 0,1 1,0 0,-1 -1,0 z m 0,1 -1,0 0,1 1,0 0,-1 z m -1,1 -1,0 0,1 0,1 3,0 0,-1 -2,0 0,-1 z"
+ id="path23968" />
+ <rect
+ style="fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="rect23970"
+ width="6"
+ height="9"
+ x="534"
+ y="955"
+ ry="0"
+ transform="matrix(0,1,1,0,0,0)" />
+ <g
+ clip-path="url(#clipPath23877-4)"
+ id="g23972">
+ <circle
+ r="8"
+ cy="118"
+ cx="132"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+ id="path23974"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ transform="matrix(0,-0.5624964,0.5624964,0,893.12545,612.74956)" />
+ <path
+ inkscape:connector-curvature="0"
+ d="m 958,536 0,1 2,0 0,-1 -2,0 z m 2,1 0,1 1,0 0,-1 -1,0 z m 0,1 -1,0 0,1 1,0 0,-1 z m 0,1 0,1 1,0 0,-1 -1,0 z m 0,1 -2,0 0,1 2,0 0,-1 z"
+ id="path23976" />
+ </g>
+ </g>
+ <g
+ transform="translate(211.95667,88.183716)"
+ id="g45475"
+ style="display:inline;enable-background:new">
+ <g
+ style="display:inline"
+ id="g22242"
+ transform="translate(696,-194)"
+ inkscape:export-filename="C:\Documents and Settings\Pracowniaa\Moje dokumenty\Moje obrazy\BLENDER ICONS redesign\ver 2\IMAGE BROWSER ICONS.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <rect
+ ry="0"
+ rx="2.4004419"
+ y="430"
+ x="108"
+ height="48"
+ width="48"
+ id="rect22244"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;enable-background:accumulate" />
+ <g
+ id="g22246">
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;fill:url(#linearGradient22274);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ id="path22249"
+ sodipodi:nodetypes="cccccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
+ style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ id="path22251"
+ sodipodi:nodetypes="cccc" />
+ <path
+ inkscape:connector-curvature="0"
+ clip-path="url(#clipPath13106-7)"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccc"
+ id="path22253"
+ d="m 115,444 12,0 -1,-11 -11,11 z"
+ style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)" />
+ <path
+ inkscape:connector-curvature="0"
+ clip-path="none"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 117.5,443.75 9,-2.5 0,-6"
+ style="fill:none;stroke:url(#linearGradient22276);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path22264"
+ sodipodi:nodetypes="ccc" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccc"
+ id="path22266"
+ style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:connector-curvature="0"
+ clip-path="url(#clipPath13106-7)"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccc"
+ id="path22268"
+ d="m 116,443 11,1 -2,-10 -9,9 z"
+ style="display:inline;opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
+ id="path22270"
+ sodipodi:nodetypes="cccccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc"
+ id="path22272"
+ style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 147.5,435 0,38.5 -30.5,0"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ </g>
+ </g>
+ <g
+ id="g21517"
+ inkscape:label="Layer 1"
+ transform="matrix(0.5406242,0,0,0.5829534,814.13667,247.65542)">
+ <ellipse
+ ry="5.3033009"
+ rx="15.467961"
+ cy="38.98439"
+ cx="28.019106"
+ transform="matrix(1.274286,0,0,1.377124,-7.569123,-16.70193)"
+ id="path35486"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.54857142;fill:url(#radialGradient21442);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="csssssssssscccsscccscccssccc"
+ d="m 16.048489,28.093447 c 0.0098,0.576682 0.196474,1.697902 0.471116,2.577425 0.581566,1.854137 1.56684,3.572658 2.939126,5.086496 1.407488,1.553118 3.138519,2.803227 5.139315,3.68976 2.105357,0.931573 4.384795,1.407488 6.750134,1.403741 2.365339,-0.005 4.644601,-0.488686 6.74896,-1.427017 2.00002,-0.895288 3.731043,-2.148391 5.13754,-3.705517 1.369207,-1.519844 2.352576,-3.241114 2.934089,-5.096258 0.294262,-0.938353 0.476921,-1.889392 0.553238,-2.845308 0.07331,-0.939306 0.04204,-1.883511 -0.09183,-2.823792 -0.259981,-1.835599 -0.896294,-3.556847 -1.872652,-5.12758 -0.895541,-1.441699 -2.047808,-2.70454 -3.417268,-3.766975 0,0 0.002,-0.002 0.002,-0.002 0,0 -13.828458,-10.6197195 -13.828458,-10.6197195 -0.01176,-0.00978 -0.02252,-0.019551 -0.03529,-0.028344 -0.909003,-0.6959264 -3.879837,-0.7738945 -4.87679,-0.075035 -1.01067,0.7057021 -1.091821,1.8092613 -0.195527,2.5482146 1.899775,1.4997633 2.656207,2.2801589 4.566507,3.7797379 0,0 -14.852491,0.167033 -14.852491,0.167033 -1.994685,0 -3.1682609,0.947915 -3.4153947,2.333683 -0.2180771,1.222836 0.7479213,2.738129 2.4800217,2.738129 2.956573,0.0039 5.942111,-0.0069 8.909215,-0.01272 0,0 -16.01999,12.453223 -16.01999,12.453223 -0.020527,0.01564 -0.041053,0.02933 -0.06158,0.04497 -1.4974197,1.148389 -1.9831951,3.059322 -1.0399808,4.268393 0.9598323,1.22959 2.9977653,1.230588 4.5147288,0.006 0,0 8.677593,-7.102098 8.677593,-7.102098 0,0 -0.12511,0.959824 -0.116333,1.535532 l 1e-6,2.6e-5 0,0 0,0 z"
+ id="path2482"
+ style="fill:#f57900;fill-rule:evenodd;stroke:#aa4400;stroke-width:1.7812928;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none" />
+ <ellipse
+ ry="10.125"
+ rx="11.5625"
+ cy="25.75"
+ cx="31.1875"
+ transform="matrix(0.8018194,0,0,0.8471126,6.257567,4.5089892)"
+ id="path39153"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient21444);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ style="opacity:0.4857143;fill:none;stroke:url(#linearGradient21446);stroke-width:1.7812928;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1"
+ d="m 25.8125,6.40625 c -0.334829,4.572e-4 -0.72202,0.089606 -0.90625,0.21875 4.5e-4,0.010412 4.5e-4,0.020838 0,0.03125 -0.212626,0.1484635 -0.188235,0.1956271 -0.1875,0.1875 0.0092,0.010621 -0.0072,-4.246e-4 0.03125,0.03125 0.01962,0.00828 0.03527,0.012546 0.0625,0.03125 0.01676,0.01151 0.01357,0.014555 0.03125,0.03125 0.193748,0.1576058 4.954976,4.005164 4.954976,4.005164 0.489837,0.39864 0.677395,1.066352 0.46875,1.65625 -0.115662,0.32703 -0.422813,0.541217 -0.6875,0.59375 -0.264687,0.05253 -0.498447,0.03054 -0.71875,0.03125 -5.639658,0.05119 -16.87989,0.03851 -16.87989,0.03851 -0.4102,2.75e-4 -0.935835,0.115997 -1.34375,0.34375 -0.407915,0.227753 -0.6637862,0.523861 -0.6875002,0.90625 -0.024417,0.393728 0.098829,0.605767 0.3437502,0.78125 0.244921,0.175483 0.614978,0.25 0.875,0.25 0,0 8.8125,0 8.8125,0 0.600305,-7.28e-4 1.223895,0.311058 1.4375,0.9375 0.04676,0.137121 0.06335,0.269976 0.0625,0.40625 -8.49e-4,0.136274 -0.02214,0.268794 -0.09375,0.375 -0.143211,0.212412 -0.319507,0.298568 -0.5,0.4375 0,0 -15.7871819,12.746851 -15.856336,12.800078 C 5.0310984,30.500117 5,30.53125 5,30.53125 5.0100745,30.519077 5.000335,30.499512 5,30.5 L 4.8125,30.3125 c 0.012336,0.02165 0.014481,0.03307 0.03125,0.0625 0.063558,0.0774 0.125,0.15625 0.125,0.15625 -0.00585,0.0056 -0.031233,0.03124 -0.03125,0.03125 0,0 -0.043442,-0.09921 -0.09375,-0.1875 0.037843,0.09884 0.06253,0.218739 0.0625,0.21875 -0.4662091,0.37119 -0.7783348,0.889746 -0.875,1.28125 -0.1043319,0.422581 -0.046,0.62455 0.125,0.84375 0.2999827,0.384295 1.3975356,0.595547 2.40625,-0.21875 0,0 8.65625,-7.09375 8.65625,-7.09375 0.473718,-0.387074 1.1446,-0.458625 1.6875,-0.15625 0.544608,0.303331 0.798054,0.927572 0.71875,1.53125 0,0 -0.0626,0.908319 -0.0625,1.25 2e-6,0.0085 -1.19e-4,0.02348 0,0.03125 0.192796,2.523718 1.400736,4.762818 3.03125,6.71875 2.801818,3.089095 6.627659,4.401619 10.75,4.5625 4.113324,-0.043 7.964529,-1.606111 10.75,-4.625 2.546631,-3.125326 3.513872,-6.363859 3.15625,-9.375 C 44.891575,22.325847 43.222923,19.516566 40.4375,17.25 35.951885,13.599946 31.206991,10.168434 26.59375,6.625 26.57515,6.610386 26.56455,6.59802 26.5625,6.59375 26.43835,6.498703 26.144223,6.4057899 25.8125,6.40625 Z"
+ id="path21414"
+ sodipodi:nodetypes="csssssscssscsssccssscscccsccssssccscsscccssssc" />
+ <path
+ inkscape:connector-curvature="0"
+ d="m 25.708956,26.064593 c 0.07649,-1.397943 0.759369,-2.631914 1.78592,-3.505519 1.010226,-0.858782 2.366788,-1.383145 3.848625,-1.383145 1.480894,0 2.837456,0.524363 3.847446,1.383145 1.027685,0.873605 1.709741,2.106651 1.787122,3.504594 0.07927,1.438713 -0.49591,2.77459 -1.504012,3.764001 -1.027686,1.007933 -2.493008,1.640678 -4.130556,1.640678 -1.63849,0 -3.103814,-0.632745 -4.131451,-1.640678 -1.00914,-0.989411 -1.58234,-2.325288 -1.503094,-3.763076 l 0,0 0,0 0,0 z"
+ id="path2478"
+ style="fill:#3465a4;fill-rule:evenodd;stroke:none" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="csssscsccsscsccssssscsscccsssc"
+ id="path39166"
+ d="m 25.8125,6.03125 c -0.404852,5.53e-4 -2.204797,-0.059029 -2.48145,0.1349032 -0.280209,0.195652 -0.335403,0.376484 -0.34375,0.46875 -0.0083,0.092266 -0.01539,0.17648 0.1875,0.34375 0.01899,0.015735 0.04457,0.014317 0.0625,0.03125 0.124258,0.101028 4.748869,4.1248618 4.748869,4.1248618 0.373658,0.304091 0.504393,0.795817 0.34375,1.25 -0.160635,0.454191 -0.580748,0.373449 -1.0625,0.375 -5.634142,0.05114 -15.087371,-0.129601 -15.087371,-0.129601 -0.952967,6.38e-4 -2.339958,0.524782 -2.4062504,1.59375 -0.063562,1.024947 0.9247974,1.4375 1.5937504,1.4375 0,-1e-6 8.8125,0 8.8125,0 0.488364,-5.92e-4 0.936141,0.225277 1.09375,0.6875 0.157609,0.462231 -0.01926,0.514621 -0.40625,0.8125 0,0 -16.086298,13.088586 -16.086298,13.088586 -0.00142,0.0014 -0.029829,-0.0014 -0.03125,0 -0.064037,0.04879 -0.054226,0.04875 -0.03125,0.03125 -0.5536758,0.424619 -0.9087886,1.004019 -1.03125,1.5 -0.1224536,0.495981 -0.04661,0.856152 0.1875,1.15625 0.4788333,0.613413 1.777612,0.754857 2.90625,-0.15625 1e-7,10e-7 8.65625,-7.09375 8.65625,-7.09375 0.361955,-0.295753 0.872897,-0.352437 1.28125,-0.125 0.408345,0.227436 0.623381,0.692814 0.5625,1.15625 0,-1e-6 -0.0997,0.953636 -0.09375,1.34375 0.09498,1.301756 0.451616,2.521825 0.989039,3.664234 C 20.799917,36.321089 27.770982,19.392853 44.1875,21.03125 43.339652,19.54368 42.151282,18.185293 40.65625,16.96875 36.159865,13.309932 31.42016,9.882897 26.8125,6.34375 26.805335,6.338858 26.788292,6.317553 26.78125,6.3125 26.570707,6.151312 26.216591,6.030689 25.8125,6.03125 Z"
+ style="opacity:0.51999996;fill:url(#radialGradient21448);fill-opacity:1;fill-rule:evenodd;stroke:none" />
+ </g>
+ </g>
+ <g
+ transform="translate(-0.04332638,0.18371585)"
+ style="display:inline;enable-background:new"
+ id="g6090">
+ <g
+ id="g24784"
+ transform="translate(116,247.5)"
+ style="opacity:0.5">
+ <path
+ sodipodi:nodetypes="ccccccssssccc"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient24809);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="path24789"
+ d="m 806.5,114.5 c 0,2.25 2,4 4,4 l 30,0 c 0.4163,0 1,-0.5 1,-1 l 0,-29 c 0,-0.5 -0.5,-1 -1,-1 l -21.02773,0.04419 C 818.98721,87.545209 818.5,87 818.5,86.5 l 0,-3 c 0,-0.5 -0.5,-1 -1,-1 l -10,0 c -0.5,0 -1,0.5 -1,1 l 0,31 z"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24791"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.07999998;fill:url(#linearGradient24811);fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+ d="m 807.5,89.5 33,0 m -33,12 33,0 m -33,-4 33,0 m -33,-6 33,0 m -33,20 33,0 m -33,2 33,0 m -33,-18 33,0 m -33,-2 33,0 m -20,-6 -13,0 m 0,20 33,0 m -33,-2 33,0 m -33,-2 33,0 m -33,-4 33,0 m -33,10 33,0 m -33,6 33,0"
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccc"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:export-ydpi="74.800003"
+ inkscape:export-xdpi="74.800003"
+ inkscape:export-filename="/home/jimmac/ximian_art/icons/nautilus/suse93/gnome-fs-directory.png"
+ sodipodi:nodetypes="csccsczc"
+ id="path24793"
+ d="m 844,118.5 c 3.5,0 5.5,-2 5.5,-5.5 l 0,-18.5 c -11.75604,-1.11e-4 -23.91623,0 -35.5,0 l 0,19.5 c 0,4.5 -7,4 -7,0.25 0,2 2.00002,3.73529 3,3.75 l 34,0.5 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient24813);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ d="m 807,87 12,0 0.0385,-3.33333 C 819.04423,83.166705 818.97512,83 818.5,83 l -10.92308,0 c -0.47512,0 -0.53846,0.16667 -0.53846,0.66667 L 807,87 Z"
+ id="path24796"
+ style="opacity:0.7;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ sodipodi:nodetypes="ccssccc"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="cc"
+ d="m 840.5,89 0,4.5"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.1;fill:none;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+ id="path24799"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24801"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.1;fill:none;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+ d="m 848.5,95.5 0,18 c 0,1.25 0.25,3 -1.25,4"
+ sodipodi:nodetypes="ccc"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="cccccccsc"
+ d="m 818.5,83.5 -11,0 0,30 c 0,5 7,5 7,0 l 0,-18 34,0 m -29,-8 c 0,0.5 0.5286,1 1,1 l 20,0"
+ style="display:inline;opacity:0.75;fill:none;stroke:#ffffff;stroke-width:1.29999995;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path24803"
+ inkscape:connector-curvature="0" />
+ <path
+ d="m 806.5,113.5 c 0,2.75 2,5 5,5 l 33,0 c 3,0 5,-2 5,-5 l 0,-18 c 0,-0.471405 -0.5286,-1 -1,-1 l -7,0 0,-6 c 0,-0.5 -0.5,-1 -1,-1 l -20.02773,0.04419 C 819.98721,87.54526 819.5,87 819.5,86.5 l 0,-3 c 0,-0.5 -0.5,-1 -1,-1 l -11,0 c -0.5,0 -1,0.5 -1,1 l 0,30 z"
+ id="path24805"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ sodipodi:nodetypes="ccccsscccssssccc"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;stroke:url(#linearGradient24815);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 841.5,94.5 -27,0 c -0.4714,0 -1,0.528595 -1,1 l 0,18 c 0,2.25 -1.25,3 -2.5,3"
+ id="path24807"
+ sodipodi:nodetypes="csscc"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;filter:url(#filter6078);enable-background:new"
+ id="g44334"
+ transform="translate(619,272.5)">
+ <rect
+ y="73"
+ x="320"
+ height="16"
+ width="16"
+ id="rect44336"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#1a1a1a;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.20000005;marker:none;enable-background:accumulate" />
+ <g
+ id="g44338"
+ transform="translate(0,-21)">
+ <g
+ id="g44340">
+ <g
+ id="g44342"
+ transform="translate(0,21)">
+ <path
+ style="fill:none;stroke:#000000;stroke-width:3.4000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 333.25,87 -5.25,0 -1,-1 0,-10"
+ id="path44344"
+ sodipodi:nodetypes="cccc"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:3.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 331.25,79.25 327,75.005631 322.75,79.25"
+ id="path44346"
+ sodipodi:nodetypes="ccc"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g44348"
+ transform="translate(0,21)">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path44350"
+ d="m 333.25,87 -5.25,0 -1,-1 0,-10"
+ style="fill:none;stroke:#e6e6e6;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="ccc"
+ id="path44352"
+ d="M 331.25,79.25 327,75.005631 322.75,79.25"
+ style="fill:none;stroke:#e6e6e6;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <path
+ sodipodi:nodetypes="cccccc"
+ id="path44354"
+ d="m 328.5,107.5 5,0 m -7,-9 0,8.5 m -4.25,-7 4.5,-4.5"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ </g>
+ <g
+ transform="translate(67.956674,247.68372)"
+ id="g24818"
+ style="display:inline;enable-background:new">
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccssssccc"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient24839);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="path24821"
+ d="m 806.5,114.5 c 0,2.25 2,4 4,4 l 30,0 c 0.4163,0 1,-0.5 1,-1 l 0,-29 c 0,-0.5 -0.5,-1 -1,-1 l -21.02773,0.04419 C 818.98721,87.545209 818.5,87 818.5,86.5 l 0,-3 c 0,-0.5 -0.5,-1 -1,-1 l -10,0 c -0.5,0 -1,0.5 -1,1 l 0,31 z" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path24823"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.07999998;fill:url(#linearGradient24841);fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+ d="m 807.5,89.5 33,0 m -33,12 33,0 m -33,-4 33,0 m -33,-6 33,0 m -33,20 33,0 m -33,2 33,0 m -33,-18 33,0 m -33,-2 33,0 m -20,-6 -13,0 m 0,20 33,0 m -33,-2 33,0 m -33,-2 33,0 m -33,-4 33,0 m -33,10 33,0 m -33,6 33,0"
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="74.800003"
+ inkscape:export-xdpi="74.800003"
+ inkscape:export-filename="/home/jimmac/ximian_art/icons/nautilus/suse93/gnome-fs-directory.png"
+ sodipodi:nodetypes="csccsczc"
+ id="path24825"
+ d="m 844,118.5 c 3.5,0 5.5,-2 5.5,-5.5 l 0,-16 c -11.75604,-1.11e-4 -23.91623,0 -35.5,0 l 0,17 c 0,4.5 -7,4 -7,0.25 0,2 2.00002,3.73529 3,3.75 l 34,0.5 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient24843);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ d="m 807,87 12,0 0.0385,-3.33333 C 819.04423,83.166705 818.97512,83 818.5,83 l -10.92308,0 c -0.47512,0 -0.53846,0.16667 -0.53846,0.66667 L 807,87 Z"
+ id="path24827"
+ style="opacity:0.7;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ sodipodi:nodetypes="ccssccc" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc"
+ d="m 840.5,89 0,7.5"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.1;fill:none;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+ id="path24829" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path24831"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.1;fill:none;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+ d="m 848.5,98.75 0,14.75 c 0,1.25 0.25,3 -1.25,4"
+ sodipodi:nodetypes="ccc" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccsc"
+ d="m 818.5,83.5 -11,0 0,30 c 0,5 7,5 7,0 l 0,-16 34,0 m -29,-10 c 0,0.5 0.5286,1 1,1 l 20,0"
+ style="display:inline;opacity:0.75;fill:none;stroke:#ffffff;stroke-width:1.29999995;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path24833" />
+ <path
+ inkscape:connector-curvature="0"
+ d="m 806.5,113.5 c 0,2.75 2,5 5,5 l 33,0 c 3,0 5,-2 5,-5 l 0,-16 c 0,-0.471405 -0.5286,-1 -1,-1 l -7,0 0,-8 c 0,-0.5 -0.5,-1 -1,-1 l -20.02773,0.04419 C 819.98721,87.54526 819.5,87 819.5,86.5 l 0,-3 c 0,-0.5 -0.5,-1 -1,-1 l -11,0 c -0.5,0 -1,0.5 -1,1 l 0,30 z"
+ id="path24835"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ sodipodi:nodetypes="ccccsscccssssccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:none;stroke:url(#linearGradient24845);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 841.5,96.500004 -27,0 c -0.4714,0 -1,0.528595 -1,1 l 0,15.999996 c 0,2.25 -1.25,3 -2.5,3"
+ id="path24837"
+ sodipodi:nodetypes="csscc" />
+ </g>
+ <g
+ transform="translate(-0.04332638,0.18371585)"
+ style="display:inline;enable-background:new"
+ id="g6158">
+ <g
+ transform="translate(164,247.5)"
+ id="g24847"
+ style="opacity:0.5">
+ <path
+ d="m 806.5,114.5 c 0,2.25 2,4 4,4 l 30,0 c 0.4163,0 1,-0.5 1,-1 l 0,-29 c 0,-0.5 -0.5,-1 -1,-1 l -21.02773,0.04419 C 818.98721,87.545209 818.5,87 818.5,86.5 l 0,-3 c 0,-0.5 -0.5,-1 -1,-1 l -10,0 c -0.5,0 -1,0.5 -1,1 l 0,31 z"
+ id="path24849"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient24867);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ sodipodi:nodetypes="ccccccssssccc"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccc"
+ d="m 807.5,89.5 33,0 m -33,12 33,0 m -33,-4 33,0 m -33,-6 33,0 m -33,20 33,0 m -33,2 33,0 m -33,-18 33,0 m -33,-2 33,0 m -20,-6 -13,0 m 0,20 33,0 m -33,-2 33,0 m -33,-2 33,0 m -33,-4 33,0 m -33,10 33,0 m -33,6 33,0"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.07999998;fill:url(#linearGradient24869);fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+ id="path24851"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient24871);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;enable-background:accumulate"
+ d="m 844,118.5 c 3.5,0 5.5,-2 5.5,-5.5 l 0,-18.5 c -11.75604,-1.11e-4 -23.91623,0 -35.5,0 l 0,19.5 c 0,4.5 -7,4 -7,0.25 0,2 2.00002,3.73529 3,3.75 l 34,0.5 z"
+ id="path24853"
+ sodipodi:nodetypes="csccsczc"
+ inkscape:export-filename="/home/jimmac/ximian_art/icons/nautilus/suse93/gnome-fs-directory.png"
+ inkscape:export-xdpi="74.800003"
+ inkscape:export-ydpi="74.800003"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="ccssccc"
+ style="opacity:0.7;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path24855"
+ d="m 807,87 12,0 0.0385,-3.33333 C 819.04423,83.166705 818.97512,83 818.5,83 l -10.92308,0 c -0.47512,0 -0.53846,0.16667 -0.53846,0.66667 L 807,87 Z"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24857"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.1;fill:none;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+ d="m 840.5,89 0,4.5"
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="ccc"
+ d="m 848.5,95.5 0,18 c 0,1.25 0.25,3 -1.25,4"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.1;fill:none;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+ id="path24859"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24861"
+ style="display:inline;opacity:0.75;fill:none;stroke:#ffffff;stroke-width:1.29999995;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 818.5,83.5 -11,0 0,30 c 0,5 7,5 7,0 l 0,-18 34,0 m -29,-8 c 0,0.5 0.5286,1 1,1 l 20,0"
+ sodipodi:nodetypes="cccccccsc"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="ccccsscccssssccc"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="path24863"
+ d="m 806.5,113.5 c 0,2.75 2,5 5,5 l 33,0 c 3,0 5,-2 5,-5 l 0,-18 c 0,-0.471405 -0.5286,-1 -1,-1 l -7,0 0,-6 c 0,-0.5 -0.5,-1 -1,-1 l -20.02773,0.04419 C 819.98721,87.54526 819.5,87 819.5,86.5 l 0,-3 c 0,-0.5 -0.5,-1 -1,-1 l -11,0 c -0.5,0 -1,0.5 -1,1 l 0,30 z"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="csscc"
+ id="path24865"
+ d="m 841.5,94.5 -27,0 c -0.4714,0 -1,0.528595 -1,1 l 0,18 c 0,2.25 -1.25,3 -2.5,3"
+ style="fill:none;stroke:url(#linearGradient24873);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;filter:url(#filter6146);enable-background:new"
+ id="g44356"
+ transform="translate(647,272.55)">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#1a1a1a;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.20000005;marker:none;enable-background:accumulate"
+ id="rect44358"
+ width="16"
+ height="16"
+ x="341"
+ y="73" />
+ <g
+ id="g44360"
+ transform="translate(0,-21)">
+ <g
+ id="g44362">
+ <g
+ id="g44364">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#000000;stroke-width:3.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 343.5,104.5 1.75,1.75 c 2.3454,2.33848 6.16153,2.34539 8.5,0 l 0.5,-0.5"
+ id="path44366"
+ sodipodi:nodetypes="cs"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#000000;stroke-width:3.4000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 343,108.25 0,-4.25 4.25,0"
+ id="path44368"
+ sodipodi:nodetypes="ccc"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g44370">
+ <path
+ sodipodi:nodetypes="ccc"
+ id="path44372"
+ d="m 343,108.25 0,-4.25 4.25,0"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#e6e6e6;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="cs"
+ id="path44374"
+ d="m 343.5,104.5 1.75,1.75 c 2.3454,2.33848 6.16153,2.34539 8.5,0 l 0.5,-0.5"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#e6e6e6;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;marker:none;enable-background:accumulate"
+ d="m 344,105 0,1 0,1.5 1,0 0,-1.5 1.5,0 0,-1 -1.5,0 -1,0 z"
+ id="path44376"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="matrix(-1,0,0,-1,698,204)"
+ id="g44378">
+ <g
+ id="g44380">
+ <path
+ sodipodi:nodetypes="cs"
+ id="path44382"
+ d="m 343.5,104.5 1.75,1.75 c 2.3454,2.33848 6.16153,2.34539 8.5,0 l 0.5,-0.5"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#000000;stroke-width:3.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="ccc"
+ id="path44384"
+ d="m 343,108.25 0,-4.25 4.25,0"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#000000;stroke-width:3.4000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g44386">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#e6e6e6;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 343,108.25 0,-4.25 4.25,0"
+ id="path44388"
+ sodipodi:nodetypes="ccc"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#e6e6e6;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 343.5,104.5 1.75,1.75 c 2.3454,2.33848 6.16153,2.34539 8.5,0 l 0.5,-0.5"
+ id="path44390"
+ sodipodi:nodetypes="cs"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ id="path44392"
+ d="m 344,105 0,1 0,1.5 1,0 0,-1.5 1.5,0 0,-1 -1.5,0 -1,0 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="ccc"
+ id="path44394"
+ d="m 344.90625,106.59375 c 2.52573,2.51828 6.66805,2.52691 9.1875,0 l 0.5,-0.5"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:url(#linearGradient44402);stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ sodipodi:nodetypes="ccc"
+ id="path44396"
+ d="m 350.5,99.5 4,0 0,-4"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path44398"
+ d="m 347.5,103.5 -4.5,0 c -0.25,0 -0.5,0.25 -0.5,0.5 l 0,4.5"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="ccc"
+ id="path44400"
+ d="m 345.59375,105.90625 c 2.07803,2.0719 5.36384,2.10325 7.53125,0.1875 L 354,105.25"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:url(#linearGradient44404);stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ </g>
+ <g
+ transform="translate(3.9566736,0.18371585)"
+ id="g34977"
+ style="display:inline;enable-background:new">
+ <g
+ style="display:inline"
+ id="g21853-3"
+ transform="translate(856,-154)"
+ inkscape:export-filename="C:\Documents and Settings\Pracowniaa\Moje dokumenty\Moje obrazy\BLENDER ICONS redesign\ver 2\IMAGE BROWSER ICONS.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <rect
+ ry="0"
+ rx="2.4004419"
+ y="430"
+ x="108"
+ height="48"
+ width="48"
+ id="rect21855-8"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;enable-background:accumulate" />
+ <g
+ id="g21857-6">
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;fill:url(#linearGradient21875-7-1-0-1);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ id="path21859-9"
+ sodipodi:nodetypes="cccccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
+ style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ id="path21861-8"
+ sodipodi:nodetypes="cccc" />
+ <path
+ inkscape:connector-curvature="0"
+ clip-path="url(#clipPath13106-9-2-9-9-4)"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccc"
+ id="path21863-6"
+ d="m 115,444 12,0 -1,-11 -11,11 z"
+ style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011-6-7-0-8)" />
+ <path
+ inkscape:connector-curvature="0"
+ clip-path="none"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 117.5,443.75 9,-2.5 0,-6"
+ style="fill:none;stroke:url(#linearGradient21877-3-2-7-2);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path21865-6"
+ sodipodi:nodetypes="ccc" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccc"
+ id="path21867-2"
+ style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:connector-curvature="0"
+ clip-path="url(#clipPath13106-9-2-9-9-4)"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccc"
+ id="path21869-3"
+ d="m 116,443 11,1 -2,-10 -9,9 z"
+ style="display:inline;opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011-6-7-0-8)" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
+ id="path21871-8"
+ sodipodi:nodetypes="cccccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc"
+ id="path21873-2"
+ style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 147.5,435 0,38.5 -30.5,0"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ </g>
+ </g>
+ <g
+ id="g34938"
+ transform="translate(63,-47)">
+ <path
+ id="path61236"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient34959-9-2-1);fill-opacity:1;fill-rule:nonzero;stroke:#ff0000;stroke-width:0.17893334;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 919.5,356.5067 0,-3 c 0,-1.73575 1.26424,-3 3,-3 l 5,0 c 1.73576,0 3,-1.26425 3,-3 l 0,-3.0064 2.5,0.006 c 2,0 3.5,2.5 3.5,6 0,3.5 -1.25,6 -3.5,6 -4.98134,0 -12.77318,0 -2.5,0 l 0,2.75 c 0,2.5 -2,3.24997 -5.5,3.24998 l 0,2e-5 c -3.5,0.0104 -5.5,-0.75 -5.5,-3.25 l 0,-2.7628"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cssssccsscsccsc" />
+ <path
+ sodipodi:nodetypes="cssssccsscsccsc"
+ inkscape:connector-curvature="0"
+ d="m 930.5,344.5 0,3 c 0,1.73575 -1.26424,3 -3,3 l -5,0 c -1.73576,0 -3,1.26425 -3,3 l 0,3.0064 -2.5,-0.006 c -2,0 -3.5,-2.5 -3.5,-6 0,-3.5 1.25,-6 3.5,-6 4.98134,0 12.77318,0 2.5,0 l 0,-2.75 c 0,-2.5 2,-3.24997 5.5,-3.24998 l 0,-2e-5 c 3.5,-0.0104 5.5,0.75 5.5,3.25 l 0,2.7628"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient34961-3-6-5);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.17893334;marker:none;enable-background:accumulate"
+ id="path61233" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccscccsccccsccccc"
+ id="path61167"
+ d="m 925,338.50002 c -3.5,10e-6 -5.5,0.74998 -5.5,3.24998 l 0,2.75 5.5,0 -8,0 c -2.25,0 -3.5,2.5 -3.5,6 0,3.5 1.5,6 3.5,6 l 2.5,0.0128 0,2.9872 c 0,2 2,3.01281 5.5,3.0128 3.5,-1e-5 5.5,-1.0128 5.5,-3.0128 l 0,-3 -5.5,0 8,0 c 2,0 3.5,-2.5 3.5,-6 0,-3.5 -1.5,-6 -3.5,-6 l -2.5,0.0128 0,-2.7628 c 0,-2.5 -2,-3.26045 -5.5,-3.25 z"
+ style="fill:none;stroke:#000000;stroke-width:0.80000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.8627451" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccc"
+ id="path61169"
+ d="m 930.5,344.5 0,3 c 0,1.73575 -1.26424,3 -3,3 l -5,0 c -1.73576,0 -3,1.26425 -3,3 l 0,3"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#000000;stroke-width:0.80000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.78431373;marker:none;enable-background:accumulate" />
+ <circle
+ r="1"
+ cy="342"
+ cx="922"
+ id="path61220"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.80000001;marker:none;enable-background:accumulate" />
+ <circle
+ r="1"
+ cy="359"
+ cx="928"
+ id="path61222"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.80000001;marker:none;enable-background:accumulate" />
+ <g
+ style="opacity:0.4"
+ id="g61345">
+ <path
+ style="fill:none;stroke:url(#linearGradient34963-5-9-1);stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 920.5,343.25 0,-1.5 c 0,-1.75 1.5,-2.25 4.5,-2.25 3,0 4.5,0.5 4.5,2.25 l 0,4.75"
+ id="path61333"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cszsc" />
+ <path
+ style="fill:none;stroke:url(#linearGradient34965-1-5-2);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 925.5,345 0,0.25 -0.25,0.25 -8.25,0 c -1.5,0 -2.5,2 -2.5,5 0,3 1.28917,5 2.5,5 l 1.5,0"
+ id="path61335"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccszsc" />
+ <path
+ style="fill:none;stroke:none"
+ d="m 920.75,343.5 4.5,0 0.25,0.25 0,0.5"
+ id="path61337"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;stroke:none"
+ d="m 918.5,355.25 0,-1.75 c 0,-2.25 1.75,-4 4,-4 l 4.5,0 c 1.75,0 2.5,-0.75 2.5,-2.5 l 0,-0.5"
+ id="path61339"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cssssc" />
+ <circle
+ r="1"
+ cy="342"
+ cx="922"
+ transform="matrix(1.5161021,0,0,1.5161021,-475.84616,-176.50693)"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:url(#linearGradient34967-4-1-8);stroke-width:0.52766895;stroke-miterlimit:4;stroke-dasharray:none;marker:none;enable-background:accumulate"
+ id="path61355" />
+ </g>
+ <g
+ style="opacity:0.8;stroke:#ff0000"
+ transform="matrix(-1,0,0,-1,1850,701)"
+ id="g34104">
+ <path
+ sodipodi:nodetypes="cszsc"
+ inkscape:connector-curvature="0"
+ id="path34106"
+ d="m 920.5,343.25 0,-1.5 c 0,-1.75 1.5,-2.25 4.5,-2.25 3,0 4.5,0.5 4.5,2.25 l 0,4.75"
+ style="fill:none;stroke:none" />
+ <path
+ sodipodi:nodetypes="csc"
+ inkscape:connector-curvature="0"
+ id="path34108"
+ d="m 914.5,350.5 c 0,3 1.28917,5 2.5,5 l 1.5,0"
+ style="fill:none;stroke:url(#linearGradient34969-4-4-1);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path34110"
+ d="m 920.75,343.5 4.5,0 0.25,0.25 0,0.5"
+ style="fill:none;stroke:url(#linearGradient34971-5-0-9);stroke-linecap:round;stroke-linejoin:round" />
+ <path
+ sodipodi:nodetypes="cssssc"
+ inkscape:connector-curvature="0"
+ id="path34113"
+ d="m 918.5,355.5 0,-2 c 0,-2.25 1.75,-4 4,-4 l 4.5,0 c 1.75,0 2.5,-0.75 2.5,-2.5 l 0,-0.5"
+ style="fill:none;stroke:url(#radialGradient34973-2-5-7);stroke-linecap:round;stroke-linejoin:round" />
+ <circle
+ r="1"
+ cy="342"
+ cx="922"
+ id="path34115"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:url(#linearGradient34975-9-4-9);stroke-width:0.52766895;stroke-miterlimit:4;stroke-dasharray:none;marker:none;enable-background:accumulate"
+ transform="matrix(1.5161021,0,0,1.5161021,-475.84616,-176.50693)" />
+ <path
+ style="fill:none;stroke:none"
+ d="m 925.5,345 0,0.25 -0.25,0.25 -8.25,0 c -1.5,0 -2.5,2 -2.5,5"
+ id="path34901"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccsc" />
+ </g>
+ </g>
+ </g>
+ <g
+ transform="translate(211.95667,-7.8162842)"
+ id="g45475-4"
+ style="display:inline;enable-background:new">
+ <g
+ style="display:inline"
+ id="g22242-6"
+ transform="translate(696,-194)"
+ inkscape:export-filename="C:\Documents and Settings\Pracowniaa\Moje dokumenty\Moje obrazy\BLENDER ICONS redesign\ver 2\IMAGE BROWSER ICONS.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <rect
+ ry="0"
+ rx="2.4004419"
+ y="430"
+ x="108"
+ height="48"
+ width="48"
+ id="rect22244-9"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;enable-background:accumulate" />
+ <g
+ id="g22246-2">
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;fill:url(#linearGradient22274-8);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ id="path22249-8"
+ sodipodi:nodetypes="cccccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
+ style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ id="path22251-9"
+ sodipodi:nodetypes="cccc" />
+ <path
+ inkscape:connector-curvature="0"
+ clip-path="url(#clipPath13106-5)"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccc"
+ id="path22253-5"
+ d="m 115,444 12,0 -1,-11 -11,11 z"
+ style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011-5)" />
+ <path
+ inkscape:connector-curvature="0"
+ clip-path="none"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 117.5,443.75 9,-2.5 0,-6"
+ style="fill:none;stroke:url(#linearGradient22276-5);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path22264-3"
+ sodipodi:nodetypes="ccc" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccc"
+ id="path22266-6"
+ style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:connector-curvature="0"
+ clip-path="url(#clipPath13106-5)"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccc"
+ id="path22268-0"
+ d="m 116,443 11,1 -2,-10 -9,9 z"
+ style="display:inline;opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011-5)" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
+ id="path22270-1"
+ sodipodi:nodetypes="cccccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc"
+ id="path22272-3"
+ style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 147.5,435 0,38.5 -30.5,0"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ </g>
+ </g>
+ <g
+ id="g21517-6"
+ inkscape:label="Layer 1"
+ transform="matrix(0.5406242,0,0,0.5829534,814.13667,247.65542)">
+ <ellipse
+ ry="5.3033009"
+ rx="15.467961"
+ cy="38.98439"
+ cx="28.019106"
+ transform="matrix(1.274286,0,0,1.377124,-7.569123,-16.70193)"
+ id="path35486-4"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.54857142;fill:url(#radialGradient21442-6-790);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="csssssssssscccsscccscccssccc"
+ d="m 16.048489,28.093447 c 0.0098,0.576682 0.196474,1.697902 0.471116,2.577425 0.581566,1.854137 1.56684,3.572658 2.939126,5.086496 1.407488,1.553118 3.138519,2.803227 5.139315,3.68976 2.105357,0.931573 4.384795,1.407488 6.750134,1.403741 2.365339,-0.005 4.644601,-0.488686 6.74896,-1.427017 2.00002,-0.895288 3.731043,-2.148391 5.13754,-3.705517 1.369207,-1.519844 2.352576,-3.241114 2.934089,-5.096258 0.294262,-0.938353 0.476921,-1.889392 0.553238,-2.845308 0.07331,-0.939306 0.04204,-1.883511 -0.09183,-2.823792 -0.259981,-1.835599 -0.896294,-3.556847 -1.872652,-5.12758 -0.895541,-1.441699 -2.047808,-2.70454 -3.417268,-3.766975 0,0 0.002,-0.002 0.002,-0.002 0,0 -13.828458,-10.6197195 -13.828458,-10.6197195 -0.01176,-0.00978 -0.02252,-0.019551 -0.03529,-0.028344 -0.909003,-0.6959264 -3.879837,-0.7738945 -4.87679,-0.075035 -1.01067,0.7057021 -1.091821,1.8092613 -0.195527,2.5482146 1.899775,1.4997633 2.656207,2.2801589 4.566507,3.7797379 0,0 -14.852491,0.167033 -14.852491,0.167033 -1.994685,0 -3.1682609,0.947915 -3.4153947,2.333683 -0.2180771,1.222836 0.7479213,2.738129 2.4800217,2.738129 2.956573,0.0039 5.942111,-0.0069 8.909215,-0.01272 0,0 -16.01999,12.453223 -16.01999,12.453223 -0.020527,0.01564 -0.041053,0.02933 -0.06158,0.04497 -1.4974197,1.148389 -1.9831951,3.059322 -1.0399808,4.268393 0.9598323,1.22959 2.9977653,1.230588 4.5147288,0.006 0,0 8.677593,-7.102098 8.677593,-7.102098 0,0 -0.12511,0.959824 -0.116333,1.535532 l 1e-6,2.6e-5 0,0 0,0 z"
+ id="path2482-9"
+ style="fill:#dd6d00;fill-rule:evenodd;stroke:#993d00;stroke-width:1.7812928;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none" />
+ <ellipse
+ ry="10.125"
+ rx="11.5625"
+ cy="25.75"
+ cx="31.1875"
+ transform="matrix(0.8018194,0,0,0.8471126,6.257567,4.5089892)"
+ id="path39153-3"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient21444-0-352);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ style="opacity:0.4857143;fill:none;stroke:url(#linearGradient21446-3-145);stroke-width:1.7812928;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1"
+ d="m 25.8125,6.40625 c -0.334829,4.572e-4 -0.72202,0.089606 -0.90625,0.21875 4.5e-4,0.010412 4.5e-4,0.020838 0,0.03125 -0.212626,0.1484635 -0.188235,0.1956271 -0.1875,0.1875 0.0092,0.010621 -0.0072,-4.246e-4 0.03125,0.03125 0.01962,0.00828 0.03527,0.012546 0.0625,0.03125 0.01676,0.01151 0.01357,0.014555 0.03125,0.03125 0.193748,0.1576058 4.954976,4.005164 4.954976,4.005164 0.489837,0.39864 0.677395,1.066352 0.46875,1.65625 -0.115662,0.32703 -0.422813,0.541217 -0.6875,0.59375 -0.264687,0.05253 -0.498447,0.03054 -0.71875,0.03125 -5.639658,0.05119 -16.87989,0.03851 -16.87989,0.03851 -0.4102,2.75e-4 -0.935835,0.115997 -1.34375,0.34375 -0.407915,0.227753 -0.6637862,0.523861 -0.6875002,0.90625 -0.024417,0.393728 0.098829,0.605767 0.3437502,0.78125 0.244921,0.175483 0.614978,0.25 0.875,0.25 0,0 8.8125,0 8.8125,0 0.600305,-7.28e-4 1.223895,0.311058 1.4375,0.9375 0.04676,0.137121 0.06335,0.269976 0.0625,0.40625 -8.49e-4,0.136274 -0.02214,0.268794 -0.09375,0.375 -0.143211,0.212412 -0.319507,0.298568 -0.5,0.4375 0,0 -15.7871819,12.746851 -15.856336,12.800078 C 5.0310984,30.500117 5,30.53125 5,30.53125 5.0100745,30.519077 5.000335,30.499512 5,30.5 L 4.8125,30.3125 c 0.012336,0.02165 0.014481,0.03307 0.03125,0.0625 0.063558,0.0774 0.125,0.15625 0.125,0.15625 -0.00585,0.0056 -0.031233,0.03124 -0.03125,0.03125 0,0 -0.043442,-0.09921 -0.09375,-0.1875 0.037843,0.09884 0.06253,0.218739 0.0625,0.21875 -0.4662091,0.37119 -0.7783348,0.889746 -0.875,1.28125 -0.1043319,0.422581 -0.046,0.62455 0.125,0.84375 0.2999827,0.384295 1.3975356,0.595547 2.40625,-0.21875 0,0 8.65625,-7.09375 8.65625,-7.09375 0.473718,-0.387074 1.1446,-0.458625 1.6875,-0.15625 0.544608,0.303331 0.798054,0.927572 0.71875,1.53125 0,0 -0.0626,0.908319 -0.0625,1.25 2e-6,0.0085 -1.19e-4,0.02348 0,0.03125 0.192796,2.523718 1.400736,4.762818 3.03125,6.71875 2.801818,3.089095 6.627659,4.401619 10.75,4.5625 4.113324,-0.043 7.964529,-1.606111 10.75,-4.625 2.546631,-3.125326 3.513872,-6.363859 3.15625,-9.375 C 44.891575,22.325847 43.222923,19.516566 40.4375,17.25 35.951885,13.599946 31.206991,10.168434 26.59375,6.625 26.57515,6.610386 26.56455,6.59802 26.5625,6.59375 26.43835,6.498703 26.144223,6.4057899 25.8125,6.40625 Z"
+ id="path21414-5"
+ sodipodi:nodetypes="csssssscssscsssccssscscccsccssssccscsscccssssc" />
+ <path
+ inkscape:connector-curvature="0"
+ d="m 25.708956,26.064593 c 0.07649,-1.397943 0.759369,-2.631914 1.78592,-3.505519 1.010226,-0.858782 2.366788,-1.383145 3.848625,-1.383145 1.480894,0 2.837456,0.524363 3.847446,1.383145 1.027685,0.873605 1.709741,2.106651 1.787122,3.504594 0.07927,1.438713 -0.49591,2.77459 -1.504012,3.764001 -1.027686,1.007933 -2.493008,1.640678 -4.130556,1.640678 -1.63849,0 -3.103814,-0.632745 -4.131451,-1.640678 -1.00914,-0.989411 -1.58234,-2.325288 -1.503094,-3.763076 l 0,0 0,0 0,0 z"
+ id="path2478-8"
+ style="fill:#2f5b94;fill-rule:evenodd;stroke:none" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="csssscsccsscsccssssscsscccsssc"
+ id="path39166-5"
+ d="m 25.8125,6.03125 c -0.404852,5.53e-4 -2.204797,-0.059029 -2.48145,0.1349032 -0.280209,0.195652 -0.335403,0.376484 -0.34375,0.46875 -0.0083,0.092266 -0.01539,0.17648 0.1875,0.34375 0.01899,0.015735 0.04457,0.014317 0.0625,0.03125 0.124258,0.101028 4.748869,4.1248618 4.748869,4.1248618 0.373658,0.304091 0.504393,0.795817 0.34375,1.25 -0.160635,0.454191 -0.580748,0.373449 -1.0625,0.375 -5.634142,0.05114 -15.087371,-0.129601 -15.087371,-0.129601 -0.952967,6.38e-4 -2.339958,0.524782 -2.4062504,1.59375 -0.063562,1.024947 0.9247974,1.4375 1.5937504,1.4375 0,-1e-6 8.8125,0 8.8125,0 0.488364,-5.92e-4 0.936141,0.225277 1.09375,0.6875 0.157609,0.462231 -0.01926,0.514621 -0.40625,0.8125 0,0 -16.086298,13.088586 -16.086298,13.088586 -0.00142,0.0014 -0.029829,-0.0014 -0.03125,0 -0.064037,0.04879 -0.054226,0.04875 -0.03125,0.03125 -0.5536758,0.424619 -0.9087886,1.004019 -1.03125,1.5 -0.1224536,0.495981 -0.04661,0.856152 0.1875,1.15625 0.4788333,0.613413 1.777612,0.754857 2.90625,-0.15625 1e-7,10e-7 8.65625,-7.09375 8.65625,-7.09375 0.361955,-0.295753 0.872897,-0.352437 1.28125,-0.125 0.408345,0.227436 0.623381,0.692814 0.5625,1.15625 0,-1e-6 -0.0997,0.953636 -0.09375,1.34375 0.09498,1.301756 0.451616,2.521825 0.989039,3.664234 C 20.799917,36.321089 27.770982,19.392853 44.1875,21.03125 43.339652,19.54368 42.151282,18.185293 40.65625,16.96875 36.159865,13.309932 31.42016,9.882897 26.8125,6.34375 26.805335,6.338858 26.788292,6.317553 26.78125,6.3125 26.570707,6.151312 26.216591,6.030689 25.8125,6.03125 Z"
+ style="opacity:0.51999996;fill:url(#radialGradient21448-8-143);fill-opacity:1;fill-rule:evenodd;stroke:none" />
+ </g>
+ </g>
</g>
<g
inkscape:groupmode="layer"
diff --git a/release/datafiles/blender_icons16/icon16_restrict_color_off.dat b/release/datafiles/blender_icons16/icon16_restrict_color_off.dat
new file mode 100644
index 00000000000..d313539e3c5
--- /dev/null
+++ b/release/datafiles/blender_icons16/icon16_restrict_color_off.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_restrict_color_on.dat b/release/datafiles/blender_icons16/icon16_restrict_color_on.dat
new file mode 100644
index 00000000000..bb7782bb42a
--- /dev/null
+++ b/release/datafiles/blender_icons16/icon16_restrict_color_on.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_restrict_color_off.dat b/release/datafiles/blender_icons32/icon32_restrict_color_off.dat
new file mode 100644
index 00000000000..bbe5f61935d
--- /dev/null
+++ b/release/datafiles/blender_icons32/icon32_restrict_color_off.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_restrict_color_on.dat b/release/datafiles/blender_icons32/icon32_restrict_color_on.dat
new file mode 100644
index 00000000000..46ba9e31407
--- /dev/null
+++ b/release/datafiles/blender_icons32/icon32_restrict_color_on.dat
Binary files differ
diff --git a/release/datafiles/colormanagement/config.ocio b/release/datafiles/colormanagement/config.ocio
index c2bfd3bca10..924a140d6f3 100644
--- a/release/datafiles/colormanagement/config.ocio
+++ b/release/datafiles/colormanagement/config.ocio
@@ -247,6 +247,7 @@ colorspaces:
allocation: uniform
allocationvars: [-0.125, 4.875]
to_reference: !<FileTransform> {src: srgb.spi1d, interpolation: linear}
+ from_reference: !<FileTransform> {src: srgb_inv.spi1d, interpolation: linear}
- !<ColorSpace>
name: VD16
diff --git a/release/datafiles/colormanagement/luts/srgb_inv.spi1d b/release/datafiles/colormanagement/luts/srgb_inv.spi1d
new file mode 100644
index 00000000000..2c1452fbb08
--- /dev/null
+++ b/release/datafiles/colormanagement/luts/srgb_inv.spi1d
@@ -0,0 +1,65567 @@
+Version 1
+From -0.00967492260062 40.4600768322
+Length 65561
+Components 1
+{
+ -0.1250000000000104
+ -0.11702456997145604
+ -0.10904913994290168
+ -0.10107370991434733
+ -0.09309827988579296
+ -0.0851228498572386
+ -0.07714741982868423
+ -0.06917198980012987
+ -0.0611965597715755
+ -0.05322112974302114
+ -0.045245699714466785
+ -0.03727026968591242
+ -0.02929483965735805
+ -0.02131940962880368
+ -0.013343979600249337
+ -0.00536854957169497
+ 0.0026068804568593965
+ 0.010582310485413764
+ 0.01855774051396813
+ 0.026533170542522477
+ 0.03450860057107684
+ 0.04242127131742316
+ 0.04966122909244714
+ 0.056260201931676114
+ 0.06235220012514372
+ 0.0680307887431286
+ 0.07336426762816567
+ 0.07840424805962154
+ 0.0831908247246071
+ 0.08775585933030919
+ 0.09212515427514542
+ 0.09631994226697205
+ 0.1003579373970962
+ 0.1042540955170489
+ 0.10802117631963587
+ 0.11167016674868888
+ 0.11521060529691904
+ 0.11865083408806257
+ 0.12199819743021392
+ 0.12525920007695024
+ 0.12843963473636816
+ 0.13154468581259388
+ 0.13457901456662716
+ 0.13754682959869283
+ 0.1404519456228731
+ 0.14329783282055583
+ 0.14608765855041497
+ 0.14882432280999883
+ 0.15151048855323906
+ 0.15414860774510222
+ 0.15674094386188792
+ 0.1592895914108321
+ 0.16179649293656145
+ 0.1642634538978275
+ 0.16669215573080126
+ 0.1690841673612563
+ 0.17144095538435214
+ 0.17376389309525853
+ 0.1760542685248608
+ 0.17831329161094808
+ 0.18054210061559325
+ 0.1827417678830924
+ 0.1849133050192061
+ 0.1870576675610369
+ 0.18917575919728902
+ 0.19126843559056186
+ 0.19333650784647366
+ 0.19538074566858338
+ 0.19740188023310656
+ 0.19940060681316712
+ 0.20137758717867327
+ 0.2033334517947603
+ 0.20526880183902724
+ 0.20718421105544027
+ 0.20908022746073562
+ 0.21095737491737282
+ 0.21281615458553998
+ 0.2146570462653533
+ 0.21648050963920246
+ 0.21828698542314723
+ 0.22007689643534878
+ 0.22185064858870612
+ 0.2236086318141473
+ 0.22535122092038873
+ 0.22707877639540952
+ 0.22879164515438416
+ 0.2304901612383678
+ 0.2321746464676293
+ 0.2338454110531673
+ 0.2355027541696253
+ 0.23714696449253414
+ 0.23877832070255106
+ 0.24039709195913206
+ 0.2420035383458664
+ 0.2435979112895112
+ 0.2451804539545943
+ 0.24675140161529874
+ 0.24831098200620277
+ 0.2498594156533221
+ 0.25139691618678495
+ 0.25292369063636727
+ 0.25443993971101914
+ 0.2559458580634255
+ 0.2574416345405671
+ 0.25892745242117376
+ 0.26040348964089466
+ 0.2618699190059524
+ 0.26332690839599027
+ 0.2647746209567698
+ 0.26621321528333314
+ 0.2676428455941966
+ 0.26906366189710595
+ 0.2704758101468457
+ 0.2718794323955622
+ 0.27327466693602787
+ 0.27466164843824675
+ 0.27604050807977504
+ 0.27741137367010443
+ 0.27877436976943515
+ 0.2801296178021439
+ 0.28147723616523207
+ 0.28281734033202344
+ 0.2841500429513604
+ 0.28547545394253687
+ 0.2867936805861869
+ 0.2881048276113387
+ 0.28940899727882796
+ 0.2907062894612551
+ 0.29199680171965936
+ 0.29328062937707167
+ 0.29455786558910085
+ 0.29582860141169665
+ 0.2970929258662268
+ 0.29835092600199575
+ 0.2996026869563277
+ 0.30084829201232743
+ 0.3020878226544282
+ 0.3033213586218286
+ 0.30454897795991553
+ 0.305770757069765
+ 0.30698677075580755
+ 0.3081970922717406
+ 0.3094017933647652
+ 0.31060094431822166
+ 0.31179461399269437
+ 0.3129828698656508
+ 0.31416577806967966
+ 0.3153434034293866
+ 0.3165158094970058
+ 0.31768305858678003
+ 0.3188452118081615
+ 0.32000232909788306
+ 0.3211544692509443
+ 0.322301689950559
+ 0.3234440477971047
+ 0.324581598336115
+ 0.3257143960853536
+ 0.32684249456100467
+ 0.32796594630301673
+ 0.32908480289963127
+ 0.3301991150111289
+ 0.33130893239282266
+ 0.33241430391732807
+ 0.33351527759613625
+ 0.334611900600518
+ 0.3357042192817825
+ 0.33679227919091587
+ 0.33787612509762205
+ 0.3389558010087876
+ 0.3400313501863928
+ 0.34110281516488744
+ 0.3421702377680521
+ 0.343233659125363
+ 0.3442931196878771
+ 0.3453486592436559
+ 0.3464003169327436
+ 0.347448131261715
+ 0.3484921401178078
+ 0.34953238078265525
+ 0.3505688899456305
+ 0.3516017037168178
+ 0.35263085763962254
+ 0.3536563867030321
+ 0.35467832535353966
+ 0.3556967075067415
+ 0.3567115665586197
+ 0.35772293539651945
+ 0.3587308464098318
+ 0.3597353315003909
+ 0.36073642209259493
+ 0.3617341491432607
+ 0.3627285431512185
+ 0.3637196341666574
+ 0.3647074518002276
+ 0.36569202523190786
+ 0.3666733832196455
+ 0.3676515541077763
+ 0.3686265658352298
+ 0.36959844594352864
+ 0.3705672215845863
+ 0.37153291952831047
+ 0.3724955661700178
+ 0.37345518753766527
+ 0.3744118092989043
+ 0.37536545676796235
+ 0.3763161549123569
+ 0.37726392835944816
+ 0.378208801402833
+ 0.37915079800858703
+ 0.38008994182135725
+ 0.38102625617031105
+ 0.38195976407494514
+ 0.3828904882507577
+ 0.3838184511147892
+ 0.384743674791034
+ 0.38566618111572765
+ 0.386585991642512
+ 0.3875031276474834
+ 0.38841761013412507
+ 0.3893294598381286
+ 0.3902386972321066
+ 0.3911453425301997
+ 0.39204941569258167
+ 0.3929509364298629
+ 0.3938499242073987
+ 0.3947463982495016
+ 0.3956403775435616
+ 0.3965318808440777
+ 0.39742092667660095
+ 0.3983075333415934
+ 0.39919171891820365
+ 0.4000735012679621
+ 0.4009528980383977
+ 0.40182992666657763
+ 0.40270460438257333
+ 0.40357694821285295
+ 0.4044469749836036
+ 0.40531470132398467
+ 0.4061801436693128
+ 0.407043318264183
+ 0.40790424116552426
+ 0.4087629282455935
+ 0.4096193951949089
+ 0.4104736575251232
+ 0.41132573057184
+ 0.4121756294973727
+ 0.41302336929344924
+ 0.4138689647838623
+ 0.41471243062706786
+ 0.4155537813187316
+ 0.4163930311942263
+ 0.41723019443108
+ 0.4180652850513761
+ 0.41889831692410795
+ 0.41972930376748724
+ 0.4205582591512084
+ 0.4213851964986696
+ 0.4222101290891513
+ 0.42303307005995383
+ 0.4238540324084942
+ 0.4246730289943636
+ 0.42549007254134663
+ 0.42630517563940246
+ 0.42711835074660903
+ 0.4279296101910722
+ 0.4287389661727984
+ 0.4295464307655339
+ 0.43035201591857
+ 0.43115573345851527
+ 0.4319575950910362
+ 0.43275761240256566
+ 0.43355579686198076
+ 0.4343521598222514
+ 0.43514671252205805
+ 0.4359394660873821
+ 0.4367304315330669
+ 0.43751961976435216
+ 0.43830704157838046
+ 0.4390927076656784
+ 0.4398766286116108
+ 0.4406588148978106
+ 0.4414392769035834
+ 0.44221802490728773
+ 0.44299506908769193
+ 0.443770419525308
+ 0.4445440862037016
+ 0.44531607901078113
+ 0.4460864077400641
+ 0.44685508209192243
+ 0.44762211167480676
+ 0.4483875060064502
+ 0.4491512745150527
+ 0.4499134265404436
+ 0.4506739713352282
+ 0.4514329180659122
+ 0.4521902758140098
+ 0.4529460535771325
+ 0.453700260270061
+ 0.4544529047257984
+ 0.4552039956966076
+ 0.4559535418550314
+ 0.45670155179489597
+ 0.45744803403229856
+ 0.45819299700657895
+ 0.45893644908127657
+ 0.4596783985450706
+ 0.4604188536127069
+ 0.46115782242590925
+ 0.46189531305427695
+ 0.46263133349616753
+ 0.4633658916795668
+ 0.46409899546294425
+ 0.4648306526360962
+ 0.4655608709209748
+ 0.4662896579725057
+ 0.4670170213793911
+ 0.46774296866490334
+ 0.46846750728766356
+ 0.4691906446424103
+ 0.46991238806075614
+ 0.4706327448119319
+ 0.47135172210352166
+ 0.4720693270821847
+ 0.4727855668343674
+ 0.4735004483870056
+ 0.4742139787082144
+ 0.47492616470796983
+ 0.4756370132387791
+ 0.47634653109634145
+ 0.47705472502019947
+ 0.4777616016943807
+ 0.4784671677480297
+ 0.4791714297560316
+ 0.4798743942396259
+ 0.4805760676670114
+ 0.4812764564539435
+ 0.48197556696432126
+ 0.4826734055107678
+ 0.48336997835520096
+ 0.484065291709397
+ 0.48475935173554524
+ 0.4854521645467958
+ 0.48614373620779944
+ 0.4868340727352391
+ 0.4875231800983551
+ 0.4882110642194621
+ 0.4888977309744595
+ 0.48958318619333424
+ 0.49026743566065706
+ 0.4909504851160718
+ 0.4916323402547778
+ 0.4923130067280063
+ 0.4929924901434893
+ 0.49367079606592273
+ 0.49434793001742355
+ 0.4950238974779801
+ 0.4956987038858966
+ 0.49637235463823176
+ 0.49704485509123114
+ 0.4977162105607546
+ 0.49838642632269675
+ 0.49905550761340295
+ 0.4997234596300794
+ 0.5003902875311973
+ 0.5010559964368927
+ 0.5017205914293602
+ 0.5023840775532418
+ 0.5030464598160108
+ 0.5037077431883511
+ 0.5043679326045295
+ 0.505027032962767
+ 0.5056850491256006
+ 0.5063419859202449
+ 0.506997848138946
+ 0.5076526405393319
+ 0.5083063678447589
+ 0.5089590347446522
+ 0.5096106458948445
+ 0.5102612059179071
+ 0.5109107194034802
+ 0.5115591909085965
+ 0.5122066249580017
+ 0.5128530260444712
+ 0.5134983986291228
+ 0.5141427471417247
+ 0.5147860759810003
+ 0.5154283895149301
+ 0.5160696920810476
+ 0.5167099879867336
+ 0.5173492815095067
+ 0.5179875768973081
+ 0.5186248783687863
+ 0.5192611901135757
+ 0.5198965162925724
+ 0.5205308610382073
+ 0.5211642284547156
+ 0.5217966226184027
+ 0.5224280475779073
+ 0.5230585073544609
+ 0.5236880059421449
+ 0.5243165473081439
+ 0.5249441353929966
+ 0.5255707741108426
+ 0.5261964673496685
+ 0.5268212189715482
+ 0.5274450328128827
+ 0.5280679126846359
+ 0.5286898623725683
+ 0.5293108856374671
+ 0.5299309862153745
+ 0.5305501678178125
+ 0.5311684341320065
+ 0.5317857888211045
+ 0.5324022355243946
+ 0.5330177778575208
+ 0.5336324194126949
+ 0.5342461637589065
+ 0.5348590144421317
+ 0.5354709749855369
+ 0.5360820488896832
+ 0.5366922396327265
+ 0.5373015506706158
+ 0.5379099854372894
+ 0.5385175473448693
+ 0.5391242397838527
+ 0.5397300661233013
+ 0.5403350297110296
+ 0.5409391338737894
+ 0.5415423819174541
+ 0.5421447771271991
+ 0.542746322767682
+ 0.5433470220832191
+ 0.5439468782979613
+ 0.5445458946160675
+ 0.5451440742218757
+ 0.5457414202800738
+ 0.5463379359358657
+ 0.5469336243151388
+ 0.5475284885246273
+ 0.5481225316520749
+ 0.5487157567663956
+ 0.5493081669178319
+ 0.5498997651381134
+ 0.5504905544406106
+ 0.5510805378204898
+ 0.5516697182548653
+ 0.5522580987029493
+ 0.5528456821062018
+ 0.5534324713884765
+ 0.554018469456169
+ 0.5546036791983585
+ 0.5551881034869524
+ 0.5557717451768263
+ 0.5563546071059648
+ 0.5569366920955996
+ 0.5575180029503453
+ 0.5580985424583368
+ 0.5586783133913612
+ 0.5592573185049922
+ 0.5598355605387201
+ 0.5604130422160825
+ 0.5609897662447925
+ 0.561565735316866
+ 0.562140952108748
+ 0.5627154192814369
+ 0.5632891394806072
+ 0.5638621153367335
+ 0.5644343494652092
+ 0.5650058444664678
+ 0.5655766029261005
+ 0.5661466274149737
+ 0.566715920489345
+ 0.5672844846909781
+ 0.5678523225472569
+ 0.5684194365712973
+ 0.5689858292620593
+ 0.5695515031044571
+ 0.5701164605694689
+ 0.5706807041142443
+ 0.5712442361822117
+ 0.5718070592031845
+ 0.5723691755934663
+ 0.5729305877559545
+ 0.5734912980802428
+ 0.5740513089427245
+ 0.5746106227066922
+ 0.575169241722438
+ 0.5757271683273534
+ 0.5762844048460256
+ 0.5768409535903366
+ 0.5773968168595575
+ 0.577951996940445
+ 0.578506496107335
+ 0.5790603166222362
+ 0.5796134607349228
+ 0.5801659306830255
+ 0.5807177286921227
+ 0.5812688569758304
+ 0.581819317735891
+ 0.5823691131622616
+ 0.582918245433201
+ 0.5834667167153567
+ 0.5840145291638499
+ 0.5845616849223613
+ 0.5851081861232144
+ 0.5856540348874592
+ 0.5861992333249543
+ 0.5867437835344492
+ 0.5872876876036647
+ 0.5878309476093736
+ 0.58837356561748
+ 0.5889155436830975
+ 0.5894568838506287
+ 0.5899975881538406
+ 0.5905376586159427
+ 0.5910770972496617
+ 0.5916159060573178
+ 0.5921540870308984
+ 0.5926916421521321
+ 0.593228573392562
+ 0.593764882713618
+ 0.594300572066689
+ 0.594835643393193
+ 0.5953700986246492
+ 0.5959039396827464
+ 0.5964371684794132
+ 0.5969697869168864
+ 0.5975017968877789
+ 0.5980332002751472
+ 0.5985639989525576
+ 0.5990941947841538
+ 0.5996237896247212
+ 0.6001527853197521
+ 0.6006811837055114
+ 0.6012089866090987
+ 0.6017361958485129
+ 0.6022628132327141
+ 0.6027888405616868
+ 0.6033142796265005
+ 0.6038391322093718
+ 0.6043634000837241
+ 0.6048870850142484
+ 0.6054101887569622
+ 0.605932713059269
+ 0.6064546596600165
+ 0.606976030289555
+ 0.6074968266697943
+ 0.6080170505142612
+ 0.608536703528156
+ 0.6090557874084076
+ 0.6095743038437307
+ 0.6100922545146793
+ 0.6106096410937022
+ 0.6111264652451968
+ 0.611642728625563
+ 0.6121584328832559
+ 0.6126735796588392
+ 0.6131881705850368
+ 0.6137022072867856
+ 0.6142156913812858
+ 0.6147286244780531
+ 0.615241008178968
+ 0.6157528440783272
+ 0.6162641337628921
+ 0.6167748788119393
+ 0.6172850807973084
+ 0.6177947412834511
+ 0.6183038618274795
+ 0.6188124439792131
+ 0.6193204892812265
+ 0.6198279992688963
+ 0.6203349754704474
+ 0.6208414194069992
+ 0.6213473325926118
+ 0.6218527165343305
+ 0.6223575727322312
+ 0.6228619026794657
+ 0.6233657078623049
+ 0.6238689897601829
+ 0.6243717498457413
+ 0.6248739895848714
+ 0.625375710436758
+ 0.6258769138539211
+ 0.6263776012822583
+ 0.6268777741610867
+ 0.6273774339231846
+ 0.6278765819948319
+ 0.6283752197958515
+ 0.6288733487396501
+ 0.6293709702332572
+ 0.6298680856773662
+ 0.6303646964663728
+ 0.6308608039884153
+ 0.6313564096254125
+ 0.631851514753103
+ 0.6323461207410831
+ 0.6328402289528448
+ 0.6333338407458137
+ 0.633826957471386
+ 0.6343195804749658
+ 0.6348117110960022
+ 0.635303350668025
+ 0.635794500518682
+ 0.6362851619697739
+ 0.6367753363372903
+ 0.6372650249314458
+ 0.6377542290567135
+ 0.6382429500118617
+ 0.638731189089987
+ 0.6392189475785497
+ 0.6397062267594065
+ 0.6401930279088457
+ 0.6406793522976195
+ 0.6411652011909784
+ 0.641650575848703
+ 0.6421354775251377
+ 0.6426199074692227
+ 0.6431038669245264
+ 0.6435873571292771
+ 0.6440703793163952
+ 0.6445529347135247
+ 0.6450350245430638
+ 0.6455166500221968
+ 0.6459978123629245
+ 0.6464785127720948
+ 0.6469587524514324
+ 0.6474385325975706
+ 0.6479178544020793
+ 0.6483967190514957
+ 0.6488751277273537
+ 0.6493530816062127
+ 0.6498305818596873
+ 0.650307629654475
+ 0.6507842261523856
+ 0.6512603725103696
+ 0.6517360698805457
+ 0.6522113194102296
+ 0.652686122241961
+ 0.6531604795135315
+ 0.6536343923580116
+ 0.6541078619037786
+ 0.6545808892745422
+ 0.6550534755893728
+ 0.6555256219627267
+ 0.6559973295044734
+ 0.656468599319921
+ 0.6569394325098428
+ 0.6574098301705026
+ 0.6578797933936803
+ 0.6583493232666978
+ 0.6588184208724435
+ 0.6592870872893981
+ 0.6597553235916588
+ 0.660223130848964
+ 0.6606905101267186
+ 0.6611574624860173
+ 0.6616239889836691
+ 0.6620900906722215
+ 0.6625557685999844
+ 0.6630210238110531
+ 0.6634858573453323
+ 0.6639502702385592
+ 0.6644142635223268
+ 0.6648778382241065
+ 0.6653409953672712
+ 0.6658037359711182
+ 0.666266061050891
+ 0.6667279716178021
+ 0.6671894686790549
+ 0.6676505532378664
+ 0.6681112262934876
+ 0.6685714888412271
+ 0.6690313418724714
+ 0.669490786374706
+ 0.6699498233315381
+ 0.6704084537227161
+ 0.6708666785241519
+ 0.6713244987079406
+ 0.6717819152423823
+ 0.6722389290920013
+ 0.6726955412175679
+ 0.6731517525761174
+ 0.6736075641209708
+ 0.6740629768017552
+ 0.6745179915644224
+ 0.6749726093512699
+ 0.6754268311009598
+ 0.6758806577485381
+ 0.6763340902254544
+ 0.6767871294595809
+ 0.677239776375231
+ 0.6776920318931791
+ 0.6781438969306786
+ 0.6785953724014809
+ 0.679046459215854
+ 0.6794971582806004
+ 0.6799474704990758
+ 0.6803973967712075
+ 0.6808469379935113
+ 0.681296095059111
+ 0.6817448688577551
+ 0.6821932602758344
+ 0.6826412701964003
+ 0.6830888994991816
+ 0.6835361490606021
+ 0.6839830197537975
+ 0.684429512448633
+ 0.6848756280117199
+ 0.6853213673064323
+ 0.6857667311929244
+ 0.6862117205281468
+ 0.6866563361658626
+ 0.6871005789566649
+ 0.6875444497479918
+ 0.6879879493841439
+ 0.6884310787062992
+ 0.68887383855253
+ 0.6893162297578187
+ 0.6897582531540725
+ 0.6901999095701408
+ 0.690641199831829
+ 0.6910821247619159
+ 0.6915226851801671
+ 0.6919628819033519
+ 0.692402715745257
+ 0.6928421875167031
+ 0.693281298025559
+ 0.6937200480767561
+ 0.6941584384723043
+ 0.6945964700113061
+ 0.695034143489971
+ 0.6954714597016298
+ 0.6959084194367504
+ 0.6963450234829502
+ 0.696781272625012
+ 0.697217167644897
+ 0.6976527093217595
+ 0.6980878984319602
+ 0.6985227357490809
+ 0.6989572220439378
+ 0.6993913580845952
+ 0.6998251446363791
+ 0.7002585824618911
+ 0.7006916723210213
+ 0.7011244149709618
+ 0.7015568111662203
+ 0.7019888616586326
+ 0.7024205671973769
+ 0.7028519285289851
+ 0.7032829463973578
+ 0.7037136215437753
+ 0.7041439547069109
+ 0.7045739466228449
+ 0.7050035980250752
+ 0.7054329096445309
+ 0.7058618822095851
+ 0.7062905164460667
+ 0.7067188130772725
+ 0.7071467728239802
+ 0.7075743964044601
+ 0.708001684534487
+ 0.7084286379273523
+ 0.7088552572938766
+ 0.7092815433424207
+ 0.7097074967788977
+ 0.7101331183067848
+ 0.710558408627135
+ 0.7109833684385883
+ 0.7114079984373836
+ 0.7118322993173697
+ 0.7122562717700176
+ 0.7126799164844306
+ 0.7131032341473562
+ 0.7135262254431971
+ 0.7139488910540225
+ 0.7143712316595785
+ 0.7147932479373
+ 0.715214940562321
+ 0.7156363102074853
+ 0.7160573575433575
+ 0.7164780832382337
+ 0.7168984879581524
+ 0.7173185723669041
+ 0.7177383371260433
+ 0.7181577828948973
+ 0.718576910330578
+ 0.7189957200879913
+ 0.7194142128198479
+ 0.7198323891766729
+ 0.7202502498068166
+ 0.7206677953564643
+ 0.721085026469646
+ 0.7215019437882471
+ 0.721918547952017
+ 0.722334839598581
+ 0.7227508193634478
+ 0.7231664878800207
+ 0.7235818457796069
+ 0.7239968936914271
+ 0.7244116322426246
+ 0.7248260620582758
+ 0.7252401837613989
+ 0.7256539979729629
+ 0.726067505311898
+ 0.7264807063951044
+ 0.7268936018374613
+ 0.7273061922518361
+ 0.7277184782490941
+ 0.7281304604381066
+ 0.7285421394257607
+ 0.728953515816968
+ 0.7293645902146736
+ 0.7297753632198648
+ 0.7301858354315799
+ 0.7305960074469169
+ 0.7310058798610428
+ 0.7314154532672014
+ 0.7318247282567221
+ 0.7322337054190293
+ 0.7326423853416497
+ 0.7330507686102217
+ 0.7334588558085031
+ 0.73386664751838
+ 0.7342741443198749
+ 0.7346813467911548
+ 0.73508825550854
+ 0.7354948710465111
+ 0.735901193977719
+ 0.7363072248729909
+ 0.7367129643013398
+ 0.7371184128299723
+ 0.7375235710242953
+ 0.737928439447926
+ 0.7383330186626975
+ 0.7387373092286689
+ 0.7391413117041312
+ 0.7395450266456158
+ 0.7399484546079022
+ 0.7403515961440256
+ 0.7407544518052843
+ 0.7411570221412477
+ 0.7415593076997634
+ 0.7419613090269644
+ 0.7423630266672778
+ 0.7427644611634306
+ 0.7431656130564579
+ 0.7435664828857104
+ 0.7439670711888607
+ 0.744367378501912
+ 0.7447674053592039
+ 0.7451671522934205
+ 0.7455666198355965
+ 0.7459658085151255
+ 0.7463647188597662
+ 0.7467633513956498
+ 0.7471617066472862
+ 0.7475597851375722
+ 0.7479575873877972
+ 0.7483551139176509
+ 0.7487523652452291
+ 0.7491493418870419
+ 0.7495460443580189
+ 0.7499424731715167
+ 0.7503386288393262
+ 0.7507345118716775
+ 0.751130122777248
+ 0.7515254620631685
+ 0.7519205302350292
+ 0.752315327796887
+ 0.7527098552512715
+ 0.7531041130991917
+ 0.7534981018401414
+ 0.7538918219721071
+ 0.7542852739915732
+ 0.7546784583935284
+ 0.7550713756714725
+ 0.7554640263174218
+ 0.7558564108219162
+ 0.7562485296740245
+ 0.7566403833613508
+ 0.7570319723700408
+ 0.7574232971847877
+ 0.7578143582888381
+ 0.7582051561639983
+ 0.7585956912906398
+ 0.7589859641477052
+ 0.7593759752127148
+ 0.7597657249617719
+ 0.7601552138695682
+ 0.7605444424093908
+ 0.760933411053127
+ 0.7613221202712702
+ 0.7617105705329256
+ 0.7620987623058164
+ 0.7624866960562886
+ 0.7628743722493174
+ 0.7632617913485118
+ 0.7636489538161217
+ 0.7640358601130418
+ 0.7644225106988182
+ 0.764808906031653
+ 0.7651950465684108
+ 0.7655809327646229
+ 0.765966565074494
+ 0.7663519439509066
+ 0.7667370698454264
+ 0.7671219432083081
+ 0.7675065644885001
+ 0.7678909341336503
+ 0.768275052590111
+ 0.7686589203029439
+ 0.7690425377159261
+ 0.7694259052715542
+ 0.7698090234110497
+ 0.770191892574365
+ 0.7705745132001871
+ 0.7709568857259431
+ 0.7713390105878063
+ 0.7717208882206993
+ 0.7721025190583006
+ 0.7724839035330485
+ 0.7728650420761464
+ 0.7732459351175679
+ 0.7736265830860611
+ 0.7740069864091542
+ 0.7743871455131596
+ 0.7747670608231787
+ 0.7751467327631073
+ 0.77552616175564
+ 0.7759053482222747
+ 0.7762842925833175
+ 0.7766629952578874
+ 0.7770414566639211
+ 0.7774196772181768
+ 0.7777976573362402
+ 0.7781753974325276
+ 0.7785528979202916
+ 0.7789301592116251
+ 0.7793071817174656
+ 0.7796839658476005
+ 0.7800605120106705
+ 0.7804368206141749
+ 0.7808128920644756
+ 0.7811887267668015
+ 0.7815643251252533
+ 0.7819396875428071
+ 0.7823148144213194
+ 0.7826897061615312
+ 0.7830643631630723
+ 0.7834387858244652
+ 0.7838129745431301
+ 0.7841869297153886
+ 0.7845606517364677
+ 0.7849341410005048
+ 0.7853073979005509
+ 0.7856804228285759
+ 0.7860532161754709
+ 0.7864257783310545
+ 0.7867981096840755
+ 0.7871702106222171
+ 0.7875420815321015
+ 0.7879137227992932
+ 0.7882851348083036
+ 0.7886563179425948
+ 0.7890272725845834
+ 0.7893979991156443
+ 0.7897684979161157
+ 0.7901387693653015
+ 0.7905088138414763
+ 0.7908786317218885
+ 0.7912482233827651
+ 0.7916175891993146
+ 0.7919867295457311
+ 0.7923556447951985
+ 0.7927243353198936
+ 0.7930928014909908
+ 0.7934610436786649
+ 0.7938290622520949
+ 0.7941968575794689
+ 0.794564430027986
+ 0.7949317799638616
+ 0.7952989077523296
+ 0.7956658137576477
+ 0.7960324983430992
+ 0.7963989618709981
+ 0.7967652047026921
+ 0.7971312271985656
+ 0.7974970297180445
+ 0.7978626126195986
+ 0.798227976260746
+ 0.7985931209980558
+ 0.798958047187152
+ 0.7993227551827173
+ 0.7996872453384957
+ 0.800051518007297
+ 0.8004155735409991
+ 0.8007794122905524
+ 0.8011430346059825
+ 0.801506440836394
+ 0.8018696313299735
+ 0.8022326064339932
+ 0.8025953664948146
+ 0.8029579118578904
+ 0.80332024286777
+ 0.8036823598681007
+ 0.8040442632016317
+ 0.8044059532102183
+ 0.8047674302348236
+ 0.8051286946155228
+ 0.8054897466915057
+ 0.8058505868010807
+ 0.8062112152816772
+ 0.8065716324698489
+ 0.8069318387012776
+ 0.8072918343107752
+ 0.8076516196322884
+ 0.8080111949989
+ 0.8083705607428333
+ 0.8087297171954546
+ 0.8090886646872766
+ 0.8094474035479607
+ 0.8098059341063215
+ 0.8101642566903283
+ 0.8105223716271085
+ 0.8108802792429515
+ 0.8112379798633105
+ 0.8115954738128058
+ 0.8119527614152287
+ 0.8123098429935426
+ 0.8126667188698878
+ 0.8130233893655835
+ 0.8133798548011301
+ 0.8137361154962135
+ 0.8140921717697069
+ 0.8144480239396743
+ 0.8148036723233726
+ 0.8151591172372552
+ 0.8155143589969746
+ 0.8158693979173848
+ 0.8162242343125445
+ 0.8165788684957203
+ 0.8169333007793881
+ 0.8172875314752374
+ 0.8176415608941731
+ 0.8179953893463187
+ 0.8183490171410186
+ 0.8187024445868412
+ 0.8190556719915816
+ 0.8194086996622637
+ 0.8197615279051436
+ 0.8201141570257121
+ 0.8204665873286969
+ 0.8208188191180658
+ 0.8211708526970289
+ 0.8215226883680417
+ 0.8218743264328068
+ 0.8222257671922779
+ 0.8225770109466612
+ 0.8229280579954183
+ 0.8232789086372687
+ 0.823629563170193
+ 0.823980021891434
+ 0.8243302850975011
+ 0.824680353084171
+ 0.8250302261464918
+ 0.8253799045787843
+ 0.8257293886746447
+ 0.8260786787269478
+ 0.8264277750278487
+ 0.8267766778687853
+ 0.8271253875404814
+ 0.8274739043329481
+ 0.8278222285354871
+ 0.8281703604366931
+ 0.8285183003244552
+ 0.8288660484859602
+ 0.8292136052076953
+ 0.8295609707754489
+ 0.8299081454743148
+ 0.8302551295886935
+ 0.8306019234022944
+ 0.8309485271981389
+ 0.8312949412585622
+ 0.8316411658652154
+ 0.8319872012990682
+ 0.8323330478404116
+ 0.8326787057688588
+ 0.8330241753633489
+ 0.8333694569021484
+ 0.8337145506628533
+ 0.8340594569223921
+ 0.8344041759570275
+ 0.8347487080423587
+ 0.8350930534533233
+ 0.8354372124642
+ 0.8357811853486108
+ 0.8361249723795225
+ 0.83646857382925
+ 0.836811989969457
+ 0.8371552210711598
+ 0.8374982674047278
+ 0.8378411292398871
+ 0.8381838068457216
+ 0.8385263004906756
+ 0.8388686104425556
+ 0.8392107369685327
+ 0.8395526803351449
+ 0.8398944408082982
+ 0.8402360186532699
+ 0.8405774141347099
+ 0.8409186275166429
+ 0.8412596590624704
+ 0.841600509034973
+ 0.8419411776963124
+ 0.8422816653080328
+ 0.8426219721310639
+ 0.8429620984257221
+ 0.8433020444517129
+ 0.8436418104681328
+ 0.843981396733471
+ 0.8443208035056121
+ 0.8446600310418373
+ 0.8449990795988267
+ 0.845337949432661
+ 0.8456766407988241
+ 0.8460151539522043
+ 0.8463534891470962
+ 0.8466916466372033
+ 0.8470296266756395
+ 0.8473674295149308
+ 0.8477050554070176
+ 0.848042504603256
+ 0.8483797773544207
+ 0.8487168739107056
+ 0.8490537945217268
+ 0.8493905394365233
+ 0.8497271089035602
+ 0.8500635031707294
+ 0.8503997224853518
+ 0.8507357670941794
+ 0.851071637243397
+ 0.8514073331786233
+ 0.8517428551449141
+ 0.8520782033867625
+ 0.8524133781481021
+ 0.8527483796723079
+ 0.8530832082021981
+ 0.8534178639800365
+ 0.8537523472475336
+ 0.8540866582458488
+ 0.8544207972155916
+ 0.854754764396824
+ 0.8550885600290615
+ 0.8554221843512757
+ 0.8557556376018954
+ 0.8560889200188083
+ 0.8564220318393629
+ 0.8567549733003701
+ 0.857087744638105
+ 0.8574203460883085
+ 0.8577527778861891
+ 0.8580850402664241
+ 0.8584171334631621
+ 0.8587490577100235
+ 0.8590808132401035
+ 0.8594124002859729
+ 0.8597438190796793
+ 0.8600750698527501
+ 0.8604061528361928
+ 0.8607370682604977
+ 0.8610678163556381
+ 0.8613983973510735
+ 0.8617288114757501
+ 0.862059058958103
+ 0.8623891400260572
+ 0.8627190549070298
+ 0.8630488038279313
+ 0.8633783870151666
+ 0.8637078046946379
+ 0.8640370570917446
+ 0.8643661444313865
+ 0.8646950669379639
+ 0.8650238248353802
+ 0.8653524183470427
+ 0.8656808476958646
+ 0.8660091131042662
+ 0.8663372147941767
+ 0.8666651529870353
+ 0.8669929279037932
+ 0.8673205397649147
+ 0.8676479887903787
+ 0.8679752751996808
+ 0.8683023992118335
+ 0.8686293610453693
+ 0.8689561609183405
+ 0.8692827990483218
+ 0.8696092756524118
+ 0.8699355909472336
+ 0.8702617451489367
+ 0.8705877384731985
+ 0.870913571135226
+ 0.8712392433497564
+ 0.8715647553310594
+ 0.8718901072929378
+ 0.8722152994487299
+ 0.8725403320113096
+ 0.8728652051930895
+ 0.8731899192060203
+ 0.8735144742615938
+ 0.8738388705708438
+ 0.8741631083443467
+ 0.8744871877922242
+ 0.8748111091241438
+ 0.8751348725493204
+ 0.8754584782765173
+ 0.8757819265140481
+ 0.8761052174697779
+ 0.8764283513511243
+ 0.8767513283650591
+ 0.8770741487181097
+ 0.87739681261636
+ 0.877719320265452
+ 0.8780416718705868
+ 0.8783638676365266
+ 0.8786859077675956
+ 0.8790077924676806
+ 0.8793295219402338
+ 0.879651096388273
+ 0.8799725160143826
+ 0.8802937810207161
+ 0.8806148916089963
+ 0.8809358479805174
+ 0.8812566503361453
+ 0.8815772988763196
+ 0.8818977938010547
+ 0.882218135309941
+ 0.8825383236021459
+ 0.8828583588764157
+ 0.8831782413310761
+ 0.8834979711640337
+ 0.8838175485727777
+ 0.88413697375438
+ 0.8844562469054978
+ 0.8847753682223738
+ 0.8850943379008376
+ 0.8854131561363074
+ 0.8857318231237906
+ 0.8860503390578853
+ 0.8863687041327816
+ 0.8866869185422621
+ 0.8870049824797042
+ 0.8873228961380802
+ 0.8876406597099595
+ 0.8879582733875087
+ 0.8882757373624933
+ 0.8885930518262792
+ 0.8889102169698333
+ 0.8892272329837247
+ 0.8895441000581263
+ 0.8898608183828154
+ 0.8901773881471753
+ 0.890493809540196
+ 0.8908100827504757
+ 0.8911262079662217
+ 0.8914421853752514
+ 0.891758015164994
+ 0.892073697522491
+ 0.8923892326343977
+ 0.8927046206869839
+ 0.8930198618661355
+ 0.893334956357355
+ 0.8936499043457634
+ 0.8939647060161005
+ 0.8942793615527264
+ 0.8945938711396225
+ 0.8949082349603926
+ 0.8952224531982639
+ 0.8955365260360881
+ 0.8958504536563425
+ 0.8961642362411314
+ 0.896477873972186
+ 0.8967913670308673
+ 0.8971047155981652
+ 0.8974179198547008
+ 0.8977309799807273
+ 0.8980438961561307
+ 0.8983566685604306
+ 0.8986692973727824
+ 0.898981782771977
+ 0.8992941249364425
+ 0.8996063240442449
+ 0.8999183802730895
+ 0.9002302938003218
+ 0.9005420648029282
+ 0.9008536934575374
+ 0.9011651799404212
+ 0.9014765244274955
+ 0.9017877270943214
+ 0.9020987881161061
+ 0.9024097076677038
+ 0.9027204859236169
+ 0.9030311230579967
+ 0.9033416192446452
+ 0.9036519746570146
+ 0.9039621894682095
+ 0.9042722638509877
+ 0.9045821979777603
+ 0.9048919920205939
+ 0.9052016461512107
+ 0.9055111605409897
+ 0.9058205353609676
+ 0.9061297707818401
+ 0.9064388669739623
+ 0.90674782410735
+ 0.9070566423516802
+ 0.9073653218762928
+ 0.9076738628501909
+ 0.9079822654420421
+ 0.9082905298201789
+ 0.9085986561526003
+ 0.908906644606972
+ 0.9092144953506281
+ 0.9095222085505715
+ 0.9098297843734748
+ 0.9101372229856814
+ 0.9104445245532061
+ 0.9107516892417369
+ 0.9110587172166342
+ 0.9113656086429334
+ 0.9116723636853452
+ 0.9119789825082559
+ 0.9122854652757291
+ 0.9125918121515061
+ 0.9128980232990069
+ 0.9132040988813314
+ 0.9135100390612594
+ 0.9138158440012526
+ 0.9141215138634546
+ 0.9144270488096922
+ 0.9147324490014759
+ 0.9150377146000013
+ 0.9153428457661492
+ 0.9156478426604875
+ 0.9159527054432709
+ 0.9162574342744423
+ 0.9165620293136338
+ 0.9168664907201675
+ 0.9171708186530557
+ 0.9174750132710026
+ 0.9177790747324047
+ 0.9180830031953515
+ 0.9183867988176267
+ 0.9186904617567087
+ 0.9189939921697715
+ 0.9192973902136856
+ 0.9196006560450188
+ 0.9199037898200372
+ 0.920206791694705
+ 0.920509661824687
+ 0.9208124003653481
+ 0.9211150074717542
+ 0.9214174832986738
+ 0.921719828000578
+ 0.9220220417316415
+ 0.9223241246457436
+ 0.922626076896469
+ 0.9229278986371079
+ 0.9232295900206577
+ 0.9235311511998234
+ 0.9238325823270181
+ 0.9241338835543643
+ 0.9244350550336942
+ 0.9247360969165507
+ 0.9250370093541881
+ 0.9253377924975732
+ 0.925638446497385
+ 0.9259389715040172
+ 0.926239367667577
+ 0.9265396351378876
+ 0.9268397740644876
+ 0.9271397845966326
+ 0.9274396668832955
+ 0.9277394210731674
+ 0.9280390473146584
+ 0.9283385457558984
+ 0.9286379165447373
+ 0.9289371598287465
+ 0.9292362757552189
+ 0.9295352644711706
+ 0.9298341261233404
+ 0.9301328608581911
+ 0.930431468821911
+ 0.930729950160413
+ 0.9310283050193365
+ 0.9313265335440483
+ 0.9316246358796418
+ 0.9319226121709395
+ 0.9322204625624928
+ 0.9325181871985825
+ 0.93281578622322
+ 0.9331132597801479
+ 0.9334106080128407
+ 0.933707831064505
+ 0.934004929078081
+ 0.9343019021962424
+ 0.9345987505613981
+ 0.9348954743156915
+ 0.9351920736010028
+ 0.9354885485589478
+ 0.9357848993308805
+ 0.9360811260578924
+ 0.9363772288808135
+ 0.9366732079402139
+ 0.936969063376403
+ 0.9372647953294306
+ 0.9375604039390888
+ 0.9378558893449107
+ 0.9381512516861726
+ 0.938446491101894
+ 0.9387416077308385
+ 0.9390366017115138
+ 0.9393314731821732
+ 0.9396262222808162
+ 0.9399208491451883
+ 0.9402153539127824
+ 0.9405097367208394
+ 0.9408039977063486
+ 0.9410981370060484
+ 0.941392154756427
+ 0.9416860510937228
+ 0.9419798261539257
+ 0.9422734800727767
+ 0.9425670129857693
+ 0.94286042502815
+ 0.9431537163349191
+ 0.9434468870408304
+ 0.9437399372803928
+ 0.944032867187871
+ 0.9443256768972852
+ 0.9446183665424124
+ 0.9449109362567867
+ 0.9452033861737003
+ 0.9454957164262036
+ 0.9457879271471067
+ 0.9460800184689783
+ 0.9463719905241484
+ 0.9466638434447073
+ 0.946955577362507
+ 0.9472471924091616
+ 0.9475386887160476
+ 0.9478300664143048
+ 0.9481213256348374
+ 0.9484124665083137
+ 0.9487034891651663
+ 0.9489943937355948
+ 0.949285180349564
+ 0.9495758491368059
+ 0.9498664002268197
+ 0.9501568337488725
+ 0.9504471498320003
+ 0.9507373486050071
+ 0.9510274301964684
+ 0.9513173947347283
+ 0.9516072423479026
+ 0.9518969731638777
+ 0.9521865873103129
+ 0.9524760849146393
+ 0.9527654661040613
+ 0.9530547310055572
+ 0.9533438797458785
+ 0.9536329124515527
+ 0.9539218292488819
+ 0.9542106302639443
+ 0.9544993156225939
+ 0.9547878854504627
+ 0.955076339872959
+ 0.9553646790152702
+ 0.9556529030023618
+ 0.9559410119589785
+ 0.9562290060096444
+ 0.9565168852786642
+ 0.9568046498901231
+ 0.9570922999678878
+ 0.957379835635607
+ 0.957667257016711
+ 0.9579545642344133
+ 0.9582417574117114
+ 0.9585288366713861
+ 0.958815802136003
+ 0.9591026539279123
+ 0.9593893921692501
+ 0.9596760169819384
+ 0.9599625284876857
+ 0.9602489268079876
+ 0.9605352120641274
+ 0.9608213843771763
+ 0.9611074438679942
+ 0.9613933906572304
+ 0.9616792248653235
+ 0.9619649466125021
+ 0.9622505560187858
+ 0.9625360532039854
+ 0.9628214382877031
+ 0.9631067113893333
+ 0.9633918726280634
+ 0.9636769221228733
+ 0.9639618599925374
+ 0.9642466863556235
+ 0.9645314013304943
+ 0.9648160050353082
+ 0.9651004975880183
+ 0.9653848791063745
+ 0.965669149707923
+ 0.9659533095100074
+ 0.9662373586297682
+ 0.9665212971841449
+ 0.966805125289875
+ 0.9670888430634951
+ 0.9673724506213414
+ 0.96765594807955
+ 0.9679393355540574
+ 0.9682226131606017
+ 0.9685057810147212
+ 0.9687888392317571
+ 0.9690717879268526
+ 0.9693546272149539
+ 0.9696373572108102
+ 0.9699199780289746
+ 0.9702024897838045
+ 0.9704848925894619
+ 0.9707671865599142
+ 0.971049371808934
+ 0.9713314484501004
+ 0.9716134165967986
+ 0.9718952763622214
+ 0.9721770278593683
+ 0.9724586712010473
+ 0.9727402064998744
+ 0.9730216338682746
+ 0.9733029534184822
+ 0.9735841652625409
+ 0.9738652695123048
+ 0.9741462662794388
+ 0.9744271556754182
+ 0.9747079378115305
+ 0.9749886127988746
+ 0.9752691807483621
+ 0.9755496417707171
+ 0.9758299959764772
+ 0.9761102434759937
+ 0.976390384379432
+ 0.9766704187967717
+ 0.9769503468378077
+ 0.9772301686121504
+ 0.9775098842292259
+ 0.9777894937982764
+ 0.9780689974283613
+ 0.9783483952283566
+ 0.9786276873069558
+ 0.9789068737726715
+ 0.979185954733833
+ 0.9794649302985897
+ 0.9797438005749096
+ 0.9800225656705807
+ 0.9803012256932108
+ 0.9805797807502287
+ 0.9808582309488832
+ 0.9811365763962453
+ 0.9814148171992073
+ 0.9816929534644839
+ 0.9819709852986122
+ 0.9822489128079522
+ 0.9825267360986872
+ 0.9828044552768246
+ 0.9830820704481956
+ 0.9833595817184567
+ 0.9836369891930884
+ 0.9839142929773971
+ 0.9841914931765151
+ 0.984468589895401
+ 0.9847455832388395
+ 0.9850224733114427
+ 0.9852992602176499
+ 0.9855759440617281
+ 0.9858525249477729
+ 0.9861290029797077
+ 0.9864053782612857
+ 0.9866816508960891
+ 0.9869578209875297
+ 0.9872338886388495
+ 0.9875098539531212
+ 0.9877857170332479
+ 0.9880614779819646
+ 0.9883371369018378
+ 0.9886126938952658
+ 0.9888881490644795
+ 0.9891635025115427
+ 0.9894387543383519
+ 0.989713904646638
+ 0.9899889535379652
+ 0.9902639011137321
+ 0.9905387474751722
+ 0.990813492723354
+ 0.9910881369591814
+ 0.9913626802833942
+ 0.991637122796568
+ 0.9919114645991155
+ 0.9921857057912861
+ 0.9924598464731665
+ 0.9927338867446808
+ 0.9930078267055914
+ 0.993281666455499
+ 0.9935554060938433
+ 0.9938290457199025
+ 0.9941025854327948
+ 0.9943760253314781
+ 0.9946493655147505
+ 0.9949226060812503
+ 0.9951957471294574
+ 0.9954687887576922
+ 0.9957417310641171
+ 0.9960145741467364
+ 0.9962873181033972
+ 0.9965599630317882
+ 0.996832509029442
+ 0.9971049561937345
+ 0.9973773046218847
+ 0.9976495544109562
+ 0.9979217056578572
+ 0.99819375845934
+ 0.9984657129120024
+ 0.9987375691122878
+ 0.9990093271564849
+ 0.9992809871407292
+ 0.9995525491610021
+ 0.9998240133131321
+ 1.0000953796927947
+ 1.0003666483955125
+ 1.000637819516657
+ 1.0009088931514474
+ 1.0011798693949505
+ 1.0014507483420831
+ 1.0017215300876108
+ 1.0019922147261482
+ 1.0022628023521607
+ 1.002533293059963
+ 1.0028036869437207
+ 1.00307398409745
+ 1.0033441846150188
+ 1.0036142885901453
+ 1.003884296116401
+ 1.004154207287208
+ 1.004424022195842
+ 1.0046937409354313
+ 1.0049633635989568
+ 1.005232890279253
+ 1.0055023210690084
+ 1.0057716560607652
+ 1.0060408953469202
+ 1.0063100390197246
+ 1.0065790871712854
+ 1.0068480398935635
+ 1.0071168972783773
+ 1.0073856594173993
+ 1.0076543264021594
+ 1.0079228983240436
+ 1.008191375274295
+ 1.0084597573440142
+ 1.0087280446241587
+ 1.0089962372055439
+ 1.0092643351788437
+ 1.0095323386345905
+ 1.0098002476631749
+ 1.0100680623548466
+ 1.010335782799715
+ 1.0106034090877494
+ 1.0108709413087784
+ 1.0111383795524909
+ 1.011405723908437
+ 1.0116729744660269
+ 1.0119401313145329
+ 1.0122071945430873
+ 1.0124741642406858
+ 1.012741040496185
+ 1.0130078233983044
+ 1.013274513035626
+ 1.0135411094965943
+ 1.013807612869518
+ 1.0140740232425685
+ 1.0143403407037814
+ 1.0146065653410563
+ 1.0148726972421571
+ 1.015138736494713
+ 1.015404683186217
+ 1.0156705374040282
+ 1.0159362992353715
+ 1.016201968767337
+ 1.0164675460868813
+ 1.0167330312808274
+ 1.0169984244358645
+ 1.0172637256385495
+ 1.0175289349753065
+ 1.0177940525324263
+ 1.0180590783960686
+ 1.0183240126522608
+ 1.0185888553868983
+ 1.0188536066857459
+ 1.0191182666344365
+ 1.019382835318473
+ 1.0196473128232275
+ 1.0199116992339416
+ 1.0201759946357278
+ 1.0204401991135679
+ 1.0207043127523148
+ 1.020968335636692
+ 1.021232267851295
+ 1.0214961094805899
+ 1.021759860608914
+ 1.0220235213204782
+ 1.0222870916993643
+ 1.022550571829527
+ 1.0228139617947936
+ 1.0230772616788646
+ 1.023340471565314
+ 1.023603591537589
+ 1.023866621679011
+ 1.024129562072775
+ 1.024392412801951
+ 1.024655173949483
+ 1.0249178455981898
+ 1.0251804278307666
+ 1.0254429207297822
+ 1.0257053243776828
+ 1.0259676388567889
+ 1.0262298642492986
+ 1.0264920006372855
+ 1.0267540481027004
+ 1.027016006727371
+ 1.027277876593002
+ 1.0275396577811753
+ 1.0278013503733516
+ 1.0280629544508686
+ 1.0283244700949423
+ 1.0285858973866675
+ 1.028847236407018
+ 1.0291084872368461
+ 1.0293696499568834
+ 1.029630724647741
+ 1.0298917113899098
+ 1.0301526102637606
+ 1.0304134213495448
+ 1.030674144727394
+ 1.0309347804773203
+ 1.0311953286792173
+ 1.0314557894128593
+ 1.0317161627579028
+ 1.031976448793885
+ 1.0322366476002254
+ 1.0324967592562264
+ 1.032756783841072
+ 1.0330167214338295
+ 1.0332765721134487
+ 1.0335363359587626
+ 1.0337960130484876
+ 1.0340556034612236
+ 1.0343151072754555
+ 1.0345745245695503
+ 1.0348338554217613
+ 1.0350930999102252
+ 1.035352258112964
+ 1.0356113301078846
+ 1.0358703159727791
+ 1.0361292157853257
+ 1.0363880296230874
+ 1.0366467575635143
+ 1.0369053996839417
+ 1.0371639560615924
+ 1.0374224267735748
+ 1.0376808118968848
+ 1.0379391115084056
+ 1.0381973256849077
+ 1.0384554545030489
+ 1.0387134980393748
+ 1.0389714563703196
+ 1.0392293295722057
+ 1.0394871177212435
+ 1.0397448208935325
+ 1.040002439165061
+ 1.0402599726117074
+ 1.0405174213092379
+ 1.0407747853333094
+ 1.0410320647594684
+ 1.0412892596631518
+ 1.0415463701196865
+ 1.0418033962042899
+ 1.04206033799207
+ 1.0423171955580266
+ 1.0425739689770495
+ 1.0428306583239209
+ 1.0430872636733142
+ 1.0433437850997944
+ 1.043600222677819
+ 1.0438565764817378
+ 1.0441128465857927
+ 1.0443690330641189
+ 1.0446251359907435
+ 1.0448811554395878
+ 1.0451370914844662
+ 1.0453929441990863
+ 1.0456487136570496
+ 1.0459043999318518
+ 1.0461600030968827
+ 1.0464155232254266
+ 1.0466709603906625
+ 1.0469263146656635
+ 1.0471815861233988
+ 1.047436774836732
+ 1.047691880878423
+ 1.0479469043211265
+ 1.0482018452373938
+ 1.0484567036996715
+ 1.0487114797803034
+ 1.0489661735515292
+ 1.0492207850854858
+ 1.0494753144542057
+ 1.0497297617296204
+ 1.0499841269835575
+ 1.0502384102877422
+ 1.0504926117137983
+ 1.050746731333246
+ 1.0510007692175047
+ 1.0512547254378923
+ 1.0515086000656249
+ 1.0517623931718163
+ 1.0520161048274812
+ 1.052269735103532
+ 1.0525232840707806
+ 1.0527767517999391
+ 1.0530301383616187
+ 1.0532834438263308
+ 1.0535366682644864
+ 1.0537898117463977
+ 1.0540428743422767
+ 1.0542958561222362
+ 1.0545487571562902
+ 1.0548015775143535
+ 1.0550543172662425
+ 1.055306976481675
+ 1.0555595552302697
+ 1.055812053581548
+ 1.0560644716049337
+ 1.056316809369752
+ 1.0565690669452301
+ 1.0568212444004998
+ 1.0570733418045937
+ 1.0573253592264482
+ 1.0575772967349033
+ 1.0578291543987015
+ 1.0580809322864897
+ 1.058332630466818
+ 1.0585842490081403
+ 1.0588357879788157
+ 1.0590872474471063
+ 1.0593386274811794
+ 1.059589928149107
+ 1.0598411495188658
+ 1.0600922916583375
+ 1.0603433546353094
+ 1.0605943385174739
+ 1.0608452433724287
+ 1.061096069267678
+ 1.0613468162706319
+ 1.061597484448606
+ 1.0618480738688223
+ 1.0620985845984106
+ 1.0623490167044058
+ 1.0625993702537504
+ 1.0628496453132938
+ 1.0630998419497932
+ 1.0633499602299121
+ 1.0636000002202226
+ 1.063849961987204
+ 1.0640998455972437
+ 1.0643496511166373
+ 1.0645993786115888
+ 1.0648490281482104
+ 1.065098599792523
+ 1.0653480936104567
+ 1.0655975096678498
+ 1.0658468480304508
+ 1.0660961087639167
+ 1.0663452919338143
+ 1.0665943976056202
+ 1.0668434258447208
+ 1.0670923767164127
+ 1.0673412502859023
+ 1.0675900466183066
+ 1.0678387657786534
+ 1.068087407831881
+ 1.0683359728428383
+ 1.0685844608762858
+ 1.068832871996895
+ 1.0690812062692487
+ 1.0693294637578412
+ 1.0695776445270788
+ 1.0698257486412797
+ 1.070073776164674
+ 1.0703217271614038
+ 1.0705696016955244
+ 1.0708173998310027
+ 1.071065121631719
+ 1.0713127671614662
+ 1.0715603364839505
+ 1.0718078296627913
+ 1.0720552467615208
+ 1.0723025878435857
+ 1.0725498529723456
+ 1.0727970422110746
+ 1.0730441556229602
+ 1.073291193271105
+ 1.0735381552185252
+ 1.0737850415281516
+ 1.07403185226283
+ 1.074278587485321
+ 1.0745252472582998
+ 1.0747718316443575
+ 1.0750183407059999
+ 1.0752647745056485
+ 1.0755111331056404
+ 1.0757574165682287
+ 1.076003624955582
+ 1.0762497583297856
+ 1.0764958167528407
+ 1.076741800286665
+ 1.076987708993093
+ 1.0772335429338757
+ 1.0774793021706806
+ 1.0777249867650933
+ 1.0779705967786157
+ 1.0782161322726675
+ 1.078461593308586
+ 1.0787069799476254
+ 1.0789522922509587
+ 1.0791975302796764
+ 1.079442694094787
+ 1.0796877837572179
+ 1.0799327993278143
+ 1.0801777408673399
+ 1.0804226084364776
+ 1.0806674020958293
+ 1.0809121219059152
+ 1.0811567679271754
+ 1.081401340219969
+ 1.0816458388445747
+ 1.0818902638611907
+ 1.082134615329935
+ 1.0823788933108458
+ 1.0826230978638811
+ 1.082867229048919
+ 1.0831112869257584
+ 1.0833552715541184
+ 1.0835991829936389
+ 1.0838430213038805
+ 1.0840867865443249
+ 1.0843304787743748
+ 1.084574098053354
+ 1.0848176444405084
+ 1.0850611179950043
+ 1.0853045187759307
+ 1.0855478468422977
+ 1.0857911022530378
+ 1.0860342850670055
+ 1.0862773953429776
+ 1.0865204331396534
+ 1.0867633985156542
+ 1.0870062915295249
+ 1.087249112239732
+ 1.0874918607046662
+ 1.0877345369826406
+ 1.0879771411318913
+ 1.0882196732105789
+ 1.0884621332767863
+ 1.0887045213885207
+ 1.088946837603713
+ 1.0891890819802181
+ 1.0894312545758145
+ 1.0896733554482059
+ 1.0899153846550196
+ 1.0901573422538071
+ 1.0903992283020454
+ 1.0906410428571356
+ 1.0908827859764045
+ 1.0911244577171026
+ 1.0913660581364069
+ 1.0916075872914195
+ 1.0918490452391667
+ 1.092090432036602
+ 1.0923317477406036
+ 1.0925729924079763
+ 1.0928141660954502
+ 1.0930552688596817
+ 1.0932963007572536
+ 1.0935372618446753
+ 1.0937781521783816
+ 1.0940189718147357
+ 1.0942597208100264
+ 1.0945003992204694
+ 1.0947410071022081
+ 1.0949815445113125
+ 1.09522201150378
+ 1.095462408135536
+ 1.0957027344624324
+ 1.09594299054025
+ 1.0961831764246965
+ 1.096423292171408
+ 1.0966633378359483
+ 1.0969033134738104
+ 1.0971432191404142
+ 1.0973830548911094
+ 1.0976228207811733
+ 1.097862516865813
+ 1.0981021432001628
+ 1.0983416998392876
+ 1.0985811868381812
+ 1.0988206042517652
+ 1.0990599521348925
+ 1.0992992305423444
+ 1.0995384395288315
+ 1.0997775791489952
+ 1.1000166494574062
+ 1.100255650508565
+ 1.1004945823569023
+ 1.1007334450567794
+ 1.1009722386624876
+ 1.1012109632282487
+ 1.1014496188082155
+ 1.101688205456471
+ 1.1019267232270293
+ 1.1021651721738355
+ 1.1024035523507658
+ 1.102641863811628
+ 1.10288010661016
+ 1.1031182808000326
+ 1.1033563864348472
+ 1.1035944235681379
+ 1.1038323922533697
+ 1.1040702925439396
+ 1.1043081244931772
+ 1.1045458881543442
+ 1.104783583580634
+ 1.1050212108251734
+ 1.1052587699410208
+ 1.1054962609811678
+ 1.1057336839985388
+ 1.105971039045991
+ 1.1062083261763143
+ 1.106445545442232
+ 1.106682696896401
+ 1.106919780591411
+ 1.1071567965797855
+ 1.1073937449139815
+ 1.10763062564639
+ 1.1078674388293355
+ 1.108104184515076
+ 1.1083408627558051
+ 1.1085774736036487
+ 1.1088140171106686
+ 1.1090504933288599
+ 1.109286902310153
+ 1.1095232441064122
+ 1.1097595187694371
+ 1.109995726350962
+ 1.1102318669026563
+ 1.1104679404761246
+ 1.1107039471229057
+ 1.1109398868944755
+ 1.111175759842244
+ 1.111411566017557
+ 1.1116473054716962
+ 1.1118829782558788
+ 1.1121185844212587
+ 1.112354124018924
+ 1.1125895970999011
+ 1.112825003715151
+ 1.1130603439155715
+ 1.1132956177519973
+ 1.113530825275199
+ 1.113765966535884
+ 1.1140010415846973
+ 1.1142360504722193
+ 1.1144709932489685
+ 1.1147058699654
+ 1.1149406806719064
+ 1.1151754254188175
+ 1.1154101042564002
+ 1.1156447172348596
+ 1.1158792644043378
+ 1.1161137458149148
+ 1.1163481615166087
+ 1.1165825115593753
+ 1.116816795993109
+ 1.1170510148676414
+ 1.117285168232743
+ 1.1175192561381224
+ 1.1177532786334274
+ 1.1179872357682434
+ 1.1182211275920952
+ 1.1184549541544464
+ 1.1186887155046987
+ 1.1189224116921939
+ 1.119156042766212
+ 1.1193896087759727
+ 1.1196231097706353
+ 1.1198565457992977
+ 1.1200899169109986
+ 1.1203232231547144
+ 1.1205564645793633
+ 1.1207896412338023
+ 1.121022753166828
+ 1.121255800427178
+ 1.1214887830635296
+ 1.1217217011244998
+ 1.121954554658647
+ 1.1221873437144692
+ 1.1224200683404058
+ 1.1226527285848356
+ 1.1228853244960793
+ 1.123117856122398
+ 1.1233503235119937
+ 1.12358272671301
+ 1.1238150657735309
+ 1.1240473407415819
+ 1.12427955166513
+ 1.1245116985920836
+ 1.1247437815702928
+ 1.124975800647549
+ 1.1252077558715856
+ 1.1254396472900783
+ 1.1256714749506436
+ 1.1259032389008408
+ 1.1261349391881714
+ 1.1263665758600792
+ 1.1265981489639498
+ 1.1268296585471116
+ 1.127061104656836
+ 1.1272924873403358
+ 1.127523806644768
+ 1.1277550626172308
+ 1.1279862553047673
+ 1.1282173847543615
+ 1.128448451012942
+ 1.1286794541273804
+ 1.1289103941444911
+ 1.129141271111032
+ 1.1293720850737048
+ 1.1296028360791548
+ 1.1298335241739703
+ 1.1300641494046844
+ 1.1302947118177733
+ 1.1305252114596576
+ 1.1307556483767014
+ 1.1309860226152135
+ 1.1312163342214472
+ 1.1314465832415992
+ 1.1316767697218113
+ 1.1319068937081695
+ 1.1321369552467049
+ 1.1323669543833925
+ 1.1325968911641533
+ 1.1328267656348519
+ 1.1330565778412987
+ 1.1332863278292487
+ 1.1335160156444024
+ 1.1337456413324056
+ 1.1339752049388492
+ 1.1342047065092695
+ 1.134434146089149
+ 1.1346635237239147
+ 1.1348928394589402
+ 1.1351220933395443
+ 1.1353512854109924
+ 1.135580415718495
+ 1.1358094843072097
+ 1.1360384912222394
+ 1.1362674365086336
+ 1.136496320211388
+ 1.1367251423754448
+ 1.1369539030456925
+ 1.137182602266967
+ 1.13741124008405
+ 1.1376398165416703
+ 1.1378683316845033
+ 1.1380967855571718
+ 1.1383251782042456
+ 1.138553509670241
+ 1.1387817799996227
+ 1.1390099892368013
+ 1.1392381374261358
+ 1.1394662246119323
+ 1.1396942508384444
+ 1.1399222161498734
+ 1.1401501205903686
+ 1.1403779642040268
+ 1.1406057470348927
+ 1.1408334691269593
+ 1.1410611305241674
+ 1.1412887312704056
+ 1.1415162714095117
+ 1.141743750985271
+ 1.1419711700414175
+ 1.1421985286216338
+ 1.142425826769551
+ 1.1426530645287487
+ 1.1428802419427555
+ 1.1431073590550485
+ 1.1433344159090544
+ 1.143561412548148
+ 1.1437883490156537
+ 1.144015225354845
+ 1.1442420416089447
+ 1.1444687978211248
+ 1.1446954940345064
+ 1.1449221302921613
+ 1.1451487066371095
+ 1.145375223112321
+ 1.1456016797607165
+ 1.1458280766251645
+ 1.1460544137484858
+ 1.1462806911734496
+ 1.1465069089427757
+ 1.1467330670991336
+ 1.1469591656851437
+ 1.1471852047433766
+ 1.1474111843163524
+ 1.147637104446543
+ 1.1478629651763699
+ 1.1480887665482056
+ 1.1483145086043727
+ 1.1485401913871458
+ 1.1487658149387494
+ 1.1489913793013593
+ 1.149216884517102
+ 1.1494423306280555
+ 1.1496677176762489
+ 1.1498930457036622
+ 1.1501183147522274
+ 1.150343524863827
+ 1.150568676080296
+ 1.1507937684434204
+ 1.1510188019949377
+ 1.1512437767765378
+ 1.1514686928298616
+ 1.1516935501965024
+ 1.1519183489180054
+ 1.1521430890358675
+ 1.1523677705915383
+ 1.1525923936264193
+ 1.1528169581818637
+ 1.153041464299178
+ 1.1532659120196205
+ 1.1534903013844027
+ 1.1537146324346874
+ 1.1539389052115911
+ 1.1541631197561826
+ 1.1543872761094838
+ 1.1546113743124695
+ 1.1548354144060666
+ 1.1550593964311564
+ 1.1552833204285717
+ 1.1555071864391002
+ 1.1557309945034815
+ 1.155954744662409
+ 1.1561784369565296
+ 1.1564020714264434
+ 1.1566256481127044
+ 1.1568491670558199
+ 1.157072628296251
+ 1.1572960318744125
+ 1.1575193778306732
+ 1.1577426662053556
+ 1.1579658970387363
+ 1.1581890703710462
+ 1.1584121862424699
+ 1.1586352446931463
+ 1.1588582457631686
+ 1.1590811894925845
+ 1.1593040759213964
+ 1.15952690508956
+ 1.159749677036987
+ 1.1599723918035427
+ 1.1601950494290476
+ 1.160417649953277
+ 1.160640193415961
+ 1.160862679856784
+ 1.1610851093153864
+ 1.1613074818313633
+ 1.1615297974442642
+ 1.161752056193595
+ 1.1619742581188162
+ 1.1621964032593433
+ 1.1624184916545481
+ 1.1626405233437571
+ 1.162862498366253
+ 1.1630844167612733
+ 1.1633062785680122
+ 1.1635280838256186
+ 1.1637498325731983
+ 1.163971524849812
+ 1.164193160694477
+ 1.1644147401461669
+ 1.16463626324381
+ 1.1648577300262928
+ 1.165079140532456
+ 1.1653004948010983
+ 1.1655217928709738
+ 1.1657430347807936
+ 1.1659642205692244
+ 1.1661853502748905
+ 1.1664064239363725
+ 1.1666274415922073
+ 1.1668484032808897
+ 1.16706930904087
+ 1.167290158910556
+ 1.1675109529283125
+ 1.167731691132462
+ 1.167952373561283
+ 1.168173000253011
+ 1.1683935712458404
+ 1.168614086577922
+ 1.168834546287363
+ 1.1690549504122298
+ 1.1692752989905448
+ 1.1694955920602892
+ 1.1697158296594012
+ 1.1699360118257764
+ 1.1701561385972692
+ 1.1703762100116908
+ 1.170596226106811
+ 1.170816186920357
+ 1.1710360924900147
+ 1.1712559428534275
+ 1.1714757380481973
+ 1.1716954781118842
+ 1.1719151630820066
+ 1.1721347929960413
+ 1.172354367891423
+ 1.1725738878055458
+ 1.1727933527757615
+ 1.1730127628393812
+ 1.1732321180336742
+ 1.1734514183958686
+ 1.1736706639631516
+ 1.173889854772669
+ 1.1741089908615259
+ 1.1743280722667855
+ 1.1745470990254712
+ 1.1747660711745647
+ 1.1749849887510073
+ 1.1752038517916996
+ 1.175422660333501
+ 1.1756414144132306
+ 1.1758601140676674
+ 1.1760787593335487
+ 1.1762973502475724
+ 1.176515886846396
+ 1.1767343691666363
+ 1.1769527972448695
+ 1.1771711711176323
+ 1.1773894908214209
+ 1.1776077563926914
+ 1.1778259678678602
+ 1.1780441252833036
+ 1.178262228675358
+ 1.1784802780803194
+ 1.1786982735344451
+ 1.1789162150739516
+ 1.1791341027350168
+ 1.1793519365537783
+ 1.1795697165663346
+ 1.179787442808744
+ 1.180005115317026
+ 1.1802227341271607
+ 1.1804402992750889
+ 1.1806578107967123
+ 1.180875268727893
+ 1.181092673104454
+ 1.1813100239621797
+ 1.1815273213368154
+ 1.1817445652640672
+ 1.1819617557796023
+ 1.1821788929190495
+ 1.1823959767179986
+ 1.1826130072120002
+ 1.1828299844365673
+ 1.1830469084271735
+ 1.1832637792192542
+ 1.183480596848206
+ 1.1836973613493877
+ 1.1839140727581192
+ 1.1841307311096823
+ 1.1843473364393207
+ 1.1845638887822392
+ 1.1847803881736059
+ 1.1849968346485493
+ 1.1852132282421608
+ 1.185429568989494
+ 1.185645856925564
+ 1.1858620920853478
+ 1.1860782745037854
+ 1.1862944042157793
+ 1.186510481256193
+ 1.186726505659854
+ 1.186942477461551
+ 1.1871583966960355
+ 1.187374263398022
+ 1.187590077602187
+ 1.1878058393431705
+ 1.1880215486555743
+ 1.1882372055739636
+ 1.188452810132866
+ 1.1886683623667726
+ 1.1888838623101368
+ 1.1890993099973752
+ 1.1893147054628674
+ 1.1895300487409566
+ 1.1897453398659488
+ 1.1899605788721128
+ 1.1901757657936816
+ 1.1903909006648505
+ 1.190605983519779
+ 1.19082101439259
+ 1.191035993317369
+ 1.1912509203281663
+ 1.191465795458995
+ 1.1916806187438316
+ 1.1918953902166176
+ 1.1921101099112565
+ 1.1923247778616173
+ 1.1925393941015314
+ 1.1927539586647957
+ 1.1929684715851694
+ 1.193182932896377
+ 1.1933973426321063
+ 1.1936117008260096
+ 1.1938260075117038
+ 1.194040262722769
+ 1.1942544664927506
+ 1.1944686188551574
+ 1.1946827198434637
+ 1.1948967694911075
+ 1.1951107678314914
+ 1.1953247148979824
+ 1.1955386107239128
+ 1.195752455342579
+ 1.195966248787242
+ 1.1961799910911277
+ 1.1963936822874277
+ 1.1966073224092968
+ 1.1968209114898558
+ 1.1970344495621903
+ 1.1972479366593511
+ 1.1974613728143537
+ 1.197674758060179
+ 1.1978880924297728
+ 1.1981013759560464
+ 1.198314608671876
+ 1.1985277906101037
+ 1.1987409218035365
+ 1.1989540022849474
+ 1.1991670320870738
+ 1.1993800112426198
+ 1.1995929397842549
+ 1.199805817744613
+ 1.2000186451562955
+ 1.2002314220518682
+ 1.200444148463863
+ 1.200656824424778
+ 1.200869449967077
+ 1.2010820251231897
+ 1.2012945499255114
+ 1.2015070244064041
+ 1.2017194485981957
+ 1.2019318225331799
+ 1.2021441462436164
+ 1.2023564197617322
+ 1.2025686431197191
+ 1.2027808163497367
+ 1.2029929394839098
+ 1.2032050125543303
+ 1.2034170355930565
+ 1.2036290086321129
+ 1.2038409317034904
+ 1.2040528048391475
+ 1.2042646280710083
+ 1.2044764014309648
+ 1.2046881249508736
+ 1.204899798662561
+ 1.2051114225978177
+ 1.2053229967884027
+ 1.2055345212660415
+ 1.2057459960624266
+ 1.2059574212092175
+ 1.206168796738041
+ 1.2063801226804907
+ 1.206591399068128
+ 1.2068026259324809
+ 1.2070138033050446
+ 1.207224931217283
+ 1.2074360097006251
+ 1.2076470387864693
+ 1.2078580185061805
+ 1.2080689488910918
+ 1.208279829972503
+ 1.2084906617816817
+ 1.2087014443498643
+ 1.208912177708253
+ 1.2091228618880194
+ 1.209333496920302
+ 1.2095440828362076
+ 1.2097546196668105
+ 1.2099651074431534
+ 1.2101755461962465
+ 1.2103859359570677
+ 1.2105962767565643
+ 1.210806568625651
+ 1.2110168115952102
+ 1.211227005696093
+ 1.2114371509591184
+ 1.2116472474150743
+ 1.2118572950947166
+ 1.2120672940287696
+ 1.212277244247926
+ 1.2124871457828468
+ 1.2126969986641618
+ 1.2129068029224694
+ 1.213116558588337
+ 1.2133262656922994
+ 1.2135359242648613
+ 1.2137455343364956
+ 1.2139550959376442
+ 1.214164609098718
+ 1.214374073850096
+ 1.2145834902221273
+ 1.214792858245129
+ 1.2150021779493878
+ 1.215211449365159
+ 1.215420672522667
+ 1.2156298474521063
+ 1.2158389741836393
+ 1.2160480527473982
+ 1.2162570831734847
+ 1.2164660654919692
+ 1.2166749997328925
+ 1.2168838859262636
+ 1.217092724102062
+ 1.2173015142902355
+ 1.217510256520703
+ 1.2177189508233512
+ 1.2179275972280381
+ 1.2181361957645904
+ 1.2183447464628046
+ 1.218553249352447
+ 1.218761704463254
+ 1.2189701118249312
+ 1.2191784714671547
+ 1.2193867834195704
+ 1.219595047711794
+ 1.2198032643734114
+ 1.220011433433978
+ 1.22021955492302
+ 1.220427628870033
+ 1.2206356553044837
+ 1.2208436342558084
+ 1.2210515657534138
+ 1.2212594498266764
+ 1.2214672865049443
+ 1.2216750758175343
+ 1.221882817793735
+ 1.222090512462805
+ 1.2222981598539733
+ 1.2225057599964393
+ 1.2227133129193735
+ 1.2229208186519167
+ 1.2231282772231802
+ 1.2233356886622464
+ 1.2235430529981681
+ 1.2237503702599695
+ 1.2239576404766443
+ 1.224164863677159
+ 1.2243720398904494
+ 1.2245791691454226
+ 1.2247862514709575
+ 1.2249932868959033
+ 1.2252002754490803
+ 1.2254072171592798
+ 1.225614112055265
+ 1.2258209601657697
+ 1.2260277615194988
+ 1.226234516145129
+ 1.2264412240713076
+ 1.226647885326654
+ 1.226854499939759
+ 1.2270610679391838
+ 1.2272675893534626
+ 1.2274740642110995
+ 1.2276804925405713
+ 1.2278868743703264
+ 1.2280932097287838
+ 1.2282994986443352
+ 1.228505741145344
+ 1.2287119372601445
+ 1.2289180870170433
+ 1.2291241904443195
+ 1.2293302475702226
+ 1.229536258422975
+ 1.2297422230307713
+ 1.229948141421777
+ 1.2301540136241305
+ 1.230359839665942
+ 1.230565619575294
+ 1.230771353380241
+ 1.2309770411088088
+ 1.2311826827889973
+ 1.231388278448777
+ 1.2315938281160914
+ 1.2317993318188563
+ 1.2320047895849593
+ 1.2322102014422616
+ 1.2324155674185953
+ 1.2326208875417666
+ 1.2328261618395526
+ 1.2330313903397045
+ 1.233236573069945
+ 1.2334417100579698
+ 1.233646801331447
+ 1.233851846918018
+ 1.2340568468452966
+ 1.2342618011408693
+ 1.2344667098322952
+ 1.234671572947107
+ 1.2348763905128097
+ 1.235081162556881
+ 1.2352858891067724
+ 1.2354905701899077
+ 1.2356952058336839
+ 1.2358997960654714
+ 1.2361043409126131
+ 1.2363088404024258
+ 1.2365132945621986
+ 1.2367177034191947
+ 1.2369220670006502
+ 1.2371263853337742
+ 1.2373306584457495
+ 1.237534886363732
+ 1.2377390691148515
+ 1.2379432067262106
+ 1.2381472992248856
+ 1.238351346637927
+ 1.2385553489923573
+ 1.2387593063151743
+ 1.2389632186333481
+ 1.2391670859738233
+ 1.2393709083635178
+ 1.239574685829323
+ 1.239778418398105
+ 1.2399821060967027
+ 1.240185748951929
+ 1.2403893469905711
+ 1.2405929002393898
+ 1.2407964087251198
+ 1.2409998724744702
+ 1.2412032915141236
+ 1.2414066658707363
+ 1.24160999557094
+ 1.2418132806413393
+ 1.2420165211085137
+ 1.2422197169990161
+ 1.2424228683393743
+ 1.2426259751560902
+ 1.2428290374756399
+ 1.2430320553244734
+ 1.243235028729016
+ 1.243437957715667
+ 1.2436408423107992
+ 1.243843682540761
+ 1.2440464784318757
+ 1.2442492300104395
+ 1.2444519373027245
+ 1.2446546003349765
+ 1.2448572191334168
+ 1.2450597937242407
+ 1.2452623241336185
+ 1.2454648103876953
+ 1.2456672525125905
+ 1.2458696505343994
+ 1.2460720044791902
+ 1.246274314373008
+ 1.2464765802418718
+ 1.2466788021117754
+ 1.246880980008688
+ 1.2470831139585539
+ 1.2472852039872915
+ 1.2474872501207956
+ 1.247689252384935
+ 1.2478912108055544
+ 1.2480931254084733
+ 1.2482949962194863
+ 1.2484968232643636
+ 1.24869860656885
+ 1.2489003461586667
+ 1.249102042059509
+ 1.2493036942970484
+ 1.2495053028969314
+ 1.2497068678847802
+ 1.2499083892861924
+ 1.250109867126741
+ 1.2503113014319747
+ 1.2505126922274172
+ 1.2507140395385683
+ 1.2509153433909037
+ 1.2511166038098742
+ 1.2513178208209064
+ 1.251518994449403
+ 1.2517201247207417
+ 1.251921211660277
+ 1.2521222552933382
+ 1.252323255645231
+ 1.2525242127412373
+ 1.2527251266066142
+ 1.2529259972665951
+ 1.2531268247463891
+ 1.2533276090711822
+ 1.2535283502661352
+ 1.2537290483563857
+ 1.2539297033670476
+ 1.25413031532321
+ 1.2543308842499394
+ 1.2545314101722775
+ 1.2547318931152427
+ 1.25493233310383
+ 1.2551327301630093
+ 1.2553330843177288
+ 1.2555333955929113
+ 1.255733664013457
+ 1.2559338896042425
+ 1.2561340723901202
+ 1.2563342123959194
+ 1.256534309646446
+ 1.2567343641664825
+ 1.2569343759807876
+ 1.2571343451140966
+ 1.257334271591122
+ 1.2575341554365524
+ 1.2577339966750534
+ 1.257933795331267
+ 1.2581335514298124
+ 1.2583332649952852
+ 1.2585329360522581
+ 1.2587325646252803
+ 1.2589321507388784
+ 1.2591316944175552
+ 1.259331195685791
+ 1.2595306545680431
+ 1.2597300710887456
+ 1.2599294452723095
+ 1.2601287771431229
+ 1.2603280667255508
+ 1.2605273140439361
+ 1.260726519122598
+ 1.2609256819858339
+ 1.2611248026579165
+ 1.261323881163098
+ 1.2615229175256062
+ 1.2617219117696472
+ 1.2619208639194037
+ 1.2621197739990364
+ 1.2623186420326828
+ 1.262517468044458
+ 1.262716252058455
+ 1.2629149940987439
+ 1.2631136941893717
+ 1.2633123523543641
+ 1.2635109686177237
+ 1.2637095430034304
+ 1.2639080755354426
+ 1.2641065662376956
+ 1.2643050151341026
+ 1.2645034222485543
+ 1.2647017876049196
+ 1.2649001112270448
+ 1.2650983931387543
+ 1.2652966333638498
+ 1.2654948319261115
+ 1.2656929888492967
+ 1.2658911041571412
+ 1.2660891778733587
+ 1.266287210021641
+ 1.2664852006256566
+ 1.266683149709054
+ 1.2668810572954587
+ 1.2670789234084738
+ 1.2672767480716818
+ 1.267474531308642
+ 1.2676722731428929
+ 1.2678699735979502
+ 1.2680676326973086
+ 1.2682652504644407
+ 1.2684628269227978
+ 1.2686603620958088
+ 1.2688578560068815
+ 1.2690553086794019
+ 1.269252720136734
+ 1.269450090402221
+ 1.2696474194991838
+ 1.2698447074509218
+ 1.2700419542807135
+ 1.2702391600118155
+ 1.2704363246674628
+ 1.2706334482708694
+ 1.2708305308452277
+ 1.2710275724137083
+ 1.2712245729994611
+ 1.2714215326256149
+ 1.2716184513152762
+ 1.2718153290915308
+ 1.2720121659774437
+ 1.2722089619960577
+ 1.2724057171703955
+ 1.2726024315234574
+ 1.2727991050782241
+ 1.2729957378576544
+ 1.2731923298846852
+ 1.273388881182234
+ 1.273585391773196
+ 1.2737818616804462
+ 1.2739782909268378
+ 1.2741746795352042
+ 1.274371027528357
+ 1.274567334929087
+ 1.2747636017601642
+ 1.2749598280443384
+ 1.2751560138043379
+ 1.27535215906287
+ 1.2755482638426219
+ 1.27574432816626
+ 1.2759403520564296
+ 1.2761363355357556
+ 1.276332278626842
+ 1.2765281813522729
+ 1.2767240437346106
+ 1.2769198657963976
+ 1.2771156475601566
+ 1.2773113890483878
+ 1.2775070902835728
+ 1.2777027512881718
+ 1.2778983720846246
+ 1.2780939526953505
+ 1.2782894931427493
+ 1.2784849934491995
+ 1.278680453637059
+ 1.2788758737286667
+ 1.27907125374634
+ 1.2792665937123768
+ 1.279461893649054
+ 1.279657153578629
+ 1.279852373523339
+ 1.2800475535054001
+ 1.2802426935470095
+ 1.2804377936703435
+ 1.2806328538975589
+ 1.2808278742507917
+ 1.2810228547521585
+ 1.2812177954237554
+ 1.281412696287659
+ 1.281607557365926
+ 1.2818023786805925
+ 1.2819971602536753
+ 1.2821919021071708
+ 1.282386604263056
+ 1.2825812667432883
+ 1.2827758895698043
+ 1.2829704727645217
+ 1.2831650163493382
+ 1.2833595203461317
+ 1.2835539847767603
+ 1.2837484096630625
+ 1.2839427950268576
+ 1.2841371408899442
+ 1.2843314472741025
+ 1.2845257142010924
+ 1.2847199416926545
+ 1.2849141297705091
+ 1.2851082784563583
+ 1.2853023877718839
+ 1.285496457738748
+ 1.2856904883785942
+ 1.285884479713046
+ 1.2860784317637073
+ 1.286272344552163
+ 1.2864662180999789
+ 1.286660052428701
+ 1.2868538475598565
+ 1.287047603514953
+ 1.2872413203154782
+ 1.2874349979829018
+ 1.2876286365386738
+ 1.2878222360042249
+ 1.2880157964009666
+ 1.2882093177502918
+ 1.2884028000735732
+ 1.2885962433921658
+ 1.2887896477274046
+ 1.2889830131006057
+ 1.2891763395330662
+ 1.289369627046065
+ 1.2895628756608606
+ 1.2897560853986936
+ 1.2899492562807855
+ 1.2901423883283387
+ 1.2903354815625367
+ 1.2905285360045446
+ 1.2907215516755084
+ 1.2909145285965549
+ 1.2911074667887925
+ 1.2913003662733111
+ 1.2914932270711819
+ 1.2916860492034563
+ 1.2918788326911683
+ 1.2920715775553329
+ 1.2922642838169458
+ 1.292456951496985
+ 1.2926495806164093
+ 1.2928421711961595
+ 1.2930347232571568
+ 1.293227236820305
+ 1.2934197119064894
+ 1.2936121485365755
+ 1.2938045467314117
+ 1.2939969065118273
+ 1.2941892278986336
+ 1.294381510912623
+ 1.2945737555745702
+ 1.2947659619052307
+ 1.2949581299253425
+ 1.295150259655625
+ 1.2953423511167792
+ 1.2955344043294876
+ 1.2957264193144153
+ 1.2959183960922083
+ 1.296110334683495
+ 1.2963022351088853
+ 1.2964940973889716
+ 1.2966859215443267
+ 1.296877707595507
+ 1.2970694555630498
+ 1.2972611654674748
+ 1.2974528373292837
+ 1.2976444711689594
+ 1.297836067006968
+ 1.2980276248637566
+ 1.298219144759755
+ 1.2984106267153748
+ 1.2986020707510098
+ 1.298793476887036
+ 1.2989848451438113
+ 1.299176175541676
+ 1.2993674681009524
+ 1.2995587228419452
+ 1.299749939784941
+ 1.299941118950209
+ 1.3001322603580006
+ 1.3003233640285494
+ 1.3005144299820712
+ 1.3007054582387647
+ 1.3008964488188102
+ 1.3010874017423706
+ 1.3012783170295914
+ 1.3014691947006007
+ 1.3016600347755085
+ 1.301850837274408
+ 1.302041602217374
+ 1.3022323296244644
+ 1.3024230195157194
+ 1.3026136719111618
+ 1.3028042868307972
+ 1.3029948642946134
+ 1.303185404322581
+ 1.3033759069346533
+ 1.3035663721507662
+ 1.3037567999908384
+ 1.3039471904747706
+ 1.3041375436224472
+ 1.3043278594537349
+ 1.3045181379884834
+ 1.304708379246524
+ 1.304898583247673
+ 1.3050887500117274
+ 1.305278879558468
+ 1.3054689719076589
+ 1.3056590270790458
+ 1.3058490450923586
+ 1.3060390259673094
+ 1.3062289697235934
+ 1.3064188763808888
+ 1.3066087459588567
+ 1.3067985784771414
+ 1.30698837395537
+ 1.307178132413153
+ 1.3073678538700833
+ 1.3075575383457376
+ 1.307747185859675
+ 1.3079367964314386
+ 1.3081263700805539
+ 1.3083159068265302
+ 1.3085054066888593
+ 1.3086948696870164
+ 1.3088842958404603
+ 1.309073685168633
+ 1.309263037690959
+ 1.3094523534268474
+ 1.3096416323956894
+ 1.30983087461686
+ 1.310020080109718
+ 1.3102092488936044
+ 1.3103983809878448
+ 1.3105874764117473
+ 1.3107765351846046
+ 1.3109655573256915
+ 1.3111545428542668
+ 1.311343491789573
+ 1.311532404150836
+ 1.3117212799572653
+ 1.3119101192280533
+ 1.3120989219823769
+ 1.3122876882393961
+ 1.3124764180182547
+ 1.3126651113380792
+ 1.3128537682179813
+ 1.3130423886770555
+ 1.3132309727343798
+ 1.3134195204090164
+ 1.313608031720011
+ 1.3137965066863928
+ 1.313984945327175
+ 1.3141733476613549
+ 1.3143617137079127
+ 1.314550043485813
+ 1.314738337014005
+ 1.3149265943114203
+ 1.3151148153969752
+ 1.3153030002895694
+ 1.3154911490080872
+ 1.3156792615713964
+ 1.3158673379983488
+ 1.31605537830778
+ 1.3162433825185096
+ 1.3164313506493421
+ 1.3166192827190648
+ 1.3168071787464495
+ 1.3169950387502523
+ 1.317182862749213
+ 1.3173706507620555
+ 1.3175584028074885
+ 1.3177461189042041
+ 1.3179337990708786
+ 1.3181214433261728
+ 1.3183090516887315
+ 1.318496624177184
+ 1.3186841608101434
+ 1.3188716616062073
+ 1.3190591265839573
+ 1.3192465557619597
+ 1.3194339491587648
+ 1.3196213067929072
+ 1.3198086286829065
+ 1.3199959148472655
+ 1.3201831653044724
+ 1.3203703800729991
+ 1.3205575591713026
+ 1.3207447026178234
+ 1.3209318104309873
+ 1.3211188826292042
+ 1.3213059192308687
+ 1.3214929202543595
+ 1.32167988571804
+ 1.3218668156402584
+ 1.3220537100393475
+ 1.322240568933624
+ 1.3224273923413898
+ 1.3226141802809315
+ 1.3228009327705195
+ 1.3229876498284099
+ 1.3231743314728428
+ 1.3233609777220434
+ 1.323547588594221
+ 1.3237341641075704
+ 1.3239207042802705
+ 1.3241072091304853
+ 1.3242936786763633
+ 1.3244801129360382
+ 1.324666511927628
+ 1.3248528756692362
+ 1.3250392041789505
+ 1.3252254974748436
+ 1.325411755574973
+ 1.325597978497382
+ 1.3257841662600973
+ 1.3259703188811314
+ 1.3261564363784824
+ 1.326342518770132
+ 1.3265285660740476
+ 1.3267145783081815
+ 1.3269005554904714
+ 1.3270864976388392
+ 1.3272724047711923
+ 1.3274582769054237
+ 1.3276441140594104
+ 1.3278299162510159
+ 1.328015683498087
+ 1.3282014158184576
+ 1.328387113229945
+ 1.3285727757503532
+ 1.32875840339747
+ 1.3289439961890692
+ 1.3291295541429105
+ 1.329315077276737
+ 1.329500565608279
+ 1.3296860191552502
+ 1.3298714379353516
+ 1.3300568219662676
+ 1.3302421712656693
+ 1.3304274858512128
+ 1.330612765740539
+ 1.330798010951275
+ 1.3309832215010324
+ 1.331168397407409
+ 1.331353538687988
+ 1.331538645360337
+ 1.3317237174420107
+ 1.3319087549505477
+ 1.3320937579034733
+ 1.3322787263182976
+ 1.3324636602125162
+ 1.332648559603611
+ 1.3328334245090485
+ 1.3330182549462817
+ 1.3332030509327484
+ 1.3333878124858722
+ 1.3335725396230627
+ 1.3337572323617148
+ 1.3339418907192093
+ 1.3341265147129122
+ 1.3343111043601759
+ 1.334495659678338
+ 1.3346801806847217
+ 1.3348646673966367
+ 1.3350491198313774
+ 1.3352335380062252
+ 1.335417921938446
+ 1.3356022716452929
+ 1.335786587144003
+ 1.335970868451801
+ 1.3361551155858966
+ 1.3363393285634855
+ 1.3365235074017492
+ 1.3367076521178554
+ 1.3368917627289574
+ 1.3370758392521946
+ 1.3372598817046926
+ 1.337443890103562
+ 1.3376278644659005
+ 1.3378118048087917
+ 1.3379957111493042
+ 1.3381795835044936
+ 1.3383634218914011
+ 1.3385472263270546
+ 1.338730996828467
+ 1.3389147334126383
+ 1.339098436096554
+ 1.3392821048971861
+ 1.3394657398314926
+ 1.3396493409164174
+ 1.3398329081688907
+ 1.3400164416058291
+ 1.3401999412441354
+ 1.3403834071006986
+ 1.3405668391923937
+ 1.3407502375360818
+ 1.3409336021486111
+ 1.3411169330468151
+ 1.3413002302475143
+ 1.341483493767515
+ 1.3416667236236106
+ 1.3418499198325797
+ 1.3420330824111881
+ 1.342216211376188
+ 1.3423993067443174
+ 1.3425823685323013
+ 1.3427653967568505
+ 1.3429483914346632
+ 1.343131352582423
+ 1.3433142802168005
+ 1.3434971743544528
+ 1.3436800350120235
+ 1.3438628622061422
+ 1.3440456559534257
+ 1.344228416270477
+ 1.3444111431738859
+ 1.3445938366802286
+ 1.3447764968060678
+ 1.344959123567953
+ 1.3451417169824202
+ 1.3453242770659917
+ 1.3455068038351772
+ 1.3456892973064725
+ 1.3458717574963601
+ 1.3460541844213096
+ 1.3462365780977772
+ 1.3464189385422052
+ 1.3466012657710231
+ 1.3467835598006477
+ 1.346965820647481
+ 1.347148048327914
+ 1.3473302428583225
+ 1.3475124042550701
+ 1.347694532534507
+ 1.3478766277129706
+ 1.3480586898067841
+ 1.348240718832259
+ 1.3484227148056924
+ 1.3486046777433693
+ 1.348786607661561
+ 1.348968504576526
+ 1.3491503685045094
+ 1.349332199461744
+ 1.3495139974644486
+ 1.3496957625288297
+ 1.3498774946710805
+ 1.3500591939073816
+ 1.3502408602538998
+ 1.3504224937267897
+ 1.3506040943421926
+ 1.350785662116237
+ 1.350967197065039
+ 1.3511486992047006
+ 1.3513301685513122
+ 1.3515116051209497
+ 1.3516930089296784
+ 1.3518743799935486
+ 1.3520557183285993
+ 1.352237023950856
+ 1.352418296876331
+ 1.3525995371210249
+ 1.3527807447009246
+ 1.3529619196320046
+ 1.3531430619302267
+ 1.35332417161154
+ 1.3535052486918804
+ 1.353686293187172
+ 1.3538673051133254
+ 1.354048284486239
+ 1.354229231321798
+ 1.354410145635876
+ 1.354591027444333
+ 1.3547718767630164
+ 1.3549526936077612
+ 1.3551334779943904
+ 1.3553142299387138
+ 1.3554949494565287
+ 1.3556756365636198
+ 1.3558562912757592
+ 1.3560369136087072
+ 1.3562175035782107
+ 1.3563980612000046
+ 1.3565785864898112
+ 1.35675907946334
+ 1.3569395401362885
+ 1.357119968524342
+ 1.3573003646431727
+ 1.3574807285084407
+ 1.357661060135794
+ 1.3578413595408672
+ 1.3580216267392844
+ 1.358201861746655
+ 1.358382064578578
+ 1.358562235250639
+ 1.358742373778412
+ 1.3589224801774578
+ 1.3591025544633257
+ 1.3592825966515525
+ 1.3594626067576627
+ 1.3596425847971685
+ 1.3598225307855696
+ 1.3600024447383543
+ 1.360182326670998
+ 1.360362176598964
+ 1.3605419945377035
+ 1.3607217805026557
+ 1.3609015345092472
+ 1.3610812565728931
+ 1.361260946708996
+ 1.3614406049329462
+ 1.361620231260122
+ 1.36179982570589
+ 1.3619793882856042
+ 1.3621589190146073
+ 1.3623384179082287
+ 1.3625178849817872
+ 1.362697320250588
+ 1.3628767237299262
+ 1.3630560954350832
+ 1.3632354353813292
+ 1.3634147435839223
+ 1.3635940200581091
+ 1.3637732648191232
+ 1.3639524778821874
+ 1.3641316592625115
+ 1.3643108089752944
+ 1.3644899270357227
+ 1.364669013458971
+ 1.3648480682602018
+ 1.3650270914545666
+ 1.3652060830572041
+ 1.365385043083242
+ 1.3655639715477956
+ 1.3657428684659685
+ 1.3659217338528529
+ 1.3661005677235285
+ 1.3662793700930642
+ 1.366458140976516
+ 1.3666368803889288
+ 1.3668155883453363
+ 1.3669942648607598
+ 1.367172909950209
+ 1.3673515236286815
+ 1.367530105911164
+ 1.3677086568126313
+ 1.3678871763480462
+ 1.3680656645323608
+ 1.3682441213805139
+ 1.3684225469074343
+ 1.3686009411280384
+ 1.3687793040572314
+ 1.3689576357099065
+ 1.3691359361009456
+ 1.369314205245219
+ 1.3694924431575854
+ 1.3696706498528926
+ 1.3698488253459755
+ 1.3700269696516587
+ 1.3702050827847552
+ 1.370383164760066
+ 1.370561215592381
+ 1.3707392352964785
+ 1.3709172238871252
+ 1.371095181379077
+ 1.371273107787078
+ 1.3714510031258607
+ 1.371628867410146
+ 1.3718067006546444
+ 1.3719845028740543
+ 1.372162274083063
+ 1.372340014296346
+ 1.372517723528568
+ 1.372695401794382
+ 1.3728730491084302
+ 1.3730506654853436
+ 1.3732282509397404
+ 1.3734058054862297
+ 1.373583329139408
+ 1.3737608219138606
+ 1.373938283824162
+ 1.3741157148848755
+ 1.3742931151105526
+ 1.3744704845157343
+ 1.3746478231149504
+ 1.3748251309227184
+ 1.3750024079535463
+ 1.3751796542219297
+ 1.3753568697423535
+ 1.375534054529292
+ 1.3757112085972072
+ 1.375888331960551
+ 1.376065424633764
+ 1.3762424866312752
+ 1.3764195179675034
+ 1.3765965186568554
+ 1.3767734887137277
+ 1.3769504281525056
+ 1.377127336987563
+ 1.3773042152332635
+ 1.3774810629039587
+ 1.3776578800139903
+ 1.3778346665776882
+ 1.378011422609372
+ 1.3781881481233498
+ 1.378364843133919
+ 1.3785415076553662
+ 1.378718141701967
+ 1.3788947452879856
+ 1.3790713184276757
+ 1.3792478611352812
+ 1.3794243734250329
+ 1.3796008553111527
+ 1.3797773068078505
+ 1.379953727929326
+ 1.3801301186897679
+ 1.3803064791033537
+ 1.3804828091842507
+ 1.3806591089466151
+ 1.3808353784045924
+ 1.3810116175723173
+ 1.3811878264639137
+ 1.381364005093495
+ 1.3815401534751632
+ 1.381716271623011
+ 1.3818923595511183
+ 1.382068417273556
+ 1.382244444804384
+ 1.3824204421576511
+ 1.3825964093473955
+ 1.382772346387645
+ 1.3829482532924169
+ 1.383124130075717
+ 1.3832999767515417
+ 1.383475793333876
+ 1.3836515798366944
+ 1.3838273362739608
+ 1.384003062659629
+ 1.3841787590076413
+ 1.3843544253319306
+ 1.3845300616464185
+ 1.384705667965016
+ 1.384881244301624
+ 1.385056790670133
+ 1.3852323070844224
+ 1.3854077935583615
+ 1.385583250105809
+ 1.3857586767406134
+ 1.3859340734766123
+ 1.3861094403276333
+ 1.3862847773074933
+ 1.3864600844299992
+ 1.3866353617089464
+ 1.3868106091581214
+ 1.3869858267912991
+ 1.3871610146222448
+ 1.3873361726647127
+ 1.3875113009324476
+ 1.3876863994391828
+ 1.3878614681986428
+ 1.38803650722454
+ 1.3882115165305775
+ 1.3883864961304486
+ 1.388561446037835
+ 1.388736366266409
+ 1.3889112568298325
+ 1.389086117741757
+ 1.3892609490158236
+ 1.389435750665664
+ 1.3896105227048983
+ 1.3897852651471374
+ 1.3899599780059821
+ 1.3901346612950223
+ 1.3903093150278383
+ 1.3904839392179993
+ 1.390658533879066
+ 1.390833099024587
+ 1.3910076346681026
+ 1.391182140823142
+ 1.3913566175032235
+ 1.391531064721857
+ 1.3917054824925412
+ 1.3918798708287654
+ 1.3920542297440077
+ 1.3922285592517372
+ 1.3924028593654123
+ 1.3925771300984822
+ 1.3927513714643853
+ 1.3929255834765497
+ 1.3930997661483944
+ 1.3932739194933281
+ 1.393448043524749
+ 1.3936221382560454
+ 1.3937962037005966
+ 1.393970239871771
+ 1.394144246782927
+ 1.3943182244474137
+ 1.3944921728785695
+ 1.3946660920897236
+ 1.3948399820941948
+ 1.3950138429052923
+ 1.395187674536315
+ 1.3953614770005527
+ 1.3955352503112841
+ 1.395708994481779
+ 1.395882709525298
+ 1.3960563954550897
+ 1.396230052284395
+ 1.3964036800264432
+ 1.3965772786944557
+ 1.3967508483016424
+ 1.3969243888612046
+ 1.3970979003863329
+ 1.3972713828902086
+ 1.3974448363860035
+ 1.3976182608868792
+ 1.3977916564059878
+ 1.397965022956471
+ 1.3981383605514621
+ 1.3983116692040838
+ 1.398484948927449
+ 1.3986581997346612
+ 1.398831421638814
+ 1.3990046146529918
+ 1.3991777787902688
+ 1.3993509140637101
+ 1.3995240204863706
+ 1.399697098071296
+ 1.3998701468315218
+ 1.4000431667800748
+ 1.400216157929971
+ 1.4003891202942182
+ 1.4005620538858135
+ 1.4007349587177451
+ 1.4009078348029909
+ 1.4010806821545199
+ 1.4012535007852918
+ 1.401426290708256
+ 1.4015990519363524
+ 1.4017717844825124
+ 1.4019444883596563
+ 1.4021171635806968
+ 1.4022898101585355
+ 1.4024624281060651
+ 1.4026350174361693
+ 1.4028075781617215
+ 1.4029801102955861
+ 1.4031526138506185
+ 1.4033250888396636
+ 1.4034975352755577
+ 1.4036699531711276
+ 1.4038423425391904
+ 1.4040147033925543
+ 1.4041870357440176
+ 1.4043593396063696
+ 1.4045316149923897
+ 1.4047038619148486
+ 1.4048760803865075
+ 1.405048270420118
+ 1.4052204320284225
+ 1.4053925652241543
+ 1.4055646700200368
+ 1.4057367464287853
+ 1.4059087944631043
+ 1.40608081413569
+ 1.4062528054592294
+ 1.4064247684463995
+ 1.4065967031098687
+ 1.406768609462296
+ 1.406940487516331
+ 1.4071123372846144
+ 1.4072841587797773
+ 1.407455952014442
+ 1.407627717001221
+ 1.4077994537527185
+ 1.4079711622815292
+ 1.4081428426002378
+ 1.4083144947214208
+ 1.4084861186576456
+ 1.40865771442147
+ 1.4088292820254427
+ 1.4090008214821035
+ 1.4091723328039831
+ 1.4093438160036027
+ 1.409515271093475
+ 1.4096866980861034
+ 1.4098580969939818
+ 1.4100294678295955
+ 1.4102008106054211
+ 1.4103721253339254
+ 1.4105434120275664
+ 1.410714670698793
+ 1.4108859013600452
+ 1.4110571040237545
+ 1.4112282787023427
+ 1.4113994254082227
+ 1.4115705441537985
+ 1.4117416349514653
+ 1.4119126978136094
+ 1.412083732752608
+ 1.4122547397808283
+ 1.4124257189106308
+ 1.4125966701543653
+ 1.4127675935243735
+ 1.412938489032988
+ 1.4131093566925315
+ 1.4132801965153199
+ 1.4134510085136585
+ 1.4136217926998442
+ 1.4137925490861656
+ 1.4139632776849014
+ 1.414133978508322
+ 1.4143046515686895
+ 1.4144752968782563
+ 1.4146459144492665
+ 1.414816504293955
+ 1.414987066424548
+ 1.4151576008532634
+ 1.4153281075923096
+ 1.4154985866538867
+ 1.415669038050186
+ 1.4158394617933896
+ 1.4160098578956717
+ 1.4161802263691967
+ 1.416350567226121
+ 1.416520880478592
+ 1.4166911661387487
+ 1.4168614242187212
+ 1.4170316547306303
+ 1.417201857686589
+ 1.4173720330987014
+ 1.417542180979063
+ 1.4177123013397601
+ 1.4178823941928704
+ 1.418052459550464
+ 1.4182224974246012
+ 1.418392507827334
+ 1.4185624907707062
+ 1.4187324462667523
+ 1.4189023743274987
+ 1.419072274964963
+ 1.4192421481911544
+ 1.419411994018073
+ 1.4195818124577113
+ 1.419751603522052
+ 1.4199213672230708
+ 1.4200911035727333
+ 1.420260812582997
+ 1.4204304942658117
+ 1.420600148633118
+ 1.4207697756968476
+ 1.4209393754689243
+ 1.421108947961264
+ 1.4212784931857723
+ 1.4214480111543482
+ 1.421617501878881
+ 1.421786965371252
+ 1.4219564016433346
+ 1.4221258107069925
+ 1.422295192574082
+ 1.4224645472564508
+ 1.422633874765937
+ 1.4228031751143728
+ 1.4229724483135795
+ 1.4231416943753712
+ 1.4233109133115536
+ 1.4234801051339234
+ 1.42364926985427
+ 1.4238184074843732
+ 1.4239875180360055
+ 1.4241566015209304
+ 1.4243256579509032
+ 1.4244946873376714
+ 1.4246636896929732
+ 1.4248326650285392
+ 1.4250016133560917
+ 1.425170534687344
+ 1.4253394290340025
+ 1.4255082964077637
+ 1.4256771368203167
+ 1.4258459502833423
+ 1.4260147368085134
+ 1.4261834964074935
+ 1.4263522290919393
+ 1.4265209348734977
+ 1.426689613763809
+ 1.4268582657745041
+ 1.4270268909172064
+ 1.4271954892035303
+ 1.427364060645083
+ 1.4275326052534631
+ 1.4277011230402605
+ 1.4278696140170581
+ 1.4280380781954292
+ 1.42820651558694
+ 1.4283749262031482
+ 1.4285433100556035
+ 1.4287116671558475
+ 1.4288799975154132
+ 1.4290483011458264
+ 1.4292165780586035
+ 1.4293848282652541
+ 1.4295530517772792
+ 1.4297212486061717
+ 1.4298894187634161
+ 1.4300575622604894
+ 1.4302256791088603
+ 1.4303937693199893
+ 1.4305618329053296
+ 1.4307298698763249
+ 1.4308978802444123
+ 1.4310658640210203
+ 1.4312338212175693
+ 1.4314017518454718
+ 1.431569655916133
+ 1.4317375334409483
+ 1.4319053844313074
+ 1.4320732088985904
+ 1.4322410068541698
+ 1.4324087783094106
+ 1.4325765232756695
+ 1.4327442417642953
+ 1.4329119337866287
+ 1.4330795993540029
+ 1.4332472384777428
+ 1.4334148511691658
+ 1.4335824374395807
+ 1.433749997300289
+ 1.4339175307625842
+ 1.434085037837752
+ 1.4342525185370705
+ 1.4344199728718086
+ 1.4345874008532287
+ 1.4347548024925851
+ 1.4349221778011243
+ 1.4350895267900843
+ 1.4352568494706959
+ 1.4354241458541819
+ 1.4355914159517575
+ 1.43575865977463
+ 1.4359258773339982
+ 1.436093068641055
+ 1.4362602337069827
+ 1.4364273725429584
+ 1.4365944851601504
+ 1.436761571569719
+ 1.4369286317828172
+ 1.43709566581059
+ 1.4372626736641745
+ 1.4374296553547006
+ 1.4375966108932903
+ 1.4377635402910576
+ 1.437930443559109
+ 1.4380973207085435
+ 1.4382641717504516
+ 1.4384309966959175
+ 1.4385977955560163
+ 1.4387645683418167
+ 1.4389313150643788
+ 1.4390980357347551
+ 1.439264730363991
+ 1.4394313989631238
+ 1.4395980415431837
+ 1.4397646581151926
+ 1.4399312486901652
+ 1.4400978132791085
+ 1.4402643518930218
+ 1.4404308645428971
+ 1.4405973512397185
+ 1.4407638119944628
+ 1.4409302468180987
+ 1.441096655721588
+ 1.4412630387158847
+ 1.4414293958119346
+ 1.4415957270206774
+ 1.4417620323530438
+ 1.441928311819958
+ 1.4420945654323358
+ 1.4422607932010862
+ 1.4424269951371107
+ 1.4425931712513023
+ 1.442759321554548
+ 1.442925446057726
+ 1.443091544771708
+ 1.4432576177073575
+ 1.4434236648755312
+ 1.4435896862870776
+ 1.443755681952838
+ 1.443921651883647
+ 1.4440875960903305
+ 1.4442535145837085
+ 1.4444194073745917
+ 1.4445852744737848
+ 1.4447511158920847
+ 1.444916931640281
+ 1.4450827217291558
+ 1.4452484861694834
+ 1.4454142249720312
+ 1.4455799381475594
+ 1.4457456257068206
+ 1.44591128766056
+ 1.446076924019515
+ 1.4462425347944166
+ 1.446408119995988
+ 1.4465736796349449
+ 1.4467392137219957
+ 1.4469047222678417
+ 1.4470702052831768
+ 1.4472356627786878
+ 1.4474010947650537
+ 1.4475665012529468
+ 1.4477318822530314
+ 1.4478972377759651
+ 1.4480625678323986
+ 1.4482278724329742
+ 1.4483931515883277
+ 1.4485584053090876
+ 1.4487236336058753
+ 1.4488888364893042
+ 1.4490540139699815
+ 1.4492191660585063
+ 1.4493842927654712
+ 1.4495493941014612
+ 1.4497144700770543
+ 1.4498795207028206
+ 1.450044545989324
+ 1.450209545947121
+ 1.4503745205867604
+ 1.4505394699187844
+ 1.4507043939537279
+ 1.4508692927021178
+ 1.4510341661744754
+ 1.451199014381314
+ 1.4513638373331397
+ 1.4515286350404513
+ 1.451693407513741
+ 1.4518581547634941
+ 1.452022876800188
+ 1.4521875736342933
+ 1.4523522452762736
+ 1.4525168917365854
+ 1.452681513025678
+ 1.4528461091539944
+ 1.453010680131969
+ 1.4531752259700308
+ 1.4533397466786002
+ 1.453504242268092
+ 1.4536687127489127
+ 1.4538331581314627
+ 1.453997578426135
+ 1.4541619736433153
+ 1.454326343793383
+ 1.4544906888867097
+ 1.4546550089336605
+ 1.4548193039445938
+ 1.4549835739298598
+ 1.4551478188998033
+ 1.4553120388647607
+ 1.4554762338350626
+ 1.4556404038210315
+ 1.4558045488329845
+ 1.4559686688812297
+ 1.4561327639760702
+ 1.4562968341278009
+ 1.4564608793467102
+ 1.4566248996430802
+ 1.4567888950271846
+ 1.4569528655092914
+ 1.4571168110996615
+ 1.4572807318085486
+ 1.4574446276461999
+ 1.4576084986228552
+ 1.4577723447487476
+ 1.457936166034104
+ 1.4580999624891433
+ 1.4582637341240783
+ 1.4584274809491151
+ 1.4585912029744519
+ 1.4587549002102815
+ 1.4589185726667888
+ 1.459082220354152
+ 1.4592458432825433
+ 1.459409441462127
+ 1.4595730149030612
+ 1.459736563615497
+ 1.4599000876095791
+ 1.460063586895445
+ 1.4602270614832251
+ 1.460390511383044
+ 1.4605539366050186
+ 1.4607173371592594
+ 1.4608807130558705
+ 1.4610440643049485
+ 1.461207390916584
+ 1.46137069290086
+ 1.461533970267854
+ 1.4616972230276355
+ 1.4618604511902682
+ 1.4620236547658083
+ 1.4621868337643062
+ 1.462349988195805
+ 1.462513118070341
+ 1.4626762233979442
+ 1.4628393041886376
+ 1.463002360452438
+ 1.4631653921993548
+ 1.4633283994393917
+ 1.4634913821825448
+ 1.4636543404388038
+ 1.463817274218152
+ 1.4639801835305664
+ 1.4641430683860162
+ 1.4643059287944655
+ 1.46446876476587
+ 1.4646315763101805
+ 1.4647943634373406
+ 1.4649571261572865
+ 1.4651198644799486
+ 1.465282578415251
+ 1.4654452679731105
+ 1.4656079331634373
+ 1.465770573996136
+ 1.465933190481103
+ 1.4660957826282304
+ 1.4662583504474014
+ 1.466420893948494
+ 1.4665834131413793
+ 1.4667459080359224
+ 1.4669083786419808
+ 1.4670708249694062
+ 1.4672332470280436
+ 1.4673956448277319
+ 1.4675580183783028
+ 1.467720367689582
+ 1.4678826927713884
+ 1.468044993633535
+ 1.468207270285827
+ 1.4683695227380649
+ 1.4685317510000409
+ 1.4686939550815425
+ 1.4688561349923497
+ 1.4690182907422358
+ 1.4691804223409686
+ 1.469342529798309
+ 1.4695046131240108
+ 1.4696666723278227
+ 1.4698287074194858
+ 1.4699907184087355
+ 1.4701527053053003
+ 1.470314668118903
+ 1.4704766068592592
+ 1.4706385215360784
+ 1.4708004121590639
+ 1.4709622787379122
+ 1.4711241212823145
+ 1.4712859398019538
+ 1.4714477343065084
+ 1.4716095048056494
+ 1.471771251309042
+ 1.4719329738263442
+ 1.472094672367209
+ 1.4722563469412817
+ 1.4724179975582024
+ 1.4725796242276041
+ 1.4727412269591138
+ 1.472902805762352
+ 1.4730643606469336
+ 1.4732258916224659
+ 1.473387398698551
+ 1.4735488818847846
+ 1.473710341190755
+ 1.473871776626046
+ 1.4740331882002342
+ 1.4741945759228894
+ 1.4743559398035757
+ 1.4745172798518513
+ 1.4746785960772675
+ 1.47483988848937
+ 1.4750011570976975
+ 1.475162401911783
+ 1.4753236229411535
+ 1.4754848201953288
+ 1.4756459936838235
+ 1.4758071434161455
+ 1.4759682694017962
+ 1.476129371650272
+ 1.4762904501710614
+ 1.4764515049736484
+ 1.4766125360675093
+ 1.4767735434621156
+ 1.4769345271669316
+ 1.4770954871914161
+ 1.477256423545021
+ 1.4774173362371927
+ 1.4775782252773713
+ 1.4777390906749905
+ 1.4778999324394786
+ 1.4780607505802565
+ 1.4782215451067404
+ 1.4783823160283391
+ 1.4785430633544565
+ 1.478703787094489
+ 1.478864487257828
+ 1.4790251638538587
+ 1.4791858168919596
+ 1.479346446381504
+ 1.4795070523318579
+ 1.479667634752382
+ 1.4798281936524313
+ 1.4799887290413543
+ 1.4801492409284929
+ 1.4803097293231837
+ 1.480470194234757
+ 1.480630635672537
+ 1.4807910536458422
+ 1.4809514481639843
+ 1.4811118192362698
+ 1.481272166871999
+ 1.4814324910804655
+ 1.4815927918709582
+ 1.4817530692527583
+ 1.4819133232351427
+ 1.4820735538273808
+ 1.482233761038737
+ 1.4823939448784698
+ 1.4825541053558309
+ 1.4827142424800663
+ 1.4828743562604167
+ 1.4830344467061165
+ 1.4831945138263933
+ 1.4833545576304696
+ 1.4835145781275623
+ 1.4836745753268812
+ 1.4838345492376315
+ 1.4839944998690109
+ 1.4841544272302127
+ 1.4843143313304235
+ 1.4844742121788241
+ 1.4846340697845892
+ 1.484793904156888
+ 1.4849537153048835
+ 1.4851135032377332
+ 1.485273267964588
+ 1.4854330094945931
+ 1.4855927278368888
+ 1.4857524230006083
+ 1.4859120949948794
+ 1.4860717438288245
+ 1.4862313695115588
+ 1.486390972052193
+ 1.4865505514598318
+ 1.4867101077435734
+ 1.4868696409125106
+ 1.48702915097573
+ 1.487188637942313
+ 1.4873481018213346
+ 1.4875075426218647
+ 1.487666960352966
+ 1.487826355023697
+ 1.4879857266431094
+ 1.4881450752202492
+ 1.4883044007641575
+ 1.4884637032838681
+ 1.4886229827884103
+ 1.4887822392868069
+ 1.4889414727880754
+ 1.4891006833012272
+ 1.4892598708352682
+ 1.4894190353991985
+ 1.4895781770020118
+ 1.4897372956526973
+ 1.4898963913602372
+ 1.4900554641336088
+ 1.4902145139817837
+ 1.4903735409137269
+ 1.4905325449383986
+ 1.490691526064753
+ 1.4908504843017383
+ 1.4910094196582975
+ 1.4911683321433675
+ 1.4913272217658795
+ 1.4914860885347594
+ 1.4916449324589274
+ 1.491803753547297
+ 1.4919625518087776
+ 1.4921213272522718
+ 1.4922800798866767
+ 1.4924388097208845
+ 1.4925975167637804
+ 1.4927562010242457
+ 1.492914862511154
+ 1.4930735012333751
+ 1.493232117199772
+ 1.4933907104192028
+ 1.4935492809005197
+ 1.4937078286525687
+ 1.4938663536841914
+ 1.4940248560042224
+ 1.494183335621492
+ 1.494341792544824
+ 1.4945002267830367
+ 1.4946586383449438
+ 1.4948170272393517
+ 1.494975393475063
+ 1.4951337370608733
+ 1.4952920580055733
+ 1.4954503563179482
+ 1.4956086320067776
+ 1.4957668850808352
+ 1.495925115548889
+ 1.4960833234197028
+ 1.496241508702033
+ 1.496399671404632
+ 1.4965578115362457
+ 1.496715929105615
+ 1.4968740241214746
+ 1.4970320965925545
+ 1.4971901465275792
+ 1.4973481739352668
+ 1.4975061788243305
+ 1.497664161203478
+ 1.497822121081412
+ 1.4979800584668284
+ 1.4981379733684188
+ 1.4982958657948686
+ 1.4984537357548584
+ 1.4986115832570628
+ 1.498769408310151
+ 1.498927210922787
+ 1.499084991103629
+ 1.49924274886133
+ 1.4994004842045379
+ 1.499558197141894
+ 1.4997158876820358
+ 1.4998735558335936
+ 1.5000312016051935
+ 1.5001888250054563
+ 1.5003464260429962
+ 1.500504004726423
+ 1.500661561064341
+ 1.5008190950653488
+ 1.5009766067380397
+ 1.5011340960910013
+ 1.5012915631328168
+ 1.5014490078720628
+ 1.5016064303173113
+ 1.5017638304771281
+ 1.5019212083600755
+ 1.5020785639747078
+ 1.502235897329576
+ 1.5023932084332252
+ 1.5025504972941945
+ 1.5027077639210185
+ 1.5028650083222257
+ 1.50302223050634
+ 1.5031794304818797
+ 1.5033366082573576
+ 1.503493763841281
+ 1.5036508972421527
+ 1.5038080084684693
+ 1.5039650975287226
+ 1.504122164431399
+ 1.504279209184979
+ 1.504436231797939
+ 1.5045932322787494
+ 1.504750210635875
+ 1.5049071668777758
+ 1.5050641010129064
+ 1.5052210130497163
+ 1.5053779029966499
+ 1.5055347708621452
+ 1.5056916166546361
+ 1.5058484403825512
+ 1.506005242054313
+ 1.5061620216783398
+ 1.5063187792630437
+ 1.5064755148168325
+ 1.506632228348108
+ 1.5067889198652673
+ 1.5069455893767019
+ 1.5071022368907976
+ 1.5072588624159369
+ 1.5074154659604948
+ 1.5075720475328422
+ 1.5077286071413454
+ 1.507885144794364
+ 1.5080416605002536
+ 1.5081981542673644
+ 1.5083546261040406
+ 1.5085110760186224
+ 1.5086675040194442
+ 1.5088239101148353
+ 1.5089802943131199
+ 1.5091366566226165
+ 1.5092929970516398
+ 1.509449315608498
+ 1.5096056123014947
+ 1.5097618871389287
+ 1.5099181401290924
+ 1.5100743712802744
+ 1.510230580600758
+ 1.510386768098821
+ 1.5105429337827356
+ 1.5106990776607698
+ 1.5108551997411865
+ 1.5110113000322425
+ 1.5111673785421906
+ 1.5113234352792777
+ 1.511479470251746
+ 1.511635483467833
+ 1.5117914749357697
+ 1.5119474446637842
+ 1.512103392660097
+ 1.512259318932926
+ 1.5124152234904822
+ 1.5125711063409724
+ 1.5127269674925978
+ 1.5128828069535554
+ 1.5130386247320362
+ 1.513194420836227
+ 1.513350195274309
+ 1.5135059480544582
+ 1.5136616791848458
+ 1.5138173886736388
+ 1.513973076528998
+ 1.5141287427590797
+ 1.5142843873720349
+ 1.5144400103760096
+ 1.5145956117791453
+ 1.5147511915895784
+ 1.5149067498154394
+ 1.5150622864648549
+ 1.5152178015459459
+ 1.5153732950668288
+ 1.5155287670356148
+ 1.5156842174604097
+ 1.5158396463493156
+ 1.5159950537104279
+ 1.5161504395518384
+ 1.5163058038816333
+ 1.5164611467078943
+ 1.5166164680386975
+ 1.5167717678821147
+ 1.516927046246212
+ 1.517082303139052
+ 1.51723753856869
+ 1.517392752543179
+ 1.517547945070565
+ 1.5177031161588903
+ 1.5178582658161919
+ 1.5180133940505018
+ 1.5181685008698471
+ 1.5183235862822502
+ 1.5184786502957286
+ 1.5186336929182942
+ 1.518788714157955
+ 1.5189437140227133
+ 1.5190986925205678
+ 1.5192536496595104
+ 1.5194085854475297
+ 1.5195634998926084
+ 1.5197183930027252
+ 1.5198732647858535
+ 1.5200281152499615
+ 1.5201829444030133
+ 1.5203377522529675
+ 1.5204925388077783
+ 1.520647304075395
+ 1.5208020480637614
+ 1.5209567707808171
+ 1.5211114722344974
+ 1.5212661524327316
+ 1.5214208113834444
+ 1.5215754490945566
+ 1.5217300655739832
+ 1.5218846608296348
+ 1.5220392348694176
+ 1.5221937877012317
+ 1.5223483193329739
+ 1.5225028297725354
+ 1.5226573190278025
+ 1.5228117871066573
+ 1.5229662340169767
+ 1.5231206597666327
+ 1.523275064363493
+ 1.52342944781542
+ 1.523583810130272
+ 1.5237381513159016
+ 1.5238924713801578
+ 1.5240467703308835
+ 1.524201048175918
+ 1.5243553049230953
+ 1.5245095405802447
+ 1.5246637551551911
+ 1.5248179486557543
+ 1.5249721210897493
+ 1.5251262724649866
+ 1.525280402789272
+ 1.5254345120704063
+ 1.5255886003161858
+ 1.5257426675344024
+ 1.5258967137328427
+ 1.5260507389192888
+ 1.5262047431015182
+ 1.5263587262873042
+ 1.5265126884844138
+ 1.5266666297006115
+ 1.5268205499436551
+ 1.5269744492212989
+ 1.5271283275412926
+ 1.5272821849113805
+ 1.5274360213393026
+ 1.5275898368327943
+ 1.5277436313995865
+ 1.5278974050474048
+ 1.5280511577839708
+ 1.528204889617001
+ 1.528358600554208
+ 1.528512290603299
+ 1.5286659597719763
+ 1.5288196080679386
+ 1.5289732354988792
+ 1.5291268420724873
+ 1.529280427796447
+ 1.5294339926784375
+ 1.5295875367261345
+ 1.529741059947208
+ 1.5298945623493243
+ 1.5300480439401443
+ 1.530201504727325
+ 1.5303549447185176
+ 1.5305083639213704
+ 1.5306617623435257
+ 1.5308151399926222
+ 1.5309684968762933
+ 1.5311218330021685
+ 1.531275148377872
+ 1.5314284430110237
+ 1.5315817169092392
+ 1.5317349700801293
+ 1.5318882025313003
+ 1.532041414270354
+ 1.5321946053048876
+ 1.5323477756424935
+ 1.5325009252907602
+ 1.5326540542572709
+ 1.5328071625496051
+ 1.5329602501753368
+ 1.5331133171420361
+ 1.5332663634572687
+ 1.5334193891285952
+ 1.5335723941635726
+ 1.5337253785697522
+ 1.5338783423546816
+ 1.5340312855259033
+ 1.5341842080909565
+ 1.5343371100573746
+ 1.5344899914326873
+ 1.5346428522244189
+ 1.5347956924400905
+ 1.5349485120872177
+ 1.535101311173312
+ 1.5352540897058804
+ 1.5354068476924254
+ 1.5355595851404453
+ 1.5357123020574337
+ 1.5358649984508792
+ 1.536017674328267
+ 1.536170329697077
+ 1.5363229645647853
+ 1.536475578938863
+ 1.536628172826777
+ 1.53678074623599
+ 1.5369332991739593
+ 1.5370858316481395
+ 1.537238343665979
+ 1.5373908352349228
+ 1.537543306362411
+ 1.53769575705588
+ 1.537848187322761
+ 1.538000597170481
+ 1.5381529866064627
+ 1.5383053556381245
+ 1.5384577042728804
+ 1.5386100325181393
+ 1.5387623403813069
+ 1.5389146278697834
+ 1.5390668949909654
+ 1.5392191417522454
+ 1.53937136816101
+ 1.5395235742246425
+ 1.5396757599505224
+ 1.5398279253460236
+ 1.5399800704185165
+ 1.5401321951753666
+ 1.5402842996239354
+ 1.54043638377158
+ 1.5405884476256528
+ 1.5407404911935025
+ 1.5408925144824728
+ 1.5410445174999037
+ 1.5411965002531303
+ 1.5413484627494836
+ 1.5415004049962902
+ 1.5416523270008726
+ 1.541804228770549
+ 1.5419561103126325
+ 1.5421079716344332
+ 1.5422598127432559
+ 1.5424116336464013
+ 1.542563434351166
+ 1.5427152148648422
+ 1.5428669751947177
+ 1.5430187153480763
+ 1.543170435332197
+ 1.5433221351543553
+ 1.5434738148218219
+ 1.5436254743418627
+ 1.5437771137217402
+ 1.5439287329687126
+ 1.5440803320900331
+ 1.5442319110929519
+ 1.544383469984713
+ 1.5445350087725582
+ 1.544686527463724
+ 1.5448380260654424
+ 1.5449895045849418
+ 1.5451409630294461
+ 1.545292401406175
+ 1.5454438197223437
+ 1.545595217985164
+ 1.545746596201842
+ 1.5458979543795808
+ 1.546049292525579
+ 1.546200610647031
+ 1.5463519087511268
+ 1.546503186845052
+ 1.5466544449359887
+ 1.546805683031114
+ 1.5469569011376016
+ 1.54710809926262
+ 1.5472592774133347
+ 1.5474104355969056
+ 1.5475615738204898
+ 1.5477126920912394
+ 1.5478637904163024
+ 1.5480148688028232
+ 1.548165927257941
+ 1.548316965788792
+ 1.5484679844025073
+ 1.5486189831062138
+ 1.5487699619070352
+ 1.5489209208120902
+ 1.5490718598284938
+ 1.5492227789633564
+ 1.5493736782237846
+ 1.5495245576168808
+ 1.5496754171497433
+ 1.5498262568294658
+ 1.5499770766631389
+ 1.550127876657848
+ 1.5502786568206746
+ 1.5504294171586965
+ 1.5505801576789875
+ 1.5507308783886162
+ 1.5508815792946486
+ 1.551032260404145
+ 1.5511829217241635
+ 1.5513335632617558
+ 1.5514841850239713
+ 1.5516347870178546
+ 1.5517853692504466
+ 1.5519359317287833
+ 1.5520864744598977
+ 1.5522369974508174
+ 1.5523875007085675
+ 1.5525379842401676
+ 1.552688448052634
+ 1.552838892152979
+ 1.55298931654821
+ 1.5531397212453313
+ 1.553290106251343
+ 1.5534404715732404
+ 1.5535908172180155
+ 1.5537411431926558
+ 1.553891449504145
+ 1.5540417361594632
+ 1.5541920031655851
+ 1.5543422505294828
+ 1.5544924782581235
+ 1.5546426863584708
+ 1.5547928748374844
+ 1.554943043702119
+ 1.5550931929593268
+ 1.5552433226160545
+ 1.5553934326792458
+ 1.5555435231558394
+ 1.5556935940527716
+ 1.5558436453769733
+ 1.5559936771353717
+ 1.5561436893348901
+ 1.556293681982448
+ 1.5564436550849605
+ 1.556593608649339
+ 1.556743542682491
+ 1.5568934571913198
+ 1.5570433521827247
+ 1.5571932276636011
+ 1.5573430836408406
+ 1.5574929201213306
+ 1.5576427371119543
+ 1.5577925346195918
+ 1.5579423126511183
+ 1.558092071213405
+ 1.5582418103133207
+ 1.558391529957728
+ 1.5585412301534871
+ 1.558690910907454
+ 1.5588405722264804
+ 1.5589902141174141
+ 1.5591398365870992
+ 1.5592894396423755
+ 1.5594390232900797
+ 1.5595885875370437
+ 1.5597381323900958
+ 1.5598876578560603
+ 1.5600371639417576
+ 1.5601866506540045
+ 1.5603361179996134
+ 1.560485565985393
+ 1.5606349946181481
+ 1.5607844039046797
+ 1.5609337938517847
+ 1.5610831644662566
+ 1.5612325157548839
+ 1.5613818477244525
+ 1.5615311603817437
+ 1.561680453733535
+ 1.5618297277866002
+ 1.561978982547709
+ 1.5621282180236276
+ 1.5622774342211174
+ 1.5624266311469373
+ 1.5625758088078412
+ 1.5627249672105799
+ 1.5628741063618998
+ 1.5630232262685433
+ 1.5631723269372502
+ 1.5633214083747546
+ 1.5634704705877884
+ 1.5636195135830786
+ 1.5637685373673487
+ 1.5639175419473186
+ 1.5640665273297039
+ 1.5642154935212171
+ 1.5643644405285657
+ 1.564513368358455
+ 1.5646622770175842
+ 1.5648111665126512
+ 1.5649600368503485
+ 1.5651088880373651
+ 1.5652577200803865
+ 1.565406532986094
+ 1.5655553267611653
+ 1.5657041014122743
+ 1.5658528569460914
+ 1.5660015933692824
+ 1.5661503106885097
+ 1.5662990089104327
+ 1.5664476880417055
+ 1.5665963480889802
+ 1.566744989058903
+ 1.5668936109581184
+ 1.5670422137932656
+ 1.567190797570981
+ 1.5673393622978966
+ 1.5674879079806414
+ 1.5676364346258393
+ 1.5677849422401122
+ 1.5679334308300767
+ 1.5680819004023465
+ 1.5682303509635314
+ 1.5683787825202369
+ 1.5685271950790656
+ 1.5686755886466162
+ 1.5688239632294831
+ 1.5689723188342573
+ 1.569120655467526
+ 1.5692689731358733
+ 1.5694172718458788
+ 1.5695655516041178
+ 1.569713812417164
+ 1.5698620542915849
+ 1.570010277233946
+ 1.5701584812508087
+ 1.57030666634873
+ 1.570454832534264
+ 1.570602979813961
+ 1.5707511081943673
+ 1.5708992176820251
+ 1.5710473082834742
+ 1.5711953800052494
+ 1.5713434328538824
+ 1.5714914668359017
+ 1.5716394819578308
+ 1.5717874782261907
+ 1.5719354556474983
+ 1.5720834142282665
+ 1.5722313539750055
+ 1.5723792748942207
+ 1.5725271769924143
+ 1.5726750602760853
+ 1.5728229247517282
+ 1.5729707704258344
+ 1.5731185973048913
+ 1.573266405395383
+ 1.5734141947037903
+ 1.5735619652365893
+ 1.5737097170002525
+ 1.5738574500012503
+ 1.5740051642460477
+ 1.5741528597411074
+ 1.5743005364928875
+ 1.5744481945078428
+ 1.5745958337924242
+ 1.57474345435308
+ 1.574891056196254
+ 1.575038639328386
+ 1.5751862037559132
+ 1.5753337494852686
+ 1.5754812765228818
+ 1.5756287848751787
+ 1.5757762745485813
+ 1.5759237455495083
+ 1.5760711978843756
+ 1.5762186315595936
+ 1.5763660465815712
+ 1.576513442956712
+ 1.576660820691417
+ 1.5768081797920834
+ 1.5769555202651049
+ 1.5771028421168711
+ 1.5772501453537686
+ 1.5773974299821802
+ 1.5775446960084853
+ 1.5776919434390602
+ 1.5778391722802756
+ 1.5779863825385012
+ 1.5781335742201017
+ 1.5782807473314386
+ 1.5784279018788698
+ 1.5785750378687495
+ 1.5787221553074287
+ 1.5788692542012546
+ 1.5790163345565713
+ 1.5791633963797183
+ 1.5793104396770326
+ 1.5794574644548474
+ 1.579604470719492
+ 1.579751458477293
+ 1.5798984277345722
+ 1.5800453784976491
+ 1.580192310772839
+ 1.5803392245664543
+ 1.5804861198848026
+ 1.5806329967341897
+ 1.5807798551209162
+ 1.5809266950512806
+ 1.5810735165315775
+ 1.5812203195680972
+ 1.5813671041671273
+ 1.5815138703349518
+ 1.5816606180778514
+ 1.5818073474021026
+ 1.5819540583139793
+ 1.5821007508197509
+ 1.5822474249256842
+ 1.5823940806380423
+ 1.5825407179630844
+ 1.5826873369070669
+ 1.5828339374762423
+ 1.5829805196768592
+ 1.583127083515164
+ 1.5832736289973985
+ 1.5834201561298014
+ 1.583566664918608
+ 1.58371315537005
+ 1.5838596274903558
+ 1.5840060812857504
+ 1.584152516762455
+ 1.584298933926688
+ 1.5844453327846635
+ 1.584591713342593
+ 1.584738075606684
+ 1.5848844195831406
+ 1.585030745278164
+ 1.5851770526979512
+ 1.5853233418486965
+ 1.58546961273659
+ 1.5856158653678192
+ 1.5857620997485673
+ 1.5859083158850154
+ 1.5860545137833395
+ 1.5862006934497135
+ 1.5863468548903072
+ 1.5864929981112876
+ 1.5866391231188177
+ 1.5867852299190572
+ 1.5869313185181626
+ 1.5870773889222871
+ 1.5872234411375803
+ 1.5873694751701883
+ 1.5875154910262539
+ 1.587661488711917
+ 1.5878074682333134
+ 1.5879534295965756
+ 1.5880993728078332
+ 1.5882452978732124
+ 1.5883912047988353
+ 1.5885370935908212
+ 1.5886829642552867
+ 1.588828816798343
+ 1.5889746512261003
+ 1.5891204675446637
+ 1.589266265760136
+ 1.5894120458786163
+ 1.5895578079061998
+ 1.5897035518489795
+ 1.589849277713044
+ 1.589994985504479
+ 1.5901406752293668
+ 1.5902863468937865
+ 1.5904320005038135
+ 1.5905776360655206
+ 1.5907232535849767
+ 1.5908688530682469
+ 1.591014434521394
+ 1.5911599979504767
+ 1.591305543361551
+ 1.5914510707606688
+ 1.5915965801538798
+ 1.5917420715472295
+ 1.5918875449467598
+ 1.5920330003585104
+ 1.5921784377885169
+ 1.5923238572428116
+ 1.5924692587274243
+ 1.59261464224838
+ 1.5927600078117021
+ 1.5929053554234098
+ 1.5930506850895187
+ 1.5931959968160416
+ 1.5933412906089885
+ 1.593486566474365
+ 1.5936318244181742
+ 1.5937770644464153
+ 1.5939222865650853
+ 1.5940674907801768
+ 1.5942126770976797
+ 1.5943578455235805
+ 1.5945029960638624
+ 1.5946481287245053
+ 1.5947932435114864
+ 1.5949383404307786
+ 1.5950834194883523
+ 1.5952284806901742
+ 1.5953735240422087
+ 1.5955185495504154
+ 1.595663557220752
+ 1.5958085470591723
+ 1.5959535190716274
+ 1.5960984732640642
+ 1.596243409642427
+ 1.5963883282126572
+ 1.5965332289806922
+ 1.5966781119524665
+ 1.596822977133912
+ 1.5969678245309564
+ 1.5971126541495242
+ 1.5972574659955376
+ 1.597402260074915
+ 1.597547036393571
+ 1.5976917949574185
+ 1.5978365357723656
+ 1.597981258844318
+ 1.5981259641791787
+ 1.598270651782846
+ 1.5984153216612162
+ 1.5985599738201826
+ 1.5987046082656338
+ 1.598849225003457
+ 1.5989938240395352
+ 1.599138405379748
+ 1.5992829690299726
+ 1.5994275149960826
+ 1.5995720432839486
+ 1.5997165538994378
+ 1.5998610468484138
+ 1.6000055221367384
+ 1.6001499797702687
+ 1.6002944197548596
+ 1.6004388420963624
+ 1.6005832468006251
+ 1.6007276338734933
+ 1.6008720033208088
+ 1.6010163551484102
+ 1.601160689362133
+ 1.6013050059678102
+ 1.6014493049712708
+ 1.6015935863783408
+ 1.6017378501948434
+ 1.6018820964265985
+ 1.6020263250794227
+ 1.6021705361591299
+ 1.6023147296715303
+ 1.6024589056224312
+ 1.602603064017637
+ 1.6027472048629485
+ 1.6028913281641644
+ 1.6030354339270783
+ 1.6031795221574827
+ 1.603323592861166
+ 1.603467646043914
+ 1.6036116817115083
+ 1.6037556998697287
+ 1.6038997005243512
+ 1.6040436836811487
+ 1.6041876493458913
+ 1.6043315975243457
+ 1.6044755282222753
+ 1.6046194414454416
+ 1.604763337199601
+ 1.6049072154905084
+ 1.6050510763239154
+ 1.6051949197055697
+ 1.6053387456412171
+ 1.605482554136599
+ 1.6056263451974546
+ 1.60577011882952
+ 1.6059138750385276
+ 1.6060576138302074
+ 1.6062013352102862
+ 1.6063450391844873
+ 1.6064887257585316
+ 1.606632394938136
+ 1.6067760467290153
+ 1.606919681136881
+ 1.6070632981674409
+ 1.6072068978264007
+ 1.607350480119462
+ 1.6074940450523243
+ 1.6076375926306834
+ 1.6077811228602328
+ 1.6079246357466617
+ 1.6080681312956577
+ 1.6082116095129046
+ 1.6083550704040825
+ 1.60849851397487
+ 1.6086419402309415
+ 1.608785349177969
+ 1.608928740821621
+ 1.609072115167563
+ 1.609215472221458
+ 1.6093588119889655
+ 1.6095021344757419
+ 1.609645439687441
+ 1.6097887276297131
+ 1.6099319983082059
+ 1.6100752517285641
+ 1.6102184878964292
+ 1.6103617068174392
+ 1.6105049084972303
+ 1.6106480929414349
+ 1.6107912601556817
+ 1.6109344101455985
+ 1.6110775429168076
+ 1.61122065847493
+ 1.6113637568255836
+ 1.6115068379743824
+ 1.6116499019269381
+ 1.6117929486888591
+ 1.6119359782657514
+ 1.6120789906632174
+ 1.6122219858868563
+ 1.6123649639422653
+ 1.6125079248350378
+ 1.6126508685707641
+ 1.6127937951550326
+ 1.612936704593428
+ 1.6130795968915315
+ 1.6132224720549224
+ 1.6133653300891762
+ 1.613508170999866
+ 1.613650994792562
+ 1.6137938014728306
+ 1.6139365910462362
+ 1.61407936351834
+ 1.6142221188946995
+ 1.6143648571808706
+ 1.6145075783824052
+ 1.6146502825048523
+ 1.6147929695537588
+ 1.6149356395346681
+ 1.61507829245312
+ 1.6152209283146528
+ 1.6153635471248007
+ 1.6155061488890956
+ 1.615648733613066
+ 1.615791301302238
+ 1.6159338519621342
+ 1.616076385598275
+ 1.616218902216177
+ 1.6163614018213546
+ 1.6165038844193191
+ 1.6166463500155788
+ 1.616788798615639
+ 1.616931230225002
+ 1.617073644849168
+ 1.6172160424936333
+ 1.6173584231638916
+ 1.6175007868654339
+ 1.6176431336037482
+ 1.6177854633843196
+ 1.6179277762126305
+ 1.6180700720941599
+ 1.6182123510343847
+ 1.6183546130387778
+ 1.6184968581128105
+ 1.6186390862619497
+ 1.6187812974916613
+ 1.6189234918074067
+ 1.619065669214645
+ 1.6192078297188328
+ 1.6193499733254235
+ 1.6194921000398672
+ 1.6196342098676122
+ 1.6197763028141028
+ 1.6199183788847809
+ 1.6200604380850854
+ 1.6202024804204533
+ 1.6203445058963173
+ 1.6204865145181078
+ 1.6206285062912527
+ 1.6207704812211767
+ 1.6209124393133023
+ 1.6210543805730475
+ 1.6211963050058291
+ 1.621338212617061
+ 1.6214801034121529
+ 1.6216219773965133
+ 1.6217638345755463
+ 1.6219056749546543
+ 1.6220474985392368
+ 1.6221893053346896
+ 1.622331095346407
+ 1.622472868579779
+ 1.622614625040194
+ 1.6227563647330367
+ 1.62289808766369
+ 1.6230397938375325
+ 1.6231814832599416
+ 1.6233231559362904
+ 1.6234648118719506
+ 1.6236064510722898
+ 1.623748073542674
+ 1.6238896792884652
+ 1.624031268315023
+ 1.6241728406277056
+ 1.624314396231866
+ 1.6244559351328558
+ 1.6245974573360238
+ 1.6247389628467157
+ 1.6248804516702744
+ 1.6250219238120402
+ 1.6251633792773508
+ 1.6253048180715404
+ 1.6254462401999406
+ 1.6255876456678813
+ 1.6257290344806883
+ 1.625870406643685
+ 1.6260117621621923
+ 1.6261531010415282
+ 1.626294423287008
+ 1.6264357289039435
+ 1.626577017897645
+ 1.6267182902734192
+ 1.6268595460365705
+ 1.6270007851923995
+ 1.6271420077462053
+ 1.627283213703284
+ 1.6274244030689282
+ 1.6275655758484284
+ 1.6277067320470722
+ 1.6278478716701446
+ 1.6279889947229274
+ 1.6281301012107
+ 1.6282711911387389
+ 1.6284122645123185
+ 1.628553321336709
+ 1.6286943616171796
+ 1.6288353853589956
+ 1.6289763925674199
+ 1.6291173832477126
+ 1.6292583574051311
+ 1.6293993150449306
+ 1.6295402561723626
+ 1.6296811807926765
+ 1.629822088911119
+ 1.6299629805329334
+ 1.6301038556633616
+ 1.630244714307641
+ 1.6303855564710084
+ 1.6305263821586957
+ 1.6306671913759339
+ 1.6308079841279504
+ 1.63094876041997
+ 1.6310895202572142
+ 1.6312302636449032
+ 1.6313709905882539
+ 1.6315117010924796
+ 1.6316523951627921
+ 1.6317930728043994
+ 1.6319337340225084
+ 1.632074378822322
+ 1.6322150072090404
+ 1.6323556191878619
+ 1.6324962147639817
+ 1.6326367939425916
+ 1.6327773567288824
+ 1.6329179031280407
+ 1.6330584331452511
+ 1.633198946785695
+ 1.6333394440545523
+ 1.6334799249569993
+ 1.633620389498209
+ 1.6337608376833535
+ 1.6339012695176003
+ 1.6340416850061161
+ 1.634182084154063
+ 1.6343224669666025
+ 1.634462833448892
+ 1.6346031836060864
+ 1.6347435174433382
+ 1.6348838349657977
+ 1.6350241361786115
+ 1.6351644210869245
+ 1.6353046896958787
+ 1.6354449420106132
+ 1.6355851780362642
+ 1.6357253977779662
+ 1.6358656012408503
+ 1.6360057884300454
+ 1.636145959350677
+ 1.636286114007869
+ 1.636426252406742
+ 1.6365663745524144
+ 1.6367064804500016
+ 1.6368465701046162
+ 1.6369866435213687
+ 1.6371267007053667
+ 1.6372667416617153
+ 1.637406766395517
+ 1.637546774911871
+ 1.6376867672158755
+ 1.6378267433126241
+ 1.6379667032072094
+ 1.63810664690472
+ 1.6382465744102435
+ 1.6383864857288637
+ 1.638526380865662
+ 1.6386662598257176
+ 1.6388061226141062
+ 1.638945969235902
+ 1.639085799696176
+ 1.6392256139999972
+ 1.6393654121524308
+ 1.6395051941585403
+ 1.6396449600233869
+ 1.6397847097520284
+ 1.6399244433495208
+ 1.6400641608209166
+ 1.6402038621712662
+ 1.6403435474056176
+ 1.6404832165290162
+ 1.6406228695465048
+ 1.640762506463123
+ 1.6409021272839086
+ 1.6410417320138968
+ 1.6411813206581196
+ 1.6413208932216072
+ 1.6414604497093865
+ 1.6415999901264824
+ 1.641739514477917
+ 1.6418790227687101
+ 1.642018515003878
+ 1.642157991188436
+ 1.6422974513273958
+ 1.6424368954257662
+ 1.6425763234885546
+ 1.6427157355207653
+ 1.6428551315273996
+ 1.642994511513457
+ 1.6431338754839335
+ 1.643273223443824
+ 1.6434125553981196
+ 1.6435518713518096
+ 1.6436911713098799
+ 1.6438304552773149
+ 1.6439697232590957
+ 1.6441089752602014
+ 1.644248211285608
+ 1.6443874313402895
+ 1.6445266354292176
+ 1.6446658235573604
+ 1.6448049957296842
+ 1.6449441519511532
+ 1.6450832922267282
+ 1.645222416561368
+ 1.6453615249600286
+ 1.6455006174276638
+ 1.6456396939692246
+ 1.6457787545896596
+ 1.6459177992939154
+ 1.6460568280869348
+ 1.6461958409736595
+ 1.646334837959028
+ 1.6464738190479762
+ 1.6466127842454377
+ 1.6467517335563437
+ 1.646890666985623
+ 1.6470295845382015
+ 1.6471684862190028
+ 1.647307372032948
+ 1.647446241984956
+ 1.6475850960799425
+ 1.6477239343228216
+ 1.647862756718504
+ 1.6480015632718992
+ 1.6481403539879125
+ 1.648279128871448
+ 1.6484178879274074
+ 1.648556631160689
+ 1.648695358576189
+ 1.6488340701788016
+ 1.648972765973418
+ 1.6491114459649272
+ 1.6492501101582155
+ 1.649388758558167
+ 1.6495273911696633
+ 1.6496660079975831
+ 1.6498046090468033
+ 1.6499431943221978
+ 1.6500817638286387
+ 1.6502203175709946
+ 1.6503588555541329
+ 1.6504973777829175
+ 1.6506358842622104
+ 1.6507743749968709
+ 1.6509128499917562
+ 1.6510513092517205
+ 1.6511897527816164
+ 1.6513281805862932
+ 1.6514665926705978
+ 1.6516049890393756
+ 1.6517433696974688
+ 1.6518817346497172
+ 1.652020083900958
+ 1.6521584174560264
+ 1.6522967353197555
+ 1.6524350374969745
+ 1.6525733239925122
+ 1.6527115948111932
+ 1.652849849957841
+ 1.6529880894372757
+ 1.6531263132543152
+ 1.6532645214137756
+ 1.6534027139204697
+ 1.6535408907792088
+ 1.653679051994801
+ 1.6538171975720524
+ 1.6539553275157666
+ 1.6540934418307447
+ 1.6542315405217856
+ 1.6543696235936858
+ 1.654507691051239
+ 1.6546457428992367
+ 1.6547837791424684
+ 1.6549217997857208
+ 1.6550598048337786
+ 1.6551977942914229
+ 1.655335768163434
+ 1.6554737264545891
+ 1.6556116691696625
+ 1.6557495963134274
+ 1.6558875078906532
+ 1.656025403906108
+ 1.656163284364557
+ 1.6563011492707629
+ 1.6564389986294863
+ 1.6565768324454855
+ 1.656714650723516
+ 1.6568524534683315
+ 1.6569902406846828
+ 1.6571280123773189
+ 1.6572657685509855
+ 1.6574035092104271
+ 1.657541234360385
+ 1.6576789440055981
+ 1.657816638150804
+ 1.6579543168007362
+ 1.658091979960128
+ 1.658229627633708
+ 1.658367259826204
+ 1.6585048765423414
+ 1.6586424777868423
+ 1.6587800635644274
+ 1.6589176338798148
+ 1.6590551887377198
+ 1.659192728142856
+ 1.6593302520999342
+ 1.659467760613663
+ 1.6596052536887487
+ 1.659742731329895
+ 1.659880193541804
+ 1.6600176403291746
+ 1.6601550716967037
+ 1.6602924876490859
+ 1.6604298881910136
+ 1.6605672733271766
+ 1.6607046430622627
+ 1.6608419974009567
+ 1.6609793363479421
+ 1.6611166599078993
+ 1.6612539680855065
+ 1.66139126088544
+ 1.6615285383123728
+ 1.6616658003709768
+ 1.6618030470659209
+ 1.6619402784018718
+ 1.662077494383494
+ 1.6622146950154493
+ 1.6623518803023976
+ 1.6624890502489966
+ 1.6626262048599014
+ 1.6627633441397645
+ 1.6629004680932369
+ 1.6630375767249668
+ 1.6631746700395997
+ 1.6633117480417798
+ 1.6634488107361483
+ 1.6635858581273444
+ 1.6637228902200043
+ 1.6638599070187632
+ 1.6639969085282529
+ 1.6641338947531037
+ 1.6642708656979426
+ 1.6644078213673952
+ 1.664544761766085
+ 1.6646816868986318
+ 1.6648185967696547
+ 1.6649554913837703
+ 1.665092370745592
+ 1.6652292348597315
+ 1.6653660837307978
+ 1.6655029173633988
+ 1.6656397357621389
+ 1.6657765389316208
+ 1.6659133268764448
+ 1.6660500996012086
+ 1.6661868571105083
+ 1.6663235994089374
+ 1.6664603265010869
+ 1.666597038391546
+ 1.6667337350849014
+ 1.6668704165857373
+ 1.6670070828986363
+ 1.667143734028178
+ 1.6672803699789405
+ 1.6674169907554988
+ 1.6675535963624264
+ 1.667690186804294
+ 1.6678267620856704
+ 1.667963322211122
+ 1.6680998671852134
+ 1.6682363970125063
+ 1.6683729116975603
+ 1.6685094112449328
+ 1.6686458956591794
+ 1.6687823649448528
+ 1.668918819106504
+ 1.6690552581486817
+ 1.6691916820759318
+ 1.6693280908927988
+ 1.669464484603824
+ 1.6696008632135477
+ 1.6697372267265067
+ 1.6698735751472369
+ 1.6700099084802702
+ 1.6701462267301384
+ 1.6702825299013695
+ 1.6704188179984898
+ 1.6705550910260236
+ 1.6706913489884923
+ 1.6708275918904163
+ 1.6709638197363124
+ 1.671100032530696
+ 1.6712362302780803
+ 1.6713724129829761
+ 1.6715085806498917
+ 1.6716447332833337
+ 1.6717808708878066
+ 1.6719169934678118
+ 1.6720531010278499
+ 1.6721891935724178
+ 1.672325271106011
+ 1.6724613336331229
+ 1.6725973811582446
+ 1.6727334136858647
+ 1.67286943122047
+ 1.6730054337665448
+ 1.6731414213285716
+ 1.67327739391103
+ 1.6734133515183987
+ 1.6735492941551522
+ 1.6736852218257652
+ 1.6738211345347085
+ 1.673957032286451
+ 1.6740929150854604
+ 1.674228782936201
+ 1.6743646358431354
+ 1.674500473810724
+ 1.6746362968434259
+ 1.6747721049456963
+ 1.6749078981219894
+ 1.6750436763767567
+ 1.6751794397144484
+ 1.6753151881395119
+ 1.675450921656392
+ 1.675586640269532
+ 1.6757223439833733
+ 1.675858032802354
+ 1.6759937067309112
+ 1.6761293657734793
+ 1.6762650099344907
+ 1.6764006392183755
+ 1.6765362536295616
+ 1.6766718531724754
+ 1.6768074378515399
+ 1.676943007671177
+ 1.6770785626358067
+ 1.6772141027498457
+ 1.677349628017709
+ 1.6774851384438096
+ 1.6776206340325592
+ 1.6777561147883657
+ 1.677891580715636
+ 1.6780270318187747
+ 1.6781624681021838
+ 1.678297889570264
+ 1.6784332962274127
+ 1.6785686880780264
+ 1.6787040651264984
+ 1.6788394273772207
+ 1.678974774834583
+ 1.6791101075029724
+ 1.6792454253867746
+ 1.6793807284903723
+ 1.6795160168181469
+ 1.6796512903744774
+ 1.6797865491637403
+ 1.6799217931903103
+ 1.6800570224585607
+ 1.680192236972861
+ 1.6803274367375804
+ 1.6804626217570848
+ 1.6805977920357384
+ 1.6807329475779034
+ 1.6808680883879392
+ 1.6810032144702045
+ 1.6811383258290542
+ 1.6812734224688426
+ 1.681408504393921
+ 1.6815435716086387
+ 1.6816786241173431
+ 1.6818136619243798
+ 1.6819486850340912
+ 1.682083693450819
+ 1.682218687178902
+ 1.682353666222677
+ 1.682488630586479
+ 1.6826235802746403
+ 1.682758515291492
+ 1.6828934356413623
+ 1.6830283413285778
+ 1.6831632323574628
+ 1.6832981087323393
+ 1.683432970457528
+ 1.683567817537347
+ 1.683702649976112
+ 1.6838374677781371
+ 1.6839722709477343
+ 1.6841070594892136
+ 1.6842418334068825
+ 1.6843765927050465
+ 1.6845113373880096
+ 1.684646067460073
+ 1.6847807829255368
+ 1.684915483788698
+ 1.6850501700538516
+ 1.6851848417252917
+ 1.685319498807309
+ 1.6854541413041928
+ 1.6855887692202305
+ 1.6857233825597069
+ 1.6858579813269048
+ 1.6859925655261059
+ 1.686127135161588
+ 1.686261690237629
+ 1.6863962307585034
+ 1.686530756728484
+ 1.686665268151841
+ 1.686799765032844
+ 1.6869342473757585
+ 1.68706871518485
+ 1.6872031684643807
+ 1.6873376072186115
+ 1.6874720314518001
+ 1.687606441168204
+ 1.6877408363720765
+ 1.6878752170676705
+ 1.6880095832592363
+ 1.6881439349510226
+ 1.6882782721472749
+ 1.6884125948522377
+ 1.6885469030701536
+ 1.6886811968052624
+ 1.6888154760618026
+ 1.6889497408440097
+ 1.6890839911561186
+ 1.6892182270023612
+ 1.6893524483869673
+ 1.689486655314165
+ 1.6896208477881804
+ 1.6897550258132379
+ 1.6898891893935593
+ 1.6900233385333643
+ 1.690157473236871
+ 1.6902915935082958
+ 1.6904256993518523
+ 1.6905597907717522
+ 1.6906938677722063
+ 1.690827930357422
+ 1.6909619785316052
+ 1.6910960122989602
+ 1.6912300316636886
+ 1.6913640366299907
+ 1.691498027202064
+ 1.6916320033841048
+ 1.6917659651803072
+ 1.6918999125948628
+ 1.692033845631962
+ 1.6921677642957922
+ 1.6923016685905399
+ 1.692435558520389
+ 1.6925694340895214
+ 1.692703295302117
+ 1.6928371421623545
+ 1.6929709746744093
+ 1.6931047928424556
+ 1.6932385966706658
+ 1.69337238616321
+ 1.6935061613242557
+ 1.6936399221579699
+ 1.6937736686685163
+ 1.6939074008600574
+ 1.6940411187367532
+ 1.6941748223027624
+ 1.6943085115622405
+ 1.6944421865193426
+ 1.6945758471782209
+ 1.6947094935430256
+ 1.6948431256179053
+ 1.6949767434070062
+ 1.6951103469144733
+ 1.6952439361444487
+ 1.6953775111010732
+ 1.6955110717884854
+ 1.695644618210822
+ 1.6957781503722174
+ 1.6959116682768047
+ 1.696045171928715
+ 1.6961786613320766
+ 1.6963121364910165
+ 1.6964455974096597
+ 1.6965790440921296
+ 1.6967124765425468
+ 1.6968458947650302
+ 1.6969792987636974
+ 1.6971126885426637
+ 1.6972460641060418
+ 1.6973794254579437
+ 1.6975127726024786
+ 1.6976461055437537
+ 1.6977794242858748
+ 1.6979127288329456
+ 1.6980460191890672
+ 1.69817929535834
+ 1.698312557344861
+ 1.698445805152727
+ 1.6985790387860313
+ 1.6987122582488658
+ 1.698845463545321
+ 1.698978654679485
+ 1.6991118316554434
+ 1.6992449944772816
+ 1.699378143149081
+ 1.6995112776749226
+ 1.6996443980588847
+ 1.699777504305044
+ 1.6999105964174752
+ 1.700043674400251
+ 1.700176738257442
+ 1.7003097879931177
+ 1.7004428236113454
+ 1.7005758451161894
+ 1.700708852511713
+ 1.7008418458019783
+ 1.700974824991044
+ 1.701107790082968
+ 1.7012407410818056
+ 1.7013736779916107
+ 1.7015066008164348
+ 1.7016395095603283
+ 1.7017724042273386
+ 1.7019052848215122
+ 1.7020381513468932
+ 1.702171003807524
+ 1.7023038422074448
+ 1.7024366665506943
+ 1.7025694768413089
+ 1.7027022730833237
+ 1.7028350552807712
+ 1.7029678234376826
+ 1.7031005775580867
+ 1.7032333176460108
+ 1.7033660437054803
+ 1.7034987557405186
+ 1.7036314537551471
+ 1.7037641377533854
+ 1.7038968077392513
+ 1.704029463716761
+ 1.704162105689928
+ 1.704294733662765
+ 1.704427347639282
+ 1.704559947623487
+ 1.7046925336193872
+ 1.7048251056309869
+ 1.7049576636622887
+ 1.7050902077172938
+ 1.7052227378000009
+ 1.705355253914408
+ 1.7054877560645092
+ 1.7056202442542985
+ 1.7057527184877679
+ 1.7058851787689067
+ 1.7060176251017025
+ 1.7061500574901416
+ 1.7062824759382083
+ 1.7064148804498847
+ 1.706547271029151
+ 1.7066796476799861
+ 1.7068120104063667
+ 1.7069443592122675
+ 1.7070766941016615
+ 1.70720901507852
+ 1.7073413221468121
+ 1.7074736153105057
+ 1.707605894573566
+ 1.707738159939957
+ 1.7078704114136405
+ 1.7080026489985765
+ 1.7081348726987235
+ 1.708267082518038
+ 1.708399278460474
+ 1.7085314605299846
+ 1.708663628730521
+ 1.7087957830660319
+ 1.7089279235404644
+ 1.7090600501577642
+ 1.7091921629218747
+ 1.7093242618367375
+ 1.709456346906293
+ 1.7095884181344785
+ 1.7097204755252309
+ 1.7098525190824845
+ 1.7099845488101717
+ 1.7101165647122232
+ 1.710248566792568
+ 1.7103805550551336
+ 1.7105125295038448
+ 1.7106444901426257
+ 1.710776436975397
+ 1.7109083700060796
+ 1.7110402892385908
+ 1.7111721946768472
+ 1.711304086324763
+ 1.7114359641862509
+ 1.7115678282652218
+ 1.7116996785655845
+ 1.711831515091246
+ 1.711963337846112
+ 1.7120951468340861
+ 1.71222694205907
+ 1.712358723524963
+ 1.712490491235664
+ 1.7126222451950692
+ 1.712753985407073
+ 1.7128857118755683
+ 1.7130174246044456
+ 1.7131491235975949
+ 1.7132808088589024
+ 1.7134124803922546
+ 1.7135441382015348
+ 1.7136757822906252
+ 1.713807412663406
+ 1.7139390293237553
+ 1.71407063227555
+ 1.7142022215226647
+ 1.7143337970689725
+ 1.7144653589183447
+ 1.7145969070746507
+ 1.714728441541758
+ 1.7148599623235325
+ 1.7149914694238388
+ 1.715122962846539
+ 1.7152544425954932
+ 1.7153859086745606
+ 1.7155173610875984
+ 1.715648799838461
+ 1.7157802249310028
+ 1.7159116363690752
+ 1.7160430341565274
+ 1.7161744182972083
+ 1.7163057887949642
+ 1.7164371456536396
+ 1.716568488877077
+ 1.7166998184691178
+ 1.7168311344336011
+ 1.7169624367743646
+ 1.7170937254952443
+ 1.7172250006000738
+ 1.717356262092685
+ 1.7174875099769094
+ 1.7176187442565747
+ 1.7177499649355088
+ 1.7178811720175362
+ 1.7180123655064805
+ 1.7181435454061638
+ 1.7182747117204056
+ 1.7184058644530245
+ 1.7185370036078365
+ 1.7186681291886563
+ 1.7187992411992974
+ 1.7189303396435707
+ 1.7190614245252855
+ 1.7191924958482496
+ 1.719323553616269
+ 1.719454597833148
+ 1.7195856285026891
+ 1.719716645628693
+ 1.7198476492149584
+ 1.719978639265283
+ 1.7201096157834623
+ 1.72024057877329
+ 1.7203715282385577
+ 1.7205024641830564
+ 1.7206333866105745
+ 1.720764295524899
+ 1.7208951909298145
+ 1.7210260728291047
+ 1.7211569412265513
+ 1.7212877961259345
+ 1.721418637531032
+ 1.7215494654456207
+ 1.7216802798734752
+ 1.7218110808183686
+ 1.7219418682840721
+ 1.7220726422743553
+ 1.7222034027929864
+ 1.722334149843731
+ 1.7224648834303542
+ 1.7225956035566183
+ 1.7227263102262846
+ 1.722857003443112
+ 1.7229876832108586
+ 1.7231183495332796
+ 1.7232490024141296
+ 1.7233796418571614
+ 1.723510267866125
+ 1.7236408804447698
+ 1.7237714795968433
+ 1.723902065326091
+ 1.7240326376362562
+ 1.7241631965310822
+ 1.724293742014309
+ 1.7244242740896754
+ 1.7245547927609184
+ 1.7246852980317735
+ 1.7248157899059746
+ 1.7249462683872534
+ 1.7250767334793407
+ 1.7252071851859643
+ 1.7253376235108522
+ 1.7254680484577287
+ 1.725598460030318
+ 1.7257288582323418
+ 1.7258592430675197
+ 1.725989614539571
+ 1.726119972652212
+ 1.7262503174091581
+ 1.7263806488141225
+ 1.726510966870817
+ 1.7266412715829518
+ 1.7267715629542348
+ 1.7269018409883732
+ 1.7270321056890718
+ 1.7271623570600343
+ 1.7272925951049618
+ 1.7274228198275545
+ 1.7275530312315106
+ 1.7276832293205266
+ 1.7278134140982981
+ 1.727943585568518
+ 1.7280737437348777
+ 1.728203888601067
+ 1.7283340201707749
+ 1.7284641384476875
+ 1.7285942434354895
+ 1.728724335137865
+ 1.7288544135584947
+ 1.7289844787010589
+ 1.729114530569236
+ 1.7292445691667024
+ 1.7293745944971333
+ 1.7295046065642017
+ 1.7296346053715792
+ 1.7297645909229362
+ 1.7298945632219407
+ 1.7300245222722592
+ 1.7301544680775571
+ 1.7302844006414975
+ 1.7304143199677422
+ 1.730544226059951
+ 1.7306741189217827
+ 1.7308039985568937
+ 1.7309338649689394
+ 1.731063718161573
+ 1.7311935581384463
+ 1.7313233849032097
+ 1.7314531984595116
+ 1.7315829988109985
+ 1.7317127859613162
+ 1.731842559914108
+ 1.7319723206730158
+ 1.7321020682416801
+ 1.7322318026237393
+ 1.7323615238228307
+ 1.7324912318425896
+ 1.7326209266866497
+ 1.732750608358643
+ 1.7328802768622003
+ 1.7330099322009502
+ 1.7331395743785203
+ 1.7332692033985353
+ 1.7333988192646204
+ 1.733528421980397
+ 1.7336580115494862
+ 1.7337875879755067
+ 1.7339171512620766
+ 1.7340467014128111
+ 1.734176238431325
+ 1.7343057623212308
+ 1.7344352730861388
+ 1.7345647707296592
+ 1.734694255255399
+ 1.7348237266669648
+ 1.734953184967961
+ 1.7350826301619904
+ 1.7352120622526541
+ 1.7353414812435521
+ 1.7354708871382822
+ 1.7356002799404409
+ 1.7357296596536231
+ 1.7358590262814217
+ 1.7359883798274287
+ 1.7361177202952338
+ 1.7362470476884255
+ 1.7363763620105905
+ 1.7365056632653137
+ 1.7366349514561794
+ 1.7367642265867689
+ 1.7368934886606628
+ 1.7370227376814398
+ 1.737151973652677
+ 1.7372811965779502
+ 1.737410406460833
+ 1.737539603304898
+ 1.737668787113716
+ 1.737797957890856
+ 1.7379271156398857
+ 1.738056260364371
+ 1.7381853920678763
+ 1.7383145107539644
+ 1.7384436164261967
+ 1.7385727090881324
+ 1.73870178874333
+ 1.7388308553953455
+ 1.7389599090477343
+ 1.739088949704049
+ 1.7392179773678418
+ 1.7393469920426625
+ 1.7394759937320599
+ 1.7396049824395807
+ 1.7397339581687707
+ 1.7398629209231729
+ 1.7399918707063302
+ 1.7401208075217827
+ 1.74024973137307
+ 1.740378642263729
+ 1.740507540197296
+ 1.7406364251773052
+ 1.7407652972072893
+ 1.7408941562907796
+ 1.7410230024313056
+ 1.7411518356323954
+ 1.7412806558975753
+ 1.7414094632303707
+ 1.7415382576343044
+ 1.741667039112898
+ 1.7417958076696725
+ 1.741924563308146
+ 1.7420533060318355
+ 1.7421820358442568
+ 1.7423107527489237
+ 1.7424394567493486
+ 1.7425681478490422
+ 1.7426968260515143
+ 1.742825491360272
+ 1.742954143778822
+ 1.7430827833106683
+ 1.7432114099593143
+ 1.7433400237282617
+ 1.74346862462101
+ 1.743597212641058
+ 1.7437257877919023
+ 1.7438543500770383
+ 1.7439828994999595
+ 1.7441114360641587
+ 1.744239959773126
+ 1.7443684706303506
+ 1.7444969686393201
+ 1.7446254538035204
+ 1.7447539261264362
+ 1.7448823856115505
+ 1.7450108322623445
+ 1.7451392660822982
+ 1.7452676870748896
+ 1.7453960952435958
+ 1.7455244905918919
+ 1.7456528731232517
+ 1.7457812428411472
+ 1.7459095997490492
+ 1.7460379438504265
+ 1.7461662751487472
+ 1.7462945936474767
+ 1.74642289935008
+ 1.74655119226002
+ 1.746679472380758
+ 1.7468077397157538
+ 1.746935994268466
+ 1.7470642360423514
+ 1.7471924650408652
+ 1.7473206812674618
+ 1.7474488847255925
+ 1.747577075418709
+ 1.74770525335026
+ 1.7478334185236932
+ 1.7479615709424554
+ 1.7480897106099909
+ 1.7482178375297424
+ 1.7483459517051523
+ 1.7484740531396605
+ 1.7486021418367055
+ 1.7487302177997246
+ 1.7488582810321531
+ 1.7489863315374252
+ 1.7491143693189737
+ 1.7492423943802295
+ 1.749370406724622
+ 1.7494984063555796
+ 1.7496263932765286
+ 1.7497543674908942
+ 1.7498823290020997
+ 1.750010277813567
+ 1.750138213928717
+ 1.7502661373509687
+ 1.7503940480837392
+ 1.7505219461304449
+ 1.7506498314945003
+ 1.7507777041793182
+ 1.7509055641883102
+ 1.7510334115248865
+ 1.7511612461924553
+ 1.7512890681944235
+ 1.7514168775341974
+ 1.7515446742151803
+ 1.7516724582407752
+ 1.7518002296143829
+ 1.7519279883394028
+ 1.7520557344192331
+ 1.7521834678572707
+ 1.7523111886569103
+ 1.7524388968215459
+ 1.752566592354569
+ 1.7526942752593706
+ 1.7528219455393401
+ 1.7529496031978649
+ 1.7530772482383312
+ 1.7532048806641236
+ 1.7533325004786255
+ 1.7534601076852185
+ 1.753587702287283
+ 1.7537152842881976
+ 1.7538428536913397
+ 1.7539704105000853
+ 1.7540979547178082
+ 1.754225486347882
+ 1.7543530053936776
+ 1.7544805118585651
+ 1.754608005745913
+ 1.754735487059088
+ 1.7548629558014563
+ 1.754990411976381
+ 1.7551178555872258
+ 1.7552452866373507
+ 1.7553727051301158
+ 1.7555001110688795
+ 1.755627504456998
+ 1.7557548852978273
+ 1.7558822535947203
+ 1.75600960935103
+ 1.7561369525701072
+ 1.7562642832553008
+ 1.7563916014099594
+ 1.756518907037429
+ 1.7566462001410545
+ 1.75677348072418
+ 1.7569007487901473
+ 1.7570280043422972
+ 1.7571552473839687
+ 1.7572824779185
+ 1.7574096959492265
+ 1.757536901479484
+ 1.7576640945126054
+ 1.7577912750519225
+ 1.7579184431007662
+ 1.7580455986624655
+ 1.7581727417403477
+ 1.758299872337739
+ 1.7584269904579646
+ 1.758554096104347
+ 1.7586811892802086
+ 1.7588082699888694
+ 1.7589353382336486
+ 1.7590623940178636
+ 1.7591894373448302
+ 1.7593164682178637
+ 1.7594434866402764
+ 1.7595704926153806
+ 1.7596974861464865
+ 1.7598244672369028
+ 1.759951435889937
+ 1.7600783921088954
+ 1.760205335897082
+ 1.7603322672578003
+ 1.7604591861943522
+ 1.7605860927100372
+ 1.7607129868081546
+ 1.760839868492002
+ 1.760966737764875
+ 1.7610935946300685
+ 1.761220439090875
+ 1.7613472711505869
+ 1.7614740908124942
+ 1.7616008980798858
+ 1.7617276929560493
+ 1.7618544754442698
+ 1.761981245547833
+ 1.7621080032700214
+ 1.762234748614117
+ 1.7623614815834
+ 1.7624882021811492
+ 1.7626149104106423
+ 1.7627416062751555
+ 1.762868289777963
+ 1.7629949609223383
+ 1.7631216197115533
+ 1.7632482661488782
+ 1.7633749002375823
+ 1.7635015219809327
+ 1.7636281313821962
+ 1.7637547284446369
+ 1.7638813131715185
+ 1.7640078855661032
+ 1.764134445631651
+ 1.7642609933714215
+ 1.764387528788672
+ 1.764514051886659
+ 1.764640562668638
+ 1.7647670611378616
+ 1.7648935472975824
+ 1.765020021151051
+ 1.7651464827015166
+ 1.7652729319522276
+ 1.76539936890643
+ 1.7655257935673692
+ 1.7656522059382886
+ 1.765778606022431
+ 1.7659049938230367
+ 1.7660313693433458
+ 1.7661577325865963
+ 1.7662840835560247
+ 1.7664104222548669
+ 1.7665367486863566
+ 1.7666630628537259
+ 1.7667893647602064
+ 1.766915654409028
+ 1.767041931803419
+ 1.7671681969466062
+ 1.7672944498418157
+ 1.7674206904922711
+ 1.767546918901196
+ 1.7676731350718116
+ 1.7677993390073377
+ 1.7679255307109936
+ 1.7680517101859958
+ 1.7681778774355612
+ 1.7683040324629034
+ 1.7684301752712364
+ 1.7685563058637717
+ 1.7686824242437198
+ 1.7688085304142898
+ 1.768934624378689
+ 1.7690607061401245
+ 1.7691867757018005
+ 1.7693128330669208
+ 1.7694388782386876
+ 1.7695649112203018
+ 1.769690932014963
+ 1.7698169406258688
+ 1.7699429370562163
+ 1.770068921309201
+ 1.7701948933880165
+ 1.7703208532958554
+ 1.7704468010359091
+ 1.7705727366113675
+ 1.770698660025419
+ 1.7708245712812511
+ 1.7709504703820491
+ 1.7710763573309978
+ 1.77120223213128
+ 1.7713280947860774
+ 1.7714539452985707
+ 1.7715797836719385
+ 1.7717056099093589
+ 1.7718314240140076
+ 1.7719572259890597
+ 1.7720830158376892
+ 1.7722087935630677
+ 1.7723345591683664
+ 1.7724603126567546
+ 1.7725860540314007
+ 1.772711783295471
+ 1.772837500452132
+ 1.7729632055045468
+ 1.7730888984558784
+ 1.7732145793092882
+ 1.7733402480679363
+ 1.7734659047349817
+ 1.7735915493135812
+ 1.7737171818068913
+ 1.7738428022180663
+ 1.7739684105502598
+ 1.7740940068066238
+ 1.7742195909903087
+ 1.774345163104464
+ 1.7744707231522376
+ 1.7745962711367762
+ 1.774721807061225
+ 1.7748473309287278
+ 1.7749728427424274
+ 1.7750983425054652
+ 1.7752238302209808
+ 1.7753493058921133
+ 1.7754747695219995
+ 1.7756002211137756
+ 1.7757256606705758
+ 1.775851088195534
+ 1.7759765036917818
+ 1.7761019071624498
+ 1.776227298610667
+ 1.7763526780395622
+ 1.7764780454522615
+ 1.7766034008518898
+ 1.7767287442415718
+ 1.7768540756244298
+ 1.7769793950035853
+ 1.7771047023821578
+ 1.7772299977632664
+ 1.7773552811500286
+ 1.7774805525455601
+ 1.777605811952976
+ 1.7777310593753892
+ 1.7778562948159122
+ 1.7779815182776553
+ 1.7781067297637287
+ 1.7782319292772397
+ 1.7783571168212955
+ 1.7784822923990014
+ 1.778607456013462
+ 1.7787326076677796
+ 1.7788577473650564
+ 1.778982875108392
+ 1.7791079909008858
+ 1.7792330947456352
+ 1.7793581866457364
+ 1.7794832666042846
+ 1.7796083346243736
+ 1.7797333907090955
+ 1.7798584348615416
+ 1.7799834670848014
+ 1.7801084873819635
+ 1.780233495756115
+ 1.7803584922103421
+ 1.780483476747729
+ 1.780608449371359
+ 1.7807334100843142
+ 1.780858358889675
+ 1.780983295790521
+ 1.7811082207899303
+ 1.7812331338909793
+ 1.7813580350967437
+ 1.7814829244102974
+ 1.7816078018347141
+ 1.7817326673730645
+ 1.7818575210284189
+ 1.7819823628038465
+ 1.7821071927024152
+ 1.7822320107271912
+ 1.7823568168812396
+ 1.782481611167624
+ 1.7826063935894074
+ 1.7827311641496506
+ 1.7828559228514138
+ 1.7829806696977555
+ 1.7831054046917332
+ 1.783230127836403
+ 1.783354839134819
+ 1.783479538590036
+ 1.7836042262051053
+ 1.783728901983078
+ 1.7838535659270043
+ 1.7839782180399317
+ 1.7841028583249081
+ 1.7842274867849786
+ 1.7843521034231884
+ 1.7844767082425803
+ 1.7846013012461968
+ 1.7847258824370777
+ 1.7848504518182633
+ 1.7849750093927916
+ 1.785099555163699
+ 1.7852240891340216
+ 1.7853486113067936
+ 1.785473121685048
+ 1.7855976202718167
+ 1.7857221070701301
+ 1.7858465820830174
+ 1.7859710453135067
+ 1.7860954967646245
+ 1.7862199364393967
+ 1.786344364340847
+ 1.7864687804719985
+ 1.7865931848358727
+ 1.7867175774354902
+ 1.7868419582738702
+ 1.78696632735403
+ 1.7870906846789865
+ 1.787215030251755
+ 1.7873393640753497
+ 1.7874636861527835
+ 1.7875879964870673
+ 1.787712295081212
+ 1.7878365819382265
+ 1.7879608570611183
+ 1.7880851204528942
+ 1.788209372116559
+ 1.7883336120551174
+ 1.7884578402715716
+ 1.7885820567689232
+ 1.7887062615501723
+ 1.7888304546183182
+ 1.7889546359763584
+ 1.7890788056272893
+ 1.7892029635741062
+ 1.789327109819803
+ 1.7894512443673727
+ 1.7895753672198063
+ 1.7896994783800944
+ 1.7898235778512261
+ 1.7899476656361888
+ 1.790071741737969
+ 1.7901958061595518
+ 1.7903198589039215
+ 1.7904438999740608
+ 1.7905679293729513
+ 1.790691947103573
+ 1.7908159531689047
+ 1.790939947571925
+ 1.7910639303156097
+ 1.7911879014029346
+ 1.7913118608368732
+ 1.7914358086203988
+ 1.7915597447564828
+ 1.7916836692480957
+ 1.7918075820982065
+ 1.7919314833097828
+ 1.7920553728857918
+ 1.7921792508291987
+ 1.7923031171429677
+ 1.7924269718300614
+ 1.792550814893442
+ 1.7926746463360697
+ 1.7927984661609038
+ 1.7929222743709023
+ 1.7930460709690221
+ 1.7931698559582188
+ 1.7932936293414468
+ 1.7934173911216587
+ 1.7935411413018072
+ 1.7936648798848422
+ 1.7937886068737137
+ 1.7939123222713698
+ 1.794036026080757
+ 1.794159718304822
+ 1.7942833989465086
+ 1.7944070680087605
+ 1.794530725494519
+ 1.7946543714067265
+ 1.7947780057483211
+ 1.7949016285222426
+ 1.7950252397314275
+ 1.7951488393788118
+ 1.7952724274673302
+ 1.7953960039999166
+ 1.7955195689795036
+ 1.795643122409022
+ 1.7957666642914016
+ 1.7958901946295713
+ 1.7960137134264589
+ 1.7961372206849904
+ 1.796260716408091
+ 1.7963842005986843
+ 1.7965076732596934
+ 1.7966311343940398
+ 1.7967545840046435
+ 1.7968780220944238
+ 1.797001448666298
+ 1.7971248637231834
+ 1.797248267267995
+ 1.7973716593036475
+ 1.7974950398330536
+ 1.797618408859125
+ 1.7977417663847728
+ 1.797865112412906
+ 1.7979884469464331
+ 1.7981117699882607
+ 1.798235081541295
+ 1.7983583816084407
+ 1.7984816701926014
+ 1.7986049472966787
+ 1.798728212923574
+ 1.798851467076187
+ 1.7989747097574167
+ 1.7990979409701602
+ 1.7992211607173139
+ 1.7993443690017727
+ 1.7994675658264307
+ 1.7995907511941807
+ 1.7997139251079137
+ 1.7998370875705205
+ 1.7999602385848898
+ 1.8000833781539096
+ 1.800206506280467
+ 1.8003296229674475
+ 1.800452728217735
+ 1.8005758220342127
+ 1.800698904419763
+ 1.8008219753772665
+ 1.8009450349096028
+ 1.8010680830196504
+ 1.8011911197102863
+ 1.801314144984387
+ 1.8014371588448272
+ 1.8015601612944803
+ 1.8016831523362193
+ 1.801806131972915
+ 1.8019291002074382
+ 1.8020520570426577
+ 1.802175002481441
+ 1.8022979365266547
+ 1.8024208591811648
+ 1.8025437704478353
+ 1.8026666703295289
+ 1.8027895588291083
+ 1.8029124359494335
+ 1.8030353016933645
+ 1.8031581560637597
+ 1.8032809990634762
+ 1.8034038306953706
+ 1.8035266509622967
+ 1.8036494598671093
+ 1.8037722574126605
+ 1.8038950436018018
+ 1.804017818437383
+ 1.8041405819222538
+ 1.8042633340592618
+ 1.804386074851254
+ 1.8045088043010753
+ 1.8046315224115705
+ 1.804754229185583
+ 1.8048769246259546
+ 1.8049996087355265
+ 1.805122281517138
+ 1.8052449429736281
+ 1.8053675931078341
+ 1.805490231922592
+ 1.8056128594207375
+ 1.805735475605104
+ 1.8058580804785245
+ 1.8059806740438304
+ 1.8061032563038526
+ 1.8062258272614202
+ 1.8063483869193613
+ 1.806470935280503
+ 1.8065934723476713
+ 1.8067159981236904
+ 1.8068385126113844
+ 1.8069610158135754
+ 1.807083507733085
+ 1.807205988372733
+ 1.8073284577353381
+ 1.8074509158237186
+ 1.807573362640691
+ 1.8076957981890707
+ 1.807818222471672
+ 1.8079406354913081
+ 1.8080630372507913
+ 1.8081854277529323
+ 1.8083078070005412
+ 1.8084301749964262
+ 1.808552531743395
+ 1.808674877244254
+ 1.8087972115018083
+ 1.808919534518862
+ 1.8090418462982176
+ 1.8091641468426776
+ 1.8092864361550423
+ 1.8094087142381112
+ 1.8095309810946827
+ 1.809653236727554
+ 1.8097754811395212
+ 1.8098977143333792
+ 1.8100199363119218
+ 1.8101421470779417
+ 1.8102643466342305
+ 1.8103865349835786
+ 1.810508712128775
+ 1.8106308780726084
+ 1.8107530328178656
+ 1.810875176367332
+ 1.8109973087237932
+ 1.8111194298900322
+ 1.8112415398688315
+ 1.8113636386629726
+ 1.811485726275236
+ 1.8116078027084004
+ 1.811729867965244
+ 1.8118519220485438
+ 1.811973964961075
+ 1.8120959967056127
+ 1.8122180172849303
+ 1.8123400267018002
+ 1.8124620249589933
+ 1.81258401205928
+ 1.812705988005429
+ 1.8128279528002087
+ 1.8129499064463854
+ 1.8130718489467248
+ 1.8131937803039917
+ 1.8133157005209493
+ 1.8134376096003595
+ 1.813559507544984
+ 1.8136813943575827
+ 1.8138032700409144
+ 1.813925134597737
+ 1.814046988030807
+ 1.8141688303428802
+ 1.8142906615367111
+ 1.8144124816150529
+ 1.814534290580658
+ 1.8146560884362772
+ 1.8147778751846608
+ 1.8148996508285578
+ 1.8150214153707158
+ 1.8151431688138815
+ 1.8152649111608004
+ 1.815386642414217
+ 1.815508362576875
+ 1.8156300716515166
+ 1.8157517696408825
+ 1.8158734565477128
+ 1.8159951323747467
+ 1.8161167971247223
+ 1.816238450800376
+ 1.816360093404443
+ 1.8164817249396585
+ 1.816603345408756
+ 1.816724954814467
+ 1.8168465531595235
+ 1.8169681404466553
+ 1.8170897166785918
+ 1.8172112818580601
+ 1.817332835987788
+ 1.8174543790705004
+ 1.8175759111089227
+ 1.8176974321057775
+ 1.8178189420637882
+ 1.8179404409856759
+ 1.8180619288741604
+ 1.818183405731961
+ 1.818304871561796
+ 1.8184263263663825
+ 1.818547770148436
+ 1.8186692029106715
+ 1.8187906246558025
+ 1.818912035386542
+ 1.8190334351056012
+ 1.8191548238156905
+ 1.8192762015195194
+ 1.819397568219796
+ 1.8195189239192275
+ 1.8196402686205204
+ 1.8197616023263792
+ 1.8198829250395079
+ 1.8200042367626095
+ 1.8201255374983856
+ 1.8202468272495365
+ 1.8203681060187626
+ 1.8204893738087615
+ 1.8206106306222314
+ 1.8207318764618683
+ 1.8208531113303672
+ 1.8209743352304224
+ 1.8210955481647273
+ 1.8212167501359737
+ 1.8213379411468524
+ 1.8214591212000535
+ 1.8215802902982654
+ 1.8217014484441765
+ 1.8218225956404728
+ 1.8219437318898397
+ 1.8220648571949625
+ 1.8221859715585238
+ 1.8223070749832062
+ 1.8224281674716911
+ 1.8225492490266586
+ 1.8226703196507879
+ 1.8227913793467567
+ 1.8229124281172424
+ 1.8230334659649203
+ 1.8231544928924661
+ 1.823275508902553
+ 1.8233965139978536
+ 1.8235175081810397
+ 1.823638491454782
+ 1.82375946382175
+ 1.8238804252846121
+ 1.8240013758460354
+ 1.8241223155086863
+ 1.8242432442752303
+ 1.8243641621483313
+ 1.8244850691306524
+ 1.8246059652248559
+ 1.8247268504336025
+ 1.824847724759552
+ 1.8249685882053641
+ 1.8250894407736957
+ 1.825210282467204
+ 1.8253311132885444
+ 1.825451933240372
+ 1.8255727423253398
+ 1.8256935405461006
+ 1.825814327905306
+ 1.825935104405606
+ 1.8260558700496505
+ 1.8261766248400875
+ 1.826297368779564
+ 1.8264181018707264
+ 1.82653882411622
+ 1.8266595355186885
+ 1.8267802360807757
+ 1.8269009258051225
+ 1.8270216046943706
+ 1.8271422727511595
+ 1.8272629299781287
+ 1.8273835763779152
+ 1.827504211953156
+ 1.8276248367064865
+ 1.8277454506405417
+ 1.8278660537579554
+ 1.8279866460613599
+ 1.8281072275533863
+ 1.828227798236666
+ 1.8283483581138273
+ 1.8284689071874995
+ 1.8285894454603095
+ 1.8287099729348832
+ 1.8288304896138468
+ 1.8289509954998238
+ 1.8290714905954373
+ 1.82919197490331
+ 1.8293124484260623
+ 1.8294329111663152
+ 1.8295533631266865
+ 1.829673804309795
+ 1.8297942347182574
+ 1.8299146543546896
+ 1.8300350632217062
+ 1.8301554613219213
+ 1.8302758486579478
+ 1.8303962252323973
+ 1.8305165910478804
+ 1.8306369461070071
+ 1.8307572904123857
+ 1.830877623966624
+ 1.8309979467723285
+ 1.8311182588321047
+ 1.8312385601485572
+ 1.8313588507242897
+ 1.831479130561905
+ 1.8315993996640034
+ 1.8317196580331863
+ 1.8318399056720525
+ 1.8319601425832008
+ 1.8320803687692282
+ 1.8322005842327311
+ 1.8323207889763051
+ 1.8324409830025439
+ 1.8325611663140413
+ 1.832681338913389
+ 1.8328015008031784
+ 1.8329216519859997
+ 1.833041792464442
+ 1.8331619222410935
+ 1.8332820413185411
+ 1.8334021496993709
+ 1.8335222473861683
+ 1.833642334381517
+ 1.833762410688
+ 1.8338824763081993
+ 1.8340025312446964
+ 1.8341225755000707
+ 1.8342426090769013
+ 1.8343626319777662
+ 1.8344826442052422
+ 1.8346026457619051
+ 1.8347226366503302
+ 1.834842616873091
+ 1.8349625864327608
+ 1.835082545331911
+ 1.8352024935731126
+ 1.8353224311589353
+ 1.8354423580919483
+ 1.835562274374719
+ 1.8356821800098144
+ 1.8358020749998
+ 1.835921959347241
+ 1.8360418330547013
+ 1.836161696124743
+ 1.8362815485599282
+ 1.836401390362818
+ 1.8365212215359714
+ 1.8366410420819477
+ 1.8367608520033047
+ 1.8368806513025988
+ 1.8370004399823856
+ 1.8371202180452204
+ 1.8372399854936563
+ 1.8373597423302468
+ 1.8374794885575427
+ 1.8375992241780952
+ 1.8377189491944543
+ 1.837838663609168
+ 1.8379583674247846
+ 1.8380780606438505
+ 1.8381977432689114
+ 1.8383174153025124
+ 1.838437076747197
+ 1.838556727605508
+ 1.8386763678799867
+ 1.8387959975731742
+ 1.8389156166876106
+ 1.8390352252258342
+ 1.8391548231903825
+ 1.8392744105837928
+ 1.8393939874086007
+ 1.8395135536673408
+ 1.8396331093625473
+ 1.8397526544967524
+ 1.8398721890724883
+ 1.8399917130922858
+ 1.8401112265586745
+ 1.8402307294741835
+ 1.8403502218413403
+ 1.8404697036626725
+ 1.840589174940705
+ 1.8407086356779634
+ 1.840828085876971
+ 1.8409475255402514
+ 1.841066954670326
+ 1.8411863732697158
+ 1.8413057813409408
+ 1.8414251788865201
+ 1.8415445659089718
+ 1.8416639424108125
+ 1.8417833083945587
+ 1.841902663862725
+ 1.8420220088178256
+ 1.8421413432623739
+ 1.8422606671988813
+ 1.8423799806298597
+ 1.8424992835578187
+ 1.8426185759852678
+ 1.842737857914715
+ 1.8428571293486675
+ 1.8429763902896317
+ 1.8430956407401125
+ 1.8432148807026147
+ 1.8433341101796412
+ 1.8434533291736943
+ 1.8435725376872758
+ 1.8436917357228857
+ 1.8438109232830233
+ 1.8439301003701876
+ 1.8440492669868755
+ 1.8441684231355835
+ 1.8442875688188076
+ 1.844406704039042
+ 1.8445258287987802
+ 1.844644943100515
+ 1.844764046946738
+ 1.84488314033994
+ 1.8450022232826104
+ 1.8451212957772385
+ 1.8452403578263112
+ 1.845359409432316
+ 1.8454784505977386
+ 1.8455974813250637
+ 1.8457165016167754
+ 1.8458355114753564
+ 1.845954510903289
+ 1.846073499903054
+ 1.8461924784771315
+ 1.846311446628001
+ 1.8464304043581399
+ 1.8465493516700258
+ 1.8466682885661347
+ 1.846787215048942
+ 1.846906131120922
+ 1.847025036784548
+ 1.8471439320422924
+ 1.8472628168966265
+ 1.8473816913500212
+ 1.8475005554049453
+ 1.8476194090638678
+ 1.847738252329256
+ 1.8478570852035767
+ 1.8479759076892956
+ 1.848094719788878
+ 1.8482135215047863
+ 1.8483323128394846
+ 1.8484510937954342
+ 1.8485698643750956
+ 1.8486886245809295
+ 1.8488073744153948
+ 1.8489261138809492
+ 1.84904484298005
+ 1.8491635617151536
+ 1.8492822700887146
+ 1.8494009681031878
+ 1.8495196557610263
+ 1.8496383330646824
+ 1.8497570000166077
+ 1.8498756566192525
+ 1.8499943028750665
+ 1.8501129387864979
+ 1.8502315643559946
+ 1.8503501795860036
+ 1.8504687844789702
+ 1.850587379037339
+ 1.8507059632635545
+ 1.8508245371600593
+ 1.8509431007292951
+ 1.8510616539737035
+ 1.851180196895724
+ 1.8512987294977958
+ 1.851417251782358
+ 1.8515357637518466
+ 1.8516542654086985
+ 1.8517727567553492
+ 1.8518912377942334
+ 1.8520097085277838
+ 1.8521281689584335
+ 1.852246619088614
+ 1.852365058920756
+ 1.8524834884572896
+ 1.8526019077006433
+ 1.8527203166532449
+ 1.8528387153175216
+ 1.8529571036958996
+ 1.8530754817908033
+ 1.8531938496046576
+ 1.853312207139885
+ 1.8534305543989085
+ 1.8535488913841491
+ 1.8536672180980274
+ 1.853785534542963
+ 1.853903840721374
+ 1.8540221366356786
+ 1.854140422288293
+ 1.8542586976816335
+ 1.8543769628181146
+ 1.8544952177001501
+ 1.8546134623301536
+ 1.8547316967105367
+ 1.8548499208437108
+ 1.8549681347320859
+ 1.8550863383780716
+ 1.855204531784076
+ 1.8553227149525064
+ 1.85544088788577
+ 1.8555590505862718
+ 1.8556772030564168
+ 1.8557953452986087
+ 1.8559134773152501
+ 1.8560315991087433
+ 1.856149710681489
+ 1.8562678120358878
+ 1.8563859031743382
+ 1.8565039840992386
+ 1.8566220548129866
+ 1.8567401153179783
+ 1.8568581656166097
+ 1.8569762057112746
+ 1.8570942356043674
+ 1.8572122552982804
+ 1.8573302647954057
+ 1.8574482640981342
+ 1.8575662532088555
+ 1.857684232129959
+ 1.8578022008638329
+ 1.8579201594128643
+ 1.8580381077794395
+ 1.8581560459659443
+ 1.858273973974763
+ 1.858391891808279
+ 1.8585097994688753
+ 1.8586276969589335
+ 1.8587455842808345
+ 1.8588634614369581
+ 1.8589813284296839
+ 1.8590991852613898
+ 1.8592170319344528
+ 1.8593348684512496
+ 1.8594526948141552
+ 1.8595705110255445
+ 1.859688317087791
+ 1.8598061130032673
+ 1.8599238987743454
+ 1.8600416744033959
+ 1.860159439892789
+ 1.860277195244894
+ 1.8603949404620788
+ 1.8605126755467107
+ 1.8606304005011565
+ 1.860748115327781
+ 1.8608658200289492
+ 1.8609835146070248
+ 1.8611011990643704
+ 1.8612188734033484
+ 1.861336537626319
+ 1.8614541917356426
+ 1.8615718357336786
+ 1.8616894696227853
+ 1.86180709340532
+ 1.8619247070836384
+ 1.8620423106600976
+ 1.8621599041370511
+ 1.8622774875168533
+ 1.8623950608018571
+ 1.8625126239944143
+ 1.8626301770968763
+ 1.862747720111593
+ 1.8628652530409138
+ 1.8629827758871873
+ 1.863100288652761
+ 1.8632177913399817
+ 1.863335283951195
+ 1.8634527664887452
+ 1.8635702389549778
+ 1.8636877013522344
+ 1.863805153682858
+ 1.8639225959491899
+ 1.86404002815357
+ 1.8641574502983385
+ 1.8642748623858336
+ 1.8643922644183932
+ 1.8645096563983543
+ 1.864627038328053
+ 1.8647444102098243
+ 1.8648617720460021
+ 1.8649791238389204
+ 1.8650964655909108
+ 1.8652137973043057
+ 1.8653311189814352
+ 1.8654484306246297
+ 1.8655657322362176
+ 1.865683023818527
+ 1.8658003053738854
+ 1.8659175769046188
+ 1.8660348384130527
+ 1.8661520899015118
+ 1.8662693313723195
+ 1.8663865628277985
+ 1.8665037842702707
+ 1.8666209957020576
+ 1.8667381971254788
+ 1.8668553885428536
+ 1.8669725699565005
+ 1.867089741368737
+ 1.8672069027818803
+ 1.8673240541982448
+ 1.8674411956201464
+ 1.8675583270498988
+ 1.8676754484898153
+ 1.8677925599422078
+ 1.8679096614093882
+ 1.8680267528936667
+ 1.8681438343973527
+ 1.8682609059227553
+ 1.8683779674721823
+ 1.8684950190479408
+ 1.8686120606523369
+ 1.8687290922876758
+ 1.8688461139562618
+ 1.8689631256603987
+ 1.8690801274023892
+ 1.869197119184535
+ 1.8693141010091368
+ 1.869431072878495
+ 1.869548034794909
+ 1.8696649867606763
+ 1.8697819287780952
+ 1.869898860849462
+ 1.8700157829770725
+ 1.8701326951632216
+ 1.870249597410203
+ 1.8703664897203103
+ 1.8704833720958356
+ 1.8706002445390704
+ 1.870717107052305
+ 1.8708339596378292
+ 1.8709508022979322
+ 1.8710676350349014
+ 1.8711844578510244
+ 1.8713012707485872
+ 1.8714180737298753
+ 1.8715348667971734
+ 1.871651649952765
+ 1.8717684231989324
+ 1.8718851865379587
+ 1.8720019399721237
+ 1.872118683503709
+ 1.872235417134993
+ 1.8723521408682546
+ 1.8724688547057715
+ 1.8725855586498203
+ 1.8727022527026775
+ 1.8728189368666177
+ 1.8729356111439153
+ 1.873052275536844
+ 1.8731689300476757
+ 1.8732855746786827
+ 1.8734022094321356
+ 1.8735188343103046
+ 1.8736354493154588
+ 1.8737520544498665
+ 1.8738686497157948
+ 1.8739852351155109
+ 1.8741018106512801
+ 1.8742183763253673
+ 1.8743349321400367
+ 1.8744514780975516
+ 1.8745680142001744
+ 1.8746845404501664
+ 1.8748010568497884
+ 1.8749175634013002
+ 1.8750340601069606
+ 1.875150546969028
+ 1.8752670239897593
+ 1.8753834911714116
+ 1.8754999485162396
+ 1.8756163960264989
+ 1.875732833704443
+ 1.875849261552325
+ 1.8759656795723973
+ 1.876082087766911
+ 1.876198486138117
+ 1.8763148746882643
+ 1.8764312534196026
+ 1.8765476223343793
+ 1.876663981434842
+ 1.8767803307232367
+ 1.8768966702018093
+ 1.8770129998728042
+ 1.8771293197384653
+ 1.8772456298010354
+ 1.877361930062757
+ 1.877478220525871
+ 1.8775945011926183
+ 1.8777107720652384
+ 1.8778270331459699
+ 1.877943284437051
+ 1.8780595259407187
+ 1.8781757576592093
+ 1.8782919795947586
+ 1.8784081917496007
+ 1.8785243941259697
+ 1.8786405867260987
+ 1.8787567695522196
+ 1.8788729426065638
+ 1.878989105891362
+ 1.8791052594088433
+ 1.8792214031612373
+ 1.8793375371507712
+ 1.8794536613796728
+ 1.879569775850168
+ 1.879685880564482
+ 1.8798019755248403
+ 1.8799180607334665
+ 1.880034136192583
+ 1.880150201904413
+ 1.880266257871177
+ 1.880382304095096
+ 1.8804983405783895
+ 1.8806143673232765
+ 1.880730384331975
+ 1.8808463916067024
+ 1.8809623891496747
+ 1.881078376963108
+ 1.881194355049217
+ 1.8813103234102153
+ 1.8814262820483165
+ 1.8815422309657326
+ 1.8816581701646748
+ 1.8817740996473542
+ 1.8818900194159809
+ 1.8820059294727631
+ 1.8821218298199096
+ 1.882237720459628
+ 1.882353601394124
+ 1.8824694726256042
+ 1.882585334156273
+ 1.8827011859883347
+ 1.8828170281239927
+ 1.8829328605654492
+ 1.8830486833149063
+ 1.8831644963745646
+ 1.8832802997466238
+ 1.8833960934332834
+ 1.8835118774367423
+ 1.8836276517591974
+ 1.8837434164028457
+ 1.8838591713698831
+ 1.8839749166625046
+ 1.884090652282905
+ 1.8842063782332776
+ 1.8843220945158152
+ 1.8844378011327094
+ 1.8845534980861514
+ 1.8846691853783317
+ 1.8847848630114397
+ 1.8849005309876639
+ 1.8850161893091921
+ 1.8851318379782116
+ 1.8852474769969083
+ 1.8853631063674683
+ 1.8854787260920753
+ 1.885594336172914
+ 1.8857099366121666
+ 1.8858255274120161
+ 1.8859411085746434
+ 1.8860566801022287
+ 1.8861722419969527
+ 1.886287794260994
+ 1.8864033368965305
+ 1.8865188699057396
+ 1.8866343932907983
+ 1.8867499070538822
+ 1.8868654111971663
+ 1.8869809057228244
+ 1.8870963906330303
+ 1.8872118659299562
+ 1.887327331615774
+ 1.8874427876926545
+ 1.8875582341627684
+ 1.8876736710282846
+ 1.8877890982913719
+ 1.8879045159541978
+ 1.8880199240189295
+ 1.8881353224877329
+ 1.8882507113627736
+ 1.8883660906462159
+ 1.8884814603402238
+ 1.8885968204469603
+ 1.8887121709685877
+ 1.888827511907267
+ 1.8889428432651592
+ 1.8890581650444236
+ 1.8891734772472195
+ 1.8892887798757052
+ 1.889404072932038
+ 1.8895193564183745
+ 1.8896346303368707
+ 1.8897498946896816
+ 1.8898651494789611
+ 1.889980394706863
+ 1.8900956303755398
+ 1.8902108564871434
+ 1.890326073043825
+ 1.8904412800477346
+ 1.890556477501022
+ 1.8906716654058358
+ 1.890786843764324
+ 1.8909020125786336
+ 1.891017171850911
+ 1.8911323215833018
+ 1.8912474617779509
+ 1.891362592437002
+ 1.8914777135625984
+ 1.8915928251568828
+ 1.8917079272219963
+ 1.89182301976008
+ 1.891938102773274
+ 1.8920531762637178
+ 1.8921682402335496
+ 1.892283294684907
+ 1.8923983396199273
+ 1.8925133750407463
+ 1.8926284009494994
+ 1.8927434173483215
+ 1.892858424239346
+ 1.892973421624706
+ 1.8930884095065341
+ 1.8932033878869612
+ 1.8933183567681184
+ 1.8934333161521355
+ 1.8935482660411413
+ 1.8936632064372647
+ 1.8937781373426326
+ 1.8938930587593723
+ 1.8940079706896098
+ 1.89412287313547
+ 1.8942377660990775
+ 1.8943526495825562
+ 1.8944675235880286
+ 1.8945823881176171
+ 1.8946972431734428
+ 1.8948120887576267
+ 1.8949269248722882
+ 1.8950417515195466
+ 1.8951565687015197
+ 1.8952713764203255
+ 1.8953861746780805
+ 1.8955009634769007
+ 1.8956157428189009
+ 1.895730512706196
+ 1.8958452731408992
+ 1.895960024125124
+ 1.8960747656609815
+ 1.8961894977505838
+ 1.896304220396041
+ 1.8964189335994632
+ 1.896533637362959
+ 1.8966483316886373
+ 1.8967630165786047
+ 1.8968776920349686
+ 1.8969923580598345
+ 1.8971070146553075
+ 1.8972216618234925
+ 1.8973362995664926
+ 1.897450927886411
+ 1.89756554678535
+ 1.8976801562654102
+ 1.8977947563286928
+ 1.8979093469772972
+ 1.8980239282133229
+ 1.8981385000388675
+ 1.898253062456029
+ 1.8983676154669045
+ 1.8984821590735892
+ 1.8985966932781788
+ 1.8987112180827677
+ 1.8988257334894492
+ 1.8989402395003165
+ 1.8990547361174623
+ 1.8991692233429776
+ 1.899283701178953
+ 1.899398169627478
+ 1.8995126286906427
+ 1.899627078370535
+ 1.8997415186692421
+ 1.8998559495888516
+ 1.899970371131449
+ 1.9000847832991203
+ 1.9001991860939496
+ 1.9003135795180208
+ 1.9004279635734174
+ 1.900542338262221
+ 1.9006567035865136
+ 1.9007710595483764
+ 1.900885406149889
+ 1.9009997433931307
+ 1.90111407128018
+ 1.9012283898131148
+ 1.9013426989940123
+ 1.9014569988249488
+ 1.9015712893079997
+ 1.9016855704452398
+ 1.9017998422387434
+ 1.9019141046905834
+ 1.9020283578028325
+ 1.9021426015775629
+ 1.9022568360168448
+ 1.9023710611227493
+ 1.9024852768973455
+ 1.9025994833427025
+ 1.902713680460888
+ 1.9028278682539697
+ 1.9029420467240137
+ 1.9030562158730864
+ 1.903170375703252
+ 1.9032845262165756
+ 1.9033986674151204
+ 1.9035127993009493
+ 1.9036269218761244
+ 1.903741035142707
+ 1.903855139102758
+ 1.903969233758337
+ 1.9040833191115027
+ 1.904197395164314
+ 1.9043114619188282
+ 1.9044255193771025
+ 1.9045395675411925
+ 1.9046536064131543
+ 1.904767635995042
+ 1.9048816562889097
+ 1.9049956672968107
+ 1.905109669020797
+ 1.9052236614629205
+ 1.9053376446252324
+ 1.9054516185097825
+ 1.9055655831186205
+ 1.9056795384537952
+ 1.9057934845173543
+ 1.9059074213113454
+ 1.9060213488378148
+ 1.9061352670988083
+ 1.9062491760963713
+ 1.9063630758325474
+ 1.9064769663093803
+ 1.9065908475289133
+ 1.9067047194931883
+ 1.9068185822042465
+ 1.9069324356641286
+ 1.9070462798748749
+ 1.907160114838524
+ 1.9072739405571144
+ 1.907387757032684
+ 1.90750156426727
+ 1.9076153622629077
+ 1.9077291510216337
+ 1.907842930545482
+ 1.9079567008364868
+ 1.9080704618966817
+ 1.9081842137280993
+ 1.9082979563327709
+ 1.9084116897127281
+ 1.908525413870001
+ 1.9086391288066193
+ 1.908752834524612
+ 1.9088665310260073
+ 1.9089802183128326
+ 1.909093896387115
+ 1.9092075652508802
+ 1.909321224906153
+ 1.909434875354959
+ 1.9095485165993211
+ 1.9096621486412628
+ 1.9097757714828067
+ 1.9098893851259742
+ 1.9100029895727864
+ 1.910116584825263
+ 1.9102301708854241
+ 1.9103437477552885
+ 1.9104573154368738
+ 1.9105708739321974
+ 1.9106844232432758
+ 1.9107979633721253
+ 1.9109114943207606
+ 1.9110250160911963
+ 1.9111385286854463
+ 1.9112520321055233
+ 1.9113655263534401
+ 1.9114790114312072
+ 1.9115924873408365
+ 1.9117059540843375
+ 1.9118194116637197
+ 1.9119328600809917
+ 1.9120462993381617
+ 1.912159729437237
+ 1.9122731503802237
+ 1.9123865621691278
+ 1.9124999648059544
+ 1.912613358292708
+ 1.9127267426313919
+ 1.9128401178240093
+ 1.9129534838725621
+ 1.9130668407790523
+ 1.9131801885454807
+ 1.9132935271738465
+ 1.9134068566661502
+ 1.9135201770243897
+ 1.9136334882505635
+ 1.9137467903466678
+ 1.9138600833147001
+ 1.9139733671566561
+ 1.9140866418745304
+ 1.9141999074703175
+ 1.9143131639460114
+ 1.914426411303605
+ 1.9145396495450901
+ 1.9146528786724586
+ 1.914766098687701
+ 1.9148793095928078
+ 1.9149925113897683
+ 1.915105704080571
+ 1.915218887667204
+ 1.9153320621516547
+ 1.9154452275359095
+ 1.9155583838219543
+ 1.9156715310117742
+ 1.9157846691073537
+ 1.9158977981106766
+ 1.9160109180237257
+ 1.9161240288484838
+ 1.916237130586932
+ 1.9163502232410514
+ 1.9164633068128225
+ 1.9165763813042245
+ 1.9166894467172362
+ 1.9168025030538358
+ 1.9169155503160005
+ 1.9170285885057077
+ 1.9171416176249323
+ 1.9172546376756505
+ 1.9173676486598366
+ 1.9174806505794642
+ 1.9175936434365068
+ 1.917706627232937
+ 1.9178196019707263
+ 1.917932567651846
+ 1.918045524278266
+ 1.9181584718519566
+ 1.9182714103748866
+ 1.9183843398490241
+ 1.918497260276337
+ 1.918610171658792
+ 1.9187230739983556
+ 1.9188359672969926
+ 1.9189488515566684
+ 1.9190617267793468
+ 1.9191745929669914
+ 1.919287450121565
+ 1.9194002982450293
+ 1.9195131373393461
+ 1.9196259674064755
+ 1.9197387884483776
+ 1.919851600467012
+ 1.9199644034643368
+ 1.9200771974423099
+ 1.9201899824028887
+ 1.9203027583480294
+ 1.920415525279688
+ 1.9205282831998194
+ 1.920641032110378
+ 1.9207537720133177
+ 1.9208665029105914
+ 1.9209792248041513
+ 1.9210919376959492
+ 1.9212046415879356
+ 1.9213173364820615
+ 1.9214300223802758
+ 1.921542699284528
+ 1.9216553671967656
+ 1.9217680261189363
+ 1.9218806760529872
+ 1.921993317000864
+ 1.9221059489645125
+ 1.922218571945877
+ 1.922331185946902
+ 1.9224437909695309
+ 1.922556387015706
+ 1.9226689740873695
+ 1.9227815521864626
+ 1.922894121314926
+ 1.9230066814746998
+ 1.923119232667723
+ 1.9232317748959342
+ 1.9233443081612716
+ 1.9234568324656716
+ 1.9235693478110716
+ 1.9236818541994072
+ 1.9237943516326133
+ 1.9239068401126247
+ 1.924019319641375
+ 1.9241317902207975
+ 1.9242442518528242
+ 1.924356704539387
+ 1.9244691482824174
+ 1.9245815830838453
+ 1.9246940089456008
+ 1.9248064258696125
+ 1.9249188338578092
+ 1.9250312329121182
+ 1.9251436230344665
+ 1.9252560042267808
+ 1.9253683764909864
+ 1.9254807398290081
+ 1.9255930942427708
+ 1.9257054397341975
+ 1.9258177763052116
+ 1.925930103957735
+ 1.9260424226936892
+ 1.9261547325149957
+ 1.926267033423574
+ 1.926379325421344
+ 1.9264916085102246
+ 1.926603882692134
+ 1.9267161479689898
+ 1.9268284043427086
+ 1.9269406518152068
+ 1.9270528903883999
+ 1.9271651200642024
+ 1.9272773408445292
+ 1.927389552731293
+ 1.9275017557264071
+ 1.9276139498317832
+ 1.9277261350493338
+ 1.9278383113809685
+ 1.927950478828598
+ 1.9280626373941316
+ 1.9281747870794785
+ 1.9282869278865467
+ 1.9283990598172431
+ 1.9285111828734751
+ 1.9286232970571486
+ 1.9287354023701693
+ 1.9288474988144415
+ 1.9289595863918698
+ 1.9290716651043573
+ 1.929183734953807
+ 1.929295795942121
+ 1.929407848071201
+ 1.9295198913429472
+ 1.9296319257592602
+ 1.9297439513220394
+ 1.9298559680331835
+ 1.9299679758945905
+ 1.9300799749081579
+ 1.9301919650757828
+ 1.9303039463993614
+ 1.9304159188807886
+ 1.9305278825219596
+ 1.9306398373247686
+ 1.930751783291109
+ 1.9308637204228736
+ 1.930975648721955
+ 1.9310875681902437
+ 1.9311994788296314
+ 1.931311380642008
+ 1.9314232736292634
+ 1.9315351577932858
+ 1.9316470331359636
+ 1.9317588996591848
+ 1.931870757364836
+ 1.9319826062548031
+ 1.9320944463309722
+ 1.932206277595228
+ 1.9323181000494545
+ 1.932429913695536
+ 1.9325417185353546
+ 1.9326535145707933
+ 1.9327653018037332
+ 1.9328770802360555
+ 1.9329888498696404
+ 1.9331006107063677
+ 1.9332123627481164
+ 1.933324105996765
+ 1.933435840454191
+ 1.933547566122271
+ 1.9336592830028823
+ 1.9337709910979
+ 1.9338826904091992
+ 1.9339943809386544
+ 1.9341060626881397
+ 1.934217735659528
+ 1.9343293998546918
+ 1.934441055275503
+ 1.9345527019238324
+ 1.9346643398015508
+ 1.9347759689105282
+ 1.9348875892526336
+ 1.9349992008297356
+ 1.9351108036437024
+ 1.9352223976964007
+ 1.9353339829896974
+ 1.9354455595254587
+ 1.9355571273055496
+ 1.935668686331835
+ 1.935780236606179
+ 1.9358917781304446
+ 1.9360033109064945
+ 1.9361148349361914
+ 1.936226350221396
+ 1.93633785676397
+ 1.9364493545657726
+ 1.936560843628664
+ 1.9366723239545027
+ 1.9367837955451468
+ 1.936895258402454
+ 1.9370067125282815
+ 1.9371181579244852
+ 1.937229594592921
+ 1.9373410225354435
+ 1.9374524417539074
+ 1.9375638522501664
+ 1.9376752540260733
+ 1.937786647083481
+ 1.9378980314242409
+ 1.9380094070502039
+ 1.938120773963221
+ 1.938232132165142
+ 1.9383434816578156
+ 1.938454822443091
+ 1.9385661545228159
+ 1.9386774778988376
+ 1.9387887925730025
+ 1.938900098547157
+ 1.939011395823146
+ 1.9391226844028147
+ 1.9392339642880072
+ 1.9393452354805667
+ 1.939456497982336
+ 1.9395677517951575
+ 1.9396789969208728
+ 1.9397902333613224
+ 1.939901461118347
+ 1.940012680193786
+ 1.9401238905894784
+ 1.9402350923072627
+ 1.9403462853489766
+ 1.940457469716457
+ 1.9405686454115407
+ 1.9406798124360634
+ 1.9407909707918602
+ 1.9409021204807657
+ 1.941013261504614
+ 1.941124393865238
+ 1.9412355175644709
+ 1.941346632604144
+ 1.9414577389860894
+ 1.9415688367121375
+ 1.9416799257841184
+ 1.9417910062038621
+ 1.941902077973197
+ 1.9420131410939514
+ 1.942124195567953
+ 1.9422352413970283
+ 1.9423462785830043
+ 1.9424573071277067
+ 1.9425683270329601
+ 1.9426793383005894
+ 1.9427903409324185
+ 1.9429013349302702
+ 1.9430123202959673
+ 1.9431232970313315
+ 1.9432342651381846
+ 1.943345224618347
+ 1.9434561754736388
+ 1.9435671177058793
+ 1.9436780513168876
+ 1.943788976308482
+ 1.9438998926824798
+ 1.9440108004406975
+ 1.9441216995849522
+ 1.9442325901170592
+ 1.9443434720388337
+ 1.9444543453520902
+ 1.9445652100586421
+ 1.9446760661603029
+ 1.9447869136588856
+ 1.9448977525562012
+ 1.9450085828540622
+ 1.945119404554278
+ 1.9452302176586598
+ 1.9453410221690162
+ 1.9454518180871563
+ 1.945562605414889
+ 1.945673384154021
+ 1.9457841543063596
+ 1.9458949158737113
+ 1.9460056688578817
+ 1.9461164132606756
+ 1.9462271490838983
+ 1.946337876329353
+ 1.9464485949988435
+ 1.9465593050941716
+ 1.94667000661714
+ 1.94678069956955
+ 1.9468913839532023
+ 1.9470020597698972
+ 1.9471127270214341
+ 1.9472233857096117
+ 1.947334035836229
+ 1.9474446774030831
+ 1.9475553104119714
+ 1.94766593486469
+ 1.9477765507630356
+ 1.9478871581088024
+ 1.9479977569037856
+ 1.9481083471497793
+ 1.9482189288485767
+ 1.9483295020019702
+ 1.948440066611753
+ 1.9485506226797156
+ 1.9486611702076495
+ 1.9487717091973449
+ 1.9488822396505914
+ 1.9489927615691787
+ 1.9491032749548947
+ 1.9492137798095268
+ 1.9493242761348635
+ 1.9494347639326908
+ 1.9495452432047948
+ 1.9496557139529613
+ 1.9497661761789742
+ 1.9498766298846186
+ 1.9499870750716777
+ 1.9500975117419352
+ 1.9502079398971726
+ 1.9503183595391718
+ 1.9504287706697145
+ 1.9505391732905808
+ 1.9506495674035509
+ 1.9507599530104043
+ 1.9508703301129195
+ 1.9509806987128748
+ 1.9510910588120474
+ 1.9512014104122148
+ 1.9513117535151527
+ 1.9514220881226374
+ 1.9515324142364434
+ 1.9516427318583458
+ 1.9517530409901183
+ 1.9518633416335336
+ 1.9519736337903655
+ 1.9520839174623854
+ 1.9521941926513648
+ 1.9523044593590748
+ 1.952414717587286
+ 1.952524967337767
+ 1.9526352086122876
+ 1.9527454414126166
+ 1.9528556657405212
+ 1.952965881597769
+ 1.9530760889861265
+ 1.95318628790736
+ 1.953296478363235
+ 1.9534066603555165
+ 1.953516833885968
+ 1.9536269989563537
+ 1.9537371555684369
+ 1.9538473037239792
+ 1.9539574434247438
+ 1.9540675746724905
+ 1.954177697468981
+ 1.9542878118159754
+ 1.9543979177152326
+ 1.9545080151685117
+ 1.9546181041775708
+ 1.954728184744168
+ 1.9548382568700602
+ 1.9549483205570037
+ 1.9550583758067546
+ 1.9551684226210682
+ 1.955278461001699
+ 1.9553884909504016
+ 1.9554985124689288
+ 1.955608525559034
+ 1.9557185302224689
+ 1.9558285264609865
+ 1.9559385142763366
+ 1.9560484936702707
+ 1.956158464644538
+ 1.9562684272008883
+ 1.9563783813410704
+ 1.9564883270668318
+ 1.956598264379921
+ 1.9567081932820842
+ 1.9568181137750689
+ 1.9569280258606196
+ 1.9570379295404818
+ 1.9571478248164007
+ 1.9572577116901202
+ 1.9573675901633834
+ 1.9574774602379332
+ 1.957587321915512
+ 1.957697175197861
+ 1.9578070200867217
+ 1.9579168565838352
+ 1.95802668469094
+ 1.9581365044097765
+ 1.9582463157420833
+ 1.9583561186895981
+ 1.9584659132540587
+ 1.958575699437202
+ 1.9586854772407645
+ 1.9587952466664815
+ 1.958905007716089
+ 1.959014760391321
+ 1.9591245046939114
+ 1.9592342406255943
+ 1.9593439681881024
+ 1.9594536873831674
+ 1.9595633982125211
+ 1.9596731006778956
+ 1.95978279478102
+ 1.959892480523625
+ 1.96000215790744
+ 1.9601118269341937
+ 1.9602214876056137
+ 1.9603311399234291
+ 1.960440783889365
+ 1.960550419505149
+ 1.9606600467725064
+ 1.960769665693163
+ 1.9608792762688434
+ 1.9609888785012715
+ 1.9610984723921703
+ 1.9612080579432638
+ 1.9613176351562738
+ 1.961427204032922
+ 1.96153676457493
+ 1.961646316784018
+ 1.961755860661906
+ 1.961865396210314
+ 1.9619749234309605
+ 1.962084442325564
+ 1.9621939528958416
+ 1.962303455143511
+ 1.9624129490702893
+ 1.9625224346778916
+ 1.9626319119680333
+ 1.9627413809424297
+ 1.9628508416027952
+ 1.9629602939508428
+ 1.9630697379882867
+ 1.9631791737168378
+ 1.9632886011382096
+ 1.963398020254113
+ 1.9635074310662588
+ 1.9636168335763566
+ 1.9637262277861167
+ 1.9638356136972484
+ 1.9639449913114595
+ 1.9640543606304586
+ 1.9641637216559527
+ 1.9642730743896488
+ 1.9643824188332528
+ 1.9644917549884704
+ 1.9646010828570073
+ 1.964710402440567
+ 1.964819713740854
+ 1.9649290167595719
+ 1.9650383114984227
+ 1.9651475979591095
+ 1.9652568761433333
+ 1.9653661460527954
+ 1.9654754076891965
+ 1.9655846610542358
+ 1.9656939061496137
+ 1.9658031429770284
+ 1.965912371538178
+ 1.9660215918347606
+ 1.9661308038684726
+ 1.9662400076410111
+ 1.9663492031540721
+ 1.9664583904093507
+ 1.9665675694085418
+ 1.9666767401533394
+ 1.9667859026454375
+ 1.966895056886529
+ 1.967004202878307
+ 1.9671133406224628
+ 1.9672224701206875
+ 1.9673315913746732
+ 1.9674407043861095
+ 1.9675498091566854
+ 1.967658905688091
+ 1.967767993982015
+ 1.967877074040145
+ 1.9679861458641679
+ 1.9680952094557715
+ 1.9682042648166418
+ 1.9683133119484648
+ 1.968422350852925
+ 1.9685313815317083
+ 1.968640403986497
+ 1.968749418218976
+ 1.968858424230828
+ 1.968967422023735
+ 1.969076411599379
+ 1.9691853929594416
+ 1.969294366105603
+ 1.9694033310395438
+ 1.969512287762943
+ 1.96962123627748
+ 1.9697301765848334
+ 1.969839108686681
+ 1.9699480325847
+ 1.9700569482805672
+ 1.970165855775959
+ 1.9702747550725508
+ 1.9703836461720179
+ 1.970492529076035
+ 1.9706014037862751
+ 1.9707102703044133
+ 1.9708191286321213
+ 1.9709279787710716
+ 1.9710368207229358
+ 1.971145654489386
+ 1.9712544800720917
+ 1.9713632974727238
+ 1.9714721066929515
+ 1.9715809077344442
+ 1.9716897005988694
+ 1.9717984852878956
+ 1.9719072618031899
+ 1.9720160301464194
+ 1.9721247903192503
+ 1.9722335423233475
+ 1.9723422861603772
+ 1.972451021832003
+ 1.9725597493398894
+ 1.9726684686857
+ 1.9727771798710967
+ 1.972885882897743
+ 1.9729945777673
+ 1.973103264481429
+ 1.9732119430417911
+ 1.9733206134500458
+ 1.9734292757078535
+ 1.973537929816872
+ 1.973646575778761
+ 1.973755213595178
+ 1.9738638432677795
+ 1.9739724647982235
+ 1.974081078188166
+ 1.9741896834392623
+ 1.9742982805531681
+ 1.9744068695315373
+ 1.974515450376025
+ 1.9746240230882839
+ 1.9747325876699666
+ 1.974841144122727
+ 1.9749496924482155
+ 1.9750582326480843
+ 1.9751667647239837
+ 1.9752752886775642
+ 1.9753838045104757
+ 1.9754923122243666
+ 1.9756008118208868
+ 1.9757093033016828
+ 1.9758177866684032
+ 1.9759262619226943
+ 1.976034729066203
+ 1.9761431881005749
+ 1.9762516390274552
+ 1.9763600818484892
+ 1.9764685165653206
+ 1.9765769431795934
+ 1.9766853616929503
+ 1.9767937721070348
+ 1.9769021744234878
+ 1.9770105686439516
+ 1.9771189547700672
+ 1.9772273328034748
+ 1.9773357027458143
+ 1.9774440645987246
+ 1.9775524183638453
+ 1.9776607640428143
+ 1.9777691016372694
+ 1.9778774311488474
+ 1.9779857525791857
+ 1.9780940659299195
+ 1.9782023712026848
+ 1.9783106683991167
+ 1.9784189575208495
+ 1.9785272385695178
+ 1.9786355115467538
+ 1.9787437764541915
+ 1.9788520332934623
+ 1.9789602820661985
+ 1.9790685227740312
+ 1.9791767554185913
+ 1.9792849800015084
+ 1.979393196524413
+ 1.9795014049889332
+ 1.9796096053966987
+ 1.9797177977493365
+ 1.9798259820484752
+ 1.9799341582957404
+ 1.980042326492759
+ 1.980150486641157
+ 1.98025863874256
+ 1.9803667827985925
+ 1.9804749188108788
+ 1.9805830467810426
+ 1.9806911667107074
+ 1.9807992786014956
+ 1.980907382455029
+ 1.9810154782729297
+ 1.9811235660568187
+ 1.9812316458083161
+ 1.9813397175290424
+ 1.981447781220617
+ 1.9815558368846584
+ 1.9816638845227856
+ 1.981771924136616
+ 1.981879955727767
+ 1.9819879792978556
+ 1.9820959948484982
+ 1.98220400238131
+ 1.9823120018979064
+ 1.9824199933999023
+ 1.982527976888912
+ 1.9826359523665482
+ 1.9827439198344254
+ 1.9828518792941547
+ 1.982959830747349
+ 1.9830677741956195
+ 1.9831757096405778
+ 1.9832836370838332
+ 1.9833915565269964
+ 1.9834994679716764
+ 1.9836073714194822
+ 1.9837152668720226
+ 1.9838231543309048
+ 1.983931033797736
+ 1.984038905274123
+ 1.9841467687616727
+ 1.9842546242619898
+ 1.9843624717766801
+ 1.984470311307348
+ 1.9845781428555977
+ 1.9846859664230332
+ 1.9847937820112562
+ 1.984901589621871
+ 1.9850093892564782
+ 1.9851171809166799
+ 1.985224964604077
+ 1.9853327403202699
+ 1.9854405080668587
+ 1.9855482678454421
+ 1.9856560196576203
+ 1.9857637635049905
+ 1.9858714993891506
+ 1.985979227311698
+ 1.9860869472742297
+ 1.9861946592783422
+ 1.9863023633256305
+ 1.9864100594176903
+ 1.986517747556116
+ 1.9866254277425017
+ 1.9867330999784423
+ 1.9868407642655288
+ 1.9869484206053551
+ 1.9870560689995134
+ 1.9871637094495942
+ 1.9872713419571897
+ 1.9873789665238901
+ 1.987486583151285
+ 1.9875941918409639
+ 1.987701792594516
+ 1.9878093854135301
+ 1.9879169702995936
+ 1.988024547254294
+ 1.9881321162792178
+ 1.988239677375952
+ 1.9883472305460825
+ 1.9884547757911941
+ 1.9885623131128722
+ 1.9886698425127005
+ 1.9887773639922635
+ 1.9888848775531434
+ 1.9889923831969234
+ 1.9890998809251867
+ 1.9892073707395135
+ 1.9893148526414859
+ 1.9894223266326845
+ 1.9895297927146893
+ 1.98963725088908
+ 1.9897447011574358
+ 1.9898521435213354
+ 1.9899595779823567
+ 1.990067004542077
+ 1.9901744232020742
+ 1.9902818339639239
+ 1.990389236829203
+ 1.990496631799487
+ 1.9906040188763503
+ 1.9907113980613682
+ 1.9908187693561137
+ 1.9909261327621615
+ 1.9910334882810832
+ 1.9911408359144522
+ 1.9912481756638407
+ 1.9913555075308194
+ 1.9914628315169598
+ 1.9915701476238319
+ 1.991677455853006
+ 1.9917847562060509
+ 1.9918920486845362
+ 1.9919993332900299
+ 1.9921066100241
+ 1.9922138788883135
+ 1.9923211398842382
+ 1.9924283930134392
+ 1.9925356382774833
+ 1.9926428756779353
+ 1.9927501052163603
+ 1.9928573268943228
+ 1.992964540713386
+ 1.9930717466751136
+ 1.9931789447810682
+ 1.9932861350328122
+ 1.9933933174319078
+ 1.9935004919799153
+ 1.9936076586783964
+ 1.9937148175289108
+ 1.9938219685330185
+ 1.9939291116922788
+ 1.9940362470082496
+ 1.9941433744824903
+ 1.9942504941165586
+ 1.994357605912011
+ 1.9944647098704043
+ 1.9945718059932946
+ 1.9946788942822387
+ 1.994785974738791
+ 1.9948930473645057
+ 1.9950001121609382
+ 1.9951071691296411
+ 1.9952142182721684
+ 1.995321259590072
+ 1.995428293084905
+ 1.995535318758218
+ 1.9956423366115634
+ 1.9957493466464913
+ 1.9958563488645515
+ 1.9959633432672945
+ 1.9960703298562688
+ 1.9961773086330232
+ 1.996284279599106
+ 1.9963912427560648
+ 1.9964981981054473
+ 1.9966051456487992
+ 1.9967120853876674
+ 1.9968190173235978
+ 1.9969259414581348
+ 1.9970328577928231
+ 1.9971397663292076
+ 1.9972466670688316
+ 1.9973535600132382
+ 1.9974604451639697
+ 1.9975673225225694
+ 1.9976741920905778
+ 1.9977810538695373
+ 1.9978879078609875
+ 1.9979947540664689
+ 1.9981015924875216
+ 1.9982084231256845
+ 1.9983152459824962
+ 1.9984220610594952
+ 1.9985288683582187
+ 1.9986356678802044
+ 1.9987424596269892
+ 1.9988492436001082
+ 1.998956019801099
+ 1.9990627882314949
+ 1.999169548892832
+ 1.999276301786644
+ 1.9993830469144644
+ 1.999489784277827
+ 1.9995965138782645
+ 1.9997032357173092
+ 1.9998099497964923
+ 1.9999166561173454
+ 2.0000233546813995
+ 2.000130045490185
+ 2.0002367285452314
+ 2.000343403848068
+ 2.0004500714002234
+ 2.0005567312032264
+ 2.000663383258605
+ 2.0007700275678864
+ 2.000876664132597
+ 2.0009832929542632
+ 2.001089914034411
+ 2.001196527374567
+ 2.001303132976254
+ 2.0014097308409977
+ 2.001516320970322
+ 2.0016229033657496
+ 2.001729478028804
+ 2.0018360449610078
+ 2.001942604163882
+ 2.0020491556389497
+ 2.00215569938773
+ 2.0022622354117448
+ 2.002368763712514
+ 2.002475284291556
+ 2.0025817971503908
+ 2.002688302290537
+ 2.0027947997135125
+ 2.002901289420834
+ 2.00300777141402
+ 2.003114245694586
+ 2.0032207122640484
+ 2.003327171123923
+ 2.003433622275725
+ 2.0035400657209688
+ 2.0036465014611684
+ 2.0037529294978382
+ 2.003859349832491
+ 2.003965762466639
+ 2.004072167401795
+ 2.0041785646394707
+ 2.004284954181177
+ 2.004391336028425
+ 2.004497710182725
+ 2.004604076645587
+ 2.0047104354185197
+ 2.004816786503032
+ 2.0049231299006327
+ 2.0050294656128296
+ 2.00513579364113
+ 2.00524211398704
+ 2.0053484266520676
+ 2.005454731637718
+ 2.005561028945496
+ 2.005667318576908
+ 2.0057736005334568
+ 2.0058798748166473
+ 2.0059861414279836
+ 2.0060924003689675
+ 2.006198651641103
+ 2.0063048952458904
+ 2.006411131184833
+ 2.006517359459431
+ 2.006623580071186
+ 2.006729793021597
+ 2.006835998312164
+ 2.0069421959443865
+ 2.0070483859197634
+ 2.0071545682397924
+ 2.007260742905972
+ 2.0073669099197984
+ 2.00747306928277
+ 2.0075792209963814
+ 2.00768536506213
+ 2.0077915014815098
+ 2.007897630256017
+ 2.0080037513871454
+ 2.008109864876389
+ 2.008215970725241
+ 2.008322068935195
+ 2.0084281595077433
+ 2.008534242444378
+ 2.0086403177465906
+ 2.008746385415872
+ 2.008852445453713
+ 2.008958497861604
+ 2.0090645426410347
+ 2.009170579793494
+ 2.0092766093204704
+ 2.0093826312234526
+ 2.0094886455039283
+ 2.0095946521633845
+ 2.009700651203309
+ 2.009806642625187
+ 2.0099126264305047
+ 2.010018602620748
+ 2.0101245711974016
+ 2.01023053216195
+ 2.0103364855158765
+ 2.0104424312606657
+ 2.0105483693978004
+ 2.010654299928763
+ 2.010760222855035
+ 2.0108661381780992
+ 2.010972045899436
+ 2.0110779460205266
+ 2.0111838385428507
+ 2.0112897234678884
+ 2.0113956007971185
+ 2.011501470532021
+ 2.0116073326740733
+ 2.0117131872247533
+ 2.0118190341855384
+ 2.011924873557906
+ 2.0120307053433324
+ 2.012136529543293
+ 2.0122423461592645
+ 2.012348155192721
+ 2.012453956645137
+ 2.0125597505179877
+ 2.0126655368127464
+ 2.0127713155308853
+ 2.0128770866738783
+ 2.012982850243197
+ 2.0130886062403133
+ 2.0131943546666986
+ 2.013300095523824
+ 2.01340582881316
+ 2.013511554536176
+ 2.0136172726943418
+ 2.013722983289126
+ 2.0138286863219976
+ 2.013934381794425
+ 2.0140400697078746
+ 2.0141457500638147
+ 2.0142514228637114
+ 2.014357088109031
+ 2.01446274580124
+ 2.014568395941802
+ 2.0146740385321835
+ 2.0147796735738477
+ 2.0148853010682592
+ 2.0149909210168815
+ 2.015096533421177
+ 2.015202138282608
+ 2.015307735602638
+ 2.0154133253827267
+ 2.0155189076243367
+ 2.0156244823289278
+ 2.0157300494979604
+ 2.0158356091328944
+ 2.015941161235189
+ 2.016046705806303
+ 2.0161522428476943
+ 2.016257772360822
+ 2.016363294347142
+ 2.016468808808112
+ 2.0165743157451894
+ 2.016679815159829
+ 2.0167853070534862
+ 2.0168907914276173
+ 2.016996268283676
+ 2.017101737623117
+ 2.017207199447394
+ 2.01731265375796
+ 2.0174181005562684
+ 2.0175235398437708
+ 2.01762897162192
+ 2.017734395892167
+ 2.017839812655962
+ 2.0179452219147573
+ 2.0180506236700015
+ 2.018156017923145
+ 2.0182614046756364
+ 2.018366783928925
+ 2.018472155684459
+ 2.018577519943686
+ 2.0186828767080534
+ 2.0187882259790078
+ 2.018893567757996
+ 2.018998902046464
+ 2.019104228845857
+ 2.01920954815762
+ 2.019314859983199
+ 2.019420164324036
+ 2.0195254611815763
+ 2.0196307505572624
+ 2.0197360324525375
+ 2.0198413068688437
+ 2.0199465738076228
+ 2.020051833270317
+ 2.0201570852583655
+ 2.0202623297732107
+ 2.020367566816292
+ 2.020472796389049
+ 2.020578018492921
+ 2.0206832331293465
+ 2.020788440299764
+ 2.020893640005611
+ 2.020998832248325
+ 2.021104017029343
+ 2.0212091943501016
+ 2.0213143642120364
+ 2.0214195266165835
+ 2.0215246815651775
+ 2.0216298290592536
+ 2.021734969100245
+ 2.0218401016895866
+ 2.021945226828711
+ 2.0220503445190516
+ 2.0221554547620406
+ 2.0222605575591097
+ 2.0223656529116902
+ 2.022470740821214
+ 2.022575821289111
+ 2.022680894316812
+ 2.022785959905746
+ 2.0228910180573427
+ 2.022996068773031
+ 2.023101112054239
+ 2.0232061479023944
+ 2.023311176318925
+ 2.023416197305258
+ 2.02352121086282
+ 2.023626216993037
+ 2.0237312156973344
+ 2.0238362069771374
+ 2.0239411908338716
+ 2.0240461672689603
+ 2.0241511362838285
+ 2.0242560978798987
+ 2.024361052058594
+ 2.024465998821338
+ 2.0245709381695516
+ 2.0246758701046574
+ 2.0247807946280756
+ 2.0248857117412276
+ 2.0249906214455344
+ 2.0250955237424146
+ 2.0252004186332884
+ 2.025305306119575
+ 2.0254101862026923
+ 2.025515058884059
+ 2.0256199241650927
+ 2.02572478204721
+ 2.0258296325318286
+ 2.0259344756203648
+ 2.0260393113142334
+ 2.026144139614851
+ 2.0262489605236325
+ 2.0263537740419917
+ 2.0264585801713437
+ 2.0265633789131017
+ 2.026668170268679
+ 2.026772954239489
+ 2.0268777308269432
+ 2.0269825000324535
+ 2.0270872618574325
+ 2.02719201630329
+ 2.0272967633714374
+ 2.0274015030632846
+ 2.0275062353802418
+ 2.0276109603237176
+ 2.0277156778951206
+ 2.0278203880958605
+ 2.027925090927344
+ 2.0280297863909795
+ 2.0281344744881737
+ 2.0282391552203336
+ 2.028343828588865
+ 2.028448494595174
+ 2.0285531532406655
+ 2.028657804526745
+ 2.028762448454817
+ 2.0288670850262847
+ 2.0289717142425525
+ 2.0290763361050232
+ 2.0291809506150997
+ 2.0292855577741844
+ 2.0293901575836792
+ 2.029494750044985
+ 2.029599335159503
+ 2.029703912928634
+ 2.029808483353778
+ 2.0299130464363344
+ 2.030017602177703
+ 2.0301221505792824
+ 2.0302266916424703
+ 2.030331225368666
+ 2.0304357517592657
+ 2.0305402708156666
+ 2.0306447825392664
+ 2.03074928693146
+ 2.0308537839936442
+ 2.0309582737272134
+ 2.0310627561335632
+ 2.0311672312140883
+ 2.031271698970182
+ 2.031376159403238
+ 2.0314806125146503
+ 2.03158505830581
+ 2.0316894967781116
+ 2.031793927932945
+ 2.0318983517717024
+ 2.032002768295775
+ 2.0321071775065533
+ 2.0322115794054274
+ 2.032315973993787
+ 2.032420361273021
+ 2.0325247412445187
+ 2.032629113909669
+ 2.0327334792698584
+ 2.032837837326476
+ 2.032942188080908
+ 2.0330465315345414
+ 2.0331508676887626
+ 2.0332551965449577
+ 2.033359518104511
+ 2.033463832368809
+ 2.033568139339235
+ 2.033672439017174
+ 2.0337767314040085
+ 2.033881016501123
+ 2.0339852943099004
+ 2.034089564831722
+ 2.0341938280679708
+ 2.034298084020028
+ 2.034402332689275
+ 2.0345065740770916
+ 2.034610808184859
+ 2.0347150350139565
+ 2.0348192545657637
+ 2.03492346684166
+ 2.0350276718430234
+ 2.0351318695712326
+ 2.035236060027665
+ 2.0353402432136978
+ 2.0354444191307075
+ 2.0355485877800716
+ 2.035652749163165
+ 2.035756903281364
+ 2.035861050136044
+ 2.035965189728579
+ 2.0360693220603436
+ 2.036173447132712
+ 2.0362775649470573
+ 2.0363816755047526
+ 2.0364857788071706
+ 2.036589874855683
+ 2.0366939636516626
+ 2.03679804519648
+ 2.0369021194915065
+ 2.0370061865381124
+ 2.037110246337668
+ 2.0372142988915423
+ 2.0373183442011054
+ 2.0374223822677258
+ 2.0375264130927713
+ 2.037630436677611
+ 2.0377344530236114
+ 2.0378384621321404
+ 2.0379424640045642
+ 2.038046458642249
+ 2.038150446046562
+ 2.0382544262188667
+ 2.0383583991605287
+ 2.0384623648729137
+ 2.0385663233573847
+ 2.0386702746153063
+ 2.038774218648041
+ 2.038878155456952
+ 2.0389820850434024
+ 2.039086007408754
+ 2.039189922554368
+ 2.0392938304816055
+ 2.0393977311918285
+ 2.0395016246863964
+ 2.0396055109666693
+ 2.039709390034007
+ 2.0398132618897686
+ 2.0399171265353133
+ 2.0400209839719987
+ 2.0401248342011833
+ 2.0402286772242237
+ 2.0403325130424776
+ 2.040436341657302
+ 2.040540163070053
+ 2.0406439772820857
+ 2.040747784294756
+ 2.0408515841094186
+ 2.0409553767274287
+ 2.04105916215014
+ 2.041162940378906
+ 2.0412667114150804
+ 2.0413704752600164
+ 2.041474231915066
+ 2.0415779813815815
+ 2.0416817236609144
+ 2.0417854587544157
+ 2.041889186663437
+ 2.041992907389328
+ 2.0420966209334392
+ 2.0422003272971203
+ 2.0423040264817196
+ 2.0424077184885867
+ 2.0425114033190694
+ 2.0426150809745165
+ 2.0427187514562744
+ 2.042822414765691
+ 2.0429260709041124
+ 2.0430297198728855
+ 2.0431333616733562
+ 2.0432369963068693
+ 2.0433406237747707
+ 2.0434442440784037
+ 2.043547857219114
+ 2.043651463198245
+ 2.04375506201714
+ 2.0438586536771415
+ 2.0439622381795925
+ 2.0440658155258355
+ 2.0441693857172116
+ 2.0442729487550624
+ 2.044376504640729
+ 2.044480053375552
+ 2.0445835949608715
+ 2.044687129398027
+ 2.044790656688358
+ 2.044894176833203
+ 2.0449976898339006
+ 2.0451011956917893
+ 2.045204694408207
+ 2.0453081859844895
+ 2.0454116704219754
+ 2.0455151477219995
+ 2.0456186178858995
+ 2.04572208091501
+ 2.0458255368106664
+ 2.0459289855742036
+ 2.0460324272069554
+ 2.0461358617102565
+ 2.0462392890854404
+ 2.0463427093338407
+ 2.046446122456789
+ 2.0465495284556185
+ 2.046652927331661
+ 2.0467563190862483
+ 2.046859703720711
+ 2.04696308123638
+ 2.0470664516345862
+ 2.047169814916659
+ 2.0472731710839276
+ 2.0473765201377216
+ 2.0474798620793697
+ 2.0475831969102005
+ 2.047686524631541
+ 2.04778984524472
+ 2.047893158751063
+ 2.0479964651518983
+ 2.048099764448551
+ 2.0482030566423473
+ 2.048306341734613
+ 2.048409619726673
+ 2.0485128906198518
+ 2.0486161544154737
+ 2.048719411114863
+ 2.048822660719343
+ 2.0489259032302365
+ 2.049029138648866
+ 2.049132366976554
+ 2.0492355882146223
+ 2.049338802364393
+ 2.049442009427186
+ 2.0495452094043225
+ 2.0496484022971235
+ 2.0497515881069073
+ 2.049854766834995
+ 2.049957938482704
+ 2.050061103051354
+ 2.050164260542263
+ 2.050267410956749
+ 2.0503705542961286
+ 2.0504736905617205
+ 2.0505768197548395
+ 2.0506799418768034
+ 2.050783056928927
+ 2.050886164912526
+ 2.0509892658289157
+ 2.0510923596794104
+ 2.0511954464653246
+ 2.0512985261879724
+ 2.0514015988486665
+ 2.05150466444872
+ 2.0516077229894467
+ 2.0517107744721574
+ 2.051813818898165
+ 2.0519168562687806
+ 2.0520198865853154
+ 2.0521229098490794
+ 2.0522259260613835
+ 2.0523289352235374
+ 2.0524319373368507
+ 2.0525349324026325
+ 2.052637920422191
+ 2.0527409013968354
+ 2.0528438753278726
+ 2.0529468422166106
+ 2.0530498020643564
+ 2.0531527548724164
+ 2.0532557006420973
+ 2.0533586393747054
+ 2.053461571071545
+ 2.0535644957339225
+ 2.053667413363142
+ 2.0537703239605074
+ 2.0538732275273235
+ 2.0539761240648935
+ 2.05407901357452
+ 2.0541818960575067
+ 2.0542847715151553
+ 2.054387639948768
+ 2.054490501359646
+ 2.054593355749091
+ 2.0546962031184037
+ 2.054799043468884
+ 2.0549018768018326
+ 2.055004703118549
+ 2.0551075224203315
+ 2.05521033470848
+ 2.055313139984292
+ 2.0554159382490664
+ 2.0555187295041004
+ 2.0556215137506917
+ 2.055724290990136
+ 2.055827061223731
+ 2.0559298244527726
+ 2.0560325806785555
+ 2.056135329902376
+ 2.0562380721255287
+ 2.056340807349308
+ 2.0564435355750077
+ 2.056546256803923
+ 2.0566489710373452
+ 2.056751678276569
+ 2.0568543785228854
+ 2.0569570717775876
+ 2.057059758041967
+ 2.0571624373173156
+ 2.0572651096049235
+ 2.0573677749060817
+ 2.057470433222081
+ 2.05757308455421
+ 2.057675728903759
+ 2.057778366272017
+ 2.0578809966602725
+ 2.0579836200698143
+ 2.058086236501929
+ 2.0581888459579054
+ 2.05829144843903
+ 2.05839404394659
+ 2.0584966324818716
+ 2.05859921404616
+ 2.0587017886407417
+ 2.058804356266901
+ 2.058906916925924
+ 2.059009470619094
+ 2.059112017347695
+ 2.059214557113011
+ 2.0593170899163264
+ 2.0594196157589217
+ 2.059522134642081
+ 2.059624646567086
+ 2.0597271515352187
+ 2.0598296495477593
+ 2.0599321406059903
+ 2.060034624711191
+ 2.0601371018646426
+ 2.0602395720676236
+ 2.0603420353214155
+ 2.060444491627295
+ 2.0605469409865416
+ 2.0606493834004342
+ 2.0607518188702496
+ 2.060854247397266
+ 2.0609566689827608
+ 2.061059083628009
+ 2.061161491334289
+ 2.0612638921028763
+ 2.0613662859350455
+ 2.0614686728320724
+ 2.061571052795232
+ 2.0616734258257976
+ 2.061775791925045
+ 2.061878151094246
+ 2.061980503334676
+ 2.062082848647606
+ 2.0621851870343098
+ 2.0622875184960585
+ 2.0623898430341243
+ 2.0624921606497786
+ 2.0625944713442923
+ 2.062696775118936
+ 2.06279907197498
+ 2.0629013619136947
+ 2.063003644936348
+ 2.0631059210442104
+ 2.06320819023855
+ 2.063310452520636
+ 2.063412707891735
+ 2.0635149563531154
+ 2.063617197906044
+ 2.0637194325517876
+ 2.063821660291613
+ 2.0639238811267866
+ 2.0640260950585727
+ 2.064128302088238
+ 2.0642305022170464
+ 2.064332695446263
+ 2.064434881777152
+ 2.064537061210977
+ 2.0646392337490007
+ 2.0647413993924877
+ 2.0648435581426994
+ 2.0649457100008988
+ 2.065047854968347
+ 2.065149993046306
+ 2.065252124236037
+ 2.0653542485388003
+ 2.065456365955857
+ 2.0655584764884667
+ 2.065660580137889
+ 2.0657626769053827
+ 2.065864766792208
+ 2.065966849799622
+ 2.066068925928884
+ 2.066170995181251
+ 2.0662730575579804
+ 2.0663751130603294
+ 2.0664771616895545
+ 2.066579203446912
+ 2.066681238333658
+ 2.066783266351048
+ 2.066885287500337
+ 2.0669873017827793
+ 2.0670893091996296
+ 2.067191309752143
+ 2.0672933034415713
+ 2.067395290269168
+ 2.0674972702361876
+ 2.0675992433438815
+ 2.0677012095935017
+ 2.0678031689863006
+ 2.0679051215235287
+ 2.068007067206438
+ 2.0681090060362783
+ 2.0682109380143006
+ 2.068312863141754
+ 2.068414781419889
+ 2.068516692849954
+ 2.0686185974331983
+ 2.06872049517087
+ 2.068822386064217
+ 2.0689242701144877
+ 2.0690261473229286
+ 2.0691280176907867
+ 2.069229881219309
+ 2.069331737909742
+ 2.0694335877633296
+ 2.06953543078132
+ 2.0696372669649565
+ 2.0697390963154843
+ 2.0698409188341484
+ 2.0699427345221912
+ 2.0700445433808574
+ 2.0701463454113904
+ 2.0702481406150324
+ 2.0703499289930263
+ 2.0704517105466143
+ 2.0705534852770375
+ 2.070655253185538
+ 2.0707570142733567
+ 2.070858768541734
+ 2.0709605159919104
+ 2.0710622566251256
+ 2.07116399044262
+ 2.071265717445631
+ 2.071367437635399
+ 2.071469151013162
+ 2.071570857580158
+ 2.0716725573376245
+ 2.0717742502867993
+ 2.071875936428919
+ 2.0719776157652205
+ 2.07207928829694
+ 2.0721809540253133
+ 2.0722826129515757
+ 2.072384265076963
+ 2.072485910402709
+ 2.0725875489300485
+ 2.0726891806602166
+ 2.0727908055944457
+ 2.0728924237339688
+ 2.0729940350800202
+ 2.0730956396338316
+ 2.0731972373966356
+ 2.073298828369664
+ 2.0734004125541476
+ 2.0735019899513194
+ 2.073603560562408
+ 2.073705124388645
+ 2.0738066814312597
+ 2.0739082316914828
+ 2.0740097751705426
+ 2.074111311869669
+ 2.0742128417900894
+ 2.0743143649330333
+ 2.0744158812997275
+ 2.0745173908914003
+ 2.074618893709278
+ 2.0747203897545883
+ 2.0748218790285575
+ 2.0749233615324107
+ 2.075024837267374
+ 2.075126306234673
+ 2.075227768435533
+ 2.075329223871178
+ 2.075430672542832
+ 2.07553211445172
+ 2.075633549599064
+ 2.0757349779860887
+ 2.0758363996140154
+ 2.075937814484067
+ 2.076039222597467
+ 2.076140623955435
+ 2.0762420185591934
+ 2.076343406409963
+ 2.076444787508965
+ 2.0765461618574186
+ 2.0766475294565447
+ 2.076748890307562
+ 2.0768502444116903
+ 2.076951591770148
+ 2.077052932384154
+ 2.0771542662549263
+ 2.0772555933836823
+ 2.07735691377164
+ 2.0774582274200157
+ 2.077559534330027
+ 2.0776608345028897
+ 2.077762127939819
+ 2.077863414642032
+ 2.077964694610743
+ 2.078065967847166
+ 2.0781672343525175
+ 2.078268494128011
+ 2.07836974717486
+ 2.078470993494278
+ 2.0785722330874785
+ 2.0786734659556734
+ 2.0787746921000756
+ 2.078875911521897
+ 2.0789771242223494
+ 2.079078330202644
+ 2.0791795294639925
+ 2.079280722007604
+ 2.0793819078346902
+ 2.07948308694646
+ 2.0795842593441236
+ 2.0796854250288903
+ 2.0797865840019676
+ 2.0798877362645656
+ 2.0799888818178918
+ 2.0800900206631536
+ 2.0801911528015586
+ 2.0802922782343143
+ 2.0803933969626267
+ 2.080494508987703
+ 2.0805956143107482
+ 2.0806967129329688
+ 2.0807978048555698
+ 2.080898890079755
+ 2.080999968606731
+ 2.081101040437701
+ 2.081202105573869
+ 2.0813031640164383
+ 2.0814042157666117
+ 2.081505260825593
+ 2.0816062991945836
+ 2.081707330874787
+ 2.081808355867403
+ 2.0819093741736348
+ 2.082010385794683
+ 2.0821113907317477
+ 2.0822123889860293
+ 2.0823133805587286
+ 2.0824143654510445
+ 2.0825153436641766
+ 2.0826163151993233
+ 2.0827172800576843
+ 2.0828182382404568
+ 2.082919189748839
+ 2.083020134584029
+ 2.0831210727472227
+ 2.0832220042396186
+ 2.083322929062412
+ 2.0834238472167987
+ 2.0835247587039754
+ 2.0836256635251376
+ 2.08372656168148
+ 2.083827453174197
+ 2.0839283380044833
+ 2.0840292161735334
+ 2.0841300876825404
+ 2.084230952532698
+ 2.0843318107251982
+ 2.084432662261235
+ 2.0845335071420004
+ 2.084634345368686
+ 2.0847351769424827
+ 2.084836001864583
+ 2.084936820136178
+ 2.085037631758457
+ 2.0851384367326102
+ 2.0852392350598286
+ 2.085340026741301
+ 2.0854408117782164
+ 2.0855415901717644
+ 2.085642361923133
+ 2.08574312703351
+ 2.085843885504083
+ 2.085944637336041
+ 2.086045382530569
+ 2.086146121088855
+ 2.0862468530120855
+ 2.086347578301446
+ 2.086448296958122
+ 2.086549008983299
+ 2.086649714378163
+ 2.0867504131438968
+ 2.0868511052816863
+ 2.086951790792715
+ 2.087052469678166
+ 2.0871531419392237
+ 2.0872538075770697
+ 2.087354466592888
+ 2.08745511898786
+ 2.0875557647631666
+ 2.087656403919991
+ 2.087757036459515
+ 2.087857662382917
+ 2.0879582816913795
+ 2.088058894386082
+ 2.088159500468204
+ 2.088260099938925
+ 2.088360692799425
+ 2.0884612790508825
+ 2.0885618586944754
+ 2.0886624317313824
+ 2.0887629981627818
+ 2.0888635579898494
+ 2.088964111213764
+ 2.0890646578357006
+ 2.089165197856837
+ 2.089265731278349
+ 2.089366258101412
+ 2.0894667783272016
+ 2.089567291956893
+ 2.0896677989916608
+ 2.0897682994326785
+ 2.0898687932811217
+ 2.089969280538163
+ 2.090069761204976
+ 2.0901702352827334
+ 2.090270702772609
+ 2.0903711636757736
+ 2.0904716179933995
+ 2.090572065726659
+ 2.0906725068767233
+ 2.090772941444763
+ 2.090873369431949
+ 2.0909737908394512
+ 2.09107420566844
+ 2.0911746139200846
+ 2.091275015595554
+ 2.0913754106960183
+ 2.091475799222645
+ 2.0915761811766025
+ 2.091676556559059
+ 2.0917769253711818
+ 2.091877287614138
+ 2.0919776432890953
+ 2.0920779923972197
+ 2.0921783349396765
+ 2.092278670917633
+ 2.092379000332254
+ 2.0924793231847056
+ 2.0925796394761513
+ 2.092679949207757
+ 2.0927802523806847
+ 2.0928805489961007
+ 2.0929808390551674
+ 2.093081122559048
+ 2.0931813995089055
+ 2.093281669905902
+ 2.0933819337512007
+ 2.093482191045962
+ 2.0935824417913484
+ 2.0936826859885205
+ 2.09378292363864
+ 2.093883154742866
+ 2.0939833793023603
+ 2.094083597318281
+ 2.094183808791789
+ 2.0942840137240424
+ 2.094384212116201
+ 2.094484403969422
+ 2.0945845892848647
+ 2.0946847680636864
+ 2.094784940307045
+ 2.094885106016097
+ 2.0949852651919993
+ 2.0950854178359086
+ 2.095185563948981
+ 2.0952857035323724
+ 2.0953858365872384
+ 2.0954859631147333
+ 2.095586083116013
+ 2.095686196592231
+ 2.095786303544542
+ 2.0958864039741
+ 2.0959864978820577
+ 2.096086585269569
+ 2.0961866661377866
+ 2.0962867404878622
+ 2.0963868083209487
+ 2.0964868696381975
+ 2.0965869244407602
+ 2.0966869727297883
+ 2.0967870145064325
+ 2.0968870497718424
+ 2.096987078527169
+ 2.097087100773562
+ 2.097187116512171
+ 2.097287125744145
+ 2.0973871284706327
+ 2.097487124692783
+ 2.0975871144117426
+ 2.0976870976286612
+ 2.097787074344686
+ 2.097887044560963
+ 2.09798700827864
+ 2.098086965498863
+ 2.098186916222779
+ 2.098286860451533
+ 2.0983867981862705
+ 2.0984867294281373
+ 2.0985866541782774
+ 2.0986865724378365
+ 2.098786484207958
+ 2.098886389489786
+ 2.098986288284464
+ 2.0990861805931353
+ 2.099186066416942
+ 2.0992859457570283
+ 2.0993858186145347
+ 2.099485684990604
+ 2.099585544886377
+ 2.099685398302997
+ 2.099785245241603
+ 2.099885085703335
+ 2.0999849196893354
+ 2.100084747200743
+ 2.1001845682386966
+ 2.100284382804337
+ 2.100384190898802
+ 2.1004839925232313
+ 2.1005837876787625
+ 2.1006835763665332
+ 2.100783358587682
+ 2.100883134343346
+ 2.100982903634661
+ 2.1010826664627653
+ 2.101182422828794
+ 2.101282172733884
+ 2.1013819161791703
+ 2.1014816531657887
+ 2.101581383694874
+ 2.1016811077675612
+ 2.101780825384984
+ 2.101880536548278
+ 2.1019802412585746
+ 2.1020799395170093
+ 2.1021796313247143
+ 2.1022793166828224
+ 2.102378995592466
+ 2.1024786680547773
+ 2.102578334070888
+ 2.1026779936419295
+ 2.102777646769033
+ 2.10287729345333
+ 2.10297693369595
+ 2.1030765674980234
+ 2.1031761948606804
+ 2.10327581578505
+ 2.1033754302722616
+ 2.1034750383234444
+ 2.103574639939727
+ 2.103674235122237
+ 2.103773823872103
+ 2.1038734061904516
+ 2.103972982078411
+ 2.104072551537108
+ 2.104172114567669
+ 2.10427167117122
+ 2.104371221348888
+ 2.104470765101797
+ 2.1045703024310742
+ 2.104669833337843
+ 2.1047693578232294
+ 2.1048688758883567
+ 2.1049683875343494
+ 2.1050678927623316
+ 2.1051673915734255
+ 2.105266883968756
+ 2.1053663699494436
+ 2.1054658495166128
+ 2.1055653226713855
+ 2.105664789414882
+ 2.105764249748225
+ 2.105863703672535
+ 2.105963151188933
+ 2.1060625922985405
+ 2.106162027002476
+ 2.1062614553018606
+ 2.106360877197814
+ 2.1064602926914544
+ 2.1065597017839015
+ 2.106659104476274
+ 2.106758500769689
+ 2.106857890665266
+ 2.1069572741641216
+ 2.1070566512673734
+ 2.107156021976139
+ 2.1072553862915346
+ 2.1073547442146765
+ 2.107454095746681
+ 2.107553440888663
+ 2.107652779641739
+ 2.1077521120070233
+ 2.1078514379856315
+ 2.107950757578678
+ 2.108050070787276
+ 2.10814937761254
+ 2.1082486780555834
+ 2.108347972117519
+ 2.108447259799461
+ 2.1085465411025206
+ 2.1086458160278108
+ 2.1087450845764426
+ 2.108844346749529
+ 2.1089436025481803
+ 2.1090428519735074
+ 2.1091420950266215
+ 2.109241331708633
+ 2.109340562020652
+ 2.109439785963787
+ 2.109539003539149
+ 2.109638214747846
+ 2.1097374195909873
+ 2.1098366180696813
+ 2.109935810185036
+ 2.1100349959381597
+ 2.1101341753301592
+ 2.110233348362142
+ 2.110332515035215
+ 2.110431675350485
+ 2.1105308293090577
+ 2.11062997691204
+ 2.1107291181605365
+ 2.1108282530556526
+ 2.1109273815984944
+ 2.1110265037901654
+ 2.1111256196317707
+ 2.1112247291244133
+ 2.111323832269199
+ 2.111422929067229
+ 2.1115220195196076
+ 2.1116211036274373
+ 2.1117201813918207
+ 2.1118192528138597
+ 2.1119183178946566
+ 2.1120173766353134
+ 2.1121164290369303
+ 2.1122154751006086
+ 2.112314514827449
+ 2.112413548218552
+ 2.112512575275017
+ 2.1126115959979446
+ 2.1127106103884334
+ 2.112809618447583
+ 2.1129086201764915
+ 2.113007615576258
+ 2.1131066046479807
+ 2.1132055873927564
+ 2.113304563811684
+ 2.11340353390586
+ 2.113502497676381
+ 2.1136014551243436
+ 2.1137004062508447
+ 2.11379935105698
+ 2.1138982895438447
+ 2.113997221712535
+ 2.114096147564145
+ 2.1141950670997702
+ 2.1142939803205048
+ 2.1143928872274427
+ 2.114491787821677
+ 2.114590682104303
+ 2.1146895700764117
+ 2.1147884517390985
+ 2.1148873270934536
+ 2.11498619614057
+ 2.11508505888154
+ 2.1151839153174556
+ 2.115282765449407
+ 2.115381609278486
+ 2.115480446805783
+ 2.1155792780323885
+ 2.1156781029593925
+ 2.1157769215878854
+ 2.115875733918956
+ 2.1159745399536933
+ 2.1160733396931866
+ 2.1161721331385244
+ 2.1162709202907948
+ 2.116369701151086
+ 2.116468475720485
+ 2.11656724400008
+ 2.116666005990958
+ 2.116764761694204
+ 2.116863511110907
+ 2.116962254242151
+ 2.117060991089023
+ 2.1171597216526084
+ 2.1172584459339916
+ 2.117357163934258
+ 2.117455875654492
+ 2.1175545810957783
+ 2.1176532802592005
+ 2.1177519731458423
+ 2.1178506597567868
+ 2.1179493400931175
+ 2.1180480141559173
+ 2.1181466819462678
+ 2.1182453434652517
+ 2.1183439987139505
+ 2.1184426476934464
+ 2.11854129040482
+ 2.1186399268491525
+ 2.118738557027524
+ 2.118837180941016
+ 2.118935798590707
+ 2.1190344099776777
+ 2.119133015103007
+ 2.119231613967774
+ 2.119330206573058
+ 2.1194287929199374
+ 2.1195273730094897
+ 2.119625946842793
+ 2.119724514420925
+ 2.119823075744964
+ 2.119921630815985
+ 2.1200201796350666
+ 2.1201187222032836
+ 2.1202172585217127
+ 2.12031578859143
+ 2.1204143124135104
+ 2.1205128299890297
+ 2.1206113413190617
+ 2.1207098464046816
+ 2.120808345246964
+ 2.1209068378469826
+ 2.1210053242058104
+ 2.1211038043245214
+ 2.121202278204189
+ 2.1213007458458852
+ 2.1213992072506827
+ 2.1214976624196535
+ 2.12159611135387
+ 2.1216945540544025
+ 2.1217929905223243
+ 2.121891420758704
+ 2.121989844764614
+ 2.1220882625411233
+ 2.1221866740893036
+ 2.1222850794102226
+ 2.122383478504952
+ 2.122481871374559
+ 2.122580258020113
+ 2.1226786384426832
+ 2.1227770126433367
+ 2.122875380623143
+ 2.1229737423831683
+ 2.123072097924481
+ 2.123170447248147
+ 2.123268790355234
+ 2.123367127246808
+ 2.123465457923936
+ 2.1235637823876825
+ 2.123662100639114
+ 2.123760412679295
+ 2.1238587185092914
+ 2.123957018130167
+ 2.1240553115429868
+ 2.1241535987488147
+ 2.1242518797487144
+ 2.124350154543749
+ 2.124448423134982
+ 2.1245466855234763
+ 2.124644941710295
+ 2.124743191696499
+ 2.124841435483152
+ 2.1249396730713146
+ 2.1250379044620478
+ 2.125136129656414
+ 2.125234348655473
+ 2.125332561460286
+ 2.125430768071912
+ 2.1255289684914125
+ 2.1256271627198458
+ 2.125725350758272
+ 2.12582353260775
+ 2.1259217082693382
+ 2.126019877744095
+ 2.126118041033079
+ 2.1262161981373477
+ 2.1263143490579597
+ 2.12641249379597
+ 2.1265106323524376
+ 2.126608764728418
+ 2.126706890924968
+ 2.1268050109431442
+ 2.1269031247840013
+ 2.1270012324485954
+ 2.127099333937982
+ 2.1271974292532145
+ 2.1272955183953495
+ 2.12739360136544
+ 2.1274916781645414
+ 2.127589748793705
+ 2.1276878132539867
+ 2.1277858715464384
+ 2.1278839236721128
+ 2.1279819696320628
+ 2.128080009427341
+ 2.128178043058999
+ 2.128276070528088
+ 2.1283740918356604
+ 2.128472106982766
+ 2.128570115970457
+ 2.1286681187997827
+ 2.128766115471794
+ 2.1288641059875406
+ 2.128962090348072
+ 2.129060068554438
+ 2.1291580406076873
+ 2.129256006508868
+ 2.1293539662590297
+ 2.12945191985922
+ 2.129549867310487
+ 2.129647808613878
+ 2.12974574377044
+ 2.1298436727812207
+ 2.1299415956472663
+ 2.1300395123696236
+ 2.1301374229493386
+ 2.130235327387457
+ 2.1303332256850243
+ 2.130431117843086
+ 2.130529003862687
+ 2.1306268837448714
+ 2.1307247574906847
+ 2.13082262510117
+ 2.130920486577372
+ 2.131018341920333
+ 2.131116191131097
+ 2.1312140342107067
+ 2.1313118711602055
+ 2.131409701980635
+ 2.131507526673037
+ 2.131605345238454
+ 2.131703157677927
+ 2.131800963992497
+ 2.131898764183206
+ 2.1319965582510934
+ 2.1320943461972006
+ 2.132192128022566
+ 2.1322899037282315
+ 2.132387673315235
+ 2.1324854367846164
+ 2.1325831941374145
+ 2.132680945374667
+ 2.132778690497414
+ 2.132876429506692
+ 2.1329741624035394
+ 2.1330718891889933
+ 2.1331696098640913
+ 2.13326732442987
+ 2.133365032887366
+ 2.1334627352376154
+ 2.133560431481655
+ 2.13365812162052
+ 2.133755805655246
+ 2.133853483586867
+ 2.13395115541642
+ 2.134048821144938
+ 2.1341464807734556
+ 2.134244134303007
+ 2.134341781734627
+ 2.1344394230693466
+ 2.134537058308201
+ 2.134634687452222
+ 2.1347323105024434
+ 2.134829927459896
+ 2.1349275383256123
+ 2.1350251431006244
+ 2.1351227417859637
+ 2.1352203343826615
+ 2.135317920891748
+ 2.135415501314254
+ 2.1355130756512106
+ 2.1356106439036466
+ 2.135708206072593
+ 2.1358057621590785
+ 2.135903312164132
+ 2.136000856088783
+ 2.13609839393406
+ 2.136195925700991
+ 2.1362934513906042
+ 2.1363909710039275
+ 2.136488484541988
+ 2.1365859920058132
+ 2.1366834933964296
+ 2.1367809887148645
+ 2.136878477962144
+ 2.1369759611392936
+ 2.1370734382473393
+ 2.1371709092873075
+ 2.1372683742602216
+ 2.137365833167109
+ 2.137463286008992
+ 2.1375607327868957
+ 2.1376581735018445
+ 2.1377556081548623
+ 2.137853036746972
+ 2.1379504592791974
+ 2.1380478757525614
+ 2.138145286168086
+ 2.138242690526794
+ 2.138340088829708
+ 2.138437481077849
+ 2.138534867272239
+ 2.1386322474138995
+ 2.1387296215038503
+ 2.138826989543113
+ 2.1389243515327085
+ 2.139021707473656
+ 2.139119057366976
+ 2.139216401213688
+ 2.13931373901481
+ 2.139411070771363
+ 2.1395083964843646
+ 2.139605716154833
+ 2.1397030297837873
+ 2.139800337372245
+ 2.1398976389212234
+ 2.13999493443174
+ 2.1400922239048117
+ 2.140189507341456
+ 2.1402867847426883
+ 2.1403840561095255
+ 2.140481321442984
+ 2.140578580744078
+ 2.140675834013824
+ 2.1407730812532373
+ 2.1408703224633316
+ 2.1409675576451224
+ 2.1410647867996233
+ 2.1411620099278488
+ 2.1412592270308126
+ 2.1413564381095282
+ 2.1414536431650077
+ 2.1415508421982654
+ 2.1416480352103133
+ 2.141745222202163
+ 2.141842403174828
+ 2.1419395781293185
+ 2.1420367470666477
+ 2.142133909987825
+ 2.1422310668938627
+ 2.142328217785771
+ 2.1424253626645595
+ 2.1425225015312397
+ 2.1426196343868202
+ 2.142716761232311
+ 2.142813882068722
+ 2.142910996897061
+ 2.143008105718338
+ 2.14310520853356
+ 2.143202305343737
+ 2.1432993961498745
+ 2.143396480952982
+ 2.1434935597540665
+ 2.143590632554134
+ 2.143687699354193
+ 2.1437847601552487
+ 2.1438818149583074
+ 2.1439788637643757
+ 2.144075906574459
+ 2.144172943389562
+ 2.144269974210691
+ 2.144366999038851
+ 2.144464017875045
+ 2.1445610307202783
+ 2.1446580375755544
+ 2.1447550384418785
+ 2.1448520333202525
+ 2.1449490222116805
+ 2.1450460051171647
+ 2.1451429820377084
+ 2.145239952974314
+ 2.145336917927983
+ 2.145433876899718
+ 2.1455308298905194
+ 2.1456277769013896
+ 2.1457247179333296
+ 2.1458216529873395
+ 2.14591858206442
+ 2.146015505165572
+ 2.146112422291794
+ 2.146209333444087
+ 2.1463062386234495
+ 2.146403137830881
+ 2.1465000310673803
+ 2.146596918333946
+ 2.146693799631576
+ 2.146790674961269
+ 2.1468875443240223
+ 2.146984407720833
+ 2.1470812651526994
+ 2.1471781166206174
+ 2.147274962125584
+ 2.147371801668595
+ 2.1474686352506485
+ 2.147565462872738
+ 2.1476622845358597
+ 2.1477591002410104
+ 2.147855909989183
+ 2.147952713781373
+ 2.148049511618576
+ 2.1481463035017843
+ 2.1482430894319933
+ 2.1483398694101963
+ 2.1484366434373863
+ 2.148533411514557
+ 2.1486301736427014
+ 2.148726929822811
+ 2.148823680055879
+ 2.1489204243428968
+ 2.1490171626848573
+ 2.149113895082751
+ 2.1492106215375695
+ 2.1493073420503035
+ 2.149404056621944
+ 2.149500765253482
+ 2.1495974679459064
+ 2.149694164700208
+ 2.1497908555173764
+ 2.1498875403984
+ 2.149984219344269
+ 2.1500808923559713
+ 2.1501775594344963
+ 2.1502742205808323
+ 2.1503708757959665
+ 2.1504675250808876
+ 2.150564168436582
+ 2.1506608058640375
+ 2.150757437364241
+ 2.1508540629381794
+ 2.150950682586839
+ 2.151047296311205
+ 2.151143904112265
+ 2.1512405059910034
+ 2.151337101948405
+ 2.1514336919854564
+ 2.1515302761031414
+ 2.151626854302445
+ 2.151723426584351
+ 2.151819992949844
+ 2.1519165533999067
+ 2.152013107935524
+ 2.152109656557678
+ 2.1522061992673516
+ 2.152302736065528
+ 2.1523992669531893
+ 2.152495791931318
+ 2.1525923110008955
+ 2.1526888241629036
+ 2.1527853314183236
+ 2.1528818327681365
+ 2.152978328213323
+ 2.153074817754864
+ 2.1531713013937392
+ 2.153267779130929
+ 2.153364250967414
+ 2.153460716904172
+ 2.153557176942183
+ 2.153653631082426
+ 2.1537500793258793
+ 2.153846521673522
+ 2.1539429581263314
+ 2.1540393886852867
+ 2.1541358133513637
+ 2.1542322321255405
+ 2.1543286450087953
+ 2.1544250520021033
+ 2.154521453106442
+ 2.154617848322787
+ 2.154714237652115
+ 2.1548106210954017
+ 2.1549069986536225
+ 2.1550033703277522
+ 2.1550997361187667
+ 2.1551960960276397
+ 2.155292450055346
+ 2.1553887982028606
+ 2.1554851404711557
+ 2.1555814768612067
+ 2.1556778073739857
+ 2.1557741320104666
+ 2.1558704507716224
+ 2.155966763658425
+ 2.156063070671847
+ 2.1561593718128607
+ 2.156255667082438
+ 2.15635195648155
+ 2.1564482400111684
+ 2.1565445176722635
+ 2.156640789465807
+ 2.156737055392769
+ 2.15683331545412
+ 2.15692956965083
+ 2.157025817983868
+ 2.157122060454204
+ 2.1572182970628075
+ 2.1573145278106467
+ 2.157410752698691
+ 2.157506971727908
+ 2.157603184899267
+ 2.157699392213735
+ 2.1577955936722795
+ 2.1578917892758684
+ 2.157987979025469
+ 2.158084162922047
+ 2.1581803409665703
+ 2.1582765131600046
+ 2.1583726795033162
+ 2.1584688399974707
+ 2.158564994643434
+ 2.158661143442171
+ 2.1587572863946463
+ 2.1588534235018257
+ 2.158949554764673
+ 2.159045680184153
+ 2.1591417997612288
+ 2.1592379134968653
+ 2.159334021392025
+ 2.1594301234476716
+ 2.1595262196647678
+ 2.1596223100442766
+ 2.15971839458716
+ 2.159814473294381
+ 2.1599105461668997
+ 2.16000661320568
+ 2.1601026744116822
+ 2.160198729785867
+ 2.160294779329197
+ 2.1603908230426305
+ 2.1604868609271293
+ 2.1605828929836535
+ 2.1606789192131624
+ 2.1607749396166156
+ 2.1608709541949733
+ 2.1609669629491934
+ 2.1610629658802356
+ 2.161158962989058
+ 2.161254954276619
+ 2.161350939743877
+ 2.161446919391789
+ 2.161542893221313
+ 2.1616388612334068
+ 2.1617348234290272
+ 2.16183077980913
+ 2.1619267303746725
+ 2.1620226751266105
+ 2.162118614065901
+ 2.1622145471934986
+ 2.162310474510359
+ 2.1624063960174387
+ 2.1625023117156905
+ 2.1625982216060704
+ 2.1626941256895327
+ 2.162790023967032
+ 2.1628859164395218
+ 2.1629818031079555
+ 2.163077683973287
+ 2.1631735590364687
+ 2.163269428298455
+ 2.163365291760197
+ 2.1634611494226483
+ 2.16355700128676
+ 2.163652847353485
+ 2.1637486876237744
+ 2.1638445220985796
+ 2.1639403507788524
+ 2.1640361736655422
+ 2.1641319907596013
+ 2.1642278020619785
+ 2.1643236075736256
+ 2.164419407295491
+ 2.1645152012285247
+ 2.164610989373677
+ 2.1647067717318955
+ 2.1648025483041304
+ 2.1648983190913293
+ 2.164994084094441
+ 2.165089843314413
+ 2.165185596752194
+ 2.1652813444087315
+ 2.1653770862849724
+ 2.1654728223818642
+ 2.1655685527003525
+ 2.1656642772413854
+ 2.165759996005909
+ 2.1658557089948682
+ 2.16595141620921
+ 2.1660471176498794
+ 2.1661428133178213
+ 2.166238503213982
+ 2.1663341873393054
+ 2.166429865694736
+ 2.1665255382812187
+ 2.1666212050996965
+ 2.1667168661511145
+ 2.1668125214364156
+ 2.166908170956542
+ 2.167003814712439
+ 2.1670994527050476
+ 2.1671950849353108
+ 2.1672907114041715
+ 2.1673863321125704
+ 2.167481947061451
+ 2.167577556251753
+ 2.1676731596844188
+ 2.167768757360389
+ 2.167864349280605
+ 2.167959935446007
+ 2.168055515857535
+ 2.168151090516129
+ 2.168246659422729
+ 2.1683422225782745
+ 2.1684377799837047
+ 2.1685333316399587
+ 2.168628877547975
+ 2.1687244177086926
+ 2.1688199521230493
+ 2.1689154807919833
+ 2.1690110037164323
+ 2.169106520897334
+ 2.1692020323356256
+ 2.169297538032244
+ 2.169393037988126
+ 2.169488532204208
+ 2.1695840206814263
+ 2.1696795034207175
+ 2.169774980423017
+ 2.1698704516892597
+ 2.169965917220382
+ 2.1700613770173183
+ 2.170156831081003
+ 2.1702522794123715
+ 2.1703477220123575
+ 2.1704431588818944
+ 2.1705385900219176
+ 2.1706340154333597
+ 2.1707294351171535
+ 2.1708248490742332
+ 2.170920257305531
+ 2.171015659811979
+ 2.17111105659451
+ 2.1712064476540562
+ 2.1713018329915497
+ 2.1713972126079204
+ 2.171492586504101
+ 2.171587954681023
+ 2.1716833171396157
+ 2.171778673880811
+ 2.1718740249055384
+ 2.1719693702147285
+ 2.1720647098093107
+ 2.1721600436902144
+ 2.1722553718583697
+ 2.1723506943147055
+ 2.1724460110601496
+ 2.1725413220956318
+ 2.1726366274220803
+ 2.172731927040422
+ 2.172827220951587
+ 2.1729225091565008
+ 2.1730177916560915
+ 2.1731130684512863
+ 2.1732083395430117
+ 2.173303604932195
+ 2.173398864619762
+ 2.17349411860664
+ 2.173589366893753
+ 2.1736846094820272
+ 2.1737798463723887
+ 2.1738750775657625
+ 2.173970303063073
+ 2.1740655228652455
+ 2.174160736973204
+ 2.1742559453878725
+ 2.1743511481101754
+ 2.174446345141036
+ 2.174541536481378
+ 2.1746367221321243
+ 2.174731902094198
+ 2.1748270763685222
+ 2.1749222449560186
+ 2.17501740785761
+ 2.175112565074218
+ 2.1752077166067645
+ 2.175302862456171
+ 2.175398002623359
+ 2.1754931371092487
+ 2.1755882659147616
+ 2.175683389040818
+ 2.175778506488338
+ 2.1758736182582417
+ 2.175968724351449
+ 2.1760638247688795
+ 2.1761589195114523
+ 2.176254008580086
+ 2.1763490919757005
+ 2.176444169699214
+ 2.176539241751544
+ 2.1766343081336093
+ 2.1767293688463276
+ 2.1768244238906167
+ 2.1769194732673935
+ 2.177014516977575
+ 2.177109555022079
+ 2.1772045874018215
+ 2.177299614117719
+ 2.1773946351706877
+ 2.177489650561643
+ 2.177584660291501
+ 2.177679664361177
+ 2.1777746627715864
+ 2.1778696555236436
+ 2.1779646426182637
+ 2.1780596240563614
+ 2.1781545998388507
+ 2.178249569966645
+ 2.178344534440659
+ 2.1784394932618056
+ 2.178534446430998
+ 2.1786293939491492
+ 2.178724335817172
+ 2.1788192720359794
+ 2.178914202606483
+ 2.1790091275295955
+ 2.1791040468062284
+ 2.1791989604372928
+ 2.1792938684237004
+ 2.179388770766363
+ 2.17948366746619
+ 2.179578558524093
+ 2.1796734439409824
+ 2.1797683237177674
+ 2.179863197855359
+ 2.1799580663546663
+ 2.1800529292165995
+ 2.1801477864420664
+ 2.1802426380319764
+ 2.180337483987238
+ 2.180432324308761
+ 2.180527158997452
+ 2.18062198805422
+ 2.180716811479972
+ 2.1808116292756163
+ 2.180906441442059
+ 2.1810012479802086
+ 2.1810960488909705
+ 2.181190844175252
+ 2.1812856338339586
+ 2.1813804178679974
+ 2.181475196278274
+ 2.181569969065694
+ 2.181664736231162
+ 2.181759497775584
+ 2.181854253699864
+ 2.181949004004908
+ 2.182043748691619
+ 2.182138487760902
+ 2.18223322121366
+ 2.182327949050798
+ 2.182422671273218
+ 2.1825173878818247
+ 2.1826120988775206
+ 2.1827068042612074
+ 2.182801504033789
+ 2.1828961981961674
+ 2.182990886749243
+ 2.1830855696939198
+ 2.1831802470310984
+ 2.1832749187616796
+ 2.1833695848865657
+ 2.183464245406657
+ 2.1835589003228533
+ 2.1836535496360563
+ 2.1837481933471645
+ 2.18384283145708
+ 2.1839374639667004
+ 2.184032090876926
+ 2.184126712188657
+ 2.18422132790279
+ 2.184315938020226
+ 2.1844105425418623
+ 2.1845051414685974
+ 2.1845997348013295
+ 2.184694322540956
+ 2.1847889046883746
+ 2.184883481244483
+ 2.1849780522101776
+ 2.1850726175863557
+ 2.185167177373914
+ 2.1852617315737484
+ 2.185356280186755
+ 2.1854508232138308
+ 2.18554536065587
+ 2.185639892513769
+ 2.1857344187884227
+ 2.185828939480726
+ 2.185923454591574
+ 2.1860179641218602
+ 2.18611246807248
+ 2.186206966444327
+ 2.186301459238295
+ 2.186395946455278
+ 2.1864904280961683
+ 2.18658490416186
+ 2.186679374653245
+ 2.186773839571217
+ 2.1868682989166675
+ 2.1869627526904893
+ 2.187057200893574
+ 2.1871516435268132
+ 2.187246080591099
+ 2.187340512087322
+ 2.187434938016373
+ 2.1875293583791433
+ 2.1876237731765236
+ 2.187718182409404
+ 2.1878125860786737
+ 2.187906984185224
+ 2.188001376729943
+ 2.1880957637137217
+ 2.188190145137448
+ 2.1882845210020117
+ 2.1883788913083
+ 2.1884732560572027
+ 2.1885676152496076
+ 2.1886619688864033
+ 2.1887563169684765
+ 2.188850659496716
+ 2.188944996472007
+ 2.1890393278952387
+ 2.1891336537672967
+ 2.1892279740890674
+ 2.189322288861439
+ 2.1894165980852955
+ 2.189510901761524
+ 2.1896051998910093
+ 2.1896994924746385
+ 2.1897937795132942
+ 2.189888061007864
+ 2.189982336959231
+ 2.1900766073682805
+ 2.190170872235896
+ 2.1902651315629624
+ 2.1903593853503636
+ 2.1904536335989824
+ 2.1905478763097026
+ 2.190642113483407
+ 2.190736345120979
+ 2.1908305712233016
+ 2.1909247917912564
+ 2.1910190068257256
+ 2.191113216327592
+ 2.1912074202977365
+ 2.1913016187370413
+ 2.1913958116463874
+ 2.191489999026656
+ 2.1915841808787278
+ 2.1916783572034833
+ 2.1917725280018034
+ 2.1918666932745676
+ 2.191960853022656
+ 2.1920550072469487
+ 2.1921491559483255
+ 2.1922432991276644
+ 2.192337436785845
+ 2.1924315689237464
+ 2.1925256955422467
+ 2.1926198166422246
+ 2.192713932224558
+ 2.1928080422901246
+ 2.192902146839803
+ 2.192996245874469
+ 2.193090339395001
+ 2.1931844274022763
+ 2.19327850989717
+ 2.1933725868805602
+ 2.1934666583533224
+ 2.193560724316333
+ 2.1936547847704673
+ 2.1937488397166014
+ 2.1938428891556105
+ 2.1939369330883696
+ 2.194030971515754
+ 2.1941250044386384
+ 2.194219031857897
+ 2.1943130537744038
+ 2.1944070701890332
+ 2.1945010811026586
+ 2.1945950865161543
+ 2.194689086430393
+ 2.194783080846248
+ 2.194877069764592
+ 2.194971053186298
+ 2.195065031112238
+ 2.1951590035432846
+ 2.1952529704803094
+ 2.195346931924185
+ 2.195440887875782
+ 2.1955348383359716
+ 2.195628783305626
+ 2.1957227227856144
+ 2.195816656776809
+ 2.195910585280079
+ 2.196004508296296
+ 2.196098425826328
+ 2.1961923378710466
+ 2.19628624443132
+ 2.196380145508018
+ 2.1964740411020096
+ 2.196567931214164
+ 2.1966618158453493
+ 2.1967556949964337
+ 2.1968495686682856
+ 2.196943436861773
+ 2.1970372995777643
+ 2.1971311568171252
+ 2.1972250085807246
+ 2.1973188548694287
+ 2.1974126956841045
+ 2.197506531025619
+ 2.197600360894838
+ 2.1976941852926277
+ 2.197788004219854
+ 2.197881817677383
+ 2.19797562566608
+ 2.19806942818681
+ 2.1981632252404375
+ 2.1982570168278284
+ 2.1983508029498466
+ 2.198444583607357
+ 2.198538358801223
+ 2.198632128532309
+ 2.1987258928014786
+ 2.198819651609595
+ 2.1989134049575214
+ 2.199007152846121
+ 2.199100895276257
+ 2.199194632248792
+ 2.1992883637645875
+ 2.1993820898245056
+ 2.1994758104294094
+ 2.199569525580159
+ 2.199663235277617
+ 2.1997569395226444
+ 2.1998506383161023
+ 2.199944331658851
+ 2.2000380195517515
+ 2.2001317019956637
+ 2.2002253789914485
+ 2.2003190505399655
+ 2.2004127166420733
+ 2.200506377298633
+ 2.200600032510503
+ 2.200693682278542
+ 2.2007873266036095
+ 2.2008809654865638
+ 2.2009745989282634
+ 2.2010682269295665
+ 2.20116184949133
+ 2.201255466614413
+ 2.201349078299672
+ 2.201442684547965
+ 2.201536285360148
+ 2.201629880737079
+ 2.201723470679614
+ 2.201817055188609
+ 2.201910634264921
+ 2.202004207909405
+ 2.2020977761229177
+ 2.2021913389063137
+ 2.2022848962604487
+ 2.202378448186178
+ 2.2024719946843554
+ 2.2025655357558365
+ 2.2026590714014755
+ 2.2027526016221266
+ 2.2028461264186436
+ 2.20293964579188
+ 2.2030331597426898
+ 2.203126668271926
+ 2.203220171380442
+ 2.20331366906909
+ 2.203407161338723
+ 2.203500648190194
+ 2.203594129624354
+ 2.203687605642056
+ 2.2037810762441516
+ 2.203874541431492
+ 2.2039680012049283
+ 2.204061455565312
+ 2.2041549045134943
+ 2.2042483480503248
+ 2.2043417861766557
+ 2.2044352188933356
+ 2.2045286462012155
+ 2.2046220681011444
+ 2.2047154845939723
+ 2.2048088956805487
+ 2.2049023013617224
+ 2.2049957016383424
+ 2.205089096511258
+ 2.205182485981317
+ 2.2052758700493684
+ 2.205369248716259
+ 2.205462621982838
+ 2.2055559898499517
+ 2.205649352318449
+ 2.205742709389176
+ 2.20583606106298
+ 2.2059294073407076
+ 2.206022748223206
+ 2.20611608371132
+ 2.2062094138058974
+ 2.2063027385077834
+ 2.2063960578178237
+ 2.2064893717368634
+ 2.206582680265748
+ 2.206675983405323
+ 2.206769281156433
+ 2.206862573519922
+ 2.2069558604966346
+ 2.207049142087415
+ 2.207142418293108
+ 2.2072356891145564
+ 2.207328954552603
+ 2.2074222146080933
+ 2.2075154692818684
+ 2.2076087185747713
+ 2.207701962487646
+ 2.2077952010213338
+ 2.2078884341766774
+ 2.2079816619545185
+ 2.2080748843556997
+ 2.208168101381061
+ 2.208261313031445
+ 2.2083545193076923
+ 2.208447720210645
+ 2.2085409157411418
+ 2.2086341059000243
+ 2.2087272906881337
+ 2.2088204701063083
+ 2.2089136441553894
+ 2.2090068128362152
+ 2.209099976149626
+ 2.209193134096462
+ 2.2092862866775604
+ 2.2093794338937607
+ 2.2094725757459015
+ 2.2095657122348213
+ 2.2096588433613586
+ 2.2097519691263505
+ 2.209845089530635
+ 2.20993820457505
+ 2.210031314260432
+ 2.2101244185876188
+ 2.210217517557447
+ 2.2103106111707533
+ 2.2104036994283742
+ 2.2104967823311457
+ 2.210589859879904
+ 2.2106829320754846
+ 2.2107759989187237
+ 2.210869060410456
+ 2.210962116551517
+ 2.211055167342742
+ 2.211148212784965
+ 2.2112412528790206
+ 2.211334287625744
+ 2.2114273170259686
+ 2.211520341080528
+ 2.211613359790256
+ 2.211706373155987
+ 2.2117993811785532
+ 2.211892383858788
+ 2.211985381197524
+ 2.2120783731955944
+ 2.2121713598538313
+ 2.212264341173066
+ 2.212357317154132
+ 2.2124502877978602
+ 2.212543253105083
+ 2.21263621307663
+ 2.212729167713334
+ 2.212822117016025
+ 2.212915060985534
+ 2.213007999622692
+ 2.213100932928328
+ 2.2131938609032735
+ 2.213286783548358
+ 2.2133797008644107
+ 2.213472612852261
+ 2.213565519512738
+ 2.213658420846672
+ 2.2137513168548906
+ 2.2138442075382225
+ 2.213937092897497
+ 2.214029972933541
+ 2.2141228476471833
+ 2.214215717039252
+ 2.214308581110573
+ 2.2144014398619754
+ 2.214494293294285
+ 2.2145871414083302
+ 2.2146799842049365
+ 2.214772821684931
+ 2.21486565384914
+ 2.2149584806983893
+ 2.2150513022335048
+ 2.2151441184553122
+ 2.2152369293646372
+ 2.2153297349623045
+ 2.2154225352491395
+ 2.215515330225967
+ 2.215608119893612
+ 2.2157009042528983
+ 2.21579368330465
+ 2.215886457049692
+ 2.2159792254888475
+ 2.2160719886229394
+ 2.2161647464527925
+ 2.216257498979229
+ 2.216350246203072
+ 2.2164429881251446
+ 2.2165357247462687
+ 2.216628456067267
+ 2.2167211820889623
+ 2.216813902812175
+ 2.216906618237728
+ 2.216999328366442
+ 2.217092033199139
+ 2.2171847327366394
+ 2.217277426979765
+ 2.2173701159293357
+ 2.217462799586172
+ 2.217555477951094
+ 2.217648151024923
+ 2.217740818808477
+ 2.217833481302577
+ 2.2179261385080418
+ 2.218018790425691
+ 2.218111437056343
+ 2.2182040784008166
+ 2.2182967144599313
+ 2.2183893452345047
+ 2.2184819707253554
+ 2.218574590933301
+ 2.2186672058591594
+ 2.2187598155037476
+ 2.218852419867884
+ 2.2189450189523856
+ 2.219037612758069
+ 2.2191302012857506
+ 2.2192227845362473
+ 2.2193153625103763
+ 2.2194079352089515
+ 2.219500502632791
+ 2.219593064782709
+ 2.219685621659522
+ 2.219778173264045
+ 2.2198707195970933
+ 2.2199632606594806
+ 2.220055796452023
+ 2.2201483269755338
+ 2.220240852230829
+ 2.220333372218721
+ 2.220425886940024
+ 2.2205183963955517
+ 2.2206109005861183
+ 2.220703399512536
+ 2.220795893175618
+ 2.2208883815761777
+ 2.2209808647150275
+ 2.22107334259298
+ 2.221165815210847
+ 2.22125828256944
+ 2.221350744669572
+ 2.221443201512054
+ 2.2215356530976975
+ 2.2216280994273134
+ 2.221720540501713
+ 2.221812976321707
+ 2.221905406888106
+ 2.2219978322017204
+ 2.22209025226336
+ 2.222182667073836
+ 2.2222750766339563
+ 2.222367480944532
+ 2.222459880006372
+ 2.222552273820285
+ 2.22264466238708
+ 2.2227370457075666
+ 2.222829423782553
+ 2.2229217966128467
+ 2.2230141641992565
+ 2.2231065265425904
+ 2.223198883643656
+ 2.223291235503261
+ 2.2233835821222123
+ 2.2234759235013177
+ 2.223568259641383
+ 2.2236605905432163
+ 2.2237529162076233
+ 2.22384523663541
+ 2.223937551827383
+ 2.2240298617843486
+ 2.224122166507112
+ 2.2242144659964787
+ 2.2243067602532536
+ 2.2243990492782424
+ 2.22449133307225
+ 2.2245836116360813
+ 2.22467588497054
+ 2.224768153076431
+ 2.2248604159545584
+ 2.2249526736057255
+ 2.225044926030736
+ 2.2251371732303946
+ 2.2252294152055034
+ 2.2253216519568655
+ 2.2254138834852846
+ 2.2255061097915627
+ 2.225598330876502
+ 2.2256905467409056
+ 2.2257827573855753
+ 2.2258749628113126
+ 2.2259671630189195
+ 2.226059358009197
+ 2.226151547782947
+ 2.2262437323409707
+ 2.2263359116840684
+ 2.226428085813041
+ 2.2265202547286886
+ 2.226612418431812
+ 2.226704576923211
+ 2.2267967302036857
+ 2.2268888782740355
+ 2.22698102113506
+ 2.2270731587875585
+ 2.227165291232329
+ 2.2272574184701726
+ 2.227349540501886
+ 2.2274416573282685
+ 2.2275337689501185
+ 2.2276258753682336
+ 2.2277179765834116
+ 2.227810072596451
+ 2.2279021634081486
+ 2.2279942490193014
+ 2.228086329430707
+ 2.228178404643162
+ 2.228270474657463
+ 2.2283625394744067
+ 2.22845459909479
+ 2.2285466535194076
+ 2.228638702749056
+ 2.2287307467845308
+ 2.2288227856266283
+ 2.2289148192761425
+ 2.229006847733869
+ 2.2290988710006028
+ 2.2291908890771386
+ 2.229282901964271
+ 2.2293749096627935
+ 2.229466912173501
+ 2.2295589094971873
+ 2.2296509016346464
+ 2.2297428885866704
+ 2.229834870354054
+ 2.2299268469375897
+ 2.2300188183380705
+ 2.230110784556289
+ 2.2302027455930378
+ 2.2302947014491092
+ 2.2303866521252957
+ 2.230478597622388
+ 2.2305705379411798
+ 2.230662473082461
+ 2.2307544030470225
+ 2.230846327835657
+ 2.2309382474491546
+ 2.231030161888306
+ 2.231122071153902
+ 2.2312139752467326
+ 2.231305874167588
+ 2.231397767917259
+ 2.2314896564965343
+ 2.231581539906203
+ 2.231673418147056
+ 2.231765291219881
+ 2.2318571591254677
+ 2.2319490218646045
+ 2.2320408794380806
+ 2.2321327318466837
+ 2.2322245790912025
+ 2.2323164211724245
+ 2.2324082580911377
+ 2.2325000898481298
+ 2.2325919164441874
+ 2.232683737880099
+ 2.2327755541566505
+ 2.232867365274629
+ 2.2329591712348216
+ 2.2330509720380136
+ 2.2331427676849924
+ 2.2332345581765436
+ 2.2333263435134527
+ 2.233418123696506
+ 2.233509898726488
+ 2.2336016686041846
+ 2.2336934333303806
+ 2.2337851929058608
+ 2.2338769473314097
+ 2.2339686966078123
+ 2.234060440735852
+ 2.234152179716314
+ 2.234243913549981
+ 2.234335642237638
+ 2.2344273657800673
+ 2.2345190841780522
+ 2.2346107974323766
+ 2.2347025055438228
+ 2.234794208513174
+ 2.2348859063412116
+ 2.2349775990287193
+ 2.2350692865764783
+ 2.235160968985271
+ 2.235252646255879
+ 2.235344318389083
+ 2.2354359853856662
+ 2.235527647246408
+ 2.2356193039720904
+ 2.2357109555634933
+ 2.2358026020213977
+ 2.2358942433465847
+ 2.235985879539833
+ 2.2360775106019237
+ 2.236169136533636
+ 2.23626075733575
+ 2.2363523730090447
+ 2.236443983554299
+ 2.236535588972293
+ 2.2366271892638045
+ 2.236718784429613
+ 2.236810374470496
+ 2.236901959387233
+ 2.2369935391806006
+ 2.237085113851377
+ 2.2371766834003406
+ 2.2372682478282684
+ 2.237359807135938
+ 2.237451361324126
+ 2.2375429103936093
+ 2.237634454345165
+ 2.2377259931795694
+ 2.237817526897599
+ 2.23790905550003
+ 2.238000578987638
+ 2.2380920973611986
+ 2.2381836106214874
+ 2.238275118769281
+ 2.2383666218053526
+ 2.2384581197304785
+ 2.2385496125454325
+ 2.2386411002509905
+ 2.2387325828479256
+ 2.2388240603370138
+ 2.2389155327190267
+ 2.23900699999474
+ 2.2390984621649266
+ 2.2391899192303595
+ 2.2392813711918134
+ 2.23937281805006
+ 2.2394642598058723
+ 2.239555696460024
+ 2.2396471280132864
+ 2.2397385544664323
+ 2.2398299758202342
+ 2.2399213920754635
+ 2.240012803232892
+ 2.2401042092932912
+ 2.2401956102574325
+ 2.240287006126087
+ 2.2403783969000264
+ 2.24046978258002
+ 2.2405611631668396
+ 2.240652538661255
+ 2.2407439090640366
+ 2.240835274375955
+ 2.2409266345977787
+ 2.241017989730279
+ 2.2411093397742237
+ 2.2412006847303823
+ 2.241292024599525
+ 2.2413833593824206
+ 2.2414746890798365
+ 2.2415660136925415
+ 2.2416573332213052
+ 2.241748647666894
+ 2.2418399570300775
+ 2.2419312613116227
+ 2.242022560512296
+ 2.2421138546328665
+ 2.2422051436741004
+ 2.242296427636765
+ 2.2423877065216273
+ 2.2424789803294534
+ 2.2425702490610107
+ 2.2426615127170635
+ 2.2427527712983797
+ 2.2428440248057244
+ 2.242935273239863
+ 2.243026516601562
+ 2.2431177548915855
+ 2.243208988110699
+ 2.2433002162596676
+ 2.2433914393392564
+ 2.2434826573502296
+ 2.2435738702933503
+ 2.2436650781693848
+ 2.2437562809790954
+ 2.2438474787232465
+ 2.243938671402602
+ 2.244029859017925
+ 2.2441210415699784
+ 2.2442122190595257
+ 2.2443033914873296
+ 2.244394558854153
+ 2.244485721160758
+ 2.2445768784079063
+ 2.2446680305963613
+ 2.244759177726884
+ 2.2448503198002365
+ 2.2449414568171804
+ 2.245032588778477
+ 2.2451237156848864
+ 2.245214837537171
+ 2.245305954336091
+ 2.2453970660824076
+ 2.2454881727768803
+ 2.2455792744202694
+ 2.2456703710133357
+ 2.245761462556838
+ 2.2458525490515364
+ 2.2459436304981915
+ 2.246034706897561
+ 2.2461257782504043
+ 2.246216844557481
+ 2.2463079058195494
+ 2.246398962037368
+ 2.246490013211695
+ 2.246581059343289
+ 2.2466721004329075
+ 2.2467631364813094
+ 2.246854167489251
+ 2.2469451934574898
+ 2.247036214386784
+ 2.24712723027789
+ 2.247218241131565
+ 2.247309246948565
+ 2.2474002477296473
+ 2.247491243475568
+ 2.247582234187083
+ 2.2476732198649487
+ 2.24776420050992
+ 2.247855176122753
+ 2.2479461467042032
+ 2.2480371122550262
+ 2.248128072775976
+ 2.2482190282678083
+ 2.2483099787312772
+ 2.248400924167137
+ 2.2484918645761427
+ 2.248582799959048
+ 2.2486737303166073
+ 2.248764655649573
+ 2.2488555759587
+ 2.2489464912447414
+ 2.2490374015084496
+ 2.2491283067505785
+ 2.2492192069718806
+ 2.249310102173108
+ 2.2494009923550142
+ 2.249491877518351
+ 2.249582757663869
+ 2.249673632792323
+ 2.2497645029044624
+ 2.249855368001039
+ 2.249946228082805
+ 2.250037083150511
+ 2.250127933204908
+ 2.2502187782467478
+ 2.2503096182767792
+ 2.2504004532957533
+ 2.25049128330442
+ 2.2505821083035307
+ 2.250672928293835
+ 2.250763743276081
+ 2.250854553251019
+ 2.2509453582193992
+ 2.2510361581819702
+ 2.2511269531394804
+ 2.251217743092679
+ 2.2513085280423146
+ 2.2513993079891352
+ 2.25149008293389
+ 2.2515808528773262
+ 2.2516716178201914
+ 2.2517623777632343
+ 2.2518531327072018
+ 2.251943882652841
+ 2.2520346276009
+ 2.2521253675521242
+ 2.252216102507261
+ 2.2523068324670574
+ 2.25239755743226
+ 2.2524882774036143
+ 2.252578992381866
+ 2.2526697023677626
+ 2.2527604073620484
+ 2.2528511073654687
+ 2.25294180237877
+ 2.253032492402696
+ 2.2531231774379927
+ 2.2532138574854046
+ 2.2533045325456764
+ 2.2533952026195525
+ 2.2534858677077763
+ 2.2535765278110933
+ 2.2536671829302457
+ 2.253757833065978
+ 2.2538484782190342
+ 2.253939118390157
+ 2.2540297535800895
+ 2.254120383789575
+ 2.2542110090193566
+ 2.2543016292701754
+ 2.2543922445427755
+ 2.2544828548378977
+ 2.2545734601562852
+ 2.25466406049868
+ 2.254754655865822
+ 2.2548452462584545
+ 2.2549358316773183
+ 2.2550264121231542
+ 2.2551169875967036
+ 2.255207558098707
+ 2.2552981236299052
+ 2.255388684191039
+ 2.255479239782848
+ 2.255569790406072
+ 2.2556603360614518
+ 2.255750876749726
+ 2.2558414124716357
+ 2.2559319432279192
+ 2.2560224690193156
+ 2.256112989846564
+ 2.2562035057104035
+ 2.256294016611572
+ 2.2563845225508095
+ 2.2564750235288527
+ 2.25656551954644
+ 2.25665601060431
+ 2.256746496703199
+ 2.2568369778438466
+ 2.256927454026989
+ 2.2570179252533635
+ 2.2571083915237065
+ 2.2571988528387563
+ 2.257289309199248
+ 2.2573797606059194
+ 2.257470207059506
+ 2.257560648560744
+ 2.2576510851103695
+ 2.2577415167091184
+ 2.257831943357726
+ 2.257922365056928
+ 2.258012781807459
+ 2.2581031936100553
+ 2.258193600465451
+ 2.2582840023743804
+ 2.2583743993375784
+ 2.258464791355779
+ 2.2585551784297175
+ 2.258645560560127
+ 2.2587359377477414
+ 2.2588263099932946
+ 2.258916677297519
+ 2.259007039661149
+ 2.2590973970849175
+ 2.2591877495695574
+ 2.2592780971158013
+ 2.2593684397243816
+ 2.2594587773960315
+ 2.259549110131482
+ 2.259639437931466
+ 2.259729760796715
+ 2.259820078727961
+ 2.2599103917259353
+ 2.2600006997913686
+ 2.260091002924993
+ 2.26018130112754
+ 2.2602715943997382
+ 2.26036188274232
+ 2.260452166156016
+ 2.260542444641555
+ 2.260632718199669
+ 2.2607229868310856
+ 2.2608132505365366
+ 2.260903509316751
+ 2.2609937631724573
+ 2.261084012104385
+ 2.2611742561132644
+ 2.2612644951998226
+ 2.26135472936479
+ 2.261444958608894
+ 2.261535182932863
+ 2.261625402337425
+ 2.261715616823308
+ 2.261805826391241
+ 2.2618960310419505
+ 2.261986230776164
+ 2.2620764255946084
+ 2.262166615498012
+ 2.262256800487101
+ 2.2623469805626018
+ 2.2624371557252414
+ 2.262527325975746
+ 2.2626174913148422
+ 2.262707651743256
+ 2.2627978072617125
+ 2.2628879578709387
+ 2.262978103571659
+ 2.2630682443645993
+ 2.2631583802504847
+ 2.26324851123004
+ 2.26333863730399
+ 2.2634287584730597
+ 2.263518874737973
+ 2.263608986099455
+ 2.263699092558229
+ 2.2637891941150197
+ 2.26387929077055
+ 2.2639693825255445
+ 2.264059469380726
+ 2.2641495513368177
+ 2.264239628394543
+ 2.264329700554624
+ 2.264419767817785
+ 2.2645098301847475
+ 2.264599887656234
+ 2.264689940232966
+ 2.264779987915667
+ 2.2648700307050578
+ 2.2649600686018605
+ 2.2650501016067963
+ 2.265140129720587
+ 2.2652301529439534
+ 2.2653201712776165
+ 2.2654101847222976
+ 2.2655001932787164
+ 2.2655901969475947
+ 2.2656801957296513
+ 2.2657701896256075
+ 2.2658601786361827
+ 2.265950162762097
+ 2.2660401420040692
+ 2.2661301163628202
+ 2.2662200858390675
+ 2.2663100504335314
+ 2.266400010146931
+ 2.2664899649799835
+ 2.2665799149334096
+ 2.266669860007926
+ 2.2667598002042517
+ 2.266849735523104
+ 2.266939665965202
+ 2.2670295915312626
+ 2.2671195122220036
+ 2.267209428038142
+ 2.2672993389803953
+ 2.267389245049481
+ 2.267479146246115
+ 2.2675690425710138
+ 2.267658934024895
+ 2.2677488206084746
+ 2.2678387023224684
+ 2.2679285791675925
+ 2.2680184511445627
+ 2.268108318254095
+ 2.2681981804969045
+ 2.2682880378737065
+ 2.268377890385216
+ 2.268467738032148
+ 2.268557580815218
+ 2.2686474187351395
+ 2.268737251792628
+ 2.2688270799883976
+ 2.2689169033231615
+ 2.2690067217976337
+ 2.2690965354125296
+ 2.2691863441685607
+ 2.269276148066442
+ 2.269365947106886
+ 2.2694557412906056
+ 2.2695455306183137
+ 2.269635315090724
+ 2.269725094708548
+ 2.2698148694724987
+ 2.269904639383288
+ 2.269994404441628
+ 2.2700841646482304
+ 2.2701739200038076
+ 2.27026367050907
+ 2.27035341616473
+ 2.2704431569714987
+ 2.2705328929300865
+ 2.270622624041205
+ 2.2707123503055637
+ 2.270802071723875
+ 2.2708917882968476
+ 2.2709815000251923
+ 2.271071206909619
+ 2.2711609089508373
+ 2.271250606149558
+ 2.271340298506489
+ 2.2714299860223406
+ 2.271519668697822
+ 2.271609346533642
+ 2.2716990195305087
+ 2.2717886876891322
+ 2.2718783510102196
+ 2.2719680094944805
+ 2.2720576631426215
+ 2.272147311955352
+ 2.2722369559333795
+ 2.272326595077411
+ 2.272416229388154
+ 2.2725058588663165
+ 2.2725954835126054
+ 2.2726851033277273
+ 2.2727747183123896
+ 2.2728643284672985
+ 2.2729539337931604
+ 2.273043534290682
+ 2.2731331299605686
+ 2.2732227208035263
+ 2.273312306820262
+ 2.2734018880114806
+ 2.273491464377887
+ 2.273581035920187
+ 2.273670602639086
+ 2.2737601645352887
+ 2.2738497216094995
+ 2.2739392738624233
+ 2.2740288212947646
+ 2.274118363907228
+ 2.2742079017005166
+ 2.274297434675335
+ 2.2743869628323874
+ 2.2744764861723765
+ 2.274566004696007
+ 2.27465551840398
+ 2.2747450272970005
+ 2.2748345313757703
+ 2.2749240306409937
+ 2.2750135250933714
+ 2.2751030147336073
+ 2.275192499562402
+ 2.27528197958046
+ 2.275371454788481
+ 2.2754609251871685
+ 2.275550390777222
+ 2.2756398515593452
+ 2.2757293075342373
+ 2.275818758702601
+ 2.2759082050651367
+ 2.2759976466225447
+ 2.276087083375526
+ 2.276176515324781
+ 2.2762659424710097
+ 2.276355364814913
+ 2.27644478235719
+ 2.27653419509854
+ 2.276623603039664
+ 2.27671300618126
+ 2.276802404524029
+ 2.2768917980686685
+ 2.2769811868158776
+ 2.2770705707663557
+ 2.2771599499208017
+ 2.2772493242799126
+ 2.2773386938443876
+ 2.277428058614925
+ 2.2775174185922222
+ 2.277606773776977
+ 2.2776961241698874
+ 2.277785469771651
+ 2.2778748105829645
+ 2.277964146604525
+ 2.2780534778370294
+ 2.278142804281175
+ 2.278232125937658
+ 2.2783214428071745
+ 2.2784107548904218
+ 2.278500062188095
+ 2.278589364700891
+ 2.278678662429505
+ 2.2787679553746316
+ 2.2788572435369683
+ 2.278946526917209
+ 2.2790358055160493
+ 2.2791250793341837
+ 2.2792143483723075
+ 2.2793036126311157
+ 2.2793928721113015
+ 2.2794821268135603
+ 2.2795713767385855
+ 2.2796606218870714
+ 2.279749862259712
+ 2.2798390978572005
+ 2.2799283286802305
+ 2.280017554729496
+ 2.2801067760056895
+ 2.2801959925095034
+ 2.2802852042416317
+ 2.280374411202766
+ 2.2804636133936
+ 2.2805528108148247
+ 2.280642003467133
+ 2.280731191351217
+ 2.280820374467768
+ 2.280909552817478
+ 2.2809987264010383
+ 2.281087895219141
+ 2.2811770592724763
+ 2.281266218561736
+ 2.2813553730876097
+ 2.2814445228507894
+ 2.281533667851965
+ 2.281622808091827
+ 2.2817119435710658
+ 2.281801074290371
+ 2.281890200250433
+ 2.281979321451941
+ 2.282068437895585
+ 2.282157549582054
+ 2.282246656512037
+ 2.282335758686224
+ 2.2824248561053024
+ 2.282513948769963
+ 2.282603036680892
+ 2.2826921198387797
+ 2.2827811982443142
+ 2.2828702718981817
+ 2.2829593408010727
+ 2.283048404953673
+ 2.283137464356671
+ 2.283226519010754
+ 2.2833155689166094
+ 2.283404614074924
+ 2.2834936544863846
+ 2.2835826901516785
+ 2.2836717210714923
+ 2.2837607472465122
+ 2.283849768677425
+ 2.283938785364916
+ 2.284027797309671
+ 2.2841168045123768
+ 2.284205806973719
+ 2.2842948046943823
+ 2.2843837976750523
+ 2.2844727859164142
+ 2.284561769419154
+ 2.284650748183955
+ 2.2847397222115027
+ 2.284828691502481
+ 2.2849176560575746
+ 2.285006615877468
+ 2.285095570962845
+ 2.2851845213143895
+ 2.285273466932785
+ 2.2853624078187154
+ 2.2854513439728636
+ 2.2855402753959138
+ 2.285629202088548
+ 2.2857181240514493
+ 2.2858070412853007
+ 2.2858959537907846
+ 2.285984861568584
+ 2.28607376461938
+ 2.286162662943856
+ 2.286251556542693
+ 2.286340445416573
+ 2.2864293295661784
+ 2.2865182089921894
+ 2.286607083695288
+ 2.2866959536761553
+ 2.2867848189354723
+ 2.2868736794739197
+ 2.286962535292178
+ 2.287051386390928
+ 2.2871402327708497
+ 2.2872290744326236
+ 2.2873179113769297
+ 2.2874067436044476
+ 2.2874955711158576
+ 2.287584393911838
+ 2.2876732119930696
+ 2.2877620253602307
+ 2.2878508340140007
+ 2.2879396379550583
+ 2.288028437184083
+ 2.2881172317017517
+ 2.2882060215087447
+ 2.288294806605739
+ 2.288383586993414
+ 2.2884723626724455
+ 2.288561133643513
+ 2.2886498999072944
+ 2.288738661464466
+ 2.2888274183157056
+ 2.28891617046169
+ 2.2890049179030965
+ 2.2890936606406025
+ 2.289182398674883
+ 2.289271132006617
+ 2.2893598606364787
+ 2.289448584565145
+ 2.289537303793292
+ 2.2896260183215955
+ 2.2897147281507317
+ 2.2898034332813753
+ 2.2898921337142024
+ 2.2899808294498873
+ 2.2900695204891064
+ 2.290158206832534
+ 2.2902468884808447
+ 2.2903355654347135
+ 2.2904242376948143
+ 2.290512905261822
+ 2.2906015681364105
+ 2.2906902263192532
+ 2.290778879811025
+ 2.2908675286123983
+ 2.2909561727240475
+ 2.2910448121466462
+ 2.291133446880867
+ 2.291222076927383
+ 2.291310702286867
+ 2.291399322959992
+ 2.29148793894743
+ 2.2915765502498546
+ 2.2916651568679365
+ 2.291753758802349
+ 2.2918423560537633
+ 2.291930948622851
+ 2.292019536510285
+ 2.292108119716736
+ 2.292196698242874
+ 2.2922852720893725
+ 2.2923738412569006
+ 2.2924624057461305
+ 2.2925509655577314
+ 2.2926395206923753
+ 2.2927280711507323
+ 2.292816616933471
+ 2.292905158041264
+ 2.2929936944747786
+ 2.2930822262346866
+ 2.2931707533216565
+ 2.2932592757363577
+ 2.29334779347946
+ 2.293436306551632
+ 2.293524814953543
+ 2.293613318685862
+ 2.2937018177492567
+ 2.293790312144396
+ 2.293878801871949
+ 2.293967286932583
+ 2.2940557673269666
+ 2.294144243055767
+ 2.2942327141196523
+ 2.29432118051929
+ 2.2944096422553475
+ 2.294498099328492
+ 2.294586551739391
+ 2.29467499948871
+ 2.2947634425771173
+ 2.294851881005279
+ 2.294940314773861
+ 2.295028743883531
+ 2.295117168334954
+ 2.295205588128796
+ 2.295294003265723
+ 2.295382413746401
+ 2.2954708195714955
+ 2.2955592207416715
+ 2.295647617257594
+ 2.295736009119929
+ 2.29582439632934
+ 2.295912778886493
+ 2.296001156792052
+ 2.296089530046682
+ 2.296177898651047
+ 2.2962662626058106
+ 2.2963546219116373
+ 2.2964429765691907
+ 2.2965313265791343
+ 2.2966196719421323
+ 2.2967080126588475
+ 2.2967963487299428
+ 2.296884680156082
+ 2.2969730069379275
+ 2.297061329076143
+ 2.2971496465713894
+ 2.29723795942433
+ 2.2973262676356274
+ 2.2974145712059433
+ 2.2975028701359395
+ 2.297591164426278
+ 2.2976794540776213
+ 2.297767739090629
+ 2.2978560194659647
+ 2.297944295204288
+ 2.29803256630626
+ 2.2981208327725424
+ 2.298209094603795
+ 2.29829735180068
+ 2.2983856043638555
+ 2.298473852293984
+ 2.298562095591724
+ 2.2986503342577365
+ 2.29873856829268
+ 2.2988267976972163
+ 2.2989150224720034
+ 2.2990032426177005
+ 2.299091458134967
+ 2.299179669024463
+ 2.299267875286846
+ 2.2993560769227757
+ 2.2994442739329095
+ 2.2995324663179075
+ 2.2996206540784265
+ 2.299708837215126
+ 2.2997970157286622
+ 2.299885189619695
+ 2.2999733588888804
+ 2.3000615235368764
+ 2.3001496835643405
+ 2.3002378389719302
+ 2.300325989760302
+ 2.3004141359301133
+ 2.3005022774820207
+ 2.3005904144166807
+ 2.3006785467347495
+ 2.300766674436884
+ 2.3008547975237397
+ 2.300942915995973
+ 2.30103102985424
+ 2.3011191390991956
+ 2.301207243731496
+ 2.3012953437517965
+ 2.3013834391607517
+ 2.301471529959018
+ 2.3015596161472494
+ 2.3016476977261
+ 2.3017357746962257
+ 2.301823847058281
+ 2.301911914812919
+ 2.301999977960795
+ 2.3020880365025627
+ 2.3021760904388753
+ 2.302264139770388
+ 2.302352184497752
+ 2.302440224621624
+ 2.302528260142654
+ 2.3026162910614976
+ 2.302704317378806
+ 2.302792339095233
+ 2.3028803562114315
+ 2.302968368728053
+ 2.3030563766457504
+ 2.3031443799651754
+ 2.303232378686981
+ 2.3033203728118186
+ 2.30340836234034
+ 2.3034963472731964
+ 2.3035843276110404
+ 2.303672303354522
+ 2.303760274504293
+ 2.3038482410610044
+ 2.303936203025307
+ 2.304024160397851
+ 2.3041121131792877
+ 2.304200061370267
+ 2.3042880049714394
+ 2.3043759439834544
+ 2.3044638784069633
+ 2.304551808242615
+ 2.304639733491059
+ 2.304727654152945
+ 2.304815570228922
+ 2.30490348171964
+ 2.304991388625748
+ 2.3050792909478934
+ 2.3051671886867267
+ 2.305255081842896
+ 2.30534297041705
+ 2.3054308544098356
+ 2.305518733821902
+ 2.305606608653898
+ 2.30569447890647
+ 2.3057823445802663
+ 2.305870205675934
+ 2.3059580621941222
+ 2.306045914135476
+ 2.306133761500644
+ 2.3062216042902715
+ 2.306309442505007
+ 2.3063972761454967
+ 2.3064851052123867
+ 2.306572929706323
+ 2.3066607496279534
+ 2.3067485649779225
+ 2.3068363757568764
+ 2.3069241819654613
+ 2.3070119836043226
+ 2.307099780674106
+ 2.3071875731754563
+ 2.307275361109019
+ 2.307363144475439
+ 2.3074509232753613
+ 2.3075386975094307
+ 2.307626467178292
+ 2.3077142322825885
+ 2.3078019928229656
+ 2.307889748800067
+ 2.3079775002145366
+ 2.308065247067019
+ 2.3081529893581565
+ 2.308240727088594
+ 2.308328460258974
+ 2.3084161888699395
+ 2.3085039129221347
+ 2.308591632416202
+ 2.308679347352784
+ 2.3087670577325237
+ 2.308854763556063
+ 2.308942464824044
+ 2.3090301615371107
+ 2.3091178536959034
+ 2.309205541301065
+ 2.3092932243532363
+ 2.30938090285306
+ 2.3094685768011765
+ 2.309556246198228
+ 2.309643911044855
+ 2.3097315713416986
+ 2.3098192270894007
+ 2.3099068782886008
+ 2.30999452493994
+ 2.310082167044058
+ 2.3101698046015966
+ 2.310257437613195
+ 2.310345066079493
+ 2.3104326900011305
+ 2.310520309378748
+ 2.3106079242129836
+ 2.310695534504478
+ 2.31078314025387
+ 2.3108707414617986
+ 2.310958338128903
+ 2.311045930255822
+ 2.3111335178431944
+ 2.311221100891658
+ 2.3113086794018516
+ 2.311396253374414
+ 2.3114838228099823
+ 2.3115713877091952
+ 2.31165894807269
+ 2.3117465039011047
+ 2.3118340551950767
+ 2.3119216019552433
+ 2.3120091441822415
+ 2.312096681876709
+ 2.312184215039282
+ 2.3122717436705975
+ 2.312359267771292
+ 2.3124467873420027
+ 2.312534302383365
+ 2.3126218128960154
+ 2.3127093188805907
+ 2.312796820337726
+ 2.312884317268056
+ 2.3129718096722183
+ 2.3130592975508475
+ 2.3131467809045785
+ 2.3132342597340476
+ 2.3133217340398886
+ 2.3134092038227374
+ 2.3134966690832277
+ 2.3135841298219946
+ 2.3136715860396726
+ 2.313759037736896
+ 2.313846484914299
+ 2.3139339275725153
+ 2.3140213657121786
+ 2.3141087993339235
+ 2.314196228438383
+ 2.31428365302619
+ 2.314371073097979
+ 2.314458488654382
+ 2.3145458996960326
+ 2.3146333062235636
+ 2.314720708237607
+ 2.314808105738796
+ 2.3148954987277635
+ 2.314982887205141
+ 2.315070271171561
+ 2.3151576506276554
+ 2.3152450255740558
+ 2.3153323960113936
+ 2.3154197619403005
+ 2.3155071233614093
+ 2.315594480275349
+ 2.315681832682752
+ 2.3157691805842497
+ 2.3158565239804725
+ 2.31594386287205
+ 2.3160311972596146
+ 2.3161185271437947
+ 2.316205852525222
+ 2.3162931734045267
+ 2.3163804897823375
+ 2.316467801659285
+ 2.316555109035999
+ 2.316642411913109
+ 2.3167297102912436
+ 2.316817004171033
+ 2.3169042935531063
+ 2.3169915784380914
+ 2.3170788588266182
+ 2.317166134719315
+ 2.31725340611681
+ 2.317340673019732
+ 2.3174279354287095
+ 2.31751519334437
+ 2.3176024467673417
+ 2.317689695698252
+ 2.3177769401377293
+ 2.3178641800864
+ 2.317951415544893
+ 2.3180386465138345
+ 2.318125872993852
+ 2.318213094985572
+ 2.318300312489622
+ 2.318387525506628
+ 2.3184747340372165
+ 2.3185619380820146
+ 2.3186491376416476
+ 2.3187363327167425
+ 2.3188235233079246
+ 2.31891070941582
+ 2.3189978910410542
+ 2.319085068184253
+ 2.3191722408460413
+ 2.319259409027045
+ 2.319346572727888
+ 2.3194337319491973
+ 2.319520886691595
+ 2.3196080369557084
+ 2.319695182742161
+ 2.319782324051576
+ 2.319869460884579
+ 2.3199565932417947
+ 2.320043721123845
+ 2.3201308445313558
+ 2.320217963464949
+ 2.3203050779252496
+ 2.3203921879128804
+ 2.3204792934284644
+ 2.3205663944726242
+ 2.3206534910459844
+ 2.3207405831491665
+ 2.3208276707827937
+ 2.3209147539474886
+ 2.321001832643873
+ 2.32108890687257
+ 2.321175976634201
+ 2.3212630419293885
+ 2.3213501027587538
+ 2.321437159122919
+ 2.3215242110225054
+ 2.3216112584581348
+ 2.321698301430428
+ 2.321785339940007
+ 2.321872373987491
+ 2.321959403573503
+ 2.322046428698662
+ 2.3221334493635895
+ 2.322220465568906
+ 2.322307477315231
+ 2.322394484603185
+ 2.322481487433388
+ 2.322568485806461
+ 2.322655479723022
+ 2.3227424691836904
+ 2.3228294541890873
+ 2.322916434739831
+ 2.323003410836541
+ 2.323090382479836
+ 2.3231773496703356
+ 2.3232643124086576
+ 2.323351270695421
+ 2.3234382245312437
+ 2.323525173916745
+ 2.3236121188525427
+ 2.3236990593392544
+ 2.3237859953774986
+ 2.323872926967893
+ 2.323959854111054
+ 2.324046776807601
+ 2.3241336950581504
+ 2.3242206088633193
+ 2.3243075182237245
+ 2.3243944231399842
+ 2.3244813236127135
+ 2.3245682196425297
+ 2.3246551112300495
+ 2.3247419983758895
+ 2.3248288810806654
+ 2.324915759344994
+ 2.3250026331694897
+ 2.32508950255477
+ 2.325176367501449
+ 2.3252632280101437
+ 2.3253500840814687
+ 2.3254369357160396
+ 2.325523782914471
+ 2.325610625677379
+ 2.3256974640053762
+ 2.3257842978990797
+ 2.325871127359103
+ 2.32595795238606
+ 2.3260447729805658
+ 2.326131589143234
+ 2.326218400874679
+ 2.3263052081755147
+ 2.3263920110463543
+ 2.3264788094878117
+ 2.3265656035005002
+ 2.3266523930850336
+ 2.326739178242024
+ 2.3268259589720857
+ 2.326912735275831
+ 2.326999507153872
+ 2.327086274606822
+ 2.3271730376352937
+ 2.327259796239899
+ 2.3273465504212507
+ 2.3274333001799596
+ 2.3275200455166383
+ 2.3276067864318994
+ 2.327693522926353
+ 2.327780255000612
+ 2.3278669826552867
+ 2.327953705890989
+ 2.32804042470833
+ 2.32812713910792
+ 2.3282138490903703
+ 2.3283005546562916
+ 2.328387255806294
+ 2.3284739525409885
+ 2.3285606448609855
+ 2.3286473327668937
+ 2.328734016259325
+ 2.3288206953388877
+ 2.3289073700061924
+ 2.3289940402618488
+ 2.329080706106465
+ 2.329167367540652
+ 2.329254024565018
+ 2.3293406771801726
+ 2.3294273253867237
+ 2.329513969185281
+ 2.3296006085764525
+ 2.3296872435608473
+ 2.329773874139073
+ 2.3298605003117387
+ 2.329947122079451
+ 2.3300337394428197
+ 2.3301203524024516
+ 2.330206960958954
+ 2.3302935651129353
+ 2.3303801648650024
+ 2.3304667602157623
+ 2.3305533511658223
+ 2.33063993771579
+ 2.3307265198662708
+ 2.3308130976178725
+ 2.3308996709712018
+ 2.330986239926865
+ 2.3310728044854674
+ 2.331159364647616
+ 2.3312459204139167
+ 2.3313324717849757
+ 2.331419018761398
+ 2.33150556134379
+ 2.331592099532757
+ 2.3316786333289037
+ 2.3317651627328355
+ 2.3318516877451585
+ 2.331938208366476
+ 2.332024724597394
+ 2.3321112364385166
+ 2.3321977438904486
+ 2.332284246953794
+ 2.3323707456291576
+ 2.332457239917143
+ 2.3325437298183544
+ 2.3326302153333955
+ 2.3327166964628705
+ 2.332803173207382
+ 2.3328896455675348
+ 2.332976113543931
+ 2.3330625771371736
+ 2.333149036347867
+ 2.3332354911766133
+ 2.3333219416240145
+ 2.3334083876906746
+ 2.3334948293771953
+ 2.3335812666841793
+ 2.3336676996122283
+ 2.333754128161945
+ 2.3338405523339305
+ 2.3339269721287876
+ 2.3340133875471176
+ 2.3340997985895218
+ 2.3341862052566014
+ 2.3342726075489586
+ 2.3343590054671934
+ 2.334445399011908
+ 2.334531788183702
+ 2.3346181729831774
+ 2.334704553410934
+ 2.334790929467572
+ 2.3348773011536927
+ 2.3349636684698956
+ 2.3350500314167806
+ 2.335136389994948
+ 2.3352227442049975
+ 2.335309094047529
+ 2.3353954395231415
+ 2.335481780632435
+ 2.3355681173760083
+ 2.3356544497544602
+ 2.3357407777683905
+ 2.3358271014183978
+ 2.3359134207050807
+ 2.3359997356290374
+ 2.336086046190867
+ 2.3361723523911677
+ 2.3362586542305372
+ 2.336344951709574
+ 2.3364312448288755
+ 2.3365175335890402
+ 2.3366038179906656
+ 2.3366900980343486
+ 2.3367763737206872
+ 2.336862645050278
+ 2.336948912023719
+ 2.3370351746416063
+ 2.3371214329045378
+ 2.337207686813109
+ 2.3372939363679173
+ 2.337380181569559
+ 2.33746642241863
+ 2.3375526589157265
+ 2.337638891061445
+ 2.3377251188563815
+ 2.3378113423011313
+ 2.3378975613962902
+ 2.337983776142454
+ 2.3380699865402175
+ 2.3381561925901764
+ 2.3382423942929256
+ 2.3383285916490606
+ 2.338414784659175
+ 2.3385009733238653
+ 2.3385871576437243
+ 2.338673337619348
+ 2.3387595132513295
+ 2.338845684540263
+ 2.3389318514867434
+ 2.3390180140913643
+ 2.3391041723547192
+ 2.3391903262774023
+ 2.339276475860007
+ 2.3393626211031258
+ 2.3394487620073523
+ 2.3395348985732807
+ 2.3396210308015033
+ 2.339707158692612
+ 2.339793282247201
+ 2.339879401465862
+ 2.339965516349188
+ 2.340051626897772
+ 2.3401377331122037
+ 2.3402238349930777
+ 2.340309932540985
+ 2.340396025756517
+ 2.340482114640266
+ 2.340568199192823
+ 2.34065427941478
+ 2.3407403553067274
+ 2.3408264268692576
+ 2.3409124941029607
+ 2.3409985570084277
+ 2.34108461558625
+ 2.341170669837017
+ 2.34125671976132
+ 2.341342765359749
+ 2.3414288066328948
+ 2.341514843581347
+ 2.341600876205696
+ 2.341686904506531
+ 2.3417729284844424
+ 2.3418589481400187
+ 2.3419449634738503
+ 2.3420309744865264
+ 2.342116981178636
+ 2.342202983550768
+ 2.3422889816035113
+ 2.3423749753374548
+ 2.3424609647531875
+ 2.342546949851297
+ 2.342632930632373
+ 2.3427189070970025
+ 2.3428048792457745
+ 2.342890847079276
+ 2.342976810598096
+ 2.3430627698028217
+ 2.3431487246940406
+ 2.3432346752723405
+ 2.3433206215383087
+ 2.343406563492532
+ 2.3434925011355974
+ 2.343578434468093
+ 2.343664363490604
+ 2.3437502882037182
+ 2.343836208608022
+ 2.3439221247041018
+ 2.3440080364925437
+ 2.3440939439739332
+ 2.3441798471488577
+ 2.3442657460179026
+ 2.3443516405816536
+ 2.3444375308406964
+ 2.344523416795616
+ 2.3446092984469984
+ 2.344695175795429
+ 2.3447810488414924
+ 2.3448669175857737
+ 2.344952782028858
+ 2.3450386421713296
+ 2.345124498013774
+ 2.3452103495567744
+ 2.3452961968009163
+ 2.345382039746784
+ 2.3454678783949605
+ 2.34555371274603
+ 2.3456395428005767
+ 2.3457253685591843
+ 2.345811190022437
+ 2.3458970071909175
+ 2.3459828200652084
+ 2.3460686286458943
+ 2.3461544329335577
+ 2.3462402329287806
+ 2.3463260286321477
+ 2.34641182004424
+ 2.346497607165641
+ 2.3465833899969324
+ 2.3466691685386976
+ 2.346754942791517
+ 2.3468407127559745
+ 2.3469264784326507
+ 2.347012239822128
+ 2.3470979969249877
+ 2.347183749741811
+ 2.3472694982731803
+ 2.347355242519676
+ 2.3474409824818796
+ 2.3475267181603723
+ 2.3476124495557342
+ 2.3476981766685467
+ 2.3477838994993903
+ 2.3478696180488448
+ 2.347955332317492
+ 2.3480410423059106
+ 2.3481267480146815
+ 2.348212449444385
+ 2.3482981465956
+ 2.3483838394689065
+ 2.3484695280648844
+ 2.3485552123841127
+ 2.3486408924271713
+ 2.3487265681946394
+ 2.3488122396870956
+ 2.348897906905119
+ 2.3489835698492887
+ 2.3490692285201824
+ 2.34915488291838
+ 2.3492405330444592
+ 2.3493261788989988
+ 2.349411820482576
+ 2.3494974577957697
+ 2.349583090839157
+ 2.349668719613317
+ 2.3497543441188267
+ 2.3498399643562635
+ 2.3499255803262042
+ 2.3500111920292275
+ 2.3500967994659097
+ 2.350182402636827
+ 2.3502680015425583
+ 2.350353596183679
+ 2.350439186560766
+ 2.3505247726743956
+ 2.3506103545251453
+ 2.35069593211359
+ 2.3507815054403065
+ 2.3508670745058704
+ 2.350952639310858
+ 2.351038199855845
+ 2.3511237561414067
+ 2.351209308168119
+ 2.351294855936557
+ 2.3513803994472964
+ 2.351465938700912
+ 2.3515514736979783
+ 2.351637004439071
+ 2.3517225309247647
+ 2.3518080531556333
+ 2.351893571132252
+ 2.3519790848551954
+ 2.3520645943250367
+ 2.3521500995423508
+ 2.3522356005077114
+ 2.352321097221693
+ 2.352406589684868
+ 2.3524920778978107
+ 2.352577561861095
+ 2.352663041575294
+ 2.352748517040981
+ 2.3528339882587286
+ 2.3529194552291104
+ 2.353004917952699
+ 2.3530903764300666
+ 2.3531758306617863
+ 2.3532612806484305
+ 2.353346726390572
+ 2.353432167888782
+ 2.3535176051436335
+ 2.3536030381556983
+ 2.353688466925548
+ 2.3537738914537547
+ 2.353859311740889
+ 2.3539447277875234
+ 2.354030139594229
+ 2.3541155471615762
+ 2.354200950490138
+ 2.3542863495804833
+ 2.3543717444331835
+ 2.3544571350488104
+ 2.354542521427933
+ 2.354627903571123
+ 2.35471328147895
+ 2.3547986551519844
+ 2.3548840245907967
+ 2.3549693897959565
+ 2.3550547507680335
+ 2.355140107507597
+ 2.355225460015218
+ 2.3553108082914647
+ 2.3553961523369065
+ 2.3554814921521134
+ 2.3555668277376536
+ 2.3556521590940966
+ 2.355737486222011
+ 2.355822809121966
+ 2.3559081277945295
+ 2.3559934422402704
+ 2.3560787524597564
+ 2.3561640584535564
+ 2.3562493602222383
+ 2.35633465776637
+ 2.3564199510865196
+ 2.356505240183254
+ 2.356590525057142
+ 2.35667580570875
+ 2.3567610821386458
+ 2.3568463543473963
+ 2.356931622335569
+ 2.357016886103731
+ 2.3571021456524486
+ 2.3571874009822884
+ 2.357272652093818
+ 2.357357898987603
+ 2.3574431416642097
+ 2.3575283801242053
+ 2.357613614368154
+ 2.357698844396624
+ 2.3577840702101796
+ 2.357869291809387
+ 2.3579545091948115
+ 2.3580397223670198
+ 2.358124931326576
+ 2.3582101360740446
+ 2.3582953366099932
+ 2.3583805329349845
+ 2.3584657250495846
+ 2.3585509129543576
+ 2.3586360966498683
+ 2.3587212761366816
+ 2.358806451415361
+ 2.3588916224864716
+ 2.358976789350577
+ 2.3590619520082416
+ 2.3591471104600283
+ 2.359232264706502
+ 2.359317414748226
+ 2.359402560585764
+ 2.359487702219678
+ 2.359572839650533
+ 2.359657972878891
+ 2.3597431019053157
+ 2.3598282267303703
+ 2.3599133473546163
+ 2.359998463778617
+ 2.360083576002935
+ 2.3601686840281326
+ 2.3602537878547722
+ 2.3603388874834157
+ 2.3604239829146256
+ 2.360509074148963
+ 2.3605941611869903
+ 2.3606792440292694
+ 2.360764322676361
+ 2.3608493971288262
+ 2.3609344673872283
+ 2.3610195334521267
+ 2.361104595324083
+ 2.3611896530036574
+ 2.361274706491412
+ 2.3613597557879067
+ 2.361444800893702
+ 2.3615298418093587
+ 2.3616148785354367
+ 2.3616999110724963
+ 2.3617849394210984
+ 2.361869963581801
+ 2.3619549835551656
+ 2.362039999341752
+ 2.3621250109421186
+ 2.362210018356825
+ 2.362295021586432
+ 2.362380020631497
+ 2.36246501549258
+ 2.36255000617024
+ 2.3626349926650354
+ 2.362719974977525
+ 2.3628049531082684
+ 2.3628899270578225
+ 2.362974896826747
+ 2.3630598624155987
+ 2.3631448238249373
+ 2.36322978105532
+ 2.3633147341073046
+ 2.363399682981449
+ 2.363484627678311
+ 2.3635695681984474
+ 2.363654504542416
+ 2.363739436710775
+ 2.36382436470408
+ 2.3639092885228887
+ 2.3639942081677585
+ 2.3640791236392453
+ 2.3641640349379065
+ 2.3642489420642976
+ 2.3643338450189764
+ 2.364418743802498
+ 2.364503638415419
+ 2.364588528858296
+ 2.3646734151316844
+ 2.36475829723614
+ 2.364843175172218
+ 2.364928048940475
+ 2.365012918541466
+ 2.365097783975746
+ 2.3651826452438707
+ 2.365267502346395
+ 2.3653523552838736
+ 2.365437204056862
+ 2.3655220486659143
+ 2.365606889111585
+ 2.365691725394429
+ 2.365776557515001
+ 2.3658613854738544
+ 2.3659462092715433
+ 2.3660310289086226
+ 2.3661158443856456
+ 2.3662006557031665
+ 2.3662854628617382
+ 2.3663702658619146
+ 2.3664550647042493
+ 2.3665398593892952
+ 2.3666246499176053
+ 2.366709436289734
+ 2.3667942185062323
+ 2.366878996567654
+ 2.366963770474552
+ 2.367048540227478
+ 2.3671333058269854
+ 2.367218067273626
+ 2.3673028245679517
+ 2.3673875777105153
+ 2.367472326701869
+ 2.367557071542563
+ 2.3676418122331513
+ 2.367726548774183
+ 2.3678112811662113
+ 2.3678960094097876
+ 2.3679807335054623
+ 2.3680654534537866
+ 2.368150169255313
+ 2.3682348809105895
+ 2.3683195884201695
+ 2.368404291784602
+ 2.3684889910044395
+ 2.36857368608023
+ 2.368658377012525
+ 2.3687430638018747
+ 2.3688277464488294
+ 2.368912424953938
+ 2.3689970993177516
+ 2.369081769540819
+ 2.36916643562369
+ 2.369251097566914
+ 2.3693357553710404
+ 2.369420409036618
+ 2.369505058564197
+ 2.369589703954325
+ 2.3696743452075526
+ 2.3697589823244267
+ 2.369843615305497
+ 2.3699282441513114
+ 2.370012868862419
+ 2.370097489439367
+ 2.370182105882705
+ 2.3702667181929793
+ 2.3703513263707396
+ 2.3704359304165323
+ 2.3705205303309063
+ 2.370605126114408
+ 2.3706897177675854
+ 2.3707743052909853
+ 2.370858888685156
+ 2.370943467950643
+ 2.371028043087995
+ 2.371112614097757
+ 2.3711971809804777
+ 2.371281743736702
+ 2.3713663023669778
+ 2.37145085687185
+ 2.3715354072518666
+ 2.371619953507572
+ 2.3717044956395132
+ 2.3717890336482363
+ 2.3718735675342866
+ 2.3719580972982093
+ 2.3720426229405507
+ 2.372127144461856
+ 2.372211661862671
+ 2.37229617514354
+ 2.3723806843050084
+ 2.372465189347621
+ 2.3725496902719234
+ 2.37263418707846
+ 2.372718679767775
+ 2.3728031683404125
+ 2.372887652796918
+ 2.3729721331378353
+ 2.3730566093637075
+ 2.373141081475081
+ 2.3732255494724974
+ 2.3733100133565013
+ 2.373394473127637
+ 2.3734789287864473
+ 2.3735633803334757
+ 2.3736478277692656
+ 2.37373227109436
+ 2.3738167103093026
+ 2.373901145414635
+ 2.373985576410902
+ 2.374070003298645
+ 2.3741544260784067
+ 2.3742388447507308
+ 2.3743232593161574
+ 2.3744076697752314
+ 2.3744920761284924
+ 2.3745764783764844
+ 2.374660876519748
+ 2.374745270558826
+ 2.3748296604942594
+ 2.3749140463265896
+ 2.374998428056359
+ 2.3750828056841082
+ 2.3751671792103783
+ 2.3752515486357115
+ 2.3753359139606474
+ 2.375420275185727
+ 2.375504632311492
+ 2.3755889853384824
+ 2.3756733342672387
+ 2.3757576790983013
+ 2.3758420198322105
+ 2.3759263564695066
+ 2.3760106890107298
+ 2.3760950174564193
+ 2.3761793418071155
+ 2.3762636620633586
+ 2.376347978225687
+ 2.376432290294641
+ 2.37651659827076
+ 2.3766009021545824
+ 2.3766852019466485
+ 2.3767694976474965
+ 2.376853789257665
+ 2.3769380767776935
+ 2.377022360208121
+ 2.3771066395494844
+ 2.377190914802324
+ 2.3772751859671764
+ 2.377359453044581
+ 2.3774437160350756
+ 2.3775279749391984
+ 2.3776122297574864
+ 2.3776964804904783
+ 2.3777807271387115
+ 2.3778649697027228
+ 2.3779492081830504
+ 2.378033442580231
+ 2.3781176728948017
+ 2.3782018991273004
+ 2.3782861212782636
+ 2.3783703393482276
+ 2.3784545533377295
+ 2.3785387632473056
+ 2.3786229690774934
+ 2.378707170828828
+ 2.3787913685018456
+ 2.3788755620970834
+ 2.378959751615076
+ 2.379043937056361
+ 2.379128118421473
+ 2.379212295710948
+ 2.3792964689253213
+ 2.3793806380651286
+ 2.3794648031309054
+ 2.379548964123186
+ 2.3796331210425063
+ 2.3797172738894017
+ 2.3798014226644058
+ 2.3798855673680537
+ 2.3799697080008806
+ 2.380053844563421
+ 2.3801379770562083
+ 2.380222105479778
+ 2.380306229834664
+ 2.3803903501213997
+ 2.380474466340519
+ 2.3805585784925567
+ 2.380642686578046
+ 2.3807267905975205
+ 2.3808108905515133
+ 2.380894986440558
+ 2.3809790782651885
+ 2.3810631660259376
+ 2.381147249723338
+ 2.381231329357922
+ 2.3813154049302234
+ 2.381399476440775
+ 2.3814835438901087
+ 2.3815676072787575
+ 2.3816516666072536
+ 2.3817357218761286
+ 2.381819773085916
+ 2.381903820237146
+ 2.3819878633303517
+ 2.382071902366065
+ 2.382155937344817
+ 2.382239968267139
+ 2.382323995133563
+ 2.3824080179446203
+ 2.382492036700842
+ 2.3825760514027587
+ 2.3826600620509026
+ 2.382744068645803
+ 2.382828071187992
+ 2.382912069677999
+ 2.382996064116356
+ 2.383080054503592
+ 2.3831640408402386
+ 2.383248023126825
+ 2.3833320013638812
+ 2.3834159755519377
+ 2.383499945691524
+ 2.38358391178317
+ 2.3836678738274055
+ 2.38375183182476
+ 2.3838357857757626
+ 2.3839197356809425
+ 2.384003681540829
+ 2.3840876233559514
+ 2.3841715611268386
+ 2.384255494854019
+ 2.384339424538022
+ 2.384423350179375
+ 2.3845072717786078
+ 2.384591189336248
+ 2.3846751028528246
+ 2.384759012328865
+ 2.3848429177648973
+ 2.38492681916145
+ 2.38501071651905
+ 2.3850946098382266
+ 2.3851784991195055
+ 2.3852623843634153
+ 2.385346265570483
+ 2.385430142741236
+ 2.385514015876201
+ 2.385597884975906
+ 2.385681750040877
+ 2.385765611071641
+ 2.385849468068725
+ 2.385933321032655
+ 2.3860171699639583
+ 2.386101014863161
+ 2.386184855730789
+ 2.386268692567368
+ 2.3863525253734252
+ 2.3864363541494855
+ 2.3865201788960753
+ 2.38660399961372
+ 2.386687816302945
+ 2.3867716289642766
+ 2.386855437598239
+ 2.386939242205359
+ 2.3870230427861596
+ 2.387106839341167
+ 2.387190631870906
+ 2.3872744203759018
+ 2.3873582048566786
+ 2.3874419853137607
+ 2.3875257617476735
+ 2.38760953415894
+ 2.3876933025480853
+ 2.387777066915634
+ 2.387860827262109
+ 2.387944583588035
+ 2.388028335893935
+ 2.3881120841803334
+ 2.388195828447753
+ 2.3882795686967184
+ 2.3883633049277524
+ 2.3884470371413777
+ 2.388530765338118
+ 2.388614489518496
+ 2.3886982096830347
+ 2.388781925832257
+ 2.3888656379666857
+ 2.388949346086843
+ 2.3890330501932513
+ 2.389116750286433
+ 2.3892004463669108
+ 2.3892841384352064
+ 2.389367826491842
+ 2.3894515105373393
+ 2.38953519057222
+ 2.389618866597006
+ 2.389702538612219
+ 2.38978620661838
+ 2.389869870616011
+ 2.3899535306056325
+ 2.390037186587766
+ 2.3901208385629324
+ 2.390204486531653
+ 2.390288130494448
+ 2.390371770451839
+ 2.3904554064043446
+ 2.3905390383524874
+ 2.3906226662967867
+ 2.390706290237763
+ 2.3907899101759362
+ 2.3908735261118266
+ 2.3909571380459544
+ 2.3910407459788385
+ 2.3911243499109998
+ 2.391207949842956
+ 2.3912915457752284
+ 2.3913751377083354
+ 2.391458725642797
+ 2.3915423095791315
+ 2.3916258895178584
+ 2.391709465459497
+ 2.3917930374045646
+ 2.3918766053535814
+ 2.391960169307066
+ 2.3920437292655357
+ 2.3921272852295097
+ 2.392210837199506
+ 2.392294385176043
+ 2.3923779291596383
+ 2.392461469150811
+ 2.3925450051500774
+ 2.392628537157956
+ 2.3927120651749636
+ 2.392795589201619
+ 2.392879109238439
+ 2.39296262528594
+ 2.393046137344641
+ 2.3931296454150575
+ 2.393213149497707
+ 2.393296649593106
+ 2.393380145701772
+ 2.3934636378242207
+ 2.3935471259609695
+ 2.3936306101125333
+ 2.3937140902794303
+ 2.3937975664621756
+ 2.3938810386612857
+ 2.3939645068772757
+ 2.3940479711106626
+ 2.3941314313619615
+ 2.3942148876316884
+ 2.394298339920358
+ 2.394381788228487
+ 2.3944652325565894
+ 2.394548672905181
+ 2.3946321092747773
+ 2.3947155416658927
+ 2.3947989700790417
+ 2.3948823945147404
+ 2.394965814973502
+ 2.395049231455842
+ 2.3951326439622744
+ 2.395216052493314
+ 2.3952994570494743
+ 2.39538285763127
+ 2.3954662542392153
+ 2.395549646873823
+ 2.395633035535608
+ 2.395716420225084
+ 2.3957998009427626
+ 2.3958831776891603
+ 2.395966550464788
+ 2.3960499192701605
+ 2.39613328410579
+ 2.39621664497219
+ 2.3963000018698732
+ 2.3963833547993523
+ 2.3964667037611402
+ 2.39655004875575
+ 2.3966333897836933
+ 2.396716726845483
+ 2.3968000599416306
+ 2.3968833890726495
+ 2.3969667142390514
+ 2.3970500354413473
+ 2.3971333526800502
+ 2.3972166659556717
+ 2.397299975268722
+ 2.3973832806197146
+ 2.3974665820091596
+ 2.397549879437569
+ 2.3976331729054534
+ 2.3977164624133245
+ 2.3977997479616926
+ 2.3978830295510694
+ 2.397966307181965
+ 2.39804958085489
+ 2.3981328505703554
+ 2.3982161163288715
+ 2.3982993781309485
+ 2.398382635977097
+ 2.3984658898678264
+ 2.3985491398036474
+ 2.3986323857850698
+ 2.3987156278126025
+ 2.3987988658867567
+ 2.398882100008041
+ 2.398965330176965
+ 2.3990485563940385
+ 2.3991317786597697
+ 2.3992149969746692
+ 2.3992982113392447
+ 2.3993814217540064
+ 2.3994646282194627
+ 2.3995478307361213
+ 2.399631029304492
+ 2.399714223925083
+ 2.3997974145984022
+ 2.3998806013249587
+ 2.399963784105261
+ 2.400046962939815
+ 2.4001301378291315
+ 2.4002133087737167
+ 2.400296475774079
+ 2.4003796388307252
+ 2.400462797944164
+ 2.400545953114902
+ 2.400629104343447
+ 2.400712251630306
+ 2.400795394975986
+ 2.4008785343809946
+ 2.400961669845838
+ 2.401044801371024
+ 2.401127928957058
+ 2.401211052604447
+ 2.401294172313698
+ 2.4013772880853175
+ 2.401460399919811
+ 2.4015435078176854
+ 2.401626611779446
+ 2.4017097118055992
+ 2.4017928078966513
+ 2.4018759000531067
+ 2.4019589882754726
+ 2.402042072564253
+ 2.402125152919955
+ 2.402208229343083
+ 2.4022913018341416
+ 2.4023743703936375
+ 2.4024574350220744
+ 2.4025404957199576
+ 2.4026235524877917
+ 2.4027066053260824
+ 2.4027896542353324
+ 2.4028726992160476
+ 2.402955740268732
+ 2.4030387773938897
+ 2.4031218105920256
+ 2.4032048398636427
+ 2.4032878652092453
+ 2.4033708866293377
+ 2.403453904124423
+ 2.4035369176950057
+ 2.403619927341588
+ 2.4037029330646744
+ 2.403785934864768
+ 2.403868932742372
+ 2.4039519266979887
+ 2.404034916732122
+ 2.4041179028452753
+ 2.40420088503795
+ 2.4042838633106496
+ 2.4043668376638765
+ 2.404449808098133
+ 2.4045327746139216
+ 2.4046157372117447
+ 2.4046986958921046
+ 2.4047816506555035
+ 2.404864601502442
+ 2.4049475484334235
+ 2.4050304914489495
+ 2.4051134305495205
+ 2.405196365735639
+ 2.4052792970078065
+ 2.4053622243665242
+ 2.4054451478122925
+ 2.405528067345614
+ 2.405610982966988
+ 2.405693894676917
+ 2.4057768024759003
+ 2.40585970636444
+ 2.405942606343036
+ 2.406025502412189
+ 2.4061083945723984
+ 2.4061912828241656
+ 2.4062741671679904
+ 2.4063570476043727
+ 2.4064399241338132
+ 2.406522796756811
+ 2.406605665473866
+ 2.4066885302854777
+ 2.406771391192146
+ 2.4068542481943704
+ 2.4069371012926495
+ 2.407019950487483
+ 2.4071027957793705
+ 2.4071856371688103
+ 2.4072684746563016
+ 2.4073513082423434
+ 2.407434137927434
+ 2.4075169637120726
+ 2.407599785596757
+ 2.4076826035819856
+ 2.4077654176682572
+ 2.40784822785607
+ 2.4079310341459212
+ 2.4080138365383106
+ 2.408096635033734
+ 2.408179429632691
+ 2.408262220335677
+ 2.4083450071431916
+ 2.408427790055732
+ 2.4085105690737945
+ 2.4085933441978775
+ 2.4086761154284773
+ 2.4087588827660915
+ 2.4088416462112168
+ 2.40892440576435
+ 2.409007161425988
+ 2.4090899131966275
+ 2.4091726610767643
+ 2.4092554050668955
+ 2.4093381451675175
+ 2.409420881379127
+ 2.4095036137022183
+ 2.409586342137289
+ 2.4096690666848355
+ 2.4097517873453516
+ 2.4098345041193343
+ 2.4099172170072793
+ 2.4099999260096814
+ 2.4100826311270365
+ 2.41016533235984
+ 2.410248029708587
+ 2.410330723173772
+ 2.4104134127558905
+ 2.4104960984554373
+ 2.4105787802729073
+ 2.4106614582087946
+ 2.410744132263595
+ 2.410826802437802
+ 2.41090946873191
+ 2.4109921311464135
+ 2.4110747896818063
+ 2.411157444338583
+ 2.411240095117237
+ 2.411322742018263
+ 2.411405385042154
+ 2.4114880241894037
+ 2.4115706594605055
+ 2.4116532908559534
+ 2.4117359183762406
+ 2.41181854202186
+ 2.4119011617933053
+ 2.4119837776910686
+ 2.4120663897156436
+ 2.412148997867523
+ 2.4122316021471994
+ 2.412314202555166
+ 2.412396799091914
+ 2.412479391757937
+ 2.412561980553727
+ 2.4126445654797757
+ 2.4127271465365756
+ 2.4128097237246195
+ 2.412892297044398
+ 2.4129748664964037
+ 2.413057432081128
+ 2.4131399937990623
+ 2.4132225516506987
+ 2.4133051056365282
+ 2.413387655757042
+ 2.4134702020127317
+ 2.413552744404088
+ 2.413635282931602
+ 2.4137178175957645
+ 2.4138003483970665
+ 2.413882875335999
+ 2.4139653984130516
+ 2.4140479176287157
+ 2.414130432983481
+ 2.4142129444778386
+ 2.414295452112278
+ 2.4143779558872893
+ 2.414460455803363
+ 2.414542951860988
+ 2.4146254440606554
+ 2.414707932402854
+ 2.4147904168880734
+ 2.414872897516803
+ 2.4149553742895327
+ 2.415037847206751
+ 2.4151203162689474
+ 2.4152027814766113
+ 2.415285242830232
+ 2.415367700330297
+ 2.4154501539772957
+ 2.4155326037717173
+ 2.41561504971405
+ 2.4156974918047815
+ 2.4157799300444016
+ 2.4158623644333974
+ 2.4159447949722574
+ 2.41602722166147
+ 2.4161096445015224
+ 2.416192063492903
+ 2.4162744786360997
+ 2.4163568899316
+ 2.416439297379891
+ 2.4165217009814604
+ 2.4166041007367958
+ 2.4166864966463844
+ 2.416768888710713
+ 2.416851276930269
+ 2.416933661305539
+ 2.4170160418370097
+ 2.4170984185251685
+ 2.4171807913705017
+ 2.4172631603734964
+ 2.4173455255346377
+ 2.417427886854413
+ 2.4175102443333083
+ 2.41759259797181
+ 2.417674947770403
+ 2.4177572937295744
+ 2.41783963584981
+ 2.417921974131595
+ 2.4180043085754157
+ 2.4180866391817566
+ 2.418168965951104
+ 2.418251288883943
+ 2.418333607980759
+ 2.418415923242037
+ 2.4184982346682613
+ 2.4185805422599183
+ 2.4186628460174915
+ 2.418745145941467
+ 2.4188274420323275
+ 2.418909734290559
+ 2.418992022716646
+ 2.4190743073110728
+ 2.419156588074322
+ 2.41923886500688
+ 2.4193211381092294
+ 2.419403407381855
+ 2.41948567282524
+ 2.4195679344398684
+ 2.4196501922262237
+ 2.4197324461847893
+ 2.419814696316049
+ 2.419896942620486
+ 2.4199791850985837
+ 2.420061423750825
+ 2.4201436585776928
+ 2.42022588957967
+ 2.4203081167572407
+ 2.4203903401108855
+ 2.4204725596410888
+ 2.4205547753483323
+ 2.4206369872330993
+ 2.4207191952958707
+ 2.4208013995371296
+ 2.4208835999573584
+ 2.4209657965570384
+ 2.4210479893366523
+ 2.4211301782966816
+ 2.421212363437608
+ 2.4212945447599132
+ 2.4213767222640787
+ 2.4214588959505865
+ 2.421541065819917
+ 2.421623231872552
+ 2.421705394108973
+ 2.4217875525296595
+ 2.4218697071350945
+ 2.421951857925758
+ 2.4220340049021307
+ 2.422116148064693
+ 2.4221982874139254
+ 2.4222804229503088
+ 2.422362554674324
+ 2.42244468258645
+ 2.422526806687168
+ 2.4226089269769577
+ 2.4226910434562994
+ 2.4227731561256727
+ 2.422855264985557
+ 2.4229373700364323
+ 2.4230194712787783
+ 2.423101568713074
+ 2.4231836623397998
+ 2.4232657521594336
+ 2.423347838172456
+ 2.4234299203793452
+ 2.42351199878058
+ 2.42359407337664
+ 2.4236761441680033
+ 2.4237582111551492
+ 2.423840274338556
+ 2.4239223337187017
+ 2.424004389296066
+ 2.424086441071126
+ 2.42416848904436
+ 2.424250533216247
+ 2.4243325735872636
+ 2.424414610157889
+ 2.4244966429286006
+ 2.4245786718998756
+ 2.4246606970721922
+ 2.4247427184460277
+ 2.4248247360218596
+ 2.424906749800165
+ 2.4249887597814213
+ 2.4250707659661055
+ 2.425152768354695
+ 2.4252347669476664
+ 2.425316761745496
+ 2.4253987527486616
+ 2.425480739957639
+ 2.4255627233729053
+ 2.4256447029949366
+ 2.4257266788242093
+ 2.4258086508611996
+ 2.4258906191063834
+ 2.4259725835602373
+ 2.4260545442232373
+ 2.426136501095858
+ 2.426218454178577
+ 2.4263004034718687
+ 2.4263823489762095
+ 2.426464290692074
+ 2.4265462286199377
+ 2.4266281627602764
+ 2.426710093113565
+ 2.426792019680278
+ 2.426873942460891
+ 2.426955861455879
+ 2.427037776665717
+ 2.4271196880908787
+ 2.427201595731839
+ 2.4272834995890733
+ 2.427365399663055
+ 2.4274472959542583
+ 2.4275291884631582
+ 2.427611077190228
+ 2.427692962135943
+ 2.4277748433007753
+ 2.4278567206851998
+ 2.4279385942896905
+ 2.4280204641147196
+ 2.4281023301607623
+ 2.428184192428291
+ 2.428266050917779
+ 2.428347905629701
+ 2.428429756564528
+ 2.428511603722734
+ 2.4285934471047916
+ 2.428675286711175
+ 2.4287571225423554
+ 2.428838954598806
+ 2.4289207828809993
+ 2.4290026073894078
+ 2.429084428124504
+ 2.4291662450867593
+ 2.4292480582766474
+ 2.429329867694639
+ 2.429411673341207
+ 2.4294934752168222
+ 2.4295752733219573
+ 2.429657067657084
+ 2.4297388582226738
+ 2.429820645019198
+ 2.4299024280471277
+ 2.429984207306935
+ 2.43006598279909
+ 2.430147754524065
+ 2.4302295224823296
+ 2.4303112866743564
+ 2.4303930471006154
+ 2.430474803761577
+ 2.430556556657712
+ 2.430638305789491
+ 2.4307200511573845
+ 2.4308017927618635
+ 2.430883530603397
+ 2.4309652646824556
+ 2.4310469949995097
+ 2.431128721555029
+ 2.431210444349483
+ 2.4312921633833424
+ 2.431373878657076
+ 2.4314555901711543
+ 2.4315372979260452
+ 2.4316190019222197
+ 2.431700702160146
+ 2.431782398640294
+ 2.431864091363133
+ 2.431945780329131
+ 2.4320274655387575
+ 2.432109146992481
+ 2.4321908246907706
+ 2.432272498634095
+ 2.4323541688229224
+ 2.432435835257721
+ 2.4325174979389597
+ 2.4325991568671066
+ 2.4326808120426295
+ 2.432762463465997
+ 2.432844111137676
+ 2.4329257550581356
+ 2.433007395227843
+ 2.4330890316472655
+ 2.433170664316872
+ 2.433252293237128
+ 2.4333339184085023
+ 2.433415539831462
+ 2.4334971575064737
+ 2.433578771434005
+ 2.433660381614523
+ 2.433741988048494
+ 2.4338235907363854
+ 2.4339051896786636
+ 2.4339867848757955
+ 2.4340683763282476
+ 2.434149964036486
+ 2.4342315480009766
+ 2.434313128222187
+ 2.4343947047005825
+ 2.4344762774366293
+ 2.4345578464307933
+ 2.43463941168354
+ 2.4347209731953354
+ 2.4348025309666457
+ 2.4348840849979365
+ 2.434965635289672
+ 2.4350471818423194
+ 2.4351287246563422
+ 2.435210263732207
+ 2.4352917990703777
+ 2.435373330671321
+ 2.4354548585355
+ 2.4355363826633805
+ 2.435617903055427
+ 2.435699419712104
+ 2.435780932633876
+ 2.4358624418212083
+ 2.4359439472745645
+ 2.4360254489944086
+ 2.436106946981205
+ 2.436188441235419
+ 2.4362699317575123
+ 2.4363514185479502
+ 2.4364329016071964
+ 2.4365143809357144
+ 2.436595856533968
+ 2.4366773284024204
+ 2.4367587965415347
+ 2.436840260951775
+ 2.436921721633604
+ 2.4370031785874855
+ 2.437084631813881
+ 2.437166081313255
+ 2.43724752708607
+ 2.4373289691327886
+ 2.4374104074538736
+ 2.437491842049787
+ 2.437573272920992
+ 2.4376547000679505
+ 2.4377361234911246
+ 2.437817543190977
+ 2.43789895916797
+ 2.4379803714225647
+ 2.4380617799552238
+ 2.438143184766409
+ 2.4382245858565814
+ 2.438305983226203
+ 2.438387376875736
+ 2.4384687668056406
+ 2.43855015301638
+ 2.438631535508413
+ 2.438712914282203
+ 2.43879428933821
+ 2.4388756606768944
+ 2.4389570282987183
+ 2.4390383922041416
+ 2.439119752393626
+ 2.439201108867631
+ 2.4392824616266178
+ 2.4393638106710465
+ 2.4394451560013772
+ 2.4395264976180706
+ 2.439607835521587
+ 2.439689169712386
+ 2.4397705001909276
+ 2.4398518269576717
+ 2.439933150013078
+ 2.4400144693576062
+ 2.4400957849917164
+ 2.4401770969158676
+ 2.440258405130519
+ 2.44033970963613
+ 2.4404210104331607
+ 2.4405023075220686
+ 2.440583600903314
+ 2.4406648905773554
+ 2.4407461765446516
+ 2.4408274588056615
+ 2.4409087373608434
+ 2.4409900122106567
+ 2.4410712833555586
+ 2.441152550796008
+ 2.441233814532464
+ 2.4413150745653835
+ 2.441396330895226
+ 2.4414775835224485
+ 2.441558832447509
+ 2.4416400776708658
+ 2.441721319192976
+ 2.4418025570142974
+ 2.4418837911352873
+ 2.4419650215564044
+ 2.4420462482781047
+ 2.4421274713008456
+ 2.4422086906250855
+ 2.44228990625128
+ 2.442371118179887
+ 2.4424523264113627
+ 2.442533530946165
+ 2.4426147317847495
+ 2.4426959289275727
+ 2.4427771223750927
+ 2.4428583121277643
+ 2.442939498186045
+ 2.4430206805503896
+ 2.443101859221256
+ 2.4431830341990985
+ 2.4432642054843745
+ 2.44334537307754
+ 2.443426536979049
+ 2.4435076971893595
+ 2.4435888537089254
+ 2.443670006538203
+ 2.443751155677647
+ 2.4438323011277143
+ 2.4439134428888583
+ 2.4439945809615353
+ 2.4440757153462003
+ 2.444156846043308
+ 2.444237973053313
+ 2.4443190963766703
+ 2.4444002160138347
+ 2.4444813319652607
+ 2.444562444231403
+ 2.444643552812716
+ 2.444724657709654
+ 2.444805758922671
+ 2.4448868564522215
+ 2.444967950298759
+ 2.445049040462738
+ 2.445130126944613
+ 2.445211209744836
+ 2.445292288863862
+ 2.4453733643021436
+ 2.445454436060136
+ 2.445535504138291
+ 2.445616568537063
+ 2.4456976292569044
+ 2.4457786862982687
+ 2.445859739661609
+ 2.445940789347378
+ 2.4460218353560292
+ 2.4461028776880145
+ 2.446183916343787
+ 2.4462649513238
+ 2.446345982628505
+ 2.4464270102583545
+ 2.4465080342138013
+ 2.4465890544952975
+ 2.446670071103295
+ 2.446751084038246
+ 2.446832093300603
+ 2.4469130988908168
+ 2.4469941008093397
+ 2.4470750990566232
+ 2.447156093633119
+ 2.4472370845392795
+ 2.447318071775555
+ 2.447399055342397
+ 2.447480035240257
+ 2.4475610114695865
+ 2.4476419840308354
+ 2.447722952924455
+ 2.4478039181508975
+ 2.447884879710612
+ 2.4479658376040505
+ 2.448046791831663
+ 2.4481277423938996
+ 2.448208689291211
+ 2.448289632524048
+ 2.4483705720928604
+ 2.4484515079980986
+ 2.4485324402402124
+ 2.448613368819652
+ 2.448694293736867
+ 2.4487752149923074
+ 2.448856132586423
+ 2.448937046519663
+ 2.4490179567924777
+ 2.449098863405316
+ 2.4491797663586263
+ 2.4492606656528597
+ 2.4493415612884646
+ 2.4494224532658895
+ 2.449503341585584
+ 2.4495842262479965
+ 2.4496651072535762
+ 2.449745984602772
+ 2.4498268582960323
+ 2.4499077283338053
+ 2.4499885947165394
+ 2.450069457444684
+ 2.450150316518686
+ 2.4502311719389946
+ 2.4503120237060574
+ 2.4503928718203225
+ 2.4504737162822376
+ 2.450554557092251
+ 2.45063539425081
+ 2.450716227758362
+ 2.4507970576153553
+ 2.450877883822237
+ 2.450958706379454
+ 2.451039525287454
+ 2.4511203405466846
+ 2.451201152157592
+ 2.4512819601206237
+ 2.4513627644362272
+ 2.451443565104848
+ 2.4515243621269343
+ 2.4516051555029312
+ 2.4516859452332866
+ 2.4517667313184464
+ 2.4518475137588567
+ 2.451928292554965
+ 2.4520090677072157
+ 2.452089839216056
+ 2.452170607081932
+ 2.4522513713052896
+ 2.4523321318865743
+ 2.4524128888262315
+ 2.452493642124708
+ 2.452574391782448
+ 2.4526551377998986
+ 2.4527358801775043
+ 2.45281661891571
+ 2.452897354014962
+ 2.452978085475704
+ 2.4530588132983824
+ 2.453139537483442
+ 2.4532202580313265
+ 2.4533009749424823
+ 2.4533816882173527
+ 2.4534623978563834
+ 2.4535431038600177
+ 2.453623806228701
+ 2.453704504962878
+ 2.453785200062992
+ 2.4538658915294866
+ 2.4539465793628077
+ 2.454027263563398
+ 2.4541079441317017
+ 2.4541886210681634
+ 2.4542692943732254
+ 2.454349964047332
+ 2.4544306300909264
+ 2.4545112925044528
+ 2.454591951288354
+ 2.454672606443074
+ 2.4547532579690547
+ 2.45483390586674
+ 2.4549145501365732
+ 2.4549951907789964
+ 2.4550758277944533
+ 2.455156461183386
+ 2.455237090946237
+ 2.45531771708345
+ 2.455398339595466
+ 2.455478958482728
+ 2.4555595737456795
+ 2.4556401853847607
+ 2.455720793400416
+ 2.455801397793085
+ 2.4558819985632105
+ 2.4559625957112354
+ 2.4560431892376005
+ 2.4561237791427475
+ 2.4562043654271184
+ 2.456284948091154
+ 2.456365527135297
+ 2.456446102559988
+ 2.456526674365668
+ 2.4566072425527787
+ 2.45668780712176
+ 2.4567683680730545
+ 2.456848925407103
+ 2.456929479124345
+ 2.4570100292252213
+ 2.4570905757101738
+ 2.4571711185796423
+ 2.457251657834067
+ 2.457332193473889
+ 2.4574127254995486
+ 2.457493253911485
+ 2.4575737787101395
+ 2.457654299895951
+ 2.45773481746936
+ 2.4578153314308064
+ 2.45789584178073
+ 2.457976348519571
+ 2.458056851647768
+ 2.4581373511657603
+ 2.458217847073988
+ 2.4582983393728908
+ 2.458378828062907
+ 2.458459313144476
+ 2.458539794618038
+ 2.4586202724840303
+ 2.4587007467428927
+ 2.4587812173950643
+ 2.4588616844409827
+ 2.458942147881088
+ 2.4590226077158164
+ 2.459103063945609
+ 2.459183516570903
+ 2.4592639655921364
+ 2.4593444110097478
+ 2.459424852824175
+ 2.459505291035857
+ 2.45958572564523
+ 2.459666156652734
+ 2.4597465840588044
+ 2.4598270078638804
+ 2.4599074280683992
+ 2.4599878446727983
+ 2.4600682576775155
+ 2.4601486670829877
+ 2.460229072889652
+ 2.4603094750979464
+ 2.4603898737083068
+ 2.46047026872117
+ 2.460550660136975
+ 2.460631047956156
+ 2.4607114321791514
+ 2.4607918128063977
+ 2.4608721898383306
+ 2.4609525632753875
+ 2.461032933118004
+ 2.461113299366617
+ 2.461193662021662
+ 2.4612740210835757
+ 2.461354376552794
+ 2.4614347284297535
+ 2.4615150767148886
+ 2.461595421408636
+ 2.4616757625114314
+ 2.46175610002371
+ 2.461836433945907
+ 2.461916764278459
+ 2.4619970910218005
+ 2.4620774141763673
+ 2.4621577337425937
+ 2.4622380497209155
+ 2.4623183621117675
+ 2.4623986709155847
+ 2.4624789761328016
+ 2.462559277763853
+ 2.4626395758091735
+ 2.4627198702691984
+ 2.4628001611443615
+ 2.4628804484350972
+ 2.46296073214184
+ 2.463041012265024
+ 2.4631212888050835
+ 2.4632015617624528
+ 2.463281831137565
+ 2.4633620969308545
+ 2.4634423591427552
+ 2.4635226177737004
+ 2.463602872824124
+ 2.4636831242944597
+ 2.4637633721851406
+ 2.4638436164966
+ 2.4639238572292723
+ 2.464004094383589
+ 2.464084327959984
+ 2.464164557958891
+ 2.4642447843807416
+ 2.4643250072259697
+ 2.4644052264950074
+ 2.4644854421882876
+ 2.4645656543062437
+ 2.4646458628493066
+ 2.4647260678179097
+ 2.4648062692124855
+ 2.464886467033466
+ 2.464966661281283
+ 2.465046851956369
+ 2.465127039059156
+ 2.465207222590076
+ 2.4652874025495604
+ 2.465367578938041
+ 2.4654477517559505
+ 2.465527921003719
+ 2.4656080866817787
+ 2.4656882487905607
+ 2.465768407330496
+ 2.465848562302017
+ 2.4659287137055546
+ 2.466008861541539
+ 2.4660890058104017
+ 2.4661691465125735
+ 2.4662492836484855
+ 2.4663294172185672
+ 2.4664095472232512
+ 2.466489673662967
+ 2.466569796538144
+ 2.4666499158492146
+ 2.466730031596608
+ 2.4668101437807546
+ 2.4668902524020844
+ 2.4669703574610273
+ 2.4670504589580142
+ 2.4671305568934736
+ 2.4672106512678362
+ 2.4672907420815315
+ 2.467370829334989
+ 2.4674509130286384
+ 2.4675309931629092
+ 2.4676110697382305
+ 2.4676911427550317
+ 2.467771212213742
+ 2.4678512781147908
+ 2.4679313404586063
+ 2.4680113992456185
+ 2.4680914544762556
+ 2.4681715061509464
+ 2.46825155427012
+ 2.4683315988342045
+ 2.4684116398436284
+ 2.468491677298821
+ 2.4685717112002092
+ 2.468651741548223
+ 2.4687317683432894
+ 2.4688117915858365
+ 2.4688918112762925
+ 2.468971827415086
+ 2.469051840002644
+ 2.4691318490393943
+ 2.4692118545257657
+ 2.469291856462184
+ 2.469371854849078
+ 2.4694518496868745
+ 2.4695318409760016
+ 2.4696118287168853
+ 2.4696918129099545
+ 2.4697717935556343
+ 2.4698517706543535
+ 2.469931744206538
+ 2.470011714212615
+ 2.470091680673011
+ 2.4701716435881527
+ 2.470251602958467
+ 2.4703315587843804
+ 2.470411511066319
+ 2.4704914598047094
+ 2.470571404999977
+ 2.47065134665255
+ 2.470731284762852
+ 2.470811219331311
+ 2.470891150358352
+ 2.4709710778444007
+ 2.4710510017898835
+ 2.471130922195225
+ 2.471210839060852
+ 2.471290752387189
+ 2.4713706621746625
+ 2.4714505684236965
+ 2.471530471134718
+ 2.47161037030815
+ 2.471690265944419
+ 2.47177015804395
+ 2.471850046607168
+ 2.4719299316344965
+ 2.472009813126362
+ 2.4720896910831884
+ 2.4721695655054003
+ 2.472249436393422
+ 2.472329303747678
+ 2.4724091675685926
+ 2.4724890278565903
+ 2.472568884612095
+ 2.4726487378355313
+ 2.472728587527323
+ 2.4728084336878933
+ 2.4728882763176667
+ 2.4729681154170673
+ 2.4730479509865178
+ 2.473127783026443
+ 2.473207611537265
+ 2.4732874365194086
+ 2.473367257973296
+ 2.4734470758993514
+ 2.473526890297997
+ 2.4736067011696563
+ 2.473686508514753
+ 2.4737663123337095
+ 2.473846112626948
+ 2.473925909394892
+ 2.4740057026379647
+ 2.4740854923565876
+ 2.474165278551183
+ 2.4742450612221747
+ 2.474324840369984
+ 2.4744046159950335
+ 2.4744843880977454
+ 2.4745641566785417
+ 2.474643921737844
+ 2.4747236832760757
+ 2.474803441293657
+ 2.4748831957910107
+ 2.474962946768558
+ 2.4750426942267203
+ 2.47512243816592
+ 2.4752021785865774
+ 2.4752819154891146
+ 2.475361648873953
+ 2.4754413787415133
+ 2.475521105092217
+ 2.4756008279264847
+ 2.4756805472447376
+ 2.475760263047396
+ 2.4758399753348823
+ 2.4759196841076156
+ 2.475999389366017
+ 2.476079091110507
+ 2.4761587893415067
+ 2.476238484059435
+ 2.4763181752647134
+ 2.476397862957762
+ 2.4764775471390013
+ 2.4765572278088497
+ 2.4766369049677293
+ 2.476716578616058
+ 2.4767962487542565
+ 2.4768759153827453
+ 2.4769555785019426
+ 2.477035238112269
+ 2.477114894214143
+ 2.477194546807985
+ 2.4772741958942137
+ 2.4773538414732488
+ 2.477433483545509
+ 2.4775131221114135
+ 2.477592757171381
+ 2.477672388725831
+ 2.4777520167751814
+ 2.477831641319852
+ 2.4779112623602613
+ 2.477990879896827
+ 2.4780704939299683
+ 2.4781501044601035
+ 2.4782297114876513
+ 2.4783093150130284
+ 2.478388915036655
+ 2.478468511558948
+ 2.4785481045803257
+ 2.4786276941012058
+ 2.4787072801220065
+ 2.478786862643145
+ 2.4788664416650397
+ 2.478946017188108
+ 2.4790255892127666
+ 2.479105157739434
+ 2.4791847227685273
+ 2.4792642843004633
+ 2.4793438423356595
+ 2.4794233968745334
+ 2.479502947917501
+ 2.4795824954649803
+ 2.4796620395173874
+ 2.4797415800751397
+ 2.4798211171386537
+ 2.479900650708345
+ 2.479980180784632
+ 2.4800597073679302
+ 2.480139230458656
+ 2.480218750057225
+ 2.4802982661640547
+ 2.4803777787795607
+ 2.4804572879041586
+ 2.480536793538265
+ 2.4806162956822955
+ 2.480695794336666
+ 2.480775289501792
+ 2.480854781178089
+ 2.480934269365974
+ 2.4810137540658608
+ 2.4810932352781654
+ 2.4811727130033034
+ 2.4812521872416893
+ 2.4813316579937386
+ 2.481411125259867
+ 2.4814905890404884
+ 2.481570049336019
+ 2.481649506146873
+ 2.4817289594734646
+ 2.4818084093162094
+ 2.4818878556755215
+ 2.4819672985518153
+ 2.4820467379455056
+ 2.482126173857007
+ 2.4822056062867333
+ 2.4822850352350985
+ 2.482364460702517
+ 2.4824438826894033
+ 2.4825233011961707
+ 2.4826027162232336
+ 2.4826821277710054
+ 2.4827615358398996
+ 2.48284094043033
+ 2.482920341542711
+ 2.4829997391774548
+ 2.4830791333349755
+ 2.4831585240156864
+ 2.4832379112200003
+ 2.483317294948331
+ 2.483396675201091
+ 2.4834760519786934
+ 2.4835554252815517
+ 2.483634795110078
+ 2.4837141614646856
+ 2.4837935243457867
+ 2.483872883753794
+ 2.48395223968912
+ 2.4840315921521783
+ 2.484110941143379
+ 2.4841902866631362
+ 2.4842696287118615
+ 2.4843489672899666
+ 2.484428302397864
+ 2.4845076340359658
+ 2.484586962204684
+ 2.4846662869044294
+ 2.484745608135615
+ 2.484824925898651
+ 2.48490424019395
+ 2.4849835510219234
+ 2.4850628583829826
+ 2.4851421622775387
+ 2.4852214627060025
+ 2.485300759668786
+ 2.4853800531663
+ 2.4854593431989556
+ 2.4855386297671633
+ 2.485617912871334
+ 2.485697192511879
+ 2.4857764686892088
+ 2.4858557414037334
+ 2.4859350106558638
+ 2.4860142764460105
+ 2.4860935387745835
+ 2.4861727976419936
+ 2.4862520530486507
+ 2.4863313049949647
+ 2.4864105534813463
+ 2.4864897985082046
+ 2.4865690400759504
+ 2.486648278184993
+ 2.486727512835742
+ 2.4868067440286072
+ 2.4868859717639986
+ 2.486965196042325
+ 2.4870444168639967
+ 2.487123634229422
+ 2.4872028481390105
+ 2.4872820585931716
+ 2.4873612655923143
+ 2.4874404691368475
+ 2.48751966922718
+ 2.487598865863722
+ 2.48767805904688
+ 2.4877572487770645
+ 2.487836435054683
+ 2.487915617880145
+ 2.4879947972538585
+ 2.4880739731762316
+ 2.4881531456476726
+ 2.4882323146685907
+ 2.488311480239393
+ 2.4883906423604882
+ 2.4884698010322843
+ 2.4885489562551886
+ 2.4886281080296095
+ 2.488707256355954
+ 2.4887864012346306
+ 2.488865542666047
+ 2.4889446806506097
+ 2.489023815188727
+ 2.489102946280806
+ 2.489182073927254
+ 2.489261198128479
+ 2.489340318884887
+ 2.4894194361968847
+ 2.4894985500648805
+ 2.48957766048928
+ 2.489656767470491
+ 2.4897358710089197
+ 2.489814971104973
+ 2.489894067759057
+ 2.4899731609715787
+ 2.4900522507429446
+ 2.490131337073561
+ 2.4902104199638333
+ 2.4902894994141684
+ 2.4903685754249727
+ 2.490447647996652
+ 2.490526717129612
+ 2.4906057828242587
+ 2.490684845080998
+ 2.490763903900236
+ 2.490842959282377
+ 2.4909220112278274
+ 2.491001059736994
+ 2.4910801048102797
+ 2.491159146448091
+ 2.4912381846508342
+ 2.491317219418913
+ 2.4913962507527327
+ 2.4914752786526986
+ 2.4915543031192158
+ 2.491633324152689
+ 2.491712341753523
+ 2.491791355922122
+ 2.4918703666588917
+ 2.4919493739642355
+ 2.492028377838559
+ 2.4921073782822654
+ 2.4921863752957605
+ 2.4922653688794467
+ 2.4923443590337295
+ 2.492423345759013
+ 2.4925023290557
+ 2.4925813089241955
+ 2.492660285364903
+ 2.4927392583782266
+ 2.4928182279645696
+ 2.492897194124336
+ 2.492976156857929
+ 2.4930551161657517
+ 2.4931340720482082
+ 2.493213024505702
+ 2.493291973538635
+ 2.4933709191474116
+ 2.4934498613324347
+ 2.493528800094107
+ 2.4936077354328314
+ 2.493686667349011
+ 2.493765595843048
+ 2.4938445209153453
+ 2.493923442566307
+ 2.494002360796333
+ 2.4940812756058275
+ 2.4941601869951926
+ 2.4942390949648305
+ 2.494317999515143
+ 2.494396900646533
+ 2.494475798359402
+ 2.494554692654152
+ 2.494633583531186
+ 2.494712470990904
+ 2.494791355033709
+ 2.494870235660002
+ 2.4949491128701857
+ 2.4950279866646605
+ 2.495106857043828
+ 2.4951857240080906
+ 2.4952645875578483
+ 2.495343447693503
+ 2.495422304415456
+ 2.4955011577241075
+ 2.4955800076198598
+ 2.4956588541031124
+ 2.495737697174267
+ 2.4958165368337237
+ 2.4958953730818845
+ 2.495974205919149
+ 2.4960530353459176
+ 2.496131861362591
+ 2.49621068396957
+ 2.496289503167254
+ 2.496368318956044
+ 2.4964471313363403
+ 2.4965259403085422
+ 2.49660474587305
+ 2.4966835480302634
+ 2.496762346780583
+ 2.496841142124408
+ 2.4969199340621384
+ 2.496998722594173
+ 2.497077507720912
+ 2.4971562894427546
+ 2.4972350677601005
+ 2.497313842673349
+ 2.4973926141828997
+ 2.4974713822891506
+ 2.497550146992501
+ 2.497628908293351
+ 2.497707666192098
+ 2.4977864206891427
+ 2.497865171784882
+ 2.497943919479716
+ 2.4980226637740426
+ 2.4981014046682604
+ 2.498180142162768
+ 2.4982588762579634
+ 2.4983376069542453
+ 2.498416334252012
+ 2.4984950581516614
+ 2.498573778653592
+ 2.4986524957582015
+ 2.498731209465888
+ 2.498809919777049
+ 2.4988886266920827
+ 2.4989673302113866
+ 2.4990460303353585
+ 2.4991247270643955
+ 2.4992034203988953
+ 2.4992821103392555
+ 2.499360796885873
+ 2.4994394800391455
+ 2.4995181597994702
+ 2.499596836167244
+ 2.4996755091428637
+ 2.499754178726726
+ 2.4998328449192293
+ 2.499911507720769
+ 2.4999901671317417
+ 2.500068823152545
+ 2.500147475783575
+ 2.5002261250252276
+ 2.5003047708779005
+ 2.5003834133419884
+ 2.5004620524178893
+ 2.500540688105998
+ 2.5006193204067113
+ 2.500697949320425
+ 2.5007765748475355
+ 2.500855196988438
+ 2.500933815743529
+ 2.5010124311132036
+ 2.501091043097858
+ 2.5011696516978876
+ 2.5012482569136876
+ 2.5013268587456534
+ 2.5014054571941813
+ 2.501484052259666
+ 2.501562643942502
+ 2.501641232243085
+ 2.5017198171618107
+ 2.5017983986990733
+ 2.501876976855268
+ 2.501955551630789
+ 2.502034123026032
+ 2.5021126910413916
+ 2.5021912556772614
+ 2.502269816934037
+ 2.5023483748121125
+ 2.502426929311882
+ 2.50250548043374
+ 2.5025840281780813
+ 2.5026625725452987
+ 2.5027411135357878
+ 2.5028196511499416
+ 2.5028981853881542
+ 2.5029767162508203
+ 2.5030552437383324
+ 2.503133767851085
+ 2.503212288589471
+ 2.503290805953885
+ 2.50336931994472
+ 2.503447830562369
+ 2.5035263378072257
+ 2.5036048416796834
+ 2.5036833421801354
+ 2.5037618393089742
+ 2.5038403330665937
+ 2.503918823453386
+ 2.5039973104697446
+ 2.504075794116062
+ 2.504154274392731
+ 2.5042327513001448
+ 2.504311224838695
+ 2.5043896950087743
+ 2.504468161810776
+ 2.504546625245091
+ 2.5046250853121137
+ 2.5047035420122348
+ 2.504781995345846
+ 2.5048604453133403
+ 2.5049388919151094
+ 2.5050173351515457
+ 2.5050957750230403
+ 2.505174211529985
+ 2.5052526446727716
+ 2.5053310744517927
+ 2.505409500867438
+ 2.5054879239201
+ 2.5055663436101705
+ 2.505644759938041
+ 2.5057231729041014
+ 2.5058015825087434
+ 2.5058799887523584
+ 2.5059583916353376
+ 2.5060367911580714
+ 2.5061151873209506
+ 2.506193580124367
+ 2.50627196956871
+ 2.506350355654371
+ 2.506428738381741
+ 2.5065071177512093
+ 2.506585493763167
+ 2.506663866418005
+ 2.5067422357161124
+ 2.5068206016578802
+ 2.5068989642436987
+ 2.5069773234739574
+ 2.507055679349046
+ 2.5071340318693554
+ 2.5072123810352744
+ 2.507290726847194
+ 2.5073690693055024
+ 2.5074474084105907
+ 2.507525744162847
+ 2.507604076562662
+ 2.5076824056104248
+ 2.507760731306524
+ 2.50783905365135
+ 2.5079173726452906
+ 2.5079956882887355
+ 2.508074000582074
+ 2.5081523095256952
+ 2.5082306151199876
+ 2.50830891736534
+ 2.508387216262141
+ 2.5084655118107797
+ 2.508543804011644
+ 2.5086220928651235
+ 2.5087003783716053
+ 2.5087786605314784
+ 2.508856939345131
+ 2.508935214812952
+ 2.509013486935329
+ 2.50909175571265
+ 2.5091700211453025
+ 2.509248283233675
+ 2.5093265419781554
+ 2.5094047973791316
+ 2.509483049436991
+ 2.509561298152121
+ 2.5096395435249095
+ 2.5097177855557438
+ 2.509796024245012
+ 2.5098742595931003
+ 2.5099524916003966
+ 2.5100307202672876
+ 2.510108945594161
+ 2.510187167581404
+ 2.510265386229403
+ 2.5103436015385454
+ 2.5104218135092173
+ 2.510500022141806
+ 2.5105782274366986
+ 2.51065642939428
+ 2.510734628014939
+ 2.51081282329906
+ 2.510891015247031
+ 2.5109692038592373
+ 2.511047389136065
+ 2.5111255710779012
+ 2.511203749685132
+ 2.5112819249581424
+ 2.511360096897319
+ 2.511438265503047
+ 2.511516430775713
+ 2.511594592715703
+ 2.5116727513234016
+ 2.5117509065991954
+ 2.511829058543469
+ 2.5119072071566078
+ 2.511985352438998
+ 2.512063494391025
+ 2.512141633013073
+ 2.5122197683055276
+ 2.512297900268774
+ 2.5123760289031973
+ 2.512454154209182
+ 2.512532276187113
+ 2.5126103948373757
+ 2.512688510160354
+ 2.512766622156433
+ 2.5128447308259974
+ 2.512922836169431
+ 2.5130009381871194
+ 2.513079036879446
+ 2.5131571322467954
+ 2.513235224289551
+ 2.513313313008098
+ 2.5133913984028204
+ 2.5134694804741016
+ 2.513547559222326
+ 2.513625634647877
+ 2.513703706751139
+ 2.5137817755324945
+ 2.5138598409923287
+ 2.5139379031310236
+ 2.514015961948964
+ 2.5140940174465323
+ 2.5141720696241125
+ 2.5142501184820873
+ 2.5143281640208404
+ 2.514406206240755
+ 2.5144842451422136
+ 2.5145622807255994
+ 2.5146403129912955
+ 2.514718341939685
+ 2.514796367571149
+ 2.514874389886072
+ 2.5149524088848367
+ 2.5150304245678243
+ 2.5151084369354177
+ 2.5151864459880002
+ 2.515264451725953
+ 2.5153424541496587
+ 2.5154204532594995
+ 2.515498449055858
+ 2.5155764415391157
+ 2.515654430709654
+ 2.5157324165678565
+ 2.5158103991141036
+ 2.515888378348777
+ 2.5159663542722592
+ 2.5160443268849315
+ 2.5161222961871754
+ 2.516200262179372
+ 2.516278224861903
+ 2.5163561842351503
+ 2.516434140299494
+ 2.516512093055316
+ 2.5165900425029974
+ 2.5166679886429186
+ 2.5167459314754614
+ 2.516823871001006
+ 2.516901807219934
+ 2.5169797401326255
+ 2.517057669739461
+ 2.5171355960408217
+ 2.517213519037088
+ 2.5172914387286403
+ 2.5173693551158585
+ 2.5174472681991236
+ 2.5175251779788157
+ 2.5176030844553146
+ 2.5176809876290007
+ 2.5177588875002543
+ 2.517836784069455
+ 2.517914677336983
+ 2.5179925673032173
+ 2.5180704539685386
+ 2.518148337333326
+ 2.518226217397959
+ 2.518304094162818
+ 2.5183819676282813
+ 2.518459837794729
+ 2.5185377046625406
+ 2.518615568232095
+ 2.5186934285037714
+ 2.5187712854779485
+ 2.518849139155006
+ 2.5189269895353226
+ 2.519004836619277
+ 2.5190826804072484
+ 2.5191605208996153
+ 2.519238358096757
+ 2.5193161919990508
+ 2.519394022606876
+ 2.5194718499206115
+ 2.519549673940635
+ 2.519627494667325
+ 2.51970531210106
+ 2.519783126242218
+ 2.519860937091177
+ 2.5199387446483152
+ 2.5200165489140103
+ 2.5200943498886406
+ 2.520172147572584
+ 2.520249941966218
+ 2.5203277330699194
+ 2.520405520884068
+ 2.520483305409039
+ 2.5205610866452113
+ 2.520638864592962
+ 2.5207166392526683
+ 2.5207944106247075
+ 2.5208721787094572
+ 2.520949943507294
+ 2.5210277050185947
+ 2.5211054632437366
+ 2.521183218183097
+ 2.5212609698370523
+ 2.5213387182059797
+ 2.5214164632902554
+ 2.5214942050902556
+ 2.521571943606358
+ 2.521649678838939
+ 2.521727410788374
+ 2.52180513945504
+ 2.5218828648393132
+ 2.5219605869415695
+ 2.522038305762185
+ 2.522116021301537
+ 2.522193733560001
+ 2.522271442537951
+ 2.522349148235765
+ 2.5224268506538183
+ 2.5225045497924863
+ 2.5225822456521447
+ 2.5226599382331694
+ 2.522737627535936
+ 2.5228153135608187
+ 2.5228929963081943
+ 2.522970675778437
+ 2.523048351971924
+ 2.5231260248890277
+ 2.5232036945301246
+ 2.5232813608955897
+ 2.5233590239857984
+ 2.5234366838011244
+ 2.5235143403419436
+ 2.5235919936086297
+ 2.5236696436015587
+ 2.5237472903211042
+ 2.523824933767641
+ 2.523902573941543
+ 2.523980210843185
+ 2.5240578444729413
+ 2.524135474831187
+ 2.5242131019182947
+ 2.5242907257346396
+ 2.5243683462805957
+ 2.5244459635565364
+ 2.524523577562836
+ 2.5246011882998682
+ 2.5246787957680064
+ 2.5247563999676252
+ 2.5248340008990975
+ 2.5249115985627966
+ 2.5249891929590964
+ 2.525066784088371
+ 2.5251443719509927
+ 2.525221956547335
+ 2.525299537877771
+ 2.525377115942674
+ 2.5254546907424174
+ 2.5255322622773733
+ 2.5256098305479155
+ 2.5256873955544163
+ 2.525764957297249
+ 2.5258425157767856
+ 2.5259200709933998
+ 2.525997622947463
+ 2.526075171639348
+ 2.526152717069428
+ 2.526230259238075
+ 2.5263077981456603
+ 2.5263853337925575
+ 2.5264628661791377
+ 2.5265403953057746
+ 2.526617921172838
+ 2.526695443780701
+ 2.5267729631297353
+ 2.5268504792203133
+ 2.526927992052806
+ 2.527005501627585
+ 2.527083007945023
+ 2.52716051100549
+ 2.527238010809359
+ 2.5273155073569997
+ 2.527393000648785
+ 2.527470490685085
+ 2.5275479774662717
+ 2.527625460992716
+ 2.527702941264789
+ 2.5277804182828607
+ 2.5278578920473036
+ 2.527935362558487
+ 2.528012829816783
+ 2.5280902938225616
+ 2.528167754576194
+ 2.52824521207805
+ 2.5283226663285
+ 2.5284001173279154
+ 2.5284775650766655
+ 2.528555009575122
+ 2.5286324508236535
+ 2.528709888822631
+ 2.5287873235724248
+ 2.5288647550734047
+ 2.52894218332594
+ 2.529019608330401
+ 2.529097030087158
+ 2.5291744485965806
+ 2.5292518638590376
+ 2.5293292758748995
+ 2.5294066846445356
+ 2.5294840901683155
+ 2.5295614924466086
+ 2.5296388914797836
+ 2.52971628726821
+ 2.5297936798122573
+ 2.529871069112295
+ 2.5299484551686913
+ 2.5300258379818157
+ 2.530103217552037
+ 2.5301805938797237
+ 2.530257966965246
+ 2.5303353368089705
+ 2.530412703411267
+ 2.530490066772504
+ 2.5305674268930494
+ 2.530644783773273
+ 2.530722137413542
+ 2.5307994878142255
+ 2.530876834975691
+ 2.5309541788983063
+ 2.531031519582441
+ 2.5311088570284617
+ 2.5311861912367375
+ 2.531263522207636
+ 2.531340849941524
+ 2.5314181744387696
+ 2.5314954956997417
+ 2.531572813724807
+ 2.531650128514333
+ 2.5317274400686878
+ 2.5318047483882378
+ 2.5318820534733506
+ 2.5319593553243944
+ 2.5320366539417356
+ 2.532113949325742
+ 2.5321912414767795
+ 2.5322685303952164
+ 2.5323458160814187
+ 2.532423098535754
+ 2.532500377758588
+ 2.5325776537502884
+ 2.5326549265112224
+ 2.532732196041755
+ 2.5328094623422537
+ 2.532886725413085
+ 2.5329639852546153
+ 2.53304124186721
+ 2.533118495251237
+ 2.533195745407061
+ 2.533272992335049
+ 2.5333502360355666
+ 2.5334274765089804
+ 2.5335047137556557
+ 2.533581947775958
+ 2.5336591785702542
+ 2.533736406138909
+ 2.5338136304822894
+ 2.533890851600759
+ 2.533968069494685
+ 2.5340452841644323
+ 2.534122495610366
+ 2.5341997038328516
+ 2.534276908832254
+ 2.53435411060894
+ 2.5344313091632724
+ 2.5345085044956175
+ 2.53458569660634
+ 2.534662885495805
+ 2.5347400711643777
+ 2.534817253612422
+ 2.5348944328403027
+ 2.534971608848385
+ 2.535048781637033
+ 2.535125951206612
+ 2.5352031175574856
+ 2.5352802806900185
+ 2.535357440604575
+ 2.535434597301519
+ 2.5355117507812146
+ 2.5355889010440267
+ 2.535666048090319
+ 2.535743191920455
+ 2.535820332534799
+ 2.5358974699337145
+ 2.5359746041175657
+ 2.5360517350867164
+ 2.5361288628415295
+ 2.5362059873823695
+ 2.5362831087095987
+ 2.536360226823582
+ 2.5364373417246813
+ 2.5365144534132615
+ 2.536591561889684
+ 2.5366686671543137
+ 2.5367457692075117
+ 2.536822868049643
+ 2.5368999636810696
+ 2.5369770561021547
+ 2.537054145313261
+ 2.537131231314751
+ 2.5372083141069877
+ 2.5372853936903335
+ 2.5373624700651507
+ 2.537439543231803
+ 2.5375166131906512
+ 2.537593679942059
+ 2.5376707434863883
+ 2.537747803824001
+ 2.537824860955259
+ 2.5379019148805253
+ 2.5379789656001615
+ 2.5380560131145296
+ 2.538133057423991
+ 2.538210098528908
+ 2.538287136429642
+ 2.5383641711265557
+ 2.53844120262001
+ 2.5385182309103658
+ 2.5385952559979854
+ 2.5386722778832302
+ 2.5387492965664613
+ 2.5388263120480405
+ 2.538903324328328
+ 2.5389803334076864
+ 2.539057339286475
+ 2.5391343419650565
+ 2.539211341443791
+ 2.5392883377230393
+ 2.539365330803163
+ 2.539442320684522
+ 2.5395193073674776
+ 2.53959629085239
+ 2.5396732711396197
+ 2.5397502482295278
+ 2.539827222122474
+ 2.539904192818819
+ 2.539981160318923
+ 2.540058124623147
+ 2.5401350857318494
+ 2.5402120436453925
+ 2.540288998364135
+ 2.540365949888437
+ 2.5404428982186578
+ 2.5405198433551583
+ 2.5405967852982982
+ 2.5406737240484367
+ 2.5407506596059335
+ 2.5408275919711483
+ 2.5409045211444408
+ 2.5409814471261702
+ 2.5410583699166955
+ 2.5411352895163763
+ 2.5412122059255724
+ 2.5412891191446425
+ 2.5413660291739455
+ 2.5414429360138406
+ 2.5415198396646868
+ 2.5415967401268427
+ 2.541673637400668
+ 2.5417505314865205
+ 2.54182742238476
+ 2.541904310095744
+ 2.541981194619831
+ 2.542058075957381
+ 2.5421349541087515
+ 2.5422118290743003
+ 2.5422887008543866
+ 2.5423655694493688
+ 2.542442434859604
+ 2.5425192970854513
+ 2.5425961561272685
+ 2.542673011985413
+ 2.5427498646602436
+ 2.5428267141521177
+ 2.542903560461393
+ 2.5429804035884276
+ 2.543057243533579
+ 2.5431340802972047
+ 2.5432109138796624
+ 2.543287744281309
+ 2.5433645715025026
+ 2.5434413955436
+ 2.543518216404959
+ 2.5435950340869367
+ 2.5436718485898897
+ 2.543748659914175
+ 2.5438254680601506
+ 2.5439022730281735
+ 2.543979074818599
+ 2.544055873431785
+ 2.5441326688680883
+ 2.544209461127865
+ 2.5442862502114725
+ 2.5443630361192664
+ 2.544439818851604
+ 2.544516598408842
+ 2.544593374791335
+ 2.5446701479994407
+ 2.544746918033516
+ 2.5448236848939154
+ 2.5449004485809956
+ 2.5449772090951126
+ 2.545053966436623
+ 2.5451307206058815
+ 2.545207471603245
+ 2.5452842194290692
+ 2.5453609640837094
+ 2.545437705567521
+ 2.54551444388086
+ 2.5455911790240817
+ 2.5456679109975413
+ 2.545744639801595
+ 2.545821365436597
+ 2.5458980879029034
+ 2.545974807200869
+ 2.546051523330849
+ 2.5461282362931987
+ 2.546204946088273
+ 2.5462816527164267
+ 2.5463583561780143
+ 2.546435056473391
+ 2.5465117536029114
+ 2.5465884475669305
+ 2.5466651383658023
+ 2.5467418259998813
+ 2.546818510469523
+ 2.5468951917750804
+ 2.546971869916909
+ 2.547048544895362
+ 2.5471252167107945
+ 2.5472018853635605
+ 2.5472785508540134
+ 2.547355213182508
+ 2.547431872349398
+ 2.5475085283550376
+ 2.5475851811997794
+ 2.5476618308839787
+ 2.547738477407988
+ 2.547815120772162
+ 2.547891760976853
+ 2.547968398022416
+ 2.5480450319092025
+ 2.548121662637568
+ 2.548198290207864
+ 2.5482749146204453
+ 2.5483515358756637
+ 2.548428153973873
+ 2.5485047689154263
+ 2.5485813807006763
+ 2.5486579893299757
+ 2.548734594803678
+ 2.548811197122135
+ 2.548887796285701
+ 2.5489643922947276
+ 2.549040985149567
+ 2.5491175748505723
+ 2.5491941613980966
+ 2.5492707447924907
+ 2.549347325034108
+ 2.549423902123301
+ 2.5495004760604214
+ 2.549577046845822
+ 2.549653614479854
+ 2.5497301789628692
+ 2.5498067402952205
+ 2.5498832984772597
+ 2.5499598535093377
+ 2.550036405391807
+ 2.5501129541250194
+ 2.550189499709326
+ 2.5502660421450787
+ 2.5503425814326297
+ 2.550419117572329
+ 2.5504956505645286
+ 2.5505721804095804
+ 2.5506487071078343
+ 2.5507252306596433
+ 2.550801751065357
+ 2.550878268325327
+ 2.5509547824399044
+ 2.55103129340944
+ 2.5511078012342847
+ 2.551184305914789
+ 2.551260807451304
+ 2.5513373058441804
+ 2.5514138010937684
+ 2.551490293200419
+ 2.5515667821644823
+ 2.551643267986309
+ 2.5517197506662495
+ 2.551796230204654
+ 2.5518727066018725
+ 2.551949179858255
+ 2.5520256499741523
+ 2.552102116949914
+ 2.55217858078589
+ 2.5522550414824305
+ 2.552331499039885
+ 2.5524079534586037
+ 2.5524844047389363
+ 2.552560852881232
+ 2.5526372978858403
+ 2.552713739753111
+ 2.552790178483394
+ 2.5528666140770384
+ 2.5529430465343927
+ 2.5530194758558076
+ 2.5530959020416315
+ 2.553172325092213
+ 2.553248745007903
+ 2.553325161789048
+ 2.5534015754359993
+ 2.553477985949104
+ 2.5535543933287124
+ 2.553630797575172
+ 2.5537071986888327
+ 2.553783596670042
+ 2.5538599915191496
+ 2.5539363832365027
+ 2.5540127718224506
+ 2.5540891572773416
+ 2.554165539601524
+ 2.5542419187953462
+ 2.5543182948591556
+ 2.5543946677933014
+ 2.554471037598131
+ 2.554547404273993
+ 2.5546237678212345
+ 2.554700128240204
+ 2.554776485531249
+ 2.554852839694717
+ 2.5549291907309564
+ 2.555005538640315
+ 2.5550818834231395
+ 2.5551582250797775
+ 2.555234563610577
+ 2.5553108990158853
+ 2.555387231296049
+ 2.5554635604514155
+ 2.555539886482333
+ 2.555616209389148
+ 2.5556925291722066
+ 2.555768845831858
+ 2.5558451593684466
+ 2.555921469782321
+ 2.5559977770738276
+ 2.5560740812433127
+ 2.5561503822911233
+ 2.556226680217607
+ 2.5563029750231085
+ 2.556379266707975
+ 2.5564555552725534
+ 2.5565318407171898
+ 2.556608123042231
+ 2.556684402248022
+ 2.5567606783349097
+ 2.5568369513032407
+ 2.5569132211533607
+ 2.556989487885615
+ 2.5570657515003505
+ 2.5571420119979127
+ 2.557218269378647
+ 2.5572945236429
+ 2.557370774791017
+ 2.5574470228233426
+ 2.557523267740224
+ 2.557599509542006
+ 2.5576757482290335
+ 2.5577519838016527
+ 2.557828216260208
+ 2.557904445605046
+ 2.5579806718365106
+ 2.5580568949549476
+ 2.5581331149607016
+ 2.558209331854118
+ 2.5582855456355422
+ 2.558361756305317
+ 2.55843796386379
+ 2.558514168311304
+ 2.558590369648204
+ 2.5586665678748353
+ 2.5587427629915416
+ 2.558818954998668
+ 2.5588951438965593
+ 2.5589713296855585
+ 2.559047512366011
+ 2.559123691938261
+ 2.559199868402652
+ 2.5592760417595293
+ 2.5593522120092356
+ 2.559428379152116
+ 2.5595045431885133
+ 2.5595807041187726
+ 2.5596568619432367
+ 2.5597330166622503
+ 2.559809168276156
+ 2.5598853167852984
+ 2.5599614621900204
+ 2.560037604490666
+ 2.560113743687578
+ 2.5601898797811007
+ 2.560266012771576
+ 2.560342142659349
+ 2.5604182694447615
+ 2.5604943931281574
+ 2.560570513709879
+ 2.5606466311902696
+ 2.5607227455696724
+ 2.56079885684843
+ 2.560874965026885
+ 2.560951070105381
+ 2.5610271720842603
+ 2.5611032709638653
+ 2.561179366744539
+ 2.561255459426623
+ 2.5613315490104607
+ 2.561407635496394
+ 2.5614837188847654
+ 2.561559799175917
+ 2.561635876370191
+ 2.56171195046793
+ 2.5617880214694755
+ 2.56186408937517
+ 2.561940154185355
+ 2.5620162159003725
+ 2.5620922745205648
+ 2.5621683300462728
+ 2.562244382477839
+ 2.5623204318156048
+ 2.562396478059911
+ 2.5624725212111006
+ 2.562548561269514
+ 2.562624598235493
+ 2.562700632109379
+ 2.562776662891513
+ 2.5628526905822366
+ 2.56292871518189
+ 2.5630047366908153
+ 2.5630807551093535
+ 2.563156770437845
+ 2.563232782676631
+ 2.563308791826052
+ 2.5633847978864495
+ 2.563460800858164
+ 2.5635368007415353
+ 2.5636127975369054
+ 2.563688791244614
+ 2.5637647818650016
+ 2.563840769398409
+ 2.563916753845176
+ 2.563992735205643
+ 2.5640687134801508
+ 2.564144688669039
+ 2.564220660772648
+ 2.564296629791318
+ 2.5643725957253882
+ 2.564448558575199
+ 2.5645245183410905
+ 2.564600475023403
+ 2.5646764286224744
+ 2.564752379138646
+ 2.5648283265722576
+ 2.564904270923648
+ 2.564980212193156
+ 2.565056150381123
+ 2.5651320854878863
+ 2.5652080175137866
+ 2.5652839464591626
+ 2.565359872324354
+ 2.5654357951096998
+ 2.5655117148155377
+ 2.565587631442209
+ 2.5656635449900507
+ 2.5657394554594024
+ 2.565815362850604
+ 2.5658912671639924
+ 2.565967168399908
+ 2.566043066558688
+ 2.5661189616406714
+ 2.566194853646198
+ 2.5662707425756044
+ 2.56634662842923
+ 2.566422511207413
+ 2.5664983909104917
+ 2.566574267538804
+ 2.5666501410926887
+ 2.5667260115724835
+ 2.5668018789785263
+ 2.566877743311155
+ 2.566953604570709
+ 2.5670294627575236
+ 2.5671053178719383
+ 2.567181169914291
+ 2.567257018884918
+ 2.567332864784158
+ 2.567408707612349
+ 2.567484547369827
+ 2.5675603840569305
+ 2.5676362176739964
+ 2.5677120482213627
+ 2.567787875699366
+ 2.5678637001083437
+ 2.567939521448633
+ 2.5680153397205707
+ 2.5680911549244945
+ 2.56816696706074
+ 2.5682427761296456
+ 2.568318582131547
+ 2.568394385066782
+ 2.568470184935686
+ 2.568545981738597
+ 2.5686217754758505
+ 2.568697566147784
+ 2.5687733537547333
+ 2.5688491382970344
+ 2.568924919775025
+ 2.5690006981890408
+ 2.569076473539417
+ 2.569152245826491
+ 2.569228015050599
+ 2.5693037812120756
+ 2.5693795443112584
+ 2.5694553043484825
+ 2.569531061324084
+ 2.569606815238399
+ 2.5696825660917626
+ 2.5697583138845106
+ 2.5698340586169786
+ 2.5699098002895027
+ 2.5699855389024187
+ 2.5700612744560605
+ 2.5701370069507647
+ 2.5702127363868668
+ 2.5702884627647005
+ 2.570364186084603
+ 2.5704399063469086
+ 2.5705156235519517
+ 2.5705913377000686
+ 2.5706670487915937
+ 2.5707427568268613
+ 2.570818461806207
+ 2.570894163729965
+ 2.5709698625984716
+ 2.5710455584120595
+ 2.5711212511710637
+ 2.5711969408758195
+ 2.5712726275266613
+ 2.571348311123923
+ 2.5714239916679387
+ 2.571499669159044
+ 2.571575343597572
+ 2.571651014983857
+ 2.571726683318234
+ 2.571802348601036
+ 2.5718780108325974
+ 2.5719536700132526
+ 2.5720293261433347
+ 2.572104979223178
+ 2.5721806292531166
+ 2.5722562762334835
+ 2.5723319201646127
+ 2.572407561046838
+ 2.5724831988804926
+ 2.5725588336659095
+ 2.572634465403423
+ 2.5727100940933667
+ 2.572785719736073
+ 2.5728613423318754
+ 2.5729369618811067
+ 2.5730125783841005
+ 2.5730881918411903
+ 2.573163802252709
+ 2.5732394096189886
+ 2.5733150139403627
+ 2.5733906152171633
+ 2.573466213449725
+ 2.573541808638378
+ 2.573617400783457
+ 2.5736929898852936
+ 2.5737685759442215
+ 2.573844158960571
+ 2.573919738934676
+ 2.573995315866869
+ 2.5740708897574818
+ 2.5741464606068463
+ 2.5742220284152952
+ 2.574297593183161
+ 2.5743731549107745
+ 2.5744487135984686
+ 2.574524269246575
+ 2.574599821855426
+ 2.5746753714253523
+ 2.574750917956687
+ 2.574826461449761
+ 2.5749020019049063
+ 2.574977539322454
+ 2.5750530737027355
+ 2.5751286050460833
+ 2.575204133352828
+ 2.575279658623301
+ 2.575355180857834
+ 2.5754307000567573
+ 2.575506216220403
+ 2.5755817293491026
+ 2.5756572394431854
+ 2.575732746502984
+ 2.575808250528828
+ 2.5758837515210495
+ 2.575959249479979
+ 2.5760347444059466
+ 2.5761102362992836
+ 2.5761857251603204
+ 2.576261210989388
+ 2.5763366937868164
+ 2.576412173552936
+ 2.576487650288078
+ 2.576563123992572
+ 2.576638594666748
+ 2.5767140623109372
+ 2.576789526925469
+ 2.576864988510674
+ 2.5769404470668813
+ 2.577015902594422
+ 2.577091355093626
+ 2.577166804564822
+ 2.577242251008341
+ 2.577317694424512
+ 2.5773931348136654
+ 2.5774685721761306
+ 2.5775440065122366
+ 2.577619437822314
+ 2.577694866106691
+ 2.5777702913656984
+ 2.5778457135996637
+ 2.577921132808918
+ 2.5779965489937897
+ 2.578071962154608
+ 2.578147372291702
+ 2.578222779405401
+ 2.5782981834960337
+ 2.578373584563929
+ 2.578448982609416
+ 2.578524377632823
+ 2.57859976963448
+ 2.578675158614714
+ 2.578750544573855
+ 2.578825927512231
+ 2.578901307430171
+ 2.578976684328003
+ 2.5790520582060554
+ 2.579127429064657
+ 2.579202796904135
+ 2.579278161724819
+ 2.579353523527036
+ 2.579428882311116
+ 2.579504238077384
+ 2.579579590826171
+ 2.579654940557803
+ 2.579730287272609
+ 2.5798056309709163
+ 2.5798809716530524
+ 2.579956309319346
+ 2.580031643970124
+ 2.5801069756057133
+ 2.5801823042264433
+ 2.58025762983264
+ 2.5803329524246315
+ 2.5804082720027446
+ 2.580483588567307
+ 2.580558902118646
+ 2.5806342126570887
+ 2.580709520182962
+ 2.5807848246965936
+ 2.58086012619831
+ 2.580935424688438
+ 2.581010720167305
+ 2.581086012635237
+ 2.581161302092562
+ 2.5812365885396056
+ 2.581311871976695
+ 2.5813871524041567
+ 2.581462429822318
+ 2.581537704231504
+ 2.5816129756320425
+ 2.5816882440242583
+ 2.5817635094084794
+ 2.5818387717850313
+ 2.58191403115424
+ 2.5819892875164316
+ 2.5820645408719334
+ 2.5821397912210697
+ 2.582215038564167
+ 2.582290282901552
+ 2.58236552423355
+ 2.582440762560487
+ 2.5825159978826884
+ 2.5825912302004794
+ 2.5826664595141873
+ 2.582741685824136
+ 2.582816909130652
+ 2.58289212943406
+ 2.5829673467346868
+ 2.583042561032856
+ 2.5831177723288934
+ 2.583192980623125
+ 2.583268185915875
+ 2.58334338820747
+ 2.5834185874982327
+ 2.58349378378849
+ 2.5835689770785666
+ 2.583644167368787
+ 2.5837193546594754
+ 2.583794538950958
+ 2.583869720243558
+ 2.583944898537601
+ 2.5840200738334116
+ 2.584095246131314
+ 2.5841704154316325
+ 2.5842455817346917
+ 2.584320745040817
+ 2.584395905350331
+ 2.5844710626635585
+ 2.584546216980825
+ 2.584621368302453
+ 2.5846965166287665
+ 2.5847716619600907
+ 2.5848468042967494
+ 2.584921943639066
+ 2.5849970799873643
+ 2.5850722133419684
+ 2.5851473437032015
+ 2.585222471071388
+ 2.585297595446851
+ 2.585372716829915
+ 2.585447835220902
+ 2.5855229506201365
+ 2.5855980630279416
+ 2.585673172444641
+ 2.585748278870557
+ 2.585823382306014
+ 2.5858984827513343
+ 2.5859735802068418
+ 2.5860486746728584
+ 2.5861237661497083
+ 2.586198854637714
+ 2.5862739401371977
+ 2.5863490226484838
+ 2.5864241021718932
+ 2.58649917870775
+ 2.586574252256376
+ 2.586649322818095
+ 2.5867243903932273
+ 2.586799454982098
+ 2.586874516585028
+ 2.5869495752023393
+ 2.587024630834356
+ 2.5870996834813984
+ 2.5871747331437898
+ 2.587249779821852
+ 2.5873248235159068
+ 2.587399864226277
+ 2.5874749019532843
+ 2.58754993669725
+ 2.587624968458497
+ 2.5876999972373462
+ 2.58777502303412
+ 2.58785004584914
+ 2.5879250656827266
+ 2.588000082535203
+ 2.5880750964068904
+ 2.5881501072981097
+ 2.5882251152091826
+ 2.5883001201404303
+ 2.5883751220921742
+ 2.5884501210647355
+ 2.5885251170584356
+ 2.588600110073595
+ 2.5886751001105357
+ 2.588750087169578
+ 2.588825071251043
+ 2.588900052355252
+ 2.5889750304825254
+ 2.589050005633184
+ 2.5891249778075487
+ 2.58919994700594
+ 2.5892749132286785
+ 2.5893498764760854
+ 2.5894248367484805
+ 2.589499794046184
+ 2.589574748369517
+ 2.5896496997187994
+ 2.5897246480943514
+ 2.589799593496494
+ 2.589874535925546
+ 2.5899494753818293
+ 2.5900244118656626
+ 2.590099345377366
+ 2.59017427591726
+ 2.590249203485664
+ 2.5903241280828984
+ 2.590399049709282
+ 2.590473968365135
+ 2.590548884050778
+ 2.590623796766529
+ 2.590698706512709
+ 2.590773613289636
+ 2.5908485170976308
+ 2.590923417937012
+ 2.590998315808099
+ 2.5910732107112118
+ 2.5911481026466685
+ 2.5912229916147886
+ 2.5912978776158915
+ 2.5913727606502968
+ 2.591447640718322
+ 2.591522517820287
+ 2.5915973919565105
+ 2.591672263127311
+ 2.5917471313330083
+ 2.5918219965739198
+ 2.5918968588503652
+ 2.5919717181626623
+ 2.59204657451113
+ 2.5921214278960867
+ 2.592196278317851
+ 2.5922711257767412
+ 2.5923459702730756
+ 2.5924208118071723
+ 2.5924956503793495
+ 2.5925704859899255
+ 2.5926453186392187
+ 2.5927201483275466
+ 2.5927949750552273
+ 2.592869798822579
+ 2.5929446196299195
+ 2.593019437477566
+ 2.5930942523658373
+ 2.5931690642950502
+ 2.5932438732655227
+ 2.593318679277573
+ 2.5933934823315177
+ 2.5934682824276742
+ 2.593543079566361
+ 2.5936178737478945
+ 2.593692664972592
+ 2.5937674532407713
+ 2.5938422385527495
+ 2.593917020908844
+ 2.593991800309371
+ 2.5940665767546482
+ 2.594141350244992
+ 2.5942161207807204
+ 2.5942908883621496
+ 2.594365652989596
+ 2.5944404146633775
+ 2.5945151733838094
+ 2.5945899291512093
+ 2.594664681965894
+ 2.5947394318281787
+ 2.594814178738382
+ 2.5948889226968177
+ 2.5949636637038043
+ 2.5950384017596573
+ 2.5951131368646934
+ 2.595187869019228
+ 2.5952625982235777
+ 2.595337324478059
+ 2.595412047782987
+ 2.5954867681386786
+ 2.595561485545449
+ 2.595636200003615
+ 2.5957109115134913
+ 2.5957856200753944
+ 2.5958603256896398
+ 2.5959350283565428
+ 2.59600972807642
+ 2.596084424849586
+ 2.596159118676357
+ 2.5962338095570474
+ 2.5963084974919735
+ 2.5963831824814507
+ 2.596457864525793
+ 2.596532543625317
+ 2.5966072197803376
+ 2.5966818929911692
+ 2.5967565632581273
+ 2.5968312305815275
+ 2.5969058949616834
+ 2.596980556398911
+ 2.597055214893525
+ 2.597129870445839
+ 2.59720452305617
+ 2.5972791727248303
+ 2.597353819452136
+ 2.597428463238401
+ 2.5975031040839394
+ 2.5975777419890673
+ 2.5976523769540973
+ 2.5977270089793447
+ 2.5978016380651234
+ 2.5978762642117474
+ 2.5979508874195316
+ 2.5980255076887895
+ 2.5981001250198354
+ 2.598174739412983
+ 2.598249350868547
+ 2.598323959386841
+ 2.598398564968178
+ 2.5984731676128727
+ 2.5985477673212385
+ 2.5986223640935893
+ 2.5986969579302386
+ 2.5987715488314995
+ 2.5988461367976865
+ 2.598920721829112
+ 2.598995303926091
+ 2.599069883088935
+ 2.599144459317958
+ 2.599219032613473
+ 2.599293602975794
+ 2.599368170405233
+ 2.5994427349021043
+ 2.59951729646672
+ 2.5995918550993933
+ 2.5996664108004373
+ 2.5997409635701647
+ 2.5998155134088883
+ 2.5998900603169215
+ 2.5999646042945757
+ 2.6000391453421647
+ 2.6001136834599996
+ 2.6001882186483947
+ 2.600262750907662
+ 2.6003372802381133
+ 2.600411806640061
+ 2.6004863301138186
+ 2.6005608506596967
+ 2.6006353682780086
+ 2.600709882969066
+ 2.600784394733181
+ 2.6008589035706655
+ 2.6009334094818324
+ 2.6010079124669927
+ 2.6010824125264587
+ 2.6011569096605416
+ 2.6012314038695545
+ 2.601305895153808
+ 2.6013803835136136
+ 2.6014548689492836
+ 2.6015293514611293
+ 2.601603831049462
+ 2.6016783077145935
+ 2.6017527814568355
+ 2.601827252276499
+ 2.601901720173894
+ 2.6019761851493337
+ 2.602050647203128
+ 2.6021251063355892
+ 2.6021995625470273
+ 2.6022740158377538
+ 2.602348466208079
+ 2.602422913658315
+ 2.6024973581887716
+ 2.60257179979976
+ 2.602646238491591
+ 2.602720674264575
+ 2.6027951071190234
+ 2.6028695370552453
+ 2.6029439640735528
+ 2.603018388174256
+ 2.6030928093576646
+ 2.6031672276240894
+ 2.6032416429738405
+ 2.603316055407229
+ 2.6033904649245643
+ 2.6034648715261564
+ 2.6035392752123157
+ 2.6036136759833526
+ 2.6036880738395762
+ 2.603762468781298
+ 2.6038368608088263
+ 2.6039112499224712
+ 2.6039856361225433
+ 2.6040600194093515
+ 2.6041343997832054
+ 2.604208777244416
+ 2.604283151793291
+ 2.604357523430141
+ 2.604431892155275
+ 2.604506257969003
+ 2.6045806208716336
+ 2.6046549808634762
+ 2.604729337944841
+ 2.604803692116036
+ 2.6048780433773704
+ 2.6049523917291544
+ 2.6050267371716957
+ 2.605101079705304
+ 2.605175419330288
+ 2.6052497560469567
+ 2.6053240898556185
+ 2.605398420756583
+ 2.605472748750158
+ 2.605547073836653
+ 2.6056213960163754
+ 2.605695715289635
+ 2.6057700316567396
+ 2.605844345117998
+ 2.605918655673718
+ 2.605992963324209
+ 2.6060672680697774
+ 2.6061415699107338
+ 2.606215868847384
+ 2.606290164880038
+ 2.6063644580090033
+ 2.6064387482345874
+ 2.6065130355570987
+ 2.6065873199768443
+ 2.6066616014941335
+ 2.6067358801092735
+ 2.6068101558225716
+ 2.606884428634335
+ 2.606958698544873
+ 2.607032965554492
+ 2.6071072296635
+ 2.6071814908722044
+ 2.6072557491809123
+ 2.6073300045899312
+ 2.6074042570995686
+ 2.6074785067101316
+ 2.607552753421927
+ 2.607626997235263
+ 2.6077012381504456
+ 2.6077754761677827
+ 2.607849711287581
+ 2.607923943510148
+ 2.607998172835789
+ 2.6080723992648123
+ 2.6081466227975243
+ 2.608220843434231
+ 2.6082950611752405
+ 2.6083692760208583
+ 2.608443487971391
+ 2.608517697027146
+ 2.6085919031884295
+ 2.608666106455547
+ 2.608740306828806
+ 2.6088145043085116
+ 2.608888698894971
+ 2.6089628905884905
+ 2.609037079389376
+ 2.609111265297933
+ 2.609185448314468
+ 2.609259628439287
+ 2.609333805672696
+ 2.609407980015001
+ 2.609482151466508
+ 2.6095563200275222
+ 2.6096304856983497
+ 2.609704648479296
+ 2.609778808370667
+ 2.6098529653727676
+ 2.609927119485904
+ 2.6100012707103812
+ 2.610075419046505
+ 2.610149564494581
+ 2.610223707054914
+ 2.6102978467278093
+ 2.610371983513572
+ 2.6104461174125073
+ 2.6105202484249204
+ 2.610594376551117
+ 2.6106685017914004
+ 2.610742624146077
+ 2.6108167436154517
+ 2.610890860199828
+ 2.6109649738995127
+ 2.6110390847148084
+ 2.6111131926460214
+ 2.6111872976934554
+ 2.6112613998574155
+ 2.6113354991382054
+ 2.6114095955361307
+ 2.611483689051495
+ 2.6115577796846035
+ 2.6116318674357593
+ 2.6117059523052673
+ 2.6117800342934316
+ 2.6118541134005566
+ 2.611928189626946
+ 2.6120022629729047
+ 2.6120763334387354
+ 2.612150401024743
+ 2.612224465731231
+ 2.612298527558503
+ 2.6123725865068637
+ 2.6124466425766157
+ 2.6125206957680636
+ 2.6125947460815104
+ 2.61266879351726
+ 2.612742838075616
+ 2.6128168797568816
+ 2.6128909185613605
+ 2.612964954489356
+ 2.6130389875411706
+ 2.613113017717109
+ 2.613187045017473
+ 2.6132610694425664
+ 2.6133350909926927
+ 2.6134091096681544
+ 2.613483125469255
+ 2.613557138396297
+ 2.6136311484495836
+ 2.6137051556294173
+ 2.613779159936101
+ 2.613853161369937
+ 2.613927159931229
+ 2.6140011556202793
+ 2.61407514843739
+ 2.614149138382864
+ 2.6142231254570043
+ 2.6142971096601126
+ 2.614371090992491
+ 2.614445069454442
+ 2.6145190450462685
+ 2.6145930177682724
+ 2.6146669876207556
+ 2.6147409546040206
+ 2.614814918718369
+ 2.6148888799641035
+ 2.6149628383415253
+ 2.615036793850937
+ 2.61511074649264
+ 2.615184696266936
+ 2.615258643174127
+ 2.615332587214515
+ 2.615406528388401
+ 2.6154804666960874
+ 2.6155544021378745
+ 2.615628334714066
+ 2.615702264424961
+ 2.6157761912708617
+ 2.6158501152520692
+ 2.615924036368886
+ 2.6159979546216117
+ 2.6160718700105483
+ 2.6161457825359977
+ 2.6162196921982592
+ 2.6162935989976353
+ 2.6163675029344264
+ 2.6164414040089334
+ 2.616515302221458
+ 2.6165891975722992
+ 2.616663090061759
+ 2.6167369796901383
+ 2.6168108664577376
+ 2.616884750364857
+ 2.616958631411798
+ 2.61703250959886
+ 2.617106384926344
+ 2.617180257394551
+ 2.61725412700378
+ 2.6173279937543326
+ 2.617401857646508
+ 2.6174757186806072
+ 2.61754957685693
+ 2.617623432175777
+ 2.6176972846374476
+ 2.617771134242242
+ 2.6178449809904603
+ 2.6179188248824024
+ 2.6179926659183677
+ 2.618066504098657
+ 2.6181403394235683
+ 2.618214171893403
+ 2.61828800150846
+ 2.618361828269039
+ 2.6184356521754393
+ 2.6185094732279612
+ 2.618583291426903
+ 2.6186571067725644
+ 2.6187309192652455
+ 2.6188047289052445
+ 2.6188785356928617
+ 2.6189523396283954
+ 2.6190261407121453
+ 2.6190999389444096
+ 2.619173734325489
+ 2.6192475268556805
+ 2.6193213165352844
+ 2.619395103364599
+ 2.6194688873439236
+ 2.619542668473556
+ 2.6196164467537963
+ 2.619690222184942
+ 2.619763994767292
+ 2.619837764501145
+ 2.6199115313867996
+ 2.619985295424554
+ 2.6200590566147066
+ 2.6201328149575565
+ 2.620206570453401
+ 2.6202803231025387
+ 2.6203540729052683
+ 2.620427819861887
+ 2.6205015639726943
+ 2.6205753052379865
+ 2.620649043658063
+ 2.6207227792332213
+ 2.620796511963759
+ 2.6208702418499747
+ 2.620943968892165
+ 2.621017693090629
+ 2.6210914144456634
+ 2.621165132957567
+ 2.6212388486266356
+ 2.621312561453168
+ 2.621386271437462
+ 2.621459978579814
+ 2.621533682880522
+ 2.621607384339883
+ 2.6216810829581947
+ 2.6217547787357542
+ 2.6218284716728584
+ 2.6219021617698055
+ 2.621975849026891
+ 2.6220495334444127
+ 2.622123215022668
+ 2.622196893761953
+ 2.6222705696625654
+ 2.622344242724801
+ 2.622417912948958
+ 2.6224915803353324
+ 2.6225652448842207
+ 2.62263890659592
+ 2.622712565470726
+ 2.622786221508936
+ 2.622859874710846
+ 2.6229335250767534
+ 2.6230071726069535
+ 2.623080817301743
+ 2.623154459161418
+ 2.6232280981862752
+ 2.623301734376611
+ 2.62337536773272
+ 2.6234489982549
+ 2.6235226259434463
+ 2.623596250798655
+ 2.623669872820822
+ 2.6237434920102425
+ 2.6238171083672137
+ 2.6238907218920304
+ 2.6239643325849884
+ 2.624037940446384
+ 2.624111545476511
+ 2.6241851476756675
+ 2.624258747044148
+ 2.6243323435822474
+ 2.6244059372902613
+ 2.6244795281684854
+ 2.624553116217215
+ 2.6246267014367453
+ 2.6247002838273716
+ 2.624773863389389
+ 2.6248474401230926
+ 2.6249210140287773
+ 2.6249945851067387
+ 2.6250681533572706
+ 2.6251417187806694
+ 2.6252152813772294
+ 2.625288841147245
+ 2.625362398091011
+ 2.6254359522088224
+ 2.625509503500974
+ 2.62558305196776
+ 2.6256565976094755
+ 2.625730140426415
+ 2.625803680418872
+ 2.6258772175871417
+ 2.625950751931519
+ 2.626024283452297
+ 2.6260978121497707
+ 2.626171338024234
+ 2.626244861075982
+ 2.6263183813053077
+ 2.6263918987125052
+ 2.6264654132978693
+ 2.6265389250616935
+ 2.626612434004271
+ 2.6266859401258977
+ 2.6267594434268653
+ 2.6268329439074685
+ 2.626906441568001
+ 2.6269799364087563
+ 2.627053428430028
+ 2.6271269176321104
+ 2.6272004040152956
+ 2.6272738875798782
+ 2.6273473683261512
+ 2.627420846254408
+ 2.6274943213649427
+ 2.627567793658047
+ 2.627641263134015
+ 2.6277147297931402
+ 2.6277881936357153
+ 2.6278616546620333
+ 2.6279351128723873
+ 2.62800856826707
+ 2.6280820208463753
+ 2.628155470610595
+ 2.628228917560022
+ 2.62830236169495
+ 2.628375803015671
+ 2.628449241522478
+ 2.628522677215663
+ 2.628596110095519
+ 2.6286695401623383
+ 2.6287429674164136
+ 2.628816391858038
+ 2.6288898134875023
+ 2.6289632323051007
+ 2.629036648311123
+ 2.6291100615058642
+ 2.6291834718896148
+ 2.6292568794626674
+ 2.629330284225314
+ 2.6294036861778465
+ 2.6294770853205574
+ 2.629550481653738
+ 2.6296238751776797
+ 2.629697265892676
+ 2.629770653799017
+ 2.6298440388969957
+ 2.629917421186903
+ 2.6299908006690305
+ 2.6300641773436704
+ 2.6301375512111136
+ 2.6302109222716523
+ 2.630284290525577
+ 2.63035765597318
+ 2.6304310186147517
+ 2.6305043784505844
+ 2.6305777354809687
+ 2.6306510897061957
+ 2.630724441126557
+ 2.6307977897423434
+ 2.630871135553846
+ 2.630944478561356
+ 2.6310178187651636
+ 2.63109115616556
+ 2.6311644907628375
+ 2.6312378225572846
+ 2.6313111515491934
+ 2.6313844777388544
+ 2.6314578011265577
+ 2.631531121712595
+ 2.6316044394972558
+ 2.6316777544808305
+ 2.631751066663611
+ 2.6318243760458864
+ 2.631897682627947
+ 2.6319709864100838
+ 2.6320442873925867
+ 2.6321175855757457
+ 2.632190880959852
+ 2.6322641735451944
+ 2.6323374633320635
+ 2.6324107503207492
+ 2.6324840345115414
+ 2.63255731590473
+ 2.6326305945006054
+ 2.6327038702994567
+ 2.6327771433015745
+ 2.632850413507247
+ 2.632923680916766
+ 2.632996945530419
+ 2.633070207348497
+ 2.633143466371289
+ 2.633216722599085
+ 2.6332899760321733
+ 2.633363226670844
+ 2.633436474515386
+ 2.6335097195660895
+ 2.6335829618232434
+ 2.633656201287136
+ 2.633729437958057
+ 2.6338026718362957
+ 2.6338759029221412
+ 2.633949131215882
+ 2.634022356717807
+ 2.6340955794282057
+ 2.6341687993473664
+ 2.6342420164755778
+ 2.6343152308131295
+ 2.6343884423603092
+ 2.6344616511174057
+ 2.634534857084708
+ 2.6346080602625044
+ 2.634681260651084
+ 2.6347544582507343
+ 2.634827653061744
+ 2.6349008450844016
+ 2.634974034318995
+ 2.635047220765813
+ 2.6351204044251437
+ 2.635193585297275
+ 2.635266763382495
+ 2.6353399386810925
+ 2.6354131111933543
+ 2.6354862809195687
+ 2.635559447860025
+ 2.6356326120150086
+ 2.6357057733848097
+ 2.6357789319697145
+ 2.635852087770011
+ 2.6359252407859874
+ 2.635998391017931
+ 2.6360715384661293
+ 2.6361446831308704
+ 2.6362178250124404
+ 2.636290964111128
+ 2.6363641004272202
+ 2.6364372339610043
+ 2.636510364712768
+ 2.636583492682797
+ 2.6366566178713806
+ 2.6367297402788044
+ 2.636802859905356
+ 2.636875976751323
+ 2.6369490908169912
+ 2.6370222021026484
+ 2.6370953106085815
+ 2.6371684163350766
+ 2.6372415192824215
+ 2.6373146194509025
+ 2.6373877168408058
+ 2.637460811452419
+ 2.6375339032860277
+ 2.6376069923419196
+ 2.63768007862038
+ 2.637753162121696
+ 2.6378262428461543
+ 2.6378993207940407
+ 2.6379723959656416
+ 2.6380454683612435
+ 2.638118537981132
+ 2.6381916048255944
+ 2.6382646688949167
+ 2.6383377301893836
+ 2.638410788709282
+ 2.6384838444548984
+ 2.6385568974265174
+ 2.6386299476244264
+ 2.6387029950489103
+ 2.638776039700255
+ 2.638849081578746
+ 2.63892212068467
+ 2.638995157018312
+ 2.639068190579957
+ 2.6391412213698913
+ 2.6392142493884
+ 2.639287274635769
+ 2.6393602971122836
+ 2.6394333168182285
+ 2.63950633375389
+ 2.6395793479195526
+ 2.639652359315502
+ 2.6397253679420225
+ 2.6397983737994
+ 2.63987137688792
+ 2.6399443772078666
+ 2.640017374759525
+ 2.6400903695431803
+ 2.640163361559117
+ 2.640236350807621
+ 2.6403093372889757
+ 2.6403823210034663
+ 2.640455301951378
+ 2.640528280132995
+ 2.640601255548601
+ 2.6406742281984825
+ 2.6407471980829227
+ 2.6408201652022063
+ 2.6408931295566176
+ 2.6409660911464408
+ 2.641039049971961
+ 2.6411120060334614
+ 2.641184959331227
+ 2.6412579098655415
+ 2.6413308576366887
+ 2.641403802644954
+ 2.6414767448906202
+ 2.6415496843739716
+ 2.641622621095292
+ 2.6416955550548655
+ 2.641768486252976
+ 2.6418414146899067
+ 2.6419143403659424
+ 2.6419872632813655
+ 2.64206018343646
+ 2.64213310083151
+ 2.6422060154667992
+ 2.6422789273426104
+ 2.6423518364592273
+ 2.642424742816933
+ 2.6424976464160115
+ 2.642570547256746
+ 2.6426434453394188
+ 2.642716340664314
+ 2.642789233231715
+ 2.642862123041904
+ 2.6429350100951647
+ 2.6430078943917796
+ 2.6430807759320327
+ 2.643153654716206
+ 2.6432265307445824
+ 2.643299404017445
+ 2.6433722745350767
+ 2.6434451422977596
+ 2.6435180073057776
+ 2.643590869559412
+ 2.6436637290589466
+ 2.6437365858046626
+ 2.6438094397968435
+ 2.6438822910357715
+ 2.643955139521729
+ 2.6440279852549984
+ 2.6441008282358616
+ 2.644173668464601
+ 2.6442465059414997
+ 2.6443193406668386
+ 2.6443921726409005
+ 2.6444650018639675
+ 2.644537828336321
+ 2.644610652058244
+ 2.644683473030018
+ 2.644756291251924
+ 2.644829106724245
+ 2.6449019194472627
+ 2.644974729421258
+ 2.645047536646513
+ 2.64512034112331
+ 2.6451931428519297
+ 2.6452659418326543
+ 2.645338738065765
+ 2.6454115315515425
+ 2.6454843222902698
+ 2.6455571102822275
+ 2.6456298955276965
+ 2.645702678026958
+ 2.645775457780295
+ 2.6458482347879864
+ 2.6459210090503142
+ 2.6459937805675597
+ 2.646066549340004
+ 2.6461393153679276
+ 2.6462120786516117
+ 2.6462848391913374
+ 2.646357596987385
+ 2.6464303520400354
+ 2.6465031043495704
+ 2.6465758539162696
+ 2.646648600740414
+ 2.646721344822284
+ 2.6467940861621604
+ 2.6468668247603238
+ 2.6469395606170543
+ 2.647012293732633
+ 2.6470850241073394
+ 2.647157751741455
+ 2.6472304766352583
+ 2.647303198789031
+ 2.647375918203053
+ 2.6474486348776045
+ 2.647521348812965
+ 2.6475940600094154
+ 2.6476667684672353
+ 2.647739474186704
+ 2.647812177168103
+ 2.6478848774117107
+ 2.6479575749178075
+ 2.6480302696866733
+ 2.648102961718587
+ 2.6481756510138297
+ 2.6482483375726797
+ 2.6483210213954176
+ 2.648393702482322
+ 2.648466380833673
+ 2.64853905644975
+ 2.6486117293308324
+ 2.6486843994771996
+ 2.6487570668891305
+ 2.6488297315669045
+ 2.6489023935108014
+ 2.6489750527210996
+ 2.6490477091980784
+ 2.6491203629420172
+ 2.6491930139531945
+ 2.64926566223189
+ 2.649338307778382
+ 2.64941095059295
+ 2.649483590675872
+ 2.649556228027427
+ 2.6496288626478948
+ 2.649701494537553
+ 2.6497741236966803
+ 2.649846750125556
+ 2.6499193738244577
+ 2.6499919947936648
+ 2.6500646130334555
+ 2.650137228544108
+ 2.6502098413259008
+ 2.650282451379112
+ 2.6503550587040205
+ 2.650427663300904
+ 2.6505002651700407
+ 2.6505728643117092
+ 2.650645460726187
+ 2.650718054413753
+ 2.6507906453746846
+ 2.650863233609259
+ 2.6509358191177554
+ 2.6510084019004516
+ 2.6510809819576244
+ 2.6511535592895528
+ 2.6512261338965137
+ 2.651298705778785
+ 2.6513712749366443
+ 2.651443841370369
+ 2.6515164050802373
+ 2.651588966066526
+ 2.651661524329513
+ 2.6517340798694757
+ 2.651806632686691
+ 2.6518791827814363
+ 2.6519517301539897
+ 2.6520242748046274
+ 2.652096816733627
+ 2.6521693559412656
+ 2.6522418924278206
+ 2.6523144261935685
+ 2.652386957238786
+ 2.6524594855637513
+ 2.6525320111687405
+ 2.6526045340540305
+ 2.652677054219898
+ 2.65274957166662
+ 2.652822086394473
+ 2.6528945984037335
+ 2.652967107694679
+ 2.653039614267585
+ 2.653112118122728
+ 2.6531846192603865
+ 2.6532571176808344
+ 2.6533296133843494
+ 2.653402106371207
+ 2.653474596641685
+ 2.6535470841960582
+ 2.653619569034604
+ 2.653692051157597
+ 2.6537645305653146
+ 2.6538370072580326
+ 2.653909481236026
+ 2.6539819524995734
+ 2.654054421048948
+ 2.654126886884427
+ 2.654199350006286
+ 2.6542718104148006
+ 2.6543442681102474
+ 2.6544167230929006
+ 2.6544891753630373
+ 2.654561624920932
+ 2.654634071766861
+ 2.6547065159011
+ 2.6547789573239235
+ 2.6548513960356077
+ 2.654923832036428
+ 2.6549962653266594
+ 2.6550686959065777
+ 2.655141123776457
+ 2.6552135489365742
+ 2.6552859713872037
+ 2.65535839112862
+ 2.6554308081610984
+ 2.6555032224849144
+ 2.6555756341003427
+ 2.6556480430076586
+ 2.6557204492071365
+ 2.6557928526990513
+ 2.6558652534836784
+ 2.6559376515612914
+ 2.656010046932166
+ 2.656082439596576
+ 2.656154829554797
+ 2.6562272168071033
+ 2.6562996013537687
+ 2.656371983195069
+ 2.656444362331277
+ 2.6565167387626683
+ 2.6565891124895167
+ 2.656661483512097
+ 2.6567338518306833
+ 2.656806217445549
+ 2.656878580356969
+ 2.6569509405652174
+ 2.6570232980705684
+ 2.657095652873295
+ 2.6571680049736726
+ 2.6572403543719743
+ 2.657312701068474
+ 2.657385045063446
+ 2.6574573863571636
+ 2.657529724949901
+ 2.6576020608419313
+ 2.6576743940335286
+ 2.6577467245249666
+ 2.657819052316519
+ 2.6578913774084585
+ 2.65796369980106
+ 2.6580360194945953
+ 2.6581083364893385
+ 2.658180650785563
+ 2.6582529623835423
+ 2.6583252712835495
+ 2.6583975774858577
+ 2.65846988099074
+ 2.6585421817984694
+ 2.65861447990932
+ 2.658686775323563
+ 2.6587590680414728
+ 2.6588313580633227
+ 2.658903645389384
+ 2.6589759300199307
+ 2.659048211955235
+ 2.65912049119557
+ 2.659192767741209
+ 2.6592650415924233
+ 2.659337312749487
+ 2.659409581212671
+ 2.6594818469822497
+ 2.6595541100584943
+ 2.6596263704416776
+ 2.6596986281320714
+ 2.659770883129949
+ 2.6598431354355827
+ 2.6599153850492443
+ 2.659987631971206
+ 2.6600598762017404
+ 2.660132117741119
+ 2.6602043565896145
+ 2.6602765927474987
+ 2.6603488262150434
+ 2.660421056992521
+ 2.6604932850802028
+ 2.6605655104783605
+ 2.6606377331872673
+ 2.660709953207194
+ 2.6607821705384116
+ 2.660854385181193
+ 2.660926597135809
+ 2.6609988064025325
+ 2.6610710129816333
+ 2.6611432168733846
+ 2.6612154180780556
+ 2.6612876165959207
+ 2.6613598124272486
+ 2.661432005572312
+ 2.661504196031382
+ 2.6615763838047295
+ 2.661648568892626
+ 2.6617207512953422
+ 2.66179293101315
+ 2.6618651080463196
+ 2.661937282395123
+ 2.6620094540598296
+ 2.662081623040712
+ 2.6621537893380403
+ 2.662225952952085
+ 2.662298113883118
+ 2.6623702721314086
+ 2.6624424276972283
+ 2.6625145805808477
+ 2.6625867307825377
+ 2.6626588783025684
+ 2.6627310231412102
+ 2.662803165298734
+ 2.6628753047754103
+ 2.6629474415715086
+ 2.6630195756873003
+ 2.6630917071230553
+ 2.6631638358790437
+ 2.663235961955536
+ 2.6633080853528015
+ 2.6633802060711123
+ 2.6634523241107364
+ 2.6635244394719444
+ 2.6635965521550067
+ 2.6636686621601933
+ 2.6637407694877737
+ 2.663812874138018
+ 2.663884976111196
+ 2.663957075407577
+ 2.664029172027431
+ 2.6641012659710284
+ 2.6641733572386377
+ 2.664245445830529
+ 2.664317531746972
+ 2.6643896149882362
+ 2.66446169555459
+ 2.6645337734463044
+ 2.664605848663648
+ 2.66467792120689
+ 2.6647499910763
+ 2.664822058272147
+ 2.6648941227947005
+ 2.664966184644229
+ 2.665038243821002
+ 2.665110300325289
+ 2.665182354157358
+ 2.6652544053174787
+ 2.66532645380592
+ 2.6653984996229507
+ 2.6654705427688397
+ 2.665542583243855
+ 2.6656146210482663
+ 2.6656866561823422
+ 2.665758688646351
+ 2.665830718440562
+ 2.6659027455652424
+ 2.665974770020662
+ 2.666046791807089
+ 2.6661188109247913
+ 2.666190827374038
+ 2.6662628411550973
+ 2.666334852268237
+ 2.6664068607137255
+ 2.6664788664918317
+ 2.666550869602823
+ 2.666622870046968
+ 2.6666948678245346
+ 2.666766862935791
+ 2.666838855381004
+ 2.6669108451604435
+ 2.666982832274377
+ 2.6670548167230708
+ 2.667126798506794
+ 2.667198777625815
+ 2.6672707540803997
+ 2.667342727870817
+ 2.6674146989973346
+ 2.6674866674602202
+ 2.6675586332597403
+ 2.6676305963961635
+ 2.6677025568697568
+ 2.667774514680788
+ 2.6678464698295237
+ 2.6679184223162316
+ 2.6679903721411793
+ 2.6680623193046342
+ 2.668134263806863
+ 2.668206205648133
+ 2.6682781448287116
+ 2.668350081348865
+ 2.668422015208862
+ 2.6684939464089674
+ 2.6685658749494494
+ 2.668637800830575
+ 2.668709724052611
+ 2.6687816446158235
+ 2.66885356252048
+ 2.6689254777668467
+ 2.6689973903551913
+ 2.6690693002857793
+ 2.6691412075588774
+ 2.6692131121747527
+ 2.669285014133671
+ 2.6693569134359003
+ 2.669428810081705
+ 2.669500704071353
+ 2.6695725954051097
+ 2.669644484083242
+ 2.6697163701060154
+ 2.6697882534736967
+ 2.669860134186552
+ 2.669932012244848
+ 2.6700038876488494
+ 2.6700757603988237
+ 2.670147630495036
+ 2.6702194979377523
+ 2.670291362727238
+ 2.67036322486376
+ 2.670435084347584
+ 2.6705069411789757
+ 2.6705787953581996
+ 2.670650646885523
+ 2.6707224957612103
+ 2.6707943419855287
+ 2.670866185558742
+ 2.6709380264811164
+ 2.6710098647529175
+ 2.671081700374411
+ 2.6711535333458616
+ 2.671225363667535
+ 2.671297191339696
+ 2.671369016362611
+ 2.6714408387365447
+ 2.6715126584617614
+ 2.671584475538527
+ 2.6716562899671064
+ 2.6717281017477648
+ 2.671799910880767
+ 2.6718717173663777
+ 2.671943521204863
+ 2.672015322396486
+ 2.6720871209415122
+ 2.6721589168402073
+ 2.672230710092835
+ 2.6723025006996606
+ 2.672374288660948
+ 2.672446073976962
+ 2.6725178566479677
+ 2.672589636674229
+ 2.672661414056011
+ 2.6727331887935777
+ 2.6728049608871935
+ 2.672876730337123
+ 2.67294849714363
+ 2.6730202613069793
+ 2.6730920228274346
+ 2.6731637817052607
+ 2.6732355379407204
+ 2.67330729153408
+ 2.6733790424856014
+ 2.6734507907955503
+ 2.673522536464189
+ 2.6735942794917826
+ 2.6736660198785946
+ 2.6737377576248886
+ 2.6738094927309284
+ 2.6738812251969786
+ 2.673952955023302
+ 2.674024682210162
+ 2.674096406757823
+ 2.674168128666549
+ 2.674239847936602
+ 2.6743115645682463
+ 2.6743832785617454
+ 2.6744549899173626
+ 2.6745266986353613
+ 2.6745984047160043
+ 2.674670108159556
+ 2.6747418089662784
+ 2.6748135071364354
+ 2.6748852026702905
+ 2.674956895568106
+ 2.6750285858301446
+ 2.6751002734566702
+ 2.6751719584479456
+ 2.6752436408042337
+ 2.675315320525797
+ 2.6753869976128986
+ 2.6754586720658016
+ 2.6755303438847684
+ 2.6756020130700615
+ 2.675673679621944
+ 2.675745343540678
+ 2.675817004826527
+ 2.6758886634797525
+ 2.6759603195006183
+ 2.676031972889385
+ 2.6761036236463163
+ 2.6761752717716747
+ 2.676246917265722
+ 2.6763185601287205
+ 2.6763902003609323
+ 2.6764618379626204
+ 2.6765334729340458
+ 2.6766051052754714
+ 2.6766767349871596
+ 2.6767483620693713
+ 2.676819986522369
+ 2.6768916083464154
+ 2.676963227541771
+ 2.6770348441086984
+ 2.6771064580474597
+ 2.677178069358316
+ 2.6772496780415302
+ 2.6773212840973626
+ 2.6773928875260755
+ 2.6774644883279297
+ 2.6775360865031885
+ 2.6776076820521117
+ 2.677679274974962
+ 2.677750865272
+ 2.677822452943487
+ 2.677894037989686
+ 2.677965620410856
+ 2.678037200207259
+ 2.678108777379157
+ 2.678180351926811
+ 2.6782519238504814
+ 2.67832349315043
+ 2.678395059826917
+ 2.678466623880204
+ 2.6785381853105523
+ 2.678609744118223
+ 2.6786813003034755
+ 2.6787528538665715
+ 2.6788244048077723
+ 2.678895953127338
+ 2.67896749882553
+ 2.679039041902608
+ 2.679110582358833
+ 2.679182120194466
+ 2.679253655409767
+ 2.679325188004997
+ 2.679396717980416
+ 2.679468245336285
+ 2.6795397700728634
+ 2.6796112921904123
+ 2.6796828116891915
+ 2.679754328569462
+ 2.6798258428314834
+ 2.679897354475516
+ 2.67996886350182
+ 2.680040369910655
+ 2.680111873702282
+ 2.68018337487696
+ 2.6802548734349494
+ 2.6803263693765103
+ 2.680397862701902
+ 2.680469353411385
+ 2.680540841505219
+ 2.6806123269836633
+ 2.680683809846977
+ 2.6807552900954215
+ 2.680826767729255
+ 2.680898242748738
+ 2.6809697151541285
+ 2.681041184945688
+ 2.6811126521236748
+ 2.6811841166883483
+ 2.681255578639968
+ 2.6813270379787935
+ 2.6813984947050837
+ 2.6814699488190983
+ 2.6815414003210956
+ 2.681612849211336
+ 2.681684295490077
+ 2.6817557391575795
+ 2.681827180214101
+ 2.681898618659902
+ 2.6819700544952396
+ 2.6820414877203738
+ 2.6821129183355636
+ 2.6821843463410677
+ 2.682255771737144
+ 2.6823271945240528
+ 2.682398614702051
+ 2.682470032271399
+ 2.682541447232354
+ 2.6826128595851753
+ 2.6826842693301214
+ 2.6827556764674507
+ 2.682827080997421
+ 2.682898482920292
+ 2.682969882236321
+ 2.6830412789457667
+ 2.6831126730488872
+ 2.683184064545941
+ 2.683255453437186
+ 2.6833268397228807
+ 2.6833982234032825
+ 2.6834696044786503
+ 2.6835409829492423
+ 2.683612358815315
+ 2.683683732077128
+ 2.683755102734938
+ 2.683826470789004
+ 2.6838978362395824
+ 2.6839691990869325
+ 2.6840405593313106
+ 2.6841119169729755
+ 2.684183272012184
+ 2.6842546244491943
+ 2.6843259742842633
+ 2.6843973215176495
+ 2.6844686661496104
+ 2.684540008180402
+ 2.684611347610283
+ 2.6846826844395104
+ 2.684754018668341
+ 2.6848253502970336
+ 2.6848966793258433
+ 2.684968005755029
+ 2.6850393295848467
+ 2.6851106508155547
+ 2.6851819694474086
+ 2.6852532854806666
+ 2.6853245989155856
+ 2.6853959097524216
+ 2.6854672179914325
+ 2.685538523632875
+ 2.6856098266770054
+ 2.685681127124081
+ 2.685752424974358
+ 2.6858237202280932
+ 2.685895012885544
+ 2.6859663029469663
+ 2.686037590412617
+ 2.686108875282752
+ 2.686180157557629
+ 2.6862514372375035
+ 2.686322714322632
+ 2.68639398881327
+ 2.686465260709676
+ 2.6865365300121047
+ 2.686607796720813
+ 2.686679060836056
+ 2.6867503223580913
+ 2.686821581287174
+ 2.6868928376235606
+ 2.686964091367507
+ 2.6870353425192692
+ 2.6871065910791034
+ 2.6871778370472654
+ 2.687249080424011
+ 2.687320321209596
+ 2.687391559404276
+ 2.6874627950083068
+ 2.687534028021944
+ 2.687605258445444
+ 2.687676486279062
+ 2.6877477115230533
+ 2.6878189341776735
+ 2.687890154243178
+ 2.687961371719823
+ 2.6880325866078634
+ 2.688103798907554
+ 2.688175008619151
+ 2.6882462157429092
+ 2.688317420279084
+ 2.6883886222279307
+ 2.6884598215897046
+ 2.6885310183646607
+ 2.6886022125530538
+ 2.688673404155139
+ 2.6887445931711715
+ 2.6888157796014065
+ 2.6888869634460986
+ 2.688958144705502
+ 2.6890293233798737
+ 2.689100499469466
+ 2.6891716729745347
+ 2.6892428438953346
+ 2.68931401223212
+ 2.6893851779851468
+ 2.6894563411546675
+ 2.6895275017409386
+ 2.6895986597442136
+ 2.689669815164747
+ 2.6897409680027935
+ 2.689812118258607
+ 2.6898832659324428
+ 2.689954411024554
+ 2.690025553535196
+ 2.690096693464622
+ 2.690167830813088
+ 2.6902389655808454
+ 2.6903100977681507
+ 2.6903812273752563
+ 2.6904523544024173
+ 2.6905234788498866
+ 2.69059460071792
+ 2.6906657200067694
+ 2.6907368367166895
+ 2.690807950847935
+ 2.690879062400758
+ 2.6909501713754134
+ 2.691021277772154
+ 2.691092381591234
+ 2.6911634828329074
+ 2.6912345814974272
+ 2.6913056775850475
+ 2.691376771096021
+ 2.6914478620306013
+ 2.691518950389043
+ 2.6915900361715974
+ 2.6916611193785194
+ 2.6917322000100614
+ 2.691803278066478
+ 2.691874353548021
+ 2.691945426454944
+ 2.6920164967874998
+ 2.6920875645459423
+ 2.6921586297305238
+ 2.692229692341498
+ 2.6923007523791176
+ 2.6923718098436344
+ 2.692442864735303
+ 2.692513917054376
+ 2.692584966801105
+ 2.6926560139757436
+ 2.6927270585785443
+ 2.69279810060976
+ 2.6928691400696434
+ 2.6929401769584467
+ 2.6930112112764224
+ 2.6930822430238237
+ 2.6931532722009024
+ 2.6932242988079116
+ 2.6932953228451026
+ 2.6933663443127287
+ 2.6934373632110424
+ 2.693508379540295
+ 2.6935793933007397
+ 2.693650404492628
+ 2.6937214131162124
+ 2.6937924191717446
+ 2.6938634226594775
+ 2.6939344235796625
+ 2.6940054219325513
+ 2.6940764177183967
+ 2.6941474109374504
+ 2.6942184015899637
+ 2.6942893896761886
+ 2.6943603751963776
+ 2.6944313581507813
+ 2.6945023385396523
+ 2.6945733163632424
+ 2.694644291621802
+ 2.694715264315584
+ 2.6947862344448392
+ 2.69485720200982
+ 2.6949281670107768
+ 2.6949991294479614
+ 2.6950700893216255
+ 2.69514104663202
+ 2.6952120013793963
+ 2.695282953564006
+ 2.6953539031861
+ 2.6954248502459297
+ 2.6954957947437466
+ 2.6955667366798006
+ 2.695637676054344
+ 2.695708612867627
+ 2.6957795471199013
+ 2.695850478811417
+ 2.6959214079424254
+ 2.695992334513178
+ 2.6960632585239246
+ 2.6961341799749166
+ 2.6962050988664044
+ 2.696276015198639
+ 2.696346928971871
+ 2.696417840186351
+ 2.69648874884233
+ 2.6965596549400574
+ 2.6966305584797845
+ 2.6967014594617624
+ 2.6967723578862404
+ 2.6968432537534692
+ 2.6969141470636995
+ 2.6969850378171807
+ 2.697055926014164
+ 2.697126811654899
+ 2.697197694739637
+ 2.697268575268627
+ 2.6973394532421193
+ 2.6974103286603643
+ 2.697481201523612
+ 2.697552071832112
+ 2.697622939586115
+ 2.6976938047858696
+ 2.697764667431627
+ 2.697835527523636
+ 2.697906385062147
+ 2.6979772400474102
+ 2.698048092479674
+ 2.6981189423591894
+ 2.698189789686205
+ 2.698260634460971
+ 2.6983314766837365
+ 2.6984023163547515
+ 2.698473153474265
+ 2.698543988042527
+ 2.6986148200597864
+ 2.698685649526292
+ 2.698756476442295
+ 2.6988273008080426
+ 2.698898122623785
+ 2.698968941889771
+ 2.6990397586062502
+ 2.699110572773472
+ 2.6991813843916845
+ 2.6992521934611373
+ 2.69932299998208
+ 2.6993938039547603
+ 2.699464605379428
+ 2.699535404256331
+ 2.6996062005857193
+ 2.6996769943678407
+ 2.699747785602945
+ 2.69981857429128
+ 2.6998893604330947
+ 2.699960144028638
+ 2.700030925078158
+ 2.7001017035819035
+ 2.7001724795401234
+ 2.700243252953065
+ 2.700314023820978
+ 2.7003847921441104
+ 2.7004555579227105
+ 2.7005263211570263
+ 2.700597081847307
+ 2.700667839993799
+ 2.7007385955967527
+ 2.7008093486564153
+ 2.7008800991730344
+ 2.700950847146859
+ 2.7010215925781362
+ 2.7010923354671146
+ 2.7011630758140424
+ 2.701233813619167
+ 2.7013045488827365
+ 2.701375281604998
+ 2.701446011786201
+ 2.7015167394265918
+ 2.7015874645264186
+ 2.7016581870859295
+ 2.7017289071053714
+ 2.701799624584992
+ 2.701870339525039
+ 2.7019410519257607
+ 2.7020117617874035
+ 2.702082469110216
+ 2.7021531738944438
+ 2.7022238761403354
+ 2.7022945758481387
+ 2.7023652730181005
+ 2.7024359676504672
+ 2.702506659745487
+ 2.702577349303407
+ 2.702648036324474
+ 2.702718720808935
+ 2.702789402757038
+ 2.7028600821690287
+ 2.702930759045155
+ 2.7030014333856633
+ 2.7030721051908007
+ 2.7031427744608143
+ 2.7032134411959503
+ 2.7032841053964565
+ 2.7033547670625784
+ 2.703425426194564
+ 2.7034960827926584
+ 2.70356673685711
+ 2.7036373883881644
+ 2.703708037386068
+ 2.703778683851067
+ 2.7038493277834093
+ 2.70391996918334
+ 2.703990608051106
+ 2.704061244386954
+ 2.7041318781911294
+ 2.704202509463879
+ 2.704273138205449
+ 2.704343764416086
+ 2.7044143880960356
+ 2.7044850092455435
+ 2.704555627864857
+ 2.7046262439542215
+ 2.704696857513883
+ 2.704767468544087
+ 2.70483807704508
+ 2.704908683017108
+ 2.704979286460417
+ 2.7050498873752513
+ 2.7051204857618587
+ 2.7051910816204834
+ 2.705261674951372
+ 2.7053322657547696
+ 2.7054028540309223
+ 2.7054734397800755
+ 2.705544023002474
+ 2.7056146036983644
+ 2.7056851818679917
+ 2.7057557575116014
+ 2.7058263306294386
+ 2.7058969012217484
+ 2.705967469288777
+ 2.7060380348307693
+ 2.70610859784797
+ 2.7061791583406247
+ 2.706249716308979
+ 2.7063202717532766
+ 2.7063908246737642
+ 2.706461375070686
+ 2.706531922944287
+ 2.706602468294812
+ 2.7066730111225064
+ 2.706743551427615
+ 2.7068140892103822
+ 2.706884624471053
+ 2.7069551572098725
+ 2.7070256874270844
+ 2.707096215122935
+ 2.707166740297667
+ 2.707237262951527
+ 2.707307783084758
+ 2.7073783006976058
+ 2.7074488157903134
+ 2.7075193283631265
+ 2.707589838416289
+ 2.7076603459500452
+ 2.7077308509646394
+ 2.7078013534603165
+ 2.7078718534373194
+ 2.7079423508958937
+ 2.7080128458362833
+ 2.708083338258732
+ 2.708153828163484
+ 2.7082243155507832
+ 2.7082948004208736
+ 2.7083652827739995
+ 2.7084357626104048
+ 2.7085062399303332
+ 2.708576714734029
+ 2.708647187021736
+ 2.7087176567936972
+ 2.7087881240501566
+ 2.7088585887913585
+ 2.708929051017546
+ 2.7089995107289626
+ 2.7090699679258528
+ 2.7091404226084594
+ 2.709210874777026
+ 2.709281324431797
+ 2.709351771573014
+ 2.709422216200922
+ 2.7094926583157637
+ 2.709563097917783
+ 2.709633535007222
+ 2.7097039695843246
+ 2.7097744016493346
+ 2.7098448312024943
+ 2.709915258244047
+ 2.7099856827742372
+ 2.710056104793306
+ 2.7101265243014967
+ 2.710196941299053
+ 2.710267355786218
+ 2.710337767763234
+ 2.7104081772303434
+ 2.7104785841877903
+ 2.710548988635817
+ 2.7106193905746663
+ 2.71068979000458
+ 2.710760186925802
+ 2.7108305813385747
+ 2.7109009732431395
+ 2.7109713626397407
+ 2.7110417495286194
+ 2.7111121339100195
+ 2.711182515784182
+ 2.7112528951513504
+ 2.711323272011767
+ 2.7113936463656727
+ 2.7114640182133116
+ 2.711534387554925
+ 2.711604754390755
+ 2.7116751187210446
+ 2.7117454805460355
+ 2.711815839865969
+ 2.711886196681088
+ 2.7119565509916352
+ 2.7120269027978514
+ 2.7120972520999787
+ 2.7121675988982594
+ 2.712237943192935
+ 2.712308284984248
+ 2.7123786242724397
+ 2.712448961057752
+ 2.712519295340426
+ 2.712589627120704
+ 2.712659956398828
+ 2.7127302831750395
+ 2.712800607449579
+ 2.7128709292226887
+ 2.7129412484946105
+ 2.7130115652655857
+ 2.713081879535855
+ 2.7131521913056607
+ 2.7132225005752435
+ 2.7132928073448452
+ 2.7133631116147066
+ 2.7134334133850686
+ 2.713503712656174
+ 2.713574009428262
+ 2.713644303701575
+ 2.7137145954763535
+ 2.7137848847528385
+ 2.7138551715312715
+ 2.7139254558118933
+ 2.713995737594944
+ 2.7140660168806656
+ 2.7141362936692985
+ 2.714206567961083
+ 2.714276839756261
+ 2.714347109055072
+ 2.714417375857758
+ 2.7144876401645583
+ 2.7145579019757142
+ 2.7146281612914662
+ 2.7146984181120555
+ 2.7147686724377214
+ 2.714838924268705
+ 2.7149091736052466
+ 2.714979420447587
+ 2.7150496647959663
+ 2.7151199066506244
+ 2.715190146011802
+ 2.7152603828797393
+ 2.715330617254677
+ 2.715400849136854
+ 2.7154710785265115
+ 2.7155413054238884
+ 2.7156115298292267
+ 2.7156817517427645
+ 2.715751971164743
+ 2.7158221880954017
+ 2.71589240253498
+ 2.7159626144837192
+ 2.7160328239418576
+ 2.7161030309096357
+ 2.716173235387293
+ 2.71624343737507
+ 2.716313636873205
+ 2.7163838338819386
+ 2.7164540284015106
+ 2.7165242204321594
+ 2.716594409974126
+ 2.7166645970276484
+ 2.716734781592967
+ 2.7168049636703215
+ 2.71687514325995
+ 2.716945320362093
+ 2.7170154949769896
+ 2.7170856671048784
+ 2.717155836745999
+ 2.7172260039005915
+ 2.7172961685688937
+ 2.717366330751145
+ 2.717436490447585
+ 2.717506647658452
+ 2.717576802383986
+ 2.7176469546244255
+ 2.717717104380009
+ 2.7177872516509756
+ 2.7178573964375645
+ 2.717927538740014
+ 2.7179976785585636
+ 2.718067815893451
+ 2.7181379507449157
+ 2.718208083113196
+ 2.718278212998531
+ 2.718348340401159
+ 2.718418465321318
+ 2.7184885877592473
+ 2.7185587077151854
+ 2.7186288251893695
+ 2.7186989401820396
+ 2.7187690526934336
+ 2.7188391627237887
+ 2.7189092702733446
+ 2.7189793753423395
+ 2.7190494779310104
+ 2.7191195780395967
+ 2.719189675668336
+ 2.719259770817467
+ 2.719329863487226
+ 2.719399953677853
+ 2.719470041389585
+ 2.7195401266226598
+ 2.7196102093773162
+ 2.719680289653792
+ 2.719750367452324
+ 2.719820442773151
+ 2.71989051561651
+ 2.719960585982639
+ 2.7200306538717762
+ 2.720100719284159
+ 2.7201707822200247
+ 2.720240842679611
+ 2.720310900663155
+ 2.7203809561708954
+ 2.7204510092030687
+ 2.7205210597599128
+ 2.7205911078416647
+ 2.720661153448562
+ 2.7207311965808425
+ 2.7208012372387422
+ 2.7208712754224993
+ 2.720941311132351
+ 2.721011344368534
+ 2.7210813751312855
+ 2.7211514034208433
+ 2.7212214292374437
+ 2.7212914525813243
+ 2.7213614734527214
+ 2.7214314918518725
+ 2.7215015077790143
+ 2.721571521234383
+ 2.721641532218217
+ 2.7217115407307526
+ 2.7217815467722253
+ 2.7218515503428735
+ 2.7219215514429327
+ 2.72199155007264
+ 2.722061546232232
+ 2.722131539921945
+ 2.7222015311420162
+ 2.7222715198926815
+ 2.7223415061741774
+ 2.7224114899867407
+ 2.7224814713306076
+ 2.7225514502060144
+ 2.722621426613198
+ 2.7226914005523932
+ 2.7227613720238377
+ 2.722831341027767
+ 2.7229013075644177
+ 2.7229712716340257
+ 2.723041233236827
+ 2.723111192373058
+ 2.7231811490429547
+ 2.723251103246753
+ 2.723321054984688
+ 2.7233910042569964
+ 2.723460951063914
+ 2.723530895405677
+ 2.723600837282521
+ 2.7236707766946813
+ 2.7237407136423943
+ 2.723810648125895
+ 2.7238805801454196
+ 2.723950509701204
+ 2.724020436793482
+ 2.724090361422492
+ 2.724160283588467
+ 2.7242302032916434
+ 2.724300120532257
+ 2.724370035310543
+ 2.724439947626737
+ 2.7245098574810735
+ 2.724579764873788
+ 2.724649669805116
+ 2.7247195722752933
+ 2.7247894722845545
+ 2.724859369833134
+ 2.724929264921268
+ 2.7249991575491914
+ 2.725069047717139
+ 2.725138935425346
+ 2.725208820674047
+ 2.7252787034634767
+ 2.7253485837938713
+ 2.725418461665464
+ 2.725488337078491
+ 2.725558210033186
+ 2.725628080529784
+ 2.7256979485685204
+ 2.7257678141496293
+ 2.7258376772733457
+ 2.725907537939903
+ 2.7259773961495375
+ 2.726047251902482
+ 2.726117105198972
+ 2.7261869560392427
+ 2.7262568044235267
+ 2.7263266503520596
+ 2.7263964938250753
+ 2.7264663348428084
+ 2.726536173405493
+ 2.7266060095133633
+ 2.7266758431666527
+ 2.726745674365597
+ 2.726815503110429
+ 2.726885329401384
+ 2.726955153238695
+ 2.727024974622596
+ 2.7270947935533214
+ 2.7271646100311053
+ 2.727234424056181
+ 2.7273042356287824
+ 2.7273740447491446
+ 2.7274438514174997
+ 2.7275136556340818
+ 2.7275834573991253
+ 2.727653256712864
+ 2.727723053575531
+ 2.7277928479873594
+ 2.727862639948584
+ 2.727932429459437
+ 2.7280022165201534
+ 2.7280720011309656
+ 2.728141783292107
+ 2.7282115630038115
+ 2.7282813402663124
+ 2.728351115079843
+ 2.7284208874446367
+ 2.7284906573609256
+ 2.728560424828945
+ 2.728630189848926
+ 2.7286999524211026
+ 2.728769712545708
+ 2.7288394702229755
+ 2.7289092254531377
+ 2.7289789782364275
+ 2.7290487285730785
+ 2.729118476463323
+ 2.729188221907394
+ 2.7292579649055244
+ 2.7293277054579472
+ 2.729397443564895
+ 2.7294671792266003
+ 2.7295369124432964
+ 2.7296066432152157
+ 2.7296763715425905
+ 2.729746097425654
+ 2.729815820864638
+ 2.7298855418597756
+ 2.729955260411299
+ 2.7300249765194406
+ 2.730094690184434
+ 2.7301644014065096
+ 2.730234110185901
+ 2.7303038165228397
+ 2.730373520417559
+ 2.7304432218702908
+ 2.730512920881267
+ 2.7305826174507195
+ 2.730652311578881
+ 2.7307220032659836
+ 2.730791692512259
+ 2.7308613793179393
+ 2.730931063683257
+ 2.7310007456084433
+ 2.7310704250937303
+ 2.7311401021393498
+ 2.731209776745535
+ 2.7312794489125154
+ 2.731349118640524
+ 2.731418785929792
+ 2.7314884507805526
+ 2.7315581131930355
+ 2.7316277731674736
+ 2.7316974307040978
+ 2.73176708580314
+ 2.731836738464832
+ 2.7319063886894046
+ 2.73197603647709
+ 2.732045681828119
+ 2.732115324742723
+ 2.732184965221134
+ 2.7322546032635824
+ 2.7323242388702993
+ 2.7323938720415173
+ 2.732463502777467
+ 2.7325331310783785
+ 2.732602756944484
+ 2.7326723803760142
+ 2.7327420013732007
+ 2.7328116199362738
+ 2.732881236065465
+ 2.732950849761005
+ 2.733020461023125
+ 2.7330900698520555
+ 2.733159676248027
+ 2.7332292802112708
+ 2.733298881742018
+ 2.7333684808404985
+ 2.733438077506944
+ 2.7335076717415845
+ 2.7335772635446505
+ 2.7336468529163724
+ 2.7337164398569813
+ 2.733786024366708
+ 2.733855606445782
+ 2.7339251860944347
+ 2.7339947633128956
+ 2.7340643381013963
+ 2.734133910460166
+ 2.7342034803894353
+ 2.734273047889434
+ 2.7343426129603934
+ 2.7344121756025435
+ 2.734481735816114
+ 2.734551293601335
+ 2.734620848958437
+ 2.734690401887649
+ 2.7347599523892026
+ 2.734829500463327
+ 2.7348990461102516
+ 2.734968589330207
+ 2.7350381301234234
+ 2.735107668490129
+ 2.735177204430556
+ 2.7352467379449323
+ 2.7353162690334885
+ 2.7353857976964537
+ 2.735455323934058
+ 2.735524847746531
+ 2.7355943691341027
+ 2.7356638880970015
+ 2.7357334046354573
+ 2.735802918749701
+ 2.73587243043996
+ 2.735941939706465
+ 2.736011446549445
+ 2.736080950969129
+ 2.7361504529657474
+ 2.7362199525395283
+ 2.7362894496907013
+ 2.7363589444194956
+ 2.7364284367261402
+ 2.736497926610865
+ 2.7365674140738983
+ 2.7366368991154695
+ 2.7367063817358073
+ 2.7367758619351408
+ 2.7368453397136996
+ 2.7369148150717115
+ 2.7369842880094066
+ 2.7370537585270127
+ 2.7371232266247585
+ 2.7371926923028744
+ 2.7372621555615875
+ 2.7373316164011268
+ 2.7374010748217215
+ 2.7374705308236003
+ 2.737539984406991
+ 2.7376094355721228
+ 2.7376788843192235
+ 2.7377483306485226
+ 2.7378177745602477
+ 2.7378872160546286
+ 2.737956655131892
+ 2.7380260917922663
+ 2.7380955260359814
+ 2.7381649578632645
+ 2.7382343872743435
+ 2.7383038142694476
+ 2.7383732388488045
+ 2.7384426610126424
+ 2.738512080761189
+ 2.7385814980946726
+ 2.7386509130133216
+ 2.738720325517364
+ 2.7387897356070274
+ 2.7388591432825398
+ 2.738928548544129
+ 2.7389979513920233
+ 2.7390673518264497
+ 2.739136749847636
+ 2.7392061454558116
+ 2.739275538651203
+ 2.7393449294340377
+ 2.739414317804543
+ 2.7394837037629483
+ 2.739553087309479
+ 2.7396224684443644
+ 2.739691847167831
+ 2.7397612234801065
+ 2.7398305973814185
+ 2.739899968871994
+ 2.7399693379520604
+ 2.7400387046218464
+ 2.7401080688815775
+ 2.7401774307314812
+ 2.740246790171786
+ 2.740316147202718
+ 2.7403855018245045
+ 2.7404548540373734
+ 2.7405242038415505
+ 2.7405935512372634
+ 2.7406628962247397
+ 2.7407322388042057
+ 2.740801578975889
+ 2.740870916740015
+ 2.740940252096813
+ 2.7410095850465077
+ 2.7410789155893265
+ 2.741148243725497
+ 2.741217569455245
+ 2.7412868927787977
+ 2.7413562136963816
+ 2.7414255322082233
+ 2.7414948483145496
+ 2.741564162015587
+ 2.7416334733115617
+ 2.7417027822027005
+ 2.7417720886892303
+ 2.7418413927713763
+ 2.7419106944493663
+ 2.7419799937234255
+ 2.7420492905937808
+ 2.742118585060658
+ 2.742187877124285
+ 2.742257166784886
+ 2.7423264540426877
+ 2.7423957388979168
+ 2.7424650213507995
+ 2.742534301401561
+ 2.7426035790504284
+ 2.7426728542976266
+ 2.7427421271433827
+ 2.7428113975879214
+ 2.74288066563147
+ 2.742949931274253
+ 2.7430191945164974
+ 2.7430884553584285
+ 2.743157713800272
+ 2.743226969842253
+ 2.743296223484599
+ 2.743365474727534
+ 2.7434347235712844
+ 2.743503970016075
+ 2.743573214062133
+ 2.743642455709682
+ 2.743711694958949
+ 2.743780931810158
+ 2.7438501662635364
+ 2.7439193983193078
+ 2.743988627977698
+ 2.7440578552389328
+ 2.744127080103237
+ 2.7441963025708365
+ 2.744265522641956
+ 2.74433474031682
+ 2.744403955595655
+ 2.744473168478686
+ 2.7445423789661363
+ 2.7446115870582326
+ 2.7446807927552004
+ 2.744749996057263
+ 2.7448191969646465
+ 2.7448883954775747
+ 2.7449575915962745
+ 2.7450267853209684
+ 2.745095976651882
+ 2.7451651655892415
+ 2.74523435213327
+ 2.7453035362841924
+ 2.745372718042234
+ 2.7454418974076185
+ 2.745511074380571
+ 2.7455802489613164
+ 2.745649421150079
+ 2.745718590947083
+ 2.745787758352553
+ 2.745856923366714
+ 2.7459260859897894
+ 2.745995246222004
+ 2.746064404063582
+ 2.7461335595147482
+ 2.7462027125757267
+ 2.746271863246741
+ 2.746341011528016
+ 2.7464101574197755
+ 2.746479300922244
+ 2.746548442035645
+ 2.746617580760203
+ 2.746686717096142
+ 2.7467558510436856
+ 2.746824982603058
+ 2.7468941117744836
+ 2.7469632385581857
+ 2.7470323629543874
+ 2.747101484963314
+ 2.7471706045851887
+ 2.7472397218202347
+ 2.7473088366686764
+ 2.747377949130737
+ 2.7474470592066407
+ 2.74751616689661
+ 2.74758527220087
+ 2.747654375119643
+ 2.7477234756531534
+ 2.747792573801624
+ 2.747861669565278
+ 2.74793076294434
+ 2.747999853939032
+ 2.748068942549578
+ 2.748138028776201
+ 2.7482071126191245
+ 2.7482761940785716
+ 2.748345273154766
+ 2.74841434984793
+ 2.7484834241582874
+ 2.7485524960860612
+ 2.748621565631474
+ 2.7486906327947493
+ 2.74875969757611
+ 2.7488287599757784
+ 2.7488978199939784
+ 2.748966877630932
+ 2.7490359328868634
+ 2.7491049857619942
+ 2.749174036256547
+ 2.749243084370745
+ 2.7493121301048116
+ 2.7493811734589686
+ 2.7494502144334385
+ 2.7495192530284447
+ 2.749588289244209
+ 2.749657323080955
+ 2.7497263545389035
+ 2.7497953836182787
+ 2.7498644103193026
+ 2.749933434642197
+ 2.7500024565871843
+ 2.7500714761544875
+ 2.7501404933443285
+ 2.7502095081569293
+ 2.7502785205925133
+ 2.750347530651301
+ 2.7504165383335164
+ 2.75048554363938
+ 2.7505545465691146
+ 2.7506235471229425
+ 2.7506925453010855
+ 2.750761541103765
+ 2.750830534531204
+ 2.7508995255836246
+ 2.7509685142612477
+ 2.7510375005642946
+ 2.7511064844929893
+ 2.751175466047552
+ 2.7512444452282048
+ 2.751313422035169
+ 2.7513823964686677
+ 2.751451368528921
+ 2.7515203382161517
+ 2.751589305530581
+ 2.7516582704724297
+ 2.7517272330419202
+ 2.751796193239274
+ 2.7518651510647123
+ 2.7519341065184557
+ 2.752003059600727
+ 2.752072010311747
+ 2.7521409586517374
+ 2.7522099046209187
+ 2.752278848219513
+ 2.7523477894477404
+ 2.752416728305823
+ 2.7524856647939817
+ 2.752554598912438
+ 2.7526235306614124
+ 2.7526924600411267
+ 2.7527613870518004
+ 2.752830311693656
+ 2.7528992339669145
+ 2.752968153871796
+ 2.7530370714085217
+ 2.7531059865773124
+ 2.753174899378389
+ 2.7532438098119725
+ 2.7533127178782824
+ 2.7533816235775412
+ 2.7534505269099685
+ 2.7535194278757857
+ 2.753588326475213
+ 2.7536572227084704
+ 2.753726116575779
+ 2.75379500807736
+ 2.7538638972134324
+ 2.7539327839842183
+ 2.7540016683899373
+ 2.7540705504308094
+ 2.7541394301070548
+ 2.754208307418895
+ 2.7542771823665495
+ 2.754346054950239
+ 2.7544149251701833
+ 2.754483793026602
+ 2.754552658519717
+ 2.7546215216497463
+ 2.7546903824169116
+ 2.754759240821432
+ 2.754828096863528
+ 2.7548969505434195
+ 2.7549658018613266
+ 2.755034650817469
+ 2.7551034974120667
+ 2.7551723416453395
+ 2.7552411835175072
+ 2.7553100230287892
+ 2.755378860179406
+ 2.7554476949695768
+ 2.7555165273995215
+ 2.7555853574694593
+ 2.7556541851796106
+ 2.7557230105301946
+ 2.755791833521431
+ 2.755860654153538
+ 2.755929472426738
+ 2.7559982883412473
+ 2.7560671018972873
+ 2.7561359130950764
+ 2.7562047219348345
+ 2.7562735284167807
+ 2.7563423325411343
+ 2.7564111343081144
+ 2.7564799337179404
+ 2.756548730770832
+ 2.7566175254670067
+ 2.7566863178066856
+ 2.7567551077900867
+ 2.7568238954174293
+ 2.7568926806889325
+ 2.756961463604815
+ 2.757030244165296
+ 2.757099022370594
+ 2.757167798220929
+ 2.7572365717165184
+ 2.757305342857581
+ 2.7573741116443373
+ 2.7574428780770046
+ 2.757511642155803
+ 2.7575804038809486
+ 2.7576491632526627
+ 2.7577179202711624
+ 2.7577866749366673
+ 2.757855427249395
+ 2.7579241772095644
+ 2.7579929248173944
+ 2.758061670073103
+ 2.758130412976908
+ 2.7581991535290293
+ 2.7582678917296843
+ 2.7583366275790917
+ 2.758405361077469
+ 2.7584740922250353
+ 2.758542821022008
+ 2.7586115474686066
+ 2.758680271565048
+ 2.7587489933115505
+ 2.7588177127083333
+ 2.758886429755613
+ 2.7589551444536085
+ 2.759023856802538
+ 2.759092566802618
+ 2.759161274454068
+ 2.759229979757105
+ 2.7592986827119477
+ 2.7593673833188133
+ 2.7594360815779195
+ 2.7595047774894845
+ 2.7595734710537254
+ 2.7596421622708607
+ 2.759710851141107
+ 2.759779537664683
+ 2.7598482218418057
+ 2.759916903672693
+ 2.759985583157562
+ 2.760054260296631
+ 2.7601229350901164
+ 2.760191607538236
+ 2.7602602776412075
+ 2.7603289453992486
+ 2.760397610812576
+ 2.7604662738814065
+ 2.7605349346059582
+ 2.760603592986448
+ 2.7606722490230937
+ 2.760740902716112
+ 2.7608095540657196
+ 2.760878203072134
+ 2.7609468497355727
+ 2.7610154940562524
+ 2.76108413603439
+ 2.761152775670202
+ 2.761221412963906
+ 2.761290047915719
+ 2.7613586805258574
+ 2.7614273107945384
+ 2.761495938721979
+ 2.761564564308395
+ 2.761633187554004
+ 2.7617018084590224
+ 2.7617704270236674
+ 2.761839043248155
+ 2.761907657132702
+ 2.761976268677525
+ 2.76204487788284
+ 2.762113484748865
+ 2.762182089275815
+ 2.762250691463907
+ 2.762319291313357
+ 2.7623878888243825
+ 2.762456483997199
+ 2.7625250768320226
+ 2.76259366732907
+ 2.7626622554885576
+ 2.7627308413107015
+ 2.762799424795717
+ 2.762868005943822
+ 2.7629365847552307
+ 2.763005161230161
+ 2.763073735368828
+ 2.763142307171447
+ 2.7632108766382357
+ 2.763279443769409
+ 2.7633480085651825
+ 2.7634165710257728
+ 2.7634851311513953
+ 2.7635536889422667
+ 2.7636222443986016
+ 2.7636907975206166
+ 2.763759348308527
+ 2.7638278967625487
+ 2.7638964428828974
+ 2.7639649866697886
+ 2.764033528123438
+ 2.764102067244061
+ 2.7641706040318734
+ 2.76423913848709
+ 2.764307670609927
+ 2.7643762004006005
+ 2.764444727859324
+ 2.7645132529863146
+ 2.764581775781787
+ 2.764650296245956
+ 2.7647188143790373
+ 2.764787330181246
+ 2.7648558436527986
+ 2.764924354793908
+ 2.764992863604791
+ 2.7650613700856623
+ 2.7651298742367367
+ 2.7651983760582297
+ 2.7652668755503558
+ 2.7653353727133303
+ 2.7654038675473687
+ 2.7654723600526845
+ 2.7655408502294936
+ 2.765609338078011
+ 2.765677823598451
+ 2.765746306791029
+ 2.7658147876559585
+ 2.7658832661934554
+ 2.7659517424037343
+ 2.7660202162870093
+ 2.7660886878434954
+ 2.7661571570734074
+ 2.766225623976959
+ 2.766294088554366
+ 2.766362550805842
+ 2.7664310107316012
+ 2.766499468331859
+ 2.766567923606829
+ 2.7666363765567263
+ 2.7667048271817647
+ 2.7667732754821586
+ 2.7668417214581225
+ 2.76691016510987
+ 2.7669786064376156
+ 2.7670470454415743
+ 2.7671154821219592
+ 2.767183916478985
+ 2.7672523485128653
+ 2.7673207782238145
+ 2.7673892056120466
+ 2.767457630677775
+ 2.7675260534212147
+ 2.767594473842579
+ 2.7676628919420816
+ 2.767731307719937
+ 2.7677997211763588
+ 2.7678681323115595
+ 2.7679365411257546
+ 2.7680049476191577
+ 2.7680733517919816
+ 2.7681417536444406
+ 2.7682101531767476
+ 2.768278550389117
+ 2.7683469452817624
+ 2.7684153378548966
+ 2.7684837281087336
+ 2.768552116043486
+ 2.768620501659369
+ 2.7686888849565947
+ 2.7687572659353767
+ 2.7688256445959283
+ 2.768894020938463
+ 2.768962394963194
+ 2.7690307666703347
+ 2.7690991360600976
+ 2.769167503132697
+ 2.7692358678883453
+ 2.769304230327256
+ 2.769372590449642
+ 2.7694409482557156
+ 2.7695093037456915
+ 2.769577656919781
+ 2.7696460077781984
+ 2.7697143563211553
+ 2.769782702548866
+ 2.7698510464615422
+ 2.7699193880593973
+ 2.7699877273426443
+ 2.7700560643114955
+ 2.7701243989661637
+ 2.770192731306862
+ 2.770261061333802
+ 2.7703293890471983
+ 2.7703977144472614
+ 2.770466037534205
+ 2.7705343583082414
+ 2.7706026767695833
+ 2.770670992918443
+ 2.7707393067550328
+ 2.770807618279566
+ 2.7708759274922534
+ 2.770944234393308
+ 2.7710125389829434
+ 2.77108084126137
+ 2.771149141228801
+ 2.7712174388854485
+ 2.7712857342315247
+ 2.771354027267242
+ 2.771422317992812
+ 2.7714906064084466
+ 2.7715588925143595
+ 2.7716271763107607
+ 2.7716954577978634
+ 2.771763736975879
+ 2.7718320138450196
+ 2.7719002884054977
+ 2.771968560657524
+ 2.7720368306013117
+ 2.7721050982370716
+ 2.7721733635650163
+ 2.7722416265853562
+ 2.772309887298304
+ 2.7723781457040713
+ 2.7724464018028696
+ 2.7725146555949114
+ 2.7725829070804067
+ 2.772651156259568
+ 2.772719403132607
+ 2.7727876476997344
+ 2.7728558899611624
+ 2.7729241299171017
+ 2.7729923675677646
+ 2.773060602913362
+ 2.7731288359541053
+ 2.773197066690206
+ 2.773265295121875
+ 2.7733335212493233
+ 2.7734017450727624
+ 2.7734699665924043
+ 2.773538185808459
+ 2.7736064027211382
+ 2.773674617330653
+ 2.773742829637214
+ 2.773811039641032
+ 2.773879247342319
+ 2.7739474527412855
+ 2.774015655838142
+ 2.7740838566331005
+ 2.77415205512637
+ 2.7742202513181633
+ 2.77428844520869
+ 2.7743566367981614
+ 2.7744248260867876
+ 2.7744930130747805
+ 2.7745611977623494
+ 2.774629380149706
+ 2.7746975602370605
+ 2.774765738024623
+ 2.7748339135126048
+ 2.774902086701216
+ 2.774970257590667
+ 2.775038426181169
+ 2.7751065924729312
+ 2.775174756466165
+ 2.7752429181610805
+ 2.7753110775578884
+ 2.775379234656798
+ 2.7754473894580203
+ 2.775515541961765
+ 2.775583692168243
+ 2.775651840077664
+ 2.7757199856902384
+ 2.775788129006176
+ 2.775856270025687
+ 2.7759244087489816
+ 2.77599254517627
+ 2.7760606793077613
+ 2.7761288111436664
+ 2.7761969406841946
+ 2.776265067929556
+ 2.776333192879961
+ 2.776401315535619
+ 2.7764694358967392
+ 2.776537553963532
+ 2.776605669736207
+ 2.7766737832149744
+ 2.7767418944000424
+ 2.7768100032916228
+ 2.7768781098899233
+ 2.7769462141951538
+ 2.777014316207525
+ 2.7770824159272456
+ 2.777150513354525
+ 2.7772186084895725
+ 2.7772867013325984
+ 2.7773547918838113
+ 2.7774228801434204
+ 2.777490966111636
+ 2.7775590497886666
+ 2.777627131174721
+ 2.77769521027001
+ 2.777763287074741
+ 2.777831361589125
+ 2.77789943381337
+ 2.7779675037476843
+ 2.7780355713922784
+ 2.7781036367473613
+ 2.7781716998131416
+ 2.778239760589828
+ 2.7783078190776305
+ 2.7783758752767564
+ 2.7784439291874157
+ 2.7785119808098178
+ 2.77858003014417
+ 2.778648077190682
+ 2.778716121949562
+ 2.7787841644210194
+ 2.778852204605263
+ 2.778920242502501
+ 2.778988278112942
+ 2.7790563114367948
+ 2.779124342474268
+ 2.7791923712255704
+ 2.77926039769091
+ 2.7793284218704954
+ 2.7793964437645355
+ 2.779464463373238
+ 2.779532480696812
+ 2.779600495735465
+ 2.7796685084894066
+ 2.7797365189588437
+ 2.7798045271439857
+ 2.7798725330450402
+ 2.7799405366622154
+ 2.78000853799572
+ 2.780076537045762
+ 2.780144533812549
+ 2.7802125282962895
+ 2.7802805204971914
+ 2.7803485104154624
+ 2.780416498051311
+ 2.780484483404946
+ 2.780552466476573
+ 2.780620447266402
+ 2.78068842577464
+ 2.780756402001495
+ 2.7808243759471747
+ 2.780892347611887
+ 2.7809603169958392
+ 2.7810282840992397
+ 2.7810962489222963
+ 2.7811642114652155
+ 2.781232171728206
+ 2.7813001297114748
+ 2.7813680854152296
+ 2.7814360388396784
+ 2.781503989985028
+ 2.781571938851487
+ 2.781639885439261
+ 2.7817078297485587
+ 2.781775771779587
+ 2.7818437115325536
+ 2.781911649007666
+ 2.7819795842051303
+ 2.782047517125155
+ 2.7821154477679473
+ 2.782183376133714
+ 2.782251302222661
+ 2.782319226034998
+ 2.7823871475709305
+ 2.7824550668306656
+ 2.7825229838144105
+ 2.7825908985223724
+ 2.782658810954758
+ 2.782726721111774
+ 2.7827946289936283
+ 2.782862534600527
+ 2.782930437932677
+ 2.7829983389902857
+ 2.783066237773559
+ 2.783134134282704
+ 2.7832020285179278
+ 2.7832699204794364
+ 2.7833378101674375
+ 2.7834056975821366
+ 2.7834735827237407
+ 2.7835414655924566
+ 2.7836093461884914
+ 2.7836772245120507
+ 2.783745100563341
+ 2.7838129743425686
+ 2.7838808458499407
+ 2.783948715085663
+ 2.784016582049943
+ 2.7840844467429853
+ 2.7841523091649973
+ 2.784220169316185
+ 2.784288027196755
+ 2.7843558828069135
+ 2.7844237361468656
+ 2.7844915872168183
+ 2.7845594360169783
+ 2.7846272825475507
+ 2.7846951268087414
+ 2.784762968800757
+ 2.784830808523804
+ 2.7848986459780876
+ 2.7849664811638135
+ 2.785034314081188
+ 2.785102144730417
+ 2.7851699731117066
+ 2.7852377992252624
+ 2.78530562307129
+ 2.785373444649995
+ 2.7854412639615833
+ 2.785509081006261
+ 2.7855768957842333
+ 2.7856447082957057
+ 2.7857125185408838
+ 2.785780326519974
+ 2.7858481322331814
+ 2.785915935680711
+ 2.785983736862768
+ 2.7860515357795594
+ 2.7861193324312894
+ 2.786187126818164
+ 2.786254918940388
+ 2.786322708798166
+ 2.786390496391705
+ 2.78645828172121
+ 2.786526064786885
+ 2.7865938455889365
+ 2.7866616241275683
+ 2.786729400402987
+ 2.7867971744153968
+ 2.7868649461650032
+ 2.786932715652011
+ 2.7870004828766253
+ 2.787068247839051
+ 2.7871360105394936
+ 2.787203770978157
+ 2.7872715291552472
+ 2.7873392850709684
+ 2.7874070387255254
+ 2.787474790119124
+ 2.7875425392519673
+ 2.787610286124261
+ 2.78767803073621
+ 2.7877457730880186
+ 2.787813513179892
+ 2.787881251012034
+ 2.787948986584649
+ 2.788016719897943
+ 2.7880844509521197
+ 2.7881521797473834
+ 2.7882199062839392
+ 2.7882876305619906
+ 2.7883553525817426
+ 2.7884230723434
+ 2.7884907898471663
+ 2.788558505093247
+ 2.788626218081845
+ 2.788693928813165
+ 2.7887616372874118
+ 2.788829343504789
+ 2.788897047465501
+ 2.788964749169752
+ 2.7890324486177462
+ 2.7891001458096873
+ 2.7891678407457796
+ 2.789235533426227
+ 2.7893032238512343
+ 2.789370912021004
+ 2.789438597935741
+ 2.7895062815956493
+ 2.789573963000932
+ 2.789641642151794
+ 2.789709319048438
+ 2.789776993691069
+ 2.789844666079889
+ 2.789912336215104
+ 2.789980004096916
+ 2.790047669725529
+ 2.790115333101147
+ 2.790182994223973
+ 2.7902506530942115
+ 2.790318309712065
+ 2.7903859640777378
+ 2.7904536161914333
+ 2.790521266053354
+ 2.7905889136637048
+ 2.7906565590226884
+ 2.7907242021305074
+ 2.7907918429873666
+ 2.790859481593468
+ 2.790927117949016
+ 2.7909947520542127
+ 2.7910623839092623
+ 2.7911300135143673
+ 2.791197640869732
+ 2.7912652659755577
+ 2.7913328888320486
+ 2.791400509439408
+ 2.791468127797838
+ 2.7915357439075423
+ 2.791603357768724
+ 2.791670969381585
+ 2.79173857874633
+ 2.79180618586316
+ 2.7918737907322795
+ 2.79194139335389
+ 2.792008993728195
+ 2.792076591855397
+ 2.792144187735699
+ 2.792211781369303
+ 2.7922793727564126
+ 2.79234696189723
+ 2.7924145487919585
+ 2.7924821334407994
+ 2.792549715843956
+ 2.7926172960016307
+ 2.792684873914026
+ 2.7927524495813447
+ 2.7928200230037885
+ 2.7928875941815603
+ 2.7929551631148626
+ 2.7930227298038974
+ 2.7930902942488673
+ 2.793157856449975
+ 2.7932254164074215
+ 2.79329297412141
+ 2.7933605295921424
+ 2.793428082819821
+ 2.7934956338046475
+ 2.7935631825468246
+ 2.793630729046554
+ 2.7936982733040385
+ 2.793765815319479
+ 2.793833355093078
+ 2.7939008926250373
+ 2.79396842791556
+ 2.794035960964846
+ 2.7941034917730985
+ 2.7941710203405186
+ 2.794238546667309
+ 2.794306070753671
+ 2.7943735925998063
+ 2.7944411122059165
+ 2.7945086295722037
+ 2.7945761446988695
+ 2.7946436575861147
+ 2.794711168234142
+ 2.7947786766431526
+ 2.794846182813348
+ 2.79491368674493
+ 2.7949811884380993
+ 2.7950486878930585
+ 2.795116185110008
+ 2.795183680089149
+ 2.7952511728306844
+ 2.795318663334814
+ 2.79538615160174
+ 2.7954536376316637
+ 2.7955211214247853
+ 2.795588602981307
+ 2.7956560823014294
+ 2.7957235593853547
+ 2.7957910342332832
+ 2.795858506845416
+ 2.795925977221954
+ 2.795993445363099
+ 2.7960609112690515
+ 2.7961283749400128
+ 2.796195836376183
+ 2.7962632955777638
+ 2.796330752544956
+ 2.7963982072779605
+ 2.796465659776978
+ 2.7965331100422093
+ 2.7966005580738553
+ 2.7966680038721163
+ 2.796735447437194
+ 2.796802888769288
+ 2.7968703278685996
+ 2.796937764735329
+ 2.7970051993696776
+ 2.797072631771845
+ 2.7971400619420326
+ 2.79720748988044
+ 2.7972749155872685
+ 2.797342339062718
+ 2.7974097603069894
+ 2.797477179320283
+ 2.7975445961027985
+ 2.797612010654737
+ 2.7976794229762985
+ 2.797746833067684
+ 2.797814240929092
+ 2.7978816465607244
+ 2.7979490499627806
+ 2.798016451135461
+ 2.7980838500789655
+ 2.798151246793495
+ 2.7982186412792487
+ 2.798286033536427
+ 2.798353423565229
+ 2.798420811365857
+ 2.7984881969385085
+ 2.7985555802833844
+ 2.798622961400685
+ 2.798690340290609
+ 2.7987577169533577
+ 2.7988250913891304
+ 2.798892463598126
+ 2.798959833580545
+ 2.7990272013365876
+ 2.7990945668664526
+ 2.7991619301703397
+ 2.7992292912484493
+ 2.7992966501009806
+ 2.799364006728133
+ 2.7994313611301065
+ 2.7994987133071
+ 2.799566063259313
+ 2.7996334109869454
+ 2.799700756490197
+ 2.799768099769266
+ 2.799835440824353
+ 2.7999027796556564
+ 2.7999701162633754
+ 2.800037450647711
+ 2.80010478280886
+ 2.800172112747024
+ 2.8002394404624003
+ 2.8003067659551895
+ 2.800374089225589
+ 2.8004414102737996
+ 2.80050872910002
+ 2.8005760457044486
+ 2.8006433600872853
+ 2.800710672248728
+ 2.800777982188977
+ 2.8008452899082297
+ 2.800912595406686
+ 2.8009798986845453
+ 2.8010471997420052
+ 2.801114498579265
+ 2.801181795196524
+ 2.80124908959398
+ 2.801316381771833
+ 2.8013836717302802
+ 2.8014509594695216
+ 2.8015182449897544
+ 2.801585528291179
+ 2.801652809373993
+ 2.801720088238394
+ 2.8017873648845826
+ 2.8018546393127557
+ 2.8019219115231127
+ 2.8019891815158515
+ 2.802056449291171
+ 2.802123714849269
+ 2.802190978190344
+ 2.8022582393145945
+ 2.8023254982222188
+ 2.802392754913415
+ 2.8024600093883816
+ 2.8025272616473167
+ 2.802594511690418
+ 2.802661759517885
+ 2.802729005129914
+ 2.8027962485267044
+ 2.8028634897084537
+ 2.8029307286753604
+ 2.8029979654276223
+ 2.8030651999654372
+ 2.803132432289003
+ 2.8031996623985176
+ 2.803266890294179
+ 2.8033341159761855
+ 2.803401339444734
+ 2.803468560700024
+ 2.8035357797422504
+ 2.8036029965716143
+ 2.803670211188311
+ 2.803737423592539
+ 2.8038046337844964
+ 2.8038718417643804
+ 2.803939047532388
+ 2.804006251088718
+ 2.8040734524335664
+ 2.804140651567132
+ 2.8042078484896127
+ 2.8042750432012045
+ 2.8043422357021055
+ 2.8044094259925134
+ 2.804476614072625
+ 2.804543799942638
+ 2.8046109836027497
+ 2.804678165053157
+ 2.8047453442940578
+ 2.804812521325649
+ 2.8048796961481277
+ 2.8049468687616916
+ 2.805014039166537
+ 2.805081207362862
+ 2.8051483733508626
+ 2.805215537130737
+ 2.8052826987026807
+ 2.8053498580668923
+ 2.805417015223568
+ 2.805484170172905
+ 2.8055513229150995
+ 2.805618473450349
+ 2.8056856217788506
+ 2.8057527679008007
+ 2.8058199118163962
+ 2.8058870535258342
+ 2.8059541930293106
+ 2.806021330327023
+ 2.806088465419168
+ 2.806155598305941
+ 2.8062227289875405
+ 2.806289857464162
+ 2.8063569837360025
+ 2.806424107803258
+ 2.8064912296661255
+ 2.8065583493248014
+ 2.8066254667794817
+ 2.806692582030364
+ 2.8067596950776434
+ 2.8068268059215162
+ 2.8068939145621803
+ 2.8069610209998306
+ 2.807028125234664
+ 2.8070952272668763
+ 2.807162327096664
+ 2.8072294247242238
+ 2.807296520149751
+ 2.807363613373442
+ 2.807430704395493
+ 2.8074977932161005
+ 2.8075648798354598
+ 2.8076319642537677
+ 2.8076990464712197
+ 2.8077661264880116
+ 2.80783320430434
+ 2.8079002799204
+ 2.807967353336388
+ 2.8080344245525
+ 2.8081014935689317
+ 2.8081685603858784
+ 2.8082356250035363
+ 2.8083026874221013
+ 2.808369747641769
+ 2.8084368056627347
+ 2.808503861485195
+ 2.8085709151093443
+ 2.808637966535379
+ 2.8087050157634947
+ 2.808772062793887
+ 2.8088391076267505
+ 2.8089061502622816
+ 2.8089731907006756
+ 2.8090402289421275
+ 2.8091072649868334
+ 2.809174298834988
+ 2.8092413304867874
+ 2.809308359942426
+ 2.8093753872020994
+ 2.8094424122660038
+ 2.809509435134333
+ 2.809576455807283
+ 2.809643474285049
+ 2.809710490567826
+ 2.8097775046558087
+ 2.8098445165491928
+ 2.809911526248173
+ 2.809978533752945
+ 2.810045539063703
+ 2.8101125421806423
+ 2.810179543103958
+ 2.8102465418338447
+ 2.810313538370497
+ 2.810380532714111
+ 2.8104475248648804
+ 2.810514514823
+ 2.8105815025886653
+ 2.810648488162071
+ 2.810715471543411
+ 2.8107824527328806
+ 2.8108494317306745
+ 2.810916408536987
+ 2.810983383152013
+ 2.811050355575947
+ 2.811117325808984
+ 2.811184293851318
+ 2.811251259703143
+ 2.8113182233646543
+ 2.8113851848360465
+ 2.811452144117513
+ 2.811519101209249
+ 2.811586056111449
+ 2.811653008824307
+ 2.811719959348017
+ 2.8117869076827735
+ 2.811853853828771
+ 2.8119207977862035
+ 2.811987739555265
+ 2.81205467913615
+ 2.8121216165290526
+ 2.8121885517341667
+ 2.8122554847516867
+ 2.812322415581806
+ 2.81238934422472
+ 2.8124562706806207
+ 2.8125231949497036
+ 2.812590117032162
+ 2.81265703692819
+ 2.812723954637981
+ 2.8127908701617303
+ 2.8128577834996302
+ 2.8129246946518753
+ 2.8129916036186584
+ 2.813058510400174
+ 2.8131254149966165
+ 2.813192317408178
+ 2.8132592176350535
+ 2.8133261156774356
+ 2.813393011535519
+ 2.813459905209496
+ 2.8135267966995614
+ 2.813593686005908
+ 2.813660573128729
+ 2.8137274580682186
+ 2.8137943408245705
+ 2.813861221397977
+ 2.813928099788632
+ 2.8139949759967284
+ 2.8140618500224606
+ 2.8141287218660205
+ 2.8141955915276027
+ 2.8142624590074
+ 2.814329324305605
+ 2.8143961874224117
+ 2.8144630483580126
+ 2.8145299071126013
+ 2.8145967636863705
+ 2.8146636180795137
+ 2.8147304702922233
+ 2.8147973203246934
+ 2.814864168177116
+ 2.8149310138496846
+ 2.8149978573425916
+ 2.8150646986560304
+ 2.8151315377901938
+ 2.815198374745274
+ 2.815265209521465
+ 2.8153320421189587
+ 2.8153988725379477
+ 2.8154657007786255
+ 2.8155325268411846
+ 2.815599350725817
+ 2.8156661724327163
+ 2.8157329919620744
+ 2.8157998093140844
+ 2.815866624488939
+ 2.8159334374868297
+ 2.8160002483079505
+ 2.8160670569524924
+ 2.816133863420649
+ 2.8162006677126117
+ 2.816267469828574
+ 2.8163342697687277
+ 2.816401067533265
+ 2.8164678631223787
+ 2.816534656536261
+ 2.816601447775103
+ 2.8166682368390994
+ 2.81673502372844
+ 2.8168018084433175
+ 2.8168685909839253
+ 2.816935371350454
+ 2.8170021495430966
+ 2.817068925562045
+ 2.817135699407491
+ 2.817202471079627
+ 2.8172692405786446
+ 2.817336007904736
+ 2.8174027730580935
+ 2.8174695360389084
+ 2.8175362968473725
+ 2.8176030554836777
+ 2.8176698119480164
+ 2.8177365662405793
+ 2.81780331836156
+ 2.8178700683111484
+ 2.817936816089537
+ 2.818003561696917
+ 2.818070305133481
+ 2.8181370463994195
+ 2.818203785494925
+ 2.818270522420189
+ 2.8183372571754024
+ 2.8184039897607573
+ 2.8184707201764447
+ 2.818537448422657
+ 2.8186041744995847
+ 2.818670898407419
+ 2.8187376201463525
+ 2.8188043397165754
+ 2.8188710571182796
+ 2.8189377723516555
+ 2.8190044854168965
+ 2.8190711963141917
+ 2.819137905043733
+ 2.819204611605711
+ 2.8192713160003184
+ 2.819338018227745
+ 2.8194047182881827
+ 2.819471416181822
+ 2.8195381119088543
+ 2.8196048054694702
+ 2.819671496863861
+ 2.8197381860922177
+ 2.819804873154731
+ 2.8198715580515925
+ 2.819938240782992
+ 2.8200049213491214
+ 2.820071599750171
+ 2.8201382759863316
+ 2.8202049500577933
+ 2.820271621964748
+ 2.8203382917073867
+ 2.820404959285899
+ 2.8204716247004757
+ 2.8205382879513072
+ 2.820604949038585
+ 2.8206716079625
+ 2.8207382647232415
+ 2.820804919321
+ 2.8208715717559674
+ 2.8209382220283326
+ 2.821004870138287
+ 2.8210715160860205
+ 2.8211381598717242
+ 2.8212048014955884
+ 2.8212714409578026
+ 2.8213380782585578
+ 2.8214047133980436
+ 2.821471346376451
+ 2.82153797719397
+ 2.8216046058507906
+ 2.821671232347103
+ 2.8217378566830975
+ 2.8218044788589642
+ 2.8218710988748934
+ 2.821937716731074
+ 2.822004332427698
+ 2.822070945964954
+ 2.8221375573430323
+ 2.8222041665621234
+ 2.822270773622416
+ 2.822337378524101
+ 2.822403981267368
+ 2.8224705818524063
+ 2.822537180279407
+ 2.822603776548559
+ 2.822670370660052
+ 2.822736962614076
+ 2.8228035524108206
+ 2.822870140050475
+ 2.8229367255332303
+ 2.8230033088592745
+ 2.8230698900287985
+ 2.823136469041991
+ 2.823203045899042
+ 2.8232696206001404
+ 2.8233361931454763
+ 2.823402763535239
+ 2.823469331769618
+ 2.823535897848802
+ 2.823602461772982
+ 2.8236690235423456
+ 2.823735583157083
+ 2.823802140617384
+ 2.8238686959234367
+ 2.8239352490754315
+ 2.8240018000735563
+ 2.8240683489180016
+ 2.8241348956089554
+ 2.824201440146608
+ 2.8242679825311474
+ 2.8243345227627636
+ 2.824401060841645
+ 2.824467596767981
+ 2.8245341305419607
+ 2.8246006621637725
+ 2.824667191633606
+ 2.8247337189516495
+ 2.8248002441180926
+ 2.824866767133124
+ 2.8249332879969318
+ 2.8249998067097053
+ 2.825066323271634
+ 2.8251328376829057
+ 2.825199349943709
+ 2.825265860054234
+ 2.8253323680146676
+ 2.825398873825199
+ 2.825465377486018
+ 2.8255318789973116
+ 2.825598378359269
+ 2.8256648755720795
+ 2.82573137063593
+ 2.825797863551011
+ 2.825864354317509
+ 2.8259308429356134
+ 2.8259973294055127
+ 2.8260638137273952
+ 2.8261302959014487
+ 2.8261967759278623
+ 2.826263253806824
+ 2.826329729538522
+ 2.826396203123144
+ 2.826462674560879
+ 2.8265291438519156
+ 2.8265956109964407
+ 2.8266620759946437
+ 2.8267285388467114
+ 2.8267949995528334
+ 2.8268614581131963
+ 2.826927914527989
+ 2.8269943687973993
+ 2.827060820921615
+ 2.8271272709008244
+ 2.827193718735215
+ 2.8272601644249753
+ 2.827326607970292
+ 2.827393049371355
+ 2.82745948862835
+ 2.8275259257414658
+ 2.8275923607108897
+ 2.82765879353681
+ 2.827725224219414
+ 2.82779165275889
+ 2.827858079155425
+ 2.8279245034092066
+ 2.8279909255204227
+ 2.8280573454892606
+ 2.8281237633159084
+ 2.828190179000553
+ 2.828256592543382
+ 2.8283230039445835
+ 2.8283894132043437
+ 2.8284558203228514
+ 2.828522225300293
+ 2.8285886281368566
+ 2.828655028832729
+ 2.8287214273880976
+ 2.8287878238031494
+ 2.8288542180780722
+ 2.8289206102130535
+ 2.8289870002082793
+ 2.8290533880639384
+ 2.829119773780216
+ 2.829186157357301
+ 2.8292525387953793
+ 2.8293189180946383
+ 2.8293852952552654
+ 2.8294516702774475
+ 2.829518043161371
+ 2.8295844139072237
+ 2.829650782515192
+ 2.8297171489854627
+ 2.8297835133182234
+ 2.8298498755136605
+ 2.8299162355719605
+ 2.8299825934933107
+ 2.8300489492778973
+ 2.830115302925908
+ 2.8301816544375287
+ 2.830248003812946
+ 2.8303143510523476
+ 2.830380696155919
+ 2.8304470391238468
+ 2.8305133799563187
+ 2.8305797186535204
+ 2.8306460552156385
+ 2.8307123896428594
+ 2.83077872193537
+ 2.8308450520933572
+ 2.8309113801170063
+ 2.8309777060065047
+ 2.831044029762037
+ 2.831110351383792
+ 2.8311766708719546
+ 2.831242988226711
+ 2.8313093034482484
+ 2.831375616536752
+ 2.8314419274924085
+ 2.831508236315404
+ 2.8315745430059245
+ 2.831640847564157
+ 2.8317071499902866
+ 2.8317734502844996
+ 2.831839748446982
+ 2.8319060444779205
+ 2.8319723383775006
+ 2.8320386301459077
+ 2.832104919783329
+ 2.83217120728995
+ 2.8322374926659553
+ 2.8323037759115324
+ 2.832370057026867
+ 2.832436336012144
+ 2.83250261286755
+ 2.83256888759327
+ 2.832635160189491
+ 2.8327014306563973
+ 2.832767698994175
+ 2.83283396520301
+ 2.832900229283088
+ 2.8329664912345947
+ 2.8330327510577153
+ 2.8330990087526358
+ 2.833165264319541
+ 2.8332315177586174
+ 2.8332977690700494
+ 2.8333640182540227
+ 2.8334302653107235
+ 2.833496510240337
+ 2.8335627530430476
+ 2.8336289937190413
+ 2.833695232268504
+ 2.8337614686916197
+ 2.8338277029885752
+ 2.833893935159554
+ 2.833960165204743
+ 2.8340263931243257
+ 2.8340926189184885
+ 2.8341588425874167
+ 2.834225064131294
+ 2.8342912835503076
+ 2.8343575008446407
+ 2.8344237160144785
+ 2.8344899290600067
+ 2.83455613998141
+ 2.8346223487788733
+ 2.834688555452582
+ 2.8347547600027205
+ 2.8348209624294736
+ 2.834887162733026
+ 2.834953360913563
+ 2.8350195569712695
+ 2.83508575090633
+ 2.835151942718929
+ 2.835218132409251
+ 2.835284319977481
+ 2.8353505054238046
+ 2.8354166887484054
+ 2.835482869951468
+ 2.835549049033177
+ 2.835615225993717
+ 2.835681400833273
+ 2.835747573552029
+ 2.83581374415017
+ 2.8358799126278798
+ 2.835946078985343
+ 2.836012243222744
+ 2.8360784053402672
+ 2.8361445653380972
+ 2.8362107232164186
+ 2.836276878975415
+ 2.8363430326152708
+ 2.83640918413617
+ 2.836475333538297
+ 2.836541480821837
+ 2.8366076259869724
+ 2.836673769033889
+ 2.8367399099627697
+ 2.836806048773799
+ 2.8368721854671612
+ 2.83693832004304
+ 2.837004452501619
+ 2.8370705828430838
+ 2.837136711067616
+ 2.837202837175402
+ 2.8372689611666235
+ 2.8373350830414656
+ 2.8374012028001125
+ 2.8374673204427467
+ 2.837533435969553
+ 2.8375995493807147
+ 2.8376656606764157
+ 2.8377317698568403
+ 2.837797876922171
+ 2.8378639818725926
+ 2.837930084708288
+ 2.8379961854294407
+ 2.8380622840362353
+ 2.8381283805288544
+ 2.8381944749074814
+ 2.838260567172301
+ 2.8383266573234955
+ 2.838392745361249
+ 2.838458831285745
+ 2.838524915097166
+ 2.838590996795696
+ 2.8386570763815193
+ 2.8387231538548177
+ 2.838789229215775
+ 2.838855302464575
+ 2.8389213736013996
+ 2.8389874426264337
+ 2.8390535095398595
+ 2.8391195743418605
+ 2.8391856370326196
+ 2.8392516976123203
+ 2.8393177560811456
+ 2.8393838124392783
+ 2.8394498666869015
+ 2.8395159188241985
+ 2.839581968851352
+ 2.8396480167685447
+ 2.8397140625759607
+ 2.839780106273782
+ 2.839846147862191
+ 2.8399121873413717
+ 2.839978224711506
+ 2.8400442599727773
+ 2.840110293125368
+ 2.8401763241694615
+ 2.84024235310524
+ 2.8403083799328863
+ 2.8403744046525827
+ 2.8404404272645123
+ 2.8405064477688584
+ 2.840572466165802
+ 2.840638482455527
+ 2.840704496638215
+ 2.8407705087140496
+ 2.8408365186832123
+ 2.8409025265458867
+ 2.840968532302254
+ 2.841034535952497
+ 2.841100537496799
+ 2.841166536935341
+ 2.8412325342683062
+ 2.8412985294958766
+ 2.8413645226182345
+ 2.841430513635563
+ 2.8414965025480425
+ 2.8415624893558573
+ 2.841628474059188
+ 2.8416944566582174
+ 2.8417604371531278
+ 2.841826415544101
+ 2.841892391831319
+ 2.8419583660149645
+ 2.8420243380952193
+ 2.842090308072265
+ 2.8421562759462837
+ 2.8422222417174576
+ 2.8422882053859686
+ 2.8423541669519987
+ 2.842420126415729
+ 2.842486083777343
+ 2.8425520390370203
+ 2.842617992194944
+ 2.8426839432512967
+ 2.8427498922062586
+ 2.842815839060012
+ 2.842881783812739
+ 2.8429477264646206
+ 2.8430136670158386
+ 2.8430796054665755
+ 2.843145541817012
+ 2.8432114760673297
+ 2.8432774082177104
+ 2.843343338268336
+ 2.843409266219387
+ 2.8434751920710455
+ 2.8435411158234927
+ 2.843607037476911
+ 2.84367295703148
+ 2.843738874487383
+ 2.8438047898448
+ 2.8438707031039128
+ 2.8439366142649023
+ 2.8440025233279504
+ 2.844068430293238
+ 2.844134335160946
+ 2.8442002379312568
+ 2.84426613860435
+ 2.8443320371804073
+ 2.844397933659611
+ 2.8444638280421404
+ 2.844529720328177
+ 2.844595610517903
+ 2.844661498611498
+ 2.844727384609144
+ 2.844793268511021
+ 2.844859150317311
+ 2.844925030028194
+ 2.8449909076438513
+ 2.8450567831644635
+ 2.845122656590212
+ 2.845188527921277
+ 2.8452543971578397
+ 2.845320264300081
+ 2.845386129348181
+ 2.8454519923023205
+ 2.8455178531626806
+ 2.845583711929442
+ 2.845649568602785
+ 2.8457154231828903
+ 2.8457812756699385
+ 2.84584712606411
+ 2.8459129743655853
+ 2.8459788205745453
+ 2.8460446646911706
+ 2.8461105067156414
+ 2.846176346648137
+ 2.84624218448884
+ 2.846308020237929
+ 2.846373853895585
+ 2.8464396854619882
+ 2.8465055149373195
+ 2.846571342321758
+ 2.8466371676154854
+ 2.84670299081868
+ 2.8467688119315238
+ 2.8468346309541968
+ 2.846900447886878
+ 2.8469662627297483
+ 2.847032075482988
+ 2.8470978861467766
+ 2.8471636947212944
+ 2.847229501206721
+ 2.8472953056032373
+ 2.847361107911023
+ 2.8474269081302577
+ 2.8474927062611215
+ 2.847558502303794
+ 2.8476242962584557
+ 2.847690088125286
+ 2.847755877904464
+ 2.8478216655961712
+ 2.847887451200586
+ 2.8479532347178886
+ 2.848019016148259
+ 2.8480847954918764
+ 2.8481505727489207
+ 2.8482163479195717
+ 2.8482821210040083
+ 2.8483478920024115
+ 2.848413660914959
+ 2.8484794277418324
+ 2.8485451924832095
+ 2.84861095513927
+ 2.848676715710195
+ 2.8487424741961616
+ 2.848808230597351
+ 2.8488739849139417
+ 2.848939737146113
+ 2.8490054872940456
+ 2.849071235357917
+ 2.849136981337908
+ 2.849202725234196
+ 2.849268467046962
+ 2.8493342067763847
+ 2.849399944422643
+ 2.8494656799859164
+ 2.8495314134663836
+ 2.8495971448642243
+ 2.849662874179617
+ 2.849728601412741
+ 2.8497943265637757
+ 2.8498600496328996
+ 2.849925770620292
+ 2.849991489526132
+ 2.850057206350598
+ 2.850122921093869
+ 2.850188633756124
+ 2.8502543443375425
+ 2.850320052838302
+ 2.850385759258583
+ 2.850451463598563
+ 2.850517165858421
+ 2.850582866038336
+ 2.8506485641384867
+ 2.850714260159052
+ 2.8507799541002097
+ 2.850845645962139
+ 2.850911335745019
+ 2.8509770234490275
+ 2.8510427090743433
+ 2.851108392621145
+ 2.8511740740896108
+ 2.85123975347992
+ 2.8513054307922507
+ 2.8513711060267806
+ 2.8514367791836888
+ 2.8515024502631534
+ 2.8515681192653535
+ 2.8516337861904666
+ 2.8516994510386713
+ 2.851765113810146
+ 2.8518307745050686
+ 2.8518964331236174
+ 2.8519620896659714
+ 2.852027744132308
+ 2.8520933965228057
+ 2.8521590468376417
+ 2.8522246950769956
+ 2.8522903412410447
+ 2.852355985329967
+ 2.852421627343941
+ 2.852487267283144
+ 2.8525529051477547
+ 2.8526185409379505
+ 2.8526841746539096
+ 2.85274980629581
+ 2.8528154358638296
+ 2.852881063358146
+ 2.8529466887789368
+ 2.8530123121263804
+ 2.853077933400655
+ 2.853143552601937
+ 2.8532091697304054
+ 2.8532747847862368
+ 2.8533403977696095
+ 2.853406008680702
+ 2.853471617519691
+ 2.8535372242867534
+ 2.853602828982068
+ 2.8536684316058123
+ 2.853734032158163
+ 2.8537996306392985
+ 2.853865227049396
+ 2.8539308213886323
+ 2.853996413657186
+ 2.8540620038552333
+ 2.854127591982953
+ 2.854193178040521
+ 2.8542587620281155
+ 2.854324343945914
+ 2.8543899237940935
+ 2.8544555015728306
+ 2.8545210772823038
+ 2.8545866509226894
+ 2.8546522224941646
+ 2.8547177919969076
+ 2.854783359431094
+ 2.854848924796902
+ 2.8549144880945083
+ 2.8549800493240904
+ 2.8550456084858244
+ 2.855111165579888
+ 2.8551767206064587
+ 2.855242273565713
+ 2.8553078244578267
+ 2.8553733732829785
+ 2.8554389200413444
+ 2.855504464733101
+ 2.8555700073584265
+ 2.855635547917496
+ 2.8557010864104875
+ 2.8557666228375775
+ 2.8558321571989422
+ 2.8558976894947588
+ 2.8559632197252043
+ 2.8560287478904547
+ 2.856094273990687
+ 2.8561597980260776
+ 2.8562253199968035
+ 2.856290839903041
+ 2.8563563577449664
+ 2.8564218735227573
+ 2.856487387236589
+ 2.856552898886638
+ 2.8566184084730817
+ 2.8566839159960957
+ 2.856749421455857
+ 2.856814924852542
+ 2.856880426186326
+ 2.8569459254573863
+ 2.857011422665899
+ 2.8570769178120403
+ 2.857142410895987
+ 2.857207901917914
+ 2.857273390877999
+ 2.8573388777764173
+ 2.857404362613345
+ 2.8574698453889593
+ 2.857535326103435
+ 2.8576008047569483
+ 2.857666281349676
+ 2.857731755881794
+ 2.8577972283534776
+ 2.8578626987649036
+ 2.8579281671162478
+ 2.857993633407686
+ 2.858059097639394
+ 2.8581245598115474
+ 2.8581900199243226
+ 2.8582554779778957
+ 2.858320933972442
+ 2.8583863879081375
+ 2.8584518397851575
+ 2.8585172896036783
+ 2.8585827373638755
+ 2.8586481830659243
+ 2.858713626710001
+ 2.8587790682962813
+ 2.8588445078249403
+ 2.8589099452961535
+ 2.8589753807100973
+ 2.859040814066947
+ 2.8591062453668767
+ 2.859171674610064
+ 2.8592371017966833
+ 2.85930252692691
+ 2.85936795000092
+ 2.859433371018888
+ 2.8594987899809903
+ 2.8595642068874016
+ 2.8596296217382973
+ 2.859695034533852
+ 2.8597604452742424
+ 2.8598258539596433
+ 2.8598912605902296
+ 2.8599566651661763
+ 2.860022067687659
+ 2.8600874681548527
+ 2.8601528665679323
+ 2.860218262927074
+ 2.8602836572324515
+ 2.86034904948424
+ 2.8604144396826157
+ 2.8604798278277523
+ 2.860545213919826
+ 2.8606105979590106
+ 2.8606759799454817
+ 2.8607413598794142
+ 2.8608067377609823
+ 2.860872113590362
+ 2.8609374873677273
+ 2.861002859093253
+ 2.8610682287671145
+ 2.861133596389486
+ 2.8611989619605427
+ 2.861264325480459
+ 2.8613296869494094
+ 2.861395046367569
+ 2.8614604037351117
+ 2.8615257590522134
+ 2.8615911123190476
+ 2.8616564635357897
+ 2.8617218127026134
+ 2.8617871598196936
+ 2.8618525048872048
+ 2.861917847905322
+ 2.861983188874219
+ 2.86204852779407
+ 2.86211386466505
+ 2.8621791994873327
+ 2.8622445322610934
+ 2.862309862986506
+ 2.8623751916637445
+ 2.8624405182929835
+ 2.862505842874397
+ 2.8625711654081596
+ 2.8626364858944453
+ 2.862701804333428
+ 2.862767120725282
+ 2.8628324350701826
+ 2.8628977473683017
+ 2.8629630576198153
+ 2.8630283658248965
+ 2.8630936719837194
+ 2.8631589760964586
+ 2.8632242781632877
+ 2.863289578184381
+ 2.8633548761599115
+ 2.8634201720900534
+ 2.8634854659749815
+ 2.863550757814869
+ 2.8636160476098893
+ 2.8636813353602175
+ 2.8637466210660265
+ 2.86381190472749
+ 2.863877186344782
+ 2.863942465918076
+ 2.864007743447546
+ 2.8640730189333654
+ 2.8641382923757086
+ 2.8642035637747485
+ 2.8642688331306587
+ 2.864334100443613
+ 2.8643993657137847
+ 2.864464628941348
+ 2.8645298901264753
+ 2.864595149269341
+ 2.864660406370118
+ 2.864725661428981
+ 2.8647909144461012
+ 2.8648561654216538
+ 2.8649214143558117
+ 2.864986661248748
+ 2.865051906100636
+ 2.865117148911649
+ 2.865182389681961
+ 2.865247628411744
+ 2.865312865101172
+ 2.8653780997504184
+ 2.8654433323596558
+ 2.8655085629290573
+ 2.865573791458796
+ 2.865639017949047
+ 2.86570424239998
+ 2.8657694648117706
+ 2.8658346851845904
+ 2.8658999035186135
+ 2.8659651198140117
+ 2.8660303340709588
+ 2.866095546289628
+ 2.866160756470191
+ 2.866225964612822
+ 2.8662911707176932
+ 2.866356374784978
+ 2.8664215768148478
+ 2.8664867768074767
+ 2.866551974763037
+ 2.866617170681702
+ 2.8666823645636432
+ 2.8667475564090346
+ 2.866812746218048
+ 2.8668779339908563
+ 2.8669431197276327
+ 2.867008303428549
+ 2.867073485093778
+ 2.867138664723492
+ 2.8672038423178643
+ 2.867269017877067
+ 2.867334191401272
+ 2.867399362890653
+ 2.867464532345381
+ 2.867529699765629
+ 2.86759486515157
+ 2.8676600285033755
+ 2.867725189821219
+ 2.867790349105271
+ 2.867855506355705
+ 2.8679206615726933
+ 2.8679858147564077
+ 2.868050965907021
+ 2.868116115024704
+ 2.8681812621096308
+ 2.8682464071619727
+ 2.868311550181901
+ 2.868376691169589
+ 2.868441830125208
+ 2.8685069670489307
+ 2.8685721019409285
+ 2.8686372348013736
+ 2.8687023656304387
+ 2.8687674944282944
+ 2.868832621195114
+ 2.8688977459310676
+ 2.8689628686363293
+ 2.8690279893110695
+ 2.8690931079554605
+ 2.869158224569674
+ 2.869223339153882
+ 2.869288451708256
+ 2.869353562232968
+ 2.8694186707281895
+ 2.869483777194092
+ 2.8695488816308474
+ 2.8696139840386277
+ 2.869679084417604
+ 2.869744182767948
+ 2.8698092790898313
+ 2.8698743733834258
+ 2.8699394656489026
+ 2.8700045558864336
+ 2.8700696440961897
+ 2.870134730278343
+ 2.8701998144330645
+ 2.8702648965605255
+ 2.870329976660898
+ 2.870395054734353
+ 2.870460130781061
+ 2.870525204801195
+ 2.870590276794925
+ 2.8706553467624234
+ 2.8707204147038596
+ 2.870785480619407
+ 2.8708505445092354
+ 2.870915606373516
+ 2.8709806662124207
+ 2.87104572402612
+ 2.8711107798147855
+ 2.871175833578587
+ 2.8712408853176976
+ 2.871305935032287
+ 2.871370982722526
+ 2.871436028388587
+ 2.8715010720306395
+ 2.8715661136488553
+ 2.8716311532434045
+ 2.8716961908144594
+ 2.871761226362189
+ 2.871826259886765
+ 2.871891291388359
+ 2.871956320867141
+ 2.8720213483232815
+ 2.8720863737569515
+ 2.8721513971683224
+ 2.8722164185575636
+ 2.872281437924847
+ 2.872346455270343
+ 2.872411470594222
+ 2.8724764838966546
+ 2.872541495177811
+ 2.8726065044378624
+ 2.8726715116769794
+ 2.872736516895332
+ 2.8728015200930908
+ 2.8728665212704265
+ 2.8729315204275094
+ 2.8729965175645105
+ 2.8730615126815993
+ 2.873126505778946
+ 2.8731914968567223
+ 2.873256485915097
+ 2.8733214729542413
+ 2.873386457974325
+ 2.8734514409755194
+ 2.873516421957994
+ 2.8735814009219185
+ 2.8736463778674635
+ 2.8737113527947993
+ 2.8737763257040965
+ 2.873841296595524
+ 2.873906265469253
+ 2.873971232325453
+ 2.8740361971642945
+ 2.8741011599859463
+ 2.8741661207905804
+ 2.874231079578365
+ 2.8742960363494716
+ 2.8743609911040684
+ 2.8744259438423265
+ 2.8744908945644156
+ 2.8745558432705054
+ 2.874620789960766
+ 2.8746857346353663
+ 2.874750677294477
+ 2.874815617938268
+ 2.874880556566908
+ 2.874945493180568
+ 2.875010427779417
+ 2.8750753603636245
+ 2.875140290933361
+ 2.875205219488795
+ 2.8752701460300965
+ 2.8753350705574356
+ 2.8753999930709817
+ 2.875464913570904
+ 2.8755298320573717
+ 2.875594748530555
+ 2.8756596629906226
+ 2.875724575437745
+ 2.8757894858720907
+ 2.8758543942938295
+ 2.8759193007031305
+ 2.8759842051001634
+ 2.8760491074850973
+ 2.876114007858102
+ 2.876178906219346
+ 2.8762438025689985
+ 2.87630869690723
+ 2.876373589234208
+ 2.876438479550103
+ 2.8765033678550833
+ 2.8765682541493187
+ 2.876633138432978
+ 2.87669802070623
+ 2.8767629009692444
+ 2.87682777922219
+ 2.8768926554652356
+ 2.87695752969855
+ 2.8770224019223027
+ 2.877087272136663
+ 2.877152140341799
+ 2.877217006537879
+ 2.877281870725074
+ 2.877346732903551
+ 2.8774115930734796
+ 2.877476451235029
+ 2.8775413073883667
+ 2.8776061615336626
+ 2.8776710136710855
+ 2.877735863800803
+ 2.877800711922985
+ 2.8778655580378
+ 2.8779304021454157
+ 2.877995244246001
+ 2.8780600843397255
+ 2.8781249224267573
+ 2.878189758507265
+ 2.878254592581416
+ 2.8783194246493804
+ 2.8783842547113254
+ 2.8784490827674207
+ 2.878513908817834
+ 2.878578732862734
+ 2.8786435549022893
+ 2.8787083749366675
+ 2.8787731929660376
+ 2.8788380089905674
+ 2.8789028230104257
+ 2.8789676350257807
+ 2.879032445036801
+ 2.8790972530436534
+ 2.8791620590465077
+ 2.8792268630455315
+ 2.879291665040893
+ 2.8793564650327603
+ 2.8794212630213014
+ 2.8794860590066844
+ 2.8795508529890776
+ 2.879615644968649
+ 2.8796804349455667
+ 2.8797452229199982
+ 2.8798100088921124
+ 2.879874792862077
+ 2.879939574830059
+ 2.8800043547962275
+ 2.8800691327607493
+ 2.880133908723793
+ 2.8801986826855264
+ 2.8802634546461174
+ 2.8803282246057336
+ 2.8803929925645426
+ 2.880457758522712
+ 2.8805225224804105
+ 2.8805872844378047
+ 2.880652044395063
+ 2.880716802352353
+ 2.8807815583098413
+ 2.8808463122676975
+ 2.8809110642260873
+ 2.880975814185179
+ 2.8810405621451407
+ 2.881105308106139
+ 2.881170052068342
+ 2.8812347940319167
+ 2.8812995339970318
+ 2.881364271963853
+ 2.881429007932548
+ 2.8814937419032853
+ 2.8815584738762317
+ 2.881623203851554
+ 2.8816879318294206
+ 2.8817526578099977
+ 2.881817381793453
+ 2.8818821037799536
+ 2.8819468237696677
+ 2.8820115417627616
+ 2.882076257759402
+ 2.882140971759757
+ 2.8822056837639933
+ 2.882270393772278
+ 2.8823351017847787
+ 2.882399807801662
+ 2.8824645118230947
+ 2.882529213849244
+ 2.882593913880277
+ 2.8826586119163613
+ 2.882723307957663
+ 2.8827880020043493
+ 2.8828526940565875
+ 2.882917384114543
+ 2.8829820721783848
+ 2.8830467582482777
+ 2.88311144232439
+ 2.883176124406888
+ 2.8832408044959386
+ 2.883305482591708
+ 2.8833701586943636
+ 2.8834348328040718
+ 2.8834995049209993
+ 2.8835641750453127
+ 2.8836288431771786
+ 2.8836935093167635
+ 2.883758173464235
+ 2.883822835619758
+ 2.8838874957835
+ 2.883952153955628
+ 2.8840168101363077
+ 2.8840814643257056
+ 2.884146116523988
+ 2.8842107667313224
+ 2.884275414947874
+ 2.8843400611738095
+ 2.884404705409296
+ 2.884469347654499
+ 2.884533987909585
+ 2.88459862617472
+ 2.8846632624500717
+ 2.884727896735804
+ 2.8847925290320853
+ 2.884857159339081
+ 2.8849217876569564
+ 2.884986413985879
+ 2.885051038326014
+ 2.885115660677528
+ 2.8851802810405873
+ 2.885244899415358
+ 2.8853095158020046
+ 2.885374130200695
+ 2.8854387426115946
+ 2.8855033530348693
+ 2.8855679614706844
+ 2.8856325679192074
+ 2.8856971723806026
+ 2.885761774855037
+ 2.885826375342676
+ 2.885890973843685
+ 2.8859555703582305
+ 2.8860201648864785
+ 2.8860847574285935
+ 2.886149347984743
+ 2.8862139365550914
+ 2.8862785231398047
+ 2.886343107739049
+ 2.8864076903529896
+ 2.8864722709817925
+ 2.8865368496256223
+ 2.8866014262846456
+ 2.886666000959028
+ 2.8867305736489346
+ 2.8867951443545308
+ 2.8868597130759825
+ 2.886924279813455
+ 2.8869888445671137
+ 2.887053407337125
+ 2.8871179681236523
+ 2.8871825269268627
+ 2.8872470837469204
+ 2.887311638583992
+ 2.8873761914382423
+ 2.887440742309836
+ 2.887505291198939
+ 2.8875698381057164
+ 2.887634383030333
+ 2.887698925972955
+ 2.8877634669337473
+ 2.8878280059128745
+ 2.8878925429105013
+ 2.8879570779267945
+ 2.888021610961918
+ 2.888086142016037
+ 2.8881506710893166
+ 2.8882151981819217
+ 2.888279723294018
+ 2.8883442464257696
+ 2.888408767577342
+ 2.8884732867489005
+ 2.888537803940609
+ 2.888602319152633
+ 2.888666832385137
+ 2.8887313436382867
+ 2.888795852912246
+ 2.8888603602071803
+ 2.888924865523254
+ 2.888989368860632
+ 2.889053870219479
+ 2.88911836959996
+ 2.889182867002239
+ 2.8892473624264814
+ 2.8893118558728514
+ 2.889376347341514
+ 2.8894408368326334
+ 2.889505324346375
+ 2.889569809882902
+ 2.88963429344238
+ 2.8896987750249736
+ 2.889763254630847
+ 2.8898277322601635
+ 2.88989220791309
+ 2.8899566815897884
+ 2.8900211532904243
+ 2.890085623015163
+ 2.8901500907641666
+ 2.890214556537602
+ 2.8902790203356314
+ 2.89034348215842
+ 2.8904079420061324
+ 2.890472399878932
+ 2.8905368557769835
+ 2.8906013097004513
+ 2.8906657616494993
+ 2.890730211624292
+ 2.890794659624993
+ 2.8908591056517667
+ 2.8909235497047767
+ 2.890987991784188
+ 2.8910524318901643
+ 2.891116870022869
+ 2.891181306182467
+ 2.891245740369122
+ 2.891310172582997
+ 2.8913746028242575
+ 2.891439031093067
+ 2.891503457389588
+ 2.8915678817139865
+ 2.891632304066425
+ 2.891696724447067
+ 2.8917611428560774
+ 2.8918255592936193
+ 2.8918899737598567
+ 2.8919543862549535
+ 2.892018796779073
+ 2.892083205332379
+ 2.892147611915036
+ 2.892212016527206
+ 2.8922764191690544
+ 2.892340819840743
+ 2.8924052185424367
+ 2.8924696152742992
+ 2.8925340100364925
+ 2.892598402829182
+ 2.89266279365253
+ 2.8927271825067002
+ 2.8927915693918567
+ 2.892855954308162
+ 2.8929203372557795
+ 2.892984718234873
+ 2.893049097245606
+ 2.8931134742881417
+ 2.8931778493626434
+ 2.893242222469274
+ 2.8933065936081976
+ 2.8933709627795765
+ 2.893435329983575
+ 2.8934996952203553
+ 2.8935640584900812
+ 2.8936284197929156
+ 2.893692779129021
+ 2.8937571364985617
+ 2.8938214919017007
+ 2.8938858453386
+ 2.893950196809424
+ 2.8940145463143345
+ 2.894078893853495
+ 2.894143239427069
+ 2.8942075830352185
+ 2.8942719246781077
+ 2.894336264355898
+ 2.894400602068753
+ 2.8944649378168363
+ 2.8945292716003097
+ 2.894593603419336
+ 2.894657933274079
+ 2.8947222611647008
+ 2.8947865870913643
+ 2.894850911054232
+ 2.894915233053467
+ 2.8949795530892315
+ 2.895043871161689
+ 2.895108187271001
+ 2.895172501417331
+ 2.895236813600841
+ 2.8953011238216946
+ 2.895365432080054
+ 2.8954297383760808
+ 2.895494042709938
+ 2.8955583450817888
+ 2.895622645491795
+ 2.89568694394012
+ 2.8957512404269243
+ 2.8958155349523724
+ 2.8958798275166253
+ 2.895944118119846
+ 2.896008406762197
+ 2.8960726934438394
+ 2.896136978164937
+ 2.8962012609256513
+ 2.896265541726145
+ 2.8963298205665797
+ 2.8963940974471183
+ 2.8964583723679227
+ 2.896522645329155
+ 2.8965869163309774
+ 2.8966511853735524
+ 2.896715452457041
+ 2.8967797175816066
+ 2.8968439807474105
+ 2.896908241954615
+ 2.8969725012033822
+ 2.8970367584938734
+ 2.897101013826252
+ 2.8971652672006782
+ 2.897229518617315
+ 2.8972937680763247
+ 2.8973580155778675
+ 2.897422261122107
+ 2.897486504709205
+ 2.8975507463393217
+ 2.8976149860126204
+ 2.897679223729262
+ 2.8977434594894094
+ 2.8978076932932226
+ 2.897871925140865
+ 2.8979361550324976
+ 2.8980003829682817
+ 2.8980646089483795
+ 2.8981288329729527
+ 2.8981930550421624
+ 2.8982572751561704
+ 2.898321493315138
+ 2.8983857095192276
+ 2.8984499237685997
+ 2.8985141360634157
+ 2.898578346403838
+ 2.8986425547900283
+ 2.898706761222147
+ 2.8987709657003555
+ 2.8988351682248155
+ 2.8988993687956888
+ 2.8989635674131367
+ 2.8990277640773194
+ 2.8990919587883996
+ 2.8991561515465376
+ 2.8992203423518954
+ 2.899284531204633
+ 2.8993487181049136
+ 2.8994129030528963
+ 2.8994770860487438
+ 2.8995412670926166
+ 2.8996054461846756
+ 2.8996696233250825
+ 2.899733798513998
+ 2.8997979717515827
+ 2.8998621430379985
+ 2.8999263123734065
+ 2.899990479757967
+ 2.900054645191841
+ 2.9001188086751903
+ 2.9001829702081747
+ 2.9002471297909556
+ 2.900311287423694
+ 2.900375443106551
+ 2.900439596839687
+ 2.900503748623263
+ 2.9005678984574392
+ 2.9006320463423774
+ 2.9006961922782377
+ 2.900760336265181
+ 2.9008244783033685
+ 2.90088861839296
+ 2.9009527565341164
+ 2.9010168927269993
+ 2.901081026971768
+ 2.9011451592685837
+ 2.901209289617607
+ 2.9012734180189987
+ 2.9013375444729186
+ 2.9014016689795277
+ 2.9014657915389868
+ 2.9015299121514553
+ 2.9015940308170953
+ 2.901658147536066
+ 2.901722262308528
+ 2.9017863751346424
+ 2.901850486014568
+ 2.901914594948467
+ 2.901978701936499
+ 2.9020428069788236
+ 2.902106910075602
+ 2.9021710112269936
+ 2.9022351104331596
+ 2.9022992076942598
+ 2.902363303010454
+ 2.9024273963819027
+ 2.902491487808766
+ 2.9025555772912046
+ 2.902619664829378
+ 2.902683750423446
+ 2.90274783407357
+ 2.9028119157799086
+ 2.902875995542622
+ 2.9029400733618713
+ 2.903004149237815
+ 2.903068223170614
+ 2.9031322951604284
+ 2.903196365207417
+ 2.903260433311741
+ 2.9033244994735594
+ 2.9033885636930328
+ 2.90345262597032
+ 2.903516686305582
+ 2.903580744698978
+ 2.9036448011506675
+ 2.90370885566081
+ 2.9037729082295662
+ 2.903836958857095
+ 2.9039010075435567
+ 2.903965054289111
+ 2.9040290990939166
+ 2.9040931419581337
+ 2.904157182881922
+ 2.9042212218654413
+ 2.9042852589088506
+ 2.9043492940123095
+ 2.9044133271759778
+ 2.904477358400015
+ 2.90454138768458
+ 2.9046054150298333
+ 2.904669440435933
+ 2.904733463903039
+ 2.9047974854313114
+ 2.904861505020909
+ 2.904925522671991
+ 2.904989538384717
+ 2.9050535521592464
+ 2.9051175639957374
+ 2.9051815738943505
+ 2.9052455818552447
+ 2.905309587878579
+ 2.9053735919645125
+ 2.905437594113205
+ 2.9055015943248144
+ 2.9055655925995008
+ 2.905629588937423
+ 2.9056935833387407
+ 2.9057575758036114
+ 2.905821566332196
+ 2.905885554924652
+ 2.905949541581139
+ 2.9060135263018165
+ 2.9060775090868427
+ 2.9061414899363767
+ 2.906205468850578
+ 2.906269445829605
+ 2.9063334208736156
+ 2.906397393982771
+ 2.9064613651572273
+ 2.9065253343971453
+ 2.906589301702683
+ 2.906653267074
+ 2.9067172305112536
+ 2.9067811920146034
+ 2.906845151584208
+ 2.906909109220226
+ 2.906973064922816
+ 2.9070370186921366
+ 2.907100970528347
+ 2.9071649204316046
+ 2.9072288684020693
+ 2.9072928144398986
+ 2.9073567585452516
+ 2.907420700718287
+ 2.907484640959163
+ 2.9075485792680373
+ 2.9076125156450696
+ 2.9076764500904178
+ 2.9077403826042403
+ 2.907804313186695
+ 2.9078682418379413
+ 2.9079321685581365
+ 2.90799609334744
+ 2.9080600162060093
+ 2.908123937134002
+ 2.9081878561315784
+ 2.908251773198895
+ 2.9083156883361103
+ 2.9083796015433827
+ 2.9084435128208708
+ 2.908507422168732
+ 2.9085713295871254
+ 2.908635235076208
+ 2.908699138636138
+ 2.9087630402670746
+ 2.908826939969175
+ 2.9088908377425966
+ 2.9089547335874983
+ 2.909018627504038
+ 2.9090825194923737
+ 2.909146409552663
+ 2.9092102976850645
+ 2.9092741838897345
+ 2.909338068166832
+ 2.9094019505165156
+ 2.909465830938942
+ 2.909529709434269
+ 2.9095935860026554
+ 2.9096574606442576
+ 2.909721333359234
+ 2.909785204147743
+ 2.909849073009941
+ 2.9099129399459867
+ 2.9099768049560373
+ 2.9100406680402506
+ 2.910104529198784
+ 2.9101683884317953
+ 2.9102322457394423
+ 2.9102961011218818
+ 2.9103599545792718
+ 2.9104238061117704
+ 2.910487655719534
+ 2.910551503402721
+ 2.9106153491614886
+ 2.910679192995993
+ 2.910743034906394
+ 2.910806874892847
+ 2.91087071295551
+ 2.9109345490945406
+ 2.9109983833100954
+ 2.911062215602333
+ 2.9111260459714092
+ 2.9111898744174827
+ 2.91125370094071
+ 2.911317525541248
+ 2.9113813482192534
+ 2.9114451689748857
+ 2.911508987808299
+ 2.9115728047196536
+ 2.9116366197091037
+ 2.9117004327768083
+ 2.9117642439229243
+ 2.9118280531476075
+ 2.9118918604510164
+ 2.911955665833307
+ 2.9120194692946364
+ 2.9120832708351623
+ 2.9121470704550414
+ 2.9122108681544296
+ 2.912274663933485
+ 2.912338457792364
+ 2.912402249731224
+ 2.912466039750221
+ 2.9125298278495126
+ 2.912593614029255
+ 2.912657398289605
+ 2.91272118063072
+ 2.912784961052756
+ 2.91284873955587
+ 2.912912516140219
+ 2.912976290805959
+ 2.9130400635532476
+ 2.91310383438224
+ 2.9131676032930947
+ 2.913231370285967
+ 2.9132951353610133
+ 2.913358898518391
+ 2.9134226597582558
+ 2.913486419080765
+ 2.913550176486075
+ 2.9136139319743415
+ 2.913677685545722
+ 2.9137414372003723
+ 2.9138051869384483
+ 2.9138689347601074
+ 2.9139326806655053
+ 2.913996424654799
+ 2.9140601667281443
+ 2.9141239068856972
+ 2.914187645127615
+ 2.9142513814540525
+ 2.914315115865167
+ 2.914378848361115
+ 2.914442578942052
+ 2.914506307608134
+ 2.9145700343595182
+ 2.91463375919636
+ 2.914697482118815
+ 2.9147612031270396
+ 2.9148249222211904
+ 2.914888639401424
+ 2.9149523546678946
+ 2.9150160680207597
+ 2.915079779460175
+ 2.915143488986296
+ 2.915207196599279
+ 2.91527090229928
+ 2.915334606086455
+ 2.915398307960959
+ 2.9154620079229487
+ 2.91552570597258
+ 2.915589402110008
+ 2.9156530963353897
+ 2.9157167886488797
+ 2.9157804790506345
+ 2.9158441675408096
+ 2.9159078541195607
+ 2.9159715387870433
+ 2.916035221543413
+ 2.9160989023888257
+ 2.9161625813234378
+ 2.916226258347404
+ 2.9162899334608796
+ 2.916353606664021
+ 2.9164172779569832
+ 2.916480947339922
+ 2.916544614812993
+ 2.916608280376351
+ 2.9166719440301527
+ 2.916735605774553
+ 2.9167992656097064
+ 2.9168629235357697
+ 2.9169265795528974
+ 2.9169902336612457
+ 2.9170538858609687
+ 2.917117536152223
+ 2.9171811845351625
+ 2.917244831009944
+ 2.9173084755767222
+ 2.9173721182356527
+ 2.917435758986889
+ 2.9174993978305888
+ 2.9175630347669053
+ 2.9176266697959945
+ 2.9176903029180115
+ 2.917753934133111
+ 2.9178175634414494
+ 2.9178811908431803
+ 2.9179448163384594
+ 2.9180084399274415
+ 2.918072061610282
+ 2.918135681387136
+ 2.918199299258158
+ 2.9182629152235022
+ 2.918326529283325
+ 2.918390141437781
+ 2.918453751687025
+ 2.9185173600312115
+ 2.9185809664704956
+ 2.9186445710050326
+ 2.918708173634976
+ 2.918771774360482
+ 2.918835373181704
+ 2.918898970098798
+ 2.9189625651119187
+ 2.91902615822122
+ 2.919089749426857
+ 2.919153338728984
+ 2.9192169261277567
+ 2.9192805116233287
+ 2.9193440952158554
+ 2.91940767690549
+ 2.919471256692389
+ 2.919534834576705
+ 2.9195984105585935
+ 2.9196619846382093
+ 2.9197255568157066
+ 2.9197891270912404
+ 2.9198526954649635
+ 2.919916261937032
+ 2.9199798265075994
+ 2.9200433891768207
+ 2.920106949944849
+ 2.920170508811841
+ 2.9202340657779486
+ 2.920297620843327
+ 2.920361174008131
+ 2.9204247252725146
+ 2.9204882746366314
+ 2.9205518221006366
+ 2.9206153676646833
+ 2.9206789113289267
+ 2.92074245309352
+ 2.9208059929586185
+ 2.9208695309243753
+ 2.920933066990945
+ 2.920996601158482
+ 2.9210601334271393
+ 2.9211236637970717
+ 2.9211871922684334
+ 2.921250718841377
+ 2.9213142435160586
+ 2.921377766292631
+ 2.921441287171248
+ 2.921504806152063
+ 2.9215683232352316
+ 2.9216318384209066
+ 2.9216953517092414
+ 2.921758863100391
+ 2.9218223725945083
+ 2.921885880191747
+ 2.921949385892262
+ 2.9220128896962057
+ 2.9220763916037327
+ 2.9221398916149965
+ 2.9222033897301505
+ 2.9222668859493486
+ 2.922330380272745
+ 2.922393872700492
+ 2.9224573632327444
+ 2.9225208518696557
+ 2.9225843386113786
+ 2.922647823458067
+ 2.922711306409875
+ 2.9227747874669556
+ 2.9228382666294626
+ 2.9229017438975493
+ 2.9229652192713687
+ 2.9230286927510747
+ 2.923092164336821
+ 2.9231556340287606
+ 2.923219101827047
+ 2.923282567731833
+ 2.923346031743273
+ 2.9234094938615187
+ 2.923472954086725
+ 2.923536412419045
+ 2.9235998688586307
+ 2.9236633234056364
+ 2.9237267760602146
+ 2.9237902268225193
+ 2.923853675692703
+ 2.923917122670919
+ 2.923980567757321
+ 2.924044010952061
+ 2.924107452255293
+ 2.9241708916671696
+ 2.924234329187844
+ 2.924297764817469
+ 2.9243611985561984
+ 2.9244246304041837
+ 2.9244880603615795
+ 2.924551488428538
+ 2.9246149146052116
+ 2.9246783388917543
+ 2.9247417612883178
+ 2.924805181795056
+ 2.924868600412121
+ 2.9249320171396658
+ 2.9249954319778437
+ 2.9250588449268062
+ 2.925122255986708
+ 2.9251856651577004
+ 2.9252490724399363
+ 2.925312477833568
+ 2.92537588133875
+ 2.925439282955633
+ 2.9255026826843706
+ 2.925566080525115
+ 2.925629476478019
+ 2.9256928705432355
+ 2.9257562627209164
+ 2.9258196530112146
+ 2.9258830414142825
+ 2.9259464279302727
+ 2.9260098125593377
+ 2.9260731953016297
+ 2.9261365761573015
+ 2.9261999551265054
+ 2.9262633322093934
+ 2.9263267074061186
+ 2.926390080716833
+ 2.9264534521416885
+ 2.926516821680838
+ 2.926580189334434
+ 2.9266435551026277
+ 2.926706918985573
+ 2.92677028098342
+ 2.926833641096323
+ 2.926896999324433
+ 2.926960355667903
+ 2.9270237101268837
+ 2.9270870627015286
+ 2.9271504133919892
+ 2.9272137621984182
+ 2.927277109120967
+ 2.927340454159788
+ 2.927403797315033
+ 2.9274671385868545
+ 2.9275304779754032
+ 2.927593815480833
+ 2.9276571511032947
+ 2.92772048484294
+ 2.9277838166999217
+ 2.9278471466743907
+ 2.9279104747665
+ 2.9279738009764005
+ 2.928037125304245
+ 2.928100447750184
+ 2.92816376831437
+ 2.928227086996955
+ 2.9282904037980906
+ 2.9283537187179287
+ 2.92841703175662
+ 2.9284803429143174
+ 2.9285436521911725
+ 2.9286069595873365
+ 2.928670265102961
+ 2.9287335687381977
+ 2.928796870493198
+ 2.9288601703681145
+ 2.9289234683630974
+ 2.9289867644782985
+ 2.92905005871387
+ 2.9291133510699634
+ 2.9291766415467295
+ 2.9292399301443206
+ 2.9293032168628867
+ 2.9293665017025807
+ 2.929429784663553
+ 2.9294930657459557
+ 2.92955634494994
+ 2.929619622275657
+ 2.9296828977232576
+ 2.9297461712928943
+ 2.9298094429847175
+ 2.9298727127988786
+ 2.9299359807355287
+ 2.9299992467948193
+ 2.930062510976901
+ 2.930125773281926
+ 2.930189033710045
+ 2.9302522922614087
+ 2.930315548936169
+ 2.9303788037344765
+ 2.9304420566564824
+ 2.9305053077023375
+ 2.930568556872193
+ 2.9306318041662003
+ 2.9306950495845094
+ 2.9307582931272727
+ 2.93082153479464
+ 2.930884774586763
+ 2.930948012503792
+ 2.931011248545878
+ 2.9310744827131723
+ 2.9311377150058253
+ 2.9312009454239885
+ 2.931264173967812
+ 2.931327400637447
+ 2.9313906254330435
+ 2.9314538483547534
+ 2.931517069402727
+ 2.9315802885771154
+ 2.9316435058780685
+ 2.931706721305737
+ 2.9317699348602724
+ 2.9318331465418246
+ 2.9318963563505447
+ 2.9319595642865828
+ 2.93202277035009
+ 2.9320859745412164
+ 2.932149176860113
+ 2.9322123773069304
+ 2.9322755758818184
+ 2.9323387725849277
+ 2.9324019674164097
+ 2.932465160376413
+ 2.9325283514650904
+ 2.93259154068259
+ 2.9326547280290636
+ 2.9327179135046615
+ 2.9327810971095336
+ 2.9328442788438305
+ 2.932907458707702
+ 2.932970636701299
+ 2.9330338128247715
+ 2.9330969870782693
+ 2.9331601594619436
+ 2.9332233299759443
+ 2.933286498620421
+ 2.933349665395524
+ 2.933412830301404
+ 2.933475993338211
+ 2.933539154506095
+ 2.933602313805206
+ 2.933665471235694
+ 2.933728626797709
+ 2.9337917804914015
+ 2.933854932316921
+ 2.9339180822744177
+ 2.9339812303640422
+ 2.9340443765859434
+ 2.934107520940272
+ 2.9341706634271767
+ 2.934233804046809
+ 2.934296942799318
+ 2.934360079684853
+ 2.934423214703565
+ 2.934486347855603
+ 2.9345494791411175
+ 2.9346126085602573
+ 2.934675736113173
+ 2.9347388618000134
+ 2.9348019856209295
+ 2.93486510757607
+ 2.9349282276655857
+ 2.9349913458896246
+ 2.935054462248337
+ 2.9351175767418733
+ 2.935180689370383
+ 2.9352438001340144
+ 2.9353069090329185
+ 2.935370016067244
+ 2.93543312123714
+ 2.935496224542757
+ 2.9355593259842445
+ 2.935622425561751
+ 2.935685523275427
+ 2.9357486191254214
+ 2.9358117131118835
+ 2.935874805234963
+ 2.9359378954948085
+ 2.936000983891571
+ 2.936064070425398
+ 2.9361271550964396
+ 2.9361902379048455
+ 2.9362533188507642
+ 2.9363163979343456
+ 2.9363794751557384
+ 2.936442550515092
+ 2.9365056240125558
+ 2.9365686956482784
+ 2.9366317654224097
+ 2.9366948333350984
+ 2.936757899386494
+ 2.9368209635767446
+ 2.936884025906
+ 2.9369470863744094
+ 2.9370101449821213
+ 2.937073201729286
+ 2.937136256616051
+ 2.9371993096425655
+ 2.937262360808979
+ 2.9373254101154402
+ 2.937388457562098
+ 2.9374515031491013
+ 2.9375145468765993
+ 2.93757758874474
+ 2.9376406287536736
+ 2.937703666903548
+ 2.9377667031945114
+ 2.9378297376267133
+ 2.937892770200303
+ 2.9379558009154287
+ 2.938018829772239
+ 2.9380818567708826
+ 2.938144881911508
+ 2.9382079051942647
+ 2.938270926619301
+ 2.9383339461867646
+ 2.9383969638968055
+ 2.938459979749571
+ 2.9385229937452113
+ 2.938586005883873
+ 2.938649016165706
+ 2.9387120245908585
+ 2.9387750311594787
+ 2.938838035871715
+ 2.9389010387277166
+ 2.938964039727631
+ 2.9390270388716075
+ 2.9390900361597936
+ 2.9391530315923386
+ 2.9392160251693897
+ 2.939279016891096
+ 2.939342006757607
+ 2.939404994769068
+ 2.93946798092563
+ 2.9395309652274397
+ 2.9395939476746458
+ 2.9396569282673974
+ 2.9397199070058413
+ 2.9397828838901265
+ 2.939845858920401
+ 2.9399088320968128
+ 2.93997180341951
+ 2.940034772888641
+ 2.9400977405043536
+ 2.9401607062667954
+ 2.9402236701761155
+ 2.940286632232462
+ 2.9403495924359815
+ 2.940412550786823
+ 2.9404755072851345
+ 2.9405384619310637
+ 2.9406014147247586
+ 2.940664365666367
+ 2.9407273147560367
+ 2.940790261993916
+ 2.9408532073801528
+ 2.940916150914894
+ 2.940979092598288
+ 2.9410420324304836
+ 2.9411049704116268
+ 2.941167906541866
+ 2.9412308408213494
+ 2.9412937732502247
+ 2.941356703828639
+ 2.94141963255674
+ 2.941482559434676
+ 2.9415454844625946
+ 2.941608407640643
+ 2.941671328968969
+ 2.941734248447719
+ 2.941797166077043
+ 2.9418600818570866
+ 2.941922995787998
+ 2.941985907869925
+ 2.9420488181030144
+ 2.942111726487414
+ 2.9421746330232716
+ 2.9422375377107337
+ 2.942300440549949
+ 2.9423633415410633
+ 2.9424262406842256
+ 2.942489137979582
+ 2.942552033427281
+ 2.9426149270274684
+ 2.942677818780293
+ 2.942740708685901
+ 2.94280359674444
+ 2.942866482956058
+ 2.942929367320901
+ 2.942992249839117
+ 2.9430551305108525
+ 2.9431180093362554
+ 2.9431808863154725
+ 2.943243761448651
+ 2.943306634735938
+ 2.94336950617748
+ 2.9434323757734253
+ 2.9434952435239197
+ 2.943558109429111
+ 2.9436209734891463
+ 2.9436838357041717
+ 2.943746696074335
+ 2.943809554599783
+ 2.9438724112806622
+ 2.94393526611712
+ 2.943998119109303
+ 2.9440609702573584
+ 2.944123819561433
+ 2.944186667021673
+ 2.9442495126382258
+ 2.9443123564112383
+ 2.9443751983408575
+ 2.9444380384272293
+ 2.9445008766705008
+ 2.9445637130708193
+ 2.94462654762833
+ 2.9446893803431817
+ 2.9447522112155196
+ 2.9448150402454902
+ 2.944877867433241
+ 2.9449406927789186
+ 2.9450035162826684
+ 2.9450663379446382
+ 2.9451291577649745
+ 2.9451919757438234
+ 2.945254791881331
+ 2.9453176061776447
+ 2.9453804186329102
+ 2.945443229247275
+ 2.945506038020884
+ 2.945568844953885
+ 2.945631650046424
+ 2.9456944532986467
+ 2.9457572547107005
+ 2.945820054282731
+ 2.945882852014885
+ 2.9459456479073083
+ 2.9460084419601476
+ 2.946071234173549
+ 2.946134024547659
+ 2.946196813082623
+ 2.946259599778588
+ 2.9463223846357
+ 2.946385167654106
+ 2.94644794883395
+ 2.9465107281753804
+ 2.9465735056785416
+ 2.946636281343581
+ 2.9466990551706442
+ 2.946761827159877
+ 2.946824597311426
+ 2.9468873656254364
+ 2.946950132102055
+ 2.947012896741427
+ 2.9470756595436987
+ 2.9471384205090168
+ 2.947201179637526
+ 2.9472639369293727
+ 2.9473266923847037
+ 2.947389446003663
+ 2.947452197786398
+ 2.947514947733054
+ 2.9475776958437767
+ 2.947640442118712
+ 2.9477031865580057
+ 2.947765929161803
+ 2.9478286699302507
+ 2.947891408863494
+ 2.947954145961679
+ 2.9480168812249503
+ 2.9480796146534547
+ 2.948142346247337
+ 2.9482050760067433
+ 2.948267803931819
+ 2.9483305300227096
+ 2.9483932542795612
+ 2.948455976702519
+ 2.9485186972917283
+ 2.9485814160473347
+ 2.9486441329694846
+ 2.9487068480583214
+ 2.9487695613139926
+ 2.948832272736643
+ 2.9488949823264177
+ 2.9489576900834624
+ 2.949020396007922
+ 2.9490831000999425
+ 2.9491458023596686
+ 2.9492085027872466
+ 2.9492712013828206
+ 2.949333898146537
+ 2.9493965930785397
+ 2.9494592861789757
+ 2.949521977447989
+ 2.949584666885725
+ 2.949647354492329
+ 2.949710040267946
+ 2.9497727242127216
+ 2.9498354063268004
+ 2.9498980866103284
+ 2.949960765063449
+ 2.9500234416863087
+ 2.950086116479053
+ 2.9501487894418252
+ 2.9502114605747716
+ 2.950274129878037
+ 2.9503367973517665
+ 2.9503994629961046
+ 2.950462126811196
+ 2.9505247887971864
+ 2.9505874489542205
+ 2.9506501072824425
+ 2.9507127637819983
+ 2.9507754184530324
+ 2.9508380712956894
+ 2.9509007223101142
+ 2.9509633714964516
+ 2.9510260188548467
+ 2.9510886643854435
+ 2.9511513080883875
+ 2.9512139499638232
+ 2.9512765900118954
+ 2.951339228232748
+ 2.951401864626527
+ 2.951464499193376
+ 2.95152713193344
+ 2.9515897628468637
+ 2.951652391933791
+ 2.9517150191943675
+ 2.9517776446287374
+ 2.951840268237045
+ 2.9519028900194346
+ 2.9519655099760516
+ 2.9520281281070395
+ 2.9520907444125433
+ 2.9521533588927076
+ 2.952215971547676
+ 2.952278582377594
+ 2.952341191382605
+ 2.952403798562854
+ 2.9524664039184847
+ 2.952529007449642
+ 2.9525916091564706
+ 2.9526542090391135
+ 2.9527168070977163
+ 2.9527794033324226
+ 2.9528419977433766
+ 2.9529045903307227
+ 2.952967181094605
+ 2.953029770035168
+ 2.9530923571525554
+ 2.9531549424469112
+ 2.9532175259183804
+ 2.9532801075671062
+ 2.9533426873932336
+ 2.953405265396906
+ 2.9534678415782665
+ 2.9535304159374616
+ 2.953592988474633
+ 2.953655559189926
+ 2.9537181280834837
+ 2.953780695155451
+ 2.9538432604059714
+ 2.9539058238351883
+ 2.953968385443247
+ 2.9540309452302895
+ 2.9540935031964612
+ 2.9541560593419054
+ 2.9542186136667654
+ 2.954281166171186
+ 2.954343716855311
+ 2.9544062657192827
+ 2.9544688127632464
+ 2.954531357987345
+ 2.954593901391722
+ 2.9546564429765225
+ 2.954718982741889
+ 2.9547815206879653
+ 2.9548440568148955
+ 2.9549065911228225
+ 2.9549691236118907
+ 2.9550316542822426
+ 2.9550941831340234
+ 2.955156710167375
+ 2.955219235382442
+ 2.9552817587793667
+ 2.9553442803582946
+ 2.955406800119367
+ 2.9554693180627294
+ 2.9555318341885237
+ 2.9555943484968936
+ 2.9556568609879834
+ 2.955719371661935
+ 2.9557818805188933
+ 2.9558443875590004
+ 2.9559068927824
+ 2.955969396189236
+ 2.9560318977796514
+ 2.956094397553789
+ 2.9561568955117927
+ 2.9562193916538053
+ 2.95628188597997
+ 2.95634437849043
+ 2.956406869185329
+ 2.9564693580648096
+ 2.956531845129015
+ 2.956594330378089
+ 2.956656813812173
+ 2.9567192954314123
+ 2.9567817752359487
+ 2.9568442532259254
+ 2.9569067294014855
+ 2.956969203762771
+ 2.9570316763099274
+ 2.9570941470430956
+ 2.957156615962419
+ 2.957219083068041
+ 2.957281548360104
+ 2.957344011838751
+ 2.9574064735041254
+ 2.9574689333563695
+ 2.9575313913956265
+ 2.9575938476220385
+ 2.957656302035749
+ 2.9577187546369013
+ 2.9577812054256367
+ 2.957843654402099
+ 2.957906101566431
+ 2.957968546918775
+ 2.958030990459274
+ 2.9580934321880705
+ 2.9581558721053067
+ 2.958218310211126
+ 2.9582807465056713
+ 2.958343180989084
+ 2.958405613661508
+ 2.958468044523085
+ 2.9585304735739575
+ 2.958592900814269
+ 2.958655326244161
+ 2.958717749863776
+ 2.9587801716732574
+ 2.958842591672747
+ 2.958905009862387
+ 2.958967426242321
+ 2.95902984081269
+ 2.959092253573637
+ 2.9591546645253044
+ 2.9592170736678343
+ 2.95927948100137
+ 2.9593418865260523
+ 2.959404290242025
+ 2.959466692149429
+ 2.9595290922484074
+ 2.959591490539102
+ 2.9596538870216555
+ 2.95971628169621
+ 2.959778674562908
+ 2.959841065621891
+ 2.9599034548733014
+ 2.959965842317281
+ 2.9600282279539725
+ 2.9600906117835177
+ 2.9601529938060587
+ 2.960215374021738
+ 2.960277752430697
+ 2.960340129033078
+ 2.960402503829023
+ 2.9604648768186737
+ 2.9605272480021725
+ 2.9605896173796618
+ 2.9606519849512822
+ 2.9607143507171765
+ 2.9607767146774866
+ 2.9608390768323543
+ 2.960901437181921
+ 2.9609637957263297
+ 2.961026152465721
+ 2.961088507400237
+ 2.96115086053002
+ 2.9612132118552115
+ 2.9612755613759525
+ 2.961337909092386
+ 2.961400255004653
+ 2.9614625991128958
+ 2.961524941417255
+ 2.9615872819178732
+ 2.9616496206148915
+ 2.9617119575084523
+ 2.961774292598696
+ 2.9618366258857654
+ 2.9618989573698014
+ 2.9619612870509457
+ 2.9620236149293393
+ 2.962085941005125
+ 2.962148265278443
+ 2.9622105877494356
+ 2.9622729084182438
+ 2.9623352272850094
+ 2.9623975443498733
+ 2.9624598596129776
+ 2.962522173074463
+ 2.9625844847344722
+ 2.9626467945931445
+ 2.9627091026506225
+ 2.962771408907048
+ 2.962833713362561
+ 2.9628960160173037
+ 2.962958316871417
+ 2.9630206159250423
+ 2.9630829131783205
+ 2.963145208631393
+ 2.9632075022844013
+ 2.9632697941374864
+ 2.9633320841907893
+ 2.9633943724444514
+ 2.9634566588986133
+ 2.963518943553417
+ 2.9635812264090022
+ 2.963643507465511
+ 2.963705786723085
+ 2.963768064181864
+ 2.9638303398419894
+ 2.963892613703602
+ 2.9639548857668436
+ 2.9640171560318542
+ 2.964079424498775
+ 2.9641416911677476
+ 2.9642039560389124
+ 2.96426621911241
+ 2.964328480388381
+ 2.9643907398669676
+ 2.96445299754831
+ 2.964515253432548
+ 2.9645775075198237
+ 2.964639759810277
+ 2.9647020103040487
+ 2.964764259001281
+ 2.9648265059021126
+ 2.9648887510066855
+ 2.96495099431514
+ 2.9650132358276164
+ 2.965075475544256
+ 2.9651377134651997
+ 2.965199949590587
+ 2.9652621839205593
+ 2.9653244164552564
+ 2.96538664719482
+ 2.96544887613939
+ 2.965511103289107
+ 2.965573328644111
+ 2.9656355522045437
+ 2.965697773970544
+ 2.965759993942254
+ 2.965822212119813
+ 2.9658844285033616
+ 2.9659466430930403
+ 2.96600885588899
+ 2.96607106689135
+ 2.966133276100262
+ 2.966195483515865
+ 2.9662576891383
+ 2.9663198929677073
+ 2.966382095004227
+ 2.9664442952479995
+ 2.9665064936991645
+ 2.966568690357863
+ 2.9666308852242347
+ 2.96669307829842
+ 2.9667552695805597
+ 2.9668174590707928
+ 2.9668796467692595
+ 2.966941832676101
+ 2.967004016791456
+ 2.9670661991154654
+ 2.9671283796482695
+ 2.967190558390008
+ 2.9672527353408205
+ 2.967314910500848
+ 2.96737708387023
+ 2.9674392554491056
+ 2.9675014252376157
+ 2.9675635932359006
+ 2.967625759444099
+ 2.9676879238623517
+ 2.967750086490799
+ 2.9678122473295794
+ 2.9678744063788334
+ 2.9679365636387014
+ 2.967998719109323
+ 2.968060872790837
+ 2.968123024683384
+ 2.968185174787104
+ 2.968247323102136
+ 2.9683094696286205
+ 2.968371614366696
+ 2.968433757316504
+ 2.9684958984781824
+ 2.968558037851872
+ 2.9686201754377115
+ 2.9686823112358414
+ 2.968744445246401
+ 2.96880657746953
+ 2.9688687079053673
+ 2.9689308365540534
+ 2.968992963415727
+ 2.9690550884905282
+ 2.969117211778596
+ 2.96917933328007
+ 2.96924145299509
+ 2.969303570923796
+ 2.9693656870663254
+ 2.9694278014228193
+ 2.9694899139934168
+ 2.969552024778257
+ 2.9696141337774793
+ 2.9696762409912227
+ 2.9697383464196268
+ 2.969800450062831
+ 2.969862551920975
+ 2.9699246519941975
+ 2.969986750282638
+ 2.9700488467864354
+ 2.9701109415057285
+ 2.970173034440658
+ 2.9702351255913615
+ 2.970297214957979
+ 2.970359302540649
+ 2.9704213883395116
+ 2.970483472354705
+ 2.970545554586369
+ 2.970607635034642
+ 2.970669713699663
+ 2.9707317905815716
+ 2.970793865680507
+ 2.970855938996607
+ 2.9709180105300117
+ 2.9709800802808597
+ 2.97104214824929
+ 2.971104214435441
+ 2.9711662788394526
+ 2.971228341461463
+ 2.971290402301611
+ 2.971352461360036
+ 2.9714145186368763
+ 2.971476574132271
+ 2.9715386278463587
+ 2.971600679779278
+ 2.9716627299311686
+ 2.9717247783021685
+ 2.9717868248924164
+ 2.971848869702051
+ 2.9719109127312113
+ 2.971972953980036
+ 2.972034993448663
+ 2.9720970311372317
+ 2.9721590670458813
+ 2.972221101174749
+ 2.9722831335239737
+ 2.972345164093695
+ 2.97240719288405
+ 2.9724692198951788
+ 2.9725312451272186
+ 2.972593268580308
+ 2.972655290254587
+ 2.972717310150192
+ 2.972779328267263
+ 2.972841344605937
+ 2.972903359166354
+ 2.9729653719486517
+ 2.973027382952968
+ 2.9730893921794417
+ 2.9731513996282115
+ 2.9732134052994152
+ 2.973275409193191
+ 2.9733374113096773
+ 2.973399411649013
+ 2.973461410211335
+ 2.973523406996783
+ 2.9735854020054946
+ 2.973647395237608
+ 2.9737093866932613
+ 2.9737713763725933
+ 2.973833364275741
+ 2.9738953504028434
+ 2.973957334754038
+ 2.9740193173294633
+ 2.9740812981292573
+ 2.9741432771535585
+ 2.9742052544025044
+ 2.9742672298762325
+ 2.9743292035748823
+ 2.9743911754985906
+ 2.974453145647496
+ 2.9745151140217354
+ 2.974577080621448
+ 2.9746390454467715
+ 2.9747010084978434
+ 2.9747629697748015
+ 2.974824929277784
+ 2.974886887006929
+ 2.974948842962374
+ 2.975010797144256
+ 2.9750727495527145
+ 2.975134700187886
+ 2.9751966490499084
+ 2.9752585961389197
+ 2.975320541455058
+ 2.9753824849984603
+ 2.975444426769265
+ 2.975506366767609
+ 2.9755683049936303
+ 2.9756302414474667
+ 2.975692176129256
+ 2.9757541090391353
+ 2.9758160401772424
+ 2.975877969543715
+ 2.9759398971386903
+ 2.976001822962307
+ 2.9760637470147007
+ 2.97612566929601
+ 2.976187589806372
+ 2.976249508545925
+ 2.976311425514806
+ 2.976373340713152
+ 2.9764352541411006
+ 2.9764971657987895
+ 2.9765590756863562
+ 2.976620983803938
+ 2.9766828901516713
+ 2.976744794729694
+ 2.9768066975381444
+ 2.9768685985771586
+ 2.9769304978468742
+ 2.9769923953474287
+ 2.9770542910789586
+ 2.977116185041602
+ 2.977178077235496
+ 2.9772399676607777
+ 2.9773018563175837
+ 2.9773637432060513
+ 2.9774256283263187
+ 2.9774875116785218
+ 2.9775493932627977
+ 2.9776112730792845
+ 2.9776731511281187
+ 2.977735027409437
+ 2.977796901923377
+ 2.977858774670075
+ 2.9779206456496694
+ 2.977982514862296
+ 2.9780443823080915
+ 2.9781062479871943
+ 2.9781681118997394
+ 2.978229974045865
+ 2.978291834425708
+ 2.978353693039405
+ 2.978415549887093
+ 2.978477404968908
+ 2.9785392582849877
+ 2.9786011098354694
+ 2.9786629596204883
+ 2.978724807640183
+ 2.978786653894688
+ 2.978848498384143
+ 2.9789103411086817
+ 2.9789721820684436
+ 2.979034021263563
+ 2.9790958586941776
+ 2.979157694360424
+ 2.979219528262439
+ 2.979281360400359
+ 2.9793431907743213
+ 2.979405019384461
+ 2.979466846230916
+ 2.9795286713138225
+ 2.9795904946333165
+ 2.9796523161895347
+ 2.9797141359826145
+ 2.979775954012691
+ 2.9798377702799015
+ 2.9798995847843828
+ 2.97996139752627
+ 2.980023208505701
+ 2.9800850177228115
+ 2.9801468251777377
+ 2.980208630870616
+ 2.980270434801583
+ 2.9803322369707748
+ 2.980394037378328
+ 2.980455836024379
+ 2.9805176329090637
+ 2.980579428032518
+ 2.980641221394879
+ 2.9807030129962824
+ 2.9807648028368643
+ 2.9808265909167617
+ 2.980888377236109
+ 2.980950161795045
+ 2.9810119445937033
+ 2.9810737256322217
+ 2.981135504910735
+ 2.9811972824293806
+ 2.981259058188294
+ 2.9813208321876106
+ 2.9813826044274676
+ 2.981444374908
+ 2.981506143629344
+ 2.9815679105916364
+ 2.9816296757950123
+ 2.981691439239608
+ 2.981753200925559
+ 2.981814960853002
+ 2.9818767190220727
+ 2.9819384754329064
+ 2.9820002300856387
+ 2.982061982980407
+ 2.982123734117345
+ 2.9821854834965906
+ 2.9822472311182784
+ 2.982308976982545
+ 2.982370721089525
+ 2.9824324634393546
+ 2.98249420403217
+ 2.9825559428681063
+ 2.9826176799472996
+ 2.9826794152698852
+ 2.982741148836
+ 2.982802880645777
+ 2.982864610699355
+ 2.982926338996867
+ 2.9829880655384504
+ 2.9830497903242397
+ 2.9831115133543706
+ 2.9831732346289783
+ 2.9832349541481995
+ 2.983296671912169
+ 2.9833583879210224
+ 2.983420102174895
+ 2.983481814673922
+ 2.983543525418239
+ 2.983605234407982
+ 2.9836669416432864
+ 2.9837286471242863
+ 2.9837903508511183
+ 2.9838520528239174
+ 2.9839137530428186
+ 2.9839754515079577
+ 2.98403714821947
+ 2.984098843177491
+ 2.984160536382155
+ 2.9842222278335977
+ 2.9842839175319544
+ 2.9843456054773605
+ 2.9844072916699513
+ 2.9844689761098615
+ 2.984530658797226
+ 2.984592339732181
+ 2.9846540189148607
+ 2.984715696345401
+ 2.9847773720239363
+ 2.984839045950602
+ 2.984900718125533
+ 2.9849623885488645
+ 2.9850240572207314
+ 2.9850857241412685
+ 2.9851473893106117
+ 2.985209052728895
+ 2.9852707143962536
+ 2.9853323743128226
+ 2.985394032478737
+ 2.9854556888941315
+ 2.9855173435591404
+ 2.9855789964739
+ 2.9856406476385438
+ 2.9857022970532077
+ 2.985763944718026
+ 2.9858255906331332
+ 2.9858872347986645
+ 2.985948877214755
+ 2.986010517881539
+ 2.9860721567991506
+ 2.986133793967726
+ 2.9861954293873985
+ 2.9862570630583036
+ 2.986318694980576
+ 2.9863803251543497
+ 2.98644195357976
+ 2.986503580256942
+ 2.9865652051860287
+ 2.9866268283671555
+ 2.986688449800457
+ 2.9867500694860682
+ 2.986811687424123
+ 2.986873303614756
+ 2.986934918058102
+ 2.9869965307542956
+ 2.9870581417034705
+ 2.987119750905762
+ 2.987181358361304
+ 2.987242964070231
+ 2.9873045680326773
+ 2.9873661702487775
+ 2.987427770718666
+ 2.9874893694424776
+ 2.9875509664203457
+ 2.987612561652405
+ 2.9876741551387895
+ 2.9877357468796344
+ 2.9877973368750728
+ 2.98785892512524
+ 2.987920511630269
+ 2.9879820963902954
+ 2.9880436794054526
+ 2.9881052606758747
+ 2.9881668402016968
+ 2.988228417983051
+ 2.988289994020074
+ 2.9883515683128983
+ 2.9884131408616583
+ 2.9884747116664885
+ 2.988536280727522
+ 2.988597848044894
+ 2.988659413618737
+ 2.988720977449187
+ 2.988782539536377
+ 2.9888440998804406
+ 2.988905658481512
+ 2.9889672153397258
+ 2.989028770455215
+ 2.989090323828114
+ 2.989151875458557
+ 2.9892134253466764
+ 2.9892749734926083
+ 2.9893365198964847
+ 2.9893980645584404
+ 2.989459607478609
+ 2.989521148657124
+ 2.9895826880941194
+ 2.989644225789729
+ 2.9897057617440863
+ 2.9897672959573254
+ 2.98982882842958
+ 2.9898903591609836
+ 2.98995188815167
+ 2.9900134154017723
+ 2.9900749409114247
+ 2.990136464680761
+ 2.9901979867099144
+ 2.9902595069990188
+ 2.990321025548208
+ 2.990382542357614
+ 2.990444057427372
+ 2.9905055707576156
+ 2.9905670823484773
+ 2.990628592200091
+ 2.99069010031259
+ 2.9907516066861084
+ 2.990813111320779
+ 2.9908746142167355
+ 2.990936115374111
+ 2.9909976147930397
+ 2.991059112473654
+ 2.9911206084160877
+ 2.991182102620474
+ 2.9912435950869467
+ 2.9913050858156383
+ 2.9913665748066824
+ 2.991428062060213
+ 2.991489547576362
+ 2.9915510313552645
+ 2.991612513397052
+ 2.991673993701858
+ 2.991735472269817
+ 2.99179694910106
+ 2.9918584241957222
+ 2.9919198975539354
+ 2.9919813691758335
+ 2.9920428390615497
+ 2.9921043072112163
+ 2.992165773624967
+ 2.9922272383029345
+ 2.992288701245252
+ 2.9923501624520528
+ 2.9924116219234693
+ 2.992473079659635
+ 2.9925345356606825
+ 2.992595989926745
+ 2.9926574424579555
+ 2.992718893254447
+ 2.9927803423163524
+ 2.9928417896438035
+ 2.992903235236935
+ 2.9929646790958784
+ 2.993026121220767
+ 2.9930875616117345
+ 2.993149000268912
+ 2.9932104371924333
+ 2.9932718723824308
+ 2.993333305839038
+ 2.9933947375623866
+ 2.99345616755261
+ 2.993517595809841
+ 2.993579022334212
+ 2.993640447125855
+ 2.9937018701849043
+ 2.993763291511491
+ 2.993824711105749
+ 2.9938861289678096
+ 2.993947545097806
+ 2.994008959495871
+ 2.994070372162138
+ 2.994131783096737
+ 2.994193192299803
+ 2.994254599771467
+ 2.9943160055118625
+ 2.9943774095211215
+ 2.9944388117993763
+ 2.9945002123467597
+ 2.994561611163404
+ 2.9946230082494414
+ 2.9946844036050044
+ 2.9947457972302254
+ 2.994807189125237
+ 2.994868579290172
+ 2.9949299677251613
+ 2.994991354430338
+ 2.995052739405835
+ 2.9951141226517835
+ 2.995175504168316
+ 2.9952368839555654
+ 2.9952982620136632
+ 2.9953596383427423
+ 2.9954210129429346
+ 2.995482385814372
+ 2.9955437569571868
+ 2.9956051263715118
+ 2.995666494057478
+ 2.995727860015218
+ 2.9957892242448643
+ 2.9958505867465486
+ 2.9959119475204026
+ 2.995973306566559
+ 2.99603466388515
+ 2.9960960194763064
+ 2.996157373340161
+ 2.996218725476847
+ 2.996280075886494
+ 2.996341424569236
+ 2.996402771525203
+ 2.9964641167545287
+ 2.996525460257344
+ 2.9965868020337814
+ 2.996648142083972
+ 2.996709480408048
+ 2.9967708170061416
+ 2.996832151878384
+ 2.9968934850249074
+ 2.996954816445844
+ 2.9970161461413243
+ 2.997077474111481
+ 2.997138800356446
+ 2.9972001248763505
+ 2.997261447671326
+ 2.9973227687415056
+ 2.9973840880870193
+ 2.9974454057079996
+ 2.9975067216045774
+ 2.997568035776885
+ 2.997629348225054
+ 2.997690658949216
+ 2.9977519679495024
+ 2.9978132752260445
+ 2.997874580778974
+ 2.9979358846084234
+ 2.9979971867145228
+ 2.9980584870974036
+ 2.998119785757199
+ 2.998181082694039
+ 2.998242377908055
+ 2.9983036713993787
+ 2.998364963168142
+ 2.9984262532144763
+ 2.9984875415385126
+ 2.9985488281403816
+ 2.9986101130202156
+ 2.9986713961781457
+ 2.9987326776143033
+ 2.998793957328819
+ 2.9988552353218254
+ 2.998916511593452
+ 2.998977786143832
+ 2.999039058973095
+ 2.9991003300813737
+ 2.9991615994687977
+ 2.999222867135499
+ 2.9992841330816087
+ 2.999345397307258
+ 2.999406659812578
+ 2.9994679205977
+ 2.9995291796627543
+ 2.9995904370078734
+ 2.9996516926331873
+ 2.999712946538827
+ 2.999774198724924
+ 2.999835449191609
+ 2.9998966979390134
+ 2.9999579449672678
+ 3.0000191902765034
+ 3.0000804338668505
+ 3.0001416757384414
+ 3.000202915891406
+ 3.000264154325875
+ 3.00032539104198
+ 3.0003866260398513
+ 3.00044785931962
+ 3.0005090908814176
+ 3.000570320725374
+ 3.0006315488516195
+ 3.0006927752602865
+ 3.0007539999515047
+ 3.000815222925405
+ 3.0008764441821185
+ 3.0009376637217757
+ 3.000998881544507
+ 3.001060097650443
+ 3.0011213120397153
+ 3.001182524712454
+ 3.0012437356687895
+ 3.001304944908853
+ 3.001366152432775
+ 3.001427358240685
+ 3.0014885623327148
+ 3.0015497647089946
+ 3.001610965369655
+ 3.0016721643148268
+ 3.0017333615446398
+ 3.001794557059225
+ 3.001855750858713
+ 3.0019169429432333
+ 3.001978133312918
+ 3.002039321967896
+ 3.002100508908299
+ 3.002161694134256
+ 3.002222877645899
+ 3.0022840594433564
+ 3.0023452395267602
+ 3.0024064178962404
+ 3.0024675945519266
+ 3.00252876949395
+ 3.00258994272244
+ 3.002651114237528
+ 3.0027122840393434
+ 3.0027734521280163
+ 3.0028346185036776
+ 3.0028957831664567
+ 3.0029569461164844
+ 3.0030181073538915
+ 3.0030792668788067
+ 3.003140424691361
+ 3.0032015807916843
+ 3.0032627351799066
+ 3.0033238878561583
+ 3.0033850388205696
+ 3.00344618807327
+ 3.0035073356143904
+ 3.0035684814440597
+ 3.0036296255624086
+ 3.0036907679695672
+ 3.003751908665665
+ 3.0038130476508322
+ 3.0038741849251993
+ 3.003935320488895
+ 3.00399645434205
+ 3.0040575864847945
+ 3.0041187169172576
+ 3.00417984563957
+ 3.004240972651861
+ 3.0043020979542607
+ 3.0043632215468987
+ 3.0044243434299043
+ 3.004485463603409
+ 3.00454658206754
+ 3.0046076988224293
+ 3.004668813868206
+ 3.004729927204999
+ 3.0047910388329395
+ 3.004852148752156
+ 3.004913256962779
+ 3.0049743634649366
+ 3.00503546825876
+ 3.0050965713443785
+ 3.005157672721922
+ 3.005218772391519
+ 3.0052798703532995
+ 3.0053409666073936
+ 3.005402061153931
+ 3.0054631539930403
+ 3.0055242451248514
+ 3.0055853345494943
+ 3.0056464222670978
+ 3.0057075082777915
+ 3.0057685925817057
+ 3.005829675178968
+ 3.0058907560697103
+ 3.0059518352540593
+ 3.006012912732147
+ 3.0060739885041
+ 3.00613506257005
+ 3.0061961349301254
+ 3.006257205584456
+ 3.0063182745331702
+ 3.006379341776398
+ 3.006440407314268
+ 3.0065014711469105
+ 3.006562533274454
+ 3.0066235936970283
+ 3.0066846524147617
+ 3.006745709427784
+ 3.0068067647362247
+ 3.0068678183402118
+ 3.0069288702398755
+ 3.0069899204353447
+ 3.0070509689267486
+ 3.0071120157142164
+ 3.007173060797876
+ 3.0072341041778583
+ 3.007295145854291
+ 3.0073561858273035
+ 3.007417224097025
+ 3.0074782606635844
+ 3.0075392955271107
+ 3.0076003286877326
+ 3.0076613601455797
+ 3.0077223899007803
+ 3.0077834179534633
+ 3.007844444303758
+ 3.0079054689517934
+ 3.0079664918976987
+ 3.0080275131416014
+ 3.0080885326836313
+ 3.0081495505239166
+ 3.0082105666625876
+ 3.0082715810997716
+ 3.008332593835598
+ 3.008393604870195
+ 3.008454614203692
+ 3.0085156218362177
+ 3.0085766277679
+ 3.0086376319988686
+ 3.0086986345292517
+ 3.0087596353591786
+ 3.0088206344887767
+ 3.0088816319181753
+ 3.0089426276475035
+ 3.0090036216768894
+ 3.0090646140064616
+ 3.009125604636349
+ 3.0091865935666795
+ 3.0092475807975827
+ 3.009308566329186
+ 3.009369550161618
+ 3.009430532295008
+ 3.0094915127294843
+ 3.0095524914651746
+ 3.009613468502208
+ 3.009674443840713
+ 3.0097354174808175
+ 3.0097963894226507
+ 3.0098573596663396
+ 3.009918328212014
+ 3.009979295059802
+ 3.010040260209831
+ 3.01010122366223
+ 3.010162185417128
+ 3.010223145474652
+ 3.010284103834931
+ 3.0103450604980933
+ 3.010406015464266
+ 3.010466968733579
+ 3.01052792030616
+ 3.0105888701821364
+ 3.010649818361637
+ 3.0107107648447897
+ 3.0107717096317237
+ 3.0108326527225655
+ 3.010893594117444
+ 3.0109545338164874
+ 3.011015471819823
+ 3.0110764081275807
+ 3.0111373427398864
+ 3.01119827565687
+ 3.0112592068786577
+ 3.011320136405379
+ 3.011381064237161
+ 3.011441990374132
+ 3.0115029148164205
+ 3.011563837564154
+ 3.0116247586174594
+ 3.0116856779764656
+ 3.0117465956413008
+ 3.011807511612093
+ 3.0118684258889687
+ 3.0119293384720565
+ 3.0119902493614847
+ 3.012051158557381
+ 3.0121120660598724
+ 3.0121729718690875
+ 3.012233875985154
+ 3.012294778408199
+ 3.012355679138351
+ 3.0124165781757375
+ 3.0124774755204857
+ 3.0125383711727243
+ 3.0125992651325797
+ 3.012660157400181
+ 3.012721047975654
+ 3.012781936859128
+ 3.01284282405073
+ 3.0129037095505877
+ 3.0129645933588285
+ 3.0130254754755796
+ 3.0130863559009695
+ 3.013147234635125
+ 3.013208111678174
+ 3.0132689870302434
+ 3.0133298606914614
+ 3.0133907326619553
+ 3.0134516029418523
+ 3.01351247153128
+ 3.013573338430366
+ 3.013634203639237
+ 3.0136950671580216
+ 3.013755928986846
+ 3.013816789125838
+ 3.0138776475751254
+ 3.013938504334835
+ 3.0139993594050933
+ 3.01406021278603
+ 3.0141210644777696
+ 3.0141819144804414
+ 3.0142427627941717
+ 3.0143036094190876
+ 3.014364454355317
+ 3.014425297602987
+ 3.0144861391622237
+ 3.014546979033156
+ 3.01460781721591
+ 3.0146686537106127
+ 3.014729488517392
+ 3.014790321636374
+ 3.0148511530676867
+ 3.014911982811457
+ 3.0149728108678113
+ 3.015033637236878
+ 3.0150944619187823
+ 3.0151552849136523
+ 3.015216106221615
+ 3.015276925842797
+ 3.015337743777326
+ 3.015398560025328
+ 3.0154593745869316
+ 3.0155201874622617
+ 3.015580998651446
+ 3.0156418081546112
+ 3.0157026159718847
+ 3.0157634221033933
+ 3.015824226549263
+ 3.0158850293096218
+ 3.0159458303845956
+ 3.0160066297743118
+ 3.016067427478897
+ 3.016128223498478
+ 3.016189017833181
+ 3.0162498104831337
+ 3.016310601448462
+ 3.0163713907292924
+ 3.016432178325753
+ 3.016492964237969
+ 3.016553748466068
+ 3.016614531010176
+ 3.01667531187042
+ 3.0167360910469263
+ 3.016796868539822
+ 3.016857644349233
+ 3.016918418475287
+ 3.016979190918109
+ 3.0170399616778267
+ 3.0171007307545663
+ 3.0171614981484542
+ 3.0172222638596167
+ 3.017283027888181
+ 3.0173437902342726
+ 3.0174045508980187
+ 3.017465309879545
+ 3.017526067178979
+ 3.0175868227964457
+ 3.0176475767320725
+ 3.0177083289859854
+ 3.017769079558311
+ 3.0178298284491754
+ 3.017890575658705
+ 3.017951321187026
+ 3.018012065034265
+ 3.018072807200547
+ 3.0181335476860003
+ 3.0181942864907496
+ 3.018255023614922
+ 3.0183157590586434
+ 3.0183764928220396
+ 3.018437224905237
+ 3.018497955308362
+ 3.018558684031541
+ 3.018619411074899
+ 3.018680136438564
+ 3.01874086012266
+ 3.0188015821273146
+ 3.018862302452653
+ 3.018923021098802
+ 3.018983738065886
+ 3.0190444533540335
+ 3.0191051669633686
+ 3.019165878894018
+ 3.019226589146108
+ 3.019287297719764
+ 3.0193480046151118
+ 3.0194087098322773
+ 3.0194694133713877
+ 3.0195301152325675
+ 3.0195908154159428
+ 3.0196515139216404
+ 3.019712210749785
+ 3.0197729059005027
+ 3.0198335993739196
+ 3.0198942911701616
+ 3.019954981289354
+ 3.020015669731623
+ 3.0200763564970945
+ 3.020137041585894
+ 3.020197724998147
+ 3.0202584067339795
+ 3.020319086793517
+ 3.020379765176885
+ 3.0204404418842103
+ 3.0205011169156175
+ 3.0205617902712323
+ 3.020622461951181
+ 3.020683131955588
+ 3.02074380028458
+ 3.020804466938282
+ 3.0208651319168194
+ 3.0209257952203186
+ 3.020986456848904
+ 3.0210471168027024
+ 3.021107775081838
+ 3.0211684316864376
+ 3.0212290866166254
+ 3.0212897398725276
+ 3.0213503914542694
+ 3.021411041361977
+ 3.021471689595774
+ 3.0215323361557878
+ 3.021592981042142
+ 3.0216536242549634
+ 3.0217142657943765
+ 3.0217749056605068
+ 3.0218355438534803
+ 3.0218961803734214
+ 3.0219568152204555
+ 3.0220174483947084
+ 3.0220780798963043
+ 3.02213870972537
+ 3.0221993378820295
+ 3.022259964366408
+ 3.0223205891786318
+ 3.0223812123188254
+ 3.0224418337871133
+ 3.0225024535836216
+ 3.0225630717084755
+ 3.022623688161799
+ 3.022684302943718
+ 3.0227449160543576
+ 3.022805527493843
+ 3.022866137262299
+ 3.0229267453598507
+ 3.0229873517866226
+ 3.023047956542741
+ 3.0231085596283296
+ 3.023169161043514
+ 3.0232297607884187
+ 3.023290358863169
+ 3.0233509552678903
+ 3.0234115500027063
+ 3.023472143067744
+ 3.0235327344631253
+ 3.023593324188978
+ 3.023653912245425
+ 3.0237144986325917
+ 3.023775083350603
+ 3.0238356663995845
+ 3.023896247779659
+ 3.023956827490954
+ 3.0240174055335913
+ 3.0240779819076984
+ 3.0241385566133983
+ 3.024199129650816
+ 3.024259701020076
+ 3.0243202707213044
+ 3.0243808387546243
+ 3.0244414051201605
+ 3.0245019698180386
+ 3.0245625328483827
+ 3.024623094211317
+ 3.024683653906967
+ 3.0247442119354564
+ 3.02480476829691
+ 3.0248653229914533
+ 3.0249258760192093
+ 3.0249864273803033
+ 3.02504697707486
+ 3.025107525103003
+ 3.0251680714648583
+ 3.0252286161605495
+ 3.0252891591902005
+ 3.0253497005539365
+ 3.025410240251882
+ 3.0254707782841606
+ 3.0255313146508973
+ 3.0255918493522165
+ 3.0256523823882424
+ 3.025712913759099
+ 3.025773443464911
+ 3.0258339715058034
+ 3.0258944978818993
+ 3.0259550225933234
+ 3.0260155456402
+ 3.0260760670226534
+ 3.0261365867408077
+ 3.0261971047947873
+ 3.0262576211847163
+ 3.026318135910719
+ 3.0263786489729196
+ 3.0264391603714422
+ 3.02649967010641
+ 3.026560178177949
+ 3.0266206845861823
+ 3.0266811893312338
+ 3.026741692413228
+ 3.026802193832288
+ 3.0268626935885394
+ 3.0269231916821053
+ 3.02698368811311
+ 3.027044182881677
+ 3.027104675987931
+ 3.027165167431996
+ 3.0272256572139953
+ 3.027286145334053
+ 3.0273466317922932
+ 3.02740711658884
+ 3.0274675997238174
+ 3.027528081197349
+ 3.027588561009558
+ 3.0276490391605697
+ 3.027709515650507
+ 3.0277699904794937
+ 3.027830463647654
+ 3.0278909351551113
+ 3.0279514050019896
+ 3.0280118731884134
+ 3.0280723397145053
+ 3.0281328045803892
+ 3.028193267786189
+ 3.028253729332029
+ 3.0283141892180323
+ 3.028374647444322
+ 3.028435104011023
+ 3.0284955589182583
+ 3.0285560121661512
+ 3.0286164637548265
+ 3.0286769136844067
+ 3.0287373619550153
+ 3.028797808566777
+ 3.028858253519814
+ 3.0289186968142507
+ 3.0289791384502105
+ 3.029039578427817
+ 3.029100016747193
+ 3.0291604534084624
+ 3.029220888411749
+ 3.029281321757176
+ 3.029341753444867
+ 3.029402183474945
+ 3.0294626118475336
+ 3.0295230385627567
+ 3.029583463620737
+ 3.029643887021598
+ 3.0297043087654636
+ 3.029764728852456
+ 3.0298251472826996
+ 3.0298855640563174
+ 3.029945979173432
+ 3.0300063926341676
+ 3.030066804438647
+ 3.0301272145869937
+ 3.030187623079331
+ 3.0302480299157812
+ 3.0303084350964684
+ 3.030368838621516
+ 3.030429240491046
+ 3.030489640705183
+ 3.030550039264049
+ 3.030610436167768
+ 3.0306708314164617
+ 3.030731225010255
+ 3.03079161694927
+ 3.0308520072336296
+ 3.0309123958634574
+ 3.030972782838876
+ 3.0310331681600085
+ 3.031093551826978
+ 3.031153933839908
+ 3.03121431419892
+ 3.0312746929041383
+ 3.0313350699556856
+ 3.0313954453536844
+ 3.031455819098258
+ 3.031516191189529
+ 3.0315765616276207
+ 3.0316369304126556
+ 3.0316972975447567
+ 3.0317576630240466
+ 3.0318180268506487
+ 3.031878389024685
+ 3.0319387495462795
+ 3.0319991084155533
+ 3.032059465632631
+ 3.032119821197634
+ 3.0321801751106854
+ 3.0322405273719077
+ 3.0323008779814247
+ 3.0323612269393574
+ 3.03242157424583
+ 3.0324819199009636
+ 3.0325422639048827
+ 3.0326026062577087
+ 3.0326629469595647
+ 3.032723286010573
+ 3.0327836234108556
+ 3.032843959160536
+ 3.032904293259737
+ 3.0329646257085807
+ 3.033024956507189
+ 3.0330852856556856
+ 3.0331456131541925
+ 3.0332059390028316
+ 3.0332662632017255
+ 3.0333265857509977
+ 3.0333869066507693
+ 3.0334472259011642
+ 3.0335075435023033
+ 3.03356785945431
+ 3.033628173757306
+ 3.033688486411414
+ 3.0337487974167563
+ 3.033809106773455
+ 3.0338694144816336
+ 3.033929720541413
+ 3.0339900249529155
+ 3.034050327716265
+ 3.0341106288315816
+ 3.034170928298989
+ 3.034231226118609
+ 3.0342915222905633
+ 3.0343518168149752
+ 3.0344121096919663
+ 3.034472400921658
+ 3.0345326905041743
+ 3.0345929784396355
+ 3.0346532647281643
+ 3.034713549369884
+ 3.0347738323649147
+ 3.0348341137133796
+ 3.034894393415401
+ 3.0349546714711
+ 3.0350149478806
+ 3.035075222644022
+ 3.035135495761488
+ 3.035195767233121
+ 3.035256037059041
+ 3.035316305239372
+ 3.0353765717742354
+ 3.035436836663752
+ 3.0354970999080453
+ 3.035557361507236
+ 3.035617621461447
+ 3.0356778797707995
+ 3.0357381364354157
+ 3.0357983914554163
+ 3.035858644830925
+ 3.0359188965620625
+ 3.035979146648951
+ 3.036039395091712
+ 3.0360996418904675
+ 3.0361598870453386
+ 3.036220130556448
+ 3.036280372423917
+ 3.0363406126478676
+ 3.036400851228421
+ 3.036461088165699
+ 3.0365213234598234
+ 3.036581557110916
+ 3.036641789119098
+ 3.0367020194844914
+ 3.036762248207218
+ 3.0368224752873987
+ 3.0368827007251555
+ 3.03694292452061
+ 3.037003146673884
+ 3.037063367185098
+ 3.037123586054375
+ 3.037183803281836
+ 3.0372440188676015
+ 3.0373042328117945
+ 3.0373644451145347
+ 3.0374246557759452
+ 3.0374848647961468
+ 3.0375450721752606
+ 3.037605277913409
+ 3.037665482010712
+ 3.0377256844672917
+ 3.0377858852832698
+ 3.037846084458767
+ 3.0379062819939056
+ 3.0379664778888054
+ 3.0380266721435887
+ 3.038086864758377
+ 3.0381470557332904
+ 3.038207245068452
+ 3.0382674327639814
+ 3.038327618820001
+ 3.0383878032366307
+ 3.0384479860139924
+ 3.038508167152208
+ 3.0385683466513975
+ 3.0386285245116826
+ 3.038688700733185
+ 3.0387488753160246
+ 3.038809048260324
+ 3.038869219566202
+ 3.0389293892337825
+ 3.0389895572631844
+ 3.0390497236545295
+ 3.039109888407939
+ 3.0391700515235343
+ 3.0392302130014355
+ 3.039290372841764
+ 3.0393505310446405
+ 3.039410687610187
+ 3.0394708425385235
+ 3.0395309958297707
+ 3.0395911474840505
+ 3.039651297501483
+ 3.0397114458821894
+ 3.0397715926262907
+ 3.0398317377339077
+ 3.0398918812051607
+ 3.039952023040172
+ 3.0400121632390604
+ 3.0400723018019478
+ 3.040132438728955
+ 3.0401925740202036
+ 3.040252707675813
+ 3.0403128396959036
+ 3.040372970080598
+ 3.040433098830015
+ 3.040493225944277
+ 3.0405533514235037
+ 3.040613475267816
+ 3.040673597477334
+ 3.0407337180521785
+ 3.0407938369924716
+ 3.040853954298332
+ 3.040914069969882
+ 3.04097418400724
+ 3.041034296410529
+ 3.0410944071798673
+ 3.0411545163153773
+ 3.041214623817179
+ 3.041274729685392
+ 3.0413348339201383
+ 3.041394936521537
+ 3.041455037489709
+ 3.041515136824776
+ 3.0415752345268565
+ 3.041635330596072
+ 3.0416954250325428
+ 3.041755517836389
+ 3.041815609007731
+ 3.04187569854669
+ 3.0419357864533856
+ 3.041995872727938
+ 3.0420559573704677
+ 3.042116040381096
+ 3.0421761217599412
+ 3.042236201507125
+ 3.0422962796227675
+ 3.042356356106989
+ 3.0424164309599093
+ 3.042476504181649
+ 3.042536575772328
+ 3.042596645732067
+ 3.042656714060986
+ 3.0427167807592044
+ 3.0427768458268436
+ 3.0428369092640226
+ 3.0428969710708627
+ 3.0429570312474827
+ 3.043017089794004
+ 3.0430771467105457
+ 3.043137201997228
+ 3.0431972556541718
+ 3.0432573076814964
+ 3.043317358079322
+ 3.043377406847768
+ 3.043437453986955
+ 3.043497499497003
+ 3.043557543378032
+ 3.043617585630162
+ 3.043677626253513
+ 3.043737665248204
+ 3.0437977026143557
+ 3.043857738352088
+ 3.0439177724615214
+ 3.043977804942774
+ 3.0440378357959674
+ 3.0440978650212207
+ 3.044157892618653
+ 3.044217918588386
+ 3.0442779429305378
+ 3.0443379656452287
+ 3.0443979867325783
+ 3.044458006192707
+ 3.0445180240257335
+ 3.044578040231779
+ 3.0446380548109615
+ 3.0446980677634015
+ 3.044758079089219
+ 3.0448180887885337
+ 3.044878096861465
+ 3.0449381033081315
+ 3.044998108128654
+ 3.0450581113231525
+ 3.0451181128917457
+ 3.045178112834553
+ 3.045238111151695
+ 3.04529810784329
+ 3.045358102909459
+ 3.04541809635032
+ 3.0454780881659937
+ 3.0455380783565986
+ 3.0455980669222553
+ 3.0456580538630824
+ 3.045718039179199
+ 3.0457780228707256
+ 3.0458380049377816
+ 3.0458979853804857
+ 3.045957964198957
+ 3.046017941393316
+ 3.0460779169636814
+ 3.0461378909101726
+ 3.0461978632329085
+ 3.0462578339320094
+ 3.046317803007594
+ 3.046377770459782
+ 3.046437736288692
+ 3.046497700494444
+ 3.0465576630771563
+ 3.0466176240369487
+ 3.046677583373941
+ 3.046737541088252
+ 3.0467974971799996
+ 3.0468574516493048
+ 3.0469174044962863
+ 3.046977355721063
+ 3.0470373053237534
+ 3.047097253304478
+ 3.047157199663354
+ 3.047217144400503
+ 3.047277087516042
+ 3.0473370290100914
+ 3.0473969688827696
+ 3.0474569071341953
+ 3.047516843764488
+ 3.0475767787737666
+ 3.0476367121621504
+ 3.0476966439297577
+ 3.047756574076708
+ 3.04781650260312
+ 3.047876429509113
+ 3.0479363547948055
+ 3.0479962784603165
+ 3.048056200505765
+ 3.04811612093127
+ 3.04817603973695
+ 3.048235956922924
+ 3.0482958724893114
+ 3.04835578643623
+ 3.0484156987637987
+ 3.0484756094721375
+ 3.0485355185613643
+ 3.0485954260315977
+ 3.0486553318829563
+ 3.0487152361155596
+ 3.0487751387295257
+ 3.0488350397249744
+ 3.048894939102023
+ 3.0489548368607906
+ 3.049014733001396
+ 3.049074627523958
+ 3.049134520428595
+ 3.0491944117154253
+ 3.0492543013845683
+ 3.0493141894361426
+ 3.049374075870266
+ 3.0494339606870575
+ 3.0494938438866352
+ 3.0495537254691185
+ 3.0496136054346255
+ 3.0496734837832746
+ 3.049733360515184
+ 3.049793235630473
+ 3.0498531091292596
+ 3.0499129810116616
+ 3.049972851277799
+ 3.050032719927789
+ 3.0500925869617497
+ 3.0501524523798005
+ 3.0502123161820593
+ 3.0502721783686453
+ 3.0503320389396755
+ 3.050391897895269
+ 3.0504517552355437
+ 3.0505116109606187
+ 3.0505714650706115
+ 3.0506313175656405
+ 3.0506911684458244
+ 3.0507510177112813
+ 3.0508108653621293
+ 3.050870711398486
+ 3.0509305558204716
+ 3.050990398628202
+ 3.0510502398217967
+ 3.0511100794013735
+ 3.05116991736705
+ 3.0512297537189457
+ 3.0512895884571773
+ 3.051349421581864
+ 3.0514092530931234
+ 3.0514690829910736
+ 3.051528911275833
+ 3.051588737947519
+ 3.05164856300625
+ 3.0517083864521437
+ 3.0517682082853193
+ 3.051828028505893
+ 3.0518878471139845
+ 3.051947664109711
+ 3.05200747949319
+ 3.0520672932645403
+ 3.0521271054238794
+ 3.052186915971325
+ 3.052246724906995
+ 3.0523065322310083
+ 3.0523663379434818
+ 3.0524261420445336
+ 3.0524859445342813
+ 3.0525457454128424
+ 3.052605544680336
+ 3.0526653423368795
+ 3.0527251383825895
+ 3.0527849328175853
+ 3.0528447256419837
+ 3.0529045168559024
+ 3.05296430645946
+ 3.053024094452774
+ 3.053083880835961
+ 3.0531436656091397
+ 3.0532034487724276
+ 3.053263230325942
+ 3.0533230102698017
+ 3.0533827886041234
+ 3.0534425653290245
+ 3.053502340444623
+ 3.053562113951036
+ 3.053621885848382
+ 3.0536816561367783
+ 3.0537414248163417
+ 3.0538011918871906
+ 3.0538609573494417
+ 3.053920721203214
+ 3.053980483448623
+ 3.0540402440857877
+ 3.0541000031148244
+ 3.0541597605358515
+ 3.054219516348986
+ 3.0542792705543462
+ 3.054339023152048
+ 3.05439877414221
+ 3.0544585235249486
+ 3.054518271300382
+ 3.0545780174686272
+ 3.0546377620298015
+ 3.0546975049840226
+ 3.0547572463314077
+ 3.054816986072073
+ 3.054876724206138
+ 3.054936460733718
+ 3.054996195654931
+ 3.0550559289698938
+ 3.0551156606787244
+ 3.0551753907815398
+ 3.0552351192784566
+ 3.0552948461695926
+ 3.055354571455065
+ 3.0554142951349905
+ 3.0554740172094865
+ 3.0555337376786706
+ 3.055593456542659
+ 3.055653173801569
+ 3.0557128894555188
+ 3.0557726035046238
+ 3.055832315949002
+ 3.0558920267887704
+ 3.055951736024046
+ 3.0560114436549455
+ 3.0560711496815864
+ 3.0561308541040852
+ 3.05619055692256
+ 3.0562502581371263
+ 3.0563099577479016
+ 3.0563696557550033
+ 3.0564293521585473
+ 3.056489046958651
+ 3.056548740155432
+ 3.056608431749007
+ 3.0566681217394915
+ 3.0567278101270037
+ 3.05678749691166
+ 3.0568471820935774
+ 3.056906865672873
+ 3.056966547649662
+ 3.0570262280240637
+ 3.057085906796193
+ 3.057145583966167
+ 3.057205259534103
+ 3.0572649335001167
+ 3.057324605864326
+ 3.057384276626847
+ 3.0574439457877967
+ 3.057503613347291
+ 3.0575632793054477
+ 3.0576229436623827
+ 3.057682606418212
+ 3.057742267573054
+ 3.0578019271270236
+ 3.057861585080239
+ 3.0579212414328145
+ 3.057980896184869
+ 3.058040549336518
+ 3.0581002008878775
+ 3.0581598508390653
+ 3.058219499190197
+ 3.058279145941389
+ 3.0583387910927584
+ 3.058398434644421
+ 3.058458076596494
+ 3.0585177169490936
+ 3.0585773557023352
+ 3.058636992856337
+ 3.0586966284112136
+ 3.058756262367083
+ 3.0588158947240607
+ 3.058875525482263
+ 3.0589351546418064
+ 3.0589947822028076
+ 3.059054408165382
+ 3.0591140325296466
+ 3.0591736552957176
+ 3.0592332764637113
+ 3.0592928960337438
+ 3.0593525140059312
+ 3.0594121303803905
+ 3.0594717451572366
+ 3.059531358336587
+ 3.059590969918557
+ 3.059650579903263
+ 3.0597101882908215
+ 3.059769795081349
+ 3.05982940027496
+ 3.0598890038717723
+ 3.059948605871901
+ 3.060008206275463
+ 3.0600678050825736
+ 3.06012740229335
+ 3.0601869979079064
+ 3.06024659192636
+ 3.060306184348827
+ 3.0603657751754234
+ 3.0604253644062642
+ 3.0604849520414668
+ 3.0605445380811465
+ 3.060604122525419
+ 3.0606637053744006
+ 3.060723286628207
+ 3.060782866286954
+ 3.0608424443507576
+ 3.060902020819734
+ 3.060961595693999
+ 3.0610211689736677
+ 3.0610807406588574
+ 3.061140310749683
+ 3.06119987924626
+ 3.061259446148705
+ 3.061319011457133
+ 3.0613785751716605
+ 3.061438137292402
+ 3.0614976978194752
+ 3.0615572567529945
+ 3.0616168140930764
+ 3.0616763698398355
+ 3.061735923993389
+ 3.0617954765538506
+ 3.0618550275213376
+ 3.0619145768959655
+ 3.061974124677849
+ 3.062033670867105
+ 3.0620932154638476
+ 3.062152758468194
+ 3.062212299880258
+ 3.062271839700157
+ 3.0623313779280052
+ 3.0623909145639194
+ 3.062450449608013
+ 3.062509983060404
+ 3.062569514921207
+ 3.062629045190537
+ 3.0626885738685092
+ 3.06274810095524
+ 3.0628076264508453
+ 3.0628671503554386
+ 3.062926672669137
+ 3.062986193392055
+ 3.0630457125243087
+ 3.0631052300660127
+ 3.0631647460172826
+ 3.0632242603782345
+ 3.063283773148983
+ 3.0633432843296435
+ 3.063402793920331
+ 3.0634623019211618
+ 3.06352180833225
+ 3.0635813131537124
+ 3.063640816385662
+ 3.0637003180282165
+ 3.0637598180814893
+ 3.0638193165455965
+ 3.0638788134206534
+ 3.063938308706774
+ 3.0639978024040753
+ 3.064057294512671
+ 3.064116785032677
+ 3.064176273964208
+ 3.0642357613073794
+ 3.0642952470623057
+ 3.0643547312291033
+ 3.064414213807886
+ 3.0644736947987696
+ 3.0645331742018684
+ 3.064592652017298
+ 3.064652128245174
+ 3.0647116028856107
+ 3.0647710759387228
+ 3.064830547404626
+ 3.0648900172834344
+ 3.064949485575263
+ 3.065008952280228
+ 3.065068417398444
+ 3.065127880930025
+ 3.065187342875086
+ 3.0652468032337428
+ 3.0653062620061093
+ 3.065365719192301
+ 3.065425174792433
+ 3.065484628806619
+ 3.0655440812349743
+ 3.0656035320776143
+ 3.065662981334653
+ 3.065722429006206
+ 3.0657818750923878
+ 3.065841319593313
+ 3.065900762509096
+ 3.065960203839852
+ 3.0660196435856952
+ 3.066079081746741
+ 3.066138518323104
+ 3.0661979533148984
+ 3.066257386722239
+ 3.0663168185452405
+ 3.0663762487840174
+ 3.0664356774386845
+ 3.066495104509357
+ 3.066554529996148
+ 3.0666139538991737
+ 3.0666733762185476
+ 3.0667327969543847
+ 3.066792216106799
+ 3.0668516336759057
+ 3.0669110496618193
+ 3.0669704640646533
+ 3.067029876884523
+ 3.0670892881215432
+ 3.0671486977758278
+ 3.0672081058474916
+ 3.0672675123366484
+ 3.0673269172434128
+ 3.0673863205678997
+ 3.0674457223102234
+ 3.067505122470498
+ 3.067564521048838
+ 3.0676239180453573
+ 3.067683313460171
+ 3.0677427072933927
+ 3.0678020995451374
+ 3.0678614902155186
+ 3.0679208793046517
+ 3.0679802668126497
+ 3.068039652739628
+ 3.0680990370856995
+ 3.0681584198509793
+ 3.068217801035582
+ 3.0682771806396207
+ 3.0683365586632108
+ 3.0683959351064654
+ 3.068455309969499
+ 3.0685146832524266
+ 3.068574054955361
+ 3.068633425078417
+ 3.068692793621709
+ 3.0687521605853507
+ 3.0688115259694557
+ 3.068870889774139
+ 3.0689302519995136
+ 3.068989612645695
+ 3.0690489717127956
+ 3.069108329200931
+ 3.0691676851102137
+ 3.0692270394407584
+ 3.069286392192679
+ 3.06934574336609
+ 3.0694050929611043
+ 3.069464440977837
+ 3.0695237874164003
+ 3.06958313227691
+ 3.069642475559479
+ 3.0697018172642214
+ 3.069761157391251
+ 3.069820495940682
+ 3.069879832912627
+ 3.0699391683072013
+ 3.069998502124518
+ 3.070057834364691
+ 3.0701171650278343
+ 3.0701764941140612
+ 3.0702358216234864
+ 3.0702951475562226
+ 3.0703544719123834
+ 3.070413794692083
+ 3.070473115895436
+ 3.0705324355225545
+ 3.070591753573553
+ 3.0706510700485454
+ 3.070710384947645
+ 3.070769698270965
+ 3.07082901001862
+ 3.0708883201907224
+ 3.070947628787387
+ 3.0710069358087266
+ 3.071066241254855
+ 3.071125545125886
+ 3.0711848474219323
+ 3.0712441481431085
+ 3.0713034472895275
+ 3.0713627448613035
+ 3.071422040858549
+ 3.0714813352813777
+ 3.0715406281299034
+ 3.0715999194042394
+ 3.0716592091045
+ 3.0717184972307967
+ 3.071777783783244
+ 3.071837068761956
+ 3.071896352167045
+ 3.0719556339986247
+ 3.0720149142568083
+ 3.0720741929417095
+ 3.0721334700534415
+ 3.072192745592118
+ 3.0722520195578515
+ 3.0723112919507556
+ 3.072370562770944
+ 3.072429832018529
+ 3.072489099693625
+ 3.072548365796344
+ 3.0726076303268006
+ 3.072666893285107
+ 3.072726154671377
+ 3.072785414485723
+ 3.0728446727282592
+ 3.0729039293990983
+ 3.0729631844983527
+ 3.073022438026137
+ 3.073081689982563
+ 3.073140940367744
+ 3.0732001891817937
+ 3.073259436424825
+ 3.073318682096951
+ 3.0733779261982845
+ 3.0734371687289386
+ 3.0734964096890263
+ 3.0735556490786604
+ 3.0736148868979543
+ 3.073674123147021
+ 3.073733357825973
+ 3.073792590934924
+ 3.0738518224739866
+ 3.073911052443273
+ 3.073970280842897
+ 3.0740295076729716
+ 3.074088732933609
+ 3.074147956624923
+ 3.074207178747025
+ 3.0742663993000288
+ 3.074325618284048
+ 3.074384835699194
+ 3.07444405154558
+ 3.07450326582332
+ 3.074562478532525
+ 3.0746216896733083
+ 3.074680899245783
+ 3.0747401072500624
+ 3.074799313686258
+ 3.0748585185544832
+ 3.074917721854851
+ 3.0749769235874735
+ 3.0750361237524633
+ 3.0750953223499335
+ 3.0751545193799967
+ 3.075213714842766
+ 3.0752729087383526
+ 3.0753321010668704
+ 3.0753912918284314
+ 3.075450481023149
+ 3.0755096686511343
+ 3.075568854712501
+ 3.0756280392073614
+ 3.075687222135828
+ 3.075746403498013
+ 3.0758055832940294
+ 3.07586476152399
+ 3.075923938188006
+ 3.075983113286191
+ 3.076042286818657
+ 3.076101458785516
+ 3.076160629186882
+ 3.076219798022866
+ 3.076278965293581
+ 3.0763381309991384
+ 3.076397295139652
+ 3.0764564577152336
+ 3.076515618725995
+ 3.0765747781720494
+ 3.0766339360535087
+ 3.076693092370485
+ 3.0767522471230913
+ 3.0768114003114384
+ 3.0768705519356403
+ 3.0769297019958084
+ 3.076988850492055
+ 3.0770479974244926
+ 3.077107142793233
+ 3.0771662865983886
+ 3.0772254288400718
+ 3.077284569518395
+ 3.077343708633469
+ 3.0774028461854077
+ 3.0774619821743223
+ 3.077521116600325
+ 3.077580249463528
+ 3.0776393807640434
+ 3.0776985105019827
+ 3.0777576386774594
+ 3.0778167652905846
+ 3.07787589034147
+ 3.077935013830228
+ 3.077994135756972
+ 3.078053256121811
+ 3.0781123749248596
+ 3.078171492166229
+ 3.0782306078460304
+ 3.078289721964377
+ 3.07834883452138
+ 3.078407945517151
+ 3.078467054951803
+ 3.078526162825447
+ 3.078585269138196
+ 3.07864437389016
+ 3.0787034770814525
+ 3.0787625787121846
+ 3.0788216787824685
+ 3.078880777292415
+ 3.078939874242138
+ 3.0789989696317477
+ 3.079058063461356
+ 3.079117155731075
+ 3.079176246441016
+ 3.0792353355912914
+ 3.0792944231820125
+ 3.0793535092132918
+ 3.0794125936852392
+ 3.0794716765979686
+ 3.0795307579515905
+ 3.0795898377462163
+ 3.079648915981958
+ 3.079707992658928
+ 3.079767067777237
+ 3.0798261413369965
+ 3.0798852133383186
+ 3.0799442837813147
+ 3.080003352666097
+ 3.080062419992776
+ 3.0801214857614636
+ 3.0801805499722716
+ 3.080239612625311
+ 3.0802986737206943
+ 3.0803577332585323
+ 3.080416791238936
+ 3.0804758476620178
+ 3.0805349025278894
+ 3.080593955836661
+ 3.080653007588445
+ 3.0807120577833524
+ 3.0807711064214947
+ 3.0808301535029834
+ 3.0808891990279297
+ 3.080948242996445
+ 3.0810072854086408
+ 3.0810663262646285
+ 3.081125365564519
+ 3.081184403308424
+ 3.081243439496455
+ 3.081302474128723
+ 3.081361507205339
+ 3.0814205387264146
+ 3.0814795686920604
+ 3.081538597102389
+ 3.081597623957511
+ 3.081656649257537
+ 3.081715673002579
+ 3.081774695192747
+ 3.0818337158281537
+ 3.0818927349089096
+ 3.081951752435126
+ 3.0820107684069136
+ 3.0820697828243837
+ 3.0821287956876473
+ 3.0821878069968163
+ 3.0822468167520007
+ 3.0823058249533126
+ 3.0823648316008616
+ 3.0824238366947605
+ 3.0824828402351185
+ 3.082541842222048
+ 3.08260084265566
+ 3.082659841536065
+ 3.0827188388633737
+ 3.0827778346376977
+ 3.0828368288591474
+ 3.0828958215278344
+ 3.082954812643869
+ 3.083013802207362
+ 3.0830727902184254
+ 3.083131776677169
+ 3.083190761583704
+ 3.0832497449381417
+ 3.083308726740592
+ 3.0833677069911665
+ 3.0834266856899757
+ 3.0834856628371305
+ 3.083544638432742
+ 3.0836036124769204
+ 3.083662584969777
+ 3.0837215559114215
+ 3.0837805253019663
+ 3.0838394931415207
+ 3.0838984594301966
+ 3.083957424168104
+ 3.0840163873553537
+ 3.084075348992056
+ 3.0841343090783226
+ 3.084193267614263
+ 3.0842522245999886
+ 3.08431118003561
+ 3.084370133921237
+ 3.0844290862569816
+ 3.0844880370429535
+ 3.0845469862792627
+ 3.084605933966021
+ 3.0846648801033383
+ 3.0847238246913253
+ 3.084782767730092
+ 3.0848417092197504
+ 3.084900649160409
+ 3.08495958755218
+ 3.085018524395173
+ 3.085077459689498
+ 3.085136393435267
+ 3.0851953256325886
+ 3.0852542562815746
+ 3.085313185382335
+ 3.08537211293498
+ 3.08543103893962
+ 3.085489963396366
+ 3.085548886305328
+ 3.0856078076666154
+ 3.0856667274803398
+ 3.0857256457466105
+ 3.085784562465539
+ 3.0858434776372348
+ 3.0859023912618087
+ 3.08596130333937
+ 3.0860202138700297
+ 3.086079122853898
+ 3.0861380302910852
+ 3.086196936181701
+ 3.0862558405258564
+ 3.0863147433236606
+ 3.086373644575225
+ 3.0864325442806586
+ 3.0864914424400727
+ 3.0865503390535767
+ 3.0866092341212807
+ 3.086668127643295
+ 3.0867270196197296
+ 3.0867859100506942
+ 3.0868447989363
+ 3.0869036862766563
+ 3.0869625720718727
+ 3.08702145632206
+ 3.0870803390273287
+ 3.087139220187787
+ 3.087198099803547
+ 3.0872569778747176
+ 3.0873158544014085
+ 3.0873747293837304
+ 3.087433602821793
+ 3.0874924747157055
+ 3.087551345065579
+ 3.0876102138715225
+ 3.087669081133647
+ 3.0877279468520613
+ 3.0877868110268754
+ 3.0878456736581996
+ 3.087904534746144
+ 3.0879633942908167
+ 3.08802225229233
+ 3.0880811087507922
+ 3.0881399636663134
+ 3.0881988170390033
+ 3.088257668868972
+ 3.0883165191563284
+ 3.0883753679011834
+ 3.0884342151036464
+ 3.088493060763827
+ 3.088551904881834
+ 3.088610747457779
+ 3.08866958849177
+ 3.0887284279839173
+ 3.088787265934331
+ 3.08884610234312
+ 3.0889049372103936
+ 3.0889637705362634
+ 3.0890226023208363
+ 3.0890814325642237
+ 3.089140261266535
+ 3.0891990884278795
+ 3.0892579140483662
+ 3.089316738128106
+ 3.089375560667207
+ 3.0894343816657797
+ 3.0894932011239327
+ 3.0895520190417765
+ 3.08961083541942
+ 3.0896696502569725
+ 3.089728463554544
+ 3.089787275312244
+ 3.0898460855301813
+ 3.0899048942084657
+ 3.089963701347206
+ 3.0900225069465126
+ 3.0900813110064944
+ 3.0901401135272604
+ 3.090198914508921
+ 3.0902577139515843
+ 3.09031651185536
+ 3.090375308220358
+ 3.090434103046687
+ 3.0904928963344562
+ 3.090551688083776
+ 3.090610478294754
+ 3.0906692669675007
+ 3.090728054102125
+ 3.0907868396987355
+ 3.090845623757442
+ 3.0909044062783537
+ 3.09096318726158
+ 3.09102196670723
+ 3.0910807446154123
+ 3.0911395209862365
+ 3.091198295819811
+ 3.0912570691162466
+ 3.0913158408756507
+ 3.0913746110981335
+ 3.091433379783804
+ 3.0914921469327705
+ 3.091550912545142
+ 3.0916096766210286
+ 3.091668439160539
+ 3.0917272001637817
+ 3.091785959630866
+ 3.091844717561901
+ 3.0919034739569957
+ 3.091962228816259
+ 3.0920209821398
+ 3.092079733927727
+ 3.09213848418015
+ 3.0921972328971767
+ 3.0922559800789173
+ 3.0923147257254797
+ 3.0923734698369727
+ 3.092432212413507
+ 3.0924909534551888
+ 3.0925496929621286
+ 3.0926084309344346
+ 3.092667167372216
+ 3.0927259022755815
+ 3.0927846356446405
+ 3.0928433674795004
+ 3.092902097780271
+ 3.0929608265470607
+ 3.0930195537799787
+ 3.093078279479133
+ 3.093137003644633
+ 3.093195726276587
+ 3.0932544473751036
+ 3.093313166940292
+ 3.0933718849722602
+ 3.0934306014711175
+ 3.093489316436972
+ 3.0935480298699325
+ 3.0936067417701083
+ 3.093665452137607
+ 3.0937241609725374
+ 3.093782868275009
+ 3.0938415740451286
+ 3.0939002782830065
+ 3.093958980988751
+ 3.0940176821624696
+ 3.094076381804271
+ 3.094135079914265
+ 3.094193776492559
+ 3.0942524715392614
+ 3.0943111650544814
+ 3.094369857038327
+ 3.094428547490906
+ 3.0944872364123284
+ 3.094545923802701
+ 3.0946046096621336
+ 3.0946632939907333
+ 3.09472197678861
+ 3.0947806580558703
+ 3.0948393377926235
+ 3.0948980159989783
+ 3.0949566926750425
+ 3.0950153678209245
+ 3.0950740414367326
+ 3.0951327135225752
+ 3.0951913840785603
+ 3.0952500531047966
+ 3.095308720601392
+ 3.0953673865684554
+ 3.095426051006094
+ 3.095484713914417
+ 3.0955433752935315
+ 3.0956020351435467
+ 3.0956606934645707
+ 3.095719350256711
+ 3.0957780055200765
+ 3.0958366592547746
+ 3.095895311460914
+ 3.0959539621386027
+ 3.0960126112879487
+ 3.09607125890906
+ 3.096129905002045
+ 3.0961885495670116
+ 3.096247192604068
+ 3.096305834113322
+ 3.0963644740948824
+ 3.0964231125488557
+ 3.096481749475351
+ 3.096540384874476
+ 3.0965990187463386
+ 3.0966576510910473
+ 3.0967162819087095
+ 3.096774911199433
+ 3.0968335389633266
+ 3.0968921652004973
+ 3.096950789911053
+ 3.0970094130951034
+ 3.0970680347527537
+ 3.097126654884113
+ 3.0971852734892895
+ 3.0972438905683912
+ 3.0973025061215247
+ 3.097361120148799
+ 3.0974197326503217
+ 3.0974783436262
+ 3.0975369530765424
+ 3.0975955610014565
+ 3.0976541674010494
+ 3.0977127722754294
+ 3.097771375624704
+ 3.0978299774489817
+ 3.097888577748369
+ 3.0979471765229745
+ 3.0980057737729054
+ 3.09806436949827
+ 3.098122963699175
+ 3.0981815563757293
+ 3.0982401475280397
+ 3.098298737156213
+ 3.0983573252603582
+ 3.0984159118405827
+ 3.098474496896994
+ 3.098533080429699
+ 3.098591662438806
+ 3.0986502429244225
+ 3.0987088218866554
+ 3.098767399325613
+ 3.0988259752414025
+ 3.098884549634131
+ 3.0989431225039064
+ 3.0990016938508367
+ 3.099060263675028
+ 3.099118831976589
+ 3.0991773987556264
+ 3.0992359640122484
+ 3.099294527746562
+ 3.0993530899586736
+ 3.099411650648692
+ 3.099470209816724
+ 3.0995287674628775
+ 3.099587323587259
+ 3.099645878189976
+ 3.0997044312711366
+ 3.0997629828308475
+ 3.0998215328692154
+ 3.099880081386349
+ 3.0999386283823545
+ 3.0999971738573393
+ 3.100055717811411
+ 3.1001142602446765
+ 3.100172801157244
+ 3.1002313405492186
+ 3.1002898784207096
+ 3.100348414771824
+ 3.100406949602667
+ 3.1004654829133482
+ 3.100524014703973
+ 3.1005825449746496
+ 3.1006410737254853
+ 3.100699600956586
+ 3.1007581266680595
+ 3.1008166508600135
+ 3.100875173532554
+ 3.1009336946857884
+ 3.100992214319824
+ 3.101050732434768
+ 3.1011092490307264
+ 3.1011677641078075
+ 3.101226277666118
+ 3.1012847897057645
+ 3.101343300226854
+ 3.1014018092294933
+ 3.10146031671379
+ 3.101518822679851
+ 3.1015773271277824
+ 3.1016358300576923
+ 3.1016943314696865
+ 3.1017528313638723
+ 3.101811329740357
+ 3.1018698265992466
+ 3.1019283219406493
+ 3.1019868157646706
+ 3.1020453080714177
+ 3.102103798860998
+ 3.1021622881335174
+ 3.102220775889083
+ 3.1022792621278024
+ 3.102337746849782
+ 3.1023962300551275
+ 3.1024547117439467
+ 3.102513191916346
+ 3.1025716705724324
+ 3.102630147712312
+ 3.102688623336092
+ 3.102747097443879
+ 3.10280557003578
+ 3.1028640411119013
+ 3.1029225106723493
+ 3.1029809787172313
+ 3.1030394452466528
+ 3.1030979102607215
+ 3.103156373759544
+ 3.103214835743226
+ 3.1032732962118748
+ 3.103331755165597
+ 3.1033902126044985
+ 3.1034486685286864
+ 3.103507122938267
+ 3.1035655758333474
+ 3.1036240272140327
+ 3.103682477080431
+ 3.103740925432648
+ 3.10379937227079
+ 3.1038578175949643
+ 3.103916261405276
+ 3.103974703701832
+ 3.1040331444847395
+ 3.104091583754105
+ 3.104150021510033
+ 3.104208457752632
+ 3.104266892482008
+ 3.1043253256982655
+ 3.104383757401513
+ 3.1044421875918555
+ 3.1045006162694
+ 3.1045590434342536
+ 3.1046174690865205
+ 3.1046758932263088
+ 3.1047343158537237
+ 3.104792736968873
+ 3.1048511565718604
+ 3.104909574662794
+ 3.1049679912417796
+ 3.105026406308924
+ 3.105084819864332
+ 3.1051432319081105
+ 3.1052016424403663
+ 3.105260051461205
+ 3.1053184589707326
+ 3.105376864969055
+ 3.1054352694562795
+ 3.1054936724325106
+ 3.1055520738978553
+ 3.1056104738524204
+ 3.1056688722963104
+ 3.1057272692296323
+ 3.105785664652492
+ 3.105844058564996
+ 3.1059024509672493
+ 3.1059608418593587
+ 3.10601923124143
+ 3.1060776191135693
+ 3.106136005475882
+ 3.1061943903284748
+ 3.1062527736714536
+ 3.106311155504924
+ 3.106369535828992
+ 3.106427914643764
+ 3.1064862919493446
+ 3.106544667745841
+ 3.106603042033359
+ 3.106661414812003
+ 3.1067197860818805
+ 3.1067781558430974
+ 3.1068365240957587
+ 3.1068948908399703
+ 3.106953256075838
+ 3.107011619803468
+ 3.1070699820229657
+ 3.107128342734437
+ 3.107186701937988
+ 3.107245059633724
+ 3.1073034158217507
+ 3.1073617705021745
+ 3.1074201236751002
+ 3.107478475340634
+ 3.1075368254988818
+ 3.1075951741499486
+ 3.10765352129394
+ 3.107711866930963
+ 3.107770211061122
+ 3.1078285536845227
+ 3.107886894801271
+ 3.1079452344114724
+ 3.108003572515233
+ 3.108061909112658
+ 3.1081202442038522
+ 3.108178577788922
+ 3.1082369098679736
+ 3.108295240441111
+ 3.1083535695084406
+ 3.1084118970700683
+ 3.1084702231260986
+ 3.108528547676637
+ 3.10858687072179
+ 3.1086451922616627
+ 3.1087035122963593
+ 3.108761830825987
+ 3.1088201478506505
+ 3.108878463370455
+ 3.1089367773855066
+ 3.108995089895909
+ 3.10905340090177
+ 3.109111710403193
+ 3.109170018400284
+ 3.1092283248931487
+ 3.109286629881892
+ 3.109344933366619
+ 3.109403235347436
+ 3.109461535824447
+ 3.109519834797758
+ 3.1095781322674747
+ 3.1096364282337015
+ 3.109694722696544
+ 3.1097530156561075
+ 3.1098113071124964
+ 3.1098695970658174
+ 3.1099278855161745
+ 3.1099861724636733
+ 3.1100444579084194
+ 3.110102741850517
+ 3.110161024290072
+ 3.1102193052271887
+ 3.110277584661974
+ 3.110335862594531
+ 3.110394139024965
+ 3.1104524139533827
+ 3.1105106873798882
+ 3.110568959304586
+ 3.1106272297275823
+ 3.1106854986489814
+ 3.110743766068888
+ 3.1108020319874083
+ 3.110860296404646
+ 3.110918559320707
+ 3.1109768207356954
+ 3.111035080649717
+ 3.1110933390628763
+ 3.1111515959752785
+ 3.1112098513870285
+ 3.111268105298231
+ 3.1113263577089914
+ 3.111384608619414
+ 3.111442858029604
+ 3.111501105939666
+ 3.111559352349705
+ 3.1116175972598263
+ 3.1116758406701344
+ 3.111734082580734
+ 3.1117923229917297
+ 3.1118505619032266
+ 3.111908799315329
+ 3.111967035228143
+ 3.112025269641772
+ 3.1120835025563216
+ 3.1121417339718955
+ 3.1121999638885995
+ 3.112258192306538
+ 3.1123164192258157
+ 3.112374644646537
+ 3.1124328685688067
+ 3.1124910909927297
+ 3.1125493119184107
+ 3.112607531345954
+ 3.1126657492754646
+ 3.1127239657070467
+ 3.1127821806408047
+ 3.1128403940768443
+ 3.112898606015269
+ 3.112956816456184
+ 3.113015025399693
+ 3.113073232845902
+ 3.1131314387949143
+ 3.1131896432468347
+ 3.113247846201768
+ 3.113306047659819
+ 3.113364247621091
+ 3.113422446085689
+ 3.1134806430537183
+ 3.1135388385252827
+ 3.1135970325004867
+ 3.1136552249794347
+ 3.1137134159622306
+ 3.1137716054489797
+ 3.1138297934397863
+ 3.113887979934754
+ 3.1139461649339877
+ 3.114004348437592
+ 3.11406253044567
+ 3.1141207109583284
+ 3.1141788899756695
+ 3.114237067497798
+ 3.114295243524819
+ 3.1143534180568357
+ 3.114411591093953
+ 3.1144697626362747
+ 3.114527932683906
+ 3.11458610123695
+ 3.1146442682955118
+ 3.114702433859695
+ 3.1147605979296045
+ 3.114818760505344
+ 3.114876921587018
+ 3.1149350811747296
+ 3.1149932392685846
+ 3.1150513958686856
+ 3.115109550975138
+ 3.115167704588045
+ 3.1152258567075113
+ 3.1152840073336407
+ 3.1153421564665376
+ 3.115400304106305
+ 3.1154584502530485
+ 3.1155165949068717
+ 3.1155747380678775
+ 3.115632879736171
+ 3.115691019911857
+ 3.1157491585950376
+ 3.1158072957858183
+ 3.115865431484302
+ 3.115923565690593
+ 3.1159816984047954
+ 3.116039829627014
+ 3.1160979593573512
+ 3.1161560875959116
+ 3.1162142143427993
+ 3.116272339598118
+ 3.1163304633619715
+ 3.1163885856344637
+ 3.1164467064156987
+ 3.11650482570578
+ 3.1165629435048117
+ 3.116621059812897
+ 3.116679174630141
+ 3.116737287956646
+ 3.1167953997925175
+ 3.1168535101378576
+ 3.1169116189927712
+ 3.1169697263573615
+ 3.117027832231732
+ 3.1170859366159873
+ 3.1171440395102303
+ 3.1172021409145656
+ 3.1172602408290957
+ 3.117318339253925
+ 3.117376436189157
+ 3.117434531634896
+ 3.117492625591244
+ 3.1175507180583066
+ 3.117608809036186
+ 3.117666898524987
+ 3.117724986524812
+ 3.117783073035765
+ 3.1178411580579506
+ 3.117899241591471
+ 3.1179573236364297
+ 3.1180154041929313
+ 3.1180734832610795
+ 3.1181315608409763
+ 3.118189636932726
+ 3.1182477115364327
+ 3.1183057846521987
+ 3.118363856280128
+ 3.118421926420325
+ 3.1184799950728914
+ 3.118538062237932
+ 3.11859612791555
+ 3.118654192105848
+ 3.1187122548089303
+ 3.1187703160248996
+ 3.1188283757538597
+ 3.1188864339959146
+ 3.118944490751166
+ 3.119002546019719
+ 3.1190605998016756
+ 3.1191186520971397
+ 3.119176702906215
+ 3.1192347522290036
+ 3.1192928000656104
+ 3.1193508464161375
+ 3.1194088912806883
+ 3.119466934659367
+ 3.119524976552275
+ 3.119583016959517
+ 3.119641055881196
+ 3.1196990933174145
+ 3.1197571292682764
+ 3.1198151637338847
+ 3.1198731967143427
+ 3.119931228209753
+ 3.1199892582202193
+ 3.120047286745845
+ 3.1201053137867323
+ 3.1201633393429846
+ 3.120221363414706
+ 3.1202793860019984
+ 3.120337407104965
+ 3.1203954267237095
+ 3.120453444858334
+ 3.1205114615089427
+ 3.1205694766756378
+ 3.1206274903585225
+ 3.1206855025577
+ 3.120743513273273
+ 3.1208015225053445
+ 3.120859530254018
+ 3.1209175365193955
+ 3.1209755413015805
+ 3.1210335446006763
+ 3.1210915464167854
+ 3.1211495467500106
+ 3.1212075456004547
+ 3.1212655429682212
+ 3.1213235388534124
+ 3.1213815332561317
+ 3.1214395261764816
+ 3.1214975176145647
+ 3.1215555075704846
+ 3.121613496044343
+ 3.121671483036244
+ 3.121729468546289
+ 3.1217874525745817
+ 3.121845435121225
+ 3.121903416186321
+ 3.121961395769973
+ 3.1220193738722832
+ 3.1220773504933548
+ 3.1221353256332907
+ 3.1221932992921926
+ 3.122251271470164
+ 3.122309242167308
+ 3.1223672113837257
+ 3.1224251791195217
+ 3.1224831453747974
+ 3.1225411101496556
+ 3.122599073444199
+ 3.1226570352585297
+ 3.1227149955927516
+ 3.1227729544469662
+ 3.1228309118212767
+ 3.122888867715785
+ 3.122946822130594
+ 3.1230047750658065
+ 3.1230627265215247
+ 3.1231206764978507
+ 3.123178624994888
+ 3.1232365720127384
+ 3.123294517551505
+ 3.123352461611289
+ 3.123410404192194
+ 3.1234683452943224
+ 3.123526284917776
+ 3.123584223062658
+ 3.1236421597290702
+ 3.1237000949171154
+ 3.1237580286268956
+ 3.123815960858513
+ 3.123873891612071
+ 3.123931820887671
+ 3.1239897486854153
+ 3.1240476750054067
+ 3.1241055998477476
+ 3.1241635232125398
+ 3.1242214450998858
+ 3.124279365509888
+ 3.124337284442649
+ 3.124395201898271
+ 3.1244531178768544
+ 3.124511032378504
+ 3.1245689454033214
+ 3.1246268569514077
+ 3.124684767022866
+ 3.1247426756177985
+ 3.1248005827363072
+ 3.124858488378494
+ 3.124916392544461
+ 3.1249742952343116
+ 3.1250321964481462
+ 3.125090096186068
+ 3.1251479944481786
+ 3.1252058912345806
+ 3.1252637865453754
+ 3.1253216803806656
+ 3.125379572740554
+ 3.1254374636251407
+ 3.125495353034529
+ 3.1255532409688214
+ 3.125611127428119
+ 3.125669012412524
+ 3.1257268959221385
+ 3.1257847779570644
+ 3.1258426585174037
+ 3.125900537603259
+ 3.125958415214731
+ 3.1260162913519225
+ 3.126074166014935
+ 3.126132039203871
+ 3.1261899109188316
+ 3.126247781159919
+ 3.126305649927236
+ 3.1263635172208835
+ 3.126421383040963
+ 3.1264792473875773
+ 3.126537110260828
+ 3.126594971660816
+ 3.126652831587645
+ 3.1267106900414143
+ 3.126768547022228
+ 3.1268264025301864
+ 3.1268842565653925
+ 3.126942109127947
+ 3.1269999602179515
+ 3.1270578098355086
+ 3.1271156579807196
+ 3.1271735046536864
+ 3.1272313498545103
+ 3.127289193583293
+ 3.1273470358401365
+ 3.127404876625143
+ 3.1274627159384125
+ 3.1275205537800486
+ 3.1275783901501515
+ 3.127636225048823
+ 3.1276940584761657
+ 3.12775189043228
+ 3.127809720917268
+ 3.127867549931232
+ 3.1279253774742717
+ 3.1279832035464907
+ 3.1280410281479885
+ 3.1280988512788688
+ 3.128156672939231
+ 3.128214493129178
+ 3.128272311848811
+ 3.1283301290982317
+ 3.128387944877541
+ 3.128445759186841
+ 3.1285035720262324
+ 3.128561383395817
+ 3.1286191932956964
+ 3.1286770017259715
+ 3.128734808686744
+ 3.1287926141781153
+ 3.1288504182001873
+ 3.1289082207530607
+ 3.128966021836837
+ 3.129023821451617
+ 3.1290816195975037
+ 3.1291394162745965
+ 3.129197211482998
+ 3.1292550052228085
+ 3.12931279749413
+ 3.1293705882970637
+ 3.1294283776317102
+ 3.129486165498172
+ 3.129543951896549
+ 3.129601736826944
+ 3.129659520289456
+ 3.129717302284188
+ 3.129775082811241
+ 3.129832861870716
+ 3.1298906394627135
+ 3.1299484155873354
+ 3.1300061902446825
+ 3.130063963434856
+ 3.1301217351579576
+ 3.1301795054140875
+ 3.1302372742033473
+ 3.130295041525838
+ 3.1303528073816604
+ 3.1304105717709163
+ 3.130468334693706
+ 3.130526096150131
+ 3.130583856140292
+ 3.130641614664291
+ 3.1306993717222276
+ 3.130757127314203
+ 3.1308148814403194
+ 3.1308726341006765
+ 3.1309303852953763
+ 3.130988135024519
+ 3.131045883288205
+ 3.131103630086537
+ 3.1311613754196146
+ 3.1312191192875387
+ 3.1312768616904108
+ 3.1313346026283315
+ 3.131392342101402
+ 3.1314500801097225
+ 3.1315078166533943
+ 3.131565551732518
+ 3.131623285347195
+ 3.131681017497525
+ 3.1317387481836105
+ 3.1317964774055507
+ 3.131854205163447
+ 3.1319119314573998
+ 3.131969656287511
+ 3.13202737965388
+ 3.132085101556608
+ 3.1321428219957967
+ 3.1322005409715454
+ 3.1322582584839553
+ 3.1323159745331277
+ 3.132373689119162
+ 3.13243140224216
+ 3.1324891139022215
+ 3.1325468240994483
+ 3.1326045328339402
+ 3.1326622401057977
+ 3.1327199459151225
+ 3.132777650262014
+ 3.132835353146573
+ 3.1328930545689
+ 3.1329507545290967
+ 3.133008453027262
+ 3.133066150063498
+ 3.1331238456379045
+ 3.1331815397505816
+ 3.1332392324016305
+ 3.1332969235911508
+ 3.133354613319244
+ 3.133412301586011
+ 3.133469988391551
+ 3.1335276737359647
+ 3.133585357619353
+ 3.1336430400418163
+ 3.1337007210034544
+ 3.1337584005043686
+ 3.1338160785446583
+ 3.133873755124425
+ 3.1339314302437686
+ 3.133989103902789
+ 3.1340467761015876
+ 3.1341044468402632
+ 3.134162116118918
+ 3.1342197839376507
+ 3.1342774502965627
+ 3.134335115195754
+ 3.1343927786353243
+ 3.134450440615374
+ 3.1345081011360048
+ 3.134565760197315
+ 3.134623417799406
+ 3.134681073942378
+ 3.134738728626331
+ 3.1347963818513644
+ 3.13485403361758
+ 3.1349116839250772
+ 3.1349693327739554
+ 3.135026980164316
+ 3.135084626096259
+ 3.1351422705698835
+ 3.135199913585291
+ 3.13525755514258
+ 3.1353151952418523
+ 3.135372833883207
+ 3.135430471066745
+ 3.1354881067925655
+ 3.1355457410607688
+ 3.1356033738714553
+ 3.1356610052247245
+ 3.1357186351206767
+ 3.1357762635594124
+ 3.1358338905410306
+ 3.135891516065632
+ 3.1359491401333166
+ 3.136006762744184
+ 3.1360643838983346
+ 3.136122003595868
+ 3.136179621836884
+ 3.1362372386214834
+ 3.136294853949765
+ 3.1363524678218297
+ 3.1364100802377766
+ 3.1364676911977054
+ 3.1365253007017175
+ 3.136582908749911
+ 3.1366405153423873
+ 3.136698120479245
+ 3.1367557241605835
+ 3.1368133263865046
+ 3.1368709271571067
+ 3.1369285264724893
+ 3.1369861243327537
+ 3.1370437207379984
+ 3.1371013156883234
+ 3.1371589091838286
+ 3.137216501224614
+ 3.137274091810778
+ 3.1373316809424225
+ 3.137389268619646
+ 3.137446854842548
+ 3.137504439611228
+ 3.1375620229257866
+ 3.1376196047863227
+ 3.1376771851929366
+ 3.137734764145727
+ 3.137792341644795
+ 3.1378499176902386
+ 3.137907492282158
+ 3.1379650654206532
+ 3.1380226371058235
+ 3.1380802073377687
+ 3.1381377761165874
+ 3.1381953434423804
+ 3.1382529093152467
+ 3.138310473735286
+ 3.1383680367025977
+ 3.138425598217281
+ 3.1384831582794352
+ 3.1385407168891613
+ 3.138598274046557
+ 3.138655829751723
+ 3.138713384004758
+ 3.1387709368057615
+ 3.138828488154833
+ 3.138886038052072
+ 3.1389435864975783
+ 3.139001133491451
+ 3.139058679033789
+ 3.1391162231246925
+ 3.1391737657642604
+ 3.139231306952592
+ 3.1392888466897864
+ 3.1393463849759438
+ 3.1394039218111627
+ 3.1394614571955426
+ 3.139518991129183
+ 3.139576523612183
+ 3.139634054644642
+ 3.139691584226659
+ 3.139749112358334
+ 3.139806639039765
+ 3.1398641642710525
+ 3.1399216880522953
+ 3.1399792103835917
+ 3.140036731265042
+ 3.140094250696745
+ 3.1401517686788005
+ 3.1402092852113066
+ 3.140266800294363
+ 3.1403243139280685
+ 3.1403818261125225
+ 3.140439336847824
+ 3.1404968461340728
+ 3.1405543539713667
+ 3.140611860359806
+ 3.1406693652994893
+ 3.140726868790515
+ 3.1407843708329835
+ 3.140841871426993
+ 3.1408993705726425
+ 3.1409568682700306
+ 3.141014364519258
+ 3.1410718593204217
+ 3.141129352673622
+ 3.1411868445789572
+ 3.141244335036527
+ 3.141301824046429
+ 3.1413593116087637
+ 3.141416797723629
+ 3.1414742823911244
+ 3.141531765611348
+ 3.1415892473844
+ 3.141646727710378
+ 3.141704206589382
+ 3.1417616840215095
+ 3.1418191600068606
+ 3.1418766345455333
+ 3.141934107637627
+ 3.1419915792832405
+ 3.1420490494824724
+ 3.1421065182354218
+ 3.1421639855421866
+ 3.1422214514028664
+ 3.1422789158175597
+ 3.1423363787863656
+ 3.1423938403093823
+ 3.1424513003867087
+ 3.1425087590184444
+ 3.142566216204686
+ 3.1426236719455343
+ 3.1426811262410874
+ 3.1427385790914433
+ 3.1427960304967018
+ 3.14285348045696
+ 3.142910928972318
+ 3.142968376042874
+ 3.143025821668726
+ 3.143083265849974
+ 3.143140708586715
+ 3.143198149879048
+ 3.1432555897270724
+ 3.143313028130886
+ 3.143370465090588
+ 3.143427900606276
+ 3.14348533467805
+ 3.143542767306007
+ 3.143600198490246
+ 3.1436576282308657
+ 3.143715056527965
+ 3.143772483381641
+ 3.143829908791994
+ 3.1438873327591206
+ 3.1439447552831203
+ 3.144002176364092
+ 3.1440595960021334
+ 3.144117014197343
+ 3.1441744309498194
+ 3.14423184625966
+ 3.1442892601269654
+ 3.144346672551831
+ 3.144404083534358
+ 3.144461493074643
+ 3.1445189011727845
+ 3.1445763078288818
+ 3.1446337130430324
+ 3.1446911168153346
+ 3.144748519145887
+ 3.1448059200347878
+ 3.144863319482135
+ 3.1449207174880276
+ 3.1449781140525626
+ 3.1450355091758397
+ 3.145092902857956
+ 3.14515029509901
+ 3.1452076858991
+ 3.1452650752583247
+ 3.145322463176781
+ 3.1453798496545686
+ 3.145437234691785
+ 3.145494618288528
+ 3.145552000444896
+ 3.145609381160987
+ 3.1456667604368995
+ 3.1457241382727315
+ 3.145781514668581
+ 3.145838889624546
+ 3.1458962631407243
+ 3.145953635217215
+ 3.1460110058541146
+ 3.1460683750515224
+ 3.1461257428095366
+ 3.1461831091282537
+ 3.1462404740077736
+ 3.1462978374481927
+ 3.14635519944961
+ 3.1464125600121227
+ 3.1464699191358294
+ 3.146527276820828
+ 3.1465846330672163
+ 3.146641987875092
+ 3.146699341244554
+ 3.1467566931756985
+ 3.1468140436686247
+ 3.1468713927234306
+ 3.146928740340213
+ 3.1469860865190706
+ 3.147043431260101
+ 3.1471007745634023
+ 3.1471581164290723
+ 3.147215456857208
+ 3.1472727958479085
+ 3.147330133401271
+ 3.1473874695173936
+ 3.147444804196373
+ 3.147502137438308
+ 3.147559469243296
+ 3.147616799611435
+ 3.1476741285428225
+ 3.1477314560375564
+ 3.1477887820957338
+ 3.1478461067174535
+ 3.147903429902813
+ 3.1479607516519086
+ 3.1480180719648394
+ 3.148075390841703
+ 3.148132708282596
+ 3.1481900242876173
+ 3.148247338856864
+ 3.1483046519904336
+ 3.1483619636884237
+ 3.1484192739509322
+ 3.148476582778056
+ 3.1485338901698934
+ 3.148591196126542
+ 3.1486485006480986
+ 3.148705803734661
+ 3.1487631053863274
+ 3.148820405603195
+ 3.148877704385361
+ 3.148935001732923
+ 3.1489922976459783
+ 3.149049592124625
+ 3.14910688516896
+ 3.1491641767790814
+ 3.1492214669550855
+ 3.1492787556970714
+ 3.149336043005135
+ 3.149393328879374
+ 3.1494506133198867
+ 3.1495078963267695
+ 3.1495651779001204
+ 3.1496224580400365
+ 3.1496797367466147
+ 3.1497370140199537
+ 3.149794289860149
+ 3.1498515642672995
+ 3.149908837241502
+ 3.1499661087828534
+ 3.1500233788914516
+ 3.150080647567393
+ 3.150137914810776
+ 3.1501951806216972
+ 3.150252445000254
+ 3.1503097079465436
+ 3.1503669694606637
+ 3.1504242295427103
+ 3.1504814881927823
+ 3.1505387454109757
+ 3.1505960011973873
+ 3.1506532555521156
+ 3.1507105084752567
+ 3.1507677599669086
+ 3.1508250100271677
+ 3.150882258656132
+ 3.150939505853897
+ 3.150996751620562
+ 3.151053995956222
+ 3.151111238860976
+ 3.1511684803349196
+ 3.1512257203781506
+ 3.1512829589907656
+ 3.151340196172862
+ 3.151397431924537
+ 3.1514546662458875
+ 3.15151189913701
+ 3.151569130598002
+ 3.1516263606289607
+ 3.1516835892299824
+ 3.1517408164011647
+ 3.1517980421426044
+ 3.151855266454398
+ 3.151912489336643
+ 3.1519697107894364
+ 3.1520269308128746
+ 3.152084149407054
+ 3.1521413665720734
+ 3.1521985823080283
+ 3.1522557966150155
+ 3.1523130094931324
+ 3.1523702209424753
+ 3.152427430963142
+ 3.152484639555228
+ 3.1525418467188318
+ 3.1525990524540486
+ 3.152656256760976
+ 3.1527134596397106
+ 3.152770661090349
+ 3.1528278611129883
+ 3.1528850597077254
+ 3.1529422568746566
+ 3.1529994526138787
+ 3.153056646925489
+ 3.153113839809583
+ 3.153171031266259
+ 3.1532282212956124
+ 3.1532854098977405
+ 3.1533425970727396
+ 3.1533997828207068
+ 3.1534569671417385
+ 3.153514150035931
+ 3.153571331503382
+ 3.153628511544187
+ 3.153685690158443
+ 3.1537428673462466
+ 3.153800043107695
+ 3.1538572174428836
+ 3.15391439035191
+ 3.15397156183487
+ 3.1540287318918607
+ 3.1540859005229778
+ 3.154143067728319
+ 3.15420023350798
+ 3.1542573978620574
+ 3.154314560790648
+ 3.1543717222938477
+ 3.154428882371754
+ 3.1544860410244624
+ 3.1545431982520693
+ 3.1546003540546725
+ 3.1546575084323667
+ 3.154714661385249
+ 3.1547718129134164
+ 3.1548289630169646
+ 3.1548861116959896
+ 3.154943258950589
+ 3.155000404780858
+ 3.1550575491868935
+ 3.155114692168792
+ 3.155171833726649
+ 3.155228973860562
+ 3.1552861125706264
+ 3.1553432498569394
+ 3.155400385719596
+ 3.1554575201586936
+ 3.1555146531743286
+ 3.155571784766596
+ 3.155628914935593
+ 3.1556860436814156
+ 3.15574317100416
+ 3.155800296903922
+ 3.155857421380799
+ 3.1559145444348857
+ 3.1559716660662795
+ 3.156028786275076
+ 3.1560859050613717
+ 3.1561430224252622
+ 3.156200138366844
+ 3.156257252886213
+ 3.156314365983466
+ 3.156371477658698
+ 3.1564285879120058
+ 3.156485696743486
+ 3.1565428041532333
+ 3.1565999101413453
+ 3.1566570147079167
+ 3.1567141178530442
+ 3.156771219576824
+ 3.1568283198793514
+ 3.1568854187607234
+ 3.156942516221035
+ 3.1569996122603836
+ 3.1570567068788637
+ 3.1571138000765715
+ 3.157170891853604
+ 3.157227982210056
+ 3.157285071146024
+ 3.157342158661604
+ 3.1573992447568915
+ 3.1574563294319824
+ 3.1575134126869737
+ 3.1575704945219596
+ 3.1576275749370373
+ 3.1576846539323022
+ 3.15774173150785
+ 3.1577988076637764
+ 3.1578558824001774
+ 3.1579129557171495
+ 3.1579700276147875
+ 3.158027098093188
+ 3.158084167152446
+ 3.1581412347926583
+ 3.1581983010139196
+ 3.1582553658163266
+ 3.158312429199974
+ 3.1583694911649585
+ 3.158426551711375
+ 3.1584836108393204
+ 3.158540668548889
+ 3.158597724840178
+ 3.158654779713282
+ 3.158711833168296
+ 3.1587688852053173
+ 3.158825935824441
+ 3.1588829850257625
+ 3.1589400328093777
+ 3.1589970791753816
+ 3.1590541241238705
+ 3.15911116765494
+ 3.159168209768685
+ 3.1592252504652016
+ 3.159282289744586
+ 3.159339327606933
+ 3.1593963640523373
+ 3.159453399080896
+ 3.1595104326927035
+ 3.1595674648878562
+ 3.159624495666449
+ 3.159681525028578
+ 3.159738552974338
+ 3.159795579503825
+ 3.159852604617134
+ 3.1599096283143604
+ 3.1599666505956003
+ 3.160023671460949
+ 3.160080690910501
+ 3.160137708944353
+ 3.1601947255625995
+ 3.1602517407653363
+ 3.1603087545526587
+ 3.160365766924662
+ 3.160422777881442
+ 3.160479787423093
+ 3.160536795549711
+ 3.1605938022613915
+ 3.16065080755823
+ 3.1607078114403215
+ 3.1607648139077607
+ 3.1608218149606437
+ 3.1608788145990654
+ 3.160935812823121
+ 3.160992809632906
+ 3.161049805028516
+ 3.1611067990100454
+ 3.16116379157759
+ 3.161220782731245
+ 3.161277772471105
+ 3.1613347607972657
+ 3.1613917477098226
+ 3.1614487332088705
+ 3.1615057172945042
+ 3.161562699966819
+ 3.1616196812259107
+ 3.1616766610718736
+ 3.1617336395048037
+ 3.161790616524795
+ 3.161847592131944
+ 3.1619045663263443
+ 3.161961539108092
+ 3.1620185104772816
+ 3.1620754804340088
+ 3.1621324489783675
+ 3.162189416110454
+ 3.162246381830363
+ 3.162303346138189
+ 3.162360309034027
+ 3.162417270517973
+ 3.162474230590121
+ 3.162531189250566
+ 3.1625881464994032
+ 3.162645102336728
+ 3.162702056762635
+ 3.1627590097772185
+ 3.1628159613805744
+ 3.162872911572797
+ 3.162929860353981
+ 3.1629868077242222
+ 3.1630437536836147
+ 3.163100698232254
+ 3.1631576413702343
+ 3.163214583097651
+ 3.163271523414598
+ 3.1633284623211715
+ 3.1633853998174652
+ 3.1634423359035746
+ 3.163499270579594
+ 3.163556203845619
+ 3.163613135701743
+ 3.163670066148062
+ 3.1637269951846694
+ 3.163783922811662
+ 3.1638408490291328
+ 3.163897773837177
+ 3.1639546972358894
+ 3.164011619225365
+ 3.1640685398056982
+ 3.1641254589769834
+ 3.164182376739316
+ 3.16423929309279
+ 3.1642962080375003
+ 3.164353121573541
+ 3.1644100337010084
+ 3.164466944419995
+ 3.164523853730597
+ 3.164580761632908
+ 3.1646376681270225
+ 3.1646945732130365
+ 3.164751476891043
+ 3.164808379161137
+ 3.1648652800234136
+ 3.164922179477967
+ 3.1649790775248907
+ 3.1650359741642813
+ 3.165092869396232
+ 3.1651497632208376
+ 3.165206655638192
+ 3.16526354664839
+ 3.165320436251527
+ 3.165377324447696
+ 3.165434211236992
+ 3.16549109661951
+ 3.165547980595344
+ 3.1656048631645883
+ 3.165661744327337
+ 3.1657186240836857
+ 3.165775502433727
+ 3.165832379377557
+ 3.1658892549152684
+ 3.165946129046957
+ 3.1660030017727165
+ 3.1660598730926415
+ 3.166116743006826
+ 3.1661736115153643
+ 3.166230478618351
+ 3.1662873443158803
+ 3.166344208608046
+ 3.166401071494943
+ 3.1664579329766656
+ 3.1665147930533073
+ 3.166571651724963
+ 3.1666285089917268
+ 3.166685364853693
+ 3.166742219310955
+ 3.166799072363608
+ 3.166855924011746
+ 3.1669127742554632
+ 3.166969623094853
+ 3.167026470530011
+ 3.1670833165610293
+ 3.167140161188004
+ 3.1671970044110282
+ 3.1672538462301967
+ 3.167310686645603
+ 3.167367525657341
+ 3.1674243632655052
+ 3.1674811994701897
+ 3.1675380342714883
+ 3.1675948676694956
+ 3.167651699664305
+ 3.167708530256011
+ 3.1677653594447066
+ 3.1678221872304873
+ 3.1678790136134465
+ 3.167935838593678
+ 3.1679926621712755
+ 3.1680494843463336
+ 3.168106305118946
+ 3.168163124489207
+ 3.1682199424572097
+ 3.168276759023049
+ 3.168333574186818
+ 3.168390387948611
+ 3.168447200308522
+ 3.1685040112666445
+ 3.1685608208230724
+ 3.1686176289779007
+ 3.168674435731222
+ 3.1687312410831305
+ 3.1687880450337196
+ 3.1688448475830833
+ 3.1689016487313166
+ 3.1689584484785116
+ 3.169015246824763
+ 3.1690720437701647
+ 3.1691288393148103
+ 3.169185633458793
+ 3.169242426202208
+ 3.169299217545147
+ 3.169356007487705
+ 3.169412796029976
+ 3.169469583172053
+ 3.1695263689140303
+ 3.1695831532560006
+ 3.1696399361980587
+ 3.169696717740298
+ 3.1697534978828115
+ 3.169810276625694
+ 3.1698670539690377
+ 3.169923829912937
+ 3.1699806044574856
+ 3.1700373776027777
+ 3.1700941493489054
+ 3.1701509196959634
+ 3.170207688644045
+ 3.170264456193244
+ 3.170321222343653
+ 3.1703779870953674
+ 3.170434750448479
+ 3.1704915124030815
+ 3.170548272959269
+ 3.1706050321171353
+ 3.1706617898767737
+ 3.170718546238277
+ 3.1707753012017394
+ 3.1708320547672537
+ 3.170888806934914
+ 3.170945557704814
+ 3.171002307077046
+ 3.171059055051704
+ 3.1711158016288823
+ 3.171172546808673
+ 3.171229290591169
+ 3.1712860329764663
+ 3.1713427739646556
+ 3.1713995135558317
+ 3.1714562517500875
+ 3.171512988547516
+ 3.171569723948212
+ 3.1716264579522675
+ 3.1716831905597753
+ 3.1717399217708304
+ 3.1717966515855243
+ 3.171853380003952
+ 3.1719101070262057
+ 3.171966832652379
+ 3.1720235568825648
+ 3.172080279716857
+ 3.172137001155348
+ 3.172193721198132
+ 3.172250439845301
+ 3.172307157096949
+ 3.1723638729531696
+ 3.1724205874140554
+ 3.172477300479699
+ 3.1725340121501953
+ 3.172590722425636
+ 3.172647431306114
+ 3.1727041387917234
+ 3.172760844882557
+ 3.1728175495787077
+ 3.172874252880269
+ 3.172930954787334
+ 3.172987655299995
+ 3.1730443544183453
+ 3.173101052142479
+ 3.173157748472488
+ 3.173214443408466
+ 3.1732711369505058
+ 3.173327829098701
+ 3.173384519853143
+ 3.173441209213926
+ 3.173497897181144
+ 3.1735545837548873
+ 3.173611268935251
+ 3.1736679527223273
+ 3.1737246351162094
+ 3.1737813161169903
+ 3.1738379957247624
+ 3.173894673939619
+ 3.1739513507616537
+ 3.1740080261909576
+ 3.1740647002276257
+ 3.174121372871749
+ 3.1741780441234217
+ 3.174234713982736
+ 3.1742913824497845
+ 3.174348049524661
+ 3.1744047152074577
+ 3.174461379498268
+ 3.1745180423971835
+ 3.1745747039042977
+ 3.1746313640197035
+ 3.174688022743494
+ 3.174744680075761
+ 3.174801336016598
+ 3.174857990566098
+ 3.1749146437243527
+ 3.174971295491456
+ 3.1750279458675
+ 3.175084594852577
+ 3.1751412424467804
+ 3.1751978886502026
+ 3.175254533462936
+ 3.1753111768850735
+ 3.1753678189167083
+ 3.1754244595579326
+ 3.1754810988088384
+ 3.17553773666952
+ 3.175594373140068
+ 3.175651008220576
+ 3.175707641911137
+ 3.1757642742118435
+ 3.1758209051227873
+ 3.1758775346440613
+ 3.175934162775758
+ 3.1759907895179706
+ 3.1760474148707907
+ 3.1761040388343114
+ 3.176160661408625
+ 3.1762172825938246
+ 3.176273902390002
+ 3.1763305207972494
+ 3.1763871378156603
+ 3.176443753445326
+ 3.17650036768634
+ 3.1765569805387943
+ 3.176613592002781
+ 3.1766702020783932
+ 3.176726810765723
+ 3.1767834180648626
+ 3.1768400239759047
+ 3.1768966284989415
+ 3.176953231634066
+ 3.177009833381369
+ 3.1770664337409444
+ 3.177123032712884
+ 3.1771796302972803
+ 3.1772362264942253
+ 3.177292821303812
+ 3.1773494147261316
+ 3.177406006761277
+ 3.1774625974093405
+ 3.177519186670415
+ 3.177575774544591
+ 3.177632361031963
+ 3.1776889461326214
+ 3.1777455298466593
+ 3.1778021121741693
+ 3.177858693115242
+ 3.177915272669972
+ 3.1779718508384494
+ 3.178028427620767
+ 3.178085003017018
+ 3.1781415770272927
+ 3.178198149651685
+ 3.1782547208902865
+ 3.1783112907431885
+ 3.1783678592104843
+ 3.178424426292265
+ 3.178480991988624
+ 3.1785375562996516
+ 3.178594119225442
+ 3.1786506807660855
+ 3.178707240921675
+ 3.1787637996923017
+ 3.1788203570780595
+ 3.178876913079039
+ 3.1789334676953316
+ 3.1789900209270305
+ 3.179046572774228
+ 3.1791031232370153
+ 3.1791596723154845
+ 3.1792162200097276
+ 3.179272766319837
+ 3.179329311245904
+ 3.1793858547880207
+ 3.1794423969462797
+ 3.179498937720772
+ 3.17955547711159
+ 3.1796120151188254
+ 3.1796685517425702
+ 3.1797250869829163
+ 3.179781620839956
+ 3.17983815331378
+ 3.1798946844044815
+ 3.1799512141121515
+ 3.180007742436882
+ 3.1800642693787653
+ 3.1801207949378925
+ 3.180177319114356
+ 3.180233841908247
+ 3.1802903633196578
+ 3.18034688334868
+ 3.1804034019954055
+ 3.180459919259926
+ 3.1805164351423327
+ 3.180572949642718
+ 3.180629462761173
+ 3.1806859744977904
+ 3.1807424848526615
+ 3.1807989938258774
+ 3.1808555014175304
+ 3.180912007627712
+ 3.1809685124565137
+ 3.1810250159040274
+ 3.181081517970345
+ 3.181138018655558
+ 3.1811945179597574
+ 3.1812510158830354
+ 3.181307512425483
+ 3.181364007587193
+ 3.181420501368256
+ 3.1814769937687637
+ 3.1815334847888077
+ 3.1815899744284803
+ 3.1816464626878718
+ 3.181702949567075
+ 3.18175943506618
+ 3.1818159191852793
+ 3.181872401924464
+ 3.1819288832838266
+ 3.1819853632634567
+ 3.1820418418634477
+ 3.1820983190838903
+ 3.1821547949248754
+ 3.1822112693864955
+ 3.182267742468841
+ 3.182324214172004
+ 3.182380684496076
+ 3.1824371534411475
+ 3.1824936210073114
+ 3.1825500871946573
+ 3.1826065520032785
+ 3.1826630154332647
+ 3.182719477484708
+ 3.1827759381577
+ 3.1828323974523314
+ 3.1828888553686943
+ 3.182945311906879
+ 3.183001767066978
+ 3.1830582208490816
+ 3.183114673253282
+ 3.1831711242796694
+ 3.183227573928336
+ 3.183284022199372
+ 3.18334046909287
+ 3.1833969146089203
+ 3.1834533587476153
+ 3.1835098015090444
+ 3.1835662428933005
+ 3.1836226829004737
+ 3.183679121530655
+ 3.183735558783937
+ 3.18379199466041
+ 3.1838484291601645
+ 3.183904862283293
+ 3.183961294029886
+ 3.184017724400034
+ 3.184074153393829
+ 3.184130581011362
+ 3.184187007252724
+ 3.1842434321180058
+ 3.184299855607299
+ 3.184356277720694
+ 3.184412698458283
+ 3.1844691178201554
+ 3.184525535806404
+ 3.1845819524171186
+ 3.184638367652391
+ 3.184694781512311
+ 3.184751193996971
+ 3.184807605106461
+ 3.184864014840873
+ 3.1849204232002974
+ 3.184976830184825
+ 3.1850332357945477
+ 3.1850896400295547
+ 3.1851460428899383
+ 3.185202444375789
+ 3.1852588444871976
+ 3.185315243224255
+ 3.1853716405870527
+ 3.185428036575681
+ 3.185484431190231
+ 3.1855408244307934
+ 3.1855972162974595
+ 3.185653606790319
+ 3.1857099959094644
+ 3.1857663836549857
+ 3.185822770026973
+ 3.185879155025518
+ 3.1859355386507118
+ 3.185991920902644
+ 3.186048301781407
+ 3.1861046812870897
+ 3.1861610594197844
+ 3.186217436179581
+ 3.1862738115665707
+ 3.1863301855808435
+ 3.186386558222491
+ 3.1864429294916037
+ 3.186499299388272
+ 3.186555667912587
+ 3.186612035064639
+ 3.186668400844519
+ 3.186724765252317
+ 3.1867811282881244
+ 3.1868374899520315
+ 3.186893850244129
+ 3.1869502091645074
+ 3.1870065667132574
+ 3.1870629228904703
+ 3.187119277696236
+ 3.187175631130644
+ 3.187231983193787
+ 3.187288333885754
+ 3.1873446832066366
+ 3.187401031156525
+ 3.1874573777355093
+ 3.1875137229436796
+ 3.187570066781128
+ 3.1876264092479443
+ 3.1876827503442184
+ 3.1877390900700413
+ 3.187795428425504
+ 3.1878517654106955
+ 3.1879081010257075
+ 3.1879644352706302
+ 3.1880207681455537
+ 3.1880770996505685
+ 3.1881334297857653
+ 3.188189758551235
+ 3.1882460859470667
+ 3.1883024119733516
+ 3.18835873663018
+ 3.188415059917642
+ 3.188471381835828
+ 3.1885277023848295
+ 3.1885840215647354
+ 3.188640339375636
+ 3.1886966558176226
+ 3.188752970890785
+ 3.1888092845952136
+ 3.1888655969309982
+ 3.18892190789823
+ 3.1889782174969987
+ 3.1890345257273944
+ 3.1890908325895078
+ 3.189147138083429
+ 3.1892034422092475
+ 3.189259744967055
+ 3.1893160463569408
+ 3.189372346378995
+ 3.1894286450333085
+ 3.1894849423199703
+ 3.1895412382390713
+ 3.1895975327907022
+ 3.1896538259749523
+ 3.189710117791912
+ 3.1897664082416717
+ 3.1898226973243213
+ 3.1898789850399507
+ 3.18993527138865
+ 3.1899915563705106
+ 3.1900478399856205
+ 3.190104122234071
+ 3.1901604031159523
+ 3.1902166826313536
+ 3.1902729607803657
+ 3.1903292375630783
+ 3.190385512979582
+ 3.1904417870299664
+ 3.1904980597143213
+ 3.1905543310327364
+ 3.190610600985303
+ 3.1906668695721097
+ 3.190723136793247
+ 3.190779402648805
+ 3.1908356671388742
+ 3.190891930263543
+ 3.1909481920229026
+ 3.1910044524170424
+ 3.1910607114460525
+ 3.191116969110023
+ 3.191173225409043
+ 3.1912294803432033
+ 3.1912857339125935
+ 3.1913419861173034
+ 3.191398236957423
+ 3.1914544864330416
+ 3.1915107345442495
+ 3.1915669812911367
+ 3.1916232266737925
+ 3.191679470692307
+ 3.19173571334677
+ 3.1917919546372717
+ 3.1918481945639012
+ 3.1919044331267483
+ 3.191960670325903
+ 3.192016906161455
+ 3.1920731406334943
+ 3.1921293737421106
+ 3.192185605487393
+ 3.192241835869432
+ 3.1922980648883166
+ 3.192354292544137
+ 3.1924105188369825
+ 3.1924667437669436
+ 3.1925229673341087
+ 3.1925791895385682
+ 3.1926354103804115
+ 3.1926916298597288
+ 3.192747847976609
+ 3.1928040647311424
+ 3.192860280123418
+ 3.1929164941535255
+ 3.192972706821555
+ 3.1930289181275953
+ 3.1930851280717367
+ 3.193141336654068
+ 3.193197543874679
+ 3.19325374973366
+ 3.1933099542310996
+ 3.1933661573670884
+ 3.193422359141714
+ 3.193478559555068
+ 3.1935347586072385
+ 3.193590956298315
+ 3.193647152628388
+ 3.193703347597546
+ 3.1937595412058792
+ 3.1938157334534765
+ 3.1938719243404274
+ 3.1939281138668214
+ 3.1939843020327485
+ 3.194040488838297
+ 3.194096674283557
+ 3.194152858368618
+ 3.1942090410935684
+ 3.1942652224584984
+ 3.1943214024634976
+ 3.1943775811086543
+ 3.194433758394059
+ 3.1944899343198006
+ 3.194546108885968
+ 3.194602282092651
+ 3.1946584539399394
+ 3.194714624427921
+ 3.1947707935566863
+ 3.1948269613263243
+ 3.1948831277369236
+ 3.1949392927885745
+ 3.194995456481365
+ 3.195051618815386
+ 3.195107779790726
+ 3.195163939407473
+ 3.1952200976657177
+ 3.1952762545655493
+ 3.1953324101070555
+ 3.1953885642903272
+ 3.1954447171154525
+ 3.195500868582521
+ 3.1955570186916216
+ 3.195613167442844
+ 3.1956693148362763
+ 3.1957254608720085
+ 3.195781605550129
+ 3.195837748870728
+ 3.1958938908338936
+ 3.195950031439715
+ 3.196006170688282
+ 3.1960623085796827
+ 3.196118445114007
+ 3.196174580291343
+ 3.1962307141117803
+ 3.196286846575408
+ 3.196342977682315
+ 3.1963991074325904
+ 3.1964552358263227
+ 3.1965113628636015
+ 3.1965674885445154
+ 3.196623612869154
+ 3.196679735837605
+ 3.1967358574499585
+ 3.196791977706303
+ 3.196848096606727
+ 3.19690421415132
+ 3.196960330340172
+ 3.1970164451733694
+ 3.1970725586510027
+ 3.1971286707731603
+ 3.197184781539932
+ 3.1972408909514054
+ 3.197296999007669
+ 3.197353105708814
+ 3.1974092110549264
+ 3.197465315046097
+ 3.1975214176824136
+ 3.1975775189639655
+ 3.1976336188908414
+ 3.1976897174631302
+ 3.1977458146809203
+ 3.1978019105443
+ 3.1978580050533596
+ 3.197914098208187
+ 3.1979701900088706
+ 3.1980262804554993
+ 3.1980823695481617
+ 3.1981384572869476
+ 3.1981945436719443
+ 3.198250628703241
+ 3.198306712380927
+ 3.1983627947050897
+ 3.1984188756758183
+ 3.1984749552932024
+ 3.1985310335573294
+ 3.198587110468288
+ 3.198643186026168
+ 3.1986992602310567
+ 3.1987553330830436
+ 3.1988114045822162
+ 3.1988674747286643
+ 3.198923543522476
+ 3.19897961096374
+ 3.199035677052544
+ 3.199091741788978
+ 3.1991478051731295
+ 3.199203867205087
+ 3.19925992788494
+ 3.199315987212776
+ 3.199372045188684
+ 3.1994281018127517
+ 3.199484157085069
+ 3.199540211005723
+ 3.199596263574803
+ 3.199652314792397
+ 3.199708364658594
+ 3.1997644131734817
+ 3.199820460337149
+ 3.1998765061496846
+ 3.1999325506111758
+ 3.199988593721712
+ 3.200044635481382
+ 3.2001006758902726
+ 3.2001567149484735
+ 3.200212752656072
+ 3.200268789013158
+ 3.2003248240198183
+ 3.200380857676142
+ 3.200436889982217
+ 3.200492920938132
+ 3.2005489505439755
+ 3.200604978799835
+ 3.200661005705799
+ 3.200717031261957
+ 3.200773055468395
+ 3.2008290783252034
+ 3.2008850998324694
+ 3.200941119990281
+ 3.2009971387987277
+ 3.2010531562578963
+ 3.2011091723678757
+ 3.2011651871287534
+ 3.2012212005406186
+ 3.2012772126035594
+ 3.201333223317663
+ 3.2013892326830184
+ 3.2014452406997136
+ 3.2015012473678364
+ 3.2015572526874756
+ 3.2016132566587183
+ 3.201669259281654
+ 3.201725260556369
+ 3.201781260482953
+ 3.2018372590614934
+ 3.2018932562920783
+ 3.201949252174796
+ 3.2020052467097346
+ 3.202061239896982
+ 3.2021172317366253
+ 3.2021732222287542
+ 3.202229211373456
+ 3.2022851991708188
+ 3.20234118562093
+ 3.202397170723878
+ 3.202453154479751
+ 3.2025091368886365
+ 3.202565117950623
+ 3.2026210976657983
+ 3.20267707603425
+ 3.2027330530560665
+ 3.2027890287313356
+ 3.202845003060145
+ 3.2029009760425824
+ 3.2029569476787367
+ 3.2030129179686946
+ 3.2030688869125448
+ 3.2031248545103748
+ 3.203180820762273
+ 3.203236785668326
+ 3.2032927492286225
+ 3.2033487114432506
+ 3.203404672312298
+ 3.2034606318358523
+ 3.2035165900140012
+ 3.203572546846832
+ 3.2036285023344337
+ 3.203684456476893
+ 3.2037404092742987
+ 3.2037963607267375
+ 3.203852310834298
+ 3.203908259597067
+ 3.2039642070151335
+ 3.2040201530885843
+ 3.2040760978175076
+ 3.2041320412019902
+ 3.2041879832421207
+ 3.204243923937987
+ 3.2042998632896755
+ 3.204355801297275
+ 3.2044117379608728
+ 3.204467673280557
+ 3.204523607256414
+ 3.204579539888533
+ 3.2046354711769998
+ 3.2046914011219036
+ 3.2047473297233315
+ 3.204803256981371
+ 3.2048591828961097
+ 3.2049151074676354
+ 3.204971030696035
+ 3.2050269525813966
+ 3.205082873123808
+ 3.205138792323356
+ 3.205194710180129
+ 3.2052506266942133
+ 3.2053065418656974
+ 3.2053624556946687
+ 3.2054183681812147
+ 3.205474279325422
+ 3.2055301891273795
+ 3.2055860975871733
+ 3.2056420047048917
+ 3.205697910480622
+ 3.2057538149144515
+ 3.2058097180064675
+ 3.205865619756757
+ 3.2059215201654094
+ 3.2059774192325095
+ 3.206033316958146
+ 3.2060892133424064
+ 3.2061451083853774
+ 3.2062010020871474
+ 3.206256894447803
+ 3.206312785467431
+ 3.20636867514612
+ 3.206424563483956
+ 3.2064804504810276
+ 3.2065363361374213
+ 3.206592220453225
+ 3.2066481034285252
+ 3.206703985063409
+ 3.206759865357965
+ 3.2068157443122796
+ 3.2068716219264397
+ 3.206927498200533
+ 3.2069833731346473
+ 3.2070392467288684
+ 3.207095118983285
+ 3.2071509898979826
+ 3.2072068594730503
+ 3.2072627277085743
+ 3.2073185946046414
+ 3.20737446016134
+ 3.2074303243787554
+ 3.2074861872569764
+ 3.2075420487960895
+ 3.2075979089961817
+ 3.2076537678573405
+ 3.207709625379653
+ 3.207765481563206
+ 3.207821336408086
+ 3.207877189914381
+ 3.207933042082178
+ 3.207988892911564
+ 3.2080447424026257
+ 3.2081005905554507
+ 3.2081564373701257
+ 3.2082122828467377
+ 3.2082681269853737
+ 3.2083239697861203
+ 3.208379811249065
+ 3.2084356513742955
+ 3.2084914901618977
+ 3.2085473276119587
+ 3.2086031637245656
+ 3.2086589984998057
+ 3.208714831937765
+ 3.208770664038532
+ 3.208826494802192
+ 3.2088823242288327
+ 3.208938152318541
+ 3.208993979071404
+ 3.2090498044875075
+ 3.20910562856694
+ 3.209161451309787
+ 3.209217272716136
+ 3.209273092786074
+ 3.2093289115196875
+ 3.209384728917063
+ 3.209440544978288
+ 3.2094963597034494
+ 3.2095521730926326
+ 3.2096079851459263
+ 3.209663795863416
+ 3.2097196052451893
+ 3.2097754132913328
+ 3.2098312200019326
+ 3.2098870253770757
+ 3.2099428294168493
+ 3.20999863212134
+ 3.2100544334906336
+ 3.210110233524818
+ 3.21016603222398
+ 3.210221829588205
+ 3.210277625617581
+ 3.2103334203121934
+ 3.2103892136721304
+ 3.210445005697477
+ 3.210500796388321
+ 3.2105565857447487
+ 3.210612373766847
+ 3.210668160454702
+ 3.210723945808401
+ 3.2107797298280296
+ 3.210835512513676
+ 3.2108912938654246
+ 3.210947073883364
+ 3.211002852567579
+ 3.211058629918157
+ 3.2111144059351853
+ 3.2111701806187494
+ 3.211225953968936
+ 3.2112817259858324
+ 3.211337496669524
+ 3.2113932660200977
+ 3.2114490340376403
+ 3.211504800722238
+ 3.211560566073977
+ 3.2116163300929443
+ 3.211672092779226
+ 3.211727854132909
+ 3.2117836141540796
+ 3.2118393728428236
+ 3.211895130199228
+ 3.211950886223379
+ 3.212006640915363
+ 3.2120623942752666
+ 3.2121181463031765
+ 3.212173896999178
+ 3.212229646363358
+ 3.212285394395803
+ 3.2123411410965996
+ 3.2123968864658337
+ 3.212452630503592
+ 3.2125083732099595
+ 3.2125641145850246
+ 3.2126198546288722
+ 3.2126755933415887
+ 3.212731330723261
+ 3.2127870667739753
+ 3.212842801493817
+ 3.212898534882873
+ 3.2129542669412294
+ 3.2130099976689728
+ 3.213065727066189
+ 3.2131214551329643
+ 3.213177181869385
+ 3.2132329072755366
+ 3.2132886313515066
+ 3.2133443540973805
+ 3.213400075513244
+ 3.213455795599184
+ 3.213511514355287
+ 3.2135672317816377
+ 3.2136229478783234
+ 3.21367866264543
+ 3.2137343760830435
+ 3.21379008819125
+ 3.2138457989701354
+ 3.213901508419786
+ 3.213957216540288
+ 3.2140129233317274
+ 3.21406862879419
+ 3.2141243329277627
+ 3.2141800357325305
+ 3.2142357372085795
+ 3.2142914373559965
+ 3.2143471361748674
+ 3.2144028336652775
+ 3.214458529827313
+ 3.2145142246610603
+ 3.2145699181666054
+ 3.214625610344034
+ 3.2146813011934317
+ 3.2147369907148846
+ 3.2147926789084798
+ 3.214848365774302
+ 3.214904051312437
+ 3.2149597355229718
+ 3.2150154184059914
+ 3.215071099961582
+ 3.2151267801898293
+ 3.2151824590908196
+ 3.2152381366646385
+ 3.215293812911372
+ 3.2153494878311055
+ 3.215405161423925
+ 3.2154608336899173
+ 3.215516504629167
+ 3.21557217424176
+ 3.2156278425277827
+ 3.215683509487321
+ 3.21573917512046
+ 3.215794839427286
+ 3.2158505024078843
+ 3.2159061640623414
+ 3.215961824390743
+ 3.216017483393174
+ 3.21607314106972
+ 3.216128797420468
+ 3.216184452445503
+ 3.2162401061449106
+ 3.216295758518777
+ 3.216351409567187
+ 3.2164070592902267
+ 3.2164627076879824
+ 3.216518354760539
+ 3.216574000507982
+ 3.216629644930398
+ 3.2166852880278722
+ 3.2167409298004896
+ 3.216796570248337
+ 3.216852209371499
+ 3.2169078471700616
+ 3.2169634836441108
+ 3.217019118793731
+ 3.2170747526190087
+ 3.2171303851200292
+ 3.2171860162968784
+ 3.217241646149641
+ 3.2172972746784034
+ 3.2173529018832507
+ 3.2174085277642686
+ 3.2174641523215426
+ 3.217519775555158
+ 3.217575397465201
+ 3.217631018051756
+ 3.2176866373149093
+ 3.2177422552547457
+ 3.217797871871351
+ 3.2178534871648106
+ 3.2179091011352106
+ 3.2179647137826355
+ 3.218020325107171
+ 3.2180759351089026
+ 3.2181315437879157
+ 3.2181871511442957
+ 3.2182427571781274
+ 3.2182983618894974
+ 3.2183539652784896
+ 3.2184095673451907
+ 3.218465168089686
+ 3.218520767512059
+ 3.2185763656123973
+ 3.218631962390785
+ 3.218687557847308
+ 3.2187431519820504
+ 3.218798744795099
+ 3.2188543362865385
+ 3.2189099264564542
+ 3.218965515304931
+ 3.2190211028320546
+ 3.2190766890379106
+ 3.219132273922583
+ 3.219187857486158
+ 3.2192434397287206
+ 3.2192990206503556
+ 3.2193546002511493
+ 3.219410178531186
+ 3.219465755490551
+ 3.2195213311293296
+ 3.219576905447607
+ 3.2196324784454684
+ 3.219688050122999
+ 3.219743620480283
+ 3.219799189517407
+ 3.219854757234456
+ 3.219910323631513
+ 3.2199658887086655
+ 3.220021452465998
+ 3.2200770149035955
+ 3.2201325760215425
+ 3.2201881358199245
+ 3.220243694298827
+ 3.220299251458334
+ 3.2203548072985315
+ 3.220410361819504
+ 3.220465915021337
+ 3.2205214669041147
+ 3.220577017467923
+ 3.2206325667128466
+ 3.2206881146389703
+ 3.220743661246379
+ 3.2207992065351587
+ 3.2208547505053926
+ 3.220910293157167
+ 3.2209658344905665
+ 3.2210213745056757
+ 3.22107691320258
+ 3.221132450581364
+ 3.221187986642113
+ 3.2212435213849115
+ 3.2212990548098444
+ 3.2213545869169966
+ 3.221410117706453
+ 3.221465647178299
+ 3.2215211753326187
+ 3.2215767021694974
+ 3.2216322276890197
+ 3.2216877518912703
+ 3.2217432747763346
+ 3.221798796344296
+ 3.221854316595241
+ 3.2219098355292544
+ 3.2219653531464196
+ 3.222020869446822
+ 3.2220763844305473
+ 3.2221318980976785
+ 3.2221874104483015
+ 3.222242921482501
+ 3.222298431200361
+ 3.2223539396019674
+ 3.222409446687404
+ 3.2224649524567557
+ 3.222520456910107
+ 3.222575960047543
+ 3.222631461869149
+ 3.222686962375008
+ 3.222742461565206
+ 3.222797959439827
+ 3.2228534559989557
+ 3.222908951242677
+ 3.2229644451710753
+ 3.2230199377842355
+ 3.223075429082242
+ 3.223130919065179
+ 3.2231864077331323
+ 3.223241895086185
+ 3.2232973811244228
+ 3.2233528658479296
+ 3.22340834925679
+ 3.223463831351089
+ 3.223519312130911
+ 3.2235747915963398
+ 3.2236302697474613
+ 3.2236857465843585
+ 3.2237412221071167
+ 3.22379669631582
+ 3.2238521692105535
+ 3.223907640791402
+ 3.2239631110584486
+ 3.2240185800117787
+ 3.224074047651476
+ 3.2241295139776263
+ 3.224184978990312
+ 3.22424044268962
+ 3.224295905075633
+ 3.224351366148435
+ 3.2244068259081122
+ 3.2244622843547477
+ 3.224517741488426
+ 3.2245731973092315
+ 3.2246286518172496
+ 3.224684105012563
+ 3.2247395568952566
+ 3.224795007465415
+ 3.2248504567231224
+ 3.2249059046684634
+ 3.224961351301522
+ 3.2250167966223824
+ 3.225072240631129
+ 3.225127683327847
+ 3.2251831247126184
+ 3.2252385647855295
+ 3.2252940035466637
+ 3.2253494409961054
+ 3.2254048771339394
+ 3.225460311960249
+ 3.225515745475119
+ 3.225571177678633
+ 3.2256266085708765
+ 3.2256820381519318
+ 3.2257374664218843
+ 3.2257928933808184
+ 3.2258483190288176
+ 3.225903743365966
+ 3.2259591663923484
+ 3.226014588108048
+ 3.22607000851315
+ 3.2261254276077382
+ 3.2261808453918963
+ 3.2262362618657088
+ 3.2262916770292596
+ 3.2263470908826326
+ 3.2264025034259123
+ 3.226457914659182
+ 3.226513324582527
+ 3.22656873319603
+ 3.226624140499776
+ 3.2266795464938487
+ 3.226734951178332
+ 3.2267903545533105
+ 3.2268457566188675
+ 3.226901157375087
+ 3.2269565568220533
+ 3.227011954959851
+ 3.2270673517885626
+ 3.2271227473082735
+ 3.2271781415190666
+ 3.227233534421026
+ 3.2272889260142366
+ 3.2273443162987814
+ 3.2273997052747445
+ 3.22745509294221
+ 3.227510479301261
+ 3.2275658643519822
+ 3.2276212480944575
+ 3.2276766305287707
+ 3.2277320116550055
+ 3.2277873914732456
+ 3.2278427699835754
+ 3.227898147186078
+ 3.227953523080838
+ 3.2280088976679386
+ 3.228064270947464
+ 3.228119642919498
+ 3.228175013584124
+ 3.228230382941426
+ 3.228285750991488
+ 3.2283411177343937
+ 3.2283964831702265
+ 3.2284518472990706
+ 3.228507210121009
+ 3.2285625716361266
+ 3.2286179318445063
+ 3.228673290746232
+ 3.228728648341387
+ 3.228784004630056
+ 3.2288393596123215
+ 3.2288947132882684
+ 3.2289500656579797
+ 3.229005416721539
+ 3.22906076647903
+ 3.229116114930536
+ 3.229171462076142
+ 3.22922680791593
+ 3.229282152449984
+ 3.2293374956783887
+ 3.229392837601227
+ 3.229448178218582
+ 3.2295035175305378
+ 3.229558855537178
+ 3.2296141922385857
+ 3.229669527634845
+ 3.229724861726039
+ 3.229780194512252
+ 3.2298355259935665
+ 3.229890856170067
+ 3.229946185041836
+ 3.230001512608958
+ 3.230056838871516
+ 3.2301121638295935
+ 3.230167487483274
+ 3.2302228098326413
+ 3.2302781308777777
+ 3.2303334506187684
+ 3.230388769055696
+ 3.2304440861886436
+ 3.2304994020176947
+ 3.230554716542933
+ 3.230610029764442
+ 3.2306653416823052
+ 3.2307206522966054
+ 3.2307759616074265
+ 3.2308312696148516
+ 3.230886576318964
+ 3.2309418817198474
+ 3.230997185817585
+ 3.2310524886122605
+ 3.2311077901039567
+ 3.231163090292757
+ 3.2312183891787445
+ 3.2312736867620027
+ 3.2313289830426157
+ 3.231384278020666
+ 3.2314395716962365
+ 3.231494864069411
+ 3.2315501551402726
+ 3.2316054449089053
+ 3.231660733375391
+ 3.231716020539814
+ 3.231771306402257
+ 3.231826590962803
+ 3.231881874221536
+ 3.2319371561785393
+ 3.231992436833895
+ 3.2320477161876866
+ 3.232102994239998
+ 3.232158270990912
+ 3.2322135464405113
+ 3.2322688205888794
+ 3.2323240934361
+ 3.2323793649822554
+ 3.232434635227429
+ 3.2324899041717035
+ 3.2325451718151634
+ 3.23260043815789
+ 3.2326557031999674
+ 3.2327109669414784
+ 3.232766229382507
+ 3.2328214905231345
+ 3.2328767503634457
+ 3.232932008903522
+ 3.2329872661434473
+ 3.2330425220833052
+ 3.2330977767231777
+ 3.233153030063148
+ 3.2332082821032997
+ 3.233263532843716
+ 3.233318782284478
+ 3.2333740304256717
+ 3.233429277267377
+ 3.233484522809679
+ 3.2335397670526596
+ 3.2335950099964013
+ 3.2336502516409884
+ 3.233705491986503
+ 3.2337607310330285
+ 3.2338159687806476
+ 3.2338712052294425
+ 3.2339264403794976
+ 3.2339816742308938
+ 3.2340369067837154
+ 3.2340921380380454
+ 3.2341473679939656
+ 3.234202596651559
+ 3.2342578240109097
+ 3.234313050072099
+ 3.234368274835211
+ 3.2344234983003273
+ 3.234478720467532
+ 3.2345339413369065
+ 3.234589160908535
+ 3.2346443791824995
+ 3.2346995961588823
+ 3.2347548118377674
+ 3.234810026219236
+ 3.234865239303372
+ 3.234920451090258
+ 3.2349756615799765
+ 3.23503087077261
+ 3.235086078668242
+ 3.235141285266954
+ 3.23519649056883
+ 3.2352516945739516
+ 3.235306897282402
+ 3.235362098694264
+ 3.2354172988096206
+ 3.235472497628553
+ 3.2355276951511454
+ 3.235582891377479
+ 3.2356380863076377
+ 3.235693279941704
+ 3.2357484722797594
+ 3.2358036633218874
+ 3.2358588530681707
+ 3.235914041518691
+ 3.235969228673532
+ 3.2360244145327752
+ 3.236079599096504
+ 3.236134782364801
+ 3.236189964337748
+ 3.236245145015428
+ 3.236300324397923
+ 3.236355502485316
+ 3.2364106792776894
+ 3.236465854775126
+ 3.2365210289777084
+ 3.236576201885518
+ 3.2366313734986383
+ 3.236686543817151
+ 3.2367417128411393
+ 3.2367968805706853
+ 3.236852047005871
+ 3.2369072121467797
+ 3.236962375993494
+ 3.237017538546094
+ 3.2370726998046653
+ 3.237127859769288
+ 3.237183018440046
+ 3.23723817581702
+ 3.2372933319002937
+ 3.237348486689949
+ 3.2374036401860686
+ 3.237458792388734
+ 3.237513943298029
+ 3.237569092914034
+ 3.237624241236833
+ 3.2376793882665074
+ 3.237734534003139
+ 3.237789678446812
+ 3.2378448215976072
+ 3.237899963455607
+ 3.237955104020893
+ 3.2380102432935494
+ 3.238065381273657
+ 3.2381205179612986
+ 3.2381756533565556
+ 3.238230787459511
+ 3.238285920270247
+ 3.238341051788846
+ 3.2383961820153893
+ 3.23845131094996
+ 3.238506438592639
+ 3.23856156494351
+ 3.2386166900026545
+ 3.2386718137701545
+ 3.238726936246093
+ 3.2387820574305506
+ 3.2388371773236106
+ 3.238892295925355
+ 3.2389474132358655
+ 3.2390025292552242
+ 3.2390576439835135
+ 3.239112757420816
+ 3.239167869567212
+ 3.239222980422786
+ 3.239278089987618
+ 3.2393331982617912
+ 3.2393883052453867
+ 3.2394434109384873
+ 3.239498515341175
+ 3.239553618453532
+ 3.2396087202756396
+ 3.23966382080758
+ 3.2397189200494356
+ 3.239774018001288
+ 3.239829114663219
+ 3.239884210035312
+ 3.2399393041176467
+ 3.239994396910306
+ 3.240049488413373
+ 3.240104578626928
+ 3.240159667551054
+ 3.240214755185832
+ 3.2402698415313442
+ 3.2403249265876735
+ 3.2403800103549
+ 3.2404350928331076
+ 3.240490174022377
+ 3.2405452539227895
+ 3.2406003325344277
+ 3.2406554098573737
+ 3.240710485891709
+ 3.240765560637515
+ 3.240820634094875
+ 3.240875706263869
+ 3.2409307771445794
+ 3.240985846737089
+ 3.2410409150414785
+ 3.24109598205783
+ 3.241151047786224
+ 3.241206112226745
+ 3.2412611753794724
+ 3.2413162372444897
+ 3.241371297821877
+ 3.2414263571117163
+ 3.241481415114091
+ 3.2415364718290807
+ 3.241591527256768
+ 3.2416465813972346
+ 3.2417016342505622
+ 3.2417566858168327
+ 3.241811736096128
+ 3.2418667850885283
+ 3.2419218327941164
+ 3.2419768792129737
+ 3.242031924345182
+ 3.242086968190823
+ 3.2421420107499777
+ 3.242197052022729
+ 3.242252092009157
+ 3.242307130709344
+ 3.2423621681233716
+ 3.2424172042513213
+ 3.2424722390932743
+ 3.242527272649313
+ 3.242582304919518
+ 3.242637335903972
+ 3.242692365602755
+ 3.2427473940159497
+ 3.242802421143638
+ 3.2428574469859
+ 3.242912471542818
+ 3.242967494814473
+ 3.243022516800948
+ 3.243077537502322
+ 3.243132556918679
+ 3.2431875750500985
+ 3.2432425918966628
+ 3.2432976074584534
+ 3.2433526217355513
+ 3.243407634728039
+ 3.243462646435997
+ 3.243517656859506
+ 3.2435726659986486
+ 3.2436276738535055
+ 3.243682680424159
+ 3.2437376857106894
+ 3.243792689713179
+ 3.2438476924317086
+ 3.2439026938663593
+ 3.2439576940172135
+ 3.2440126928843513
+ 3.2440676904678547
+ 3.244122686767805
+ 3.244177681784283
+ 3.2442326755173703
+ 3.2442876679671486
+ 3.2443426591336983
+ 3.244397649017102
+ 3.2444526376174396
+ 3.244507624934793
+ 3.244562610969243
+ 3.2446175957208716
+ 3.24467257918976
+ 3.2447275613759885
+ 3.2447825422796392
+ 3.2448375219007928
+ 3.244892500239531
+ 3.244947477295934
+ 3.245002453070084
+ 3.245057427562062
+ 3.245112400771949
+ 3.245167372699826
+ 3.245222343345774
+ 3.2452773127098746
+ 3.2453322807922094
+ 3.245387247592858
+ 3.2454422131119025
+ 3.2454971773494243
+ 3.2455521403055037
+ 3.245607101980222
+ 3.245662062373661
+ 3.245717021485901
+ 3.245771979317023
+ 3.2458269358671084
+ 3.245881891136239
+ 3.2459368451244943
+ 3.245991797831956
+ 3.246046749258705
+ 3.246101699404823
+ 3.2461566482703903
+ 3.2462115958554882
+ 3.2462665421601975
+ 3.2463214871845993
+ 3.2463764309287746
+ 3.246431373392804
+ 3.2464863145767686
+ 3.24654125448075
+ 3.2465961931048284
+ 3.2466511304490844
+ 3.2467060665136
+ 3.2467610012984554
+ 3.2468159348037324
+ 3.2468708670295103
+ 3.246925797975871
+ 3.246980727642896
+ 3.247035656030665
+ 3.247090583139259
+ 3.247145508968759
+ 3.247200433519246
+ 3.2472553567908014
+ 3.2473102787835053
+ 3.2473651994974384
+ 3.247420118932682
+ 3.247475037089316
+ 3.2475299539674225
+ 3.2475848695670817
+ 3.2476397838883746
+ 3.247694696931381
+ 3.247749608696183
+ 3.2478045191828606
+ 3.2478594283914943
+ 3.2479143363221654
+ 3.2479692429749547
+ 3.248024148349943
+ 3.24807905244721
+ 3.248133955266837
+ 3.248188856808905
+ 3.2482437570734946
+ 3.248298656060686
+ 3.248353553770561
+ 3.2484084502031987
+ 3.248463345358681
+ 3.2485182392370873
+ 3.2485731318384996
+ 3.248628023162998
+ 3.2486829132106627
+ 3.248737801981575
+ 3.2487926894758155
+ 3.248847575693464
+ 3.2489024606346013
+ 3.248957344299309
+ 3.2490122266876664
+ 3.249067107799755
+ 3.2491219876356543
+ 3.249176866195446
+ 3.24923174347921
+ 3.2492866194870267
+ 3.249341494218977
+ 3.2493963676751414
+ 3.2494512398556
+ 3.249506110760434
+ 3.2495609803897234
+ 3.2496158487435487
+ 3.24967071582199
+ 3.249725581625129
+ 3.2497804461530446
+ 3.2498353094058183
+ 3.24989017138353
+ 3.249945032086261
+ 3.2499998915140904
+ 3.2500547496670995
+ 3.2501096065453683
+ 3.250164462148978
+ 3.2502193164780078
+ 3.2502741695325392
+ 3.250329021312651
+ 3.2503838718184257
+ 3.2504387210499424
+ 3.2504935690072814
+ 3.250548415690523
+ 3.2506032610997475
+ 3.2506581052350363
+ 3.2507129480964685
+ 3.250767789684125
+ 3.250822629998086
+ 3.2508774690384312
+ 3.250932306805242
+ 3.2509871432985977
+ 3.251041978518579
+ 3.251096812465266
+ 3.251151645138739
+ 3.2512064765390782
+ 3.2512613066663643
+ 3.2513161355206766
+ 3.251370963102096
+ 3.251425789410703
+ 3.251480614446577
+ 3.2515354382097983
+ 3.251590260700448
+ 3.251645081918605
+ 3.25169990186435
+ 3.2517547205377633
+ 3.251809537938925
+ 3.2518643540679157
+ 3.2519191689248146
+ 3.251973982509702
+ 3.2520287948226585
+ 3.2520836058637643
+ 3.2521384156330995
+ 3.252193224130743
+ 3.252248031356776
+ 3.2523028373112783
+ 3.2523576419943305
+ 3.2524124454060117
+ 3.2524672475464027
+ 3.252522048415583
+ 3.252576848013633
+ 3.2526316463406326
+ 3.252686443396662
+ 3.252741239181801
+ 3.2527960336961295
+ 3.2528508269397274
+ 3.2529056189126755
+ 3.252960409615053
+ 3.25301519904694
+ 3.253069987208417
+ 3.2531247740995624
+ 3.253179559720458
+ 3.2532343440711826
+ 3.253289127151817
+ 3.2533439089624396
+ 3.253398689503132
+ 3.253453468773974
+ 3.253508246775044
+ 3.2535630235064237
+ 3.253617798968191
+ 3.2536725731604275
+ 3.2537273460832123
+ 3.2537821177366255
+ 3.253836888120747
+ 3.2538916572356555
+ 3.2539464250814327
+ 3.254001191658157
+ 3.254055956965909
+ 3.2541107210047686
+ 3.254165483774815
+ 3.2542202452761275
+ 3.254275005508787
+ 3.2543297644728733
+ 3.254384522168465
+ 3.254439278595643
+ 3.2544940337544865
+ 3.2545487876450756
+ 3.2546035402674893
+ 3.254658291621808
+ 3.254713041708112
+ 3.254767790526479
+ 3.2548225380769904
+ 3.2548772843597256
+ 3.2549320293747637
+ 3.2549867731221855
+ 3.2550415156020693
+ 3.2550962568144954
+ 3.2551509967595442
+ 3.255205735437294
+ 3.255260472847825
+ 3.255315208991217
+ 3.255369943867549
+ 3.255424677476902
+ 3.255479409819354
+ 3.2555341408949854
+ 3.2555888707038756
+ 3.2556435992461044
+ 3.255698326521751
+ 3.255753052530895
+ 3.255807777273616
+ 3.2558625007499944
+ 3.2559172229601083
+ 3.255971943904038
+ 3.256026663581863
+ 3.256081381993663
+ 3.2561360991395167
+ 3.256190815019505
+ 3.256245529633706
+ 3.2563002429821992
+ 3.2563549550650652
+ 3.2564096658823827
+ 3.256464375434231
+ 3.2565190837206903
+ 3.256573790741839
+ 3.2566284964977577
+ 3.2566832009885247
+ 3.25673790421422
+ 3.2567926061749235
+ 3.2568473068707133
+ 3.25690200630167
+ 3.256956704467872
+ 3.2570114013694
+ 3.257066097006332
+ 3.257120791378748
+ 3.257175484486727
+ 3.257230176330349
+ 3.2572848669096923
+ 3.2573395562248373
+ 3.2573942442758628
+ 3.257448931062848
+ 3.257503616585872
+ 3.257558300845015
+ 3.2576129838403554
+ 3.257667665571973
+ 3.2577223460399467
+ 3.2577770252443563
+ 3.25783170318528
+ 3.257886379862798
+ 3.25794105527699
+ 3.2579957294279334
+ 3.2580504023157086
+ 3.258105073940395
+ 3.258159744302072
+ 3.2582144134008177
+ 3.258269081236712
+ 3.2583237478098344
+ 3.258378413120263
+ 3.258433077168078
+ 3.2584877399533574
+ 3.258542401476182
+ 3.2585970617366296
+ 3.25865172073478
+ 3.2587063784707113
+ 3.2587610349445044
+ 3.258815690156237
+ 3.2588703441059885
+ 3.258924996793838
+ 3.258979648219865
+ 3.259034298384148
+ 3.259088947286766
+ 3.2591435949277985
+ 3.2591982413073253
+ 3.2592528864254233
+ 3.2593075302821735
+ 3.259362172877654
+ 3.259416814211944
+ 3.2594714542851224
+ 3.2595260930972683
+ 3.259580730648461
+ 3.2596353669387788
+ 3.259690001968301
+ 3.2597446357371074
+ 3.2597992682452754
+ 3.2598538994928847
+ 3.2599085294800147
+ 3.259963158206744
+ 3.2600177856731514
+ 3.2600724118793156
+ 3.260127036825316
+ 3.2601816605112313
+ 3.2602362829371403
+ 3.260290904103122
+ 3.260345524009255
+ 3.2604001426556186
+ 3.2604547600422915
+ 3.260509376169353
+ 3.2605639910368804
+ 3.2606186046449546
+ 3.2606732169936525
+ 3.2607278280830547
+ 3.2607824379132384
+ 3.260837046484284
+ 3.260891653796269
+ 3.260946259849273
+ 3.261000864643374
+ 3.2610554681786517
+ 3.261110070455184
+ 3.26116467147305
+ 3.2612192712323287
+ 3.261273869733099
+ 3.261328466975439
+ 3.2613830629594274
+ 3.2614376576851436
+ 3.261492251152666
+ 3.2615468433620727
+ 3.261601434313443
+ 3.261656024006856
+ 3.2617106124423896
+ 3.2617651996201227
+ 3.2618197855401343
+ 3.2618743702025026
+ 3.261928953607306
+ 3.261983535754624
+ 3.262038116644535
+ 3.262092696277117
+ 3.262147274652449
+ 3.2622018517706097
+ 3.262256427631678
+ 3.2623110022357316
+ 3.2623655755828493
+ 3.2624201476731107
+ 3.262474718506593
+ 3.262529288083376
+ 3.2625838564035377
+ 3.262638423467156
+ 3.2626929892743104
+ 3.2627475538250783
+ 3.2628021171195396
+ 3.2628566791577724
+ 3.262911239939854
+ 3.2629657994658645
+ 3.263020357735882
+ 3.2630749147499847
+ 3.2631294705082503
+ 3.2631840250107587
+ 3.2632385782575875
+ 3.2632931302488157
+ 3.2633476809845208
+ 3.2634022304647825
+ 3.2634567786896778
+ 3.2635113256592865
+ 3.263565871373686
+ 3.2636204158329547
+ 3.2636749590371714
+ 3.2637295009864147
+ 3.2637840416807626
+ 3.263838581120294
+ 3.2638931193050866
+ 3.2639476562352185
+ 3.2640021919107687
+ 3.264056726331815
+ 3.264111259498437
+ 3.2641657914107114
+ 3.2642203220687174
+ 3.2642748514725333
+ 3.264329379622237
+ 3.2643839065179066
+ 3.264438432159621
+ 3.2644929565474583
+ 3.2645474796814966
+ 3.2646020015618142
+ 3.2646565221884893
+ 3.2647110415616005
+ 3.2647655596812255
+ 3.2648200765474424
+ 3.2648745921603304
+ 3.2649291065199666
+ 3.2649836196264297
+ 3.2650381314797983
+ 3.26509264208015
+ 3.265147151427563
+ 3.265201659522116
+ 3.2652561663638857
+ 3.2653106719529523
+ 3.265365176289393
+ 3.2654196793732853
+ 3.265474181204708
+ 3.2655286817837395
+ 3.265583181110457
+ 3.2656376791849393
+ 3.2656921760072644
+ 3.2657466715775105
+ 3.2658011658957546
+ 3.265855658962077
+ 3.2659101507765533
+ 3.2659646413392633
+ 3.2660191306502844
+ 3.2660736187096946
+ 3.2661281055175717
+ 3.266182591073994
+ 3.2662370753790397
+ 3.266291558432787
+ 3.266346040235313
+ 3.2664005207866964
+ 3.2664550000870154
+ 3.266509478136347
+ 3.26656395493477
+ 3.2666184304823624
+ 3.266672904779201
+ 3.2667273778253656
+ 3.266781849620932
+ 3.2668363201659805
+ 3.2668907894605876
+ 3.2669452575048306
+ 3.2669997242987887
+ 3.2670541898425394
+ 3.2671086541361603
+ 3.267163117179729
+ 3.267217578973325
+ 3.2672720395170245
+ 3.2673264988109056
+ 3.2673809568550465
+ 3.2674354136495247
+ 3.267489869194419
+ 3.267544323489806
+ 3.2675987765357637
+ 3.267653228332371
+ 3.267707678879704
+ 3.2677621281778424
+ 3.2678165762268625
+ 3.2678710230268426
+ 3.267925468577861
+ 3.2679799128799947
+ 3.268034355933321
+ 3.268088797737919
+ 3.2681432382938653
+ 3.2681976776012385
+ 3.2682521156601156
+ 3.2683065524705746
+ 3.268360988032694
+ 3.2684154223465502
+ 3.268469855412221
+ 3.2685242872297846
+ 3.268578717799319
+ 3.268633147120901
+ 3.268687575194609
+ 3.2687420020205207
+ 3.2687964275987125
+ 3.2688508519292636
+ 3.268905275012251
+ 3.268959696847752
+ 3.269014117435845
+ 3.269068536776606
+ 3.2691229548701144
+ 3.269177371716447
+ 3.269231787315682
+ 3.269286201667896
+ 3.2693406147731667
+ 3.2693950266315723
+ 3.2694494372431895
+ 3.269503846608097
+ 3.2695582547263715
+ 3.2696126615980905
+ 3.2696670672233314
+ 3.269721471602173
+ 3.2697758747346914
+ 3.2698302766209637
+ 3.2698846772610692
+ 3.269939076655084
+ 3.269993474803086
+ 3.2700478717051524
+ 3.270102267361361
+ 3.27015666177179
+ 3.2702110549365146
+ 3.270265446855614
+ 3.2703198375291658
+ 3.270374226957246
+ 3.270428615139934
+ 3.270483002077305
+ 3.2705373877694375
+ 3.270591772216409
+ 3.2706461554182966
+ 3.270700537375178
+ 3.27075491808713
+ 3.2708092975542304
+ 3.2708636757765563
+ 3.270918052754185
+ 3.2709724284871946
+ 3.271026802975661
+ 3.271081176219663
+ 3.2711355482192768
+ 3.27118991897458
+ 3.2712442884856503
+ 3.271298656752565
+ 3.2713530237754003
+ 3.271407389554235
+ 3.271461754089145
+ 3.271516117380208
+ 3.2715704794275022
+ 3.271624840231103
+ 3.2716791997910892
+ 3.2717335581075373
+ 3.2717879151805245
+ 3.2718422710101285
+ 3.271896625596426
+ 3.2719509789394943
+ 3.2720053310394106
+ 3.2720596818962524
+ 3.2721140315100965
+ 3.2721683798810197
+ 3.2722227270091
+ 3.272277072894414
+ 3.2723314175370386
+ 3.2723857609370515
+ 3.27244010309453
+ 3.2724944440095505
+ 3.2725487836821903
+ 3.2726031221125265
+ 3.2726574593006363
+ 3.272711795246597
+ 3.2727661299504853
+ 3.2728204634123785
+ 3.2728747956323536
+ 3.2729291266104874
+ 3.2729834563468576
+ 3.2730377848415397
+ 3.273092112094613
+ 3.2731464381061524
+ 3.273200762876236
+ 3.273255086404941
+ 3.2733094086923438
+ 3.2733637297385214
+ 3.2734180495435514
+ 3.27347236810751
+ 3.2735266854304745
+ 3.2735810015125217
+ 3.273635316353729
+ 3.273689629954173
+ 3.2737439423139305
+ 3.273798253433079
+ 3.2738525633116944
+ 3.2739068719498547
+ 3.273961179347636
+ 3.2740154855051156
+ 3.2740697904223706
+ 3.274124094099477
+ 3.274178396536513
+ 3.2742326977335536
+ 3.2742869976906777
+ 3.274341296407961
+ 3.2743955938854805
+ 3.2744498901233126
+ 3.274504185121535
+ 3.274558478880224
+ 3.274612771399456
+ 3.2746670626793093
+ 3.274721352719859
+ 3.274775641521183
+ 3.2748299290833573
+ 3.274884215406459
+ 3.274938500490565
+ 3.274992784335752
+ 3.2750470669420966
+ 3.275101348309675
+ 3.275155628438565
+ 3.275209907328843
+ 3.275264184980586
+ 3.2753184613938693
+ 3.275372736568771
+ 3.2754270105053678
+ 3.275481283203735
+ 3.275535554663951
+ 3.2755898248860915
+ 3.2756440938702327
+ 3.275698361616453
+ 3.275752628124827
+ 3.2758068933954325
+ 3.2758611574283463
+ 3.275915420223644
+ 3.2759696817814032
+ 3.2760239421017
+ 3.2760782011846112
+ 3.2761324590302134
+ 3.276186715638583
+ 3.2762409710097966
+ 3.276295225143931
+ 3.2763494780410625
+ 3.2764037297012676
+ 3.276457980124623
+ 3.276512229311206
+ 3.2765664772610914
+ 3.276620723974357
+ 3.276674969451079
+ 3.2767292136913335
+ 3.2767834566951977
+ 3.276837698462748
+ 3.2768919389940603
+ 3.2769461782892115
+ 3.277000416348278
+ 3.2770546531713363
+ 3.2771088887584625
+ 3.277163123109734
+ 3.277217356225226
+ 3.2772715881050156
+ 3.2773258187491794
+ 3.2773800481577933
+ 3.2774342763309336
+ 3.277488503268678
+ 3.277542728971101
+ 3.2775969534382803
+ 3.277651176670292
+ 3.2777053986672122
+ 3.277759619429117
+ 3.2778138389560834
+ 3.2778680572481873
+ 3.2779222743055056
+ 3.2779764901281143
+ 3.2780307047160897
+ 3.2780849180695077
+ 3.278139130188445
+ 3.2781933410729778
+ 3.278247550723183
+ 3.2783017591391355
+ 3.2783559663209134
+ 3.278410172268591
+ 3.2784643769822464
+ 3.278518580461955
+ 3.2785727827077924
+ 3.278626983719836
+ 3.278681183498161
+ 3.278735382042844
+ 3.278789579353962
+ 3.2788437754315902
+ 3.278897970275805
+ 3.2789521638866828
+ 3.2790063562642997
+ 3.279060547408732
+ 3.2791147373200555
+ 3.2791689259983468
+ 3.2792231134436816
+ 3.2792772996561363
+ 3.2793314846357875
+ 3.27938566838271
+ 3.2794398508969813
+ 3.279494032178677
+ 3.279548212227873
+ 3.279602391044646
+ 3.2796565686290715
+ 3.2797107449812253
+ 3.2797649201011843
+ 3.279819093989024
+ 3.2798732666448203
+ 3.27992743806865
+ 3.279981608260589
+ 3.2800357772207125
+ 3.280089944949097
+ 3.280144111445819
+ 3.2801982767109545
+ 3.2802524407445786
+ 3.280306603546768
+ 3.280360765117598
+ 3.2804149254571455
+ 3.2804690845654862
+ 3.280523242442696
+ 3.280577399088851
+ 3.2806315545040263
+ 3.280685708688299
+ 3.2807398616417442
+ 3.280794013364438
+ 3.2808481638564566
+ 3.2809023131178763
+ 3.280956461148772
+ 3.2810106079492196
+ 3.2810647535192965
+ 3.281118897859077
+ 3.2811730409686377
+ 3.2812271828480544
+ 3.281281323497402
+ 3.281335462916758
+ 3.2813896011061976
+ 3.281443738065796
+ 3.28149787379563
+ 3.2815520082957748
+ 3.281606141566306
+ 3.2816602736073
+ 3.2817144044188327
+ 3.281768534000979
+ 3.2818226623538154
+ 3.2818767894774172
+ 3.281930915371861
+ 3.2819850400372217
+ 3.2820391634735753
+ 3.2820932856809977
+ 3.2821474066595644
+ 3.282201526409352
+ 3.282255644930435
+ 3.28230976222289
+ 3.2823638782867914
+ 3.2824179931222166
+ 3.282472106729241
+ 3.282526219107939
+ 3.282580330258387
+ 3.282634440180661
+ 3.2826885488748365
+ 3.282742656340989
+ 3.2827967625791947
+ 3.2828508675895285
+ 3.2829049713720657
+ 3.282959073926883
+ 3.2830131752540552
+ 3.2830672753536585
+ 3.283121374225768
+ 3.28317547187046
+ 3.283229568287809
+ 3.2832836634778917
+ 3.283337757440783
+ 3.2833918501765584
+ 3.2834459416852937
+ 3.2835000319670646
+ 3.2835541210219463
+ 3.2836082088500147
+ 3.2836622954513452
+ 3.2837163808260135
+ 3.283770464974094
+ 3.2838245478956636
+ 3.283878629590797
+ 3.28393271005957
+ 3.283986789302058
+ 3.284040867318336
+ 3.2840949441084804
+ 3.2841490196725664
+ 3.2842030940106692
+ 3.2842571671228638
+ 3.2843112390092264
+ 3.2843653096698318
+ 3.2844193791047562
+ 3.284473447314075
+ 3.2845275142978623
+ 3.284581580056195
+ 3.284635644589147
+ 3.2846897078967956
+ 3.284743769979215
+ 3.2847978308364794
+ 3.2848518904686665
+ 3.2849059488758505
+ 3.2849600060581063
+ 3.2850140620155104
+ 3.2850681167481373
+ 3.2851221702560625
+ 3.285176222539361
+ 3.285230273598109
+ 3.2852843234323807
+ 3.285338372042252
+ 3.285392419427798
+ 3.2854464655890947
+ 3.285500510526216
+ 3.2855545542392384
+ 3.2856085967282365
+ 3.2856626379932856
+ 3.2857166780344613
+ 3.285770716851838
+ 3.2858247544454917
+ 3.285878790815498
+ 3.2859328259619307
+ 3.285986859884866
+ 3.2860408925843787
+ 3.2860949240605444
+ 3.286148954313438
+ 3.2862029833431348
+ 3.28625701114971
+ 3.2863110377332383
+ 3.2863650630937955
+ 3.2864190872314563
+ 3.2864731101462956
+ 3.2865271318383895
+ 3.2865811523078117
+ 3.2866351715546385
+ 3.286689189578945
+ 3.2867432063808057
+ 3.2867972219602954
+ 3.2868512363174904
+ 3.2869052494524644
+ 3.286959261365293
+ 3.287013272056052
+ 3.2870672815248154
+ 3.287121289771658
+ 3.2871752967966565
+ 3.287229302599884
+ 3.287283307181417
+ 3.28733731054133
+ 3.2873913126796976
+ 3.2874453135965958
+ 3.287499313292098
+ 3.2875533117662803
+ 3.287607309019218
+ 3.2876613050509853
+ 3.2877152998616577
+ 3.287769293451309
+ 3.287823285820015
+ 3.2878772769678513
+ 3.287931266894892
+ 3.2879852556012117
+ 3.288039243086886
+ 3.28809322935199
+ 3.2881472143965977
+ 3.2882011982207846
+ 3.2882551808246254
+ 3.2883091622081952
+ 3.2883631423715687
+ 3.288417121314821
+ 3.288471099038026
+ 3.2885250755412594
+ 3.2885790508245965
+ 3.2886330248881115
+ 3.2886869977318787
+ 3.2887409693559735
+ 3.288794939760471
+ 3.288848908945446
+ 3.2889028769109725
+ 3.2889568436571253
+ 3.2890108091839805
+ 3.2890647734916114
+ 3.2891187365800936
+ 3.2891726984495016
+ 3.2892266590999104
+ 3.2892806185313943
+ 3.2893345767440283
+ 3.2893885337378865
+ 3.289442489513045
+ 3.2894964440695773
+ 3.2895503974075586
+ 3.289604349527064
+ 3.2896583004281674
+ 3.2897122501109437
+ 3.2897661985754674
+ 3.2898201458218135
+ 3.289874091850056
+ 3.2899280366602714
+ 3.289981980252532
+ 3.2900359226269145
+ 3.290089863783492
+ 3.2901438037223394
+ 3.2901977424435316
+ 3.2902516799471435
+ 3.2903056162332494
+ 3.2903595513019233
+ 3.290413485153241
+ 3.290467417787276
+ 3.2905213492041034
+ 3.290575279403798
+ 3.2906292083864335
+ 3.2906831361520856
+ 3.2907370627008277
+ 3.290790988032735
+ 3.290844912147882
+ 3.290898835046343
+ 3.290952756728192
+ 3.2910066771935043
+ 3.2910605964423545
+ 3.2911145144748173
+ 3.2911684312909655
+ 3.2912223468908754
+ 3.291276261274621
+ 3.2913301744422756
+ 3.2913840863939154
+ 3.2914379971296137
+ 3.2914919066494455
+ 3.291545814953485
+ 3.291599722041806
+ 3.2916536279144846
+ 3.291707532571593
+ 3.2917614360132075
+ 3.2918153382394015
+ 3.2918692392502495
+ 3.2919231390458266
+ 3.291977037626206
+ 3.2920309349914625
+ 3.2920848311416706
+ 3.292138726076905
+ 3.2921926197972393
+ 3.2922465123027482
+ 3.292300403593506
+ 3.2923542936695873
+ 3.2924081825310663
+ 3.2924620701780163
+ 3.2925159566105133
+ 3.29256984182863
+ 3.2926237258324416
+ 3.292677608622023
+ 3.2927314901974465
+ 3.292785370558788
+ 3.292839249706121
+ 3.29289312763952
+ 3.2929470043590596
+ 3.293000879864813
+ 3.293054754156856
+ 3.293108627235261
+ 3.2931624991001036
+ 3.293216369751457
+ 3.2932702391893964
+ 3.293324107413995
+ 3.2933779744253275
+ 3.2934318402234686
+ 3.293485704808491
+ 3.2935395681804702
+ 3.29359343033948
+ 3.293647291285594
+ 3.293701151018887
+ 3.293755009539433
+ 3.2938088668473053
+ 3.293862722942579
+ 3.293916577825328
+ 3.293970431495626
+ 3.2940242839535476
+ 3.294078135199167
+ 3.2941319852325575
+ 3.2941858340537937
+ 3.2942396816629493
+ 3.294293528060099
+ 3.2943473732453157
+ 3.2944012172186747
+ 3.29445505998025
+ 3.2945089015301146
+ 3.2945627418683423
+ 3.294616580995009
+ 3.2946704189101865
+ 3.294724255613951
+ 3.294778091106374
+ 3.294831925387532
+ 3.2948857584574966
+ 3.2949395903163436
+ 3.294993420964146
+ 3.2950472504009785
+ 3.2951010786269137
+ 3.295154905642027
+ 3.2952087314463916
+ 3.2952625560400817
+ 3.295316379423171
+ 3.2953702015957327
+ 3.2954240225578424
+ 3.2954778423095723
+ 3.2955316608509975
+ 3.295585478182191
+ 3.2956392943032276
+ 3.29569310921418
+ 3.295746922915123
+ 3.29580073540613
+ 3.295854546687275
+ 3.2959083567586314
+ 3.2959621656202738
+ 3.2960159732722754
+ 3.2960697797147103
+ 3.296123584947652
+ 3.296177388971175
+ 3.296231191785352
+ 3.296284993390257
+ 3.296338793785965
+ 3.296392592972549
+ 3.296446390950082
+ 3.2965001877186384
+ 3.2965539832782924
+ 3.296607777629117
+ 3.296661570771186
+ 3.2967153627045733
+ 3.296769153429353
+ 3.2968229429455986
+ 3.2968767312533833
+ 3.296930518352781
+ 3.296984304243866
+ 3.2970380889267106
+ 3.2970918724013902
+ 3.2971456546679767
+ 3.2971994357265455
+ 3.2972532155771694
+ 3.2973069942199214
+ 3.2973607716548763
+ 3.297414547882107
+ 3.297468322901687
+ 3.2975220967136907
+ 3.297575869318191
+ 3.2976296407152614
+ 3.2976834109049764
+ 3.2977371798874087
+ 3.2977909476626324
+ 3.2978447142307203
+ 3.2978984795917468
+ 3.297952243745785
+ 3.298006006692909
+ 3.298059768433191
+ 3.2981135289667067
+ 3.298167288293527
+ 3.298221046413728
+ 3.298274803327381
+ 3.2983285590345615
+ 3.298382313535341
+ 3.2984360668297943
+ 3.2984898189179948
+ 3.298543569800015
+ 3.2985973194759297
+ 3.2986510679458116
+ 3.2987048152097342
+ 3.2987585612677703
+ 3.298812306119995
+ 3.2988660497664806
+ 3.298919792207301
+ 3.298973533442528
+ 3.299027273472238
+ 3.2990810122965013
+ 3.2991347499153933
+ 3.299188486328987
+ 3.299242221537355
+ 3.299295955540572
+ 3.29934968833871
+ 3.2994034199318425
+ 3.299457150320044
+ 3.2995108795033867
+ 3.2995646074819445
+ 3.2996183342557908
+ 3.2996720598249984
+ 3.299725784189641
+ 3.2997795073497915
+ 3.299833229305524
+ 3.2998869500569104
+ 3.299940669604026
+ 3.2999943879469424
+ 3.3000481050857333
+ 3.3001018210204722
+ 3.300155535751232
+ 3.300209249278087
+ 3.3002629616011085
+ 3.3003166727203714
+ 3.300370382635948
+ 3.3004240913479124
+ 3.300477798856337
+ 3.3005315051612953
+ 3.3005852102628603
+ 3.3006389141611057
+ 3.3006926168561033
+ 3.3007463183479286
+ 3.300800018636653
+ 3.3008537177223496
+ 3.3009074156050926
+ 3.3009611122849543
+ 3.3010148077620083
+ 3.301068502036328
+ 3.301122195107985
+ 3.301175886977055
+ 3.3012295776436087
+ 3.3012832671077206
+ 3.3013369553694627
+ 3.3013906424289092
+ 3.3014443282861325
+ 3.3014980129412055
+ 3.301551696394202
+ 3.3016053786451947
+ 3.3016590596942565
+ 3.30171273954146
+ 3.3017664181868795
+ 3.3018200956305868
+ 3.301873771872656
+ 3.3019274469131594
+ 3.30198112075217
+ 3.3020347933897605
+ 3.302088464826005
+ 3.3021421350609756
+ 3.3021958040947452
+ 3.3022494719273876
+ 3.302303138558975
+ 3.3023568039895808
+ 3.3024104682192768
+ 3.3024641312481378
+ 3.3025177930762353
+ 3.302571453703643
+ 3.3026251131304334
+ 3.3026787713566796
+ 3.3027324283824546
+ 3.302786084207831
+ 3.3028397388328816
+ 3.30289339225768
+ 3.302947044482298
+ 3.30300069550681
+ 3.303054345331287
+ 3.3031079939558032
+ 3.303161641380431
+ 3.3032152876052434
+ 3.303268932630313
+ 3.303322576455712
+ 3.303376219081515
+ 3.303429860507793
+ 3.3034835007346204
+ 3.303537139762068
+ 3.3035907775902102
+ 3.3036444142191197
+ 3.3036980496488684
+ 3.3037516838795296
+ 3.303805316911176
+ 3.3038589487438808
+ 3.3039125793777164
+ 3.303966208812755
+ 3.3040198370490694
+ 3.3040734640867333
+ 3.3041270899258186
+ 3.304180714566398
+ 3.3042343380085453
+ 3.3042879602523314
+ 3.3043415812978303
+ 3.3043952011451143
+ 3.304448819794256
+ 3.3045024372453278
+ 3.3045560534984033
+ 3.304609668553554
+ 3.304663282410853
+ 3.304716895070374
+ 3.3047705065321877
+ 3.3048241167963677
+ 3.3048777258629864
+ 3.304931333732118
+ 3.304984940403832
+ 3.3050385458782037
+ 3.3050921501553043
+ 3.305145753235207
+ 3.305199355117984
+ 3.3052529558037076
+ 3.305306555292451
+ 3.305360153584287
+ 3.3054137506792873
+ 3.3054673465775246
+ 3.3055209412790716
+ 3.3055745347840007
+ 3.305628127092385
+ 3.3056817182042963
+ 3.3057353081198073
+ 3.305788896838991
+ 3.305842484361919
+ 3.3058960706886644
+ 3.3059496558192993
+ 3.3060032397538968
+ 3.306056822492528
+ 3.306110404035267
+ 3.3061639843821857
+ 3.3062175635333557
+ 3.3062711414888506
+ 3.306324718248742
+ 3.3063782938131028
+ 3.306431868182005
+ 3.3064854413555214
+ 3.306539013333724
+ 3.3065925841166854
+ 3.306646153704478
+ 3.306699722097174
+ 3.3067532892948464
+ 3.3068068552975665
+ 3.3068604201054077
+ 3.3069139837184416
+ 3.306967546136741
+ 3.3070211073603772
+ 3.3070746673894247
+ 3.3071282262239534
+ 3.307181783864037
+ 3.307235340309748
+ 3.307288895561158
+ 3.307342449618339
+ 3.3073960024813633
+ 3.307449554150305
+ 3.3075031046252334
+ 3.307556653906223
+ 3.3076102019933455
+ 3.307663748886673
+ 3.307717294586278
+ 3.307770839092232
+ 3.307824382404608
+ 3.3078779245234777
+ 3.3079314654489136
+ 3.307985005180988
+ 3.3080385437197726
+ 3.30809208106534
+ 3.3081456172177623
+ 3.3081991521771115
+ 3.3082526859434602
+ 3.3083062185168806
+ 3.308359749897444
+ 3.3084132800852233
+ 3.3084668090802904
+ 3.3085203368827174
+ 3.308573863492576
+ 3.3086273889099393
+ 3.308680913134879
+ 3.3087344361674664
+ 3.3087879580077755
+ 3.308841478655876
+ 3.3088949981118416
+ 3.308948516375744
+ 3.309002033447655
+ 3.309055549327647
+ 3.3091090640157916
+ 3.309162577512161
+ 3.309216089816828
+ 3.3092696009298637
+ 3.30932311085134
+ 3.30937661958133
+ 3.309430127119905
+ 3.309483633467137
+ 3.3095371386230976
+ 3.3095906425878594
+ 3.3096441453614944
+ 3.3096976469440746
+ 3.3097511473356716
+ 3.3098046465363575
+ 3.3098581445462036
+ 3.309911641365283
+ 3.3099651369936676
+ 3.3100186314314284
+ 3.3100721246786375
+ 3.310125616735368
+ 3.31017910760169
+ 3.3102325972776767
+ 3.3102860857634
+ 3.310339573058931
+ 3.310393059164342
+ 3.3104465440797046
+ 3.3105000278050913
+ 3.3105535103405734
+ 3.3106069916862233
+ 3.310660471842112
+ 3.3107139508083123
+ 3.310767428584895
+ 3.310820905171933
+ 3.3108743805694973
+ 3.31092785477766
+ 3.310981327796493
+ 3.311034799626068
+ 3.3110882702664566
+ 3.3111417397177307
+ 3.3111952079799623
+ 3.3112486750532235
+ 3.3113021409375856
+ 3.3113556056331195
+ 3.3114090691398985
+ 3.311462531457993
+ 3.3115159925874758
+ 3.311569452528418
+ 3.3116229112808915
+ 3.3116763688449677
+ 3.3117298252207195
+ 3.311783280408217
+ 3.3118367344075326
+ 3.3118901872187383
+ 3.311943638841905
+ 3.311997089277105
+ 3.31205053852441
+ 3.3121039865838915
+ 3.3121574334556207
+ 3.31221087913967
+ 3.3122643236361102
+ 3.312317766945014
+ 3.312371209066452
+ 3.3124246500004957
+ 3.3124780897472177
+ 3.31253152830669
+ 3.3125849656789823
+ 3.312638401864167
+ 3.3126918368623164
+ 3.3127452706735014
+ 3.3127987032977937
+ 3.312852134735265
+ 3.312905564985986
+ 3.3129589940500304
+ 3.313012421927467
+ 3.3130658486183693
+ 3.3131192741228075
+ 3.3131726984408543
+ 3.3132261215725807
+ 3.3132795435180578
+ 3.3133329642773575
+ 3.3133863838505513
+ 3.3134398022377107
+ 3.313493219438907
+ 3.313546635454212
+ 3.3136000502836964
+ 3.313653463927433
+ 3.3137068763854916
+ 3.313760287657945
+ 3.3138136977448633
+ 3.313867106646319
+ 3.313920514362383
+ 3.3139739208931274
+ 3.3140273262386226
+ 3.3140807303989415
+ 3.314134133374153
+ 3.3141875351643315
+ 3.314240935769546
+ 3.314294335189869
+ 3.3143477334253717
+ 3.3144011304761247
+ 3.3144545263422005
+ 3.3145079210236696
+ 3.314561314520604
+ 3.3146147068330745
+ 3.3146680979611527
+ 3.3147214879049094
+ 3.3147748766644165
+ 3.314828264239745
+ 3.3148816506309666
+ 3.3149350358381517
+ 3.314988419861373
+ 3.3150418027007
+ 3.3150951843562053
+ 3.3151485648279597
+ 3.3152019441160343
+ 3.315255322220501
+ 3.31530869914143
+ 3.3153620748788937
+ 3.315415449432962
+ 3.315468822803707
+ 3.3155221949911997
+ 3.3155755659955117
+ 3.3156289358167133
+ 3.3156823044548767
+ 3.3157356719100717
+ 3.315789038182371
+ 3.3158424032718448
+ 3.315895767178565
+ 3.315949129902602
+ 3.316002491444027
+ 3.3160558518029113
+ 3.316109210979327
+ 3.3161625689733434
+ 3.3162159257850328
+ 3.316269281414466
+ 3.316322635861714
+ 3.3163759891268483
+ 3.3164293412099397
+ 3.3164826921110597
+ 3.3165360418302785
+ 3.3165893903676675
+ 3.316642737723298
+ 3.316696083897241
+ 3.316749428889568
+ 3.3168027727003486
+ 3.3168561153296556
+ 3.3169094567775588
+ 3.3169627970441296
+ 3.317016136129439
+ 3.3170694740335582
+ 3.317122810756558
+ 3.317176146298509
+ 3.317229480659483
+ 3.3172828138395505
+ 3.3173361458387824
+ 3.31738947665725
+ 3.317442806295024
+ 3.317496134752175
+ 3.317549462028775
+ 3.3176027881248937
+ 3.3176561130406026
+ 3.317709436775973
+ 3.317762759331075
+ 3.31781608070598
+ 3.3178694009007588
+ 3.317922719915483
+ 3.3179760377502223
+ 3.318029354405048
+ 3.318082669880031
+ 3.3181359841752425
+ 3.318189297290753
+ 3.3182426092266333
+ 3.3182959199829543
+ 3.3183492295597867
+ 3.318402537957202
+ 3.3184558451752704
+ 3.318509151214063
+ 3.31856245607365
+ 3.318615759754103
+ 3.3186690622554926
+ 3.3187223635778893
+ 3.318775663721364
+ 3.3188289626859877
+ 3.3188822604718307
+ 3.3189355570789645
+ 3.318988852507459
+ 3.3190421467573854
+ 3.3190954398288146
+ 3.3191487317218167
+ 3.319202022436463
+ 3.319255311972824
+ 3.3193086003309706
+ 3.3193618875109734
+ 3.319415173512903
+ 3.31946845833683
+ 3.319521741982826
+ 3.31957502445096
+ 3.319628305741304
+ 3.3196815858539277
+ 3.319734864788903
+ 3.3197881425462996
+ 3.3198414191261887
+ 3.31989469452864
+ 3.319947968753725
+ 3.3200012418015143
+ 3.320054513672078
+ 3.3201077843654874
+ 3.320161053881812
+ 3.320214322221124
+ 3.3202675893834925
+ 3.3203208553689887
+ 3.3203741201776835
+ 3.3204273838096467
+ 3.3204806462649494
+ 3.320533907543662
+ 3.320587167645855
+ 3.3206404265715994
+ 3.3206936843209647
+ 3.3207469408940224
+ 3.3208001962908424
+ 3.3208534505114957
+ 3.3209067035560524
+ 3.3209599554245837
+ 3.321013206117159
+ 3.32106645563385
+ 3.3211197039747256
+ 3.321172951139858
+ 3.3212261971293167
+ 3.321279441943172
+ 3.321332685581495
+ 3.3213859280443554
+ 3.321439169331825
+ 3.321492409443972
+ 3.321545648380869
+ 3.321598886142585
+ 3.3216521227291915
+ 3.3217053581407576
+ 3.3217585923773547
+ 3.321811825439053
+ 3.321865057325923
+ 3.321918288038034
+ 3.3219715175754585
+ 3.322024745938265
+ 3.322077973126524
+ 3.322131199140306
+ 3.322184423979683
+ 3.3222376476447226
+ 3.322290870135497
+ 3.3223440914520763
+ 3.3223973115945302
+ 3.322450530562929
+ 3.322503748357344
+ 3.3225569649778444
+ 3.3226101804245007
+ 3.3226633946973836
+ 3.322716607796563
+ 3.3227698197221094
+ 3.3228230304740927
+ 3.322876240052584
+ 3.322929448457652
+ 3.3229826556893682
+ 3.323035861747803
+ 3.3230890666330257
+ 3.323142270345107
+ 3.323195472884117
+ 3.3232486742501264
+ 3.3233018744432044
+ 3.323355073463422
+ 3.3234082713108486
+ 3.3234614679855556
+ 3.323514663487612
+ 3.3235678578170886
+ 3.3236210509740554
+ 3.323674242958582
+ 3.3237274337707396
+ 3.323780623410598
+ 3.3238338118782265
+ 3.323886999173696
+ 3.3239401852970767
+ 3.3239933702484383
+ 3.3240465540278508
+ 3.3240997366353846
+ 3.3241529180711105
+ 3.3242060983350967
+ 3.324259277427415
+ 3.3243124553481342
+ 3.3243656320973263
+ 3.324418807675059
+ 3.3244719820814033
+ 3.3245251553164294
+ 3.324578327380208
+ 3.3246314982728076
+ 3.3246846679942994
+ 3.324737836544753
+ 3.324791003924238
+ 3.3248441701328253
+ 3.324897335170584
+ 3.3249504990375844
+ 3.325003661733897
+ 3.325056823259591
+ 3.325109983614737
+ 3.3251631427994046
+ 3.325216300813664
+ 3.3252694576575843
+ 3.3253226133312364
+ 3.32537576783469
+ 3.3254289211680144
+ 3.3254820733312807
+ 3.3255352243245575
+ 3.325588374147916
+ 3.325641522801425
+ 3.325694670285155
+ 3.325747816599175
+ 3.325800961743557
+ 3.325854105718368
+ 3.3259072485236802
+ 3.325960390159562
+ 3.326013530626084
+ 3.326066669923316
+ 3.3261198080513275
+ 3.326172945010189
+ 3.3262260807999686
+ 3.3262792154207386
+ 3.3263323488725667
+ 3.326385481155524
+ 3.3264386122696794
+ 3.326491742215104
+ 3.3265448709918655
+ 3.3265979986000356
+ 3.326651125039683
+ 3.326704250310878
+ 3.32675737441369
+ 3.326810497348189
+ 3.3268636191144445
+ 3.3269167397125265
+ 3.3269698591425043
+ 3.327022977404448
+ 3.3270760944984272
+ 3.327129210424512
+ 3.327182325182771
+ 3.327235438773275
+ 3.3272885511960935
+ 3.3273416624512957
+ 3.327394772538951
+ 3.32744788145913
+ 3.327500989211902
+ 3.3275540957973364
+ 3.3276072012155034
+ 3.327660305466472
+ 3.3277134085503124
+ 3.327766510467093
+ 3.327819611216885
+ 3.327872710799757
+ 3.3279258092157793
+ 3.327978906465021
+ 3.328032002547552
+ 3.3280850974634415
+ 3.3281381912127594
+ 3.328191283795575
+ 3.328244375211958
+ 3.3282974654619784
+ 3.3283505545457044
+ 3.3284036424632073
+ 3.3284567292145555
+ 3.328509814799819
+ 3.3285628992190666
+ 3.328615982472369
+ 3.3286690645597945
+ 3.328722145481413
+ 3.3287752252372944
+ 3.328828303827508
+ 3.3288813812521236
+ 3.32893445751121
+ 3.3289875326048364
+ 3.3290406065330735
+ 3.3290936792959895
+ 3.329146750893655
+ 3.3291998213261387
+ 3.32925289059351
+ 3.329305958695839
+ 3.329359025633194
+ 3.3294120914056453
+ 3.3294651560132618
+ 3.329518219456113
+ 3.329571281734269
+ 3.3296243428477985
+ 3.329677402796771
+ 3.329730461581256
+ 3.329783519201322
+ 3.3298365756570396
+ 3.3298896309484776
+ 3.329942685075706
+ 3.3299957380387926
+ 3.330048789837808
+ 3.3301018404728215
+ 3.330154889943902
+ 3.3302079382511187
+ 3.330260985394541
+ 3.3303140313742388
+ 3.33036707619028
+ 3.330420119842736
+ 3.330473162331674
+ 3.3305262036571643
+ 3.3305792438192765
+ 3.3306322828180788
+ 3.3306853206536413
+ 3.3307383573260325
+ 3.3307913928353226
+ 3.3308444271815802
+ 3.3308974603648744
+ 3.3309504923852753
+ 3.3310035232428508
+ 3.3310565529376714
+ 3.3311095814698057
+ 3.3311626088393225
+ 3.3312156350462914
+ 3.3312686600907813
+ 3.331321683972862
+ 3.331374706692602
+ 3.331427728250071
+ 3.3314807486453373
+ 3.3315337678784718
+ 3.3315867859495407
+ 3.3316398028586165
+ 3.3316928186057657
+ 3.331745833191059
+ 3.3317988466145643
+ 3.331851858876352
+ 3.33190486997649
+ 3.331957879915049
+ 3.332010888692096
+ 3.332063896307701
+ 3.3321169027619337
+ 3.3321699080548624
+ 3.3322229121865563
+ 3.3322759151570844
+ 3.332328916966516
+ 3.33238191761492
+ 3.3324349171023657
+ 3.3324879154289215
+ 3.3325409125946566
+ 3.3325939085996406
+ 3.3326469034439414
+ 3.3326998971276294
+ 3.3327528896507728
+ 3.33280588101344
+ 3.3328588712157017
+ 3.332911860257625
+ 3.3329648481392797
+ 3.3330178348607347
+ 3.333070820422059
+ 3.3331238048233223
+ 3.3331767880645913
+ 3.3332297701459375
+ 3.333282751067428
+ 3.333335730829133
+ 3.3333887094311203
+ 3.3334416868734595
+ 3.3334946631562192
+ 3.333547638279469
+ 3.333600612243276
+ 3.333653585047711
+ 3.333706556692842
+ 3.333759527178738
+ 3.3338124965054683
+ 3.3338654646731007
+ 3.3339184316817048
+ 3.333971397531349
+ 3.334024362222103
+ 3.3340773257540346
+ 3.3341302881272137
+ 3.334183249341707
+ 3.334236209397586
+ 3.3342891682949176
+ 3.334342126033772
+ 3.334395082614216
+ 3.3344480380363204
+ 3.3345009923001534
+ 3.334553945405783
+ 3.3346068973532788
+ 3.3346598481427088
+ 3.3347127977741424
+ 3.3347657462476485
+ 3.3348186935632946
+ 3.3348716397211513
+ 3.3349245847212847
+ 3.334977528563767
+ 3.3350304712486634
+ 3.335083412776045
+ 3.33513635314598
+ 3.335189292358536
+ 3.3352422304137823
+ 3.335295167311788
+ 3.3353481030526213
+ 3.335401037636351
+ 3.335453971063046
+ 3.335506903332775
+ 3.335559834445606
+ 3.3356127644016076
+ 3.3356656932008493
+ 3.335718620843399
+ 3.3357715473293252
+ 3.335824472658697
+ 3.335877396831583
+ 3.3359303198480514
+ 3.3359832417081714
+ 3.336036162412011
+ 3.3360890819596385
+ 3.3361420003511237
+ 3.3361949175865337
+ 3.3362478336659382
+ 3.3363007485894047
+ 3.3363536623570025
+ 3.3364065749687994
+ 3.3364594864248653
+ 3.3365123967252672
+ 3.3365653058700744
+ 3.3366182138593556
+ 3.336671120693179
+ 3.3367240263716123
+ 3.3367769308947253
+ 3.3368298342625855
+ 3.3368827364752622
+ 3.3369356375328234
+ 3.3369885374353374
+ 3.337041436182873
+ 3.337094333775499
+ 3.3371472302132825
+ 3.3372001254962926
+ 3.337253019624599
+ 3.3373059125982674
+ 3.337358804417369
+ 3.337411695081971
+ 3.337464584592141
+ 3.337517472947949
+ 3.337570360149462
+ 3.3376232461967494
+ 3.337676131089879
+ 3.337729014828919
+ 3.3377818974139384
+ 3.337834778845005
+ 3.3378876591221878
+ 3.3379405382455545
+ 3.3379934162151734
+ 3.338046293031113
+ 3.3380991686934416
+ 3.338152043202228
+ 3.3382049165575394
+ 3.3382577887594453
+ 3.338310659808013
+ 3.338363529703312
+ 3.338416398445409
+ 3.338469266034374
+ 3.3385221324702736
+ 3.3385749977531773
+ 3.3386278618831526
+ 3.338680724860268
+ 3.3387335866845915
+ 3.3387864473561923
+ 3.3388393068751374
+ 3.338892165241496
+ 3.338945022455335
+ 3.3389978785167242
+ 3.339050733425731
+ 3.3391035871824237
+ 3.33915643978687
+ 3.3392092912391385
+ 3.339262141539298
+ 3.3393149906874156
+ 3.33936783868356
+ 3.339420685527799
+ 3.3394735312202015
+ 3.3395263757608347
+ 3.3395792191497673
+ 3.339632061387067
+ 3.3396849024728033
+ 3.339737742407042
+ 3.3397905811898534
+ 3.3398434188213044
+ 3.339896255301463
+ 3.3399490906303977
+ 3.340001924808177
+ 3.340054757834868
+ 3.3401075897105392
+ 3.340160420435259
+ 3.340213250009095
+ 3.340266078432116
+ 3.3403189057043883
+ 3.3403717318259822
+ 3.340424556796964
+ 3.340477380617403
+ 3.340530203287366
+ 3.3405830248069215
+ 3.3406358451761378
+ 3.3406886643950826
+ 3.3407414824638235
+ 3.3407942993824298
+ 3.3408471151509684
+ 3.340899929769507
+ 3.3409527432381143
+ 3.341005555556858
+ 3.3410583667258065
+ 3.3411111767450263
+ 3.3411639856145876
+ 3.341216793334556
+ 3.3412695999050013
+ 3.34132240532599
+ 3.341375209597591
+ 3.3414280127198714
+ 3.3414808146929
+ 3.341533615516744
+ 3.3415864151914714
+ 3.34163921371715
+ 3.341692011093848
+ 3.341744807321633
+ 3.3417976024005736
+ 3.341850396330736
+ 3.34190318911219
+ 3.3419559807450017
+ 3.3420087712292403
+ 3.342061560564973
+ 3.3421143487522675
+ 3.342167135791192
+ 3.3422199216818136
+ 3.3422727064242013
+ 3.3423254900184216
+ 3.3423782724645426
+ 3.342431053762633
+ 3.34248383391276
+ 3.3425366129149907
+ 3.3425893907693935
+ 3.3426421674760367
+ 3.342694943034987
+ 3.3427477174463127
+ 3.3428004907100815
+ 3.342853262826361
+ 3.342906033795219
+ 3.3429588036167233
+ 3.343011572290941
+ 3.3430643398179405
+ 3.3431171061977896
+ 3.3431698714305553
+ 3.3432226355163057
+ 3.3432753984551087
+ 3.3433281602470317
+ 3.3433809208921423
+ 3.3434336803905076
+ 3.343486438742197
+ 3.343539195947276
+ 3.343591952005814
+ 3.3436447069178774
+ 3.3436974606835346
+ 3.3437502133028523
+ 3.3438029647758998
+ 3.343855715102743
+ 3.3439084642834502
+ 3.3439612123180886
+ 3.344013959206727
+ 3.344066704949431
+ 3.34411944954627
+ 3.3441721929973105
+ 3.34422493530262
+ 3.3442776764622675
+ 3.3443304164763186
+ 3.344383155344842
+ 3.344435893067905
+ 3.3444886296455745
+ 3.3445413650779194
+ 3.344594099365006
+ 3.344646832506902
+ 3.3446995645036752
+ 3.344752295355393
+ 3.3448050250621235
+ 3.3448577536239332
+ 3.3449104810408894
+ 3.344963207313061
+ 3.345015932440514
+ 3.345068656423317
+ 3.345121379261536
+ 3.34517410095524
+ 3.3452268215044954
+ 3.34527954090937
+ 3.3453322591699313
+ 3.345384976286246
+ 3.345437692258383
+ 3.3454904070864084
+ 3.3455431207703903
+ 3.345595833310396
+ 3.345648544706492
+ 3.3457012549587466
+ 3.345753964067227
+ 3.3458066720320008
+ 3.3458593788531346
+ 3.345912084530697
+ 3.345964789064754
+ 3.3460174924553727
+ 3.346070194702622
+ 3.3461228958065683
+ 3.3461755957672796
+ 3.346228294584822
+ 3.3462809922592642
+ 3.3463336887906716
+ 3.346386384179114
+ 3.3464390784246563
+ 3.3464917715273677
+ 3.346544463487314
+ 3.3465971543045634
+ 3.3466498439791823
+ 3.346702532511239
+ 3.3467552199008006
+ 3.3468079061479337
+ 3.346860591252705
+ 3.3469132752151833
+ 3.346965958035436
+ 3.3470186397135278
+ 3.3470713202495284
+ 3.3471239996435034
+ 3.3471766778955208
+ 3.347229355005648
+ 3.3472820309739517
+ 3.3473347058004994
+ 3.3473873794853577
+ 3.3474400520285945
+ 3.347492723430277
+ 3.347545393690471
+ 3.3475980628092454
+ 3.347650730786666
+ 3.3477033976228014
+ 3.3477560633177164
+ 3.347808727871481
+ 3.3478613912841597
+ 3.3479140535558214
+ 3.3479667146865326
+ 3.34801937467636
+ 3.348072033525371
+ 3.348124691233633
+ 3.348177347801213
+ 3.348230003228177
+ 3.3482826575145936
+ 3.3483353106605285
+ 3.3483879626660498
+ 3.348440613531224
+ 3.348493263256119
+ 3.3485459118408003
+ 3.3485985592853362
+ 3.3486512055897926
+ 3.3487038507542377
+ 3.348756494778738
+ 3.34880913766336
+ 3.3488617794081716
+ 3.348914420013239
+ 3.3489670594786296
+ 3.3490196978044104
+ 3.3490723349906486
+ 3.34912497103741
+ 3.3491776059447624
+ 3.3492302397127727
+ 3.3492828723415085
+ 3.3493355038310355
+ 3.3493881341814213
+ 3.349440763392733
+ 3.349493391465037
+ 3.3495460183984003
+ 3.3495986441928896
+ 3.3496512688485724
+ 3.3497038923655156
+ 3.349756514743785
+ 3.3498091359834494
+ 3.3498617560845743
+ 3.3499143750472262
+ 3.349966992871473
+ 3.3500196095573807
+ 3.350072225105017
+ 3.350124839514448
+ 3.3501774527857404
+ 3.3502300649189616
+ 3.3502826759141784
+ 3.3503352857714574
+ 3.3503878944908654
+ 3.3504405020724697
+ 3.350493108516336
+ 3.350545713822532
+ 3.3505983179911243
+ 3.3506509210221793
+ 3.3507035229157642
+ 3.3507561236719456
+ 3.35080872329079
+ 3.3508613217723653
+ 3.3509139191167363
+ 3.3509665153239716
+ 3.351019110394136
+ 3.3510717043272984
+ 3.3511242971235236
+ 3.3511768887828794
+ 3.3512294793054322
+ 3.351282068691249
+ 3.351334656940396
+ 3.3513872440529404
+ 3.351439830028948
+ 3.3514924148684866
+ 3.351544998571622
+ 3.3515975811384213
+ 3.351650162568951
+ 3.3517027428632775
+ 3.3517553220214675
+ 3.351807900043589
+ 3.3518604769297067
+ 3.3519130526798877
+ 3.351965627294199
+ 3.3520182007727075
+ 3.352070773115479
+ 3.352123344322581
+ 3.352175914394079
+ 3.35222848333004
+ 3.352281051130531
+ 3.3523336177956184
+ 3.3523861833253688
+ 3.3524387477198485
+ 3.352491310979124
+ 3.352543873103262
+ 3.3525964340923293
+ 3.3526489939463917
+ 3.3527015526655166
+ 3.3527541102497698
+ 3.3528066666992182
+ 3.352859222013928
+ 3.352911776193966
+ 3.3529643292393994
+ 3.3530168811502934
+ 3.353069431926715
+ 3.3531219815687296
+ 3.353174530076406
+ 3.353227077449809
+ 3.3532796236890055
+ 3.3533321687940614
+ 3.353384712765044
+ 3.353437255602019
+ 3.3534897973050537
+ 3.3535423378742135
+ 3.3535948773095656
+ 3.3536474156111757
+ 3.353699952779111
+ 3.3537524888134373
+ 3.3538050237142216
+ 3.3538575574815295
+ 3.353910090115428
+ 3.3539626216159832
+ 3.3540151519832606
+ 3.354067681217329
+ 3.354120209318252
+ 3.3541727362860976
+ 3.3542252621209316
+ 3.3542777868228204
+ 3.3543303103918305
+ 3.354382832828028
+ 3.354435354131479
+ 3.3544878743022504
+ 3.354540393340408
+ 3.354592911246019
+ 3.3546454280191473
+ 3.354697943659862
+ 3.3547504581682284
+ 3.3548029715443124
+ 3.3548554837881808
+ 3.3549079948998988
+ 3.3549605048795335
+ 3.355013013727151
+ 3.3550655214428176
+ 3.3551180280265993
+ 3.3551705334785633
+ 3.3552230377987744
+ 3.355275540987299
+ 3.3553280430442043
+ 3.355380543969556
+ 3.35543304376342
+ 3.355485542425863
+ 3.3555380399569503
+ 3.3555905363567495
+ 3.355643031625325
+ 3.3556955257627443
+ 3.3557480187690736
+ 3.3558005106443782
+ 3.355853001388725
+ 3.3559054910021793
+ 3.355957979484808
+ 3.3560104668366764
+ 3.3560629530578523
+ 3.3561154381483993
+ 3.3561679221083858
+ 3.3562204049378765
+ 3.3562728866369382
+ 3.3563253672056366
+ 3.356377846644038
+ 3.3564303249522083
+ 3.356482802130214
+ 3.3565352781781206
+ 3.3565877530959947
+ 3.356640226883901
+ 3.3566926995419077
+ 3.3567451710700795
+ 3.356797641468482
+ 3.3568501107371826
+ 3.3569025788762463
+ 3.3569550458857393
+ 3.3570075117657274
+ 3.3570599765162776
+ 3.3571124401374544
+ 3.3571649026293255
+ 3.3572173639919547
+ 3.3572698242254106
+ 3.3573222833297565
+ 3.3573747413050605
+ 3.3574271981513872
+ 3.3574796538688036
+ 3.3575321084573746
+ 3.3575845619171667
+ 3.357637014248246
+ 3.357689465450678
+ 3.3577419155245294
+ 3.3577943644698642
+ 3.3578468122867506
+ 3.3578992589752534
+ 3.3579517045354383
+ 3.358004148967371
+ 3.3580565922711187
+ 3.358109034446746
+ 3.3581614754943194
+ 3.358213915413905
+ 3.358266354205567
+ 3.358318791869373
+ 3.358371228405389
+ 3.3584236638136793
+ 3.358476098094311
+ 3.358528531247349
+ 3.35858096327286
+ 3.358633394170909
+ 3.3586858239415625
+ 3.358738252584886
+ 3.3587906801009453
+ 3.358843106489806
+ 3.358895531751534
+ 3.3589479558861957
+ 3.359000378893856
+ 3.3590528007745806
+ 3.3591052215284356
+ 3.359157641155487
+ 3.3592100596558003
+ 3.3592624770294415
+ 3.3593148932764754
+ 3.3593673083969686
+ 3.3594197223909865
+ 3.3594721352585957
+ 3.35952454699986
+ 3.359576957614847
+ 3.359629367103621
+ 3.3596817754662487
+ 3.3597341827027956
+ 3.3597865888133263
+ 3.359838993797908
+ 3.359891397656605
+ 3.359943800389484
+ 3.35999620199661
+ 3.3600486024780496
+ 3.360101001833867
+ 3.3601534000641284
+ 3.3602057971689
+ 3.360258193148247
+ 3.3603105880022346
+ 3.3603629817309293
+ 3.360415374334396
+ 3.3604677658127007
+ 3.3605201561659084
+ 3.360572545394085
+ 3.3606249334972964
+ 3.360677320475608
+ 3.360729706329085
+ 3.3607820910577932
+ 3.360834474661798
+ 3.3608868571411654
+ 3.360939238495961
+ 3.360991618726249
+ 3.3610439978320965
+ 3.3610963758135677
+ 3.3611487526707298
+ 3.3612011284036463
+ 3.3612535030123842
+ 3.3613058764970085
+ 3.361358248857585
+ 3.361410620094178
+ 3.3614629902068542
+ 3.361515359195679
+ 3.361567727060718
+ 3.3616200938020353
+ 3.361672459419697
+ 3.3617248239137694
+ 3.3617771872843174
+ 3.3618295495314063
+ 3.361881910655101
+ 3.3619342706554685
+ 3.361986629532572
+ 3.362038987286479
+ 3.3620913439172537
+ 3.3621436994249616
+ 3.3621960538096682
+ 3.3622484070714393
+ 3.36230075921034
+ 3.3623531102264357
+ 3.3624054601197915
+ 3.362457808890473
+ 3.3625101565385447
+ 3.3625625030640736
+ 3.362614848467124
+ 3.362667192747761
+ 3.362719535906051
+ 3.3627718779420577
+ 3.362824218855848
+ 3.3628765586474856
+ 3.3629288973170377
+ 3.362981234864568
+ 3.363033571290143
+ 3.363085906593827
+ 3.363138240775686
+ 3.3631905738357837
+ 3.363242905774188
+ 3.363295236590962
+ 3.363347566286172
+ 3.3633998948598824
+ 3.3634522223121595
+ 3.3635045486430677
+ 3.363556873852673
+ 3.3636091979410403
+ 3.3636615209082334
+ 3.36371384275432
+ 3.3637661634793634
+ 3.3638184830834295
+ 3.3638708015665832
+ 3.363923118928891
+ 3.3639754351704156
+ 3.3640277502912244
+ 3.3640800642913815
+ 3.3641323771709524
+ 3.3641846889300013
+ 3.3642369995685955
+ 3.364289309086798
+ 3.3643416174846745
+ 3.3643939247622905
+ 3.3644462309197114
+ 3.3644985359570017
+ 3.3645508398742265
+ 3.3646031426714513
+ 3.364655444348741
+ 3.3647077449061604
+ 3.3647600443437753
+ 3.3648123426616503
+ 3.36486463985985
+ 3.36491693593844
+ 3.364969230897486
+ 3.3650215247370516
+ 3.3650738174572035
+ 3.365126109058005
+ 3.3651783995395226
+ 3.36523068890182
+ 3.3652829771449633
+ 3.3653352642690173
+ 3.365387550274047
+ 3.365439835160117
+ 3.3654921189272926
+ 3.365544401575639
+ 3.3655966831052204
+ 3.3656489635161027
+ 3.36570124280835
+ 3.365753520982028
+ 3.3658057980372016
+ 3.3658580739739357
+ 3.3659103487922946
+ 3.3659626224923436
+ 3.3660148950741484
+ 3.366067166537773
+ 3.3661194368832823
+ 3.366171706110742
+ 3.3662239742202167
+ 3.3662762412117706
+ 3.3663285070854694
+ 3.3663807718413774
+ 3.366433035479561
+ 3.366485298000083
+ 3.366537559403009
+ 3.3665898196884045
+ 3.366642078856333
+ 3.3666943369068614
+ 3.3667465938400527
+ 3.366798849655973
+ 3.366851104354686
+ 3.3669033579362573
+ 3.366955610400751
+ 3.3670078617482333
+ 3.367060111978768
+ 3.36711236109242
+ 3.367164609089254
+ 3.367216855969335
+ 3.367269101732728
+ 3.367321346379497
+ 3.3673735899097075
+ 3.3674258323234243
+ 3.367478073620712
+ 3.367530313801635
+ 3.3675825528662586
+ 3.3676347908146465
+ 3.3676870276468653
+ 3.367739263362978
+ 3.36779149796305
+ 3.3678437314471457
+ 3.367895963815331
+ 3.367948195067669
+ 3.368000425204225
+ 3.368052654225064
+ 3.368104882130251
+ 3.3681571089198497
+ 3.3682093345939252
+ 3.368261559152542
+ 3.3683137825957656
+ 3.3683660049236592
+ 3.3684182261362894
+ 3.368470446233719
+ 3.3685226652160134
+ 3.3685748830832374
+ 3.3686270998354555
+ 3.368679315472732
+ 3.3687315299951317
+ 3.3687837434027195
+ 3.36883595569556
+ 3.3688881668737176
+ 3.368940376937256
+ 3.3689925858862417
+ 3.3690447937207377
+ 3.369097000440809
+ 3.3691492060465205
+ 3.369201410537937
+ 3.3692536139151215
+ 3.3693058161781404
+ 3.369358017327057
+ 3.369410217361937
+ 3.3694624162828437
+ 3.3695146140898427
+ 3.3695668107829975
+ 3.369619006362373
+ 3.369671200828034
+ 3.3697233941800455
+ 3.3697755864184704
+ 3.369827777543374
+ 3.369879967554821
+ 3.3699321564528764
+ 3.3699843442376034
+ 3.370036530909067
+ 3.370088716467332
+ 3.3701409009124625
+ 3.370193084244523
+ 3.370245266463578
+ 3.370297447569692
+ 3.3703496275629288
+ 3.3704018064433536
+ 3.3704539842110313
+ 3.3705061608660247
+ 3.3705583364083993
+ 3.370610510838219
+ 3.3706626841555485
+ 3.3707148563604523
+ 3.370767027452995
+ 3.3708191974332395
+ 3.370871366301252
+ 3.370923534057096
+ 3.3709757007008365
+ 3.371027866232536
+ 3.3710800306522613
+ 3.371132193960075
+ 3.3711843561560424
+ 3.371236517240227
+ 3.3712886772126938
+ 3.3713408360735064
+ 3.3713929938227305
+ 3.3714451504604286
+ 3.3714973059866664
+ 3.3715494604015075
+ 3.371601613705016
+ 3.371653765897257
+ 3.3717059169782937
+ 3.3717580669481912
+ 3.371810215807013
+ 3.371862363554825
+ 3.371914510191689
+ 3.3719666557176713
+ 3.3720188001328353
+ 3.372070943437245
+ 3.3721230856309647
+ 3.372175226714059
+ 3.3722273666865923
+ 3.3722795055486277
+ 3.3723316433002304
+ 3.3723837799414644
+ 3.372435915472394
+ 3.3724880498930827
+ 3.3725401832035953
+ 3.372592315403996
+ 3.372644446494349
+ 3.372696576474717
+ 3.3727487053451664
+ 3.3728008331057597
+ 3.372852959756562
+ 3.3729050852976368
+ 3.3729572097290488
+ 3.3730093330508617
+ 3.3730614552631395
+ 3.373113576365947
+ 3.3731656963593473
+ 3.373217815243405
+ 3.3732699330181846
+ 3.373322049683749
+ 3.373374165240164
+ 3.373426279687492
+ 3.3734783930257977
+ 3.373530505255146
+ 3.3735826163755998
+ 3.3736347263872233
+ 3.373686835290081
+ 3.3737389430842364
+ 3.373791049769754
+ 3.3738431553466977
+ 3.3738952598151313
+ 3.373947363175119
+ 3.3739994654267247
+ 3.374051566570013
+ 3.3741036666050466
+ 3.374155765531891
+ 3.3742078633506085
+ 3.3742599600612646
+ 3.3743120556639226
+ 3.3743641501586468
+ 3.3744162435455003
+ 3.3744683358245475
+ 3.374520426995853
+ 3.37457251705948
+ 3.3746246060154923
+ 3.3746766938639543
+ 3.3747287806049298
+ 3.3747808662384826
+ 3.3748329507646773
+ 3.3748850341835763
+ 3.374937116495245
+ 3.374989197699746
+ 3.3750412777971444
+ 3.3750933567875037
+ 3.375145434670887
+ 3.375197511447359
+ 3.375249587116983
+ 3.375301661679824
+ 3.375353735135944
+ 3.375405807485408
+ 3.3754578787282803
+ 3.375509948864624
+ 3.3755620178945027
+ 3.375614085817981
+ 3.3756661526351213
+ 3.3757182183459893
+ 3.375770282950647
+ 3.37582234644916
+ 3.37587440884159
+ 3.375926470128003
+ 3.375978530308461
+ 3.3760305893830287
+ 3.3760826473517693
+ 3.3761347042147474
+ 3.376186759972026
+ 3.376238814623669
+ 3.3762908681697406
+ 3.3763429206103033
+ 3.3763949719454223
+ 3.37644702217516
+ 3.3764990712995817
+ 3.3765511193187496
+ 3.3766031662327283
+ 3.3766552120415807
+ 3.3767072567453713
+ 3.3767593003441636
+ 3.376811342838021
+ 3.3768633842270073
+ 3.376915424511186
+ 3.376967463690621
+ 3.377019501765376
+ 3.377071538735515
+ 3.3771235746011006
+ 3.3771756093621974
+ 3.377227643018868
+ 3.3772796755711774
+ 3.377331707019188
+ 3.377383737362964
+ 3.3774357666025687
+ 3.3774877947380664
+ 3.3775398217695196
+ 3.3775918476969933
+ 3.3776438725205495
+ 3.377695896240253
+ 3.3777479188561665
+ 3.3777999403683547
+ 3.37785196077688
+ 3.3779039800818063
+ 3.377955998283197
+ 3.3780080153811163
+ 3.378060031375627
+ 3.3781120462667933
+ 3.378164060054678
+ 3.3782160727393453
+ 3.3782680843208586
+ 3.3783200947992804
+ 3.3783721041746753
+ 3.3784241124471066
+ 3.378476119616638
+ 3.3785281256833324
+ 3.3785801306472534
+ 3.3786321345084644
+ 3.378684137267029
+ 3.378736138923011
+ 3.378788139476474
+ 3.37884013892748
+ 3.378892137276094
+ 3.378944134522379
+ 3.378996130666398
+ 3.379048125708215
+ 3.3791001196478927
+ 3.379152112485495
+ 3.379204104221086
+ 3.379256094854728
+ 3.3793080843864844
+ 3.3793600728164197
+ 3.3794120601445954
+ 3.3794640463710763
+ 3.379516031495926
+ 3.3795680155192067
+ 3.3796199984409827
+ 3.379671980261317
+ 3.3797239609802725
+ 3.3797759405979138
+ 3.3798279191143026
+ 3.3798798965295034
+ 3.379931872843579
+ 3.379983848056593
+ 3.3800358221686087
+ 3.3800877951796893
+ 3.3801397670898985
+ 3.380191737899298
+ 3.3802437076079537
+ 3.380295676215926
+ 3.3803476437232804
+ 3.3803996101300795
+ 3.3804515754363864
+ 3.3805035396422642
+ 3.380555502747776
+ 3.380607464752986
+ 3.3806594256579565
+ 3.380711385462751
+ 3.3807633441674327
+ 3.3808153017720652
+ 3.3808672582767114
+ 3.3809192136814343
+ 3.3809711679862975
+ 3.3810231211913635
+ 3.3810750732966968
+ 3.3811270243023595
+ 3.381178974208415
+ 3.3812309230149267
+ 3.381282870721957
+ 3.3813348173295705
+ 3.3813867628378285
+ 3.381438707246796
+ 3.3814906505565347
+ 3.381542592767109
+ 3.3815945338785807
+ 3.3816464738910144
+ 3.381698412804471
+ 3.3817503506190163
+ 3.3818022873347116
+ 3.3818542229516213
+ 3.381906157469807
+ 3.3819580908893325
+ 3.382010023210261
+ 3.3820619544326553
+ 3.3821138845565795
+ 3.3821658135820947
+ 3.3822177415092654
+ 3.3822696683381546
+ 3.382321594068825
+ 3.3823735187013395
+ 3.3824254422357614
+ 3.3824773646721535
+ 3.3825292860105796
+ 3.3825812062511016
+ 3.382633125393783
+ 3.382685043438687
+ 3.382736960385876
+ 3.3827888762354137
+ 3.382840790987363
+ 3.382892704641787
+ 3.3829446171987483
+ 3.3829965286583095
+ 3.383048439020534
+ 3.383100348285485
+ 3.3831522564532253
+ 3.3832041635238173
+ 3.3832560694973246
+ 3.3833079743738104
+ 3.3833598781533367
+ 3.383411780835967
+ 3.3834636824217643
+ 3.3835155829107912
+ 3.3835674823031106
+ 3.3836193805987858
+ 3.383671277797879
+ 3.383723173900454
+ 3.383775068906573
+ 3.383826962816299
+ 3.383878855629695
+ 3.3839307473468234
+ 3.3839826379677476
+ 3.384034527492531
+ 3.3840864159212356
+ 3.384138303253924
+ 3.3841901894906594
+ 3.3842420746315045
+ 3.384293958676523
+ 3.3843458416257763
+ 3.3843977234793288
+ 3.3844496042372416
+ 3.384501483899579
+ 3.3845533624664026
+ 3.384605239937776
+ 3.384657116313761
+ 3.384708991594422
+ 3.3847608657798203
+ 3.3848127388700195
+ 3.384864610865082
+ 3.384916481765071
+ 3.384968351570048
+ 3.385020220280077
+ 3.3850720878952205
+ 3.385123954415541
+ 3.385175819841101
+ 3.3852276841719635
+ 3.385279547408192
+ 3.3853314095498477
+ 3.3853832705969946
+ 3.385435130549694
+ 3.38548698940801
+ 3.3855388471720045
+ 3.3855907038417405
+ 3.3856425594172808
+ 3.3856944138986873
+ 3.3857462672860232
+ 3.3857981195793516
+ 3.385849970778734
+ 3.3859018208842344
+ 3.3859536698959145
+ 3.386005517813837
+ 3.3860573646380647
+ 3.38610921036866
+ 3.386161055005686
+ 3.3862128985492053
+ 3.38626474099928
+ 3.386316582355973
+ 3.3863684226193467
+ 3.3864202617894636
+ 3.386472099866387
+ 3.3865239368501783
+ 3.3865757727409016
+ 3.3866276075386175
+ 3.3866794412433907
+ 3.386731273855282
+ 3.386783105374355
+ 3.3868349358006715
+ 3.386886765134295
+ 3.386938593375287
+ 3.38699042052371
+ 3.3870422465796275
+ 3.387094071543101
+ 3.387145895414194
+ 3.387197718192968
+ 3.3872495398794866
+ 3.387301360473811
+ 3.387353179976005
+ 3.3874049983861294
+ 3.3874568157042484
+ 3.387508631930423
+ 3.387560447064717
+ 3.387612261107192
+ 3.3876640740579105
+ 3.387715885916935
+ 3.3877676966843286
+ 3.3878195063601524
+ 3.3878713149444706
+ 3.387923122437344
+ 3.387974928838835
+ 3.388026734149007
+ 3.3880785383679224
+ 3.3881303414956427
+ 3.388182143532231
+ 3.3882339444777494
+ 3.38828574433226
+ 3.388337543095826
+ 3.3883893407685086
+ 3.388441137350372
+ 3.388492932841476
+ 3.3885447272418845
+ 3.3885965205516597
+ 3.3886483127708646
+ 3.3887001038995597
+ 3.388751893937809
+ 3.3888036828856745
+ 3.388855470743218
+ 3.3889072575105024
+ 3.388959043187589
+ 3.3890108277745408
+ 3.38906261127142
+ 3.3891143936782893
+ 3.3891661749952102
+ 3.3892179552222457
+ 3.3892697343594573
+ 3.389321512406908
+ 3.3893732893646593
+ 3.389425065232774
+ 3.3894768400113144
+ 3.3895286137003424
+ 3.38958038629992
+ 3.3896321578101105
+ 3.3896839282309745
+ 3.389735697562576
+ 3.3897874658049756
+ 3.3898392329582365
+ 3.389890999022421
+ 3.38994276399759
+ 3.3899945278838075
+ 3.390046290681134
+ 3.390098052389633
+ 3.3901498130093657
+ 3.390201572540395
+ 3.3902533309827825
+ 3.39030508833659
+ 3.3903568446018806
+ 3.3904085997787163
+ 3.3904603538671587
+ 3.3905121068672703
+ 3.390563858779113
+ 3.390615609602749
+ 3.39066735933824
+ 3.390719107985649
+ 3.3907708555450373
+ 3.390822602016468
+ 3.390874347400002
+ 3.390926091695701
+ 3.3909778349036293
+ 3.3910295770238466
+ 3.3910813180564165
+ 3.3911330580014
+ 3.39118479685886
+ 3.3912365346288587
+ 3.3912882713114567
+ 3.391340006906717
+ 3.3913917414147026
+ 3.3914434748354734
+ 3.3914952071690934
+ 3.391546938415623
+ 3.3915986685751256
+ 3.3916503976476613
+ 3.3917021256332944
+ 3.391753852532086
+ 3.3918055783440972
+ 3.3918573030693913
+ 3.3919090267080287
+ 3.391960749260073
+ 3.392012470725585
+ 3.3920641911046276
+ 3.3921159103972616
+ 3.3921676286035503
+ 3.3922193457235545
+ 3.3922710617573366
+ 3.392322776704958
+ 3.392374490566482
+ 3.392426203341969
+ 3.3924779150314817
+ 3.3925296256350816
+ 3.3925813351528307
+ 3.392633043584791
+ 3.3926847509310245
+ 3.3927364571915932
+ 3.3927881623665583
+ 3.3928398664559825
+ 3.3928915694599264
+ 3.3929432713784538
+ 3.3929949722116244
+ 3.3930466719595014
+ 3.3930983706221465
+ 3.3931500681996214
+ 3.393201764691987
+ 3.3932534600993067
+ 3.393305154421641
+ 3.3933568476590534
+ 3.393408539811604
+ 3.3934602308793544
+ 3.393511920862368
+ 3.393563609760706
+ 3.393615297574429
+ 3.3936669843036005
+ 3.393718669948281
+ 3.393770354508533
+ 3.393822037984418
+ 3.393873720375998
+ 3.393925401683334
+ 3.3939770819064883
+ 3.3940287610455226
+ 3.3940804391004984
+ 3.3941321160714777
+ 3.394183791958522
+ 3.394235466761694
+ 3.3942871404810533
+ 3.3943388131166636
+ 3.3943904846685853
+ 3.394442155136881
+ 3.3944938245216116
+ 3.39454549282284
+ 3.394597160040626
+ 3.3946488261750325
+ 3.3947004912261214
+ 3.3947521551939532
+ 3.394803818078591
+ 3.3948554798800954
+ 3.3949071405985283
+ 3.394958800233951
+ 3.395010458786426
+ 3.395062116256014
+ 3.3951137726427776
+ 3.395165427946777
+ 3.3952170821680747
+ 3.3952687353067326
+ 3.395320387362812
+ 3.395372038336374
+ 3.395423688227481
+ 3.395475337036193
+ 3.395526984762574
+ 3.3955786314066834
+ 3.395630276968584
+ 3.3956819214483374
+ 3.3957335648460036
+ 3.395785207161646
+ 3.395836848395325
+ 3.395888488547103
+ 3.3959401276170404
+ 3.3959917656051997
+ 3.396043402511642
+ 3.3960950383364286
+ 3.3961466730796213
+ 3.3961983067412818
+ 3.396249939321471
+ 3.396301570820251
+ 3.396353201237682
+ 3.3964048305738275
+ 3.3964564588287476
+ 3.396508086002504
+ 3.3965597120951583
+ 3.3966113371067723
+ 3.3966629610374066
+ 3.3967145838871224
+ 3.3967662056559824
+ 3.3968178263440474
+ 3.3968694459513786
+ 3.3969210644780374
+ 3.396972681924086
+ 3.397024298289585
+ 3.397075913574596
+ 3.3971275277791797
+ 3.397179140903399
+ 3.3972307529473147
+ 3.3972823639109877
+ 3.397333973794479
+ 3.397385582597851
+ 3.3974371903211646
+ 3.3974887969644816
+ 3.3975404025278624
+ 3.3975920070113688
+ 3.397643610415062
+ 3.3976952127390043
+ 3.397746813983256
+ 3.3977984141478776
+ 3.397850013232933
+ 3.3979016112384812
+ 3.3979532081645845
+ 3.398004804011303
+ 3.3980563987787
+ 3.3981079924668354
+ 3.3981595850757707
+ 3.398211176605567
+ 3.398262767056287
+ 3.398314356427989
+ 3.3983659447207373
+ 3.3984175319345917
+ 3.3984691180696136
+ 3.398520703125864
+ 3.3985722871034043
+ 3.3986238700022966
+ 3.3986754518226006
+ 3.3987270325643784
+ 3.3987786122276913
+ 3.3988301908126
+ 3.3988817683191663
+ 3.398933344747451
+ 3.3989849200975146
+ 3.3990364943694202
+ 3.3990880675632265
+ 3.3991396396789972
+ 3.399191210716791
+ 3.3992427806766714
+ 3.3992943495586974
+ 3.3993459173629317
+ 3.3993974840894348
+ 3.3994490497382683
+ 3.399500614309493
+ 3.399552177803169
+ 3.39960374021936
+ 3.399655301558124
+ 3.3997068618195248
+ 3.399758421003621
+ 3.399809979110476
+ 3.3998615361401496
+ 3.3999130920927034
+ 3.399964646968198
+ 3.400016200766695
+ 3.400067753488255
+ 3.4001193051329395
+ 3.4001708557008086
+ 3.400222405191925
+ 3.4002739536063484
+ 3.4003255009441404
+ 3.400377047205362
+ 3.4004285923900737
+ 3.4004801364983375
+ 3.4005316795302134
+ 3.4005832214857628
+ 3.400634762365047
+ 3.4006863021681264
+ 3.400737840895063
+ 3.400789378545917
+ 3.400840915120749
+ 3.4008924506196205
+ 3.4009439850425927
+ 3.4009955183897267
+ 3.4010470506610826
+ 3.401098581856722
+ 3.4011501119767056
+ 3.4012016410210943
+ 3.4012531689899497
+ 3.401304695883332
+ 3.4013562217013016
+ 3.4014077464439216
+ 3.4014592701112507
+ 3.40151079270335
+ 3.4015623142202815
+ 3.4016138346621054
+ 3.401665354028883
+ 3.4017168723206748
+ 3.401768389537542
+ 3.401819905679545
+ 3.4018714207467453
+ 3.401922934739203
+ 3.40197444765698
+ 3.402025959500136
+ 3.4020774702687326
+ 3.4021289799628303
+ 3.40218048858249
+ 3.4022319961277727
+ 3.4022835025987392
+ 3.40233500799545
+ 3.402386512317966
+ 3.402438015566349
+ 3.4024895177406584
+ 3.4025410188409557
+ 3.402592518867301
+ 3.4026440178197563
+ 3.4026955156983814
+ 3.4027470125032373
+ 3.4027985082343846
+ 3.402850002891885
+ 3.4029014964757978
+ 3.4029529889861854
+ 3.4030044804231068
+ 3.403055970786624
+ 3.4031074600767974
+ 3.403158948293688
+ 3.403210435437355
+ 3.4032619215078617
+ 3.4033134065052666
+ 3.403364890429631
+ 3.4034163732810168
+ 3.403467855059483
+ 3.403519335765091
+ 3.4035708153979014
+ 3.403622293957975
+ 3.403673771445373
+ 3.403725247860155
+ 3.403776723202382
+ 3.403828197472115
+ 3.4038796706694145
+ 3.4039311427943413
+ 3.4039826138469556
+ 3.4040340838273186
+ 3.40408555273549
+ 3.404137020571532
+ 3.4041884873355035
+ 3.404239953027466
+ 3.40429141764748
+ 3.404342881195606
+ 3.404394343671905
+ 3.404445805076437
+ 3.4044972654092627
+ 3.4045487246704424
+ 3.404600182860038
+ 3.4046516399781086
+ 3.4047030960247158
+ 3.404754550999919
+ 3.40480600490378
+ 3.404857457736358
+ 3.404908909497715
+ 3.4049603601879106
+ 3.405011809807006
+ 3.40506325835506
+ 3.4051147058321356
+ 3.4051661522382917
+ 3.4052175975735897
+ 3.405269041838089
+ 3.405320485031851
+ 3.4053719271549356
+ 3.4054233682074035
+ 3.4054748081893154
+ 3.4055262471007315
+ 3.4055776849417128
+ 3.4056291217123187
+ 3.405680557412611
+ 3.4057319920426488
+ 3.4057834256024937
+ 3.4058348580922053
+ 3.405886289511845
+ 3.405937719861472
+ 3.4059891491411474
+ 3.406040577350931
+ 3.4060920044908847
+ 3.406143430561067
+ 3.40619485556154
+ 3.4062462794923634
+ 3.4062977023535965
+ 3.406349124145302
+ 3.4064005448675383
+ 3.4064519645203664
+ 3.406503383103847
+ 3.40655480061804
+ 3.4066062170630054
+ 3.406657632438805
+ 3.4067090467454975
+ 3.4067604599831447
+ 3.4068118721518053
+ 3.4068632832515413
+ 3.4069146932824115
+ 3.4069661022444775
+ 3.407017510137799
+ 3.407068916962437
+ 3.40712032271845
+ 3.4071717274059
+ 3.4072231310248466
+ 3.4072745335753503
+ 3.4073259350574716
+ 3.4073773354712698
+ 3.4074287348168064
+ 3.4074801330941407
+ 3.4075315303033338
+ 3.407582926444445
+ 3.4076343215175355
+ 3.407685715522665
+ 3.407737108459894
+ 3.4077885003292816
+ 3.40783989113089
+ 3.407891280864778
+ 3.4079426695310064
+ 3.4079940571296348
+ 3.4080454436607246
+ 3.4080968291243345
+ 3.4081482135205254
+ 3.4081995968493577
+ 3.408250979110891
+ 3.408302360305186
+ 3.4083537404323025
+ 3.4084051194923015
+ 3.4084564974852416
+ 3.4085078744111845
+ 3.408559250270189
+ 3.4086106250623165
+ 3.4086619987876263
+ 3.4087133714461793
+ 3.4087647430380343
+ 3.4088161135632524
+ 3.4088674830218944
+ 3.4089188514140187
+ 3.4089702187396864
+ 3.4090215849989574
+ 3.409072950191892
+ 3.4091243143185497
+ 3.409175677378991
+ 3.4092270393732766
+ 3.409278400301466
+ 3.409329760163618
+ 3.4093811189597942
+ 3.409432476690055
+ 3.409483833354459
+ 3.4095351889530674
+ 3.40958654348594
+ 3.409637896953136
+ 3.4096892493547166
+ 3.4097406006907405
+ 3.409791950961269
+ 3.4098433001663615
+ 3.409894648306078
+ 3.409945995380479
+ 3.4099973413896234
+ 3.410048686333573
+ 3.4101000302123854
+ 3.4101513730261224
+ 3.410202714774843
+ 3.410254055458608
+ 3.410305395077476
+ 3.410356733631509
+ 3.4104080711207643
+ 3.410459407545305
+ 3.4105107429051884
+ 3.4105620772004754
+ 3.410613410431226
+ 3.4106647425975
+ 3.4107160736993576
+ 3.4107674037368585
+ 3.410818732710062
+ 3.4108700606190285
+ 3.4109213874638185
+ 3.410972713244491
+ 3.4110240379611065
+ 3.411075361613724
+ 3.4111266842024044
+ 3.4111780057272068
+ 3.4112293261881916
+ 3.411280645585418
+ 3.4113319639189466
+ 3.411383281188837
+ 3.4114345973951488
+ 3.4114859125379415
+ 3.411537226617276
+ 3.411588539633211
+ 3.4116398515858073
+ 3.411691162475124
+ 3.411742472301221
+ 3.411793781064158
+ 3.4118450887639957
+ 3.4118963954007926
+ 3.4119477009746095
+ 3.4119990054855056
+ 3.4120503089335403
+ 3.4121016113187745
+ 3.4121529126412673
+ 3.4122042129010786
+ 3.4122555120982674
+ 3.412306810232894
+ 3.412358107305019
+ 3.412409403314701
+ 3.412460698262
+ 3.4125119921469764
+ 3.412563284969688
+ 3.412614576730197
+ 3.412665867428561
+ 3.4127171570648414
+ 3.412768445639097
+ 3.4128197331513874
+ 3.412871019601772
+ 3.412922304990312
+ 3.412973589317066
+ 3.4130248725820924
+ 3.4130761547854536
+ 3.4131274359272066
+ 3.4131787160074127
+ 3.413229995026131
+ 3.4132812729834217
+ 3.4133325498793434
+ 3.413383825713957
+ 3.4134351004873205
+ 3.413486374199495
+ 3.413537646850539
+ 3.4135889184405137
+ 3.4136401889694765
+ 3.413691458437489
+ 3.4137427268446094
+ 3.413793994190898
+ 3.413845260476414
+ 3.4138965257012175
+ 3.4139477898653676
+ 3.413999052968924
+ 3.4140503150119463
+ 3.4141015759944935
+ 3.414152835916626
+ 3.414204094778403
+ 3.414255352579884
+ 3.4143066093211285
+ 3.4143578650021964
+ 3.414409119623146
+ 3.414460373184039
+ 3.4145116256849324
+ 3.4145628771258876
+ 3.414614127506963
+ 3.4146653768282187
+ 3.4147166250897136
+ 3.4147678722915082
+ 3.414819118433661
+ 3.414870363516232
+ 3.4149216075392803
+ 3.414972850502865
+ 3.4150240924070467
+ 3.415075333251884
+ 3.415126573037437
+ 3.4151778117637637
+ 3.4152290494309256
+ 3.41528028603898
+ 3.4153315215879885
+ 3.415382756078009
+ 3.4154339895091006
+ 3.415485221881324
+ 3.415536453194738
+ 3.4155876834494014
+ 3.4156389126453752
+ 3.415690140782717
+ 3.415741367861487
+ 3.415792593881745
+ 3.415843818843549
+ 3.4158950427469605
+ 3.4159462655920363
+ 3.4159974873788377
+ 3.416048708107423
+ 3.4160999277778523
+ 3.416151146390184
+ 3.4162023639444787
+ 3.4162535804407943
+ 3.4163047958791912
+ 3.416356010259728
+ 3.4164072235824645
+ 3.41645843584746
+ 3.416509647054774
+ 3.4165608572044643
+ 3.416612066296592
+ 3.4166632743312157
+ 3.4167144813083947
+ 3.416765687228188
+ 3.416816892090655
+ 3.416868095895855
+ 3.4169192986438475
+ 3.4169705003346915
+ 3.417021700968446
+ 3.417072900545171
+ 3.4171240990649245
+ 3.4171752965277675
+ 3.417226492933757
+ 3.4172776882829545
+ 3.417328882575417
+ 3.417380075811206
+ 3.4174312679903784
+ 3.417482459112995
+ 3.417533649179114
+ 3.417584838188796
+ 3.4176360261420986
+ 3.4176872130390814
+ 3.4177383988798047
+ 3.4177895836643257
+ 3.4178407673927054
+ 3.4178919500650013
+ 3.417943131681274
+ 3.4179943122415817
+ 3.4180454917459837
+ 3.4180966701945397
+ 3.418147847587308
+ 3.4181990239243487
+ 3.41825019920572
+ 3.418301373431481
+ 3.4183525466016915
+ 3.41840371871641
+ 3.418454889775696
+ 3.4185060597796078
+ 3.418557228728206
+ 3.418608396621548
+ 3.418659563459694
+ 3.418710729242703
+ 3.418761893970633
+ 3.418813057643544
+ 3.418864220261495
+ 3.4189153818245446
+ 3.418966542332752
+ 3.419017701786177
+ 3.4190688601848773
+ 3.419120017528913
+ 3.4191711738183423
+ 3.419222329053225
+ 3.4192734832336193
+ 3.419324636359585
+ 3.4193757884311804
+ 3.4194269394484653
+ 3.4194780894114976
+ 3.419529238320337
+ 3.419580386175042
+ 3.419631532975672
+ 3.4196826787222863
+ 3.419733823414943
+ 3.419784967053702
+ 3.4198361096386205
+ 3.4198872511697593
+ 3.4199383916471766
+ 3.4199895310709314
+ 3.4200406694410828
+ 3.4200918067576893
+ 3.4201429430208097
+ 3.4201940782305034
+ 3.4202452123868294
+ 3.4202963454898465
+ 3.4203474775396128
+ 3.4203986085361886
+ 3.4204497384796313
+ 3.4205008673700004
+ 3.420551995207355
+ 3.4206031219917543
+ 3.420654247723256
+ 3.4207053724019194
+ 3.420756496027804
+ 3.4208076186009686
+ 3.420858740121471
+ 3.4209098605893704
+ 3.4209609800047267
+ 3.421012098367597
+ 3.421063215678042
+ 3.421114331936119
+ 3.421165447141887
+ 3.421216561295405
+ 3.421267674396733
+ 3.421318786445928
+ 3.4213698974430495
+ 3.421421007388156
+ 3.421472116281307
+ 3.4215232241225606
+ 3.421574330911976
+ 3.4216254366496117
+ 3.421676541335526
+ 3.4217276449697787
+ 3.4217787475524273
+ 3.4218298490835317
+ 3.42188094956315
+ 3.421932048991341
+ 3.4219831473681634
+ 3.422034244693676
+ 3.4220853409679375
+ 3.4221364361910065
+ 3.422187530362942
+ 3.4222386234838025
+ 3.4222897155536467
+ 3.4223408065725334
+ 3.4223918965405202
+ 3.4224429854576677
+ 3.422494073324033
+ 3.4225451601396752
+ 3.4225962459046535
+ 3.422647330619026
+ 3.422698414282851
+ 3.4227494968961882
+ 3.422800578459095
+ 3.4228516589716307
+ 3.4229027384338546
+ 3.4229538168458244
+ 3.4230048942075983
+ 3.423055970519236
+ 3.4231070457807955
+ 3.423158119992335
+ 3.4232091931539146
+ 3.4232602652655912
+ 3.4233113363274246
+ 3.4233624063394723
+ 3.423413475301794
+ 3.4234645432144473
+ 3.423515610077491
+ 3.4235666758909837
+ 3.423617740654984
+ 3.423668804369551
+ 3.423719867034742
+ 3.4237709286506166
+ 3.4238219892172332
+ 3.4238730487346496
+ 3.423924107202925
+ 3.423975164622118
+ 3.4240262209922863
+ 3.4240772763134895
+ 3.424128330585785
+ 3.424179383809232
+ 3.4242304359838887
+ 3.4242814871098135
+ 3.424332537187065
+ 3.4243835862157024
+ 3.424434634195783
+ 3.424485681127366
+ 3.424536727010509
+ 3.4245877718452715
+ 3.4246388156317114
+ 3.4246898583698866
+ 3.4247409000598568
+ 3.4247919407016796
+ 3.4248429802954137
+ 3.4248940188411168
+ 3.4249450563388484
+ 3.4249960927886662
+ 3.425047128190629
+ 3.4250981625447947
+ 3.425149195851222
+ 3.4252002281099694
+ 3.425251259321095
+ 3.4253022894846574
+ 3.425353318600715
+ 3.4254043466693265
+ 3.4254553736905486
+ 3.425506399664442
+ 3.4255574245910627
+ 3.425608448470471
+ 3.4256594713027244
+ 3.4257104930878812
+ 3.425761513826
+ 3.425812533517139
+ 3.425863552161356
+ 3.4259145697587097
+ 3.425965586309259
+ 3.4260166018130613
+ 3.4260676162701755
+ 3.4261186296806594
+ 3.4261696420445715
+ 3.42622065336197
+ 3.426271663632914
+ 3.4263226728574603
+ 3.4263736810356678
+ 3.4264246881675953
+ 3.4264756942533006
+ 3.4265266992928414
+ 3.426577703286277
+ 3.4266287062336653
+ 3.426679708135064
+ 3.4267307089905317
+ 3.4267817088001262
+ 3.4268327075639067
+ 3.4268837052819308
+ 3.426934701954256
+ 3.426985697580942
+ 3.427036692162046
+ 3.4270876856976265
+ 3.427138678187741
+ 3.4271896696324484
+ 3.4272406600318073
+ 3.4272916493858747
+ 3.42734263769471
+ 3.42739362495837
+ 3.427444611176914
+ 3.4274955963503992
+ 3.4275465804788845
+ 3.4275975635624283
+ 3.4276485456010874
+ 3.4276995265949206
+ 3.427750506543987
+ 3.427801485448343
+ 3.427852463308048
+ 3.4279034401231594
+ 3.427954415893736
+ 3.428005390619835
+ 3.4280563643015154
+ 3.4281073369388344
+ 3.428158308531851
+ 3.4282092790806225
+ 3.4282602485852065
+ 3.4283112170456627
+ 3.4283621844620478
+ 3.4284131508344204
+ 3.4284641161628384
+ 3.4285150804473603
+ 3.428566043688043
+ 3.4286170058849454
+ 3.4286679670381255
+ 3.4287189271476413
+ 3.4287698862135505
+ 3.4288208442359114
+ 3.4288718012147816
+ 3.42892275715022
+ 3.4289737120422834
+ 3.429024665891031
+ 3.429075618696519
+ 3.429126570458808
+ 3.429177521177954
+ 3.4292284708540146
+ 3.4292794194870497
+ 3.4293303670771156
+ 3.429381313624271
+ 3.4294322591285735
+ 3.429483203590082
+ 3.4295341470088525
+ 3.4295850893849447
+ 3.4296360307184157
+ 3.429686971009324
+ 3.4297379102577263
+ 3.4297888484636823
+ 3.4298397856272484
+ 3.4298907217484835
+ 3.429941656827444
+ 3.42999259086419
+ 3.4300435238587776
+ 3.430094455811265
+ 3.430145386721711
+ 3.4301963165901728
+ 3.430247245416708
+ 3.430298173201374
+ 3.4303490999442303
+ 3.430400025645334
+ 3.430450950304742
+ 3.430501873922513
+ 3.4305527964987057
+ 3.430603718033376
+ 3.4306546385265833
+ 3.4307055579783836
+ 3.430756476388837
+ 3.4308073937579997
+ 3.4308583100859305
+ 3.430909225372686
+ 3.430960139618325
+ 3.4310110528229045
+ 3.4310619649864833
+ 3.4311128761091187
+ 3.431163786190868
+ 3.4312146952317892
+ 3.43126560323194
+ 3.431316510191379
+ 3.431367416110163
+ 3.43141832098835
+ 3.4314692248259977
+ 3.431520127623164
+ 3.431571029379906
+ 3.431621930096283
+ 3.4316728297723507
+ 3.4317237284081683
+ 3.4317746260037922
+ 3.4318255225592815
+ 3.4318764180746926
+ 3.4319273125500844
+ 3.431978205985514
+ 3.432029098381039
+ 3.432079989736717
+ 3.432130880052606
+ 3.4321817693287637
+ 3.432232657565247
+ 3.4322835447621145
+ 3.4323344309194233
+ 3.4323853160372306
+ 3.4324362001155952
+ 3.4324870831545744
+ 3.4325379651542254
+ 3.4325888461146055
+ 3.4326397260357733
+ 3.432690604917786
+ 3.432741482760701
+ 3.4327923595645755
+ 3.4328432353294684
+ 3.432894110055436
+ 3.4329449837425368
+ 3.4329958563908276
+ 3.4330467280003663
+ 3.433097598571211
+ 3.433148468103418
+ 3.433199336597046
+ 3.433250204052152
+ 3.433301070468794
+ 3.4333519358470297
+ 3.433402800186915
+ 3.4334536634885096
+ 3.4335045257518697
+ 3.433555386977053
+ 3.4336062471641173
+ 3.4336571063131207
+ 3.433707964424119
+ 3.4337588214971713
+ 3.433809677532334
+ 3.433860532529666
+ 3.433911386489223
+ 3.4339622394110636
+ 3.4340130912952453
+ 3.434063942141825
+ 3.434114791950861
+ 3.4341656407224095
+ 3.434216488456529
+ 3.4342673351532764
+ 3.43431818081271
+ 3.434369025434886
+ 3.434419869019863
+ 3.4344707115676973
+ 3.434521553078447
+ 3.4345723935521693
+ 3.434623232988922
+ 3.4346740713887622
+ 3.4347249087517473
+ 3.434775745077934
+ 3.434826580367382
+ 3.4348774146201464
+ 3.434928247836285
+ 3.4349790800158555
+ 3.435029911158915
+ 3.4350807412655215
+ 3.4351315703357317
+ 3.4351823983696037
+ 3.4352332253671936
+ 3.4352840513285603
+ 3.4353348762537594
+ 3.43538570014285
+ 3.4354365229958885
+ 3.4354873448129317
+ 3.4355381655940382
+ 3.435588985339265
+ 3.435639804048668
+ 3.435690621722306
+ 3.4357414383602363
+ 3.4357922539625156
+ 3.435843068529201
+ 3.4358938820603506
+ 3.435944694556021
+ 3.435995506016269
+ 3.436046316441154
+ 3.4360971258307305
+ 3.436147934185058
+ 3.436198741504192
+ 3.436249547788191
+ 3.4363003530371117
+ 3.4363511572510115
+ 3.436401960429947
+ 3.4364527625739774
+ 3.436503563683157
+ 3.4365543637575455
+ 3.436605162797199
+ 3.436655960802175
+ 3.43670675777253
+ 3.4367575537083224
+ 3.4368083486096084
+ 3.436859142476445
+ 3.4369099353088908
+ 3.4369607271070017
+ 3.437011517870835
+ 3.4370623076004483
+ 3.4371130962958985
+ 3.437163883957243
+ 3.4372146705845386
+ 3.4372654561778426
+ 3.437316240737213
+ 3.437367024262705
+ 3.437417806754377
+ 3.437468588212286
+ 3.437519368636489
+ 3.437570148027043
+ 3.437620926384006
+ 3.4376717037074336
+ 3.4377224799973845
+ 3.437773255253914
+ 3.4378240294770803
+ 3.4378748026669412
+ 3.437925574823552
+ 3.437976345946971
+ 3.438027116037255
+ 3.4380778850944607
+ 3.4381286531186457
+ 3.4381794201098668
+ 3.438230186068181
+ 3.4382809509936454
+ 3.438331714886317
+ 3.438382477746253
+ 3.43843323957351
+ 3.438484000368146
+ 3.4385347601302163
+ 3.43858551885978
+ 3.438636276556892
+ 3.4386870332216106
+ 3.438737788853993
+ 3.4387885434540952
+ 3.438839297021975
+ 3.4388900495576893
+ 3.4389408010612943
+ 3.4389915515328475
+ 3.4390423009724067
+ 3.439093049380027
+ 3.439143796755767
+ 3.4391945430996826
+ 3.439245288411832
+ 3.4392960326922704
+ 3.4393467759410563
+ 3.4393975181582457
+ 3.4394482593438958
+ 3.4394989994980634
+ 3.439549738620806
+ 3.4396004767121795
+ 3.4396512137722417
+ 3.4397019498010493
+ 3.4397526847986586
+ 3.439803418765127
+ 3.439854151700511
+ 3.4399048836048682
+ 3.439955614478255
+ 3.4400063443207283
+ 3.4400570731323445
+ 3.440107800913162
+ 3.4401585276632356
+ 3.440209253382623
+ 3.440259978071382
+ 3.440310701729568
+ 3.440361424357239
+ 3.4404121459544506
+ 3.44046286652126
+ 3.440513586057725
+ 3.440564304563902
+ 3.4406150220398466
+ 3.440665738485617
+ 3.440716453901269
+ 3.4407671682868606
+ 3.4408178816424475
+ 3.4408685939680868
+ 3.4409193052638356
+ 3.44097001552975
+ 3.4410207247658873
+ 3.4410714329723047
+ 3.4411221401490573
+ 3.4411728462962032
+ 3.4412235514137994
+ 3.4412742555019014
+ 3.441324958560567
+ 3.4413756605898524
+ 3.441426361589815
+ 3.4414770615605104
+ 3.4415277605019963
+ 3.441578458414329
+ 3.441629155297565
+ 3.4416798511517612
+ 3.441730545976974
+ 3.4417812397732606
+ 3.4418319325406777
+ 3.4418826242792817
+ 3.4419333149891296
+ 3.441984004670277
+ 3.442034693322782
+ 3.4420853809467005
+ 3.4421360675420893
+ 3.442186753109005
+ 3.442237437647504
+ 3.442288121157643
+ 3.4423388036394793
+ 3.442389485093069
+ 3.4424401655184687
+ 3.442490844915735
+ 3.4425415232849246
+ 3.4425922006260943
+ 3.4426428769393
+ 3.4426935522245996
+ 3.442744226482048
+ 3.4427948997117035
+ 3.4428455719136206
+ 3.442896243087858
+ 3.4429469132344717
+ 3.4429975823535175
+ 3.4430482504450524
+ 3.443098917509133
+ 3.4431495835458157
+ 3.443200248555158
+ 3.443250912537214
+ 3.4433015754920433
+ 3.4433522374197
+ 3.4434028983202425
+ 3.4434535581937262
+ 3.4435042170402075
+ 3.443554874859743
+ 3.4436055316523895
+ 3.443656187418204
+ 3.4437068421572423
+ 3.4437574958695607
+ 3.4438081485552163
+ 3.443858800214265
+ 3.443909450846763
+ 3.443960100452769
+ 3.4440107490323366
+ 3.4440613965855236
+ 3.444112043112386
+ 3.4441626886129812
+ 3.4442133330873648
+ 3.444263976535593
+ 3.444314618957723
+ 3.4443652603538113
+ 3.4444159007239135
+ 3.444466540068086
+ 3.444517178386387
+ 3.44456781567887
+ 3.444618451945594
+ 3.4446690871866137
+ 3.4447197214019867
+ 3.4447703545917685
+ 3.4448209867560156
+ 3.4448716178947847
+ 3.4449222480081323
+ 3.4449728770961143
+ 3.445023505158788
+ 3.4450741321962086
+ 3.445124758208433
+ 3.445175383195517
+ 3.4452260071575176
+ 3.445276630094491
+ 3.4453272520064937
+ 3.4453778728935816
+ 3.445428492755811
+ 3.445479111593239
+ 3.4455297294059206
+ 3.4455803461939136
+ 3.445630961957273
+ 3.445681576696056
+ 3.4457321904103178
+ 3.445782803100116
+ 3.4458334147655063
+ 3.4458840254065453
+ 3.4459346350232885
+ 3.4459852436157927
+ 3.4460358511841145
+ 3.4460864577283092
+ 3.446137063248434
+ 3.446187667744544
+ 3.4462382712166972
+ 3.4462888736649484
+ 3.446339475089354
+ 3.446390075489971
+ 3.4464406748668543
+ 3.446491273220061
+ 3.4465418705496482
+ 3.4465924668556704
+ 3.4466430621381843
+ 3.446693656397247
+ 3.4467442496329137
+ 3.4467948418452403
+ 3.4468454330342846
+ 3.446896023200101
+ 3.446946612342747
+ 3.4469972004622775
+ 3.44704778755875
+ 3.44709837363222
+ 3.4471489586827433
+ 3.447199542710377
+ 3.4472501257151755
+ 3.447300707697197
+ 3.4473512886564963
+ 3.4474018685931305
+ 3.447452447507154
+ 3.4475030253986256
+ 3.447553602267599
+ 3.4476041781141316
+ 3.4476547529382784
+ 3.4477053267400968
+ 3.447755899519642
+ 3.4478064712769707
+ 3.4478570420121377
+ 3.447907611725201
+ 3.447958180416215
+ 3.448008748085237
+ 3.4480593147323226
+ 3.4481098803575274
+ 3.448160444960908
+ 3.44821100854252
+ 3.44826157110242
+ 3.4483121326406634
+ 3.448362693157307
+ 3.4484132526524056
+ 3.448463811126017
+ 3.448514368578196
+ 3.4485649250089985
+ 3.448615480418481
+ 3.4486660348066995
+ 3.448716588173709
+ 3.4487671405195672
+ 3.448817691844329
+ 3.4488682421480505
+ 3.448918791430788
+ 3.448969339692597
+ 3.4490198869335336
+ 3.449070433153654
+ 3.4491209783530143
+ 3.44917152253167
+ 3.4492220656896775
+ 3.4492726078270914
+ 3.44932314894397
+ 3.449373689040367
+ 3.4494242281163396
+ 3.449474766171943
+ 3.449525303207234
+ 3.4495758392222675
+ 3.4496263742171003
+ 3.4496769081917877
+ 3.449727441146386
+ 3.4497779730809506
+ 3.449828503995538
+ 3.4498790338902032
+ 3.4499295627650026
+ 3.4499800906199924
+ 3.450030617455228
+ 3.4500811432707663
+ 3.4501316680666614
+ 3.45018219184297
+ 3.450232714599748
+ 3.450283236337051
+ 3.4503337570549353
+ 3.4503842767534567
+ 3.4504347954326704
+ 3.4504853130926327
+ 3.4505358297333992
+ 3.4505863453550263
+ 3.450636859957569
+ 3.4506873735410837
+ 3.4507378861056255
+ 3.4507883976512512
+ 3.4508389081780155
+ 3.450889417685975
+ 3.4509399261751845
+ 3.450990433645701
+ 3.45104094009758
+ 3.4510914455308765
+ 3.451141949945647
+ 3.4511924533419465
+ 3.451242955719832
+ 3.4512934570793576
+ 3.45134395742058
+ 3.4513944567435555
+ 3.4514449550483386
+ 3.4514954523349854
+ 3.451545948603552
+ 3.4515964438540943
+ 3.4516469380866672
+ 3.451697431301327
+ 3.451747923498129
+ 3.451798414677129
+ 3.4518489048383825
+ 3.4518993939819462
+ 3.4519498821078742
+ 3.452000369216224
+ 3.4520508553070495
+ 3.4521013403804073
+ 3.4521518244363527
+ 3.4522023074749417
+ 3.45225278949623
+ 3.452303270500273
+ 3.452353750487126
+ 3.4524042294568456
+ 3.4524547074094856
+ 3.452505184345104
+ 3.452555660263754
+ 3.4526061351654938
+ 3.452656609050377
+ 3.45270708191846
+ 3.452757553769798
+ 3.4528080246044475
+ 3.4528584944224634
+ 3.4529089632239005
+ 3.4529594310088156
+ 3.453009897777264
+ 3.453060363529301
+ 3.453110828264982
+ 3.4531612919843635
+ 3.4532117546875
+ 3.4532622163744473
+ 3.4533126770452616
+ 3.4533631366999975
+ 3.453413595338711
+ 3.453464052961458
+ 3.453514509568293
+ 3.4535649651592726
+ 3.4536154197344517
+ 3.4536658732938856
+ 3.45371632583763
+ 3.453766777365742
+ 3.4538172278782744
+ 3.4538676773752837
+ 3.4539181258568266
+ 3.4539685733229564
+ 3.454019019773731
+ 3.4540694652092037
+ 3.4541199096294313
+ 3.4541703530344683
+ 3.4542207954243715
+ 3.454271236799195
+ 3.454321677158995
+ 3.4543721165038264
+ 3.454422554833745
+ 3.4544729921488067
+ 3.454523428449066
+ 3.454573863734579
+ 3.4546242980054003
+ 3.454674731261586
+ 3.4547251635031917
+ 3.4547755947302727
+ 3.454826024942883
+ 3.4548764541410804
+ 3.454926882324918
+ 3.454977309494453
+ 3.455027735649739
+ 3.4550781607908334
+ 3.45512858491779
+ 3.455179008030665
+ 3.455229430129513
+ 3.45527985121439
+ 3.4553302712853506
+ 3.455380690342451
+ 3.455431108385746
+ 3.455481525415292
+ 3.455531941431142
+ 3.4555823564333537
+ 3.455632770421981
+ 3.4556831833970802
+ 3.455733595358706
+ 3.455784006306913
+ 3.4558344162417582
+ 3.4558848251632956
+ 3.455935233071581
+ 3.455985639966669
+ 3.4560360458486157
+ 3.456086450717476
+ 3.4561368545733053
+ 3.456187257416159
+ 3.456237659246092
+ 3.4562880600631596
+ 3.456338459867417
+ 3.45638885865892
+ 3.4564392564377235
+ 3.4564896532038825
+ 3.4565400489574523
+ 3.456590443698488
+ 3.456640837427045
+ 3.4566912301431794
+ 3.4567416218469442
+ 3.456792012538397
+ 3.4568424022175916
+ 3.456892790884584
+ 3.4569431785394276
+ 3.45699356518218
+ 3.457043950812895
+ 3.457094335431628
+ 3.457144719038434
+ 3.457195101633369
+ 3.4572454832164867
+ 3.4572958637878437
+ 3.4573462433474944
+ 3.457396621895494
+ 3.4574469994318977
+ 3.4574973759567604
+ 3.457547751470138
+ 3.4575981259720847
+ 3.457648499462656
+ 3.4576988719419073
+ 3.4577492434098933
+ 3.4577996138666696
+ 3.45784998331229
+ 3.457900351746811
+ 3.4579507191702876
+ 3.458001085582774
+ 3.458051450984326
+ 3.4581018153749987
+ 3.4581521787548466
+ 3.458202541123925
+ 3.4582529024822892
+ 3.458303262829994
+ 3.458353622167095
+ 3.458403980493646
+ 3.4584543378097035
+ 3.4585046941153217
+ 3.4585550494105552
+ 3.4586054036954605
+ 3.4586557569700913
+ 3.458706109234503
+ 3.458756460488751
+ 3.4588068107328898
+ 3.458857159966974
+ 3.4589075081910603
+ 3.4589578554052016
+ 3.4590082016094543
+ 3.4590585468038726
+ 3.4591088909885124
+ 3.4591592341634274
+ 3.4592095763286737
+ 3.4592599174843057
+ 3.4593102576303782
+ 3.4593605967669467
+ 3.459410934894066
+ 3.459461272011791
+ 3.4595116081201756
+ 3.4595619432192763
+ 3.4596122773091476
+ 3.459662610389844
+ 3.45971294246142
+ 3.4597632735239325
+ 3.459813603577434
+ 3.459863932621981
+ 3.4599142606576274
+ 3.459964587684429
+ 3.4600149137024396
+ 3.4600652387117155
+ 3.46011556271231
+ 3.4601658857042796
+ 3.4602162076876777
+ 3.4602665286625602
+ 3.4603168486289815
+ 3.460367167586996
+ 3.46041748553666
+ 3.460467802478027
+ 3.460518118411152
+ 3.46056843333609
+ 3.460618747252896
+ 3.4606690601616252
+ 3.460719372062332
+ 3.4607696829550703
+ 3.460819992839897
+ 3.4608703017168647
+ 3.46092060958603
+ 3.4609709164474456
+ 3.461021222301169
+ 3.461071527147253
+ 3.4611218309857525
+ 3.4611721338167234
+ 3.4612224356402197
+ 3.4612727364562956
+ 3.461323036265007
+ 3.4613733350664084
+ 3.461423632860554
+ 3.4614739296474997
+ 3.4615242254272984
+ 3.4615745202000063
+ 3.4616248139656776
+ 3.461675106724367
+ 3.46172539847613
+ 3.46177568922102
+ 3.461825978959092
+ 3.461876267690402
+ 3.461926555415003
+ 3.4619768421329513
+ 3.4620271278443
+ 3.462077412549105
+ 3.462127696247421
+ 3.4621779789393012
+ 3.462228260624802
+ 3.462278541303977
+ 3.4623288209768814
+ 3.4623790996435697
+ 3.4624293773040966
+ 3.4624796539585168
+ 3.4625299296068848
+ 3.4625802042492553
+ 3.462630477885683
+ 3.4626807505162223
+ 3.462731022140928
+ 3.4627812927598547
+ 3.462831562373057
+ 3.4628818309805895
+ 3.462932098582507
+ 3.462982365178864
+ 3.4630326307697152
+ 3.4630828953551145
+ 3.463133158935117
+ 3.4631834215097776
+ 3.463233683079151
+ 3.4632839436432907
+ 3.463334203202252
+ 3.46338446175609
+ 3.463434719304858
+ 3.463484975848611
+ 3.463535231387404
+ 3.463585485921292
+ 3.4636357394503277
+ 3.4636859919745673
+ 3.463736243494065
+ 3.463786494008875
+ 3.4638367435190514
+ 3.46388699202465
+ 3.463937239525724
+ 3.4639874860223285
+ 3.4640377315145185
+ 3.4640879760023475
+ 3.4641382194858705
+ 3.464188461965142
+ 3.4642387034402167
+ 3.4642889439111486
+ 3.464339183377992
+ 3.464389421840802
+ 3.464439659299633
+ 3.4644898957545394
+ 3.464540131205575
+ 3.4645903656527945
+ 3.464640599096253
+ 3.4646908315360045
+ 3.464741062972104
+ 3.4647912934046046
+ 3.464841522833562
+ 3.46489175125903
+ 3.4649419786810634
+ 3.464992205099716
+ 3.4650424305150427
+ 3.4650926549270977
+ 3.4651428783359357
+ 3.465193100741611
+ 3.4652433221441767
+ 3.465293542543689
+ 3.4653437619402014
+ 3.465393980333769
+ 3.465444197724445
+ 3.465494414112285
+ 3.465544629497342
+ 3.4655948438796718
+ 3.465645057259328
+ 3.4656952696363645
+ 3.4657454810108366
+ 3.4657956913827976
+ 3.465845900752303
+ 3.465896109119406
+ 3.4659463164841613
+ 3.465996522846624
+ 3.4660467282068477
+ 3.466096932564886
+ 3.4661471359207945
+ 3.4661973382746263
+ 3.466247539626437
+ 3.4662977399762798
+ 3.46634793932421
+ 3.4663981376702804
+ 3.4664483350145465
+ 3.466498531357062
+ 3.4665487266978814
+ 3.4665989210370594
+ 3.466649114374649
+ 3.4666993067107055
+ 3.4667494980452833
+ 3.466799688378436
+ 3.4668498777102177
+ 3.466900066040683
+ 3.466950253369886
+ 3.4670004396978813
+ 3.467050625024722
+ 3.467100809350464
+ 3.46715099267516
+ 3.4672011749988654
+ 3.467251356321633
+ 3.467301536643519
+ 3.4673517159645746
+ 3.467401894284857
+ 3.467452071604419
+ 3.467502247923315
+ 3.467552423241598
+ 3.4676025975593245
+ 3.4676527708765463
+ 3.467702943193319
+ 3.467753114509696
+ 3.4678032848257327
+ 3.4678534541414816
+ 3.4679036224569977
+ 3.4679537897723356
+ 3.468003956087548
+ 3.4680541214026905
+ 3.4681042857178155
+ 3.468154449032979
+ 3.468204611348234
+ 3.468254772663635
+ 3.4683049329792355
+ 3.46835509229509
+ 3.468405250611253
+ 3.468455407927778
+ 3.4685055642447193
+ 3.468555719562131
+ 3.4686058738800667
+ 3.4686560271985813
+ 3.468706179517728
+ 3.4687563308375617
+ 3.4688064811581354
+ 3.4688566304795043
+ 3.4689067788017214
+ 3.468956926124841
+ 3.469007072448919
+ 3.4690572177740058
+ 3.4691073621001585
+ 3.4691575054274293
+ 3.4692076477558733
+ 3.4692577890855434
+ 3.469307929416495
+ 3.469358068748781
+ 3.4694082070824557
+ 3.4694583444175735
+ 3.469508480754188
+ 3.4695586160923524
+ 3.4696087504321222
+ 3.4696588837735507
+ 3.469709016116692
+ 3.469759147461599
+ 3.4698092778083267
+ 3.4698594071569295
+ 3.46990953550746
+ 3.469959662859973
+ 3.4700097892145223
+ 3.4700599145711615
+ 3.4701100389299446
+ 3.4701601622909264
+ 3.4702102846541596
+ 3.470260406019699
+ 3.4703105263875975
+ 3.47036064575791
+ 3.47041076413069
+ 3.4704608815059914
+ 3.470510997883868
+ 3.4705611132643743
+ 3.470611227647563
+ 3.4706613410334883
+ 3.470711453422205
+ 3.4707615648137664
+ 3.4708116752082256
+ 3.4708617846056375
+ 3.470911893006056
+ 3.470962000409534
+ 3.471012106816126
+ 3.471062212225885
+ 3.471112316638867
+ 3.471162420055123
+ 3.471212522474709
+ 3.4712626238976774
+ 3.4713127243240827
+ 3.4713628237539784
+ 3.4714129221874184
+ 3.4714630196244567
+ 3.471513116065147
+ 3.471563211509543
+ 3.471613305957699
+ 3.4716633994096675
+ 3.4717134918655033
+ 3.4717635833252602
+ 3.471813673788991
+ 3.4718637632567506
+ 3.471913851728592
+ 3.4719639392045694
+ 3.4720140256847367
+ 3.472064111169147
+ 3.472114195657854
+ 3.4721642791509124
+ 3.4722143616483745
+ 3.4722644431502956
+ 3.4723145236567277
+ 3.472364603167726
+ 3.4724146816833437
+ 3.472464759203634
+ 3.472514835728651
+ 3.472564911258449
+ 3.472614985793081
+ 3.4726650593326
+ 3.4727151318770613
+ 3.472765203426517
+ 3.472815273981022
+ 3.472865343540629
+ 3.4729154121053925
+ 3.472965479675365
+ 3.473015546250602
+ 3.4730656118311547
+ 3.473115676417079
+ 3.4731657400084277
+ 3.4732158026052535
+ 3.4732658642076113
+ 3.4733159248155543
+ 3.4733659844291362
+ 3.4734160430484105
+ 3.47346610067343
+ 3.47351615730425
+ 3.4735662129409226
+ 3.4736162675835023
+ 3.4736663212320424
+ 3.473716373886596
+ 3.473766425547218
+ 3.47381647621396
+ 3.4738665258868773
+ 3.4739165745660223
+ 3.47396662225145
+ 3.4740166689432117
+ 3.474066714641363
+ 3.4741167593459563
+ 3.4741668030570465
+ 3.4742168457746847
+ 3.4742668874989273
+ 3.474316928229826
+ 3.4743669679674345
+ 3.474417006711806
+ 3.4744670444629957
+ 3.4745170812210557
+ 3.4745671169860395
+ 3.474617151758001
+ 3.4746671855369935
+ 3.474717218323071
+ 3.4747672501162854
+ 3.474817280916692
+ 3.4748673107243437
+ 3.474917339539293
+ 3.4749673673615953
+ 3.4750173941913025
+ 3.4750674200284686
+ 3.475117444873147
+ 3.4751674687253913
+ 3.475217491585254
+ 3.4752675134527897
+ 3.4753175343280516
+ 3.4753675542110933
+ 3.4754175731019665
+ 3.475467591000727
+ 3.475517607907427
+ 3.47556762382212
+ 3.47561763874486
+ 3.4756676526756993
+ 3.4757176656146918
+ 3.4757676775618913
+ 3.4758176885173504
+ 3.4758676984811236
+ 3.4759177074532634
+ 3.475967715433823
+ 3.4760177224228563
+ 3.4760677284204164
+ 3.476117733426557
+ 3.4761677374413313
+ 3.4762177404647923
+ 3.4762677424969937
+ 3.476317743537989
+ 3.47636774358783
+ 3.4764177426465728
+ 3.4764677407142686
+ 3.476517737790971
+ 3.476567733876734
+ 3.4766177289716103
+ 3.4766677230756535
+ 3.476717716188917
+ 3.4767677083114537
+ 3.476817699443317
+ 3.476867689584561
+ 3.4769176787352376
+ 3.476967666895401
+ 3.477017654065104
+ 3.4770676402444005
+ 3.477117625433343
+ 3.4771676096319855
+ 3.4772175928403803
+ 3.477267575058582
+ 3.4773175562866423
+ 3.4773675365246155
+ 3.477417515772555
+ 3.477467494030513
+ 3.477517471298543
+ 3.477567447576699
+ 3.4776174228650336
+ 3.4776673971636
+ 3.477717370472451
+ 3.4777673427916413
+ 3.4778173141212227
+ 3.4778672844612486
+ 3.4779172538117726
+ 3.477967222172848
+ 3.478017189544527
+ 3.478067155926864
+ 3.478117121319911
+ 3.4781670857237224
+ 3.4782170491383506
+ 3.4782670115638488
+ 3.47831697300027
+ 3.4783669334476675
+ 3.478416892906095
+ 3.4784668513756047
+ 3.4785168088562504
+ 3.4785667653480847
+ 3.4786167208511616
+ 3.478666675365533
+ 3.478716628891253
+ 3.4787665814283737
+ 3.47881653297695
+ 3.478866483537033
+ 3.478916433108677
+ 3.4789663816919347
+ 3.4790163292868588
+ 3.479066275893503
+ 3.4791162215119202
+ 3.4791661661421642
+ 3.479216109784286
+ 3.479266052438341
+ 3.4793159941043807
+ 3.479365934782459
+ 3.4794158744726285
+ 3.479465813174942
+ 3.479515750889453
+ 3.479565687616215
+ 3.47961562335528
+ 3.4796655581067015
+ 3.479715491870533
+ 3.479765424646826
+ 3.479815356435635
+ 3.4798652872370126
+ 3.479915217051012
+ 3.4799651458776855
+ 3.4800150737170865
+ 3.4800650005692684
+ 3.4801149264342843
+ 3.4801648513121854
+ 3.480214775203027
+ 3.4802646981068603
+ 3.4803146200237394
+ 3.4803645409537163
+ 3.4804144608968444
+ 3.4804643798531774
+ 3.4805142978227672
+ 3.4805642148056672
+ 3.4806141308019303
+ 3.4806640458116087
+ 3.480713959834757
+ 3.4807638728714267
+ 3.480813784921671
+ 3.4808636959855432
+ 3.4809136060630963
+ 3.4809635151543823
+ 3.4810134232594545
+ 3.4810633303783667
+ 3.4811132365111703
+ 3.481163141657919
+ 3.481213045818666
+ 3.481262948993464
+ 3.481312851182365
+ 3.481362752385423
+ 3.4814126526026903
+ 3.4814625518342197
+ 3.481512450080064
+ 3.481562347340277
+ 3.4816122436149093
+ 3.4816621389040168
+ 3.48171203320765
+ 3.4817619265258624
+ 3.481811818858707
+ 3.481861710206237
+ 3.481911600568504
+ 3.481961489945562
+ 3.482011378337463
+ 3.4820612657442607
+ 3.4821111521660075
+ 3.482161037602755
+ 3.482210922054558
+ 3.482260805521468
+ 3.482310688003538
+ 3.4823605695008206
+ 3.4824104500133695
+ 3.482460329541236
+ 3.4825102080844745
+ 3.4825600856431365
+ 3.4826099622172753
+ 3.4826598378069433
+ 3.482709712412193
+ 3.4827595860330782
+ 3.482809458669651
+ 3.482859330321965
+ 3.4829092009900706
+ 3.4829590706740228
+ 3.4830089393738732
+ 3.483058807089675
+ 3.4831086738214805
+ 3.483158539569343
+ 3.483208404333314
+ 3.4832582681134476
+ 3.483308130909796
+ 3.4833579927224116
+ 3.483407853551347
+ 3.4834577133966556
+ 3.483507572258389
+ 3.4835574301366012
+ 3.4836072870313433
+ 3.483657142942669
+ 3.4837069978706308
+ 3.4837568518152815
+ 3.4838067047766734
+ 3.483856556754859
+ 3.483906407749892
+ 3.483956257761823
+ 3.484006106790706
+ 3.484055954836594
+ 3.484105801899539
+ 3.4841556479795925
+ 3.4842054930768094
+ 3.484255337191241
+ 3.4843051803229397
+ 3.4843550224719584
+ 3.4844048636383502
+ 3.4844547038221667
+ 3.4845045430234616
+ 3.4845543812422863
+ 3.484604218478694
+ 3.4846540547327374
+ 3.4847038900044685
+ 3.4847537242939404
+ 3.484803557601205
+ 3.484853389926316
+ 3.4849032212693243
+ 3.484953051630284
+ 3.485002881009247
+ 3.4850527094062658
+ 3.4851025368213926
+ 3.4851523632546804
+ 3.4852021887061815
+ 3.4852520131759483
+ 3.4853018366640334
+ 3.4853516591704894
+ 3.4854014806953693
+ 3.4854513012387245
+ 3.485501120800608
+ 3.485550939381073
+ 3.4856007569801704
+ 3.485650573597954
+ 3.485700389234476
+ 3.485750203889788
+ 3.4858000175639434
+ 3.4858498302569942
+ 3.4858996419689934
+ 3.485949452699993
+ 3.4859992624500453
+ 3.486049071219203
+ 3.486098879007519
+ 3.4861486858150443
+ 3.4861984916418325
+ 3.4862482964879358
+ 3.486298100353407
+ 3.4863479032382974
+ 3.4863977051426605
+ 3.4864475060665474
+ 3.4864973060100124
+ 3.486547104973106
+ 3.4865969029558816
+ 3.486646699958392
+ 3.4866964959806888
+ 3.486746291022824
+ 3.4867960850848507
+ 3.4868458781668212
+ 3.486895670268787
+ 3.486945461390802
+ 3.486995251532918
+ 3.487045040695186
+ 3.4870948288776598
+ 3.487144616080392
+ 3.4871944023034334
+ 3.487244187546837
+ 3.4872939718106557
+ 3.4873437550949418
+ 3.4873935373997464
+ 3.487443318725123
+ 3.487493099071124
+ 3.487542878437801
+ 3.487592656825206
+ 3.4876424342333925
+ 3.487692210662411
+ 3.4877419861123156
+ 3.487791760583158
+ 3.48784153407499
+ 3.4878913065878647
+ 3.487941078121833
+ 3.4879908486769486
+ 3.4880406182532626
+ 3.488090386850828
+ 3.4881401544696966
+ 3.4881899211099214
+ 3.488239686771554
+ 3.488289451454647
+ 3.4883392151592516
+ 3.488388977885421
+ 3.488438739633207
+ 3.4884885004026622
+ 3.488538260193839
+ 3.488588019006789
+ 3.488637776841564
+ 3.4886875336982173
+ 3.4887372895768007
+ 3.4887870444773657
+ 3.4888367983999657
+ 3.4888865513446516
+ 3.488936303311477
+ 3.4889860543004922
+ 3.4890358043117513
+ 3.489085553345305
+ 3.4891353014012063
+ 3.4891850484795066
+ 3.489234794580259
+ 3.4892845397035144
+ 3.4893342838493266
+ 3.489384027017747
+ 3.4894337692088264
+ 3.4894835104226187
+ 3.489533250659175
+ 3.4895829899185484
+ 3.4896327282007897
+ 3.489682465505952
+ 3.489732201834087
+ 3.489781937185247
+ 3.4898316715594837
+ 3.4898814049568494
+ 3.489931137377396
+ 3.4899808688211764
+ 3.4900305992882417
+ 3.4900803287786446
+ 3.4901300572924363
+ 3.49017978482967
+ 3.490229511390397
+ 3.4902792369746694
+ 3.4903289615825397
+ 3.4903786852140595
+ 3.4904284078692807
+ 3.490478129548255
+ 3.4905278502510364
+ 3.490577569977675
+ 3.490627288728223
+ 3.4906770065027324
+ 3.4907267233012567
+ 3.4907764391238456
+ 3.490826153970553
+ 3.49087586784143
+ 3.4909255807365285
+ 3.4909752926559006
+ 3.491025003599599
+ 3.4910747135676745
+ 3.49112442256018
+ 3.4911741305771664
+ 3.4912238376186866
+ 3.491273543684793
+ 3.491323248775536
+ 3.4913729528909694
+ 3.4914226560311437
+ 3.4914723581961113
+ 3.4915220593859235
+ 3.491571759600634
+ 3.4916214588402927
+ 3.491671157104953
+ 3.4917208543946656
+ 3.4917705507094836
+ 3.4918202460494583
+ 3.491869940414641
+ 3.491919633805085
+ 3.491969326220841
+ 3.492019017661961
+ 3.4920687081284982
+ 3.4921183976205024
+ 3.4921680861380273
+ 3.492217773681124
+ 3.492267460249844
+ 3.49231714584424
+ 3.4923668304643636
+ 3.492416514110266
+ 3.4924661967819994
+ 3.492515878479616
+ 3.4925655592031672
+ 3.4926152389527054
+ 3.492664917728282
+ 3.4927145955299483
+ 3.4927642723577574
+ 3.4928139482117606
+ 3.492863623092009
+ 3.4929132969985552
+ 3.49296296993145
+ 3.493012641890747
+ 3.4930623128764964
+ 3.4931119828887507
+ 3.493161651927562
+ 3.493211319992981
+ 3.49326098708506
+ 3.4933106532038507
+ 3.4933603183494055
+ 3.4934099825217757
+ 3.4934596457210128
+ 3.493509307947169
+ 3.4935589692002957
+ 3.4936086294804443
+ 3.493658288787668
+ 3.493707947122017
+ 3.4937576044835437
+ 3.493807260872299
+ 3.493856916288337
+ 3.493906570731706
+ 3.4939562242024604
+ 3.494005876700651
+ 3.4940555282263293
+ 3.4941051787795474
+ 3.4941548283603563
+ 3.4942044769688088
+ 3.494254124604955
+ 3.4943037712688487
+ 3.4943534169605397
+ 3.4944030616800807
+ 3.494452705427523
+ 3.4945023482029183
+ 3.4945519900063178
+ 3.4946016308377748
+ 3.4946512706973385
+ 3.4947009095850623
+ 3.4947505475009977
+ 3.494800184445196
+ 3.4948498204177083
+ 3.4948994554185875
+ 3.494949089447884
+ 3.4949987225056502
+ 3.4950483545919373
+ 3.4950979857067965
+ 3.495147615850281
+ 3.4951972450224407
+ 3.495246873223328
+ 3.4952965004529943
+ 3.495346126711491
+ 3.4953957519988705
+ 3.4954453763151836
+ 3.4954949996604814
+ 3.495544622034817
+ 3.4955942434382408
+ 3.4956438638708045
+ 3.49569348333256
+ 3.4957431018235585
+ 3.495792719343852
+ 3.495842335893492
+ 3.495891951472529
+ 3.4959415660810156
+ 3.4959911797190037
+ 3.4960407923865433
+ 3.496090404083687
+ 3.4961400148104866
+ 3.496189624566993
+ 3.4962392333532573
+ 3.496288841169332
+ 3.496338448015268
+ 3.4963880538911174
+ 3.4964376587969306
+ 3.49648726273276
+ 3.4965368656986566
+ 3.496586467694673
+ 3.496636068720859
+ 3.4966856687772667
+ 3.4967352678639476
+ 3.4967848659809535
+ 3.496834463128336
+ 3.496884059306146
+ 3.496933654514434
+ 3.4969832487532537
+ 3.497032842022655
+ 3.4970824343226896
+ 3.4971320256534093
+ 3.4971816160148648
+ 3.4972312054071084
+ 3.4972807938301904
+ 3.497330381284164
+ 3.4973799677690787
+ 3.497429553284987
+ 3.49747913783194
+ 3.4975287214099886
+ 3.497578304019185
+ 3.497627885659581
+ 3.497677466331226
+ 3.497727046034173
+ 3.497776624768473
+ 3.4978262025341773
+ 3.4978757793313378
+ 3.497925355160005
+ 3.4979749300202307
+ 3.4980245039120654
+ 3.4980740768355623
+ 3.498123648790771
+ 3.498173219777744
+ 3.4982227897965315
+ 3.498272358847186
+ 3.4983219269297576
+ 3.4983714940442985
+ 3.49842106019086
+ 3.498470625369493
+ 3.4985201895802485
+ 3.498569752823179
+ 3.498619315098335
+ 3.498668876405768
+ 3.498718436745529
+ 3.498767996117669
+ 3.4988175545222404
+ 3.4988671119592927
+ 3.4989166684288797
+ 3.49896622393105
+ 3.4990157784658567
+ 3.4990653320333505
+ 3.499114884633582
+ 3.4991644362666037
+ 3.4992139869324657
+ 3.4992635366312195
+ 3.499313085362917
+ 3.4993626331276086
+ 3.499412179925346
+ 3.4994617257561806
+ 3.499511270620163
+ 3.4995608145173454
+ 3.4996103574477773
+ 3.4996598994115113
+ 3.499709440408598
+ 3.4997589804390894
+ 3.4998085195030355
+ 3.499858057600489
+ 3.499907594731499
+ 3.499957130896119
+ 3.500006666094398
+ 3.500056200326389
+ 3.5001057335921413
+ 3.500155265891708
+ 3.5002047972251393
+ 3.500254327592486
+ 3.5003038569937996
+ 3.5003533854291318
+ 3.500402912898533
+ 3.5004524394020544
+ 3.5005019649397475
+ 3.500551489511663
+ 3.500601013117852
+ 3.500650535758366
+ 3.500700057433256
+ 3.5007495781425733
+ 3.500799097886368
+ 3.5008486166646926
+ 3.5008981344775973
+ 3.5009476513251334
+ 3.500997167207352
+ 3.5010466821243043
+ 3.501096196076041
+ 3.5011457090626137
+ 3.5011952210840724
+ 3.5012447321404694
+ 3.5012942422318556
+ 3.5013437513582817
+ 3.5013932595197987
+ 3.501442766716458
+ 3.501492272948309
+ 3.5015417782154055
+ 3.5015912825177966
+ 3.501640785855534
+ 3.5016902882286685
+ 3.5017397896372513
+ 3.501789290081333
+ 3.501838789560965
+ 3.5018882880761986
+ 3.5019377856270837
+ 3.501987282213672
+ 3.502036777836015
+ 3.502086272494163
+ 3.5021357661881676
+ 3.5021852589180784
+ 3.5022347506839484
+ 3.502284241485827
+ 3.5023337313237652
+ 3.5023832201978147
+ 3.502432708108026
+ 3.502482195054451
+ 3.502531681037139
+ 3.502581166056142
+ 3.5026306501115103
+ 3.5026801332032957
+ 3.5027296153315484
+ 3.5027790964963197
+ 3.502828576697661
+ 3.502878055935622
+ 3.502927534210254
+ 3.5029770115216086
+ 3.503026487869736
+ 3.5030759632546875
+ 3.5031254376765135
+ 3.503174911135266
+ 3.5032243836309944
+ 3.5032738551637506
+ 3.5033233257335854
+ 3.5033727953405487
+ 3.5034222639846933
+ 3.5034717316660675
+ 3.5035211983847243
+ 3.503570664140714
+ 3.5036201289340867
+ 3.5036695927648935
+ 3.503719055633186
+ 3.5037685175390143
+ 3.50381797848243
+ 3.503867438463483
+ 3.5039168974822243
+ 3.503966355538705
+ 3.5040158126329763
+ 3.504065268765088
+ 3.504114723935092
+ 3.5041641781430384
+ 3.504213631388978
+ 3.504263083672962
+ 3.504312534995041
+ 3.504361985355265
+ 3.504411434753686
+ 3.504460883190355
+ 3.5045103306653207
+ 3.504559777178636
+ 3.504609222730351
+ 3.5046586673205162
+ 3.504708110949182
+ 3.5047575536164
+ 3.504806995322221
+ 3.504856436066695
+ 3.5049058758498726
+ 3.5049553146718053
+ 3.5050047525325434
+ 3.505054189432138
+ 3.50510362537064
+ 3.505153060348099
+ 3.5052024943645663
+ 3.505251927420093
+ 3.505301359514729
+ 3.505350790648526
+ 3.5054002208215342
+ 3.5054496500338033
+ 3.505499078285386
+ 3.5055485055763316
+ 3.5055979319066912
+ 3.505647357276515
+ 3.5056967816858546
+ 3.505746205134759
+ 3.5057956276232813
+ 3.50584504915147
+ 3.505894469719377
+ 3.5059438893270514
+ 3.505993307974546
+ 3.5060427256619104
+ 3.5060921423891944
+ 3.50614155815645
+ 3.506190972963727
+ 3.5062403868110765
+ 3.5062897996985485
+ 3.506339211626194
+ 3.5063886225940637
+ 3.506438032602208
+ 3.5064874416506773
+ 3.5065368497395237
+ 3.506586256868795
+ 3.5066356630385442
+ 3.506685068248821
+ 3.5067344724996756
+ 3.506783875791159
+ 3.506833278123322
+ 3.5068826794962145
+ 3.5069320799098875
+ 3.506981479364392
+ 3.5070308778597776
+ 3.5070802753960955
+ 3.507129671973396
+ 3.5071790675917294
+ 3.5072284622511463
+ 3.507277855951698
+ 3.507327248693434
+ 3.5073766404764055
+ 3.5074260313006627
+ 3.507475421166256
+ 3.507524810073236
+ 3.5075741980216537
+ 3.5076235850115585
+ 3.5076729710430024
+ 3.5077223561160342
+ 3.5077717402307056
+ 3.5078211233870666
+ 3.507870505585168
+ 3.5079198868250603
+ 3.5079692671067932
+ 3.5080186464304184
+ 3.508068024795985
+ 3.508117402203544
+ 3.508166778653146
+ 3.5082161541448413
+ 3.5082655286786806
+ 3.5083149022547144
+ 3.5083642748729926
+ 3.508413646533566
+ 3.508463017236484
+ 3.508512386981799
+ 3.50856175576956
+ 3.5086111235998185
+ 3.508660490472623
+ 3.5087098563880263
+ 3.5087592213460765
+ 3.5088085853468254
+ 3.508857948390323
+ 3.5089073104766197
+ 3.5089566716057665
+ 3.5090060317778127
+ 3.5090553909928093
+ 3.509104749250806
+ 3.509154106551854
+ 3.5092034628960036
+ 3.5092528182833047
+ 3.5093021727138076
+ 3.5093515261875634
+ 3.5094008787046214
+ 3.5094502302650326
+ 3.509499580868847
+ 3.509548930516116
+ 3.509598279206888
+ 3.509647626941215
+ 3.509696973719146
+ 3.509746319540733
+ 3.5097956644060244
+ 3.5098450083150716
+ 3.509894351267925
+ 3.509943693264634
+ 3.50999303430525
+ 3.510042374389822
+ 3.5100917135184018
+ 3.5101410516910385
+ 3.510190388907783
+ 3.5102397251686845
+ 3.5102890604737955
+ 3.510338394823164
+ 3.510387728216841
+ 3.510437060654877
+ 3.5104863921373224
+ 3.5105357226642266
+ 3.510585052235641
+ 3.5106343808516147
+ 3.510683708512199
+ 3.510733035217443
+ 3.5107823609673976
+ 3.510831685762113
+ 3.510881009601639
+ 3.510930332486027
+ 3.5109796544153253
+ 3.511028975389585
+ 3.5110782954088573
+ 3.5111276144731907
+ 3.5111769325826367
+ 3.511226249737245
+ 3.511275565937065
+ 3.5113248811821487
+ 3.5113741954725444
+ 3.5114235088083032
+ 3.511472821189475
+ 3.51152213261611
+ 3.5115714430882585
+ 3.5116207526059706
+ 3.511670061169296
+ 3.5117193687782855
+ 3.511768675432989
+ 3.5118179811334564
+ 3.5118672858797386
+ 3.511916589671884
+ 3.5119658925099446
+ 3.5120151943939697
+ 3.51206449532401
+ 3.512113795300114
+ 3.512163094322333
+ 3.512212392390717
+ 3.512261689505317
+ 3.512310985666181
+ 3.5123602808733607
+ 3.5124095751269055
+ 3.512458868426866
+ 3.5125081607732915
+ 3.5125574521662326
+ 3.5126067426057395
+ 3.512656032091862
+ 3.51270532062465
+ 3.5127546082041534
+ 3.512803894830423
+ 3.5128531805035075
+ 3.512902465223459
+ 3.5129517489903255
+ 3.5130010318041585
+ 3.513050313665007
+ 3.5130995945729215
+ 3.5131488745279515
+ 3.513198153530148
+ 3.5132474315795603
+ 3.5132967086762386
+ 3.5133459848202326
+ 3.513395260011593
+ 3.513444534250369
+ 3.513493807536611
+ 3.5135430798703684
+ 3.513592351251692
+ 3.513641621680631
+ 3.5136908911572364
+ 3.513740159681557
+ 3.513789427253644
+ 3.5138386938735464
+ 3.513887959541314
+ 3.5139372242569973
+ 3.513986488020646
+ 3.5140357508323103
+ 3.51408501269204
+ 3.514134273599885
+ 3.514183533555895
+ 3.5142327925601204
+ 3.5142820506126102
+ 3.514331307713416
+ 3.5143805638625856
+ 3.5144298190601706
+ 3.51447907330622
+ 3.514528326600784
+ 3.5145775789439124
+ 3.5146268303356547
+ 3.514676080776062
+ 3.5147253302651826
+ 3.5147745788030678
+ 3.5148238263897666
+ 3.514873073025329
+ 3.5149223187098046
+ 3.514971563443244
+ 3.5150208072256963
+ 3.515070050057212
+ 3.5151192919378405
+ 3.515168532867632
+ 3.515217772846636
+ 3.5152670118749016
+ 3.515316249952481
+ 3.515365487079421
+ 3.5154147232557738
+ 3.5154639584815874
+ 3.5155131927569134
+ 3.5155624260818
+ 3.5156116584562986
+ 3.5156608898804573
+ 3.5157101203543273
+ 3.515759349877957
+ 3.5158085784513977
+ 3.5158578060746977
+ 3.5159070327479083
+ 3.515956258471078
+ 3.5160054832442573
+ 3.5160547070674952
+ 3.5161039299408428
+ 3.5161531518643483
+ 3.5162023728380625
+ 3.516251592862035
+ 3.516300811936315
+ 3.5163500300609525
+ 3.5163992472359973
+ 3.5164484634614994
+ 3.5164976787375077
+ 3.516546893064073
+ 3.516596106441244
+ 3.5166453188690716
+ 3.5166945303476047
+ 3.516743740876893
+ 3.5167929504569857
+ 3.5168421590879344
+ 3.5168913667697863
+ 3.516940573502593
+ 3.5169897792864027
+ 3.5170389841212666
+ 3.5170881880072336
+ 3.517137390944353
+ 3.5171865929326747
+ 3.5172357939722487
+ 3.5172849940631243
+ 3.5173341932053512
+ 3.5173833913989796
+ 3.5174325886440583
+ 3.5174817849406375
+ 3.5175309802887664
+ 3.517580174688495
+ 3.5176293681398727
+ 3.51767856064295
+ 3.517727752197775
+ 3.5177769428043986
+ 3.517826132462869
+ 3.5178753211732374
+ 3.517924508935552
+ 3.517973695749864
+ 3.5180228816162216
+ 3.5180720665346743
+ 3.5181212505052732
+ 3.518170433528066
+ 3.518219615603104
+ 3.5182687967304354
+ 3.5183179769101107
+ 3.5183671561421788
+ 3.5184163344266897
+ 3.5184655117636923
+ 3.518514688153237
+ 3.518563863595373
+ 3.51861303809015
+ 3.5186622116376167
+ 3.518711384237824
+ 3.5187605558908204
+ 3.518809726596656
+ 3.5188588963553795
+ 3.5189080651670417
+ 3.5189572330316907
+ 3.519006399949377
+ 3.51905556592015
+ 3.5191047309440586
+ 3.519153895021153
+ 3.519203058151482
+ 3.5192522203350958
+ 3.5193013815720438
+ 3.5193505418623747
+ 3.5193997012061384
+ 3.519448859603385
+ 3.519498017054163
+ 3.519547173558523
+ 3.5195963291165127
+ 3.519645483728183
+ 3.5196946373935827
+ 3.519743790112762
+ 3.5197929418857696
+ 3.519842092712655
+ 3.5198912425934683
+ 3.5199403915282583
+ 3.519989539517074
+ 3.5200386865599658
+ 3.5200878326569827
+ 3.520136977808174
+ 3.5201861220135884
+ 3.5202352652732767
+ 3.520284407587288
+ 3.5203335489556715
+ 3.520382689378476
+ 3.520431828855751
+ 3.520480967387547
+ 3.520530104973912
+ 3.5205792416148967
+ 3.520628377310549
+ 3.5206775120609195
+ 3.5207266458660564
+ 3.5207757787260103
+ 3.52082491064083
+ 3.520874041610565
+ 3.5209231716352636
+ 3.520972300714977
+ 3.5210214288497528
+ 3.5210705560396414
+ 3.5211196822846915
+ 3.521168807584953
+ 3.521217931940475
+ 3.521267055351306
+ 3.521316177817497
+ 3.521365299339096
+ 3.5214144199161526
+ 3.5214635395487157
+ 3.5215126582368357
+ 3.521561775980561
+ 3.521610892779941
+ 3.5216600086350254
+ 3.5217091235458633
+ 3.5217582375125036
+ 3.521807350534995
+ 3.521856462613389
+ 3.5219055737477323
+ 3.521954683938076
+ 3.522003793184468
+ 3.5220529014869584
+ 3.5221020088455965
+ 3.522151115260431
+ 3.5222002207315115
+ 3.522249325258887
+ 3.522298428842607
+ 3.5223475314827204
+ 3.522396633179276
+ 3.5224457339323245
+ 3.5224948337419137
+ 3.5225439326080936
+ 3.5225930305309134
+ 3.5226421275104216
+ 3.522691223546668
+ 3.522740318639701
+ 3.522789412789571
+ 3.5228385059963263
+ 3.522887598260016
+ 3.5229366895806895
+ 3.522985779958397
+ 3.5230348693931854
+ 3.5230839578851065
+ 3.523133045434207
+ 3.523182132040538
+ 3.523231217704147
+ 3.5232803024250847
+ 3.523329386203399
+ 3.52337846903914
+ 3.523427550932356
+ 3.5234766318830966
+ 3.523525711891411
+ 3.523574790957347
+ 3.5236238690809563
+ 3.5236729462622858
+ 3.5237220225013854
+ 3.523771097798304
+ 3.5238201721530915
+ 3.5238692455657956
+ 3.5239183180364666
+ 3.5239673895651524
+ 3.5240164601519033
+ 3.5240655297967676
+ 3.524114598499795
+ 3.5241636662610336
+ 3.5242127330805335
+ 3.524261798958343
+ 3.5243108638945118
+ 3.5243599278890887
+ 3.5244089909421223
+ 3.5244580530536624
+ 3.524507114223757
+ 3.524556174452456
+ 3.524605233739808
+ 3.524654292085863
+ 3.5247033494906685
+ 3.5247524059542745
+ 3.5248014614767293
+ 3.524850516058083
+ 3.524899569698384
+ 3.5249486223976807
+ 3.524997674156023
+ 3.5250467249734596
+ 3.525095774850039
+ 3.525144823785811
+ 3.525193871780824
+ 3.525242918835128
+ 3.5252919649487704
+ 3.5253410101218012
+ 3.525390054354269
+ 3.525439097646222
+ 3.5254881399977114
+ 3.5255371814087835
+ 3.5255862218794896
+ 3.5256352614098763
+ 3.5256842999999947
+ 3.5257333376498923
+ 3.5257823743596193
+ 3.5258314101292227
+ 3.5258804449587533
+ 3.525929478848259
+ 3.5259785117977893
+ 3.5260275438073925
+ 3.5260765748771177
+ 3.526125605007014
+ 3.5261746341971305
+ 3.5262236624475154
+ 3.526272689758218
+ 3.526321716129288
+ 3.5263707415607723
+ 3.526419766052722
+ 3.526468789605184
+ 3.5265178122182084
+ 3.5265668338918434
+ 3.5266158546261384
+ 3.526664874421142
+ 3.526713893276903
+ 3.52676291119347
+ 3.526811928170893
+ 3.52686094420922
+ 3.526909959308499
+ 3.52695897346878
+ 3.5270079866901116
+ 3.527056998972542
+ 3.5271060103161216
+ 3.527155020720897
+ 3.5272040301869194
+ 3.5272530387142353
+ 3.5273020463028946
+ 3.527351052952947
+ 3.5274000586644387
+ 3.5274490634374214
+ 3.5274980672719423
+ 3.5275470701680502
+ 3.5275960721257946
+ 3.527645073145224
+ 3.527694073226386
+ 3.527743072369331
+ 3.5277920705741073
+ 3.5278410678407632
+ 3.527890064169348
+ 3.52793905955991
+ 3.5279880540124977
+ 3.528037047527161
+ 3.5280860401039478
+ 3.5281350317429063
+ 3.528184022444086
+ 3.5282330122075356
+ 3.528282001033304
+ 3.528330988921439
+ 3.5283799758719905
+ 3.5284289618850058
+ 3.5284779469605354
+ 3.528526931098626
+ 3.5285759142993283
+ 3.5286248965626896
+ 3.528673877888759
+ 3.5287228582775847
+ 3.5287718377292165
+ 3.528820816243702
+ 3.5288697938210905
+ 3.5289187704614298
+ 3.52896774616477
+ 3.5290167209311583
+ 3.5290656947606442
+ 3.529114667653276
+ 3.529163639609103
+ 3.5292126106281727
+ 3.5292615807105348
+ 3.5293105498562376
+ 3.5293595180653297
+ 3.529408485337859
+ 3.529457451673875
+ 3.529506417073426
+ 3.529555381536561
+ 3.5296043450633285
+ 3.529653307653776
+ 3.5297022693079536
+ 3.529751230025909
+ 3.5298001898076916
+ 3.529849148653349
+ 3.5298981065629302
+ 3.529947063536484
+ 3.529996019574059
+ 3.530044974675703
+ 3.5300939288414654
+ 3.530142882071395
+ 3.530191834365539
+ 3.5302407857239473
+ 3.530289736146668
+ 3.5303386856337493
+ 3.53038763418524
+ 3.530436581801189
+ 3.530485528481644
+ 3.5305344742266542
+ 3.530583419036268
+ 3.530632362910534
+ 3.5306813058495
+ 3.530730247853216
+ 3.530779188921729
+ 3.5308281290550885
+ 3.5308770682533424
+ 3.530926006516539
+ 3.5309749438447278
+ 3.531023880237956
+ 3.5310728156962736
+ 3.5311217502197274
+ 3.531170683808367
+ 3.5312196164622405
+ 3.531268548181397
+ 3.531317478965884
+ 3.5313664088157504
+ 3.5314153377310444
+ 3.5314642657118154
+ 3.5315131927581103
+ 3.5315621188699784
+ 3.5316110440474686
+ 3.5316599682906284
+ 3.531708891599507
+ 3.531757813974153
+ 3.531806735414613
+ 3.5318556559209373
+ 3.531904575493174
+ 3.531953494131371
+ 3.5320024118355766
+ 3.53205132860584
+ 3.5321002444422094
+ 3.5321491593447325
+ 3.532198073313458
+ 3.5322469863484347
+ 3.532295898449711
+ 3.5323448096173347
+ 3.532393719851354
+ 3.532442629151818
+ 3.532491537518775
+ 3.5325404449522733
+ 3.5325893514523607
+ 3.532638257019086
+ 3.5326871616524973
+ 3.5327360653526436
+ 3.532784968119572
+ 3.532833869953332
+ 3.532882770853972
+ 3.5329316708215397
+ 3.532980569856083
+ 3.5330294679576517
+ 3.5330783651262925
+ 3.533127261362055
+ 3.5331761566649864
+ 3.5332250510351355
+ 3.5332739444725507
+ 3.533322836977281
+ 3.533371728549373
+ 3.533420619188876
+ 3.533469508895838
+ 3.5335183976703086
+ 3.5335672855123343
+ 3.533616172421964
+ 3.533665058399246
+ 3.533713943444228
+ 3.5337628275569597
+ 3.533811710737488
+ 3.533860592985862
+ 3.533909474302129
+ 3.533958354686338
+ 3.534007234138537
+ 3.5340561126587744
+ 3.5341049902470982
+ 3.534153866903557
+ 3.5342027426281977
+ 3.5342516174210705
+ 3.5343004912822225
+ 3.5343493642117023
+ 3.5343982362095576
+ 3.534447107275837
+ 3.5344959774105886
+ 3.5345448466138607
+ 3.534593714885701
+ 3.5346425822261582
+ 3.53469144863528
+ 3.5347403141131157
+ 3.5347891786597123
+ 3.5348380422751178
+ 3.5348869049593814
+ 3.5349357667125507
+ 3.534984627534674
+ 3.5350334874257996
+ 3.5350823463859755
+ 3.535131204415249
+ 3.5351800615136697
+ 3.5352289176812843
+ 3.535277772918142
+ 3.535326627224291
+ 3.535375480599779
+ 3.535424333044654
+ 3.535473184558964
+ 3.535522035142758
+ 3.535570884796083
+ 3.535619733518988
+ 3.53566858131152
+ 3.535717428173728
+ 3.53576627410566
+ 3.5358151191073643
+ 3.535863963178888
+ 3.53591280632028
+ 3.5359616485315883
+ 3.536010489812861
+ 3.5360593301641456
+ 3.5361081695854915
+ 3.536157008076945
+ 3.536205845638555
+ 3.53625468227037
+ 3.5363035179724376
+ 3.5363523527448057
+ 3.5364011865875224
+ 3.5364500195006356
+ 3.536498851484194
+ 3.536547682538245
+ 3.536596512662837
+ 3.5366453418580175
+ 3.536694170123835
+ 3.5367429974603373
+ 3.5367918238675724
+ 3.5368406493455886
+ 3.536889473894433
+ 3.5369382975141552
+ 3.5369871202048015
+ 3.5370359419664212
+ 3.537084762799061
+ 3.5371335827027703
+ 3.5371824016775957
+ 3.5372312197235862
+ 3.5372800368407895
+ 3.5373288530292526
+ 3.5373776682890252
+ 3.5374264826201545
+ 3.537475296022688
+ 3.5375241084966738
+ 3.5375729200421597
+ 3.5376217306591946
+ 3.5376705403478255
+ 3.5377193491081003
+ 3.537768156940068
+ 3.537816963843775
+ 3.5378657698192697
+ 3.5379145748666008
+ 3.5379633789858156
+ 3.538012182176962
+ 3.5380609844400888
+ 3.5381097857752417
+ 3.538158586182471
+ 3.5382073856618232
+ 3.538256184213347
+ 3.5383049818370895
+ 3.5383537785330987
+ 3.538402574301423
+ 3.538451369142109
+ 3.538500163055207
+ 3.5385489560407626
+ 3.5385977480988244
+ 3.53864653922944
+ 3.538695329432658
+ 3.5387441187085256
+ 3.538792907057091
+ 3.538841694478402
+ 3.538890480972506
+ 3.538939266539451
+ 3.538988051179285
+ 3.539036834892056
+ 3.539085617677811
+ 3.5391343995365996
+ 3.5391831804684672
+ 3.5392319604734634
+ 3.5392807395516352
+ 3.5393295177030306
+ 3.5393782949276975
+ 3.539427071225684
+ 3.5394758465970364
+ 3.5395246210418048
+ 3.5395733945600347
+ 3.5396221671517756
+ 3.5396709388170735
+ 3.5397197095559783
+ 3.5397684793685364
+ 3.5398172482547956
+ 3.5398660162148037
+ 3.5399147832486095
+ 3.5399635493562593
+ 3.5400123145378015
+ 3.540061078793284
+ 3.5401098421227535
+ 3.5401586045262596
+ 3.540207366003848
+ 3.540256126555568
+ 3.5403048861814668
+ 3.5403536448815918
+ 3.54040240265599
+ 3.5404511595047112
+ 3.540499915427801
+ 3.540548670425309
+ 3.5405974244972813
+ 3.5406461776437665
+ 3.5406949298648116
+ 3.540743681160465
+ 3.540792431530773
+ 3.5408411809757854
+ 3.540889929495549
+ 3.5409386770901103
+ 3.5409874237595185
+ 3.5410361695038204
+ 3.5410849143230636
+ 3.5411336582172965
+ 3.5411824011865662
+ 3.5412311432309203
+ 3.5412798843504065
+ 3.541328624545073
+ 3.5413773638149664
+ 3.5414261021601345
+ 3.5414748395806264
+ 3.5415235760764876
+ 3.541572311647767
+ 3.5416210462945115
+ 3.5416697800167696
+ 3.5417185128145885
+ 3.5417672446880153
+ 3.5418159756370984
+ 3.5418647056618844
+ 3.541913434762422
+ 3.5419621629387583
+ 3.5420108901909404
+ 3.5420596165190164
+ 3.542108341923034
+ 3.5421570664030404
+ 3.542205789959083
+ 3.5422545125912097
+ 3.5423032342994683
+ 3.5423519550839058
+ 3.54240067494457
+ 3.5424493938815087
+ 3.5424981118947687
+ 3.5425468289843987
+ 3.5425955451504447
+ 3.542644260392955
+ 3.542692974711978
+ 3.5427416881075597
+ 3.542790400579749
+ 3.542839112128592
+ 3.5428878227541367
+ 3.5429365324564315
+ 3.5429852412355225
+ 3.5430339490914586
+ 3.543082656024286
+ 3.543131362034053
+ 3.543180067120807
+ 3.543228771284595
+ 3.543277474525465
+ 3.5433261768434643
+ 3.54337487823864
+ 3.54342357871104
+ 3.5434722782607118
+ 3.5435209768877027
+ 3.54356967459206
+ 3.543618371373831
+ 3.543667067233064
+ 3.5437157621698057
+ 3.5437644561841037
+ 3.5438131492760054
+ 3.543861841445558
+ 3.5439105326928093
+ 3.5439592230178065
+ 3.5440079124205974
+ 3.544056600901229
+ 3.5441052884597486
+ 3.544153975096204
+ 3.544202660810642
+ 3.5442513456031106
+ 3.544300029473657
+ 3.544348712422329
+ 3.544397394449173
+ 3.544446075554237
+ 3.5444947557375683
+ 3.5445434349992144
+ 3.5445921133392226
+ 3.54464079075764
+ 3.5446894672545146
+ 3.5447381428298925
+ 3.544786817483822
+ 3.5448354912163507
+ 3.5448841640275255
+ 3.5449328359173937
+ 3.5449815068860024
+ 3.5450301769333996
+ 3.5450788460596323
+ 3.5451275142647476
+ 3.545176181548793
+ 3.5452248479118156
+ 3.5452735133538633
+ 3.545322177874983
+ 3.545370841475222
+ 3.5454195041546273
+ 3.5454681659132468
+ 3.5455168267511277
+ 3.5455654866683166
+ 3.545614145664861
+ 3.545662803740809
+ 3.5457114608962077
+ 3.5457601171311035
+ 3.545808772445544
+ 3.545857426839577
+ 3.545906080313249
+ 3.545954732866608
+ 3.5460033844997008
+ 3.546052035212574
+ 3.546100685005277
+ 3.546149333877854
+ 3.546197981830355
+ 3.546246628862826
+ 3.546295274975314
+ 3.5463439201678666
+ 3.5463925644405307
+ 3.546441207793354
+ 3.5464898502263833
+ 3.546538491739666
+ 3.546587132333249
+ 3.54663577200718
+ 3.546684410761506
+ 3.5467330485962743
+ 3.5467816855115313
+ 3.5468303215073256
+ 3.5468789565837033
+ 3.546927590740712
+ 3.5469762239783984
+ 3.5470248562968103
+ 3.5470734876959944
+ 3.547122118175998
+ 3.547170747736869
+ 3.547219376378653
+ 3.547268004101398
+ 3.5473166309051516
+ 3.5473652567899605
+ 3.547413881755871
+ 3.547462505802932
+ 3.5475111289311894
+ 3.5475597511406898
+ 3.547608372431482
+ 3.5476569928036117
+ 3.5477056122571264
+ 3.547754230792074
+ 3.5478028484085007
+ 3.547851465106454
+ 3.54790008088598
+ 3.5479486957471273
+ 3.547997309689942
+ 3.548045922714472
+ 3.5480945348207635
+ 3.548143146008864
+ 3.548191756278821
+ 3.5482403656306807
+ 3.5482889740644907
+ 3.5483375815802978
+ 3.5483861881781493
+ 3.5484347938580916
+ 3.5484833986201725
+ 3.548532002464439
+ 3.548580605390938
+ 3.548629207399716
+ 3.5486778084908215
+ 3.5487264086642996
+ 3.548775007920199
+ 3.5488236062585656
+ 3.548872203679447
+ 3.54892080018289
+ 3.5489693957689417
+ 3.549017990437649
+ 3.5490665841890587
+ 3.5491151770232183
+ 3.5491637689401743
+ 3.549212359939974
+ 3.5492609500226644
+ 3.5493095391882923
+ 3.5493581274369053
+ 3.5494067147685495
+ 3.549455301183272
+ 3.5495038866811197
+ 3.5495524712621402
+ 3.5496010549263803
+ 3.549649637673887
+ 3.5496982195047067
+ 3.5497468004188866
+ 3.5497953804164735
+ 3.549843959497515
+ 3.5498925376620574
+ 3.5499411149101476
+ 3.5499896912418327
+ 3.5500382666571597
+ 3.5500868411561757
+ 3.5501354147389272
+ 3.5501839874054615
+ 3.5502325591558255
+ 3.550281129990065
+ 3.5503296999082288
+ 3.5503782689103622
+ 3.550426836996513
+ 3.5504754041667272
+ 3.550523970421053
+ 3.5505725357595357
+ 3.550621100182224
+ 3.5506696636891633
+ 3.5507182262804013
+ 3.550766787955984
+ 3.550815348715959
+ 3.550863908560373
+ 3.5509124674892725
+ 3.5509610255027053
+ 3.551009582600717
+ 3.5510581387833553
+ 3.551106694050666
+ 3.551155248402698
+ 3.551203801839496
+ 3.551252354361108
+ 3.55130090596758
+ 3.5513494566589596
+ 3.551398006435293
+ 3.5514465552966277
+ 3.55149510324301
+ 3.5515436502744873
+ 3.551592196391105
+ 3.5516407415929114
+ 3.5516892858799523
+ 3.5517378292522754
+ 3.5517863717099267
+ 3.5518349132529528
+ 3.5518834538814015
+ 3.5519319935953186
+ 3.5519805323947518
+ 3.5520290702797466
+ 3.552077607250351
+ 3.552126143306611
+ 3.5521746784485737
+ 3.5522232126762856
+ 3.552271745989794
+ 3.5523202783891445
+ 3.552368809874385
+ 3.5524173404455617
+ 3.5524658701027207
+ 3.5525143988459105
+ 3.552562926675176
+ 3.5526114535905653
+ 3.552659979592124
+ 3.5527085046798996
+ 3.552757028853938
+ 3.552805552114287
+ 3.5528540744609924
+ 3.552902595894101
+ 3.5529511164136602
+ 3.5529996360197154
+ 3.5530481547123145
+ 3.553096672491504
+ 3.553145189357329
+ 3.553193705309839
+ 3.553242220349078
+ 3.553290734475094
+ 3.553339247687934
+ 3.553387759987644
+ 3.5534362713742698
+ 3.55348478184786
+ 3.5535332914084594
+ 3.553581800056116
+ 3.5536303077908755
+ 3.5536788146127853
+ 3.5537273205218916
+ 3.553775825518241
+ 3.55382432960188
+ 3.5538728327728553
+ 3.553921335031214
+ 3.5539698363770023
+ 3.554018336810267
+ 3.554066836331054
+ 3.5541153349394103
+ 3.554163832635383
+ 3.5542123294190184
+ 3.5542608252903625
+ 3.5543093202494633
+ 3.554357814296365
+ 3.5544063074311167
+ 3.5544547996537634
+ 3.554503290964352
+ 3.5545517813629304
+ 3.5546002708495426
+ 3.554648759424237
+ 3.5546972470870597
+ 3.554745733838057
+ 3.5547942196772753
+ 3.5548427046047624
+ 3.554891188620563
+ 3.5549396717247252
+ 3.5549881539172943
+ 3.555036635198318
+ 3.555085115567842
+ 3.555133595025913
+ 3.5551820735725768
+ 3.5552305512078815
+ 3.5552790279318724
+ 3.555327503744597
+ 3.5553759786461
+ 3.5554244526364296
+ 3.555472925715632
+ 3.5555213978837528
+ 3.5555698691408395
+ 3.5556183394869376
+ 3.5556668089220946
+ 3.5557152774463563
+ 3.5557637450597697
+ 3.5558122117623805
+ 3.555860677554235
+ 3.555909142435381
+ 3.5559576064058644
+ 3.5560060694657305
+ 3.556054531615027
+ 3.5561029928538
+ 3.556151453182096
+ 3.5561999125999613
+ 3.5562483711074426
+ 3.556296828704586
+ 3.556345285391438
+ 3.5563937411680446
+ 3.556442196034453
+ 3.556490649990709
+ 3.5565391030368594
+ 3.5565875551729507
+ 3.556636006399028
+ 3.55668445671514
+ 3.556732906121331
+ 3.5567813546176485
+ 3.5568298022041382
+ 3.5568782488808472
+ 3.5569266946478213
+ 3.5569751395051075
+ 3.557023583452751
+ 3.557072026490799
+ 3.557120468619298
+ 3.5571689098382944
+ 3.557217350147834
+ 3.5572657895479627
+ 3.5573142280387287
+ 3.5573626656201762
+ 3.5574111022923534
+ 3.5574595380553045
+ 3.557507972909078
+ 3.557556406853719
+ 3.557604839889274
+ 3.5576532720157896
+ 3.5577017032333123
+ 3.5577501335418873
+ 3.557798562941562
+ 3.557846991432382
+ 3.5578954190143937
+ 3.557943845687644
+ 3.5579922714521786
+ 3.558040696308044
+ 3.558089120255287
+ 3.558137543293953
+ 3.558185965424088
+ 3.5582343866457395
+ 3.5582828069589527
+ 3.5583312263637747
+ 3.558379644860251
+ 3.5584280624484284
+ 3.5584764791283527
+ 3.5585248949000707
+ 3.5585733097636276
+ 3.5586217237190714
+ 3.558670136766446
+ 3.5587185489058
+ 3.558766960137178
+ 3.5588153704606267
+ 3.5588637798761926
+ 3.5589121883839216
+ 3.5589605959838604
+ 3.5590090026760546
+ 3.5590574084605504
+ 3.559105813337394
+ 3.559154217306632
+ 3.5592026203683105
+ 3.5592510225224756
+ 3.5592994237691733
+ 3.55934782410845
+ 3.5593962235403516
+ 3.5594446220649245
+ 3.5594930196822148
+ 3.559541416392269
+ 3.559589812195133
+ 3.5596382070908525
+ 3.5596866010794743
+ 3.5597349941610443
+ 3.5597833863356088
+ 3.559831777603214
+ 3.559880167963905
+ 3.5599285574177295
+ 3.5599769459647326
+ 3.560025333604961
+ 3.56007372033846
+ 3.5601221061652764
+ 3.5601704910854566
+ 3.560218875099046
+ 3.560267258206091
+ 3.5603156404066376
+ 3.5603640217007326
+ 3.5604124020884207
+ 3.560460781569749
+ 3.560509160144763
+ 3.56055753781351
+ 3.5606059145760347
+ 3.5606542904323835
+ 3.5607026653826033
+ 3.560751039426739
+ 3.560799412564837
+ 3.560847784796944
+ 3.5608961561231056
+ 3.5609445265433677
+ 3.560992896057777
+ 3.5610412646663785
+ 3.561089632369219
+ 3.561137999166344
+ 3.5611863650578006
+ 3.5612347300436333
+ 3.5612830941238895
+ 3.5613314572986146
+ 3.5613798195678545
+ 3.5614281809316553
+ 3.561476541390063
+ 3.5615249009431236
+ 3.5615732595908836
+ 3.561621617333388
+ 3.5616699741706843
+ 3.561718330102817
+ 3.5617666851298324
+ 3.5618150392517776
+ 3.561863392468697
+ 3.561911744780638
+ 3.561960096187645
+ 3.5620084466897652
+ 3.5620567962870444
+ 3.5621051449795282
+ 3.5621534927672625
+ 3.562201839650294
+ 3.5622501856286677
+ 3.56229853070243
+ 3.5623468748716274
+ 3.5623952181363046
+ 3.5624435604965083
+ 3.562491901952285
+ 3.5625402425036787
+ 3.5625885821507377
+ 3.5626369208935063
+ 3.5626852587320306
+ 3.5627335956663577
+ 3.5627819316965312
+ 3.5628302668226
+ 3.5628786010446074
+ 3.5629269343626007
+ 3.5629752667766255
+ 3.563023598286727
+ 3.563071928892952
+ 3.5631202585953465
+ 3.5631685873939554
+ 3.5632169152888253
+ 3.5632652422800017
+ 3.563313568367531
+ 3.5633618935514586
+ 3.5634102178318305
+ 3.5634585412086923
+ 3.5635068636820906
+ 3.56355518525207
+ 3.5636035059186777
+ 3.563651825681959
+ 3.5637001445419583
+ 3.563748462498724
+ 3.5637967795523005
+ 3.563845095702734
+ 3.5638934109500693
+ 3.5639417252943537
+ 3.5639900387356325
+ 3.5640383512739513
+ 3.5640866629093555
+ 3.5641349736418917
+ 3.5641832834716056
+ 3.5642315923985426
+ 3.5642799004227483
+ 3.564328207544269
+ 3.564376513763151
+ 3.5644248190794383
+ 3.564473123493179
+ 3.5645214270044168
+ 3.564569729613199
+ 3.56461803131957
+ 3.564666332123576
+ 3.5647146320252636
+ 3.564762931024678
+ 3.5648112291218643
+ 3.5648595263168694
+ 3.564907822609738
+ 3.5649561180005174
+ 3.5650044124892513
+ 3.5650527060759862
+ 3.5651009987607685
+ 3.5651492905436433
+ 3.5651975814246564
+ 3.5652458714038535
+ 3.56529416048128
+ 3.565342448656983
+ 3.565390735931007
+ 3.5654390223033974
+ 3.5654873077742
+ 3.565535592343461
+ 3.565583876011227
+ 3.5656321587775412
+ 3.565680440642452
+ 3.565728721606003
+ 3.565777001668241
+ 3.565825280829211
+ 3.565873559088959
+ 3.5659218364475307
+ 3.565970112904972
+ 3.566018388461328
+ 3.566066663116645
+ 3.566114936870968
+ 3.5661632097243428
+ 3.566211481676815
+ 3.5662597527284308
+ 3.566308022879235
+ 3.566356292129274
+ 3.566404560478593
+ 3.566452827927238
+ 3.5665010944752535
+ 3.566549360122686
+ 3.5665976248695817
+ 3.5666458887159846
+ 3.566694151661942
+ 3.566742413707498
+ 3.5667906748527
+ 3.5668389350975915
+ 3.5668871944422196
+ 3.566935452886629
+ 3.566983710430866
+ 3.5670319670749753
+ 3.5670802228190035
+ 3.5671284776629957
+ 3.567176731606997
+ 3.567224984651054
+ 3.567273236795211
+ 3.5673214880395148
+ 3.5673697383840097
+ 3.567417987828742
+ 3.5674662363737575
+ 3.567514484019101
+ 3.567562730764818
+ 3.5676109766109554
+ 3.567659221557557
+ 3.5677074656046694
+ 3.5677557087523373
+ 3.5678039510006077
+ 3.567852192349524
+ 3.5679004327991337
+ 3.567948672349481
+ 3.5679969110006113
+ 3.5680451487525717
+ 3.5680933856054056
+ 3.5681416215591604
+ 3.5681898566138797
+ 3.568238090769611
+ 3.568286324026398
+ 3.5683345563842868
+ 3.568382787843323
+ 3.5684310184035524
+ 3.5684792480650196
+ 3.5685274768277715
+ 3.568575704691852
+ 3.568623931657307
+ 3.568672157724182
+ 3.5687203828925234
+ 3.568768607162375
+ 3.568816830533783
+ 3.5688650530067934
+ 3.5689132745814507
+ 3.5689614952578013
+ 3.5690097150358895
+ 3.5690579339157615
+ 3.569106151897462
+ 3.569154368981037
+ 3.5692025851665314
+ 3.569250800453992
+ 3.569299014843462
+ 3.5693472283349887
+ 3.569395440928617
+ 3.5694436526243916
+ 3.5694918634223587
+ 3.569540073322563
+ 3.5695882823250495
+ 3.569636490429865
+ 3.5696846976370544
+ 3.5697329039466625
+ 3.5697811093587344
+ 3.5698293138733166
+ 3.569877517490454
+ 3.5699257202101915
+ 3.569973922032575
+ 3.570022122957649
+ 3.57007032298546
+ 3.5701185221160525
+ 3.570166720349472
+ 3.5702149176857643
+ 3.570263114124974
+ 3.570311309667147
+ 3.570359504312328
+ 3.5704076980605635
+ 3.5704558909118975
+ 3.570504082866375
+ 3.570552273924043
+ 3.570600464084946
+ 3.5706486533491293
+ 3.570696841716637
+ 3.5707450291875165
+ 3.570793215761812
+ 3.5708414014395684
+ 3.5708895862208316
+ 3.5709377701056466
+ 3.5709859530940586
+ 3.571034135186113
+ 3.5710823163818555
+ 3.571130496681331
+ 3.571178676084584
+ 3.5712268545916603
+ 3.5712750322026063
+ 3.571323208917465
+ 3.571371384736284
+ 3.5714195596591067
+ 3.571467733685979
+ 3.571515906816946
+ 3.5715640790520538
+ 3.571612250391346
+ 3.5716604208348697
+ 3.571708590382668
+ 3.571756759034788
+ 3.5718049267912737
+ 3.5718530936521704
+ 3.5719012596175244
+ 3.5719494246873795
+ 3.571997588861782
+ 3.572045752140776
+ 3.5720939145244075
+ 3.5721420760127214
+ 3.572190236605763
+ 3.5722383963035775
+ 3.57228655510621
+ 3.5723347130137046
+ 3.5723828700261087
+ 3.5724310261434655
+ 3.5724791813658214
+ 3.572527335693221
+ 3.572575489125709
+ 3.572623641663331
+ 3.572671793306132
+ 3.572719944054158
+ 3.572768093907453
+ 3.572816242866063
+ 3.5728643909300315
+ 3.5729125380994056
+ 3.5729606843742294
+ 3.5730088297545484
+ 3.573056974240407
+ 3.573105117831852
+ 3.5731532605289256
+ 3.5732014023316756
+ 3.573249543240146
+ 3.5732976832543817
+ 3.5733458223744283
+ 3.573393960600331
+ 3.573442097932134
+ 3.573490234369883
+ 3.573538369913623
+ 3.573586504563399
+ 3.573634638319256
+ 3.573682771181239
+ 3.573730903149394
+ 3.5737790342237648
+ 3.5738271644043964
+ 3.573875293691335
+ 3.5739234220846248
+ 3.573971549584311
+ 3.574019676190439
+ 3.574067801903053
+ 3.574115926722199
+ 3.5741640506479206
+ 3.574212173680265
+ 3.574260295819275
+ 3.574308417064997
+ 3.5743565374174757
+ 3.5744046568767556
+ 3.5744527754428828
+ 3.5745008931159012
+ 3.574549009895856
+ 3.5745971257827924
+ 3.5746452407767557
+ 3.5746933548777897
+ 3.5747414680859415
+ 3.5747895804012533
+ 3.574837691823773
+ 3.574885802353543
+ 3.57493391199061
+ 3.574982020735018
+ 3.5750301285868122
+ 3.575078235546038
+ 3.57512634161274
+ 3.575174446786963
+ 3.5752225510687525
+ 3.5752706544581523
+ 3.5753187569552085
+ 3.5753668585599656
+ 3.5754149592724684
+ 3.575463059092762
+ 3.575511158020891
+ 3.575559256056901
+ 3.575607353200836
+ 3.575655449452742
+ 3.5757035448126624
+ 3.575751639280644
+ 3.57579973285673
+ 3.5758478255409663
+ 3.575895917333397
+ 3.575944008234068
+ 3.575992098243023
+ 3.576040187360308
+ 3.5760882755859673
+ 3.576136362920046
+ 3.5761844493625885
+ 3.57623253491364
+ 3.5762806195732457
+ 3.5763287033414497
+ 3.576376786218298
+ 3.5764248682038335
+ 3.576472949298103
+ 3.57652102950115
+ 3.576569108813021
+ 3.576617187233759
+ 3.5766652647634096
+ 3.5767133414020176
+ 3.576761417149628
+ 3.576809492006285
+ 3.5768575659720345
+ 3.5769056390469203
+ 3.576953711230988
+ 3.5770017825242815
+ 3.577049852926846
+ 3.577097922438727
+ 3.577145991059968
+ 3.5771940587906155
+ 3.577242125630712
+ 3.5772901915803046
+ 3.577338256639436
+ 3.5773863208081527
+ 3.5774343840864984
+ 3.5774824464745185
+ 3.5775305079722575
+ 3.57757856857976
+ 3.577626628297071
+ 3.577674687124235
+ 3.5777227450612967
+ 3.5777708021083017
+ 3.5778188582652937
+ 3.577866913532318
+ 3.577914967909419
+ 3.577963021396642
+ 3.578011073994031
+ 3.5780591257016305
+ 3.578107176519487
+ 3.578155226447643
+ 3.578203275486145
+ 3.578251323635036
+ 3.5782993708943622
+ 3.5783474172641676
+ 3.578395462744497
+ 3.578443507335395
+ 3.5784915510369064
+ 3.578539593849076
+ 3.5785876357719486
+ 3.5786356768055683
+ 3.57868371694998
+ 3.5787317562052285
+ 3.578779794571359
+ 3.5788278320484155
+ 3.5788758686364424
+ 3.578923904335485
+ 3.5789719391455876
+ 3.5790199730667953
+ 3.5790680060991513
+ 3.5791160382427027
+ 3.5791640694974918
+ 3.579212099863565
+ 3.579260129340965
+ 3.5793081579297388
+ 3.5793561856299294
+ 3.5794042124415815
+ 3.5794522383647402
+ 3.57950026339945
+ 3.5795482875457556
+ 3.5795963108037014
+ 3.5796443331733316
+ 3.5796923546546924
+ 3.5797403752478263
+ 3.579788394952779
+ 3.5798364137695953
+ 3.5798844316983187
+ 3.579932448738995
+ 3.579980464891668
+ 3.580028480156383
+ 3.5800764945331838
+ 3.5801245080221156
+ 3.5801725206232224
+ 3.5802205323365497
+ 3.5802685431621404
+ 3.5803165531000403
+ 3.5803645621502938
+ 3.5804125703129452
+ 3.580460577588039
+ 3.5805085839756203
+ 3.5805565894757327
+ 3.5806045940884217
+ 3.5806525978137316
+ 3.5807006006517064
+ 3.580748602602391
+ 3.580796603665829
+ 3.580844603842067
+ 3.5808926031311477
+ 3.580940601533116
+ 3.5809885990480166
+ 3.5810365956758945
+ 3.581084591416793
+ 3.5811325862707575
+ 3.5811805802378323
+ 3.5812285733180613
+ 3.58127656551149
+ 3.5813245568181626
+ 3.581372547238123
+ 3.5814205367714154
+ 3.5814685254180856
+ 3.5815165131781774
+ 3.581564500051735
+ 3.581612486038803
+ 3.581660471139426
+ 3.5817084553536476
+ 3.5817564386815137
+ 3.5818044211230675
+ 3.5818524026783547
+ 3.5819003833474183
+ 3.5819483631303037
+ 3.5819963420270553
+ 3.582044320037717
+ 3.5820922971623332
+ 3.582140273400949
+ 3.582188248753608
+ 3.582236223220355
+ 3.582284196801235
+ 3.582332169496291
+ 3.5823801413055683
+ 3.582428112229112
+ 3.582476082266965
+ 3.5825240514191723
+ 3.5825720196857787
+ 3.5826199870668276
+ 3.5826679535623644
+ 3.582715919172433
+ 3.582763883897078
+ 3.5828118477363433
+ 3.5828598106902736
+ 3.582907772758913
+ 3.5829557339423066
+ 3.5830036942404977
+ 3.5830516536535315
+ 3.5830996121814516
+ 3.5831475698243027
+ 3.5831955265821294
+ 3.583243482454976
+ 3.583291437442886
+ 3.583339391545905
+ 3.583387344764076
+ 3.583435297097444
+ 3.5834832485460537
+ 3.583531199109949
+ 3.583579148789174
+ 3.583627097583773
+ 3.583675045493791
+ 3.5837229925192715
+ 3.5837709386602588
+ 3.5838188839167975
+ 3.583866828288932
+ 3.5839147717767066
+ 3.583962714380165
+ 3.584010656099352
+ 3.584058596934312
+ 3.5841065368850886
+ 3.5841544759517268
+ 3.58420241413427
+ 3.5842503514327633
+ 3.584298287847251
+ 3.584346223377776
+ 3.5843941580243843
+ 3.584442091787119
+ 3.584490024666025
+ 3.5845379566611455
+ 3.5845858877725263
+ 3.58463381800021
+ 3.5846817473442423
+ 3.5847296758046663
+ 3.584777603381527
+ 3.5848255300748675
+ 3.5848734558847335
+ 3.584921380811168
+ 3.5849693048542157
+ 3.5850172280139203
+ 3.585065150290327
+ 3.58511307168348
+ 3.5851609921934218
+ 3.585208911820198
+ 3.5852568305638526
+ 3.58530474842443
+ 3.5853526654019734
+ 3.5854005814965273
+ 3.585448496708137
+ 3.585496411036845
+ 3.5855443244826968
+ 3.5855922370457356
+ 3.585640148726006
+ 3.5856880595235525
+ 3.585735969438418
+ 3.585783878470649
+ 3.5858317866202865
+ 3.5858796938873776
+ 3.5859276002719636
+ 3.585975505774091
+ 3.586023410393804
+ 3.5860713141311438
+ 3.5861192169861575
+ 3.5861671189588877
+ 3.5862150200493796
+ 3.586262920257676
+ 3.586310819583822
+ 3.5863587180278613
+ 3.586406615589838
+ 3.586454512269796
+ 3.58650240806778
+ 3.5865503029838335
+ 3.586598197018001
+ 3.5866460901703263
+ 3.586693982440853
+ 3.5867418738296264
+ 3.5867897643366895
+ 3.5868376539620863
+ 3.586885542705862
+ 3.58693343056806
+ 3.5869813175487235
+ 3.5870292036478983
+ 3.5870770888656263
+ 3.5871249732019534
+ 3.587172856656923
+ 3.5872207392305784
+ 3.587268620922965
+ 3.587316501734126
+ 3.5873643816641048
+ 3.5874122607129473
+ 3.587460138880695
+ 3.5875080161673942
+ 3.5875558925730875
+ 3.58760376809782
+ 3.5876516427416343
+ 3.5876995165045757
+ 3.5877473893866876
+ 3.5877952613880137
+ 3.587843132508599
+ 3.587891002748486
+ 3.5879388721077197
+ 3.587986740586344
+ 3.588034608184403
+ 3.58808247490194
+ 3.5881303407389993
+ 3.588178205695625
+ 3.5882260697718613
+ 3.5882739329677507
+ 3.5883217952833397
+ 3.58836965671867
+ 3.588417517273786
+ 3.588465376948733
+ 3.5885132357435534
+ 3.5885610936582917
+ 3.5886089506929917
+ 3.588656806847697
+ 3.5887046621224528
+ 3.5887525165173018
+ 3.588800370032288
+ 3.5888482226674556
+ 3.5888960744228484
+ 3.5889439252985107
+ 3.588991775294486
+ 3.589039624410818
+ 3.589087472647551
+ 3.5891353200047282
+ 3.5891831664823943
+ 3.5892310120805937
+ 3.5892788567993685
+ 3.5893267006387637
+ 3.589374543598823
+ 3.589422385679591
+ 3.5894702268811103
+ 3.5895180672034255
+ 3.5895659066465795
+ 3.589613745210618
+ 3.5896615828955833
+ 3.5897094197015194
+ 3.589757255628471
+ 3.5898050906764802
+ 3.5898529248455935
+ 3.5899007581358524
+ 3.5899485905473014
+ 3.589996422079985
+ 3.5900442527339465
+ 3.5900920825092295
+ 3.5901399114058785
+ 3.590187739423936
+ 3.590235566563447
+ 3.590283392824455
+ 3.590331218207004
+ 3.5903790427111373
+ 3.590426866336899
+ 3.590474689084333
+ 3.590522510953482
+ 3.590570331944392
+ 3.5906181520571048
+ 3.590665971291665
+ 3.590713789648116
+ 3.590761607126502
+ 3.590809423726866
+ 3.590857239449253
+ 3.5909050542937053
+ 3.5909528682602683
+ 3.591000681348984
+ 3.5910484935598976
+ 3.5910963048930515
+ 3.591144115348491
+ 3.5911919249262585
+ 3.5912397336263986
+ 3.5912875414489545
+ 3.59133534839397
+ 3.591383154461489
+ 3.591430959651555
+ 3.591478763964212
+ 3.5915265673995034
+ 3.591574369957473
+ 3.5916221716381647
+ 3.591669972441622
+ 3.5917177723678884
+ 3.591765571417008
+ 3.5918133695890244
+ 3.5918611668839815
+ 3.5919089633019223
+ 3.591956758842891
+ 3.5920045535069307
+ 3.592052347294086
+ 3.5921001402044
+ 3.5921479322379164
+ 3.5921957233946786
+ 3.592243513674731
+ 3.5922913030781167
+ 3.5923390916048796
+ 3.592386879255063
+ 3.5924346660287103
+ 3.5924824519258665
+ 3.5925302369465735
+ 3.5925780210908758
+ 3.5926258043588173
+ 3.5926735867504416
+ 3.5927213682657912
+ 3.592769148904911
+ 3.592816928667844
+ 3.592864707554634
+ 3.5929124855653245
+ 3.5929602626999593
+ 3.593008038958582
+ 3.593055814341236
+ 3.5931035888479648
+ 3.593151362478812
+ 3.5931991352338217
+ 3.593246907113037
+ 3.5932946781165014
+ 3.5933424482442584
+ 3.5933902174963523
+ 3.593437985872826
+ 3.5934857533737237
+ 3.5935335199990877
+ 3.593581285748963
+ 3.593629050623392
+ 3.593676814622419
+ 3.593724577746088
+ 3.593772339994441
+ 3.593820101367523
+ 3.5938678618653763
+ 3.593915621488045
+ 3.5939633802355737
+ 3.594011138108004
+ 3.594058895105381
+ 3.5941066512277473
+ 3.5941544064751465
+ 3.5942021608476225
+ 3.5942499143452182
+ 3.594297666967978
+ 3.5943454187159447
+ 3.594393169589162
+ 3.594440919587673
+ 3.5944886687115227
+ 3.594536416960752
+ 3.5945841643354073
+ 3.59463191083553
+ 3.594679656461164
+ 3.5947274012123525
+ 3.5947751450891405
+ 3.59482288809157
+ 3.5948706302196842
+ 3.594918371473528
+ 3.594966111853144
+ 3.595013851358576
+ 3.5950615899898666
+ 3.59510932774706
+ 3.5951570646301994
+ 3.5952048006393285
+ 3.5952525357744904
+ 3.595300270035729
+ 3.5953480034230867
+ 3.595395735936608
+ 3.595443467576336
+ 3.595491198342314
+ 3.5955389282345855
+ 3.595586657253194
+ 3.595634385398182
+ 3.595682112669594
+ 3.5957298390674732
+ 3.595777564591863
+ 3.5958252892428075
+ 3.595873013020348
+ 3.5959207359245293
+ 3.5959684579553945
+ 3.596016179112988
+ 3.5960638993973513
+ 3.5961116188085294
+ 3.5961593373465646
+ 3.596207055011501
+ 3.596254771803381
+ 3.5963024877222485
+ 3.5963502027681473
+ 3.5963979169411204
+ 3.5964456302412113
+ 3.596493342668463
+ 3.596541054222919
+ 3.5965887649046224
+ 3.596636474713617
+ 3.596684183649946
+ 3.5967318917136524
+ 3.59677959890478
+ 3.5968273052233717
+ 3.5968750106694705
+ 3.596922715243121
+ 3.596970418944365
+ 3.597018121773247
+ 3.5970658237298094
+ 3.597113524814096
+ 3.5971612250261495
+ 3.5972089243660146
+ 3.597256622833733
+ 3.597304320429349
+ 3.597352017152905
+ 3.5973997130044455
+ 3.5974474079840126
+ 3.59749510209165
+ 3.597542795327401
+ 3.5975904876913094
+ 3.5976381791834178
+ 3.597685869803769
+ 3.597733559552407
+ 3.5977812484293747
+ 3.597828936434716
+ 3.5978766235684727
+ 3.59792430983069
+ 3.5979719952214095
+ 3.5980196797406756
+ 3.5980673633885303
+ 3.598115046165018
+ 3.5981627280701813
+ 3.5982104091040634
+ 3.5982580892667078
+ 3.5983057685581574
+ 3.5983534469784555
+ 3.5984011245276455
+ 3.5984488012057705
+ 3.5984964770128736
+ 3.5985441519489982
+ 3.5985918260141867
+ 3.5986394992084834
+ 3.598687171531931
+ 3.5987348429845722
+ 3.598782513566451
+ 3.59883018327761
+ 3.598877852118093
+ 3.5989255200879424
+ 3.598973187187202
+ 3.5990208534159143
+ 3.599068518774123
+ 3.599116183261871
+ 3.5991638468792018
+ 3.599211509626158
+ 3.599259171502783
+ 3.5993068325091198
+ 3.5993544926452112
+ 3.599402151911102
+ 3.599449810306833
+ 3.5994974678324487
+ 3.5995451244879924
+ 3.599592780273506
+ 3.599640435189034
+ 3.599688089234619
+ 3.599735742410304
+ 3.5997833947161313
+ 3.599831046152145
+ 3.5998786967183882
+ 3.599926346414904
+ 3.5999739952417347
+ 3.6000216431989243
+ 3.6000692902865152
+ 3.600116936504551
+ 3.600164581853075
+ 3.6002122263321295
+ 3.600259869941757
+ 3.6003075126820026
+ 3.6003551545529078
+ 3.600402795554516
+ 3.600450435686871
+ 3.6004980749500137
+ 3.6005457133439895
+ 3.600593350868841
+ 3.6006409875246104
+ 3.600688623311341
+ 3.6007362582290763
+ 3.600783892277858
+ 3.600831525457731
+ 3.6008791577687376
+ 3.60092678921092
+ 3.600974419784322
+ 3.6010220494889866
+ 3.6010696783249565
+ 3.601117306292275
+ 3.601164933390985
+ 3.6012125596211297
+ 3.6012601849827517
+ 3.601307809475894
+ 3.6013554331006
+ 3.6014030558569123
+ 3.601450677744874
+ 3.601498298764528
+ 3.601545918915917
+ 3.601593538199085
+ 3.6016411566140736
+ 3.6016887741609267
+ 3.6017363908396876
+ 3.601784006650398
+ 3.6018316215931017
+ 3.601879235667841
+ 3.60192684887466
+ 3.6019744612136004
+ 3.6020220726847065
+ 3.6020696832880197
+ 3.6021172930235834
+ 3.6021649018914412
+ 3.6022125098916358
+ 3.6022601170242097
+ 3.6023077232892056
+ 3.602355328686667
+ 3.602402933216637
+ 3.602450536879158
+ 3.602498139674273
+ 3.602545741602025
+ 3.602593342662457
+ 3.602640942855611
+ 3.602688542181531
+ 3.60273614064026
+ 3.6027837382318397
+ 3.6028313349563144
+ 3.6028789308137257
+ 3.602926525804117
+ 3.6029741199275316
+ 3.603021713184012
+ 3.603069305573601
+ 3.6031168970963408
+ 3.6031644877522755
+ 3.603212077541447
+ 3.603259666463899
+ 3.6033072545196734
+ 3.6033548417088137
+ 3.6034024280313623
+ 3.603450013487363
+ 3.603497598076857
+ 3.6035451817998885
+ 3.6035927646564994
+ 3.6036403466467335
+ 3.603687927770633
+ 3.6037355080282407
+ 3.6037830874195995
+ 3.6038306659447525
+ 3.6038782436037424
+ 3.603925820396611
+ 3.6039733963234024
+ 3.6040209713841587
+ 3.604068545578923
+ 3.6041161189077378
+ 3.6041636913706467
+ 3.604211262967691
+ 3.604258833698915
+ 3.6043064035643604
+ 3.6043539725640703
+ 3.6044015406980874
+ 3.604449107966455
+ 3.6044966743692153
+ 3.604544239906411
+ 3.604591804578085
+ 3.6046393683842806
+ 3.6046869313250394
+ 3.6047344934004055
+ 3.6047820546104203
+ 3.604829614955127
+ 3.604877174434569
+ 3.604924733048788
+ 3.6049722907978277
+ 3.6050198476817297
+ 3.605067403700538
+ 3.6051149588542946
+ 3.6051625131430414
+ 3.6052100665668227
+ 3.605257619125681
+ 3.6053051708196575
+ 3.605352721648796
+ 3.6054002716131395
+ 3.60544782071273
+ 3.6054953689476106
+ 3.6055429163178236
+ 3.605590462823412
+ 3.605638008464419
+ 3.605685553240886
+ 3.605733097152856
+ 3.6057806402003725
+ 3.6058281823834775
+ 3.605875723702214
+ 3.605923264156624
+ 3.6059708037467506
+ 3.6060183424726366
+ 3.6060658803343246
+ 3.606113417331857
+ 3.6061609534652765
+ 3.606208488734626
+ 3.6062560231399483
+ 3.606303556681285
+ 3.6063510893586797
+ 3.6063986211721746
+ 3.6064461521218125
+ 3.6064936822076357
+ 3.6065412114296875
+ 3.60658873978801
+ 3.6066362672826453
+ 3.6066837939136374
+ 3.6067313196810273
+ 3.6067788445848583
+ 3.6068263686251734
+ 3.6068738918020147
+ 3.606921414115425
+ 3.6069689355654466
+ 3.607016456152122
+ 3.6070639758754943
+ 3.607111494735606
+ 3.6071590127324993
+ 3.6072065298662164
+ 3.6072540461368017
+ 3.6073015615442947
+ 3.6073490760887412
+ 3.6073965897701816
+ 3.607444102588659
+ 3.607491614544216
+ 3.607539125636895
+ 3.607586635866739
+ 3.6076341452337903
+ 3.6076816537380916
+ 3.6077291613796842
+ 3.607776668158612
+ 3.6078241740749175
+ 3.6078716791286425
+ 3.6079191833198294
+ 3.6079666866485223
+ 3.608014189114761
+ 3.608061690718591
+ 3.6081091914600525
+ 3.608156691339189
+ 3.6082041903560427
+ 3.608251688510656
+ 3.6082991858030726
+ 3.608346682233333
+ 3.608394177801481
+ 3.6084416725075585
+ 3.6084891663516085
+ 3.6085366593336725
+ 3.608584151453795
+ 3.6086316427120155
+ 3.608679133108379
+ 3.6087266226429264
+ 3.608774111315701
+ 3.6088215991267454
+ 3.608869086076101
+ 3.608916572163811
+ 3.6089640573899175
+ 3.609011541754463
+ 3.6090590252574906
+ 3.6091065078990416
+ 3.6091539896791596
+ 3.6092014705978865
+ 3.609248950655264
+ 3.6092964298513355
+ 3.6093439081861427
+ 3.609391385659729
+ 3.6094388622721354
+ 3.6094863380234057
+ 3.609533812913581
+ 3.6095812869427046
+ 3.609628760110819
+ 3.609676232417966
+ 3.6097237038641876
+ 3.609771174449528
+ 3.609818644174027
+ 3.609866113037729
+ 3.6099135810406757
+ 3.6099610481829094
+ 3.610008514464472
+ 3.6100559798854075
+ 3.6101034444457563
+ 3.610150908145561
+ 3.6101983709848655
+ 3.610245832963711
+ 3.6102932940821395
+ 3.6103407543401937
+ 3.6103882137379166
+ 3.61043567227535
+ 3.610483129952536
+ 3.6105305867695168
+ 3.6105780427263356
+ 3.610625497823034
+ 3.6106729520596543
+ 3.61072040543624
+ 3.610767857952831
+ 3.610815309609472
+ 3.610862760406204
+ 3.610910210343069
+ 3.6109576594201105
+ 3.61100510763737
+ 3.61105255499489
+ 3.6111000014927126
+ 3.6111474471308806
+ 3.6111948919094354
+ 3.61124233582842
+ 3.6112897788878766
+ 3.611337221087847
+ 3.611384662428374
+ 3.6114321029094993
+ 3.611479542531266
+ 3.6115269812937156
+ 3.6115744191968906
+ 3.611621856240833
+ 3.6116692924255855
+ 3.61171672775119
+ 3.6117641622176886
+ 3.6118115958251242
+ 3.6118590285735386
+ 3.611906460462974
+ 3.611953891493472
+ 3.6120013216650766
+ 3.6120487509778276
+ 3.612096179431769
+ 3.612143607026943
+ 3.612191033763391
+ 3.612238459641155
+ 3.6122858846602783
+ 3.6123333088208023
+ 3.612380732122769
+ 3.6124281545662216
+ 3.6124755761512013
+ 3.6125229968777504
+ 3.612570416745912
+ 3.6126178357557266
+ 3.612665253907238
+ 3.6127126712004882
+ 3.612760087635518
+ 3.6128075032123705
+ 3.612854917931088
+ 3.612902331791713
+ 3.6129497447942867
+ 3.6129971569388517
+ 3.6130445682254493
+ 3.6130919786541233
+ 3.6131393882249148
+ 3.6131867969378657
+ 3.613234204793019
+ 3.6132816117904163
+ 3.6133290179300994
+ 3.6133764232121117
+ 3.6134238276364936
+ 3.613471231203288
+ 3.613518633912537
+ 3.6135660357642836
+ 3.6136134367585684
+ 3.613660836895434
+ 3.613708236174923
+ 3.613755634597077
+ 3.6138030321619383
+ 3.6138504288695485
+ 3.6138978247199507
+ 3.6139452197131856
+ 3.6139926138492973
+ 3.6140400071283256
+ 3.6140873995503138
+ 3.6141347911153034
+ 3.6141821818233373
+ 3.614229571674457
+ 3.614276960668705
+ 3.6143243488061225
+ 3.614371736086752
+ 3.6144191225106357
+ 3.6144665080778156
+ 3.6145138927883336
+ 3.614561276642232
+ 3.614608659639552
+ 3.614656041780337
+ 3.6147034230646278
+ 3.614750803492467
+ 3.6147981830638964
+ 3.6148455617789583
+ 3.6148929396376945
+ 3.614940316640147
+ 3.6149876927863582
+ 3.615035068076369
+ 3.6150824425102233
+ 3.615129816087961
+ 3.6151771888096254
+ 3.615224560675258
+ 3.6152719316849016
+ 3.6153193018385967
+ 3.6153666711363863
+ 3.6154140395783125
+ 3.615461407164416
+ 3.615508773894741
+ 3.615556139769327
+ 3.6156035047882176
+ 3.6156508689514544
+ 3.615698232259079
+ 3.615745594711133
+ 3.6157929563076605
+ 3.6158403170487006
+ 3.615887676934297
+ 3.615935035964491
+ 3.615982394139325
+ 3.61602975145884
+ 3.6160771079230796
+ 3.6161244635320835
+ 3.616171818285895
+ 3.6162191721845565
+ 3.6162665252281085
+ 3.6163138774165944
+ 3.616361228750055
+ 3.6164085792285325
+ 3.616455928852069
+ 3.616503277620706
+ 3.6165506255344853
+ 3.61659797259345
+ 3.6166453187976404
+ 3.6166926641470996
+ 3.616740008641868
+ 3.6167873522819898
+ 3.6168346950675048
+ 3.6168820369984562
+ 3.6169293780748846
+ 3.616976718296833
+ 3.617024057664343
+ 3.6170713961774554
+ 3.617118733836213
+ 3.6171660706406583
+ 3.617213406590832
+ 3.617260741686777
+ 3.6173080759285337
+ 3.6173554093161444
+ 3.6174027418496526
+ 3.6174500735290978
+ 3.617497404354523
+ 3.61754473432597
+ 3.6175920634434804
+ 3.617639391707096
+ 3.617686719116859
+ 3.6177340456728104
+ 3.6177813713749933
+ 3.6178286962234476
+ 3.6178760202182176
+ 3.617923343359343
+ 3.617970665646866
+ 3.618017987080829
+ 3.618065307661274
+ 3.618112627388242
+ 3.6181599462617746
+ 3.6182072642819145
+ 3.6182545814487024
+ 3.6183018977621813
+ 3.618349213222392
+ 3.6183965278293773
+ 3.6184438415831774
+ 3.618491154483835
+ 3.618538466531392
+ 3.6185857777258903
+ 3.618633088067371
+ 3.6186803975558766
+ 3.6187277061914473
+ 3.618775013974127
+ 3.6188223209039556
+ 3.618869626980976
+ 3.6189169322052295
+ 3.618964236576758
+ 3.6190115400956024
+ 3.6190588427618056
+ 3.619106144575408
+ 3.6191534455364525
+ 3.6192007456449806
+ 3.619248044901034
+ 3.619295343304654
+ 3.619342640855882
+ 3.619389937554761
+ 3.6194372334013316
+ 3.6194845283956356
+ 3.6195318225377147
+ 3.619579115827611
+ 3.6196264082653653
+ 3.619673699851021
+ 3.619720990584618
+ 3.619768280466199
+ 3.6198155694958047
+ 3.6198628576734775
+ 3.6199101449992592
+ 3.619957431473191
+ 3.6200047170953145
+ 3.620052001865672
+ 3.620099285784305
+ 3.6201465688512537
+ 3.620193851066561
+ 3.6202411324302695
+ 3.6202884129424193
+ 3.620335692603052
+ 3.6203829714122104
+ 3.6204302493699343
+ 3.6204775264762676
+ 3.62052480273125
+ 3.6205720781349244
+ 3.6206193526873314
+ 3.6206666263885134
+ 3.620713899238512
+ 3.6207611712373677
+ 3.6208084423851234
+ 3.62085571268182
+ 3.6209029821274994
+ 3.6209502507222027
+ 3.620997518465972
+ 3.621044785358848
+ 3.621092051400874
+ 3.62113931659209
+ 3.6211865809325383
+ 3.6212338444222603
+ 3.621281107061298
+ 3.6213283688496913
+ 3.621375629787484
+ 3.6214228898747156
+ 3.6214701491114294
+ 3.6215174074976657
+ 3.6215646650334667
+ 3.6216119217188747
+ 3.621659177553929
+ 3.621706432538673
+ 3.6217536866731472
+ 3.621800939957394
+ 3.6218481923914547
+ 3.6218954439753706
+ 3.6219426947091824
+ 3.6219899445929333
+ 3.6220371936266638
+ 3.622084441810415
+ 3.6221316891442292
+ 3.622178935628148
+ 3.6222261812622127
+ 3.622273426046464
+ 3.6223206699809447
+ 3.6223679130656956
+ 3.6224151553007573
+ 3.6224623966861733
+ 3.6225096372219836
+ 3.62255687690823
+ 3.6226041157449536
+ 3.6226513537321967
+ 3.6226985908700002
+ 3.6227458271584054
+ 3.6227930625974545
+ 3.622840297187188
+ 3.6228875309276485
+ 3.622934763818876
+ 3.6229819958609135
+ 3.623029227053801
+ 3.623076457397581
+ 3.6231236868922942
+ 3.6231709155379823
+ 3.6232181433346873
+ 3.62326537028245
+ 3.6233125963813118
+ 3.6233598216313143
+ 3.623407046032499
+ 3.623454269584907
+ 3.6235014922885798
+ 3.623548714143559
+ 3.623595935149886
+ 3.623643155307602
+ 3.623690374616748
+ 3.623737593077366
+ 3.6237848106894974
+ 3.623832027453184
+ 3.623879243368466
+ 3.6239264584353847
+ 3.6239736726539835
+ 3.6240208860243013
+ 3.624068098546381
+ 3.624115310220264
+ 3.624162521045991
+ 3.6242097310236034
+ 3.624256940153143
+ 3.6243041484346508
+ 3.6243513558681677
+ 3.6243985624537363
+ 3.6244457681913964
+ 3.624492973081191
+ 3.6245401771231593
+ 3.624587380317345
+ 3.624634582663788
+ 3.62468178416253
+ 3.624728984813612
+ 3.624776184617076
+ 3.624823383572963
+ 3.624870581681314
+ 3.6249177789421703
+ 3.624964975355574
+ 3.625012170921565
+ 3.6250593656401855
+ 3.6251065595114778
+ 3.6251537525354807
+ 3.625200944712238
+ 3.6252481360417894
+ 3.6252953265241765
+ 3.6253425161594413
+ 3.6253897049476245
+ 3.6254368928887666
+ 3.62548407998291
+ 3.6255312662300954
+ 3.625578451630365
+ 3.625625636183759
+ 3.625672819890319
+ 3.6257200027500858
+ 3.6257671847631014
+ 3.625814365929407
+ 3.6258615462490433
+ 3.6259087257220513
+ 3.625955904348474
+ 3.6260030821283507
+ 3.6260502590617234
+ 3.626097435148633
+ 3.6261446103891206
+ 3.6261917847832286
+ 3.626238958330997
+ 3.6262861310324674
+ 3.626333302887681
+ 3.626380473896679
+ 3.6264276440595027
+ 3.626474813376193
+ 3.6265219818467918
+ 3.6265691494713392
+ 3.6266163162498777
+ 3.6266634821824475
+ 3.62671064726909
+ 3.6267578115098464
+ 3.6268049749047577
+ 3.6268521374538656
+ 3.626899299157211
+ 3.626946460014835
+ 3.6269936200267785
+ 3.627040779193083
+ 3.62708793751379
+ 3.6271350949889403
+ 3.6271822516185743
+ 3.6272294074027345
+ 3.627276562341461
+ 3.6273237164347956
+ 3.627370869682779
+ 3.6274180220854526
+ 3.6274651736428574
+ 3.6275123243550347
+ 3.6275594742220254
+ 3.627606623243871
+ 3.6276537714206123
+ 3.6277009187522897
+ 3.6277480652389458
+ 3.627795210880621
+ 3.627842355677356
+ 3.6278894996291924
+ 3.627936642736171
+ 3.627983784998333
+ 3.62803092641572
+ 3.628078066988372
+ 3.628125206716331
+ 3.628172345599638
+ 3.6282194836383335
+ 3.62826662083246
+ 3.628313757182056
+ 3.6283608926871653
+ 3.628408027347827
+ 3.6284551611640836
+ 3.6285022941359752
+ 3.628549426263543
+ 3.628596557546828
+ 3.628643687985872
+ 3.6286908175807153
+ 3.628737946331399
+ 3.6287850742379644
+ 3.6288322013004524
+ 3.628879327518904
+ 3.6289264528933596
+ 3.628973577423862
+ 3.6290207011104503
+ 3.629067823953167
+ 3.6291149459520518
+ 3.6291620671071465
+ 3.629209187418492
+ 3.6292563068861297
+ 3.6293034255100998
+ 3.629350543290444
+ 3.6293976602272022
+ 3.629444776320417
+ 3.6294918915701286
+ 3.6295390059763775
+ 3.6295861195392054
+ 3.6296332322586524
+ 3.6296803441347607
+ 3.6297274551675707
+ 3.629774565357123
+ 3.629821674703459
+ 3.6298687832066197
+ 3.629915890866646
+ 3.6299629976835788
+ 3.6300101036574586
+ 3.6300572087883274
+ 3.630104313076225
+ 3.630151416521193
+ 3.6301985191232724
+ 3.630245620882504
+ 3.630292721798929
+ 3.6303398218725875
+ 3.630386921103521
+ 3.6304340194917706
+ 3.6304811170373767
+ 3.630528213740381
+ 3.6305753096008235
+ 3.6306224046187454
+ 3.6306694987941888
+ 3.630716592127192
+ 3.6307636846177984
+ 3.6308107762660478
+ 3.630857867071982
+ 3.63090495703564
+ 3.630952046157065
+ 3.6309991344362955
+ 3.631046221873375
+ 3.6310933084683414
+ 3.631140394221238
+ 3.6311874791321053
+ 3.6312345632009833
+ 3.6312816464279134
+ 3.631328728812936
+ 3.631375810356093
+ 3.631422891057424
+ 3.6314699709169704
+ 3.6315170499347733
+ 3.6315641281108735
+ 3.631611205445311
+ 3.631658281938128
+ 3.6317053575893636
+ 3.631752432399061
+ 3.631799506367259
+ 3.6318465794939994
+ 3.6318936517793223
+ 3.63194072322327
+ 3.6319877938258815
+ 3.6320348635871986
+ 3.6320819325072615
+ 3.632129000586112
+ 3.6321760678237904
+ 3.6322231342203373
+ 3.6322701997757934
+ 3.6323172644902
+ 3.6323643283635976
+ 3.632411391396027
+ 3.6324584535875295
+ 3.632505514938144
+ 3.632552575447914
+ 3.6325996351168786
+ 3.632646693945079
+ 3.6326937519325555
+ 3.6327408090793494
+ 3.632787865385502
+ 3.632834920851053
+ 3.632881975476043
+ 3.632929029260514
+ 3.6329760822045056
+ 3.633023134308059
+ 3.6330701855712153
+ 3.6331172359940145
+ 3.633164285576498
+ 3.6332113343187062
+ 3.6332583822206796
+ 3.6333054292824594
+ 3.6333524755040867
+ 3.6333995208856007
+ 3.633446565427044
+ 3.6334936091284553
+ 3.633540651989877
+ 3.6335876940113496
+ 3.633634735192913
+ 3.6336817755346082
+ 3.633728815036476
+ 3.6337758536985576
+ 3.633822891520893
+ 3.6338699285035228
+ 3.6339169646464886
+ 3.63396399994983
+ 3.6340110344135885
+ 3.6340580680378043
+ 3.634105100822518
+ 3.6341521327677704
+ 3.6341991638736024
+ 3.634246194140055
+ 3.6342932235671674
+ 3.6343402521549817
+ 3.634387279903538
+ 3.6344343068128775
+ 3.6344813328830394
+ 3.634528358114066
+ 3.634575382505997
+ 3.6346224060588734
+ 3.634669428772736
+ 3.634716450647625
+ 3.6347634716835815
+ 3.634810491880645
+ 3.6348575112388577
+ 3.6349045297582587
+ 3.6349515474388903
+ 3.6349985642807914
+ 3.635045580284004
+ 3.6350925954485676
+ 3.6351396097745234
+ 3.6351866232619123
+ 3.635233635910774
+ 3.63528064772115
+ 3.6353276586930803
+ 3.6353746688266053
+ 3.6354216781217668
+ 3.635468686578604
+ 3.6355156941971583
+ 3.635562700977469
+ 3.635609706919579
+ 3.635656712023527
+ 3.635703716289354
+ 3.635750719717101
+ 3.6357977223068074
+ 3.6358447240585154
+ 3.635891724972264
+ 3.6359387250480952
+ 3.6359857242860483
+ 3.636032722686165
+ 3.636079720248484
+ 3.636126716973048
+ 3.6361737128598963
+ 3.63622070790907
+ 3.6362677021206085
+ 3.6363146954945536
+ 3.6363616880309455
+ 3.6364086797298247
+ 3.636455670591231
+ 3.6365026606152058
+ 3.6365496498017897
+ 3.6365966381510217
+ 3.6366436256629444
+ 3.6366906123375973
+ 3.6367375981750207
+ 3.6367845831752548
+ 3.636831567338341
+ 3.6368785506643193
+ 3.6369255331532306
+ 3.636972514805115
+ 3.6370194956200126
+ 3.637066475597964
+ 3.6371134547390107
+ 3.6371604330431917
+ 3.6372074105105487
+ 3.637254387141121
+ 3.6373013629349504
+ 3.637348337892076
+ 3.6373953120125395
+ 3.637442285296381
+ 3.6374892577436393
+ 3.637536229354357
+ 3.637583200128574
+ 3.63763017006633
+ 3.6376771391676663
+ 3.6377241074326228
+ 3.6377710748612393
+ 3.637818041453558
+ 3.637865007209618
+ 3.6379119721294604
+ 3.637958936213124
+ 3.6380058994606514
+ 3.638052861872082
+ 3.6380998234474564
+ 3.638146784186814
+ 3.638193744090197
+ 3.638240703157644
+ 3.638287661389197
+ 3.638334618784895
+ 3.6383815753447792
+ 3.63842853106889
+ 3.6384754859572666
+ 3.638522440009951
+ 3.6385693932269825
+ 3.6386163456084026
+ 3.6386632971542503
+ 3.6387102478645668
+ 3.638757197739392
+ 3.638804146778767
+ 3.638851094982731
+ 3.6388980423513253
+ 3.6389449888845897
+ 3.638991934582565
+ 3.639038879445291
+ 3.6390858234728087
+ 3.6391327666651576
+ 3.639179709022379
+ 3.6392266505445128
+ 3.639273591231598
+ 3.639320531083678
+ 3.63936747010079
+ 3.639414408282976
+ 3.6394613456302753
+ 3.63950828214273
+ 3.6395552178203783
+ 3.6396021526632616
+ 3.6396490866714197
+ 3.6396960198448935
+ 3.639742952183723
+ 3.6397898836879485
+ 3.63983681435761
+ 3.639883744192749
+ 3.6399306731934034
+ 3.639977601359616
+ 3.6400245286914252
+ 3.640071455188872
+ 3.6401183808519977
+ 3.6401653056808403
+ 3.6402122296754422
+ 3.6402591528358426
+ 3.6403060751620813
+ 3.6403529966542
+ 3.6403999173122377
+ 3.640446837136235
+ 3.6404937561262325
+ 3.6405406742822692
+ 3.6405875916043873
+ 3.6406345080926257
+ 3.640681423747025
+ 3.640728338567625
+ 3.6407752525544668
+ 3.6408221657075894
+ 3.640869078027034
+ 3.6409159895128407
+ 3.6409629001650496
+ 3.6410098099837005
+ 3.641056718968834
+ 3.641103627120491
+ 3.64115053443871
+ 3.641197440923532
+ 3.6412443465749975
+ 3.6412912513931466
+ 3.641338155378019
+ 3.641385058529656
+ 3.641431960848096
+ 3.6414788623333814
+ 3.64152576298555
+ 3.641572662804644
+ 3.641619561790702
+ 3.6416664599437656
+ 3.6417133572638734
+ 3.641760253751067
+ 3.641807149405386
+ 3.6418540442268696
+ 3.6419009382155596
+ 3.6419478313714952
+ 3.6419947236947166
+ 3.6420416151852635
+ 3.6420885058431773
+ 3.642135395668497
+ 3.642182284661264
+ 3.642229172821516
+ 3.6422760601492956
+ 3.642322946644642
+ 3.6423698323075953
+ 3.642416717138195
+ 3.642463601136482
+ 3.6425104843024965
+ 3.6425573666362783
+ 3.642604248137867
+ 3.6426511288073042
+ 3.642698008644628
+ 3.64274488764988
+ 3.6427917658230995
+ 3.642838643164327
+ 3.6428855196736025
+ 3.642932395350966
+ 3.6429792701964567
+ 3.643026144210116
+ 3.643073017391984
+ 3.6431198897421
+ 3.6431667612605043
+ 3.6432136319472366
+ 3.643260501802338
+ 3.6433073708258474
+ 3.643354239017806
+ 3.6434011063782523
+ 3.6434479729072273
+ 3.6434948386047714
+ 3.6435417034709237
+ 3.6435885675057254
+ 3.6436354307092156
+ 3.643682293081434
+ 3.6437291546224215
+ 3.643776015332218
+ 3.643822875210863
+ 3.643869734258397
+ 3.64391659247486
+ 3.6439634498602924
+ 3.644010306414733
+ 3.644057162138222
+ 3.6441040170308003
+ 3.6441508710925077
+ 3.6441977243233836
+ 3.6442445767234686
+ 3.644291428292802
+ 3.6443382790314245
+ 3.6443851289393754
+ 3.6444319780166956
+ 3.6444788262634242
+ 3.6445256736796012
+ 3.6445725202652675
+ 3.6446193660204615
+ 3.644666210945225
+ 3.6447130550395963
+ 3.6447598983036165
+ 3.644806740737325
+ 3.6448535823407617
+ 3.644900423113967
+ 3.6449472630569804
+ 3.6449941021698415
+ 3.6450409404525916
+ 3.6450877779052693
+ 3.6451346145279153
+ 3.6451814503205684
+ 3.6452282852832703
+ 3.645275119416059
+ 3.6453219527189766
+ 3.6453687851920606
+ 3.6454156168353524
+ 3.6454624476488924
+ 3.6455092776327183
+ 3.6455561067868727
+ 3.645602935111393
+ 3.6456497626063213
+ 3.6456965892716955
+ 3.645743415107557
+ 3.645790240113945
+ 3.6458370642909
+ 3.645883887638461
+ 3.6459307101566685
+ 3.6459775318455616
+ 3.646024352705181
+ 3.6460711727355664
+ 3.6461179919367575
+ 3.646164810308794
+ 3.646211627851716
+ 3.6462584445655635
+ 3.646305260450376
+ 3.6463520755061936
+ 3.6463988897330557
+ 3.6464457031310027
+ 3.6464925157000745
+ 3.64653932744031
+ 3.64658613835175
+ 3.646632948434435
+ 3.646679757688402
+ 3.6467265661136943
+ 3.646773373710349
+ 3.6468201804784077
+ 3.646866986417909
+ 3.6469137915288936
+ 3.6469605958114
+ 3.64700739926547
+ 3.6470542018911423
+ 3.647101003688456
+ 3.6471478046574517
+ 3.647194604798169
+ 3.6472414041106487
+ 3.647288202594929
+ 3.6473350002510503
+ 3.6473817970790523
+ 3.6474285930789754
+ 3.647475388250858
+ 3.647522182594742
+ 3.6475689761106653
+ 3.647615768798668
+ 3.6476625606587905
+ 3.6477093516910717
+ 3.6477561418955524
+ 3.6478029312722713
+ 3.6478497198212687
+ 3.6478965075425847
+ 3.6479432944362586
+ 3.6479900805023293
+ 3.6480368657408384
+ 3.648083650151824
+ 3.648130433735327
+ 3.6481772164913857
+ 3.648223998420041
+ 3.6482707795213325
+ 3.6483175597953
+ 3.6483643392419824
+ 3.64841111786142
+ 3.6484578956536526
+ 3.6485046726187202
+ 3.6485514487566615
+ 3.6485982240675168
+ 3.6486449985513256
+ 3.648691772208128
+ 3.6487385450379635
+ 3.6487853170408715
+ 3.648832088216892
+ 3.6488788585660643
+ 3.6489256280884286
+ 3.6489723967840244
+ 3.6490191646528913
+ 3.6490659316950684
+ 3.6491126979105966
+ 3.649159463299514
+ 3.6492062278618618
+ 3.649252991597679
+ 3.6492997545070054
+ 3.6493465165898797
+ 3.6493932778463427
+ 3.649440038276434
+ 3.6494867978801926
+ 3.649533556657658
+ 3.649580314608871
+ 3.6496270717338697
+ 3.6496738280326952
+ 3.6497205835053865
+ 3.649767338151982
+ 3.649814091972524
+ 3.64986084496705
+ 3.6499075971356
+ 3.649954348478214
+ 3.650001098994931
+ 3.6500478486857912
+ 3.6500945975508343
+ 3.6501413455900993
+ 3.650188092803626
+ 3.6502348391914543
+ 3.650281584753624
+ 3.650328329490173
+ 3.6503750734011433
+ 3.6504218164865723
+ 3.6504685587465016
+ 3.650515300180969
+ 3.6505620407900152
+ 3.6506087805736795
+ 3.650655519532001
+ 3.6507022576650194
+ 3.6507489949727745
+ 3.650795731455306
+ 3.6508424671126534
+ 3.6508892019448558
+ 3.650935935951953
+ 3.6509826691339846
+ 3.65102940149099
+ 3.6510761330230093
+ 3.651122863730081
+ 3.6511695936122455
+ 3.6512163226695415
+ 3.65126305090201
+ 3.651309778309688
+ 3.651356504892618
+ 3.6514032306508377
+ 3.651449955584387
+ 3.6514966796933055
+ 3.651543402977632
+ 3.6515901254374072
+ 3.6516368470726692
+ 3.651683567883459
+ 3.6517302878698152
+ 3.6517770070317774
+ 3.651823725369385
+ 3.651870442882678
+ 3.651917159571695
+ 3.651963875436476
+ 3.6520105904770603
+ 3.652057304693488
+ 3.6521040180857978
+ 3.6521507306540295
+ 3.652197442398222
+ 3.652244153318416
+ 3.6522908634146503
+ 3.6523375726869634
+ 3.652384281135396
+ 3.6524309887599866
+ 3.6524776955607763
+ 3.6525244015378022
+ 3.6525711066911057
+ 3.652617811020725
+ 3.6526645145267005
+ 3.6527112172090703
+ 3.6527579190678754
+ 3.6528046201031543
+ 3.6528513203149466
+ 3.652898019703291
+ 3.6529447182682286
+ 3.652991416009797
+ 3.6530381129280367
+ 3.6530848090229866
+ 3.653131504294687
+ 3.653178198743176
+ 3.653224892368494
+ 3.6532715851706796
+ 3.6533182771497725
+ 3.6533649683058123
+ 3.653411658638838
+ 3.6534583481488894
+ 3.6535050368360054
+ 3.653551724700226
+ 3.65359841174159
+ 3.653645097960137
+ 3.653691783355906
+ 3.653738467928937
+ 3.653785151679269
+ 3.6538318346069416
+ 3.653878516711994
+ 3.653925197994465
+ 3.653971878454394
+ 3.654018558091822
+ 3.6540652369067863
+ 3.6541119148993273
+ 3.6541585920694835
+ 3.654205268417295
+ 3.654251943942801
+ 3.654298618646041
+ 3.654345292527054
+ 3.6543919655858783
+ 3.6544386378225555
+ 3.6544853092371232
+ 3.654531979829621
+ 3.6545786496000887
+ 3.654625318548565
+ 3.6546719866750896
+ 3.654718653979702
+ 3.6547653204624404
+ 3.6548119861233452
+ 3.6548586509624554
+ 3.6549053149798105
+ 3.654951978175449
+ 3.654998640549411
+ 3.6550453021017346
+ 3.6550919628324605
+ 3.6551386227416276
+ 3.655185281829274
+ 3.6552319400954407
+ 3.655278597540166
+ 3.6553252541634893
+ 3.6553719099654494
+ 3.655418564946087
+ 3.655465219105439
+ 3.6555118724435465
+ 3.655558524960448
+ 3.655605176656183
+ 3.6556518275307908
+ 3.655698477584311
+ 3.6557451268167815
+ 3.6557917752282427
+ 3.6558384228187335
+ 3.655885069588293
+ 3.6559317155369606
+ 3.6559783606647747
+ 3.656025004971776
+ 3.6560716484580023
+ 3.6561182911234935
+ 3.6561649329682893
+ 3.6562115739924277
+ 3.6562582141959483
+ 3.656304853578891
+ 3.6563514921412943
+ 3.656398129883198
+ 3.6564447668046403
+ 3.6564914029056608
+ 3.6565380381862984
+ 3.6565846726465936
+ 3.656631306286584
+ 3.65667793910631
+ 3.6567245711058094
+ 3.6567712022851224
+ 3.656817832644288
+ 3.6568644621833446
+ 3.6569110909023324
+ 3.65695771880129
+ 3.657004345880256
+ 3.657050972139271
+ 3.6570975975783733
+ 3.6571442221976014
+ 3.6571908459969955
+ 3.6572374689765943
+ 3.6572840911364373
+ 3.6573307124765626
+ 3.6573773329970103
+ 3.657423952697819
+ 3.657470571579028
+ 3.657517189640677
+ 3.6575638068828034
+ 3.657610423305448
+ 3.657657038908649
+ 3.6577036536924465
+ 3.657750267656878
+ 3.657796880801984
+ 3.657843493127803
+ 3.657890104634374
+ 3.6579367153217364
+ 3.6579833251899294
+ 3.6580299342389915
+ 3.658076542468962
+ 3.65812314987988
+ 3.6581697564717848
+ 3.658216362244715
+ 3.65826296719871
+ 3.6583095713338087
+ 3.658356174650051
+ 3.658402777147474
+ 3.658449378826119
+ 3.6584959796860237
+ 3.658542579727227
+ 3.658589178949769
+ 3.658635777353687
+ 3.6586823749390223
+ 3.6587289717058122
+ 3.658775567654096
+ 3.6588221627839133
+ 3.6588687570953033
+ 3.6589153505883036
+ 3.658961943262955
+ 3.6590085351192956
+ 3.6590551261573645
+ 3.6591017163772
+ 3.6591483057788428
+ 3.6591948943623303
+ 3.659241482127702
+ 3.6592880690749974
+ 3.6593346552042543
+ 3.6593812405155135
+ 3.659427825008812
+ 3.6594744086841904
+ 3.6595209915416866
+ 3.65956757358134
+ 3.6596141548031897
+ 3.6596607352072748
+ 3.6597073147936334
+ 3.6597538935623057
+ 3.6598004715133294
+ 3.6598470486467445
+ 3.659893624962589
+ 3.659940200460903
+ 3.6599867751417245
+ 3.6600333490050927
+ 3.6600799220510467
+ 3.6601264942796257
+ 3.6601730656908678
+ 3.6602196362848125
+ 3.660266206061499
+ 3.660312775020965
+ 3.6603593431632513
+ 3.6604059104883953
+ 3.6604524769964364
+ 3.6604990426874138
+ 3.660545607561366
+ 3.6605921716183323
+ 3.660638734858351
+ 3.6606852972814616
+ 3.6607318588877025
+ 3.660778419677113
+ 3.6608249796497323
+ 3.6608715388055986
+ 3.6609180971447515
+ 3.6609646546672283
+ 3.66101121137307
+ 3.661057767262314
+ 3.661104322335
+ 3.6611508765911664
+ 3.6611974300308523
+ 3.661243982654096
+ 3.661290534460937
+ 3.6613370854514145
+ 3.6613836356255667
+ 3.6614301849834323
+ 3.6614767335250504
+ 3.6615232812504606
+ 3.6615698281597
+ 3.6616163742528096
+ 3.6616629195298267
+ 3.6617094639907903
+ 3.6617560076357396
+ 3.6618025504647136
+ 3.6618490924777505
+ 3.66189563367489
+ 3.66194217405617
+ 3.66198871362163
+ 3.6620352523713082
+ 3.662081790305244
+ 3.662128327423476
+ 3.662174863726043
+ 3.6622213992129837
+ 3.6622679338843365
+ 3.662314467740141
+ 3.6623610007804364
+ 3.66240753300526
+ 3.6624540644146513
+ 3.6625005950086496
+ 3.6625471247872925
+ 3.66259365375062
+ 3.66264018189867
+ 3.6626867092314823
+ 3.662733235749095
+ 3.6627797614515463
+ 3.6628262863388756
+ 3.662872810411122
+ 3.6629193336683237
+ 3.6629658561105196
+ 3.6630123777377483
+ 3.663058898550049
+ 3.66310541854746
+ 3.66315193773002
+ 3.663198456097768
+ 3.663244973650743
+ 3.6632914903889833
+ 3.6633380063125274
+ 3.6633845214214147
+ 3.6634310357156834
+ 3.6634775491953726
+ 3.663524061860521
+ 3.663570573711167
+ 3.6636170847473495
+ 3.663663594969107
+ 3.663710104376479
+ 3.6637566129695025
+ 3.6638031207482182
+ 3.6638496277126635
+ 3.6638961338628775
+ 3.663942639198899
+ 3.663989143720767
+ 3.6640356474285185
+ 3.6640821503221943
+ 3.6641286524018324
+ 3.664175153667471
+ 3.6642216541191486
+ 3.6642681537569053
+ 3.6643146525807784
+ 3.664361150590807
+ 3.664407647787029
+ 3.664454144169485
+ 3.6645006397382116
+ 3.6645471344932483
+ 3.6645936284346345
+ 3.664640121562407
+ 3.664686613876606
+ 3.66473310537727
+ 3.664779596064437
+ 3.664826085938146
+ 3.664872574998436
+ 3.6649190632453448
+ 3.664965550678912
+ 3.665012037299175
+ 3.665058523106173
+ 3.665105008099945
+ 3.665151492280529
+ 3.6651979756479642
+ 3.6652444582022894
+ 3.665290939943542
+ 3.665337420871762
+ 3.6653839009869866
+ 3.6654303802892554
+ 3.665476858778607
+ 3.665523336455079
+ 3.665569813318712
+ 3.665616289369542
+ 3.66566276460761
+ 3.6657092390329526
+ 3.6657557126456095
+ 3.6658021854456186
+ 3.66584865743302
+ 3.6658951286078496
+ 3.6659415989701487
+ 3.665988068519954
+ 3.666034537257305
+ 3.6660810051822397
+ 3.6661274722947974
+ 3.6661739385950156
+ 3.666220404082934
+ 3.66626686875859
+ 3.666313332622023
+ 3.6663597956732716
+ 3.666406257912373
+ 3.6664527193393672
+ 3.6664991799542923
+ 3.666545639757187
+ 3.666592098748089
+ 3.666638556927038
+ 3.6666850142940715
+ 3.6667314708492285
+ 3.666777926592547
+ 3.666824381524066
+ 3.6668708356438247
+ 3.6669172889518604
+ 3.6669637414482117
+ 3.667010193132918
+ 3.6670566440060166
+ 3.667103094067547
+ 3.6671495433175476
+ 3.667195991756056
+ 3.6672424393831116
+ 3.6672888861987523
+ 3.667335332203017
+ 3.667381777395944
+ 3.6674282217775716
+ 3.6674746653479384
+ 3.6675211081070827
+ 3.667567550055043
+ 3.6676139911918586
+ 3.6676604315175667
+ 3.6677068710322067
+ 3.6677533097358164
+ 3.6677997476284343
+ 3.6678461847100987
+ 3.667892620980849
+ 3.6679390564407233
+ 3.667985491089759
+ 3.668031924927996
+ 3.668078357955471
+ 3.668124790172224
+ 3.6681712215782922
+ 3.6682176521737158
+ 3.668264081958531
+ 3.6683105109327774
+ 3.6683569390964936
+ 3.668403366449718
+ 3.668449792992488
+ 3.668496218724843
+ 3.668542643646821
+ 3.668589067758461
+ 3.6686354910598
+ 3.668681913550878
+ 3.668728335231732
+ 3.6687747561024016
+ 3.668821176162924
+ 3.6688675954133383
+ 3.668914013853683
+ 3.668960431483996
+ 3.669006848304316
+ 3.669053264314681
+ 3.6690996795151305
+ 3.669146093905701
+ 3.669192507486432
+ 3.669238920257362
+ 3.6692853322185286
+ 3.669331743369971
+ 3.669378153711727
+ 3.669424563243835
+ 3.669470971966333
+ 3.66951737987926
+ 3.6695637869826543
+ 3.6696101932765535
+ 3.669656598760997
+ 3.6697030034360223
+ 3.6697494073016674
+ 3.6697958103579715
+ 3.669842212604973
+ 3.66988861404271
+ 3.6699350146712195
+ 3.669981414490542
+ 3.6700278135007136
+ 3.670074211701774
+ 3.670120609093762
+ 3.6701670056767144
+ 3.6702134014506704
+ 3.670259796415668
+ 3.670306190571745
+ 3.6703525839189415
+ 3.6703989764572933
+ 3.67044536818684
+ 3.6704917591076205
+ 3.6705381492196723
+ 3.6705845385230327
+ 3.670630927017742
+ 3.670677314703837
+ 3.6707237015813563
+ 3.670770087650338
+ 3.670816472910821
+ 3.670862857362843
+ 3.6709092410064423
+ 3.670955623841657
+ 3.6710020058685258
+ 3.671048387087087
+ 3.671094767497378
+ 3.6711411470994384
+ 3.671187525893304
+ 3.671233903879016
+ 3.671280281056611
+ 3.6713266574261274
+ 3.671373032987603
+ 3.671419407741077
+ 3.6714657816865874
+ 3.671512154824171
+ 3.6715585271538678
+ 3.671604898675715
+ 3.6716512693897516
+ 3.671697639296015
+ 3.6717440083945436
+ 3.671790376685376
+ 3.6718367441685493
+ 3.671883110844103
+ 3.6719294767120747
+ 3.6719758417725026
+ 3.672022206025425
+ 3.6720685694708797
+ 3.6721149321089053
+ 3.6721612939395394
+ 3.6722076549628206
+ 3.6722540151787877
+ 3.6723003745874774
+ 3.6723467331889292
+ 3.67239309098318
+ 3.6724394479702696
+ 3.6724858041502344
+ 3.6725321595231133
+ 3.672578514088945
+ 3.6726248678477664
+ 3.6726712207996166
+ 3.6727175729445336
+ 3.672763924282555
+ 3.67281027481372
+ 3.672856624538065
+ 3.67290297345563
+ 3.6729493215664517
+ 3.6729956688705694
+ 3.6730420153680203
+ 3.6730883610588427
+ 3.673134705943075
+ 3.6731810500207547
+ 3.6732273932919206
+ 3.67327373575661
+ 3.673320077414862
+ 3.673366418266714
+ 3.6734127583122045
+ 3.6734590975513703
+ 3.673505435984252
+ 3.673551773610885
+ 3.6735981104313096
+ 3.673644446445562
+ 3.6736907816536815
+ 3.673737116055706
+ 3.6737834496516726
+ 3.673829782441621
+ 3.673876114425588
+ 3.6739224456036115
+ 3.6739687759757307
+ 3.6740151055419825
+ 3.674061434302406
+ 3.6741077622570386
+ 3.674154089405918
+ 3.674200415749083
+ 3.6742467412865714
+ 3.674293066018421
+ 3.6743393899446697
+ 3.6743857130653566
+ 3.6744320353805184
+ 3.6744783568901935
+ 3.6745246775944205
+ 3.6745709974932366
+ 3.6746173165866796
+ 3.6746636348747894
+ 3.6747099523576012
+ 3.674756269035156
+ 3.674802584907489
+ 3.6748488999746405
+ 3.674895214236647
+ 3.674941527693547
+ 3.674987840345379
+ 3.675034152192179
+ 3.6750804632339875
+ 3.6751267734708413
+ 3.6751730829027784
+ 3.675219391529837
+ 3.6752656993520545
+ 3.6753120063694693
+ 3.67535831258212
+ 3.675404617990043
+ 3.675450922593278
+ 3.6754972263918617
+ 3.6755435293858327
+ 3.675589831575228
+ 3.6756361329600873
+ 3.6756824335404468
+ 3.6757287333163453
+ 3.6757750322878207
+ 3.6758213304549106
+ 3.6758676278176536
+ 3.6759139243760868
+ 3.6759602201302486
+ 3.676006515080177
+ 3.6760528092259097
+ 3.676099102567484
+ 3.676145395104939
+ 3.6761916868383118
+ 3.6762379777676415
+ 3.676284267892964
+ 3.676330557214319
+ 3.676376845731743
+ 3.6764231334452755
+ 3.676469420354953
+ 3.676515706460814
+ 3.676561991762896
+ 3.6766082762612373
+ 3.6766545599558764
+ 3.676700842846849
+ 3.6767471249341956
+ 3.6767934062179526
+ 3.6768396866981576
+ 3.6768859663748494
+ 3.6769322452480653
+ 3.6769785233178434
+ 3.677024800584222
+ 3.6770710770472377
+ 3.67711735270693
+ 3.677163627563335
+ 3.6772099016164916
+ 3.677256174866437
+ 3.67730244731321
+ 3.677348718956848
+ 3.6773949897973885
+ 3.6774412598348696
+ 3.6774875290693294
+ 3.677533797500806
+ 3.677580065129335
+ 3.677626331954957
+ 3.6776725979777085
+ 3.6777188631976276
+ 3.6777651276147516
+ 3.6778113912291195
+ 3.6778576540407677
+ 3.6779039160497353
+ 3.6779501772560588
+ 3.6779964376597767
+ 3.678042697260927
+ 3.678088956059547
+ 3.678135214055675
+ 3.6781814712493484
+ 3.678227727640605
+ 3.6782739832294826
+ 3.678320238016019
+ 3.6783664920002526
+ 3.67841274518222
+ 3.6784589975619597
+ 3.67850524913951
+ 3.678551499914907
+ 3.67859774988819
+ 3.678643999059396
+ 3.678690247428563
+ 3.678736494995729
+ 3.6787827417609313
+ 3.6788289877242075
+ 3.678875232885596
+ 3.6789214772451335
+ 3.6789677208028593
+ 3.6790139635588095
+ 3.6790602055130237
+ 3.6791064466655374
+ 3.6791526870163898
+ 3.679198926565619
+ 3.6792451653132607
+ 3.679291403259355
+ 3.6793376404039377
+ 3.6793838767470475
+ 3.6794301122887223
+ 3.6794763470289995
+ 3.6795225809679164
+ 3.6795688141055107
+ 3.679615046441821
+ 3.679661277976884
+ 3.6797075087107385
+ 3.679753738643421
+ 3.6797999677749695
+ 3.6798461961054225
+ 3.6798924236348163
+ 3.67993865036319
+ 3.6799848762905802
+ 3.680031101417025
+ 3.6800773257425625
+ 3.6801235492672295
+ 3.6801697719910638
+ 3.6802159939141035
+ 3.6802622150363864
+ 3.6803084353579494
+ 3.680354654878831
+ 3.6804008735990683
+ 3.680447091518699
+ 3.6804933086377605
+ 3.6805395249562913
+ 3.6805857404743283
+ 3.6806319551919096
+ 3.6806781691090715
+ 3.6807243822258533
+ 3.680770594542292
+ 3.6808168060584254
+ 3.680863016774291
+ 3.680909226689926
+ 3.6809554358053687
+ 3.681001644120656
+ 3.6810478516358263
+ 3.6810940583509164
+ 3.6811402642659647
+ 3.681186469381008
+ 3.6812326736960843
+ 3.681278877211231
+ 3.681325079926486
+ 3.681371281841887
+ 3.6814174829574715
+ 3.6814636832732766
+ 3.68150988278934
+ 3.681556081505699
+ 3.681602279422393
+ 3.6816484765394573
+ 3.6816946728569304
+ 3.68174086837485
+ 3.6817870630932537
+ 3.681833257012179
+ 3.6818794501316625
+ 3.6819256424517426
+ 3.681971833972457
+ 3.6820180246938436
+ 3.6820642146159392
+ 3.6821104037387813
+ 3.682156592062408
+ 3.6822027795868557
+ 3.682248966312163
+ 3.682295152238368
+ 3.6823413373655067
+ 3.6823875216936175
+ 3.6824337052227376
+ 3.682479887952905
+ 3.6825260698841564
+ 3.6825722510165297
+ 3.682618431350063
+ 3.682664610884793
+ 3.682710789620758
+ 3.682756967557994
+ 3.6828031446965404
+ 3.6828493210364335
+ 3.6828954965777108
+ 3.68294167132041
+ 3.6829878452645692
+ 3.683034018410225
+ 3.6830801907574156
+ 3.683126362306177
+ 3.683172533056549
+ 3.6832187030085675
+ 3.68326487216227
+ 3.683311040517694
+ 3.683357208074878
+ 3.6834033748338584
+ 3.6834495407946726
+ 3.683495705957359
+ 3.683541870321954
+ 3.6835880338884963
+ 3.683634196657022
+ 3.683680358627569
+ 3.683726519800174
+ 3.6837726801748767
+ 3.6838188397517126
+ 3.6838649985307197
+ 3.683911156511935
+ 3.6839573136953967
+ 3.6840034700811413
+ 3.684049625669207
+ 3.6840957804596313
+ 3.684141934452451
+ 3.6841880876477036
+ 3.684234240045427
+ 3.684280391645658
+ 3.6843265424484346
+ 3.6843726924537936
+ 3.6844188416617727
+ 3.6844649900724096
+ 3.684511137685741
+ 3.684557284501805
+ 3.6846034305206383
+ 3.6846495757422786
+ 3.6846957201667636
+ 3.6847418637941307
+ 3.6847880066244163
+ 3.6848341486576586
+ 3.684880289893895
+ 3.6849264303331624
+ 3.6849725699754985
+ 3.6850187088209405
+ 3.6850648468695257
+ 3.685110984121292
+ 3.6851571205762768
+ 3.6852032562345163
+ 3.6852493910960487
+ 3.6852955251609107
+ 3.6853416584291407
+ 3.685387790900775
+ 3.6854339225758523
+ 3.685480053454408
+ 3.685526183536481
+ 3.685572312822108
+ 3.6856184413113264
+ 3.6856645690041736
+ 3.6857106959006867
+ 3.685756822000903
+ 3.68580294730486
+ 3.685849071812595
+ 3.685895195524146
+ 3.6859413184395486
+ 3.6859874405588413
+ 3.6860335618820614
+ 3.6860796824092463
+ 3.6861258021404324
+ 3.6861719210756574
+ 3.686218039214959
+ 3.6862641565583742
+ 3.6863102731059407
+ 3.686356388857695
+ 3.6864025038136745
+ 3.686448617973917
+ 3.6864947313384597
+ 3.686540843907339
+ 3.6865869556805935
+ 3.6866330666582594
+ 3.6866791768403746
+ 3.6867252862269755
+ 3.6867713948181007
+ 3.686817502613786
+ 3.68686360961407
+ 3.686909715818989
+ 3.6869558212285805
+ 3.687001925842882
+ 3.68704802966193
+ 3.6870941326857625
+ 3.6871402349144162
+ 3.6871863363479287
+ 3.6872324369863367
+ 3.687278536829679
+ 3.6873246358779905
+ 3.68737073413131
+ 3.687416831589674
+ 3.68746292825312
+ 3.6875090241216855
+ 3.6875551191954075
+ 3.6876012134743226
+ 3.6876473069584685
+ 3.6876933996478822
+ 3.6877394915426014
+ 3.687785582642663
+ 3.687831672948104
+ 3.687877762458962
+ 3.687923851175274
+ 3.6879699390970764
+ 3.6880160262244073
+ 3.6880621125573034
+ 3.6881081980958026
+ 3.688154282839941
+ 3.688200366789757
+ 3.6882464499452867
+ 3.6882925323065674
+ 3.688338613873637
+ 3.6883846946465315
+ 3.688430774625289
+ 3.688476853809947
+ 3.6885229322005415
+ 3.6885690097971096
+ 3.688615086599689
+ 3.6886611626083172
+ 3.6887072378230314
+ 3.688753312243868
+ 3.6887993858708636
+ 3.6888454587040567
+ 3.6888915307434837
+ 3.688937601989182
+ 3.6889836724411884
+ 3.68902974209954
+ 3.6890758109642743
+ 3.6891218790354285
+ 3.6891679463130385
+ 3.6892140127971436
+ 3.689260078487778
+ 3.6893061433849814
+ 3.68935220748879
+ 3.6893982707992405
+ 3.68944433331637
+ 3.6894903950402163
+ 3.6895364559708157
+ 3.6895825161082056
+ 3.6896285754524234
+ 3.6896746340035054
+ 3.6897206917614893
+ 3.6897667487264116
+ 3.6898128048983105
+ 3.689858860277222
+ 3.6899049148631833
+ 3.6899509686562317
+ 3.689997021656404
+ 3.6900430738637375
+ 3.6900891252782695
+ 3.6901351759000365
+ 3.690181225729076
+ 3.6902272747654243
+ 3.690273323009119
+ 3.6903193704601973
+ 3.690365417118696
+ 3.690411462984652
+ 3.6904575080581026
+ 3.6905035523390843
+ 3.6905495958276346
+ 3.690595638523791
+ 3.690641680427589
+ 3.690687721539067
+ 3.6907337618582616
+ 3.69077980138521
+ 3.690825840119948
+ 3.6908718780625143
+ 3.690917915212945
+ 3.6909639515712773
+ 3.691009987137548
+ 3.691056021911794
+ 3.691102055894053
+ 3.691148089084361
+ 3.6911941214827553
+ 3.691240153089274
+ 3.6912861839039524
+ 3.691332213926828
+ 3.691378243157938
+ 3.69142427159732
+ 3.691470299245009
+ 3.691516326101044
+ 3.6915623521654615
+ 3.691608377438298
+ 3.6916544019195903
+ 3.6917004256093757
+ 3.691746448507691
+ 3.691792470614573
+ 3.69183849193006
+ 3.6918845124541866
+ 3.6919305321869915
+ 3.6919765511285108
+ 3.6920225692787816
+ 3.6920685866378413
+ 3.6921146032057264
+ 3.6921606189824745
+ 3.6922066339681208
+ 3.692252648162704
+ 3.6922986615662596
+ 3.6923446741788255
+ 3.6923906860004387
+ 3.6924366970311358
+ 3.692482707270953
+ 3.692528716719928
+ 3.6925747253780976
+ 3.692620733245499
+ 3.6926667403221685
+ 3.6927127466081435
+ 3.69275875210346
+ 3.692804756808156
+ 3.692850760722267
+ 3.692896763845831
+ 3.6929427661788847
+ 3.6929887677214652
+ 3.6930347684736087
+ 3.6930807684353524
+ 3.6931267676067336
+ 3.6931727659877884
+ 3.6932187635785536
+ 3.693264760379067
+ 3.693310756389365
+ 3.693356751609483
+ 3.6934027460394607
+ 3.6934487396793325
+ 3.6934947325291367
+ 3.693540724588909
+ 3.6935867158586877
+ 3.6936327063385077
+ 3.693678696028407
+ 3.6937246849284224
+ 3.693770673038591
+ 3.6938166603589493
+ 3.6938626468895337
+ 3.693908632630382
+ 3.6939546175815297
+ 3.694000601743014
+ 3.6940465851148727
+ 3.6940925676971412
+ 3.6941385494898573
+ 3.694184530493058
+ 3.694230510706779
+ 3.694276490131058
+ 3.6943224687659315
+ 3.6943684466114357
+ 3.694414423667608
+ 3.694460399934486
+ 3.6945063754121046
+ 3.6945523501005018
+ 3.694598323999714
+ 3.694644297109779
+ 3.694690269430732
+ 3.6947362409626106
+ 3.694782211705451
+ 3.6948281816592905
+ 3.694874150824166
+ 3.6949201192001135
+ 3.6949660867871708
+ 3.6950120535853737
+ 3.6950580195947595
+ 3.6951039848153644
+ 3.695149949247226
+ 3.6951959128903797
+ 3.6952418757448635
+ 3.6952878378107137
+ 3.695333799087967
+ 3.6953797595766598
+ 3.69542571927683
+ 3.695471678188513
+ 3.695517636311746
+ 3.6955635936465656
+ 3.6956095501930086
+ 3.6956555059511116
+ 3.6957014609209113
+ 3.695747415102445
+ 3.6957933684957487
+ 3.6958393211008596
+ 3.6958852729178133
+ 3.695931223946648
+ 3.6959771741873992
+ 3.696023123640105
+ 3.6960690723048004
+ 3.696115020181523
+ 3.696160967270309
+ 3.696206913571196
+ 3.6962528590842196
+ 3.6962988038094173
+ 3.6963447477468248
+ 3.69639069089648
+ 3.6964366332584184
+ 3.6964825748326775
+ 3.6965285156192937
+ 3.6965744556183036
+ 3.6966203948297434
+ 3.6966663332536505
+ 3.6967122708900613
+ 3.6967582077390118
+ 3.6968041438005397
+ 3.6968500790746814
+ 3.6968960135614726
+ 3.696941947260951
+ 3.6969878801731526
+ 3.6970338122981143
+ 3.697079743635873
+ 3.697125674186464
+ 3.697171603949926
+ 3.697217532926294
+ 3.697263461115605
+ 3.6973093885178967
+ 3.697355315133204
+ 3.697401240961564
+ 3.697447166003014
+ 3.6974930902575895
+ 3.6975390137253283
+ 3.6975849364062663
+ 3.6976308583004402
+ 3.6976767794078866
+ 3.697722699728642
+ 3.6977686192627433
+ 3.6978145380102263
+ 3.697860455971129
+ 3.6979063731454858
+ 3.6979522895333354
+ 3.6979982051347133
+ 3.6980441199496568
+ 3.698090033978201
+ 3.6981359472203836
+ 3.6981818596762417
+ 3.6982277713458105
+ 3.6982736822291273
+ 3.698319592326228
+ 3.6983655016371504
+ 3.69841141016193
+ 3.6984573179006035
+ 3.6985032248532073
+ 3.6985491310197784
+ 3.6985950364003535
+ 3.6986409409949683
+ 3.69868684480366
+ 3.6987327478264644
+ 3.6987786500634185
+ 3.6988245515145595
+ 3.6988704521799227
+ 3.6989163520595456
+ 3.6989622511534637
+ 3.6990081494617146
+ 3.699054046984334
+ 3.6990999437213583
+ 3.699145839672825
+ 3.6991917348387697
+ 3.699237629219229
+ 3.6992835228142398
+ 3.6993294156238377
+ 3.69937530764806
+ 3.699421198886944
+ 3.6994670893405237
+ 3.6995129790088375
+ 3.6995588678919216
+ 3.6996047559898124
+ 3.699650643302546
+ 3.699696529830159
+ 3.6997424155726883
+ 3.69978830053017
+ 3.69983418470264
+ 3.6998800680901356
+ 3.6999259506926934
+ 3.699971832510349
+ 3.700017713543139
+ 3.7000635937911004
+ 3.7001094732542694
+ 3.700155351932682
+ 3.7002012298263756
+ 3.700247106935386
+ 3.7002929832597493
+ 3.700338858799502
+ 3.7003847335546816
+ 3.700430607525323
+ 3.7004764807114636
+ 3.70052235311314
+ 3.7005682247303877
+ 3.700614095563244
+ 3.7006599656117443
+ 3.700705834875926
+ 3.700751703355825
+ 3.7007975710514778
+ 3.7008434379629205
+ 3.70088930409019
+ 3.7009351694333223
+ 3.700981033992354
+ 3.7010268977673215
+ 3.701072760758261
+ 3.7011186229652093
+ 3.7011644843882023
+ 3.7012103450272766
+ 3.701256204882468
+ 3.701302063953814
+ 3.70134792224135
+ 3.701393779745113
+ 3.701439636465139
+ 3.7014854924014635
+ 3.7015313475541247
+ 3.701577201923158
+ 3.7016230555085996
+ 3.701668908310486
+ 3.701714760328853
+ 3.7017606115637385
+ 3.701806462015177
+ 3.7018523116832065
+ 3.7018981605678616
+ 3.70194400866918
+ 3.7019898559871973
+ 3.70203570252195
+ 3.702081548273475
+ 3.7021273932418075
+ 3.702173237426985
+ 3.702219080829043
+ 3.7022649234480176
+ 3.7023107652839458
+ 3.7023566063368634
+ 3.7024024466068077
+ 3.702448286093814
+ 3.702494124797919
+ 3.7025399627191584
+ 3.7025857998575686
+ 3.702631636213187
+ 3.702677471786048
+ 3.70272330657619
+ 3.702769140583648
+ 3.7028149738084584
+ 3.7028608062506576
+ 3.702906637910282
+ 3.702952468787368
+ 3.702998298881951
+ 3.7030441281940676
+ 3.7030899567237556
+ 3.703135784471049
+ 3.7031816114359852
+ 3.7032274376186005
+ 3.7032732630189305
+ 3.703319087637013
+ 3.703364911472882
+ 3.7034107345265754
+ 3.703456556798128
+ 3.703502378287578
+ 3.70354819899496
+ 3.7035940189203114
+ 3.7036398380636673
+ 3.7036856564250646
+ 3.7037314740045395
+ 3.7037772908021283
+ 3.703823106817866
+ 3.703868922051791
+ 3.7039147365039375
+ 3.703960550174343
+ 3.704006363063043
+ 3.7040521751700743
+ 3.704097986495472
+ 3.704143797039274
+ 3.704189606801515
+ 3.704235415782232
+ 3.704281223981461
+ 3.704327031399237
+ 3.7043728380355985
+ 3.70441864389058
+ 3.704464448964219
+ 3.7045102532565495
+ 3.70455605676761
+ 3.704601859497435
+ 3.704647661446061
+ 3.704693462613525
+ 3.7047392629998632
+ 3.7047850626051106
+ 3.7048308614293037
+ 3.7048766594724793
+ 3.7049224567346735
+ 3.704968253215921
+ 3.70501404891626
+ 3.705059843835726
+ 3.7051056379743543
+ 3.705151431332182
+ 3.705197223909244
+ 3.7052430157055776
+ 3.7052888067212186
+ 3.7053345969562033
+ 3.7053803864105674
+ 3.705426175084347
+ 3.7054719629775787
+ 3.7055177500902987
+ 3.7055635364225425
+ 3.7056093219743467
+ 3.7056551067457466
+ 3.7057008907367797
+ 3.7057466739474805
+ 3.705792456377887
+ 3.7058382380280332
+ 3.7058840188979567
+ 3.7059297989876927
+ 3.7059755782972776
+ 3.706021356826748
+ 3.706067134576139
+ 3.706112911545488
+ 3.70615868773483
+ 3.706204463144201
+ 3.7062502377736375
+ 3.706296011623176
+ 3.7063417846928512
+ 3.7063875569827007
+ 3.7064333284927597
+ 3.7064790992230647
+ 3.7065248691736508
+ 3.7065706383445556
+ 3.706616406735814
+ 3.706662174347462
+ 3.7067079411795367
+ 3.706753707232073
+ 3.7067994725051077
+ 3.7068452369986757
+ 3.706891000712815
+ 3.7069367636475596
+ 3.7069825258029465
+ 3.707028287179012
+ 3.7070740477757917
+ 3.7071198075933216
+ 3.7071655666316374
+ 3.707211324890776
+ 3.7072570823707727
+ 3.7073028390716636
+ 3.7073485949934852
+ 3.7073943501362727
+ 3.707440104500063
+ 3.707485858084891
+ 3.707531610890794
+ 3.707577362917807
+ 3.7076231141659663
+ 3.7076688646353078
+ 3.7077146143258677
+ 3.707760363237682
+ 3.7078061113707865
+ 3.707851858725217
+ 3.7078976053010093
+ 3.707943351098201
+ 3.7079890961168256
+ 3.7080348403569205
+ 3.708080583818522
+ 3.7081263265016653
+ 3.7081720684063866
+ 3.7082178095327216
+ 3.7082635498807064
+ 3.7083092894503773
+ 3.70835502824177
+ 3.7084007662549205
+ 3.7084465034898644
+ 3.7084922399466373
+ 3.708537975625277
+ 3.7085837105258173
+ 3.7086294446482952
+ 3.7086751779927467
+ 3.708720910559207
+ 3.7087666423477126
+ 3.7088123733582994
+ 3.708858103591003
+ 3.7089038330458597
+ 3.708949561722905
+ 3.708995289622176
+ 3.709041016743706
+ 3.7090867430875334
+ 3.7091324686536935
+ 3.709178193442222
+ 3.709223917453154
+ 3.7092696406865264
+ 3.709315363142375
+ 3.7093610848207357
+ 3.709406805721644
+ 3.709452525845136
+ 3.7094982451912473
+ 3.709543963760014
+ 3.7095896815514724
+ 3.7096353985656574
+ 3.7096811148026063
+ 3.709726830262353
+ 3.7097725449449355
+ 3.709818258850388
+ 3.709863971978747
+ 3.7099096843300488
+ 3.7099553959043283
+ 3.710001106701622
+ 3.7100468167219653
+ 3.7100925259653947
+ 3.7101382344319456
+ 3.710183942121654
+ 3.7102296490345554
+ 3.710275355170686
+ 3.7103210605300814
+ 3.7103667651127776
+ 3.7104124689188103
+ 3.7104581719482157
+ 3.710503874201029
+ 3.710549575677286
+ 3.710595276377023
+ 3.710640976300276
+ 3.71068667544708
+ 3.7107323738174722
+ 3.7107780714114864
+ 3.71082376822916
+ 3.7108694642705276
+ 3.7109151595356265
+ 3.710960854024491
+ 3.7110065477371577
+ 3.7110522406736624
+ 3.71109793283404
+ 3.711143624218328
+ 3.7111893148265604
+ 3.7112350046587745
+ 3.7112806937150045
+ 3.7113263819952875
+ 3.7113720694996584
+ 3.7114177562281534
+ 3.711463442180808
+ 3.7115091273576586
+ 3.7115548117587402
+ 3.711600495384089
+ 3.71164617823374
+ 3.7116918603077305
+ 3.7117375416060945
+ 3.7117832221288696
+ 3.7118289018760895
+ 3.711874580847791
+ 3.7119202590440104
+ 3.7119659364647815
+ 3.7120116131101426
+ 3.7120572889801275
+ 3.712102964074773
+ 3.712148638394114
+ 3.712194311938187
+ 3.712239984707027
+ 3.71228565670067
+ 3.712331327919152
+ 3.712376998362508
+ 3.7124226680307744
+ 3.7124683369239873
+ 3.7125140050421805
+ 3.7125596723853924
+ 3.712605338953656
+ 3.712651004747009
+ 3.712696669765487
+ 3.712742334009124
+ 3.7127879974779567
+ 3.7128336601720213
+ 3.7128793220913527
+ 3.712924983235987
+ 3.71297064360596
+ 3.7130163032013064
+ 3.713061962022063
+ 3.713107620068265
+ 3.7131532773399476
+ 3.713198933837148
+ 3.7132445895599
+ 3.7132902445082405
+ 3.7133358986822045
+ 3.7133815520818283
+ 3.7134272047071466
+ 3.7134728565581954
+ 3.7135185076350115
+ 3.713564157937629
+ 3.7136098074660837
+ 3.7136554562204123
+ 3.713701104200649
+ 3.713746751406831
+ 3.7137923978389926
+ 3.7138380434971703
+ 3.7138836883813986
+ 3.713929332491715
+ 3.7139749758281533
+ 3.7140206183907494
+ 3.71406626017954
+ 3.71411190119456
+ 3.7141575414358443
+ 3.71420318090343
+ 3.7142488195973518
+ 3.7142944575176453
+ 3.714340094664346
+ 3.71438573103749
+ 3.7144313666371125
+ 3.714477001463249
+ 3.714522635515936
+ 3.7145682687952073
+ 3.7146139013011004
+ 3.7146595330336494
+ 3.714705163992891
+ 3.7147507941788596
+ 3.714796423591592
+ 3.7148420522311225
+ 3.7148876800974877
+ 3.714933307190723
+ 3.7149789335108636
+ 3.715024559057945
+ 3.7150701838320033
+ 3.7151158078330733
+ 3.7151614310611913
+ 3.715207053516392
+ 3.715252675198712
+ 3.715298296108186
+ 3.7153439162448496
+ 3.715389535608739
+ 3.715435154199889
+ 3.7154807720183354
+ 3.7155263890641135
+ 3.7155720053372594
+ 3.715617620837808
+ 3.7156632355657955
+ 3.7157088495212567
+ 3.7157544627042274
+ 3.7158000751147426
+ 3.7158456867528393
+ 3.715891297618551
+ 3.715936907711915
+ 3.7159825170329657
+ 3.7160281255817393
+ 3.7160737333582703
+ 3.716119340362595
+ 3.716164946594749
+ 3.716210552054767
+ 3.716256156742685
+ 3.716301760658539
+ 3.716347363802363
+ 3.716392966174194
+ 3.716438567774067
+ 3.7164841686020167
+ 3.7165297686580794
+ 3.71657536794229
+ 3.716620966454685
+ 3.716666564195299
+ 3.716712161164167
+ 3.716757757361326
+ 3.7168033527868096
+ 3.7168489474406545
+ 3.716894541322896
+ 3.71694013443357
+ 3.71698572677271
+ 3.7170313183403536
+ 3.717076909136535
+ 3.71712249916129
+ 3.7171680884146543
+ 3.717213676896663
+ 3.717259264607351
+ 3.717304851546755
+ 3.717350437714909
+ 3.7173960231118497
+ 3.717441607737612
+ 3.7174871915922307
+ 3.717532774675742
+ 3.7175783569881813
+ 3.717623938529583
+ 3.7176695192999847
+ 3.717715099299419
+ 3.7177606785279234
+ 3.7178062569855324
+ 3.717851834672281
+ 3.717897411588206
+ 3.717942987733341
+ 3.717988563107723
+ 3.7180341377113866
+ 3.718079711544367
+ 3.7181252846066997
+ 3.7181708568984204
+ 3.7182164284195642
+ 3.7182619991701666
+ 3.7183075691502623
+ 3.718353138359888
+ 3.718398706799078
+ 3.718444274467868
+ 3.718489841366293
+ 3.718535407494389
+ 3.7185809728521906
+ 3.718626537439734
+ 3.718672101257054
+ 3.718717664304186
+ 3.7187632265811654
+ 3.7188087880880274
+ 3.718854348824807
+ 3.7188999087915406
+ 3.718945467988263
+ 3.7189910264150083
+ 3.719036584071814
+ 3.7190821409587134
+ 3.7191276970757436
+ 3.719173252422939
+ 3.7192188070003347
+ 3.719264360807966
+ 3.7193099138458687
+ 3.719355466114078
+ 3.7194010176126295
+ 3.719446568341557
+ 3.7194921183008978
+ 3.719537667490686
+ 3.7195832159109568
+ 3.719628763561747
+ 3.7196743104430894
+ 3.719719856555021
+ 3.7197654018975768
+ 3.719810946470792
+ 3.7198564902747013
+ 3.719902033309341
+ 3.7199475755747455
+ 3.719993117070951
+ 3.720038657797992
+ 3.7200841977559036
+ 3.7201297369447217
+ 3.720175275364481
+ 3.7202208130152172
+ 3.720266349896965
+ 3.7203118860097604
+ 3.720357421353638
+ 3.7204029559286336
+ 3.7204484897347823
+ 3.720494022772119
+ 3.720539555040679
+ 3.7205850865404972
+ 3.7206306172716093
+ 3.7206761472340513
+ 3.7207216764278566
+ 3.7207672048530624
+ 3.7208127325097022
+ 3.7208582593978123
+ 3.7209037855174274
+ 3.7209493108685834
+ 3.720994835451314
+ 3.721040359265656
+ 3.721085882311644
+ 3.721131404589313
+ 3.7211769260986984
+ 3.721222446839836
+ 3.7212679668127597
+ 3.7213134860175052
+ 3.7213590044541083
+ 3.721404522122603
+ 3.721450039023026
+ 3.7214955551554114
+ 3.7215410705197947
+ 3.721586585116211
+ 3.721632098944695
+ 3.721677612005283
+ 3.7217231242980096
+ 3.7217686358229094
+ 3.7218141465800185
+ 3.721859656569371
+ 3.7219051657910036
+ 3.7219506742449497
+ 3.7219961819312455
+ 3.722041688849926
+ 3.722087195001026
+ 3.722132700384581
+ 3.7221782050006262
+ 3.7222237088491967
+ 3.7222692119303273
+ 3.722314714244053
+ 3.7223602157904097
+ 3.7224057165694324
+ 3.7224512165811547
+ 3.722496715825614
+ 3.7225422143028437
+ 3.72258771201288
+ 3.7226332089557577
+ 3.7226787051315116
+ 3.7227242005401764
+ 3.722769695181788
+ 3.7228151890563823
+ 3.7228606821639927
+ 3.7229061745046548
+ 3.7229516660784037
+ 3.722997156885275
+ 3.7230426469253035
+ 3.7230881361985246
+ 3.723133624704972
+ 3.723179112444683
+ 3.7232245994176907
+ 3.723270085624031
+ 3.723315571063739
+ 3.72336105573685
+ 3.723406539643398
+ 3.72345202278342
+ 3.723497505156949
+ 3.7235429867640213
+ 3.7235884676046718
+ 3.723633947678935
+ 3.7236794269868465
+ 3.7237249055284414
+ 3.723770383303754
+ 3.72381586031282
+ 3.7238613365556748
+ 3.7239068120323524
+ 3.7239522867428887
+ 3.7239977606873182
+ 3.724043233865676
+ 3.724088706277998
+ 3.7241341779243173
+ 3.724179648804671
+ 3.7242251189190934
+ 3.724270588267619
+ 3.7243160568502827
+ 3.7243615246671204
+ 3.724406991718167
+ 3.7244524580034573
+ 3.7244979235230256
+ 3.7245433882769077
+ 3.7245888522651387
+ 3.7246343154877533
+ 3.724679777944786
+ 3.7247252396362724
+ 3.7247707005622477
+ 3.7248161607227463
+ 3.7248616201178035
+ 3.7249070787474543
+ 3.7249525366117338
+ 3.7249979937106765
+ 3.7250434500443177
+ 3.725088905612693
+ 3.7251343604158356
+ 3.7251798144537824
+ 3.7252252677265667
+ 3.7252707202342252
+ 3.7253161719767913
+ 3.725361622954301
+ 3.7254070731667888
+ 3.7254525226142894
+ 3.725497971296839
+ 3.72554341921447
+ 3.7255888663672203
+ 3.7256343127551226
+ 3.725679758378213
+ 3.7257252032365265
+ 3.7257706473300973
+ 3.725816090658961
+ 3.725861533223152
+ 3.725906975022706
+ 3.7259524160576567
+ 3.7259978563280396
+ 3.72604329583389
+ 3.7260887345752427
+ 3.7261341725521326
+ 3.726179609764594
+ 3.7262250462126625
+ 3.7262704818963726
+ 3.72631591681576
+ 3.7263613509708584
+ 3.726406784361703
+ 3.726452216988329
+ 3.7264976488507715
+ 3.726543079949065
+ 3.7265885102832446
+ 3.726633939853345
+ 3.7266793686594015
+ 3.7267247967014483
+ 3.7267702239795204
+ 3.726815650493654
+ 3.726861076243882
+ 3.72690650123024
+ 3.726951925452763
+ 3.7269973489114867
+ 3.727042771606444
+ 3.7270881935376714
+ 3.7271336147052034
+ 3.7271790351090743
+ 3.72722445474932
+ 3.7272698736259735
+ 3.727315291739072
+ 3.7273607090886482
+ 3.727406125674739
+ 3.727451541497377
+ 3.7274969565565987
+ 3.7275423708524387
+ 3.727587784384931
+ 3.7276331971541112
+ 3.7276786091600136
+ 3.7277240204026736
+ 3.7277694308821254
+ 3.727814840598404
+ 3.7278602495515454
+ 3.727905657741582
+ 3.727951065168551
+ 3.727996471832486
+ 3.728041877733421
+ 3.728087282871393
+ 3.7281326872464344
+ 3.728178090858582
+ 3.7282234937078695
+ 3.728268895794332
+ 3.728314297118004
+ 3.7283596976789206
+ 3.7284050974771166
+ 3.7284504965126266
+ 3.7284958947854854
+ 3.728541292295728
+ 3.7285866890433885
+ 3.7286320850285026
+ 3.7286774802511045
+ 3.7287228747112287
+ 3.7287682684089107
+ 3.728813661344185
+ 3.7288590535170862
+ 3.7289044449276494
+ 3.7289498355759085
+ 3.7289952254618988
+ 3.7290406145856556
+ 3.7290860029472124
+ 3.729131390546605
+ 3.7291767773838673
+ 3.7292221634590352
+ 3.7292675487721425
+ 3.729312933323224
+ 3.7293583171123146
+ 3.7294037001394496
+ 3.7294490824046624
+ 3.7294944639079888
+ 3.729539844649463
+ 3.72958522462912
+ 3.7296306038469944
+ 3.7296759823031214
+ 3.7297213599975345
+ 3.7297667369302694
+ 3.72981211310136
+ 3.7298574885108424
+ 3.72990286315875
+ 3.7299482370451176
+ 3.7299936101699807
+ 3.730038982533373
+ 3.73008435413533
+ 3.730129724975886
+ 3.730175095055076
+ 3.7302204643729335
+ 3.7302658329294953
+ 3.730311200724794
+ 3.7303565677588657
+ 3.730401934031744
+ 3.730447299543464
+ 3.7304926642940606
+ 3.730538028283569
+ 3.7305833915120226
+ 3.730628753979456
+ 3.7306741156859053
+ 3.730719476631404
+ 3.730764836815987
+ 3.7308101962396893
+ 3.7308555549025444
+ 3.730900912804589
+ 3.7309462699458553
+ 3.73099162632638
+ 3.7310369819461964
+ 3.73108233680534
+ 3.7311276909038447
+ 3.7311730442417455
+ 3.731218396819077
+ 3.731263748635874
+ 3.7313090996921705
+ 3.731354449988002
+ 3.7313997995234023
+ 3.7314451482984063
+ 3.731490496313049
+ 3.731535843567365
+ 3.7315811900613873
+ 3.7316265357951526
+ 3.7316718807686944
+ 3.7317172249820474
+ 3.7317625684352467
+ 3.7318079111283264
+ 3.7318532530613213
+ 3.731898594234266
+ 3.7319439346471945
+ 3.731989274300142
+ 3.732034613193143
+ 3.732079951326232
+ 3.732125288699444
+ 3.7321706253128126
+ 3.7322159611663728
+ 3.73226129626016
+ 3.7323066305942074
+ 3.73235196416855
+ 3.732397296983223
+ 3.7324426290382604
+ 3.7324879603336965
+ 3.7325332908695663
+ 3.732578620645904
+ 3.732623949662745
+ 3.732669277920123
+ 3.7327146054180727
+ 3.7327599321566285
+ 3.7328052581358246
+ 3.732850583355697
+ 3.7328959078162787
+ 3.7329412315176054
+ 3.7329865544597105
+ 3.733031876642629
+ 3.7330771980663955
+ 3.7331225187310446
+ 3.7331678386366107
+ 3.733213157783128
+ 3.7332584761706316
+ 3.7333037937991556
+ 3.733349110668734
+ 3.7333944267794026
+ 3.733439742131195
+ 3.7334850567241453
+ 3.7335303705582894
+ 3.7335756836336604
+ 3.733620995950294
+ 3.7336663075082233
+ 3.733711618307484
+ 3.7337569283481096
+ 3.7338022376301354
+ 3.733847546153595
+ 3.7338928539185243
+ 3.7339381609249562
+ 3.733983467172926
+ 3.734028772662468
+ 3.734074077393617
+ 3.7341193813664066
+ 3.734164684580872
+ 3.734209987037047
+ 3.7342552887349667
+ 3.7343005896746653
+ 3.7343458898561774
+ 3.7343911892795374
+ 3.7344364879447793
+ 3.734481785851938
+ 3.7345270830010477
+ 3.734572379392143
+ 3.7346176750252584
+ 3.7346629699004286
+ 3.7347082640176867
+ 3.7347535573770685
+ 3.734798849978608
+ 3.7348441418223395
+ 3.7348894329082976
+ 3.7349347232365164
+ 3.734980012807031
+ 3.7350253016198747
+ 3.735070589675083
+ 3.7351158769726895
+ 3.735161163512729
+ 3.735206449295236
+ 3.735251734320244
+ 3.7352970185877887
+ 3.7353423020979037
+ 3.7353875848506237
+ 3.7354328668459833
+ 3.735478148084016
+ 3.7355234285647567
+ 3.73556870828824
+ 3.7356139872545002
+ 3.7356592654635716
+ 3.735704542915488
+ 3.7357498196102847
+ 3.7357950955479953
+ 3.7358403707286545
+ 3.735885645152297
+ 3.7359309188189567
+ 3.735976191728668
+ 3.7360214638814653
+ 3.7360667352773826
+ 3.736112005916455
+ 3.7361572757987167
+ 3.7362025449242013
+ 3.736247813292944
+ 3.7362930809049786
+ 3.736338347760339
+ 3.736383613859061
+ 3.7364288792011777
+ 3.736474143786724
+ 3.7365194076157335
+ 3.7365646706882414
+ 3.736609933004282
+ 3.7366551945638884
+ 3.7367004553670964
+ 3.7367457154139387
+ 3.7367909747044514
+ 3.736836233238668
+ 3.7368814910166224
+ 3.7369267480383495
+ 3.7369720043038837
+ 3.7370172598132583
+ 3.737062514566509
+ 3.7371077685636687
+ 3.737153021804773
+ 3.737198274289855
+ 3.7372435260189496
+ 3.737288776992091
+ 3.7373340272093136
+ 3.737379276670651
+ 3.737424525376139
+ 3.7374697733258104
+ 3.7375150205196994
+ 3.7375602669578414
+ 3.73760551264027
+ 3.7376507575670193
+ 3.737696001738124
+ 3.737741245153618
+ 3.7377864878135356
+ 3.7378317297179113
+ 3.737876970866779
+ 3.7379222112601735
+ 3.7379674508981284
+ 3.7380126897806787
+ 3.738057927907857
+ 3.7381031652797
+ 3.73814840189624
+ 3.7381936377575116
+ 3.7382388728635494
+ 3.7382841072143873
+ 3.7383293408100604
+ 3.738374573650602
+ 3.738419805736046
+ 3.7384650370664274
+ 3.7385102676417805
+ 3.7385554974621384
+ 3.738600726527537
+ 3.7386459548380087
+ 3.7386911823935893
+ 3.738736409194312
+ 3.7387816352402115
+ 3.7388268605313213
+ 3.738872085067676
+ 3.738917308849311
+ 3.7389625318762585
+ 3.7390077541485534
+ 3.7390529756662296
+ 3.739098196429323
+ 3.739143416437865
+ 3.7391886356918924
+ 3.739233854191437
+ 3.739279071936535
+ 3.7393242889272194
+ 3.7393695051635247
+ 3.7394147206454855
+ 3.7394599353731355
+ 3.7395051493465084
+ 3.7395503625656388
+ 3.739595575030561
+ 3.739640786741309
+ 3.739685997697917
+ 3.739731207900419
+ 3.7397764173488492
+ 3.739821626043242
+ 3.7398668339836316
+ 3.7399120411700513
+ 3.739957247602536
+ 3.7400024532811194
+ 3.7400476582058357
+ 3.740092862376719
+ 3.7401380657938046
+ 3.7401832684571246
+ 3.740228470366715
+ 3.7402736715226084
+ 3.7403188719248393
+ 3.7403640715734423
+ 3.7404092704684513
+ 3.7404544686099004
+ 3.7404996659978234
+ 3.740544862632255
+ 3.740590058513228
+ 3.7406352536407783
+ 3.740680448014939
+ 3.7407256416357444
+ 3.7407708345032282
+ 3.740816026617425
+ 3.7408612179783685
+ 3.740906408586093
+ 3.740951598440632
+ 3.740996787542021
+ 3.7410419758902926
+ 3.741087163485481
+ 3.741132350327621
+ 3.741177536416747
+ 3.7412227217528913
+ 3.74126790633609
+ 3.7413130901663756
+ 3.741358273243783
+ 3.7414034555683457
+ 3.7414486371400986
+ 3.7414938179590744
+ 3.741538998025309
+ 3.7415841773388347
+ 3.7416293558996863
+ 3.741674533707897
+ 3.741719710763503
+ 3.741764887066536
+ 3.741810062617031
+ 3.7418552374150225
+ 3.741900411460543
+ 3.7419455847536285
+ 3.7419907572943116
+ 3.7420359290826264
+ 3.742081100118608
+ 3.7421262704022893
+ 3.742171439933704
+ 3.742216608712888
+ 3.7422617767398734
+ 3.7423069440146945
+ 3.7423521105373863
+ 3.742397276307982
+ 3.7424424413265154
+ 3.7424876055930207
+ 3.742532769107533
+ 3.7425779318700845
+ 3.7426230938807103
+ 3.742668255139444
+ 3.7427134156463198
+ 3.742758575401371
+ 3.7428037344046325
+ 3.742848892656138
+ 3.742894050155921
+ 3.742939206904016
+ 3.7429843629004567
+ 3.743029518145277
+ 3.743074672638511
+ 3.7431198263801924
+ 3.743164979370356
+ 3.7432101316090347
+ 3.743255283096263
+ 3.743300433832075
+ 3.7433455838165037
+ 3.743390733049584
+ 3.7434358815313495
+ 3.743481029261834
+ 3.7435261762410716
+ 3.7435713224690965
+ 3.7436164679459423
+ 3.743661612671643
+ 3.743706756646232
+ 3.7437518998697445
+ 3.743797042342213
+ 3.7438421840636726
+ 3.7438873250341564
+ 3.7439324652536983
+ 3.743977604722333
+ 3.7440227434400937
+ 3.7440678814070143
+ 3.7441130186231293
+ 3.7441581550884715
+ 3.7442032908030756
+ 3.7442484257669757
+ 3.744293559980205
+ 3.7443386934427982
+ 3.7443838261547886
+ 3.74442895811621
+ 3.7444740893270962
+ 3.7445192197874824
+ 3.7445643494974004
+ 3.7446094784568857
+ 3.7446546066659714
+ 3.7446997341246915
+ 3.74474486083308
+ 3.7447899867911705
+ 3.744835111998997
+ 3.7448802364565936
+ 3.744925360163994
+ 3.744970483121232
+ 3.7450156053283408
+ 3.745060726785355
+ 3.7451058474923093
+ 3.7451509674492356
+ 3.745196086656169
+ 3.745241205113143
+ 3.7452863228201916
+ 3.7453314397773485
+ 3.7453765559846475
+ 3.7454216714421227
+ 3.7454667861498074
+ 3.745511900107736
+ 3.7455570133159415
+ 3.7456021257744587
+ 3.745647237483321
+ 3.745692348442562
+ 3.7457374586522154
+ 3.745782568112316
+ 3.745827676822896
+ 3.7458727847839914
+ 3.7459178919956337
+ 3.745962998457858
+ 3.7460081041706976
+ 3.7460532091341867
+ 3.7460983133483587
+ 3.746143416813248
+ 3.746188519528887
+ 3.7462336214953114
+ 3.7462787227125536
+ 3.746323823180648
+ 3.7463689228996273
+ 3.746414021869527
+ 3.7464591200903796
+ 3.74650421756222
+ 3.7465493142850805
+ 3.7465944102589956
+ 3.746639505483999
+ 3.7466845999601253
+ 3.746729693687407
+ 3.746774786665878
+ 3.7468198788955727
+ 3.7468649703765244
+ 3.746910061108767
+ 3.746955151092334
+ 3.7470002403272593
+ 3.747045328813577
+ 3.7470904165513206
+ 3.7471355035405236
+ 3.74718058978122
+ 3.7472256752734427
+ 3.7472707600172273
+ 3.747315844012605
+ 3.747360927259612
+ 3.74740600975828
+ 3.7474510915086445
+ 3.747496172510738
+ 3.7475412527645946
+ 3.747586332270248
+ 3.7476314110277316
+ 3.747676489037079
+ 3.7477215662983245
+ 3.7477666428115017
+ 3.7478117185766444
+ 3.7478567935937854
+ 3.7479018678629594
+ 3.7479469413841997
+ 3.7479920141575396
+ 3.748037086183014
+ 3.748082157460655
+ 3.7481272279904974
+ 3.7481722977725744
+ 3.7482173668069194
+ 3.7482624350935674
+ 3.74830750263255
+ 3.748352569423903
+ 3.7483976354676583
+ 3.7484427007638508
+ 3.748487765312513
+ 3.7485328291136804
+ 3.748577892167384
+ 3.7486229544736602
+ 3.7486680160325405
+ 3.74871307684406
+ 3.7487581369082514
+ 3.748803196225149
+ 3.7488482547947855
+ 3.748893312617196
+ 3.7489383696924126
+ 3.74898342602047
+ 3.7490284816014015
+ 3.749073536435241
+ 3.7491185905220217
+ 3.749163643861777
+ 3.7492086964545406
+ 3.749253748300347
+ 3.7492987993992295
+ 3.7493438497512206
+ 3.749388899356355
+ 3.7494339482146657
+ 3.749478996326187
+ 3.749524043690952
+ 3.749569090308994
+ 3.749614136180348
+ 3.749659181305046
+ 3.7497042256831223
+ 3.74974926931461
+ 3.749794312199544
+ 3.7498393543379565
+ 3.749884395729881
+ 3.7499294363753526
+ 3.7499744762744034
+ 3.7500195154270672
+ 3.7500645538333783
+ 3.7501095914933695
+ 3.7501546284070746
+ 3.7501996645745272
+ 3.7502446999957617
+ 3.75028973467081
+ 3.750334768599707
+ 3.750379801782486
+ 3.7504248342191797
+ 3.7504698659098223
+ 3.7505148968544475
+ 3.750559927053089
+ 3.7506049565057795
+ 3.7506499852125534
+ 3.750695013173444
+ 3.7507400403884845
+ 3.7507850668577083
+ 3.75083009258115
+ 3.750875117558842
+ 3.750920141790818
+ 3.7509651652771123
+ 3.7510101880177573
+ 3.7510552100127876
+ 3.751100231262236
+ 3.7511452517661366
+ 3.7511902715245222
+ 3.751235290537427
+ 3.7512803088048834
+ 3.7513253263269264
+ 3.7513703431035883
+ 3.751415359134903
+ 3.7514603744209043
+ 3.751505388961625
+ 3.7515504027570996
+ 3.7515954158073606
+ 3.7516404281124425
+ 3.7516854396723778
+ 3.7517304504872
+ 3.7517754605569436
+ 3.7518204698816415
+ 3.7518654784613266
+ 3.751910486296033
+ 3.751955493385794
+ 3.7520004997306433
+ 3.7520455053306137
+ 3.75209051018574
+ 3.7521355142960537
+ 3.7521805176615897
+ 3.7522255202823818
+ 3.752270522158462
+ 3.7523155232898646
+ 3.752360523676623
+ 3.752405523318771
+ 3.7524505222163413
+ 3.7524955203693677
+ 3.7525405177778834
+ 3.7525855144419222
+ 3.7526305103615174
+ 3.7526755055367023
+ 3.7527204999675106
+ 3.7527654936539747
+ 3.7528104865961303
+ 3.7528554787940083
+ 3.752900470247644
+ 3.7529454609570694
+ 3.7529904509223186
+ 3.753035440143425
+ 3.753080428620422
+ 3.753125416353343
+ 3.7531704033422213
+ 3.75321538958709
+ 3.753260375087984
+ 3.7533053598449344
+ 3.753350343857976
+ 3.7533953271271425
+ 3.7534403096524662
+ 3.7534852914339814
+ 3.7535302724717203
+ 3.753575252765718
+ 3.753620232316006
+ 3.753665211122619
+ 3.75371018918559
+ 3.753755166504953
+ 3.75380014308074
+ 3.7538451189129853
+ 3.7538900940017226
+ 3.753935068346984
+ 3.7539800419488034
+ 3.754025014807215
+ 3.754069986922251
+ 3.7541149582939455
+ 3.754159928922332
+ 3.754204898807443
+ 3.7542498679493117
+ 3.754294836347973
+ 3.754339804003459
+ 3.7543847709158027
+ 3.754429737085039
+ 3.754474702511199
+ 3.754519667194318
+ 3.754564631134429
+ 3.7546095943315647
+ 3.7546545567857583
+ 3.754699518497044
+ 3.754744479465454
+ 3.754789439691023
+ 3.7548343991737823
+ 3.754879357913768
+ 3.75492431591101
+ 3.7549692731655453
+ 3.7550142296774043
+ 3.7550591854466218
+ 3.7551041404732306
+ 3.7551490947572637
+ 3.755194048298755
+ 3.755239001097737
+ 3.7552839531542443
+ 3.7553289044683087
+ 3.755373855039965
+ 3.7554188048692447
+ 3.755463753956183
+ 3.7555087023008116
+ 3.7555536499031645
+ 3.755598596763275
+ 3.7556435428811756
+ 3.755688488256901
+ 3.7557334328904832
+ 3.755778376781956
+ 3.7558233199313524
+ 3.7558682623387067
+ 3.7559132040040506
+ 3.7559581449274178
+ 3.756003085108842
+ 3.7560480245483565
+ 3.756092963245994
+ 3.756137901201788
+ 3.756182838415772
+ 3.7562277748879787
+ 3.7562727106184415
+ 3.7563176456071945
+ 3.7563625798542692
+ 3.7564075133597004
+ 3.7564524461235207
+ 3.756497378145763
+ 3.756542309426461
+ 3.7565872399656484
+ 3.7566321697633573
+ 3.7566770988196216
+ 3.756722027134474
+ 3.7567669547079485
+ 3.7568118815400773
+ 3.7568568076308946
+ 3.756901732980433
+ 3.756946657588726
+ 3.7569915814558064
+ 3.7570365045817073
+ 3.7570814269664625
+ 3.757126348610105
+ 3.7571712695126678
+ 3.7572161896741845
+ 3.757261109094688
+ 3.7573060277742107
+ 3.7573509457127874
+ 3.75739586291045
+ 3.757440779367232
+ 3.7574856950831665
+ 3.7575306100582875
+ 3.7575755242926268
+ 3.757620437786218
+ 3.757665350539095
+ 3.75771026255129
+ 3.757755173822837
+ 3.7578000843537684
+ 3.757844994144118
+ 3.7578899031939184
+ 3.7579348115032034
+ 3.7579797190720052
+ 3.758024625900358
+ 3.7580695319882937
+ 3.7581144373358466
+ 3.758159341943049
+ 3.758204245809935
+ 3.7582491489365366
+ 3.7582940513228875
+ 3.7583389529690208
+ 3.7583838538749696
+ 3.7584287540407675
+ 3.7584736534664467
+ 3.7585185521520406
+ 3.7585634500975824
+ 3.7586083473031056
+ 3.758653243768643
+ 3.758698139494227
+ 3.7587430344798918
+ 3.7587879287256705
+ 3.758832822231595
+ 3.7588777149976993
+ 3.7589226070240165
+ 3.75896749831058
+ 3.7590123888574216
+ 3.7590572786645757
+ 3.759102167732075
+ 3.7591470560599523
+ 3.759191943648241
+ 3.7592368304969734
+ 3.759281716606184
+ 3.759326601975904
+ 3.7593714866061685
+ 3.7594163704970094
+ 3.7594612536484595
+ 3.7595061360605526
+ 3.7595510177333216
+ 3.7595958986667988
+ 3.759640778861019
+ 3.759685658316013
+ 3.7597305370318157
+ 3.759775415008459
+ 3.759820292245977
+ 3.759865168744401
+ 3.759910044503766
+ 3.759954919524104
+ 3.759999793805448
+ 3.7600446673478314
+ 3.760089540151287
+ 3.7601344122158484
+ 3.7601792835415475
+ 3.7602241541284185
+ 3.760269023976493
+ 3.7603138930858053
+ 3.7603587614563883
+ 3.7604036290882745
+ 3.760448495981497
+ 3.760493362136089
+ 3.760538227552083
+ 3.760583092229513
+ 3.760627956168411
+ 3.7606728193688106
+ 3.760717681830745
+ 3.760762543554246
+ 3.760807404539348
+ 3.760852264786083
+ 3.760897124294485
+ 3.760941983064586
+ 3.7609868410964196
+ 3.7610316983900174
+ 3.7610765549454146
+ 3.7611214107626427
+ 3.761166265841735
+ 3.7612111201827245
+ 3.7612559737856444
+ 3.761300826650527
+ 3.761345678777406
+ 3.761390530166314
+ 3.761435380817284
+ 3.7614802307303488
+ 3.761525079905542
+ 3.7615699283428956
+ 3.761614776042443
+ 3.7616596230042174
+ 3.761704469228251
+ 3.761749314714578
+ 3.76179415946323
+ 3.7618390034742406
+ 3.7618838467476428
+ 3.761928689283469
+ 3.761973531081753
+ 3.762018372142527
+ 3.7620632124658235
+ 3.762108052051677
+ 3.762152890900119
+ 3.762197729011183
+ 3.7622425663849017
+ 3.7622874030213085
+ 3.7623322389204352
+ 3.762377074082316
+ 3.762421908506983
+ 3.7624667421944697
+ 3.762511575144808
+ 3.762556407358032
+ 3.7626012388341743
+ 3.762646069573267
+ 3.7626908995753436
+ 3.7627357288404366
+ 3.76278055736858
+ 3.762825385159805
+ 3.7628702122141457
+ 3.7629150385316343
+ 3.7629598641123043
+ 3.763004688956188
+ 3.763049513063319
+ 3.7630943364337295
+ 3.7631391590674528
+ 3.7631839809645204
+ 3.7632288021249676
+ 3.7632736225488257
+ 3.763318442236127
+ 3.763363261186906
+ 3.7634080794011946
+ 3.7634528968790253
+ 3.763497713620432
+ 3.7635425296254468
+ 3.7635873448941024
+ 3.763632159426432
+ 3.763676973222468
+ 3.7637217862822445
+ 3.763766598605793
+ 3.7638114101931466
+ 3.763856221044338
+ 3.763901031159401
+ 3.7639458405383674
+ 3.7639906491812702
+ 3.7640354570881427
+ 3.7640802642590176
+ 3.7641250706939267
+ 3.764169876392904
+ 3.7642146813559823
+ 3.7642594855831937
+ 3.764304289074571
+ 3.7643490918301477
+ 3.7643938938499564
+ 3.764438695134029
+ 3.7644834956824
+ 3.7645282954951003
+ 3.764573094572164
+ 3.7646178929136234
+ 3.7646626905195113
+ 3.7647074873898605
+ 3.7647522835247043
+ 3.764797078924074
+ 3.7648418735880047
+ 3.7648866675165267
+ 3.764931460709675
+ 3.7649762531674806
+ 3.765021044889977
+ 3.765065835877197
+ 3.765110626129173
+ 3.7651554156459386
+ 3.7652002044275252
+ 3.765244992473967
+ 3.765289779785296
+ 3.765334566361545
+ 3.7653793522027463
+ 3.765424137308934
+ 3.7654689216801396
+ 3.7655137053163963
+ 3.765558488217736
+ 3.765603270384193
+ 3.7656480518157984
+ 3.7656928325125865
+ 3.765737612474589
+ 3.7657823917018387
+ 3.765827170194369
+ 3.765871947952212
+ 3.7659167249754004
+ 3.765961501263967
+ 3.766006276817945
+ 3.766051051637366
+ 3.766095825722264
+ 3.7661405990726706
+ 3.7661853716886196
+ 3.766230143570142
+ 3.7662749147172727
+ 3.766319685130043
+ 3.7663644548084863
+ 3.7664092237526337
+ 3.7664539919625204
+ 3.7664987594381767
+ 3.7665435261796367
+ 3.766588292186933
+ 3.7666330574600977
+ 3.766677821999164
+ 3.7667225858041644
+ 3.766767348875131
+ 3.7668121112120976
+ 3.7668568728150964
+ 3.7669016336841596
+ 3.76694639381932
+ 3.7669911532206104
+ 3.767035911888064
+ 3.7670806698217127
+ 3.7671254270215897
+ 3.767170183487727
+ 3.7672149392201577
+ 3.7672596942189145
+ 3.7673044484840297
+ 3.767349202015536
+ 3.767393954813467
+ 3.767438706877854
+ 3.7674834582087295
+ 3.7675282088061275
+ 3.76757295867008
+ 3.76761770780062
+ 3.7676624561977787
+ 3.76770720386159
+ 3.7677519507920865
+ 3.7677966969893
+ 3.767841442453264
+ 3.7678861871840112
+ 3.7679309311815734
+ 3.7679756744459834
+ 3.768020416977274
+ 3.768065158775478
+ 3.7681098998406273
+ 3.7681546401727557
+ 3.768199379771895
+ 3.7682441186380773
+ 3.768288856771336
+ 3.768333594171704
+ 3.7683783308392127
+ 3.7684230667738956
+ 3.768467801975785
+ 3.7685125364449137
+ 3.768557270181314
+ 3.768602003185018
+ 3.7686467354560595
+ 3.7686914669944707
+ 3.7687361978002833
+ 3.76878092787353
+ 3.7688256572142445
+ 3.768870385822458
+ 3.7689151136982044
+ 3.7689598408415153
+ 3.7690045672524235
+ 3.7690492929309616
+ 3.769094017877162
+ 3.7691387420910574
+ 3.769183465572681
+ 3.7692281883220633
+ 3.7692729103392395
+ 3.7693176316242405
+ 3.7693623521770987
+ 3.7694070719978474
+ 3.7694517910865186
+ 3.769496509443145
+ 3.7695412270677595
+ 3.7695859439603945
+ 3.769630660121082
+ 3.769675375549855
+ 3.7697200902467456
+ 3.769764804211787
+ 3.769809517445011
+ 3.7698542299464504
+ 3.7698989417161375
+ 3.7699436527541055
+ 3.769988363060386
+ 3.770033072635012
+ 3.770077781478016
+ 3.7701224895894305
+ 3.770167196969288
+ 3.7702119036176205
+ 3.7702566095344614
+ 3.7703013147198416
+ 3.7703460191737954
+ 3.7703907228963547
+ 3.7704354258875514
+ 3.770480128147419
+ 3.770524829675989
+ 3.770569530473294
+ 3.770614230539367
+ 3.77065892987424
+ 3.7707036284779454
+ 3.7707483263505157
+ 3.7707930234919846
+ 3.7708377199023824
+ 3.770882415581743
+ 3.7709271105300988
+ 3.770971804747482
+ 3.771016498233925
+ 3.77106119098946
+ 3.7711058830141195
+ 3.7711505743079368
+ 3.771195264870943
+ 3.771239954703171
+ 3.771284643804654
+ 3.771329332175424
+ 3.771374019815513
+ 3.7714187067249543
+ 3.771463392903779
+ 3.7715080783520207
+ 3.7715527630697117
+ 3.7715974470568834
+ 3.7716421303135697
+ 3.771686812839801
+ 3.771731494635612
+ 3.771776175701034
+ 3.7718208560360993
+ 3.7718655356408406
+ 3.77191021451529
+ 3.77195489265948
+ 3.771999570073443
+ 3.7720442467572117
+ 3.7720889227108185
+ 3.772133597934295
+ 3.7721782724276745
+ 3.772222946190989
+ 3.772267619224271
+ 3.7723122915275527
+ 3.772356963100866
+ 3.772401633944244
+ 3.7724463040577194
+ 3.772490973441324
+ 3.7725356420950904
+ 3.77258031001905
+ 3.772624977213237
+ 3.7726696436776823
+ 3.7727143094124185
+ 3.772758974417478
+ 3.772803638692894
+ 3.7728483022386974
+ 3.7728929650549214
+ 3.7729376271415984
+ 3.7729822884987607
+ 3.7730269491264408
+ 3.7730716090246705
+ 3.773116268193482
+ 3.773160926632909
+ 3.773205584342982
+ 3.7732502413237348
+ 3.7732948975751985
+ 3.7733395530974065
+ 3.7733842078903903
+ 3.7734288619541836
+ 3.773473515288817
+ 3.773518167894324
+ 3.773562819770736
+ 3.773607470918086
+ 3.7736521213364056
+ 3.773696771025728
+ 3.7737414199860853
+ 3.7737860682175093
+ 3.773830715720033
+ 3.773875362493688
+ 3.7739200085385067
+ 3.773964653854522
+ 3.774009298441765
+ 3.7740539423002692
+ 3.774098585430067
+ 3.7741432278311895
+ 3.77418786950367
+ 3.77423251044754
+ 3.7742771506628325
+ 3.7743217901495796
+ 3.774366428907813
+ 3.774411066937566
+ 3.7744557042388696
+ 3.7745003408117572
+ 3.77454497665626
+ 3.7745896117724116
+ 3.7746342461602427
+ 3.774678879819787
+ 3.774723512751076
+ 3.774768144954142
+ 3.774812776429017
+ 3.774857407175734
+ 3.7749020371943245
+ 3.7749466664848215
+ 3.7749912950472564
+ 3.7750359228816626
+ 3.7750805499880706
+ 3.7751251763665135
+ 3.7751698020170243
+ 3.7752144269396344
+ 3.775259051134376
+ 3.7753036746012816
+ 3.7753482973403836
+ 3.7753929193517135
+ 3.7754375406353042
+ 3.7754821611911877
+ 3.775526781019396
+ 3.7755714001199614
+ 3.775616018492917
+ 3.775660636138293
+ 3.775705253056124
+ 3.7757498692464395
+ 3.775794484709275
+ 3.7758390994446596
+ 3.775883713452627
+ 3.77592832673321
+ 3.775972939286439
+ 3.776017551112348
+ 3.7760621622109674
+ 3.776106772582331
+ 3.7761513822264705
+ 3.7761959911434175
+ 3.7762405993332044
+ 3.7762852067958637
+ 3.7763298135314276
+ 3.776374419539928
+ 3.7764190248213967
+ 3.7764636293758667
+ 3.7765082332033697
+ 3.7765528363039382
+ 3.776597438677604
+ 3.7766420403243988
+ 3.776686641244355
+ 3.7767312414375063
+ 3.776775840903883
+ 3.776820439643518
+ 3.7768650376564428
+ 3.7769096349426903
+ 3.7769542315022924
+ 3.7769988273352806
+ 3.777043422441688
+ 3.7770880168215464
+ 3.777132610474888
+ 3.777177203401744
+ 3.777221795602148
+ 3.7772663870761316
+ 3.7773109778237264
+ 3.7773555678449644
+ 3.777400157139879
+ 3.777444745708501
+ 3.777489333550864
+ 3.777533920666998
+ 3.7775785070569365
+ 3.7776230927207117
+ 3.777667677658355
+ 3.777712261869899
+ 3.777756845355375
+ 3.7778014281148162
+ 3.777846010148254
+ 3.777890591455721
+ 3.777935172037249
+ 3.7779797518928704
+ 3.778024331022616
+ 3.778068909426519
+ 3.7781134871046116
+ 3.778158064056926
+ 3.778202640283493
+ 3.7782472157843463
+ 3.7782917905595164
+ 3.778336364609036
+ 3.7783809379329383
+ 3.778425510531254
+ 3.7784700824040156
+ 3.778514653551255
+ 3.778559223973004
+ 3.778603793669295
+ 3.7786483626401606
+ 3.778692930885632
+ 3.778737498405742
+ 3.7787820652005215
+ 3.7788266312700034
+ 3.7788711966142197
+ 3.7789157612332023
+ 3.7789603251269828
+ 3.779004888295594
+ 3.7790494507390675
+ 3.7790940124574353
+ 3.7791385734507297
+ 3.7791831337189827
+ 3.779227693262226
+ 3.7792722520804922
+ 3.7793168101738126
+ 3.779361367542219
+ 3.779405924185745
+ 3.7794504801044204
+ 3.7794950352982792
+ 3.779539589767352
+ 3.779584143511672
+ 3.7796286965312698
+ 3.7796732488261786
+ 3.77971780039643
+ 3.7797623512420553
+ 3.779806901363088
+ 3.779851450759559
+ 3.7798959994315
+ 3.779940547378944
+ 3.779985094601922
+ 3.780029641100467
+ 3.78007418687461
+ 3.780118731924383
+ 3.780163276249819
+ 3.7802078198509492
+ 3.7802523627278055
+ 3.7802969048804203
+ 3.780341446308825
+ 3.780385987013052
+ 3.7804305269931335
+ 3.780475066249101
+ 3.780519604780986
+ 3.7805641425888212
+ 3.7806086796726386
+ 3.7806532160324697
+ 3.780697751668347
+ 3.7807422865803013
+ 3.7807868207683657
+ 3.7808313542325718
+ 3.780875886972952
+ 3.780920418989537
+ 3.7809649502823595
+ 3.7810094808514516
+ 3.781054010696845
+ 3.7810985398185712
+ 3.781143068216663
+ 3.7811875958911516
+ 3.7812321228420696
+ 3.781276649069448
+ 3.781321174573319
+ 3.7813656993537155
+ 3.781410223410668
+ 3.7814547467442092
+ 3.7814992693543705
+ 3.7815437912411847
+ 3.7815883124046827
+ 3.781632832844897
+ 3.7816773525618594
+ 3.7817218715556016
+ 3.7817663898261555
+ 3.781810907373553
+ 3.781855424197826
+ 3.781899940299007
+ 3.7819444556771264
+ 3.781988970332218
+ 3.782033484264312
+ 3.782077997473441
+ 3.782122509959637
+ 3.7821670217229313
+ 3.7822115327633563
+ 3.782256043080944
+ 3.7823005526757254
+ 3.7823450615477334
+ 3.7823895696969996
+ 3.782434077123555
+ 3.7824785838274324
+ 3.782523089808663
+ 3.7825675950672797
+ 3.7826120996033135
+ 3.782656603416796
+ 3.78270110650776
+ 3.782745608876236
+ 3.7827901105222566
+ 3.7828346114458533
+ 3.782879111647059
+ 3.782923611125905
+ 3.782968109882422
+ 3.7830126079166435
+ 3.7830571052286004
+ 3.783101601818324
+ 3.7831460976858473
+ 3.7831905928312017
+ 3.783235087254419
+ 3.7832795809555306
+ 3.7833240739345686
+ 3.7833685661915655
+ 3.7834130577265515
+ 3.78345754853956
+ 3.7835020386306217
+ 3.7835465279997695
+ 3.783591016647034
+ 3.7836355045724477
+ 3.7836799917760415
+ 3.7837244782578487
+ 3.7837689640179
+ 3.7838134490562276
+ 3.7838579333728637
+ 3.783902416967839
+ 3.7839468998411854
+ 3.7839913819929354
+ 3.7840358634231204
+ 3.7840803441317723
+ 3.7841248241189227
+ 3.784169303384604
+ 3.784213781928847
+ 3.7842582597516836
+ 3.7843027368531463
+ 3.784347213233266
+ 3.7843916888920752
+ 3.7844361638296053
+ 3.7844806380458875
+ 3.7845251115409546
+ 3.7845695843148377
+ 3.7846140563675688
+ 3.7846585276991793
+ 3.7847029983097014
+ 3.7847474681991664
+ 3.7847919373676056
+ 3.784836405815052
+ 3.784880873541537
+ 3.7849253405470917
+ 3.784969806831748
+ 3.7850142723955376
+ 3.785058737238493
+ 3.785103201360645
+ 3.7851476647620252
+ 3.785192127442666
+ 3.785236589402599
+ 3.7852810506418555
+ 3.785325511160468
+ 3.7853699709584667
+ 3.785414430035885
+ 3.7854588883927534
+ 3.785503346029104
+ 3.7855478029449685
+ 3.7855922591403792
+ 3.7856367146153667
+ 3.7856811693699637
+ 3.7857256234042005
+ 3.785770076718111
+ 3.785814529311724
+ 3.7858589811850734
+ 3.7859034323381904
+ 3.7859478827711066
+ 3.785992332483853
+ 3.7860367814764624
+ 3.7860812297489654
+ 3.7861256773013943
+ 3.786170124133781
+ 3.7862145702461563
+ 3.7862590156385525
+ 3.7863034603110006
+ 3.7863479042635335
+ 3.786392347496182
+ 3.7864367900089775
+ 3.786481231801952
+ 3.786525672875137
+ 3.786570113228564
+ 3.786614552862266
+ 3.786658991776273
+ 3.786703429970617
+ 3.7867478674453303
+ 3.786792304200443
+ 3.786836740235989
+ 3.786881175551998
+ 3.7869256101485025
+ 3.7869700440255336
+ 3.787014477183124
+ 3.7870589096213036
+ 3.787103341340106
+ 3.7871477723395612
+ 3.7871922026197016
+ 3.7872366321805586
+ 3.787281061022164
+ 3.787325489144549
+ 3.7873699165477452
+ 3.787414343231785
+ 3.787458769196699
+ 3.7875031944425195
+ 3.787547618969278
+ 3.787592042777006
+ 3.787636465865734
+ 3.7876808882354958
+ 3.7877253098863206
+ 3.787769730818242
+ 3.7878141510312906
+ 3.787858570525498
+ 3.7879029893008958
+ 3.7879474073575157
+ 3.7879918246953888
+ 3.7880362413145474
+ 3.788080657215023
+ 3.7881250723968467
+ 3.78816948686005
+ 3.7882139006046653
+ 3.7882583136307235
+ 3.788302725938256
+ 3.7883471375272944
+ 3.788391548397871
+ 3.7884359585500165
+ 3.7884803679837624
+ 3.7885247766991412
+ 3.788569184696183
+ 3.788613591974921
+ 3.788657998535385
+ 3.788702404377608
+ 3.7887468095016206
+ 3.788791213907455
+ 3.7888356175951428
+ 3.788880020564714
+ 3.7889244228162022
+ 3.788968824349638
+ 3.789013225165052
+ 3.7890576252624775
+ 3.7891020246419442
+ 3.7891464233034857
+ 3.7891908212471317
+ 3.7892352184729146
+ 3.7892796149808654
+ 3.7893240107710158
+ 3.789368405843397
+ 3.7894128001980416
+ 3.78945719383498
+ 3.7895015867542434
+ 3.7895459789558648
+ 3.789590370439875
+ 3.7896347612063046
+ 3.789679151255186
+ 3.7897235405865506
+ 3.7897679292004294
+ 3.7898123170968545
+ 3.7898567042758566
+ 3.789901090737468
+ 3.78994547648172
+ 3.7899898615086443
+ 3.7900342458182714
+ 3.7900786294106337
+ 3.7901230122857617
+ 3.7901673944436873
+ 3.790211775884443
+ 3.790256156608059
+ 3.790300536614567
+ 3.790344915903998
+ 3.790389294476385
+ 3.790433672331758
+ 3.790478049470149
+ 3.7905224258915893
+ 3.79056680159611
+ 3.7906111765837434
+ 3.7906555508545208
+ 3.7906999244084725
+ 3.7907442972456313
+ 3.790788669366027
+ 3.790833040769693
+ 3.79087741145666
+ 3.7909217814269587
+ 3.7909661506806214
+ 3.791010519217678
+ 3.7910548870381624
+ 3.7910992541421042
+ 3.791143620529535
+ 3.7911879862004865
+ 3.7912323511549904
+ 3.7912767153930775
+ 3.79132107891478
+ 3.7913654417201283
+ 3.7914098038091546
+ 3.7914541651818894
+ 3.7914985258383656
+ 3.791542885778613
+ 3.7915872450026638
+ 3.7916316035105493
+ 3.7916759613023006
+ 3.79172031837795
+ 3.7917646747375273
+ 3.791809030381065
+ 3.7918533853085936
+ 3.791897739520146
+ 3.7919420930157526
+ 3.7919864457954446
+ 3.7920307978592533
+ 3.792075149207211
+ 3.7921194998393477
+ 3.792163849755696
+ 3.7922081989562866
+ 3.792252547441151
+ 3.7922968952103204
+ 3.7923412422638263
+ 3.7923855886017
+ 3.792429934223973
+ 3.7924742791306763
+ 3.7925186233218415
+ 3.7925629667975005
+ 3.792607309557683
+ 3.792651651602422
+ 3.792695992931748
+ 3.7927403335456926
+ 3.7927846734442867
+ 3.792829012627563
+ 3.7928733510955506
+ 3.7929176888482825
+ 3.7929620258857897
+ 3.793006362208103
+ 3.793050697815254
+ 3.7930950327072743
+ 3.7931393668841946
+ 3.7931837003460473
+ 3.7932280330928623
+ 3.7932723651246723
+ 3.793316696441507
+ 3.793361027043399
+ 3.7934053569303794
+ 3.793449686102479
+ 3.79349401455973
+ 3.793538342302162
+ 3.793582669329808
+ 3.7936269956426982
+ 3.793671321240865
+ 3.7937156461243378
+ 3.79375997029315
+ 3.7938042937473315
+ 3.7938486164869145
+ 3.793892938511929
+ 3.7939372598224077
+ 3.7939815804183814
+ 3.7940259002998804
+ 3.7940702194669376
+ 3.7941145379195826
+ 3.7941588556578476
+ 3.794203172681764
+ 3.7942474889913624
+ 3.794291804586675
+ 3.794336119467732
+ 3.794380433634565
+ 3.794424747087206
+ 3.794469059825685
+ 3.794513371850034
+ 3.794557683160284
+ 3.7946019937564666
+ 3.794646303638612
+ 3.794690612806753
+ 3.794734921260919
+ 3.794779229001143
+ 3.7948235360274554
+ 3.7948678423398876
+ 3.79491214793847
+ 3.794956452823235
+ 3.7950007569942135
+ 3.7950450604514363
+ 3.7950893631949345
+ 3.79513366522474
+ 3.795177966540884
+ 3.795222267143396
+ 3.79526656703231
+ 3.795310866207655
+ 3.795355164669463
+ 3.7953994624177656
+ 3.7954437594525934
+ 3.795488055773977
+ 3.7955323513819494
+ 3.79557664627654
+ 3.7956209404577814
+ 3.7956652339257033
+ 3.795709526680338
+ 3.7957538187217157
+ 3.7957981100498692
+ 3.7958424006648284
+ 3.795886690566624
+ 3.7959309797552887
+ 3.7959752682308525
+ 3.796019555993347
+ 3.7960638430428033
+ 3.796108129379253
+ 3.796152415002726
+ 3.7961966999132546
+ 3.7962409841108697
+ 3.7962852675956023
+ 3.796329550367484
+ 3.796373832426545
+ 3.7964181137728175
+ 3.796462394406332
+ 3.7965066743271194
+ 3.796550953535212
+ 3.7965952320306395
+ 3.7966395098134336
+ 3.796683786883626
+ 3.7967280632412472
+ 3.7967723388863286
+ 3.796816613818901
+ 3.7968608880389954
+ 3.796905161546644
+ 3.7969494343418764
+ 3.796993706424725
+ 3.7970379777952203
+ 3.797082248453393
+ 3.797126518399276
+ 3.797170787632898
+ 3.7972150561542914
+ 3.797259323963487
+ 3.797303591060516
+ 3.7973478574454096
+ 3.797392123118199
+ 3.797436388078915
+ 3.797480652327589
+ 3.797524915864252
+ 3.797569178688934
+ 3.797613440801668
+ 3.7976577022024838
+ 3.797701962891413
+ 3.7977462228684864
+ 3.797790482133735
+ 3.79783474068719
+ 3.7978789985288826
+ 3.797923255658844
+ 3.7979675120771046
+ 3.798011767783696
+ 3.798056022778649
+ 3.7981002770619954
+ 3.7981445306337656
+ 3.7981887834939903
+ 3.7982330356427014
+ 3.7982772870799293
+ 3.7983215378057054
+ 3.7983657878200607
+ 3.798410037123026
+ 3.7984542857146324
+ 3.798498533594911
+ 3.7985427807638934
+ 3.7985870272216093
+ 3.7986312729680916
+ 3.7986755180033693
+ 3.798719762327475
+ 3.798764005940439
+ 3.798808248842293
+ 3.7988524910330668
+ 3.7988967325127927
+ 3.7989409732815003
+ 3.798985213339222
+ 3.7990294526859882
+ 3.79907369132183
+ 3.7991179292467785
+ 3.799162166460864
+ 3.7992064029641193
+ 3.7992506387565728
+ 3.7992948738382575
+ 3.7993391082092036
+ 3.7993833418694427
+ 3.799427574819005
+ 3.799471807057922
+ 3.7995160385862246
+ 3.7995602694039436
+ 3.7996044995111102
+ 3.799648728907756
+ 3.79969295759391
+ 3.799737185569605
+ 3.7997814128348715
+ 3.7998256393897405
+ 3.7998698652342426
+ 3.7999140903684094
+ 3.7999583147922715
+ 3.80000253850586
+ 3.8000467615092055
+ 3.8000909838023396
+ 3.8001352053852924
+ 3.8001794262580955
+ 3.8002236464207795
+ 3.8002678658733755
+ 3.8003120846159146
+ 3.800356302648428
+ 3.8004005199709456
+ 3.8004447365834992
+ 3.80048895248612
+ 3.8005331676788376
+ 3.800577382161685
+ 3.8006215959346914
+ 3.800665808997888
+ 3.800710021351306
+ 3.8007542329949766
+ 3.800798443928931
+ 3.800842654153199
+ 3.800886863667812
+ 3.800931072472801
+ 3.8009752805681973
+ 3.8010194879540316
+ 3.8010636946303342
+ 3.801107900597137
+ 3.80115210585447
+ 3.8011963104023643
+ 3.8012405142408516
+ 3.801284717369962
+ 3.801328919789726
+ 3.8013731215001756
+ 3.8014173225013415
+ 3.8014615227932533
+ 3.801505722375944
+ 3.8015499212494426
+ 3.8015941194137812
+ 3.8016383168689902
+ 3.8016825136151002
+ 3.8017267096521423
+ 3.8017709049801476
+ 3.8018150995991475
+ 3.801859293509171
+ 3.8019034867102515
+ 3.8019476792024176
+ 3.801991870985701
+ 3.8020360620601332
+ 3.8020802524257444
+ 3.8021244420825653
+ 3.8021686310306277
+ 3.802212819269961
+ 3.8022570068005974
+ 3.8023011936225677
+ 3.8023453797359013
+ 3.8023895651406305
+ 3.8024337498367857
+ 3.8024779338243975
+ 3.802522117103497
+ 3.8025662996741145
+ 3.8026104815362816
+ 3.802654662690029
+ 3.802698843135387
+ 3.8027430228723875
+ 3.8027872019010602
+ 3.8028313802214364
+ 3.8028755578335467
+ 3.802919734737422
+ 3.802963910933094
+ 3.8030080864205917
+ 3.8030522611999475
+ 3.8030964352711916
+ 3.8031406086343544
+ 3.8031847812894677
+ 3.8032289532365615
+ 3.803273124475667
+ 3.8033172950068153
+ 3.803361464830036
+ 3.803405633945361
+ 3.80344980235282
+ 3.803493970052445
+ 3.803538137044267
+ 3.803582303328316
+ 3.8036264689046217
+ 3.8036706337732173
+ 3.8037147979341315
+ 3.803758961387397
+ 3.8038031241330423
+ 3.8038472861711004
+ 3.803891447501601
+ 3.803935608124574
+ 3.803979768040052
+ 3.8040239272480645
+ 3.804068085748643
+ 3.8041122435418173
+ 3.804156400627619
+ 3.804200557006079
+ 3.804244712677227
+ 3.8042888676410946
+ 3.8043330218977127
+ 3.8043771754471107
+ 3.8044213282893216
+ 3.804465480424374
+ 3.8045096318523
+ 3.80455378257313
+ 3.804597932586894
+ 3.804642081893624
+ 3.80468623049335
+ 3.804730378386102
+ 3.8047745255719128
+ 3.804818672050811
+ 3.804862817822828
+ 3.8049069628879955
+ 3.804951107246343
+ 3.804995250897902
+ 3.805039393842702
+ 3.8050835360807755
+ 3.805127677612152
+ 3.805171818436862
+ 3.8052159585549368
+ 3.8052600979664075
+ 3.805304236671304
+ 3.8053483746696575
+ 3.805392511961498
+ 3.8054366485468574
+ 3.805480784425765
+ 3.8055249195982523
+ 3.80556905406435
+ 3.805613187824089
+ 3.8056573208774993
+ 3.8057014532246116
+ 3.8057455848654578
+ 3.805789715800067
+ 3.8058338460284706
+ 3.8058779755506995
+ 3.8059221043667835
+ 3.805966232476754
+ 3.8060103598806423
+ 3.8060544865784776
+ 3.8060986125702914
+ 3.806142737856114
+ 3.8061868624359767
+ 3.8062309863099095
+ 3.8062751094779435
+ 3.8063192319401087
+ 3.8063633536964367
+ 3.806407474746957
+ 3.8064515950917017
+ 3.8064957147307
+ 3.806539833663983
+ 3.8065839518915823
+ 3.8066280694135273
+ 3.806672186229849
+ 3.806716302340578
+ 3.8067604177457453
+ 3.806804532445381
+ 3.8068486464395166
+ 3.806892759728181
+ 3.8069368723114074
+ 3.8069809841892237
+ 3.8070250953616624
+ 3.8070692058287534
+ 3.8071133155905272
+ 3.8071574246470146
+ 3.8072015329982465
+ 3.8072456406442527
+ 3.807289747585065
+ 3.807333853820713
+ 3.8073779593512276
+ 3.80742206417664
+ 3.8074661682969793
+ 3.8075102717122777
+ 3.8075543744225646
+ 3.8075984764278714
+ 3.807642577728228
+ 3.807686678323666
+ 3.8077307782142147
+ 3.807774877399906
+ 3.8078189758807692
+ 3.807863073656836
+ 3.807907170728136
+ 3.8079512670947
+ 3.80799536275656
+ 3.808039457713744
+ 3.8080835519662846
+ 3.8081276455142117
+ 3.8081717383575557
+ 3.8082158304963474
+ 3.8082599219306172
+ 3.808304012660396
+ 3.8083481026857138
+ 3.8083921920066013
+ 3.808436280623089
+ 3.808480368535208
+ 3.808524455742989
+ 3.808568542246461
+ 3.808612628045656
+ 3.8086567131406035
+ 3.8087007975313356
+ 3.8087448812178812
+ 3.808788964200272
+ 3.8088330464785374
+ 3.8088771280527087
+ 3.8089212089228166
+ 3.808965289088891
+ 3.8090093685509627
+ 3.8090534473090623
+ 3.80909752536322
+ 3.8091416027134666
+ 3.809185679359833
+ 3.809229755302349
+ 3.809273830541045
+ 3.809317905075952
+ 3.8093619789071007
+ 3.8094060520345208
+ 3.809450124458244
+ 3.8094941961782993
+ 3.8095382671947187
+ 3.809582337507531
+ 3.8096264071167685
+ 3.8096704760224602
+ 3.809714544224638
+ 3.809758611723331
+ 3.8098026785185706
+ 3.8098467446103865
+ 3.80989080999881
+ 3.8099348746838713
+ 3.8099789386656004
+ 3.8100230019440287
+ 3.8100670645191856
+ 3.8101111263911025
+ 3.810155187559809
+ 3.810199248025336
+ 3.8102433077877147
+ 3.8102873668469743
+ 3.8103314252031457
+ 3.81037548285626
+ 3.8104195398063463
+ 3.8104635960534363
+ 3.8105076515975593
+ 3.8105517064387477
+ 3.8105957605770295
+ 3.810639814012437
+ 3.810683866745
+ 3.8107279187747483
+ 3.8107719701017135
+ 3.810816020725925
+ 3.8108600706474136
+ 3.8109041198662106
+ 3.8109481683823447
+ 3.8109922161958476
+ 3.8110362633067494
+ 3.8110803097150803
+ 3.8111243554208714
+ 3.8111684004241524
+ 3.8112124447249536
+ 3.811256488323306
+ 3.81130053121924
+ 3.811344573412785
+ 3.811388614903973
+ 3.811432655692833
+ 3.811476695779396
+ 3.811520735163693
+ 3.8115647738457525
+ 3.8116088118256073
+ 3.8116528491032864
+ 3.81169688567882
+ 3.8117409215522393
+ 3.8117849567235744
+ 3.811828991192855
+ 3.8118730249601125
+ 3.8119170580253767
+ 3.811961090388678
+ 3.812005122050047
+ 3.8120491530095144
+ 3.8120931832671094
+ 3.8121372128228637
+ 3.8121812416768064
+ 3.8122252698289687
+ 3.812269297279381
+ 3.8123133240280733
+ 3.8123573500750765
+ 3.81240137542042
+ 3.8124454000641346
+ 3.812489424006251
+ 3.8125334472467998
+ 3.81257746978581
+ 3.812621491623313
+ 3.8126655127593394
+ 3.8127095331939187
+ 3.8127535529270813
+ 3.8127975719588587
+ 3.8128415902892794
+ 3.812885607918375
+ 3.8129296248461757
+ 3.812973641072712
+ 3.813017656598013
+ 3.8130616714221106
+ 3.8131056855450343
+ 3.8131496989668143
+ 3.8131937116874814
+ 3.8132377237070654
+ 3.813281735025597
+ 3.8133257456431067
+ 3.813369755559624
+ 3.81341376477518
+ 3.8134577732898047
+ 3.813501781103528
+ 3.813545788216381
+ 3.813589794628393
+ 3.813633800339596
+ 3.813677805350018
+ 3.813721809659692
+ 3.8137658132686454
+ 3.81380981617691
+ 3.813853818384516
+ 3.813897819891494
+ 3.8139418206978735
+ 3.8139858208036856
+ 3.81402982020896
+ 3.814073818913727
+ 3.8141178169180168
+ 3.81416181422186
+ 3.8142058108252868
+ 3.8142498067283275
+ 3.814293801931012
+ 3.814337796433371
+ 3.814381790235434
+ 3.8144257833372324
+ 3.8144697757387958
+ 3.8145137674401544
+ 3.814557758441339
+ 3.8146017487423785
+ 3.814645738343305
+ 3.814689727244147
+ 3.814733715444936
+ 3.814777702945702
+ 3.814821689746475
+ 3.814865675847285
+ 3.8149096612481626
+ 3.8149536459491378
+ 3.814997629950241
+ 3.815041613251503
+ 3.815085595852952
+ 3.815129577754621
+ 3.8151735589565376
+ 3.815217539458734
+ 3.81526151926124
+ 3.8153054983640846
+ 3.8153494767672997
+ 3.8153934544709145
+ 3.815437431474959
+ 3.815481407779464
+ 3.81552538338446
+ 3.815569358289976
+ 3.8156133324960435
+ 3.815657306002692
+ 3.815701278809952
+ 3.8157452509178524
+ 3.8157892223264254
+ 3.8158331930357003
+ 3.8158771630457076
+ 3.815921132356476
+ 3.8159651009680378
+ 3.8160090688804216
+ 3.816053036093659
+ 3.8160970026077785
+ 3.816140968422812
+ 3.816184933538788
+ 3.816228897955738
+ 3.8162728616736907
+ 3.8163168246926786
+ 3.816360787012729
+ 3.816404748633875
+ 3.816448709556145
+ 3.8164926697795685
+ 3.8165366293041774
+ 3.8165805881300003
+ 3.8166245462570685
+ 3.8166685036854116
+ 3.81671246041506
+ 3.816756416446044
+ 3.8168003717783936
+ 3.816844326412138
+ 3.816888280347309
+ 3.8169322335839353
+ 3.816976186122048
+ 3.817020137961676
+ 3.8170640891028516
+ 3.8171080395456025
+ 3.8171519892899606
+ 3.817195938335955
+ 3.817239886683616
+ 3.8172838343329745
+ 3.8173277812840594
+ 3.817371727536902
+ 3.817415673091531
+ 3.817459617947978
+ 3.817503562106272
+ 3.8175475055664436
+ 3.817591448328523
+ 3.81763539039254
+ 3.817679331758525
+ 3.817723272426508
+ 3.8177672123965185
+ 3.8178111516685878
+ 3.817855090242745
+ 3.8178990281190206
+ 3.817942965297444
+ 3.8179869017780472
+ 3.8180308375608574
+ 3.818074772645908
+ 3.818118707033226
+ 3.818162640722843
+ 3.818206573714789
+ 3.8182505060090937
+ 3.8182944376057875
+ 3.8183383685049006
+ 3.818382298706463
+ 3.818426228210504
+ 3.818470157017054
+ 3.8185140851261443
+ 3.818558012537803
+ 3.818601939252062
+ 3.81864586526895
+ 3.8186897905884973
+ 3.8187337152107346
+ 3.8187776391356913
+ 3.818821562363398
+ 3.818865484893884
+ 3.8189094067271796
+ 3.8189533278633156
+ 3.818997248302321
+ 3.8190411680442264
+ 3.819085087089061
+ 3.8191290054368565
+ 3.819172923087642
+ 3.8192168400414466
+ 3.8192607562983016
+ 3.8193046718582364
+ 3.819348586721281
+ 3.8193925008874663
+ 3.8194364143568214
+ 3.8194803271293765
+ 3.819524239205162
+ 3.819568150584207
+ 3.819612061266542
+ 3.819655971252198
+ 3.819699880541203
+ 3.819743789133589
+ 3.8197876970293847
+ 3.8198316042286202
+ 3.8198755107313263
+ 3.8199194165375316
+ 3.819963321647268
+ 3.8200072260605635
+ 3.82005112977745
+ 3.8200950327979557
+ 3.820138935122112
+ 3.8201828367499475
+ 3.8202267376814936
+ 3.820270637916779
+ 3.8203145374558347
+ 3.82035843629869
+ 3.820402334445376
+ 3.8204462318959203
+ 3.820490128650355
+ 3.82053402470871
+ 3.820577920071014
+ 3.8206218147372986
+ 3.8206657087075917
+ 3.8207096019819247
+ 3.8207534945603268
+ 3.820797386442829
+ 3.82084127762946
+ 3.8208851681202507
+ 3.820929057915231
+ 3.82097294701443
+ 3.821016835417878
+ 3.8210607231256053
+ 3.8211046101376414
+ 3.821148496454017
+ 3.821192382074761
+ 3.8212362669999043
+ 3.8212801512294754
+ 3.821324034763506
+ 3.821367917602025
+ 3.8214117997450625
+ 3.8214556811926483
+ 3.821499561944812
+ 3.821543442001585
+ 3.821587321362995
+ 3.821631200029074
+ 3.8216750779998505
+ 3.821718955275355
+ 3.821762831855617
+ 3.821806707740667
+ 3.821850582930534
+ 3.821894457425249
+ 3.8219383312248416
+ 3.821982204329341
+ 3.8220260767387777
+ 3.8220699484531813
+ 3.8221138194725817
+ 3.8221576897970095
+ 3.8222015594264938
+ 3.822245428361064
+ 3.8222892966007516
+ 3.8223331641455847
+ 3.8223770309955944
+ 3.82242089715081
+ 3.8224647626112613
+ 3.822508627376979
+ 3.822552491447992
+ 3.8225963548243302
+ 3.8226402175060246
+ 3.8226840794931034
+ 3.822727940785598
+ 3.822771801383537
+ 3.8228156612869513
+ 3.8228595204958693
+ 3.8229033790103233
+ 3.8229472368303403
+ 3.8229910939559524
+ 3.823034950387188
+ 3.823078806124078
+ 3.8231226611666513
+ 3.823166515514938
+ 3.823210369168968
+ 3.8232542221287713
+ 3.823298074394378
+ 3.823341925965817
+ 3.823385776843119
+ 3.823429627026314
+ 3.823473476515431
+ 3.8235173253104997
+ 3.8235611734115507
+ 3.8236050208186136
+ 3.8236488675317184
+ 3.8236927135508942
+ 3.823736558876171
+ 3.8237804035075786
+ 3.823824247445148
+ 3.8238680906889075
+ 3.8239119332388873
+ 3.8239557750951176
+ 3.8239996162576277
+ 3.824043456726448
+ 3.8240872965016073
+ 3.824131135583136
+ 3.824174973971064
+ 3.8242188116654217
+ 3.824262648666237
+ 3.8243064849735418
+ 3.8243503205873646
+ 3.824394155507735
+ 3.8244379897346836
+ 3.8244818232682403
+ 3.8245256561084338
+ 3.824569488255295
+ 3.8246133197088525
+ 3.8246571504691373
+ 3.8247009805361785
+ 3.8247448099100056
+ 3.824788638590649
+ 3.824832466578138
+ 3.8248762938725025
+ 3.8249201204737715
+ 3.8249639463819767
+ 3.825007771597146
+ 3.82505159611931
+ 3.8250954199484983
+ 3.825139243084741
+ 3.8251830655280665
+ 3.8252268872785056
+ 3.825270708336088
+ 3.825314528700843
+ 3.8253583483728018
+ 3.8254021673519922
+ 3.8254459856384444
+ 3.825489803232189
+ 3.8255336201332555
+ 3.8255774363416726
+ 3.8256212518574704
+ 3.8256650666806795
+ 3.825708880811329
+ 3.825752694249448
+ 3.8257965069950677
+ 3.8258403190482166
+ 3.825884130408925
+ 3.825927941077222
+ 3.825971751053138
+ 3.826015560336702
+ 3.8260593689279445
+ 3.8261031768268947
+ 3.8261469840335818
+ 3.8261907905480363
+ 3.8262345963702877
+ 3.8262784015003657
+ 3.8263222059383004
+ 3.8263660096841203
+ 3.826409812737856
+ 3.826453615099537
+ 3.8264974167691927
+ 3.826541217746853
+ 3.826585018032548
+ 3.8266288176263066
+ 3.826672616528159
+ 3.8267164147381343
+ 3.826760212256263
+ 3.826804009082574
+ 3.8268478052170978
+ 3.826891600659863
+ 3.8269353954108998
+ 3.826979189470238
+ 3.827022982837907
+ 3.8270667755139365
+ 3.8271105674983565
+ 3.827154358791196
+ 3.8271981493924856
+ 3.8272419393022536
+ 3.827285728520531
+ 3.827329517047346
+ 3.8273733048827294
+ 3.8274170920267103
+ 3.827460878479319
+ 3.827504664240584
+ 3.827548449310536
+ 3.827592233689204
+ 3.827636017376618
+ 3.8276798003728074
+ 3.8277235826778018
+ 3.827767364291631
+ 3.827811145214324
+ 3.827854925445911
+ 3.8278987049864215
+ 3.8279424838358858
+ 3.827986261994332
+ 3.828030039461791
+ 3.8280738162382915
+ 3.828117592323864
+ 3.828161367718537
+ 3.8282051424223416
+ 3.8282489164353057
+ 3.8282926897574603
+ 3.828336462388834
+ 3.828380234329457
+ 3.8284240055793584
+ 3.828467776138569
+ 3.828511546007116
+ 3.828555315185031
+ 3.828599083672343
+ 3.828642851469082
+ 3.8286866185752766
+ 3.8287303849909566
+ 3.828774150716153
+ 3.8288179157508933
+ 3.8288616800952084
+ 3.8289054437491274
+ 3.82894920671268
+ 3.828992968985895
+ 3.829036730568804
+ 3.829080491461434
+ 3.8291242516638166
+ 3.82916801117598
+ 3.829211769997954
+ 3.8292555281297687
+ 3.829299285571454
+ 3.8293430423230377
+ 3.8293867983845513
+ 3.829430553756023
+ 3.829474308437483
+ 3.8295180624289604
+ 3.8295618157304854
+ 3.829605568342087
+ 3.8296493202637945
+ 3.829693071495638
+ 3.829736822037647
+ 3.82978057188985
+ 3.829824321052278
+ 3.82986806952496
+ 3.829911817307925
+ 3.829955564401203
+ 3.829999310804823
+ 3.8300430565188157
+ 3.8300868015432092
+ 3.830130545878034
+ 3.8301742895233186
+ 3.8302180324790935
+ 3.8302617747453875
+ 3.830305516322231
+ 3.8303492572096522
+ 3.8303929974076816
+ 3.8304367369163486
+ 3.830480475735682
+ 3.8305242138657123
+ 3.830567951306468
+ 3.8306116880579792
+ 3.8306554241202755
+ 3.830699159493386
+ 3.83074289417734
+ 3.8307866281721674
+ 3.8308303614778976
+ 3.8308740940945594
+ 3.8309178260221834
+ 3.8309615572607982
+ 3.831005287810434
+ 3.83104901767112
+ 3.831092746842885
+ 3.8311364753257586
+ 3.831180203119771
+ 3.831223930224952
+ 3.8312676566413293
+ 3.8313113823689333
+ 3.8313551074077945
+ 3.831398831757941
+ 3.831442555419402
+ 3.831486278392208
+ 3.831530000676388
+ 3.8315737222719717
+ 3.831617443178988
+ 3.831661163397466
+ 3.8317048829274367
+ 3.8317486017689277
+ 3.8317923199219703
+ 3.831836037386592
+ 3.8318797541628236
+ 3.8319234702506937
+ 3.8319671856502326
+ 3.8320109003614693
+ 3.832054614384432
+ 3.832098327719152
+ 3.832142040365658
+ 3.832185752323979
+ 3.8322294635941447
+ 3.8322731741761853
+ 3.8323168840701287
+ 3.8323605932760056
+ 3.8324043017938445
+ 3.832448009623675
+ 3.832491716765527
+ 3.8325354232194293
+ 3.8325791289854116
+ 3.832622834063503
+ 3.8326665384537333
+ 3.8327102421561317
+ 3.8327539451707273
+ 3.83279764749755
+ 3.832841349136629
+ 3.832885050087994
+ 3.832928750351673
+ 3.8329724499276967
+ 3.8330161488160948
+ 3.833059847016895
+ 3.833103544530128
+ 3.8331472413558227
+ 3.8331909374940087
+ 3.8332346329447153
+ 3.833278327707972
+ 3.8333220217838075
+ 3.8333657151722518
+ 3.8334094078733343
+ 3.833453099887084
+ 3.8334967912135296
+ 3.833540481852702
+ 3.8335841718046297
+ 3.833627861069342
+ 3.8336715496468683
+ 3.8337152375372376
+ 3.83375892474048
+ 3.8338026112566244
+ 3.8338462970857
+ 3.833889982227736
+ 3.833933666682763
+ 3.8339773504508083
+ 3.8340210335319025
+ 3.834064715926075
+ 3.8341083976333543
+ 3.8341520786537706
+ 3.8341957589873528
+ 3.83423943863413
+ 3.8342831175941323
+ 3.834326795867388
+ 3.834370473453927
+ 3.834414150353778
+ 3.8344578265669718
+ 3.8345015020935356
+ 3.8345451769335
+ 3.834588851086895
+ 3.8346325245537485
+ 3.8346761973340895
+ 3.8347198694279485
+ 3.8347635408353544
+ 3.8348072115563365
+ 3.834850881590924
+ 3.834894550939146
+ 3.8349382196010326
+ 3.8349818875766117
+ 3.8350255548659136
+ 3.835069221468967
+ 3.835112887385802
+ 3.835156552616447
+ 3.8352002171609314
+ 3.835243881019285
+ 3.8352875441915364
+ 3.8353312066777154
+ 3.8353748684778517
+ 3.835418529591973
+ 3.8354621900201096
+ 3.8355058497622907
+ 3.835549508818546
+ 3.8355931671889034
+ 3.8356368248733936
+ 3.835680481872045
+ 3.8357241381848866
+ 3.8357677938119483
+ 3.83581144875326
+ 3.835855103008849
+ 3.835898756578746
+ 3.83594240946298
+ 3.8359860616615795
+ 3.836029713174575
+ 3.8360733640019946
+ 3.8361170141438685
+ 3.836160663600225
+ 3.836204312371094
+ 3.836247960456504
+ 3.8362916078564844
+ 3.836335254571065
+ 3.8363789006002746
+ 3.8364225459441426
+ 3.8364661906026982
+ 3.8365098345759705
+ 3.8365534778639883
+ 3.8365971204667817
+ 3.836640762384379
+ 3.8366844036168097
+ 3.836728044164103
+ 3.8367716840262887
+ 3.8368153232033952
+ 3.836858961695452
+ 3.836902599502489
+ 3.836946236624533
+ 3.8369898730616163
+ 3.8370335088137657
+ 3.837077143881012
+ 3.8371207782633827
+ 3.8371644119609094
+ 3.8372080449736186
+ 3.837251677301541
+ 3.8372953089447055
+ 3.8373389399031415
+ 3.8373825701768776
+ 3.8374261997659436
+ 3.8374698286703675
+ 3.83751345689018
+ 3.8375570844254097
+ 3.8376007112760853
+ 3.837644337442236
+ 3.8376879629238916
+ 3.837731587721081
+ 3.8377752118338324
+ 3.8378188352621763
+ 3.837862458006141
+ 3.8379060800657565
+ 3.837949701441051
+ 3.8379933221320544
+ 3.8380369421387948
+ 3.8380805614613025
+ 3.838124180099606
+ 3.838167798053734
+ 3.838211415323717
+ 3.8382550319095827
+ 3.838298647811361
+ 3.8383422630290807
+ 3.8383858775627715
+ 3.8384294914124615
+ 3.838473104578181
+ 3.8385167170599583
+ 3.838560328857823
+ 3.838603939971803
+ 3.838647550401929
+ 3.838691160148229
+ 3.8387347692107334
+ 3.8387783775894695
+ 3.838821985284468
+ 3.838865592295757
+ 3.8389091986233663
+ 3.838952804267324
+ 3.8389964092276605
+ 3.8390400135044036
+ 3.8390836170975833
+ 3.8391272200072284
+ 3.8391708222333683
+ 3.8392144237760313
+ 3.839258024635247
+ 3.8393016248110445
+ 3.839345224303453
+ 3.8393888231125013
+ 3.839432421238218
+ 3.839476018680633
+ 3.839519615439775
+ 3.8395632115156735
+ 3.8396068069083564
+ 3.8396504016178543
+ 3.839693995644195
+ 3.8397375889874086
+ 3.839781181647523
+ 3.8398247736245685
+ 3.839868364918573
+ 3.8399119555295664
+ 3.8399555454575776
+ 3.839999134702635
+ 3.840042723264768
+ 3.8400863111440064
+ 3.840129898340378
+ 3.8401734848539126
+ 3.8402170706846395
+ 3.8402606558325867
+ 3.840304240297784
+ 3.8403478240802604
+ 3.8403914071800447
+ 3.840434989597166
+ 3.8404785713316536
+ 3.8405221523835356
+ 3.840565732752842
+ 3.8406093124396015
+ 3.840652891443843
+ 3.8406964697655956
+ 3.8407400474048887
+ 3.8407836243617504
+ 3.8408272006362107
+ 3.840870776228298
+ 3.8409143511380415
+ 3.84095792536547
+ 3.8410014989106127
+ 3.8410450717734985
+ 3.8410886439541563
+ 3.8411322154526157
+ 3.8411757862689044
+ 3.841219356403053
+ 3.8412629258550894
+ 3.841306494625043
+ 3.841350062712942
+ 3.8413936301188167
+ 3.8414371968426955
+ 3.841480762884607
+ 3.8415243282445806
+ 3.841567892922645
+ 3.8416114569188293
+ 3.841655020233163
+ 3.8416985828656736
+ 3.8417421448163918
+ 3.8417857060853455
+ 3.8418292666725637
+ 3.841872826578076
+ 3.8419163858019107
+ 3.8419599443440973
+ 3.842003502204664
+ 3.8420470593836407
+ 3.8420906158810553
+ 3.842134171696938
+ 3.8421777268313164
+ 3.8422212812842202
+ 3.842264835055678
+ 3.84230838814572
+ 3.8423519405543733
+ 3.8423954922816677
+ 3.842439043327632
+ 3.8424825936922957
+ 3.8425261433756863
+ 3.8425696923778347
+ 3.8426132406987685
+ 3.8426567883385165
+ 3.8427003352971085
+ 3.842743881574572
+ 3.842787427170938
+ 3.842830972086234
+ 3.8428745163204887
+ 3.842918059873732
+ 3.842961602745992
+ 3.843005144937298
+ 3.8430486864476787
+ 3.8430922272771633
+ 3.84313576742578
+ 3.843179306893559
+ 3.843222845680528
+ 3.8432663837867165
+ 3.8433099212121533
+ 3.8433534579568667
+ 3.843396994020886
+ 3.8434405294042406
+ 3.843484064106959
+ 3.8435275981290697
+ 3.843571131470602
+ 3.843614664131585
+ 3.8436581961120466
+ 3.843701727412017
+ 3.843745258031524
+ 3.843788787970597
+ 3.843832317229265
+ 3.8438758458075566
+ 3.8439193737055
+ 3.8439629009231253
+ 3.8440064274604606
+ 3.8440499533175356
+ 3.8440934784943774
+ 3.844137002991017
+ 3.8441805268074813
+ 3.8442240499438007
+ 3.8442675724000037
+ 3.8443110941761183
+ 3.8443546152721737
+ 3.8443981356881993
+ 3.8444416554242236
+ 3.8444851744802757
+ 3.8445286928563838
+ 3.844572210552577
+ 3.8446157275688844
+ 3.8446592439053346
+ 3.8447027595619567
+ 3.844746274538779
+ 3.8447897888358313
+ 3.8448333024531416
+ 3.8448768153907382
+ 3.8449203276486514
+ 3.8449638392269088
+ 3.8450073501255395
+ 3.845050860344573
+ 3.845094369884037
+ 3.845137878743961
+ 3.8451813869243736
+ 3.8452248944253036
+ 3.8452684012467806
+ 3.8453119073888318
+ 3.8453554128514873
+ 3.8453989176347756
+ 3.8454424217387255
+ 3.845485925163365
+ 3.845529427908724
+ 3.8455729299748307
+ 3.845616431361714
+ 3.845659932069403
+ 3.8457034320979258
+ 3.845746931447312
+ 3.8457904301175896
+ 3.845833928108788
+ 3.8458774254209356
+ 3.845920922054061
+ 3.8459644180081938
+ 3.846007913283362
+ 3.846051407879594
+ 3.84609490179692
+ 3.846138395035368
+ 3.846181887594966
+ 3.8462253794757437
+ 3.8462688706777297
+ 3.8463123612009524
+ 3.8463558510454408
+ 3.846399340211224
+ 3.84644282869833
+ 3.846486316506788
+ 3.846529803636627
+ 3.8465732900878753
+ 3.8466167758605616
+ 3.8466602609547147
+ 3.846703745370364
+ 3.8467472291075375
+ 3.8467907121662637
+ 3.846834194546572
+ 3.8468776762484906
+ 3.846921157272049
+ 3.8469646376172753
+ 3.847008117284198
+ 3.847051596272846
+ 3.8470950745832493
+ 3.8471385522154344
+ 3.847182029169432
+ 3.847225505445269
+ 3.847268981042976
+ 3.8473124559625798
+ 3.8473559302041105
+ 3.8473994037675965
+ 3.8474428766530666
+ 3.847486348860549
+ 3.8475298203900725
+ 3.847573291241666
+ 3.847616761415358
+ 3.8476602309111776
+ 3.8477036997291534
+ 3.8477471678693136
+ 3.847790635331687
+ 3.847834102116303
+ 3.8478775682231903
+ 3.847921033652376
+ 3.8479644984038903
+ 3.8480079624777614
+ 3.848051425874018
+ 3.848094888592689
+ 3.848138350633803
+ 3.848181811997388
+ 3.848225272683473
+ 3.8482687326920875
+ 3.8483121920232595
+ 3.848355650677017
+ 3.84839910865339
+ 3.848442565952406
+ 3.8484860225740944
+ 3.8485294785184836
+ 3.848572933785602
+ 3.8486163883754787
+ 3.848659842288143
+ 3.8487032955236216
+ 3.8487467480819446
+ 3.84879019996314
+ 3.848833651167237
+ 3.8488771016942636
+ 3.8489205515442495
+ 3.8489640007172223
+ 3.8490074492132105
+ 3.8490508970322437
+ 3.84909434417435
+ 3.849137790639558
+ 3.849181236427896
+ 3.849224681539394
+ 3.849268125974078
+ 3.84931156973198
+ 3.8493550128131253
+ 3.8493984552175453
+ 3.8494418969452666
+ 3.8494853379963185
+ 3.8495287783707304
+ 3.8495722180685297
+ 3.8496156570897453
+ 3.8496590954344065
+ 3.849702533102541
+ 3.8497459700941783
+ 3.849789406409346
+ 3.8498328420480736
+ 3.8498762770103894
+ 3.8499197112963213
+ 3.849963144905899
+ 3.85000657783915
+ 3.850050010096104
+ 3.8500934416767882
+ 3.8501368725812326
+ 3.850180302809465
+ 3.8502237323615143
+ 3.850267161237409
+ 3.8503105894371776
+ 3.850354016960848
+ 3.8503974438084505
+ 3.850440869980012
+ 3.8504842954755616
+ 3.850527720295128
+ 3.85057114443874
+ 3.8506145679064256
+ 3.8506579906982132
+ 3.850701412814132
+ 3.850744834254211
+ 3.850788255018478
+ 3.850831675106961
+ 3.8508750945196892
+ 3.8509185132566914
+ 3.850961931317996
+ 3.8510053487036306
+ 3.8510487654136254
+ 3.8510921814480072
+ 3.8511355968068064
+ 3.85117901149005
+ 3.851222425497767
+ 3.8512658388299865
+ 3.851309251486736
+ 3.8513526634680444
+ 3.851396074773941
+ 3.851439485404453
+ 3.8514828953596103
+ 3.85152630463944
+ 3.8515697132439723
+ 3.8516131211732345
+ 3.851656528427255
+ 3.851699935006063
+ 3.8517433409096866
+ 3.851786746138154
+ 3.8518301506914945
+ 3.851873554569736
+ 3.8519169577729073
+ 3.8519603603010375
+ 3.852003762154153
+ 3.852047163332285
+ 3.8520905638354597
+ 3.852133963663707
+ 3.8521773628170553
+ 3.852220761295532
+ 3.852264159099167
+ 3.852307556227988
+ 3.852350952682023
+ 3.852394348461302
+ 3.8524377435658517
+ 3.852481137995702
+ 3.8525245317508805
+ 3.852567924831416
+ 3.8526113172373373
+ 3.8526547089686716
+ 3.8526981000254494
+ 3.8527414904076975
+ 3.8527848801154447
+ 3.85282826914872
+ 3.852871657507551
+ 3.852915045191967
+ 3.852958432201996
+ 3.8530018185376664
+ 3.8530452041990078
+ 3.8530885891860467
+ 3.853131973498813
+ 3.853175357137334
+ 3.8532187401016396
+ 3.853262122391757
+ 3.853305504007715
+ 3.853348884949542
+ 3.8533922652172667
+ 3.8534356448109177
+ 3.8534790237305225
+ 3.8535224019761105
+ 3.8535657795477096
+ 3.8536091564453487
+ 3.8536525326690554
+ 3.853695908218859
+ 3.853739283094787
+ 3.853782657296869
+ 3.8538260308251324
+ 3.853869403679606
+ 3.8539127758603184
+ 3.8539561473672976
+ 3.8539995182005726
+ 3.8540428883601705
+ 3.8540862578461215
+ 3.8541296266584526
+ 3.8541729947971928
+ 3.85421636226237
+ 3.8542597290540135
+ 3.8543030951721513
+ 3.8543464606168114
+ 3.8543898253880227
+ 3.854433189485813
+ 3.854476552910211
+ 3.8545199156612453
+ 3.8545632777389445
+ 3.854606639143336
+ 3.854649999874449
+ 3.854693359932311
+ 3.854736719316952
+ 3.854780078028399
+ 3.8548234360666807
+ 3.854866793431825
+ 3.8549101501238616
+ 3.8549535061428175
+ 3.8549968614887216
+ 3.8550402161616026
+ 3.855083570161488
+ 3.855126923488407
+ 3.855170276142388
+ 3.855213628123458
+ 3.855256979431647
+ 3.8553003300669824
+ 3.855343680029493
+ 3.855387029319207
+ 3.8554303779361527
+ 3.855473725880358
+ 3.855517073151852
+ 3.8555604197506628
+ 3.8556037656768187
+ 3.855647110930348
+ 3.8556904555112785
+ 3.8557337994196392
+ 3.8557771426554583
+ 3.8558204852187647
+ 3.855863827109585
+ 3.8559071683279496
+ 3.855950508873885
+ 3.855993848747421
+ 3.856037187948585
+ 3.8560805264774056
+ 3.8561238643339113
+ 3.85616720151813
+ 3.85621053803009
+ 3.8562538738698207
+ 3.856297209037348
+ 3.8563405435327027
+ 3.8563838773559125
+ 3.8564272105070048
+ 3.8564705429860084
+ 3.8565138747929515
+ 3.8565572059278628
+ 3.85660053639077
+ 3.856643866181702
+ 3.8566871953006863
+ 3.8567305237477516
+ 3.8567738515229264
+ 3.856817178626239
+ 3.856860505057717
+ 3.85690383081739
+ 3.8569471559052846
+ 3.8569904803214303
+ 3.8570338040658547
+ 3.857077127138587
+ 3.857120449539654
+ 3.857163771269085
+ 3.857207092326908
+ 3.8572504127131513
+ 3.8572937324278436
+ 3.8573370514710117
+ 3.857380369842686
+ 3.8574236875428927
+ 3.857467004571661
+ 3.8575103209290194
+ 3.857553636614996
+ 3.8575969516296182
+ 3.857640265972916
+ 3.857683579644916
+ 3.8577268926456467
+ 3.8577702049751372
+ 3.8578135166334153
+ 3.857856827620508
+ 3.8579001379364457
+ 3.8579434475812553
+ 3.8579867565549653
+ 3.858030064857604
+ 3.8580733724891996
+ 3.85811667944978
+ 3.858159985739374
+ 3.858203291358009
+ 3.858246596305714
+ 3.8582899005825175
+ 3.858333204188446
+ 3.8583765071235296
+ 3.8584198093877955
+ 3.858463110981273
+ 3.8585064119039885
+ 3.8585497121559715
+ 3.85859301173725
+ 3.8586363106478516
+ 3.858679608887805
+ 3.8587229064571393
+ 3.8587662033558807
+ 3.858809499584059
+ 3.858852795141702
+ 3.8588960900288374
+ 3.8589393842454935
+ 3.858982677791699
+ 3.8590259706674814
+ 3.8590692628728696
+ 3.8591125544078912
+ 3.8591558452725745
+ 3.859199135466948
+ 3.85924242499104
+ 3.859285713844878
+ 3.8593290020284905
+ 3.8593722895419056
+ 3.859415576385151
+ 3.8594588625582564
+ 3.8595021480612477
+ 3.8595454328941554
+ 3.859588717057006
+ 3.859632000549828
+ 3.8596752833726504
+ 3.8597185655255
+ 3.8597618470084063
+ 3.8598051278213963
+ 3.8598484079644986
+ 3.8598916874377416
+ 3.8599349662411533
+ 3.8599782443747612
+ 3.8600215218385947
+ 3.860064798632681
+ 3.860108074757048
+ 3.8601513502117246
+ 3.8601946249967387
+ 3.8602378991121182
+ 3.8602811725578916
+ 3.8603244453340864
+ 3.8603677174407314
+ 3.860410988877854
+ 3.860454259645483
+ 3.860497529743647
+ 3.860540799172372
+ 3.8605840679316885
+ 3.860627336021623
+ 3.8606706034422045
+ 3.860713870193461
+ 3.8607571362754203
+ 3.86080040168811
+ 3.8608436664315593
+ 3.860886930505796
+ 3.8609301939108476
+ 3.8609734566467426
+ 3.8610167187135094
+ 3.8610599801111753
+ 3.8611032408397694
+ 3.861146500899319
+ 3.8611897602898524
+ 3.8612330190113977
+ 3.861276277063983
+ 3.8613195344476368
+ 3.8613627911623856
+ 3.86140604720826
+ 3.861449302585286
+ 3.8614925572934924
+ 3.861535811332907
+ 3.8615790647035584
+ 3.8616223174054745
+ 3.861665569438683
+ 3.861708820803212
+ 3.86175207149909
+ 3.861795321526345
+ 3.8618385708850043
+ 3.861881819575097
+ 3.8619250675966508
+ 3.861968314949693
+ 3.8620115616342527
+ 3.8620548076503574
+ 3.8620980529980353
+ 3.862141297677314
+ 3.8621845416882223
+ 3.8622277850307882
+ 3.862271027705039
+ 3.8623142697110033
+ 3.8623575110487085
+ 3.8624007517181838
+ 3.8624439917194557
+ 3.862487231052554
+ 3.8625304697175054
+ 3.862573707714338
+ 3.8626169450430803
+ 3.8626601817037605
+ 3.8627034176964057
+ 3.862746653021045
+ 3.8627898876777054
+ 3.862833121666416
+ 3.8628763549872036
+ 3.862919587640097
+ 3.8629628196251242
+ 3.863006050942313
+ 3.8630492815916915
+ 3.8630925115732873
+ 3.863135740887129
+ 3.8631789695332444
+ 3.863222197511661
+ 3.863265424822407
+ 3.8633086514655113
+ 3.863351877441001
+ 3.863395102748904
+ 3.863438327389249
+ 3.8634815513620633
+ 3.863524774667375
+ 3.8635679973052124
+ 3.863611219275603
+ 3.8636544405785758
+ 3.8636976612141574
+ 3.863740881182376
+ 3.8637841004832603
+ 3.863827319116838
+ 3.8638705370831374
+ 3.8639137543821853
+ 3.8639569710140114
+ 3.8640001869786413
+ 3.8640434022761054
+ 3.86408661690643
+ 3.864129830869644
+ 3.8641730441657747
+ 3.864216256794851
+ 3.8642594687568996
+ 3.8643026800519493
+ 3.864345890680027
+ 3.864389100641163
+ 3.8644323099353826
+ 3.864475518562715
+ 3.8645187265231877
+ 3.8645619338168293
+ 3.864605140443667
+ 3.864648346403729
+ 3.8646915516970433
+ 3.864734756323638
+ 3.864777960283541
+ 3.8648211635767797
+ 3.864864366203382
+ 3.8649075681633764
+ 3.8649507694567915
+ 3.864993970083653
+ 3.865037170043991
+ 3.865080369337832
+ 3.865123567965205
+ 3.865166765926137
+ 3.8652099632206567
+ 3.865253159848791
+ 3.8652963558105684
+ 3.8653395511060173
+ 3.8653827457351646
+ 3.865425939698039
+ 3.8654691329946678
+ 3.865512325625079
+ 3.8655555175893013
+ 3.865598708887361
+ 3.8656418995192876
+ 3.8656850894851083
+ 3.8657282787848506
+ 3.865771467418543
+ 3.865814655386213
+ 3.865857842687889
+ 3.8659010293235982
+ 3.8659442152933687
+ 3.8659874005972283
+ 3.8660305852352055
+ 3.8660737692073273
+ 3.866116952513622
+ 3.866160135154118
+ 3.8662033171288424
+ 3.8662464984378224
+ 3.8662896790810874
+ 3.8663328590586645
+ 3.8663760383705816
+ 3.8664192170168663
+ 3.866462394997547
+ 3.8665055723126507
+ 3.8665487489622063
+ 3.866591924946241
+ 3.8666351002647827
+ 3.86667827491786
+ 3.866721448905499
+ 3.8667646222277297
+ 3.8668077948845783
+ 3.8668509668760733
+ 3.866894138202242
+ 3.8669373088631134
+ 3.866980478858714
+ 3.8670236481890723
+ 3.867066816854216
+ 3.8671099848541726
+ 3.8671531521889713
+ 3.867196318858638
+ 3.8672394848632017
+ 3.8672826502026894
+ 3.86732581487713
+ 3.867368978886551
+ 3.8674121422309797
+ 3.8674553049104436
+ 3.8674984669249715
+ 3.8675416282745907
+ 3.8675847889593293
+ 3.8676279489792145
+ 3.8676711083342745
+ 3.8677142670245375
+ 3.8677574250500304
+ 3.8678005824107817
+ 3.8678437391068186
+ 3.8678868951381697
+ 3.867930050504862
+ 3.867973205206923
+ 3.8680163592443817
+ 3.8680595126172657
+ 3.868102665325601
+ 3.868145817369418
+ 3.8681889687487425
+ 3.868232119463604
+ 3.8682752695140277
+ 3.868318418900044
+ 3.868361567621679
+ 3.8684047156789614
+ 3.868447863071918
+ 3.868491009800578
+ 3.868534155864968
+ 3.8685773012651157
+ 3.86862044600105
+ 3.8686635900727966
+ 3.8687067334803853
+ 3.868749876223843
+ 3.8687930183031978
+ 3.8688361597184766
+ 3.8688793004697084
+ 3.86892244055692
+ 3.8689655799801392
+ 3.8690087187393942
+ 3.8690518568347128
+ 3.869094994266121
+ 3.8691381310336497
+ 3.869181267137324
+ 3.8692244025771725
+ 3.869267537353223
+ 3.8693106714655032
+ 3.869353804914041
+ 3.8693969376988635
+ 3.869440069819999
+ 3.8694832012774754
+ 3.86952633207132
+ 3.86956946220156
+ 3.8696125916682242
+ 3.8696557204713393
+ 3.869698848610934
+ 3.8697419760870355
+ 3.8697851028996717
+ 3.8698282290488697
+ 3.869871354534658
+ 3.869914479357063
+ 3.8699576035161143
+ 3.8700007270118384
+ 3.8700438498442633
+ 3.870086972013416
+ 3.8701300935193252
+ 3.870173214362018
+ 3.870216334541523
+ 3.8702594540578663
+ 3.8703025729110765
+ 3.8703456911011815
+ 3.870388808628209
+ 3.8704319254921864
+ 3.8704750416931404
+ 3.8705181572311007
+ 3.8705612721060927
+ 3.870604386318146
+ 3.8706474998672875
+ 3.870690612753545
+ 3.8707337249769456
+ 3.8707768365375177
+ 3.8708199474352885
+ 3.8708630576702863
+ 3.870906167242538
+ 3.8709492761520714
+ 3.8709923843989147
+ 3.8710354919830947
+ 3.87107859890464
+ 3.871121705163577
+ 3.8711648107599346
+ 3.8712079156937396
+ 3.8712510199650203
+ 3.871294123573804
+ 3.8713372265201182
+ 3.8713803288039905
+ 3.8714234304254487
+ 3.8714665313845207
+ 3.8715096316812336
+ 3.8715527313156155
+ 3.8715958302876943
+ 3.871638928597496
+ 3.871682026245051
+ 3.8717251232303838
+ 3.871768219553524
+ 3.871811315214499
+ 3.8718544102133357
+ 3.8718975045500623
+ 3.871940598224706
+ 3.8719836912372956
+ 3.8720267835878572
+ 3.872069875276419
+ 3.8721129663030083
+ 3.872156056667653
+ 3.872199146370381
+ 3.87224223541122
+ 3.872285323790196
+ 3.872328411507339
+ 3.8723714985626745
+ 3.8724145849562315
+ 3.8724576706880365
+ 3.8725007557581184
+ 3.8725438401665033
+ 3.87258692391322
+ 3.8726300069982953
+ 3.872673089421757
+ 3.872716171183633
+ 3.87275925228395
+ 3.872802332722737
+ 3.8728454125000202
+ 3.872888491615828
+ 3.8729315700701874
+ 3.8729746478631264
+ 3.8730177249946727
+ 3.8730608014648538
+ 3.873103877273696
+ 3.8731469524212288
+ 3.873190026907478
+ 3.873233100732473
+ 3.8732761738962402
+ 3.873319246398807
+ 3.8733623182402015
+ 3.8734053894204505
+ 3.873448459939582
+ 3.8734915297976245
+ 3.873534598994604
+ 3.8735776675305487
+ 3.8736207354054866
+ 3.873663802619444
+ 3.87370686917245
+ 3.873749935064531
+ 3.873793000295714
+ 3.8738360648660284
+ 3.8738791287755006
+ 3.8739221920241578
+ 3.873965254612028
+ 3.874008316539139
+ 3.874051377805518
+ 3.874094438411192
+ 3.8741374983561894
+ 3.8741805576405377
+ 3.8742236162642634
+ 3.874266674227395
+ 3.8743097315299595
+ 3.874352788171985
+ 3.874395844153498
+ 3.874438899474527
+ 3.8744819541350988
+ 3.874525008135241
+ 3.874568061474982
+ 3.8746111141543476
+ 3.8746541661733667
+ 3.874697217532067
+ 3.8747402682304743
+ 3.874783318268618
+ 3.874826367646524
+ 3.8748694163642208
+ 3.8749124644217354
+ 3.8749555118190955
+ 3.8749985585563294
+ 3.8750416046334624
+ 3.875084650050524
+ 3.8751276948075404
+ 3.8751707389045404
+ 3.87521378234155
+ 3.875256825118598
+ 3.8752998672357104
+ 3.8753429086929163
+ 3.875385949490242
+ 3.875428989627715
+ 3.875472029105364
+ 3.8755150679232147
+ 3.8755581060812956
+ 3.875601143579634
+ 3.875644180418257
+ 3.875687216597193
+ 3.875730252116468
+ 3.8757732869761106
+ 3.875816321176148
+ 3.875859354716607
+ 3.875902387597516
+ 3.8759454198189016
+ 3.875988451380792
+ 3.8760314822832136
+ 3.876074512526195
+ 3.876117542109763
+ 3.8761605710339455
+ 3.876203599298769
+ 3.876246626904262
+ 3.8762896538504505
+ 3.876332680137364
+ 3.8763757057650277
+ 3.8764187307334708
+ 3.8764617550427194
+ 3.8765047786928015
+ 3.8765478016837447
+ 3.8765908240155764
+ 3.876633845688324
+ 3.876676866702014
+ 3.8767198870566753
+ 3.876762906752334
+ 3.876805925789018
+ 3.876848944166755
+ 3.8768919618855717
+ 3.876934978945496
+ 3.8769779953465555
+ 3.877021011088777
+ 3.8770640261721883
+ 3.8771070405968167
+ 3.87715005436269
+ 3.877193067469834
+ 3.877236079918278
+ 3.877279091708048
+ 3.8773221028391727
+ 3.8773651133116784
+ 3.877408123125593
+ 3.8774511322809437
+ 3.8774941407777574
+ 3.8775371486160624
+ 3.877580155795885
+ 3.877623162317254
+ 3.877666168180195
+ 3.877709173384737
+ 3.8777521779309065
+ 3.877795181818731
+ 3.877838185048238
+ 3.8778811876194546
+ 3.8779241895324077
+ 3.8779671907871256
+ 3.8780101913836353
+ 3.878053191321964
+ 3.878096190602139
+ 3.8781391892241883
+ 3.878182187188139
+ 3.878225184494017
+ 3.8782681811418516
+ 3.878311177131669
+ 3.878354172463497
+ 3.878397167137363
+ 3.8784401611532937
+ 3.878483154511317
+ 3.8785261472114603
+ 3.8785691392537505
+ 3.8786121306382153
+ 3.8786551213648814
+ 3.878698111433777
+ 3.8787411008449286
+ 3.8787840895983643
+ 3.878827077694111
+ 3.8788700651321957
+ 3.8789130519126465
+ 3.87895603803549
+ 3.878999023500753
+ 3.8790420083084647
+ 3.8790849924586506
+ 3.879127975951339
+ 3.8791709587865566
+ 3.879213940964331
+ 3.879256922484689
+ 3.8792999033476585
+ 3.8793428835532673
+ 3.879385863101541
+ 3.8794288419925085
+ 3.879471820226196
+ 3.879514797802632
+ 3.8795577747218424
+ 3.8796007509838555
+ 3.879643726588698
+ 3.8796867015363974
+ 3.879729675826981
+ 3.8797726494604756
+ 3.87981562243691
+ 3.8798585947563087
+ 3.8799015664187015
+ 3.879944537424115
+ 3.879987507772576
+ 3.880030477464112
+ 3.88007344649875
+ 3.8801164148765177
+ 3.8801593825974425
+ 3.8802023496615505
+ 3.880245316068871
+ 3.880288281819429
+ 3.880331246913253
+ 3.8803742113503703
+ 3.8804171751308076
+ 3.880460138254593
+ 3.8805031007217523
+ 3.880546062532314
+ 3.8805890236863045
+ 3.8806319841837524
+ 3.8806749440246833
+ 3.880717903209125
+ 3.880760861737105
+ 3.8808038196086505
+ 3.8808467768237884
+ 3.8808897333825465
+ 3.880932689284952
+ 3.880975644531031
+ 3.8810185991208113
+ 3.881061553054321
+ 3.881104506331586
+ 3.8811474589526345
+ 3.881190410917493
+ 3.88123336222619
+ 3.8812763128787506
+ 3.8813192628752042
+ 3.881362212215576
+ 3.881405160899895
+ 3.881448108928187
+ 3.88149105630048
+ 3.881534003016801
+ 3.8815769490771768
+ 3.8816198944816356
+ 3.881662839230203
+ 3.881705783322908
+ 3.8817487267597763
+ 3.8817916695408363
+ 3.881834611666114
+ 3.8818775531356375
+ 3.8819204939494334
+ 3.8819634341075293
+ 3.8820063736099524
+ 3.8820493124567297
+ 3.8820922506478874
+ 3.882135188183455
+ 3.882178125063457
+ 3.8822210612879227
+ 3.882263996856878
+ 3.882306931770351
+ 3.8823498660283677
+ 3.882392799630956
+ 3.8824357325781436
+ 3.8824786648699563
+ 3.882521596506422
+ 3.882564527487568
+ 3.8826074578134215
+ 3.8826503874840093
+ 3.882693316499359
+ 3.8827362448594966
+ 3.8827791725644505
+ 3.8828220996142475
+ 3.8828650260089144
+ 3.8829079517484786
+ 3.8829508768329672
+ 3.8829938012624075
+ 3.8830367250368263
+ 3.8830796481562513
+ 3.8831225706207086
+ 3.8831654924302264
+ 3.883208413584831
+ 3.88325133408455
+ 3.8832942539294106
+ 3.88333717311944
+ 3.8833800916546646
+ 3.8834230095351123
+ 3.883465926760809
+ 3.883508843331784
+ 3.883551759248062
+ 3.883594674509672
+ 3.88363758911664
+ 3.8836805030689936
+ 3.8837234163667596
+ 3.883766329009965
+ 3.883809240998638
+ 3.883852152332804
+ 3.883895063012491
+ 3.883937973037726
+ 3.8839808824085362
+ 3.8840237911249487
+ 3.8840666991869908
+ 3.8841096065946887
+ 3.8841525133480705
+ 3.8841954194471624
+ 3.8842383248919923
+ 3.884281229682587
+ 3.8843241338189727
+ 3.884367037301178
+ 3.884409940129229
+ 3.8844528423031526
+ 3.884495743822977
+ 3.884538644688728
+ 3.884581544900433
+ 3.8846244444581197
+ 3.8846673433618144
+ 3.884710241611545
+ 3.884753139207338
+ 3.88479603614922
+ 3.8848389324372192
+ 3.8848818280713617
+ 3.884924723051675
+ 3.884967617378185
+ 3.885010511050921
+ 3.8850534040699083
+ 3.8850962964351745
+ 3.8851391881467463
+ 3.8851820792046516
+ 3.8852249696089163
+ 3.8852678593595686
+ 3.885310748456635
+ 3.8853536369001413
+ 3.8853965246901168
+ 3.8854394118265874
+ 3.88548229830958
+ 3.8855251841391216
+ 3.8855680693152395
+ 3.8856109538379604
+ 3.885653837707312
+ 3.885696720923321
+ 3.8857396034860137
+ 3.8857824853954184
+ 3.8858253666515603
+ 3.8858682472544683
+ 3.885911127204169
+ 3.8859540065006883
+ 3.885996885144054
+ 3.8860397631342933
+ 3.8860826404714333
+ 3.8861255171555005
+ 3.8861683931865216
+ 3.8862112685645247
+ 3.8862541432895354
+ 3.886297017361582
+ 3.886339890780691
+ 3.886382763546889
+ 3.8864256356602036
+ 3.886468507120661
+ 3.886511377928289
+ 3.886554248083114
+ 3.8865971175851635
+ 3.886639986434464
+ 3.886682854631043
+ 3.886725722174927
+ 3.886768589066143
+ 3.8868114553047186
+ 3.88685432089068
+ 3.8868971858240546
+ 3.8869400501048688
+ 3.88698291373315
+ 3.8870257767089256
+ 3.887068639032222
+ 3.8871115007030665
+ 3.887154361721485
+ 3.8871972220875057
+ 3.8872400818011554
+ 3.8872829408624603
+ 3.8873257992714483
+ 3.887368657028145
+ 3.8874115141325793
+ 3.8874543705847766
+ 3.8874972263847645
+ 3.8875400815325696
+ 3.887582936028219
+ 3.8876257898717395
+ 3.8876686430631584
+ 3.887711495602502
+ 3.887754347489798
+ 3.887797198725073
+ 3.8878400493083536
+ 3.887882899239667
+ 3.88792574851904
+ 3.8879685971465
+ 3.8880114451220735
+ 3.8880542924457875
+ 3.888097139117669
+ 3.8881399851377445
+ 3.8881828305060413
+ 3.8882256752225866
+ 3.8882685192874065
+ 3.888311362700529
+ 3.8883542054619795
+ 3.8883970475717864
+ 3.8884398890299754
+ 3.8884827298365745
+ 3.88852556999161
+ 3.888568409495109
+ 3.888611248347098
+ 3.8886540865476045
+ 3.8886969240966542
+ 3.8887397609942758
+ 3.888782597240495
+ 3.8888254328353384
+ 3.8888682677788333
+ 3.8889111020710074
+ 3.8889539357118865
+ 3.888996768701498
+ 3.8890396010398685
+ 3.889082432727025
+ 3.8891252637629945
+ 3.8891680941478035
+ 3.8892109238814796
+ 3.8892537529640485
+ 3.8892965813955382
+ 3.8893394091759745
+ 3.889382236305386
+ 3.8894250627837974
+ 3.889467888611237
+ 3.8895107137877307
+ 3.8895535383133066
+ 3.8895963621879903
+ 3.8896391854118098
+ 3.889682007984791
+ 3.889724829906961
+ 3.889767651178347
+ 3.889810471798975
+ 3.8898532917688735
+ 3.889896111088068
+ 3.889938929756585
+ 3.8899817477744523
+ 3.8900245651416965
+ 3.8900673818583438
+ 3.890110197924422
+ 3.8901530133399573
+ 3.890195828104977
+ 3.8902386422195074
+ 3.890281455683575
+ 3.8903242684972086
+ 3.890367080660432
+ 3.890409892173275
+ 3.890452703035762
+ 3.8904955132479215
+ 3.890538322809779
+ 3.8905811317213623
+ 3.890623939982698
+ 3.890666747593813
+ 3.8907095545547334
+ 3.890752360865487
+ 3.8907951665261
+ 3.890837971536599
+ 3.8908807758970116
+ 3.8909235796073633
+ 3.8909663826676826
+ 3.891009185077995
+ 3.891051986838328
+ 3.8910947879487074
+ 3.8911375884091615
+ 3.8911803882197153
+ 3.8912231873803975
+ 3.8912659858912333
+ 3.89130878375225
+ 3.891351580963475
+ 3.8913943775249344
+ 3.8914371734366546
+ 3.891479968698664
+ 3.8915227633109875
+ 3.8915655572736525
+ 3.8916083505866865
+ 3.8916511432501153
+ 3.8916939352639663
+ 3.8917367266282654
+ 3.8917795173430405
+ 3.8918223074083182
+ 3.8918650968241244
+ 3.8919078855904865
+ 3.891950673707431
+ 3.8919934611749847
+ 3.8920362479931745
+ 3.892079034162027
+ 3.8921218196815692
+ 3.8921646045518274
+ 3.892207388772829
+ 3.8922501723445997
+ 3.892292955267167
+ 3.8923357375405576
+ 3.8923785191647986
+ 3.8924213001399157
+ 3.892464080465937
+ 3.8925068601428876
+ 3.8925496391707957
+ 3.892592417549687
+ 3.8926351952795883
+ 3.892677972360527
+ 3.89272074879253
+ 3.892763524575623
+ 3.892806299709833
+ 3.8928490741951873
+ 3.892891848031712
+ 3.8929346212194345
+ 3.8929773937583803
+ 3.8930201656485774
+ 3.893062936890052
+ 3.893105707482831
+ 3.89314847742694
+ 3.8931912467224077
+ 3.8932340153692584
+ 3.8932767833675213
+ 3.893319550717221
+ 3.8933623174183856
+ 3.893405083471041
+ 3.8934478488752147
+ 3.8934906136309326
+ 3.8935333777382217
+ 3.8935761411971086
+ 3.89361890400762
+ 3.893661666169782
+ 3.8937044276836223
+ 3.8937471885491677
+ 3.8937899487664436
+ 3.893832708335478
+ 3.8938754672562963
+ 3.8939182255289264
+ 3.893960983153394
+ 3.894003740129727
+ 3.89404649645795
+ 3.8940892521380923
+ 3.894132007170178
+ 3.8941747615542357
+ 3.8942175152902916
+ 3.894260268378371
+ 3.8943030208185023
+ 3.8943457726107114
+ 3.894388523755025
+ 3.8944312742514695
+ 3.8944740241000724
+ 3.8945167733008588
+ 3.8945595218538576
+ 3.8946022697590927
+ 3.8946450170165936
+ 3.8946877636263846
+ 3.894730509588494
+ 3.894773254902947
+ 3.8948159995697713
+ 3.894858743588993
+ 3.8949014869606393
+ 3.894944229684736
+ 3.8949869717613104
+ 3.895029713190389
+ 3.8950724539719985
+ 3.895115194106165
+ 3.895157933592915
+ 3.895200672432276
+ 3.8952434106242744
+ 3.8952861481689363
+ 3.895328885066289
+ 3.8953716213163583
+ 3.8954143569191717
+ 3.895457091874755
+ 3.8954998261831353
+ 3.8955425598443387
+ 3.8955852928583923
+ 3.8956280252253226
+ 3.8956707569451563
+ 3.89571348801792
+ 3.8957562184436396
+ 3.8957989482223425
+ 3.8958416773540554
+ 3.895884405838804
+ 3.8959271336766155
+ 3.895969860867517
+ 3.8960125874115334
+ 3.896055313308693
+ 3.896098038559022
+ 3.896140763162546
+ 3.8961834871192926
+ 3.896226210429288
+ 3.8962689330925593
+ 3.896311655109132
+ 3.896354376479034
+ 3.89639709720229
+ 3.896439817278929
+ 3.8964825367089757
+ 3.8965252554924574
+ 3.8965679736294003
+ 3.8966106911198315
+ 3.896653407963777
+ 3.896696124161263
+ 3.8967388397123175
+ 3.8967815546169655
+ 3.8968242688752346
+ 3.8968669824871514
+ 3.896909695452742
+ 3.896952407772032
+ 3.89699511944505
+ 3.8970378304718207
+ 3.897080540852371
+ 3.897123250586729
+ 3.8971659596749197
+ 3.8972086681169698
+ 3.897251375912906
+ 3.897294083062755
+ 3.8973367895665434
+ 3.8973794954242975
+ 3.8974222006360435
+ 3.8974649052018084
+ 3.897507609121619
+ 3.897550312395501
+ 3.897593015023481
+ 3.8976357170055866
+ 3.897678418341843
+ 3.8977211190322776
+ 3.8977638190769164
+ 3.897806518475786
+ 3.8978492172289134
+ 3.8978919153363245
+ 3.897934612798046
+ 3.897977309614104
+ 3.8980200057845265
+ 3.898062701309338
+ 3.898105396188566
+ 3.8981480904222376
+ 3.898190784010378
+ 3.8982334769530143
+ 3.8982761692501735
+ 3.8983188609018806
+ 3.898361551908164
+ 3.898404242269049
+ 3.8984469319845623
+ 3.8984896210547304
+ 3.898532309479579
+ 3.898574997259136
+ 3.8986176843934275
+ 3.8986603708824794
+ 3.898703056726319
+ 3.8987457419249716
+ 3.898788426478465
+ 3.8988311103868245
+ 3.8988737936500772
+ 3.898916476268249
+ 3.8989591582413676
+ 3.899001839569458
+ 3.8990445202525477
+ 3.8990872002906625
+ 3.899129879683829
+ 3.899172558432074
+ 3.899215236535424
+ 3.8992579139939045
+ 3.8993005908075427
+ 3.8993432669763655
+ 3.8993859425003983
+ 3.899428617379668
+ 3.8994712916142014
+ 3.899513965204025
+ 3.8995566381491638
+ 3.8995993104496463
+ 3.8996419821054973
+ 3.899684653116744
+ 3.899727323483413
+ 3.89976999320553
+ 3.8998126622831224
+ 3.899855330716215
+ 3.8998979985048363
+ 3.8999406656490114
+ 3.8999833321487674
+ 3.9000259980041294
+ 3.9000686632151256
+ 3.9001113277817807
+ 3.900153991704123
+ 3.900196654982177
+ 3.900239317615971
+ 3.9002819796055297
+ 3.9003246409508803
+ 3.9003673016520493
+ 3.900409961709063
+ 3.9004526211219472
+ 3.900495279890729
+ 3.9005379380154355
+ 3.9005805954960913
+ 3.900623252332724
+ 3.9006659085253594
+ 3.9007085640740247
+ 3.900751218978745
+ 3.900793873239548
+ 3.9008365268564593
+ 3.9008791798295057
+ 3.9009218321587134
+ 3.900964483844109
+ 3.901007134885718
+ 3.901049785283568
+ 3.9010924350376848
+ 3.9011350841480943
+ 3.9011777326148236
+ 3.901220380437899
+ 3.9012630276173463
+ 3.9013056741531926
+ 3.901348320045464
+ 3.9013909652941865
+ 3.901433609899387
+ 3.901476253861091
+ 3.9015188971793258
+ 3.9015615398541175
+ 3.9016041818854923
+ 3.9016468232734764
+ 3.9016894640180966
+ 3.9017321041193784
+ 3.90177474357735
+ 3.9018173823920352
+ 3.901860020563462
+ 3.9019026580916565
+ 3.9019452949766453
+ 3.9019879312184536
+ 3.9020305668171087
+ 3.9020732017726365
+ 3.902115836085064
+ 3.9021584697544167
+ 3.9022011027807215
+ 3.9022437351640042
+ 3.902286366904292
+ 3.9023289980016105
+ 3.902371628455986
+ 3.902414258267445
+ 3.9024568874360135
+ 3.9024995159617184
+ 3.9025421438445855
+ 3.902584771084642
+ 3.902627397681913
+ 3.9026700236364262
+ 3.902712648948206
+ 3.9027552736172804
+ 3.902797897643675
+ 3.902840521027416
+ 3.90288314376853
+ 3.9029257658670433
+ 3.902968387322982
+ 3.9030110081363723
+ 3.903053628307241
+ 3.903096247835614
+ 3.903138866721517
+ 3.9031814849649775
+ 3.9032241025660213
+ 3.9032667195246744
+ 3.9033093358409636
+ 3.9033519515149147
+ 3.9033945665465537
+ 3.903437180935908
+ 3.903479794683003
+ 3.9035224077878645
+ 3.90356502025052
+ 3.903607632070995
+ 3.903650243249316
+ 3.9036928537855093
+ 3.9037354636796016
+ 3.903778072931618
+ 3.903820681541586
+ 3.903863289509531
+ 3.903905896835479
+ 3.903948503519458
+ 3.9039911095614914
+ 3.9040337149616087
+ 3.9040763197198336
+ 3.9041189238361937
+ 3.904161527310715
+ 3.904204130143423
+ 3.904246732334345
+ 3.904289333883507
+ 3.9043319347909344
+ 3.904374535056654
+ 3.9044171346806924
+ 3.9044597336630757
+ 3.9045023320038297
+ 3.9045449297029813
+ 3.904587526760556
+ 3.90463012317658
+ 3.9046727189510806
+ 3.9047153140840827
+ 3.9047579085756134
+ 3.904800502425698
+ 3.9048430956343645
+ 3.9048856882016376
+ 3.9049282801275433
+ 3.904970871412109
+ 3.90501346205536
+ 3.905056052057323
+ 3.9050986414180238
+ 3.905141230137489
+ 3.905183818215745
+ 3.905226405652817
+ 3.905268992448732
+ 3.9053115786035164
+ 3.905354164117196
+ 3.9053967489897965
+ 3.905439333221345
+ 3.9054819168118677
+ 3.90552449976139
+ 3.9055670820699384
+ 3.9056096637375393
+ 3.905652244764219
+ 3.905694825150003
+ 3.9057374048949183
+ 3.9057799839989906
+ 3.9058225624622467
+ 3.9058651402847113
+ 3.905907717466412
+ 3.9059502940073747
+ 3.9059928699076254
+ 3.9060354451671904
+ 3.9060780197860954
+ 3.906120593764367
+ 3.9061631671020316
+ 3.906205739799115
+ 3.9062483118556424
+ 3.906290883271642
+ 3.9063334540471386
+ 3.9063760241821583
+ 3.906418593676728
+ 3.906461162530874
+ 3.906503730744621
+ 3.906546298317996
+ 3.906588865251026
+ 3.906631431543736
+ 3.9066739971961524
+ 3.906716562208302
+ 3.9067591265802095
+ 3.906801690311903
+ 3.9068442534034062
+ 3.906886815854748
+ 3.9069293776659517
+ 3.9069719388370463
+ 3.9070144993680556
+ 3.9070570592590066
+ 3.907099618509926
+ 3.9071421771208388
+ 3.9071847350917723
+ 3.9072272924227516
+ 3.907269849113803
+ 3.9073124051649533
+ 3.907354960576228
+ 3.9073975153476534
+ 3.907440069479256
+ 3.907482622971061
+ 3.907525175823095
+ 3.907567728035384
+ 3.9076102796079546
+ 3.9076528305408327
+ 3.9076953808340438
+ 3.907737930487615
+ 3.9077804795015707
+ 3.907823027875939
+ 3.907865575610745
+ 3.907908122706015
+ 3.907950669161775
+ 3.9079932149780507
+ 3.908035760154869
+ 3.9080783046922556
+ 3.908120848590236
+ 3.9081633918488374
+ 3.908205934468085
+ 3.9082484764480054
+ 3.908291017788624
+ 3.908333558489968
+ 3.9083760985520626
+ 3.908418637974934
+ 3.9084611767586086
+ 3.908503714903112
+ 3.908546252408471
+ 3.9085887892747104
+ 3.9086313255018577
+ 3.908673861089938
+ 3.9087163960389777
+ 3.9087589303490025
+ 3.908801464020039
+ 3.908843997052113
+ 3.9088865294452506
+ 3.9089290611994776
+ 3.908971592314821
+ 3.9090141227913056
+ 3.909056652628958
+ 3.909099181827804
+ 3.9091417103878703
+ 3.9091842383091824
+ 3.9092267655917663
+ 3.9092692922356482
+ 3.909311818240854
+ 3.90935434360741
+ 3.909396868335342
+ 3.909439392424676
+ 3.9094819158754386
+ 3.9095244386876558
+ 3.9095669608613517
+ 3.909609482396555
+ 3.90965200329329
+ 3.909694523551584
+ 3.9097370431714613
+ 3.909779562152949
+ 3.9098220804960735
+ 3.90986459820086
+ 3.9099071152673353
+ 3.9099496316955245
+ 3.909992147485454
+ 3.9100346626371505
+ 3.9100771771506384
+ 3.9101196910259453
+ 3.910162204263097
+ 3.910204716862118
+ 3.9102472288230365
+ 3.9102897401458763
+ 3.910332250830665
+ 3.910374760877428
+ 3.910417270286191
+ 3.910459779056981
+ 3.9105022871898227
+ 3.910544794684743
+ 3.9105873015417676
+ 3.9106298077609227
+ 3.910672313342234
+ 3.910714818285727
+ 3.9107573225914285
+ 3.9107998262593644
+ 3.91084232928956
+ 3.910884831682042
+ 3.910927333436836
+ 3.9109698345539687
+ 3.9110123350334645
+ 3.911054834875351
+ 3.9110973340796527
+ 3.911139832646397
+ 3.9111823305756093
+ 3.911224827867315
+ 3.9112673245215404
+ 3.9113098205383117
+ 3.911352315917655
+ 3.911394810659596
+ 3.9114373047641604
+ 3.9114797982313743
+ 3.9115222910612633
+ 3.9115647832538545
+ 3.911607274809173
+ 3.9116497657272444
+ 3.911692256008095
+ 3.911734745651751
+ 3.9117772346582385
+ 3.9118197230275826
+ 3.91186221075981
+ 3.911904697854946
+ 3.9119471843130174
+ 3.9119896701340493
+ 3.912032155318068
+ 3.912074639865099
+ 3.9121171237751686
+ 3.9121596070483036
+ 3.9122020896845284
+ 3.912244571683869
+ 3.9122870530463527
+ 3.9123295337720037
+ 3.9123720138608493
+ 3.9124144933129146
+ 3.912456972128226
+ 3.912499450306809
+ 3.91254192784869
+ 3.9125844047538947
+ 3.9126268810224487
+ 3.912669356654378
+ 3.9127118316497085
+ 3.912754306008466
+ 3.912796779730677
+ 3.9128392528163674
+ 3.912881725265562
+ 3.9129241970782873
+ 3.9129666682545694
+ 3.9130091387944343
+ 3.913051608697907
+ 3.913094077965015
+ 3.913136546595782
+ 3.9131790145902356
+ 3.9132214819484012
+ 3.913263948670305
+ 3.913306414755972
+ 3.9133488802054286
+ 3.9133913450187006
+ 3.9134338091958143
+ 3.9134762727367947
+ 3.913518735641668
+ 3.9135611979104605
+ 3.9136036595431976
+ 3.9136461205399056
+ 3.91368858090061
+ 3.9137310406253363
+ 3.913773499714111
+ 3.91381595816696
+ 3.913858415983909
+ 3.913900873164983
+ 3.913943329710209
+ 3.9139857856196127
+ 3.914028240893219
+ 3.9140706955310556
+ 3.9141131495331463
+ 3.9141556028995175
+ 3.9141980556301963
+ 3.914240507725207
+ 3.914282959184576
+ 3.9143254100083293
+ 3.914367860196492
+ 3.9144103097490914
+ 3.914452758666152
+ 3.9144952069477
+ 3.9145376545937616
+ 3.9145801016043618
+ 3.914622547979527
+ 3.9146649937192834
+ 3.914707438823656
+ 3.9147498832926715
+ 3.9147923271263547
+ 3.9148347703247315
+ 3.914877212887829
+ 3.9149196548156717
+ 3.914962096108286
+ 3.9150045367656974
+ 3.9150469767879317
+ 3.915089416175015
+ 3.9151318549269725
+ 3.9151742930438314
+ 3.9152167305256156
+ 3.9152591673723522
+ 3.9153016035840666
+ 3.9153440391607846
+ 3.9153864741025317
+ 3.9154289084093348
+ 3.915471342081218
+ 3.9155137751182085
+ 3.915556207520331
+ 3.9155986392876123
+ 3.9156410704200777
+ 3.915683500917753
+ 3.915725930780664
+ 3.9157683600088364
+ 3.915810788602296
+ 3.915853216561069
+ 3.9158956438851797
+ 3.9159380705746556
+ 3.9159804966295217
+ 3.9160229220498035
+ 3.916065346835528
+ 3.916107770986719
+ 3.9161501945034045
+ 3.916192617385608
+ 3.916235039633357
+ 3.9162774612466764
+ 3.9163198822255922
+ 3.9163623025701297
+ 3.9164047222803156
+ 3.9164471413561746
+ 3.916489559797734
+ 3.9165319776050174
+ 3.9165743947780514
+ 3.916616811316863
+ 3.916659227221476
+ 3.916701642491918
+ 3.916744057128213
+ 3.916786471130388
+ 3.916828884498468
+ 3.9168712972324786
+ 3.916913709332446
+ 3.9169561207983965
+ 3.9169985316303553
+ 3.9170409418283474
+ 3.917083351392399
+ 3.9171257603225365
+ 3.9171681686187845
+ 3.9172105762811693
+ 3.9172529833097167
+ 3.917295389704452
+ 3.917337795465402
+ 3.9173802005925906
+ 3.9174226050860455
+ 3.9174650089457903
+ 3.9175074121718527
+ 3.917549814764257
+ 3.91759221672303
+ 3.9176346180481962
+ 3.9176770187397825
+ 3.9177194187978133
+ 3.917761818222316
+ 3.9178042170133147
+ 3.9178466151708355
+ 3.9178890126949044
+ 3.9179314095855475
+ 3.9179738058427898
+ 3.918016201466657
+ 3.9180585964571746
+ 3.9181009908143696
+ 3.918143384538266
+ 3.9181857776288895
+ 3.9182281700862673
+ 3.918270561910424
+ 3.9183129531013856
+ 3.918355343659178
+ 3.918397733583826
+ 3.918440122875356
+ 3.9184825115337936
+ 3.9185248995591637
+ 3.9185672869514936
+ 3.9186096737108067
+ 3.918652059837131
+ 3.9186944453304906
+ 3.918736830190912
+ 3.91877921441842
+ 3.9188215980130408
+ 3.9188639809748005
+ 3.9189063633037233
+ 3.9189487449998364
+ 3.9189911260631645
+ 3.919033506493734
+ 3.9190758862915698
+ 3.919118265456698
+ 3.919160643989144
+ 3.9192030218889338
+ 3.919245399156092
+ 3.9192877757906457
+ 3.9193301517926193
+ 3.9193725271620394
+ 3.919414901898931
+ 3.91945727600332
+ 3.9194996494752314
+ 3.9195420223146917
+ 3.919584394521727
+ 3.919626766096361
+ 3.919669137038621
+ 3.9197115073485316
+ 3.9197538770261193
+ 3.919796246071409
+ 3.9198386144844264
+ 3.9198809822651977
+ 3.919923349413748
+ 3.9199657159301027
+ 3.920008081814288
+ 3.9200504470663287
+ 3.9200928116862515
+ 3.9201351756740808
+ 3.9201775390298432
+ 3.9202199017535637
+ 3.9202622638452684
+ 3.9203046253049822
+ 3.920346986132732
+ 3.920389346328541
+ 3.920431705892437
+ 3.9204740648244454
+ 3.92051642312459
+ 3.9205587807928985
+ 3.9206011378293955
+ 3.920643494234106
+ 3.920685850007057
+ 3.920728205148273
+ 3.9207705596577798
+ 3.9208129135356034
+ 3.920855266781769
+ 3.920897619396302
+ 3.920939971379228
+ 3.9209823227305733
+ 3.921024673450362
+ 3.9210670235386216
+ 3.921109372995376
+ 3.9211517218206517
+ 3.921194070014473
+ 3.9212364175768677
+ 3.9212787645078597
+ 3.921321110807474
+ 3.9213634564757385
+ 3.9214058015126763
+ 3.9214481459183146
+ 3.9214904896926774
+ 3.921532832835792
+ 3.9215751753476824
+ 3.921617517228375
+ 3.9216598584778954
+ 3.9217021990962686
+ 3.921744539083521
+ 3.9217868784396774
+ 3.9218292171647624
+ 3.9218715552588037
+ 3.921913892721826
+ 3.921956229553854
+ 3.9219985657549135
+ 3.922040901325031
+ 3.9220832362642315
+ 3.9221255705725397
+ 3.922167904249982
+ 3.922210237296584
+ 3.9222525697123705
+ 3.9222949014973674
+ 3.9223372326516013
+ 3.9223795631750953
+ 3.922421893067877
+ 3.922464222329971
+ 3.9225065509614025
+ 3.922548878962198
+ 3.922591206332383
+ 3.922633533071982
+ 3.9226758591810205
+ 3.9227181846595247
+ 3.9227605095075204
+ 3.9228028337250325
+ 3.922845157312086
+ 3.9228874802687077
+ 3.922929802594921
+ 3.922972124290754
+ 3.9230144453562303
+ 3.9230567657913764
+ 3.9230990855962173
+ 3.923141404770778
+ 3.923183723315085
+ 3.9232260412291637
+ 3.923268358513038
+ 3.9233106751667357
+ 3.9233529911902805
+ 3.9233953065836986
+ 3.923437621347016
+ 3.923479935480257
+ 3.923522248983447
+ 3.923564561856613
+ 3.923606874099779
+ 3.9236491857129714
+ 3.9236914966962146
+ 3.923733807049535
+ 3.923776116772958
+ 3.923818425866509
+ 3.9238607343302125
+ 3.9239030421640955
+ 3.923945349368182
+ 3.923987655942498
+ 3.92402996188707
+ 3.9240722672019217
+ 3.924114571887079
+ 3.9241568759425682
+ 3.924199179368414
+ 3.9242414821646423
+ 3.924283784331278
+ 3.924326085868347
+ 3.9243683867758747
+ 3.924410687053886
+ 3.924452986702407
+ 3.924495285721463
+ 3.9245375841110786
+ 3.92457988187128
+ 3.9246221790020925
+ 3.9246644755035422
+ 3.924706771375653
+ 3.9247490666184515
+ 3.9247913612319625
+ 3.9248336552162115
+ 3.924875948571225
+ 3.924918241297027
+ 3.924960533393643
+ 3.925002824861099
+ 3.92504511569942
+ 3.9250874059086325
+ 3.92512969548876
+ 3.9251719844398294
+ 3.925214272761866
+ 3.925256560454894
+ 3.92529884751894
+ 3.925341133954029
+ 3.9253834197601867
+ 3.9254257049374375
+ 3.9254679894858078
+ 3.9255102734053224
+ 3.9255525566960072
+ 3.925594839357887
+ 3.925637121390988
+ 3.9256794027953346
+ 3.925721683570953
+ 3.925763963717868
+ 3.925806243236105
+ 3.9258485221256896
+ 3.925890800386648
+ 3.925933078019004
+ 3.9259753550227834
+ 3.9260176313980124
+ 3.9260599071447153
+ 3.9261021822629187
+ 3.9261444567526467
+ 3.9261867306139253
+ 3.9262290038467795
+ 3.9262712764512355
+ 3.9263135484273177
+ 3.9263558197750514
+ 3.926398090494463
+ 3.926440360585577
+ 3.926482630048419
+ 3.9265248988830144
+ 3.926567167089388
+ 3.926609434667566
+ 3.9266517016175735
+ 3.9266939679394355
+ 3.926736233633177
+ 3.926778498698824
+ 3.9268207631364023
+ 3.926863026945936
+ 3.9269052901274515
+ 3.9269475526809736
+ 3.9269898146065274
+ 3.9270320759041386
+ 3.927074336573833
+ 3.9271165966156345
+ 3.9271588560295694
+ 3.927201114815664
+ 3.9272433729739413
+ 3.927285630504428
+ 3.9273278874071496
+ 3.9273701436821313
+ 3.9274123993293975
+ 3.9274546543489746
+ 3.927496908740888
+ 3.9275391625051617
+ 3.927581415641822
+ 3.927623668150894
+ 3.9276659200324033
+ 3.927708171286375
+ 3.9277504219128336
+ 3.927792671911806
+ 3.9278349212833157
+ 3.9278771700273896
+ 3.9279194181440515
+ 3.9279616656333283
+ 3.9280039124952437
+ 3.9280461587298245
+ 3.9280884043370947
+ 3.9281306493170804
+ 3.9281728936698066
+ 3.9282151373952985
+ 3.9282573804935814
+ 3.9282996229646807
+ 3.9283418648086217
+ 3.928384106025429
+ 3.9284263466151295
+ 3.9284685865777464
+ 3.9285108259133064
+ 3.928553064621834
+ 3.9285953027033553
+ 3.9286375401578946
+ 3.928679776985478
+ 3.9287220131861305
+ 3.9287642487598773
+ 3.9288064837067433
+ 3.9288487180267544
+ 3.928890951719935
+ 3.928933184786311
+ 3.9289754172259075
+ 3.9290176490387503
+ 3.9290598802248633
+ 3.9291021107842727
+ 3.9291443407170044
+ 3.929186570023082
+ 3.929228798702532
+ 3.9292710267553788
+ 3.9293132541816487
+ 3.9293554809813656
+ 3.9293977071545556
+ 3.929439932701244
+ 3.9294821576214556
+ 3.929524381915216
+ 3.9295666055825498
+ 3.929608828623483
+ 3.9296510510380407
+ 3.9296932728262473
+ 3.929735493988129
+ 3.9297777145237105
+ 3.9298199344330174
+ 3.929862153716074
+ 3.929904372372907
+ 3.9299465904035404
+ 3.9299888078079994
+ 3.930031024586311
+ 3.9300732407384973
+ 3.9301154562645864
+ 3.9301576711646016
+ 3.930199885438569
+ 3.9302420990865143
+ 3.930284312108461
+ 3.930326524504436
+ 3.9303687362744637
+ 3.930410947418569
+ 3.930453157936778
+ 3.9304953678291152
+ 3.9305375770956057
+ 3.9305797857362754
+ 3.930621993751149
+ 3.9306642011402517
+ 3.930706407903608
+ 3.9307486140412453
+ 3.930790819553186
+ 3.930833024439457
+ 3.9308752287000828
+ 3.9309174323350886
+ 3.9309596353445007
+ 3.9310018377283424
+ 3.9310440394866397
+ 3.9310862406194187
+ 3.9311284411267033
+ 3.931170641008519
+ 3.9312128402648914
+ 3.931255038895845
+ 3.931297236901405
+ 3.9313394342815977
+ 3.9313816310364467
+ 3.931423827165978
+ 3.9314660226702163
+ 3.9315082175491876
+ 3.9315504118029163
+ 3.9315926054314274
+ 3.931634798434747
+ 3.9316769908128992
+ 3.93171918256591
+ 3.9317613736938037
+ 3.931803564196606
+ 3.9318457540743412
+ 3.931887943327036
+ 3.931930131954714
+ 3.931972319957402
+ 3.932014507335123
+ 3.932056694087904
+ 3.932098880215769
+ 3.932141065718744
+ 3.9321832505968524
+ 3.932225434850122
+ 3.9322676184785754
+ 3.9323098014822393
+ 3.9323519838611385
+ 3.9323941656152974
+ 3.932436346744742
+ 3.9324785272494966
+ 3.932520707129587
+ 3.932562886385038
+ 3.932605065015875
+ 3.932647243022122
+ 3.9326894204038063
+ 3.932731597160951
+ 3.9327737732935817
+ 3.932815948801724
+ 3.9328581236854028
+ 3.9329002979446424
+ 3.9329424715794694
+ 3.9329846445899075
+ 3.9330268169759828
+ 3.9330689887377197
+ 3.933111159875143
+ 3.9331533303882793
+ 3.933195500277152
+ 3.933237669541787
+ 3.933279838182209
+ 3.933322006198444
+ 3.933364173590516
+ 3.9334063403584505
+ 3.933448506502273
+ 3.9334906720220073
+ 3.9335328369176796
+ 3.9335750011893147
+ 3.933617164836938
+ 3.933659327860574
+ 3.9337014902602476
+ 3.933743652035985
+ 3.93378581318781
+ 3.933827973715748
+ 3.933870133619825
+ 3.9339122929000645
+ 3.9339544515564926
+ 3.9339966095891334
+ 3.9340387669980137
+ 3.9340809237831573
+ 3.934123079944589
+ 3.9341652354823347
+ 3.934207390396418
+ 3.934249544686866
+ 3.934291698353703
+ 3.9343338513969526
+ 3.934376003816642
+ 3.934418155612794
+ 3.934460306785436
+ 3.9345024573345917
+ 3.934544607260286
+ 3.9345867565625445
+ 3.9346289052413916
+ 3.9346710532968534
+ 3.934713200728953
+ 3.9347553475377177
+ 3.934797493723171
+ 3.9348396392853386
+ 3.9348817842242454
+ 3.9349239285399165
+ 3.9349660722323763
+ 3.9350082153016506
+ 3.935050357747764
+ 3.9350924995707417
+ 3.935134640770608
+ 3.935176781347389
+ 3.935218921301109
+ 3.9352610606317935
+ 3.9353031993394665
+ 3.935345337424154
+ 3.935387474885881
+ 3.9354296117246723
+ 3.9354717479405528
+ 3.9355138835335466
+ 3.935556018503681
+ 3.9355981528509782
+ 3.9356402865754654
+ 3.9356824196771663
+ 3.9357245521561066
+ 3.935766684012311
+ 3.935808815245805
+ 3.935850945856612
+ 3.935893075844759
+ 3.9359352052102694
+ 3.935977333953169
+ 3.936019462073483
+ 3.936061589571236
+ 3.9361037164464525
+ 3.936145842699158
+ 3.936187968329377
+ 3.9362300933371355
+ 3.936272217722457
+ 3.9363143414853683
+ 3.936356464625893
+ 3.9363985871440557
+ 3.9364407090398825
+ 3.9364828303133983
+ 3.9365249509646274
+ 3.9365670709935947
+ 3.9366091904003255
+ 3.9366513091848447
+ 3.9366934273471776
+ 3.9367355448873487
+ 3.936777661805383
+ 3.9368197781013055
+ 3.9368618937751414
+ 3.936904008826915
+ 3.9369461232566514
+ 3.936988237064376
+ 3.937030350250114
+ 3.937072462813889
+ 3.9371145747557272
+ 3.9371566860756526
+ 3.937198796773691
+ 3.9372409068498673
+ 3.9372830163042054
+ 3.937325125136731
+ 3.9373672333474694
+ 3.9374093409364446
+ 3.937451447903682
+ 3.9374935542492064
+ 3.937535659973043
+ 3.9375777650752166
+ 3.9376198695557516
+ 3.9376619734146736
+ 3.9377040766520066
+ 3.937746179267777
+ 3.9377882812620086
+ 3.937830382634726
+ 3.9378724833859553
+ 3.9379145835157208
+ 3.9379566830240473
+ 3.937998781910959
+ 3.9380408801764824
+ 3.938082977820641
+ 3.9381250748434606
+ 3.9381671712449653
+ 3.9382092670251807
+ 3.9382513621841313
+ 3.9382934567218424
+ 3.938335550638338
+ 3.9383776439336438
+ 3.938419736607784
+ 3.9384618286607846
+ 3.9385039200926695
+ 3.938546010903464
+ 3.9385881010931927
+ 3.938630190661881
+ 3.938672279609553
+ 3.9387143679362335
+ 3.9387564556419488
+ 3.938798542726722
+ 3.938840629190579
+ 3.938882715033545
+ 3.9389248002556436
+ 3.9389668848569
+ 3.93900896883734
+ 3.9390510521969873
+ 3.939093134935868
+ 3.939135217054006
+ 3.9391772985514266
+ 3.939219379428154
+ 3.939261459684214
+ 3.9393035393196305
+ 3.9393456183344293
+ 3.9393876967286348
+ 3.9394297745022713
+ 3.939471851655364
+ 3.9395139281879383
+ 3.9395560041000186
+ 3.9395980793916294
+ 3.9396401540627966
+ 3.9396822281135435
+ 3.9397243015438965
+ 3.9397663743538796
+ 3.9398084465435175
+ 3.9398505181128347
+ 3.939892589061857
+ 3.939934659390609
+ 3.939976729099115
+ 3.9400187981874
+ 3.940060866655489
+ 3.9401029345034067
+ 3.9401450017311785
+ 3.9401870683388283
+ 3.940229134326381
+ 3.9402711996938624
+ 3.9403132644412957
+ 3.940355328568707
+ 3.9403973920761213
+ 3.9404394549635624
+ 3.940481517231055
+ 3.9405235788786253
+ 3.9405656399062967
+ 3.9406077003140947
+ 3.940649760102044
+ 3.940691819270169
+ 3.940733877818495
+ 3.940775935747047
+ 3.9408179930558482
+ 3.9408600497449258
+ 3.940902105814303
+ 3.940944161264005
+ 3.940986216094056
+ 3.9410282703044817
+ 3.941070323895307
+ 3.9411123768665552
+ 3.9411544292182525
+ 3.941196480950423
+ 3.941238532063092
+ 3.941280582556284
+ 3.9413226324300235
+ 3.9413646816843353
+ 3.9414067303192444
+ 3.941448778334776
+ 3.941490825730954
+ 3.9415328725078034
+ 3.9415749186653497
+ 3.9416169642036167
+ 3.94165900912263
+ 3.941701053422413
+ 3.941743097102991
+ 3.94178514016439
+ 3.941827182606634
+ 3.9418692244297473
+ 3.9419112656337547
+ 3.941953306218682
+ 3.9419953461845516
+ 3.942037385531391
+ 3.942079424259223
+ 3.942121462368074
+ 3.942163499857967
+ 3.942205536728927
+ 3.9422475729809805
+ 3.9422896086141503
+ 3.9423316436284614
+ 3.94237367802394
+ 3.9424157118006087
+ 3.9424577449584937
+ 3.9424997774976194
+ 3.9425418094180102
+ 3.942583840719692
+ 3.9426258714026874
+ 3.9426679014670234
+ 3.9427099309127227
+ 3.942751959739811
+ 3.942793987948313
+ 3.9428360155382536
+ 3.942878042509657
+ 3.9429200688625485
+ 3.942962094596952
+ 3.943004119712893
+ 3.943046144210396
+ 3.943088168089486
+ 3.943130191350186
+ 3.943172213992523
+ 3.9432142360165203
+ 3.943256257422203
+ 3.943298278209596
+ 3.9433402983787236
+ 3.943382317929611
+ 3.943424336862282
+ 3.9434663551767617
+ 3.9435083728730755
+ 3.943550389951247
+ 3.9435924064113017
+ 3.943634422253264
+ 3.9436764374771585
+ 3.9437184520830098
+ 3.9437604660708425
+ 3.943802479440682
+ 3.943844492192552
+ 3.943886504326478
+ 3.943928515842484
+ 3.943970526740595
+ 3.9440125370208357
+ 3.94405454668323
+ 3.9440965557278043
+ 3.944138564154582
+ 3.9441805719635874
+ 3.944222579154846
+ 3.9442645857283827
+ 3.944306591684221
+ 3.944348597022387
+ 3.9443906017429033
+ 3.9444326058457966
+ 3.9444746093310905
+ 3.94451661219881
+ 3.944558614448979
+ 3.944600616081624
+ 3.9446426170967674
+ 3.9446846174944357
+ 3.944726617274652
+ 3.944768616437442
+ 3.9448106149828295
+ 3.9448526129108403
+ 3.944894610221498
+ 3.9449366069148275
+ 3.944978602990854
+ 3.945020598449601
+ 3.945062593291094
+ 3.9451045875153574
+ 3.945146581122416
+ 3.945188574112294
+ 3.9452305664850162
+ 3.945272558240607
+ 3.9453145493790918
+ 3.945356539900494
+ 3.9453985298048395
+ 3.9454405190921524
+ 3.9454825077624567
+ 3.945524495815778
+ 3.9455664832521404
+ 3.945608470071569
+ 3.945650456274087
+ 3.945692441859721
+ 3.9457344268284937
+ 3.945776411180431
+ 3.9458183949155567
+ 3.945860378033896
+ 3.9459023605354733
+ 3.945944342420313
+ 3.9459863236884396
+ 3.9460283043398783
+ 3.946070284374653
+ 3.9461122637927883
+ 3.9461542425943095
+ 3.946196220779241
+ 3.9462381983476074
+ 3.946280175299432
+ 3.946322151634741
+ 3.9463641273535583
+ 3.9464061024559087
+ 3.946448076941817
+ 3.9464900508113065
+ 3.946532024064403
+ 3.9465739967011317
+ 3.9466159687215145
+ 3.946657940125579
+ 3.9466999109133476
+ 3.946741881084846
+ 3.9467838506400983
+ 3.94682581957913
+ 3.946867787901964
+ 3.9469097556086257
+ 3.9469517226991404
+ 3.946993689173531
+ 3.9470356550318235
+ 3.9470776202740425
+ 3.9471195849002103
+ 3.9471615489103553
+ 3.947203512304498
+ 3.9472454750826658
+ 3.9472874372448827
+ 3.947329398791172
+ 3.947371359721559
+ 3.9474133200360693
+ 3.9474552797347253
+ 3.947497238817553
+ 3.9475391972845757
+ 3.9475811551358198
+ 3.9476231123713093
+ 3.9476650689910673
+ 3.9477070249951196
+ 3.94774898038349
+ 3.947790935156205
+ 3.9478328893132857
+ 3.9478748428547594
+ 3.947916795780649
+ 3.9479587480909806
+ 3.9480006997857777
+ 3.9480426508650646
+ 3.948084601328866
+ 3.948126551177207
+ 3.948168500410111
+ 3.9482104490276035
+ 3.948252397029709
+ 3.948294344416451
+ 3.948336291187855
+ 3.9483782373439458
+ 3.9484201828847465
+ 3.948462127810283
+ 3.948504072120579
+ 3.948546015815658
+ 3.9485879588955473
+ 3.948629901360269
+ 3.948671843209848
+ 3.9487137844443096
+ 3.9487557250636782
+ 3.948797665067977
+ 3.948839604457232
+ 3.9488815432314666
+ 3.948923481390706
+ 3.9489654189349745
+ 3.9490073558642966
+ 3.9490492921786964
+ 3.9490912278781987
+ 3.9491331629628283
+ 3.9491750974326085
+ 3.949217031287565
+ 3.9492589645277216
+ 3.9493008971531034
+ 3.9493428291637342
+ 3.949384760559639
+ 3.949426691340841
+ 3.9494686215073664
+ 3.9495105510592388
+ 3.9495524799964827
+ 3.9495944083191223
+ 3.9496363360271833
+ 3.949678263120689
+ 3.9497201895996628
+ 3.949762115464131
+ 3.949804040714118
+ 3.9498459653496467
+ 3.949887889370743
+ 3.9499298127774316
+ 3.949971735569735
+ 3.95001365774768
+ 3.950055579311289
+ 3.9500975002605876
+ 3.9501394205955997
+ 3.9501813403163504
+ 3.9502232594228635
+ 3.950265177915163
+ 3.9503070957932755
+ 3.9503490130572225
+ 3.9503909297070305
+ 3.9504328457427236
+ 3.9504747611643247
+ 3.9505166759718606
+ 3.9505585901653535
+ 3.950600503744829
+ 3.9506424167103114
+ 3.950684329061825
+ 3.9507262407993946
+ 3.9507681519230444
+ 3.9508100624327986
+ 3.9508519723286812
+ 3.950893881610717
+ 3.950935790278931
+ 3.950977698333347
+ 3.9510196057739893
+ 3.9510615126008823
+ 3.9511034188140504
+ 3.951145324413519
+ 3.9511872293993116
+ 3.951229133771452
+ 3.9512710375299656
+ 3.951312940674876
+ 3.9513548432062087
+ 3.951396745123987
+ 3.9514386464282363
+ 3.951480547118979
+ 3.951522447196242
+ 3.951564346660048
+ 3.951606245510423
+ 3.951648143747389
+ 3.951690041370972
+ 3.951731938381197
+ 3.9517738347780864
+ 3.9518157305616657
+ 3.9518576257319595
+ 3.951899520288991
+ 3.951941414232786
+ 3.9519833075633684
+ 3.952025200280762
+ 3.952067092384992
+ 3.9521089838760823
+ 3.952150874754057
+ 3.9521927650189412
+ 3.9522346546707587
+ 3.9522765437095333
+ 3.9523184321352907
+ 3.952360319948053
+ 3.952402207147848
+ 3.9524440937346976
+ 3.952485979708627
+ 3.952527865069659
+ 3.9525697498178203
+ 3.952611633953134
+ 3.9526535174756243
+ 3.952695400385316
+ 3.9527372826822327
+ 3.9527791643663996
+ 3.9528210454378407
+ 3.952862925896581
+ 3.952904805742643
+ 3.952946684976053
+ 3.952988563596834
+ 3.953030441605011
+ 3.9530723190006083
+ 3.9531141957836495
+ 3.9531560719541603
+ 3.9531979475121637
+ 3.9532398224576846
+ 3.953281696790748
+ 3.9533235705113765
+ 3.9533654436195955
+ 3.953407316115429
+ 3.9534491879989013
+ 3.953491059270038
+ 3.9535329299288615
+ 3.953574799975397
+ 3.953616669409669
+ 3.9536585382317013
+ 3.9537004064415187
+ 3.953742274039145
+ 3.9537841410246037
+ 3.9538260073979212
+ 3.9538678731591204
+ 3.953909738308226
+ 3.953951602845262
+ 3.9539934667702537
+ 3.9540353300832227
+ 3.954077192784197
+ 3.9541190548731984
+ 3.954160916350251
+ 3.954202777215381
+ 3.954244637468611
+ 3.954286497109966
+ 3.9543283561394698
+ 3.9543702145571475
+ 3.9544120723630223
+ 3.954453929557119
+ 3.954495786139462
+ 3.954537642110076
+ 3.9545794974689836
+ 3.954621352216211
+ 3.9546632063517815
+ 3.9547050598757196
+ 3.9547469127880492
+ 3.954788765088795
+ 3.9548306167779814
+ 3.954872467855632
+ 3.9549143183217708
+ 3.9549561681764236
+ 3.9549980174196135
+ 3.9550398660513646
+ 3.9550817140717025
+ 3.9551235614806486
+ 3.9551654082782304
+ 3.95520725446447
+ 3.9552491000393926
+ 3.9552909450030227
+ 3.9553327893553836
+ 3.9553746330965
+ 3.955416476226396
+ 3.955458318745096
+ 3.9555001606526248
+ 3.9555420019490053
+ 3.955583842634262
+ 3.9556256827084204
+ 3.955667522171504
+ 3.9557093610235365
+ 3.9557511992645424
+ 3.9557930368945464
+ 3.9558348739135725
+ 3.9558767103216446
+ 3.9559185461187867
+ 3.9559603813050246
+ 3.9560022158803796
+ 3.9560440498448792
+ 3.956085883198545
+ 3.956127715941403
+ 3.956169548073476
+ 3.9562113795947895
+ 3.9562532105053667
+ 3.9562950408052324
+ 3.9563368704944097
+ 3.9563786995729244
+ 3.9564205280408005
+ 3.956462355898061
+ 3.9565041831447307
+ 3.9565460097808347
+ 3.956587835806395
+ 3.9566296612214384
+ 3.956671486025987
+ 3.9567133102200667
+ 3.9567551338036995
+ 3.956796956776912
+ 3.956838779139727
+ 3.9568806008921684
+ 3.956922422034262
+ 3.95696424256603
+ 3.957006062487497
+ 3.957047881798689
+ 3.9570897004996284
+ 3.9571315185903386
+ 3.9571733360708463
+ 3.9572151529411737
+ 3.9572569692013464
+ 3.9572987848513868
+ 3.9573405998913205
+ 3.9573824143211715
+ 3.957424228140963
+ 3.95746604135072
+ 3.957507853950466
+ 3.9575496659402263
+ 3.957591477320024
+ 3.9576332880898843
+ 3.95767509824983
+ 3.957716907799886
+ 3.9577587167400767
+ 3.9578005250704247
+ 3.9578423327909564
+ 3.957884139901695
+ 3.9579259464026637
+ 3.957967752293888
+ 3.958009557575392
+ 3.958051362247199
+ 3.958093166309333
+ 3.958134969761819
+ 3.958176772604681
+ 3.9582185748379426
+ 3.9582603764616278
+ 3.9583021774757614
+ 3.9583439778803675
+ 3.95838577767547
+ 3.958427576861093
+ 3.9584693754372604
+ 3.958511173403997
+ 3.958552970761325
+ 3.9585947675092714
+ 3.958636563647859
+ 3.9586783591771115
+ 3.9587201540970525
+ 3.9587619484077083
+ 3.9588037421091005
+ 3.9588455352012546
+ 3.9588873276841947
+ 3.958929119557945
+ 3.958970910822529
+ 3.95901270147797
+ 3.959054491524294
+ 3.9590962809615244
+ 3.959138069789685
+ 3.9591798580088002
+ 3.9592216456188933
+ 3.959263432619989
+ 3.9593052190121125
+ 3.9593470047952866
+ 3.9593887899695344
+ 3.9594305745348817
+ 3.9594723584913525
+ 3.9595141418389708
+ 3.9595559245777596
+ 3.959597706707743
+ 3.9596394882289476
+ 3.959681269141394
+ 3.9597230494451083
+ 3.959764829140115
+ 3.9598066082264363
+ 3.9598483867040977
+ 3.9598901645731233
+ 3.959931941833536
+ 3.959973718485361
+ 3.9600154945286223
+ 3.9600572699633436
+ 3.960099044789549
+ 3.9601408190072624
+ 3.960182592616508
+ 3.9602243656173095
+ 3.960266138009692
+ 3.9603079097936784
+ 3.9603496809692937
+ 3.960391451536561
+ 3.960433221495505
+ 3.96047499084615
+ 3.96051675958852
+ 3.9605585277226374
+ 3.9606002952485286
+ 3.9606420621662157
+ 3.9606838284757235
+ 3.960725594177077
+ 3.960767359270299
+ 3.9608091237554137
+ 3.960850887632445
+ 3.960892650901418
+ 3.9609344135623554
+ 3.9609761756152824
+ 3.9610179370602228
+ 3.961059697897199
+ 3.961101458126237
+ 3.96114321774736
+ 3.9611849767605922
+ 3.961226735165958
+ 3.96126849296348
+ 3.961310250153184
+ 3.9613520067350927
+ 3.9613937627092306
+ 3.9614355180756218
+ 3.96147727283429
+ 3.96151902698526
+ 3.9615607805285546
+ 3.9616025334641995
+ 3.9616442857922167
+ 3.961686037512631
+ 3.9617277886254674
+ 3.961769539130748
+ 3.9618112890284984
+ 3.961853038318742
+ 3.9618947870015027
+ 3.961936535076805
+ 3.9619782825446728
+ 3.9620200294051293
+ 3.962061775658199
+ 3.9621035213039053
+ 3.9621452663422736
+ 3.962187010773327
+ 3.962228754597089
+ 3.962270497813584
+ 3.9623122404228366
+ 3.96235398242487
+ 3.9623957238197085
+ 3.9624374646073766
+ 3.9624792047878965
+ 3.962520944361294
+ 3.9625626833275924
+ 3.9626044216868155
+ 3.9626461594389872
+ 3.9626878965841326
+ 3.9627296331222737
+ 3.9627713690534363
+ 3.9628131043776436
+ 3.9628548390949194
+ 3.962896573205287
+ 3.962938306708772
+ 3.9629800396053976
+ 3.9630217718951877
+ 3.9630635035781654
+ 3.9631052346543565
+ 3.963146965123783
+ 3.9631886949864703
+ 3.963230424242442
+ 3.963272152891722
+ 3.9633138809343333
+ 3.9633556083703003
+ 3.9633973351996485
+ 3.9634390614223993
+ 3.9634807870385784
+ 3.96352251204821
+ 3.9635642364513166
+ 3.9636059602479228
+ 3.963647683438053
+ 3.96368940602173
+ 3.963731127998979
+ 3.9637728493698234
+ 3.963814570134287
+ 3.963856290292393
+ 3.963898009844167
+ 3.9639397287896316
+ 3.9639814471288113
+ 3.9640231648617292
+ 3.9640648819884112
+ 3.9641065985088786
+ 3.964148314423158
+ 3.9641900297312707
+ 3.9642317444332416
+ 3.9642734585290955
+ 3.9643151720188547
+ 3.964356884902545
+ 3.9643985971801894
+ 3.964440308851811
+ 3.9644820199174347
+ 3.9645237303770844
+ 3.9645654402307833
+ 3.9646071494785553
+ 3.9646488581204253
+ 3.9646905661564165
+ 3.9647322735865527
+ 3.964773980410858
+ 3.9648156866293562
+ 3.9648573922420716
+ 3.964899097249027
+ 3.9649408016502474
+ 3.964982505445756
+ 3.9650242086355774
+ 3.965065911219734
+ 3.9651076131982523
+ 3.965149314571153
+ 3.9651910153384624
+ 3.965232715500204
+ 3.9652744150563994
+ 3.965316114007076
+ 3.9653578123522553
+ 3.9653995100919617
+ 3.965441207226218
+ 3.9654829037550514
+ 3.965524599678482
+ 3.965566294996535
+ 3.9656079897092353
+ 3.9656496838166055
+ 3.9656913773186706
+ 3.9657330702154527
+ 3.9657747625069777
+ 3.9658164541932677
+ 3.9658581452743475
+ 3.9658998357502413
+ 3.965941525620971
+ 3.965983214886563
+ 3.9660249035470394
+ 3.966066591602425
+ 3.9661082790527424
+ 3.966149965898017
+ 3.966191652138271
+ 3.9662333377735304
+ 3.9662750228038166
+ 3.9663167072291547
+ 3.9663583910495697
+ 3.9664000742650827
+ 3.9664417568757195
+ 3.9664834388815033
+ 3.966525120282458
+ 3.9665668010786077
+ 3.9666084812699762
+ 3.9666501608565867
+ 3.966691839838463
+ 3.9667335182156296
+ 3.96677519598811
+ 3.966816873155928
+ 3.9668585497191082
+ 3.9669002256776724
+ 3.9669419010316465
+ 3.9669835757810534
+ 3.9670252499259164
+ 3.9670669234662603
+ 3.967108596402109
+ 3.967150268733485
+ 3.967191940460413
+ 3.9672336115829165
+ 3.9672752821010193
+ 3.967316952014746
+ 3.9673586213241196
+ 3.9674002900291643
+ 3.967441958129903
+ 3.9674836256263597
+ 3.9675252925185602
+ 3.967566958806525
+ 3.9676086244902806
+ 3.9676502895698493
+ 3.967691954045256
+ 3.967733617916523
+ 3.9677752811836746
+ 3.9678169438467354
+ 3.9678586059057293
+ 3.9679002673606782
+ 3.967941928211608
+ 3.9679835884585413
+ 3.9680252481015015
+ 3.9680669071405137
+ 3.968108565575601
+ 3.9681502234067865
+ 3.968191880634095
+ 3.968233537257549
+ 3.9682751932771745
+ 3.9683168486929925
+ 3.9683585035050286
+ 3.968400157713307
+ 3.9684418113178492
+ 3.968483464318681
+ 3.9685251167158246
+ 3.9685667685093056
+ 3.968608419699146
+ 3.9686500702853693
+ 3.968691720268002
+ 3.968733369647065
+ 3.968775018422584
+ 3.9688166665945803
+ 3.96885831416308
+ 3.968899961128107
+ 3.968941607489682
+ 3.9689832532478317
+ 3.9690248984025795
+ 3.969066542953948
+ 3.9691081869019604
+ 3.9691498302466433
+ 3.9691914729880176
+ 3.9692331151261073
+ 3.9692747566609383
+ 3.969316397592532
+ 3.969358037920913
+ 3.969399677646105
+ 3.969441316768132
+ 3.9694829552870172
+ 3.969524593202784
+ 3.9695662305154573
+ 3.96960786722506
+ 3.9696495033316164
+ 3.9696911388351492
+ 3.9697327737356827
+ 3.9697744080332407
+ 3.9698160417278463
+ 3.9698576748195245
+ 3.969899307308298
+ 3.9699409391941907
+ 3.969982570477226
+ 3.9700242011574276
+ 3.97006583123482
+ 3.970107460709426
+ 3.97014908958127
+ 3.970190717850375
+ 3.970232345516765
+ 3.9702739725804634
+ 3.9703155990414944
+ 3.970357224899882
+ 3.970398850155649
+ 3.9704404748088193
+ 3.9704820988594167
+ 3.970523722307465
+ 3.970565345152988
+ 3.9706069673960083
+ 3.9706485890365513
+ 3.9706902100746393
+ 3.9707318305102963
+ 3.9707734503435472
+ 3.9708150695744133
+ 3.9708566882029195
+ 3.9708983062290897
+ 3.970939923652949
+ 3.9709815404745172
+ 3.9710231566938208
+ 3.9710647723108834
+ 3.9711063873257273
+ 3.9711480017383773
+ 3.9711896155488575
+ 3.971231228757189
+ 3.971272841363399
+ 3.971314453367508
+ 3.9713560647695414
+ 3.971397675569523
+ 3.971439285767475
+ 3.9714808953634226
+ 3.9715225043573885
+ 3.971564112749396
+ 3.9716057205394706
+ 3.971647327727634
+ 3.9716889343139097
+ 3.971730540298323
+ 3.9717721456808968
+ 3.971813750461654
+ 3.9718553546406192
+ 3.971896958217816
+ 3.9719385611932663
+ 3.9719801635669962
+ 3.972021765339029
+ 3.9720633665093854
+ 3.9721049670780926
+ 3.9721465670451725
+ 3.9721881664106493
+ 3.972229765174546
+ 3.9722713633368865
+ 3.972312960897695
+ 3.972354557856993
+ 3.9723961542148065
+ 3.9724377499711587
+ 3.972479345126072
+ 3.9725209396795713
+ 3.9725625336316797
+ 3.972604126982421
+ 3.9726457197318177
+ 3.9726873118798944
+ 3.9727289034266744
+ 3.9727704943721824
+ 3.9728120847164408
+ 3.9728536744594733
+ 3.9728952636013033
+ 3.9729368521419546
+ 3.972978440081451
+ 3.973020027419816
+ 3.9730616141570736
+ 3.9731032002932465
+ 3.973144785828359
+ 3.9731863707624338
+ 3.973227955095496
+ 3.973269538827568
+ 3.9733111219586736
+ 3.973352704488836
+ 3.97339428641808
+ 3.9734358677464274
+ 3.973477448473903
+ 3.97351902860053
+ 3.973560608126333
+ 3.9736021870513336
+ 3.9736437653755563
+ 3.973685343099025
+ 3.9737269202217633
+ 3.9737684967437947
+ 3.973810072665142
+ 3.9738516479858297
+ 3.9738932227058803
+ 3.973934796825318
+ 3.973976370344167
+ 3.97401794326245
+ 3.974059515580189
+ 3.9741010872974116
+ 3.9741426584141384
+ 3.9741842289303935
+ 3.9742257988462
+ 3.9742673681615828
+ 3.974308936876564
+ 3.974350504991168
+ 3.974392072505417
+ 3.974433639419337
+ 3.9744752057329493
+ 3.9745167714462784
+ 3.974558336559348
+ 3.9745999010721813
+ 3.9746414649848014
+ 3.974683028297233
+ 3.974724591009498
+ 3.9747661531216214
+ 3.974807714633626
+ 3.974849275545535
+ 3.9748908358573734
+ 3.9749323955691627
+ 3.974973954680928
+ 3.9750155131926914
+ 3.975057071104478
+ 3.9750986284163097
+ 3.9751401851282115
+ 3.9751817412402066
+ 3.975223296752317
+ 3.9752648516645688
+ 3.975306405976983
+ 3.9753479596895844
+ 3.9753895128023964
+ 3.9754310653154428
+ 3.975472617228746
+ 3.9755141685423303
+ 3.9755557192562185
+ 3.9755972693704362
+ 3.975638818885004
+ 3.975680367799947
+ 3.975721916115288
+ 3.975763463831051
+ 3.9758050109472607
+ 3.9758465574639374
+ 3.975888103381107
+ 3.9759296486987936
+ 3.9759711934170183
+ 3.976012737535806
+ 3.97605428105518
+ 3.976095823975164
+ 3.9761373662957813
+ 3.976178908017054
+ 3.976220449139008
+ 3.976261989661666
+ 3.9763035295850506
+ 3.976345068909185
+ 3.9763866076340944
+ 3.9764281457598005
+ 3.976469683286328
+ 3.9765112202136996
+ 3.9765527565419387
+ 3.9765942922710695
+ 3.976635827401115
+ 3.9766773619320994
+ 3.9767188958640447
+ 3.976760429196975
+ 3.976801961930914
+ 3.976843494065886
+ 3.9768850256019124
+ 3.9769265565390177
+ 3.9769680868772253
+ 3.977009616616559
+ 3.977051145757042
+ 3.977092674298697
+ 3.977134202241549
+ 3.97717572958562
+ 3.9772172563309343
+ 3.9772587824775143
+ 3.977300308025385
+ 3.977341832974568
+ 3.977383357325088
+ 3.9774248810769683
+ 3.9774664042302317
+ 3.9775079267849027
+ 3.9775494487410037
+ 3.9775909700985586
+ 3.9776324908575904
+ 3.9776740110181232
+ 3.97771553058018
+ 3.977757049543784
+ 3.9777985679089594
+ 3.9778400856757288
+ 3.9778816028441164
+ 3.9779231194141436
+ 3.977964635385837
+ 3.9780061507592177
+ 3.978047665534309
+ 3.978089179711136
+ 3.9781306932897205
+ 3.9781722062700866
+ 3.9782137186522584
+ 3.978255230436257
+ 3.9782967416221084
+ 3.9783382522098347
+ 3.97837976219946
+ 3.978421271591006
+ 3.9784627803844983
+ 3.9785042885799586
+ 3.978545796177411
+ 3.9785873031768797
+ 3.9786288095783866
+ 3.978670315381956
+ 3.9787118205876104
+ 3.9787533251953744
+ 3.97879482920527
+ 3.978836332617322
+ 3.9788778354315517
+ 3.978919337647985
+ 3.978960839266644
+ 3.979002340287552
+ 3.9790438407107334
+ 3.97908534053621
+ 3.9791268397640054
+ 3.9791683383941447
+ 3.9792098364266493
+ 3.979251333861543
+ 3.9792928306988498
+ 3.979334326938592
+ 3.9793758225807943
+ 3.97941731762548
+ 3.979458812072671
+ 3.9795003059223917
+ 3.979541799174665
+ 3.9795832918295146
+ 3.979624783886964
+ 3.979666275347036
+ 3.979707766209755
+ 3.979749256475143
+ 3.9797907461432236
+ 3.979832235214021
+ 3.979873723687558
+ 3.9799152115638576
+ 3.9799566988429436
+ 3.9799981855248387
+ 3.980039671609568
+ 3.980081157097153
+ 3.980122641987617
+ 3.9801641262809846
+ 3.980205609977278
+ 3.9802470930765215
+ 3.980288575578737
+ 3.98033005748395
+ 3.980371538792182
+ 3.9804130195034566
+ 3.9804544996177973
+ 3.980495979135228
+ 3.9805374580557706
+ 3.9805789363794504
+ 3.9806204141062893
+ 3.9806618912363105
+ 3.980703367769538
+ 3.980744843705996
+ 3.980786319045705
+ 3.980827793788691
+ 3.9808692679349753
+ 3.9809107414845832
+ 3.980952214437537
+ 3.9809936867938585
+ 3.9810351585535737
+ 3.981076629716704
+ 3.981118100283274
+ 3.9811595702533062
+ 3.9812010396268245
+ 3.981242508403851
+ 3.9812839765844097
+ 3.9813254441685237
+ 3.981366911156217
+ 3.981408377547512
+ 3.9814498433424332
+ 3.981491308541002
+ 3.9815327731432437
+ 3.98157423714918
+ 3.981615700558835
+ 3.981657163372231
+ 3.981698625589393
+ 3.981740087210343
+ 3.9817815482351047
+ 3.9818230086637
+ 3.981864468496154
+ 3.9819059277324906
+ 3.9819473863727306
+ 3.981988844416899
+ 3.982030301865018
+ 3.9820717587171113
+ 3.9821132149732033
+ 3.982154670633315
+ 3.9821961256974716
+ 3.982237580165696
+ 3.9822790340380103
+ 3.9823204873144387
+ 3.982361939995004
+ 3.9824033920797297
+ 3.9824448435686404
+ 3.9824862944617565
+ 3.982527744759103
+ 3.982569194460704
+ 3.9826106435665802
+ 3.982652092076757
+ 3.982693539991257
+ 3.9827349873101023
+ 3.9827764340333185
+ 3.9828178801609266
+ 3.9828593256929516
+ 3.9829007706294157
+ 3.982942214970342
+ 3.9829836587157534
+ 3.983025101865675
+ 3.983066544420128
+ 3.9831079863791374
+ 3.9831494277427244
+ 3.983190868510913
+ 3.983232308683728
+ 3.98327374826119
+ 3.9833151872433237
+ 3.9833566256301522
+ 3.9833980634216997
+ 3.9834395006179872
+ 3.983480937219039
+ 3.983522373224879
+ 3.983563808635529
+ 3.9836052434510134
+ 3.9836466776713553
+ 3.9836881112965767
+ 3.983729544326702
+ 3.9837709767617544
+ 3.983812408601757
+ 3.983853839846732
+ 3.9838952704967032
+ 3.9839367005516944
+ 3.9839781300117285
+ 3.984019558876828
+ 3.9840609871470174
+ 3.9841024148223183
+ 3.9841438419027546
+ 3.984185268388351
+ 3.9842266942791276
+ 3.9842681195751104
+ 3.984309544276321
+ 3.9843509683827825
+ 3.9843923918945188
+ 3.984433814811553
+ 3.9844752371339083
+ 3.9845166588616077
+ 3.9845580799946743
+ 3.984599500533131
+ 3.9846409204770015
+ 3.984682339826309
+ 3.9847237585810764
+ 3.9847651767413264
+ 3.984806594307083
+ 3.9848480112783693
+ 3.9848894276552076
+ 3.984930843437622
+ 3.984972258625635
+ 3.9850136732192705
+ 3.985055087218551
+ 3.985096500623499
+ 3.9851379134341394
+ 3.985179325650495
+ 3.9852207372725874
+ 3.9852621483004413
+ 3.985303558734079
+ 3.9853449685735236
+ 3.985386377818799
+ 3.9854277864699283
+ 3.985469194526933
+ 3.9855106019898385
+ 3.9855520088586673
+ 3.9855934151334416
+ 3.9856348208141843
+ 3.9856762259009204
+ 3.985717630393672
+ 3.9857590342924616
+ 3.985800437597313
+ 3.985841840308249
+ 3.985883242425294
+ 3.985924643948469
+ 3.9859660448777983
+ 3.9860074452133056
+ 3.9860488449550124
+ 3.9860902441029435
+ 3.986131642657121
+ 3.9861730406175684
+ 3.9862144379843083
+ 3.986255834757364
+ 3.9862972309367595
+ 3.986338626522517
+ 3.9863800215146603
+ 3.986421415913211
+ 3.986462809718194
+ 3.986504202929631
+ 3.9865455955475464
+ 3.9865869875719624
+ 3.986628379002902
+ 3.9866697698403892
+ 3.9867111600844463
+ 3.986752549735096
+ 3.986793938792363
+ 3.986835327256269
+ 3.986876715126838
+ 3.986918102404091
+ 3.9869594890880538
+ 3.9870008751787487
+ 3.9870422606761973
+ 3.9870836455804244
+ 3.9871250298914522
+ 3.987166413609305
+ 3.9872077967340043
+ 3.9872491792655738
+ 3.9872905612040364
+ 3.987331942549415
+ 3.987373323301734
+ 3.9874147034610155
+ 3.9874560830272814
+ 3.9874974620005577
+ 3.987538840380864
+ 3.9875802181682256
+ 3.9876215953626652
+ 3.987662971964206
+ 3.9877043479728704
+ 3.9877457233886813
+ 3.987787098211663
+ 3.9878284724418376
+ 3.9878698460792283
+ 3.9879112191238586
+ 3.9879525915757505
+ 3.987993963434928
+ 3.9880353347014137
+ 3.988076705375232
+ 3.9881180754564034
+ 3.988159444944952
+ 3.9882008138409026
+ 3.9882421821442757
+ 3.988283549855096
+ 3.988324916973385
+ 3.9883662834991678
+ 3.988407649432466
+ 3.988449014773303
+ 3.988490379521702
+ 3.9885317436776853
+ 3.9885731072412764
+ 3.988614470212499
+ 3.9886558325913746
+ 3.9886971943779277
+ 3.9887385555721804
+ 3.9887799161741566
+ 3.9888212761838786
+ 3.9888626356013694
+ 3.988903994426653
+ 3.988945352659751
+ 3.988986710300687
+ 3.989028067349484
+ 3.9890694238061655
+ 3.9891107796707534
+ 3.989152134943272
+ 3.989193489623743
+ 3.989234843712192
+ 3.9892761972086386
+ 3.9893175501131064
+ 3.989358902425621
+ 3.989400254146203
+ 3.989441605274877
+ 3.989482955811664
+ 3.989524305756589
+ 3.9895656551096725
+ 3.989607003870941
+ 3.989648352040414
+ 3.989689699618117
+ 3.989731046604072
+ 3.989772392998302
+ 3.9898137388008297
+ 3.9898550840116784
+ 3.9898964286308716
+ 3.9899377726584313
+ 3.9899791160943816
+ 3.9900204589387447
+ 3.9900618011915436
+ 3.9901031428528007
+ 3.9901444839225406
+ 3.990185824400785
+ 3.9902271642875564
+ 3.9902685035828793
+ 3.9903098422867767
+ 3.990351180399269
+ 3.9903925179203825
+ 3.990433854850138
+ 3.9904751911885588
+ 3.9905165269356684
+ 3.99055786209149
+ 3.9905991966560452
+ 3.9906405306293586
+ 3.9906818640114516
+ 3.990723196802349
+ 3.9907645290020723
+ 3.9908058606106445
+ 3.9908471916280885
+ 3.9908885220544286
+ 3.990929851889686
+ 3.9909711811338853
+ 3.991012509787048
+ 3.9910538378491975
+ 3.9910951653203566
+ 3.9911364922005492
+ 3.991177818489797
+ 3.9912191441881233
+ 3.991260469295552
+ 3.9913017938121045
+ 3.9913431177378045
+ 3.991384441072675
+ 3.9914257638167387
+ 3.9914670859700183
+ 3.9915084075325376
+ 3.9915497285043187
+ 3.9915910488853847
+ 3.991632368675759
+ 3.991673687875464
+ 3.991715006484523
+ 3.991756324502958
+ 3.9917976419307934
+ 3.9918389587680507
+ 3.9918802750147537
+ 3.9919215906709247
+ 3.9919629057365875
+ 3.9920042202117645
+ 3.9920455340964778
+ 3.9920868473907514
+ 3.9921281600946084
+ 3.99216947220807
+ 3.9922107837311613
+ 3.9922520946639035
+ 3.9922934050063206
+ 3.9923347147584347
+ 3.99237602392027
+ 3.9924173324918475
+ 3.9924586404731905
+ 3.992499947864323
+ 3.992541254665268
+ 3.992582560876047
+ 3.9926238664966838
+ 3.9926651715272006
+ 3.9927064759676214
+ 3.9927477798179685
+ 3.992789083078264
+ 3.9928303857485328
+ 3.9928716878287953
+ 3.9929129893190756
+ 3.9929542902193966
+ 3.9929955905297816
+ 3.9930368902502527
+ 3.993078189380833
+ 3.9931194879215446
+ 3.9931607858724125
+ 3.993202083233457
+ 3.9932433800047034
+ 3.9932846761861733
+ 3.9933259717778884
+ 3.9933672667798743
+ 3.9934085611921515
+ 3.993449855014744
+ 3.993491148247674
+ 3.9935324408909643
+ 3.9935737329446384
+ 3.99361502440872
+ 3.99365631528323
+ 3.9936976055681925
+ 3.9937388952636295
+ 3.9937801843695646
+ 3.99382147288602
+ 3.9938627608130193
+ 3.993904048150585
+ 3.9939453348987395
+ 3.993986621057507
+ 3.9940279066269073
+ 3.994069191606967
+ 3.9941104759977066
+ 3.99415175979915
+ 3.9941930430113195
+ 3.994234325634238
+ 3.994275607667927
+ 3.994316889112412
+ 3.994358169967715
+ 3.9943994502338573
+ 3.994440729910863
+ 3.9944820089987547
+ 3.994523287497555
+ 3.994564565407287
+ 3.994605842727974
+ 3.994647119459638
+ 3.9946883956023016
+ 3.9947296711559885
+ 3.994770946120721
+ 3.9948122204965215
+ 3.9948534942834137
+ 3.9948947674814197
+ 3.9949360400905634
+ 3.994977312110865
+ 3.995018583542351
+ 3.9950598543850417
+ 3.99510112463896
+ 3.9951423943041298
+ 3.995183663380573
+ 3.995224931868313
+ 3.995266199767372
+ 3.995307467077773
+ 3.995348733799539
+ 3.995389999932693
+ 3.9954312654772575
+ 3.9954725304332546
+ 3.9955137948007073
+ 3.9955550585796398
+ 3.995596321770073
+ 3.9956375843720315
+ 3.995678846385537
+ 3.995720107810612
+ 3.99576136864728
+ 3.995802628895564
+ 3.9958438885554846
+ 3.995885147627068
+ 3.995926406110334
+ 3.9959676640053075
+ 3.996008921312009
+ 3.996050178030464
+ 3.9960914341606926
+ 3.9961326897027196
+ 3.9961739446565674
+ 3.996215199022258
+ 3.996256452799814
+ 3.996297705989259
+ 3.996338958590615
+ 3.9963802106039057
+ 3.996421462029154
+ 3.9964627128663808
+ 3.9965039631156105
+ 3.9965452127768644
+ 3.996586461850167
+ 3.9966277103355403
+ 3.9966689582330077
+ 3.9967102055425907
+ 3.9967514522643124
+ 3.996792698398196
+ 3.996833943944264
+ 3.9968751889025387
+ 3.9969164332730434
+ 3.9969576770558013
+ 3.996998920250834
+ 3.997040162858164
+ 3.997081404877816
+ 3.9971226463098106
+ 3.9971638871541724
+ 3.9972051274109224
+ 3.9972463670800846
+ 3.9972876061616804
+ 3.9973288446557347
+ 3.997370082562268
+ 3.9974113198813037
+ 3.9974525566128647
+ 3.997493792756974
+ 3.997535028313654
+ 3.997576263282928
+ 3.9976174976648173
+ 3.9976587314593455
+ 3.9976999646665354
+ 3.9977411972864094
+ 3.9977824293189914
+ 3.997823660764302
+ 3.9978648916223647
+ 3.997906121893204
+ 3.99794735157684
+ 3.997988580673297
+ 3.998029809182596
+ 3.998071037104762
+ 3.998112264439816
+ 3.998153491187782
+ 3.998194717348681
+ 3.998235942922537
+ 3.998277167909373
+ 3.9983183923092107
+ 3.9983596161220727
+ 3.998400839347982
+ 3.9984420619869616
+ 3.9984832840390347
+ 3.9985245055042227
+ 3.9985657263825494
+ 3.998606946674036
+ 3.998648166378706
+ 3.9986893854965824
+ 3.998730604027688
+ 3.998771821972045
+ 3.9988130393296752
+ 3.998854256100604
+ 3.998895472284851
+ 3.998936687882441
+ 3.9989779028933943
+ 3.999019117317736
+ 3.9990603311554884
+ 3.9991015444066735
+ 3.9991427570713136
+ 3.9991839691494317
+ 3.999225180641051
+ 3.9992663915461937
+ 3.9993076018648828
+ 3.9993488115971405
+ 3.999390020742989
+ 3.9994312293024517
+ 3.9994724372755512
+ 3.999513644662311
+ 3.999554851462752
+ 3.999596057676897
+ 3.9996372633047703
+ 3.9996784683463926
+ 3.999719672801788
+ 3.9997608766709782
+ 3.999802079953987
+ 3.999843282650836
+ 3.9998844847615476
+ 3.999925686286145
+ 3.999966887224651
+ 4.000008087577089
+ 4.000049287343479
+ 4.000090486523846
+ 4.000131685118212
+ 4.000172883126599
+ 4.00021408054903
+ 4.000255277385528
+ 4.000296473636115
+ 4.000337669300815
+ 4.000378864379648
+ 4.000420058872639
+ 4.00046125277981
+ 4.0005024461011836
+ 4.000543638836781
+ 4.000584830986628
+ 4.000626022550744
+ 4.0006672135291526
+ 4.000708403921877
+ 4.00074959372894
+ 4.000790782950363
+ 4.0008319715861695
+ 4.000873159636382
+ 4.0009143471010225
+ 4.000955533980115
+ 4.00099672027368
+ 4.001037905981741
+ 4.001079091104321
+ 4.001120275641444
+ 4.0011614595931295
+ 4.001202642959402
+ 4.001243825740284
+ 4.001285007935798
+ 4.001326189545965
+ 4.001367370570811
+ 4.001408551010354
+ 4.001449730864621
+ 4.001490910133632
+ 4.00153208881741
+ 4.001573266915979
+ 4.001614444429359
+ 4.001655621357575
+ 4.001696797700648
+ 4.001737973458601
+ 4.0017791486314565
+ 4.0018203232192375
+ 4.001861497221967
+ 4.001902670639666
+ 4.001943843472358
+ 4.0019850157200665
+ 4.002026187382811
+ 4.002067358460618
+ 4.002108528953507
+ 4.002149698861503
+ 4.002190868184626
+ 4.0022320369229005
+ 4.0022732050763485
+ 4.002314372644992
+ 4.002355539628854
+ 4.002396706027957
+ 4.002437871842324
+ 4.002479037071977
+ 4.002520201716939
+ 4.002561365777231
+ 4.0026025292528775
+ 4.0026436921438995
+ 4.0026848544503215
+ 4.002726016172164
+ 4.002767177309451
+ 4.002808337862204
+ 4.0028494978304465
+ 4.002890657214199
+ 4.002931816013487
+ 4.0029729742283315
+ 4.003014131858754
+ 4.003055288904779
+ 4.0030964453664275
+ 4.003137601243723
+ 4.003178756536688
+ 4.003219911245344
+ 4.003261065369714
+ 4.003302218909821
+ 4.003343371865687
+ 4.003384524237335
+ 4.003425676024787
+ 4.003466827228066
+ 4.003507977847194
+ 4.003549127882194
+ 4.003590277333088
+ 4.003631426199899
+ 4.003672574482649
+ 4.00371372218136
+ 4.003754869296057
+ 4.00379601582676
+ 4.003837161773492
+ 4.003878307136276
+ 4.0039194519151335
+ 4.003960596110089
+ 4.004001739721162
+ 4.0040428827483785
+ 4.004084025191759
+ 4.004125167051325
+ 4.0041663083271
+ 4.004207449019108
+ 4.00424858912737
+ 4.004289728651908
+ 4.004330867592746
+ 4.004372005949905
+ 4.004413143723408
+ 4.0044542809132775
+ 4.004495417519536
+ 4.004536553542206
+ 4.00457768898131
+ 4.0046188238368705
+ 4.00465995810891
+ 4.00470109179745
+ 4.004742224902515
+ 4.004783357424126
+ 4.004824489362305
+ 4.004865620717076
+ 4.00490675148846
+ 4.004947881676481
+ 4.004989011281159
+ 4.0050301403025195
+ 4.005071268740584
+ 4.005112396595373
+ 4.005153523866911
+ 4.00519465055522
+ 4.005235776660323
+ 4.00527690218224
+ 4.005318027120996
+ 4.005359151476613
+ 4.005400275249113
+ 4.005441398438519
+ 4.005482521044852
+ 4.005523643068136
+ 4.005564764508392
+ 4.005605885365644
+ 4.005647005639914
+ 4.005688125331224
+ 4.005729244439596
+ 4.005770362965053
+ 4.005811480907618
+ 4.005852598267312
+ 4.005893715044159
+ 4.005934831238181
+ 4.0059759468494
+ 4.006017061877838
+ 4.006058176323519
+ 4.006099290186463
+ 4.006140403466695
+ 4.006181516164236
+ 4.006222628279108
+ 4.0062637398113345
+ 4.006304850760937
+ 4.00634596112794
+ 4.006387070912363
+ 4.00642818011423
+ 4.0064692887335625
+ 4.006510396770384
+ 4.006551504224717
+ 4.006592611096583
+ 4.006633717386004
+ 4.006674823093004
+ 4.006715928217604
+ 4.006757032759827
+ 4.006798136719695
+ 4.006839240097231
+ 4.006880342892458
+ 4.006921445105396
+ 4.00696254673607
+ 4.007003647784501
+ 4.007044748250712
+ 4.007085848134724
+ 4.007126947436562
+ 4.007168046156245
+ 4.007209144293798
+ 4.007250241849242
+ 4.0072913388226015
+ 4.007332435213896
+ 4.007373531023149
+ 4.007414626250384
+ 4.007455720895622
+ 4.007496814958886
+ 4.007537908440198
+ 4.007579001339581
+ 4.0076200936570565
+ 4.007661185392647
+ 4.007702276546375
+ 4.007743367118264
+ 4.007784457108335
+ 4.00782554651661
+ 4.007866635343113
+ 4.0079077235878655
+ 4.007948811250889
+ 4.007989898332208
+ 4.0080309848318425
+ 4.008072070749816
+ 4.008113156086151
+ 4.008154240840869
+ 4.008195325013994
+ 4.008236408605547
+ 4.00827749161555
+ 4.008318574044026
+ 4.008359655890997
+ 4.008400737156486
+ 4.008441817840515
+ 4.008482897943106
+ 4.008523977464283
+ 4.008565056404066
+ 4.008606134762478
+ 4.008647212539542
+ 4.0086882897352805
+ 4.008729366349715
+ 4.008770442382867
+ 4.008811517834761
+ 4.008852592705419
+ 4.008893666994862
+ 4.008934740703112
+ 4.008975813830193
+ 4.009016886376126
+ 4.009057958340935
+ 4.0090990297246405
+ 4.009140100527266
+ 4.009181170748834
+ 4.009222240389365
+ 4.009263309448882
+ 4.009304377927409
+ 4.009345445824966
+ 4.009386513141577
+ 4.009427579877264
+ 4.009468646032048
+ 4.009509711605953
+ 4.009550776599001
+ 4.009591841011214
+ 4.009632904842613
+ 4.009673968093223
+ 4.009715030763064
+ 4.009756092852158
+ 4.00979715436053
+ 4.009838215288201
+ 4.009879275635192
+ 4.009920335401526
+ 4.009961394587226
+ 4.010002453192313
+ 4.010043511216812
+ 4.0100845686607425
+ 4.010125625524127
+ 4.010166681806989
+ 4.01020773750935
+ 4.0102487926312325
+ 4.010289847172659
+ 4.010330901133652
+ 4.010371954514233
+ 4.010413007314424
+ 4.010454059534249
+ 4.010495111173729
+ 4.010536162232885
+ 4.010577212711742
+ 4.01061826261032
+ 4.010659311928643
+ 4.010700360666733
+ 4.010741408824611
+ 4.0107824564023
+ 4.0108235033998225
+ 4.0108645498172
+ 4.010905595654456
+ 4.0109466409116115
+ 4.01098768558869
+ 4.011028729685712
+ 4.011069773202701
+ 4.01111081613968
+ 4.011151858496669
+ 4.011192900273692
+ 4.011233941470771
+ 4.011274982087928
+ 4.011316022125185
+ 4.011357061582564
+ 4.011398100460089
+ 4.011439138757781
+ 4.0114801764756605
+ 4.0115212136137535
+ 4.011562250172079
+ 4.01160328615066
+ 4.01164432154952
+ 4.011685356368679
+ 4.011726390608162
+ 4.0117674242679895
+ 4.0118084573481845
+ 4.0118494898487675
+ 4.011890521769764
+ 4.011931553111192
+ 4.011972583873077
+ 4.01201361405544
+ 4.0120546436583036
+ 4.012095672681689
+ 4.012136701125621
+ 4.012177728990118
+ 4.012218756275205
+ 4.012259782980903
+ 4.012300809107235
+ 4.012341834654223
+ 4.012382859621889
+ 4.012423884010255
+ 4.012464907819344
+ 4.012505931049176
+ 4.012546953699776
+ 4.012587975771166
+ 4.012628997263366
+ 4.0126700181764
+ 4.0127110385102895
+ 4.012752058265057
+ 4.012793077440723
+ 4.012834096037314
+ 4.0128751140548475
+ 4.012916131493348
+ 4.012957148352837
+ 4.012998164633338
+ 4.013039180334871
+ 4.0130801954574595
+ 4.013121210001126
+ 4.0131622239658915
+ 4.013203237351779
+ 4.013244250158811
+ 4.013285262387009
+ 4.0133262740363955
+ 4.013367285106993
+ 4.013408295598822
+ 4.013449305511906
+ 4.013490314846268
+ 4.013531323601929
+ 4.013572331778911
+ 4.013613339377237
+ 4.013654346396928
+ 4.013695352838008
+ 4.013736358700497
+ 4.013777363984418
+ 4.013818368689794
+ 4.013859372816647
+ 4.013900376364998
+ 4.01394137933487
+ 4.013982381726285
+ 4.014023383539265
+ 4.014064384773833
+ 4.014105385430009
+ 4.014146385507817
+ 4.014187385007279
+ 4.014228383928417
+ 4.0142693822712525
+ 4.014310380035808
+ 4.014351377222107
+ 4.0143923738301694
+ 4.0144333698600185
+ 4.014474365311677
+ 4.014515360185165
+ 4.014556354480507
+ 4.014597348197723
+ 4.014638341336838
+ 4.01467933389787
+ 4.0147203258808455
+ 4.0147613172857834
+ 4.014802308112707
+ 4.014843298361639
+ 4.014884288032601
+ 4.014925277125615
+ 4.014966265640703
+ 4.015007253577887
+ 4.0150482409371895
+ 4.015089227718633
+ 4.015130213922238
+ 4.015171199548029
+ 4.0152121845960265
+ 4.015253169066253
+ 4.015294152958731
+ 4.015335136273482
+ 4.0153761190105275
+ 4.015417101169891
+ 4.015458082751594
+ 4.015499063755659
+ 4.0155400441821065
+ 4.01558102403096
+ 4.0156220033022425
+ 4.015662981995974
+ 4.0157039601121785
+ 4.015744937650876
+ 4.015785914612091
+ 4.015826890995843
+ 4.015867866802157
+ 4.0159088420310525
+ 4.015949816682553
+ 4.015990790756679
+ 4.016031764253455
+ 4.016072737172902
+ 4.016113709515041
+ 4.016154681279896
+ 4.016195652467488
+ 4.016236623077838
+ 4.01627759311097
+ 4.016318562566906
+ 4.016359531445666
+ 4.016400499747275
+ 4.016441467471752
+ 4.016482434619121
+ 4.016523401189404
+ 4.016564367182623
+ 4.016605332598799
+ 4.016646297437956
+ 4.016687261700113
+ 4.016728225385296
+ 4.016769188493524
+ 4.016810151024821
+ 4.016851112979206
+ 4.016892074356705
+ 4.016933035157338
+ 4.016973995381127
+ 4.017014955028094
+ 4.017055914098262
+ 4.017096872591652
+ 4.017137830508286
+ 4.017178787848188
+ 4.017219744611378
+ 4.017260700797878
+ 4.017301656407711
+ 4.017342611440898
+ 4.017383565897463
+ 4.017424519777426
+ 4.01746547308081
+ 4.017506425807636
+ 4.017547377957928
+ 4.017588329531707
+ 4.017629280528993
+ 4.017670230949812
+ 4.017711180794183
+ 4.017752130062129
+ 4.017793078753672
+ 4.017834026868835
+ 4.017874974407638
+ 4.017915921370104
+ 4.017956867756256
+ 4.017997813566114
+ 4.018038758799702
+ 4.01807970345704
+ 4.018120647538153
+ 4.01816159104306
+ 4.018202533971784
+ 4.018243476324347
+ 4.018284418100772
+ 4.0183253593010795
+ 4.018366299925293
+ 4.018407239973433
+ 4.018448179445522
+ 4.0184891183415825
+ 4.018530056661636
+ 4.018570994405705
+ 4.018611931573811
+ 4.018652868165977
+ 4.018693804182223
+ 4.018734739622572
+ 4.018775674487047
+ 4.018816608775669
+ 4.01885754248846
+ 4.018898475625442
+ 4.018939408186637
+ 4.018980340172067
+ 4.019021271581755
+ 4.019062202415721
+ 4.0191031326739886
+ 4.019144062356579
+ 4.019184991463514
+ 4.019225919994817
+ 4.019266847950508
+ 4.01930777533061
+ 4.0193487021351455
+ 4.019389628364135
+ 4.019430554017601
+ 4.019471479095567
+ 4.019512403598053
+ 4.019553327525082
+ 4.0195942508766755
+ 4.019635173652856
+ 4.019676095853645
+ 4.0197170174790635
+ 4.0197579385291355
+ 4.019798859003882
+ 4.019839778903324
+ 4.019880698227486
+ 4.019921616976387
+ 4.019962535150051
+ 4.020003452748498
+ 4.020044369771753
+ 4.020085286219834
+ 4.020126202092767
+ 4.020167117390571
+ 4.02020803211327
+ 4.0202489462608835
+ 4.020289859833436
+ 4.020330772830946
+ 4.02037168525344
+ 4.020412597100937
+ 4.02045350837346
+ 4.02049441907103
+ 4.020535329193669
+ 4.020576238741399
+ 4.020617147714244
+ 4.0206580561122225
+ 4.020698963935359
+ 4.020739871183675
+ 4.020780777857191
+ 4.020821683955932
+ 4.020862589479916
+ 4.020903494429167
+ 4.020944398803706
+ 4.020985302603556
+ 4.021026205828739
+ 4.021067108479277
+ 4.0211080105551895
+ 4.021148912056502
+ 4.021189812983233
+ 4.021230713335408
+ 4.021271613113045
+ 4.021312512316169
+ 4.0213534109448
+ 4.021394308998962
+ 4.021435206478675
+ 4.021476103383962
+ 4.021516999714843
+ 4.021557895471342
+ 4.0215987906534805
+ 4.021639685261279
+ 4.021680579294761
+ 4.021721472753948
+ 4.021762365638862
+ 4.021803257949524
+ 4.021844149685958
+ 4.021885040848183
+ 4.021925931436223
+ 4.021966821450098
+ 4.022007710889832
+ 4.022048599755446
+ 4.022089488046961
+ 4.022130375764401
+ 4.0221712629077855
+ 4.022212149477138
+ 4.022253035472479
+ 4.022293920893833
+ 4.0223348057412185
+ 4.022375690014659
+ 4.022416573714176
+ 4.022457456839793
+ 4.02249833939153
+ 4.022539221369409
+ 4.0225801027734525
+ 4.022620983603682
+ 4.02266186386012
+ 4.022702743542787
+ 4.022743622651706
+ 4.022784501186899
+ 4.0228253791483874
+ 4.022866256536192
+ 4.022907133350337
+ 4.022948009590842
+ 4.022988885257731
+ 4.023029760351024
+ 4.023070634870743
+ 4.0231115088169105
+ 4.023152382189549
+ 4.023193254988679
+ 4.023234127214323
+ 4.023274998866503
+ 4.0233158699452405
+ 4.023356740450557
+ 4.0233976103824745
+ 4.023438479741015
+ 4.023479348526203
+ 4.023520216738055
+ 4.023561084376596
+ 4.023601951441847
+ 4.0236428179338315
+ 4.023683683852569
+ 4.023724549198083
+ 4.023765413970395
+ 4.023806278169526
+ 4.023847141795499
+ 4.0238880048483345
+ 4.023928867328054
+ 4.023969729234682
+ 4.024010590568238
+ 4.024051451328745
+ 4.024092311516224
+ 4.024133171130696
+ 4.024174030172185
+ 4.024214888640711
+ 4.024255746536297
+ 4.024296603858964
+ 4.024337460608734
+ 4.024378316785629
+ 4.024419172389671
+ 4.024460027420882
+ 4.024500881879282
+ 4.024541735764895
+ 4.024582589077742
+ 4.024623441817845
+ 4.024664293985224
+ 4.024705145579904
+ 4.0247459966019035
+ 4.024786847051247
+ 4.024827696927955
+ 4.024868546232049
+ 4.024909394963551
+ 4.0249502431224835
+ 4.024991090708868
+ 4.0250319377227255
+ 4.025072784164079
+ 4.0251136300329495
+ 4.025154475329359
+ 4.025195320053328
+ 4.02523616420488
+ 4.025277007784037
+ 4.02531785079082
+ 4.02535869322525
+ 4.025399535087351
+ 4.025440376377142
+ 4.025481217094646
+ 4.025522057239885
+ 4.025562896812882
+ 4.025603735813656
+ 4.02564457424223
+ 4.0256854120986265
+ 4.025726249382867
+ 4.025767086094971
+ 4.025807922234964
+ 4.025848757802866
+ 4.025889592798698
+ 4.025930427222483
+ 4.0259712610742415
+ 4.026012094353996
+ 4.026052927061769
+ 4.026093759197581
+ 4.026134590761454
+ 4.026175421753409
+ 4.02621625217347
+ 4.026257082021658
+ 4.026297911297993
+ 4.026338740002498
+ 4.026379568135195
+ 4.026420395696105
+ 4.02646122268525
+ 4.026502049102652
+ 4.0265428749483325
+ 4.0265837002223135
+ 4.026624524924617
+ 4.026665349055263
+ 4.026706172614276
+ 4.026746995601675
+ 4.026787818017483
+ 4.026828639861722
+ 4.026869461134413
+ 4.026910281835578
+ 4.02695110196524
+ 4.026991921523418
+ 4.027032740510136
+ 4.027073558925415
+ 4.027114376769277
+ 4.027155194041742
+ 4.027196010742834
+ 4.027236826872574
+ 4.027277642430984
+ 4.027318457418084
+ 4.027359271833898
+ 4.027400085678446
+ 4.027440898951751
+ 4.027481711653833
+ 4.0275225237847145
+ 4.027563335344419
+ 4.0276041463329655
+ 4.027644956750377
+ 4.027685766596675
+ 4.027726575871881
+ 4.027767384576017
+ 4.027808192709105
+ 4.027849000271166
+ 4.027889807262222
+ 4.027930613682295
+ 4.027971419531406
+ 4.028012224809577
+ 4.028053029516829
+ 4.028093833653185
+ 4.028134637218666
+ 4.028175440213294
+ 4.02821624263709
+ 4.0282570444900765
+ 4.028297845772275
+ 4.028338646483706
+ 4.028379446624393
+ 4.028420246194356
+ 4.028461045193619
+ 4.0285018436222
+ 4.028542641480124
+ 4.028583438767411
+ 4.0286242354840835
+ 4.028665031630163
+ 4.02870582720567
+ 4.028746622210628
+ 4.0287874166450575
+ 4.02882821050898
+ 4.028869003802417
+ 4.028909796525392
+ 4.028950588677925
+ 4.028991380260038
+ 4.029032171271752
+ 4.029072961713091
+ 4.029113751584074
+ 4.029154540884723
+ 4.029195329615061
+ 4.029236117775109
+ 4.029276905364888
+ 4.02931769238442
+ 4.0293584788337276
+ 4.029399264712831
+ 4.029440050021753
+ 4.0294808347605136
+ 4.029521618929137
+ 4.029562402527643
+ 4.029603185556054
+ 4.02964396801439
+ 4.029684749902675
+ 4.029725531220929
+ 4.0297663119691745
+ 4.029807092147432
+ 4.029847871755725
+ 4.029888650794073
+ 4.029929429262499
+ 4.029970207161025
+ 4.030010984489671
+ 4.030051761248459
+ 4.030092537437412
+ 4.030133313056551
+ 4.0301740881058965
+ 4.0302148625854715
+ 4.030255636495296
+ 4.030296409835394
+ 4.030337182605785
+ 4.030377954806491
+ 4.030418726437535
+ 4.030459497498938
+ 4.030500267990719
+ 4.030541037912904
+ 4.030581807265511
+ 4.030622576048564
+ 4.0306633442620825
+ 4.03070411190609
+ 4.030744878980607
+ 4.030785645485655
+ 4.030826411421256
+ 4.0308671767874324
+ 4.030907941584204
+ 4.030948705811594
+ 4.030989469469622
+ 4.031030232558312
+ 4.031070995077685
+ 4.031111757027761
+ 4.031152518408563
+ 4.031193279220112
+ 4.031234039462429
+ 4.031274799135538
+ 4.0313155582394575
+ 4.031356316774212
+ 4.031397074739821
+ 4.031437832136306
+ 4.03147858896369
+ 4.0315193452219935
+ 4.031560100911237
+ 4.031600856031446
+ 4.031641610582637
+ 4.031682364564836
+ 4.031723117978062
+ 4.031763870822337
+ 4.031804623097683
+ 4.031845374804121
+ 4.031886125941672
+ 4.03192687651036
+ 4.0319676265102045
+ 4.032008375941227
+ 4.03204912480345
+ 4.032089873096894
+ 4.032130620821581
+ 4.032171367977534
+ 4.032212114564772
+ 4.032252860583319
+ 4.032293606033194
+ 4.032334350914421
+ 4.03237509522702
+ 4.032415838971013
+ 4.0324565821464216
+ 4.032497324753266
+ 4.03253806679157
+ 4.032578808261355
+ 4.03261954916264
+ 4.032660289495449
+ 4.032701029259803
+ 4.032741768455723
+ 4.032782507083231
+ 4.032823245142347
+ 4.032863982633095
+ 4.032904719555495
+ 4.0329454559095685
+ 4.032986191695338
+ 4.033026926912823
+ 4.033067661562049
+ 4.0331083956430325
+ 4.033149129155798
+ 4.033189862100367
+ 4.03323059447676
+ 4.033271326284999
+ 4.033312057525106
+ 4.033352788197102
+ 4.033393518301008
+ 4.033434247836846
+ 4.033474976804638
+ 4.033515705204405
+ 4.033556433036168
+ 4.033597160299949
+ 4.03363788699577
+ 4.0336786131236515
+ 4.033719338683615
+ 4.033760063675683
+ 4.033800788099877
+ 4.0338415119562185
+ 4.033882235244727
+ 4.0339229579654265
+ 4.033963680118337
+ 4.034004401703481
+ 4.034045122720878
+ 4.034085843170552
+ 4.034126563052524
+ 4.034167282366814
+ 4.034208001113444
+ 4.034248719292437
+ 4.034289436903812
+ 4.034330153947593
+ 4.0343708704238
+ 4.034411586332454
+ 4.034452301673578
+ 4.034493016447192
+ 4.034533730653319
+ 4.034574444291979
+ 4.034615157363195
+ 4.034655869866986
+ 4.034696581803376
+ 4.034737293172386
+ 4.034778003974036
+ 4.034818714208349
+ 4.0348594238753455
+ 4.034900132975047
+ 4.034940841507476
+ 4.034981549472653
+ 4.0350222568706
+ 4.035062963701338
+ 4.035103669964888
+ 4.035144375661273
+ 4.035185080790513
+ 4.03522578535263
+ 4.035266489347645
+ 4.03530719277558
+ 4.035347895636457
+ 4.035388597930296
+ 4.035429299657119
+ 4.035470000816948
+ 4.035510701409804
+ 4.035551401435709
+ 4.035592100894683
+ 4.035632799786749
+ 4.035673498111928
+ 4.0357141958702405
+ 4.035754893061709
+ 4.035795589686354
+ 4.035836285744198
+ 4.035876981235262
+ 4.035917676159567
+ 4.035958370517135
+ 4.035999064307988
+ 4.036039757532145
+ 4.036080450189631
+ 4.0361211422804635
+ 4.036161833804667
+ 4.0362025247622615
+ 4.036243215153268
+ 4.03628390497771
+ 4.036324594235607
+ 4.0363652829269805
+ 4.0364059710518525
+ 4.036446658610244
+ 4.036487345602178
+ 4.0365280320276735
+ 4.0365687178867535
+ 4.036609403179439
+ 4.03665008790575
+ 4.036690772065709
+ 4.036731455659339
+ 4.0367721386866595
+ 4.036812821147693
+ 4.03685350304246
+ 4.036894184370981
+ 4.036934865133279
+ 4.036975545329375
+ 4.037016224959292
+ 4.037056904023048
+ 4.0370975825206665
+ 4.037138260452168
+ 4.0371789378175755
+ 4.037219614616909
+ 4.037260290850189
+ 4.037300966517439
+ 4.037341641618679
+ 4.037382316153931
+ 4.037422990123216
+ 4.037463663526555
+ 4.0375043363639715
+ 4.037545008635484
+ 4.037585680341115
+ 4.037626351480887
+ 4.03766702205482
+ 4.037707692062935
+ 4.037748361505255
+ 4.0377890303818
+ 4.037829698692592
+ 4.0378703664376525
+ 4.037911033617002
+ 4.037951700230663
+ 4.037992366278656
+ 4.038033031761003
+ 4.038073696677724
+ 4.038114361028843
+ 4.038155024814378
+ 4.038195688034352
+ 4.038236350688788
+ 4.038277012777705
+ 4.038317674301124
+ 4.038358335259069
+ 4.038398995651559
+ 4.038439655478617
+ 4.038480314740262
+ 4.038520973436518
+ 4.038561631567405
+ 4.038602289132944
+ 4.038642946133157
+ 4.0386836025680655
+ 4.03872425843769
+ 4.038764913742052
+ 4.038805568481175
+ 4.038846222655077
+ 4.038886876263781
+ 4.038927529307308
+ 4.0389681817856795
+ 4.039008833698917
+ 4.039049485047042
+ 4.039090135830075
+ 4.039130786048037
+ 4.039171435700951
+ 4.039212084788838
+ 4.039252733311718
+ 4.039293381269613
+ 4.0393340286625445
+ 4.039374675490533
+ 4.0394153217536015
+ 4.03945596745177
+ 4.03949661258506
+ 4.039537257153493
+ 4.03957790115709
+ 4.039618544595872
+ 4.039659187469862
+ 4.039699829779079
+ 4.0397404715235465
+ 4.0397811127032845
+ 4.039821753318313
+ 4.039862393368657
+ 4.039903032854334
+ 4.039943671775368
+ 4.0399843101317785
+ 4.040024947923588
+ 4.040065585150817
+ 4.040106221813487
+ 4.04014685791162
+ 4.040187493445236
+ 4.040228128414356
+ 4.040268762819005
+ 4.0403093966591985
+ 4.040350029934963
+ 4.040390662646317
+ 4.040431294793281
+ 4.040471926375879
+ 4.0405125573941305
+ 4.040553187848057
+ 4.040593817737681
+ 4.040634447063022
+ 4.040675075824101
+ 4.040715704020942
+ 4.040756331653563
+ 4.040796958721987
+ 4.040837585226236
+ 4.04087821116633
+ 4.04091883654229
+ 4.040959461354139
+ 4.041000085601897
+ 4.041040709285584
+ 4.0410813324052235
+ 4.041121954960836
+ 4.041162576952442
+ 4.041203198380065
+ 4.041243819243723
+ 4.04128443954344
+ 4.0413250592792345
+ 4.041365678451131
+ 4.041406297059148
+ 4.041446915103309
+ 4.041487532583634
+ 4.041528149500144
+ 4.041568765852861
+ 4.0416093816418055
+ 4.041649996866999
+ 4.041690611528463
+ 4.041731225626219
+ 4.041771839160287
+ 4.0418124521306895
+ 4.041853064537448
+ 4.041893676380582
+ 4.041934287660114
+ 4.041974898376065
+ 4.042015508528456
+ 4.0420561181173085
+ 4.042096727142645
+ 4.042137335604484
+ 4.042177943502848
+ 4.042218550837759
+ 4.042259157609237
+ 4.042299763817304
+ 4.042340369461981
+ 4.042380974543289
+ 4.04242157906125
+ 4.042462183015885
+ 4.042502786407213
+ 4.0425433892352585
+ 4.042583991500041
+ 4.042624593201582
+ 4.042665194339903
+ 4.042705794915024
+ 4.042746394926968
+ 4.042786994375755
+ 4.042827593261406
+ 4.042868191583943
+ 4.042908789343387
+ 4.042949386539759
+ 4.042989983173081
+ 4.043030579243372
+ 4.043071174750656
+ 4.043111769694953
+ 4.043152364076283
+ 4.043192957894669
+ 4.043233551150131
+ 4.043274143842691
+ 4.04331473597237
+ 4.043355327539189
+ 4.043395918543168
+ 4.043436508984331
+ 4.043477098862696
+ 4.043517688178287
+ 4.043558276931123
+ 4.043598865121227
+ 4.043639452748619
+ 4.04368003981332
+ 4.043720626315352
+ 4.0437612122547355
+ 4.043801797631492
+ 4.043842382445643
+ 4.043882966697209
+ 4.043923550386212
+ 4.043964133512672
+ 4.044004716076611
+ 4.044045298078049
+ 4.044085879517009
+ 4.044126460393511
+ 4.044167040707577
+ 4.044207620459227
+ 4.044248199648483
+ 4.044288778275367
+ 4.044329356339898
+ 4.0443699338420975
+ 4.044410510781988
+ 4.04445108715959
+ 4.0444916629749255
+ 4.0445322382280136
+ 4.044572812918878
+ 4.044613387047537
+ 4.044653960614014
+ 4.04469453361833
+ 4.044735106060505
+ 4.044775677940559
+ 4.044816249258517
+ 4.044856820014397
+ 4.044897390208222
+ 4.044937959840011
+ 4.044978528909787
+ 4.04501909741757
+ 4.045059665363382
+ 4.045100232747243
+ 4.045140799569176
+ 4.045181365829201
+ 4.0452219315273386
+ 4.04526249666361
+ 4.045303061238037
+ 4.045343625250641
+ 4.045384188701443
+ 4.045424751590463
+ 4.045465313917722
+ 4.045505875683244
+ 4.045546436887046
+ 4.045586997529153
+ 4.045627557609583
+ 4.0456681171283595
+ 4.045708676085501
+ 4.045749234481032
+ 4.04578979231497
+ 4.045830349587339
+ 4.045870906298158
+ 4.04591146244745
+ 4.045952018035235
+ 4.045992573061533
+ 4.046033127526368
+ 4.046073681429759
+ 4.046114234771728
+ 4.046154787552294
+ 4.046195339771481
+ 4.046235891429308
+ 4.046276442525798
+ 4.04631699306097
+ 4.046357543034847
+ 4.046398092447449
+ 4.046438641298797
+ 4.046479189588912
+ 4.046519737317817
+ 4.04656028448553
+ 4.046600831092074
+ 4.04664137713747
+ 4.0466819226217385
+ 4.0467224675449005
+ 4.046763011906978
+ 4.046803555707991
+ 4.046844098947961
+ 4.04688464162691
+ 4.046925183744857
+ 4.046965725301826
+ 4.047006266297835
+ 4.047046806732907
+ 4.047087346607062
+ 4.047127885920322
+ 4.047168424672707
+ 4.047208962864239
+ 4.04724950049494
+ 4.047290037564828
+ 4.047330574073926
+ 4.047371110022255
+ 4.047411645409837
+ 4.047452180236691
+ 4.04749271450284
+ 4.047533248208303
+ 4.047573781353104
+ 4.0476143139372605
+ 4.047654845960795
+ 4.0476953774237305
+ 4.047735908326085
+ 4.047776438667881
+ 4.04781696844914
+ 4.047857497669883
+ 4.047898026330129
+ 4.047938554429901
+ 4.047979081969221
+ 4.048019608948108
+ 4.048060135366583
+ 4.048100661224668
+ 4.0481411865223835
+ 4.048181711259751
+ 4.048222235436792
+ 4.048262759053526
+ 4.048303282109975
+ 4.04834380460616
+ 4.048384326542102
+ 4.048424847917822
+ 4.048465368733341
+ 4.04850588898868
+ 4.048546408683859
+ 4.048586927818901
+ 4.048627446393826
+ 4.048667964408655
+ 4.048708481863409
+ 4.048748998758109
+ 4.048789515092776
+ 4.048830030867431
+ 4.048870546082096
+ 4.04891106073679
+ 4.048951574831536
+ 4.0489920883663535
+ 4.049032601341264
+ 4.049073113756289
+ 4.04911362561145
+ 4.049154136906766
+ 4.049194647642259
+ 4.04923515781795
+ 4.049275667433862
+ 4.049316176490012
+ 4.049356684986424
+ 4.049397192923118
+ 4.049437700300115
+ 4.049478207117436
+ 4.049518713375102
+ 4.049559219073135
+ 4.0495997242115545
+ 4.049640228790382
+ 4.049680732809638
+ 4.049721236269345
+ 4.049761739169522
+ 4.049802241510192
+ 4.049842743291374
+ 4.04988324451309
+ 4.049923745175361
+ 4.049964245278209
+ 4.050004744821653
+ 4.050045243805715
+ 4.050085742230415
+ 4.050126240095776
+ 4.050166737401817
+ 4.0502072341485595
+ 4.050247730336024
+ 4.050288225964233
+ 4.050328721033207
+ 4.0503692155429665
+ 4.0504097094935325
+ 4.050450202884925
+ 4.050490695717167
+ 4.050531187990278
+ 4.050571679704279
+ 4.050612170859192
+ 4.050652661455037
+ 4.050693151491834
+ 4.050733640969606
+ 4.0507741298883735
+ 4.0508146182481575
+ 4.050855106048977
+ 4.050895593290855
+ 4.0509360799738126
+ 4.050976566097869
+ 4.051017051663047
+ 4.051057536669367
+ 4.051098021116848
+ 4.051138505005514
+ 4.051178988335384
+ 4.05121947110648
+ 4.051259953318822
+ 4.051300434972431
+ 4.051340916067328
+ 4.051381396603535
+ 4.051421876581072
+ 4.05146235599996
+ 4.051502834860219
+ 4.051543313161871
+ 4.051583790904938
+ 4.051624268089439
+ 4.051664744715397
+ 4.0517052207828295
+ 4.051745696291761
+ 4.05178617124221
+ 4.051826645634198
+ 4.051867119467747
+ 4.051907592742877
+ 4.051948065459609
+ 4.051988537617964
+ 4.0520290092179625
+ 4.052069480259626
+ 4.052109950742976
+ 4.052150420668031
+ 4.052190890034814
+ 4.052231358843347
+ 4.052271827093648
+ 4.052312294785739
+ 4.052352761919641
+ 4.052393228495376
+ 4.052433694512963
+ 4.052474159972424
+ 4.05251462487378
+ 4.052555089217051
+ 4.052595553002259
+ 4.052636016229425
+ 4.052676478898568
+ 4.05271694100971
+ 4.0527574025628725
+ 4.052797863558077
+ 4.052838323995342
+ 4.05287878387469
+ 4.052919243196142
+ 4.052959701959717
+ 4.053000160165438
+ 4.053040617813326
+ 4.0530810749034005
+ 4.053121531435683
+ 4.053161987410194
+ 4.053202442826955
+ 4.053242897685987
+ 4.05328335198731
+ 4.053323805730945
+ 4.053364258916913
+ 4.053404711545236
+ 4.053445163615933
+ 4.053485615129026
+ 4.053526066084536
+ 4.0535665164824835
+ 4.053606966322889
+ 4.053647415605774
+ 4.053687864331158
+ 4.0537283124990635
+ 4.053768760109511
+ 4.053809207162521
+ 4.053849653658115
+ 4.0538900995963125
+ 4.053930544977136
+ 4.053970989800605
+ 4.054011434066741
+ 4.0540518777755645
+ 4.054092320927096
+ 4.054132763521358
+ 4.05417320555837
+ 4.054213647038153
+ 4.054254087960728
+ 4.054294528326116
+ 4.054334968134337
+ 4.054375407385412
+ 4.054415846079364
+ 4.05445628421621
+ 4.054496721795974
+ 4.054537158818675
+ 4.054577595284336
+ 4.054618031192976
+ 4.054658466544615
+ 4.054698901339276
+ 4.054739335576979
+ 4.0547797692577445
+ 4.054820202381594
+ 4.054860634948547
+ 4.054901066958625
+ 4.054941498411851
+ 4.054981929308242
+ 4.05502235964782
+ 4.0550627894306075
+ 4.055103218656625
+ 4.055143647325892
+ 4.055184075438429
+ 4.055224502994258
+ 4.0552649299934
+ 4.055305356435875
+ 4.055345782321704
+ 4.055386207650908
+ 4.055426632423508
+ 4.055467056639524
+ 4.055507480298978
+ 4.05554790340189
+ 4.05558832594828
+ 4.0556287479381705
+ 4.055669169371581
+ 4.055709590248534
+ 4.055750010569048
+ 4.055790430333144
+ 4.055830849540844
+ 4.05587126819217
+ 4.05591168628714
+ 4.055952103825777
+ 4.0559925208081
+ 4.05603293723413
+ 4.056073353103889
+ 4.056113768417397
+ 4.056154183174676
+ 4.056194597375744
+ 4.0562350110206244
+ 4.056275424109337
+ 4.056315836641903
+ 4.056356248618342
+ 4.056396660038676
+ 4.056437070902925
+ 4.056477481211111
+ 4.056517890963253
+ 4.056558300159374
+ 4.056598708799491
+ 4.056639116883629
+ 4.056679524411806
+ 4.056719931384045
+ 4.056760337800364
+ 4.056800743660786
+ 4.056841148965331
+ 4.05688155371402
+ 4.056921957906873
+ 4.056962361543911
+ 4.057002764625156
+ 4.057043167150627
+ 4.057083569120345
+ 4.057123970534332
+ 4.0571643713926075
+ 4.057204771695194
+ 4.05724517144211
+ 4.057285570633376
+ 4.057325969269017
+ 4.057366367349048
+ 4.057406764873494
+ 4.057447161842373
+ 4.057487558255708
+ 4.057527954113518
+ 4.057568349415825
+ 4.057608744162649
+ 4.0576491383540105
+ 4.057689531989931
+ 4.057729925070431
+ 4.057770317595531
+ 4.057810709565251
+ 4.057851100979613
+ 4.057891491838638
+ 4.057931882142345
+ 4.057972271890756
+ 4.058012661083891
+ 4.058053049721772
+ 4.058093437804418
+ 4.058133825331851
+ 4.058174212304092
+ 4.058214598721159
+ 4.058254984583076
+ 4.058295369889863
+ 4.05833575464154
+ 4.058376138838127
+ 4.058416522479646
+ 4.058456905566117
+ 4.058497288097561
+ 4.058537670073999
+ 4.058578051495451
+ 4.058618432361938
+ 4.058658812673482
+ 4.058699192430101
+ 4.0587395716318175
+ 4.058779950278653
+ 4.058820328370626
+ 4.058860705907758
+ 4.0589010828900705
+ 4.058941459317584
+ 4.058981835190318
+ 4.059022210508295
+ 4.059062585271533
+ 4.0591029594800565
+ 4.059143333133883
+ 4.059183706233035
+ 4.0592240787775316
+ 4.059264450767395
+ 4.059304822202645
+ 4.059345193083302
+ 4.059385563409387
+ 4.059425933180922
+ 4.059466302397927
+ 4.05950667106042
+ 4.059547039168426
+ 4.059587406721962
+ 4.0596277737210515
+ 4.059668140165714
+ 4.059708506055969
+ 4.059748871391839
+ 4.059789236173343
+ 4.059829600400503
+ 4.059869964073339
+ 4.059910327191873
+ 4.059950689756124
+ 4.059991051766112
+ 4.060031413221861
+ 4.060071774123388
+ 4.060112134470716
+ 4.060152494263865
+ 4.060192853502855
+ 4.060233212187707
+ 4.060273570318442
+ 4.06031392789508
+ 4.060354284917643
+ 4.06039464138615
+ 4.060434997300622
+ 4.060475352661081
+ 4.060515707467546
+ 4.060556061720039
+ 4.06059641541858
+ 4.060636768563189
+ 4.060677121153887
+ 4.060717473190696
+ 4.060757824673634
+ 4.0607981756027245
+ 4.060838525977986
+ 4.060878875799441
+ 4.060919225067107
+ 4.060959573781008
+ 4.060999921941164
+ 4.061040269547593
+ 4.06108061660032
+ 4.061120963099361
+ 4.06116130904474
+ 4.061201654436476
+ 4.06124199927459
+ 4.061282343559102
+ 4.061322687290034
+ 4.061363030467406
+ 4.061403373091239
+ 4.061443715161553
+ 4.061484056678368
+ 4.061524397641706
+ 4.061564738051586
+ 4.06160507790803
+ 4.061645417211059
+ 4.061685755960692
+ 4.061726094156951
+ 4.061766431799855
+ 4.061806768889427
+ 4.061847105425685
+ 4.0618874414086505
+ 4.0619277768383455
+ 4.061968111714789
+ 4.062008446038003
+ 4.062048779808006
+ 4.06208911302482
+ 4.062129445688465
+ 4.062169777798963
+ 4.062210109356332
+ 4.062250440360597
+ 4.0622907708117735
+ 4.062331100709884
+ 4.0623714300549505
+ 4.062411758846992
+ 4.0624520870860295
+ 4.062492414772085
+ 4.062532741905176
+ 4.062573068485325
+ 4.062613394512554
+ 4.062653719986881
+ 4.062694044908327
+ 4.062734369276914
+ 4.062774693092662
+ 4.062815016355589
+ 4.06285533906572
+ 4.062895661223073
+ 4.0629359828276685
+ 4.062976303879528
+ 4.063016624378672
+ 4.06305694432512
+ 4.063097263718893
+ 4.063137582560012
+ 4.0631779008484985
+ 4.063218218584371
+ 4.063258535767651
+ 4.063298852398359
+ 4.063339168476515
+ 4.063379484002141
+ 4.063419798975256
+ 4.063460113395882
+ 4.063500427264039
+ 4.063540740579747
+ 4.063581053343026
+ 4.063621365553899
+ 4.063661677212385
+ 4.063701988318503
+ 4.063742298872276
+ 4.063782608873724
+ 4.063822918322866
+ 4.063863227219724
+ 4.063903535564319
+ 4.063943843356671
+ 4.0639841505967995
+ 4.0640244572847255
+ 4.064064763420471
+ 4.064105069004055
+ 4.0641453740354985
+ 4.064185678514821
+ 4.0642259824420455
+ 4.06426628581719
+ 4.064306588640277
+ 4.064346890911326
+ 4.064387192630356
+ 4.064427493797391
+ 4.064467794412449
+ 4.064508094475551
+ 4.064548393986717
+ 4.06458869294597
+ 4.064628991353327
+ 4.064669289208811
+ 4.064709586512442
+ 4.0647498832642395
+ 4.064790179464226
+ 4.064830475112419
+ 4.0648707702088425
+ 4.064911064753514
+ 4.064951358746456
+ 4.064991652187689
+ 4.065031945077232
+ 4.065072237415106
+ 4.065112529201333
+ 4.06515282043593
+ 4.065193111118922
+ 4.065233401250327
+ 4.065273690830165
+ 4.065313979858458
+ 4.065354268335225
+ 4.065394556260488
+ 4.065434843634266
+ 4.065475130456582
+ 4.065515416727453
+ 4.065555702446902
+ 4.065595987614948
+ 4.065636272231614
+ 4.065676556296917
+ 4.06571683981088
+ 4.065757122773522
+ 4.065797405184864
+ 4.065837687044927
+ 4.065877968353732
+ 4.065918249111297
+ 4.065958529317645
+ 4.065998808972795
+ 4.066039088076769
+ 4.066079366629586
+ 4.066119644631266
+ 4.066159922081831
+ 4.066200198981301
+ 4.066240475329696
+ 4.066280751127038
+ 4.066321026373345
+ 4.066361301068639
+ 4.06640157521294
+ 4.06644184880627
+ 4.066482121848646
+ 4.066522394340092
+ 4.066562666280627
+ 4.066602937670271
+ 4.066643208509045
+ 4.0666834787969695
+ 4.066723748534065
+ 4.0667640177203515
+ 4.06680428635585
+ 4.06684455444058
+ 4.066884821974563
+ 4.066925088957819
+ 4.066965355390369
+ 4.067005621272233
+ 4.067045886603431
+ 4.067086151383984
+ 4.067126415613912
+ 4.067166679293236
+ 4.067206942421977
+ 4.067247205000153
+ 4.0672874670277865
+ 4.067327728504897
+ 4.0673679894315065
+ 4.067408249807634
+ 4.0674485096333
+ 4.067488768908524
+ 4.06752902763333
+ 4.067569285807735
+ 4.06760954343176
+ 4.067649800505427
+ 4.067690057028754
+ 4.067730313001762
+ 4.067770568424474
+ 4.067810823296909
+ 4.067851077619085
+ 4.067891331391025
+ 4.067931584612749
+ 4.0679718372842775
+ 4.06801208940563
+ 4.068052340976829
+ 4.068092591997892
+ 4.068132842468841
+ 4.068173092389697
+ 4.068213341760479
+ 4.068253590581207
+ 4.068293838851904
+ 4.068334086572588
+ 4.068374333743281
+ 4.068414580364003
+ 4.068454826434774
+ 4.068495071955613
+ 4.0685353169265435
+ 4.068575561347584
+ 4.068615805218754
+ 4.068656048540077
+ 4.06869629131157
+ 4.068736533533254
+ 4.068776775205151
+ 4.068817016327282
+ 4.068857256899665
+ 4.068897496922321
+ 4.068937736395271
+ 4.068977975318535
+ 4.069018213692133
+ 4.069058451516087
+ 4.069098688790416
+ 4.069138925515141
+ 4.069179161690281
+ 4.069219397315858
+ 4.0692596323918915
+ 4.069299866918402
+ 4.069340100895411
+ 4.069380334322936
+ 4.069420567201001
+ 4.069460799529624
+ 4.0695010313088265
+ 4.069541262538627
+ 4.069581493219049
+ 4.06962172335011
+ 4.069661952931831
+ 4.069702181964234
+ 4.069742410447337
+ 4.069782638381163
+ 4.06982286576573
+ 4.069863092601059
+ 4.069903318887171
+ 4.069943544624085
+ 4.069983769811823
+ 4.070023994450405
+ 4.070064218539851
+ 4.07010444208018
+ 4.070144665071415
+ 4.070184887513575
+ 4.07022510940668
+ 4.07026533075075
+ 4.070305551545807
+ 4.070345771791871
+ 4.07038599148896
+ 4.070426210637097
+ 4.070466429236301
+ 4.070506647286594
+ 4.070546864787994
+ 4.0705870817405225
+ 4.0706272981442
+ 4.070667513999046
+ 4.070707729305082
+ 4.070747944062328
+ 4.070788158270803
+ 4.07082837193053
+ 4.070868585041526
+ 4.070908797603813
+ 4.070949009617412
+ 4.0709892210823435
+ 4.0710294319986255
+ 4.071069642366281
+ 4.071109852185328
+ 4.071150061455789
+ 4.0711902701776825
+ 4.071230478351031
+ 4.071270685975851
+ 4.071310893052167
+ 4.071351099579997
+ 4.071391305559361
+ 4.071431510990282
+ 4.071471715872776
+ 4.071511920206867
+ 4.071552123992575
+ 4.071592327229918
+ 4.071632529918918
+ 4.071672732059595
+ 4.071712933651969
+ 4.071753134696061
+ 4.07179333519189
+ 4.071833535139477
+ 4.071873734538844
+ 4.071913933390008
+ 4.0719541316929915
+ 4.071994329447815
+ 4.072034526654497
+ 4.07207472331306
+ 4.072114919423522
+ 4.072155114985905
+ 4.072195310000229
+ 4.072235504466513
+ 4.07227569838478
+ 4.072315891755047
+ 4.072356084577336
+ 4.072396276851668
+ 4.072436468578062
+ 4.072476659756538
+ 4.072516850387117
+ 4.07255704046982
+ 4.072597230004667
+ 4.072637418991676
+ 4.072677607430871
+ 4.072717795322268
+ 4.072757982665892
+ 4.072798169461759
+ 4.072838355709892
+ 4.07287854141031
+ 4.072918726563033
+ 4.072958911168083
+ 4.072999095225479
+ 4.073039278735241
+ 4.0730794616973895
+ 4.073119644111945
+ 4.0731598259789275
+ 4.073200007298357
+ 4.073240188070256
+ 4.0732803682946415
+ 4.0733205479715355
+ 4.073360727100957
+ 4.073400905682928
+ 4.073441083717468
+ 4.073481261204598
+ 4.073521438144336
+ 4.073561614536704
+ 4.073601790381722
+ 4.07364196567941
+ 4.073682140429788
+ 4.073722314632877
+ 4.073762488288697
+ 4.073802661397268
+ 4.07384283395861
+ 4.0738830059727436
+ 4.073923177439689
+ 4.073963348359467
+ 4.074003518732097
+ 4.074043688557598
+ 4.074083857835993
+ 4.074124026567301
+ 4.074164194751542
+ 4.074204362388735
+ 4.074244529478903
+ 4.0742846960220644
+ 4.07432486201824
+ 4.07436502746745
+ 4.0744051923697135
+ 4.074445356725053
+ 4.074485520533486
+ 4.074525683795035
+ 4.074565846509719
+ 4.074606008677558
+ 4.074646170298574
+ 4.074686331372785
+ 4.074726491900212
+ 4.074766651880876
+ 4.0748068113147955
+ 4.074846970201993
+ 4.074887128542486
+ 4.0749272863362975
+ 4.0749674435834455
+ 4.075007600283952
+ 4.075047756437836
+ 4.075087912045117
+ 4.075128067105816
+ 4.075168221619954
+ 4.07520837558755
+ 4.0752485290086256
+ 4.0752886818832
+ 4.075328834211293
+ 4.075368985992926
+ 4.075409137228117
+ 4.075449287916889
+ 4.07548943805926
+ 4.075529587655252
+ 4.0755697367048835
+ 4.075609885208175
+ 4.0756500331651475
+ 4.075690180575821
+ 4.075730327440215
+ 4.07577047375835
+ 4.075810619530246
+ 4.075850764755924
+ 4.075890909435404
+ 4.075931053568705
+ 4.075971197155848
+ 4.076011340196853
+ 4.0760514826917404
+ 4.07609162464053
+ 4.076131766043242
+ 4.076171906899898
+ 4.076212047210516
+ 4.076252186975117
+ 4.076292326193722
+ 4.07633246486635
+ 4.076372602993021
+ 4.0764127405737565
+ 4.076452877608576
+ 4.076493014097498
+ 4.076533150040546
+ 4.076573285437737
+ 4.076613420289093
+ 4.076653554594634
+ 4.076693688354379
+ 4.07673382156835
+ 4.0767739542365655
+ 4.076814086359046
+ 4.076854217935812
+ 4.076894348966883
+ 4.07693447945228
+ 4.076974609392023
+ 4.077014738786132
+ 4.077054867634627
+ 4.077094995937528
+ 4.077135123694855
+ 4.077175250906628
+ 4.077215377572869
+ 4.077255503693595
+ 4.077295629268829
+ 4.07733575429859
+ 4.077375878782898
+ 4.077416002721773
+ 4.077456126115235
+ 4.077496248963305
+ 4.077536371266003
+ 4.077576493023348
+ 4.077616614235361
+ 4.077656734902062
+ 4.077696855023471
+ 4.077736974599608
+ 4.077777093630494
+ 4.077817212116147
+ 4.07785733005659
+ 4.07789744745184
+ 4.07793756430192
+ 4.077977680606849
+ 4.078017796366646
+ 4.0780579115813325
+ 4.078098026250928
+ 4.0781381403754535
+ 4.078178253954928
+ 4.078218366989371
+ 4.078258479478804
+ 4.0782985914232475
+ 4.0783387028227205
+ 4.078378813677243
+ 4.078418923986836
+ 4.078459033751518
+ 4.078499142971311
+ 4.078539251646234
+ 4.078579359776307
+ 4.078619467361551
+ 4.078659574401986
+ 4.07869968089763
+ 4.078739786848505
+ 4.078779892254632
+ 4.078819997116029
+ 4.078860101432717
+ 4.078900205204715
+ 4.0789403084320455
+ 4.078980411114727
+ 4.07902051325278
+ 4.079060614846223
+ 4.079100715895078
+ 4.079140816399365
+ 4.079180916359103
+ 4.079221015774313
+ 4.079261114645014
+ 4.079301212971227
+ 4.079341310752972
+ 4.079381407990269
+ 4.079421504683138
+ 4.079461600831599
+ 4.079501696435671
+ 4.079541791495377
+ 4.079581886010733
+ 4.079621979981763
+ 4.0796620734084845
+ 4.079702166290919
+ 4.079742258629085
+ 4.079782350423004
+ 4.079822441672696
+ 4.07986253237818
+ 4.0799026225394766
+ 4.079942712156606
+ 4.079982801229588
+ 4.080022889758443
+ 4.08006297774319
+ 4.080103065183851
+ 4.080143152080445
+ 4.080183238432991
+ 4.08022332424151
+ 4.080263409506022
+ 4.0803034942265475
+ 4.080343578403107
+ 4.080383662035718
+ 4.080423745124403
+ 4.080463827669181
+ 4.080503909670072
+ 4.080543991127096
+ 4.080584072040275
+ 4.0806241524096265
+ 4.08066423223517
+ 4.080704311516929
+ 4.080744390254919
+ 4.080784468449164
+ 4.080824546099683
+ 4.0808646232064945
+ 4.0809046997696194
+ 4.080944775789078
+ 4.0809848512648905
+ 4.081024926197077
+ 4.081065000585656
+ 4.081105074430648
+ 4.081145147732075
+ 4.081185220489955
+ 4.081225292704309
+ 4.081265364375156
+ 4.081305435502517
+ 4.081345506086412
+ 4.08138557612686
+ 4.081425645623882
+ 4.081465714577498
+ 4.081505782987727
+ 4.08154585085459
+ 4.0815859181781065
+ 4.081625984958296
+ 4.08166605119518
+ 4.081706116888778
+ 4.081746182039109
+ 4.081786246646193
+ 4.081826310710052
+ 4.081866374230704
+ 4.081906437208169
+ 4.081946499642469
+ 4.081986561533622
+ 4.082026622881648
+ 4.082066683686568
+ 4.082106743948402
+ 4.082146803667169
+ 4.08218686284289
+ 4.082226921475583
+ 4.082266979565271
+ 4.082307037111972
+ 4.082347094115707
+ 4.082387150576494
+ 4.082427206494356
+ 4.0824672618693105
+ 4.082507316701378
+ 4.0825473709905795
+ 4.082587424736934
+ 4.082627477940462
+ 4.082667530601182
+ 4.082707582719117
+ 4.082747634294284
+ 4.0827876853267036
+ 4.082827735816397
+ 4.0828677857633835
+ 4.082907835167683
+ 4.082947884029315
+ 4.082987932348301
+ 4.083027980124658
+ 4.08306802735841
+ 4.083108074049573
+ 4.083148120198169
+ 4.083188165804218
+ 4.08322821086774
+ 4.083268255388754
+ 4.083308299367281
+ 4.08334834280334
+ 4.083388385696952
+ 4.083428428048136
+ 4.083468469856912
+ 4.083508511123301
+ 4.083548551847321
+ 4.0835885920289945
+ 4.083628631668339
+ 4.083668670765376
+ 4.083708709320125
+ 4.0837487473326055
+ 4.083788784802838
+ 4.083828821730843
+ 4.083868858116638
+ 4.083908893960246
+ 4.083948929261685
+ 4.083988964020976
+ 4.0840289982381375
+ 4.084069031913191
+ 4.084109065046155
+ 4.084149097637051
+ 4.084189129685898
+ 4.084229161192716
+ 4.084269192157524
+ 4.084309222580344
+ 4.084349252461194
+ 4.084389281800094
+ 4.084429310597066
+ 4.084469338852128
+ 4.0845093665653005
+ 4.084549393736603
+ 4.084589420366057
+ 4.08462944645368
+ 4.084669471999493
+ 4.084709497003516
+ 4.084749521465769
+ 4.084789545386272
+ 4.084829568765044
+ 4.084869591602106
+ 4.084909613897477
+ 4.084949635651179
+ 4.084989656863229
+ 4.085029677533648
+ 4.0850696976624565
+ 4.085109717249674
+ 4.08514973629532
+ 4.085189754799415
+ 4.085229772761979
+ 4.085269790183031
+ 4.0853098070625915
+ 4.08534982340068
+ 4.085389839197317
+ 4.0854298544525225
+ 4.085469869166315
+ 4.085509883338717
+ 4.085549896969745
+ 4.085589910059421
+ 4.085629922607765
+ 4.085669934614796
+ 4.085709946080534
+ 4.0857499570049995
+ 4.085789967388212
+ 4.085829977230191
+ 4.085869986530958
+ 4.08590999529053
+ 4.08595000350893
+ 4.085990011186174
+ 4.086030018322286
+ 4.086070024917284
+ 4.086110030971188
+ 4.086150036484017
+ 4.086190041455792
+ 4.086230045886532
+ 4.0862700497762585
+ 4.08631005312499
+ 4.086350055932747
+ 4.086390058199548
+ 4.086430059925414
+ 4.086470061110365
+ 4.08651006175442
+ 4.0865500618576
+ 4.086590061419924
+ 4.086630060441412
+ 4.086670058922084
+ 4.08671005686196
+ 4.086750054261059
+ 4.086790051119402
+ 4.086830047437008
+ 4.086870043213898
+ 4.086910038450089
+ 4.086950033145604
+ 4.086990027300462
+ 4.087030020914682
+ 4.087070013988285
+ 4.087110006521289
+ 4.087149998513716
+ 4.0871899899655855
+ 4.0872299808769155
+ 4.087269971247728
+ 4.08730996107804
+ 4.087349950367875
+ 4.08738993911725
+ 4.087429927326186
+ 4.087469914994703
+ 4.08750990212282
+ 4.087549888710557
+ 4.087589874757935
+ 4.087629860264972
+ 4.087669845231689
+ 4.087709829658106
+ 4.087749813544242
+ 4.087789796890117
+ 4.087829779695752
+ 4.087869761961165
+ 4.087909743686377
+ 4.087949724871407
+ 4.087989705516276
+ 4.088029685621002
+ 4.088069665185606
+ 4.088109644210109
+ 4.088149622694528
+ 4.088189600638885
+ 4.088229578043199
+ 4.088269554907489
+ 4.0883095312317765
+ 4.088349507016081
+ 4.088389482260421
+ 4.088429456964818
+ 4.0884694311292895
+ 4.088509404753856
+ 4.08854937783854
+ 4.088589350383359
+ 4.088629322388332
+ 4.0886692938534805
+ 4.0887092647788235
+ 4.088749235164381
+ 4.088789205010173
+ 4.088829174316218
+ 4.088869143082537
+ 4.08890911130915
+ 4.088949078996076
+ 4.088989046143335
+ 4.089029012750947
+ 4.089068978818932
+ 4.089108944347308
+ 4.089148909336098
+ 4.089188873785319
+ 4.089228837694992
+ 4.089268801065137
+ 4.089308763895772
+ 4.089348726186919
+ 4.089388687938596
+ 4.0894286491508245
+ 4.089468609823624
+ 4.089508569957013
+ 4.089548529551011
+ 4.089588488605639
+ 4.0896284471209166
+ 4.089668405096863
+ 4.089708362533499
+ 4.089748319430843
+ 4.089788275788916
+ 4.089828231607737
+ 4.089868186887326
+ 4.089908141627702
+ 4.089948095828887
+ 4.089988049490898
+ 4.090028002613756
+ 4.090067955197481
+ 4.090107907242092
+ 4.090147858747609
+ 4.0901878097140525
+ 4.090227760141442
+ 4.090267710029797
+ 4.090307659379135
+ 4.0903476081894805
+ 4.09038755646085
+ 4.090427504193262
+ 4.09046745138674
+ 4.090507398041302
+ 4.090547344156967
+ 4.0905872897337545
+ 4.090627234771686
+ 4.09066717927078
+ 4.090707123231057
+ 4.090747066652535
+ 4.090787009535236
+ 4.090826951879179
+ 4.090866893684382
+ 4.090906834950867
+ 4.090946775678653
+ 4.090986715867759
+ 4.091026655518205
+ 4.091066594630012
+ 4.091106533203198
+ 4.091146471237784
+ 4.091186408733789
+ 4.091226345691232
+ 4.091266282110134
+ 4.091306217990515
+ 4.091346153332394
+ 4.091386088135789
+ 4.091426022400723
+ 4.091465956127213
+ 4.091505889315282
+ 4.091545821964945
+ 4.091585754076225
+ 4.0916256856491415
+ 4.091665616683713
+ 4.09170554717996
+ 4.091745477137903
+ 4.091785406557559
+ 4.09182533543895
+ 4.091865263782096
+ 4.091905191587014
+ 4.091945118853728
+ 4.091985045582254
+ 4.092024971772612
+ 4.092064897424823
+ 4.092104822538906
+ 4.092144747114882
+ 4.092184671152769
+ 4.0922245946525875
+ 4.092264517614357
+ 4.092304440038097
+ 4.092344361923828
+ 4.092384283271567
+ 4.092424204081338
+ 4.092464124353158
+ 4.092504044087046
+ 4.092543963283023
+ 4.092583881941109
+ 4.092623800061322
+ 4.092663717643684
+ 4.092703634688212
+ 4.092743551194928
+ 4.092783467163851
+ 4.092823382595001
+ 4.092863297488396
+ 4.092903211844057
+ 4.0929431256620035
+ 4.092983038942255
+ 4.093022951684831
+ 4.0930628638897515
+ 4.093102775557036
+ 4.093142686686705
+ 4.093182597278776
+ 4.093222507333271
+ 4.093262416850209
+ 4.093302325829608
+ 4.09334223427149
+ 4.093382142175874
+ 4.093422049542778
+ 4.093461956372224
+ 4.09350186266423
+ 4.093541768418817
+ 4.093581673636003
+ 4.093621578315808
+ 4.093661482458254
+ 4.0937013860633575
+ 4.093741289131139
+ 4.09378119166162
+ 4.093821093654817
+ 4.093860995110753
+ 4.093900896029445
+ 4.093940796410914
+ 4.093980696255179
+ 4.0940205955622595
+ 4.094060494332176
+ 4.094100392564948
+ 4.094140290260594
+ 4.094180187419134
+ 4.094220084040589
+ 4.094259980124977
+ 4.094299875672319
+ 4.094339770682633
+ 4.09437966515594
+ 4.094419559092259
+ 4.09445945249161
+ 4.094499345354012
+ 4.094539237679485
+ 4.094579129468048
+ 4.094619020719723
+ 4.094658911434526
+ 4.09469880161248
+ 4.0947386912536015
+ 4.094778580357913
+ 4.094818468925432
+ 4.094858356956179
+ 4.094898244450173
+ 4.094938131407433
+ 4.094978017827982
+ 4.095017903711836
+ 4.095057789059016
+ 4.095097673869542
+ 4.095137558143433
+ 4.0951774418807085
+ 4.0952173250813875
+ 4.095257207745491
+ 4.095297089873038
+ 4.0953369714640475
+ 4.095376852518541
+ 4.095416733036536
+ 4.095456613018052
+ 4.09549649246311
+ 4.095536371371729
+ 4.095576249743929
+ 4.095616127579729
+ 4.095656004879149
+ 4.095695881642206
+ 4.095735757868925
+ 4.095775633559321
+ 4.095815508713415
+ 4.0958553833312275
+ 4.095895257412776
+ 4.095935130958082
+ 4.0959750039671645
+ 4.096014876440043
+ 4.096054748376736
+ 4.096094619777265
+ 4.096134490641648
+ 4.096174360969907
+ 4.096214230762058
+ 4.096254100018123
+ 4.09629396873812
+ 4.096333836922071
+ 4.096373704569992
+ 4.096413571681906
+ 4.096453438257831
+ 4.096493304297788
+ 4.096533169801793
+ 4.096573034769869
+ 4.096612899202034
+ 4.096652763098308
+ 4.096692626458711
+ 4.096732489283262
+ 4.09677235157198
+ 4.096812213324886
+ 4.096852074541998
+ 4.096891935223336
+ 4.09693179536892
+ 4.09697165497877
+ 4.097011514052904
+ 4.097051372591343
+ 4.097091230594105
+ 4.097131088061212
+ 4.097170944992681
+ 4.097210801388533
+ 4.097250657248788
+ 4.097290512573463
+ 4.09733036736258
+ 4.097370221616157
+ 4.097410075334215
+ 4.097449928516773
+ 4.0974897811638495
+ 4.097529633275465
+ 4.09756948485164
+ 4.0976093358923915
+ 4.0976491863977405
+ 4.097689036367707
+ 4.09772888580231
+ 4.097768734701569
+ 4.097808583065503
+ 4.097848430894133
+ 4.097888278187476
+ 4.097928124945554
+ 4.097967971168385
+ 4.09800781685599
+ 4.098047662008387
+ 4.098087506625597
+ 4.098127350707638
+ 4.09816719425453
+ 4.098207037266293
+ 4.098246879742946
+ 4.0982867216845085
+ 4.098326563091
+ 4.098366403962441
+ 4.098406244298849
+ 4.098446084100245
+ 4.098485923366648
+ 4.098525762098079
+ 4.098565600294555
+ 4.098605437956097
+ 4.098645275082725
+ 4.098685111674456
+ 4.098724947731312
+ 4.098764783253312
+ 4.098804618240474
+ 4.09884445269282
+ 4.098884286610367
+ 4.0989241199931366
+ 4.098963952841147
+ 4.099003785154418
+ 4.099043616932968
+ 4.099083448176819
+ 4.099123278885989
+ 4.099163109060496
+ 4.099202938700362
+ 4.099242767805605
+ 4.099282596376246
+ 4.0993224244123025
+ 4.099362251913795
+ 4.099402078880743
+ 4.099441905313166
+ 4.099481731211084
+ 4.099521556574515
+ 4.099561381403478
+ 4.099601205697996
+ 4.099641029458085
+ 4.099680852683766
+ 4.099720675375058
+ 4.09976049753198
+ 4.099800319154553
+ 4.099840140242795
+ 4.099879960796725
+ 4.099919780816365
+ 4.099959600301733
+ 4.099999419252847
+ 4.100039237669729
+ 4.100079055552397
+ 4.10011887290087
+ 4.100158689715169
+ 4.100198505995313
+ 4.10023832174132
+ 4.100278136953211
+ 4.100317951631005
+ 4.100357765774721
+ 4.100397579384379
+ 4.100437392459998
+ 4.100477205001598
+ 4.1005170170091985
+ 4.100556828482818
+ 4.100596639422477
+ 4.100636449828194
+ 4.1006762596999895
+ 4.100716069037882
+ 4.100755877841892
+ 4.100795686112038
+ 4.100835493848339
+ 4.100875301050816
+ 4.100915107719486
+ 4.100954913854372
+ 4.10099471945549
+ 4.101034524522862
+ 4.101074329056505
+ 4.1011141330564405
+ 4.101153936522686
+ 4.1011937394552636
+ 4.10123354185419
+ 4.101273343719486
+ 4.10131314505117
+ 4.101352945849263
+ 4.101392746113784
+ 4.101432545844752
+ 4.101472345042186
+ 4.101512143706105
+ 4.101551941836531
+ 4.101591739433481
+ 4.101631536496974
+ 4.101671333027031
+ 4.101711129023672
+ 4.101750924486915
+ 4.101790719416779
+ 4.101830513813284
+ 4.10187030767645
+ 4.101910101006296
+ 4.10194989380284
+ 4.101989686066104
+ 4.102029477796106
+ 4.1020692689928655
+ 4.102109059656401
+ 4.102148849786735
+ 4.102188639383883
+ 4.102228428447866
+ 4.102268216978703
+ 4.102308004976416
+ 4.10234779244102
+ 4.102387579372538
+ 4.102427365770987
+ 4.102467151636388
+ 4.1025069369687595
+ 4.102546721768122
+ 4.102586506034493
+ 4.102626289767894
+ 4.102666072968343
+ 4.102705855635859
+ 4.102745637770462
+ 4.1027854193721724
+ 4.102825200441008
+ 4.102864980976989
+ 4.102904760980135
+ 4.102944540450464
+ 4.102984319387996
+ 4.103024097792752
+ 4.103063875664749
+ 4.103103653004009
+ 4.103143429810548
+ 4.103183206084388
+ 4.103222981825548
+ 4.103262757034046
+ 4.103302531709902
+ 4.103342305853136
+ 4.103382079463767
+ 4.103421852541814
+ 4.103461625087298
+ 4.103501397100235
+ 4.103541168580648
+ 4.103580939528554
+ 4.103620709943972
+ 4.1036604798269245
+ 4.103700249177427
+ 4.103740017995502
+ 4.103779786281167
+ 4.103819554034442
+ 4.103859321255346
+ 4.103899087943898
+ 4.103938854100118
+ 4.103978619724026
+ 4.10401838481564
+ 4.104058149374979
+ 4.1040979134020645
+ 4.104137676896914
+ 4.104177439859548
+ 4.104217202289985
+ 4.104256964188244
+ 4.104296725554345
+ 4.104336486388307
+ 4.10437624669015
+ 4.104416006459894
+ 4.104455765697556
+ 4.104495524403156
+ 4.104535282576714
+ 4.10457504021825
+ 4.104614797327782
+ 4.10465455390533
+ 4.104694309950912
+ 4.104734065464551
+ 4.104773820446262
+ 4.104813574896066
+ 4.104853328813983
+ 4.104893082200031
+ 4.104932835054231
+ 4.104972587376601
+ 4.1050123391671605
+ 4.105052090425929
+ 4.105091841152926
+ 4.1051315913481705
+ 4.1051713410116815
+ 4.105211090143479
+ 4.105250838743583
+ 4.105290586812011
+ 4.105330334348783
+ 4.105370081353918
+ 4.105409827827436
+ 4.105449573769357
+ 4.105489319179698
+ 4.10552906405848
+ 4.105568808405723
+ 4.105608552221444
+ 4.105648295505663
+ 4.105688038258401
+ 4.1057277804796755
+ 4.105767522169507
+ 4.105807263327914
+ 4.105847003954915
+ 4.105886744050531
+ 4.10592648361478
+ 4.105966222647683
+ 4.106005961149258
+ 4.106045699119523
+ 4.1060854365585
+ 4.106125173466205
+ 4.106164909842661
+ 4.106204645687885
+ 4.106244381001897
+ 4.106284115784716
+ 4.106323850036361
+ 4.106363583756852
+ 4.106403316946208
+ 4.106443049604447
+ 4.10648278173159
+ 4.106522513327656
+ 4.106562244392665
+ 4.106601974926633
+ 4.106641704929583
+ 4.106681434401532
+ 4.1067211633425
+ 4.106760891752507
+ 4.10680061963157
+ 4.106840346979711
+ 4.1068800737969475
+ 4.1069198000833005
+ 4.1069595258387865
+ 4.106999251063427
+ 4.1070389757572405
+ 4.107078699920247
+ 4.107118423552464
+ 4.107158146653912
+ 4.10719786922461
+ 4.107237591264577
+ 4.107277312773833
+ 4.107317033752397
+ 4.107356754200288
+ 4.107396474117525
+ 4.107436193504129
+ 4.1074759123601154
+ 4.107515630685508
+ 4.107555348480322
+ 4.107595065744579
+ 4.107634782478298
+ 4.107674498681498
+ 4.107714214354199
+ 4.107753929496418
+ 4.107793644108177
+ 4.107833358189493
+ 4.107873071740386
+ 4.107912784760876
+ 4.10795249725098
+ 4.10799220921072
+ 4.108031920640114
+ 4.108071631539182
+ 4.108111341907941
+ 4.108151051746413
+ 4.1081907610546144
+ 4.108230469832567
+ 4.108270178080289
+ 4.1083098857978
+ 4.1083495929851175
+ 4.108389299642263
+ 4.1084290057692545
+ 4.108468711366111
+ 4.108508416432852
+ 4.108548120969497
+ 4.108587824976066
+ 4.108627528452577
+ 4.108667231399049
+ 4.108706933815501
+ 4.108746635701954
+ 4.108786337058426
+ 4.108826037884936
+ 4.108865738181503
+ 4.108905437948148
+ 4.108945137184888
+ 4.108984835891743
+ 4.109024534068732
+ 4.109064231715875
+ 4.109103928833191
+ 4.109143625420698
+ 4.109183321478416
+ 4.109223017006365
+ 4.109262712004563
+ 4.10930240647303
+ 4.109342100411785
+ 4.109381793820846
+ 4.109421486700234
+ 4.109461179049968
+ 4.1095008708700655
+ 4.109540562160547
+ 4.109580252921432
+ 4.1096199431527385
+ 4.109659632854486
+ 4.109699322026694
+ 4.109739010669382
+ 4.109778698782569
+ 4.109818386366273
+ 4.109858073420515
+ 4.109897759945314
+ 4.109937445940687
+ 4.109977131406656
+ 4.110016816343237
+ 4.110056500750453
+ 4.11009618462832
+ 4.110135867976859
+ 4.110175550796088
+ 4.110215233086027
+ 4.110254914846694
+ 4.11029459607811
+ 4.110334276780293
+ 4.110373956953262
+ 4.110413636597036
+ 4.110453315711635
+ 4.110492994297078
+ 4.110532672353384
+ 4.110572349880572
+ 4.110612026878661
+ 4.110651703347671
+ 4.110691379287619
+ 4.110731054698527
+ 4.110770729580413
+ 4.110810403933295
+ 4.110850077757193
+ 4.1108897510521265
+ 4.110929423818115
+ 4.110969096055177
+ 4.111008767763331
+ 4.111048438942597
+ 4.111088109592995
+ 4.111127779714542
+ 4.111167449307258
+ 4.111207118371163
+ 4.111246786906276
+ 4.111286454912614
+ 4.1113261223901985
+ 4.1113657893390485
+ 4.111405455759182
+ 4.111445121650618
+ 4.111484787013378
+ 4.111524451847478
+ 4.111564116152939
+ 4.11160377992978
+ 4.111643443178019
+ 4.111683105897677
+ 4.11172276808877
+ 4.1117624297513204
+ 4.111802090885346
+ 4.111841751490866
+ 4.111881411567899
+ 4.111921071116465
+ 4.111960730136583
+ 4.112000388628271
+ 4.11204004659155
+ 4.112079704026437
+ 4.112119360932953
+ 4.112159017311115
+ 4.112198673160945
+ 4.1122383284824595
+ 4.112277983275678
+ 4.112317637540621
+ 4.1123572912773065
+ 4.112396944485754
+ 4.112436597165982
+ 4.112476249318011
+ 4.112515900941858
+ 4.112555552037545
+ 4.112595202605087
+ 4.112634852644507
+ 4.112674502155823
+ 4.112714151139053
+ 4.112753799594215
+ 4.112793447521333
+ 4.112833094920421
+ 4.1128727417915
+ 4.112912388134589
+ 4.112952033949708
+ 4.112991679236874
+ 4.1130313239961085
+ 4.113070968227429
+ 4.113110611930855
+ 4.113150255106405
+ 4.1131898977541
+ 4.113229539873957
+ 4.113269181465995
+ 4.113308822530235
+ 4.113348463066694
+ 4.113388103075392
+ 4.1134277425563495
+ 4.113467381509583
+ 4.1135070199351125
+ 4.113546657832958
+ 4.113586295203137
+ 4.113625932045671
+ 4.113665568360576
+ 4.113705204147873
+ 4.11374483940758
+ 4.1137844741397185
+ 4.113824108344304
+ 4.113863742021358
+ 4.113903375170898
+ 4.113943007792946
+ 4.113982639887517
+ 4.114022271454632
+ 4.114061902494312
+ 4.114101533006572
+ 4.114141162991435
+ 4.114180792448916
+ 4.114220421379038
+ 4.114260049781818
+ 4.114299677657275
+ 4.114339305005429
+ 4.114378931826298
+ 4.114418558119901
+ 4.114458183886258
+ 4.114497809125388
+ 4.1145374338373095
+ 4.114577058022041
+ 4.114616681679603
+ 4.114656304810014
+ 4.114695927413292
+ 4.114735549489457
+ 4.114775171038528
+ 4.114814792060524
+ 4.114854412555464
+ 4.114894032523366
+ 4.11493365196425
+ 4.114973270878136
+ 4.115012889265041
+ 4.115052507124986
+ 4.1150921244579886
+ 4.115131741264069
+ 4.115171357543244
+ 4.115210973295536
+ 4.1152505885209605
+ 4.115290203219539
+ 4.115329817391289
+ 4.115369431036231
+ 4.115409044154383
+ 4.115448656745764
+ 4.1154882688103935
+ 4.11552788034829
+ 4.1155674913594735
+ 4.1156071018439615
+ 4.115646711801774
+ 4.11568632123293
+ 4.115725930137448
+ 4.1157655385153475
+ 4.115805146366647
+ 4.115844753691366
+ 4.115884360489524
+ 4.115923966761138
+ 4.115963572506229
+ 4.116003177724815
+ 4.116042782416916
+ 4.1160823865825495
+ 4.116121990221736
+ 4.1161615933344935
+ 4.1162011959208415
+ 4.116240797980799
+ 4.116280399514384
+ 4.1163200005216165
+ 4.116359601002515
+ 4.116399200957099
+ 4.116438800385388
+ 4.1164783992873994
+ 4.116517997663153
+ 4.116557595512668
+ 4.116597192835963
+ 4.116636789633057
+ 4.116676385903969
+ 4.116715981648719
+ 4.116755576867324
+ 4.116795171559805
+ 4.116834765726179
+ 4.1168743593664665
+ 4.116913952480687
+ 4.116953545068856
+ 4.116993137130997
+ 4.117032728667127
+ 4.117072319677264
+ 4.1171119101614275
+ 4.117151500119637
+ 4.117191089551912
+ 4.117230678458269
+ 4.11727026683873
+ 4.117309854693313
+ 4.117349442022036
+ 4.117389028824919
+ 4.117428615101979
+ 4.117468200853239
+ 4.117507786078713
+ 4.117547370778423
+ 4.1175869549523885
+ 4.117626538600626
+ 4.117666121723157
+ 4.117705704319998
+ 4.11774528639117
+ 4.11778486793669
+ 4.117824448956578
+ 4.117864029450854
+ 4.117903609419536
+ 4.117943188862642
+ 4.117982767780193
+ 4.118022346172205
+ 4.118061924038701
+ 4.118101501379696
+ 4.118141078195211
+ 4.118180654485264
+ 4.118220230249875
+ 4.118259805489062
+ 4.118299380202845
+ 4.118338954391241
+ 4.118378528054271
+ 4.118418101191954
+ 4.118457673804307
+ 4.11849724589135
+ 4.118536817453101
+ 4.118576388489582
+ 4.118615959000808
+ 4.1186555289868005
+ 4.118695098447577
+ 4.1187346673831575
+ 4.11877423579356
+ 4.118813803678804
+ 4.118853371038909
+ 4.118892937873892
+ 4.118932504183773
+ 4.118972069968572
+ 4.119011635228307
+ 4.119051199962996
+ 4.119090764172659
+ 4.119130327857315
+ 4.119169891016982
+ 4.11920945365168
+ 4.119249015761428
+ 4.119288577346243
+ 4.1193281384061455
+ 4.119367698941154
+ 4.119407258951289
+ 4.1194468184365665
+ 4.119486377397006
+ 4.119525935832629
+ 4.119565493743452
+ 4.119605051129494
+ 4.119644607990775
+ 4.119684164327313
+ 4.119723720139127
+ 4.119763275426236
+ 4.119802830188659
+ 4.119842384426415
+ 4.119881938139524
+ 4.119921491328002
+ 4.11996104399187
+ 4.120000596131146
+ 4.12004014774585
+ 4.120079698836
+ 4.120119249401615
+ 4.120158799442714
+ 4.120198348959315
+ 4.120237897951439
+ 4.120277446419103
+ 4.120316994362327
+ 4.1203565417811285
+ 4.120396088675528
+ 4.120435635045542
+ 4.120475180891193
+ 4.120514726212496
+ 4.120554271009473
+ 4.120593815282141
+ 4.12063335903052
+ 4.120672902254627
+ 4.120712444954483
+ 4.120751987130106
+ 4.120791528781515
+ 4.120831069908729
+ 4.1208706105117665
+ 4.120910150590646
+ 4.120949690145387
+ 4.120989229176009
+ 4.121028767682529
+ 4.121068305664967
+ 4.121107843123342
+ 4.121147380057673
+ 4.121186916467978
+ 4.121226452354277
+ 4.121265987716587
+ 4.121305522554929
+ 4.12134505686932
+ 4.121384590659781
+ 4.121424123926328
+ 4.121463656668983
+ 4.121503188887762
+ 4.121542720582686
+ 4.121582251753773
+ 4.12162178240104
+ 4.12166131252451
+ 4.121700842124198
+ 4.121740371200125
+ 4.121779899752308
+ 4.121819427780768
+ 4.121858955285522
+ 4.121898482266591
+ 4.121938008723991
+ 4.121977534657743
+ 4.122017060067865
+ 4.122056584954376
+ 4.122096109317295
+ 4.12213563315664
+ 4.122175156472431
+ 4.122214679264686
+ 4.122254201533424
+ 4.1222937232786645
+ 4.1223332445004255
+ 4.122372765198725
+ 4.122412285373584
+ 4.122451805025019
+ 4.122491324153051
+ 4.122530842757698
+ 4.122570360838978
+ 4.1226098783969105
+ 4.122649395431515
+ 4.1226889119428085
+ 4.122728427930811
+ 4.122767943395542
+ 4.122807458337019
+ 4.122846972755261
+ 4.1228864866502875
+ 4.122926000022117
+ 4.122965512870768
+ 4.123005025196259
+ 4.12304453699861
+ 4.123084048277839
+ 4.123123559033964
+ 4.123163069267005
+ 4.123202578976982
+ 4.123242088163911
+ 4.123281596827812
+ 4.123321104968704
+ 4.123360612586605
+ 4.123400119681536
+ 4.123439626253513
+ 4.123479132302557
+ 4.123518637828686
+ 4.123558142831918
+ 4.123597647312272
+ 4.123637151269768
+ 4.123676654704424
+ 4.123716157616258
+ 4.12375566000529
+ 4.123795161871537
+ 4.12383466321502
+ 4.123874164035757
+ 4.1239136643337675
+ 4.123953164109068
+ 4.12399266336168
+ 4.12403216209162
+ 4.124071660298908
+ 4.124111157983562
+ 4.124150655145602
+ 4.124190151785045
+ 4.124229647901912
+ 4.12426914349622
+ 4.124308638567989
+ 4.124348133117237
+ 4.1243876271439825
+ 4.124427120648245
+ 4.124466613630042
+ 4.1245061060893935
+ 4.124545598026318
+ 4.124585089440835
+ 4.124624580332961
+ 4.124664070702718
+ 4.12470356055012
+ 4.124743049875192
+ 4.124782538677947
+ 4.124822026958408
+ 4.12486151471659
+ 4.124901001952516
+ 4.1249404886662004
+ 4.1249799748576645
+ 4.125019460526928
+ 4.125058945674007
+ 4.125098430298921
+ 4.12513791440169
+ 4.125177397982331
+ 4.125216881040864
+ 4.125256363577308
+ 4.125295845591681
+ 4.125335327084001
+ 4.125374808054288
+ 4.125414288502561
+ 4.125453768428837
+ 4.125493247833137
+ 4.125532726715477
+ 4.125572205075879
+ 4.125611682914359
+ 4.1256511602309365
+ 4.125690637025631
+ 4.12573011329846
+ 4.125769589049444
+ 4.1258090642786
+ 4.125848538985947
+ 4.1258880131715046
+ 4.125927486835291
+ 4.125966959977324
+ 4.126006432597625
+ 4.126045904696209
+ 4.126085376273098
+ 4.126124847328308
+ 4.1261643178618606
+ 4.126203787873772
+ 4.126243257364062
+ 4.12628272633275
+ 4.126322194779853
+ 4.126361662705391
+ 4.126401130109382
+ 4.126440596991846
+ 4.1264800633528
+ 4.126519529192263
+ 4.126558994510256
+ 4.126598459306795
+ 4.126637923581899
+ 4.1266773873355875
+ 4.126716850567878
+ 4.126756313278792
+ 4.126795775468345
+ 4.126835237136558
+ 4.126874698283448
+ 4.126914158909035
+ 4.126953619013337
+ 4.126993078596373
+ 4.1270325376581605
+ 4.12707199619872
+ 4.12711145421807
+ 4.127150911716227
+ 4.1271903686932125
+ 4.127229825149043
+ 4.1272692810837395
+ 4.127308736497318
+ 4.1273481913898
+ 4.1273876457612015
+ 4.127427099611542
+ 4.127466552940842
+ 4.127506005749117
+ 4.127545458036388
+ 4.127584909802674
+ 4.1276243610479915
+ 4.1276638117723605
+ 4.1277032619758005
+ 4.127742711658329
+ 4.127782160819964
+ 4.127821609460726
+ 4.127861057580632
+ 4.127900505179702
+ 4.127939952257955
+ 4.127979398815407
+ 4.128018844852079
+ 4.128058290367989
+ 4.1280977353631565
+ 4.128137179837599
+ 4.128176623791335
+ 4.1282160672243835
+ 4.128255510136764
+ 4.128294952528495
+ 4.128334394399594
+ 4.12837383575008
+ 4.128413276579972
+ 4.1284527168892895
+ 4.12849215667805
+ 4.128531595946272
+ 4.128571034693975
+ 4.128610472921176
+ 4.128649910627896
+ 4.128689347814153
+ 4.128728784479964
+ 4.12876822062535
+ 4.128807656250327
+ 4.128847091354916
+ 4.1288865259391345
+ 4.128925960003001
+ 4.128965393546535
+ 4.129004826569754
+ 4.129044259072678
+ 4.129083691055325
+ 4.129123122517713
+ 4.129162553459861
+ 4.129201983881788
+ 4.129241413783513
+ 4.129280843165053
+ 4.129320272026428
+ 4.129359700367656
+ 4.129399128188757
+ 4.129438555489747
+ 4.1294779822706476
+ 4.129517408531475
+ 4.1295568342722495
+ 4.129596259492989
+ 4.129635684193712
+ 4.129675108374436
+ 4.129714532035182
+ 4.1297539551759685
+ 4.129793377796811
+ 4.1298327998977316
+ 4.129872221478747
+ 4.129911642539876
+ 4.129951063081139
+ 4.129990483102552
+ 4.130029902604135
+ 4.130069321585906
+ 4.130108740047884
+ 4.130148157990088
+ 4.130187575412536
+ 4.130226992315246
+ 4.130266408698239
+ 4.130305824561531
+ 4.130345239905141
+ 4.130384654729089
+ 4.130424069033393
+ 4.130463482818071
+ 4.130502896083142
+ 4.130542308828624
+ 4.130581721054536
+ 4.130621132760898
+ 4.130660543947727
+ 4.130699954615041
+ 4.13073936476286
+ 4.130778774391202
+ 4.130818183500086
+ 4.13085759208953
+ 4.130897000159552
+ 4.1309364077101725
+ 4.13097581474141
+ 4.13101522125328
+ 4.131054627245804
+ 4.131094032719
+ 4.131133437672886
+ 4.131172842107481
+ 4.131212246022804
+ 4.131251649418871
+ 4.131291052295705
+ 4.131330454653321
+ 4.131369856491739
+ 4.131409257810978
+ 4.131448658611054
+ 4.131488058891989
+ 4.1315274586538
+ 4.131566857896504
+ 4.131606256620123
+ 4.1316456548246725
+ 4.131685052510173
+ 4.131724449676643
+ 4.131763846324099
+ 4.131803242452562
+ 4.131842638062048
+ 4.1318820331525785
+ 4.13192142772417
+ 4.1319608217768415
+ 4.132000215310613
+ 4.1320396083255
+ 4.132079000821524
+ 4.132118392798702
+ 4.1321577842570525
+ 4.132197175196596
+ 4.132236565617348
+ 4.1322759555193285
+ 4.132315344902557
+ 4.13235473376705
+ 4.132394122112829
+ 4.132433509939909
+ 4.132472897248311
+ 4.132512284038053
+ 4.132551670309153
+ 4.13259105606163
+ 4.132630441295502
+ 4.132669826010789
+ 4.132709210207508
+ 4.132748593885677
+ 4.132787977045316
+ 4.132827359686444
+ 4.132866741809078
+ 4.132906123413238
+ 4.132945504498941
+ 4.132984885066206
+ 4.1330242651150515
+ 4.133063644645497
+ 4.13310302365756
+ 4.133142402151258
+ 4.133181780126613
+ 4.133221157583639
+ 4.133260534522359
+ 4.133299910942788
+ 4.133339286844946
+ 4.133378662228852
+ 4.133418037094524
+ 4.13345741144198
+ 4.133496785271238
+ 4.133536158582319
+ 4.133575531375239
+ 4.133614903650018
+ 4.133654275406673
+ 4.1336936466452245
+ 4.13373301736569
+ 4.133772387568087
+ 4.133811757252436
+ 4.1338511264187545
+ 4.13389049506706
+ 4.133929863197373
+ 4.1339692308097105
+ 4.134008597904092
+ 4.134047964480535
+ 4.134087330539058
+ 4.134126696079681
+ 4.134166061102421
+ 4.134205425607297
+ 4.1342447895943275
+ 4.134284153063531
+ 4.134323516014925
+ 4.134362878448529
+ 4.134402240364363
+ 4.134441601762443
+ 4.1344809626427885
+ 4.134520323005417
+ 4.134559682850348
+ 4.134599042177601
+ 4.134638400987193
+ 4.134677759279143
+ 4.134717117053468
+ 4.134756474310188
+ 4.134795831049321
+ 4.1348351872708875
+ 4.134874542974902
+ 4.134913898161386
+ 4.134953252830358
+ 4.134992606981834
+ 4.1350319606158354
+ 4.135071313732379
+ 4.1351106663314825
+ 4.135150018413166
+ 4.135189369977448
+ 4.135228721024347
+ 4.135268071553879
+ 4.135307421566065
+ 4.135346771060923
+ 4.135386120038471
+ 4.135425468498728
+ 4.135464816441712
+ 4.1355041638674415
+ 4.1355435107759355
+ 4.135582857167211
+ 4.135622203041288
+ 4.135661548398185
+ 4.13570089323792
+ 4.13574023756051
+ 4.135779581365976
+ 4.135818924654334
+ 4.135858267425604
+ 4.135897609679805
+ 4.135936951416954
+ 4.1359762926370705
+ 4.136015633340172
+ 4.136054973526277
+ 4.136094313195405
+ 4.136133652347573
+ 4.136172990982801
+ 4.136212329101106
+ 4.136251666702507
+ 4.136291003787023
+ 4.1363303403546725
+ 4.136369676405472
+ 4.136409011939443
+ 4.1364483469566
+ 4.136487681456965
+ 4.136527015440556
+ 4.1365663489073885
+ 4.136605681857485
+ 4.136645014290861
+ 4.1366843462075344
+ 4.1367236776075265
+ 4.136763008490854
+ 4.136802338857536
+ 4.136841668707589
+ 4.136880998041035
+ 4.13692032685789
+ 4.136959655158171
+ 4.1369989829419
+ 4.137038310209093
+ 4.137077636959768
+ 4.137116963193946
+ 4.137156288911643
+ 4.137195614112878
+ 4.13723493879767
+ 4.137274262966037
+ 4.1373135866179975
+ 4.137352909753569
+ 4.137392232372772
+ 4.137431554475623
+ 4.1374708760621415
+ 4.137510197132345
+ 4.137549517686253
+ 4.137588837723882
+ 4.137628157245254
+ 4.137667476250383
+ 4.13770679473929
+ 4.1377461127119926
+ 4.137785430168511
+ 4.13782474710886
+ 4.137864063533061
+ 4.1379033794411315
+ 4.1379426948330895
+ 4.137982009708955
+ 4.138021324068744
+ 4.138060637912475
+ 4.138099951240168
+ 4.1381392640518415
+ 4.138178576347513
+ 4.138217888127201
+ 4.138257199390924
+ 4.1382965101387
+ 4.138335820370548
+ 4.1383751300864855
+ 4.138414439286532
+ 4.138453747970704
+ 4.138493056139023
+ 4.138532363791504
+ 4.138571670928168
+ 4.138610977549032
+ 4.138650283654115
+ 4.138689589243434
+ 4.138728894317009
+ 4.138768198874858
+ 4.1388075029169995
+ 4.138846806443451
+ 4.138886109454232
+ 4.138925411949359
+ 4.138964713928853
+ 4.13900401539273
+ 4.139043316341009
+ 4.13908261677371
+ 4.139121916690849
+ 4.139161216092445
+ 4.139200514978517
+ 4.139239813349084
+ 4.139279111204163
+ 4.139318408543773
+ 4.139357705367932
+ 4.139397001676659
+ 4.139436297469971
+ 4.139475592747887
+ 4.139514887510427
+ 4.139554181757607
+ 4.139593475489446
+ 4.1396327687059635
+ 4.139672061407175
+ 4.139711353593103
+ 4.139750645263763
+ 4.139789936419174
+ 4.139829227059354
+ 4.139868517184322
+ 4.1399078067940955
+ 4.139947095888694
+ 4.139986384468134
+ 4.140025672532436
+ 4.140064960081617
+ 4.140104247115696
+ 4.14014353363469
+ 4.1401828196386194
+ 4.140222105127501
+ 4.140261390101354
+ 4.140300674560195
+ 4.140339958504045
+ 4.140379241932921
+ 4.14041852484684
+ 4.140457807245823
+ 4.140497089129886
+ 4.140536370499048
+ 4.140575651353329
+ 4.1406149316927445
+ 4.140654211517314
+ 4.140693490827057
+ 4.140732769621991
+ 4.140772047902133
+ 4.140811325667503
+ 4.1408506029181185
+ 4.140889879653999
+ 4.140929155875161
+ 4.140968431581624
+ 4.141007706773405
+ 4.141046981450525
+ 4.141086255613
+ 4.141125529260848
+ 4.141164802394089
+ 4.14120407501274
+ 4.141243347116821
+ 4.141282618706348
+ 4.1413218897813415
+ 4.141361160341817
+ 4.141400430387796
+ 4.141439699919294
+ 4.141478968936331
+ 4.141518237438926
+ 4.141557505427095
+ 4.141596772900858
+ 4.1416360398602325
+ 4.141675306305238
+ 4.141714572235891
+ 4.14175383765221
+ 4.141793102554216
+ 4.141832366941923
+ 4.141871630815352
+ 4.141910894174521
+ 4.141950157019448
+ 4.141989419350152
+ 4.142028681166649
+ 4.142067942468961
+ 4.142107203257102
+ 4.142146463531094
+ 4.142185723290953
+ 4.142224982536699
+ 4.142264241268348
+ 4.14230349948592
+ 4.142342757189433
+ 4.142382014378905
+ 4.142421271054354
+ 4.142460527215799
+ 4.142499782863258
+ 4.142539037996748
+ 4.14257829261629
+ 4.1426175467219
+ 4.142656800313596
+ 4.142696053391399
+ 4.142735305955324
+ 4.142774558005391
+ 4.142813809541619
+ 4.142853060564024
+ 4.142892311072626
+ 4.142931561067443
+ 4.142970810548492
+ 4.1430100595157935
+ 4.143049307969364
+ 4.143088555909222
+ 4.143127803335386
+ 4.143167050247875
+ 4.1432062966467065
+ 4.143245542531898
+ 4.143284787903469
+ 4.143324032761437
+ 4.14336327710582
+ 4.143402520936637
+ 4.1434417642539065
+ 4.143481007057646
+ 4.1435202493478736
+ 4.143559491124608
+ 4.143598732387868
+ 4.143637973137671
+ 4.143677213374034
+ 4.143716453096978
+ 4.143755692306519
+ 4.143794931002677
+ 4.143834169185469
+ 4.1438734068549135
+ 4.143912644011029
+ 4.143951880653833
+ 4.1439911167833445
+ 4.144030352399581
+ 4.144069587502562
+ 4.1441088220923055
+ 4.144148056168828
+ 4.144187289732149
+ 4.144226522782287
+ 4.1442657553192594
+ 4.144304987343085
+ 4.144344218853782
+ 4.144383449851368
+ 4.144422680335861
+ 4.144461910307281
+ 4.144501139765645
+ 4.144540368710971
+ 4.144579597143277
+ 4.144618825062583
+ 4.144658052468905
+ 4.144697279362263
+ 4.1447365057426735
+ 4.144775731610156
+ 4.144814956964728
+ 4.144854181806408
+ 4.144893406135214
+ 4.144932629951165
+ 4.144971853254278
+ 4.145011076044572
+ 4.145050298322065
+ 4.145089520086775
+ 4.145128741338721
+ 4.145167962077919
+ 4.1452071823043894
+ 4.1452464020181505
+ 4.1452856212192195
+ 4.145324839907614
+ 4.145364058083354
+ 4.145403275746457
+ 4.145442492896939
+ 4.145481709534822
+ 4.145520925660121
+ 4.145560141272856
+ 4.1455993563730456
+ 4.145638570960705
+ 4.145677785035856
+ 4.145716998598514
+ 4.1457562116487
+ 4.145795424186429
+ 4.145834636211721
+ 4.145873847724594
+ 4.145913058725066
+ 4.145952269213155
+ 4.14599147918888
+ 4.146030688652259
+ 4.146069897603309
+ 4.146109106042049
+ 4.146148313968497
+ 4.1461875213826715
+ 4.14622672828459
+ 4.146265934674272
+ 4.146305140551734
+ 4.146344345916995
+ 4.146383550770072
+ 4.1464227551109865
+ 4.146461958939753
+ 4.146501162256391
+ 4.146540365060919
+ 4.146579567353355
+ 4.146618769133718
+ 4.146657970402023
+ 4.146697171158292
+ 4.1467363714025405
+ 4.146775571134788
+ 4.146814770355053
+ 4.146853969063352
+ 4.146893167259704
+ 4.146932364944128
+ 4.146971562116641
+ 4.147010758777262
+ 4.1470499549260085
+ 4.147089150562898
+ 4.147128345687951
+ 4.147167540301183
+ 4.147206734402613
+ 4.14724592799226
+ 4.147285121070142
+ 4.147324313636275
+ 4.147363505690681
+ 4.147402697233375
+ 4.147441888264375
+ 4.1474810787837
+ 4.147520268791371
+ 4.147559458287401
+ 4.147598647271812
+ 4.14763783574462
+ 4.147677023705843
+ 4.147716211155502
+ 4.147755398093612
+ 4.147794584520192
+ 4.147833770435261
+ 4.147872955838836
+ 4.147912140730936
+ 4.1479513251115785
+ 4.147990508980781
+ 4.148029692338564
+ 4.1480688751849435
+ 4.148108057519938
+ 4.148147239343565
+ 4.148186420655845
+ 4.148225601456794
+ 4.14826478174643
+ 4.148303961524772
+ 4.148343140791838
+ 4.148382319547646
+ 4.1484214977922145
+ 4.148460675525561
+ 4.148499852747704
+ 4.148539029458661
+ 4.14857820565845
+ 4.148617381347091
+ 4.148656556524599
+ 4.148695731190995
+ 4.148734905346295
+ 4.1487740789905185
+ 4.148813252123683
+ 4.148852424745807
+ 4.148891596856908
+ 4.148930768457005
+ 4.148969939546115
+ 4.149009110124257
+ 4.1490482801914474
+ 4.149087449747707
+ 4.149126618793051
+ 4.1491657873275
+ 4.149204955351071
+ 4.149244122863782
+ 4.149283289865651
+ 4.149322456356697
+ 4.1493616223369365
+ 4.149400787806389
+ 4.149439952765072
+ 4.149479117213003
+ 4.149518281150201
+ 4.149557444576684
+ 4.1495966074924695
+ 4.149635769897576
+ 4.149674931792021
+ 4.149714093175824
+ 4.149753254049002
+ 4.149792414411572
+ 4.149831574263555
+ 4.149870733604966
+ 4.149909892435826
+ 4.14994905075615
+ 4.149988208565958
+ 4.1500273658652675
+ 4.150066522654097
+ 4.150105678932464
+ 4.150144834700386
+ 4.150183989957884
+ 4.150223144704971
+ 4.15026229894167
+ 4.150301452667996
+ 4.15034060588397
+ 4.150379758589606
+ 4.150418910784925
+ 4.150458062469945
+ 4.150497213644683
+ 4.150536364309156
+ 4.150575514463385
+ 4.150614664107385
+ 4.150653813241177
+ 4.1506929618647765
+ 4.150732109978203
+ 4.150771257581474
+ 4.150810404674608
+ 4.150849551257623
+ 4.150888697330537
+ 4.150927842893367
+ 4.1509669879461315
+ 4.15100613248885
+ 4.151045276521538
+ 4.151084420044216
+ 4.151123563056901
+ 4.151162705559611
+ 4.151201847552364
+ 4.151240989035178
+ 4.151280130008071
+ 4.1513192704710615
+ 4.151358410424168
+ 4.151397549867406
+ 4.151436688800796
+ 4.151475827224356
+ 4.1515149651381025
+ 4.151554102542055
+ 4.15159323943623
+ 4.151632375820647
+ 4.151671511695324
+ 4.151710647060277
+ 4.151749781915526
+ 4.151788916261088
+ 4.151828050096983
+ 4.151867183423226
+ 4.151906316239837
+ 4.151945448546834
+ 4.151984580344234
+ 4.152023711632055
+ 4.1520628424103165
+ 4.152101972679036
+ 4.15214110243823
+ 4.152180231687918
+ 4.152219360428117
+ 4.1522584886588465
+ 4.152297616380124
+ 4.152336743591966
+ 4.152375870294391
+ 4.152414996487419
+ 4.152454122171067
+ 4.152493247345351
+ 4.152532372010292
+ 4.152571496165906
+ 4.1526106198122115
+ 4.152649742949227
+ 4.15268886557697
+ 4.152727987695458
+ 4.15276710930471
+ 4.152806230404743
+ 4.152845350995577
+ 4.152884471077228
+ 4.1529235906497135
+ 4.152962709713053
+ 4.153001828267265
+ 4.153040946312366
+ 4.153080063848374
+ 4.153119180875308
+ 4.153158297393185
+ 4.153197413402024
+ 4.153236528901842
+ 4.153275643892657
+ 4.1533147583744885
+ 4.153353872347352
+ 4.1533929858112675
+ 4.1534320987662525
+ 4.153471211212325
+ 4.153510323149502
+ 4.153549434577802
+ 4.153588545497244
+ 4.153627655907845
+ 4.153666765809622
+ 4.153705875202596
+ 4.1537449840867815
+ 4.153784092462199
+ 4.153823200328865
+ 4.153862307686798
+ 4.153901414536016
+ 4.153940520876536
+ 4.153979626708378
+ 4.154018732031559
+ 4.154057836846095
+ 4.154096941152008
+ 4.154136044949312
+ 4.154175148238028
+ 4.154214251018171
+ 4.154253353289762
+ 4.154292455052816
+ 4.154331556307353
+ 4.1543706570533905
+ 4.154409757290947
+ 4.154448857020038
+ 4.154487956240685
+ 4.154527054952903
+ 4.154566153156712
+ 4.1546052508521285
+ 4.154644348039171
+ 4.154683444717858
+ 4.154722540888207
+ 4.1547616365502344
+ 4.154800731703961
+ 4.154839826349403
+ 4.154878920486579
+ 4.1549180141155055
+ 4.154957107236202
+ 4.154996199848686
+ 4.1550352919529745
+ 4.1550743835490875
+ 4.155113474637041
+ 4.155152565216854
+ 4.155191655288545
+ 4.155230744852129
+ 4.155269833907627
+ 4.155308922455056
+ 4.155348010494433
+ 4.155387098025778
+ 4.155426185049107
+ 4.155465271564439
+ 4.1555043575717905
+ 4.15554344307118
+ 4.155582528062627
+ 4.155621612546148
+ 4.155660696521761
+ 4.155699779989485
+ 4.1557388629493355
+ 4.155777945401332
+ 4.155817027345493
+ 4.155856108781836
+ 4.155895189710377
+ 4.155934270131137
+ 4.155973350044133
+ 4.156012429449381
+ 4.1560515083469
+ 4.15609058673671
+ 4.156129664618826
+ 4.156168741993266
+ 4.156207818860049
+ 4.156246895219194
+ 4.156285971070717
+ 4.156325046414636
+ 4.156364121250971
+ 4.1564031955797365
+ 4.156442269400953
+ 4.156481342714638
+ 4.156520415520809
+ 4.156559487819484
+ 4.15659855961068
+ 4.156637630894417
+ 4.156676701670711
+ 4.15671577193958
+ 4.1567548417010425
+ 4.156793910955117
+ 4.15683297970182
+ 4.15687204794117
+ 4.156911115673185
+ 4.156950182897883
+ 4.156989249615281
+ 4.157028315825398
+ 4.157067381528252
+ 4.157106446723859
+ 4.1571455114122395
+ 4.157184575593409
+ 4.157223639267388
+ 4.157262702434191
+ 4.157301765093838
+ 4.1573408272463475
+ 4.157379888891736
+ 4.157418950030021
+ 4.157458010661222
+ 4.157497070785356
+ 4.157536130402441
+ 4.157575189512494
+ 4.157614248115534
+ 4.157653306211579
+ 4.1576923638006456
+ 4.157731420882753
+ 4.157770477457918
+ 4.157809533526159
+ 4.157848589087494
+ 4.15788764414194
+ 4.157926698689517
+ 4.15796575273024
+ 4.158004806264128
+ 4.1580438592912
+ 4.158082911811473
+ 4.158121963824964
+ 4.158161015331692
+ 4.158200066331674
+ 4.158239116824929
+ 4.158278166811474
+ 4.158317216291327
+ 4.158356265264506
+ 4.158395313731028
+ 4.158434361690912
+ 4.158473409144175
+ 4.158512456090835
+ 4.158551502530911
+ 4.15859054846442
+ 4.158629593891379
+ 4.1586686388118075
+ 4.158707683225721
+ 4.15874672713314
+ 4.15878577053408
+ 4.158824813428561
+ 4.158863855816599
+ 4.158902897698212
+ 4.1589419390734195
+ 4.158980979942238
+ 4.159020020304686
+ 4.1590590601607795
+ 4.159098099510539
+ 4.15913713835398
+ 4.159176176691123
+ 4.159215214521982
+ 4.159254251846578
+ 4.159293288664928
+ 4.15933232497705
+ 4.159371360782961
+ 4.159410396082679
+ 4.159449430876222
+ 4.159488465163609
+ 4.159527498944856
+ 4.159566532219981
+ 4.159605564989002
+ 4.159644597251939
+ 4.159683629008806
+ 4.159722660259624
+ 4.15976169100441
+ 4.1598007212431805
+ 4.159839750975954
+ 4.159878780202749
+ 4.159917808923582
+ 4.1599568371384725
+ 4.1599958648474376
+ 4.160034892050494
+ 4.160073918747662
+ 4.160112944938956
+ 4.160151970624397
+ 4.160190995804
+ 4.160230020477785
+ 4.160269044645769
+ 4.16030806830797
+ 4.160347091464406
+ 4.160386114115092
+ 4.16042513626005
+ 4.160464157899296
+ 4.1605031790328475
+ 4.160542199660723
+ 4.160581219782939
+ 4.160620239399514
+ 4.160659258510467
+ 4.160698277115814
+ 4.160737295215573
+ 4.160776312809762
+ 4.1608153298984005
+ 4.1608543464815035
+ 4.160893362559091
+ 4.160932378131179
+ 4.160971393197786
+ 4.161010407758931
+ 4.16104942181463
+ 4.161088435364902
+ 4.161127448409763
+ 4.161166460949233
+ 4.161205472983328
+ 4.161244484512067
+ 4.161283495535467
+ 4.161322506053547
+ 4.161361516066322
+ 4.161400525573814
+ 4.161439534576036
+ 4.16147854307301
+ 4.161517551064751
+ 4.161556558551278
+ 4.1615955655326085
+ 4.16163457200876
+ 4.16167357797975
+ 4.161712583445597
+ 4.161751588406318
+ 4.161790592861932
+ 4.1618295968124555
+ 4.161868600257907
+ 4.161907603198303
+ 4.161946605633663
+ 4.161985607564004
+ 4.162024608989343
+ 4.1620636099096995
+ 4.162102610325089
+ 4.1621416102355315
+ 4.162180609641043
+ 4.162219608541642
+ 4.162258606937346
+ 4.162297604828174
+ 4.1623366022141415
+ 4.1623755990952676
+ 4.16241459547157
+ 4.162453591343067
+ 4.162492586709774
+ 4.162531581571712
+ 4.162570575928896
+ 4.162609569781345
+ 4.1626485631290775
+ 4.162687555972109
+ 4.162726548310459
+ 4.162765540144145
+ 4.162804531473184
+ 4.162843522297594
+ 4.162882512617394
+ 4.1629215024325985
+ 4.162960491743229
+ 4.162999480549302
+ 4.163038468850834
+ 4.1630774566478435
+ 4.163116443940348
+ 4.1631554307283665
+ 4.163194417011915
+ 4.163233402791012
+ 4.163272388065675
+ 4.1633113728359215
+ 4.163350357101771
+ 4.1633893408632385
+ 4.163428324120343
+ 4.163467306873102
+ 4.163506289121535
+ 4.163545270865656
+ 4.163584252105486
+ 4.163623232841041
+ 4.16366221307234
+ 4.163701192799399
+ 4.163740172022237
+ 4.163779150740872
+ 4.16381812895532
+ 4.1638571066656
+ 4.16389608387173
+ 4.163935060573727
+ 4.1639740367716085
+ 4.164013012465393
+ 4.164051987655097
+ 4.164090962340739
+ 4.164129936522338
+ 4.164168910199908
+ 4.164207883373471
+ 4.164246856043042
+ 4.16428582820864
+ 4.164324799870281
+ 4.164363771027984
+ 4.164402741681767
+ 4.164441711831647
+ 4.164480681477642
+ 4.164519650619769
+ 4.164558619258046
+ 4.164597587392492
+ 4.164636555023122
+ 4.164675522149956
+ 4.164714488773011
+ 4.164753454892304
+ 4.164792420507855
+ 4.164831385619678
+ 4.164870350227794
+ 4.164909314332219
+ 4.16494827793297
+ 4.164987241030066
+ 4.165026203623524
+ 4.165065165713363
+ 4.1651041272996
+ 4.165143088382251
+ 4.165182048961335
+ 4.165221009036871
+ 4.165259968608874
+ 4.165298927677363
+ 4.165337886242357
+ 4.165376844303871
+ 4.165415801861925
+ 4.1654547589165345
+ 4.1654937154677185
+ 4.165532671515495
+ 4.16557162705988
+ 4.165610582100894
+ 4.165649536638551
+ 4.165688490672872
+ 4.165727444203872
+ 4.165766397231572
+ 4.165805349755985
+ 4.165844301777132
+ 4.16588325329503
+ 4.165922204309696
+ 4.165961154821149
+ 4.166000104829405
+ 4.166039054334482
+ 4.1660780033364
+ 4.166116951835174
+ 4.166155899830821
+ 4.166194847323361
+ 4.16623379431281
+ 4.166272740799187
+ 4.166311686782508
+ 4.166350632262792
+ 4.166389577240055
+ 4.166428521714318
+ 4.166467465685595
+ 4.166506409153905
+ 4.1665453521192655
+ 4.166584294581695
+ 4.16662323654121
+ 4.166662177997829
+ 4.166701118951568
+ 4.166740059402447
+ 4.166778999350482
+ 4.166817938795692
+ 4.166856877738093
+ 4.166895816177703
+ 4.166934754114541
+ 4.166973691548622
+ 4.1670126284799665
+ 4.167051564908591
+ 4.167090500834512
+ 4.167129436257747
+ 4.167168371178317
+ 4.167207305596235
+ 4.167246239511522
+ 4.167285172924194
+ 4.16732410583427
+ 4.167363038241766
+ 4.167401970146701
+ 4.1674409015490905
+ 4.167479832448955
+ 4.16751876284631
+ 4.167557692741174
+ 4.167596622133565
+ 4.167635551023498
+ 4.1676744794109934
+ 4.167713407296069
+ 4.16775233467874
+ 4.167791261559026
+ 4.167830187936944
+ 4.167869113812512
+ 4.167908039185746
+ 4.167946964056665
+ 4.167985888425287
+ 4.168024812291629
+ 4.168063735655707
+ 4.168102658517541
+ 4.168141580877148
+ 4.168180502734545
+ 4.1682194240897505
+ 4.16825834494278
+ 4.168297265293654
+ 4.168336185142389
+ 4.168375104489
+ 4.168414023333509
+ 4.16845294167593
+ 4.1684918595162825
+ 4.168530776854583
+ 4.16856969369085
+ 4.1686086100251005
+ 4.168647525857353
+ 4.168686441187624
+ 4.168725356015932
+ 4.168764270342293
+ 4.168803184166726
+ 4.1688420974892475
+ 4.168881010309876
+ 4.168919922628629
+ 4.168958834445524
+ 4.168997745760579
+ 4.16903665657381
+ 4.169075566885236
+ 4.169114476694873
+ 4.169153386002741
+ 4.169192294808856
+ 4.169231203113236
+ 4.169270110915898
+ 4.16930901821686
+ 4.169347925016139
+ 4.169386831313754
+ 4.169425737109721
+ 4.169464642404058
+ 4.169503547196783
+ 4.169542451487914
+ 4.169581355277466
+ 4.16962025856546
+ 4.169659161351912
+ 4.1696980636368375
+ 4.169736965420258
+ 4.169775866702189
+ 4.169814767482647
+ 4.169853667761651
+ 4.169892567539218
+ 4.169931466815367
+ 4.169970365590113
+ 4.170009263863475
+ 4.170048161635471
+ 4.170087058906117
+ 4.170125955675432
+ 4.170164851943433
+ 4.170203747710138
+ 4.1702426429755635
+ 4.1702815377397275
+ 4.170320432002647
+ 4.170359325764342
+ 4.170398219024826
+ 4.17043711178412
+ 4.170476004042241
+ 4.170514895799205
+ 4.170553787055031
+ 4.170592677809735
+ 4.170631568063335
+ 4.1706704578158496
+ 4.170709347067295
+ 4.17074823581769
+ 4.1707871240670515
+ 4.170826011815397
+ 4.170864899062743
+ 4.170903785809109
+ 4.170942672054511
+ 4.170981557798968
+ 4.1710204430424955
+ 4.1710593277851125
+ 4.171098212026836
+ 4.171137095767683
+ 4.171175979007672
+ 4.171214861746821
+ 4.1712537439851465
+ 4.171292625722665
+ 4.171331506959397
+ 4.171370387695357
+ 4.171409267930563
+ 4.171448147665035
+ 4.171487026898787
+ 4.171525905631838
+ 4.1715647838642065
+ 4.171603661595909
+ 4.171642538826964
+ 4.171681415557388
+ 4.171720291787198
+ 4.171759167516412
+ 4.171798042745048
+ 4.171836917473124
+ 4.171875791700655
+ 4.1719146654276615
+ 4.171953538654159
+ 4.171992411380166
+ 4.1720312836057
+ 4.172070155330777
+ 4.172109026555416
+ 4.172147897279634
+ 4.17218676750345
+ 4.1722256372268784
+ 4.17226450644994
+ 4.172303375172649
+ 4.172342243395025
+ 4.172381111117086
+ 4.172419978338847
+ 4.172458845060327
+ 4.172497711281544
+ 4.172536577002515
+ 4.172575442223257
+ 4.172614306943789
+ 4.172653171164127
+ 4.172692034884288
+ 4.17273089810429
+ 4.172769760824152
+ 4.172808623043889
+ 4.17284748476352
+ 4.172886345983063
+ 4.172925206702534
+ 4.17296406692195
+ 4.173002926641332
+ 4.173041785860693
+ 4.173080644580053
+ 4.1731195027994294
+ 4.17315836051884
+ 4.1731972177382985
+ 4.1732360744578285
+ 4.173274930677443
+ 4.17331378639716
+ 4.173352641616998
+ 4.173391496336976
+ 4.1734303505571075
+ 4.173469204277413
+ 4.1735080574979095
+ 4.1735469102186125
+ 4.173585762439542
+ 4.173624614160714
+ 4.173663465382146
+ 4.1737023161038564
+ 4.173741166325861
+ 4.1737800160481795
+ 4.173818865270827
+ 4.173857713993823
+ 4.173896562217184
+ 4.173935409940927
+ 4.173974257165069
+ 4.17401310388963
+ 4.174051950114624
+ 4.174090795840072
+ 4.174129641065988
+ 4.174168485792392
+ 4.1742073300193
+ 4.17424617374673
+ 4.174285016974699
+ 4.174323859703226
+ 4.174362701932326
+ 4.174401543662018
+ 4.1744403848923195
+ 4.174479225623247
+ 4.1745180658548176
+ 4.1745569055870515
+ 4.174595744819963
+ 4.174634583553571
+ 4.174673421787892
+ 4.174712259522945
+ 4.174751096758746
+ 4.174789933495312
+ 4.174828769732663
+ 4.174867605470813
+ 4.174906440709782
+ 4.174945275449587
+ 4.174984109690245
+ 4.175022943431772
+ 4.1750617766741875
+ 4.175100609417508
+ 4.175139441661751
+ 4.175178273406935
+ 4.1752171046530755
+ 4.175255935400192
+ 4.175294765648299
+ 4.175333595397417
+ 4.175372424647561
+ 4.1754112533987495
+ 4.175450081651001
+ 4.175488909404331
+ 4.175527736658758
+ 4.175566563414299
+ 4.175605389670971
+ 4.175644215428792
+ 4.17568304068778
+ 4.175721865447951
+ 4.175760689709323
+ 4.175799513471913
+ 4.1758383367357395
+ 4.175877159500819
+ 4.175915981767169
+ 4.1759548035348075
+ 4.17599362480375
+ 4.176032445574017
+ 4.176071265845623
+ 4.176110085618586
+ 4.1761489048929255
+ 4.176187723668657
+ 4.176226541945797
+ 4.176265359724366
+ 4.176304177004378
+ 4.176342993785852
+ 4.176381810068805
+ 4.176420625853256
+ 4.17645944113922
+ 4.176498255926715
+ 4.176537070215758
+ 4.176575884006368
+ 4.176614697298563
+ 4.176653510092357
+ 4.17669232238777
+ 4.176731134184817
+ 4.176769945483519
+ 4.17680875628389
+ 4.176847566585949
+ 4.176886376389714
+ 4.1769251856952
+ 4.176963994502427
+ 4.177002802811411
+ 4.177041610622169
+ 4.177080417934718
+ 4.177119224749077
+ 4.177158031065264
+ 4.177196836883292
+ 4.177235642203183
+ 4.177274447024954
+ 4.177313251348618
+ 4.177352055174197
+ 4.177390858501707
+ 4.177429661331165
+ 4.177468463662588
+ 4.1775072654959935
+ 4.1775460668313995
+ 4.177584867668823
+ 4.177623668008281
+ 4.177662467849792
+ 4.177701267193371
+ 4.177740066039038
+ 4.177778864386809
+ 4.177817662236702
+ 4.1778564595887335
+ 4.1778952564429215
+ 4.177934052799282
+ 4.177972848657834
+ 4.178011644018594
+ 4.17805043888158
+ 4.178089233246809
+ 4.1781280271142975
+ 4.178166820484064
+ 4.178205613356126
+ 4.178244405730499
+ 4.178283197607202
+ 4.178321988986252
+ 4.178360779867667
+ 4.178399570251462
+ 4.178438360137657
+ 4.178477149526268
+ 4.178515938417313
+ 4.178554726810808
+ 4.178593514706772
+ 4.17863230210522
+ 4.178671089006172
+ 4.178709875409644
+ 4.1787486613156535
+ 4.178787446724217
+ 4.1788262316353535
+ 4.1788650160490795
+ 4.178903799965411
+ 4.178942583384367
+ 4.1789813663059645
+ 4.1790201487302205
+ 4.179058930657154
+ 4.179097712086779
+ 4.179136493019115
+ 4.179175273454179
+ 4.179214053391989
+ 4.17925283283256
+ 4.179291611775911
+ 4.17933039022206
+ 4.179369168171023
+ 4.179407945622819
+ 4.179446722577461
+ 4.179485499034971
+ 4.179524274995365
+ 4.17956305045866
+ 4.179601825424872
+ 4.179640599894021
+ 4.179679373866121
+ 4.179718147341193
+ 4.179756920319252
+ 4.179795692800315
+ 4.1798344647844
+ 4.179873236271525
+ 4.179912007261706
+ 4.179950777754961
+ 4.1799895477513065
+ 4.180028317250761
+ 4.180067086253342
+ 4.180105854759064
+ 4.180144622767947
+ 4.180183390280008
+ 4.180222157295264
+ 4.180260923813731
+ 4.1802996898354285
+ 4.180338455360372
+ 4.18037722038858
+ 4.180415984920069
+ 4.180454748954857
+ 4.180493512492959
+ 4.1805322755343965
+ 4.180571038079182
+ 4.180609800127337
+ 4.180648561678876
+ 4.180687322733817
+ 4.1807260832921775
+ 4.180764843353975
+ 4.180803602919227
+ 4.180842361987948
+ 4.1808811205601595
+ 4.180919878635876
+ 4.180958636215116
+ 4.180997393297894
+ 4.181036149884233
+ 4.181074905974144
+ 4.1811136615676485
+ 4.181152416664761
+ 4.181191171265501
+ 4.181229925369885
+ 4.18126867897793
+ 4.181307432089652
+ 4.181346184705071
+ 4.181384936824203
+ 4.1814236884470635
+ 4.181462439573672
+ 4.181501190204046
+ 4.181539940338201
+ 4.181578689976155
+ 4.181617439117925
+ 4.181656187763529
+ 4.181694935912985
+ 4.181733683566308
+ 4.181772430723515
+ 4.181811177384626
+ 4.181849923549656
+ 4.181888669218624
+ 4.181927414391545
+ 4.1819661590684385
+ 4.18200490324932
+ 4.182043646934207
+ 4.182082390123119
+ 4.18212113281607
+ 4.182159875013079
+ 4.182198616714162
+ 4.182237357919338
+ 4.182276098628623
+ 4.182314838842035
+ 4.1823535785595904
+ 4.182392317781307
+ 4.182431056507202
+ 4.182469794737292
+ 4.182508532471595
+ 4.182547269710128
+ 4.182586006452908
+ 4.182624742699952
+ 4.1826634784512775
+ 4.182702213706903
+ 4.182740948466843
+ 4.182779682731117
+ 4.1828184164997415
+ 4.182857149772733
+ 4.182895882550111
+ 4.182934614831889
+ 4.182973346618087
+ 4.183012077908722
+ 4.18305080870381
+ 4.18308953900337
+ 4.183128268807417
+ 4.18316699811597
+ 4.183205726929045
+ 4.183244455246661
+ 4.183283183068832
+ 4.183321910395579
+ 4.183360637226916
+ 4.183399363562863
+ 4.183438089403434
+ 4.183476814748649
+ 4.183515539598524
+ 4.183554263953077
+ 4.1835929878123235
+ 4.183631711176282
+ 4.183670434044969
+ 4.183709156418403
+ 4.183747878296601
+ 4.1837865996795776
+ 4.183825320567354
+ 4.183864040959943
+ 4.183902760857366
+ 4.183941480259637
+ 4.183980199166775
+ 4.184018917578796
+ 4.184057635495719
+ 4.184096352917559
+ 4.184135069844335
+ 4.184173786276063
+ 4.18421250221276
+ 4.184251217654445
+ 4.184289932601133
+ 4.184328647052843
+ 4.18436736100959
+ 4.184406074471393
+ 4.184444787438268
+ 4.184483499910234
+ 4.184522211887305
+ 4.184560923369503
+ 4.18459963435684
+ 4.184638344849337
+ 4.184677054847009
+ 4.184715764349874
+ 4.184754473357948
+ 4.1847931818712505
+ 4.1848318898897965
+ 4.184870597413604
+ 4.18490930444269
+ 4.184948010977073
+ 4.184986717016767
+ 4.185025422561792
+ 4.185064127612165
+ 4.185102832167902
+ 4.18514153622902
+ 4.185180239795537
+ 4.18521894286747
+ 4.185257645444837
+ 4.185296347527654
+ 4.185335049115937
+ 4.185373750209705
+ 4.185412450808975
+ 4.185451150913765
+ 4.185489850524089
+ 4.185528549639968
+ 4.185567248261416
+ 4.185605946388451
+ 4.1856446440210915
+ 4.185683341159353
+ 4.185722037803253
+ 4.18576073395281
+ 4.18579942960804
+ 4.185838124768961
+ 4.185876819435588
+ 4.18591551360794
+ 4.185954207286033
+ 4.185992900469886
+ 4.186031593159514
+ 4.186070285354936
+ 4.1861089770561675
+ 4.186147668263227
+ 4.186186358976131
+ 4.186225049194896
+ 4.18626373891954
+ 4.1863024281500785
+ 4.186341116886532
+ 4.186379805128915
+ 4.1864184928772445
+ 4.18645718013154
+ 4.186495866891816
+ 4.18653455315809
+ 4.1865732389303805
+ 4.186611924208704
+ 4.186650608993077
+ 4.186689293283517
+ 4.186727977080042
+ 4.186766660382668
+ 4.186805343191412
+ 4.186844025506292
+ 4.1868827073273245
+ 4.186921388654526
+ 4.186960069487916
+ 4.186998749827509
+ 4.187037429673324
+ 4.187076109025376
+ 4.187114787883684
+ 4.1871534662482635
+ 4.187192144119133
+ 4.1872308214963105
+ 4.187269498379811
+ 4.187308174769651
+ 4.18734685066585
+ 4.187385526068425
+ 4.18742420097739
+ 4.187462875392766
+ 4.187501549314568
+ 4.187540222742814
+ 4.18757889567752
+ 4.187617568118704
+ 4.1876562400663815
+ 4.187694911520572
+ 4.1877335824812905
+ 4.187772252948556
+ 4.1878109229223845
+ 4.1878495924027925
+ 4.187888261389799
+ 4.187926929883419
+ 4.18796559788367
+ 4.188004265390571
+ 4.1880429324041355
+ 4.188081598924384
+ 4.1881202649513325
+ 4.188158930484998
+ 4.188197595525398
+ 4.188236260072547
+ 4.188274924126466
+ 4.188313587687169
+ 4.188352250754675
+ 4.188390913329
+ 4.1884295754101615
+ 4.188468236998177
+ 4.1885068980930615
+ 4.188545558694835
+ 4.188584218803513
+ 4.188622878419114
+ 4.188661537541652
+ 4.188700196171147
+ 4.188738854307614
+ 4.188777511951071
+ 4.1888161691015355
+ 4.188854825759026
+ 4.1888934819235555
+ 4.188932137595144
+ 4.188970792773808
+ 4.189009447459564
+ 4.189048101652429
+ 4.189086755352422
+ 4.189125408559558
+ 4.189164061273854
+ 4.189202713495329
+ 4.189241365223999
+ 4.189280016459879
+ 4.189318667202989
+ 4.189357317453345
+ 4.189395967210963
+ 4.189434616475863
+ 4.189473265248059
+ 4.189511913527569
+ 4.18955056131441
+ 4.189589208608599
+ 4.189627855410154
+ 4.189666501719091
+ 4.189705147535427
+ 4.18974379285918
+ 4.189782437690367
+ 4.189821082029003
+ 4.189859725875108
+ 4.189898369228696
+ 4.189937012089787
+ 4.189975654458396
+ 4.1900142963345415
+ 4.190052937718239
+ 4.190091578609506
+ 4.19013021900836
+ 4.190168858914817
+ 4.190207498328896
+ 4.190246137250613
+ 4.190284775679984
+ 4.190323413617028
+ 4.19036205106176
+ 4.190400688014199
+ 4.19043932447436
+ 4.190477960442261
+ 4.190516595917919
+ 4.190555230901351
+ 4.190593865392575
+ 4.190632499391607
+ 4.190671132898464
+ 4.190709765913163
+ 4.190748398435721
+ 4.190787030466155
+ 4.190825662004483
+ 4.19086429305072
+ 4.1909029236048845
+ 4.1909415536669945
+ 4.190980183237064
+ 4.1910188123151135
+ 4.191057440901157
+ 4.191096068995214
+ 4.191134696597299
+ 4.191173323707431
+ 4.191211950325626
+ 4.1912505764519015
+ 4.191289202086274
+ 4.191327827228761
+ 4.19136645187938
+ 4.191405076038146
+ 4.1914436997050775
+ 4.1914823228801925
+ 4.191520945563505
+ 4.191559567755036
+ 4.1915981894547985
+ 4.191636810662812
+ 4.191675431379093
+ 4.191714051603658
+ 4.191752671336525
+ 4.19179129057771
+ 4.19182990932723
+ 4.191868527585102
+ 4.191907145351343
+ 4.191945762625971
+ 4.191984379409002
+ 4.1920229957004524
+ 4.192061611500341
+ 4.192100226808683
+ 4.192138841625497
+ 4.192177455950798
+ 4.192216069784606
+ 4.192254683126935
+ 4.1922932959778025
+ 4.192331908337226
+ 4.192370520205223
+ 4.192409131581811
+ 4.192447742467005
+ 4.192486352860822
+ 4.192524962763281
+ 4.192563572174399
+ 4.192602181094189
+ 4.192640789522674
+ 4.192679397459866
+ 4.192718004905784
+ 4.192756611860445
+ 4.192795218323866
+ 4.192833824296063
+ 4.192872429777053
+ 4.192911034766856
+ 4.192949639265485
+ 4.192988243272958
+ 4.1930268467892935
+ 4.193065449814507
+ 4.193104052348615
+ 4.193142654391638
+ 4.193181255943587
+ 4.193219857004485
+ 4.193258457574345
+ 4.193297057653186
+ 4.193335657241023
+ 4.193374256337875
+ 4.193412854943757
+ 4.193451453058688
+ 4.1934900506826835
+ 4.193528647815761
+ 4.193567244457937
+ 4.19360584060923
+ 4.193644436269655
+ 4.193683031439229
+ 4.19372162611797
+ 4.193760220305895
+ 4.19379881400302
+ 4.1938374072093625
+ 4.19387599992494
+ 4.193914592149769
+ 4.193953183883866
+ 4.193991775127247
+ 4.194030365879931
+ 4.194068956141934
+ 4.1941075459132735
+ 4.194146135193966
+ 4.194184723984028
+ 4.194223312283476
+ 4.194261900092329
+ 4.194300487410602
+ 4.194339074238313
+ 4.194377660575478
+ 4.194416246422115
+ 4.1944548317782395
+ 4.194493416643869
+ 4.194532001019023
+ 4.194570584903714
+ 4.194609168297962
+ 4.194647751201783
+ 4.194686333615193
+ 4.1947249155382105
+ 4.194763496970852
+ 4.194802077913133
+ 4.194840658365073
+ 4.1948792383266875
+ 4.194917817797992
+ 4.194956396779006
+ 4.194994975269744
+ 4.195033553270226
+ 4.195072130780466
+ 4.195110707800482
+ 4.195149284330291
+ 4.195187860369909
+ 4.195226435919355
+ 4.195265010978644
+ 4.195303585547793
+ 4.19534215962682
+ 4.195380733215741
+ 4.195419306314574
+ 4.195457878923334
+ 4.19549645104204
+ 4.195535022670707
+ 4.195573593809353
+ 4.1956121644579945
+ 4.19565073461665
+ 4.195689304285333
+ 4.1957278734640635
+ 4.195766442152856
+ 4.19580501035173
+ 4.1958435780607015
+ 4.195882145279786
+ 4.195920712009001
+ 4.195959278248364
+ 4.195997843997892
+ 4.1960364092576015
+ 4.19607497402751
+ 4.196113538307633
+ 4.1961521020979875
+ 4.196190665398591
+ 4.196229228209461
+ 4.196267790530614
+ 4.196306352362067
+ 4.196344913703836
+ 4.1963834745559385
+ 4.196422034918392
+ 4.196460594791211
+ 4.196499154174416
+ 4.196537713068021
+ 4.196576271472044
+ 4.196614829386501
+ 4.196653386811411
+ 4.196691943746788
+ 4.1967305001926505
+ 4.196769056149016
+ 4.1968076116159
+ 4.196846166593319
+ 4.196884721081291
+ 4.1969232750798335
+ 4.196961828588963
+ 4.197000381608695
+ 4.197038934139047
+ 4.197077486180037
+ 4.197116037731679
+ 4.197154588793993
+ 4.197193139366996
+ 4.197231689450701
+ 4.197270239045129
+ 4.197308788150295
+ 4.197347336766216
+ 4.197385884892908
+ 4.19742443253039
+ 4.1974629796786775
+ 4.197501526337787
+ 4.197540072507736
+ 4.197578618188541
+ 4.19761716338022
+ 4.197655708082787
+ 4.197694252296262
+ 4.197732796020661
+ 4.197771339255999
+ 4.1978098820022955
+ 4.197848424259566
+ 4.197886966027827
+ 4.197925507307096
+ 4.197964048097388
+ 4.198002588398723
+ 4.198041128211117
+ 4.198079667534585
+ 4.198118206369146
+ 4.198156744714814
+ 4.198195282571609
+ 4.198233819939546
+ 4.198272356818642
+ 4.198310893208915
+ 4.1983494291103804
+ 4.1983879645230555
+ 4.198426499446957
+ 4.198465033882103
+ 4.198503567828509
+ 4.198542101286191
+ 4.198580634255167
+ 4.198619166735455
+ 4.19865769872707
+ 4.19869623023003
+ 4.198734761244349
+ 4.198773291770047
+ 4.198811821807141
+ 4.198850351355645
+ 4.198888880415579
+ 4.1989274089869575
+ 4.198965937069798
+ 4.199004464664117
+ 4.199042991769933
+ 4.199081518387262
+ 4.1991200445161185
+ 4.199158570156522
+ 4.199197095308488
+ 4.199235619972034
+ 4.199274144147177
+ 4.199312667833933
+ 4.199351191032319
+ 4.199389713742352
+ 4.199428235964049
+ 4.199466757697428
+ 4.199505278942502
+ 4.199543799699291
+ 4.199582319967812
+ 4.199620839748079
+ 4.199659359040113
+ 4.199697877843926
+ 4.199736396159539
+ 4.199774913986966
+ 4.199813431326224
+ 4.199851948177331
+ 4.199890464540305
+ 4.19992898041516
+ 4.199967495801914
+ 4.200006010700584
+ 4.200044525111186
+ 4.2000830390337365
+ 4.200121552468255
+ 4.200160065414756
+ 4.200198577873255
+ 4.200237089843772
+ 4.2002756013263225
+ 4.200314112320922
+ 4.200352622827588
+ 4.200391132846338
+ 4.200429642377189
+ 4.200468151420157
+ 4.200506659975257
+ 4.2005451680425105
+ 4.200583675621931
+ 4.200622182713534
+ 4.200660689317339
+ 4.200699195433362
+ 4.20073770106162
+ 4.200776206202127
+ 4.200814710854904
+ 4.200853215019966
+ 4.200891718697329
+ 4.20093022188701
+ 4.200968724589027
+ 4.201007226803395
+ 4.201045728530133
+ 4.201084229769255
+ 4.20112273052078
+ 4.201161230784724
+ 4.201199730561104
+ 4.201238229849935
+ 4.201276728651237
+ 4.201315226965024
+ 4.201353724791314
+ 4.201392222130123
+ 4.201430718981469
+ 4.201469215345368
+ 4.201507711221836
+ 4.2015462066108915
+ 4.201584701512551
+ 4.201623195926828
+ 4.2016616898537436
+ 4.201700183293313
+ 4.201738676245552
+ 4.2017771687104775
+ 4.201815660688108
+ 4.201854152178457
+ 4.201892643181544
+ 4.201931133697386
+ 4.201969623725998
+ 4.202008113267397
+ 4.202046602321602
+ 4.202085090888626
+ 4.2021235789684885
+ 4.202162066561206
+ 4.202200553666793
+ 4.202239040285269
+ 4.202277526416649
+ 4.202316012060952
+ 4.202354497218192
+ 4.202392981888386
+ 4.202431466071553
+ 4.202469949767707
+ 4.202508432976866
+ 4.202546915699048
+ 4.202585397934268
+ 4.202623879682542
+ 4.202662360943889
+ 4.2027008417183245
+ 4.202739322005866
+ 4.202777801806528
+ 4.20281628112033
+ 4.202854759947287
+ 4.202893238287416
+ 4.202931716140735
+ 4.202970193507259
+ 4.203008670387005
+ 4.203047146779991
+ 4.203085622686232
+ 4.203124098105745
+ 4.203162573038548
+ 4.203201047484658
+ 4.203239521444089
+ 4.20327799491686
+ 4.203316467902987
+ 4.203354940402487
+ 4.203393412415377
+ 4.203431883941672
+ 4.20347035498139
+ 4.203508825534548
+ 4.203547295601163
+ 4.203585765181249
+ 4.203624234274827
+ 4.20366270288191
+ 4.203701171002516
+ 4.203739638636663
+ 4.203778105784365
+ 4.203816572445642
+ 4.203855038620508
+ 4.20389350430898
+ 4.203931969511075
+ 4.203970434226811
+ 4.204008898456204
+ 4.204047362199269
+ 4.2040858254560245
+ 4.204124288226487
+ 4.204162750510673
+ 4.204201212308599
+ 4.2042396736202825
+ 4.204278134445738
+ 4.204316594784984
+ 4.204355054638038
+ 4.204393514004914
+ 4.204431972885631
+ 4.204470431280205
+ 4.204508889188653
+ 4.20454734661099
+ 4.204585803547235
+ 4.204624259997403
+ 4.204662715961511
+ 4.204701171439576
+ 4.204739626431616
+ 4.204778080937645
+ 4.204816534957681
+ 4.204854988491742
+ 4.204893441539841
+ 4.204931894101999
+ 4.2049703461782295
+ 4.20500879776855
+ 4.205047248872979
+ 4.20508569949153
+ 4.205124149624222
+ 4.205162599271071
+ 4.205201048432094
+ 4.205239497107307
+ 4.205277945296727
+ 4.20531639300037
+ 4.205354840218254
+ 4.205393286950395
+ 4.205431733196809
+ 4.205470178957514
+ 4.205508624232524
+ 4.2055470690218595
+ 4.205585513325535
+ 4.205623957143567
+ 4.205662400475973
+ 4.205700843322768
+ 4.205739285683971
+ 4.205777727559597
+ 4.205816168949663
+ 4.205854609854186
+ 4.205893050273182
+ 4.205931490206669
+ 4.205969929654661
+ 4.206008368617177
+ 4.206046807094233
+ 4.206085245085847
+ 4.2061236825920325
+ 4.2061621196128085
+ 4.2062005561481906
+ 4.206238992198197
+ 4.206277427762842
+ 4.2063158628421435
+ 4.2063542974361186
+ 4.206392731544784
+ 4.206431165168155
+ 4.206469598306248
+ 4.206508030959083
+ 4.2065464631266725
+ 4.206584894809035
+ 4.206623326006187
+ 4.2066617567181455
+ 4.206700186944927
+ 4.206738616686547
+ 4.206777045943023
+ 4.2068154747143724
+ 4.206853903000611
+ 4.206892330801755
+ 4.206930758117822
+ 4.206969184948827
+ 4.207007611294788
+ 4.207046037155722
+ 4.207084462531645
+ 4.207122887422573
+ 4.207161311828524
+ 4.207199735749513
+ 4.207238159185557
+ 4.207276582136674
+ 4.20731500460288
+ 4.20735342658419
+ 4.207391848080623
+ 4.207430269092193
+ 4.20746868961892
+ 4.207507109660817
+ 4.207545529217903
+ 4.2075839482901936
+ 4.207622366877707
+ 4.207660784980456
+ 4.207699202598461
+ 4.207737619731738
+ 4.207776036380302
+ 4.207814452544171
+ 4.207852868223362
+ 4.207891283417888
+ 4.207929698127771
+ 4.207968112353022
+ 4.208006526093663
+ 4.208044939349708
+ 4.2080833521211725
+ 4.208121764408075
+ 4.208160176210431
+ 4.2081985875282575
+ 4.208236998361571
+ 4.208275408710389
+ 4.208313818574726
+ 4.2083522279546
+ 4.2083906368500275
+ 4.208429045261025
+ 4.208467453187608
+ 4.208505860629796
+ 4.208544267587603
+ 4.208582674061046
+ 4.208621080050142
+ 4.208659485554907
+ 4.208697890575359
+ 4.208736295111513
+ 4.208774699163387
+ 4.208813102730995
+ 4.208851505814356
+ 4.208889908413487
+ 4.208928310528402
+ 4.20896671215912
+ 4.209005113305657
+ 4.209043513968028
+ 4.209081914146252
+ 4.2091203138403435
+ 4.20915871305032
+ 4.209197111776198
+ 4.209235510017994
+ 4.209273907775724
+ 4.209312305049406
+ 4.209350701839056
+ 4.209389098144689
+ 4.209427493966324
+ 4.209465889303975
+ 4.209504284157662
+ 4.209542678527398
+ 4.209581072413202
+ 4.209619465815089
+ 4.209657858733076
+ 4.20969625116718
+ 4.209734643117417
+ 4.2097730345838045
+ 4.2098114255663575
+ 4.209849816065094
+ 4.20988820608003
+ 4.209926595611182
+ 4.209964984658566
+ 4.210003373222199
+ 4.210041761302099
+ 4.21008014889828
+ 4.210118536010761
+ 4.210156922639556
+ 4.210195308784684
+ 4.21023369444616
+ 4.2102720796240005
+ 4.210310464318223
+ 4.2103488485288425
+ 4.2103872322558775
+ 4.210425615499343
+ 4.210463998259257
+ 4.210502380535634
+ 4.210540762328492
+ 4.2105791436378475
+ 4.210617524463717
+ 4.210655904806116
+ 4.210694284665062
+ 4.210732664040572
+ 4.210771042932662
+ 4.210809421341348
+ 4.210847799266647
+ 4.210886176708574
+ 4.210924553667148
+ 4.210962930142385
+ 4.211001306134301
+ 4.211039681642911
+ 4.211078056668235
+ 4.211116431210288
+ 4.211154805269084
+ 4.211193178844643
+ 4.211231551936979
+ 4.2112699245461105
+ 4.211308296672053
+ 4.211346668314823
+ 4.211385039474437
+ 4.211423410150912
+ 4.211461780344265
+ 4.21150015005451
+ 4.211538519281667
+ 4.21157688802575
+ 4.211615256286775
+ 4.211653624064762
+ 4.211691991359723
+ 4.211730358171678
+ 4.211768724500643
+ 4.211807090346633
+ 4.211845455709665
+ 4.211883820589756
+ 4.211922184986922
+ 4.211960548901181
+ 4.211998912332547
+ 4.2120372752810376
+ 4.21207563774667
+ 4.21211399972946
+ 4.212152361229425
+ 4.2121907222465795
+ 4.212229082780943
+ 4.212267442832529
+ 4.212305802401354
+ 4.212344161487438
+ 4.212382520090794
+ 4.21242087821144
+ 4.212459235849392
+ 4.212497593004667
+ 4.212535949677281
+ 4.212574305867251
+ 4.2126126615745925
+ 4.212651016799323
+ 4.212689371541458
+ 4.212727725801016
+ 4.21276607957801
+ 4.212804432872459
+ 4.21284278568438
+ 4.212881138013789
+ 4.2129194898607
+ 4.2129578412251325
+ 4.212996192107102
+ 4.213034542506626
+ 4.2130728924237175
+ 4.213111241858397
+ 4.213149590810679
+ 4.21318793928058
+ 4.2132262872681165
+ 4.213264634773306
+ 4.213302981796164
+ 4.213341328336707
+ 4.21337967439495
+ 4.213418019970913
+ 4.21345636506461
+ 4.213494709676058
+ 4.213533053805274
+ 4.213571397452273
+ 4.213609740617073
+ 4.21364808329969
+ 4.21368642550014
+ 4.213724767218439
+ 4.213763108454606
+ 4.213801449208654
+ 4.213839789480602
+ 4.213878129270466
+ 4.213916468578261
+ 4.213954807404005
+ 4.213993145747713
+ 4.214031483609404
+ 4.214069820989091
+ 4.214108157886794
+ 4.214146494302527
+ 4.214184830236307
+ 4.214223165688152
+ 4.214261500658075
+ 4.214299835146096
+ 4.214338169152229
+ 4.214376502676491
+ 4.2144148357189
+ 4.21445316827947
+ 4.21449150035822
+ 4.214529831955165
+ 4.214568163070321
+ 4.214606493703706
+ 4.214644823855334
+ 4.2146831535252245
+ 4.214721482713391
+ 4.214759811419851
+ 4.214798139644623
+ 4.2148364673877206
+ 4.214874794649161
+ 4.214913121428961
+ 4.214951447727137
+ 4.214989773543705
+ 4.215028098878682
+ 4.215066423732084
+ 4.215104748103929
+ 4.21514307199423
+ 4.215181395403007
+ 4.215219718330275
+ 4.215258040776049
+ 4.2152963627403475
+ 4.215334684223186
+ 4.215373005224581
+ 4.215411325744548
+ 4.215449645783106
+ 4.215487965340269
+ 4.215526284416054
+ 4.2155646030104785
+ 4.2156029211235575
+ 4.215641238755308
+ 4.215679555905747
+ 4.215717872574889
+ 4.215756188762753
+ 4.215794504469353
+ 4.215832819694707
+ 4.215871134438831
+ 4.2159094487017414
+ 4.215947762483454
+ 4.215986075783986
+ 4.216024388603353
+ 4.216062700941572
+ 4.21610101279866
+ 4.216139324174633
+ 4.216177635069507
+ 4.216215945483297
+ 4.216254255416023
+ 4.2162925648676985
+ 4.2163308738383405
+ 4.216369182327965
+ 4.21640749033659
+ 4.216445797864231
+ 4.216484104910903
+ 4.216522411476625
+ 4.2165607175614115
+ 4.216599023165279
+ 4.216637328288245
+ 4.216675632930325
+ 4.216713937091536
+ 4.216752240771894
+ 4.216790543971415
+ 4.216828846690116
+ 4.216867148928013
+ 4.216905450685122
+ 4.21694375196146
+ 4.216982052757045
+ 4.21702035307189
+ 4.217058652906013
+ 4.217096952259431
+ 4.217135251132159
+ 4.217173549524214
+ 4.217211847435614
+ 4.217250144866373
+ 4.2172884418165095
+ 4.2173267382860375
+ 4.217365034274975
+ 4.217403329783337
+ 4.2174416248111415
+ 4.2174799193584045
+ 4.217518213425141
+ 4.217556507011369
+ 4.217594800117104
+ 4.217633092742362
+ 4.217671384887161
+ 4.217709676551516
+ 4.217747967735444
+ 4.21778625843896
+ 4.217824548662082
+ 4.217862838404827
+ 4.21790112766721
+ 4.217939416449245
+ 4.217977704750953
+ 4.218015992572347
+ 4.218054279913446
+ 4.2180925667742635
+ 4.218130853154817
+ 4.218169139055125
+ 4.2182074244752
+ 4.218245709415061
+ 4.218283993874724
+ 4.218322277854205
+ 4.21836056135352
+ 4.218398844372686
+ 4.218437126911719
+ 4.218475408970635
+ 4.218513690549451
+ 4.218551971648183
+ 4.218590252266847
+ 4.218628532405461
+ 4.218666812064039
+ 4.218705091242598
+ 4.218743369941156
+ 4.218781648159728
+ 4.218819925898329
+ 4.218858203156978
+ 4.21889647993569
+ 4.218934756234482
+ 4.218973032053369
+ 4.219011307392368
+ 4.219049582251495
+ 4.219087856630768
+ 4.219126130530201
+ 4.219164403949812
+ 4.219202676889617
+ 4.219240949349632
+ 4.219279221329873
+ 4.219317492830357
+ 4.2193557638511
+ 4.219394034392118
+ 4.219432304453428
+ 4.2194705740350456
+ 4.219508843136988
+ 4.2195471117592716
+ 4.219585379901911
+ 4.219623647564925
+ 4.219661914748327
+ 4.219700181452136
+ 4.2197384476763675
+ 4.219776713421036
+ 4.219814978686161
+ 4.219853243471756
+ 4.219891507777839
+ 4.219929771604426
+ 4.219968034951533
+ 4.220006297819176
+ 4.220044560207373
+ 4.2200828221161375
+ 4.220121083545488
+ 4.22015934449544
+ 4.2201976049660095
+ 4.220235864957214
+ 4.220274124469069
+ 4.22031238350159
+ 4.220350642054795
+ 4.2203889001286985
+ 4.220427157723319
+ 4.220465414838671
+ 4.220503671474771
+ 4.220541927631636
+ 4.2205801833092815
+ 4.220618438507724
+ 4.220656693226982
+ 4.220694947467067
+ 4.220733201228
+ 4.220771454509794
+ 4.220809707312467
+ 4.220847959636036
+ 4.220886211480515
+ 4.220924462845923
+ 4.220962713732273
+ 4.221000964139584
+ 4.221039214067871
+ 4.221077463517152
+ 4.221115712487441
+ 4.2211539609787545
+ 4.221192208991111
+ 4.221230456524524
+ 4.221268703579011
+ 4.221306950154589
+ 4.221345196251274
+ 4.221383441869081
+ 4.221421687008029
+ 4.22145993166813
+ 4.221498175849404
+ 4.221536419551866
+ 4.221574662775531
+ 4.221612905520417
+ 4.221651147786541
+ 4.221689389573917
+ 4.221727630882563
+ 4.221765871712494
+ 4.221804112063727
+ 4.221842351936278
+ 4.221880591330164
+ 4.2219188302454
+ 4.221957068682003
+ 4.22199530663999
+ 4.222033544119375
+ 4.222071781120176
+ 4.222110017642409
+ 4.2221482536860915
+ 4.222186489251237
+ 4.222224724337864
+ 4.222262958945987
+ 4.222301193075625
+ 4.2223394267267915
+ 4.222377659899504
+ 4.222415892593777
+ 4.22245412480963
+ 4.222492356547076
+ 4.222530587806134
+ 4.222568818586819
+ 4.222607048889147
+ 4.222645278713134
+ 4.222683508058797
+ 4.222721736926151
+ 4.222759965315215
+ 4.222798193226003
+ 4.222836420658531
+ 4.222874647612817
+ 4.222912874088874
+ 4.222951100086723
+ 4.222989325606376
+ 4.223027550647851
+ 4.223065775211165
+ 4.223103999296333
+ 4.223142222903371
+ 4.223180446032296
+ 4.223218668683124
+ 4.223256890855871
+ 4.223295112550554
+ 4.22333333376719
+ 4.223371554505792
+ 4.223409774766379
+ 4.223447994548966
+ 4.22348621385357
+ 4.223524432680207
+ 4.223562651028893
+ 4.223600868899644
+ 4.2236390862924775
+ 4.223677303207407
+ 4.223715519644452
+ 4.223753735603626
+ 4.223791951084948
+ 4.223830166088431
+ 4.223868380614094
+ 4.223906594661952
+ 4.223944808232021
+ 4.223983021324317
+ 4.224021233938857
+ 4.224059446075658
+ 4.224097657734735
+ 4.224135868916103
+ 4.22417407961978
+ 4.224212289845782
+ 4.224250499594125
+ 4.224288708864825
+ 4.224326917657899
+ 4.224365125973362
+ 4.224403333811231
+ 4.2244415411715215
+ 4.224479748054251
+ 4.224517954459434
+ 4.224556160387088
+ 4.224594365837229
+ 4.224632570809873
+ 4.224670775305036
+ 4.224708979322735
+ 4.224747182862985
+ 4.224785385925803
+ 4.224823588511205
+ 4.224861790619207
+ 4.224899992249825
+ 4.2249381934030765
+ 4.2249763940789755
+ 4.225014594277542
+ 4.2250527939987865
+ 4.22509099324273
+ 4.225129192009387
+ 4.225167390298773
+ 4.225205588110905
+ 4.2252437854458
+ 4.225281982303472
+ 4.225320178683939
+ 4.225358374587217
+ 4.225396570013322
+ 4.2254347649622686
+ 4.225472959434075
+ 4.225511153428758
+ 4.22554934694633
+ 4.225587539986812
+ 4.225625732550217
+ 4.225663924636562
+ 4.225702116245863
+ 4.225740307378136
+ 4.2257784980333986
+ 4.2258166882116655
+ 4.225854877912953
+ 4.225893067137278
+ 4.225931255884656
+ 4.225969444155103
+ 4.226007631948637
+ 4.226045819265271
+ 4.226084006105024
+ 4.226122192467911
+ 4.226160378353948
+ 4.226198563763151
+ 4.226236748695538
+ 4.226274933151122
+ 4.226313117129922
+ 4.226351300631952
+ 4.226389483657229
+ 4.226427666205771
+ 4.226465848277591
+ 4.226504029872707
+ 4.226542210991136
+ 4.226580391632892
+ 4.226618571797991
+ 4.226656751486452
+ 4.226694930698288
+ 4.226733109433518
+ 4.226771287692156
+ 4.226809465474219
+ 4.226847642779724
+ 4.226885819608684
+ 4.226923995961119
+ 4.226962171837043
+ 4.227000347236472
+ 4.2270385221594236
+ 4.227076696605912
+ 4.227114870575956
+ 4.227153044069569
+ 4.227191217086768
+ 4.2272293896275706
+ 4.227267561691991
+ 4.227305733280046
+ 4.227343904391752
+ 4.2273820750271245
+ 4.227420245186181
+ 4.227458414868937
+ 4.227496584075408
+ 4.22753475280561
+ 4.227572921059559
+ 4.227611088837273
+ 4.227649256138767
+ 4.227687422964056
+ 4.227725589313158
+ 4.227763755186088
+ 4.227801920582862
+ 4.227840085503497
+ 4.2278782499480085
+ 4.227916413916414
+ 4.227954577408727
+ 4.227992740424965
+ 4.228030902965145
+ 4.228069065029281
+ 4.228107226617391
+ 4.22814538772949
+ 4.228183548365595
+ 4.228221708525721
+ 4.228259868209887
+ 4.228298027418105
+ 4.228336186150393
+ 4.2283743444067685
+ 4.228412502187245
+ 4.22845065949184
+ 4.228488816320571
+ 4.228526972673452
+ 4.228565128550499
+ 4.228603283951728
+ 4.228641438877157
+ 4.2286795933268015
+ 4.228717747300677
+ 4.228755900798799
+ 4.228794053821185
+ 4.22883220636785
+ 4.22887035843881
+ 4.228908510034082
+ 4.228946661153682
+ 4.228984811797626
+ 4.22902296196593
+ 4.229061111658609
+ 4.229099260875682
+ 4.22913740961716
+ 4.229175557883066
+ 4.229213705673409
+ 4.229251852988211
+ 4.229289999827484
+ 4.229328146191247
+ 4.229366292079514
+ 4.229404437492302
+ 4.229442582429627
+ 4.229480726891505
+ 4.2295188708779525
+ 4.229557014388984
+ 4.229595157424617
+ 4.229633299984868
+ 4.229671442069752
+ 4.229709583679286
+ 4.2297477248134845
+ 4.229785865472366
+ 4.229824005655945
+ 4.229862145364238
+ 4.229900284597259
+ 4.229938423355028
+ 4.2299765616375575
+ 4.230014699444867
+ 4.230052836776969
+ 4.230090973633882
+ 4.230129110015621
+ 4.230167245922202
+ 4.230205381353643
+ 4.230243516309957
+ 4.230281650791163
+ 4.230319784797275
+ 4.230357918328309
+ 4.230396051384282
+ 4.230434183965211
+ 4.2304723160711095
+ 4.230510447701996
+ 4.230548578857886
+ 4.230586709538794
+ 4.2306248397447375
+ 4.230662969475731
+ 4.230701098731793
+ 4.230739227512939
+ 4.230777355819184
+ 4.230815483650543
+ 4.230853611007035
+ 4.230891737888674
+ 4.230929864295478
+ 4.23096799022746
+ 4.231006115684638
+ 4.2310442406670274
+ 4.231082365174645
+ 4.231120489207507
+ 4.231158612765628
+ 4.231196735849026
+ 4.231234858457714
+ 4.2312729805917115
+ 4.231311102251033
+ 4.2313492234356955
+ 4.231387344145713
+ 4.231425464381103
+ 4.23146358414188
+ 4.231501703428063
+ 4.231539822239665
+ 4.231577940576704
+ 4.2316160584391955
+ 4.231654175827156
+ 4.2316922927406
+ 4.231730409179545
+ 4.231768525144007
+ 4.231806640634
+ 4.231844755649543
+ 4.231882870190649
+ 4.2319209842573375
+ 4.2319590978496215
+ 4.231997210967519
+ 4.232035323611044
+ 4.232073435780215
+ 4.232111547475046
+ 4.232149658695554
+ 4.232187769441756
+ 4.232225879713665
+ 4.2322639895113
+ 4.232302098834675
+ 4.232340207683808
+ 4.232378316058713
+ 4.232416423959408
+ 4.2324545313859065
+ 4.232492638338226
+ 4.232530744816384
+ 4.232568850820394
+ 4.232606956350272
+ 4.232645061406037
+ 4.2326831659877024
+ 4.2327212700952845
+ 4.2327593737288005
+ 4.232797476888264
+ 4.232835579573694
+ 4.232873681785104
+ 4.232911783522512
+ 4.232949884785933
+ 4.232987985575382
+ 4.233026085890877
+ 4.233064185732434
+ 4.233102285100067
+ 4.233140383993793
+ 4.233178482413628
+ 4.2332165803595885
+ 4.23325467783169
+ 4.233292774829948
+ 4.233330871354379
+ 4.233368967405001
+ 4.233407062981827
+ 4.233445158084874
+ 4.233483252714158
+ 4.233521346869694
+ 4.2335594405515
+ 4.233597533759592
+ 4.233635626493983
+ 4.233673718754693
+ 4.233711810541735
+ 4.233749901855126
+ 4.233787992694882
+ 4.233826083061019
+ 4.233864172953553
+ 4.2339022623725
+ 4.233940351317876
+ 4.233978439789697
+ 4.234016527787978
+ 4.234054615312737
+ 4.234092702363989
+ 4.234130788941748
+ 4.2341688750460325
+ 4.234206960676858
+ 4.234245045834241
+ 4.234283130518196
+ 4.23432121472874
+ 4.234359298465889
+ 4.234397381729657
+ 4.234435464520063
+ 4.234473546837122
+ 4.234511628680849
+ 4.234549710051259
+ 4.234587790948371
+ 4.2346258713722
+ 4.2346639513227595
+ 4.234702030800069
+ 4.234740109804142
+ 4.234778188334997
+ 4.234816266392646
+ 4.2348543439771085
+ 4.234892421088398
+ 4.234930497726533
+ 4.2349685738915275
+ 4.235006649583398
+ 4.235044724802161
+ 4.235082799547831
+ 4.235120873820426
+ 4.23515894761996
+ 4.23519702094645
+ 4.235235093799911
+ 4.235273166180362
+ 4.2353112380878155
+ 4.235349309522288
+ 4.235387380483797
+ 4.235425450972357
+ 4.235463520987984
+ 4.235501590530696
+ 4.235539659600505
+ 4.235577728197431
+ 4.235615796321488
+ 4.235653863972693
+ 4.2356919311510595
+ 4.235729997856605
+ 4.235768064089347
+ 4.2358061298493
+ 4.23584419513648
+ 4.235882259950901
+ 4.235920324292582
+ 4.235958388161538
+ 4.235996451557783
+ 4.236034514481337
+ 4.236072576932212
+ 4.236110638910426
+ 4.236148700415994
+ 4.2361867614489315
+ 4.236224822009257
+ 4.236262882096983
+ 4.236300941712129
+ 4.2363390008547075
+ 4.236377059524736
+ 4.236415117722231
+ 4.236453175447208
+ 4.236491232699682
+ 4.2365292894796704
+ 4.236567345787187
+ 4.23660540162225
+ 4.236643456984875
+ 4.236681511875076
+ 4.236719566292871
+ 4.236757620238275
+ 4.2367956737113035
+ 4.236833726711974
+ 4.2368717792403014
+ 4.236909831296301
+ 4.23694788287999
+ 4.236985933991383
+ 4.237023984630496
+ 4.237062034797347
+ 4.237100084491949
+ 4.23713813371432
+ 4.237176182464475
+ 4.23721423074243
+ 4.237252278548202
+ 4.237290325881804
+ 4.237328372743256
+ 4.23736641913257
+ 4.237404465049765
+ 4.237442510494854
+ 4.237480555467855
+ 4.237518599968784
+ 4.237556643997655
+ 4.237594687554486
+ 4.237632730639292
+ 4.237670773252089
+ 4.2377088153928915
+ 4.237746857061718
+ 4.237784898258583
+ 4.237822938983502
+ 4.237860979236491
+ 4.237899019017568
+ 4.237937058326745
+ 4.237975097164041
+ 4.238013135529472
+ 4.2380511734230515
+ 4.238089210844796
+ 4.238127247794724
+ 4.238165284272848
+ 4.238203320279187
+ 4.238241355813754
+ 4.238279390876566
+ 4.238317425467639
+ 4.23835545958699
+ 4.238393493234632
+ 4.238431526410584
+ 4.2384695591148605
+ 4.238507591347477
+ 4.23854562310845
+ 4.238583654397795
+ 4.238621685215528
+ 4.238659715561665
+ 4.238697745436221
+ 4.238735774839214
+ 4.238773803770658
+ 4.23881183223057
+ 4.238849860218964
+ 4.238887887735858
+ 4.238925914781266
+ 4.238963941355206
+ 4.239001967457693
+ 4.239039993088742
+ 4.239078018248368
+ 4.2391160429365895
+ 4.239154067153422
+ 4.23919209089888
+ 4.23923011417298
+ 4.2392681369757375
+ 4.239306159307168
+ 4.239344181167288
+ 4.239382202556115
+ 4.239420223473662
+ 4.239458243919946
+ 4.239496263894983
+ 4.239534283398789
+ 4.239572302431379
+ 4.239610320992771
+ 4.239648339082978
+ 4.239686356702017
+ 4.239724373849905
+ 4.239762390526655
+ 4.239800406732287
+ 4.239838422466812
+ 4.239876437730251
+ 4.2399144525226165
+ 4.239952466843924
+ 4.239990480694192
+ 4.240028494073433
+ 4.240066506981666
+ 4.240104519418905
+ 4.240142531385167
+ 4.2401805428804655
+ 4.240218553904819
+ 4.240256564458242
+ 4.240294574540751
+ 4.240332584152362
+ 4.24037059329309
+ 4.240408601962951
+ 4.24044661016196
+ 4.240484617890134
+ 4.24052262514749
+ 4.240560631934041
+ 4.240598638249805
+ 4.240636644094798
+ 4.2406746494690335
+ 4.24071265437253
+ 4.2407506588053
+ 4.240788662767364
+ 4.240826666258735
+ 4.240864669279428
+ 4.240902671829459
+ 4.240940673908846
+ 4.240978675517604
+ 4.2410166766557476
+ 4.2410546773232936
+ 4.241092677520258
+ 4.241130677246655
+ 4.241168676502503
+ 4.241206675287816
+ 4.24124467360261
+ 4.241282671446902
+ 4.2413206688207055
+ 4.2413586657240385
+ 4.241396662156916
+ 4.241434658119354
+ 4.241472653611367
+ 4.241510648632973
+ 4.241548643184186
+ 4.241586637265023
+ 4.241624630875499
+ 4.241662624015632
+ 4.241700616685434
+ 4.241738608884924
+ 4.241776600614115
+ 4.241814591873025
+ 4.24185258266167
+ 4.241890572980064
+ 4.241928562828225
+ 4.241966552206167
+ 4.242004541113906
+ 4.242042529551458
+ 4.242080517518839
+ 4.242118505016065
+ 4.242156492043152
+ 4.242194478600115
+ 4.242232464686969
+ 4.242270450303733
+ 4.242308435450419
+ 4.242346420127046
+ 4.242384404333627
+ 4.24242238807018
+ 4.24246037133672
+ 4.242498354133262
+ 4.242536336459823
+ 4.242574318316417
+ 4.242612299703063
+ 4.242650280619773
+ 4.242688261066565
+ 4.242726241043454
+ 4.242764220550457
+ 4.242802199587589
+ 4.242840178154865
+ 4.242878156252302
+ 4.242916133879914
+ 4.24295411103772
+ 4.2429920877257326
+ 4.243030063943969
+ 4.243068039692445
+ 4.2431060149711755
+ 4.243143989780178
+ 4.243181964119466
+ 4.243219937989057
+ 4.243257911388965
+ 4.243295884319209
+ 4.243333856779802
+ 4.243371828770759
+ 4.243409800292098
+ 4.243447771343836
+ 4.243485741925984
+ 4.243523712038562
+ 4.243561681681585
+ 4.243599650855066
+ 4.243637619559024
+ 4.243675587793474
+ 4.243713555558431
+ 4.243751522853911
+ 4.24378948967993
+ 4.243827456036503
+ 4.243865421923648
+ 4.243903387341376
+ 4.243941352289709
+ 4.243979316768659
+ 4.244017280778242
+ 4.244055244318474
+ 4.244093207389371
+ 4.244131169990948
+ 4.244169132123222
+ 4.2442070937862075
+ 4.244245054979921
+ 4.244283015704379
+ 4.244320975959597
+ 4.244358935745589
+ 4.244396895062372
+ 4.244434853909961
+ 4.244472812288373
+ 4.244510770197622
+ 4.244548727637726
+ 4.244586684608699
+ 4.2446246411105575
+ 4.244662597143318
+ 4.244700552706994
+ 4.244738507801602
+ 4.244776462427159
+ 4.24481441658368
+ 4.244852370271182
+ 4.2448903234896775
+ 4.244928276239184
+ 4.2449662285197185
+ 4.2450041803312955
+ 4.24504213167393
+ 4.24508008254764
+ 4.245118032952438
+ 4.245155982888344
+ 4.245193932355369
+ 4.245231881353531
+ 4.245269829882846
+ 4.245307777943331
+ 4.245345725534998
+ 4.245383672657866
+ 4.24542161931195
+ 4.245459565497264
+ 4.245497511213826
+ 4.245535456461651
+ 4.245573401240753
+ 4.24561134555115
+ 4.245649289392857
+ 4.245687232765889
+ 4.245725175670263
+ 4.2457631181059945
+ 4.245801060073098
+ 4.245839001571589
+ 4.245876942601486
+ 4.2459148831628015
+ 4.245952823255553
+ 4.245990762879756
+ 4.246028702035425
+ 4.246066640722577
+ 4.246104578941228
+ 4.2461425166913935
+ 4.246180453973088
+ 4.2462183907863285
+ 4.24625632713113
+ 4.246294263007508
+ 4.2463321984154785
+ 4.246370133355057
+ 4.246408067826261
+ 4.246446001829104
+ 4.246483935363601
+ 4.24652186842977
+ 4.246559801027627
+ 4.246597733157185
+ 4.246635664818462
+ 4.2466735960114725
+ 4.246711526736232
+ 4.246749456992757
+ 4.2467873867810635
+ 4.246825316101166
+ 4.24686324495308
+ 4.246901173336823
+ 4.246939101252409
+ 4.246977028699855
+ 4.247014955679176
+ 4.247052882190388
+ 4.247090808233507
+ 4.2471287338085455
+ 4.247166658915524
+ 4.247204583554455
+ 4.247242507725355
+ 4.247280431428241
+ 4.247318354663126
+ 4.247356277430027
+ 4.247394199728961
+ 4.247432121559942
+ 4.247470042922986
+ 4.247507963818109
+ 4.247545884245326
+ 4.247583804204654
+ 4.247621723696107
+ 4.247659642719702
+ 4.247697561275454
+ 4.247735479363378
+ 4.247773396983492
+ 4.24781131413581
+ 4.247849230820347
+ 4.24788714703712
+ 4.247925062786144
+ 4.247962978067434
+ 4.2480008928810085
+ 4.24803880722688
+ 4.248076721105066
+ 4.24811463451558
+ 4.24815254745844
+ 4.248190459933661
+ 4.2482283719412575
+ 4.2482662834812475
+ 4.248304194553644
+ 4.248342105158464
+ 4.248380015295724
+ 4.2484179249654375
+ 4.248455834167622
+ 4.248493742902292
+ 4.248531651169465
+ 4.248569558969154
+ 4.248607466301376
+ 4.2486453731661475
+ 4.248683279563482
+ 4.248721185493398
+ 4.248759090955908
+ 4.2487969959510306
+ 4.248834900478779
+ 4.248872804539169
+ 4.248910708132219
+ 4.2489486112579415
+ 4.248986513916353
+ 4.2490244161074715
+ 4.249062317831309
+ 4.249100219087883
+ 4.24913811987721
+ 4.249176020199303
+ 4.24921392005418
+ 4.249251819441856
+ 4.249289718362346
+ 4.249327616815665
+ 4.2493655148018314
+ 4.249403412320859
+ 4.249441309372764
+ 4.24947920595756
+ 4.249517102075266
+ 4.249554997725895
+ 4.249592892909463
+ 4.2496307876259864
+ 4.24966868187548
+ 4.249706575657961
+ 4.249744468973444
+ 4.249782361821945
+ 4.2498202542034775
+ 4.24985814611806
+ 4.249896037565706
+ 4.249933928546433
+ 4.249971819060256
+ 4.250009709107189
+ 4.25004759868725
+ 4.250085487800453
+ 4.2501233764468145
+ 4.25016126462635
+ 4.250199152339074
+ 4.250237039585003
+ 4.2502749263641535
+ 4.2503128126765395
+ 4.250350698522178
+ 4.250388583901083
+ 4.250426468813272
+ 4.250464353258758
+ 4.25050223723756
+ 4.250540120749691
+ 4.250578003795168
+ 4.250615886374005
+ 4.250653768486219
+ 4.250691650131826
+ 4.25072953131084
+ 4.2507674120232775
+ 4.250805292269155
+ 4.250843172048487
+ 4.250881051361288
+ 4.250918930207575
+ 4.250956808587365
+ 4.250994686500672
+ 4.2510325639475095
+ 4.251070440927896
+ 4.2511083174418465
+ 4.251146193489377
+ 4.2511840690705025
+ 4.251221944185237
+ 4.251259818833599
+ 4.251297693015603
+ 4.251335566731263
+ 4.251373439980597
+ 4.2514113127636195
+ 4.251449185080345
+ 4.251487056930791
+ 4.251524928314971
+ 4.251562799232905
+ 4.251600669684603
+ 4.251638539670083
+ 4.25167640918936
+ 4.251714278242451
+ 4.251752146829371
+ 4.251790014950135
+ 4.251827882604759
+ 4.251865749793257
+ 4.251903616515648
+ 4.251941482771945
+ 4.2519793485621635
+ 4.252017213886321
+ 4.252055078744431
+ 4.2520929431365095
+ 4.2521308070625725
+ 4.252168670522637
+ 4.252206533516715
+ 4.2522443960448255
+ 4.252282258106982
+ 4.252320119703201
+ 4.252357980833498
+ 4.252395841497888
+ 4.252433701696388
+ 4.252471561429012
+ 4.252509420695775
+ 4.252547279496694
+ 4.252585137831785
+ 4.252622995701062
+ 4.252660853104542
+ 4.252698710042239
+ 4.25273656651417
+ 4.25277442252035
+ 4.252812278060794
+ 4.252850133135518
+ 4.252887987744538
+ 4.25292584188787
+ 4.252963695565528
+ 4.253001548777528
+ 4.253039401523886
+ 4.2530772538046175
+ 4.253115105619737
+ 4.253152956969262
+ 4.253190807853207
+ 4.2532286582715875
+ 4.253266508224418
+ 4.253304357711717
+ 4.253342206733497
+ 4.2533800552897745
+ 4.253417903380566
+ 4.253455751005886
+ 4.2534935981657505
+ 4.253531444860174
+ 4.253569291089174
+ 4.253607136852764
+ 4.253644982150961
+ 4.25368282698378
+ 4.253720671351236
+ 4.253758515253345
+ 4.253796358690124
+ 4.253834201661586
+ 4.253872044167748
+ 4.253909886208626
+ 4.253947727784233
+ 4.253985568894588
+ 4.254023409539703
+ 4.254061249719596
+ 4.254099089434282
+ 4.254136928683776
+ 4.254174767468094
+ 4.254212605787251
+ 4.254250443641264
+ 4.254288281030147
+ 4.254326117953916
+ 4.254363954412585
+ 4.254401790406173
+ 4.254439625934692
+ 4.254477460998161
+ 4.254515295596591
+ 4.254553129730002
+ 4.254590963398407
+ 4.254628796601821
+ 4.254666629340262
+ 4.254704461613743
+ 4.254742293422281
+ 4.254780124765891
+ 4.254817955644589
+ 4.254855786058391
+ 4.25489361600731
+ 4.254931445491364
+ 4.254969274510568
+ 4.255007103064936
+ 4.255044931154485
+ 4.25508275877923
+ 4.255120585939188
+ 4.255158412634372
+ 4.255196238864798
+ 4.255234064630483
+ 4.255271889931441
+ 4.25530971476769
+ 4.255347539139241
+ 4.2553853630461145
+ 4.255423186488322
+ 4.255461009465882
+ 4.255498831978808
+ 4.255536654027116
+ 4.255574475610821
+ 4.2556122967299395
+ 4.255650117384486
+ 4.255687937574478
+ 4.255725757299929
+ 4.255763576560855
+ 4.255801395357271
+ 4.255839213689194
+ 4.255877031556638
+ 4.255914848959618
+ 4.255952665898152
+ 4.255990482372253
+ 4.256028298381938
+ 4.256066113927222
+ 4.25610392900812
+ 4.2561417436246485
+ 4.256179557776821
+ 4.256217371464655
+ 4.2562551846881655
+ 4.2562929974473676
+ 4.256330809742278
+ 4.25636862157291
+ 4.25640643293928
+ 4.256444243841404
+ 4.256482054279297
+ 4.256519864252975
+ 4.256557673762452
+ 4.256595482807747
+ 4.25663329138887
+ 4.256671099505842
+ 4.256708907158674
+ 4.2567467143473845
+ 4.256784521071988
+ 4.256822327332499
+ 4.256860133128935
+ 4.256897938461309
+ 4.256935743329638
+ 4.256973547733938
+ 4.2570113516742225
+ 4.25704915515051
+ 4.2570869581628115
+ 4.257124760711147
+ 4.2571625627955285
+ 4.257200364415974
+ 4.257238165572497
+ 4.257275966265115
+ 4.2573137664938425
+ 4.257351566258693
+ 4.2573893655596855
+ 4.257427164396832
+ 4.257464962770151
+ 4.257502760679655
+ 4.2575405581253625
+ 4.257578355107286
+ 4.257616151625444
+ 4.25765394767985
+ 4.257691743270519
+ 4.257729538397467
+ 4.25776733306071
+ 4.257805127260264
+ 4.257842920996143
+ 4.257880714268363
+ 4.257918507076939
+ 4.257956299421887
+ 4.257994091303223
+ 4.25803188272096
+ 4.258069673675117
+ 4.258107464165707
+ 4.258145254192746
+ 4.258183043756249
+ 4.2582208328562325
+ 4.258258621492711
+ 4.2582964096657
+ 4.258334197375215
+ 4.258371984621273
+ 4.258409771403888
+ 4.258447557723074
+ 4.258485343578848
+ 4.258523128971226
+ 4.258560913900223
+ 4.258598698365854
+ 4.258636482368134
+ 4.25867426590708
+ 4.258712048982706
+ 4.258749831595027
+ 4.258787613744061
+ 4.258825395429821
+ 4.258863176652323
+ 4.258900957411583
+ 4.258938737707615
+ 4.258976517540436
+ 4.25901429691006
+ 4.259052075816504
+ 4.259089854259782
+ 4.259127632239911
+ 4.259165409756904
+ 4.25920318681078
+ 4.259240963401551
+ 4.259278739529233
+ 4.259316515193843
+ 4.259354290395395
+ 4.259392065133906
+ 4.259429839409389
+ 4.259467613221862
+ 4.2595053865713375
+ 4.2595431594578335
+ 4.259580931881364
+ 4.259618703841944
+ 4.259656475339591
+ 4.25969424637432
+ 4.259732016946144
+ 4.25976978705508
+ 4.259807556701143
+ 4.259845325884349
+ 4.259883094604714
+ 4.259920862862252
+ 4.259958630656978
+ 4.2599963979889095
+ 4.260034164858061
+ 4.260071931264446
+ 4.260109697208082
+ 4.260147462688985
+ 4.260185227707168
+ 4.260222992262648
+ 4.26026075635544
+ 4.260298519985559
+ 4.260336283153022
+ 4.260374045857842
+ 4.260411808100035
+ 4.2604495698796185
+ 4.260487331196605
+ 4.2605250920510125
+ 4.260562852442853
+ 4.260600612372145
+ 4.260638371838905
+ 4.260676130843144
+ 4.2607138893848795
+ 4.260751647464128
+ 4.260789405080903
+ 4.260827162235221
+ 4.260864918927097
+ 4.260902675156546
+ 4.2609404309235845
+ 4.260978186228227
+ 4.2610159410704895
+ 4.261053695450387
+ 4.261091449367934
+ 4.261129202823148
+ 4.261166955816042
+ 4.261204708346633
+ 4.261242460414935
+ 4.261280212020964
+ 4.261317963164736
+ 4.2613557138462665
+ 4.26139346406557
+ 4.261431213822662
+ 4.261468963117558
+ 4.261506711950272
+ 4.261544460320823
+ 4.261582208229222
+ 4.261619955675487
+ 4.261657702659633
+ 4.261695449181675
+ 4.2617331952416295
+ 4.26177094083951
+ 4.261808685975332
+ 4.261846430649111
+ 4.261884174860865
+ 4.261921918610606
+ 4.26195966189835
+ 4.261997404724114
+ 4.2620351470879125
+ 4.26207288898976
+ 4.262110630429673
+ 4.262148371407665
+ 4.262186111923754
+ 4.262223851977954
+ 4.2622615915702795
+ 4.262299330700746
+ 4.262337069369371
+ 4.262374807576168
+ 4.262412545321152
+ 4.262450282604341
+ 4.262488019425747
+ 4.262525755785386
+ 4.262563491683275
+ 4.262601227119429
+ 4.262638962093861
+ 4.262676696606589
+ 4.262714430657628
+ 4.262752164246992
+ 4.262789897374697
+ 4.26282763004076
+ 4.262865362245193
+ 4.2629030939880135
+ 4.262940825269236
+ 4.262978556088877
+ 4.263016286446949
+ 4.263054016343472
+ 4.263091745778457
+ 4.2631294747519215
+ 4.26316720326388
+ 4.263204931314349
+ 4.263242658903342
+ 4.263280386030876
+ 4.2633181126969655
+ 4.263355838901626
+ 4.263393564644873
+ 4.263431289926721
+ 4.263469014747186
+ 4.263506739106283
+ 4.263544463004028
+ 4.263582186440436
+ 4.263619909415522
+ 4.2636576319293
+ 4.263695353981788
+ 4.2637330755730005
+ 4.263770796702952
+ 4.263808517371658
+ 4.263846237579134
+ 4.263883957325395
+ 4.263921676610458
+ 4.263959395434335
+ 4.2639971137970445
+ 4.2640348316986
+ 4.264072549139018
+ 4.264110266118313
+ 4.2641479826365
+ 4.264185698693595
+ 4.264223414289614
+ 4.26426112942457
+ 4.264298844098479
+ 4.264336558311357
+ 4.264374272063221
+ 4.264411985354084
+ 4.264449698183961
+ 4.264487410552869
+ 4.264525122460822
+ 4.264562833907836
+ 4.264600544893925
+ 4.264638255419106
+ 4.264675965483394
+ 4.264713675086803
+ 4.264751384229349
+ 4.264789092911049
+ 4.264826801131916
+ 4.264864508891965
+ 4.264902216191214
+ 4.264939923029675
+ 4.264977629407365
+ 4.265015335324301
+ 4.2650530407804945
+ 4.265090745775963
+ 4.265128450310722
+ 4.2651661543847865
+ 4.265203857998171
+ 4.265241561150891
+ 4.265279263842962
+ 4.265316966074401
+ 4.26535466784522
+ 4.265392369155437
+ 4.265430070005066
+ 4.265467770394122
+ 4.265505470322621
+ 4.265543169790577
+ 4.265580868798009
+ 4.265618567344927
+ 4.26565626543135
+ 4.265693963057291
+ 4.265731660222768
+ 4.265769356927794
+ 4.2658070531723835
+ 4.265844748956555
+ 4.265882444280321
+ 4.265920139143698
+ 4.2659578335467
+ 4.265995527489345
+ 4.266033220971645
+ 4.266070913993618
+ 4.266108606555276
+ 4.266146298656639
+ 4.266183990297717
+ 4.266221681478529
+ 4.266259372199088
+ 4.266297062459412
+ 4.266334752259513
+ 4.266372441599409
+ 4.266410130479112
+ 4.266447818898642
+ 4.266485506858009
+ 4.266523194357233
+ 4.266560881396326
+ 4.266598567975304
+ 4.266636254094182
+ 4.266673939752977
+ 4.266711624951703
+ 4.266749309690375
+ 4.266786993969008
+ 4.266824677787618
+ 4.26686236114622
+ 4.266900044044829
+ 4.2669377264834605
+ 4.266975408462129
+ 4.2670130899808525
+ 4.267050771039643
+ 4.267088451638517
+ 4.26712613177749
+ 4.267163811456576
+ 4.267201490675792
+ 4.267239169435151
+ 4.267276847734672
+ 4.267314525574365
+ 4.2673522029542506
+ 4.267389879874339
+ 4.26742755633465
+ 4.267465232335196
+ 4.2675029078759925
+ 4.267540582957056
+ 4.267578257578402
+ 4.267615931740042
+ 4.267653605441996
+ 4.267691278684275
+ 4.267728951466898
+ 4.267766623789878
+ 4.267804295653232
+ 4.267841967056973
+ 4.267879638001117
+ 4.2679173084856785
+ 4.267954978510676
+ 4.26799264807612
+ 4.2680303171820295
+ 4.268067985828418
+ 4.268105654015301
+ 4.268143321742693
+ 4.26818098901061
+ 4.2682186558190685
+ 4.2682563221680825
+ 4.268293988057666
+ 4.268331653487835
+ 4.268369318458606
+ 4.268406982969992
+ 4.268444647022011
+ 4.268482310614675
+ 4.268519973748002
+ 4.268557636422005
+ 4.2685952986367015
+ 4.268632960392104
+ 4.268670621688231
+ 4.268708282525095
+ 4.2687459429027115
+ 4.268783602821096
+ 4.268821262280264
+ 4.2688589212802315
+ 4.268896579821012
+ 4.268934237902623
+ 4.268971895525077
+ 4.26900955268839
+ 4.269047209392578
+ 4.269084865637657
+ 4.26912252142364
+ 4.269160176750543
+ 4.269197831618382
+ 4.269235486027171
+ 4.269273139976926
+ 4.269310793467662
+ 4.269348446499395
+ 4.269386099072138
+ 4.269423751185908
+ 4.26946140284072
+ 4.269499054036588
+ 4.269536704773529
+ 4.2695743550515575
+ 4.269612004870687
+ 4.2696496542309355
+ 4.269687303132315
+ 4.269724951574845
+ 4.269762599558537
+ 4.269800247083406
+ 4.269837894149471
+ 4.269875540756743
+ 4.26991318690524
+ 4.269950832594975
+ 4.269988477825964
+ 4.270026122598224
+ 4.270063766911767
+ 4.27010141076661
+ 4.270139054162769
+ 4.270176697100257
+ 4.27021433957909
+ 4.270251981599284
+ 4.2702896231608545
+ 4.2703272642638135
+ 4.27036490490818
+ 4.270402545093967
+ 4.27044018482119
+ 4.270477824089866
+ 4.270515462900008
+ 4.27055310125163
+ 4.27059073914475
+ 4.270628376579382
+ 4.270666013555542
+ 4.270703650073243
+ 4.270741286132503
+ 4.270778921733334
+ 4.270816556875754
+ 4.270854191559777
+ 4.270891825785418
+ 4.270929459552692
+ 4.270967092861615
+ 4.2710047257122
+ 4.271042358104465
+ 4.271079990038425
+ 4.271117621514092
+ 4.271155252531485
+ 4.271192883090616
+ 4.271230513191503
+ 4.271268142834158
+ 4.271305772018597
+ 4.271343400744838
+ 4.271381029012893
+ 4.271418656822779
+ 4.27145628417451
+ 4.271493911068102
+ 4.271531537503569
+ 4.271569163480927
+ 4.271606789000191
+ 4.271644414061376
+ 4.271682038664497
+ 4.271719662809569
+ 4.271757286496608
+ 4.271794909725629
+ 4.271832532496646
+ 4.271870154809674
+ 4.27190777666473
+ 4.271945398061829
+ 4.271983019000984
+ 4.272020639482213
+ 4.272058259505528
+ 4.272095879070946
+ 4.272133498178482
+ 4.272171116828151
+ 4.272208735019968
+ 4.272246352753948
+ 4.272283970030106
+ 4.272321586848458
+ 4.272359203209018
+ 4.272396819111801
+ 4.272434434556824
+ 4.272472049544101
+ 4.272509664073646
+ 4.272547278145476
+ 4.272584891759605
+ 4.272622504916048
+ 4.27266011761482
+ 4.272697729855938
+ 4.2727353416394145
+ 4.272772952965267
+ 4.2728105638335085
+ 4.272848174244156
+ 4.272885784197222
+ 4.272923393692725
+ 4.272961002730677
+ 4.272998611311095
+ 4.273036219433994
+ 4.273073827099388
+ 4.273111434307293
+ 4.273149041057724
+ 4.2731866473506965
+ 4.273224253186225
+ 4.273261858564325
+ 4.27329946348501
+ 4.273337067948297
+ 4.273374671954201
+ 4.273412275502737
+ 4.273449878593918
+ 4.273487481227763
+ 4.273525083404284
+ 4.273562685123496
+ 4.273600286385416
+ 4.273637887190058
+ 4.273675487537438
+ 4.273713087427569
+ 4.2737506868604695
+ 4.273788285836151
+ 4.273825884354631
+ 4.273863482415923
+ 4.2739010800200425
+ 4.273938677167006
+ 4.273976273856827
+ 4.274013870089521
+ 4.274051465865105
+ 4.27408906118359
+ 4.274126656044994
+ 4.274164250449331
+ 4.274201844396618
+ 4.274239437886867
+ 4.2742770309200955
+ 4.274314623496318
+ 4.274352215615549
+ 4.274389807277804
+ 4.274427398483097
+ 4.274464989231446
+ 4.2745025795228635
+ 4.274540169357365
+ 4.274577758734965
+ 4.274615347655681
+ 4.274652936119525
+ 4.274690524126514
+ 4.274728111676663
+ 4.274765698769987
+ 4.2748032854065
+ 4.274840871586218
+ 4.274878457309156
+ 4.274916042575328
+ 4.274953627384751
+ 4.274991211737439
+ 4.275028795633407
+ 4.275066379072671
+ 4.275103962055244
+ 4.2751415445811425
+ 4.275179126650382
+ 4.275216708262977
+ 4.2752542894189425
+ 4.275291870118293
+ 4.275329450361045
+ 4.275367030147212
+ 4.2754046094768094
+ 4.275442188349853
+ 4.275479766766358
+ 4.275517344726339
+ 4.2755549222298095
+ 4.2755924992767875
+ 4.275630075867285
+ 4.275667652001321
+ 4.275705227678905
+ 4.275742802900058
+ 4.275780377664791
+ 4.275817951973121
+ 4.275855525825062
+ 4.275893099220629
+ 4.275930672159838
+ 4.275968244642703
+ 4.27600581666924
+ 4.276043388239463
+ 4.276080959353389
+ 4.276118530011031
+ 4.276156100212404
+ 4.276193669957524
+ 4.276231239246406
+ 4.276268808079066
+ 4.2763063764555165
+ 4.276343944375774
+ 4.276381511839853
+ 4.27641907884777
+ 4.276456645399538
+ 4.276494211495174
+ 4.276531777134691
+ 4.276569342318107
+ 4.276606907045433
+ 4.276644471316687
+ 4.276682035131883
+ 4.276719598491036
+ 4.276757161394163
+ 4.276794723841276
+ 4.27683228583239
+ 4.276869847367522
+ 4.276907408446688
+ 4.276944969069901
+ 4.276982529237175
+ 4.277020088948527
+ 4.277057648203972
+ 4.277095207003524
+ 4.277132765347199
+ 4.277170323235011
+ 4.2772078806669755
+ 4.277245437643107
+ 4.277282994163422
+ 4.277320550227934
+ 4.277358105836659
+ 4.277395660989611
+ 4.2774332156868065
+ 4.277470769928259
+ 4.277508323713985
+ 4.2775458770439965
+ 4.277583429918312
+ 4.277620982336946
+ 4.277658534299911
+ 4.277696085807225
+ 4.2777336368589
+ 4.277771187454954
+ 4.277808737595401
+ 4.277846287280256
+ 4.277883836509532
+ 4.277921385283247
+ 4.277958933601415
+ 4.27799648146405
+ 4.278034028871167
+ 4.278071575822783
+ 4.278109122318911
+ 4.278146668359566
+ 4.2781842139447654
+ 4.278221759074522
+ 4.27825930374885
+ 4.278296847967767
+ 4.278334391731287
+ 4.278371935039424
+ 4.278409477892193
+ 4.278447020289611
+ 4.278484562231691
+ 4.278522103718448
+ 4.278559644749898
+ 4.278597185326056
+ 4.278634725446937
+ 4.278672265112554
+ 4.278709804322925
+ 4.278747343078063
+ 4.278784881377984
+ 4.278822419222702
+ 4.278859956612233
+ 4.27889749354659
+ 4.278935030025791
+ 4.278972566049849
+ 4.27901010161878
+ 4.279047636732598
+ 4.279085171391318
+ 4.279122705594955
+ 4.2791602393435255
+ 4.279197772637043
+ 4.279235305475522
+ 4.279272837858978
+ 4.279310369787428
+ 4.279347901260884
+ 4.279385432279363
+ 4.279422962842879
+ 4.279460492951445
+ 4.279498022605081
+ 4.2795355518037965
+ 4.279573080547611
+ 4.279610608836537
+ 4.279648136670589
+ 4.279685664049785
+ 4.279723190974136
+ 4.279760717443659
+ 4.2797982434583695
+ 4.279835769018281
+ 4.27987329412341
+ 4.27991081877377
+ 4.2799483429693765
+ 4.279985866710246
+ 4.280023389996391
+ 4.280060912827827
+ 4.280098435204571
+ 4.280135957126635
+ 4.280173478594036
+ 4.280210999606788
+ 4.280248520164906
+ 4.280286040268407
+ 4.280323559917303
+ 4.28036107911161
+ 4.280398597851343
+ 4.280436116136517
+ 4.280473633967148
+ 4.280511151343249
+ 4.280548668264835
+ 4.2805861847319235
+ 4.280623700744527
+ 4.280661216302661
+ 4.280698731406342
+ 4.280736246055582
+ 4.280773760250398
+ 4.280811273990805
+ 4.280848787276817
+ 4.280886300108449
+ 4.2809238124857165
+ 4.280961324408635
+ 4.2809988358772175
+ 4.28103634689148
+ 4.28107385745144
+ 4.2811113675571075
+ 4.281148877208501
+ 4.281186386405634
+ 4.281223895148521
+ 4.281261403437179
+ 4.281298911271621
+ 4.281336418651863
+ 4.2813739255779195
+ 4.281411432049805
+ 4.281448938067534
+ 4.281486443631124
+ 4.281523948740587
+ 4.281561453395939
+ 4.281598957597196
+ 4.281636461344371
+ 4.281673964637481
+ 4.28171146747654
+ 4.281748969861561
+ 4.281786471792562
+ 4.281823973269556
+ 4.281861474292558
+ 4.281898974861585
+ 4.281936474976649
+ 4.281973974637767
+ 4.282011473844953
+ 4.282048972598222
+ 4.282086470897589
+ 4.282123968743069
+ 4.282161466134676
+ 4.282198963072426
+ 4.2822364595563345
+ 4.282273955586414
+ 4.282311451162683
+ 4.282348946285153
+ 4.28238644095384
+ 4.282423935168761
+ 4.282461428929928
+ 4.282498922237356
+ 4.282536415091061
+ 4.282573907491059
+ 4.282611399437363
+ 4.2826488909299885
+ 4.282686381968952
+ 4.282723872554265
+ 4.282761362685945
+ 4.282798852364007
+ 4.282836341588463
+ 4.282873830359331
+ 4.282911318676626
+ 4.28294880654036
+ 4.282986293950551
+ 4.283023780907212
+ 4.283061267410359
+ 4.283098753460005
+ 4.283136239056168
+ 4.28317372419886
+ 4.283211208888097
+ 4.283248693123894
+ 4.283286176906266
+ 4.283323660235228
+ 4.283361143110794
+ 4.283398625532979
+ 4.2834361075017995
+ 4.283473589017269
+ 4.283511070079402
+ 4.283548550688215
+ 4.28358603084372
+ 4.283623510545936
+ 4.283660989794874
+ 4.2836984685905515
+ 4.283735946932981
+ 4.28377342482218
+ 4.283810902258162
+ 4.283848379240942
+ 4.283885855770534
+ 4.283923331846954
+ 4.283960807470217
+ 4.283998282640338
+ 4.284035757357332
+ 4.284073231621211
+ 4.284110705431994
+ 4.284148178789693
+ 4.284185651694324
+ 4.284223124145902
+ 4.284260596144443
+ 4.284298067689958
+ 4.284335538782465
+ 4.284373009421979
+ 4.284410479608514
+ 4.284447949342085
+ 4.284485418622706
+ 4.284522887450393
+ 4.28456035582516
+ 4.284597823747024
+ 4.284635291215997
+ 4.284672758232095
+ 4.284710224795332
+ 4.284747690905726
+ 4.284785156563288
+ 4.2848226217680345
+ 4.2848600865199815
+ 4.284897550819142
+ 4.284935014665532
+ 4.284972478059165
+ 4.285009941000058
+ 4.285047403488224
+ 4.285084865523679
+ 4.285122327106436
+ 4.285159788236512
+ 4.285197248913922
+ 4.2852347091386775
+ 4.285272168910797
+ 4.285309628230295
+ 4.285347087097184
+ 4.285384545511481
+ 4.2854220034732
+ 4.285459460982357
+ 4.285496918038964
+ 4.285534374643038
+ 4.285571830794593
+ 4.285609286493646
+ 4.285646741740209
+ 4.285684196534298
+ 4.285721650875927
+ 4.285759104765113
+ 4.285796558201868
+ 4.2858340111862105
+ 4.28587146371815
+ 4.285908915797707
+ 4.285946367424893
+ 4.285983818599724
+ 4.286021269322214
+ 4.286058719592378
+ 4.286096169410233
+ 4.28613361877579
+ 4.286171067689066
+ 4.286208516150076
+ 4.286245964158835
+ 4.286283411715356
+ 4.286320858819656
+ 4.286358305471748
+ 4.286395751671648
+ 4.286433197419371
+ 4.2864706427149315
+ 4.286508087558343
+ 4.286545531949622
+ 4.286582975888784
+ 4.286620419375841
+ 4.28665786241081
+ 4.286695304993706
+ 4.286732747124542
+ 4.2867701888033345
+ 4.286807630030098
+ 4.286845070804846
+ 4.286882511127596
+ 4.286919950998358
+ 4.286957390417153
+ 4.286994829383992
+ 4.28703226789889
+ 4.287069705961863
+ 4.287107143572924
+ 4.2871445807320905
+ 4.287182017439376
+ 4.287219453694792
+ 4.28725688949836
+ 4.287294324850089
+ 4.287331759749997
+ 4.2873691941980985
+ 4.287406628194406
+ 4.287444061738936
+ 4.287481494831705
+ 4.287518927472724
+ 4.287556359662011
+ 4.287593791399579
+ 4.287631222685444
+ 4.28766865351962
+ 4.287706083902121
+ 4.287743513832964
+ 4.287780943312161
+ 4.28781837233973
+ 4.2878558009156835
+ 4.287893229040036
+ 4.287930656712805
+ 4.287968083934003
+ 4.288005510703646
+ 4.288042937021746
+ 4.288080362888322
+ 4.288117788303385
+ 4.288155213266952
+ 4.288192637779038
+ 4.288230061839656
+ 4.288267485448822
+ 4.288304908606551
+ 4.288342331312856
+ 4.288379753567755
+ 4.28841717537126
+ 4.288454596723388
+ 4.28849201762415
+ 4.2885294380735655
+ 4.288566858071646
+ 4.288604277618407
+ 4.288641696713864
+ 4.288679115358031
+ 4.288716533550923
+ 4.288753951292556
+ 4.2887913685829435
+ 4.288828785422099
+ 4.28886620181004
+ 4.28890361774678
+ 4.288941033232333
+ 4.288978448266715
+ 4.28901586284994
+ 4.289053276982023
+ 4.289090690662979
+ 4.289128103892823
+ 4.289165516671568
+ 4.289202928999232
+ 4.289240340875827
+ 4.289277752301367
+ 4.28931516327587
+ 4.289352573799349
+ 4.2893899838718195
+ 4.289427393493296
+ 4.289464802663791
+ 4.289502211383322
+ 4.289539619651904
+ 4.28957702746955
+ 4.289614434836275
+ 4.289651841752093
+ 4.289689248217022
+ 4.289726654231074
+ 4.289764059794265
+ 4.289801464906608
+ 4.289838869568119
+ 4.289876273778814
+ 4.2899136775387054
+ 4.28995108084781
+ 4.289988483706139
+ 4.290025886113712
+ 4.290063288070542
+ 4.290100689576642
+ 4.290138090632027
+ 4.290175491236714
+ 4.290212891390716
+ 4.290250291094049
+ 4.290287690346726
+ 4.290325089148762
+ 4.290362487500173
+ 4.290399885400973
+ 4.290437282851176
+ 4.290474679850799
+ 4.290512076399855
+ 4.290549472498359
+ 4.290586868146325
+ 4.290624263343769
+ 4.290661658090705
+ 4.290699052387149
+ 4.290736446233113
+ 4.290773839628614
+ 4.290811232573668
+ 4.290848625068286
+ 4.290886017112484
+ 4.290923408706279
+ 4.290960799849683
+ 4.2909981905427115
+ 4.29103558078538
+ 4.291072970577703
+ 4.291110359919695
+ 4.291147748811371
+ 4.291185137252743
+ 4.29122252524383
+ 4.291259912784645
+ 4.291297299875202
+ 4.291334686515517
+ 4.291372072705604
+ 4.291409458445477
+ 4.291446843735152
+ 4.2914842285746415
+ 4.2915216129639635
+ 4.29155899690313
+ 4.291596380392158
+ 4.291633763431061
+ 4.291671146019852
+ 4.291708528158549
+ 4.291745909847164
+ 4.291783291085713
+ 4.291820671874211
+ 4.291858052212673
+ 4.291895432101112
+ 4.291932811539544
+ 4.291970190527982
+ 4.292007569066444
+ 4.292044947154941
+ 4.2920823247934905
+ 4.292119701982106
+ 4.292157078720802
+ 4.292194455009594
+ 4.292231830848496
+ 4.292269206237523
+ 4.29230658117669
+ 4.292343955666011
+ 4.292381329705501
+ 4.2924187032951755
+ 4.292456076435047
+ 4.292493449125133
+ 4.292530821365446
+ 4.292568193156002
+ 4.292605564496815
+ 4.292642935387899
+ 4.292680305829271
+ 4.292717675820943
+ 4.292755045362932
+ 4.292792414455251
+ 4.292829783097916
+ 4.29286715129094
+ 4.292904519034339
+ 4.292941886328128
+ 4.292979253172321
+ 4.293016619566933
+ 4.293053985511977
+ 4.293091351007471
+ 4.293128716053426
+ 4.2931660806498595
+ 4.293203444796785
+ 4.293240808494217
+ 4.293278171742171
+ 4.293315534540661
+ 4.293352896889702
+ 4.293390258789308
+ 4.293427620239495
+ 4.293464981240276
+ 4.293502341791667
+ 4.293539701893683
+ 4.293577061546337
+ 4.293614420749644
+ 4.2936517795036195
+ 4.29368913780828
+ 4.293726495663635
+ 4.293763853069705
+ 4.2938012100265
+ 4.2938385665340375
+ 4.29387592259233
+ 4.293913278201395
+ 4.293950633361244
+ 4.293987988071894
+ 4.294025342333359
+ 4.294062696145653
+ 4.294100049508792
+ 4.29413740242279
+ 4.294174754887661
+ 4.294212106903419
+ 4.294249458470082
+ 4.294286809587662
+ 4.294324160256173
+ 4.294361510475632
+ 4.294398860246051
+ 4.294436209567448
+ 4.294473558439835
+ 4.294510906863227
+ 4.294548254837639
+ 4.294585602363085
+ 4.2946229494395824
+ 4.294660296067143
+ 4.294697642245782
+ 4.294734987975514
+ 4.294772333256354
+ 4.294809678088317
+ 4.2948470224714175
+ 4.294884366405669
+ 4.294921709891088
+ 4.294959052927687
+ 4.294996395515482
+ 4.295033737654489
+ 4.295071079344719
+ 4.29510842058619
+ 4.295145761378915
+ 4.29518310172291
+ 4.295220441618187
+ 4.2952577810647625
+ 4.295295120062653
+ 4.295332458611868
+ 4.295369796712427
+ 4.295407134364342
+ 4.295444471567629
+ 4.295481808322302
+ 4.295519144628375
+ 4.295556480485865
+ 4.295593815894783
+ 4.295631150855147
+ 4.29566848536697
+ 4.295705819430266
+ 4.295743153045051
+ 4.2957804862113385
+ 4.295817818929145
+ 4.295855151198483
+ 4.295892483019368
+ 4.2959298143918145
+ 4.295967145315838
+ 4.2960044757914515
+ 4.296041805818669
+ 4.296079135397509
+ 4.296116464527983
+ 4.296153793210106
+ 4.296191121443893
+ 4.296228449229359
+ 4.296265776566518
+ 4.296303103455384
+ 4.296340429895973
+ 4.296377755888298
+ 4.296415081432376
+ 4.2964524065282195
+ 4.296489731175844
+ 4.296527055375264
+ 4.296564379126494
+ 4.296601702429548
+ 4.296639025284442
+ 4.296676347691189
+ 4.296713669649805
+ 4.296750991160304
+ 4.296788312222701
+ 4.2968256328370105
+ 4.296862953003246
+ 4.296900272721423
+ 4.296937591991557
+ 4.2969749108136615
+ 4.29701222918775
+ 4.29704954711384
+ 4.297086864591943
+ 4.297124181622076
+ 4.297161498204252
+ 4.297198814338488
+ 4.297236130024794
+ 4.2972734452631896
+ 4.297310760053686
+ 4.2973480743963
+ 4.297385388291045
+ 4.297422701737936
+ 4.297460014736987
+ 4.297497327288212
+ 4.297534639391629
+ 4.297571951047248
+ 4.2976092622550865
+ 4.297646573015158
+ 4.297683883327478
+ 4.297721193192061
+ 4.29775850260892
+ 4.29779581157807
+ 4.297833120099528
+ 4.297870428173307
+ 4.297907735799419
+ 4.297945042977884
+ 4.297982349708711
+ 4.2980196559919195
+ 4.29805696182752
+ 4.298094267215529
+ 4.298131572155961
+ 4.29816887664883
+ 4.2982061806941525
+ 4.298243484291941
+ 4.29828078744221
+ 4.298318090144975
+ 4.298355392400251
+ 4.298392694208051
+ 4.298429995568391
+ 4.2984672964812844
+ 4.2985045969467475
+ 4.298541896964793
+ 4.298579196535437
+ 4.298616495658692
+ 4.298653794334575
+ 4.298691092563098
+ 4.298728390344279
+ 4.298765687678129
+ 4.298802984564665
+ 4.2988402810039
+ 4.29887757699585
+ 4.298914872540528
+ 4.29895216763795
+ 4.298989462288129
+ 4.299026756491082
+ 4.2990640502468205
+ 4.29910134355536
+ 4.299138636416718
+ 4.2991759288309055
+ 4.299213220797938
+ 4.299250512317831
+ 4.299287803390597
+ 4.299325094016253
+ 4.299362384194813
+ 4.29939967392629
+ 4.2994369632107
+ 4.299474252048057
+ 4.299511540438375
+ 4.2995488283816705
+ 4.299586115877955
+ 4.299623402927247
+ 4.299660689529556
+ 4.299697975684901
+ 4.2997352613932955
+ 4.2997725466547525
+ 4.299809831469288
+ 4.299847115836916
+ 4.299884399757651
+ 4.299921683231508
+ 4.299958966258499
+ 4.299996248838643
+ 4.300033530971952
+ 4.300070812658441
+ 4.300108093898123
+ 4.300145374691015
+ 4.30018265503713
+ 4.300219934936482
+ 4.300257214389087
+ 4.300294493394959
+ 4.300331771954112
+ 4.300369050066562
+ 4.300406327732322
+ 4.300443604951408
+ 4.300480881723832
+ 4.300518158049612
+ 4.300555433928759
+ 4.30059270936129
+ 4.300629984347219
+ 4.300667258886559
+ 4.300704532979327
+ 4.300741806625535
+ 4.3007790798252
+ 4.300816352578335
+ 4.3008536248849545
+ 4.300890896745074
+ 4.3009281681587055
+ 4.300965439125867
+ 4.301002709646571
+ 4.301039979720833
+ 4.301077249348666
+ 4.3011145185300865
+ 4.301151787265107
+ 4.301189055553744
+ 4.30122632339601
+ 4.301263590791922
+ 4.3013008577414915
+ 4.301338124244734
+ 4.301375390301666
+ 4.3014126559123
+ 4.301449921076651
+ 4.301487185794733
+ 4.3015244500665615
+ 4.301561713892151
+ 4.301598977271515
+ 4.301636240204669
+ 4.301673502691626
+ 4.301710764732403
+ 4.301748026327012
+ 4.301785287475469
+ 4.301822548177789
+ 4.301859808433984
+ 4.30189706824407
+ 4.3019343276080635
+ 4.301971586525975
+ 4.302008844997822
+ 4.302046103023619
+ 4.302083360603378
+ 4.302120617737115
+ 4.302157874424845
+ 4.302195130666582
+ 4.30223238646234
+ 4.302269641812136
+ 4.30230689671598
+ 4.30234415117389
+ 4.302381405185879
+ 4.3024186587519635
+ 4.302455911872155
+ 4.30249316454647
+ 4.302530416774922
+ 4.3025676685575265
+ 4.302604919894296
+ 4.302642170785248
+ 4.302679421230394
+ 4.302716671229752
+ 4.302753920783331
+ 4.302791169891152
+ 4.302828418553224
+ 4.302865666769565
+ 4.302902914540188
+ 4.3029401618651075
+ 4.302977408744338
+ 4.303014655177894
+ 4.303051901165791
+ 4.303089146708042
+ 4.303126391804661
+ 4.303163636455666
+ 4.303200880661067
+ 4.303238124420881
+ 4.3032753677351225
+ 4.303312610603805
+ 4.303349853026942
+ 4.303387095004552
+ 4.303424336536645
+ 4.3034615776232386
+ 4.3034988182643445
+ 4.303536058459979
+ 4.303573298210156
+ 4.303610537514892
+ 4.303647776374198
+ 4.30368501478809
+ 4.303722252756583
+ 4.30375949027969
+ 4.303796727357427
+ 4.303833963989809
+ 4.3038712001768475
+ 4.303908435918561
+ 4.30394567121496
+ 4.303982906066061
+ 4.304020140471878
+ 4.304057374432427
+ 4.30409460794772
+ 4.304131841017772
+ 4.304169073642599
+ 4.3042063058222135
+ 4.304243537556631
+ 4.304280768845867
+ 4.304317999689934
+ 4.304355230088847
+ 4.304392460042621
+ 4.30442968955127
+ 4.304466918614809
+ 4.304504147233252
+ 4.304541375406613
+ 4.304578603134907
+ 4.3046158304181485
+ 4.304653057256351
+ 4.30469028364953
+ 4.304727509597701
+ 4.304764735100876
+ 4.304801960159071
+ 4.304839184772298
+ 4.304876408940576
+ 4.304913632663916
+ 4.304950855942333
+ 4.304988078775842
+ 4.3050253011644575
+ 4.305062523108192
+ 4.305099744607063
+ 4.305136965661083
+ 4.305174186270267
+ 4.305211406434629
+ 4.305248626154184
+ 4.305285845428946
+ 4.305323064258929
+ 4.30536028264415
+ 4.30539750058462
+ 4.305434718080355
+ 4.3054719351313695
+ 4.305509151737677
+ 4.305546367899293
+ 4.305583583616233
+ 4.3056207988885085
+ 4.305658013716135
+ 4.305695228099128
+ 4.305732442037502
+ 4.30576965553127
+ 4.305806868580446
+ 4.305844081185046
+ 4.3058812933450845
+ 4.305918505060576
+ 4.305955716331534
+ 4.3059929271579716
+ 4.3060301375399055
+ 4.30606734747735
+ 4.306104556970318
+ 4.306141766018826
+ 4.3061789746228865
+ 4.3062161827825145
+ 4.306253390497725
+ 4.306290597768532
+ 4.3063278045949485
+ 4.306365010976992
+ 4.306402216914674
+ 4.30643942240801
+ 4.306476627457015
+ 4.306513832061703
+ 4.306551036222087
+ 4.306588239938185
+ 4.306625443210008
+ 4.306662646037571
+ 4.306699848420888
+ 4.306737050359976
+ 4.306774251854847
+ 4.306811452905516
+ 4.306848653511998
+ 4.306885853674306
+ 4.306923053392455
+ 4.306960252666461
+ 4.306997451496336
+ 4.307034649882096
+ 4.307071847823755
+ 4.307109045321326
+ 4.307146242374826
+ 4.307183438984267
+ 4.3072206351496645
+ 4.307257830871034
+ 4.307295026148387
+ 4.30733222098174
+ 4.307369415371108
+ 4.307406609316502
+ 4.307443802817941
+ 4.307480995875436
+ 4.307518188489003
+ 4.3075553806586555
+ 4.307592572384409
+ 4.3076297636662755
+ 4.307666954504272
+ 4.307704144898412
+ 4.30774133484871
+ 4.307778524355179
+ 4.307815713417835
+ 4.307852902036692
+ 4.307890090211764
+ 4.307927277943066
+ 4.3079644652306115
+ 4.308001652074416
+ 4.308038838474491
+ 4.308076024430856
+ 4.308113209943522
+ 4.308150395012503
+ 4.3081875796378135
+ 4.30822476381947
+ 4.308261947557485
+ 4.308299130851874
+ 4.308336313702649
+ 4.3083734961098274
+ 4.308410678073423
+ 4.308447859593448
+ 4.308485040669918
+ 4.308522221302848
+ 4.308559401492252
+ 4.308596581238144
+ 4.308633760540538
+ 4.308670939399449
+ 4.308708117814892
+ 4.30874529578688
+ 4.308782473315429
+ 4.308819650400553
+ 4.3088568270422645
+ 4.308894003240579
+ 4.30893117899551
+ 4.3089683543070745
+ 4.309005529175284
+ 4.309042703600155
+ 4.3090798775817
+ 4.309117051119935
+ 4.309154224214873
+ 4.309191396866529
+ 4.309228569074916
+ 4.309265740840051
+ 4.309302912161947
+ 4.3093400830406186
+ 4.309377253476079
+ 4.309414423468343
+ 4.3094515930174255
+ 4.309488762123341
+ 4.309525930786103
+ 4.309563099005727
+ 4.309600266782227
+ 4.309637434115617
+ 4.30967460100591
+ 4.309711767453123
+ 4.309748933457269
+ 4.3097860990183605
+ 4.309823264136416
+ 4.3098604288114455
+ 4.309897593043467
+ 4.309934756832492
+ 4.309971920178537
+ 4.310009083081615
+ 4.310046245541741
+ 4.310083407558929
+ 4.3101205691331925
+ 4.310157730264547
+ 4.3101948909530075
+ 4.310232051198586
+ 4.310269211001299
+ 4.310306370361159
+ 4.310343529278183
+ 4.3103806877523825
+ 4.310417845783772
+ 4.310455003372369
+ 4.310492160518184
+ 4.310529317221234
+ 4.310566473481531
+ 4.3106036292990915
+ 4.310640784673929
+ 4.310677939606057
+ 4.310715094095491
+ 4.310752248142244
+ 4.310789401746332
+ 4.310826554907768
+ 4.3108637076265675
+ 4.310900859902743
+ 4.310938011736311
+ 4.310975163127283
+ 4.311012314075677
+ 4.311049464581505
+ 4.311086614644781
+ 4.3111237642655205
+ 4.311160913443736
+ 4.311198062179445
+ 4.311235210472658
+ 4.311272358323392
+ 4.3113095057316615
+ 4.311346652697478
+ 4.3113837992208595
+ 4.311420945301816
+ 4.311458090940366
+ 4.311495236136522
+ 4.311532380890298
+ 4.311569525201708
+ 4.311606669070768
+ 4.311643812497491
+ 4.31168095548189
+ 4.311718098023983
+ 4.31175524012378
+ 4.311792381781299
+ 4.311829522996551
+ 4.311866663769554
+ 4.311903804100319
+ 4.311940943988861
+ 4.311978083435196
+ 4.312015222439338
+ 4.312052361001299
+ 4.312089499121095
+ 4.31212663679874
+ 4.312163774034248
+ 4.312200910827634
+ 4.312238047178912
+ 4.312275183088095
+ 4.3123123185551995
+ 4.312349453580239
+ 4.3123865881632275
+ 4.312423722304179
+ 4.312460856003107
+ 4.312497989260028
+ 4.312535122074955
+ 4.312572254447903
+ 4.3126093863788855
+ 4.312646517867916
+ 4.31268364891501
+ 4.312720779520182
+ 4.312757909683445
+ 4.312795039404816
+ 4.312832168684307
+ 4.312869297521931
+ 4.312906425917704
+ 4.312943553871642
+ 4.312980681383756
+ 4.313017808454061
+ 4.313054935082573
+ 4.313092061269305
+ 4.3131291870142725
+ 4.313166312317488
+ 4.3132034371789665
+ 4.313240561598723
+ 4.31327768557677
+ 4.313314809113123
+ 4.313351932207797
+ 4.313389054860805
+ 4.313426177072161
+ 4.3134632988418815
+ 4.313500420169977
+ 4.313537541056466
+ 4.313574661501359
+ 4.313611781504672
+ 4.313648901066421
+ 4.3136860201866165
+ 4.313723138865275
+ 4.313760257102411
+ 4.313797374898038
+ 4.313834492252172
+ 4.313871609164823
+ 4.3139087256360105
+ 4.3139458416657455
+ 4.3139829572540425
+ 4.314020072400916
+ 4.31405718710638
+ 4.31409430137045
+ 4.31413141519314
+ 4.314168528574463
+ 4.314205641514435
+ 4.314242754013067
+ 4.314279866070378
+ 4.314316977686379
+ 4.3143540888610845
+ 4.314391199594509
+ 4.314428309886667
+ 4.314465419737573
+ 4.314502529147241
+ 4.314539638115685
+ 4.31457674664292
+ 4.314613854728958
+ 4.3146509623738165
+ 4.314688069577508
+ 4.314725176340046
+ 4.314762282661445
+ 4.314799388541722
+ 4.314836493980887
+ 4.314873598978957
+ 4.314910703535945
+ 4.314947807651867
+ 4.314984911326736
+ 4.315022014560565
+ 4.31505911735337
+ 4.315096219705165
+ 4.3151333216159635
+ 4.315170423085781
+ 4.31520752411463
+ 4.315244624702525
+ 4.3152817248494815
+ 4.315318824555513
+ 4.315355923820633
+ 4.315393022644858
+ 4.3154301210282
+ 4.3154672189706735
+ 4.3155043164722935
+ 4.315541413533073
+ 4.315578510153029
+ 4.315615606332171
+ 4.315652702070519
+ 4.315689797368083
+ 4.315726892224878
+ 4.315763986640919
+ 4.315801080616219
+ 4.315838174150794
+ 4.315875267244658
+ 4.3159123598978235
+ 4.3159494521103055
+ 4.3159865438821186
+ 4.316023635213278
+ 4.316060726103795
+ 4.316097816553687
+ 4.316134906562966
+ 4.316171996131647
+ 4.316209085259744
+ 4.316246173947272
+ 4.316283262194244
+ 4.316320350000676
+ 4.316357437366579
+ 4.316394524291971
+ 4.316431610776863
+ 4.316468696821271
+ 4.316505782425209
+ 4.316542867588692
+ 4.316579952311732
+ 4.316617036594344
+ 4.316654120436544
+ 4.316691203838344
+ 4.3167282867997585
+ 4.316765369320803
+ 4.31680245140149
+ 4.316839533041835
+ 4.316876614241853
+ 4.316913695001555
+ 4.316950775320959
+ 4.316987855200076
+ 4.317024934638921
+ 4.31706201363751
+ 4.317099092195855
+ 4.317136170313972
+ 4.317173247991874
+ 4.317210325229574
+ 4.31724740202709
+ 4.317284478384432
+ 4.317321554301618
+ 4.317358629778658
+ 4.31739570481557
+ 4.317432779412366
+ 4.31746985356906
+ 4.317506927285668
+ 4.317544000562202
+ 4.317581073398678
+ 4.31761814579511
+ 4.31765521775151
+ 4.317692289267895
+ 4.317729360344278
+ 4.317766430980672
+ 4.317803501177095
+ 4.317840570933556
+ 4.317877640250072
+ 4.317914709126657
+ 4.3179517775633265
+ 4.317988845560092
+ 4.318025913116968
+ 4.318062980233971
+ 4.318100046911113
+ 4.318137113148409
+ 4.318174178945872
+ 4.318211244303519
+ 4.318248309221362
+ 4.318285373699415
+ 4.318322437737693
+ 4.31835950133621
+ 4.318396564494979
+ 4.318433627214016
+ 4.318470689493334
+ 4.318507751332947
+ 4.318544812732871
+ 4.318581873693119
+ 4.318618934213704
+ 4.318655994294641
+ 4.318693053935944
+ 4.318730113137628
+ 4.318767171899707
+ 4.318804230222194
+ 4.318841288105105
+ 4.318878345548452
+ 4.318915402552251
+ 4.318952459116514
+ 4.318989515241257
+ 4.319026570926494
+ 4.319063626172239
+ 4.319100680978506
+ 4.319137735345309
+ 4.319174789272662
+ 4.31921184276058
+ 4.319248895809076
+ 4.319285948418164
+ 4.31932300058786
+ 4.319360052318176
+ 4.319397103609128
+ 4.319434154460729
+ 4.319471204872994
+ 4.3195082548459345
+ 4.319545304379569
+ 4.319582353473908
+ 4.319619402128967
+ 4.319656450344761
+ 4.319693498121302
+ 4.319730545458606
+ 4.319767592356687
+ 4.319804638815557
+ 4.319841684835233
+ 4.319878730415728
+ 4.319915775557056
+ 4.319952820259231
+ 4.319989864522267
+ 4.320026908346178
+ 4.32006395173098
+ 4.320100994676684
+ 4.320138037183306
+ 4.320175079250862
+ 4.320212120879362
+ 4.320249162068823
+ 4.320286202819258
+ 4.320323243130681
+ 4.320360283003107
+ 4.320397322436549
+ 4.320434361431023
+ 4.320471399986541
+ 4.320508438103119
+ 4.3205454757807695
+ 4.320582513019507
+ 4.320619549819346
+ 4.320656586180301
+ 4.320693622102385
+ 4.320730657585614
+ 4.320767692629999
+ 4.320804727235557
+ 4.320841761402301
+ 4.320878795130245
+ 4.320915828419403
+ 4.32095286126979
+ 4.3209898936814195
+ 4.321026925654305
+ 4.3210639571884615
+ 4.321100988283903
+ 4.321138018940643
+ 4.321175049158697
+ 4.3212120789380775
+ 4.3212491082788
+ 4.321286137180877
+ 4.321323165644324
+ 4.321360193669154
+ 4.321397221255382
+ 4.321434248403023
+ 4.321471275112088
+ 4.321508301382593
+ 4.321545327214553
+ 4.321582352607981
+ 4.321619377562891
+ 4.321656402079298
+ 4.321693426157214
+ 4.321730449796656
+ 4.321767472997636
+ 4.32180449576017
+ 4.321841518084269
+ 4.32187853996995
+ 4.321915561417226
+ 4.321952582426111
+ 4.321989602996619
+ 4.322026623128765
+ 4.322063642822561
+ 4.322100662078024
+ 4.322137680895167
+ 4.322174699274001
+ 4.322211717214545
+ 4.32224873471681
+ 4.322285751780811
+ 4.322322768406562
+ 4.322359784594077
+ 4.32239680034337
+ 4.322433815654456
+ 4.322470830527347
+ 4.32250784496206
+ 4.322544858958606
+ 4.322581872517001
+ 4.322618885637259
+ 4.322655898319394
+ 4.322692910563418
+ 4.32272992236935
+ 4.322766933737198
+ 4.322803944666981
+ 4.32284095515871
+ 4.322877965212401
+ 4.322914974828066
+ 4.32295198400572
+ 4.322988992745379
+ 4.3230260010470545
+ 4.323063008910761
+ 4.3231000163365145
+ 4.323137023324327
+ 4.323174029874213
+ 4.323211035986187
+ 4.323248041660263
+ 4.323285046896454
+ 4.323322051694776
+ 4.323359056055241
+ 4.323396059977865
+ 4.323433063462661
+ 4.3234700665096435
+ 4.323507069118826
+ 4.323544071290223
+ 4.323581073023847
+ 4.3236180743197155
+ 4.323655075177839
+ 4.323692075598234
+ 4.323729075580912
+ 4.32376607512589
+ 4.323803074233181
+ 4.323840072902799
+ 4.323877071134757
+ 4.32391406892907
+ 4.323951066285752
+ 4.323988063204817
+ 4.324025059686279
+ 4.324062055730152
+ 4.324099051336451
+ 4.324136046505188
+ 4.324173041236379
+ 4.324210035530037
+ 4.324247029386176
+ 4.324284022804811
+ 4.324321015785954
+ 4.3243580083296225
+ 4.324395000435827
+ 4.324431992104584
+ 4.3244689833359065
+ 4.324505974129807
+ 4.3245429644863025
+ 4.324579954405406
+ 4.324616943887131
+ 4.324653932931491
+ 4.324690921538501
+ 4.324727909708176
+ 4.324764897440527
+ 4.324801884735572
+ 4.324838871593321
+ 4.324875858013791
+ 4.324912843996995
+ 4.324949829542947
+ 4.324986814651661
+ 4.3250237993231515
+ 4.325060783557431
+ 4.3250977673545155
+ 4.325134750714418
+ 4.325171733637153
+ 4.3252087161227335
+ 4.325245698171175
+ 4.32528267978249
+ 4.325319660956694
+ 4.3253566416938005
+ 4.325393621993823
+ 4.325430601856775
+ 4.325467581282673
+ 4.325504560271528
+ 4.325541538823357
+ 4.325578516938171
+ 4.325615494615986
+ 4.325652471856816
+ 4.325689448660674
+ 4.325726425027574
+ 4.325763400957531
+ 4.32580037645056
+ 4.325837351506672
+ 4.3258743261258825
+ 4.3259113003082055
+ 4.325948274053656
+ 4.325985247362246
+ 4.326022220233992
+ 4.326059192668906
+ 4.3260961646670015
+ 4.326133136228295
+ 4.326170107352799
+ 4.326207078040527
+ 4.326244048291494
+ 4.326281018105714
+ 4.3263179874832005
+ 4.326354956423968
+ 4.32639192492803
+ 4.3264288929954
+ 4.326465860626094
+ 4.326502827820123
+ 4.326539794577504
+ 4.3265767608982495
+ 4.326613726782372
+ 4.32665069222989
+ 4.326687657240813
+ 4.326724621815156
+ 4.326761585952935
+ 4.326798549654163
+ 4.326835512918852
+ 4.326872475747019
+ 4.326909438138676
+ 4.3269464000938385
+ 4.326983361612519
+ 4.3270203226947315
+ 4.3270572833404914
+ 4.327094243549812
+ 4.327131203322707
+ 4.32716816265919
+ 4.327205121559276
+ 4.3272420800229785
+ 4.327279038050312
+ 4.327315995641289
+ 4.327352952795925
+ 4.327389909514234
+ 4.3274268657962285
+ 4.327463821641924
+ 4.327500777051335
+ 4.327537732024473
+ 4.327574686561353
+ 4.32761164066199
+ 4.327648594326397
+ 4.32768554755459
+ 4.32772250034658
+ 4.327759452702382
+ 4.32779640462201
+ 4.327833356105478
+ 4.327870307152801
+ 4.327907257763992
+ 4.327944207939065
+ 4.327981157678035
+ 4.328018106980914
+ 4.328055055847717
+ 4.328092004278458
+ 4.328128952273152
+ 4.328165899831811
+ 4.32820284695445
+ 4.3282397936410835
+ 4.328276739891725
+ 4.328313685706386
+ 4.328350631085086
+ 4.328387576027834
+ 4.328424520534646
+ 4.328461464605535
+ 4.328498408240517
+ 4.328535351439604
+ 4.32857229420281
+ 4.328609236530149
+ 4.3286461784216375
+ 4.328683119877285
+ 4.328720060897109
+ 4.328757001481123
+ 4.32879394162934
+ 4.328830881341774
+ 4.328867820618439
+ 4.328904759459349
+ 4.3289416978645185
+ 4.328978635833961
+ 4.329015573367689
+ 4.329052510465721
+ 4.329089447128067
+ 4.3291263833547395
+ 4.329163319145757
+ 4.3292002545011306
+ 4.329237189420875
+ 4.329274123905004
+ 4.329311057953531
+ 4.329347991566471
+ 4.329384924743838
+ 4.329421857485645
+ 4.329458789791906
+ 4.329495721662635
+ 4.329532653097848
+ 4.329569584097555
+ 4.329606514661775
+ 4.329643444790516
+ 4.329680374483796
+ 4.329717303741629
+ 4.329754232564026
+ 4.329791160951004
+ 4.329828088902576
+ 4.329865016418754
+ 4.329901943499555
+ 4.329938870144992
+ 4.329975796355077
+ 4.330012722129826
+ 4.330049647469252
+ 4.330086572373371
+ 4.330123496842193
+ 4.330160420875735
+ 4.330197344474009
+ 4.330234267637032
+ 4.330271190364815
+ 4.330308112657373
+ 4.3303450345147185
+ 4.330381955936868
+ 4.330418876923834
+ 4.33045579747563
+ 4.330492717592271
+ 4.33052963727377
+ 4.330566556520141
+ 4.330603475331398
+ 4.330640393707555
+ 4.3306773116486275
+ 4.330714229154627
+ 4.330751146225568
+ 4.330788062861466
+ 4.330824979062332
+ 4.330861894828183
+ 4.330898810159031
+ 4.33093572505489
+ 4.330972639515775
+ 4.3310095535416995
+ 4.331046467132676
+ 4.33108338028872
+ 4.331120293009846
+ 4.3311572052960665
+ 4.331194117147395
+ 4.331231028563846
+ 4.331267939545435
+ 4.331304850092173
+ 4.331341760204077
+ 4.3313786698811585
+ 4.331415579123433
+ 4.331452487930912
+ 4.331489396303612
+ 4.331526304241547
+ 4.331563211744728
+ 4.331600118813172
+ 4.331637025446891
+ 4.331673931645899
+ 4.331710837410212
+ 4.331747742739841
+ 4.331784647634802
+ 4.331821552095108
+ 4.331858456120772
+ 4.33189535971181
+ 4.331932262868235
+ 4.33196916559006
+ 4.3320060678773
+ 4.332042969729968
+ 4.332079871148079
+ 4.332116772131646
+ 4.3321536726806835
+ 4.332190572795204
+ 4.332227472475223
+ 4.332264371720755
+ 4.332301270531811
+ 4.332338168908408
+ 4.332375066850557
+ 4.332411964358274
+ 4.332448861431572
+ 4.332485758070466
+ 4.332522654274968
+ 4.332559550045094
+ 4.332596445380856
+ 4.332633340282269
+ 4.332670234749346
+ 4.3327071287821015
+ 4.332744022380549
+ 4.332780915544704
+ 4.332817808274578
+ 4.332854700570186
+ 4.332891592431542
+ 4.33292848385866
+ 4.332965374851552
+ 4.333002265410234
+ 4.3330391555347205
+ 4.333076045225023
+ 4.333112934481156
+ 4.333149823303136
+ 4.333186711690972
+ 4.333223599644683
+ 4.33326048716428
+ 4.333297374249777
+ 4.333334260901188
+ 4.333371147118527
+ 4.333408032901808
+ 4.333444918251045
+ 4.333481803166252
+ 4.333518687647442
+ 4.333555571694629
+ 4.333592455307828
+ 4.333629338487053
+ 4.333666221232316
+ 4.333703103543631
+ 4.333739985421014
+ 4.3337768668644765
+ 4.333813747874034
+ 4.333850628449699
+ 4.333887508591488
+ 4.333924388299412
+ 4.333961267573485
+ 4.333998146413722
+ 4.334035024820137
+ 4.334071902792744
+ 4.334108780331555
+ 4.3341456574365855
+ 4.33418253410785
+ 4.3342194103453595
+ 4.33425628614913
+ 4.334293161519176
+ 4.334330036455509
+ 4.334366910958146
+ 4.3344037850270976
+ 4.33444065866238
+ 4.334477531864004
+ 4.334514404631988
+ 4.334551276966342
+ 4.334588148867082
+ 4.3346250203342205
+ 4.334661891367772
+ 4.334698761967751
+ 4.334735632134169
+ 4.334772501867043
+ 4.334809371166385
+ 4.334846240032208
+ 4.334883108464528
+ 4.3349199764633575
+ 4.334956844028711
+ 4.3349937111606005
+ 4.335030577859042
+ 4.335067444124049
+ 4.335104309955635
+ 4.335141175353813
+ 4.335178040318599
+ 4.335214904850004
+ 4.335251768948043
+ 4.335288632612732
+ 4.335325495844082
+ 4.335362358642107
+ 4.335399221006822
+ 4.335436082938241
+ 4.335472944436376
+ 4.335509805501243
+ 4.3355466661328546
+ 4.335583526331225
+ 4.335620386096367
+ 4.335657245428296
+ 4.335694104327025
+ 4.335730962792568
+ 4.335767820824939
+ 4.335804678424151
+ 4.33584153559022
+ 4.335878392323156
+ 4.335915248622977
+ 4.335952104489694
+ 4.335988959923322
+ 4.3360258149238735
+ 4.336062669491365
+ 4.336099523625807
+ 4.336136377327215
+ 4.336173230595604
+ 4.336210083430984
+ 4.336246935833374
+ 4.336283787802784
+ 4.336320639339229
+ 4.3363574904427225
+ 4.336394341113279
+ 4.336431191350912
+ 4.336468041155635
+ 4.336504890527462
+ 4.336541739466407
+ 4.336578587972483
+ 4.336615436045705
+ 4.336652283686085
+ 4.33668913089364
+ 4.33672597766838
+ 4.3367628240103215
+ 4.336799669919477
+ 4.336836515395862
+ 4.336873360439488
+ 4.336910205050368
+ 4.33694704922852
+ 4.336983892973954
+ 4.337020736286686
+ 4.3370575791667285
+ 4.337094421614097
+ 4.337131263628803
+ 4.337168105210861
+ 4.337204946360285
+ 4.337241787077089
+ 4.337278627361288
+ 4.3373154672128935
+ 4.337352306631921
+ 4.337389145618382
+ 4.3374259841722935
+ 4.337462822293666
+ 4.337499659982516
+ 4.3375364972388555
+ 4.3375733340627
+ 4.337610170454061
+ 4.337647006412955
+ 4.337683841939393
+ 4.337720677033391
+ 4.337757511694962
+ 4.337794345924119
+ 4.337831179720877
+ 4.337868013085249
+ 4.337904846017249
+ 4.3379416785168905
+ 4.337978510584188
+ 4.338015342219155
+ 4.338052173421805
+ 4.338089004192151
+ 4.338125834530208
+ 4.338162664435989
+ 4.338199493909509
+ 4.338236322950782
+ 4.338273151559819
+ 4.338309979736636
+ 4.338346807481247
+ 4.338383634793663
+ 4.338420461673902
+ 4.338457288121974
+ 4.338494114137895
+ 4.338530939721678
+ 4.338567764873337
+ 4.338604589592886
+ 4.338641413880338
+ 4.338678237735707
+ 4.338715061159007
+ 4.338751884150252
+ 4.338788706709455
+ 4.33882552883663
+ 4.338862350531792
+ 4.338899171794953
+ 4.338935992626127
+ 4.338972813025329
+ 4.33900963299257
+ 4.339046452527868
+ 4.3390832716312335
+ 4.339120090302682
+ 4.3391569085422255
+ 4.33919372634988
+ 4.339230543725656
+ 4.339267360669571
+ 4.339304177181637
+ 4.3393409932618665
+ 4.3393778089102755
+ 4.339414624126876
+ 4.339451438911683
+ 4.339488253264709
+ 4.33952506718597
+ 4.339561880675477
+ 4.339598693733245
+ 4.339635506359287
+ 4.339672318553618
+ 4.339709130316253
+ 4.339745941647201
+ 4.339782752546481
+ 4.339819563014103
+ 4.3398563730500825
+ 4.339893182654433
+ 4.339929991827168
+ 4.339966800568302
+ 4.340003608877847
+ 4.340040416755818
+ 4.340077224202229
+ 4.340114031217094
+ 4.340150837800425
+ 4.340187643952237
+ 4.340224449672544
+ 4.340261254961358
+ 4.340298059818695
+ 4.340334864244567
+ 4.340371668238988
+ 4.340408471801973
+ 4.3404452749335345
+ 4.340482077633687
+ 4.340518879902444
+ 4.340555681739818
+ 4.340592483145824
+ 4.340629284120476
+ 4.340666084663787
+ 4.340702884775771
+ 4.340739684456443
+ 4.340776483705813
+ 4.340813282523898
+ 4.340850080910711
+ 4.340886878866265
+ 4.340923676390576
+ 4.340960473483654
+ 4.3409972701455155
+ 4.3410340663761735
+ 4.341070862175641
+ 4.341107657543932
+ 4.341144452481062
+ 4.341181246987043
+ 4.341218041061889
+ 4.341254834705612
+ 4.3412916279182285
+ 4.341328420699751
+ 4.341365213050194
+ 4.34140200496957
+ 4.3414387964578935
+ 4.341475587515178
+ 4.341512378141437
+ 4.341549168336684
+ 4.341585958100933
+ 4.341622747434198
+ 4.3416595363364925
+ 4.34169632480783
+ 4.341733112848225
+ 4.34176990045769
+ 4.341806687636239
+ 4.341843474383886
+ 4.341880260700645
+ 4.341917046586531
+ 4.341953832041553
+ 4.341990617065729
+ 4.342027401659072
+ 4.342064185821594
+ 4.342100969553312
+ 4.342137752854236
+ 4.342174535724381
+ 4.342211318163762
+ 4.342248100172391
+ 4.342284881750282
+ 4.342321662897449
+ 4.342358443613906
+ 4.3423952238996675
+ 4.342432003754745
+ 4.342468783179153
+ 4.342505562172906
+ 4.342542340736016
+ 4.342579118868499
+ 4.342615896570368
+ 4.342652673841634
+ 4.3426894506823155
+ 4.342726227092423
+ 4.342763003071969
+ 4.342799778620971
+ 4.342836553739439
+ 4.342873328427389
+ 4.342910102684835
+ 4.342946876511788
+ 4.342983649908264
+ 4.343020422874275
+ 4.343057195409837
+ 4.343093967514962
+ 4.3431307391896645
+ 4.343167510433957
+ 4.343204281247854
+ 4.343241051631369
+ 4.3432778215845165
+ 4.343314591107308
+ 4.34335136019976
+ 4.343388128861884
+ 4.343424897093694
+ 4.343461664895206
+ 4.343498432266429
+ 4.343535199207381
+ 4.343571965718074
+ 4.343608731798522
+ 4.343645497448739
+ 4.343682262668737
+ 4.343719027458531
+ 4.3437557918181335
+ 4.34379255574756
+ 4.343829319246823
+ 4.3438660823159365
+ 4.343902844954914
+ 4.34393960716377
+ 4.343976368942515
+ 4.3440131302911675
+ 4.344049891209738
+ 4.34408665169824
+ 4.34412341175669
+ 4.344160171385098
+ 4.34419693058348
+ 4.3442336893518485
+ 4.344270447690218
+ 4.344307205598601
+ 4.344343963077012
+ 4.344380720125466
+ 4.344417476743974
+ 4.344454232932551
+ 4.344490988691211
+ 4.344527744019967
+ 4.344564498918833
+ 4.344601253387822
+ 4.344638007426948
+ 4.344674761036225
+ 4.344711514215667
+ 4.344748266965286
+ 4.344785019285098
+ 4.3448217711751145
+ 4.3448585226353496
+ 4.344895273665818
+ 4.344932024266532
+ 4.344968774437507
+ 4.345005524178754
+ 4.34504227349029
+ 4.345079022372126
+ 4.345115770824276
+ 4.345152518846755
+ 4.345189266439575
+ 4.34522601360275
+ 4.345262760336294
+ 4.345299506640222
+ 4.345336252514546
+ 4.345372997959279
+ 4.345409742974436
+ 4.34544648756003
+ 4.3454832317160745
+ 4.345519975442584
+ 4.345556718739571
+ 4.34559346160705
+ 4.345630204045034
+ 4.345666946053538
+ 4.345703687632573
+ 4.345740428782155
+ 4.3457771695022975
+ 4.345813909793013
+ 4.345850649654315
+ 4.345887389086218
+ 4.345924128088735
+ 4.34596086666188
+ 4.345997604805667
+ 4.346034342520109
+ 4.34607107980522
+ 4.3461078166610125
+ 4.346144553087502
+ 4.346181289084701
+ 4.346218024652622
+ 4.3462547597912815
+ 4.346291494500691
+ 4.346328228780863
+ 4.3463649626318155
+ 4.346401696053557
+ 4.346438429046105
+ 4.346475161609471
+ 4.346511893743669
+ 4.346548625448713
+ 4.346585356724615
+ 4.346622087571392
+ 4.346658817989055
+ 4.346695547977617
+ 4.346732277537094
+ 4.346769006667498
+ 4.346805735368843
+ 4.346842463641144
+ 4.346879191484412
+ 4.346915918898661
+ 4.346952645883906
+ 4.34698937244016
+ 4.347026098567437
+ 4.34706282426575
+ 4.3470995495351135
+ 4.34713627437554
+ 4.347172998787043
+ 4.347209722769637
+ 4.347246446323336
+ 4.347283169448151
+ 4.347319892144099
+ 4.347356614411191
+ 4.347393336249442
+ 4.347430057658865
+ 4.3474667786394745
+ 4.347503499191283
+ 4.347540219314303
+ 4.347576939008552
+ 4.34761365827404
+ 4.3476503771107815
+ 4.34768709551879
+ 4.34772381349808
+ 4.347760531048664
+ 4.347797248170557
+ 4.347833964863771
+ 4.34787068112832
+ 4.347907396964218
+ 4.347944112371479
+ 4.347980827350115
+ 4.348017541900141
+ 4.3480542560215705
+ 4.348090969714417
+ 4.348127682978694
+ 4.348164395814414
+ 4.348201108221592
+ 4.34823782020024
+ 4.348274531750374
+ 4.348311242872005
+ 4.348347953565149
+ 4.348384663829818
+ 4.348421373666025
+ 4.348458083073785
+ 4.348494792053111
+ 4.348531500604017
+ 4.348568208726516
+ 4.348604916420622
+ 4.3486416236863485
+ 4.348678330523709
+ 4.348715036932716
+ 4.348751742913385
+ 4.348788448465728
+ 4.34882515358976
+ 4.348861858285493
+ 4.348898562552941
+ 4.348935266392119
+ 4.348971969803039
+ 4.349008672785716
+ 4.349045375340161
+ 4.349082077466389
+ 4.349118779164415
+ 4.34915548043425
+ 4.349192181275909
+ 4.349228881689407
+ 4.349265581674754
+ 4.349302281231966
+ 4.349338980361057
+ 4.349375679062038
+ 4.349412377334925
+ 4.349449075179731
+ 4.349485772596469
+ 4.349522469585153
+ 4.349559166145796
+ 4.349595862278412
+ 4.349632557983015
+ 4.349669253259617
+ 4.349705948108234
+ 4.349742642528877
+ 4.349779336521561
+ 4.349816030086299
+ 4.349852723223105
+ 4.349889415931992
+ 4.3499261082129745
+ 4.349962800066065
+ 4.349999491491277
+ 4.350036182488625
+ 4.350072873058122
+ 4.350109563199782
+ 4.350146252913617
+ 4.350182942199642
+ 4.350219631057871
+ 4.350256319488316
+ 4.350293007490991
+ 4.35032969506591
+ 4.350366382213087
+ 4.350403068932534
+ 4.350439755224266
+ 4.350476441088295
+ 4.350513126524637
+ 4.350549811533304
+ 4.350586496114309
+ 4.350623180267665
+ 4.350659863993387
+ 4.35069654729149
+ 4.350733230161984
+ 4.350769912604885
+ 4.350806594620204
+ 4.350843276207958
+ 4.350879957368158
+ 4.350916638100819
+ 4.350953318405953
+ 4.350989998283575
+ 4.351026677733698
+ 4.351063356756335
+ 4.3511000353515
+ 4.351136713519207
+ 4.351173391259468
+ 4.351210068572297
+ 4.35124674545771
+ 4.351283421915717
+ 4.351320097946334
+ 4.351356773549573
+ 4.351393448725449
+ 4.351430123473973
+ 4.351466797795161
+ 4.351503471689026
+ 4.35154014515558
+ 4.351576818194839
+ 4.351613490806813
+ 4.351650162991519
+ 4.3516868347489694
+ 4.3517235060791775
+ 4.351760176982158
+ 4.351796847457922
+ 4.351833517506484
+ 4.351870187127858
+ 4.351906856322057
+ 4.351943525089095
+ 4.351980193428985
+ 4.352016861341742
+ 4.352053528827377
+ 4.352090195885905
+ 4.3521268625173395
+ 4.352163528721694
+ 4.352200194498981
+ 4.352236859849215
+ 4.35227352477241
+ 4.352310189268579
+ 4.352346853337734
+ 4.352383516979891
+ 4.352420180195062
+ 4.352456842983259
+ 4.3524935053445
+ 4.352530167278794
+ 4.3525668287861565
+ 4.352603489866602
+ 4.352640150520141
+ 4.3526768107467895
+ 4.35271347054656
+ 4.3527501299194675
+ 4.352786788865523
+ 4.352823447384742
+ 4.352860105477137
+ 4.352896763142721
+ 4.352933420381508
+ 4.352970077193513
+ 4.353006733578747
+ 4.353043389537225
+ 4.35308004506896
+ 4.353116700173967
+ 4.353153354852256
+ 4.353190009103844
+ 4.353226662928742
+ 4.353263316326965
+ 4.353299969298526
+ 4.3533366218434395
+ 4.353373273961716
+ 4.353409925653373
+ 4.3534465769184205
+ 4.353483227756874
+ 4.353519878168745
+ 4.353556528154051
+ 4.353593177712801
+ 4.353629826845011
+ 4.3536664755506935
+ 4.353703123829862
+ 4.35373977168253
+ 4.353776419108712
+ 4.353813066108421
+ 4.35384971268167
+ 4.353886358828472
+ 4.353923004548841
+ 4.353959649842791
+ 4.353996294710335
+ 4.354032939151487
+ 4.354069583166259
+ 4.354106226754666
+ 4.354142869916721
+ 4.354179512652437
+ 4.354216154961828
+ 4.354252796844907
+ 4.354289438301688
+ 4.354326079332184
+ 4.354362719936408
+ 4.3543993601143764
+ 4.354435999866099
+ 4.35447263919159
+ 4.354509278090864
+ 4.354545916563934
+ 4.354582554610814
+ 4.3546191922315165
+ 4.354655829426054
+ 4.354692466194443
+ 4.3547291025366945
+ 4.354765738452823
+ 4.354802373942842
+ 4.354839009006764
+ 4.354875643644603
+ 4.354912277856372
+ 4.3549489116420865
+ 4.354985545001758
+ 4.3550221779354
+ 4.355058810443025
+ 4.355095442524649
+ 4.355132074180284
+ 4.355168705409945
+ 4.3552053362136425
+ 4.355241966591391
+ 4.355278596543206
+ 4.3553152260690995
+ 4.355351855169084
+ 4.355388483843173
+ 4.355425112091383
+ 4.355461739913723
+ 4.355498367310209
+ 4.3555349942808546
+ 4.355571620825673
+ 4.3556082469446755
+ 4.355644872637879
+ 4.355681497905295
+ 4.355718122746938
+ 4.35575474716282
+ 4.355791371152955
+ 4.355827994717357
+ 4.355864617856038
+ 4.355901240569013
+ 4.355937862856295
+ 4.355974484717896
+ 4.356011106153832
+ 4.356047727164115
+ 4.356084347748759
+ 4.356120967907777
+ 4.356157587641181
+ 4.356194206948986
+ 4.356230825831206
+ 4.3562674442878535
+ 4.356304062318943
+ 4.356340679924486
+ 4.356377297104497
+ 4.35641391385899
+ 4.356450530187977
+ 4.356487146091473
+ 4.356523761569489
+ 4.356560376622041
+ 4.356596991249142
+ 4.356633605450805
+ 4.356670219227043
+ 4.35670683257787
+ 4.356743445503298
+ 4.356780058003342
+ 4.356816670078016
+ 4.356853281727331
+ 4.356889892951303
+ 4.356926503749943
+ 4.356963114123267
+ 4.356999724071286
+ 4.3570363335940145
+ 4.357072942691467
+ 4.357109551363655
+ 4.357146159610592
+ 4.357182767432293
+ 4.3572193748287695
+ 4.357255981800037
+ 4.357292588346107
+ 4.3573291944669945
+ 4.357365800162711
+ 4.357402405433272
+ 4.357439010278689
+ 4.357475614698978
+ 4.357512218694149
+ 4.357548822264217
+ 4.357585425409197
+ 4.3576220281291
+ 4.357658630423941
+ 4.3576952322937315
+ 4.357731833738487
+ 4.35776843475822
+ 4.357805035352944
+ 4.3578416355226715
+ 4.357878235267417
+ 4.357914834587194
+ 4.3579514334820155
+ 4.357988031951894
+ 4.358024629996844
+ 4.358061227616879
+ 4.358097824812012
+ 4.358134421582258
+ 4.358171017927627
+ 4.358207613848134
+ 4.358244209343794
+ 4.358280804414617
+ 4.35831739906062
+ 4.358353993281814
+ 4.3583905870782145
+ 4.358427180449832
+ 4.358463773396682
+ 4.358500365918776
+ 4.358536958016131
+ 4.3585735496887565
+ 4.358610140936668
+ 4.358646731759879
+ 4.3586833221584005
+ 4.358719912132249
+ 4.358756501681436
+ 4.358793090805975
+ 4.35882967950588
+ 4.358866267781163
+ 4.35890285563184
+ 4.358939443057922
+ 4.358976030059424
+ 4.359012616636358
+ 4.359049202788738
+ 4.359085788516577
+ 4.35912237381989
+ 4.359158958698687
+ 4.359195543152985
+ 4.359232127182795
+ 4.3592687107881325
+ 4.359305293969008
+ 4.359341876725437
+ 4.3593784590574325
+ 4.359415040965008
+ 4.359451622448176
+ 4.35948820350695
+ 4.359524784141344
+ 4.3595613643513715
+ 4.359597944137045
+ 4.359634523498378
+ 4.359671102435385
+ 4.359707680948078
+ 4.3597442590364714
+ 4.359780836700578
+ 4.3598174139404104
+ 4.359853990755984
+ 4.3598905671473105
+ 4.359927143114403
+ 4.359963718657276
+ 4.360000293775942
+ 4.360036868470415
+ 4.360073442740709
+ 4.360110016586835
+ 4.360146590008808
+ 4.360183163006642
+ 4.360219735580349
+ 4.360256307729944
+ 4.3602928794554385
+ 4.360329450756846
+ 4.360366021634181
+ 4.360402592087456
+ 4.360439162116685
+ 4.36047573172188
+ 4.360512300903056
+ 4.360548869660225
+ 4.360585437993402
+ 4.360622005902599
+ 4.360658573387829
+ 4.360695140449107
+ 4.360731707086445
+ 4.360768273299857
+ 4.360804839089354
+ 4.360841404454954
+ 4.3608779693966655
+ 4.360914533914507
+ 4.360951098008486
+ 4.360987661678619
+ 4.36102422492492
+ 4.361060787747401
+ 4.361097350146077
+ 4.361133912120958
+ 4.36117047367206
+ 4.3612070347993965
+ 4.36124359550298
+ 4.361280155782824
+ 4.3613167156389405
+ 4.3613532750713455
+ 4.36138983408005
+ 4.361426392665068
+ 4.3614629508264136
+ 4.361499508564099
+ 4.361536065878139
+ 4.361572622768545
+ 4.361609179235332
+ 4.361645735278512
+ 4.3616822908980994
+ 4.3617188460941065
+ 4.3617554008665484
+ 4.361791955215436
+ 4.361828509140785
+ 4.3618650626426065
+ 4.3619016157209165
+ 4.361938168375724
+ 4.361974720607048
+ 4.362011272414898
+ 4.362047823799287
+ 4.36208437476023
+ 4.362120925297741
+ 4.362157475411831
+ 4.3621940251025135
+ 4.3622305743698035
+ 4.362267123213715
+ 4.362303671634258
+ 4.362340219631449
+ 4.362376767205299
+ 4.362413314355822
+ 4.362449861083033
+ 4.3624864073869425
+ 4.362522953267566
+ 4.362559498724916
+ 4.362596043759006
+ 4.3626325883698485
+ 4.362669132557458
+ 4.362705676321847
+ 4.362742219663029
+ 4.362778762581018
+ 4.362815305075826
+ 4.362851847147467
+ 4.3628883887959535
+ 4.362924930021301
+ 4.36296147082352
+ 4.3629980112026265
+ 4.363034551158632
+ 4.36307109069155
+ 4.363107629801394
+ 4.363144168488177
+ 4.363180706751914
+ 4.363217244592616
+ 4.363253782010297
+ 4.363290319004971
+ 4.36332685557665
+ 4.363363391725349
+ 4.363399927451081
+ 4.363436462753857
+ 4.363472997633693
+ 4.3635095320906006
+ 4.363546066124594
+ 4.363582599735687
+ 4.363619132923891
+ 4.363655665689221
+ 4.363692198031689
+ 4.36372872995131
+ 4.363765261448096
+ 4.363801792522061
+ 4.3638383231732165
+ 4.363874853401579
+ 4.363911383207157
+ 4.363947912589969
+ 4.363984441550025
+ 4.36402097008734
+ 4.364057498201927
+ 4.364094025893798
+ 4.364130553162967
+ 4.364167080009447
+ 4.364203606433252
+ 4.364240132434395
+ 4.364276658012888
+ 4.364313183168748
+ 4.364349707901983
+ 4.3643862322126115
+ 4.364422756100643
+ 4.364459279566091
+ 4.364495802608971
+ 4.364532325229295
+ 4.364568847427076
+ 4.364605369202328
+ 4.364641890555063
+ 4.364678411485297
+ 4.364714931993039
+ 4.364751452078308
+ 4.364787971741111
+ 4.364824490981465
+ 4.364861009799383
+ 4.364897528194878
+ 4.364934046167963
+ 4.364970563718649
+ 4.365007080846954
+ 4.365043597552888
+ 4.3650801138364645
+ 4.365116629697699
+ 4.365153145136602
+ 4.365189660153186
+ 4.365226174747469
+ 4.365262688919461
+ 4.365299202669174
+ 4.365335715996623
+ 4.365372228901822
+ 4.365408741384782
+ 4.36544525344552
+ 4.365481765084045
+ 4.365518276300373
+ 4.365554787094516
+ 4.365591297466487
+ 4.365627807416301
+ 4.365664316943969
+ 4.3657008260495065
+ 4.365737334732925
+ 4.365773842994239
+ 4.36581035083346
+ 4.365846858250603
+ 4.36588336524568
+ 4.365919871818705
+ 4.365956377969692
+ 4.365992883698652
+ 4.3660293890056
+ 4.36606589389055
+ 4.3661023983535125
+ 4.366138902394503
+ 4.366175406013534
+ 4.366211909210619
+ 4.3662484119857705
+ 4.366284914339002
+ 4.366321416270328
+ 4.36635791777976
+ 4.366394418867312
+ 4.366430919532997
+ 4.3664674197768285
+ 4.36650391959882
+ 4.3665404189989845
+ 4.366576917977334
+ 4.366613416533884
+ 4.366649914668646
+ 4.366686412381634
+ 4.366722909672862
+ 4.36675940654234
+ 4.366795902990085
+ 4.366832399016109
+ 4.366868894620424
+ 4.366905389803045
+ 4.366941884563984
+ 4.366978378903254
+ 4.367014872820871
+ 4.3670513663168435
+ 4.367087859391188
+ 4.367124352043919
+ 4.367160844275045
+ 4.367197336084584
+ 4.367233827472546
+ 4.367270318438946
+ 4.367306808983795
+ 4.36734329910711
+ 4.3673797888089005
+ 4.367416278089181
+ 4.367452766947967
+ 4.367489255385268
+ 4.3675257434011
+ 4.367562230995475
+ 4.367598718168406
+ 4.367635204919906
+ 4.367671691249989
+ 4.3677081771586685
+ 4.367744662645957
+ 4.3677811477118675
+ 4.367817632356414
+ 4.367854116579609
+ 4.367890600381466
+ 4.367927083761999
+ 4.36796356672122
+ 4.368000049259142
+ 4.36803653137578
+ 4.368073013071146
+ 4.368109494345252
+ 4.3681459751981135
+ 4.368182455629742
+ 4.368218935640152
+ 4.3682554152293545
+ 4.368291894397366
+ 4.368328373144197
+ 4.368364851469862
+ 4.3684013293743735
+ 4.368437806857746
+ 4.3684742839199915
+ 4.368510760561122
+ 4.368547236781153
+ 4.368583712580097
+ 4.368620187957968
+ 4.368656662914778
+ 4.368693137450539
+ 4.368729611565267
+ 4.368766085258972
+ 4.36880255853167
+ 4.368839031383374
+ 4.368875503814096
+ 4.368911975823848
+ 4.368948447412647
+ 4.368984918580503
+ 4.36902138932743
+ 4.3690578596534415
+ 4.36909432955855
+ 4.36913079904277
+ 4.369167268106113
+ 4.3692037367485925
+ 4.369240204970224
+ 4.369276672771018
+ 4.369313140150989
+ 4.3693496071101485
+ 4.369386073648512
+ 4.3694225397660915
+ 4.3694590054629
+ 4.3694954707389515
+ 4.369531935594258
+ 4.369568400028834
+ 4.369604864042691
+ 4.369641327635845
+ 4.369677790808306
+ 4.369714253560089
+ 4.369750715891207
+ 4.369787177801672
+ 4.369823639291498
+ 4.369860100360699
+ 4.369896561009288
+ 4.3699330212372764
+ 4.369969481044678
+ 4.370005940431508
+ 4.370042399397777
+ 4.3700788579435
+ 4.370115316068689
+ 4.370151773773357
+ 4.370188231057519
+ 4.370224687921185
+ 4.370261144364372
+ 4.37029760038709
+ 4.370334055989355
+ 4.370370511171177
+ 4.370406965932571
+ 4.37044342027355
+ 4.370479874194127
+ 4.370516327694316
+ 4.370552780774129
+ 4.370589233433578
+ 4.37062568567268
+ 4.370662137491443
+ 4.370698588889886
+ 4.370735039868017
+ 4.370771490425852
+ 4.370807940563404
+ 4.370844390280685
+ 4.370880839577709
+ 4.370917288454489
+ 4.370953736911037
+ 4.3709901849473685
+ 4.371026632563495
+ 4.37106307975943
+ 4.371099526535186
+ 4.3711359728907775
+ 4.371172418826217
+ 4.371208864341518
+ 4.371245309436692
+ 4.371281754111753
+ 4.371318198366716
+ 4.3713546422015925
+ 4.371391085616396
+ 4.371427528611138
+ 4.371463971185834
+ 4.371500413340496
+ 4.371536855075138
+ 4.371573296389772
+ 4.371609737284412
+ 4.371646177759071
+ 4.371682617813761
+ 4.371719057448496
+ 4.37175549666329
+ 4.371791935458155
+ 4.371828373833105
+ 4.371864811788153
+ 4.371901249323311
+ 4.371937686438592
+ 4.37197412313401
+ 4.3720105594095795
+ 4.372046995265312
+ 4.37208343070122
+ 4.372119865717319
+ 4.37215630031362
+ 4.372192734490136
+ 4.372229168246881
+ 4.3722656015838695
+ 4.3723020345011125
+ 4.372338466998624
+ 4.372374899076416
+ 4.372411330734503
+ 4.372447761972898
+ 4.372484192791613
+ 4.372520623190662
+ 4.372557053170059
+ 4.372593482729815
+ 4.372629911869946
+ 4.372666340590461
+ 4.3727027688913775
+ 4.372739196772706
+ 4.3727756242344595
+ 4.372812051276653
+ 4.372848477899297
+ 4.372884904102408
+ 4.372921329885996
+ 4.372957755250075
+ 4.3729941801946595
+ 4.373030604719762
+ 4.373067028825393
+ 4.37310345251157
+ 4.373139875778302
+ 4.373176298625606
+ 4.373212721053492
+ 4.373249143061974
+ 4.3732855646510655
+ 4.3733219858207795
+ 4.373358406571129
+ 4.373394826902127
+ 4.373431246813787
+ 4.373467666306122
+ 4.373504085379145
+ 4.373540504032869
+ 4.373576922267307
+ 4.373613340082471
+ 4.373649757478378
+ 4.373686174455037
+ 4.373722591012463
+ 4.373759007150668
+ 4.373795422869666
+ 4.37383183816947
+ 4.373868253050093
+ 4.373904667511548
+ 4.373941081553848
+ 4.373977495177006
+ 4.374013908381036
+ 4.37405032116595
+ 4.374086733531763
+ 4.374123145478484
+ 4.374159557006131
+ 4.374195968114714
+ 4.374232378804247
+ 4.374268789074743
+ 4.374305198926215
+ 4.374341608358676
+ 4.374378017372139
+ 4.374414425966617
+ 4.374450834142125
+ 4.374487241898673
+ 4.374523649236277
+ 4.374560056154947
+ 4.3745964626547
+ 4.374632868735545
+ 4.3746692743974975
+ 4.37470567964057
+ 4.374742084464775
+ 4.374778488870127
+ 4.374814892856638
+ 4.374851296424321
+ 4.374887699573191
+ 4.3749241023032575
+ 4.374960504614537
+ 4.37499690650704
+ 4.375033307980782
+ 4.375069709035774
+ 4.37510610967203
+ 4.375142509889563
+ 4.375178909688386
+ 4.375215309068512
+ 4.375251708029954
+ 4.375288106572726
+ 4.375324504696841
+ 4.375360902402309
+ 4.375397299689147
+ 4.375433696557367
+ 4.37547009300698
+ 4.375506489038002
+ 4.375542884650444
+ 4.375579279844319
+ 4.375615674619643
+ 4.375652068976426
+ 4.375688462914681
+ 4.375724856434423
+ 4.375761249535664
+ 4.3757976422184175
+ 4.375834034482695
+ 4.375870426328512
+ 4.3759068177558795
+ 4.375943208764812
+ 4.375979599355323
+ 4.376015989527423
+ 4.376052379281127
+ 4.376088768616448
+ 4.376125157533399
+ 4.376161546031991
+ 4.37619793411224
+ 4.376234321774159
+ 4.376270709017758
+ 4.376307095843053
+ 4.376343482250056
+ 4.3763798682387804
+ 4.3764162538092375
+ 4.376452638961443
+ 4.376489023695409
+ 4.376525408011147
+ 4.376561791908673
+ 4.376598175387997
+ 4.376634558449133
+ 4.376670941092096
+ 4.3767073233168965
+ 4.376743705123549
+ 4.376780086512067
+ 4.3768164674824614
+ 4.376852848034747
+ 4.3768892281689356
+ 4.376925607885042
+ 4.376961987183077
+ 4.376998366063055
+ 4.377034744524989
+ 4.377071122568894
+ 4.377107500194779
+ 4.377143877402659
+ 4.377180254192548
+ 4.377216630564457
+ 4.3772530065184005
+ 4.377289382054391
+ 4.377325757172443
+ 4.377362131872567
+ 4.377398506154777
+ 4.377434880019087
+ 4.377471253465509
+ 4.377507626494056
+ 4.377543999104742
+ 4.3775803712975785
+ 4.377616743072581
+ 4.37765311442976
+ 4.37768948536913
+ 4.377725855890703
+ 4.377762225994493
+ 4.377798595680512
+ 4.377834964948773
+ 4.377871333799292
+ 4.377907702232077
+ 4.377944070247145
+ 4.377980437844507
+ 4.378016805024178
+ 4.378053171786169
+ 4.378089538130493
+ 4.378125904057165
+ 4.378162269566197
+ 4.3781986346576005
+ 4.378234999331391
+ 4.378271363587579
+ 4.37830772742618
+ 4.3783440908472055
+ 4.378380453850669
+ 4.378416816436584
+ 4.378453178604961
+ 4.378489540355816
+ 4.378525901689161
+ 4.378562262605009
+ 4.3785986231033736
+ 4.378634983184267
+ 4.378671342847702
+ 4.378707702093692
+ 4.3787440609222505
+ 4.378780419333389
+ 4.378816777327122
+ 4.378853134903463
+ 4.378889492062423
+ 4.378925848804015
+ 4.378962205128255
+ 4.378998561035154
+ 4.3790349165247235
+ 4.379071271596979
+ 4.379107626251933
+ 4.379143980489597
+ 4.379180334309986
+ 4.379216687713112
+ 4.379253040698988
+ 4.379289393267626
+ 4.379325745419042
+ 4.379362097153245
+ 4.37939844847025
+ 4.379434799370072
+ 4.379471149852721
+ 4.379507499918211
+ 4.379543849566555
+ 4.3795801987977665
+ 4.379616547611858
+ 4.3796528960088414
+ 4.379689243988731
+ 4.379725591551541
+ 4.379761938697282
+ 4.379798285425967
+ 4.379834631737611
+ 4.379870977632227
+ 4.379907323109825
+ 4.379943668170422
+ 4.379980012814027
+ 4.380016357040656
+ 4.38005270085032
+ 4.380089044243034
+ 4.380125387218809
+ 4.380161729777659
+ 4.3801980719195965
+ 4.380234413644635
+ 4.380270754952788
+ 4.380307095844067
+ 4.380343436318486
+ 4.380379776376057
+ 4.380416116016795
+ 4.38045245524071
+ 4.380488794047817
+ 4.38052513243813
+ 4.38056147041166
+ 4.38059780796842
+ 4.3806341451084245
+ 4.380670481831684
+ 4.380706818138214
+ 4.380743154028027
+ 4.380779489501134
+ 4.38081582455755
+ 4.380852159197288
+ 4.38088849342036
+ 4.380924827226779
+ 4.380961160616558
+ 4.380997493589711
+ 4.38103382614625
+ 4.381070158286189
+ 4.381106490009538
+ 4.381142821316314
+ 4.381179152206527
+ 4.381215482680192
+ 4.381251812737321
+ 4.381288142377925
+ 4.381324471602021
+ 4.3813608004096185
+ 4.381397128800733
+ 4.381433456775376
+ 4.381469784333561
+ 4.381506111475299
+ 4.381542438200607
+ 4.381578764509494
+ 4.381615090401976
+ 4.381651415878063
+ 4.381687740937771
+ 4.3817240655811105
+ 4.381760389808096
+ 4.38179671361874
+ 4.381833037013054
+ 4.381869359991053
+ 4.38190568255275
+ 4.381942004698156
+ 4.381978326427285
+ 4.382014647740151
+ 4.382050968636766
+ 4.382087289117143
+ 4.382123609181295
+ 4.382159928829233
+ 4.382196248060974
+ 4.382232566876528
+ 4.382268885275908
+ 4.382305203259128
+ 4.382341520826201
+ 4.382377837977139
+ 4.382414154711957
+ 4.3824504710306655
+ 4.382486786933278
+ 4.382523102419808
+ 4.382559417490268
+ 4.382595732144671
+ 4.382632046383031
+ 4.3826683602053595
+ 4.38270467361167
+ 4.382740986601975
+ 4.382777299176288
+ 4.382813611334622
+ 4.38284992307699
+ 4.382886234403404
+ 4.382922545313878
+ 4.3829588558084245
+ 4.382995165887056
+ 4.383031475549787
+ 4.383067784796629
+ 4.383104093627594
+ 4.383140402042697
+ 4.38317671004195
+ 4.383213017625366
+ 4.383249324792958
+ 4.383285631544739
+ 4.383321937880722
+ 4.383358243800919
+ 4.383394549305344
+ 4.3834308543940095
+ 4.383467159066929
+ 4.383503463324114
+ 4.38353976716558
+ 4.383576070591337
+ 4.383612373601399
+ 4.383648676195779
+ 4.383684978374491
+ 4.3837212801375465
+ 4.383757581484959
+ 4.38379388241674
+ 4.383830182932905
+ 4.383866483033466
+ 4.383902782718435
+ 4.383939081987825
+ 4.383975380841649
+ 4.384011679279921
+ 4.384047977302653
+ 4.384084274909859
+ 4.3841205721015495
+ 4.3841568688777395
+ 4.384193165238441
+ 4.3842294611836685
+ 4.3842657567134315
+ 4.384302051827747
+ 4.384338346526625
+ 4.38437464081008
+ 4.384410934678123
+ 4.384447228130769
+ 4.38448352116803
+ 4.38451981378992
+ 4.38455610599645
+ 4.384592397787633
+ 4.384628689163484
+ 4.384664980124013
+ 4.384701270669235
+ 4.384737560799164
+ 4.38477385051381
+ 4.384810139813187
+ 4.384846428697308
+ 4.384882717166186
+ 4.384919005219834
+ 4.384955292858265
+ 4.3849915800814925
+ 4.385027866889527
+ 4.385064153282384
+ 4.385100439260074
+ 4.385136724822614
+ 4.3851730099700115
+ 4.385209294702283
+ 4.38524557901944
+ 4.385281862921496
+ 4.385318146408464
+ 4.385354429480356
+ 4.385390712137186
+ 4.3854269943789665
+ 4.3854632762057095
+ 4.385499557617429
+ 4.385535838614137
+ 4.3855721191958486
+ 4.385608399362574
+ 4.385644679114326
+ 4.38568095845112
+ 4.385717237372967
+ 4.3857535158798795
+ 4.385789793971872
+ 4.385826071648957
+ 4.385862348911146
+ 4.385898625758453
+ 4.3859349021908915
+ 4.385971178208473
+ 4.386007453811211
+ 4.386043728999118
+ 4.386080003772208
+ 4.386116278130493
+ 4.386152552073986
+ 4.386188825602699
+ 4.386225098716647
+ 4.38626137141584
+ 4.386297643700293
+ 4.3863339155700185
+ 4.38637018702503
+ 4.386406458065339
+ 4.386442728690958
+ 4.386478998901902
+ 4.386515268698183
+ 4.386551538079813
+ 4.386587807046805
+ 4.386624075599173
+ 4.386660343736928
+ 4.386696611460085
+ 4.3867328787686555
+ 4.386769145662654
+ 4.386805412142089
+ 4.38684167820698
+ 4.386877943857334
+ 4.386914209093167
+ 4.3869504739144904
+ 4.386986738321319
+ 4.387023002313663
+ 4.387059265891537
+ 4.387095529054954
+ 4.3871317918039265
+ 4.387168054138466
+ 4.387204316058589
+ 4.387240577564304
+ 4.387276838655625
+ 4.387313099332567
+ 4.387349359595142
+ 4.387385619443361
+ 4.387421878877238
+ 4.387458137896786
+ 4.387494396502019
+ 4.387530654692949
+ 4.387566912469587
+ 4.387603169831948
+ 4.387639426780044
+ 4.387675683313889
+ 4.387711939433494
+ 4.387748195138873
+ 4.38778445043004
+ 4.387820705307004
+ 4.387856959769783
+ 4.387893213818385
+ 4.387929467452826
+ 4.387965720673119
+ 4.388001973479274
+ 4.388038225871306
+ 4.388074477849227
+ 4.388110729413051
+ 4.38814698056279
+ 4.3881832312984566
+ 4.388219481620064
+ 4.388255731527624
+ 4.388291981021153
+ 4.388328230100659
+ 4.3883644787661575
+ 4.388400727017661
+ 4.388436974855183
+ 4.388473222278735
+ 4.388509469288331
+ 4.388545715883981
+ 4.388581962065702
+ 4.388618207833505
+ 4.388654453187402
+ 4.388690698127408
+ 4.388726942653532
+ 4.388763186765791
+ 4.388799430464196
+ 4.388835673748759
+ 4.388871916619495
+ 4.388908159076415
+ 4.388944401119531
+ 4.388980642748859
+ 4.389016883964409
+ 4.389053124766195
+ 4.38908936515423
+ 4.389125605128526
+ 4.389161844689096
+ 4.389198083835954
+ 4.389234322569111
+ 4.389270560888582
+ 4.389306798794378
+ 4.389343036286512
+ 4.389379273364997
+ 4.389415510029846
+ 4.389451746281073
+ 4.3894879821186885
+ 4.389524217542707
+ 4.38956045255314
+ 4.389596687150003
+ 4.3896329213333045
+ 4.389669155103061
+ 4.389705388459284
+ 4.389741621401986
+ 4.3897778539311805
+ 4.389814086046879
+ 4.3898503177490955
+ 4.389886549037843
+ 4.389922779913134
+ 4.389959010374982
+ 4.3899952404233975
+ 4.390031470058395
+ 4.390067699279988
+ 4.3901039280881875
+ 4.390140156483007
+ 4.39017638446446
+ 4.390212612032559
+ 4.390248839187316
+ 4.390285065928746
+ 4.390321292256858
+ 4.390357518171668
+ 4.3903937436731875
+ 4.39042996876143
+ 4.390466193436407
+ 4.390502417698134
+ 4.3905386415466205
+ 4.390574864981882
+ 4.390611088003929
+ 4.390647310612775
+ 4.390683532808434
+ 4.390719754590918
+ 4.39075597596024
+ 4.390792196916411
+ 4.390828417459447
+ 4.390864637589359
+ 4.390900857306159
+ 4.390937076609861
+ 4.390973295500478
+ 4.391009513978021
+ 4.391045732042506
+ 4.391081949693942
+ 4.391118166932345
+ 4.391154383757725
+ 4.3911906001700975
+ 4.391226816169474
+ 4.391263031755867
+ 4.391299246929289
+ 4.391335461689753
+ 4.391371676037274
+ 4.391407889971862
+ 4.391444103493529
+ 4.3914803166022915
+ 4.391516529298159
+ 4.391552741581147
+ 4.391588953451265
+ 4.391625164908529
+ 4.39166137595295
+ 4.39169758658454
+ 4.391733796803314
+ 4.391770006609284
+ 4.391806216002462
+ 4.39184242498286
+ 4.391878633550494
+ 4.391914841705374
+ 4.3919510494475125
+ 4.3919872567769245
+ 4.392023463693621
+ 4.392059670197616
+ 4.392095876288921
+ 4.392132081967549
+ 4.392168287233513
+ 4.392204492086827
+ 4.3922406965275025
+ 4.392276900555552
+ 4.392313104170989
+ 4.392349307373825
+ 4.392385510164075
+ 4.392421712541751
+ 4.392457914506863
+ 4.392494116059428
+ 4.392530317199456
+ 4.39256651792696
+ 4.392602718241954
+ 4.39263891814445
+ 4.39267511763446
+ 4.392711316711998
+ 4.392747515377078
+ 4.39278371362971
+ 4.392819911469906
+ 4.392856108897683
+ 4.39289230591305
+ 4.392928502516021
+ 4.392964698706609
+ 4.393000894484827
+ 4.393037089850687
+ 4.393073284804204
+ 4.393109479345386
+ 4.39314567347425
+ 4.393181867190807
+ 4.39321806049507
+ 4.393254253387053
+ 4.393290445866766
+ 4.393326637934224
+ 4.39336282958944
+ 4.393399020832423
+ 4.393435211663191
+ 4.3934714020817545
+ 4.393507592088125
+ 4.393543781682317
+ 4.393579970864343
+ 4.393616159634214
+ 4.393652347991944
+ 4.393688535937547
+ 4.393724723471034
+ 4.393760910592418
+ 4.393797097301712
+ 4.393833283598927
+ 4.39386946948408
+ 4.393905654957181
+ 4.393941840018242
+ 4.393978024667277
+ 4.394014208904298
+ 4.394050392729318
+ 4.39408657614235
+ 4.394122759143408
+ 4.394158941732502
+ 4.394195123909646
+ 4.394231305674853
+ 4.394267487028135
+ 4.394303667969506
+ 4.394339848498978
+ 4.394376028616564
+ 4.394412208322276
+ 4.394448387616127
+ 4.39448456649813
+ 4.394520744968297
+ 4.3945569230266415
+ 4.394593100673177
+ 4.394629277907915
+ 4.394665454730869
+ 4.394701631142049
+ 4.394737807141472
+ 4.394773982729148
+ 4.39481015790509
+ 4.394846332669312
+ 4.394882507021825
+ 4.394918680962642
+ 4.394954854491777
+ 4.394991027609242
+ 4.395027200315051
+ 4.395063372609214
+ 4.395099544491745
+ 4.395135715962657
+ 4.395171887021963
+ 4.395208057669675
+ 4.395244227905805
+ 4.395280397730368
+ 4.395316567143375
+ 4.395352736144839
+ 4.395388904734773
+ 4.39542507291319
+ 4.395461240680101
+ 4.395497408035521
+ 4.395533574979461
+ 4.395569741511935
+ 4.3956059076329534
+ 4.3956420733425325
+ 4.395678238640682
+ 4.395714403527417
+ 4.395750568002747
+ 4.3957867320666875
+ 4.395822895719251
+ 4.395859058960448
+ 4.395895221790292
+ 4.395931384208798
+ 4.395967546215978
+ 4.396003707811842
+ 4.3960398689964055
+ 4.396076029769679
+ 4.396112190131678
+ 4.396148350082412
+ 4.396184509621897
+ 4.396220668750143
+ 4.396256827467163
+ 4.396292985772972
+ 4.396329143667579
+ 4.396365301151
+ 4.396401458223246
+ 4.396437614884331
+ 4.396473771134266
+ 4.396509926973064
+ 4.396546082400739
+ 4.396582237417302
+ 4.396618392022768
+ 4.396654546217148
+ 4.3966907000004545
+ 4.3967268533727
+ 4.396763006333898
+ 4.396799158884061
+ 4.396835311023202
+ 4.396871462751334
+ 4.396907614068468
+ 4.396943764974618
+ 4.396979915469797
+ 4.397016065554016
+ 4.39705221522729
+ 4.39708836448963
+ 4.397124513341049
+ 4.397160661781559
+ 4.397196809811174
+ 4.397232957429908
+ 4.397269104637768
+ 4.397305251434774
+ 4.397341397820934
+ 4.397377543796262
+ 4.39741368936077
+ 4.397449834514471
+ 4.397485979257379
+ 4.397522123589504
+ 4.397558267510862
+ 4.397594411021463
+ 4.397630554121321
+ 4.397666696810448
+ 4.397702839088857
+ 4.39773898095656
+ 4.397775122413571
+ 4.397811263459901
+ 4.397847404095564
+ 4.397883544320573
+ 4.397919684134939
+ 4.397955823538675
+ 4.397991962531796
+ 4.398028101114312
+ 4.398064239286236
+ 4.398100377047582
+ 4.398136514398361
+ 4.398172651338587
+ 4.398208787868272
+ 4.39824492398743
+ 4.398281059696072
+ 4.398317194994211
+ 4.398353329881859
+ 4.39838946435903
+ 4.398425598425737
+ 4.398461732081991
+ 4.398497865327806
+ 4.3985339981631935
+ 4.398570130588167
+ 4.398606262602739
+ 4.398642394206922
+ 4.398678525400729
+ 4.398714656184172
+ 4.398750786557264
+ 4.3987869165200175
+ 4.398823046072446
+ 4.39885917521456
+ 4.398895303946375
+ 4.3989314322679025
+ 4.398967560179154
+ 4.399003687680144
+ 4.399039814770883
+ 4.399075941451386
+ 4.3991120677216635
+ 4.39914819358173
+ 4.399184319031596
+ 4.399220444071276
+ 4.399256568700783
+ 4.399292692920128
+ 4.399328816729325
+ 4.399364940128385
+ 4.399401063117322
+ 4.399437185696148
+ 4.399473307864876
+ 4.39950942962352
+ 4.399545550972089
+ 4.399581671910599
+ 4.39961779243906
+ 4.399653912557488
+ 4.399690032265894
+ 4.3997261515642885
+ 4.399762270452687
+ 4.3997983889311
+ 4.399834506999543
+ 4.399870624658025
+ 4.399906741906562
+ 4.399942858745164
+ 4.399978975173846
+ 4.400015091192619
+ 4.4000512068014945
+ 4.400087322000489
+ 4.4001234367896105
+ 4.400159551168875
+ 4.400195665138294
+ 4.40023177869788
+ 4.400267891847646
+ 4.400304004587605
+ 4.400340116917768
+ 4.400376228838149
+ 4.40041234034876
+ 4.4004484514496145
+ 4.400484562140724
+ 4.400520672422101
+ 4.40055678229376
+ 4.4005928917557116
+ 4.400629000807969
+ 4.400665109450546
+ 4.400701217683453
+ 4.400737325506705
+ 4.400773432920312
+ 4.400809539924289
+ 4.400845646518648
+ 4.4008817527034
+ 4.40091785847856
+ 4.400953963844139
+ 4.40099006880015
+ 4.401026173346606
+ 4.401062277483519
+ 4.401098381210902
+ 4.401134484528768
+ 4.401170587437129
+ 4.401206689935997
+ 4.4012427920253865
+ 4.4012788937053084
+ 4.401314994975776
+ 4.401351095836801
+ 4.401387196288398
+ 4.401423296330578
+ 4.401459395963355
+ 4.401495495186738
+ 4.401531594000744
+ 4.401567692405383
+ 4.401603790400669
+ 4.401639887986613
+ 4.40167598516323
+ 4.4017120819305315
+ 4.4017481782885275
+ 4.401784274237236
+ 4.401820369776664
+ 4.401856464906826
+ 4.401892559627737
+ 4.401928653939408
+ 4.40196474784185
+ 4.402000841335078
+ 4.402036934419104
+ 4.402073027093938
+ 4.402109119359596
+ 4.40214521121609
+ 4.402181302663431
+ 4.4022173937016325
+ 4.402253484330707
+ 4.402289574550669
+ 4.402325664361527
+ 4.402361753763296
+ 4.402397842755989
+ 4.402433931339619
+ 4.402470019514197
+ 4.402506107279735
+ 4.402542194636248
+ 4.402578281583747
+ 4.4026143681222445
+ 4.402650454251754
+ 4.402686539972288
+ 4.402722625283858
+ 4.402758710186478
+ 4.402794794680158
+ 4.402830878764915
+ 4.402866962440758
+ 4.4029030457077
+ 4.402939128565754
+ 4.402975211014934
+ 4.4030112930552505
+ 4.403047374686716
+ 4.403083455909346
+ 4.40311953672315
+ 4.403155617128141
+ 4.403191697124334
+ 4.403227776711738
+ 4.403263855890368
+ 4.403299934660235
+ 4.403336013021353
+ 4.403372090973735
+ 4.403408168517392
+ 4.403444245652337
+ 4.403480322378582
+ 4.403516398696142
+ 4.403552474605026
+ 4.403588550105249
+ 4.403624625196824
+ 4.403660699879762
+ 4.403696774154075
+ 4.403732848019779
+ 4.403768921476882
+ 4.4038049945254
+ 4.403841067165344
+ 4.4038771393967275
+ 4.403913211219562
+ 4.40394928263386
+ 4.403985353639635
+ 4.4040214242369
+ 4.404057494425666
+ 4.404093564205946
+ 4.404129633577754
+ 4.404165702541101
+ 4.404201771095998
+ 4.4042378392424615
+ 4.404273906980501
+ 4.404309974310132
+ 4.4043460412313635
+ 4.40438210774421
+ 4.4044181738486845
+ 4.404454239544798
+ 4.4044903048325645
+ 4.404526369711995
+ 4.404562434183103
+ 4.404598498245901
+ 4.404634561900402
+ 4.404670625146618
+ 4.404706687984563
+ 4.404742750414247
+ 4.4047788124356835
+ 4.404814874048885
+ 4.404850935253865
+ 4.404886996050635
+ 4.404923056439209
+ 4.404959116419597
+ 4.404995175991814
+ 4.405031235155871
+ 4.40506729391178
+ 4.405103352259557
+ 4.405139410199211
+ 4.405175467730755
+ 4.405211524854203
+ 4.405247581569567
+ 4.405283637876858
+ 4.405319693776091
+ 4.405355749267277
+ 4.40539180435043
+ 4.4054278590255604
+ 4.405463913292682
+ 4.405499967151806
+ 4.4055360206029475
+ 4.405572073646117
+ 4.405608126281328
+ 4.405644178508592
+ 4.405680230327921
+ 4.4057162817393305
+ 4.40575233274283
+ 4.405788383338436
+ 4.405824433526156
+ 4.405860483306005
+ 4.405896532677995
+ 4.405932581642139
+ 4.40596863019845
+ 4.406004678346939
+ 4.406040726087619
+ 4.406076773420504
+ 4.406112820345606
+ 4.406148866862937
+ 4.406184912972508
+ 4.406220958674334
+ 4.406257003968426
+ 4.406293048854797
+ 4.4063290933334605
+ 4.4063651374044275
+ 4.406401181067711
+ 4.406437224323324
+ 4.406473267171278
+ 4.406509309611587
+ 4.406545351644262
+ 4.406581393269316
+ 4.406617434486762
+ 4.406653475296612
+ 4.406689515698879
+ 4.406725555693575
+ 4.406761595280713
+ 4.406797634460305
+ 4.406833673232364
+ 4.406869711596902
+ 4.406905749553932
+ 4.406941787103466
+ 4.406977824245517
+ 4.407013860980098
+ 4.407049897307219
+ 4.407085933226896
+ 4.407121968739139
+ 4.407158003843961
+ 4.407194038541375
+ 4.407230072831394
+ 4.4072661067140295
+ 4.4073021401892944
+ 4.407338173257201
+ 4.407374205917761
+ 4.407410238170988
+ 4.407446270016895
+ 4.407482301455494
+ 4.407518332486798
+ 4.407554363110817
+ 4.407590393327567
+ 4.407626423137057
+ 4.407662452539302
+ 4.4076984815343145
+ 4.407734510122105
+ 4.407770538302688
+ 4.407806566076076
+ 4.40784259344228
+ 4.407878620401313
+ 4.407914646953188
+ 4.4079506730979165
+ 4.407986698835512
+ 4.4080227241659875
+ 4.408058749089355
+ 4.408094773605625
+ 4.408130797714812
+ 4.408166821416929
+ 4.408202844711988
+ 4.408238867600001
+ 4.408274890080979
+ 4.408310912154937
+ 4.408346933821886
+ 4.408382955081841
+ 4.4084189759348105
+ 4.40845499638081
+ 4.40849101641985
+ 4.408527036051946
+ 4.4085630552771065
+ 4.4085990740953465
+ 4.408635092506677
+ 4.408671110511113
+ 4.408707128108665
+ 4.408743145299345
+ 4.408779162083167
+ 4.408815178460143
+ 4.408851194430285
+ 4.408887209993606
+ 4.408923225150117
+ 4.408959239899832
+ 4.408995254242764
+ 4.409031268178924
+ 4.409067281708325
+ 4.40910329483098
+ 4.4091393075469005
+ 4.4091753198561
+ 4.4092113317585895
+ 4.409247343254384
+ 4.4092833543434935
+ 4.409319365025931
+ 4.409355375301709
+ 4.409391385170842
+ 4.409427394633339
+ 4.409463403689216
+ 4.409499412338482
+ 4.409535420581152
+ 4.409571428417238
+ 4.409607435846751
+ 4.409643442869704
+ 4.409679449486113
+ 4.409715455695984
+ 4.409751461499336
+ 4.409787466896176
+ 4.4098234718865195
+ 4.409859476470378
+ 4.409895480647764
+ 4.40993148441869
+ 4.40996748778317
+ 4.4100034907412144
+ 4.410039493292837
+ 4.410075495438049
+ 4.410111497176863
+ 4.410147498509292
+ 4.410183499435348
+ 4.410219499955044
+ 4.410255500068393
+ 4.410291499775407
+ 4.410327499076097
+ 4.4103634979704776
+ 4.410399496458559
+ 4.410435494540356
+ 4.41047149221588
+ 4.410507489485142
+ 4.410543486348157
+ 4.410579482804937
+ 4.410615478855492
+ 4.410651474499837
+ 4.410687469737983
+ 4.410723464569943
+ 4.41075945899573
+ 4.410795453015356
+ 4.410831446628834
+ 4.410867439836175
+ 4.410903432637392
+ 4.410939425032498
+ 4.410975417021505
+ 4.411011408604426
+ 4.411047399781273
+ 4.411083390552057
+ 4.4111193809167935
+ 4.411155370875492
+ 4.411191360428168
+ 4.41122734957483
+ 4.411263338315494
+ 4.41129932665017
+ 4.4113353145788725
+ 4.411371302101612
+ 4.411407289218403
+ 4.411443275929255
+ 4.411479262234184
+ 4.4115152481332
+ 4.411551233626315
+ 4.411587218713543
+ 4.411623203394896
+ 4.411659187670388
+ 4.411695171540027
+ 4.411731155003829
+ 4.411767138061806
+ 4.41180312071397
+ 4.411839102960333
+ 4.411875084800908
+ 4.4119110662357075
+ 4.411947047264743
+ 4.411983027888028
+ 4.412019008105576
+ 4.412054987917395
+ 4.412090967323502
+ 4.412126946323909
+ 4.412162924918625
+ 4.412198903107666
+ 4.4122348808910425
+ 4.4122708582687675
+ 4.412306835240853
+ 4.412342811807312
+ 4.412378787968156
+ 4.4124147637234
+ 4.412450739073052
+ 4.412486714017129
+ 4.41252268855564
+ 4.4125586626886
+ 4.412594636416019
+ 4.412630609737912
+ 4.412666582654288
+ 4.412702555165162
+ 4.412738527270546
+ 4.412774498970452
+ 4.412810470264893
+ 4.4128464411538815
+ 4.412882411637428
+ 4.4129183817155475
+ 4.412954351388251
+ 4.41299032065555
+ 4.413026289517459
+ 4.413062257973989
+ 4.413098226025153
+ 4.413134193670963
+ 4.413170160911432
+ 4.413206127746572
+ 4.413242094176396
+ 4.413278060200914
+ 4.413314025820141
+ 4.41334999103409
+ 4.41338595584277
+ 4.413421920246195
+ 4.41345788424438
+ 4.4134938478373344
+ 4.413529811025071
+ 4.413565773807602
+ 4.413601736184941
+ 4.4136376981571
+ 4.413673659724091
+ 4.413709620885926
+ 4.413745581642618
+ 4.41378154199418
+ 4.413817501940623
+ 4.413853461481961
+ 4.413889420618204
+ 4.413925379349367
+ 4.4139613376754605
+ 4.413997295596499
+ 4.414033253112492
+ 4.414069210223453
+ 4.414105166929396
+ 4.414141123230332
+ 4.414177079126273
+ 4.414213034617232
+ 4.414248989703222
+ 4.414284944384255
+ 4.414320898660342
+ 4.414356852531496
+ 4.414392805997731
+ 4.414428759059057
+ 4.414464711715489
+ 4.414500663967036
+ 4.414536615813715
+ 4.414572567255534
+ 4.414608518292507
+ 4.414644468924648
+ 4.414680419151965
+ 4.414716368974474
+ 4.414752318392189
+ 4.414788267405117
+ 4.414824216013276
+ 4.414860164216674
+ 4.414896112015325
+ 4.414932059409241
+ 4.414968006398436
+ 4.4150039529829215
+ 4.415039899162708
+ 4.415075844937809
+ 4.415111790308239
+ 4.415147735274008
+ 4.415183679835129
+ 4.415219623991614
+ 4.415255567743476
+ 4.415291511090728
+ 4.415327454033379
+ 4.415363396571446
+ 4.415399338704939
+ 4.4154352804338695
+ 4.415471221758251
+ 4.415507162678097
+ 4.415543103193417
+ 4.415579043304225
+ 4.415614983010533
+ 4.415650922312356
+ 4.415686861209703
+ 4.4157227997025865
+ 4.41575873779102
+ 4.4157946754750155
+ 4.415830612754586
+ 4.415866549629743
+ 4.4159024861004985
+ 4.415938422166867
+ 4.415974357828858
+ 4.416010293086486
+ 4.416046227939762
+ 4.4160821623887
+ 4.416118096433309
+ 4.416154030073606
+ 4.416189963309599
+ 4.416225896141303
+ 4.4162618285687305
+ 4.416297760591893
+ 4.416333692210802
+ 4.41636962342547
+ 4.4164055542359115
+ 4.416441484642136
+ 4.4164774146441586
+ 4.41651334424199
+ 4.416549273435642
+ 4.416585202225128
+ 4.41662113061046
+ 4.416657058591651
+ 4.416692986168711
+ 4.4167289133416565
+ 4.416764840110496
+ 4.4168007664752444
+ 4.416836692435911
+ 4.416872617992512
+ 4.416908543145056
+ 4.416944467893558
+ 4.416980392238029
+ 4.417016316178483
+ 4.4170522397149306
+ 4.417088162847383
+ 4.417124085575856
+ 4.41716000790036
+ 4.417195929820906
+ 4.417231851337509
+ 4.41726777245018
+ 4.417303693158932
+ 4.417339613463776
+ 4.417375533364725
+ 4.417411452861791
+ 4.417447371954987
+ 4.417483290644325
+ 4.417519208929818
+ 4.417555126811477
+ 4.417591044289315
+ 4.417626961363345
+ 4.417662878033578
+ 4.417698794300027
+ 4.417734710162705
+ 4.417770625621623
+ 4.417806540676794
+ 4.4178424553282305
+ 4.417878369575944
+ 4.4179142834199485
+ 4.417950196860255
+ 4.417986109896876
+ 4.418022022529823
+ 4.4180579347591085
+ 4.418093846584747
+ 4.4181297580067485
+ 4.418165669025127
+ 4.418201579639894
+ 4.418237489851061
+ 4.418273399658641
+ 4.418309309062646
+ 4.41834521806309
+ 4.418381126659983
+ 4.418417034853339
+ 4.418452942643169
+ 4.418488850029486
+ 4.418524757012302
+ 4.41856066359163
+ 4.418596569767481
+ 4.418632475539869
+ 4.418668380908805
+ 4.418704285874303
+ 4.418740190436372
+ 4.418776094595027
+ 4.4188119983502805
+ 4.418847901702144
+ 4.418883804650628
+ 4.418919707195749
+ 4.418955609337515
+ 4.418991511075941
+ 4.4190274124110385
+ 4.419063313342819
+ 4.419099213871296
+ 4.419135113996481
+ 4.419171013718388
+ 4.419206913037026
+ 4.419242811952411
+ 4.419278710464552
+ 4.419314608573464
+ 4.419350506279158
+ 4.419386403581646
+ 4.4194223004809405
+ 4.419458196977054
+ 4.41949409307
+ 4.4195299887597885
+ 4.419565884046432
+ 4.4196017789299455
+ 4.419637673410339
+ 4.419673567487624
+ 4.4197094611618155
+ 4.419745354432924
+ 4.4197812473009614
+ 4.419817139765941
+ 4.419853031827875
+ 4.419888923486775
+ 4.419924814742655
+ 4.419960705595524
+ 4.419996596045398
+ 4.420032486092287
+ 4.420068375736204
+ 4.4201042649771605
+ 4.4201401538151694
+ 4.420176042250244
+ 4.420211930282394
+ 4.420247817911635
+ 4.420283705137977
+ 4.420319591961433
+ 4.420355478382015
+ 4.420391364399735
+ 4.420427250014605
+ 4.4204631352266395
+ 4.420499020035848
+ 4.420534904442245
+ 4.42057078844584
+ 4.420606672046649
+ 4.42064255524468
+ 4.42067843803995
+ 4.4207143204324675
+ 4.420750202422246
+ 4.420786084009298
+ 4.420821965193636
+ 4.420857845975272
+ 4.420893726354217
+ 4.4209296063304855
+ 4.420965485904089
+ 4.421001365075039
+ 4.421037243843348
+ 4.421073122209029
+ 4.421109000172094
+ 4.421144877732553
+ 4.421180754890423
+ 4.421216631645712
+ 4.421252507998434
+ 4.4212883839486015
+ 4.421324259496226
+ 4.42136013464132
+ 4.421396009383896
+ 4.421431883723966
+ 4.421467757661542
+ 4.421503631196637
+ 4.421539504329263
+ 4.4215753770594315
+ 4.421611249387157
+ 4.421647121312448
+ 4.421682992835321
+ 4.421718863955784
+ 4.421754734673852
+ 4.421790604989538
+ 4.4218264749028515
+ 4.421862344413807
+ 4.421898213522415
+ 4.42193408222869
+ 4.421969950532642
+ 4.422005818434284
+ 4.422041685933628
+ 4.422077553030689
+ 4.422113419725474
+ 4.422149286018
+ 4.422185151908276
+ 4.422221017396317
+ 4.422256882482133
+ 4.422292747165737
+ 4.422328611447142
+ 4.422364475326359
+ 4.422400338803401
+ 4.42243620187828
+ 4.422472064551009
+ 4.4225079268215985
+ 4.422543788690062
+ 4.422579650156412
+ 4.42261551122066
+ 4.422651371882819
+ 4.4226872321429
+ 4.422723092000917
+ 4.422758951456881
+ 4.422794810510804
+ 4.422830669162698
+ 4.422866527412578
+ 4.4229023852604525
+ 4.422938242706336
+ 4.422974099750239
+ 4.4230099563921765
+ 4.423045812632158
+ 4.423081668470197
+ 4.423117523906305
+ 4.423153378940497
+ 4.423189233572781
+ 4.423225087803172
+ 4.42326094163168
+ 4.423296795058321
+ 4.423332648083104
+ 4.423368500706041
+ 4.423404352927147
+ 4.423440204746432
+ 4.423476056163908
+ 4.42351190717959
+ 4.423547757793487
+ 4.423583608005611
+ 4.4236194578159775
+ 4.423655307224596
+ 4.423691156231481
+ 4.423727004836643
+ 4.423762853040094
+ 4.4237987008418465
+ 4.4238345482419135
+ 4.423870395240306
+ 4.423906241837038
+ 4.42394208803212
+ 4.423977933825565
+ 4.424013779217385
+ 4.424049624207592
+ 4.4240854687962
+ 4.424121312983219
+ 4.424157156768661
+ 4.424193000152541
+ 4.424228843134868
+ 4.424264685715656
+ 4.424300527894916
+ 4.424336369672662
+ 4.424372211048905
+ 4.424408052023657
+ 4.42444389259693
+ 4.424479732768738
+ 4.424515572539092
+ 4.424551411908004
+ 4.424587250875486
+ 4.424623089441551
+ 4.4246589276062105
+ 4.424694765369478
+ 4.424730602731363
+ 4.424766439691881
+ 4.424802276251043
+ 4.424838112408859
+ 4.424873948165344
+ 4.42490978352051
+ 4.424945618474368
+ 4.4249814530269305
+ 4.42501728717821
+ 4.425053120928218
+ 4.425088954276967
+ 4.42512478722447
+ 4.425160619770739
+ 4.425196451915785
+ 4.425232283659622
+ 4.42526811500226
+ 4.425303945943714
+ 4.425339776483994
+ 4.425375606623112
+ 4.425411436361081
+ 4.425447265697914
+ 4.4254830946336225
+ 4.425518923168218
+ 4.425554751301712
+ 4.42559057903412
+ 4.425626406365451
+ 4.425662233295719
+ 4.425698059824935
+ 4.425733885953112
+ 4.425769711680261
+ 4.425805537006395
+ 4.425841361931527
+ 4.425877186455669
+ 4.425913010578832
+ 4.425948834301028
+ 4.425984657622271
+ 4.426020480542571
+ 4.426056303061943
+ 4.4260921251803955
+ 4.426127946897943
+ 4.4261637682145984
+ 4.4261995891303725
+ 4.426235409645278
+ 4.426271229759327
+ 4.426307049472531
+ 4.426342868784903
+ 4.426378687696454
+ 4.426414506207198
+ 4.4264503243171465
+ 4.426486142026311
+ 4.426521959334703
+ 4.426557776242338
+ 4.426593592749224
+ 4.426629408855376
+ 4.426665224560805
+ 4.426701039865524
+ 4.426736854769544
+ 4.426772669272879
+ 4.426808483375538
+ 4.426844297077537
+ 4.426880110378885
+ 4.426915923279595
+ 4.4269517357796815
+ 4.426987547879153
+ 4.427023359578024
+ 4.427059170876306
+ 4.427094981774013
+ 4.427130792271154
+ 4.427166602367741
+ 4.427202412063789
+ 4.42723822135931
+ 4.427274030254313
+ 4.427309838748815
+ 4.427345646842823
+ 4.427381454536352
+ 4.427417261829414
+ 4.427453068722021
+ 4.427488875214185
+ 4.427524681305918
+ 4.4275604869972325
+ 4.427596292288141
+ 4.4276320971786545
+ 4.427667901668786
+ 4.427703705758546
+ 4.42773950944795
+ 4.427775312737008
+ 4.427811115625731
+ 4.427846918114135
+ 4.427882720202227
+ 4.427918521890023
+ 4.427954323177534
+ 4.427990124064772
+ 4.42802592455175
+ 4.428061724638479
+ 4.428097524324971
+ 4.428133323611238
+ 4.4281691224972946
+ 4.428204920983151
+ 4.428240719068818
+ 4.428276516754311
+ 4.42831231403964
+ 4.4283481109248175
+ 4.428383907409855
+ 4.428419703494766
+ 4.428455499179562
+ 4.428491294464255
+ 4.428527089348857
+ 4.42856288383338
+ 4.428598677917838
+ 4.428634471602241
+ 4.428670264886602
+ 4.428706057770933
+ 4.428741850255245
+ 4.428777642339552
+ 4.428813434023866
+ 4.4288492253081975
+ 4.42888501619256
+ 4.428920806676965
+ 4.4289565967614255
+ 4.428992386445953
+ 4.429028175730559
+ 4.429063964615256
+ 4.429099753100057
+ 4.429135541184974
+ 4.429171328870017
+ 4.429207116155202
+ 4.429242903040537
+ 4.429278689526037
+ 4.429314475611712
+ 4.429350261297577
+ 4.429386046583642
+ 4.429421831469919
+ 4.42945761595642
+ 4.429493400043159
+ 4.429529183730146
+ 4.429564967017395
+ 4.4296007499049175
+ 4.429636532392724
+ 4.429672314480828
+ 4.429708096169242
+ 4.429743877457978
+ 4.429779658347046
+ 4.429815438836461
+ 4.429851218926235
+ 4.429886998616377
+ 4.429922777906902
+ 4.429958556797822
+ 4.429994335289148
+ 4.430030113380893
+ 4.430065891073068
+ 4.430101668365685
+ 4.430137445258758
+ 4.430173221752298
+ 4.430208997846317
+ 4.430244773540827
+ 4.4302805488358405
+ 4.430316323731369
+ 4.430352098227425
+ 4.4303878723240215
+ 4.430423646021169
+ 4.430459419318881
+ 4.430495192217169
+ 4.430530964716044
+ 4.4305667368155195
+ 4.430602508515607
+ 4.43063827981632
+ 4.430674050717669
+ 4.430709821219666
+ 4.4307455913223235
+ 4.430781361025655
+ 4.430817130329671
+ 4.430852899234383
+ 4.430888667739805
+ 4.430924435845948
+ 4.430960203552823
+ 4.430995970860445
+ 4.431031737768825
+ 4.431067504277973
+ 4.431103270387903
+ 4.431139036098627
+ 4.431174801410157
+ 4.4312105663225045
+ 4.431246330835683
+ 4.431282094949702
+ 4.431317858664577
+ 4.431353621980318
+ 4.431389384896935
+ 4.431425147414445
+ 4.4314609095328565
+ 4.431496671252183
+ 4.431532432572436
+ 4.4315681934936295
+ 4.431603954015772
+ 4.4316397141388775
+ 4.431675473862959
+ 4.431711233188028
+ 4.431746992114094
+ 4.431782750641173
+ 4.431818508769275
+ 4.431854266498414
+ 4.4318900238286
+ 4.431925780759844
+ 4.43196153729216
+ 4.431997293425562
+ 4.432033049160058
+ 4.432068804495663
+ 4.432104559432387
+ 4.432140313970244
+ 4.4321760681092455
+ 4.432211821849403
+ 4.432247575190729
+ 4.432283328133234
+ 4.432319080676933
+ 4.4323548328218365
+ 4.432390584567957
+ 4.432426335915306
+ 4.432462086863896
+ 4.432497837413738
+ 4.432533587564846
+ 4.43256933731723
+ 4.432605086670903
+ 4.432640835625879
+ 4.432676584182167
+ 4.43271233233978
+ 4.4327480800987304
+ 4.432783827459031
+ 4.4328195744206935
+ 4.4328553209837285
+ 4.43289106714815
+ 4.432926812913968
+ 4.432962558281197
+ 4.432998303249847
+ 4.433034047819931
+ 4.4330697919914615
+ 4.43310553576445
+ 4.4331412791389075
+ 4.433177022114848
+ 4.433212764692284
+ 4.433248506871225
+ 4.433284248651684
+ 4.433319990033673
+ 4.433355731017206
+ 4.433391471602292
+ 4.4334272117889455
+ 4.433462951577177
+ 4.433498690966999
+ 4.433534429958424
+ 4.433570168551464
+ 4.4336059067461315
+ 4.433641644542437
+ 4.433677381940393
+ 4.433713118940013
+ 4.4337488555413085
+ 4.43378459174429
+ 4.433820327548971
+ 4.433856062955363
+ 4.433891797963478
+ 4.433927532573328
+ 4.433963266784926
+ 4.433999000598284
+ 4.434034734013413
+ 4.434070467030325
+ 4.434106199649033
+ 4.434141931869548
+ 4.434177663691883
+ 4.43421339511605
+ 4.43424912614206
+ 4.434284856769927
+ 4.43432058699966
+ 4.434356316831273
+ 4.434392046264779
+ 4.434427775300189
+ 4.434463503937514
+ 4.4344992321767664
+ 4.43453496001796
+ 4.434570687461106
+ 4.434606414506216
+ 4.434642141153301
+ 4.434677867402375
+ 4.4347135932534485
+ 4.434749318706535
+ 4.434785043761645
+ 4.434820768418792
+ 4.434856492677987
+ 4.434892216539242
+ 4.434927940002569
+ 4.4349636630679825
+ 4.43499938573549
+ 4.435035108005108
+ 4.435070829876845
+ 4.435106551350716
+ 4.435142272426731
+ 4.435177993104902
+ 4.435213713385242
+ 4.435249433267763
+ 4.435285152752476
+ 4.435320871839394
+ 4.435356590528528
+ 4.4353923088198925
+ 4.435428026713496
+ 4.435463744209353
+ 4.435499461307475
+ 4.435535178007874
+ 4.435570894310561
+ 4.43560661021555
+ 4.435642325722851
+ 4.435678040832478
+ 4.43571375554444
+ 4.435749469858752
+ 4.435785183775426
+ 4.435820897294472
+ 4.435856610415902
+ 4.435892323139731
+ 4.4359280354659685
+ 4.435963747394627
+ 4.435999458925718
+ 4.436035170059254
+ 4.436070880795247
+ 4.4361065911337105
+ 4.4361423010746535
+ 4.43617801061809
+ 4.436213719764032
+ 4.436249428512491
+ 4.4362851368634795
+ 4.436320844817009
+ 4.436356552373091
+ 4.436392259531739
+ 4.436427966292964
+ 4.436463672656778
+ 4.436499378623193
+ 4.436535084192221
+ 4.436570789363875
+ 4.436606494138165
+ 4.436642198515106
+ 4.436677902494707
+ 4.436713606076982
+ 4.436749309261941
+ 4.436785012049597
+ 4.436820714439964
+ 4.436856416433051
+ 4.436892118028872
+ 4.436927819227438
+ 4.436963520028761
+ 4.436999220432853
+ 4.437034920439726
+ 4.437070620049392
+ 4.437106319261864
+ 4.437142018077154
+ 4.43717771649527
+ 4.43721341451623
+ 4.437249112140043
+ 4.43728480936672
+ 4.437320506196275
+ 4.4373562026287185
+ 4.437391898664063
+ 4.4374275943023225
+ 4.437463289543505
+ 4.437498984387625
+ 4.4375346788346945
+ 4.437570372884726
+ 4.437606066537729
+ 4.437641759793718
+ 4.437677452652703
+ 4.437713145114698
+ 4.437748837179713
+ 4.437784528847762
+ 4.437820220118856
+ 4.437855910993006
+ 4.437891601470225
+ 4.437927291550526
+ 4.43796298123392
+ 4.437998670520418
+ 4.438034359410032
+ 4.438070047902777
+ 4.438105735998662
+ 4.4381414236977
+ 4.438177110999901
+ 4.438212797905281
+ 4.438248484413848
+ 4.438284170525617
+ 4.438319856240598
+ 4.4383555415588045
+ 4.438391226480246
+ 4.438426911004938
+ 4.438462595132889
+ 4.438498278864114
+ 4.438533962198623
+ 4.438569645136428
+ 4.438605327677542
+ 4.438641009821976
+ 4.438676691569742
+ 4.438712372920852
+ 4.43874805387532
+ 4.438783734433156
+ 4.438819414594372
+ 4.4388550943589795
+ 4.438890773726992
+ 4.4389264526984205
+ 4.438962131273277
+ 4.438997809451574
+ 4.439033487233322
+ 4.439069164618535
+ 4.439104841607223
+ 4.4391405181994
+ 4.439176194395078
+ 4.439211870194265
+ 4.439247545596977
+ 4.439283220603226
+ 4.439318895213021
+ 4.439354569426378
+ 4.439390243243305
+ 4.439425916663815
+ 4.439461589687921
+ 4.439497262315635
+ 4.4395329345469685
+ 4.439568606381934
+ 4.439604277820543
+ 4.439639948862807
+ 4.439675619508736
+ 4.439711289758348
+ 4.439746959611648
+ 4.439782629068652
+ 4.439818298129373
+ 4.4398539667938195
+ 4.439889635062005
+ 4.439925302933942
+ 4.439960970409641
+ 4.439996637489116
+ 4.4400323041723775
+ 4.440067970459436
+ 4.440103636350307
+ 4.440139301845002
+ 4.440174966943529
+ 4.440210631645904
+ 4.440246295952137
+ 4.440281959862239
+ 4.440317623376226
+ 4.440353286494106
+ 4.440388949215891
+ 4.440424611541596
+ 4.440460273471231
+ 4.440495935004807
+ 4.440531596142338
+ 4.440567256883835
+ 4.440602917229309
+ 4.440638577178772
+ 4.44067423673224
+ 4.440709895889719
+ 4.440745554651223
+ 4.440781213016766
+ 4.4408168709863585
+ 4.440852528560012
+ 4.440888185737739
+ 4.4409238425195525
+ 4.440959498905462
+ 4.4409951548954805
+ 4.44103081048962
+ 4.441066465687893
+ 4.44110212049031
+ 4.441137774896886
+ 4.441173428907629
+ 4.441209082522553
+ 4.44124473574167
+ 4.441280388564991
+ 4.441316040992529
+ 4.441351693024296
+ 4.441387344660302
+ 4.4414229959005604
+ 4.441458646745084
+ 4.441494297193883
+ 4.441529947246971
+ 4.441565596904357
+ 4.441601246166057
+ 4.4416368950320795
+ 4.441672543502438
+ 4.441708191577144
+ 4.44174383925621
+ 4.441779486539647
+ 4.441815133427468
+ 4.441850779919685
+ 4.441886426016308
+ 4.44192207171735
+ 4.441957717022824
+ 4.44199336193274
+ 4.442029006447112
+ 4.44206465056595
+ 4.442100294289267
+ 4.442135937617074
+ 4.442171580549385
+ 4.442207223086209
+ 4.44224286522756
+ 4.442278506973449
+ 4.442314148323889
+ 4.44234978927889
+ 4.442385429838466
+ 4.442421070002627
+ 4.4424567097713865
+ 4.442492349144755
+ 4.4425279881227455
+ 4.442563626705371
+ 4.44259926489264
+ 4.442634902684567
+ 4.4426705400811635
+ 4.4427061770824405
+ 4.442741813688411
+ 4.4427774498990855
+ 4.442813085714478
+ 4.4428487211346
+ 4.44288435615946
+ 4.4429199907890755
+ 4.442955625023455
+ 4.44299125886261
+ 4.443026892306553
+ 4.443062525355296
+ 4.443098158008851
+ 4.443133790267231
+ 4.443169422130446
+ 4.443205053598509
+ 4.443240684671432
+ 4.443276315349226
+ 4.443311945631904
+ 4.443347575519477
+ 4.443383205011957
+ 4.443418834109356
+ 4.443454462811685
+ 4.443490091118959
+ 4.443525719031187
+ 4.443561346548381
+ 4.443596973670553
+ 4.443632600397717
+ 4.4436682267298835
+ 4.443703852667063
+ 4.4437394782092685
+ 4.443775103356513
+ 4.443810728108807
+ 4.443846352466162
+ 4.4438819764285915
+ 4.443917599996106
+ 4.443953223168719
+ 4.44398884594644
+ 4.444024468329283
+ 4.444060090317258
+ 4.4440957119103786
+ 4.444131333108656
+ 4.444166953912101
+ 4.4442025743207285
+ 4.444238194334547
+ 4.44427381395357
+ 4.444309433177811
+ 4.444345052007278
+ 4.444380670441985
+ 4.4444162884819445
+ 4.444451906127167
+ 4.444487523377666
+ 4.444523140233452
+ 4.444558756694536
+ 4.444594372760934
+ 4.444629988432653
+ 4.444665603709708
+ 4.444701218592108
+ 4.444736833079868
+ 4.444772447172999
+ 4.4448080608715115
+ 4.444843674175419
+ 4.444879287084732
+ 4.444914899599463
+ 4.4449505117196235
+ 4.4449861234452275
+ 4.445021734776283
+ 4.445057345712805
+ 4.445092956254805
+ 4.445128566402293
+ 4.4451641761552825
+ 4.445199785513784
+ 4.445235394477812
+ 4.445271003047376
+ 4.445306611222488
+ 4.44534221900316
+ 4.4453778263894055
+ 4.445413433381234
+ 4.4454490399786595
+ 4.445484646181692
+ 4.445520251990344
+ 4.445555857404628
+ 4.445591462424555
+ 4.445627067050137
+ 4.4456626712813865
+ 4.445698275118315
+ 4.445733878560935
+ 4.445769481609256
+ 4.445805084263292
+ 4.445840686523055
+ 4.445876288388556
+ 4.445911889859806
+ 4.4459474909368195
+ 4.445983091619606
+ 4.446018691908178
+ 4.446054291802547
+ 4.446089891302726
+ 4.446125490408726
+ 4.446161089120559
+ 4.446196687438237
+ 4.446232285361771
+ 4.446267882891173
+ 4.446303480026457
+ 4.446339076767632
+ 4.446374673114712
+ 4.446410269067707
+ 4.4464458646266305
+ 4.446481459791492
+ 4.446517054562307
+ 4.446552648939084
+ 4.446588242921837
+ 4.446623836510576
+ 4.446659429705314
+ 4.446695022506063
+ 4.446730614912833
+ 4.4467662069256395
+ 4.446801798544491
+ 4.446837389769399
+ 4.4468729806003795
+ 4.44690857103744
+ 4.446944161080594
+ 4.446979750729854
+ 4.4470153399852315
+ 4.447050928846736
+ 4.447086517314383
+ 4.447122105388182
+ 4.447157693068146
+ 4.447193280354286
+ 4.447228867246613
+ 4.447264453745142
+ 4.44730003984988
+ 4.447335625560844
+ 4.4473712108780425
+ 4.447406795801488
+ 4.447442380331194
+ 4.4474779644671685
+ 4.447513548209427
+ 4.44754913155798
+ 4.447584714512839
+ 4.447620297074017
+ 4.447655879241525
+ 4.447691461015373
+ 4.447727042395577
+ 4.447762623382145
+ 4.447798203975091
+ 4.447833784174426
+ 4.447869363980161
+ 4.44790494339231
+ 4.4479405224108834
+ 4.447976101035893
+ 4.448011679267351
+ 4.448047257105268
+ 4.448082834549658
+ 4.4481184116005315
+ 4.4481539882579
+ 4.448189564521775
+ 4.448225140392171
+ 4.448260715869096
+ 4.448296290952564
+ 4.448331865642587
+ 4.448367439939178
+ 4.448403013842344
+ 4.4484385873521015
+ 4.448474160468461
+ 4.448509733191433
+ 4.448545305521032
+ 4.4485808774572675
+ 4.448616449000151
+ 4.448652020149697
+ 4.448687590905915
+ 4.448723161268816
+ 4.4487587312384145
+ 4.448794300814721
+ 4.448829869997747
+ 4.4488654387875055
+ 4.4489010071840065
+ 4.448936575187262
+ 4.448972142797286
+ 4.4490077100140875
+ 4.449043276837681
+ 4.449078843268076
+ 4.4491144093052855
+ 4.449149974949321
+ 4.449185540200194
+ 4.449221105057917
+ 4.4492566695225015
+ 4.449292233593958
+ 4.449327797272301
+ 4.449363360557539
+ 4.449398923449688
+ 4.449434485948756
+ 4.449470048054757
+ 4.4495056097677015
+ 4.4495411710876
+ 4.449576732014469
+ 4.4496122925483155
+ 4.449647852689153
+ 4.449683412436994
+ 4.4497189717918495
+ 4.449754530753732
+ 4.4497900893226525
+ 4.449825647498622
+ 4.449861205281655
+ 4.449896762671761
+ 4.449932319668952
+ 4.449967876273241
+ 4.450003432484639
+ 4.450038988303157
+ 4.450074543728808
+ 4.450110098761603
+ 4.450145653401555
+ 4.450181207648674
+ 4.450216761502972
+ 4.450252314964463
+ 4.450287868033157
+ 4.450323420709065
+ 4.450358972992201
+ 4.450394524882575
+ 4.450430076380199
+ 4.450465627485086
+ 4.450501178197246
+ 4.450536728516693
+ 4.450572278443435
+ 4.450607827977488
+ 4.450643377118862
+ 4.450678925867569
+ 4.45071447422362
+ 4.450750022187027
+ 4.450785569757802
+ 4.450821116935957
+ 4.450856663721504
+ 4.450892210114454
+ 4.450927756114821
+ 4.450963301722613
+ 4.450998846937844
+ 4.451034391760525
+ 4.451069936190669
+ 4.451105480228287
+ 4.451141023873391
+ 4.451176567125992
+ 4.451212109986103
+ 4.451247652453734
+ 4.451283194528898
+ 4.451318736211607
+ 4.451354277501872
+ 4.451389818399706
+ 4.451425358905119
+ 4.451460899018124
+ 4.451496438738733
+ 4.451531978066956
+ 4.451567517002807
+ 4.451603055546296
+ 4.451638593697435
+ 4.451674131456237
+ 4.451709668822713
+ 4.451745205796874
+ 4.451780742378733
+ 4.4518162785683
+ 4.45185181436559
+ 4.451887349770611
+ 4.451922884783377
+ 4.4519584194038995
+ 4.451993953632189
+ 4.452029487468259
+ 4.452065020912121
+ 4.452100553963786
+ 4.452136086623265
+ 4.452171618890572
+ 4.452207150765716
+ 4.452242682248712
+ 4.452278213339569
+ 4.4523137440383
+ 4.452349274344916
+ 4.452384804259429
+ 4.452420333781851
+ 4.452455862912195
+ 4.45249139165047
+ 4.452526919996689
+ 4.452562447950866
+ 4.452597975513008
+ 4.452633502683131
+ 4.452669029461245
+ 4.452704555847362
+ 4.452740081841494
+ 4.45277560744365
+ 4.452811132653847
+ 4.452846657472093
+ 4.452882181898399
+ 4.45291770593278
+ 4.452953229575246
+ 4.452988752825808
+ 4.453024275684479
+ 4.45305979815127
+ 4.453095320226193
+ 4.45313084190926
+ 4.453166363200482
+ 4.453201884099872
+ 4.45323740460744
+ 4.453272924723199
+ 4.453308444447161
+ 4.453343963779336
+ 4.453379482719737
+ 4.453415001268377
+ 4.453450519425265
+ 4.453486037190414
+ 4.453521554563836
+ 4.453557071545543
+ 4.453592588135546
+ 4.453628104333857
+ 4.453663620140486
+ 4.453699135555448
+ 4.453734650578753
+ 4.453770165210413
+ 4.453805679450439
+ 4.453841193298843
+ 4.453876706755637
+ 4.453912219820834
+ 4.453947732494443
+ 4.453983244776479
+ 4.45401875666695
+ 4.454054268165871
+ 4.454089779273252
+ 4.454125289989103
+ 4.45416080031344
+ 4.454196310246272
+ 4.45423181978761
+ 4.454267328937469
+ 4.454302837695857
+ 4.454338346062788
+ 4.4543738540382725
+ 4.454409361622322
+ 4.454444868814951
+ 4.454480375616169
+ 4.454515882025986
+ 4.454551388044417
+ 4.454586893671472
+ 4.454622398907163
+ 4.454657903751501
+ 4.454693408204499
+ 4.4547289122661695
+ 4.454764415936521
+ 4.454799919215567
+ 4.45483542210332
+ 4.454870924599791
+ 4.454906426704992
+ 4.4549419284189335
+ 4.4549774297416285
+ 4.455012930673089
+ 4.455048431213324
+ 4.455083931362348
+ 4.455119431120173
+ 4.455154930486809
+ 4.455190429462268
+ 4.455225928046562
+ 4.455261426239703
+ 4.455296924041702
+ 4.455332421452571
+ 4.455367918472322
+ 4.455403415100967
+ 4.455438911338517
+ 4.455474407184983
+ 4.455509902640378
+ 4.455545397704714
+ 4.455580892378
+ 4.455616386660252
+ 4.455651880551478
+ 4.455687374051691
+ 4.455722867160903
+ 4.455758359879126
+ 4.45579385220637
+ 4.455829344142648
+ 4.455864835687972
+ 4.455900326842354
+ 4.455935817605804
+ 4.455971307978333
+ 4.456006797959956
+ 4.456042287550682
+ 4.456077776750525
+ 4.456113265559494
+ 4.456148753977602
+ 4.456184242004861
+ 4.456219729641283
+ 4.456255216886878
+ 4.456290703741659
+ 4.456326190205638
+ 4.456361676278825
+ 4.456397161961233
+ 4.456432647252873
+ 4.456468132153758
+ 4.4565036166639
+ 4.456539100783307
+ 4.456574584511994
+ 4.456610067849973
+ 4.456645550797253
+ 4.456681033353847
+ 4.456716515519768
+ 4.456751997295027
+ 4.456787478679634
+ 4.456822959673602
+ 4.4568584402769424
+ 4.456893920489668
+ 4.456929400311788
+ 4.4569648797433175
+ 4.457000358784264
+ 4.457035837434643
+ 4.4570713156944635
+ 4.457106793563739
+ 4.45714227104248
+ 4.457177748130699
+ 4.457213224828408
+ 4.457248701135616
+ 4.457284177052338
+ 4.457319652578585
+ 4.457355127714366
+ 4.457390602459696
+ 4.457426076814585
+ 4.457461550779044
+ 4.457497024353086
+ 4.457532497536722
+ 4.457567970329964
+ 4.4576034427328235
+ 4.457638914745313
+ 4.457674386367444
+ 4.457709857599226
+ 4.457745328440672
+ 4.457780798891794
+ 4.457816268952604
+ 4.457851738623114
+ 4.457887207903333
+ 4.4579226767932765
+ 4.457958145292953
+ 4.457993613402375
+ 4.4580290811215555
+ 4.458064548450504
+ 4.458100015389234
+ 4.458135481937756
+ 4.4581709480960825
+ 4.458206413864224
+ 4.458241879242194
+ 4.458277344230002
+ 4.458312808827661
+ 4.458348273035182
+ 4.458383736852578
+ 4.458419200279859
+ 4.4584546633170365
+ 4.458490125964124
+ 4.458525588221132
+ 4.458561050088071
+ 4.458596511564955
+ 4.458631972651794
+ 4.458667433348601
+ 4.458702893655386
+ 4.458738353572161
+ 4.458773813098939
+ 4.4588092722357295
+ 4.458844730982547
+ 4.458880189339402
+ 4.458915647306304
+ 4.4589511048832655
+ 4.4589865620703
+ 4.459022018867419
+ 4.459057475274631
+ 4.459092931291952
+ 4.45912838691939
+ 4.4591638421569595
+ 4.459199297004669
+ 4.459234751462533
+ 4.4592702055305615
+ 4.459305659208767
+ 4.459341112497161
+ 4.459376565395754
+ 4.45941201790456
+ 4.459447470023588
+ 4.45948292175285
+ 4.459518373092361
+ 4.459553824042128
+ 4.459589274602165
+ 4.4596247247724845
+ 4.459660174553095
+ 4.459695623944012
+ 4.459731072945244
+ 4.459766521556804
+ 4.459801969778704
+ 4.459837417610955
+ 4.459872865053569
+ 4.459908312106557
+ 4.45994375876993
+ 4.459979205043702
+ 4.460014650927882
+ 4.460050096422483
+ 4.460085541527517
+ 4.460120986242996
+ 4.4601564305689285
+ 4.4601918745053295
+ 4.46022731805221
+ 4.460262761209581
+ 4.4602982039774535
+ 4.460333646355839
+ 4.460369088344752
+ 4.4604045299442
+ 4.460439971154197
+ 4.460475411974755
+ 4.460510852405886
+ 4.4605462924475985
+ 4.460581732099906
+ 4.460617171362821
+ 4.460652610236355
+ 4.460688048720518
+ 4.460723486815322
+ 4.46075892452078
+ 4.4607943618369035
+ 4.460829798763703
+ 4.460865235301188
+ 4.460900671449376
+ 4.460936107208273
+ 4.460971542577894
+ 4.461006977558249
+ 4.46104241214935
+ 4.461077846351209
+ 4.461113280163837
+ 4.461148713587245
+ 4.461184146621447
+ 4.4612195792664515
+ 4.461255011522273
+ 4.461290443388921
+ 4.461325874866408
+ 4.461361305954745
+ 4.4613967366539455
+ 4.461432166964018
+ 4.461467596884978
+ 4.461503026416833
+ 4.461538455559597
+ 4.461573884313281
+ 4.461609312677896
+ 4.461644740653455
+ 4.461680168239968
+ 4.461715595437449
+ 4.461751022245907
+ 4.461786448665355
+ 4.461821874695803
+ 4.4618573003372655
+ 4.461892725589752
+ 4.461928150453274
+ 4.461963574927843
+ 4.461998999013472
+ 4.462034422710172
+ 4.462069846017955
+ 4.46210526893683
+ 4.4621406914668125
+ 4.462176113607911
+ 4.462211535360138
+ 4.462246956723507
+ 4.462282377698027
+ 4.46231779828371
+ 4.462353218480568
+ 4.462388638288613
+ 4.462424057707856
+ 4.462459476738309
+ 4.462494895379983
+ 4.462530313632891
+ 4.462565731497044
+ 4.4626011489724515
+ 4.462636566059127
+ 4.462671982757083
+ 4.462707399066328
+ 4.462742814986877
+ 4.46277823051874
+ 4.462813645661928
+ 4.4628490604164535
+ 4.462884474782329
+ 4.462919888759563
+ 4.46295530234817
+ 4.46299071554816
+ 4.4630261283595445
+ 4.463061540782337
+ 4.463096952816547
+ 4.4631323644621865
+ 4.463167775719268
+ 4.463203186587803
+ 4.463238597067801
+ 4.463274007159277
+ 4.463309416862239
+ 4.463344826176701
+ 4.463380235102673
+ 4.463415643640169
+ 4.463451051789198
+ 4.463486459549772
+ 4.463521866921903
+ 4.463557273905604
+ 4.463592680500884
+ 4.4636280867077565
+ 4.463663492526233
+ 4.463698897956323
+ 4.46373430299804
+ 4.4637697076513945
+ 4.4638051119163995
+ 4.463840515793065
+ 4.463875919281404
+ 4.463911322381427
+ 4.463946725093145
+ 4.463982127416571
+ 4.464017529351716
+ 4.464052930898592
+ 4.46408833205721
+ 4.464123732827582
+ 4.4641591332097175
+ 4.46419453320363
+ 4.4642299328093324
+ 4.464265332026834
+ 4.464300730856146
+ 4.464336129297282
+ 4.464371527350252
+ 4.464406925015068
+ 4.464442322291742
+ 4.464477719180286
+ 4.46451311568071
+ 4.4645485117930255
+ 4.4645839075172455
+ 4.464619302853381
+ 4.464654697801443
+ 4.464690092361445
+ 4.464725486533395
+ 4.464760880317307
+ 4.464796273713193
+ 4.4648316667210635
+ 4.46486705934093
+ 4.4649024515728035
+ 4.464937843416698
+ 4.464973234872622
+ 4.465008625940589
+ 4.465044016620609
+ 4.465079406912696
+ 4.4651147968168585
+ 4.46515018633311
+ 4.465185575461462
+ 4.465220964201927
+ 4.465256352554513
+ 4.465291740519234
+ 4.465327128096101
+ 4.465362515285127
+ 4.465397902086322
+ 4.465433288499698
+ 4.465468674525266
+ 4.465504060163038
+ 4.465539445413025
+ 4.465574830275241
+ 4.465610214749693
+ 4.465645598836397
+ 4.465680982535361
+ 4.465716365846599
+ 4.465751748770122
+ 4.465787131305941
+ 4.465822513454068
+ 4.465857895214513
+ 4.46589327658729
+ 4.465928657572409
+ 4.465964038169882
+ 4.46599941837972
+ 4.466034798201936
+ 4.466070177636539
+ 4.466105556683543
+ 4.466140935342957
+ 4.466176313614795
+ 4.466211691499068
+ 4.466247068995787
+ 4.466282446104963
+ 4.466317822826609
+ 4.466353199160734
+ 4.466388575107352
+ 4.466423950666474
+ 4.466459325838112
+ 4.466494700622275
+ 4.466530075018977
+ 4.46656544902823
+ 4.466600822650042
+ 4.466636195884427
+ 4.466671568731398
+ 4.466706941190965
+ 4.466742313263136
+ 4.466777684947929
+ 4.466813056245352
+ 4.466848427155416
+ 4.466883797678134
+ 4.466919167813517
+ 4.466954537561576
+ 4.466989906922323
+ 4.46702527589577
+ 4.4670606444819265
+ 4.467096012680806
+ 4.467131380492421
+ 4.467166747916781
+ 4.4672021149538965
+ 4.467237481603782
+ 4.467272847866448
+ 4.4673082137419025
+ 4.467343579230162
+ 4.467378944331237
+ 4.467414309045137
+ 4.467449673371875
+ 4.467485037311462
+ 4.467520400863909
+ 4.467555764029228
+ 4.467591126807431
+ 4.467626489198529
+ 4.467661851202533
+ 4.4676972128194565
+ 4.4677325740493075
+ 4.467767934892102
+ 4.467803295347847
+ 4.467838655416557
+ 4.467874015098242
+ 4.467909374392915
+ 4.467944733300587
+ 4.467980091821267
+ 4.468015449954969
+ 4.468050807701705
+ 4.468086165061485
+ 4.468121522034322
+ 4.468156878620226
+ 4.468192234819208
+ 4.468227590631282
+ 4.468262946056457
+ 4.4682983010947455
+ 4.468333655746159
+ 4.46836901001071
+ 4.468404363888408
+ 4.468439717379266
+ 4.4684750704832945
+ 4.468510423200506
+ 4.468545775530911
+ 4.468581127474521
+ 4.468616479031349
+ 4.468651830201404
+ 4.4686871809847
+ 4.468722531381246
+ 4.468757881391056
+ 4.46879323101414
+ 4.468828580250511
+ 4.468863929100178
+ 4.468899277563153
+ 4.4689346256394495
+ 4.468969973329078
+ 4.469005320632049
+ 4.4690406675483745
+ 4.469076014078067
+ 4.469111360221137
+ 4.469146705977596
+ 4.469182051347455
+ 4.469217396330726
+ 4.4692527409274225
+ 4.469288085137552
+ 4.469323428961129
+ 4.469358772398163
+ 4.469394115448667
+ 4.469429458112653
+ 4.46946480039013
+ 4.469500142281111
+ 4.469535483785608
+ 4.469570824903631
+ 4.469606165635193
+ 4.469641505980304
+ 4.469676845938977
+ 4.469712185511223
+ 4.469747524697053
+ 4.469782863496477
+ 4.46981820190951
+ 4.469853539936161
+ 4.469888877576442
+ 4.469924214830365
+ 4.46995955169794
+ 4.46999488817918
+ 4.470030224274097
+ 4.470065559982699
+ 4.470100895305001
+ 4.470136230241013
+ 4.470171564790748
+ 4.470206898954215
+ 4.470242232731428
+ 4.470277566122395
+ 4.470312899127132
+ 4.470348231745646
+ 4.470383563977951
+ 4.470418895824059
+ 4.470454227283979
+ 4.470489558357725
+ 4.470524889045307
+ 4.470560219346737
+ 4.4705955492620255
+ 4.470630878791185
+ 4.470666207934227
+ 4.470701536691163
+ 4.470736865062003
+ 4.470772193046761
+ 4.470807520645446
+ 4.47084284785807
+ 4.470878174684646
+ 4.4709135011251835
+ 4.470948827179694
+ 4.4709841528481915
+ 4.4710194781306845
+ 4.471054803027187
+ 4.471090127537709
+ 4.47112545166226
+ 4.471160775400855
+ 4.471196098753503
+ 4.471231421720217
+ 4.4712667443010075
+ 4.471302066495887
+ 4.471337388304866
+ 4.471372709727955
+ 4.471408030765168
+ 4.471443351416514
+ 4.471478671682006
+ 4.471513991561655
+ 4.4715493110554725
+ 4.471584630163469
+ 4.471619948885658
+ 4.471655267222048
+ 4.471690585172653
+ 4.471725902737484
+ 4.471761219916551
+ 4.471796536709867
+ 4.471831853117442
+ 4.471867169139289
+ 4.471902484775419
+ 4.471937800025843
+ 4.471973114890573
+ 4.472008429369619
+ 4.472043743462994
+ 4.472079057170709
+ 4.472114370492775
+ 4.472149683429204
+ 4.472184995980006
+ 4.472220308145196
+ 4.472255619924781
+ 4.472290931318775
+ 4.47232624232719
+ 4.472361552950035
+ 4.472396863187323
+ 4.472432173039065
+ 4.472467482505273
+ 4.472502791585958
+ 4.472538100281131
+ 4.472573408590804
+ 4.472608716514991
+ 4.4726440240536975
+ 4.472679331206939
+ 4.472714637974726
+ 4.47274994435707
+ 4.472785250353982
+ 4.472820555965474
+ 4.472855861191558
+ 4.472891166032245
+ 4.472926470487545
+ 4.47296177455747
+ 4.472997078242033
+ 4.473032381541244
+ 4.473067684455115
+ 4.473102986983657
+ 4.473138289126882
+ 4.473173590884801
+ 4.473208892257425
+ 4.473244193244766
+ 4.473279493846835
+ 4.4733147940636435
+ 4.4733500938952035
+ 4.473385393341527
+ 4.473420692402623
+ 4.473455991078505
+ 4.473491289369183
+ 4.4735265872746695
+ 4.473561884794975
+ 4.473597181930113
+ 4.473632478680091
+ 4.473667775044925
+ 4.473703071024623
+ 4.473738366619198
+ 4.473773661828661
+ 4.4738089566530235
+ 4.473844251092296
+ 4.473879545146491
+ 4.47391483881562
+ 4.473950132099694
+ 4.473985424998724
+ 4.4740207175127225
+ 4.474056009641699
+ 4.474091301385667
+ 4.4741265927446365
+ 4.474161883718621
+ 4.474197174307628
+ 4.474232464511673
+ 4.474267754330765
+ 4.474303043764915
+ 4.4743383328141375
+ 4.47437362147844
+ 4.474408909757837
+ 4.474444197652337
+ 4.474479485161954
+ 4.474514772286698
+ 4.474550059026581
+ 4.474585345381614
+ 4.47462063135181
+ 4.474655916937177
+ 4.47469120213773
+ 4.474726486953476
+ 4.474761771384432
+ 4.474797055430605
+ 4.474832339092008
+ 4.474867622368653
+ 4.47490290526055
+ 4.4749381877677115
+ 4.4749734698901475
+ 4.475008751627872
+ 4.475044032980893
+ 4.475079313949224
+ 4.475114594532877
+ 4.475149874731862
+ 4.475185154546191
+ 4.475220433975874
+ 4.475255713020925
+ 4.475290991681353
+ 4.475326269957169
+ 4.475361547848388
+ 4.475396825355019
+ 4.475432102477072
+ 4.47546737921456
+ 4.475502655567494
+ 4.475537931535887
+ 4.475573207119748
+ 4.475608482319089
+ 4.4756437571339225
+ 4.475679031564259
+ 4.475714305610109
+ 4.475749579271485
+ 4.475784852548399
+ 4.475820125440862
+ 4.475855397948884
+ 4.475890670072476
+ 4.475925941811653
+ 4.475961213166423
+ 4.4759964841367985
+ 4.476031754722791
+ 4.476067024924412
+ 4.476102294741673
+ 4.476137564174583
+ 4.476172833223156
+ 4.476208101887404
+ 4.476243370167336
+ 4.476278638062964
+ 4.476313905574299
+ 4.476349172701355
+ 4.476384439444142
+ 4.47641970580267
+ 4.47645497177695
+ 4.4764902373669955
+ 4.476525502572816
+ 4.4765607673944245
+ 4.476596031831832
+ 4.476631295885049
+ 4.476666559554088
+ 4.47670182283896
+ 4.476737085739675
+ 4.4767723482562465
+ 4.476807610388684
+ 4.476842872137
+ 4.476878133501206
+ 4.476913394481311
+ 4.476948655077329
+ 4.476983915289272
+ 4.4770191751171495
+ 4.477054434560973
+ 4.477089693620754
+ 4.477124952296504
+ 4.477160210588235
+ 4.477195468495958
+ 4.477230726019682
+ 4.4772659831594215
+ 4.477301239915188
+ 4.47733649628699
+ 4.477371752274841
+ 4.477407007878752
+ 4.477442263098735
+ 4.4774775179347985
+ 4.477512772386957
+ 4.477548026455222
+ 4.477583280139601
+ 4.4776185334401095
+ 4.477653786356758
+ 4.477689038889555
+ 4.477724291038515
+ 4.477759542803648
+ 4.477794794184966
+ 4.477830045182481
+ 4.477865295796201
+ 4.477900546026142
+ 4.477935795872312
+ 4.477971045334723
+ 4.478006294413386
+ 4.478041543108314
+ 4.478076791419518
+ 4.478112039347008
+ 4.478147286890795
+ 4.478182534050893
+ 4.478217780827311
+ 4.4782530272200605
+ 4.478288273229155
+ 4.4783235188546024
+ 4.478358764096417
+ 4.478394008954608
+ 4.478429253429189
+ 4.478464497520169
+ 4.478499741227561
+ 4.478534984551374
+ 4.478570227491623
+ 4.4786054700483175
+ 4.478640712221468
+ 4.478675954011087
+ 4.478711195417184
+ 4.478746436439773
+ 4.478781677078864
+ 4.478816917334467
+ 4.478852157206596
+ 4.478887396695261
+ 4.478922635800473
+ 4.478957874522243
+ 4.478993112860584
+ 4.479028350815506
+ 4.47906358838702
+ 4.4790988255751385
+ 4.479134062379873
+ 4.479169298801233
+ 4.479204534839232
+ 4.479239770493878
+ 4.479275005765187
+ 4.479310240653167
+ 4.47934547515783
+ 4.479380709279186
+ 4.47941594301725
+ 4.479451176372031
+ 4.47948640934354
+ 4.479521641931789
+ 4.479556874136789
+ 4.479592105958551
+ 4.479627337397086
+ 4.479662568452407
+ 4.479697799124525
+ 4.47973302941345
+ 4.479768259319194
+ 4.4798034888417675
+ 4.479838717981184
+ 4.479873946737452
+ 4.479909175110585
+ 4.479944403100594
+ 4.479979630707489
+ 4.480014857931283
+ 4.480050084771985
+ 4.48008531122961
+ 4.480120537304166
+ 4.480155762995664
+ 4.480190988304118
+ 4.480226213229538
+ 4.480261437771936
+ 4.4802966619313205
+ 4.480331885707706
+ 4.480367109101103
+ 4.480402332111523
+ 4.480437554738975
+ 4.480472776983473
+ 4.480507998845028
+ 4.48054322032365
+ 4.480578441419351
+ 4.480613662132143
+ 4.480648882462036
+ 4.480684102409042
+ 4.480719321973173
+ 4.480754541154439
+ 4.4807897599528514
+ 4.480824978368423
+ 4.480860196401162
+ 4.4808954140510835
+ 4.480930631318196
+ 4.480965848202512
+ 4.481001064704042
+ 4.481036280822799
+ 4.481071496558793
+ 4.481106711912035
+ 4.481141926882536
+ 4.48117714147031
+ 4.481212355675365
+ 4.4812475694977145
+ 4.4812827829373685
+ 4.4813179959943374
+ 4.481353208668635
+ 4.481388420960271
+ 4.481423632869257
+ 4.481458844395604
+ 4.481494055539325
+ 4.481529266300429
+ 4.481564476678928
+ 4.4815996866748335
+ 4.481634896288157
+ 4.481670105518909
+ 4.481705314367103
+ 4.481740522832746
+ 4.481775730915855
+ 4.4818109386164355
+ 4.481846145934503
+ 4.481881352870066
+ 4.481916559423137
+ 4.481951765593729
+ 4.4819869713818505
+ 4.482022176787513
+ 4.48205738181073
+ 4.482092586451511
+ 4.4821277907098676
+ 4.482162994585811
+ 4.482198198079352
+ 4.482233401190504
+ 4.482268603919276
+ 4.48230380626568
+ 4.482339008229728
+ 4.48237420981143
+ 4.4824094110107975
+ 4.482444611827842
+ 4.482479812262575
+ 4.482515012315009
+ 4.482550211985153
+ 4.482585411273019
+ 4.482620610178619
+ 4.482655808701963
+ 4.482691006843063
+ 4.482726204601931
+ 4.4827614019785775
+ 4.482796598973013
+ 4.482831795585251
+ 4.4828669918153
+ 4.482902187663173
+ 4.482937383128881
+ 4.482972578212435
+ 4.4830077729138464
+ 4.483042967233128
+ 4.483078161170287
+ 4.483113354725339
+ 4.483148547898292
+ 4.48318374068916
+ 4.483218933097952
+ 4.483254125124681
+ 4.483289316769357
+ 4.483324508031991
+ 4.483359698912597
+ 4.483394889411183
+ 4.4834300795277615
+ 4.483465269262345
+ 4.483500458614942
+ 4.483535647585565
+ 4.483570836174227
+ 4.483606024380936
+ 4.483641212205706
+ 4.483676399648547
+ 4.483711586709472
+ 4.483746773388489
+ 4.483781959685611
+ 4.483817145600851
+ 4.4838523311342176
+ 4.483887516285723
+ 4.483922701055378
+ 4.4839578854431945
+ 4.483993069449184
+ 4.484028253073356
+ 4.484063436315724
+ 4.484098619176299
+ 4.484133801655091
+ 4.48416898375211
+ 4.484204165467371
+ 4.484239346800883
+ 4.484274527752658
+ 4.484309708322705
+ 4.484344888511038
+ 4.484380068317668
+ 4.4844152477426045
+ 4.484450426785859
+ 4.4844856054474445
+ 4.484520783727372
+ 4.48455596162565
+ 4.484591139142292
+ 4.48462631627731
+ 4.484661493030714
+ 4.484696669402515
+ 4.484731845392724
+ 4.484767021001353
+ 4.484802196228414
+ 4.484837371073916
+ 4.484872545537873
+ 4.484907719620294
+ 4.4849428933211914
+ 4.484978066640575
+ 4.485013239578458
+ 4.485048412134851
+ 4.485083584309764
+ 4.485118756103209
+ 4.4851539275151975
+ 4.485189098545742
+ 4.485224269194851
+ 4.485259439462538
+ 4.485294609348813
+ 4.485329778853687
+ 4.485364947977172
+ 4.485400116719279
+ 4.48543528508002
+ 4.4854704530594045
+ 4.485505620657444
+ 4.485540787874152
+ 4.485575954709537
+ 4.485611121163612
+ 4.485646287236388
+ 4.485681452927874
+ 4.485716618238086
+ 4.485751783167029
+ 4.485786947714718
+ 4.4858221118811645
+ 4.48585727566638
+ 4.485892439070373
+ 4.485927602093156
+ 4.485962764734741
+ 4.4859979269951396
+ 4.486033088874361
+ 4.486068250372418
+ 4.486103411489322
+ 4.486138572225082
+ 4.486173732579712
+ 4.486208892553222
+ 4.486244052145623
+ 4.486279211356927
+ 4.486314370187144
+ 4.486349528636286
+ 4.486384686704365
+ 4.48641984439139
+ 4.486455001697374
+ 4.486490158622328
+ 4.486525315166263
+ 4.486560471329189
+ 4.48659562711112
+ 4.486630782512065
+ 4.486665937532035
+ 4.4867010921710415
+ 4.486736246429097
+ 4.486771400306212
+ 4.486806553802397
+ 4.486841706917666
+ 4.486876859652025
+ 4.48691201200549
+ 4.48694716397807
+ 4.486982315569776
+ 4.487017466780621
+ 4.487052617610614
+ 4.487087768059768
+ 4.487122918128091
+ 4.4871580678155985
+ 4.487193217122301
+ 4.487228366048208
+ 4.487263514593329
+ 4.487298662757679
+ 4.4873338105412675
+ 4.487368957944105
+ 4.487404104966204
+ 4.487439251607576
+ 4.4874743978682305
+ 4.48750954374818
+ 4.487544689247434
+ 4.487579834366006
+ 4.487614979103906
+ 4.487650123461145
+ 4.487685267437735
+ 4.487720411033687
+ 4.487755554249011
+ 4.487790697083719
+ 4.487825839537823
+ 4.487860981611333
+ 4.487896123304261
+ 4.487931264616617
+ 4.4879664055484145
+ 4.488001546099663
+ 4.488036686270373
+ 4.488071826060556
+ 4.488106965470225
+ 4.488142104499389
+ 4.48817724314806
+ 4.488212381416251
+ 4.488247519303971
+ 4.488282656811231
+ 4.488317793938043
+ 4.488352930684417
+ 4.4883880670503675
+ 4.488423203035902
+ 4.488458338641033
+ 4.488493473865771
+ 4.48852860871013
+ 4.488563743174117
+ 4.488598877257747
+ 4.488634010961028
+ 4.488669144283974
+ 4.488704277226594
+ 4.4887394097888995
+ 4.488774541970903
+ 4.488809673772614
+ 4.488844805194046
+ 4.488879936235207
+ 4.488915066896112
+ 4.488950197176768
+ 4.488985327077189
+ 4.489020456597386
+ 4.489055585737368
+ 4.489090714497149
+ 4.489125842876738
+ 4.4891609708761475
+ 4.4891960984953885
+ 4.48923122573447
+ 4.489266352593408
+ 4.489301479072209
+ 4.489336605170886
+ 4.48937173088945
+ 4.489406856227912
+ 4.4894419811862845
+ 4.489477105764577
+ 4.4895122299628
+ 4.489547353780967
+ 4.489582477219088
+ 4.489617600277175
+ 4.4896527229552365
+ 4.489687845253286
+ 4.4897229671713355
+ 4.489758088709393
+ 4.489793209867472
+ 4.489828330645584
+ 4.489863451043738
+ 4.489898571061947
+ 4.489933690700222
+ 4.489968809958574
+ 4.490003928837013
+ 4.490039047335552
+ 4.490074165454201
+ 4.490109283192971
+ 4.490144400551874
+ 4.49017951753092
+ 4.490214634130122
+ 4.49024975034949
+ 4.490284866189033
+ 4.490319981648765
+ 4.490355096728698
+ 4.490390211428841
+ 4.4904253257492055
+ 4.4904604396898025
+ 4.4904955532506445
+ 4.490530666431741
+ 4.490565779233103
+ 4.4906008916547435
+ 4.4906360036966735
+ 4.490671115358903
+ 4.490706226641442
+ 4.4907413375443035
+ 4.490776448067499
+ 4.490811558211038
+ 4.4908466679749335
+ 4.490881777359194
+ 4.490916886363833
+ 4.490951994988862
+ 4.49098710323429
+ 4.4910222111001294
+ 4.491057318586392
+ 4.491092425693086
+ 4.491127532420226
+ 4.491162638767822
+ 4.491197744735885
+ 4.491232850324425
+ 4.491267955533455
+ 4.491303060362985
+ 4.491338164813027
+ 4.49137326888359
+ 4.491408372574688
+ 4.491443475886331
+ 4.491478578818529
+ 4.491513681371295
+ 4.491548783544638
+ 4.491583885338572
+ 4.491618986753106
+ 4.491654087788251
+ 4.491689188444019
+ 4.491724288720421
+ 4.491759388617468
+ 4.49179448813517
+ 4.491829587273542
+ 4.49186468603259
+ 4.491899784412329
+ 4.491934882412767
+ 4.491969980033919
+ 4.492005077275792
+ 4.4920401741384
+ 4.492075270621752
+ 4.4921103667258615
+ 4.492145462450739
+ 4.492180557796393
+ 4.492215652762837
+ 4.4922507473500835
+ 4.49228584155814
+ 4.492320935387021
+ 4.492356028836736
+ 4.492391121907295
+ 4.492426214598711
+ 4.492461306910995
+ 4.492496398844157
+ 4.492531490398209
+ 4.492566581573161
+ 4.492601672369027
+ 4.492636762785813
+ 4.492671852823535
+ 4.492706942482203
+ 4.492742031761826
+ 4.492777120662418
+ 4.492812209183986
+ 4.492847297326547
+ 4.492882385090106
+ 4.492917472474679
+ 4.492952559480274
+ 4.492987646106904
+ 4.4930227323545795
+ 4.493057818223311
+ 4.493092903713109
+ 4.493127988823987
+ 4.493163073555953
+ 4.493198157909021
+ 4.4932332418832015
+ 4.493268325478505
+ 4.493303408694942
+ 4.493338491532524
+ 4.493373573991263
+ 4.493408656071169
+ 4.493443737772253
+ 4.493478819094529
+ 4.493513900038003
+ 4.49354898060269
+ 4.493584060788601
+ 4.493619140595745
+ 4.493654220024134
+ 4.49368929907378
+ 4.493724377744694
+ 4.4937594560368845
+ 4.493794533950365
+ 4.493829611485148
+ 4.49386468864124
+ 4.493899765418657
+ 4.493934841817407
+ 4.493969917837504
+ 4.4940049934789545
+ 4.494040068741774
+ 4.49407514362597
+ 4.494110218131557
+ 4.494145292258544
+ 4.494180366006943
+ 4.494215439376765
+ 4.49425051236802
+ 4.49428558498072
+ 4.494320657214876
+ 4.494355729070499
+ 4.494390800547602
+ 4.494425871646191
+ 4.494460942366282
+ 4.494496012707885
+ 4.49453108267101
+ 4.494566152255668
+ 4.494601221461871
+ 4.494636290289631
+ 4.494671358738956
+ 4.49470642680986
+ 4.494741494502352
+ 4.494776561816446
+ 4.49481162875215
+ 4.494846695309477
+ 4.494881761488435
+ 4.49491682728904
+ 4.4949518927113
+ 4.494986957755225
+ 4.495022022420829
+ 4.4950570867081225
+ 4.495092150617115
+ 4.495127214147818
+ 4.495162277300244
+ 4.4951973400744025
+ 4.495232402470305
+ 4.495267464487962
+ 4.495302526127387
+ 4.495337587388588
+ 4.4953726482715775
+ 4.495407708776367
+ 4.495442768902968
+ 4.495477828651389
+ 4.495512888021643
+ 4.495547947013741
+ 4.495583005627695
+ 4.495618063863513
+ 4.495653121721209
+ 4.495688179200793
+ 4.495723236302277
+ 4.49575829302567
+ 4.4957933493709845
+ 4.495828405338233
+ 4.495863460927422
+ 4.495898516138568
+ 4.495933570971678
+ 4.495968625426765
+ 4.49600367950384
+ 4.496038733202913
+ 4.496073786523997
+ 4.496108839467102
+ 4.496143892032237
+ 4.496178944219416
+ 4.49621399602865
+ 4.496249047459949
+ 4.496284098513323
+ 4.496319149188784
+ 4.496354199486345
+ 4.496389249406015
+ 4.496424298947804
+ 4.496459348111725
+ 4.4964943968977895
+ 4.496529445306007
+ 4.496564493336388
+ 4.496599540988946
+ 4.496634588263691
+ 4.496669635160633
+ 4.496704681679785
+ 4.496739727821156
+ 4.496774773584757
+ 4.496809818970602
+ 4.4968448639786995
+ 4.496879908609061
+ 4.496914952861697
+ 4.49694999673662
+ 4.49698504023384
+ 4.497020083353368
+ 4.4970551260952165
+ 4.497090168459394
+ 4.497125210445914
+ 4.497160252054786
+ 4.497195293286022
+ 4.497230334139632
+ 4.497265374615628
+ 4.4973004147140205
+ 4.497335454434821
+ 4.49737049377804
+ 4.497405532743689
+ 4.497440571331779
+ 4.497475609542321
+ 4.497510647375326
+ 4.497545684830805
+ 4.497580721908769
+ 4.497615758609229
+ 4.497650794932196
+ 4.497685830877682
+ 4.497720866445696
+ 4.49775590163625
+ 4.497790936449356
+ 4.497825970885025
+ 4.497861004943267
+ 4.497896038624092
+ 4.497931071927513
+ 4.497966104853541
+ 4.498001137402187
+ 4.49803616957346
+ 4.498071201367374
+ 4.498106232783938
+ 4.498141263823165
+ 4.498176294485062
+ 4.4982113247696445
+ 4.498246354676921
+ 4.498281384206904
+ 4.4983164133596025
+ 4.49835144213503
+ 4.498386470533196
+ 4.498421498554112
+ 4.498456526197789
+ 4.498491553464238
+ 4.498526580353469
+ 4.498561606865495
+ 4.498596633000324
+ 4.498631658757971
+ 4.4986666841384455
+ 4.4987017091417565
+ 4.498736733767918
+ 4.498771758016939
+ 4.498806781888831
+ 4.498841805383606
+ 4.498876828501273
+ 4.498911851241844
+ 4.498946873605331
+ 4.4989818955917436
+ 4.499016917201095
+ 4.499051938433394
+ 4.499086959288651
+ 4.49912197976688
+ 4.499156999868089
+ 4.499192019592291
+ 4.499227038939497
+ 4.499262057909716
+ 4.499297076502961
+ 4.499332094719243
+ 4.499367112558572
+ 4.499402130020959
+ 4.499437147106417
+ 4.4994721638149535
+ 4.4995071801465825
+ 4.499542196101314
+ 4.499577211679159
+ 4.499612226880129
+ 4.499647241704233
+ 4.499682256151484
+ 4.499717270221894
+ 4.499752283915471
+ 4.499787297232228
+ 4.499822310172176
+ 4.499857322735325
+ 4.499892334921687
+ 4.499927346731272
+ 4.499962358164092
+ 4.499997369220158
+ 4.50003237989948
+ 4.500067390202069
+ 4.500102400127939
+ 4.500137409677096
+ 4.500172418849555
+ 4.500207427645325
+ 4.5002424360644175
+ 4.500277444106844
+ 4.500312451772615
+ 4.500347459061743
+ 4.500382465974235
+ 4.500417472510106
+ 4.500452478669366
+ 4.500487484452025
+ 4.500522489858095
+ 4.500557494887586
+ 4.5005924995405096
+ 4.500627503816878
+ 4.500662507716699
+ 4.500697511239987
+ 4.500732514386751
+ 4.500767517157003
+ 4.500802519550754
+ 4.500837521568013
+ 4.500872523208794
+ 4.500907524473106
+ 4.50094252536096
+ 4.500977525872368
+ 4.50101252600734
+ 4.501047525765889
+ 4.501082525148023
+ 4.501117524153755
+ 4.501152522783095
+ 4.501187521036055
+ 4.501222518912645
+ 4.501257516412877
+ 4.501292513536762
+ 4.501327510284309
+ 4.50136250665553
+ 4.501397502650437
+ 4.5014324982690415
+ 4.501467493511352
+ 4.501502488377381
+ 4.501537482867139
+ 4.5015724769806384
+ 4.501607470717889
+ 4.5016424640789
+ 4.5016774570636855
+ 4.501712449672255
+ 4.5017474419046195
+ 4.5017824337607895
+ 4.5018174252407785
+ 4.501852416344594
+ 4.501887407072249
+ 4.501922397423755
+ 4.501957387399121
+ 4.501992376998359
+ 4.502027366221479
+ 4.502062355068494
+ 4.502097343539415
+ 4.50213233163425
+ 4.502167319353013
+ 4.502202306695714
+ 4.502237293662363
+ 4.502272280252972
+ 4.502307266467551
+ 4.502342252306113
+ 4.502377237768668
+ 4.5024122228552255
+ 4.5024472075657975
+ 4.502482191900396
+ 4.5025171758590306
+ 4.502552159441713
+ 4.502587142648453
+ 4.502622125479263
+ 4.502657107934154
+ 4.502692090013136
+ 4.50272707171622
+ 4.502762053043418
+ 4.502797033994739
+ 4.502832014570196
+ 4.502866994769799
+ 4.50290197459356
+ 4.5029369540414885
+ 4.502971933113596
+ 4.503006911809893
+ 4.503041890130392
+ 4.5030768680751025
+ 4.503111845644035
+ 4.503146822837203
+ 4.503181799654615
+ 4.503216776096283
+ 4.503251752162218
+ 4.50328672785243
+ 4.5033217031669315
+ 4.503356678105732
+ 4.503391652668843
+ 4.503426626856276
+ 4.50346160066804
+ 4.503496574104149
+ 4.503531547164612
+ 4.50356651984944
+ 4.503601492158645
+ 4.503636464092237
+ 4.503671435650227
+ 4.503706406832626
+ 4.503741377639444
+ 4.503776348070694
+ 4.503811318126387
+ 4.503846287806532
+ 4.50388125711114
+ 4.503916226040223
+ 4.503951194593793
+ 4.503986162771859
+ 4.504021130574433
+ 4.5040560980015245
+ 4.504091065053147
+ 4.504126031729309
+ 4.504160998030024
+ 4.504195963955299
+ 4.504230929505149
+ 4.504265894679582
+ 4.504300859478611
+ 4.504335823902245
+ 4.504370787950497
+ 4.504405751623377
+ 4.504440714920896
+ 4.504475677843065
+ 4.504510640389895
+ 4.504545602561396
+ 4.504580564357579
+ 4.504615525778457
+ 4.504650486824039
+ 4.504685447494337
+ 4.50472040778936
+ 4.504755367709122
+ 4.504790327253632
+ 4.5048252864229
+ 4.504860245216939
+ 4.50489520363576
+ 4.504930161679372
+ 4.504965119347786
+ 4.505000076641015
+ 4.505035033559069
+ 4.505069990101958
+ 4.505104946269694
+ 4.505139902062289
+ 4.5051748574797505
+ 4.505209812522091
+ 4.505244767189324
+ 4.5052797214814575
+ 4.505314675398503
+ 4.505349628940472
+ 4.505384582107374
+ 4.5054195348992225
+ 4.505454487316025
+ 4.505489439357796
+ 4.505524391024545
+ 4.505559342316281
+ 4.505594293233018
+ 4.505629243774765
+ 4.505664193941533
+ 4.5056991437333345
+ 4.505734093150178
+ 4.505769042192076
+ 4.50580399085904
+ 4.505838939151079
+ 4.505873887068206
+ 4.5059088346104295
+ 4.505943781777764
+ 4.505978728570216
+ 4.506013674987799
+ 4.506048621030525
+ 4.506083566698401
+ 4.506118511991443
+ 4.506153456909657
+ 4.506188401453058
+ 4.506223345621654
+ 4.506258289415458
+ 4.506293232834478
+ 4.506328175878728
+ 4.506363118548219
+ 4.506398060842959
+ 4.506433002762961
+ 4.506467944308236
+ 4.506502885478794
+ 4.506537826274646
+ 4.506572766695802
+ 4.506607706742277
+ 4.506642646414076
+ 4.5066775857112145
+ 4.506712524633701
+ 4.506747463181549
+ 4.506782401354766
+ 4.506817339153366
+ 4.506852276577357
+ 4.506887213626751
+ 4.50692215030156
+ 4.506957086601793
+ 4.506992022527464
+ 4.507026958078581
+ 4.507061893255156
+ 4.5070968280571995
+ 4.507131762484723
+ 4.507166696537737
+ 4.507201630216251
+ 4.507236563520278
+ 4.507271496449829
+ 4.507306429004914
+ 4.507341361185543
+ 4.507376292991729
+ 4.507411224423481
+ 4.507446155480811
+ 4.50748108616373
+ 4.507516016472248
+ 4.5075509464063765
+ 4.507585875966127
+ 4.507620805151508
+ 4.507655733962533
+ 4.507690662399212
+ 4.507725590461555
+ 4.507760518149575
+ 4.507795445463281
+ 4.507830372402684
+ 4.507865298967796
+ 4.507900225158627
+ 4.507935150975189
+ 4.507970076417491
+ 4.508005001485544
+ 4.508039926179362
+ 4.508074850498953
+ 4.5081097744443275
+ 4.5081446980154976
+ 4.508179621212475
+ 4.508214544035269
+ 4.508249466483892
+ 4.508284388558352
+ 4.508319310258663
+ 4.508354231584835
+ 4.508389152536878
+ 4.508424073114804
+ 4.508458993318624
+ 4.508493913148348
+ 4.508528832603986
+ 4.508563751685551
+ 4.508598670393053
+ 4.508633588726502
+ 4.508668506685909
+ 4.508703424271287
+ 4.508738341482646
+ 4.5087732583199935
+ 4.508808174783345
+ 4.50884309087271
+ 4.508878006588097
+ 4.508912921929521
+ 4.508947836896989
+ 4.508982751490515
+ 4.509017665710107
+ 4.509052579555777
+ 4.509087493027537
+ 4.509122406125397
+ 4.509157318849367
+ 4.509192231199459
+ 4.509227143175685
+ 4.509262054778053
+ 4.509296966006575
+ 4.509331876861263
+ 4.509366787342127
+ 4.509401697449178
+ 4.509436607182426
+ 4.5094715165418835
+ 4.50950642552756
+ 4.509541334139466
+ 4.509576242377615
+ 4.509611150242015
+ 4.509646057732678
+ 4.509680964849615
+ 4.509715871592836
+ 4.509750777962354
+ 4.509785683958177
+ 4.509820589580318
+ 4.509855494828787
+ 4.509890399703595
+ 4.509925304204753
+ 4.509960208332271
+ 4.509995112086161
+ 4.510030015466433
+ 4.510064918473099
+ 4.510099821106168
+ 4.5101347233656535
+ 4.510169625251564
+ 4.510204526763911
+ 4.510239427902705
+ 4.510274328667958
+ 4.51030922905968
+ 4.510344129077882
+ 4.510379028722575
+ 4.51041392799377
+ 4.510448826891477
+ 4.510483725415709
+ 4.510518623566473
+ 4.510553521343783
+ 4.510588418747651
+ 4.510623315778083
+ 4.510658212435094
+ 4.510693108718693
+ 4.510728004628892
+ 4.510762900165702
+ 4.510797795329132
+ 4.5108326901191935
+ 4.510867584535898
+ 4.510902478579257
+ 4.51093737224928
+ 4.510972265545978
+ 4.511007158469362
+ 4.5110420510194436
+ 4.511076943196232
+ 4.51111183499974
+ 4.511146726429977
+ 4.511181617486955
+ 4.5112165081706825
+ 4.511251398481174
+ 4.511286288418438
+ 4.511321177982485
+ 4.511356067173327
+ 4.511390955990974
+ 4.511425844435437
+ 4.511460732506727
+ 4.5114956202048555
+ 4.511530507529832
+ 4.511565394481668
+ 4.5116002810603755
+ 4.511635167265963
+ 4.511670053098443
+ 4.511704938557825
+ 4.511739823644121
+ 4.511774708357343
+ 4.5118095926974995
+ 4.511844476664602
+ 4.51187936025866
+ 4.511914243479688
+ 4.511949126327694
+ 4.511984008802689
+ 4.5120188909046846
+ 4.512053772633691
+ 4.51208865398972
+ 4.512123534972781
+ 4.5121584155828875
+ 4.512193295820046
+ 4.512228175684271
+ 4.512263055175572
+ 4.51229793429396
+ 4.5123328130394444
+ 4.512367691412038
+ 4.512402569411751
+ 4.512437447038595
+ 4.51247232429258
+ 4.512507201173715
+ 4.512542077682014
+ 4.512576953817487
+ 4.512611829580144
+ 4.512646704969995
+ 4.512681579987053
+ 4.512716454631327
+ 4.512751328902829
+ 4.512786202801569
+ 4.512821076327559
+ 4.512855949480809
+ 4.512890822261328
+ 4.51292569466913
+ 4.512960566704224
+ 4.512995438366621
+ 4.513030309656333
+ 4.513065180573368
+ 4.513100051117741
+ 4.51313492128946
+ 4.513169791088535
+ 4.513204660514979
+ 4.513239529568802
+ 4.513274398250013
+ 4.513309266558626
+ 4.51334413449465
+ 4.513379002058096
+ 4.513413869248976
+ 4.513448736067299
+ 4.513483602513076
+ 4.513518468586319
+ 4.513553334287038
+ 4.513588199615244
+ 4.513623064570948
+ 4.513657929154159
+ 4.513692793364891
+ 4.5137276572031535
+ 4.513762520668956
+ 4.51379738376231
+ 4.513832246483227
+ 4.513867108831717
+ 4.513901970807792
+ 4.513936832411461
+ 4.513971693642736
+ 4.514006554501629
+ 4.514041414988148
+ 4.514076275102305
+ 4.514111134844111
+ 4.514145994213577
+ 4.514180853210713
+ 4.514215711835531
+ 4.51425057008804
+ 4.514285427968254
+ 4.514320285476181
+ 4.514355142611831
+ 4.514389999375217
+ 4.51442485576635
+ 4.514459711785239
+ 4.514494567431896
+ 4.514529422706331
+ 4.514564277608556
+ 4.5145991321385806
+ 4.514633986296416
+ 4.514668840082073
+ 4.514703693495561
+ 4.514738546536894
+ 4.514773399206081
+ 4.5148082515031325
+ 4.514843103428059
+ 4.5148779549808715
+ 4.514912806161582
+ 4.5149476569702
+ 4.514982507406737
+ 4.515017357471202
+ 4.515052207163609
+ 4.515087056483966
+ 4.515121905432285
+ 4.515156754008577
+ 4.515191602212852
+ 4.5152264500451205
+ 4.515261297505395
+ 4.515296144593685
+ 4.515330991310001
+ 4.515365837654355
+ 4.515400683626756
+ 4.515435529227217
+ 4.515470374455747
+ 4.515505219312356
+ 4.515540063797057
+ 4.51557490790986
+ 4.515609751650777
+ 4.5156445950198165
+ 4.5156794380169885
+ 4.515714280642307
+ 4.515749122895782
+ 4.515783964777422
+ 4.515818806287241
+ 4.515853647425246
+ 4.515888488191452
+ 4.515923328585866
+ 4.515958168608501
+ 4.5159930082593664
+ 4.516027847538474
+ 4.516062686445835
+ 4.5160975249814586
+ 4.516132363145357
+ 4.516167200937541
+ 4.51620203835802
+ 4.516236875406804
+ 4.516271712083908
+ 4.5163065483893385
+ 4.516341384323108
+ 4.516376219885227
+ 4.516411055075706
+ 4.516445889894556
+ 4.516480724341789
+ 4.516515558417414
+ 4.5165503921214425
+ 4.516585225453885
+ 4.516620058414751
+ 4.516654891004055
+ 4.516689723221804
+ 4.51672455506801
+ 4.5167593865426845
+ 4.516794217645837
+ 4.51682904837748
+ 4.516863878737623
+ 4.516898708726276
+ 4.5169335383434515
+ 4.5169683675891585
+ 4.51700319646341
+ 4.517038024966214
+ 4.517072853097584
+ 4.517107680857529
+ 4.517142508246059
+ 4.517177335263187
+ 4.517212161908924
+ 4.5172469881832775
+ 4.517281814086261
+ 4.517316639617884
+ 4.517351464778159
+ 4.517386289567094
+ 4.517421113984702
+ 4.5174559380309915
+ 4.517490761705977
+ 4.517525585009666
+ 4.517560407942069
+ 4.517595230503199
+ 4.5176300526930655
+ 4.517664874511679
+ 4.517699695959051
+ 4.5177345170351915
+ 4.517769337740112
+ 4.517804158073823
+ 4.517838978036335
+ 4.51787379762766
+ 4.517908616847806
+ 4.517943435696786
+ 4.5179782541746105
+ 4.518013072281288
+ 4.518047890016833
+ 4.518082707381253
+ 4.518117524374561
+ 4.5181523409967665
+ 4.51818715724788
+ 4.518221973127913
+ 4.518256788636876
+ 4.518291603774779
+ 4.518326418541635
+ 4.518361232937452
+ 4.518396046962242
+ 4.518430860616017
+ 4.518465673898785
+ 4.5185004868105585
+ 4.518535299351347
+ 4.518570111521163
+ 4.518604923320016
+ 4.518639734747917
+ 4.518674545804877
+ 4.518709356490906
+ 4.518744166806015
+ 4.518778976750216
+ 4.518813786323518
+ 4.518848595525933
+ 4.518883404357471
+ 4.518918212818142
+ 4.518953020907958
+ 4.518987828626929
+ 4.519022635975066
+ 4.519057442952381
+ 4.519092249558882
+ 4.5191270557945815
+ 4.519161861659489
+ 4.519196667153619
+ 4.519231472276976
+ 4.519266277029576
+ 4.519301081411428
+ 4.519335885422542
+ 4.51937068906293
+ 4.5194054923326
+ 4.519440295231566
+ 4.5194750977598375
+ 4.519509899917424
+ 4.519544701704338
+ 4.51957950312059
+ 4.51961430416619
+ 4.519649104841148
+ 4.5196839051454765
+ 4.519718705079185
+ 4.519753504642285
+ 4.519788303834787
+ 4.519823102656701
+ 4.519857901108039
+ 4.5198926991888095
+ 4.519927496899025
+ 4.519962294238697
+ 4.519997091207835
+ 4.520031887806448
+ 4.520066684034551
+ 4.52010147989215
+ 4.520136275379259
+ 4.520171070495888
+ 4.520205865242047
+ 4.5202406596177465
+ 4.5202754536229985
+ 4.520310247257812
+ 4.520345040522199
+ 4.52037983341617
+ 4.520414625939736
+ 4.520449418092906
+ 4.5204842098756925
+ 4.520519001288107
+ 4.520553792330157
+ 4.520588583001856
+ 4.520623373303214
+ 4.52065816323424
+ 4.520692952794948
+ 4.520727741985346
+ 4.520762530805446
+ 4.520797319255258
+ 4.520832107334792
+ 4.520866895044061
+ 4.520901682383075
+ 4.520936469351843
+ 4.520971255950375
+ 4.521006042178685
+ 4.521040828036782
+ 4.521075613524678
+ 4.5211103986423815
+ 4.521145183389904
+ 4.521179967767257
+ 4.52121475177445
+ 4.521249535411495
+ 4.5212843186784015
+ 4.52131910157518
+ 4.521353884101843
+ 4.5213886662583995
+ 4.521423448044861
+ 4.521458229461238
+ 4.521493010507541
+ 4.521527791183781
+ 4.521562571489968
+ 4.521597351426113
+ 4.521632130992227
+ 4.521666910188321
+ 4.521701689014406
+ 4.5217364674704905
+ 4.521771245556587
+ 4.521806023272705
+ 4.521840800618857
+ 4.521875577595052
+ 4.521910354201302
+ 4.521945130437618
+ 4.521979906304008
+ 4.522014681800484
+ 4.522049456927059
+ 4.52208423168374
+ 4.5221190060705405
+ 4.52215378008747
+ 4.522188553734538
+ 4.522223327011758
+ 4.522258099919139
+ 4.52229287245669
+ 4.522327644624426
+ 4.522362416422354
+ 4.522397187850485
+ 4.522431958908831
+ 4.5224667295974035
+ 4.52250149991621
+ 4.522536269865264
+ 4.522571039444575
+ 4.522605808654155
+ 4.522640577494011
+ 4.522675345964158
+ 4.522710114064604
+ 4.5227448817953615
+ 4.5227796491564405
+ 4.52281441614785
+ 4.522849182769602
+ 4.5228839490217085
+ 4.522918714904178
+ 4.522953480417023
+ 4.522988245560253
+ 4.523023010333878
+ 4.52305777473791
+ 4.523092538772359
+ 4.523127302437236
+ 4.523162065732553
+ 4.5231968286583175
+ 4.523231591214541
+ 4.523266353401237
+ 4.523301115218414
+ 4.523335876666082
+ 4.523370637744253
+ 4.523405398452938
+ 4.523440158792146
+ 4.523474918761888
+ 4.523509678362175
+ 4.523544437593019
+ 4.5235791964544285
+ 4.523613954946415
+ 4.52364871306899
+ 4.523683470822164
+ 4.523718228205946
+ 4.523752985220348
+ 4.52378774186538
+ 4.523822498141055
+ 4.52385725404738
+ 4.523892009584367
+ 4.523926764752028
+ 4.523961519550373
+ 4.523996273979411
+ 4.524031028039155
+ 4.524065781729615
+ 4.524100535050801
+ 4.524135288002722
+ 4.524170040585393
+ 4.524204792798821
+ 4.524239544643018
+ 4.524274296117995
+ 4.5243090472237615
+ 4.524343797960331
+ 4.524378548327709
+ 4.524413298325911
+ 4.524448047954945
+ 4.524482797214823
+ 4.524517546105554
+ 4.52455229462715
+ 4.524587042779623
+ 4.52462179056298
+ 4.524656537977234
+ 4.524691285022396
+ 4.524726031698475
+ 4.524760778005483
+ 4.52479552394343
+ 4.524830269512327
+ 4.5248650147121845
+ 4.524899759543013
+ 4.524934504004824
+ 4.524969248097626
+ 4.525003991821431
+ 4.525038735176251
+ 4.525073478162094
+ 4.525108220778973
+ 4.525142963026897
+ 4.525177704905878
+ 4.525212446415925
+ 4.52524718755705
+ 4.525281928329263
+ 4.525316668732573
+ 4.525351408766994
+ 4.525386148432536
+ 4.525420887729207
+ 4.525455626657019
+ 4.525490365215984
+ 4.525525103406111
+ 4.525559841227412
+ 4.525594578679895
+ 4.525629315763574
+ 4.525664052478458
+ 4.525698788824556
+ 4.525733524801882
+ 4.5257682604104446
+ 4.5258029956502535
+ 4.525837730521322
+ 4.525872465023659
+ 4.525907199157275
+ 4.525941932922181
+ 4.525976666318389
+ 4.526011399345906
+ 4.526046132004747
+ 4.526080864294919
+ 4.526115596216435
+ 4.5261503277693045
+ 4.526185058953538
+ 4.526219789769147
+ 4.526254520216142
+ 4.526289250294533
+ 4.526323980004331
+ 4.526358709345546
+ 4.526393438318189
+ 4.526428166922272
+ 4.5264628951578025
+ 4.5264976230247935
+ 4.526532350523255
+ 4.5265670776531985
+ 4.526601804414633
+ 4.526636530807571
+ 4.526671256832021
+ 4.526705982487996
+ 4.526740707775503
+ 4.5267754326945555
+ 4.526810157245165
+ 4.52684488142734
+ 4.52687960524109
+ 4.526914328686429
+ 4.526949051763365
+ 4.526983774471911
+ 4.527018496812074
+ 4.527053218783868
+ 4.527087940387302
+ 4.527122661622388
+ 4.5271573824891345
+ 4.527192102987553
+ 4.527226823117655
+ 4.52726154287945
+ 4.527296262272949
+ 4.527330981298162
+ 4.527365699955101
+ 4.527400418243776
+ 4.527435136164197
+ 4.527469853716375
+ 4.527504570900319
+ 4.527539287716044
+ 4.527574004163556
+ 4.527608720242868
+ 4.5276434359539905
+ 4.527678151296933
+ 4.527712866271706
+ 4.527747580878322
+ 4.52778229511679
+ 4.52781700898712
+ 4.527851722489324
+ 4.527886435623413
+ 4.527921148389397
+ 4.527955860787285
+ 4.52799057281709
+ 4.528025284478821
+ 4.52805999577249
+ 4.528094706698106
+ 4.5281294172556805
+ 4.5281641274452245
+ 4.528198837266746
+ 4.5282335467202595
+ 4.528268255805774
+ 4.528302964523299
+ 4.528337672872845
+ 4.5283723808544245
+ 4.528407088468047
+ 4.528441795713722
+ 4.528476502591463
+ 4.5285112091012785
+ 4.528545915243179
+ 4.528580621017175
+ 4.528615326423278
+ 4.528650031461498
+ 4.528684736131846
+ 4.528719440434332
+ 4.528754144368968
+ 4.528788847935763
+ 4.528823551134728
+ 4.528858253965874
+ 4.528892956429209
+ 4.528927658524748
+ 4.528962360252499
+ 4.528997061612473
+ 4.52903176260468
+ 4.529066463229133
+ 4.529101163485838
+ 4.529135863374809
+ 4.5291705628960575
+ 4.529205262049591
+ 4.5292399608354215
+ 4.529274659253561
+ 4.529309357304017
+ 4.529344054986803
+ 4.529378752301928
+ 4.529413449249403
+ 4.529448145829237
+ 4.529482842041444
+ 4.529517537886031
+ 4.529552233363012
+ 4.529586928472395
+ 4.52962162321419
+ 4.529656317588411
+ 4.529691011595066
+ 4.529725705234165
+ 4.52976039850572
+ 4.529795091409741
+ 4.52982978394624
+ 4.529864476115225
+ 4.529899167916708
+ 4.529933859350701
+ 4.529968550417212
+ 4.530003241116252
+ 4.530037931447833
+ 4.530072621411964
+ 4.530107311008656
+ 4.530142000237921
+ 4.5301766890997675
+ 4.530211377594208
+ 4.5302460657212515
+ 4.530280753480909
+ 4.53031544087319
+ 4.5303501278981075
+ 4.530384814555671
+ 4.53041950084589
+ 4.530454186768776
+ 4.53048887232434
+ 4.530523557512592
+ 4.530558242333543
+ 4.530592926787201
+ 4.530627610873581
+ 4.530662294592691
+ 4.53069697794454
+ 4.530731660929142
+ 4.530766343546506
+ 4.530801025796642
+ 4.530835707679561
+ 4.5308703891952735
+ 4.530905070343789
+ 4.530939751125121
+ 4.530974431539278
+ 4.53100911158627
+ 4.531043791266109
+ 4.531078470578804
+ 4.531113149524367
+ 4.5311478281028075
+ 4.5311825063141375
+ 4.531217184158366
+ 4.5312518616355035
+ 4.531286538745562
+ 4.531321215488551
+ 4.531355891864481
+ 4.5313905678733635
+ 4.531425243515208
+ 4.531459918790025
+ 4.531494593697826
+ 4.531529268238621
+ 4.531563942412419
+ 4.531598616219234
+ 4.531633289659074
+ 4.531667962731951
+ 4.531702635437873
+ 4.531737307776853
+ 4.531771979748901
+ 4.531806651354026
+ 4.531841322592242
+ 4.531875993463556
+ 4.531910663967981
+ 4.531945334105525
+ 4.531980003876201
+ 4.532014673280019
+ 4.532049342316988
+ 4.532084010987119
+ 4.5321186792904244
+ 4.532153347226913
+ 4.5321880147965965
+ 4.532222681999485
+ 4.5322573488355875
+ 4.532292015304917
+ 4.532326681407483
+ 4.532361347143294
+ 4.532396012512364
+ 4.532430677514701
+ 4.532465342150318
+ 4.532500006419223
+ 4.532534670321427
+ 4.532569333856942
+ 4.532603997025777
+ 4.532638659827944
+ 4.532673322263451
+ 4.532707984332312
+ 4.532742646034534
+ 4.532777307370131
+ 4.532811968339111
+ 4.532846628941485
+ 4.532881289177264
+ 4.532915949046459
+ 4.532950608549079
+ 4.532985267685135
+ 4.53301992645464
+ 4.5330545848576005
+ 4.533089242894029
+ 4.533123900563936
+ 4.533158557867333
+ 4.533193214804228
+ 4.533227871374635
+ 4.533262527578561
+ 4.5332971834160185
+ 4.533331838887017
+ 4.5333664939915685
+ 4.533401148729682
+ 4.533435803101368
+ 4.53347045710664
+ 4.533505110745504
+ 4.533539764017974
+ 4.533574416924059
+ 4.533609069463769
+ 4.533643721637115
+ 4.533678373444109
+ 4.533713024884759
+ 4.533747675959078
+ 4.533782326667074
+ 4.53381697700876
+ 4.533851626984145
+ 4.533886276593239
+ 4.533920925836054
+ 4.533955574712599
+ 4.533990223222886
+ 4.534024871366925
+ 4.5340595191447255
+ 4.534094166556301
+ 4.534128813601658
+ 4.5341634602808085
+ 4.534198106593765
+ 4.534232752540535
+ 4.534267398121131
+ 4.534302043335563
+ 4.534336688183841
+ 4.534371332665976
+ 4.534405976781978
+ 4.534440620531859
+ 4.5344752639156285
+ 4.534509906933296
+ 4.534544549584872
+ 4.53457919187037
+ 4.534613833789797
+ 4.5346484753431655
+ 4.534683116530486
+ 4.534717757351767
+ 4.534752397807021
+ 4.534787037896258
+ 4.5348216776194885
+ 4.534856316976723
+ 4.534890955967972
+ 4.534925594593245
+ 4.534960232852554
+ 4.534994870745909
+ 4.53502950827332
+ 4.535064145434799
+ 4.535098782230353
+ 4.535133418659997
+ 4.535168054723739
+ 4.535202690421589
+ 4.535237325753559
+ 4.535271960719659
+ 4.535306595319899
+ 4.535341229554289
+ 4.535375863422841
+ 4.535410496925565
+ 4.535445130062472
+ 4.53547976283357
+ 4.535514395238872
+ 4.535549027278388
+ 4.535583658952128
+ 4.5356182902601025
+ 4.535652921202322
+ 4.535687551778798
+ 4.53572218198954
+ 4.535756811834557
+ 4.535791441313863
+ 4.535826070427467
+ 4.535860699175377
+ 4.535895327557608
+ 4.535929955574166
+ 4.535964583225064
+ 4.535999210510313
+ 4.536033837429921
+ 4.536068463983901
+ 4.536103090172261
+ 4.536137715995015
+ 4.536172341452171
+ 4.536206966543738
+ 4.5362415912697305
+ 4.536276215630156
+ 4.536310839625027
+ 4.536345463254351
+ 4.5363800865181405
+ 4.536414709416406
+ 4.536449331949159
+ 4.536483954116407
+ 4.536518575918162
+ 4.5365531973544355
+ 4.536587818425238
+ 4.536622439130578
+ 4.536657059470466
+ 4.536691679444914
+ 4.536726299053933
+ 4.536760918297532
+ 4.536795537175722
+ 4.536830155688514
+ 4.536864773835917
+ 4.536899391617942
+ 4.5369340090346
+ 4.536968626085902
+ 4.537003242771857
+ 4.537037859092477
+ 4.53707247504777
+ 4.53710709063775
+ 4.537141705862425
+ 4.537176320721806
+ 4.537210935215902
+ 4.5372455493447275
+ 4.5372801631082895
+ 4.537314776506599
+ 4.537349389539667
+ 4.537384002207504
+ 4.53741861451012
+ 4.537453226447525
+ 4.537487838019732
+ 4.537522449226748
+ 4.537557060068586
+ 4.537591670545256
+ 4.5376262806567675
+ 4.537660890403131
+ 4.537695499784358
+ 4.537730108800458
+ 4.537764717451442
+ 4.537799325737321
+ 4.537833933658105
+ 4.537868541213803
+ 4.5379031484044265
+ 4.537937755229987
+ 4.5379723616904935
+ 4.538006967785957
+ 4.538041573516389
+ 4.5380761788817985
+ 4.538110783882196
+ 4.538145388517592
+ 4.538179992787998
+ 4.5382145966934235
+ 4.538249200233879
+ 4.538283803409376
+ 4.538318406219924
+ 4.538353008665532
+ 4.538387610746213
+ 4.538422212461977
+ 4.538456813812832
+ 4.538491414798791
+ 4.538526015419865
+ 4.5385606156760625
+ 4.538595215567395
+ 4.538629815093872
+ 4.538664414255504
+ 4.5386990130523035
+ 4.538733611484278
+ 4.53876820955144
+ 4.538802807253799
+ 4.538837404591367
+ 4.538872001564152
+ 4.538906598172165
+ 4.538941194415417
+ 4.53897579029392
+ 4.539010385807682
+ 4.539044980956715
+ 4.539079575741028
+ 4.539114170160633
+ 4.539148764215539
+ 4.539183357905758
+ 4.539217951231299
+ 4.5392525441921725
+ 4.539287136788389
+ 4.539321729019961
+ 4.539356320886896
+ 4.539390912389207
+ 4.5394255035269016
+ 4.539460094299993
+ 4.539494684708489
+ 4.539529274752403
+ 4.539563864431742
+ 4.539598453746521
+ 4.539633042696746
+ 4.539667631282429
+ 4.53970221950358
+ 4.539736807360212
+ 4.539771394852332
+ 4.539805981979952
+ 4.539840568743082
+ 4.5398751551417345
+ 4.539909741175917
+ 4.5399443268456405
+ 4.539978912150917
+ 4.5400134970917545
+ 4.540048081668165
+ 4.54008266588016
+ 4.540117249727748
+ 4.54015183321094
+ 4.540186416329748
+ 4.540220999084179
+ 4.540255581474246
+ 4.540290163499959
+ 4.540324745161327
+ 4.540359326458363
+ 4.540393907391076
+ 4.540428487959477
+ 4.540463068163574
+ 4.54049764800338
+ 4.540532227478906
+ 4.540566806590159
+ 4.540601385337154
+ 4.540635963719898
+ 4.540670541738401
+ 4.540705119392676
+ 4.540739696682731
+ 4.540774273608579
+ 4.540808850170229
+ 4.540843426367691
+ 4.540878002200976
+ 4.5409125776700945
+ 4.540947152775057
+ 4.540981727515872
+ 4.541016301892552
+ 4.541050875905108
+ 4.541085449553549
+ 4.541120022837885
+ 4.541154595758127
+ 4.541189168314286
+ 4.541223740506372
+ 4.541258312334395
+ 4.541292883798367
+ 4.541327454898295
+ 4.541362025634194
+ 4.541396596006069
+ 4.541431166013936
+ 4.541465735657801
+ 4.541500304937678
+ 4.541534873853574
+ 4.541569442405502
+ 4.541604010593471
+ 4.5416385784174915
+ 4.541673145877573
+ 4.54170771297373
+ 4.541742279705969
+ 4.541776846074299
+ 4.541811412078736
+ 4.541845977719285
+ 4.54188054299596
+ 4.541915107908769
+ 4.541949672457724
+ 4.541984236642834
+ 4.542018800464111
+ 4.542053363921563
+ 4.542087927015204
+ 4.542122489745041
+ 4.542157052111087
+ 4.542191614113349
+ 4.542226175751841
+ 4.542260737026572
+ 4.542295297937552
+ 4.542329858484791
+ 4.542364418668302
+ 4.542398978488092
+ 4.542433537944174
+ 4.542468097036555
+ 4.54250265576525
+ 4.542537214130266
+ 4.5425717721316135
+ 4.542606329769305
+ 4.54264088704335
+ 4.542675443953757
+ 4.5427100005005405
+ 4.542744556683706
+ 4.5427791125032675
+ 4.5428136679592335
+ 4.542848223051616
+ 4.542882777780424
+ 4.542917332145667
+ 4.542951886147358
+ 4.542986439785505
+ 4.543020993060121
+ 4.543055545971213
+ 4.543090098518793
+ 4.543124650702873
+ 4.543159202523462
+ 4.543193753980569
+ 4.543228305074207
+ 4.543262855804384
+ 4.543297406171113
+ 4.543331956174402
+ 4.543366505814261
+ 4.543401055090704
+ 4.543435604003737
+ 4.543470152553373
+ 4.543504700739621
+ 4.543539248562493
+ 4.543573796021999
+ 4.543608343118147
+ 4.54364288985095
+ 4.543677436220419
+ 4.5437119822265615
+ 4.543746527869389
+ 4.543781073148912
+ 4.543815618065143
+ 4.543850162618089
+ 4.543884706807762
+ 4.543919250634172
+ 4.543953794097329
+ 4.543988337197246
+ 4.544022879933928
+ 4.544057422307392
+ 4.544091964317643
+ 4.544126505964694
+ 4.544161047248555
+ 4.544195588169235
+ 4.544230128726747
+ 4.544264668921099
+ 4.544299208752302
+ 4.5443337482203665
+ 4.5443682873253035
+ 4.544402826067123
+ 4.544437364445834
+ 4.544471902461448
+ 4.5445064401139765
+ 4.544540977403428
+ 4.544575514329814
+ 4.544610050893144
+ 4.544644587093429
+ 4.54467912293068
+ 4.5447136584049055
+ 4.544748193516117
+ 4.544782728264325
+ 4.544817262649539
+ 4.544851796671771
+ 4.544886330331029
+ 4.5449208636273255
+ 4.5449553965606695
+ 4.544989929131073
+ 4.545024461338544
+ 4.545058993183095
+ 4.545093524664735
+ 4.545128055783474
+ 4.545162586539324
+ 4.545197116932294
+ 4.545231646962396
+ 4.545266176629638
+ 4.545300705934032
+ 4.545335234875587
+ 4.545369763454316
+ 4.545404291670226
+ 4.545438819523329
+ 4.545473347013636
+ 4.5455078741411565
+ 4.545542400905902
+ 4.545576927307879
+ 4.545611453347103
+ 4.545645979023581
+ 4.545680504337325
+ 4.545715029288344
+ 4.545749553876648
+ 4.545784078102251
+ 4.545818601965159
+ 4.545853125465385
+ 4.545887648602938
+ 4.545922171377828
+ 4.545956693790067
+ 4.545991215839664
+ 4.54602573752663
+ 4.546060258850975
+ 4.54609477981271
+ 4.5461293004118435
+ 4.546163820648388
+ 4.546198340522353
+ 4.546232860033749
+ 4.546267379182584
+ 4.546301897968873
+ 4.546336416392624
+ 4.546370934453845
+ 4.54640545215255
+ 4.546439969488747
+ 4.546474486462448
+ 4.546509003073661
+ 4.546543519322399
+ 4.546578035208671
+ 4.546612550732488
+ 4.5466470658938585
+ 4.546681580692795
+ 4.546716095129306
+ 4.546750609203404
+ 4.5467851229150975
+ 4.546819636264398
+ 4.546854149251314
+ 4.546888661875858
+ 4.546923174138039
+ 4.546957686037868
+ 4.5469921975753556
+ 4.5470267087505105
+ 4.547061219563345
+ 4.547095730013869
+ 4.54713024010209
+ 4.547164749828023
+ 4.547199259191676
+ 4.547233768193059
+ 4.547268276832182
+ 4.547302785109056
+ 4.547337293023692
+ 4.547371800576099
+ 4.5474063077662885
+ 4.547440814594269
+ 4.5474753210600545
+ 4.547509827163651
+ 4.547544332905071
+ 4.547578838284324
+ 4.547613343301423
+ 4.547647847956375
+ 4.54768235224919
+ 4.547716856179882
+ 4.547751359748458
+ 4.54778586295493
+ 4.547820365799307
+ 4.5478548682816005
+ 4.54788937040182
+ 4.547923872159977
+ 4.547958373556081
+ 4.5479928745901415
+ 4.548027375262171
+ 4.548061875572177
+ 4.5480963755201715
+ 4.548130875106165
+ 4.548165374330167
+ 4.548199873192188
+ 4.5482343716922395
+ 4.54826886983033
+ 4.54830336760647
+ 4.548337865020671
+ 4.548372362072945
+ 4.548406858763297
+ 4.54844135509174
+ 4.548475851058287
+ 4.548510346662945
+ 4.548544841905724
+ 4.548579336786638
+ 4.548613831305693
+ 4.548648325462902
+ 4.548682819258274
+ 4.54871731269182
+ 4.548751805763549
+ 4.548786298473474
+ 4.548820790821603
+ 4.548855282807947
+ 4.548889774432516
+ 4.548924265695321
+ 4.548958756596372
+ 4.548993247135678
+ 4.549027737313253
+ 4.549062227129103
+ 4.549096716583239
+ 4.549131205675674
+ 4.549165694406417
+ 4.549200182775476
+ 4.549234670782864
+ 4.549269158428592
+ 4.549303645712667
+ 4.549338132635103
+ 4.549372619195907
+ 4.54940710539509
+ 4.5494415912326645
+ 4.549476076708639
+ 4.549510561823023
+ 4.54954504657583
+ 4.549579530967066
+ 4.549614014996745
+ 4.549648498664875
+ 4.5496829819714675
+ 4.549717464916531
+ 4.549751947500079
+ 4.549786429722118
+ 4.549820911582661
+ 4.549855393081718
+ 4.549889874219298
+ 4.5499243549954125
+ 4.549958835410071
+ 4.5499933154632854
+ 4.550027795155064
+ 4.550062274485416
+ 4.550096753454356
+ 4.550131232061889
+ 4.55016571030803
+ 4.550200188192787
+ 4.550234665716172
+ 4.550269142878191
+ 4.550303619678859
+ 4.550338096118184
+ 4.550372572196176
+ 4.550407047912848
+ 4.550441523268207
+ 4.5504759982622645
+ 4.55051047289503
+ 4.550544947166515
+ 4.55057942107673
+ 4.550613894625685
+ 4.550648367813389
+ 4.550682840639853
+ 4.550717313105088
+ 4.550751785209104
+ 4.550786256951911
+ 4.550820728333519
+ 4.550855199353938
+ 4.550889670013181
+ 4.5509241403112535
+ 4.550958610248169
+ 4.550993079823939
+ 4.55102754903857
+ 4.551062017892074
+ 4.551096486384463
+ 4.551130954515744
+ 4.551165422285931
+ 4.55119988969503
+ 4.551234356743055
+ 4.551268823430014
+ 4.551303289755919
+ 4.551337755720779
+ 4.551372221324604
+ 4.551406686567406
+ 4.551441151449192
+ 4.551475615969977
+ 4.551510080129767
+ 4.551544543928575
+ 4.551579007366409
+ 4.551613470443281
+ 4.5516479331592015
+ 4.551682395514179
+ 4.551716857508225
+ 4.551751319141348
+ 4.551785780413562
+ 4.551820241324874
+ 4.551854701875295
+ 4.551889162064836
+ 4.551923621893508
+ 4.5519580813613185
+ 4.551992540468278
+ 4.552026999214401
+ 4.552061457599693
+ 4.552095915624166
+ 4.552130373287832
+ 4.552164830590698
+ 4.552199287532776
+ 4.552233744114076
+ 4.552268200334608
+ 4.552302656194383
+ 4.5523371116934115
+ 4.552371566831703
+ 4.552406021609267
+ 4.552440476026115
+ 4.552474930082258
+ 4.552509383777703
+ 4.552543837112463
+ 4.552578290086547
+ 4.552612742699968
+ 4.552647194952732
+ 4.552681646844852
+ 4.552716098376338
+ 4.552750549547199
+ 4.552785000357447
+ 4.552819450807091
+ 4.552853900896141
+ 4.552888350624609
+ 4.552922799992502
+ 4.552957248999834
+ 4.552991697646614
+ 4.55302614593285
+ 4.553060593858555
+ 4.553095041423738
+ 4.553129488628409
+ 4.55316393547258
+ 4.553198381956259
+ 4.553232828079458
+ 4.553267273842186
+ 4.553301719244454
+ 4.553336164286271
+ 4.553370608967648
+ 4.553405053288596
+ 4.5534394972491254
+ 4.553473940849246
+ 4.553508384088967
+ 4.5535428269682985
+ 4.553577269487253
+ 4.553611711645838
+ 4.553646153444066
+ 4.553680594881945
+ 4.553715035959487
+ 4.553749476676704
+ 4.553783917033602
+ 4.553818357030193
+ 4.553852796666488
+ 4.553887235942497
+ 4.55392167485823
+ 4.553956113413696
+ 4.553990551608907
+ 4.554024989443873
+ 4.554059426918603
+ 4.554093864033108
+ 4.5541283007874
+ 4.554162737181486
+ 4.554197173215378
+ 4.554231608889086
+ 4.554266044202621
+ 4.554300479155991
+ 4.554334913749209
+ 4.554369347982282
+ 4.554403781855224
+ 4.554438215368043
+ 4.554472648520748
+ 4.554507081313352
+ 4.554541513745864
+ 4.554575945818294
+ 4.5546103775306515
+ 4.55464480888295
+ 4.554679239875195
+ 4.5547136705074
+ 4.554748100779575
+ 4.554782530691728
+ 4.554816960243872
+ 4.554851389436016
+ 4.554885818268169
+ 4.554920246740344
+ 4.554954674852548
+ 4.554989102604794
+ 4.55502352999709
+ 4.555057957029447
+ 4.555092383701877
+ 4.555126810014388
+ 4.55516123596699
+ 4.555195661559696
+ 4.555230086792512
+ 4.555264511665452
+ 4.5552989361785245
+ 4.55533336033174
+ 4.555367784125108
+ 4.5554022075586404
+ 4.555436630632346
+ 4.555471053346235
+ 4.555505475700318
+ 4.555539897694605
+ 4.555574319329108
+ 4.555608740603835
+ 4.555643161518796
+ 4.555677582074002
+ 4.5557120022694635
+ 4.555746422105191
+ 4.555780841581193
+ 4.555815260697481
+ 4.555849679454066
+ 4.5558840978509565
+ 4.555918515888164
+ 4.555952933565698
+ 4.555987350883568
+ 4.556021767841787
+ 4.5560561844403615
+ 4.556090600679305
+ 4.5561250165586245
+ 4.556159432078333
+ 4.556193847238439
+ 4.556228262038953
+ 4.556262676479886
+ 4.556297090561247
+ 4.5563315042830475
+ 4.556365917645297
+ 4.556400330648006
+ 4.556434743291184
+ 4.556469155574841
+ 4.556503567498989
+ 4.556537979063637
+ 4.556572390268794
+ 4.556606801114472
+ 4.556641211600682
+ 4.556675621727432
+ 4.556710031494732
+ 4.556744440902595
+ 4.556778849951027
+ 4.556813258640041
+ 4.556847666969648
+ 4.556882074939856
+ 4.556916482550677
+ 4.5569508898021205
+ 4.5569852966941955
+ 4.5570197032269135
+ 4.557054109400285
+ 4.557088515214319
+ 4.557122920669026
+ 4.5571573257644165
+ 4.557191730500501
+ 4.557226134877289
+ 4.557260538894791
+ 4.557294942553018
+ 4.557329345851978
+ 4.557363748791683
+ 4.557398151372143
+ 4.557432553593369
+ 4.557466955455369
+ 4.557501356958154
+ 4.557535758101735
+ 4.557570158886121
+ 4.557604559311324
+ 4.557638959377351
+ 4.557673359084216
+ 4.557707758431926
+ 4.557742157420494
+ 4.5577765560499275
+ 4.557810954320239
+ 4.557845352231436
+ 4.557879749783531
+ 4.557914146976534
+ 4.557948543810454
+ 4.557982940285302
+ 4.558017336401087
+ 4.558051732157822
+ 4.558086127555514
+ 4.558120522594175
+ 4.558154917273814
+ 4.558189311594441
+ 4.558223705556069
+ 4.558258099158706
+ 4.5582924924023605
+ 4.558326885287046
+ 4.558361277812771
+ 4.558395669979545
+ 4.558430061787379
+ 4.558464453236284
+ 4.558498844326269
+ 4.558533235057344
+ 4.55856762542952
+ 4.558602015442807
+ 4.558636405097215
+ 4.558670794392754
+ 4.558705183329434
+ 4.5587395719072665
+ 4.55877396012626
+ 4.5588083479864245
+ 4.558842735487772
+ 4.558877122630311
+ 4.558911509414052
+ 4.558945895839007
+ 4.558980281905184
+ 4.559014667612593
+ 4.559049052961246
+ 4.55908343795115
+ 4.55911782258232
+ 4.559152206854762
+ 4.559186590768487
+ 4.559220974323507
+ 4.559255357519831
+ 4.559289740357468
+ 4.559324122836429
+ 4.559358504956726
+ 4.559392886718366
+ 4.559427268121361
+ 4.559461649165721
+ 4.559496029851457
+ 4.559530410178576
+ 4.559564790147091
+ 4.5595991697570115
+ 4.559633549008349
+ 4.559667927901111
+ 4.559702306435309
+ 4.559736684610953
+ 4.559771062428053
+ 4.5598054398866195
+ 4.5598398169866625
+ 4.5598741937281915
+ 4.559908570111219
+ 4.5599429461357515
+ 4.559977321801802
+ 4.56001169710938
+ 4.560046072058496
+ 4.560080446649158
+ 4.5601148208813775
+ 4.560149194755166
+ 4.560183568270532
+ 4.560217941427486
+ 4.560252314226038
+ 4.5602866866662
+ 4.560321058747978
+ 4.560355430471386
+ 4.5603898018364335
+ 4.5604241728431285
+ 4.560458543491483
+ 4.560492913781507
+ 4.56052728371321
+ 4.560561653286603
+ 4.560596022501696
+ 4.560630391358498
+ 4.560664759857021
+ 4.560699127997273
+ 4.560733495779266
+ 4.560767863203007
+ 4.560802230268512
+ 4.560836596975785
+ 4.560870963324839
+ 4.560905329315685
+ 4.560939694948332
+ 4.56097406022279
+ 4.561008425139068
+ 4.561042789697178
+ 4.561077153897131
+ 4.561111517738934
+ 4.5611458812226
+ 4.561180244348137
+ 4.561214607115557
+ 4.5612489695248675
+ 4.561283331576082
+ 4.561317693269208
+ 4.5613520546042565
+ 4.5613864155812385
+ 4.561420776200163
+ 4.56145513646104
+ 4.561489496363881
+ 4.561523855908695
+ 4.561558215095491
+ 4.561592573924282
+ 4.561626932395076
+ 4.561661290507884
+ 4.561695648262716
+ 4.561730005659582
+ 4.561764362698492
+ 4.561798719379455
+ 4.561833075702483
+ 4.5618674316675865
+ 4.561901787274774
+ 4.561936142524056
+ 4.561970497415443
+ 4.562004851948945
+ 4.562039206124571
+ 4.562073559942334
+ 4.562107913402241
+ 4.5621422665043045
+ 4.5621766192485325
+ 4.562210971634936
+ 4.562245323663526
+ 4.562279675334312
+ 4.562314026647303
+ 4.562348377602511
+ 4.562382728199945
+ 4.562417078439615
+ 4.562451428321531
+ 4.562485777845705
+ 4.562520127012145
+ 4.562554475820861
+ 4.562588824271865
+ 4.562623172365166
+ 4.562657520100774
+ 4.562691867478698
+ 4.562726214498951
+ 4.562760561161541
+ 4.562794907466478
+ 4.562829253413773
+ 4.562863599003436
+ 4.562897944235477
+ 4.562932289109905
+ 4.562966633626732
+ 4.5630009777859675
+ 4.563035321587621
+ 4.563069665031702
+ 4.563104008118222
+ 4.563138350847192
+ 4.563172693218619
+ 4.563207035232515
+ 4.56324137688889
+ 4.5632757181877555
+ 4.563310059129118
+ 4.563344399712991
+ 4.563378739939383
+ 4.563413079808305
+ 4.563447419319766
+ 4.563481758473777
+ 4.563516097270346
+ 4.563550435709487
+ 4.563584773791208
+ 4.563619111515518
+ 4.563653448882428
+ 4.56368778589195
+ 4.56372212254409
+ 4.563756458838861
+ 4.563790794776273
+ 4.563825130356336
+ 4.563859465579059
+ 4.563893800444453
+ 4.563928134952528
+ 4.563962469103294
+ 4.563996802896761
+ 4.5640311363329396
+ 4.5640654694118385
+ 4.5640998021334696
+ 4.564134134497842
+ 4.564168466504965
+ 4.564202798154851
+ 4.564237129447508
+ 4.5642714603829475
+ 4.5643057909611775
+ 4.564340121182211
+ 4.5643744510460555
+ 4.564408780552722
+ 4.564443109702221
+ 4.564477438494564
+ 4.564511766929758
+ 4.564546095007814
+ 4.564580422728743
+ 4.564614750092555
+ 4.56464907709926
+ 4.564683403748867
+ 4.564717730041387
+ 4.564752055976831
+ 4.564786381555207
+ 4.564820706776526
+ 4.564855031640799
+ 4.5648893561480355
+ 4.564923680298245
+ 4.564958004091438
+ 4.564992327527625
+ 4.565026650606815
+ 4.565060973329018
+ 4.565095295694246
+ 4.565129617702508
+ 4.5651639393538135
+ 4.565198260648173
+ 4.5652325815855965
+ 4.565266902166094
+ 4.565301222389677
+ 4.565335542256353
+ 4.565369861766134
+ 4.56540418091903
+ 4.565438499715049
+ 4.565472818154204
+ 4.565507136236503
+ 4.5655414539619565
+ 4.565575771330575
+ 4.565610088342369
+ 4.565644404997348
+ 4.565678721295522
+ 4.5657130372369
+ 4.565747352821496
+ 4.565781668049314
+ 4.56581598292037
+ 4.565850297434669
+ 4.565884611592225
+ 4.565918925393047
+ 4.565953238837142
+ 4.5659875519245245
+ 4.566021864655203
+ 4.5660561770291865
+ 4.566090489046486
+ 4.5661248007071125
+ 4.566159112011073
+ 4.566193422958381
+ 4.566227733549044
+ 4.566262043783074
+ 4.566296353660481
+ 4.566330663181273
+ 4.566364972345462
+ 4.566399281153057
+ 4.5664335896040695
+ 4.566467897698508
+ 4.5665022054363815
+ 4.566536512817703
+ 4.5665708198424815
+ 4.566605126510726
+ 4.566639432822448
+ 4.566673738777657
+ 4.566708044376362
+ 4.566742349618575
+ 4.566776654504304
+ 4.566810959033561
+ 4.566845263206355
+ 4.566879567022696
+ 4.566913870482593
+ 4.566948173586059
+ 4.566982476333102
+ 4.567016778723732
+ 4.567051080757961
+ 4.5670853824357955
+ 4.567119683757248
+ 4.567153984722329
+ 4.567188285331048
+ 4.567222585583413
+ 4.567256885479438
+ 4.567291185019128
+ 4.567325484202498
+ 4.567359783029556
+ 4.567394081500311
+ 4.567428379614773
+ 4.567462677372955
+ 4.567496974774865
+ 4.567531271820512
+ 4.567565568509908
+ 4.567599864843062
+ 4.567634160819983
+ 4.567668456440684
+ 4.567702751705173
+ 4.567737046613461
+ 4.567771341165555
+ 4.56780563536147
+ 4.567839929201213
+ 4.567874222684794
+ 4.567908515812223
+ 4.567942808583512
+ 4.56797710099867
+ 4.568011393057705
+ 4.568045684760629
+ 4.568079976107453
+ 4.568114267098185
+ 4.568148557732837
+ 4.568182848011416
+ 4.568217137933934
+ 4.568251427500403
+ 4.568285716710831
+ 4.5683200055652256
+ 4.568354294063602
+ 4.568388582205965
+ 4.568422869992328
+ 4.568457157422701
+ 4.568491444497093
+ 4.568525731215513
+ 4.568560017577974
+ 4.568594303584483
+ 4.568628589235052
+ 4.56866287452969
+ 4.568697159468408
+ 4.568731444051214
+ 4.568765728278122
+ 4.568800012149137
+ 4.5688342956642725
+ 4.568868578823537
+ 4.568902861626942
+ 4.5689371440744955
+ 4.568971426166209
+ 4.569005707902093
+ 4.569039989282156
+ 4.569074270306409
+ 4.56910855097486
+ 4.5691428312875235
+ 4.5691771112444055
+ 4.569211390845516
+ 4.569245670090868
+ 4.569279948980469
+ 4.56931422751433
+ 4.569348505692461
+ 4.569382783514872
+ 4.569417060981572
+ 4.569451338092573
+ 4.569485614847884
+ 4.569519891247515
+ 4.569554167291474
+ 4.569588442979775
+ 4.569622718312425
+ 4.569656993289436
+ 4.569691267910817
+ 4.5697255421765774
+ 4.569759816086727
+ 4.569794089641278
+ 4.569828362840239
+ 4.569862635683619
+ 4.5698969081714305
+ 4.569931180303682
+ 4.569965452080383
+ 4.569999723501545
+ 4.570033994567176
+ 4.570068265277288
+ 4.57010253563189
+ 4.570136805630992
+ 4.5701710752746045
+ 4.570205344562737
+ 4.570239613495399
+ 4.570273882072602
+ 4.570308150294356
+ 4.57034241816067
+ 4.570376685671554
+ 4.570410952827017
+ 4.570445219627072
+ 4.570479486071727
+ 4.570513752160991
+ 4.570548017894876
+ 4.570582283273391
+ 4.570616548296547
+ 4.570650812964354
+ 4.57068507727682
+ 4.570719341233957
+ 4.570753604835773
+ 4.57078786808228
+ 4.570822130973489
+ 4.570856393509406
+ 4.570890655690044
+ 4.570924917515413
+ 4.570959178985522
+ 4.57099344010038
+ 4.571027700859999
+ 4.571061961264389
+ 4.571096221313559
+ 4.571130481007518
+ 4.57116474034628
+ 4.57119899932985
+ 4.571233257958242
+ 4.571267516231463
+ 4.571301774149524
+ 4.571336031712436
+ 4.571370288920208
+ 4.57140454577285
+ 4.5714388022703725
+ 4.571473058412786
+ 4.571507314200098
+ 4.571541569632322
+ 4.571575824709464
+ 4.571610079431539
+ 4.571644333798552
+ 4.571678587810515
+ 4.57171284146744
+ 4.571747094769334
+ 4.571781347716209
+ 4.5718156003080725
+ 4.571849852544937
+ 4.571884104426812
+ 4.571918355953707
+ 4.571952607125631
+ 4.571986857942597
+ 4.572021108404611
+ 4.572055358511687
+ 4.572089608263831
+ 4.572123857661056
+ 4.5721581067033705
+ 4.5721923553907855
+ 4.57222660372331
+ 4.572260851700955
+ 4.57229509932373
+ 4.572329346591643
+ 4.572363593504708
+ 4.572397840062932
+ 4.572432086266327
+ 4.5724663321148995
+ 4.572500577608663
+ 4.572534822747627
+ 4.572569067531799
+ 4.572603311961192
+ 4.572637556035814
+ 4.5726717997556765
+ 4.572706043120788
+ 4.572740286131159
+ 4.5727745287868
+ 4.57280877108772
+ 4.572843013033929
+ 4.57287725462544
+ 4.572911495862258
+ 4.572945736744397
+ 4.572979977271864
+ 4.573014217444671
+ 4.5730484572628285
+ 4.573082696726344
+ 4.573116935835229
+ 4.573151174589492
+ 4.5731854129891465
+ 4.5732196510342
+ 4.573253888724661
+ 4.573288126060543
+ 4.573322363041853
+ 4.573356599668601
+ 4.573390835940801
+ 4.573425071858457
+ 4.573459307421584
+ 4.57349354263019
+ 4.5735277774842835
+ 4.573562011983877
+ 4.573596246128979
+ 4.573630479919599
+ 4.573664713355749
+ 4.573698946437436
+ 4.573733179164673
+ 4.573767411537468
+ 4.573801643555832
+ 4.573835875219776
+ 4.5738701065293075
+ 4.573904337484437
+ 4.5739385680851745
+ 4.573972798331531
+ 4.574007028223516
+ 4.574041257761139
+ 4.574075486944411
+ 4.57410971577334
+ 4.574143944247938
+ 4.574178172368214
+ 4.5742124001341775
+ 4.574246627545841
+ 4.57428085460321
+ 4.574315081306298
+ 4.5743493076551145
+ 4.574383533649668
+ 4.57441775928997
+ 4.574451984576029
+ 4.574486209507857
+ 4.5745204340854615
+ 4.574554658308854
+ 4.574588882178044
+ 4.574623105693042
+ 4.574657328853856
+ 4.574691551660499
+ 4.574725774112979
+ 4.574759996211307
+ 4.574794217955491
+ 4.574828439345542
+ 4.574862660381472
+ 4.574896881063288
+ 4.574931101391
+ 4.57496532136462
+ 4.574999540984157
+ 4.575033760249621
+ 4.575067979161022
+ 4.575102197718369
+ 4.575136415921674
+ 4.575170633770944
+ 4.575204851266191
+ 4.575239068407425
+ 4.575273285194656
+ 4.5753075016278935
+ 4.575341717707146
+ 4.575375933432426
+ 4.5754101488037415
+ 4.575444363821104
+ 4.575478578484521
+ 4.575512792794005
+ 4.575547006749566
+ 4.575581220351212
+ 4.575615433598954
+ 4.575649646492802
+ 4.575683859032765
+ 4.575718071218854
+ 4.575752283051079
+ 4.57578649452945
+ 4.5758207056539755
+ 4.5758549164246665
+ 4.575889126841533
+ 4.5759233369045855
+ 4.575957546613833
+ 4.575991755969285
+ 4.5760259649709525
+ 4.576060173618845
+ 4.576094381912972
+ 4.576128589853344
+ 4.576162797439971
+ 4.576197004672863
+ 4.576231211552029
+ 4.5762654180774796
+ 4.576299624249225
+ 4.576333830067275
+ 4.576368035531639
+ 4.576402240642328
+ 4.576436445399351
+ 4.576470649802718
+ 4.576504853852438
+ 4.576539057548524
+ 4.576573260890982
+ 4.576607463879825
+ 4.576641666515062
+ 4.576675868796702
+ 4.576710070724756
+ 4.5767442722992335
+ 4.576778473520144
+ 4.576812674387498
+ 4.576846874901305
+ 4.576881075061576
+ 4.57691527486832
+ 4.576949474321547
+ 4.5769836734212666
+ 4.577017872167489
+ 4.5770520705602245
+ 4.577086268599483
+ 4.577120466285273
+ 4.577154663617607
+ 4.577188860596493
+ 4.577223057221941
+ 4.577257253493962
+ 4.577291449412565
+ 4.577325644977759
+ 4.577359840189556
+ 4.5773940350479645
+ 4.5774282295529956
+ 4.577462423704659
+ 4.5774966175029626
+ 4.577530810947918
+ 4.577565004039535
+ 4.5775991967778245
+ 4.577633389162795
+ 4.577667581194455
+ 4.5777017728728175
+ 4.577735964197891
+ 4.577770155169686
+ 4.577804345788211
+ 4.577838536053477
+ 4.577872725965495
+ 4.577906915524271
+ 4.577941104729819
+ 4.577975293582148
+ 4.578009482081267
+ 4.578043670227186
+ 4.578077858019914
+ 4.578112045459464
+ 4.578146232545842
+ 4.578180419279061
+ 4.578214605659129
+ 4.5782487916860575
+ 4.578282977359855
+ 4.578317162680532
+ 4.578351347648098
+ 4.578385532262565
+ 4.578419716523939
+ 4.578453900432233
+ 4.578488083987455
+ 4.5785222671896175
+ 4.578556450038727
+ 4.578590632534795
+ 4.578624814677833
+ 4.5786589964678495
+ 4.578693177904853
+ 4.578727358988856
+ 4.578761539719867
+ 4.578795720097895
+ 4.57882990012295
+ 4.578864079795045
+ 4.578898259114188
+ 4.578932438080386
+ 4.578966616693653
+ 4.579000794953997
+ 4.579034972861429
+ 4.5790691504159575
+ 4.5791033276175925
+ 4.579137504466345
+ 4.579171680962225
+ 4.579205857105241
+ 4.579240032895403
+ 4.5792742083327225
+ 4.579308383417208
+ 4.57934255814887
+ 4.5793767325277175
+ 4.579410906553761
+ 4.5794450802270115
+ 4.579479253547476
+ 4.579513426515168
+ 4.579547599130094
+ 4.579581771392267
+ 4.579615943301694
+ 4.579650114858387
+ 4.579684286062355
+ 4.579718456913608
+ 4.579752627412155
+ 4.579786797558008
+ 4.579820967351175
+ 4.579855136791666
+ 4.579889305879492
+ 4.579923474614662
+ 4.579957642997187
+ 4.5799918110270745
+ 4.580025978704337
+ 4.580060146028983
+ 4.580094313001023
+ 4.580128479620466
+ 4.580162645887323
+ 4.580196811801603
+ 4.580230977363315
+ 4.580265142572471
+ 4.58029930742908
+ 4.5803334719331525
+ 4.580367636084697
+ 4.580401799883723
+ 4.580435963330243
+ 4.580470126424264
+ 4.580504289165797
+ 4.580538451554854
+ 4.580572613591442
+ 4.58060677527557
+ 4.580640936607251
+ 4.580675097586495
+ 4.580709258213308
+ 4.580743418487703
+ 4.580777578409689
+ 4.5808117379792765
+ 4.580845897196475
+ 4.580880056061293
+ 4.580914214573743
+ 4.5809483727338325
+ 4.580982530541572
+ 4.581016687996972
+ 4.581050845100043
+ 4.581085001850793
+ 4.581119158249233
+ 4.5811533142953715
+ 4.581187469989221
+ 4.58122162533079
+ 4.581255780320087
+ 4.581289934957124
+ 4.581324089241909
+ 4.581358243174454
+ 4.581392396754767
+ 4.581426549982858
+ 4.581460702858738
+ 4.581494855382417
+ 4.581529007553902
+ 4.581563159373206
+ 4.581597310840338
+ 4.581631461955308
+ 4.581665612718124
+ 4.5816997631288
+ 4.581733913187342
+ 4.58176806289376
+ 4.581802212248066
+ 4.581836361250268
+ 4.581870509900377
+ 4.581904658198403
+ 4.581938806144356
+ 4.581972953738243
+ 4.582007100980078
+ 4.582041247869868
+ 4.582075394407624
+ 4.582109540593356
+ 4.582143686427073
+ 4.582177831908785
+ 4.582211977038503
+ 4.582246121816235
+ 4.582280266241992
+ 4.582314410315784
+ 4.582348554037621
+ 4.582382697407512
+ 4.582416840425467
+ 4.582450983091498
+ 4.5824851254056105
+ 4.582519267367817
+ 4.582553408978129
+ 4.5825875502365525
+ 4.5826216911431
+ 4.582655831697781
+ 4.582689971900605
+ 4.582724111751581
+ 4.58275825125072
+ 4.5827923903980325
+ 4.582826529193526
+ 4.582860667637212
+ 4.582894805729101
+ 4.5829289434692
+ 4.582963080857523
+ 4.582997217894077
+ 4.583031354578872
+ 4.583065490911918
+ 4.583099626893226
+ 4.583133762522803
+ 4.583167897800664
+ 4.583202032726813
+ 4.583236167301263
+ 4.583270301524022
+ 4.583304435395103
+ 4.583338568914514
+ 4.583372702082264
+ 4.583406834898364
+ 4.583440967362823
+ 4.583475099475652
+ 4.583509231236859
+ 4.583543362646456
+ 4.583577493704451
+ 4.583611624410854
+ 4.583645754765676
+ 4.5836798847689275
+ 4.583714014420615
+ 4.583748143720753
+ 4.583782272669346
+ 4.583816401266409
+ 4.583850529511948
+ 4.583884657405974
+ 4.583918784948499
+ 4.583952912139528
+ 4.583987038979076
+ 4.58402116546715
+ 4.58405529160376
+ 4.584089417388916
+ 4.584123542822628
+ 4.584157667904906
+ 4.584191792635759
+ 4.5842259170152
+ 4.584260041043233
+ 4.584294164719872
+ 4.584328288045128
+ 4.584362411019007
+ 4.58439653364152
+ 4.584430655912679
+ 4.584464777832491
+ 4.584498899400968
+ 4.584533020618119
+ 4.584567141483952
+ 4.58460126199848
+ 4.584635382161712
+ 4.584669501973655
+ 4.584703621434322
+ 4.584737740543723
+ 4.584771859301864
+ 4.5848059777087595
+ 4.584840095764417
+ 4.584874213468845
+ 4.584908330822056
+ 4.584942447824059
+ 4.5849765644748635
+ 4.585010680774478
+ 4.585044796722914
+ 4.585078912320181
+ 4.5851130275662895
+ 4.585147142461248
+ 4.5851812570050665
+ 4.585215371197756
+ 4.585249485039325
+ 4.5852835985297835
+ 4.585317711669142
+ 4.585351824457409
+ 4.585385936894596
+ 4.585420048980712
+ 4.585454160715767
+ 4.58548827209977
+ 4.585522383132732
+ 4.585556493814662
+ 4.585590604145569
+ 4.585624714125466
+ 4.5856588237543585
+ 4.585692933032259
+ 4.585727041959178
+ 4.585761150535122
+ 4.585795258760104
+ 4.585829366634133
+ 4.585863474157218
+ 4.58589758132937
+ 4.585931688150597
+ 4.58596579462091
+ 4.585999900740318
+ 4.586034006508832
+ 4.586068111926463
+ 4.586102216993217
+ 4.586136321709105
+ 4.5861704260741405
+ 4.586204530088328
+ 4.586238633751681
+ 4.586272737064209
+ 4.586306840025919
+ 4.586340942636824
+ 4.586375044896931
+ 4.586409146806251
+ 4.5864432483647954
+ 4.586477349572572
+ 4.586511450429591
+ 4.586545550935863
+ 4.586579651091396
+ 4.586613750896202
+ 4.586647850350289
+ 4.586681949453669
+ 4.586716048206349
+ 4.58675014660834
+ 4.586784244659653
+ 4.586818342360297
+ 4.586852439710279
+ 4.586886536709613
+ 4.586920633358307
+ 4.586954729656371
+ 4.5869888256038145
+ 4.5870229212006475
+ 4.58705701644688
+ 4.58709111134252
+ 4.58712520588758
+ 4.587159300082069
+ 4.587193393925996
+ 4.58722748741937
+ 4.5872615805622035
+ 4.587295673354505
+ 4.587329765796283
+ 4.587363857887548
+ 4.58739794962831
+ 4.587432041018579
+ 4.587466132058365
+ 4.5875002227476775
+ 4.587534313086525
+ 4.58756840307492
+ 4.587602492712871
+ 4.587636582000386
+ 4.587670670937476
+ 4.5877047595241525
+ 4.5877388477604235
+ 4.587772935646298
+ 4.587807023181789
+ 4.587841110366902
+ 4.58787519720165
+ 4.587909283686042
+ 4.587943369820087
+ 4.587977455603795
+ 4.588011541037177
+ 4.58804562612024
+ 4.588079710852998
+ 4.588113795235456
+ 4.588147879267628
+ 4.588181962949521
+ 4.588216046281146
+ 4.588250129262511
+ 4.58828421189363
+ 4.588318294174507
+ 4.588352376105157
+ 4.588386457685587
+ 4.588420538915806
+ 4.588454619795826
+ 4.588488700325656
+ 4.588522780505306
+ 4.588556860334784
+ 4.588590939814102
+ 4.588625018943269
+ 4.588659097722294
+ 4.588693176151188
+ 4.588727254229961
+ 4.5887613319586205
+ 4.588795409337178
+ 4.588829486365643
+ 4.5888635630440255
+ 4.588897639372335
+ 4.58893171535058
+ 4.588965790978773
+ 4.588999866256922
+ 4.589033941185036
+ 4.589068015763128
+ 4.589102089991203
+ 4.5891361638692745
+ 4.589170237397352
+ 4.589204310575442
+ 4.589238383403559
+ 4.589272455881709
+ 4.589306528009903
+ 4.589340599788152
+ 4.589374671216464
+ 4.589408742294848
+ 4.589442813023316
+ 4.589476883401878
+ 4.589510953430541
+ 4.589545023109318
+ 4.589579092438217
+ 4.589613161417247
+ 4.589647230046419
+ 4.589681298325742
+ 4.589715366255226
+ 4.589749433834881
+ 4.589783501064717
+ 4.589817567944743
+ 4.58985163447497
+ 4.5898857006554055
+ 4.589919766486062
+ 4.589953831966947
+ 4.589987897098071
+ 4.590021961879445
+ 4.5900560263110775
+ 4.590090090392977
+ 4.590124154125156
+ 4.590158217507622
+ 4.590192280540386
+ 4.590226343223456
+ 4.590260405556845
+ 4.59029446754056
+ 4.590328529174611
+ 4.5903625904590095
+ 4.590396651393764
+ 4.590430711978883
+ 4.590464772214379
+ 4.59049883210026
+ 4.590532891636536
+ 4.590566950823216
+ 4.590601009660311
+ 4.59063506814783
+ 4.590669126285784
+ 4.59070318407418
+ 4.590737241513031
+ 4.590771298602344
+ 4.590805355342131
+ 4.5908394117324
+ 4.590873467773162
+ 4.590907523464426
+ 4.590941578806202
+ 4.590975633798499
+ 4.591009688441328
+ 4.591043742734698
+ 4.591077796678618
+ 4.5911118502731
+ 4.59114590351815
+ 4.591179956413782
+ 4.591214008960002
+ 4.591248061156823
+ 4.591282113004254
+ 4.5913161645023015
+ 4.59135021565098
+ 4.591384266450295
+ 4.591418316900259
+ 4.5914523670008816
+ 4.59148641675217
+ 4.591520466154138
+ 4.5915545152067905
+ 4.5915885639101415
+ 4.5916226122641985
+ 4.5916566602689715
+ 4.591690707924471
+ 4.591724755230706
+ 4.591758802187686
+ 4.591792848795421
+ 4.591826895053921
+ 4.591860940963196
+ 4.591894986523254
+ 4.591929031734108
+ 4.591963076595765
+ 4.5919971211082355
+ 4.5920311652715275
+ 4.592065209085654
+ 4.592099252550624
+ 4.592133295666445
+ 4.592167338433128
+ 4.592201380850683
+ 4.592235422919119
+ 4.592269464638447
+ 4.592303506008676
+ 4.592337547029815
+ 4.592371587701875
+ 4.5924056280248635
+ 4.592439667998793
+ 4.592473707623673
+ 4.5925077468995115
+ 4.592541785826318
+ 4.592575824404103
+ 4.592609862632878
+ 4.59264390051265
+ 4.592677938043431
+ 4.592711975225227
+ 4.592746012058052
+ 4.592780048541914
+ 4.592814084676823
+ 4.5928481204627865
+ 4.592882155899818
+ 4.592916190987924
+ 4.592950225727115
+ 4.592984260117402
+ 4.593018294158795
+ 4.593052327851301
+ 4.593086361194932
+ 4.593120394189697
+ 4.593154426835606
+ 4.593188459132668
+ 4.593222491080892
+ 4.593256522680291
+ 4.5932905539308715
+ 4.5933245848326445
+ 4.593358615385618
+ 4.593392645589805
+ 4.593426675445213
+ 4.593460704951852
+ 4.593494734109731
+ 4.5935287629188615
+ 4.593562791379251
+ 4.593596819490911
+ 4.593630847253851
+ 4.59366487466808
+ 4.593698901733608
+ 4.593732928450444
+ 4.593766954818599
+ 4.593800980838081
+ 4.593835006508902
+ 4.59386903183107
+ 4.593903056804596
+ 4.5939370814294875
+ 4.593971105705757
+ 4.594005129633411
+ 4.594039153212462
+ 4.594073176442918
+ 4.59410719932479
+ 4.594141221858086
+ 4.594175244042818
+ 4.594209265878994
+ 4.5942432873666235
+ 4.594277308505718
+ 4.594311329296285
+ 4.594345349738335
+ 4.594379369831878
+ 4.594413389576923
+ 4.594447408973482
+ 4.594481428021562
+ 4.594515446721173
+ 4.594549465072326
+ 4.59458348307503
+ 4.594617500729294
+ 4.594651518035129
+ 4.594685534992545
+ 4.594719551601549
+ 4.594753567862153
+ 4.594787583774366
+ 4.594821599338198
+ 4.5948556145536585
+ 4.594889629420757
+ 4.594923643939503
+ 4.594957658109908
+ 4.594991671931979
+ 4.5950256854057265
+ 4.595059698531162
+ 4.595093711308293
+ 4.595127723737129
+ 4.5951617358176815
+ 4.595195747549959
+ 4.595229758933972
+ 4.595263769969729
+ 4.595297780657241
+ 4.595331790996517
+ 4.595365800987566
+ 4.5953998106304
+ 4.595433819925025
+ 4.595467828871453
+ 4.595501837469694
+ 4.595535845719758
+ 4.595569853621653
+ 4.595603861175388
+ 4.595637868380976
+ 4.595671875238424
+ 4.595705881747743
+ 4.595739887908941
+ 4.59577389372203
+ 4.595807899187018
+ 4.595841904303915
+ 4.595875909072731
+ 4.595909913493475
+ 4.595943917566158
+ 4.595977921290788
+ 4.596011924667376
+ 4.596045927695931
+ 4.596079930376463
+ 4.596113932708982
+ 4.596147934693495
+ 4.596181936330015
+ 4.596215937618551
+ 4.5962499385591125
+ 4.596283939151708
+ 4.596317939396348
+ 4.596351939293043
+ 4.596385938841801
+ 4.596419938042633
+ 4.596453936895547
+ 4.596487935400556
+ 4.596521933557666
+ 4.596555931366888
+ 4.596589928828232
+ 4.596623925941708
+ 4.596657922707324
+ 4.596691919125092
+ 4.5967259151950195
+ 4.596759910917119
+ 4.596793906291396
+ 4.596827901317864
+ 4.596861895996529
+ 4.596895890327405
+ 4.596929884310499
+ 4.59696387794582
+ 4.596997871233379
+ 4.597031864173187
+ 4.59706585676525
+ 4.597099849009579
+ 4.597133840906187
+ 4.59716783245508
+ 4.597201823656268
+ 4.597235814509761
+ 4.5972698050155705
+ 4.597303795173703
+ 4.59733778498417
+ 4.597371774446981
+ 4.597405763562147
+ 4.597439752329675
+ 4.597473740749575
+ 4.597507728821859
+ 4.597541716546535
+ 4.597575703923613
+ 4.597609690953101
+ 4.597643677635011
+ 4.597677663969352
+ 4.597711649956134
+ 4.597745635595365
+ 4.5977796208870565
+ 4.597813605831217
+ 4.597847590427856
+ 4.597881574676983
+ 4.59791555857861
+ 4.597949542132744
+ 4.597983525339395
+ 4.598017508198574
+ 4.598051490710291
+ 4.598085472874553
+ 4.598119454691371
+ 4.5981534361607554
+ 4.598187417282715
+ 4.598221398057261
+ 4.598255378484399
+ 4.598289358564143
+ 4.598323338296502
+ 4.598357317681483
+ 4.598391296719098
+ 4.5984252754093555
+ 4.5984592537522655
+ 4.598493231747837
+ 4.598527209396082
+ 4.598561186697007
+ 4.598595163650624
+ 4.598629140256942
+ 4.5986631165159695
+ 4.5986970924277175
+ 4.598731067992195
+ 4.598765043209411
+ 4.598799018079377
+ 4.598832992602102
+ 4.598866966777593
+ 4.598900940605864
+ 4.598934914086921
+ 4.598968887220776
+ 4.599002860007437
+ 4.599036832446915
+ 4.599070804539219
+ 4.599104776284358
+ 4.599138747682342
+ 4.599172718733181
+ 4.599206689436886
+ 4.5992406597934625
+ 4.599274629802924
+ 4.59930859946528
+ 4.599342568780537
+ 4.599376537748707
+ 4.5994105063698
+ 4.599444474643825
+ 4.599478442570791
+ 4.599512410150709
+ 4.599546377383586
+ 4.599580344269435
+ 4.5996143108082626
+ 4.599648277000081
+ 4.599682242844898
+ 4.599716208342724
+ 4.599750173493567
+ 4.59978413829744
+ 4.599818102754351
+ 4.599852066864308
+ 4.599886030627323
+ 4.599919994043404
+ 4.59995395711256
+ 4.5999879198348035
+ 4.600021882210142
+ 4.600055844238585
+ 4.600089805920144
+ 4.600123767254827
+ 4.6001577282426425
+ 4.600191688883602
+ 4.600225649177715
+ 4.600259609124991
+ 4.600293568725439
+ 4.600327527979069
+ 4.600361486885891
+ 4.600395445445913
+ 4.600429403659147
+ 4.600463361525601
+ 4.600497319045285
+ 4.6005312762182085
+ 4.6005652330443825
+ 4.600599189523813
+ 4.600633145656514
+ 4.600667101442492
+ 4.600701056881758
+ 4.600735011974321
+ 4.600768966720191
+ 4.600802921119378
+ 4.600836875171891
+ 4.60087082887774
+ 4.600904782236934
+ 4.600938735249483
+ 4.600972687915396
+ 4.601006640234685
+ 4.601040592207355
+ 4.60107454383342
+ 4.6011084951128876
+ 4.601142446045769
+ 4.601176396632071
+ 4.601210346871805
+ 4.601244296764981
+ 4.601278246311607
+ 4.601312195511695
+ 4.601346144365253
+ 4.601380092872289
+ 4.601414041032816
+ 4.601447988846841
+ 4.601481936314376
+ 4.601515883435428
+ 4.601549830210008
+ 4.601583776638126
+ 4.60161772271979
+ 4.601651668455012
+ 4.601685613843799
+ 4.6017195588861615
+ 4.60175350358211
+ 4.601787447931654
+ 4.601821391934801
+ 4.601855335591564
+ 4.6018892789019485
+ 4.6019232218659685
+ 4.60195716448363
+ 4.601991106754945
+ 4.602025048679922
+ 4.60205899025857
+ 4.602092931490899
+ 4.60212687237692
+ 4.602160812916641
+ 4.602194753110073
+ 4.602228692957224
+ 4.602262632458103
+ 4.602296571612722
+ 4.60233051042109
+ 4.602364448883216
+ 4.602398386999108
+ 4.602432324768778
+ 4.602466262192236
+ 4.602500199269489
+ 4.602534136000547
+ 4.602568072385423
+ 4.602602008424124
+ 4.602635944116657
+ 4.602669879463036
+ 4.60270381446327
+ 4.602737749117366
+ 4.602771683425335
+ 4.602805617387187
+ 4.602839551002932
+ 4.6028734842725765
+ 4.602907417196134
+ 4.602941349773612
+ 4.602975282005021
+ 4.60300921389037
+ 4.603043145429669
+ 4.603077076622927
+ 4.603111007470153
+ 4.603144937971359
+ 4.603178868126552
+ 4.6032127979357425
+ 4.60324672739894
+ 4.603280656516155
+ 4.603314585287396
+ 4.603348513712672
+ 4.603382441791994
+ 4.603416369525371
+ 4.603450296912814
+ 4.60348422395433
+ 4.603518150649929
+ 4.603552076999623
+ 4.603586003003419
+ 4.6036199286613275
+ 4.603653853973357
+ 4.60368777893952
+ 4.603721703559824
+ 4.6037556278342775
+ 4.603789551762891
+ 4.603823475345675
+ 4.60385739858264
+ 4.603891321473792
+ 4.603925244019144
+ 4.603959166218703
+ 4.603993088072481
+ 4.604027009580485
+ 4.604060930742727
+ 4.604094851559215
+ 4.604128772029958
+ 4.604162692154968
+ 4.604196611934253
+ 4.604230531367822
+ 4.604264450455686
+ 4.604298369197853
+ 4.604332287594334
+ 4.604366205645138
+ 4.604400123350274
+ 4.604434040709752
+ 4.604467957723582
+ 4.604501874391774
+ 4.604535790714334
+ 4.604569706691278
+ 4.6046036223226094
+ 4.60463753760834
+ 4.604671452548481
+ 4.6047053671430405
+ 4.604739281392027
+ 4.6047731952954525
+ 4.604807108853324
+ 4.604841022065653
+ 4.6048749349324485
+ 4.604908847453719
+ 4.604942759629476
+ 4.604976671459727
+ 4.605010582944483
+ 4.605044494083754
+ 4.605078404877547
+ 4.605112315325875
+ 4.605146225428744
+ 4.605180135186167
+ 4.60521404459815
+ 4.605247953664706
+ 4.6052818623858425
+ 4.605315770761569
+ 4.605349678791896
+ 4.605383586476832
+ 4.605417493816388
+ 4.605451400810572
+ 4.6054853074593955
+ 4.605519213762866
+ 4.605553119720994
+ 4.605587025333788
+ 4.605620930601259
+ 4.605654835523417
+ 4.60568874010027
+ 4.605722644331828
+ 4.6057565482181
+ 4.6057904517590975
+ 4.605824354954828
+ 4.605858257805301
+ 4.605892160310528
+ 4.605926062470517
+ 4.605959964285278
+ 4.60599386575482
+ 4.606027766879154
+ 4.606061667658288
+ 4.606095568092231
+ 4.606129468180995
+ 4.606163367924587
+ 4.606197267323019
+ 4.606231166376298
+ 4.606265065084435
+ 4.606298963447441
+ 4.606332861465321
+ 4.606366759138089
+ 4.606400656465753
+ 4.606434553448322
+ 4.6064684500858055
+ 4.606502346378214
+ 4.606536242325557
+ 4.606570137927844
+ 4.606604033185083
+ 4.6066379280972845
+ 4.60667182266446
+ 4.606705716886616
+ 4.606739610763762
+ 4.60677350429591
+ 4.606807397483069
+ 4.606841290325248
+ 4.6068751828224555
+ 4.606909074974701
+ 4.606942966781997
+ 4.606976858244349
+ 4.60701074936177
+ 4.607044640134267
+ 4.607078530561851
+ 4.607112420644531
+ 4.6071463103823165
+ 4.607180199775217
+ 4.607214088823243
+ 4.607247977526402
+ 4.607281865884706
+ 4.607315753898162
+ 4.607349641566782
+ 4.607383528890574
+ 4.607417415869547
+ 4.607451302503711
+ 4.607485188793078
+ 4.607519074737653
+ 4.60755296033745
+ 4.607586845592475
+ 4.607620730502738
+ 4.607654615068252
+ 4.607688499289022
+ 4.60772238316506
+ 4.607756266696375
+ 4.607790149882978
+ 4.607824032724875
+ 4.6078579152220795
+ 4.607891797374598
+ 4.607925679182441
+ 4.607959560645619
+ 4.6079934417641395
+ 4.608027322538013
+ 4.60806120296725
+ 4.608095083051859
+ 4.6081289627918505
+ 4.608162842187232
+ 4.608196721238015
+ 4.608230599944208
+ 4.608264478305821
+ 4.608298356322862
+ 4.608332233995343
+ 4.608366111323273
+ 4.608399988306659
+ 4.608433864945513
+ 4.608467741239845
+ 4.6085016171896624
+ 4.608535492794975
+ 4.608569368055795
+ 4.608603242972128
+ 4.608637117543985
+ 4.608670991771378
+ 4.608704865654313
+ 4.608738739192801
+ 4.6087726123868515
+ 4.6088064852364745
+ 4.608840357741678
+ 4.608874229902473
+ 4.6089081017188684
+ 4.6089419731908725
+ 4.608975844318498
+ 4.6090097151017515
+ 4.609043585540643
+ 4.609077455635183
+ 4.609111325385381
+ 4.609145194791245
+ 4.609179063852785
+ 4.609212932570013
+ 4.609246800942935
+ 4.609280668971562
+ 4.609314536655903
+ 4.60934840399597
+ 4.609382270991769
+ 4.609416137643311
+ 4.609450003950605
+ 4.609483869913662
+ 4.60951773553249
+ 4.609551600807099
+ 4.609585465737498
+ 4.609619330323698
+ 4.609653194565706
+ 4.609687058463534
+ 4.60972092201719
+ 4.609754785226683
+ 4.6097886480920245
+ 4.609822510613223
+ 4.609856372790287
+ 4.6098902346232284
+ 4.609924096112055
+ 4.609957957256775
+ 4.6099918180574
+ 4.6100256785139395
+ 4.610059538626402
+ 4.610093398394798
+ 4.610127257819135
+ 4.610161116899425
+ 4.610194975635675
+ 4.610228834027897
+ 4.610262692076098
+ 4.61029654978029
+ 4.610330407140481
+ 4.61036426415668
+ 4.610398120828899
+ 4.610431977157144
+ 4.6104658331414266
+ 4.610499688781755
+ 4.610533544078141
+ 4.610567399030593
+ 4.6106012536391185
+ 4.61063510790373
+ 4.610668961824435
+ 4.610702815401243
+ 4.610736668634165
+ 4.610770521523209
+ 4.610804374068386
+ 4.610838226269704
+ 4.610872078127173
+ 4.610905929640802
+ 4.610939780810601
+ 4.61097363163658
+ 4.6110074821187474
+ 4.6110413322571135
+ 4.611075182051687
+ 4.611109031502478
+ 4.6111428806094965
+ 4.611176729372751
+ 4.61121057779225
+ 4.611244425868006
+ 4.611278273600026
+ 4.61131212098832
+ 4.611345968032898
+ 4.611379814733769
+ 4.611413661090943
+ 4.611447507104428
+ 4.611481352774236
+ 4.611515198100373
+ 4.611549043082853
+ 4.611582887721681
+ 4.61161673201687
+ 4.611650575968427
+ 4.611684419576362
+ 4.611718262840685
+ 4.611752105761406
+ 4.611785948338534
+ 4.611819790572078
+ 4.611853632462047
+ 4.611887474008452
+ 4.611921315211301
+ 4.611955156070605
+ 4.611988996586372
+ 4.612022836758612
+ 4.6120566765873345
+ 4.612090516072549
+ 4.612124355214266
+ 4.612158194012493
+ 4.61219203246724
+ 4.612225870578517
+ 4.612259708346334
+ 4.612293545770699
+ 4.612327382851624
+ 4.612361219589114
+ 4.612395055983183
+ 4.612428892033838
+ 4.6124627277410895
+ 4.612496563104945
+ 4.6125303981254175
+ 4.612564232802513
+ 4.612598067136243
+ 4.612631901126617
+ 4.6126657347736435
+ 4.612699568077331
+ 4.6127334010376915
+ 4.612767233654734
+ 4.6128010659284655
+ 4.612834897858898
+ 4.61286872944604
+ 4.612902560689901
+ 4.612936391590489
+ 4.612970222147817
+ 4.613004052361892
+ 4.613037882232724
+ 4.613071711760321
+ 4.613105540944694
+ 4.613139369785854
+ 4.613173198283807
+ 4.613207026438563
+ 4.613240854250135
+ 4.613274681718529
+ 4.6133085088437555
+ 4.613342335625823
+ 4.6133761620647435
+ 4.613409988160524
+ 4.613443813913175
+ 4.6134776393227055
+ 4.613511464389125
+ 4.613545289112443
+ 4.613579113492669
+ 4.613612937529813
+ 4.613646761223882
+ 4.613680584574889
+ 4.613714407582842
+ 4.613748230247751
+ 4.613782052569623
+ 4.613815874548469
+ 4.6138496961843
+ 4.613883517477123
+ 4.613917338426949
+ 4.613951159033786
+ 4.613984979297645
+ 4.6140187992185355
+ 4.614052618796466
+ 4.614086438031445
+ 4.614120256923485
+ 4.614154075472592
+ 4.614187893678777
+ 4.61422171154205
+ 4.61425552906242
+ 4.614289346239896
+ 4.614323163074487
+ 4.614356979566203
+ 4.614390795715056
+ 4.614424611521051
+ 4.614458426984199
+ 4.614492242104511
+ 4.614526056881997
+ 4.614559871316662
+ 4.614593685408519
+ 4.614627499157576
+ 4.614661312563844
+ 4.614695125627332
+ 4.6147289383480485
+ 4.614762750726004
+ 4.614796562761206
+ 4.614830374453666
+ 4.614864185803392
+ 4.614897996810394
+ 4.614931807474683
+ 4.6149656177962655
+ 4.614999427775153
+ 4.615033237411354
+ 4.615067046704879
+ 4.6151008556557365
+ 4.615134664263936
+ 4.6151684725294855
+ 4.615202280452397
+ 4.615236088032679
+ 4.615269895270341
+ 4.615303702165392
+ 4.615337508717841
+ 4.6153713149277
+ 4.615405120794976
+ 4.615438926319677
+ 4.615472731501816
+ 4.6155065363414
+ 4.6155403408384394
+ 4.615574144992943
+ 4.615607948804921
+ 4.6156417522743824
+ 4.615675555401337
+ 4.615709358185793
+ 4.615743160627762
+ 4.615776962727251
+ 4.615810764484271
+ 4.615844565898831
+ 4.61587836697094
+ 4.615912167700608
+ 4.6159459680878445
+ 4.615979768132658
+ 4.616013567835059
+ 4.616047367195057
+ 4.61608116621266
+ 4.6161149648878785
+ 4.616148763220721
+ 4.616182561211199
+ 4.61621635885932
+ 4.616250156165093
+ 4.616283953128529
+ 4.616317749749637
+ 4.616351546028427
+ 4.6163853419649055
+ 4.6164191375590855
+ 4.616452932810974
+ 4.616486727720582
+ 4.616520522287918
+ 4.616554316512992
+ 4.616588110395813
+ 4.616621903936389
+ 4.616655697134732
+ 4.616689489990851
+ 4.616723282504753
+ 4.616757074676451
+ 4.6167908665059505
+ 4.616824657993264
+ 4.6168584491384
+ 4.616892239941366
+ 4.616926030402175
+ 4.616959820520834
+ 4.616993610297352
+ 4.61702739973174
+ 4.617061188824008
+ 4.617094977574163
+ 4.617128765982215
+ 4.617162554048174
+ 4.6171963417720505
+ 4.617230129153851
+ 4.617263916193587
+ 4.6172977028912685
+ 4.617331489246904
+ 4.617365275260502
+ 4.6173990609320725
+ 4.617432846261626
+ 4.617466631249171
+ 4.617500415894717
+ 4.617534200198271
+ 4.617567984159847
+ 4.617601767779452
+ 4.617635551057094
+ 4.617669333992786
+ 4.617703116586533
+ 4.617736898838349
+ 4.617770680748239
+ 4.617804462316215
+ 4.617838243542287
+ 4.617872024426463
+ 4.6179058049687525
+ 4.617939585169164
+ 4.617973365027709
+ 4.6180071445443955
+ 4.618040923719232
+ 4.618074702552231
+ 4.618108481043399
+ 4.618142259192747
+ 4.618176037000283
+ 4.6182098144660175
+ 4.618243591589959
+ 4.618277368372118
+ 4.618311144812504
+ 4.618344920911125
+ 4.618378696667991
+ 4.618412472083111
+ 4.618446247156494
+ 4.6184800218881525
+ 4.618513796278092
+ 4.618547570326325
+ 4.618581344032858
+ 4.618615117397703
+ 4.618648890420867
+ 4.618682663102361
+ 4.6187164354421935
+ 4.6187502074403755
+ 4.618783979096914
+ 4.618817750411821
+ 4.6188515213851025
+ 4.6188852920167704
+ 4.618919062306834
+ 4.618952832255302
+ 4.618986601862185
+ 4.6190203711274895
+ 4.619054140051228
+ 4.619087908633408
+ 4.619121676874039
+ 4.619155444773132
+ 4.619189212330695
+ 4.619222979546737
+ 4.619256746421268
+ 4.619290512954297
+ 4.619324279145835
+ 4.619358044995889
+ 4.619391810504471
+ 4.619425575671587
+ 4.619459340497249
+ 4.619493104981466
+ 4.619526869124246
+ 4.619560632925601
+ 4.619594396385537
+ 4.619628159504066
+ 4.619661922281196
+ 4.619695684716936
+ 4.619729446811297
+ 4.6197632085642875
+ 4.619796969975917
+ 4.6198307310461955
+ 4.619864491775131
+ 4.619898252162733
+ 4.619932012209012
+ 4.619965771913977
+ 4.619999531277636
+ 4.6200332903
+ 4.620067048981079
+ 4.620100807320879
+ 4.620134565319414
+ 4.62016832297669
+ 4.620202080292717
+ 4.620235837267505
+ 4.620269593901062
+ 4.6203033501934
+ 4.620337106144526
+ 4.620370861754449
+ 4.6204046170231825
+ 4.62043837195073
+ 4.620472126537105
+ 4.620505880782315
+ 4.62053963468637
+ 4.620573388249279
+ 4.620607141471052
+ 4.620640894351698
+ 4.620674646891228
+ 4.620708399089648
+ 4.6207421509469695
+ 4.6207759024632
+ 4.620809653638353
+ 4.620843404472432
+ 4.620877154965451
+ 4.620910905117418
+ 4.620944654928342
+ 4.620978404398233
+ 4.6210121535271
+ 4.621045902314951
+ 4.621079650761798
+ 4.621113398867648
+ 4.621147146632511
+ 4.6211808940563985
+ 4.621214641139317
+ 4.621248387881276
+ 4.6212821342822865
+ 4.621315880342357
+ 4.621349626061497
+ 4.621383371439716
+ 4.621417116477023
+ 4.621450861173428
+ 4.621484605528939
+ 4.621518349543566
+ 4.621552093217318
+ 4.6215858365502065
+ 4.621619579542238
+ 4.621653322193424
+ 4.621687064503772
+ 4.621720806473292
+ 4.621754548101994
+ 4.621788289389888
+ 4.621822030336981
+ 4.6218557709432835
+ 4.621889511208805
+ 4.6219232511335555
+ 4.6219569907175435
+ 4.621990729960778
+ 4.622024468863269
+ 4.622058207425026
+ 4.622091945646058
+ 4.622125683526373
+ 4.622159421065984
+ 4.6221931582648965
+ 4.622226895123121
+ 4.622260631640668
+ 4.622294367817545
+ 4.622328103653763
+ 4.622361839149331
+ 4.622395574304258
+ 4.622429309118554
+ 4.6224630435922265
+ 4.622496777725287
+ 4.622530511517743
+ 4.622564244969605
+ 4.622597978080883
+ 4.622631710851584
+ 4.622665443281719
+ 4.622699175371297
+ 4.622732907120328
+ 4.62276663852882
+ 4.622800369596783
+ 4.622834100324227
+ 4.6228678307111615
+ 4.622901560757594
+ 4.622935290463535
+ 4.622969019828994
+ 4.623002748853979
+ 4.6230364775385
+ 4.623070205882568
+ 4.623103933886192
+ 4.623137661549378
+ 4.623171388872139
+ 4.623205115854483
+ 4.623238842496418
+ 4.6232725687979555
+ 4.623306294759105
+ 4.623340020379873
+ 4.623373745660272
+ 4.623407470600308
+ 4.6234411951999945
+ 4.623474919459337
+ 4.623508643378347
+ 4.623542366957033
+ 4.623576090195406
+ 4.623609813093473
+ 4.623643535651244
+ 4.623677257868728
+ 4.623710979745935
+ 4.623744701282875
+ 4.623778422479556
+ 4.623812143335987
+ 4.623845863852178
+ 4.623879584028139
+ 4.62391330386388
+ 4.623947023359407
+ 4.623980742514733
+ 4.624014461329865
+ 4.624048179804813
+ 4.624081897939586
+ 4.624115615734193
+ 4.624149333188646
+ 4.6241830503029515
+ 4.624216767077119
+ 4.624250483511158
+ 4.624284199605079
+ 4.6243179153588905
+ 4.624351630772602
+ 4.624385345846222
+ 4.624419060579761
+ 4.6244527749732285
+ 4.624486489026632
+ 4.624520202739982
+ 4.624553916113287
+ 4.624587629146558
+ 4.624621341839803
+ 4.624655054193031
+ 4.624688766206252
+ 4.624722477879477
+ 4.624756189212712
+ 4.624789900205968
+ 4.624823610859254
+ 4.62485732117258
+ 4.624891031145955
+ 4.624924740779387
+ 4.624958450072888
+ 4.624992159026465
+ 4.625025867640127
+ 4.625059575913885
+ 4.625093283847747
+ 4.625126991441724
+ 4.625160698695824
+ 4.625194405610056
+ 4.62522811218443
+ 4.625261818418954
+ 4.625295524313641
+ 4.625329229868495
+ 4.62536293508353
+ 4.625396639958752
+ 4.6254303444941725
+ 4.625464048689799
+ 4.625497752545642
+ 4.625531456061711
+ 4.625565159238014
+ 4.625598862074561
+ 4.625632564571362
+ 4.625666266728427
+ 4.625699968545761
+ 4.6257336700233775
+ 4.6257673711612854
+ 4.6258010719594935
+ 4.62583477241801
+ 4.625868472536844
+ 4.625902172316006
+ 4.625935871755506
+ 4.625969570855352
+ 4.626003269615553
+ 4.626036968036119
+ 4.6260706661170605
+ 4.626104363858385
+ 4.626138061260101
+ 4.62617175832222
+ 4.62620545504475
+ 4.6262391514277015
+ 4.626272847471082
+ 4.626306543174903
+ 4.626340238539171
+ 4.626373933563897
+ 4.6264076282490905
+ 4.6264413225947605
+ 4.626475016600916
+ 4.626508710267566
+ 4.626542403594721
+ 4.626576096582389
+ 4.62660978923058
+ 4.626643481539303
+ 4.626677173508568
+ 4.626710865138382
+ 4.626744556428758
+ 4.626778247379702
+ 4.626811937991225
+ 4.626845628263335
+ 4.626879318196043
+ 4.626913007789356
+ 4.6269466970432855
+ 4.6269803859578404
+ 4.627014074533029
+ 4.627047762768861
+ 4.6270814506653455
+ 4.627115138222492
+ 4.62714882544031
+ 4.627182512318808
+ 4.6272161988579965
+ 4.627249885057885
+ 4.62728357091848
+ 4.6273172564397935
+ 4.627350941621835
+ 4.627384626464611
+ 4.6274183109681335
+ 4.627451995132411
+ 4.627485678957451
+ 4.627519362443266
+ 4.627553045589862
+ 4.627586728397252
+ 4.6276204108654415
+ 4.627654092994442
+ 4.6276877747842615
+ 4.6277214562349105
+ 4.627755137346398
+ 4.6277888181187326
+ 4.627822498551924
+ 4.627856178645981
+ 4.627889858400914
+ 4.627923537816732
+ 4.627957216893442
+ 4.627990895631057
+ 4.628024574029583
+ 4.628058252089032
+ 4.62809192980941
+ 4.6281256071907295
+ 4.628159284232999
+ 4.628192960936225
+ 4.628226637300421
+ 4.628260313325594
+ 4.628293989011752
+ 4.628327664358907
+ 4.628361339367067
+ 4.628395014036241
+ 4.628428688366439
+ 4.628462362357668
+ 4.628496036009942
+ 4.628529709323265
+ 4.628563382297649
+ 4.628597054933104
+ 4.628630727229637
+ 4.628664399187259
+ 4.628698070805977
+ 4.628731742085804
+ 4.628765413026746
+ 4.628799083628813
+ 4.6288327538920155
+ 4.628866423816362
+ 4.628900093401861
+ 4.628933762648522
+ 4.628967431556355
+ 4.62900110012537
+ 4.629034768355575
+ 4.629068436246978
+ 4.629102103799591
+ 4.629135771013421
+ 4.629169437888479
+ 4.629203104424773
+ 4.629236770622313
+ 4.629270436481108
+ 4.629304102001167
+ 4.629337767182499
+ 4.629371432025115
+ 4.629405096529021
+ 4.62943876069423
+ 4.629472424520748
+ 4.629506088008587
+ 4.629539751157755
+ 4.629573413968259
+ 4.629607076440113
+ 4.629640738573323
+ 4.6296744003678985
+ 4.629708061823849
+ 4.629741722941184
+ 4.629775383719913
+ 4.629809044160045
+ 4.629842704261589
+ 4.629876364024555
+ 4.629910023448951
+ 4.629943682534786
+ 4.629977341282071
+ 4.630010999690815
+ 4.630044657761026
+ 4.630078315492714
+ 4.630111972885888
+ 4.630145629940557
+ 4.630179286656731
+ 4.630212943034419
+ 4.63024659907363
+ 4.630280254774373
+ 4.630313910136659
+ 4.630347565160493
+ 4.630381219845889
+ 4.630414874192854
+ 4.630448528201397
+ 4.630482181871527
+ 4.630515835203257
+ 4.63054948819659
+ 4.63058314085154
+ 4.630616793168113
+ 4.630650445146322
+ 4.630684096786173
+ 4.630717748087677
+ 4.630751399050842
+ 4.630785049675679
+ 4.6308186999621945
+ 4.6308523499104
+ 4.630885999520304
+ 4.630919648791917
+ 4.630953297725245
+ 4.6309869463203
+ 4.631020594577091
+ 4.631054242495626
+ 4.631087890075915
+ 4.631121537317968
+ 4.631155184221793
+ 4.631188830787399
+ 4.631222477014796
+ 4.631256122903993
+ 4.631289768455
+ 4.631323413667825
+ 4.631357058542478
+ 4.631390703078967
+ 4.631424347277303
+ 4.631457991137495
+ 4.63149163465955
+ 4.631525277843481
+ 4.631558920689294
+ 4.631592563196999
+ 4.631626205366605
+ 4.631659847198123
+ 4.631693488691561
+ 4.631727129846928
+ 4.631760770664233
+ 4.631794411143486
+ 4.631828051284695
+ 4.631861691087871
+ 4.631895330553022
+ 4.631928969680159
+ 4.631962608469288
+ 4.63199624692042
+ 4.632029885033565
+ 4.632063522808731
+ 4.6320971602459275
+ 4.632130797345163
+ 4.63216443410645
+ 4.632198070529793
+ 4.632231706615205
+ 4.632265342362691
+ 4.632298977772265
+ 4.6323326128439355
+ 4.632366247577709
+ 4.632399881973595
+ 4.632433516031606
+ 4.632467149751746
+ 4.632500783134029
+ 4.632534416178462
+ 4.632568048885055
+ 4.632601681253816
+ 4.632635313284756
+ 4.632668944977883
+ 4.632702576333206
+ 4.632736207350736
+ 4.632769838030479
+ 4.632803468372447
+ 4.632837098376649
+ 4.632870728043093
+ 4.632904357371787
+ 4.6329379863627445
+ 4.632971615015971
+ 4.633005243331477
+ 4.633038871309271
+ 4.633072498949363
+ 4.633106126251762
+ 4.633139753216477
+ 4.633173379843518
+ 4.633207006132893
+ 4.633240632084612
+ 4.633274257698683
+ 4.633307882975116
+ 4.633341507913922
+ 4.633375132515107
+ 4.633408756778684
+ 4.6334423807046585
+ 4.633476004293041
+ 4.633509627543841
+ 4.633543250457068
+ 4.63357687303273
+ 4.633610495270838
+ 4.633644117171399
+ 4.6336777387344235
+ 4.633711359959921
+ 4.6337449808479
+ 4.6337786013983715
+ 4.6338122216113415
+ 4.633845841486821
+ 4.633879461024819
+ 4.633913080225344
+ 4.6339466990884075
+ 4.633980317614016
+ 4.634013935802181
+ 4.63404755365291
+ 4.634081171166212
+ 4.634114788342098
+ 4.634148405180575
+ 4.634182021681653
+ 4.634215637845343
+ 4.634249253671652
+ 4.6342828691605895
+ 4.634316484312165
+ 4.634350099126389
+ 4.634383713603268
+ 4.6344173277428125
+ 4.634450941545032
+ 4.634484555009937
+ 4.634518168137533
+ 4.634551780927834
+ 4.634585393380843
+ 4.6346190054965755
+ 4.634652617275037
+ 4.634686228716237
+ 4.634719839820186
+ 4.634753450586893
+ 4.634787061016366
+ 4.634820671108615
+ 4.6348542808636495
+ 4.634887890281477
+ 4.634921499362108
+ 4.634955108105552
+ 4.634988716511819
+ 4.635022324580916
+ 4.635055932312852
+ 4.635089539707638
+ 4.635123146765284
+ 4.635156753485796
+ 4.635190359869185
+ 4.6352239659154595
+ 4.6352575716246305
+ 4.635291176996705
+ 4.635324782031693
+ 4.635358386729604
+ 4.635391991090448
+ 4.635425595114231
+ 4.635459198800966
+ 4.63549280215066
+ 4.635526405163322
+ 4.635560007838962
+ 4.635593610177589
+ 4.635627212179212
+ 4.635660813843841
+ 4.635694415171484
+ 4.635728016162151
+ 4.63576161681585
+ 4.635795217132592
+ 4.635828817112384
+ 4.635862416755238
+ 4.63589601606116
+ 4.635929615030162
+ 4.63596321366225
+ 4.635996811957437
+ 4.63603040991573
+ 4.636064007537137
+ 4.6360976048216695
+ 4.636131201769335
+ 4.636164798380144
+ 4.636198394654105
+ 4.636231990591227
+ 4.636265586191519
+ 4.636299181454991
+ 4.636332776381652
+ 4.63636637097151
+ 4.636399965224576
+ 4.636433559140857
+ 4.636467152720365
+ 4.636500745963106
+ 4.636534338869092
+ 4.63656793143833
+ 4.636601523670829
+ 4.636635115566601
+ 4.6366687071256525
+ 4.636702298347994
+ 4.636735889233633
+ 4.636769479782582
+ 4.636803069994847
+ 4.636836659870437
+ 4.6368702494093625
+ 4.636903838611634
+ 4.636937427477257
+ 4.636971016006244
+ 4.637004604198603
+ 4.637038192054343
+ 4.637071779573473
+ 4.637105366756002
+ 4.63713895360194
+ 4.637172540111296
+ 4.637206126284079
+ 4.637239712120298
+ 4.637273297619961
+ 4.637306882783079
+ 4.637340467609661
+ 4.637374052099715
+ 4.637407636253252
+ 4.637441220070278
+ 4.6374748035508055
+ 4.637508386694841
+ 4.637541969502397
+ 4.6375755519734785
+ 4.637609134108098
+ 4.637642715906262
+ 4.637676297367983
+ 4.637709878493266
+ 4.637743459282124
+ 4.637777039734563
+ 4.637810619850595
+ 4.637844199630226
+ 4.637877779073468
+ 4.637911358180328
+ 4.637944936950817
+ 4.637978515384945
+ 4.638012093482717
+ 4.638045671244146
+ 4.638079248669239
+ 4.638112825758006
+ 4.638146402510456
+ 4.6381799789265985
+ 4.638213555006442
+ 4.638247130749996
+ 4.6382807061572695
+ 4.638314281228273
+ 4.638347855963012
+ 4.6383814303615
+ 4.638415004423743
+ 4.638448578149752
+ 4.638482151539535
+ 4.638515724593103
+ 4.638549297310463
+ 4.638582869691624
+ 4.6386164417365965
+ 4.638650013445388
+ 4.638683584818011
+ 4.638717155854471
+ 4.638750726554779
+ 4.638784296918944
+ 4.638817866946974
+ 4.6388514366388796
+ 4.63888500599467
+ 4.638918575014352
+ 4.638952143697937
+ 4.638985712045434
+ 4.639019280056851
+ 4.639052847732198
+ 4.639086415071485
+ 4.639119982074718
+ 4.639153548741909
+ 4.639187115073066
+ 4.639220681068199
+ 4.639254246727317
+ 4.639287812050428
+ 4.639321377037542
+ 4.639354941688668
+ 4.639388506003815
+ 4.6394220699829924
+ 4.639455633626208
+ 4.639489196933473
+ 4.639522759904796
+ 4.639556322540185
+ 4.63958988483965
+ 4.6396234468032
+ 4.639657008430844
+ 4.639690569722592
+ 4.639724130678451
+ 4.639757691298432
+ 4.639791251582544
+ 4.639824811530795
+ 4.6398583711431955
+ 4.639891930419753
+ 4.639925489360479
+ 4.639959047965381
+ 4.639992606234467
+ 4.6400261641677485
+ 4.640059721765232
+ 4.640093279026931
+ 4.64012683595285
+ 4.640160392543
+ 4.64019394879739
+ 4.640227504716029
+ 4.640261060298927
+ 4.640294615546093
+ 4.640328170457534
+ 4.640361725033261
+ 4.6403952792732825
+ 4.64042883317761
+ 4.640462386746247
+ 4.640495939979209
+ 4.640529492876501
+ 4.640563045438133
+ 4.640596597664115
+ 4.640630149554456
+ 4.640663701109164
+ 4.640697252328248
+ 4.640730803211719
+ 4.640764353759584
+ 4.640797903971855
+ 4.640831453848538
+ 4.640865003389643
+ 4.640898552595179
+ 4.640932101465157
+ 4.6409656499995835
+ 4.64099919819847
+ 4.641032746061824
+ 4.641066293589654
+ 4.641099840781971
+ 4.641133387638783
+ 4.6411669341601
+ 4.641200480345929
+ 4.641234026196282
+ 4.6412675717111656
+ 4.641301116890591
+ 4.6413346617345645
+ 4.641368206243098
+ 4.6414017504161995
+ 4.641435294253879
+ 4.641468837756142
+ 4.641502380923003
+ 4.641535923754469
+ 4.641569466250546
+ 4.641603008411248
+ 4.641636550236581
+ 4.641670091726554
+ 4.641703632881177
+ 4.64173717370046
+ 4.641770714184412
+ 4.64180425433304
+ 4.641837794146354
+ 4.641871333624365
+ 4.641904872767078
+ 4.641938411574507
+ 4.641971950046658
+ 4.642005488183541
+ 4.642039025985165
+ 4.6420725634515385
+ 4.642106100582671
+ 4.642139637378573
+ 4.642173173839252
+ 4.642206709964717
+ 4.642240245754977
+ 4.642273781210043
+ 4.642307316329921
+ 4.642340851114624
+ 4.642374385564159
+ 4.642407919678533
+ 4.6424414534577565
+ 4.642474986901841
+ 4.642508520010794
+ 4.642542052784623
+ 4.642575585223339
+ 4.642609117326951
+ 4.6426426490954675
+ 4.642676180528897
+ 4.64270971162725
+ 4.642743242390535
+ 4.642776772818761
+ 4.642810302911936
+ 4.642843832670071
+ 4.6428773620931745
+ 4.6429108911812556
+ 4.642944419934322
+ 4.642977948352384
+ 4.643011476435452
+ 4.6430450041835325
+ 4.643078531596636
+ 4.643112058674771
+ 4.643145585417948
+ 4.643179111826175
+ 4.64321263789946
+ 4.643246163637814
+ 4.643279689041245
+ 4.643313214109761
+ 4.643346738843374
+ 4.643380263242092
+ 4.643413787305922
+ 4.643447311034875
+ 4.643480834428961
+ 4.643514357488186
+ 4.643547880212563
+ 4.643581402602098
+ 4.6436149246568
+ 4.643648446376681
+ 4.643681967761747
+ 4.643715488812009
+ 4.6437490095274745
+ 4.643782529908154
+ 4.643816049954056
+ 4.64384956966519
+ 4.643883089041563
+ 4.643916608083188
+ 4.643950126790071
+ 4.643983645162221
+ 4.644017163199648
+ 4.644050680902362
+ 4.644084198270371
+ 4.6441177153036834
+ 4.64415123200231
+ 4.644184748366259
+ 4.644218264395539
+ 4.644251780090159
+ 4.644285295450129
+ 4.644318810475457
+ 4.644352325166154
+ 4.644385839522227
+ 4.644419353543685
+ 4.644452867230539
+ 4.644486380582797
+ 4.644519893600466
+ 4.64455340628356
+ 4.644586918632083
+ 4.6446204306460475
+ 4.64465394232546
+ 4.644687453670332
+ 4.644720964680671
+ 4.6447544753564864
+ 4.644787985697787
+ 4.644821495704583
+ 4.644855005376883
+ 4.644888514714695
+ 4.644922023718028
+ 4.644955532386893
+ 4.644989040721297
+ 4.645022548721251
+ 4.645056056386762
+ 4.645089563717841
+ 4.6451230707144955
+ 4.645156577376735
+ 4.64519008370457
+ 4.645223589698008
+ 4.645257095357057
+ 4.6452906006817285
+ 4.645324105672031
+ 4.645357610327972
+ 4.645391114649562
+ 4.64542461863681
+ 4.645458122289725
+ 4.645491625608315
+ 4.645525128592591
+ 4.64555863124256
+ 4.645592133558232
+ 4.6456256355396155
+ 4.64565913718672
+ 4.645692638499555
+ 4.64572613947813
+ 4.645759640122452
+ 4.645793140432532
+ 4.645826640408378
+ 4.64586014005
+ 4.645893639357405
+ 4.645927138330604
+ 4.6459606369696065
+ 4.64599413527442
+ 4.646027633245054
+ 4.646061130881518
+ 4.64609462818382
+ 4.646128125151971
+ 4.646161621785978
+ 4.646195118085851
+ 4.646228614051598
+ 4.64626210968323
+ 4.646295604980755
+ 4.6463290999441815
+ 4.646362594573518
+ 4.6463960888687765
+ 4.646429582829964
+ 4.646463076457089
+ 4.646496569750162
+ 4.646530062709191
+ 4.646563555334184
+ 4.6465970476251535
+ 4.646630539582105
+ 4.6466640312050504
+ 4.646697522493996
+ 4.646731013448952
+ 4.646764504069928
+ 4.646797994356934
+ 4.646831484309976
+ 4.646864973929065
+ 4.64689846321421
+ 4.64693195216542
+ 4.6469654407827035
+ 4.64699892906607
+ 4.647032417015528
+ 4.647065904631088
+ 4.647099391912757
+ 4.647132878860545
+ 4.647166365474462
+ 4.6471998517545146
+ 4.6472333377007145
+ 4.647266823313069
+ 4.647300308591588
+ 4.64733379353628
+ 4.647367278147155
+ 4.64740076242422
+ 4.647434246367486
+ 4.647467729976962
+ 4.647501213252655
+ 4.647534696194576
+ 4.647568178802733
+ 4.647601661077137
+ 4.647635143017794
+ 4.647668624624715
+ 4.647702105897909
+ 4.647735586837385
+ 4.64776906744315
+ 4.647802547715215
+ 4.6478360276535895
+ 4.647869507258282
+ 4.647902986529299
+ 4.647936465466654
+ 4.647969944070352
+ 4.648003422340405
+ 4.648036900276822
+ 4.648070377879608
+ 4.648103855148777
+ 4.648137332084336
+ 4.648170808686293
+ 4.648204284954658
+ 4.64823776088944
+ 4.648271236490649
+ 4.648304711758292
+ 4.648338186692379
+ 4.64837166129292
+ 4.648405135559921
+ 4.648438609493395
+ 4.648472083093348
+ 4.648505556359792
+ 4.648539029292732
+ 4.64857250189218
+ 4.648605974158144
+ 4.648639446090634
+ 4.648672917689658
+ 4.648706388955225
+ 4.648739859887344
+ 4.648773330486025
+ 4.6488068007512755
+ 4.648840270683105
+ 4.648873740281523
+ 4.648907209546539
+ 4.648940678478161
+ 4.648974147076399
+ 4.649007615341262
+ 4.649041083272756
+ 4.6490745508708935
+ 4.649108018135682
+ 4.649141485067132
+ 4.649174951665252
+ 4.649208417930049
+ 4.649241883861534
+ 4.649275349459716
+ 4.649308814724603
+ 4.649342279656204
+ 4.649375744254528
+ 4.649409208519586
+ 4.649442672451385
+ 4.649476136049934
+ 4.649509599315244
+ 4.649543062247321
+ 4.649576524846176
+ 4.649609987111818
+ 4.649643449044254
+ 4.649676910643497
+ 4.649710371909552
+ 4.6497438328424305
+ 4.649777293442139
+ 4.649810753708691
+ 4.649844213642089
+ 4.649877673242348
+ 4.649911132509474
+ 4.649944591443477
+ 4.649978050044364
+ 4.650011508312148
+ 4.650044966246834
+ 4.650078423848433
+ 4.6501118811169535
+ 4.650145338052405
+ 4.650178794654796
+ 4.650212250924135
+ 4.6502457068604315
+ 4.650279162463695
+ 4.650312617733935
+ 4.65034607267116
+ 4.650379527275375
+ 4.650412981546597
+ 4.650446435484828
+ 4.65047988909008
+ 4.650513342362363
+ 4.650546795301683
+ 4.650580247908051
+ 4.650613700181475
+ 4.650647152121965
+ 4.65068060372953
+ 4.650714055004178
+ 4.650747505945918
+ 4.650780956554761
+ 4.650814406830714
+ 4.650847856773787
+ 4.650881306383987
+ 4.650914755661325
+ 4.650948204605811
+ 4.650981653217451
+ 4.651015101496255
+ 4.651048549442234
+ 4.651081997055394
+ 4.651115444335746
+ 4.6511488912833
+ 4.651182337898061
+ 4.651215784180042
+ 4.65124923012925
+ 4.651282675745693
+ 4.651316121029383
+ 4.651349565980327
+ 4.651383010598534
+ 4.651416454884014
+ 4.651449898836774
+ 4.651483342456826
+ 4.6515167857441755
+ 4.651550228698835
+ 4.651583671320812
+ 4.651617113610113
+ 4.651650555566751
+ 4.651683997190732
+ 4.651717438482066
+ 4.651750879440764
+ 4.651784320066832
+ 4.65181776036028
+ 4.651851200321117
+ 4.651884639949352
+ 4.651918079244995
+ 4.651951518208053
+ 4.651984956838535
+ 4.652018395136452
+ 4.6520518331018135
+ 4.652085270734625
+ 4.652118708034899
+ 4.652152145002642
+ 4.652185581637863
+ 4.652219017940573
+ 4.652252453910779
+ 4.652285889548492
+ 4.652319324853719
+ 4.65235275982647
+ 4.652386194466753
+ 4.652419628774579
+ 4.652453062749954
+ 4.652486496392889
+ 4.652519929703393
+ 4.652553362681475
+ 4.652586795327144
+ 4.652620227640408
+ 4.652653659621276
+ 4.652687091269757
+ 4.652720522585861
+ 4.652753953569597
+ 4.652787384220973
+ 4.652820814539998
+ 4.652854244526681
+ 4.6528876741810326
+ 4.652921103503059
+ 4.652954532492772
+ 4.6529879611501785
+ 4.653021389475287
+ 4.653054817468109
+ 4.653088245128651
+ 4.653121672456924
+ 4.653155099452936
+ 4.653188526116696
+ 4.653221952448212
+ 4.653255378447495
+ 4.653288804114553
+ 4.653322229449393
+ 4.653355654452028
+ 4.653389079122463
+ 4.6534225034607095
+ 4.6534559274667755
+ 4.65348935114067
+ 4.653522774482402
+ 4.65355619749198
+ 4.653589620169415
+ 4.653623042514713
+ 4.653656464527886
+ 4.653689886208941
+ 4.653723307557886
+ 4.653756728574732
+ 4.653790149259487
+ 4.653823569612161
+ 4.653856989632762
+ 4.653890409321298
+ 4.65392382867778
+ 4.653957247702217
+ 4.653990666394615
+ 4.654024084754986
+ 4.6540575027833375
+ 4.65409092047968
+ 4.65412433784402
+ 4.654157754876368
+ 4.654191171576732
+ 4.654224587945123
+ 4.654258003981548
+ 4.654291419686016
+ 4.654324835058539
+ 4.65435825009912
+ 4.654391664807773
+ 4.654425079184506
+ 4.654458493229327
+ 4.654491906942244
+ 4.654525320323268
+ 4.654558733372408
+ 4.65459214608967
+ 4.654625558475067
+ 4.6546589705286046
+ 4.654692382250294
+ 4.654725793640143
+ 4.654759204698162
+ 4.654792615424357
+ 4.65482602581874
+ 4.654859435881318
+ 4.654892845612101
+ 4.654926255011097
+ 4.654959664078316
+ 4.654993072813766
+ 4.655026481217456
+ 4.655059889289396
+ 4.655093297029595
+ 4.65512670443806
+ 4.655160111514801
+ 4.655193518259828
+ 4.655226924673149
+ 4.655260330754772
+ 4.655293736504707
+ 4.655327141922964
+ 4.65536054700955
+ 4.6553939517644745
+ 4.655427356187747
+ 4.655460760279376
+ 4.655494164039371
+ 4.65552756746774
+ 4.655560970564492
+ 4.655594373329637
+ 4.655627775763183
+ 4.65566117786514
+ 4.655694579635515
+ 4.655727981074318
+ 4.655761382181558
+ 4.655794782957245
+ 4.655828183401386
+ 4.655861583513992
+ 4.655894983295069
+ 4.655928382744629
+ 4.655961781862678
+ 4.655995180649229
+ 4.656028579104287
+ 4.6560619772278615
+ 4.656095375019964
+ 4.656128772480602
+ 4.656162169609782
+ 4.656195566407517
+ 4.656228962873814
+ 4.656262359008681
+ 4.656295754812128
+ 4.656329150284164
+ 4.656362545424798
+ 4.656395940234039
+ 4.656429334711895
+ 4.656462728858376
+ 4.65649612267349
+ 4.656529516157246
+ 4.656562909309653
+ 4.656596302130722
+ 4.6566296946204595
+ 4.656663086778875
+ 4.656696478605977
+ 4.656729870101775
+ 4.656763261266279
+ 4.656796652099495
+ 4.656830042601435
+ 4.656863432772106
+ 4.656896822611517
+ 4.656930212119678
+ 4.656963601296597
+ 4.656996990142284
+ 4.6570303786567475
+ 4.657063766839995
+ 4.657097154692037
+ 4.657130542212882
+ 4.6571639294025395
+ 4.6571973162610165
+ 4.657230702788325
+ 4.657264088984471
+ 4.6572974748494635
+ 4.657330860383314
+ 4.657364245586029
+ 4.657397630457618
+ 4.6574310149980915
+ 4.6574643992074565
+ 4.657497783085723
+ 4.657531166632898
+ 4.657564549848994
+ 4.657597932734015
+ 4.657631315287976
+ 4.65766469751088
+ 4.657698079402739
+ 4.657731460963562
+ 4.657764842193357
+ 4.657798223092133
+ 4.6578316036599
+ 4.657864983896664
+ 4.657898363802437
+ 4.657931743377229
+ 4.657965122621044
+ 4.6579985015338945
+ 4.658031880115789
+ 4.658065258366737
+ 4.658098636286744
+ 4.658132013875822
+ 4.658165391133981
+ 4.658198768061226
+ 4.658232144657569
+ 4.658265520923018
+ 4.658298896857581
+ 4.658332272461268
+ 4.6583656477340885
+ 4.65839902267605
+ 4.658432397287163
+ 4.658465771567433
+ 4.658499145516873
+ 4.658532519135489
+ 4.658565892423291
+ 4.65859926538029
+ 4.658632638006491
+ 4.658666010301905
+ 4.658699382266541
+ 4.6587327539004075
+ 4.658766125203514
+ 4.658799496175868
+ 4.6588328668174785
+ 4.658866237128356
+ 4.658899607108509
+ 4.658932976757946
+ 4.658966346076674
+ 4.658999715064706
+ 4.659033083722048
+ 4.659066452048709
+ 4.659099820044699
+ 4.659133187710025
+ 4.659166555044699
+ 4.659199922048726
+ 4.6592332887221195
+ 4.659266655064885
+ 4.659300021077031
+ 4.6593333867585685
+ 4.659366752109506
+ 4.659400117129851
+ 4.659433481819614
+ 4.659466846178803
+ 4.659500210207426
+ 4.659533573905495
+ 4.659566937273016
+ 4.659600300309999
+ 4.659633663016452
+ 4.659667025392386
+ 4.659700387437807
+ 4.659733749152726
+ 4.6597671105371505
+ 4.659800471591091
+ 4.659833832314555
+ 4.6598671927075515
+ 4.6599005527700905
+ 4.659933912502179
+ 4.659967271903828
+ 4.660000630975046
+ 4.66003398971584
+ 4.660067348126221
+ 4.660100706206197
+ 4.660134063955777
+ 4.66016742137497
+ 4.660200778463784
+ 4.660234135222229
+ 4.6602674916503135
+ 4.660300847748046
+ 4.660334203515436
+ 4.660367558952491
+ 4.660400914059223
+ 4.660434268835639
+ 4.660467623281746
+ 4.660500977397556
+ 4.660534331183076
+ 4.660567684638314
+ 4.660601037763282
+ 4.660634390557986
+ 4.6606677430224375
+ 4.660701095156643
+ 4.660734446960612
+ 4.660767798434353
+ 4.660801149577877
+ 4.660834500391191
+ 4.660867850874305
+ 4.660901201027225
+ 4.660934550849964
+ 4.660967900342528
+ 4.661001249504927
+ 4.661034598337169
+ 4.661067946839264
+ 4.661101295011221
+ 4.661134642853048
+ 4.661167990364754
+ 4.6612013375463475
+ 4.661234684397837
+ 4.661268030919233
+ 4.6613013771105445
+ 4.6613347229717785
+ 4.661368068502945
+ 4.661401413704053
+ 4.661434758575111
+ 4.661468103116128
+ 4.661501447327113
+ 4.661534791208073
+ 4.661568134759021
+ 4.6616014779799615
+ 4.661634820870906
+ 4.661668163431862
+ 4.66170150566284
+ 4.661734847563848
+ 4.661768189134894
+ 4.661801530375987
+ 4.661834871287138
+ 4.661868211868353
+ 4.661901552119642
+ 4.661934892041016
+ 4.66196823163248
+ 4.662001570894045
+ 4.66203490982572
+ 4.662068248427513
+ 4.662101586699434
+ 4.6621349246414905
+ 4.662168262253693
+ 4.662201599536049
+ 4.662234936488567
+ 4.662268273111257
+ 4.662301609404127
+ 4.662334945367187
+ 4.662368281000446
+ 4.66240161630391
+ 4.662434951277592
+ 4.662468285921498
+ 4.662501620235637
+ 4.6625349542200185
+ 4.6625682878746515
+ 4.662601621199545
+ 4.662634954194708
+ 4.662668286860148
+ 4.662701619195875
+ 4.662734951201897
+ 4.662768282878225
+ 4.662801614224865
+ 4.662834945241827
+ 4.662868275929121
+ 4.662901606286755
+ 4.662934936314736
+ 4.662968266013077
+ 4.663001595381782
+ 4.663034924420863
+ 4.663068253130329
+ 4.663101581510187
+ 4.663134909560446
+ 4.663168237281116
+ 4.663201564672208
+ 4.663234891733726
+ 4.663268218465681
+ 4.663301544868082
+ 4.663334870940939
+ 4.663368196684259
+ 4.663401522098051
+ 4.663434847182325
+ 4.663468171937089
+ 4.663501496362353
+ 4.663534820458125
+ 4.663568144224413
+ 4.663601467661226
+ 4.663634790768574
+ 4.663668113546465
+ 4.663701435994909
+ 4.663734758113914
+ 4.6637680799034875
+ 4.6638014013636395
+ 4.663834722494381
+ 4.663868043295718
+ 4.66390136376766
+ 4.663934683910216
+ 4.663968003723394
+ 4.664001323207204
+ 4.664034642361655
+ 4.664067961186755
+ 4.664101279682515
+ 4.66413459784894
+ 4.664167915686042
+ 4.664201233193827
+ 4.664234550372307
+ 4.664267867221489
+ 4.664301183741381
+ 4.664334499931996
+ 4.664367815793337
+ 4.664401131325416
+ 4.664434446528243
+ 4.664467761401824
+ 4.664501075946171
+ 4.664534390161289
+ 4.66456770404719
+ 4.664601017603882
+ 4.6646343308313725
+ 4.664667643729672
+ 4.6647009562987884
+ 4.664734268538731
+ 4.6647675804495075
+ 4.664800892031129
+ 4.664834203283602
+ 4.664867514206937
+ 4.664900824801141
+ 4.6649341350662255
+ 4.664967445002198
+ 4.665000754609066
+ 4.66503406388684
+ 4.665067372835527
+ 4.665100681455139
+ 4.665133989745683
+ 4.665167297707166
+ 4.6652006053395985
+ 4.665233912642991
+ 4.66526721961735
+ 4.665300526262685
+ 4.665333832579004
+ 4.665367138566318
+ 4.665400444224634
+ 4.665433749553962
+ 4.66546705455431
+ 4.665500359225686
+ 4.665533663568101
+ 4.665566967581561
+ 4.665600271266078
+ 4.665633574621658
+ 4.665666877648311
+ 4.665700180346047
+ 4.665733482714874
+ 4.6657667847547994
+ 4.6658000864658336
+ 4.665833387847984
+ 4.665866688901262
+ 4.665899989625673
+ 4.665933290021229
+ 4.665966590087937
+ 4.665999889825806
+ 4.666033189234846
+ 4.666066488315063
+ 4.66609978706647
+ 4.666133085489071
+ 4.666166383582879
+ 4.6661996813479005
+ 4.666232978784144
+ 4.666266275891621
+ 4.666299572670338
+ 4.666332869120303
+ 4.666366165241528
+ 4.666399461034019
+ 4.6664327564977865
+ 4.666466051632837
+ 4.666499346439183
+ 4.66653264091683
+ 4.666565935065788
+ 4.666599228886065
+ 4.666632522377673
+ 4.666665815540616
+ 4.666699108374906
+ 4.6667324008805515
+ 4.6667656930575605
+ 4.666798984905943
+ 4.666832276425706
+ 4.666865567616859
+ 4.666898858479412
+ 4.666932149013372
+ 4.666965439218749
+ 4.6669987290955515
+ 4.667032018643789
+ 4.667065307863468
+ 4.6670985967546
+ 4.667131885317192
+ 4.667165173551255
+ 4.6671984614567945
+ 4.667231749033822
+ 4.667265036282345
+ 4.667298323202373
+ 4.667331609793913
+ 4.667364896056978
+ 4.667398181991572
+ 4.667431467597706
+ 4.66746475287539
+ 4.66749803782463
+ 4.667531322445438
+ 4.667564606737819
+ 4.667597890701785
+ 4.667631174337344
+ 4.667664457644504
+ 4.667697740623273
+ 4.667731023273663
+ 4.66776430559568
+ 4.667797587589334
+ 4.667830869254632
+ 4.667864150591585
+ 4.667897431600203
+ 4.66793071228049
+ 4.667963992632459
+ 4.667997272656118
+ 4.668030552351474
+ 4.668063831718537
+ 4.668097110757315
+ 4.6681303894678186
+ 4.668163667850056
+ 4.668196945904034
+ 4.668230223629764
+ 4.668263501027254
+ 4.6682967780965114
+ 4.668330054837546
+ 4.668363331250368
+ 4.6683966073349845
+ 4.668429883091404
+ 4.668463158519636
+ 4.668496433619689
+ 4.668529708391572
+ 4.668562982835295
+ 4.668596256950864
+ 4.668629530738291
+ 4.668662804197581
+ 4.668696077328747
+ 4.668729350131794
+ 4.668762622606733
+ 4.668795894753573
+ 4.668829166572321
+ 4.668862438062987
+ 4.66889570922558
+ 4.668928980060108
+ 4.6689622505665795
+ 4.668995520745006
+ 4.669028790595393
+ 4.66906206011775
+ 4.6690953293120865
+ 4.669128598178411
+ 4.669161866716733
+ 4.669195134927061
+ 4.669228402809401
+ 4.669261670363767
+ 4.669294937590164
+ 4.669328204488601
+ 4.669361471059088
+ 4.669394737301634
+ 4.669428003216245
+ 4.669461268802934
+ 4.669494534061706
+ 4.669527798992572
+ 4.66956106359554
+ 4.669594327870619
+ 4.669627591817817
+ 4.669660855437145
+ 4.669694118728609
+ 4.669727381692218
+ 4.669760644327984
+ 4.669793906635913
+ 4.669827168616014
+ 4.669860430268296
+ 4.669893691592767
+ 4.669926952589438
+ 4.669960213258316
+ 4.669993473599409
+ 4.670026733612729
+ 4.670059993298281
+ 4.670093252656075
+ 4.670126511686122
+ 4.6701597703884286
+ 4.670193028763004
+ 4.670226286809855
+ 4.670259544528994
+ 4.670292801920429
+ 4.670326058984166
+ 4.670359315720216
+ 4.670392572128588
+ 4.6704258282092885
+ 4.67045908396233
+ 4.670492339387717
+ 4.670525594485462
+ 4.6705588492555705
+ 4.670592103698055
+ 4.670625357812921
+ 4.670658611600179
+ 4.670691865059837
+ 4.6707251181919025
+ 4.670758370996388
+ 4.670791623473298
+ 4.670824875622644
+ 4.6708581274444345
+ 4.670891378938677
+ 4.6709246301053815
+ 4.670957880944557
+ 4.67099113145621
+ 4.6710243816403505
+ 4.671057631496989
+ 4.671090881026133
+ 4.671124130227789
+ 4.67115737910197
+ 4.671190627648681
+ 4.671223875867934
+ 4.671257123759734
+ 4.671290371324093
+ 4.6713236185610185
+ 4.671356865470519
+ 4.671390112052603
+ 4.6714233583072815
+ 4.67145660423456
+ 4.671489849834449
+ 4.671523095106958
+ 4.671556340052094
+ 4.671589584669867
+ 4.6716228289602855
+ 4.671656072923358
+ 4.6716893165590925
+ 4.671722559867499
+ 4.671755802848587
+ 4.671789045502362
+ 4.671822287828837
+ 4.671855529828017
+ 4.671888771499912
+ 4.671922012844532
+ 4.671955253861884
+ 4.671988494551979
+ 4.672021734914823
+ 4.672054974950426
+ 4.672088214658798
+ 4.672121454039945
+ 4.672154693093878
+ 4.672187931820606
+ 4.672221170220135
+ 4.672254408292476
+ 4.6722876460376375
+ 4.672320883455628
+ 4.672354120546456
+ 4.67238735731013
+ 4.6724205937466605
+ 4.672453829856054
+ 4.67248706563832
+ 4.672520301093468
+ 4.672553536221505
+ 4.672586771022442
+ 4.672620005496287
+ 4.672653239643047
+ 4.672686473462734
+ 4.672719706955354
+ 4.672752940120916
+ 4.672786172959429
+ 4.672819405470904
+ 4.672852637655345
+ 4.672885869512766
+ 4.672919101043171
+ 4.672952332246573
+ 4.672985563122978
+ 4.673018793672395
+ 4.673052023894834
+ 4.673085253790303
+ 4.6731184833588095
+ 4.673151712600363
+ 4.673184941514974
+ 4.6732181701026505
+ 4.6732513983634
+ 4.67328462629723
+ 4.6733178539041536
+ 4.673351081184175
+ 4.673384308137305
+ 4.673417534763554
+ 4.673450761062927
+ 4.6734839870354365
+ 4.673517212681088
+ 4.673550437999893
+ 4.673583662991857
+ 4.6736168876569915
+ 4.673650111995305
+ 4.673683336006804
+ 4.6737165596915
+ 4.6737497830494
+ 4.673783006080514
+ 4.673816228784849
+ 4.673849451162416
+ 4.67388267321322
+ 4.6739158949372746
+ 4.673949116334584
+ 4.67398233740516
+ 4.67401555814901
+ 4.674048778566144
+ 4.674081998656569
+ 4.674115218420295
+ 4.674148437857329
+ 4.674181656967681
+ 4.67421487575136
+ 4.674248094208374
+ 4.674281312338733
+ 4.6743145301424445
+ 4.674347747619517
+ 4.67438096476996
+ 4.674414181593781
+ 4.674447398090992
+ 4.674480614261597
+ 4.6745138301056075
+ 4.674547045623032
+ 4.67458026081388
+ 4.674613475678158
+ 4.6746466902158765
+ 4.674679904427043
+ 4.674713118311668
+ 4.674746331869757
+ 4.674779545101323
+ 4.674812758006372
+ 4.674845970584912
+ 4.674879182836954
+ 4.674912394762505
+ 4.674945606361575
+ 4.674978817634172
+ 4.675012028580305
+ 4.6750452391999815
+ 4.675078449493212
+ 4.675111659460004
+ 4.675144869100367
+ 4.675178078414309
+ 4.675211287401839
+ 4.675244496062966
+ 4.675277704397698
+ 4.675310912406045
+ 4.675344120088014
+ 4.675377327443615
+ 4.675410534472856
+ 4.675443741175746
+ 4.675476947552293
+ 4.675510153602507
+ 4.675543359326396
+ 4.67557656472397
+ 4.675609769795235
+ 4.675642974540202
+ 4.675676178958878
+ 4.675709383051274
+ 4.675742586817396
+ 4.675775790257255
+ 4.675808993370858
+ 4.675842196158215
+ 4.6758753986193335
+ 4.675908600754223
+ 4.6759418025628925
+ 4.67597500404535
+ 4.676008205201604
+ 4.676041406031664
+ 4.676074606535538
+ 4.676107806713235
+ 4.676141006564764
+ 4.676174206090134
+ 4.676207405289352
+ 4.6762406041624285
+ 4.676273802709371
+ 4.676307000930188
+ 4.67634019882489
+ 4.676373396393484
+ 4.6764065936359795
+ 4.676439790552386
+ 4.67647298714271
+ 4.6765061834069614
+ 4.676539379345148
+ 4.676572574957281
+ 4.676605770243367
+ 4.676638965203415
+ 4.676672159837433
+ 4.676705354145433
+ 4.676738548127418
+ 4.676771741783401
+ 4.676804935113391
+ 4.676838128117395
+ 4.67687132079542
+ 4.676904513147478
+ 4.676937705173576
+ 4.6769708968737245
+ 4.677004088247928
+ 4.6770372792962
+ 4.677070470018546
+ 4.677103660414978
+ 4.6771368504855
+ 4.677170040230123
+ 4.677203229648857
+ 4.6772364187417095
+ 4.677269607508689
+ 4.677302795949804
+ 4.6773359840650635
+ 4.677369171854477
+ 4.6774023593180525
+ 4.677435546455797
+ 4.677468733267722
+ 4.677501919753835
+ 4.677535105914145
+ 4.67756829174866
+ 4.677601477257389
+ 4.677634662440341
+ 4.677667847297524
+ 4.677701031828947
+ 4.67773421603462
+ 4.677767399914549
+ 4.677800583468745
+ 4.677833766697215
+ 4.677866949599968
+ 4.677900132177014
+ 4.677933314428361
+ 4.677966496354018
+ 4.677999677953992
+ 4.678032859228294
+ 4.6780660401769305
+ 4.678099220799912
+ 4.678132401097246
+ 4.678165581068941
+ 4.678198760715007
+ 4.6782319400354515
+ 4.678265119030284
+ 4.678298297699513
+ 4.678331476043145
+ 4.678364654061193
+ 4.678397831753662
+ 4.678431009120562
+ 4.678464186161902
+ 4.678497362877691
+ 4.6785305392679355
+ 4.678563715332647
+ 4.678596891071832
+ 4.6786300664855
+ 4.678663241573659
+ 4.678696416336319
+ 4.6787295907734885
+ 4.678762764885175
+ 4.678795938671387
+ 4.678829112132135
+ 4.678862285267427
+ 4.678895458077271
+ 4.678928630561676
+ 4.678961802720649
+ 4.678994974554203
+ 4.6790281460623415
+ 4.679061317245077
+ 4.679094488102417
+ 4.6791276586343695
+ 4.679160828840943
+ 4.679193998722147
+ 4.679227168277992
+ 4.679260337508483
+ 4.6792935064136305
+ 4.679326674993442
+ 4.679359843247928
+ 4.679393011177097
+ 4.679426178780955
+ 4.679459346059514
+ 4.679492513012781
+ 4.679525679640764
+ 4.679558845943474
+ 4.679592011920917
+ 4.679625177573104
+ 4.679658342900042
+ 4.679691507901739
+ 4.679724672578207
+ 4.679757836929452
+ 4.679791000955483
+ 4.679824164656307
+ 4.679857328031937
+ 4.679890491082378
+ 4.67992365380764
+ 4.6799568162077305
+ 4.679989978282661
+ 4.680023140032437
+ 4.680056301457068
+ 4.680089462556563
+ 4.680122623330932
+ 4.680155783780182
+ 4.680188943904321
+ 4.680222103703359
+ 4.680255263177306
+ 4.680288422326167
+ 4.680321581149952
+ 4.680354739648672
+ 4.680387897822333
+ 4.680421055670946
+ 4.680454213194517
+ 4.680487370393057
+ 4.680520527266572
+ 4.680553683815073
+ 4.680586840038567
+ 4.680619995937064
+ 4.6806531515105725
+ 4.6806863067591
+ 4.6807194616826555
+ 4.680752616281249
+ 4.680785770554888
+ 4.680818924503581
+ 4.680852078127336
+ 4.680885231426164
+ 4.680918384400073
+ 4.6809515370490695
+ 4.6809846893731635
+ 4.681017841372364
+ 4.6810509930466795
+ 4.681084144396119
+ 4.68111729542069
+ 4.681150446120402
+ 4.681183596495263
+ 4.681216746545282
+ 4.681249896270468
+ 4.6812830456708285
+ 4.6813161947463735
+ 4.681349343497112
+ 4.68138249192305
+ 4.681415640024199
+ 4.681448787800567
+ 4.681481935252161
+ 4.681515082378991
+ 4.6815482291810655
+ 4.681581375658393
+ 4.681614521810983
+ 4.681647667638843
+ 4.6816808131419805
+ 4.681713958320407
+ 4.68174710317413
+ 4.6817802477031565
+ 4.681813391907498
+ 4.68184653578716
+ 4.6818796793421535
+ 4.681912822572486
+ 4.681945965478167
+ 4.681979108059204
+ 4.682012250315608
+ 4.682045392247385
+ 4.682078533854544
+ 4.6821116751370955
+ 4.682144816095045
+ 4.682177956728404
+ 4.68221109703718
+ 4.682244237021381
+ 4.682277376681017
+ 4.682310516016096
+ 4.682343655026626
+ 4.682376793712617
+ 4.682409932074076
+ 4.682443070111013
+ 4.682476207823436
+ 4.682509345211354
+ 4.6825424822747745
+ 4.682575619013708
+ 4.682608755428161
+ 4.682641891518144
+ 4.682675027283664
+ 4.682708162724731
+ 4.682741297841353
+ 4.682774432633539
+ 4.682807567101297
+ 4.682840701244636
+ 4.682873835063565
+ 4.682906968558091
+ 4.682940101728224
+ 4.682973234573973
+ 4.683006367095347
+ 4.683039499292352
+ 4.6830726311649995
+ 4.6831057627132955
+ 4.683138893937252
+ 4.683172024836874
+ 4.683205155412171
+ 4.683238285663155
+ 4.6832714155898305
+ 4.683304545192207
+ 4.683337674470295
+ 4.683370803424101
+ 4.6834039320536345
+ 4.683437060358904
+ 4.683470188339919
+ 4.683503315996687
+ 4.683536443329216
+ 4.683569570337516
+ 4.683602697021596
+ 4.683635823381463
+ 4.683668949417126
+ 4.683702075128594
+ 4.683735200515876
+ 4.683768325578981
+ 4.683801450317916
+ 4.68383457473269
+ 4.683867698823312
+ 4.683900822589791
+ 4.683933946032136
+ 4.683967069150354
+ 4.684000191944455
+ 4.684033314414447
+ 4.684066436560338
+ 4.684099558382137
+ 4.684132679879854
+ 4.684165801053496
+ 4.684198921903072
+ 4.684232042428592
+ 4.684265162630062
+ 4.684298282507492
+ 4.684331402060891
+ 4.6843645212902665
+ 4.684397640195629
+ 4.684430758776984
+ 4.684463877034342
+ 4.684496994967714
+ 4.684530112577105
+ 4.6845632298625235
+ 4.68459634682398
+ 4.684629463461483
+ 4.68466257977504
+ 4.684695695764661
+ 4.684728811430353
+ 4.684761926772125
+ 4.684795041789988
+ 4.684828156483946
+ 4.684861270854012
+ 4.684894384900192
+ 4.6849274986224945
+ 4.684960612020929
+ 4.684993725095506
+ 4.685026837846231
+ 4.685059950273113
+ 4.685093062376163
+ 4.6851261741553865
+ 4.685159285610795
+ 4.685192396742394
+ 4.685225507550196
+ 4.685258618034204
+ 4.685291728194432
+ 4.685324838030886
+ 4.685357947543576
+ 4.685391056732509
+ 4.685424165597694
+ 4.68545727413914
+ 4.685490382356856
+ 4.6855234902508505
+ 4.68555659782113
+ 4.685589705067706
+ 4.685622811990585
+ 4.685655918589778
+ 4.685689024865291
+ 4.685722130817133
+ 4.685755236445314
+ 4.685788341749842
+ 4.685821446730724
+ 4.685854551387972
+ 4.68588765572159
+ 4.685920759731592
+ 4.685953863417981
+ 4.685986966780771
+ 4.686020069819966
+ 4.686053172535577
+ 4.686086274927613
+ 4.686119376996079
+ 4.68615247874099
+ 4.686185580162348
+ 4.686218681260165
+ 4.686251782034449
+ 4.686284882485208
+ 4.686317982612453
+ 4.68635108241619
+ 4.686384181896427
+ 4.686417281053175
+ 4.686450379886442
+ 4.686483478396235
+ 4.686516576582564
+ 4.686549674445437
+ 4.686582771984864
+ 4.686615869200851
+ 4.686648966093409
+ 4.686682062662545
+ 4.686715158908267
+ 4.6867482548305865
+ 4.686781350429509
+ 4.6868144457050445
+ 4.686847540657203
+ 4.68688063528599
+ 4.686913729591415
+ 4.686946823573489
+ 4.686979917232218
+ 4.68701301056761
+ 4.687046103579676
+ 4.6870791962684235
+ 4.687112288633862
+ 4.6871453806759975
+ 4.687178472394842
+ 4.6872115637904
+ 4.687244654862684
+ 4.6872777456117
+ 4.687310836037458
+ 4.687343926139965
+ 4.687377015919231
+ 4.687410105375265
+ 4.687443194508075
+ 4.687476283317667
+ 4.687509371804054
+ 4.687542459967242
+ 4.68757554780724
+ 4.6876086353240565
+ 4.6876417225177
+ 4.68767480938818
+ 4.687707895935503
+ 4.68774098215968
+ 4.687774068060717
+ 4.687807153638626
+ 4.687840238893412
+ 4.6878733238250865
+ 4.687906408433656
+ 4.687939492719129
+ 4.687972576681515
+ 4.688005660320823
+ 4.688038743637061
+ 4.688071826630238
+ 4.68810490930036
+ 4.688137991647439
+ 4.688171073671483
+ 4.688204155372498
+ 4.688237236750496
+ 4.6882703178054825
+ 4.688303398537469
+ 4.688336478946462
+ 4.688369559032468
+ 4.688402638795501
+ 4.688435718235566
+ 4.688468797352672
+ 4.688501876146828
+ 4.688534954618042
+ 4.688568032766324
+ 4.68860111059168
+ 4.68863418809412
+ 4.688667265273654
+ 4.688700342130288
+ 4.688733418664033
+ 4.688766494874895
+ 4.688799570762884
+ 4.688832646328009
+ 4.688865721570276
+ 4.688898796489697
+ 4.68893187108628
+ 4.6889649453600315
+ 4.688998019310961
+ 4.689031092939077
+ 4.689064166244388
+ 4.6890972392269035
+ 4.689130311886631
+ 4.68916338422358
+ 4.689196456237758
+ 4.689229527929173
+ 4.689262599297836
+ 4.689295670343753
+ 4.689328741066934
+ 4.689361811467387
+ 4.689394881545121
+ 4.689427951300145
+ 4.689461020732466
+ 4.689494089842093
+ 4.689527158629036
+ 4.689560227093301
+ 4.689593295234899
+ 4.689626363053837
+ 4.689659430550125
+ 4.689692497723771
+ 4.689725564574782
+ 4.689758631103167
+ 4.689791697308937
+ 4.689824763192099
+ 4.68985782875266
+ 4.68989089399063
+ 4.689923958906019
+ 4.689957023498832
+ 4.689990087769081
+ 4.6900231517167725
+ 4.690056215341915
+ 4.6900892786445185
+ 4.69012234162459
+ 4.690155404282139
+ 4.690188466617174
+ 4.690221528629703
+ 4.690254590319736
+ 4.690287651687279
+ 4.690320712732342
+ 4.690353773454935
+ 4.6903868338550625
+ 4.690419893932738
+ 4.690452953687966
+ 4.690486013120758
+ 4.69051907223112
+ 4.690552131019062
+ 4.690585189484592
+ 4.690618247627718
+ 4.69065130544845
+ 4.690684362946797
+ 4.690717420122765
+ 4.690750476976365
+ 4.690783533507603
+ 4.69081658971649
+ 4.690849645603033
+ 4.690882701167241
+ 4.690915756409122
+ 4.690948811328686
+ 4.690981865925941
+ 4.691014920200894
+ 4.691047974153555
+ 4.691081027783933
+ 4.691114081092035
+ 4.6911471340778705
+ 4.691180186741447
+ 4.691213239082775
+ 4.691246291101861
+ 4.6912793427987145
+ 4.691312394173345
+ 4.691345445225759
+ 4.6913784959559655
+ 4.691411546363973
+ 4.691444596449792
+ 4.691477646213428
+ 4.691510695654893
+ 4.691543744774193
+ 4.691576793571336
+ 4.691609842046332
+ 4.69164289019919
+ 4.691675938029917
+ 4.691708985538522
+ 4.6917420327250134
+ 4.691775079589401
+ 4.691808126131692
+ 4.691841172351896
+ 4.691874218250019
+ 4.691907263826072
+ 4.6919403090800635
+ 4.691973354012001
+ 4.692006398621893
+ 4.692039442909749
+ 4.692072486875578
+ 4.6921055305193855
+ 4.692138573841182
+ 4.692171616840977
+ 4.692204659518777
+ 4.692237701874592
+ 4.69227074390843
+ 4.692303785620299
+ 4.692336827010209
+ 4.692369868078167
+ 4.692402908824182
+ 4.692435949248264
+ 4.6924689893504175
+ 4.692502029130655
+ 4.692535068588984
+ 4.692568107725412
+ 4.692601146539949
+ 4.692634185032602
+ 4.69266722320338
+ 4.692700261052291
+ 4.692733298579346
+ 4.692766335784551
+ 4.692799372667916
+ 4.692832409229447
+ 4.692865445469154
+ 4.692898481387048
+ 4.692931516983134
+ 4.692964552257422
+ 4.69299758720992
+ 4.693030621840636
+ 4.69306365614958
+ 4.693096690136761
+ 4.693129723802185
+ 4.693162757145862
+ 4.693195790167801
+ 4.693228822868009
+ 4.6932618552464955
+ 4.693294887303269
+ 4.693327919038338
+ 4.69336095045171
+ 4.6933939815433945
+ 4.693427012313401
+ 4.693460042761736
+ 4.693493072888409
+ 4.693526102693428
+ 4.693559132176803
+ 4.69359216133854
+ 4.693625190178649
+ 4.69365821869714
+ 4.693691246894018
+ 4.693724274769294
+ 4.693757302322976
+ 4.693790329555072
+ 4.693823356465591
+ 4.693856383054541
+ 4.693889409321931
+ 4.693922435267771
+ 4.693955460892066
+ 4.693988486194827
+ 4.694021511176062
+ 4.694054535835779
+ 4.694087560173987
+ 4.694120584190693
+ 4.694153607885909
+ 4.694186631259639
+ 4.694219654311896
+ 4.694252677042686
+ 4.694285699452017
+ 4.694318721539899
+ 4.694351743306338
+ 4.694384764751346
+ 4.69441778587493
+ 4.694450806677097
+ 4.694483827157858
+ 4.69451684731722
+ 4.694549867155191
+ 4.694582886671781
+ 4.694615905866997
+ 4.694648924740849
+ 4.694681943293345
+ 4.694714961524491
+ 4.6947479794342994
+ 4.694780997022777
+ 4.694814014289933
+ 4.694847031235774
+ 4.694880047860309
+ 4.694913064163549
+ 4.694946080145499
+ 4.69497909580617
+ 4.695012111145569
+ 4.695045126163706
+ 4.695078140860587
+ 4.695111155236224
+ 4.6951441692906215
+ 4.695177183023791
+ 4.69521019643574
+ 4.695243209526476
+ 4.69527622229601
+ 4.695309234744348
+ 4.695342246871499
+ 4.695375258677473
+ 4.695408270162277
+ 4.6954412813259205
+ 4.69547429216841
+ 4.695507302689756
+ 4.695540312889966
+ 4.695573322769049
+ 4.695606332327013
+ 4.695639341563868
+ 4.69567235047962
+ 4.695705359074279
+ 4.695738367347853
+ 4.6957713753003505
+ 4.69580438293178
+ 4.695837390242151
+ 4.695870397231471
+ 4.695903403899747
+ 4.695936410246991
+ 4.695969416273209
+ 4.696002421978409
+ 4.696035427362601
+ 4.696068432425793
+ 4.696101437167994
+ 4.696134441589211
+ 4.696167445689453
+ 4.69620044946873
+ 4.696233452927048
+ 4.696266456064418
+ 4.696299458880847
+ 4.696332461376344
+ 4.696365463550916
+ 4.696398465404573
+ 4.696431466937324
+ 4.696464468149176
+ 4.696497469040138
+ 4.696530469610218
+ 4.696563469859426
+ 4.696596469787769
+ 4.696629469395257
+ 4.696662468681895
+ 4.696695467647696
+ 4.696728466292665
+ 4.696761464616813
+ 4.696794462620146
+ 4.696827460302675
+ 4.696860457664406
+ 4.69689345470535
+ 4.6969264514255125
+ 4.696959447824905
+ 4.696992443903534
+ 4.697025439661409
+ 4.697058435098538
+ 4.697091430214929
+ 4.69712442501059
+ 4.697157419485531
+ 4.697190413639761
+ 4.697223407473286
+ 4.697256400986117
+ 4.697289394178259
+ 4.6973223870497245
+ 4.69735537960052
+ 4.6973883718306535
+ 4.697421363740133
+ 4.69745435532897
+ 4.697487346597171
+ 4.697520337544743
+ 4.697553328171697
+ 4.69758631847804
+ 4.697619308463781
+ 4.6976522981289275
+ 4.69768528747349
+ 4.697718276497474
+ 4.697751265200891
+ 4.697784253583747
+ 4.697817241646052
+ 4.697850229387814
+ 4.697883216809042
+ 4.6979162039097435
+ 4.697949190689927
+ 4.697982177149602
+ 4.698015163288776
+ 4.698048149107457
+ 4.698081134605655
+ 4.698114119783377
+ 4.698147104640633
+ 4.698180089177429
+ 4.698213073393776
+ 4.698246057289682
+ 4.698279040865153
+ 4.698312024120201
+ 4.698345007054833
+ 4.698377989669056
+ 4.69841097196288
+ 4.698443953936313
+ 4.698476935589364
+ 4.698509916922041
+ 4.698542897934352
+ 4.698575878626306
+ 4.698608858997911
+ 4.698641839049176
+ 4.69867481878011
+ 4.6987077981907195
+ 4.698740777281015
+ 4.698773756051003
+ 4.698806734500694
+ 4.698839712630097
+ 4.698872690439216
+ 4.698905667928063
+ 4.698938645096647
+ 4.698971621944974
+ 4.699004598473055
+ 4.699037574680896
+ 4.699070550568506
+ 4.699103526135896
+ 4.69913650138307
+ 4.699169476310041
+ 4.699202450916814
+ 4.699235425203399
+ 4.699268399169805
+ 4.699301372816039
+ 4.69933434614211
+ 4.699367319148026
+ 4.699400291833796
+ 4.6994332641994285
+ 4.699466236244933
+ 4.699499207970315
+ 4.699532179375585
+ 4.699565150460753
+ 4.699598121225824
+ 4.699631091670808
+ 4.699664061795713
+ 4.699697031600549
+ 4.699730001085323
+ 4.699762970250044
+ 4.699795939094719
+ 4.6998289076193585
+ 4.699861875823969
+ 4.69989484370856
+ 4.699927811273141
+ 4.6999607785177195
+ 4.6999937454423035
+ 4.7000267120469
+ 4.700059678331521
+ 4.7000926442961735
+ 4.700125609940864
+ 4.700158575265602
+ 4.7001915402703975
+ 4.700224504955258
+ 4.70025746932019
+ 4.700290433365205
+ 4.70032339709031
+ 4.700356360495513
+ 4.700389323580823
+ 4.700422286346248
+ 4.700455248791798
+ 4.700488210917478
+ 4.7005211727233
+ 4.700554134209271
+ 4.7005870953754
+ 4.700620056221694
+ 4.700653016748162
+ 4.700685976954813
+ 4.700718936841656
+ 4.700751896408697
+ 4.700784855655947
+ 4.700817814583414
+ 4.700850773191105
+ 4.700883731479028
+ 4.700916689447195
+ 4.7009496470956105
+ 4.700982604424285
+ 4.701015561433226
+ 4.701048518122443
+ 4.701081474491944
+ 4.701114430541737
+ 4.701147386271829
+ 4.701180341682232
+ 4.701213296772952
+ 4.7012462515439974
+ 4.701279205995377
+ 4.7013121601271
+ 4.7013451139391735
+ 4.701378067431607
+ 4.701411020604407
+ 4.701443973457585
+ 4.701476925991146
+ 4.701509878205102
+ 4.701542830099459
+ 4.701575781674227
+ 4.701608732929411
+ 4.701641683865023
+ 4.701674634481071
+ 4.701707584777562
+ 4.701740534754506
+ 4.701773484411909
+ 4.7018064337497805
+ 4.701839382768131
+ 4.701872331466966
+ 4.7019052798462955
+ 4.701938227906127
+ 4.70197117564647
+ 4.702004123067332
+ 4.702037070168723
+ 4.70207001695065
+ 4.70210296341312
+ 4.7021359095561435
+ 4.702168855379729
+ 4.702201800883884
+ 4.702234746068617
+ 4.702267690933937
+ 4.702300635479851
+ 4.7023335797063694
+ 4.7023665236135
+ 4.702399467201249
+ 4.702432410469628
+ 4.702465353418645
+ 4.702498296048305
+ 4.70253123835862
+ 4.702564180349598
+ 4.7025971220212455
+ 4.702630063373573
+ 4.702663004406587
+ 4.702695945120298
+ 4.702728885514711
+ 4.702761825589839
+ 4.702794765345686
+ 4.702827704782265
+ 4.702860643899579
+ 4.702893582697641
+ 4.702926521176457
+ 4.7029594593360375
+ 4.702992397176388
+ 4.703025334697518
+ 4.703058271899438
+ 4.703091208782153
+ 4.703124145345673
+ 4.703157081590007
+ 4.703190017515163
+ 4.703222953121149
+ 4.703255888407973
+ 4.703288823375645
+ 4.703321758024171
+ 4.703354692353562
+ 4.703387626363825
+ 4.703420560054969
+ 4.703453493427001
+ 4.70348642647993
+ 4.703519359213766
+ 4.703552291628516
+ 4.703585223724189
+ 4.703618155500791
+ 4.703651086958334
+ 4.703684018096824
+ 4.70371694891627
+ 4.70374987941668
+ 4.7037828095980645
+ 4.7038157394604285
+ 4.703848669003784
+ 4.703881598228136
+ 4.703914527133495
+ 4.70394745571987
+ 4.703980383987266
+ 4.704013311935695
+ 4.704046239565163
+ 4.7040791668756805
+ 4.704112093867254
+ 4.704145020539893
+ 4.704177946893605
+ 4.7042108729284
+ 4.704243798644285
+ 4.704276724041267
+ 4.704309649119357
+ 4.704342573878564
+ 4.704375498318893
+ 4.704408422440354
+ 4.704441346242957
+ 4.704474269726709
+ 4.704507192891617
+ 4.70454011573769
+ 4.7045730382649396
+ 4.704605960473371
+ 4.704638882362992
+ 4.704671803933812
+ 4.7047047251858425
+ 4.704737646119087
+ 4.704770566733555
+ 4.704803487029257
+ 4.7048364070062005
+ 4.704869326664393
+ 4.704902246003844
+ 4.70493516502456
+ 4.704968083726552
+ 4.705001002109826
+ 4.705033920174391
+ 4.705066837920257
+ 4.7050997553474305
+ 4.705132672455921
+ 4.705165589245736
+ 4.705198505716885
+ 4.7052314218693745
+ 4.705264337703214
+ 4.705297253218412
+ 4.705330168414978
+ 4.7053630832929185
+ 4.705395997852242
+ 4.705428912092958
+ 4.705461826015074
+ 4.705494739618598
+ 4.70552765290354
+ 4.705560565869907
+ 4.705593478517708
+ 4.705626390846951
+ 4.705659302857644
+ 4.705692214549796
+ 4.705725125923416
+ 4.70575803697851
+ 4.705790947715089
+ 4.70582385813316
+ 4.7058567682327315
+ 4.705889678013813
+ 4.705922587476411
+ 4.705955496620534
+ 4.705988405446193
+ 4.706021313953394
+ 4.7060542221421455
+ 4.706087130012456
+ 4.706120037564334
+ 4.706152944797789
+ 4.706185851712827
+ 4.706218758309459
+ 4.706251664587691
+ 4.706284570547532
+ 4.706317476188992
+ 4.7063503815120775
+ 4.706383286516798
+ 4.706416191203161
+ 4.706449095571175
+ 4.7064819996208485
+ 4.70651490335219
+ 4.706547806765208
+ 4.706580709859911
+ 4.706613612636306
+ 4.706646515094404
+ 4.70667941723421
+ 4.706712319055735
+ 4.706745220558986
+ 4.706778121743972
+ 4.706811022610702
+ 4.706843923159182
+ 4.706876823389424
+ 4.706909723301432
+ 4.706942622895217
+ 4.706975522170787
+ 4.707008421128151
+ 4.707041319767316
+ 4.707074218088292
+ 4.707107116091085
+ 4.707140013775705
+ 4.707172911142161
+ 4.7072058081904595
+ 4.707238704920609
+ 4.707271601332621
+ 4.707304497426499
+ 4.7073373932022555
+ 4.707370288659895
+ 4.707403183799429
+ 4.707436078620866
+ 4.707468973124213
+ 4.707501867309477
+ 4.70753476117667
+ 4.707567654725797
+ 4.707600547956868
+ 4.70763344086989
+ 4.707666333464873
+ 4.707699225741825
+ 4.707732117700754
+ 4.707765009341667
+ 4.707797900664575
+ 4.707830791669485
+ 4.707863682356405
+ 4.707896572725343
+ 4.707929462776309
+ 4.707962352509311
+ 4.707995241924355
+ 4.708028131021452
+ 4.708061019800609
+ 4.708093908261836
+ 4.708126796405138
+ 4.7081596842305276
+ 4.70819257173801
+ 4.708225458927594
+ 4.7082583457992895
+ 4.708291232353103
+ 4.7083241185890445
+ 4.708357004507121
+ 4.708389890107341
+ 4.708422775389714
+ 4.708455660354247
+ 4.708488545000949
+ 4.708521429329827
+ 4.708554313340891
+ 4.708587197034151
+ 4.708620080409611
+ 4.708652963467283
+ 4.708685846207173
+ 4.7087187286292895
+ 4.708751610733643
+ 4.708784492520239
+ 4.708817373989088
+ 4.708850255140197
+ 4.708883135973576
+ 4.708916016489231
+ 4.708948896687172
+ 4.7089817765674065
+ 4.709014656129944
+ 4.709047535374792
+ 4.709080414301957
+ 4.709113292911452
+ 4.709146171203281
+ 4.709179049177454
+ 4.709211926833979
+ 4.709244804172865
+ 4.70927768119412
+ 4.7093105578977505
+ 4.709343434283769
+ 4.70937631035218
+ 4.7094091861029925
+ 4.709442061536217
+ 4.709474936651859
+ 4.70950781144993
+ 4.709540685930435
+ 4.709573560093384
+ 4.709606433938784
+ 4.709639307466646
+ 4.709672180676977
+ 4.709705053569785
+ 4.709737926145077
+ 4.709770798402864
+ 4.7098036703431525
+ 4.709836541965951
+ 4.709869413271269
+ 4.709902284259114
+ 4.709935154929494
+ 4.709968025282419
+ 4.7100008953178945
+ 4.710033765035931
+ 4.710066634436536
+ 4.710099503519717
+ 4.710132372285484
+ 4.710165240733845
+ 4.710198108864808
+ 4.710230976678381
+ 4.710263844174573
+ 4.710296711353391
+ 4.710329578214845
+ 4.710362444758942
+ 4.710395310985691
+ 4.7104281768951
+ 4.710461042487178
+ 4.710493907761932
+ 4.710526772719372
+ 4.710559637359505
+ 4.710592501682339
+ 4.710625365687884
+ 4.710658229376146
+ 4.710691092747137
+ 4.710723955800861
+ 4.710756818537329
+ 4.710789680956549
+ 4.710822543058529
+ 4.710855404843277
+ 4.710888266310801
+ 4.71092112746111
+ 4.7109539882942135
+ 4.7109868488101165
+ 4.71101970900883
+ 4.711052568890363
+ 4.711085428454721
+ 4.711118287701914
+ 4.71115114663195
+ 4.711184005244837
+ 4.711216863540585
+ 4.7112497215191995
+ 4.711282579180691
+ 4.711315436525067
+ 4.711348293552335
+ 4.711381150262505
+ 4.711414006655585
+ 4.711446862731582
+ 4.711479718490505
+ 4.711512573932363
+ 4.711545429057163
+ 4.711578283864916
+ 4.711611138355626
+ 4.7116439925293045
+ 4.711676846385958
+ 4.711709699925597
+ 4.711742553148229
+ 4.711775406053861
+ 4.7118082586425025
+ 4.711841110914161
+ 4.711873962868845
+ 4.711906814506564
+ 4.711939665827325
+ 4.711972516831136
+ 4.712005367518007
+ 4.712038217887945
+ 4.712071067940958
+ 4.712103917677055
+ 4.712136767096244
+ 4.712169616198534
+ 4.712202464983933
+ 4.712235313452448
+ 4.712268161604088
+ 4.712301009438863
+ 4.712333856956779
+ 4.712366704157846
+ 4.712399551042072
+ 4.712432397609464
+ 4.712465243860031
+ 4.712498089793781
+ 4.712530935410723
+ 4.712563780710866
+ 4.712596625694216
+ 4.712629470360784
+ 4.712662314710576
+ 4.7126951587436
+ 4.712728002459867
+ 4.712760845859383
+ 4.712793688942158
+ 4.712826531708199
+ 4.712859374157514
+ 4.712892216290112
+ 4.712925058106002
+ 4.712957899605191
+ 4.712990740787688
+ 4.7130235816535
+ 4.713056422202638
+ 4.7130892624351075
+ 4.713122102350918
+ 4.713154941950078
+ 4.713187781232596
+ 4.71322062019848
+ 4.713253458847737
+ 4.713286297180376
+ 4.713319135196407
+ 4.713351972895836
+ 4.713384810278673
+ 4.713417647344925
+ 4.713450484094602
+ 4.71348332052771
+ 4.713516156644259
+ 4.713548992444255
+ 4.71358182792771
+ 4.713614663094629
+ 4.713647497945021
+ 4.713680332478896
+ 4.713713166696261
+ 4.713746000597124
+ 4.713778834181493
+ 4.713811667449378
+ 4.713844500400786
+ 4.7138773330357235
+ 4.7139101653542035
+ 4.71394299735623
+ 4.7139758290418134
+ 4.714008660410961
+ 4.714041491463682
+ 4.714074322199983
+ 4.714107152619874
+ 4.714139982723363
+ 4.7141728125104585
+ 4.7142056419811675
+ 4.7142384711354985
+ 4.714271299973462
+ 4.714304128495063
+ 4.714336956700312
+ 4.714369784589216
+ 4.714402612161785
+ 4.7144354394180255
+ 4.7144682663579465
+ 4.714501092981556
+ 4.714533919288862
+ 4.714566745279875
+ 4.7145995709546
+ 4.714632396313047
+ 4.714665221355224
+ 4.71469804608114
+ 4.714730870490802
+ 4.71476369458422
+ 4.7147965183614
+ 4.714829341822352
+ 4.714862164967083
+ 4.714894987795602
+ 4.714927810307918
+ 4.714960632504038
+ 4.714993454383971
+ 4.715026275947725
+ 4.715059097195308
+ 4.7150919181267295
+ 4.715124738741996
+ 4.715157559041116
+ 4.7151903790241
+ 4.715223198690953
+ 4.715256018041686
+ 4.715288837076305
+ 4.715321655794821
+ 4.715354474197239
+ 4.7153872922835705
+ 4.715420110053822
+ 4.715452927508001
+ 4.715485744646117
+ 4.715518561468179
+ 4.715551377974194
+ 4.71558419416417
+ 4.715617010038115
+ 4.7156498255960395
+ 4.71568264083795
+ 4.7157154557638545
+ 4.715748270373762
+ 4.715781084667681
+ 4.715813898645619
+ 4.7158467123075845
+ 4.715879525653587
+ 4.715912338683632
+ 4.7159451513977295
+ 4.715977963795888
+ 4.716010775878116
+ 4.716043587644421
+ 4.716076399094812
+ 4.716109210229295
+ 4.71614202104788
+ 4.716174831550577
+ 4.71620764173739
+ 4.716240451608332
+ 4.7162732611634075
+ 4.716306070402626
+ 4.716338879325997
+ 4.716371687933528
+ 4.716404496225226
+ 4.716437304201101
+ 4.71647011186116
+ 4.716502919205411
+ 4.716535726233863
+ 4.716568532946525
+ 4.716601339343404
+ 4.716634145424508
+ 4.716666951189847
+ 4.7166997566394295
+ 4.716732561773259
+ 4.716765366591351
+ 4.716798171093707
+ 4.71683097528034
+ 4.7168637791512555
+ 4.716896582706463
+ 4.716929385945971
+ 4.716962188869786
+ 4.716994991477918
+ 4.717027793770375
+ 4.7170605957471645
+ 4.717093397408295
+ 4.717126198753776
+ 4.717158999783614
+ 4.717191800497817
+ 4.717224600896396
+ 4.7172574009793555
+ 4.717290200746707
+ 4.717323000198457
+ 4.717355799334613
+ 4.7173885981551855
+ 4.717421396660182
+ 4.717454194849609
+ 4.717486992723478
+ 4.717519790281794
+ 4.717552587524566
+ 4.717585384451803
+ 4.717618181063514
+ 4.717650977359706
+ 4.717683773340388
+ 4.717716569005567
+ 4.717749364355253
+ 4.7177821593894524
+ 4.7178149541081735
+ 4.717847748511427
+ 4.717880542599218
+ 4.717913336371556
+ 4.7179461298284515
+ 4.717978922969909
+ 4.718011715795938
+ 4.718044508306549
+ 4.718077300501746
+ 4.718110092381542
+ 4.718142883945941
+ 4.718175675194954
+ 4.718208466128589
+ 4.718241256746852
+ 4.718274047049753
+ 4.718306837037301
+ 4.718339626709502
+ 4.718372416066366
+ 4.718405205107901
+ 4.718437993834114
+ 4.718470782245015
+ 4.718503570340612
+ 4.718536358120911
+ 4.718569145585922
+ 4.7186019327356545
+ 4.718634719570114
+ 4.718667506089312
+ 4.718700292293253
+ 4.7187330781819465
+ 4.718765863755403
+ 4.718798649013627
+ 4.71883143395663
+ 4.718864218584419
+ 4.718897002897
+ 4.718929786894386
+ 4.718962570576582
+ 4.718995353943596
+ 4.719028136995437
+ 4.719060919732114
+ 4.719093702153634
+ 4.719126484260006
+ 4.719159266051237
+ 4.719192047527337
+ 4.719224828688313
+ 4.719257609534174
+ 4.719290390064928
+ 4.719323170280583
+ 4.7193559501811455
+ 4.719388729766627
+ 4.719421509037034
+ 4.719454287992375
+ 4.719487066632658
+ 4.719519844957891
+ 4.7195526229680835
+ 4.7195854006632425
+ 4.719618178043376
+ 4.719650955108492
+ 4.719683731858601
+ 4.719716508293709
+ 4.719749284413825
+ 4.719782060218956
+ 4.719814835709113
+ 4.719847610884301
+ 4.719880385744531
+ 4.71991316028981
+ 4.719945934520146
+ 4.719978708435547
+ 4.720011482036021
+ 4.720044255321578
+ 4.7200770282922235
+ 4.720109800947968
+ 4.720142573288819
+ 4.720175345314785
+ 4.720208117025874
+ 4.720240888422094
+ 4.7202736595034525
+ 4.720306430269959
+ 4.720339200721622
+ 4.720371970858448
+ 4.720404740680446
+ 4.720437510187625
+ 4.720470279379992
+ 4.720503048257555
+ 4.720535816820324
+ 4.720568585068307
+ 4.72060135300151
+ 4.720634120619942
+ 4.720666887923614
+ 4.720699654912531
+ 4.7207324215867015
+ 4.720765187946135
+ 4.720797953990839
+ 4.720830719720822
+ 4.720863485136092
+ 4.720896250236657
+ 4.720929015022526
+ 4.720961779493707
+ 4.720994543650207
+ 4.721027307492035
+ 4.721060071019199
+ 4.721092834231708
+ 4.72112559712957
+ 4.721158359712792
+ 4.721191121981383
+ 4.721223883935352
+ 4.721256645574707
+ 4.721289406899455
+ 4.721322167909604
+ 4.721354928605164
+ 4.721387688986142
+ 4.721420449052546
+ 4.721453208804387
+ 4.7214859682416686
+ 4.721518727364401
+ 4.721551486172594
+ 4.7215842446662535
+ 4.721617002845389
+ 4.721649760710009
+ 4.72168251826012
+ 4.721715275495731
+ 4.721748032416851
+ 4.721780789023488
+ 4.72181354531565
+ 4.721846301293344
+ 4.721879056956579
+ 4.721911812305366
+ 4.721944567339708
+ 4.721977322059616
+ 4.722010076465099
+ 4.722042830556164
+ 4.72207558433282
+ 4.722108337795072
+ 4.722141090942933
+ 4.7221738437764085
+ 4.722206596295507
+ 4.722239348500237
+ 4.722272100390607
+ 4.722304851966624
+ 4.722337603228296
+ 4.7223703541756334
+ 4.7224031048086434
+ 4.722435855127332
+ 4.722468605131712
+ 4.722501354821786
+ 4.722534104197567
+ 4.72256685325906
+ 4.722599602006276
+ 4.72263235043922
+ 4.722665098557902
+ 4.72269784636233
+ 4.722730593852512
+ 4.7227633410284575
+ 4.722796087890172
+ 4.722828834437666
+ 4.722861580670948
+ 4.722894326590023
+ 4.722927072194903
+ 4.7229598174855925
+ 4.722992562462103
+ 4.723025307124441
+ 4.723058051472615
+ 4.723090795506632
+ 4.723123539226504
+ 4.7231562826322335
+ 4.723189025723833
+ 4.723221768501309
+ 4.723254510964671
+ 4.723287253113926
+ 4.723319994949082
+ 4.723352736470148
+ 4.723385477677132
+ 4.723418218570042
+ 4.723450959148885
+ 4.723483699413671
+ 4.723516439364407
+ 4.723549179001102
+ 4.723581918323763
+ 4.723614657332401
+ 4.723647396027021
+ 4.7236801344076325
+ 4.723712872474243
+ 4.723745610226862
+ 4.723778347665496
+ 4.723811084790155
+ 4.723843821600846
+ 4.723876558097577
+ 4.723909294280357
+ 4.723942030149193
+ 4.723974765704094
+ 4.724007500945069
+ 4.724040235872126
+ 4.72407297048527
+ 4.724105704784512
+ 4.724138438769862
+ 4.7241711724413245
+ 4.724203905798908
+ 4.724236638842624
+ 4.724269371572476
+ 4.724302103988477
+ 4.724334836090632
+ 4.724367567878949
+ 4.724400299353438
+ 4.724433030514106
+ 4.724465761360962
+ 4.724498491894013
+ 4.724531222113269
+ 4.724563952018736
+ 4.724596681610422
+ 4.724629410888338
+ 4.72466213985249
+ 4.724694868502886
+ 4.724727596839535
+ 4.724760324862445
+ 4.724793052571624
+ 4.72482577996708
+ 4.724858507048823
+ 4.724891233816859
+ 4.724923960271195
+ 4.724956686411843
+ 4.724989412238807
+ 4.7250221377521
+ 4.725054862951725
+ 4.7250875878376934
+ 4.725120312410012
+ 4.725153036668691
+ 4.725185760613735
+ 4.725218484245156
+ 4.72525120756296
+ 4.725283930567155
+ 4.7253166532577495
+ 4.725349375634752
+ 4.725382097698171
+ 4.725414819448013
+ 4.7254475408842875
+ 4.725480262007004
+ 4.725512982816168
+ 4.725545703311789
+ 4.725578423493874
+ 4.725611143362433
+ 4.725643862917473
+ 4.725676582159003
+ 4.725709301087029
+ 4.725742019701562
+ 4.725774738002609
+ 4.725807455990177
+ 4.725840173664276
+ 4.7258728910249115
+ 4.725905608072095
+ 4.725938324805833
+ 4.725971041226134
+ 4.726003757333006
+ 4.726036473126456
+ 4.726069188606494
+ 4.7261019037731264
+ 4.7261346186263635
+ 4.726167333166211
+ 4.7262000473926795
+ 4.726232761305775
+ 4.726265474905508
+ 4.726298188191884
+ 4.726330901164913
+ 4.726363613824602
+ 4.726396326170961
+ 4.726429038203995
+ 4.726461749923715
+ 4.726494461330128
+ 4.726527172423242
+ 4.726559883203065
+ 4.726592593669606
+ 4.726625303822872
+ 4.726658013662873
+ 4.726690723189615
+ 4.726723432403108
+ 4.726756141303359
+ 4.726788849890377
+ 4.726821558164168
+ 4.726854266124743
+ 4.726886973772109
+ 4.726919681106272
+ 4.726952388127245
+ 4.7269850948350305
+ 4.727017801229641
+ 4.727050507311082
+ 4.727083213079363
+ 4.727115918534492
+ 4.727148623676477
+ 4.727181328505327
+ 4.727214033021048
+ 4.727246737223649
+ 4.72727944111314
+ 4.7273121446895265
+ 4.727344847952818
+ 4.7273775509030225
+ 4.727410253540149
+ 4.727442955864203
+ 4.727475657875195
+ 4.727508359573132
+ 4.727541060958023
+ 4.727573762029876
+ 4.727606462788699
+ 4.727639163234499
+ 4.727671863367286
+ 4.727704563187067
+ 4.72773726269385
+ 4.7277699618876445
+ 4.7278026607684565
+ 4.727835359336295
+ 4.727868057591169
+ 4.727900755533087
+ 4.727933453162055
+ 4.727966150478083
+ 4.727998847481178
+ 4.7280315441713485
+ 4.728064240548602
+ 4.728096936612948
+ 4.728129632364395
+ 4.728162327802948
+ 4.7281950229286185
+ 4.728227717741413
+ 4.728260412241339
+ 4.728293106428407
+ 4.728325800302623
+ 4.728358493863996
+ 4.728391187112535
+ 4.728423880048246
+ 4.7284565726711385
+ 4.72848926498122
+ 4.728521956978498
+ 4.728554648662983
+ 4.728587340034681
+ 4.728620031093602
+ 4.728652721839751
+ 4.728685412273139
+ 4.728718102393773
+ 4.728750792201662
+ 4.728783481696814
+ 4.7288161708792344
+ 4.728848859748934
+ 4.728881548305921
+ 4.728914236550204
+ 4.7289469244817885
+ 4.728979612100685
+ 4.729012299406899
+ 4.729044986400443
+ 4.729077673081321
+ 4.7291103594495425
+ 4.729143045505116
+ 4.729175731248049
+ 4.72920841667835
+ 4.7292411017960285
+ 4.729273786601089
+ 4.729306471093542
+ 4.729339155273397
+ 4.7293718391406605
+ 4.72940452269534
+ 4.729437205937444
+ 4.729469888866981
+ 4.72950257148396
+ 4.729535253788386
+ 4.7295679357802705
+ 4.729600617459621
+ 4.729633298826444
+ 4.729665979880749
+ 4.729698660622544
+ 4.729731341051837
+ 4.729764021168634
+ 4.729796700972946
+ 4.72982938046478
+ 4.729862059644145
+ 4.729894738511048
+ 4.729927417065497
+ 4.729960095307501
+ 4.7299927732370675
+ 4.730025450854205
+ 4.7300581281589205
+ 4.7300908051512245
+ 4.7301234818311215
+ 4.730156158198624
+ 4.730188834253736
+ 4.730221509996468
+ 4.730254185426828
+ 4.730286860544823
+ 4.730319535350462
+ 4.730352209843754
+ 4.730384884024704
+ 4.730417557893323
+ 4.730450231449617
+ 4.730482904693598
+ 4.730515577625269
+ 4.730548250244641
+ 4.730580922551721
+ 4.730613594546519
+ 4.73064626622904
+ 4.730678937599294
+ 4.730711608657291
+ 4.730744279403035
+ 4.730776949836537
+ 4.730809619957804
+ 4.730842289766845
+ 4.730874959263668
+ 4.730907628448279
+ 4.7309402973206875
+ 4.730972965880903
+ 4.731005634128931
+ 4.731038302064783
+ 4.731070969688464
+ 4.731103636999982
+ 4.731136303999347
+ 4.731168970686567
+ 4.731201637061649
+ 4.731234303124602
+ 4.731266968875432
+ 4.73129963431415
+ 4.731332299440763
+ 4.731364964255278
+ 4.731397628757705
+ 4.731430292948051
+ 4.731462956826324
+ 4.731495620392531
+ 4.731528283646683
+ 4.731560946588786
+ 4.731593609218849
+ 4.731626271536879
+ 4.731658933542884
+ 4.731691595236874
+ 4.731724256618856
+ 4.731756917688837
+ 4.7317895784468265
+ 4.731822238892833
+ 4.731854899026863
+ 4.731887558848926
+ 4.731920218359027
+ 4.7319528775571795
+ 4.731985536443387
+ 4.73201819501766
+ 4.732050853280006
+ 4.7320835112304325
+ 4.732116168868948
+ 4.7321488261955595
+ 4.732181483210277
+ 4.732214139913109
+ 4.732246796304061
+ 4.732279452383143
+ 4.732312108150361
+ 4.7323447636057265
+ 4.732377418749245
+ 4.732410073580924
+ 4.732442728100773
+ 4.7324753823088015
+ 4.732508036205015
+ 4.732540689789422
+ 4.7325733430620325
+ 4.732605996022853
+ 4.732638648671891
+ 4.732671301009156
+ 4.7327039530346555
+ 4.732736604748396
+ 4.732769256150388
+ 4.732801907240639
+ 4.7328345580191575
+ 4.732867208485951
+ 4.732899858641026
+ 4.732932508484392
+ 4.732965158016058
+ 4.732997807236031
+ 4.733030456144319
+ 4.73306310474093
+ 4.733095753025873
+ 4.733128400999155
+ 4.733161048660786
+ 4.733193696010771
+ 4.73322634304912
+ 4.733258989775841
+ 4.733291636190941
+ 4.733324282294431
+ 4.733356928086315
+ 4.733389573566604
+ 4.7334222187353046
+ 4.733454863592426
+ 4.733487508137975
+ 4.733520152371961
+ 4.733552796294391
+ 4.733585439905274
+ 4.7336180832046155
+ 4.733650726192429
+ 4.733683368868716
+ 4.73371601123349
+ 4.733748653286756
+ 4.733781295028522
+ 4.733813936458798
+ 4.733846577577592
+ 4.733879218384909
+ 4.733911858880761
+ 4.733944499065154
+ 4.733977138938095
+ 4.734009778499595
+ 4.734042417749659
+ 4.734075056688297
+ 4.734107695315517
+ 4.734140333631327
+ 4.734172971635734
+ 4.734205609328747
+ 4.734238246710373
+ 4.7342708837806216
+ 4.7343035205395
+ 4.734336156987017
+ 4.73436879312318
+ 4.734401428947996
+ 4.734434064461475
+ 4.734466699663625
+ 4.734499334554453
+ 4.7345319691339665
+ 4.734564603402175
+ 4.734597237359086
+ 4.7346298710047074
+ 4.734662504339048
+ 4.734695137362115
+ 4.734727770073917
+ 4.7347604024744605
+ 4.734793034563756
+ 4.73482566634181
+ 4.734858297808632
+ 4.734890928964228
+ 4.734923559808607
+ 4.734956190341777
+ 4.734988820563747
+ 4.735021450474524
+ 4.735054080074116
+ 4.735086709362532
+ 4.735119338339779
+ 4.735151967005866
+ 4.7351845953608
+ 4.7352172234045895
+ 4.735249851137243
+ 4.7352824785587675
+ 4.735315105669173
+ 4.735347732468465
+ 4.735380358956653
+ 4.735412985133746
+ 4.735445610999751
+ 4.735478236554675
+ 4.735510861798527
+ 4.7355434867313155
+ 4.735576111353049
+ 4.735608735663733
+ 4.7356413596633775
+ 4.735673983351992
+ 4.735706606729582
+ 4.735739229796155
+ 4.735771852551722
+ 4.735804474996289
+ 4.735837097129865
+ 4.735869718952458
+ 4.735902340464074
+ 4.735934961664724
+ 4.735967582554415
+ 4.736000203133154
+ 4.73603282340095
+ 4.736065443357811
+ 4.736098063003744
+ 4.736130682338759
+ 4.736163301362862
+ 4.736195920076064
+ 4.736228538478369
+ 4.736261156569788
+ 4.736293774350329
+ 4.736326391819998
+ 4.736359008978804
+ 4.736391625826756
+ 4.736424242363862
+ 4.736456858590128
+ 4.7364894745055635
+ 4.736522090110178
+ 4.736554705403976
+ 4.7365873203869695
+ 4.736619935059164
+ 4.736652549420567
+ 4.736685163471188
+ 4.736717777211036
+ 4.7367503906401165
+ 4.736783003758438
+ 4.736815616566012
+ 4.736848229062841
+ 4.736880841248938
+ 4.736913453124308
+ 4.7369460646889605
+ 4.736978675942901
+ 4.737011286886142
+ 4.737043897518688
+ 4.737076507840548
+ 4.73710911785173
+ 4.737141727552243
+ 4.737174336942093
+ 4.73720694602129
+ 4.737239554789841
+ 4.737272163247755
+ 4.7373047713950385
+ 4.7373373792317
+ 4.737369986757749
+ 4.737402593973192
+ 4.737435200878037
+ 4.737467807472293
+ 4.737500413755967
+ 4.737533019729069
+ 4.737565625391604
+ 4.737598230743582
+ 4.73763083578501
+ 4.737663440515898
+ 4.737696044936252
+ 4.73772864904608
+ 4.737761252845392
+ 4.737793856334195
+ 4.737826459512496
+ 4.737859062380303
+ 4.737891664937625
+ 4.7379242671844715
+ 4.737956869120848
+ 4.737989470746762
+ 4.738022072062225
+ 4.738054673067242
+ 4.738087273761822
+ 4.738119874145973
+ 4.738152474219704
+ 4.738185073983021
+ 4.738217673435933
+ 4.7382502725784486
+ 4.738282871410576
+ 4.7383154699323216
+ 4.7383480681436945
+ 4.738380666044702
+ 4.738413263635354
+ 4.738445860915656
+ 4.738478457885618
+ 4.7385110545452465
+ 4.738543650894551
+ 4.738576246933539
+ 4.7386088426622175
+ 4.738641438080595
+ 4.738674033188682
+ 4.738706627986482
+ 4.738739222474007
+ 4.738771816651263
+ 4.738804410518258
+ 4.738837004075
+ 4.738869597321498
+ 4.73890219025776
+ 4.738934782883794
+ 4.738967375199606
+ 4.738999967205206
+ 4.739032558900602
+ 4.739065150285802
+ 4.739097741360812
+ 4.739130332125642
+ 4.739162922580301
+ 4.739195512724795
+ 4.739228102559132
+ 4.73926069208332
+ 4.7392932812973685
+ 4.739325870201284
+ 4.739358458795076
+ 4.739391047078752
+ 4.739423635052319
+ 4.739456222715786
+ 4.73948881006916
+ 4.73952139711245
+ 4.739553983845664
+ 4.73958657026881
+ 4.739619156381894
+ 4.739651742184928
+ 4.739684327677916
+ 4.739716912860868
+ 4.739749497733793
+ 4.739782082296697
+ 4.73981466654959
+ 4.739847250492477
+ 4.739879834125367
+ 4.739912417448272
+ 4.739945000461194
+ 4.739977583164144
+ 4.740010165557131
+ 4.740042747640162
+ 4.740075329413244
+ 4.740107910876385
+ 4.740140492029596
+ 4.7401730728728815
+ 4.74020565340625
+ 4.740238233629712
+ 4.7402708135432725
+ 4.740303393146942
+ 4.740335972440726
+ 4.740368551424634
+ 4.740401130098675
+ 4.740433708462855
+ 4.740466286517183
+ 4.740498864261666
+ 4.740531441696314
+ 4.740564018821134
+ 4.7405965956361324
+ 4.74062917214132
+ 4.740661748336703
+ 4.740694324222289
+ 4.740726899798087
+ 4.740759475064106
+ 4.740792050020351
+ 4.740824624666834
+ 4.740857199003559
+ 4.740889773030537
+ 4.740922346747773
+ 4.740954920155278
+ 4.7409874932530585
+ 4.741020066041123
+ 4.741052638519479
+ 4.7410852106881345
+ 4.741117782547097
+ 4.741150354096377
+ 4.7411829253359805
+ 4.741215496265915
+ 4.74124806688619
+ 4.7412806371968115
+ 4.7413132071977895
+ 4.741345776889131
+ 4.741378346270844
+ 4.741410915342937
+ 4.741443484105417
+ 4.741476052558293
+ 4.741508620701572
+ 4.741541188535264
+ 4.741573756059374
+ 4.741606323273913
+ 4.741638890178887
+ 4.741671456774305
+ 4.741704023060174
+ 4.741736589036502
+ 4.741769154703299
+ 4.74180172006057
+ 4.741834285108324
+ 4.741866849846571
+ 4.741899414275316
+ 4.74193197839457
+ 4.741964542204339
+ 4.741997105704632
+ 4.742029668895454
+ 4.742062231776818
+ 4.742094794348728
+ 4.742127356611194
+ 4.742159918564223
+ 4.742192480207823
+ 4.742225041542001
+ 4.742257602566769
+ 4.7422901632821315
+ 4.742322723688096
+ 4.742355283784672
+ 4.742387843571868
+ 4.742420403049691
+ 4.742452962218148
+ 4.742485521077249
+ 4.7425180796270014
+ 4.742550637867412
+ 4.74258319579849
+ 4.742615753420244
+ 4.7426483107326805
+ 4.742680867735807
+ 4.742713424429633
+ 4.742745980814166
+ 4.742778536889414
+ 4.742811092655384
+ 4.742843648112086
+ 4.742876203259527
+ 4.742908758097714
+ 4.742941312626656
+ 4.742973866846362
+ 4.743006420756837
+ 4.7430389743580905
+ 4.743071527650132
+ 4.743104080632967
+ 4.743136633306605
+ 4.743169185671054
+ 4.743201737726321
+ 4.743234289472415
+ 4.743266840909343
+ 4.743299392037113
+ 4.743331942855734
+ 4.743364493365214
+ 4.74339704356556
+ 4.7434295934567805
+ 4.743462143038882
+ 4.7434946923118755
+ 4.743527241275767
+ 4.743559789930563
+ 4.743592338276276
+ 4.743624886312909
+ 4.743657434040472
+ 4.743689981458974
+ 4.743722528568422
+ 4.743755075368823
+ 4.7437876218601875
+ 4.743820168042521
+ 4.743852713915833
+ 4.74388525948013
+ 4.743917804735421
+ 4.743950349681714
+ 4.743982894319018
+ 4.744015438647337
+ 4.744047982666683
+ 4.744080526377063
+ 4.744113069778485
+ 4.744145612870956
+ 4.744178155654485
+ 4.744210698129079
+ 4.744243240294746
+ 4.744275782151494
+ 4.744308323699332
+ 4.744340864938269
+ 4.744373405868309
+ 4.744405946489463
+ 4.744438486801738
+ 4.744471026805143
+ 4.7445035664996835
+ 4.744536105885371
+ 4.74456864496221
+ 4.744601183730211
+ 4.74463372218938
+ 4.744666260339726
+ 4.744698798181258
+ 4.744731335713983
+ 4.744763872937907
+ 4.74479640985304
+ 4.744828946459391
+ 4.744861482756965
+ 4.744894018745772
+ 4.744926554425821
+ 4.744959089797117
+ 4.7449916248596695
+ 4.745024159613488
+ 4.745056694058577
+ 4.745089228194947
+ 4.745121762022604
+ 4.745154295541559
+ 4.745186828751818
+ 4.745219361653388
+ 4.745251894246279
+ 4.745284426530497
+ 4.745316958506051
+ 4.74534949017295
+ 4.7453820215312
+ 4.745414552580811
+ 4.745447083321789
+ 4.745479613754142
+ 4.745512143877879
+ 4.745544673693008
+ 4.745577203199536
+ 4.745609732397472
+ 4.7456422612868225
+ 4.745674789867597
+ 4.745707318139803
+ 4.745739846103448
+ 4.74577237375854
+ 4.745804901105088
+ 4.745837428143099
+ 4.745869954872579
+ 4.74590248129354
+ 4.745935007405987
+ 4.745967533209929
+ 4.746000058705375
+ 4.7460325838923305
+ 4.746065108770805
+ 4.746097633340805
+ 4.746130157602342
+ 4.746162681555419
+ 4.746195205200048
+ 4.746227728536235
+ 4.746260251563988
+ 4.746292774283316
+ 4.746325296694226
+ 4.746357818796725
+ 4.746390340590823
+ 4.746422862076527
+ 4.746455383253846
+ 4.746487904122786
+ 4.7465204246833546
+ 4.746552944935562
+ 4.7465854648794155
+ 4.746617984514922
+ 4.7466505038420905
+ 4.746683022860928
+ 4.746715541571445
+ 4.746748059973645
+ 4.746780578067539
+ 4.746813095853134
+ 4.746845613330438
+ 4.74687813049946
+ 4.746910647360206
+ 4.746943163912686
+ 4.746975680156907
+ 4.747008196092875
+ 4.747040711720603
+ 4.747073227040093
+ 4.747105742051357
+ 4.7471382567544005
+ 4.747170771149232
+ 4.747203285235861
+ 4.7472357990142955
+ 4.7472683124845405
+ 4.747300825646606
+ 4.7473333385005
+ 4.74736585104623
+ 4.747398363283804
+ 4.74743087521323
+ 4.747463386834516
+ 4.74749589814767
+ 4.747528409152698
+ 4.747560919849612
+ 4.747593430238417
+ 4.74762594031912
+ 4.747658450091731
+ 4.747690959556258
+ 4.7477234687127075
+ 4.747755977561089
+ 4.74778848610141
+ 4.747820994333677
+ 4.7478535022578985
+ 4.747886009874084
+ 4.74791851718224
+ 4.747951024182375
+ 4.747983530874496
+ 4.748016037258611
+ 4.74804854333473
+ 4.7480810491028596
+ 4.748113554563006
+ 4.748146059715179
+ 4.748178564559386
+ 4.748211069095636
+ 4.748243573323935
+ 4.7482760772442925
+ 4.748308580856716
+ 4.748341084161214
+ 4.748373587157792
+ 4.74840608984646
+ 4.748438592227227
+ 4.748471094300098
+ 4.748503596065082
+ 4.748536097522189
+ 4.748568598671423
+ 4.748601099512796
+ 4.748633600046313
+ 4.748666100271984
+ 4.748698600189814
+ 4.748731099799815
+ 4.7487635991019905
+ 4.748796098096352
+ 4.748828596782905
+ 4.748861095161659
+ 4.748893593232621
+ 4.7489260909958
+ 4.7489585884512024
+ 4.7489910855988375
+ 4.749023582438712
+ 4.749056078970835
+ 4.749088575195212
+ 4.749121071111854
+ 4.749153566720769
+ 4.749186062021962
+ 4.749218557015443
+ 4.749251051701218
+ 4.7492835460792975
+ 4.7493160401496874
+ 4.749348533912396
+ 4.749381027367433
+ 4.749413520514804
+ 4.749446013354518
+ 4.749478505886583
+ 4.749510998111007
+ 4.749543490027796
+ 4.74957598163696
+ 4.749608472938507
+ 4.7496409639324435
+ 4.749673454618779
+ 4.74970594499752
+ 4.749738435068674
+ 4.7497709248322515
+ 4.749803414288258
+ 4.7498359034367015
+ 4.749868392277591
+ 4.749900880810935
+ 4.7499333690367385
+ 4.749965856955012
+ 4.749998344565763
+ 4.750030831869
+ 4.750063318864728
+ 4.750095805552958
+ 4.750128291933696
+ 4.7501607780069515
+ 4.750193263772731
+ 4.750225749231043
+ 4.750258234381895
+ 4.750290719225296
+ 4.750323203761253
+ 4.7503556879897735
+ 4.750388171910867
+ 4.75042065552454
+ 4.7504531388308
+ 4.750485621829656
+ 4.750518104521116
+ 4.750550586905186
+ 4.750583068981876
+ 4.750615550751194
+ 4.750648032213147
+ 4.750680513367743
+ 4.7507129942149895
+ 4.750745474754894
+ 4.750777954987467
+ 4.7508104349127125
+ 4.750842914530643
+ 4.750875393841262
+ 4.7509078728445795
+ 4.750940351540604
+ 4.750972829929341
+ 4.751005308010801
+ 4.75103778578499
+ 4.751070263251918
+ 4.751102740411591
+ 4.751135217264017
+ 4.7511676938092045
+ 4.751200170047162
+ 4.751232645977896
+ 4.751265121601415
+ 4.751297596917728
+ 4.751330071926841
+ 4.751362546628763
+ 4.751395021023501
+ 4.751427495111064
+ 4.751459968891459
+ 4.751492442364695
+ 4.751524915530778
+ 4.751557388389718
+ 4.751589860941521
+ 4.751622333186197
+ 4.751654805123752
+ 4.751687276754194
+ 4.751719748077532
+ 4.751752219093774
+ 4.751784689802927
+ 4.751817160204998
+ 4.751849630299997
+ 4.751882100087931
+ 4.7519145695688065
+ 4.751947038742633
+ 4.751979507609418
+ 4.75201197616917
+ 4.752044444421896
+ 4.752076912367605
+ 4.752109380006303
+ 4.752141847337999
+ 4.752174314362701
+ 4.7522067810804165
+ 4.752239247491154
+ 4.75227171359492
+ 4.752304179391724
+ 4.752336644881573
+ 4.752369110064476
+ 4.752401574940438
+ 4.75243403950947
+ 4.752466503771579
+ 4.752498967726772
+ 4.752531431375058
+ 4.7525638947164435
+ 4.752596357750937
+ 4.752628820478548
+ 4.752661282899282
+ 4.752693745013147
+ 4.752726206820153
+ 4.752758668320306
+ 4.752791129513614
+ 4.752823590400086
+ 4.752856050979729
+ 4.752888511252551
+ 4.75292097121856
+ 4.7529534308777635
+ 4.75298589023017
+ 4.753018349275788
+ 4.753050808014622
+ 4.753083266446684
+ 4.75311572457198
+ 4.753148182390518
+ 4.753180639902305
+ 4.75321309710735
+ 4.7532455540056615
+ 4.753278010597246
+ 4.753310466882112
+ 4.753342922860267
+ 4.75337537853172
+ 4.7534078338964765
+ 4.753440288954546
+ 4.753472743705937
+ 4.753505198150656
+ 4.753537652288712
+ 4.753570106120112
+ 4.753602559644864
+ 4.753635012862976
+ 4.7536674657744555
+ 4.7536999183793105
+ 4.753732370677549
+ 4.753764822669181
+ 4.753797274354211
+ 4.753829725732648
+ 4.7538621768045
+ 4.7538946275697755
+ 4.7539270780284815
+ 4.7539595281806255
+ 4.7539919780262165
+ 4.754024427565262
+ 4.754056876797769
+ 4.754089325723748
+ 4.754121774343203
+ 4.754154222656144
+ 4.7541866706625795
+ 4.754219118362516
+ 4.754251565755962
+ 4.754284012842926
+ 4.754316459623413
+ 4.754348906097435
+ 4.754381352264997
+ 4.754413798126107
+ 4.754446243680774
+ 4.754478688929006
+ 4.7545111338708095
+ 4.754543578506194
+ 4.754576022835166
+ 4.754608466857733
+ 4.7546409105739045
+ 4.754673353983686
+ 4.754705797087089
+ 4.7547382398841185
+ 4.754770682374783
+ 4.754803124559089
+ 4.754835566437047
+ 4.754868008008665
+ 4.754900449273947
+ 4.7549328902329036
+ 4.754965330885544
+ 4.754997771231873
+ 4.755030211271901
+ 4.755062651005633
+ 4.75509509043308
+ 4.755127529554248
+ 4.755159968369146
+ 4.75519240687778
+ 4.755224845080161
+ 4.7552572829762925
+ 4.755289720566185
+ 4.755322157849847
+ 4.755354594827284
+ 4.755387031498506
+ 4.755419467863519
+ 4.755451903922334
+ 4.755484339674956
+ 4.755516775121392
+ 4.755549210261653
+ 4.755581645095745
+ 4.755614079623676
+ 4.755646513845454
+ 4.755678947761086
+ 4.755711381370582
+ 4.755743814673948
+ 4.755776247671192
+ 4.755808680362323
+ 4.755841112747347
+ 4.755873544826273
+ 4.755905976599109
+ 4.755938408065862
+ 4.755970839226541
+ 4.756003270081154
+ 4.756035700629706
+ 4.756068130872208
+ 4.756100560808667
+ 4.75613299043909
+ 4.756165419763486
+ 4.756197848781863
+ 4.756230277494226
+ 4.756262705900586
+ 4.7562951340009505
+ 4.756327561795326
+ 4.75635998928372
+ 4.7563924164661415
+ 4.7564248433426
+ 4.7564572699131
+ 4.756489696177651
+ 4.75652212213626
+ 4.756554547788936
+ 4.756586973135686
+ 4.756619398176519
+ 4.756651822911441
+ 4.756684247340462
+ 4.756716671463588
+ 4.756749095280826
+ 4.756781518792187
+ 4.756813941997677
+ 4.756846364897303
+ 4.756878787491075
+ 4.756911209778999
+ 4.756943631761084
+ 4.756976053437337
+ 4.7570084748077655
+ 4.757040895872378
+ 4.757073316631184
+ 4.757105737084187
+ 4.757138157231398
+ 4.757170577072825
+ 4.757202996608475
+ 4.757235415838356
+ 4.757267834762476
+ 4.757300253380842
+ 4.7573326716934625
+ 4.757365089700345
+ 4.757397507401498
+ 4.757429924796929
+ 4.7574623418866455
+ 4.757494758670655
+ 4.757527175148966
+ 4.757559591321587
+ 4.757592007188524
+ 4.757624422749786
+ 4.757656838005381
+ 4.757689252955316
+ 4.7577216675996
+ 4.75775408193824
+ 4.757786495971244
+ 4.757818909698619
+ 4.757851323120374
+ 4.757883736236517
+ 4.7579161490470545
+ 4.757948561551994
+ 4.757980973751346
+ 4.758013385645116
+ 4.758045797233313
+ 4.758078208515944
+ 4.758110619493017
+ 4.758143030164541
+ 4.758175440530521
+ 4.758207850590967
+ 4.758240260345888
+ 4.758272669795289
+ 4.75830507893918
+ 4.758337487777567
+ 4.758369896310458
+ 4.758402304537863
+ 4.758434712459787
+ 4.758467120076239
+ 4.758499527387229
+ 4.758531934392761
+ 4.758564341092845
+ 4.758596747487488
+ 4.758629153576698
+ 4.758661559360484
+ 4.758693964838852
+ 4.758726370011811
+ 4.75875877487937
+ 4.758791179441532
+ 4.758823583698311
+ 4.75885598764971
+ 4.75888839129574
+ 4.758920794636407
+ 4.758953197671719
+ 4.758985600401685
+ 4.759018002826311
+ 4.759050404945606
+ 4.759082806759578
+ 4.759115208268234
+ 4.759147609471582
+ 4.75918001036963
+ 4.759212410962386
+ 4.759244811249858
+ 4.759277211232053
+ 4.759309610908979
+ 4.759342010280644
+ 4.759374409347057
+ 4.759406808108223
+ 4.759439206564152
+ 4.759471604714852
+ 4.7595040025603295
+ 4.759536400100593
+ 4.75956879733565
+ 4.759601194265508
+ 4.759633590890176
+ 4.759665987209661
+ 4.75969838322397
+ 4.759730778933112
+ 4.759763174337096
+ 4.759795569435927
+ 4.759827964229614
+ 4.759860358718165
+ 4.759892752901588
+ 4.7599251467798895
+ 4.75995754035308
+ 4.759989933621164
+ 4.760022326584152
+ 4.76005471924205
+ 4.760087111594867
+ 4.76011950364261
+ 4.760151895385287
+ 4.760184286822906
+ 4.760216677955475
+ 4.7602490687830015
+ 4.760281459305493
+ 4.760313849522957
+ 4.760346239435402
+ 4.760378629042837
+ 4.760411018345267
+ 4.760443407342702
+ 4.7604757960351485
+ 4.7605081844226165
+ 4.76054057250511
+ 4.76057296028264
+ 4.760605347755212
+ 4.760637734922837
+ 4.76067012178552
+ 4.760702508343269
+ 4.7607348945960934
+ 4.760767280544
+ 4.760799666186995
+ 4.760832051525089
+ 4.760864436558288
+ 4.760896821286601
+ 4.760929205710035
+ 4.7609615898285975
+ 4.760993973642298
+ 4.761026357151143
+ 4.761058740355138
+ 4.761091123254294
+ 4.761123505848619
+ 4.761155888138119
+ 4.761188270122804
+ 4.761220651802678
+ 4.761253033177753
+ 4.761285414248033
+ 4.761317795013529
+ 4.761350175474246
+ 4.7613825556301945
+ 4.761414935481381
+ 4.761447315027812
+ 4.7614796942694975
+ 4.761512073206443
+ 4.76154445183866
+ 4.7615768301661525
+ 4.761609208188929
+ 4.761641585906999
+ 4.761673963320369
+ 4.761706340429048
+ 4.761738717233041
+ 4.761771093732358
+ 4.761803469927008
+ 4.7618358458169965
+ 4.761868221402332
+ 4.761900596683021
+ 4.761932971659073
+ 4.761965346330496
+ 4.761997720697296
+ 4.762030094759482
+ 4.762062468517063
+ 4.762094841970044
+ 4.762127215118435
+ 4.762159587962242
+ 4.762191960501474
+ 4.76222433273614
+ 4.762256704666244
+ 4.762289076291798
+ 4.762321447612807
+ 4.76235381862928
+ 4.762386189341225
+ 4.762418559748648
+ 4.762450929851558
+ 4.762483299649963
+ 4.762515669143871
+ 4.762548038333288
+ 4.762580407218224
+ 4.7626127757986865
+ 4.762645144074681
+ 4.762677512046218
+ 4.762709879713303
+ 4.762742247075947
+ 4.762774614134154
+ 4.762806980887934
+ 4.762839347337294
+ 4.762871713482242
+ 4.762904079322786
+ 4.7629364448589335
+ 4.762968810090692
+ 4.76300117501807
+ 4.763033539641075
+ 4.763065903959715
+ 4.763098267973997
+ 4.763130631683929
+ 4.763162995089519
+ 4.763195358190774
+ 4.763227720987703
+ 4.763260083480313
+ 4.763292445668612
+ 4.763324807552609
+ 4.76335716913231
+ 4.763389530407721
+ 4.763421891378855
+ 4.763454252045716
+ 4.763486612408313
+ 4.763518972466652
+ 4.763551332220743
+ 4.763583691670593
+ 4.76361605081621
+ 4.7636484096576
+ 4.763680768194774
+ 4.763713126427737
+ 4.763745484356497
+ 4.763777841981064
+ 4.763810199301444
+ 4.763842556317644
+ 4.763874913029673
+ 4.7639072694375395
+ 4.763939625541249
+ 4.763971981340811
+ 4.7640043368362335
+ 4.764036692027522
+ 4.764069046914687
+ 4.764101401497736
+ 4.764133755776674
+ 4.764166109751511
+ 4.764198463422255
+ 4.7642308167889125
+ 4.764263169851493
+ 4.764295522610002
+ 4.764327875064448
+ 4.76436022721484
+ 4.764392579061185
+ 4.76442493060349
+ 4.764457281841763
+ 4.764489632776013
+ 4.764521983406247
+ 4.764554333732472
+ 4.764586683754698
+ 4.76461903347293
+ 4.764651382887177
+ 4.764683731997446
+ 4.764716080803748
+ 4.764748429306085
+ 4.764780777504469
+ 4.764813125398908
+ 4.764845472989407
+ 4.764877820275976
+ 4.764910167258622
+ 4.764942513937352
+ 4.764974860312174
+ 4.765007206383097
+ 4.765039552150129
+ 4.765071897613274
+ 4.765104242772545
+ 4.7651365876279455
+ 4.765168932179487
+ 4.765201276427173
+ 4.765233620371015
+ 4.765265964011018
+ 4.765298307347192
+ 4.765330650379543
+ 4.765362993108079
+ 4.7653953355328085
+ 4.76542767765374
+ 4.765460019470879
+ 4.765492360984235
+ 4.765524702193814
+ 4.765557043099626
+ 4.765589383701678
+ 4.765621723999977
+ 4.765654063994531
+ 4.765686403685348
+ 4.765718743072435
+ 4.765751082155801
+ 4.7657834209354535
+ 4.7658157594113995
+ 4.765848097583646
+ 4.765880435452203
+ 4.765912773017077
+ 4.765945110278276
+ 4.765977447235807
+ 4.766009783889679
+ 4.766042120239898
+ 4.766074456286473
+ 4.766106792029412
+ 4.766139127468722
+ 4.766171462604411
+ 4.766203797436487
+ 4.766236131964956
+ 4.766268466189829
+ 4.766300800111111
+ 4.766333133728811
+ 4.766365467042937
+ 4.766397800053496
+ 4.766430132760495
+ 4.766462465163943
+ 4.766494797263847
+ 4.766527129060216
+ 4.766559460553056
+ 4.766591791742376
+ 4.766624122628183
+ 4.7666564532104845
+ 4.76668878348929
+ 4.766721113464605
+ 4.76675344313644
+ 4.766785772504799
+ 4.766818101569692
+ 4.766850430331127
+ 4.7668827587891105
+ 4.766915086943651
+ 4.766947414794757
+ 4.766979742342435
+ 4.767012069586692
+ 4.767044396527538
+ 4.76707672316498
+ 4.767109049499024
+ 4.767141375529679
+ 4.7671737012569535
+ 4.767206026680854
+ 4.767238351801389
+ 4.7672706766185655
+ 4.767303001132391
+ 4.7673353253428745
+ 4.7673676492500245
+ 4.767399972853845
+ 4.767432296154348
+ 4.7674646191515375
+ 4.767496941845424
+ 4.767529264236013
+ 4.767561586323315
+ 4.767593908107335
+ 4.767626229588083
+ 4.7676585507655656
+ 4.767690871639789
+ 4.767723192210764
+ 4.767755512478496
+ 4.767787832442994
+ 4.767820152104265
+ 4.767852471462317
+ 4.767884790517158
+ 4.767917109268794
+ 4.767949427717235
+ 4.767981745862488
+ 4.768014063704561
+ 4.768046381243461
+ 4.7680786984791945
+ 4.7681110154117725
+ 4.7681433320412
+ 4.768175648367486
+ 4.768207964390638
+ 4.768240280110663
+ 4.76827259552757
+ 4.7683049106413655
+ 4.768337225452058
+ 4.768369539959655
+ 4.768401854164163
+ 4.768434168065593
+ 4.768466481663949
+ 4.768498794959241
+ 4.768531107951476
+ 4.76856342064066
+ 4.768595733026806
+ 4.7686280451099154
+ 4.768660356889999
+ 4.7686926683670645
+ 4.76872497954112
+ 4.768757290412172
+ 4.768789600980228
+ 4.768821911245298
+ 4.768854221207387
+ 4.768886530866505
+ 4.768918840222657
+ 4.7689511492758525
+ 4.7689834580261
+ 4.769015766473405
+ 4.7690480746177775
+ 4.769080382459223
+ 4.769112689997752
+ 4.7691449972333695
+ 4.769177304166084
+ 4.7692096107959046
+ 4.769241917122836
+ 4.76927422314689
+ 4.7693065288680705
+ 4.769338834286388
+ 4.769371139401848
+ 4.7694034442144595
+ 4.76943574872423
+ 4.769468052931167
+ 4.769500356835278
+ 4.769532660436571
+ 4.769564963735054
+ 4.769597266730735
+ 4.769629569423621
+ 4.769661871813719
+ 4.769694173901039
+ 4.769726475685586
+ 4.769758777167369
+ 4.769791078346396
+ 4.769823379222674
+ 4.769855679796211
+ 4.769887980067016
+ 4.769920280035094
+ 4.769952579700456
+ 4.769984879063106
+ 4.770017178123054
+ 4.770049476880307
+ 4.770081775334875
+ 4.770114073486761
+ 4.770146371335977
+ 4.770178668882528
+ 4.770210966126423
+ 4.7702432630676705
+ 4.770275559706276
+ 4.7703078560422485
+ 4.770340152075596
+ 4.7703724478063245
+ 4.770404743234445
+ 4.770437038359962
+ 4.770469333182884
+ 4.7705016277032195
+ 4.7705339219209755
+ 4.770566215836161
+ 4.7705985094487815
+ 4.770630802758846
+ 4.770663095766362
+ 4.770695388471338
+ 4.770727680873779
+ 4.770759972973695
+ 4.770792264771094
+ 4.770824556265984
+ 4.770856847458371
+ 4.770889138348262
+ 4.770921428935668
+ 4.770953719220593
+ 4.770986009203048
+ 4.771018298883037
+ 4.7710505882605725
+ 4.771082877335657
+ 4.771115166108302
+ 4.771147454578514
+ 4.7711797427463
+ 4.771212030611668
+ 4.771244318174627
+ 4.771276605435182
+ 4.771308892393344
+ 4.771341179049118
+ 4.7713734654025135
+ 4.771405751453536
+ 4.771438037202197
+ 4.771470322648499
+ 4.7715026077924545
+ 4.771534892634069
+ 4.771567177173349
+ 4.771599461410304
+ 4.771631745344941
+ 4.771664028977268
+ 4.771696312307292
+ 4.771728595335022
+ 4.771760878060465
+ 4.771793160483629
+ 4.77182544260452
+ 4.771857724423147
+ 4.771890005939518
+ 4.771922287153641
+ 4.771954568065522
+ 4.77198684867517
+ 4.772019128982593
+ 4.772051408987798
+ 4.772083688690792
+ 4.772115968091583
+ 4.772148247190181
+ 4.77218052598659
+ 4.77221280448082
+ 4.772245082672877
+ 4.7722773605627715
+ 4.772309638150508
+ 4.772341915436097
+ 4.772374192419544
+ 4.772406469100859
+ 4.772438745480047
+ 4.7724710215571156
+ 4.772503297332075
+ 4.772535572804931
+ 4.772567847975693
+ 4.772600122844366
+ 4.772632397410962
+ 4.772664671675483
+ 4.77269694563794
+ 4.772729219298341
+ 4.772761492656694
+ 4.772793765713004
+ 4.77282603846728
+ 4.77285831091953
+ 4.772890583069763
+ 4.772922854917985
+ 4.772955126464203
+ 4.772987397708426
+ 4.773019668650662
+ 4.773051939290917
+ 4.7730842096292
+ 4.773116479665518
+ 4.77314874939988
+ 4.773181018832291
+ 4.773213287962761
+ 4.773245556791298
+ 4.773277825317908
+ 4.773310093542598
+ 4.773342361465378
+ 4.7733746290862555
+ 4.773406896405236
+ 4.773439163422329
+ 4.773471430137541
+ 4.773503696550883
+ 4.773535962662358
+ 4.773568228471975
+ 4.7736004939797425
+ 4.773632759185668
+ 4.77366502408976
+ 4.773697288692024
+ 4.77372955299247
+ 4.7737618169911045
+ 4.773794080687936
+ 4.77382634408297
+ 4.773858607176217
+ 4.773890869967682
+ 4.773923132457375
+ 4.773955394645302
+ 4.773987656531472
+ 4.77401991811589
+ 4.774052179398567
+ 4.774084440379509
+ 4.774116701058725
+ 4.77414896143622
+ 4.774181221512004
+ 4.7742134812860835
+ 4.774245740758467
+ 4.774277999929162
+ 4.774310258798176
+ 4.774342517365515
+ 4.774374775631189
+ 4.774407033595205
+ 4.77443929125757
+ 4.774471548618293
+ 4.77450380567738
+ 4.77453606243484
+ 4.77456831889068
+ 4.774600575044907
+ 4.77463283089753
+ 4.7746650864485565
+ 4.774697341697992
+ 4.774729596645848
+ 4.77476185129213
+ 4.774794105636844
+ 4.7748263596800005
+ 4.774858613421605
+ 4.774890866861667
+ 4.774923120000193
+ 4.774955372837192
+ 4.7749876253726695
+ 4.775019877606635
+ 4.775052129539095
+ 4.775084381170058
+ 4.77511663249953
+ 4.77514888352752
+ 4.775181134254036
+ 4.775213384679085
+ 4.775245634802675
+ 4.775277884624813
+ 4.775310134145508
+ 4.775342383364767
+ 4.775374632282596
+ 4.775406880899005
+ 4.775439129214
+ 4.77547137722759
+ 4.77550362493978
+ 4.7755358723505825
+ 4.775568119460001
+ 4.775600366268044
+ 4.77563261277472
+ 4.775664858980036
+ 4.775697104884
+ 4.77572935048662
+ 4.775761595787903
+ 4.7757938407878555
+ 4.7758260854864885
+ 4.775858329883806
+ 4.775890573979818
+ 4.775922817774531
+ 4.775955061267953
+ 4.775987304460092
+ 4.776019547350955
+ 4.776051789940549
+ 4.776084032228884
+ 4.776116274215965
+ 4.776148515901801
+ 4.7761807572864
+ 4.776212998369769
+ 4.776245239151916
+ 4.7762774796328475
+ 4.7763097198125735
+ 4.776341959691099
+ 4.776374199268433
+ 4.7764064385445835
+ 4.776438677519557
+ 4.776470916193362
+ 4.776503154566005
+ 4.776535392637495
+ 4.77656763040784
+ 4.776599867877046
+ 4.776632105045121
+ 4.776664341912073
+ 4.77669657847791
+ 4.776728814742641
+ 4.776761050706269
+ 4.7767932863688065
+ 4.7768255217302595
+ 4.776857756790633
+ 4.776889991549939
+ 4.776922226008183
+ 4.7769544601653715
+ 4.776986694021515
+ 4.777018927576617
+ 4.77705116083069
+ 4.777083393783739
+ 4.777115626435771
+ 4.777147858786795
+ 4.7771800908368185
+ 4.777212322585848
+ 4.777244554033892
+ 4.777276785180958
+ 4.777309016027054
+ 4.7773412465721865
+ 4.777373476816365
+ 4.777405706759596
+ 4.7774379364018875
+ 4.777470165743245
+ 4.77750239478368
+ 4.777534623523197
+ 4.7775668519618035
+ 4.77759908009951
+ 4.777631307936322
+ 4.777663535472247
+ 4.777695762707294
+ 4.77772798964147
+ 4.777760216274781
+ 4.777792442607238
+ 4.7778246686388455
+ 4.777856894369612
+ 4.7778891197995454
+ 4.777921344928655
+ 4.777953569756945
+ 4.777985794284425
+ 4.778018018511102
+ 4.7780502424369855
+ 4.778082466062081
+ 4.778114689386396
+ 4.77814691240994
+ 4.77817913513272
+ 4.778211357554742
+ 4.7782435796760145
+ 4.778275801496545
+ 4.778308023016343
+ 4.778340244235413
+ 4.778372465153765
+ 4.778404685771407
+ 4.778436906088344
+ 4.778469126104586
+ 4.778501345820138
+ 4.778533565235011
+ 4.77856578434921
+ 4.778598003162744
+ 4.77863022167562
+ 4.778662439887846
+ 4.77869465779943
+ 4.778726875410378
+ 4.778759092720699
+ 4.7787913097304
+ 4.7788235264394885
+ 4.778855742847973
+ 4.778887958955861
+ 4.778920174763159
+ 4.7789523902698745
+ 4.778984605476017
+ 4.779016820381594
+ 4.779049034986611
+ 4.7790812492910755
+ 4.779113463294998
+ 4.779145676998383
+ 4.779177890401242
+ 4.779210103503578
+ 4.779242316305401
+ 4.779274528806719
+ 4.779306741007539
+ 4.779338952907869
+ 4.779371164507716
+ 4.779403375807088
+ 4.779435586805992
+ 4.779467797504435
+ 4.779500007902428
+ 4.779532217999974
+ 4.779564427797085
+ 4.779596637293765
+ 4.779628846490024
+ 4.779661055385867
+ 4.779693263981304
+ 4.779725472276343
+ 4.779757680270991
+ 4.779789887965253
+ 4.7798220953591395
+ 4.779854302452658
+ 4.779886509245815
+ 4.779918715738618
+ 4.779950921931075
+ 4.779983127823195
+ 4.780015333414984
+ 4.780047538706449
+ 4.780079743697599
+ 4.780111948388441
+ 4.780144152778983
+ 4.780176356869233
+ 4.7802085606591955
+ 4.780240764148883
+ 4.7802729673383
+ 4.780305170227455
+ 4.780337372816355
+ 4.7803695751050075
+ 4.780401777093421
+ 4.780433978781602
+ 4.780466180169559
+ 4.7804983812573
+ 4.780530582044831
+ 4.7805627825321615
+ 4.780594982719297
+ 4.7806271826062465
+ 4.780659382193018
+ 4.780691581479618
+ 4.7807237804660545
+ 4.780755979152335
+ 4.780788177538467
+ 4.780820375624458
+ 4.780852573410317
+ 4.78088477089605
+ 4.780916968081664
+ 4.7809491649671685
+ 4.780981361552572
+ 4.781013557837878
+ 4.781045753823096
+ 4.781077949508236
+ 4.781110144893303
+ 4.781142339978304
+ 4.781174534763249
+ 4.781206729248145
+ 4.781238923432997
+ 4.781271117317815
+ 4.781303310902607
+ 4.781335504187379
+ 4.781367697172141
+ 4.781399889856897
+ 4.781432082241657
+ 4.781464274326429
+ 4.781496466111219
+ 4.781528657596034
+ 4.7815608487808845
+ 4.7815930396657755
+ 4.781625230250717
+ 4.781657420535714
+ 4.781689610520775
+ 4.781721800205909
+ 4.781753989591121
+ 4.781786178676421
+ 4.781818367461814
+ 4.781850555947311
+ 4.781882744132917
+ 4.78191493201864
+ 4.781947119604488
+ 4.781979306890468
+ 4.782011493876589
+ 4.782043680562857
+ 4.782075866949281
+ 4.782108053035866
+ 4.782140238822623
+ 4.782172424309557
+ 4.782204609496677
+ 4.782236794383991
+ 4.782268978971504
+ 4.782301163259226
+ 4.782333347247164
+ 4.782365530935326
+ 4.782397714323717
+ 4.782429897412349
+ 4.782462080201226
+ 4.782494262690356
+ 4.782526444879749
+ 4.7825586267694105
+ 4.782590808359347
+ 4.7826229896495684
+ 4.782655170640083
+ 4.782687351330894
+ 4.782719531722014
+ 4.7827517118134475
+ 4.782783891605203
+ 4.782816071097288
+ 4.78284825028971
+ 4.782880429182477
+ 4.782912607775596
+ 4.782944786069074
+ 4.782976964062921
+ 4.783009141757142
+ 4.783041319151746
+ 4.78307349624674
+ 4.7831056730421295
+ 4.783137849537926
+ 4.783170025734136
+ 4.783202201630766
+ 4.783234377227824
+ 4.783266552525317
+ 4.7832987275232535
+ 4.78333090222164
+ 4.7833630766204855
+ 4.7833952507197965
+ 4.783427424519581
+ 4.783459598019847
+ 4.7834917712206
+ 4.783523944121851
+ 4.783556116723603
+ 4.783588289025868
+ 4.783620461028651
+ 4.783652632731961
+ 4.783684804135805
+ 4.78371697524019
+ 4.783749146045125
+ 4.783781316550616
+ 4.78381348675667
+ 4.783845656663297
+ 4.783877826270503
+ 4.783909995578297
+ 4.7839421645866835
+ 4.783974333295673
+ 4.784006501705272
+ 4.784038669815488
+ 4.784070837626329
+ 4.784103005137801
+ 4.784135172349915
+ 4.784167339262675
+ 4.7841995058760896
+ 4.784231672190167
+ 4.7842638382049145
+ 4.78429600392034
+ 4.78432816933645
+ 4.784360334453253
+ 4.784392499270756
+ 4.784424663788967
+ 4.784456828007894
+ 4.784488991927543
+ 4.784521155547924
+ 4.784553318869042
+ 4.784585481890906
+ 4.7846176446135225
+ 4.7846498070369
+ 4.7846819691610465
+ 4.784714130985968
+ 4.784746292511674
+ 4.784778453738171
+ 4.7848106146654645
+ 4.784842775293566
+ 4.78487493562248
+ 4.7849070956522155
+ 4.784939255382781
+ 4.784971414814181
+ 4.785003573946427
+ 4.785035732779522
+ 4.785067891313478
+ 4.785100049548299
+ 4.785132207483994
+ 4.785164365120572
+ 4.785196522458039
+ 4.785228679496401
+ 4.785260836235669
+ 4.785292992675848
+ 4.785325148816947
+ 4.785357304658973
+ 4.785389460201933
+ 4.785421615445834
+ 4.785453770390686
+ 4.785485925036496
+ 4.785518079383269
+ 4.785550233431014
+ 4.78558238717974
+ 4.785614540629453
+ 4.78564669378016
+ 4.78567884663187
+ 4.78571099918459
+ 4.785743151438328
+ 4.78577530339309
+ 4.785807455048885
+ 4.785839606405721
+ 4.785871757463604
+ 4.785903908222542
+ 4.785936058682544
+ 4.785968208843615
+ 4.786000358705764
+ 4.786032508268999
+ 4.786064657533326
+ 4.786096806498754
+ 4.786128955165291
+ 4.786161103532942
+ 4.786193251601716
+ 4.786225399371622
+ 4.786257546842666
+ 4.786289694014855
+ 4.786321840888198
+ 4.786353987462702
+ 4.786386133738374
+ 4.786418279715222
+ 4.7864504253932525
+ 4.786482570772475
+ 4.786514715852896
+ 4.786546860634523
+ 4.786579005117364
+ 4.786611149301425
+ 4.786643293186715
+ 4.786675436773242
+ 4.7867075800610115
+ 4.786739723050034
+ 4.786771865740314
+ 4.786804008131861
+ 4.786836150224682
+ 4.7868682920187835
+ 4.786900433514175
+ 4.786932574710862
+ 4.786964715608853
+ 4.786996856208156
+ 4.787028996508779
+ 4.787061136510728
+ 4.787093276214011
+ 4.787125415618636
+ 4.78715755472461
+ 4.787189693531941
+ 4.787221832040636
+ 4.787253970250703
+ 4.787286108162149
+ 4.787318245774983
+ 4.78735038308921
+ 4.78738252010484
+ 4.78741465682188
+ 4.787446793240336
+ 4.7874789293602165
+ 4.78751106518153
+ 4.787543200704281
+ 4.787575335928481
+ 4.787607470854135
+ 4.787639605481251
+ 4.787671739809838
+ 4.7877038738399005
+ 4.787736007571449
+ 4.78776814100449
+ 4.78780027413903
+ 4.787832406975078
+ 4.787864539512641
+ 4.787896671751725
+ 4.787928803692341
+ 4.787960935334493
+ 4.78799306667819
+ 4.78802519772344
+ 4.78805732847025
+ 4.788089458918628
+ 4.78812158906858
+ 4.788153718920116
+ 4.7881858484732405
+ 4.788217977727964
+ 4.788250106684291
+ 4.7882822353422325
+ 4.788314363701793
+ 4.788346491762982
+ 4.7883786195258065
+ 4.788410746990274
+ 4.78844287415639
+ 4.788475001024165
+ 4.788507127593605
+ 4.788539253864719
+ 4.788571379837512
+ 4.788603505511992
+ 4.78863563088817
+ 4.78866775596605
+ 4.78869988074564
+ 4.788732005226947
+ 4.788764129409982
+ 4.788796253294749
+ 4.788828376881256
+ 4.788860500169511
+ 4.788892623159522
+ 4.788924745851296
+ 4.788956868244839
+ 4.788988990340163
+ 4.78902111213727
+ 4.789053233636172
+ 4.789085354836874
+ 4.789117475739384
+ 4.7891495963437105
+ 4.789181716649859
+ 4.789213836657838
+ 4.7892459563676555
+ 4.78927807577932
+ 4.7893101948928365
+ 4.789342313708214
+ 4.789374432225459
+ 4.789406550444581
+ 4.789438668365586
+ 4.789470785988481
+ 4.789502903313276
+ 4.789535020339975
+ 4.789567137068588
+ 4.789599253499122
+ 4.789631369631584
+ 4.789663485465982
+ 4.789695601002324
+ 4.789727716240615
+ 4.7897598311808665
+ 4.789791945823084
+ 4.789824060167273
+ 4.789856174213444
+ 4.789888287961603
+ 4.7899204014117585
+ 4.789952514563917
+ 4.789984627418086
+ 4.790016739974274
+ 4.790048852232489
+ 4.790080964192736
+ 4.790113075855024
+ 4.79014518721936
+ 4.7901772982857524
+ 4.790209409054209
+ 4.790241519524736
+ 4.790273629697341
+ 4.790305739572033
+ 4.790337849148817
+ 4.7903699584277035
+ 4.790402067408697
+ 4.790434176091807
+ 4.7904662844770405
+ 4.790498392564406
+ 4.790530500353909
+ 4.790562607845557
+ 4.79059471503936
+ 4.790626821935324
+ 4.790658928533456
+ 4.790691034833763
+ 4.7907231408362545
+ 4.790755246540938
+ 4.790787351947818
+ 4.790819457056904
+ 4.790851561868205
+ 4.790883666381726
+ 4.790915770597476
+ 4.790947874515461
+ 4.79097997813569
+ 4.791012081458169
+ 4.791044184482908
+ 4.791076287209911
+ 4.79110838963919
+ 4.791140491770748
+ 4.791172593604595
+ 4.791204695140738
+ 4.791236796379184
+ 4.791268897319942
+ 4.791300997963018
+ 4.791333098308418
+ 4.791365198356154
+ 4.7913972981062285
+ 4.791429397558653
+ 4.791461496713432
+ 4.791493595570576
+ 4.791525694130089
+ 4.791557792391981
+ 4.79158989035626
+ 4.791621988022931
+ 4.791654085392003
+ 4.791686182463484
+ 4.79171827923738
+ 4.791750375713699
+ 4.791782471892449
+ 4.791814567773638
+ 4.791846663357273
+ 4.791878758643359
+ 4.791910853631907
+ 4.791942948322923
+ 4.791975042716415
+ 4.792007136812391
+ 4.792039230610856
+ 4.792071324111819
+ 4.792103417315289
+ 4.7921355102212715
+ 4.792167602829774
+ 4.792199695140805
+ 4.792231787154371
+ 4.792263878870481
+ 4.792295970289141
+ 4.79232806141036
+ 4.792360152234143
+ 4.792392242760499
+ 4.7924243329894365
+ 4.792456422920961
+ 4.7924885125550825
+ 4.792520601891805
+ 4.792552690931139
+ 4.792584779673089
+ 4.792616868117666
+ 4.792648956264876
+ 4.792681044114726
+ 4.792713131667224
+ 4.792745218922376
+ 4.7927773058801915
+ 4.792809392540677
+ 4.79284147890384
+ 4.79287356496969
+ 4.792905650738231
+ 4.792937736209472
+ 4.792969821383421
+ 4.793001906260084
+ 4.793033990839471
+ 4.793066075121588
+ 4.793098159106441
+ 4.7931302427940405
+ 4.793162326184392
+ 4.793194409277504
+ 4.793226492073382
+ 4.793258574572035
+ 4.793290656773472
+ 4.7933227386776975
+ 4.793354820284721
+ 4.793386901594548
+ 4.7934189826071885
+ 4.793451063322648
+ 4.793483143740935
+ 4.793515223862056
+ 4.793547303686021
+ 4.793579383212834
+ 4.793611462442504
+ 4.7936435413750385
+ 4.793675620010446
+ 4.793707698348732
+ 4.793739776389907
+ 4.793771854133974
+ 4.793803931580943
+ 4.793836008730822
+ 4.793868085583618
+ 4.793900162139338
+ 4.79393223839799
+ 4.793964314359581
+ 4.793996390024119
+ 4.7940284653916105
+ 4.7940605404620635
+ 4.794092615235487
+ 4.794124689711886
+ 4.794156763891269
+ 4.794188837773644
+ 4.794220911359017
+ 4.794252984647398
+ 4.794285057638792
+ 4.794317130333207
+ 4.7943492027306505
+ 4.7943812748311325
+ 4.794413346634656
+ 4.794445418141231
+ 4.794477489350864
+ 4.794509560263565
+ 4.794541630879339
+ 4.7945737011981935
+ 4.794605771220136
+ 4.7946378409451755
+ 4.794669910373318
+ 4.7947019795045716
+ 4.794734048338944
+ 4.794766116876441
+ 4.794798185117073
+ 4.794830253060844
+ 4.794862320707764
+ 4.794894388057839
+ 4.794926455111078
+ 4.794958521867487
+ 4.794990588327075
+ 4.7950226544898475
+ 4.795054720355814
+ 4.795086785924979
+ 4.795118851197353
+ 4.795150916172942
+ 4.795182980851754
+ 4.795215045233796
+ 4.795247109319076
+ 4.795279173107601
+ 4.795311236599378
+ 4.795343299794416
+ 4.795375362692721
+ 4.795407425294301
+ 4.795439487599164
+ 4.795471549607315
+ 4.7955036113187655
+ 4.79553567273352
+ 4.795567733851586
+ 4.795599794672972
+ 4.795631855197685
+ 4.795663915425733
+ 4.795695975357123
+ 4.795728034991862
+ 4.7957600943299585
+ 4.795792153371419
+ 4.795824212116251
+ 4.795856270564464
+ 4.795888328716061
+ 4.795920386571054
+ 4.795952444129448
+ 4.795984501391251
+ 4.796016558356471
+ 4.796048615025115
+ 4.79608067139719
+ 4.796112727472704
+ 4.7961447832516635
+ 4.796176838734078
+ 4.796208893919953
+ 4.796240948809297
+ 4.796273003402116
+ 4.79630505769842
+ 4.796337111698214
+ 4.796369165401507
+ 4.796401218808305
+ 4.796433271918618
+ 4.79646532473245
+ 4.796497377249811
+ 4.7965294294707075
+ 4.7965614813951465
+ 4.796593533023136
+ 4.796625584354685
+ 4.796657635389798
+ 4.7966896861284845
+ 4.796721736570751
+ 4.7967537867166055
+ 4.7967858365660545
+ 4.796817886119106
+ 4.796849935375769
+ 4.796881984336048
+ 4.796914032999952
+ 4.79694608136749
+ 4.796978129438666
+ 4.797010177213489
+ 4.797042224691968
+ 4.797074271874109
+ 4.797106318759919
+ 4.797138365349407
+ 4.797170411642577
+ 4.797202457639441
+ 4.797234503340004
+ 4.797266548744274
+ 4.797298593852258
+ 4.797330638663963
+ 4.797362683179397
+ 4.797394727398568
+ 4.797426771321483
+ 4.797458814948149
+ 4.797490858278574
+ 4.797522901312765
+ 4.79755494405073
+ 4.797586986492475
+ 4.797619028638009
+ 4.797651070487339
+ 4.797683112040473
+ 4.797715153297418
+ 4.79774719425818
+ 4.797779234922769
+ 4.79781127529119
+ 4.797843315363452
+ 4.797875355139562
+ 4.797907394619528
+ 4.797939433803356
+ 4.797971472691054
+ 4.79800351128263
+ 4.798035549578091
+ 4.798067587577445
+ 4.798099625280699
+ 4.798131662687859
+ 4.798163699798935
+ 4.798195736613934
+ 4.798227773132861
+ 4.798259809355726
+ 4.798291845282536
+ 4.798323880913298
+ 4.798355916248018
+ 4.798387951286705
+ 4.7984199860293675
+ 4.79845202047601
+ 4.798484054626643
+ 4.798516088481272
+ 4.7985481220399056
+ 4.79858015530255
+ 4.798612188269212
+ 4.798644220939902
+ 4.798676253314625
+ 4.7987082853933885
+ 4.7987403171762
+ 4.79877234866307
+ 4.798804379854
+ 4.798836410749003
+ 4.798868441348084
+ 4.79890047165125
+ 4.798932501658509
+ 4.798964531369869
+ 4.798996560785335
+ 4.7990285899049185
+ 4.799060618728624
+ 4.799092647256459
+ 4.799124675488431
+ 4.79915670342455
+ 4.799188731064819
+ 4.799220758409249
+ 4.7992527854578455
+ 4.799284812210617
+ 4.79931683866757
+ 4.799348864828714
+ 4.799380890694055
+ 4.799412916263598
+ 4.799444941537353
+ 4.7994769665153285
+ 4.79950899119753
+ 4.799541015583965
+ 4.799573039674642
+ 4.799605063469566
+ 4.799637086968749
+ 4.799669110172193
+ 4.7997011330799095
+ 4.7997331556919045
+ 4.799765178008184
+ 4.799797200028758
+ 4.799829221753631
+ 4.799861243182814
+ 4.799893264316312
+ 4.799925285154132
+ 4.7999573056962825
+ 4.7999893259427715
+ 4.800021345893605
+ 4.8000533655487905
+ 4.800085384908337
+ 4.80011740397225
+ 4.800149422740538
+ 4.800181441213208
+ 4.8002134593902674
+ 4.800245477271725
+ 4.800277494857585
+ 4.800309512147858
+ 4.800341529142551
+ 4.800373545841668
+ 4.800405562245221
+ 4.800437578353216
+ 4.8004695941656585
+ 4.800501609682557
+ 4.800533624903919
+ 4.800565639829753
+ 4.8005976544600655
+ 4.800629668794863
+ 4.8006616828341535
+ 4.8006936965779445
+ 4.800725710026245
+ 4.800757723179061
+ 4.800789736036398
+ 4.800821748598266
+ 4.800853760864673
+ 4.800885772835623
+ 4.800917784511126
+ 4.8009497958911895
+ 4.8009818069758206
+ 4.801013817765026
+ 4.801045828258813
+ 4.801077838457189
+ 4.801109848360163
+ 4.801141857967741
+ 4.801173867279929
+ 4.801205876296738
+ 4.801237885018173
+ 4.801269893444242
+ 4.801301901574951
+ 4.801333909410311
+ 4.801365916950326
+ 4.801397924195003
+ 4.801429931144352
+ 4.801461937798379
+ 4.801493944157093
+ 4.801525950220498
+ 4.801557955988605
+ 4.801589961461419
+ 4.8016219666389475
+ 4.801653971521199
+ 4.801685976108181
+ 4.8017179803999
+ 4.8017499843963645
+ 4.801781988097581
+ 4.801813991503556
+ 4.801845994614299
+ 4.801877997429815
+ 4.801909999950114
+ 4.801942002175203
+ 4.8019740041050865
+ 4.802006005739775
+ 4.8020380070792745
+ 4.802070008123593
+ 4.802102008872737
+ 4.802134009326716
+ 4.802166009485534
+ 4.802198009349201
+ 4.802230008917724
+ 4.802262008191109
+ 4.802294007169365
+ 4.8023260058525
+ 4.802358004240519
+ 4.80239000233343
+ 4.802422000131243
+ 4.802453997633961
+ 4.802485994841596
+ 4.802517991754152
+ 4.802549988371637
+ 4.802581984694059
+ 4.802613980721426
+ 4.802645976453744
+ 4.802677971891022
+ 4.802709967033265
+ 4.802741961880483
+ 4.802773956432683
+ 4.80280595068987
+ 4.802837944652053
+ 4.80286993831924
+ 4.802901931691437
+ 4.802933924768654
+ 4.802965917550894
+ 4.80299791003817
+ 4.803029902230484
+ 4.803061894127845
+ 4.803093885730262
+ 4.803125877037742
+ 4.803157868050291
+ 4.803189858767918
+ 4.803221849190629
+ 4.803253839318432
+ 4.803285829151335
+ 4.803317818689344
+ 4.803349807932467
+ 4.803381796880711
+ 4.803413785534085
+ 4.8034457738925935
+ 4.803477761956247
+ 4.803509749725051
+ 4.803541737199014
+ 4.803573724378142
+ 4.803605711262443
+ 4.803637697851925
+ 4.803669684146595
+ 4.803701670146459
+ 4.803733655851527
+ 4.803765641261804
+ 4.803797626377299
+ 4.803829611198018
+ 4.80386159572397
+ 4.803893579955161
+ 4.803925563891599
+ 4.803957547533291
+ 4.803989530880244
+ 4.804021513932467
+ 4.804053496689965
+ 4.804085479152748
+ 4.804117461320822
+ 4.804149443194193
+ 4.804181424772872
+ 4.804213406056863
+ 4.804245387046174
+ 4.804277367740814
+ 4.804309348140788
+ 4.804341328246106
+ 4.804373308056774
+ 4.8044052875727985
+ 4.804437266794188
+ 4.8044692457209495
+ 4.804501224353091
+ 4.804533202690619
+ 4.804565180733541
+ 4.804597158481866
+ 4.804629135935598
+ 4.804661113094747
+ 4.80469308995932
+ 4.804725066529325
+ 4.804757042804767
+ 4.804789018785655
+ 4.804820994471997
+ 4.8048529698637985
+ 4.804884944961068
+ 4.804916919763813
+ 4.804948894272041
+ 4.8049808684857584
+ 4.805012842404973
+ 4.805044816029693
+ 4.8050767893599255
+ 4.805108762395676
+ 4.805140735136954
+ 4.805172707583766
+ 4.8052046797361205
+ 4.805236651594022
+ 4.80526862315748
+ 4.8053005944265035
+ 4.8053325654010965
+ 4.805364536081268
+ 4.805396506467026
+ 4.805428476558375
+ 4.805460446355327
+ 4.805492415857884
+ 4.805524385066057
+ 4.8055563539798545
+ 4.80558832259928
+ 4.8056202909243435
+ 4.80565225895505
+ 4.80568422669141
+ 4.805716194133428
+ 4.805748161281114
+ 4.805780128134472
+ 4.805812094693514
+ 4.8058440609582425
+ 4.805876026928668
+ 4.805907992604796
+ 4.805939957986635
+ 4.8059719230741935
+ 4.806003887867476
+ 4.806035852366491
+ 4.806067816571248
+ 4.80609978048175
+ 4.806131744098009
+ 4.806163707420029
+ 4.806195670447819
+ 4.806227633181385
+ 4.806259595620737
+ 4.806291557765879
+ 4.806323519616821
+ 4.8063554811735685
+ 4.80638744243613
+ 4.806419403404513
+ 4.806451364078724
+ 4.80648332445877
+ 4.80651528454466
+ 4.8065472443364
+ 4.806579203833998
+ 4.806611163037461
+ 4.806643121946796
+ 4.8066750805620115
+ 4.806707038883113
+ 4.80673899691011
+ 4.806770954643008
+ 4.8068029120818165
+ 4.806834869226541
+ 4.80686682607719
+ 4.806898782633769
+ 4.806930738896287
+ 4.80696269486475
+ 4.806994650539167
+ 4.807026605919545
+ 4.807058561005891
+ 4.807090515798212
+ 4.807122470296515
+ 4.807154424500809
+ 4.8071863784110995
+ 4.807218332027395
+ 4.807250285349703
+ 4.807282238378029
+ 4.807314191112384
+ 4.8073461435527705
+ 4.807378095699199
+ 4.807410047551677
+ 4.807441999110211
+ 4.807473950374807
+ 4.8075059013454755
+ 4.807537852022222
+ 4.807569802405053
+ 4.8076017524939765
+ 4.807633702289
+ 4.807665651790131
+ 4.807697600997377
+ 4.8077295499107455
+ 4.807761498530244
+ 4.807793446855877
+ 4.807825394887655
+ 4.807857342625586
+ 4.807889290069674
+ 4.807921237219929
+ 4.807953184076357
+ 4.807985130638966
+ 4.808017076907763
+ 4.808049022882756
+ 4.808080968563951
+ 4.808112913951357
+ 4.80814485904498
+ 4.808176803844828
+ 4.808208748350907
+ 4.808240692563226
+ 4.808272636481791
+ 4.808304580106612
+ 4.808336523437693
+ 4.808368466475043
+ 4.808400409218669
+ 4.808432351668579
+ 4.80846429382478
+ 4.808496235687279
+ 4.808528177256083
+ 4.8085601185312
+ 4.808592059512637
+ 4.8086240002004015
+ 4.8086559405945
+ 4.808687880694941
+ 4.808719820501732
+ 4.8087517600148795
+ 4.8087836992343895
+ 4.808815638160272
+ 4.808847576792534
+ 4.808879515131181
+ 4.808911453176222
+ 4.808943390927664
+ 4.808975328385514
+ 4.809007265549778
+ 4.809039202420466
+ 4.809071138997583
+ 4.809103075281137
+ 4.809135011271136
+ 4.809166946967588
+ 4.809198882370498
+ 4.809230817479876
+ 4.8092627522957265
+ 4.809294686818059
+ 4.80932662104688
+ 4.809358554982197
+ 4.809390488624016
+ 4.809422421972347
+ 4.809454355027196
+ 4.80948628778857
+ 4.809518220256476
+ 4.809550152430922
+ 4.809582084311915
+ 4.809614015899462
+ 4.809645947193571
+ 4.8096778781942495
+ 4.809709808901505
+ 4.809741739315343
+ 4.8097736694357724
+ 4.809805599262801
+ 4.809837528796435
+ 4.809869458036681
+ 4.809901386983548
+ 4.809933315637044
+ 4.809965243997173
+ 4.8099971720639445
+ 4.810029099837366
+ 4.8100610273174444
+ 4.810092954504187
+ 4.8101248813976
+ 4.810156807997694
+ 4.810188734304473
+ 4.810220660317946
+ 4.810252586038119
+ 4.810284511465
+ 4.8103164365985975
+ 4.810348361438917
+ 4.810380285985967
+ 4.810412210239754
+ 4.810444134200286
+ 4.81047605786757
+ 4.810507981241613
+ 4.810539904322423
+ 4.810571827110006
+ 4.810603749604371
+ 4.8106356718055245
+ 4.810667593713473
+ 4.810699515328225
+ 4.810731436649788
+ 4.8107633576781685
+ 4.810795278413375
+ 4.810827198855413
+ 4.810859119004291
+ 4.810891038860015
+ 4.810922958422594
+ 4.810954877692034
+ 4.810986796668344
+ 4.81101871535153
+ 4.8110506337415995
+ 4.81108255183856
+ 4.811114469642418
+ 4.811146387153181
+ 4.811178304370859
+ 4.811210221295456
+ 4.811242137926979
+ 4.811274054265438
+ 4.811305970310839
+ 4.811337886063189
+ 4.811369801522495
+ 4.811401716688766
+ 4.811433631562007
+ 4.8114655461422275
+ 4.811497460429433
+ 4.811529374423632
+ 4.811561288124832
+ 4.811593201533039
+ 4.811625114648262
+ 4.811657027470505
+ 4.8116889399997795
+ 4.811720852236091
+ 4.811752764179446
+ 4.811784675829853
+ 4.811816587187319
+ 4.81184849825185
+ 4.811880409023455
+ 4.811912319502141
+ 4.8119442296879145
+ 4.811976139580783
+ 4.812008049180755
+ 4.812039958487837
+ 4.812071867502035
+ 4.812103776223358
+ 4.812135684651814
+ 4.812167592787407
+ 4.812199500630147
+ 4.812231408180042
+ 4.8122633154370975
+ 4.81229522240132
+ 4.8123271290727185
+ 4.8123590354513
+ 4.812390941537073
+ 4.812422847330041
+ 4.812454752830216
+ 4.812486658037602
+ 4.812518562952207
+ 4.812550467574039
+ 4.812582371903105
+ 4.812614275939412
+ 4.812646179682968
+ 4.812678083133779
+ 4.812709986291853
+ 4.8127418891571985
+ 4.81277379172982
+ 4.812805694009727
+ 4.812837595996927
+ 4.812869497691426
+ 4.8129013990932314
+ 4.812933300202352
+ 4.812965201018793
+ 4.812997101542563
+ 4.813029001773669
+ 4.8130609017121175
+ 4.813092801357918
+ 4.813124700711075
+ 4.813156599771597
+ 4.813188498539493
+ 4.813220397014767
+ 4.8132522951974295
+ 4.813284193087485
+ 4.813316090684943
+ 4.8133479879898085
+ 4.8133798850020915
+ 4.813411781721797
+ 4.813443678148934
+ 4.813475574283507
+ 4.813507470125527
+ 4.813539365674999
+ 4.813571260931932
+ 4.813603155896331
+ 4.813635050568204
+ 4.813666944947559
+ 4.813698839034403
+ 4.813730732828744
+ 4.813762626330587
+ 4.813794519539941
+ 4.813826412456815
+ 4.8138583050812125
+ 4.813890197413143
+ 4.813922089452613
+ 4.813953981199631
+ 4.813985872654203
+ 4.814017763816336
+ 4.81404965468604
+ 4.814081545263319
+ 4.814113435548181
+ 4.814145325540635
+ 4.8141772152406865
+ 4.814209104648344
+ 4.8142409937636135
+ 4.814272882586503
+ 4.81430477111702
+ 4.814336659355172
+ 4.814368547300965
+ 4.814400434954408
+ 4.814432322315507
+ 4.814464209384268
+ 4.814496096160701
+ 4.814527982644813
+ 4.814559868836609
+ 4.814591754736099
+ 4.814623640343288
+ 4.814655525658185
+ 4.814687410680796
+ 4.814719295411129
+ 4.814751179849191
+ 4.81478306399499
+ 4.814814947848531
+ 4.814846831409825
+ 4.814878714678875
+ 4.814910597655692
+ 4.814942480340282
+ 4.8149743627326504
+ 4.815006244832806
+ 4.815038126640757
+ 4.81507000815651
+ 4.815101889380072
+ 4.81513377031145
+ 4.815165650950651
+ 4.815197531297684
+ 4.815229411352554
+ 4.81526129111527
+ 4.815293170585839
+ 4.815325049764268
+ 4.815356928650563
+ 4.815388807244733
+ 4.815420685546785
+ 4.815452563556725
+ 4.815484441274562
+ 4.815516318700303
+ 4.815548195833954
+ 4.815580072675523
+ 4.815611949225018
+ 4.815643825482446
+ 4.815675701447813
+ 4.815707577121127
+ 4.815739452502395
+ 4.815771327591626
+ 4.815803202388825
+ 4.8158350768939995
+ 4.815866951107158
+ 4.815898825028308
+ 4.815930698657454
+ 4.815962571994607
+ 4.815994445039771
+ 4.816026317792956
+ 4.816058190254168
+ 4.816090062423413
+ 4.816121934300701
+ 4.816153805886036
+ 4.816185677179428
+ 4.816217548180883
+ 4.8162494188904095
+ 4.816281289308013
+ 4.816313159433701
+ 4.816345029267482
+ 4.816376898809362
+ 4.816408768059349
+ 4.81644063701745
+ 4.816472505683673
+ 4.816504374058024
+ 4.8165362421405105
+ 4.816568109931141
+ 4.816599977429922
+ 4.81663184463686
+ 4.816663711551962
+ 4.816695578175237
+ 4.816727444506692
+ 4.816759310546333
+ 4.816791176294167
+ 4.816823041750204
+ 4.816854906914447
+ 4.816886771786907
+ 4.81691863636759
+ 4.816950500656502
+ 4.8169823646536525
+ 4.817014228359048
+ 4.817046091772694
+ 4.8170779548946
+ 4.817109817724773
+ 4.8171416802632185
+ 4.817173542509945
+ 4.81720540446496
+ 4.81723726612827
+ 4.817269127499883
+ 4.817300988579806
+ 4.8173328493680465
+ 4.817364709864611
+ 4.817396570069506
+ 4.8174284299827415
+ 4.817460289604322
+ 4.817492148934257
+ 4.81752400797255
+ 4.817555866719213
+ 4.817587725174252
+ 4.817619583337672
+ 4.817651441209481
+ 4.817683298789688
+ 4.8177151560782985
+ 4.817747013075321
+ 4.817778869780761
+ 4.817810726194627
+ 4.817842582316927
+ 4.817874438147666
+ 4.817906293686853
+ 4.817938148934496
+ 4.8179700038906
+ 4.818001858555173
+ 4.818033712928223
+ 4.818065567009756
+ 4.818097420799781
+ 4.818129274298304
+ 4.8181611275053315
+ 4.818192980420872
+ 4.818224833044934
+ 4.818256685377522
+ 4.818288537418645
+ 4.818320389168309
+ 4.818352240626521
+ 4.81838409179329
+ 4.818415942668624
+ 4.818447793252527
+ 4.818479643545008
+ 4.818511493546074
+ 4.818543343255732
+ 4.818575192673991
+ 4.818607041800856
+ 4.818638890636335
+ 4.818670739180435
+ 4.818702587433164
+ 4.8187344353945285
+ 4.818766283064536
+ 4.818798130443194
+ 4.818829977530509
+ 4.818861824326489
+ 4.818893670831141
+ 4.818925517044471
+ 4.818957362966489
+ 4.818989208597199
+ 4.819021053936613
+ 4.819052898984732
+ 4.819084743741567
+ 4.819116588207124
+ 4.819148432381413
+ 4.819180276264437
+ 4.819212119856206
+ 4.819243963156726
+ 4.819275806166005
+ 4.81930764888405
+ 4.819339491310868
+ 4.819371333446467
+ 4.819403175290853
+ 4.819435016844034
+ 4.819466858106018
+ 4.81949869907681
+ 4.8195305397564185
+ 4.819562380144852
+ 4.819594220242116
+ 4.819626060048217
+ 4.819657899563165
+ 4.819689738786964
+ 4.8197215777196245
+ 4.819753416361151
+ 4.819785254711552
+ 4.819817092770836
+ 4.819848930539007
+ 4.819880768016075
+ 4.819912605202045
+ 4.8199444420969275
+ 4.819976278700727
+ 4.820008115013452
+ 4.820039951035107
+ 4.820071786765703
+ 4.820103622205246
+ 4.820135457353742
+ 4.820167292211199
+ 4.820199126777624
+ 4.820230961053024
+ 4.820262795037409
+ 4.820294628730781
+ 4.820326462133153
+ 4.820358295244528
+ 4.820390128064913
+ 4.820421960594319
+ 4.82045379283275
+ 4.820485624780215
+ 4.82051745643672
+ 4.820549287802272
+ 4.820581118876881
+ 4.82061294966055
+ 4.820644780153289
+ 4.820676610355105
+ 4.820708440266005
+ 4.820740269885995
+ 4.820772099215082
+ 4.820803928253277
+ 4.820835757000584
+ 4.820867585457011
+ 4.820899413622564
+ 4.820931241497251
+ 4.820963069081081
+ 4.820994896374059
+ 4.821026723376192
+ 4.821058550087489
+ 4.821090376507957
+ 4.821122202637602
+ 4.821154028476432
+ 4.821185854024454
+ 4.821217679281674
+ 4.821249504248102
+ 4.821281328923742
+ 4.821313153308605
+ 4.821344977402694
+ 4.82137680120602
+ 4.821408624718586
+ 4.821440447940404
+ 4.821472270871478
+ 4.821504093511816
+ 4.821535915861426
+ 4.821567737920314
+ 4.8215995596884875
+ 4.821631381165954
+ 4.82166320235272
+ 4.821695023248795
+ 4.821726843854184
+ 4.821758664168894
+ 4.821790484192934
+ 4.821822303926309
+ 4.821854123369029
+ 4.8218859425210985
+ 4.821917761382526
+ 4.821949579953317
+ 4.821981398233483
+ 4.822013216223026
+ 4.822045033921957
+ 4.822076851330282
+ 4.822108668448007
+ 4.822140485275141
+ 4.82217230181169
+ 4.8222041180576625
+ 4.822235934013063
+ 4.822267749677903
+ 4.8222995650521865
+ 4.822331380135919
+ 4.822363194929112
+ 4.822395009431772
+ 4.822426823643903
+ 4.822458637565516
+ 4.822490451196616
+ 4.822522264537211
+ 4.822554077587307
+ 4.822585890346912
+ 4.822617702816033
+ 4.822649514994678
+ 4.822681326882854
+ 4.822713138480568
+ 4.822744949787825
+ 4.822776760804637
+ 4.822808571531007
+ 4.8228403819669445
+ 4.822872192112455
+ 4.822904001967546
+ 4.8229358115322265
+ 4.822967620806502
+ 4.82299942979038
+ 4.8230312384838685
+ 4.823063046886973
+ 4.8230948549997015
+ 4.823126662822063
+ 4.823158470354062
+ 4.823190277595707
+ 4.823222084547004
+ 4.823253891207963
+ 4.823285697578588
+ 4.823317503658889
+ 4.8233493094488695
+ 4.823381114948541
+ 4.823412920157908
+ 4.823444725076978
+ 4.823476529705759
+ 4.8235083340442575
+ 4.823540138092482
+ 4.823571941850437
+ 4.823603745318133
+ 4.823635548495573
+ 4.823667351382768
+ 4.8236991539797245
+ 4.823730956286448
+ 4.823762758302948
+ 4.823794560029229
+ 4.823826361465301
+ 4.823858162611169
+ 4.823889963466841
+ 4.823921764032324
+ 4.823953564307626
+ 4.823985364292754
+ 4.824017163987714
+ 4.824048963392514
+ 4.82408076250716
+ 4.8241125613316616
+ 4.8241443598660245
+ 4.824176158110256
+ 4.824207956064363
+ 4.824239753728354
+ 4.8242715511022345
+ 4.824303348186013
+ 4.824335144979696
+ 4.824366941483291
+ 4.8243987376968045
+ 4.8244305336202435
+ 4.824462329253617
+ 4.82449412459693
+ 4.824525919650191
+ 4.824557714413408
+ 4.824589508886586
+ 4.824621303069733
+ 4.824653096962857
+ 4.8246848905659645
+ 4.824716683879063
+ 4.824748476902159
+ 4.8247802696352595
+ 4.824812062078374
+ 4.824843854231507
+ 4.824875646094666
+ 4.824907437667861
+ 4.824939228951096
+ 4.824971019944378
+ 4.8250028106477165
+ 4.825034601061118
+ 4.825066391184588
+ 4.825098181018136
+ 4.825129970561768
+ 4.825161759815491
+ 4.825193548779313
+ 4.825225337453239
+ 4.825257125837279
+ 4.82528891393144
+ 4.825320701735728
+ 4.8253524892501485
+ 4.825384276474711
+ 4.825416063409422
+ 4.8254478500542906
+ 4.825479636409321
+ 4.825511422474522
+ 4.8255432082499
+ 4.825574993735463
+ 4.825606778931217
+ 4.82563856383717
+ 4.82567034845333
+ 4.825702132779702
+ 4.825733916816295
+ 4.825765700563116
+ 4.82579748402017
+ 4.825829267187468
+ 4.825861050065014
+ 4.8258928326528165
+ 4.825924614950884
+ 4.82595639695922
+ 4.825988178677834
+ 4.826019960106733
+ 4.826051741245925
+ 4.826083522095416
+ 4.826115302655213
+ 4.826147082925324
+ 4.826178862905755
+ 4.826210642596514
+ 4.826242421997609
+ 4.8262742011090465
+ 4.826305979930832
+ 4.826337758462975
+ 4.8263695367054815
+ 4.8264013146583595
+ 4.826433092321615
+ 4.826464869695257
+ 4.826496646779289
+ 4.8265284235737225
+ 4.8265602000785615
+ 4.826591976293816
+ 4.826623752219491
+ 4.826655527855594
+ 4.826687303202132
+ 4.826719078259113
+ 4.826750853026543
+ 4.826782627504431
+ 4.826814401692783
+ 4.826846175591606
+ 4.826877949200908
+ 4.8269097225206945
+ 4.826941495550973
+ 4.826973268291752
+ 4.827005040743039
+ 4.827036812904839
+ 4.8270685847771615
+ 4.8271003563600114
+ 4.827132127653398
+ 4.827163898657326
+ 4.827195669371805
+ 4.827227439796841
+ 4.827259209932442
+ 4.827290979778613
+ 4.827322749335363
+ 4.827354518602699
+ 4.827386287580629
+ 4.827418056269158
+ 4.827449824668293
+ 4.827481592778044
+ 4.827513360598417
+ 4.827545128129417
+ 4.827576895371053
+ 4.827608662323334
+ 4.827640428986264
+ 4.827672195359851
+ 4.827703961444102
+ 4.827735727239025
+ 4.827767492744627
+ 4.827799257960915
+ 4.827831022887896
+ 4.827862787525577
+ 4.827894551873966
+ 4.827926315933068
+ 4.827958079702893
+ 4.827989843183446
+ 4.828021606374735
+ 4.828053369276768
+ 4.8280851318895515
+ 4.828116894213092
+ 4.8281486562473965
+ 4.828180417992472
+ 4.828212179448329
+ 4.8282439406149695
+ 4.828275701492404
+ 4.82830746208064
+ 4.8283392223796815
+ 4.828370982389538
+ 4.828402742110217
+ 4.828434501541725
+ 4.828466260684069
+ 4.828498019537256
+ 4.828529778101292
+ 4.8285615363761885
+ 4.828593294361947
+ 4.8286250520585785
+ 4.8286568094660876
+ 4.828688566584485
+ 4.828720323413774
+ 4.828752079953962
+ 4.82878383620506
+ 4.828815592167072
+ 4.828847347840005
+ 4.828879103223867
+ 4.828910858318666
+ 4.828942613124409
+ 4.8289743676411
+ 4.82900612186875
+ 4.829037875807364
+ 4.829069629456949
+ 4.829101382817515
+ 4.829133135889066
+ 4.82916488867161
+ 4.829196641165154
+ 4.829228393369706
+ 4.829260145285273
+ 4.829291896911861
+ 4.829323648249479
+ 4.829355399298131
+ 4.829387150057827
+ 4.829418900528575
+ 4.8294506507103785
+ 4.829482400603247
+ 4.8295141502071885
+ 4.829545899522207
+ 4.8295776485483115
+ 4.82960939728551
+ 4.8296411457338095
+ 4.829672893893216
+ 4.829704641763736
+ 4.829736389345378
+ 4.829768136638149
+ 4.829799883642056
+ 4.829831630357106
+ 4.8298633767833055
+ 4.8298951229206635
+ 4.829926868769186
+ 4.82995861432888
+ 4.829990359599751
+ 4.83002210458181
+ 4.830053849275061
+ 4.830085593679512
+ 4.830117337795171
+ 4.830149081622044
+ 4.830180825160139
+ 4.830212568409461
+ 4.830244311370021
+ 4.830276054041822
+ 4.830307796424873
+ 4.8303395385191825
+ 4.830371280324757
+ 4.830403021841601
+ 4.830434763069724
+ 4.8304665040091335
+ 4.830498244659835
+ 4.830529985021837
+ 4.830561725095145
+ 4.830593464879768
+ 4.830625204375713
+ 4.830656943582985
+ 4.830688682501593
+ 4.830720421131545
+ 4.830752159472846
+ 4.830783897525504
+ 4.830815635289525
+ 4.830847372764919
+ 4.83087910995169
+ 4.830910846849847
+ 4.830942583459397
+ 4.830974319780346
+ 4.8310060558127015
+ 4.831037791556471
+ 4.831069527011661
+ 4.831101262178281
+ 4.8311329970563355
+ 4.831164731645833
+ 4.831196465946778
+ 4.831228199959183
+ 4.831259933683049
+ 4.8312916671183865
+ 4.8313234002652035
+ 4.831355133123504
+ 4.831386865693297
+ 4.831418597974589
+ 4.83145032996739
+ 4.831482061671702
+ 4.831513793087535
+ 4.831545524214897
+ 4.831577255053793
+ 4.831608985604232
+ 4.831640715866219
+ 4.8316724458397635
+ 4.83170417552487
+ 4.831735904921549
+ 4.831767634029805
+ 4.831799362849646
+ 4.831831091381079
+ 4.83186281962411
+ 4.831894547578748
+ 4.8319262752449985
+ 4.83195800262287
+ 4.831989729712369
+ 4.832021456513503
+ 4.832053183026278
+ 4.832084909250701
+ 4.8321166351867815
+ 4.832148360834525
+ 4.832180086193938
+ 4.832211811265029
+ 4.8322435360478035
+ 4.8322752605422705
+ 4.832306984748436
+ 4.832338708666306
+ 4.83237043229589
+ 4.832402155637194
+ 4.8324338786902254
+ 4.832465601454989
+ 4.832497323931496
+ 4.832529046119751
+ 4.832560768019761
+ 4.8325924896315335
+ 4.832624210955076
+ 4.832655931990395
+ 4.832687652737499
+ 4.832719373196393
+ 4.832751093367085
+ 4.832782813249583
+ 4.832814532843893
+ 4.832846252150023
+ 4.832877971167979
+ 4.832909689897769
+ 4.8329414083394
+ 4.8329731264928775
+ 4.833004844358212
+ 4.833036561935407
+ 4.833068279224473
+ 4.833099996225413
+ 4.833131712938238
+ 4.833163429362954
+ 4.833195145499566
+ 4.833226861348084
+ 4.833258576908514
+ 4.8332902921808625
+ 4.833322007165136
+ 4.833353721861344
+ 4.8333854362694915
+ 4.833417150389587
+ 4.833448864221636
+ 4.833480577765647
+ 4.833512291021628
+ 4.833544003989584
+ 4.833575716669522
+ 4.83360742906145
+ 4.833639141165375
+ 4.833670852981305
+ 4.833702564509246
+ 4.8337342757492054
+ 4.83376598670119
+ 4.833797697365207
+ 4.833829407741264
+ 4.833861117829367
+ 4.8338928276295245
+ 4.833924537141743
+ 4.8339562463660295
+ 4.8339879553023914
+ 4.834019663950835
+ 4.834051372311368
+ 4.834083080383997
+ 4.834114788168731
+ 4.834146495665575
+ 4.8341782028745355
+ 4.834209909795622
+ 4.83424161642884
+ 4.834273322774197
+ 4.8343050288317
+ 4.834336734601356
+ 4.834368440083173
+ 4.834400145277156
+ 4.834431850183315
+ 4.834463554801655
+ 4.834495259132184
+ 4.834526963174907
+ 4.834558666929835
+ 4.834590370396972
+ 4.834622073576326
+ 4.834653776467904
+ 4.834685479071713
+ 4.83471718138776
+ 4.8347488834160535
+ 4.834780585156599
+ 4.834812286609404
+ 4.834843987774475
+ 4.83487568865182
+ 4.8349073892414465
+ 4.834939089543361
+ 4.83497078955757
+ 4.835002489284081
+ 4.835034188722901
+ 4.835065887874037
+ 4.835097586737496
+ 4.835129285313286
+ 4.835160983601414
+ 4.835192681601886
+ 4.8352243793147105
+ 4.835256076739893
+ 4.835287773877441
+ 4.835319470727362
+ 4.835351167289664
+ 4.8353828635643525
+ 4.835414559551435
+ 4.835446255250919
+ 4.835477950662812
+ 4.835509645787119
+ 4.835541340623849
+ 4.8355730351730095
+ 4.835604729434605
+ 4.835636423408645
+ 4.835668117095137
+ 4.835699810494085
+ 4.835731503605499
+ 4.835763196429385
+ 4.83579488896575
+ 4.835826581214602
+ 4.835858273175947
+ 4.835889964849791
+ 4.8359216562361445
+ 4.8359533473350105
+ 4.8359850381464
+ 4.836016728670318
+ 4.8360484189067705
+ 4.836080108855767
+ 4.8361117985173125
+ 4.836143487891416
+ 4.836175176978083
+ 4.836206865777321
+ 4.836238554289138
+ 4.836270242513541
+ 4.836301930450534
+ 4.836333618100128
+ 4.836365305462328
+ 4.836396992537143
+ 4.836428679324577
+ 4.836460365824639
+ 4.836492052037336
+ 4.836523737962676
+ 4.836555423600664
+ 4.836587108951308
+ 4.836618794014616
+ 4.8366504787905935
+ 4.836682163279248
+ 4.836713847480587
+ 4.836745531394618
+ 4.836777215021347
+ 4.836808898360783
+ 4.83684058141293
+ 4.836872264177797
+ 4.836903946655391
+ 4.836935628845718
+ 4.836967310748787
+ 4.836998992364603
+ 4.837030673693175
+ 4.83706235473451
+ 4.8370940354886125
+ 4.837125715955492
+ 4.837157396135154
+ 4.837189076027607
+ 4.837220755632858
+ 4.837252434950913
+ 4.83728411398178
+ 4.837315792725464
+ 4.837347471181976
+ 4.83737914935132
+ 4.837410827233503
+ 4.837442504828534
+ 4.837474182136419
+ 4.837505859157164
+ 4.837537535890778
+ 4.837569212337268
+ 4.837600888496639
+ 4.8376325643689
+ 4.837664239954057
+ 4.837695915252117
+ 4.837727590263087
+ 4.8377592649869765
+ 4.8377909394237895
+ 4.837822613573534
+ 4.837854287436218
+ 4.837885961011848
+ 4.83791763430043
+ 4.837949307301972
+ 4.837980980016481
+ 4.838012652443965
+ 4.838044324584429
+ 4.838075996437881
+ 4.83810766800433
+ 4.838139339283781
+ 4.83817101027624
+ 4.838202680981716
+ 4.838234351400215
+ 4.838266021531745
+ 4.8382976913763125
+ 4.838329360933925
+ 4.838361030204589
+ 4.8383926991883115
+ 4.8384243678851
+ 4.838456036294962
+ 4.838487704417902
+ 4.838519372253931
+ 4.838551039803054
+ 4.838582707065277
+ 4.838614374040609
+ 4.838646040729055
+ 4.838677707130625
+ 4.838709373245322
+ 4.838741039073158
+ 4.838772704614135
+ 4.838804369868265
+ 4.83883603483555
+ 4.838867699516001
+ 4.838899363909623
+ 4.838931028016424
+ 4.838962691836411
+ 4.838994355369591
+ 4.8390260186159715
+ 4.839057681575556
+ 4.839089344248357
+ 4.839121006634379
+ 4.839152668733628
+ 4.839184330546113
+ 4.839215992071839
+ 4.839247653310815
+ 4.839279314263047
+ 4.839310974928543
+ 4.8393426353073075
+ 4.839374295399351
+ 4.839405955204678
+ 4.839437614723297
+ 4.839469273955215
+ 4.839500932900437
+ 4.8395325915589735
+ 4.839564249930828
+ 4.839595908016011
+ 4.839627565814527
+ 4.839659223326383
+ 4.839690880551588
+ 4.839722537490147
+ 4.839754194142069
+ 4.839785850507359
+ 4.839817506586026
+ 4.839849162378075
+ 4.839880817883515
+ 4.839912473102351
+ 4.839944128034592
+ 4.839975782680244
+ 4.840007437039315
+ 4.84003909111181
+ 4.840070744897738
+ 4.840102398397105
+ 4.84013405160992
+ 4.840165704536187
+ 4.840197357175916
+ 4.840229009529112
+ 4.840260661595782
+ 4.840292313375933
+ 4.840323964869573
+ 4.84035561607671
+ 4.840387266997349
+ 4.8404189176314985
+ 4.840450567979165
+ 4.8404822180403535
+ 4.840513867815075
+ 4.840545517303333
+ 4.8405771665051365
+ 4.840608815420493
+ 4.840640464049407
+ 4.840672112391888
+ 4.840703760447942
+ 4.840735408217577
+ 4.840767055700798
+ 4.840798702897613
+ 4.840830349808031
+ 4.840861996432056
+ 4.840893642769697
+ 4.8409252888209595
+ 4.8409569345858525
+ 4.840988580064382
+ 4.841020225256554
+ 4.841051870162376
+ 4.841083514781857
+ 4.841115159115002
+ 4.841146803161819
+ 4.8411784469223145
+ 4.841210090396496
+ 4.84124173358437
+ 4.841273376485943
+ 4.841305019101225
+ 4.841336661430218
+ 4.841368303472933
+ 4.8413999452293766
+ 4.841431586699555
+ 4.841463227883475
+ 4.841494868781143
+ 4.841526509392567
+ 4.841558149717756
+ 4.841589789756714
+ 4.841621429509449
+ 4.841653068975967
+ 4.841684708156278
+ 4.841716347050387
+ 4.841747985658301
+ 4.841779623980026
+ 4.841811262015571
+ 4.841842899764942
+ 4.841874537228147
+ 4.841906174405191
+ 4.841937811296084
+ 4.84196944790083
+ 4.842001084219439
+ 4.842032720251916
+ 4.842064355998267
+ 4.842095991458502
+ 4.842127626632625
+ 4.842159261520646
+ 4.84219089612257
+ 4.842222530438404
+ 4.842254164468157
+ 4.842285798211834
+ 4.842317431669442
+ 4.842349064840988
+ 4.842380697726481
+ 4.842412330325927
+ 4.842443962639332
+ 4.842475594666704
+ 4.84250722640805
+ 4.842538857863375
+ 4.84257048903269
+ 4.842602119915999
+ 4.8426337505133095
+ 4.842665380824629
+ 4.842697010849965
+ 4.842728640589323
+ 4.842760270042711
+ 4.8427918992101375
+ 4.842823528091605
+ 4.842855156687126
+ 4.842886784996704
+ 4.842918413020347
+ 4.842950040758063
+ 4.842981668209856
+ 4.843013295375736
+ 4.84304492225571
+ 4.843076548849783
+ 4.8431081751579645
+ 4.843139801180259
+ 4.843171426916674
+ 4.843203052367217
+ 4.843234677531896
+ 4.843266302410718
+ 4.843297927003688
+ 4.8433295513108146
+ 4.843361175332104
+ 4.843392799067564
+ 4.8434244225172005
+ 4.843456045681021
+ 4.8434876685590345
+ 4.843519291151245
+ 4.843550913457661
+ 4.843582535478289
+ 4.843614157213137
+ 4.843645778662212
+ 4.843677399825518
+ 4.843709020703066
+ 4.84374064129486
+ 4.843772261600909
+ 4.84380388162122
+ 4.843835501355799
+ 4.843867120804653
+ 4.84389873996779
+ 4.843930358845215
+ 4.843961977436939
+ 4.843993595742964
+ 4.844025213763301
+ 4.844056831497954
+ 4.844088448946931
+ 4.844120066110241
+ 4.844151682987889
+ 4.844183299579882
+ 4.844214915886227
+ 4.844246531906933
+ 4.844278147642004
+ 4.84430976309145
+ 4.844341378255274
+ 4.844372993133487
+ 4.844404607726095
+ 4.844436222033104
+ 4.844467836054521
+ 4.844499449790353
+ 4.844531063240608
+ 4.8445626764052925
+ 4.844594289284414
+ 4.844625901877978
+ 4.844657514185993
+ 4.844689126208467
+ 4.844720737945403
+ 4.844752349396812
+ 4.844783960562698
+ 4.844815571443071
+ 4.8448471820379355
+ 4.8448787923473
+ 4.844910402371171
+ 4.844942012109556
+ 4.84497362156246
+ 4.8450052307298925
+ 4.8450368396118595
+ 4.845068448208367
+ 4.845100056519424
+ 4.845131664545036
+ 4.845163272285211
+ 4.845194879739954
+ 4.845226486909275
+ 4.845258093793178
+ 4.845289700391673
+ 4.845321306704765
+ 4.845352912732461
+ 4.845384518474768
+ 4.845416123931694
+ 4.845447729103245
+ 4.845479333989429
+ 4.845510938590253
+ 4.845542542905722
+ 4.845574146935845
+ 4.845605750680629
+ 4.84563735414008
+ 4.845668957314205
+ 4.845700560203011
+ 4.845732162806505
+ 4.845763765124696
+ 4.845795367157588
+ 4.84582696890519
+ 4.845858570367508
+ 4.84589017154455
+ 4.845921772436321
+ 4.845953373042829
+ 4.845984973364083
+ 4.846016573400087
+ 4.84604817315085
+ 4.8460797726163785
+ 4.8461113717966775
+ 4.846142970691758
+ 4.846174569301622
+ 4.846206167626281
+ 4.846237765665741
+ 4.8462693634200065
+ 4.846300960889087
+ 4.846332558072988
+ 4.846364154971718
+ 4.846395751585282
+ 4.846427347913689
+ 4.846458943956945
+ 4.846490539715057
+ 4.846522135188032
+ 4.846553730375876
+ 4.846585325278598
+ 4.846616919896204
+ 4.8466485142287015
+ 4.846680108276096
+ 4.846711702038395
+ 4.846743295515607
+ 4.8467748887077375
+ 4.846806481614795
+ 4.846838074236784
+ 4.8468696665737125
+ 4.846901258625589
+ 4.8469328503924185
+ 4.84696444187421
+ 4.846996033070968
+ 4.847027623982701
+ 4.847059214609416
+ 4.8470908049511205
+ 4.84712239500782
+ 4.8471539847795215
+ 4.847185574266233
+ 4.8472171634679615
+ 4.847248752384714
+ 4.847280341016496
+ 4.847311929363317
+ 4.84734351742518
+ 4.847375105202097
+ 4.847406692694071
+ 4.847438279901112
+ 4.847469866823225
+ 4.847501453460417
+ 4.847533039812696
+ 4.847564625880067
+ 4.84759621166254
+ 4.847627797160119
+ 4.847659382372813
+ 4.847690967300628
+ 4.847722551943571
+ 4.84775413630165
+ 4.847785720374871
+ 4.847817304163241
+ 4.847848887666767
+ 4.847880470885456
+ 4.847912053819316
+ 4.847943636468352
+ 4.847975218832572
+ 4.8480068009119845
+ 4.848038382706593
+ 4.848069964216409
+ 4.848101545441434
+ 4.848133126381679
+ 4.848164707037151
+ 4.848196287407855
+ 4.848227867493798
+ 4.848259447294988
+ 4.848291026811433
+ 4.848322606043138
+ 4.84835418499011
+ 4.848385763652358
+ 4.848417342029887
+ 4.848448920122704
+ 4.848480497930817
+ 4.848512075454233
+ 4.848543652692957
+ 4.848575229646999
+ 4.848606806316364
+ 4.8486383827010595
+ 4.848669958801092
+ 4.848701534616469
+ 4.848733110147196
+ 4.848764685393283
+ 4.848796260354735
+ 4.848827835031559
+ 4.848859409423761
+ 4.8488909835313505
+ 4.848922557354333
+ 4.848954130892714
+ 4.848985704146504
+ 4.849017277115706
+ 4.84904884980033
+ 4.849080422200382
+ 4.849111994315869
+ 4.849143566146798
+ 4.849175137693175
+ 4.849206708955007
+ 4.849238279932304
+ 4.849269850625069
+ 4.849301421033311
+ 4.849332991157036
+ 4.849364560996253
+ 4.849396130550966
+ 4.849427699821183
+ 4.849459268806913
+ 4.849490837508161
+ 4.849522405924933
+ 4.849553974057239
+ 4.849585541905083
+ 4.849617109468474
+ 4.849648676747417
+ 4.849680243741921
+ 4.849711810451992
+ 4.849743376877637
+ 4.849774943018863
+ 4.849806508875677
+ 4.849838074448086
+ 4.849869639736096
+ 4.849901204739715
+ 4.84993276945895
+ 4.8499643338938085
+ 4.8499958980442965
+ 4.85002746191042
+ 4.850059025492187
+ 4.850090588789605
+ 4.850122151802681
+ 4.850153714531421
+ 4.850185276975833
+ 4.850216839135923
+ 4.850248401011698
+ 4.850279962603166
+ 4.850311523910332
+ 4.850343084933204
+ 4.850374645671789
+ 4.850406206126095
+ 4.850437766296128
+ 4.850469326181894
+ 4.8505008857834016
+ 4.850532445100658
+ 4.850564004133668
+ 4.8505955628824395
+ 4.85062712134698
+ 4.850658679527296
+ 4.850690237423395
+ 4.850721795035283
+ 4.850753352362967
+ 4.850784909406456
+ 4.850816466165754
+ 4.85084802264087
+ 4.85087957883181
+ 4.850911134738582
+ 4.85094269036119
+ 4.8509742456996445
+ 4.851005800753952
+ 4.851037355524117
+ 4.851068910010148
+ 4.8511004642120525
+ 4.851132018129837
+ 4.851163571763508
+ 4.851195125113072
+ 4.851226678178537
+ 4.8512582309599095
+ 4.851289783457197
+ 4.851321335670406
+ 4.8513528875995435
+ 4.851384439244616
+ 4.851415990605631
+ 4.851447541682595
+ 4.851479092475516
+ 4.851510642984398
+ 4.8515421932092515
+ 4.851573743150082
+ 4.851605292806896
+ 4.851636842179703
+ 4.851668391268506
+ 4.851699940073313
+ 4.851731488594133
+ 4.851763036830971
+ 4.8517945847838355
+ 4.851826132452731
+ 4.851857679837667
+ 4.851889226938649
+ 4.851920773755685
+ 4.85195232028878
+ 4.851983866537944
+ 4.85201541250318
+ 4.8520469581844985
+ 4.852078503581905
+ 4.852110048695406
+ 4.852141593525008
+ 4.852173138070721
+ 4.852204682332548
+ 4.852236226310499
+ 4.852267770004579
+ 4.852299313414795
+ 4.852330856541155
+ 4.852362399383665
+ 4.852393941942333
+ 4.852425484217164
+ 4.852457026208167
+ 4.8524885679153495
+ 4.852520109338716
+ 4.852551650478273
+ 4.852583191334031
+ 4.8526147319059945
+ 4.85264627219417
+ 4.852677812198565
+ 4.852709351919189
+ 4.852740891356044
+ 4.852772430509141
+ 4.852803969378485
+ 4.852835507964084
+ 4.852867046265943
+ 4.8528985842840715
+ 4.852930122018474
+ 4.85296165946916
+ 4.852993196636134
+ 4.853024733519403
+ 4.853056270118977
+ 4.85308780643486
+ 4.853119342467059
+ 4.853150878215582
+ 4.853182413680437
+ 4.853213948861628
+ 4.853245483759163
+ 4.853277018373051
+ 4.853308552703297
+ 4.853340086749906
+ 4.853371620512889
+ 4.853403153992251
+ 4.853434687187999
+ 4.85346622010014
+ 4.85349775272868
+ 4.853529285073628
+ 4.853560817134989
+ 4.853592348912771
+ 4.853623880406979
+ 4.8536554116176225
+ 4.853686942544709
+ 4.853718473188241
+ 4.853750003548229
+ 4.85378153362468
+ 4.8538130634176
+ 4.853844592926996
+ 4.853876122152873
+ 4.853907651095242
+ 4.853939179754107
+ 4.853970708129476
+ 4.854002236221355
+ 4.854033764029752
+ 4.854065291554672
+ 4.854096818796125
+ 4.854128345754115
+ 4.854159872428652
+ 4.85419139881974
+ 4.854222924927386
+ 4.854254450751599
+ 4.854285976292386
+ 4.85431750154975
+ 4.854349026523702
+ 4.854380551214248
+ 4.854412075621394
+ 4.854443599745148
+ 4.854475123585515
+ 4.854506647142505
+ 4.854538170416122
+ 4.854569693406375
+ 4.854601216113268
+ 4.854632738536811
+ 4.85466426067701
+ 4.854695782533872
+ 4.854727304107403
+ 4.85475882539761
+ 4.854790346404502
+ 4.854821867128083
+ 4.854853387568363
+ 4.854884907725346
+ 4.85491642759904
+ 4.854947947189452
+ 4.854979466496589
+ 4.855010985520458
+ 4.855042504261066
+ 4.855074022718418
+ 4.8551055408925246
+ 4.855137058783391
+ 4.855168576391021
+ 4.8552000937154265
+ 4.855231610756612
+ 4.8552631275145846
+ 4.8552946439893505
+ 4.855326160180917
+ 4.855357676089293
+ 4.855389191714482
+ 4.855420707056494
+ 4.855452222115334
+ 4.855483736891009
+ 4.855515251383526
+ 4.855546765592893
+ 4.855578279519117
+ 4.855609793162203
+ 4.855641306522159
+ 4.855672819598992
+ 4.855704332392709
+ 4.855735844903316
+ 4.855767357130821
+ 4.8557988690752305
+ 4.855830380736552
+ 4.855861892114791
+ 4.855893403209955
+ 4.855924914022053
+ 4.855956424551088
+ 4.85598793479707
+ 4.856019444760004
+ 4.8560509544398975
+ 4.856082463836758
+ 4.856113972950593
+ 4.8561454817814065
+ 4.8561769903292085
+ 4.856208498594005
+ 4.856240006575802
+ 4.8562715142746065
+ 4.856303021690428
+ 4.856334528823269
+ 4.8563660356731395
+ 4.856397542240045
+ 4.856429048523994
+ 4.856460554524992
+ 4.856492060243047
+ 4.856523565678164
+ 4.856555070830352
+ 4.856586575699617
+ 4.856618080285965
+ 4.856649584589404
+ 4.856681088609941
+ 4.8567125923475825
+ 4.856744095802336
+ 4.856775598974207
+ 4.856807101863203
+ 4.856838604469332
+ 4.8568701067925995
+ 4.856901608833014
+ 4.85693311059058
+ 4.856964612065306
+ 4.856996113257199
+ 4.857027614166265
+ 4.857059114792512
+ 4.857090615135945
+ 4.857122115196574
+ 4.857153614974403
+ 4.8571851144694405
+ 4.857216613681692
+ 4.857248112611167
+ 4.8572796112578684
+ 4.857311109621806
+ 4.8573426077029875
+ 4.8573741055014175
+ 4.857405603017103
+ 4.857437100250052
+ 4.8574685972002705
+ 4.857500093867767
+ 4.857531590252546
+ 4.857563086354617
+ 4.857594582173983
+ 4.8576260777106555
+ 4.857657572964639
+ 4.85768906793594
+ 4.857720562624568
+ 4.857752057030526
+ 4.857783551153823
+ 4.857815044994466
+ 4.8578465385524625
+ 4.857878031827818
+ 4.857909524820539
+ 4.857941017530634
+ 4.857972509958109
+ 4.858004002102971
+ 4.858035493965227
+ 4.858066985544884
+ 4.858098476841949
+ 4.858129967856428
+ 4.858161458588329
+ 4.858192949037657
+ 4.858224439204421
+ 4.858255929088627
+ 4.858287418690283
+ 4.858318908009394
+ 4.858350397045967
+ 4.858381885800011
+ 4.858413374271531
+ 4.8584448624605345
+ 4.858476350367028
+ 4.858507837991019
+ 4.858539325332513
+ 4.85857081239152
+ 4.858602299168042
+ 4.85863378566209
+ 4.85866527187367
+ 4.858696757802788
+ 4.858728243449452
+ 4.858759728813666
+ 4.858791213895441
+ 4.858822698694782
+ 4.858854183211695
+ 4.858885667446188
+ 4.858917151398267
+ 4.858948635067941
+ 4.8589801184552135
+ 4.859011601560094
+ 4.859043084382589
+ 4.859074566922704
+ 4.859106049180447
+ 4.859137531155825
+ 4.859169012848844
+ 4.859200494259512
+ 4.859231975387835
+ 4.859263456233821
+ 4.859294936797475
+ 4.8593264170788055
+ 4.859357897077818
+ 4.859389376794521
+ 4.859420856228921
+ 4.8594523353810235
+ 4.8594838142508365
+ 4.859515292838366
+ 4.859546771143621
+ 4.8595782491666055
+ 4.859609726907329
+ 4.859641204365796
+ 4.859672681542015
+ 4.859704158435991
+ 4.859735635047734
+ 4.859767111377249
+ 4.859798587424542
+ 4.859830063189622
+ 4.859861538672494
+ 4.859893013873166
+ 4.859924488791644
+ 4.859955963427936
+ 4.859987437782047
+ 4.860018911853986
+ 4.860050385643759
+ 4.860081859151372
+ 4.860113332376833
+ 4.860144805320149
+ 4.860176277981326
+ 4.860207750360371
+ 4.860239222457292
+ 4.860270694272094
+ 4.860302165804785
+ 4.860333637055372
+ 4.860365108023861
+ 4.86039657871026
+ 4.860428049114574
+ 4.860459519236813
+ 4.860490989076982
+ 4.860522458635087
+ 4.860553927911136
+ 4.860585396905135
+ 4.860616865617092
+ 4.860648334047013
+ 4.860679802194905
+ 4.860711270060775
+ 4.860742737644631
+ 4.860774204946479
+ 4.860805671966324
+ 4.860837138704176
+ 4.860868605160039
+ 4.860900071333922
+ 4.86093153722583
+ 4.860963002835772
+ 4.860994468163754
+ 4.861025933209782
+ 4.861057397973863
+ 4.861088862456006
+ 4.8611203266562155
+ 4.861151790574499
+ 4.861183254210862
+ 4.861214717565314
+ 4.861246180637861
+ 4.861277643428508
+ 4.8613091059372655
+ 4.861340568164136
+ 4.86137203010913
+ 4.861403491772253
+ 4.861434953153512
+ 4.861466414252912
+ 4.861497875070462
+ 4.8615293356061695
+ 4.861560795860039
+ 4.861592255832079
+ 4.861623715522295
+ 4.861655174930696
+ 4.861686634057288
+ 4.861718092902076
+ 4.861749551465069
+ 4.861781009746274
+ 4.861812467745695
+ 4.861843925463342
+ 4.861875382899221
+ 4.861906840053338
+ 4.8619382969257
+ 4.861969753516314
+ 4.862001209825189
+ 4.862032665852329
+ 4.862064121597741
+ 4.862095577061433
+ 4.862127032243412
+ 4.8621584871436845
+ 4.8621899417622565
+ 4.862221396099136
+ 4.862252850154328
+ 4.862284303927842
+ 4.862315757419684
+ 4.862347210629859
+ 4.862378663558377
+ 4.8624101162052416
+ 4.862441568570461
+ 4.862473020654043
+ 4.862504472455994
+ 4.86253592397632
+ 4.862567375215028
+ 4.8625988261721265
+ 4.86263027684762
+ 4.862661727241516
+ 4.862693177353823
+ 4.862724627184545
+ 4.8627560767336915
+ 4.862787526001267
+ 4.862818974987281
+ 4.8628504236917385
+ 4.862881872114647
+ 4.862913320256013
+ 4.862944768115843
+ 4.862976215694144
+ 4.863007662990923
+ 4.863039110006188
+ 4.863070556739945
+ 4.8631020031922
+ 4.8631334493629605
+ 4.863164895252233
+ 4.863196340860025
+ 4.863227786186344
+ 4.863259231231194
+ 4.863290675994585
+ 4.863322120476522
+ 4.863353564677012
+ 4.863385008596063
+ 4.863416452233681
+ 4.863447895589872
+ 4.863479338664645
+ 4.863510781458005
+ 4.863542223969959
+ 4.863573666200514
+ 4.863605108149677
+ 4.863636549817456
+ 4.863667991203856
+ 4.863699432308885
+ 4.863730873132549
+ 4.8637623136748545
+ 4.86379375393581
+ 4.863825193915422
+ 4.863856633613696
+ 4.863888073030639
+ 4.863919512166259
+ 4.863950951020563
+ 4.863982389593555
+ 4.864013827885245
+ 4.86404526589564
+ 4.864076703624743
+ 4.864108141072566
+ 4.8641395782391115
+ 4.864171015124388
+ 4.864202451728403
+ 4.864233888051163
+ 4.864265324092674
+ 4.864296759852944
+ 4.864328195331978
+ 4.864359630529784
+ 4.8643910654463705
+ 4.864422500081742
+ 4.864453934435905
+ 4.864485368508868
+ 4.8645168023006375
+ 4.86454823581122
+ 4.864579669040623
+ 4.864611101988851
+ 4.864642534655913
+ 4.864673967041816
+ 4.864705399146565
+ 4.864736830970169
+ 4.864768262512634
+ 4.864799693773965
+ 4.864831124754171
+ 4.86486255545326
+ 4.864893985871236
+ 4.864925416008106
+ 4.864956845863879
+ 4.864988275438559
+ 4.8650197047321555
+ 4.865051133744674
+ 4.865082562476121
+ 4.865113990926504
+ 4.865145419095831
+ 4.865176846984106
+ 4.865208274591338
+ 4.865239701917534
+ 4.865271128962699
+ 4.8653025557268395
+ 4.8653339822099655
+ 4.865365408412081
+ 4.865396834333194
+ 4.865428259973311
+ 4.865459685332438
+ 4.865491110410584
+ 4.865522535207754
+ 4.865553959723956
+ 4.865585383959195
+ 4.865616807913479
+ 4.865648231586817
+ 4.8656796549792105
+ 4.865711078090671
+ 4.865742500921203
+ 4.865773923470815
+ 4.865805345739513
+ 4.865836767727303
+ 4.865868189434193
+ 4.865899610860189
+ 4.865931032005298
+ 4.865962452869527
+ 4.865993873452883
+ 4.866025293755372
+ 4.866056713777001
+ 4.866088133517779
+ 4.86611955297771
+ 4.866150972156802
+ 4.866182391055062
+ 4.866213809672496
+ 4.866245228009111
+ 4.8662766460649145
+ 4.866308063839912
+ 4.866339481334113
+ 4.866370898547522
+ 4.866402315480145
+ 4.866433732131991
+ 4.8664651485030666
+ 4.866496564593376
+ 4.86652798040293
+ 4.866559395931733
+ 4.866590811179791
+ 4.866622226147114
+ 4.866653640833705
+ 4.866685055239573
+ 4.866716469364726
+ 4.866747883209167
+ 4.866779296772906
+ 4.86681071005595
+ 4.866842123058303
+ 4.866873535779974
+ 4.86690494822097
+ 4.866936360381296
+ 4.866967772260961
+ 4.86699918385997
+ 4.86703059517833
+ 4.86706200621605
+ 4.867093416973133
+ 4.867124827449589
+ 4.867156237645424
+ 4.867187647560645
+ 4.867219057195258
+ 4.867250466549269
+ 4.867281875622687
+ 4.867313284415517
+ 4.867344692927767
+ 4.867376101159443
+ 4.867407509110554
+ 4.8674389167811025
+ 4.867470324171099
+ 4.867501731280548
+ 4.867533138109459
+ 4.867564544657836
+ 4.867595950925688
+ 4.86762735691302
+ 4.86765876261984
+ 4.8676901680461535
+ 4.867721573191969
+ 4.867752978057292
+ 4.867784382642131
+ 4.8678157869464895
+ 4.8678471909703775
+ 4.867878594713801
+ 4.867909998176766
+ 4.86794140135928
+ 4.867972804261349
+ 4.868004206882981
+ 4.868035609224182
+ 4.868067011284959
+ 4.868098413065319
+ 4.868129814565269
+ 4.868161215784815
+ 4.868192616723963
+ 4.868224017382722
+ 4.868255417761097
+ 4.868286817859096
+ 4.868318217676726
+ 4.868349617213991
+ 4.868381016470902
+ 4.868412415447463
+ 4.868443814143682
+ 4.868475212559566
+ 4.868506610695119
+ 4.868538008550352
+ 4.868569406125268
+ 4.868600803419876
+ 4.868632200434182
+ 4.868663597168194
+ 4.868694993621917
+ 4.868726389795358
+ 4.868757785688526
+ 4.868789181301425
+ 4.8688205766340635
+ 4.868851971686448
+ 4.8688833664585855
+ 4.8689147609504815
+ 4.868946155162144
+ 4.86897754909358
+ 4.869008942744795
+ 4.869040336115797
+ 4.869071729206593
+ 4.869103122017187
+ 4.869134514547589
+ 4.8691659067978055
+ 4.869197298767842
+ 4.869228690457706
+ 4.869260081867403
+ 4.869291472996942
+ 4.869322863846328
+ 4.869354254415569
+ 4.86938564470467
+ 4.86941703471364
+ 4.869448424442486
+ 4.8694798138912105
+ 4.869511203059825
+ 4.869542591948336
+ 4.869573980556747
+ 4.869605368885067
+ 4.869636756933303
+ 4.869668144701461
+ 4.869699532189547
+ 4.86973091939757
+ 4.869762306325536
+ 4.8697936929734515
+ 4.8698250793413225
+ 4.869856465429157
+ 4.86988785123696
+ 4.869919236764741
+ 4.869950622012504
+ 4.869982006980258
+ 4.870013391668008
+ 4.870044776075763
+ 4.870076160203527
+ 4.87010754405131
+ 4.870138927619116
+ 4.8701703109069525
+ 4.870201693914826
+ 4.870233076642745
+ 4.8702644590907145
+ 4.870295841258742
+ 4.870327223146834
+ 4.870358604754998
+ 4.870389986083239
+ 4.8704213671315655
+ 4.870452747899985
+ 4.870484128388502
+ 4.870515508597125
+ 4.870546888525859
+ 4.870578268174713
+ 4.870609647543691
+ 4.8706410266328035
+ 4.870672405442054
+ 4.87070378397145
+ 4.870735162221
+ 4.870766540190709
+ 4.870797917880584
+ 4.870829295290632
+ 4.870860672420861
+ 4.8708920492712755
+ 4.870923425841884
+ 4.870954802132691
+ 4.870986178143707
+ 4.871017553874936
+ 4.871048929326386
+ 4.871080304498062
+ 4.871111679389974
+ 4.8711430540021246
+ 4.871174428334523
+ 4.871205802387177
+ 4.871237176160092
+ 4.871268549653275
+ 4.871299922866731
+ 4.87133129580047
+ 4.871362668454497
+ 4.871394040828818
+ 4.871425412923441
+ 4.871456784738373
+ 4.871488156273621
+ 4.871519527529189
+ 4.871550898505087
+ 4.871582269201322
+ 4.871613639617896
+ 4.871645009754821
+ 4.8716763796121025
+ 4.871707749189746
+ 4.871739118487758
+ 4.871770487506147
+ 4.871801856244919
+ 4.871833224704081
+ 4.871864592883639
+ 4.8718959607836
+ 4.871927328403971
+ 4.87195869574476
+ 4.8719900628059705
+ 4.872021429587612
+ 4.872052796089692
+ 4.8720841623122135
+ 4.872115528255186
+ 4.872146893918616
+ 4.872178259302512
+ 4.872209624406877
+ 4.87224098923172
+ 4.872272353777047
+ 4.872303718042866
+ 4.872335082029182
+ 4.872366445736003
+ 4.872397809163336
+ 4.872429172311187
+ 4.872460535179562
+ 4.8724918977684695
+ 4.872523260077916
+ 4.872554622107907
+ 4.872585983858449
+ 4.87261734532955
+ 4.872648706521218
+ 4.872680067433457
+ 4.872711428066275
+ 4.8727427884196794
+ 4.872774148493677
+ 4.872805508288272
+ 4.872836867803474
+ 4.872868227039288
+ 4.872899585995723
+ 4.872930944672784
+ 4.872962303070477
+ 4.8729936611888105
+ 4.873025019027791
+ 4.873056376587424
+ 4.873087733867718
+ 4.873119090868679
+ 4.873150447590311
+ 4.873181804032626
+ 4.873213160195627
+ 4.873244516079323
+ 4.873275871683719
+ 4.873307227008821
+ 4.873338582054639
+ 4.873369936821176
+ 4.873401291308442
+ 4.873432645516441
+ 4.873463999445183
+ 4.873495353094672
+ 4.873526706464915
+ 4.87355805955592
+ 4.873589412367693
+ 4.873620764900241
+ 4.873652117153571
+ 4.8736834691276885
+ 4.8737148208226015
+ 4.873746172238316
+ 4.873777523374839
+ 4.873808874232179
+ 4.87384022481034
+ 4.873871575109329
+ 4.873902925129154
+ 4.873934274869821
+ 4.873965624331339
+ 4.873996973513711
+ 4.874028322416946
+ 4.87405967104105
+ 4.874091019386031
+ 4.8741223674518945
+ 4.874153715238648
+ 4.874185062746296
+ 4.874216409974849
+ 4.87424775692431
+ 4.874279103594689
+ 4.874310449985992
+ 4.874341796098224
+ 4.874373141931392
+ 4.874404487485505
+ 4.874435832760568
+ 4.8744671777565864
+ 4.87449852247357
+ 4.874529866911524
+ 4.874561211070455
+ 4.87459255495037
+ 4.874623898551276
+ 4.874655241873178
+ 4.874686584916087
+ 4.874717927680004
+ 4.874749270164941
+ 4.8747806123709
+ 4.8748119542978925
+ 4.874843295945922
+ 4.874874637314996
+ 4.874905978405121
+ 4.874937319216305
+ 4.8749686597485535
+ 4.875000000001874
+}
diff --git a/release/datafiles/ctodata.py b/release/datafiles/ctodata.py
index 079f6c3b918..8c1d4a4fb34 100755
--- a/release/datafiles/ctodata.py
+++ b/release/datafiles/ctodata.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ***** BEGIN GPL LICENSE BLOCK *****
diff --git a/release/datafiles/fonts/droidsans.ttf.gz b/release/datafiles/fonts/droidsans.ttf.gz
index 5b942162141..7940852f637 100644
--- a/release/datafiles/fonts/droidsans.ttf.gz
+++ b/release/datafiles/fonts/droidsans.ttf.gz
Binary files differ
diff --git a/release/datafiles/locale b/release/datafiles/locale
-Subproject 9628dc1922be2fb6281bc66f5f7512c2a57c294
+Subproject dc166057192ea882b5cc70484d4c8bacd7cb41b
diff --git a/release/datafiles/prvicons.png b/release/datafiles/prvicons.png
index 7209385da9c..ccd47438da6 100644
--- a/release/datafiles/prvicons.png
+++ b/release/datafiles/prvicons.png
Binary files differ
diff --git a/release/datafiles/prvicons.svg b/release/datafiles/prvicons.svg
index e0894ff2dc8..0d64bf78865 100644
--- a/release/datafiles/prvicons.svg
+++ b/release/datafiles/prvicons.svg
@@ -14,7 +14,7 @@
height="192"
id="svg2"
sodipodi:version="0.32"
- inkscape:version="0.48.4 r9939"
+ inkscape:version="0.91 r13725"
version="1.0"
sodipodi:docname="prvicons.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
@@ -32,19 +32,19 @@
objecttolerance="10000"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
- inkscape:zoom="5.6568542"
- inkscape:cx="118.09116"
- inkscape:cy="73.89985"
+ inkscape:zoom="4.29"
+ inkscape:cx="86.93017"
+ inkscape:cy="96"
inkscape:document-units="px"
- inkscape:current-layer="g32752"
- showgrid="false"
+ inkscape:current-layer="layer1"
+ showgrid="true"
inkscape:window-width="1920"
- inkscape:window-height="1018"
- inkscape:window-x="-8"
- inkscape:window-y="-8"
+ inkscape:window-height="1005"
+ inkscape:window-x="-2"
+ inkscape:window-y="27"
inkscape:snap-nodes="true"
- inkscape:snap-bbox="false"
- showguides="true"
+ inkscape:snap-bbox="true"
+ showguides="false"
inkscape:guide-bbox="true"
inkscape:object-nodes="false"
inkscape:object-paths="false"
@@ -53,28 +53,29 @@
inkscape:window-maximized="1"
inkscape:bbox-paths="false"
inkscape:snap-global="true"
- inkscape:snap-bbox-midpoints="false"
+ inkscape:snap-bbox-midpoints="true"
inkscape:snap-grids="true"
- inkscape:snap-to-guides="false"
+ inkscape:snap-to-guides="true"
inkscape:snap-page="false"
units="px"
inkscape:snap-center="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
- fit-margin-bottom="0">
+ fit-margin-bottom="0"
+ inkscape:snap-bbox-edge-midpoints="false">
<inkscape:grid
originy="0px"
originx="0px"
snapvisiblegridlinesonly="true"
empopacity="0.25098039"
- empcolor="#7f7f7f"
+ empcolor="#7f1118"
dotted="false"
opacity="0.09803922"
color="#808080"
empspacing="4"
- spacingy="0.25px"
- spacingx="0.25px"
+ spacingy="4"
+ spacingx="4"
enabled="true"
visible="true"
id="grid17394"
@@ -15166,32 +15167,6 @@
id="linearGradient44404"
xlink:href="#linearGradient44939-8"
inkscape:collect="always" />
- <filter
- color-interpolation-filters="sRGB"
- height="1.229448"
- y="-0.11472401"
- width="1.2515693"
- x="-0.12578467"
- id="filter44473"
- inkscape:collect="always">
- <feGaussianBlur
- id="feGaussianBlur44475"
- stdDeviation="0.81235925"
- inkscape:collect="always" />
- </filter>
- <filter
- color-interpolation-filters="sRGB"
- height="1.2365714"
- y="-0.11828571"
- width="1.2435294"
- x="-0.12176471"
- id="filter44477"
- inkscape:collect="always">
- <feGaussianBlur
- id="feGaussianBlur44479"
- stdDeviation="0.8625"
- inkscape:collect="always" />
- </filter>
<linearGradient
y2="106.5"
x2="284.5"
@@ -17793,19 +17768,6 @@
d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
style="fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;display:inline" />
</clipPath>
- <filter
- color-interpolation-filters="sRGB"
- id="filter63011-8"
- height="2.0133312"
- y="-0.50666559"
- width="1.9120018"
- x="-0.45600089"
- inkscape:collect="always">
- <feGaussianBlur
- id="feGaussianBlur63013-2"
- stdDeviation="1.899998"
- inkscape:collect="always" />
- </filter>
<linearGradient
y2="383.69843"
x2="174.29811"
@@ -17928,6 +17890,78 @@
offset="1"
id="stop39175-18" />
</linearGradient>
+ <filter
+ style="color-interpolation-filters:sRGB;"
+ inkscape:label="Drop Shadow"
+ id="filter6078"
+ x="-0.29999999999999999"
+ width="1.3500000000000001"
+ height="1.3999999999999999"
+ y="-0.14999999999999999">
+ <feFlood
+ flood-opacity="0.40000000000000002"
+ flood-color="rgb(0,0,0)"
+ result="flood"
+ id="feFlood6080" />
+ <feComposite
+ in="flood"
+ in2="SourceGraphic"
+ operator="in"
+ result="composite1"
+ id="feComposite6082" />
+ <feGaussianBlur
+ in="composite1"
+ stdDeviation="1.5"
+ result="blur"
+ id="feGaussianBlur6084" />
+ <feOffset
+ dx="-2"
+ dy="2"
+ result="offset"
+ id="feOffset6086" />
+ <feComposite
+ in="SourceGraphic"
+ in2="offset"
+ operator="over"
+ result="composite2"
+ id="feComposite6088" />
+ </filter>
+ <filter
+ style="color-interpolation-filters:sRGB;"
+ inkscape:label="Drop Shadow"
+ id="filter6146"
+ x="-0.29999999999999999"
+ width="1.3500000000000001"
+ y="-0.14999999999999999"
+ height="1.3999999999999999">
+ <feFlood
+ flood-opacity="0.40000000000000002"
+ flood-color="rgb(0,0,0)"
+ result="flood"
+ id="feFlood6148" />
+ <feComposite
+ in="flood"
+ in2="SourceGraphic"
+ operator="in"
+ result="composite1"
+ id="feComposite6150" />
+ <feGaussianBlur
+ in="composite1"
+ stdDeviation="1.5"
+ result="blur"
+ id="feGaussianBlur6152" />
+ <feOffset
+ dx="-2"
+ dy="2"
+ result="offset"
+ id="feOffset6154" />
+ <feComposite
+ in="SourceGraphic"
+ in2="offset"
+ operator="over"
+ result="composite2"
+ id="feComposite6156" />
+ </filter>
</defs>
<metadata
id="metadata7">
@@ -17989,6 +18023,600 @@
id="path23347"
style="fill:none;stroke:#ffffff;stroke-width:1.79999995;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="sheet_layout"
+ sodipodi:insensitive="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path19551-18-1"
+ d="m 35.75,29.5 0,1 -0.5,0 0,1 0.5,0 0,1 -0.75,0 0,1 0.75,0 0,1 1.5,0 0,-1 0.75,0 0,-1 -0.75,0 0,-1 0.5,0 0,-1 -0.5,0 0,-1 -1.5,0 z m 0.25,1 1,0 0,1 -1,0 0,-1 z m 0,2 1,0 0,1 -1,0 0,-1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ id="path30643-7-0"
+ d="m 31.75,29.5 0,1 -0.75,0 0,3 0.75,0 0,1 1.5,0 0,-1 0.75,0 0,-3 -0.75,0 0,-1 -1.5,0 z m 0.25,1 1,0 0,3 -1,0 0,-3 z m 0.25,1 0,1 0.5,0 0,-1 -0.5,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path30647-6-1"
+ d="m 19,29.5 0,1 2,0 0,1 -1,0 0,1 1,0 0,-0.75 1,0 0,-1.5 -1,0 0,-0.75 -2,0 z m 1,3 -1,0 0,1 0,1 3,0 0,-1 -2,0 0,-1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path30649-7-4"
+ d="m 25,29.5 0,3 1,0 1,0 0,1 -2,0 0,1 2,0 0,-0.75 1,0 0,-1.5 -1,0 0,-0.75 -1,0 0,-1 2,0 0,-1 -2,0 -1,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <rect
+ y="33.5"
+ x="23"
+ height="1"
+ width="1"
+ id="rect30651-8-6"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect30653-7-0"
+ width="1"
+ height="1"
+ x="29"
+ y="33.5" />
+ <rect
+ y="33.5"
+ x="15"
+ height="1"
+ width="1"
+ id="rect30725-8-7"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ id="path30723-1-1"
+ d="m 11,31.5 0,2.25 1,0 0,0.75 1,0 0,-0.75 1,0 0,-2.25 -1,0 0,2 -1,0 0,-2 -1,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ sodipodi:nodetypes="ccccccccccccc"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="translate(-62,136.5)"
+ id="g72798"
+ style="display:inline;opacity:0.5;enable-background:new">
+ <g
+ id="g72716">
+ <path
+ id="path72434"
+ d="m 186,-127 0,0.75 -1,0 0,3.5 1,0 0,0.75 2,0 0,-1 0,-1.25 -1,0 0,1.25 -1,0 0,-3 2,0 0,-1 -2,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <rect
+ y="-127"
+ x="219"
+ height="5"
+ width="1"
+ id="rect72436"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ id="path72438"
+ d="m 144,-127 0,4 -1,0 0,-1 -1,0 0,1 0.75,0 0,1 1.5,0 0,-1 0.75,0 0,-4 -1,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path72440"
+ d="m 189,-127 0,5 1,0 0,-3 1,0 0,-1 -1,0 0,-1 -1,0 z m 2,2 0,1 1,0 0,2 1,0 0,-5 -1,0 0,2 -1,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path72442"
+ d="m 165,-127 0,1 2,0 0,-1 -2,0 z m 2,1 0,3 1,0 0,-3 -1,0 z m 0,3 -2,0 0,1 2,0 0,-1 z m -2,0 0,-3 -1,0 0,3 1,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path72446"
+ d="m 130,-127 0,0.75 -1,0 0,1.5 1,0 0,0.75 1,0 0,1 -2,0 0,1 2,0 0,-0.75 1,0 0,-1.5 -1,0 0,-0.75 -1,0 0,-1 1.5,0 0,-1 -1.5,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path72448"
+ d="m 154,-127 0,1 1,0 0,4 1,0 0,-4 1,0 0,-1 -3,0 0,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path72450"
+ d="m 133,-127 0,4.25 1,0 0,0.75 2,0 0,-0.75 1,0 0,-4.25 -1,0 0,4 -2,0 0,-4 -1,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path72452"
+ d="m 138,-127 0,5 1,0 1,0 0,-0.5 1,0 0,-1.5 -0.75,0 0,-1 0.75,0 0,-1.25 -1,0 0,-0.75 -1,0 -1,0 z m 1,1 1,0 0,1 -1,0 0,-1 z m 0,2 1,0 0,1 -1,0 0,-1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path72454"
+ d="m 151,-127 0,0.75 -1,0 0,3.5 1,0 0,0.75 2,0 0,-1 -2,0 0,-3 2,0 0,-1 -2,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path72456"
+ d="m 146,-127 0,5 1,0 2,0 0,-1 -2,0 0,-1 1,0 0,-1 -1,0 0,-1 2,0 0,-1 -2,0 -1,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 209,-127 0,5 1,0 2,0 0,-1 -2,0 0,-4 -1,0 z"
+ id="path72458"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 160,-127 0,1 1,0 0,4 1,0 0,-4 1,0 0,-1 -3,0 0,0 z"
+ id="path72460" />
+ <path
+ id="path72462"
+ d="m 171,-127 0,1 1,0 0,4 1,0 0,-4 1,0 0,-1 -3,0 0,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path72464"
+ d="m 175,-127 0,5 1,0 0,-2 1,0 0,2 1,0 0,-5 -1,0 0,2 -1,0 0,-2 -1,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 179,-127 0,5 1,0 2,0 0,-1 -2,0 0,-1 1,0 0,-1 -1,0 0,-1 2,0 0,-1 -2,0 -1,0 z"
+ id="path72466" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 194,-127 0,4.25 1,0 0,0.75 2,0 0,-0.75 1,0 0,-4.25 -1,0 0,4 -2,0 0,-4 -1,0 z"
+ id="path72468" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 202,-127 0,0.75 -1,0 0,3.5 1,0 0,0.75 2,0 0,-1 0,-1.25 -1,0 0,1.25 -1,0 0,-3 2,0 0,-1 -2,0 z"
+ id="path72470" />
+ <path
+ id="path72472"
+ d="m 205,-127 0,5 1,0 0,-2 1.25,0 0,-1 0.75,0 0,-1.25 -1,0 0,-0.75 -1,0 -1,0 z m 1,1 1,0 0,1 -1,0 0,-1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path72474"
+ d="m 215,-127 0,5 1,0 2,0 0,-1 -2,0 0,-4 -1,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 222,-127 0,0.75 -1,0 0,3.5 1,0 0,0.75 2,0 0,-1 -2,0 0,-3 2,0 0,-1 -2,0 z"
+ id="path72476" />
+ <path
+ id="path72478"
+ d="m 225,-127 0,5 1,0 2,0 0,-1 -2,0 0,-1 1,0 0,-1 -1,0 0,-1 2,0 0,-1 -2,0 -1,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 229,-127 0,5 1,0 0,-3 1,0 0,-1 -1,0 0,-1 -1,0 z m 2,2 0,1 1,0 0,2 1,0 0,-5 -1,0 0,2 -1,0 z"
+ id="path72480" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 235,-127 0,0.75 -1,0 0,3.5 1,0 0,0.75 2,0 0,-1 -2,0 0,-3 2,0 0,-1 -2,0 z"
+ id="path72482" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 238,-127 0,5 1,0 2,0 0,-1 -2,0 0,-1 1,0 0,-1 -1,0 0,-1 2,0 0,-1 -2,0 -1,0 z"
+ id="path72484" />
+ <path
+ id="path72486"
+ d="m 242.75,-123 0,1 -0.75,0 0,1 1,0 0,-1 1,0 0,-1 -1.25,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path32008-7"
+ d="m 72,-127 0,1 1,0 0,4 1,0 0,-4 1,0 0,-1 -3,0 0,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path32010-4"
+ d="m 76,-127 0,5 1,0 0,-2 1,0 0,2 1,0 0,-5 -1,0 0,2 -1,0 0,-2 -1,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <rect
+ y="-127"
+ x="80"
+ height="5"
+ width="1"
+ id="rect32012-0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path32015-9"
+ d="m 83,-127 0,0.75 -1,0 0,1.5 1,0 0,0.75 1,0 0,1 -2,0 0,1 2,0 0,-0.75 1,0 0,-1.5 -1,0 0,-0.75 -1,0 0,-1 1.5,0 0,-1 -1.5,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path32017-4"
+ d="m 89,-127 0,0.75 -1,0 0,3.5 1,0 0,0.75 2,0 0,-1 -2,0 0,-3 2,0 0,-1 -2,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path32019-8"
+ d="m 97,-127 0,5 1,0 0,-3 1,0 0,-1 -1,0 0,-1 -1,0 z m 2,2 0,1 1,0 0,2 1,0 0,-5 -1,0 0,2 -1,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path32021-8"
+ d="m 93,-127 0,1 2,0 0,-1 -2,0 z m 2,1 0,3 1,0 0,-3 -1,0 z m 0,3 -2,0 0,1 2,0 0,-1 z m -2,0 0,-3 -1,0 0,3 1,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path32023-2"
+ d="m 102,-127 0,1 1,0 0,4 1,0 0,-4 1,0 0,-1 -3,0 0,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path32026-4"
+ d="m 106,-127 0,5 1,0 2,0 0,-1 -2,0 0,-1 1,0 0,-1 -1,0 0,-1 2,0 0,-1 -2,0 -1,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 110,-127 0,5 1,0 0,-3 1,0 0,-1 -1,0 0,-1 -1,0 z m 2,2 0,1 1,0 0,2 1,0 0,-5 -1,0 0,2 -1,0 z"
+ id="path32029-5" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 115,-127 0,1 1,0 0,4 1,0 0,-4 1,0 0,-1 -3,0 0,0 z"
+ id="path32031-5" />
+ <rect
+ y="-127"
+ x="121"
+ height="5"
+ width="1"
+ id="rect32033-1"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 124,-127 0,0.75 -1,0 0,1.5 1,0 0,0.75 1,0 0,1 -2,0 0,1 2,0 0,-0.75 1,0 0,-1.5 -1,0 0,-0.75 -1,0 0,-1 1.5,0 0,-1 -1.5,0 z"
+ id="path32035-7" />
+ </g>
+ <g
+ id="g72757">
+ <path
+ id="path72562"
+ d="m 78,-119 0,5 1,0 0,-2 1,0 0,2 1,0 0,-5 -1,0 0,2 -1,0 0,-2 -1,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <rect
+ y="-119"
+ x="82"
+ height="5"
+ width="1"
+ id="rect72564"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ id="path72576"
+ d="m 72,-119 0,3.25 1,0 0,1.75 1,0 0,-1.75 1,0 0,1.75 1,0 0,-1.75 1,0 0,-3.25 -1,0 0,3 -1,0 0,-2 -1,0 0,2 -1,0 0,-3 -1,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path72578"
+ d="m 130,-119 0,2.25 1,0 0,2.75 1,0 0,-2.75 1,0 0,-2.25 -1,0 0,2 -1,0 0,-2 -1,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path72580"
+ d="m 94.75,-119 0,1 -0.75,0 0,4 1,0 0,-2 1,0 0,2 1,0 0,-4 -0.75,0 0,-1 -1.5,0 z m 0.25,1 1,0 0,1 -1,0 0,-1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path72582"
+ d="m 85,-119 0,0.75 -1,0 0,3.5 1,0 0,0.75 2,0 0,-1 -2,0 0,-3 2,0 0,-1 -2,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 88,-119 0,5 1,0 0,-2 1,0 0,2 1,0 0,-5 -1,0 0,2 -1,0 0,-2 -1,0 z"
+ id="path72588" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 99,-119 0,0.75 -1,0 0,3.5 1,0 0,0.75 2,0 0,-1 -2,0 0,-3 2,0 0,-1 -2,0 z"
+ id="path72590" />
+ <path
+ id="path72592"
+ d="m 103,-119 0,0.75 -1,0 0,3.5 1,0 0,0.75 2,0 0,-1 -2,0 0,-3 2,0 0,-1 -2,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 107,-119 0,1 2,0 0,-1 -2,0 z m 2,1 0,3 1,0 0,-3 -1,0 z m 0,3 -2,0 0,1 2,0 0,-1 z m -2,0 0,-3 -1,0 0,3 1,0 z"
+ id="path72594" />
+ <path
+ id="path72596"
+ d="m 111,-119 0,5 1,0 0,-3 1,0 0,-1 -1,0 0,-1 -1,0 z m 2,2 0,1 1,0 0,-1 -1,0 z m 1,0 1,0 0,3 1,0 0,-5 -1,0 0,1 -1,0 0,1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 117,-119 0,5 1,0 0,-2 1.25,0 0,-1 0.75,0 0,-1.25 -1,0 0,-0.75 -1,0 -1,0 z m 1,1 1,0 0,1 -1,0 0,-1 z"
+ id="path72598" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 121.75,-119 0,1 -0.75,0 0,4 1,0 0,-2 1,0 0,2 1,0 0,-4 -0.75,0 0,-1 -1.5,0 z m 0.25,1 1,0 0,1 -1,0 0,-1 z"
+ id="path72600" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 125,-119 0,5 1,0 0,-3 1,0 0,-1 -1,0 0,-1 -1,0 z m 2,2 0,1 1,0 0,2 1,0 0,-5 -1,0 0,2 -1,0 z"
+ id="path72602" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect72604"
+ width="1"
+ height="5"
+ x="136"
+ y="-119" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 138,-119 0,1 1,0 0,4 1,0 0,-4 1,0 0,-1 -3,0 0,0 z"
+ id="path72606" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 144.75,-119 0,1 -0.75,0 0,4 1,0 0,-2 1,0 0,2 1,0 0,-4 -0.75,0 0,-1 -1.5,0 z m 0.25,1 1,0 0,1 -1,0 0,-1 z"
+ id="path72608" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path72610"
+ d="m 148,-119 0,5 1,0 2,0 0,-1 -2,0 0,-4 -1,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 153,-119 0,1 2,0 0,-1 -2,0 z m 2,1 0,3 1,0 0,-3 -1,0 z m 0,3 -2,0 0,1 2,0 0,-1 z m -2,0 0,-3 -1,0 0,3 1,0 z"
+ id="path72612" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 157,-119 0,5 1,0 0,-3 1,0 0,-1 -1,0 0,-1 -1,0 z m 2,2 0,1 1,0 0,2 1,0 0,-5 -1,0 0,2 -1,0 z"
+ id="path72614" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 163,-119 0,0.75 -1,0 0,3.5 1,0 0,0.75 2,0 0,-1 0,-1.25 -1,0 0,1.25 -1,0 0,-3 2,0 0,-1 -2,0 z"
+ id="path72616" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect72618"
+ width="1"
+ height="5"
+ x="174"
+ y="-119" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 168,-119 0,3.25 1,0 0,1.75 1,0 0,-1.75 1,0 0,1.75 1,0 0,-1.75 1,0 0,-3.25 -1,0 0,3 -1,0 0,-2 -1,0 0,2 -1,0 0,-3 -1,0 z"
+ id="path72620" />
+ <path
+ id="path72622"
+ d="m 180,-119 0,5 1,0 0,-2 1,0 0,2 1,0 0,-5 -1,0 0,2 -1,0 0,-2 -1,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path72624"
+ d="m 176,-119 0,1 1,0 0,4 1,0 0,-4 1,0 0,-1 -3,0 0,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path32207-9-7"
+ d="m 187,-119 0,0.75 -1,0 0,3.5 1,0 0,0.75 2,0 0,-1 -2,0 0,-3 2,0 0,-1 -2,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path32209-6-7"
+ d="m 191,-119 0,1 2,0 0,-1 -2,0 z m 2,1 0,3 1,0 0,-3 -1,0 z m 0,3 -2,0 0,1 2,0 0,-1 z m -2,0 0,-3 -1,0 0,3 1,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path32211-3-7"
+ d="m 195,-119 0,5 1,0 0,-2 1.25,0 0,-1 0.75,0 0,-1.25 -1,0 0,-0.75 -1,0 -1,0 z m 1,1 1,0 0,1 -1,0 0,-1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path32213-7-3"
+ d="m 199,-119 0,2.25 1,0 0,2.75 1,0 0,-2.75 1,0 0,-2.25 -1,0 0,2 -1,0 0,-2 -1,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path32216-8-3"
+ d="m 203,-119 0,5 1,0 0,-2 1,0 0,2 1,0 0,-2 -0.75,0 0,-1 0.75,0 0,-1.25 -1,0 0,-0.75 -1,0 -1,0 z m 1,1 1,0 0,1 -1,0 0,-1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect32218-8-5"
+ width="1"
+ height="5"
+ x="207"
+ y="-119" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path32220-2-9"
+ d="m 210,-119 0,0.75 -1,0 0,3.5 1,0 0,0.75 2,0 0,-1 0,-1.25 -1,0 0,1.25 -1,0 0,-3 2,0 0,-1 -2,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path32222-9-9"
+ d="m 213,-119 0,5 1,0 0,-2 1,0 0,2 1,0 0,-5 -1,0 0,2 -1,0 0,-2 -1,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path32224-1-8"
+ d="m 217,-119 0,1 1,0 0,4 1,0 0,-4 1,0 0,-1 -3,0 0,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ id="path72678"
+ d="m 225,-119 0,5 1,0 0,-3 1,0 0,-1 -1,0 0,-1 -1,0 z m 2,2 0,1 1,0 0,2 1,0 0,-5 -1,0 0,2 -1,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 235,-119 0,1 2,0 0,-1 -2,0 z m 2,1 0,3 1,0 0,-3 -1,0 z m 0,3 -2,0 0,1 2,0 0,-1 z m -2,0 0,-3 -1,0 0,3 1,0 z"
+ id="path72680"
+ inkscape:connector-curvature="0" />
+ <rect
+ y="-119"
+ x="223"
+ height="5"
+ width="1"
+ id="rect72682"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <rect
+ y="-115"
+ x="239"
+ height="1"
+ width="1"
+ id="rect72684"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ id="path72686"
+ d="m 230,-119 0,5 1,0 0,-2 1,0 0,-1 -1,0 0,-1 2,0 0,-1 -2,0 -1,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ transform="translate(-62,136.5)"
+ style="display:inline;enable-background:new"
+ id="g72880">
+ <g
+ transform="translate(231,-90)"
+ id="g32242-4">
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m -12.25,-17 0,1 -0.75,0 0,4 1,0 0,-2 1,0 0,2 1,0 0,-4 -0.75,0 0,-1 -1.5,0 z m 0.25,1 1,0 0,1 -1,0 0,-1 z"
+ id="path32244-2" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m -9,-17 0,5 1,0 0,-3 1,0 0,-1 -1,0 0,-1 -1,0 z m 2,2 0,1 1,0 0,-1 -1,0 z m 1,0 1,0 0,3 1,0 0,-5 -1,0 0,1 -1,0 0,1 z"
+ id="path32246-0" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m -3,-17 0,5 1,0 1,0 0,-0.5 1,0 0,-1.5 -0.75,0 0,-1 0.75,0 0,-1.25 -1,0 0,-0.75 -1,0 -1,0 z m 1,1 1,0 0,1 -1,0 0,-1 z m 0,2 1,0 0,1 -1,0 0,-1 z"
+ id="path32248-9" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 1,-17 0,5 1,0 0,-2 1,0 0,2 1,0 0,-2 -0.75,0 0,-1 0.75,0 0,-1.25 -1,0 0,-0.75 -1,0 -1,0 z m 1,1 1,0 0,1 -1,0 0,-1 z"
+ id="path32250-7" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 6,-17 0,1 2,0 0,-1 -2,0 z m 2,1 0,3 1,0 0,-3 -1,0 z m 0,3 -2,0 0,1 2,0 0,-1 z m -2,0 0,-3 -1,0 0,3 1,0 z"
+ id="path32252-3" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 10,-17 0,1 2,0 0,1 1,0 0,-1 0,-1 -3,0 z m 2,2 -1,0 0,1 1,0 0,-1 z m -1,1 -1,0 0,1 0,1 3,0 0,-1 -2,0 0,-1 z"
+ id="path32254-7" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m -43.25,-17 0,1 -0.75,0 0,4 1,0 0,-2 1,0 0,2 1,0 0,-4 -0.75,0 0,-1 -1.5,0 z m 0.25,1 1,0 0,1 -1,0 0,-1 z"
+ id="path32256-2" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path32258-6"
+ d="m -40,-17 0,5 1,0 0,-3 1,0 0,-1 -1,0 0,-1 -1,0 z m 2,2 0,1 1,0 0,2 1,0 0,-5 -1,0 0,2 -1,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path32260-0"
+ d="m -35,-17 0,1 0,3 0,1 2,0 0,-0.75 1,0 0,-3.5 -1,0 0,-0.75 -2,0 z m 1,1 1,0 0,3 -1,0 0,-3 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m -31,-17 0,5 1,0 0,-2 1,0 0,2 1,0 0,-2 -0.75,0 0,-1 0.75,0 0,-1.25 -1,0 0,-0.75 -1,0 -1,0 z m 1,1 1,0 0,1 -1,0 0,-1 z"
+ id="path32262-1" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m -27,-17 0,1 2,0 0,1 1,0 0,-1 0,-1 -3,0 z m 2,2 -1,0 0,1 1,0 0,-1 z m -1,1 -1,0 0,1 0,1 3,0 0,-1 -2,0 0,-1 z"
+ id="path32264-6" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path32266-5"
+ d="m -23,-17 0,5 1,0 2,0 0,-1 -2,0 0,-1 1,0 0,-1 -1,0 0,-1 2,0 0,-1 -2,0 -1,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path32268-7"
+ d="m -17,-17 0,4 -1,0 0,-1 -1,0 0,1 0.75,0 0,1 1.5,0 0,-1 0.75,0 0,-4 -1,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <rect
+ y="-19"
+ x="11"
+ height="1"
+ width="1"
+ id="rect32270-5"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ </g>
+ <g
+ id="g21967-4"
+ transform="translate(111.96875,-88)">
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 48,-20 0,0.75 -1,0 0,0.25 -0.25,0 0,1 -0.75,0 0,3 0.75,0 0,1 0.25,0 0,0.25 1,0 0,0.75 3,0 0,-0.75 1,0 0,-0.25 0.25,0 0,-1 0.75,0 0,-3 -0.75,0 0,-1 -0.25,0 0,-0.25 -1,0 0,-0.75 -3,0 z m 0,1 3,0 0,1 1,0 0,3 -1,0 0,1 -3,0 0,-1 -1,0 0,-3 1,0 0,-1 z"
+ id="path32272-1"
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path32274-2"
+ d="m 49,-18 0,0.75 -1,0 0,1.5 1,0 0,0.75 1.25,0 0,-1 -1.25,0 0,-1 1.25,0 0,-1 -1.25,0 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ sodipodi:nodetypes="ccccccccccccc" />
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 171.71875,-107 0,1 -0.75,0 0,3 0.75,0 0,1 1.5,0 0,-1 0.75,0 0,-3 -0.75,0 0,-1 -1.5,0 z m 0.25,1 1,0 0,3 -1,0 0,-3 z m 0.25,1 0,1 0.5,0 0,-1 -0.5,0 z"
+ id="path72688" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 175.96875,-107 0,1 -1,0 0,1 1,0 0,3 1,0 0,-5 -1,0 z"
+ id="path72690" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 177.96875,-107 0,1 2,0 0,1 -1,0 0,1 1,0 0,-0.75 1,0 0,-1.5 -1,0 0,-0.75 -2,0 z m 1,3 -1,0 0,1 0,1 3,0 0,-1 -2,0 0,-1 z"
+ id="path72692" />
+ <path
+ id="path72694"
+ d="m 166.96875,-107 0,1 2,0 0,1 -1,0 0,1 1,0 0,-0.75 1,0 0,-1.5 -1,0 0,-0.75 -2,0 z m 1,3 -1,0 0,1 0,1 3,0 0,-1 -2,0 0,-1 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ d="m 182.96875,-106 0,1 1,0 0,-1 -1,0 z m -0.21875,3 0,1 -0.75,0 0,1 1,0 0,-1 1,0 0,-1 -1.25,0 z"
+ id="path72696" />
+ </g>
+ </g>
+ <g
transform="translate(-872,-180)"
style="display:inline"
id="layer1"
@@ -18101,7 +18729,7 @@
id="g12156" />
<g
transform="translate(-98,462.06404)"
- style="opacity:0.65;display:inline"
+ style="display:inline;opacity:0.65"
id="g12249" />
<g
id="g12255"
@@ -18109,7 +18737,7 @@
style="display:inline" />
<g
id="g12325"
- style="opacity:0.65;display:inline"
+ style="display:inline;opacity:0.65"
transform="translate(-98,483.06404)" />
<g
style="display:inline"
@@ -18181,11 +18809,11 @@
height="0"
width="1"
id="rect17123"
- style="opacity:0;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001;marker:none;enable-background:accumulate" />
<g
id="g51988"
transform="translate(47,-247.0151)"
- style="fill:#d45500;fill-opacity:1;display:inline" />
+ style="display:inline;fill:#d45500;fill-opacity:1" />
<g
transform="translate(10,254)"
id="g57337"
@@ -18198,7 +18826,7 @@
height="0"
width="0"
id="rect23719"
- style="opacity:0.01000001;fill:#b3b3b3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.01000001;fill:#b3b3b3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
<g
transform="translate(341,-57.00032)"
id="g24088" />
@@ -18227,14 +18855,14 @@
<g
id="g24176"
transform="translate(-65,-169.00755)"
- style="fill:#d45500;fill-opacity:1;display:inline" />
+ style="display:inline;fill:#d45500;fill-opacity:1" />
<g
id="g28643"
inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\blender-cvs-windows\.blender\.blender\icons\jendrzych's iconset.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"
transform="translate(-323.1613,214)"
- style="fill:none;stroke:#ffffff;stroke-width:1.50000143;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:7.40000034;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#ffffff;stroke-width:1.50000143;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;marker:none;enable-background:accumulate" />
<g
id="g29500" />
<g
@@ -18264,7 +18892,7 @@
id="g33447" />
<g
transform="translate(-870.9421,-297.02038)"
- style="fill:#ffeeaa;display:inline"
+ style="display:inline;fill:#ffeeaa"
id="g77742" />
<g
id="g34782"
@@ -18272,10 +18900,10 @@
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"
transform="matrix(-1,0,0,-1,104.1613,262.99999)"
- style="stroke:#ffffff;display:inline">
+ style="display:inline;stroke:#ffffff">
<path
inkscape:connector-curvature="0"
- style="fill:none;stroke:#ffffff;stroke-width:1.60000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:7.40000034;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#ffffff;stroke-width:1.60000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;marker:none;enable-background:accumulate"
id="path34784"
sodipodi:nodetypes="cz"
d="" />
@@ -18285,10 +18913,10 @@
d=""
sodipodi:nodetypes="cz"
id="path34806"
- style="fill:none;stroke:#ffffff;stroke-width:1.60000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:7.40000034;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#ffffff;stroke-width:1.60000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;marker:none;enable-background:accumulate" />
<path
inkscape:connector-curvature="0"
- style="fill:none;stroke:#ffffff;stroke-width:1.60000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:7.40000034;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#ffffff;stroke-width:1.60000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;marker:none;enable-background:accumulate"
id="path34696"
sodipodi:nodetypes="cz"
d="" />
@@ -18299,21 +18927,21 @@
<g
id="g36511"
transform="translate(250,-41.00755)"
- style="fill:#d45500;fill-opacity:1;display:inline" />
+ style="display:inline;fill:#d45500;fill-opacity:1" />
<rect
y="67"
x="-25"
height="0"
width="1"
id="rect39658"
- style="opacity:0;fill:#fffeaa;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.80000001;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#fffeaa;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.80000001;marker:none;enable-background:new" />
<rect
y="66"
x="-24"
height="1"
width="0"
id="rect39660"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.80000001;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" />
+ style="display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.80000001;marker:none;enable-background:new" />
<g
id="g40090"
mask="url(#mask38561)"
@@ -18328,1254 +18956,1170 @@
id="g40736" />
</g>
<g
- style="stroke-width:5.41920376;stroke-miterlimit:4;stroke-dasharray:none;display:inline"
+ style="display:inline;stroke-width:5.41920376;stroke-miterlimit:4;stroke-dasharray:none"
id="g38570"
transform="matrix(0.5478212,-0.56064,0.5419177,0.5545983,197.19518,557.21673)"
inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
+ <rect
+ y="180"
+ x="872"
+ height="192"
+ width="192"
+ id="rect30285"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:5.39191818;marker:none;enable-background:accumulate" />
<g
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Pracownia\Moje dokumenty\Moje obrazy\BLENDER ICONS redesign\RELEASES\v. 2.5.06\prvicons v.2.5.06.png"
- id="g32752">
+ inkscape:export-filename="C:\Documents and Settings\Pracowniaa\Moje dokumenty\Moje obrazy\BLENDER ICONS redesign\ver 2\IMAGE BROWSER ICONS.png"
+ transform="translate(860,-202)"
+ id="g21955"
+ style="display:inline;opacity:0.3;enable-background:new">
<rect
- style="opacity:0;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:5.39191818;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="rect30285"
- width="192"
- height="192"
- x="872"
- y="180" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;enable-background:accumulate"
+ id="rect21957"
+ width="48"
+ height="48"
+ x="108"
+ y="430"
+ rx="2.4004419"
+ ry="0" />
<g
- style="opacity:0.3;display:inline;enable-background:new"
- id="g21955"
- transform="translate(856,-203)"
- inkscape:export-filename="C:\Documents and Settings\Pracowniaa\Moje dokumenty\Moje obrazy\BLENDER ICONS redesign\ver 2\IMAGE BROWSER ICONS.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <rect
- ry="0"
- rx="2.4004419"
- y="430"
- x="108"
- height="48"
- width="48"
- id="rect21957"
- style="opacity:0;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
- <g
- id="g21959">
- <path
- style="fill:url(#linearGradient21977);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;display:inline"
- d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
- id="path21961"
- sodipodi:nodetypes="cccccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- inkscape:connector-curvature="0" />
- <path
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
- style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- id="path21963"
- sodipodi:nodetypes="cccc"
- inkscape:connector-curvature="0" />
- <path
- clip-path="url(#clipPath13106)"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccc"
- id="path21965"
- d="m 115,444 12,0 -1,-11 -11,11 z"
- style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)"
- inkscape:connector-curvature="0" />
- <path
- clip-path="none"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 117.5,443.75 9,-2.5 0,-6"
- style="fill:none;stroke:url(#linearGradient21979);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- id="path21967"
- sodipodi:nodetypes="ccc"
- inkscape:connector-curvature="0" />
- <path
- sodipodi:nodetypes="cccccc"
- id="path21969"
- style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- inkscape:connector-curvature="0" />
- <path
- clip-path="url(#clipPath13106)"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccc"
- id="path21971"
- d="m 116,443 11,1 -2,-10 -9,9 z"
- style="opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline;filter:url(#filter63011)"
- inkscape:connector-curvature="0" />
- <path
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
- d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
- id="path21973"
- sodipodi:nodetypes="cccccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- inkscape:connector-curvature="0" />
- <path
- sodipodi:nodetypes="ccc"
- id="path21975"
- style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- d="m 147.5,435 0,38.5 -30.5,0"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- inkscape:connector-curvature="0" />
- </g>
+ id="g21959">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path21961"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ style="display:inline;fill:url(#linearGradient21977);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccc"
+ id="path21963"
+ style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:connector-curvature="0"
+ style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)"
+ d="m 115,444 12,0 -1,-11 -11,11 z"
+ id="path21965"
+ sodipodi:nodetypes="cccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ clip-path="url(#clipPath13106)" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc"
+ id="path21967"
+ style="fill:none;stroke:url(#linearGradient21979);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 117.5,443.75 9,-2.5 0,-6"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ clip-path="none" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
+ style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ id="path21969"
+ sodipodi:nodetypes="cccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)"
+ d="m 116,443 11,1 -2,-10 -9,9 z"
+ id="path21971"
+ sodipodi:nodetypes="cccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ clip-path="url(#clipPath13106)" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path21973"
+ d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 147.5,435 0,38.5 -30.5,0"
+ style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ id="path21975"
+ sodipodi:nodetypes="ccc" />
</g>
+ </g>
+ <g
+ transform="translate(4,0)"
+ id="g30335">
<g
- id="g30335">
- <g
- transform="translate(760,-202)"
- id="g21367">
- <path
- style="fill:url(#linearGradient30321);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;display:inline"
- d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
- id="path21369"
- sodipodi:nodetypes="cccccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- inkscape:connector-curvature="0" />
- <path
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
- style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- id="path21371"
- sodipodi:nodetypes="cccc"
- inkscape:connector-curvature="0" />
- <path
- clip-path="url(#clipPath13106)"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccc"
- id="path21373"
- d="m 115,444 12,0 -1,-11 -11,11 z"
- style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)"
- inkscape:connector-curvature="0" />
- <path
- clip-path="none"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 117.5,443.75 9,-2.5 0,-6"
- style="fill:none;stroke:url(#linearGradient30323);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- id="path21375"
- sodipodi:nodetypes="ccc"
- inkscape:connector-curvature="0" />
- <path
- sodipodi:nodetypes="cccccc"
- id="path21377"
- style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- inkscape:connector-curvature="0" />
- <path
- clip-path="url(#clipPath13106)"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccc"
- id="path21569"
- d="m 116,443 11,1 -2,-10 -9,9 z"
- style="opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline;filter:url(#filter63011)"
- inkscape:connector-curvature="0" />
- <path
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
- d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
- id="path21379"
- sodipodi:nodetypes="cccccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- inkscape:connector-curvature="0" />
- <path
- sodipodi:nodetypes="ccc"
- id="path21381"
- style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- d="m 147.5,435 0,38.5 -30.5,0"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- inkscape:connector-curvature="0" />
- </g>
+ id="g21367"
+ transform="translate(760,-202)">
<path
- sodipodi:nodetypes="ccccccccccccccccccccccc"
- id="text13209"
- d="m 891.07148,245 -0.0715,9 2.39012,0 C 896,254 896,253 896.5,251 l 0.5,0 0,7 -0.5,0 c -0.5,-2 -0.5,-3 -3.10988,-3 L 891,255 l 0,7 c 0,2.5 1,3.25 3.14146,3.39973 l -0.004,0.60029 L 885,266 l 0.004,-0.60029 C 887,265.25 888,264.5 888.00001,262 L 888,248 c 0,-2.5 -1,-3.25 -3,-3.5 l 0,-0.5 16,0 0,5 -0.5,0 c -0.50001,-1.99999 -1.5,-4 -4.5,-4 l -4.92852,0 z"
- style="font-size:33.49144363px;font-style:normal;font-weight:normal;fill:#214478;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Vera Sans"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path21369"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ style="display:inline;fill:url(#linearGradient30321);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccc"
+ id="path21371"
+ style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:connector-curvature="0"
+ style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)"
+ d="m 115,444 12,0 -1,-11 -11,11 z"
+ id="path21373"
+ sodipodi:nodetypes="cccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ clip-path="url(#clipPath13106)" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc"
+ id="path21375"
+ style="fill:none;stroke:url(#linearGradient30323);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 117.5,443.75 9,-2.5 0,-6"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ clip-path="none" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
+ style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ id="path21377"
+ sodipodi:nodetypes="cccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)"
+ d="m 116,443 11,1 -2,-10 -9,9 z"
+ id="path21569"
+ sodipodi:nodetypes="cccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ clip-path="url(#clipPath13106)" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path21379"
+ d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 147.5,435 0,38.5 -30.5,0"
+ style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ id="path21381"
+ sodipodi:nodetypes="ccc" />
</g>
+ <path
+ inkscape:connector-curvature="0"
+ style="font-style:normal;font-weight:normal;font-size:33.49144363px;font-family:'Bitstream Vera Sans';display:inline;fill:#214478;fill-opacity:1;stroke:none"
+ d="m 891.07148,245 -0.0715,9 2.39012,0 C 896,254 896,253 896.5,251 l 0.5,0 0,7 -0.5,0 c -0.5,-2 -0.5,-3 -3.10988,-3 L 891,255 l 0,7 c 0,2.5 1,3.25 3.14146,3.39973 l -0.004,0.60029 L 885,266 l 0.004,-0.60029 C 887,265.25 888,264.5 888.00001,262 L 888,248 c 0,-2.5 -1,-3.25 -3,-3.5 l 0,-0.5 16,0 0,5 -0.5,0 c -0.50001,-1.99999 -1.5,-4 -4.5,-4 l -4.92852,0 z"
+ id="text13209"
+ sodipodi:nodetypes="ccccccccccccccccccccccc" />
+ </g>
+ <g
+ style="display:inline;enable-background:new"
+ id="g21625"
+ transform="translate(908,-154)"
+ inkscape:export-filename="C:\Documents and Settings\Pracowniaa\Moje dokumenty\Moje obrazy\BLENDER ICONS redesign\ver 2\IMAGE BROWSER ICONS.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <rect
+ ry="0"
+ rx="2.4004419"
+ y="430"
+ x="108"
+ height="48"
+ width="48"
+ id="rect21627"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;enable-background:accumulate" />
<g
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Pracowniaa\Moje dokumenty\Moje obrazy\BLENDER ICONS redesign\ver 2\IMAGE BROWSER ICONS.png"
- transform="translate(904,-154)"
- id="g21625"
- style="display:inline;enable-background:new">
- <rect
- style="opacity:0;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="rect21627"
- width="48"
- height="48"
- x="108"
- y="430"
- rx="2.4004419"
- ry="0" />
+ id="g21629">
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;fill:url(#linearGradient21647);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ id="path21631"
+ sodipodi:nodetypes="cccccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
<g
- id="g21629">
- <path
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccccc"
- id="path21631"
- d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
- style="fill:url(#linearGradient21647);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;display:inline"
- inkscape:connector-curvature="0" />
+ style="display:inline;opacity:0.5;fill:#000000"
+ id="g16261"
+ transform="matrix(1.2499985,0,0,1,-87.6203,-147.85351)">
+ <rect
+ style="display:block;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect35099"
+ width="17.600004"
+ height="1"
+ x="167.69646"
+ y="598.85352"
+ rx="0.12125195"
+ ry="0.065390877" />
+ <rect
+ style="display:block;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect35101"
+ width="17.600004"
+ height="1"
+ x="167.69646"
+ y="600.85352"
+ rx="0.12125195"
+ ry="0.065390877" />
+ <rect
+ style="display:block;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect15690"
+ width="17.600004"
+ height="1"
+ x="167.69646"
+ y="602.85352"
+ rx="0.12125195"
+ ry="0.065390877" />
+ <rect
+ style="display:block;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect15692"
+ width="17.600004"
+ height="1"
+ x="167.69646"
+ y="604.85352"
+ rx="0.12125195"
+ ry="0.065390877" />
+ <rect
+ style="display:block;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect15694"
+ width="17.600004"
+ height="1"
+ x="167.69646"
+ y="606.85352"
+ rx="0.12125195"
+ ry="0.065390877" />
+ <rect
+ style="display:block;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect15696"
+ width="17.600004"
+ height="1"
+ x="167.69646"
+ y="608.85352"
+ rx="0.12125195"
+ ry="0.065390877" />
+ <rect
+ style="display:block;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect15698"
+ width="17.600004"
+ height="1"
+ x="167.69646"
+ y="610.85352"
+ rx="0.12125195"
+ ry="0.065390877" />
+ <rect
+ style="display:block;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect15700"
+ width="17.600004"
+ height="1"
+ x="167.69646"
+ y="612.85352"
+ rx="0.12125195"
+ ry="0.065390877" />
+ <rect
+ style="display:block;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="rect15732"
+ width="14.400002"
+ height="1"
+ x="167.69646"
+ y="614.85352"
+ rx="0.09920612"
+ ry="0.065390877" />
<g
- transform="matrix(1.2499985,0,0,1,-87.6203,-147.85351)"
- id="g16261"
- style="opacity:0.5;fill:#000000;display:inline">
+ transform="translate(150.89645,557.85352)"
+ id="g4849"
+ style="display:inline;fill:#000000">
<rect
ry="0.065390877"
rx="0.12125195"
- y="598.85352"
- x="167.69646"
+ y="29"
+ x="16.799992"
height="1"
width="17.600004"
- id="rect35099"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate" />
+ id="rect15736"
+ style="display:block;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
<rect
ry="0.065390877"
rx="0.12125195"
- y="600.85352"
- x="167.69646"
+ y="31"
+ x="16.799992"
height="1"
width="17.600004"
- id="rect35101"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate" />
+ id="rect15738"
+ style="display:block;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
<rect
ry="0.065390877"
rx="0.12125195"
- y="602.85352"
- x="167.69646"
+ y="33"
+ x="16.799992"
height="1"
width="17.600004"
- id="rect15690"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate" />
+ id="rect15740"
+ style="display:block;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
<rect
ry="0.065390877"
rx="0.12125195"
- y="604.85352"
- x="167.69646"
+ y="35"
+ x="16.799992"
height="1"
width="17.600004"
- id="rect15692"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate" />
+ id="rect15742"
+ style="display:block;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
<rect
ry="0.065390877"
- rx="0.12125195"
- y="606.85352"
- x="167.69646"
- height="1"
- width="17.600004"
- id="rect15694"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate" />
- <rect
- ry="0.065390877"
- rx="0.12125195"
- y="608.85352"
- x="167.69646"
- height="1"
- width="17.600004"
- id="rect15696"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate" />
- <rect
- ry="0.065390877"
- rx="0.12125195"
- y="610.85352"
- x="167.69646"
+ rx="0.055114571"
+ y="37"
+ x="16.799992"
height="1"
- width="17.600004"
- id="rect15698"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate" />
- <rect
- ry="0.065390877"
- rx="0.12125195"
- y="612.85352"
- x="167.69646"
- height="1"
- width="17.600004"
- id="rect15700"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate" />
- <rect
- ry="0.065390877"
- rx="0.09920612"
- y="614.85352"
- x="167.69646"
- height="1"
- width="14.400002"
- id="rect15732"
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate" />
- <g
- style="fill:#000000;display:inline"
- id="g4849"
- transform="translate(150.89645,557.85352)">
- <rect
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate"
- id="rect15736"
- width="17.600004"
- height="1"
- x="16.799992"
- y="29"
- rx="0.12125195"
- ry="0.065390877" />
- <rect
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate"
- id="rect15738"
- width="17.600004"
- height="1"
- x="16.799992"
- y="31"
- rx="0.12125195"
- ry="0.065390877" />
- <rect
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate"
- id="rect15740"
- width="17.600004"
- height="1"
- x="16.799992"
- y="33"
- rx="0.12125195"
- ry="0.065390877" />
- <rect
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate"
- id="rect15742"
- width="17.600004"
- height="1"
- x="16.799992"
- y="35"
- rx="0.12125195"
- ry="0.065390877" />
- <rect
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate"
- id="rect15744"
- width="8.0000095"
- height="1"
- x="16.799992"
- y="37"
- rx="0.055114571"
- ry="0.065390877" />
- </g>
- <rect
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate"
- id="rect16334"
- width="0.83333319"
- height="0.99999124"
- x="184.49646"
- y="617.85352"
- rx="0.0057410933"
- ry="0.065390304" />
+ width="8.0000095"
+ id="rect15744"
+ style="display:block;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
</g>
- <path
- sodipodi:nodetypes="cccc"
- id="path21633"
- style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- inkscape:connector-curvature="0" />
- <path
- style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)"
- d="m 115,444 12,0 -1,-11 -11,11 z"
- id="path21635"
- sodipodi:nodetypes="cccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- clip-path="url(#clipPath13106)"
- inkscape:connector-curvature="0" />
- <path
- sodipodi:nodetypes="ccc"
- id="path21637"
- style="fill:none;stroke:url(#linearGradient21649);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- d="m 117.5,443.75 9,-2.5 0,-6"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- clip-path="none"
- inkscape:connector-curvature="0" />
- <path
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
- style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- id="path21639"
- sodipodi:nodetypes="cccccc"
- inkscape:connector-curvature="0" />
- <path
- style="opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline;filter:url(#filter63011)"
- d="m 116,443 11,1 -2,-10 -9,9 z"
- id="path21641"
- sodipodi:nodetypes="cccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- clip-path="url(#clipPath13106)"
- inkscape:connector-curvature="0" />
- <path
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccccc"
- id="path21643"
- d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
- inkscape:connector-curvature="0" />
+ <rect
+ ry="0.065390304"
+ rx="0.0057410933"
+ y="617.85352"
+ x="184.49646"
+ height="0.99999124"
+ width="0.83333319"
+ id="rect16334"
+ style="display:block;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
+ style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ id="path21633"
+ sodipodi:nodetypes="cccc" />
+ <path
+ inkscape:connector-curvature="0"
+ clip-path="url(#clipPath13106)"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccc"
+ id="path21635"
+ d="m 115,444 12,0 -1,-11 -11,11 z"
+ style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)" />
+ <path
+ inkscape:connector-curvature="0"
+ clip-path="none"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 117.5,443.75 9,-2.5 0,-6"
+ style="fill:none;stroke:url(#linearGradient21649);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path21637"
+ sodipodi:nodetypes="ccc" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccc"
+ id="path21639"
+ style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:connector-curvature="0"
+ clip-path="url(#clipPath13106)"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccc"
+ id="path21641"
+ d="m 116,443 11,1 -2,-10 -9,9 z"
+ style="display:inline;opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
+ id="path21643"
+ sodipodi:nodetypes="cccccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <g
+ id="g35119"
+ transform="translate(2,-160.99999)"
+ style="display:inline">
<g
style="display:inline"
- transform="translate(2,-160.99999)"
- id="g35119">
+ transform="translate(105.39645,589.71201)"
+ id="g16097">
<g
- id="g16097"
- transform="translate(105.39645,589.71201)"
- style="display:inline">
- <g
- transform="matrix(0.229703,0,0,0.229703,4.967081,4.244972)"
- style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-miterlimit:4"
- id="g16099">
- <radialGradient
- gradientUnits="userSpaceOnUse"
- fy="114.5684"
- fx="20.892099"
- r="5.256"
- cy="114.5684"
- cx="20.892099"
- id="radialGradient16101">
- <stop
- id="stop16103"
- style="stop-color:#F0F0F0"
- offset="0" />
- <stop
- id="stop16105"
- style="stop-color:#474747"
- offset="1" />
- </radialGradient>
- <radialGradient
- gradientUnits="userSpaceOnUse"
- fy="64.567902"
- fx="20.892099"
- r="5.257"
- cy="64.567902"
- cx="20.892099"
- id="radialGradient16109">
- <stop
- id="stop16111"
- style="stop-color:#F0F0F0"
- offset="0" />
- <stop
- id="stop16113"
- style="stop-color:#474747"
- offset="1" />
- </radialGradient>
- </g>
- <path
- id="path16107"
- d="m 12.85355,31.53813 c 0,0.552274 -0.447803,0.99986 -1,0.99986 -0.552477,0 -1,-0.447865 -1,-0.99986 0,-0.552554 0.447803,-1.00014 1,-1.00014 0.552197,0 1,0.447866 1,1.00014 l 0,0 0,0 0,0 z"
- style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline"
- inkscape:connector-curvature="0" />
- <path
- id="path16117"
- d="m 12.60355,31.288131 c 0,0.552274 -0.447803,0.999859 -1,0.999859 -0.552477,0 -1,-0.447865 -1,-0.999859 0,-0.552556 0.447803,-1.000141 1,-1.000141 0.552197,0 1,0.447866 1,1.000141 z"
- style="fill:url(#radialGradient21565);fill-rule:nonzero;stroke:none"
- inkscape:connector-curvature="0" />
+ id="g16099"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-miterlimit:4"
+ transform="matrix(0.229703,0,0,0.229703,4.967081,4.244972)">
+ <radialGradient
+ id="radialGradient16101"
+ cx="20.892099"
+ cy="114.5684"
+ r="5.256"
+ fx="20.892099"
+ fy="114.5684"
+ gradientUnits="userSpaceOnUse">
+ <stop
+ offset="0"
+ style="stop-color:#F0F0F0"
+ id="stop16103" />
+ <stop
+ offset="1"
+ style="stop-color:#474747"
+ id="stop16105" />
+ </radialGradient>
+ <radialGradient
+ id="radialGradient16109"
+ cx="20.892099"
+ cy="64.567902"
+ r="5.257"
+ fx="20.892099"
+ fy="64.567902"
+ gradientUnits="userSpaceOnUse">
+ <stop
+ offset="0"
+ style="stop-color:#F0F0F0"
+ id="stop16111" />
+ <stop
+ offset="1"
+ style="stop-color:#474747"
+ id="stop16113" />
+ </radialGradient>
</g>
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 12.85355,31.53813 c 0,0.552274 -0.447803,0.99986 -1,0.99986 -0.552477,0 -1,-0.447865 -1,-0.99986 0,-0.552554 0.447803,-1.00014 1,-1.00014 0.552197,0 1,0.447866 1,1.00014 l 0,0 0,0 0,0 z"
+ id="path16107" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:url(#radialGradient21565);fill-rule:nonzero;stroke:none"
+ d="m 12.60355,31.288131 c 0,0.552274 -0.447803,0.999859 -1,0.999859 -0.552477,0 -1,-0.447865 -1,-0.999859 0,-0.552556 0.447803,-1.000141 1,-1.000141 0.552197,0 1,0.447866 1,1.000141 z"
+ id="path16117" />
+ </g>
+ <g
+ id="g16131"
+ transform="translate(105.39645,579.71201)"
+ style="display:inline">
<g
- style="display:inline"
- transform="translate(105.39645,579.71201)"
- id="g16131">
- <g
- id="g16133"
- style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-miterlimit:4"
- transform="matrix(0.229703,0,0,0.229703,4.967081,4.244972)">
- <radialGradient
- id="radialGradient16135"
- cx="20.892099"
- cy="114.5684"
- r="5.256"
- fx="20.892099"
- fy="114.5684"
- gradientUnits="userSpaceOnUse">
- <stop
- offset="0"
- style="stop-color:#F0F0F0"
- id="stop16137" />
- <stop
- offset="1"
- style="stop-color:#474747"
- id="stop16140" />
- </radialGradient>
- <radialGradient
- id="radialGradient16142"
- cx="20.892099"
- cy="64.567902"
- r="5.257"
- fx="20.892099"
- fy="64.567902"
- gradientUnits="userSpaceOnUse">
- <stop
- offset="0"
- style="stop-color:#F0F0F0"
- id="stop16144" />
- <stop
- offset="1"
- style="stop-color:#474747"
- id="stop16146" />
- </radialGradient>
- </g>
- <path
- style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline"
- d="m 12.85355,31.53813 c 0,0.552274 -0.447803,0.99986 -1,0.99986 -0.552477,0 -1,-0.447865 -1,-0.99986 0,-0.552554 0.447803,-1.00014 1,-1.00014 0.552197,0 1,0.447866 1,1.00014 l 0,0 0,0 0,0 z"
- id="path35139"
- inkscape:connector-curvature="0" />
- <path
- style="fill:url(#radialGradient21567);fill-rule:nonzero;stroke:none"
- d="m 12.60355,31.288131 c 0,0.552274 -0.447803,0.999859 -1,0.999859 -0.552477,0 -1,-0.447865 -1,-0.999859 0,-0.552556 0.447803,-1.000141 1,-1.000141 0.552197,0 1,0.447866 1,1.000141 z"
- id="path35141"
- inkscape:connector-curvature="0" />
+ transform="matrix(0.229703,0,0,0.229703,4.967081,4.244972)"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-miterlimit:4"
+ id="g16133">
+ <radialGradient
+ gradientUnits="userSpaceOnUse"
+ fy="114.5684"
+ fx="20.892099"
+ r="5.256"
+ cy="114.5684"
+ cx="20.892099"
+ id="radialGradient16135">
+ <stop
+ id="stop16137"
+ style="stop-color:#F0F0F0"
+ offset="0" />
+ <stop
+ id="stop16140"
+ style="stop-color:#474747"
+ offset="1" />
+ </radialGradient>
+ <radialGradient
+ gradientUnits="userSpaceOnUse"
+ fy="64.567902"
+ fx="20.892099"
+ r="5.257"
+ cy="64.567902"
+ cx="20.892099"
+ id="radialGradient16142">
+ <stop
+ id="stop16144"
+ style="stop-color:#F0F0F0"
+ offset="0" />
+ <stop
+ id="stop16146"
+ style="stop-color:#474747"
+ offset="1" />
+ </radialGradient>
</g>
+ <path
+ inkscape:connector-curvature="0"
+ id="path35139"
+ d="m 12.85355,31.53813 c 0,0.552274 -0.447803,0.99986 -1,0.99986 -0.552477,0 -1,-0.447865 -1,-0.99986 0,-0.552554 0.447803,-1.00014 1,-1.00014 0.552197,0 1,0.447866 1,1.00014 l 0,0 0,0 0,0 z"
+ style="display:inline;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path35141"
+ d="m 12.60355,31.288131 c 0,0.552274 -0.447803,0.999859 -1,0.999859 -0.552477,0 -1,-0.447865 -1,-0.999859 0,-0.552556 0.447803,-1.000141 1,-1.000141 0.552197,0 1,0.447866 1,1.000141 z"
+ style="fill:url(#radialGradient21567);fill-rule:nonzero;stroke:none" />
</g>
- <path
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 147.5,435 0,38.5 -30.5,0"
- style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- id="path21645"
- sodipodi:nodetypes="ccc"
- inkscape:connector-curvature="0" />
</g>
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc"
+ id="path21645"
+ style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 147.5,435 0,38.5 -30.5,0"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
</g>
+ </g>
+ <g
+ style="display:inline;enable-background:new"
+ id="g21572"
+ transform="translate(812,-202)"
+ inkscape:export-filename="C:\Documents and Settings\Pracowniaa\Moje dokumenty\Moje obrazy\BLENDER ICONS redesign\ver 2\IMAGE BROWSER ICONS.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <rect
+ ry="0"
+ rx="2.4004419"
+ y="430"
+ x="108"
+ height="48"
+ width="48"
+ id="rect21574"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;enable-background:accumulate" />
<g
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
+ id="g21576">
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;fill:url(#linearGradient21594);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ id="path21578"
+ sodipodi:nodetypes="cccccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
+ style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ id="path21580"
+ sodipodi:nodetypes="cccc" />
+ <path
+ inkscape:connector-curvature="0"
+ clip-path="url(#clipPath13106)"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccc"
+ id="path21582"
+ d="m 115,444 12,0 -1,-11 -11,11 z"
+ style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)" />
+ <path
+ inkscape:connector-curvature="0"
+ clip-path="none"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 117.5,443.75 9,-2.5 0,-6"
+ style="fill:none;stroke:url(#linearGradient21596);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path21584"
+ sodipodi:nodetypes="ccc" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccc"
+ id="path21586"
+ style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:connector-curvature="0"
+ clip-path="url(#clipPath13106)"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccc"
+ id="path21588"
+ d="m 116,443 11,1 -2,-10 -9,9 z"
+ style="display:inline;opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
+ id="path21590"
+ sodipodi:nodetypes="cccccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc"
+ id="path21592"
+ style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 147.5,435 0,38.5 -30.5,0"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ </g>
+ </g>
+ <g
+ transform="translate(4,0)"
+ id="g30382">
+ <g
+ id="g23655"
+ transform="translate(760,-154)">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path23657"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ style="display:inline;fill:url(#linearGradient30368);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccc"
+ id="path23659"
+ style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:connector-curvature="0"
+ style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)"
+ d="m 115,444 12,0 -1,-11 -11,11 z"
+ id="path23661"
+ sodipodi:nodetypes="cccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ clip-path="url(#clipPath13106)" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc"
+ id="path23663"
+ style="fill:none;stroke:url(#linearGradient30370);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 117.5,443.75 9,-2.5 0,-6"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ clip-path="none" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
+ style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ id="path23665"
+ sodipodi:nodetypes="cccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)"
+ d="m 116,443 11,1 -2,-10 -9,9 z"
+ id="path23667"
+ sodipodi:nodetypes="cccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ clip-path="url(#clipPath13106)" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccccc"
+ id="path23669"
+ d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 147.5,435 0,38.5 -30.5,0"
+ style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ id="path23671"
+ sodipodi:nodetypes="ccc" />
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;fill:#112b00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;enable-background:accumulate"
+ d="m 888,295 1,0 0,14 -1,0 0,-14 z"
+ id="path23675"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path23677"
+ d="m 900,294 1.00002,-1 0,14 -1.00002,0 0,-13 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#112b00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;enable-background:accumulate"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc"
+ id="path23679"
+ d="m 901.00003,292 0,2.25 -13.00002,2 0,-2.25 13.00002,-2 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:#112b00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;enable-background:accumulate" />
+ <g
+ id="g23681"
+ transform="matrix(1.1428564,0,0,1.2000001,822.71436,-355.40005)">
+ <ellipse
+ ry="2.25"
+ rx="4.5"
+ cy="554"
+ cx="53"
+ transform="matrix(0.7630859,-0.2494396,0.2996015,0.9926766,-151.92281,17.77746)"
+ id="path23683"
+ style="display:inline;overflow:visible;visibility:visible;fill:#112b00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;enable-background:accumulate" />
+ <ellipse
+ ry="2.25"
+ rx="4.5"
+ cy="554"
+ cx="53"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;filter:url(#filter20578);enable-background:accumulate"
+ id="path23685"
+ transform="matrix(0.3848865,-0.1700959,0.2278131,0.3626733,-93.107467,361.59408)"
+ inkscape:transform-center-y="0.3813435"
+ clip-path="url(#clipPath20586)" />
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.38999999;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;enable-background:accumulate"
+ d="m 901.00003,292 -1e-5,1 -13.00002,2 10e-6,-1 13.00002,-2 z"
+ id="path23694"
+ sodipodi:nodetypes="ccccc" />
+ <g
+ transform="matrix(1.1428564,0,0,1.2000001,834.71436,-357.40005)"
+ id="g23717">
+ <ellipse
+ ry="2.25"
+ rx="4.5"
+ cy="554"
+ cx="53"
+ style="display:inline;overflow:visible;visibility:visible;fill:#112b00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;enable-background:accumulate"
+ id="path23724"
+ transform="matrix(0.7630859,-0.2494396,0.2996015,0.9926766,-151.92281,17.77746)" />
+ <ellipse
+ ry="2.25"
+ rx="4.5"
+ cy="554"
+ cx="53"
+ clip-path="url(#clipPath20586)"
+ inkscape:transform-center-y="0.3813435"
+ transform="matrix(0.3848865,-0.1700959,0.2278131,0.3626733,-93.107467,361.59408)"
+ id="path23726"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;filter:url(#filter20578);enable-background:accumulate" />
+ </g>
+ </g>
+ <g
+ id="g23922"
+ transform="translate(-12,-220)"
+ style="display:inline;enable-background:new">
+ <g
+ style="display:inline"
+ id="g23924"
+ transform="translate(824,66)"
inkscape:export-filename="C:\Documents and Settings\Pracowniaa\Moje dokumenty\Moje obrazy\BLENDER ICONS redesign\ver 2\IMAGE BROWSER ICONS.png"
- transform="translate(808,-203)"
- id="g21572"
- style="display:inline;enable-background:new">
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
<rect
- style="opacity:0;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="rect21574"
- width="48"
- height="48"
- x="108"
- y="430"
+ ry="0"
rx="2.4004419"
- ry="0" />
+ y="430"
+ x="108"
+ height="48"
+ width="48"
+ id="rect23926"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;enable-background:accumulate" />
<g
- id="g21576">
+ id="g23928">
<path
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccccc"
- id="path21578"
+ inkscape:connector-curvature="0"
+ style="display:inline;fill:url(#linearGradient23978);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none"
d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
- style="fill:url(#linearGradient21594);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;display:inline"
- inkscape:connector-curvature="0" />
- <path
- sodipodi:nodetypes="cccc"
- id="path21580"
- style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
+ id="path23930"
+ sodipodi:nodetypes="cccccc"
inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- inkscape:connector-curvature="0" />
+ inkscape:export-ydpi="90" />
<path
- style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)"
- d="m 115,444 12,0 -1,-11 -11,11 z"
- id="path21582"
- sodipodi:nodetypes="cccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
+ inkscape:connector-curvature="0"
inkscape:export-ydpi="90"
- clip-path="url(#clipPath13106)"
- inkscape:connector-curvature="0" />
- <path
- sodipodi:nodetypes="ccc"
- id="path21584"
- style="fill:none;stroke:url(#linearGradient21596);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- d="m 117.5,443.75 9,-2.5 0,-6"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- clip-path="none"
- inkscape:connector-curvature="0" />
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
+ style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ id="path23932"
+ sodipodi:nodetypes="cccc" />
<path
+ inkscape:connector-curvature="0"
+ clip-path="url(#clipPath13106)"
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
- style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- id="path21586"
- sodipodi:nodetypes="cccccc"
- inkscape:connector-curvature="0" />
- <path
- style="opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline;filter:url(#filter63011)"
- d="m 116,443 11,1 -2,-10 -9,9 z"
- id="path21588"
sodipodi:nodetypes="cccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- clip-path="url(#clipPath13106)"
- inkscape:connector-curvature="0" />
+ id="path23934"
+ d="m 115,444 12,0 -1,-11 -11,11 z"
+ style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)" />
<path
+ inkscape:connector-curvature="0"
+ clip-path="none"
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 117.5,443.75 9,-2.5 0,-6"
+ style="fill:none;stroke:url(#linearGradient23980);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path23936"
+ sodipodi:nodetypes="ccc" />
+ <path
+ inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc"
- id="path21590"
- d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
- inkscape:connector-curvature="0" />
+ id="path23938"
+ style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
<path
+ inkscape:connector-curvature="0"
+ clip-path="url(#clipPath13106)"
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 147.5,435 0,38.5 -30.5,0"
- style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- id="path21592"
+ sodipodi:nodetypes="cccc"
+ id="path23940"
+ d="m 116,443 11,1 -2,-10 -9,9 z"
+ style="display:inline;opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
+ id="path23942"
+ sodipodi:nodetypes="cccccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc"
- inkscape:connector-curvature="0" />
+ id="path23944"
+ style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 147.5,435 0,38.5 -30.5,0"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
</g>
</g>
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccc"
+ id="path23946"
+ d="m 952,530 0,10 1,0 1,0 11,0 1,0 1,0 0,-10 -15,0 z m 1,2 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z m -12,3 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z m -12,3 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z"
+ style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" />
+ <rect
+ transform="scale(1,-1)"
+ style="fill:url(#linearGradient23982);fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="rect23948"
+ width="13"
+ height="5.5"
+ x="953"
+ y="-524" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path23952"
+ transform="translate(76,0)"
+ d="m 876,514 0,17 15,0 0,-17 -1,0 0,1 -1,0 0,-1 -11,0 0,1 -1,0 0,-1 -1,0 z m 1,3 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z m -12,3 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z m -12,3 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z m -12,3 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z m -12,3 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z"
+ style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccc"
+ style="fill:url(#linearGradient23986);fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 952,507 3,0 0,3 9,0 0,-3 3,0 0,7 -15,0 0,-7 z m 1,0 1,0 -1,0 z m 0,1 0,1 1,0 0,-1 -1,0 z m 0,3 0,1 1,0 0,-1 -1,0 z m 12,-4 1,0 -1,0 z m 0,1 0,1 1,0 0,-1 -1,0 z m 0,3 0,1 1,0 0,-1 -1,0 z"
+ id="path23954" />
+ <rect
+ transform="matrix(0,1,1,0,0,0)"
+ ry="0"
+ y="955"
+ x="507"
+ height="9"
+ width="3"
+ id="rect23956"
+ style="fill:url(#linearGradient23988);fill-opacity:1;fill-rule:nonzero;stroke:none" />
+ <rect
+ style="fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="rect23958"
+ width="9"
+ height="9"
+ x="512"
+ y="955"
+ ry="0"
+ transform="matrix(0,1,1,0,0,0)" />
+ <rect
+ transform="matrix(0,1,1,0,0,0)"
+ ry="0"
+ y="955"
+ x="523"
+ height="9"
+ width="9"
+ id="rect23960"
+ style="fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none" />
+ <circle
+ r="8"
+ cy="118"
+ cx="132"
+ transform="matrix(0,-0.5624971,0.5624971,0,893.12531,590.74965)"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path23962"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <circle
+ r="8"
+ cy="118"
+ cx="132"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+ id="path23964"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ transform="matrix(0,-0.5624964,0.5624964,0,893.12545,601.74956)" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccc"
+ id="path23966"
+ d="m 961.00001,519.00005 -3,0 0,-0.99992 0.99994,0 6e-5,-2.00008 -1,0 0,-1 1,0 0,-1 1.00006,0 0,4.00008 0.99994,0 0,0.99992 z" />
+ <path
+ inkscape:connector-curvature="0"
+ d="m 958,525 0,1 2,0 0,-1 -2,0 z m 2,1 0,1 1,0 0,-1 -1,0 z m 0,1 -1,0 0,1 1,0 0,-1 z m -1,1 -1,0 0,1 0,1 3,0 0,-1 -2,0 0,-1 z"
+ id="path23968" />
+ <rect
+ style="fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="rect23970"
+ width="6"
+ height="9"
+ x="534"
+ y="955"
+ ry="0"
+ transform="matrix(0,1,1,0,0,0)" />
+ <g
+ clip-path="url(#clipPath23877)"
+ id="g23972">
+ <circle
+ r="8"
+ cy="118"
+ cx="132"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+ id="path23974"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ transform="matrix(0,-0.5624964,0.5624964,0,893.12545,612.74956)" />
+ <path
+ inkscape:connector-curvature="0"
+ d="m 958,536 0,1 2,0 0,-1 -2,0 z m 2,1 0,1 1,0 0,-1 -1,0 z m 0,1 -1,0 0,1 1,0 0,-1 z m 0,1 0,1 1,0 0,-1 -1,0 z m 0,1 -2,0 0,1 2,0 0,-1 z"
+ id="path23976" />
+ </g>
+ </g>
+ <g
+ transform="translate(212,88)"
+ id="g45475"
+ style="display:inline;enable-background:new">
<g
- id="g30382">
+ style="display:inline"
+ id="g22242"
+ transform="translate(696,-194)"
+ inkscape:export-filename="C:\Documents and Settings\Pracowniaa\Moje dokumenty\Moje obrazy\BLENDER ICONS redesign\ver 2\IMAGE BROWSER ICONS.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <rect
+ ry="0"
+ rx="2.4004419"
+ y="430"
+ x="108"
+ height="48"
+ width="48"
+ id="rect22244"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;enable-background:accumulate" />
<g
- transform="translate(760,-154)"
- id="g23655">
+ id="g22246">
<path
- style="fill:url(#linearGradient30368);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;display:inline"
+ inkscape:connector-curvature="0"
+ style="display:inline;fill:url(#linearGradient22274);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none"
d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
- id="path23657"
+ id="path22249"
sodipodi:nodetypes="cccccc"
inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- inkscape:connector-curvature="0" />
+ inkscape:export-ydpi="90" />
<path
+ inkscape:connector-curvature="0"
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- id="path23659"
- sodipodi:nodetypes="cccc"
- inkscape:connector-curvature="0" />
+ id="path22251"
+ sodipodi:nodetypes="cccc" />
<path
+ inkscape:connector-curvature="0"
clip-path="url(#clipPath13106)"
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
sodipodi:nodetypes="cccc"
- id="path23661"
+ id="path22253"
d="m 115,444 12,0 -1,-11 -11,11 z"
- style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)"
- inkscape:connector-curvature="0" />
+ style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)" />
<path
+ inkscape:connector-curvature="0"
clip-path="none"
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
d="m 117.5,443.75 9,-2.5 0,-6"
- style="fill:none;stroke:url(#linearGradient30370);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- id="path23663"
- sodipodi:nodetypes="ccc"
- inkscape:connector-curvature="0" />
+ style="fill:none;stroke:url(#linearGradient22276);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path22264"
+ sodipodi:nodetypes="ccc" />
<path
+ inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc"
- id="path23665"
+ id="path22266"
style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- inkscape:connector-curvature="0" />
+ inkscape:export-ydpi="90" />
<path
+ inkscape:connector-curvature="0"
clip-path="url(#clipPath13106)"
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
sodipodi:nodetypes="cccc"
- id="path23667"
+ id="path22268"
d="m 116,443 11,1 -2,-10 -9,9 z"
- style="opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline;filter:url(#filter63011)"
- inkscape:connector-curvature="0" />
+ style="display:inline;opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)" />
<path
+ inkscape:connector-curvature="0"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
- id="path23669"
+ id="path22270"
sodipodi:nodetypes="cccccc"
inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- inkscape:connector-curvature="0" />
+ inkscape:export-ydpi="90" />
<path
+ inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc"
- id="path23671"
+ id="path22272"
style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
d="m 147.5,435 0,38.5 -30.5,0"
inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- inkscape:connector-curvature="0" />
- </g>
- <path
- sodipodi:nodetypes="ccccc"
- id="path23675"
- d="m 888,295 1,0 0,14 -1,0 0,-14 z"
- style="fill:#112b00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- inkscape:connector-curvature="0" />
- <path
- sodipodi:nodetypes="ccccc"
- style="fill:#112b00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- d="m 900,294 1.00002,-1 0,14 -1.00002,0 0,-13 z"
- id="path23677"
- inkscape:connector-curvature="0" />
- <path
- style="fill:#112b00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- d="m 901.00003,292 0,2.25 -13.00002,2 0,-2.25 13.00002,-2 z"
- id="path23679"
- sodipodi:nodetypes="ccccc"
- inkscape:connector-curvature="0" />
- <g
- transform="matrix(1.1428564,0,0,1.2000001,822.71436,-355.40005)"
- id="g23681">
- <path
- sodipodi:type="arc"
- style="fill:#112b00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="path23683"
- sodipodi:cx="53"
- sodipodi:cy="554"
- sodipodi:rx="4.5"
- sodipodi:ry="2.25"
- d="m 57.5,554 c 0,1.24264 -2.014719,2.25 -4.5,2.25 -2.485281,0 -4.5,-1.00736 -4.5,-2.25 0,-1.24264 2.014719,-2.25 4.5,-2.25 2.485281,0 4.5,1.00736 4.5,2.25 z"
- transform="matrix(0.7630859,-0.2494396,0.2996015,0.9926766,-151.92281,17.77746)" />
- <path
- clip-path="url(#clipPath20586)"
- inkscape:transform-center-y="0.3813435"
- transform="matrix(0.3848865,-0.1700959,0.2278131,0.3626733,-93.107467,361.59408)"
- d="m 57.5,554 c 0,1.24264 -2.014719,2.25 -4.5,2.25 -2.485281,0 -4.5,-1.00736 -4.5,-2.25 0,-1.24264 2.014719,-2.25 4.5,-2.25 2.485281,0 4.5,1.00736 4.5,2.25 z"
- sodipodi:ry="2.25"
- sodipodi:rx="4.5"
- sodipodi:cy="554"
- sodipodi:cx="53"
- id="path23685"
- style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter20578);enable-background:accumulate"
- sodipodi:type="arc" />
- </g>
- <path
- sodipodi:nodetypes="ccccc"
- id="path23694"
- d="m 901.00003,292 -1e-5,1 -13.00002,2 10e-6,-1 13.00002,-2 z"
- style="opacity:0.38999999;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- inkscape:connector-curvature="0" />
- <g
- id="g23717"
- transform="matrix(1.1428564,0,0,1.2000001,834.71436,-357.40005)">
- <path
- transform="matrix(0.7630859,-0.2494396,0.2996015,0.9926766,-151.92281,17.77746)"
- d="m 57.5,554 c 0,1.24264 -2.014719,2.25 -4.5,2.25 -2.485281,0 -4.5,-1.00736 -4.5,-2.25 0,-1.24264 2.014719,-2.25 4.5,-2.25 2.485281,0 4.5,1.00736 4.5,2.25 z"
- sodipodi:ry="2.25"
- sodipodi:rx="4.5"
- sodipodi:cy="554"
- sodipodi:cx="53"
- id="path23724"
- style="fill:#112b00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- sodipodi:type="arc" />
- <path
- sodipodi:type="arc"
- style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter20578);enable-background:accumulate"
- id="path23726"
- sodipodi:cx="53"
- sodipodi:cy="554"
- sodipodi:rx="4.5"
- sodipodi:ry="2.25"
- d="m 57.5,554 c 0,1.24264 -2.014719,2.25 -4.5,2.25 -2.485281,0 -4.5,-1.00736 -4.5,-2.25 0,-1.24264 2.014719,-2.25 4.5,-2.25 2.485281,0 4.5,1.00736 4.5,2.25 z"
- transform="matrix(0.3848865,-0.1700959,0.2278131,0.3626733,-93.107467,361.59408)"
- inkscape:transform-center-y="0.3813435"
- clip-path="url(#clipPath20586)" />
- </g>
- </g>
- <g
- style="display:inline;enable-background:new"
- transform="translate(-16,-220)"
- id="g23922">
- <g
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Pracowniaa\Moje dokumenty\Moje obrazy\BLENDER ICONS redesign\ver 2\IMAGE BROWSER ICONS.png"
- transform="translate(824,66)"
- id="g23924"
- style="display:inline">
- <rect
- style="opacity:0;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="rect23926"
- width="48"
- height="48"
- x="108"
- y="430"
- rx="2.4004419"
- ry="0" />
- <g
- id="g23928">
- <path
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccccc"
- id="path23930"
- d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
- style="fill:url(#linearGradient23978);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;display:inline"
- inkscape:connector-curvature="0" />
- <path
- sodipodi:nodetypes="cccc"
- id="path23932"
- style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- inkscape:connector-curvature="0" />
- <path
- style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)"
- d="m 115,444 12,0 -1,-11 -11,11 z"
- id="path23934"
- sodipodi:nodetypes="cccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- clip-path="url(#clipPath13106)"
- inkscape:connector-curvature="0" />
- <path
- sodipodi:nodetypes="ccc"
- id="path23936"
- style="fill:none;stroke:url(#linearGradient23980);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- d="m 117.5,443.75 9,-2.5 0,-6"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- clip-path="none"
- inkscape:connector-curvature="0" />
- <path
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
- style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- id="path23938"
- sodipodi:nodetypes="cccccc"
- inkscape:connector-curvature="0" />
- <path
- style="opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline;filter:url(#filter63011)"
- d="m 116,443 11,1 -2,-10 -9,9 z"
- id="path23940"
- sodipodi:nodetypes="cccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- clip-path="url(#clipPath13106)"
- inkscape:connector-curvature="0" />
- <path
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccccc"
- id="path23942"
- d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
- inkscape:connector-curvature="0" />
- <path
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 147.5,435 0,38.5 -30.5,0"
- style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- id="path23944"
- sodipodi:nodetypes="ccc"
- inkscape:connector-curvature="0" />
- </g>
- </g>
- <path
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
- d="m 952,530 0,10 1,0 1,0 11,0 1,0 1,0 0,-10 -15,0 z m 1,2 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z m -12,3 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z m -12,3 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z"
- id="path23946"
- sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccc"
- inkscape:connector-curvature="0" />
- <rect
- y="-524"
- x="953"
- height="5.5"
- width="13"
- id="rect23948"
- style="fill:url(#linearGradient23982);fill-opacity:1;fill-rule:nonzero;stroke:none"
- transform="scale(1,-1)" />
- <path
- style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
- d="m 876,514 0,17 15,0 0,-17 -1,0 0,1 -1,0 0,-1 -11,0 0,1 -1,0 0,-1 -1,0 z m 1,3 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z m -12,3 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z m -12,3 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z m -12,3 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z m -12,3 1,0 0,1 -1,0 0,-1 z m 12,0 1,0 0,1 -1,0 0,-1 z"
- transform="translate(76,0)"
- id="path23952"
- inkscape:connector-curvature="0" />
- <path
- id="path23954"
- d="m 952,507 3,0 0,3 9,0 0,-3 3,0 0,7 -15,0 0,-7 z m 1,0 1,0 -1,0 z m 0,1 0,1 1,0 0,-1 -1,0 z m 0,3 0,1 1,0 0,-1 -1,0 z m 12,-4 1,0 -1,0 z m 0,1 0,1 1,0 0,-1 -1,0 z m 0,3 0,1 1,0 0,-1 -1,0 z"
- style="fill:url(#linearGradient23986);fill-opacity:1;fill-rule:nonzero;stroke:none"
- sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccc"
- inkscape:connector-curvature="0" />
- <rect
- style="fill:url(#linearGradient23988);fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="rect23956"
- width="3"
- height="9"
- x="507"
- y="955"
- ry="0"
- transform="matrix(0,1,1,0,0,0)" />
- <rect
- transform="matrix(0,1,1,0,0,0)"
- ry="0"
- y="955"
- x="512"
- height="9"
- width="9"
- id="rect23958"
- style="fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none" />
- <rect
- style="fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="rect23960"
- width="9"
- height="9"
- x="523"
- y="955"
- ry="0"
- transform="matrix(0,1,1,0,0,0)" />
- <path
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
- d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z"
- sodipodi:ry="8"
- sodipodi:rx="8"
- sodipodi:cy="118"
- sodipodi:cx="132"
- id="path23962"
- style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
- sodipodi:type="arc"
- transform="matrix(0,-0.5624971,0.5624971,0,893.12531,590.74965)" />
- <path
- transform="matrix(0,-0.5624964,0.5624964,0,893.12545,601.74956)"
- sodipodi:type="arc"
- style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path23964"
- sodipodi:cx="132"
- sodipodi:cy="118"
- sodipodi:rx="8"
- sodipodi:ry="8"
- d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90" />
- <path
- d="m 961.00001,519.00005 -3,0 0,-0.99992 0.99994,0 6e-5,-2.00008 -1,0 0,-1 1,0 0,-1 1.00006,0 0,4.00008 0.99994,0 0,0.99992 z"
- id="path23966"
- sodipodi:nodetypes="ccccccccccccc"
- inkscape:connector-curvature="0" />
- <path
- id="path23968"
- d="m 958,525 0,1 2,0 0,-1 -2,0 z m 2,1 0,1 1,0 0,-1 -1,0 z m 0,1 -1,0 0,1 1,0 0,-1 z m -1,1 -1,0 0,1 0,1 3,0 0,-1 -2,0 0,-1 z"
- inkscape:connector-curvature="0" />
- <rect
- transform="matrix(0,1,1,0,0,0)"
- ry="0"
- y="955"
- x="534"
- height="9"
- width="6"
- id="rect23970"
- style="fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none" />
- <g
- id="g23972"
- clip-path="url(#clipPath23877)">
- <path
- transform="matrix(0,-0.5624964,0.5624964,0,893.12545,612.74956)"
- sodipodi:type="arc"
- style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path23974"
- sodipodi:cx="132"
- sodipodi:cy="118"
- sodipodi:rx="8"
- sodipodi:ry="8"
- d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
- inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
- <path
- id="path23976"
- d="m 958,536 0,1 2,0 0,-1 -2,0 z m 2,1 0,1 1,0 0,-1 -1,0 z m 0,1 -1,0 0,1 1,0 0,-1 z m 0,1 0,1 1,0 0,-1 -1,0 z m 0,1 -2,0 0,1 2,0 0,-1 z"
- inkscape:connector-curvature="0" />
</g>
</g>
<g
- style="display:inline;enable-background:new"
- id="g45475"
- transform="translate(208,88)">
- <g
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Pracowniaa\Moje dokumenty\Moje obrazy\BLENDER ICONS redesign\ver 2\IMAGE BROWSER ICONS.png"
- transform="translate(696,-194)"
- id="g22242"
- style="display:inline">
- <rect
- style="opacity:0;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="rect22244"
- width="48"
- height="48"
- x="108"
- y="430"
- rx="2.4004419"
- ry="0" />
- <g
- id="g22246">
- <path
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccccc"
- id="path22249"
- d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
- style="fill:url(#linearGradient22274);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;display:inline"
- inkscape:connector-curvature="0" />
- <path
- sodipodi:nodetypes="cccc"
- id="path22251"
- style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- inkscape:connector-curvature="0" />
- <path
- style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011)"
- d="m 115,444 12,0 -1,-11 -11,11 z"
- id="path22253"
- sodipodi:nodetypes="cccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- clip-path="url(#clipPath13106)"
- inkscape:connector-curvature="0" />
- <path
- sodipodi:nodetypes="ccc"
- id="path22264"
- style="fill:none;stroke:url(#linearGradient22276);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- d="m 117.5,443.75 9,-2.5 0,-6"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- clip-path="none"
- inkscape:connector-curvature="0" />
- <path
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
- style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- id="path22266"
- sodipodi:nodetypes="cccccc"
- inkscape:connector-curvature="0" />
- <path
- style="opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline;filter:url(#filter63011)"
- d="m 116,443 11,1 -2,-10 -9,9 z"
- id="path22268"
- sodipodi:nodetypes="cccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- clip-path="url(#clipPath13106)"
- inkscape:connector-curvature="0" />
- <path
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccccc"
- id="path22270"
- d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
- inkscape:connector-curvature="0" />
- <path
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 147.5,435 0,38.5 -30.5,0"
- style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- id="path22272"
- sodipodi:nodetypes="ccc"
- inkscape:connector-curvature="0" />
- </g>
- </g>
- <g
- transform="matrix(0.5406242,0,0,0.5829534,814.13667,247.65542)"
- inkscape:label="Layer 1"
- id="g21517">
- <path
- sodipodi:type="arc"
- style="opacity:0.54857142;fill:url(#radialGradient21442);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="path35486"
- sodipodi:cx="28.019106"
- sodipodi:cy="38.98439"
- sodipodi:rx="15.467961"
- sodipodi:ry="5.3033009"
- d="m 43.487067,38.98439 c 0,2.928932 -6.925242,5.303301 -15.467961,5.303301 -8.542719,0 -15.467961,-2.374369 -15.467961,-5.303301 0,-2.928932 6.925242,-5.303301 15.467961,-5.303301 8.542719,0 15.467961,2.374369 15.467961,5.303301 z"
- transform="matrix(1.274286,0,0,1.377124,-7.569123,-16.70193)" />
- <path
- style="fill:#f57900;fill-rule:evenodd;stroke:#aa4400;stroke-width:1.7812928;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
- id="path2482"
- d="m 16.048489,28.093447 c 0.0098,0.576682 0.196474,1.697902 0.471116,2.577425 0.581566,1.854137 1.56684,3.572658 2.939126,5.086496 1.407488,1.553118 3.138519,2.803227 5.139315,3.68976 2.105357,0.931573 4.384795,1.407488 6.750134,1.403741 2.365339,-0.005 4.644601,-0.488686 6.74896,-1.427017 2.00002,-0.895288 3.731043,-2.148391 5.13754,-3.705517 1.369207,-1.519844 2.352576,-3.241114 2.934089,-5.096258 0.294262,-0.938353 0.476921,-1.889392 0.553238,-2.845308 0.07331,-0.939306 0.04204,-1.883511 -0.09183,-2.823792 -0.259981,-1.835599 -0.896294,-3.556847 -1.872652,-5.12758 -0.895541,-1.441699 -2.047808,-2.70454 -3.417268,-3.766975 0,0 0.002,-0.002 0.002,-0.002 0,0 -13.828458,-10.6197195 -13.828458,-10.6197195 -0.01176,-0.00978 -0.02252,-0.019551 -0.03529,-0.028344 -0.909003,-0.6959264 -3.879837,-0.7738945 -4.87679,-0.075035 -1.01067,0.7057021 -1.091821,1.8092613 -0.195527,2.5482146 1.899775,1.4997633 2.656207,2.2801589 4.566507,3.7797379 0,0 -14.852491,0.167033 -14.852491,0.167033 -1.994685,0 -3.1682609,0.947915 -3.4153947,2.333683 -0.2180771,1.222836 0.7479213,2.738129 2.4800217,2.738129 2.956573,0.0039 5.942111,-0.0069 8.909215,-0.01272 0,0 -16.01999,12.453223 -16.01999,12.453223 -0.020527,0.01564 -0.041053,0.02933 -0.06158,0.04497 -1.4974197,1.148389 -1.9831951,3.059322 -1.0399808,4.268393 0.9598323,1.22959 2.9977653,1.230588 4.5147288,0.006 0,0 8.677593,-7.102098 8.677593,-7.102098 0,0 -0.12511,0.959824 -0.116333,1.535532 l 1e-6,2.6e-5 0,0 0,0 z"
- sodipodi:nodetypes="csssssssssscccsscccscccssccc"
- inkscape:connector-curvature="0" />
- <path
- sodipodi:type="arc"
- style="fill:url(#linearGradient21444);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="path39153"
- sodipodi:cx="31.1875"
- sodipodi:cy="25.75"
- sodipodi:rx="11.5625"
- sodipodi:ry="10.125"
- d="m 42.75,25.75 c 0,5.591883 -5.176708,10.125 -11.5625,10.125 -6.385792,0 -11.5625,-4.533117 -11.5625,-10.125 0,-5.591883 5.176708,-10.125 11.5625,-10.125 6.385792,0 11.5625,4.533117 11.5625,10.125 z"
- transform="matrix(0.8018194,0,0,0.8471126,6.257567,4.5089892)" />
- <path
- sodipodi:nodetypes="csssssscssscsssccssscscccsccssssccscsscccssssc"
- id="path21414"
- d="m 25.8125,6.40625 c -0.334829,4.572e-4 -0.72202,0.089606 -0.90625,0.21875 4.5e-4,0.010412 4.5e-4,0.020838 0,0.03125 -0.212626,0.1484635 -0.188235,0.1956271 -0.1875,0.1875 0.0092,0.010621 -0.0072,-4.246e-4 0.03125,0.03125 0.01962,0.00828 0.03527,0.012546 0.0625,0.03125 0.01676,0.01151 0.01357,0.014555 0.03125,0.03125 0.193748,0.1576058 4.954976,4.005164 4.954976,4.005164 0.489837,0.39864 0.677395,1.066352 0.46875,1.65625 -0.115662,0.32703 -0.422813,0.541217 -0.6875,0.59375 -0.264687,0.05253 -0.498447,0.03054 -0.71875,0.03125 -5.639658,0.05119 -16.87989,0.03851 -16.87989,0.03851 -0.4102,2.75e-4 -0.935835,0.115997 -1.34375,0.34375 -0.407915,0.227753 -0.6637862,0.523861 -0.6875002,0.90625 -0.024417,0.393728 0.098829,0.605767 0.3437502,0.78125 0.244921,0.175483 0.614978,0.25 0.875,0.25 0,0 8.8125,0 8.8125,0 0.600305,-7.28e-4 1.223895,0.311058 1.4375,0.9375 0.04676,0.137121 0.06335,0.269976 0.0625,0.40625 -8.49e-4,0.136274 -0.02214,0.268794 -0.09375,0.375 -0.143211,0.212412 -0.319507,0.298568 -0.5,0.4375 0,0 -15.7871819,12.746851 -15.856336,12.800078 C 5.0310984,30.500117 5,30.53125 5,30.53125 5.0100745,30.519077 5.000335,30.499512 5,30.5 L 4.8125,30.3125 c 0.012336,0.02165 0.014481,0.03307 0.03125,0.0625 0.063558,0.0774 0.125,0.15625 0.125,0.15625 -0.00585,0.0056 -0.031233,0.03124 -0.03125,0.03125 0,0 -0.043442,-0.09921 -0.09375,-0.1875 0.037843,0.09884 0.06253,0.218739 0.0625,0.21875 -0.4662091,0.37119 -0.7783348,0.889746 -0.875,1.28125 -0.1043319,0.422581 -0.046,0.62455 0.125,0.84375 0.2999827,0.384295 1.3975356,0.595547 2.40625,-0.21875 0,0 8.65625,-7.09375 8.65625,-7.09375 0.473718,-0.387074 1.1446,-0.458625 1.6875,-0.15625 0.544608,0.303331 0.798054,0.927572 0.71875,1.53125 0,0 -0.0626,0.908319 -0.0625,1.25 2e-6,0.0085 -1.19e-4,0.02348 0,0.03125 0.192796,2.523718 1.400736,4.762818 3.03125,6.71875 2.801818,3.089095 6.627659,4.401619 10.75,4.5625 4.113324,-0.043 7.964529,-1.606111 10.75,-4.625 2.546631,-3.125326 3.513872,-6.363859 3.15625,-9.375 C 44.891575,22.325847 43.222923,19.516566 40.4375,17.25 35.951885,13.599946 31.206991,10.168434 26.59375,6.625 26.57515,6.610386 26.56455,6.59802 26.5625,6.59375 26.43835,6.498703 26.144223,6.4057899 25.8125,6.40625 z"
- style="opacity:0.4857143;fill:none;stroke:url(#linearGradient21446);stroke-width:1.7812928;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1"
- inkscape:connector-curvature="0" />
- <path
- style="fill:#3465a4;fill-rule:evenodd;stroke:none"
- id="path2478"
- d="m 25.708956,26.064593 c 0.07649,-1.397943 0.759369,-2.631914 1.78592,-3.505519 1.010226,-0.858782 2.366788,-1.383145 3.848625,-1.383145 1.480894,0 2.837456,0.524363 3.847446,1.383145 1.027685,0.873605 1.709741,2.106651 1.787122,3.504594 0.07927,1.438713 -0.49591,2.77459 -1.504012,3.764001 -1.027686,1.007933 -2.493008,1.640678 -4.130556,1.640678 -1.63849,0 -3.103814,-0.632745 -4.131451,-1.640678 -1.00914,-0.989411 -1.58234,-2.325288 -1.503094,-3.763076 l 0,0 0,0 0,0 z"
- inkscape:connector-curvature="0" />
- <path
- style="opacity:0.51999996;fill:url(#radialGradient21448);fill-opacity:1;fill-rule:evenodd;stroke:none"
- d="m 25.8125,6.03125 c -0.404852,5.53e-4 -2.204797,-0.059029 -2.48145,0.1349032 -0.280209,0.195652 -0.335403,0.376484 -0.34375,0.46875 -0.0083,0.092266 -0.01539,0.17648 0.1875,0.34375 0.01899,0.015735 0.04457,0.014317 0.0625,0.03125 0.124258,0.101028 4.748869,4.1248618 4.748869,4.1248618 0.373658,0.304091 0.504393,0.795817 0.34375,1.25 -0.160635,0.454191 -0.580748,0.373449 -1.0625,0.375 -5.634142,0.05114 -15.087371,-0.129601 -15.087371,-0.129601 -0.952967,6.38e-4 -2.339958,0.524782 -2.4062504,1.59375 -0.063562,1.024947 0.9247974,1.4375 1.5937504,1.4375 0,-1e-6 8.8125,0 8.8125,0 0.488364,-5.92e-4 0.936141,0.225277 1.09375,0.6875 0.157609,0.462231 -0.01926,0.514621 -0.40625,0.8125 0,0 -16.086298,13.088586 -16.086298,13.088586 -0.00142,0.0014 -0.029829,-0.0014 -0.03125,0 -0.064037,0.04879 -0.054226,0.04875 -0.03125,0.03125 -0.5536758,0.424619 -0.9087886,1.004019 -1.03125,1.5 -0.1224536,0.495981 -0.04661,0.856152 0.1875,1.15625 0.4788333,0.613413 1.777612,0.754857 2.90625,-0.15625 1e-7,10e-7 8.65625,-7.09375 8.65625,-7.09375 0.361955,-0.295753 0.872897,-0.352437 1.28125,-0.125 0.408345,0.227436 0.623381,0.692814 0.5625,1.15625 0,-1e-6 -0.0997,0.953636 -0.09375,1.34375 0.09498,1.301756 0.451616,2.521825 0.989039,3.664234 C 20.799917,36.321089 27.770982,19.392853 44.1875,21.03125 43.339652,19.54368 42.151282,18.185293 40.65625,16.96875 36.159865,13.309932 31.42016,9.882897 26.8125,6.34375 26.805335,6.338858 26.788292,6.317553 26.78125,6.3125 26.570707,6.151312 26.216591,6.030689 25.8125,6.03125 z"
- id="path39166"
- sodipodi:nodetypes="csssscsccsscsccssssscsscccsssc"
- inkscape:connector-curvature="0" />
- </g>
- </g>
- <g
- transform="translate(162,248)"
- id="g24847"
- style="opacity:0.5">
- <path
- d="m 806.5,114.5 c 0,2.25 2,4 4,4 l 30,0 c 0.4163,0 1,-0.5 1,-1 l 0,-29 c 0,-0.5 -0.5,-1 -1,-1 l -21.02773,0.04419 C 818.98721,87.545209 818.5,87 818.5,86.5 l 0,-3 c 0,-0.5 -0.5,-1 -1,-1 l -10,0 c -0.5,0 -1,0.5 -1,1 l 0,31 z"
- id="path24849"
- style="fill:url(#linearGradient24867);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- sodipodi:nodetypes="ccccccssssccc"
- inkscape:connector-curvature="0" />
+ id="g21517"
+ inkscape:label="Layer 1"
+ transform="matrix(0.5406242,0,0,0.5829534,814.13667,247.65542)">
+ <ellipse
+ ry="5.3033009"
+ rx="15.467961"
+ cy="38.98439"
+ cx="28.019106"
+ transform="matrix(1.274286,0,0,1.377124,-7.569123,-16.70193)"
+ id="path35486"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.54857142;fill:url(#radialGradient21442);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
<path
- sodipodi:nodetypes="cccccccccccccccccccccccccccccc"
- d="m 807.5,89.5 33,0 m -33,12 33,0 m -33,-4 33,0 m -33,-6 33,0 m -33,20 33,0 m -33,2 33,0 m -33,-18 33,0 m -33,-2 33,0 m -20,-6 -13,0 m 0,20 33,0 m -33,-2 33,0 m -33,-2 33,0 m -33,-4 33,0 m -33,10 33,0 m -33,6 33,0"
- style="opacity:0.07999998;fill:url(#linearGradient24869);fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
- id="path24851"
- inkscape:connector-curvature="0" />
- <path
- style="fill:url(#linearGradient24871);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- d="m 844,118.5 c 3.5,0 5.5,-2 5.5,-5.5 l 0,-18.5 c -11.75604,-1.11e-4 -23.91623,0 -35.5,0 l 0,19.5 c 0,4.5 -7,4 -7,0.25 0,2 2.00002,3.73529 3,3.75 l 34,0.5 z"
- id="path24853"
- sodipodi:nodetypes="csccsczc"
- inkscape:export-filename="/home/jimmac/ximian_art/icons/nautilus/suse93/gnome-fs-directory.png"
- inkscape:export-xdpi="74.800003"
- inkscape:export-ydpi="74.800003"
- inkscape:connector-curvature="0" />
- <path
- sodipodi:nodetypes="ccssccc"
- style="opacity:0.7;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path24855"
- d="m 807,87 12,0 0.0385,-3.33333 C 819.04423,83.166705 818.97512,83 818.5,83 l -10.92308,0 c -0.47512,0 -0.53846,0.16667 -0.53846,0.66667 L 807,87 z"
- inkscape:connector-curvature="0" />
- <path
- id="path24857"
- style="opacity:0.1;fill:none;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
- d="m 840.5,89 0,4.5"
- sodipodi:nodetypes="cc"
- inkscape:connector-curvature="0" />
- <path
- sodipodi:nodetypes="ccc"
- d="m 848.5,95.5 0,18 c 0,1.25 0.25,3 -1.25,4"
- style="opacity:0.1;fill:none;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
- id="path24859"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="csssssssssscccsscccscccssccc"
+ d="m 16.048489,28.093447 c 0.0098,0.576682 0.196474,1.697902 0.471116,2.577425 0.581566,1.854137 1.56684,3.572658 2.939126,5.086496 1.407488,1.553118 3.138519,2.803227 5.139315,3.68976 2.105357,0.931573 4.384795,1.407488 6.750134,1.403741 2.365339,-0.005 4.644601,-0.488686 6.74896,-1.427017 2.00002,-0.895288 3.731043,-2.148391 5.13754,-3.705517 1.369207,-1.519844 2.352576,-3.241114 2.934089,-5.096258 0.294262,-0.938353 0.476921,-1.889392 0.553238,-2.845308 0.07331,-0.939306 0.04204,-1.883511 -0.09183,-2.823792 -0.259981,-1.835599 -0.896294,-3.556847 -1.872652,-5.12758 -0.895541,-1.441699 -2.047808,-2.70454 -3.417268,-3.766975 0,0 0.002,-0.002 0.002,-0.002 0,0 -13.828458,-10.6197195 -13.828458,-10.6197195 -0.01176,-0.00978 -0.02252,-0.019551 -0.03529,-0.028344 -0.909003,-0.6959264 -3.879837,-0.7738945 -4.87679,-0.075035 -1.01067,0.7057021 -1.091821,1.8092613 -0.195527,2.5482146 1.899775,1.4997633 2.656207,2.2801589 4.566507,3.7797379 0,0 -14.852491,0.167033 -14.852491,0.167033 -1.994685,0 -3.1682609,0.947915 -3.4153947,2.333683 -0.2180771,1.222836 0.7479213,2.738129 2.4800217,2.738129 2.956573,0.0039 5.942111,-0.0069 8.909215,-0.01272 0,0 -16.01999,12.453223 -16.01999,12.453223 -0.020527,0.01564 -0.041053,0.02933 -0.06158,0.04497 -1.4974197,1.148389 -1.9831951,3.059322 -1.0399808,4.268393 0.9598323,1.22959 2.9977653,1.230588 4.5147288,0.006 0,0 8.677593,-7.102098 8.677593,-7.102098 0,0 -0.12511,0.959824 -0.116333,1.535532 l 1e-6,2.6e-5 0,0 0,0 z"
+ id="path2482"
+ style="fill:#f57900;fill-rule:evenodd;stroke:#aa4400;stroke-width:1.7812928;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none" />
+ <ellipse
+ ry="10.125"
+ rx="11.5625"
+ cy="25.75"
+ cx="31.1875"
+ transform="matrix(0.8018194,0,0,0.8471126,6.257567,4.5089892)"
+ id="path39153"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient21444);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
<path
- id="path24861"
- style="opacity:0.75;fill:none;stroke:#ffffff;stroke-width:1.29999995;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
- d="m 818.5,83.5 -11,0 0,30 c 0,5 7,5 7,0 l 0,-18 34,0 m -29,-8 c 0,0.5 0.5286,1 1,1 l 20,0"
- sodipodi:nodetypes="cccccccsc"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ style="opacity:0.4857143;fill:none;stroke:url(#linearGradient21446);stroke-width:1.7812928;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1"
+ d="m 25.8125,6.40625 c -0.334829,4.572e-4 -0.72202,0.089606 -0.90625,0.21875 4.5e-4,0.010412 4.5e-4,0.020838 0,0.03125 -0.212626,0.1484635 -0.188235,0.1956271 -0.1875,0.1875 0.0092,0.010621 -0.0072,-4.246e-4 0.03125,0.03125 0.01962,0.00828 0.03527,0.012546 0.0625,0.03125 0.01676,0.01151 0.01357,0.014555 0.03125,0.03125 0.193748,0.1576058 4.954976,4.005164 4.954976,4.005164 0.489837,0.39864 0.677395,1.066352 0.46875,1.65625 -0.115662,0.32703 -0.422813,0.541217 -0.6875,0.59375 -0.264687,0.05253 -0.498447,0.03054 -0.71875,0.03125 -5.639658,0.05119 -16.87989,0.03851 -16.87989,0.03851 -0.4102,2.75e-4 -0.935835,0.115997 -1.34375,0.34375 -0.407915,0.227753 -0.6637862,0.523861 -0.6875002,0.90625 -0.024417,0.393728 0.098829,0.605767 0.3437502,0.78125 0.244921,0.175483 0.614978,0.25 0.875,0.25 0,0 8.8125,0 8.8125,0 0.600305,-7.28e-4 1.223895,0.311058 1.4375,0.9375 0.04676,0.137121 0.06335,0.269976 0.0625,0.40625 -8.49e-4,0.136274 -0.02214,0.268794 -0.09375,0.375 -0.143211,0.212412 -0.319507,0.298568 -0.5,0.4375 0,0 -15.7871819,12.746851 -15.856336,12.800078 C 5.0310984,30.500117 5,30.53125 5,30.53125 5.0100745,30.519077 5.000335,30.499512 5,30.5 L 4.8125,30.3125 c 0.012336,0.02165 0.014481,0.03307 0.03125,0.0625 0.063558,0.0774 0.125,0.15625 0.125,0.15625 -0.00585,0.0056 -0.031233,0.03124 -0.03125,0.03125 0,0 -0.043442,-0.09921 -0.09375,-0.1875 0.037843,0.09884 0.06253,0.218739 0.0625,0.21875 -0.4662091,0.37119 -0.7783348,0.889746 -0.875,1.28125 -0.1043319,0.422581 -0.046,0.62455 0.125,0.84375 0.2999827,0.384295 1.3975356,0.595547 2.40625,-0.21875 0,0 8.65625,-7.09375 8.65625,-7.09375 0.473718,-0.387074 1.1446,-0.458625 1.6875,-0.15625 0.544608,0.303331 0.798054,0.927572 0.71875,1.53125 0,0 -0.0626,0.908319 -0.0625,1.25 2e-6,0.0085 -1.19e-4,0.02348 0,0.03125 0.192796,2.523718 1.400736,4.762818 3.03125,6.71875 2.801818,3.089095 6.627659,4.401619 10.75,4.5625 4.113324,-0.043 7.964529,-1.606111 10.75,-4.625 2.546631,-3.125326 3.513872,-6.363859 3.15625,-9.375 C 44.891575,22.325847 43.222923,19.516566 40.4375,17.25 35.951885,13.599946 31.206991,10.168434 26.59375,6.625 26.57515,6.610386 26.56455,6.59802 26.5625,6.59375 26.43835,6.498703 26.144223,6.4057899 25.8125,6.40625 Z"
+ id="path21414"
+ sodipodi:nodetypes="csssssscssscsssccssscscccsccssssccscsscccssssc" />
<path
- sodipodi:nodetypes="ccccsscccssssccc"
- style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="path24863"
- d="m 806.5,113.5 c 0,2.75 2,5 5,5 l 33,0 c 3,0 5,-2 5,-5 l 0,-18 c 0,-0.471405 -0.5286,-1 -1,-1 l -7,0 0,-6 c 0,-0.5 -0.5,-1 -1,-1 l -20.02773,0.04419 C 819.98721,87.54526 819.5,87 819.5,86.5 l 0,-3 c 0,-0.5 -0.5,-1 -1,-1 l -11,0 c -0.5,0 -1,0.5 -1,1 l 0,30 z"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ d="m 25.708956,26.064593 c 0.07649,-1.397943 0.759369,-2.631914 1.78592,-3.505519 1.010226,-0.858782 2.366788,-1.383145 3.848625,-1.383145 1.480894,0 2.837456,0.524363 3.847446,1.383145 1.027685,0.873605 1.709741,2.106651 1.787122,3.504594 0.07927,1.438713 -0.49591,2.77459 -1.504012,3.764001 -1.027686,1.007933 -2.493008,1.640678 -4.130556,1.640678 -1.63849,0 -3.103814,-0.632745 -4.131451,-1.640678 -1.00914,-0.989411 -1.58234,-2.325288 -1.503094,-3.763076 l 0,0 0,0 0,0 z"
+ id="path2478"
+ style="fill:#3465a4;fill-rule:evenodd;stroke:none" />
<path
- sodipodi:nodetypes="csscc"
- id="path24865"
- d="m 841.5,94.5 -27,0 c -0.4714,0 -1,0.528595 -1,1 l 0,18 c 0,2.25 -1.25,3 -2.5,3"
- style="fill:none;stroke:url(#linearGradient24873);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="csssscsccsscsccssssscsscccsssc"
+ id="path39166"
+ d="m 25.8125,6.03125 c -0.404852,5.53e-4 -2.204797,-0.059029 -2.48145,0.1349032 -0.280209,0.195652 -0.335403,0.376484 -0.34375,0.46875 -0.0083,0.092266 -0.01539,0.17648 0.1875,0.34375 0.01899,0.015735 0.04457,0.014317 0.0625,0.03125 0.124258,0.101028 4.748869,4.1248618 4.748869,4.1248618 0.373658,0.304091 0.504393,0.795817 0.34375,1.25 -0.160635,0.454191 -0.580748,0.373449 -1.0625,0.375 -5.634142,0.05114 -15.087371,-0.129601 -15.087371,-0.129601 -0.952967,6.38e-4 -2.339958,0.524782 -2.4062504,1.59375 -0.063562,1.024947 0.9247974,1.4375 1.5937504,1.4375 0,-1e-6 8.8125,0 8.8125,0 0.488364,-5.92e-4 0.936141,0.225277 1.09375,0.6875 0.157609,0.462231 -0.01926,0.514621 -0.40625,0.8125 0,0 -16.086298,13.088586 -16.086298,13.088586 -0.00142,0.0014 -0.029829,-0.0014 -0.03125,0 -0.064037,0.04879 -0.054226,0.04875 -0.03125,0.03125 -0.5536758,0.424619 -0.9087886,1.004019 -1.03125,1.5 -0.1224536,0.495981 -0.04661,0.856152 0.1875,1.15625 0.4788333,0.613413 1.777612,0.754857 2.90625,-0.15625 1e-7,10e-7 8.65625,-7.09375 8.65625,-7.09375 0.361955,-0.295753 0.872897,-0.352437 1.28125,-0.125 0.408345,0.227436 0.623381,0.692814 0.5625,1.15625 0,-1e-6 -0.0997,0.953636 -0.09375,1.34375 0.09498,1.301756 0.451616,2.521825 0.989039,3.664234 C 20.799917,36.321089 27.770982,19.392853 44.1875,21.03125 43.339652,19.54368 42.151282,18.185293 40.65625,16.96875 36.159865,13.309932 31.42016,9.882897 26.8125,6.34375 26.805335,6.338858 26.788292,6.317553 26.78125,6.3125 26.570707,6.151312 26.216591,6.030689 25.8125,6.03125 Z"
+ style="opacity:0.51999996;fill:url(#radialGradient21448);fill-opacity:1;fill-rule:evenodd;stroke:none" />
</g>
+ </g>
+ <g
+ id="g6090">
<g
id="g24784"
- transform="translate(114,248)"
+ transform="translate(116,247.5)"
style="opacity:0.5">
<path
sodipodi:nodetypes="ccccccssssccc"
- style="fill:url(#linearGradient24809);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient24809);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
id="path24789"
d="m 806.5,114.5 c 0,2.25 2,4 4,4 l 30,0 c 0.4163,0 1,-0.5 1,-1 l 0,-29 c 0,-0.5 -0.5,-1 -1,-1 l -21.02773,0.04419 C 818.98721,87.545209 818.5,87 818.5,86.5 l 0,-3 c 0,-0.5 -0.5,-1 -1,-1 l -10,0 c -0.5,0 -1,0.5 -1,1 l 0,31 z"
inkscape:connector-curvature="0" />
<path
id="path24791"
- style="opacity:0.07999998;fill:url(#linearGradient24811);fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.07999998;fill:url(#linearGradient24811);fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;marker:none"
d="m 807.5,89.5 33,0 m -33,12 33,0 m -33,-4 33,0 m -33,-6 33,0 m -33,20 33,0 m -33,2 33,0 m -33,-18 33,0 m -33,-2 33,0 m -20,-6 -13,0 m 0,20 33,0 m -33,-2 33,0 m -33,-2 33,0 m -33,-4 33,0 m -33,10 33,0 m -33,6 33,0"
sodipodi:nodetypes="cccccccccccccccccccccccccccccc"
inkscape:connector-curvature="0" />
@@ -19586,10 +20130,10 @@
sodipodi:nodetypes="csccsczc"
id="path24793"
d="m 844,118.5 c 3.5,0 5.5,-2 5.5,-5.5 l 0,-18.5 c -11.75604,-1.11e-4 -23.91623,0 -35.5,0 l 0,19.5 c 0,4.5 -7,4 -7,0.25 0,2 2.00002,3.73529 3,3.75 l 34,0.5 z"
- style="fill:url(#linearGradient24813);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient24813);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- d="m 807,87 12,0 0.0385,-3.33333 C 819.04423,83.166705 818.97512,83 818.5,83 l -10.92308,0 c -0.47512,0 -0.53846,0.16667 -0.53846,0.66667 L 807,87 z"
+ d="m 807,87 12,0 0.0385,-3.33333 C 819.04423,83.166705 818.97512,83 818.5,83 l -10.92308,0 c -0.47512,0 -0.53846,0.16667 -0.53846,0.66667 L 807,87 Z"
id="path24796"
style="opacity:0.7;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
sodipodi:nodetypes="ccssccc"
@@ -19597,25 +20141,25 @@
<path
sodipodi:nodetypes="cc"
d="m 840.5,89 0,4.5"
- style="opacity:0.1;fill:none;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.1;fill:none;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;marker:none"
id="path24799"
inkscape:connector-curvature="0" />
<path
id="path24801"
- style="opacity:0.1;fill:none;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.1;fill:none;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;marker:none"
d="m 848.5,95.5 0,18 c 0,1.25 0.25,3 -1.25,4"
sodipodi:nodetypes="ccc"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="cccccccsc"
d="m 818.5,83.5 -11,0 0,30 c 0,5 7,5 7,0 l 0,-18 34,0 m -29,-8 c 0,0.5 0.5286,1 1,1 l 20,0"
- style="opacity:0.75;fill:none;stroke:#ffffff;stroke-width:1.29999995;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+ style="display:inline;opacity:0.75;fill:none;stroke:#ffffff;stroke-width:1.29999995;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path24803"
inkscape:connector-curvature="0" />
<path
d="m 806.5,113.5 c 0,2.75 2,5 5,5 l 33,0 c 3,0 5,-2 5,-5 l 0,-18 c 0,-0.471405 -0.5286,-1 -1,-1 l -7,0 0,-6 c 0,-0.5 -0.5,-1 -1,-1 l -20.02773,0.04419 C 819.98721,87.54526 819.5,87 819.5,86.5 l 0,-3 c 0,-0.5 -0.5,-1 -1,-1 l -11,0 c -0.5,0 -1,0.5 -1,1 l 0,30 z"
id="path24805"
- style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
sodipodi:nodetypes="ccccsscccssssccc"
inkscape:connector-curvature="0" />
<path
@@ -19626,33 +20170,16 @@
inkscape:connector-curvature="0" />
</g>
<g
- id="g44424"
- style="opacity:0.4;stroke:#3d361a;filter:url(#filter44473)"
- transform="translate(0,-2)">
- <path
- style="fill:none;stroke:#3d361a;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline;enable-background:new"
- d="m 950.25,362 -5.25,0 -1,-1 0,-10"
- id="path44406"
- sodipodi:nodetypes="cccc"
- inkscape:connector-curvature="0" />
- <path
- style="fill:none;stroke:#3d361a;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline;enable-background:new"
- d="M 948.25,354.25 944,350.00563 939.75,354.25"
- id="path44408"
- sodipodi:nodetypes="ccc"
- inkscape:connector-curvature="0" />
- </g>
- <g
- style="display:inline;enable-background:new"
+ style="display:inline;filter:url(#filter6078);enable-background:new"
id="g44334"
- transform="translate(617,273)">
+ transform="translate(619,272.5)">
<rect
y="73"
x="320"
height="16"
width="16"
id="rect44336"
- style="opacity:0;fill:#1a1a1a;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.20000005;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#1a1a1a;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.20000005;marker:none;enable-background:accumulate" />
<g
id="g44338"
transform="translate(0,-21)">
@@ -19662,13 +20189,13 @@
id="g44342"
transform="translate(0,21)">
<path
- style="fill:none;stroke:#000000;stroke-width:3.4000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ style="fill:none;stroke:#000000;stroke-width:3.4000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 333.25,87 -5.25,0 -1,-1 0,-10"
id="path44344"
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0" />
<path
- style="fill:none;stroke:#000000;stroke-width:3.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ style="fill:none;stroke:#000000;stroke-width:3.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 331.25,79.25 327,75.005631 322.75,79.25"
id="path44346"
sodipodi:nodetypes="ccc"
@@ -19681,13 +20208,13 @@
sodipodi:nodetypes="cccc"
id="path44350"
d="m 333.25,87 -5.25,0 -1,-1 0,-10"
- style="fill:none;stroke:#e6e6e6;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ style="fill:none;stroke:#e6e6e6;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="ccc"
id="path44352"
d="M 331.25,79.25 327,75.005631 322.75,79.25"
- style="fill:none;stroke:#e6e6e6;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ style="fill:none;stroke:#e6e6e6;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0" />
</g>
</g>
@@ -19695,30 +20222,95 @@
sodipodi:nodetypes="cccccc"
id="path44354"
d="m 328.5,107.5 5,0 m -7,-9 0,8.5 m -4.25,-7 4.5,-4.5"
- style="fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
</g>
</g>
+ </g>
+ <g
+ transform="translate(68,247.5)"
+ id="g24818"
+ style="display:inline;enable-background:new">
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccssssccc"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient24839);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+ id="path24821"
+ d="m 806.5,114.5 c 0,2.25 2,4 4,4 l 30,0 c 0.4163,0 1,-0.5 1,-1 l 0,-29 c 0,-0.5 -0.5,-1 -1,-1 l -21.02773,0.04419 C 818.98721,87.545209 818.5,87 818.5,86.5 l 0,-3 c 0,-0.5 -0.5,-1 -1,-1 l -10,0 c -0.5,0 -1,0.5 -1,1 l 0,31 z" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path24823"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.07999998;fill:url(#linearGradient24841);fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+ d="m 807.5,89.5 33,0 m -33,12 33,0 m -33,-4 33,0 m -33,-6 33,0 m -33,20 33,0 m -33,2 33,0 m -33,-18 33,0 m -33,-2 33,0 m -20,-6 -13,0 m 0,20 33,0 m -33,-2 33,0 m -33,-2 33,0 m -33,-4 33,0 m -33,10 33,0 m -33,6 33,0"
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="74.800003"
+ inkscape:export-xdpi="74.800003"
+ inkscape:export-filename="/home/jimmac/ximian_art/icons/nautilus/suse93/gnome-fs-directory.png"
+ sodipodi:nodetypes="csccsczc"
+ id="path24825"
+ d="m 844,118.5 c 3.5,0 5.5,-2 5.5,-5.5 l 0,-16 c -11.75604,-1.11e-4 -23.91623,0 -35.5,0 l 0,17 c 0,4.5 -7,4 -7,0.25 0,2 2.00002,3.73529 3,3.75 l 34,0.5 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient24843);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ d="m 807,87 12,0 0.0385,-3.33333 C 819.04423,83.166705 818.97512,83 818.5,83 l -10.92308,0 c -0.47512,0 -0.53846,0.16667 -0.53846,0.66667 L 807,87 Z"
+ id="path24827"
+ style="opacity:0.7;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ sodipodi:nodetypes="ccssccc" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc"
+ d="m 840.5,89 0,7.5"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.1;fill:none;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+ id="path24829" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path24831"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.1;fill:none;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+ d="m 848.5,98.75 0,14.75 c 0,1.25 0.25,3 -1.25,4"
+ sodipodi:nodetypes="ccc" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccsc"
+ d="m 818.5,83.5 -11,0 0,30 c 0,5 7,5 7,0 l 0,-16 34,0 m -29,-10 c 0,0.5 0.5286,1 1,1 l 20,0"
+ style="display:inline;opacity:0.75;fill:none;stroke:#ffffff;stroke-width:1.29999995;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path24833" />
+ <path
+ inkscape:connector-curvature="0"
+ d="m 806.5,113.5 c 0,2.75 2,5 5,5 l 33,0 c 3,0 5,-2 5,-5 l 0,-16 c 0,-0.471405 -0.5286,-1 -1,-1 l -7,0 0,-8 c 0,-0.5 -0.5,-1 -1,-1 l -20.02773,0.04419 C 819.98721,87.54526 819.5,87 819.5,86.5 l 0,-3 c 0,-0.5 -0.5,-1 -1,-1 l -11,0 c -0.5,0 -1,0.5 -1,1 l 0,30 z"
+ id="path24835"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ sodipodi:nodetypes="ccccsscccssssccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:none;stroke:url(#linearGradient24845);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 841.5,96.500004 -27,0 c -0.4714,0 -1,0.528595 -1,1 l 0,15.999996 c 0,2.25 -1.25,3 -2.5,3"
+ id="path24837"
+ sodipodi:nodetypes="csscc" />
+ </g>
+ <g
+ id="g6158">
<g
- style="display:inline;enable-background:new"
- id="g24818"
- transform="translate(66,248)">
+ transform="translate(164,247.5)"
+ id="g24847"
+ style="opacity:0.5">
<path
d="m 806.5,114.5 c 0,2.25 2,4 4,4 l 30,0 c 0.4163,0 1,-0.5 1,-1 l 0,-29 c 0,-0.5 -0.5,-1 -1,-1 l -21.02773,0.04419 C 818.98721,87.545209 818.5,87 818.5,86.5 l 0,-3 c 0,-0.5 -0.5,-1 -1,-1 l -10,0 c -0.5,0 -1,0.5 -1,1 l 0,31 z"
- id="path24821"
- style="fill:url(#linearGradient24839);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="path24849"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient24867);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
sodipodi:nodetypes="ccccccssssccc"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="cccccccccccccccccccccccccccccc"
d="m 807.5,89.5 33,0 m -33,12 33,0 m -33,-4 33,0 m -33,-6 33,0 m -33,20 33,0 m -33,2 33,0 m -33,-18 33,0 m -33,-2 33,0 m -20,-6 -13,0 m 0,20 33,0 m -33,-2 33,0 m -33,-2 33,0 m -33,-4 33,0 m -33,10 33,0 m -33,6 33,0"
- style="opacity:0.07999998;fill:url(#linearGradient24841);fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
- id="path24823"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.07999998;fill:url(#linearGradient24869);fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+ id="path24851"
inkscape:connector-curvature="0" />
<path
- style="fill:url(#linearGradient24843);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- d="m 844,118.5 c 3.5,0 5.5,-2 5.5,-5.5 l 0,-16 c -11.75604,-1.11e-4 -23.91623,0 -35.5,0 l 0,17 c 0,4.5 -7,4 -7,0.25 0,2 2.00002,3.73529 3,3.75 l 34,0.5 z"
- id="path24825"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient24871);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;enable-background:accumulate"
+ d="m 844,118.5 c 3.5,0 5.5,-2 5.5,-5.5 l 0,-18.5 c -11.75604,-1.11e-4 -23.91623,0 -35.5,0 l 0,19.5 c 0,4.5 -7,4 -7,0.25 0,2 2.00002,3.73529 3,3.75 l 34,0.5 z"
+ id="path24853"
sodipodi:nodetypes="csccsczc"
inkscape:export-filename="/home/jimmac/ximian_art/icons/nautilus/suse93/gnome-fs-directory.png"
inkscape:export-xdpi="74.800003"
@@ -19727,78 +20319,46 @@
<path
sodipodi:nodetypes="ccssccc"
style="opacity:0.7;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path24827"
- d="m 807,87 12,0 0.0385,-3.33333 C 819.04423,83.166705 818.97512,83 818.5,83 l -10.92308,0 c -0.47512,0 -0.53846,0.16667 -0.53846,0.66667 L 807,87 z"
+ id="path24855"
+ d="m 807,87 12,0 0.0385,-3.33333 C 819.04423,83.166705 818.97512,83 818.5,83 l -10.92308,0 c -0.47512,0 -0.53846,0.16667 -0.53846,0.66667 L 807,87 Z"
inkscape:connector-curvature="0" />
<path
- id="path24829"
- style="opacity:0.1;fill:none;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
- d="m 840.5,89 0,7.5"
+ id="path24857"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.1;fill:none;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+ d="m 840.5,89 0,4.5"
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="ccc"
- d="m 848.5,98.75 0,14.75 c 0,1.25 0.25,3 -1.25,4"
- style="opacity:0.1;fill:none;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
- id="path24831"
+ d="m 848.5,95.5 0,18 c 0,1.25 0.25,3 -1.25,4"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.1;fill:none;stroke:#000000;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+ id="path24859"
inkscape:connector-curvature="0" />
<path
- id="path24833"
- style="opacity:0.75;fill:none;stroke:#ffffff;stroke-width:1.29999995;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
- d="m 818.5,83.5 -11,0 0,30 c 0,5 7,5 7,0 l 0,-16 34,0 m -29,-10 c 0,0.5 0.5286,1 1,1 l 20,0"
+ id="path24861"
+ style="display:inline;opacity:0.75;fill:none;stroke:#ffffff;stroke-width:1.29999995;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 818.5,83.5 -11,0 0,30 c 0,5 7,5 7,0 l 0,-18 34,0 m -29,-8 c 0,0.5 0.5286,1 1,1 l 20,0"
sodipodi:nodetypes="cccccccsc"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="ccccsscccssssccc"
- style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="path24835"
- d="m 806.5,113.5 c 0,2.75 2,5 5,5 l 33,0 c 3,0 5,-2 5,-5 l 0,-16 c 0,-0.471405 -0.5286,-1 -1,-1 l -7,0 0,-8 c 0,-0.5 -0.5,-1 -1,-1 l -20.02773,0.04419 C 819.98721,87.54526 819.5,87 819.5,86.5 l 0,-3 c 0,-0.5 -0.5,-1 -1,-1 l -11,0 c -0.5,0 -1,0.5 -1,1 l 0,30 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="path24863"
+ d="m 806.5,113.5 c 0,2.75 2,5 5,5 l 33,0 c 3,0 5,-2 5,-5 l 0,-18 c 0,-0.471405 -0.5286,-1 -1,-1 l -7,0 0,-6 c 0,-0.5 -0.5,-1 -1,-1 l -20.02773,0.04419 C 819.98721,87.54526 819.5,87 819.5,86.5 l 0,-3 c 0,-0.5 -0.5,-1 -1,-1 l -11,0 c -0.5,0 -1,0.5 -1,1 l 0,30 z"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="csscc"
- id="path24837"
- d="m 841.5,96.500004 -27,0 c -0.4714,0 -1,0.528595 -1,1 l 0,15.999996 c 0,2.25 -1.25,3 -2.5,3"
- style="fill:none;stroke:url(#linearGradient24845);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- inkscape:connector-curvature="0" />
- </g>
- <g
- id="g44455"
- style="opacity:0.4;filter:url(#filter44477)">
- <path
- sodipodi:nodetypes="cs"
- id="path44446"
- d="m 343.5,104.5 1.75,1.75 c 2.3454,2.33848 6.16153,2.34539 8.5,0 l 0.5,-0.5"
- style="fill:none;stroke:#3d361a;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- transform="translate(645,252.05)"
- inkscape:connector-curvature="0" />
- <path
- sodipodi:nodetypes="ccc"
- id="path44449"
- d="m 343,108.25 0,-4.25 4.25,0"
- style="fill:none;stroke:#3d361a;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- transform="translate(645,252.05)"
- inkscape:connector-curvature="0" />
- <path
- style="fill:none;stroke:#3d361a;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- d="m 343.5,104.5 1.75,1.75 c 2.3454,2.33848 6.16153,2.34539 8.5,0 l 0.5,-0.5"
- id="path44451"
- sodipodi:nodetypes="cs"
- transform="matrix(-1,0,0,-1,1343,456.05)"
- inkscape:connector-curvature="0" />
- <path
- style="fill:none;stroke:#3d361a;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- d="m 343,108.25 0,-4.25 4.25,0"
- id="path44453"
- sodipodi:nodetypes="ccc"
- transform="matrix(-1,0,0,-1,1343,456.05)"
+ id="path24865"
+ d="m 841.5,94.5 -27,0 c -0.4714,0 -1,0.528595 -1,1 l 0,18 c 0,2.25 -1.25,3 -2.5,3"
+ style="fill:none;stroke:url(#linearGradient24873);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;enable-background:new"
+ style="display:inline;filter:url(#filter6146);enable-background:new"
id="g44356"
- transform="translate(645,273.05)">
+ transform="translate(647,272.55)">
<rect
- style="opacity:0;fill:#1a1a1a;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.20000005;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#1a1a1a;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.20000005;marker:none;enable-background:accumulate"
id="rect44358"
width="16"
height="16"
@@ -19812,13 +20372,13 @@
<g
id="g44364">
<path
- style="fill:none;stroke:#000000;stroke-width:3.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#000000;stroke-width:3.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
d="m 343.5,104.5 1.75,1.75 c 2.3454,2.33848 6.16153,2.34539 8.5,0 l 0.5,-0.5"
id="path44366"
sodipodi:nodetypes="cs"
inkscape:connector-curvature="0" />
<path
- style="fill:none;stroke:#000000;stroke-width:3.4000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#000000;stroke-width:3.4000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
d="m 343,108.25 0,-4.25 4.25,0"
id="path44368"
sodipodi:nodetypes="ccc"
@@ -19830,17 +20390,17 @@
sodipodi:nodetypes="ccc"
id="path44372"
d="m 343,108.25 0,-4.25 4.25,0"
- style="fill:none;stroke:#e6e6e6;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#e6e6e6;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="cs"
id="path44374"
d="m 343.5,104.5 1.75,1.75 c 2.3454,2.33848 6.16153,2.34539 8.5,0 l 0.5,-0.5"
- style="fill:none;stroke:#e6e6e6;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#e6e6e6;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
</g>
<path
- style="opacity:0.1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;marker:none;enable-background:accumulate"
d="m 344,105 0,1 0,1.5 1,0 0,-1.5 1.5,0 0,-1 -1.5,0 -1,0 z"
id="path44376"
inkscape:connector-curvature="0" />
@@ -19854,25 +20414,25 @@
sodipodi:nodetypes="cs"
id="path44382"
d="m 343.5,104.5 1.75,1.75 c 2.3454,2.33848 6.16153,2.34539 8.5,0 l 0.5,-0.5"
- style="fill:none;stroke:#000000;stroke-width:3.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#000000;stroke-width:3.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="ccc"
id="path44384"
d="m 343,108.25 0,-4.25 4.25,0"
- style="fill:none;stroke:#000000;stroke-width:3.4000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#000000;stroke-width:3.4000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
</g>
<g
id="g44386">
<path
- style="fill:none;stroke:#e6e6e6;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#e6e6e6;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
d="m 343,108.25 0,-4.25 4.25,0"
id="path44388"
sodipodi:nodetypes="ccc"
inkscape:connector-curvature="0" />
<path
- style="fill:none;stroke:#e6e6e6;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#e6e6e6;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
d="m 343.5,104.5 1.75,1.75 c 2.3454,2.33848 6.16153,2.34539 8.5,0 l 0.5,-0.5"
id="path44390"
sodipodi:nodetypes="cs"
@@ -19881,409 +20441,394 @@
<path
id="path44392"
d="m 344,105 0,1 0,1.5 1,0 0,-1.5 1.5,0 0,-1 -1.5,0 -1,0 z"
- style="opacity:0.1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="ccc"
id="path44394"
d="m 344.90625,106.59375 c 2.52573,2.51828 6.66805,2.52691 9.1875,0 l 0.5,-0.5"
- style="fill:none;stroke:url(#linearGradient44402);stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:url(#linearGradient44402);stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
</g>
<path
sodipodi:nodetypes="ccc"
id="path44396"
d="m 350.5,99.5 4,0 0,-4"
- style="fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="cccc"
id="path44398"
d="m 347.5,103.5 -4.5,0 c -0.25,0 -0.5,0.25 -0.5,0.5 l 0,4.5"
- style="fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="ccc"
id="path44400"
d="m 345.59375,105.90625 c 2.07803,2.0719 5.36384,2.10325 7.53125,0.1875 L 354,105.25"
- style="fill:none;stroke:url(#linearGradient44404);stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:url(#linearGradient44404);stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
</g>
</g>
+ </g>
+ <g
+ transform="translate(4,0)"
+ id="g34977"
+ style="display:inline;enable-background:new">
<g
- style="display:inline;enable-background:new"
- id="g34977">
- <g
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Pracowniaa\Moje dokumenty\Moje obrazy\BLENDER ICONS redesign\ver 2\IMAGE BROWSER ICONS.png"
- transform="translate(856,-154)"
- id="g21853-3"
- style="display:inline">
- <rect
- style="opacity:0;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="rect21855-8"
- width="48"
- height="48"
- x="108"
- y="430"
- rx="2.4004419"
- ry="0" />
- <g
- id="g21857-6">
- <path
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccccc"
- id="path21859-9"
- d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
- style="fill:url(#linearGradient21875-7-1-0-1);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;display:inline"
- inkscape:connector-curvature="0" />
- <path
- sodipodi:nodetypes="cccc"
- id="path21861-8"
- style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- inkscape:connector-curvature="0" />
- <path
- style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011-6-7-0-8)"
- d="m 115,444 12,0 -1,-11 -11,11 z"
- id="path21863-6"
- sodipodi:nodetypes="cccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- clip-path="url(#clipPath13106-9-2-9-9)"
- inkscape:connector-curvature="0" />
- <path
- sodipodi:nodetypes="ccc"
- id="path21865-6"
- style="fill:none;stroke:url(#linearGradient21877-3-2-7-2);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- d="m 117.5,443.75 9,-2.5 0,-6"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- clip-path="none"
- inkscape:connector-curvature="0" />
- <path
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
- style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- id="path21867-2"
- sodipodi:nodetypes="cccccc"
- inkscape:connector-curvature="0" />
- <path
- style="opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline;filter:url(#filter63011-6-7-0-8)"
- d="m 116,443 11,1 -2,-10 -9,9 z"
- id="path21869-3"
- sodipodi:nodetypes="cccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- clip-path="url(#clipPath13106-9-2-9-9)"
- inkscape:connector-curvature="0" />
- <path
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccccc"
- id="path21871-8"
- d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
- inkscape:connector-curvature="0" />
- <path
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 147.5,435 0,38.5 -30.5,0"
- style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- id="path21873-2"
- sodipodi:nodetypes="ccc"
- inkscape:connector-curvature="0" />
- </g>
- </g>
+ style="display:inline"
+ id="g21853-3"
+ transform="translate(856,-154)"
+ inkscape:export-filename="C:\Documents and Settings\Pracowniaa\Moje dokumenty\Moje obrazy\BLENDER ICONS redesign\ver 2\IMAGE BROWSER ICONS.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <rect
+ ry="0"
+ rx="2.4004419"
+ y="430"
+ x="108"
+ height="48"
+ width="48"
+ id="rect21855-8"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;enable-background:accumulate" />
<g
- transform="translate(63,-47)"
- id="g34938">
+ id="g21857-6">
<path
- sodipodi:nodetypes="cssssccsscsccsc"
inkscape:connector-curvature="0"
- d="m 919.5,356.5067 0,-3 c 0,-1.73575 1.26424,-3 3,-3 l 5,0 c 1.73576,0 3,-1.26425 3,-3 l 0,-3.0064 2.5,0.006 c 2,0 3.5,2.5 3.5,6 0,3.5 -1.25,6 -3.5,6 -4.98134,0 -12.77318,0 -2.5,0 l 0,2.75 c 0,2.5 -2,3.24997 -5.5,3.24998 l 0,2e-5 c -3.5,0.0104 -5.5,-0.75 -5.5,-3.25 l 0,-2.7628"
- style="color:#000000;fill:url(#linearGradient34959-9-2-1);fill-opacity:1;fill-rule:nonzero;stroke:#ff0000;stroke-width:0.17893334;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="path61236" />
+ style="display:inline;fill:url(#linearGradient21875-7-1-0-1);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ id="path21859-9"
+ sodipodi:nodetypes="cccccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
<path
- id="path61233"
- style="color:#000000;fill:url(#linearGradient34961-3-6-5);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.17893334;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- d="m 930.5,344.5 0,3 c 0,1.73575 -1.26424,3 -3,3 l -5,0 c -1.73576,0 -3,1.26425 -3,3 l 0,3.0064 -2.5,-0.006 c -2,0 -3.5,-2.5 -3.5,-6 0,-3.5 1.25,-6 3.5,-6 4.98134,0 12.77318,0 2.5,0 l 0,-2.75 c 0,-2.5 2,-3.24997 5.5,-3.24998 l 0,-2e-5 c 3.5,-0.0104 5.5,0.75 5.5,3.25 l 0,2.7628"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="cssssccsscsccsc" />
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
+ style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ id="path21861-8"
+ sodipodi:nodetypes="cccc" />
<path
- style="fill:none;stroke:#000000;stroke-width:0.80000001;stroke-miterlimit:4;stroke-opacity:0.8627451;stroke-dasharray:none"
- d="m 925,338.50002 c -3.5,10e-6 -5.5,0.74998 -5.5,3.24998 l 0,2.75 5.5,0 -8,0 c -2.25,0 -3.5,2.5 -3.5,6 0,3.5 1.5,6 3.5,6 l 2.5,0.0128 0,2.9872 c 0,2 2,3.01281 5.5,3.0128 3.5,-1e-5 5.5,-1.0128 5.5,-3.0128 l 0,-3 -5.5,0 8,0 c 2,0 3.5,-2.5 3.5,-6 0,-3.5 -1.5,-6 -3.5,-6 l -2.5,0.0128 0,-2.7628 c 0,-2.5 -2,-3.26045 -5.5,-3.25 z"
- id="path61167"
- sodipodi:nodetypes="cccccscccsccccsccccc"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ clip-path="url(#clipPath13106-9-2-9-9)"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccc"
+ id="path21863-6"
+ d="m 115,444 12,0 -1,-11 -11,11 z"
+ style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011-6-7-0-8)" />
<path
- style="fill:none;stroke:#000000;stroke-width:0.80000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.78431373;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- d="m 930.5,344.5 0,3 c 0,1.73575 -1.26424,3 -3,3 l -5,0 c -1.73576,0 -3,1.26425 -3,3 l 0,3"
- id="path61169"
+ inkscape:connector-curvature="0"
+ clip-path="none"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 117.5,443.75 9,-2.5 0,-6"
+ style="fill:none;stroke:url(#linearGradient21877-3-2-7-2);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path21865-6"
+ sodipodi:nodetypes="ccc" />
+ <path
+ inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc"
- inkscape:connector-curvature="0" />
+ id="path21867-2"
+ style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:connector-curvature="0"
+ clip-path="url(#clipPath13106-9-2-9-9)"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccc"
+ id="path21869-3"
+ d="m 116,443 11,1 -2,-10 -9,9 z"
+ style="display:inline;opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011-6-7-0-8)" />
<path
- sodipodi:type="arc"
- style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.80000001;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="path61220"
- sodipodi:cx="922"
- sodipodi:cy="342"
- sodipodi:rx="1"
- sodipodi:ry="1"
- d="m 923,342 c 0,0.55228 -0.44772,1 -1,1 -0.55228,0 -1,-0.44772 -1,-1 0,-0.55228 0.44772,-1 1,-1 0.55228,0 1,0.44772 1,1 z" />
+ inkscape:connector-curvature="0"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
+ id="path21871-8"
+ sodipodi:nodetypes="cccccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
<path
- sodipodi:type="arc"
- style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.80000001;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="path61222"
- sodipodi:cx="928"
- sodipodi:cy="359"
- sodipodi:rx="1"
- sodipodi:ry="1"
- d="m 929,359 c 0,0.55228 -0.44772,1 -1,1 -0.55228,0 -1,-0.44772 -1,-1 0,-0.55228 0.44772,-1 1,-1 0.55228,0 1,0.44772 1,1 z" />
- <g
- id="g61345"
- style="opacity:0.4">
- <path
- sodipodi:nodetypes="cszsc"
- inkscape:connector-curvature="0"
- id="path61333"
- d="m 920.5,343.25 0,-1.5 c 0,-1.75 1.5,-2.25 4.5,-2.25 3,0 4.5,0.5 4.5,2.25 l 0,4.75"
- style="fill:none;stroke:url(#linearGradient34963-5-9-1);stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
- <path
- sodipodi:nodetypes="cccszsc"
- inkscape:connector-curvature="0"
- id="path61335"
- d="m 925.5,345 0,0.25 -0.25,0.25 -8.25,0 c -1.5,0 -2.5,2 -2.5,5 0,3 1.28917,5 2.5,5 l 1.5,0"
- style="fill:none;stroke:url(#linearGradient34965-1-5-2);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
- <path
- inkscape:connector-curvature="0"
- id="path61337"
- d="m 920.75,343.5 4.5,0 0.25,0.25 0,0.5"
- style="fill:none;stroke:none" />
- <path
- sodipodi:nodetypes="cssssc"
- inkscape:connector-curvature="0"
- id="path61339"
- d="m 918.5,355.25 0,-1.75 c 0,-2.25 1.75,-4 4,-4 l 4.5,0 c 1.75,0 2.5,-0.75 2.5,-2.5 l 0,-0.5"
- style="fill:none;stroke:none" />
- <path
- d="m 923,342 c 0,0.55228 -0.44772,1 -1,1 -0.55228,0 -1,-0.44772 -1,-1 0,-0.55228 0.44772,-1 1,-1 0.55228,0 1,0.44772 1,1 z"
- sodipodi:ry="1"
- sodipodi:rx="1"
- sodipodi:cy="342"
- sodipodi:cx="922"
- id="path61355"
- style="color:#000000;fill:none;stroke:url(#linearGradient34967-4-1-8);stroke-width:0.52766895;stroke-miterlimit:4;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- sodipodi:type="arc"
- transform="matrix(1.5161021,0,0,1.5161021,-475.84616,-176.50693)" />
- </g>
- <g
- id="g34104"
- transform="matrix(-1,0,0,-1,1850,701)"
- style="opacity:0.8;stroke:#ff0000">
- <path
- style="fill:none;stroke:none"
- d="m 920.5,343.25 0,-1.5 c 0,-1.75 1.5,-2.25 4.5,-2.25 3,0 4.5,0.5 4.5,2.25 l 0,4.75"
- id="path34106"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cszsc" />
- <path
- style="fill:none;stroke:url(#linearGradient34969-4-4-1);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- d="m 914.5,350.5 c 0,3 1.28917,5 2.5,5 l 1.5,0"
- id="path34108"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="csc" />
- <path
- style="fill:none;stroke:url(#linearGradient34971-5-0-9);stroke-linecap:round;stroke-linejoin:round"
- d="m 920.75,343.5 4.5,0 0.25,0.25 0,0.5"
- id="path34110"
- inkscape:connector-curvature="0" />
- <path
- style="fill:none;stroke:url(#radialGradient34973-2-5-7);stroke-linecap:round;stroke-linejoin:round"
- d="m 918.5,355.5 0,-2 c 0,-2.25 1.75,-4 4,-4 l 4.5,0 c 1.75,0 2.5,-0.75 2.5,-2.5 l 0,-0.5"
- id="path34113"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cssssc" />
- <path
- transform="matrix(1.5161021,0,0,1.5161021,-475.84616,-176.50693)"
- sodipodi:type="arc"
- style="color:#000000;fill:none;stroke:url(#linearGradient34975-9-4-9);stroke-width:0.52766895;stroke-miterlimit:4;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="path34115"
- sodipodi:cx="922"
- sodipodi:cy="342"
- sodipodi:rx="1"
- sodipodi:ry="1"
- d="m 923,342 c 0,0.55228 -0.44772,1 -1,1 -0.55228,0 -1,-0.44772 -1,-1 0,-0.55228 0.44772,-1 1,-1 0.55228,0 1,0.44772 1,1 z" />
- <path
- sodipodi:nodetypes="cccsc"
- inkscape:connector-curvature="0"
- id="path34901"
- d="m 925.5,345 0,0.25 -0.25,0.25 -8.25,0 c -1.5,0 -2.5,2 -2.5,5"
- style="fill:none;stroke:none" />
- </g>
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc"
+ id="path21873-2"
+ style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 147.5,435 0,38.5 -30.5,0"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
</g>
</g>
<g
- style="display:inline;enable-background:new"
- id="g45475-4"
- transform="translate(208,-9)">
+ id="g34938"
+ transform="translate(63,-47)">
+ <path
+ id="path61236"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient34959-9-2-1);fill-opacity:1;fill-rule:nonzero;stroke:#ff0000;stroke-width:0.17893334;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 919.5,356.5067 0,-3 c 0,-1.73575 1.26424,-3 3,-3 l 5,0 c 1.73576,0 3,-1.26425 3,-3 l 0,-3.0064 2.5,0.006 c 2,0 3.5,2.5 3.5,6 0,3.5 -1.25,6 -3.5,6 -4.98134,0 -12.77318,0 -2.5,0 l 0,2.75 c 0,2.5 -2,3.24997 -5.5,3.24998 l 0,2e-5 c -3.5,0.0104 -5.5,-0.75 -5.5,-3.25 l 0,-2.7628"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cssssccsscsccsc" />
+ <path
+ sodipodi:nodetypes="cssssccsscsccsc"
+ inkscape:connector-curvature="0"
+ d="m 930.5,344.5 0,3 c 0,1.73575 -1.26424,3 -3,3 l -5,0 c -1.73576,0 -3,1.26425 -3,3 l 0,3.0064 -2.5,-0.006 c -2,0 -3.5,-2.5 -3.5,-6 0,-3.5 1.25,-6 3.5,-6 4.98134,0 12.77318,0 2.5,0 l 0,-2.75 c 0,-2.5 2,-3.24997 5.5,-3.24998 l 0,-2e-5 c 3.5,-0.0104 5.5,0.75 5.5,3.25 l 0,2.7628"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient34961-3-6-5);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.17893334;marker:none;enable-background:accumulate"
+ id="path61233" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccscccsccccsccccc"
+ id="path61167"
+ d="m 925,338.50002 c -3.5,10e-6 -5.5,0.74998 -5.5,3.24998 l 0,2.75 5.5,0 -8,0 c -2.25,0 -3.5,2.5 -3.5,6 0,3.5 1.5,6 3.5,6 l 2.5,0.0128 0,2.9872 c 0,2 2,3.01281 5.5,3.0128 3.5,-1e-5 5.5,-1.0128 5.5,-3.0128 l 0,-3 -5.5,0 8,0 c 2,0 3.5,-2.5 3.5,-6 0,-3.5 -1.5,-6 -3.5,-6 l -2.5,0.0128 0,-2.7628 c 0,-2.5 -2,-3.26045 -5.5,-3.25 z"
+ style="fill:none;stroke:#000000;stroke-width:0.80000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.8627451" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccc"
+ id="path61169"
+ d="m 930.5,344.5 0,3 c 0,1.73575 -1.26424,3 -3,3 l -5,0 c -1.73576,0 -3,1.26425 -3,3 l 0,3"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#000000;stroke-width:0.80000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.78431373;marker:none;enable-background:accumulate" />
+ <circle
+ r="1"
+ cy="342"
+ cx="922"
+ id="path61220"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.80000001;marker:none;enable-background:accumulate" />
+ <circle
+ r="1"
+ cy="359"
+ cx="928"
+ id="path61222"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.80000001;marker:none;enable-background:accumulate" />
<g
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Pracowniaa\Moje dokumenty\Moje obrazy\BLENDER ICONS redesign\ver 2\IMAGE BROWSER ICONS.png"
- transform="translate(696,-194)"
- id="g22242-6"
- style="display:inline">
- <rect
- style="opacity:0;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="rect22244-9"
- width="48"
- height="48"
- x="108"
- y="430"
- rx="2.4004419"
- ry="0" />
- <g
- id="g22246-2">
- <path
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccccc"
- id="path22249-8"
- d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
- style="fill:url(#linearGradient22274-8);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;display:inline"
- inkscape:connector-curvature="0" />
- <path
- sodipodi:nodetypes="cccc"
- id="path22251-9"
- style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- inkscape:connector-curvature="0" />
- <path
- style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011-5)"
- d="m 115,444 12,0 -1,-11 -11,11 z"
- id="path22253-5"
- sodipodi:nodetypes="cccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- clip-path="url(#clipPath13106-5)"
- inkscape:connector-curvature="0" />
- <path
- sodipodi:nodetypes="ccc"
- id="path22264-3"
- style="fill:none;stroke:url(#linearGradient22276-5);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- d="m 117.5,443.75 9,-2.5 0,-6"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- clip-path="none"
- inkscape:connector-curvature="0" />
- <path
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
- style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- id="path22266-6"
- sodipodi:nodetypes="cccccc"
- inkscape:connector-curvature="0" />
- <path
- style="opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline;filter:url(#filter63011-5)"
- d="m 116,443 11,1 -2,-10 -9,9 z"
- id="path22268-0"
- sodipodi:nodetypes="cccc"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- clip-path="url(#clipPath13106-5)"
- inkscape:connector-curvature="0" />
- <path
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- sodipodi:nodetypes="cccccc"
- id="path22270-1"
- d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
- inkscape:connector-curvature="0" />
- <path
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
- d="m 147.5,435 0,38.5 -30.5,0"
- style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- id="path22272-3"
- sodipodi:nodetypes="ccc"
- inkscape:connector-curvature="0" />
- </g>
+ style="opacity:0.4"
+ id="g61345">
+ <path
+ style="fill:none;stroke:url(#linearGradient34963-5-9-1);stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 920.5,343.25 0,-1.5 c 0,-1.75 1.5,-2.25 4.5,-2.25 3,0 4.5,0.5 4.5,2.25 l 0,4.75"
+ id="path61333"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cszsc" />
+ <path
+ style="fill:none;stroke:url(#linearGradient34965-1-5-2);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 925.5,345 0,0.25 -0.25,0.25 -8.25,0 c -1.5,0 -2.5,2 -2.5,5 0,3 1.28917,5 2.5,5 l 1.5,0"
+ id="path61335"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccszsc" />
+ <path
+ style="fill:none;stroke:none"
+ d="m 920.75,343.5 4.5,0 0.25,0.25 0,0.5"
+ id="path61337"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;stroke:none"
+ d="m 918.5,355.25 0,-1.75 c 0,-2.25 1.75,-4 4,-4 l 4.5,0 c 1.75,0 2.5,-0.75 2.5,-2.5 l 0,-0.5"
+ id="path61339"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cssssc" />
+ <circle
+ r="1"
+ cy="342"
+ cx="922"
+ transform="matrix(1.5161021,0,0,1.5161021,-475.84616,-176.50693)"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:url(#linearGradient34967-4-1-8);stroke-width:0.52766895;stroke-miterlimit:4;stroke-dasharray:none;marker:none;enable-background:accumulate"
+ id="path61355" />
</g>
<g
- transform="matrix(0.5406242,0,0,0.5829534,814.13667,247.65542)"
- inkscape:label="Layer 1"
- id="g21517-6">
+ style="opacity:0.8;stroke:#ff0000"
+ transform="matrix(-1,0,0,-1,1850,701)"
+ id="g34104">
<path
- sodipodi:type="arc"
- style="opacity:0.54857142;fill:url(#radialGradient21442-6-790);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="path35486-4"
- sodipodi:cx="28.019106"
- sodipodi:cy="38.98439"
- sodipodi:rx="15.467961"
- sodipodi:ry="5.3033009"
- d="m 43.487067,38.98439 c 0,2.928932 -6.925242,5.303301 -15.467961,5.303301 -8.542719,0 -15.467961,-2.374369 -15.467961,-5.303301 0,-2.928932 6.925242,-5.303301 15.467961,-5.303301 8.542719,0 15.467961,2.374369 15.467961,5.303301 z"
- transform="matrix(1.274286,0,0,1.377124,-7.569123,-16.70193)" />
+ sodipodi:nodetypes="cszsc"
+ inkscape:connector-curvature="0"
+ id="path34106"
+ d="m 920.5,343.25 0,-1.5 c 0,-1.75 1.5,-2.25 4.5,-2.25 3,0 4.5,0.5 4.5,2.25 l 0,4.75"
+ style="fill:none;stroke:none" />
<path
- style="fill:#dd6d00;fill-rule:evenodd;stroke:#993d00;stroke-width:1.7812928;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
- id="path2482-9"
- d="m 16.048489,28.093447 c 0.0098,0.576682 0.196474,1.697902 0.471116,2.577425 0.581566,1.854137 1.56684,3.572658 2.939126,5.086496 1.407488,1.553118 3.138519,2.803227 5.139315,3.68976 2.105357,0.931573 4.384795,1.407488 6.750134,1.403741 2.365339,-0.005 4.644601,-0.488686 6.74896,-1.427017 2.00002,-0.895288 3.731043,-2.148391 5.13754,-3.705517 1.369207,-1.519844 2.352576,-3.241114 2.934089,-5.096258 0.294262,-0.938353 0.476921,-1.889392 0.553238,-2.845308 0.07331,-0.939306 0.04204,-1.883511 -0.09183,-2.823792 -0.259981,-1.835599 -0.896294,-3.556847 -1.872652,-5.12758 -0.895541,-1.441699 -2.047808,-2.70454 -3.417268,-3.766975 0,0 0.002,-0.002 0.002,-0.002 0,0 -13.828458,-10.6197195 -13.828458,-10.6197195 -0.01176,-0.00978 -0.02252,-0.019551 -0.03529,-0.028344 -0.909003,-0.6959264 -3.879837,-0.7738945 -4.87679,-0.075035 -1.01067,0.7057021 -1.091821,1.8092613 -0.195527,2.5482146 1.899775,1.4997633 2.656207,2.2801589 4.566507,3.7797379 0,0 -14.852491,0.167033 -14.852491,0.167033 -1.994685,0 -3.1682609,0.947915 -3.4153947,2.333683 -0.2180771,1.222836 0.7479213,2.738129 2.4800217,2.738129 2.956573,0.0039 5.942111,-0.0069 8.909215,-0.01272 0,0 -16.01999,12.453223 -16.01999,12.453223 -0.020527,0.01564 -0.041053,0.02933 -0.06158,0.04497 -1.4974197,1.148389 -1.9831951,3.059322 -1.0399808,4.268393 0.9598323,1.22959 2.9977653,1.230588 4.5147288,0.006 0,0 8.677593,-7.102098 8.677593,-7.102098 0,0 -0.12511,0.959824 -0.116333,1.535532 l 1e-6,2.6e-5 0,0 0,0 z"
- sodipodi:nodetypes="csssssssssscccsscccscccssccc"
- inkscape:connector-curvature="0" />
+ sodipodi:nodetypes="csc"
+ inkscape:connector-curvature="0"
+ id="path34108"
+ d="m 914.5,350.5 c 0,3 1.28917,5 2.5,5 l 1.5,0"
+ style="fill:none;stroke:url(#linearGradient34969-4-4-1);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
<path
- sodipodi:type="arc"
- style="fill:url(#linearGradient21444-0-352);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="path39153-3"
- sodipodi:cx="31.1875"
- sodipodi:cy="25.75"
- sodipodi:rx="11.5625"
- sodipodi:ry="10.125"
- d="m 42.75,25.75 c 0,5.591883 -5.176708,10.125 -11.5625,10.125 -6.385792,0 -11.5625,-4.533117 -11.5625,-10.125 0,-5.591883 5.176708,-10.125 11.5625,-10.125 6.385792,0 11.5625,4.533117 11.5625,10.125 z"
- transform="matrix(0.8018194,0,0,0.8471126,6.257567,4.5089892)" />
+ inkscape:connector-curvature="0"
+ id="path34110"
+ d="m 920.75,343.5 4.5,0 0.25,0.25 0,0.5"
+ style="fill:none;stroke:url(#linearGradient34971-5-0-9);stroke-linecap:round;stroke-linejoin:round" />
<path
- sodipodi:nodetypes="csssssscssscsssccssscscccsccssssccscsscccssssc"
- id="path21414-5"
- d="m 25.8125,6.40625 c -0.334829,4.572e-4 -0.72202,0.089606 -0.90625,0.21875 4.5e-4,0.010412 4.5e-4,0.020838 0,0.03125 -0.212626,0.1484635 -0.188235,0.1956271 -0.1875,0.1875 0.0092,0.010621 -0.0072,-4.246e-4 0.03125,0.03125 0.01962,0.00828 0.03527,0.012546 0.0625,0.03125 0.01676,0.01151 0.01357,0.014555 0.03125,0.03125 0.193748,0.1576058 4.954976,4.005164 4.954976,4.005164 0.489837,0.39864 0.677395,1.066352 0.46875,1.65625 -0.115662,0.32703 -0.422813,0.541217 -0.6875,0.59375 -0.264687,0.05253 -0.498447,0.03054 -0.71875,0.03125 -5.639658,0.05119 -16.87989,0.03851 -16.87989,0.03851 -0.4102,2.75e-4 -0.935835,0.115997 -1.34375,0.34375 -0.407915,0.227753 -0.6637862,0.523861 -0.6875002,0.90625 -0.024417,0.393728 0.098829,0.605767 0.3437502,0.78125 0.244921,0.175483 0.614978,0.25 0.875,0.25 0,0 8.8125,0 8.8125,0 0.600305,-7.28e-4 1.223895,0.311058 1.4375,0.9375 0.04676,0.137121 0.06335,0.269976 0.0625,0.40625 -8.49e-4,0.136274 -0.02214,0.268794 -0.09375,0.375 -0.143211,0.212412 -0.319507,0.298568 -0.5,0.4375 0,0 -15.7871819,12.746851 -15.856336,12.800078 C 5.0310984,30.500117 5,30.53125 5,30.53125 5.0100745,30.519077 5.000335,30.499512 5,30.5 L 4.8125,30.3125 c 0.012336,0.02165 0.014481,0.03307 0.03125,0.0625 0.063558,0.0774 0.125,0.15625 0.125,0.15625 -0.00585,0.0056 -0.031233,0.03124 -0.03125,0.03125 0,0 -0.043442,-0.09921 -0.09375,-0.1875 0.037843,0.09884 0.06253,0.218739 0.0625,0.21875 -0.4662091,0.37119 -0.7783348,0.889746 -0.875,1.28125 -0.1043319,0.422581 -0.046,0.62455 0.125,0.84375 0.2999827,0.384295 1.3975356,0.595547 2.40625,-0.21875 0,0 8.65625,-7.09375 8.65625,-7.09375 0.473718,-0.387074 1.1446,-0.458625 1.6875,-0.15625 0.544608,0.303331 0.798054,0.927572 0.71875,1.53125 0,0 -0.0626,0.908319 -0.0625,1.25 2e-6,0.0085 -1.19e-4,0.02348 0,0.03125 0.192796,2.523718 1.400736,4.762818 3.03125,6.71875 2.801818,3.089095 6.627659,4.401619 10.75,4.5625 4.113324,-0.043 7.964529,-1.606111 10.75,-4.625 2.546631,-3.125326 3.513872,-6.363859 3.15625,-9.375 C 44.891575,22.325847 43.222923,19.516566 40.4375,17.25 35.951885,13.599946 31.206991,10.168434 26.59375,6.625 26.57515,6.610386 26.56455,6.59802 26.5625,6.59375 26.43835,6.498703 26.144223,6.4057899 25.8125,6.40625 z"
- style="opacity:0.4857143;fill:none;stroke:url(#linearGradient21446-3-145);stroke-width:1.7812928;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1"
- inkscape:connector-curvature="0" />
+ sodipodi:nodetypes="cssssc"
+ inkscape:connector-curvature="0"
+ id="path34113"
+ d="m 918.5,355.5 0,-2 c 0,-2.25 1.75,-4 4,-4 l 4.5,0 c 1.75,0 2.5,-0.75 2.5,-2.5 l 0,-0.5"
+ style="fill:none;stroke:url(#radialGradient34973-2-5-7);stroke-linecap:round;stroke-linejoin:round" />
+ <circle
+ r="1"
+ cy="342"
+ cx="922"
+ id="path34115"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:url(#linearGradient34975-9-4-9);stroke-width:0.52766895;stroke-miterlimit:4;stroke-dasharray:none;marker:none;enable-background:accumulate"
+ transform="matrix(1.5161021,0,0,1.5161021,-475.84616,-176.50693)" />
<path
- style="fill:#2f5b94;fill-rule:evenodd;stroke:none"
- id="path2478-8"
- d="m 25.708956,26.064593 c 0.07649,-1.397943 0.759369,-2.631914 1.78592,-3.505519 1.010226,-0.858782 2.366788,-1.383145 3.848625,-1.383145 1.480894,0 2.837456,0.524363 3.847446,1.383145 1.027685,0.873605 1.709741,2.106651 1.787122,3.504594 0.07927,1.438713 -0.49591,2.77459 -1.504012,3.764001 -1.027686,1.007933 -2.493008,1.640678 -4.130556,1.640678 -1.63849,0 -3.103814,-0.632745 -4.131451,-1.640678 -1.00914,-0.989411 -1.58234,-2.325288 -1.503094,-3.763076 l 0,0 0,0 0,0 z"
- inkscape:connector-curvature="0" />
+ style="fill:none;stroke:none"
+ d="m 925.5,345 0,0.25 -0.25,0.25 -8.25,0 c -1.5,0 -2.5,2 -2.5,5"
+ id="path34901"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccsc" />
+ </g>
+ </g>
+ </g>
+ <g
+ transform="translate(212,-8)"
+ id="g45475-4"
+ style="display:inline;enable-background:new">
+ <g
+ style="display:inline"
+ id="g22242-6"
+ transform="translate(696,-194)"
+ inkscape:export-filename="C:\Documents and Settings\Pracowniaa\Moje dokumenty\Moje obrazy\BLENDER ICONS redesign\ver 2\IMAGE BROWSER ICONS.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <rect
+ ry="0"
+ rx="2.4004419"
+ y="430"
+ x="108"
+ height="48"
+ width="48"
+ id="rect22244-9"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;marker:none;enable-background:accumulate" />
+ <g
+ id="g22246-2">
<path
- style="opacity:0.51999996;fill:url(#radialGradient21448-8-143);fill-opacity:1;fill-rule:evenodd;stroke:none"
- d="m 25.8125,6.03125 c -0.404852,5.53e-4 -2.204797,-0.059029 -2.48145,0.1349032 -0.280209,0.195652 -0.335403,0.376484 -0.34375,0.46875 -0.0083,0.092266 -0.01539,0.17648 0.1875,0.34375 0.01899,0.015735 0.04457,0.014317 0.0625,0.03125 0.124258,0.101028 4.748869,4.1248618 4.748869,4.1248618 0.373658,0.304091 0.504393,0.795817 0.34375,1.25 -0.160635,0.454191 -0.580748,0.373449 -1.0625,0.375 -5.634142,0.05114 -15.087371,-0.129601 -15.087371,-0.129601 -0.952967,6.38e-4 -2.339958,0.524782 -2.4062504,1.59375 -0.063562,1.024947 0.9247974,1.4375 1.5937504,1.4375 0,-1e-6 8.8125,0 8.8125,0 0.488364,-5.92e-4 0.936141,0.225277 1.09375,0.6875 0.157609,0.462231 -0.01926,0.514621 -0.40625,0.8125 0,0 -16.086298,13.088586 -16.086298,13.088586 -0.00142,0.0014 -0.029829,-0.0014 -0.03125,0 -0.064037,0.04879 -0.054226,0.04875 -0.03125,0.03125 -0.5536758,0.424619 -0.9087886,1.004019 -1.03125,1.5 -0.1224536,0.495981 -0.04661,0.856152 0.1875,1.15625 0.4788333,0.613413 1.777612,0.754857 2.90625,-0.15625 1e-7,10e-7 8.65625,-7.09375 8.65625,-7.09375 0.361955,-0.295753 0.872897,-0.352437 1.28125,-0.125 0.408345,0.227436 0.623381,0.692814 0.5625,1.15625 0,-1e-6 -0.0997,0.953636 -0.09375,1.34375 0.09498,1.301756 0.451616,2.521825 0.989039,3.664234 C 20.799917,36.321089 27.770982,19.392853 44.1875,21.03125 43.339652,19.54368 42.151282,18.185293 40.65625,16.96875 36.159865,13.309932 31.42016,9.882897 26.8125,6.34375 26.805335,6.338858 26.788292,6.317553 26.78125,6.3125 26.570707,6.151312 26.216591,6.030689 25.8125,6.03125 z"
- id="path39166-5"
- sodipodi:nodetypes="csssscsccsscsccssssscsscccsssc"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ style="display:inline;fill:url(#linearGradient22274-8);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none"
+ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z"
+ id="path22249-8"
+ sodipodi:nodetypes="cccccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 147.25,434.5 c -4.875,0 -21.75,0 -21.75,0 m -8.9447,8.5 -0.0553,30"
+ style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ id="path22251-9"
+ sodipodi:nodetypes="cccc" />
+ <path
+ inkscape:connector-curvature="0"
+ clip-path="url(#clipPath13106-5)"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccc"
+ id="path22253-5"
+ d="m 115,444 12,0 -1,-11 -11,11 z"
+ style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011-5)" />
+ <path
+ inkscape:connector-curvature="0"
+ clip-path="none"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ d="m 117.5,443.75 9,-2.5 0,-6"
+ style="fill:none;stroke:url(#linearGradient22276-5);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path22264-3"
+ sodipodi:nodetypes="ccc" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccc"
+ id="path22266-6"
+ style="fill:none;stroke:#333333;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 115.5,442.75 0,31.75 33,0 0,-41 -23.75,0 -9.25,9.25 z"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:connector-curvature="0"
+ clip-path="url(#clipPath13106-5)"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ sodipodi:nodetypes="cccc"
+ id="path22268-0"
+ d="m 116,443 11,1 -2,-10 -9,9 z"
+ style="display:inline;opacity:0.16000001;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;filter:url(#filter63011-5)" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 116,443 0.0108,0.72434 L 126,441 l 0,-7 -1,0 -9,9 z"
+ id="path22270-1"
+ sodipodi:nodetypes="cccccc"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc"
+ id="path22272-3"
+ style="opacity:0.15;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="m 147.5,435 0,38.5 -30.5,0"
+ inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
</g>
</g>
+ <g
+ id="g21517-6"
+ inkscape:label="Layer 1"
+ transform="matrix(0.5406242,0,0,0.5829534,814.13667,247.65542)">
+ <ellipse
+ ry="5.3033009"
+ rx="15.467961"
+ cy="38.98439"
+ cx="28.019106"
+ transform="matrix(1.274286,0,0,1.377124,-7.569123,-16.70193)"
+ id="path35486-4"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.54857142;fill:url(#radialGradient21442-6-790);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="csssssssssscccsscccscccssccc"
+ d="m 16.048489,28.093447 c 0.0098,0.576682 0.196474,1.697902 0.471116,2.577425 0.581566,1.854137 1.56684,3.572658 2.939126,5.086496 1.407488,1.553118 3.138519,2.803227 5.139315,3.68976 2.105357,0.931573 4.384795,1.407488 6.750134,1.403741 2.365339,-0.005 4.644601,-0.488686 6.74896,-1.427017 2.00002,-0.895288 3.731043,-2.148391 5.13754,-3.705517 1.369207,-1.519844 2.352576,-3.241114 2.934089,-5.096258 0.294262,-0.938353 0.476921,-1.889392 0.553238,-2.845308 0.07331,-0.939306 0.04204,-1.883511 -0.09183,-2.823792 -0.259981,-1.835599 -0.896294,-3.556847 -1.872652,-5.12758 -0.895541,-1.441699 -2.047808,-2.70454 -3.417268,-3.766975 0,0 0.002,-0.002 0.002,-0.002 0,0 -13.828458,-10.6197195 -13.828458,-10.6197195 -0.01176,-0.00978 -0.02252,-0.019551 -0.03529,-0.028344 -0.909003,-0.6959264 -3.879837,-0.7738945 -4.87679,-0.075035 -1.01067,0.7057021 -1.091821,1.8092613 -0.195527,2.5482146 1.899775,1.4997633 2.656207,2.2801589 4.566507,3.7797379 0,0 -14.852491,0.167033 -14.852491,0.167033 -1.994685,0 -3.1682609,0.947915 -3.4153947,2.333683 -0.2180771,1.222836 0.7479213,2.738129 2.4800217,2.738129 2.956573,0.0039 5.942111,-0.0069 8.909215,-0.01272 0,0 -16.01999,12.453223 -16.01999,12.453223 -0.020527,0.01564 -0.041053,0.02933 -0.06158,0.04497 -1.4974197,1.148389 -1.9831951,3.059322 -1.0399808,4.268393 0.9598323,1.22959 2.9977653,1.230588 4.5147288,0.006 0,0 8.677593,-7.102098 8.677593,-7.102098 0,0 -0.12511,0.959824 -0.116333,1.535532 l 1e-6,2.6e-5 0,0 0,0 z"
+ id="path2482-9"
+ style="fill:#dd6d00;fill-rule:evenodd;stroke:#993d00;stroke-width:1.7812928;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none" />
+ <ellipse
+ ry="10.125"
+ rx="11.5625"
+ cy="25.75"
+ cx="31.1875"
+ transform="matrix(0.8018194,0,0,0.8471126,6.257567,4.5089892)"
+ id="path39153-3"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient21444-0-352);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ style="opacity:0.4857143;fill:none;stroke:url(#linearGradient21446-3-145);stroke-width:1.7812928;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1"
+ d="m 25.8125,6.40625 c -0.334829,4.572e-4 -0.72202,0.089606 -0.90625,0.21875 4.5e-4,0.010412 4.5e-4,0.020838 0,0.03125 -0.212626,0.1484635 -0.188235,0.1956271 -0.1875,0.1875 0.0092,0.010621 -0.0072,-4.246e-4 0.03125,0.03125 0.01962,0.00828 0.03527,0.012546 0.0625,0.03125 0.01676,0.01151 0.01357,0.014555 0.03125,0.03125 0.193748,0.1576058 4.954976,4.005164 4.954976,4.005164 0.489837,0.39864 0.677395,1.066352 0.46875,1.65625 -0.115662,0.32703 -0.422813,0.541217 -0.6875,0.59375 -0.264687,0.05253 -0.498447,0.03054 -0.71875,0.03125 -5.639658,0.05119 -16.87989,0.03851 -16.87989,0.03851 -0.4102,2.75e-4 -0.935835,0.115997 -1.34375,0.34375 -0.407915,0.227753 -0.6637862,0.523861 -0.6875002,0.90625 -0.024417,0.393728 0.098829,0.605767 0.3437502,0.78125 0.244921,0.175483 0.614978,0.25 0.875,0.25 0,0 8.8125,0 8.8125,0 0.600305,-7.28e-4 1.223895,0.311058 1.4375,0.9375 0.04676,0.137121 0.06335,0.269976 0.0625,0.40625 -8.49e-4,0.136274 -0.02214,0.268794 -0.09375,0.375 -0.143211,0.212412 -0.319507,0.298568 -0.5,0.4375 0,0 -15.7871819,12.746851 -15.856336,12.800078 C 5.0310984,30.500117 5,30.53125 5,30.53125 5.0100745,30.519077 5.000335,30.499512 5,30.5 L 4.8125,30.3125 c 0.012336,0.02165 0.014481,0.03307 0.03125,0.0625 0.063558,0.0774 0.125,0.15625 0.125,0.15625 -0.00585,0.0056 -0.031233,0.03124 -0.03125,0.03125 0,0 -0.043442,-0.09921 -0.09375,-0.1875 0.037843,0.09884 0.06253,0.218739 0.0625,0.21875 -0.4662091,0.37119 -0.7783348,0.889746 -0.875,1.28125 -0.1043319,0.422581 -0.046,0.62455 0.125,0.84375 0.2999827,0.384295 1.3975356,0.595547 2.40625,-0.21875 0,0 8.65625,-7.09375 8.65625,-7.09375 0.473718,-0.387074 1.1446,-0.458625 1.6875,-0.15625 0.544608,0.303331 0.798054,0.927572 0.71875,1.53125 0,0 -0.0626,0.908319 -0.0625,1.25 2e-6,0.0085 -1.19e-4,0.02348 0,0.03125 0.192796,2.523718 1.400736,4.762818 3.03125,6.71875 2.801818,3.089095 6.627659,4.401619 10.75,4.5625 4.113324,-0.043 7.964529,-1.606111 10.75,-4.625 2.546631,-3.125326 3.513872,-6.363859 3.15625,-9.375 C 44.891575,22.325847 43.222923,19.516566 40.4375,17.25 35.951885,13.599946 31.206991,10.168434 26.59375,6.625 26.57515,6.610386 26.56455,6.59802 26.5625,6.59375 26.43835,6.498703 26.144223,6.4057899 25.8125,6.40625 Z"
+ id="path21414-5"
+ sodipodi:nodetypes="csssssscssscsssccssscscccsccssssccscsscccssssc" />
+ <path
+ inkscape:connector-curvature="0"
+ d="m 25.708956,26.064593 c 0.07649,-1.397943 0.759369,-2.631914 1.78592,-3.505519 1.010226,-0.858782 2.366788,-1.383145 3.848625,-1.383145 1.480894,0 2.837456,0.524363 3.847446,1.383145 1.027685,0.873605 1.709741,2.106651 1.787122,3.504594 0.07927,1.438713 -0.49591,2.77459 -1.504012,3.764001 -1.027686,1.007933 -2.493008,1.640678 -4.130556,1.640678 -1.63849,0 -3.103814,-0.632745 -4.131451,-1.640678 -1.00914,-0.989411 -1.58234,-2.325288 -1.503094,-3.763076 l 0,0 0,0 0,0 z"
+ id="path2478-8"
+ style="fill:#2f5b94;fill-rule:evenodd;stroke:none" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="csssscsccsscsccssssscsscccsssc"
+ id="path39166-5"
+ d="m 25.8125,6.03125 c -0.404852,5.53e-4 -2.204797,-0.059029 -2.48145,0.1349032 -0.280209,0.195652 -0.335403,0.376484 -0.34375,0.46875 -0.0083,0.092266 -0.01539,0.17648 0.1875,0.34375 0.01899,0.015735 0.04457,0.014317 0.0625,0.03125 0.124258,0.101028 4.748869,4.1248618 4.748869,4.1248618 0.373658,0.304091 0.504393,0.795817 0.34375,1.25 -0.160635,0.454191 -0.580748,0.373449 -1.0625,0.375 -5.634142,0.05114 -15.087371,-0.129601 -15.087371,-0.129601 -0.952967,6.38e-4 -2.339958,0.524782 -2.4062504,1.59375 -0.063562,1.024947 0.9247974,1.4375 1.5937504,1.4375 0,-1e-6 8.8125,0 8.8125,0 0.488364,-5.92e-4 0.936141,0.225277 1.09375,0.6875 0.157609,0.462231 -0.01926,0.514621 -0.40625,0.8125 0,0 -16.086298,13.088586 -16.086298,13.088586 -0.00142,0.0014 -0.029829,-0.0014 -0.03125,0 -0.064037,0.04879 -0.054226,0.04875 -0.03125,0.03125 -0.5536758,0.424619 -0.9087886,1.004019 -1.03125,1.5 -0.1224536,0.495981 -0.04661,0.856152 0.1875,1.15625 0.4788333,0.613413 1.777612,0.754857 2.90625,-0.15625 1e-7,10e-7 8.65625,-7.09375 8.65625,-7.09375 0.361955,-0.295753 0.872897,-0.352437 1.28125,-0.125 0.408345,0.227436 0.623381,0.692814 0.5625,1.15625 0,-1e-6 -0.0997,0.953636 -0.09375,1.34375 0.09498,1.301756 0.451616,2.521825 0.989039,3.664234 C 20.799917,36.321089 27.770982,19.392853 44.1875,21.03125 43.339652,19.54368 42.151282,18.185293 40.65625,16.96875 36.159865,13.309932 31.42016,9.882897 26.8125,6.34375 26.805335,6.338858 26.788292,6.317553 26.78125,6.3125 26.570707,6.151312 26.216591,6.030689 25.8125,6.03125 Z"
+ style="opacity:0.51999996;fill:url(#radialGradient21448-8-143);fill-opacity:1;fill-rule:evenodd;stroke:none" />
+ </g>
</g>
<g
transform="translate(0,12)"
@@ -20293,7 +20838,7 @@
<path
sodipodi:nodetypes="cc"
id="path34332"
- style="fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
d=""
inkscape:connector-curvature="0" />
</g>
diff --git a/release/datafiles/splash.png b/release/datafiles/splash.png
index fa893b4be0d..60956db2576 100644
--- a/release/datafiles/splash.png
+++ b/release/datafiles/splash.png
Binary files differ
diff --git a/release/datafiles/splash_2x.png b/release/datafiles/splash_2x.png
index f8dd2bbeaf3..3a5000c6bbc 100644
--- a/release/datafiles/splash_2x.png
+++ b/release/datafiles/splash_2x.png
Binary files differ
diff --git a/release/datafiles/splash_scale.sh b/release/datafiles/splash_scale.sh
new file mode 100755
index 00000000000..8a3f2c6d1eb
--- /dev/null
+++ b/release/datafiles/splash_scale.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+# Use this script to generate splash.png from splash_2x.png.
+# Supposed to give best quality image.
+#
+# Based on ImageMagic documentation, which is interesting
+# to read anyway:
+#
+# http://www.imagemagick.org/Usage/filter
+# http://www.imagemagick.org/Usage/filter/nicolas/
+
+convert \
+ splash_2x.png \
+ -colorspace RGB \
+ -filter Cosine \
+ -resize 50% \
+ -colorspace sRGB \
+ splash.png
diff --git a/release/datafiles/splash_template.xcf b/release/datafiles/splash_template.xcf
index b3141471c51..12719b5c155 100644
--- a/release/datafiles/splash_template.xcf
+++ b/release/datafiles/splash_template.xcf
Binary files differ
diff --git a/release/scripts/addons b/release/scripts/addons
-Subproject 407d0ea752b3af73d3f13ba072671bd09eefecb
+Subproject 06dad53c80801e0e0919f086040e3d9c31bbd0a
diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib
-Subproject 9f29e18707917ec5be262431d2e09dbb85332f4
+Subproject 04af69be141a5757fc60b44cc1a5b72db524af3
diff --git a/release/scripts/freestyle/modules/parameter_editor.py b/release/scripts/freestyle/modules/parameter_editor.py
index 082ce139a59..93305cb7c5a 100644
--- a/release/scripts/freestyle/modules/parameter_editor.py
+++ b/release/scripts/freestyle/modules/parameter_editor.py
@@ -914,14 +914,25 @@ class QuantitativeInvisibilityRangeUP1D(UnaryPredicate1D):
return self.qi_start <= qi <= self.qi_end
+def getQualifiedObjectName(ob):
+ if ob.library is not None:
+ return ob.library.filepath + '/' + ob.name
+ return ob.name
+
+
class ObjectNamesUP1D(UnaryPredicate1D):
def __init__(self, names, negative):
UnaryPredicate1D.__init__(self)
self.names = names
self.negative = negative
+ def getViewShapeName(self, vs):
+ if vs.library_path is not None:
+ return vs.library_path + '/' + vs.name
+ return vs.name
+
def __call__(self, viewEdge):
- found = viewEdge.viewshape.name in self.names
+ found = self.getViewShapeName(viewEdge.viewshape) in self.names
if self.negative:
return not found
return found
@@ -1256,7 +1267,7 @@ def process(layer_name, lineset_name):
# prepare selection criteria by group of objects
if lineset.select_by_group:
if lineset.group is not None:
- names = {ob.name: True for ob in lineset.group.objects}
+ names = {getQualifiedObjectName(ob): True for ob in lineset.group.objects}
upred = ObjectNamesUP1D(names, lineset.group_negation == 'EXCLUSIVE')
selection_criteria.append(upred)
# prepare selection criteria by image border
diff --git a/release/scripts/modules/addon_utils.py b/release/scripts/modules/addon_utils.py
index 95c0e5f187d..0f096f5812c 100644
--- a/release/scripts/modules/addon_utils.py
+++ b/release/scripts/modules/addon_utils.py
@@ -26,7 +26,7 @@ __all__ = (
"disable",
"reset_all",
"module_bl_info",
- )
+)
import bpy as _bpy
_user_preferences = _bpy.context.user_preferences
@@ -458,7 +458,7 @@ def module_bl_info(mod, info_basis=None):
"category": "",
"warning": "",
"show_expanded": False,
- }
+ }
addon_info = getattr(mod, "bl_info", {})
diff --git a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
index 5a3eda567be..3b7eff6db9c 100644
--- a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
+++ b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
@@ -230,12 +230,13 @@ def dump_rna_messages(msgs, reports, settings, verbose=False):
_rna = {getattr(bpy.types, cls) for cls in dir(bpy.types)}
# Classes which are attached to collections can be skipped too, these are api access only.
- for cls in _rna:
- for prop in cls.bl_rna.properties:
- if prop.type == 'COLLECTION':
- prop_cls = prop.srna
- if prop_cls is not None:
- blacklist_rna_class.add(prop_cls.__class__)
+ # XXX This is not true, some of those show in UI, see e.g. tooltip of KeyingSets.active...
+ #~ for cls in _rna:
+ #~ for prop in cls.bl_rna.properties:
+ #~ if prop.type == 'COLLECTION':
+ #~ prop_cls = prop.srna
+ #~ if prop_cls is not None:
+ #~ blacklist_rna_class.add(prop_cls.__class__)
# Now here is the *ugly* hack!
# Unfortunately, all classes we want to access are not available from bpy.types (OperatorProperties subclasses
@@ -375,6 +376,7 @@ def dump_rna_messages(msgs, reports, settings, verbose=False):
walk_keymap_hierarchy(lvl[3], msgsrc)
# Dump Messages
+ operator_categories = {}
def process_cls_list(cls_list):
if not cls_list:
return
@@ -391,6 +393,16 @@ def dump_rna_messages(msgs, reports, settings, verbose=False):
cls_id = bl_rna.identifier + "." + cls_id
bl_rna = bl_rna.base
return cls_id
+
+ def operator_category(cls):
+ """Extract operators' categories, as displayed in 'search' space menu."""
+ # NOTE: keep in sync with C code in ui_searchbox_region_draw_cb__operator().
+ if issubclass(cls, bpy.types.OperatorProperties) and "_OT_" in cls.__name__:
+ cat_id = cls.__name__.split("_OT_")[0]
+ if cat_id not in operator_categories:
+ cat_str = cat_id.capitalize() + ":"
+ operator_categories[cat_id] = cat_str
+
if verbose:
print(cls_list)
cls_list.sort(key=full_class_id)
@@ -402,6 +414,7 @@ def dump_rna_messages(msgs, reports, settings, verbose=False):
if (cls in blacklist_rna_class) or issubclass(cls, bpy.types.Operator):
reports["rna_structs_skipped"].append(cls)
else:
+ operator_category(cls)
walk_class(cls)
# Recursively process subclasses.
process_cls_list(cls.__subclasses__())
@@ -409,6 +422,11 @@ def dump_rna_messages(msgs, reports, settings, verbose=False):
# Parse everything (recursively parsing from bpy_struct "class"...).
process_cls_list(bpy.types.ID.__base__.__subclasses__())
+ # Finalize generated 'operator categories' messages.
+ for cat_str in operator_categories.values():
+ process_msg(msgs, bpy.app.translations.contexts.operator_default, cat_str, "Generated operator category",
+ reports, check_ctxt_rna, settings)
+
# And parse keymaps!
from bpy_extras.keyconfig_utils import KM_HIERARCHY
walk_keymap_hierarchy(KM_HIERARCHY, "KM_HIERARCHY")
diff --git a/release/scripts/modules/bl_i18n_utils/settings.py b/release/scripts/modules/bl_i18n_utils/settings.py
index dd6b79f6686..07fc9f0c338 100644
--- a/release/scripts/modules/bl_i18n_utils/settings.py
+++ b/release/scripts/modules/bl_i18n_utils/settings.py
@@ -329,16 +329,21 @@ WARN_MSGID_NOT_CAPITALIZED_ALLOWED = {
"available with",
"brown fox",
"can't save image while rendering",
+ "constructive modifier",
+ "edge data",
"expected a timeline/animation area to be active",
"expected a view3d region",
"expected a view3d region & editcurve",
"expected a view3d region & editmesh",
+ "face data",
"image file not found",
"image format is read-only",
"image path can't be written to",
"in memory to enable editing!",
"jumps over",
"left",
+ "multi-res modifier",
+ "non-triangle face",
"right",
"the lazy dog",
"unable to load movie clip",
@@ -351,6 +356,7 @@ WARN_MSGID_NOT_CAPITALIZED_ALLOWED = {
"unsupported format",
"unsupported image format",
"unsupported movie clip format",
+ "vertex data",
"verts only",
"virtual parents",
}
diff --git a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py
index df014e8262b..f749cf82bb9 100644
--- a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py
+++ b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py
@@ -58,7 +58,6 @@ class SpellChecker:
"vertices",
# Merged words
- "addon", "addons",
"antialiasing",
"arcsine", "arccosine", "arctangent",
"autoclip",
@@ -118,6 +117,7 @@ class SpellChecker:
"localview",
"lookup", "lookups",
"mathutils",
+ "micropolygon",
"midlevel",
"midground",
"mixdown",
@@ -126,7 +126,9 @@ class SpellChecker:
"multipaint",
"multires", "multiresolution",
"multisampling",
+ "multiscatter",
"multitexture",
+ "multithreaded",
"multiuser",
"multiview",
"namespace",
@@ -151,7 +153,7 @@ class SpellChecker:
"realtime",
"rekey",
"remesh",
- "reprojection",
+ "reprojection", "reproject",
"resize",
"restpose",
"retarget", "retargets", "retargeting", "retargeted",
@@ -161,6 +163,7 @@ class SpellChecker:
"runtime",
"scanline",
"screencast", "screenshot", "screenshots",
+ "seekability",
"selfcollision",
"shadowbuffer", "shadowbuffers",
"singletexture",
@@ -182,6 +185,7 @@ class SpellChecker:
"timestamp", "timestamps",
"timestep", "timesteps",
"todo",
+ "tradeoff",
"un",
"unbake",
"uncomment",
@@ -195,6 +199,7 @@ class SpellChecker:
"unmute",
"unpremultiply",
"unprojected",
+ "unprotect",
"unreacted",
"unregister",
"unselected", "unselectable",
@@ -412,6 +417,7 @@ class SpellChecker:
# Blender terms
"audaspace",
"bbone",
+ "bendy", # bones
"bmesh",
"breakdowner",
"bspline",
@@ -473,9 +479,16 @@ class SpellChecker:
"wpaint",
"uvwarp",
- # Algorithm names
+ # UOC (Ugly Operator Categories)
+ "cachefile",
+ "paintcurve",
+ "ptcache",
+ "dpaint",
+
+ # Algorithm/library names
"ashikhmin", # Ashikhmin-Shirley
"beckmann",
+ "blosc",
"catmull",
"catrom",
"chebychev",
@@ -489,6 +502,7 @@ class SpellChecker:
"musgrave",
"nayar",
"netravali",
+ "ogawa",
"oren",
"preetham",
"prewitt",
@@ -526,6 +540,7 @@ class SpellChecker:
"futura",
"fx",
"gfx",
+ "ggx",
"gl",
"glsl",
"gpl",
@@ -560,7 +575,9 @@ class SpellChecker:
"ui",
"unix",
"vbo", "vbos",
+ "wxyz",
"ycc", "ycca",
+ "yrgb",
"yuv", "yuva",
# Blender acronyms
diff --git a/release/scripts/modules/bl_previews_utils/bl_previews_render.py b/release/scripts/modules/bl_previews_utils/bl_previews_render.py
index 674c1c00ab1..b4f0b8dd3b8 100644
--- a/release/scripts/modules/bl_previews_utils/bl_previews_render.py
+++ b/release/scripts/modules/bl_previews_utils/bl_previews_render.py
@@ -21,9 +21,7 @@
# Populate a template file (POT format currently) from Blender RNA/py/C data.
# Note: This script is meant to be used from inside Blender!
-import collections
import os
-import sys
import bpy
from mathutils import Vector, Euler, Matrix
@@ -67,6 +65,8 @@ def rna_backup_restore(data, backup):
def do_previews(do_objects, do_groups, do_scenes, do_data_intern):
+ import collections
+
# Helpers.
RenderContext = collections.namedtuple("RenderContext", (
"scene", "world", "camera", "lamp", "camera_data", "lamp_data", "image", # All those are names!
@@ -169,7 +169,7 @@ def do_previews(do_objects, do_groups, do_scenes, do_data_intern):
scene.objects.unlink(bpy.data.objects[render_context.camera, None])
if render_context.lamp:
scene.objects.unlink(bpy.data.objects[render_context.lamp, None])
- bpy.data.scenes.remove(scene)
+ bpy.data.scenes.remove(scene, do_unlink=True)
scene = None
else:
rna_backup_restore(scene, render_context.backup_scene)
@@ -236,8 +236,8 @@ def do_previews(do_objects, do_groups, do_scenes, do_data_intern):
return success
def objects_render_engine_guess(obs):
- for obname in obs:
- ob = bpy.data.objects[obname, None]
+ for obname, libpath in obs:
+ ob = bpy.data.objects[obname, libpath]
for matslot in ob.material_slots:
mat = matslot.material
if mat and mat.use_nodes and mat.node_tree:
@@ -247,10 +247,20 @@ def do_previews(do_objects, do_groups, do_scenes, do_data_intern):
return 'BLENDER_RENDER'
def object_bbox_merge(bbox, ob, ob_space, offset_matrix):
- if ob.bound_box:
+ # Take group instances into account (including linked one in this case).
+ if ob.type == 'EMPTY' and ob.dupli_type == 'GROUP':
+ grp_objects = tuple((ob.name, ob.library.filepath if ob.library else None) for ob in ob.dupli_group.objects)
+ if (len(grp_objects) == 0):
+ ob_bbox = ob.bound_box
+ else:
+ coords = objects_bbox_calc(ob_space, grp_objects,
+ Matrix.Translation(ob.dupli_group.dupli_offset).inverted())
+ ob_bbox = ((coords[0], coords[1], coords[2]), (coords[21], coords[22], coords[23]))
+ elif ob.bound_box:
ob_bbox = ob.bound_box
else:
ob_bbox = ((-ob.scale.x, -ob.scale.y, -ob.scale.z), (ob.scale.x, ob.scale.y, ob.scale.z))
+
for v in ob_bbox:
v = offset_matrix * Vector(v) if offset_matrix is not None else Vector(v)
v = ob_space.matrix_world.inverted() * ob.matrix_world * v
@@ -269,8 +279,8 @@ def do_previews(do_objects, do_groups, do_scenes, do_data_intern):
def objects_bbox_calc(camera, objects, offset_matrix):
bbox = (Vector((1e9, 1e9, 1e9)), Vector((-1e9, -1e9, -1e9)))
- for obname in objects:
- ob = bpy.data.objects[obname, None]
+ for obname, libpath in objects:
+ ob = bpy.data.objects[obname, libpath]
object_bbox_merge(bbox, ob, camera, offset_matrix)
# Our bbox has been generated in camera local space, bring it back in world one
bbox[0][:] = camera.matrix_world * bbox[0]
@@ -333,7 +343,7 @@ def do_previews(do_objects, do_groups, do_scenes, do_data_intern):
continue
if root.type not in OBJECT_TYPES_RENDER:
continue
- objects = (root.name,)
+ objects = ((root.name, None),)
render_engine = objects_render_engine_guess(objects)
render_context = render_contexts.get(render_engine, None)
@@ -344,8 +354,8 @@ def do_previews(do_objects, do_groups, do_scenes, do_data_intern):
scene = bpy.data.scenes[render_context.scene, None]
bpy.context.screen.scene = scene
- for obname in objects:
- ob = bpy.data.objects[obname, None]
+ for obname, libpath in objects:
+ ob = bpy.data.objects[obname, libpath]
if obname not in scene.objects:
scene.objects.link(ob)
ob.hide_render = False
@@ -362,10 +372,9 @@ def do_previews(do_objects, do_groups, do_scenes, do_data_intern):
# File "<string>", line 327, in do_previews
# OverflowError: Python int too large to convert to C long
# ... :(
- import sys
scene = bpy.data.scenes[render_context.scene, None]
- for obname in objects:
- ob = bpy.data.objects[obname, None]
+ for obname, libpath in objects:
+ ob = bpy.data.objects[obname, libpath]
scene.objects.unlink(ob)
ob.hide_render = True
@@ -378,7 +387,8 @@ def do_previews(do_objects, do_groups, do_scenes, do_data_intern):
for grp in ids_nolib(bpy.data.groups):
if grp.name in groups_ignored:
continue
- objects = tuple(ob.name for ob in grp.objects)
+ # Here too, we do want to keep linked objects members of local group...
+ objects = tuple((ob.name, ob.library.filepath if ob.library else None) for ob in grp.objects)
render_engine = objects_render_engine_guess(objects)
render_context = render_contexts.get(render_engine, None)
@@ -416,7 +426,7 @@ def do_previews(do_objects, do_groups, do_scenes, do_data_intern):
objects = None
if not has_camera:
# We had to add a temp camera, now we need to place it to see interesting objects!
- objects = tuple(ob.name for ob in scene.objects
+ objects = tuple((ob.name, ob.library.filepath if ob.library else None) for ob in scene.objects
if (not ob.hide_render) and (ob.type in OBJECT_TYPES_RENDER))
preview_render_do(render_context, 'scenes', scene.name, objects)
diff --git a/release/scripts/modules/blend_render_info.py b/release/scripts/modules/blend_render_info.py
index a62eaeea143..30c3ed2388b 100755
--- a/release/scripts/modules/blend_render_info.py
+++ b/release/scripts/modules/blend_render_info.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# ##### BEGIN GPL LICENSE BLOCK #####
#
@@ -42,8 +42,8 @@ def read_blend_rend_chunk(path):
if head[0:2] == b'\x1f\x8b': # gzip magic
import gzip
- blendfile.close()
- blendfile = gzip.open(path, "rb")
+ blendfile.seek(0)
+ blendfile = gzip.open(blendfile, "rb")
head = blendfile.read(7)
if head != b'BLENDER':
diff --git a/release/scripts/modules/bpy/__init__.py b/release/scripts/modules/bpy/__init__.py
index f012c1317d4..26fdbc8cc56 100644
--- a/release/scripts/modules/bpy/__init__.py
+++ b/release/scripts/modules/bpy/__init__.py
@@ -31,7 +31,7 @@ __all__ = (
"props",
"types",
"utils",
- )
+)
# internal blender C module
@@ -57,11 +57,11 @@ def main():
# fake module to allow:
# from bpy.types import Panel
sys.modules.update({
- "bpy.app": app,
- "bpy.app.handlers": app.handlers,
- "bpy.app.translations": app.translations,
- "bpy.types": types,
- })
+ "bpy.app": app,
+ "bpy.app.handlers": app.handlers,
+ "bpy.app.translations": app.translations,
+ "bpy.types": types,
+ })
# Initializes Python classes.
# (good place to run a profiler or trace).
diff --git a/release/scripts/modules/bpy/path.py b/release/scripts/modules/bpy/path.py
index 30f6c8eebed..a864a86eba7 100644
--- a/release/scripts/modules/bpy/path.py
+++ b/release/scripts/modules/bpy/path.py
@@ -39,16 +39,16 @@ __all__ = (
"reduce_dirs",
"relpath",
"resolve_ncase",
- )
+)
import bpy as _bpy
import os as _os
from _bpy_path import (
- extensions_audio,
- extensions_movie,
- extensions_image,
- )
+ extensions_audio,
+ extensions_movie,
+ extensions_image,
+)
def _getattr_bytes(var, attr):
@@ -71,22 +71,22 @@ def abspath(path, start=None, library=None):
if path.startswith(b"//"):
if library:
start = _os.path.dirname(
- abspath(_getattr_bytes(library, "filepath")))
+ abspath(_getattr_bytes(library, "filepath")))
return _os.path.join(
- _os.path.dirname(_getattr_bytes(_bpy.data, "filepath"))
- if start is None else start,
- path[2:],
- )
+ _os.path.dirname(_getattr_bytes(_bpy.data, "filepath"))
+ if start is None else start,
+ path[2:],
+ )
else:
if path.startswith("//"):
if library:
start = _os.path.dirname(
- abspath(library.filepath))
+ abspath(library.filepath))
return _os.path.join(
- _os.path.dirname(_bpy.data.filepath)
- if start is None else start,
- path[2:],
- )
+ _os.path.dirname(_bpy.data.filepath)
+ if start is None else start,
+ path[2:],
+ )
return path
@@ -175,7 +175,7 @@ def clean_name(name, replace="_"):
0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe,
- )
+ )
trans = str.maketrans({char: replace for char in bad_chars})
trans_cache[replace] = trans
return trans
diff --git a/release/scripts/modules/bpy/utils/__init__.py b/release/scripts/modules/bpy/utils/__init__.py
index 986d8b9f45c..66974dedc24 100644
--- a/release/scripts/modules/bpy/utils/__init__.py
+++ b/release/scripts/modules/bpy/utils/__init__.py
@@ -52,15 +52,15 @@ __all__ = (
)
from _bpy import (
+ _utils_units as units,
+ blend_paths,
escape_identifier,
register_class,
- unregister_class,
- blend_paths,
resource_path,
+ script_paths as _bpy_script_paths,
+ unregister_class,
+ user_resource as _user_resource,
)
-from _bpy import script_paths as _bpy_script_paths
-from _bpy import user_resource as _user_resource
-from _bpy import _utils_units as units
import bpy as _bpy
import os as _os
@@ -305,15 +305,21 @@ def script_paths(subdir=None, user_pref=True, check_all=False):
"""
scripts = list(_scripts)
- if check_all:
- # all possible paths
- base_paths = tuple(_os.path.join(resource_path(res), "scripts")
- for res in ('LOCAL', 'USER', 'SYSTEM'))
- else:
- # only paths blender uses
- base_paths = _bpy_script_paths()
+ # Only paths Blender uses.
+ #
+ # Needed this is needed even when 'check_all' is enabled,
+ # so the 'BLENDER_SYSTEM_SCRIPTS' environment variable will be used.
+ base_paths = _bpy_script_paths()
- for path in base_paths + (script_path_user(), script_path_pref()):
+ if check_all:
+ # All possible paths, no duplicates, keep order.
+ base_paths = (
+ *(path for path in (_os.path.join(resource_path(res), "scripts")
+ for res in ('LOCAL', 'USER', 'SYSTEM')) if path not in base_paths),
+ *base_paths,
+ )
+
+ for path in (*base_paths, script_path_user(), script_path_pref()):
if path:
path = _os.path.normpath(path)
if path not in scripts and _os.path.isdir(path):
@@ -635,11 +641,10 @@ def unregister_module(module, verbose=False):
# we start with the built-in default mapping
def _blender_default_map():
- import sys
import rna_manual_reference as ref_mod
ret = (ref_mod.url_manual_prefix, ref_mod.url_manual_mapping)
# avoid storing in memory
- del sys.modules["rna_manual_reference"]
+ del _sys.modules["rna_manual_reference"]
return ret
# hooks for doc lookups
diff --git a/release/scripts/modules/bpy/utils/previews.py b/release/scripts/modules/bpy/utils/previews.py
index c67c523ea72..568116b027c 100644
--- a/release/scripts/modules/bpy/utils/previews.py
+++ b/release/scripts/modules/bpy/utils/previews.py
@@ -30,7 +30,7 @@ This allows scripts to generate their own previews, and use them as icons in UI
Custom Icon Example
-------------------
-.. literalinclude:: ../../../release/scripts/templates_py/ui_previews_custom_icon.py
+.. literalinclude:: __/__/__/release/scripts/templates_py/ui_previews_custom_icon.py
"""
__all__ = (
diff --git a/release/scripts/modules/bpy_extras/anim_utils.py b/release/scripts/modules/bpy_extras/anim_utils.py
index 021a8bbb530..5e21260e5e4 100644
--- a/release/scripts/modules/bpy_extras/anim_utils.py
+++ b/release/scripts/modules/bpy_extras/anim_utils.py
@@ -49,7 +49,7 @@ def bake_action(frame_start,
:type frame_end: int
:arg frame_step: Frame step.
:type frame_step: int
- :arg only_selected: Only bake selected data.
+ :arg only_selected: Only bake selected bones.
:type only_selected: bool
:arg do_pose: Bake pose channels.
:type do_pose: bool
@@ -155,6 +155,11 @@ def bake_action(frame_start,
atd = obj.animation_data_create()
if action is None:
action = bpy.data.actions.new("Action")
+
+ # Leave tweak mode before trying to modify the action (T48397)
+ if atd.use_tweak_mode:
+ atd.use_tweak_mode = False
+
atd.action = action
# -------------------------------------------------------------------------
diff --git a/release/scripts/modules/bpy_extras/keyconfig_utils.py b/release/scripts/modules/bpy_extras/keyconfig_utils.py
index 6246e4489e1..6ecdd0c5e13 100644
--- a/release/scripts/modules/bpy_extras/keyconfig_utils.py
+++ b/release/scripts/modules/bpy_extras/keyconfig_utils.py
@@ -28,14 +28,12 @@ KM_HIERARCHY = [
('Screen', 'EMPTY', 'WINDOW', [ # full screen, undo, screenshot
('Screen Editing', 'EMPTY', 'WINDOW', []), # re-sizing, action corners
('Header', 'EMPTY', 'WINDOW', []), # header stuff (per region)
- ]),
+ ]),
('View2D', 'EMPTY', 'WINDOW', []), # view 2d navigation (per region)
('View2D Buttons List', 'EMPTY', 'WINDOW', []), # view 2d with buttons navigation
- ('User Interface', 'EMPTY', 'WINDOW', [
- ('Eyedropper Modal Map', 'EMPTY', 'WINDOW', []),
- ]),
+ ('User Interface', 'EMPTY', 'WINDOW', []),
('3D View', 'VIEW_3D', 'WINDOW', [ # view 3d navigation and generic stuff (select, transform)
('Object Mode', 'EMPTY', 'WINDOW', []),
@@ -71,16 +69,18 @@ KM_HIERARCHY = [
('View3D Dolly Modal', 'EMPTY', 'WINDOW', []),
('3D View Generic', 'VIEW_3D', 'WINDOW', []), # toolbar and properties
- ]),
+ ]),
('Graph Editor', 'GRAPH_EDITOR', 'WINDOW', [
('Graph Editor Generic', 'GRAPH_EDITOR', 'WINDOW', []),
- ]),
- ('Dopesheet', 'DOPESHEET_EDITOR', 'WINDOW', []),
+ ]),
+ ('Dopesheet', 'DOPESHEET_EDITOR', 'WINDOW', [
+ ('Dopesheet Generic', 'DOPESHEET_EDITOR', 'WINDOW', []),
+ ]),
('NLA Editor', 'NLA_EDITOR', 'WINDOW', [
('NLA Channels', 'NLA_EDITOR', 'WINDOW', []),
('NLA Generic', 'NLA_EDITOR', 'WINDOW', []),
- ]),
+ ]),
('Timeline', 'TIMELINE', 'WINDOW', []),
('Image', 'IMAGE_EDITOR', 'WINDOW', [
@@ -88,23 +88,23 @@ KM_HIERARCHY = [
('Image Paint', 'EMPTY', 'WINDOW', []), # image and view3d
('UV Sculpt', 'EMPTY', 'WINDOW', []),
('Image Generic', 'IMAGE_EDITOR', 'WINDOW', []),
- ]),
+ ]),
('Outliner', 'OUTLINER', 'WINDOW', []),
('Node Editor', 'NODE_EDITOR', 'WINDOW', [
('Node Generic', 'NODE_EDITOR', 'WINDOW', []),
- ]),
+ ]),
('Sequencer', 'SEQUENCE_EDITOR', 'WINDOW', [
('SequencerCommon', 'SEQUENCE_EDITOR', 'WINDOW', []),
('SequencerPreview', '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', []),
- ]),
+ ]),
('Info', 'INFO', 'WINDOW', []),
@@ -112,17 +112,17 @@ KM_HIERARCHY = [
('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', []),
- ]),
+ ]),
('Grease Pencil', 'EMPTY', 'WINDOW', [ # grease pencil stuff (per region)
('Grease Pencil Stroke Edit Mode', 'EMPTY', 'WINDOW', []),
- ]),
+ ]),
('Mask Editing', 'EMPTY', 'WINDOW', []),
('Frames', 'EMPTY', 'WINDOW', []), # frame navigation (per region)
('Markers', 'EMPTY', 'WINDOW', []), # markers (per region)
@@ -136,7 +136,8 @@ KM_HIERARCHY = [
('Standard Modal Map', 'EMPTY', 'WINDOW', []),
('Transform Modal Map', 'EMPTY', 'WINDOW', []),
- ]
+ ('Eyedropper Modal Map', 'EMPTY', 'WINDOW', []),
+]
# -----------------------------------------------------------------------------
@@ -237,7 +238,8 @@ def keyconfig_export(wm, kc, filepath):
" except Exception as e:\n"
" print(\"Warning: %r\" % e)\n\n")
f.write("wm = bpy.context.window_manager\n")
- f.write("kc = wm.keyconfigs.new(os.path.splitext(os.path.basename(__file__))[0])\n\n") # keymap must be created by caller
+ # keymap must be created by caller
+ f.write("kc = wm.keyconfigs.new(os.path.splitext(os.path.basename(__file__))[0])\n\n")
# Generate a list of keymaps to export:
#
@@ -265,7 +267,8 @@ def keyconfig_export(wm, kc, filepath):
km = km.active()
f.write("# Map %s\n" % km.name)
- f.write("km = kc.keymaps.new('%s', space_type='%s', region_type='%s', modal=%s)\n\n" % (km.name, km.space_type, km.region_type, km.is_modal))
+ f.write("km = kc.keymaps.new('%s', space_type='%s', region_type='%s', modal=%s)\n\n" %
+ (km.name, km.space_type, km.region_type, km.is_modal))
for kmi in km.keymap_items:
f.write(_kmistr(kmi, km.is_modal))
f.write("\n")
diff --git a/release/scripts/modules/bpy_extras/object_utils.py b/release/scripts/modules/bpy_extras/object_utils.py
index c2c306e5145..88cd7398fe0 100644
--- a/release/scripts/modules/bpy_extras/object_utils.py
+++ b/release/scripts/modules/bpy_extras/object_utils.py
@@ -137,16 +137,22 @@ def object_data_add(context, obdata, operator=None, use_active_layer=True, name=
if context.space_data and context.space_data.type == 'VIEW_3D':
v3d = context.space_data
+ if v3d and v3d.local_view:
+ base.layers_from_view(context.space_data)
+
if operator is not None and any(operator.layers):
base.layers = operator.layers
else:
if use_active_layer:
if v3d and v3d.local_view:
- base.layers_from_view(context.space_data)
base.layers[scene.active_layer] = True
else:
- base.layers = [True if i == scene.active_layer
- else False for i in range(len(scene.layers))]
+ if v3d and not v3d.lock_camera_and_layers:
+ base.layers = [True if i == v3d.active_layer
+ else False for i in range(len(v3d.layers))]
+ else:
+ base.layers = [True if i == scene.active_layer
+ else False for i in range(len(scene.layers))]
else:
if v3d:
base.layers_from_view(context.space_data)
diff --git a/release/scripts/modules/bpy_extras/view3d_utils.py b/release/scripts/modules/bpy_extras/view3d_utils.py
index 4aa06262970..a4834a4531c 100644
--- a/release/scripts/modules/bpy_extras/view3d_utils.py
+++ b/release/scripts/modules/bpy_extras/view3d_utils.py
@@ -23,7 +23,7 @@ __all__ = (
"region_2d_to_origin_3d",
"region_2d_to_location_3d",
"location_3d_to_region_2d",
- )
+)
def region_2d_to_vector_3d(region, rv3d, coord):
@@ -50,7 +50,7 @@ def region_2d_to_vector_3d(region, rv3d, coord):
out = Vector(((2.0 * coord[0] / region.width) - 1.0,
(2.0 * coord[1] / region.height) - 1.0,
-0.5
- ))
+ ))
w = out.dot(persinv[3].xyz) + persinv[3][3]
@@ -101,7 +101,7 @@ def region_2d_to_origin_3d(region, rv3d, coord, clamp=None):
persinv = persmat.inverted()
origin_start = ((persinv.col[0].xyz * dx) +
(persinv.col[1].xyz * dy) +
- viewinv.translation)
+ persinv.translation)
if clamp != 0.0:
if rv3d.view_perspective != 'CAMERA':
diff --git a/release/scripts/modules/bpy_restrict_state.py b/release/scripts/modules/bpy_restrict_state.py
index 4658fddf0dc..589b3960b04 100644
--- a/release/scripts/modules/bpy_restrict_state.py
+++ b/release/scripts/modules/bpy_restrict_state.py
@@ -24,7 +24,7 @@ This module contains RestrictBlend context manager.
__all__ = (
"RestrictBlend",
- )
+)
import bpy as _bpy
diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py
index c1a37d10961..d64acd2ce3b 100644
--- a/release/scripts/modules/bpy_types.py
+++ b/release/scripts/modules/bpy_types.py
@@ -39,7 +39,7 @@ class Context(StructRNA):
generic_attrs = (
*StructRNA.__dict__.keys(),
"bl_rna", "rna_type", "copy",
- )
+ )
for attr in dir(self):
if not (attr.startswith("_") or attr in generic_attrs):
value = getattr(self, attr)
@@ -408,6 +408,14 @@ class Mesh(bpy_types.ID):
the *vertices* argument. eg: [(5, 6, 8, 9), (1, 2, 3), ...]
:type faces: iterable object
+
+ .. warning::
+
+ Invalid mesh data
+ *(out of range indices, edges with matching indices,
+ 2 sided faces... etc)* are **not** prevented.
+ If the data used for mesh creation isn't known to be valid,
+ run :class:`Mesh.validate` after this function.
"""
from itertools import chain, islice, accumulate
@@ -534,6 +542,7 @@ class Sound(bpy_types.ID):
class RNAMeta(type):
+
def __new__(cls, name, bases, classdict, **args):
result = type.__new__(cls, name, bases, classdict)
if bases and bases[0] is not StructRNA:
@@ -554,6 +563,7 @@ class RNAMeta(type):
class OrderedDictMini(dict):
+
def __init__(self, *args):
self.order = []
dict.__init__(self, args)
@@ -573,6 +583,7 @@ class RNAMetaPropGroup(StructMetaPropGroup, RNAMeta):
class OrderedMeta(RNAMeta):
+
def __init__(cls, name, bases, attributes):
if attributes.__class__ is OrderedDictMini:
cls.order = attributes.order
@@ -627,7 +638,7 @@ class Macro(StructRNA, metaclass=OrderedMeta):
class PropertyGroup(StructRNA, metaclass=RNAMetaPropGroup):
- __slots__ = ()
+ __slots__ = ()
class RenderEngine(StructRNA, metaclass=RNAMeta):
diff --git a/release/scripts/modules/console/complete_import.py b/release/scripts/modules/console/complete_import.py
index f28f61b303d..e7218594a86 100644
--- a/release/scripts/modules/console/complete_import.py
+++ b/release/scripts/modules/console/complete_import.py
@@ -112,10 +112,10 @@ def module_list(path):
folder_list = []
#folder_list = glob.glob(os.path.join(path,'*'))
folder_list = [
- p for p in folder_list
- if (os.path.exists(os.path.join(path, p, '__init__.py')) or
- p[-3:] in {'.py', '.so'} or
- p[-4:] in {'.pyc', '.pyo', '.pyd'})]
+ p for p in folder_list
+ if (os.path.exists(os.path.join(path, p, '__init__.py')) or
+ p[-3:] in {'.py', '.so'} or
+ p[-4:] in {'.pyc', '.pyo', '.pyd'})]
folder_list = [os.path.basename(p).split('.')[0] for p in folder_list]
return folder_list
@@ -161,7 +161,7 @@ def complete(line):
if (not hasattr(m, '__file__')) or (not only_modules) or\
(hasattr(m, '__file__') and '__init__' in m.__file__):
completion_list = [attr for attr in dir(m)
- if is_importable(m, attr)]
+ if is_importable(m, attr)]
else:
completion_list = []
completion_list.extend(getattr(m, '__all__', []))
diff --git a/release/scripts/modules/console/complete_namespace.py b/release/scripts/modules/console/complete_namespace.py
index 992bb72aa08..3f223ba93dc 100644
--- a/release/scripts/modules/console/complete_namespace.py
+++ b/release/scripts/modules/console/complete_namespace.py
@@ -85,7 +85,7 @@ def complete_indices(word, namespace, obj=None, base=None):
>>> complete_indices("foo['b", {'foo': {'bar':0, 1:2}}, base='foo')
["foo['bar']"]
"""
- #FIXME: 'foo["b'
+ # FIXME: 'foo["b'
if base is None:
base = word
if obj is None:
@@ -148,7 +148,7 @@ def complete(word, namespace, private=True):
if re_incomplete_index:
# ignore incomplete index at the end, e.g 'a[1' -> 'a'
matches = complete_indices(word, namespace,
- base=re_incomplete_index.group(1))
+ base=re_incomplete_index.group(1))
elif not('[' in word):
matches = complete_names(word, namespace)
diff --git a/release/scripts/modules/console/intellisense.py b/release/scripts/modules/console/intellisense.py
index b694cceafea..84d4bff281d 100644
--- a/release/scripts/modules/console/intellisense.py
+++ b/release/scripts/modules/console/intellisense.py
@@ -121,8 +121,8 @@ def expand(line, cursor, namespace, private=True):
"""
if line[:cursor].strip().endswith('('):
from . import complete_calltip
- matches, word, scrollback = complete_calltip.complete(line,
- cursor, namespace)
+ matches, word, scrollback = complete_calltip.complete(
+ line, cursor, namespace)
prefix = os.path.commonprefix(matches)[len(word):]
no_calltip = False
else:
@@ -138,11 +138,11 @@ def expand(line, cursor, namespace, private=True):
white_space = " " + (" " * (cursor + len(prefix)))
word_prefix = word + prefix
scrollback = '\n'.join(
- [white_space + m[len(word_prefix):]
- if (word_prefix and m.startswith(word_prefix))
- else
- white_space + m.split('.')[-1]
- for m in matches])
+ [white_space + m[len(word_prefix):]
+ if (word_prefix and m.startswith(word_prefix))
+ else
+ white_space + m.split('.')[-1]
+ for m in matches])
no_calltip = True
diff --git a/release/scripts/modules/console_python.py b/release/scripts/modules/console_python.py
index 64bb002d6a1..a740f31c830 100644
--- a/release/scripts/modules/console_python.py
+++ b/release/scripts/modules/console_python.py
@@ -142,9 +142,9 @@ def execute(context, is_interactive):
# redirect output
from contextlib import (
- redirect_stdout,
- redirect_stderr,
- )
+ redirect_stdout,
+ redirect_stderr,
+ )
# not included with Python
class redirect_stdin(redirect_stdout.__base__):
@@ -152,8 +152,8 @@ def execute(context, is_interactive):
# don't allow the stdin to be used, can lock blender.
with redirect_stdout(stdout), \
- redirect_stderr(stderr), \
- redirect_stdin(None):
+ redirect_stderr(stderr), \
+ redirect_stdin(None):
# in case exception happens
line = "" # in case of encoding error
@@ -258,10 +258,10 @@ def autocomplete(context):
# This function isn't aware of the text editor or being an operator
# just does the autocomplete then copy its results back
result = intellisense.expand(
- line=line,
- cursor=current_line.current_character,
- namespace=console.locals,
- private=bpy.app.debug_python)
+ line=line,
+ cursor=current_line.current_character,
+ namespace=console.locals,
+ private=bpy.app.debug_python)
line_new = result[0]
current_line.body, current_line.current_character, scrollback = result
diff --git a/release/scripts/modules/keyingsets_utils.py b/release/scripts/modules/keyingsets_utils.py
index 03400edc904..8cef64c3590 100644
--- a/release/scripts/modules/keyingsets_utils.py
+++ b/release/scripts/modules/keyingsets_utils.py
@@ -28,11 +28,14 @@ __all__ = (
"RKS_POLL_selected_objects",
"RKS_POLL_selected_bones",
"RKS_POLL_selected_items",
+ "RKS_ITER_selected_objects",
+ "RKS_ITER_selected_bones",
"RKS_ITER_selected_item",
"RKS_GEN_available",
"RKS_GEN_location",
"RKS_GEN_rotation",
"RKS_GEN_scaling",
+ "RKS_GEN_bendy_bones",
)
import bpy
@@ -93,11 +96,17 @@ def RKS_ITER_selected_item(ksi, context, ks):
ksi.generate(context, ks, ob)
-# all select objects only
+# all selected objects only
def RKS_ITER_selected_objects(ksi, context, ks):
for ob in context.selected_objects:
ksi.generate(context, ks, ob)
+
+# all seelcted bones only
+def RKS_ITER_selected_bones(ksi, context, ks):
+ for bone in context.selected_pose_bones:
+ ksi.generate(context, ks, bone)
+
###########################
# Generate Callbacks
@@ -207,3 +216,44 @@ def RKS_GEN_scaling(ksi, context, ks, data):
ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping)
else:
ks.paths.add(id_block, path)
+
+# ------
+
+# Property identifiers for Bendy Bones
+bbone_property_ids = (
+ "bbone_curveinx",
+ "bbone_curveiny",
+ "bbone_curveoutx",
+ "bbone_curveouty",
+
+ "bbone_rollin",
+ "bbone_rollout",
+
+ "bbone_scalein",
+ "bbone_scaleout",
+
+ # NOTE: These are in the nested bone struct
+ # Do it this way to force them to be included
+ # in whatever actions are being keyed here
+ "bone.bbone_in",
+ "bone.bbone_out",
+)
+
+
+# Add Keying Set entries for bendy bones
+def RKS_GEN_bendy_bones(ksi, context, ks, data):
+ # get id-block and path info
+ # NOTE: This assumes that we're dealing with a bone here...
+ id_block, base_path, grouping = get_transform_generators_base_info(data)
+
+ # for each of the bendy bone properties, add a Keying Set entry for it...
+ for propname in bbone_property_ids:
+ # add the property name to the base path
+ path = path_add_property(base_path, propname)
+
+ # add Keying Set entry for this...
+ if grouping:
+ ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping)
+ else:
+ ks.paths.add(id_block, path)
+
diff --git a/release/scripts/modules/progress_report.py b/release/scripts/modules/progress_report.py
index fc77a3e998e..bcce44aab9f 100644
--- a/release/scripts/modules/progress_report.py
+++ b/release/scripts/modules/progress_report.py
@@ -92,7 +92,8 @@ class ProgressReport:
self.wm.progress_update(steps)
if msg:
prefix = " " * (len(self.steps) - 1)
- print(prefix + "(%8.4f sec | %8.4f sec) %s\nProgress: %6.2f%%\r" % (tm, loc_tm, msg, steps_percent), end='')
+ print(prefix + "(%8.4f sec | %8.4f sec) %s\nProgress: %6.2f%%\r" %
+ (tm, loc_tm, msg, steps_percent), end='')
else:
print("Progress: %6.2f%%\r" % (steps_percent,), end='')
diff --git a/release/scripts/modules/rna_info.py b/release/scripts/modules/rna_info.py
index dae262e93d7..94f5e9e17bb 100644
--- a/release/scripts/modules/rna_info.py
+++ b/release/scripts/modules/rna_info.py
@@ -95,7 +95,7 @@ class InfoStructRNA:
"children",
"references",
"properties",
- )
+ )
global_lookup = {}
@@ -119,8 +119,10 @@ class InfoStructRNA:
def build(self):
rna_type = self.bl_rna
parent_id = self.identifier
- self.properties[:] = [GetInfoPropertyRNA(rna_prop, parent_id) for rna_prop in get_direct_properties(rna_type) if rna_prop.identifier != "rna_type"]
- self.functions[:] = [GetInfoFunctionRNA(rna_prop, parent_id) for rna_prop in get_direct_functions(rna_type)]
+ self.properties[:] = [GetInfoPropertyRNA(rna_prop, parent_id)
+ for rna_prop in get_direct_properties(rna_type) if rna_prop.identifier != "rna_type"]
+ self.functions[:] = [GetInfoFunctionRNA(rna_prop, parent_id)
+ for rna_prop in get_direct_functions(rna_type)]
def get_bases(self):
bases = []
@@ -216,7 +218,7 @@ class InfoPropertyRNA:
"is_required",
"is_readonly",
"is_never_none",
- )
+ )
global_lookup = {}
def __init__(self, rna_prop):
@@ -362,7 +364,7 @@ class InfoFunctionRNA:
"args",
"return_values",
"is_classmethod",
- )
+ )
global_lookup = {}
def __init__(self, rna_func):
@@ -408,7 +410,7 @@ class InfoOperatorRNA:
"func_name",
"description",
"args",
- )
+ )
global_lookup = {}
def __init__(self, rna_op):
@@ -532,7 +534,7 @@ def BuildRNAInfo():
rna_struct = getattr(rna_type, "bl_rna", None)
if rna_struct:
- #if not rna_type_name.startswith('__'):
+ # if not rna_type_name.startswith('__'):
identifier = rna_struct.identifier
@@ -600,7 +602,8 @@ def BuildRNAInfo():
for rna_prop_ptr in (getattr(rna_prop, "fixed_type", None), getattr(rna_prop, "srna", None)):
# Does this property point to me?
if rna_prop_ptr:
- rna_references_dict[rna_prop_ptr.identifier].append("%s.%s" % (rna_struct_path, rna_prop_identifier))
+ rna_references_dict[rna_prop_ptr.identifier].append(
+ "%s.%s" % (rna_struct_path, rna_prop_identifier))
for rna_func in get_direct_functions(rna_struct):
for rna_prop_identifier, rna_prop in rna_func.parameters.items():
@@ -612,7 +615,8 @@ def BuildRNAInfo():
# Does this property point to me?
if rna_prop_ptr:
- rna_references_dict[rna_prop_ptr.identifier].append("%s.%s" % (rna_struct_path, rna_func.identifier))
+ rna_references_dict[rna_prop_ptr.identifier].append(
+ "%s.%s" % (rna_struct_path, rna_func.identifier))
# Store nested children
nested = rna_struct.nested
@@ -625,8 +629,8 @@ def BuildRNAInfo():
info_structs = []
for (rna_base, identifier, rna_struct) in structs:
- #if rna_struct.nested:
- # continue
+ # if rna_struct.nested:
+ # continue
#write_struct(rna_struct, '')
info_struct = GetInfoStructRNA(rna_struct)
@@ -664,7 +668,8 @@ def BuildRNAInfo():
default = prop.default
if type(default) in {float, int}:
if default < prop.min or default > prop.max:
- print("\t %s.%s, %s not in [%s - %s]" % (rna_info.identifier, prop.identifier, default, prop.min, prop.max))
+ print("\t %s.%s, %s not in [%s - %s]" %
+ (rna_info.identifier, prop.identifier, default, prop.min, prop.max))
# now for operators
op_mods = dir(bpy.ops)
@@ -691,8 +696,8 @@ def BuildRNAInfo():
for rna_prop in rna_info.args:
rna_prop.build()
- #for rna_info in InfoStructRNA.global_lookup.values():
- # print(rna_info)
+ # for rna_info in InfoStructRNA.global_lookup.values():
+ # print(rna_info)
return InfoStructRNA.global_lookup, InfoFunctionRNA.global_lookup, InfoOperatorRNA.global_lookup, InfoPropertyRNA.global_lookup
@@ -701,7 +706,7 @@ def main():
struct = rna_info.BuildRNAInfo()[0]
data = []
for struct_id, v in sorted(struct.items()):
- struct_id_str = v.identifier #~ "".join(sid for sid in struct_id if struct_id)
+ struct_id_str = v.identifier # "".join(sid for sid in struct_id if struct_id)
for base in v.get_bases():
struct_id_str = base.identifier + "|" + struct_id_str
@@ -714,7 +719,10 @@ def main():
if prop.array_length > 0:
prop_type += "[%d]" % prop.array_length
- data.append("%s.%s -> %s: %s%s %s" % (struct_id_str, prop.identifier, prop.identifier, prop_type, ", (read-only)" if prop.is_readonly else "", prop.description))
+ data.append(
+ "%s.%s -> %s: %s%s %s" %
+ (struct_id_str, prop.identifier, prop.identifier, prop_type,
+ ", (read-only)" if prop.is_readonly else "", prop.description))
data.sort()
if bpy.app.background:
diff --git a/release/scripts/modules/rna_xml.py b/release/scripts/modules/rna_xml.py
index ad4809efbe1..e8705834df3 100644
--- a/release/scripts/modules/rna_xml.py
+++ b/release/scripts/modules/rna_xml.py
@@ -90,7 +90,7 @@ def rna2xml(fw=print_ln,
bpy.types.PoseBone,
bpy.types.Node,
bpy.types.Sequence,
- )
+ )
def number_to_str(val, val_type):
if val_type == int:
@@ -276,7 +276,8 @@ def xml2rna(root_xml,
if value_xml.startswith("#"):
# read hexidecimal value as float array
value_xml_split = value_xml[1:]
- value_xml_coerce = [int(value_xml_split[i:i + 2], 16) / 255 for i in range(0, len(value_xml_split), 2)]
+ value_xml_coerce = [int(value_xml_split[i:i + 2], 16) /
+ 255 for i in range(0, len(value_xml_split), 2)]
del value_xml_split
else:
value_xml_split = value_xml.split()
diff --git a/release/scripts/modules/sys_info.py b/release/scripts/modules/sys_info.py
index 49395dd48f0..5b81df28524 100644
--- a/release/scripts/modules/sys_info.py
+++ b/release/scripts/modules/sys_info.py
@@ -24,7 +24,6 @@
def write_sysinfo(filepath):
import sys
- import textwrap
import subprocess
import bpy
@@ -40,169 +39,188 @@ def write_sysinfo(filepath):
r = r[1:-1]
return r
- output = open(filepath, 'w', encoding="utf-8")
-
- header = "= Blender %s System Information =\n" % bpy.app.version_string
- lilies = "%s\n\n" % ((len(header) - 1) * "=")
- output.write(lilies[:-1])
- output.write(header)
- output.write(lilies)
-
- def title(text):
- return "\n%s:\n%s" % (text, lilies)
-
- # build info
- output.write(title("Blender"))
- output.write("version: %s, branch: %s, commit date: %s %s, hash: %s, type: %s\n" %
- (bpy.app.version_string,
- prepr(bpy.app.build_branch),
- prepr(bpy.app.build_commit_date),
- prepr(bpy.app.build_commit_time),
- prepr(bpy.app.build_hash),
- prepr(bpy.app.build_type),
- ))
-
- output.write("build date: %s, %s\n" % (prepr(bpy.app.build_date), prepr(bpy.app.build_time)))
- output.write("platform: %s\n" % prepr(bpy.app.build_platform))
- output.write("binary path: %s\n" % prepr(bpy.app.binary_path))
- output.write("build cflags: %s\n" % prepr(bpy.app.build_cflags))
- output.write("build cxxflags: %s\n" % prepr(bpy.app.build_cxxflags))
- output.write("build linkflags: %s\n" % prepr(bpy.app.build_linkflags))
- output.write("build system: %s\n" % prepr(bpy.app.build_system))
-
- # python info
- output.write(title("Python"))
- output.write("version: %s\n" % (sys.version))
- output.write("paths:\n")
- for p in sys.path:
- output.write("\t%r\n" % p)
-
- output.write(title("Python (External Binary)"))
- output.write("binary path: %s\n" % prepr(bpy.app.binary_path_python))
- try:
- py_ver = prepr(subprocess.check_output([
- bpy.app.binary_path_python,
- "--version",
+ with open(filepath, 'w', encoding="utf-8") as output:
+ try:
+ header = "= Blender %s System Information =\n" % bpy.app.version_string
+ lilies = "%s\n\n" % ((len(header) - 1) * "=")
+ output.write(lilies[:-1])
+ output.write(header)
+ output.write(lilies)
+
+ def title(text):
+ return "\n%s:\n%s" % (text, lilies)
+
+ # build info
+ output.write(title("Blender"))
+ output.write(
+ "version: %s, branch: %s, commit date: %s %s, hash: %s, type: %s\n" %
+ (bpy.app.version_string,
+ prepr(bpy.app.build_branch),
+ prepr(bpy.app.build_commit_date),
+ prepr(bpy.app.build_commit_time),
+ prepr(bpy.app.build_hash),
+ prepr(bpy.app.build_type),
+ ))
+
+ output.write("build date: %s, %s\n" % (prepr(bpy.app.build_date), prepr(bpy.app.build_time)))
+ output.write("platform: %s\n" % prepr(bpy.app.build_platform))
+ output.write("binary path: %s\n" % prepr(bpy.app.binary_path))
+ output.write("build cflags: %s\n" % prepr(bpy.app.build_cflags))
+ output.write("build cxxflags: %s\n" % prepr(bpy.app.build_cxxflags))
+ output.write("build linkflags: %s\n" % prepr(bpy.app.build_linkflags))
+ output.write("build system: %s\n" % prepr(bpy.app.build_system))
+
+ # python info
+ output.write(title("Python"))
+ output.write("version: %s\n" % (sys.version))
+ output.write("paths:\n")
+ for p in sys.path:
+ output.write("\t%r\n" % p)
+
+ output.write(title("Python (External Binary)"))
+ output.write("binary path: %s\n" % prepr(bpy.app.binary_path_python))
+ try:
+ py_ver = prepr(subprocess.check_output([
+ bpy.app.binary_path_python,
+ "--version",
]).strip())
- except Exception as e:
- py_ver = str(e)
- output.write("version: %s\n" % py_ver)
- del py_ver
-
- output.write(title("Directories"))
- output.write("scripts:\n")
- for p in bpy.utils.script_paths():
- output.write("\t%r\n" % p)
- output.write("user scripts: %r\n" % (bpy.utils.script_path_user()))
- output.write("pref scripts: %r\n" % (bpy.utils.script_path_pref()))
- output.write("datafiles: %r\n" % (bpy.utils.user_resource('DATAFILES')))
- output.write("config: %r\n" % (bpy.utils.user_resource('CONFIG')))
- output.write("scripts : %r\n" % (bpy.utils.user_resource('SCRIPTS')))
- output.write("autosave: %r\n" % (bpy.utils.user_resource('AUTOSAVE')))
- output.write("tempdir: %r\n" % (bpy.app.tempdir))
-
- output.write(title("FFmpeg"))
- ffmpeg = bpy.app.ffmpeg
- if ffmpeg.supported:
- for lib in ("avcodec", "avdevice", "avformat", "avutil", "swscale"):
- output.write("%s:%s%r\n" % (lib, " " * (10 - len(lib)),
- getattr(ffmpeg, lib + "_version_string")))
- else:
- output.write("Blender was built without FFmpeg support\n")
-
- if bpy.app.build_options.sdl:
- output.write(title("SDL"))
- output.write("Version: %s\n" % bpy.app.sdl.version_string)
- output.write("Loading method: ")
- if bpy.app.build_options.sdl_dynload:
- output.write("dynamically loaded by Blender (WITH_SDL_DYNLOAD=ON)\n")
- else:
- output.write("linked (WITH_SDL_DYNLOAD=OFF)\n")
- if not bpy.app.sdl.available:
- output.write("WARNING: Blender could not load SDL library\n")
-
- output.write(title("Other Libraries"))
- ocio = bpy.app.ocio
- output.write("OpenColorIO: ")
- if ocio.supported:
- if ocio.version_string == "fallback":
- output.write("Blender was built with OpenColorIO, " +
- "but it currently uses fallback color management.\n")
- else:
- output.write("%s\n" % (ocio.version_string))
- else:
- output.write("Blender was built without OpenColorIO support\n")
-
- oiio = bpy.app.oiio
- output.write("OpenImageIO: ")
- if ocio.supported:
- output.write("%s\n" % (oiio.version_string))
- else:
- output.write("Blender was built without OpenImageIO support\n")
-
- output.write("OpenShadingLanguage: ")
- if bpy.app.build_options.cycles:
- if bpy.app.build_options.cycles_osl:
- from _cycles import osl_version_string
- output.write("%s\n" % (osl_version_string))
- else:
- output.write("Blender was built without OpenShadingLanguage support in Cycles\n")
- else:
- output.write("Blender was built without Cycles support\n")
-
- openvdb = bpy.app.openvdb
- output.write("OpenVDB: ")
- if openvdb.supported:
- output.write("%s\n" % openvdb.version_string)
- else:
- output.write("Blender was built without OpenVDB support\n")
-
- if not bpy.app.build_options.sdl:
- output.write("SDL: Blender was built without SDL support\n")
-
- if bpy.app.background:
- output.write("\nOpenGL: missing, background mode\n")
- else:
- output.write(title("OpenGL"))
- version = bgl.glGetString(bgl.GL_RENDERER)
- output.write("renderer:\t%r\n" % version)
- output.write("vendor:\t\t%r\n" % (bgl.glGetString(bgl.GL_VENDOR)))
- output.write("version:\t%r\n" % (bgl.glGetString(bgl.GL_VERSION)))
- output.write("extensions:\n")
-
- glext = sorted(bgl.glGetString(bgl.GL_EXTENSIONS).split())
- for l in glext:
- output.write("\t%s\n" % l)
-
- output.write(title("Implementation Dependent OpenGL Limits"))
- limit = bgl.Buffer(bgl.GL_INT, 1)
- bgl.glGetIntegerv(bgl.GL_MAX_TEXTURE_UNITS, limit)
- output.write("Maximum Fixed Function Texture Units:\t%d\n" % limit[0])
- bgl.glGetIntegerv(bgl.GL_MAX_ELEMENTS_VERTICES, limit)
- output.write("Maximum DrawElements Vertices:\t%d\n" % limit[0])
- bgl.glGetIntegerv(bgl.GL_MAX_ELEMENTS_INDICES, limit)
- output.write("Maximum DrawElements Indices:\t%d\n" % limit[0])
-
- output.write("\nGLSL:\n")
- bgl.glGetIntegerv(bgl.GL_MAX_VARYING_FLOATS, limit)
- output.write("Maximum Varying Floats:\t%d\n" % limit[0])
- bgl.glGetIntegerv(bgl.GL_MAX_VERTEX_ATTRIBS, limit)
- output.write("Maximum Vertex Attributes:\t%d\n" % limit[0])
- bgl.glGetIntegerv(bgl.GL_MAX_VERTEX_UNIFORM_COMPONENTS, limit)
- output.write("Maximum Vertex Uniform Components:\t%d\n" % limit[0])
- bgl.glGetIntegerv(bgl.GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, limit)
- output.write("Maximum Fragment Uniform Components:\t%d\n" % limit[0])
- bgl.glGetIntegerv(bgl.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, limit)
- output.write("Maximum Vertex Image Units:\t%d\n" % limit[0])
- bgl.glGetIntegerv(bgl.GL_MAX_TEXTURE_IMAGE_UNITS, limit)
- output.write("Maximum Fragment Image Units:\t%d\n" % limit[0])
- bgl.glGetIntegerv(bgl.GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, limit)
- output.write("Maximum Pipeline Image Units:\t%d\n" % limit[0])
-
- if bpy.app.build_options.cycles:
- import cycles
- output.write(title("Cycles"))
- output.write(cycles.engine.system_info())
-
- output.close()
-
+ except Exception as e:
+ py_ver = str(e)
+ output.write("version: %s\n" % py_ver)
+ del py_ver
+
+ output.write(title("Directories"))
+ output.write("scripts:\n")
+ for p in bpy.utils.script_paths():
+ output.write("\t%r\n" % p)
+ output.write("user scripts: %r\n" % (bpy.utils.script_path_user()))
+ output.write("pref scripts: %r\n" % (bpy.utils.script_path_pref()))
+ output.write("datafiles: %r\n" % (bpy.utils.user_resource('DATAFILES')))
+ output.write("config: %r\n" % (bpy.utils.user_resource('CONFIG')))
+ output.write("scripts : %r\n" % (bpy.utils.user_resource('SCRIPTS')))
+ output.write("autosave: %r\n" % (bpy.utils.user_resource('AUTOSAVE')))
+ output.write("tempdir: %r\n" % (bpy.app.tempdir))
+
+ output.write(title("FFmpeg"))
+ ffmpeg = bpy.app.ffmpeg
+ if ffmpeg.supported:
+ for lib in ("avcodec", "avdevice", "avformat", "avutil", "swscale"):
+ output.write(
+ "%s:%s%r\n" % (lib, " " * (10 - len(lib)),
+ getattr(ffmpeg, lib + "_version_string")))
+ else:
+ output.write("Blender was built without FFmpeg support\n")
+
+ if bpy.app.build_options.sdl:
+ output.write(title("SDL"))
+ output.write("Version: %s\n" % bpy.app.sdl.version_string)
+ output.write("Loading method: ")
+ if bpy.app.build_options.sdl_dynload:
+ output.write("dynamically loaded by Blender (WITH_SDL_DYNLOAD=ON)\n")
+ else:
+ output.write("linked (WITH_SDL_DYNLOAD=OFF)\n")
+ if not bpy.app.sdl.available:
+ output.write("WARNING: Blender could not load SDL library\n")
+
+ output.write(title("Other Libraries"))
+ ocio = bpy.app.ocio
+ output.write("OpenColorIO: ")
+ if ocio.supported:
+ if ocio.version_string == "fallback":
+ output.write("Blender was built with OpenColorIO, " +
+ "but it currently uses fallback color management.\n")
+ else:
+ output.write("%s\n" % (ocio.version_string))
+ else:
+ output.write("Blender was built without OpenColorIO support\n")
+
+ oiio = bpy.app.oiio
+ output.write("OpenImageIO: ")
+ if ocio.supported:
+ output.write("%s\n" % (oiio.version_string))
+ else:
+ output.write("Blender was built without OpenImageIO support\n")
+
+ output.write("OpenShadingLanguage: ")
+ if bpy.app.build_options.cycles:
+ if bpy.app.build_options.cycles_osl:
+ from _cycles import osl_version_string
+ output.write("%s\n" % (osl_version_string))
+ else:
+ output.write("Blender was built without OpenShadingLanguage support in Cycles\n")
+ else:
+ output.write("Blender was built without Cycles support\n")
+
+ openvdb = bpy.app.openvdb
+ output.write("OpenVDB: ")
+ if openvdb.supported:
+ output.write("%s\n" % openvdb.version_string)
+ else:
+ output.write("Blender was built without OpenVDB support\n")
+
+ alembic = bpy.app.alembic
+ output.write("Alembic: ")
+ if alembic.supported:
+ output.write("%s\n" % alembic.version_string)
+ else:
+ output.write("Blender was built without Alembic support\n")
+
+ if not bpy.app.build_options.sdl:
+ output.write("SDL: Blender was built without SDL support\n")
+
+ if bpy.app.background:
+ output.write("\nOpenGL: missing, background mode\n")
+ else:
+ output.write(title("OpenGL"))
+ version = bgl.glGetString(bgl.GL_RENDERER)
+ output.write("renderer:\t%r\n" % version)
+ output.write("vendor:\t\t%r\n" % (bgl.glGetString(bgl.GL_VENDOR)))
+ output.write("version:\t%r\n" % (bgl.glGetString(bgl.GL_VERSION)))
+ output.write("extensions:\n")
+
+ glext = sorted(bgl.glGetString(bgl.GL_EXTENSIONS).split())
+ for l in glext:
+ output.write("\t%s\n" % l)
+
+ output.write(title("Implementation Dependent OpenGL Limits"))
+ limit = bgl.Buffer(bgl.GL_INT, 1)
+ bgl.glGetIntegerv(bgl.GL_MAX_TEXTURE_UNITS, limit)
+ output.write("Maximum Fixed Function Texture Units:\t%d\n" % limit[0])
+ bgl.glGetIntegerv(bgl.GL_MAX_ELEMENTS_VERTICES, limit)
+ output.write("Maximum DrawElements Vertices:\t%d\n" % limit[0])
+ bgl.glGetIntegerv(bgl.GL_MAX_ELEMENTS_INDICES, limit)
+ output.write("Maximum DrawElements Indices:\t%d\n" % limit[0])
+
+ output.write("\nGLSL:\n")
+ bgl.glGetIntegerv(bgl.GL_MAX_VARYING_FLOATS, limit)
+ output.write("Maximum Varying Floats:\t%d\n" % limit[0])
+ bgl.glGetIntegerv(bgl.GL_MAX_VERTEX_ATTRIBS, limit)
+ output.write("Maximum Vertex Attributes:\t%d\n" % limit[0])
+ bgl.glGetIntegerv(bgl.GL_MAX_VERTEX_UNIFORM_COMPONENTS, limit)
+ output.write("Maximum Vertex Uniform Components:\t%d\n" % limit[0])
+ bgl.glGetIntegerv(bgl.GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, limit)
+ output.write("Maximum Fragment Uniform Components:\t%d\n" % limit[0])
+ bgl.glGetIntegerv(bgl.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, limit)
+ output.write("Maximum Vertex Image Units:\t%d\n" % limit[0])
+ bgl.glGetIntegerv(bgl.GL_MAX_TEXTURE_IMAGE_UNITS, limit)
+ output.write("Maximum Fragment Image Units:\t%d\n" % limit[0])
+ bgl.glGetIntegerv(bgl.GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, limit)
+ output.write("Maximum Pipeline Image Units:\t%d\n" % limit[0])
+
+ if bpy.app.build_options.cycles:
+ import cycles
+ output.write(title("Cycles"))
+ output.write(cycles.engine.system_info())
+
+ import addon_utils
+ addon_utils.modules()
+ output.write(title("Enabled add-ons"))
+ for addon in bpy.context.user_preferences.addons.keys():
+ addon_mod = addon_utils.addons_fake_modules.get(addon, None)
+ if addon_mod is None:
+ output.write("%s (MISSING)\n" % (addon))
+ else:
+ output.write("%s (version: %s, path: %s)\n" %
+ (addon, addon_mod.bl_info.get('version', "UNKNOWN"), addon_mod.__file__))
+ except Exception as e:
+ output.write("ERROR: %s\n" % e)
diff --git a/release/scripts/presets/ffmpeg/DV.py b/release/scripts/presets/ffmpeg/DV.py
deleted file mode 100644
index a95d861111a..00000000000
--- a/release/scripts/presets/ffmpeg/DV.py
+++ /dev/null
@@ -1,14 +0,0 @@
-import bpy
-is_ntsc = (bpy.context.scene.render.fps != 25)
-
-bpy.context.scene.render.ffmpeg.format = "DV"
-bpy.context.scene.render.resolution_x = 720
-
-if is_ntsc:
- bpy.context.scene.render.resolution_y = 480
-else:
- bpy.context.scene.render.resolution_y = 576
-
-bpy.context.scene.render.ffmpeg.audio_mixrate = 48000
-bpy.context.scene.render.ffmpeg.audio_codec = "PCM"
-bpy.context.scene.render.ffmpeg.audio_channels = "STEREO"
diff --git a/release/scripts/presets/ffmpeg/DVD.py b/release/scripts/presets/ffmpeg/DVD (note_colon_ this changes render resolution).py
index d858bd70836..d858bd70836 100644
--- a/release/scripts/presets/ffmpeg/DVD.py
+++ b/release/scripts/presets/ffmpeg/DVD (note_colon_ this changes render resolution).py
diff --git a/release/scripts/presets/ffmpeg/SVCD.py b/release/scripts/presets/ffmpeg/SVCD.py
deleted file mode 100644
index deaf9697045..00000000000
--- a/release/scripts/presets/ffmpeg/SVCD.py
+++ /dev/null
@@ -1,24 +0,0 @@
-import bpy
-is_ntsc = (bpy.context.scene.render.fps != 25)
-
-bpy.context.scene.render.ffmpeg.format = "MPEG2"
-bpy.context.scene.render.resolution_x = 480
-
-if is_ntsc:
- bpy.context.scene.render.resolution_y = 480
- bpy.context.scene.render.ffmpeg.gopsize = 18
-else:
- bpy.context.scene.render.resolution_y = 576
- bpy.context.scene.render.ffmpeg.gopsize = 15
-
-bpy.context.scene.render.ffmpeg.video_bitrate = 2040
-bpy.context.scene.render.ffmpeg.maxrate = 2516
-bpy.context.scene.render.ffmpeg.minrate = 0
-bpy.context.scene.render.ffmpeg.buffersize = 224 * 8
-bpy.context.scene.render.ffmpeg.packetsize = 2324
-bpy.context.scene.render.ffmpeg.muxrate = 0
-
-bpy.context.scene.render.ffmpeg.audio_bitrate = 224
-bpy.context.scene.render.ffmpeg.audio_mixrate = 44100
-bpy.context.scene.render.ffmpeg.audio_codec = "MP2"
-bpy.context.scene.render.ffmpeg.audio_channels = "STEREO"
diff --git a/release/scripts/presets/ffmpeg/VCD.py b/release/scripts/presets/ffmpeg/VCD.py
deleted file mode 100644
index 3e57be720fb..00000000000
--- a/release/scripts/presets/ffmpeg/VCD.py
+++ /dev/null
@@ -1,24 +0,0 @@
-import bpy
-is_ntsc = (bpy.context.scene.render.fps != 25)
-
-bpy.context.scene.render.ffmpeg.format = "MPEG1"
-bpy.context.scene.render.resolution_x = 352
-
-if is_ntsc:
- bpy.context.scene.render.resolution_y = 240
- bpy.context.scene.render.ffmpeg.gopsize = 18
-else:
- bpy.context.scene.render.resolution_y = 288
- bpy.context.scene.render.ffmpeg.gopsize = 15
-
-bpy.context.scene.render.ffmpeg.video_bitrate = 1150
-bpy.context.scene.render.ffmpeg.maxrate = 1150
-bpy.context.scene.render.ffmpeg.minrate = 1150
-bpy.context.scene.render.ffmpeg.buffersize = 40 * 8
-bpy.context.scene.render.ffmpeg.packetsize = 2324
-bpy.context.scene.render.ffmpeg.muxrate = 2352 * 75 * 8
-
-bpy.context.scene.render.ffmpeg.audio_bitrate = 224
-bpy.context.scene.render.ffmpeg.audio_mixrate = 44100
-bpy.context.scene.render.ffmpeg.audio_codec = "MP2"
-bpy.context.scene.render.ffmpeg.audio_channels = "STEREO"
diff --git a/release/scripts/presets/ffmpeg/h264 in MP4.py b/release/scripts/presets/ffmpeg/h264 in MP4.py
new file mode 100644
index 00000000000..0e9c32c4878
--- /dev/null
+++ b/release/scripts/presets/ffmpeg/h264 in MP4.py
@@ -0,0 +1,18 @@
+import bpy
+is_ntsc = (bpy.context.scene.render.fps != 25)
+
+bpy.context.scene.render.ffmpeg.format = "MPEG4"
+bpy.context.scene.render.ffmpeg.codec = "H264"
+
+if is_ntsc:
+ bpy.context.scene.render.ffmpeg.gopsize = 18
+else:
+ bpy.context.scene.render.ffmpeg.gopsize = 15
+bpy.context.scene.render.ffmpeg.use_max_b_frames = False
+
+bpy.context.scene.render.ffmpeg.video_bitrate = 6000
+bpy.context.scene.render.ffmpeg.maxrate = 9000
+bpy.context.scene.render.ffmpeg.minrate = 0
+bpy.context.scene.render.ffmpeg.buffersize = 224 * 8
+bpy.context.scene.render.ffmpeg.packetsize = 2048
+bpy.context.scene.render.ffmpeg.muxrate = 10080000
diff --git a/release/scripts/presets/ffmpeg/h264 in Matroska for scrubbing.py b/release/scripts/presets/ffmpeg/h264 in Matroska for scrubbing.py
new file mode 100644
index 00000000000..eb1889d272f
--- /dev/null
+++ b/release/scripts/presets/ffmpeg/h264 in Matroska for scrubbing.py
@@ -0,0 +1,14 @@
+"""Sets up FFmpeg to output files that can easily be scrubbed through.
+
+Information was taken from https://trac.ffmpeg.org/wiki/Encode/VFX#H.264
+"""
+
+import bpy
+
+bpy.context.scene.render.ffmpeg.format = "MKV"
+bpy.context.scene.render.ffmpeg.codec = "H264"
+
+bpy.context.scene.render.ffmpeg.gopsize = 1
+bpy.context.scene.render.ffmpeg.constant_rate_factor = 'PERC_LOSSLESS'
+bpy.context.scene.render.ffmpeg.use_max_b_frames = True
+bpy.context.scene.render.ffmpeg.max_b_frames = 0
diff --git a/release/scripts/presets/ffmpeg/h264.py b/release/scripts/presets/ffmpeg/h264 in Matroska.py
index e1dbdc1d8b9..1fe066dc4bf 100644
--- a/release/scripts/presets/ffmpeg/h264.py
+++ b/release/scripts/presets/ffmpeg/h264 in Matroska.py
@@ -1,7 +1,7 @@
import bpy
is_ntsc = (bpy.context.scene.render.fps != 25)
-bpy.context.scene.render.ffmpeg.format = "H264"
+bpy.context.scene.render.ffmpeg.format = "MKV"
bpy.context.scene.render.ffmpeg.codec = "H264"
if is_ntsc:
diff --git a/release/scripts/presets/ffmpeg/theora.py b/release/scripts/presets/ffmpeg/ogg_theora.py
index 88f1ac9bbae..b450b67fd98 100644
--- a/release/scripts/presets/ffmpeg/theora.py
+++ b/release/scripts/presets/ffmpeg/ogg_theora.py
@@ -8,6 +8,7 @@ if is_ntsc:
bpy.context.scene.render.ffmpeg.gopsize = 18
else:
bpy.context.scene.render.ffmpeg.gopsize = 15
+bpy.context.scene.render.ffmpeg.use_max_b_frames = False
bpy.context.scene.render.ffmpeg.video_bitrate = 6000
bpy.context.scene.render.ffmpeg.maxrate = 9000
diff --git a/release/scripts/presets/ffmpeg/xvid.py b/release/scripts/presets/ffmpeg/xvid.py
index e69ab663dc8..dba0f71c279 100644
--- a/release/scripts/presets/ffmpeg/xvid.py
+++ b/release/scripts/presets/ffmpeg/xvid.py
@@ -1,12 +1,14 @@
import bpy
is_ntsc = (bpy.context.scene.render.fps != 25)
-bpy.context.scene.render.ffmpeg.format = "XVID"
+bpy.context.scene.render.ffmpeg.format = "AVI"
+bpy.context.scene.render.ffmpeg.codec = "MPEG4"
if is_ntsc:
bpy.context.scene.render.ffmpeg.gopsize = 18
else:
bpy.context.scene.render.ffmpeg.gopsize = 15
+bpy.context.scene.render.ffmpeg.use_max_b_frames = False
bpy.context.scene.render.ffmpeg.video_bitrate = 6000
bpy.context.scene.render.ffmpeg.maxrate = 9000
diff --git a/release/scripts/presets/interface_theme/back_to_black.xml b/release/scripts/presets/interface_theme/back_to_black.xml
index 3b2b9b99ed2..915e9cb64f1 100644
--- a/release/scripts/presets/interface_theme/back_to_black.xml
+++ b/release/scripts/presets/interface_theme/back_to_black.xml
@@ -398,11 +398,7 @@
</ThemeGraphEditor>
</graph_editor>
<file_browser>
- <ThemeFileBrowser selected_file="#354d66"
- scrollbar="#a0a0a0"
- scroll_handle="#7f7070"
- active_file="#b1b1b1"
- active_file_text="#ffffff">
+ <ThemeFileBrowser selected_file="#354d66">
<space>
<ThemeSpaceGeneric back="#000000"
title="#5d5d5d"
@@ -428,13 +424,6 @@
</panelcolors>
</ThemeSpaceGeneric>
</space>
- <space_list>
- <ThemeSpaceListGeneric list="#181818"
- list_title="#9e9e9e"
- list_text="#5d5d5d"
- list_text_hi="#ffffff">
- </ThemeSpaceListGeneric>
- </space_list>
</ThemeFileBrowser>
</file_browser>
<nla_editor>
diff --git a/release/scripts/presets/interface_theme/blender_24x.xml b/release/scripts/presets/interface_theme/blender_24x.xml
index 445c23b4c4e..818e557adf0 100644
--- a/release/scripts/presets/interface_theme/blender_24x.xml
+++ b/release/scripts/presets/interface_theme/blender_24x.xml
@@ -179,7 +179,7 @@
</wcol_tooltip>
<wcol_menu_item>
<ThemeWidgetColors outline="#000000"
- inner="#00000000"
+ inner="#d2d2d200"
inner_sel="#7f7f7fff"
item="#ffffffff"
text="#000000"
@@ -371,7 +371,7 @@
header="#b4b4b4"
header_text="#000000"
header_text_hi="#ffffff"
- button="#727272ff"
+ button="#b4b4b457"
button_title="#000000"
button_text="#000000"
button_text_hi="#ffffff"
@@ -398,11 +398,7 @@
</ThemeGraphEditor>
</graph_editor>
<file_browser>
- <ThemeFileBrowser selected_file="#a0a0d0"
- scrollbar="#a0a0a0"
- scroll_handle="#7f7070"
- active_file="#828282"
- active_file_text="#ffffff">
+ <ThemeFileBrowser selected_file="#a0a0d0">
<space>
<ThemeSpaceGeneric back="#808080"
title="#000000"
@@ -428,13 +424,6 @@
</panelcolors>
</ThemeSpaceGeneric>
</space>
- <space_list>
- <ThemeSpaceListGeneric list="#b4b4b4"
- list_title="#000000"
- list_text="#000000"
- list_text_hi="#ffffff">
- </ThemeSpaceListGeneric>
- </space_list>
</ThemeFileBrowser>
</file_browser>
<nla_editor>
diff --git a/release/scripts/presets/interface_theme/elsyiun.xml b/release/scripts/presets/interface_theme/elsyiun.xml
index 20c88363aa9..7a3d5146636 100644
--- a/release/scripts/presets/interface_theme/elsyiun.xml
+++ b/release/scripts/presets/interface_theme/elsyiun.xml
@@ -398,11 +398,7 @@
</ThemeGraphEditor>
</graph_editor>
<file_browser>
- <ThemeFileBrowser selected_file="#755129"
- scrollbar="#a0a0a0"
- scroll_handle="#7f7070"
- active_file="#828282"
- active_file_text="#fafafa">
+ <ThemeFileBrowser selected_file="#755129">
<space>
<ThemeSpaceGeneric back="#4b4b4b"
title="#8b8b8b"
@@ -428,13 +424,6 @@
</panelcolors>
</ThemeSpaceGeneric>
</space>
- <space_list>
- <ThemeSpaceListGeneric list="#3b3b3b"
- list_title="#8b8b8b"
- list_text="#8b8b8b"
- list_text_hi="#ffffff">
- </ThemeSpaceListGeneric>
- </space_list>
</ThemeFileBrowser>
</file_browser>
<nla_editor>
diff --git a/release/scripts/presets/interface_theme/flatty_light.xml b/release/scripts/presets/interface_theme/flatty_light.xml
index f9fed2d97da..623e0b334dd 100644
--- a/release/scripts/presets/interface_theme/flatty_light.xml
+++ b/release/scripts/presets/interface_theme/flatty_light.xml
@@ -398,11 +398,7 @@
</ThemeGraphEditor>
</graph_editor>
<file_browser>
- <ThemeFileBrowser selected_file="#ff8c19"
- scrollbar="#a0a0a0"
- scroll_handle="#7f7070"
- active_file="#828282"
- active_file_text="#fafafa">
+ <ThemeFileBrowser selected_file="#ff8c19">
<space>
<ThemeSpaceGeneric back="#404040"
title="#000000"
@@ -428,13 +424,6 @@
</panelcolors>
</ThemeSpaceGeneric>
</space>
- <space_list>
- <ThemeSpaceListGeneric list="#808080"
- list_title="#000000"
- list_text="#000000"
- list_text_hi="#ffffff">
- </ThemeSpaceListGeneric>
- </space_list>
</ThemeFileBrowser>
</file_browser>
<nla_editor>
diff --git a/release/scripts/presets/interface_theme/graph.xml b/release/scripts/presets/interface_theme/graph.xml
index 4943bf3b4d5..a032d8bd3b2 100644
--- a/release/scripts/presets/interface_theme/graph.xml
+++ b/release/scripts/presets/interface_theme/graph.xml
@@ -398,11 +398,7 @@
</ThemeGraphEditor>
</graph_editor>
<file_browser>
- <ThemeFileBrowser selected_file="#607f9e"
- scrollbar="#a0a0a0"
- scroll_handle="#7f7070"
- active_file="#ffffff"
- active_file_text="#ffffff">
+ <ThemeFileBrowser selected_file="#607f9e">
<space>
<ThemeSpaceGeneric back="#4b4b4b"
title="#e4e4e4"
@@ -428,13 +424,6 @@
</panelcolors>
</ThemeSpaceGeneric>
</space>
- <space_list>
- <ThemeSpaceListGeneric list="#3b3b3b"
- list_title="#8b8b8b"
- list_text="#8b8b8b"
- list_text_hi="#ffffff">
- </ThemeSpaceListGeneric>
- </space_list>
</ThemeFileBrowser>
</file_browser>
<nla_editor>
diff --git a/release/scripts/presets/interface_theme/hexagon.xml b/release/scripts/presets/interface_theme/hexagon.xml
index 1db4db0cb47..4b24abc5fa7 100644
--- a/release/scripts/presets/interface_theme/hexagon.xml
+++ b/release/scripts/presets/interface_theme/hexagon.xml
@@ -398,11 +398,7 @@
</ThemeGraphEditor>
</graph_editor>
<file_browser>
- <ThemeFileBrowser selected_file="#69a5be"
- scrollbar="#a0a0a0"
- scroll_handle="#7f7070"
- active_file="#859cb9"
- active_file_text="#fafafa">
+ <ThemeFileBrowser selected_file="#69a5be">
<space>
<ThemeSpaceGeneric back="#646875"
title="#000000"
@@ -428,13 +424,6 @@
</panelcolors>
</ThemeSpaceGeneric>
</space>
- <space_list>
- <ThemeSpaceListGeneric list="#6c717f"
- list_title="#d7d7d7"
- list_text="#d7d7d7"
- list_text_hi="#ffffff">
- </ThemeSpaceListGeneric>
- </space_list>
</ThemeFileBrowser>
</file_browser>
<nla_editor>
diff --git a/release/scripts/presets/interface_theme/rtheme.xml b/release/scripts/presets/interface_theme/rtheme.xml
index 1f187695909..27f33aa2fe5 100644
--- a/release/scripts/presets/interface_theme/rtheme.xml
+++ b/release/scripts/presets/interface_theme/rtheme.xml
@@ -398,11 +398,7 @@
</ThemeGraphEditor>
</graph_editor>
<file_browser>
- <ThemeFileBrowser selected_file="#ff8c19"
- scrollbar="#a0a0a0"
- scroll_handle="#7f7070"
- active_file="#828282"
- active_file_text="#fafafa">
+ <ThemeFileBrowser selected_file="#ff8c19">
<space>
<ThemeSpaceGeneric back="#9098a0"
title="#000000"
@@ -428,13 +424,6 @@
</panelcolors>
</ThemeSpaceGeneric>
</space>
- <space_list>
- <ThemeSpaceListGeneric list="#484848"
- list_title="#000000"
- list_text="#000000"
- list_text_hi="#ffffff">
- </ThemeSpaceListGeneric>
- </space_list>
</ThemeFileBrowser>
</file_browser>
<nla_editor>
diff --git a/release/scripts/presets/interface_theme/science_lab.xml b/release/scripts/presets/interface_theme/science_lab.xml
index 7ebaa68b5a6..9341e945375 100644
--- a/release/scripts/presets/interface_theme/science_lab.xml
+++ b/release/scripts/presets/interface_theme/science_lab.xml
@@ -398,11 +398,7 @@
</ThemeGraphEditor>
</graph_editor>
<file_browser>
- <ThemeFileBrowser selected_file="#517da1"
- scrollbar="#a0a0a0"
- scroll_handle="#7f7070"
- active_file="#828282"
- active_file_text="#fafafa">
+ <ThemeFileBrowser selected_file="#517da1">
<space>
<ThemeSpaceGeneric back="#363636"
title="#646464"
@@ -428,13 +424,6 @@
</panelcolors>
</ThemeSpaceGeneric>
</space>
- <space_list>
- <ThemeSpaceListGeneric list="#444444"
- list_title="#c0c0c0"
- list_text="#999999"
- list_text_hi="#ffffff">
- </ThemeSpaceListGeneric>
- </space_list>
</ThemeFileBrowser>
</file_browser>
<nla_editor>
diff --git a/release/scripts/presets/interface_theme/softimage.xml b/release/scripts/presets/interface_theme/softimage.xml
index 619af7c5e52..ab0a5994838 100644
--- a/release/scripts/presets/interface_theme/softimage.xml
+++ b/release/scripts/presets/interface_theme/softimage.xml
@@ -398,11 +398,7 @@
</ThemeGraphEditor>
</graph_editor>
<file_browser>
- <ThemeFileBrowser selected_file="#f1e593"
- scrollbar="#4d4b4d"
- scroll_handle="#8c8a88"
- active_file="#f1e593"
- active_file_text="#ffffff">
+ <ThemeFileBrowser selected_file="#f1e593">
<space>
<ThemeSpaceGeneric back="#aca8a7"
title="#ffffff"
@@ -428,13 +424,6 @@
</panelcolors>
</ThemeSpaceGeneric>
</space>
- <space_list>
- <ThemeSpaceListGeneric list="#aaa8a6"
- list_title="#3a3a3a"
- list_text="#7f7f7f"
- list_text_hi="#ffffff">
- </ThemeSpaceListGeneric>
- </space_list>
</ThemeFileBrowser>
</file_browser>
<nla_editor>
diff --git a/release/scripts/presets/interface_theme/ubuntu_ambiance.xml b/release/scripts/presets/interface_theme/ubuntu_ambiance.xml
index a319b0be5c0..184ea4214a4 100644
--- a/release/scripts/presets/interface_theme/ubuntu_ambiance.xml
+++ b/release/scripts/presets/interface_theme/ubuntu_ambiance.xml
@@ -398,11 +398,7 @@
</ThemeGraphEditor>
</graph_editor>
<file_browser>
- <ThemeFileBrowser selected_file="#6b395a"
- scrollbar="#a0a0a0"
- scroll_handle="#7f7070"
- active_file="#eeedeb"
- active_file_text="#ffffff">
+ <ThemeFileBrowser selected_file="#6b395a">
<space>
<ThemeSpaceGeneric back="#131311"
title="#000000"
@@ -428,13 +424,6 @@
</panelcolors>
</ThemeSpaceGeneric>
</space>
- <space_list>
- <ThemeSpaceListGeneric list="#3c3b37"
- list_title="#95948f"
- list_text="#95948f"
- list_text_hi="#ffffff">
- </ThemeSpaceListGeneric>
- </space_list>
</ThemeFileBrowser>
</file_browser>
<nla_editor>
diff --git a/release/scripts/presets/keyconfig/maya.py b/release/scripts/presets/keyconfig/maya.py
index cdd16f26877..67fd1fddcac 100644
--- a/release/scripts/presets/keyconfig/maya.py
+++ b/release/scripts/presets/keyconfig/maya.py
@@ -698,7 +698,7 @@ kmi.properties.level = 5
km = kc.keymaps.new('Knife Tool Modal Map', space_type='EMPTY', region_type='WINDOW', modal=True)
kmi = km.keymap_items.new_modal('CANCEL', 'ESC', 'ANY', any=True)
-kmi = km.keymap_items.new_modal('ADD_CUT', 'LEFTMOUSE', 'ANY')
+kmi = km.keymap_items.new_modal('ADD_CUT', 'LEFTMOUSE', 'ANY', any=True)
kmi = km.keymap_items.new_modal('PANNING', 'LEFTMOUSE', 'ANY', alt=True)
kmi = km.keymap_items.new_modal('PANNING', 'MIDDLEMOUSE', 'ANY', alt=True)
kmi = km.keymap_items.new_modal('PANNING', 'RIGHTMOUSE', 'ANY', alt=True)
diff --git a/release/scripts/startup/bl_operators/add_mesh_torus.py b/release/scripts/startup/bl_operators/add_mesh_torus.py
index 82014c87be9..303a8b01192 100644
--- a/release/scripts/startup/bl_operators/add_mesh_torus.py
+++ b/release/scripts/startup/bl_operators/add_mesh_torus.py
@@ -23,6 +23,7 @@ from bpy.types import Operator
from bpy.props import (
FloatProperty,
IntProperty,
+ BoolProperty,
)
from bpy.app.translations import pgettext_data as data_
@@ -81,6 +82,33 @@ def add_torus(major_rad, minor_rad, major_seg, minor_seg):
return verts, faces
+def add_uvs(mesh, minor_seg, major_seg):
+ mesh.uv_textures.new()
+ uv_layer = mesh.uv_layers.active
+ u_step = 1.0/major_seg
+ v_step = 1.0/minor_seg
+ vertex_index = 0
+
+ u = 0.5
+ for major_index in range(major_seg):
+ v = 0.5
+ for minor_index in range(minor_seg):
+ loops = mesh.polygons[vertex_index].loop_indices
+ if minor_index == minor_seg-1 and major_index == 0:
+ uv_layer.data[loops[1]].uv = (u, v)
+ uv_layer.data[loops[2]].uv = (u + u_step, v)
+ uv_layer.data[loops[0]].uv = (u, v + v_step)
+ uv_layer.data[loops[3]].uv = (u + u_step, v + v_step)
+ else:
+ uv_layer.data[loops[0]].uv = (u, v)
+ uv_layer.data[loops[1]].uv = (u + u_step, v)
+ uv_layer.data[loops[3]].uv = (u, v + v_step)
+ uv_layer.data[loops[2]].uv = (u + u_step, v + v_step)
+ v = (v + v_step) % 1.0
+ vertex_index += 1
+ u = (u + u_step) % 1.0
+
+
class AddTorus(Operator, object_utils.AddObjectHelper):
"""Add a torus mesh"""
bl_idname = "mesh.primitive_torus_add"
@@ -145,10 +173,18 @@ class AddTorus(Operator, object_utils.AddObjectHelper):
subtype='DISTANCE',
unit='LENGTH',
)
+ generate_uvs = BoolProperty(
+ name="Generate UVs",
+ description="Generate a default UV map",
+ default=False,
+ )
def draw(self, context):
layout = self.layout
+
col = layout.column(align=True)
+ col.prop(self, 'generate_uvs')
+ col.separator()
col.prop(self, 'view_align')
col = layout.column(align=True)
@@ -217,6 +253,10 @@ class AddTorus(Operator, object_utils.AddObjectHelper):
mesh.polygons.foreach_set("loop_start", range(0, nbr_loops, 4))
mesh.polygons.foreach_set("loop_total", (4,) * nbr_polys)
mesh.loops.foreach_set("vertex_index", faces)
+
+ if self.generate_uvs:
+ add_uvs(mesh, self.minor_segments, self.major_segments)
+
mesh.update()
object_utils.object_data_add(context, mesh, operator=self)
diff --git a/release/scripts/startup/bl_operators/anim.py b/release/scripts/startup/bl_operators/anim.py
index 05817216a54..c20d591241c 100644
--- a/release/scripts/startup/bl_operators/anim.py
+++ b/release/scripts/startup/bl_operators/anim.py
@@ -222,7 +222,7 @@ class BakeAction(Operator):
)
only_selected = BoolProperty(
name="Only Selected",
- description="Only key selected object/bones",
+ description="Only key selected bones (Pose baking only)",
default=True,
)
visual_keying = BoolProperty(
diff --git a/release/scripts/startup/bl_operators/file.py b/release/scripts/startup/bl_operators/file.py
index 64cc0aeddb3..51e079164b6 100644
--- a/release/scripts/startup/bl_operators/file.py
+++ b/release/scripts/startup/bl_operators/file.py
@@ -97,13 +97,9 @@ class WM_OT_previews_batch_generate(Operator):
return {'RUNNING_MODAL'}
def execute(self, context):
- if "subprocess" in locals():
- import imp
- imp.reload(preview_render)
- else:
- import os
- import subprocess
- from bl_previews_utils import bl_previews_render as preview_render
+ import os
+ import subprocess
+ from bl_previews_utils import bl_previews_render as preview_render
context.window_manager.progress_begin(0, len(self.files))
context.window_manager.progress_update(0)
@@ -210,13 +206,9 @@ class WM_OT_previews_batch_clear(Operator):
return {'RUNNING_MODAL'}
def execute(self, context):
- if "subprocess" in locals():
- import imp
- imp.reload(preview_render)
- else:
- import os
- import subprocess
- from bl_previews_utils import bl_previews_render as preview_render
+ import os
+ import subprocess
+ from bl_previews_utils import bl_previews_render as preview_render
context.window_manager.progress_begin(0, len(self.files))
context.window_manager.progress_update(0)
diff --git a/release/scripts/startup/bl_operators/object.py b/release/scripts/startup/bl_operators/object.py
index b89890a223c..6356da216b1 100644
--- a/release/scripts/startup/bl_operators/object.py
+++ b/release/scripts/startup/bl_operators/object.py
@@ -685,6 +685,91 @@ class ClearAllRestrictRender(Operator):
return {'FINISHED'}
+class TransformsToDeltas(Operator):
+ """Convert normal object transforms to delta transforms, """ \
+ """any existing delta transforms will be included as well"""
+ bl_idname = "object.transforms_to_deltas"
+ bl_label = "Transforms to Deltas"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ mode = EnumProperty(
+ items=(('ALL',
+ "All Transforms",
+ "Transfer location, rotation, and scale transforms",
+ ),
+ ('LOC',
+ "Location",
+ "Transfer location transforms only",
+ ),
+ ('ROT',
+ "Rotation",
+ "Transfer rotation transforms only",
+ ),
+ ('SCALE',
+ "Scale",
+ "Transfer scale transforms only",
+ ),
+ ),
+ name="Mode",
+ description="Which transforms to transfer",
+ default='ALL',
+ )
+ reset_values = BoolProperty(
+ name="Reset Values",
+ description=("Clear transform values after transferring to deltas"),
+ default=True,
+ )
+
+ @classmethod
+ def poll(cls, context):
+ obs = context.selected_editable_objects
+ return (obs is not None)
+
+ def execute(self, context):
+ for obj in context.selected_editable_objects:
+ if self.mode in {'ALL', 'LOC'}:
+ self.transfer_location(obj)
+
+ if self.mode in {'ALL', 'ROT'}:
+ self.transfer_rotation(obj)
+
+ if self.mode in {'ALL', 'SCALE'}:
+ self.transfer_scale(obj)
+
+ return {'FINISHED'}
+
+ def transfer_location(self, obj):
+ obj.delta_location += obj.location
+
+ if self.reset_values:
+ obj.location.zero()
+
+ def transfer_rotation(self, obj):
+ # TODO: add transforms together...
+ if obj.rotation_mode == 'QUATERNION':
+ obj.delta_rotation_quaternion += obj.rotation_quaternion
+
+ if self.reset_values:
+ obj.rotation_quaternion.identity()
+ elif obj.rotation_mode == 'AXIS_ANGLE':
+ pass # Unsupported
+ else:
+ delta = obj.delta_rotation_euler.copy()
+ obj.delta_rotation_euler = obj.rotation_euler
+ obj.delta_rotation_euler.rotate(delta)
+
+ if self.reset_values:
+ obj.rotation_euler.zero()
+
+ def transfer_scale(self, obj):
+ obj.delta_scale[0] *= obj.scale[0]
+ obj.delta_scale[1] *= obj.scale[1]
+ obj.delta_scale[2] *= obj.scale[2]
+
+ if self.reset_values:
+ obj.scale[:] = (1, 1, 1)
+
+
class TransformsToDeltasAnim(Operator):
"""Convert object animation for normal transforms to delta transforms"""
bl_idname = "object.anim_transforms_to_deltas"
diff --git a/release/scripts/startup/bl_operators/object_align.py b/release/scripts/startup/bl_operators/object_align.py
index 5c3d95e113c..a6ee16e6b71 100644
--- a/release/scripts/startup/bl_operators/object_align.py
+++ b/release/scripts/startup/bl_operators/object_align.py
@@ -365,6 +365,7 @@ class AlignObjects(Operator):
)
align_mode = EnumProperty(
name="Align Mode:",
+ description="Side of object to use for alignment",
items=(('OPT_1', "Negative Sides", ""),
('OPT_2', "Centers", ""),
('OPT_3', "Positive Sides", ""),
@@ -373,10 +374,11 @@ class AlignObjects(Operator):
)
relative_to = EnumProperty(
name="Relative To:",
- items=(('OPT_1', "Scene Origin", ""),
- ('OPT_2', "3D Cursor", ""),
- ('OPT_3', "Selection", ""),
- ('OPT_4', "Active", ""),
+ description="Reference location to align to",
+ items=(('OPT_1', "Scene Origin", "Use the Scene Origin as the position for the selected objects to align to"),
+ ('OPT_2', "3D Cursor", "Use the 3D cursor as the position for the selected objects to align to"),
+ ('OPT_3', "Selection", "Use the selected objects as the position for the selected objects to align to"),
+ ('OPT_4', "Active", "Use the active object as the position for the selected objects to align to"),
),
default='OPT_4',
)
diff --git a/release/scripts/startup/bl_operators/uvcalc_lightmap.py b/release/scripts/startup/bl_operators/uvcalc_lightmap.py
index a120e2b2461..3b095c883a3 100644
--- a/release/scripts/startup/bl_operators/uvcalc_lightmap.py
+++ b/release/scripts/startup/bl_operators/uvcalc_lightmap.py
@@ -285,8 +285,7 @@ def lightmap_uvpack(meshes,
for face_sel in face_groups:
print("\nStarting unwrap")
- if len(face_sel) < 4:
- print("\tWarning, less then 4 faces, skipping")
+ if not face_sel:
continue
pretty_faces = [prettyface(f) for f in face_sel if f.loop_total >= 4]
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py
index 76d41d91b78..1c97d213e05 100644
--- a/release/scripts/startup/bl_operators/wm.py
+++ b/release/scripts/startup/bl_operators/wm.py
@@ -1006,10 +1006,10 @@ class WM_OT_doc_view(Operator):
doc_id = doc_id
if bpy.app.version_cycle == "release":
- _prefix = ("http://www.blender.org/documentation/blender_python_api_%s%s_release" %
+ _prefix = ("https://www.blender.org/api/blender_python_api_%s%s_release" %
("_".join(str(v) for v in bpy.app.version[:2]), bpy.app.version_char))
else:
- _prefix = ("http://www.blender.org/documentation/blender_python_api_%s" %
+ _prefix = ("https://www.blender.org/api/blender_python_api_%s" %
"_".join(str(v) for v in bpy.app.version))
def execute(self, context):
@@ -1023,79 +1023,6 @@ class WM_OT_doc_view(Operator):
return {'FINISHED'}
-'''
-class WM_OT_doc_edit(Operator):
- """Edit online reference docs"""
- bl_idname = "wm.doc_edit"
- bl_label = "Edit Documentation"
-
- doc_id = doc_id
- doc_new = doc_new
-
- _url = "http://www.mindrones.com/blender/svn/xmlrpc.php"
-
- def _send_xmlrpc(self, data_dict):
- print("sending data:", data_dict)
-
- import xmlrpc.client
- user = "blenderuser"
- pwd = "blender>user"
-
- docblog = xmlrpc.client.ServerProxy(self._url)
- docblog.metaWeblog.newPost(1, user, pwd, data_dict, 1)
-
- def execute(self, context):
-
- doc_id = self.doc_id
- doc_new = self.doc_new
-
- class_name, class_prop = doc_id.split('.')
-
- if not doc_new:
- self.report({'ERROR'}, "No input given for '%s'" % doc_id)
- return {'CANCELLED'}
-
- # check if this is an operator
- op_name = class_name.upper() + '_OT_' + class_prop
- op_class = getattr(bpy.types, op_name, None)
-
- # Upload this to the web server
- upload = {}
-
- if op_class:
- rna = op_class.bl_rna
- doc_orig = rna.description
- if doc_orig == doc_new:
- return {'RUNNING_MODAL'}
-
- print("op - old:'%s' -> new:'%s'" % (doc_orig, doc_new))
- upload["title"] = 'OPERATOR %s:%s' % (doc_id, doc_orig)
- else:
- rna = getattr(bpy.types, class_name).bl_rna
- doc_orig = rna.properties[class_prop].description
- if doc_orig == doc_new:
- return {'RUNNING_MODAL'}
-
- print("rna - old:'%s' -> new:'%s'" % (doc_orig, doc_new))
- upload["title"] = 'RNA %s:%s' % (doc_id, doc_orig)
-
- upload["description"] = doc_new
-
- self._send_xmlrpc(upload)
-
- return {'FINISHED'}
-
- def draw(self, context):
- layout = self.layout
- layout.label(text="Descriptor ID: '%s'" % self.doc_id)
- layout.prop(self, "doc_new", text="")
-
- def invoke(self, context, event):
- wm = context.window_manager
- return wm.invoke_props_dialog(self, width=600)
-'''
-
-
rna_path = StringProperty(
name="Property Edit",
description="Property data_path edit",
@@ -1357,7 +1284,10 @@ class WM_OT_properties_add(Operator):
return prop_new
- prop = unique_name(item.keys())
+ prop = unique_name(
+ {*item.keys(),
+ *type(item).bl_rna.properties.keys(),
+ })
item[prop] = 1.0
rna_idprop_ui_prop_update(item, prop)
diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py
index 6fc668e67f5..2389be6787d 100644
--- a/release/scripts/startup/bl_ui/__init__.py
+++ b/release/scripts/startup/bl_ui/__init__.py
@@ -126,7 +126,7 @@ def register():
WindowManager.addon_filter = EnumProperty(
items=addon_filter_items,
name="Category",
- description="Filter addons by category",
+ description="Filter add-ons by category",
)
WindowManager.addon_support = EnumProperty(
diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py
index ef0fc9c7c9f..cb5f1595ff3 100644
--- a/release/scripts/startup/bl_ui/properties_constraint.py
+++ b/release/scripts/startup/bl_ui/properties_constraint.py
@@ -65,9 +65,10 @@ class ConstraintButtonsPanel:
layout.prop_search(con, "subtarget", con.target.data, "bones", text="Bone")
if hasattr(con, "head_tail"):
- row = layout.row()
+ row = layout.row(align=True)
row.label(text="Head/Tail:")
row.prop(con, "head_tail", text="")
+ row.prop(con, "use_bbone_shape", text="", icon='IPO_BEZIER') # XXX icon, and only when bone has segments?
elif con.target.type in {'MESH', 'LATTICE'}:
layout.prop_search(con, "subtarget", con.target, "vertex_groups", text="Vertex Group")
@@ -879,6 +880,19 @@ class ConstraintButtonsPanel:
layout.operator("clip.constraint_to_fcurve")
+ def TRANSFORM_CACHE(self, context, layout, con):
+ layout.label(text="Cache File Properties:")
+ box = layout.box()
+ box.template_cache_file(con, "cache_file")
+
+ cache_file = con.cache_file
+
+ layout.label(text="Constraint Properties:")
+ box = layout.box()
+
+ if cache_file is not None:
+ box.prop_search(con, "object_path", cache_file, "object_paths")
+
def SCRIPT(self, context, layout, con):
layout.label("Blender 2.6 doesn't support python constraints yet")
diff --git a/release/scripts/startup/bl_ui/properties_data_armature.py b/release/scripts/startup/bl_ui/properties_data_armature.py
index 3c9e2eb8f8b..8261f0c7770 100644
--- a/release/scripts/startup/bl_ui/properties_data_armature.py
+++ b/release/scripts/startup/bl_ui/properties_data_armature.py
@@ -181,7 +181,7 @@ class DATA_PT_pose_library(ArmatureButtonsPanel, Panel):
# list of poses in pose library
row = layout.row()
row.template_list("UI_UL_list", "pose_markers", poselib, "pose_markers",
- poselib.pose_markers, "active_index", rows=3)
+ poselib.pose_markers, "active_index", rows=5)
# column of operators for active pose
# - goes beside list
@@ -201,6 +201,10 @@ class DATA_PT_pose_library(ArmatureButtonsPanel, Panel):
col.operator("poselib.action_sanitize", icon='HELP', text="") # XXX: put in menu?
+ if pose_marker_active is not None:
+ col.operator("poselib.pose_move", icon='TRIA_UP', text="").direction = 'UP'
+ col.operator("poselib.pose_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
+
# TODO: this panel will soon be deprecated too
class DATA_PT_ghost(ArmatureButtonsPanel, Panel):
diff --git a/release/scripts/startup/bl_ui/properties_data_bone.py b/release/scripts/startup/bl_ui/properties_data_bone.py
index 690c22c1440..3a5475514c9 100644
--- a/release/scripts/startup/bl_ui/properties_data_bone.py
+++ b/release/scripts/startup/bl_ui/properties_data_bone.py
@@ -146,6 +146,81 @@ class BONE_PT_transform_locks(BoneButtonsPanel, Panel):
sub.prop(pchan, "lock_rotation_w", text="W")
+class BONE_PT_curved(BoneButtonsPanel, Panel):
+ bl_label = "Bendy Bones"
+ #bl_options = {'DEFAULT_CLOSED'}
+
+ def draw(self, context):
+ ob = context.object
+ bone = context.bone
+ # arm = context.armature
+ pchan = None
+
+ if ob and bone:
+ pchan = ob.pose.bones[bone.name]
+ bbone = pchan
+ elif bone is None:
+ bone = context.edit_bone
+ bbone = bone
+ else:
+ bbone = bone
+
+ layout = self.layout
+ layout.prop(bone, "bbone_segments", text="Segments")
+
+ col = layout.column()
+ col.active = bone.bbone_segments > 1
+
+ row = col.row()
+ sub = row.column(align=True)
+ sub.label(text="Curve XY Offsets:")
+ sub.prop(bbone, "bbone_curveinx", text="In X")
+ sub.prop(bbone, "bbone_curveoutx", text="Out X")
+ sub.prop(bbone, "bbone_curveiny", text="In Y")
+ sub.prop(bbone, "bbone_curveouty", text="Out Y")
+
+ sub = row.column(align=True)
+ sub.label("Roll:")
+ sub.prop(bbone, "bbone_rollin", text="In")
+ sub.prop(bbone, "bbone_rollout", text="Out")
+ sub.prop(bone, "use_endroll_as_inroll")
+
+ row = col.row()
+ sub = row.column(align=True)
+ sub.label(text="Scale:")
+ sub.prop(bbone, "bbone_scalein", text="Scale In")
+ sub.prop(bbone, "bbone_scaleout", text="Scale Out")
+
+ sub = row.column(align=True)
+ sub.label("Easing:")
+ if pchan:
+ # XXX: have these also be an overlay?
+ sub.prop(bbone.bone, "bbone_in", text="Ease In")
+ sub.prop(bbone.bone, "bbone_out", text="Ease Out")
+ else:
+ sub.prop(bone, "bbone_in", text="Ease In")
+ sub.prop(bone, "bbone_out", text="Ease Out")
+
+ if pchan:
+ layout.separator()
+
+ col = layout.column()
+ col.prop(pchan, "use_bbone_custom_handles")
+
+ row = col.row()
+ row.active = pchan.use_bbone_custom_handles
+
+ sub = row.column(align=True)
+ sub.label(text="In:")
+ sub.prop_search(pchan, "bbone_custom_handle_start", ob.pose, "bones", text="")
+ sub.prop(pchan, "use_bbone_relative_start_handle", text="Relative")
+
+ sub = row.column(align=True)
+ sub.label(text="Out:")
+ sub.prop_search(pchan, "bbone_custom_handle_end", ob.pose, "bones", text="")
+ sub.prop(pchan, "use_bbone_relative_end_handle", text="Relative")
+
+
class BONE_PT_relations(BoneButtonsPanel, Panel):
bl_label = "Relations"
@@ -348,28 +423,18 @@ class BONE_PT_deform(BoneButtonsPanel, Panel):
layout.active = bone.use_deform
- split = layout.split()
+ row = layout.row()
- col = split.column()
+ col = row.column(align=True)
col.label(text="Envelope:")
-
- sub = col.column(align=True)
- sub.prop(bone, "envelope_distance", text="Distance")
- sub.prop(bone, "envelope_weight", text="Weight")
+ col.prop(bone, "envelope_distance", text="Distance")
+ col.prop(bone, "envelope_weight", text="Weight")
col.prop(bone, "use_envelope_multiply", text="Multiply")
- sub = col.column(align=True)
- sub.label(text="Radius:")
- sub.prop(bone, "head_radius", text="Head")
- sub.prop(bone, "tail_radius", text="Tail")
-
- col = split.column()
- col.label(text="Curved Bones:")
-
- sub = col.column(align=True)
- sub.prop(bone, "bbone_segments", text="Segments")
- sub.prop(bone, "bbone_in", text="Ease In")
- sub.prop(bone, "bbone_out", text="Ease Out")
+ col = row.column(align=True)
+ col.label(text="Envelope Radius:")
+ col.prop(bone, "head_radius", text="Head")
+ col.prop(bone, "tail_radius", text="Tail")
class BONE_PT_custom_props(BoneButtonsPanel, PropertyPanel, Panel):
diff --git a/release/scripts/startup/bl_ui/properties_data_camera.py b/release/scripts/startup/bl_ui/properties_data_camera.py
index 58a4820e27a..c6fa77aec00 100644
--- a/release/scripts/startup/bl_ui/properties_data_camera.py
+++ b/release/scripts/startup/bl_ui/properties_data_camera.py
@@ -165,7 +165,15 @@ class DATA_PT_camera_stereoscopy(CameraButtonsPanel, Panel):
if is_spherical_stereo:
col.separator()
- col.prop(st, "use_spherical_stereo")
+ row = col.row()
+ row.prop(st, "use_spherical_stereo")
+ sub = row.row()
+ sub.active = st.use_spherical_stereo
+ sub.prop(st, "use_pole_merge")
+ row = col.row(align=True)
+ row.active = st.use_pole_merge
+ row.prop(st, "pole_merge_angle_from")
+ row.prop(st, "pole_merge_angle_to")
col.label(text="Pivot:")
row = col.row()
diff --git a/release/scripts/startup/bl_ui/properties_data_curve.py b/release/scripts/startup/bl_ui/properties_data_curve.py
index 81ecd2e8db5..33af812b6c4 100644
--- a/release/scripts/startup/bl_ui/properties_data_curve.py
+++ b/release/scripts/startup/bl_ui/properties_data_curve.py
@@ -125,7 +125,7 @@ class DATA_PT_shape_curve(CurveButtonsPanel, Panel):
col.prop(curve, "use_fill_deform")
if is_curve:
- col.label(text="Path / Curve-Deform:")
+ col.label(text="Path/Curve-Deform:")
sub = col.column()
subsub = sub.row()
subsub.prop(curve, "use_radius")
@@ -370,8 +370,11 @@ class DATA_PT_paragraph(CurveButtonsPanelText, Panel):
text = context.curve
- layout.label(text="Align:")
- layout.prop(text, "align", expand=True)
+ layout.label(text="Horizontal Alignment:")
+ layout.prop(text, "align_x", expand=True)
+
+ layout.label(text="Vertical Alignment:")
+ layout.prop(text, "align_y", expand=True)
split = layout.split()
diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py
index aa03863a198..540c29f31e4 100644
--- a/release/scripts/startup/bl_ui/properties_data_modifier.py
+++ b/release/scripts/startup/bl_ui/properties_data_modifier.py
@@ -156,16 +156,12 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
col.label(text="Object:")
col.prop(md, "object", text="")
- """
- layout.prop(md, "use_bmesh")
- if md.use_bmesh:
- box = layout.box()
- box.label("BMesh Options:")
- box.prop(md, "use_bmesh_separate")
- box.prop(md, "use_bmesh_dissolve")
- box.prop(md, "use_bmesh_connect_regions")
- box.prop(md, "threshold")
- """
+ split = layout.split()
+ split.column().label(text="Solver:")
+ split.column().prop(md, "solver", text="")
+
+ if md.solver == 'BMESH':
+ layout.prop(md, "double_threshold")
def BUILD(self, layout, ob, md):
split = layout.split()
@@ -185,6 +181,9 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
layout.prop(md, "cache_format")
layout.prop(md, "filepath")
+ if md.cache_format == 'ABC':
+ layout.prop(md, "sub_object")
+
layout.label(text="Evaluation:")
layout.prop(md, "factor", slider=True)
layout.prop(md, "deform_mode")
@@ -219,6 +218,22 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
row = split.row()
row.prop(md, "flip_axis")
+ def MESH_SEQUENCE_CACHE(self, layout, ob, md):
+ layout.label(text="Cache File Properties:")
+ box = layout.box()
+ box.template_cache_file(md, "cache_file")
+
+ cache_file = md.cache_file
+
+ layout.label(text="Modifier Properties:")
+ box = layout.box()
+
+ if cache_file is not None:
+ box.prop_search(md, "object_path", cache_file, "object_paths")
+
+ if ob.type == 'MESH':
+ box.row().prop(md, "read_data")
+
def CAST(self, layout, ob, md):
split = layout.split(percentage=0.25)
@@ -321,6 +336,9 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
col = split.column(align=True)
col.label(text="Direction:")
col.prop(md, "direction", text="")
+ if md.direction in {'X', 'Y', 'Z', 'RGB_TO_XYZ'}:
+ col.label(text="Space:")
+ col.prop(md, "space", text="")
col.label(text="Vertex Group:")
col.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
@@ -884,17 +902,48 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
split = layout.split()
col = split.column()
- col.label(text="Subdivisions:")
- col.prop(md, "levels", text="View")
- col.prop(md, "render_levels", text="Render")
+
+ scene = bpy.context.scene
+ engine = scene.render.engine
+ show_adaptive_options = (engine == "CYCLES" and md == ob.modifiers[-1] and
+ scene.cycles.feature_set == "EXPERIMENTAL")
+
+ if show_adaptive_options:
+ col.label(text="View:")
+ col.prop(md, "levels", text="Levels")
+ col.label(text="Render:")
+ col.prop(ob.cycles, "use_adaptive_subdivision", text="Adaptive")
+ if ob.cycles.use_adaptive_subdivision:
+ col.prop(ob.cycles, "dicing_rate")
+ else:
+ col.prop(md, "render_levels", text="Levels")
+ else:
+ col.label(text="Subdivisions:")
+ col.prop(md, "levels", text="View")
+ col.prop(md, "render_levels", text="Render")
col = split.column()
col.label(text="Options:")
- col.prop(md, "use_subsurf_uv")
+
+ sub = col.column()
+ sub.active = (not show_adaptive_options) or (not ob.cycles.use_adaptive_subdivision)
+ sub.prop(md, "use_subsurf_uv")
+
col.prop(md, "show_only_control_edges")
if hasattr(md, "use_opensubdiv"):
col.prop(md, "use_opensubdiv")
+ if show_adaptive_options and ob.cycles.use_adaptive_subdivision:
+ col = layout.column(align=True)
+ col.scale_y = 0.6
+ col.separator()
+ col.label("Final Dicing Rate:")
+ col.separator()
+
+ render = max(scene.cycles.dicing_rate * ob.cycles.dicing_rate, 0.1)
+ preview = max(scene.cycles.preview_dicing_rate * ob.cycles.dicing_rate, 0.1)
+ col.label("Render %.2f px, Preview %.2f px" % (render, preview))
+
def SURFACE(self, layout, ob, md):
layout.label(text="Settings are inside the Physics tab")
@@ -1418,6 +1467,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
sub = row.row(align=True)
sub.active = has_vgroup
sub.prop(md, "invert_vertex_group", text="", icon='ARROW_LEFTRIGHT')
+ subcol.prop(md, "mix_limit")
def CORRECTIVE_SMOOTH(self, layout, ob, md):
is_bind = md.is_bind
diff --git a/release/scripts/startup/bl_ui/properties_game.py b/release/scripts/startup/bl_ui/properties_game.py
index 8baad4ea0f2..386ad254892 100644
--- a/release/scripts/startup/bl_ui/properties_game.py
+++ b/release/scripts/startup/bl_ui/properties_game.py
@@ -404,6 +404,7 @@ class RENDER_PT_game_shading(RenderButtonsPanel, Panel):
col.prop(gs, "use_glsl_lights", text="Lights")
col.prop(gs, "use_glsl_shaders", text="Shaders")
col.prop(gs, "use_glsl_shadows", text="Shadows")
+ col.prop(gs, "use_glsl_environment_lighting", text="Environment Lighting")
col = split.column()
col.prop(gs, "use_glsl_ramps", text="Ramps")
@@ -567,7 +568,7 @@ class WORLD_PT_game_context_world(WorldButtonsPanel, Panel):
@classmethod
def poll(cls, context):
rd = context.scene.render
- return (context.scene) and (rd.use_game_engine)
+ return (context.scene) and (rd.engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
@@ -599,9 +600,35 @@ class WORLD_PT_game_world(WorldButtonsPanel, Panel):
row = layout.row()
row.column().prop(world, "horizon_color")
+ row.column().prop(world, "zenith_color")
row.column().prop(world, "ambient_color")
+class WORLD_PT_game_environment_lighting(WorldButtonsPanel, Panel):
+ bl_label = "Environment Lighting"
+ COMPAT_ENGINES = {'BLENDER_GAME'}
+
+ @classmethod
+ def poll(cls, context):
+ scene = context.scene
+ return (scene.world and scene.render.engine in cls.COMPAT_ENGINES)
+
+ def draw_header(self, context):
+ light = context.world.light_settings
+ self.layout.prop(light, "use_environment_light", text="")
+
+ def draw(self, context):
+ layout = self.layout
+
+ light = context.world.light_settings
+
+ layout.active = light.use_environment_light
+
+ split = layout.split()
+ split.prop(light, "environment_energy", text="Energy")
+ split.prop(light, "environment_color", text="")
+
+
class WORLD_PT_game_mist(WorldButtonsPanel, Panel):
bl_label = "Mist"
COMPAT_ENGINES = {'BLENDER_GAME'}
diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
index a823789f2c3..bc40932018d 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -20,6 +20,7 @@
from bpy.types import Menu, UIList
+from bpy.app.translations import pgettext_iface as iface_
def gpencil_stroke_placement_settings(context, layout):
@@ -51,6 +52,40 @@ def gpencil_stroke_placement_settings(context, layout):
row.active = getattr(ts, propname) in {'SURFACE', 'STROKE'}
row.prop(ts, "use_gpencil_stroke_endpoints")
+ if context.scene.tool_settings.gpencil_stroke_placement_view3d == 'CURSOR':
+ row = col.row(align=True)
+ row.label("Lock axis:")
+ row = col.row(align=True)
+ row.prop(ts.gpencil_sculpt, "lockaxis", expand=True)
+
+
+def gpencil_active_brush_settings_simple(context, layout):
+ brush = context.active_gpencil_brush
+
+ col = layout.column()
+ col.label("Active Brush: ")
+
+ row = col.row(align=True)
+ row.operator_context = 'EXEC_REGION_WIN'
+ row.operator_menu_enum("gpencil.brush_change", "brush", text="", icon='BRUSH_DATA')
+ row.prop(brush, "name", text="")
+
+ col.prop(brush, "line_width", slider=True)
+ row = col.row(align=True)
+ row.prop(brush, "use_random_pressure", text='', icon='RNDCURVE')
+ row.prop(brush, "pen_sensitivity_factor", slider=True)
+ row.prop(brush, "use_pressure", text='', icon='STYLUS_PRESSURE')
+ row = col.row(align=True)
+ row.prop(brush, "use_random_strength", text='', icon='RNDCURVE')
+ row.prop(brush, "strength", slider=True)
+ row.prop(brush, "use_strength_pressure", text='', icon='STYLUS_PRESSURE')
+ row = col.row(align=True)
+ row.prop(brush, "jitter", slider=True)
+ row.prop(brush, "use_jitter_pressure", text='', icon='STYLUS_PRESSURE')
+ row = col.row()
+ row.prop(brush, "angle", slider=True)
+ row.prop(brush, "angle_factor", text="Factor", slider=True)
+
class GreasePencilDrawingToolsPanel:
# subclass must set
@@ -63,6 +98,9 @@ class GreasePencilDrawingToolsPanel:
def draw(self, context):
layout = self.layout
+ is_3d_view = context.space_data.type == 'VIEW_3D'
+ is_clip_editor = context.space_data.type == 'CLIP_EDITOR'
+
col = layout.column(align=True)
col.label(text="Draw:")
@@ -77,6 +115,7 @@ class GreasePencilDrawingToolsPanel:
sub = col.column(align=True)
sub.prop(context.tool_settings, "use_gpencil_additive_drawing", text="Additive Drawing")
sub.prop(context.tool_settings, "use_gpencil_continuous_drawing", text="Continuous Drawing")
+ sub.prop(context.tool_settings, "use_gpencil_draw_onback", text="Draw on Back")
col.separator()
col.separator()
@@ -85,9 +124,9 @@ class GreasePencilDrawingToolsPanel:
col.separator()
col.label("Data Source:")
row = col.row(align=True)
- if context.space_data.type == 'VIEW_3D':
+ if is_3d_view:
row.prop(context.tool_settings, "grease_pencil_source", expand=True)
- elif context.space_data.type == 'CLIP_EDITOR':
+ elif is_clip_editor:
row.prop(context.space_data, "grease_pencil_source", expand=True)
col.separator()
@@ -97,19 +136,19 @@ class GreasePencilDrawingToolsPanel:
gpd = context.gpencil_data
- if gpd:
+ if gpd and not is_3d_view:
layout.separator()
layout.separator()
col = layout.column(align=True)
col.prop(gpd, "use_stroke_edit_mode", text="Enable Editing", icon='EDIT', toggle=True)
- if context.space_data.type == 'VIEW_3D':
+ if is_3d_view:
col.separator()
col.separator()
col.label(text="Tools:")
- col.operator("gpencil.convert", text="Convert...")
+ col.operator_menu_enum("gpencil.convert", text="Convert to Geometry...", property="type")
col.operator("view3d.ruler")
@@ -133,45 +172,147 @@ class GreasePencilStrokeEditPanel:
def draw(self, context):
layout = self.layout
- layout.label(text="Select:")
- col = layout.column(align=True)
- col.operator("gpencil.select_all", text="Select All")
- col.operator("gpencil.select_border")
- col.operator("gpencil.select_circle")
+ is_3d_view = context.space_data.type == 'VIEW_3D'
- layout.separator()
+ if not is_3d_view:
+ layout.label(text="Select:")
+ col = layout.column(align=True)
+ col.operator("gpencil.select_all", text="Select All")
+ col.operator("gpencil.select_border")
+ col.operator("gpencil.select_circle")
- col = layout.column(align=True)
- col.operator("gpencil.select_linked")
- col.operator("gpencil.select_more")
- col.operator("gpencil.select_less")
+ layout.separator()
- layout.separator()
+ col = layout.column(align=True)
+ col.operator("gpencil.select_linked")
+ col.operator("gpencil.select_more")
+ col.operator("gpencil.select_less")
+ col.operator("gpencil.palettecolor_select")
layout.label(text="Edit:")
row = layout.row(align=True)
row.operator("gpencil.copy", text="Copy")
- row.operator("gpencil.paste", text="Paste")
+ row.operator("gpencil.paste", text="Paste").type = 'COPY'
+ row.operator("gpencil.paste", text="Paste & Merge").type = 'MERGE'
col = layout.column(align=True)
- col.operator("gpencil.delete", text="Delete")
+ col.operator("gpencil.delete")
col.operator("gpencil.duplicate_move", text="Duplicate")
- col.operator("transform.mirror", text="Mirror")
+ if is_3d_view:
+ col.operator("gpencil.stroke_cyclical_set", text="Toggle Cyclic").type = 'TOGGLE'
layout.separator()
- col = layout.column(align=True)
- col.operator("transform.translate") # icon='MAN_TRANS'
- col.operator("transform.rotate") # icon='MAN_ROT'
- col.operator("transform.resize", text="Scale") # icon='MAN_SCALE'
+ if not is_3d_view:
+ col = layout.column(align=True)
+ col.operator("transform.translate") # icon='MAN_TRANS'
+ col.operator("transform.rotate") # icon='MAN_ROT'
+ col.operator("transform.resize", text="Scale") # icon='MAN_SCALE'
- layout.separator()
+ layout.separator()
col = layout.column(align=True)
col.operator("transform.bend", text="Bend")
+ col.operator("transform.mirror", text="Mirror")
col.operator("transform.shear", text="Shear")
col.operator("transform.tosphere", text="To Sphere")
+ layout.separator()
+ col = layout.column(align=True)
+ col.operator_menu_enum("gpencil.stroke_arrange", text="Arrange Strokes...", property="direction")
+ col.operator("gpencil.stroke_change_color", text="Move to Color")
+
+ if is_3d_view:
+ layout.separator()
+ col = layout.column(align=True)
+ col.operator("gpencil.interpolate", text="Interpolate")
+ col.operator("gpencil.interpolate_sequence", text="Sequence")
+ settings = context.tool_settings.gpencil_sculpt
+ col.prop(settings, "interpolate_all_layers")
+ col.prop(settings, "interpolate_selected_only")
+
+ layout.separator()
+ col = layout.column(align=True)
+ col.operator("gpencil.stroke_subdivide", text="Subdivide")
+ col.operator("gpencil.stroke_join", text="Join").type = 'JOIN'
+ col.operator("gpencil.stroke_join", text="Join & Copy").type = 'JOINCOPY'
+ col.operator("gpencil.stroke_flip", text="Flip Direction")
+
+ gpd = context.gpencil_data
+ if gpd:
+ col.prop(gpd, "show_stroke_direction", text="Show Directions")
+
+ if is_3d_view:
+ layout.separator()
+ layout.operator("gpencil.reproject")
+
+
+class GreasePencilBrushPanel:
+ # subclass must set
+ # bl_space_type = 'IMAGE_EDITOR'
+ bl_label = "Drawing Brushes"
+ bl_category = "Grease Pencil"
+ bl_region_type = 'TOOLS'
+
+ @staticmethod
+ def draw(self, context):
+ layout = self.layout
+
+ row = layout.row()
+ col = row.column()
+ ts = context.scene.tool_settings
+ if len(ts.gpencil_brushes) >= 2:
+ brows = 3
+ else:
+ brows = 2
+ col.template_list("GPENCIL_UL_brush", "", ts, "gpencil_brushes", ts.gpencil_brushes, "active_index", rows=brows)
+
+ col = row.column()
+
+ sub = col.column(align=True)
+ sub.operator("gpencil.brush_add", icon='ZOOMIN', text="")
+ sub.operator("gpencil.brush_remove", icon='ZOOMOUT', text="")
+ sub.menu("GPENCIL_MT_brush_specials", icon='DOWNARROW_HLT', text="")
+ brush = context.active_gpencil_brush
+ if brush:
+ if len(ts.gpencil_brushes) > 1:
+ col.separator()
+ sub = col.column(align=True)
+ sub.operator("gpencil.brush_move", icon='TRIA_UP', text="").type = 'UP'
+ sub.operator("gpencil.brush_move", icon='TRIA_DOWN', text="").type = 'DOWN'
+
+ # Brush details
+ if brush is not None:
+ row = layout.row()
+ row.prop(brush, "line_width")
+ row = layout.row(align=True)
+ row.prop(brush, "use_random_pressure", text='', icon='RNDCURVE')
+ row.prop(brush, "pen_sensitivity_factor", slider=True)
+ row.prop(brush, "use_pressure", text='', icon='STYLUS_PRESSURE')
+ row = layout.row(align=True)
+ row.prop(brush, "use_random_strength", text='', icon='RNDCURVE')
+ row.prop(brush, "strength", slider=True)
+ row.prop(brush, "use_strength_pressure", text='', icon='STYLUS_PRESSURE')
+ row = layout.row(align=True)
+ row.prop(brush, "random_press", slider=True)
+
+ row = layout.row(align=True)
+ row.prop(brush, "jitter", slider=True)
+ row.prop(brush, "use_jitter_pressure", text='', icon='STYLUS_PRESSURE')
+ row = layout.row()
+ row.prop(brush, "angle", slider=True)
+ row.prop(brush, "angle_factor", text="Factor", slider=True)
+
+ box = layout.box()
+ col = box.column(align=True)
+ col.label(text="Stroke Quality:")
+ col.prop(brush, "pen_smooth_factor")
+ col.prop(brush, "pen_smooth_steps")
+ col.separator()
+ row = col.row(align=False)
+ row.prop(brush, "pen_subdivision_steps")
+ row.prop(brush, "random_subdiv", text='Randomness', slider=True)
+
class GreasePencilStrokeSculptPanel:
# subclass must set
@@ -196,7 +337,7 @@ class GreasePencilStrokeSculptPanel:
tool = settings.tool
brush = settings.brush
- layout.column().prop(settings, "tool", expand=True)
+ layout.column().prop(settings, "tool")
col = layout.column()
col.prop(brush, "size", slider=True)
@@ -204,12 +345,17 @@ class GreasePencilStrokeSculptPanel:
row.prop(brush, "strength", slider=True)
row.prop(brush, "use_pressure_strength", text="")
col.prop(brush, "use_falloff")
+ if tool in {'SMOOTH', 'RANDOMIZE'}:
+ row = layout.row(align=True)
+ row.prop(settings, "affect_position", text="Position", icon='MESH_DATA', toggle=True)
+ row.prop(settings, "affect_strength", text="Strength", icon='COLOR', toggle=True)
+ row.prop(settings, "affect_thickness", text="Thickness", icon='LINE_DATA', toggle=True)
layout.separator()
- if settings.tool == 'THICKNESS':
+ if tool == 'THICKNESS':
layout.row().prop(brush, "direction", expand=True)
- elif settings.tool == 'PINCH':
+ elif tool == 'PINCH':
row = layout.row(align=True)
row.prop_enum(brush, "direction", 'ADD', text="Pinch")
row.prop_enum(brush, "direction", 'SUBTRACT', text="Inflate")
@@ -218,13 +364,49 @@ class GreasePencilStrokeSculptPanel:
row.prop_enum(brush, "direction", 'SUBTRACT', text="CW")
row.prop_enum(brush, "direction", 'ADD', text="CCW")
- layout.separator()
- layout.prop(settings, "use_select_mask")
+ row = layout.row(align=True)
+ row.prop(settings, "use_select_mask")
+ row = layout.row(align=True)
+ row.prop(settings, "selection_alpha", slider=True)
- if settings.tool == 'SMOOTH':
+ if tool == 'SMOOTH':
layout.prop(brush, "affect_pressure")
+class GreasePencilBrushCurvesPanel:
+ # subclass must set
+ # bl_space_type = 'IMAGE_EDITOR'
+ bl_label = "Brush Curves"
+ bl_category = "Grease Pencil"
+ bl_region_type = 'TOOLS'
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ if context.active_gpencil_brush is None:
+ return False
+
+ brush = context.active_gpencil_brush
+ return bool(brush)
+
+ @staticmethod
+ def draw(self, context):
+ layout = self.layout
+ brush = context.active_gpencil_brush
+ # Brush
+ layout.label("Sensitivity")
+ box = layout.box()
+ box.template_curve_mapping(brush, "curve_sensitivity", brush=True)
+
+ layout.label("Strength")
+ box = layout.box()
+ box.template_curve_mapping(brush, "curve_strength", brush=True)
+
+ layout.label("Jitter")
+ box = layout.box()
+ box.template_curve_mapping(brush, "curve_jitter", brush=True)
+
+
###############################
class GPENCIL_PIE_tool_palette(Menu):
@@ -275,6 +457,7 @@ class GPENCIL_PIE_tool_palette(Menu):
col.operator("gpencil.select_all", text="Select All", icon='PARTICLE_POINT')
col.operator("gpencil.select_all", text="Select Inverse", icon='BLANK1')
col.operator("gpencil.select_linked", text="Select Linked", icon='LINKED')
+ col.operator("gpencil.palettecolor_select", text="Select Color", icon='COLOR')
# NE - Select (Modal)
col = pie.column()
@@ -306,26 +489,31 @@ class GPENCIL_PIE_settings_palette(Menu):
layout = self.layout
pie = layout.menu_pie()
- # gpd = context.gpencil_data
+ gpd = context.gpencil_data
gpl = context.active_gpencil_layer
+ palcolor = context.active_gpencil_palettecolor
+ brush = context.active_gpencil_brush
+
+ is_editmode = bool(gpd and gpd.use_stroke_edit_mode and context.editable_gpencil_strokes)
# W - Stroke draw settings
col = pie.column(align=True)
- col.label(text="Stroke")
- col.prop(gpl, "color", text="")
- col.prop(gpl, "alpha", text="", slider=True)
+ if palcolor is not None:
+ col.enabled = not palcolor.lock
+ col.label(text="Stroke")
+ col.prop(palcolor, "color", text="")
+ col.prop(palcolor, "alpha", text="", slider=True)
# E - Fill draw settings
col = pie.column(align=True)
- col.label(text="Fill")
- col.prop(gpl, "fill_color", text="")
- col.prop(gpl, "fill_alpha", text="", slider=True)
+ if palcolor is not None:
+ col.enabled = not palcolor.lock
+ col.label(text="Fill")
+ col.prop(palcolor, "fill_color", text="")
+ col.prop(palcolor, "fill_alpha", text="", slider=True)
- # S - Layer settings
- col = pie.column()
- col.prop(gpl, "line_width", slider=True)
- # col.prop(gpl, "use_volumetric_strokes")
- col.prop(gpl, "use_onion_skinning")
+ # S Brush settings
+ gpencil_active_brush_settings_simple(context, pie)
# N - Active Layer
col = pie.column()
@@ -340,6 +528,36 @@ class GPENCIL_PIE_settings_palette(Menu):
row = col.row()
row.prop(gpl, "lock")
row.prop(gpl, "hide")
+ col.prop(gpl, "use_onion_skinning")
+
+ # NW/NE/SW/SE - These operators are only available in editmode
+ # as they require strokes to be selected to work
+ if is_editmode:
+ # NW - Move stroke Down
+ col = pie.column(align=True)
+ col.label("Arrange Strokes")
+ col.operator("gpencil.stroke_arrange", text="Send to Back").direction = 'BOTTOM'
+ col.operator("gpencil.stroke_arrange", text="Send Backward").direction = 'DOWN'
+
+ # NE - Move stroke Up
+ col = pie.column(align=True)
+ col.label("Arrange Strokes")
+ col.operator("gpencil.stroke_arrange", text="Bring to Front").direction = 'TOP'
+ col.operator("gpencil.stroke_arrange", text="Bring Forward").direction = 'UP'
+
+ # SW - Move stroke to color
+ col = pie.column(align=True)
+ col.operator("gpencil.stroke_change_color", text="Move to Color")
+
+ # SE - Join strokes
+ col = pie.column(align=True)
+ col.label("Join Strokes")
+ row = col.row()
+ row.operator("gpencil.stroke_join", text="Join").type = 'JOIN'
+ row.operator("gpencil.stroke_join", text="Join & Copy").type = 'JOINCOPY'
+ col.operator("gpencil.stroke_flip", text="Flip direction")
+
+ col.prop(gpd, "show_stroke_direction", text="Show drawing direction")
class GPENCIL_PIE_tools_more(Menu):
@@ -404,6 +622,11 @@ class GPENCIL_PIE_sculpt(Menu):
row.prop(brush, "strength", slider=True)
# row.prop(brush, "use_pressure_strength", text="", icon_only=True)
col.prop(brush, "use_falloff")
+ if settings.tool in {'SMOOTH', 'RANDOMIZE'}:
+ row = col.row(align=True)
+ row.prop(settings, "affect_position", text="Position", icon='MESH_DATA', toggle=True)
+ row.prop(settings, "affect_strength", text="Strength", icon='COLOR', toggle=True)
+ row.prop(settings, "affect_thickness", text="Thickness", icon='LINE_DATA', toggle=True)
# S - Change Brush Type Shortcuts
row = pie.row()
@@ -415,6 +638,7 @@ class GPENCIL_PIE_sculpt(Menu):
row = pie.row()
row.prop_enum(settings, "tool", value='SMOOTH')
row.prop_enum(settings, "tool", value='THICKNESS')
+ row.prop_enum(settings, "tool", value='STRENGTH')
row.prop_enum(settings, "tool", value='RANDOMIZE')
@@ -438,9 +662,74 @@ class GPENCIL_MT_snap(Menu):
layout.operator("view3d.snap_cursor_to_grid", text="Cursor to Grid")
+class GPENCIL_MT_gpencil_edit_specials(Menu):
+ bl_label = "GPencil Specials"
+
+ def draw(self, context):
+ layout = self.layout
+ is_3d_view = context.space_data.type == 'VIEW_3D'
+
+ layout.operator_context = 'INVOKE_REGION_WIN'
+
+ layout.operator("gpencil.stroke_subdivide", text="Subdivide")
+
+ layout.separator()
+
+ layout.operator("gpencil.stroke_join", text="Join").type = 'JOIN'
+ layout.operator("gpencil.stroke_join", text="Join & Copy").type = 'JOINCOPY'
+ layout.operator("gpencil.stroke_flip", text="Flip Direction")
+
+ if is_3d_view:
+ layout.separator()
+ layout.operator("gpencil.reproject")
+
+
###############################
+class GPENCIL_UL_brush(UIList):
+ def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
+ # assert(isinstance(item, bpy.types.GPencilBrush)
+ brush = item
+
+ if self.layout_type in {'DEFAULT', 'COMPACT'}:
+ row = layout.row(align=True)
+ row.prop(brush, "name", text="", emboss=False, icon='BRUSH_DATA')
+ elif self.layout_type == 'GRID':
+ layout.alignment = 'CENTER'
+ layout.label(text="", icon_value=icon)
+
+
+class GPENCIL_UL_palettecolor(UIList):
+ def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
+ # assert(isinstance(item, bpy.types.PaletteColor)
+ palcolor = item
+
+ if self.layout_type in {'DEFAULT', 'COMPACT'}:
+ if palcolor.lock:
+ layout.active = False
+
+ split = layout.split(percentage=0.25)
+ row = split.row(align=True)
+ row.enabled = not palcolor.lock
+ row.prop(palcolor, "color", text="", emboss=palcolor.is_stroke_visible)
+ row.prop(palcolor, "fill_color", text="", emboss=palcolor.is_fill_visible)
+ split.prop(palcolor, "name", text="", emboss=False)
+
+ row = layout.row(align=True)
+ row.prop(palcolor, "lock", text="", emboss=False)
+ row.prop(palcolor, "hide", text="", emboss=False)
+ if palcolor.ghost is True:
+ icon = 'GHOST_DISABLED'
+ else:
+ icon = 'GHOST_ENABLED'
+ row.prop(palcolor, "ghost", text="", icon=icon, emboss=False)
+
+ elif self.layout_type == 'GRID':
+ layout.alignment = 'CENTER'
+ layout.label(text="", icon_value=icon)
+
+
class GPENCIL_UL_layer(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
# assert(isinstance(item, bpy.types.GPencilLayer)
@@ -450,15 +739,19 @@ class GPENCIL_UL_layer(UIList):
if gpl.lock:
layout.active = False
- split = layout.split(percentage=0.25)
- row = split.row(align=True)
- row.prop(gpl, "color", text="", emboss=gpl.is_stroke_visible)
- row.prop(gpl, "fill_color", text="", emboss=gpl.is_fill_visible)
- split.prop(gpl, "info", text="", emboss=False)
+ row = layout.row(align=True)
+ if gpl.is_parented:
+ icon = 'BONE_DATA'
+ else:
+ icon = 'BLANK1'
+
+ row.label(text="", icon=icon)
+ row.prop(gpl, "info", text="", emboss=False)
row = layout.row(align=True)
row.prop(gpl, "lock", text="", emboss=False)
row.prop(gpl, "hide", text="", emboss=False)
+ row.prop(gpl, "unlock_color", text="", emboss=False)
elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="", icon_value=icon)
@@ -482,11 +775,45 @@ class GPENCIL_MT_layer_specials(Menu):
layout.operator("gpencil.lock_all", icon='LOCKED', text="Lock All")
layout.operator("gpencil.unlock_all", icon='UNLOCKED', text="UnLock All")
+ layout.separator()
+
+ layout.operator("gpencil.layer_merge", icon='NLA', text="Merge Down")
+
+
+class GPENCIL_MT_brush_specials(Menu):
+ bl_label = "Layer"
+
+ def draw(self, context):
+ layout = self.layout
+ layout.operator("gpencil.brush_copy", icon='PASTEDOWN', text="Copy current drawing brush")
+ layout.operator("gpencil.brush_presets_create", icon='HELP', text="Create a set of predefined brushes")
+
+
+class GPENCIL_MT_palettecolor_specials(Menu):
+ bl_label = "Layer"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("gpencil.palettecolor_reveal", icon='RESTRICT_VIEW_OFF', text="Show All")
+ layout.operator("gpencil.palettecolor_hide", icon='RESTRICT_VIEW_ON', text="Hide Others").unselected = True
+
+ layout.separator()
+
+ layout.operator("gpencil.palettecolor_lock_all", icon='LOCKED', text="Lock All")
+ layout.operator("gpencil.palettecolor_unlock_all", icon='UNLOCKED', text="UnLock All")
+ layout.operator("gpencil.palettecolor_copy", icon='PASTEDOWN', text="Copy Color")
+
+ layout.separator()
+
+ layout.operator("gpencil.palettecolor_select", icon='COLOR', text="Select Strokes")
+ layout.operator("gpencil.stroke_change_color", icon='MAN_TRANS', text="Move to Color")
+
class GreasePencilDataPanel:
# subclass must set
# bl_space_type = 'IMAGE_EDITOR'
- bl_label = "Grease Pencil"
+ bl_label = "Grease Pencil Layers"
bl_region_type = 'UI'
@staticmethod
@@ -546,45 +873,53 @@ class GreasePencilDataPanel:
col.separator()
sub = col.column(align=True)
- sub.operator("gpencil.layer_isolate", icon='SOLO_OFF', text="").affect_visibility = False
+ sub.operator("gpencil.layer_isolate", icon='LOCKED', text="").affect_visibility = False
sub.operator("gpencil.layer_isolate", icon='RESTRICT_VIEW_OFF', text="").affect_visibility = True
if gpl:
- self.draw_layer(layout, gpl)
+ self.draw_layer(context, layout, gpl)
+
+ def draw_layer(self, context, layout, gpl):
+ row = layout.row(align=True)
+ row.prop(gpl, "opacity", text="Opacity", slider=True)
- def draw_layer(self, layout, gpl):
- # layer settings
+ # Layer options
split = layout.split(percentage=0.5)
split.active = not gpl.lock
+ split.prop(gpl, "show_x_ray")
+ split.prop(gpl, "show_points")
- # Column 1 - Stroke
- col = split.column(align=True)
- col.label(text="Stroke:")
- col.prop(gpl, "color", text="")
- col.prop(gpl, "alpha", slider=True)
-
- # Column 2 - Fill
- col = split.column(align=True)
- col.label(text="Fill:")
- col.prop(gpl, "fill_color", text="")
- col.prop(gpl, "fill_alpha", text="Opacity", slider=True)
+ # Offsets + Parenting (where available)
+ if context.space_data.type == 'VIEW_3D':
+ split = layout.split(percentage=0.5)
+ else:
+ split = layout.column() # parenting is not available in 2D editors...
+ split.active = not gpl.lock
- # Options
- col = layout.column(align=True)
- col.active = not gpl.lock
- col.prop(gpl, "line_width", slider=True)
+ # Offsets - Color Tint
+ col = split.column()
+ subcol = col.column(align=True)
+ subcol.label("Tint")
+ subcol.enabled = not gpl.lock
+ subcol.prop(gpl, "tint_color", text="")
+ subcol.prop(gpl, "tint_factor", text="Factor", slider=True)
+ # Offsets - Thickness
+ row = col.row(align=True)
+ row.prop(gpl, "line_change", text="Thickness Change", slider=True)
+ row.operator("gpencil.stroke_apply_thickness", icon='STYLUS_PRESSURE', text="")
- split = layout.split(percentage=0.5)
- split.active = not gpl.lock
+ # Parenting
+ if context.space_data.type == 'VIEW_3D':
+ col = split.column(align=True)
+ col.label(text="Parent:")
+ col.prop(gpl, "parent", text="")
- col = split.column(align=True)
- col.prop(gpl, "use_volumetric_strokes")
- col.prop(gpl, "show_points", text="Points")
-
- col = split.column(align=True)
- col.prop(gpl, "use_hq_fill")
- col.prop(gpl, "show_x_ray")
+ sub = col.column()
+ sub.prop(gpl, "parent_type", text="")
+ parent = gpl.parent
+ if parent and gpl.parent_type == 'BONE' and parent.type == 'ARMATURE':
+ sub.prop_search(gpl, "parent_bone", parent.data, "bones", text="")
layout.separator()
@@ -593,10 +928,10 @@ class GreasePencilDataPanel:
row.active = not gpl.lock
if gpl.active_frame:
- lock_status = "Locked" if gpl.lock_frame else "Unlocked"
- lock_label = "Frame: %d (%s)" % (gpl.active_frame.frame_number, lock_status)
+ lock_status = iface_("Locked") if gpl.lock_frame else iface_("Unlocked")
+ lock_label = iface_("Frame: %d (%s)") % (gpl.active_frame.frame_number, lock_status)
else:
- lock_label = "Lock Frame"
+ lock_label = iface_("Lock Frame")
row.prop(gpl, "lock_frame", text=lock_label, icon='UNLOCKED')
row.operator("gpencil.active_frame_delete", text="", icon='X')
@@ -627,17 +962,108 @@ class GreasePencilDataPanel:
row.prop(gpl, "after_color", text="")
sub.prop(gpl, "ghost_after_range", text="After")
- # Smooth and subdivide new strokes
- layout.separator()
- col = layout.column(align=True)
- col.label(text="New Stroke Quality:")
- col.prop(gpl, "pen_smooth_factor")
- col.prop(gpl, "pen_smooth_steps")
- col.separator()
- col.prop(gpl, "pen_subdivision_steps")
+
+class GreasePencilPaletteColorPanel:
+ # subclass must set
+ bl_label = "Grease Pencil Colors"
+ bl_region_type = 'UI'
+
+ @classmethod
+ def poll(cls, context):
+ if context.gpencil_data is None:
+ return False
+
+ gpd = context.gpencil_data
+ return bool(gpd.layers.active)
+
+ @staticmethod
+ def draw(self, context):
+ layout = self.layout
+ palette = context.active_gpencil_palette
+
+ if palette:
+ row = layout.row(align=True)
+ row.operator_context = 'EXEC_REGION_WIN'
+ row.operator_menu_enum("gpencil.palette_change", "palette", text="", icon='COLOR')
+ row.prop(palette, "name", text="")
+ row.operator("gpencil.palette_add", icon='ZOOMIN', text="")
+ row.operator("gpencil.palette_remove", icon='X', text="")
+
+ # Palette colors
+ row = layout.row()
+ col = row.column()
+ if len(palette.colors) >= 2:
+ color_rows = 5
+ else:
+ color_rows = 2
+ col.template_list("GPENCIL_UL_palettecolor", "", palette, "colors", palette.colors, "active_index",
+ rows=color_rows)
+
+ col = row.column()
+
+ sub = col.column(align=True)
+ sub.operator("gpencil.palettecolor_add", icon='ZOOMIN', text="")
+ sub.operator("gpencil.palettecolor_remove", icon='ZOOMOUT', text="")
+
+ palcol = context.active_gpencil_palettecolor
+ if palcol:
+ sub.menu("GPENCIL_MT_palettecolor_specials", icon='DOWNARROW_HLT', text="")
+
+ if len(palette.colors) > 1:
+ col.separator()
+
+ sub = col.column(align=True)
+ sub.operator("gpencil.palettecolor_move", icon='TRIA_UP', text="").direction = 'UP'
+ sub.operator("gpencil.palettecolor_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
+
+ row = layout.row()
+ sub = row.row(align=True)
+ sub.label(text="Isolate:") # based on active color only
+ sub.operator("gpencil.palettecolor_isolate", icon='LOCKED', text="").affect_visibility = False
+ sub.operator("gpencil.palettecolor_isolate", icon='RESTRICT_VIEW_OFF', text="").affect_visibility = True
+ sub = row.row(align=True)
+ sub.label(text="Lock:") # based on other stuff...
+ sub.operator("gpencil.stroke_lock_color", icon='BORDER_RECT', text="")
+ sub.operator("gpencil.palette_lock_layer", icon='COLOR', text="")
+
+ pcolor = palette.colors.active
+ if pcolor:
+ self.draw_palettecolors(layout, pcolor)
+
+ # Draw palette colors
+ def draw_palettecolors(self, layout, pcolor):
+ # color settings
+ split = layout.split(percentage=0.5)
+ split.active = not pcolor.lock
+
+ # Column 1 - Stroke
+ col = split.column(align=True)
+ col.enabled = not pcolor.lock
+ col.label(text="Stroke:")
+ col.prop(pcolor, "color", text="")
+ col.prop(pcolor, "alpha", slider=True)
+
+ # Column 2 - Fill
+ col = split.column(align=True)
+ col.enabled = not pcolor.lock
+ col.label(text="Fill:")
+ col.prop(pcolor, "fill_color", text="")
+ col.prop(pcolor, "fill_alpha", text="Opacity", slider=True)
+
+ # Options
+ split = layout.split(percentage=0.5)
+ split.active = not pcolor.lock
+
+ col = split.column(align=True)
+ col.active = not pcolor.lock
+ col.prop(pcolor, "use_volumetric_strokes")
+ col = split.column(align=True)
+ col.active = not pcolor.lock
+ col.prop(pcolor, "use_hq_fill")
class GreasePencilToolsPanel:
+ # For use in "2D" Editors without their own toolbar
# subclass must set
# bl_space_type = 'IMAGE_EDITOR'
# bl_options = {'DEFAULT_CLOSED'}
@@ -667,4 +1093,8 @@ class GreasePencilToolsPanel:
layout.separator()
layout.separator()
+ gpencil_active_brush_settings_simple(context, layout)
+
+ layout.separator()
+
gpencil_stroke_placement_settings(context, layout)
diff --git a/release/scripts/startup/bl_ui/properties_particle.py b/release/scripts/startup/bl_ui/properties_particle.py
index 08290f20a69..4e2666d7e40 100644
--- a/release/scripts/startup/bl_ui/properties_particle.py
+++ b/release/scripts/startup/bl_ui/properties_particle.py
@@ -79,6 +79,8 @@ class PARTICLE_MT_specials(Menu):
props.use_active = False
props.remove_target_particles = True
+ layout.operator("particle.duplicate_particle_system")
+
class PARTICLE_MT_hair_dynamics_presets(Menu):
bl_label = "Hair Dynamics Presets"
@@ -605,6 +607,8 @@ class PARTICLE_PT_physics(ParticleButtonsPanel, Panel):
row.prop(part, "use_size_deflect")
row.prop(part, "use_die_on_collision")
+ layout.prop(part, "collision_group")
+
if part.physics_type == 'FLUID':
fluid = part.fluid
@@ -714,6 +718,8 @@ class PARTICLE_PT_physics(ParticleButtonsPanel, Panel):
col.prop(boids, "land_personal_space")
col.prop(boids, "land_stick_force")
+ layout.prop(part, "collision_group")
+
split = layout.split()
col = split.column(align=True)
diff --git a/release/scripts/startup/bl_ui/properties_physics_cloth.py b/release/scripts/startup/bl_ui/properties_physics_cloth.py
index a5cbffb2e2c..3ebf2691b4c 100644
--- a/release/scripts/startup/bl_ui/properties_physics_cloth.py
+++ b/release/scripts/startup/bl_ui/properties_physics_cloth.py
@@ -46,11 +46,12 @@ class PhysicButtonsPanel:
def poll(cls, context):
ob = context.object
rd = context.scene.render
- return (ob and ob.type == 'MESH') and (not rd.use_game_engine) and (context.cloth)
+ return (ob and ob.type == 'MESH') and (rd.engine in cls.COMPAT_ENGINES) and (context.cloth)
class PHYSICS_PT_cloth(PhysicButtonsPanel, Panel):
bl_label = "Cloth"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw(self, context):
layout = self.layout
@@ -59,20 +60,29 @@ class PHYSICS_PT_cloth(PhysicButtonsPanel, Panel):
ob = context.object
cloth = md.settings
- split = layout.split()
-
- split.active = cloth_panel_enabled(md)
+ layout.active = cloth_panel_enabled(md)
- col = split.column()
+ split = layout.split(percentage=0.25)
- col.label(text="Presets:")
- sub = col.row(align=True)
+ split.label(text="Presets:")
+ sub = split.row(align=True)
sub.menu("CLOTH_MT_presets", text=bpy.types.CLOTH_MT_presets.bl_label)
sub.operator("cloth.preset_add", text="", icon='ZOOMIN')
sub.operator("cloth.preset_add", text="", icon='ZOOMOUT').remove_active = True
- col.label(text="Quality:")
- col.prop(cloth, "quality", text="Steps", slider=True)
+ split = layout.split(percentage=0.25)
+
+ split.label(text="Quality:")
+ split.prop(cloth, "quality", text="Steps")
+
+ split = layout.split(percentage=0.25)
+
+ split.label(text="Speed:")
+ split.prop(cloth, "time_scale", text="Multiplier")
+
+ split = layout.split()
+
+ col = split.column()
col.label(text="Material:")
col.prop(cloth, "mass")
@@ -86,7 +96,11 @@ class PHYSICS_PT_cloth(PhysicButtonsPanel, Panel):
col.prop(cloth, "air_damping", text="Air")
col.prop(cloth, "vel_damping", text="Velocity")
- col.prop(cloth, "use_pin_cloth", text="Pinning")
+ split = layout.split()
+
+ col = split.column()
+
+ col.prop(cloth, "use_pin_cloth", text="Pinning:")
sub = col.column()
sub.active = cloth.use_pin_cloth
sub.prop_search(cloth, "vertex_group_mass", ob, "vertex_groups", text="")
@@ -103,16 +117,23 @@ class PHYSICS_PT_cloth(PhysicButtonsPanel, Panel):
col.prop(cloth, "goal_friction", text="Friction")
"""
+ col = split.column()
+
+ col.prop(cloth, "use_dynamic_mesh", text="Dynamic Mesh")
+
key = ob.data.shape_keys
if key:
- col.label(text="Rest Shape Key:")
- col.prop_search(cloth, "rest_shape_key", key, "key_blocks", text="")
+ sub = col.column()
+ sub.active = not cloth.use_dynamic_mesh
+ sub.label(text="Rest Shape Key:")
+ sub.prop_search(cloth, "rest_shape_key", key, "key_blocks", text="")
class PHYSICS_PT_cloth_cache(PhysicButtonsPanel, Panel):
bl_label = "Cloth Cache"
bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw(self, context):
md = context.cloth
@@ -122,6 +143,7 @@ class PHYSICS_PT_cloth_cache(PhysicButtonsPanel, Panel):
class PHYSICS_PT_cloth_collision(PhysicButtonsPanel, Panel):
bl_label = "Cloth Collision"
bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw_header(self, context):
cloth = context.cloth.collision_settings
@@ -141,7 +163,7 @@ class PHYSICS_PT_cloth_collision(PhysicButtonsPanel, Panel):
split = layout.split()
col = split.column()
- col.prop(cloth, "collision_quality", slider=True, text="Quality")
+ col.prop(cloth, "collision_quality", text="Quality")
col.prop(cloth, "distance_min", slider=True, text="Distance")
col.prop(cloth, "repel_force", slider=True, text="Repel")
col.prop(cloth, "distance_repel", slider=True, text="Repel Distance")
@@ -151,7 +173,7 @@ class PHYSICS_PT_cloth_collision(PhysicButtonsPanel, Panel):
col.prop(cloth, "use_self_collision", text="Self Collision")
sub = col.column()
sub.active = cloth.use_self_collision
- sub.prop(cloth, "self_collision_quality", slider=True, text="Quality")
+ sub.prop(cloth, "self_collision_quality", text="Quality")
sub.prop(cloth, "self_distance_min", slider=True, text="Distance")
sub.prop_search(cloth, "vertex_group_self_collisions", ob, "vertex_groups", text="")
@@ -161,6 +183,7 @@ class PHYSICS_PT_cloth_collision(PhysicButtonsPanel, Panel):
class PHYSICS_PT_cloth_stiffness(PhysicButtonsPanel, Panel):
bl_label = "Cloth Stiffness Scaling"
bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw_header(self, context):
cloth = context.cloth.settings
@@ -193,6 +216,7 @@ class PHYSICS_PT_cloth_stiffness(PhysicButtonsPanel, Panel):
class PHYSICS_PT_cloth_sewing(PhysicButtonsPanel, Panel):
bl_label = "Cloth Sewing Springs"
bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw_header(self, context):
cloth = context.cloth.settings
@@ -226,6 +250,7 @@ class PHYSICS_PT_cloth_sewing(PhysicButtonsPanel, Panel):
class PHYSICS_PT_cloth_field_weights(PhysicButtonsPanel, Panel):
bl_label = "Cloth Field Weights"
bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw(self, context):
cloth = context.cloth.settings
diff --git a/release/scripts/startup/bl_ui/properties_physics_common.py b/release/scripts/startup/bl_ui/properties_physics_common.py
index 82eecf0fb5a..277b59d187d 100644
--- a/release/scripts/startup/bl_ui/properties_physics_common.py
+++ b/release/scripts/startup/bl_ui/properties_physics_common.py
@@ -31,7 +31,7 @@ class PhysicButtonsPanel:
@classmethod
def poll(cls, context):
rd = context.scene.render
- return (context.object) and (not rd.use_game_engine)
+ return (context.object) and rd.engine in cls.COMPAT_ENGINES
def physics_add(self, layout, md, name, type, typeicon, toggles):
@@ -57,6 +57,7 @@ def physics_add_special(self, layout, data, name, addop, removeop, typeicon):
class PHYSICS_PT_add(PhysicButtonsPanel, Panel):
bl_label = ""
bl_options = {'HIDE_HEADER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw(self, context):
obj = context.object
diff --git a/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py b/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py
index 269ffa6d371..6c3a3246cf6 100644
--- a/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py
+++ b/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py
@@ -56,11 +56,12 @@ class PhysicButtonsPanel:
def poll(cls, context):
ob = context.object
rd = context.scene.render
- return (ob and ob.type == 'MESH') and (not rd.use_game_engine) and context.dynamic_paint
+ return (ob and ob.type == 'MESH') and rd.engine in cls.COMPAT_ENGINES and context.dynamic_paint
class PHYSICS_PT_dynamic_paint(PhysicButtonsPanel, Panel):
bl_label = "Dynamic Paint"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw(self, context):
layout = self.layout
@@ -137,12 +138,13 @@ class PHYSICS_PT_dynamic_paint(PhysicButtonsPanel, Panel):
class PHYSICS_PT_dp_advanced_canvas(PhysicButtonsPanel, Panel):
bl_label = "Dynamic Paint Advanced"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
md = context.dynamic_paint
rd = context.scene.render
- return md and md.ui_type == 'CANVAS' and md.canvas_settings and md.canvas_settings.canvas_surfaces.active and (not rd.use_game_engine)
+ return md and md.ui_type == 'CANVAS' and md.canvas_settings and md.canvas_settings.canvas_surfaces.active and rd.engine in cls.COMPAT_ENGINES
def draw(self, context):
layout = self.layout
@@ -213,6 +215,7 @@ class PHYSICS_PT_dp_advanced_canvas(PhysicButtonsPanel, Panel):
class PHYSICS_PT_dp_canvas_output(PhysicButtonsPanel, Panel):
bl_label = "Dynamic Paint Output"
bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
@@ -223,7 +226,7 @@ class PHYSICS_PT_dp_canvas_output(PhysicButtonsPanel, Panel):
surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active
return (surface and
(not (surface.surface_format == 'VERTEX' and (surface.surface_type in {'DISPLACE', 'WAVE'}))) and
- (not rd.use_game_engine))
+ (rd.engine in cls.COMPAT_ENGINES))
def draw(self, context):
layout = self.layout
@@ -306,6 +309,7 @@ class PHYSICS_PT_dp_canvas_output(PhysicButtonsPanel, Panel):
class PHYSICS_PT_dp_canvas_initial_color(PhysicButtonsPanel, Panel):
bl_label = "Dynamic Paint Initial Color"
bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
@@ -314,7 +318,7 @@ class PHYSICS_PT_dp_canvas_initial_color(PhysicButtonsPanel, Panel):
if not (md and md.ui_type == 'CANVAS' and md.canvas_settings):
return 0
surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active
- return (surface and surface.surface_type == 'PAINT') and (not rd.use_game_engine)
+ return (surface and surface.surface_type == 'PAINT') and (rd.engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
@@ -342,6 +346,7 @@ class PHYSICS_PT_dp_canvas_initial_color(PhysicButtonsPanel, Panel):
class PHYSICS_PT_dp_effects(PhysicButtonsPanel, Panel):
bl_label = "Dynamic Paint Effects"
bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
@@ -350,7 +355,7 @@ class PHYSICS_PT_dp_effects(PhysicButtonsPanel, Panel):
if not (md and md.ui_type == 'CANVAS' and md.canvas_settings):
return False
surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active
- return (surface and surface.surface_type == 'PAINT') and (not rd.use_game_engine)
+ return (surface and surface.surface_type == 'PAINT') and (rd.engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
@@ -391,6 +396,7 @@ class PHYSICS_PT_dp_effects(PhysicButtonsPanel, Panel):
class PHYSICS_PT_dp_cache(PhysicButtonsPanel, Panel):
bl_label = "Dynamic Paint Cache"
bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
@@ -401,7 +407,7 @@ class PHYSICS_PT_dp_cache(PhysicButtonsPanel, Panel):
md.canvas_settings and
md.canvas_settings.canvas_surfaces.active and
md.canvas_settings.canvas_surfaces.active.is_cache_user and
- (not rd.use_game_engine))
+ (rd.engine in cls.COMPAT_ENGINES))
def draw(self, context):
surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active
@@ -412,12 +418,13 @@ class PHYSICS_PT_dp_cache(PhysicButtonsPanel, Panel):
class PHYSICS_PT_dp_brush_source(PhysicButtonsPanel, Panel):
bl_label = "Dynamic Paint Source"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
md = context.dynamic_paint
rd = context.scene.render
- return md and md.ui_type == 'BRUSH' and md.brush_settings and (not rd.use_game_engine)
+ return md and md.ui_type == 'BRUSH' and md.brush_settings and (rd.engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
@@ -465,12 +472,13 @@ class PHYSICS_PT_dp_brush_source(PhysicButtonsPanel, Panel):
class PHYSICS_PT_dp_brush_velocity(PhysicButtonsPanel, Panel):
bl_label = "Dynamic Paint Velocity"
bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
md = context.dynamic_paint
rd = context.scene.render
- return md and md.ui_type == 'BRUSH' and md.brush_settings and (not rd.use_game_engine)
+ return md and md.ui_type == 'BRUSH' and md.brush_settings and (rd.engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
@@ -501,12 +509,13 @@ class PHYSICS_PT_dp_brush_velocity(PhysicButtonsPanel, Panel):
class PHYSICS_PT_dp_brush_wave(PhysicButtonsPanel, Panel):
bl_label = "Dynamic Paint Waves"
bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
md = context.dynamic_paint
rd = context.scene.render
- return md and md.ui_type == 'BRUSH' and md.brush_settings and (not rd.use_game_engine)
+ return md and md.ui_type == 'BRUSH' and md.brush_settings and (rd.engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
diff --git a/release/scripts/startup/bl_ui/properties_physics_field.py b/release/scripts/startup/bl_ui/properties_physics_field.py
index 348f66da145..1cebc0496b0 100644
--- a/release/scripts/startup/bl_ui/properties_physics_field.py
+++ b/release/scripts/startup/bl_ui/properties_physics_field.py
@@ -34,17 +34,18 @@ class PhysicButtonsPanel:
@classmethod
def poll(cls, context):
rd = context.scene.render
- return (context.object) and (not rd.use_game_engine)
+ return (context.object) and (rd.engine in cls.COMPAT_ENGINES)
class PHYSICS_PT_field(PhysicButtonsPanel, Panel):
bl_label = "Force Fields"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
ob = context.object
rd = context.scene.render
- return (not rd.use_game_engine) and (ob.field) and (ob.field.type != 'NONE')
+ return (rd.engine in cls.COMPAT_ENGINES) and (ob.field) and (ob.field.type != 'NONE')
def draw(self, context):
layout = self.layout
@@ -176,12 +177,13 @@ class PHYSICS_PT_field(PhysicButtonsPanel, Panel):
class PHYSICS_PT_collision(PhysicButtonsPanel, Panel):
bl_label = "Collision"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
ob = context.object
rd = context.scene.render
- return (ob and ob.type == 'MESH') and (not rd.use_game_engine) and (context.collision)
+ return (ob and ob.type == 'MESH') and (rd.engine in cls.COMPAT_ENGINES) and (context.collision)
def draw(self, context):
layout = self.layout
diff --git a/release/scripts/startup/bl_ui/properties_physics_fluid.py b/release/scripts/startup/bl_ui/properties_physics_fluid.py
index d6fd8f3792c..5d7034c2e68 100644
--- a/release/scripts/startup/bl_ui/properties_physics_fluid.py
+++ b/release/scripts/startup/bl_ui/properties_physics_fluid.py
@@ -38,11 +38,12 @@ class PhysicButtonsPanel:
def poll(cls, context):
ob = context.object
rd = context.scene.render
- return (ob and ob.type == 'MESH') and (not rd.use_game_engine) and (context.fluid)
+ return (ob and ob.type == 'MESH') and rd.engine in cls.COMPAT_ENGINES and (context.fluid)
class PHYSICS_PT_fluid(PhysicButtonsPanel, Panel):
bl_label = "Fluid"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw(self, context):
layout = self.layout
@@ -205,12 +206,13 @@ class PHYSICS_PT_fluid(PhysicButtonsPanel, Panel):
class PHYSICS_PT_domain_gravity(PhysicButtonsPanel, Panel):
bl_label = "Fluid World"
bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
md = context.fluid
rd = context.scene.render
- return md and md.settings and (md.settings.type == 'DOMAIN') and (not rd.use_game_engine)
+ return md and md.settings and (md.settings.type == 'DOMAIN') and rd.engine in cls.COMPAT_ENGINES
def draw(self, context):
layout = self.layout
@@ -258,12 +260,13 @@ class PHYSICS_PT_domain_gravity(PhysicButtonsPanel, Panel):
class PHYSICS_PT_domain_boundary(PhysicButtonsPanel, Panel):
bl_label = "Fluid Boundary"
bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
md = context.fluid
rd = context.scene.render
- return md and md.settings and (md.settings.type == 'DOMAIN') and (not rd.use_game_engine)
+ return md and md.settings and (md.settings.type == 'DOMAIN') and rd.engine in cls.COMPAT_ENGINES
def draw(self, context):
layout = self.layout
@@ -288,12 +291,13 @@ class PHYSICS_PT_domain_boundary(PhysicButtonsPanel, Panel):
class PHYSICS_PT_domain_particles(PhysicButtonsPanel, Panel):
bl_label = "Fluid Particles"
bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
md = context.fluid
rd = context.scene.render
- return md and md.settings and (md.settings.type == 'DOMAIN') and (not rd.use_game_engine)
+ return md and md.settings and (md.settings.type == 'DOMAIN') and rd.engine in cls.COMPAT_ENGINES
def draw(self, context):
layout = self.layout
diff --git a/release/scripts/startup/bl_ui/properties_physics_rigidbody.py b/release/scripts/startup/bl_ui/properties_physics_rigidbody.py
index e7225d73e41..eeb21c046bf 100644
--- a/release/scripts/startup/bl_ui/properties_physics_rigidbody.py
+++ b/release/scripts/startup/bl_ui/properties_physics_rigidbody.py
@@ -29,12 +29,13 @@ class PHYSICS_PT_rigidbody_panel:
class PHYSICS_PT_rigid_body(PHYSICS_PT_rigidbody_panel, Panel):
bl_label = "Rigid Body"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
obj = context.object
return (obj and obj.rigid_body and
- (not context.scene.render.use_game_engine))
+ (context.scene.render.engine in cls.COMPAT_ENGINES))
def draw(self, context):
layout = self.layout
@@ -55,12 +56,13 @@ class PHYSICS_PT_rigid_body(PHYSICS_PT_rigidbody_panel, Panel):
class PHYSICS_PT_rigid_body_collisions(PHYSICS_PT_rigidbody_panel, Panel):
bl_label = "Rigid Body Collisions"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
obj = context.object
return (obj and obj.rigid_body and
- (not context.scene.render.use_game_engine))
+ (context.scene.render.engine in cls.COMPAT_ENGINES))
def draw(self, context):
layout = self.layout
@@ -99,13 +101,14 @@ class PHYSICS_PT_rigid_body_collisions(PHYSICS_PT_rigidbody_panel, Panel):
class PHYSICS_PT_rigid_body_dynamics(PHYSICS_PT_rigidbody_panel, Panel):
bl_label = "Rigid Body Dynamics"
bl_default_closed = True
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
obj = context.object
return (obj and obj.rigid_body and
obj.rigid_body.type == 'ACTIVE' and
- (not context.scene.render.use_game_engine))
+ (context.scene.render.engine in cls.COMPAT_ENGINES))
def draw(self, context):
layout = self.layout
diff --git a/release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py b/release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py
index 3f5e0f1fc9b..38c97746f4a 100644
--- a/release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py
+++ b/release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py
@@ -29,12 +29,13 @@ class PHYSICS_PT_rigidbody_constraint_panel:
class PHYSICS_PT_rigid_body_constraint(PHYSICS_PT_rigidbody_constraint_panel, Panel):
bl_label = "Rigid Body Constraint"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
ob = context.object
rd = context.scene.render
- return (ob and ob.rigid_body_constraint and (not rd.use_game_engine))
+ return (ob and ob.rigid_body_constraint and rd.engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
diff --git a/release/scripts/startup/bl_ui/properties_physics_smoke.py b/release/scripts/startup/bl_ui/properties_physics_smoke.py
index ef7d25e0a42..df03f23a4b5 100644
--- a/release/scripts/startup/bl_ui/properties_physics_smoke.py
+++ b/release/scripts/startup/bl_ui/properties_physics_smoke.py
@@ -35,11 +35,12 @@ class PhysicButtonsPanel:
def poll(cls, context):
ob = context.object
rd = context.scene.render
- return (ob and ob.type == 'MESH') and (not rd.use_game_engine) and (context.smoke)
+ return (ob and ob.type == 'MESH') and (rd.engine in cls.COMPAT_ENGINES) and (context.smoke)
class PHYSICS_PT_smoke(PhysicButtonsPanel, Panel):
bl_label = "Smoke"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw(self, context):
layout = self.layout
@@ -131,6 +132,7 @@ class PHYSICS_PT_smoke(PhysicButtonsPanel, Panel):
class PHYSICS_PT_smoke_flow_advanced(PhysicButtonsPanel, Panel):
bl_label = "Smoke Flow Advanced"
bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
@@ -165,6 +167,7 @@ class PHYSICS_PT_smoke_flow_advanced(PhysicButtonsPanel, Panel):
class PHYSICS_PT_smoke_fire(PhysicButtonsPanel, Panel):
bl_label = "Smoke Flames"
bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
@@ -194,6 +197,7 @@ class PHYSICS_PT_smoke_fire(PhysicButtonsPanel, Panel):
class PHYSICS_PT_smoke_adaptive_domain(PhysicButtonsPanel, Panel):
bl_label = "Smoke Adaptive Domain"
bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
@@ -227,12 +231,13 @@ class PHYSICS_PT_smoke_adaptive_domain(PhysicButtonsPanel, Panel):
class PHYSICS_PT_smoke_highres(PhysicButtonsPanel, Panel):
bl_label = "Smoke High Resolution"
bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
md = context.smoke
rd = context.scene.render
- return md and (md.smoke_type == 'DOMAIN') and (not rd.use_game_engine)
+ return md and (md.smoke_type == 'DOMAIN') and (rd.engine in cls.COMPAT_ENGINES)
def draw_header(self, context):
md = context.smoke.domain_settings
@@ -266,12 +271,13 @@ class PHYSICS_PT_smoke_highres(PhysicButtonsPanel, Panel):
class PHYSICS_PT_smoke_groups(PhysicButtonsPanel, Panel):
bl_label = "Smoke Groups"
bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
md = context.smoke
rd = context.scene.render
- return md and (md.smoke_type == 'DOMAIN') and (not rd.use_game_engine)
+ return md and (md.smoke_type == 'DOMAIN') and (rd.engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
@@ -294,12 +300,13 @@ class PHYSICS_PT_smoke_groups(PhysicButtonsPanel, Panel):
class PHYSICS_PT_smoke_cache(PhysicButtonsPanel, Panel):
bl_label = "Smoke Cache"
bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
md = context.smoke
rd = context.scene.render
- return md and (md.smoke_type == 'DOMAIN') and (not rd.use_game_engine)
+ return md and (md.smoke_type == 'DOMAIN') and (rd.engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
@@ -330,16 +337,66 @@ class PHYSICS_PT_smoke_cache(PhysicButtonsPanel, Panel):
class PHYSICS_PT_smoke_field_weights(PhysicButtonsPanel, Panel):
bl_label = "Smoke Field Weights"
bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
md = context.smoke
rd = context.scene.render
- return md and (md.smoke_type == 'DOMAIN') and (not rd.use_game_engine)
+ return md and (md.smoke_type == 'DOMAIN') and (rd.engine in cls.COMPAT_ENGINES)
def draw(self, context):
domain = context.smoke.domain_settings
effector_weights_ui(self, context, domain.effector_weights, 'SMOKE')
+
+class PHYSICS_PT_smoke_display_settings(PhysicButtonsPanel, Panel):
+ bl_label = "Smoke Display Settings"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ md = context.smoke
+ rd = context.scene.render
+ return md and (md.smoke_type == 'DOMAIN') and (not rd.use_game_engine)
+
+ def draw(self, context):
+ domain = context.smoke.domain_settings
+ layout = self.layout
+
+ layout.prop(domain, "display_thickness")
+
+ layout.separator()
+ layout.label(text="Slicing:")
+ layout.prop(domain, "slice_method")
+
+ slice_method = domain.slice_method
+ axis_slice_method = domain.axis_slice_method
+
+ do_axis_slicing = (slice_method == 'AXIS_ALIGNED')
+ do_full_slicing = (axis_slice_method == 'FULL')
+
+ row = layout.row();
+ row.enabled = do_axis_slicing
+ row.prop(domain, "axis_slice_method")
+
+ col = layout.column();
+ col.enabled = not do_full_slicing and do_axis_slicing
+ col.prop(domain, "slice_axis")
+ col.prop(domain, "slice_depth")
+
+ row = layout.row();
+ row.enabled = do_full_slicing or not do_axis_slicing
+ row.prop(domain, "slice_per_voxel")
+
+ layout.separator()
+ layout.label(text="Debug:")
+ layout.prop(domain, "draw_velocity")
+ col = layout.column();
+ col.enabled = domain.draw_velocity
+ col.prop(domain, "vector_draw_type")
+ col.prop(domain, "vector_scale")
+
+
if __name__ == "__main__": # only for live edit.
bpy.utils.register_module(__name__)
diff --git a/release/scripts/startup/bl_ui/properties_physics_softbody.py b/release/scripts/startup/bl_ui/properties_physics_softbody.py
index e74cac3d06b..a458af739f2 100644
--- a/release/scripts/startup/bl_ui/properties_physics_softbody.py
+++ b/release/scripts/startup/bl_ui/properties_physics_softbody.py
@@ -39,11 +39,12 @@ class PhysicButtonsPanel:
def poll(cls, context):
ob = context.object
rd = context.scene.render
- return (ob and (ob.type == 'MESH' or ob.type == 'LATTICE'or ob.type == 'CURVE')) and (not rd.use_game_engine) and (context.soft_body)
+ return (ob and (ob.type == 'MESH' or ob.type == 'LATTICE'or ob.type == 'CURVE')) and (rd.engine in cls.COMPAT_ENGINES) and (context.soft_body)
class PHYSICS_PT_softbody(PhysicButtonsPanel, Panel):
bl_label = "Soft Body"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw(self, context):
layout = self.layout
@@ -67,10 +68,13 @@ class PHYSICS_PT_softbody(PhysicButtonsPanel, Panel):
col.label(text="Simulation:")
col.prop(softbody, "speed")
+ layout.prop(softbody, "collision_group")
+
class PHYSICS_PT_softbody_cache(PhysicButtonsPanel, Panel):
bl_label = "Soft Body Cache"
bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw(self, context):
md = context.soft_body
@@ -80,6 +84,7 @@ class PHYSICS_PT_softbody_cache(PhysicButtonsPanel, Panel):
class PHYSICS_PT_softbody_goal(PhysicButtonsPanel, Panel):
bl_label = "Soft Body Goal"
bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw_header(self, context):
softbody = context.soft_body.settings
@@ -119,6 +124,7 @@ class PHYSICS_PT_softbody_goal(PhysicButtonsPanel, Panel):
class PHYSICS_PT_softbody_edge(PhysicButtonsPanel, Panel):
bl_label = "Soft Body Edges"
bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw_header(self, context):
softbody = context.soft_body.settings
@@ -168,6 +174,7 @@ class PHYSICS_PT_softbody_edge(PhysicButtonsPanel, Panel):
class PHYSICS_PT_softbody_collision(PhysicButtonsPanel, Panel):
bl_label = "Soft Body Self Collision"
bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw_header(self, context):
softbody = context.soft_body.settings
@@ -196,6 +203,7 @@ class PHYSICS_PT_softbody_collision(PhysicButtonsPanel, Panel):
class PHYSICS_PT_softbody_solver(PhysicButtonsPanel, Panel):
bl_label = "Soft Body Solver"
bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw(self, context):
layout = self.layout
@@ -228,6 +236,7 @@ class PHYSICS_PT_softbody_solver(PhysicButtonsPanel, Panel):
class PHYSICS_PT_softbody_field_weights(PhysicButtonsPanel, Panel):
bl_label = "Soft Body Field Weights"
bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw(self, context):
md = context.soft_body
diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py
index 6c4904939bf..850606eb80b 100644
--- a/release/scripts/startup/bl_ui/properties_render.py
+++ b/release/scripts/startup/bl_ui/properties_render.py
@@ -193,7 +193,6 @@ class RENDER_PT_antialiasing(RenderButtonsPanel, Panel):
col = split.column()
col.row().prop(rd, "antialiasing_samples", expand=True)
sub = col.row()
- sub.enabled = not rd.use_border
sub.prop(rd, "use_full_sample")
col = split.column()
@@ -248,6 +247,7 @@ class RENDER_PT_shading(RenderButtonsPanel, Panel):
col = split.column()
col.prop(rd, "use_raytrace", text="Ray Tracing")
col.prop(rd, "alpha_mode", text="Alpha")
+ col.prop(rd, "use_world_space_shading", text="World Space Shading")
class RENDER_PT_performance(RenderButtonsPanel, Panel):
@@ -279,7 +279,7 @@ class RENDER_PT_performance(RenderButtonsPanel, Panel):
col = split.column()
col.label(text="Memory:")
sub = col.column()
- sub.enabled = not (rd.use_border or rd.use_full_sample)
+ sub.enabled = not rd.use_full_sample
sub.prop(rd, "use_save_buffers")
sub = col.column()
sub.active = rd.use_compositing
@@ -345,7 +345,9 @@ class RENDER_PT_stamp(RenderButtonsPanel, Panel):
layout.prop(rd, "use_stamp")
col = layout.column()
col.active = rd.use_stamp
- col.prop(rd, "stamp_font_size", text="Font Size")
+ row = col.row()
+ row.prop(rd, "stamp_font_size", text="Font Size")
+ row.prop(rd, "use_stamp_labels", text="Draw labels")
row = col.row()
row.column().prop(rd, "stamp_foreground", slider=True)
@@ -360,6 +362,7 @@ class RENDER_PT_stamp(RenderButtonsPanel, Panel):
col.prop(rd, "use_stamp_render_time", text="RenderTime")
col.prop(rd, "use_stamp_frame", text="Frame")
col.prop(rd, "use_stamp_scene", text="Scene")
+ col.prop(rd, "use_stamp_memory", text="Memory")
col = split.column()
col.prop(rd, "use_stamp_camera", text="Camera")
@@ -458,31 +461,42 @@ class RENDER_PT_encoding(RenderButtonsPanel, Panel):
split = layout.split()
split.prop(rd.ffmpeg, "format")
- if ffmpeg.format in {'AVI', 'QUICKTIME', 'MKV', 'OGG', 'MPEG4'}:
- split.prop(ffmpeg, "codec")
- if ffmpeg.codec == 'H264':
- row = layout.row()
- row.label()
- row.prop(ffmpeg, "use_lossless_output")
- elif rd.ffmpeg.format == 'H264':
- split.prop(ffmpeg, "use_lossless_output")
- else:
- split.label()
+ split.prop(ffmpeg, "use_autosplit")
+
+ layout.separator()
+ needs_codec = ffmpeg.format in {'AVI', 'QUICKTIME', 'MKV', 'OGG', 'MPEG4'}
+ if needs_codec:
+ layout.prop(ffmpeg, "codec")
+
+ if ffmpeg.codec in {'DNXHD'}:
+ layout.prop(ffmpeg, "use_lossless_output")
+
+ # Output quality
+ if needs_codec and ffmpeg.codec in {'H264', 'MPEG4'}:
+ layout.prop(ffmpeg, "constant_rate_factor")
+
+ # Encoding speed
+ layout.prop(ffmpeg, "ffmpeg_preset")
+ # I-frames
+ layout.prop(ffmpeg, "gopsize")
+ # B-Frames
row = layout.row()
- row.prop(ffmpeg, "video_bitrate")
- row.prop(ffmpeg, "gopsize")
+ row.prop(ffmpeg, "use_max_b_frames", text='Max B-frames')
+ pbox = row.split()
+ pbox.prop(ffmpeg, "max_b_frames", text='')
+ pbox.enabled = ffmpeg.use_max_b_frames
split = layout.split()
-
+ split.enabled = ffmpeg.constant_rate_factor == 'NONE'
col = split.column()
col.label(text="Rate:")
+ col.prop(ffmpeg, "video_bitrate")
col.prop(ffmpeg, "minrate", text="Minimum")
col.prop(ffmpeg, "maxrate", text="Maximum")
col.prop(ffmpeg, "buffersize", text="Buffer")
col = split.column()
- col.prop(ffmpeg, "use_autosplit")
col.label(text="Mux:")
col.prop(ffmpeg, "muxrate", text="Rate")
col.prop(ffmpeg, "packetsize", text="Packet Size")
@@ -494,6 +508,7 @@ class RENDER_PT_encoding(RenderButtonsPanel, Panel):
layout.prop(ffmpeg, "audio_codec", text="Audio Codec")
row = layout.row()
+ row.enabled = ffmpeg.audio_codec != 'NONE'
row.prop(ffmpeg, "audio_bitrate")
row.prop(ffmpeg, "audio_volume", slider=True)
diff --git a/release/scripts/startup/bl_ui/properties_world.py b/release/scripts/startup/bl_ui/properties_world.py
index 2c8a6fac967..e07349a99ee 100644
--- a/release/scripts/startup/bl_ui/properties_world.py
+++ b/release/scripts/startup/bl_ui/properties_world.py
@@ -41,7 +41,7 @@ class WORLD_PT_context_world(WorldButtonsPanel, Panel):
@classmethod
def poll(cls, context):
rd = context.scene.render
- return (not rd.use_game_engine) and (rd.engine in cls.COMPAT_ENGINES)
+ return rd.engine in cls.COMPAT_ENGINES
def draw(self, context):
layout = self.layout
@@ -69,7 +69,7 @@ class WORLD_PT_preview(WorldButtonsPanel, Panel):
@classmethod
def poll(cls, context):
rd = context.scene.render
- return (context.world) and (not rd.use_game_engine) and (rd.engine in cls.COMPAT_ENGINES)
+ return (context.world) and (rd.engine in cls.COMPAT_ENGINES)
def draw(self, context):
self.layout.template_preview(context.world)
diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py
index e809ef9ffde..5cc135392c1 100644
--- a/release/scripts/startup/bl_ui/space_clip.py
+++ b/release/scripts/startup/bl_ui/space_clip.py
@@ -25,8 +25,10 @@ from bl_ui.properties_grease_pencil_common import (
GreasePencilDrawingToolsPanel,
GreasePencilStrokeEditPanel,
GreasePencilStrokeSculptPanel,
- GreasePencilDataPanel
- )
+ GreasePencilBrushPanel,
+ GreasePencilBrushCurvesPanel,
+ GreasePencilDataPanel,
+ GreasePencilPaletteColorPanel)
class CLIP_UL_tracking_objects(UIList):
@@ -619,6 +621,7 @@ class CLIP_PT_track(CLIP_PT_tracking_panel, Panel):
text="", toggle=True, icon='IMAGE_ALPHA')
layout.prop(act_track, "weight")
+ layout.prop(act_track, "weight_stab")
if act_track.has_bundle:
label_text = "Average Error: %.4f" % (act_track.average_error)
@@ -905,44 +908,78 @@ class CLIP_PT_stabilization(CLIP_PT_reconstruction_panel, Panel):
self.layout.prop(stab, "use_2d_stabilization", text="")
def draw(self, context):
- layout = self.layout
-
tracking = context.space_data.clip.tracking
stab = tracking.stabilization
+ layout = self.layout
layout.active = stab.use_2d_stabilization
- row = layout.row()
- row.template_list("UI_UL_list", "stabilization_tracks", stab, "tracks",
- stab, "active_track_index", rows=2)
+ layout.prop(stab, "anchor_frame")
- sub = row.column(align=True)
+ row = layout.row(align=True)
+ row.prop(stab, "use_stabilize_rotation", text="Rotation", toggle=True)
+ sub = row.row(align=True)
+ sub.active = stab.use_stabilize_rotation
+ sub.prop(stab, "use_stabilize_scale", text="Scale", toggle=True)
- sub.operator("clip.stabilize_2d_add", icon='ZOOMIN', text="")
- sub.operator("clip.stabilize_2d_remove", icon='ZOOMOUT', text="")
+ box = layout.box()
+ row = box.row(align=True)
+ row.prop(stab, "show_tracks_expanded", text="", emboss=False)
- sub.menu('CLIP_MT_stabilize_2d_specials', text="",
- icon='DOWNARROW_HLT')
+ if not stab.show_tracks_expanded:
+ row.label(text="Tracks For Stabilization")
+ else:
+ row.label(text="Tracks For Location")
+ row = box.row()
+ row.template_list("UI_UL_list", "stabilization_tracks", stab, "tracks",
+ stab, "active_track_index", rows=2)
- layout.prop(stab, "influence_location")
+ sub = row.column(align=True)
- layout.prop(stab, "use_autoscale")
- col = layout.column()
- col.active = stab.use_autoscale
- col.prop(stab, "scale_max")
- col.prop(stab, "influence_scale")
+ sub.operator("clip.stabilize_2d_add", icon='ZOOMIN', text="")
+ sub.operator("clip.stabilize_2d_remove", icon='ZOOMOUT', text="")
- layout.prop(stab, "use_stabilize_rotation")
- col = layout.column()
- col.active = stab.use_stabilize_rotation
+ sub.menu('CLIP_MT_stabilize_2d_specials', text="",
+ icon='DOWNARROW_HLT')
+
+ # Usually we don't hide things from iterface, but here every pixel of
+ # vertical space is precious.
+ if stab.use_stabilize_rotation:
+ box.label(text="Tracks For Rotation / Scale")
+ row = box.row()
+ row.template_list("UI_UL_list", "stabilization_rotation_tracks",
+ stab, "rotation_tracks",
+ stab, "active_rotation_track_index", rows=2)
+
+ sub = row.column(align=True)
+ sub.operator("clip.stabilize_2d_rotation_add", icon='ZOOMIN', text="")
+ sub.operator("clip.stabilize_2d_rotation_remove", icon='ZOOMOUT', text="")
+
+ sub.menu('CLIP_MT_stabilize_2d_rotation_specials', text="",
+ icon='DOWNARROW_HLT')
+
+ row = layout.row()
+ row.prop(stab, "use_autoscale")
+ sub = row.row()
+ sub.active = stab.use_autoscale
+ sub.prop(stab, "scale_max", text="Max")
+
+ col = layout.column(align=True)
row = col.row(align=True)
- row.prop_search(stab, "rotation_track", tracking, "tracks", text="")
- row.operator("clip.stabilize_2d_set_rotation", text="", icon='ZOOMIN')
+ # Hrm, how to make it more obvious label?
+ row.prop(stab, "target_position", text="")
+ col.prop(stab, "target_rotation")
+ row = col.row(align=True)
+ row.prop(stab, "target_scale")
+ row.active = not stab.use_autoscale
- row = col.row()
- row.active = stab.rotation_track is not None
- row.prop(stab, "influence_rotation")
+ col = layout.column(align=True)
+ col.prop(stab, "influence_location")
+ sub = col.column(align=True)
+ sub.active = stab.use_stabilize_rotation
+ sub.prop(stab, "influence_rotation")
+ sub.prop(stab, "influence_scale")
layout.prop(stab, "filter_type")
@@ -950,7 +987,7 @@ class CLIP_PT_stabilization(CLIP_PT_reconstruction_panel, Panel):
class CLIP_PT_proxy(CLIP_PT_clip_view_panel, Panel):
bl_space_type = 'CLIP_EDITOR'
bl_region_type = 'UI'
- bl_label = "Proxy / Timecode"
+ bl_label = "Proxy/Timecode"
bl_options = {'DEFAULT_CLOSED'}
def draw_header(self, context):
@@ -1126,6 +1163,16 @@ class CLIP_PT_grease_pencil(GreasePencilDataPanel, CLIP_PT_clip_view_panel, Pane
# But, this should only be visible in "clip" view
+# Grease Pencil palette colors
+class CLIP_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, CLIP_PT_clip_view_panel, Panel):
+ bl_space_type = 'CLIP_EDITOR'
+ bl_region_type = 'UI'
+ bl_options = {'DEFAULT_CLOSED'}
+
+ # NOTE: this is just a wrapper around the generic GP Panel
+ # But, this should only be visible in "clip" view
+
+
# Grease Pencil drawing tools
class CLIP_PT_tools_grease_pencil_draw(GreasePencilDrawingToolsPanel, Panel):
bl_space_type = 'CLIP_EDITOR'
@@ -1141,6 +1188,15 @@ class CLIP_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel):
bl_space_type = 'CLIP_EDITOR'
+# Grease Pencil drawing brushes
+class CLIP_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel):
+ bl_space_type = 'CLIP_EDITOR'
+
+
+# Grease Pencil drawing curves
+class CLIP_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel):
+ bl_space_type = 'CLIP_EDITOR'
+
class CLIP_MT_view(Menu):
bl_label = "View"
@@ -1186,8 +1242,8 @@ class CLIP_MT_view(Menu):
layout.separator()
layout.operator("screen.area_dupli")
- layout.operator("screen.screen_full_area", text="Toggle Maximize Area")
- layout.operator("screen.screen_full_area").use_hide_panels = True
+ layout.operator("screen.screen_full_area")
+ layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True
class CLIP_MT_clip(Menu):
@@ -1413,7 +1469,7 @@ class CLIP_MT_track_color_specials(Menu):
class CLIP_MT_stabilize_2d_specials(Menu):
- bl_label = "Track Color Specials"
+ bl_label = "Translation Track Specials"
def draw(self, context):
layout = self.layout
@@ -1421,5 +1477,14 @@ class CLIP_MT_stabilize_2d_specials(Menu):
layout.operator("clip.stabilize_2d_select")
+class CLIP_MT_stabilize_2d_rotation_specials(Menu):
+ bl_label = "Rotation Track Specials"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("clip.stabilize_2d_rotation_select")
+
+
if __name__ == "__main__": # only for live edit.
bpy.utils.register_module(__name__)
diff --git a/release/scripts/startup/bl_ui/space_console.py b/release/scripts/startup/bl_ui/space_console.py
index 327fb94cb95..4266abc5ad7 100644
--- a/release/scripts/startup/bl_ui/space_console.py
+++ b/release/scripts/startup/bl_ui/space_console.py
@@ -70,8 +70,8 @@ class CONSOLE_MT_console(Menu):
layout.separator()
layout.operator("screen.area_dupli")
- layout.operator("screen.screen_full_area", text="Toggle Maximize Area")
- layout.operator("screen.screen_full_area").use_hide_panels = True
+ layout.operator("screen.screen_full_area")
+ layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True
class CONSOLE_MT_language(Menu):
diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py
index 0eeba5be369..4d365c8dc08 100644
--- a/release/scripts/startup/bl_ui/space_dopesheet.py
+++ b/release/scripts/startup/bl_ui/space_dopesheet.py
@@ -101,6 +101,8 @@ def dopesheet_filter(layout, context, genericFiltersOnly=False):
if bpy.data.grease_pencil:
row.prop(dopesheet, "show_gpencil", text="")
+ layout.prop(dopesheet, "use_datablock_sort", text="")
+
#######################################
# DopeSheet Editor - General/Standard UI
@@ -232,8 +234,8 @@ class DOPESHEET_MT_view(Menu):
layout.separator()
layout.operator("screen.area_dupli")
- layout.operator("screen.screen_full_area", text="Toggle Maximize Area")
- layout.operator("screen.screen_full_area").use_hide_panels = True
+ layout.operator("screen.screen_full_area")
+ layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True
class DOPESHEET_MT_select(Menu):
@@ -250,6 +252,8 @@ class DOPESHEET_MT_select(Menu):
layout.operator("action.select_border").axis_range = False
layout.operator("action.select_border", text="Border Axis Range").axis_range = True
+ layout.operator("action.select_circle")
+
layout.separator()
layout.operator("action.select_column", text="Columns on Selected Keys").mode = 'KEYS'
layout.operator("action.select_column", text="Column on Current Frame").mode = 'CFRA'
diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py
index 82497f11bb1..446df9e6e79 100644
--- a/release/scripts/startup/bl_ui/space_graph.py
+++ b/release/scripts/startup/bl_ui/space_graph.py
@@ -129,8 +129,8 @@ class GRAPH_MT_view(Menu):
layout.separator()
layout.operator("screen.area_dupli")
- layout.operator("screen.screen_full_area", text="Toggle Maximize Area")
- layout.operator("screen.screen_full_area").use_hide_panels = True
+ layout.operator("screen.screen_full_area")
+ layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True
class GRAPH_MT_select(Menu):
@@ -154,6 +154,8 @@ class GRAPH_MT_select(Menu):
props.axis_range = False
props.include_handles = True
+ layout.operator("graph.select_circle")
+
layout.separator()
layout.operator("graph.select_column", text="Columns on Selected Keys").mode = 'KEYS'
layout.operator("graph.select_column", text="Column on Current Frame").mode = 'CFRA'
diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py
index fbea07a317e..b6087184518 100644
--- a/release/scripts/startup/bl_ui/space_image.py
+++ b/release/scripts/startup/bl_ui/space_image.py
@@ -29,7 +29,10 @@ from bl_ui.properties_grease_pencil_common import (
GreasePencilDrawingToolsPanel,
GreasePencilStrokeEditPanel,
GreasePencilStrokeSculptPanel,
+ GreasePencilBrushPanel,
+ GreasePencilBrushCurvesPanel,
GreasePencilDataPanel,
+ GreasePencilPaletteColorPanel
)
from bpy.app.translations import pgettext_iface as iface_
@@ -123,8 +126,8 @@ class IMAGE_MT_view(Menu):
layout.separator()
layout.operator("screen.area_dupli")
- layout.operator("screen.screen_full_area", text="Toggle Maximize Area")
- layout.operator("screen.screen_full_area").use_hide_panels = True
+ layout.operator("screen.screen_full_area")
+ layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True
class IMAGE_MT_select(Menu):
@@ -684,6 +687,12 @@ class IMAGE_PT_view_properties(Panel):
sub.active = uvedit.show_stretch
sub.row().prop(uvedit, "draw_stretch_type", expand=True)
+ col = layout.column()
+ col.prop(uvedit, "show_other_objects")
+ row = col.row()
+ row.active = uvedit.show_other_objects
+ row.prop(uvedit, "other_uv_filter", text="Filter")
+
if show_render and ima:
layout.separator()
render_slot = ima.render_slots.active
@@ -729,7 +738,6 @@ class IMAGE_PT_paint(Panel, ImagePaintPanel):
@classmethod
def poll(cls, context):
sima = context.space_data
- toolsettings = context.tool_settings.image_paint
return sima.show_paint
@@ -987,7 +995,7 @@ class IMAGE_PT_tools_paint_options(BrushButtonsPanel, Panel):
layout = self.layout
toolsettings = context.tool_settings
- brush = toolsettings.image_paint.brush
+ # brush = toolsettings.image_paint.brush
ups = toolsettings.unified_paint_settings
@@ -1188,6 +1196,14 @@ class IMAGE_PT_grease_pencil(GreasePencilDataPanel, Panel):
# NOTE: this is just a wrapper around the generic GP Panel
+# Grease Pencil palette colors
+class IMAGE_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, Panel):
+ bl_space_type = 'IMAGE_EDITOR'
+ bl_region_type = 'UI'
+
+ # NOTE: this is just a wrapper around the generic GP Panel
+
+
# Grease Pencil drawing tools
class IMAGE_PT_tools_grease_pencil_draw(GreasePencilDrawingToolsPanel, Panel):
bl_space_type = 'IMAGE_EDITOR'
@@ -1203,5 +1219,15 @@ class IMAGE_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel):
bl_space_type = 'IMAGE_EDITOR'
+# Grease Pencil drawing brushes
+class IMAGE_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel):
+ bl_space_type = 'IMAGE_EDITOR'
+
+
+# Grease Pencil drawing curves
+class IMAGE_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel):
+ bl_space_type = 'IMAGE_EDITOR'
+
+
if __name__ == "__main__": # only for live edit.
bpy.utils.register_module(__name__)
diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py
index 1e476b63b56..780dc4cf982 100644
--- a/release/scripts/startup/bl_ui/space_info.py
+++ b/release/scripts/startup/bl_ui/space_info.py
@@ -158,6 +158,8 @@ class INFO_MT_file_import(Menu):
def draw(self, context):
if bpy.app.build_options.collada:
self.layout.operator("wm.collada_import", text="Collada (Default) (.dae)")
+ if bpy.app.build_options.alembic:
+ self.layout.operator("wm.alembic_import", text="Alembic (.abc)")
class INFO_MT_file_export(Menu):
@@ -167,6 +169,8 @@ class INFO_MT_file_export(Menu):
def draw(self, context):
if bpy.app.build_options.collada:
self.layout.operator("wm.collada_export", text="Collada (Default) (.dae)")
+ if bpy.app.build_options.alembic:
+ self.layout.operator("wm.alembic_export", text="Alembic (.abc)")
class INFO_MT_file_external_data(Menu):
@@ -300,19 +304,36 @@ class INFO_MT_help(Menu):
def draw(self, context):
layout = self.layout
- layout.operator("wm.url_open", text="Manual", icon='HELP').url = "https://www.blender.org/manual"
- layout.operator("wm.url_open", text="Release Log", icon='URL').url = "http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/%d.%d" % bpy.app.version[:2]
+ layout.operator(
+ "wm.url_open", text="Manual", icon='HELP',
+ ).url = "https://www.blender.org/manual"
+ layout.operator(
+ "wm.url_open", text="Release Log", icon='URL',
+ ).url = "http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/%d.%d" % bpy.app.version[:2]
layout.separator()
- layout.operator("wm.url_open", text="Blender Website", icon='URL').url = "https://www.blender.org"
- layout.operator("wm.url_open", text="Blender Store", icon='URL').url = "https://store.blender.org"
- layout.operator("wm.url_open", text="Developer Community", icon='URL').url = "https://www.blender.org/get-involved/"
- layout.operator("wm.url_open", text="User Community", icon='URL').url = "https://www.blender.org/support/user-community"
+ layout.operator(
+ "wm.url_open", text="Blender Website", icon='URL',
+ ).url = "https://www.blender.org"
+ layout.operator(
+ "wm.url_open", text="Blender Store", icon='URL',
+ ).url = "https://store.blender.org"
+ layout.operator(
+ "wm.url_open", text="Developer Community", icon='URL',
+ ).url = "https://www.blender.org/get-involved/"
+ layout.operator(
+ "wm.url_open", text="User Community", icon='URL',
+ ).url = "https://www.blender.org/support/user-community"
layout.separator()
- layout.operator("wm.url_open", text="Report a Bug", icon='URL').url = "https://developer.blender.org/maniphest/task/create/?project=2&type=Bug"
+ layout.operator(
+ "wm.url_open", text="Report a Bug", icon='URL',
+ ).url = "https://developer.blender.org/maniphest/task/edit/form/1"
layout.separator()
- layout.operator("wm.url_open", text="Python API Reference", icon='URL').url = bpy.types.WM_OT_doc_view._prefix
+ layout.operator(
+ "wm.url_open", text="Python API Reference", icon='URL',
+ ).url = bpy.types.WM_OT_doc_view._prefix
+
layout.operator("wm.operator_cheat_sheet", icon='TEXT')
layout.operator("wm.sysinfo", icon='TEXT')
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_logic.py b/release/scripts/startup/bl_ui/space_logic.py
index 48b54feba17..1b316a3eede 100644
--- a/release/scripts/startup/bl_ui/space_logic.py
+++ b/release/scripts/startup/bl_ui/space_logic.py
@@ -127,8 +127,8 @@ class LOGIC_MT_view(Menu):
layout.separator()
layout.operator("screen.area_dupli")
- layout.operator("screen.screen_full_area", text="Toggle Maximize Area")
- layout.operator("screen.screen_full_area").use_hide_panels = True
+ layout.operator("screen.screen_full_area")
+ layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True
if __name__ == "__main__": # only for live edit.
bpy.utils.register_module(__name__)
diff --git a/release/scripts/startup/bl_ui/space_nla.py b/release/scripts/startup/bl_ui/space_nla.py
index 64d3b427260..8fbf9bfc6ac 100644
--- a/release/scripts/startup/bl_ui/space_nla.py
+++ b/release/scripts/startup/bl_ui/space_nla.py
@@ -77,6 +77,7 @@ class NLA_MT_view(Menu):
layout.prop(st, "show_locked_time")
layout.prop(st, "show_strip_curves")
+ layout.prop(st, "show_local_markers")
layout.separator()
layout.operator("anim.previewrange_set")
@@ -90,8 +91,8 @@ class NLA_MT_view(Menu):
layout.separator()
layout.operator("screen.area_dupli")
- layout.operator("screen.screen_full_area", text="Toggle Maximize Area")
- layout.operator("screen.screen_full_area").use_hide_panels = True
+ layout.operator("screen.screen_full_area")
+ layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True
class NLA_MT_select(Menu):
diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py
index 986edc7405b..8821fa0ca58 100644
--- a/release/scripts/startup/bl_ui/space_node.py
+++ b/release/scripts/startup/bl_ui/space_node.py
@@ -25,8 +25,11 @@ from bl_ui.properties_grease_pencil_common import (
GreasePencilDrawingToolsPanel,
GreasePencilStrokeEditPanel,
GreasePencilStrokeSculptPanel,
+ GreasePencilBrushPanel,
+ GreasePencilBrushCurvesPanel,
GreasePencilDataPanel,
- GreasePencilToolsPanel,
+ GreasePencilPaletteColorPanel,
+ GreasePencilToolsPanel
)
@@ -192,8 +195,8 @@ class NODE_MT_view(Menu):
layout.separator()
layout.operator("screen.area_dupli")
- layout.operator("screen.screen_full_area", text="Toggle Maximize Area")
- layout.operator("screen.screen_full_area").use_hide_panels = True
+ layout.operator("screen.screen_full_area")
+ layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True
class NODE_MT_select(Menu):
@@ -464,6 +467,19 @@ class NODE_PT_grease_pencil(GreasePencilDataPanel, Panel):
return snode is not None and snode.node_tree is not None
+# Grease Pencil palette colors
+class NODE_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, Panel):
+ bl_space_type = 'NODE_EDITOR'
+ bl_region_type = 'UI'
+
+ # NOTE: this is just a wrapper around the generic GP Panel
+
+ @classmethod
+ def poll(cls, context):
+ snode = context.space_data
+ return snode is not None and snode.node_tree is not None
+
+
class NODE_PT_grease_pencil_tools(GreasePencilToolsPanel, Panel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'UI'
@@ -494,6 +510,16 @@ class NODE_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'TOOLS'
+# Grease Pencil drawing brushes
+class NODE_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel):
+ bl_space_type = 'NODE_EDITOR'
+ bl_region_type = 'TOOLS'
+
+# Grease Pencil drawing curves
+class NODE_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel):
+ bl_space_type = 'NODE_EDITOR'
+ bl_region_type = 'TOOLS'
+
# -----------------------------
diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py
index 7b1dfb9579a..708db2eec8d 100644
--- a/release/scripts/startup/bl_ui/space_outliner.py
+++ b/release/scripts/startup/bl_ui/space_outliner.py
@@ -99,8 +99,8 @@ class OUTLINER_MT_view(Menu):
layout.separator()
layout.operator("screen.area_dupli")
- layout.operator("screen.screen_full_area", text="Toggle Maximize Area")
- layout.operator("screen.screen_full_area").use_hide_panels = True
+ layout.operator("screen.screen_full_area")
+ layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True
class OUTLINER_MT_search(Menu):
diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py
index 65fd0a43619..26136a8e024 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -20,7 +20,11 @@
import bpy
from bpy.types import Header, Menu, Panel
from rna_prop_ui import PropertyPanel
-from bl_ui.properties_grease_pencil_common import GreasePencilDataPanel, GreasePencilToolsPanel
+from bl_ui.properties_grease_pencil_common import (
+ GreasePencilDataPanel,
+ GreasePencilPaletteColorPanel,
+ GreasePencilToolsPanel,
+ )
from bpy.app.translations import pgettext_iface as iface_
@@ -221,8 +225,8 @@ class SEQUENCER_MT_view(Menu):
layout.separator()
layout.operator("screen.area_dupli")
- layout.operator("screen.screen_full_area", text="Toggle Maximize Area")
- layout.operator("screen.screen_full_area").use_hide_panels = True
+ layout.operator("screen.screen_full_area")
+ layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True
class SEQUENCER_MT_select(Menu):
@@ -972,7 +976,7 @@ class SEQUENCER_PT_filter(SequencerButtonsPanel, Panel):
class SEQUENCER_PT_proxy(SequencerButtonsPanel, Panel):
- bl_label = "Proxy / Timecode"
+ bl_label = "Proxy/Timecode"
@classmethod
def poll(cls, context):
@@ -1186,6 +1190,14 @@ class SEQUENCER_PT_grease_pencil(GreasePencilDataPanel, SequencerButtonsPanel_Ou
# But, it should only show up when there are images in the preview region
+class SEQUENCER_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, SequencerButtonsPanel_Output, Panel):
+ bl_space_type = 'SEQUENCE_EDITOR'
+ bl_region_type = 'UI'
+
+ # NOTE: this is just a wrapper around the generic GP Panel
+ # But, it should only show up when there are images in the preview region
+
+
class SEQUENCER_PT_grease_pencil_tools(GreasePencilToolsPanel, SequencerButtonsPanel_Output, Panel):
bl_space_type = 'SEQUENCE_EDITOR'
bl_region_type = 'UI'
diff --git a/release/scripts/startup/bl_ui/space_text.py b/release/scripts/startup/bl_ui/space_text.py
index 5eb4e333130..1fd10575e07 100644
--- a/release/scripts/startup/bl_ui/space_text.py
+++ b/release/scripts/startup/bl_ui/space_text.py
@@ -181,8 +181,8 @@ class TEXT_MT_view(Menu):
layout.separator()
layout.operator("screen.area_dupli")
- layout.operator("screen.screen_full_area", text="Toggle Maximize Area")
- layout.operator("screen.screen_full_area").use_hide_panels = True
+ layout.operator("screen.screen_full_area")
+ layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True
class TEXT_MT_text(Menu):
diff --git a/release/scripts/startup/bl_ui/space_time.py b/release/scripts/startup/bl_ui/space_time.py
index 5b0075b4147..508e62e4f56 100644
--- a/release/scripts/startup/bl_ui/space_time.py
+++ b/release/scripts/startup/bl_ui/space_time.py
@@ -152,8 +152,8 @@ class TIME_MT_view(Menu):
layout.separator()
layout.operator("screen.area_dupli")
- layout.operator("screen.screen_full_area", text="Toggle Maximize Area")
- layout.operator("screen.screen_full_area").use_hide_panels = True
+ layout.operator("screen.screen_full_area")
+ layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True
class TIME_MT_cache(Menu):
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index dc46aed08c0..dcafac66fca 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -489,7 +489,7 @@ class USERPREF_PT_system(Panel):
col.separator()
- col.label(text="Sequencer / Clip Editor:")
+ col.label(text="Sequencer/Clip Editor:")
# currently disabled in the code
# col.prop(system, "prefetch_frames")
col.prop(system, "memory_cache_limit")
@@ -1177,15 +1177,16 @@ class USERPREF_PT_input(Panel):
sub.prop(walk, "view_height")
sub.prop(walk, "jump_height")
- col.separator()
- col.label(text="NDOF Device:")
- sub = col.column(align=True)
- sub.prop(inputs, "ndof_sensitivity", text="NDOF Sensitivity")
- sub.prop(inputs, "ndof_orbit_sensitivity", text="NDOF Orbit Sensitivity")
- sub.prop(inputs, "ndof_deadzone", text="NDOF Deadzone")
- sub = col.column(align=True)
- sub.row().prop(inputs, "ndof_view_navigate_method", expand=True)
- sub.row().prop(inputs, "ndof_view_rotate_method", expand=True)
+ if inputs.use_ndof:
+ col.separator()
+ col.label(text="NDOF Device:")
+ sub = col.column(align=True)
+ sub.prop(inputs, "ndof_sensitivity", text="NDOF Sensitivity")
+ sub.prop(inputs, "ndof_orbit_sensitivity", text="NDOF Orbit Sensitivity")
+ sub.prop(inputs, "ndof_deadzone", text="NDOF Deadzone")
+ sub = col.column(align=True)
+ sub.row().prop(inputs, "ndof_view_navigate_method", expand=True)
+ sub.row().prop(inputs, "ndof_view_rotate_method", expand=True)
row.separator()
@@ -1416,7 +1417,7 @@ class USERPREF_PT_addons(Panel):
split.operator("wm.url_open", text="Documentation", icon='HELP').url = info["wiki_url"]
split.operator("wm.url_open", text="Report a Bug", icon='URL').url = info.get(
"tracker_url",
- "http://developer.blender.org/maniphest/task/create/?project=3&type=Bug")
+ "https://developer.blender.org/maniphest/task/edit/form/2")
if user_addon:
split.operator("wm.addon_remove", text="Remove", icon='CANCEL').module = mod.__name__
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 2b92f20dcf6..8a3a5d3b7e8 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -19,7 +19,10 @@
# <pep8 compliant>
import bpy
from bpy.types import Header, Menu, Panel
-from bl_ui.properties_grease_pencil_common import GreasePencilDataPanel
+from bl_ui.properties_grease_pencil_common import (
+ GreasePencilDataPanel,
+ GreasePencilPaletteColorPanel,
+ )
from bl_ui.properties_paint_common import UnifiedPaintPanel
from bpy.app.translations import contexts as i18n_contexts
@@ -37,7 +40,6 @@ class VIEW3D_HT_header(Header):
row = layout.row(align=True)
row.template_header()
- sub = row.row(align=True)
VIEW3D_MT_editor_menus.draw_collapsible(context, layout)
@@ -81,7 +83,20 @@ class VIEW3D_HT_header(Header):
row.prop(toolsettings, "proportional_edit_falloff", icon_only=True)
# Snap
- if not obj or mode not in {'SCULPT', 'VERTEX_PAINT', 'WEIGHT_PAINT', 'TEXTURE_PAINT'}:
+ show_snap = False
+ if obj is None:
+ show_snap = True
+ else:
+ if mode not in {'SCULPT', 'VERTEX_PAINT', 'WEIGHT_PAINT', 'TEXTURE_PAINT'}:
+ show_snap = True
+ else:
+ paint_settings = UnifiedPaintPanel.paint_settings(context)
+ if paint_settings:
+ brush = paint_settings.brush
+ if brush and brush.stroke_method == 'CURVE':
+ show_snap = True
+
+ if show_snap:
snap_element = toolsettings.snap_element
row = layout.row(align=True)
row.prop(toolsettings, "use_snap", text="")
@@ -91,10 +106,10 @@ class VIEW3D_HT_header(Header):
else:
row.prop(toolsettings, "snap_target", text="")
if obj:
- if mode in {'OBJECT', 'POSE'} and snap_element != 'VOLUME':
- row.prop(toolsettings, "use_snap_align_rotation", text="")
- elif mode == 'EDIT':
+ if mode == 'EDIT':
row.prop(toolsettings, "use_snap_self", text="")
+ if mode in {'OBJECT', 'POSE', 'EDIT'} and snap_element != 'VOLUME':
+ row.prop(toolsettings, "use_snap_align_rotation", text="")
if snap_element == 'VOLUME':
row.prop(toolsettings, "use_snap_peel_object", text="")
@@ -124,11 +139,12 @@ class VIEW3D_HT_header(Header):
row.operator("gpencil.copy", text="", icon='COPYDOWN')
row.operator("gpencil.paste", text="", icon='PASTEDOWN')
- layout.prop(context.gpencil_data, "use_onion_skinning", text="Onion Skins", icon='PARTICLE_PATH') # XXX: icon
-
- layout.prop(context.tool_settings.gpencil_sculpt, "use_select_mask")
-
+ # XXX: icon
+ layout.prop(context.gpencil_data, "use_onion_skinning", text="Onion Skins", icon='PARTICLE_PATH')
+ row = layout.row(align=True)
+ row.prop(context.tool_settings.gpencil_sculpt, "use_select_mask")
+ row.prop(context.tool_settings.gpencil_sculpt, "selection_alpha", slider=True)
class VIEW3D_MT_editor_menus(Menu):
@@ -283,10 +299,6 @@ class VIEW3D_MT_transform_object(VIEW3D_MT_transform_base):
layout.operator("object.randomize_transform")
layout.operator("object.align")
- layout.separator()
-
- layout.operator("object.anim_transforms_to_deltas")
-
# Armature EditMode extensions to Transform menu
class VIEW3D_MT_transform_armature(VIEW3D_MT_transform_base):
@@ -358,6 +370,7 @@ class VIEW3D_MT_snap(Menu):
layout.operator("view3d.snap_selected_to_grid", text="Selection to Grid")
layout.operator("view3d.snap_selected_to_cursor", text="Selection to Cursor").use_offset = False
layout.operator("view3d.snap_selected_to_cursor", text="Selection to Cursor (Offset)").use_offset = True
+ layout.operator("view3d.snap_selected_to_active", text="Selection to Active")
layout.separator()
@@ -398,6 +411,20 @@ class VIEW3D_MT_uv_map(Menu):
layout.operator("uv.reset")
+class VIEW3D_MT_edit_proportional(Menu):
+ bl_label = "Proportional Editing"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.props_enum(context.tool_settings, "proportional_edit")
+
+ layout.separator()
+
+ layout.label("Falloff:")
+ layout.props_enum(context.tool_settings, "proportional_edit_falloff")
+
+
# ********** View menus **********
@@ -458,8 +485,8 @@ class VIEW3D_MT_view(Menu):
layout.operator("screen.area_dupli")
layout.operator("screen.region_quadview")
- layout.operator("screen.screen_full_area", text="Toggle Maximize Area")
- layout.operator("screen.screen_full_area").use_hide_panels = True
+ layout.operator("screen.screen_full_area")
+ layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True
class VIEW3D_MT_view_navigation(Menu):
@@ -987,8 +1014,7 @@ class VIEW3D_MT_select_gpencil(Menu):
layout.operator("gpencil.select_all", text="(De)select All").action = 'TOGGLE'
layout.operator("gpencil.select_all", text="Inverse").action = 'INVERT'
layout.operator("gpencil.select_linked", text="Linked")
- #layout.operator_menu_enum("gpencil.select_grouped", "type", text="Grouped")
- layout.operator("gpencil.select_grouped", text="Grouped")
+ layout.operator_menu_enum("gpencil.select_grouped", "type", text="Grouped")
layout.separator()
@@ -1496,6 +1522,15 @@ class VIEW3D_MT_object_apply(Menu):
layout.separator()
+ layout.operator("object.transforms_to_deltas", text="Location to Deltas", text_ctxt=i18n_contexts.default).mode = 'LOC'
+ layout.operator("object.transforms_to_deltas", text="Rotation to Deltas", text_ctxt=i18n_contexts.default).mode = 'ROT'
+ layout.operator("object.transforms_to_deltas", text="Scale to Deltas", text_ctxt=i18n_contexts.default).mode = 'SCALE'
+
+ layout.operator("object.transforms_to_deltas", text="All Transforms to Deltas", text_ctxt=i18n_contexts.default).mode = 'ALL'
+ layout.operator("object.anim_transforms_to_deltas")
+
+ layout.separator()
+
layout.operator("object.visual_transform_apply", text="Visual Transform", text_ctxt=i18n_contexts.default)
layout.operator("object.duplicates_make_real")
@@ -1726,6 +1761,13 @@ class VIEW3D_MT_paint_vertex(Menu):
layout.operator("paint.vertex_color_smooth")
layout.operator("paint.vertex_color_dirt")
+ layout.separator()
+
+ layout.operator("paint.vertex_color_invert", text="Invert")
+ layout.operator("paint.vertex_color_levels", text="Levels")
+ layout.operator("paint.vertex_color_hsv", text="Hue Saturation Value")
+ layout.operator("paint.vertex_color_brightness_contrast", text="Bright/Contrast")
+
class VIEW3D_MT_hook(Menu):
bl_label = "Hooks"
@@ -2283,8 +2325,7 @@ class VIEW3D_MT_edit_mesh(Menu):
layout.separator()
layout.prop(toolsettings, "use_mesh_automerge")
- layout.prop_menu_enum(toolsettings, "proportional_edit")
- layout.prop_menu_enum(toolsettings, "proportional_edit_falloff")
+ layout.menu("VIEW3D_MT_edit_proportional")
layout.separator()
@@ -2399,6 +2440,8 @@ class VIEW3D_MT_edit_mesh_vertices(Menu):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
+ with_bullet = bpy.app.build_options.bullet
+
layout.operator("mesh.merge")
layout.operator("mesh.rip_move")
layout.operator("mesh.rip_move_fill")
@@ -2419,7 +2462,8 @@ class VIEW3D_MT_edit_mesh_vertices(Menu):
layout.separator()
layout.operator("mesh.bevel").vertex_only = True
- layout.operator("mesh.convex_hull")
+ if with_bullet:
+ layout.operator("mesh.convex_hull")
layout.operator("mesh.vertices_smooth")
layout.operator("mesh.remove_doubles")
@@ -2446,6 +2490,7 @@ class VIEW3D_MT_edit_mesh_edges(Menu):
layout.operator("mesh.edge_face_add")
layout.operator("mesh.subdivide")
+ layout.operator("mesh.subdivide_edgering")
layout.operator("mesh.unsubdivide")
layout.separator()
@@ -2567,6 +2612,7 @@ class VIEW3D_MT_edit_mesh_clean(Menu):
layout.separator()
+ layout.operator("mesh.decimate")
layout.operator("mesh.dissolve_degenerate")
layout.operator("mesh.dissolve_limited")
layout.operator("mesh.face_make_planar")
@@ -2615,6 +2661,10 @@ class VIEW3D_MT_edit_gpencil_delete(Menu):
layout.operator("gpencil.dissolve")
+ layout.separator()
+
+ layout.operator("gpencil.active_frames_delete_all")
+
# Edit Curve
# draw_curve is used by VIEW3D_MT_edit_curve and VIEW3D_MT_edit_surface
@@ -2647,8 +2697,7 @@ def draw_curve(self, context):
layout.separator()
- layout.prop_menu_enum(toolsettings, "proportional_edit")
- layout.prop_menu_enum(toolsettings, "proportional_edit_falloff")
+ layout.menu("VIEW3D_MT_edit_proportional")
layout.separator()
@@ -2807,8 +2856,7 @@ class VIEW3D_MT_edit_meta(Menu):
layout.separator()
- layout.prop_menu_enum(toolsettings, "proportional_edit")
- layout.prop_menu_enum(toolsettings, "proportional_edit_falloff")
+ layout.menu("VIEW3D_MT_edit_proportional")
layout.separator()
@@ -2845,8 +2893,7 @@ class VIEW3D_MT_edit_lattice(Menu):
layout.separator()
- layout.prop_menu_enum(toolsettings, "proportional_edit")
- layout.prop_menu_enum(toolsettings, "proportional_edit_falloff")
+ layout.menu("VIEW3D_MT_edit_proportional")
class VIEW3D_MT_edit_armature(Menu):
@@ -3006,8 +3053,7 @@ class VIEW3D_MT_edit_gpencil(Menu):
layout.separator()
- layout.prop_menu_enum(toolsettings, "proportional_edit")
- layout.prop_menu_enum(toolsettings, "proportional_edit_falloff")
+ layout.menu("VIEW3D_MT_edit_proportional")
layout.separator()
@@ -3049,6 +3095,13 @@ class VIEW3D_PT_grease_pencil(GreasePencilDataPanel, Panel):
# NOTE: this is just a wrapper around the generic GP Panel
+class VIEW3D_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'UI'
+
+ # NOTE: this is just a wrapper around the generic GP Panel
+
+
class VIEW3D_PT_view3d_properties(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
@@ -3178,8 +3231,10 @@ class VIEW3D_PT_view3d_display(Panel):
row.prop(view, "show_axis_z", text="Z", toggle=True)
sub = col.column(align=True)
- sub.active = (display_all and view.show_floor)
- sub.prop(view, "grid_lines", text="Lines")
+ sub.active = bool(view.show_floor or view.region_quadviews or not view.region_3d.is_perspective)
+ subsub = sub.column(align=True)
+ subsub.active = view.show_floor
+ subsub.prop(view, "grid_lines", text="Lines")
sub.prop(view, "grid_scale", text="Scale")
subsub = sub.column(align=True)
subsub.active = scene.unit_settings.system == 'NONE'
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 49c7600c055..8019c8d2f34 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -22,7 +22,9 @@ from bpy.types import Menu, Panel, UIList
from bl_ui.properties_grease_pencil_common import (
GreasePencilDrawingToolsPanel,
GreasePencilStrokeEditPanel,
- GreasePencilStrokeSculptPanel
+ GreasePencilStrokeSculptPanel,
+ GreasePencilBrushPanel,
+ GreasePencilBrushCurvesPanel
)
from bl_ui.properties_paint_common import (
UnifiedPaintPanel,
@@ -570,6 +572,7 @@ class VIEW3D_PT_tools_curveedit_options_stroke(View3DPanel, Panel):
if cps.curve_type == 'BEZIER':
col.label("Bezier Options:")
col.prop(cps, "error_threshold")
+ col.prop(cps, "fit_method")
col.prop(cps, "use_corners_detect")
col = layout.column()
@@ -604,6 +607,7 @@ class VIEW3D_PT_tools_curveedit_options_stroke(View3DPanel, Panel):
colsub = layout.column(align=True)
colsub.prop(cps, "surface_plane", expand=True)
+
# ********** default tools for editmode_surface ****************
class VIEW3D_PT_tools_transform_surface(View3DPanel, Panel):
@@ -1532,6 +1536,15 @@ class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel):
def poll(cls, context):
return (context.sculpt_object and context.tool_settings.sculpt)
+ def draw_header(self, context):
+ layout = self.layout
+ layout.operator(
+ "sculpt.dynamic_topology_toggle",
+ icon='CHECKBOX_HLT' if context.sculpt_object.use_dynamic_topology_sculpting else 'CHECKBOX_DEHLT',
+ text="",
+ emboss=False,
+ )
+
def draw(self, context):
layout = self.layout
@@ -1540,11 +1553,6 @@ class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel):
settings = self.paint_settings(context)
brush = settings.brush
- if context.sculpt_object.use_dynamic_topology_sculpting:
- layout.operator("sculpt.dynamic_topology_toggle", icon='X', text="Disable Dyntopo")
- else:
- layout.operator("sculpt.dynamic_topology_toggle", icon='SCULPT_DYNTOPO', text="Enable Dyntopo")
-
col = layout.column()
col.active = context.sculpt_object.use_dynamic_topology_sculpting
sub = col.column(align=True)
@@ -1603,7 +1611,7 @@ class VIEW3D_PT_sculpt_options(Panel, View3DPaintPanel):
class VIEW3D_PT_sculpt_symmetry(Panel, View3DPaintPanel):
bl_category = "Tools"
- bl_label = "Symmetry / Lock"
+ bl_label = "Symmetry/Lock"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
@@ -1959,6 +1967,15 @@ class VIEW3D_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel)
bl_space_type = 'VIEW_3D'
+# Grease Pencil drawing brushes
+class VIEW3D_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel):
+ bl_space_type = 'VIEW_3D'
+
+# Grease Pencil drawingcurves
+class VIEW3D_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel):
+ bl_space_type = 'VIEW_3D'
+
+
# Note: moved here so that it's always in last position in 'Tools' panels!
class VIEW3D_PT_tools_history(View3DPanel, Panel):
bl_category = "Tools"
diff --git a/release/scripts/startup/keyingsets_builtins.py b/release/scripts/startup/keyingsets_builtins.py
index 6d52a81456b..97320e56378 100644
--- a/release/scripts/startup/keyingsets_builtins.py
+++ b/release/scripts/startup/keyingsets_builtins.py
@@ -25,6 +25,9 @@ to work correctly.
Beware also about changing the order that these are defined here, since this can result in old files referring to the
wrong Keying Set as the active one, potentially resulting in lost (i.e. unkeyed) animation.
+
+Note that these classes cannot be subclassed further; only direct subclasses of KeyingSetInfo
+are supported.
"""
import bpy
@@ -43,6 +46,7 @@ ANIM_KS_SCALING_ID = "Scaling"
ANIM_KS_LOC_ROT_SCALE_ID = "LocRotScale"
ANIM_KS_AVAILABLE_ID = "Available"
ANIM_KS_WHOLE_CHARACTER_ID = "WholeCharacter"
+ANIM_KS_WHOLE_CHARACTER_SELECTED_ID = "WholeCharacterSelected"
# Location
@@ -176,6 +180,23 @@ class BUILTIN_KSI_RotScale(KeyingSetInfo):
# ------------
+# Bendy Bones
+class BUILTIN_KSI_BendyBones(KeyingSetInfo):
+ """Insert a keyframe for each of the BBone shape properties"""
+ bl_label = "BBone Shape"
+
+ # poll - use callback for selected bones
+ poll = keyingsets_utils.RKS_POLL_selected_bones
+
+ # iterator - use callback for selected bones
+ iterator = keyingsets_utils.RKS_ITER_selected_bones
+
+ # generator - use generator for bendy bone properties
+ generate = keyingsets_utils.RKS_GEN_bendy_bones
+
+# ------------
+
+
# VisualLocation
class BUILTIN_KSI_VisualLoc(KeyingSetInfo):
"""Insert a keyframe on each of the location channels, taking into account effects of constraints """
@@ -379,7 +400,8 @@ class BUILTIN_KSI_WholeCharacter(KeyingSetInfo):
# generator - all unlocked bone transforms + custom properties
def generate(ksi, context, ks, bone):
# loc, rot, scale - only include unlocked ones
- ksi.doLoc(ks, bone)
+ if not bone.bone.use_connect:
+ ksi.doLoc(ks, bone)
if bone.rotation_mode in {'QUATERNION', 'AXIS_ANGLE'}:
ksi.doRot4d(ks, bone)
@@ -387,6 +409,9 @@ class BUILTIN_KSI_WholeCharacter(KeyingSetInfo):
ksi.doRot3d(ks, bone)
ksi.doScale(ks, bone)
+ # bbone properties?
+ ksi.doBBone(context, ks, bone)
+
# custom props?
ksi.doCustomProps(ks, bone)
@@ -466,6 +491,19 @@ class BUILTIN_KSI_WholeCharacter(KeyingSetInfo):
# ----------------
+ # bendy bone properties
+ def doBBone(ksi, context, ks, pchan):
+ bone = pchan.bone
+
+ # This check is crude, but is the best we can do for now
+ # It simply adds all of these if the bbone has segments
+ # (and the bone is a control bone). This may lead to some
+ # false positives...
+ if bone.bbone_segments > 1:
+ keyingsets_utils.RKS_GEN_bendy_bones(ksi, context, ks, pchan)
+
+ # ----------------
+
# custom properties
def doCustomProps(ksi, ks, bone):
@@ -488,9 +526,35 @@ class BUILTIN_KSI_WholeCharacter(KeyingSetInfo):
elif prop_rna.is_animatable:
ksi.addProp(ks, bone, prop)
+# All properties that are likely to get animated in a character rig, only selected bones.
+class BUILTIN_KSI_WholeCharacterSelected(KeyingSetInfo):
+ """Insert a keyframe for all properties that are likely to get animated in a character rig """
+ """(only selected bones)"""
+ bl_idname = ANIM_KS_WHOLE_CHARACTER_SELECTED_ID
+ bl_label = "Whole Character (Selected bones only)"
-###############################
+ # iterator - all bones regardless of selection
+ def iterator(ksi, context, ks):
+ # Use either the selected bones, or all of them if none are selected.
+ bones = context.selected_pose_bones or context.active_object.pose.bones
+
+ for bone in bones:
+ if bone.name.startswith(BUILTIN_KSI_WholeCharacter.badBonePrefixes):
+ continue
+ ksi.generate(context, ks, bone)
+
+ # Poor man's subclassing. Blender breaks when we actually subclass BUILTIN_KSI_WholeCharacter.
+ poll = BUILTIN_KSI_WholeCharacter.poll
+ generate = BUILTIN_KSI_WholeCharacter.generate
+ addProp = BUILTIN_KSI_WholeCharacter.addProp
+ doLoc = BUILTIN_KSI_WholeCharacter.doLoc
+ doRot4d = BUILTIN_KSI_WholeCharacter.doRot4d
+ doRot3d = BUILTIN_KSI_WholeCharacter.doRot3d
+ doScale = BUILTIN_KSI_WholeCharacter.doScale
+ doBBone = BUILTIN_KSI_WholeCharacter.doBBone
+ doCustomProps = BUILTIN_KSI_WholeCharacter.doCustomProps
+###############################
# Delta Location
class BUILTIN_KSI_DeltaLocation(KeyingSetInfo):
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index baaa10b77b0..4906ca03b02 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -32,6 +32,7 @@ class SortedNodeCategory(NodeCategory):
super().__init__(identifier, name, description, items)
+
class CompositorNodeCategory(SortedNodeCategory):
@classmethod
def poll(cls, context):
diff --git a/release/scripts/templates_py/script_stub.py b/release/scripts/templates_py/external_script_stub.py
index 5505ca64078..5505ca64078 100644
--- a/release/scripts/templates_py/script_stub.py
+++ b/release/scripts/templates_py/external_script_stub.py
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt
index e36f9e2b43e..6f2b78e0845 100644
--- a/source/blender/CMakeLists.txt
+++ b/source/blender/CMakeLists.txt
@@ -31,6 +31,7 @@ set(SRC_DNA_INC
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_armature_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_boid_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_brush_types.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_cachefile_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_camera_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_cloth_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_color_types.h
@@ -153,3 +154,6 @@ if(WITH_FREESTYLE)
add_subdirectory(freestyle)
endif()
+if(WITH_ALEMBIC)
+ add_subdirectory(alembic)
+endif()
diff --git a/source/blender/alembic/ABC_alembic.h b/source/blender/alembic/ABC_alembic.h
new file mode 100644
index 00000000000..e92d5f2d9f7
--- /dev/null
+++ b/source/blender/alembic/ABC_alembic.h
@@ -0,0 +1,119 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __ABC_ALEMBIC_H__
+#define __ABC_ALEMBIC_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct bContext;
+struct CacheReader;
+struct DerivedMesh;
+struct ListBase;
+struct Object;
+struct Scene;
+
+typedef struct AbcArchiveHandle AbcArchiveHandle;
+
+enum {
+ ABC_ARCHIVE_OGAWA = 0,
+ ABC_ARCHIVE_HDF5 = 1,
+};
+
+int ABC_get_version(void);
+
+struct AlembicExportParams {
+ double frame_start;
+ double frame_end;
+
+ double frame_step_xform;
+ double frame_step_shape;
+
+ double shutter_open;
+ double shutter_close;
+
+ /* bools */
+ unsigned int selected_only : 1;
+ unsigned int uvs : 1;
+ unsigned int normals : 1;
+ unsigned int vcolors : 1;
+ unsigned int apply_subdiv : 1;
+ unsigned int flatten_hierarchy : 1;
+ unsigned int visible_layers_only : 1;
+ unsigned int renderable_only : 1;
+ unsigned int face_sets : 1;
+ unsigned int use_subdiv_schema : 1;
+ unsigned int packuv : 1;
+ unsigned int triangulate : 1;
+
+ unsigned int compression_type : 1;
+
+ int quad_method;
+ int ngon_method;
+ float global_scale;
+};
+
+void ABC_export(
+ struct Scene *scene,
+ struct bContext *C,
+ const char *filepath,
+ const struct AlembicExportParams *params);
+
+void ABC_import(struct bContext *C,
+ const char *filepath,
+ float scale,
+ bool is_sequence,
+ bool set_frame_range,
+ int sequence_len,
+ int offset,
+ bool validate_meshes);
+
+AbcArchiveHandle *ABC_create_handle(const char *filename, struct ListBase *object_paths);
+
+void ABC_free_handle(AbcArchiveHandle *handle);
+
+void ABC_get_transform(struct CacheReader *reader,
+ float r_mat[4][4],
+ float time,
+ float scale);
+
+struct DerivedMesh *ABC_read_mesh(struct CacheReader *reader,
+ struct Object *ob,
+ struct DerivedMesh *dm,
+ const float time,
+ const char **err_str,
+ int flags);
+
+void CacheReader_free(struct CacheReader *reader);
+
+struct CacheReader *CacheReader_open_alembic_object(struct AbcArchiveHandle *handle,
+ struct CacheReader *reader,
+ struct Object *object,
+ const char *object_path);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ABC_ALEMBIC_H__ */
diff --git a/source/blender/alembic/CMakeLists.txt b/source/blender/alembic/CMakeLists.txt
new file mode 100644
index 00000000000..ad85f79ef2e
--- /dev/null
+++ b/source/blender/alembic/CMakeLists.txt
@@ -0,0 +1,85 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public 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): Kevin Dietrich.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ ../blenkernel
+ ../blenlib
+ ../blenloader
+ ../bmesh
+ ../editors/include
+ ../makesdna
+ ../makesrna
+ ../windowmanager
+ ../../../intern/guardedalloc
+ ../../../intern/utfconv
+)
+
+set(INC_SYS
+ ${ALEMBIC_INCLUDE_DIRS}
+ ${HDF5_INCLUDE_DIRS}
+ ${OPENEXR_INCLUDE_DIRS}
+)
+if(APPLE OR WIN32)
+ list(APPEND INC_SYS
+ ${BOOST_INCLUDE_DIR}
+ )
+endif()
+
+set(SRC
+ intern/abc_archive.cc
+ intern/abc_camera.cc
+ intern/abc_customdata.cc
+ intern/abc_curves.cc
+ intern/abc_exporter.cc
+ intern/abc_hair.cc
+ intern/abc_mesh.cc
+ intern/abc_nurbs.cc
+ intern/abc_object.cc
+ intern/abc_points.cc
+ intern/abc_transform.cc
+ intern/abc_util.cc
+ intern/alembic_capi.cc
+
+ ABC_alembic.h
+ intern/abc_archive.h
+ intern/abc_camera.h
+ intern/abc_customdata.h
+ intern/abc_curves.h
+ intern/abc_exporter.h
+ intern/abc_hair.h
+ intern/abc_mesh.h
+ intern/abc_nurbs.h
+ intern/abc_object.h
+ intern/abc_points.h
+ intern/abc_transform.h
+ intern/abc_util.h
+)
+
+if(WITH_ALEMBIC_HDF5)
+ add_definitions(-DWITH_ALEMBIC_HDF5)
+endif()
+
+blender_add_lib(bf_alembic "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/alembic/intern/abc_archive.cc b/source/blender/alembic/intern/abc_archive.cc
new file mode 100644
index 00000000000..0985a06d732
--- /dev/null
+++ b/source/blender/alembic/intern/abc_archive.cc
@@ -0,0 +1,175 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Kévin Dietrich.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+#include "abc_archive.h"
+
+#ifdef WIN32
+# include "utfconv.h"
+#endif
+
+using Alembic::Abc::Exception;
+using Alembic::Abc::ErrorHandler;
+using Alembic::Abc::IArchive;
+using Alembic::Abc::kWrapExisting;
+using Alembic::Abc::OArchive;
+
+static IArchive open_archive(const std::string &filename,
+ const std::vector<std::istream *> &input_streams,
+ bool &is_hdf5)
+{
+ try {
+ is_hdf5 = false;
+ Alembic::AbcCoreOgawa::ReadArchive archive_reader(input_streams);
+
+ return IArchive(archive_reader(filename),
+ kWrapExisting,
+ ErrorHandler::kThrowPolicy);
+ }
+ catch (const Exception &e) {
+ std::cerr << e.what() << '\n';
+
+#ifdef WITH_ALEMBIC_HDF5
+ try {
+ is_hdf5 = true;
+ Alembic::AbcCoreAbstract::ReadArraySampleCachePtr cache_ptr;
+
+ return IArchive(Alembic::AbcCoreHDF5::ReadArchive(),
+ filename.c_str(), ErrorHandler::kThrowPolicy,
+ cache_ptr);
+ }
+ catch (const Exception &) {
+ std::cerr << e.what() << '\n';
+ return IArchive();
+ }
+#else
+ return IArchive();
+#endif
+ }
+
+ return IArchive();
+}
+
+ArchiveReader::ArchiveReader(const char *filename)
+{
+#ifdef WIN32
+ UTF16_ENCODE(filename);
+ std::wstring wstr(filename_16);
+ m_infile.open(wstr.c_str(), std::ios::in | std::ios::binary);
+ UTF16_UN_ENCODE(filename);
+#else
+ m_infile.open(filename, std::ios::in | std::ios::binary);
+#endif
+
+ m_streams.push_back(&m_infile);
+
+ bool is_hdf5;
+ m_archive = open_archive(filename, m_streams, is_hdf5);
+
+ /* We can't open an HDF5 file from a stream, so close it. */
+ if (is_hdf5) {
+ m_infile.close();
+ m_streams.clear();
+ }
+}
+
+bool ArchiveReader::valid() const
+{
+ return m_archive.valid();
+}
+
+Alembic::Abc::IObject ArchiveReader::getTop()
+{
+ return m_archive.getTop();
+}
+
+/* ************************************************************************** */
+
+/* This kinda duplicates CreateArchiveWithInfo, but Alembic does not seem to
+ * have a version supporting streams. */
+static OArchive create_archive(std::ostream *ostream,
+ const std::string &filename,
+ const std::string &scene_name,
+ Alembic::Abc::MetaData &md,
+ bool ogawa)
+{
+ md.set(Alembic::Abc::kApplicationNameKey, "Blender");
+ md.set(Alembic::Abc::kUserDescriptionKey, scene_name);
+
+ time_t raw_time;
+ time(&raw_time);
+ char buffer[128];
+
+#if defined _WIN32 || defined _WIN64
+ ctime_s(buffer, 128, &raw_time);
+#else
+ ctime_r(&raw_time, buffer);
+#endif
+
+ const std::size_t buffer_len = strlen(buffer);
+ if (buffer_len > 0 && buffer[buffer_len - 1] == '\n') {
+ buffer[buffer_len - 1] = '\0';
+ }
+
+ md.set(Alembic::Abc::kDateWrittenKey, buffer);
+
+ ErrorHandler::Policy policy = ErrorHandler::kThrowPolicy;
+
+#ifdef WITH_ALEMBIC_HDF5
+ if (!ogawa) {
+ return OArchive(Alembic::AbcCoreHDF5::WriteArchive(), filename, md, policy);
+ }
+#else
+ static_cast<void>(filename);
+ static_cast<void>(ogawa);
+#endif
+
+ Alembic::AbcCoreOgawa::WriteArchive archive_writer;
+ return OArchive(archive_writer(ostream, md), kWrapExisting, policy);
+}
+
+ArchiveWriter::ArchiveWriter(const char *filename, const char *scene, bool do_ogawa, Alembic::Abc::MetaData &md)
+{
+ /* Use stream to support unicode character paths on Windows. */
+ if (do_ogawa) {
+#ifdef WIN32
+ UTF16_ENCODE(filename);
+ std::wstring wstr(filename_16);
+ m_outfile.open(wstr.c_str(), std::ios::out | std::ios::binary);
+ UTF16_UN_ENCODE(filename);
+#else
+ m_outfile.open(filename, std::ios::out | std::ios::binary);
+#endif
+ }
+
+ m_archive = create_archive(&m_outfile,
+ filename,
+ scene,
+ md,
+ do_ogawa);
+}
+
+OArchive &ArchiveWriter::archive()
+{
+ return m_archive;
+}
diff --git a/source/blender/alembic/intern/abc_archive.h b/source/blender/alembic/intern/abc_archive.h
new file mode 100644
index 00000000000..d412574b736
--- /dev/null
+++ b/source/blender/alembic/intern/abc_archive.h
@@ -0,0 +1,66 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Kévin Dietrich.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+#ifndef __ABC_ARCHIVE_H__
+#define __ABC_ARCHIVE_H__
+
+#include <Alembic/Abc/All.h>
+
+#ifdef WITH_ALEMBIC_HDF5
+# include <Alembic/AbcCoreHDF5/All.h>
+#endif
+
+#include <Alembic/AbcCoreOgawa/All.h>
+
+#include <fstream>
+
+/* Wrappers around input and output archives. The goal is to be able to use
+ * streams so that unicode paths work on Windows (T49112), and to make sure that
+ * the stream objects remain valid as long as the archives are open.
+ */
+
+class ArchiveReader {
+ Alembic::Abc::IArchive m_archive;
+ std::ifstream m_infile;
+ std::vector<std::istream *> m_streams;
+
+public:
+ explicit ArchiveReader(const char *filename);
+
+ bool valid() const;
+
+ Alembic::Abc::IObject getTop();
+};
+
+class ArchiveWriter {
+ std::ofstream m_outfile;
+ Alembic::Abc::OArchive m_archive;
+
+public:
+ explicit ArchiveWriter(const char *filename, const char *scene, bool do_ogawa, Alembic::Abc::MetaData &md);
+
+ Alembic::Abc::OArchive &archive();
+};
+
+#endif /* __ABC_ARCHIVE_H__ */
diff --git a/source/blender/alembic/intern/abc_camera.cc b/source/blender/alembic/intern/abc_camera.cc
new file mode 100644
index 00000000000..d5271e3ca31
--- /dev/null
+++ b/source/blender/alembic/intern/abc_camera.cc
@@ -0,0 +1,160 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "abc_camera.h"
+
+#include "abc_transform.h"
+#include "abc_util.h"
+
+extern "C" {
+#include "DNA_camera_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_camera.h"
+#include "BKE_object.h"
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+}
+
+using Alembic::AbcGeom::ICamera;
+using Alembic::AbcGeom::ICompoundProperty;
+using Alembic::AbcGeom::IFloatProperty;
+using Alembic::AbcGeom::ISampleSelector;
+
+using Alembic::AbcGeom::OCamera;
+using Alembic::AbcGeom::OFloatProperty;
+
+using Alembic::AbcGeom::CameraSample;
+using Alembic::AbcGeom::kWrapExisting;
+
+/* ************************************************************************** */
+
+AbcCameraWriter::AbcCameraWriter(Scene *scene,
+ Object *ob,
+ AbcTransformWriter *parent,
+ uint32_t time_sampling,
+ ExportSettings &settings)
+ : AbcObjectWriter(scene, ob, time_sampling, settings, parent)
+{
+ OCamera camera(parent->alembicXform(), m_name, m_time_sampling);
+ m_camera_schema = camera.getSchema();
+
+ m_custom_data_container = m_camera_schema.getUserProperties();
+ m_stereo_distance = OFloatProperty(m_custom_data_container, "stereoDistance", m_time_sampling);
+ m_eye_separation = OFloatProperty(m_custom_data_container, "eyeSeparation", m_time_sampling);
+}
+
+void AbcCameraWriter::do_write()
+{
+ Camera *cam = static_cast<Camera *>(m_object->data);
+
+ m_stereo_distance.set(cam->stereo.convergence_distance);
+ m_eye_separation.set(cam->stereo.interocular_distance);
+
+ const double apperture_x = cam->sensor_x / 10.0;
+ const double apperture_y = cam->sensor_y / 10.0;
+ const double film_aspect = apperture_x / apperture_y;
+
+ m_camera_sample.setFocalLength(cam->lens);
+ m_camera_sample.setHorizontalAperture(apperture_x);
+ m_camera_sample.setVerticalAperture(apperture_y);
+ m_camera_sample.setHorizontalFilmOffset(apperture_x * cam->shiftx);
+ m_camera_sample.setVerticalFilmOffset(apperture_y * cam->shifty * film_aspect);
+ m_camera_sample.setNearClippingPlane(cam->clipsta);
+ m_camera_sample.setFarClippingPlane(cam->clipend);
+
+ if (cam->dof_ob) {
+ Imath::V3f v(m_object->loc[0] - cam->dof_ob->loc[0],
+ m_object->loc[1] - cam->dof_ob->loc[1],
+ m_object->loc[2] - cam->dof_ob->loc[2]);
+ m_camera_sample.setFocusDistance(v.length());
+ }
+ else {
+ m_camera_sample.setFocusDistance(cam->gpu_dof.focus_distance);
+ }
+
+ /* Blender camera does not have an fstop param, so try to find a custom prop
+ * instead. */
+ m_camera_sample.setFStop(cam->gpu_dof.fstop);
+
+ m_camera_sample.setLensSqueezeRatio(1.0);
+ m_camera_schema.set(m_camera_sample);
+}
+
+/* ************************************************************************** */
+
+AbcCameraReader::AbcCameraReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
+ : AbcObjectReader(object, settings)
+{
+ ICamera abc_cam(m_iobject, kWrapExisting);
+ m_schema = abc_cam.getSchema();
+
+ get_min_max_time(m_iobject, m_schema, m_min_time, m_max_time);
+}
+
+bool AbcCameraReader::valid() const
+{
+ return m_schema.valid();
+}
+
+void AbcCameraReader::readObjectData(Main *bmain, float time)
+{
+ Camera *bcam = static_cast<Camera *>(BKE_camera_add(bmain, m_data_name.c_str()));
+
+ ISampleSelector sample_sel(time);
+ CameraSample cam_sample;
+ m_schema.get(cam_sample, sample_sel);
+
+ ICompoundProperty customDataContainer = m_schema.getUserProperties();
+
+ if (customDataContainer.valid() &&
+ customDataContainer.getPropertyHeader("stereoDistance") &&
+ customDataContainer.getPropertyHeader("eyeSeparation"))
+ {
+ IFloatProperty convergence_plane(customDataContainer, "stereoDistance");
+ IFloatProperty eye_separation(customDataContainer, "eyeSeparation");
+
+ bcam->stereo.interocular_distance = eye_separation.getValue(sample_sel);
+ bcam->stereo.convergence_distance = convergence_plane.getValue(sample_sel);
+ }
+
+ const float lens = cam_sample.getFocalLength();
+ const float apperture_x = cam_sample.getHorizontalAperture();
+ const float apperture_y = cam_sample.getVerticalAperture();
+ const float h_film_offset = cam_sample.getHorizontalFilmOffset();
+ const float v_film_offset = cam_sample.getVerticalFilmOffset();
+ const float film_aspect = apperture_x / apperture_y;
+
+ bcam->lens = lens;
+ bcam->sensor_x = apperture_x * 10;
+ bcam->sensor_y = apperture_y * 10;
+ bcam->shiftx = h_film_offset / apperture_x;
+ bcam->shifty = v_film_offset / apperture_y / film_aspect;
+ bcam->clipsta = max_ff(0.1f, cam_sample.getNearClippingPlane());
+ bcam->clipend = cam_sample.getFarClippingPlane();
+ bcam->gpu_dof.focus_distance = cam_sample.getFocusDistance();
+ bcam->gpu_dof.fstop = cam_sample.getFStop();
+
+ m_object = BKE_object_add_only_object(bmain, OB_CAMERA, m_object_name.c_str());
+ m_object->data = bcam;
+}
diff --git a/source/blender/alembic/intern/abc_camera.h b/source/blender/alembic/intern/abc_camera.h
new file mode 100644
index 00000000000..fafb4d3eb39
--- /dev/null
+++ b/source/blender/alembic/intern/abc_camera.h
@@ -0,0 +1,61 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __ABC_CAMERA_H__
+#define __ABC_CAMERA_H__
+
+#include "abc_object.h"
+
+/* ************************************************************************** */
+
+class AbcCameraWriter : public AbcObjectWriter {
+ Alembic::AbcGeom::OCameraSchema m_camera_schema;
+ Alembic::AbcGeom::CameraSample m_camera_sample;
+ Alembic::AbcGeom::OCompoundProperty m_custom_data_container;
+ Alembic::AbcGeom::OFloatProperty m_stereo_distance;
+ Alembic::AbcGeom::OFloatProperty m_eye_separation;
+
+public:
+ AbcCameraWriter(Scene *scene,
+ Object *ob,
+ AbcTransformWriter *parent,
+ uint32_t time_sampling,
+ ExportSettings &settings);
+
+private:
+ virtual void do_write();
+};
+
+/* ************************************************************************** */
+
+class AbcCameraReader : public AbcObjectReader {
+ Alembic::AbcGeom::ICameraSchema m_schema;
+
+public:
+ AbcCameraReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
+
+ bool valid() const;
+
+ void readObjectData(Main *bmain, float time);
+};
+
+#endif /* __ABC_CAMERA_H__ */ \ No newline at end of file
diff --git a/source/blender/alembic/intern/abc_curves.cc b/source/blender/alembic/intern/abc_curves.cc
new file mode 100644
index 00000000000..7e5ea3b1853
--- /dev/null
+++ b/source/blender/alembic/intern/abc_curves.cc
@@ -0,0 +1,407 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Kévin Dietrich.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+#include "abc_curves.h"
+
+#include <cstdio>
+
+#include "abc_transform.h"
+#include "abc_util.h"
+
+extern "C" {
+#include "MEM_guardedalloc.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_listbase.h"
+
+#include "BKE_cdderivedmesh.h"
+#include "BKE_curve.h"
+#include "BKE_object.h"
+
+#include "ED_curve.h"
+}
+
+using Alembic::Abc::IInt32ArrayProperty;
+using Alembic::Abc::Int32ArraySamplePtr;
+using Alembic::Abc::FloatArraySamplePtr;
+using Alembic::Abc::P3fArraySamplePtr;
+using Alembic::Abc::UcharArraySamplePtr;
+
+using Alembic::AbcGeom::ICurves;
+using Alembic::AbcGeom::ICurvesSchema;
+using Alembic::AbcGeom::IFloatGeomParam;
+using Alembic::AbcGeom::ISampleSelector;
+using Alembic::AbcGeom::kWrapExisting;
+using Alembic::AbcGeom::CurvePeriodicity;
+
+using Alembic::AbcGeom::OCurves;
+using Alembic::AbcGeom::OCurvesSchema;
+using Alembic::AbcGeom::ON3fGeomParam;
+using Alembic::AbcGeom::OV2fGeomParam;
+
+/* ************************************************************************** */
+
+AbcCurveWriter::AbcCurveWriter(Scene *scene,
+ Object *ob,
+ AbcTransformWriter *parent,
+ uint32_t time_sampling,
+ ExportSettings &settings)
+ : AbcObjectWriter(scene, ob, time_sampling, settings, parent)
+{
+ OCurves curves(parent->alembicXform(), m_name, m_time_sampling);
+ m_schema = curves.getSchema();
+}
+
+void AbcCurveWriter::do_write()
+{
+ Curve *curve = static_cast<Curve *>(m_object->data);
+
+ std::vector<Imath::V3f> verts;
+ std::vector<int32_t> vert_counts;
+ std::vector<float> widths;
+ std::vector<float> weights;
+ std::vector<float> knots;
+ std::vector<uint8_t> orders;
+ Imath::V3f temp_vert;
+
+ Alembic::AbcGeom::BasisType curve_basis;
+ Alembic::AbcGeom::CurveType curve_type;
+ Alembic::AbcGeom::CurvePeriodicity periodicity;
+
+ Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
+ for (; nurbs; nurbs = nurbs->next) {
+ if (nurbs->bp) {
+ curve_basis = Alembic::AbcGeom::kNoBasis;
+ curve_type = Alembic::AbcGeom::kLinear;
+
+ const int totpoint = nurbs->pntsu * nurbs->pntsv;
+
+ const BPoint *point = nurbs->bp;
+
+ for (int i = 0; i < totpoint; ++i, ++point) {
+ copy_zup_yup(temp_vert.getValue(), point->vec);
+ verts.push_back(temp_vert);
+ weights.push_back(point->vec[3]);
+ widths.push_back(point->radius);
+ }
+ }
+ else if (nurbs->bezt) {
+ curve_basis = Alembic::AbcGeom::kBezierBasis;
+ curve_type = Alembic::AbcGeom::kCubic;
+
+ const int totpoint = nurbs->pntsu;
+
+ const BezTriple *bezier = nurbs->bezt;
+
+ /* TODO(kevin): store info about handles, Alembic doesn't have this. */
+ for (int i = 0; i < totpoint; ++i, ++bezier) {
+ copy_zup_yup(temp_vert.getValue(), bezier->vec[1]);
+ verts.push_back(temp_vert);
+ widths.push_back(bezier->radius);
+ }
+ }
+
+ if ((nurbs->flagu & CU_NURB_ENDPOINT) != 0) {
+ periodicity = Alembic::AbcGeom::kNonPeriodic;
+ }
+ else if ((nurbs->flagu & CU_NURB_CYCLIC) != 0) {
+ periodicity = Alembic::AbcGeom::kPeriodic;
+
+ /* Duplicate the start points to indicate that the curve is actually
+ * cyclic since other software need those.
+ */
+
+ for (int i = 0; i < nurbs->orderu; ++i) {
+ verts.push_back(verts[i]);
+ }
+ }
+
+ if (nurbs->knotsu != NULL) {
+ const size_t num_knots = KNOTSU(nurbs);
+
+ /* Add an extra knot at the beggining and end of the array since most apps
+ * require/expect them. */
+ knots.resize(num_knots + 2);
+
+ for (int i = 0; i < num_knots; ++i) {
+ knots[i + 1] = nurbs->knotsu[i];
+ }
+
+ if ((nurbs->flagu & CU_NURB_CYCLIC) != 0) {
+ knots[0] = nurbs->knotsu[0];
+ knots[num_knots - 1] = nurbs->knotsu[num_knots - 1];
+ }
+ else {
+ knots[0] = (2.0f * nurbs->knotsu[0] - nurbs->knotsu[1]);
+ knots[num_knots - 1] = (2.0f * nurbs->knotsu[num_knots - 1] - nurbs->knotsu[num_knots - 2]);
+ }
+ }
+
+ orders.push_back(nurbs->orderu + 1);
+ vert_counts.push_back(verts.size());
+ }
+
+ Alembic::AbcGeom::OFloatGeomParam::Sample width_sample;
+ width_sample.setVals(widths);
+
+ m_sample = OCurvesSchema::Sample(verts,
+ vert_counts,
+ curve_type,
+ periodicity,
+ width_sample,
+ OV2fGeomParam::Sample(), /* UVs */
+ ON3fGeomParam::Sample(), /* normals */
+ curve_basis,
+ weights,
+ orders,
+ knots);
+
+ m_sample.setSelfBounds(bounds());
+ m_schema.set(m_sample);
+}
+
+/* ************************************************************************** */
+
+AbcCurveReader::AbcCurveReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
+ : AbcObjectReader(object, settings)
+{
+ ICurves abc_curves(object, kWrapExisting);
+ m_curves_schema = abc_curves.getSchema();
+
+ get_min_max_time(m_iobject, m_curves_schema, m_min_time, m_max_time);
+}
+
+bool AbcCurveReader::valid() const
+{
+ return m_curves_schema.valid();
+}
+
+void AbcCurveReader::readObjectData(Main *bmain, float time)
+{
+ Curve *cu = BKE_curve_add(bmain, m_data_name.c_str(), OB_CURVE);
+
+ cu->flag |= CU_DEFORM_FILL | CU_3D;
+ cu->actvert = CU_ACT_NONE;
+
+ m_object = BKE_object_add_only_object(bmain, OB_CURVE, m_object_name.c_str());
+ m_object->data = cu;
+
+ read_curve_sample(cu, m_curves_schema, time);
+
+ if (has_animations(m_curves_schema, m_settings)) {
+ addCacheModifier();
+ }
+}
+
+/* ************************************************************************** */
+
+void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const float time)
+{
+ const ISampleSelector sample_sel(time);
+ ICurvesSchema::Sample smp = schema.getValue(sample_sel);
+ const Int32ArraySamplePtr num_vertices = smp.getCurvesNumVertices();
+ const P3fArraySamplePtr positions = smp.getPositions();
+ const FloatArraySamplePtr weights = smp.getPositionWeights();
+ const FloatArraySamplePtr knots = smp.getKnots();
+ const CurvePeriodicity periodicity = smp.getWrap();
+ const UcharArraySamplePtr orders = smp.getOrders();
+
+ const IFloatGeomParam widths_param = schema.getWidthsParam();
+ FloatArraySamplePtr radiuses;
+
+ if (widths_param.valid()) {
+ IFloatGeomParam::Sample wsample = widths_param.getExpandedValue(sample_sel);
+ radiuses = wsample.getVals();
+ }
+
+ int knot_offset = 0;
+
+ size_t idx = 0;
+ for (size_t i = 0; i < num_vertices->size(); ++i) {
+ const int num_verts = (*num_vertices)[i];
+
+ Nurb *nu = static_cast<Nurb *>(MEM_callocN(sizeof(Nurb), "abc_getnurb"));
+ nu->resolu = cu->resolu;
+ nu->resolv = cu->resolv;
+ nu->pntsu = num_verts;
+ nu->pntsv = 1;
+ nu->flag |= CU_SMOOTH;
+
+ nu->orderu = num_verts;
+
+ if (smp.getType() == Alembic::AbcGeom::kCubic) {
+ nu->orderu = 3;
+ }
+ else if (orders && orders->size() > i) {
+ nu->orderu = static_cast<short>((*orders)[i] - 1);
+ }
+
+ if (periodicity == Alembic::AbcGeom::kNonPeriodic) {
+ nu->flagu |= CU_NURB_ENDPOINT;
+ }
+ else if (periodicity == Alembic::AbcGeom::kPeriodic) {
+ nu->flagu |= CU_NURB_CYCLIC;
+
+ /* Check the number of points which overlap, we don't have
+ * overlapping points in Blender, but other software do use them to
+ * indicate that a curve is actually cyclic. Usually the number of
+ * overlapping points is equal to the order/degree of the curve.
+ */
+
+ const int start = idx;
+ const int end = idx + num_verts;
+ int overlap = 0;
+
+ for (int j = start, k = end - nu->orderu; j < nu->orderu; ++j, ++k) {
+ const Imath::V3f &p1 = (*positions)[j];
+ const Imath::V3f &p2 = (*positions)[k];
+
+ if (p1 != p2) {
+ break;
+ }
+
+ ++overlap;
+ }
+
+ /* TODO: Special case, need to figure out how it coincides with knots. */
+ if (overlap == 0 && num_verts > 2 && (*positions)[start] == (*positions)[end - 1]) {
+ overlap = 1;
+ }
+
+ /* There is no real cycles. */
+ if (overlap == 0) {
+ nu->flagu &= ~CU_NURB_CYCLIC;
+ nu->flagu |= CU_NURB_ENDPOINT;
+ }
+
+ nu->pntsu -= overlap;
+ }
+
+ const bool do_weights = (weights != NULL) && (weights->size() > 1);
+ float weight = 1.0f;
+
+ const bool do_radius = (radiuses != NULL) && (radiuses->size() > 1);
+ float radius = (radiuses && radiuses->size() == 1) ? (*radiuses)[0] : 1.0f;
+
+ nu->type = CU_NURBS;
+
+ nu->bp = static_cast<BPoint *>(MEM_callocN(sizeof(BPoint) * nu->pntsu, "abc_getnurb"));
+ BPoint *bp = nu->bp;
+
+ for (int j = 0; j < nu->pntsu; ++j, ++bp, ++idx) {
+ const Imath::V3f &pos = (*positions)[idx];
+
+ if (do_radius) {
+ radius = (*radiuses)[idx];
+ }
+
+ if (do_weights) {
+ weight = (*weights)[idx];
+ }
+
+ copy_yup_zup(bp->vec, pos.getValue());
+ bp->vec[3] = weight;
+ bp->f1 = SELECT;
+ bp->radius = radius;
+ bp->weight = 1.0f;
+ }
+
+ if (knots && knots->size() != 0) {
+ nu->knotsu = static_cast<float *>(MEM_callocN(KNOTSU(nu) * sizeof(float), "abc_setsplineknotsu"));
+
+ /* TODO: second check is temporary, for until the check for cycles is rock solid. */
+ if (periodicity == Alembic::AbcGeom::kPeriodic && (KNOTSU(nu) == knots->size() - 2)) {
+ /* Skip first and last knots. */
+ for (size_t i = 1; i < knots->size() - 1; ++i) {
+ nu->knotsu[i - 1] = (*knots)[knot_offset + i];
+ }
+ }
+ else {
+ /* TODO: figure out how to use the knots array from other
+ * software in this case. */
+ BKE_nurb_knot_calc_u(nu);
+ }
+
+ knot_offset += knots->size();
+ }
+ else {
+ BKE_nurb_knot_calc_u(nu);
+ }
+
+ BLI_addtail(BKE_curve_nurbs_get(cu), nu);
+ }
+}
+
+/* NOTE: Alembic only stores data about control points, but the DerivedMesh
+ * passed from the cache modifier contains the displist, which has more data
+ * than the control points, so to avoid corrupting the displist we modify the
+ * object directly and create a new DerivedMesh from that. Also we might need to
+ * create new or delete existing NURBS in the curve.
+ */
+DerivedMesh *AbcCurveReader::read_derivedmesh(DerivedMesh */*dm*/, const float time, int /*read_flag*/)
+{
+ ISampleSelector sample_sel(time);
+ const ICurvesSchema::Sample sample = m_curves_schema.getValue(sample_sel);
+
+ const P3fArraySamplePtr &positions = sample.getPositions();
+ const Int32ArraySamplePtr num_vertices = sample.getCurvesNumVertices();
+
+ int vertex_idx = 0;
+ int curve_idx = 0;
+ Curve *curve = static_cast<Curve *>(m_object->data);
+
+ const int curve_count = BLI_listbase_count(&curve->nurb);
+
+ if (curve_count != num_vertices->size()) {
+ BKE_nurbList_free(&curve->nurb);
+ read_curve_sample(curve, m_curves_schema, time);
+ }
+ else {
+ Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
+ for (; nurbs; nurbs = nurbs->next, ++curve_idx) {
+ const int totpoint = (*num_vertices)[curve_idx];
+
+ if (nurbs->bp) {
+ BPoint *point = nurbs->bp;
+
+ for (int i = 0; i < totpoint; ++i, ++point, ++vertex_idx) {
+ const Imath::V3f &pos = (*positions)[vertex_idx];
+ copy_yup_zup(point->vec, pos.getValue());
+ }
+ }
+ else if (nurbs->bezt) {
+ BezTriple *bezier = nurbs->bezt;
+
+ for (int i = 0; i < totpoint; ++i, ++bezier, ++vertex_idx) {
+ const Imath::V3f &pos = (*positions)[vertex_idx];
+ copy_yup_zup(bezier->vec[1], pos.getValue());
+ }
+ }
+ }
+ }
+
+ return CDDM_from_curve(m_object);
+}
diff --git a/source/blender/alembic/intern/abc_curves.h b/source/blender/alembic/intern/abc_curves.h
new file mode 100644
index 00000000000..979ee8af639
--- /dev/null
+++ b/source/blender/alembic/intern/abc_curves.h
@@ -0,0 +1,66 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Kévin Dietrich.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+#ifndef __ABC_CURVES_H__
+#define __ABC_CURVES_H__
+
+#include "abc_object.h"
+
+struct Curve;
+
+/* ************************************************************************** */
+
+class AbcCurveWriter : public AbcObjectWriter {
+ Alembic::AbcGeom::OCurvesSchema m_schema;
+ Alembic::AbcGeom::OCurvesSchema::Sample m_sample;
+
+public:
+ AbcCurveWriter(Scene *scene,
+ Object *ob,
+ AbcTransformWriter *parent,
+ uint32_t time_sampling,
+ ExportSettings &settings);
+
+ void do_write();
+};
+
+/* ************************************************************************** */
+
+class AbcCurveReader : public AbcObjectReader {
+ Alembic::AbcGeom::ICurvesSchema m_curves_schema;
+
+public:
+ AbcCurveReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
+
+ bool valid() const;
+
+ void readObjectData(Main *bmain, float time);
+ DerivedMesh *read_derivedmesh(DerivedMesh *, const float time, int);
+};
+
+/* ************************************************************************** */
+
+void read_curve_sample(Curve *cu, const Alembic::AbcGeom::ICurvesSchema &schema, const float time);
+
+#endif /* __ABC_CURVES_H__ */
diff --git a/source/blender/alembic/intern/abc_customdata.cc b/source/blender/alembic/intern/abc_customdata.cc
new file mode 100644
index 00000000000..ebf1b2ba96e
--- /dev/null
+++ b/source/blender/alembic/intern/abc_customdata.cc
@@ -0,0 +1,379 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Kévin Dietrich.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+#include "abc_customdata.h"
+
+#include <Alembic/AbcGeom/All.h>
+#include <algorithm>
+
+extern "C" {
+#include "DNA_customdata_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_customdata.h"
+}
+
+/* NOTE: for now only UVs and Vertex Colors are supported for streaming.
+ * Although Alembic only allows for a single UV layer per {I|O}Schema, and does
+ * not have a vertex color concept, there is a convention between DCCs to write
+ * such data in a way that lets other DCC know what they are for. See comments
+ * in the write code for the conventions. */
+
+using Alembic::AbcGeom::kVertexScope;
+using Alembic::AbcGeom::kFacevaryingScope;
+
+using Alembic::Abc::C4fArraySample;
+using Alembic::Abc::UInt32ArraySample;
+using Alembic::Abc::V2fArraySample;
+
+using Alembic::AbcGeom::OV2fGeomParam;
+using Alembic::AbcGeom::OC4fGeomParam;
+
+static void get_uvs(const CDStreamConfig &config,
+ std::vector<Imath::V2f> &uvs,
+ std::vector<uint32_t> &uvidx,
+ void *cd_data)
+{
+ MLoopUV *mloopuv_array = static_cast<MLoopUV *>(cd_data);
+
+ if (!mloopuv_array) {
+ return;
+ }
+
+ const int num_poly = config.totpoly;
+ MPoly *polygons = config.mpoly;
+
+ if (!config.pack_uvs) {
+ int cnt = 0;
+ uvidx.resize(config.totloop);
+ uvs.resize(config.totloop);
+
+ for (int i = 0; i < num_poly; ++i) {
+ MPoly &current_poly = polygons[i];
+ MLoopUV *loopuvpoly = mloopuv_array + current_poly.loopstart + current_poly.totloop;
+
+ for (int j = 0; j < current_poly.totloop; ++j, ++cnt) {
+ --loopuvpoly;
+
+ uvidx[cnt] = cnt;
+ uvs[cnt][0] = loopuvpoly->uv[0];
+ uvs[cnt][1] = loopuvpoly->uv[1];
+ }
+ }
+ }
+ else {
+ for (int i = 0; i < num_poly; ++i) {
+ MPoly &current_poly = polygons[i];
+ MLoopUV *loopuvpoly = mloopuv_array + current_poly.loopstart + current_poly.totloop;
+
+ for (int j = 0; j < current_poly.totloop; ++j) {
+ loopuvpoly--;
+ Imath::V2f uv(loopuvpoly->uv[0], loopuvpoly->uv[1]);
+
+ std::vector<Imath::V2f>::iterator it = std::find(uvs.begin(), uvs.end(), uv);
+
+ if (it == uvs.end()) {
+ uvidx.push_back(uvs.size());
+ uvs.push_back(uv);
+ }
+ else {
+ uvidx.push_back(std::distance(uvs.begin(), it));
+ }
+ }
+ }
+ }
+}
+
+const char *get_uv_sample(UVSample &sample, const CDStreamConfig &config, CustomData *data)
+{
+ const int active_uvlayer = CustomData_get_active_layer(data, CD_MLOOPUV);
+
+ if (active_uvlayer < 0) {
+ return "";
+ }
+
+ void *cd_data = CustomData_get_layer_n(data, CD_MLOOPUV, active_uvlayer);
+
+ get_uvs(config, sample.uvs, sample.indices, cd_data);
+
+ return CustomData_get_layer_name(data, CD_MLOOPUV, active_uvlayer);
+}
+
+/* Convention to write UVs:
+ * - V2fGeomParam on the arbGeomParam
+ * - set scope as face varying
+ * - (optional due to its behaviour) tag as UV using Alembic::AbcGeom::SetIsUV
+ */
+static void write_uv(const OCompoundProperty &prop, const CDStreamConfig &config, void *data, const char *name)
+{
+ std::vector<uint32_t> indices;
+ std::vector<Imath::V2f> uvs;
+
+ get_uvs(config, uvs, indices, data);
+
+ if (indices.empty() || uvs.empty()) {
+ return;
+ }
+
+ OV2fGeomParam param(prop, name, true, kFacevaryingScope, 1);
+
+ OV2fGeomParam::Sample sample(
+ V2fArraySample(&uvs.front(), uvs.size()),
+ UInt32ArraySample(&indices.front(), indices.size()),
+ kFacevaryingScope);
+
+ param.set(sample);
+}
+
+/* Convention to write Vertex Colors:
+ * - C3fGeomParam/C4fGeomParam on the arbGeomParam
+ * - set scope as vertex varying
+ */
+static void write_mcol(const OCompoundProperty &prop, const CDStreamConfig &config, void *data, const char *name)
+{
+ const float cscale = 1.0f / 255.0f;
+ MPoly *polys = config.mpoly;
+ MLoop *mloops = config.mloop;
+ MCol *cfaces = static_cast<MCol *>(data);
+
+ std::vector<Imath::C4f> buffer(config.totvert);
+
+ Imath::C4f col;
+
+ for (int i = 0; i < config.totpoly; ++i) {
+ MPoly *p = &polys[i];
+ MCol *cface = &cfaces[p->loopstart + p->totloop];
+ MLoop *mloop = &mloops[p->loopstart + p->totloop];
+
+ for (int j = 0; j < p->totloop; ++j) {
+ cface--;
+ mloop--;
+
+ col[0] = cface->a * cscale;
+ col[1] = cface->r * cscale;
+ col[2] = cface->g * cscale;
+ col[3] = cface->b * cscale;
+
+ buffer[mloop->v] = col;
+ }
+ }
+
+ OC4fGeomParam param(prop, name, true, kFacevaryingScope, 1);
+
+ OC4fGeomParam::Sample sample(
+ C4fArraySample(&buffer.front(), buffer.size()),
+ kVertexScope);
+
+ param.set(sample);
+}
+
+void write_custom_data(const OCompoundProperty &prop, const CDStreamConfig &config, CustomData *data, int data_type)
+{
+ CustomDataType cd_data_type = static_cast<CustomDataType>(data_type);
+
+ if (!CustomData_has_layer(data, cd_data_type)) {
+ return;
+ }
+
+ const int active_layer = CustomData_get_active_layer(data, cd_data_type);
+ const int tot_layers = CustomData_number_of_layers(data, cd_data_type);
+
+ for (int i = 0; i < tot_layers; ++i) {
+ void *cd_data = CustomData_get_layer_n(data, cd_data_type, i);
+ const char *name = CustomData_get_layer_name(data, cd_data_type, i);
+
+ if (cd_data_type == CD_MLOOPUV) {
+ /* Already exported. */
+ if (i == active_layer) {
+ continue;
+ }
+
+ write_uv(prop, config, cd_data, name);
+ }
+ else if (cd_data_type == CD_MLOOPCOL) {
+ write_mcol(prop, config, cd_data, name);
+ }
+ }
+}
+
+/* ************************************************************************** */
+
+using Alembic::Abc::C3fArraySamplePtr;
+using Alembic::Abc::C4fArraySamplePtr;
+using Alembic::Abc::PropertyHeader;
+
+using Alembic::AbcGeom::IC3fGeomParam;
+using Alembic::AbcGeom::IC4fGeomParam;
+using Alembic::AbcGeom::IV2fGeomParam;
+
+static void read_mcols(const CDStreamConfig &config, void *data,
+ const C3fArraySamplePtr &c3f_ptr, const C4fArraySamplePtr &c4f_ptr)
+{
+ MCol *cfaces = static_cast<MCol *>(data);
+ MPoly *polys = config.mpoly;
+ MLoop *mloops = config.mloop;
+
+ if (c3f_ptr) {
+ for (int i = 0; i < config.totpoly; ++i) {
+ MPoly *p = &polys[i];
+ MCol *cface = &cfaces[p->loopstart + p->totloop];
+ MLoop *mloop = &mloops[p->loopstart + p->totloop];
+
+ for (int j = 0; j < p->totloop; ++j) {
+ cface--;
+ mloop--;
+ const Imath::C3f &color = (*c3f_ptr)[mloop->v];
+ cface->a = FTOCHAR(color[0]);
+ cface->r = FTOCHAR(color[1]);
+ cface->g = FTOCHAR(color[2]);
+ cface->b = 255;
+ }
+ }
+ }
+ else if (c4f_ptr) {
+ for (int i = 0; i < config.totpoly; ++i) {
+ MPoly *p = &polys[i];
+ MCol *cface = &cfaces[p->loopstart + p->totloop];
+ MLoop *mloop = &mloops[p->loopstart + p->totloop];
+
+ for (int j = 0; j < p->totloop; ++j) {
+ cface--;
+ mloop--;
+ const Imath::C4f &color = (*c4f_ptr)[mloop->v];
+ cface->a = FTOCHAR(color[0]);
+ cface->r = FTOCHAR(color[1]);
+ cface->g = FTOCHAR(color[2]);
+ cface->b = FTOCHAR(color[3]);
+ }
+ }
+ }
+}
+
+static void read_uvs(const CDStreamConfig &config, void *data,
+ const Alembic::AbcGeom::V2fArraySamplePtr &uvs,
+ const Alembic::AbcGeom::UInt32ArraySamplePtr &indices)
+{
+ MPoly *mpolys = config.mpoly;
+ MLoopUV *mloopuvs = static_cast<MLoopUV *>(data);
+
+ unsigned int uv_index, loop_index;
+
+ for (int i = 0; i < config.totpoly; ++i) {
+ MPoly &poly = mpolys[i];
+
+ for (int f = 0; f < poly.totloop; ++f) {
+ loop_index = poly.loopstart + f;
+ uv_index = (*indices)[loop_index];
+ const Imath::V2f &uv = (*uvs)[uv_index];
+
+ MLoopUV &loopuv = mloopuvs[loop_index];
+ loopuv.uv[0] = uv[0];
+ loopuv.uv[1] = uv[1];
+ }
+ }
+}
+
+static void read_custom_data_ex(const ICompoundProperty &prop,
+ const PropertyHeader &prop_header,
+ const CDStreamConfig &config,
+ const Alembic::Abc::ISampleSelector &iss,
+ int data_type)
+{
+ if (data_type == CD_MLOOPCOL) {
+ C3fArraySamplePtr c3f_ptr = C3fArraySamplePtr();
+ C4fArraySamplePtr c4f_ptr = C4fArraySamplePtr();
+
+ if (IC3fGeomParam::matches(prop_header)) {
+ IC3fGeomParam color_param(prop, prop_header.getName());
+ IC3fGeomParam::Sample sample;
+ color_param.getIndexed(sample, iss);
+
+ c3f_ptr = sample.getVals();
+ }
+ else if (IC4fGeomParam::matches(prop_header)) {
+ IC4fGeomParam color_param(prop, prop_header.getName());
+ IC4fGeomParam::Sample sample;
+ color_param.getIndexed(sample, iss);
+
+ c4f_ptr = sample.getVals();
+ }
+
+ void *cd_data = config.add_customdata_cb(config.user_data,
+ prop_header.getName().c_str(),
+ data_type);
+
+ read_mcols(config, cd_data, c3f_ptr, c4f_ptr);
+ }
+ else if (data_type == CD_MLOOPUV) {
+ IV2fGeomParam uv_param(prop, prop_header.getName());
+ IV2fGeomParam::Sample sample;
+ uv_param.getIndexed(sample, iss);
+
+ if (uv_param.getScope() != kFacevaryingScope) {
+ return;
+ }
+
+ void *cd_data = config.add_customdata_cb(config.user_data,
+ prop_header.getName().c_str(),
+ data_type);
+
+ read_uvs(config, cd_data, sample.getVals(), sample.getIndices());
+ }
+}
+
+void read_custom_data(const ICompoundProperty &prop, const CDStreamConfig &config, const Alembic::Abc::ISampleSelector &iss)
+{
+ if (!prop.valid()) {
+ return;
+ }
+
+ int num_uvs = 0;
+ int num_colors = 0;
+
+ const size_t num_props = prop.getNumProperties();
+
+ for (size_t i = 0; i < num_props; ++i) {
+ const Alembic::Abc::PropertyHeader &prop_header = prop.getPropertyHeader(i);
+
+ /* Read UVs according to convention. */
+ if (IV2fGeomParam::matches(prop_header) && Alembic::AbcGeom::isUV(prop_header)) {
+ if (++num_uvs > MAX_MTFACE) {
+ continue;
+ }
+
+ read_custom_data_ex(prop, prop_header, config, iss, CD_MLOOPUV);
+ continue;
+ }
+
+ /* Read vertex colors according to convention. */
+ if (IC3fGeomParam::matches(prop_header) || IC4fGeomParam::matches(prop_header)) {
+ if (++num_colors > MAX_MCOL) {
+ continue;
+ }
+
+ read_custom_data_ex(prop, prop_header, config, iss, CD_MLOOPCOL);
+ continue;
+ }
+ }
+}
diff --git a/source/blender/alembic/intern/abc_customdata.h b/source/blender/alembic/intern/abc_customdata.h
new file mode 100644
index 00000000000..bc42e24eba1
--- /dev/null
+++ b/source/blender/alembic/intern/abc_customdata.h
@@ -0,0 +1,102 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Kévin Dietrich.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+#ifndef __ABC_CUSTOMDATA_H__
+#define __ABC_CUSTOMDATA_H__
+
+#include <Alembic/Abc/All.h>
+
+struct CustomData;
+struct MLoop;
+struct MLoopUV;
+struct MPoly;
+struct MVert;
+
+using Alembic::Abc::ICompoundProperty;
+using Alembic::Abc::OCompoundProperty;
+
+struct UVSample {
+ std::vector<Imath::V2f> uvs;
+ std::vector<uint32_t> indices;
+};
+
+struct CDStreamConfig {
+ MLoop *mloop;
+ int totloop;
+
+ MPoly *mpoly;
+ int totpoly;
+
+ MVert *mvert;
+ int totvert;
+
+ MLoopUV *mloopuv;
+
+ CustomData *loopdata;
+
+ bool pack_uvs;
+
+ /* TODO(kevin): might need a better way to handle adding and/or updating
+ * custom datas such that it updates the custom data holder and its pointers
+ * properly. */
+ void *user_data;
+ void *(*add_customdata_cb)(void *user_data, const char *name, int data_type);
+
+ float weight;
+ float time;
+ int index;
+ int ceil_index;
+
+ CDStreamConfig()
+ : mloop(NULL)
+ , totloop(0)
+ , mpoly(NULL)
+ , totpoly(0)
+ , totvert(0)
+ , pack_uvs(false)
+ , user_data(NULL)
+ , add_customdata_cb(NULL)
+ , weight(0.0f)
+ , time(0.0f)
+ , index(0)
+ , ceil_index(0)
+ {}
+};
+
+/* Get the UVs for the main UV property on a OSchema.
+ * Returns the name of the UV layer.
+ *
+ * For now the active layer is used, maybe needs a better way to choose this. */
+const char *get_uv_sample(UVSample &sample, const CDStreamConfig &config, CustomData *data);
+
+void write_custom_data(const OCompoundProperty &prop,
+ const CDStreamConfig &config,
+ CustomData *data,
+ int data_type);
+
+void read_custom_data(const ICompoundProperty &prop,
+ const CDStreamConfig &config,
+ const Alembic::Abc::ISampleSelector &iss);
+
+#endif /* __ABC_CUSTOMDATA_H__ */
diff --git a/source/blender/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc
new file mode 100644
index 00000000000..d259721e192
--- /dev/null
+++ b/source/blender/alembic/intern/abc_exporter.cc
@@ -0,0 +1,584 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "abc_exporter.h"
+
+#include <cmath>
+
+#include "abc_archive.h"
+#include "abc_camera.h"
+#include "abc_curves.h"
+#include "abc_hair.h"
+#include "abc_mesh.h"
+#include "abc_nurbs.h"
+#include "abc_points.h"
+#include "abc_transform.h"
+#include "abc_util.h"
+
+extern "C" {
+#include "DNA_camera_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h" /* for FILE_MAX */
+
+#include "BLI_string.h"
+
+#ifdef WIN32
+/* needed for MSCV because of snprintf from BLI_string */
+# include "BLI_winstuff.h"
+#endif
+
+#include "BKE_anim.h"
+#include "BKE_global.h"
+#include "BKE_idprop.h"
+#include "BKE_main.h"
+#include "BKE_modifier.h"
+#include "BKE_particle.h"
+#include "BKE_scene.h"
+}
+
+using Alembic::Abc::TimeSamplingPtr;
+using Alembic::Abc::OBox3dProperty;
+
+/* ************************************************************************** */
+
+ExportSettings::ExportSettings()
+ : scene(NULL)
+ , selected_only(false)
+ , visible_layers_only(false)
+ , renderable_only(false)
+ , frame_start(1)
+ , frame_end(1)
+ , frame_step_xform(1)
+ , frame_step_shape(1)
+ , shutter_open(0.0)
+ , shutter_close(1.0)
+ , global_scale(1.0f)
+ , flatten_hierarchy(false)
+ , export_normals(false)
+ , export_uvs(false)
+ , export_vcols(false)
+ , export_face_sets(false)
+ , export_vweigths(false)
+ , apply_subdiv(false)
+ , use_subdiv_schema(false)
+ , export_child_hairs(true)
+ , export_ogawa(true)
+ , pack_uv(false)
+ , triangulate(false)
+ , quad_method(0)
+ , ngon_method(0)
+ , do_convert_axis(false)
+{}
+
+static bool object_is_smoke_sim(Object *ob)
+{
+ ModifierData *md = modifiers_findByType(ob, eModifierType_Smoke);
+
+ if (md) {
+ SmokeModifierData *smd = reinterpret_cast<SmokeModifierData *>(md);
+ return (smd->type == MOD_SMOKE_TYPE_DOMAIN);
+ }
+
+ return false;
+}
+
+static bool object_is_shape(Object *ob)
+{
+ switch (ob->type) {
+ case OB_MESH:
+ if (object_is_smoke_sim(ob)) {
+ return false;
+ }
+
+ return true;
+ case OB_CURVE:
+ case OB_SURF:
+ case OB_CAMERA:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool export_object(const ExportSettings * const settings, Object *ob)
+{
+ if (settings->selected_only && !parent_selected(ob)) {
+ return false;
+ }
+
+ if (settings->visible_layers_only && !(settings->scene->lay & ob->lay)) {
+ return false;
+ }
+
+ if (settings->renderable_only && (ob->restrictflag & OB_RESTRICT_RENDER)) {
+ return false;
+ }
+
+ return true;
+}
+
+/* ************************************************************************** */
+
+AbcExporter::AbcExporter(Scene *scene, const char *filename, ExportSettings &settings)
+ : m_settings(settings)
+ , m_filename(filename)
+ , m_trans_sampling_index(0)
+ , m_shape_sampling_index(0)
+ , m_scene(scene)
+ , m_writer(NULL)
+{}
+
+AbcExporter::~AbcExporter()
+{
+ std::map<std::string, AbcTransformWriter*>::iterator it, e;
+ for (it = m_xforms.begin(), e = m_xforms.end(); it != e; ++it) {
+ delete it->second;
+ }
+
+ for (int i = 0, e = m_shapes.size(); i != e; ++i) {
+ delete m_shapes[i];
+ }
+
+ delete m_writer;
+}
+
+void AbcExporter::getShutterSamples(double step, bool time_relative,
+ std::vector<double> &samples)
+{
+ samples.clear();
+
+ const double time_factor = time_relative ? m_scene->r.frs_sec : 1.0;
+ const double shutter_open = m_settings.shutter_open;
+ const double shutter_close = m_settings.shutter_close;
+
+ /* sample all frame */
+ if (shutter_open == 0.0 && shutter_close == 1.0) {
+ for (double t = 0; t < 1.0; t += step) {
+ samples.push_back((t + m_settings.frame_start) / time_factor);
+ }
+ }
+ else {
+ /* sample between shutter open & close */
+ const int nsamples = std::max((1.0 / step) - 1.0, 1.0);
+ const double time_inc = (shutter_close - shutter_open) / nsamples;
+
+ for (double t = shutter_open; t <= shutter_close; t += time_inc) {
+ samples.push_back((t + m_settings.frame_start) / time_factor);
+ }
+ }
+}
+
+Alembic::Abc::TimeSamplingPtr AbcExporter::createTimeSampling(double step)
+{
+ TimeSamplingPtr time_sampling;
+ std::vector<double> samples;
+
+ if (m_settings.frame_start == m_settings.frame_end) {
+ time_sampling.reset(new Alembic::Abc::TimeSampling());
+ return time_sampling;
+ }
+
+ getShutterSamples(step, true, samples);
+
+ Alembic::Abc::TimeSamplingType ts(static_cast<uint32_t>(samples.size()), 1.0 / m_scene->r.frs_sec);
+ time_sampling.reset(new Alembic::Abc::TimeSampling(ts, samples));
+
+ return time_sampling;
+}
+
+void AbcExporter::getFrameSet(double step, std::set<double> &frames)
+{
+ frames.clear();
+
+ std::vector<double> shutter_samples;
+
+ getShutterSamples(step, false, shutter_samples);
+
+ for (int frame = m_settings.frame_start; frame <= m_settings.frame_end; ++frame) {
+ for (int j = 0, e = shutter_samples.size(); j < e; ++j) {
+ frames.insert(frame + shutter_samples[j]);
+ }
+ }
+}
+
+void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled)
+{
+ std::string scene_name;
+
+ if (bmain->name[0] != '\0') {
+ char scene_file_name[FILE_MAX];
+ BLI_strncpy(scene_file_name, bmain->name, FILE_MAX);
+ scene_name = scene_file_name;
+ }
+ else {
+ scene_name = "untitled";
+ }
+
+ Scene *scene = m_scene;
+ const int fps = FPS;
+ char buf[16];
+ snprintf(buf, 15, "%d", fps);
+ const std::string str_fps = buf;
+
+ Alembic::AbcCoreAbstract::MetaData md;
+ md.set("FramesPerTimeUnit", str_fps);
+
+ m_writer = new ArchiveWriter(m_filename, scene_name.c_str(), m_settings.export_ogawa, md);
+
+ /* Create time samplings for transforms and shapes. */
+
+ TimeSamplingPtr trans_time = createTimeSampling(m_settings.frame_step_xform);
+
+ m_trans_sampling_index = m_writer->archive().addTimeSampling(*trans_time);
+
+ TimeSamplingPtr shape_time;
+
+ if ((m_settings.frame_step_shape == m_settings.frame_step_xform) ||
+ (m_settings.frame_start == m_settings.frame_end))
+ {
+ shape_time = trans_time;
+ m_shape_sampling_index = m_trans_sampling_index;
+ }
+ else {
+ shape_time = createTimeSampling(m_settings.frame_step_shape);
+ m_shape_sampling_index = m_writer->archive().addTimeSampling(*shape_time);
+ }
+
+ OBox3dProperty archive_bounds_prop = Alembic::AbcGeom::CreateOArchiveBounds(m_writer->archive(), m_trans_sampling_index);
+
+ if (m_settings.flatten_hierarchy) {
+ createTransformWritersFlat();
+ }
+ else {
+ createTransformWritersHierarchy(bmain->eval_ctx);
+ }
+
+ createShapeWriters(bmain->eval_ctx);
+
+ /* Make a list of frames to export. */
+
+ std::set<double> xform_frames;
+ getFrameSet(m_settings.frame_step_xform, xform_frames);
+
+ std::set<double> shape_frames;
+ getFrameSet(m_settings.frame_step_shape, shape_frames);
+
+ /* Merge all frames needed. */
+
+ std::set<double> frames(xform_frames);
+ frames.insert(shape_frames.begin(), shape_frames.end());
+
+ /* Export all frames. */
+
+ std::set<double>::const_iterator begin = frames.begin();
+ std::set<double>::const_iterator end = frames.end();
+
+ const float size = static_cast<float>(frames.size());
+ size_t i = 0;
+
+ for (; begin != end; ++begin) {
+ progress = (++i / size);
+
+ if (G.is_break) {
+ was_canceled = true;
+ break;
+ }
+
+ const double frame = *begin;
+
+ /* 'frame' is offset by start frame, so need to cancel the offset. */
+ setCurrentFrame(bmain, frame - m_settings.frame_start);
+
+ if (shape_frames.count(frame) != 0) {
+ for (int i = 0, e = m_shapes.size(); i != e; ++i) {
+ m_shapes[i]->write();
+ }
+ }
+
+ if (xform_frames.count(frame) == 0) {
+ continue;
+ }
+
+ std::map<std::string, AbcTransformWriter *>::iterator xit, xe;
+ for (xit = m_xforms.begin(), xe = m_xforms.end(); xit != xe; ++xit) {
+ xit->second->write();
+ }
+
+ /* Save the archive 's bounding box. */
+ Imath::Box3d bounds;
+
+ for (xit = m_xforms.begin(), xe = m_xforms.end(); xit != xe; ++xit) {
+ Imath::Box3d box = xit->second->bounds();
+ bounds.extendBy(box);
+ }
+
+ archive_bounds_prop.set(bounds);
+ }
+}
+
+void AbcExporter::createTransformWritersHierarchy(EvaluationContext *eval_ctx)
+{
+ Base *base = static_cast<Base *>(m_scene->base.first);
+
+ while (base) {
+ Object *ob = base->object;
+
+ if (export_object(&m_settings, ob)) {
+ switch(ob->type) {
+ case OB_LAMP:
+ case OB_LATTICE:
+ case OB_MBALL:
+ case OB_SPEAKER:
+ /* We do not export transforms for objects of these classes. */
+ break;
+
+ default:
+ exploreTransform(eval_ctx, ob, ob->parent, NULL);
+ }
+ }
+
+ base = base->next;
+ }
+}
+
+void AbcExporter::createTransformWritersFlat()
+{
+ Base *base = static_cast<Base *>(m_scene->base.first);
+
+ while (base) {
+ Object *ob = base->object;
+
+ if (export_object(&m_settings, ob) && object_is_shape(ob)) {
+ std::string name = get_id_name(ob);
+ m_xforms[name] = new AbcTransformWriter(ob, m_writer->archive().getTop(), 0, m_trans_sampling_index, m_settings);
+ }
+
+ base = base->next;
+ }
+}
+
+void AbcExporter::exploreTransform(EvaluationContext *eval_ctx, Object *ob, Object *parent, Object *dupliObParent)
+{
+ createTransformWriter(ob, parent, dupliObParent);
+
+ ListBase *lb = object_duplilist(eval_ctx, m_scene, ob);
+
+ if (lb) {
+ DupliObject *link = static_cast<DupliObject *>(lb->first);
+ Object *dupli_ob = NULL;
+ Object *dupli_parent = NULL;
+
+ while (link) {
+ if (link->type == OB_DUPLIGROUP) {
+ dupli_ob = link->ob;
+ dupli_parent = (dupli_ob->parent) ? dupli_ob->parent : ob;
+
+ exploreTransform(eval_ctx, dupli_ob, dupli_parent, ob);
+ }
+
+ link = link->next;
+ }
+ }
+
+ free_object_duplilist(lb);
+}
+
+void AbcExporter::createTransformWriter(Object *ob, Object *parent, Object *dupliObParent)
+{
+ const std::string name = get_object_dag_path_name(ob, dupliObParent);
+
+ /* check if we have already created a transform writer for this object */
+ if (m_xforms.find(name) != m_xforms.end()){
+ std::cerr << "xform " << name << " already exists\n";
+ return;
+ }
+
+ AbcTransformWriter *parent_xform = NULL;
+
+ if (parent) {
+ const std::string parentname = get_object_dag_path_name(parent, dupliObParent);
+ parent_xform = getXForm(parentname);
+
+ if (!parent_xform) {
+ if (parent->parent) {
+ createTransformWriter(parent, parent->parent, dupliObParent);
+ }
+ else {
+ createTransformWriter(parent, dupliObParent, dupliObParent);
+ }
+
+ parent_xform = getXForm(parentname);
+ }
+ }
+
+ if (parent_xform) {
+ m_xforms[name] = new AbcTransformWriter(ob, parent_xform->alembicXform(), parent_xform, m_trans_sampling_index, m_settings);
+ m_xforms[name]->setParent(parent);
+ }
+ else {
+ m_xforms[name] = new AbcTransformWriter(ob, m_writer->archive().getTop(), NULL, m_trans_sampling_index, m_settings);
+ }
+}
+
+void AbcExporter::createShapeWriters(EvaluationContext *eval_ctx)
+{
+ Base *base = static_cast<Base *>(m_scene->base.first);
+
+ while (base) {
+ Object *ob = base->object;
+ exploreObject(eval_ctx, ob, NULL);
+
+ base = base->next;
+ }
+}
+
+void AbcExporter::exploreObject(EvaluationContext *eval_ctx, Object *ob, Object *dupliObParent)
+{
+ ListBase *lb = object_duplilist(eval_ctx, m_scene, ob);
+
+ createShapeWriter(ob, dupliObParent);
+
+ if (lb) {
+ DupliObject *dupliob = static_cast<DupliObject *>(lb->first);
+
+ while (dupliob) {
+ if (dupliob->type == OB_DUPLIGROUP) {
+ exploreObject(eval_ctx, dupliob->ob, ob);
+ }
+
+ dupliob = dupliob->next;
+ }
+ }
+
+ free_object_duplilist(lb);
+}
+
+void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent)
+{
+ if (!object_is_shape(ob)) {
+ return;
+ }
+
+ if (!export_object(&m_settings, ob)) {
+ return;
+ }
+
+ std::string name;
+
+ if (m_settings.flatten_hierarchy) {
+ name = get_id_name(ob);
+ }
+ else {
+ name = get_object_dag_path_name(ob, dupliObParent);
+ }
+
+ AbcTransformWriter *xform = getXForm(name);
+
+ if (!xform) {
+ std::cerr << __func__ << ": xform " << name << " is NULL\n";
+ return;
+ }
+
+ ParticleSystem *psys = static_cast<ParticleSystem *>(ob->particlesystem.first);
+
+ for (; psys; psys = psys->next) {
+ if (!psys_check_enabled(ob, psys, G.is_rendering) || !psys->part) {
+ continue;
+ }
+
+ if (psys->part->type == PART_HAIR) {
+ m_settings.export_child_hairs = true;
+ m_shapes.push_back(new AbcHairWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings, psys));
+ }
+ else if (psys->part->type == PART_EMITTER) {
+ m_shapes.push_back(new AbcPointsWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings, psys));
+ }
+ }
+
+ switch(ob->type) {
+ case OB_MESH:
+ {
+ Mesh *me = static_cast<Mesh *>(ob->data);
+
+ if (!me || me->totvert == 0) {
+ return;
+ }
+
+ m_shapes.push_back(new AbcMeshWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings));
+ break;
+ }
+ case OB_SURF:
+ {
+ Curve *cu = static_cast<Curve *>(ob->data);
+
+ if (!cu) {
+ return;
+ }
+
+ m_shapes.push_back(new AbcNurbsWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings));
+ break;
+ }
+ case OB_CURVE:
+ {
+ Curve *cu = static_cast<Curve *>(ob->data);
+
+ if (!cu) {
+ return;
+ }
+
+ m_shapes.push_back(new AbcCurveWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings));
+ break;
+ }
+ case OB_CAMERA:
+ {
+ Camera *cam = static_cast<Camera *>(ob->data);
+
+ if (cam->type == CAM_PERSP) {
+ m_shapes.push_back(new AbcCameraWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings));
+ }
+
+ break;
+ }
+ }
+}
+
+AbcTransformWriter *AbcExporter::getXForm(const std::string &name)
+{
+ std::map<std::string, AbcTransformWriter *>::iterator it = m_xforms.find(name);
+
+ if (it == m_xforms.end()) {
+ return NULL;
+ }
+
+ return it->second;
+}
+
+void AbcExporter::setCurrentFrame(Main *bmain, double t)
+{
+ m_scene->r.cfra = std::floor(t);
+ m_scene->r.subframe = t - m_scene->r.cfra;
+ BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, m_scene, m_scene->lay);
+}
diff --git a/source/blender/alembic/intern/abc_exporter.h b/source/blender/alembic/intern/abc_exporter.h
new file mode 100644
index 00000000000..b0eb8e185d6
--- /dev/null
+++ b/source/blender/alembic/intern/abc_exporter.h
@@ -0,0 +1,118 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __ABC_EXPORTER_H__
+#define __ABC_EXPORTER_H__
+
+#include <Alembic/Abc/All.h>
+#include <map>
+#include <set>
+#include <vector>
+
+class AbcObjectWriter;
+class AbcTransformWriter;
+class ArchiveWriter;
+
+struct EvaluationContext;
+struct Main;
+struct Object;
+struct Scene;
+
+struct ExportSettings {
+ ExportSettings();
+
+ Scene *scene;
+
+ bool selected_only;
+ bool visible_layers_only;
+ bool renderable_only;
+
+ double frame_start, frame_end;
+ double frame_step_xform;
+ double frame_step_shape;
+ double shutter_open;
+ double shutter_close;
+ float global_scale;
+
+ bool flatten_hierarchy;
+
+ bool export_normals;
+ bool export_uvs;
+ bool export_vcols;
+ bool export_face_sets;
+ bool export_vweigths;
+
+ bool apply_subdiv;
+ bool use_subdiv_schema;
+ bool export_child_hairs;
+ bool export_ogawa;
+ bool pack_uv;
+ bool triangulate;
+
+ int quad_method;
+ int ngon_method;
+
+ bool do_convert_axis;
+ float convert_matrix[3][3];
+};
+
+class AbcExporter {
+ ExportSettings &m_settings;
+
+ const char *m_filename;
+
+ unsigned int m_trans_sampling_index, m_shape_sampling_index;
+
+ Scene *m_scene;
+
+ ArchiveWriter *m_writer;
+
+ std::map<std::string, AbcTransformWriter *> m_xforms;
+ std::vector<AbcObjectWriter *> m_shapes;
+
+public:
+ AbcExporter(Scene *scene, const char *filename, ExportSettings &settings);
+ ~AbcExporter();
+
+ void operator()(Main *bmain, float &progress, bool &was_canceled);
+
+private:
+ void getShutterSamples(double step, bool time_relative, std::vector<double> &samples);
+
+ Alembic::Abc::TimeSamplingPtr createTimeSampling(double step);
+
+ void getFrameSet(double step, std::set<double> &frames);
+
+ void createTransformWritersHierarchy(EvaluationContext *eval_ctx);
+ void createTransformWritersFlat();
+ void createTransformWriter(Object *ob, Object *parent, Object *dupliObParent);
+ void exploreTransform(EvaluationContext *eval_ctx, Object *ob, Object *parent, Object *dupliObParent = NULL);
+ void exploreObject(EvaluationContext *eval_ctx, Object *ob, Object *dupliObParent);
+ void createShapeWriters(EvaluationContext *eval_ctx);
+ void createShapeWriter(Object *ob, Object *dupliObParent);
+
+ AbcTransformWriter *getXForm(const std::string &name);
+
+ void setCurrentFrame(Main *bmain, double t);
+};
+
+#endif /* __ABC_EXPORTER_H__ */
diff --git a/source/blender/alembic/intern/abc_hair.cc b/source/blender/alembic/intern/abc_hair.cc
new file mode 100644
index 00000000000..14bcf6731ea
--- /dev/null
+++ b/source/blender/alembic/intern/abc_hair.cc
@@ -0,0 +1,290 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "abc_hair.h"
+
+#include <cstdio>
+
+#include "abc_transform.h"
+#include "abc_util.h"
+
+extern "C" {
+#include "MEM_guardedalloc.h"
+
+#include "DNA_modifier_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math_geom.h"
+
+#include "BKE_DerivedMesh.h"
+#include "BKE_object.h"
+#include "BKE_particle.h"
+}
+
+using Alembic::Abc::P3fArraySamplePtr;
+
+using Alembic::AbcGeom::OCurves;
+using Alembic::AbcGeom::OCurvesSchema;
+using Alembic::AbcGeom::ON3fGeomParam;
+using Alembic::AbcGeom::OV2fGeomParam;
+
+/* ************************************************************************** */
+
+AbcHairWriter::AbcHairWriter(Scene *scene,
+ Object *ob,
+ AbcTransformWriter *parent,
+ uint32_t time_sampling,
+ ExportSettings &settings,
+ ParticleSystem *psys)
+ : AbcObjectWriter(scene, ob, time_sampling, settings, parent)
+{
+ m_psys = psys;
+
+ OCurves curves(parent->alembicXform(), psys->name, m_time_sampling);
+ m_schema = curves.getSchema();
+}
+
+void AbcHairWriter::do_write()
+{
+ if (!m_psys) {
+ return;
+ }
+
+ ParticleSystemModifierData *psmd = psys_get_modifier(m_object, m_psys);
+
+ if (!psmd->dm_final) {
+ return;
+ }
+
+ DerivedMesh *dm = mesh_create_derived_view(m_scene, m_object, CD_MASK_MESH);
+ DM_ensure_tessface(dm);
+ DM_update_tessface_data(dm);
+
+ std::vector<Imath::V3f> verts;
+ std::vector<int32_t> hvertices;
+ std::vector<Imath::V2f> uv_values;
+ std::vector<Imath::V3f> norm_values;
+
+ if (m_psys->pathcache) {
+ ParticleSettings *part = m_psys->part;
+
+ write_hair_sample(dm, part, verts, norm_values, uv_values, hvertices);
+
+ if (m_settings.export_child_hairs && m_psys->childcache) {
+ write_hair_child_sample(dm, part, verts, norm_values, uv_values, hvertices);
+ }
+ }
+
+ dm->release(dm);
+
+ Alembic::Abc::P3fArraySample iPos(verts);
+ m_sample = OCurvesSchema::Sample(iPos, hvertices);
+ m_sample.setBasis(Alembic::AbcGeom::kNoBasis);
+ m_sample.setType(Alembic::AbcGeom::kLinear);
+ m_sample.setWrap(Alembic::AbcGeom::kNonPeriodic);
+
+ if (!uv_values.empty()) {
+ OV2fGeomParam::Sample uv_smp;
+ uv_smp.setVals(uv_values);
+ m_sample.setUVs(uv_smp);
+ }
+
+ if (!norm_values.empty()) {
+ ON3fGeomParam::Sample norm_smp;
+ norm_smp.setVals(norm_values);
+ m_sample.setNormals(norm_smp);
+ }
+
+ m_sample.setSelfBounds(bounds());
+ m_schema.set(m_sample);
+}
+
+void AbcHairWriter::write_hair_sample(DerivedMesh *dm,
+ ParticleSettings *part,
+ std::vector<Imath::V3f> &verts,
+ std::vector<Imath::V3f> &norm_values,
+ std::vector<Imath::V2f> &uv_values,
+ std::vector<int32_t> &hvertices)
+{
+ /* Get untransformed vertices, there's a xform under the hair. */
+ float inv_mat[4][4];
+ invert_m4_m4_safe(inv_mat, m_object->obmat);
+
+ MTFace *mtface = static_cast<MTFace *>(CustomData_get_layer(&dm->faceData, CD_MTFACE));
+ MFace *mface = dm->getTessFaceArray(dm);
+ MVert *mverts = dm->getVertArray(dm);
+
+ if (!mtface || !mface) {
+ std::fprintf(stderr, "Warning, no UV set found for underlying geometry.\n");
+ }
+
+ ParticleData * pa = m_psys->particles;
+ int k;
+
+ ParticleCacheKey **cache = m_psys->pathcache;
+ ParticleCacheKey *path;
+ float normal[3];
+ Imath::V3f tmp_nor;
+
+ for (int p = 0; p < m_psys->totpart; ++p, ++pa) {
+ /* underlying info for faces-only emission */
+ path = cache[p];
+
+ if (part->from == PART_FROM_FACE && mtface) {
+ const int num = pa->num_dmcache >= 0 ? pa->num_dmcache : pa->num;
+
+ if (num < dm->getNumTessFaces(dm)) {
+ MFace *face = static_cast<MFace *>(dm->getTessFaceData(dm, num, CD_MFACE));
+ MTFace *tface = mtface + num;
+
+ if (mface) {
+ float r_uv[2], mapfw[4], vec[3];
+
+ psys_interpolate_uvs(tface, face->v4, pa->fuv, r_uv);
+ uv_values.push_back(Imath::V2f(r_uv[0], r_uv[1]));
+
+ psys_interpolate_face(mverts, face, tface, NULL, mapfw, vec, normal, NULL, NULL, NULL, NULL);
+
+ copy_zup_yup(tmp_nor.getValue(), normal);
+ norm_values.push_back(tmp_nor);
+ }
+ }
+ else {
+ std::fprintf(stderr, "Particle to faces overflow (%d/%d)\n", num, dm->getNumTessFaces(dm));
+ }
+ }
+ else if (part->from == PART_FROM_VERT && mtface) {
+ /* vertex id */
+ const int num = (pa->num_dmcache >= 0) ? pa->num_dmcache : pa->num;
+
+ /* iterate over all faces to find a corresponding underlying UV */
+ for (int n = 0; n < dm->getNumTessFaces(dm); ++n) {
+ MFace *face = static_cast<MFace *>(dm->getTessFaceData(dm, n, CD_MFACE));
+ MTFace *tface = mtface + n;
+ unsigned int vtx[4];
+ vtx[0] = face->v1;
+ vtx[1] = face->v2;
+ vtx[2] = face->v3;
+ vtx[3] = face->v4;
+ bool found = false;
+
+ for (int o = 0; o < 4; ++o) {
+ if (o > 2 && vtx[o] == 0) {
+ break;
+ }
+
+ if (vtx[o] == num) {
+ uv_values.push_back(Imath::V2f(tface->uv[o][0], tface->uv[o][1]));
+
+ MVert *mv = mverts + vtx[o];
+
+ normal_short_to_float_v3(normal, mv->no);
+ copy_zup_yup(tmp_nor.getValue(), normal);
+ norm_values.push_back(tmp_nor);
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ break;
+ }
+ }
+ }
+
+ int steps = path->segments + 1;
+ hvertices.push_back(steps);
+
+ for (k = 0; k < steps; ++k) {
+ float vert[3];
+ copy_v3_v3(vert, path->co);
+ mul_m4_v3(inv_mat, vert);
+
+ /* Convert Z-up to Y-up. */
+ verts.push_back(Imath::V3f(vert[0], vert[2], -vert[1]));
+
+ ++path;
+ }
+ }
+}
+
+void AbcHairWriter::write_hair_child_sample(DerivedMesh *dm,
+ ParticleSettings *part,
+ std::vector<Imath::V3f> &verts,
+ std::vector<Imath::V3f> &norm_values,
+ std::vector<Imath::V2f> &uv_values,
+ std::vector<int32_t> &hvertices)
+{
+ /* Get untransformed vertices, there's a xform under the hair. */
+ float inv_mat[4][4];
+ invert_m4_m4_safe(inv_mat, m_object->obmat);
+
+ MTFace *mtface = static_cast<MTFace *>(CustomData_get_layer(&dm->faceData, CD_MTFACE));
+ MFace *mface = dm->getTessFaceArray(dm);
+ MVert *mverts = dm->getVertArray(dm);
+
+ if (!mtface || !mface) {
+ std::fprintf(stderr, "Warning, no UV set found for underlying geometry.\n");
+ }
+
+ ParticleCacheKey **cache = m_psys->childcache;
+ ParticleCacheKey *path;
+
+ ChildParticle *pc = m_psys->child;
+
+ for (int p = 0; p < m_psys->totchild; ++p, ++pc) {
+ path = cache[p];
+
+ if (part->from == PART_FROM_FACE) {
+ const int num = pc->num;
+
+ MFace *face = static_cast<MFace *>(dm->getTessFaceData(dm, num, CD_MFACE));
+ MTFace *tface = mtface + num;
+
+ if (mface && mtface) {
+ float r_uv[2], tmpnor[3], mapfw[4], vec[3];
+
+ psys_interpolate_uvs(tface, face->v4, pc->fuv, r_uv);
+ uv_values.push_back(Imath::V2f(r_uv[0], r_uv[1]));
+
+ psys_interpolate_face(mverts, face, tface, NULL, mapfw, vec, tmpnor, NULL, NULL, NULL, NULL);
+
+ /* Convert Z-up to Y-up. */
+ norm_values.push_back(Imath::V3f(tmpnor[0], tmpnor[2], -tmpnor[1]));
+ }
+ }
+
+ int steps = path->segments + 1;
+ hvertices.push_back(steps);
+
+ for (int k = 0; k < steps; ++k) {
+ float vert[3];
+ copy_v3_v3(vert, path->co);
+ mul_m4_v3(inv_mat, vert);
+
+ /* Convert Z-up to Y-up. */
+ verts.push_back(Imath::V3f(vert[0], vert[2], -vert[1]));
+
+ ++path;
+ }
+ }
+}
diff --git a/source/blender/alembic/intern/abc_hair.h b/source/blender/alembic/intern/abc_hair.h
new file mode 100644
index 00000000000..d132b60be12
--- /dev/null
+++ b/source/blender/alembic/intern/abc_hair.h
@@ -0,0 +1,66 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __ABC_HAIR_H__
+#define __ABC_HAIR_H__
+
+#include "abc_object.h"
+
+struct DerivedMesh;
+struct ParticleSettings;
+struct ParticleSystem;
+
+/* ************************************************************************** */
+
+class AbcHairWriter : public AbcObjectWriter {
+ ParticleSystem *m_psys;
+
+ Alembic::AbcGeom::OCurvesSchema m_schema;
+ Alembic::AbcGeom::OCurvesSchema::Sample m_sample;
+
+public:
+ AbcHairWriter(Scene *scene,
+ Object *ob,
+ AbcTransformWriter *parent,
+ uint32_t time_sampling,
+ ExportSettings &settings,
+ ParticleSystem *psys);
+
+private:
+ virtual void do_write();
+
+ void write_hair_sample(DerivedMesh *dm,
+ ParticleSettings *part,
+ std::vector<Imath::V3f> &verts,
+ std::vector<Imath::V3f> &norm_values,
+ std::vector<Imath::V2f> &uv_values,
+ std::vector<int32_t> &hvertices);
+
+ void write_hair_child_sample(DerivedMesh *dm,
+ ParticleSettings *part,
+ std::vector<Imath::V3f> &verts,
+ std::vector<Imath::V3f> &norm_values,
+ std::vector<Imath::V2f> &uv_values,
+ std::vector<int32_t> &hvertices);
+};
+
+#endif /* __ABC_HAIR_H__ */
diff --git a/source/blender/alembic/intern/abc_mesh.cc b/source/blender/alembic/intern/abc_mesh.cc
new file mode 100644
index 00000000000..5b282e3c5bb
--- /dev/null
+++ b/source/blender/alembic/intern/abc_mesh.cc
@@ -0,0 +1,1303 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "abc_mesh.h"
+
+#include <algorithm>
+
+#include "abc_transform.h"
+#include "abc_util.h"
+
+extern "C" {
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_fluidsim.h"
+#include "DNA_object_types.h"
+
+#include "BLI_math_geom.h"
+#include "BLI_string.h"
+
+#include "BKE_cdderivedmesh.h"
+#include "BKE_depsgraph.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_mesh.h"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
+}
+
+using Alembic::Abc::FloatArraySample;
+using Alembic::Abc::ICompoundProperty;
+using Alembic::Abc::Int32ArraySample;
+using Alembic::Abc::Int32ArraySamplePtr;
+using Alembic::Abc::P3fArraySamplePtr;
+using Alembic::Abc::V2fArraySample;
+using Alembic::Abc::V3fArraySample;
+using Alembic::Abc::C4fArraySample;
+
+using Alembic::AbcGeom::IFaceSet;
+using Alembic::AbcGeom::IFaceSetSchema;
+using Alembic::AbcGeom::IObject;
+using Alembic::AbcGeom::IPolyMesh;
+using Alembic::AbcGeom::IPolyMeshSchema;
+using Alembic::AbcGeom::ISampleSelector;
+using Alembic::AbcGeom::ISubD;
+using Alembic::AbcGeom::ISubDSchema;
+using Alembic::AbcGeom::IV2fGeomParam;
+
+using Alembic::AbcGeom::OArrayProperty;
+using Alembic::AbcGeom::OBoolProperty;
+using Alembic::AbcGeom::OC3fArrayProperty;
+using Alembic::AbcGeom::OC3fGeomParam;
+using Alembic::AbcGeom::OC4fGeomParam;
+using Alembic::AbcGeom::OCompoundProperty;
+using Alembic::AbcGeom::OFaceSet;
+using Alembic::AbcGeom::OFaceSetSchema;
+using Alembic::AbcGeom::OFloatGeomParam;
+using Alembic::AbcGeom::OInt32GeomParam;
+using Alembic::AbcGeom::ON3fArrayProperty;
+using Alembic::AbcGeom::ON3fGeomParam;
+using Alembic::AbcGeom::OPolyMesh;
+using Alembic::AbcGeom::OPolyMeshSchema;
+using Alembic::AbcGeom::OSubD;
+using Alembic::AbcGeom::OSubDSchema;
+using Alembic::AbcGeom::OV2fGeomParam;
+using Alembic::AbcGeom::OV3fGeomParam;
+
+using Alembic::AbcGeom::kFacevaryingScope;
+using Alembic::AbcGeom::kVaryingScope;
+using Alembic::AbcGeom::kVertexScope;
+using Alembic::AbcGeom::kWrapExisting;
+using Alembic::AbcGeom::UInt32ArraySample;
+using Alembic::AbcGeom::N3fArraySamplePtr;
+using Alembic::AbcGeom::IN3fGeomParam;
+
+/* ************************************************************************** */
+
+/* NOTE: Alembic's polygon winding order is clockwise, to match with Renderman. */
+
+static void get_vertices(DerivedMesh *dm, std::vector<Imath::V3f> &points)
+{
+ points.clear();
+ points.resize(dm->getNumVerts(dm));
+
+ MVert *verts = dm->getVertArray(dm);
+
+ for (int i = 0, e = dm->getNumVerts(dm); i < e; ++i) {
+ copy_zup_yup(points[i].getValue(), verts[i].co);
+ }
+}
+
+static void get_topology(DerivedMesh *dm,
+ std::vector<int32_t> &poly_verts,
+ std::vector<int32_t> &loop_counts,
+ bool &smooth_normal)
+{
+ const int num_poly = dm->getNumPolys(dm);
+ const int num_loops = dm->getNumLoops(dm);
+ MLoop *mloop = dm->getLoopArray(dm);
+ MPoly *mpoly = dm->getPolyArray(dm);
+
+ poly_verts.clear();
+ loop_counts.clear();
+ poly_verts.reserve(num_loops);
+ loop_counts.reserve(num_poly);
+
+ /* NOTE: data needs to be written in the reverse order. */
+ for (int i = 0; i < num_poly; ++i) {
+ MPoly &poly = mpoly[i];
+ loop_counts.push_back(poly.totloop);
+
+ smooth_normal |= ((poly.flag & ME_SMOOTH) != 0);
+
+ MLoop *loop = mloop + poly.loopstart + (poly.totloop - 1);
+
+ for (int j = 0; j < poly.totloop; ++j, --loop) {
+ poly_verts.push_back(loop->v);
+ }
+ }
+}
+
+static void get_creases(DerivedMesh *dm,
+ std::vector<int32_t> &indices,
+ std::vector<int32_t> &lengths,
+ std::vector<float> &sharpnesses)
+{
+ const float factor = 1.0f / 255.0f;
+
+ indices.clear();
+ lengths.clear();
+ sharpnesses.clear();
+
+ MEdge *edge = dm->getEdgeArray(dm);
+
+ for (int i = 0, e = dm->getNumEdges(dm); i < e; ++i) {
+ const float sharpness = static_cast<float>(edge[i].crease) * factor;
+
+ if (sharpness != 0.0f) {
+ indices.push_back(edge[i].v1);
+ indices.push_back(edge[i].v2);
+ sharpnesses.push_back(sharpness);
+ }
+ }
+
+ lengths.resize(sharpnesses.size(), 2);
+}
+
+static void get_vertex_normals(DerivedMesh *dm, std::vector<Imath::V3f> &normals)
+{
+ normals.clear();
+ normals.resize(dm->getNumVerts(dm));
+
+ MVert *verts = dm->getVertArray(dm);
+ float no[3];
+
+ for (int i = 0, e = dm->getNumVerts(dm); i < e; ++i) {
+ normal_short_to_float_v3(no, verts[i].no);
+ copy_zup_yup(normals[i].getValue(), no);
+ }
+}
+
+static void get_loop_normals(DerivedMesh *dm, std::vector<Imath::V3f> &normals)
+{
+ MPoly *mpoly = dm->getPolyArray(dm);
+ MPoly *mp = mpoly;
+
+ MLoop *mloop = dm->getLoopArray(dm);
+ MLoop *ml = mloop;
+
+ MVert *verts = dm->getVertArray(dm);
+
+ const float (*lnors)[3] = static_cast<float(*)[3]>(dm->getLoopDataArray(dm, CD_NORMAL));
+
+ normals.clear();
+ normals.resize(dm->getNumLoops(dm));
+
+ unsigned loop_index = 0;
+
+ /* NOTE: data needs to be written in the reverse order. */
+
+ if (lnors) {
+ for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i, ++mp) {
+ ml = mloop + mp->loopstart + (mp->totloop - 1);
+
+ for (int j = 0; j < mp->totloop; --ml, ++j, ++loop_index) {
+ const int index = ml->v;
+ copy_zup_yup(normals[loop_index].getValue(), lnors[index]);
+ }
+ }
+ }
+ else {
+ float no[3];
+
+ for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i, ++mp) {
+ ml = mloop + mp->loopstart + (mp->totloop - 1);
+
+ /* Flat shaded, use common normal for all verts. */
+ if ((mp->flag & ME_SMOOTH) == 0) {
+ BKE_mesh_calc_poly_normal(mp, ml - (mp->totloop - 1), verts, no);
+
+ for (int j = 0; j < mp->totloop; --ml, ++j, ++loop_index) {
+ copy_zup_yup(normals[loop_index].getValue(), no);
+ }
+ }
+ else {
+ /* Smooth shaded, use individual vert normals. */
+ for (int j = 0; j < mp->totloop; --ml, ++j, ++loop_index) {
+ normal_short_to_float_v3(no, verts[ml->v].no);
+ copy_zup_yup(normals[loop_index].getValue(), no);
+ }
+ }
+ }
+ }
+}
+
+/* *************** Modifiers *************** */
+
+/* check if the mesh is a subsurf, ignoring disabled modifiers and
+ * displace if it's after subsurf. */
+static ModifierData *get_subsurf_modifier(Scene *scene, Object *ob)
+{
+ ModifierData *md = static_cast<ModifierData *>(ob->modifiers.last);
+
+ for (; md; md = md->prev) {
+ if (!modifier_isEnabled(scene, md, eModifierMode_Render)) {
+ continue;
+ }
+
+ if (md->type == eModifierType_Subsurf) {
+ SubsurfModifierData *smd = reinterpret_cast<SubsurfModifierData*>(md);
+
+ if (smd->subdivType == ME_CC_SUBSURF) {
+ return md;
+ }
+ }
+
+ /* mesh is not a subsurf. break */
+ if ((md->type != eModifierType_Displace) && (md->type != eModifierType_ParticleSystem)) {
+ return NULL;
+ }
+ }
+
+ return NULL;
+}
+
+static ModifierData *get_liquid_sim_modifier(Scene *scene, Object *ob)
+{
+ ModifierData *md = modifiers_findByType(ob, eModifierType_Fluidsim);
+
+ if (md && (modifier_isEnabled(scene, md, eModifierMode_Render))) {
+ FluidsimModifierData *fsmd = reinterpret_cast<FluidsimModifierData *>(md);
+
+ if (fsmd->fss && fsmd->fss->type == OB_FLUIDSIM_DOMAIN) {
+ return md;
+ }
+ }
+
+ return NULL;
+}
+
+/* ************************************************************************** */
+
+AbcMeshWriter::AbcMeshWriter(Scene *scene,
+ Object *ob,
+ AbcTransformWriter *parent,
+ uint32_t time_sampling,
+ ExportSettings &settings)
+ : AbcObjectWriter(scene, ob, time_sampling, settings, parent)
+{
+ m_is_animated = isAnimated();
+ m_subsurf_mod = NULL;
+ m_is_subd = false;
+
+ /* If the object is static, use the default static time sampling. */
+ if (!m_is_animated) {
+ time_sampling = 0;
+ }
+
+ if (!m_settings.apply_subdiv) {
+ m_subsurf_mod = get_subsurf_modifier(m_scene, m_object);
+ m_is_subd = (m_subsurf_mod != NULL);
+ }
+
+ m_is_liquid = (get_liquid_sim_modifier(m_scene, m_object) != NULL);
+
+ while (parent->alembicXform().getChildHeader(m_name)) {
+ m_name.append("_");
+ }
+
+ if (m_settings.use_subdiv_schema && m_is_subd) {
+ OSubD subd(parent->alembicXform(), m_name, m_time_sampling);
+ m_subdiv_schema = subd.getSchema();
+ }
+ else {
+ OPolyMesh mesh(parent->alembicXform(), m_name, m_time_sampling);
+ m_mesh_schema = mesh.getSchema();
+
+ OCompoundProperty typeContainer = m_mesh_schema.getUserProperties();
+ OBoolProperty type(typeContainer, "meshtype");
+ type.set(m_is_subd);
+ }
+}
+
+AbcMeshWriter::~AbcMeshWriter()
+{
+ if (m_subsurf_mod) {
+ m_subsurf_mod->mode &= ~eModifierMode_DisableTemporary;
+ }
+}
+
+bool AbcMeshWriter::isAnimated() const
+{
+ /* Check if object has shape keys. */
+ Mesh *me = static_cast<Mesh *>(m_object->data);
+
+ if (me->key) {
+ return true;
+ }
+
+ /* Test modifiers. */
+ ModifierData *md = static_cast<ModifierData *>(m_object->modifiers.first);
+
+ while (md) {
+ if (md->type != eModifierType_Subsurf) {
+ return true;
+ }
+
+ md = md->next;
+ }
+
+ return false;
+}
+
+void AbcMeshWriter::do_write()
+{
+ /* We have already stored a sample for this object. */
+ if (!m_first_frame && !m_is_animated)
+ return;
+
+ DerivedMesh *dm = getFinalMesh();
+
+ try {
+ if (m_settings.use_subdiv_schema && m_subdiv_schema.valid()) {
+ writeSubD(dm);
+ }
+ else {
+ writeMesh(dm);
+ }
+
+ freeMesh(dm);
+ }
+ catch (...) {
+ freeMesh(dm);
+ throw;
+ }
+}
+
+void AbcMeshWriter::writeMesh(DerivedMesh *dm)
+{
+ std::vector<Imath::V3f> points, normals;
+ std::vector<int32_t> poly_verts, loop_counts;
+
+ bool smooth_normal = false;
+
+ get_vertices(dm, points);
+ get_topology(dm, poly_verts, loop_counts, smooth_normal);
+
+ if (m_first_frame && m_settings.export_face_sets) {
+ writeFaceSets(dm, m_mesh_schema);
+ }
+
+ m_mesh_sample = OPolyMeshSchema::Sample(V3fArraySample(points),
+ Int32ArraySample(poly_verts),
+ Int32ArraySample(loop_counts));
+
+ UVSample sample;
+ if (m_first_frame && m_settings.export_uvs) {
+ const char *name = get_uv_sample(sample, m_custom_data_config, &dm->loopData);
+
+ if (!sample.indices.empty() && !sample.uvs.empty()) {
+ OV2fGeomParam::Sample uv_sample;
+ uv_sample.setVals(V2fArraySample(sample.uvs));
+ uv_sample.setIndices(UInt32ArraySample(sample.indices));
+ uv_sample.setScope(kFacevaryingScope);
+
+ m_mesh_schema.setUVSourceName(name);
+ m_mesh_sample.setUVs(uv_sample);
+ }
+
+ write_custom_data(m_mesh_schema.getArbGeomParams(), m_custom_data_config, &dm->loopData, CD_MLOOPUV);
+ }
+
+ if (m_settings.export_normals) {
+ if (smooth_normal) {
+ get_loop_normals(dm, normals);
+ }
+ else {
+ get_vertex_normals(dm, normals);
+ }
+
+ ON3fGeomParam::Sample normals_sample;
+ if (!normals.empty()) {
+ normals_sample.setScope((smooth_normal) ? kFacevaryingScope : kVertexScope);
+ normals_sample.setVals(V3fArraySample(normals));
+ }
+
+ m_mesh_sample.setNormals(normals_sample);
+ }
+
+ if (m_is_liquid) {
+ std::vector<Imath::V3f> velocities;
+ getVelocities(dm, velocities);
+
+ m_mesh_sample.setVelocities(V3fArraySample(velocities));
+ }
+
+ m_mesh_sample.setSelfBounds(bounds());
+
+ m_mesh_schema.set(m_mesh_sample);
+
+ writeArbGeoParams(dm);
+}
+
+void AbcMeshWriter::writeSubD(DerivedMesh *dm)
+{
+ std::vector<float> crease_sharpness;
+ std::vector<Imath::V3f> points;
+ std::vector<int32_t> poly_verts, loop_counts;
+ std::vector<int32_t> crease_indices, crease_lengths;
+
+ bool smooth_normal = false;
+
+ get_vertices(dm, points);
+ get_topology(dm, poly_verts, loop_counts, smooth_normal);
+ get_creases(dm, crease_indices, crease_lengths, crease_sharpness);
+
+ if (m_first_frame && m_settings.export_face_sets) {
+ writeFaceSets(dm, m_subdiv_schema);
+ }
+
+ m_subdiv_sample = OSubDSchema::Sample(V3fArraySample(points),
+ Int32ArraySample(poly_verts),
+ Int32ArraySample(loop_counts));
+
+ UVSample sample;
+ if (m_first_frame && m_settings.export_uvs) {
+ const char *name = get_uv_sample(sample, m_custom_data_config, &dm->loopData);
+
+ if (!sample.indices.empty() && !sample.uvs.empty()) {
+ OV2fGeomParam::Sample uv_sample;
+ uv_sample.setVals(V2fArraySample(sample.uvs));
+ uv_sample.setIndices(UInt32ArraySample(sample.indices));
+ uv_sample.setScope(kFacevaryingScope);
+
+ m_subdiv_schema.setUVSourceName(name);
+ m_subdiv_sample.setUVs(uv_sample);
+ }
+
+ write_custom_data(m_subdiv_schema.getArbGeomParams(), m_custom_data_config, &dm->loopData, CD_MLOOPUV);
+ }
+
+ if (!crease_indices.empty()) {
+ m_subdiv_sample.setCreaseIndices(Int32ArraySample(crease_indices));
+ m_subdiv_sample.setCreaseLengths(Int32ArraySample(crease_lengths));
+ m_subdiv_sample.setCreaseSharpnesses(FloatArraySample(crease_sharpness));
+ }
+
+ m_subdiv_sample.setSelfBounds(bounds());
+ m_subdiv_schema.set(m_subdiv_sample);
+
+ writeArbGeoParams(dm);
+}
+
+template <typename Schema>
+void AbcMeshWriter::writeFaceSets(DerivedMesh *dm, Schema &schema)
+{
+ std::map< std::string, std::vector<int32_t> > geo_groups;
+ getGeoGroups(dm, geo_groups);
+
+ std::map< std::string, std::vector<int32_t> >::iterator it;
+ for (it = geo_groups.begin(); it != geo_groups.end(); ++it) {
+ OFaceSet face_set = schema.createFaceSet(it->first);
+ OFaceSetSchema::Sample samp;
+ samp.setFaces(Int32ArraySample(it->second));
+ face_set.getSchema().set(samp);
+ }
+}
+
+DerivedMesh *AbcMeshWriter::getFinalMesh()
+{
+ /* We don't want subdivided mesh data */
+ if (m_subsurf_mod) {
+ m_subsurf_mod->mode |= eModifierMode_DisableTemporary;
+ }
+
+ DerivedMesh *dm = mesh_create_derived_render(m_scene, m_object, CD_MASK_MESH);
+
+ if (m_subsurf_mod) {
+ m_subsurf_mod->mode &= ~eModifierMode_DisableTemporary;
+ }
+
+ if (m_settings.triangulate) {
+ const bool tag_only = false;
+ const int quad_method = m_settings.quad_method;
+ const int ngon_method = m_settings.ngon_method;
+
+ BMesh *bm = DM_to_bmesh(dm, true);
+
+ BM_mesh_triangulate(bm, quad_method, ngon_method, tag_only, NULL, NULL, NULL);
+
+ DerivedMesh *result = CDDM_from_bmesh(bm, false);
+ BM_mesh_free(bm);
+
+ freeMesh(dm);
+
+ dm = result;
+ }
+
+ m_custom_data_config.pack_uvs = m_settings.pack_uv;
+ m_custom_data_config.mpoly = dm->getPolyArray(dm);
+ m_custom_data_config.mloop = dm->getLoopArray(dm);
+ m_custom_data_config.totpoly = dm->getNumPolys(dm);
+ m_custom_data_config.totloop = dm->getNumLoops(dm);
+ m_custom_data_config.totvert = dm->getNumVerts(dm);
+
+ return dm;
+}
+
+void AbcMeshWriter::freeMesh(DerivedMesh *dm)
+{
+ dm->release(dm);
+}
+
+void AbcMeshWriter::writeArbGeoParams(DerivedMesh *dm)
+{
+ if (m_is_liquid) {
+ /* We don't need anything more for liquid meshes. */
+ return;
+ }
+
+ if (m_first_frame && m_settings.export_vcols) {
+ if (m_subdiv_schema.valid()) {
+ write_custom_data(m_subdiv_schema.getArbGeomParams(), m_custom_data_config, &dm->loopData, CD_MLOOPCOL);
+ }
+ else {
+ write_custom_data(m_mesh_schema.getArbGeomParams(), m_custom_data_config, &dm->loopData, CD_MLOOPCOL);
+ }
+ }
+}
+
+void AbcMeshWriter::getVelocities(DerivedMesh *dm, std::vector<Imath::V3f> &vels)
+{
+ const int totverts = dm->getNumVerts(dm);
+
+ vels.clear();
+ vels.resize(totverts);
+
+ ModifierData *md = get_liquid_sim_modifier(m_scene, m_object);
+ FluidsimModifierData *fmd = reinterpret_cast<FluidsimModifierData *>(md);
+ FluidsimSettings *fss = fmd->fss;
+
+ if (fss->meshVelocities) {
+ float *mesh_vels = reinterpret_cast<float *>(fss->meshVelocities);
+
+ for (int i = 0; i < totverts; ++i) {
+ copy_zup_yup(vels[i].getValue(), mesh_vels);
+ mesh_vels += 3;
+ }
+ }
+ else {
+ std::fill(vels.begin(), vels.end(), Imath::V3f(0.0f));
+ }
+}
+
+void AbcMeshWriter::getGeoGroups(
+ DerivedMesh *dm,
+ std::map<std::string, std::vector<int32_t> > &geo_groups)
+{
+ const int num_poly = dm->getNumPolys(dm);
+ MPoly *polygons = dm->getPolyArray(dm);
+
+ for (int i = 0; i < num_poly; ++i) {
+ MPoly &current_poly = polygons[i];
+ short mnr = current_poly.mat_nr;
+
+ Material *mat = give_current_material(m_object, mnr + 1);
+
+ if (!mat) {
+ continue;
+ }
+
+ std::string name = get_id_name(&mat->id);
+
+ if (geo_groups.find(name) == geo_groups.end()) {
+ std::vector<int32_t> faceArray;
+ geo_groups[name] = faceArray;
+ }
+
+ geo_groups[name].push_back(i);
+ }
+
+ if (geo_groups.size() == 0) {
+ Material *mat = give_current_material(m_object, 1);
+
+ std::string name = (mat) ? get_id_name(&mat->id) : "default";
+
+ std::vector<int32_t> faceArray;
+
+ for (int i = 0, e = dm->getNumTessFaces(dm); i < e; ++i) {
+ faceArray.push_back(i);
+ }
+
+ geo_groups[name] = faceArray;
+ }
+}
+
+/* ************************************************************************** */
+
+/* Some helpers for mesh generation */
+namespace utils {
+
+static void build_mat_map(const Main *bmain, std::map<std::string, Material *> &mat_map)
+{
+ Material *material = static_cast<Material *>(bmain->mat.first);
+
+ for (; material; material = static_cast<Material *>(material->id.next)) {
+ mat_map[material->id.name + 2] = material;
+ }
+}
+
+static void assign_materials(Main *bmain, Object *ob, const std::map<std::string, int> &mat_index_map)
+{
+ bool can_assign = true;
+ std::map<std::string, int>::const_iterator it = mat_index_map.begin();
+
+ int matcount = 0;
+ for (; it != mat_index_map.end(); ++it, ++matcount) {
+ if (!BKE_object_material_slot_add(ob)) {
+ can_assign = false;
+ break;
+ }
+ }
+
+ /* TODO(kevin): use global map? */
+ std::map<std::string, Material *> mat_map;
+ build_mat_map(bmain, mat_map);
+
+ std::map<std::string, Material *>::iterator mat_iter;
+
+ if (can_assign) {
+ it = mat_index_map.begin();
+
+ for (; it != mat_index_map.end(); ++it) {
+ std::string mat_name = it->first;
+ mat_iter = mat_map.find(mat_name.c_str());
+
+ Material *assigned_name;
+
+ if (mat_iter == mat_map.end()) {
+ assigned_name = BKE_material_add(bmain, mat_name.c_str());
+ mat_map[mat_name] = assigned_name;
+ }
+ else {
+ assigned_name = mat_iter->second;
+ }
+
+ assign_material(ob, assigned_name, it->second, BKE_MAT_ASSIGN_OBJECT);
+ }
+ }
+}
+
+} /* namespace utils */
+
+/* ************************************************************************** */
+
+using Alembic::AbcGeom::UInt32ArraySamplePtr;
+using Alembic::AbcGeom::V2fArraySamplePtr;
+
+struct AbcMeshData {
+ Int32ArraySamplePtr face_indices;
+ Int32ArraySamplePtr face_counts;
+
+ P3fArraySamplePtr positions;
+ P3fArraySamplePtr ceil_positions;
+
+ N3fArraySamplePtr vertex_normals;
+ N3fArraySamplePtr face_normals;
+
+ V2fArraySamplePtr uvs;
+ UInt32ArraySamplePtr uvs_indices;
+};
+
+static void read_mverts_interp(MVert *mverts, const P3fArraySamplePtr &positions, const P3fArraySamplePtr &ceil_positions, const float weight)
+{
+ float tmp[3];
+ for (int i = 0; i < positions->size(); ++i) {
+ MVert &mvert = mverts[i];
+ const Imath::V3f &floor_pos = (*positions)[i];
+ const Imath::V3f &ceil_pos = (*ceil_positions)[i];
+
+ interp_v3_v3v3(tmp, floor_pos.getValue(), ceil_pos.getValue(), weight);
+ copy_yup_zup(mvert.co, tmp);
+
+ mvert.bweight = 0;
+ }
+}
+
+static void read_mverts(CDStreamConfig &config, const AbcMeshData &mesh_data)
+{
+ MVert *mverts = config.mvert;
+ const P3fArraySamplePtr &positions = mesh_data.positions;
+ const N3fArraySamplePtr &normals = mesh_data.vertex_normals;
+
+ if ( config.weight != 0.0f
+ && mesh_data.ceil_positions != NULL
+ && mesh_data.ceil_positions->size() == positions->size())
+ {
+ read_mverts_interp(mverts, positions, mesh_data.ceil_positions, config.weight);
+ return;
+ }
+
+ read_mverts(mverts, positions, normals);
+}
+
+void read_mverts(MVert *mverts, const P3fArraySamplePtr &positions, const N3fArraySamplePtr &normals)
+{
+ for (int i = 0; i < positions->size(); ++i) {
+ MVert &mvert = mverts[i];
+ Imath::V3f pos_in = (*positions)[i];
+
+ copy_yup_zup(mvert.co, pos_in.getValue());
+
+ mvert.bweight = 0;
+
+ if (normals) {
+ Imath::V3f nor_in = (*normals)[i];
+
+ short no[3];
+ normal_float_to_short_v3(no, nor_in.getValue());
+
+ copy_yup_zup(mvert.no, no);
+ }
+ }
+}
+
+static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data)
+{
+ MPoly *mpolys = config.mpoly;
+ MLoop *mloops = config.mloop;
+ MLoopUV *mloopuvs = config.mloopuv;
+
+ const Int32ArraySamplePtr &face_indices = mesh_data.face_indices;
+ const Int32ArraySamplePtr &face_counts = mesh_data.face_counts;
+ const V2fArraySamplePtr &uvs = mesh_data.uvs;
+ const UInt32ArraySamplePtr &uvs_indices = mesh_data.uvs_indices;
+ const N3fArraySamplePtr &normals = mesh_data.face_normals;
+
+ const bool do_uvs = (mloopuvs && uvs && uvs_indices) && (uvs_indices->size() == face_indices->size());
+ unsigned int loop_index = 0;
+ unsigned int rev_loop_index = 0;
+ unsigned int uv_index = 0;
+
+ for (int i = 0; i < face_counts->size(); ++i) {
+ const int face_size = (*face_counts)[i];
+
+ MPoly &poly = mpolys[i];
+ poly.loopstart = loop_index;
+ poly.totloop = face_size;
+
+ if (normals != NULL) {
+ poly.flag |= ME_SMOOTH;
+ }
+
+ /* NOTE: Alembic data is stored in the reverse order. */
+ rev_loop_index = loop_index + (face_size - 1);
+
+ for (int f = 0; f < face_size; ++f, ++loop_index, --rev_loop_index) {
+ MLoop &loop = mloops[rev_loop_index];
+ loop.v = (*face_indices)[loop_index];
+
+ if (do_uvs) {
+ MLoopUV &loopuv = mloopuvs[rev_loop_index];
+
+ uv_index = (*uvs_indices)[loop_index];
+ loopuv.uv[0] = (*uvs)[uv_index][0];
+ loopuv.uv[1] = (*uvs)[uv_index][1];
+ }
+ }
+ }
+}
+
+ABC_INLINE void read_uvs_params(CDStreamConfig &config,
+ AbcMeshData &abc_data,
+ const IV2fGeomParam &uv,
+ const ISampleSelector &selector)
+{
+ if (!uv.valid()) {
+ return;
+ }
+
+ IV2fGeomParam::Sample uvsamp;
+ uv.getIndexed(uvsamp, selector);
+
+ abc_data.uvs = uvsamp.getVals();
+ abc_data.uvs_indices = uvsamp.getIndices();
+
+ if (abc_data.uvs_indices->size() == config.totloop) {
+ std::string name = Alembic::Abc::GetSourceName(uv.getMetaData());
+
+ /* According to the convention, primary UVs should have had their name
+ * set using Alembic::Abc::SetSourceName, but you can't expect everyone
+ * to follow it! :) */
+ if (name.empty()) {
+ name = uv.getName();
+ }
+
+ void *cd_ptr = config.add_customdata_cb(config.user_data, name.c_str(), CD_MLOOPUV);
+ config.mloopuv = static_cast<MLoopUV *>(cd_ptr);
+ }
+}
+
+/* TODO(kevin): normals from Alembic files are not read in anymore, this is due
+ * to the fact that there are many issues that are not so easy to solve, mainly
+ * regarding the way normals are handled in Blender (MPoly.flag vs loop normals).
+ */
+ABC_INLINE void read_normals_params(AbcMeshData &abc_data,
+ const IN3fGeomParam &normals,
+ const ISampleSelector &selector)
+{
+ if (!normals.valid()) {
+ return;
+ }
+
+ IN3fGeomParam::Sample normsamp = normals.getExpandedValue(selector);
+
+ if (normals.getScope() == kFacevaryingScope) {
+ abc_data.face_normals = normsamp.getVals();
+ }
+ else if ((normals.getScope() == kVertexScope) || (normals.getScope() == kVaryingScope)) {
+ abc_data.vertex_normals = N3fArraySamplePtr();
+ }
+}
+
+/* ************************************************************************** */
+
+AbcMeshReader::AbcMeshReader(const IObject &object, ImportSettings &settings)
+ : AbcObjectReader(object, settings)
+{
+ m_settings->read_flag |= MOD_MESHSEQ_READ_ALL;
+
+ IPolyMesh ipoly_mesh(m_iobject, kWrapExisting);
+ m_schema = ipoly_mesh.getSchema();
+
+ get_min_max_time(m_iobject, m_schema, m_min_time, m_max_time);
+}
+
+bool AbcMeshReader::valid() const
+{
+ return m_schema.valid();
+}
+
+void AbcMeshReader::readObjectData(Main *bmain, float time)
+{
+ Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
+
+ m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
+ m_object->data = mesh;
+
+ const ISampleSelector sample_sel(time);
+
+ DerivedMesh *dm = CDDM_from_mesh(mesh);
+ DerivedMesh *ndm = this->read_derivedmesh(dm, time, MOD_MESHSEQ_READ_ALL);
+
+ if (ndm != dm) {
+ dm->release(dm);
+ }
+
+ DM_to_mesh(ndm, mesh, m_object, CD_MASK_MESH, true);
+
+ if (m_settings->validate_meshes) {
+ BKE_mesh_validate(mesh, false, false);
+ }
+
+ readFaceSetsSample(bmain, mesh, 0, sample_sel);
+
+ if (has_animations(m_schema, m_settings)) {
+ addCacheModifier();
+ }
+}
+
+static bool check_smooth_poly_flag(DerivedMesh *dm)
+{
+ MPoly *mpolys = dm->getPolyArray(dm);
+
+ for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i) {
+ MPoly &poly = mpolys[i];
+
+ if ((poly.flag & ME_SMOOTH) != 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void set_smooth_poly_flag(DerivedMesh *dm)
+{
+ MPoly *mpolys = dm->getPolyArray(dm);
+
+ for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i) {
+ MPoly &poly = mpolys[i];
+ poly.flag |= ME_SMOOTH;
+ }
+}
+
+static void *add_customdata_cb(void *user_data, const char *name, int data_type)
+{
+ DerivedMesh *dm = static_cast<DerivedMesh *>(user_data);
+ CustomDataType cd_data_type = static_cast<CustomDataType>(data_type);
+ void *cd_ptr = NULL;
+
+ if (ELEM(cd_data_type, CD_MLOOPUV, CD_MLOOPCOL)) {
+ cd_ptr = CustomData_get_layer_named(dm->getLoopDataLayout(dm), cd_data_type, name);
+
+ if (cd_ptr == NULL) {
+ cd_ptr = CustomData_add_layer_named(dm->getLoopDataLayout(dm),
+ cd_data_type,
+ CD_DEFAULT,
+ NULL,
+ dm->getNumLoops(dm),
+ name);
+ }
+ }
+
+ return cd_ptr;
+}
+
+CDStreamConfig get_config(DerivedMesh *dm)
+{
+ CDStreamConfig config;
+
+ config.user_data = dm;
+ config.mvert = dm->getVertArray(dm);
+ config.mloop = dm->getLoopArray(dm);
+ config.mpoly = dm->getPolyArray(dm);
+ config.totloop = dm->getNumLoops(dm);
+ config.totpoly = dm->getNumPolys(dm);
+ config.loopdata = dm->getLoopDataLayout(dm);
+ config.add_customdata_cb = add_customdata_cb;
+
+ return config;
+}
+
+DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm, const float time, int read_flag)
+{
+ ISampleSelector sample_sel(time);
+ const IPolyMeshSchema::Sample sample = m_schema.getValue(sample_sel);
+
+ const P3fArraySamplePtr &positions = sample.getPositions();
+ const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices();
+ const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts();
+
+ DerivedMesh *new_dm = NULL;
+
+ /* Only read point data when streaming meshes, unless we need to create new ones. */
+ ImportSettings settings;
+ settings.read_flag |= read_flag;
+
+ if (dm->getNumVerts(dm) != positions->size()) {
+ new_dm = CDDM_from_template(dm,
+ positions->size(),
+ 0,
+ 0,
+ face_indices->size(),
+ face_counts->size());
+
+ settings.read_flag |= MOD_MESHSEQ_READ_ALL;
+ }
+
+ CDStreamConfig config = get_config(new_dm ? new_dm : dm);
+ config.time = time;
+
+ bool do_normals = false;
+ read_mesh_sample(&settings, m_schema, sample_sel, config, do_normals);
+
+ if (new_dm) {
+ /* Check if we had ME_SMOOTH flag set to restore it. */
+ if (!do_normals && check_smooth_poly_flag(dm)) {
+ set_smooth_poly_flag(new_dm);
+ }
+
+ CDDM_calc_normals(new_dm);
+ CDDM_calc_edges(new_dm);
+
+ return new_dm;
+ }
+
+ if (do_normals) {
+ CDDM_calc_normals(dm);
+ }
+
+ return dm;
+}
+
+void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start,
+ const ISampleSelector &sample_sel)
+{
+ std::vector<std::string> face_sets;
+ m_schema.getFaceSetNames(face_sets);
+
+ if (face_sets.empty()) {
+ return;
+ }
+
+ std::map<std::string, int> mat_map;
+ int current_mat = 0;
+
+ for (int i = 0; i < face_sets.size(); ++i) {
+ const std::string &grp_name = face_sets[i];
+
+ if (mat_map.find(grp_name) == mat_map.end()) {
+ mat_map[grp_name] = 1 + current_mat++;
+ }
+
+ const int assigned_mat = mat_map[grp_name];
+
+ const IFaceSet faceset = m_schema.getFaceSet(grp_name);
+
+ if (!faceset.valid()) {
+ continue;
+ }
+
+ const IFaceSetSchema face_schem = faceset.getSchema();
+ const IFaceSetSchema::Sample face_sample = face_schem.getValue(sample_sel);
+ const Int32ArraySamplePtr group_faces = face_sample.getFaces();
+ const size_t num_group_faces = group_faces->size();
+
+ for (size_t l = 0; l < num_group_faces; l++) {
+ size_t pos = (*group_faces)[l] + poly_start;
+
+ if (pos >= mesh->totpoly) {
+ std::cerr << "Faceset overflow on " << faceset.getName() << '\n';
+ break;
+ }
+
+ MPoly &poly = mesh->mpoly[pos];
+ poly.mat_nr = assigned_mat - 1;
+ }
+ }
+
+ utils::assign_materials(bmain, m_object, mat_map);
+}
+
+static void get_weight_and_index(CDStreamConfig &config,
+ Alembic::AbcCoreAbstract::TimeSamplingPtr time_sampling,
+ size_t samples_number)
+{
+ Alembic::AbcGeom::index_t i0, i1;
+
+ config.weight = get_weight_and_index(config.time,
+ time_sampling,
+ samples_number,
+ i0,
+ i1);
+
+ config.index = i0;
+ config.ceil_index = i1;
+}
+
+void read_mesh_sample(ImportSettings *settings,
+ const IPolyMeshSchema &schema,
+ const ISampleSelector &selector,
+ CDStreamConfig &config,
+ bool &do_normals)
+{
+ const IPolyMeshSchema::Sample sample = schema.getValue(selector);
+
+ AbcMeshData abc_mesh_data;
+ abc_mesh_data.face_counts = sample.getFaceCounts();
+ abc_mesh_data.face_indices = sample.getFaceIndices();
+ abc_mesh_data.positions = sample.getPositions();
+
+ read_normals_params(abc_mesh_data, schema.getNormalsParam(), selector);
+
+ do_normals = (abc_mesh_data.face_normals != NULL);
+
+ get_weight_and_index(config, schema.getTimeSampling(), schema.getNumSamples());
+
+ if (config.weight != 0.0f) {
+ Alembic::AbcGeom::IPolyMeshSchema::Sample ceil_sample;
+ schema.get(ceil_sample, Alembic::Abc::ISampleSelector(static_cast<Alembic::AbcCoreAbstract::index_t>(config.ceil_index)));
+ abc_mesh_data.ceil_positions = ceil_sample.getPositions();
+ }
+
+ if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) {
+ read_uvs_params(config, abc_mesh_data, schema.getUVsParam(), selector);
+ }
+
+ if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0) {
+ read_mverts(config, abc_mesh_data);
+ }
+
+ if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) {
+ read_mpolys(config, abc_mesh_data);
+ }
+
+ if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) {
+ read_custom_data(schema.getArbGeomParams(), config, selector);
+ }
+
+ /* TODO: face sets */
+}
+
+/* ************************************************************************** */
+
+ABC_INLINE MEdge *find_edge(MEdge *edges, int totedge, int v1, int v2)
+{
+ for (int i = 0, e = totedge; i < e; ++i) {
+ MEdge &edge = edges[i];
+
+ if (edge.v1 == v1 && edge.v2 == v2) {
+ return &edge;
+ }
+ }
+
+ return NULL;
+}
+
+AbcSubDReader::AbcSubDReader(const IObject &object, ImportSettings &settings)
+ : AbcObjectReader(object, settings)
+{
+ m_settings->read_flag |= MOD_MESHSEQ_READ_ALL;
+
+ ISubD isubd_mesh(m_iobject, kWrapExisting);
+ m_schema = isubd_mesh.getSchema();
+
+ get_min_max_time(m_iobject, m_schema, m_min_time, m_max_time);
+}
+
+bool AbcSubDReader::valid() const
+{
+ return m_schema.valid();
+}
+
+void AbcSubDReader::readObjectData(Main *bmain, float time)
+{
+ Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
+
+ m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
+ m_object->data = mesh;
+
+ DerivedMesh *dm = CDDM_from_mesh(mesh);
+ DerivedMesh *ndm = this->read_derivedmesh(dm, time, MOD_MESHSEQ_READ_ALL);
+
+ if (ndm != dm) {
+ dm->release(dm);
+ }
+
+ DM_to_mesh(ndm, mesh, m_object, CD_MASK_MESH, true);
+
+ const ISampleSelector sample_sel(time);
+ const ISubDSchema::Sample sample = m_schema.getValue(sample_sel);
+ Int32ArraySamplePtr indices = sample.getCreaseIndices();
+ Alembic::Abc::FloatArraySamplePtr sharpnesses = sample.getCreaseSharpnesses();
+
+ MEdge *edges = mesh->medge;
+
+ if (indices && sharpnesses) {
+ for (int i = 0, s = 0, e = indices->size(); i < e; i += 2, ++s) {
+ MEdge *edge = find_edge(edges, mesh->totedge, (*indices)[i], (*indices)[i + 1]);
+
+ if (edge) {
+ edge->crease = FTOCHAR((*sharpnesses)[s]);
+ }
+ }
+
+ mesh->cd_flag |= ME_CDFLAG_EDGE_CREASE;
+ }
+
+ BKE_mesh_calc_normals(mesh);
+ BKE_mesh_calc_edges(mesh, false, false);
+
+ if (m_settings->validate_meshes) {
+ BKE_mesh_validate(mesh, false, false);
+ }
+
+ if (has_animations(m_schema, m_settings)) {
+ addCacheModifier();
+ }
+}
+
+void read_subd_sample(ImportSettings *settings,
+ const ISubDSchema &schema,
+ const ISampleSelector &selector,
+ CDStreamConfig &config)
+{
+ const ISubDSchema::Sample sample = schema.getValue(selector);
+
+ AbcMeshData abc_mesh_data;
+ abc_mesh_data.face_counts = sample.getFaceCounts();
+ abc_mesh_data.face_indices = sample.getFaceIndices();
+ abc_mesh_data.vertex_normals = N3fArraySamplePtr();
+ abc_mesh_data.face_normals = N3fArraySamplePtr();
+ abc_mesh_data.positions = sample.getPositions();
+
+ get_weight_and_index(config, schema.getTimeSampling(), schema.getNumSamples());
+
+ if (config.weight != 0.0f) {
+ Alembic::AbcGeom::ISubDSchema::Sample ceil_sample;
+ schema.get(ceil_sample, Alembic::Abc::ISampleSelector(static_cast<Alembic::AbcCoreAbstract::index_t>(config.ceil_index)));
+ abc_mesh_data.ceil_positions = ceil_sample.getPositions();
+ }
+
+ if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) {
+ read_uvs_params(config, abc_mesh_data, schema.getUVsParam(), selector);
+ }
+
+ if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0) {
+ read_mverts(config, abc_mesh_data);
+ }
+
+ if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) {
+ read_mpolys(config, abc_mesh_data);
+ }
+
+ if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) {
+ read_custom_data(schema.getArbGeomParams(), config, selector);
+ }
+
+ /* TODO: face sets */
+}
+
+DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm, const float time, int read_flag)
+{
+ ISampleSelector sample_sel(time);
+ const ISubDSchema::Sample sample = m_schema.getValue(sample_sel);
+
+ const P3fArraySamplePtr &positions = sample.getPositions();
+ const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices();
+ const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts();
+
+ DerivedMesh *new_dm = NULL;
+
+ ImportSettings settings;
+ settings.read_flag |= read_flag;
+
+ if (dm->getNumVerts(dm) != positions->size()) {
+ new_dm = CDDM_from_template(dm,
+ positions->size(),
+ 0,
+ 0,
+ face_indices->size(),
+ face_counts->size());
+
+ settings.read_flag |= MOD_MESHSEQ_READ_ALL;
+ }
+
+ /* Only read point data when streaming meshes, unless we need to create new ones. */
+ CDStreamConfig config = get_config(new_dm ? new_dm : dm);
+ config.time = time;
+ read_subd_sample(&settings, m_schema, sample_sel, config);
+
+ if (new_dm) {
+ /* Check if we had ME_SMOOTH flag set to restore it. */
+ if (check_smooth_poly_flag(dm)) {
+ set_smooth_poly_flag(new_dm);
+ }
+
+ CDDM_calc_normals(new_dm);
+ CDDM_calc_edges(new_dm);
+
+ return new_dm;
+ }
+
+ return dm;
+}
diff --git a/source/blender/alembic/intern/abc_mesh.h b/source/blender/alembic/intern/abc_mesh.h
new file mode 100644
index 00000000000..66e6585a3d3
--- /dev/null
+++ b/source/blender/alembic/intern/abc_mesh.h
@@ -0,0 +1,147 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __ABC_MESH_H__
+#define __ABC_MESH_H__
+
+#include "abc_customdata.h"
+#include "abc_object.h"
+
+struct DerivedMesh;
+struct Mesh;
+struct ModifierData;
+
+/* ************************************************************************** */
+
+class AbcMeshWriter : public AbcObjectWriter {
+ Alembic::AbcGeom::OPolyMeshSchema m_mesh_schema;
+ Alembic::AbcGeom::OPolyMeshSchema::Sample m_mesh_sample;
+
+ Alembic::AbcGeom::OSubDSchema m_subdiv_schema;
+ Alembic::AbcGeom::OSubDSchema::Sample m_subdiv_sample;
+
+ Alembic::Abc::OArrayProperty m_mat_indices;
+
+ bool m_is_animated;
+ ModifierData *m_subsurf_mod;
+
+ CDStreamConfig m_custom_data_config;
+
+ bool m_is_liquid;
+ bool m_is_subd;
+
+public:
+ AbcMeshWriter(Scene *scene,
+ Object *ob,
+ AbcTransformWriter *parent,
+ uint32_t time_sampling,
+ ExportSettings &settings);
+
+ ~AbcMeshWriter();
+
+private:
+ virtual void do_write();
+
+ bool isAnimated() const;
+
+ void writeMesh(DerivedMesh *dm);
+ void writeSubD(DerivedMesh *dm);
+
+ void getMeshInfo(DerivedMesh *dm, std::vector<float> &points,
+ std::vector<int32_t> &facePoints,
+ std::vector<int32_t> &faceCounts,
+ std::vector<int32_t> &creaseIndices,
+ std::vector<int32_t> &creaseLengths,
+ std::vector<float> &creaseSharpness);
+
+ DerivedMesh *getFinalMesh();
+ void freeMesh(DerivedMesh *dm);
+
+ void getMaterialIndices(DerivedMesh *dm, std::vector<int32_t> &indices);
+
+ void writeArbGeoParams(DerivedMesh *dm);
+ void getGeoGroups(DerivedMesh *dm, std::map<std::string, std::vector<int32_t> > &geoGroups);
+
+ /* fluid surfaces support */
+ void getVelocities(DerivedMesh *dm, std::vector<Imath::V3f> &vels);
+
+ template <typename Schema>
+ void writeFaceSets(DerivedMesh *dm, Schema &schema);
+};
+
+/* ************************************************************************** */
+
+class AbcMeshReader : public AbcObjectReader {
+ Alembic::AbcGeom::IPolyMeshSchema m_schema;
+
+ CDStreamConfig m_mesh_data;
+
+public:
+ AbcMeshReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
+
+ bool valid() const;
+
+ void readObjectData(Main *bmain, float time);
+
+ DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag);
+
+private:
+ void readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start,
+ const Alembic::AbcGeom::ISampleSelector &sample_sel);
+};
+
+void read_mesh_sample(ImportSettings *settings,
+ const Alembic::AbcGeom::IPolyMeshSchema &schema,
+ const Alembic::AbcGeom::ISampleSelector &selector,
+ CDStreamConfig &config,
+ bool &do_normals);
+
+/* ************************************************************************** */
+
+class AbcSubDReader : public AbcObjectReader {
+ Alembic::AbcGeom::ISubDSchema m_schema;
+
+ CDStreamConfig m_mesh_data;
+
+public:
+ AbcSubDReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
+
+ bool valid() const;
+
+ void readObjectData(Main *bmain, float time);
+ DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag);
+};
+
+void read_subd_sample(ImportSettings *settings,
+ const Alembic::AbcGeom::ISubDSchema &schema,
+ const Alembic::AbcGeom::ISampleSelector &selector,
+ CDStreamConfig &config);
+
+/* ************************************************************************** */
+
+void read_mverts(MVert *mverts,
+ const Alembic::AbcGeom::P3fArraySamplePtr &positions,
+ const Alembic::AbcGeom::N3fArraySamplePtr &normals);
+
+CDStreamConfig get_config(DerivedMesh *dm);
+
+#endif /* __ABC_MESH_H__ */
diff --git a/source/blender/alembic/intern/abc_nurbs.cc b/source/blender/alembic/intern/abc_nurbs.cc
new file mode 100644
index 00000000000..4f57dfdae9e
--- /dev/null
+++ b/source/blender/alembic/intern/abc_nurbs.cc
@@ -0,0 +1,367 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "abc_nurbs.h"
+
+#include "abc_transform.h"
+#include "abc_util.h"
+
+extern "C" {
+#include "MEM_guardedalloc.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_curve.h"
+#include "BKE_object.h"
+}
+
+using Alembic::AbcGeom::bool_t;
+using Alembic::AbcGeom::FloatArraySample;
+using Alembic::AbcGeom::FloatArraySamplePtr;
+using Alembic::AbcGeom::MetaData;
+using Alembic::AbcGeom::P3fArraySamplePtr;
+using Alembic::AbcGeom::kWrapExisting;
+
+using Alembic::AbcGeom::IBoolProperty;
+using Alembic::AbcGeom::ICompoundProperty;
+using Alembic::AbcGeom::INuPatch;
+using Alembic::AbcGeom::INuPatchSchema;
+using Alembic::AbcGeom::IObject;
+using Alembic::AbcGeom::ISampleSelector;
+
+using Alembic::AbcGeom::OBoolProperty;
+using Alembic::AbcGeom::OCompoundProperty;
+using Alembic::AbcGeom::ONuPatch;
+using Alembic::AbcGeom::ONuPatchSchema;
+
+/* ************************************************************************** */
+
+AbcNurbsWriter::AbcNurbsWriter(Scene *scene,
+ Object *ob,
+ AbcTransformWriter *parent,
+ uint32_t time_sampling,
+ ExportSettings &settings)
+ : AbcObjectWriter(scene, ob, time_sampling, settings, parent)
+{
+ m_is_animated = isAnimated();
+
+ /* if the object is static, use the default static time sampling */
+ if (!m_is_animated) {
+ m_time_sampling = 0;
+ }
+
+ Curve *curve = static_cast<Curve *>(m_object->data);
+ size_t numNurbs = BLI_listbase_count(&curve->nurb);
+
+ for (size_t i = 0; i < numNurbs; ++i) {
+ std::stringstream str;
+ str << m_name << '_' << i;
+
+ while (parent->alembicXform().getChildHeader(str.str())) {
+ str << "_";
+ }
+
+ ONuPatch nurbs(parent->alembicXform(), str.str().c_str(), m_time_sampling);
+ m_nurbs_schema.push_back(nurbs.getSchema());
+ }
+}
+
+bool AbcNurbsWriter::isAnimated() const
+{
+ /* check if object has shape keys */
+ Curve *cu = static_cast<Curve *>(m_object->data);
+ return (cu->key != NULL);
+}
+
+static void get_knots(std::vector<float> &knots, const int num_knots, float *nu_knots)
+{
+ if (num_knots <= 1) {
+ return;
+ }
+
+ /* Add an extra knot at the beggining and end of the array since most apps
+ * require/expect them. */
+ knots.reserve(num_knots + 2);
+
+ knots.push_back(0.0f);
+
+ for (int i = 0; i < num_knots; ++i) {
+ knots.push_back(nu_knots[i]);
+ }
+
+ knots[0] = 2.0f * knots[1] - knots[2];
+ knots.push_back(2.0f * knots[num_knots] - knots[num_knots - 1]);
+}
+
+void AbcNurbsWriter::do_write()
+{
+ /* we have already stored a sample for this object. */
+ if (!m_first_frame && !m_is_animated) {
+ return;
+ }
+
+ if (!ELEM(m_object->type, OB_SURF, OB_CURVE)) {
+ return;
+ }
+
+ Curve *curve = static_cast<Curve *>(m_object->data);
+ ListBase *nulb;
+
+ if (m_object->curve_cache->deformed_nurbs.first != NULL) {
+ nulb = &m_object->curve_cache->deformed_nurbs;
+ }
+ else {
+ nulb = BKE_curve_nurbs_get(curve);
+ }
+
+ size_t count = 0;
+ for (Nurb *nu = static_cast<Nurb *>(nulb->first); nu; nu = nu->next, ++count) {
+ std::vector<float> knotsU;
+ get_knots(knotsU, KNOTSU(nu), nu->knotsu);
+
+ std::vector<float> knotsV;
+ get_knots(knotsV, KNOTSV(nu), nu->knotsv);
+
+ const int size = nu->pntsu * nu->pntsv;
+ std::vector<Imath::V3f> positions(size);
+ std::vector<float> weights(size);
+
+ const BPoint *bp = nu->bp;
+
+ for (int i = 0; i < size; ++i, ++bp) {
+ copy_zup_yup(positions[i].getValue(), bp->vec);
+ weights[i] = bp->vec[3];
+ }
+
+ ONuPatchSchema::Sample sample;
+ sample.setUOrder(nu->orderu + 1);
+ sample.setVOrder(nu->orderv + 1);
+ sample.setPositions(positions);
+ sample.setPositionWeights(weights);
+ sample.setUKnot(FloatArraySample(knotsU));
+ sample.setVKnot(FloatArraySample(knotsV));
+ sample.setNu(nu->pntsu);
+ sample.setNv(nu->pntsv);
+
+ /* TODO(kevin): to accomodate other software we should duplicate control
+ * points to indicate that a NURBS is cyclic. */
+ OCompoundProperty user_props = m_nurbs_schema[count].getUserProperties();
+
+ if ((nu->flagu & CU_NURB_ENDPOINT) != 0) {
+ OBoolProperty prop(user_props, "endpoint_u");
+ prop.set(true);
+ }
+
+ if ((nu->flagv & CU_NURB_ENDPOINT) != 0) {
+ OBoolProperty prop(user_props, "endpoint_v");
+ prop.set(true);
+ }
+
+ if ((nu->flagu & CU_NURB_CYCLIC) != 0) {
+ OBoolProperty prop(user_props, "cyclic_u");
+ prop.set(true);
+ }
+
+ if ((nu->flagv & CU_NURB_CYCLIC) != 0) {
+ OBoolProperty prop(user_props, "cyclic_v");
+ prop.set(true);
+ }
+
+ m_nurbs_schema[count].set(sample);
+ }
+}
+
+/* ************************************************************************** */
+
+AbcNurbsReader::AbcNurbsReader(const IObject &object, ImportSettings &settings)
+ : AbcObjectReader(object, settings)
+{
+ getNurbsPatches(m_iobject);
+ get_min_max_time(m_iobject, m_schemas[0].first, m_min_time, m_max_time);
+}
+
+bool AbcNurbsReader::valid() const
+{
+ if (m_schemas.empty()) {
+ return false;
+ }
+
+ std::vector< std::pair<INuPatchSchema, IObject> >::const_iterator it;
+ for (it = m_schemas.begin(); it != m_schemas.end(); ++it) {
+ const INuPatchSchema &schema = it->first;
+
+ if (!schema.valid()) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool set_knots(const FloatArraySamplePtr &knots, float *&nu_knots)
+{
+ if (!knots || knots->size() == 0) {
+ return false;
+ }
+
+ /* Skip first and last knots, as they are used for padding. */
+ const size_t num_knots = knots->size() - 2;
+ nu_knots = static_cast<float *>(MEM_callocN(num_knots * sizeof(float), "abc_setsplineknotsu"));
+
+ for (size_t i = 0; i < num_knots; ++i) {
+ nu_knots[i] = (*knots)[i + 1];
+ }
+
+ return true;
+}
+
+void AbcNurbsReader::readObjectData(Main *bmain, float time)
+{
+ Curve *cu = static_cast<Curve *>(BKE_curve_add(bmain, "abc_curve", OB_SURF));
+ cu->actvert = CU_ACT_NONE;
+
+ std::vector< std::pair<INuPatchSchema, IObject> >::iterator it;
+
+ for (it = m_schemas.begin(); it != m_schemas.end(); ++it) {
+ Nurb *nu = static_cast<Nurb *>(MEM_callocN(sizeof(Nurb), "abc_getnurb"));
+ nu->flag = CU_SMOOTH;
+ nu->type = CU_NURBS;
+ nu->resolu = cu->resolu;
+ nu->resolv = cu->resolv;
+
+ const ISampleSelector sample_sel(time);
+ const INuPatchSchema &schema = it->first;
+ const INuPatchSchema::Sample smp = schema.getValue(sample_sel);
+
+ nu->orderu = smp.getUOrder() - 1;
+ nu->orderv = smp.getVOrder() - 1;
+ nu->pntsu = smp.getNumU();
+ nu->pntsv = smp.getNumV();
+
+ /* Read positions and weights. */
+
+ const P3fArraySamplePtr positions = smp.getPositions();
+ const FloatArraySamplePtr weights = smp.getPositionWeights();
+
+ const size_t num_points = positions->size();
+
+ nu->bp = static_cast<BPoint *>(MEM_callocN(num_points * sizeof(BPoint), "abc_setsplinetype"));
+
+ BPoint *bp = nu->bp;
+ float posw_in = 1.0f;
+
+ for (int i = 0; i < num_points; ++i, ++bp) {
+ const Imath::V3f &pos_in = (*positions)[i];
+
+ if (weights) {
+ posw_in = (*weights)[i];
+ }
+
+ copy_yup_zup(bp->vec, pos_in.getValue());
+ bp->vec[3] = posw_in;
+ bp->f1 = SELECT;
+ bp->radius = 1.0f;
+ bp->weight = 1.0f;
+ }
+
+ /* Read knots. */
+
+ if (!set_knots(smp.getUKnot(), nu->knotsu)) {
+ BKE_nurb_knot_calc_u(nu);
+ }
+
+ if (!set_knots(smp.getVKnot(), nu->knotsv)) {
+ BKE_nurb_knot_calc_v(nu);
+ }
+
+ /* Read flags. */
+
+ ICompoundProperty user_props = schema.getUserProperties();
+
+ if (has_property(user_props, "enpoint_u")) {
+ nu->flagu |= CU_NURB_ENDPOINT;
+ }
+
+ if (has_property(user_props, "enpoint_v")) {
+ nu->flagv |= CU_NURB_ENDPOINT;
+ }
+
+ if (has_property(user_props, "cyclic_u")) {
+ nu->flagu |= CU_NURB_CYCLIC;
+ }
+
+ if (has_property(user_props, "cyclic_v")) {
+ nu->flagv |= CU_NURB_CYCLIC;
+ }
+
+ BLI_addtail(BKE_curve_nurbs_get(cu), nu);
+ }
+
+ BLI_strncpy(cu->id.name + 2, m_data_name.c_str(), m_data_name.size() + 1);
+
+ m_object = BKE_object_add_only_object(bmain, OB_SURF, m_object_name.c_str());
+ m_object->data = cu;
+}
+
+void AbcNurbsReader::getNurbsPatches(const IObject &obj)
+{
+ if (!obj.valid()) {
+ return;
+ }
+
+ const int num_children = obj.getNumChildren();
+
+ if (num_children == 0) {
+ INuPatch abc_nurb(obj, kWrapExisting);
+ INuPatchSchema schem = abc_nurb.getSchema();
+ m_schemas.push_back(std::pair<INuPatchSchema, IObject>(schem, obj));
+ return;
+ }
+
+ for (int i = 0; i < num_children; ++i) {
+ bool ok = true;
+ IObject child(obj, obj.getChildHeader(i).getName());
+
+ if (!m_name.empty() && child.valid() && !begins_with(child.getFullName(), m_name)) {
+ ok = false;
+ }
+
+ if (!child.valid()) {
+ continue;
+ }
+
+ const MetaData &md = child.getMetaData();
+
+ if (INuPatch::matches(md) && ok) {
+ INuPatch abc_nurb(child, kWrapExisting);
+ INuPatchSchema schem = abc_nurb.getSchema();
+ m_schemas.push_back(std::pair<INuPatchSchema, IObject>(schem, child));
+ }
+
+ getNurbsPatches(child);
+ }
+}
diff --git a/source/blender/alembic/intern/abc_nurbs.h b/source/blender/alembic/intern/abc_nurbs.h
new file mode 100644
index 00000000000..1b2e7a8391f
--- /dev/null
+++ b/source/blender/alembic/intern/abc_nurbs.h
@@ -0,0 +1,63 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __ABC_NURBS_H__
+#define __ABC_NURBS_H__
+
+#include "abc_object.h"
+
+/* ************************************************************************** */
+
+class AbcNurbsWriter : public AbcObjectWriter {
+ std::vector<Alembic::AbcGeom::ONuPatchSchema> m_nurbs_schema;
+ bool m_is_animated;
+
+public:
+ AbcNurbsWriter(Scene *scene,
+ Object *ob,
+ AbcTransformWriter *parent,
+ uint32_t time_sampling,
+ ExportSettings &settings);
+
+private:
+ virtual void do_write();
+
+ bool isAnimated() const;
+};
+
+/* ************************************************************************** */
+
+class AbcNurbsReader : public AbcObjectReader {
+ std::vector< std::pair<Alembic::AbcGeom::INuPatchSchema, Alembic::Abc::IObject> > m_schemas;
+
+public:
+ AbcNurbsReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
+
+ bool valid() const;
+
+ void readObjectData(Main *bmain, float time);
+
+private:
+ void getNurbsPatches(const Alembic::Abc::IObject &obj);
+};
+
+#endif /* __ABC_NURBS_H__ */
diff --git a/source/blender/alembic/intern/abc_object.cc b/source/blender/alembic/intern/abc_object.cc
new file mode 100644
index 00000000000..314b2568bed
--- /dev/null
+++ b/source/blender/alembic/intern/abc_object.cc
@@ -0,0 +1,325 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "abc_object.h"
+
+#include "abc_util.h"
+
+extern "C" {
+#include "DNA_cachefile_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_space_types.h" /* for FILE_MAX */
+
+#include "BKE_constraint.h"
+#include "BKE_depsgraph.h"
+#include "BKE_idprop.h"
+#include "BKE_library.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_string.h"
+}
+
+using Alembic::AbcGeom::IObject;
+using Alembic::AbcGeom::IXform;
+using Alembic::AbcGeom::IXformSchema;
+
+using Alembic::AbcGeom::OCompoundProperty;
+using Alembic::AbcGeom::ODoubleArrayProperty;
+using Alembic::AbcGeom::ODoubleProperty;
+using Alembic::AbcGeom::OFloatArrayProperty;
+using Alembic::AbcGeom::OFloatProperty;
+using Alembic::AbcGeom::OInt32ArrayProperty;
+using Alembic::AbcGeom::OInt32Property;
+using Alembic::AbcGeom::OStringArrayProperty;
+using Alembic::AbcGeom::OStringProperty;
+
+/* ************************************************************************** */
+
+AbcObjectWriter::AbcObjectWriter(Scene *scene,
+ Object *ob,
+ uint32_t time_sampling,
+ ExportSettings &settings,
+ AbcObjectWriter *parent)
+ : m_object(ob)
+ , m_settings(settings)
+ , m_scene(scene)
+ , m_time_sampling(time_sampling)
+ , m_first_frame(true)
+{
+ m_name = get_id_name(m_object) + "Shape";
+
+ if (parent) {
+ parent->addChild(this);
+ }
+}
+
+AbcObjectWriter::~AbcObjectWriter()
+{}
+
+void AbcObjectWriter::addChild(AbcObjectWriter *child)
+{
+ m_children.push_back(child);
+}
+
+Imath::Box3d AbcObjectWriter::bounds()
+{
+ BoundBox *bb = BKE_object_boundbox_get(this->m_object);
+
+ if (!bb) {
+ if (this->m_object->type != OB_CAMERA) {
+ std::cerr << "Boundbox is null!\n";
+ }
+
+ return Imath::Box3d();
+ }
+
+ /* Convert Z-up to Y-up. */
+ this->m_bounds.min.x = bb->vec[0][0];
+ this->m_bounds.min.y = bb->vec[0][2];
+ this->m_bounds.min.z = -bb->vec[0][1];
+
+ this->m_bounds.max.x = bb->vec[6][0];
+ this->m_bounds.max.y = bb->vec[6][2];
+ this->m_bounds.max.z = -bb->vec[6][1];
+
+ return this->m_bounds;
+}
+
+void AbcObjectWriter::write()
+{
+ do_write();
+ m_first_frame = false;
+}
+
+/* ************************************************************************** */
+
+AbcObjectReader::AbcObjectReader(const IObject &object, ImportSettings &settings)
+ : m_name("")
+ , m_object_name("")
+ , m_data_name("")
+ , m_object(NULL)
+ , m_iobject(object)
+ , m_settings(&settings)
+ , m_min_time(std::numeric_limits<chrono_t>::max())
+ , m_max_time(std::numeric_limits<chrono_t>::min())
+ , m_refcount(0)
+{
+ m_name = object.getFullName();
+ std::vector<std::string> parts;
+ split(m_name, '/', parts);
+
+ if (parts.size() >= 2) {
+ m_object_name = parts[parts.size() - 2];
+ m_data_name = parts[parts.size() - 1];
+ }
+ else {
+ m_object_name = m_data_name = parts[parts.size() - 1];
+ }
+}
+
+AbcObjectReader::~AbcObjectReader()
+{}
+
+const IObject &AbcObjectReader::iobject() const
+{
+ return m_iobject;
+}
+
+Object *AbcObjectReader::object() const
+{
+ return m_object;
+}
+
+void AbcObjectReader::object(Object *ob)
+{
+ m_object = ob;
+}
+
+static Imath::M44d blend_matrices(const Imath::M44d &m0, const Imath::M44d &m1, const float weight)
+{
+ float mat0[4][4], mat1[4][4], ret[4][4];
+
+ /* Cannot use Imath::M44d::getValue() since this returns a pointer to
+ * doubles and interp_m4_m4m4 expects pointers to floats. So need to convert
+ * the matrices manually.
+ */
+
+ for (int i = 0; i < 4; ++i) {
+ for (int j = 0; j < 4; ++j) {
+ mat0[i][j] = m0[i][j];
+ }
+ }
+
+ for (int i = 0; i < 4; ++i) {
+ for (int j = 0; j < 4; ++j) {
+ mat1[i][j] = m1[i][j];
+ }
+ }
+
+ interp_m4_m4m4(ret, mat0, mat1, weight);
+
+ Imath::M44d m;
+
+ for (int i = 0; i < 4; ++i) {
+ for (int j = 0; j < 4; ++j) {
+ m[i][j] = ret[i][j];
+ }
+ }
+
+ return m;
+}
+
+Imath::M44d get_matrix(const IXformSchema &schema, const float time)
+{
+ Alembic::AbcGeom::index_t i0, i1;
+ Alembic::AbcGeom::XformSample s0, s1;
+
+ const float weight = get_weight_and_index(time,
+ schema.getTimeSampling(),
+ schema.getNumSamples(),
+ i0,
+ i1);
+
+ schema.get(s0, Alembic::AbcGeom::ISampleSelector(i0));
+
+ if (i0 != i1) {
+ schema.get(s1, Alembic::AbcGeom::ISampleSelector(i1));
+ return blend_matrices(s0.getMatrix(), s1.getMatrix(), weight);
+ }
+
+ return s0.getMatrix();
+}
+
+void AbcObjectReader::readObjectMatrix(const float time)
+{
+ bool is_constant = false;
+
+ this->read_matrix(m_object->obmat, time, m_settings->scale, is_constant);
+ invert_m4_m4(m_object->imat, m_object->obmat);
+
+ BKE_object_apply_mat4(m_object, m_object->obmat, false, false);
+
+ if (!is_constant) {
+ bConstraint *con = BKE_constraint_add_for_object(m_object, NULL, CONSTRAINT_TYPE_TRANSFORM_CACHE);
+ bTransformCacheConstraint *data = static_cast<bTransformCacheConstraint *>(con->data);
+ BLI_strncpy(data->object_path, m_iobject.getFullName().c_str(), FILE_MAX);
+
+ data->cache_file = m_settings->cache_file;
+ id_us_plus(&data->cache_file->id);
+
+ data->reader = reinterpret_cast<CacheReader *>(this);
+ this->incref();
+ }
+}
+
+void AbcObjectReader::read_matrix(float mat[4][4], const float time, const float scale, bool &is_constant)
+{
+ IXform ixform;
+ bool has_alembic_parent = false;
+
+ /* Check that we have an empty object (locator, bone head/tail...). */
+ if (IXform::matches(m_iobject.getMetaData())) {
+ ixform = IXform(m_iobject, Alembic::AbcGeom::kWrapExisting);
+
+ /* See comment below. */
+ has_alembic_parent = m_iobject.getParent().getParent().valid();
+ }
+ /* Check that we have an object with actual data. */
+ else if (IXform::matches(m_iobject.getParent().getMetaData())) {
+ ixform = IXform(m_iobject.getParent(), Alembic::AbcGeom::kWrapExisting);
+
+ /* This is a bit hackish, but we need to make sure that extra
+ * transformations added to the matrix (rotation/scale) are only applied
+ * to root objects. The way objects and their hierarchy are created will
+ * need to be revisited at some point but for now this seems to do the
+ * trick.
+ *
+ * Explanation of the trick:
+ * The first getParent() will return this object's transformation matrix.
+ * The second getParent() will get the parent of the transform, but this
+ * might be the archive root ('/') which is valid, so we go passed it to
+ * make sure that there is no parent.
+ */
+ has_alembic_parent = m_iobject.getParent().getParent().getParent().valid();
+ }
+ /* Should not happen. */
+ else {
+ return;
+ }
+
+ const IXformSchema &schema(ixform.getSchema());
+
+ if (!schema.valid()) {
+ return;
+ }
+
+ const Imath::M44d matrix = get_matrix(schema, time);
+ convert_matrix(matrix, m_object, mat, scale, has_alembic_parent);
+
+ is_constant = schema.isConstant();
+}
+
+void AbcObjectReader::addCacheModifier()
+{
+ ModifierData *md = modifier_new(eModifierType_MeshSequenceCache);
+ BLI_addtail(&m_object->modifiers, md);
+
+ MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
+
+ mcmd->cache_file = m_settings->cache_file;
+ id_us_plus(&mcmd->cache_file->id);
+
+ BLI_strncpy(mcmd->object_path, m_iobject.getFullName().c_str(), FILE_MAX);
+
+ mcmd->reader = reinterpret_cast<CacheReader *>(this);
+ this->incref();
+}
+
+chrono_t AbcObjectReader::minTime() const
+{
+ return m_min_time;
+}
+
+chrono_t AbcObjectReader::maxTime() const
+{
+ return m_max_time;
+}
+
+int AbcObjectReader::refcount() const
+{
+ return m_refcount;
+}
+
+void AbcObjectReader::incref()
+{
+ ++m_refcount;
+}
+
+void AbcObjectReader::decref()
+{
+ --m_refcount;
+}
diff --git a/source/blender/alembic/intern/abc_object.h b/source/blender/alembic/intern/abc_object.h
new file mode 100644
index 00000000000..7ff927b4d33
--- /dev/null
+++ b/source/blender/alembic/intern/abc_object.h
@@ -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.
+ *
+ * Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __ABC_OBJECT_H__
+#define __ABC_OBJECT_H__
+
+#include <Alembic/Abc/All.h>
+#include <Alembic/AbcGeom/All.h>
+
+#include "abc_exporter.h"
+
+extern "C" {
+#include "DNA_ID.h"
+}
+
+class AbcTransformWriter;
+
+struct Main;
+struct Object;
+
+/* ************************************************************************** */
+
+class AbcObjectWriter {
+protected:
+ Object *m_object;
+ ExportSettings &m_settings;
+
+ Scene *m_scene;
+ uint32_t m_time_sampling;
+
+ Imath::Box3d m_bounds;
+ std::vector<AbcObjectWriter *> m_children;
+
+ std::vector< std::pair<std::string, IDProperty *> > m_props;
+
+ bool m_first_frame;
+ std::string m_name;
+
+public:
+ AbcObjectWriter(Scene *scene,
+ Object *ob,
+ uint32_t time_sampling,
+ ExportSettings &settings,
+ AbcObjectWriter *parent = NULL);
+
+ virtual ~AbcObjectWriter();
+
+ void addChild(AbcObjectWriter *child);
+
+ virtual Imath::Box3d bounds();
+
+ void write();
+
+private:
+ virtual void do_write() = 0;
+};
+
+/* ************************************************************************** */
+
+class CacheFile;
+
+struct ImportSettings {
+ bool do_convert_mat;
+ float conversion_mat[4][4];
+
+ int from_up;
+ int from_forward;
+ float scale;
+ bool is_sequence;
+ bool set_frame_range;
+
+ /* Length and frame offset of file sequences. */
+ int sequence_len;
+ int offset;
+
+ /* From MeshSeqCacheModifierData.read_flag */
+ int read_flag;
+
+ bool validate_meshes;
+
+ CacheFile *cache_file;
+
+ ImportSettings()
+ : do_convert_mat(false)
+ , from_up(0)
+ , from_forward(0)
+ , scale(1.0f)
+ , is_sequence(false)
+ , set_frame_range(false)
+ , sequence_len(1)
+ , offset(0)
+ , read_flag(0)
+ , validate_meshes(false)
+ , cache_file(NULL)
+ {}
+};
+
+template <typename Schema>
+static bool has_animations(Schema &schema, ImportSettings *settings)
+{
+ if (settings->is_sequence) {
+ return true;
+ }
+
+ if (!schema.isConstant()) {
+ return true;
+ }
+
+ return false;
+}
+
+/* ************************************************************************** */
+
+struct DerivedMesh;
+
+using Alembic::AbcCoreAbstract::chrono_t;
+
+class AbcObjectReader {
+protected:
+ std::string m_name;
+ std::string m_object_name;
+ std::string m_data_name;
+ Object *m_object;
+ Alembic::Abc::IObject m_iobject;
+
+ ImportSettings *m_settings;
+
+ chrono_t m_min_time;
+ chrono_t m_max_time;
+
+ /* Use reference counting since the same reader may be used by multiple
+ * modifiers and/or constraints. */
+ int m_refcount;
+
+public:
+ explicit AbcObjectReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
+
+ virtual ~AbcObjectReader();
+
+ const Alembic::Abc::IObject &iobject() const;
+
+ Object *object() const;
+ void object(Object *ob);
+
+ virtual bool valid() const = 0;
+
+ virtual void readObjectData(Main *bmain, float time) = 0;
+
+ virtual DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag)
+ {
+ (void)time;
+ (void)read_flag;
+ return dm;
+ }
+
+ void readObjectMatrix(const float time);
+
+ void addCacheModifier();
+
+ chrono_t minTime() const;
+ chrono_t maxTime() const;
+
+ int refcount() const;
+ void incref();
+ void decref();
+
+ void read_matrix(float mat[4][4], const float time, const float scale, bool &is_constant);
+};
+
+Imath::M44d get_matrix(const Alembic::AbcGeom::IXformSchema &schema, const float time);
+
+#endif /* __ABC_OBJECT_H__ */
diff --git a/source/blender/alembic/intern/abc_points.cc b/source/blender/alembic/intern/abc_points.cc
new file mode 100644
index 00000000000..c16da621c77
--- /dev/null
+++ b/source/blender/alembic/intern/abc_points.cc
@@ -0,0 +1,219 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Kévin Dietrich.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+#include "abc_points.h"
+
+#include "abc_mesh.h"
+#include "abc_transform.h"
+#include "abc_util.h"
+
+extern "C" {
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_cdderivedmesh.h"
+#include "BKE_lattice.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_particle.h"
+#include "BKE_scene.h"
+
+#include "BLI_math.h"
+}
+
+using Alembic::AbcGeom::kVertexScope;
+using Alembic::AbcGeom::kWrapExisting;
+using Alembic::AbcGeom::P3fArraySamplePtr;
+using Alembic::AbcGeom::N3fArraySamplePtr;
+
+using Alembic::AbcGeom::ICompoundProperty;
+using Alembic::AbcGeom::IN3fArrayProperty;
+using Alembic::AbcGeom::IPoints;
+using Alembic::AbcGeom::IPointsSchema;
+using Alembic::AbcGeom::ISampleSelector;
+
+using Alembic::AbcGeom::OPoints;
+using Alembic::AbcGeom::OPointsSchema;
+
+/* ************************************************************************** */
+
+AbcPointsWriter::AbcPointsWriter(Scene *scene,
+ Object *ob,
+ AbcTransformWriter *parent,
+ uint32_t time_sampling,
+ ExportSettings &settings,
+ ParticleSystem *psys)
+ : AbcObjectWriter(scene, ob, time_sampling, settings, parent)
+{
+ m_psys = psys;
+
+ OPoints points(parent->alembicXform(), psys->name, m_time_sampling);
+ m_schema = points.getSchema();
+}
+
+void AbcPointsWriter::do_write()
+{
+ if (!m_psys) {
+ return;
+ }
+
+ std::vector<Imath::V3f> points;
+ std::vector<Imath::V3f> velocities;
+ std::vector<float> widths;
+ std::vector<uint64_t> ids;
+
+ ParticleKey state;
+
+ ParticleSimulationData sim;
+ sim.scene = m_scene;
+ sim.ob = m_object;
+ sim.psys = m_psys;
+
+ m_psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
+
+ uint64_t index = 0;
+ for (int p = 0; p < m_psys->totpart; p++) {
+ float pos[3], vel[3];
+
+ if (m_psys->particles[p].flag & (PARS_NO_DISP | PARS_UNEXIST)) {
+ continue;
+ }
+
+ state.time = BKE_scene_frame_get(m_scene);
+
+ if (psys_get_particle_state(&sim, p, &state, 0) == 0) {
+ continue;
+ }
+
+ /* location */
+ mul_v3_m4v3(pos, m_object->imat, state.co);
+
+ /* velocity */
+ sub_v3_v3v3(vel, state.co, m_psys->particles[p].prev_state.co);
+
+ /* Convert Z-up to Y-up. */
+ points.push_back(Imath::V3f(pos[0], pos[2], -pos[1]));
+ velocities.push_back(Imath::V3f(vel[0], vel[2], -vel[1]));
+ widths.push_back(m_psys->particles[p].size);
+ ids.push_back(index++);
+ }
+
+ if (m_psys->lattice_deform_data) {
+ end_latt_deform(m_psys->lattice_deform_data);
+ m_psys->lattice_deform_data = NULL;
+ }
+
+ Alembic::Abc::P3fArraySample psample(points);
+ Alembic::Abc::UInt64ArraySample idsample(ids);
+ Alembic::Abc::V3fArraySample vsample(velocities);
+ Alembic::Abc::FloatArraySample wsample_array(widths);
+ Alembic::AbcGeom::OFloatGeomParam::Sample wsample(wsample_array, kVertexScope);
+
+ m_sample = OPointsSchema::Sample(psample, idsample, vsample, wsample);
+ m_sample.setSelfBounds(bounds());
+
+ m_schema.set(m_sample);
+}
+
+/* ************************************************************************** */
+
+AbcPointsReader::AbcPointsReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
+ : AbcObjectReader(object, settings)
+{
+ IPoints ipoints(m_iobject, kWrapExisting);
+ m_schema = ipoints.getSchema();
+ get_min_max_time(m_iobject, m_schema, m_min_time, m_max_time);
+}
+
+bool AbcPointsReader::valid() const
+{
+ return m_schema.valid();
+}
+
+void AbcPointsReader::readObjectData(Main *bmain, float time)
+{
+ Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
+
+ DerivedMesh *dm = CDDM_from_mesh(mesh);
+ DerivedMesh *ndm = this->read_derivedmesh(dm, time, 0);
+
+ if (ndm != dm) {
+ dm->release(dm);
+ }
+
+ DM_to_mesh(ndm, mesh, m_object, CD_MASK_MESH, true);
+
+ if (m_settings->validate_meshes) {
+ BKE_mesh_validate(mesh, false, false);
+ }
+
+ m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
+ m_object->data = mesh;
+
+ if (has_animations(m_schema, m_settings)) {
+ addCacheModifier();
+ }
+}
+
+void read_points_sample(const IPointsSchema &schema,
+ const ISampleSelector &selector,
+ CDStreamConfig &config,
+ float time)
+{
+ Alembic::AbcGeom::IPointsSchema::Sample sample = schema.getValue(selector);
+
+ const P3fArraySamplePtr &positions = sample.getPositions();
+
+ ICompoundProperty prop = schema.getArbGeomParams();
+ N3fArraySamplePtr vnormals;
+
+ if (has_property(prop, "N")) {
+ const IN3fArrayProperty &normals_prop = IN3fArrayProperty(prop, "N", time);
+
+ if (normals_prop) {
+ vnormals = normals_prop.getValue(selector);
+ }
+ }
+
+ read_mverts(config.mvert, positions, vnormals);
+}
+
+DerivedMesh *AbcPointsReader::read_derivedmesh(DerivedMesh *dm, const float time, int /*read_flag*/)
+{
+ ISampleSelector sample_sel(time);
+ const IPointsSchema::Sample sample = m_schema.getValue(sample_sel);
+
+ const P3fArraySamplePtr &positions = sample.getPositions();
+
+ DerivedMesh *new_dm = NULL;
+
+ if (dm->getNumVerts(dm) != positions->size()) {
+ new_dm = CDDM_new(positions->size(), 0, 0, 0, 0);
+ }
+
+ CDStreamConfig config = get_config(new_dm ? new_dm : dm);
+ read_points_sample(m_schema, sample_sel, config, time);
+
+ return new_dm ? new_dm : dm;
+}
diff --git a/source/blender/alembic/intern/abc_points.h b/source/blender/alembic/intern/abc_points.h
new file mode 100644
index 00000000000..54873eed346
--- /dev/null
+++ b/source/blender/alembic/intern/abc_points.h
@@ -0,0 +1,72 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Kévin Dietrich.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+#ifndef __ABC_POINTS_H__
+#define __ABC_POINTS_H__
+
+#include "abc_object.h"
+#include "abc_customdata.h"
+
+class ParticleSystem;
+
+/* ************************************************************************** */
+
+class AbcPointsWriter : public AbcObjectWriter {
+ Alembic::AbcGeom::OPointsSchema m_schema;
+ Alembic::AbcGeom::OPointsSchema::Sample m_sample;
+ ParticleSystem *m_psys;
+
+public:
+ AbcPointsWriter(Scene *scene,
+ Object *ob,
+ AbcTransformWriter *parent,
+ uint32_t time_sampling,
+ ExportSettings &settings,
+ ParticleSystem *psys);
+
+ void do_write();
+};
+
+/* ************************************************************************** */
+
+class AbcPointsReader : public AbcObjectReader {
+ Alembic::AbcGeom::IPointsSchema m_schema;
+ Alembic::AbcGeom::IPointsSchema::Sample m_sample;
+
+public:
+ AbcPointsReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
+
+ bool valid() const;
+
+ void readObjectData(Main *bmain, float time);
+
+ DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag);
+};
+
+void read_points_sample(const Alembic::AbcGeom::IPointsSchema &schema,
+ const Alembic::AbcGeom::ISampleSelector &selector,
+ CDStreamConfig &config,
+ float time);
+
+#endif /* __ABC_POINTS_H__ */
diff --git a/source/blender/alembic/intern/abc_transform.cc b/source/blender/alembic/intern/abc_transform.cc
new file mode 100644
index 00000000000..7f8984f9970
--- /dev/null
+++ b/source/blender/alembic/intern/abc_transform.cc
@@ -0,0 +1,152 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "abc_transform.h"
+
+#include <OpenEXR/ImathBoxAlgo.h>
+
+#include "abc_util.h"
+
+extern "C" {
+#include "DNA_object_types.h"
+
+#include "BLI_math.h"
+
+#include "BKE_object.h"
+}
+
+using Alembic::AbcGeom::OObject;
+using Alembic::AbcGeom::OXform;
+
+/* ************************************************************************** */
+
+static bool has_parent_camera(Object *ob)
+{
+ if (!ob->parent) {
+ return false;
+ }
+
+ Object *parent = ob->parent;
+
+ if (parent->type == OB_CAMERA) {
+ return true;
+ }
+
+ return has_parent_camera(parent);
+}
+
+/* ************************************************************************** */
+
+AbcTransformWriter::AbcTransformWriter(Object *ob,
+ const OObject &abc_parent,
+ AbcTransformWriter *parent,
+ unsigned int time_sampling,
+ ExportSettings &settings)
+ : AbcObjectWriter(NULL, ob, time_sampling, settings, parent)
+{
+ m_is_animated = hasAnimation(m_object);
+ m_parent = NULL;
+
+ if (!m_is_animated) {
+ time_sampling = 0;
+ }
+
+ m_xform = OXform(abc_parent, get_id_name(m_object), time_sampling);
+ m_schema = m_xform.getSchema();
+}
+
+void AbcTransformWriter::do_write()
+{
+ if (m_first_frame) {
+ m_visibility = Alembic::AbcGeom::CreateVisibilityProperty(m_xform, m_xform.getSchema().getTimeSampling());
+ }
+
+ m_visibility.set(!(m_object->restrictflag & OB_RESTRICT_VIEW));
+
+ if (!m_first_frame && !m_is_animated) {
+ return;
+ }
+
+ float mat[4][4];
+ create_transform_matrix(m_object, mat);
+
+ /* Only apply rotation to root camera, parenting will propagate it. */
+ if (m_object->type == OB_CAMERA && !has_parent_camera(m_object)) {
+ float rot_mat[4][4];
+ unit_m4(rot_mat);
+ rotate_m4(rot_mat, 'X', -M_PI_2);
+ mul_m4_m4m4(mat, mat, rot_mat);
+ }
+
+ if (!m_object->parent) {
+ /* Only apply scaling to root objects, parenting will propagate it. */
+ float scale_mat[4][4];
+ scale_m4_fl(scale_mat, m_settings.global_scale);
+ mul_m4_m4m4(mat, mat, scale_mat);
+ mul_v3_fl(mat[3], m_settings.global_scale);
+ }
+
+ m_matrix = convert_matrix(mat);
+
+ m_sample.setMatrix(m_matrix);
+ m_schema.set(m_sample);
+}
+
+Imath::Box3d AbcTransformWriter::bounds()
+{
+ Imath::Box3d bounds;
+
+ for (int i = 0; i < m_children.size(); ++i) {
+ Imath::Box3d box(m_children[i]->bounds());
+ bounds.extendBy(box);
+ }
+
+ return Imath::transform(bounds, m_matrix);
+}
+
+bool AbcTransformWriter::hasAnimation(Object */*ob*/) const
+{
+ /* TODO(kevin): implement this. */
+ return true;
+}
+
+/* ************************************************************************** */
+
+AbcEmptyReader::AbcEmptyReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
+ : AbcObjectReader(object, settings)
+{
+ Alembic::AbcGeom::IXform xform(object, Alembic::AbcGeom::kWrapExisting);
+ m_schema = xform.getSchema();
+
+ get_min_max_time(m_iobject, m_schema, m_min_time, m_max_time);
+}
+
+bool AbcEmptyReader::valid() const
+{
+ return m_schema.valid();
+}
+
+void AbcEmptyReader::readObjectData(Main *bmain, float /*time*/)
+{
+ m_object = BKE_object_add_only_object(bmain, OB_EMPTY, m_object_name.c_str());
+ m_object->data = NULL;
+}
diff --git a/source/blender/alembic/intern/abc_transform.h b/source/blender/alembic/intern/abc_transform.h
new file mode 100644
index 00000000000..6a3aae216f2
--- /dev/null
+++ b/source/blender/alembic/intern/abc_transform.h
@@ -0,0 +1,73 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __ABC_TRANSFORM_H__
+#define __ABC_TRANSFORM_H__
+
+#include "abc_object.h"
+
+#include <Alembic/AbcGeom/All.h>
+
+/* ************************************************************************** */
+
+class AbcTransformWriter : public AbcObjectWriter {
+ Alembic::AbcGeom::OXform m_xform;
+ Alembic::AbcGeom::OXformSchema m_schema;
+ Alembic::AbcGeom::XformSample m_sample;
+ Alembic::AbcGeom::OVisibilityProperty m_visibility;
+ Alembic::Abc::M44d m_matrix;
+
+ bool m_is_animated;
+ Object *m_parent;
+ bool m_visible;
+
+public:
+ AbcTransformWriter(Object *ob,
+ const Alembic::AbcGeom::OObject &abc_parent,
+ AbcTransformWriter *parent,
+ unsigned int time_sampling,
+ ExportSettings &settings);
+
+ Alembic::AbcGeom::OXform &alembicXform() { return m_xform;}
+ virtual Imath::Box3d bounds();
+ void setParent(Object *p) { m_parent = p; }
+
+private:
+ virtual void do_write();
+
+ bool hasAnimation(Object *ob) const;
+};
+
+/* ************************************************************************** */
+
+class AbcEmptyReader : public AbcObjectReader {
+ Alembic::AbcGeom::IXformSchema m_schema;
+
+public:
+ AbcEmptyReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
+
+ bool valid() const;
+
+ void readObjectData(Main *bmain, float time);
+};
+
+#endif /* __ABC_TRANSFORM_H__ */
diff --git a/source/blender/alembic/intern/abc_util.cc b/source/blender/alembic/intern/abc_util.cc
new file mode 100644
index 00000000000..f87d18605d4
--- /dev/null
+++ b/source/blender/alembic/intern/abc_util.cc
@@ -0,0 +1,526 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "abc_util.h"
+
+#include "abc_camera.h"
+#include "abc_curves.h"
+#include "abc_mesh.h"
+#include "abc_nurbs.h"
+#include "abc_points.h"
+#include "abc_transform.h"
+
+#include <Alembic/AbcMaterial/IMaterial.h>
+
+#include <algorithm>
+
+extern "C" {
+#include "DNA_object_types.h"
+
+#include "BLI_math.h"
+}
+
+std::string get_id_name(Object *ob)
+{
+ if (!ob) {
+ return "";
+ }
+
+ return get_id_name(&ob->id);
+}
+
+std::string get_id_name(ID *id)
+{
+ std::string name(id->name + 2);
+ std::replace(name.begin(), name.end(), ' ', '_');
+ std::replace(name.begin(), name.end(), '.', '_');
+ std::replace(name.begin(), name.end(), ':', '_');
+
+ return name;
+}
+
+std::string get_object_dag_path_name(Object *ob, Object *dupli_parent)
+{
+ std::string name = get_id_name(ob);
+
+ Object *p = ob->parent;
+
+ while (p) {
+ name = get_id_name(p) + "/" + name;
+ p = p->parent;
+ }
+
+ if (dupli_parent && (ob != dupli_parent)) {
+ name = get_id_name(dupli_parent) + "/" + name;
+ }
+
+ return name;
+}
+
+bool object_selected(Object *ob)
+{
+ return ob->flag & SELECT;
+}
+
+bool parent_selected(Object *ob)
+{
+ if (object_selected(ob)) {
+ return true;
+ }
+
+ bool do_export = false;
+
+ Object *parent = ob->parent;
+
+ while (parent != NULL) {
+ if (object_selected(parent)) {
+ do_export = true;
+ break;
+ }
+
+ parent = parent->parent;
+ }
+
+ return do_export;
+}
+
+Imath::M44d convert_matrix(float mat[4][4])
+{
+ Imath::M44d m;
+
+ for (int i = 0; i < 4; ++i) {
+ for (int j = 0; j < 4; ++j) {
+ m[i][j] = mat[i][j];
+ }
+ }
+
+ return m;
+}
+
+void split(const std::string &s, const char delim, std::vector<std::string> &tokens)
+{
+ tokens.clear();
+
+ std::stringstream ss(s);
+ std::string item;
+
+ while (std::getline(ss, item, delim)) {
+ if (!item.empty()) {
+ tokens.push_back(item);
+ }
+ }
+}
+
+/* Create a rotation matrix for each axis from euler angles.
+ * Euler angles are swaped to change coordinate system. */
+static void create_rotation_matrix(
+ float rot_x_mat[3][3], float rot_y_mat[3][3],
+ float rot_z_mat[3][3], const float euler[3], const bool to_yup)
+{
+ const float rx = euler[0];
+ const float ry = (to_yup) ? euler[2] : -euler[2];
+ const float rz = (to_yup) ? -euler[1] : euler[1];
+
+ unit_m3(rot_x_mat);
+ unit_m3(rot_y_mat);
+ unit_m3(rot_z_mat);
+
+ rot_x_mat[1][1] = cos(rx);
+ rot_x_mat[2][1] = -sin(rx);
+ rot_x_mat[1][2] = sin(rx);
+ rot_x_mat[2][2] = cos(rx);
+
+ rot_y_mat[2][2] = cos(ry);
+ rot_y_mat[0][2] = -sin(ry);
+ rot_y_mat[2][0] = sin(ry);
+ rot_y_mat[0][0] = cos(ry);
+
+ rot_z_mat[0][0] = cos(rz);
+ rot_z_mat[1][0] = -sin(rz);
+ rot_z_mat[0][1] = sin(rz);
+ rot_z_mat[1][1] = cos(rz);
+}
+
+/* Recompute transform matrix of object in new coordinate system
+ * (from Y-Up to Z-Up). */
+void create_transform_matrix(float r_mat[4][4])
+{
+ float rot_mat[3][3], rot[3][3], scale_mat[4][4], invmat[4][4], transform_mat[4][4];
+ float rot_x_mat[3][3], rot_y_mat[3][3], rot_z_mat[3][3];
+ float loc[3], scale[3], euler[3];
+
+ zero_v3(loc);
+ zero_v3(scale);
+ zero_v3(euler);
+ unit_m3(rot);
+ unit_m3(rot_mat);
+ unit_m4(scale_mat);
+ unit_m4(transform_mat);
+ unit_m4(invmat);
+
+ /* Compute rotation matrix. */
+
+ /* Extract location, rotation, and scale from matrix. */
+ mat4_to_loc_rot_size(loc, rot, scale, r_mat);
+
+ /* Get euler angles from rotation matrix. */
+ mat3_to_eulO(euler, ROT_MODE_XYZ, rot);
+
+ /* Create X, Y, Z rotation matrices from euler angles. */
+ create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, false);
+
+ /* Concatenate rotation matrices. */
+ mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
+
+ /* Add rotation matrix to transformation matrix. */
+ copy_m4_m3(transform_mat, rot_mat);
+
+ /* Add translation to transformation matrix. */
+ copy_yup_zup(transform_mat[3], loc);
+
+ /* Create scale matrix. */
+ scale_mat[0][0] = scale[0];
+ scale_mat[1][1] = scale[2];
+ scale_mat[2][2] = scale[1];
+
+ /* Add scale to transformation matrix. */
+ mul_m4_m4m4(transform_mat, transform_mat, scale_mat);
+
+ copy_m4_m4(r_mat, transform_mat);
+}
+
+void convert_matrix(const Imath::M44d &xform, Object *ob,
+ float r_mat[4][4], float scale, bool has_alembic_parent)
+{
+ for (int i = 0; i < 4; ++i) {
+ for (int j = 0; j < 4; ++j) {
+ r_mat[i][j] = xform[i][j];
+ }
+ }
+
+ if (ob->type == OB_CAMERA) {
+ float cam_to_yup[4][4];
+ unit_m4(cam_to_yup);
+ rotate_m4(cam_to_yup, 'X', M_PI_2);
+ mul_m4_m4m4(r_mat, r_mat, cam_to_yup);
+ }
+
+ create_transform_matrix(r_mat);
+
+ if (ob->parent) {
+ mul_m4_m4m4(r_mat, ob->parent->obmat, r_mat);
+ }
+ /* TODO(kevin) */
+ else if (!has_alembic_parent) {
+ /* Only apply scaling to root objects, parenting will propagate it. */
+ float scale_mat[4][4];
+ scale_m4_fl(scale_mat, scale);
+ mul_m4_m4m4(r_mat, r_mat, scale_mat);
+ mul_v3_fl(r_mat[3], scale);
+ }
+}
+
+/* Recompute transform matrix of object in new coordinate system (from Z-Up to Y-Up). */
+void create_transform_matrix(Object *obj, float transform_mat[4][4])
+{
+ float rot_mat[3][3], rot[3][3], scale_mat[4][4], invmat[4][4], mat[4][4];
+ float rot_x_mat[3][3], rot_y_mat[3][3], rot_z_mat[3][3];
+ float loc[3], scale[3], euler[3];
+
+ zero_v3(loc);
+ zero_v3(scale);
+ zero_v3(euler);
+ unit_m3(rot);
+ unit_m3(rot_mat);
+ unit_m4(scale_mat);
+ unit_m4(transform_mat);
+ unit_m4(invmat);
+ unit_m4(mat);
+
+ /* get local matrix. */
+ if (obj->parent) {
+ invert_m4_m4(invmat, obj->parent->obmat);
+ mul_m4_m4m4(mat, invmat, obj->obmat);
+ }
+ else {
+ copy_m4_m4(mat, obj->obmat);
+ }
+
+ /* Compute rotation matrix. */
+ switch (obj->rotmode) {
+ case ROT_MODE_AXISANGLE:
+ {
+ /* Get euler angles from axis angle rotation. */
+ axis_angle_to_eulO(euler, ROT_MODE_XYZ, obj->rotAxis, obj->rotAngle);
+
+ /* Create X, Y, Z rotation matrices from euler angles. */
+ create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
+
+ /* Concatenate rotation matrices. */
+ mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
+
+ /* Extract location and scale from matrix. */
+ mat4_to_loc_rot_size(loc, rot, scale, mat);
+
+ break;
+ }
+ case ROT_MODE_QUAT:
+ {
+ float q[4];
+ copy_v4_v4(q, obj->quat);
+
+ /* Swap axis. */
+ q[2] = obj->quat[3];
+ q[3] = -obj->quat[2];
+
+ /* Compute rotation matrix from quaternion. */
+ quat_to_mat3(rot_mat, q);
+
+ /* Extract location and scale from matrix. */
+ mat4_to_loc_rot_size(loc, rot, scale, mat);
+
+ break;
+ }
+ case ROT_MODE_XYZ:
+ {
+ /* Extract location, rotation, and scale form matrix. */
+ mat4_to_loc_rot_size(loc, rot, scale, mat);
+
+ /* Get euler angles from rotation matrix. */
+ mat3_to_eulO(euler, ROT_MODE_XYZ, rot);
+
+ /* Create X, Y, Z rotation matrices from euler angles. */
+ create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
+
+ /* Concatenate rotation matrices. */
+ mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
+
+ break;
+ }
+ case ROT_MODE_XZY:
+ {
+ /* Extract location, rotation, and scale form matrix. */
+ mat4_to_loc_rot_size(loc, rot, scale, mat);
+
+ /* Get euler angles from rotation matrix. */
+ mat3_to_eulO(euler, ROT_MODE_XZY, rot);
+
+ /* Create X, Y, Z rotation matrices from euler angles. */
+ create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
+
+ /* Concatenate rotation matrices. */
+ mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
+
+ break;
+ }
+ case ROT_MODE_YXZ:
+ {
+ /* Extract location, rotation, and scale form matrix. */
+ mat4_to_loc_rot_size(loc, rot, scale, mat);
+
+ /* Get euler angles from rotation matrix. */
+ mat3_to_eulO(euler, ROT_MODE_YXZ, rot);
+
+ /* Create X, Y, Z rotation matrices from euler angles. */
+ create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
+
+ /* Concatenate rotation matrices. */
+ mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
+
+ break;
+ }
+ case ROT_MODE_YZX:
+ {
+ /* Extract location, rotation, and scale form matrix. */
+ mat4_to_loc_rot_size(loc, rot, scale, mat);
+
+ /* Get euler angles from rotation matrix. */
+ mat3_to_eulO(euler, ROT_MODE_YZX, rot);
+
+ /* Create X, Y, Z rotation matrices from euler angles. */
+ create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
+
+ /* Concatenate rotation matrices. */
+ mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
+
+ break;
+ }
+ case ROT_MODE_ZXY:
+ {
+ /* Extract location, rotation, and scale form matrix. */
+ mat4_to_loc_rot_size(loc, rot, scale, mat);
+
+ /* Get euler angles from rotation matrix. */
+ mat3_to_eulO(euler, ROT_MODE_ZXY, rot);
+
+ /* Create X, Y, Z rotation matrices from euler angles. */
+ create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
+
+ /* Concatenate rotation matrices. */
+ mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
+
+ break;
+ }
+ case ROT_MODE_ZYX:
+ {
+ /* Extract location, rotation, and scale form matrix. */
+ mat4_to_loc_rot_size(loc, rot, scale, mat);
+
+ /* Get euler angles from rotation matrix. */
+ mat3_to_eulO(euler, ROT_MODE_ZYX, rot);
+
+ /* Create X, Y, Z rotation matrices from euler angles. */
+ create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
+
+ /* Concatenate rotation matrices. */
+ mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
+ mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
+
+ break;
+ }
+ }
+
+ /* Add rotation matrix to transformation matrix. */
+ copy_m4_m3(transform_mat, rot_mat);
+
+ /* Add translation to transformation matrix. */
+ copy_zup_yup(transform_mat[3], loc);
+
+ /* Create scale matrix. */
+ scale_mat[0][0] = scale[0];
+ scale_mat[1][1] = scale[2];
+ scale_mat[2][2] = scale[1];
+
+ /* Add scale to transformation matrix. */
+ mul_m4_m4m4(transform_mat, transform_mat, scale_mat);
+}
+
+bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string &name)
+{
+ if (!prop.valid()) {
+ return false;
+ }
+
+ return prop.getPropertyHeader(name) != NULL;
+}
+
+typedef std::pair<Alembic::AbcCoreAbstract::index_t, float> index_time_pair_t;
+
+float get_weight_and_index(float time,
+ const Alembic::AbcCoreAbstract::TimeSamplingPtr &time_sampling,
+ int samples_number,
+ Alembic::AbcGeom::index_t &i0,
+ Alembic::AbcGeom::index_t &i1)
+{
+ samples_number = std::max(samples_number, 1);
+
+ index_time_pair_t t0 = time_sampling->getFloorIndex(time, samples_number);
+ i0 = i1 = t0.first;
+
+ if (samples_number == 1 || (fabs(time - t0.second) < 0.0001f)) {
+ return 0.0f;
+ }
+
+ index_time_pair_t t1 = time_sampling->getCeilIndex(time, samples_number);
+ i1 = t1.first;
+
+ if (i0 == i1) {
+ return 0.0f;
+ }
+
+ const float bias = (time - t0.second) / (t1.second - t0.second);
+
+ if (fabs(1.0f - bias) < 0.0001f) {
+ i0 = i1;
+ return 0.0f;
+ }
+
+ return bias;
+}
+
+//#define USE_NURBS
+
+AbcObjectReader *create_reader(const Alembic::AbcGeom::IObject &object, ImportSettings &settings)
+{
+ AbcObjectReader *reader = NULL;
+
+ const Alembic::AbcGeom::MetaData &md = object.getMetaData();
+
+ if (Alembic::AbcGeom::IXform::matches(md)) {
+ reader = new AbcEmptyReader(object, settings);
+ }
+ else if (Alembic::AbcGeom::IPolyMesh::matches(md)) {
+ reader = new AbcMeshReader(object, settings);
+ }
+ else if (Alembic::AbcGeom::ISubD::matches(md)) {
+ reader = new AbcSubDReader(object, settings);
+ }
+ else if (Alembic::AbcGeom::INuPatch::matches(md)) {
+#ifdef USE_NURBS
+ /* TODO(kevin): importing cyclic NURBS from other software crashes
+ * at the moment. This is due to the fact that NURBS in other
+ * software have duplicated points which causes buffer overflows in
+ * Blender. Need to figure out exactly how these points are
+ * duplicated, in all cases (cyclic U, cyclic V, and cyclic UV).
+ * Until this is fixed, disabling NURBS reading. */
+ reader = new AbcNurbsReader(child, settings);
+#endif
+ }
+ else if (Alembic::AbcGeom::ICamera::matches(md)) {
+ reader = new AbcCameraReader(object, settings);
+ }
+ else if (Alembic::AbcGeom::IPoints::matches(md)) {
+ reader = new AbcPointsReader(object, settings);
+ }
+ else if (Alembic::AbcMaterial::IMaterial::matches(md)) {
+ /* Pass for now. */
+ }
+ else if (Alembic::AbcGeom::ILight::matches(md)) {
+ /* Pass for now. */
+ }
+ else if (Alembic::AbcGeom::IFaceSet::matches(md)) {
+ /* Pass, those are handled in the mesh reader. */
+ }
+ else if (Alembic::AbcGeom::ICurves::matches(md)) {
+ reader = new AbcCurveReader(object, settings);
+ }
+ else {
+ assert(false);
+ }
+
+ return reader;
+}
diff --git a/source/blender/alembic/intern/abc_util.h b/source/blender/alembic/intern/abc_util.h
new file mode 100644
index 00000000000..2f423a9f8c5
--- /dev/null
+++ b/source/blender/alembic/intern/abc_util.h
@@ -0,0 +1,149 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __ABC_UTIL_H__
+#define __ABC_UTIL_H__
+
+#include <Alembic/Abc/All.h>
+#include <Alembic/AbcGeom/All.h>
+
+#ifdef _MSC_VER
+# define ABC_INLINE static __forceinline
+#else
+# define ABC_INLINE static inline
+#endif
+
+struct CacheReader {
+ int unused;
+};
+
+using Alembic::Abc::chrono_t;
+
+class AbcObjectReader;
+class ImportSettings;
+
+struct ID;
+struct Object;
+
+std::string get_id_name(ID *id);
+std::string get_id_name(Object *ob);
+std::string get_object_dag_path_name(Object *ob, Object *dupli_parent);
+
+bool object_selected(Object *ob);
+bool parent_selected(Object *ob);
+
+Imath::M44d convert_matrix(float mat[4][4]);
+void create_transform_matrix(float r_mat[4][4]);
+void create_transform_matrix(Object *obj, float transform_mat[4][4]);
+
+void split(const std::string &s, const char delim, std::vector<std::string> &tokens);
+
+template<class TContainer>
+bool begins_with(const TContainer &input, const TContainer &match)
+{
+ return input.size() >= match.size()
+ && std::equal(match.begin(), match.end(), input.begin());
+}
+
+void convert_matrix(const Imath::M44d &xform, Object *ob,
+ float r_mat[4][4], float scale, bool has_alembic_parent = false);
+
+template <typename Schema>
+void get_min_max_time_ex(const Schema &schema, chrono_t &min, chrono_t &max)
+{
+ const Alembic::Abc::TimeSamplingPtr &time_samp = schema.getTimeSampling();
+
+ if (!schema.isConstant()) {
+ const size_t num_samps = schema.getNumSamples();
+
+ if (num_samps > 0) {
+ const chrono_t min_time = time_samp->getSampleTime(0);
+ min = std::min(min, min_time);
+
+ const chrono_t max_time = time_samp->getSampleTime(num_samps - 1);
+ max = std::max(max, max_time);
+ }
+ }
+}
+
+template <typename Schema>
+void get_min_max_time(const Alembic::AbcGeom::IObject &object, const Schema &schema, chrono_t &min, chrono_t &max)
+{
+ get_min_max_time_ex(schema, min, max);
+
+ const Alembic::AbcGeom::IObject &parent = object.getParent();
+ if (parent.valid() && Alembic::AbcGeom::IXform::matches(parent.getMetaData())) {
+ Alembic::AbcGeom::IXform xform(parent, Alembic::AbcGeom::kWrapExisting);
+ get_min_max_time_ex(xform.getSchema(), min, max);
+ }
+}
+
+bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string &name);
+
+float get_weight_and_index(float time,
+ const Alembic::AbcCoreAbstract::TimeSamplingPtr &time_sampling,
+ int samples_number,
+ Alembic::AbcGeom::index_t &i0,
+ Alembic::AbcGeom::index_t &i1);
+
+AbcObjectReader *create_reader(const Alembic::AbcGeom::IObject &object, ImportSettings &settings);
+
+/* ************************** */
+
+/* TODO(kevin): for now keeping these transformations hardcoded to make sure
+ * everything works properly, and also because Alembic is almost exclusively
+ * used in Y-up software, but eventually they'll be set by the user in the UI
+ * like other importers/exporters do, to support other axis. */
+
+/* Copy from Y-up to Z-up. */
+
+ABC_INLINE void copy_yup_zup(float zup[3], const float yup[3])
+{
+ zup[0] = yup[0];
+ zup[1] = -yup[2];
+ zup[2] = yup[1];
+}
+
+ABC_INLINE void copy_yup_zup(short zup[3], const short yup[3])
+{
+ zup[0] = yup[0];
+ zup[1] = -yup[2];
+ zup[2] = yup[1];
+}
+
+/* Copy from Z-up to Y-up. */
+
+ABC_INLINE void copy_zup_yup(float yup[3], const float zup[3])
+{
+ yup[0] = zup[0];
+ yup[1] = zup[2];
+ yup[2] = -zup[1];
+}
+
+ABC_INLINE void copy_zup_yup(short yup[3], const short zup[3])
+{
+ yup[0] = zup[0];
+ yup[1] = zup[2];
+ yup[2] = -zup[1];
+}
+
+#endif /* __ABC_UTIL_H__ */
diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc
new file mode 100644
index 00000000000..e690a255505
--- /dev/null
+++ b/source/blender/alembic/intern/alembic_capi.cc
@@ -0,0 +1,887 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../ABC_alembic.h"
+
+#include <Alembic/AbcMaterial/IMaterial.h>
+
+#include "abc_archive.h"
+#include "abc_camera.h"
+#include "abc_curves.h"
+#include "abc_hair.h"
+#include "abc_mesh.h"
+#include "abc_nurbs.h"
+#include "abc_points.h"
+#include "abc_transform.h"
+#include "abc_util.h"
+
+extern "C" {
+#include "MEM_guardedalloc.h"
+
+#include "DNA_cachefile_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_cachefile.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_context.h"
+#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_scene.h"
+
+/* SpaceType struct has a member called 'new' which obviously conflicts with C++
+ * so temporarily redefining the new keyword to make it compile. */
+#define new extern_new
+#include "BKE_screen.h"
+#undef new
+
+#include "BLI_fileops.h"
+#include "BLI_ghash.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+}
+
+using Alembic::Abc::Int32ArraySamplePtr;
+using Alembic::Abc::ObjectHeader;
+
+using Alembic::AbcGeom::MetaData;
+using Alembic::AbcGeom::P3fArraySamplePtr;
+using Alembic::AbcGeom::kWrapExisting;
+
+using Alembic::AbcGeom::ICamera;
+using Alembic::AbcGeom::ICurves;
+using Alembic::AbcGeom::ICurvesSchema;
+using Alembic::AbcGeom::IFaceSet;
+using Alembic::AbcGeom::ILight;
+using Alembic::AbcGeom::INuPatch;
+using Alembic::AbcGeom::IObject;
+using Alembic::AbcGeom::IPoints;
+using Alembic::AbcGeom::IPointsSchema;
+using Alembic::AbcGeom::IPolyMesh;
+using Alembic::AbcGeom::IPolyMeshSchema;
+using Alembic::AbcGeom::ISampleSelector;
+using Alembic::AbcGeom::ISubD;
+using Alembic::AbcGeom::IV2fGeomParam;
+using Alembic::AbcGeom::IXform;
+using Alembic::AbcGeom::IXformSchema;
+using Alembic::AbcGeom::N3fArraySamplePtr;
+using Alembic::AbcGeom::XformSample;
+using Alembic::AbcGeom::ICompoundProperty;
+using Alembic::AbcGeom::IN3fArrayProperty;
+using Alembic::AbcGeom::IN3fGeomParam;
+using Alembic::AbcGeom::V3fArraySamplePtr;
+
+using Alembic::AbcMaterial::IMaterial;
+
+struct AbcArchiveHandle {
+ int unused;
+};
+
+ABC_INLINE ArchiveReader *archive_from_handle(AbcArchiveHandle *handle)
+{
+ return reinterpret_cast<ArchiveReader *>(handle);
+}
+
+ABC_INLINE AbcArchiveHandle *handle_from_archive(ArchiveReader *archive)
+{
+ return reinterpret_cast<AbcArchiveHandle *>(archive);
+}
+
+//#define USE_NURBS
+
+/* NOTE: this function is similar to visit_objects below, need to keep them in
+ * sync. */
+static void gather_objects_paths(const IObject &object, ListBase *object_paths)
+{
+ if (!object.valid()) {
+ return;
+ }
+
+ for (int i = 0; i < object.getNumChildren(); ++i) {
+ IObject child = object.getChild(i);
+
+ if (!child.valid()) {
+ continue;
+ }
+
+ bool get_path = false;
+
+ const MetaData &md = child.getMetaData();
+
+ if (IXform::matches(md)) {
+ /* Check whether or not this object is a Maya locator, which is
+ * similar to empties used as parent object in Blender. */
+ if (has_property(child.getProperties(), "locator")) {
+ get_path = true;
+ }
+ else {
+ /* Avoid creating an empty object if the child of this transform
+ * is not a transform (that is an empty). */
+ if (child.getNumChildren() == 1) {
+ if (IXform::matches(child.getChild(0).getMetaData())) {
+ get_path = true;
+ }
+#if 0
+ else {
+ std::cerr << "Skipping " << child.getFullName() << '\n';
+ }
+#endif
+ }
+ else {
+ get_path = true;
+ }
+ }
+ }
+ else if (IPolyMesh::matches(md)) {
+ get_path = true;
+ }
+ else if (ISubD::matches(md)) {
+ get_path = true;
+ }
+ else if (INuPatch::matches(md)) {
+#ifdef USE_NURBS
+ get_path = true;
+#endif
+ }
+ else if (ICamera::matches(md)) {
+ get_path = true;
+ }
+ else if (IPoints::matches(md)) {
+ get_path = true;
+ }
+ else if (IMaterial::matches(md)) {
+ /* Pass for now. */
+ }
+ else if (ILight::matches(md)) {
+ /* Pass for now. */
+ }
+ else if (IFaceSet::matches(md)) {
+ /* Pass, those are handled in the mesh reader. */
+ }
+ else if (ICurves::matches(md)) {
+ get_path = true;
+ }
+ else {
+ assert(false);
+ }
+
+ if (get_path) {
+ AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>(
+ MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath"));
+
+ BLI_strncpy(abc_path->path, child.getFullName().c_str(), PATH_MAX);
+
+ BLI_addtail(object_paths, abc_path);
+ }
+
+ gather_objects_paths(child, object_paths);
+ }
+}
+
+AbcArchiveHandle *ABC_create_handle(const char *filename, ListBase *object_paths)
+{
+ ArchiveReader *archive = new ArchiveReader(filename);
+
+ if (!archive->valid()) {
+ delete archive;
+ return NULL;
+ }
+
+ if (object_paths) {
+ gather_objects_paths(archive->getTop(), object_paths);
+ }
+
+ return handle_from_archive(archive);
+}
+
+void ABC_free_handle(AbcArchiveHandle *handle)
+{
+ delete archive_from_handle(handle);
+}
+
+int ABC_get_version()
+{
+ return ALEMBIC_LIBRARY_VERSION;
+}
+
+static void find_iobject(const IObject &object, IObject &ret,
+ const std::string &path)
+{
+ if (!object.valid()) {
+ return;
+ }
+
+ std::vector<std::string> tokens;
+ split(path, '/', tokens);
+
+ IObject tmp = object;
+
+ std::vector<std::string>::iterator iter;
+ for (iter = tokens.begin(); iter != tokens.end(); ++iter) {
+ IObject child = tmp.getChild(*iter);
+ tmp = child;
+ }
+
+ ret = tmp;
+}
+
+struct ExportJobData {
+ Scene *scene;
+ Main *bmain;
+
+ char filename[1024];
+ ExportSettings settings;
+
+ short *stop;
+ short *do_update;
+ float *progress;
+
+ bool was_canceled;
+};
+
+static void export_startjob(void *customdata, short *stop, short *do_update, float *progress)
+{
+ ExportJobData *data = static_cast<ExportJobData *>(customdata);
+
+ data->stop = stop;
+ data->do_update = do_update;
+ data->progress = progress;
+
+ /* XXX annoying hack: needed to prevent data corruption when changing
+ * scene frame in separate threads
+ */
+ G.is_rendering = true;
+ BKE_spacedata_draw_locks(true);
+
+ G.is_break = false;
+
+ try {
+ Scene *scene = data->scene;
+ AbcExporter exporter(scene, data->filename, data->settings);
+
+ const int orig_frame = CFRA;
+
+ data->was_canceled = false;
+ exporter(data->bmain, *data->progress, data->was_canceled);
+
+ if (CFRA != orig_frame) {
+ CFRA = orig_frame;
+
+ BKE_scene_update_for_newframe(data->bmain->eval_ctx, data->bmain,
+ scene, scene->lay);
+ }
+ }
+ catch (const std::exception &e) {
+ std::cerr << "Abc Export error: " << e.what() << '\n';
+ }
+ catch (...) {
+ std::cerr << "Abc Export error\n";
+ }
+}
+
+static void export_endjob(void *customdata)
+{
+ ExportJobData *data = static_cast<ExportJobData *>(customdata);
+
+ if (data->was_canceled && BLI_exists(data->filename)) {
+ BLI_delete(data->filename, false, false);
+ }
+
+ G.is_rendering = false;
+ BKE_spacedata_draw_locks(false);
+}
+
+void ABC_export(
+ Scene *scene,
+ bContext *C,
+ const char *filepath,
+ const struct AlembicExportParams *params)
+{
+ ExportJobData *job = static_cast<ExportJobData *>(MEM_mallocN(sizeof(ExportJobData), "ExportJobData"));
+ job->scene = scene;
+ job->bmain = CTX_data_main(C);
+ BLI_strncpy(job->filename, filepath, 1024);
+
+ job->settings.scene = job->scene;
+ job->settings.frame_start = params->frame_start;
+ job->settings.frame_end = params->frame_end;
+ job->settings.frame_step_xform = params->frame_step_xform;
+ job->settings.frame_step_shape = params->frame_step_shape;
+ job->settings.shutter_open = params->shutter_open;
+ job->settings.shutter_close = params->shutter_close;
+ job->settings.selected_only = params->selected_only;
+ job->settings.export_face_sets = params->face_sets;
+ job->settings.export_normals = params->normals;
+ job->settings.export_uvs = params->uvs;
+ job->settings.export_vcols = params->vcolors;
+ job->settings.apply_subdiv = params->apply_subdiv;
+ job->settings.flatten_hierarchy = params->flatten_hierarchy;
+ job->settings.visible_layers_only = params->visible_layers_only;
+ job->settings.renderable_only = params->renderable_only;
+ job->settings.use_subdiv_schema = params->use_subdiv_schema;
+ job->settings.export_ogawa = (params->compression_type == ABC_ARCHIVE_OGAWA);
+ job->settings.pack_uv = params->packuv;
+ job->settings.global_scale = params->global_scale;
+ job->settings.triangulate = params->triangulate;
+ job->settings.quad_method = params->quad_method;
+ job->settings.ngon_method = params->ngon_method;
+
+ if (job->settings.frame_start > job->settings.frame_end) {
+ std::swap(job->settings.frame_start, job->settings.frame_end);
+ }
+
+ wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
+ CTX_wm_window(C),
+ job->scene,
+ "Alembic Export",
+ WM_JOB_PROGRESS,
+ WM_JOB_TYPE_ALEMBIC);
+
+ /* setup job */
+ WM_jobs_customdata_set(wm_job, job, MEM_freeN);
+ WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME);
+ WM_jobs_callbacks(wm_job, export_startjob, NULL, NULL, export_endjob);
+
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+}
+
+/* ********************** Import file ********************** */
+
+static void visit_object(const IObject &object,
+ std::vector<AbcObjectReader *> &readers,
+ GHash *parent_map,
+ ImportSettings &settings)
+{
+ if (!object.valid()) {
+ return;
+ }
+
+ for (int i = 0; i < object.getNumChildren(); ++i) {
+ IObject child = object.getChild(i);
+
+ if (!child.valid()) {
+ continue;
+ }
+
+ AbcObjectReader *reader = NULL;
+
+ const MetaData &md = child.getMetaData();
+
+ if (IXform::matches(md)) {
+ bool create_xform = false;
+
+ /* Check whether or not this object is a Maya locator, which is
+ * similar to empties used as parent object in Blender. */
+ if (has_property(child.getProperties(), "locator")) {
+ create_xform = true;
+ }
+ else {
+ /* Avoid creating an empty object if the child of this transform
+ * is not a transform (that is an empty). */
+ if (child.getNumChildren() == 1) {
+ if (IXform::matches(child.getChild(0).getMetaData())) {
+ create_xform = true;
+ }
+#if 0
+ else {
+ std::cerr << "Skipping " << child.getFullName() << '\n';
+ }
+#endif
+ }
+ else {
+ create_xform = true;
+ }
+ }
+
+ if (create_xform) {
+ reader = new AbcEmptyReader(child, settings);
+ }
+ }
+ else if (IPolyMesh::matches(md)) {
+ reader = new AbcMeshReader(child, settings);
+ }
+ else if (ISubD::matches(md)) {
+ reader = new AbcSubDReader(child, settings);
+ }
+ else if (INuPatch::matches(md)) {
+#ifdef USE_NURBS
+ /* TODO(kevin): importing cyclic NURBS from other software crashes
+ * at the moment. This is due to the fact that NURBS in other
+ * software have duplicated points which causes buffer overflows in
+ * Blender. Need to figure out exactly how these points are
+ * duplicated, in all cases (cyclic U, cyclic V, and cyclic UV).
+ * Until this is fixed, disabling NURBS reading. */
+ reader = new AbcNurbsReader(child, settings);
+#endif
+ }
+ else if (ICamera::matches(md)) {
+ reader = new AbcCameraReader(child, settings);
+ }
+ else if (IPoints::matches(md)) {
+ reader = new AbcPointsReader(child, settings);
+ }
+ else if (IMaterial::matches(md)) {
+ /* Pass for now. */
+ }
+ else if (ILight::matches(md)) {
+ /* Pass for now. */
+ }
+ else if (IFaceSet::matches(md)) {
+ /* Pass, those are handled in the mesh reader. */
+ }
+ else if (ICurves::matches(md)) {
+ reader = new AbcCurveReader(child, settings);
+ }
+ else {
+ assert(false);
+ }
+
+ if (reader) {
+ readers.push_back(reader);
+ reader->incref();
+
+ AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>(
+ MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath"));
+
+ BLI_strncpy(abc_path->path, child.getFullName().c_str(), PATH_MAX);
+
+ BLI_addtail(&settings.cache_file->object_paths, abc_path);
+
+ /* Cast to `void *` explicitly to avoid compiler errors because it
+ * is a `const char *` which the compiler cast to `const void *`
+ * instead of the expected `void *`. */
+ BLI_ghash_insert(parent_map, (void *)child.getFullName().c_str(), reader);
+ }
+
+ visit_object(child, readers, parent_map, settings);
+ }
+}
+
+enum {
+ ABC_NO_ERROR = 0,
+ ABC_ARCHIVE_FAIL,
+};
+
+struct ImportJobData {
+ Main *bmain;
+ Scene *scene;
+
+ char filename[1024];
+ ImportSettings settings;
+
+ GHash *parent_map;
+ std::vector<AbcObjectReader *> readers;
+
+ short *stop;
+ short *do_update;
+ float *progress;
+
+ char error_code;
+ bool was_cancelled;
+};
+
+ABC_INLINE bool is_mesh_and_strands(const IObject &object)
+{
+ bool has_mesh = false;
+ bool has_curve = false;
+
+ for (int i = 0; i < object.getNumChildren(); ++i) {
+ const IObject &child = object.getChild(i);
+
+ if (!child.valid()) {
+ continue;
+ }
+
+ const MetaData &md = child.getMetaData();
+
+ if (IPolyMesh::matches(md)) {
+ has_mesh = true;
+ }
+ else if (ISubD::matches(md)) {
+ has_mesh = true;
+ }
+ else if (ICurves::matches(md)) {
+ has_curve = true;
+ }
+ else if (IPoints::matches(md)) {
+ has_curve = true;
+ }
+ }
+
+ return has_mesh && has_curve;
+}
+
+static void import_startjob(void *user_data, short *stop, short *do_update, float *progress)
+{
+ ImportJobData *data = static_cast<ImportJobData *>(user_data);
+
+ data->stop = stop;
+ data->do_update = do_update;
+ data->progress = progress;
+
+ ArchiveReader *archive = new ArchiveReader(data->filename);
+
+ if (!archive->valid()) {
+ delete archive;
+ data->error_code = ABC_ARCHIVE_FAIL;
+ return;
+ }
+
+ CacheFile *cache_file = static_cast<CacheFile *>(BKE_cachefile_add(data->bmain, BLI_path_basename(data->filename)));
+
+ /* Decrement the ID ref-count because it is going to be incremented for each
+ * modifier and constraint that it will be attached to, so since currently
+ * it is not used by anyone, its use count will off by one. */
+ id_us_min(&cache_file->id);
+
+ cache_file->is_sequence = data->settings.is_sequence;
+ cache_file->scale = data->settings.scale;
+ cache_file->handle = handle_from_archive(archive);
+ BLI_strncpy(cache_file->filepath, data->filename, 1024);
+
+ data->settings.cache_file = cache_file;
+
+ *data->do_update = true;
+ *data->progress = 0.05f;
+
+ data->parent_map = BLI_ghash_str_new("alembic parent ghash");
+
+ /* Parse Alembic Archive. */
+
+ visit_object(archive->getTop(), data->readers, data->parent_map, data->settings);
+
+ if (G.is_break) {
+ data->was_cancelled = true;
+ return;
+ }
+
+ *data->do_update = true;
+ *data->progress = 0.1f;
+
+ /* Create objects and set scene frame range. */
+
+ const float size = static_cast<float>(data->readers.size());
+ size_t i = 0;
+
+ chrono_t min_time = std::numeric_limits<chrono_t>::max();
+ chrono_t max_time = std::numeric_limits<chrono_t>::min();
+
+ std::vector<AbcObjectReader *>::iterator iter;
+ for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
+ AbcObjectReader *reader = *iter;
+
+ if (reader->valid()) {
+ reader->readObjectData(data->bmain, 0.0f);
+ reader->readObjectMatrix(0.0f);
+
+ min_time = std::min(min_time, reader->minTime());
+ max_time = std::max(max_time, reader->maxTime());
+ }
+
+ *data->progress = 0.1f + 0.6f * (++i / size);
+ *data->do_update = true;
+
+ if (G.is_break) {
+ data->was_cancelled = true;
+ return;
+ }
+ }
+
+ if (data->settings.set_frame_range) {
+ Scene *scene = data->scene;
+
+ if (data->settings.is_sequence) {
+ SFRA = data->settings.offset;
+ EFRA = SFRA + (data->settings.sequence_len - 1);
+ CFRA = SFRA;
+ }
+ else if (min_time < max_time) {
+ SFRA = min_time * FPS;
+ EFRA = max_time * FPS;
+ CFRA = SFRA;
+ }
+ }
+
+ /* Setup parentship. */
+
+ i = 0;
+ for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
+ const AbcObjectReader *reader = *iter;
+ const AbcObjectReader *parent_reader = NULL;
+ const IObject &iobject = reader->iobject();
+
+ IObject parent = iobject.getParent();
+
+ if (!IXform::matches(iobject.getHeader())) {
+ /* In the case of an non XForm node, the parent is the transform
+ * matrix of the data itself, so we get the its grand parent.
+ */
+
+ /* Special case with object only containing a mesh and some strands,
+ * we want both objects to be parented to the same object. */
+ if (!is_mesh_and_strands(parent)) {
+ parent = parent.getParent();
+ }
+ }
+
+ parent_reader = reinterpret_cast<AbcObjectReader *>(
+ BLI_ghash_lookup(data->parent_map, parent.getFullName().c_str()));
+
+ if (parent_reader) {
+ Object *parent = parent_reader->object();
+
+ if (parent != NULL && reader->object() != parent) {
+ Object *ob = reader->object();
+ ob->parent = parent;
+ }
+ }
+
+ *data->progress = 0.7f + 0.3f * (++i / size);
+ *data->do_update = true;
+
+ if (G.is_break) {
+ data->was_cancelled = true;
+ return;
+ }
+ }
+}
+
+static void import_endjob(void *user_data)
+{
+ ImportJobData *data = static_cast<ImportJobData *>(user_data);
+
+ std::vector<AbcObjectReader *>::iterator iter;
+
+ /* Delete objects on cancelation. */
+ if (data->was_cancelled) {
+ for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
+ Object *ob = (*iter)->object();
+
+ if (ob->data) {
+ BKE_libblock_free_us(data->bmain, ob->data);
+ ob->data = NULL;
+ }
+
+ BKE_libblock_free_us(data->bmain, ob);
+ }
+ }
+ else {
+ /* Add object to scene. */
+ BKE_scene_base_deselect_all(data->scene);
+
+ for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
+ Object *ob = (*iter)->object();
+ ob->lay = data->scene->lay;
+
+ BKE_scene_base_add(data->scene, ob);
+
+ DAG_id_tag_update_ex(data->bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ }
+
+ DAG_relations_tag_update(data->bmain);
+ }
+
+ for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
+ AbcObjectReader *reader = *iter;
+ reader->decref();
+
+ if (reader->refcount() == 0) {
+ delete reader;
+ }
+ }
+
+ if (data->parent_map) {
+ BLI_ghash_free(data->parent_map, NULL, NULL);
+ }
+
+ switch (data->error_code) {
+ default:
+ case ABC_NO_ERROR:
+ break;
+ case ABC_ARCHIVE_FAIL:
+ WM_report(RPT_ERROR, "Could not open Alembic archive for reading! See console for detail.");
+ break;
+ }
+
+ WM_main_add_notifier(NC_SCENE | ND_FRAME, data->scene);
+}
+
+static void import_freejob(void *user_data)
+{
+ ImportJobData *data = static_cast<ImportJobData *>(user_data);
+ delete data;
+}
+
+void ABC_import(bContext *C, const char *filepath, float scale, bool is_sequence, bool set_frame_range, int sequence_len, int offset, bool validate_meshes)
+{
+ /* Using new here since MEM_* funcs do not call ctor to properly initialize
+ * data. */
+ ImportJobData *job = new ImportJobData();
+ job->bmain = CTX_data_main(C);
+ job->scene = CTX_data_scene(C);
+ BLI_strncpy(job->filename, filepath, 1024);
+
+ job->settings.scale = scale;
+ job->settings.is_sequence = is_sequence;
+ job->settings.set_frame_range = set_frame_range;
+ job->settings.sequence_len = sequence_len;
+ job->settings.offset = offset;
+ job->settings.validate_meshes = validate_meshes;
+ job->parent_map = NULL;
+ job->error_code = ABC_NO_ERROR;
+ job->was_cancelled = false;
+
+ G.is_break = false;
+
+ wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
+ CTX_wm_window(C),
+ job->scene,
+ "Alembic Import",
+ WM_JOB_PROGRESS,
+ WM_JOB_TYPE_ALEMBIC);
+
+ /* setup job */
+ WM_jobs_customdata_set(wm_job, job, import_freejob);
+ WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME);
+ WM_jobs_callbacks(wm_job, import_startjob, NULL, NULL, import_endjob);
+
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+}
+
+/* ************************************************************************** */
+
+void ABC_get_transform(CacheReader *reader, float r_mat[4][4], float time, float scale)
+{
+ if (!reader) {
+ return;
+ }
+
+ AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader);
+
+ bool is_constant = false;
+ abc_reader->read_matrix(r_mat, time, scale, is_constant);
+}
+
+/* ************************************************************************** */
+
+DerivedMesh *ABC_read_mesh(CacheReader *reader,
+ Object *ob,
+ DerivedMesh *dm,
+ const float time,
+ const char **err_str,
+ int read_flag)
+{
+ AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader);
+ IObject iobject = abc_reader->iobject();
+
+ if (!iobject.valid()) {
+ *err_str = "Invalid object: verify object path";
+ return NULL;
+ }
+
+ const ObjectHeader &header = iobject.getHeader();
+
+ if (IPolyMesh::matches(header)) {
+ if (ob->type != OB_MESH) {
+ *err_str = "Object type mismatch: object path points to a mesh!";
+ return NULL;
+ }
+
+ return abc_reader->read_derivedmesh(dm, time, read_flag);
+ }
+ else if (ISubD::matches(header)) {
+ if (ob->type != OB_MESH) {
+ *err_str = "Object type mismatch: object path points to a subdivision mesh!";
+ return NULL;
+ }
+
+ return abc_reader->read_derivedmesh(dm, time, read_flag);
+ }
+ else if (IPoints::matches(header)) {
+ if (ob->type != OB_MESH) {
+ *err_str = "Object type mismatch: object path points to a point cloud (requires a mesh object)!";
+ return NULL;
+ }
+
+ return abc_reader->read_derivedmesh(dm, time, read_flag);
+ }
+ else if (ICurves::matches(header)) {
+ if (ob->type != OB_CURVE) {
+ *err_str = "Object type mismatch: object path points to a curve!";
+ return NULL;
+ }
+
+ return abc_reader->read_derivedmesh(dm, time, read_flag);
+ }
+
+ *err_str = "Unsupported object type: verify object path"; // or poke developer
+ return NULL;
+}
+
+/* ************************************************************************** */
+
+void CacheReader_free(CacheReader *reader)
+{
+ AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader);
+ abc_reader->decref();
+
+ if (abc_reader->refcount() == 0) {
+ delete abc_reader;
+ }
+}
+
+CacheReader *CacheReader_open_alembic_object(AbcArchiveHandle *handle, CacheReader *reader, Object *object, const char *object_path)
+{
+ if (object_path[0] == '\0') {
+ return reader;
+ }
+
+ ArchiveReader *archive = archive_from_handle(handle);
+
+ if (!archive || !archive->valid()) {
+ return reader;
+ }
+
+ IObject iobject;
+ find_iobject(archive->getTop(), iobject, object_path);
+
+ if (reader) {
+ CacheReader_free(reader);
+ }
+
+ ImportSettings settings;
+ AbcObjectReader *abc_reader = create_reader(iobject, settings);
+ abc_reader->object(object);
+ abc_reader->incref();
+
+ return reinterpret_cast<CacheReader *>(abc_reader);
+}
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index dfebaecb96e..44a1d08f1fd 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -370,12 +370,10 @@ static void blf_font_draw_buffer_ex(
fbuf[3] = 1.0f;
}
else {
- float alphatest;
fbuf[0] = (b_col_float[0] * a) + (fbuf[0] * (1.0f - a));
fbuf[1] = (b_col_float[1] * a) + (fbuf[1] * (1.0f - a));
fbuf[2] = (b_col_float[2] * a) + (fbuf[2] * (1.0f - a));
- fbuf[3] = (alphatest = (fbuf[3] + a)) < 1.0f ?
- alphatest : 1.0f;
+ fbuf[3] = MIN2(fbuf[3] + a, 1.0f); /* clamp to 1.0 */
}
}
}
@@ -407,12 +405,10 @@ static void blf_font_draw_buffer_ex(
cbuf[3] = 255;
}
else {
- int alphatest;
cbuf[0] = (unsigned char)((b_col_char[0] * a) + (cbuf[0] * (1.0f - a)));
cbuf[1] = (unsigned char)((b_col_char[1] * a) + (cbuf[1] * (1.0f - a)));
cbuf[2] = (unsigned char)((b_col_char[2] * a) + (cbuf[2] * (1.0f - a)));
- cbuf[3] = (unsigned char)(((alphatest = ((int)cbuf[3] + (int)(a * 255))) < 255) ?
- alphatest : 255);
+ cbuf[3] = (unsigned char)MIN2((int)cbuf[3] + (int)(a * 255), 255); /* clamp to 255 */
}
}
}
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index 41726e41176..aa7d539538b 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -55,6 +55,10 @@
#include "BIF_gl.h"
#include "BLF_api.h"
+#ifndef BLF_STANDALONE
+#include "GPU_basic_shader.h"
+#endif
+
#include "blf_internal_types.h"
#include "blf_internal.h"
@@ -179,6 +183,16 @@ static void blf_glyph_cache_texture(FontBLF *font, GlyphCacheBLF *gc)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+#ifndef BLF_STANDALONE
+ /* needed since basic shader doesn't support alpha-only textures,
+ * while we could add support this is only used in a few places
+ * (an alternative could be to have a simple shader for BLF). */
+ if (GLEW_ARB_texture_swizzle && GPU_basic_shader_use_glsl_get()) {
+ GLint swizzle_mask[] = {GL_ONE, GL_ONE, GL_ONE, GL_ALPHA};
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle_mask);
+ }
+#endif
+
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, gc->p2_width, gc->p2_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, NULL);
}
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index 7419b182c04..789bc8df7e5 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -181,7 +181,7 @@ struct DerivedMesh {
int numVertData, numEdgeData, numTessFaceData, numLoopData, numPolyData;
int needsFree; /* checked on ->release, is set to 0 for cached results */
int deformedOnly; /* set by modifier stack if only deformed from original */
- BVHCache bvhCache;
+ BVHCache *bvhCache;
struct GPUDrawObject *drawObject;
DerivedMeshType type;
float auto_bump_scale;
@@ -694,7 +694,7 @@ DerivedMesh *mesh_create_derived_render(
CustomDataMask dataMask);
DerivedMesh *getEditDerivedBMesh(
- struct BMEditMesh *em, struct Object *ob,
+ struct BMEditMesh *em, struct Object *ob, CustomDataMask data_mask,
float (*vertexCos)[3]);
DerivedMesh *mesh_create_derived_index_render(
@@ -723,7 +723,7 @@ DerivedMesh *mesh_create_derived_physics(
CustomDataMask dataMask);
DerivedMesh *editbmesh_get_derived_base(
- struct Object *, struct BMEditMesh *em);
+ struct Object *ob, struct BMEditMesh *em, CustomDataMask data_mask);
DerivedMesh *editbmesh_get_derived_cage(
struct Scene *scene, struct Object *,
struct BMEditMesh *em, CustomDataMask dataMask);
@@ -757,22 +757,22 @@ void DM_update_weight_mcol(
typedef struct DMVertexAttribs {
struct {
struct MLoopUV *array;
- int em_offset, gl_index, gl_texco;
+ int em_offset, gl_index, gl_texco, gl_info_index;
} tface[MAX_MTFACE];
struct {
struct MLoopCol *array;
- int em_offset, gl_index;
+ int em_offset, gl_index, gl_info_index;
} mcol[MAX_MCOL];
struct {
float (*array)[4];
- int em_offset, gl_index;
+ int em_offset, gl_index, gl_info_index;
} tang[MAX_MTFACE];
struct {
float (*array)[3];
- int em_offset, gl_index, gl_texco;
+ int em_offset, gl_index, gl_texco, gl_info_index;
} orco;
int tottface, totmcol, tottang, totorco;
@@ -783,6 +783,7 @@ void DM_vertex_attributes_from_gpu(
struct GPUVertexAttribs *gattribs, DMVertexAttribs *attribs);
void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert, int loop);
+void DM_draw_attrib_vertex_uniforms(const DMVertexAttribs *attribs);
void DM_calc_tangents_names_from_gpu(
const struct GPUVertexAttribs *gattribs,
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index c164cd542f3..6527ba7f94f 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -58,13 +58,12 @@ extern "C" {
struct bAction *add_empty_action(struct Main *bmain, const char name[]);
/* Allocate a copy of the given Action and all its data */
-struct bAction *BKE_action_copy(struct bAction *src);
+struct bAction *BKE_action_copy(struct Main *bmain, struct bAction *src);
/* Deallocate all of the Action's data, but not the Action itself */
void BKE_action_free(struct bAction *act);
-// XXX is this needed?
-void BKE_action_make_local(struct bAction *act);
+void BKE_action_make_local(struct Main *bmain, struct bAction *act, const bool lib_local);
/* Action API ----------------- */
@@ -79,12 +78,15 @@ typedef enum eAction_TransformFlags {
ACT_TRANS_ROT = (1 << 1),
/* scaling */
ACT_TRANS_SCALE = (1 << 2),
-
+
+ /* bbone shape - for all the parameters, provided one is set */
+ ACT_TRANS_BBONE = (1 << 3),
+
/* strictly not a transform, but custom properties are also
* quite often used in modern rigs
*/
- ACT_TRANS_PROP = (1 << 3),
-
+ ACT_TRANS_PROP = (1 << 4),
+
/* all flags */
ACT_TRANS_ONLY = (ACT_TRANS_LOC | ACT_TRANS_ROT | ACT_TRANS_SCALE),
ACT_TRANS_ALL = (ACT_TRANS_ONLY | ACT_TRANS_PROP)
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index dc751747f32..00ea323f934 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -37,6 +37,7 @@ struct Main;
struct AnimData;
struct KeyingSet;
struct KS_Path;
+struct PathResolvedRNA;
struct bContext;
struct PointerRNA;
@@ -50,7 +51,8 @@ struct AnimMapper;
/* AnimData API */
/* Check if the given ID-block can have AnimData */
-bool id_type_can_have_animdata(struct ID *id);
+bool id_type_can_have_animdata(const short id_type);
+bool id_can_have_animdata(const struct ID *id);
/* Get AnimData from the given ID-block */
struct AnimData *BKE_animdata_from_id(struct ID *id);
@@ -62,7 +64,7 @@ struct AnimData *BKE_animdata_add_id(struct ID *id);
bool BKE_animdata_set_action(struct ReportList *reports, struct ID *id, struct bAction *act);
/* Free AnimData */
-void BKE_animdata_free(struct ID *id);
+void BKE_animdata_free(struct ID *id, const bool do_id_user);
/* Copy AnimData */
struct AnimData *BKE_animdata_copy(struct AnimData *adt, const bool do_action);
@@ -177,7 +179,7 @@ void BKE_animsys_evaluate_all_animation(struct Main *main, struct Scene *scene,
/* TODO(sergey): This is mainly a temp public function. */
struct FCurve;
-bool BKE_animsys_execute_fcurve(struct PointerRNA *ptr, struct AnimMapper *remap, struct FCurve *fcu);
+bool BKE_animsys_execute_fcurve(struct PointerRNA *ptr, struct AnimMapper *remap, struct FCurve *fcu, float curval);
/* ------------ Specialized API --------------- */
/* There are a few special tools which require these following functions. They are NOT to be used
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index 6d00110e318..c2323100205 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -76,8 +76,8 @@ struct bArmature *BKE_armature_from_object(struct Object *ob);
int BKE_armature_bonelist_count(struct ListBase *lb);
void BKE_armature_bonelist_free(struct ListBase *lb);
void BKE_armature_free(struct bArmature *arm);
-void BKE_armature_make_local(struct bArmature *arm);
-struct bArmature *BKE_armature_copy(struct bArmature *arm);
+void BKE_armature_make_local(struct Main *bmain, struct bArmature *arm, const bool lib_local);
+struct bArmature *BKE_armature_copy(struct Main *bmain, struct bArmature *arm);
/* Bounding box. */
struct BoundBox *BKE_armature_boundbox_get(struct Object *ob);
@@ -95,6 +95,7 @@ float distfactor_to_bone(const float vec[3], const float b1[3], const float b2[3
void BKE_armature_where_is(struct bArmature *arm);
void BKE_armature_where_is_bone(struct Bone *bone, struct Bone *prevbone, const bool use_recursion);
+void BKE_pose_clear_pointers(struct bPose *pose);
void BKE_pose_rebuild(struct Object *ob, struct bArmature *arm);
void BKE_pose_where_is(struct Scene *scene, struct Object *ob);
void BKE_pose_where_is_bone(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime, bool do_extra);
@@ -135,6 +136,7 @@ typedef struct Mat4 {
float mat[4][4];
} Mat4;
+void equalize_bbone_bezier(float *data, int desired);
void b_bone_spline_setup(struct bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BBONE_SUBDIV]);
/* like EBONE_VISIBLE */
diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h
index 8ce85c8e615..d2d9c763031 100644
--- a/source/blender/blenkernel/BKE_blender.h
+++ b/source/blender/blenkernel/BKE_blender.h
@@ -50,6 +50,11 @@ void BKE_blender_userdef_refresh(void);
void BKE_blender_callback_test_break_set(void (*func)(void));
int BKE_blender_test_break(void);
+/* Blenders' own atexit (avoids leaking) */
+void BKE_blender_atexit_register(void (*func)(void *user_data), void *user_data);
+void BKE_blender_atexit_unregister(void (*func)(void *user_data), const void *user_data);
+void BKE_blender_atexit(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_blender_copybuffer.h b/source/blender/blenkernel/BKE_blender_copybuffer.h
index 8aaf295c33a..02bd96217f6 100644
--- a/source/blender/blenkernel/BKE_blender_copybuffer.h
+++ b/source/blender/blenkernel/BKE_blender_copybuffer.h
@@ -37,6 +37,7 @@ struct ID;
void BKE_copybuffer_begin(struct Main *bmain_src);
void BKE_copybuffer_tag_ID(struct ID *id);
bool BKE_copybuffer_save(struct Main *bmain_src, const char *filename, struct ReportList *reports);
+bool BKE_copybuffer_read(struct Main *bmain_dst, const char *libname, struct ReportList *reports);
bool BKE_copybuffer_paste(struct bContext *C, const char *libname, const short flag, struct ReportList *reports);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_blender_undo.h b/source/blender/blenkernel/BKE_blender_undo.h
index cd18bd8db40..9547eeb9838 100644
--- a/source/blender/blenkernel/BKE_blender_undo.h
+++ b/source/blender/blenkernel/BKE_blender_undo.h
@@ -45,6 +45,8 @@ extern const char *BKE_undo_get_name(int nr, bool *r_active);
extern bool BKE_undo_save_file(const char *filename);
extern struct Main *BKE_undo_get_main(struct Scene **r_scene);
+extern void BKE_undo_callback_wm_kill_jobs_set(void (*callback)(struct bContext *C));
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 618b36c5851..55142510f9e 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -27,7 +27,7 @@
/* these lines are grep'd, watch out for our not-so-awesome regex
* and keep comment above the defines.
* Use STRINGIFY() rather than defining with quotes */
-#define BLENDER_VERSION 277
+#define BLENDER_VERSION 278
#define BLENDER_SUBVERSION 1
/* Several breakages with 270, e.g. constraint deg vs rad */
#define BLENDER_MINVERSION 270
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index c663458963c..8bd4bdf89e1 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -44,8 +44,8 @@ void BKE_brush_system_exit(void);
void BKE_brush_init(struct Brush *brush);
struct Brush *BKE_brush_add(struct Main *bmain, const char *name, short ob_mode);
struct Brush *BKE_brush_first_search(struct Main *bmain, short ob_mode);
-struct Brush *BKE_brush_copy(struct Brush *brush);
-void BKE_brush_make_local(struct Brush *brush);
+struct Brush *BKE_brush_copy(struct Main *bmain, struct Brush *brush);
+void BKE_brush_make_local(struct Main *bmain, struct Brush *brush, const bool lib_local);
void BKE_brush_unlink(struct Main *bmain, struct Brush *brush);
void BKE_brush_free(struct Brush *brush);
diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h
index 856923b7b0f..07db2217bac 100644
--- a/source/blender/blenkernel/BKE_bvhutils.h
+++ b/source/blender/blenkernel/BKE_bvhutils.h
@@ -43,9 +43,11 @@ struct BMEditMesh;
struct MVert;
struct MFace;
+typedef struct LinkNode BVHCache;
+
/**
-* struct that kepts basic information about a BVHTree build from a editmesh
-*/
+ * struct that kepts basic information about a BVHTree build from a editmesh
+ */
typedef struct BVHTreeFromEditMesh {
struct BVHTree *tree;
@@ -54,11 +56,13 @@ typedef struct BVHTreeFromEditMesh {
BVHTree_RayCastCallback raycast_callback;
BVHTree_NearestToRayCallback nearest_to_ray_callback;
+ struct BMEditMesh *em;
+
/* radius for raycast */
float sphere_radius;
/* Private data */
- struct BMEditMesh *em;
+ bool cached;
} BVHTreeFromEditMesh;
@@ -118,6 +122,14 @@ BVHTree *bvhtree_from_mesh_verts_ex(
const bool vert_allocated, const BLI_bitmap *mask, int verts_num_active,
float epsilon, int tree_type, int axis);
+BVHTree *bvhtree_from_editmesh_edges(
+ BVHTreeFromEditMesh *data, struct BMEditMesh *em,
+ float epsilon, int tree_type, int axis);
+BVHTree *bvhtree_from_editmesh_edges_ex(
+ BVHTreeFromEditMesh *data, struct BMEditMesh *em,
+ const BLI_bitmap *edges_mask, int edges_num_active,
+ float epsilon, int tree_type, int axis);
+
BVHTree *bvhtree_from_mesh_edges(
struct BVHTreeFromMesh *data, struct DerivedMesh *mesh,
float epsilon, int tree_type, int axis);
@@ -133,12 +145,12 @@ BVHTree *bvhtree_from_mesh_faces_ex(
float epsilon, int tree_type, int axis);
BVHTree *bvhtree_from_editmesh_looptri(
- BVHTreeFromEditMesh *data, struct BMEditMesh *em, float epsilon,
- int tree_type, int axis);
+ BVHTreeFromEditMesh *data, struct BMEditMesh *em,
+ float epsilon, int tree_type, int axis, BVHCache **bvhCache);
BVHTree *bvhtree_from_editmesh_looptri_ex(
BVHTreeFromEditMesh *data, struct BMEditMesh *em,
const BLI_bitmap *mask, int looptri_num_active,
- float epsilon, int tree_type, int axis);
+ float epsilon, int tree_type, int axis, BVHCache **bvhCache);
BVHTree *bvhtree_from_mesh_looptri(
struct BVHTreeFromMesh *data, struct DerivedMesh *mesh, float epsilon, int tree_type, int axis);
@@ -165,9 +177,7 @@ float bvhtree_ray_tri_intersection(
float bvhtree_sphereray_tri_intersection(
const BVHTreeRay *ray, float radius, const float m_dist,
const float v0[3], const float v1[3], const float v2[3]);
-float nearest_point_in_tri_surface_squared(
- const float v0[3], const float v1[3], const float v2[3],
- const float p[3], int *v, int *e, float nearest[3]);
+
/**
* BVHCache
@@ -179,30 +189,16 @@ enum {
BVHTREE_FROM_EDGES = 1,
BVHTREE_FROM_FACES = 2,
BVHTREE_FROM_LOOPTRI = 3,
-};
-typedef struct LinkNode *BVHCache;
+ BVHTREE_FROM_EM_LOOPTRI = 4,
+};
-/**
- * Queries a bvhcache for the cache bvhtree of the request type
- */
BVHTree *bvhcache_find(BVHCache *cache, int type);
+bool bvhcache_has_tree(const BVHCache *cache, const BVHTree *tree);
+void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, int type);
+void bvhcache_init(BVHCache **cache_p);
+void bvhcache_free(BVHCache **cache_p);
-/**
- * Inserts a BVHTree of the given type under the cache
- * After that the caller no longer needs to worry when to free the BVHTree
- * as that will be done when the cache is freed.
- *
- * A call to this assumes that there was no previous cached tree of the given type
- */
-void bvhcache_insert(BVHCache *cache, BVHTree *tree, int type);
-
-/**
- * inits and frees a bvhcache
- */
-void bvhcache_init(BVHCache *cache);
-void bvhcache_free(BVHCache *cache);
#endif
-
diff --git a/source/blender/blenkernel/BKE_cachefile.h b/source/blender/blenkernel/BKE_cachefile.h
new file mode 100644
index 00000000000..7e1c069df9a
--- /dev/null
+++ b/source/blender/blenkernel/BKE_cachefile.h
@@ -0,0 +1,72 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Kevin Dietrich.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BKE_CACHEFILE_H__
+#define __BKE_CACHEFILE_H__
+
+/** \file BKE_cachefile.h
+ * \ingroup bke
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct CacheFile;
+struct Main;
+struct Scene;
+
+void BKE_cachefiles_init(void);
+void BKE_cachefiles_exit(void);
+
+void *BKE_cachefile_add(struct Main *bmain, const char *name);
+
+void BKE_cachefile_init(struct CacheFile *cache_file);
+
+void BKE_cachefile_free(struct CacheFile *cache_file);
+
+struct CacheFile *BKE_cachefile_copy(struct Main *bmain, struct CacheFile *cache_file);
+
+void BKE_cachefile_make_local(struct Main *bmain, struct CacheFile *cache_file, const bool lib_local);
+
+void BKE_cachefile_reload(const struct Main *bmain, struct CacheFile *cache_file);
+
+void BKE_cachefile_ensure_handle(const struct Main *bmain, struct CacheFile *cache_file);
+
+void BKE_cachefile_update_frame(struct Main *bmain, struct Scene *scene,const float ctime, const float fps);
+
+bool BKE_cachefile_filepath_get(
+ const struct Main *bmain, const struct CacheFile *cache_file, float frame,
+ char r_filename[1024]);
+
+float BKE_cachefile_time_offset(struct CacheFile *cache_file, const float time, const float fps);
+
+void BKE_cachefile_clean(struct Scene *scene, struct CacheFile *cache_file);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BKE_CACHEFILE_H__ */
diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h
index d13a711c589..31a732cf7e5 100644
--- a/source/blender/blenkernel/BKE_camera.h
+++ b/source/blender/blenkernel/BKE_camera.h
@@ -52,8 +52,8 @@ struct GPUFXSettings;
void BKE_camera_init(struct Camera *cam);
void *BKE_camera_add(struct Main *bmain, const char *name);
-struct Camera *BKE_camera_copy(struct Camera *cam);
-void BKE_camera_make_local(struct Camera *cam);
+struct Camera *BKE_camera_copy(struct Main *bmain, struct Camera *cam);
+void BKE_camera_make_local(struct Main *bmain, struct Camera *cam, const bool lib_local);
void BKE_camera_free(struct Camera *ca);
/* Camera Usage */
diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h
index 50fcbd8e139..36330242f18 100644
--- a/source/blender/blenkernel/BKE_cloth.h
+++ b/source/blender/blenkernel/BKE_cloth.h
@@ -171,6 +171,7 @@ typedef enum {
CLOTH_SIMSETTINGS_FLAG_CCACHE_EDIT = (1 << 12), /* edit cache in editmode */
CLOTH_SIMSETTINGS_FLAG_NO_SPRING_COMPRESS = (1 << 13), /* don't allow spring compression */
CLOTH_SIMSETTINGS_FLAG_SEW = (1 << 14), /* pull ends of loose edges together */
+ CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH = (1 << 15), /* make simulation respect deformations in the base object */
} CLOTH_SIMSETTINGS_FLAGS;
/* COLLISION FLAGS */
diff --git a/source/blender/blenkernel/BKE_collision.h b/source/blender/blenkernel/BKE_collision.h
index d5b4a584ec6..8fedcd4ab06 100644
--- a/source/blender/blenkernel/BKE_collision.h
+++ b/source/blender/blenkernel/BKE_collision.h
@@ -146,6 +146,10 @@ void collision_get_collider_velocity(float vel_old[3], float vel_new[3], struct
/////////////////////////////////////////////////
// used in effect.c
/////////////////////////////////////////////////
+
+/* explicit control over layer mask and dupli recursion */
+struct Object **get_collisionobjects_ext(struct Scene *scene, struct Object *self, struct Group *group, int layer, unsigned int *numcollobj, unsigned int modifier_type, bool dupli);
+
struct Object **get_collisionobjects(struct Scene *scene, struct Object *self, struct Group *group, unsigned int *numcollobj, unsigned int modifier_type);
typedef struct ColliderCache {
diff --git a/source/blender/blenkernel/BKE_colortools.h b/source/blender/blenkernel/BKE_colortools.h
index e5d348031e9..5b4f5910821 100644
--- a/source/blender/blenkernel/BKE_colortools.h
+++ b/source/blender/blenkernel/BKE_colortools.h
@@ -61,7 +61,7 @@ void curvemap_reset(struct CurveMap *cuma, const struct rctf
void curvemap_remove(struct CurveMap *cuma, const short flag);
bool curvemap_remove_point(struct CurveMap *cuma, struct CurveMapPoint *cmp);
struct CurveMapPoint *curvemap_insert(struct CurveMap *cuma, float x, float y);
-void curvemap_sethandle(struct CurveMap *cuma, int type);
+void curvemap_handle_set(struct CurveMap *cuma, int type);
void curvemapping_changed(struct CurveMapping *cumap, const bool rem_doubles);
void curvemapping_changed_all(struct CurveMapping *cumap);
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index 65a68a4387c..4da6a61cbfa 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -39,6 +39,7 @@ extern "C" {
struct ARegion;
struct bScreen;
+struct CacheFile;
struct ListBase;
struct Main;
struct Object;
@@ -58,6 +59,9 @@ struct bPoseChannel;
struct bGPdata;
struct bGPDlayer;
struct bGPDframe;
+struct bGPDpalette;
+struct bGPDpalettecolor;
+struct bGPDbrush;
struct wmWindow;
struct wmWindowManager;
struct SpaceText;
@@ -268,6 +272,8 @@ struct Text *CTX_data_edit_text(const bContext *C);
struct MovieClip *CTX_data_edit_movieclip(const bContext *C);
struct Mask *CTX_data_edit_mask(const bContext *C);
+struct CacheFile *CTX_data_edit_cachefile(const bContext *C);
+
int CTX_data_selected_nodes(const bContext *C, ListBase *list);
struct EditBone *CTX_data_active_bone(const bContext *C);
@@ -283,6 +289,9 @@ int CTX_data_visible_pose_bones(const bContext *C, ListBase *list);
struct bGPdata *CTX_data_gpencil_data(const bContext *C);
struct bGPDlayer *CTX_data_active_gpencil_layer(const bContext *C);
struct bGPDframe *CTX_data_active_gpencil_frame(const bContext *C);
+struct bGPDpalette *CTX_data_active_gpencil_palette(const bContext *C);
+struct bGPDpalettecolor *CTX_data_active_gpencil_palettecolor(const bContext *C);
+struct bGPDbrush *CTX_data_active_gpencil_brush(const bContext *C);
int CTX_data_visible_gpencil_layers(const bContext *C, ListBase *list);
int CTX_data_editable_gpencil_layers(const bContext *C, ListBase *list);
int CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list);
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
index 061270b8b41..5558786d254 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -66,13 +66,12 @@ typedef struct CurveCache {
#define CU_DO_2DFILL(cu) ((((cu)->flag & CU_3D) == 0) && (((cu)->flag & (CU_FRONT | CU_BACK)) != 0))
/* ** Curve ** */
-void BKE_curve_unlink(struct Curve *cu);
void BKE_curve_free(struct Curve *cu);
void BKE_curve_editfont_free(struct Curve *cu);
void BKE_curve_init(struct Curve *cu);
struct Curve *BKE_curve_add(struct Main *bmain, const char *name, int type);
-struct Curve *BKE_curve_copy(struct Curve *cu);
-void BKE_curve_make_local(struct Curve *cu);
+struct Curve *BKE_curve_copy(struct Main *bmain, struct Curve *cu);
+void BKE_curve_make_local(struct Main *bmain, struct Curve *cu, const bool lib_local);
short BKE_curve_type_get(struct Curve *cu);
void BKE_curve_type_test(struct Object *ob);
void BKE_curve_curve_dimension_update(struct Curve *cu);
@@ -151,6 +150,16 @@ void BKE_nurb_minmax(struct Nurb *nu, bool use_radius, float min[3], float max[3
void BKE_nurb_makeFaces(struct Nurb *nu, float *coord_array, int rowstride, int resolu, int resolv);
void BKE_nurb_makeCurve(struct Nurb *nu, float *coord_array, float *tilt_array, float *radius_array, float *weight_array, int resolu, int stride);
+unsigned int BKE_curve_calc_coords_axis_len(
+ const unsigned int bezt_array_len, const unsigned int resolu,
+ const bool is_cyclic, const bool use_cyclic_duplicate_endpoint);
+void BKE_curve_calc_coords_axis(
+ const struct BezTriple *bezt_array, const unsigned int bezt_array_len, const unsigned int resolu,
+ const bool is_cyclic, const bool use_cyclic_duplicate_endpoint,
+ /* array params */
+ const unsigned int axis, const unsigned int stride,
+ float *r_points);
+
void BKE_nurb_knot_calc_u(struct Nurb *nu);
void BKE_nurb_knot_calc_v(struct Nurb *nu);
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index 17ad51a7a16..2cdda34b9b5 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -244,7 +244,7 @@ void CustomData_free_elem(struct CustomData *data, int index, int count);
*/
void CustomData_interp(
const struct CustomData *source, struct CustomData *dest,
- int *src_indices, float *weights, float *sub_weights,
+ const int *src_indices, const float *weights, const float *sub_weights,
int count, int dest_index);
void CustomData_bmesh_interp_n(
struct CustomData *data, const void **src_blocks, const float *weights,
@@ -358,7 +358,7 @@ void CustomData_file_write_prepare(
struct CustomDataLayer **r_write_layers, struct CustomDataLayer *write_layers_buff, size_t write_layers_size);
/* query info over types */
-void CustomData_file_write_info(int type, const char **structname, int *structnum);
+void CustomData_file_write_info(int type, const char **r_struct_name, int *r_struct_num);
int CustomData_sizeof(int type);
/* get the name of a layer type */
diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h
index 3b096773d96..9625f05192a 100644
--- a/source/blender/blenkernel/BKE_displist.h
+++ b/source/blender/blenkernel/BKE_displist.h
@@ -45,10 +45,14 @@
#define DL_VERTS 7
/* dl->flag */
-#define DL_CYCL_U 1
-#define DL_CYCL_V 2
-#define DL_FRONT_CURVE 4
-#define DL_BACK_CURVE 8
+enum {
+ /** U/V swapped here compared with #Nurb.flagu, #Nurb.flagv and #CU_NURB_CYCLIC */
+ DL_CYCL_U = (1 << 0),
+ DL_CYCL_V = (1 << 1),
+
+ DL_FRONT_CURVE = (1 << 2),
+ DL_BACK_CURVE = (1 << 3),
+};
/* prototypes */
@@ -70,7 +74,7 @@ typedef struct DispList {
int charidx;
int totindex; /* indexed array drawing surfaces */
- unsigned int *bevelSplitFlag;
+ unsigned int *bevel_split; /* BLI_bitmap */
} DispList;
void BKE_displist_copy(struct ListBase *lbn, struct ListBase *lb);
diff --git a/source/blender/blenkernel/BKE_dynamicpaint.h b/source/blender/blenkernel/BKE_dynamicpaint.h
index 00256176d98..5abb53d4c52 100644
--- a/source/blender/blenkernel/BKE_dynamicpaint.h
+++ b/source/blender/blenkernel/BKE_dynamicpaint.h
@@ -82,7 +82,7 @@ void dynamicPaint_resetPreview(struct DynamicPaintCanvasSettings *canvas);
struct DynamicPaintSurface *get_activeSurface(struct DynamicPaintCanvasSettings *canvas);
/* image sequence baking */
-int dynamicPaint_createUVSurface(struct Scene *scene, struct DynamicPaintSurface *surface);
+int dynamicPaint_createUVSurface(struct Scene *scene, struct DynamicPaintSurface *surface, float *progress, short *do_update);
int dynamicPaint_calculateFrame(struct DynamicPaintSurface *surface, struct Scene *scene, struct Object *cObject, int frame);
void dynamicPaint_outputSurfaceImage(struct DynamicPaintSurface *surface, char *filename, short output_layer);
diff --git a/source/blender/blenkernel/BKE_effect.h b/source/blender/blenkernel/BKE_effect.h
index f8fee444d91..b934ec7166d 100644
--- a/source/blender/blenkernel/BKE_effect.h
+++ b/source/blender/blenkernel/BKE_effect.h
@@ -110,7 +110,7 @@ typedef struct EffectorCache {
} EffectorCache;
void free_partdeflect(struct PartDeflect *pd);
-struct ListBase *pdInitEffectors(struct Scene *scene, struct Object *ob_src, struct ParticleSystem *psys_src, struct EffectorWeights *weights, bool precalc);
+struct ListBase *pdInitEffectors(struct Scene *scene, struct Object *ob_src, struct ParticleSystem *psys_src, struct EffectorWeights *weights, bool for_simulation);
void pdEndEffectors(struct ListBase **effectors);
void pdPrecalculateEffectors(struct ListBase *effectors);
void pdDoEffectors(struct ListBase *effectors, struct ListBase *colliders, struct EffectorWeights *weights, struct EffectedPoint *point, float *force, float *impulse);
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index 2022d11d508..3a45097efc5 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -48,6 +48,7 @@ struct AnimData;
struct bAction;
struct BezTriple;
struct StructRNA;
+struct PathResolvedRNA;
struct PointerRNA;
struct PropertyRNA;
@@ -107,7 +108,7 @@ bool driver_get_variable_property(
struct ChannelDriver *driver, struct DriverTarget *dtar,
struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index);
-float evaluate_driver(struct ChannelDriver *driver, const float evaltime);
+float evaluate_driver(struct PathResolvedRNA *anim_rna, struct ChannelDriver *driver, const float evaltime);
/* ************** F-Curve Modifiers *************** */
@@ -278,8 +279,9 @@ void correct_bezpart(float v1[2], float v2[2], float v3[2], float v4[2]);
/* evaluate fcurve */
float evaluate_fcurve(struct FCurve *fcu, float evaltime);
+float evaluate_fcurve_driver(struct PathResolvedRNA *anim_rna, struct FCurve *fcu, float evaltime);
/* evaluate fcurve and store value */
-void calculate_fcurve(struct FCurve *fcu, float ctime);
+float calculate_fcurve(struct PathResolvedRNA *anim_rna, struct FCurve *fcu, float evaltime);
/* ************* F-Curve Samples API ******************** */
diff --git a/source/blender/blenkernel/BKE_font.h b/source/blender/blenkernel/BKE_font.h
index 0711c423d1c..6775639125f 100644
--- a/source/blender/blenkernel/BKE_font.h
+++ b/source/blender/blenkernel/BKE_font.h
@@ -82,6 +82,8 @@ struct VFont *BKE_vfont_load(struct Main *bmain, const char *filepath);
struct VFont *BKE_vfont_load_exists_ex(struct Main *bmain, const char *filepath, bool *r_exists);
struct VFont *BKE_vfont_load_exists(struct Main *bmain, const char *filepath);
+void BKE_vfont_make_local(struct Main *bmain, struct VFont *vfont, const bool lib_local);
+
bool BKE_vfont_to_curve_ex(struct Main *bmain, struct Object *ob, int mode,
struct ListBase *r_nubase,
const wchar_t **r_text, int *r_text_len, bool *r_text_free,
diff --git a/source/blender/blenkernel/BKE_freestyle.h b/source/blender/blenkernel/BKE_freestyle.h
index e10594634f0..50407f3bdfc 100644
--- a/source/blender/blenkernel/BKE_freestyle.h
+++ b/source/blender/blenkernel/BKE_freestyle.h
@@ -55,8 +55,7 @@ void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *con
/* FreestyleConfig.modules */
FreestyleModuleConfig *BKE_freestyle_module_add(FreestyleConfig *config);
bool BKE_freestyle_module_delete(FreestyleConfig *config, FreestyleModuleConfig *module_conf);
-bool BKE_freestyle_module_move_up(FreestyleConfig *config, FreestyleModuleConfig *module_conf);
-bool BKE_freestyle_module_move_down(FreestyleConfig *config, FreestyleModuleConfig *module_conf);
+bool BKE_freestyle_module_move(FreestyleConfig *config, FreestyleModuleConfig *module_conf, int direction);
/* FreestyleConfig.linesets */
FreestyleLineSet *BKE_freestyle_lineset_add(struct Main *bmain, FreestyleConfig *config, const char *name);
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index 26a40597ca8..5ef5a807f63 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -178,6 +178,7 @@ enum {
#define G_FILE_MESH_COMPAT (1 << 26)
/* On write, restore paths after editing them (G_FILE_RELATIVE_REMAP) */
#define G_FILE_SAVE_COPY (1 << 27)
+#define G_FILE_GLSL_NO_ENV_LIGHTING (1 << 28)
#define G_FILE_FLAGS_RUNTIME (G_FILE_NO_UI | G_FILE_RELATIVE_REMAP | G_FILE_MESH_COMPAT | G_FILE_SAVE_COPY)
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index 24e330d927f..ab8b83f8271 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -31,35 +31,53 @@
* \author Joshua Leung
*/
+struct ToolSettings;
struct ListBase;
struct bGPdata;
struct bGPDlayer;
struct bGPDframe;
struct bGPDstroke;
+struct bGPDpalette;
+struct bGPDpalettecolor;
+struct Main;
/* ------------ Grease-Pencil API ------------------ */
-bool free_gpencil_strokes(struct bGPDframe *gpf);
-void free_gpencil_frames(struct bGPDlayer *gpl);
-void free_gpencil_layers(struct ListBase *list);
-void BKE_gpencil_free(struct bGPdata *gpd);
+void BKE_gpencil_free_stroke(struct bGPDstroke *gps);
+bool BKE_gpencil_free_strokes(struct bGPDframe *gpf);
+void BKE_gpencil_free_frames(struct bGPDlayer *gpl);
+void BKE_gpencil_free_layers(struct ListBase *list);
+void BKE_gpencil_free_brushes(struct ListBase *list);
+void BKE_gpencil_free_palettes(struct ListBase *list);
+void BKE_gpencil_free(struct bGPdata *gpd, bool free_palettes);
-void gpencil_stroke_sync_selection(struct bGPDstroke *gps);
+void BKE_gpencil_stroke_sync_selection(struct bGPDstroke *gps);
-struct bGPDframe *gpencil_frame_addnew(struct bGPDlayer *gpl, int cframe);
-struct bGPDframe *gpencil_frame_addcopy(struct bGPDlayer *gpl, int cframe);
-struct bGPDlayer *gpencil_layer_addnew(struct bGPdata *gpd, const char *name, bool setactive);
-struct bGPdata *gpencil_data_addnew(const char name[]);
+struct bGPDframe *BKE_gpencil_frame_addnew(struct bGPDlayer *gpl, int cframe);
+struct bGPDframe *BKE_gpencil_frame_addcopy(struct bGPDlayer *gpl, int cframe);
+struct bGPDlayer *BKE_gpencil_layer_addnew(struct bGPdata *gpd, const char *name, bool setactive);
+struct bGPdata *BKE_gpencil_data_addnew(const char name[]);
-struct bGPDframe *gpencil_frame_duplicate(struct bGPDframe *src);
-struct bGPDlayer *gpencil_layer_duplicate(struct bGPDlayer *src);
-struct bGPdata *gpencil_data_duplicate(struct bGPdata *gpd, bool internal_copy);
+struct bGPDframe *BKE_gpencil_frame_duplicate(const struct bGPDframe *gpf_src);
+struct bGPDlayer *BKE_gpencil_layer_duplicate(const struct bGPDlayer *gpl_src);
+struct bGPdata *BKE_gpencil_data_duplicate(struct Main *bmain, struct bGPdata *gpd, bool internal_copy);
-void gpencil_frame_delete_laststroke(struct bGPDlayer *gpl, struct bGPDframe *gpf);
+void BKE_gpencil_make_local(struct Main *bmain, struct bGPdata *gpd, const bool lib_local);
+
+void BKE_gpencil_frame_delete_laststroke(struct bGPDlayer *gpl, struct bGPDframe *gpf);
+
+struct bGPDpalette *BKE_gpencil_palette_addnew(struct bGPdata *gpd, const char *name, bool setactive);
+struct bGPDpalette *BKE_gpencil_palette_duplicate(const struct bGPDpalette *palette_src);
+struct bGPDpalettecolor *BKE_gpencil_palettecolor_addnew(struct bGPDpalette *palette, const char *name, bool setactive);
+
+struct bGPDbrush *BKE_gpencil_brush_addnew(struct ToolSettings *ts, const char *name, bool setactive);
+struct bGPDbrush *BKE_gpencil_brush_duplicate(const struct bGPDbrush *brush_src);
+void BKE_gpencil_brush_init_presets(struct ToolSettings *ts);
/* Stroke and Fill - Alpha Visibility Threshold */
#define GPENCIL_ALPHA_OPACITY_THRESH 0.001f
+#define GPENCIL_STRENGTH_MIN 0.003f
bool gpencil_layer_is_editable(const struct bGPDlayer *gpl);
@@ -76,12 +94,28 @@ typedef enum eGP_GetFrame_Mode {
GP_GETFRAME_ADD_COPY = 2
} eGP_GetFrame_Mode;
-struct bGPDframe *gpencil_layer_getframe(struct bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew);
+struct bGPDframe *BKE_gpencil_layer_getframe(struct bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew);
struct bGPDframe *BKE_gpencil_layer_find_frame(struct bGPDlayer *gpl, int cframe);
-bool gpencil_layer_delframe(struct bGPDlayer *gpl, struct bGPDframe *gpf);
-
-struct bGPDlayer *gpencil_layer_getactive(struct bGPdata *gpd);
-void gpencil_layer_setactive(struct bGPdata *gpd, struct bGPDlayer *active);
-void gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl);
+bool BKE_gpencil_layer_delframe(struct bGPDlayer *gpl, struct bGPDframe *gpf);
+
+struct bGPDlayer *BKE_gpencil_layer_getactive(struct bGPdata *gpd);
+void BKE_gpencil_layer_setactive(struct bGPdata *gpd, struct bGPDlayer *active);
+void BKE_gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl);
+
+struct bGPDbrush *BKE_gpencil_brush_getactive(struct ToolSettings *ts);
+void BKE_gpencil_brush_setactive(struct ToolSettings *ts, struct bGPDbrush *active);
+void BKE_gpencil_brush_delete(struct ToolSettings *ts, struct bGPDbrush *palette);
+
+struct bGPDpalette *BKE_gpencil_palette_getactive(struct bGPdata *gpd);
+void BKE_gpencil_palette_setactive(struct bGPdata *gpd, struct bGPDpalette *active);
+void BKE_gpencil_palette_delete(struct bGPdata *gpd, struct bGPDpalette *palette);
+void BKE_gpencil_palette_change_strokes(struct bGPdata *gpd);
+
+struct bGPDpalettecolor *BKE_gpencil_palettecolor_getactive(struct bGPDpalette *palette);
+void BKE_gpencil_palettecolor_setactive(struct bGPDpalette *palette, struct bGPDpalettecolor *active);
+void BKE_gpencil_palettecolor_delete(struct bGPDpalette *palette, struct bGPDpalettecolor *palcolor);
+struct bGPDpalettecolor *BKE_gpencil_palettecolor_getbyname(struct bGPDpalette *palette, char *name);
+void BKE_gpencil_palettecolor_changename(struct bGPdata *gpd, char *oldname, const char *newname);
+void BKE_gpencil_palettecolor_delete_strokes(struct bGPdata *gpd, char *name);
#endif /* __BKE_GPENCIL_H__ */
diff --git a/source/blender/blenkernel/BKE_group.h b/source/blender/blenkernel/BKE_group.h
index 9056e48cf50..09a069ee36f 100644
--- a/source/blender/blenkernel/BKE_group.h
+++ b/source/blender/blenkernel/BKE_group.h
@@ -41,9 +41,9 @@ struct Object;
struct Scene;
void BKE_group_free(struct Group *group);
-void BKE_group_unlink(struct Main *bmain, struct Group *group);
struct Group *BKE_group_add(struct Main *bmain, const char *name);
-struct Group *BKE_group_copy(struct Group *group);
+struct Group *BKE_group_copy(struct Main *bmain, struct Group *group);
+void BKE_group_make_local(struct Main *bmain, struct Group *group, const bool lib_local);
bool BKE_group_object_add(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base);
bool BKE_group_object_unlink(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base);
struct Group *BKE_group_object_find(struct Group *group, struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h
index 763a3874d4e..6944c5ccd28 100644
--- a/source/blender/blenkernel/BKE_icons.h
+++ b/source/blender/blenkernel/BKE_icons.h
@@ -55,7 +55,7 @@ void BKE_icons_init(int first_dyn_id);
/* return icon id for library object or create new icon if not found */
int BKE_icon_id_ensure(struct ID *id);
-int BKE_icon_preview_ensure(struct PreviewImage *preview);
+int BKE_icon_preview_ensure(struct ID *id, struct PreviewImage *preview);
/* retrieve icon for id */
struct Icon *BKE_icon_get(int icon_id);
@@ -99,6 +99,8 @@ struct PreviewImage *BKE_previewimg_create(void);
/* create a copy of the preview image */
struct PreviewImage *BKE_previewimg_copy(struct PreviewImage *prv);
+void BKE_previewimg_id_copy(struct ID *new_id, struct ID *old_id);
+
/* retrieve existing or create new preview image */
struct PreviewImage *BKE_previewimg_id_ensure(struct ID *id);
@@ -112,6 +114,7 @@ struct PreviewImage *BKE_previewimg_cached_thumbnail_read(
const char *name, const char *path, const int source, bool force_update);
void BKE_previewimg_cached_release(const char *name);
+void BKE_previewimg_cached_release_pointer(struct PreviewImage *prv);
#define ICON_RENDER_DEFAULT_HEIGHT 32
diff --git a/source/blender/blenkernel/BKE_idcode.h b/source/blender/blenkernel/BKE_idcode.h
index 6de0efe2709..964a49435f1 100644
--- a/source/blender/blenkernel/BKE_idcode.h
+++ b/source/blender/blenkernel/BKE_idcode.h
@@ -42,6 +42,8 @@ bool BKE_idcode_is_valid(short idcode);
int BKE_idcode_to_idfilter(const short idcode);
short BKE_idcode_from_idfilter(const int idfilter);
+int BKE_idcode_to_index(const short idcode);
+
/**
* Return an ID code and steps the index forward 1.
*
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index eb98268c9f0..132c73209d1 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -108,7 +108,7 @@ struct anim *openanim_noload(const char *name, int flags, int streamindex, char
void BKE_image_de_interlace(struct Image *ima, int odd);
-void BKE_image_make_local(struct Image *ima);
+void BKE_image_make_local(struct Main *bmain, struct Image *ima, const bool lib_local);
void BKE_image_tag_time(struct Image *ima);
diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h
index 1edbb455ca4..e590ff148d7 100644
--- a/source/blender/blenkernel/BKE_key.h
+++ b/source/blender/blenkernel/BKE_key.h
@@ -39,6 +39,7 @@ struct ListBase;
struct Curve;
struct Object;
struct Lattice;
+struct Main;
struct Mesh;
struct WeightsArrayCache;
@@ -50,9 +51,8 @@ extern "C" {
void BKE_key_free(struct Key *sc);
void BKE_key_free_nolib(struct Key *key);
struct Key *BKE_key_add(struct ID *id);
-struct Key *BKE_key_copy(struct Key *key);
+struct Key *BKE_key_copy(struct Main *bmain, struct Key *key);
struct Key *BKE_key_copy_nolib(struct Key *key);
-void BKE_key_make_local(struct Key *key);
void BKE_key_sort(struct Key *key);
void key_curve_position_weights(float t, float data[4], int type);
diff --git a/source/blender/blenkernel/BKE_lamp.h b/source/blender/blenkernel/BKE_lamp.h
index d830c19651f..4d53850c572 100644
--- a/source/blender/blenkernel/BKE_lamp.h
+++ b/source/blender/blenkernel/BKE_lamp.h
@@ -44,9 +44,9 @@ struct Scene;
void BKE_lamp_init(struct Lamp *la);
struct Lamp *BKE_lamp_add(struct Main *bmain, const char *name) ATTR_WARN_UNUSED_RESULT;
-struct Lamp *BKE_lamp_copy(struct Lamp *la) ATTR_WARN_UNUSED_RESULT;
+struct Lamp *BKE_lamp_copy(struct Main *bmain, struct Lamp *la) ATTR_WARN_UNUSED_RESULT;
struct Lamp *localize_lamp(struct Lamp *la) ATTR_WARN_UNUSED_RESULT;
-void BKE_lamp_make_local(struct Lamp *la);
+void BKE_lamp_make_local(struct Main *bmain, struct Lamp *la, const bool lib_local);
void BKE_lamp_free(struct Lamp *la);
void lamp_drivers_update(struct Scene *scene, struct Lamp *la, float ctime);
diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h
index 828a40de1c9..226c82da295 100644
--- a/source/blender/blenkernel/BKE_lattice.h
+++ b/source/blender/blenkernel/BKE_lattice.h
@@ -47,9 +47,9 @@ struct MDeformVert;
void BKE_lattice_resize(struct Lattice *lt, int u, int v, int w, struct Object *ltOb);
void BKE_lattice_init(struct Lattice *lt);
struct Lattice *BKE_lattice_add(struct Main *bmain, const char *name);
-struct Lattice *BKE_lattice_copy(struct Lattice *lt);
+struct Lattice *BKE_lattice_copy(struct Main *bmain, struct Lattice *lt);
void BKE_lattice_free(struct Lattice *lt);
-void BKE_lattice_make_local(struct Lattice *lt);
+void BKE_lattice_make_local(struct Main *bmain, struct Lattice *lt, const bool lib_local);
void calc_lat_fudu(int flag, int res, float *r_fu, float *r_du);
struct LatticeDeformData;
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index 21585a160dd..0d82de09165 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -52,21 +52,22 @@ struct PropertyRNA;
void *BKE_libblock_alloc_notest(short type);
void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void BKE_libblock_init_empty(struct ID *id);
-void *BKE_libblock_copy_ex(struct Main *bmain, struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+void *BKE_libblock_copy(struct Main *bmain, struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void *BKE_libblock_copy_nolib(struct ID *id, const bool do_action) ATTR_NONNULL();
-void *BKE_libblock_copy(struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void BKE_libblock_copy_data(struct ID *id, const struct ID *id_from, const bool do_action);
void BKE_libblock_relink(struct ID *id);
void BKE_libblock_rename(struct Main *bmain, struct ID *id, const char *name) ATTR_NONNULL();
void BLI_libblock_ensure_unique_name(struct Main *bmain, const char *name) ATTR_NONNULL();
+struct ID *BKE_libblock_find_name_ex(struct Main *bmain, const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+struct ID *BKE_libblock_find_name(const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+
+/* library_remap.c (keep here since they're general functions) */
void BKE_libblock_free(struct Main *bmain, void *idv) ATTR_NONNULL();
-void BKE_libblock_free_ex(struct Main *bmain, void *idv, bool do_id_user) ATTR_NONNULL();
+void BKE_libblock_free_ex(struct Main *bmain, void *idv, const bool do_id_user) ATTR_NONNULL();
void BKE_libblock_free_us(struct Main *bmain, void *idv) ATTR_NONNULL();
void BKE_libblock_free_data(struct Main *bmain, struct ID *id) ATTR_NONNULL();
-
-struct ID *BKE_libblock_find_name_ex(struct Main *bmain, const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-struct ID *BKE_libblock_find_name(const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+void BKE_libblock_delete(struct Main *bmain, void *idv) ATTR_NONNULL();
void BKE_id_lib_local_paths(struct Main *bmain, struct Library *lib, struct ID *id);
void id_lib_extern(struct ID *id);
@@ -79,19 +80,21 @@ void id_us_min(struct ID *id);
void id_fake_user_set(struct ID *id);
void id_fake_user_clear(struct ID *id);
-bool id_make_local(struct ID *id, bool test);
+void BKE_id_make_local_generic(struct Main *bmain, struct ID *id, const bool id_in_mainlist, const bool lib_local);
+bool id_make_local(struct Main *bmain, struct ID *id, const bool test, const bool force_local);
bool id_single_user(struct bContext *C, struct ID *id, struct PointerRNA *ptr, struct PropertyRNA *prop);
-bool id_copy(struct ID *id, struct ID **newid, bool test);
-bool id_unlink(struct ID *id, int test);
+bool id_copy(struct Main *bmain, struct ID *id, struct ID **newid, bool test);
void id_sort_by_name(struct ListBase *lb, struct ID *id);
+void BKE_id_expand_local(struct ID *id);
+void BKE_id_copy_ensure_local(struct Main *bmain, struct ID *old_id, struct ID *new_id);
bool new_id(struct ListBase *lb, struct ID *id, const char *name);
void id_clear_lib_data(struct Main *bmain, struct ID *id);
-void id_clear_lib_data_ex(struct Main *bmain, struct ID *id, bool id_in_mainlist);
+void id_clear_lib_data_ex(struct Main *bmain, struct ID *id, const bool id_in_mainlist);
struct ListBase *which_libbase(struct Main *mainlib, short type);
-#define MAX_LIBARRAY 34
+#define MAX_LIBARRAY 35
int set_listbasepointers(struct Main *main, struct ListBase *lb[MAX_LIBARRAY]);
/* Main API */
@@ -119,15 +122,11 @@ void BKE_main_lib_objects_recalc_all(struct Main *bmain);
/* (MAX_ID_NAME - 2) + 3 */
void BKE_id_ui_prefix(char name[66 + 1], const struct ID *id);
-void BKE_library_make_local(struct Main *bmain, struct Library *lib, bool untagged_only, bool set_fake);
+void BKE_library_free(struct Library *lib);
-typedef void (*BKE_library_free_window_manager_cb)(struct bContext *, struct wmWindowManager *);
-typedef void (*BKE_library_free_notifier_reference_cb)(const void *);
-typedef void (*BKE_library_free_editor_id_reference_cb)(const struct ID *);
+void BKE_library_make_local(
+ struct Main *bmain, const struct Library *lib, const bool untagged_only, const bool set_fake);
-void BKE_library_callback_free_window_manager_set(BKE_library_free_window_manager_cb func);
-void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func);
-void BKE_library_callback_free_editor_id_reference_set(BKE_library_free_editor_id_reference_cb func);
/* use when "" is given to new_id() */
#define ID_FALLBACK_NAME N_("Untitled")
diff --git a/source/blender/blenkernel/BKE_library_idmap.h b/source/blender/blenkernel/BKE_library_idmap.h
new file mode 100644
index 00000000000..971586ea8b7
--- /dev/null
+++ b/source/blender/blenkernel/BKE_library_idmap.h
@@ -0,0 +1,50 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_LIBRARY_IDMAP_H__
+#define __BKE_LIBRARY_IDMAP_H__
+
+/** \file BKE_library_idmap.h
+ * \ingroup bke
+ */
+
+#include "BLI_compiler_attrs.h"
+
+struct ID;
+struct Main;
+struct IDNameLib_Map;
+
+struct IDNameLib_Map *BKE_main_idmap_create(
+ struct Main *bmain)
+ ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+void BKE_main_idmap_destroy(
+ struct IDNameLib_Map *id_typemap)
+ ATTR_NONNULL();
+struct Main *BKE_main_idmap_main_get(
+ struct IDNameLib_Map *id_typemap)
+ ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+struct ID *BKE_main_idmap_lookup(
+ struct IDNameLib_Map *id_typemap,
+ short id_type, const char *name, const struct Library *lib)
+ ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 3);
+struct ID *BKE_main_idmap_lookup_id(
+ struct IDNameLib_Map *id_typemap, const struct ID *id)
+ ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
+
+#endif /* __BKE_LIBRARY_IDMAP_H__ */
diff --git a/source/blender/blenkernel/BKE_library_query.h b/source/blender/blenkernel/BKE_library_query.h
index 2e73be576f9..c6b63754b57 100644
--- a/source/blender/blenkernel/BKE_library_query.h
+++ b/source/blender/blenkernel/BKE_library_query.h
@@ -32,6 +32,7 @@
*/
struct ID;
+struct Main;
/* Tips for the callback for cases it's gonna to modify the pointer. */
enum {
@@ -40,6 +41,12 @@ enum {
IDWALK_NEVER_SELF = (1 << 1),
/**
+ * Indicates whether this is direct (i.e. by local data) or indirect (i.e. by linked data) usage.
+ * \note Object proxies are half-local, half-linked...
+ */
+ IDWALK_INDIRECT_USAGE = (1 << 2),
+
+ /**
* Adjusts #ID.us reference-count.
* \note keep in sync with 'newlibadr_us' use in readfile.c
*/
@@ -52,7 +59,7 @@ enum {
enum {
IDWALK_RET_NOP = 0,
- IDWALK_RET_STOP_ITER = 1 << 0, /* Completly top iteration. */
+ IDWALK_RET_STOP_ITER = 1 << 0, /* Completly stop iteration. */
IDWALK_RET_STOP_RECURSION = 1 << 1, /* Stop recursion, that is, do not loop over ID used by current one. */
};
@@ -75,4 +82,12 @@ void BKE_library_update_ID_link_user(struct ID *id_dst, struct ID *id_src, const
int BKE_library_ID_use_ID(struct ID *id_user, struct ID *id_used);
+bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id_type_used);
+
+bool BKE_library_ID_is_locally_used(struct Main *bmain, void *idv);
+bool BKE_library_ID_is_indirectly_used(struct Main *bmain, void *idv);
+void BKE_library_ID_test_usages(struct Main *bmain, void *idv, bool *is_used_local, bool *is_used_linked);
+
+void BKE_library_tag_unused_linked_data(struct Main *bmain, const bool do_init_tag);
+
#endif /* __BKE_LIBRARY_QUERY_H__ */
diff --git a/source/blender/blenkernel/BKE_library_remap.h b/source/blender/blenkernel/BKE_library_remap.h
new file mode 100644
index 00000000000..89b087014b2
--- /dev/null
+++ b/source/blender/blenkernel/BKE_library_remap.h
@@ -0,0 +1,80 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_LIBRARY_REMAP_H__
+#define __BKE_LIBRARY_REMAP_H__
+
+/** \file BKE_library_remap.h
+ * \ingroup bke
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "BLI_compiler_attrs.h"
+
+/* BKE_libblock_free, delete are declared in BKE_library.h for convenience. */
+
+/* Also IDRemap->flag. */
+enum {
+ /* Do not remap indirect usages of IDs (that is, when user is some linked data). */
+ ID_REMAP_SKIP_INDIRECT_USAGE = 1 << 0,
+ /* This flag should always be set, *except for 'unlink' scenarios* (only relevant when new_id == NULL).
+ * Basically, when unset, NEVER_NULL ID usages will keep pointing to old_id, but (if needed) old_id user count
+ * will still be decremented. This is mandatory for 'delete ID' case, but in all other situation this would lead
+ * to invalid user counts! */
+ ID_REMAP_SKIP_NEVER_NULL_USAGE = 1 << 1,
+ /* This tells the callback func to flag with LIB_DOIT all IDs using target one with a 'never NULL' pointer
+ * (like e.g. Object->data). */
+ ID_REMAP_FLAG_NEVER_NULL_USAGE = 1 << 2,
+ /* This tells the callback func to force setting IDs using target one with a 'never NULL' pointer to NULL.
+ * WARNING! Use with extreme care, this will leave database in broken state and can cause crashes very easily! */
+ ID_REMAP_FORCE_NEVER_NULL_USAGE = 1 << 3,
+};
+
+/* Note: Requiring new_id to be non-null, this *may* not be the case ultimately, but makes things simpler for now. */
+void BKE_libblock_remap_locked(
+ struct Main *bmain, void *old_idv, void *new_idv,
+ const short remap_flags) ATTR_NONNULL(1, 2);
+void BKE_libblock_remap(
+ struct Main *bmain, void *old_idv, void *new_idv,
+ const short remap_flags) ATTR_NONNULL(1, 2);
+
+void BKE_libblock_unlink(
+ struct Main *bmain, void *idv,
+ const bool do_flag_never_null, const bool do_skip_indirect) ATTR_NONNULL();
+
+void BKE_libblock_relink_ex(
+ struct Main *bmain, void *idv, void *old_idv, void *new_idv,
+ const bool us_min_never_null) ATTR_NONNULL(1, 2);
+
+
+typedef void (*BKE_library_free_window_manager_cb)(struct bContext *, struct wmWindowManager *);
+typedef void (*BKE_library_free_notifier_reference_cb)(const void *);
+typedef void (*BKE_library_remap_editor_id_reference_cb)(struct ID *, struct ID *);
+
+void BKE_library_callback_free_window_manager_set(BKE_library_free_window_manager_cb func);
+void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func);
+void BKE_library_callback_remap_editor_id_reference_set(BKE_library_remap_editor_id_reference_cb func);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BKE_LIBRARY_REMAP_H__ */
diff --git a/source/blender/blenkernel/BKE_linestyle.h b/source/blender/blenkernel/BKE_linestyle.h
index e3eead4102c..af9bf58ce77 100644
--- a/source/blender/blenkernel/BKE_linestyle.h
+++ b/source/blender/blenkernel/BKE_linestyle.h
@@ -54,6 +54,8 @@ FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name);
void BKE_linestyle_free(FreestyleLineStyle *linestyle);
FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, FreestyleLineStyle *linestyle);
+void BKE_linestyle_make_local(struct Main *bmain, struct FreestyleLineStyle *linestyle, const bool lib_local);
+
FreestyleLineStyle *BKE_linestyle_active_from_scene(struct Scene *scene);
LineStyleModifier *BKE_linestyle_color_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type);
@@ -71,16 +73,14 @@ int BKE_linestyle_alpha_modifier_remove(FreestyleLineStyle *linestyle, LineStyle
int BKE_linestyle_thickness_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *modifier);
int BKE_linestyle_geometry_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *modifier);
-void BKE_linestyle_color_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction);
-void BKE_linestyle_alpha_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction);
-void BKE_linestyle_thickness_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction);
-void BKE_linestyle_geometry_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction);
+bool BKE_linestyle_color_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction);
+bool BKE_linestyle_alpha_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction);
+bool BKE_linestyle_thickness_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction);
+bool BKE_linestyle_geometry_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction);
void BKE_linestyle_modifier_list_color_ramps(FreestyleLineStyle *linestyle, ListBase *listbase);
char *BKE_linestyle_path_to_color_ramp(FreestyleLineStyle *linestyle, struct ColorBand *color_ramp);
-void BKE_linestyle_target_object_unlink(FreestyleLineStyle *linestyle, struct Object *ob);
-
bool BKE_linestyle_use_textures(FreestyleLineStyle *linestyle, const bool use_shading_nodes);
void BKE_linestyle_default_shader(const struct bContext *C, FreestyleLineStyle *linestyle);
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index 44e4da4e0a3..a4f5c425282 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -42,6 +42,8 @@
*/
#include "DNA_listBase.h"
+#include "BKE_library.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -102,8 +104,9 @@ typedef struct Main {
ListBase movieclip;
ListBase mask;
ListBase linestyle;
+ ListBase cachefiles;
- char id_tag_update[256];
+ char id_tag_update[MAX_LIBARRAY];
/* Evaluation context used by viewport */
struct EvaluationContext *eval_ctx;
diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h
index 25893d54dca..3349bffac85 100644
--- a/source/blender/blenkernel/BKE_mask.h
+++ b/source/blender/blenkernel/BKE_mask.h
@@ -123,10 +123,11 @@ void BKE_mask_point_select_set_handle(struct MaskSplinePoint *point, const eMask
/* general */
struct Mask *BKE_mask_new(struct Main *bmain, const char *name);
struct Mask *BKE_mask_copy_nolib(struct Mask *mask);
-struct Mask *BKE_mask_copy(struct Mask *mask);
+struct Mask *BKE_mask_copy(struct Main *bmain, struct Mask *mask);
-void BKE_mask_free_nolib(struct Mask *mask);
-void BKE_mask_free(struct Main *bmain, struct Mask *mask);
+void BKE_mask_make_local(struct Main *bmain, struct Mask *mask, const bool lib_local);
+
+void BKE_mask_free(struct Mask *mask);
void BKE_mask_coord_from_frame(float r_co[2], const float co[2], const float frame_size[2]);
void BKE_mask_coord_from_movieclip(struct MovieClip *clip, struct MovieClipUser *user, float r_co[2], const float co[2]);
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h
index 852564c8d90..8ae5c2b3c45 100644
--- a/source/blender/blenkernel/BKE_material.h
+++ b/source/blender/blenkernel/BKE_material.h
@@ -47,17 +47,17 @@ struct Scene;
void init_def_material(void);
void BKE_material_free(struct Material *ma);
void BKE_material_free_ex(struct Material *ma, bool do_id_user);
-void test_object_materials(struct Main *bmain, struct ID *id);
-void BKE_material_resize_object(struct Object *ob, const short totcol, bool do_id_user);
+void test_object_materials(struct Object *ob, struct ID *id);
+void test_all_objects_materials(struct Main *bmain, struct ID *id);
+void BKE_material_resize_object(struct Main *bmain, struct Object *ob, const short totcol, bool do_id_user);
void BKE_material_init(struct Material *ma);
void BKE_material_remap_object(struct Object *ob, const unsigned int *remap);
void BKE_material_remap_object_calc(struct Object *ob_dst, struct Object *ob_src, short *remap_src_to_dst);
struct Material *BKE_material_add(struct Main *bmain, const char *name);
-struct Material *BKE_material_copy(struct Material *ma);
+struct Material *BKE_material_copy(struct Main *bmain, struct Material *ma);
struct Material *localize_material(struct Material *ma);
struct Material *give_node_material(struct Material *ma); /* returns node material or self */
-void BKE_material_make_local(struct Material *ma);
-void extern_local_matarar(struct Material **matar, short totcol);
+void BKE_material_make_local(struct Main *bmain, struct Material *ma, const bool lib_local);
/* UNUSED */
// void automatname(struct Material *);
@@ -78,24 +78,22 @@ enum {
};
struct Material *give_current_material(struct Object *ob, short act);
-struct ID *material_from(struct Object *ob, short act);
void assign_material_id(struct ID *id, struct Material *ma, short act);
void assign_material(struct Object *ob, struct Material *ma, short act, int assign_type);
void assign_matarar(struct Object *ob, struct Material ***matar, short totcol);
-short find_material_index(struct Object *ob, struct Material *ma);
-
-bool object_add_material_slot(struct Object *ob);
-bool object_remove_material_slot(struct Object *ob);
+short BKE_object_material_slot_find_index(struct Object *ob, struct Material *ma);
+bool BKE_object_material_slot_add(struct Object *ob);
+bool BKE_object_material_slot_remove(struct Object *ob);
void BKE_texpaint_slot_refresh_cache(struct Scene *scene, struct Material *ma);
void BKE_texpaint_slots_refresh_object(struct Scene *scene, struct Object *ob);
/* rna api */
-void BKE_material_resize_id(struct ID *id, short totcol, bool do_id_user);
-void BKE_material_append_id(struct ID *id, struct Material *ma);
-struct Material *BKE_material_pop_id(struct ID *id, int index, bool update_data); /* index is an int because of RNA */
-void BKE_material_clear_id(struct ID *id, bool update_data);
+void BKE_material_resize_id(struct Main *bmain, struct ID *id, short totcol, bool do_id_user);
+void BKE_material_append_id(struct Main *bmain, struct ID *id, struct Material *ma);
+struct Material *BKE_material_pop_id(struct Main *bmain, struct ID *id, int index, bool update_data); /* index is an int because of RNA */
+void BKE_material_clear_id(struct Main *bmain, struct ID *id, bool update_data);
/* rendering */
void init_render_material(struct Material *, int, float *);
diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h
index 0574b88bef3..64320a20281 100644
--- a/source/blender/blenkernel/BKE_mball.h
+++ b/source/blender/blenkernel/BKE_mball.h
@@ -38,13 +38,12 @@ struct Object;
struct Scene;
struct MetaElem;
-void BKE_mball_unlink(struct MetaBall *mb);
void BKE_mball_free(struct MetaBall *mb);
void BKE_mball_init(struct MetaBall *mb);
struct MetaBall *BKE_mball_add(struct Main *bmain, const char *name);
-struct MetaBall *BKE_mball_copy(struct MetaBall *mb);
+struct MetaBall *BKE_mball_copy(struct Main *bmain, struct MetaBall *mb);
-void BKE_mball_make_local(struct MetaBall *mb);
+void BKE_mball_make_local(struct Main *bmain, struct MetaBall *mb, const bool lib_local);
bool BKE_mball_is_basis_for(struct Object *ob1, struct Object *ob2);
bool BKE_mball_is_basis(struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index c7d5857b873..d41878825bb 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -32,6 +32,7 @@
*/
struct ID;
+struct BMeshCreateParams;
struct BoundBox;
struct EdgeHash;
struct ListBase;
@@ -69,7 +70,9 @@ extern "C" {
/* *** mesh.c *** */
-struct BMesh *BKE_mesh_to_bmesh(struct Mesh *me, struct Object *ob, const bool add_key_index);
+struct BMesh *BKE_mesh_to_bmesh(
+ struct Mesh *me, struct Object *ob,
+ const bool add_key_index, const struct BMeshCreateParams *params);
int poly_find_loop_from_vert(
const struct MPoly *poly,
@@ -81,16 +84,14 @@ int poly_get_adj_loops_from_vert(
int BKE_mesh_edge_other_vert(const struct MEdge *e, int v);
-void BKE_mesh_unlink(struct Mesh *me);
-void BKE_mesh_free(struct Mesh *me, int unlink);
+void BKE_mesh_free(struct Mesh *me);
void BKE_mesh_init(struct Mesh *me);
struct Mesh *BKE_mesh_add(struct Main *bmain, const char *name);
-struct Mesh *BKE_mesh_copy_ex(struct Main *bmain, struct Mesh *me);
-struct Mesh *BKE_mesh_copy(struct Mesh *me);
+struct Mesh *BKE_mesh_copy(struct Main *bmain, struct Mesh *me);
void BKE_mesh_update_customdata_pointers(struct Mesh *me, const bool do_ensure_tess_cd);
void BKE_mesh_ensure_skin_customdata(struct Mesh *me);
-void BKE_mesh_make_local(struct Mesh *me);
+void BKE_mesh_make_local(struct Main *bmain, struct Mesh *me, const bool lib_local);
void BKE_mesh_boundbox_calc(struct Mesh *me, float r_loc[3], float r_size[3]);
void BKE_mesh_texspace_calc(struct Mesh *me);
float (*BKE_mesh_orco_verts_get(struct Object *ob))[3];
@@ -323,7 +324,7 @@ void BKE_mesh_mdisp_flip(struct MDisps *md, const bool use_loop_mdisp_flip);
void BKE_mesh_polygon_flip_ex(
struct MPoly *mpoly, struct MLoop *mloop, struct CustomData *ldata,
- struct MDisps *mdisp, const bool use_loop_mdisp_flip);
+ float (*lnors)[3], struct MDisps *mdisp, const bool use_loop_mdisp_flip);
void BKE_mesh_polygon_flip(struct MPoly *mpoly, struct MLoop *mloop, struct CustomData *ldata);
void BKE_mesh_polygons_flip(struct MPoly *mpoly, struct MLoop *mloop, struct CustomData *ldata, int totpoly);
diff --git a/source/blender/blenkernel/BKE_mesh_mapping.h b/source/blender/blenkernel/BKE_mesh_mapping.h
index d7dd9ed3ac5..b5b5443574c 100644
--- a/source/blender/blenkernel/BKE_mesh_mapping.h
+++ b/source/blender/blenkernel/BKE_mesh_mapping.h
@@ -114,12 +114,22 @@ void BKE_mesh_vert_loop_map_create(
MeshElemMap **r_map, int **r_mem,
const struct MPoly *mface, const struct MLoop *mloop,
int totvert, int totface, int totloop);
+void BKE_mesh_vert_looptri_map_create(
+ MeshElemMap **r_map, int **r_mem,
+ const struct MVert *mvert, const int totvert,
+ const struct MLoopTri *mlooptri, const int totlooptri,
+ const struct MLoop *mloop, const int totloop);
void BKE_mesh_vert_edge_map_create(
MeshElemMap **r_map, int **r_mem,
const struct MEdge *medge, int totvert, int totedge);
void BKE_mesh_vert_edge_vert_map_create(
MeshElemMap **r_map, int **r_mem,
const struct MEdge *medge, int totvert, int totedge);
+void BKE_mesh_edge_loop_map_create(
+ MeshElemMap **r_map, int **r_mem,
+ const struct MEdge *medge, const int totedge,
+ const struct MPoly *mpoly, const int totpoly,
+ const struct MLoop *mloop, const int totloop);
void BKE_mesh_edge_poly_map_create(
MeshElemMap **r_map, int **r_mem,
const struct MEdge *medge, const int totedge,
@@ -181,11 +191,19 @@ typedef bool (*MeshRemapIslandsCalc)(
/* Above vert/UV mapping stuff does not do what we need here, but does things we do not need here.
* So better keep them separated for now, I think.
*/
-bool BKE_mesh_calc_islands_loop_poly_uv(
+bool BKE_mesh_calc_islands_loop_poly_edgeseam(
+ struct MVert *verts, const int totvert,
+ struct MEdge *edges, const int totedge,
+ struct MPoly *polys, const int totpoly,
+ struct MLoop *loops, const int totloop,
+ MeshIslandStore *r_island_store);
+
+bool BKE_mesh_calc_islands_loop_poly_uvmap(
struct MVert *verts, const int totvert,
struct MEdge *edges, const int totedge,
struct MPoly *polys, const int totpoly,
struct MLoop *loops, const int totloop,
+ const struct MLoopUV *luvs,
MeshIslandStore *r_island_store);
int *BKE_mesh_calc_smoothgroups(
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index 455912ab819..f6c08909d23 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -101,7 +101,8 @@ typedef enum {
eModifierTypeFlag_NoUserAdd = (1 << 8),
/* For modifiers that use CD_PREVIEW_MCOL for preview. */
- eModifierTypeFlag_UsesPreview = (1 << 9)
+ eModifierTypeFlag_UsesPreview = (1 << 9),
+ eModifierTypeFlag_AcceptsLattice = (1 << 10),
} ModifierTypeFlag;
/* IMPORTANT! Keep ObjectWalkFunc and IDWalkFunc signatures compatible. */
diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h
index afca326c727..3237c146bc5 100644
--- a/source/blender/blenkernel/BKE_movieclip.h
+++ b/source/blender/blenkernel/BKE_movieclip.h
@@ -40,7 +40,9 @@ struct MovieClipUser;
struct MovieDistortion;
void BKE_movieclip_free(struct MovieClip *clip);
-void BKE_movieclip_unlink(struct Main *bmain, struct MovieClip *clip);
+
+struct MovieClip *BKE_movieclip_copy(struct Main *bmain, struct MovieClip *clip);
+void BKE_movieclip_make_local(struct Main *bmain, struct MovieClip *clip, const bool lib_local);
struct MovieClip *BKE_movieclip_file_add(struct Main *bmain, const char *name);
struct MovieClip *BKE_movieclip_file_add_exists_ex(struct Main *bmain, const char *name, bool *r_exists);
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 01a5da16dd4..82912cbd946 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -334,10 +334,9 @@ void ntreeInitDefault(struct bNodeTree *ntree);
struct bNodeTree *ntreeAddTree(struct Main *bmain, const char *name, const char *idname);
/* copy/free funcs, need to manage ID users */
-void ntreeFreeTree_ex(struct bNodeTree *ntree, const bool do_id_user);
void ntreeFreeTree(struct bNodeTree *ntree);
struct bNodeTree *ntreeCopyTree_ex(struct bNodeTree *ntree, struct Main *bmain, const bool do_id_user);
-struct bNodeTree *ntreeCopyTree(struct bNodeTree *ntree);
+struct bNodeTree *ntreeCopyTree(struct Main *bmain, struct bNodeTree *ntree);
void ntreeSwitchID_ex(struct bNodeTree *ntree, struct ID *sce_from, struct ID *sce_to, const bool do_id_user);
void ntreeSwitchID(struct bNodeTree *ntree, struct ID *sce_from, struct ID *sce_to);
/* node->id user count */
@@ -347,7 +346,8 @@ void ntreeUserDecrefID(struct bNodeTree *ntree);
struct bNodeTree *ntreeFromID(struct ID *id);
-void ntreeMakeLocal(struct bNodeTree *ntree, bool id_in_mainlist);
+void ntreeMakeLocal(struct Main *bmain, struct bNodeTree *ntree, bool id_in_mainlist, const bool lib_local);
+struct bNode *ntreeFindType(const struct bNodeTree *ntree, int type);
bool ntreeHasType(const struct bNodeTree *ntree, int type);
bool ntreeHasTree(const struct bNodeTree *ntree, const struct bNodeTree *lookup);
void ntreeUpdateTree(struct Main *main, struct bNodeTree *ntree);
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 7d6096407ff..cf07a178fe8 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -65,7 +65,6 @@ void BKE_object_free_curve_cache(struct Object *ob);
void BKE_object_update_base_layer(struct Scene *scene, struct Object *ob);
void BKE_object_free(struct Object *ob);
-void BKE_object_free_ex(struct Object *ob, bool do_id_user);
void BKE_object_free_derived_caches(struct Object *ob);
void BKE_object_free_caches(struct Object *object);
@@ -79,7 +78,6 @@ void BKE_object_free_modifiers(struct Object *ob);
void BKE_object_make_proxy(struct Object *ob, struct Object *target, struct Object *gob);
void BKE_object_copy_proxy_drivers(struct Object *ob, struct Object *target);
-void BKE_object_unlink(struct Main *bmain, struct Object *ob);
bool BKE_object_exists_check(struct Object *obtest);
bool BKE_object_is_in_editmode(struct Object *ob);
bool BKE_object_is_in_editmode_vgroup(struct Object *ob);
@@ -108,8 +106,9 @@ struct Object *BKE_object_lod_meshob_get(struct Object *ob, struct Scene *scene)
struct Object *BKE_object_lod_matob_get(struct Object *ob, struct Scene *scene);
struct Object *BKE_object_copy_ex(struct Main *bmain, struct Object *ob, bool copy_caches);
-struct Object *BKE_object_copy(struct Object *ob);
-void BKE_object_make_local(struct Object *ob);
+struct Object *BKE_object_copy(struct Main *bmain, struct Object *ob);
+void BKE_object_make_local(struct Main *bmain, struct Object *ob, const bool lib_local);
+void BKE_object_make_local_ex(struct Main *bmain, struct Object *ob, const bool lib_local, const bool clear_proxy);
bool BKE_object_is_libdata(struct Object *ob);
bool BKE_object_obdata_is_libdata(struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index bf1cfb263eb..0a3cc950f32 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -99,6 +99,8 @@ void BKE_paint_set_overlay_override(enum OverlayFlags flag);
/* palettes */
void BKE_palette_free(struct Palette *palette);
struct Palette *BKE_palette_add(struct Main *bmain, const char *name);
+struct Palette *BKE_palette_copy(struct Main *bmain, struct Palette *palette);
+void BKE_palette_make_local(struct Main *bmain, struct Palette *palette, const bool lib_local);
struct PaletteColor *BKE_palette_color_add(struct Palette *palette);
bool BKE_palette_is_empty(const struct Palette *palette);
void BKE_palette_color_remove(struct Palette *palette, struct PaletteColor *color);
@@ -107,6 +109,8 @@ void BKE_palette_clear(struct Palette *palette);
/* paint curves */
struct PaintCurve *BKE_paint_curve_add(struct Main *bmain, const char *name);
void BKE_paint_curve_free(struct PaintCurve *pc);
+struct PaintCurve *BKE_paint_curve_copy(struct Main *bmain, struct PaintCurve *pc);
+void BKE_paint_curve_make_local(struct Main *bmain, struct PaintCurve *pc, const bool lib_local);
void BKE_paint_init(struct Scene *sce, PaintMode mode, const char col[3]);
void BKE_paint_free(struct Paint *p);
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index e17fb9f7a02..b3e3968ca9b 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -63,6 +63,8 @@ struct BVHTreeRay;
struct BVHTreeRayHit;
struct EdgeHash;
+#define PARTICLE_COLLISION_MAX_COLLISIONS 10
+
#define PARTICLE_P ParticleData * pa; int p
#define LOOP_PARTICLES for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++)
#define LOOP_EXISTING_PARTICLES for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++) if (!(pa->flag & PARS_UNEXIST))
@@ -148,7 +150,8 @@ typedef struct ParticleThreadContext {
struct ParticleData *tpars;
/* path caching */
- int editupdate, between, segments, extra_segments;
+ bool editupdate;
+ int between, segments, extra_segments;
int totchild, totparent, parent_pass;
float cfra;
@@ -204,8 +207,7 @@ typedef struct ParticleCollisionElement {
typedef struct ParticleCollision {
struct Object *current;
struct Object *hit;
- struct Object *prev;
- struct Object *skip;
+ struct Object *skip[PARTICLE_COLLISION_MAX_COLLISIONS+1];
struct Object *emitter;
struct CollisionModifierData *md; // collision modifier for current object;
@@ -217,7 +219,7 @@ typedef struct ParticleCollision {
float original_ray_length; //original length of co2-co1, needed for collision time evaluation
- int prev_index;
+ int skip_count;
ParticleCollisionElement pce;
@@ -293,7 +295,7 @@ void psys_set_current_num(Object *ob, int index);
struct LatticeDeformData *psys_create_lattice_deform_data(struct ParticleSimulationData *sim);
bool psys_in_edit_mode(struct Scene *scene, struct ParticleSystem *psys);
-bool psys_check_enabled(struct Object *ob, struct ParticleSystem *psys);
+bool psys_check_enabled(struct Object *ob, struct ParticleSystem *psys, const bool use_render_params);
bool psys_check_edited(struct ParticleSystem *psys);
void psys_check_group_weights(struct ParticleSettings *part);
@@ -322,16 +324,16 @@ struct ParticleSystemModifierData *psys_get_modifier(struct Object *ob, struct P
struct ModifierData *object_add_particle_system(struct Scene *scene, struct Object *ob, const char *name);
void object_remove_particle_system(struct Scene *scene, struct Object *ob);
struct ParticleSettings *psys_new_settings(const char *name, struct Main *main);
-struct ParticleSettings *BKE_particlesettings_copy(struct ParticleSettings *part);
-void BKE_particlesettings_make_local(struct ParticleSettings *part);
+struct ParticleSettings *BKE_particlesettings_copy(struct Main *bmain, struct ParticleSettings *part);
+void BKE_particlesettings_make_local(struct Main *bmain, struct ParticleSettings *part, const bool lib_local);
void psys_reset(struct ParticleSystem *psys, int mode);
-void psys_find_parents(struct ParticleSimulationData *sim);
+void psys_find_parents(struct ParticleSimulationData *sim, const bool use_render_params);
-void psys_cache_paths(struct ParticleSimulationData *sim, float cfra);
-void psys_cache_edit_paths(struct Scene *scene, struct Object *ob, struct PTCacheEdit *edit, float cfra);
-void psys_cache_child_paths(struct ParticleSimulationData *sim, float cfra, int editupdate);
+void psys_cache_paths(struct ParticleSimulationData *sim, float cfra, const bool use_render_params);
+void psys_cache_edit_paths(struct Scene *scene, struct Object *ob, struct PTCacheEdit *edit, float cfra, const bool use_render_params);
+void psys_cache_child_paths(struct ParticleSimulationData *sim, float cfra, const bool editupdate, const bool use_render_params);
int do_guides(struct ParticleSettings *part, struct ListBase *effectors, ParticleKey *state, int pa_num, float time);
void precalc_guides(struct ParticleSimulationData *sim, struct ListBase *effectors);
float psys_get_timestep(struct ParticleSimulationData *sim);
@@ -379,7 +381,7 @@ void psys_check_boid_data(struct ParticleSystem *psys);
void psys_get_birth_coords(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ParticleKey *state, float dtime, float cfra);
-void particle_system_update(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys);
+void particle_system_update(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, const bool use_render_params);
/* Callback format for performing operations on ID-pointers for particle systems */
typedef void (*ParticleSystemIDFunc)(struct ParticleSystem *psys, struct ID **idpoin, void *userdata, int cd_flag);
diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h
index 8238ea64242..02f6c435ee2 100644
--- a/source/blender/blenkernel/BKE_pointcache.h
+++ b/source/blender/blenkernel/BKE_pointcache.h
@@ -304,7 +304,7 @@ void BKE_ptcache_mem_pointers_incr(struct PTCacheMem *pm);
int BKE_ptcache_mem_pointers_seek(int point_index, struct PTCacheMem *pm);
/* Main cache reading call. */
-int BKE_ptcache_read(PTCacheID *pid, float cfra);
+int BKE_ptcache_read(PTCacheID *pid, float cfra, bool no_extrapolate_old);
/* Main cache writing call. */
int BKE_ptcache_write(PTCacheID *pid, unsigned int cfra);
diff --git a/source/blender/blenkernel/BKE_sca.h b/source/blender/blenkernel/BKE_sca.h
index fa448aa97b8..a504f1bac3d 100644
--- a/source/blender/blenkernel/BKE_sca.h
+++ b/source/blender/blenkernel/BKE_sca.h
@@ -31,8 +31,9 @@
* \ingroup bke
*/
-struct bSensor;
+struct Main;
struct Object;
+struct bSensor;
struct bController;
struct bActuator;
@@ -67,7 +68,9 @@ void clear_sca_new_poins_ob(struct Object *ob);
void clear_sca_new_poins(void);
void set_sca_new_poins_ob(struct Object *ob);
void set_sca_new_poins(void);
-void sca_remove_ob_poin(struct Object *obt, struct Object *ob);
+
+void BKE_sca_logic_links_remap(struct Main *bmain, struct Object *ob_old, struct Object *ob_new);
+void BKE_sca_logic_copy(struct Object *ob_new, struct Object *ob);
void sca_move_sensor(struct bSensor *sens_to_move, struct Object *ob, int move_up);
void sca_move_controller(struct bController *cont_to_move, struct Object *ob, int move_up);
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index a4c44b9934e..d2152950bff 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -98,12 +98,15 @@ void BKE_scene_base_flag_from_objects(struct Scene *scene);
void BKE_scene_set_background(struct Main *bmain, struct Scene *sce);
struct Scene *BKE_scene_set_name(struct Main *bmain, const char *name);
-struct Scene *BKE_scene_copy(struct Scene *sce, int type);
+struct Scene *BKE_scene_copy(struct Main *bmain, struct Scene *sce, int type);
void BKE_scene_groups_relink(struct Scene *sce);
-void BKE_scene_unlink(struct Main *bmain, struct Scene *sce, struct Scene *newsce);
+
+void BKE_scene_make_local(struct Main *bmain, struct Scene *sce, const bool lib_local);
struct Object *BKE_scene_camera_find(struct Scene *sc);
+#ifdef DURIAN_CAMERA_SWITCH
struct Object *BKE_scene_camera_switch_find(struct Scene *scene); // DURIAN_CAMERA_SWITCH
+#endif
int BKE_scene_camera_switch_update(struct Scene *scene);
char *BKE_scene_find_marker_name(struct Scene *scene, int frame);
@@ -135,6 +138,7 @@ float get_render_aosss_error(const struct RenderData *r, float error);
bool BKE_scene_use_new_shading_nodes(const struct Scene *scene);
bool BKE_scene_use_shading_nodes_custom(struct Scene *scene);
+bool BKE_scene_use_world_space_shading(struct Scene *scene);
bool BKE_scene_use_spherical_stereo(struct Scene *scene);
bool BKE_scene_uses_blender_internal(const struct Scene *scene);
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index d05df3470b5..14e978b23f2 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -99,6 +99,9 @@ typedef struct SpaceType {
/* return context data */
int (*context)(const struct bContext *, const char *, struct bContextDataResult *);
+ /* Used when we want to replace an ID by another (or NULL). */
+ void (*id_remap)(struct ScrArea *, struct SpaceLink *, struct ID *, struct ID *);
+
/* region type definitions */
ListBase regiontypes;
@@ -274,8 +277,8 @@ void BKE_spacedata_freelist(ListBase *lb);
void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2);
void BKE_spacedata_draw_locks(int set);
-void BKE_spacedata_callback_id_unref_set(void (*func)(struct SpaceLink *sl, const struct ID *));
-void BKE_spacedata_id_unref(struct SpaceLink *sl, const struct ID *id);
+void BKE_spacedata_callback_id_remap_set(void (*func)(struct ScrArea *, struct SpaceLink *, struct ID *, struct ID *));
+void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID *id);
/* area/regions */
struct ARegion *BKE_area_region_copy(struct SpaceType *st, struct ARegion *ar);
diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h
index 30bb6954019..811e9136fc9 100644
--- a/source/blender/blenkernel/BKE_sequencer.h
+++ b/source/blender/blenkernel/BKE_sequencer.h
@@ -477,4 +477,6 @@ struct ImBuf *BKE_sequencer_render_mask_input(
int cfra, int fra_offset, bool make_float);
void BKE_sequencer_color_balance_apply(struct StripColorBalance *cb, struct ImBuf *ibuf, float mul, bool make_float, struct ImBuf *mask_input);
+void BKE_sequencer_all_free_anim_ibufs(int cfra);
+
#endif /* __BKE_SEQUENCER_H__ */
diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h
index 67db2537c8f..28b15b2a310 100644
--- a/source/blender/blenkernel/BKE_sound.h
+++ b/source/blender/blenkernel/BKE_sound.h
@@ -72,8 +72,6 @@ struct bSound *BKE_sound_new_buffer(struct Main *bmain, struct bSound *source);
struct bSound *BKE_sound_new_limiter(struct Main *bmain, struct bSound *source, float start, float end);
#endif
-void BKE_sound_delete(struct Main *bmain, struct bSound *sound);
-
void BKE_sound_cache(struct bSound *sound);
void BKE_sound_delete_cache(struct bSound *sound);
@@ -82,6 +80,8 @@ void BKE_sound_load(struct Main *main, struct bSound *sound);
void BKE_sound_free(struct bSound *sound);
+void BKE_sound_make_local(struct Main *bmain, struct bSound *sound, const bool lib_local);
+
#if defined(__AUD_C_API_H__) || defined(WITH_SYSTEM_AUDASPACE)
AUD_Device *BKE_sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start, float volume);
#endif
diff --git a/source/blender/blenkernel/BKE_speaker.h b/source/blender/blenkernel/BKE_speaker.h
index 5f30df1d6e3..b91b64c4b74 100644
--- a/source/blender/blenkernel/BKE_speaker.h
+++ b/source/blender/blenkernel/BKE_speaker.h
@@ -33,8 +33,8 @@ struct Speaker;
void BKE_speaker_init(struct Speaker *spk);
void *BKE_speaker_add(struct Main *bmain, const char *name);
-struct Speaker *BKE_speaker_copy(struct Speaker *spk);
-void BKE_speaker_make_local(struct Speaker *spk);
+struct Speaker *BKE_speaker_copy(struct Main *bmain, struct Speaker *spk);
+void BKE_speaker_make_local(struct Main *bmain, struct Speaker *spk, const bool lib_local);
void BKE_speaker_free(struct Speaker *spk);
#endif
diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h
index b14593f5a56..081b7589af6 100644
--- a/source/blender/blenkernel/BKE_text.h
+++ b/source/blender/blenkernel/BKE_text.h
@@ -53,7 +53,7 @@ struct Text *BKE_text_load_ex(struct Main *bmain, const char *file, const cha
const bool is_internal);
struct Text *BKE_text_load (struct Main *bmain, const char *file, const char *relpath);
struct Text *BKE_text_copy (struct Main *bmain, struct Text *ta);
-void BKE_text_unlink (struct Main *bmain, struct Text *text);
+void BKE_text_make_local (struct Main *bmain, struct Text *text, const bool lib_local);
void BKE_text_clear (struct Text *text);
void BKE_text_write (struct Text *text, const char *str);
int BKE_text_file_modified_check(struct Text *text);
diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h
index 95918b9ca0b..1c5ea946f59 100644
--- a/source/blender/blenkernel/BKE_texture.h
+++ b/source/blender/blenkernel/BKE_texture.h
@@ -69,10 +69,10 @@ void colorband_update_sort(struct ColorBand *coba);
void BKE_texture_free(struct Tex *tex);
void BKE_texture_default(struct Tex *tex);
-struct Tex *BKE_texture_copy(struct Tex *tex);
+struct Tex *BKE_texture_copy(struct Main *bmain, struct Tex *tex);
struct Tex *BKE_texture_add(struct Main *bmain, const char *name);
struct Tex *BKE_texture_localize(struct Tex *tex);
-void BKE_texture_make_local(struct Tex *tex);
+void BKE_texture_make_local(struct Main *bmain, struct Tex *tex, const bool lib_local);
void BKE_texture_type_set(struct Tex *tex, int type);
void BKE_texture_mtex_default(struct MTex *mtex);
diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h
index 2ca88425c29..30873567297 100644
--- a/source/blender/blenkernel/BKE_tracking.h
+++ b/source/blender/blenkernel/BKE_tracking.h
@@ -52,6 +52,7 @@ struct rcti;
/* **** Common functions **** */
void BKE_tracking_free(struct MovieTracking *tracking);
+void BKE_tracking_copy(struct MovieTracking *tracking_dst, struct MovieTracking *tracking_src);
void BKE_tracking_settings_init(struct MovieTracking *tracking);
@@ -276,9 +277,9 @@ void BKE_tracking_detect_harris(struct MovieTracking *tracking, struct ListBase
bool place_outside_layer);
/* **** 2D stabilization **** */
-void BKE_tracking_stabilization_data_get(struct MovieTracking *tracking, int framenr, int width, int height,
+void BKE_tracking_stabilization_data_get(struct MovieClip *clip, int framenr, int width, int height,
float translation[2], float *scale, float *angle);
-struct ImBuf *BKE_tracking_stabilize_frame(struct MovieTracking *tracking, int framenr, struct ImBuf *ibuf,
+struct ImBuf *BKE_tracking_stabilize_frame(struct MovieClip *clip, int framenr, struct ImBuf *ibuf,
float translation[2], float *scale, float *angle);
void BKE_tracking_stabilization_data_to_mat4(int width, int height, float aspect, float translation[2],
float scale, float angle, float mat[4][4]);
diff --git a/source/blender/blenkernel/BKE_world.h b/source/blender/blenkernel/BKE_world.h
index 8d7ab230919..23bf9ec3d22 100644
--- a/source/blender/blenkernel/BKE_world.h
+++ b/source/blender/blenkernel/BKE_world.h
@@ -37,12 +37,11 @@ struct Main;
struct World;
void BKE_world_free(struct World *sc);
-void BKE_world_free_ex(struct World *sc, bool do_id_user);
void BKE_world_init(struct World *wrld);
struct World *add_world(struct Main *bmian, const char *name);
-struct World *BKE_world_copy(struct World *wrld);
+struct World *BKE_world_copy(struct Main *bmain, struct World *wrld);
struct World *localize_world(struct World *wrld);
-void BKE_world_make_local(struct World *wrld);
+void BKE_world_make_local(struct Main *bmain, struct World *wrld, const bool lib_local);
#endif
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index afab0ccc5a5..157c4408d6a 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -49,9 +49,6 @@ set(INC
../../../intern/smoke/extern
../../../intern/atomic
../../../intern/libmv
-
- # XXX - BAD LEVEL CALL WM_api.h
- ../windowmanager
)
set(INC_SYS
@@ -84,6 +81,7 @@ set(SRC
intern/brush.c
intern/bullet.c
intern/bvhutils.c
+ intern/cachefile.c
intern/camera.c
intern/cdderivedmesh.c
intern/cloth.c
@@ -121,7 +119,9 @@ set(SRC
intern/lamp.c
intern/lattice.c
intern/library.c
+ intern/library_idmap.c
intern/library_query.c
+ intern/library_remap.c
intern/linestyle.c
intern/mask.c
intern/mask_evaluate.c
@@ -208,6 +208,7 @@ set(SRC
BKE_brush.h
BKE_bullet.h
BKE_bvhutils.h
+ BKE_cachefile.h
BKE_camera.h
BKE_ccg.h
BKE_cdderivedmesh.h
@@ -244,7 +245,9 @@ set(SRC
BKE_lamp.h
BKE_lattice.h
BKE_library.h
+ BKE_library_idmap.h
BKE_library_query.h
+ BKE_library_remap.h
BKE_linestyle.h
BKE_main.h
BKE_mask.h
@@ -499,6 +502,13 @@ if(WITH_FREESTYLE)
add_definitions(-DWITH_FREESTYLE)
endif()
+if(WITH_ALEMBIC)
+ list(APPEND INC
+ ../alembic
+ )
+ add_definitions(-DWITH_ALEMBIC)
+endif()
+
if(WITH_OPENSUBDIV)
add_definitions(-DWITH_OPENSUBDIV)
list(APPEND INC_SYS
diff --git a/source/blender/blenkernel/depsgraph_private.h b/source/blender/blenkernel/depsgraph_private.h
index 7b3199efb41..69ca75836d9 100644
--- a/source/blender/blenkernel/depsgraph_private.h
+++ b/source/blender/blenkernel/depsgraph_private.h
@@ -34,6 +34,11 @@
#include "DNA_constraint_types.h"
#include "BKE_constraint.h"
+struct Scene;
+struct Group;
+struct EffectorWeights;
+struct ModifierData;
+
/* **** DAG relation types *** */
/* scene link to object */
@@ -152,6 +157,11 @@ DagNode *dag_get_node(DagForest *forest, void *fob);
DagNode *dag_get_sub_node(DagForest *forest, void *fob);
void dag_add_relation(DagForest *forest, DagNode *fob1, DagNode *fob2, short rel, const char *name);
+typedef bool (*DagCollobjFilterFunction)(struct Object *obj, struct ModifierData *md);
+
+void dag_add_collision_relations(DagForest *dag, struct Scene *scene, Object *ob, DagNode *node, struct Group *group, int layer, unsigned int modifier_type, DagCollobjFilterFunction fn, bool dupli, const char *name);
+void dag_add_forcefield_relations(DagForest *dag, struct Scene *scene, Object *ob, DagNode *node, struct EffectorWeights *eff, bool add_absorption, int skip_forcefield, const char *name);
+
void graph_print_queue(DagNodeQueue *nqueue);
void graph_print_queue_dist(DagNodeQueue *nqueue);
void graph_print_adj_list(DagForest *dag);
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c
index 828a6bb16ac..792e9195f12 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf.c
@@ -313,12 +313,10 @@ CCGSubSurf *ccgSubSurf_new(CCGMeshIFC *ifc, int subdivLevels, CCGAllocatorIFC *a
ss->osd_vao = 0;
ss->skip_grids = false;
ss->osd_compute = 0;
- ss->osd_uvs_invalid = true;
- ss->osd_subsurf_uv = 0;
- ss->osd_uv_index = -1;
ss->osd_next_face_ptex_index = 0;
ss->osd_coarse_coords = NULL;
ss->osd_num_coarse_coords = 0;
+ ss->osd_subdiv_uvs = false;
#endif
return ss;
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.h b/source/blender/blenkernel/intern/CCGSubSurf.h
index a825cffe7a0..4c913e79586 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.h
+++ b/source/blender/blenkernel/intern/CCGSubSurf.h
@@ -205,7 +205,7 @@ void ccgSubSurf_checkTopologyChanged(CCGSubSurf *ss, struct DerivedMesh *dm);
void ccgSubSurf_prepareTopologyRefiner(CCGSubSurf *ss, struct DerivedMesh *dm);
/* Make sure GL mesh exists, up to date and ready to draw. */
-bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl);
+bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl, int active_uv_index);
/* Draw given partitions of the GL mesh.
*
@@ -244,6 +244,8 @@ void ccgSubSurf_free_osd_mesh(CCGSubSurf *ss);
void ccgSubSurf_getMinMax(CCGSubSurf *ss, float r_min[3], float r_max[3]);
+void ccgSubSurf__sync_subdivUvs(CCGSubSurf *ss, bool subsurf_uvs);
+
#endif
#endif /* __CCGSUBSURF_H__ */
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_intern.h b/source/blender/blenkernel/intern/CCGSubSurf_intern.h
index 7ec9f329444..9df1c9021ef 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_intern.h
+++ b/source/blender/blenkernel/intern/CCGSubSurf_intern.h
@@ -86,7 +86,7 @@ void ccg_ehashIterator_next(EHashIterator *ehi);
int ccg_ehashIterator_isStopped(EHashIterator *ehi);
/**
- * Standard allocator implementarion.
+ * Standard allocator implementation.
*/
CCGAllocatorIFC *ccg_getStandardAllocatorIFC(void);
@@ -255,10 +255,7 @@ struct CCGSubSurf {
*/
int osd_next_face_ptex_index;
- /* ** Needs review. ** */
- bool osd_subsurf_uv;
- int osd_uv_index;
- bool osd_uvs_invalid;
+ bool osd_subdiv_uvs;
#endif
};
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
index 2bb55c2d1ed..65cf899b42b 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
@@ -190,7 +190,6 @@ void ccgSubSurf_checkTopologyChanged(CCGSubSurf *ss, DerivedMesh *dm)
/* ** Make sure both GPU and CPU backends are properly reset. ** */
ss->osd_coarse_coords_invalid = true;
- ss->osd_uvs_invalid = true;
/* Reset GPU part. */
ss->osd_mesh_invalid = true;
@@ -216,7 +215,9 @@ static void ccgSubSurf__updateGLMeshCoords(CCGSubSurf *ss)
ss->osd_num_coarse_coords);
}
-bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl)
+bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss,
+ bool use_osd_glsl,
+ int active_uv_index)
{
int compute_type;
@@ -256,8 +257,7 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl)
ss->osd_mesh = openSubdiv_createOsdGLMeshFromTopologyRefiner(
ss->osd_topology_refiner,
compute_type,
- ss->subdivLevels,
- ss->osd_subsurf_uv);
+ ss->subdivLevels);
ss->osd_topology_refiner = NULL;
if (UNLIKELY(ss->osd_mesh == NULL)) {
@@ -290,7 +290,7 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl)
ss->osd_coarse_coords_invalid = false;
}
- openSubdiv_osdGLMeshDisplayPrepare(use_osd_glsl, ss->osd_uv_index);
+ openSubdiv_osdGLMeshDisplayPrepare(use_osd_glsl, active_uv_index);
return true;
}
@@ -984,6 +984,11 @@ void ccgSubSurf__delete_pending(void)
BLI_spin_unlock(&delete_spin);
}
+void ccgSubSurf__sync_subdivUvs(CCGSubSurf *ss, bool subdiv_uvs)
+{
+ ss->osd_subdiv_uvs = subdiv_uvs;
+}
+
/* ** Public API ** */
void BKE_subsurf_osd_init(void)
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c
index c4317f4d740..f1f82f458aa 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c
@@ -62,6 +62,16 @@ typedef struct ConvDMStorage {
*vert_poly_mem,
*edge_poly_mem;
#endif
+
+ MVert *mvert;
+ MEdge *medge;
+ MLoop *mloop;
+ MPoly *mpoly;
+
+ MeshIslandStore island_store;
+ int num_uvs;
+ float *uvs;
+ int *face_uvs;
} ConvDMStorage;
static OpenSubdiv_SchemeType conv_dm_get_type(
@@ -74,6 +84,13 @@ static OpenSubdiv_SchemeType conv_dm_get_type(
return OSD_SCHEME_CATMARK;
}
+static bool conv_dm_get_subdiv_uvs(
+ const OpenSubdiv_Converter *converter)
+{
+ ConvDMStorage *storage = converter->user_data;
+ return (storage->ss->osd_subdiv_uvs);
+}
+
static int conv_dm_get_num_faces(const OpenSubdiv_Converter *converter)
{
ConvDMStorage *storage = converter->user_data;
@@ -99,9 +116,7 @@ static int conv_dm_get_num_face_verts(const OpenSubdiv_Converter *converter,
int face)
{
ConvDMStorage *storage = converter->user_data;
- DerivedMesh *dm = storage->dm;
- const MPoly *mp = dm->getPolyArray(dm);
- const MPoly *mpoly = &mp[face];
+ const MPoly *mpoly = &storage->mpoly[face];
return mpoly->totloop;
}
@@ -110,13 +125,10 @@ static void conv_dm_get_face_verts(const OpenSubdiv_Converter *converter,
int *face_verts)
{
ConvDMStorage *storage = converter->user_data;
- DerivedMesh *dm = storage->dm;
- const MLoop *ml = dm->getLoopArray(dm);
- const MPoly *mp = dm->getPolyArray(dm);
- const MPoly *mpoly = &mp[face];
+ const MPoly *mpoly = &storage->mpoly[face];
int loop;
for (loop = 0; loop < mpoly->totloop; loop++) {
- face_verts[loop] = ml[mpoly->loopstart + loop].v;
+ face_verts[loop] = storage->mloop[mpoly->loopstart + loop].v;
}
}
@@ -125,13 +137,10 @@ static void conv_dm_get_face_edges(const OpenSubdiv_Converter *converter,
int *face_edges)
{
ConvDMStorage *storage = converter->user_data;
- DerivedMesh *dm = storage->dm;
- const MLoop *ml = dm->getLoopArray(dm);
- const MPoly *mp = dm->getPolyArray(dm);
- const MPoly *mpoly = &mp[face];
+ const MPoly *mpoly = &storage->mpoly[face];
int loop;
for (loop = 0; loop < mpoly->totloop; loop++) {
- face_edges[loop] = ml[mpoly->loopstart + loop].e;
+ face_edges[loop] = storage->mloop[mpoly->loopstart + loop].e;
}
}
@@ -140,9 +149,7 @@ static void conv_dm_get_edge_verts(const OpenSubdiv_Converter *converter,
int *edge_verts)
{
ConvDMStorage *storage = converter->user_data;
- DerivedMesh *dm = storage->dm;
- const MEdge *me = dm->getEdgeArray(dm);
- const MEdge *medge = &me[edge];
+ const MEdge *medge = &storage->medge[edge];
edge_verts[0] = medge->v1;
edge_verts[1] = medge->v2;
}
@@ -153,14 +160,12 @@ static int conv_dm_get_num_edge_faces(const OpenSubdiv_Converter *converter,
ConvDMStorage *storage = converter->user_data;
#ifndef USE_MESH_ELEMENT_MAPPING
DerivedMesh *dm = storage->dm;
- const MLoop *ml = dm->getLoopArray(dm);
- const MPoly *mp = dm->getPolyArray(dm);
int num = 0, poly;
for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
- const MPoly *mpoly = &mp[poly];
+ const MPoly *mpoly = &user_data->mpoly[poly];
int loop;
for (loop = 0; loop < mpoly->totloop; loop++) {
- const MLoop *mloop = &ml[mpoly->loopstart + loop];
+ const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
if (mloop->e == edge) {
++num;
break;
@@ -180,14 +185,12 @@ static void conv_dm_get_edge_faces(const OpenSubdiv_Converter *converter,
ConvDMStorage *storage = converter->user_data;
#ifndef USE_MESH_ELEMENT_MAPPING
DerivedMesh *dm = storage->dm;
- const MLoop *ml = dm->getLoopArray(dm);
- const MPoly *mp = dm->getPolyArray(dm);
int num = 0, poly;
for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
- const MPoly *mpoly = &mp[poly];
+ const MPoly *mpoly = &user_data->mpoly[poly];
int loop;
for (loop = 0; loop < mpoly->totloop; loop++) {
- const MLoop *mloop = &ml[mpoly->loopstart + loop];
+ const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
if (mloop->e == edge) {
edge_faces[num++] = poly;
break;
@@ -205,9 +208,8 @@ static float conv_dm_get_edge_sharpness(const OpenSubdiv_Converter *converter,
int edge)
{
ConvDMStorage *storage = converter->user_data;
- DerivedMesh *dm = storage->dm;
CCGSubSurf *ss = storage->ss;
- const MEdge *medge = dm->getEdgeArray(dm);
+ const MEdge *medge = storage->medge;
return (float)medge[edge].crease / 255.0f * ss->subdivLevels;
}
@@ -217,10 +219,9 @@ static int conv_dm_get_num_vert_edges(const OpenSubdiv_Converter *converter,
ConvDMStorage *storage = converter->user_data;
#ifndef USE_MESH_ELEMENT_MAPPING
DerivedMesh *dm = storage->dm;
- const MEdge *me = dm->getEdgeArray(dm);
int num = 0, edge;
for (edge = 0; edge < dm->getNumEdges(dm); edge++) {
- const MEdge *medge = &me[edge];
+ const MEdge *medge = &user_data->medge[edge];
if (medge->v1 == vert || medge->v2 == vert) {
++num;
}
@@ -238,10 +239,9 @@ static void conv_dm_get_vert_edges(const OpenSubdiv_Converter *converter,
ConvDMStorage *storage = converter->user_data;
#ifndef USE_MESH_ELEMENT_MAPPING
DerivedMesh *dm = storage->dm;
- const MEdge *me = dm->getEdgeArray(dm);
int num = 0, edge;
for (edge = 0; edge < dm->getNumEdges(dm); edge++) {
- const MEdge *medge = &me[edge];
+ const MEdge *medge = &user_data->medge[edge];
if (medge->v1 == vert || medge->v2 == vert) {
vert_edges[num++] = edge;
}
@@ -259,14 +259,12 @@ static int conv_dm_get_num_vert_faces(const OpenSubdiv_Converter *converter,
ConvDMStorage *storage = converter->user_data;
#ifndef USE_MESH_ELEMENT_MAPPING
DerivedMesh *dm = storage->dm;
- const MLoop *ml = dm->getLoopArray(dm);
- const MPoly *mp = dm->getPolyArray(dm);
int num = 0, poly;
for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
- const MPoly *mpoly = &mp[poly];
+ const MPoly *mpoly = &user_data->mpoly[poly];
int loop;
for (loop = 0; loop < mpoly->totloop; loop++) {
- const MLoop *mloop = &ml[mpoly->loopstart + loop];
+ const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
if (mloop->v == vert) {
++num;
break;
@@ -286,14 +284,12 @@ static void conv_dm_get_vert_faces(const OpenSubdiv_Converter *converter,
ConvDMStorage *storage = converter->user_data;
#ifndef USE_MESH_ELEMENT_MAPPING
DerivedMesh *dm = storage->dm;
- const MLoop *ml = dm->getLoopArray(dm);
- const MPoly *mp = dm->getPolyArray(dm);
int num = 0, poly;
for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
- const MPoly *mpoly = &mp[poly];
+ const MPoly *mpoly = &storage->mpoly[poly];
int loop;
for (loop = 0; loop < mpoly->totloop; loop++) {
- const MLoop *mloop = &ml[mpoly->loopstart + loop];
+ const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
if (mloop->v == vert) {
vert_faces[num++] = poly;
break;
@@ -307,9 +303,114 @@ static void conv_dm_get_vert_faces(const OpenSubdiv_Converter *converter,
#endif
}
+static int conv_dm_get_num_uv_layers(const OpenSubdiv_Converter *converter)
+{
+ ConvDMStorage *storage = converter->user_data;
+ DerivedMesh *dm = storage->dm;
+ int num_uv_layers = CustomData_number_of_layers(&dm->loopData, CD_MLOOPUV);
+ return num_uv_layers;
+}
+
+static void conv_dm_precalc_uv_layer(const OpenSubdiv_Converter *converter,
+ int layer)
+{
+ ConvDMStorage *storage = converter->user_data;
+ DerivedMesh *dm = storage->dm;
+
+ const MLoopUV *mloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, layer);
+ const int num_loops = dm->getNumLoops(dm);
+
+ /* Initialize memory required for the operations. */
+ if (storage->uvs == NULL) {
+ storage->uvs = MEM_mallocN(sizeof(float) * 2 * num_loops, "osd uvs");
+ }
+ if (storage->face_uvs == NULL) {
+ storage->face_uvs = MEM_mallocN(sizeof(int) * num_loops, "osd face uvs");
+ }
+
+ /* Calculate islands connectivity of the UVs. */
+ BKE_mesh_calc_islands_loop_poly_uvmap(
+ storage->mvert, dm->getNumVerts(dm),
+ storage->medge, dm->getNumEdges(dm),
+ storage->mpoly, dm->getNumPolys(dm),
+ storage->mloop, dm->getNumLoops(dm),
+ mloopuv,
+ &storage->island_store);
+
+ /* Here we "weld" duplicated vertices from island to the same UV value.
+ * The idea here is that we need to pass individual islands to OpenSubdiv.
+ */
+ storage->num_uvs = 0;
+ for (int island = 0; island < storage->island_store.islands_num; ++island) {
+ MeshElemMap *island_poly_map = storage->island_store.islands[island];
+ for (int poly = 0; poly < island_poly_map->count; ++poly) {
+ int poly_index = island_poly_map->indices[poly];
+ /* Within the same UV island we should share UV points across
+ * loops. Otherwise each poly will be subdivided individually
+ * which we don't really want.
+ */
+ const MPoly *mpoly = &storage->mpoly[poly_index];
+ for (int loop = 0; loop < mpoly->totloop; ++loop) {
+ const MLoopUV *luv = &mloopuv[mpoly->loopstart + loop];
+ bool found = false;
+ /* TODO(sergey): Quite bad loop, which gives us O(N^2)
+ * complexity here. But how can we do it smarter, hopefully
+ * without requiring lots of additional memory.
+ */
+ for (int i = 0; i < storage->num_uvs; ++i) {
+ if (equals_v2v2(luv->uv, &storage->uvs[2 * i])) {
+ storage->face_uvs[mpoly->loopstart + loop] = i;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ copy_v2_v2(&storage->uvs[2 * storage->num_uvs], luv->uv);
+ storage->face_uvs[mpoly->loopstart + loop] = storage->num_uvs;
+ ++storage->num_uvs;
+ }
+ }
+ }
+ }
+}
+
+static void conv_dm_finish_uv_layer(const OpenSubdiv_Converter *converter)
+{
+ ConvDMStorage *storage = converter->user_data;
+ BKE_mesh_loop_islands_free(&storage->island_store);
+}
+
+static int conv_dm_get_num_uvs(const OpenSubdiv_Converter *converter)
+{
+ ConvDMStorage *storage = converter->user_data;
+ return storage->num_uvs;
+}
+
+static void conv_dm_get_uvs(const OpenSubdiv_Converter *converter, float *uvs)
+{
+ ConvDMStorage *storage = converter->user_data;
+ memcpy(uvs, storage->uvs, sizeof(float) * 2 * storage->num_uvs);
+}
+
+static int conv_dm_get_face_corner_uv_index(const OpenSubdiv_Converter *converter,
+ int face,
+ int corner)
+{
+ ConvDMStorage *storage = converter->user_data;
+ const MPoly *mpoly = &storage->mpoly[face];
+ return storage->face_uvs[mpoly->loopstart + corner];
+}
+
static void conv_dm_free_user_data(const OpenSubdiv_Converter *converter)
{
ConvDMStorage *user_data = converter->user_data;
+ if (user_data->uvs != NULL) {
+ MEM_freeN(user_data->uvs);
+ }
+ if (user_data->face_uvs != NULL) {
+ MEM_freeN(user_data->face_uvs);
+ }
+
#ifdef USE_MESH_ELEMENT_MAPPING
MEM_freeN(user_data->vert_edge_map);
MEM_freeN(user_data->vert_edge_mem);
@@ -330,6 +431,8 @@ void ccgSubSurf_converter_setup_from_derivedmesh(
converter->get_type = conv_dm_get_type;
+ converter->get_subdiv_uvs = conv_dm_get_subdiv_uvs;
+
converter->get_num_faces = conv_dm_get_num_faces;
converter->get_num_edges = conv_dm_get_num_edges;
converter->get_num_verts = conv_dm_get_num_verts;
@@ -348,9 +451,27 @@ void ccgSubSurf_converter_setup_from_derivedmesh(
converter->get_num_vert_faces = conv_dm_get_num_vert_faces;
converter->get_vert_faces = conv_dm_get_vert_faces;
+ converter->get_num_uv_layers = conv_dm_get_num_uv_layers;
+ converter->precalc_uv_layer = conv_dm_precalc_uv_layer;
+ converter->finish_uv_layer = conv_dm_finish_uv_layer;
+ converter->get_num_uvs = conv_dm_get_num_uvs;
+ converter->get_uvs = conv_dm_get_uvs;
+ converter->get_face_corner_uv_index = conv_dm_get_face_corner_uv_index;
+
user_data = MEM_mallocN(sizeof(ConvDMStorage), __func__);
user_data->ss = ss;
user_data->dm = dm;
+
+ user_data->mvert = dm->getVertArray(dm);
+ user_data->medge = dm->getEdgeArray(dm);
+ user_data->mloop = dm->getLoopArray(dm);
+ user_data->mpoly = dm->getPolyArray(dm);
+
+ memset(&user_data->island_store, 0, sizeof(user_data->island_store));
+
+ user_data->uvs = NULL;
+ user_data->face_uvs = NULL;
+
converter->free_user_data = conv_dm_free_user_data;
converter->user_data = user_data;
@@ -405,6 +526,13 @@ static OpenSubdiv_SchemeType conv_ccg_get_bilinear_type(
}
}
+static bool conv_ccg_get_subdiv_uvs(
+ const OpenSubdiv_Converter *converter)
+{
+ CCGSubSurf *ss = converter->user_data;
+ return (ss->osd_subdiv_uvs);
+}
+
static int conv_ccg_get_num_faces(const OpenSubdiv_Converter *converter)
{
CCGSubSurf *ss = converter->user_data;
@@ -548,11 +676,44 @@ static void conv_ccg_get_vert_faces(const OpenSubdiv_Converter *converter,
}
}
+static int conv_ccg_get_num_uv_layers(const OpenSubdiv_Converter *UNUSED(converter))
+{
+ return 0;
+}
+
+static void conv_ccg_precalc_uv_layer(const OpenSubdiv_Converter * UNUSED(converter),
+ int UNUSED(layer))
+{
+}
+
+static void conv_ccg_finish_uv_layer(const OpenSubdiv_Converter *UNUSED(converter))
+{
+}
+
+static int conv_ccg_get_num_uvs(const OpenSubdiv_Converter *UNUSED(converter))
+{
+ return 0;
+}
+
+static void conv_ccg_get_uvs(const OpenSubdiv_Converter * UNUSED(converter),
+ float *UNUSED(uvs))
+{
+}
+
+static int conv_ccg_get_face_corner_uv_index(const OpenSubdiv_Converter *UNUSED(converter),
+ int UNUSED(face),
+ int UNUSED(corner_))
+{
+ return 0;
+}
+
void ccgSubSurf_converter_setup_from_ccg(CCGSubSurf *ss,
OpenSubdiv_Converter *converter)
{
converter->get_type = conv_ccg_get_bilinear_type;
+ converter->get_subdiv_uvs = conv_ccg_get_subdiv_uvs;
+
converter->get_num_faces = conv_ccg_get_num_faces;
converter->get_num_edges = conv_ccg_get_num_edges;
converter->get_num_verts = conv_ccg_get_num_verts;
@@ -571,6 +732,13 @@ void ccgSubSurf_converter_setup_from_ccg(CCGSubSurf *ss,
converter->get_num_vert_faces = conv_ccg_get_num_vert_faces;
converter->get_vert_faces = conv_ccg_get_vert_faces;
+ converter->get_num_uv_layers = conv_ccg_get_num_uv_layers;
+ converter->precalc_uv_layer = conv_ccg_precalc_uv_layer;
+ converter->finish_uv_layer = conv_ccg_finish_uv_layer;
+ converter->get_num_uvs = conv_ccg_get_num_uvs;
+ converter->get_uvs = conv_ccg_get_uvs;
+ converter->get_face_corner_uv_index = conv_ccg_get_face_corner_uv_index;
+
converter->free_user_data = NULL;
converter->user_data = ss;
}
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_util.c b/source/blender/blenkernel/intern/CCGSubSurf_util.c
index 9af69115559..c7ef528c02f 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_util.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_util.c
@@ -184,7 +184,7 @@ int ccg_ehashIterator_isStopped(EHashIterator *ehi)
}
/**
- * Standard allocator implementarion.
+ * Standard allocator implementation.
*/
static void *_stdAllocator_alloc(CCGAllocatorHDL UNUSED(a), int numBytes)
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 1ec714ea0bb..ae18f5289d4 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -80,6 +80,7 @@ static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm);
#include "GPU_shader.h"
#ifdef WITH_OPENSUBDIV
+# include "BKE_depsgraph.h"
# include "DNA_userdef_types.h"
#endif
@@ -1433,10 +1434,12 @@ static void calc_weightpaint_vert_array(
Object *ob, DerivedMesh *dm, int const draw_flag, DMWeightColorInfo *dm_wcinfo,
unsigned char (*r_wtcol_v)[4])
{
- MDeformVert *dv = DM_get_vert_data_layer(dm, CD_MDEFORMVERT);
- int numVerts = dm->getNumVerts(dm);
+ BMEditMesh *em = (dm->type == DM_TYPE_EDITBMESH) ? BKE_editmesh_from_object(ob) : NULL;
+ const int numVerts = dm->getNumVerts(dm);
- if (dv && (ob->actdef != 0)) {
+ if ((ob->actdef != 0) &&
+ (CustomData_has_layer(em ? &em->bm->vdata : &dm->vertData, CD_MDEFORMVERT)))
+ {
unsigned char (*wc)[4] = r_wtcol_v;
unsigned int i;
@@ -1455,8 +1458,30 @@ static void calc_weightpaint_vert_array(
}
}
- for (i = numVerts; i != 0; i--, wc++, dv++) {
- calc_weightpaint_vert_color((unsigned char *)wc, dv, dm_wcinfo, defbase_tot, defbase_act, defbase_sel, defbase_sel_tot, draw_flag);
+ /* editmesh won't have deform verts unless modifiers require it,
+ * avoid having to create an array of deform-verts only for drawing
+ * by reading from the bmesh directly. */
+ if (em) {
+ BMIter iter;
+ BMVert *eve;
+ const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
+ BLI_assert(cd_dvert_offset != -1);
+
+ BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
+ const MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
+ calc_weightpaint_vert_color(
+ (unsigned char *)wc, dv, dm_wcinfo,
+ defbase_tot, defbase_act, defbase_sel, defbase_sel_tot, draw_flag);
+ wc++;
+ }
+ }
+ else {
+ const MDeformVert *dv = DM_get_vert_data_layer(dm, CD_MDEFORMVERT);
+ for (i = numVerts; i != 0; i--, wc++, dv++) {
+ calc_weightpaint_vert_color(
+ (unsigned char *)wc, dv, dm_wcinfo,
+ defbase_tot, defbase_act, defbase_sel, defbase_sel_tot, draw_flag);
+ }
}
if (defbase_sel) {
@@ -2003,15 +2028,10 @@ static void mesh_calc_modifiers(
DM_add_edge_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
DM_add_poly_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
-#pragma omp parallel sections if (dm->numVertData + dm->numEdgeData + dm->numPolyData >= BKE_MESH_OMP_LIMIT)
- {
-#pragma omp section
- { range_vn_i(DM_get_vert_data_layer(dm, CD_ORIGINDEX), dm->numVertData, 0); }
-#pragma omp section
- { range_vn_i(DM_get_edge_data_layer(dm, CD_ORIGINDEX), dm->numEdgeData, 0); }
-#pragma omp section
- { range_vn_i(DM_get_poly_data_layer(dm, CD_ORIGINDEX), dm->numPolyData, 0); }
- }
+ /* Not worth parallelizing this, gives less than 0.1% overall speedup in best of best cases... */
+ range_vn_i(DM_get_vert_data_layer(dm, CD_ORIGINDEX), dm->numVertData, 0);
+ range_vn_i(DM_get_edge_data_layer(dm, CD_ORIGINDEX), dm->numEdgeData, 0);
+ range_vn_i(DM_get_poly_data_layer(dm, CD_ORIGINDEX), dm->numPolyData, 0);
}
}
@@ -2263,7 +2283,7 @@ static void editbmesh_calc_modifiers(
{
ModifierData *md, *previewmd = NULL;
float (*deformedVerts)[3] = NULL;
- CustomDataMask mask, previewmask = 0, append_mask = 0;
+ CustomDataMask mask = 0, previewmask = 0, append_mask = 0;
DerivedMesh *dm = NULL, *orcodm = NULL;
int i, numVerts = 0, cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1);
CDMaskLink *datamasks, *curr;
@@ -2287,7 +2307,7 @@ static void editbmesh_calc_modifiers(
modifiers_clearErrors(ob);
if (r_cage && cageIndex == -1) {
- *r_cage = getEditDerivedBMesh(em, ob, NULL);
+ *r_cage = getEditDerivedBMesh(em, ob, dataMask, NULL);
}
md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
@@ -2453,7 +2473,7 @@ static void editbmesh_calc_modifiers(
}
else {
*r_cage = getEditDerivedBMesh(
- em, ob,
+ em, ob, mask,
deformedVerts ? MEM_dupallocN(deformedVerts) : NULL);
}
}
@@ -2489,7 +2509,7 @@ static void editbmesh_calc_modifiers(
}
else {
/* this is just a copy of the editmesh, no need to calc normals */
- *r_final = getEditDerivedBMesh(em, ob, deformedVerts);
+ *r_final = getEditDerivedBMesh(em, ob, dataMask, deformedVerts);
deformedVerts = NULL;
/* In this case, we should never have weight-modifying modifiers in stack... */
@@ -2546,15 +2566,28 @@ static void editbmesh_calc_modifiers(
* we'll be using GPU backend of OpenSubdiv. This is so
* playback performance is kept as high as possible.
*/
-static bool calc_modifiers_skip_orco(const Object *ob)
+static bool calc_modifiers_skip_orco(Scene *scene,
+ Object *ob,
+ bool use_render_params)
{
- const ModifierData *last_md = ob->modifiers.last;
+ ModifierData *last_md = ob->modifiers.last;
+ const int required_mode = use_render_params ? eModifierMode_Render : eModifierMode_Realtime;
if (last_md != NULL &&
- last_md->type == eModifierType_Subsurf)
+ last_md->type == eModifierType_Subsurf &&
+ modifier_isEnabled(scene, last_md, required_mode))
{
+ if (U.opensubdiv_compute_type == USER_OPENSUBDIV_COMPUTE_NONE) {
+ return false;
+ }
+ else if ((ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)) != 0) {
+ return false;
+ }
+ else if ((DAG_get_eval_flags_for_object(scene, ob) & DAG_EVAL_NEED_CPU) != 0) {
+ return false;
+ }
SubsurfModifierData *smd = (SubsurfModifierData *)last_md;
/* TODO(sergey): Deduplicate this with checks from subsurf_ccg.c. */
- return smd->use_opensubdiv && U.opensubdiv_compute_type != USER_OPENSUBDIV_COMPUTE_NONE;
+ return smd->use_opensubdiv != 0;
}
return false;
}
@@ -2570,7 +2603,7 @@ static void mesh_build_data(
BKE_object_sculpt_modifiers_changed(ob);
#ifdef WITH_OPENSUBDIV
- if (calc_modifiers_skip_orco(ob)) {
+ if (calc_modifiers_skip_orco(scene, ob, false)) {
dataMask &= ~(CD_MASK_ORCO | CD_MASK_PREVIEW_MCOL);
}
#endif
@@ -2605,7 +2638,7 @@ static void editbmesh_build_data(Scene *scene, Object *obedit, BMEditMesh *em, C
BKE_editmesh_free_derivedmesh(em);
#ifdef WITH_OPENSUBDIV
- if (calc_modifiers_skip_orco(obedit)) {
+ if (calc_modifiers_skip_orco(scene, obedit, false)) {
dataMask &= ~(CD_MASK_ORCO | CD_MASK_PREVIEW_MCOL);
}
#endif
@@ -2852,9 +2885,9 @@ DerivedMesh *editbmesh_get_derived_cage(Scene *scene, Object *obedit, BMEditMesh
return em->derivedCage;
}
-DerivedMesh *editbmesh_get_derived_base(Object *obedit, BMEditMesh *em)
+DerivedMesh *editbmesh_get_derived_base(Object *obedit, BMEditMesh *em, CustomDataMask data_mask)
{
- return getEditDerivedBMesh(em, obedit, NULL);
+ return getEditDerivedBMesh(em, obedit, data_mask, NULL);
}
/***/
@@ -3223,7 +3256,7 @@ void DM_calc_tangents_names_from_gpu(
*r_tangent_names_count = count;
}
-static void DM_calc_loop_tangents_thread(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid))
+static void DM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
{
struct SGLSLMeshToTangent *mesh2tangent = taskdata;
/* new computation method */
@@ -3269,17 +3302,18 @@ void DM_calc_loop_tangents_step_0(
bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n,
char *ract_uv_name, char *rren_uv_name, char *rtangent_mask) {
/* Active uv in viewport */
+ int layer_index = CustomData_get_layer_index(loopData, CD_MLOOPUV);
*ract_uv_n = CustomData_get_active_layer(loopData, CD_MLOOPUV);
ract_uv_name[0] = 0;
if (*ract_uv_n != -1) {
- strcpy(ract_uv_name, loopData->layers[*ract_uv_n].name);
+ strcpy(ract_uv_name, loopData->layers[*ract_uv_n + layer_index].name);
}
/* Active tangent in render */
*rren_uv_n = CustomData_get_render_layer(loopData, CD_MLOOPUV);
rren_uv_name[0] = 0;
if (*rren_uv_n != -1) {
- strcpy(rren_uv_name, loopData->layers[*rren_uv_n].name);
+ strcpy(rren_uv_name, loopData->layers[*rren_uv_n + layer_index].name);
}
/* If active tangent not in tangent_names we take it into account */
@@ -3440,13 +3474,17 @@ void DM_calc_loop_tangents(
/* Update active layer index */
uv_index = CustomData_get_layer_index_n(&dm->loopData, CD_MLOOPUV, act_uv_n);
- tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, dm->loopData.layers[uv_index].name);
- CustomData_set_layer_active_index(&dm->loopData, CD_TANGENT, tan_index);
+ if (uv_index != -1) {
+ tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, dm->loopData.layers[uv_index].name);
+ CustomData_set_layer_active_index(&dm->loopData, CD_TANGENT, tan_index);
+ }
/* Update render layer index */
uv_index = CustomData_get_layer_index_n(&dm->loopData, CD_MLOOPUV, ren_uv_n);
- tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, dm->loopData.layers[uv_index].name);
- CustomData_set_layer_render_index(&dm->loopData, CD_TANGENT, tan_index);
+ if (uv_index != -1) {
+ tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, dm->loopData.layers[uv_index].name);
+ CustomData_set_layer_render_index(&dm->loopData, CD_TANGENT, tan_index);
+ }
}
}
@@ -3629,12 +3667,41 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
dm->calcLoopTangents(dm, false, (const char (*)[MAX_NAME])tangent_names, tangent_names_count);
for (b = 0; b < gattribs->totlayer; b++) {
- if (gattribs->layer[b].type == CD_MTFACE) {
- /* uv coordinates */
- if (gattribs->layer[b].name[0])
+ int type = gattribs->layer[b].type;
+ layer = -1;
+ if (type == CD_AUTO_FROM_NAME) {
+ /* We need to deduct what exact layer is used.
+ *
+ * We do it based on the specified name.
+ */
+ if (gattribs->layer[b].name[0]) {
layer = CustomData_get_named_layer_index(ldata, CD_MLOOPUV, gattribs->layer[b].name);
- else
- layer = CustomData_get_active_layer_index(ldata, CD_MLOOPUV);
+ type = CD_MTFACE;
+ if (layer == -1) {
+ layer = CustomData_get_named_layer_index(ldata, CD_MLOOPCOL, gattribs->layer[b].name);
+ type = CD_MCOL;
+ }
+ if (layer == -1) {
+ layer = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, gattribs->layer[b].name);
+ type = CD_TANGENT;
+ }
+ if (layer == -1) {
+ continue;
+ }
+ }
+ else {
+ /* Fall back to the UV layer, which matches old behavior. */
+ type = CD_MTFACE;
+ }
+ }
+ if (type == CD_MTFACE) {
+ /* uv coordinates */
+ if (layer == -1) {
+ if (gattribs->layer[b].name[0])
+ layer = CustomData_get_named_layer_index(ldata, CD_MLOOPUV, gattribs->layer[b].name);
+ else
+ layer = CustomData_get_active_layer_index(ldata, CD_MLOOPUV);
+ }
a = attribs->tottface++;
@@ -3648,13 +3715,16 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
}
attribs->tface[a].gl_index = gattribs->layer[b].glindex;
+ attribs->tface[a].gl_info_index = gattribs->layer[b].glinfoindoex;
attribs->tface[a].gl_texco = gattribs->layer[b].gltexco;
}
- else if (gattribs->layer[b].type == CD_MCOL) {
- if (gattribs->layer[b].name[0])
- layer = CustomData_get_named_layer_index(ldata, CD_MLOOPCOL, gattribs->layer[b].name);
- else
- layer = CustomData_get_active_layer_index(ldata, CD_MLOOPCOL);
+ else if (type == CD_MCOL) {
+ if (layer == -1) {
+ if (gattribs->layer[b].name[0])
+ layer = CustomData_get_named_layer_index(ldata, CD_MLOOPCOL, gattribs->layer[b].name);
+ else
+ layer = CustomData_get_active_layer_index(ldata, CD_MLOOPCOL);
+ }
a = attribs->totmcol++;
@@ -3669,14 +3739,16 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
}
attribs->mcol[a].gl_index = gattribs->layer[b].glindex;
+ attribs->mcol[a].gl_info_index = gattribs->layer[b].glinfoindoex;
}
- else if (gattribs->layer[b].type == CD_TANGENT) {
+ else if (type == CD_TANGENT) {
/* note, even with 'is_editmesh' this uses the derived-meshes loop data */
-
- if (gattribs->layer[b].name[0])
- layer = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, gattribs->layer[b].name);
- else
- layer = CustomData_get_active_layer_index(&dm->loopData, CD_TANGENT);
+ if (layer == -1) {
+ if (gattribs->layer[b].name[0])
+ layer = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, gattribs->layer[b].name);
+ else
+ layer = CustomData_get_active_layer_index(&dm->loopData, CD_TANGENT);
+ }
a = attribs->tottang++;
@@ -3690,10 +3762,13 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
}
attribs->tang[a].gl_index = gattribs->layer[b].glindex;
+ attribs->tang[a].gl_info_index = gattribs->layer[b].glinfoindoex;
}
- else if (gattribs->layer[b].type == CD_ORCO) {
+ else if (type == CD_ORCO) {
/* original coordinates */
- layer = CustomData_get_layer_index(vdata, CD_ORCO);
+ if (layer == -1) {
+ layer = CustomData_get_layer_index(vdata, CD_ORCO);
+ }
attribs->totorco = 1;
if (layer != -1) {
@@ -3707,6 +3782,7 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
attribs->orco.gl_index = gattribs->layer[b].glindex;
attribs->orco.gl_texco = gattribs->layer[b].gltexco;
+ attribs->orco.gl_info_index = gattribs->layer[b].glinfoindoex;
}
}
}
@@ -3757,29 +3833,47 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert,
/* vertex colors */
for (b = 0; b < attribs->totmcol; b++) {
- GLubyte col[4];
+ GLfloat col[4];
if (attribs->mcol[b].array) {
const MLoopCol *cp = &attribs->mcol[b].array[loop];
- copy_v4_v4_uchar(col, &cp->r);
+ rgba_uchar_to_float(col, &cp->r);
}
else {
- col[0] = 0; col[1] = 0; col[2] = 0; col[3] = 0;
+ zero_v4(col);
}
- glVertexAttrib4ubv(attribs->mcol[b].gl_index, col);
+ glVertexAttrib4fv(attribs->mcol[b].gl_index, col);
}
/* tangent for normal mapping */
for (b = 0; b < attribs->tottang; b++) {
if (attribs->tang[b].array) {
/*const*/ float (*array)[4] = attribs->tang[b].array;
- const float *tang = (array) ? array[a * 4 + vert] : zero;
+ const float *tang = (array) ? array[loop] : zero;
glVertexAttrib4fv(attribs->tang[b].gl_index, tang);
}
}
}
+void DM_draw_attrib_vertex_uniforms(const DMVertexAttribs *attribs)
+{
+ int i;
+ if (attribs->totorco) {
+ glUniform1i(attribs->orco.gl_info_index, 0);
+ }
+ for (i = 0; i < attribs->tottface; i++) {
+ glUniform1i(attribs->tface[i].gl_info_index, 0);
+ }
+ for (i = 0; i < attribs->totmcol; i++) {
+ glUniform1i(attribs->mcol[i].gl_info_index, GPU_ATTR_INFO_SRGB);
+ }
+
+ for (i = 0; i < attribs->tottang; i++) {
+ glUniform1i(attribs->tang[i].gl_info_index, 0);
+ }
+}
+
/* Set object's bounding box based on DerivedMesh min/max data */
void DM_set_object_boundbox(Object *ob, DerivedMesh *dm)
{
@@ -3843,7 +3937,6 @@ static void navmesh_drawColored(DerivedMesh *dm)
/* if (GPU_buffer_legacy(dm) ) */ /* TODO - VBO draw code, not high priority - campbell */
{
DEBUG_VBO("Using legacy code. drawNavMeshColored\n");
- //glShadeModel(GL_SMOOTH);
glBegin(glmode = GL_QUADS);
for (a = 0; a < dm->numTessFaceData; a++, mface++) {
int new_glmode = mface->v4 ? GL_QUADS : GL_TRIANGLES;
@@ -4000,7 +4093,7 @@ void DM_init_origspace(DerivedMesh *dm)
float p_nor[3], co[3];
float mat[3][3];
- float min[2] = {FLT_MAX, FLT_MAX}, max[2] = {FLT_MIN, FLT_MIN};
+ float min[2] = {FLT_MAX, FLT_MAX}, max[2] = {-FLT_MAX, -FLT_MAX};
float translate[2], scale[2];
BKE_mesh_calc_poly_normal(mp, l, mv, p_nor);
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index b969c9ec787..470098f8c7c 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -59,6 +59,8 @@
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_object.h"
@@ -92,94 +94,32 @@ bAction *add_empty_action(Main *bmain, const char name[])
/* .................................. */
-/* temp data for BKE_action_make_local */
-typedef struct tMakeLocalActionContext {
- bAction *act; /* original action */
- bAction *act_new; /* new action */
-
- bool is_lib; /* some action users were libraries */
- bool is_local; /* some action users were not libraries */
-} tMakeLocalActionContext;
-
-/* helper function for BKE_action_make_local() - local/lib init step */
-static void make_localact_init_cb(ID *id, AnimData *adt, void *mlac_ptr)
-{
- tMakeLocalActionContext *mlac = (tMakeLocalActionContext *)mlac_ptr;
-
- if (adt->action == mlac->act) {
- if (id->lib) mlac->is_lib = true;
- else mlac->is_local = true;
- }
-}
-
-/* helper function for BKE_action_make_local() - change references */
-static void make_localact_apply_cb(ID *id, AnimData *adt, void *mlac_ptr)
-{
- tMakeLocalActionContext *mlac = (tMakeLocalActionContext *)mlac_ptr;
-
- if (adt->action == mlac->act) {
- if (id->lib == NULL) {
- adt->action = mlac->act_new;
-
- id_us_plus(&mlac->act_new->id);
- id_us_min(&mlac->act->id);
- }
- }
-}
-
// does copy_fcurve...
-void BKE_action_make_local(bAction *act)
+void BKE_action_make_local(Main *bmain, bAction *act, const bool lib_local)
{
- tMakeLocalActionContext mlac = {act, NULL, false, false};
- Main *bmain = G.main;
-
- if (act->id.lib == NULL)
- return;
-
- /* XXX: double-check this; it used to be just single-user check, but that was when fake-users were still default */
- if ((act->id.flag & LIB_FAKEUSER) && (act->id.us <= 1)) {
- id_clear_lib_data(bmain, &act->id);
- return;
- }
-
- BKE_animdata_main_cb(bmain, make_localact_init_cb, &mlac);
-
- if (mlac.is_local && mlac.is_lib == false) {
- id_clear_lib_data(bmain, &act->id);
- }
- else if (mlac.is_local && mlac.is_lib) {
- mlac.act_new = BKE_action_copy(act);
- mlac.act_new->id.us = 0;
-
- BKE_id_lib_local_paths(bmain, act->id.lib, &mlac.act_new->id);
-
- BKE_animdata_main_cb(bmain, make_localact_apply_cb, &mlac);
- }
+ BKE_id_make_local_generic(bmain, &act->id, true, lib_local);
}
/* .................................. */
+/** Free (or release) any data used by this action (does not free the action itself). */
void BKE_action_free(bAction *act)
-{
- /* sanity check */
- if (act == NULL)
- return;
-
+{
+ /* No animdata here. */
+
/* Free F-Curves */
free_fcurves(&act->curves);
/* Free groups */
- if (act->groups.first)
- BLI_freelistN(&act->groups);
+ BLI_freelistN(&act->groups);
/* Free pose-references (aka local markers) */
- if (act->markers.first)
- BLI_freelistN(&act->markers);
+ BLI_freelistN(&act->markers);
}
/* .................................. */
-bAction *BKE_action_copy(bAction *src)
+bAction *BKE_action_copy(Main *bmain, bAction *src)
{
bAction *dst = NULL;
bActionGroup *dgrp, *sgrp;
@@ -187,7 +127,7 @@ bAction *BKE_action_copy(bAction *src)
if (src == NULL)
return NULL;
- dst = BKE_libblock_copy(&src->id);
+ dst = BKE_libblock_copy(bmain, &src->id);
/* duplicate the lists of groups and markers */
BLI_duplicatelist(&dst->groups, &src->groups);
@@ -216,9 +156,7 @@ bAction *BKE_action_copy(bAction *src)
}
}
- if (src->id.lib) {
- BKE_id_lib_local_paths(G.main, src->id.lib, &dst->id);
- }
+ BKE_id_copy_ensure_local(bmain, &src->id, &dst->id);
return dst;
}
@@ -493,6 +431,8 @@ bPoseChannel *BKE_pose_channel_verify(bPose *pose, const char *name)
unit_axis_angle(chan->rotAxis, &chan->rotAngle);
chan->size[0] = chan->size[1] = chan->size[2] = 1.0f;
+ chan->scaleIn = chan->scaleOut = 1.0f;
+
chan->limitmin[0] = chan->limitmin[1] = chan->limitmin[2] = -180.0f;
chan->limitmax[0] = chan->limitmax[1] = chan->limitmax[2] = 180.0f;
chan->stiffness[0] = chan->stiffness[1] = chan->stiffness[2] = 0.0f;
@@ -596,7 +536,16 @@ void BKE_pose_copy_data(bPose **dst, bPose *src, const bool copy_constraints)
outPose = MEM_callocN(sizeof(bPose), "pose");
BLI_duplicatelist(&outPose->chanbase, &src->chanbase);
-
+
+ /* Rebuild ghash here too, so that name lookups below won't be too bad...
+ * BUT this will have the penalty that the ghash will be built twice
+ * if BKE_pose_rebuild() gets called after this...
+ */
+ if (outPose->chanbase.first != outPose->chanbase.last) {
+ outPose->chanhash = NULL;
+ BKE_pose_channels_hash_make(outPose);
+ }
+
outPose->iksolver = src->iksolver;
outPose->ikdata = NULL;
outPose->ikparam = MEM_dupallocN(src->ikparam);
@@ -608,10 +557,16 @@ void BKE_pose_copy_data(bPose **dst, bPose *src, const bool copy_constraints)
id_us_plus(&pchan->custom->id);
}
- /* warning, O(n2) here, but it's a rarely used feature. */
+ /* warning, O(n2) here, if done without the hash, but these are rarely used features. */
if (pchan->custom_tx) {
pchan->custom_tx = BKE_pose_channel_find_name(outPose, pchan->custom_tx->name);
}
+ if (pchan->bbone_prev) {
+ pchan->bbone_prev = BKE_pose_channel_find_name(outPose, pchan->bbone_prev->name);
+ }
+ if (pchan->bbone_next) {
+ pchan->bbone_next = BKE_pose_channel_find_name(outPose, pchan->bbone_next->name);
+ }
if (copy_constraints) {
BKE_constraints_copy(&listb, &pchan->constraints, true); // BKE_constraints_copy NULLs listb
@@ -726,7 +681,7 @@ void BKE_pose_channels_remove(
Object *ob,
bool (*filter_fn)(const char *bone_name, void *user_data), void *user_data)
{
- /* First erase any associated pose channel */
+ /* Erase any associated pose channel, along with any references to them */
if (ob->pose) {
bPoseChannel *pchan, *pchan_next;
bConstraint *con;
@@ -735,6 +690,7 @@ void BKE_pose_channels_remove(
pchan_next = pchan->next;
if (filter_fn(pchan->name, user_data)) {
+ /* Bone itself is being removed */
BKE_pose_channel_free(pchan);
if (ob->pose->chanhash) {
BLI_ghash_remove(ob->pose->chanhash, pchan->name, NULL, NULL);
@@ -742,6 +698,7 @@ void BKE_pose_channels_remove(
BLI_freelinkN(&ob->pose->chanbase, pchan);
}
else {
+ /* Maybe something the bone references is being removed instead? */
for (con = pchan->constraints.first; con; con = con->next) {
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
@@ -765,6 +722,20 @@ void BKE_pose_channels_remove(
cti->flush_constraint_targets(con, &targets, 0);
}
}
+
+ if (pchan->bbone_prev) {
+ if (filter_fn(pchan->bbone_prev->name, user_data))
+ pchan->bbone_prev = NULL;
+ }
+ if (pchan->bbone_next) {
+ if (filter_fn(pchan->bbone_next->name, user_data))
+ pchan->bbone_next = NULL;
+ }
+
+ if (pchan->custom_tx) {
+ if (filter_fn(pchan->custom_tx->name, user_data))
+ pchan->custom_tx = NULL;
+ }
}
}
}
@@ -878,6 +849,15 @@ static void copy_pose_channel_data(bPoseChannel *pchan, const bPoseChannel *chan
copy_m4_m4(pchan->pose_mat, (float(*)[4])chan->pose_mat);
pchan->flag = chan->flag;
+ pchan->roll1 = chan->roll1;
+ pchan->roll2 = chan->roll2;
+ pchan->curveInX = chan->curveInX;
+ pchan->curveInY = chan->curveInY;
+ pchan->curveOutX = chan->curveOutX;
+ pchan->curveOutY = chan->curveOutY;
+ pchan->scaleIn = chan->scaleIn;
+ pchan->scaleOut = chan->scaleOut;
+
con = chan->constraints.first;
for (pcon = pchan->constraints.first; pcon && con; pcon = pcon->next, con = con->next) {
pcon->enforce = con->enforce;
@@ -888,7 +868,7 @@ static void copy_pose_channel_data(bPoseChannel *pchan, const bPoseChannel *chan
/**
* Copy the internal members of each pose channel including constraints
* and ID-Props, used when duplicating bones in editmode.
- * (unlike copy_pose_channel_data which only).
+ * (unlike copy_pose_channel_data which only does posing-related stuff).
*
* \note use when copying bones in editmode (on returned value from #BKE_pose_channel_verify)
*/
@@ -911,6 +891,11 @@ void BKE_pose_channel_copy_data(bPoseChannel *pchan, const bPoseChannel *pchan_f
pchan->ikstretch = pchan_from->ikstretch;
pchan->ikrotweight = pchan_from->ikrotweight;
pchan->iklinweight = pchan_from->iklinweight;
+
+ /* bbone settings (typically not animated) */
+ pchan->bboneflag = pchan_from->bboneflag;
+ pchan->bbone_next = pchan_from->bbone_next;
+ pchan->bbone_prev = pchan_from->bbone_prev;
/* constraints */
BKE_constraints_copy(&pchan->constraints, &pchan_from->constraints, true);
@@ -1280,6 +1265,18 @@ short action_get_item_transforms(bAction *act, Object *ob, bPoseChannel *pchan,
}
}
+ if ((curves) || (flags & ACT_TRANS_BBONE) == 0) {
+ /* bbone shape properties */
+ pPtr = strstr(bPtr, "bbone_");
+ if (pPtr) {
+ flags |= ACT_TRANS_BBONE;
+
+ if (curves)
+ BLI_addtail(curves, BLI_genericNodeN(fcu));
+ continue;
+ }
+ }
+
if ((curves) || (flags & ACT_TRANS_PROP) == 0) {
/* custom properties only */
pPtr = strstr(bPtr, "[\""); /* extra '"' comment here to keep my texteditor functionlist working :) */
@@ -1339,8 +1336,13 @@ void BKE_pose_rest(bPose *pose)
unit_qt(pchan->quat);
unit_axis_angle(pchan->rotAxis, &pchan->rotAngle);
pchan->size[0] = pchan->size[1] = pchan->size[2] = 1.0f;
-
- pchan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE);
+
+ pchan->roll1 = pchan->roll2 = 0.0f;
+ pchan->curveInX = pchan->curveInY = 0.0f;
+ pchan->curveOutX = pchan->curveOutY = 0.0f;
+ pchan->scaleIn = pchan->scaleOut = 1.0f;
+
+ pchan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE | POSE_BBONE_SHAPE);
}
}
@@ -1375,9 +1377,19 @@ bool BKE_pose_copy_result(bPose *to, bPose *from)
copy_v3_v3(pchanto->pose_head, pchanfrom->pose_head);
copy_v3_v3(pchanto->pose_tail, pchanfrom->pose_tail);
+ pchanto->roll1 = pchanfrom->roll1;
+ pchanto->roll2 = pchanfrom->roll2;
+ pchanto->curveInX = pchanfrom->curveInX;
+ pchanto->curveInY = pchanfrom->curveInY;
+ pchanto->curveOutX = pchanfrom->curveOutX;
+ pchanto->curveOutY = pchanfrom->curveOutY;
+ pchanto->scaleIn = pchanfrom->scaleIn;
+ pchanto->scaleOut = pchanfrom->scaleOut;
+
pchanto->rotmode = pchanfrom->rotmode;
pchanto->flag = pchanfrom->flag;
pchanto->protectflag = pchanfrom->protectflag;
+ pchanto->bboneflag = pchanfrom->bboneflag;
}
}
return true;
diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c
index dff696863e9..7d3d12ac112 100644
--- a/source/blender/blenkernel/intern/anim.c
+++ b/source/blender/blenkernel/intern/anim.c
@@ -340,11 +340,11 @@ static void motionpaths_calc_update_scene(Scene *scene)
}
}
#else // original, 'always correct' version
- /* do all updates
- * - if this is too slow, resort to using a more efficient way
- * that doesn't force complete update, but for now, this is the
- * most accurate way!
- */
+ /* do all updates
+ * - if this is too slow, resort to using a more efficient way
+ * that doesn't force complete update, but for now, this is the
+ * most accurate way!
+ */
BKE_scene_update_for_newframe(G.main->eval_ctx, G.main, scene, scene->lay); /* XXX this is the best way we can get anything moving */
#endif
}
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 41950c59a22..e3764adb969 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -79,15 +79,11 @@
/* Getter/Setter -------------------------------------------- */
/* Check if ID can have AnimData */
-bool id_type_can_have_animdata(ID *id)
+bool id_type_can_have_animdata(const short id_type)
{
- /* sanity check */
- if (id == NULL)
- return false;
-
/* Only some ID-blocks have this info for now */
/* TODO: finish adding this for the other blocktypes */
- switch (GS(id->name)) {
+ switch (id_type) {
/* has AnimData */
case ID_OB:
case ID_ME: case ID_MB: case ID_CU: case ID_AR: case ID_LT:
@@ -101,9 +97,8 @@ bool id_type_can_have_animdata(ID *id)
case ID_MC:
case ID_MSK:
case ID_GD:
- {
+ case ID_CF:
return true;
- }
/* no AnimData */
default:
@@ -111,6 +106,14 @@ bool id_type_can_have_animdata(ID *id)
}
}
+bool id_can_have_animdata(const ID *id)
+{
+ /* sanity check */
+ if (id == NULL)
+ return false;
+
+ return id_type_can_have_animdata(GS(id->name));
+}
/* Get AnimData from the given ID-block. In order for this to work, we assume that
* the AnimData pointer is stored immediately after the given ID-block in the struct,
@@ -122,7 +125,7 @@ AnimData *BKE_animdata_from_id(ID *id)
* types that do to be of type IdAdtTemplate, and extract the
* AnimData that way
*/
- if (id_type_can_have_animdata(id)) {
+ if (id_can_have_animdata(id)) {
IdAdtTemplate *iat = (IdAdtTemplate *)id;
return iat->adt;
}
@@ -140,7 +143,7 @@ AnimData *BKE_animdata_add_id(ID *id)
* types that do to be of type IdAdtTemplate, and add the AnimData
* to it using the template
*/
- if (id_type_can_have_animdata(id)) {
+ if (id_can_have_animdata(id)) {
IdAdtTemplate *iat = (IdAdtTemplate *)id;
/* check if there's already AnimData, in which case, don't add */
@@ -216,23 +219,25 @@ bool BKE_animdata_set_action(ReportList *reports, ID *id, bAction *act)
/* Freeing -------------------------------------------- */
/* Free AnimData used by the nominated ID-block, and clear ID-block's AnimData pointer */
-void BKE_animdata_free(ID *id)
+void BKE_animdata_free(ID *id, const bool do_id_user)
{
/* Only some ID-blocks have this info for now, so we cast the
* types that do to be of type IdAdtTemplate
*/
- if (id_type_can_have_animdata(id)) {
+ if (id_can_have_animdata(id)) {
IdAdtTemplate *iat = (IdAdtTemplate *)id;
AnimData *adt = iat->adt;
/* check if there's any AnimData to start with */
if (adt) {
- /* unlink action (don't free, as it's in its own list) */
- if (adt->action)
- id_us_min(&adt->action->id);
- /* same goes for the temporarily displaced action */
- if (adt->tmpact)
- id_us_min(&adt->tmpact->id);
+ if (do_id_user) {
+ /* unlink action (don't free, as it's in its own list) */
+ if (adt->action)
+ id_us_min(&adt->action->id);
+ /* same goes for the temporarily displaced action */
+ if (adt->tmpact)
+ id_us_min(&adt->tmpact->id);
+ }
/* free nla data */
free_nladata(&adt->nla_tracks);
@@ -264,8 +269,8 @@ AnimData *BKE_animdata_copy(AnimData *adt, const bool do_action)
/* make a copy of action - at worst, user has to delete copies... */
if (do_action) {
- dadt->action = BKE_action_copy(adt->action);
- dadt->tmpact = BKE_action_copy(adt->tmpact);
+ dadt->action = BKE_action_copy(G.main, adt->action);
+ dadt->tmpact = BKE_action_copy(G.main, adt->tmpact);
}
else {
id_us_plus((ID *)dadt->action);
@@ -292,7 +297,7 @@ bool BKE_animdata_copy_id(ID *id_to, ID *id_from, const bool do_action)
if ((id_to && id_from) && (GS(id_to->name) != GS(id_from->name)))
return false;
- BKE_animdata_free(id_to);
+ BKE_animdata_free(id_to, true);
adt = BKE_animdata_from_id(id_from);
if (adt) {
@@ -309,11 +314,11 @@ void BKE_animdata_copy_id_action(ID *id)
if (adt) {
if (adt->action) {
id_us_min((ID *)adt->action);
- adt->action = BKE_action_copy(adt->action);
+ adt->action = BKE_action_copy(G.main, adt->action);
}
if (adt->tmpact) {
id_us_min((ID *)adt->tmpact);
- adt->tmpact = BKE_action_copy(adt->tmpact);
+ adt->tmpact = BKE_action_copy(G.main, adt->tmpact);
}
}
}
@@ -337,8 +342,8 @@ void BKE_animdata_merge_copy(ID *dst_id, ID *src_id, eAnimData_MergeCopy_Modes a
/* handle actions... */
if (action_mode == ADT_MERGECOPY_SRC_COPY) {
/* make a copy of the actions */
- dst->action = BKE_action_copy(src->action);
- dst->tmpact = BKE_action_copy(src->tmpact);
+ dst->action = BKE_action_copy(G.main, src->action);
+ dst->tmpact = BKE_action_copy(G.main, src->tmpact);
}
else if (action_mode == ADT_MERGECOPY_SRC_REF) {
/* make a reference to it */
@@ -396,8 +401,8 @@ static void make_local_strips(ListBase *strips)
NlaStrip *strip;
for (strip = strips->first; strip; strip = strip->next) {
- if (strip->act) BKE_action_make_local(strip->act);
- if (strip->remap && strip->remap->target) BKE_action_make_local(strip->remap->target);
+ if (strip->act) BKE_action_make_local(G.main, strip->act, false);
+ if (strip->remap && strip->remap->target) BKE_action_make_local(G.main, strip->remap->target, false);
make_local_strips(&strip->strips);
}
@@ -409,10 +414,10 @@ void BKE_animdata_make_local(AnimData *adt)
NlaTrack *nlt;
/* Actions - Active and Temp */
- if (adt->action) BKE_action_make_local(adt->action);
- if (adt->tmpact) BKE_action_make_local(adt->tmpact);
+ if (adt->action) BKE_action_make_local(G.main, adt->action, false);
+ if (adt->tmpact) BKE_action_make_local(G.main, adt->tmpact, false);
/* Remaps */
- if (adt->remap && adt->remap->target) BKE_action_make_local(adt->remap->target);
+ if (adt->remap && adt->remap->target) BKE_action_make_local(G.main, adt->remap->target, false);
/* Drivers */
/* TODO: need to remap the ID-targets too? */
@@ -730,14 +735,10 @@ static char *rna_path_rename_fix(ID *owner_id, const char *prefix, const char *o
DynStr *ds = BLI_dynstr_new();
const char *postfixPtr = oldNamePtr + oldNameLen;
char *newPath = NULL;
- char oldChar;
-
+
/* add the part of the string that goes up to the start of the prefix */
if (prefixPtr > oldpath) {
- oldChar = prefixPtr[0];
- prefixPtr[0] = 0;
- BLI_dynstr_append(ds, oldpath);
- prefixPtr[0] = oldChar;
+ BLI_dynstr_nappend(ds, oldpath, prefixPtr - oldpath);
}
/* add the prefix */
@@ -1051,7 +1052,7 @@ void BKE_animdata_fix_paths_remove(ID *id, const char *prefix)
*/
NlaTrack *nlt;
- if (id_type_can_have_animdata(id)) {
+ if (id_can_have_animdata(id)) {
IdAdtTemplate *iat = (IdAdtTemplate *)id;
AnimData *adt = iat->adt;
@@ -1160,6 +1161,9 @@ void BKE_animdata_main_cb(Main *mainptr, ID_AnimData_Edit_Callback func, void *u
/* grease pencil */
ANIMDATA_IDS_CB(mainptr->gpencil.first);
+
+ /* cache files */
+ ANIMDATA_IDS_CB(mainptr->cachefiles.first);
}
/* Fix all RNA-Paths throughout the database (directly access the Global.main version)
@@ -1250,6 +1254,9 @@ void BKE_animdata_fix_paths_rename_all(ID *ref_id, const char *prefix, const cha
/* grease pencil */
RENAMEFIX_ANIM_IDS(mainptr->gpencil.first);
+
+ /* cache files */
+ RENAMEFIX_ANIM_IDS(mainptr->cachefiles.first);
/* scenes */
RENAMEFIX_ANIM_NODETREE_IDS(mainptr->scene.first, Scene);
@@ -1482,161 +1489,193 @@ static bool animsys_remap_path(AnimMapper *UNUSED(remap), char *path, char **dst
return false;
}
+static bool animsys_store_rna_setting(
+ PointerRNA *ptr, AnimMapper *remap,
+ /* typically 'fcu->rna_path', 'fcu->array_index' */
+ const char *rna_path, const int array_index,
+ PathResolvedRNA *r_result)
+{
+ bool success = false;
+
+ char *path = NULL;
+ bool free_path;
+
+ /* get path, remapped as appropriate to work in its new environment */
+ free_path = animsys_remap_path(remap, (char *)rna_path, &path);
+
+ /* write value to setting */
+ if (path) {
+ /* get property to write to */
+ if (RNA_path_resolve_property(ptr, path, &r_result->ptr, &r_result->prop)) {
+ if ((ptr->id.data == NULL) || RNA_property_animateable(&r_result->ptr, r_result->prop)) {
+ int array_len = RNA_property_array_length(&r_result->ptr, r_result->prop);
+
+ if (array_len && array_index >= array_len) {
+ if (G.debug & G_DEBUG) {
+ printf("Animato: Invalid array index. ID = '%s', '%s[%d]', array length is %d\n",
+ (ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>",
+ path, array_index, array_len - 1);
+ }
+ }
+ else {
+ r_result->prop_index = array_len ? array_index : -1;
+ success = true;
+ }
+ }
+ }
+ else {
+ /* failed to get path */
+ /* XXX don't tag as failed yet though, as there are some legit situations (Action Constraint)
+ * where some channels will not exist, but shouldn't lock up Action */
+ if (G.debug & G_DEBUG) {
+ printf("Animato: Invalid path. ID = '%s', '%s[%d]'\n",
+ (ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>",
+ path, array_index);
+ }
+ }
+ }
+
+ /* free temp path-info */
+ if (free_path) {
+ MEM_freeN((void *)path);
+ }
+
+ return success;
+}
+
/* less than 1.0 evaluates to false, use epsilon to avoid float error */
#define ANIMSYS_FLOAT_AS_BOOL(value) ((value) > ((1.0f - FLT_EPSILON)))
/* Write the given value to a setting using RNA, and return success */
-static bool animsys_write_rna_setting(PointerRNA *ptr, char *path, int array_index, float value)
+static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float value)
{
- PropertyRNA *prop;
- PointerRNA new_ptr;
-
- //printf("%p %s %i %f\n", ptr, path, array_index, value);
+ PropertyRNA *prop = anim_rna->prop;
+ PointerRNA *ptr = &anim_rna->ptr;
+ int array_index = anim_rna->prop_index;
- /* get property to write to */
- if (RNA_path_resolve_property(ptr, path, &new_ptr, &prop)) {
- /* set value for animatable numerical values only
- * HACK: some local F-Curves (e.g. those on NLA Strips) are evaluated
- * without an ID provided, which causes the animateable test to fail!
- */
- if (RNA_property_animateable(&new_ptr, prop) || (ptr->id.data == NULL)) {
- int array_len = RNA_property_array_length(&new_ptr, prop);
- bool written = false;
-
- if (array_len && array_index >= array_len) {
- if (G.debug & G_DEBUG) {
- printf("Animato: Invalid array index. ID = '%s', '%s[%d]', array length is %d\n",
- (ptr && ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>",
- path, array_index, array_len - 1);
+ /* caller must ensure this is animatable */
+ BLI_assert(RNA_property_animateable(ptr, prop) || ptr->id.data == NULL);
+
+ /* set value for animatable numerical values only
+ * HACK: some local F-Curves (e.g. those on NLA Strips) are evaluated
+ * without an ID provided, which causes the animateable test to fail!
+ */
+ bool written = false;
+
+ switch (RNA_property_type(prop)) {
+ case PROP_BOOLEAN:
+ {
+ const int value_coerce = ANIMSYS_FLOAT_AS_BOOL(value);
+ if (array_index != -1) {
+ if (RNA_property_boolean_get_index(ptr, prop, array_index) != value_coerce) {
+ RNA_property_boolean_set_index(ptr, prop, array_index, value_coerce);
+ written = true;
}
-
- return false;
}
-
- switch (RNA_property_type(prop)) {
- case PROP_BOOLEAN:
- if (array_len) {
- if (RNA_property_boolean_get_index(&new_ptr, prop, array_index) != ANIMSYS_FLOAT_AS_BOOL(value)) {
- RNA_property_boolean_set_index(&new_ptr, prop, array_index, ANIMSYS_FLOAT_AS_BOOL(value));
- written = true;
- }
- }
- else {
- if (RNA_property_boolean_get(&new_ptr, prop) != ANIMSYS_FLOAT_AS_BOOL(value)) {
- RNA_property_boolean_set(&new_ptr, prop, ANIMSYS_FLOAT_AS_BOOL(value));
- written = true;
- }
- }
- break;
- case PROP_INT:
- if (array_len) {
- if (RNA_property_int_get_index(&new_ptr, prop, array_index) != (int)value) {
- RNA_property_int_set_index(&new_ptr, prop, array_index, (int)value);
- written = true;
- }
- }
- else {
- if (RNA_property_int_get(&new_ptr, prop) != (int)value) {
- RNA_property_int_set(&new_ptr, prop, (int)value);
- written = true;
- }
- }
- break;
- case PROP_FLOAT:
- if (array_len) {
- if (RNA_property_float_get_index(&new_ptr, prop, array_index) != value) {
- RNA_property_float_set_index(&new_ptr, prop, array_index, value);
- written = true;
- }
- }
- else {
- if (RNA_property_float_get(&new_ptr, prop) != value) {
- RNA_property_float_set(&new_ptr, prop, value);
- written = true;
- }
- }
- break;
- case PROP_ENUM:
- if (RNA_property_enum_get(&new_ptr, prop) != (int)value) {
- RNA_property_enum_set(&new_ptr, prop, (int)value);
- written = true;
- }
- break;
- default:
- /* nothing can be done here... so it is unsuccessful? */
- return false;
+ else {
+ if (RNA_property_boolean_get(ptr, prop) != value_coerce) {
+ RNA_property_boolean_set(ptr, prop, value_coerce);
+ written = true;
+ }
}
-
- /* RNA property update disabled for now - [#28525] [#28690] [#28774] [#28777] */
-#if 0
- /* buffer property update for later flushing */
- if (written && RNA_property_update_check(prop)) {
- short skip_updates_hack = 0;
-
- /* optimization hacks: skip property updates for those properties
- * for we know that which the updates in RNA were really just for
- * flushing property editing via UI/Py
- */
- if (new_ptr.type == &RNA_PoseBone) {
- /* bone transforms - update pose (i.e. tag depsgraph) */
- skip_updates_hack = 1;
+ break;
+ }
+ case PROP_INT:
+ {
+ const int value_coerce = (int)value;
+ if (array_index != -1) {
+ if (RNA_property_int_get_index(ptr, prop, array_index) != value_coerce) {
+ RNA_property_int_set_index(ptr, prop, array_index, value_coerce);
+ written = true;
}
-
- if (skip_updates_hack == 0)
- RNA_property_update_cache_add(&new_ptr, prop);
}
-#endif
-
- /* as long as we don't do property update, we still tag datablock
- * as having been updated. this flag does not cause any updates to
- * be run, it's for e.g. render engines to synchronize data */
- if (written && new_ptr.id.data) {
- ID *id = new_ptr.id.data;
-
- /* for cases like duplifarmes it's only a temporary so don't
- * notify anyone of updates */
- if (!(id->tag & LIB_TAG_ANIM_NO_RECALC)) {
- id->tag |= LIB_TAG_ID_RECALC;
- DAG_id_type_tag(G.main, GS(id->name));
+ else {
+ if (RNA_property_int_get(ptr, prop) != value_coerce) {
+ RNA_property_int_set(ptr, prop, value_coerce);
+ written = true;
}
}
+ break;
}
-
- /* successful */
- return true;
+ case PROP_FLOAT:
+ {
+ if (array_index != -1) {
+ if (RNA_property_float_get_index(ptr, prop, array_index) != value) {
+ RNA_property_float_set_index(ptr, prop, array_index, value);
+ written = true;
+ }
+ }
+ else {
+ if (RNA_property_float_get(ptr, prop) != value) {
+ RNA_property_float_set(ptr, prop, value);
+ written = true;
+ }
+ }
+ break;
+ }
+ case PROP_ENUM:
+ {
+ const int value_coerce = (int)value;
+ if (RNA_property_enum_get(ptr, prop) != value_coerce) {
+ RNA_property_enum_set(ptr, prop, value_coerce);
+ written = true;
+ }
+ break;
+ }
+ default:
+ /* nothing can be done here... so it is unsuccessful? */
+ return false;
}
- else {
- /* failed to get path */
- /* XXX don't tag as failed yet though, as there are some legit situations (Action Constraint)
- * where some channels will not exist, but shouldn't lock up Action */
- if (G.debug & G_DEBUG) {
- printf("Animato: Invalid path. ID = '%s', '%s[%d]'\n",
- (ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>",
- path, array_index);
+
+ /* RNA property update disabled for now - [#28525] [#28690] [#28774] [#28777] */
+#if 0
+ /* buffer property update for later flushing */
+ if (written && RNA_property_update_check(prop)) {
+ short skip_updates_hack = 0;
+
+ /* optimization hacks: skip property updates for those properties
+ * for we know that which the updates in RNA were really just for
+ * flushing property editing via UI/Py
+ */
+ if (new_ptr.type == &RNA_PoseBone) {
+ /* bone transforms - update pose (i.e. tag depsgraph) */
+ skip_updates_hack = 1;
+ }
+
+ if (skip_updates_hack == 0)
+ RNA_property_update_cache_add(ptr, prop);
+ }
+#endif
+
+ /* as long as we don't do property update, we still tag datablock
+ * as having been updated. this flag does not cause any updates to
+ * be run, it's for e.g. render engines to synchronize data */
+ if (written && ptr->id.data) {
+ ID *id = ptr->id.data;
+
+ /* for cases like duplifarmes it's only a temporary so don't
+ * notify anyone of updates */
+ if (!(id->tag & LIB_TAG_ANIM_NO_RECALC)) {
+ id->tag |= LIB_TAG_ID_RECALC;
+ DAG_id_type_tag(G.main, GS(id->name));
}
- return false;
}
+
+ /* successful */
+ return true;
}
/* Simple replacement based data-setting of the FCurve using RNA */
-bool BKE_animsys_execute_fcurve(PointerRNA *ptr, AnimMapper *remap, FCurve *fcu)
+bool BKE_animsys_execute_fcurve(PointerRNA *ptr, AnimMapper *remap, FCurve *fcu, float curval)
{
- char *path = NULL;
- bool free_path = false;
+ PathResolvedRNA anim_rna;
bool ok = false;
-
- /* get path, remapped as appropriate to work in its new environment */
- free_path = animsys_remap_path(remap, fcu->rna_path, &path);
-
- /* write value to setting */
- if (path)
- ok = animsys_write_rna_setting(ptr, path, fcu->array_index, fcu->curval);
-
- /* free temp path-info */
- if (free_path)
- MEM_freeN(path);
-
+
+ if (animsys_store_rna_setting(ptr, remap, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ ok = animsys_write_rna_setting(&anim_rna, curval);
+ }
+
/* return whether we were successful */
return ok;
}
@@ -1654,8 +1693,11 @@ static void animsys_evaluate_fcurves(PointerRNA *ptr, ListBase *list, AnimMapper
if ((fcu->grp == NULL) || (fcu->grp->flag & AGRP_MUTED) == 0) {
/* check if this curve should be skipped */
if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) {
- calculate_fcurve(fcu, ctime);
- BKE_animsys_execute_fcurve(ptr, remap, fcu);
+ PathResolvedRNA anim_rna;
+ if (animsys_store_rna_setting(ptr, remap, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
+ animsys_write_rna_setting(&anim_rna, curval);
+ }
}
}
}
@@ -1684,8 +1726,12 @@ static void animsys_evaluate_drivers(PointerRNA *ptr, AnimData *adt, float ctime
/* evaluate this using values set already in other places
* NOTE: for 'layering' option later on, we should check if we should remove old value before adding
* new to only be done when drivers only changed */
- calculate_fcurve(fcu, ctime);
- ok = BKE_animsys_execute_fcurve(ptr, NULL, fcu);
+
+ PathResolvedRNA anim_rna;
+ if (animsys_store_rna_setting(ptr, NULL, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
+ ok = animsys_write_rna_setting(&anim_rna, curval);
+ }
/* clear recalc flag */
driver->flag &= ~DRIVER_FLAG_RECALC;
@@ -1753,8 +1799,11 @@ void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup *
for (fcu = agrp->channels.first; (fcu) && (fcu->grp == agrp); fcu = fcu->next) {
/* check if this curve should be skipped */
if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) {
- calculate_fcurve(fcu, ctime);
- BKE_animsys_execute_fcurve(ptr, remap, fcu);
+ PathResolvedRNA anim_rna;
+ if (animsys_store_rna_setting(ptr, remap, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
+ animsys_write_rna_setting(&anim_rna, curval);
+ }
}
}
}
@@ -2612,8 +2661,12 @@ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt)
AnimOverride *aor;
/* for each override, simply execute... */
- for (aor = adt->overrides.first; aor; aor = aor->next)
- animsys_write_rna_setting(ptr, aor->rna_path, aor->array_index, aor->value);
+ for (aor = adt->overrides.first; aor; aor = aor->next) {
+ PathResolvedRNA anim_rna;
+ if (animsys_store_rna_setting(ptr, NULL, aor->rna_path, aor->array_index, &anim_rna)) {
+ animsys_write_rna_setting(&anim_rna, aor->value);
+ }
+ }
}
/* ***************************************** */
@@ -2827,6 +2880,9 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime)
/* grease pencil */
EVAL_ANIM_IDS(main->gpencil.first, ADT_RECALC_ANIM);
+
+ /* cache files */
+ EVAL_ANIM_IDS(main->cachefiles.first, ADT_RECALC_ANIM);
/* objects */
/* ADT_RECALC_ANIM doesn't need to be supplied here, since object AnimData gets
@@ -2888,8 +2944,13 @@ void BKE_animsys_eval_driver(EvaluationContext *eval_ctx,
* NOTE: for 'layering' option later on, we should check if we should remove old value before adding
* new to only be done when drivers only changed */
//printf("\told val = %f\n", fcu->curval);
- calculate_fcurve(fcu, eval_ctx->ctime);
- ok = BKE_animsys_execute_fcurve(&id_ptr, NULL, fcu);
+
+ PathResolvedRNA anim_rna;
+ if (animsys_store_rna_setting(&id_ptr, NULL, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ const float curval = calculate_fcurve(&anim_rna, fcu, eval_ctx->ctime);
+ ok = animsys_write_rna_setting(&anim_rna, curval);
+ }
+
//printf("\tnew val = %f\n", fcu->curval);
/* clear recalc flag */
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 564c670fb3a..c644fe09364 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -41,6 +41,7 @@
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_ghash.h"
+#include "BLI_task.h"
#include "BLI_utildefines.h"
#include "DNA_anim_types.h"
@@ -48,6 +49,7 @@
#include "DNA_constraint_types.h"
#include "DNA_mesh_types.h"
#include "DNA_lattice_types.h"
+#include "DNA_listBase.h"
#include "DNA_meshdata_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
@@ -65,6 +67,8 @@
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_lattice.h"
#include "BKE_main.h"
#include "BKE_object.h"
@@ -118,75 +122,31 @@ void BKE_armature_bonelist_free(ListBase *lb)
BLI_freelistN(lb);
}
+/** Free (or release) any data used by this armature (does not free the armature itself). */
void BKE_armature_free(bArmature *arm)
{
- if (arm) {
- BKE_armature_bonelist_free(&arm->bonebase);
+ BKE_animdata_free(&arm->id, false);
- /* free editmode data */
- if (arm->edbo) {
- BLI_freelistN(arm->edbo);
+ BKE_armature_bonelist_free(&arm->bonebase);
- MEM_freeN(arm->edbo);
- arm->edbo = NULL;
- }
+ /* free editmode data */
+ if (arm->edbo) {
+ BLI_freelistN(arm->edbo);
- /* free sketch */
- if (arm->sketch) {
- freeSketch(arm->sketch);
- arm->sketch = NULL;
- }
+ MEM_freeN(arm->edbo);
+ arm->edbo = NULL;
+ }
- /* free animation data */
- if (arm->adt) {
- BKE_animdata_free(&arm->id);
- arm->adt = NULL;
- }
+ /* free sketch */
+ if (arm->sketch) {
+ freeSketch(arm->sketch);
+ arm->sketch = NULL;
}
}
-void BKE_armature_make_local(bArmature *arm)
+void BKE_armature_make_local(Main *bmain, bArmature *arm, const bool lib_local)
{
- Main *bmain = G.main;
- bool is_local = false, is_lib = false;
- Object *ob;
-
- if (arm->id.lib == NULL)
- return;
- if (arm->id.us == 1) {
- id_clear_lib_data(bmain, &arm->id);
- return;
- }
-
- for (ob = bmain->object.first; ob && ELEM(0, is_lib, is_local); ob = ob->id.next) {
- if (ob->data == arm) {
- if (ob->id.lib)
- is_lib = true;
- else
- is_local = true;
- }
- }
-
- if (is_local && is_lib == false) {
- id_clear_lib_data(bmain, &arm->id);
- }
- else if (is_local && is_lib) {
- bArmature *arm_new = BKE_armature_copy(arm);
- arm_new->id.us = 0;
-
- /* Remap paths of new ID using old library as base. */
- BKE_id_lib_local_paths(bmain, arm->id.lib, &arm_new->id);
-
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- if (ob->data == arm) {
- if (ob->id.lib == NULL) {
- ob->data = arm_new;
- id_us_plus(&arm_new->id);
- id_us_min(&arm->id);
- }
- }
- }
- }
+ BKE_id_make_local_generic(bmain, &arm->id, true, lib_local);
}
static void copy_bonechildren(Bone *newBone, Bone *oldBone, Bone *actBone, Bone **newActBone)
@@ -211,13 +171,13 @@ static void copy_bonechildren(Bone *newBone, Bone *oldBone, Bone *actBone, Bone
}
}
-bArmature *BKE_armature_copy(bArmature *arm)
+bArmature *BKE_armature_copy(Main *bmain, bArmature *arm)
{
bArmature *newArm;
Bone *oldBone, *newBone;
Bone *newActBone = NULL;
- newArm = BKE_libblock_copy(&arm->id);
+ newArm = BKE_libblock_copy(bmain, &arm->id);
BLI_duplicatelist(&newArm->bonebase, &arm->bonebase);
/* Duplicate the childrens' lists */
@@ -234,9 +194,7 @@ bArmature *BKE_armature_copy(bArmature *arm)
newArm->act_edbone = NULL;
newArm->sketch = NULL;
- if (arm->id.lib) {
- BKE_id_lib_local_paths(G.main, arm->id.lib, &newArm->id);
- }
+ BKE_id_copy_ensure_local(bmain, &arm->id, &newArm->id);
return newArm;
}
@@ -427,7 +385,7 @@ int bone_autoside_name(char name[MAXBONENAME], int UNUSED(strip_number), short a
/* ************* B-Bone support ******************* */
/* data has MAX_BBONE_SUBDIV+1 interpolated points, will become desired amount with equal distances */
-static void equalize_bezier(float *data, int desired)
+void equalize_bbone_bezier(float *data, int desired)
{
float *fp, totdist, ddist, dist, fac1, fac2;
float pdist[MAX_BBONE_SUBDIV + 1];
@@ -473,7 +431,7 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
{
bPoseChannel *next, *prev;
Bone *bone = pchan->bone;
- float h1[3], h2[3], scale[3], length, hlength1, hlength2, roll1 = 0.0f, roll2;
+ float h1[3], h2[3], scale[3], length, roll1 = 0.0f, roll2;
float mat3[3][3], imat[4][4], posemat[4][4], scalemat[4][4], iscalemat[4][4];
float data[MAX_BBONE_SUBDIV + 1][4], *fp;
int a;
@@ -494,16 +452,21 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
}
}
- hlength1 = bone->ease1 * length * 0.390464f; /* 0.5f * sqrt(2) * kappa, the handle length for near-perfect circles */
- hlength2 = bone->ease2 * length * 0.390464f;
-
- /* evaluate next and prev bones */
- if (bone->flag & BONE_CONNECTED)
- prev = pchan->parent;
- else
- prev = NULL;
+ /* get "next" and "prev" bones - these are used for handle calculations */
+ if (pchan->bboneflag & PCHAN_BBONE_CUSTOM_HANDLES) {
+ /* use the provided bones as the next/prev - leave blank to eliminate this effect altogether */
+ prev = pchan->bbone_prev;
+ next = pchan->bbone_next;
+ }
+ else {
+ /* evaluate next and prev bones */
+ if (bone->flag & BONE_CONNECTED)
+ prev = pchan->parent;
+ else
+ prev = NULL;
- next = pchan->child;
+ next = pchan->child;
+ }
/* find the handle points, since this is inside bone space, the
* first point = (0, 0, 0)
@@ -523,10 +486,27 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
float difmat[4][4], result[3][3], imat3[3][3];
/* transform previous point inside this bone space */
- if (rest)
- copy_v3_v3(h1, prev->bone->arm_head);
- else
- copy_v3_v3(h1, prev->pose_head);
+ if ((pchan->bboneflag & PCHAN_BBONE_CUSTOM_HANDLES) &&
+ (pchan->bboneflag & PCHAN_BBONE_CUSTOM_START_REL))
+ {
+ /* Use delta movement (from restpose), and apply this relative to the current bone's head */
+ if (rest) {
+ /* in restpose, arm_head == pose_head */
+ h1[0] = h1[1] = h1[2] = 0.0f;
+ }
+ else {
+ float delta[3];
+ sub_v3_v3v3(delta, prev->pose_head, prev->bone->arm_head);
+ sub_v3_v3v3(h1, pchan->pose_head, delta);
+ }
+ }
+ else {
+ /* Use bone head as absolute position */
+ if (rest)
+ copy_v3_v3(h1, prev->bone->arm_head);
+ else
+ copy_v3_v3(h1, prev->pose_head);
+ }
mul_m4_v3(imat, h1);
if (prev->bone->segments > 1) {
@@ -536,7 +516,7 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
}
normalize_v3(h1);
- mul_v3_fl(h1, -hlength1);
+ negate_v3(h1);
if (prev->bone->segments == 1) {
/* find the previous roll to interpolate */
@@ -555,17 +535,34 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
}
}
else {
- h1[0] = 0.0f; h1[1] = hlength1; h1[2] = 0.0f;
+ h1[0] = 0.0f; h1[1] = 1.0; h1[2] = 0.0f;
roll1 = 0.0f;
}
if (next) {
float difmat[4][4], result[3][3], imat3[3][3];
/* transform next point inside this bone space */
- if (rest)
- copy_v3_v3(h2, next->bone->arm_tail);
- else
- copy_v3_v3(h2, next->pose_tail);
+ if ((pchan->bboneflag & PCHAN_BBONE_CUSTOM_HANDLES) &&
+ (pchan->bboneflag & PCHAN_BBONE_CUSTOM_END_REL))
+ {
+ /* Use delta movement (from restpose), and apply this relative to the current bone's tail */
+ if (rest) {
+ /* in restpose, arm_tail == pose_tail */
+ h2[0] = h2[1] = h2[2] = 0.0f;
+ }
+ else {
+ float delta[3];
+ sub_v3_v3v3(delta, next->pose_tail, next->bone->arm_tail);
+ add_v3_v3v3(h2, pchan->pose_tail, delta);
+ }
+ }
+ else {
+ /* Use bone tail as absolute position */
+ if (rest)
+ copy_v3_v3(h2, next->bone->arm_tail);
+ else
+ copy_v3_v3(h2, next->pose_tail);
+ }
mul_m4_v3(imat, h2);
/* if next bone is B-bone too, use average handle direction */
@@ -591,14 +588,67 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
roll2 = atan2f(mat3[2][0], mat3[2][2]);
- /* and only now negate handle */
- mul_v3_fl(h2, -hlength2);
}
else {
- h2[0] = 0.0f; h2[1] = -hlength2; h2[2] = 0.0f;
+ h2[0] = 0.0f; h2[1] = 1.0f; h2[2] = 0.0f;
roll2 = 0.0;
}
+ {
+ const float circle_factor = length * (cubic_tangent_factor_circle_v3(h1, h2) / 0.75f);
+
+ const float hlength1 = bone->ease1 * circle_factor;
+ const float hlength2 = bone->ease2 * circle_factor;
+
+ /* and only now negate h2 */
+ mul_v3_fl(h1, hlength1);
+ mul_v3_fl(h2, -hlength2);
+ }
+
+ /* Add effects from bbone properties over the top
+ * - These properties allow users to hand-animate the
+ * bone curve/shape, without having to resort to using
+ * extra bones
+ * - The "bone" level offsets are for defining the restpose
+ * shape of the bone (e.g. for curved eyebrows for example).
+ * -> In the viewport, it's needed to define what the rest pose
+ * looks like
+ * -> For "rest == 0", we also still need to have it present
+ * so that we can "cancel out" this restpose when it comes
+ * time to deform some geometry, it won't cause double transforms.
+ * - The "pchan" level offsets are the ones that animators actually
+ * end up animating
+ */
+ {
+ /* add extra rolls */
+ roll1 += bone->roll1 + (!rest ? pchan->roll1 : 0.0f);
+ roll2 += bone->roll2 + (!rest ? pchan->roll2 : 0.0f);
+
+ if (bone->flag & BONE_ADD_PARENT_END_ROLL) {
+ if (prev) {
+ if (prev->bone)
+ roll1 += prev->bone->roll2;
+
+ if (!rest)
+ roll1 += prev->roll2;
+ }
+ }
+
+ /* extra curve x / y */
+ /* NOTE: Scale correction factors here are to compensate for some random floating-point glitches
+ * when scaling up the bone or it's parent by a factor of approximately 8.15/6, which results
+ * in the bone length getting scaled up too (from 1 to 8), causing the curve to flatten out.
+ */
+ const float xscale_correction = (do_scale) ? scale[0] : 1.0f;
+ const float yscale_correction = (do_scale) ? scale[2] : 1.0f;
+
+ h1[0] += (bone->curveInX + (!rest ? pchan->curveInX : 0.0f)) * xscale_correction;
+ h1[2] += (bone->curveInY + (!rest ? pchan->curveInY : 0.0f)) * yscale_correction;
+
+ h2[0] += (bone->curveOutX + (!rest ? pchan->curveOutX : 0.0f)) * xscale_correction;
+ h2[2] += (bone->curveOutY + (!rest ? pchan->curveOutY : 0.0f)) * yscale_correction;
+ }
+
/* make curve */
if (bone->segments > MAX_BBONE_SUBDIV)
bone->segments = MAX_BBONE_SUBDIV;
@@ -608,20 +658,45 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
BKE_curve_forward_diff_bezier(0.0f, h1[2], h2[2], 0.0f, data[0] + 2, MAX_BBONE_SUBDIV, 4 * sizeof(float));
BKE_curve_forward_diff_bezier(roll1, roll1 + 0.390464f * (roll2 - roll1), roll2 - 0.390464f * (roll2 - roll1), roll2, data[0] + 3, MAX_BBONE_SUBDIV, 4 * sizeof(float));
- equalize_bezier(data[0], bone->segments); /* note: does stride 4! */
+ equalize_bbone_bezier(data[0], bone->segments); /* note: does stride 4! */
/* make transformation matrices for the segments for drawing */
for (a = 0, fp = data[0]; a < bone->segments; a++, fp += 4) {
sub_v3_v3v3(h1, fp + 4, fp);
vec_roll_to_mat3(h1, fp[3], mat3); /* fp[3] is roll */
-
+
copy_m4_m3(result_array[a].mat, mat3);
copy_v3_v3(result_array[a].mat[3], fp);
-
+
if (do_scale) {
/* correct for scaling when this matrix is used in scaled space */
mul_m4_series(result_array[a].mat, iscalemat, result_array[a].mat, scalemat);
}
+
+ /* BBone scale... */
+ {
+ const int num_segments = bone->segments;
+
+ const float scaleIn = bone->scaleIn * (!rest ? pchan->scaleIn : 1.0f);
+ const float scaleFactorIn = 1.0f + (scaleIn - 1.0f) * ((float)(num_segments - a) / (float)num_segments);
+
+ const float scaleOut = bone->scaleOut * (!rest ? pchan->scaleOut : 1.0f);
+ const float scaleFactorOut = 1.0f + (scaleOut - 1.0f) * ((float)(a + 1) / (float)num_segments);
+
+ const float scalefac = scaleFactorIn * scaleFactorOut;
+ float bscalemat[4][4], bscale[3];
+
+ bscale[0] = scalefac;
+ bscale[1] = 1.0f;
+ bscale[2] = scalefac;
+
+ size_to_mat4(bscalemat, bscale);
+
+ /* Note: don't multiply by inverse scale mat here, as it causes problems with scaling shearing and breaking segment chains */
+ /*mul_m4_series(result_array[a].mat, ibscalemat, result_array[a].mat, bscalemat);*/
+ mul_m4_series(result_array[a].mat, result_array[a].mat, bscalemat);
+ }
+
}
}
@@ -667,7 +742,6 @@ static void pchan_b_bone_defmats(bPoseChannel *pchan, bPoseChanDeform *pdef_info
float tmat[4][4];
invert_m4_m4(tmat, b_bone_rest[a].mat);
-
mul_m4_series(b_bone_mats[a + 1].mat, pchan->chan_mat, bone->arm_mat, b_bone[a].mat, tmat, b_bone_mats[0].mat);
if (use_quaternion)
@@ -681,10 +755,10 @@ static void b_bone_deform(bPoseChanDeform *pdef_info, Bone *bone, float co[3], D
float (*mat)[4] = b_bone[0].mat;
float segment, y;
int a;
-
+
/* need to transform co back to bonespace, only need y */
y = mat[0][1] * co[0] + mat[1][1] * co[1] + mat[2][1] * co[2] + mat[3][1];
-
+
/* now calculate which of the b_bones are deforming this */
segment = bone->length / ((float)bone->segments);
a = (int)(y / segment);
@@ -854,6 +928,32 @@ static void pchan_bone_deform(bPoseChannel *pchan, bPoseChanDeform *pdef_info, f
(*contrib) += weight;
}
+typedef struct ArmatureBBoneDefmatsData {
+ bPoseChanDeform *pdef_info_array;
+ DualQuat *dualquats;
+ bool use_quaternion;
+} ArmatureBBoneDefmatsData;
+
+static void armature_bbone_defmats_cb(void *userdata, Link *iter, int index)
+{
+ ArmatureBBoneDefmatsData *data = userdata;
+ bPoseChannel *pchan = (bPoseChannel *)iter;
+
+ if (!(pchan->bone->flag & BONE_NO_DEFORM)) {
+ bPoseChanDeform *pdef_info = &data->pdef_info_array[index];
+ const bool use_quaternion = data->use_quaternion;
+
+ if (pchan->bone->segments > 1) {
+ pchan_b_bone_defmats(pchan, pdef_info, use_quaternion);
+ }
+
+ if (use_quaternion) {
+ pdef_info->dual_quat = &data->dualquats[index];
+ mat4_to_dquat(pdef_info->dual_quat, pchan->bone->arm_mat, pchan->chan_mat);
+ }
+ }
+}
+
void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3],
float (*defMats)[3][3], int numVerts, int deformflag,
float (*prevCos)[3], const char *defgrp_name)
@@ -897,19 +997,10 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float
pdef_info_array = MEM_callocN(sizeof(bPoseChanDeform) * totchan, "bPoseChanDeform");
- totchan = 0;
- pdef_info = pdef_info_array;
- for (pchan = armOb->pose->chanbase.first; pchan; pchan = pchan->next, pdef_info++) {
- if (!(pchan->bone->flag & BONE_NO_DEFORM)) {
- if (pchan->bone->segments > 1)
- pchan_b_bone_defmats(pchan, pdef_info, use_quaternion);
-
- if (use_quaternion) {
- pdef_info->dual_quat = &dualquats[totchan++];
- mat4_to_dquat(pdef_info->dual_quat, pchan->bone->arm_mat, pchan->chan_mat);
- }
- }
- }
+ ArmatureBBoneDefmatsData data = {
+ .pdef_info_array = pdef_info_array, .dualquats = dualquats, .use_quaternion = use_quaternion
+ };
+ BLI_task_parallel_listbase(&armOb->pose->chanbase, &data, armature_bbone_defmats_cb, totchan > 512);
/* get the def_nr for the overall armature vertex group if present */
armature_def_nr = defgroup_name_index(target, defgrp_name);
@@ -1812,6 +1903,17 @@ static int rebuild_pose_bone(bPose *pose, Bone *bone, bPoseChannel *parchan, int
return counter;
}
+/**
+ * Clear pointers of object's pose (needed in remap case, since we cannot always wait for a complete pose rebuild).
+ */
+void BKE_pose_clear_pointers(bPose *pose)
+{
+ for (bPoseChannel *pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ pchan->bone = NULL;
+ pchan->child = NULL;
+ }
+}
+
/* only after leave editmode, duplicating, validating older files, library syncing */
/* NOTE: pose->flag is set for it */
void BKE_pose_rebuild(Object *ob, bArmature *arm)
@@ -1832,10 +1934,7 @@ void BKE_pose_rebuild(Object *ob, bArmature *arm)
pose = ob->pose;
/* clear */
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- pchan->bone = NULL;
- pchan->child = NULL;
- }
+ BKE_pose_clear_pointers(pose);
/* first step, check if all channels are there */
for (bone = arm->bonebase.first; bone; bone = bone->next) {
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
index 34d9962139c..3bc81a69c86 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -224,7 +224,7 @@ static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPos
}
/* make a new Spline-IK chain, and store it in the IK chains */
- /* TODO: we should check if there is already an IK chain on this, since that would take presidence... */
+ /* TODO: we should check if there is already an IK chain on this, since that would take precedence... */
{
/* make new tree */
tSplineIK_Tree *tree = MEM_callocN(sizeof(tSplineIK_Tree), "SplineIK Tree");
@@ -617,9 +617,9 @@ void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx),
/* pass */
}
else {
- /* TODO(sergey): Use time source node for time. */
- float ctime = BKE_scene_frame_get(scene); /* not accurate... */
if ((pchan->flag & POSE_DONE) == 0) {
+ /* TODO(sergey): Use time source node for time. */
+ float ctime = BKE_scene_frame_get(scene); /* not accurate... */
BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
}
}
@@ -633,12 +633,16 @@ void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx),
{
Scene *scene = G.main->scene.first;
DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, pchan->name);
- if (pchan->flag & POSE_IKTREE || pchan->flag & POSE_IKSPLINE) {
+ bArmature *arm = (bArmature *)ob->data;
+ if (arm->flag & ARM_RESTPOS) {
+ return;
+ }
+ else if (pchan->flag & POSE_IKTREE || pchan->flag & POSE_IKSPLINE) {
/* IK are being solved separately/ */
}
else {
- float ctime = BKE_scene_frame_get(scene); /* not accurate... */
if ((pchan->flag & POSE_DONE) == 0) {
+ float ctime = BKE_scene_frame_get(scene); /* not accurate... */
BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
}
}
@@ -692,7 +696,7 @@ void BKE_pose_eval_flush(EvaluationContext *UNUSED(eval_ctx),
void BKE_pose_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx), Object *ob)
{
- BLI_assert(ob->id.lib != NULL && ob->proxy_from != NULL);
+ BLI_assert(ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from != NULL);
DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) {
printf("Proxy copy error, lib Object: %s proxy Object: %s\n",
diff --git a/source/blender/blenkernel/intern/autoexec.c b/source/blender/blenkernel/intern/autoexec.c
index d9462cd0262..bde06b02ae8 100644
--- a/source/blender/blenkernel/intern/autoexec.c
+++ b/source/blender/blenkernel/intern/autoexec.c
@@ -59,7 +59,10 @@ bool BKE_autoexec_match(const char *path)
BLI_assert((U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0);
for (path_cmp = U.autoexec_paths.first; path_cmp; path_cmp = path_cmp->next) {
- if ((path_cmp->flag & USER_PATHCMP_GLOB)) {
+ if (path_cmp->path[0] == '\0') {
+ /* pass */
+ }
+ else if ((path_cmp->flag & USER_PATHCMP_GLOB)) {
if (fnmatch(path_cmp->path, path, fnmatch_flags) == 0) {
return true;
}
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index 15492fbd20d..a8670395fc4 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -49,6 +49,7 @@
#include "BKE_blender_version.h" /* own include */
#include "BKE_blendfile.h"
#include "BKE_brush.h"
+#include "BKE_cachefile.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_global.h"
@@ -84,6 +85,7 @@ void BKE_blender_free(void)
BKE_spacetypes_free(); /* after free main, it uses space callbacks */
IMB_exit();
+ BKE_cachefiles_exit();
BKE_images_exit();
DAG_exit();
@@ -226,3 +228,56 @@ int BKE_blender_test_break(void)
return (G.is_break == true);
}
+
+/** \name Blender's AtExit
+ *
+ * \note Don't use MEM_mallocN so functions can be registered at any time.
+ * \{ */
+
+struct AtExitData {
+ struct AtExitData *next;
+
+ void (*func)(void *user_data);
+ void *user_data;
+} *g_atexit = NULL;
+
+void BKE_blender_atexit_register(void (*func)(void *user_data), void *user_data)
+{
+ struct AtExitData *ae = malloc(sizeof(*ae));
+ ae->next = g_atexit;
+ ae->func = func;
+ ae->user_data = user_data;
+ g_atexit = ae;
+}
+
+void BKE_blender_atexit_unregister(void (*func)(void *user_data), const void *user_data)
+{
+ struct AtExitData *ae = g_atexit;
+ struct AtExitData **ae_p = &g_atexit;
+
+ while (ae) {
+ if ((ae->func == func) && (ae->user_data == user_data)) {
+ *ae_p = ae->next;
+ free(ae);
+ return;
+ }
+ ae_p = &ae;
+ ae = ae->next;
+ }
+}
+
+void BKE_blender_atexit(void)
+{
+ struct AtExitData *ae = g_atexit, *ae_next;
+ while (ae) {
+ ae_next = ae->next;
+
+ ae->func(ae->user_data);
+
+ free(ae);
+ ae = ae_next;
+ }
+ g_atexit = NULL;
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/blender_copybuffer.c b/source/blender/blenkernel/intern/blender_copybuffer.c
index ad01fac2144..a4c28121040 100644
--- a/source/blender/blenkernel/intern/blender_copybuffer.c
+++ b/source/blender/blenkernel/intern/blender_copybuffer.c
@@ -85,6 +85,31 @@ bool BKE_copybuffer_save(Main *bmain_src, const char *filename, ReportList *repo
return retval;
}
+bool BKE_copybuffer_read(Main *bmain_dst, const char *libname, ReportList *reports)
+{
+ BlendHandle *bh = BLO_blendhandle_from_file(libname, reports);
+ if (bh == NULL) {
+ /* Error reports will have been made by BLO_blendhandle_from_file(). */
+ return false;
+ }
+ /* Here appending/linking starts. */
+ Main *mainl = BLO_library_link_begin(bmain_dst, &bh, libname);
+ BLO_library_link_copypaste(mainl, bh);
+ BLO_library_link_end(mainl, &bh, 0, NULL, NULL);
+ /* Mark all library linked objects to be updated. */
+ BKE_main_lib_objects_recalc_all(bmain_dst);
+ IMB_colormanagement_check_file_config(bmain_dst);
+ /* Append, rather than linking. */
+ Library *lib = BLI_findstring(&bmain_dst->library, libname, offsetof(Library, filepath));
+ BKE_library_make_local(bmain_dst, lib, true, false);
+ /* Important we unset, otherwise these object wont
+ * link into other scenes from this blend file.
+ */
+ BKE_main_id_tag_all(bmain_dst, LIB_TAG_PRE_EXISTING, false);
+ BLO_blendhandle_close(bh);
+ return true;
+}
+
/**
* \return Success.
*/
diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c
index ca0a1b91cea..d64bf7ecf43 100644
--- a/source/blender/blenkernel/intern/blender_undo.c
+++ b/source/blender/blenkernel/intern/blender_undo.c
@@ -66,9 +66,6 @@
#include "BLO_readfile.h"
#include "BLO_writefile.h"
-#include "WM_api.h" // XXXXX BAD, very BAD dependency (bad level call) - remove asap, elubie
-
-
/* -------------------------------------------------------------------- */
/** \name Global Undo
@@ -87,6 +84,15 @@ typedef struct UndoElem {
static ListBase undobase = {NULL, NULL};
static UndoElem *curundo = NULL;
+/**
+ * Avoid bad-level call to #WM_jobs_kill_all_except()
+ */
+static void (*undo_wm_job_kill_callback)(struct bContext *C) = NULL;
+
+void BKE_undo_callback_wm_kill_jobs_set(void (*callback)(struct bContext *C))
+{
+ undo_wm_job_kill_callback = callback;
+}
static int read_undosave(bContext *C, UndoElem *uel)
{
@@ -94,7 +100,7 @@ static int read_undosave(bContext *C, UndoElem *uel)
int success = 0, fileflags;
/* This is needed so undoing/redoing doesn't crash with threaded previews going */
- WM_jobs_kill_all_except(CTX_wm_manager(C), CTX_wm_screen(C));
+ undo_wm_job_kill_callback(C);
BLI_strncpy(mainstr, G.main->name, sizeof(mainstr)); /* temporal store */
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index 4605a12f9a0..6da68470ecc 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -121,7 +121,12 @@ static void setup_app_data(
LOAD_UNDO,
} mode;
- if (BLI_listbase_is_empty(&bfd->main->screen)) {
+ /* may happen with library files - UNDO file should never have NULL cursccene... */
+ if (ELEM(NULL, bfd->curscreen, bfd->curscene)) {
+ BKE_report(reports, RPT_WARNING, "Library file, loading empty scene");
+ mode = LOAD_UI_OFF;
+ }
+ else if (BLI_listbase_is_empty(&bfd->main->screen)) {
mode = LOAD_UNDO;
}
else if (G.fileflags & G_FILE_NO_UI) {
@@ -131,14 +136,6 @@ static void setup_app_data(
mode = LOAD_UI;
}
- if (mode != LOAD_UNDO) {
- /* may happen with library files */
- if (ELEM(NULL, bfd->curscreen, bfd->curscene)) {
- BKE_report(reports, RPT_WARNING, "Library file, loading empty scene");
- mode = LOAD_UI_OFF;
- }
- }
-
/* Free all render results, without this stale data gets displayed after loading files */
if (mode != LOAD_UNDO) {
RE_FreeAllRenderResults();
@@ -492,6 +489,9 @@ static void blendfile_write_partial_cb(void *UNUSED(handle), Main *UNUSED(bmain)
/* only tag for need-expand if not done, prevents eternal loops */
if ((id->tag & LIB_TAG_DOIT) == 0)
id->tag |= LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT;
+
+ if (id->lib && (id->lib->id.tag & LIB_TAG_DOIT) == 0)
+ id->lib->id.tag |= LIB_TAG_DOIT;
}
}
@@ -508,6 +508,10 @@ bool BKE_blendfile_write_partial(
void *path_list_backup = NULL;
const int path_list_flag = (BKE_BPATH_TRAVERSE_SKIP_LIBRARY | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE);
+ /* This is needed to be able to load that file as a real one later
+ * (otherwise main->name will not be set at read time). */
+ BLI_strncpy(bmain_dst->name, bmain_src->name, sizeof(bmain_dst->name));
+
if (write_flags & G_FILE_RELATIVE_REMAP) {
path_list_backup = BKE_bpath_list_backup(bmain_src, path_list_flag);
}
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index 76544e5ed42..487b8ffa2b5 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -48,6 +48,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_brush_types.h"
+#include "DNA_cachefile_types.h"
#include "DNA_image_types.h"
#include "DNA_mesh_types.h"
#include "DNA_modifier_types.h"
@@ -424,7 +425,7 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int
{
const char *absbase = (flag & BKE_BPATH_TRAVERSE_ABS) ? ID_BLEND_PATH(bmain, id) : NULL;
- if ((flag & BKE_BPATH_TRAVERSE_SKIP_LIBRARY) && id->lib) {
+ if ((flag & BKE_BPATH_TRAVERSE_SKIP_LIBRARY) && ID_IS_LINKED_DATABLOCK(id)) {
return;
}
@@ -653,6 +654,12 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int
rewrite_path_fixed(clip->name, visit_cb, absbase, bpath_user_data);
break;
}
+ case ID_CF:
+ {
+ CacheFile *cache_file = (CacheFile *)id;
+ rewrite_path_fixed(cache_file->filepath, visit_cb, absbase, bpath_user_data);
+ break;
+ }
default:
/* Nothing to do for other IDs that don't contain file paths. */
break;
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 31dac038e43..8ef1fae1155 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -38,6 +38,8 @@
#include "BKE_colortools.h"
#include "BKE_global.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_paint.h"
#include "BKE_texture.h"
@@ -170,11 +172,11 @@ struct Brush *BKE_brush_first_search(struct Main *bmain, short ob_mode)
return NULL;
}
-Brush *BKE_brush_copy(Brush *brush)
+Brush *BKE_brush_copy(Main *bmain, Brush *brush)
{
Brush *brushn;
- brushn = BKE_libblock_copy(&brush->id);
+ brushn = BKE_libblock_copy(bmain, &brush->id);
if (brush->mtex.tex)
id_us_plus((ID *)brush->mtex.tex);
@@ -195,102 +197,60 @@ Brush *BKE_brush_copy(Brush *brush)
/* enable fake user by default */
id_fake_user_set(&brush->id);
- if (brush->id.lib) {
- BKE_id_lib_local_paths(G.main, brush->id.lib, &brushn->id);
- }
+ BKE_id_copy_ensure_local(bmain, &brush->id, &brushn->id);
return brushn;
}
-/* not brush itself */
+/** Free (or release) any data used by this brush (does not free the brush itself). */
void BKE_brush_free(Brush *brush)
{
- id_us_min((ID *)brush->mtex.tex);
- id_us_min((ID *)brush->mask_mtex.tex);
- id_us_min((ID *)brush->paint_curve);
-
- if (brush->icon_imbuf)
+ if (brush->icon_imbuf) {
IMB_freeImBuf(brush->icon_imbuf);
-
- BKE_previewimg_free(&(brush->preview));
+ }
curvemapping_free(brush->curve);
- if (brush->gradient)
- MEM_freeN(brush->gradient);
-}
-
-/**
- * \note Currently users don't remove brushes from the UI (as is done for scene, text... etc)
- * This is only used by RNA, which can remove brushes.
- */
-void BKE_brush_unlink(Main *bmain, Brush *brush)
-{
- Brush *brush_iter;
-
- for (brush_iter = bmain->brush.first; brush_iter; brush_iter = brush_iter->id.next) {
- if (brush_iter->toggle_brush == brush) {
- brush_iter->toggle_brush = NULL;
- }
- }
-}
+ MEM_SAFE_FREE(brush->gradient);
-static void extern_local_brush(Brush *brush)
-{
- id_lib_extern((ID *)brush->mtex.tex);
- id_lib_extern((ID *)brush->mask_mtex.tex);
- id_lib_extern((ID *)brush->clone.image);
- id_lib_extern((ID *)brush->toggle_brush);
- id_lib_extern((ID *)brush->paint_curve);
+ BKE_previewimg_free(&(brush->preview));
}
-void BKE_brush_make_local(Brush *brush)
+void BKE_brush_make_local(Main *bmain, Brush *brush, const bool lib_local)
{
+ bool is_local = false, is_lib = false;
- /* - only lib users: do nothing
+ /* - only lib users: do nothing (unless force_local is set)
* - only local users: set flag
* - mixed: make copy
*/
- Main *bmain = G.main;
- Scene *scene;
- bool is_local = false, is_lib = false;
-
- if (brush->id.lib == NULL) return;
+ if (!ID_IS_LINKED_DATABLOCK(brush)) {
+ return;
+ }
if (brush->clone.image) {
- /* special case: ima always local immediately. Clone image should only
- * have one user anyway. */
- id_clear_lib_data(bmain, &brush->clone.image->id);
- extern_local_brush(brush);
+ /* Special case: ima always local immediately. Clone image should only have one user anyway. */
+ id_make_local(bmain, &brush->clone.image->id, false, false);
}
- for (scene = bmain->scene.first; scene && ELEM(0, is_lib, is_local); scene = scene->id.next) {
- if (BKE_paint_brush(&scene->toolsettings->imapaint.paint) == brush) {
- if (scene->id.lib) is_lib = true;
- else is_local = true;
+ BKE_library_ID_test_usages(bmain, brush, &is_local, &is_lib);
+
+ if (lib_local || is_local) {
+ if (!is_lib) {
+ id_clear_lib_data(bmain, &brush->id);
+ BKE_id_expand_local(&brush->id);
+
+ /* enable fake user by default */
+ id_fake_user_set(&brush->id);
}
- }
+ else {
+ Brush *brush_new = BKE_brush_copy(bmain, brush); /* Ensures FAKE_USER is set */
- if (is_local && is_lib == false) {
- id_clear_lib_data(bmain, &brush->id);
- extern_local_brush(brush);
+ brush_new->id.us = 0;
- /* enable fake user by default */
- id_fake_user_set(&brush->id);
- }
- else if (is_local && is_lib) {
- Brush *brush_new = BKE_brush_copy(brush); /* Ensures FAKE_USER is set */
- id_us_min(&brush_new->id); /* Remove user added by standard BKE_libblock_copy(). */
-
- /* Remap paths of new ID using old library as base. */
- BKE_id_lib_local_paths(bmain, brush->id.lib, &brush_new->id);
-
- for (scene = bmain->scene.first; scene; scene = scene->id.next) {
- if (BKE_paint_brush(&scene->toolsettings->imapaint.paint) == brush) {
- if (scene->id.lib == NULL) {
- BKE_paint_brush_set(&scene->toolsettings->imapaint.paint, brush_new);
- }
+ if (!lib_local) {
+ BKE_libblock_remap(bmain, brush, brush_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}
}
}
@@ -488,6 +448,7 @@ void BKE_brush_curve_preset(Brush *b, int preset)
curvemapping_changed(b->curve, false);
}
+/* XXX Unused function. */
int BKE_brush_texture_set_nr(Brush *brush, int nr)
{
ID *idtest, *id = NULL;
@@ -496,7 +457,7 @@ int BKE_brush_texture_set_nr(Brush *brush, int nr)
idtest = (ID *)BLI_findlink(&G.main->tex, nr - 1);
if (idtest == NULL) { /* new tex */
- if (id) idtest = (ID *)BKE_texture_copy((Tex *)id);
+ if (id) idtest = (ID *)BKE_texture_copy(G.main, (Tex *)id);
else idtest = (ID *)BKE_texture_add(G.main, "Tex");
id_us_min(idtest);
}
@@ -835,9 +796,7 @@ void BKE_brush_color_set(struct Scene *scene, struct Brush *brush, const float c
void BKE_brush_size_set(Scene *scene, Brush *brush, int size)
{
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
-
- size = (int)((float)size / U.pixelsize);
-
+
/* make sure range is sane */
CLAMP(size, 1, MAX_BRUSH_PIXEL_RADIUS);
@@ -852,7 +811,7 @@ int BKE_brush_size_get(const Scene *scene, const Brush *brush)
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
int size = (ups->flag & UNIFIED_PAINT_SIZE) ? ups->size : brush->size;
- return (int)((float)size * U.pixelsize);
+ return size;
}
int BKE_brush_use_locked_size(const Scene *scene, const Brush *brush)
diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c
index bc45542ef9f..264d87b86f3 100644
--- a/source/blender/blenkernel/intern/bvhutils.c
+++ b/source/blender/blenkernel/intern/bvhutils.c
@@ -397,7 +397,7 @@ static BVHTree *bvhtree_from_editmesh_verts_create_tree(
int i;
BM_mesh_elem_table_ensure(em->bm, BM_VERT);
if (verts_mask) {
- BLI_assert(IN_RANGE(verts_num_active, -1, verts_num));
+ BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num));
}
else {
verts_num_active = verts_num;
@@ -430,7 +430,7 @@ static BVHTree *bvhtree_from_mesh_verts_create_tree(
int i;
if (vert) {
if (verts_mask) {
- BLI_assert(IN_RANGE(verts_num_active, -1, verts_num));
+ BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num));
}
else {
verts_num_active = verts_num;
@@ -526,7 +526,7 @@ BVHTree *bvhtree_from_mesh_verts(
bool vert_allocated;
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- tree = bvhcache_find(&dm->bvhCache, BVHTREE_FROM_VERTS);
+ tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_VERTS);
BLI_rw_mutex_unlock(&cache_rwlock);
vert = DM_get_vert_array(dm, &vert_allocated);
@@ -534,7 +534,7 @@ BVHTree *bvhtree_from_mesh_verts(
/* Not in cache */
if (tree == NULL) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- tree = bvhcache_find(&dm->bvhCache, BVHTREE_FROM_VERTS);
+ tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_VERTS);
if (tree == NULL) {
int vert_num = dm->getNumVerts(dm);
@@ -565,7 +565,7 @@ BVHTree *bvhtree_from_mesh_verts(
/**
* Builds a bvh tree where nodes are the given vertices (note: does not copy given mverts!).
* \param vert_allocated if true, vert freeing will be done when freeing data.
- * \param mask if not null, true elements give which vert to add to BVH tree.
+ * \param verts_mask if not null, true elements give which vert to add to BVH tree.
* \param verts_num_active if >= 0, number of active verts to add to BVH tree (else will be computed from mask).
*/
BVHTree *bvhtree_from_mesh_verts_ex(
@@ -590,6 +590,77 @@ BVHTree *bvhtree_from_mesh_verts_ex(
/** \name Edge Builder
* \{ */
+static BVHTree *bvhtree_from_editmesh_edges_create_tree(
+ float epsilon, int tree_type, int axis,
+ BMEditMesh *em, const int edges_num,
+ const BLI_bitmap *edges_mask, int edges_num_active)
+{
+ BVHTree *tree = NULL;
+ int i;
+ BM_mesh_elem_table_ensure(em->bm, BM_EDGE);
+ if (edges_mask) {
+ BLI_assert(IN_RANGE_INCL(edges_num_active, 0, edges_num));
+ }
+ else {
+ edges_num_active = edges_num;
+ }
+
+ tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis);
+
+ if (tree) {
+ BMIter iter;
+ BMEdge *eed;
+ BM_ITER_MESH_INDEX (eed, &iter, em->bm, BM_EDGES_OF_MESH, i) {
+ if (edges_mask && !BLI_BITMAP_TEST_BOOL(edges_mask, i)) {
+ continue;
+ }
+ float co[2][3];
+ copy_v3_v3(co[0], eed->v1->co);
+ copy_v3_v3(co[1], eed->v2->co);
+
+ BLI_bvhtree_insert(tree, i, co[0], 2);
+ }
+ BLI_assert(BLI_bvhtree_get_size(tree) == edges_num_active);
+ BLI_bvhtree_balance(tree);
+ }
+
+ return tree;
+}
+
+/* Builds a bvh tree where nodes are the edges of the given em */
+BVHTree *bvhtree_from_editmesh_edges_ex(
+ BVHTreeFromEditMesh *data, BMEditMesh *em,
+ const BLI_bitmap *edges_mask, int edges_num_active,
+ float epsilon, int tree_type, int axis)
+{
+ int edge_num = em->bm->totedge;
+
+ BVHTree *tree = bvhtree_from_editmesh_edges_create_tree(
+ epsilon, tree_type, axis,
+ em, edge_num, edges_mask, edges_num_active);
+
+ if (tree) {
+ memset(data, 0, sizeof(*data));
+ data->tree = tree;
+ data->em = em;
+ data->nearest_callback = NULL; /* TODO */
+ data->raycast_callback = NULL; /* TODO */
+ /* TODO: not urgent however since users currently define own callbacks */
+ data->nearest_to_ray_callback = NULL;
+ }
+
+ return tree;
+}
+BVHTree *bvhtree_from_editmesh_edges(
+ BVHTreeFromEditMesh *data, BMEditMesh *em,
+ float epsilon, int tree_type, int axis)
+{
+ return bvhtree_from_editmesh_edges_ex(
+ data, em,
+ NULL, -1,
+ epsilon, tree_type, axis);
+}
+
/* Builds a bvh tree where nodes are the edges of the given dm */
BVHTree *bvhtree_from_mesh_edges(
BVHTreeFromMesh *data, DerivedMesh *dm,
@@ -601,7 +672,7 @@ BVHTree *bvhtree_from_mesh_edges(
bool vert_allocated, edge_allocated;
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- tree = bvhcache_find(&dm->bvhCache, BVHTREE_FROM_EDGES);
+ tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_EDGES);
BLI_rw_mutex_unlock(&cache_rwlock);
vert = DM_get_vert_array(dm, &vert_allocated);
@@ -610,7 +681,7 @@ BVHTree *bvhtree_from_mesh_edges(
/* Not in cache */
if (tree == NULL) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- tree = bvhcache_find(&dm->bvhCache, BVHTREE_FROM_EDGES);
+ tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_EDGES);
if (tree == NULL) {
int i;
int numEdges = dm->getNumEdges(dm);
@@ -688,7 +759,7 @@ static BVHTree *bvhtree_from_mesh_faces_create_tree(
if (faces_num) {
if (faces_mask) {
- BLI_assert(IN_RANGE(faces_num_active, -1, faces_num));
+ BLI_assert(IN_RANGE_INCL(faces_num_active, 0, faces_num));
}
else {
faces_num_active = faces_num;
@@ -765,7 +836,7 @@ BVHTree *bvhtree_from_mesh_faces(
bool vert_allocated = false, face_allocated = false;
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- tree = bvhcache_find(&dm->bvhCache, BVHTREE_FROM_FACES);
+ tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_FACES);
BLI_rw_mutex_unlock(&cache_rwlock);
vert = DM_get_vert_array(dm, &vert_allocated);
@@ -774,7 +845,7 @@ BVHTree *bvhtree_from_mesh_faces(
/* Not in cache */
if (tree == NULL) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- tree = bvhcache_find(&dm->bvhCache, BVHTREE_FROM_FACES);
+ tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_FACES);
if (tree == NULL) {
int numFaces = dm->getNumTessFaces(dm);
BLI_assert(!(numFaces == 0 && dm->getNumPolys(dm) != 0));
@@ -804,7 +875,7 @@ BVHTree *bvhtree_from_mesh_faces(
* Builds a bvh tree where nodes are the given tessellated faces (note: does not copy given mfaces!).
* \param vert_allocated if true, vert freeing will be done when freeing data.
* \param face_allocated if true, face freeing will be done when freeing data.
- * \param mask if not null, true elements give which faces to add to BVH tree.
+ * \param faces_mask: if not null, true elements give which faces to add to BVH tree.
* \param numFaces_active if >= 0, number of active faces to add to BVH tree (else will be computed from mask).
*/
BVHTree *bvhtree_from_mesh_faces_ex(
@@ -842,7 +913,7 @@ static BVHTree *bvhtree_from_editmesh_looptri_create_tree(
if (looptri_num) {
if (looptri_mask) {
- BLI_assert(IN_RANGE(looptri_num_active, -1, looptri_num));
+ BLI_assert(IN_RANGE_INCL(looptri_num_active, 0, looptri_num));
}
else {
looptri_num_active = looptri_num;
@@ -892,7 +963,7 @@ static BVHTree *bvhtree_from_mesh_looptri_create_tree(
if (looptri_num) {
if (looptri_mask) {
- BLI_assert(IN_RANGE(looptri_num_active, -1, looptri_num));
+ BLI_assert(IN_RANGE_INCL(looptri_num_active, 0, looptri_num));
}
else {
looptri_num_active = looptri_num;
@@ -968,17 +1039,37 @@ static void bvhtree_from_mesh_looptri_setup_data(
BVHTree *bvhtree_from_editmesh_looptri_ex(
BVHTreeFromEditMesh *data, BMEditMesh *em,
const BLI_bitmap *looptri_mask, int looptri_num_active,
- float epsilon, int tree_type, int axis)
+ float epsilon, int tree_type, int axis, BVHCache **bvhCache)
{
/* BMESH specific check that we have tessfaces,
- * we _could_ tessellate here but rather not - campbell
- *
- * this assert checks we have tessfaces,
- * if not caller should use DM_ensure_tessface() */
+ * we _could_ tessellate here but rather not - campbell */
- BVHTree *tree = bvhtree_from_editmesh_looptri_create_tree(
- epsilon, tree_type, axis,
- em, em->tottri, looptri_mask, looptri_num_active);
+ BVHTree *tree;
+ if (bvhCache) {
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
+ tree = bvhcache_find(*bvhCache, BVHTREE_FROM_EM_LOOPTRI);
+ BLI_rw_mutex_unlock(&cache_rwlock);
+ if (tree == NULL) {
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
+ tree = bvhcache_find(*bvhCache, BVHTREE_FROM_EM_LOOPTRI);
+ if (tree == NULL) {
+ tree = bvhtree_from_editmesh_looptri_create_tree(
+ epsilon, tree_type, axis,
+ em, em->tottri, looptri_mask, looptri_num_active);
+ if (tree) {
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(bvhCache, tree, BVHTREE_FROM_EM_LOOPTRI);
+ }
+ }
+ BLI_rw_mutex_unlock(&cache_rwlock);
+ }
+ }
+ else {
+ tree = bvhtree_from_editmesh_looptri_create_tree(
+ epsilon, tree_type, axis,
+ em, em->tottri, looptri_mask, looptri_num_active);
+ }
if (tree) {
data->tree = tree;
@@ -987,17 +1078,18 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(
data->nearest_to_ray_callback = NULL;
data->sphere_radius = 0.0f;
data->em = em;
+ data->cached = bvhCache != NULL;
}
return tree;
}
BVHTree *bvhtree_from_editmesh_looptri(
BVHTreeFromEditMesh *data, BMEditMesh *em,
- float epsilon, int tree_type, int axis)
+ float epsilon, int tree_type, int axis, BVHCache **bvhCache)
{
return bvhtree_from_editmesh_looptri_ex(
data, em, NULL, -1,
- epsilon, tree_type, axis);
+ epsilon, tree_type, axis, bvhCache);
}
/**
@@ -1018,7 +1110,7 @@ BVHTree *bvhtree_from_mesh_looptri(
bool looptri_allocated = false;
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- tree = bvhcache_find(&dm->bvhCache, BVHTREE_FROM_LOOPTRI);
+ tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_LOOPTRI);
BLI_rw_mutex_unlock(&cache_rwlock);
MPoly *mpoly;
@@ -1042,9 +1134,12 @@ BVHTree *bvhtree_from_mesh_looptri(
/* Not in cache */
if (tree == NULL) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- tree = bvhcache_find(&dm->bvhCache, BVHTREE_FROM_LOOPTRI);
+ tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_LOOPTRI);
if (tree == NULL) {
int looptri_num = dm->getNumLoopTri(dm);
+
+ /* this assert checks we have looptris,
+ * if not caller should use DM_ensure_looptri() */
BLI_assert(!(looptri_num == 0 && dm->getNumPolys(dm) != 0));
tree = bvhtree_from_mesh_looptri_create_tree(
@@ -1102,7 +1197,9 @@ BVHTree *bvhtree_from_mesh_looptri_ex(
void free_bvhtree_from_editmesh(struct BVHTreeFromEditMesh *data)
{
if (data->tree) {
- BLI_bvhtree_free(data->tree);
+ if (!data->cached) {
+ BLI_bvhtree_free(data->tree);
+ }
memset(data, 0, sizeof(*data));
}
}
@@ -1147,32 +1244,46 @@ typedef struct BVHCacheItem {
} BVHCacheItem;
-static void bvhcacheitem_set_if_match(void *_cached, void *_search)
+/**
+ * Queries a bvhcache for the cache bvhtree of the request type
+ */
+BVHTree *bvhcache_find(BVHCache *cache, int type)
{
- BVHCacheItem *cached = (BVHCacheItem *)_cached;
- BVHCacheItem *search = (BVHCacheItem *)_search;
-
- if (search->type == cached->type) {
- search->tree = cached->tree;
+ while (cache) {
+ const BVHCacheItem *item = cache->link;
+ if (item->type == type) {
+ return item->tree;
+ }
+ cache = cache->next;
}
-}
+ return NULL;
+}
-BVHTree *bvhcache_find(BVHCache *cache, int type)
+bool bvhcache_has_tree(const BVHCache *cache, const BVHTree *tree)
{
- BVHCacheItem item;
- item.type = type;
- item.tree = NULL;
-
- BLI_linklist_apply(*cache, bvhcacheitem_set_if_match, &item);
- return item.tree;
+ while (cache) {
+ const BVHCacheItem *item = cache->link;
+ if (item->tree == tree) {
+ return true;
+ }
+ cache = cache->next;
+ }
+ return false;
}
-void bvhcache_insert(BVHCache *cache, BVHTree *tree, int type)
+/**
+ * Inserts a BVHTree of the given type under the cache
+ * After that the caller no longer needs to worry when to free the BVHTree
+ * as that will be done when the cache is freed.
+ *
+ * A call to this assumes that there was no previous cached tree of the given type
+ */
+void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, int type)
{
BVHCacheItem *item = NULL;
assert(tree != NULL);
- assert(bvhcache_find(cache, type) == NULL);
+ assert(bvhcache_find(*cache_p, type) == NULL);
item = MEM_mallocN(sizeof(BVHCacheItem), "BVHCacheItem");
assert(item != NULL);
@@ -1180,13 +1291,15 @@ void bvhcache_insert(BVHCache *cache, BVHTree *tree, int type)
item->type = type;
item->tree = tree;
- BLI_linklist_prepend(cache, item);
+ BLI_linklist_prepend(cache_p, item);
}
-
-void bvhcache_init(BVHCache *cache)
+/**
+ * inits and frees a bvhcache
+ */
+void bvhcache_init(BVHCache **cache_p)
{
- *cache = NULL;
+ *cache_p = NULL;
}
static void bvhcacheitem_free(void *_item)
@@ -1198,10 +1311,10 @@ static void bvhcacheitem_free(void *_item)
}
-void bvhcache_free(BVHCache *cache)
+void bvhcache_free(BVHCache **cache_p)
{
- BLI_linklist_free(*cache, (LinkNodeFreeFP)bvhcacheitem_free);
- *cache = NULL;
+ BLI_linklist_free(*cache_p, (LinkNodeFreeFP)bvhcacheitem_free);
+ *cache_p = NULL;
}
/** \} */
diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c
new file mode 100644
index 00000000000..6a08673144e
--- /dev/null
+++ b/source/blender/blenkernel/intern/cachefile.c
@@ -0,0 +1,239 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Kevin Dietrich.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/cachefile.c
+ * \ingroup bke
+ */
+
+#include "DNA_anim_types.h"
+#include "DNA_cachefile_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_fileops.h"
+#include "BLI_listbase.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_threads.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_animsys.h"
+#include "BKE_cachefile.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_modifier.h"
+#include "BKE_scene.h"
+
+#ifdef WITH_ALEMBIC
+# include "ABC_alembic.h"
+#endif
+
+static SpinLock spin;
+
+void BKE_cachefiles_init(void)
+{
+ BLI_spin_init(&spin);
+}
+
+void BKE_cachefiles_exit(void)
+{
+ BLI_spin_end(&spin);
+}
+
+void *BKE_cachefile_add(Main *bmain, const char *name)
+{
+ CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, name);
+
+ BKE_cachefile_init(cache_file);
+
+ return cache_file;
+}
+
+void BKE_cachefile_init(CacheFile *cache_file)
+{
+ cache_file->handle = NULL;
+ cache_file->filepath[0] = '\0';
+ cache_file->override_frame = false;
+ cache_file->frame = 0.0f;
+ cache_file->is_sequence = false;
+ cache_file->scale = 1.0f;
+ cache_file->handle_mutex = BLI_mutex_alloc();
+}
+
+/** Free (or release) any data used by this cachefile (does not free the cachefile itself). */
+void BKE_cachefile_free(CacheFile *cache_file)
+{
+ BKE_animdata_free((ID *)cache_file, false);
+
+#ifdef WITH_ALEMBIC
+ ABC_free_handle(cache_file->handle);
+#endif
+
+ BLI_mutex_free(cache_file->handle_mutex);
+ BLI_freelistN(&cache_file->object_paths);
+}
+
+CacheFile *BKE_cachefile_copy(Main *bmain, CacheFile *cache_file)
+{
+ CacheFile *new_cache_file = BKE_libblock_copy(bmain, &cache_file->id);
+ new_cache_file->handle = NULL;
+
+ BLI_listbase_clear(&cache_file->object_paths);
+
+ BKE_id_copy_ensure_local(bmain, &cache_file->id, &new_cache_file->id);
+
+ return new_cache_file;
+}
+
+void BKE_cachefile_make_local(Main *bmain, CacheFile *cache_file, const bool lib_local)
+{
+ BKE_id_make_local_generic(bmain, &cache_file->id, true, lib_local);
+}
+
+void BKE_cachefile_reload(const Main *bmain, CacheFile *cache_file)
+{
+ char filepath[FILE_MAX];
+
+ BLI_strncpy(filepath, cache_file->filepath, sizeof(filepath));
+ BLI_path_abs(filepath, ID_BLEND_PATH(bmain, &cache_file->id));
+
+#ifdef WITH_ALEMBIC
+ if (cache_file->handle) {
+ ABC_free_handle(cache_file->handle);
+ }
+
+ cache_file->handle = ABC_create_handle(filepath, &cache_file->object_paths);
+#endif
+}
+
+void BKE_cachefile_ensure_handle(const Main *bmain, CacheFile *cache_file)
+{
+ BLI_spin_lock(&spin);
+ if (cache_file->handle_mutex == NULL) {
+ cache_file->handle_mutex = BLI_mutex_alloc();
+ }
+ BLI_spin_unlock(&spin);
+
+ BLI_mutex_lock(cache_file->handle_mutex);
+
+ if (cache_file->handle == NULL) {
+ BKE_cachefile_reload(bmain, cache_file);
+ }
+
+ BLI_mutex_unlock(cache_file->handle_mutex);
+}
+
+void BKE_cachefile_update_frame(Main *bmain, Scene *scene, const float ctime, const float fps)
+{
+ CacheFile *cache_file;
+ char filename[FILE_MAX];
+
+ for (cache_file = bmain->cachefiles.first; cache_file; cache_file = cache_file->id.next) {
+ /* Execute drivers only, as animation has already been done. */
+ BKE_animsys_evaluate_animdata(scene, &cache_file->id, cache_file->adt, ctime, ADT_RECALC_DRIVERS);
+
+ if (!cache_file->is_sequence) {
+ continue;
+ }
+
+ const float time = BKE_cachefile_time_offset(cache_file, ctime, fps);
+
+ if (BKE_cachefile_filepath_get(bmain, cache_file, time, filename)) {
+#ifdef WITH_ALEMBIC
+ ABC_free_handle(cache_file->handle);
+ cache_file->handle = ABC_create_handle(filename, NULL);
+#endif
+ }
+ }
+}
+
+bool BKE_cachefile_filepath_get(
+ const Main *bmain, const CacheFile *cache_file, float frame,
+ char r_filepath[FILE_MAX])
+{
+ BLI_strncpy(r_filepath, cache_file->filepath, FILE_MAX);
+ BLI_path_abs(r_filepath, ID_BLEND_PATH(bmain, &cache_file->id));
+
+ int fframe;
+ int frame_len;
+
+ if (cache_file->is_sequence && BLI_path_frame_get(r_filepath, &fframe, &frame_len)) {
+ char ext[32];
+ BLI_path_frame_strip(r_filepath, true, ext);
+ BLI_path_frame(r_filepath, frame, frame_len);
+ BLI_ensure_extension(r_filepath, FILE_MAX, ext);
+
+ /* TODO(kevin): store sequence range? */
+ return BLI_exists(r_filepath);
+ }
+
+ return true;
+}
+
+float BKE_cachefile_time_offset(CacheFile *cache_file, const float time, const float fps)
+{
+ const float frame = (cache_file->override_frame ? cache_file->frame : time);
+ return cache_file->is_sequence ? frame : frame / fps;
+}
+
+/* TODO(kevin): replace this with some depsgraph mechanism, or something similar. */
+void BKE_cachefile_clean(Scene *scene, CacheFile *cache_file)
+{
+ for (Base *base = scene->base.first; base; base = base->next) {
+ Object *ob = base->object;
+
+ ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache);
+
+ if (md) {
+ MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
+
+ if (cache_file == mcmd->cache_file) {
+#ifdef WITH_ALEMBIC
+ CacheReader_free(mcmd->reader);
+#endif
+ mcmd->reader = NULL;
+ mcmd->object_path[0] = '\0';
+ }
+ }
+
+ for (bConstraint *con = ob->constraints.first; con; con = con->next) {
+ if (con->type != CONSTRAINT_TYPE_TRANSFORM_CACHE) {
+ continue;
+ }
+
+ bTransformCacheConstraint *data = con->data;
+
+ if (cache_file == data->cache_file) {
+#ifdef WITH_ALEMBIC
+ CacheReader_free(data->reader);
+#endif
+ data->reader = NULL;
+ data->object_path[0] = '\0';
+ }
+ }
+ }
+}
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index bdf3432e6ea..85ce399b770 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -49,6 +49,8 @@
#include "BKE_object.h"
#include "BKE_global.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
@@ -76,6 +78,8 @@ void BKE_camera_init(Camera *cam)
/* stereoscopy 3d */
cam->stereo.interocular_distance = 0.065f;
cam->stereo.convergence_distance = 30.f * 0.065f;
+ cam->stereo.pole_merge_angle_from = DEG2RADF(60.0f);
+ cam->stereo.pole_merge_angle_to = DEG2RADF(75.0f);
}
void *BKE_camera_add(Main *bmain, const char *name)
@@ -89,71 +93,26 @@ void *BKE_camera_add(Main *bmain, const char *name)
return cam;
}
-Camera *BKE_camera_copy(Camera *cam)
+Camera *BKE_camera_copy(Main *bmain, Camera *cam)
{
Camera *camn;
- camn = BKE_libblock_copy(&cam->id);
+ camn = BKE_libblock_copy(bmain, &cam->id);
- id_lib_extern((ID *)camn->dof_ob);
-
- if (cam->id.lib) {
- BKE_id_lib_local_paths(G.main, cam->id.lib, &camn->id);
- }
+ BKE_id_copy_ensure_local(bmain, &cam->id, &camn->id);
return camn;
}
-void BKE_camera_make_local(Camera *cam)
+void BKE_camera_make_local(Main *bmain, Camera *cam, const bool lib_local)
{
- Main *bmain = G.main;
- Object *ob;
- bool is_local = false, is_lib = false;
-
- /* - only lib users: do nothing
- * - only local users: set flag
- * - mixed: make copy
- */
-
- if (cam->id.lib == NULL) return;
- if (cam->id.us == 1) {
- id_clear_lib_data(bmain, &cam->id);
- return;
- }
-
- for (ob = bmain->object.first; ob && ELEM(0, is_lib, is_local); ob = ob->id.next) {
- if (ob->data == cam) {
- if (ob->id.lib) is_lib = true;
- else is_local = true;
- }
- }
-
- if (is_local && is_lib == false) {
- id_clear_lib_data(bmain, &cam->id);
- }
- else if (is_local && is_lib) {
- Camera *cam_new = BKE_camera_copy(cam);
-
- cam_new->id.us = 0;
-
- /* Remap paths of new ID using old library as base. */
- BKE_id_lib_local_paths(bmain, cam->id.lib, &cam_new->id);
-
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- if (ob->data == cam) {
- if (ob->id.lib == NULL) {
- ob->data = cam_new;
- id_us_plus(&cam_new->id);
- id_us_min(&cam->id);
- }
- }
- }
- }
+ BKE_id_make_local_generic(bmain, &cam->id, true, lib_local);
}
+/** Free (or release) any data used by this camera (does not free the camera itself). */
void BKE_camera_free(Camera *ca)
{
- BKE_animdata_free((ID *)ca);
+ BKE_animdata_free((ID *)ca, false);
}
/******************************** Camera Usage *******************************/
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index e6741657f47..f2dd2a3fcf6 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -61,8 +61,6 @@
#include "GPU_shader.h"
#include "GPU_basic_shader.h"
-#include "WM_api.h"
-
#include <string.h>
#include <limits.h>
#include <math.h>
@@ -464,7 +462,6 @@ static void cdDM_drawFacesSolid(
BKE_pbvh_draw(cddm->pbvh, partial_redraw_planes, face_nors,
setMaterial, false, false);
- glShadeModel(GL_FLAT);
return;
}
}
@@ -472,7 +469,6 @@ static void cdDM_drawFacesSolid(
GPU_vertex_setup(dm);
GPU_normal_setup(dm);
GPU_triangle_setup(dm);
- glShadeModel(GL_SMOOTH);
for (a = 0; a < dm->drawObject->totmaterial; a++) {
if (!setMaterial || setMaterial(dm->drawObject->materials[a].mat_nr + 1, NULL)) {
GPU_buffer_draw_elements(
@@ -481,8 +477,6 @@ static void cdDM_drawFacesSolid(
}
}
GPU_buffers_unbind();
-
- glShadeModel(GL_FLAT);
}
static void cdDM_drawFacesTex_common(
@@ -495,11 +489,12 @@ static void cdDM_drawFacesTex_common(
CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
const MPoly *mpoly = cddm->mpoly;
MTexPoly *mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY);
- const MLoopCol *mloopcol;
+ const MLoopCol *mloopcol = NULL;
int i;
int colType, start_element, tot_drawn;
const bool use_hide = (flag & DM_DRAW_SKIP_HIDDEN) != 0;
const bool use_tface = (flag & DM_DRAW_USE_ACTIVE_UV) != 0;
+ const bool use_colors = (flag & DM_DRAW_USE_COLORS) != 0;
int totpoly;
int next_actualFace;
int mat_index;
@@ -529,15 +524,17 @@ static void cdDM_drawFacesTex_common(
}
}
- colType = CD_TEXTURE_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- if (!mloopcol) {
- colType = CD_PREVIEW_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- }
- if (!mloopcol) {
- colType = CD_MLOOPCOL;
+ if (use_colors) {
+ colType = CD_TEXTURE_MLOOPCOL;
mloopcol = dm->getLoopDataArray(dm, colType);
+ if (!mloopcol) {
+ colType = CD_PREVIEW_MLOOPCOL;
+ mloopcol = dm->getLoopDataArray(dm, colType);
+ }
+ if (!mloopcol) {
+ colType = CD_MLOOPCOL;
+ mloopcol = dm->getLoopDataArray(dm, colType);
+ }
}
GPU_vertex_setup(dm);
@@ -550,8 +547,7 @@ static void cdDM_drawFacesTex_common(
if (mloopcol) {
GPU_color_setup(dm, colType);
}
-
- glShadeModel(GL_SMOOTH);
+
/* lastFlag = 0; */ /* UNUSED */
for (mat_index = 0; mat_index < dm->drawObject->totmaterial; mat_index++) {
GPUBufferMaterial *bufmat = dm->drawObject->materials + mat_index;
@@ -630,7 +626,6 @@ static void cdDM_drawFacesTex_common(
}
GPU_buffers_unbind();
- glShadeModel(GL_FLAT);
}
@@ -692,20 +687,24 @@ static void cdDM_drawMappedFaces(
const int orig = (index_mp_to_orig) ? index_mp_to_orig[i] : i;
bool is_hidden;
- if (use_hide) {
- if (flag & DM_DRAW_SELECT_USE_EDITMODE) {
- BMFace *efa = BM_face_at_index(bm, orig);
- is_hidden = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) != 0;
+ if (orig != ORIGINDEX_NONE) {
+ if (use_hide) {
+ if (flag & DM_DRAW_SELECT_USE_EDITMODE) {
+ BMFace *efa = BM_face_at_index(bm, orig);
+ is_hidden = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) != 0;
+ }
+ else {
+ is_hidden = (me->mpoly[orig].flag & ME_HIDE) != 0;
+ }
+
+ if (!is_hidden) {
+ GPU_select_index_get(orig + 1, &selcol);
+ }
}
else {
- is_hidden = (me->mpoly[orig].flag & ME_HIDE) != 0;
+ GPU_select_index_get(orig + 1, &selcol);
}
-
- if ((orig != ORIGINDEX_NONE) && !is_hidden)
- WM_framebuffer_index_get(orig + 1, &selcol);
}
- else if (orig != ORIGINDEX_NONE)
- WM_framebuffer_index_get(orig + 1, &selcol);
for (j = 0; j < mpoly->totloop; j++)
fi_map[start_element++] = selcol;
@@ -739,9 +738,6 @@ static void cdDM_drawMappedFaces(
}
}
}
-
-
- glShadeModel(GL_SMOOTH);
tot_tri_elem = dm->drawObject->tot_triangle_point;
@@ -838,7 +834,6 @@ static void cdDM_drawMappedFaces(
}
GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- glShadeModel(GL_FLAT);
GPU_buffers_unbind();
@@ -926,8 +921,6 @@ static void cdDM_drawMappedFacesGLSL(
matnr = -1;
do_draw = false;
- glShadeModel(GL_SMOOTH);
-
if (setDrawOptions != NULL) {
DMVertexAttribs attribs;
DEBUG_VBO("Using legacy code. cdDM_drawMappedFacesGLSL\n");
@@ -948,8 +941,10 @@ static void cdDM_drawMappedFacesGLSL(
matnr = new_matnr;
do_draw = setMaterial(matnr + 1, &gattribs);
- if (do_draw)
+ if (do_draw) {
DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
+ DM_draw_attrib_vertex_uniforms(&attribs);
+ }
glBegin(GL_TRIANGLES);
}
@@ -1029,6 +1024,7 @@ static void cdDM_drawMappedFacesGLSL(
if (matconv[a].attribs.totorco && matconv[a].attribs.orco.array) {
matconv[a].datatypes[numdata].index = matconv[a].attribs.orco.gl_index;
+ matconv[a].datatypes[numdata].info_index = matconv[a].attribs.orco.gl_info_index;
matconv[a].datatypes[numdata].size = 3;
matconv[a].datatypes[numdata].type = GL_FLOAT;
numdata++;
@@ -1036,6 +1032,7 @@ static void cdDM_drawMappedFacesGLSL(
for (b = 0; b < matconv[a].attribs.tottface; b++) {
if (matconv[a].attribs.tface[b].array) {
matconv[a].datatypes[numdata].index = matconv[a].attribs.tface[b].gl_index;
+ matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tface[b].gl_info_index;
matconv[a].datatypes[numdata].size = 2;
matconv[a].datatypes[numdata].type = GL_FLOAT;
numdata++;
@@ -1044,6 +1041,7 @@ static void cdDM_drawMappedFacesGLSL(
for (b = 0; b < matconv[a].attribs.totmcol; b++) {
if (matconv[a].attribs.mcol[b].array) {
matconv[a].datatypes[numdata].index = matconv[a].attribs.mcol[b].gl_index;
+ matconv[a].datatypes[numdata].info_index = matconv[a].attribs.mcol[b].gl_info_index;
matconv[a].datatypes[numdata].size = 4;
matconv[a].datatypes[numdata].type = GL_UNSIGNED_BYTE;
numdata++;
@@ -1052,6 +1050,7 @@ static void cdDM_drawMappedFacesGLSL(
for (b = 0; b < matconv[a].attribs.tottang; b++) {
if (matconv[a].attribs.tang[b].array) {
matconv[a].datatypes[numdata].index = matconv[a].attribs.tang[b].gl_index;
+ matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tang[b].gl_info_index;
matconv[a].datatypes[numdata].size = 4;
matconv[a].datatypes[numdata].type = GL_FLOAT;
numdata++;
@@ -1146,8 +1145,6 @@ static void cdDM_drawMappedFacesGLSL(
MEM_freeN(mat_orig_to_new);
MEM_freeN(matconv);
}
-
- glShadeModel(GL_FLAT);
}
static void cdDM_drawFacesGLSL(DerivedMesh *dm, DMSetMaterial setMaterial)
@@ -1196,8 +1193,6 @@ static void cdDM_drawMappedFacesMat(
matnr = -1;
- glShadeModel(GL_SMOOTH);
-
memset(&attribs, 0, sizeof(attribs));
glBegin(GL_TRIANGLES);
@@ -1217,6 +1212,7 @@ static void cdDM_drawMappedFacesMat(
setMaterial(userData, matnr = new_matnr, &gattribs);
DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
+ DM_draw_attrib_vertex_uniforms(&attribs);
glBegin(GL_TRIANGLES);
}
@@ -1253,8 +1249,6 @@ static void cdDM_drawMappedFacesMat(
cddm_draw_attrib_vertex(&attribs, mvert, a, vtri[2], ltri[2], 2, ln3, smoothnormal);
}
glEnd();
-
- glShadeModel(GL_FLAT);
}
static void cdDM_drawMappedEdges(DerivedMesh *dm, DMSetDrawOptions setDrawOptions, void *userData)
@@ -2653,6 +2647,9 @@ void CDDM_calc_loop_normals(DerivedMesh *dm, const bool use_split_normals, const
}
/* #define DEBUG_CLNORS */
+#ifdef DEBUG_CLNORS
+# include "BLI_linklist.h"
+#endif
void CDDM_calc_loop_normals_spacearr(
DerivedMesh *dm, const bool use_split_normals, const float split_angle, MLoopNorSpaceArray *r_lnors_spacearr)
@@ -3412,7 +3409,7 @@ void CDDM_calc_edges(DerivedMesh *dm)
BLI_edgehashIterator_getKey(ehi, &med->v1, &med->v2);
j = GET_INT_FROM_POINTER(BLI_edgehashIterator_getValue(ehi));
- if (j == 0) {
+ if (j == 0 || !eindex) {
med->flag = ME_EDGEDRAW | ME_EDGERENDER;
*index = ORIGINDEX_NONE;
}
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 3e6df3ed77c..28ef3f6f248 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -58,6 +58,7 @@ static void cloth_to_object (Object *ob, ClothModifierData *clmd, float (*verte
static void cloth_from_mesh ( ClothModifierData *clmd, DerivedMesh *dm );
static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float framenr, int first);
static void cloth_update_springs( ClothModifierData *clmd );
+static void cloth_update_verts( Object *ob, ClothModifierData *clmd, DerivedMesh *dm );
static void cloth_update_spring_lengths( ClothModifierData *clmd, DerivedMesh *dm );
static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm );
static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm );
@@ -80,8 +81,10 @@ void cloth_init(ClothModifierData *clmd )
clmd->sim_parms->gravity[1] = 0.0;
clmd->sim_parms->gravity[2] = -9.81;
clmd->sim_parms->structural = 15.0;
+ clmd->sim_parms->max_struct = 15.0;
clmd->sim_parms->shear = 15.0;
clmd->sim_parms->bending = 0.5;
+ clmd->sim_parms->max_bend = 0.5;
clmd->sim_parms->bending_damping = 0.5;
clmd->sim_parms->Cdis = 5.0;
clmd->sim_parms->Cvi = 1.0;
@@ -96,6 +99,7 @@ void cloth_init(ClothModifierData *clmd )
clmd->sim_parms->avg_spring_len = 0.0;
clmd->sim_parms->presets = 2; /* cotton as start setting */
clmd->sim_parms->timescale = 1.0f; /* speed factor, describes how fast cloth moves */
+ clmd->sim_parms->time_scale = 1.0f; /* multiplies cloth speed */
clmd->sim_parms->reset = 0;
clmd->sim_parms->vel_damping = 1.0f; /* 1.0 = no damping, 0.0 = fully dampened */
@@ -368,10 +372,13 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul
effectors = pdInitEffectors(clmd->scene, ob, NULL, clmd->sim_parms->effector_weights, true);
+ if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH )
+ cloth_update_verts ( ob, clmd, result );
+
/* Support for dynamic vertex groups, changing from frame to frame */
cloth_apply_vgroup ( clmd, result );
- if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW )
+ if ( clmd->sim_parms->flags & (CLOTH_SIMSETTINGS_FLAG_SEW | CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH) )
cloth_update_spring_lengths ( clmd, result );
cloth_update_springs( clmd );
@@ -407,7 +414,7 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived
BKE_ptcache_id_from_cloth(&pid, ob, clmd);
BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, &timescale);
- clmd->sim_parms->timescale= timescale;
+ clmd->sim_parms->timescale= timescale * clmd->sim_parms->time_scale;
if (clmd->sim_parms->reset || (clmd->clothObject && dm->getNumVerts(dm) != clmd->clothObject->mvert_num)) {
clmd->sim_parms->reset = 0;
@@ -444,9 +451,12 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived
}
/* try to read from cache */
- cache_result = BKE_ptcache_read(&pid, (float)framenr+scene->r.subframe);
+ bool can_simulate = (framenr == clmd->clothObject->last_frame+1) && !(cache->flag & PTCACHE_BAKED);
+
+ cache_result = BKE_ptcache_read(&pid, (float)framenr+scene->r.subframe, can_simulate);
- if (cache_result == PTCACHE_READ_EXACT || cache_result == PTCACHE_READ_INTERPOLATED) {
+ if (cache_result == PTCACHE_READ_EXACT || cache_result == PTCACHE_READ_INTERPOLATED ||
+ (!can_simulate && cache_result == PTCACHE_READ_OLD)) {
BKE_cloth_solver_set_positions(clmd);
cloth_to_object (ob, clmd, vertexCos);
@@ -468,7 +478,7 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived
return;
}
- if (framenr!=clmd->clothObject->last_frame+1)
+ if (!can_simulate)
return;
/* if on second frame, write cache for first frame */
@@ -804,7 +814,7 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
clmd->clothObject->springs = NULL;
clmd->clothObject->numsprings = -1;
- if ( clmd->sim_parms->shapekey_rest )
+ if ( clmd->sim_parms->shapekey_rest && !(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH ) )
shapekey_rest = dm->getVertDataArray ( dm, CD_CLOTH_ORCO );
mvert = dm->getVertArray (dm);
@@ -1180,6 +1190,20 @@ static void cloth_update_springs( ClothModifierData *clmd )
cloth_hair_update_bending_targets(clmd);
}
+/* Update rest verts, for dynamically deformable cloth */
+static void cloth_update_verts( Object *ob, ClothModifierData *clmd, DerivedMesh *dm )
+{
+ unsigned int i = 0;
+ MVert *mvert = dm->getVertArray (dm);
+ ClothVertex *verts = clmd->clothObject->verts;
+
+ /* vertex count is already ensured to match */
+ for ( i = 0; i < dm->getNumVerts(dm); i++, verts++ ) {
+ copy_v3_v3(verts->xrest, mvert[i].co);
+ mul_m4_v3(ob->obmat, verts->xrest);
+ }
+}
+
/* Update spring rest lenght, for dynamically deformable cloth */
static void cloth_update_spring_lengths( ClothModifierData *clmd, DerivedMesh *dm )
{
diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c
index 8cac856b560..18ca1407ba0 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -71,6 +71,15 @@ void collision_move_object(CollisionModifierData *collmd, float step, float prev
float tv[3] = {0, 0, 0};
unsigned int i = 0;
+ /* the collider doesn't move this frame */
+ if (collmd->is_static) {
+ for (i = 0; i < collmd->mvert_num; i++) {
+ zero_v3(collmd->current_v[i].co);
+ }
+
+ return;
+ }
+
for (i = 0; i < collmd->mvert_num; i++) {
sub_v3_v3v3(tv, collmd->xnew[i].co, collmd->x[i].co);
VECADDS(collmd->current_x[i].co, collmd->x[i].co, tv, prevstep);
@@ -503,12 +512,13 @@ static void add_collision_object(Object ***objs, unsigned int *numobj, unsigned
// return all collision objects in scene
// collision object will exclude self
-Object **get_collisionobjects(Scene *scene, Object *self, Group *group, unsigned int *numcollobj, unsigned int modifier_type)
+Object **get_collisionobjects_ext(Scene *scene, Object *self, Group *group, int layer, unsigned int *numcollobj, unsigned int modifier_type, bool dupli)
{
Base *base;
Object **objs;
GroupObject *go;
unsigned int numobj= 0, maxobj= 100;
+ int level = dupli ? 0 : 1;
objs= MEM_callocN(sizeof(Object *)*maxobj, "CollisionObjectsArray");
@@ -516,16 +526,14 @@ Object **get_collisionobjects(Scene *scene, Object *self, Group *group, unsigned
if (group) {
/* use specified group */
for (go= group->gobject.first; go; go= go->next)
- add_collision_object(&objs, &numobj, &maxobj, go->ob, self, 0, modifier_type);
+ add_collision_object(&objs, &numobj, &maxobj, go->ob, self, level, modifier_type);
}
else {
Scene *sce_iter;
/* add objects in same layer in scene */
for (SETLOOPER(scene, sce_iter, base)) {
- /* Need to check for active layers, too.
- Otherwise this check fails if the objects are not on the same layer - DG */
- if ((base->lay & self->lay) || (base->lay & scene->lay))
- add_collision_object(&objs, &numobj, &maxobj, base->object, self, 0, modifier_type);
+ if ( base->lay & layer )
+ add_collision_object(&objs, &numobj, &maxobj, base->object, self, level, modifier_type);
}
}
@@ -535,6 +543,13 @@ Object **get_collisionobjects(Scene *scene, Object *self, Group *group, unsigned
return objs;
}
+Object **get_collisionobjects(Scene *scene, Object *self, Group *group, unsigned int *numcollobj, unsigned int modifier_type)
+{
+ /* Need to check for active layers, too.
+ Otherwise this check fails if the objects are not on the same layer - DG */
+ return get_collisionobjects_ext(scene, self, group, self->lay | scene->lay, numcollobj, modifier_type, true);
+}
+
static void add_collider_cache_object(ListBase **objs, Object *ob, Object *self, int level)
{
CollisionModifierData *cmd= NULL;
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index bac59c8c62d..4f3ffed41bc 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -43,6 +43,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLI_task.h"
#include "BLI_threads.h"
#include "BKE_colortools.h"
@@ -53,10 +54,6 @@
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
-#ifdef _OPENMP
-# include <omp.h>
-#endif
-
/* ********************************* color curve ********************* */
/* ***************** operations on full struct ************* */
@@ -296,8 +293,8 @@ void curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope)
cuma->curve[1].x = clipr->xmax;
cuma->curve[1].y = clipr->ymin;
if (slope == CURVEMAP_SLOPE_POS_NEG) {
- cuma->curve[0].flag |= CUMA_VECTOR;
- cuma->curve[1].flag |= CUMA_VECTOR;
+ cuma->curve[0].flag |= CUMA_HANDLE_VECTOR;
+ cuma->curve[1].flag |= CUMA_HANDLE_VECTOR;
}
break;
case CURVE_PRESET_SHARP:
@@ -394,15 +391,25 @@ void curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope)
}
}
-/* if type==1: vector, else auto */
-void curvemap_sethandle(CurveMap *cuma, int type)
+/**
+ * \param type: eBezTriple_Handle
+ */
+void curvemap_handle_set(CurveMap *cuma, int type)
{
int a;
for (a = 0; a < cuma->totpoint; a++) {
if (cuma->curve[a].flag & CUMA_SELECT) {
- if (type) cuma->curve[a].flag |= CUMA_VECTOR;
- else cuma->curve[a].flag &= ~CUMA_VECTOR;
+ cuma->curve[a].flag &= ~(CUMA_HANDLE_VECTOR | CUMA_HANDLE_AUTO_ANIM);
+ if (type == HD_VECT) {
+ cuma->curve[a].flag |= CUMA_HANDLE_VECTOR;
+ }
+ else if (type == HD_AUTO_ANIM) {
+ cuma->curve[a].flag |= CUMA_HANDLE_AUTO_ANIM;
+ }
+ else {
+ /* pass */
+ }
}
}
}
@@ -460,7 +467,7 @@ static void calchandle_curvemap(
if (len_a == 0.0f) len_a = 1.0f;
if (len_b == 0.0f) len_b = 1.0f;
- if (bezt->h1 == HD_AUTO || bezt->h2 == HD_AUTO) { /* auto */
+ if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) || ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) { /* auto */
float tvec[2];
tvec[0] = dvec_b[0] / len_b + dvec_a[0] / len_a;
tvec[1] = dvec_b[1] / len_b + dvec_a[1] / len_a;
@@ -468,13 +475,57 @@ static void calchandle_curvemap(
len = len_v2(tvec) * 2.5614f;
if (len != 0.0f) {
- if (bezt->h1 == HD_AUTO) {
+ if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM)) {
len_a /= len;
madd_v2_v2v2fl(p2_h1, p2, tvec, -len_a);
+
+ if ((bezt->h1 == HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */
+ const float ydiff1 = prev->vec[1][1] - bezt->vec[1][1];
+ const float ydiff2 = next->vec[1][1] - bezt->vec[1][1];
+ if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f) ||
+ (ydiff1 >= 0.0f && ydiff2 >= 0.0f))
+ {
+ bezt->vec[0][1] = bezt->vec[1][1];
+ }
+ else { /* handles should not be beyond y coord of two others */
+ if (ydiff1 <= 0.0f) {
+ if (prev->vec[1][1] > bezt->vec[0][1]) {
+ bezt->vec[0][1] = prev->vec[1][1];
+ }
+ }
+ else {
+ if (prev->vec[1][1] < bezt->vec[0][1]) {
+ bezt->vec[0][1] = prev->vec[1][1];
+ }
+ }
+ }
+ }
}
- if (bezt->h2 == HD_AUTO) {
+ if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) {
len_b /= len;
madd_v2_v2v2fl(p2_h2, p2, tvec, len_b);
+
+ if ((bezt->h2 == HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */
+ const float ydiff1 = prev->vec[1][1] - bezt->vec[1][1];
+ const float ydiff2 = next->vec[1][1] - bezt->vec[1][1];
+ if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f)||
+ (ydiff1 >= 0.0f && ydiff2 >= 0.0f))
+ {
+ bezt->vec[2][1] = bezt->vec[1][1];
+ }
+ else { /* handles should not be beyond y coord of two others */
+ if (ydiff1 <= 0.0f) {
+ if (next->vec[1][1] < bezt->vec[2][1]) {
+ bezt->vec[2][1] = next->vec[1][1];
+ }
+ }
+ else {
+ if (next->vec[1][1] > bezt->vec[2][1]) {
+ bezt->vec[2][1] = next->vec[1][1];
+ }
+ }
+ }
+ }
}
}
}
@@ -543,10 +594,15 @@ static void curvemap_make_table(CurveMap *cuma, const rctf *clipr)
cuma->maxtable = max_ff(cuma->maxtable, cmp[a].x);
bezt[a].vec[1][0] = cmp[a].x;
bezt[a].vec[1][1] = cmp[a].y;
- if (cmp[a].flag & CUMA_VECTOR)
+ if (cmp[a].flag & CUMA_HANDLE_VECTOR) {
bezt[a].h1 = bezt[a].h2 = HD_VECT;
- else
+ }
+ else if (cmp[a].flag & CUMA_HANDLE_AUTO_ANIM) {
+ bezt[a].h1 = bezt[a].h2 = HD_AUTO_ANIM;
+ }
+ else {
bezt[a].h1 = bezt[a].h2 = HD_AUTO;
+ }
}
const BezTriple *bezt_prev = NULL;
@@ -776,12 +832,12 @@ void curvemapping_changed(CurveMapping *cumap, const bool rem_doubles)
dy = cmp[a].y - cmp[a + 1].y;
if (sqrtf(dx * dx + dy * dy) < thresh) {
if (a == 0) {
- cmp[a + 1].flag |= CUMA_VECTOR;
+ cmp[a + 1].flag |= CUMA_HANDLE_VECTOR;
if (cmp[a + 1].flag & CUMA_SELECT)
cmp[a].flag |= CUMA_SELECT;
}
else {
- cmp[a].flag |= CUMA_VECTOR;
+ cmp[a].flag |= CUMA_HANDLE_VECTOR;
if (cmp[a].flag & CUMA_SELECT)
cmp[a + 1].flag |= CUMA_SELECT;
}
@@ -985,6 +1041,7 @@ static void save_sample_line(Scopes *scopes, const int idx, const float fx, cons
/* waveform */
switch (scopes->wavefrm_mode) {
case SCOPES_WAVEFRM_RGB:
+ case SCOPES_WAVEFRM_RGB_PARADE:
scopes->waveform_1[idx + 0] = fx;
scopes->waveform_1[idx + 1] = rgb[0];
scopes->waveform_2[idx + 0] = fx;
@@ -1089,31 +1146,170 @@ void BKE_histogram_update_sample_line(Histogram *hist, ImBuf *ibuf, const ColorM
}
/* if view_settings, it also applies this to byte buffers */
+typedef struct ScopesUpdateData {
+ Scopes *scopes;
+ const ImBuf *ibuf;
+ struct ColormanageProcessor *cm_processor;
+ const unsigned char *display_buffer;
+ const int ycc_mode;
+
+ unsigned int *bin_lum, *bin_r, *bin_g, *bin_b, *bin_a;
+} ScopesUpdateData;
+
+typedef struct ScopesUpdateDataChunk {
+ unsigned int bin_lum[256];
+ unsigned int bin_r[256];
+ unsigned int bin_g[256];
+ unsigned int bin_b[256];
+ unsigned int bin_a[256];
+ float min[3], max[3];
+} ScopesUpdateDataChunk;
+
+static void scopes_update_cb(void *userdata, void *userdata_chunk, const int y, const int UNUSED(threadid))
+{
+ const ScopesUpdateData *data = userdata;
+
+ Scopes *scopes = data->scopes;
+ const ImBuf *ibuf = data->ibuf;
+ struct ColormanageProcessor *cm_processor = data->cm_processor;
+ const unsigned char *display_buffer = data->display_buffer;
+ const int ycc_mode = data->ycc_mode;
+
+ ScopesUpdateDataChunk *data_chunk = userdata_chunk;
+ unsigned int *bin_lum = data_chunk->bin_lum;
+ unsigned int *bin_r = data_chunk->bin_r;
+ unsigned int *bin_g = data_chunk->bin_g;
+ unsigned int *bin_b = data_chunk->bin_b;
+ unsigned int *bin_a = data_chunk->bin_a;
+ float *min = data_chunk->min;
+ float *max = data_chunk->max;
+
+ const float *rf = NULL;
+ const unsigned char *rc = NULL;
+ const int rows_per_sample_line = ibuf->y / scopes->sample_lines;
+ const int savedlines = y / rows_per_sample_line;
+ const bool do_sample_line = (savedlines < scopes->sample_lines) && (y % rows_per_sample_line) == 0;
+ const bool is_float = (ibuf->rect_float != NULL);
+
+ if (is_float)
+ rf = ibuf->rect_float + ((size_t)y) * ibuf->x * ibuf->channels;
+ else {
+ rc = display_buffer + ((size_t)y) * ibuf->x * ibuf->channels;
+ }
+
+ for (int x = 0; x < ibuf->x; x++) {
+ float rgba[4], ycc[3], luma;
+
+ if (is_float) {
+ switch (ibuf->channels) {
+ case 4:
+ copy_v4_v4(rgba, rf);
+ IMB_colormanagement_processor_apply_v4(cm_processor, rgba);
+ break;
+ case 3:
+ copy_v3_v3(rgba, rf);
+ IMB_colormanagement_processor_apply_v3(cm_processor, rgba);
+ rgba[3] = 1.0f;
+ break;
+ case 2:
+ copy_v3_fl(rgba, rf[0]);
+ rgba[3] = rf[1];
+ break;
+ case 1:
+ copy_v3_fl(rgba, rf[0]);
+ rgba[3] = 1.0f;
+ break;
+ default:
+ BLI_assert(0);
+ }
+ }
+ else {
+ for (int c = 4; c--;)
+ rgba[c] = rc[c] * INV_255;
+ }
+
+ /* we still need luma for histogram */
+ luma = IMB_colormanagement_get_luminance(rgba);
+
+ /* check for min max */
+ if (ycc_mode == -1) {
+ minmax_v3v3_v3(min, max, rgba);
+ }
+ else {
+ rgb_to_ycc(rgba[0], rgba[1], rgba[2], &ycc[0], &ycc[1], &ycc[2], ycc_mode);
+ mul_v3_fl(ycc, INV_255);
+ minmax_v3v3_v3(min, max, ycc);
+ }
+ /* increment count for histo*/
+ bin_lum[get_bin_float(luma)]++;
+ bin_r[get_bin_float(rgba[0])]++;
+ bin_g[get_bin_float(rgba[1])]++;
+ bin_b[get_bin_float(rgba[2])]++;
+ bin_a[get_bin_float(rgba[3])]++;
+
+ /* save sample if needed */
+ if (do_sample_line) {
+ const float fx = (float)x / (float)ibuf->x;
+ const int idx = 2 * (ibuf->x * savedlines + x);
+ save_sample_line(scopes, idx, fx, rgba, ycc);
+ }
+
+ rf += ibuf->channels;
+ rc += ibuf->channels;
+ }
+}
+
+static void scopes_update_finalize(void *userdata, void *userdata_chunk)
+{
+ const ScopesUpdateData *data = userdata;
+ const ScopesUpdateDataChunk *data_chunk = userdata_chunk;
+
+ unsigned int *bin_lum = data->bin_lum;
+ unsigned int *bin_r = data->bin_r;
+ unsigned int *bin_g = data->bin_g;
+ unsigned int *bin_b = data->bin_b;
+ unsigned int *bin_a = data->bin_a;
+ const unsigned int *bin_lum_c = data_chunk->bin_lum;
+ const unsigned int *bin_r_c = data_chunk->bin_r;
+ const unsigned int *bin_g_c = data_chunk->bin_g;
+ const unsigned int *bin_b_c = data_chunk->bin_b;
+ const unsigned int *bin_a_c = data_chunk->bin_a;
+
+ float (*minmax)[2] = data->scopes->minmax;
+ const float *min = data_chunk->min;
+ const float *max = data_chunk->max;
+
+ for (int b = 256; b--;) {
+ bin_lum[b] += bin_lum_c[b];
+ bin_r[b] += bin_r_c[b];
+ bin_g[b] += bin_g_c[b];
+ bin_b[b] += bin_b_c[b];
+ bin_a[b] += bin_a_c[b];
+ }
+
+ for (int c = 3; c--;) {
+ if (min[c] < minmax[c][0])
+ minmax[c][0] = min[c];
+ if (max[c] > minmax[c][1])
+ minmax[c][1] = max[c];
+ }
+}
+
void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *view_settings,
const ColorManagedDisplaySettings *display_settings)
{
-#ifdef _OPENMP
- const int num_threads = BLI_system_thread_count();
-#endif
- int a, y;
+ int a;
unsigned int nl, na, nr, ng, nb;
double divl, diva, divr, divg, divb;
- unsigned char *display_buffer;
+ const unsigned char *display_buffer = NULL;
unsigned int bin_lum[256] = {0},
bin_r[256] = {0},
bin_g[256] = {0},
bin_b[256] = {0},
bin_a[256] = {0};
- unsigned int bin_lum_t[BLENDER_MAX_THREADS][256] = {{0}},
- bin_r_t[BLENDER_MAX_THREADS][256] = {{0}},
- bin_g_t[BLENDER_MAX_THREADS][256] = {{0}},
- bin_b_t[BLENDER_MAX_THREADS][256] = {{0}},
- bin_a_t[BLENDER_MAX_THREADS][256] = {{0}};
int ycc_mode = -1;
- const bool is_float = (ibuf->rect_float != NULL);
void *cache_handle = NULL;
struct ColormanageProcessor *cm_processor = NULL;
- int rows_per_sample_line;
if (ibuf->rect == NULL && ibuf->rect_float == NULL) return;
@@ -1129,6 +1325,8 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *
switch (scopes->wavefrm_mode) {
case SCOPES_WAVEFRM_RGB:
+ /* fall-through */
+ case SCOPES_WAVEFRM_RGB_PARADE:
ycc_mode = -1;
break;
case SCOPES_WAVEFRM_LUMA:
@@ -1151,7 +1349,6 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *
scopes->sample_lines = ibuf->y;
/* scan the image */
- rows_per_sample_line = ibuf->y / scopes->sample_lines;
for (a = 0; a < 3; a++) {
scopes->minmax[a][0] = 25500.0f;
scopes->minmax[a][1] = -25500.0f;
@@ -1177,129 +1374,21 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *
cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
}
else {
- display_buffer = (unsigned char *)IMB_display_buffer_acquire(ibuf,
- view_settings,
- display_settings,
- &cache_handle);
+ display_buffer = (const unsigned char *)IMB_display_buffer_acquire(
+ ibuf, view_settings, display_settings, &cache_handle);
}
/* Keep number of threads in sync with the merge parts below. */
-#pragma omp parallel for private(y) schedule(static) num_threads(num_threads) if (ibuf->y > 256)
- for (y = 0; y < ibuf->y; y++) {
-#ifdef _OPENMP
- const int thread_idx = omp_get_thread_num();
-#else
- const int thread_idx = 0;
-#endif
- const float *rf = NULL;
- const unsigned char *rc = NULL;
- const int savedlines = y / rows_per_sample_line;
- const bool do_sample_line = (savedlines < scopes->sample_lines) && (y % rows_per_sample_line) == 0;
- float min[3] = { FLT_MAX, FLT_MAX, FLT_MAX},
- max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
- int x, c;
- if (is_float)
- rf = ibuf->rect_float + ((size_t)y) * ibuf->x * ibuf->channels;
- else {
- rc = display_buffer + ((size_t)y) * ibuf->x * ibuf->channels;
- }
- for (x = 0; x < ibuf->x; x++) {
- float rgba[4], ycc[3], luma;
- if (is_float) {
-
- switch (ibuf->channels) {
- case 4:
- copy_v4_v4(rgba, rf);
- IMB_colormanagement_processor_apply_v4(cm_processor, rgba);
- break;
- case 3:
- copy_v3_v3(rgba, rf);
- IMB_colormanagement_processor_apply_v3(cm_processor, rgba);
- rgba[3] = 1.0f;
- break;
- case 2:
- copy_v3_fl(rgba, rf[0]);
- rgba[3] = rf[1];
- break;
- case 1:
- copy_v3_fl(rgba, rf[0]);
- rgba[3] = 1.0f;
- break;
- default:
- BLI_assert(0);
- }
- }
- else {
- for (c = 0; c < 4; c++)
- rgba[c] = rc[c] * INV_255;
- }
-
- /* we still need luma for histogram */
- luma = IMB_colormanagement_get_luminance(rgba);
-
- /* check for min max */
- if (ycc_mode == -1) {
- for (c = 0; c < 3; c++) {
- if (rgba[c] < min[c]) min[c] = rgba[c];
- if (rgba[c] > max[c]) max[c] = rgba[c];
- }
- }
- else {
- rgb_to_ycc(rgba[0], rgba[1], rgba[2], &ycc[0], &ycc[1], &ycc[2], ycc_mode);
- for (c = 0; c < 3; c++) {
- ycc[c] *= INV_255;
- if (ycc[c] < min[c]) min[c] = ycc[c];
- if (ycc[c] > max[c]) max[c] = ycc[c];
- }
- }
- /* increment count for histo*/
- bin_lum_t[thread_idx][get_bin_float(luma)] += 1;
- bin_r_t[thread_idx][get_bin_float(rgba[0])] += 1;
- bin_g_t[thread_idx][get_bin_float(rgba[1])] += 1;
- bin_b_t[thread_idx][get_bin_float(rgba[2])] += 1;
- bin_a_t[thread_idx][get_bin_float(rgba[3])] += 1;
-
- /* save sample if needed */
- if (do_sample_line) {
- const float fx = (float)x / (float)ibuf->x;
- const int idx = 2 * (ibuf->x * savedlines + x);
- save_sample_line(scopes, idx, fx, rgba, ycc);
- }
-
- rf += ibuf->channels;
- rc += ibuf->channels;
- }
-#pragma omp critical
- {
- for (c = 0; c < 3; c++) {
- if (min[c] < scopes->minmax[c][0]) scopes->minmax[c][0] = min[c];
- if (max[c] > scopes->minmax[c][1]) scopes->minmax[c][1] = max[c];
- }
- }
- }
-
-#ifdef _OPENMP
- if (ibuf->y > 256) {
- for (a = 0; a < num_threads; a++) {
- int b;
- for (b = 0; b < 256; b++) {
- bin_lum[b] += bin_lum_t[a][b];
- bin_r[b] += bin_r_t[a][b];
- bin_g[b] += bin_g_t[a][b];
- bin_b[b] += bin_b_t[a][b];
- bin_a[b] += bin_a_t[a][b];
- }
- }
- }
- else
-#endif
- {
- memcpy(bin_lum, bin_lum_t[0], sizeof(bin_lum));
- memcpy(bin_r, bin_r_t[0], sizeof(bin_r));
- memcpy(bin_g, bin_g_t[0], sizeof(bin_g));
- memcpy(bin_b, bin_b_t[0], sizeof(bin_b));
- memcpy(bin_a, bin_a_t[0], sizeof(bin_a));
- }
+ ScopesUpdateData data = {
+ .scopes = scopes, . ibuf = ibuf,
+ .cm_processor = cm_processor, .display_buffer = display_buffer, .ycc_mode = ycc_mode,
+ .bin_lum = bin_lum, .bin_r = bin_r, .bin_g = bin_g, .bin_b = bin_b, .bin_a = bin_a,
+ };
+ ScopesUpdateDataChunk data_chunk = {{0}};
+ INIT_MINMAX(data_chunk.min, data_chunk.max);
+
+ BLI_task_parallel_range_finalize(0, ibuf->y, &data, &data_chunk, sizeof(data_chunk),
+ scopes_update_cb, scopes_update_finalize, ibuf->y > 256, false);
/* test for nicer distribution even - non standard, leave it out for a while */
#if 0
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 7144e25ba7f..b85f1b838ff 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -46,6 +46,7 @@
#include "BLT_translation.h"
#include "DNA_armature_types.h"
+#include "DNA_cachefile_types.h"
#include "DNA_constraint_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
@@ -63,6 +64,7 @@
#include "BKE_anim.h" /* for the curve calculation part */
#include "BKE_armature.h"
#include "BKE_bvhutils.h"
+#include "BKE_cachefile.h"
#include "BKE_camera.h"
#include "BKE_constraint.h"
#include "BKE_curve.h"
@@ -86,6 +88,10 @@
# include "BPY_extern.h"
#endif
+#ifdef WITH_ALEMBIC
+# include "ABC_alembic.h"
+#endif
+
/* ---------------------------------------------------------------------------- */
/* Useful macros for testing various common flag combinations */
@@ -535,7 +541,7 @@ static void contarget_get_lattice_mat(Object *ob, const char *substring, float m
/* generic function to get the appropriate matrix for most target cases */
/* The cases where the target can be object data have not been implemented */
-static void constraint_target_to_mat4(Object *ob, const char *substring, float mat[4][4], short from, short to, float headtail)
+static void constraint_target_to_mat4(Object *ob, const char *substring, float mat[4][4], short from, short to, short flag, float headtail)
{
/* Case OBJECT */
if (substring[0] == '\0') {
@@ -573,6 +579,58 @@ static void constraint_target_to_mat4(Object *ob, const char *substring, float m
/* skip length interpolation if set to head */
mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat);
}
+ else if ((pchan->bone) && (pchan->bone->segments > 1) && (flag & CONSTRAINT_BBONE_SHAPE)) {
+ /* use point along bbone */
+ Mat4 bbone[MAX_BBONE_SUBDIV];
+ float tempmat[4][4];
+ float loc[3], fac;
+
+ /* get bbone segments */
+ b_bone_spline_setup(pchan, 0, bbone);
+
+ /* figure out which segment(s) the headtail value falls in */
+ fac = (float)pchan->bone->segments * headtail;
+
+ if (fac >= pchan->bone->segments - 1) {
+ /* special case: end segment doesn't get created properly... */
+ float pt[3], sfac;
+ int index;
+
+ /* bbone points are in bonespace, so need to move to posespace first */
+ index = pchan->bone->segments - 1;
+ mul_v3_m4v3(pt, pchan->pose_mat, bbone[index].mat[3]);
+
+ /* interpolate between last segment point and the endpoint */
+ sfac = fac - (float)(pchan->bone->segments - 1); /* fac is just the "leftover" between penultimate and last points */
+ interp_v3_v3v3(loc, pt, pchan->pose_tail, sfac);
+ }
+ else {
+ /* get indices for finding interpolating between points along the bbone */
+ float pt_a[3], pt_b[3], pt[3];
+ int index_a, index_b;
+
+ index_a = floorf(fac);
+ CLAMP(index_a, 0, MAX_BBONE_SUBDIV - 1);
+
+ index_b = ceilf(fac);
+ CLAMP(index_b, 0, MAX_BBONE_SUBDIV - 1);
+
+ /* interpolate between these points */
+ copy_v3_v3(pt_a, bbone[index_a].mat[3]);
+ copy_v3_v3(pt_b, bbone[index_b].mat[3]);
+
+ interp_v3_v3v3(pt, pt_a, pt_b, fac - floorf(fac));
+
+ /* move the point from bone local space to pose space... */
+ mul_v3_m4v3(loc, pchan->pose_mat, pt);
+ }
+
+ /* use interpolated distance for subtarget */
+ copy_m4_m4(tempmat, pchan->pose_mat);
+ copy_v3_v3(tempmat[3], loc);
+
+ mul_m4_m4m4(mat, ob->obmat, tempmat);
+ }
else {
float tempmat[4][4], loc[3];
@@ -634,7 +692,7 @@ static bConstraintTypeInfo CTI_CONSTRNAME = {
static void default_get_tarmat(bConstraint *con, bConstraintOb *UNUSED(cob), bConstraintTarget *ct, float UNUSED(ctime))
{
if (VALID_CONS_TARGET(ct))
- constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail);
+ constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail);
else if (ct)
unit_m4(ct->matrix);
}
@@ -1102,7 +1160,7 @@ static void kinematic_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstrai
bKinematicConstraint *data = con->data;
if (VALID_CONS_TARGET(ct))
- constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail);
+ constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail);
else if (ct) {
if (data->flag & CONSTRAINT_IK_AUTO) {
Object *ob = cob->ob;
@@ -1985,7 +2043,7 @@ static void pycon_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTa
/* firstly calculate the matrix the normal way, then let the py-function override
* this matrix if it needs to do so
*/
- constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail);
+ constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail);
/* only execute target calculation if allowed */
#ifdef WITH_PYTHON
@@ -2097,7 +2155,7 @@ static void actcon_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintT
unit_m4(ct->matrix);
/* get the transform matrix of the target */
- constraint_target_to_mat4(ct->tar, ct->subtarget, tempmat, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail);
+ constraint_target_to_mat4(ct->tar, ct->subtarget, tempmat, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail);
/* determine where in transform range target is */
/* data->type is mapped as follows for backwards compatibility:
@@ -2143,7 +2201,7 @@ static void actcon_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintT
}
else if (cob->type == CONSTRAINT_OBTYPE_BONE) {
Object workob;
- bPose pose = {0};
+ bPose pose = {{0}};
bPoseChannel *pchan, *tchan;
/* make a copy of the bone of interest in the temp pose before evaluating action, so that it can get set
@@ -4281,6 +4339,96 @@ static bConstraintTypeInfo CTI_OBJECTSOLVER = {
objectsolver_evaluate /* evaluate */
};
+/* ----------- Transform Cache ------------- */
+
+static void transformcache_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
+{
+ bTransformCacheConstraint *data = con->data;
+ func(con, (ID **)&data->cache_file, true, userdata);
+}
+
+static void transformcache_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets)
+{
+#ifdef WITH_ALEMBIC
+ bTransformCacheConstraint *data = con->data;
+ Scene *scene = cob->scene;
+
+ CacheFile *cache_file = data->cache_file;
+
+ if (!cache_file) {
+ return;
+ }
+
+ const float frame = BKE_scene_frame_get(scene);
+ const float time = BKE_cachefile_time_offset(cache_file, frame, FPS);
+
+ BKE_cachefile_ensure_handle(G.main, cache_file);
+
+ if (!data->reader) {
+ data->reader = CacheReader_open_alembic_object(cache_file->handle,
+ data->reader,
+ cob->ob,
+ data->object_path);
+ }
+
+ ABC_get_transform(data->reader, cob->matrix, time, cache_file->scale);
+#else
+ UNUSED_VARS(con, cob);
+#endif
+
+ UNUSED_VARS(targets);
+}
+
+static void transformcache_copy(bConstraint *con, bConstraint *srccon)
+{
+ bTransformCacheConstraint *src = srccon->data;
+ bTransformCacheConstraint *dst = con->data;
+
+ BLI_strncpy(dst->object_path, src->object_path, sizeof(dst->object_path));
+ dst->cache_file = src->cache_file;
+
+ if (dst->cache_file) {
+ id_us_plus(&dst->cache_file->id);
+ }
+}
+
+static void transformcache_free(bConstraint *con)
+{
+ bTransformCacheConstraint *data = con->data;
+
+ if (data->cache_file) {
+ id_us_min(&data->cache_file->id);
+ }
+
+ if (data->reader) {
+#ifdef WITH_ALEMBIC
+ CacheReader_free(data->reader);
+#endif
+ }
+}
+
+static void transformcache_new_data(void *cdata)
+{
+ bTransformCacheConstraint *data = (bTransformCacheConstraint *)cdata;
+
+ data->cache_file = NULL;
+}
+
+static bConstraintTypeInfo CTI_TRANSFORM_CACHE = {
+ CONSTRAINT_TYPE_TRANSFORM_CACHE, /* type */
+ sizeof(bTransformCacheConstraint), /* size */
+ "Transform Cache", /* name */
+ "bTransformCacheConstraint", /* struct name */
+ transformcache_free, /* free data */
+ transformcache_id_looper, /* id looper */
+ transformcache_copy, /* copy data */
+ transformcache_new_data, /* new data */
+ NULL, /* get constraint targets */
+ NULL, /* flush constraint targets */
+ NULL, /* get target matrix */
+ transformcache_evaluate /* evaluate */
+};
+
/* ************************* Constraints Type-Info *************************** */
/* All of the constraints api functions use bConstraintTypeInfo structs to carry out
* and operations that involve constraint specific code.
@@ -4322,6 +4470,7 @@ static void constraints_init_typeinfo(void)
constraintsTypeInfo[26] = &CTI_FOLLOWTRACK; /* Follow Track Constraint */
constraintsTypeInfo[27] = &CTI_CAMERASOLVER; /* Camera Solver Constraint */
constraintsTypeInfo[28] = &CTI_OBJECTSOLVER; /* Object Solver Constraint */
+ constraintsTypeInfo[29] = &CTI_TRANSFORM_CACHE; /* Transform Cache Constraint */
}
/* This function should be used for getting the appropriate type-info when only
@@ -4597,7 +4746,7 @@ void BKE_constraints_id_loop(ListBase *conlist, ConstraintIDFunc func, void *use
/* helper for BKE_constraints_copy(), to be used for making sure that ID's are valid */
static void con_extern_cb(bConstraint *UNUSED(con), ID **idpoin, bool UNUSED(is_reference), void *UNUSED(userData))
{
- if (*idpoin && (*idpoin)->lib)
+ if (*idpoin && ID_IS_LINKED_DATABLOCK(*idpoin))
id_lib_extern(*idpoin);
}
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index 5b7698544e0..4c01bfd35f2 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -49,6 +49,7 @@
#include "BKE_context.h"
#include "BKE_main.h"
#include "BKE_screen.h"
+#include "BKE_sound.h"
#include "RNA_access.h"
@@ -882,6 +883,7 @@ Main *CTX_data_main(const bContext *C)
void CTX_data_main_set(bContext *C, Main *bmain)
{
C->data.main = bmain;
+ BKE_sound_init_main(bmain);
}
Scene *CTX_data_scene(const bContext *C)
@@ -1067,6 +1069,11 @@ struct EditBone *CTX_data_active_bone(const bContext *C)
return ctx_data_pointer_get(C, "active_bone");
}
+struct CacheFile *CTX_data_edit_cachefile(const bContext *C)
+{
+ return ctx_data_pointer_get(C, "edit_cachefile");
+}
+
int CTX_data_selected_bones(const bContext *C, ListBase *list)
{
return ctx_data_collection_get(C, "selected_bones", list);
@@ -1112,6 +1119,21 @@ bGPDlayer *CTX_data_active_gpencil_layer(const bContext *C)
return ctx_data_pointer_get(C, "active_gpencil_layer");
}
+bGPDpalette *CTX_data_active_gpencil_palette(const bContext *C)
+{
+ return ctx_data_pointer_get(C, "active_gpencil_palette");
+}
+
+bGPDpalettecolor *CTX_data_active_gpencil_palettecolor(const bContext *C)
+{
+ return ctx_data_pointer_get(C, "active_gpencil_palettecolor");
+}
+
+bGPDbrush *CTX_data_active_gpencil_brush(const bContext *C)
+{
+ return ctx_data_pointer_get(C, "active_gpencil_brush");
+}
+
bGPDframe *CTX_data_active_gpencil_frame(const bContext *C)
{
return ctx_data_pointer_get(C, "active_gpencil_frame");
diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c
index c8de0786697..56df8e51eba 100644
--- a/source/blender/blenkernel/intern/crazyspace.c
+++ b/source/blender/blenkernel/intern/crazyspace.c
@@ -39,6 +39,7 @@
#include "DNA_meshdata_types.h"
#include "BLI_utildefines.h"
+#include "BLI_linklist.h"
#include "BLI_math.h"
#include "BKE_crazyspace.h"
@@ -275,7 +276,13 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(Scene *scene, Object *ob,
if (mti->type == eModifierTypeType_OnlyDeform && mti->deformMatricesEM) {
if (!defmats) {
- dm = getEditDerivedBMesh(em, ob, NULL);
+ const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
+ CustomDataMask data_mask = CD_MASK_BAREMESH;
+ CDMaskLink *datamasks = modifiers_calcDataMasks(scene, ob, md, data_mask, required_mode, NULL, 0);
+ data_mask = datamasks->mask;
+ BLI_linklist_free((LinkNode *)datamasks, NULL);
+
+ dm = getEditDerivedBMesh(em, ob, data_mask, NULL);
deformedVerts = editbmesh_get_vertex_cos(em, &numVerts);
defmats = MEM_mallocN(sizeof(*defmats) * numVerts, "defmats");
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index 8afb451f768..90a514781d7 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -58,6 +58,8 @@
#include "BKE_global.h"
#include "BKE_key.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_material.h"
@@ -69,36 +71,6 @@ static int cu_isectLL(const float v1[3], const float v2[3], const float v3[3], c
short cox, short coy,
float *lambda, float *mu, float vec[3]);
-void BKE_curve_unlink(Curve *cu)
-{
- int a;
-
- for (a = 0; a < cu->totcol; a++) {
- if (cu->mat[a])
- id_us_min(&cu->mat[a]->id);
- cu->mat[a] = NULL;
- }
- if (cu->vfont)
- id_us_min(&cu->vfont->id);
- cu->vfont = NULL;
-
- if (cu->vfontb)
- id_us_min(&cu->vfontb->id);
- cu->vfontb = NULL;
-
- if (cu->vfonti)
- id_us_min(&cu->vfonti->id);
- cu->vfonti = NULL;
-
- if (cu->vfontbi)
- id_us_min(&cu->vfontbi->id);
- cu->vfontbi = NULL;
-
- if (cu->key)
- id_us_min(&cu->key->id);
- cu->key = NULL;
-}
-
/* frees editcurve entirely */
void BKE_curve_editfont_free(Curve *cu)
{
@@ -136,26 +108,21 @@ void BKE_curve_editNurb_free(Curve *cu)
}
}
-/* don't free curve itself */
+/** Free (or release) any data used by this curve (does not free the curve itself). */
void BKE_curve_free(Curve *cu)
{
+ BKE_animdata_free((ID *)cu, false);
+
BKE_nurbList_free(&cu->nurb);
BKE_curve_editfont_free(cu);
BKE_curve_editNurb_free(cu);
- BKE_curve_unlink(cu);
- BKE_animdata_free((ID *)cu);
-
- if (cu->mat)
- MEM_freeN(cu->mat);
- if (cu->str)
- MEM_freeN(cu->str);
- if (cu->strinfo)
- MEM_freeN(cu->strinfo);
- if (cu->bb)
- MEM_freeN(cu->bb);
- if (cu->tb)
- MEM_freeN(cu->tb);
+
+ MEM_SAFE_FREE(cu->mat);
+ MEM_SAFE_FREE(cu->str);
+ MEM_SAFE_FREE(cu->strinfo);
+ MEM_SAFE_FREE(cu->bb);
+ MEM_SAFE_FREE(cu->tb);
}
void BKE_curve_init(Curve *cu)
@@ -207,12 +174,13 @@ Curve *BKE_curve_add(Main *bmain, const char *name, int type)
return cu;
}
-Curve *BKE_curve_copy(Curve *cu)
+Curve *BKE_curve_copy(Main *bmain, Curve *cu)
{
Curve *cun;
int a;
- cun = BKE_libblock_copy(&cu->id);
+ cun = BKE_libblock_copy(bmain, &cu->id);
+
BLI_listbase_clear(&cun->nurb);
BKE_nurbList_duplicate(&(cun->nurb), &(cu->nurb));
@@ -226,88 +194,27 @@ Curve *BKE_curve_copy(Curve *cu)
cun->tb = MEM_dupallocN(cu->tb);
cun->bb = MEM_dupallocN(cu->bb);
- cun->key = BKE_key_copy(cu->key);
- if (cun->key) cun->key->from = (ID *)cun;
+ if (cu->key) {
+ cun->key = BKE_key_copy(bmain, cu->key);
+ cun->key->from = (ID *)cun;
+ }
cun->editnurb = NULL;
cun->editfont = NULL;
-#if 0 // XXX old animation system
- /* single user ipo too */
- if (cun->ipo) cun->ipo = copy_ipo(cun->ipo);
-#endif // XXX old animation system
-
id_us_plus((ID *)cun->vfont);
id_us_plus((ID *)cun->vfontb);
id_us_plus((ID *)cun->vfonti);
id_us_plus((ID *)cun->vfontbi);
- if (cu->id.lib) {
- BKE_id_lib_local_paths(G.main, cu->id.lib, &cun->id);
- }
+ BKE_id_copy_ensure_local(bmain, &cu->id, &cun->id);
return cun;
}
-static void extern_local_curve(Curve *cu)
-{
- id_lib_extern((ID *)cu->vfont);
- id_lib_extern((ID *)cu->vfontb);
- id_lib_extern((ID *)cu->vfonti);
- id_lib_extern((ID *)cu->vfontbi);
-
- if (cu->mat) {
- extern_local_matarar(cu->mat, cu->totcol);
- }
-}
-
-void BKE_curve_make_local(Curve *cu)
+void BKE_curve_make_local(Main *bmain, Curve *cu, const bool lib_local)
{
- Main *bmain = G.main;
- Object *ob;
- bool is_local = false, is_lib = false;
-
- /* - when there are only lib users: don't do
- * - when there are only local users: set flag
- * - mixed: do a copy
- */
-
- if (cu->id.lib == NULL)
- return;
-
- if (cu->id.us == 1) {
- id_clear_lib_data(bmain, &cu->id);
- extern_local_curve(cu);
- return;
- }
-
- for (ob = bmain->object.first; ob && ELEM(0, is_lib, is_local); ob = ob->id.next) {
- if (ob->data == cu) {
- if (ob->id.lib) is_lib = true;
- else is_local = true;
- }
- }
-
- if (is_local && is_lib == false) {
- id_clear_lib_data(bmain, &cu->id);
- extern_local_curve(cu);
- }
- else if (is_local && is_lib) {
- Curve *cu_new = BKE_curve_copy(cu);
- cu_new->id.us = 0;
-
- BKE_id_lib_local_paths(bmain, cu->id.lib, &cu_new->id);
-
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- if (ob->data == cu) {
- if (ob->id.lib == NULL) {
- ob->data = cu_new;
- id_us_plus(&cu_new->id);
- id_us_min(&cu->id);
- }
- }
- }
- }
+ BKE_id_make_local_generic(bmain, &cu->id, true, lib_local);
}
/* Get list of nurbs from editnurbs structure */
@@ -1419,6 +1326,71 @@ void BKE_nurb_makeCurve(Nurb *nu, float *coord_array, float *tilt_array, float *
MEM_freeN(basisu);
}
+/**
+ * Calculate the length for arrays filled in by #BKE_curve_calc_coords_axis.
+ */
+unsigned int BKE_curve_calc_coords_axis_len(
+ const unsigned int bezt_array_len, const unsigned int resolu,
+ const bool is_cyclic, const bool use_cyclic_duplicate_endpoint)
+{
+ const unsigned int segments = bezt_array_len - (is_cyclic ? 0 : 1);
+ const unsigned int points_len = (segments * resolu) + (is_cyclic ? (use_cyclic_duplicate_endpoint) : 1);
+ return points_len;
+}
+
+/**
+ * Calculate an array for the entire curve (cyclic or non-cyclic).
+ * \note Call for each axis.
+ *
+ * \param use_cyclic_duplicate_endpoint: Duplicate values at the beginning & end of the array.
+ */
+void BKE_curve_calc_coords_axis(
+ const BezTriple *bezt_array, const unsigned int bezt_array_len, const unsigned int resolu,
+ const bool is_cyclic, const bool use_cyclic_duplicate_endpoint,
+ /* array params */
+ const unsigned int axis, const unsigned int stride,
+ float *r_points)
+{
+ const unsigned int points_len = BKE_curve_calc_coords_axis_len(
+ bezt_array_len, resolu, is_cyclic, use_cyclic_duplicate_endpoint);
+ float *r_points_offset = r_points;
+
+ const unsigned int resolu_stride = resolu * stride;
+ const unsigned int bezt_array_last = bezt_array_len - 1;
+
+ for (unsigned int i = 0; i < bezt_array_last; i++) {
+ const BezTriple *bezt_curr = &bezt_array[i];
+ const BezTriple *bezt_next = &bezt_array[i + 1];
+ BKE_curve_forward_diff_bezier(
+ bezt_curr->vec[1][axis], bezt_curr->vec[2][axis],
+ bezt_next->vec[0][axis], bezt_next->vec[1][axis],
+ r_points_offset, (int)resolu, stride);
+ r_points_offset = POINTER_OFFSET(r_points_offset, resolu_stride);
+ }
+
+ if (is_cyclic) {
+ const BezTriple *bezt_curr = &bezt_array[bezt_array_last];
+ const BezTriple *bezt_next = &bezt_array[0];
+ BKE_curve_forward_diff_bezier(
+ bezt_curr->vec[1][axis], bezt_curr->vec[2][axis],
+ bezt_next->vec[0][axis], bezt_next->vec[1][axis],
+ r_points_offset, (int)resolu, stride);
+ r_points_offset = POINTER_OFFSET(r_points_offset, resolu_stride);
+ if (use_cyclic_duplicate_endpoint) {
+ *r_points_offset = *r_points;
+ r_points_offset = POINTER_OFFSET(r_points_offset, stride);
+ }
+ }
+ else {
+ float *r_points_last = POINTER_OFFSET(r_points, bezt_array_last * resolu_stride);
+ *r_points_last = bezt_array[bezt_array_last].vec[1][axis];
+ r_points_offset = POINTER_OFFSET(r_points_offset, stride);
+ }
+
+ BLI_assert(POINTER_OFFSET(r_points, points_len * stride) == r_points_offset);
+ UNUSED_VARS_NDEBUG(points_len);
+}
+
/* forward differencing method for bezier curve */
void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride)
{
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index b0d0dc08126..612f1f477e1 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -1530,13 +1530,11 @@ void CustomData_realloc(CustomData *data, int totelem)
for (i = 0; i < data->totlayer; ++i) {
CustomDataLayer *layer = &data->layers[i];
const LayerTypeInfo *typeInfo;
- int size;
if (layer->flag & CD_FLAG_NOFREE) {
continue;
}
typeInfo = layerType_getInfo(layer->type);
- size = totelem * typeInfo->size;
- layer->data = MEM_reallocN(layer->data, size);
+ layer->data = MEM_reallocN(layer->data, (size_t)totelem * typeInfo->size);
}
}
@@ -1844,7 +1842,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, int typ
int totelem, const char *name)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- const int size = totelem * typeInfo->size;
+ const size_t size = (size_t)totelem * typeInfo->size;
int flag = 0, index = data->totlayer;
void *newlayerdata = NULL;
@@ -1855,8 +1853,6 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, int typ
(alloctype == CD_DUPLICATE) ||
(alloctype == CD_REFERENCE));
- BLI_assert(size >= 0);
-
if (!typeInfo->defaultname && CustomData_has_layer(data, type))
return &data->layers[CustomData_get_layer_index(data, type)];
@@ -2064,7 +2060,7 @@ static void *customData_duplicate_referenced_layer_index(CustomData *data, const
const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
if (typeInfo->copy) {
- void *dst_data = MEM_mallocN(totelem * typeInfo->size, "CD duplicate ref layer");
+ void *dst_data = MEM_mallocN((size_t)totelem * typeInfo->size, "CD duplicate ref layer");
typeInfo->copy(layer->data, dst_data, totelem);
layer->data = dst_data;
}
@@ -2172,7 +2168,7 @@ void CustomData_copy_elements(int type, void *src_data_ofs, void *dst_data_ofs,
if (typeInfo->copy)
typeInfo->copy(src_data_ofs, dst_data_ofs, count);
else
- memcpy(dst_data_ofs, src_data_ofs, count * typeInfo->size);
+ memcpy(dst_data_ofs, src_data_ofs, (size_t)count * typeInfo->size);
}
static void CustomData_copy_data_layer(
@@ -2181,16 +2177,14 @@ static void CustomData_copy_data_layer(
int src_index, int dst_index, int count)
{
const LayerTypeInfo *typeInfo;
- int src_offset;
- int dst_offset;
const void *src_data = source->layers[src_i].data;
void *dst_data = dest->layers[dst_i].data;
typeInfo = layerType_getInfo(source->layers[src_i].type);
- src_offset = src_index * typeInfo->size;
- dst_offset = dst_index * typeInfo->size;
+ const size_t src_offset = (size_t)src_index * typeInfo->size;
+ const size_t dst_offset = (size_t)dst_index * typeInfo->size;
if (!count || !src_data || !dst_data) {
if (count && !(src_data == NULL && dst_data == NULL)) {
@@ -2201,14 +2195,16 @@ static void CustomData_copy_data_layer(
return;
}
- if (typeInfo->copy)
+ if (typeInfo->copy) {
typeInfo->copy(POINTER_OFFSET(src_data, src_offset),
POINTER_OFFSET(dst_data, dst_offset),
count);
- else
+ }
+ else {
memcpy(POINTER_OFFSET(dst_data, dst_offset),
POINTER_OFFSET(src_data, src_offset),
- count * typeInfo->size);
+ (size_t)count * typeInfo->size);
+ }
}
void CustomData_copy_data_named(const CustomData *source, CustomData *dest,
@@ -2270,7 +2266,7 @@ void CustomData_free_elem(CustomData *data, int index, int count)
typeInfo = layerType_getInfo(data->layers[i].type);
if (typeInfo->free) {
- int offset = index * typeInfo->size;
+ size_t offset = (size_t)index * typeInfo->size;
typeInfo->free(POINTER_OFFSET(data->layers[i].data, offset), count, typeInfo->size);
}
@@ -2281,7 +2277,7 @@ void CustomData_free_elem(CustomData *data, int index, int count)
#define SOURCE_BUF_SIZE 100
void CustomData_interp(const CustomData *source, CustomData *dest,
- int *src_indices, float *weights, float *sub_weights,
+ const int *src_indices, const float *weights, const float *sub_weights,
int count, int dest_index)
{
int src_i, dest_i;
@@ -2316,11 +2312,11 @@ void CustomData_interp(const CustomData *source, CustomData *dest,
void *src_data = source->layers[src_i].data;
for (j = 0; j < count; ++j) {
- sources[j] = POINTER_OFFSET(src_data, src_indices[j] * typeInfo->size);
+ sources[j] = POINTER_OFFSET(src_data, (size_t)src_indices[j] * typeInfo->size);
}
typeInfo->interp(sources, weights, sub_weights, count,
- POINTER_OFFSET(dest->layers[dest_i].data, dest_index * typeInfo->size));
+ POINTER_OFFSET(dest->layers[dest_i].data, (size_t)dest_index * typeInfo->size));
/* if there are multiple source & dest layers of the same type,
* we don't want to copy all source layers to the same dest, so
@@ -2349,7 +2345,7 @@ void CustomData_swap_corners(struct CustomData *data, int index, const int *corn
typeInfo = layerType_getInfo(data->layers[i].type);
if (typeInfo->swap) {
- const int offset = index * typeInfo->size;
+ const size_t offset = (size_t)index * typeInfo->size;
typeInfo->swap(POINTER_OFFSET(data->layers[i].data, offset), corner_indices);
}
@@ -2387,7 +2383,6 @@ void CustomData_swap(struct CustomData *data, const int index_a, const int index
void *CustomData_get(const CustomData *data, int index, int type)
{
- int offset;
int layer_index;
BLI_assert(index >= 0);
@@ -2397,7 +2392,7 @@ void *CustomData_get(const CustomData *data, int index, int type)
if (layer_index == -1) return NULL;
/* get the offset of the desired element */
- offset = layerType_getInfo(type)->size * index;
+ const size_t offset = (size_t)index * layerType_getInfo(type)->size;
return POINTER_OFFSET(data->layers[layer_index].data, offset);
}
@@ -2405,7 +2400,6 @@ void *CustomData_get(const CustomData *data, int index, int type)
void *CustomData_get_n(const CustomData *data, int type, int index, int n)
{
int layer_index;
- int offset;
BLI_assert(index >= 0 && n >= 0);
@@ -2413,7 +2407,7 @@ void *CustomData_get_n(const CustomData *data, int type, int index, int n)
layer_index = data->typemap[type];
if (layer_index == -1) return NULL;
- offset = layerType_getInfo(type)->size * index;
+ const size_t offset = (size_t)index * layerType_getInfo(type)->size;
return POINTER_OFFSET(data->layers[layer_index + n].data, offset);
}
@@ -2838,7 +2832,7 @@ void CustomData_bmesh_free_block_data(CustomData *data, void *block)
typeInfo = layerType_getInfo(data->layers[i].type);
if (typeInfo->free) {
- int offset = data->layers[i].offset;
+ const size_t offset = data->layers[i].offset;
typeInfo->free(POINTER_OFFSET(block, offset), 1, typeInfo->size);
}
}
@@ -3218,7 +3212,7 @@ void CustomData_to_bmesh_block(const CustomData *source, CustomData *dest,
int src_index, void **dest_block, bool use_default_init)
{
const LayerTypeInfo *typeInfo;
- int dest_i, src_i, src_offset;
+ int dest_i, src_i;
if (*dest_block == NULL)
CustomData_bmesh_alloc_block(dest, dest_block);
@@ -3247,7 +3241,7 @@ void CustomData_to_bmesh_block(const CustomData *source, CustomData *dest,
void *dest_data = POINTER_OFFSET(*dest_block, offset);
typeInfo = layerType_getInfo(dest->layers[dest_i].type);
- src_offset = src_index * typeInfo->size;
+ const size_t src_offset = (size_t)src_index * typeInfo->size;
if (typeInfo->copy)
typeInfo->copy(POINTER_OFFSET(src_data, src_offset), dest_data, 1);
@@ -3294,7 +3288,7 @@ void CustomData_from_bmesh_block(const CustomData *source, CustomData *dest,
const LayerTypeInfo *typeInfo = layerType_getInfo(dest->layers[dest_i].type);
int offset = source->layers[src_i].offset;
const void *src_data = POINTER_OFFSET(src_block, offset);
- void *dst_data = POINTER_OFFSET(dest->layers[dest_i].data, dst_index * typeInfo->size);
+ void *dst_data = POINTER_OFFSET(dest->layers[dest_i].data, (size_t)dst_index * typeInfo->size);
if (typeInfo->copy)
typeInfo->copy(src_data, dst_data, 1);
@@ -3311,12 +3305,12 @@ void CustomData_from_bmesh_block(const CustomData *source, CustomData *dest,
}
-void CustomData_file_write_info(int type, const char **structname, int *structnum)
+void CustomData_file_write_info(int type, const char **r_struct_name, int *r_struct_num)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- *structname = typeInfo->structname;
- *structnum = typeInfo->structnum;
+ *r_struct_name = typeInfo->structname;
+ *r_struct_num = typeInfo->structnum;
}
/**
diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c
index 7292ed2b5c5..839673c192b 100644
--- a/source/blender/blenkernel/intern/data_transfer.c
+++ b/source/blender/blenkernel/intern/data_transfer.c
@@ -356,7 +356,7 @@ static MeshRemapIslandsCalc data_transfer_get_loop_islands_generator(const int c
{
switch (cddata_type) {
case CD_FAKE_UV:
- return BKE_mesh_calc_islands_loop_poly_uv;
+ return BKE_mesh_calc_islands_loop_poly_edgeseam;
default:
break;
}
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index 14c230e4a45..02ae123a71e 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -46,6 +46,7 @@
#include "DNA_anim_types.h"
#include "DNA_camera_types.h"
+#include "DNA_cachefile_types.h"
#include "DNA_group_types.h"
#include "DNA_lamp_types.h"
#include "DNA_lattice_types.h"
@@ -58,14 +59,18 @@
#include "DNA_windowmanager_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_mask_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_rigidbody_types.h"
#include "BKE_anim.h"
#include "BKE_animsys.h"
#include "BKE_action.h"
#include "BKE_DerivedMesh.h"
+#include "BKE_collision.h"
#include "BKE_effect.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
+#include "BKE_idcode.h"
#include "BKE_image.h"
#include "BKE_key.h"
#include "BKE_library.h"
@@ -448,49 +453,51 @@ static void dag_add_lamp_driver_relations(DagForest *dag, DagNode *node, Lamp *l
la->id.tag &= ~LIB_TAG_DOIT;
}
-static void check_and_create_collision_relation(DagForest *dag, Object *ob, DagNode *node, Object *ob1, int skip_forcefield, bool no_collision)
+static void create_collision_relation(DagForest *dag, DagNode *node, Object *ob1, const char *name)
{
- DagNode *node2;
- if (ob1->pd && (ob1->pd->deflect || ob1->pd->forcefield) && (ob1 != ob)) {
- if ((skip_forcefield && ob1->pd->forcefield == skip_forcefield) || (no_collision && ob1->pd->forcefield == 0))
- return;
- node2 = dag_get_node(dag, ob1);
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Field Collision");
+ DagNode *node2 = dag_get_node(dag, ob1);
+ dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, name);
+}
+
+void dag_add_collision_relations(DagForest *dag, Scene *scene, Object *ob, DagNode *node, Group *group, int layer, unsigned int modifier_type, DagCollobjFilterFunction fn, bool dupli, const char *name)
+{
+ unsigned int numcollobj;
+ Object **collobjs = get_collisionobjects_ext(scene, ob, group, layer, &numcollobj, modifier_type, dupli);
+
+ for (unsigned int i = 0; i < numcollobj; i++) {
+ Object *ob1 = collobjs[i];
+
+ if (!fn || fn(ob1, modifiers_findByType(ob1, modifier_type))) {
+ create_collision_relation(dag, node, ob1, name);
+ }
}
+
+ if (collobjs)
+ MEM_freeN(collobjs);
}
-static void dag_add_collision_field_relation(DagForest *dag, Scene *scene, Object *ob, DagNode *node, int skip_forcefield, bool no_collision)
+void dag_add_forcefield_relations(DagForest *dag, Scene *scene, Object *ob, DagNode *node, EffectorWeights *effector_weights, bool add_absorption, int skip_forcefield, const char *name)
{
- Base *base;
- ParticleSystem *particle_system;
+ ListBase *effectors = pdInitEffectors(scene, ob, NULL, effector_weights, false);
- for (particle_system = ob->particlesystem.first;
- particle_system;
- particle_system = particle_system->next)
- {
- EffectorWeights *effector_weights = particle_system->part->effector_weights;
- if (effector_weights->group) {
- GroupObject *group_object;
+ if (effectors) {
+ for (EffectorCache *eff = effectors->first; eff; eff = eff->next) {
+ if (eff->ob != ob && eff->pd->forcefield != skip_forcefield) {
+ create_collision_relation(dag, node, eff->ob, name);
- for (group_object = effector_weights->group->gobject.first;
- group_object;
- group_object = group_object->next)
- {
- if ((group_object->ob->lay & ob->lay)) {
- check_and_create_collision_relation(dag, ob, node, group_object->ob, skip_forcefield, no_collision);
+ if (eff->pd->forcefield == PFIELD_SMOKEFLOW && eff->pd->f_source) {
+ create_collision_relation(dag, node, eff->pd->f_source, "Smoke Force Domain");
+ }
+
+ if (add_absorption && (eff->pd->flag & PFIELD_VISIBILITY)) {
+ /* Actual code uses get_collider_cache */
+ dag_add_collision_relations(dag, scene, ob, node, NULL, eff->ob->lay, eModifierType_Collision, NULL, true, "Force Absorption");
}
}
}
}
- /* would be nice to have a list of colliders here
- * so for now walk all objects in scene check 'same layer rule' */
- for (base = scene->base.first; base; base = base->next) {
- if ((base->lay & ob->lay)) {
- Object *ob1 = base->object;
- check_and_create_collision_relation(dag, ob, node, ob1, skip_forcefield, no_collision);
- }
- }
+ pdEndEffectors(&effectors);
}
static void build_dag_object(DagForest *dag, DagNode *scenenode, Main *bmain, Scene *scene, Object *ob, int mask)
@@ -641,23 +648,13 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Main *bmain, Sc
}
}
- /* softbody collision */
+ /* rigidbody force fields */
if ((ob->type == OB_MESH) || (ob->type == OB_CURVE) || (ob->type == OB_LATTICE)) {
- if (ob->particlesystem.first ||
- modifiers_isModifierEnabled(ob, eModifierType_Softbody) ||
- modifiers_isModifierEnabled(ob, eModifierType_Cloth) ||
- modifiers_isModifierEnabled(ob, eModifierType_DynamicPaint))
- {
- dag_add_collision_field_relation(dag, scene, ob, node, 0, false); /* TODO: use effectorweight->group */
- }
- else if (modifiers_isModifierEnabled(ob, eModifierType_Smoke)) {
- dag_add_collision_field_relation(dag, scene, ob, node, PFIELD_SMOKEFLOW, false);
- }
- else if (ob->rigidbody_object) {
- dag_add_collision_field_relation(dag, scene, ob, node, 0, true);
+ if (ob->rigidbody_object && scene->rigidbody_world) {
+ dag_add_forcefield_relations(dag, scene, ob, node, scene->rigidbody_world->effector_weights, true, 0, "Force Field");
}
}
-
+
/* object data drivers */
if (ob->data) {
AnimData *adt = BKE_animdata_from_id((ID *)ob->data);
@@ -761,8 +758,6 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Main *bmain, Sc
BoidRule *rule = NULL;
BoidState *state = NULL;
ParticleSettings *part = psys->part;
- ListBase *effectors = NULL;
- EffectorCache *eff;
if (part->adt) {
dag_add_driver_relation(part->adt, dag, node, 1);
@@ -770,7 +765,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Main *bmain, Sc
dag_add_relation(dag, node, node, DAG_RL_OB_DATA, "Particle-Object Relation");
- if (!psys_check_enabled(ob, psys))
+ if (!psys_check_enabled(ob, psys, G.is_rendering))
continue;
if (ELEM(part->phystype, PART_PHYS_KEYED, PART_PHYS_BOIDS)) {
@@ -801,18 +796,12 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Main *bmain, Sc
}
}
- effectors = pdInitEffectors(scene, ob, psys, part->effector_weights, false);
-
- if (effectors) {
- for (eff = effectors->first; eff; eff = eff->next) {
- if (eff->psys) {
- node2 = dag_get_node(dag, eff->ob);
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Particle Field");
- }
- }
+ if (part->type != PART_HAIR) {
+ /* Actual code uses get_collider_cache */
+ dag_add_collision_relations(dag, scene, ob, node, part->collision_group, ob->lay, eModifierType_Collision, NULL, true, "Particle Collision");
}
- pdEndEffectors(&effectors);
+ dag_add_forcefield_relations(dag, scene, ob, node, part->effector_weights, part->type == PART_HAIR, 0, "Particle Force Field");
if (part->boids) {
for (state = part->boids->states.first; state; state = state->next) {
@@ -2173,7 +2162,12 @@ static void dag_object_time_update_flags(Main *bmain, Scene *scene, Object *ob)
if (cti) {
/* special case for camera tracking -- it doesn't use targets to define relations */
- if (ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, CONSTRAINT_TYPE_OBJECTSOLVER)) {
+ if (ELEM(cti->type,
+ CONSTRAINT_TYPE_FOLLOWTRACK,
+ CONSTRAINT_TYPE_CAMERASOLVER,
+ CONSTRAINT_TYPE_OBJECTSOLVER,
+ CONSTRAINT_TYPE_TRANSFORM_CACHE))
+ {
ob->recalc |= OB_RECALC_OB;
}
else if (cti->get_constraint_targets) {
@@ -2285,7 +2279,7 @@ static void dag_object_time_update_flags(Main *bmain, Scene *scene, Object *ob)
ParticleSystem *psys = ob->particlesystem.first;
for (; psys; psys = psys->next) {
- if (psys_check_enabled(ob, psys)) {
+ if (psys_check_enabled(ob, psys, G.is_rendering)) {
ob->recalc |= OB_RECALC_DATA;
break;
}
@@ -2799,9 +2793,7 @@ void DAG_ids_flush_tagged(Main *bmain)
ListBase *lb = lbarray[a];
ID *id = lb->first;
- /* we tag based on first ID type character to avoid
- * looping over all ID's in case there are no tags */
- if (id && bmain->id_tag_update[id->name[0]]) {
+ if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) {
for (; id; id = id->next) {
if (id->tag & (LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA)) {
@@ -2841,9 +2833,7 @@ void DAG_ids_check_recalc(Main *bmain, Scene *scene, bool time)
ListBase *lb = lbarray[a];
ID *id = lb->first;
- /* we tag based on first ID type character to avoid
- * looping over all ID's in case there are no tags */
- if (id && bmain->id_tag_update[id->name[0]]) {
+ if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) {
updated = true;
break;
}
@@ -2924,9 +2914,7 @@ void DAG_ids_clear_recalc(Main *bmain)
ListBase *lb = lbarray[a];
ID *id = lb->first;
- /* we tag based on first ID type character to avoid
- * looping over all ID's in case there are no tags */
- if (id && bmain->id_tag_update[id->name[0]]) {
+ if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) {
for (; id; id = id->next) {
if (id->tag & (LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA))
id->tag &= ~(LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA);
@@ -3001,6 +2989,33 @@ void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag)
/* BLI_assert(!"invalid flag for this 'idtype'"); */
}
}
+ else if (GS(id->name) == ID_CF) {
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache);
+
+ if (md) {
+ MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
+
+ if (mcmd->cache_file && (&mcmd->cache_file->id == id)) {
+ ob->recalc |= OB_RECALC_ALL;
+ continue;
+ }
+ }
+
+ for (bConstraint *con = ob->constraints.first; con; con = con->next) {
+ if (con->type != CONSTRAINT_TYPE_TRANSFORM_CACHE) {
+ continue;
+ }
+
+ bTransformCacheConstraint *data = con->data;
+
+ if (data->cache_file && (&data->cache_file->id == id)) {
+ ob->recalc |= OB_RECALC_ALL;
+ break;
+ }
+ }
+ }
+ }
}
void DAG_id_tag_update(ID *id, short flag)
@@ -3020,12 +3035,12 @@ void DAG_id_type_tag(Main *bmain, short idtype)
DAG_id_type_tag(bmain, ID_SCE);
}
- bmain->id_tag_update[((char *)&idtype)[0]] = 1;
+ bmain->id_tag_update[BKE_idcode_to_index(idtype)] = 1;
}
int DAG_id_type_tagged(Main *bmain, short idtype)
{
- return bmain->id_tag_update[((char *)&idtype)[0]];
+ return bmain->id_tag_update[BKE_idcode_to_index(idtype)];
}
#if 0 // UNUSED
diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c
index 98cbe47c7f9..49db75a0474 100644
--- a/source/blender/blenkernel/intern/displist.c
+++ b/source/blender/blenkernel/intern/displist.c
@@ -71,7 +71,7 @@ void BKE_displist_elem_free(DispList *dl)
if (dl->verts) MEM_freeN(dl->verts);
if (dl->nors) MEM_freeN(dl->nors);
if (dl->index) MEM_freeN(dl->index);
- if (dl->bevelSplitFlag) MEM_freeN(dl->bevelSplitFlag);
+ if (dl->bevel_split) MEM_freeN(dl->bevel_split);
MEM_freeN(dl);
}
}
@@ -144,8 +144,9 @@ void BKE_displist_copy(ListBase *lbn, ListBase *lb)
dln->nors = MEM_dupallocN(dl->nors);
dln->index = MEM_dupallocN(dl->index);
- if (dl->bevelSplitFlag)
- dln->bevelSplitFlag = MEM_dupallocN(dl->bevelSplitFlag);
+ if (dl->bevel_split) {
+ dln->bevel_split = MEM_dupallocN(dl->bevel_split);
+ }
dl = dl->next;
}
@@ -1629,7 +1630,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
if (dlb->type == DL_POLY) {
dl->flag |= DL_CYCL_U;
}
- if ((bl->poly >= 0) && (steps != 2)) {
+ if ((bl->poly >= 0) && (steps > 2)) {
dl->flag |= DL_CYCL_V;
}
@@ -1642,8 +1643,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
/* CU_2D conflicts with R_NOPUNOFLIP */
dl->rt = nu->flag & ~CU_2D;
- dl->bevelSplitFlag = MEM_callocN(sizeof(*dl->bevelSplitFlag) * ((steps + 0x1F) >> 5),
- "bevelSplitFlag");
+ dl->bevel_split = BLI_BITMAP_NEW(steps, "bevel_split");
/* for each point of poly make a bevel piece */
bevp_first = bl->bevpoints;
@@ -1683,7 +1683,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
}
if (bevp->split_tag) {
- dl->bevelSplitFlag[a >> 5] |= 1 << (a & 0x1F);
+ BLI_BITMAP_ENABLE(dl->bevel_split, a);
}
/* rotate bevel piece and write in data */
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index ab5d1b4ff9b..c7399047ed5 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -32,6 +32,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_kdtree.h"
+#include "BLI_task.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
@@ -64,6 +65,7 @@
#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_material.h"
+#include "BKE_mesh_mapping.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_particle.h"
@@ -79,13 +81,11 @@
#include "RE_render_ext.h"
#include "RE_shader_ext.h"
-#ifdef _OPENMP
-# include <omp.h>
-#endif
+#include "atomic_ops.h"
/* could enable at some point but for now there are far too many conversions */
#ifdef __GNUC__
-# pragma GCC diagnostic ignored "-Wdouble-promotion"
+//# pragma GCC diagnostic ignored "-Wdouble-promotion"
#endif
/* precalculated gaussian factors for 5x super sampling */
@@ -101,6 +101,10 @@ static const float gaussianTotal = 3.309425f;
static int neighX[8] = {1, 1, 0, -1, -1, -1, 0, 1};
static int neighY[8] = {0, 1, 1, 1, 0, -1, -1, -1};
+/* Neighbor x/y list that prioritizes grid directions over diagonals */
+static int neighStraightX[8] = {1, 0, -1, 0, 1, -1, -1, 1};
+static int neighStraightY[8] = {0, 1, 0, -1, 1, 1, -1, -1};
+
/* subframe_updateObject() flags */
#define SUBFRAME_RECURSION 5
/* surface_getBrushFlags() return vals */
@@ -123,7 +127,7 @@ static int neighY[8] = {0, 1, 1, 1, 0, -1, -1, -1};
/* dissolve inline function */
-BLI_INLINE void value_dissolve(float *r_value, const float time, const float scale, const int is_log)
+BLI_INLINE void value_dissolve(float *r_value, const float time, const float scale, const bool is_log)
{
*r_value = (is_log) ?
(*r_value) * (powf(MIN_WETNESS, 1.0f / (1.2f * time / scale))) :
@@ -138,19 +142,20 @@ typedef struct Bounds2D {
} Bounds2D;
typedef struct Bounds3D {
- int valid;
float min[3], max[3];
+ bool valid;
} Bounds3D;
typedef struct VolumeGrid {
int dim[3];
- Bounds3D grid_bounds; /* whole grid bounds */
+ Bounds3D grid_bounds; /* whole grid bounds */
+
+ Bounds3D *bounds; /* (x*y*z) precalculated grid cell bounds */
+ int *s_pos; /* (x*y*z) t_index begin id */
+ int *s_num; /* (x*y*z) number of t_index points */
+ int *t_index; /* actual surface point index, access: (s_pos + s_num) */
- Bounds3D *bounds; /* (x*y*z) precalculated grid cell bounds */
- int *s_pos; /* (x*y*z) t_index begin id */
- int *s_num; /* (x*y*z) number of t_index points */
- int *t_index; /* actual surface point index,
- * access: (s_pos+s_num) */
+ int *temp_t_index;
} VolumeGrid;
typedef struct Vec3f {
@@ -165,21 +170,21 @@ typedef struct BakeAdjPoint {
/* Surface data used while processing a frame */
typedef struct PaintBakeNormal {
float invNorm[3]; /* current pixel world-space inverted normal */
- float normal_scale; /* normal directional scale for displace mapping */
+ float normal_scale; /* normal directional scale for displace mapping */
} PaintBakeNormal;
/* Temp surface data used to process a frame */
typedef struct PaintBakeData {
/* point space data */
PaintBakeNormal *bNormal;
- int *s_pos; /* index to start reading point sample realCoord */
- int *s_num; /* num of realCoord samples */
- Vec3f *realCoord; /* current pixel center world-space coordinates for each sample
- * ordered as (s_pos+s_num)*/
+ int *s_pos; /* index to start reading point sample realCoord */
+ int *s_num; /* num of realCoord samples */
+ Vec3f *realCoord; /* current pixel center world-space coordinates for each sample ordered as (s_pos + s_num) */
Bounds3D mesh_bounds;
+ float dim[3];
/* adjacency info */
- BakeAdjPoint *bNeighs; /* current global neighbor distances and directions, if required */
+ BakeAdjPoint *bNeighs; /* current global neighbor distances and directions, if required */
double average_dist;
/* space partitioning */
VolumeGrid *grid; /* space partitioning grid to optimize brush checks */
@@ -188,11 +193,10 @@ typedef struct PaintBakeData {
Vec3f *velocity; /* speed vector in global space movement per frame, if required */
Vec3f *prev_velocity;
float *brush_velocity; /* special temp data for post-p velocity based brushes like smudge
- * 3 float dir vec + 1 float str */
+ * 3 float dir vec + 1 float str */
MVert *prev_verts; /* copy of previous frame vertices. used to observe surface movement */
float prev_obmat[4][4]; /* previous frame object matrix */
int clear; /* flag to check if surface was cleared/reset -> have to redo velocity etc. */
-
} PaintBakeData;
/* UV Image sequence format point */
@@ -201,8 +205,7 @@ typedef struct PaintUVPoint {
unsigned int tri_index, pixel_index; /* tri index on domain derived mesh */
unsigned int v1, v2, v3; /* vertex indexes */
- unsigned int neighbour_pixel; /* If this pixel isn't uv mapped to any face,
- * but it's neighboring pixel is */
+ unsigned int neighbour_pixel; /* If this pixel isn't uv mapped to any face, but it's neighboring pixel is */
} PaintUVPoint;
typedef struct ImgSeqFormatData {
@@ -214,8 +217,7 @@ typedef struct ImgSeqFormatData {
#define ADJ_ON_MESH_EDGE (1 << 0)
typedef struct PaintAdjData {
- int *n_target; /* array of neighboring point indexes,
- * for single sample use (n_index + neigh_num) */
+ int *n_target; /* array of neighboring point indexes, for single sample use (n_index + neigh_num) */
int *n_index; /* index to start reading n_target for each point */
int *n_num; /* num of neighs for each point */
int *flags; /* vertex adjacency flags */
@@ -239,11 +241,10 @@ static int dynamicPaint_surfaceNumOfPoints(DynamicPaintSurface *surface)
return 0; /* not supported atm */
}
else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- if (!surface->canvas->dm) return 0; /* invalid derived mesh */
- return surface->canvas->dm->getNumVerts(surface->canvas->dm);
+ return (surface->canvas->dm) ? surface->canvas->dm->getNumVerts(surface->canvas->dm) : 0;
}
- else
- return 0;
+
+ return 0;
}
/* checks whether surface's format/type has realtime preview */
@@ -253,32 +254,16 @@ bool dynamicPaint_surfaceHasColorPreview(DynamicPaintSurface *surface)
return false;
}
else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
- surface->type == MOD_DPAINT_SURFACE_T_WAVE)
- {
- return false;
- }
- else {
- return true;
- }
- }
- else {
- return true;
+ return !ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE);
}
+
+ return true;
}
/* get currently active surface (in user interface) */
DynamicPaintSurface *get_activeSurface(DynamicPaintCanvasSettings *canvas)
{
- DynamicPaintSurface *surface = canvas->surfaces.first;
- int i;
-
- for (i = 0; surface; surface = surface->next) {
- if (i == canvas->active_sur)
- return surface;
- i++;
- }
- return NULL;
+ return BLI_findlink(&canvas->surfaces, canvas->active_sur);
}
/* set preview to first previewable surface */
@@ -292,8 +277,9 @@ void dynamicPaint_resetPreview(DynamicPaintCanvasSettings *canvas)
surface->flags |= MOD_DPAINT_PREVIEW;
done = true;
}
- else
+ else {
surface->flags &= ~MOD_DPAINT_PREVIEW;
+ }
}
}
@@ -325,8 +311,9 @@ bool dynamicPaint_outputLayerExists(struct DynamicPaintSurface *surface, Object
Mesh *me = ob->data;
return (CustomData_get_named_layer_index(&me->ldata, CD_MLOOPCOL, name) != -1);
}
- else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT)
- return (defgroup_name_index(ob, surface->output_name) != -1);
+ else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
+ return (defgroup_name_index(ob, name) != -1);
+ }
}
return false;
@@ -334,15 +321,16 @@ bool dynamicPaint_outputLayerExists(struct DynamicPaintSurface *surface, Object
static bool surface_duplicateOutputExists(void *arg, const char *name)
{
- DynamicPaintSurface *t_surface = (DynamicPaintSurface *)arg;
+ DynamicPaintSurface *t_surface = arg;
DynamicPaintSurface *surface = t_surface->canvas->surfaces.first;
for (; surface; surface = surface->next) {
- if (surface != t_surface && surface->type == t_surface->type &&
- surface->format == t_surface->format)
- {
- if (surface->output_name[0] != '\0' && !BLI_path_cmp(name, surface->output_name)) return true;
- if (surface->output_name2[0] != '\0' && !BLI_path_cmp(name, surface->output_name2)) return true;
+ if (surface != t_surface && surface->type == t_surface->type && surface->format == t_surface->format) {
+ if ((surface->output_name[0] != '\0' && !BLI_path_cmp(name, surface->output_name)) ||
+ (surface->output_name2[0] != '\0' && !BLI_path_cmp(name, surface->output_name2)))
+ {
+ return true;
+ }
}
}
return false;
@@ -352,20 +340,25 @@ static void surface_setUniqueOutputName(DynamicPaintSurface *surface, char *base
{
char name[64];
BLI_strncpy(name, basename, sizeof(name)); /* in case basename is surface->name use a copy */
- if (!output)
- BLI_uniquename_cb(surface_duplicateOutputExists, surface, name, '.', surface->output_name, sizeof(surface->output_name));
- if (output)
- BLI_uniquename_cb(surface_duplicateOutputExists, surface, name, '.', surface->output_name2, sizeof(surface->output_name2));
+ if (output == 0) {
+ BLI_uniquename_cb(surface_duplicateOutputExists, surface, name, '.',
+ surface->output_name, sizeof(surface->output_name));
+ }
+ else if (output == 1) {
+ BLI_uniquename_cb(surface_duplicateOutputExists, surface, name, '.',
+ surface->output_name2, sizeof(surface->output_name2));
+ }
}
static bool surface_duplicateNameExists(void *arg, const char *name)
{
- DynamicPaintSurface *t_surface = (DynamicPaintSurface *)arg;
+ DynamicPaintSurface *t_surface = arg;
DynamicPaintSurface *surface = t_surface->canvas->surfaces.first;
for (; surface; surface = surface->next) {
- if (surface != t_surface && STREQ(name, surface->name)) return true;
+ if (surface != t_surface && STREQ(name, surface->name))
+ return true;
}
return false;
}
@@ -420,9 +413,7 @@ void dynamicPaintSurface_updateType(struct DynamicPaintSurface *surface)
static int surface_totalSamples(DynamicPaintSurface *surface)
{
- if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ &&
- surface->flags & MOD_DPAINT_ANTIALIAS)
- {
+ if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ && surface->flags & MOD_DPAINT_ANTIALIAS) {
return (surface->data->total_points * 5);
}
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX &&
@@ -434,8 +425,10 @@ static int surface_totalSamples(DynamicPaintSurface *surface)
return surface->data->total_points;
}
-static void blendColors(const float t_color[3], float t_alpha, const float s_color[3], float s_alpha, float result[4])
+static void blendColors(
+ const float t_color[3], const float t_alpha, const float s_color[3], const float s_alpha, float result[4])
{
+ /* Same thing as BLI's blend_color_mix_float(), but for non-premultiplied alpha. */
int i;
float i_alpha = 1.0f - s_alpha;
float f_alpha = t_alpha * i_alpha + s_alpha;
@@ -508,15 +501,11 @@ static int surface_getBrushFlags(DynamicPaintSurface *surface, const Scene *scen
/* select object */
if (surface->brush_group) {
- if (go->ob) brushObj = go->ob;
+ if (go->ob)
+ brushObj = go->ob;
}
- else
+ else {
brushObj = base->object;
-
- if (!brushObj) {
- if (surface->brush_group) go = go->next;
- else base = base->next;
- continue;
}
if (surface->brush_group)
@@ -524,6 +513,10 @@ static int surface_getBrushFlags(DynamicPaintSurface *surface, const Scene *scen
else
base = base->next;
+ if (!brushObj) {
+ continue;
+ }
+
md = modifiers_findByType(brushObj, eModifierType_DynamicPaint);
if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) {
DynamicPaintModifierData *pmd2 = (DynamicPaintModifierData *)md;
@@ -540,56 +533,58 @@ static int surface_getBrushFlags(DynamicPaintSurface *surface, const Scene *scen
return flags;
}
-static int brush_usesMaterial(DynamicPaintBrushSettings *brush, Scene *scene)
+static int brush_usesMaterial(const DynamicPaintBrushSettings *brush, const Scene *scene)
{
return ((brush->flags & MOD_DPAINT_USE_MATERIAL) && (!BKE_scene_use_new_shading_nodes(scene)));
}
/* check whether two bounds intersect */
-static int boundsIntersect(Bounds3D *b1, Bounds3D *b2)
+static bool boundsIntersect(Bounds3D *b1, Bounds3D *b2)
{
- int i = 2;
- if (!b1->valid || !b2->valid) return 0;
- for (; i >= 0; i -= 1)
- if (!(b1->min[i] <= b2->max[i] && b1->max[i] >= b2->min[i])) return 0;
- return 1;
+ if (!b1->valid || !b2->valid)
+ return false;
+ for (int i = 2; i--;) {
+ if (!(b1->min[i] <= b2->max[i] && b1->max[i] >= b2->min[i]))
+ return false;
+ }
+ return true;
}
/* check whether two bounds intersect inside defined proximity */
-static int boundsIntersectDist(Bounds3D *b1, Bounds3D *b2, float dist)
+static bool boundsIntersectDist(Bounds3D *b1, Bounds3D *b2, const float dist)
{
- int i = 2;
- if (!b1->valid || !b2->valid) return 0;
- for (; i >= 0; i -= 1)
- if (!(b1->min[i] <= (b2->max[i] + dist) && b1->max[i] >= (b2->min[i] - dist))) return 0;
- return 1;
+ if (!b1->valid || !b2->valid)
+ return false;
+ for (int i = 2; i--;) {
+ if (!(b1->min[i] <= (b2->max[i] + dist) && b1->max[i] >= (b2->min[i] - dist)))
+ return false;
+ }
+ return true;
}
/* check whether bounds intersects a point with given radius */
-static int boundIntersectPoint(Bounds3D *b, float point[3], float radius)
+static bool boundIntersectPoint(Bounds3D *b, float point[3], const float radius)
{
- int i = 2;
- if (!b->valid) return 0;
- for (; i >= 0; i -= 1)
- if (!(b->min[i] <= (point[i] + radius) && b->max[i] >= (point[i] - radius))) return 0;
- return 1;
+ if (!b->valid)
+ return false;
+ for (int i = 2; i--;) {
+ if (!(b->min[i] <= (point[i] + radius) && b->max[i] >= (point[i] - radius)))
+ return false;
+ }
+ return true;
}
/* expand bounds by a new point */
static void boundInsert(Bounds3D *b, float point[3])
{
- int i = 2;
if (!b->valid) {
copy_v3_v3(b->min, point);
copy_v3_v3(b->max, point);
- b->valid = 1;
- }
- else {
- for (; i >= 0; i -= 1) {
- if (point[i] < b->min[i]) b->min[i] = point[i];
- if (point[i] > b->max[i]) b->max[i] = point[i];
- }
+ b->valid = true;
+ return;
}
+
+ minmax_v3v3_v3(b->min, b->max, point);
}
static float getSurfaceDimension(PaintSurfaceData *sData)
@@ -612,65 +607,123 @@ static void freeGrid(PaintSurfaceData *data)
bData->grid = NULL;
}
+static void grid_bound_insert_cb_ex(void *userdata, void *userdata_chunk, const int i, const int UNUSED(thread_id))
+{
+ PaintBakeData *bData = userdata;
+
+ Bounds3D *grid_bound = userdata_chunk;
+
+ boundInsert(grid_bound, bData->realCoord[bData->s_pos[i]].v);
+}
+
+static void grid_bound_insert_finalize(void *userdata, void *userdata_chunk)
+{
+ PaintBakeData *bData = userdata;
+ VolumeGrid *grid = bData->grid;
+
+ Bounds3D *grid_bound = userdata_chunk;
+
+ boundInsert(&grid->grid_bounds, grid_bound->min);
+ boundInsert(&grid->grid_bounds, grid_bound->max);
+}
+
+static void grid_cell_points_cb_ex(void *userdata, void *userdata_chunk, const int i, const int UNUSED(thread_id))
+{
+ PaintBakeData *bData = userdata;
+ VolumeGrid *grid = bData->grid;
+ int *temp_t_index = grid->temp_t_index;
+ int *s_num = userdata_chunk;
+
+ int co[3];
+
+ for (int j = 3; j--;) {
+ co[j] = (int)floorf((bData->realCoord[bData->s_pos[i]].v[j] - grid->grid_bounds.min[j]) /
+ bData->dim[j] * grid->dim[j]);
+ CLAMP(co[j], 0, grid->dim[j] - 1);
+ }
+
+ temp_t_index[i] = co[0] + co[1] * grid->dim[0] + co[2] * grid->dim[0] * grid->dim[1];
+ s_num[temp_t_index[i]]++;
+}
+
+static void grid_cell_points_finalize(void *userdata, void *userdata_chunk)
+{
+ PaintBakeData *bData = userdata;
+ VolumeGrid *grid = bData->grid;
+ const int grid_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
+
+ int *s_num = userdata_chunk;
+
+ /* calculate grid indexes */
+ for (int i = 0; i < grid_cells; i++) {
+ grid->s_num[i] += s_num[i];
+ }
+}
+
+static void grid_cell_bounds_cb(void *userdata, const int x)
+{
+ PaintBakeData *bData = userdata;
+ VolumeGrid *grid = bData->grid;
+ float *dim = bData->dim;
+ int *grid_dim = grid->dim;
+
+ for (int y = 0; y < grid_dim[1]; y++) {
+ for (int z = 0; z < grid_dim[2]; z++) {
+ const int b_index = x + y * grid_dim[0] + z * grid_dim[0] * grid_dim[1];
+ /* set bounds */
+ for (int j = 3; j--;) {
+ const int s = (j == 0) ? x : ((j == 1) ? y : z);
+ grid->bounds[b_index].min[j] = grid->grid_bounds.min[j] + dim[j] / grid_dim[j] * s;
+ grid->bounds[b_index].max[j] = grid->grid_bounds.min[j] + dim[j] / grid_dim[j] * (s + 1);
+ }
+ grid->bounds[b_index].valid = true;
+ }
+ }
+}
+
static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
{
PaintSurfaceData *sData = surface->data;
PaintBakeData *bData = sData->bData;
- Bounds3D *grid_bounds;
VolumeGrid *grid;
int grid_cells, axis = 3;
int *temp_t_index = NULL;
int *temp_s_num = NULL;
-#ifdef _OPENMP
- int num_of_threads = omp_get_max_threads();
-#else
- int num_of_threads = 1;
-#endif
-
if (bData->grid)
freeGrid(sData);
- /* allocate separate bounds for each thread */
- grid_bounds = MEM_callocN(sizeof(Bounds3D) * num_of_threads, "Grid Bounds");
bData->grid = MEM_callocN(sizeof(VolumeGrid), "Surface Grid");
grid = bData->grid;
- if (grid && grid_bounds) {
+ {
int i, error = 0;
float dim_factor, volume, dim[3];
float td[3];
float min_dim;
/* calculate canvas dimensions */
-#pragma omp parallel for schedule(static)
- for (i = 0; i < sData->total_points; i++) {
-#ifdef _OPENMP
- int id = omp_get_thread_num();
- boundInsert(&grid_bounds[id], (bData->realCoord[bData->s_pos[i]].v));
-#else
- boundInsert(&grid_bounds[0], (bData->realCoord[bData->s_pos[i]].v));
-#endif
- }
-
- /* get final dimensions */
- for (i = 0; i < num_of_threads; i++) {
- boundInsert(&grid->grid_bounds, grid_bounds[i].min);
- boundInsert(&grid->grid_bounds, grid_bounds[i].max);
- }
+ /* Important to init correctly our ref grid_bound... */
+ boundInsert(&grid->grid_bounds, bData->realCoord[bData->s_pos[0]].v);
+ BLI_task_parallel_range_finalize(
+ 0, sData->total_points, bData, &grid->grid_bounds, sizeof(grid->grid_bounds),
+ grid_bound_insert_cb_ex, grid_bound_insert_finalize, sData->total_points > 1000, false);
/* get dimensions */
sub_v3_v3v3(dim, grid->grid_bounds.max, grid->grid_bounds.min);
copy_v3_v3(td, dim);
+ copy_v3_v3(bData->dim, dim);
min_dim = max_fff(td[0], td[1], td[2]) / 1000.f;
/* deactivate zero axises */
for (i = 0; i < 3; i++) {
- if (td[i] < min_dim) { td[i] = 1.0f; axis -= 1; }
+ if (td[i] < min_dim) {
+ td[i] = 1.0f;
+ axis--;
+ }
}
if (axis == 0 || max_fff(td[0], td[1], td[2]) < 0.0001f) {
- MEM_freeN(grid_bounds);
MEM_freeN(bData->grid);
bData->grid = NULL;
return;
@@ -692,10 +745,11 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
/* allocate memory for grids */
grid->bounds = MEM_callocN(sizeof(Bounds3D) * grid_cells, "Surface Grid Bounds");
grid->s_pos = MEM_callocN(sizeof(int) * grid_cells, "Surface Grid Position");
- grid->s_num = MEM_callocN(sizeof(int) * grid_cells * num_of_threads, "Surface Grid Points");
+
+ grid->s_num = MEM_callocN(sizeof(int) * grid_cells, "Surface Grid Points");
temp_s_num = MEM_callocN(sizeof(int) * grid_cells, "Temp Surface Grid Points");
grid->t_index = MEM_callocN(sizeof(int) * sData->total_points, "Surface Grid Target Ids");
- temp_t_index = MEM_callocN(sizeof(int) * sData->total_points, "Temp Surface Grid Target Ids");
+ grid->temp_t_index = temp_t_index = MEM_callocN(sizeof(int) * sData->total_points, "Temp Surface Grid Target Ids");
/* in case of an allocation failure abort here */
if (!grid->bounds || !grid->s_pos || !grid->s_num || !grid->t_index || !temp_s_num || !temp_t_index)
@@ -703,33 +757,12 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
if (!error) {
/* calculate number of points withing each cell */
-#pragma omp parallel for schedule(static)
- for (i = 0; i < sData->total_points; i++) {
- int co[3], j;
- for (j = 0; j < 3; j++) {
- co[j] = (int)floor((bData->realCoord[bData->s_pos[i]].v[j] - grid->grid_bounds.min[j]) / dim[j] * grid->dim[j]);
- CLAMP(co[j], 0, grid->dim[j] - 1);
- }
-
- temp_t_index[i] = co[0] + co[1] * grid->dim[0] + co[2] * grid->dim[0] * grid->dim[1];
-#ifdef _OPENMP
- grid->s_num[temp_t_index[i] + omp_get_thread_num() * grid_cells]++;
-#else
- grid->s_num[temp_t_index[i]]++;
-#endif
- }
-
- /* for first cell only calc s_num */
- for (i = 1; i < num_of_threads; i++) {
- grid->s_num[0] += grid->s_num[i * grid_cells];
- }
+ BLI_task_parallel_range_finalize(
+ 0, sData->total_points, bData, grid->s_num, sizeof(*grid->s_num) * grid_cells,
+ grid_cell_points_cb_ex, grid_cell_points_finalize, sData->total_points > 1000, false);
- /* calculate grid indexes */
+ /* calculate grid indexes (not needed for first cell, which is zero). */
for (i = 1; i < grid_cells; i++) {
- int id;
- for (id = 1; id < num_of_threads; id++) {
- grid->s_num[i] += grid->s_num[i + id * grid_cells];
- }
grid->s_pos[i] = grid->s_pos[i - 1] + grid->s_num[i - 1];
}
@@ -742,41 +775,20 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
}
/* calculate cell bounds */
- {
- int x;
-#pragma omp parallel for schedule(static)
- for (x = 0; x < grid->dim[0]; x++) {
- int y;
- for (y = 0; y < grid->dim[1]; y++) {
- int z;
- for (z = 0; z < grid->dim[2]; z++) {
- int j, b_index = x + y * grid->dim[0] + z * grid->dim[0] * grid->dim[1];
- /* set bounds */
- for (j = 0; j < 3; j++) {
- int s = (j == 0) ? x : ((j == 1) ? y : z);
- grid->bounds[b_index].min[j] = grid->grid_bounds.min[j] + dim[j] / grid->dim[j] * s;
- grid->bounds[b_index].max[j] = grid->grid_bounds.min[j] + dim[j] / grid->dim[j] * (s + 1);
- }
- grid->bounds[b_index].valid = 1;
- }
- }
- }
- }
+ BLI_task_parallel_range(0, grid->dim[0], bData, grid_cell_bounds_cb, grid_cells > 1000);
}
- if (temp_s_num) MEM_freeN(temp_s_num);
- if (temp_t_index) MEM_freeN(temp_t_index);
-
- /* free per thread s_num values */
- grid->s_num = MEM_reallocN(grid->s_num, sizeof(int) * grid_cells);
+ if (temp_s_num)
+ MEM_freeN(temp_s_num);
+ if (temp_t_index)
+ MEM_freeN(temp_t_index);
+ grid->temp_t_index = NULL;
if (error || !grid->s_num) {
setError(surface->canvas, N_("Not enough free memory"));
freeGrid(sData);
}
}
-
- if (grid_bounds) MEM_freeN(grid_bounds);
}
/***************************** Freeing data ******************************/
@@ -791,10 +803,8 @@ void dynamicPaint_freeBrush(struct DynamicPaintModifierData *pmd)
if (pmd->brush->paint_ramp)
MEM_freeN(pmd->brush->paint_ramp);
- pmd->brush->paint_ramp = NULL;
if (pmd->brush->vel_ramp)
MEM_freeN(pmd->brush->vel_ramp);
- pmd->brush->vel_ramp = NULL;
MEM_freeN(pmd->brush);
pmd->brush = NULL;
@@ -804,10 +814,14 @@ void dynamicPaint_freeBrush(struct DynamicPaintModifierData *pmd)
static void dynamicPaint_freeAdjData(PaintSurfaceData *data)
{
if (data->adj_data) {
- if (data->adj_data->n_index) MEM_freeN(data->adj_data->n_index);
- if (data->adj_data->n_num) MEM_freeN(data->adj_data->n_num);
- if (data->adj_data->n_target) MEM_freeN(data->adj_data->n_target);
- if (data->adj_data->flags) MEM_freeN(data->adj_data->flags);
+ if (data->adj_data->n_index)
+ MEM_freeN(data->adj_data->n_index);
+ if (data->adj_data->n_num)
+ MEM_freeN(data->adj_data->n_num);
+ if (data->adj_data->n_target)
+ MEM_freeN(data->adj_data->n_target);
+ if (data->adj_data->flags)
+ MEM_freeN(data->adj_data->flags);
MEM_freeN(data->adj_data);
data->adj_data = NULL;
}
@@ -817,15 +831,24 @@ static void free_bakeData(PaintSurfaceData *data)
{
PaintBakeData *bData = data->bData;
if (bData) {
- if (bData->bNormal) MEM_freeN(bData->bNormal);
- if (bData->s_pos) MEM_freeN(bData->s_pos);
- if (bData->s_num) MEM_freeN(bData->s_num);
- if (bData->realCoord) MEM_freeN(bData->realCoord);
- if (bData->bNeighs) MEM_freeN(bData->bNeighs);
- if (bData->grid) freeGrid(data);
- if (bData->prev_verts) MEM_freeN(bData->prev_verts);
- if (bData->velocity) MEM_freeN(bData->velocity);
- if (bData->prev_velocity) MEM_freeN(bData->prev_velocity);
+ if (bData->bNormal)
+ MEM_freeN(bData->bNormal);
+ if (bData->s_pos)
+ MEM_freeN(bData->s_pos);
+ if (bData->s_num)
+ MEM_freeN(bData->s_num);
+ if (bData->realCoord)
+ MEM_freeN(bData->realCoord);
+ if (bData->bNeighs)
+ MEM_freeN(bData->bNeighs);
+ if (bData->grid)
+ freeGrid(data);
+ if (bData->prev_verts)
+ MEM_freeN(bData->prev_verts);
+ if (bData->velocity)
+ MEM_freeN(bData->velocity);
+ if (bData->prev_velocity)
+ MEM_freeN(bData->prev_velocity);
MEM_freeN(data->bData);
data->bData = NULL;
@@ -835,12 +858,11 @@ static void free_bakeData(PaintSurfaceData *data)
/* free surface data if it's not used anymore */
static void surface_freeUnusedData(DynamicPaintSurface *surface)
{
- if (!surface->data) return;
+ if (!surface->data)
+ return;
/* free bakedata if not active or surface is baked */
- if (!(surface->flags & MOD_DPAINT_ACTIVE) ||
- (surface->pointcache && surface->pointcache->flag & PTCACHE_BAKED))
- {
+ if (!(surface->flags & MOD_DPAINT_ACTIVE) || (surface->pointcache && surface->pointcache->flag & PTCACHE_BAKED)) {
free_bakeData(surface->data);
}
}
@@ -848,7 +870,9 @@ static void surface_freeUnusedData(DynamicPaintSurface *surface)
void dynamicPaint_freeSurfaceData(DynamicPaintSurface *surface)
{
PaintSurfaceData *data = surface->data;
- if (!data) return;
+ if (!data)
+ return;
+
if (data->format_data) {
/* format specific free */
if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
@@ -861,7 +885,8 @@ void dynamicPaint_freeSurfaceData(DynamicPaintSurface *surface)
MEM_freeN(data->format_data);
}
/* type data */
- if (data->type_data) MEM_freeN(data->type_data);
+ if (data->type_data)
+ MEM_freeN(data->type_data);
dynamicPaint_freeAdjData(data);
/* bake data */
free_bakeData(data);
@@ -1035,7 +1060,7 @@ bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, str
brush->flags = MOD_DPAINT_ABS_ALPHA | MOD_DPAINT_RAMP_ALPHA;
brush->collision = MOD_DPAINT_COL_VOLUME;
-
+
brush->mat = NULL;
brush->r = 0.15f;
brush->g = 0.4f;
@@ -1224,31 +1249,24 @@ static void dynamicPaint_allocateSurfaceType(DynamicPaintSurface *surface)
break;
}
- if (sData->type_data == NULL) setError(surface->canvas, N_("Not enough free memory"));
+ if (sData->type_data == NULL)
+ setError(surface->canvas, N_("Not enough free memory"));
}
-static int surface_usesAdjDistance(DynamicPaintSurface *surface)
+static bool surface_usesAdjDistance(DynamicPaintSurface *surface)
{
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && surface->effect) return 1;
- if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) return 1;
- return 0;
+ return ((surface->type == MOD_DPAINT_SURFACE_T_PAINT && surface->effect) ||
+ (surface->type == MOD_DPAINT_SURFACE_T_WAVE));
}
-static int surface_usesAdjData(DynamicPaintSurface *surface)
+static bool surface_usesAdjData(DynamicPaintSurface *surface)
{
- if (surface_usesAdjDistance(surface)) return 1;
- if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX &&
- surface->flags & MOD_DPAINT_ANTIALIAS)
- {
- return 1;
- }
- else {
- return 0;
- }
+ return (surface_usesAdjDistance(surface) ||
+ (surface->format == MOD_DPAINT_SURFACE_F_VERTEX && surface->flags & MOD_DPAINT_ANTIALIAS));
}
/* initialize surface adjacency data */
-static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int force_init)
+static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, const bool force_init)
{
PaintSurfaceData *sData = surface->data;
DerivedMesh *dm = surface->canvas->dm;
@@ -1256,20 +1274,24 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int for
int *temp_data;
int neigh_points = 0;
- if (!surface_usesAdjData(surface) && !force_init) return;
+ if (!force_init && !surface_usesAdjData(surface))
+ return;
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
/* For vertex format, neighbors are connected by edges */
neigh_points = 2 * dm->getNumEdges(dm);
}
- else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
+ else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
neigh_points = sData->total_points * 8;
+ }
- if (!neigh_points) return;
+ if (!neigh_points)
+ return;
/* allocate memory */
ad = sData->adj_data = MEM_callocN(sizeof(PaintAdjData), "Surface Adj Data");
- if (!ad) return;
+ if (!ad)
+ return;
ad->n_index = MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Index");
ad->n_num = MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Counts");
temp_data = MEM_callocN(sizeof(int) * sData->total_points, "Temp Adj Data");
@@ -1280,7 +1302,8 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int for
/* in case of allocation error, free memory */
if (!ad->n_index || !ad->n_num || !ad->n_target || !temp_data) {
dynamicPaint_freeAdjData(sData);
- if (temp_data) MEM_freeN(temp_data);
+ if (temp_data)
+ MEM_freeN(temp_data);
setError(surface->canvas, N_("Not enough free memory"));
return;
}
@@ -1308,8 +1331,7 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int for
/* also add number of vertices to temp_data
* to locate points on "mesh edge" */
for (i = 0; i < numOfPolys; i++) {
- int j = 0;
- for (; j < mpoly[i].totloop; j++) {
+ for (int j = 0; j < mpoly[i].totloop; j++) {
temp_data[mloop[mpoly[i].loopstart + j].v]++;
}
}
@@ -1317,13 +1339,11 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int for
/* now check if total number of edges+faces for
* each vertex is even, if not -> vertex is on mesh edge */
for (i = 0; i < sData->total_points; i++) {
- if ((temp_data[i] % 2) ||
- (temp_data[i] < 4))
- {
+ if ((temp_data[i] % 2) || (temp_data[i] < 4)) {
ad->flags[i] |= ADJ_ON_MESH_EDGE;
}
- /* reset temp data */
+ /* reset temp data */
temp_data[i] = 0;
}
@@ -1357,6 +1377,117 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int for
MEM_freeN(temp_data);
}
+typedef struct DynamicPaintSetInitColorData {
+ const DynamicPaintSurface *surface;
+
+ const MLoop *mloop;
+ const MLoopUV *mloopuv;
+ const MLoopTri *mlooptri;
+ const MLoopCol *mloopcol;
+ struct ImagePool *pool;
+
+ const bool scene_color_manage;
+} DynamicPaintSetInitColorData;
+
+static void dynamic_paint_set_init_color_tex_to_vcol_cb(void *userdata, const int i)
+{
+ const DynamicPaintSetInitColorData *data = userdata;
+
+ const PaintSurfaceData *sData = data->surface->data;
+ PaintPoint *pPoint = (PaintPoint *)sData->type_data;
+
+ const MLoop *mloop = data->mloop;
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopUV *mloopuv = data->mloopuv;
+ struct ImagePool *pool = data->pool;
+ Tex *tex = data->surface->init_texture;
+
+ const bool scene_color_manage = data->scene_color_manage;
+
+ float uv[3] = {0.0f};
+
+ for (int j = 3; j--;) {
+ TexResult texres = {0};
+ const unsigned int vert = mloop[mlooptri[i].tri[j]].v;
+
+ /* remap to [-1.0, 1.0] */
+ uv[0] = mloopuv[mlooptri[i].tri[j]].uv[0] * 2.0f - 1.0f;
+ uv[1] = mloopuv[mlooptri[i].tri[j]].uv[1] * 2.0f - 1.0f;
+
+ multitex_ext_safe(tex, uv, &texres, pool, scene_color_manage, false);
+
+ if (texres.tin > pPoint[vert].color[3]) {
+ copy_v3_v3(pPoint[vert].color, &texres.tr);
+ pPoint[vert].color[3] = texres.tin;
+ }
+ }
+}
+
+static void dynamic_paint_set_init_color_tex_to_imseq_cb(void *userdata, const int i)
+{
+ const DynamicPaintSetInitColorData *data = userdata;
+
+ const PaintSurfaceData *sData = data->surface->data;
+ PaintPoint *pPoint = (PaintPoint *)sData->type_data;
+
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopUV *mloopuv = data->mloopuv;
+ Tex *tex = data->surface->init_texture;
+ ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
+ const int samples = (data->surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
+
+ const bool scene_color_manage = data->scene_color_manage;
+
+ float uv[9] = {0.0f};
+ float uv_final[3] = {0.0f};
+
+ TexResult texres = {0};
+
+ /* collect all uvs */
+ for (int j = 3; j--;) {
+ copy_v2_v2(&uv[j * 3], mloopuv[mlooptri[f_data->uv_p[i].tri_index].tri[j]].uv);
+ }
+
+ /* interpolate final uv pos */
+ interp_v3_v3v3v3(uv_final, &uv[0], &uv[3], &uv[6], f_data->barycentricWeights[i * samples].v);
+ /* remap to [-1.0, 1.0] */
+ uv_final[0] = uv_final[0] * 2.0f - 1.0f;
+ uv_final[1] = uv_final[1] * 2.0f - 1.0f;
+
+ multitex_ext_safe(tex, uv_final, &texres, NULL, scene_color_manage, false);
+
+ /* apply color */
+ copy_v3_v3(pPoint[i].color, &texres.tr);
+ pPoint[i].color[3] = texres.tin;
+}
+
+static void dynamic_paint_set_init_color_vcol_to_imseq_cb(void *userdata, const int i)
+{
+ const DynamicPaintSetInitColorData *data = userdata;
+
+ const PaintSurfaceData *sData = data->surface->data;
+ PaintPoint *pPoint = (PaintPoint *)sData->type_data;
+
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopCol *mloopcol = data->mloopcol;
+ ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
+ const int samples = (data->surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
+
+ const int tri_idx = f_data->uv_p[i].tri_index;
+ float colors[3][4];
+ float final_color[4];
+
+ /* collect color values */
+ for (int j = 3; j--;) {
+ rgba_uchar_to_float(colors[j], (const unsigned char *)&mloopcol[mlooptri[tri_idx].tri[j]].r);
+ }
+
+ /* interpolate final color */
+ interp_v4_v4v4v4(final_color, UNPACK3(colors), f_data->barycentricWeights[i * samples].v);
+
+ copy_v4_v4(pPoint[i].color, final_color);
+}
+
static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface *surface)
{
PaintSurfaceData *sData = surface->data;
@@ -1370,10 +1501,10 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
if (surface->init_color_type == MOD_DPAINT_INITIAL_NONE)
return;
+
/* Single color */
- else if (surface->init_color_type == MOD_DPAINT_INITIAL_COLOR) {
+ if (surface->init_color_type == MOD_DPAINT_INITIAL_COLOR) {
/* apply color to every surface point */
-#pragma omp parallel for schedule(static)
for (i = 0; i < sData->total_points; i++) {
copy_v4_v4(pPoint[i].color, surface->init_color);
}
@@ -1389,69 +1520,36 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
char uvname[MAX_CUSTOMDATA_LAYER_NAME];
- if (!tex) return;
+ if (!tex)
+ return;
/* get uv map */
CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, surface->init_layername, uvname);
mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, uvname);
- if (!mloopuv) return;
+ if (!mloopuv)
+ return;
/* for vertex surface loop through tfaces and find uv color
* that provides highest alpha */
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
struct ImagePool *pool = BKE_image_pool_new();
-#pragma omp parallel for schedule(static) shared(pool)
- for (i = 0; i < tottri; i++) {
- float uv[3] = {0.0f};
- int j;
- for (j = 0; j < 3; j++) {
- TexResult texres = {0};
- unsigned int vert = mloop[mlooptri[i].tri[j]].v;
-
- /* remap to -1.0 to 1.0 */
- uv[0] = mloopuv[mlooptri[i].tri[j]].uv[0] * 2.0f - 1.0f;
- uv[1] = mloopuv[mlooptri[i].tri[j]].uv[1] * 2.0f - 1.0f;
-
- multitex_ext_safe(tex, uv, &texres, pool, scene_color_manage, false);
-
- if (texres.tin > pPoint[vert].color[3]) {
- copy_v3_v3(pPoint[vert].color, &texres.tr);
- pPoint[vert].color[3] = texres.tin;
- }
- }
- }
+ DynamicPaintSetInitColorData data = {
+ .surface = surface,
+ .mloop = mloop, .mlooptri = mlooptri, .mloopuv = mloopuv, .pool = pool,
+ .scene_color_manage = scene_color_manage
+ };
+ BLI_task_parallel_range(0, tottri, &data, dynamic_paint_set_init_color_tex_to_vcol_cb, tottri > 1000);
BKE_image_pool_free(pool);
}
else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
- ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
- int samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
-
-#pragma omp parallel for schedule(static)
- for (i = 0; i < sData->total_points; i++) {
- float uv[9] = {0.0f};
- float uv_final[3] = {0.0f};
- int j;
- TexResult texres = {0};
-
- /* collect all uvs */
- for (j = 0; j < 3; j++) {
- copy_v2_v2(&uv[j * 3], mloopuv[mlooptri[f_data->uv_p[i].tri_index].tri[j]].uv);
- }
-
- /* interpolate final uv pos */
- interp_v3_v3v3v3(uv_final, &uv[0], &uv[3], &uv[6],
- f_data->barycentricWeights[i * samples].v);
- /* remap to -1.0 to 1.0 */
- uv_final[0] = uv_final[0] * 2.0f - 1.0f;
- uv_final[1] = uv_final[1] * 2.0f - 1.0f;
-
- multitex_ext_safe(tex, uv_final, &texres, NULL, scene_color_manage, false);
-
- /* apply color */
- copy_v3_v3(pPoint[i].color, &texres.tr);
- pPoint[i].color[3] = texres.tin;
- }
+ DynamicPaintSetInitColorData data = {
+ .surface = surface,
+ .mlooptri = mlooptri, .mloopuv = mloopuv,
+ .scene_color_manage = scene_color_manage
+ };
+ BLI_task_parallel_range(0, sData->total_points, &data, dynamic_paint_set_init_color_tex_to_imseq_cb,
+ sData->total_points > 1000);
}
}
/* vertex color layer */
@@ -1462,37 +1560,25 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
const MLoop *mloop = dm->getLoopArray(dm);
const int totloop = dm->getNumLoops(dm);
const MLoopCol *col = CustomData_get_layer_named(&dm->loopData, CD_MLOOPCOL, surface->init_layername);
- if (!col) return;
+ if (!col)
+ return;
-#pragma omp parallel for schedule(static)
for (i = 0; i < totloop; i++) {
rgba_uchar_to_float(pPoint[mloop[i].v].color, (const unsigned char *)&col[mloop[i].v].r);
}
}
else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
const MLoopTri *mlooptri = dm->getLoopTriArray(dm);
- ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
- int samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
MLoopCol *col = CustomData_get_layer_named(&dm->loopData, CD_MLOOPCOL, surface->init_layername);
- if (!col) return;
-
-#pragma omp parallel for schedule(static)
- for (i = 0; i < sData->total_points; i++) {
- int tri_ind = f_data->uv_p[i].tri_index;
- float colors[3][4];
- float final_color[4];
- int j;
-
- /* collect color values */
- for (j = 0; j < 3; j++) {
- rgba_uchar_to_float(colors[j], (const unsigned char *)&col[mlooptri[tri_ind].tri[j]].r);
- }
-
- /* interpolate final color */
- interp_v4_v4v4v4(final_color, UNPACK3(colors), f_data->barycentricWeights[i * samples].v);
-
- copy_v4_v4(pPoint[i].color, final_color);
- }
+ if (!col)
+ return;
+
+ DynamicPaintSetInitColorData data = {
+ .surface = surface,
+ .mlooptri = mlooptri, .mloopcol = col,
+ };
+ BLI_task_parallel_range(0, sData->total_points, &data, dynamic_paint_set_init_color_vcol_to_imseq_cb,
+ sData->total_points > 1000);
}
}
}
@@ -1527,20 +1613,24 @@ bool dynamicPaint_resetSurface(const Scene *scene, DynamicPaintSurface *surface)
{
int numOfPoints = dynamicPaint_surfaceNumOfPoints(surface);
/* free existing data */
- if (surface->data) dynamicPaint_freeSurfaceData(surface);
+ if (surface->data)
+ dynamicPaint_freeSurfaceData(surface);
/* don't reallocate for image sequence types. they get handled only on bake */
- if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) return true;
- if (numOfPoints < 1) return false;
+ if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
+ return true;
+ if (numOfPoints < 1)
+ return false;
/* allocate memory */
surface->data = MEM_callocN(sizeof(PaintSurfaceData), "PaintSurfaceData");
- if (!surface->data) return false;
+ if (!surface->data)
+ return false;
/* allocate data depending on surface type and format */
surface->data->total_points = numOfPoints;
dynamicPaint_allocateSurfaceType(surface);
- dynamicPaint_initAdjacencyData(surface, 0);
+ dynamicPaint_initAdjacencyData(surface, false);
/* set initial color */
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT)
@@ -1561,39 +1651,153 @@ static bool dynamicPaint_checkSurfaceData(const Scene *scene, DynamicPaintSurfac
/***************************** Modifier processing ******************************/
+typedef struct DynamicPaintModifierApplyData {
+ const DynamicPaintSurface *surface;
+ Object *ob;
+
+ MVert *mvert;
+ const MLoop *mloop;
+ const MPoly *mpoly;
+
+ float (*fcolor)[4];
+ MLoopCol *mloopcol;
+ MLoopCol *mloopcol_wet;
+ MLoopCol *mloopcol_preview;
+} DynamicPaintModifierApplyData;
+
+static void dynamic_paint_apply_surface_displace_cb(void *userdata, const int i)
+{
+ const DynamicPaintModifierApplyData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ MVert *mvert = data->mvert;
+
+ float normal[3];
+ const float *value = (float *)surface->data->type_data;
+ const float val = value[i] * surface->disp_factor;
+
+ normal_short_to_float_v3(normal, mvert[i].no);
+
+ /* same as 'mvert[i].co[0] -= normal[0] * val' etc. */
+ madd_v3_v3fl(mvert[i].co, normal, -val);
+}
/* apply displacing vertex surface to the derived mesh */
static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, DerivedMesh *result)
{
PaintSurfaceData *sData = surface->data;
- if (!sData || surface->format != MOD_DPAINT_SURFACE_F_VERTEX) return;
+ if (!sData || surface->format != MOD_DPAINT_SURFACE_F_VERTEX)
+ return;
/* displace paint */
if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
MVert *mvert = result->getVertArray(result);
- int i;
- const float *value = (float *)sData->type_data;
-#pragma omp parallel for schedule(static)
- for (i = 0; i < sData->total_points; i++) {
- float normal[3], val = value[i] * surface->disp_factor;
- normal_short_to_float_v3(normal, mvert[i].no);
- normalize_v3(normal);
+ DynamicPaintModifierApplyData data = {.surface = surface, .mvert = mvert};
+ BLI_task_parallel_range(0, sData->total_points, &data, dynamic_paint_apply_surface_displace_cb,
+ sData->total_points > 10000);
+ }
+}
+
+static void dynamic_paint_apply_surface_vpaint_blend_cb(void *userdata, const int i)
+{
+ const DynamicPaintModifierApplyData *data = userdata;
+
+ PaintPoint *pPoint = (PaintPoint *)data->surface->data->type_data;
+ float (*fcolor)[4] = data->fcolor;
+
+ /* blend dry and wet layer */
+ blendColors(pPoint[i].color, pPoint[i].color[3], pPoint[i].e_color, pPoint[i].e_color[3], fcolor[i]);
+}
+
+static void dynamic_paint_apply_surface_vpaint_cb(void *userdata, const int p_index)
+{
+ const DynamicPaintModifierApplyData *data = userdata;
+ Object *ob = data->ob;
+
+ const MLoop *mloop = data->mloop;
+ const MPoly *mpoly = data->mpoly;
+
+ const DynamicPaintSurface *surface = data->surface;
+ PaintPoint *pPoint = (PaintPoint *)surface->data->type_data;
+ float (*fcolor)[4] = data->fcolor;
+
+ MLoopCol *mloopcol = data->mloopcol;
+ MLoopCol *mloopcol_wet = data->mloopcol_wet;
+ MLoopCol *mloopcol_preview = data->mloopcol_preview;
+
+ const Material *material = mloopcol_preview ?
+ give_current_material(ob, mpoly[p_index].mat_nr + 1) : NULL;
+
+ for (int j = 0; j < mpoly[p_index].totloop; j++) {
+ const int l_index = mpoly[p_index].loopstart + j;
+ const int v_index = mloop[l_index].v;
+
+ /* save layer data to output layer */
+ /* apply color */
+ if (mloopcol) {
+ rgba_float_to_uchar((unsigned char *)&mloopcol[l_index].r, fcolor[v_index]);
+ }
+ /* apply wetness */
+ if (mloopcol_wet) {
+ const char c = FTOCHAR(pPoint[v_index].wetness);
+ mloopcol_wet[l_index].r = c;
+ mloopcol_wet[l_index].g = c;
+ mloopcol_wet[l_index].b = c;
+ mloopcol_wet[l_index].a = 255;
+ }
+
+ /* viewport preview */
+ if (mloopcol_preview) {
+ if (surface->preview_id == MOD_DPAINT_SURFACE_PREV_PAINT) {
+ float c[3];
+
+ /* Apply material color as base vertex color for preview */
+ mloopcol_preview[l_index].a = 255;
+ if (material) {
+ c[0] = material->r;
+ c[1] = material->g;
+ c[2] = material->b;
+ }
+ else { /* default gray */
+ c[0] = 0.65f;
+ c[1] = 0.65f;
+ c[2] = 0.65f;
+ }
+ /* mix surface color */
+ interp_v3_v3v3(c, c, fcolor[v_index], fcolor[v_index][3]);
- mvert[i].co[0] -= normal[0] * val;
- mvert[i].co[1] -= normal[1] * val;
- mvert[i].co[2] -= normal[2] * val;
+ rgb_float_to_uchar((unsigned char *)&mloopcol_preview[l_index].r, c);
+ }
+ else {
+ const char c = FTOCHAR(pPoint[v_index].wetness);
+ mloopcol_preview[l_index].r = c;
+ mloopcol_preview[l_index].g = c;
+ mloopcol_preview[l_index].b = c;
+ mloopcol_preview[l_index].a = 255;
+ }
}
}
}
+static void dynamic_paint_apply_surface_wave_cb(void *userdata, const int i)
+{
+ const DynamicPaintModifierApplyData *data = userdata;
+
+ PaintWavePoint *wPoint = (PaintWavePoint *)data->surface->data->type_data;
+ MVert *mvert = data->mvert;
+ float normal[3];
+
+ normal_short_to_float_v3(normal, mvert[i].no);
+ madd_v3_v3fl(mvert[i].co, normal, wPoint[i].height);
+}
+
/*
* Apply canvas data to the object derived mesh
*/
-static DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd,
- Object *ob,
- DerivedMesh *dm)
+static DerivedMesh *dynamicPaint_Modifier_apply(
+ DynamicPaintModifierData *pmd, Object *ob, DerivedMesh *dm)
{
DerivedMesh *result = CDDM_copy(dm);
@@ -1607,129 +1811,65 @@ static DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd,
PaintSurfaceData *sData = surface->data;
if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ && sData) {
- if (!(surface->flags & (MOD_DPAINT_ACTIVE))) continue;
+ if (!(surface->flags & MOD_DPAINT_ACTIVE))
+ continue;
/* process vertex surface previews */
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
/* vertex color paint */
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
-
- int i;
- PaintPoint *pPoint = (PaintPoint *)sData->type_data;
- MLoopCol *col = NULL;
MLoop *mloop = CDDM_get_loops(result);
- int totloop = result->numLoopData;
+ const int totloop = result->numLoopData;
+ MPoly *mpoly = CDDM_get_polys(result);
+ const int totpoly = result->numPolyData;
/* paint is stored on dry and wet layers, so mix final color first */
- float *fcolor = MEM_callocN(sizeof(float) * sData->total_points * 4, "Temp paint color");
-
-#pragma omp parallel for schedule(static)
- for (i = 0; i < sData->total_points; i++) {
- /* blend dry and wet layer */
- blendColors(pPoint[i].color, pPoint[i].color[3], pPoint[i].e_color, pPoint[i].e_color[3], &fcolor[i * 4]);
- }
-
- /* viewport preview */
- if (surface->flags & MOD_DPAINT_PREVIEW) {
- MPoly *mp = CDDM_get_polys(result);
- int totpoly = result->numPolyData;
-
-#if 0
- /* XXX We have to create a CD_PREVIEW_MCOL, else it might sigsev
- * (after a SubSurf mod, eg)... */
- if (!result->getTessFaceDataArray(result, CD_PREVIEW_MCOL)) {
- int numFaces = result->getNumTessFaces(result);
- CustomData_add_layer(&result->faceData, CD_PREVIEW_MCOL, CD_CALLOC, NULL, numFaces);
- }
-#endif
-
- /* Save preview results to weight layer to be
- * able to share same drawing methods */
- col = CustomData_get_layer(&result->loopData, CD_PREVIEW_MLOOPCOL);
- if (!col)
- col = CustomData_add_layer(&result->loopData, CD_PREVIEW_MLOOPCOL, CD_CALLOC,
- NULL, totloop);
-
- if (col) {
-#pragma omp parallel for schedule(static)
- for (i = 0; i < totpoly; i++) {
- int j = 0;
- Material *material = give_current_material(ob, mp[i].mat_nr + 1);
-
- for (; j < mp[i].totloop; j++) {
- int l_index = mp[i].loopstart + j;
- int v_index = mloop[l_index].v;
-
- if (surface->preview_id == MOD_DPAINT_SURFACE_PREV_PAINT) {
- float c[3];
- v_index *= 4;
-
- /* Apply material color as base vertex color for preview */
- col[l_index].a = 255;
- if (material) {
- c[0] = material->r;
- c[1] = material->g;
- c[2] = material->b;
- }
- else { /* default gray */
- c[0] = 0.65f;
- c[1] = 0.65f;
- c[2] = 0.65f;
- }
- /* mix surface color */
- interp_v3_v3v3(c, c, &fcolor[v_index], fcolor[v_index + 3]);
-
- rgb_float_to_uchar((unsigned char *)&col[l_index].r, c);
- }
- else {
- col[l_index].r =
- col[l_index].g =
- col[l_index].b = FTOCHAR(pPoint[v_index].wetness);
- col[l_index].a = 255;
- }
- }
- }
- }
- }
-
+ float (*fcolor)[4] = MEM_callocN(sizeof(*fcolor) * sData->total_points, "Temp paint color");
- /* save layer data to output layer */
+ DynamicPaintModifierApplyData data = {.surface = surface, .fcolor = fcolor};
+ BLI_task_parallel_range(0, sData->total_points, &data,
+ dynamic_paint_apply_surface_vpaint_blend_cb,
+ sData->total_points > 1000);
/* paint layer */
- col = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name);
+ MLoopCol *mloopcol = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name);
/* if output layer is lost from a constructive modifier, re-add it */
- if (!col && dynamicPaint_outputLayerExists(surface, ob, 0))
- col = CustomData_add_layer_named(&result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name);
- /* apply color */
- if (col) {
-#pragma omp parallel for schedule(static)
- for (i = 0; i < totloop; i++) {
- int index = mloop[i].v * 4;
- rgb_float_to_uchar((unsigned char *)&col[i].r, &fcolor[index]);
- col[i].a = FTOCHAR(fcolor[index + 3]); /* IS THIS NEEDED? */
- }
+ if (!mloopcol && dynamicPaint_outputLayerExists(surface, ob, 0)) {
+ mloopcol = CustomData_add_layer_named(
+ &result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name);
}
-
- MEM_freeN(fcolor);
/* wet layer */
- col = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name2);
+ MLoopCol *mloopcol_wet = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name2);
/* if output layer is lost from a constructive modifier, re-add it */
- if (!col && dynamicPaint_outputLayerExists(surface, ob, 1))
- col = CustomData_add_layer_named(&result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name2);
- /* apply color */
- if (col) {
-#pragma omp parallel for schedule(static)
- for (i = 0; i < totloop; i++) {
- int index = mloop[i].v;
- col[i].r =
- col[i].g =
- col[i].b = FTOCHAR(pPoint[index].wetness);
- col[i].a = 255;
+ if (!mloopcol_wet && dynamicPaint_outputLayerExists(surface, ob, 1)) {
+ mloopcol_wet = CustomData_add_layer_named(
+ &result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name2);
+ }
+
+ /* Save preview results to weight layer to be able to share same drawing methods */
+ MLoopCol *mloopcol_preview = NULL;
+ if (surface->flags & MOD_DPAINT_PREVIEW) {
+ mloopcol_preview = CustomData_get_layer(&result->loopData, CD_PREVIEW_MLOOPCOL);
+ if (!mloopcol_preview) {
+ mloopcol_preview = CustomData_add_layer(
+ &result->loopData, CD_PREVIEW_MLOOPCOL, CD_CALLOC, NULL, totloop);
}
}
+ data.ob = ob;
+ data.mloop = mloop;
+ data.mpoly = mpoly;
+ data.mloopcol = mloopcol;
+ data.mloopcol_wet = mloopcol_wet;
+ data.mloopcol_preview = mloopcol_preview;
+
+ BLI_task_parallel_range(0, totpoly, &data, dynamic_paint_apply_surface_vpaint_cb,
+ totpoly > 1000);
+
+ MEM_freeN(fcolor);
+
/* Mark tessellated CD layers as dirty. */
result->dirty |= DM_DIRTY_TESS_CDLAYERS;
}
@@ -1748,9 +1888,10 @@ static DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd,
}
/* apply weights into a vertex group, if doesnt exists add a new layer */
- if (defgrp_index != -1 && !dvert && (surface->output_name[0] != '\0'))
+ if (defgrp_index != -1 && !dvert && (surface->output_name[0] != '\0')) {
dvert = CustomData_add_layer_named(&result->vertData, CD_MDEFORMVERT, CD_CALLOC,
NULL, sData->total_points, surface->output_name);
+ }
if (defgrp_index != -1 && dvert) {
int i;
for (i = 0; i < sData->total_points; i++) {
@@ -1759,7 +1900,6 @@ static DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd,
/* skip if weight value is 0 and no existing weight is found */
if ((def_weight != NULL) || (weight[i] != 0.0f)) {
-
/* if not found, add a weight for it */
if (def_weight == NULL) {
def_weight = defvert_verify_index(dv, defgrp_index);
@@ -1774,15 +1914,10 @@ static DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd,
/* wave simulation */
else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
MVert *mvert = result->getVertArray(result);
- int i;
- PaintWavePoint *wPoint = (PaintWavePoint *)sData->type_data;
-
-#pragma omp parallel for schedule(static)
- for (i = 0; i < sData->total_points; i++) {
- float normal[3];
- normal_short_to_float_v3(normal, mvert[i].no);
- madd_v3_v3fl(mvert[i].co, normal, wPoint[i].height);
- }
+
+ DynamicPaintModifierApplyData data = {.surface = surface, .mvert = mvert};
+ BLI_task_parallel_range(0, sData->total_points, &data, dynamic_paint_apply_surface_wave_cb,
+ sData->total_points > 1000);
update_normals = true;
}
@@ -1801,7 +1936,8 @@ static DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd,
}
/* make a copy of dm to use as brush data */
if (pmd->brush) {
- if (pmd->brush->dm) pmd->brush->dm->release(pmd->brush->dm);
+ if (pmd->brush->dm)
+ pmd->brush->dm->release(pmd->brush->dm);
pmd->brush->dm = CDDM_copy(result);
}
@@ -1839,7 +1975,8 @@ static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd, Scene *scene
canvas_copyDerivedMesh(canvas, dm);
/* in case image sequence baking, stop here */
- if (canvas->flags & MOD_DPAINT_BAKING) return;
+ if (canvas->flags & MOD_DPAINT_BAKING)
+ return;
/* loop through surfaces */
for (; surface; surface = surface->next) {
@@ -1850,17 +1987,20 @@ static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd, Scene *scene
surface_freeUnusedData(surface);
/* image sequences are handled by bake operator */
- if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) continue;
- if (!(surface->flags & MOD_DPAINT_ACTIVE)) continue;
+ if ((surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) || !(surface->flags & MOD_DPAINT_ACTIVE))
+ continue;
/* make sure surface is valid */
no_surface_data = surface->data == NULL;
- if (!dynamicPaint_checkSurfaceData(scene, surface)) continue;
+ if (!dynamicPaint_checkSurfaceData(scene, surface))
+ continue;
/* limit frame range */
CLAMP(current_frame, surface->start_frame, surface->end_frame);
- if (no_surface_data || current_frame != surface->current_frame || (int)scene->r.cfra == surface->start_frame) {
+ if (no_surface_data || current_frame != surface->current_frame ||
+ (int)scene->r.cfra == surface->start_frame)
+ {
PointCache *cache = surface->pointcache;
PTCacheID pid;
surface->current_frame = current_frame;
@@ -1879,11 +2019,13 @@ static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd, Scene *scene
}
/* try to read from cache */
- if (BKE_ptcache_read(&pid, (float)scene->r.cfra)) {
+ bool can_simulate = ((int)scene->r.cfra == current_frame) && !(cache->flag & PTCACHE_BAKED);
+
+ if (BKE_ptcache_read(&pid, (float)scene->r.cfra, can_simulate)) {
BKE_ptcache_validate(cache, (int)scene->r.cfra);
}
/* if read failed and we're on surface range do recalculate */
- else if ((int)scene->r.cfra == current_frame && !(cache->flag & PTCACHE_BAKED)) {
+ else if (can_simulate) {
/* calculate surface frame */
canvas->flags |= MOD_DPAINT_BAKING;
dynamicPaint_calculateFrame(surface, scene, ob, current_frame);
@@ -1907,263 +2049,484 @@ static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd, Scene *scene
/* Modifier call. Processes dynamic paint modifier step. */
DerivedMesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd, Scene *scene, Object *ob, DerivedMesh *dm)
{
- /* For now generate looptris in every case */
- DM_ensure_looptri(dm);
+ if (pmd->canvas) {
+ DerivedMesh *ret;
+
+ /* For now generate looptris in every case */
+ DM_ensure_looptri(dm);
- /* Update canvas data for a new frame */
- dynamicPaint_frameUpdate(pmd, scene, ob, dm);
+ /* Update canvas data for a new frame */
+ dynamicPaint_frameUpdate(pmd, scene, ob, dm);
- /* Return output mesh */
- return dynamicPaint_Modifier_apply(pmd, ob, dm);
+ /* Return output mesh */
+ ret = dynamicPaint_Modifier_apply(pmd, ob, dm);
+
+ return ret;
+ }
+ else {
+ /* For now generate looptris in every case */
+ DM_ensure_looptri(dm);
+
+ /* Update canvas data for a new frame */
+ dynamicPaint_frameUpdate(pmd, scene, ob, dm);
+
+ /* Return output mesh */
+ return dynamicPaint_Modifier_apply(pmd, ob, dm);
+ }
}
/***************************** Image Sequence / UV Image Surface Calls ******************************/
/*
- * Tries to find the neighboring pixel in given (uv space) direction.
- * Result is used by effect system to move paint on the surface.
+ * Create a surface for uv image sequence format
+ */
+#define JITTER_SAMPLES { \
+ 0.0f, 0.0f, \
+ -0.2f, -0.4f, \
+ 0.2f, 0.4f, \
+ 0.4f, -0.2f, \
+ -0.4f, 0.3f, \
+}
+
+typedef struct DynamicPaintCreateUVSurfaceData {
+ const DynamicPaintSurface *surface;
+
+ PaintUVPoint *tempPoints;
+ Vec3f *tempWeights;
+
+ const MLoopTri *mlooptri;
+ const MLoopUV *mloopuv;
+ const MLoop *mloop;
+ const int tottri;
+
+ const Bounds2D *faceBB;
+ uint32_t *active_points;
+} DynamicPaintCreateUVSurfaceData;
+
+static void dynamic_paint_create_uv_surface_direct_cb(void *userdata, const int ty)
+{
+ const DynamicPaintCreateUVSurfaceData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ PaintUVPoint *tempPoints = data->tempPoints;
+ Vec3f *tempWeights = data->tempWeights;
+
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopUV *mloopuv = data->mloopuv;
+ const MLoop *mloop = data->mloop;
+ const int tottri = data->tottri;
+
+ const Bounds2D *faceBB = data->faceBB;
+
+ const float jitter5sample[10] = JITTER_SAMPLES;
+ const int aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
+ const int w = surface->image_resolution;
+ const int h = w;
+
+ for (int tx = 0; tx < w; tx++) {
+ const int index = tx + w * ty;
+ PaintUVPoint *tPoint = &tempPoints[index];
+ float point[5][2];
+
+ /* Init per pixel settings */
+ tPoint->tri_index = -1;
+ tPoint->neighbour_pixel = -1;
+ tPoint->pixel_index = index;
+
+ /* Actual pixel center, used when collision is found */
+ point[0][0] = ((float)tx + 0.5f) / w;
+ point[0][1] = ((float)ty + 0.5f) / h;
+
+ /*
+ * A pixel middle sample isn't enough to find very narrow polygons
+ * So using 4 samples of each corner too
+ */
+ point[1][0] = ((float)tx) / w;
+ point[1][1] = ((float)ty) / h;
+
+ point[2][0] = ((float)tx + 1) / w;
+ point[2][1] = ((float)ty) / h;
+
+ point[3][0] = ((float)tx) / w;
+ point[3][1] = ((float)ty + 1) / h;
+
+ point[4][0] = ((float)tx + 1) / w;
+ point[4][1] = ((float)ty + 1) / h;
+
+
+ /* Loop through samples, starting from middle point */
+ for (int sample = 0; sample < 5; sample++) {
+ /* Loop through every face in the mesh */
+ /* XXX TODO This is *horrible* with big meshes, should use a 2D BVHTree over UV tris here! */
+ for (int i = 0; i < tottri; i++) {
+ /* Check uv bb */
+ if ((faceBB[i].min[0] > point[sample][0]) ||
+ (faceBB[i].min[1] > point[sample][1]) ||
+ (faceBB[i].max[0] < point[sample][0]) ||
+ (faceBB[i].max[1] < point[sample][1]))
+ {
+ continue;
+ }
+
+ const float *uv1 = mloopuv[mlooptri[i].tri[0]].uv;
+ const float *uv2 = mloopuv[mlooptri[i].tri[1]].uv;
+ const float *uv3 = mloopuv[mlooptri[i].tri[2]].uv;
+
+ /* If point is inside the face */
+ if (isect_point_tri_v2(point[sample], uv1, uv2, uv3) != 0) {
+ float uv[2];
+
+ /* Add b-weights per anti-aliasing sample */
+ for (int j = 0; j < aa_samples; j++) {
+ uv[0] = point[0][0] + jitter5sample[j * 2] / w;
+ uv[1] = point[0][1] + jitter5sample[j * 2 + 1] / h;
+
+ barycentric_weights_v2(uv1, uv2, uv3, uv, tempWeights[index * aa_samples + j].v);
+ }
+
+ /* Set surface point face values */
+ tPoint->tri_index = i;
+
+ /* save vertex indexes */
+ tPoint->v1 = mloop[mlooptri[i].tri[0]].v;
+ tPoint->v2 = mloop[mlooptri[i].tri[1]].v;
+ tPoint->v3 = mloop[mlooptri[i].tri[2]].v;
+
+ sample = 5; /* make sure we exit sample loop as well */
+ break;
+ }
+ }
+ }
+ }
+}
+
+static void dynamic_paint_create_uv_surface_neighbor_cb(void *userdata, const int ty)
+{
+ const DynamicPaintCreateUVSurfaceData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ PaintUVPoint *tempPoints = data->tempPoints;
+ Vec3f *tempWeights = data->tempWeights;
+
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopUV *mloopuv = data->mloopuv;
+ const MLoop *mloop = data->mloop;
+
+ uint32_t *active_points = data->active_points;
+
+ const float jitter5sample[10] = JITTER_SAMPLES;
+ const int aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
+ const int w = surface->image_resolution;
+ const int h = w;
+
+ for (int tx = 0; tx < w; tx++) {
+ const int index = tx + w * ty;
+ PaintUVPoint *tPoint = &tempPoints[index];
+
+ /* If point isn't on canvas mesh */
+ if (tPoint->tri_index == -1) {
+ float point[2];
+
+ /* get loop area */
+ const int u_min = (tx > 0) ? -1 : 0;
+ const int u_max = (tx < (w - 1)) ? 1 : 0;
+ const int v_min = (ty > 0) ? -1 : 0;
+ const int v_max = (ty < (h - 1)) ? 1 : 0;
+
+ point[0] = ((float)tx + 0.5f) / w;
+ point[1] = ((float)ty + 0.5f) / h;
+
+ /* search through defined area for neighbor, checking grid directions first */
+ for (int ni = 0; ni < 8; ni++) {
+ int u = neighStraightX[ni];
+ int v = neighStraightY[ni];
+
+ if (u >= u_min && u <= u_max && v >= v_min && v <= v_max) {
+ /* if not this pixel itself */
+ if (u != 0 || v != 0) {
+ const int ind = (tx + u) + w * (ty + v);
+
+ /* if neighbor has index */
+ if (tempPoints[ind].neighbour_pixel == -1 && tempPoints[ind].tri_index != -1) {
+ float uv[2];
+ const int i = tempPoints[ind].tri_index;
+ const float *uv1 = mloopuv[mlooptri[i].tri[0]].uv;
+ const float *uv2 = mloopuv[mlooptri[i].tri[1]].uv;
+ const float *uv3 = mloopuv[mlooptri[i].tri[2]].uv;
+
+ /* tri index */
+ /* There is a low possibility of actually having a neighbor point which tri is
+ * already set from another neighbor in a separate thread here.
+ * Checking for both tri_index and neighbour_pixel above reduces that probability
+ * but it remains possible.
+ * That atomic op (and its memory fence) ensures tPoint->neighbour_pixel is set
+ * to non--1 *before* its tri_index is set (i.e. that it cannot be used a neighbour).
+ */
+ tPoint->neighbour_pixel = ind - 1;
+ atomic_add_uint32(&tPoint->neighbour_pixel, 1);
+ tPoint->tri_index = i;
+
+ /* Now calculate pixel data for this pixel as it was on polygon surface */
+ /* Add b-weights per anti-aliasing sample */
+ for (int j = 0; j < aa_samples; j++) {
+ uv[0] = point[0] + jitter5sample[j * 2] / w;
+ uv[1] = point[1] + jitter5sample[j * 2 + 1] / h;
+ barycentric_weights_v2(uv1, uv2, uv3, uv, tempWeights[index * aa_samples + j].v);
+ }
+
+ /* save vertex indexes */
+ tPoint->v1 = mloop[mlooptri[i].tri[0]].v;
+ tPoint->v2 = mloop[mlooptri[i].tri[1]].v;
+ tPoint->v3 = mloop[mlooptri[i].tri[2]].v;
+
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* Increase the final number of active surface points if relevant. */
+ if (tPoint->tri_index != -1)
+ atomic_add_uint32(active_points, 1);
+ }
+}
+
+#undef JITTER_SAMPLES
+
+/* Tries to find the neighboring pixel in given (uv space) direction.
+ * Result is used by effect system to move paint on the surface.
*
- * px, py : origin pixel x and y
- * n_index : lookup direction index (use neighX, neighY to get final index)
+ * px, py : origin pixel x and y
+ * n_index : lookup direction index (use neighX, neighY to get final index)
*/
-static int dynamicPaint_findNeighbourPixel(PaintUVPoint *tempPoints, DerivedMesh *dm,
- const char *uvname, int w, int h, int px, int py, int n_index)
+static int dynamic_paint_find_neighbour_pixel(
+ const DynamicPaintCreateUVSurfaceData *data, const MeshElemMap *vert_to_looptri_map,
+ const int w, const int h, const int px, const int py, const int n_index)
{
/* Note: Current method only uses polygon edges to detect neighboring pixels.
- * -> It doesn't always lead to the optimum pixel but is accurate enough
- * and faster/simpler than including possible face tip point links)
+ * -> It doesn't always lead to the optimum pixel but is accurate enough
+ * and faster/simpler than including possible face tip point links)
*/
- int x, y;
- PaintUVPoint *tPoint = NULL;
- PaintUVPoint *cPoint = NULL;
-
/* shift position by given n_index */
- x = px + neighX[n_index];
- y = py + neighY[n_index];
+ const int x = px + neighX[n_index];
+ const int y = py + neighY[n_index];
- if (x < 0 || x >= w) return OUT_OF_TEXTURE;
- if (y < 0 || y >= h) return OUT_OF_TEXTURE;
+ if (x < 0 || x >= w || y < 0 || y >= h)
+ return OUT_OF_TEXTURE;
- tPoint = &tempPoints[x + w * y]; /* UV neighbor */
- cPoint = &tempPoints[px + w * py]; /* Origin point */
+ const PaintUVPoint *tempPoints = data->tempPoints;
+ const PaintUVPoint *tPoint = &tempPoints[x + w * y]; /* UV neighbor */
+ const PaintUVPoint *cPoint = &tempPoints[px + w * py]; /* Origin point */
- /*
- * Check if shifted point is on same face -> it's a correct neighbor
- * (and if it isn't marked as an "edge pixel")
- */
+ /* Check if shifted point is on same face -> it's a correct neighbor (and if it isn't marked as an "edge pixel") */
if ((tPoint->tri_index == cPoint->tri_index) && (tPoint->neighbour_pixel == -1))
return (x + w * y);
- /*
- * Even if shifted point is on another face
- * -> use this point.
+ /* Even if shifted point is on another face
+ * -> use this point.
*
- * !! Replace with "is uv faces linked" check !!
- * This should work fine as long as uv island
- * margin is > 1 pixel.
+ * !! Replace with "is uv faces linked" check !!
+ * This should work fine as long as uv island margin is > 1 pixel.
*/
if ((tPoint->tri_index != -1) && (tPoint->neighbour_pixel == -1)) {
return (x + w * y);
}
- /*
- * If we get here, the actual neighboring pixel
- * is located on a non-linked uv face, and we have to find
- * it's "real" position.
+ /* If we get here, the actual neighboring pixel is located on a non-linked uv face,
+ * and we have to find its "real" position.
*
- * Simple neighboring face finding algorithm:
- * - find closest uv edge to shifted pixel and get
- * the another face that shares that edge
- * - find corresponding position of that new face edge
- * in uv space
+ * Simple neighboring face finding algorithm:
+ * - find closest uv edge to shifted pixel and get the another face that shares that edge
+ * - find corresponding position of that new face edge in uv space
*
- * TODO: Implement something more accurate / optimized?
+ * TODO: Implement something more accurate / optimized?
*/
{
- const MLoop *mloop = dm->getLoopArray(dm);
- const MLoopTri *mlooptri = dm->getLoopTriArray(dm);
- const int tottri = dm->getNumLoopTri(dm);
- const MLoopUV *mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, uvname);
+ const MLoop *mloop = data->mloop;
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopUV *mloopuv = data->mloopuv;
/* Get closest edge to that subpixel on UV map */
- {
- float pixel[2];
- /* distances only used for comparison */
- float dist_squared, t_dist_squared;
-
- int i, edge1_index, edge2_index,
- e1_index, e2_index, target_tri;
- float closest_point[2], lambda, dir_vec[2];
- int target_uv1 = 0, target_uv2 = 0, final_pixel[2], final_index;
-
- const float *s_uv1, *s_uv2, *t_uv1, *t_uv2;
-
- pixel[0] = ((float)(px + neighX[n_index]) + 0.5f) / (float)w;
- pixel[1] = ((float)(py + neighY[n_index]) + 0.5f) / (float)h;
-
- /*
- * Find closest edge to that pixel
- */
-
- /* Dist to first edge */
- e1_index = cPoint->v1;
- e2_index = cPoint->v2;
- edge1_index = 0;
- edge2_index = 1;
- dist_squared = dist_squared_to_line_segment_v2(
- pixel,
- mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv,
- mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv);
-
- /* Dist to second edge */
- t_dist_squared = dist_squared_to_line_segment_v2(
- pixel,
- mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv,
- mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv);
- if (t_dist_squared < dist_squared) {
- e1_index = cPoint->v2;
- e2_index = cPoint->v3;
- edge1_index = 1;
- edge2_index = 2;
- dist_squared = t_dist_squared;
- }
- /* Dist to third edge */
- t_dist_squared = dist_squared_to_line_segment_v2(
- pixel,
- mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv,
- mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv);
- if (t_dist_squared < dist_squared) {
- e1_index = cPoint->v3;
- e2_index = cPoint->v1;
- edge1_index = 2;
- edge2_index = 0;
- dist_squared = t_dist_squared;
- }
+ float pixel[2];
+ /* distances only used for comparison */
+ float dist_squared, t_dist_squared;
+ int edge1_index, edge2_index;
+ int e1_index, e2_index, target_tri;
+ float closest_point[2], lambda, dir_vec[2];
+ int target_uv1 = 0, target_uv2 = 0, final_pixel[2], final_index;
- /*
- * Now find another face that is linked to that edge
- */
- target_tri = -1;
+ const float *s_uv1, *s_uv2, *t_uv1, *t_uv2;
- for (i = 0; i < tottri; i++) {
- /*
- * Check if both edge vertices share this face
- */
- if ((e1_index == mloop[mlooptri[i].tri[0]].v || e1_index == mloop[mlooptri[i].tri[1]].v || e1_index == mloop[mlooptri[i].tri[2]].v) &&
- (e2_index == mloop[mlooptri[i].tri[0]].v || e2_index == mloop[mlooptri[i].tri[1]].v || e2_index == mloop[mlooptri[i].tri[2]].v))
- {
- if (i == cPoint->tri_index) continue;
+ pixel[0] = ((float)(px + neighX[n_index]) + 0.5f) / (float)w;
+ pixel[1] = ((float)(py + neighY[n_index]) + 0.5f) / (float)h;
- target_tri = i;
+ /*
+ * Find closest edge to that pixel
+ */
- /*
- * Get edge UV index
- */
- if (e1_index == mloop[mlooptri[i].tri[0]].v) target_uv1 = 0;
- else if (e1_index == mloop[mlooptri[i].tri[1]].v) target_uv1 = 1;
- else if (e1_index == mloop[mlooptri[i].tri[2]].v) target_uv1 = 2;
+ /* Dist to first edge */
+ e1_index = cPoint->v1;
+ e2_index = cPoint->v2;
+ edge1_index = 0;
+ edge2_index = 1;
+ dist_squared = dist_squared_to_line_segment_v2(
+ pixel,
+ mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv,
+ mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv);
+
+ /* Dist to second edge */
+ t_dist_squared = dist_squared_to_line_segment_v2(
+ pixel,
+ mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv,
+ mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv);
+ if (t_dist_squared < dist_squared) {
+ e1_index = cPoint->v2;
+ e2_index = cPoint->v3;
+ edge1_index = 1;
+ edge2_index = 2;
+ dist_squared = t_dist_squared;
+ }
- if (e2_index == mloop[mlooptri[i].tri[0]].v) target_uv2 = 0;
- else if (e2_index == mloop[mlooptri[i].tri[1]].v) target_uv2 = 1;
- else if (e2_index == mloop[mlooptri[i].tri[2]].v) target_uv2 = 2;
+ /* Dist to third edge */
+ t_dist_squared = dist_squared_to_line_segment_v2(
+ pixel,
+ mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv,
+ mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv);
+ if (t_dist_squared < dist_squared) {
+ e1_index = cPoint->v3;
+ e2_index = cPoint->v1;
+ edge1_index = 2;
+ edge2_index = 0;
+ dist_squared = t_dist_squared;
+ }
- break;
- }
- }
+ /*
+ * Now find another face that is linked to that edge
+ */
+ target_tri = -1;
- /* If none found pixel is on mesh edge */
- if (target_tri == -1) return ON_MESH_EDGE;
+ /* Use a pre-computed vert-to-looptri mapping, speeds up things a lot compared to looping over all loopti. */
+ for (int i = 0; i < vert_to_looptri_map[e1_index].count; i++) {
+ const int lt_index = vert_to_looptri_map[e1_index].indices[i];
+ const int v0 = mloop[mlooptri[lt_index].tri[0]].v;
+ const int v1 = mloop[mlooptri[lt_index].tri[1]].v;
+ const int v2 = mloop[mlooptri[lt_index].tri[2]].v;
- /*
- * If target face is connected in UV space as well, just use original index
- */
- s_uv1 = mloopuv[mlooptri[cPoint->tri_index].tri[edge1_index]].uv;
- s_uv2 = mloopuv[mlooptri[cPoint->tri_index].tri[edge2_index]].uv;
- t_uv1 = mloopuv[mlooptri[target_tri].tri[target_uv1]].uv;
- t_uv2 = mloopuv[mlooptri[target_tri].tri[target_uv2]].uv;
+ BLI_assert(ELEM(e1_index, v0, v1, v2));
- //printf("connected UV : %f,%f & %f,%f - %f,%f & %f,%f\n", s_uv1[0], s_uv1[1], s_uv2[0], s_uv2[1], t_uv1[0], t_uv1[1], t_uv2[0], t_uv2[1]);
+ if (ELEM(e2_index, v0, v1, v2)) {
+ if (lt_index == cPoint->tri_index)
+ continue;
- if (((s_uv1[0] == t_uv1[0] && s_uv1[1] == t_uv1[1]) &&
- (s_uv2[0] == t_uv2[0] && s_uv2[1] == t_uv2[1]) ) ||
- ((s_uv2[0] == t_uv1[0] && s_uv2[1] == t_uv1[1]) &&
- (s_uv1[0] == t_uv2[0] && s_uv1[1] == t_uv2[1]) ))
- {
- return ((px + neighX[n_index]) + w * (py + neighY[n_index]));
+ target_tri = lt_index;
+
+ /* Get edge UV index */
+ target_uv1 = (e1_index == v0) ? 0 : ((e1_index == v1) ? 1 : 2);
+ target_uv2 = (e2_index == v0) ? 0 : ((e2_index == v1) ? 1 : 2);
+ break;
}
+ }
+
+ /* If none found pixel is on mesh edge */
+ if (target_tri == -1)
+ return ON_MESH_EDGE;
+
+ /*
+ * If target face is connected in UV space as well, just use original index
+ */
+ s_uv1 = mloopuv[mlooptri[cPoint->tri_index].tri[edge1_index]].uv;
+ s_uv2 = mloopuv[mlooptri[cPoint->tri_index].tri[edge2_index]].uv;
+ t_uv1 = mloopuv[mlooptri[target_tri].tri[target_uv1]].uv;
+ t_uv2 = mloopuv[mlooptri[target_tri].tri[target_uv2]].uv;
+
+ //printf("connected UV : %f,%f & %f,%f - %f,%f & %f,%f\n", s_uv1[0], s_uv1[1], s_uv2[0], s_uv2[1], t_uv1[0], t_uv1[1], t_uv2[0], t_uv2[1]);
- /*
- * Find a point that is relatively at same edge position
- * on this other face UV
- */
- lambda = closest_to_line_v2(
- closest_point, pixel,
- mloopuv[mlooptri[cPoint->tri_index].tri[edge1_index]].uv,
- mloopuv[mlooptri[cPoint->tri_index].tri[edge2_index]].uv);
- if (lambda < 0.0f) lambda = 0.0f;
- if (lambda > 1.0f) lambda = 1.0f;
-
- sub_v2_v2v2(
- dir_vec,
- mloopuv[mlooptri[target_tri].tri[target_uv2]].uv,
- mloopuv[mlooptri[target_tri].tri[target_uv1]].uv);
-
- mul_v2_fl(dir_vec, lambda);
-
- copy_v2_v2(pixel, mloopuv[mlooptri[target_tri].tri[target_uv1]].uv);
- add_v2_v2(pixel, dir_vec);
- pixel[0] = (pixel[0] * (float)w) - 0.5f;
- pixel[1] = (pixel[1] * (float)h) - 0.5f;
-
- final_pixel[0] = (int)floor(pixel[0]);
- final_pixel[1] = (int)floor(pixel[1]);
-
- /* If current pixel uv is outside of texture */
- if (final_pixel[0] < 0 || final_pixel[0] >= w) return OUT_OF_TEXTURE;
- if (final_pixel[1] < 0 || final_pixel[1] >= h) return OUT_OF_TEXTURE;
-
- final_index = final_pixel[0] + w * final_pixel[1];
-
- /* If we ended up to our origin point ( mesh has smaller than pixel sized faces) */
- if (final_index == (px + w * py)) return NOT_FOUND;
- /* If found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */
- if (tempPoints[final_index].tri_index != target_tri) {
+ if (((s_uv1[0] == t_uv1[0] && s_uv1[1] == t_uv1[1]) &&
+ (s_uv2[0] == t_uv2[0] && s_uv2[1] == t_uv2[1])) ||
+ ((s_uv2[0] == t_uv1[0] && s_uv2[1] == t_uv1[1]) &&
+ (s_uv1[0] == t_uv2[0] && s_uv1[1] == t_uv2[1])))
+ {
+ final_index = x + w * y;
+
+ /* If not an active pixel, bail out */
+ if (tempPoints[final_index].tri_index == -1)
return NOT_FOUND;
- }
- /*
- * If final point is an "edge pixel", use it's "real" neighbor instead
- */
- if (tempPoints[final_index].neighbour_pixel != -1) final_index = cPoint->neighbour_pixel;
+ /* If final point is an "edge pixel", use it's "real" neighbor instead */
+ if (tempPoints[final_index].neighbour_pixel != -1) {
+ final_index = tempPoints[final_index].neighbour_pixel;
+
+ /* If we ended up to our origin point */
+ if (final_index == (px + w * py))
+ return NOT_FOUND;
+ }
return final_index;
}
+
+ /*
+ * Find a point that is relatively at same edge position
+ * on this other face UV
+ */
+ lambda = closest_to_line_v2(
+ closest_point, pixel,
+ mloopuv[mlooptri[cPoint->tri_index].tri[edge1_index]].uv,
+ mloopuv[mlooptri[cPoint->tri_index].tri[edge2_index]].uv);
+ CLAMP(lambda, 0.0f, 1.0f);
+
+ sub_v2_v2v2(
+ dir_vec,
+ mloopuv[mlooptri[target_tri].tri[target_uv2]].uv,
+ mloopuv[mlooptri[target_tri].tri[target_uv1]].uv);
+
+ mul_v2_fl(dir_vec, lambda);
+
+ copy_v2_v2(pixel, mloopuv[mlooptri[target_tri].tri[target_uv1]].uv);
+ add_v2_v2(pixel, dir_vec);
+ pixel[0] = (pixel[0] * (float)w);
+ pixel[1] = (pixel[1] * (float)h);
+
+ final_pixel[0] = (int)floorf(pixel[0]);
+ final_pixel[1] = (int)floorf(pixel[1]);
+
+ /* If current pixel uv is outside of texture */
+ if (final_pixel[0] < 0 || final_pixel[0] >= w || final_pixel[1] < 0 || final_pixel[1] >= h)
+ return OUT_OF_TEXTURE;
+
+ final_index = final_pixel[0] + w * final_pixel[1];
+
+ /* If we ended up to our origin point ( mesh has smaller than pixel sized faces) */
+ if (final_index == (px + w * py))
+ return NOT_FOUND;
+ /* If found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */
+ if (tempPoints[final_index].tri_index != target_tri)
+ return NOT_FOUND;
+
+ /* If final point is an "edge pixel", use it's "real" neighbor instead */
+ if (tempPoints[final_index].neighbour_pixel != -1) {
+ final_index = tempPoints[final_index].neighbour_pixel;
+
+ /* If we ended up to our origin point */
+ if (final_index == (px + w * py))
+ return NOT_FOUND;
+ }
+
+ return final_index;
}
}
-/*
- * Create a surface for uv image sequence format
- */
-int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
+int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, float *progress, short *do_update)
{
/* Antialias jitter point relative coords */
- const float jitter5sample[10] = {
- 0.0f, 0.0f,
- -0.2f, -0.4f,
- 0.2f, 0.4f,
- 0.4f, -0.2f,
- -0.4f, 0.3f,
- };
- int ty;
- int w, h;
- int tottri;
+ const int aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
char uvname[MAX_CUSTOMDATA_LAYER_NAME];
- int active_points = 0;
- int error = 0;
+ uint32_t active_points = 0;
+ bool error = false;
PaintSurfaceData *sData;
DynamicPaintCanvasSettings *canvas = surface->canvas;
@@ -2177,7 +2540,9 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
Bounds2D *faceBB = NULL;
int *final_index;
- int aa_samples;
+
+ *progress = 0.0f;
+ *do_update = true;
if (!dm)
return setError(canvas, N_("Canvas mesh not updated"));
@@ -2186,7 +2551,7 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
mloop = dm->getLoopArray(dm);
mlooptri = dm->getLoopTriArray(dm);
- tottri = dm->getNumLoopTri(dm);
+ const int tottri = dm->getNumLoopTri(dm);
/* get uv map */
if (CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) {
@@ -2200,7 +2565,8 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
if (surface->image_resolution < 16 || surface->image_resolution > 8192)
return setError(canvas, N_("Invalid resolution"));
- w = h = surface->image_resolution;
+ const int w = surface->image_resolution;
+ const int h = w;
/*
* Start generating the surface
@@ -2208,156 +2574,60 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
printf("DynamicPaint: Preparing UV surface of %ix%i pixels and %i tris.\n", w, h, tottri);
/* Init data struct */
- if (surface->data) dynamicPaint_freeSurfaceData(surface);
+ if (surface->data)
+ dynamicPaint_freeSurfaceData(surface);
sData = surface->data = MEM_callocN(sizeof(PaintSurfaceData), "PaintSurfaceData");
if (!surface->data)
return setError(canvas, N_("Not enough free memory"));
- aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
- tempPoints = (struct PaintUVPoint *) MEM_callocN(w * h * sizeof(struct PaintUVPoint), "Temp PaintUVPoint");
- if (!tempPoints) error = 1;
+ tempPoints = MEM_callocN(w * h * sizeof(*tempPoints), "Temp PaintUVPoint");
+ if (!tempPoints)
+ error = true;
- final_index = (int *) MEM_callocN(w * h * sizeof(int), "Temp UV Final Indexes");
- if (!final_index) error = 1;
+ final_index = MEM_callocN(w * h * sizeof(*final_index), "Temp UV Final Indexes");
+ if (!final_index)
+ error = true;
- tempWeights = (struct Vec3f *) MEM_mallocN(w * h * aa_samples * sizeof(struct Vec3f), "Temp bWeights");
- if (!tempWeights) error = 1;
+ tempWeights = MEM_mallocN(w * h * aa_samples * sizeof(*tempWeights), "Temp bWeights");
+ if (!tempWeights)
+ error = true;
/*
* Generate a temporary bounding box array for UV faces to optimize
* the pixel-inside-a-face search.
*/
if (!error) {
- faceBB = (struct Bounds2D *) MEM_mallocN(tottri * sizeof(struct Bounds2D), "MPCanvasFaceBB");
- if (!faceBB) error = 1;
+ faceBB = MEM_mallocN(tottri * sizeof(*faceBB), "MPCanvasFaceBB");
+ if (!faceBB)
+ error = true;
}
- if (!error)
- for (ty = 0; ty < tottri; ty++) {
- int i;
+ *progress = 0.01f;
+ *do_update = true;
- copy_v2_v2(faceBB[ty].min, mloopuv[mlooptri[ty].tri[0]].uv);
- copy_v2_v2(faceBB[ty].max, mloopuv[mlooptri[ty].tri[0]].uv);
+ if (!error) {
+ for (int i = 0; i < tottri; i++) {
+ copy_v2_v2(faceBB[i].min, mloopuv[mlooptri[i].tri[0]].uv);
+ copy_v2_v2(faceBB[i].max, mloopuv[mlooptri[i].tri[0]].uv);
- for (i = 1; i < 3; i++) {
- CLAMP_MAX(faceBB[ty].min[0], mloopuv[mlooptri[ty].tri[i]].uv[0]);
- CLAMP_MAX(faceBB[ty].min[1], mloopuv[mlooptri[ty].tri[i]].uv[1]);
- CLAMP_MIN(faceBB[ty].max[0], mloopuv[mlooptri[ty].tri[i]].uv[0]);
- CLAMP_MIN(faceBB[ty].max[1], mloopuv[mlooptri[ty].tri[i]].uv[1]);
+ for (int j = 1; j < 3; j++) {
+ minmax_v2v2_v2(faceBB[i].min, faceBB[i].max, mloopuv[mlooptri[i].tri[j]].uv);
}
}
- /*
- * Loop through every pixel and check
- * if pixel is uv-mapped on a canvas face.
- */
- if (!error) {
-#pragma omp parallel for schedule(static)
- for (ty = 0; ty < h; ty++) {
- int tx;
- for (tx = 0; tx < w; tx++) {
- int i, sample;
- int index = tx + w * ty;
- PaintUVPoint *tPoint = (&tempPoints[index]);
-
- bool isInside = false; /* if point is inside a uv face */
-
- float d1[2], d2[2], d3[2], point[5][2];
- float dot00, dot01, dot02, dot11, dot12, invDenom, u, v;
-
- /* Init per pixel settings */
- tPoint->tri_index = -1;
- tPoint->neighbour_pixel = -1;
- tPoint->pixel_index = index;
-
- /* Actual pixel center, used when collision is found */
- point[0][0] = ((float)tx + 0.5f) / w;
- point[0][1] = ((float)ty + 0.5f) / h;
-
- /*
- * A pixel middle sample isn't enough to find very narrow polygons
- * So using 4 samples of each corner too
- */
- point[1][0] = ((float)tx) / w;
- point[1][1] = ((float)ty) / h;
-
- point[2][0] = ((float)tx + 1) / w;
- point[2][1] = ((float)ty) / h;
-
- point[3][0] = ((float)tx) / w;
- point[3][1] = ((float)ty + 1) / h;
-
- point[4][0] = ((float)tx + 1) / w;
- point[4][1] = ((float)ty + 1) / h;
-
-
- /* Loop through samples, starting from middle point */
- for (sample = 0; sample < 5; sample++) {
-
- /* Loop through every face in the mesh */
- for (i = 0; i < tottri; i++) {
-
- /* Check uv bb */
- if (faceBB[i].min[0] > (point[sample][0])) continue;
- if (faceBB[i].min[1] > (point[sample][1])) continue;
- if (faceBB[i].max[0] < (point[sample][0])) continue;
- if (faceBB[i].max[1] < (point[sample][1])) continue;
-
- /* Calculate point inside a triangle check
- * for uv0, 1, 2 */
- sub_v2_v2v2(d1, mloopuv[mlooptri[i].tri[2]].uv, mloopuv[mlooptri[i].tri[0]].uv); /* uv2 - uv0 */
- sub_v2_v2v2(d2, mloopuv[mlooptri[i].tri[1]].uv, mloopuv[mlooptri[i].tri[0]].uv); /* uv1 - uv0 */
- sub_v2_v2v2(d3, point[sample], mloopuv[mlooptri[i].tri[0]].uv); /* point - uv0 */
-
- dot00 = d1[0] * d1[0] + d1[1] * d1[1];
- dot01 = d1[0] * d2[0] + d1[1] * d2[1];
- dot02 = d1[0] * d3[0] + d1[1] * d3[1];
- dot11 = d2[0] * d2[0] + d2[1] * d2[1];
- dot12 = d2[0] * d3[0] + d2[1] * d3[1];
-
- invDenom = (dot00 * dot11 - dot01 * dot01);
- invDenom = invDenom ? 1.0f / invDenom : 1.0f;
- u = (dot11 * dot02 - dot01 * dot12) * invDenom;
- v = (dot00 * dot12 - dot01 * dot02) * invDenom;
-
- if ((u > 0) && (v > 0) && (u + v < 1)) { isInside = true; } /* is inside a triangle */
-
- /*
- * If point was inside the face
- */
- if (isInside) {
+ *progress = 0.02f;
+ *do_update = true;
- float uv1co[2], uv2co[2], uv3co[2], uv[2];
- int j;
+ /* Loop through every pixel and check if pixel is uv-mapped on a canvas face. */
+ DynamicPaintCreateUVSurfaceData data = {
+ .surface = surface, .tempPoints = tempPoints, .tempWeights = tempWeights,
+ .mlooptri = mlooptri, .mloopuv = mloopuv, .mloop = mloop, .tottri = tottri,
+ .faceBB = faceBB,
+ };
+ BLI_task_parallel_range(0, h, &data, dynamic_paint_create_uv_surface_direct_cb, h > 64 || tottri > 1000);
- /* Get triagnle uvs */
- copy_v2_v2(uv1co, mloopuv[mlooptri[i].tri[0]].uv);
- copy_v2_v2(uv2co, mloopuv[mlooptri[i].tri[1]].uv);
- copy_v2_v2(uv3co, mloopuv[mlooptri[i].tri[2]].uv);
-
- /* Add b-weights per anti-aliasing sample */
- for (j = 0; j < aa_samples; j++) {
- uv[0] = point[0][0] + jitter5sample[j * 2] / w;
- uv[1] = point[0][1] + jitter5sample[j * 2 + 1] / h;
-
- barycentric_weights_v2(uv1co, uv2co, uv3co, uv, tempWeights[index * aa_samples + j].v);
- }
-
- /* Set surface point face values */
- tPoint->tri_index = i;
-
- /* save vertex indexes */
- tPoint->v1 = mloop[mlooptri[i].tri[0]].v;
- tPoint->v2 = mloop[mlooptri[i].tri[1]].v;
- tPoint->v3 = mloop[mlooptri[i].tri[2]].v;
-
- sample = 5; /* make sure we exit sample loop as well */
- break;
- }
- }
- } /* sample loop */
- }
- }
+ *progress = 0.04f;
+ *do_update = true;
/*
* Now loop through every pixel that was left without index
@@ -2365,87 +2635,11 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
* If so use that polygon as pixel surface.
* (To avoid seams on uv island edges)
*/
-#pragma omp parallel for schedule(static)
- for (ty = 0; ty < h; ty++) {
- int tx;
- for (tx = 0; tx < w; tx++) {
- int index = tx + w * ty;
- PaintUVPoint *tPoint = (&tempPoints[index]);
-
- /* If point isn't't on canvas mesh */
- if (tPoint->tri_index == -1) {
- int u_min, u_max, v_min, v_max;
- int u, v, ind;
- float point[2];
-
- /* get loop area */
- u_min = (tx > 0) ? -1 : 0;
- u_max = (tx < (w - 1)) ? 1 : 0;
- v_min = (ty > 0) ? -1 : 0;
- v_max = (ty < (h - 1)) ? 1 : 0;
-
- point[0] = ((float)tx + 0.5f) / w;
- point[1] = ((float)ty + 0.5f) / h;
-
- /* search through defined area for neighbor */
- for (u = u_min; u <= u_max; u++)
- for (v = v_min; v <= v_max; v++) {
- /* if not this pixel itself */
- if (u != 0 || v != 0) {
- ind = (tx + u) + w * (ty + v);
-
- /* if neighbor has index */
- if (tempPoints[ind].tri_index != -1) {
-
- float uv1co[2], uv2co[2], uv3co[2], uv[2];
- int i = tempPoints[ind].tri_index, j;
-
- /* Now calculate pixel data for this pixel as it was on polygon surface */
- copy_v2_v2(uv1co, mloopuv[mlooptri[i].tri[0]].uv);
- copy_v2_v2(uv2co, mloopuv[mlooptri[i].tri[1]].uv);
- copy_v2_v2(uv3co, mloopuv[mlooptri[i].tri[2]].uv);
-
- /* Add b-weights per anti-aliasing sample */
- for (j = 0; j < aa_samples; j++) {
-
- uv[0] = point[0] + jitter5sample[j * 2] / w;
- uv[1] = point[1] + jitter5sample[j * 2 + 1] / h;
- barycentric_weights_v2(uv1co, uv2co, uv3co, uv, tempWeights[index * aa_samples + j].v);
- }
-
- /* Set values */
- tPoint->neighbour_pixel = ind; /* tri index */
+ data.active_points = &active_points;
+ BLI_task_parallel_range(0, h, &data, dynamic_paint_create_uv_surface_neighbor_cb, h > 64);
- /* save vertex indexes */
- tPoint->v1 = mloop[mlooptri[i].tri[0]].v;
- tPoint->v2 = mloop[mlooptri[i].tri[1]].v;
- tPoint->v3 = mloop[mlooptri[i].tri[2]].v;
-
- u = u_max + 1; /* make sure we exit outer loop as well */
- break;
- }
- }
- }
- }
- }
- }
-
- /*
- * When base loop is over convert found neighbor indexes to real ones
- * Also count the final number of active surface points
- */
- for (ty = 0; ty < h; ty++) {
- int tx;
- for (tx = 0; tx < w; tx++) {
- int index = tx + w * ty;
- PaintUVPoint *tPoint = &tempPoints[index];
-
- if (tPoint->tri_index == -1 && tPoint->neighbour_pixel != -1)
- tPoint->tri_index = tempPoints[tPoint->neighbour_pixel].tri_index;
- if (tPoint->tri_index != -1)
- active_points++;
- }
- }
+ *progress = 0.06f;
+ *do_update = true;
/* Generate surface adjacency data. */
{
@@ -2461,30 +2655,47 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
}
/* allocate memory */
sData->total_points = w * h;
- dynamicPaint_initAdjacencyData(surface, 1);
+ dynamicPaint_initAdjacencyData(surface, true);
if (sData->adj_data) {
PaintAdjData *ed = sData->adj_data;
- unsigned int n_pos = 0;
- for (ty = 0; ty < h; ty++) {
- int tx;
- for (tx = 0; tx < w; tx++) {
- int index = tx + w * ty;
+ int n_pos = 0;
+
+ MeshElemMap *vert_to_looptri_map;
+ int *vert_to_looptri_map_mem;
+
+ BKE_mesh_vert_looptri_map_create(
+ &vert_to_looptri_map, &vert_to_looptri_map_mem,
+ dm->getVertArray(dm), dm->getNumVerts(dm), mlooptri, tottri, mloop, dm->getNumLoops(dm));
+
+ for (int ty = 0; ty < h; ty++) {
+ for (int tx = 0; tx < w; tx++) {
+ const int index = tx + w * ty;
if (tempPoints[index].tri_index != -1) {
+ int start_pos = n_pos;
ed->n_index[final_index[index]] = n_pos;
ed->n_num[final_index[index]] = 0;
for (int i = 0; i < 8; i++) {
+ /* Try to find a neighboring pixel in defined direction. If not found, -1 is returned */
+ const int n_target = dynamic_paint_find_neighbour_pixel(
+ &data, vert_to_looptri_map, w, h, tx, ty, i);
+
+ if (n_target >= 0 && n_target != index) {
+ bool duplicate = false;
+ for (int j = start_pos; j < n_pos; j++) {
+ if (ed->n_target[j] == final_index[n_target]) {
+ duplicate = true;
+ break;
+ }
+ }
- /* Try to find a neighboring pixel in defined direction
- * If not found, -1 is returned */
- int n_target = dynamicPaint_findNeighbourPixel(tempPoints, dm, uvname, w, h, tx, ty, i);
-
- if (n_target >= 0) {
- ed->n_target[n_pos] = final_index[n_target];
- ed->n_num[final_index[index]]++;
- n_pos++;
+ if (!duplicate) {
+ ed->n_target[n_pos] = final_index[n_target];
+ ed->n_num[final_index[index]]++;
+ n_pos++;
+ }
}
else if (n_target == ON_MESH_EDGE || n_target == OUT_OF_TEXTURE) {
ed->flags[final_index[index]] |= ADJ_ON_MESH_EDGE;
@@ -2493,43 +2704,50 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
}
}
}
+
+ MEM_freeN(vert_to_looptri_map);
+ MEM_freeN(vert_to_looptri_map_mem);
}
}
+ *progress = 0.08f;
+ *do_update = true;
+
/* Create final surface data without inactive points */
- {
- ImgSeqFormatData *f_data = MEM_callocN(sizeof(struct ImgSeqFormatData), "ImgSeqFormatData");
- if (f_data) {
- f_data->uv_p = MEM_callocN(active_points * sizeof(struct PaintUVPoint), "PaintUVPoint");
- f_data->barycentricWeights = MEM_callocN(active_points * aa_samples * sizeof(struct Vec3f), "PaintUVPoint");
+ ImgSeqFormatData *f_data = MEM_callocN(sizeof(*f_data), "ImgSeqFormatData");
+ if (f_data) {
+ f_data->uv_p = MEM_callocN(active_points * sizeof(*f_data->uv_p), "PaintUVPoint");
+ f_data->barycentricWeights =
+ MEM_callocN(active_points * aa_samples * sizeof(*f_data->barycentricWeights), "PaintUVPoint");
- if (!f_data->uv_p || !f_data->barycentricWeights) error = 1;
- }
- else {
+ if (!f_data->uv_p || !f_data->barycentricWeights)
error = 1;
- }
+ }
+ else {
+ error = 1;
+ }
- sData->total_points = active_points;
-
- /* in case of allocation error, free everything */
- if (error) {
- if (f_data) {
- if (f_data->uv_p) MEM_freeN(f_data->uv_p);
- if (f_data->barycentricWeights) MEM_freeN(f_data->barycentricWeights);
- MEM_freeN(f_data);
- }
+ /* in case of allocation error, free everything */
+ if (error) {
+ if (f_data) {
+ if (f_data->uv_p)
+ MEM_freeN(f_data->uv_p);
+ if (f_data->barycentricWeights)
+ MEM_freeN(f_data->barycentricWeights);
+ MEM_freeN(f_data);
}
- else {
- int index, cursor = 0;
- sData->total_points = active_points;
- sData->format_data = f_data;
-
- for (index = 0; index < (w * h); index++) {
- if (tempPoints[index].tri_index != -1) {
- memcpy(&f_data->uv_p[cursor], &tempPoints[index], sizeof(PaintUVPoint));
- memcpy(&f_data->barycentricWeights[cursor * aa_samples], &tempWeights[index * aa_samples], sizeof(Vec3f) * aa_samples);
- cursor++;
- }
+ sData->total_points = 0;
+ }
+ else {
+ sData->total_points = (int)active_points;
+ sData->format_data = f_data;
+
+ for (int index = 0, cursor = 0; index < (w * h); index++) {
+ if (tempPoints[index].tri_index != -1) {
+ memcpy(&f_data->uv_p[cursor], &tempPoints[index], sizeof(PaintUVPoint));
+ memcpy(&f_data->barycentricWeights[cursor * aa_samples], &tempWeights[index * aa_samples],
+ sizeof(*tempWeights) * aa_samples);
+ cursor++;
}
}
}
@@ -2537,10 +2755,14 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
if (error == 1)
setError(canvas, N_("Not enough free memory"));
- if (faceBB) MEM_freeN(faceBB);
- if (tempPoints) MEM_freeN(tempPoints);
- if (tempWeights) MEM_freeN(tempWeights);
- if (final_index) MEM_freeN(final_index);
+ if (faceBB)
+ MEM_freeN(faceBB);
+ if (tempPoints)
+ MEM_freeN(tempPoints);
+ if (tempWeights)
+ MEM_freeN(tempWeights);
+ if (final_index)
+ MEM_freeN(final_index);
/* Init surface type data */
if (!error) {
@@ -2550,38 +2772,126 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
/* -----------------------------------------------------------------
* For debug, output pixel statuses to the color map
* -----------------------------------------------------------------*/
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++)
- {
+ for (index = 0; index < sData->total_points; index++) {
ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
PaintUVPoint *uvPoint = &((PaintUVPoint *)f_data->uv_p)[index];
PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
pPoint->alpha = 1.0f;
/* Every pixel that is assigned as "edge pixel" gets blue color */
- if (uvPoint->neighbour_pixel != -1) pPoint->color[2] = 1.0f;
+ if (uvPoint->neighbour_pixel != -1)
+ pPoint->color[2] = 1.0f;
/* and every pixel that finally got an polygon gets red color */
- if (uvPoint->tri_index != -1) pPoint->color[0] = 1.0f;
/* green color shows pixel face index hash */
- if (uvPoint->tri_index != -1) pPoint->color[1] = (float)(uvPoint->tri_index % 255) / 256.0f;
+ if (uvPoint->tri_index != -1) {
+ pPoint->color[0] = 1.0f;
+ pPoint->color[1] = (float)(uvPoint->tri_index % 255) / 256.0f;
+ }
}
-
#endif
+
dynamicPaint_setInitialColor(scene, surface);
}
+ *progress = 0.09f;
+ *do_update = true;
+
return (error == 0);
}
/*
* Outputs an image file from uv surface data.
*/
+typedef struct DynamicPaintOutputSurfaceImageData {
+ const DynamicPaintSurface *surface;
+ ImBuf *ibuf;
+} DynamicPaintOutputSurfaceImageData;
+
+static void dynamic_paint_output_surface_image_paint_cb(void *userdata, const int index)
+{
+ const DynamicPaintOutputSurfaceImageData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintPoint *point = &((PaintPoint *)surface->data->type_data)[index];
+
+ ImBuf *ibuf = data->ibuf;
+ /* image buffer position */
+ const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
+
+ /* blend wet and dry layers */
+ blendColors(point->color, point->color[3], point->e_color, point->e_color[3], &ibuf->rect_float[pos]);
+
+ /* Multiply color by alpha if enabled */
+ if (surface->flags & MOD_DPAINT_MULALPHA) {
+ mul_v3_fl(&ibuf->rect_float[pos], ibuf->rect_float[pos + 3]);
+ }
+}
+
+static void dynamic_paint_output_surface_image_displace_cb(void *userdata, const int index)
+{
+ const DynamicPaintOutputSurfaceImageData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ float depth = ((float *)surface->data->type_data)[index];
+
+ ImBuf *ibuf = data->ibuf;
+ /* image buffer position */
+ const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
+
+ if (surface->depth_clamp)
+ depth /= surface->depth_clamp;
+
+ if (surface->disp_type == MOD_DPAINT_DISP_DISPLACE) {
+ depth = (0.5f - depth / 2.0f);
+ }
+
+ CLAMP(depth, 0.0f, 1.0f);
+
+ copy_v3_fl(&ibuf->rect_float[pos], depth);
+ ibuf->rect_float[pos + 3] = 1.0f;
+}
+
+static void dynamic_paint_output_surface_image_wave_cb(void *userdata, const int index)
+{
+ const DynamicPaintOutputSurfaceImageData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintWavePoint *wPoint = &((PaintWavePoint *)surface->data->type_data)[index];
+ float depth = wPoint->height;
+
+ ImBuf *ibuf = data->ibuf;
+ /* image buffer position */
+ const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
+
+ if (surface->depth_clamp)
+ depth /= surface->depth_clamp;
+
+ depth = (0.5f + depth / 2.0f);
+ CLAMP(depth, 0.0f, 1.0f);
+
+ copy_v3_fl(&ibuf->rect_float[pos], depth);
+ ibuf->rect_float[pos + 3] = 1.0f;
+}
+
+static void dynamic_paint_output_surface_image_wetmap_cb(void *userdata, const int index)
+{
+ const DynamicPaintOutputSurfaceImageData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintPoint *point = &((PaintPoint *)surface->data->type_data)[index];
+
+ ImBuf *ibuf = data->ibuf;
+ /* image buffer position */
+ const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
+
+ copy_v3_fl(&ibuf->rect_float[pos], (point->wetness > 1.0f) ? 1.0f : point->wetness);
+ ibuf->rect_float[pos + 3] = 1.0f;
+}
+
void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filename, short output_layer)
{
- int index;
ImBuf *ibuf = NULL;
PaintSurfaceData *sData = surface->data;
- ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
/* OpenEXR or PNG */
int format = (surface->image_fileformat & MOD_DPAINT_IMGFORMAT_OPENEXR) ? R_IMF_IMTYPE_OPENEXR : R_IMF_IMTYPE_PNG;
char output_file[FILE_MAX];
@@ -2592,7 +2902,8 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filenam
}
/* if selected format is openexr, but current build doesnt support one */
#ifndef WITH_OPENEXR
- if (format == R_IMF_IMTYPE_OPENEXR) format = R_IMF_IMTYPE_PNG;
+ if (format == R_IMF_IMTYPE_OPENEXR)
+ format = R_IMF_IMTYPE_PNG;
#endif
BLI_strncpy(output_file, filename, sizeof(output_file));
BKE_image_path_ensure_ext_from_imtype(output_file, format);
@@ -2608,82 +2919,66 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filenam
return;
}
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- int pos = f_data->uv_p[index].pixel_index * 4; /* image buffer position */
-
- /* Set values of preferred type */
- if (output_layer == 1) {
- /* wetmap */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- PaintPoint *point = &((PaintPoint *)sData->type_data)[index];
- float value = (point->wetness > 1.0f) ? 1.0f : point->wetness;
-
- ibuf->rect_float[pos] = value;
- ibuf->rect_float[pos + 1] = value;
- ibuf->rect_float[pos + 2] = value;
- ibuf->rect_float[pos + 3] = 1.0f;
- }
- }
- else if (output_layer == 0) {
- /* Paintmap */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- PaintPoint *point = &((PaintPoint *)sData->type_data)[index];
-
- /* blend wet and dry layers */
- blendColors(point->color, point->color[3], point->e_color, point->e_color[3], &ibuf->rect_float[pos]);
-
- /* Multiply color by alpha if enabled */
- if (surface->flags & MOD_DPAINT_MULALPHA) {
- ibuf->rect_float[pos] *= ibuf->rect_float[pos + 3];
- ibuf->rect_float[pos + 1] *= ibuf->rect_float[pos + 3];
- ibuf->rect_float[pos + 2] *= ibuf->rect_float[pos + 3];
- }
+ DynamicPaintOutputSurfaceImageData data = {.surface = surface, .ibuf = ibuf};
+ switch (surface->type) {
+ case MOD_DPAINT_SURFACE_T_PAINT:
+ switch (output_layer) {
+ case 0:
+ BLI_task_parallel_range(0, sData->total_points, &data,
+ dynamic_paint_output_surface_image_paint_cb, sData->total_points > 10000);
+ break;
+ case 1:
+ BLI_task_parallel_range(0, sData->total_points, &data,
+ dynamic_paint_output_surface_image_wetmap_cb, sData->total_points > 10000);
+ break;
+ default:
+ BLI_assert(0);
+ break;
}
- /* displace */
- else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
- float depth = ((float *)sData->type_data)[index];
- if (surface->depth_clamp)
- depth /= surface->depth_clamp;
-
- if (surface->disp_type == MOD_DPAINT_DISP_DISPLACE) {
- depth = (0.5f - depth / 2.0f);
- }
-
- CLAMP(depth, 0.0f, 1.0f);
-
- ibuf->rect_float[pos] = depth;
- ibuf->rect_float[pos + 1] = depth;
- ibuf->rect_float[pos + 2] = depth;
- ibuf->rect_float[pos + 3] = 1.0f;
+ break;
+ case MOD_DPAINT_SURFACE_T_DISPLACE:
+ switch (output_layer) {
+ case 0:
+ BLI_task_parallel_range(0, sData->total_points, &data,
+ dynamic_paint_output_surface_image_displace_cb, sData->total_points > 10000);
+ break;
+ case 1:
+ break;
+ default:
+ BLI_assert(0);
+ break;
}
- /* waves */
- else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
- PaintWavePoint *wPoint = &((PaintWavePoint *)sData->type_data)[index];
- float depth = wPoint->height;
- if (surface->depth_clamp)
- depth /= surface->depth_clamp;
- depth = (0.5f + depth / 2.0f);
- CLAMP(depth, 0.0f, 1.0f);
-
- ibuf->rect_float[pos] = depth;
- ibuf->rect_float[pos + 1] = depth;
- ibuf->rect_float[pos + 2] = depth;
- ibuf->rect_float[pos + 3] = 1.0f;
+ break;
+ case MOD_DPAINT_SURFACE_T_WAVE:
+ switch (output_layer) {
+ case 0:
+ BLI_task_parallel_range(0, sData->total_points, &data,
+ dynamic_paint_output_surface_image_wave_cb, sData->total_points > 10000);
+ break;
+ case 1:
+ break;
+ default:
+ BLI_assert(0);
+ break;
}
- }
+ break;
+ default:
+ BLI_assert(0);
+ break;
}
/* Set output format, png in case exr isn't supported */
- ibuf->ftype = IMB_FTYPE_PNG;
- ibuf->foptions.quality = 15;
-
#ifdef WITH_OPENEXR
if (format == R_IMF_IMTYPE_OPENEXR) { /* OpenEXR 32-bit float */
ibuf->ftype = IMB_FTYPE_OPENEXR;
ibuf->foptions.flag |= OPENEXR_COMPRESS;
}
+ else
#endif
+ {
+ ibuf->ftype = IMB_FTYPE_PNG;
+ ibuf->foptions.quality = 15;
+ }
/* Save image */
IMB_saveiff(ibuf, output_file, IB_rectfloat);
@@ -2749,7 +3044,7 @@ static void dynamicPaint_freeBrushMaterials(BrushMaterials *bMats)
* Get material diffuse color and alpha (including linked textures) in given coordinates
*/
static void dynamicPaint_doMaterialTex(
- BrushMaterials *bMats, float color[3], float *alpha, Object *brushOb,
+ const BrushMaterials *bMats, float color[3], float *alpha, Object *brushOb,
const float volume_co[3], const float surface_co[3],
int triIndex, DerivedMesh *orcoDm)
{
@@ -2762,9 +3057,11 @@ static void dynamicPaint_doMaterialTex(
if (mat == NULL) {
if (bMats->ob_mats) {
int mat_nr = mpoly[mlooptri[triIndex].poly].mat_nr;
- if (mat_nr >= (*give_totcolp(brushOb))) return;
+ if (mat_nr >= (*give_totcolp(brushOb)))
+ return;
mat = bMats->ob_mats[mat_nr];
- if (mat == NULL) return; /* No material assigned */
+ if (mat == NULL)
+ return; /* No material assigned */
}
else {
return;
@@ -2777,7 +3074,7 @@ static void dynamicPaint_doMaterialTex(
/***************************** Ray / Nearest Point Utils ******************************/
-/* A modified callback to bvh tree raycast. The tree must bust have been built using bvhtree_from_mesh_looptri.
+/* A modified callback to bvh tree raycast. The tree must have been built using bvhtree_from_mesh_looptri.
* userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree.
*
* To optimize brush detection speed this doesn't calculate hit coordinates or normal.
@@ -2803,10 +3100,9 @@ static void mesh_tris_spherecast_dp(void *userdata, int index, const BVHTreeRay
hit->dist = dist;
hit->no[0] = 0.0f;
}
-
}
-/* A modified callback to bvh tree nearest point. The tree must bust have been built using bvhtree_from_mesh_looptri.
+/* A modified callback to bvh tree nearest point. The tree must have been built using bvhtree_from_mesh_looptri.
* userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree.
*
* To optimize brush detection speed this doesn't calculate hit normal.
@@ -2849,15 +3145,15 @@ static void mesh_tris_nearest_point_dp(void *userdata, int index, const float co
* operations when using substeps
*/
static void dynamicPaint_mixPaintColors(
- DynamicPaintSurface *surface, int index, int paintFlags,
- const float paintColor[3], float *paintAlpha, float *paintWetness, float *timescale)
+ const DynamicPaintSurface *surface, const int index, const int paintFlags,
+ const float paintColor[3], const float paintAlpha, const float paintWetness, const float timescale)
{
PaintPoint *pPoint = &((PaintPoint *)surface->data->type_data)[index];
/* Add paint */
if (!(paintFlags & MOD_DPAINT_ERASE)) {
float mix[4];
- float temp_alpha = (*paintAlpha) * ((paintFlags & MOD_DPAINT_ABS_ALPHA) ? 1.0f : (*timescale));
+ float temp_alpha = paintAlpha * ((paintFlags & MOD_DPAINT_ABS_ALPHA) ? 1.0f : timescale);
/* mix brush color with wet layer color */
blendColors(pPoint->e_color, pPoint->e_color[3], paintColor, temp_alpha, mix);
@@ -2866,11 +3162,11 @@ static void dynamicPaint_mixPaintColors(
/* mix wetness and alpha depending on selected alpha mode */
if (paintFlags & MOD_DPAINT_ABS_ALPHA) {
/* update values to the brush level unless theyre higher already */
- CLAMP_MIN(pPoint->e_color[3], *paintAlpha);
- CLAMP_MIN(pPoint->wetness, *paintWetness);
+ CLAMP_MIN(pPoint->e_color[3], paintAlpha);
+ CLAMP_MIN(pPoint->wetness, paintWetness);
}
else {
- float wetness = (*paintWetness);
+ float wetness = paintWetness;
CLAMP(wetness, 0.0f, 1.0f);
pPoint->e_color[3] = mix[3];
pPoint->wetness = pPoint->wetness * (1.0f - wetness) + wetness;
@@ -2884,7 +3180,7 @@ static void dynamicPaint_mixPaintColors(
else {
float a_ratio, a_highest;
float wetness;
- float invFact = 1.0f - (*paintAlpha);
+ float invFact = 1.0f - paintAlpha;
/*
* Make highest alpha to match erased value
@@ -2900,47 +3196,57 @@ static void dynamicPaint_mixPaintColors(
}
}
else {
- pPoint->e_color[3] -= (*paintAlpha) * (*timescale);
+ pPoint->e_color[3] -= paintAlpha * timescale;
CLAMP_MIN(pPoint->e_color[3], 0.0f);
- pPoint->color[3] -= (*paintAlpha) * (*timescale);
+ pPoint->color[3] -= paintAlpha * timescale;
CLAMP_MIN(pPoint->color[3], 0.0f);
}
- wetness = (1.0f - (*paintWetness)) * pPoint->e_color[3];
+ wetness = (1.0f - paintWetness) * pPoint->e_color[3];
CLAMP_MAX(pPoint->wetness, wetness);
}
}
/* applies given brush intersection value for wave surface */
-static void dynamicPaint_mixWaveHeight(PaintWavePoint *wPoint, DynamicPaintBrushSettings *brush, float isect_height)
+static void dynamicPaint_mixWaveHeight(
+ PaintWavePoint *wPoint, const DynamicPaintBrushSettings *brush, float isect_height)
{
- float isect_change = isect_height - wPoint->brush_isect;
- int hit = 0;
+ const float isect_change = isect_height - wPoint->brush_isect;
+ const float wave_factor = brush->wave_factor;
+ bool hit = false;
+
/* intersection marked regardless of brush type or hit */
wPoint->brush_isect = isect_height;
wPoint->state = DPAINT_WAVE_ISECT_CHANGED;
- isect_height *= brush->wave_factor;
+ isect_height *= wave_factor;
/* determine hit depending on wave_factor */
- if (brush->wave_factor > 0.0f && wPoint->height > isect_height)
- hit = 1;
- else if (brush->wave_factor < 0.0f && wPoint->height < isect_height)
- hit = 1;
+ if (wave_factor > 0.0f && wPoint->height > isect_height)
+ hit = true;
+ else if (wave_factor < 0.0f && wPoint->height < isect_height)
+ hit = true;
if (hit) {
- if (brush->wave_type == MOD_DPAINT_WAVEB_DEPTH) {
- wPoint->height = isect_height;
- wPoint->state = DPAINT_WAVE_OBSTACLE;
- wPoint->velocity = 0.0f;
- }
- else if (brush->wave_type == MOD_DPAINT_WAVEB_FORCE)
- wPoint->velocity = isect_height;
- else if (brush->wave_type == MOD_DPAINT_WAVEB_REFLECT)
- wPoint->state = DPAINT_WAVE_REFLECT_ONLY;
- else if (brush->wave_type == MOD_DPAINT_WAVEB_CHANGE) {
- if (isect_change < 0.0f)
- wPoint->height += isect_change * brush->wave_factor;
+ switch (brush->wave_type) {
+ case MOD_DPAINT_WAVEB_DEPTH:
+ wPoint->height = isect_height;
+ wPoint->state = DPAINT_WAVE_OBSTACLE;
+ wPoint->velocity = 0.0f;
+ break;
+ case MOD_DPAINT_WAVEB_FORCE:
+ wPoint->velocity = isect_height;
+ break;
+ case MOD_DPAINT_WAVEB_REFLECT:
+ wPoint->state = DPAINT_WAVE_REFLECT_ONLY;
+ break;
+ case MOD_DPAINT_WAVEB_CHANGE:
+ if (isect_change < 0.0f)
+ wPoint->height += isect_change * wave_factor;
+ break;
+ default:
+ BLI_assert(0);
+ break;
}
}
}
@@ -2948,8 +3254,9 @@ static void dynamicPaint_mixWaveHeight(PaintWavePoint *wPoint, DynamicPaintBrush
/*
* add brush results to the surface data depending on surface type
*/
-static void dynamicPaint_updatePointData(DynamicPaintSurface *surface, unsigned int index, DynamicPaintBrushSettings *brush,
- float paint[3], float influence, float depth, float vel_factor, float timescale)
+static void dynamicPaint_updatePointData(
+ const DynamicPaintSurface *surface, const int index, const DynamicPaintBrushSettings *brush,
+ float paint[3], float influence, float depth, float vel_factor, const float timescale)
{
PaintSurfaceData *sData = surface->data;
float strength;
@@ -2969,9 +3276,7 @@ static void dynamicPaint_updatePointData(DynamicPaintSurface *surface, unsigned
if (do_colorband(brush->vel_ramp, vel_factor, coba_res)) {
if (brush->flags & MOD_DPAINT_VELOCITY_COLOR) {
- paint[0] = coba_res[0];
- paint[1] = coba_res[1];
- paint[2] = coba_res[2];
+ copy_v3_v3(paint, coba_res);
}
if (brush->flags & MOD_DPAINT_VELOCITY_ALPHA)
strength *= coba_res[3];
@@ -2982,12 +3287,10 @@ static void dynamicPaint_updatePointData(DynamicPaintSurface *surface, unsigned
/* mix paint surface */
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
-
float paintWetness = brush->wetness * strength;
float paintAlpha = strength;
- dynamicPaint_mixPaintColors(surface, index, brush->flags, paint, &paintAlpha, &paintWetness, &timescale);
-
+ dynamicPaint_mixPaintColors(surface, index, brush->flags, paint, paintAlpha, paintWetness, timescale);
}
/* displace surface */
else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
@@ -3002,10 +3305,10 @@ static void dynamicPaint_updatePointData(DynamicPaintSurface *surface, unsigned
if (brush->flags & MOD_DPAINT_ERASE) {
value[index] *= (1.0f - strength);
- if (value[index] < 0.0f) value[index] = 0.0f;
+ CLAMP_MIN(value[index], 0.0f);
}
else {
- if (value[index] < depth) value[index] = depth;
+ CLAMP_MIN(value[index], depth);
}
}
/* vertex weight group surface */
@@ -3014,10 +3317,10 @@ static void dynamicPaint_updatePointData(DynamicPaintSurface *surface, unsigned
if (brush->flags & MOD_DPAINT_ERASE) {
value[index] *= (1.0f - strength);
- if (value[index] < 0.0f) value[index] = 0.0f;
+ CLAMP_MIN(value[index], 0.0f);
}
else {
- if (value[index] < strength) value[index] = strength;
+ CLAMP_MIN(value[index], strength);
}
}
/* wave surface */
@@ -3026,8 +3329,7 @@ static void dynamicPaint_updatePointData(DynamicPaintSurface *surface, unsigned
CLAMP(depth, 0.0f - brush->wave_clamp, brush->wave_clamp);
}
- dynamicPaint_mixWaveHeight(&((PaintWavePoint *)sData->type_data)[index],
- brush, 0.0f - depth);
+ dynamicPaint_mixWaveHeight(&((PaintWavePoint *)sData->type_data)[index], brush, 0.0f - depth);
}
/* doing velocity based painting */
@@ -3037,19 +3339,57 @@ static void dynamicPaint_updatePointData(DynamicPaintSurface *surface, unsigned
}
/* checks whether surface and brush bounds intersect depending on brush type */
-static int meshBrush_boundsIntersect(Bounds3D *b1, Bounds3D *b2, DynamicPaintBrushSettings *brush, float brush_radius)
+static bool meshBrush_boundsIntersect(Bounds3D *b1, Bounds3D *b2, DynamicPaintBrushSettings *brush, float brush_radius)
{
if (brush->collision == MOD_DPAINT_COL_VOLUME)
return boundsIntersect(b1, b2);
else if (brush->collision == MOD_DPAINT_COL_DIST || brush->collision == MOD_DPAINT_COL_VOLDIST)
return boundsIntersectDist(b1, b2, brush_radius);
- else return 1;
+ return true;
}
/* calculate velocity for mesh vertices */
-static void dynamicPaint_brushMeshCalculateVelocity(Scene *scene, Object *ob, DynamicPaintBrushSettings *brush, Vec3f **brushVel, float timescale)
+typedef struct DynamicPaintBrushVelocityData {
+ Vec3f *brush_vel;
+
+ const MVert *mvert_p;
+ const MVert *mvert_c;
+
+ float (*obmat)[4];
+ float (*prev_obmat)[4];
+
+ const float timescale;
+} DynamicPaintBrushVelocityData;
+
+static void dynamic_paint_brush_velocity_compute_cb(void *userdata, const int i)
+{
+ const DynamicPaintBrushVelocityData *data = userdata;
+
+ Vec3f *brush_vel = data->brush_vel;
+
+ const MVert *mvert_p = data->mvert_p;
+ const MVert *mvert_c = data->mvert_c;
+
+ float (*obmat)[4] = data->obmat;
+ float (*prev_obmat)[4] = data->prev_obmat;
+
+ const float timescale = data->timescale;
+
+ float p1[3], p2[3];
+
+ copy_v3_v3(p1, mvert_p[i].co);
+ mul_m4_v3(prev_obmat, p1);
+
+ copy_v3_v3(p2, mvert_c[i].co);
+ mul_m4_v3(obmat, p2);
+
+ sub_v3_v3v3(brush_vel[i].v, p2, p1);
+ mul_v3_fl(brush_vel[i].v, 1.0f / timescale);
+}
+
+static void dynamicPaint_brushMeshCalculateVelocity(
+ Scene *scene, Object *ob, DynamicPaintBrushSettings *brush, Vec3f **brushVel, float timescale)
{
- int i;
float prev_obmat[4][4];
DerivedMesh *dm_p, *dm_c;
MVert *mvert_p, *mvert_c;
@@ -3069,7 +3409,8 @@ static void dynamicPaint_brushMeshCalculateVelocity(Scene *scene, Object *ob, Dy
scene->r.cfra = prev_fra;
scene->r.subframe = prev_sfra;
- BKE_object_modifier_update_subframe(scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
+ BKE_object_modifier_update_subframe(
+ scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
dm_p = CDDM_copy(brush->dm);
numOfVerts_p = dm_p->getNumVerts(dm_p);
mvert_p = dm_p->getVertArray(dm_p);
@@ -3079,33 +3420,27 @@ static void dynamicPaint_brushMeshCalculateVelocity(Scene *scene, Object *ob, Dy
scene->r.cfra = cur_fra;
scene->r.subframe = cur_sfra;
- BKE_object_modifier_update_subframe(scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
+ BKE_object_modifier_update_subframe(
+ scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
dm_c = brush->dm;
numOfVerts_c = dm_c->getNumVerts(dm_c);
mvert_c = dm_p->getVertArray(dm_c);
(*brushVel) = (struct Vec3f *) MEM_mallocN(numOfVerts_c * sizeof(Vec3f), "Dynamic Paint brush velocity");
- if (!(*brushVel)) return;
+ if (!(*brushVel))
+ return;
- /* if mesh is constructive -> num of verts has changed,
- * only use current frame derived mesh */
+ /* if mesh is constructive -> num of verts has changed, only use current frame derived mesh */
if (numOfVerts_p != numOfVerts_c)
mvert_p = mvert_c;
/* calculate speed */
-#pragma omp parallel for schedule(static)
- for (i = 0; i < numOfVerts_c; i++) {
- float p1[3], p2[3];
-
- copy_v3_v3(p1, mvert_p[i].co);
- mul_m4_v3(prev_obmat, p1);
-
- copy_v3_v3(p2, mvert_c[i].co);
- mul_m4_v3(ob->obmat, p2);
-
- sub_v3_v3v3((*brushVel)[i].v, p2, p1);
- mul_v3_fl((*brushVel)[i].v, 1.0f / timescale);
- }
+ DynamicPaintBrushVelocityData data = {
+ .brush_vel = *brushVel,
+ .mvert_p = mvert_p, .mvert_c = mvert_c, .obmat = ob->obmat, .prev_obmat = prev_obmat,
+ .timescale = timescale,
+ };
+ BLI_task_parallel_range(0, numOfVerts_c, &data, dynamic_paint_brush_velocity_compute_cb, numOfVerts_c > 10000);
dm_p->release(dm_p);
}
@@ -3129,13 +3464,15 @@ static void dynamicPaint_brushObjectCalculateVelocity(Scene *scene, Object *ob,
/* previous frame dm */
scene->r.cfra = prev_fra;
scene->r.subframe = prev_sfra;
- BKE_object_modifier_update_subframe(scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
+ BKE_object_modifier_update_subframe(
+ scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
copy_m4_m4(prev_obmat, ob->obmat);
/* current frame dm */
scene->r.cfra = cur_fra;
scene->r.subframe = cur_sfra;
- BKE_object_modifier_update_subframe(scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
+ BKE_object_modifier_update_subframe(
+ scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
/* calculate speed */
mul_m4_v3(prev_obmat, prev_loc);
@@ -3145,9 +3482,366 @@ static void dynamicPaint_brushObjectCalculateVelocity(Scene *scene, Object *ob,
mul_v3_fl(brushVel->v, 1.0f / timescale);
}
+typedef struct DynamicPaintPaintData {
+ const DynamicPaintSurface *surface;
+ const DynamicPaintBrushSettings *brush;
+ Object *brushOb;
+ const BrushMaterials *bMats;
+ const Scene *scene;
+ const float timescale;
+ const int c_index;
+
+ DerivedMesh *dm;
+ const MVert *mvert;
+ const MLoop *mloop;
+ const MLoopTri *mlooptri;
+ const float brush_radius;
+ const float *avg_brushNor;
+ const Vec3f *brushVelocity;
+
+ const ParticleSystem *psys;
+ const float solidradius;
+
+ void *treeData;
+
+ float *pointCoord;
+} DynamicPaintPaintData;
+
/*
* Paint a brush object mesh to the surface
*/
+static void dynamic_paint_paint_mesh_cell_point_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int id, const int UNUSED(threadid))
+{
+ const DynamicPaintPaintData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ const PaintBakeData *bData = sData->bData;
+ VolumeGrid *grid = bData->grid;
+
+ const DynamicPaintBrushSettings *brush = data->brush;
+ Object *brushOb = data->brushOb;
+ const BrushMaterials *bMats = data->bMats;
+
+ const Scene *scene = data->scene;
+ const float timescale = data->timescale;
+ const int c_index = data->c_index;
+
+ DerivedMesh *dm = data->dm;
+ const MVert *mvert = data->mvert;
+ const MLoop *mloop = data->mloop;
+ const MLoopTri *mlooptri = data->mlooptri;
+ const float brush_radius = data->brush_radius;
+ const float *avg_brushNor = data->avg_brushNor;
+ const Vec3f *brushVelocity = data->brushVelocity;
+
+ BVHTreeFromMesh *treeData = data->treeData;
+
+ const int index = grid->t_index[grid->s_pos[c_index] + id];
+ const int samples = bData->s_num[index];
+ int ss;
+ float total_sample = (float)samples;
+ float brushStrength = 0.0f; /* brush influence factor */
+ float depth = 0.0f; /* brush intersection depth */
+ float velocity_val = 0.0f;
+
+ float paintColor[3] = {0.0f};
+ int numOfHits = 0;
+
+ /* for image sequence anti-aliasing, use gaussian factors */
+ if (samples > 1 && surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
+ total_sample = gaussianTotal;
+
+ /* Supersampling */
+ for (ss = 0; ss < samples; ss++) {
+ float ray_start[3], ray_dir[3];
+ float sample_factor = 0.0f;
+ float sampleStrength = 0.0f;
+ BVHTreeRayHit hit;
+ BVHTreeNearest nearest;
+ short hit_found = 0;
+
+ /* volume sample */
+ float volume_factor = 0.0f;
+ /* proximity sample */
+ float proximity_factor = 0.0f;
+ float prox_colorband[4] = {0.0f};
+ const bool inner_proximity = (brush->flags & MOD_DPAINT_INVERSE_PROX &&
+ brush->collision == MOD_DPAINT_COL_VOLDIST);
+
+ /* hit data */
+ float hitCoord[3];
+ int hitTri = -1;
+
+ /* Supersampling factor */
+ if (samples > 1 && surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
+ sample_factor = gaussianFactors[ss];
+ else
+ sample_factor = 1.0f;
+
+ /* Get current sample position in world coordinates */
+ copy_v3_v3(ray_start, bData->realCoord[bData->s_pos[index] + ss].v);
+ copy_v3_v3(ray_dir, bData->bNormal[index].invNorm);
+
+ /* a simple hack to minimize chance of ray leaks at identical ray <-> edge locations */
+ add_v3_fl(ray_start, 0.001f);
+
+ hit.index = -1;
+ hit.dist = BVH_RAYCAST_DIST_MAX;
+ nearest.index = -1;
+ nearest.dist_sq = brush_radius * brush_radius; /* find_nearest uses squared distance */
+
+ /* Check volume collision */
+ if (ELEM(brush->collision, MOD_DPAINT_COL_VOLUME, MOD_DPAINT_COL_VOLDIST)) {
+ BLI_bvhtree_ray_cast(treeData->tree, ray_start, ray_dir, 0.0f, &hit, mesh_tris_spherecast_dp, treeData);
+ if (hit.index != -1) {
+ /* We hit a triangle, now check if collision point normal is facing the point */
+
+ /* For optimization sake, hit point normal isn't calculated in ray cast loop */
+ const int vtri[3] = {
+ mloop[mlooptri[hit.index].tri[0]].v,
+ mloop[mlooptri[hit.index].tri[1]].v,
+ mloop[mlooptri[hit.index].tri[2]].v,
+ };
+ float dot;
+
+ normal_tri_v3(hit.no, mvert[vtri[0]].co, mvert[vtri[1]].co, mvert[vtri[2]].co);
+ dot = dot_v3v3(ray_dir, hit.no);
+
+ /* If ray and hit face normal are facing same direction
+ * hit point is inside a closed mesh. */
+ if (dot >= 0.0f) {
+ const float dist = hit.dist;
+ const int f_index = hit.index;
+
+ /* Also cast a ray in opposite direction to make sure
+ * point is at least surrounded by two brush faces */
+ negate_v3(ray_dir);
+ hit.index = -1;
+ hit.dist = BVH_RAYCAST_DIST_MAX;
+
+ BLI_bvhtree_ray_cast(
+ treeData->tree, ray_start, ray_dir, 0.0f, &hit, mesh_tris_spherecast_dp, treeData);
+
+ if (hit.index != -1) {
+ /* Add factor on supersample filter */
+ volume_factor = 1.0f;
+ hit_found = HIT_VOLUME;
+
+ /* Mark hit info */
+ madd_v3_v3v3fl(hitCoord, ray_start, ray_dir, hit.dist); /* Calculate final hit coordinates */
+ depth += dist * sample_factor;
+ hitTri = f_index;
+ }
+ }
+ }
+ }
+
+ /* Check proximity collision */
+ if (ELEM(brush->collision, MOD_DPAINT_COL_DIST, MOD_DPAINT_COL_VOLDIST) &&
+ (!hit_found || (brush->flags & MOD_DPAINT_INVERSE_PROX)))
+ {
+ float proxDist = -1.0f;
+ float hitCo[3] = {0.0f, 0.0f, 0.0f};
+ int tri = 0;
+
+ /* if inverse prox and no hit found, skip this sample */
+ if (inner_proximity && !hit_found)
+ continue;
+
+ /* If pure distance proximity, find the nearest point on the mesh */
+ if (!(brush->flags & MOD_DPAINT_PROX_PROJECT)) {
+ BLI_bvhtree_find_nearest(treeData->tree, ray_start, &nearest, mesh_tris_nearest_point_dp, treeData);
+ if (nearest.index != -1) {
+ proxDist = sqrtf(nearest.dist_sq);
+ copy_v3_v3(hitCo, nearest.co);
+ tri = nearest.index;
+ }
+ }
+ else { /* else cast a ray in defined projection direction */
+ float proj_ray[3] = {0.0f};
+
+ if (brush->ray_dir == MOD_DPAINT_RAY_CANVAS) {
+ copy_v3_v3(proj_ray, bData->bNormal[index].invNorm);
+ negate_v3(proj_ray);
+ }
+ else if (brush->ray_dir == MOD_DPAINT_RAY_BRUSH_AVG) {
+ copy_v3_v3(proj_ray, avg_brushNor);
+ }
+ else { /* MOD_DPAINT_RAY_ZPLUS */
+ proj_ray[2] = 1.0f;
+ }
+ hit.index = -1;
+ hit.dist = brush_radius;
+
+ /* Do a face normal directional raycast, and use that distance */
+ BLI_bvhtree_ray_cast(
+ treeData->tree, ray_start, proj_ray, 0.0f, &hit, mesh_tris_spherecast_dp, treeData);
+ if (hit.index != -1) {
+ proxDist = hit.dist;
+ madd_v3_v3v3fl(hitCo, ray_start, proj_ray, hit.dist); /* Calculate final hit coordinates */
+ tri = hit.index;
+ }
+ }
+
+ /* If a hit was found, calculate required values */
+ if (proxDist >= 0.0f && proxDist <= brush_radius) {
+ proximity_factor = proxDist / brush_radius;
+ CLAMP(proximity_factor, 0.0f, 1.0f);
+ if (!inner_proximity)
+ proximity_factor = 1.0f - proximity_factor;
+
+ hit_found = HIT_PROXIMITY;
+
+ /* if no volume hit, use prox point face info */
+ if (hitTri == -1) {
+ copy_v3_v3(hitCoord, hitCo);
+ hitTri = tri;
+ }
+ }
+ }
+
+ /* mix final sample strength depending on brush settings */
+ if (hit_found) {
+ /* if "negate volume" enabled, negate all factors within volume*/
+ if (brush->collision == MOD_DPAINT_COL_VOLDIST &&
+ brush->flags & MOD_DPAINT_NEGATE_VOLUME)
+ {
+ volume_factor = 1.0f - volume_factor;
+ if (inner_proximity)
+ proximity_factor = 1.0f - proximity_factor;
+ }
+
+ /* apply final sample depending on final hit type */
+ if (hit_found == HIT_VOLUME) {
+ sampleStrength = volume_factor;
+ }
+ else if (hit_found == HIT_PROXIMITY) {
+ /* apply falloff curve to the proximity_factor */
+ if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
+ do_colorband(brush->paint_ramp, (1.0f - proximity_factor), prox_colorband))
+ {
+ proximity_factor = prox_colorband[3];
+ }
+ else if (brush->proximity_falloff == MOD_DPAINT_PRFALL_CONSTANT) {
+ proximity_factor = (!inner_proximity || brush->flags & MOD_DPAINT_NEGATE_VOLUME) ? 1.0f : 0.0f;
+ }
+ /* apply sample */
+ sampleStrength = proximity_factor;
+ }
+
+ sampleStrength *= sample_factor;
+ }
+ else {
+ continue;
+ }
+
+ /* velocity brush, only do on main sample */
+ if (brush->flags & MOD_DPAINT_USES_VELOCITY && ss == 0 && brushVelocity) {
+ float weights[4];
+ float brushPointVelocity[3];
+ float velocity[3];
+
+ const int v1 = mloop[mlooptri[hitTri].tri[0]].v;
+ const int v2 = mloop[mlooptri[hitTri].tri[1]].v;
+ const int v3 = mloop[mlooptri[hitTri].tri[2]].v;
+
+ /* calculate barycentric weights for hit point */
+ interp_weights_face_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, NULL, hitCoord);
+
+ /* simple check based on brush surface velocity,
+ * todo: perhaps implement something that handles volume movement as well */
+
+ /* interpolate vertex speed vectors to get hit point velocity */
+ interp_v3_v3v3v3(brushPointVelocity,
+ brushVelocity[v1].v,
+ brushVelocity[v2].v,
+ brushVelocity[v3].v, weights);
+
+ /* substract canvas point velocity */
+ if (bData->velocity) {
+ sub_v3_v3v3(velocity, brushPointVelocity, bData->velocity[index].v);
+ }
+ else {
+ copy_v3_v3(velocity, brushPointVelocity);
+ }
+ velocity_val = normalize_v3(velocity);
+
+ /* if brush has smudge enabled store brush velocity */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT &&
+ brush->flags & MOD_DPAINT_DO_SMUDGE && bData->brush_velocity)
+ {
+ copy_v3_v3(&bData->brush_velocity[index * 4], velocity);
+ bData->brush_velocity[index * 4 + 3] = velocity_val;
+ }
+ }
+
+ /*
+ * Process hit color and alpha
+ */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ float sampleColor[3];
+ float alpha_factor = 1.0f;
+
+ sampleColor[0] = brush->r;
+ sampleColor[1] = brush->g;
+ sampleColor[2] = brush->b;
+
+ /* Get material+textures color on hit point if required */
+ if (brush_usesMaterial(brush, scene)) {
+ dynamicPaint_doMaterialTex(bMats, sampleColor, &alpha_factor, brushOb,
+ bData->realCoord[bData->s_pos[index] + ss].v,
+ hitCoord, hitTri, dm);
+ }
+
+ /* Sample proximity colorband if required */
+ if ((hit_found == HIT_PROXIMITY) &&
+ (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP))
+ {
+ if (!(brush->flags & MOD_DPAINT_RAMP_ALPHA)) {
+ sampleColor[0] = prox_colorband[0];
+ sampleColor[1] = prox_colorband[1];
+ sampleColor[2] = prox_colorband[2];
+ }
+ }
+
+ /* Add AA sample */
+ paintColor[0] += sampleColor[0];
+ paintColor[1] += sampleColor[1];
+ paintColor[2] += sampleColor[2];
+ sampleStrength *= alpha_factor;
+ numOfHits++;
+ }
+
+ /* apply sample strength */
+ brushStrength += sampleStrength;
+ } // end supersampling
+
+
+ /* if any sample was inside paint range */
+ if (brushStrength > 0.0f || depth > 0.0f) {
+ /* apply supersampling results */
+ if (samples > 1) {
+ brushStrength /= total_sample;
+ }
+ CLAMP(brushStrength, 0.0f, 1.0f);
+
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ /* Get final pixel color and alpha */
+ paintColor[0] /= numOfHits;
+ paintColor[1] /= numOfHits;
+ paintColor[2] /= numOfHits;
+ }
+ /* get final object space depth */
+ else if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
+ depth /= bData->bNormal[index].normal_scale * total_sample;
+ }
+
+ dynamicPaint_updatePointData(surface, index, brush, paintColor, brushStrength, depth, velocity_val, timescale);
+ }
+}
+
static int dynamicPaint_paintMesh(DynamicPaintSurface *surface,
DynamicPaintBrushSettings *brush,
Object *brushOb,
@@ -3166,14 +3860,16 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface,
if (brush->flags & MOD_DPAINT_USES_VELOCITY)
dynamicPaint_brushMeshCalculateVelocity(scene, brushOb, brush, &brushVelocity, timescale);
- if (!brush->dm) return 0;
+ if (!brush->dm)
+ return 0;
+
{
BVHTreeFromMesh treeData = {NULL};
float avg_brushNor[3] = {0.0f};
- float brush_radius = brush->paint_distance * surface->radius_scale;
+ const float brush_radius = brush->paint_distance * surface->radius_scale;
int numOfVerts;
int ii;
- Bounds3D mesh_bb = {0};
+ Bounds3D mesh_bb = {{0}};
VolumeGrid *grid = bData->grid;
dm = CDDM_copy(brush->dm);
@@ -3217,327 +3913,211 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface,
/* loop through space partitioning grid */
for (c_index = 0; c_index < total_cells; c_index++) {
- int id;
-
/* check grid cell bounding box */
- if (!grid->s_num[c_index] || !meshBrush_boundsIntersect(&grid->bounds[c_index], &mesh_bb, brush, brush_radius))
+ if (!grid->s_num[c_index] ||
+ !meshBrush_boundsIntersect(&grid->bounds[c_index], &mesh_bb, brush, brush_radius))
+ {
continue;
+ }
/* loop through cell points and process brush */
-#pragma omp parallel for schedule(static)
- for (id = 0; id < grid->s_num[c_index]; id++) {
- int index = grid->t_index[grid->s_pos[c_index] + id];
- int ss, samples = bData->s_num[index];
- float total_sample = (float)samples;
- float brushStrength = 0.0f; /* brush influence factor */
- float depth = 0.0f; /* brush intersection depth */
- float velocity_val = 0.0f;
-
- float paintColor[3] = {0.0f};
- int numOfHits = 0;
-
- /* for image sequence anti-aliasing, use gaussian factors */
- if (samples > 1 && surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
- total_sample = gaussianTotal;
-
- /* Supersampling */
- for (ss = 0; ss < samples; ss++) {
-
- float ray_start[3], ray_dir[3];
- float sample_factor = 0.0f;
- float sampleStrength = 0.0f;
- BVHTreeRayHit hit;
- BVHTreeNearest nearest;
- short hit_found = 0;
-
- /* volume sample */
- float volume_factor = 0.0f;
- /* proximity sample */
- float proximity_factor = 0.0f;
- float prox_colorband[4] = {0.0f};
- int inner_proximity = (brush->flags & MOD_DPAINT_INVERSE_PROX &&
- brush->collision == MOD_DPAINT_COL_VOLDIST);
-
- /* hit data */
- float hitCoord[3];
- int hitTri = -1;
-
- /* Supersampling factor */
- if (samples > 1 && surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
- sample_factor = gaussianFactors[ss];
- else
- sample_factor = 1.0f;
-
- /* Get current sample position in world coordinates */
- copy_v3_v3(ray_start, bData->realCoord[bData->s_pos[index] + ss].v);
- copy_v3_v3(ray_dir, bData->bNormal[index].invNorm);
-
- /* a simple hack to minimize chance of ray leaks at identical ray <-> edge locations */
- add_v3_fl(ray_start, 0.001f);
-
- hit.index = -1;
- hit.dist = BVH_RAYCAST_DIST_MAX;
- nearest.index = -1;
- nearest.dist_sq = brush_radius * brush_radius; /* find_nearest uses squared distance */
-
- /* Check volume collision */
- if (brush->collision == MOD_DPAINT_COL_VOLUME || brush->collision == MOD_DPAINT_COL_VOLDIST)
- if (BLI_bvhtree_ray_cast(treeData.tree, ray_start, ray_dir, 0.0f, &hit, mesh_tris_spherecast_dp, &treeData) != -1) {
- /* We hit a triangle, now check if collision point normal is facing the point */
-
- /* For optimization sake, hit point normal isn't calculated in ray cast loop */
- const int vtri[3] = {
- mloop[mlooptri[hit.index].tri[0]].v,
- mloop[mlooptri[hit.index].tri[1]].v,
- mloop[mlooptri[hit.index].tri[2]].v,
- };
- float dot;
-
- normal_tri_v3(hit.no, mvert[vtri[0]].co, mvert[vtri[1]].co, mvert[vtri[2]].co);
- dot = dot_v3v3(ray_dir, hit.no);
-
- /* If ray and hit face normal are facing same direction
- * hit point is inside a closed mesh. */
- if (dot >= 0) {
- float dist = hit.dist;
- int f_index = hit.index;
-
- /* Also cast a ray in opposite direction to make sure
- * point is at least surrounded by two brush faces */
- negate_v3(ray_dir);
- hit.index = -1;
- hit.dist = BVH_RAYCAST_DIST_MAX;
-
- BLI_bvhtree_ray_cast(treeData.tree, ray_start, ray_dir, 0.0f, &hit, mesh_tris_spherecast_dp, &treeData);
-
- if (hit.index != -1) {
- /* Add factor on supersample filter */
- volume_factor = 1.0f;
- hit_found = HIT_VOLUME;
-
- /* Mark hit info */
- madd_v3_v3v3fl(hitCoord, ray_start, ray_dir, hit.dist); /* Calculate final hit coordinates */
- depth += dist * sample_factor;
- hitTri = f_index;
- }
- }
- }
+ DynamicPaintPaintData data = {
+ .surface = surface,
+ .brush = brush, .brushOb = brushOb, .bMats = bMats,
+ .scene = scene, .timescale = timescale, .c_index = c_index,
+ .dm = dm, .mvert = mvert, .mloop = mloop, .mlooptri = mlooptri,
+ .brush_radius = brush_radius, .avg_brushNor = avg_brushNor, .brushVelocity = brushVelocity,
+ .treeData = &treeData
+ };
+ BLI_task_parallel_range_ex(0, grid->s_num[c_index], &data, NULL, 0,
+ dynamic_paint_paint_mesh_cell_point_cb_ex,
+ grid->s_num[c_index] > 250, true);
+ }
+ }
+ }
+ /* free bvh tree */
+ free_bvhtree_from_mesh(&treeData);
+ dm->release(dm);
- /* Check proximity collision */
- if ((brush->collision == MOD_DPAINT_COL_DIST || brush->collision == MOD_DPAINT_COL_VOLDIST) &&
- (!hit_found || (brush->flags & MOD_DPAINT_INVERSE_PROX)))
- {
- float proxDist = -1.0f;
- float hitCo[3] = {0.0f, 0.0f, 0.0f};
- int tri = 0;
-
- /* if inverse prox and no hit found, skip this sample */
- if (inner_proximity && !hit_found) continue;
-
- /* If pure distance proximity, find the nearest point on the mesh */
- if (!(brush->flags & MOD_DPAINT_PROX_PROJECT)) {
- if (BLI_bvhtree_find_nearest(treeData.tree, ray_start, &nearest, mesh_tris_nearest_point_dp, &treeData) != -1) {
- proxDist = sqrtf(nearest.dist_sq);
- copy_v3_v3(hitCo, nearest.co);
- tri = nearest.index;
- }
- }
- else { /* else cast a ray in defined projection direction */
- float proj_ray[3] = {0.0f};
+ }
- if (brush->ray_dir == MOD_DPAINT_RAY_CANVAS) {
- copy_v3_v3(proj_ray, bData->bNormal[index].invNorm);
- negate_v3(proj_ray);
- }
- else if (brush->ray_dir == MOD_DPAINT_RAY_BRUSH_AVG) {
- copy_v3_v3(proj_ray, avg_brushNor);
- }
- else { /* MOD_DPAINT_RAY_ZPLUS */
- proj_ray[2] = 1.0f;
- }
- hit.index = -1;
- hit.dist = brush_radius;
-
- /* Do a face normal directional raycast, and use that distance */
- if (BLI_bvhtree_ray_cast(treeData.tree, ray_start, proj_ray, 0.0f, &hit, mesh_tris_spherecast_dp, &treeData) != -1) {
- proxDist = hit.dist;
- madd_v3_v3v3fl(hitCo, ray_start, proj_ray, hit.dist); /* Calculate final hit coordinates */
- tri = hit.index;
- }
- }
+ /* free brush velocity data */
+ if (brushVelocity)
+ MEM_freeN(brushVelocity);
- /* If a hit was found, calculate required values */
- if (proxDist >= 0.0f && proxDist <= brush_radius) {
- proximity_factor = proxDist / brush_radius;
- CLAMP(proximity_factor, 0.0f, 1.0f);
- if (!inner_proximity)
- proximity_factor = 1.0f - proximity_factor;
+ return 1;
+}
- hit_found = HIT_PROXIMITY;
+/*
+ * Paint a particle system to the surface
+ */
+static void dynamic_paint_paint_particle_cell_point_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int id, const int UNUSED(threadid))
+{
+ const DynamicPaintPaintData *data = userdata;
- /* if no volume hit, use prox point face info */
- if (hitTri == -1) {
- copy_v3_v3(hitCoord, hitCo);
- hitTri = tri;
- }
- }
- }
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ const PaintBakeData *bData = sData->bData;
+ VolumeGrid *grid = bData->grid;
- /* mix final sample strength depending on brush settings */
- if (hit_found) {
- /* if "negate volume" enabled, negate all factors within volume*/
- if (brush->collision == MOD_DPAINT_COL_VOLDIST && brush->flags & MOD_DPAINT_NEGATE_VOLUME) {
- volume_factor = 1.0f - volume_factor;
- if (inner_proximity)
- proximity_factor = 1.0f - proximity_factor;
- }
+ const DynamicPaintBrushSettings *brush = data->brush;
- /* apply final sample depending on final hit type */
- if (hit_found == HIT_VOLUME) {
- sampleStrength = volume_factor;
- }
- else if (hit_found == HIT_PROXIMITY) {
- /* apply falloff curve to the proximity_factor */
- if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP && do_colorband(brush->paint_ramp, (1.0f - proximity_factor), prox_colorband))
- proximity_factor = prox_colorband[3];
- else if (brush->proximity_falloff == MOD_DPAINT_PRFALL_CONSTANT)
- proximity_factor = (!inner_proximity || brush->flags & MOD_DPAINT_NEGATE_VOLUME) ? 1.0f : 0.0f;
- /* apply sample */
- sampleStrength = proximity_factor;
- }
+ const ParticleSystem *psys = data->psys;
- sampleStrength *= sample_factor;
- }
- else {
- continue;
- }
+ const float timescale = data->timescale;
+ const int c_index = data->c_index;
- /* velocity brush, only do on main sample */
- if (brush->flags & MOD_DPAINT_USES_VELOCITY && ss == 0 && brushVelocity) {
- int v1, v2, v3;
- float weights[4];
- float brushPointVelocity[3];
- float velocity[3];
-
- v1 = mloop[mlooptri[hitTri].tri[0]].v;
- v2 = mloop[mlooptri[hitTri].tri[1]].v;
- v3 = mloop[mlooptri[hitTri].tri[2]].v;
-
- /* calculate barycentric weights for hit point */
- interp_weights_face_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, NULL, hitCoord);
-
- /* simple check based on brush surface velocity,
- * todo: perhaps implement something that handles volume movement as well */
-
- /* interpolate vertex speed vectors to get hit point velocity */
- interp_v3_v3v3v3(brushPointVelocity,
- brushVelocity[v1].v,
- brushVelocity[v2].v,
- brushVelocity[v3].v, weights);
-
- /* substract canvas point velocity */
- if (bData->velocity) {
- sub_v3_v3v3(velocity, brushPointVelocity, bData->velocity[index].v);
- }
- else {
- copy_v3_v3(velocity, brushPointVelocity);
- }
- velocity_val = len_v3(velocity);
-
- /* if brush has smudge enabled store brush velocity */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT &&
- brush->flags & MOD_DPAINT_DO_SMUDGE && bData->brush_velocity)
- {
- copy_v3_v3(&bData->brush_velocity[index * 4], velocity);
- mul_v3_fl(&bData->brush_velocity[index * 4], 1.0f / velocity_val);
- bData->brush_velocity[index * 4 + 3] = velocity_val;
- }
- }
+ KDTree *tree = data->treeData;
- /*
- * Process hit color and alpha
- */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- float sampleColor[3];
- float alpha_factor = 1.0f;
-
- sampleColor[0] = brush->r;
- sampleColor[1] = brush->g;
- sampleColor[2] = brush->b;
-
- /* Get material+textures color on hit point if required */
- if (brush_usesMaterial(brush, scene)) {
- dynamicPaint_doMaterialTex(bMats, sampleColor, &alpha_factor, brushOb,
- bData->realCoord[bData->s_pos[index] + ss].v,
- hitCoord, hitTri, dm);
- }
+ const float solidradius = data->solidradius;
+ const float smooth = brush->particle_smooth * surface->radius_scale;
+ const float range = solidradius + smooth;
+ const float particle_timestep = 0.04f * psys->part->timetweak;
- /* Sample proximity colorband if required */
- if ((hit_found == HIT_PROXIMITY) && (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP)) {
- if (!(brush->flags & MOD_DPAINT_RAMP_ALPHA)) {
- sampleColor[0] = prox_colorband[0];
- sampleColor[1] = prox_colorband[1];
- sampleColor[2] = prox_colorband[2];
- }
- }
+ const int index = grid->t_index[grid->s_pos[c_index] + id];
+ float disp_intersect = 0.0f;
+ float radius = 0.0f;
+ float strength = 0.0f;
+ int part_index = -1;
- /* Add AA sample */
- paintColor[0] += sampleColor[0];
- paintColor[1] += sampleColor[1];
- paintColor[2] += sampleColor[2];
- sampleStrength *= alpha_factor;
- numOfHits++;
- }
+ /*
+ * With predefined radius, there is no variation between particles.
+ * It's enough to just find the nearest one.
+ */
+ {
+ KDTreeNearest nearest;
+ float smooth_range, part_solidradius;
+
+ /* Find nearest particle and get distance to it */
+ BLI_kdtree_find_nearest(tree, bData->realCoord[bData->s_pos[index]].v, &nearest);
+ /* if outside maximum range, no other particle can influence either */
+ if (nearest.dist > range)
+ return;
+
+ if (brush->flags & MOD_DPAINT_PART_RAD) {
+ /* use particles individual size */
+ ParticleData *pa = psys->particles + nearest.index;
+ part_solidradius = pa->size;
+ }
+ else {
+ part_solidradius = solidradius;
+ }
+ radius = part_solidradius + smooth;
+ if (nearest.dist < radius) {
+ /* distances inside solid radius has maximum influence -> dist = 0 */
+ smooth_range = max_ff(0.0f, (nearest.dist - part_solidradius));
+ /* do smoothness if enabled */
+ if (smooth)
+ smooth_range /= smooth;
+
+ strength = 1.0f - smooth_range;
+ disp_intersect = radius - nearest.dist;
+ part_index = nearest.index;
+ }
+ }
+ /* If using random per particle radius and closest particle didn't give max influence */
+ if (brush->flags & MOD_DPAINT_PART_RAD && strength < 1.0f && psys->part->randsize > 0.0f) {
+ /*
+ * If we use per particle radius, we have to sample all particles
+ * within max radius range
+ */
+ KDTreeNearest *nearest;
- /* apply sample strength */
- brushStrength += sampleStrength;
- } // end supersampling
+ float smooth_range = smooth * (1.0f - strength), dist;
+ /* calculate max range that can have particles with higher influence than the nearest one */
+ const float max_range = smooth - strength * smooth + solidradius;
+ /* Make gcc happy! */
+ dist = max_range;
+ const int particles = BLI_kdtree_range_search(
+ tree, bData->realCoord[bData->s_pos[index]].v, &nearest, max_range);
- /* if any sample was inside paint range */
- if (brushStrength > 0.0f || depth > 0.0f) {
+ /* Find particle that produces highest influence */
+ for (int n = 0; n < particles; n++) {
+ ParticleData *pa = &psys->particles[nearest[n].index];
- /* apply supersampling results */
- if (samples > 1) {
- brushStrength /= total_sample;
- }
- CLAMP(brushStrength, 0.0f, 1.0f);
+ /* skip if out of range */
+ if (nearest[n].dist > (pa->size + smooth))
+ continue;
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- /* Get final pixel color and alpha */
- paintColor[0] /= numOfHits;
- paintColor[1] /= numOfHits;
- paintColor[2] /= numOfHits;
- }
- /* get final object space depth */
- else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
- surface->type == MOD_DPAINT_SURFACE_T_WAVE)
- {
- depth /= bData->bNormal[index].normal_scale * total_sample;
- }
+ /* update hit data */
+ const float s_range = nearest[n].dist - pa->size;
+ /* skip if higher influence is already found */
+ if (smooth_range < s_range)
+ continue;
- dynamicPaint_updatePointData(surface, index, brush, paintColor, brushStrength, depth, velocity_val, timescale);
- }
- }
- }
+ /* update hit data */
+ smooth_range = s_range;
+ dist = nearest[n].dist;
+ part_index = nearest[n].index;
+
+ /* If inside solid range and no disp depth required, no need to seek further */
+ if ((s_range < 0.0f) && !ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
+ break;
}
}
- /* free bvh tree */
- free_bvhtree_from_mesh(&treeData);
- dm->release(dm);
+ if (nearest)
+ MEM_freeN(nearest);
+
+ /* now calculate influence for this particle */
+ const float rad = radius + smooth;
+ if ((rad - dist) > disp_intersect) {
+ disp_intersect = radius - dist;
+ radius = rad;
+ }
+
+ /* do smoothness if enabled */
+ CLAMP_MIN(smooth_range, 0.0f);
+ if (smooth)
+ smooth_range /= smooth;
+
+ const float str = 1.0f - smooth_range;
+ /* if influence is greater, use this one */
+ if (str > strength)
+ strength = str;
}
- /* free brush velocity data */
- if (brushVelocity)
- MEM_freeN(brushVelocity);
+ if (strength > 0.001f) {
+ float paintColor[4] = {0.0f};
+ float depth = 0.0f;
+ float velocity_val = 0.0f;
- return 1;
+ /* apply velocity */
+ if ((brush->flags & MOD_DPAINT_USES_VELOCITY) && (part_index != -1)) {
+ float velocity[3];
+ ParticleData *pa = psys->particles + part_index;
+ mul_v3_v3fl(velocity, pa->state.vel, particle_timestep);
+
+ /* substract canvas point velocity */
+ if (bData->velocity) {
+ sub_v3_v3(velocity, bData->velocity[index].v);
+ }
+ velocity_val = normalize_v3(velocity);
+
+ /* store brush velocity for smudge */
+ if ((surface->type == MOD_DPAINT_SURFACE_T_PAINT) &&
+ (brush->flags & MOD_DPAINT_DO_SMUDGE && bData->brush_velocity))
+ {
+ copy_v3_v3(&bData->brush_velocity[index * 4], velocity);
+ bData->brush_velocity[index * 4 + 3] = velocity_val;
+ }
+ }
+
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ copy_v3_v3(paintColor, &brush->r);
+ }
+ else if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
+ /* get displace depth */
+ disp_intersect = (1.0f - sqrtf(disp_intersect / radius)) * radius;
+ depth = max_ff(0.0f, (radius - disp_intersect) / bData->bNormal[index].normal_scale);
+ }
+
+ dynamicPaint_updatePointData(surface, index, brush, paintColor, strength, depth, velocity_val, timescale);
+ }
}
-/*
- * Paint a particle system to the surface
- */
static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
ParticleSystem *psys,
DynamicPaintBrushSettings *brush,
@@ -3546,22 +4126,23 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
ParticleSettings *part = psys->part;
PaintSurfaceData *sData = surface->data;
PaintBakeData *bData = sData->bData;
- VolumeGrid *grid = bData->grid;
+ VolumeGrid *grid = bData->grid;
KDTree *tree;
int particlesAdded = 0;
int invalidParticles = 0;
int p = 0;
- float solidradius = surface->radius_scale * ((brush->flags & MOD_DPAINT_PART_RAD) ? psys->part->size : brush->particle_radius);
- float smooth = brush->particle_smooth * surface->radius_scale;
+ const float solidradius = surface->radius_scale *
+ ((brush->flags & MOD_DPAINT_PART_RAD) ? part->size : brush->particle_radius);
+ const float smooth = brush->particle_smooth * surface->radius_scale;
- float range = solidradius + smooth;
- float particle_timestep = 0.04f * part->timetweak;
+ const float range = solidradius + smooth;
- Bounds3D part_bb = {0};
+ Bounds3D part_bb = {{0}};
- if (psys->totpart < 1) return 1;
+ if (psys->totpart < 1)
+ return 1;
/*
* Build a kd-tree to optimize distance search
@@ -3571,18 +4152,24 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
/* loop through particles and insert valid ones to the tree */
p = 0;
for (ParticleData *pa = psys->particles; p < psys->totpart; p++, pa++) {
-
/* Proceed only if particle is active */
- if (pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN) == 0) continue;
- else if (pa->alive == PARS_DEAD && (part->flag & PART_DIED) == 0) continue;
- else if (pa->flag & PARS_UNEXIST) continue;
+ if ((pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN) == 0) ||
+ (pa->alive == PARS_DEAD && (part->flag & PART_DIED) == 0) ||
+ (pa->flag & PARS_UNEXIST))
+ {
+ continue;
+ }
/* for debug purposes check if any NAN particle proceeds
* For some reason they get past activity check, this should rule most of them out */
- if (isnan(pa->state.co[0]) || isnan(pa->state.co[1]) || isnan(pa->state.co[2])) { invalidParticles++; continue; }
+ if (isnan(pa->state.co[0]) || isnan(pa->state.co[1]) || isnan(pa->state.co[2])) {
+ invalidParticles++;
+ continue;
+ }
/* make sure particle is close enough to canvas */
- if (!boundIntersectPoint(&grid->grid_bounds, pa->state.co, range)) continue;
+ if (!boundIntersectPoint(&grid->grid_bounds, pa->state.co, range))
+ continue;
BLI_kdtree_insert(tree, p, pa->state.co);
@@ -3607,14 +4194,12 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
if (boundsIntersectDist(&grid->grid_bounds, &part_bb, range)) {
int c_index;
int total_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
-
+
/* balance tree */
BLI_kdtree_balance(tree);
/* loop through space partitioning grid */
for (c_index = 0; c_index < total_cells; c_index++) {
- int id;
-
/* check cell bounding box */
if (!grid->s_num[c_index] ||
!boundsIntersectDist(&grid->bounds[c_index], &part_bb, range))
@@ -3623,156 +4208,15 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
}
/* loop through cell points */
-#pragma omp parallel for schedule(static)
- for (id = 0; id < grid->s_num[c_index]; id++) {
- int index = grid->t_index[grid->s_pos[c_index] + id];
- float disp_intersect = 0.0f;
- float radius = 0.0f;
- float strength = 0.0f;
- float velocity_val = 0.0f;
- int part_index = -1;
-
- /*
- * With predefined radius, there is no variation between particles.
- * It's enough to just find the nearest one.
- */
- {
- KDTreeNearest nearest;
- float smooth_range, part_solidradius;
-
- /* Find nearest particle and get distance to it */
- BLI_kdtree_find_nearest(tree, bData->realCoord[bData->s_pos[index]].v, &nearest);
- /* if outside maximum range, no other particle can influence either */
- if (nearest.dist > range) continue;
-
- if (brush->flags & MOD_DPAINT_PART_RAD) {
- /* use particles individual size */
- ParticleData *pa = psys->particles + nearest.index;
- part_solidradius = pa->size;
- }
- else {
- part_solidradius = solidradius;
- }
- radius = part_solidradius + smooth;
- if (nearest.dist < radius) {
- /* distances inside solid radius has maximum influence -> dist = 0 */
- smooth_range = (nearest.dist - part_solidradius);
- if (smooth_range < 0.0f) smooth_range = 0.0f;
- /* do smoothness if enabled */
- if (smooth) smooth_range /= smooth;
-
- strength = 1.0f - smooth_range;
- disp_intersect = radius - nearest.dist;
- part_index = nearest.index;
- }
- }
- /* If using random per particle radius and closest particle didn't give max influence */
- if (brush->flags & MOD_DPAINT_PART_RAD && strength < 1.0f && psys->part->randsize > 0.0f) {
- /*
- * If we use per particle radius, we have to sample all particles
- * within max radius range
- */
- KDTreeNearest *nearest;
-
- int n, particles;
- float smooth_range = smooth * (1.0f - strength), dist;
- /* calculate max range that can have particles with higher influence than the nearest one */
- float max_range = smooth - strength * smooth + solidradius;
- /* Make gcc happy! */
- dist = max_range;
-
- particles = BLI_kdtree_range_search(tree, bData->realCoord[bData->s_pos[index]].v,
- &nearest, max_range);
-
- /* Find particle that produces highest influence */
- for (n = 0; n < particles; n++) {
- ParticleData *pa = psys->particles + nearest[n].index;
- float s_range;
-
- /* skip if out of range */
- if (nearest[n].dist > (pa->size + smooth))
- continue;
-
- /* update hit data */
- s_range = nearest[n].dist - pa->size;
- /* skip if higher influence is already found */
- if (smooth_range < s_range)
- continue;
-
- /* update hit data */
- smooth_range = s_range;
- dist = nearest[n].dist;
- part_index = nearest[n].index;
-
- /* If inside solid range and no disp depth required, no need to seek further */
- if ( (s_range < 0.0f) &&
- (surface->type != MOD_DPAINT_SURFACE_T_DISPLACE) &&
- (surface->type != MOD_DPAINT_SURFACE_T_WAVE))
- {
- break;
- }
- }
-
- if (nearest) MEM_freeN(nearest);
-
- /* now calculate influence for this particle */
- {
- float rad = radius + smooth, str;
- if ((rad - dist) > disp_intersect) {
- disp_intersect = radius - dist;
- radius = rad;
- }
-
- /* do smoothness if enabled */
- if (smooth_range < 0.0f) smooth_range = 0.0f;
- if (smooth) smooth_range /= smooth;
- str = 1.0f - smooth_range;
- /* if influence is greater, use this one */
- if (str > strength) strength = str;
- }
- }
-
- if (strength > 0.001f) {
- float paintColor[4] = {0.0f};
- float depth = 0.0f;
-
- /* apply velocity */
- if ((brush->flags & MOD_DPAINT_USES_VELOCITY) && (part_index != -1)) {
- float velocity[3];
- ParticleData *pa = psys->particles + part_index;
- mul_v3_v3fl(velocity, pa->state.vel, particle_timestep);
-
- /* substract canvas point velocity */
- if (bData->velocity) {
- sub_v3_v3(velocity, bData->velocity[index].v);
- }
- velocity_val = len_v3(velocity);
-
- /* store brush velocity for smudge */
- if ( (surface->type == MOD_DPAINT_SURFACE_T_PAINT) &&
- (brush->flags & MOD_DPAINT_DO_SMUDGE && bData->brush_velocity))
- {
- copy_v3_v3(&bData->brush_velocity[index * 4], velocity);
- mul_v3_fl(&bData->brush_velocity[index * 4], 1.0f / velocity_val);
- bData->brush_velocity[index * 4 + 3] = velocity_val;
- }
- }
-
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- copy_v3_v3(paintColor, &brush->r);
- }
- else if ( (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) ||
- (surface->type == MOD_DPAINT_SURFACE_T_WAVE))
- {
- /* get displace depth */
- disp_intersect = (1.0f - sqrtf(disp_intersect / radius)) * radius;
- depth = (radius - disp_intersect) / bData->bNormal[index].normal_scale;
- if (depth < 0.0f) depth = 0.0f;
- }
-
- dynamicPaint_updatePointData(surface, index, brush, paintColor, strength, depth, velocity_val, timescale);
- }
- }
+ DynamicPaintPaintData data = {
+ .surface = surface,
+ .brush = brush, .psys = psys,
+ .solidradius = solidradius, .timescale = timescale, .c_index = c_index,
+ .treeData = tree,
+ };
+ BLI_task_parallel_range_ex(0, grid->s_num[c_index], &data, NULL, 0,
+ dynamic_paint_paint_particle_cell_point_cb_ex,
+ grid->s_num[c_index] > 250, true);
}
}
BLI_end_threaded_malloc();
@@ -3782,110 +4226,142 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
}
/* paint a single point of defined proximity radius to the surface */
-static int dynamicPaint_paintSinglePoint(DynamicPaintSurface *surface, float *pointCoord, DynamicPaintBrushSettings *brush,
- Object *brushOb, BrushMaterials *bMats, Scene *scene, float timescale)
+static void dynamic_paint_paint_single_point_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int index, const int UNUSED(threadid))
{
- int index;
- float brush_radius = brush->paint_distance * surface->radius_scale;
- PaintSurfaceData *sData = surface->data;
- PaintBakeData *bData = sData->bData;
- Vec3f brushVel;
+ const DynamicPaintPaintData *data = userdata;
- if (brush->flags & MOD_DPAINT_USES_VELOCITY)
- dynamicPaint_brushObjectCalculateVelocity(scene, brushOb, &brushVel, timescale);
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ const PaintBakeData *bData = sData->bData;
- /*
- * Loop through every surface point
- */
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- float distance = len_v3v3(pointCoord, bData->realCoord[bData->s_pos[index]].v);
- float colorband[4] = {0.0f};
- float strength;
+ const DynamicPaintBrushSettings *brush = data->brush;
+ Object *brushOb = data->brushOb;
+ const BrushMaterials *bMats = data->bMats;
- if (distance > brush_radius) continue;
+ const Scene *scene = data->scene;
+ const float timescale = data->timescale;
- /* Smooth range or color ramp */
- if (brush->proximity_falloff == MOD_DPAINT_PRFALL_SMOOTH ||
- brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP)
- {
- strength = 1.0f - distance / brush_radius;
- CLAMP(strength, 0.0f, 1.0f);
- }
- else {
- strength = 1.0f;
- }
+ const MVert *mvert = data->mvert;
+ const float brush_radius = data->brush_radius;
+ const Vec3f *brushVelocity = data->brushVelocity;
- if (strength >= 0.001f) {
- float paintColor[3] = {0.0f};
- float depth = 0.0f;
- float velocity_val = 0.0f;
+ float *pointCoord = data->pointCoord;
- /* material */
- if (brush_usesMaterial(brush, scene)) {
- float alpha_factor = 1.0f;
- float hit_coord[3];
- MVert *mvert = brush->dm->getVertArray(brush->dm);
- /* use dummy coord of first vertex */
- copy_v3_v3(hit_coord, mvert[0].co);
- mul_m4_v3(brushOb->obmat, hit_coord);
-
- dynamicPaint_doMaterialTex(bMats, paintColor, &alpha_factor, brushOb, bData->realCoord[bData->s_pos[index]].v, hit_coord, 0, brush->dm);
- }
+ const float distance = len_v3v3(pointCoord, bData->realCoord[bData->s_pos[index]].v);
+ float colorband[4] = {0.0f};
+ float strength;
- /* color ramp */
- if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP && do_colorband(brush->paint_ramp, (1.0f - strength), colorband))
- strength = colorband[3];
+ if (distance > brush_radius)
+ return;
- if (brush->flags & MOD_DPAINT_USES_VELOCITY) {
- float velocity[3];
+ /* Smooth range or color ramp */
+ if (brush->proximity_falloff == MOD_DPAINT_PRFALL_SMOOTH ||
+ brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP)
+ {
+ strength = 1.0f - distance / brush_radius;
+ CLAMP(strength, 0.0f, 1.0f);
+ }
+ else {
+ strength = 1.0f;
+ }
- /* substract canvas point velocity */
- if (bData->velocity) {
- sub_v3_v3v3(velocity, brushVel.v, bData->velocity[index].v);
- }
- else {
- copy_v3_v3(velocity, brushVel.v);
- }
- velocity_val = len_v3(velocity);
+ if (strength >= 0.001f) {
+ float paintColor[3] = {0.0f};
+ float depth = 0.0f;
+ float velocity_val = 0.0f;
- /* store brush velocity for smudge */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT &&
- brush->flags & MOD_DPAINT_DO_SMUDGE && bData->brush_velocity)
- {
- copy_v3_v3(&bData->brush_velocity[index * 4], velocity);
- mul_v3_fl(&bData->brush_velocity[index * 4], 1.0f / velocity_val);
- bData->brush_velocity[index * 4 + 3] = velocity_val;
- }
+ /* material */
+ if (brush_usesMaterial(brush, scene)) {
+ float alpha_factor = 1.0f;
+ float hit_coord[3];
+ /* use dummy coord of first vertex */
+ mul_v3_m4v3(hit_coord, brushOb->obmat, mvert[0].co);
+
+ dynamicPaint_doMaterialTex(bMats, paintColor, &alpha_factor, brushOb,
+ bData->realCoord[bData->s_pos[index]].v, hit_coord, 0, brush->dm);
+ }
+
+ /* color ramp */
+ if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
+ do_colorband(brush->paint_ramp, (1.0f - strength), colorband))
+ {
+ strength = colorband[3];
+ }
+
+ if (brush->flags & MOD_DPAINT_USES_VELOCITY) {
+ float velocity[3];
+
+ /* substract canvas point velocity */
+ if (bData->velocity) {
+ sub_v3_v3v3(velocity, brushVelocity->v, bData->velocity[index].v);
+ }
+ else {
+ copy_v3_v3(velocity, brushVelocity->v);
}
+ velocity_val = len_v3(velocity);
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
- !(brush->flags & MOD_DPAINT_RAMP_ALPHA))
- {
- paintColor[0] = colorband[0];
- paintColor[1] = colorband[1];
- paintColor[2] = colorband[2];
- }
- else {
- if (!brush_usesMaterial(brush, scene)) {
- paintColor[0] = brush->r;
- paintColor[1] = brush->g;
- paintColor[2] = brush->b;
- }
- }
+ /* store brush velocity for smudge */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT &&
+ brush->flags & MOD_DPAINT_DO_SMUDGE && bData->brush_velocity)
+ {
+ mul_v3_v3fl(&bData->brush_velocity[index * 4], velocity, 1.0f / velocity_val);
+ bData->brush_velocity[index * 4 + 3] = velocity_val;
}
- else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
- surface->type == MOD_DPAINT_SURFACE_T_WAVE)
+ }
+
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
+ !(brush->flags & MOD_DPAINT_RAMP_ALPHA))
{
- /* get displace depth */
- float disp_intersect = (1.0f - sqrtf((brush_radius - distance) / brush_radius)) * brush_radius;
- depth = (brush_radius - disp_intersect) / bData->bNormal[index].normal_scale;
- if (depth < 0.0f) depth = 0.0f;
+ paintColor[0] = colorband[0];
+ paintColor[1] = colorband[1];
+ paintColor[2] = colorband[2];
+ }
+ else {
+ if (!brush_usesMaterial(brush, scene)) {
+ paintColor[0] = brush->r;
+ paintColor[1] = brush->g;
+ paintColor[2] = brush->b;
+ }
}
- dynamicPaint_updatePointData(surface, index, brush, paintColor, strength, depth, velocity_val, timescale);
}
+ else if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
+ /* get displace depth */
+ const float disp_intersect = (1.0f - sqrtf((brush_radius - distance) / brush_radius)) * brush_radius;
+ depth = max_ff(0.0f, (brush_radius - disp_intersect) / bData->bNormal[index].normal_scale);
+ }
+ dynamicPaint_updatePointData(surface, index, brush, paintColor, strength, depth, velocity_val, timescale);
}
+}
+
+static int dynamicPaint_paintSinglePoint(
+ DynamicPaintSurface *surface, float *pointCoord, DynamicPaintBrushSettings *brush,
+ Object *brushOb, BrushMaterials *bMats, Scene *scene, float timescale)
+{
+ PaintSurfaceData *sData = surface->data;
+ float brush_radius = brush->paint_distance * surface->radius_scale;
+ Vec3f brushVel;
+
+ if (brush->flags & MOD_DPAINT_USES_VELOCITY)
+ dynamicPaint_brushObjectCalculateVelocity(scene, brushOb, &brushVel, timescale);
+
+ const MVert *mvert = brush->dm->getVertArray(brush->dm);
+
+ /*
+ * Loop through every surface point
+ */
+ DynamicPaintPaintData data = {
+ .surface = surface,
+ .brush = brush, .brushOb = brushOb, .bMats = bMats,
+ .scene = scene, .timescale = timescale,
+ .mvert = mvert,
+ .brush_radius = brush_radius, .brushVelocity = &brushVel,
+ .pointCoord = pointCoord,
+ };
+ BLI_task_parallel_range_ex(0, sData->total_points, &data, NULL, 0,
+ dynamic_paint_paint_single_point_cb_ex,
+ sData->total_points > 1000, true);
return 1;
}
@@ -3896,57 +4372,68 @@ static int dynamicPaint_paintSinglePoint(DynamicPaintSurface *surface, float *po
/*
* Calculate current frame distances and directions for adjacency data
*/
-static void dynamicPaint_prepareAdjacencyData(DynamicPaintSurface *surface, int force_init)
+
+static void dynamic_paint_prepare_adjacency_cb(void *userdata, const int index)
+{
+ PaintSurfaceData *sData = userdata;
+ PaintBakeData *bData = sData->bData;
+ BakeAdjPoint *bNeighs = bData->bNeighs;
+ PaintAdjData *adj_data = sData->adj_data;
+ Vec3f *realCoord = bData->realCoord;
+
+ const int num_neighs = adj_data->n_num[index];
+
+ for (int i = 0; i < num_neighs; i++) {
+ const int n_index = adj_data->n_index[index] + i;
+ const int t_index = adj_data->n_target[n_index];
+
+ /* dir vec */
+ sub_v3_v3v3(bNeighs[n_index].dir, realCoord[bData->s_pos[t_index]].v, realCoord[bData->s_pos[index]].v);
+ /* dist */
+ bNeighs[n_index].dist = normalize_v3(bNeighs[n_index].dir);
+ }
+}
+
+static void dynamicPaint_prepareAdjacencyData(DynamicPaintSurface *surface, const bool force_init)
{
PaintSurfaceData *sData = surface->data;
PaintBakeData *bData = sData->bData;
BakeAdjPoint *bNeighs;
PaintAdjData *adj_data = sData->adj_data;
- Vec3f *realCoord = bData->realCoord;
- int index;
- if ((!surface_usesAdjDistance(surface) && !force_init) || !sData->adj_data) return;
+ int index;
- if (bData->bNeighs) MEM_freeN(bData->bNeighs);
- bNeighs = bData->bNeighs = MEM_mallocN(sData->adj_data->total_targets * sizeof(struct BakeAdjPoint), "PaintEffectBake");
- if (!bNeighs) return;
+ if ((!surface_usesAdjDistance(surface) && !force_init) || !sData->adj_data)
+ return;
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- int i;
- int numOfNeighs = adj_data->n_num[index];
+ if (bData->bNeighs)
+ MEM_freeN(bData->bNeighs);
+ bNeighs = bData->bNeighs = MEM_mallocN(sData->adj_data->total_targets * sizeof(*bNeighs), "PaintEffectBake");
+ if (!bNeighs)
+ return;
- for (i = 0; i < numOfNeighs; i++) {
- int n_index = adj_data->n_index[index] + i;
- int t_index = adj_data->n_target[n_index];
-
- /* dir vec */
- sub_v3_v3v3(bNeighs[n_index].dir, realCoord[bData->s_pos[t_index]].v, realCoord[bData->s_pos[index]].v);
- /* dist */
- bNeighs[n_index].dist = len_v3(bNeighs[n_index].dir);
- /* normalize dir */
- if (bNeighs[n_index].dist) mul_v3_fl(bNeighs[n_index].dir, 1.0f / bNeighs[n_index].dist);
- }
- }
+ BLI_task_parallel_range(
+ 0, sData->total_points, sData, dynamic_paint_prepare_adjacency_cb, sData->total_points > 1000);
- /* calculate average values (single thread) */
- bData->average_dist = 0.0f;
+ /* calculate average values (single thread).
+ * Note: tried to put this in threaded callback (using _finalize feature), but gave ~30% slower result! */
+ bData->average_dist = 0.0;
for (index = 0; index < sData->total_points; index++) {
- int i;
int numOfNeighs = adj_data->n_num[index];
- for (i = 0; i < numOfNeighs; i++) {
+ for (int i = 0; i < numOfNeighs; i++) {
bData->average_dist += (double)bNeighs[adj_data->n_index[index] + i].dist;
}
}
- bData->average_dist /= adj_data->total_targets;
+ bData->average_dist /= adj_data->total_targets;
}
/* find two adjacency points (closest_id) and influence (closest_d) to move paint towards when affected by a force */
-static void surface_determineForceTargetPoints(PaintSurfaceData *sData, int index, float force[3], float closest_d[2], int closest_id[2])
+static void surface_determineForceTargetPoints(
+ const PaintSurfaceData *sData, const int index, const float force[3], float closest_d[2], int closest_id[2])
{
BakeAdjPoint *bNeighs = sData->bData->bNeighs;
- int numOfNeighs = sData->adj_data->n_num[index];
+ const int numOfNeighs = sData->adj_data->n_num[index];
int i;
closest_id[0] = closest_id[1] = -1;
@@ -3954,35 +4441,42 @@ static void surface_determineForceTargetPoints(PaintSurfaceData *sData, int inde
/* find closest neigh */
for (i = 0; i < numOfNeighs; i++) {
- int n_index = sData->adj_data->n_index[index] + i;
- float dir_dot = dot_v3v3(bNeighs[n_index].dir, force);
+ const int n_index = sData->adj_data->n_index[index] + i;
+ const float dir_dot = dot_v3v3(bNeighs[n_index].dir, force);
- if (dir_dot > closest_d[0] && dir_dot > 0.0f) { closest_d[0] = dir_dot; closest_id[0] = n_index; }
+ if (dir_dot > closest_d[0] && dir_dot > 0.0f) {
+ closest_d[0] = dir_dot;
+ closest_id[0] = n_index;
+ }
}
- if (closest_d[0] < 0.0f) return;
+ if (closest_d[0] < 0.0f)
+ return;
/* find second closest neigh */
for (i = 0; i < numOfNeighs; i++) {
- int n_index = sData->adj_data->n_index[index] + i;
- float dir_dot = dot_v3v3(bNeighs[n_index].dir, force);
- float closest_dot = dot_v3v3(bNeighs[n_index].dir, bNeighs[closest_id[0]].dir);
+ const int n_index = sData->adj_data->n_index[index] + i;
- if (n_index == closest_id[0]) continue;
+ if (n_index == closest_id[0])
+ continue;
+
+ const float dir_dot = dot_v3v3(bNeighs[n_index].dir, force);
+ const float closest_dot = dot_v3v3(bNeighs[n_index].dir, bNeighs[closest_id[0]].dir);
/* only accept neighbor at "other side" of the first one in relation to force dir
* so make sure angle between this and closest neigh is greater than first angle */
if (dir_dot > closest_d[1] && closest_dot < closest_d[0] && dir_dot > 0.0f) {
- closest_d[1] = dir_dot; closest_id[1] = n_index;
+ closest_d[1] = dir_dot;
+ closest_id[1] = n_index;
}
}
- /* if two valid neighs found, calculate how force effect is divided
- * evenly between them (so that d[0]+d[1] = 1.0)*/
+ /* if two valid neighs found, calculate how force effect is divided evenly between them
+ * (so that d[0] + d[1] = 1.0) */
if (closest_id[1] != -1) {
float force_proj[3];
float tangent[3];
- float neigh_diff = acosf(dot_v3v3(bNeighs[closest_id[0]].dir, bNeighs[closest_id[1]].dir));
+ const float neigh_diff = acosf(dot_v3v3(bNeighs[closest_id[0]].dir, bNeighs[closest_id[1]].dir));
float force_intersect;
float temp;
@@ -4019,20 +4513,20 @@ static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrus
int index, steps, step;
float eff_scale, max_velocity = 0.0f;
- if (!sData->adj_data) return;
+ if (!sData->adj_data)
+ return;
/* find max velocity */
for (index = 0; index < sData->total_points; index++) {
float vel = bData->brush_velocity[index * 4 + 3];
- if (vel > max_velocity) max_velocity = vel;
+ CLAMP_MIN(max_velocity, vel);
}
- steps = (int)ceil(max_velocity / bData->average_dist * timescale);
+ steps = (int)ceil((double)max_velocity / bData->average_dist * (double)timescale);
CLAMP(steps, 0, 12);
eff_scale = brush->smudge_strength / (float)steps * timescale;
for (step = 0; step < steps; step++) {
-
for (index = 0; index < sData->total_points; index++) {
int i;
PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
@@ -4042,8 +4536,9 @@ static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrus
int closest_id[2];
float closest_d[2];
- if (!smudge_str) continue;
-
+ if (!smudge_str)
+ continue;
+
/* get force affect points */
surface_determineForceTargetPoints(sData, index, &bData->brush_velocity[index * 4], closest_d, closest_id);
@@ -4056,7 +4551,8 @@ static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrus
PaintPoint *ePoint = &((PaintPoint *)sData->type_data)[sData->adj_data->n_target[n_index]];
/* just skip if angle is too extreme */
- if (dir_dot <= 0.0f) continue;
+ if (dir_dot <= 0.0f)
+ continue;
dir_factor = dir_dot * speed_scale;
CLAMP_MAX(dir_factor, brush->smudge_strength);
@@ -4075,11 +4571,83 @@ static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrus
}
}
+typedef struct DynamicPaintEffectData {
+ const DynamicPaintSurface *surface;
+ Scene *scene;
+
+ float *force;
+ ListBase *effectors;
+ const void *prevPoint;
+ const float eff_scale;
+
+ uint8_t *point_locks;
+
+ const float wave_speed;
+ const float wave_scale;
+ const float wave_max_slope;
+
+ const float dt;
+ const float min_dist;
+ const float damp_factor;
+ const bool reset_wave;
+} DynamicPaintEffectData;
+
/*
* Prepare data required by effects for current frame.
* Returns number of steps required
*/
-static int dynamicPaint_prepareEffectStep(DynamicPaintSurface *surface, Scene *scene, Object *ob, float **force, float timescale)
+static void dynamic_paint_prepare_effect_cb(void *userdata, const int index)
+{
+ const DynamicPaintEffectData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ const PaintBakeData *bData = sData->bData;
+ Vec3f *realCoord = bData->realCoord;
+
+ Scene *scene = data->scene;
+
+ float *force = data->force;
+ ListBase *effectors = data->effectors;
+
+ float forc[3] = {0};
+ float vel[3] = {0};
+
+ /* apply force fields */
+ if (effectors) {
+ EffectedPoint epoint;
+ pd_point_from_loc(scene, realCoord[bData->s_pos[index]].v, vel, index, &epoint);
+ epoint.vel_to_sec = 1.0f;
+ pdDoEffectors(effectors, NULL, surface->effector_weights, &epoint, forc, NULL);
+ }
+
+ /* if global gravity is enabled, add it too */
+ if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY)
+ /* also divide by 10 to about match default grav
+ * with default force strength (1.0) */
+ madd_v3_v3fl(forc, scene->physics_settings.gravity,
+ surface->effector_weights->global_gravity * surface->effector_weights->weight[0] / 10.f);
+
+ /* add surface point velocity and acceleration if enabled */
+ if (bData->velocity) {
+ if (surface->drip_vel)
+ madd_v3_v3fl(forc, bData->velocity[index].v, surface->drip_vel * (-1.0f));
+
+ /* acceleration */
+ if (bData->prev_velocity && surface->drip_acc) {
+ float acc[3];
+ copy_v3_v3(acc, bData->velocity[index].v);
+ sub_v3_v3(acc, bData->prev_velocity[index].v);
+ madd_v3_v3fl(forc, acc, surface->drip_acc * (-1.0f));
+ }
+ }
+
+ /* force strength, and normalize force vec */
+ force[index * 4 + 3] = normalize_v3_v3(&force[index * 4], forc);
+}
+
+static int dynamicPaint_prepareEffectStep(
+ DynamicPaintSurface *surface, Scene *scene, Object *ob, float **force, float timescale)
{
double average_force = 0.0f;
float shrink_speed = 0.0f, spread_speed = 0.0f;
@@ -4087,61 +4655,25 @@ static int dynamicPaint_prepareEffectStep(DynamicPaintSurface *surface, Scene *s
int steps;
PaintSurfaceData *sData = surface->data;
PaintBakeData *bData = sData->bData;
- Vec3f *realCoord = bData->realCoord;
- int index;
/* Init force data if required */
if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) {
- float vel[3] = {0};
ListBase *effectors = pdInitEffectors(scene, ob, NULL, surface->effector_weights, true);
/* allocate memory for force data (dir vector + strength) */
*force = MEM_mallocN(sData->total_points * 4 * sizeof(float), "PaintEffectForces");
if (*force) {
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- float forc[3] = {0};
-
- /* apply force fields */
- if (effectors) {
- EffectedPoint epoint;
- pd_point_from_loc(scene, realCoord[bData->s_pos[index]].v, vel, index, &epoint);
- epoint.vel_to_sec = 1.0f;
- pdDoEffectors(effectors, NULL, surface->effector_weights, &epoint, forc, NULL);
- }
-
- /* if global gravity is enabled, add it too */
- if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY)
- /* also divide by 10 to about match default grav
- * with default force strength (1.0) */
- madd_v3_v3fl(forc, scene->physics_settings.gravity,
- surface->effector_weights->global_gravity * surface->effector_weights->weight[0] / 10.f);
-
- /* add surface point velocity and acceleration if enabled */
- if (bData->velocity) {
- if (surface->drip_vel)
- madd_v3_v3fl(forc, bData->velocity[index].v, surface->drip_vel * (-1.0f));
-
- /* acceleration */
- if (bData->prev_velocity && surface->drip_acc) {
- float acc[3];
- copy_v3_v3(acc, bData->velocity[index].v);
- sub_v3_v3(acc, bData->prev_velocity[index].v);
- madd_v3_v3fl(forc, acc, surface->drip_acc * (-1.0f));
- }
- }
-
- /* force strength */
- (*force)[index * 4 + 3] = len_v3(forc);
- /* normalize and copy */
- if ((*force)[index * 4 + 3]) mul_v3_fl(forc, 1.0f / (*force)[index * 4 + 3]);
- copy_v3_v3(&((*force)[index * 4]), forc);
- }
+ DynamicPaintEffectData data = {
+ .surface = surface, .scene = scene,
+ .force = *force, .effectors = effectors,
+ };
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_prepare_effect_cb, sData->total_points > 1000);
/* calculate average values (single thread) */
- for (index = 0; index < sData->total_points; index++) {
- average_force += (*force)[index * 4 + 3];
+ for (int index = 0; index < sData->total_points; index++) {
+ average_force += (double)(*force)[index * 4 + 3];
}
average_force /= sData->total_points;
}
@@ -4158,9 +4690,9 @@ static int dynamicPaint_prepareEffectStep(DynamicPaintSurface *surface, Scene *s
shrink_speed = surface->shrink_speed;
fastest_effect = max_fff(spread_speed, shrink_speed, average_force);
- avg_dist = bData->average_dist * CANVAS_REL_SIZE / getSurfaceDimension(sData);
+ avg_dist = bData->average_dist * (double)CANVAS_REL_SIZE / (double)getSurfaceDimension(sData);
- steps = (int)ceil(1.5f * EFF_MOVEMENT_PER_FRAME * fastest_effect / avg_dist * timescale);
+ steps = (int)ceilf(1.5f * EFF_MOVEMENT_PER_FRAME * fastest_effect / avg_dist * timescale);
CLAMP(steps, 1, 20);
return steps;
@@ -4169,165 +4701,358 @@ static int dynamicPaint_prepareEffectStep(DynamicPaintSurface *surface, Scene *s
/**
* Processes active effect step.
*/
-static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, float *force, PaintPoint *prevPoint, float timescale, float steps)
+static void dynamic_paint_effect_spread_cb(void *userdata, const int index)
{
- PaintSurfaceData *sData = surface->data;
+ const DynamicPaintEffectData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+
+ const int numOfNeighs = sData->adj_data->n_num[index];
BakeAdjPoint *bNeighs = sData->bData->bNeighs;
- float distance_scale = getSurfaceDimension(sData) / CANVAS_REL_SIZE;
- int index;
- timescale /= steps;
+ PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+ const PaintPoint *prevPoint = data->prevPoint;
+ const float eff_scale = data->eff_scale;
+
+ const int *n_index = sData->adj_data->n_index;
+ const int *n_target = sData->adj_data->n_target;
+
+ /* Loop through neighboring points */
+ for (int i = 0; i < numOfNeighs; i++) {
+ const int n_idx = n_index[index] + i;
+ float w_factor;
+ const PaintPoint *pPoint_prev = &prevPoint[n_target[n_idx]];
+ const float speed_scale = (bNeighs[n_idx].dist < eff_scale) ? 1.0f : eff_scale / bNeighs[n_idx].dist;
+ const float color_mix = min_fff(pPoint_prev->wetness, pPoint->wetness, 1.0f) * 0.25f * surface->color_spread_speed;
+
+ /* do color mixing */
+ if (color_mix)
+ mixColors(pPoint->e_color, pPoint->e_color[3], pPoint_prev->e_color, pPoint_prev->e_color[3], color_mix);
+
+ /* Only continue if surrounding point has higher wetness */
+ if (pPoint_prev->wetness < pPoint->wetness || pPoint_prev->wetness < MIN_WETNESS)
+ continue;
- if (!sData->adj_data) return;
+ w_factor = 1.0f / numOfNeighs * min_ff(pPoint_prev->wetness, 1.0f) * speed_scale;
+ CLAMP(w_factor, 0.0f, 1.0f);
- /*
- * Spread Effect
- */
- if (surface->effect & MOD_DPAINT_EFFECT_DO_SPREAD) {
- float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * surface->spread_speed * timescale;
+ /* mix new wetness and color */
+ pPoint->wetness = (1.0f - w_factor) * pPoint->wetness + w_factor * pPoint_prev->wetness;
+ pPoint->e_color[3] = mixColors(pPoint->e_color, pPoint->e_color[3],
+ pPoint_prev->e_color, pPoint_prev->e_color[3], w_factor);
+ }
+}
- /* Copy current surface to the previous points array to read unmodified values */
- memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(struct PaintPoint));
+static void dynamic_paint_effect_shrink_cb(void *userdata, const int index)
+{
+ const DynamicPaintEffectData *data = userdata;
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- int i;
- int numOfNeighs = sData->adj_data->n_num[index];
- PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+
+ const int numOfNeighs = sData->adj_data->n_num[index];
+ BakeAdjPoint *bNeighs = sData->bData->bNeighs;
+ PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+ const PaintPoint *prevPoint = data->prevPoint;
+ const float eff_scale = data->eff_scale;
+ float totalAlpha = 0.0f;
+
+ const int *n_index = sData->adj_data->n_index;
+ const int *n_target = sData->adj_data->n_target;
+
+ /* Loop through neighboring points */
+ for (int i = 0; i < numOfNeighs; i++) {
+ const int n_idx = n_index[index] + i;
+ const float speed_scale = (bNeighs[n_idx].dist < eff_scale) ? 1.0f : eff_scale / bNeighs[n_idx].dist;
+ const PaintPoint *pPoint_prev = &prevPoint[n_target[n_idx]];
+ float a_factor, ea_factor, w_factor;
+
+ totalAlpha += pPoint_prev->e_color[3];
+
+ /* Check if neighboring point has lower alpha,
+ * if so, decrease this point's alpha as well*/
+ if (pPoint->color[3] <= 0.0f && pPoint->e_color[3] <= 0.0f && pPoint->wetness <= 0.0f)
+ continue;
+
+ /* decrease factor for dry paint alpha */
+ a_factor = max_ff((1.0f - pPoint_prev->color[3]) / numOfNeighs * (pPoint->color[3] - pPoint_prev->color[3]) * speed_scale, 0.0f);
+ /* decrease factor for wet paint alpha */
+ ea_factor = max_ff((1.0f - pPoint_prev->e_color[3]) / 8 * (pPoint->e_color[3] - pPoint_prev->e_color[3]) * speed_scale, 0.0f);
+ /* decrease factor for paint wetness */
+ w_factor = max_ff((1.0f - pPoint_prev->wetness) / 8 * (pPoint->wetness - pPoint_prev->wetness) * speed_scale, 0.0f);
+
+ pPoint->color[3] -= a_factor;
+ CLAMP_MIN(pPoint->color[3], 0.0f);
+ pPoint->e_color[3] -= ea_factor;
+ CLAMP_MIN(pPoint->e_color[3], 0.0f);
+ pPoint->wetness -= w_factor;
+ CLAMP_MIN(pPoint->wetness, 0.0f);
+ }
+}
+
+static void dynamic_paint_effect_drip_cb(void *userdata, const int index)
+{
+ const DynamicPaintEffectData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ BakeAdjPoint *bNeighs = sData->bData->bNeighs;
+ PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+ const PaintPoint *prevPoint = data->prevPoint;
+ const PaintPoint *pPoint_prev = &prevPoint[index];
+ const float *force = data->force;
+ const float eff_scale = data->eff_scale;
+
+ const int *n_target = sData->adj_data->n_target;
+
+ uint8_t *point_locks = data->point_locks;
+
+ int closest_id[2];
+ float closest_d[2];
+
+ /* adjust drip speed depending on wetness */
+ float w_factor = pPoint_prev->wetness - 0.025f;
+ if (w_factor <= 0)
+ return;
+ CLAMP(w_factor, 0.0f, 1.0f);
+
+ float ppoint_wetness_diff = 0.0f;
+
+ /* get force affect points */
+ surface_determineForceTargetPoints(sData, index, &force[index * 4], closest_d, closest_id);
+
+ /* Apply movement towards those two points */
+ for (int i = 0; i < 2; i++) {
+ const int n_idx = closest_id[i];
+ if (n_idx != -1 && closest_d[i] > 0.0f) {
+ const float dir_dot = closest_d[i];
+
+ /* just skip if angle is too extreme */
+ if (dir_dot <= 0.0f)
+ continue;
+
+ float dir_factor, a_factor;
+ const float speed_scale = eff_scale * force[index * 4 + 3] / bNeighs[n_idx].dist;
+
+ const unsigned int n_trgt = (unsigned int)n_target[n_idx];
- /* Only reads values from the surface copy (prevPoint[]),
- * so this one is thread safe */
+ /* Sort of spinlock, but only for given ePoint.
+ * Since the odds a same ePoint is modified at the same time by several threads is very low, this is
+ * much more efficient than a global spin lock. */
+ const unsigned int epointlock_idx = n_trgt / 8;
+ const uint8_t epointlock_bitmask = 1 << (n_trgt & 7); /* 7 == 0b111 */
+ while (atomic_fetch_and_or_uint8(&point_locks[epointlock_idx], epointlock_bitmask) & epointlock_bitmask);
- /* Loop through neighboring points */
- for (i = 0; i < numOfNeighs; i++) {
- int n_index = sData->adj_data->n_index[index] + i;
- float w_factor;
- PaintPoint *ePoint = &prevPoint[sData->adj_data->n_target[n_index]];
- float speed_scale = (bNeighs[n_index].dist < eff_scale) ? 1.0f : eff_scale / bNeighs[n_index].dist;
- float color_mix = (MIN3(ePoint->wetness, pPoint->wetness, 1.0f)) * 0.25f * surface->color_spread_speed;
+ PaintPoint *ePoint = &((PaintPoint *)sData->type_data)[n_trgt];
+ const float e_wet = ePoint->wetness;
- /* do color mixing */
- if (color_mix) mixColors(pPoint->e_color, pPoint->e_color[3], ePoint->e_color, ePoint->e_color[3], color_mix);
+ dir_factor = min_ff(0.5f, dir_dot * min_ff(speed_scale, 1.0f) * w_factor);
- /* Only continue if surrounding point has higher wetness */
- if (ePoint->wetness < pPoint->wetness || ePoint->wetness < MIN_WETNESS) continue;
+ /* mix new wetness */
+ ePoint->wetness += dir_factor;
+ CLAMP(ePoint->wetness, 0.0f, MAX_WETNESS);
- w_factor = 1.0f / numOfNeighs * MIN2(ePoint->wetness, 1.0f) * speed_scale;
- CLAMP(w_factor, 0.0f, 1.0f);
+ /* mix new color */
+ a_factor = dir_factor / pPoint_prev->wetness;
+ CLAMP(a_factor, 0.0f, 1.0f);
+ mixColors(ePoint->e_color, ePoint->e_color[3], pPoint_prev->e_color, pPoint_prev->e_color[3], a_factor);
+ /* dripping is supposed to preserve alpha level */
+ if (pPoint_prev->e_color[3] > ePoint->e_color[3]) {
+ ePoint->e_color[3] += a_factor * pPoint_prev->e_color[3];
+ CLAMP_MAX(ePoint->e_color[3], pPoint_prev->e_color[3]);
+ }
+
+ /* Decrease paint wetness on current point
+ * (just store diff here, that way we can only lock current point once at the end to apply it). */
+ ppoint_wetness_diff += (ePoint->wetness - e_wet);
- /* mix new wetness and color */
- pPoint->wetness = (1.0f - w_factor) * pPoint->wetness + w_factor * ePoint->wetness;
- pPoint->e_color[3] = mixColors(pPoint->e_color, pPoint->e_color[3], ePoint->e_color, ePoint->e_color[3], w_factor);
+#ifndef NDEBUG
+ {
+ uint8_t ret = atomic_fetch_and_and_uint8(&point_locks[epointlock_idx], ~epointlock_bitmask);
+ BLI_assert(ret & epointlock_bitmask);
}
+#else
+ atomic_fetch_and_and_uint8(&point_locks[epointlock_idx], ~epointlock_bitmask);
+#endif
}
}
+ {
+ const unsigned int ppointlock_idx = index / 8;
+ const uint8_t ppointlock_bitmask = 1 << (index & 7); /* 7 == 0b111 */
+ while (atomic_fetch_and_or_uint8(&point_locks[ppointlock_idx], ppointlock_bitmask) & ppointlock_bitmask);
+
+ pPoint->wetness -= ppoint_wetness_diff;
+ CLAMP(pPoint->wetness, 0.0f, MAX_WETNESS);
+
+#ifndef NDEBUG
+ {
+ uint8_t ret = atomic_fetch_and_and_uint8(&point_locks[ppointlock_idx], ~ppointlock_bitmask);
+ BLI_assert(ret & ppointlock_bitmask);
+ }
+#else
+ atomic_fetch_and_and_uint8(&point_locks[ppointlock_idx], ~ppointlock_bitmask);
+#endif
+ }
+}
+
+static void dynamicPaint_doEffectStep(
+ DynamicPaintSurface *surface, float *force, PaintPoint *prevPoint, float timescale, float steps)
+{
+ PaintSurfaceData *sData = surface->data;
+
+ const float distance_scale = getSurfaceDimension(sData) / CANVAS_REL_SIZE;
+ timescale /= steps;
+
+ if (!sData->adj_data)
+ return;
+
+ /*
+ * Spread Effect
+ */
+ if (surface->effect & MOD_DPAINT_EFFECT_DO_SPREAD) {
+ const float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * surface->spread_speed * timescale;
+
+ /* Copy current surface to the previous points array to read unmodified values */
+ memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(struct PaintPoint));
+
+ DynamicPaintEffectData data = {
+ .surface = surface, .prevPoint = prevPoint, .eff_scale = eff_scale,
+ };
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_effect_spread_cb, sData->total_points > 1000);
+ }
+
/*
* Shrink Effect
*/
if (surface->effect & MOD_DPAINT_EFFECT_DO_SHRINK) {
- float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * surface->shrink_speed * timescale;
+ const float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * surface->shrink_speed * timescale;
/* Copy current surface to the previous points array to read unmodified values */
memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(struct PaintPoint));
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- int i;
- int numOfNeighs = sData->adj_data->n_num[index];
- float totalAlpha = 0.0f;
- PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
-
- for (i = 0; i < numOfNeighs; i++) {
- int n_index = sData->adj_data->n_index[index] + i;
- float speed_scale = (bNeighs[n_index].dist < eff_scale) ? 1.0f : eff_scale / bNeighs[n_index].dist;
- PaintPoint *ePoint = &prevPoint[sData->adj_data->n_target[n_index]];
- float a_factor, ea_factor, w_factor;
-
- totalAlpha += ePoint->e_color[3];
-
- /* Check if neighboring point has lower alpha,
- * if so, decrease this point's alpha as well*/
- if (pPoint->color[3] <= 0.0f && pPoint->e_color[3] <= 0.0f && pPoint->wetness <= 0.0f) continue;
-
- /* decrease factor for dry paint alpha */
- a_factor = (1.0f - ePoint->color[3]) / numOfNeighs * (pPoint->color[3] - ePoint->color[3]) * speed_scale;
- CLAMP_MIN(a_factor, 0.0f);
- /* decrease factor for wet paint alpha */
- ea_factor = (1.0f - ePoint->e_color[3]) / 8 * (pPoint->e_color[3] - ePoint->e_color[3]) * speed_scale;
- CLAMP_MIN(ea_factor, 0.0f);
- /* decrease factor for paint wetness */
- w_factor = (1.0f - ePoint->wetness) / 8 * (pPoint->wetness - ePoint->wetness) * speed_scale;
- CLAMP_MIN(w_factor, 0.0f);
-
- pPoint->color[3] -= a_factor;
- CLAMP_MIN(pPoint->color[3], 0.0f);
- pPoint->e_color[3] -= ea_factor;
- CLAMP_MIN(pPoint->e_color[3], 0.0f);
- pPoint->wetness -= w_factor;
- CLAMP_MIN(pPoint->wetness, 0.0f);
- }
- }
+ DynamicPaintEffectData data = {
+ .surface = surface, .prevPoint = prevPoint, .eff_scale = eff_scale,
+ };
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_effect_shrink_cb, sData->total_points > 1000);
}
/*
* Drip Effect
*/
if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP && force) {
- float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * timescale / 2.0f;
+ const float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * timescale / 2.0f;
+
+ /* Same as BLI_bitmask, but handled atomicaly as 'ePoint' locks. */
+ const size_t point_locks_size = (sData->total_points / 8) + 1;
+ uint8_t *point_locks = MEM_callocN(sizeof(*point_locks) * point_locks_size, __func__);
+
/* Copy current surface to the previous points array to read unmodified values */
memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(struct PaintPoint));
- for (index = 0; index < sData->total_points; index++) {
- int i;
- PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
- PaintPoint *pPoint_prev = &prevPoint[index];
+ DynamicPaintEffectData data = {
+ .surface = surface, .prevPoint = prevPoint,
+ .eff_scale = eff_scale, .force = force,
+ .point_locks = point_locks,
+ };
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_effect_drip_cb, sData->total_points > 1000);
- int closest_id[2];
- float closest_d[2];
+ MEM_freeN(point_locks);
+ }
+}
- /* adjust drip speed depending on wetness */
- float w_factor = pPoint_prev->wetness - 0.025f;
- if (w_factor <= 0) continue;
- CLAMP(w_factor, 0.0f, 1.0f);
+static void dynamic_paint_wave_step_cb(void *userdata, const int index)
+{
+ const DynamicPaintEffectData *data = userdata;
- /* get force affect points */
- surface_determineForceTargetPoints(sData, index, &force[index * 4], closest_d, closest_id);
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ BakeAdjPoint *bNeighs = sData->bData->bNeighs;
+ const PaintWavePoint *prevPoint = data->prevPoint;
- /* Apply movement towards those two points */
- for (i = 0; i < 2; i++) {
- int n_index = closest_id[i];
- if (n_index != -1 && closest_d[i] > 0.0f) {
- float dir_dot = closest_d[i], dir_factor, a_factor;
- float speed_scale = eff_scale * force[index * 4 + 3] / bNeighs[n_index].dist;
- PaintPoint *ePoint = &((PaintPoint *)sData->type_data)[sData->adj_data->n_target[n_index]];
- float e_wet = ePoint->wetness;
+ const float wave_speed = data->wave_speed;
+ const float wave_scale = data->wave_scale;
+ const float wave_max_slope = data->wave_max_slope;
- /* just skip if angle is too extreme */
- if (dir_dot <= 0.0f) continue;
-
- dir_factor = dir_dot * MIN2(speed_scale, 1.0f) * w_factor;
- CLAMP_MAX(dir_factor, 0.5f);
-
- /* mix new wetness */
- ePoint->wetness += dir_factor;
- CLAMP(ePoint->wetness, 0.0f, MAX_WETNESS);
-
- /* mix new color */
- a_factor = dir_factor / pPoint_prev->wetness;
- CLAMP(a_factor, 0.0f, 1.0f);
- mixColors(ePoint->e_color, ePoint->e_color[3], pPoint_prev->e_color, pPoint_prev->e_color[3], a_factor);
- /* dripping is supposed to preserve alpha level */
- if (pPoint_prev->e_color[3] > ePoint->e_color[3]) {
- ePoint->e_color[3] += a_factor * pPoint_prev->e_color[3];
- CLAMP_MAX(ePoint->e_color[3], pPoint_prev->e_color[3]);
- }
+ const float dt = data->dt;
+ const float min_dist = data->min_dist;
+ const float damp_factor = data->damp_factor;
- /* decrease paint wetness on current point */
- pPoint->wetness -= (ePoint->wetness - e_wet);
- CLAMP(pPoint->wetness, 0.0f, MAX_WETNESS);
- }
- }
+ PaintWavePoint *wPoint = &((PaintWavePoint *)sData->type_data)[index];
+ const int numOfNeighs = sData->adj_data->n_num[index];
+ float force = 0.0f, avg_dist = 0.0f, avg_height = 0.0f, avg_n_height = 0.0f;
+ int numOfN = 0, numOfRN = 0;
+
+ if (wPoint->state > 0)
+ return;
+
+ const int *n_index = sData->adj_data->n_index;
+ const int *n_target = sData->adj_data->n_target;
+ const int *adj_flags = sData->adj_data->flags;
+
+ /* calculate force from surrounding points */
+ for (int i = 0; i < numOfNeighs; i++) {
+ const int n_idx = n_index[index] + i;
+ float dist = bNeighs[n_idx].dist * wave_scale;
+ const PaintWavePoint *tPoint = &prevPoint[n_target[n_idx]];
+
+ if (!dist || tPoint->state > 0)
+ continue;
+
+ CLAMP_MIN(dist, min_dist);
+ avg_dist += dist;
+ numOfN++;
+
+ /* count average height for edge points for open borders */
+ if (!(adj_flags[n_target[n_idx]] & ADJ_ON_MESH_EDGE)) {
+ avg_n_height += tPoint->height;
+ numOfRN++;
+ }
+
+ force += (tPoint->height - wPoint->height) / (dist * dist);
+ avg_height += tPoint->height;
+ }
+ avg_dist = (numOfN) ? avg_dist / numOfN : 0.0f;
+
+ if (surface->flags & MOD_DPAINT_WAVE_OPEN_BORDERS && adj_flags[index] & ADJ_ON_MESH_EDGE) {
+ /* if open borders, apply a fake height to keep waves going on */
+ avg_n_height = (numOfRN) ? avg_n_height / numOfRN : 0.0f;
+ wPoint->height = (dt * wave_speed * avg_n_height + wPoint->height * avg_dist) /
+ (avg_dist + dt * wave_speed);
+ }
+ /* else do wave eq */
+ else {
+ /* add force towards zero height based on average dist */
+ if (avg_dist)
+ force += (0.0f - wPoint->height) * surface->wave_spring / (avg_dist * avg_dist) / 2.0f;
+
+ /* change point velocity */
+ wPoint->velocity += force * dt * wave_speed * wave_speed;
+ /* damping */
+ wPoint->velocity *= damp_factor;
+ /* and new height */
+ wPoint->height += wPoint->velocity * dt;
+
+ /* limit wave slope steepness */
+ if (wave_max_slope && avg_dist) {
+ const float max_offset = wave_max_slope * avg_dist;
+ const float offset = (numOfN) ? (avg_height / numOfN - wPoint->height) : 0.0f;
+ if (offset > max_offset)
+ wPoint->height += offset - max_offset;
+ else if (offset < -max_offset)
+ wPoint->height += offset + max_offset;
+ }
+ }
+
+ if (data->reset_wave) {
+ /* if there wasnt any brush intersection, clear isect height */
+ if (wPoint->state == DPAINT_WAVE_NONE) {
+ wPoint->brush_isect = 0.0f;
}
+ wPoint->state = DPAINT_WAVE_NONE;
}
}
@@ -4338,15 +5063,17 @@ static void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescal
int index;
int steps, ss;
float dt, min_dist, damp_factor;
- float wave_speed = surface->wave_speed;
- float wave_max_slope = (surface->wave_smoothness >= 0.01f) ? (0.5f / surface->wave_smoothness) : 0.0f;
+ const float wave_speed = surface->wave_speed;
+ const float wave_max_slope = (surface->wave_smoothness >= 0.01f) ? (0.5f / surface->wave_smoothness) : 0.0f;
double average_dist = 0.0f;
const float canvas_size = getSurfaceDimension(sData);
- float wave_scale = CANVAS_REL_SIZE / canvas_size;
+ const float wave_scale = CANVAS_REL_SIZE / canvas_size;
/* allocate memory */
- PaintWavePoint *prevPoint = MEM_mallocN(sData->total_points * sizeof(PaintWavePoint), "Temp previous points for wave simulation");
- if (!prevPoint) return;
+ PaintWavePoint *prevPoint = MEM_mallocN(
+ sData->total_points * sizeof(PaintWavePoint), __func__);
+ if (!prevPoint)
+ return;
/* calculate average neigh distance (single thread) */
for (index = 0; index < sData->total_points; index++) {
@@ -4354,13 +5081,14 @@ static void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescal
int numOfNeighs = sData->adj_data->n_num[index];
for (i = 0; i < numOfNeighs; i++) {
- average_dist += bNeighs[sData->adj_data->n_index[index] + i].dist;
+ average_dist += (double)bNeighs[sData->adj_data->n_index[index] + i].dist;
}
}
- average_dist *= wave_scale / sData->adj_data->total_targets;
+ average_dist *= (double)wave_scale / sData->adj_data->total_targets;
/* determine number of required steps */
- steps = (int)ceil((WAVE_TIME_FAC * timescale * surface->wave_timescale) / (average_dist / wave_speed / 3));
+ steps = (int)ceil((double)(WAVE_TIME_FAC * timescale * surface->wave_timescale) /
+ (average_dist / (double)wave_speed / 3));
CLAMP(steps, 1, 20);
timescale /= steps;
@@ -4370,170 +5098,120 @@ static void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescal
damp_factor = pow((1.0f - surface->wave_damping), timescale * surface->wave_timescale);
for (ss = 0; ss < steps; ss++) {
-
/* copy previous frame data */
memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(PaintWavePoint));
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- PaintWavePoint *wPoint = &((PaintWavePoint *)sData->type_data)[index];
- int numOfNeighs = sData->adj_data->n_num[index];
- float force = 0.0f, avg_dist = 0.0f, avg_height = 0.0f, avg_n_height = 0.0f;
- int numOfN = 0, numOfRN = 0;
- int i;
-
- if (wPoint->state > 0) continue;
+ DynamicPaintEffectData data = {
+ .surface = surface, .prevPoint = prevPoint,
+ .wave_speed = wave_speed, .wave_scale = wave_scale, .wave_max_slope = wave_max_slope,
+ .dt = dt, .min_dist = min_dist, .damp_factor = damp_factor, .reset_wave = (ss == steps - 1),
+ };
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_wave_step_cb, sData->total_points > 1000);
+ }
- /* calculate force from surrounding points */
- for (i = 0; i < numOfNeighs; i++) {
- int n_index = sData->adj_data->n_index[index] + i;
- float dist = bNeighs[n_index].dist * wave_scale;
- PaintWavePoint *tPoint = &prevPoint[sData->adj_data->n_target[n_index]];
+ MEM_freeN(prevPoint);
+}
- if (!dist || tPoint->state > 0) continue;
- if (dist < min_dist) dist = min_dist;
- avg_dist += dist;
- numOfN++;
+/* Do dissolve and fading effects */
+static bool dynamic_paint_surface_needs_dry_dissolve(DynamicPaintSurface *surface)
+{
+ return (((surface->type == MOD_DPAINT_SURFACE_T_PAINT) &&
+ (surface->flags & (MOD_DPAINT_USE_DRYING | MOD_DPAINT_DISSOLVE))) ||
+ (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WEIGHT) &&
+ (surface->flags & MOD_DPAINT_DISSOLVE)));
+}
- /* count average height for edge points for open borders */
- if (!(sData->adj_data->flags[sData->adj_data->n_target[n_index]] & ADJ_ON_MESH_EDGE)) {
- avg_n_height += tPoint->height;
- numOfRN++;
- }
+typedef struct DynamicPaintDissolveDryData {
+ const DynamicPaintSurface *surface;
+ const float timescale;
+} DynamicPaintDissolveDryData;
- force += (tPoint->height - wPoint->height) / (dist * dist);
- avg_height += tPoint->height;
- }
- avg_dist = (numOfN) ? avg_dist / numOfN : 0.0f;
+static void dynamic_paint_surface_pre_step_cb(void *userdata, const int index)
+{
+ const DynamicPaintDissolveDryData *data = userdata;
- if (surface->flags & MOD_DPAINT_WAVE_OPEN_BORDERS &&
- sData->adj_data->flags[index] & ADJ_ON_MESH_EDGE)
- {
- /* if open borders, apply a fake height to keep waves going on */
- avg_n_height = (numOfRN) ? avg_n_height / numOfRN : 0.0f;
- wPoint->height = (dt * wave_speed * avg_n_height + wPoint->height * avg_dist) / (avg_dist + dt * wave_speed);
- }
- /* else do wave eq */
- else {
- /* add force towards zero height based on average dist */
- if (avg_dist)
- force += (0.0f - wPoint->height) * surface->wave_spring / (avg_dist * avg_dist) / 2.0f;
-
- /* change point velocity */
- wPoint->velocity += force * dt * wave_speed * wave_speed;
- /* damping */
- wPoint->velocity *= damp_factor;
- /* and new height */
- wPoint->height += wPoint->velocity * dt;
-
- /* limit wave slope steepness */
- if (wave_max_slope && avg_dist) {
- float max_offset = wave_max_slope * avg_dist;
- float offset = (numOfN) ? (avg_height / numOfN - wPoint->height) : 0.0f;
- if (offset > max_offset) wPoint->height += offset - max_offset;
- if (offset < -max_offset) wPoint->height += offset + max_offset;
- }
- }
- }
- }
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ const float timescale = data->timescale;
- /* reset state */
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- PaintWavePoint *wPoint = &((PaintWavePoint *)sData->type_data)[index];
- /* if there wasnt any brush intersection, clear isect height */
- if (wPoint->state == DPAINT_WAVE_NONE) {
- wPoint->brush_isect = 0.0f;
- }
- wPoint->state = DPAINT_WAVE_NONE;
- }
+ /* Do drying dissolve effects */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+ /* drying */
+ if (surface->flags & MOD_DPAINT_USE_DRYING) {
+ if (pPoint->wetness >= MIN_WETNESS) {
+ int i;
+ float dry_ratio, f_color[4];
+ float p_wetness = pPoint->wetness;
+
+ value_dissolve(&pPoint->wetness, surface->dry_speed, timescale,
+ (surface->flags & MOD_DPAINT_DRY_LOG) != 0);
+ CLAMP_MIN(pPoint->wetness, 0.0f);
- MEM_freeN(prevPoint);
-}
+ if (pPoint->wetness < surface->color_dry_threshold) {
+ dry_ratio = pPoint->wetness / p_wetness;
-/* Do dissolve and fading effects */
-static void dynamicPaint_surfacePreStep(DynamicPaintSurface *surface, float timescale)
-{
- PaintSurfaceData *sData = surface->data;
- int index;
+ /*
+ * Slowly "shift" paint from wet layer to dry layer as it drys:
+ */
+ /* make sure alpha values are within proper range */
+ CLAMP(pPoint->color[3], 0.0f, 1.0f);
+ CLAMP(pPoint->e_color[3], 0.0f, 1.0f);
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- /* Do drying dissolve effects */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
- /* drying */
- if (surface->flags & MOD_DPAINT_USE_DRYING) {
- if (pPoint->wetness >= MIN_WETNESS) {
- int i;
- float dry_ratio, f_color[4];
- float p_wetness = pPoint->wetness;
- value_dissolve(&pPoint->wetness, surface->dry_speed, timescale, (surface->flags & MOD_DPAINT_DRY_LOG));
- if (pPoint->wetness < 0.0f) pPoint->wetness = 0.0f;
-
- if (pPoint->wetness < surface->color_dry_threshold) {
- dry_ratio = pPoint->wetness / p_wetness;
-
- /*
- * Slowly "shift" paint from wet layer to dry layer as it drys:
- */
- /* make sure alpha values are within proper range */
- CLAMP(pPoint->color[3], 0.0f, 1.0f);
- CLAMP(pPoint->e_color[3], 0.0f, 1.0f);
-
- /* get current final blended color of these layers */
- blendColors(pPoint->color, pPoint->color[3], pPoint->e_color, pPoint->e_color[3], f_color);
- /* reduce wet layer alpha by dry factor */
- pPoint->e_color[3] *= dry_ratio;
-
- /* now calculate new alpha for dry layer that keeps final blended color unchanged */
- pPoint->color[3] = (f_color[3] - pPoint->e_color[3]) / (1.0f - pPoint->e_color[3]);
- /* for each rgb component, calculate a new dry layer color that keeps the final blend color
- * with these new alpha values. (wet layer color doesnt change)*/
- if (pPoint->color[3]) {
- for (i = 0; i < 3; i++) {
- pPoint->color[i] = (f_color[i] * f_color[3] - pPoint->e_color[i] * pPoint->e_color[3]) / (pPoint->color[3] * (1.0f - pPoint->e_color[3]));
- }
+ /* get current final blended color of these layers */
+ blendColors(pPoint->color, pPoint->color[3], pPoint->e_color, pPoint->e_color[3], f_color);
+ /* reduce wet layer alpha by dry factor */
+ pPoint->e_color[3] *= dry_ratio;
+
+ /* now calculate new alpha for dry layer that keeps final blended color unchanged */
+ pPoint->color[3] = (f_color[3] - pPoint->e_color[3]) / (1.0f - pPoint->e_color[3]);
+ /* for each rgb component, calculate a new dry layer color that keeps the final blend color
+ * with these new alpha values. (wet layer color doesnt change)*/
+ if (pPoint->color[3]) {
+ for (i = 0; i < 3; i++) {
+ pPoint->color[i] = (f_color[i] * f_color[3] - pPoint->e_color[i] * pPoint->e_color[3]) /
+ (pPoint->color[3] * (1.0f - pPoint->e_color[3]));
}
}
-
- pPoint->state = DPAINT_PAINT_WET;
- }
- /* in case of just dryed paint, just mix it to the dry layer and mark it empty */
- else if (pPoint->state > 0) {
- float f_color[4];
- blendColors(pPoint->color, pPoint->color[3], pPoint->e_color, pPoint->e_color[3], f_color);
- copy_v4_v4(pPoint->color, f_color);
- /* clear wet layer */
- pPoint->wetness = 0.0f;
- pPoint->e_color[3] = 0.0f;
- pPoint->state = DPAINT_PAINT_DRY;
}
- }
-
- if (surface->flags & MOD_DPAINT_DISSOLVE) {
- value_dissolve(&pPoint->color[3], surface->diss_speed, timescale, (surface->flags & MOD_DPAINT_DISSOLVE_LOG));
- CLAMP_MIN(pPoint->color[3], 0.0f);
- value_dissolve(&pPoint->e_color[3], surface->diss_speed, timescale, (surface->flags & MOD_DPAINT_DISSOLVE_LOG));
- CLAMP_MIN(pPoint->e_color[3], 0.0f);
+ pPoint->state = DPAINT_PAINT_WET;
+ }
+ /* in case of just dryed paint, just mix it to the dry layer and mark it empty */
+ else if (pPoint->state > 0) {
+ float f_color[4];
+ blendColors(pPoint->color, pPoint->color[3], pPoint->e_color, pPoint->e_color[3], f_color);
+ copy_v4_v4(pPoint->color, f_color);
+ /* clear wet layer */
+ pPoint->wetness = 0.0f;
+ pPoint->e_color[3] = 0.0f;
+ pPoint->state = DPAINT_PAINT_DRY;
}
}
- /* dissolve for float types */
- else if (surface->flags & MOD_DPAINT_DISSOLVE &&
- (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
- surface->type == MOD_DPAINT_SURFACE_T_WEIGHT))
- {
- float *point = &((float *)sData->type_data)[index];
- /* log or linear */
- value_dissolve(point, surface->diss_speed, timescale, (surface->flags & MOD_DPAINT_DISSOLVE_LOG));
- CLAMP_MIN(*point, 0.0f);
+ if (surface->flags & MOD_DPAINT_DISSOLVE) {
+ value_dissolve(&pPoint->color[3], surface->diss_speed, timescale,
+ (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0);
+ CLAMP_MIN(pPoint->color[3], 0.0f);
+
+ value_dissolve(&pPoint->e_color[3], surface->diss_speed, timescale,
+ (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0);
+ CLAMP_MIN(pPoint->e_color[3], 0.0f);
}
}
+ /* dissolve for float types */
+ else if (surface->flags & MOD_DPAINT_DISSOLVE &&
+ (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE || surface->type == MOD_DPAINT_SURFACE_T_WEIGHT))
+ {
+ float *point = &((float *)sData->type_data)[index];
+ /* log or linear */
+ value_dissolve(point, surface->diss_speed, timescale, (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0);
+ CLAMP_MIN(*point, 0.0f);
+ }
}
-static int dynamicPaint_surfaceHasMoved(DynamicPaintSurface *surface, Object *ob)
+static bool dynamicPaint_surfaceHasMoved(DynamicPaintSurface *surface, Object *ob)
{
PaintSurfaceData *sData = surface->data;
PaintBakeData *bData = sData->bData;
@@ -4542,67 +5220,159 @@ static int dynamicPaint_surfaceHasMoved(DynamicPaintSurface *surface, Object *ob
int numOfVerts = dm->getNumVerts(dm);
int i;
- int ret = 0;
- if (!bData->prev_verts) return 1;
+ if (!bData->prev_verts)
+ return true;
/* matrix comparison */
- for (i = 0; i < 4; i++) {
- int j;
- for (j = 0; j < 4; j++)
- if (bData->prev_obmat[i][j] != ob->obmat[i][j]) return 1;
- }
+ if (!equals_m4m4(bData->prev_obmat, ob->obmat))
+ return true;
/* vertices */
-#pragma omp parallel for schedule(static)
for (i = 0; i < numOfVerts; i++) {
- int j;
- for (j = 0; j < 3; j++)
- if (bData->prev_verts[i].co[j] != mvert[i].co[j]) {
- ret = 1;
- break;
- }
+ if (!equals_v3v3(bData->prev_verts[i].co, mvert[i].co)) {
+ return true;
+ }
}
- return ret;
+ return false;
}
-static int surface_needsVelocityData(DynamicPaintSurface *surface, const Scene *scene)
-{
- if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP)
- return 1;
+/* Prepare for surface step by creating PaintBakeNormal data */
+typedef struct DynamicPaintGenerateBakeData {
+ const DynamicPaintSurface *surface;
+ Object *ob;
- if (surface_getBrushFlags(surface, scene) & BRUSH_USES_VELOCITY)
- return 1;
+ const MVert *mvert;
+ const Vec3f *canvas_verts;
- return 0;
-}
+ const bool do_velocity_data;
+ const bool new_bdata;
+} DynamicPaintGenerateBakeData;
-static int surface_needsAccelerationData(DynamicPaintSurface *surface)
+static void dynamic_paint_generate_bake_data_cb(void *userdata, const int index)
{
- if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP)
- return 1;
+ const DynamicPaintGenerateBakeData *data = userdata;
- return 0;
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ const PaintAdjData *adj_data = sData->adj_data;
+ const PaintBakeData *bData = sData->bData;
+
+ Object *ob = data->ob;
+
+ const MVert *mvert = data->mvert;
+ const Vec3f *canvas_verts = data->canvas_verts;
+
+ const bool do_velocity_data = data->do_velocity_data;
+ const bool new_bdata = data->new_bdata;
+
+ float prev_point[3] = {0.0f, 0.0f, 0.0f};
+ float temp_nor[3];
+
+ if (do_velocity_data && !new_bdata) {
+ copy_v3_v3(prev_point, bData->realCoord[bData->s_pos[index]].v);
+ }
+
+ /*
+ * Calculate current 3D-position and normal of each surface point
+ */
+ if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
+ float n1[3], n2[3], n3[3];
+ const ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
+ const PaintUVPoint *tPoint = &((PaintUVPoint *)f_data->uv_p)[index];
+
+ bData->s_num[index] = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
+ bData->s_pos[index] = index * bData->s_num[index];
+
+ /* per sample coordinates */
+ for (int ss = 0; ss < bData->s_num[index]; ss++) {
+ interp_v3_v3v3v3(bData->realCoord[bData->s_pos[index] + ss].v,
+ canvas_verts[tPoint->v1].v,
+ canvas_verts[tPoint->v2].v,
+ canvas_verts[tPoint->v3].v,
+ f_data->barycentricWeights[index * bData->s_num[index] + ss].v);
+ }
+
+ /* Calculate current pixel surface normal */
+ normal_short_to_float_v3(n1, mvert[tPoint->v1].no);
+ normal_short_to_float_v3(n2, mvert[tPoint->v2].no);
+ normal_short_to_float_v3(n3, mvert[tPoint->v3].no);
+
+ interp_v3_v3v3v3(temp_nor, n1, n2, n3, f_data->barycentricWeights[index * bData->s_num[index]].v);
+ normalize_v3(temp_nor);
+ if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
+ /* Prepare surface normal directional scale to easily convert
+ * brush intersection amount between global and local space */
+ float scaled_nor[3];
+ mul_v3_v3v3(scaled_nor, temp_nor, ob->size);
+ bData->bNormal[index].normal_scale = len_v3(scaled_nor);
+ }
+ mul_mat3_m4_v3(ob->obmat, temp_nor);
+ normalize_v3(temp_nor);
+ negate_v3_v3(bData->bNormal[index].invNorm, temp_nor);
+ }
+ else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
+ int ss;
+ if (surface->flags & MOD_DPAINT_ANTIALIAS && adj_data) {
+ bData->s_num[index] = adj_data->n_num[index] + 1;
+ bData->s_pos[index] = adj_data->n_index[index] + index;
+ }
+ else {
+ bData->s_num[index] = 1;
+ bData->s_pos[index] = index;
+ }
+
+ /* calculate position for each sample */
+ for (ss = 0; ss < bData->s_num[index]; ss++) {
+ /* first sample is always point center */
+ copy_v3_v3(bData->realCoord[bData->s_pos[index] + ss].v, canvas_verts[index].v);
+ if (ss > 0) {
+ int t_index = adj_data->n_index[index] + (ss - 1);
+ /* get vertex position at 1/3 of each neigh edge */
+ mul_v3_fl(bData->realCoord[bData->s_pos[index] + ss].v, 2.0f / 3.0f);
+ madd_v3_v3fl(bData->realCoord[bData->s_pos[index] + ss].v,
+ canvas_verts[adj_data->n_target[t_index]].v, 1.0f / 3.0f);
+ }
+ }
+
+ /* normal */
+ normal_short_to_float_v3(temp_nor, mvert[index].no);
+ if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
+ /* Prepare surface normal directional scale to easily convert
+ * brush intersection amount between global and local space */
+ float scaled_nor[3];
+ mul_v3_v3v3(scaled_nor, temp_nor, ob->size);
+ bData->bNormal[index].normal_scale = len_v3(scaled_nor);
+ }
+ mul_mat3_m4_v3(ob->obmat, temp_nor);
+ normalize_v3(temp_nor);
+ negate_v3_v3(bData->bNormal[index].invNorm, temp_nor);
+ }
+
+ /* calculate speed vector */
+ if (do_velocity_data && !new_bdata && !bData->clear) {
+ sub_v3_v3v3(bData->velocity[index].v, bData->realCoord[bData->s_pos[index]].v, prev_point);
+ }
}
-/* Prepare for surface step by creating PaintBakeNormal data */
static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Scene *scene, Object *ob)
{
PaintSurfaceData *sData = surface->data;
- PaintAdjData *adj_data = sData->adj_data;
PaintBakeData *bData = sData->bData;
DerivedMesh *dm = surface->canvas->dm;
- int index, new_bdata = 0;
- int do_velocity_data = surface_needsVelocityData(surface, scene);
- int do_accel_data = surface_needsAccelerationData(surface);
+ int index;
+ bool new_bdata = false;
+ const bool do_velocity_data = ((surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) ||
+ (surface_getBrushFlags(surface, scene) & BRUSH_USES_VELOCITY));
+ const bool do_accel_data = (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) != 0;
int canvasNumOfVerts = dm->getNumVerts(dm);
MVert *mvert = dm->getVertArray(dm);
Vec3f *canvas_verts;
if (bData) {
- int surface_moved = dynamicPaint_surfaceHasMoved(surface, ob);
+ const bool surface_moved = dynamicPaint_surfaceHasMoved(surface, ob);
/* get previous speed for accelertaion */
if (do_accel_data && bData->prev_velocity && bData->velocity)
@@ -4618,13 +5388,15 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Sce
}
canvas_verts = (struct Vec3f *) MEM_mallocN(canvasNumOfVerts * sizeof(struct Vec3f), "Dynamic Paint transformed canvas verts");
- if (!canvas_verts) return 0;
+ if (!canvas_verts)
+ return 0;
/* allocate memory if required */
if (!bData) {
sData->bData = bData = (struct PaintBakeData *) MEM_callocN(sizeof(struct PaintBakeData), "Dynamic Paint bake data");
if (!bData) {
- if (canvas_verts) MEM_freeN(canvas_verts);
+ if (canvas_verts)
+ MEM_freeN(canvas_verts);
return 0;
}
@@ -4637,16 +5409,21 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Sce
/* if any allocation failed, free everything */
if (!bData->bNormal || !bData->s_pos || !bData->s_num || !bData->realCoord || !canvas_verts) {
- if (bData->bNormal) MEM_freeN(bData->bNormal);
- if (bData->s_pos) MEM_freeN(bData->s_pos);
- if (bData->s_num) MEM_freeN(bData->s_num);
- if (bData->realCoord) MEM_freeN(bData->realCoord);
- if (canvas_verts) MEM_freeN(canvas_verts);
+ if (bData->bNormal)
+ MEM_freeN(bData->bNormal);
+ if (bData->s_pos)
+ MEM_freeN(bData->s_pos);
+ if (bData->s_num)
+ MEM_freeN(bData->s_num);
+ if (bData->realCoord)
+ MEM_freeN(bData->realCoord);
+ if (canvas_verts)
+ MEM_freeN(canvas_verts);
return setError(surface->canvas, N_("Not enough free memory"));
}
- new_bdata = 1;
+ new_bdata = true;
}
if (do_velocity_data && !bData->velocity) {
@@ -4662,7 +5439,7 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Sce
/*
* Make a transformed copy of canvas derived mesh vertices to avoid recalculation.
*/
- bData->mesh_bounds.valid = 0;
+ bData->mesh_bounds.valid = false;
for (index = 0; index < canvasNumOfVerts; index++) {
copy_v3_v3(canvas_verts[index].v, mvert[index].co);
mul_m4_v3(ob->obmat, canvas_verts[index].v);
@@ -4672,112 +5449,20 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Sce
/*
* Prepare each surface point for a new step
*/
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- float prev_point[3] = {0.0f, 0.0f, 0.0f};
- if (do_velocity_data && !new_bdata) {
- copy_v3_v3(prev_point, bData->realCoord[bData->s_pos[index]].v);
- }
- /*
- * Calculate current 3D-position and normal of each surface point
- */
- if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
- float n1[3], n2[3], n3[3];
- ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
- PaintUVPoint *tPoint = &((PaintUVPoint *)f_data->uv_p)[index];
- int ss;
-
- bData->s_num[index] = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
- bData->s_pos[index] = index * bData->s_num[index];
-
- /* per sample coordinates */
- for (ss = 0; ss < bData->s_num[index]; ss++) {
- interp_v3_v3v3v3(bData->realCoord[bData->s_pos[index] + ss].v,
- canvas_verts[tPoint->v1].v,
- canvas_verts[tPoint->v2].v,
- canvas_verts[tPoint->v3].v,
- f_data->barycentricWeights[index * bData->s_num[index] + ss].v);
- }
-
- /* Calculate current pixel surface normal */
- normal_short_to_float_v3(n1, mvert[tPoint->v1].no);
- normal_short_to_float_v3(n2, mvert[tPoint->v2].no);
- normal_short_to_float_v3(n3, mvert[tPoint->v3].no);
-
- interp_v3_v3v3v3(bData->bNormal[index].invNorm,
- n1, n2, n3, f_data->barycentricWeights[index * bData->s_num[index]].v);
- mul_mat3_m4_v3(ob->obmat, bData->bNormal[index].invNorm);
- normalize_v3(bData->bNormal[index].invNorm);
- negate_v3(bData->bNormal[index].invNorm);
- }
- else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- int ss;
- if (surface->flags & MOD_DPAINT_ANTIALIAS && adj_data) {
- bData->s_num[index] = adj_data->n_num[index] + 1;
- bData->s_pos[index] = adj_data->n_index[index] + index;
- }
- else {
- bData->s_num[index] = 1;
- bData->s_pos[index] = index;
- }
-
- /* calculate position for each sample */
- for (ss = 0; ss < bData->s_num[index]; ss++) {
- /* first sample is always point center */
- copy_v3_v3(bData->realCoord[bData->s_pos[index] + ss].v, canvas_verts[index].v);
- if (ss > 0) {
- int t_index = adj_data->n_index[index] + (ss - 1);
- /* get vertex position at 1/3 of each neigh edge */
- mul_v3_fl(bData->realCoord[bData->s_pos[index] + ss].v, 2.0f / 3.0f);
- madd_v3_v3fl(bData->realCoord[bData->s_pos[index] + ss].v, canvas_verts[adj_data->n_target[t_index]].v, 1.0f / 3.0f);
- }
- }
-
- /* normal */
- normal_short_to_float_v3(bData->bNormal[index].invNorm, mvert[index].no);
- mul_mat3_m4_v3(ob->obmat, bData->bNormal[index].invNorm);
- normalize_v3(bData->bNormal[index].invNorm);
- negate_v3(bData->bNormal[index].invNorm);
- }
-
- /* Prepare surface normal directional scale to easily convert
- * brush intersection amount between global and local space */
- if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
- surface->type == MOD_DPAINT_SURFACE_T_WAVE)
- {
- float temp_nor[3];
- if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- normal_short_to_float_v3(temp_nor, mvert[index].no);
- normalize_v3(temp_nor);
- }
- else {
- float n1[3], n2[3], n3[3];
- ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
- PaintUVPoint *tPoint = &((PaintUVPoint *)f_data->uv_p)[index];
-
- normal_short_to_float_v3(n1, mvert[tPoint->v1].no);
- normal_short_to_float_v3(n2, mvert[tPoint->v2].no);
- normal_short_to_float_v3(n3, mvert[tPoint->v3].no);
- interp_v3_v3v3v3(temp_nor,
- n1, n2, n3, f_data->barycentricWeights[index * bData->s_num[index]].v);
- }
-
- mul_v3_v3(temp_nor, ob->size);
- bData->bNormal[index].normal_scale = len_v3(temp_nor);
- }
-
- /* calculate speed vector */
- if (do_velocity_data && !new_bdata && !bData->clear) {
- sub_v3_v3v3(bData->velocity[index].v, bData->realCoord[bData->s_pos[index]].v, prev_point);
- }
- }
+ DynamicPaintGenerateBakeData data = {
+ .surface = surface, .ob = ob,
+ .mvert = mvert, .canvas_verts = canvas_verts,
+ .do_velocity_data = do_velocity_data, .new_bdata = new_bdata,
+ };
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_generate_bake_data_cb, sData->total_points > 1000);
MEM_freeN(canvas_verts);
/* generate surface space partitioning grid */
surfaceGenerateGrid(surface);
/* calculate current frame adjacency point distances and global dirs */
- dynamicPaint_prepareAdjacencyData(surface, 0);
+ dynamicPaint_prepareAdjacencyData(surface, false);
/* Copy current frame vertices to check against in next frame */
copy_m4_m4(bData->prev_obmat, ob->obmat);
@@ -4797,9 +5482,16 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
PaintBakeData *bData = sData->bData;
DynamicPaintCanvasSettings *canvas = surface->canvas;
int ret = 1;
- if (sData->total_points < 1) return 0;
- dynamicPaint_surfacePreStep(surface, timescale);
+ if (sData->total_points < 1)
+ return 0;
+
+ if (dynamic_paint_surface_needs_dry_dissolve(surface)) {
+ DynamicPaintDissolveDryData data = {.surface = surface, .timescale = timescale};
+ BLI_task_parallel_range(0, sData->total_points, &data,
+ dynamic_paint_surface_pre_step_cb, sData->total_points > 1000);
+ }
+
/*
* Loop through surface's target paint objects and do painting
*/
@@ -4823,24 +5515,23 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
brushObj = NULL;
/* select object */
if (surface->brush_group) {
- if (go->ob) brushObj = go->ob;
+ if (go->ob)
+ brushObj = go->ob;
}
else
brushObj = base->object;
- if (!brushObj) {
- /* skip item */
- if (surface->brush_group) go = go->next;
- else base = base->next;
- continue;
- }
-
/* next item */
if (surface->brush_group)
go = go->next;
else
base = base->next;
+ if (!brushObj) {
+ /* skip item */
+ continue;
+ }
+
/* check if target has an active dp modifier */
md = modifiers_findByType(brushObj, eModifierType_DynamicPaint);
if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) {
@@ -4855,15 +5546,16 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
bData->brush_velocity = MEM_callocN(sData->total_points * sizeof(float) * 4, "Dynamic Paint brush velocity");
/* init adjacency data if not already */
if (!sData->adj_data)
- dynamicPaint_initAdjacencyData(surface, 1);
+ dynamicPaint_initAdjacencyData(surface, true);
if (!bData->bNeighs)
- dynamicPaint_prepareAdjacencyData(surface, 1);
+ dynamicPaint_prepareAdjacencyData(surface, true);
}
/* update object data on this subframe */
if (subframe) {
scene_setSubframe(scene, subframe);
- BKE_object_modifier_update_subframe(scene, brushObj, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
+ BKE_object_modifier_update_subframe(scene, brushObj, true, SUBFRAME_RECURSION,
+ BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
}
/* Prepare materials if required */
if (brush_usesMaterial(brush, scene))
@@ -4872,12 +5564,13 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
/* Apply brush on the surface depending on it's collision type */
/* Particle brush: */
if (brush->collision == MOD_DPAINT_COL_PSYS) {
- if (brush->psys && brush->psys->part && ELEM(brush->psys->part->type, PART_EMITTER, PART_FLUID) &&
- psys_check_enabled(brushObj, brush->psys))
+ if (brush->psys && brush->psys->part &&
+ ELEM(brush->psys->part->type, PART_EMITTER, PART_FLUID) &&
+ psys_check_enabled(brushObj, brush->psys, G.is_rendering))
{
-
/* Paint a particle system */
- BKE_animsys_evaluate_animdata(scene, &brush->psys->part->id, brush->psys->part->adt, BKE_scene_frame_get(scene), ADT_RECALC_ANIM);
+ BKE_animsys_evaluate_animdata(scene, &brush->psys->part->id, brush->psys->part->adt,
+ BKE_scene_frame_get(scene), ADT_RECALC_ANIM);
dynamicPaint_paintParticles(surface, brush->psys, brush, timescale);
}
}
@@ -4897,7 +5590,8 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
if (subframe) {
scene->r.cfra = scene_frame;
scene->r.subframe = scene_subframe;
- BKE_object_modifier_update_subframe(scene, brushObj, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
+ BKE_object_modifier_update_subframe(scene, brushObj, true, SUBFRAME_RECURSION,
+ BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
}
/* process special brush effects, like smudge */
@@ -4937,8 +5631,10 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
}
/* Free temporary effect data */
- if (prevPoint) MEM_freeN(prevPoint);
- if (force) MEM_freeN(force);
+ if (prevPoint)
+ MEM_freeN(prevPoint);
+ if (force)
+ MEM_freeN(force);
}
}
@@ -4957,8 +5653,8 @@ int dynamicPaint_calculateFrame(DynamicPaintSurface *surface, Scene *scene, Obje
dynamicPaint_applySurfaceDisplace(surface, surface->canvas->dm);
/* update bake data */
- dynamicPaint_generateBakeData(surface, scene, cObject);
-
+ dynamicPaint_generateBakeData(surface, scene, cObject);
+
/* don't do substeps for first frame */
if (surface->substeps && (frame != surface->start_frame)) {
int st;
@@ -4966,7 +5662,8 @@ int dynamicPaint_calculateFrame(DynamicPaintSurface *surface, Scene *scene, Obje
for (st = 1; st <= surface->substeps; st++) {
float subframe = ((float) st) / (surface->substeps + 1);
- if (!dynamicPaint_doStep(scene, cObject, surface, timescale, subframe)) return 0;
+ if (!dynamicPaint_doStep(scene, cObject, surface, timescale, subframe))
+ return 0;
}
}
diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c
index 6c117447664..05cf5f6d7bd 100644
--- a/source/blender/blenkernel/intern/editderivedmesh.c
+++ b/source/blender/blenkernel/intern/editderivedmesh.c
@@ -57,6 +57,7 @@
#include "MEM_guardedalloc.h"
#include "GPU_glew.h"
+#include "GPU_buffers.h"
#include "GPU_shader.h"
#include "GPU_basic_shader.h"
@@ -452,7 +453,7 @@ finally:
pRes[3] = fSign;
}
-static void emDM_calc_loop_tangents_thread(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid))
+static void emDM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
{
struct SGLSLEditMeshToTangent *mesh2tangent = taskdata;
/* new computation method */
@@ -1180,6 +1181,14 @@ static void emDM_drawMappedFaces(
/* if non zero we know a face was rendered */
if (poly_prev != GL_ZERO) glEnd();
+
+ if (draw_option_prev == DM_DRAW_OPTION_STIPPLE) {
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ }
+
+ if (shade_prev == GL_FLAT) {
+ glShadeModel(GL_SMOOTH);
+ }
}
static void bmdm_get_tri_uv(BMLoop *ltri[3], MLoopUV *luv[3], const int cd_loop_uv_offset)
@@ -1235,8 +1244,6 @@ static void emDM_drawFacesTex_common(
// dummylcol.r = dummylcol.g = dummylcol.b = dummylcol.a = 255; /* UNUSED */
/* always use smooth shading even for flat faces, else vertex colors wont interpolate */
- glShadeModel(GL_SMOOTH);
-
BM_mesh_elem_index_ensure(bm, BM_FACE);
/* call again below is ok */
@@ -1383,8 +1390,6 @@ static void emDM_drawFacesTex_common(
}
}
}
-
- glShadeModel(GL_FLAT);
}
static void emDM_drawFacesTex(
@@ -1449,15 +1454,15 @@ static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const B
glVertexAttrib2fv(attribs->tface[i].gl_index, uv);
}
for (i = 0; i < attribs->totmcol; i++) {
- GLubyte col[4];
+ float col[4];
if (attribs->mcol[i].em_offset != -1) {
const MLoopCol *cp = BM_ELEM_CD_GET_VOID_P(loop, attribs->mcol[i].em_offset);
- copy_v4_v4_uchar(col, &cp->r);
+ rgba_uchar_to_float(col, &cp->r);
}
else {
- col[0] = 0; col[1] = 0; col[2] = 0; col[3] = 0;
+ col[0] = 0.0f; col[1] = 0.0f; col[2] = 0.0f; col[3] = 0.0f;
}
- glVertexAttrib4ubv(attribs->mcol[i].gl_index, col);
+ glVertexAttrib4fv(attribs->mcol[i].gl_index, col);
}
for (i = 0; i < attribs->tottang; i++) {
@@ -1505,8 +1510,6 @@ static void emDM_drawMappedFacesGLSL(
vertexNos = bmdm->vertexNos;
polyNos = bmdm->polyNos;
- /* always use smooth shading even for flat faces, else vertex colors wont interpolate */
- glShadeModel(GL_SMOOTH);
BM_mesh_elem_index_ensure(bm, (BM_VERT | BM_FACE) | (lnors ? BM_LOOP : 0));
for (i = 0; i < em->tottri; i++) {
@@ -1527,6 +1530,7 @@ static void emDM_drawMappedFacesGLSL(
do_draw = setMaterial(matnr = new_matnr, &gattribs);
if (do_draw) {
DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
+ DM_draw_attrib_vertex_uniforms(&attribs);
if (UNLIKELY(attribs.tottang && bm->elem_index_dirty & BM_LOOP)) {
BM_mesh_elem_index_ensure(bm, BM_LOOP);
}
@@ -1616,8 +1620,6 @@ static void emDM_drawMappedFacesMat(
vertexNos = bmdm->vertexNos;
polyNos = bmdm->polyNos;
- /* always use smooth shading even for flat faces, else vertex colors wont interpolate */
- glShadeModel(GL_SMOOTH);
BM_mesh_elem_index_ensure(bm, (BM_VERT | BM_FACE) | (lnors ? BM_LOOP : 0));
for (i = 0; i < em->tottri; i++) {
@@ -2206,16 +2208,17 @@ static CustomData *bmDm_getPolyDataLayout(DerivedMesh *dm)
return &bmdm->em->bm->pdata;
}
-
+/**
+ * \note This may be called per-draw,
+ * avoid allocating large arrays where possible and keep this a thin wrapper for #BMesh.
+ */
DerivedMesh *getEditDerivedBMesh(
- BMEditMesh *em,
- Object *UNUSED(ob),
+ BMEditMesh *em, struct Object *UNUSED(ob),
+ CustomDataMask data_mask,
float (*vertexCos)[3])
{
EditDerivedBMesh *bmdm = MEM_callocN(sizeof(*bmdm), __func__);
BMesh *bm = em->bm;
- const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT);
- const int cd_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
bmdm->em = em;
@@ -2284,6 +2287,9 @@ DerivedMesh *getEditDerivedBMesh(
bmdm->vertexCos = (const float (*)[3])vertexCos;
bmdm->dm.deformedOnly = (vertexCos != NULL);
+ const int cd_dvert_offset = (data_mask & CD_MASK_MDEFORMVERT) ?
+ CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT) : -1;
+
if (cd_dvert_offset != -1) {
BMIter iter;
BMVert *eve;
@@ -2297,6 +2303,9 @@ DerivedMesh *getEditDerivedBMesh(
}
}
+ const int cd_skin_offset = (data_mask & CD_MASK_MVERT_SKIN) ?
+ CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN) : -1;
+
if (cd_skin_offset != -1) {
BMIter iter;
BMVert *eve;
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index 6284b3a46fb..7e6897a2858 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -139,9 +139,6 @@ void free_partdeflect(PartDeflect *pd)
if (!pd)
return;
- if (pd->tex)
- id_us_min(&pd->tex->id);
-
if (pd->rng)
BLI_rng_free(pd->rng);
@@ -158,15 +155,20 @@ static EffectorCache *new_effector_cache(Scene *scene, Object *ob, ParticleSyste
eff->frame = -1;
return eff;
}
-static void add_object_to_effectors(ListBase **effectors, Scene *scene, EffectorWeights *weights, Object *ob, Object *ob_src)
+static void add_object_to_effectors(ListBase **effectors, Scene *scene, EffectorWeights *weights, Object *ob, Object *ob_src, bool for_simulation)
{
EffectorCache *eff = NULL;
- if ( ob == ob_src || weights->weight[ob->pd->forcefield] == 0.0f )
+ if ( ob == ob_src )
return;
- if (ob->pd->shape == PFIELD_SHAPE_POINTS && !ob->derivedFinal )
- return;
+ if (for_simulation) {
+ if (weights->weight[ob->pd->forcefield] == 0.0f )
+ return;
+
+ if (ob->pd->shape == PFIELD_SHAPE_POINTS && !ob->derivedFinal )
+ return;
+ }
if (*effectors == NULL)
*effectors = MEM_callocN(sizeof(ListBase), "effectors list");
@@ -178,24 +180,24 @@ static void add_object_to_effectors(ListBase **effectors, Scene *scene, Effector
BLI_addtail(*effectors, eff);
}
-static void add_particles_to_effectors(ListBase **effectors, Scene *scene, EffectorWeights *weights, Object *ob, ParticleSystem *psys, ParticleSystem *psys_src)
+static void add_particles_to_effectors(ListBase **effectors, Scene *scene, EffectorWeights *weights, Object *ob, ParticleSystem *psys, ParticleSystem *psys_src, bool for_simulation)
{
ParticleSettings *part= psys->part;
- if ( !psys_check_enabled(ob, psys) )
+ if ( !psys_check_enabled(ob, psys, G.is_rendering) )
return;
if ( psys == psys_src && (part->flag & PART_SELF_EFFECT) == 0)
return;
- if ( part->pd && part->pd->forcefield && weights->weight[part->pd->forcefield] != 0.0f) {
+ if ( part->pd && part->pd->forcefield && (!for_simulation || weights->weight[part->pd->forcefield] != 0.0f)) {
if (*effectors == NULL)
*effectors = MEM_callocN(sizeof(ListBase), "effectors list");
BLI_addtail(*effectors, new_effector_cache(scene, ob, psys, part->pd));
}
- if (part->pd2 && part->pd2->forcefield && weights->weight[part->pd2->forcefield] != 0.0f) {
+ if (part->pd2 && part->pd2->forcefield && (!for_simulation || weights->weight[part->pd2->forcefield] != 0.0f)) {
if (*effectors == NULL)
*effectors = MEM_callocN(sizeof(ListBase), "effectors list");
@@ -205,7 +207,7 @@ static void add_particles_to_effectors(ListBase **effectors, Scene *scene, Effec
/* returns ListBase handle with objects taking part in the effecting */
ListBase *pdInitEffectors(Scene *scene, Object *ob_src, ParticleSystem *psys_src,
- EffectorWeights *weights, bool precalc)
+ EffectorWeights *weights, bool for_simulation)
{
Base *base;
unsigned int layer= ob_src->lay;
@@ -217,13 +219,13 @@ ListBase *pdInitEffectors(Scene *scene, Object *ob_src, ParticleSystem *psys_src
for (go= weights->group->gobject.first; go; go= go->next) {
if ( (go->ob->lay & layer) ) {
if ( go->ob->pd && go->ob->pd->forcefield )
- add_object_to_effectors(&effectors, scene, weights, go->ob, ob_src);
+ add_object_to_effectors(&effectors, scene, weights, go->ob, ob_src, for_simulation);
if ( go->ob->particlesystem.first ) {
ParticleSystem *psys= go->ob->particlesystem.first;
for ( ; psys; psys=psys->next )
- add_particles_to_effectors(&effectors, scene, weights, go->ob, psys, psys_src);
+ add_particles_to_effectors(&effectors, scene, weights, go->ob, psys, psys_src, for_simulation);
}
}
}
@@ -232,19 +234,19 @@ ListBase *pdInitEffectors(Scene *scene, Object *ob_src, ParticleSystem *psys_src
for (base = scene->base.first; base; base= base->next) {
if ( (base->lay & layer) ) {
if ( base->object->pd && base->object->pd->forcefield )
- add_object_to_effectors(&effectors, scene, weights, base->object, ob_src);
+ add_object_to_effectors(&effectors, scene, weights, base->object, ob_src, for_simulation);
if ( base->object->particlesystem.first ) {
ParticleSystem *psys= base->object->particlesystem.first;
for ( ; psys; psys=psys->next )
- add_particles_to_effectors(&effectors, scene, weights, base->object, psys, psys_src);
+ add_particles_to_effectors(&effectors, scene, weights, base->object, psys, psys_src, for_simulation);
}
}
}
}
- if (precalc)
+ if (for_simulation)
pdPrecalculateEffectors(effectors);
return effectors;
@@ -566,7 +568,9 @@ int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *poin
float cfra = eff->scene->r.cfra;
int ret = 0;
- if (eff->pd && eff->pd->shape==PFIELD_SHAPE_SURFACE && eff->surmd) {
+ /* In case surface object is in Edit mode when loading the .blend, surface modifier is never executed
+ * and bvhtree never built, see T48415. */
+ if (eff->pd && eff->pd->shape==PFIELD_SHAPE_SURFACE && eff->surmd && eff->surmd->bvhtree) {
/* closest point in the object surface is an effector */
float vec[3];
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index a2b5a05feac..a89d423e7a6 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -1859,7 +1859,7 @@ float driver_get_variable_value(ChannelDriver *driver, DriverVar *dvar)
* - "evaltime" is the frame at which F-Curve is being evaluated
* - has to return a float value
*/
-float evaluate_driver(ChannelDriver *driver, const float evaltime)
+float evaluate_driver(PathResolvedRNA *anim_rna, ChannelDriver *driver, const float evaltime)
{
DriverVar *dvar;
@@ -1944,7 +1944,9 @@ float evaluate_driver(ChannelDriver *driver, const float evaltime)
* - on errors it reports, then returns 0.0f
*/
BLI_mutex_lock(&python_driver_lock);
- driver->curval = BPY_driver_exec(driver, evaltime);
+
+ driver->curval = BPY_driver_exec(anim_rna, driver, evaltime);
+
BLI_mutex_unlock(&python_driver_lock);
}
#else /* WITH_PYTHON*/
@@ -2599,25 +2601,64 @@ static float fcurve_eval_samples(FCurve *fcu, FPoint *fpts, float evaltime)
/* Evaluate and return the value of the given F-Curve at the specified frame ("evaltime")
* Note: this is also used for drivers
*/
-float evaluate_fcurve(FCurve *fcu, float evaltime)
+static float evaluate_fcurve_ex(FCurve *fcu, float evaltime, float cvalue)
{
FModifierStackStorage *storage;
- float cvalue = 0.0f;
float devaltime;
+
+ /* evaluate modifiers which modify time to evaluate the base curve at */
+ storage = evaluate_fmodifiers_storage_new(&fcu->modifiers);
+ devaltime = evaluate_time_fmodifiers(storage, &fcu->modifiers, fcu, cvalue, evaltime);
+
+ /* evaluate curve-data
+ * - 'devaltime' instead of 'evaltime', as this is the time that the last time-modifying
+ * F-Curve modifier on the stack requested the curve to be evaluated at
+ */
+ if (fcu->bezt)
+ cvalue = fcurve_eval_keyframes(fcu, fcu->bezt, devaltime);
+ else if (fcu->fpt)
+ cvalue = fcurve_eval_samples(fcu, fcu->fpt, devaltime);
- /* if there is a driver (only if this F-Curve is acting as 'driver'), evaluate it to find value to use as "evaltime"
+ /* evaluate modifiers */
+ evaluate_value_fmodifiers(storage, &fcu->modifiers, fcu, &cvalue, devaltime);
+
+ evaluate_fmodifiers_storage_free(storage);
+
+ /* if curve can only have integral values, perform truncation (i.e. drop the decimal part)
+ * here so that the curve can be sampled correctly
+ */
+ if (fcu->flag & FCURVE_INT_VALUES)
+ cvalue = floorf(cvalue + 0.5f);
+
+ /* return evaluated value */
+ return cvalue;
+}
+
+float evaluate_fcurve(FCurve *fcu, float evaltime)
+{
+ BLI_assert(fcu->driver == NULL);
+
+ return evaluate_fcurve_ex(fcu, evaltime, 0.0);
+}
+
+float evaluate_fcurve_driver(PathResolvedRNA *anim_rna, FCurve *fcu, float evaltime)
+{
+ BLI_assert(fcu->driver != NULL);
+ float cvalue = 0.0f;
+
+ /* if there is a driver (only if this F-Curve is acting as 'driver'), evaluate it to find value to use as "evaltime"
* since drivers essentially act as alternative input (i.e. in place of 'time') for F-Curves
*/
if (fcu->driver) {
/* evaltime now serves as input for the curve */
- evaltime = evaluate_driver(fcu->driver, evaltime);
-
+ evaltime = evaluate_driver(anim_rna, fcu->driver, evaltime);
+
/* only do a default 1-1 mapping if it's unlikely that anything else will set a value... */
if (fcu->totvert == 0) {
FModifier *fcm;
bool do_linear = true;
-
- /* out-of-range F-Modifiers will block, as will those which just plain overwrite the values
+
+ /* out-of-range F-Modifiers will block, as will those which just plain overwrite the values
* XXX: additive is a bit more dicey; it really depends then if things are in range or not...
*/
for (fcm = fcu->modifiers.first; fcm; fcm = fcm->next) {
@@ -2634,7 +2675,7 @@ float evaluate_fcurve(FCurve *fcu, float evaltime)
do_linear = false;
}
}
-
+
/* only copy over results if none of the modifiers disagreed with this */
if (do_linear) {
cvalue = evaltime;
@@ -2642,36 +2683,11 @@ float evaluate_fcurve(FCurve *fcu, float evaltime)
}
}
- /* evaluate modifiers which modify time to evaluate the base curve at */
- storage = evaluate_fmodifiers_storage_new(&fcu->modifiers);
- devaltime = evaluate_time_fmodifiers(storage, &fcu->modifiers, fcu, cvalue, evaltime);
-
- /* evaluate curve-data
- * - 'devaltime' instead of 'evaltime', as this is the time that the last time-modifying
- * F-Curve modifier on the stack requested the curve to be evaluated at
- */
- if (fcu->bezt)
- cvalue = fcurve_eval_keyframes(fcu, fcu->bezt, devaltime);
- else if (fcu->fpt)
- cvalue = fcurve_eval_samples(fcu, fcu->fpt, devaltime);
-
- /* evaluate modifiers */
- evaluate_value_fmodifiers(storage, &fcu->modifiers, fcu, &cvalue, devaltime);
-
- evaluate_fmodifiers_storage_free(storage);
-
- /* if curve can only have integral values, perform truncation (i.e. drop the decimal part)
- * here so that the curve can be sampled correctly
- */
- if (fcu->flag & FCURVE_INT_VALUES)
- cvalue = floorf(cvalue + 0.5f);
-
- /* return evaluated value */
- return cvalue;
+ return evaluate_fcurve_ex(fcu, evaltime, cvalue);
}
/* Calculate the value of the given F-Curve at the given frame, and set its curval */
-void calculate_fcurve(FCurve *fcu, float ctime)
+float calculate_fcurve(PathResolvedRNA *anim_rna, FCurve *fcu, float evaltime)
{
/* only calculate + set curval (overriding the existing value) if curve has
* any data which warrants this...
@@ -2680,7 +2696,18 @@ void calculate_fcurve(FCurve *fcu, float ctime)
list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE))
{
/* calculate and set curval (evaluates driver too if necessary) */
- fcu->curval = evaluate_fcurve(fcu, ctime);
+ float curval;
+ if (fcu->driver) {
+ curval = evaluate_fcurve_driver(anim_rna, fcu, evaltime);
+ }
+ else {
+ curval = evaluate_fcurve(fcu, evaltime);
+ }
+ fcu->curval = curval; /* debug display only, not thread safe! */
+ return curval;
+ }
+ else {
+ return 0.0f;
}
}
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c
index aed33d2c64d..580842fe176 100644
--- a/source/blender/blenkernel/intern/font.c
+++ b/source/blender/blenkernel/intern/font.c
@@ -95,10 +95,9 @@ void BKE_vfont_free_data(struct VFont *vfont)
}
}
+/** Free (or release) any data used by this font (does not free the font itself). */
void BKE_vfont_free(struct VFont *vf)
{
- if (vf == NULL) return;
-
BKE_vfont_free_data(vf);
if (vf->packedfile) {
@@ -310,6 +309,11 @@ VFont *BKE_vfont_load_exists(struct Main *bmain, const char *filepath)
return BKE_vfont_load_exists_ex(bmain, filepath, NULL);
}
+void BKE_vfont_make_local(Main *bmain, VFont *vfont, const bool lib_local)
+{
+ BKE_id_make_local_generic(bmain, &vfont->id, true, lib_local);
+}
+
static VFont *which_vfont(Curve *cu, CharInfo *info)
{
switch (info->flag & (CU_CHINFO_BOLD | CU_CHINFO_ITALIC)) {
@@ -541,7 +545,7 @@ int BKE_vfont_select_get(Object *ob, int *r_start, int *r_end)
BLI_assert(ef->len >= 0);
BLI_assert(ef->selstart >= 0 && ef->selstart <= ef->len + 1);
- BLI_assert(ef->selend >= 0 && ef->selend <= ef->len);
+ BLI_assert(ef->selend >= 0 && ef->selend <= ef->len + 1);
BLI_assert(ef->pos >= 0 && ef->pos <= ef->len);
if (ef->selstart == 0) {
@@ -628,6 +632,8 @@ bool BKE_vfont_to_curve_ex(Main *bmain, Object *ob, int mode, ListBase *r_nubase
bool use_textbox;
VChar *che;
struct CharTrans *chartransdata = NULL, *ct;
+ /* Text at the beginning of the last used text-box (use for y-axis alignment). */
+ int i_textbox = 0;
struct TempLineInfo *lineinfo;
float *f, xof, yof, xtrax, linedist;
float twidth, maxlen = 0;
@@ -830,6 +836,7 @@ makebreak:
(cu->totbox > (curbox + 1)) &&
((-(yof - tb_scale.y)) > (tb_scale.h - linedist) - yof_scale))
{
+ i_textbox = i + 1;
maxlen = 0;
curbox++;
@@ -908,10 +915,10 @@ makebreak:
/* linedata is now: width of line */
- if (cu->spacemode != CU_LEFT) {
+ if (cu->spacemode != CU_ALIGN_X_LEFT) {
ct = chartransdata;
- if (cu->spacemode == CU_RIGHT) {
+ if (cu->spacemode == CU_ALIGN_X_RIGHT) {
struct TempLineInfo *li;
for (i = 0, li = lineinfo; i < lnr; i++, li++) {
@@ -923,7 +930,7 @@ makebreak:
ct++;
}
}
- else if (cu->spacemode == CU_MIDDLE) {
+ else if (cu->spacemode == CU_ALIGN_X_MIDDLE) {
struct TempLineInfo *li;
for (i = 0, li = lineinfo; i < lnr; i++, li++) {
@@ -935,7 +942,7 @@ makebreak:
ct++;
}
}
- else if ((cu->spacemode == CU_FLUSH) && use_textbox) {
+ else if ((cu->spacemode == CU_ALIGN_X_FLUSH) && use_textbox) {
struct TempLineInfo *li;
for (i = 0, li = lineinfo; i < lnr; i++, li++) {
@@ -956,7 +963,7 @@ makebreak:
ct++;
}
}
- else if ((cu->spacemode == CU_JUSTIFY) && use_textbox) {
+ else if ((cu->spacemode == CU_ALIGN_X_JUSTIFY) && use_textbox) {
float curofs = 0.0f;
for (i = 0; i <= slen; i++) {
for (j = i;
@@ -983,6 +990,60 @@ makebreak:
}
}
+ /* top-baseline is default, in this case, do nothing */
+ if (cu->align_y != CU_ALIGN_Y_TOP_BASELINE) {
+ if (tb_scale.h != 0.0f) {
+ /* top and top-baseline are the same when text-boxes are used */
+ if (cu->align_y != CU_ALIGN_Y_TOP && i_textbox < slen) {
+ /* all previous textboxes are 'full', only align the last used text-box */
+ float yoff;
+ int lines;
+ struct CharTrans *ct_last, *ct_textbox;
+
+ ct_last = chartransdata + slen - 1;
+ ct_textbox = chartransdata + i_textbox;
+
+ lines = ct_last->linenr - ct_textbox->linenr + 1;
+ if (mem[slen - 1] == '\n') {
+ lines++;
+ }
+
+ if (cu->align_y == CU_ALIGN_Y_BOTTOM) {
+ yoff = (lines * linedist) - tb_scale.h;
+ }
+ else if (cu->align_y == CU_ALIGN_Y_CENTER) {
+ yoff = 0.5f * ((lines * linedist) - tb_scale.h);
+ }
+
+ ct = ct_textbox;
+ for (i = i_textbox - 1; i < slen; i++) {
+ ct->yof += yoff;
+ ct++;
+ }
+ }
+ }
+ else {
+ /* non text-box case handled separately */
+ ct = chartransdata;
+ float yoff;
+
+ if (cu->align_y == CU_ALIGN_Y_TOP) {
+ yoff = -linedist;
+ }
+ else if (cu->align_y == CU_ALIGN_Y_BOTTOM) {
+ yoff = (lnr - 1.0f) * linedist;
+ }
+ else if (cu->align_y == CU_ALIGN_Y_CENTER) {
+ yoff = (lnr - 2.0f) * linedist * 0.5f;
+ }
+
+ for (i = 0; i <= slen; i++) {
+ ct->yof += yoff;
+ ct++;
+ }
+ }
+ }
+
MEM_freeN(lineinfo);
/* TEXT ON CURVE */
@@ -1021,13 +1082,13 @@ makebreak:
/* path longer than text: spacemode involves */
distfac = 1.0f / distfac;
- if (cu->spacemode == CU_RIGHT) {
+ if (cu->spacemode == CU_ALIGN_X_RIGHT) {
timeofs = 1.0f - distfac;
}
- else if (cu->spacemode == CU_MIDDLE) {
+ else if (cu->spacemode == CU_ALIGN_X_MIDDLE) {
timeofs = (1.0f - distfac) / 2.0f;
}
- else if (cu->spacemode == CU_FLUSH) {
+ else if (cu->spacemode == CU_ALIGN_X_FLUSH) {
distfac = 1.0f;
}
}
diff --git a/source/blender/blenkernel/intern/freestyle.c b/source/blender/blenkernel/intern/freestyle.c
index 3a15be5a09d..21fc1674dc5 100644
--- a/source/blender/blenkernel/intern/freestyle.c
+++ b/source/blender/blenkernel/intern/freestyle.c
@@ -151,22 +151,14 @@ bool BKE_freestyle_module_delete(FreestyleConfig *config, FreestyleModuleConfig
return true;
}
-bool BKE_freestyle_module_move_up(FreestyleConfig *config, FreestyleModuleConfig *module_conf)
-{
- if (BLI_findindex(&config->modules, module_conf) == -1)
- return false;
- BLI_remlink(&config->modules, module_conf);
- BLI_insertlinkbefore(&config->modules, module_conf->prev, module_conf);
- return true;
-}
-
-bool BKE_freestyle_module_move_down(FreestyleConfig *config, FreestyleModuleConfig *module_conf)
+/**
+ * Reinsert \a module_conf offset by \a direction from current position.
+ * \return if position of \a module_conf changed.
+ */
+bool BKE_freestyle_module_move(FreestyleConfig *config, FreestyleModuleConfig *module_conf, int direction)
{
- if (BLI_findindex(&config->modules, module_conf) == -1)
- return false;
- BLI_remlink(&config->modules, module_conf);
- BLI_insertlinkafter(&config->modules, module_conf->next, module_conf);
- return true;
+ return ((BLI_findindex(&config->modules, module_conf) > -1) &&
+ (BLI_listbase_link_move(&config->modules, module_conf, direction) == true));
}
void BKE_freestyle_lineset_unique_name(FreestyleConfig *config, FreestyleLineSet *lineset)
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index f3eb5430bce..2242113b79b 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -18,7 +18,7 @@
* The Original Code is Copyright (C) 2008, Blender Foundation
* This is a new part of Blender
*
- * Contributor(s): Joshua Leung
+ * Contributor(s): Joshua Leung, Antonio Vazquez
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -44,11 +44,14 @@
#include "DNA_gpencil_types.h"
#include "DNA_userdef_types.h"
+#include "DNA_scene_types.h"
#include "BKE_animsys.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
+#include "BKE_colortools.h"
#include "BKE_library.h"
+#include "BKE_main.h"
/* ************************************************** */
@@ -56,79 +59,155 @@
/* --------- Memory Management ------------ */
+/* free stroke, doesn't unlink from any listbase */
+void BKE_gpencil_free_stroke(bGPDstroke *gps)
+{
+ if (gps == NULL) {
+ return;
+ }
+
+ /* free stroke memory arrays, then stroke itself */
+ if (gps->points)
+ MEM_freeN(gps->points);
+ if (gps->triangles)
+ MEM_freeN(gps->triangles);
+
+ MEM_freeN(gps);
+}
+
/* Free strokes belonging to a gp-frame */
-bool free_gpencil_strokes(bGPDframe *gpf)
+bool BKE_gpencil_free_strokes(bGPDframe *gpf)
{
- bGPDstroke *gps, *gpsn;
+ bGPDstroke *gps_next;
bool changed = (BLI_listbase_is_empty(&gpf->strokes) == false);
/* free strokes */
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
-
- /* free stroke memory arrays, then stroke itself */
- if (gps->points) MEM_freeN(gps->points);
- if (gps->triangles) MEM_freeN(gps->triangles);
- BLI_freelinkN(&gpf->strokes, gps);
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps_next) {
+ gps_next = gps->next;
+ BKE_gpencil_free_stroke(gps);
}
+ BLI_listbase_clear(&gpf->strokes);
return changed;
}
/* Free all of a gp-layer's frames */
-void free_gpencil_frames(bGPDlayer *gpl)
+void BKE_gpencil_free_frames(bGPDlayer *gpl)
{
- bGPDframe *gpf, *gpfn;
+ bGPDframe *gpf_next;
/* error checking */
if (gpl == NULL) return;
/* free frames */
- for (gpf = gpl->frames.first; gpf; gpf = gpfn) {
- gpfn = gpf->next;
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf_next) {
+ gpf_next = gpf->next;
/* free strokes and their associated memory */
- free_gpencil_strokes(gpf);
+ BKE_gpencil_free_strokes(gpf);
BLI_freelinkN(&gpl->frames, gpf);
}
gpl->actframe = NULL;
}
+/* Free all of a gp-colors */
+static void free_gpencil_colors(bGPDpalette *palette)
+{
+ /* error checking */
+ if (palette == NULL) {
+ return;
+ }
+
+ /* free colors */
+ BLI_freelistN(&palette->colors);
+}
+
+/* Free all of the gp-palettes and colors */
+void BKE_gpencil_free_palettes(ListBase *list)
+{
+ bGPDpalette *palette_next;
+
+ /* error checking */
+ if (list == NULL) {
+ return;
+ }
+
+ /* delete palettes */
+ for (bGPDpalette *palette = list->first; palette; palette = palette_next) {
+ palette_next = palette->next;
+ /* free palette colors */
+ free_gpencil_colors(palette);
+
+ MEM_freeN(palette);
+ }
+ BLI_listbase_clear(list);
+}
+
+/* Free all of the gp-brushes for a viewport (list should be &gpd->brushes or so) */
+void BKE_gpencil_free_brushes(ListBase *list)
+{
+ bGPDbrush *brush_next;
+
+ /* error checking */
+ if (list == NULL) {
+ return;
+ }
+
+ /* delete brushes */
+ for (bGPDbrush *brush = list->first; brush; brush = brush_next) {
+ brush_next = brush->next;
+ /* free curves */
+ if (brush->cur_sensitivity) {
+ curvemapping_free(brush->cur_sensitivity);
+ }
+ if (brush->cur_strength) {
+ curvemapping_free(brush->cur_strength);
+ }
+ if (brush->cur_jitter) {
+ curvemapping_free(brush->cur_jitter);
+ }
+
+ MEM_freeN(brush);
+ }
+ BLI_listbase_clear(list);
+}
+
/* Free all of the gp-layers for a viewport (list should be &gpd->layers or so) */
-void free_gpencil_layers(ListBase *list)
+void BKE_gpencil_free_layers(ListBase *list)
{
- bGPDlayer *gpl, *gpln;
+ bGPDlayer *gpl_next;
/* error checking */
if (list == NULL) return;
/* delete layers */
- for (gpl = list->first; gpl; gpl = gpln) {
- gpln = gpl->next;
+ for (bGPDlayer *gpl = list->first; gpl; gpl = gpl_next) {
+ gpl_next = gpl->next;
/* free layers and their data */
- free_gpencil_frames(gpl);
+ BKE_gpencil_free_frames(gpl);
BLI_freelinkN(list, gpl);
}
}
-/* Free all of GPencil datablock's related data, but not the block itself */
-void BKE_gpencil_free(bGPdata *gpd)
+/** Free (or release) any data used by this grease pencil (does not free the gpencil itself). */
+void BKE_gpencil_free(bGPdata *gpd, bool free_palettes)
{
+ BKE_animdata_free(&gpd->id, false);
+
/* free layers */
- free_gpencil_layers(&gpd->layers);
-
- /* free animation data */
- if (gpd->adt) {
- BKE_animdata_free(&gpd->id);
- gpd->adt = NULL;
+ BKE_gpencil_free_layers(&gpd->layers);
+
+ /* free palettes */
+ if (free_palettes) {
+ BKE_gpencil_free_palettes(&gpd->palettes);
}
}
/* -------- Container Creation ---------- */
/* add a new gp-frame to the given layer */
-bGPDframe *gpencil_frame_addnew(bGPDlayer *gpl, int cframe)
+bGPDframe *BKE_gpencil_frame_addnew(bGPDlayer *gpl, int cframe)
{
bGPDframe *gpf = NULL, *gf = NULL;
short state = 0;
@@ -180,9 +259,9 @@ bGPDframe *gpencil_frame_addnew(bGPDlayer *gpl, int cframe)
}
/* add a copy of the active gp-frame to the given layer */
-bGPDframe *gpencil_frame_addcopy(bGPDlayer *gpl, int cframe)
+bGPDframe *BKE_gpencil_frame_addcopy(bGPDlayer *gpl, int cframe)
{
- bGPDframe *new_frame, *gpf;
+ bGPDframe *new_frame;
bool found = false;
/* Error checking/handling */
@@ -192,14 +271,14 @@ bGPDframe *gpencil_frame_addcopy(bGPDlayer *gpl, int cframe)
}
else if (gpl->actframe == NULL) {
/* no active frame, so just create a new one from scratch */
- return gpencil_frame_addnew(gpl, cframe);
+ return BKE_gpencil_frame_addnew(gpl, cframe);
}
/* Create a copy of the frame */
- new_frame = gpencil_frame_duplicate(gpl->actframe);
+ new_frame = BKE_gpencil_frame_duplicate(gpl->actframe);
/* Find frame to insert it before */
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
if (gpf->framenum > cframe) {
/* Add it here */
BLI_insertlinkbefore(&gpl->frames, gpf, new_frame);
@@ -211,7 +290,7 @@ bGPDframe *gpencil_frame_addcopy(bGPDlayer *gpl, int cframe)
/* This only happens when we're editing with framelock on...
* - Delete the new frame and don't do anything else here...
*/
- free_gpencil_strokes(new_frame);
+ BKE_gpencil_free_strokes(new_frame);
MEM_freeN(new_frame);
new_frame = NULL;
@@ -235,7 +314,7 @@ bGPDframe *gpencil_frame_addcopy(bGPDlayer *gpl, int cframe)
}
/* add a new gp-layer and make it the active layer */
-bGPDlayer *gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setactive)
+bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setactive)
{
bGPDlayer *gpl;
@@ -251,8 +330,11 @@ bGPDlayer *gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setactive)
/* set basic settings */
copy_v4_v4(gpl->color, U.gpencil_new_layer_col);
- gpl->thickness = 3;
-
+ /* Since GPv2 thickness must be 0 */
+ gpl->thickness = 0;
+
+ gpl->opacity = 1.0f;
+
/* onion-skinning settings */
if (gpd->flag & GP_DATA_SHOW_ONIONSKINS)
gpl->flag |= GP_LAYER_ONIONSKIN;
@@ -265,23 +347,280 @@ bGPDlayer *gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setactive)
/* high quality fill by default */
gpl->flag |= GP_LAYER_HQ_FILL;
- /* default smooth iterations */
- gpl->draw_smoothlvl = 1;
-
/* auto-name */
BLI_strncpy(gpl->info, name, sizeof(gpl->info));
BLI_uniquename(&gpd->layers, gpl, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl->info));
/* make this one the active one */
if (setactive)
- gpencil_layer_setactive(gpd, gpl);
+ BKE_gpencil_layer_setactive(gpd, gpl);
/* return layer */
return gpl;
}
+/* add a new gp-palette and make it the active */
+bGPDpalette *BKE_gpencil_palette_addnew(bGPdata *gpd, const char *name, bool setactive)
+{
+ bGPDpalette *palette;
+
+ /* check that list is ok */
+ if (gpd == NULL) {
+ return NULL;
+ }
+
+ /* allocate memory and add to end of list */
+ palette = MEM_callocN(sizeof(bGPDpalette), "bGPDpalette");
+
+ /* add to datablock */
+ BLI_addtail(&gpd->palettes, palette);
+
+ /* set basic settings */
+ /* auto-name */
+ BLI_strncpy(palette->info, name, sizeof(palette->info));
+ BLI_uniquename(&gpd->palettes, palette, DATA_("GP_Palette"), '.', offsetof(bGPDpalette, info),
+ sizeof(palette->info));
+
+ /* make this one the active one */
+ if (setactive) {
+ BKE_gpencil_palette_setactive(gpd, palette);
+ }
+
+ /* return palette */
+ return palette;
+}
+
+/* create a set of default drawing brushes with predefined presets */
+void BKE_gpencil_brush_init_presets(ToolSettings *ts)
+{
+ bGPDbrush *brush;
+ /* Basic brush */
+ brush = BKE_gpencil_brush_addnew(ts, "Basic", true);
+ brush->thickness = 3.0f;
+ brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE;
+ brush->draw_sensitivity = 1.0f;
+ brush->flag |= GP_BRUSH_USE_PRESSURE;
+
+ brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
+ brush->draw_strength = 1.0f;
+ brush->flag |= ~GP_BRUSH_USE_STENGTH_PRESSURE;
+
+ brush->draw_random_press = 0.0f;
+
+ brush->draw_jitter = 0.0f;
+ brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ brush->draw_angle = 0.0f;
+ brush->draw_angle_factor = 0.0f;
+
+ brush->draw_smoothfac = 0.0f;
+ brush->draw_smoothlvl = 1;
+ brush->sublevel = 0;
+ brush->draw_random_sub = 0.0f;
+
+ /* Pencil brush */
+ brush = BKE_gpencil_brush_addnew(ts, "Pencil", false);
+ brush->thickness = 7.0f;
+ brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE;
+ brush->draw_sensitivity = 1.0f;
+ brush->flag |= GP_BRUSH_USE_PRESSURE;
+
+ brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
+ brush->draw_strength = 0.7f;
+ brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+
+ brush->draw_random_press = 0.0f;
+
+ brush->draw_jitter = 0.0f;
+ brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ brush->draw_angle = 0.0f;
+ brush->draw_angle_factor = 0.0f;
+
+ brush->draw_smoothfac = 1.0f;
+ brush->draw_smoothlvl = 2;
+ brush->sublevel = 2;
+ brush->draw_random_sub = 0.0f;
+
+ /* Ink brush */
+ brush = BKE_gpencil_brush_addnew(ts, "Ink", false);
+ brush->thickness = 7.0f;
+ brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE;
+ brush->draw_sensitivity = 1.6f;
+ brush->flag |= GP_BRUSH_USE_PRESSURE;
+
+ brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
+ brush->draw_strength = 1.0f;
+ brush->flag &= ~GP_BRUSH_USE_STENGTH_PRESSURE;
+
+ brush->draw_random_press = 0.0f;
+
+ brush->draw_jitter = 0.0f;
+ brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ brush->draw_angle = 0.0f;
+ brush->draw_angle_factor = 0.0f;
+
+ brush->draw_smoothfac = 1.1f;
+ brush->draw_smoothlvl = 2;
+ brush->sublevel = 2;
+ brush->draw_random_sub = 0.0f;
+
+ /* Ink Noise brush */
+ brush = BKE_gpencil_brush_addnew(ts, "Ink noise", false);
+ brush->thickness = 6.0f;
+ brush->flag |= GP_BRUSH_USE_RANDOM_PRESSURE;
+ brush->draw_sensitivity = 1.611f;
+ brush->flag |= GP_BRUSH_USE_PRESSURE;
+
+ brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
+ brush->draw_strength = 1.0f;
+ brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+
+ brush->draw_random_press = 1.0f;
+
+ brush->draw_jitter = 0.0f;
+ brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ brush->draw_angle = 0.0f;
+ brush->draw_angle_factor = 0.0f;
+
+ brush->draw_smoothfac = 1.1f;
+ brush->draw_smoothlvl = 2;
+ brush->sublevel = 2;
+ brush->draw_random_sub = 0.0f;
+
+ /* Marker brush */
+ brush = BKE_gpencil_brush_addnew(ts, "Marker", false);
+ brush->thickness = 10.0f;
+ brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE;
+ brush->draw_sensitivity = 2.0f;
+ brush->flag &= ~GP_BRUSH_USE_PRESSURE;
+
+ brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
+ brush->draw_strength = 1.0f;
+ brush->flag &= ~GP_BRUSH_USE_STENGTH_PRESSURE;
+
+ brush->draw_random_press = 0.0f;
+
+ brush->draw_jitter = 0.0f;
+ brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ brush->draw_angle = M_PI_4; /* 45 degrees */
+ brush->draw_angle_factor = 1.0f;
+
+ brush->draw_smoothfac = 1.0f;
+ brush->draw_smoothlvl = 2;
+ brush->sublevel = 2;
+ brush->draw_random_sub = 0.0f;
+
+ /* Crayon brush */
+ brush = BKE_gpencil_brush_addnew(ts, "Crayon", false);
+ brush->thickness = 10.0f;
+ brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE;
+ brush->draw_sensitivity = 3.0f;
+ brush->flag &= ~GP_BRUSH_USE_PRESSURE;
+
+ brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
+ brush->draw_strength = 0.140f;
+ brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+
+ brush->draw_random_press = 0.0f;
+
+ brush->draw_jitter = 0.0f;
+ brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ brush->draw_angle = 0.0f;
+ brush->draw_angle_factor = 0.0f;
+
+ brush->draw_smoothfac = 0.0f;
+ brush->draw_smoothlvl = 1;
+ brush->sublevel = 2;
+ brush->draw_random_sub = 0.5f;
+
+}
+
+/* add a new gp-brush and make it the active */
+bGPDbrush *BKE_gpencil_brush_addnew(ToolSettings *ts, const char *name, bool setactive)
+{
+ bGPDbrush *brush;
+
+ /* check that list is ok */
+ if (ts == NULL) {
+ return NULL;
+ }
+
+ /* allocate memory and add to end of list */
+ brush = MEM_callocN(sizeof(bGPDbrush), "bGPDbrush");
+
+ /* add to datablock */
+ BLI_addtail(&ts->gp_brushes, brush);
+
+ /* set basic settings */
+ brush->thickness = 3;
+ brush->draw_smoothlvl = 1;
+ brush->flag |= GP_BRUSH_USE_PRESSURE;
+ brush->draw_sensitivity = 1.0f;
+ brush->draw_strength = 1.0f;
+ brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+ brush->draw_jitter = 0.0f;
+ brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ /* curves */
+ brush->cur_sensitivity = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ brush->cur_strength = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ brush->cur_jitter = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+
+ /* auto-name */
+ BLI_strncpy(brush->info, name, sizeof(brush->info));
+ BLI_uniquename(&ts->gp_brushes, brush, DATA_("GP_Brush"), '.', offsetof(bGPDbrush, info), sizeof(brush->info));
+
+ /* make this one the active one */
+ if (setactive) {
+ BKE_gpencil_brush_setactive(ts, brush);
+ }
+
+ /* return brush */
+ return brush;
+}
+
+/* add a new gp-palettecolor and make it the active */
+bGPDpalettecolor *BKE_gpencil_palettecolor_addnew(bGPDpalette *palette, const char *name, bool setactive)
+{
+ bGPDpalettecolor *palcolor;
+
+ /* check that list is ok */
+ if (palette == NULL) {
+ return NULL;
+ }
+
+ /* allocate memory and add to end of list */
+ palcolor = MEM_callocN(sizeof(bGPDpalettecolor), "bGPDpalettecolor");
+
+ /* add to datablock */
+ BLI_addtail(&palette->colors, palcolor);
+
+ /* set basic settings */
+ palcolor->flag |= PC_COLOR_HQ_FILL;
+ copy_v4_v4(palcolor->color, U.gpencil_new_layer_col);
+ ARRAY_SET_ITEMS(palcolor->fill, 1.0f, 1.0f, 1.0f);
+
+ /* auto-name */
+ BLI_strncpy(palcolor->info, name, sizeof(palcolor->info));
+ BLI_uniquename(&palette->colors, palcolor, DATA_("Color"), '.', offsetof(bGPDpalettecolor, info),
+ sizeof(palcolor->info));
+
+ /* make this one the active one */
+ if (setactive) {
+ BKE_gpencil_palettecolor_setactive(palette, palcolor);
+ }
+
+ /* return palette color */
+ return palcolor;
+}
+
/* add a new gp-datablock */
-bGPdata *gpencil_data_addnew(const char name[])
+bGPdata *BKE_gpencil_data_addnew(const char name[])
{
bGPdata *gpd;
@@ -302,100 +641,168 @@ bGPdata *gpencil_data_addnew(const char name[])
/* -------- Data Duplication ---------- */
/* make a copy of a given gpencil frame */
-bGPDframe *gpencil_frame_duplicate(bGPDframe *src)
+bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src)
{
- bGPDstroke *gps, *gpsd;
- bGPDframe *dst;
+ bGPDstroke *gps_dst;
+ bGPDframe *gpf_dst;
/* error checking */
- if (src == NULL)
+ if (gpf_src == NULL) {
return NULL;
+ }
/* make a copy of the source frame */
- dst = MEM_dupallocN(src);
- dst->prev = dst->next = NULL;
+ gpf_dst = MEM_dupallocN(gpf_src);
+ gpf_dst->prev = gpf_dst->next = NULL;
/* copy strokes */
- BLI_listbase_clear(&dst->strokes);
- for (gps = src->strokes.first; gps; gps = gps->next) {
+ BLI_listbase_clear(&gpf_dst->strokes);
+ for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) {
/* make copy of source stroke, then adjust pointer to points too */
- gpsd = MEM_dupallocN(gps);
- gpsd->points = MEM_dupallocN(gps->points);
- gpsd->triangles = MEM_dupallocN(gps->triangles);
- gpsd->flag |= GP_STROKE_RECALC_CACHES;
- BLI_addtail(&dst->strokes, gpsd);
+ gps_dst = MEM_dupallocN(gps_src);
+ gps_dst->points = MEM_dupallocN(gps_src->points);
+ gps_dst->triangles = MEM_dupallocN(gps_src->triangles);
+ gps_dst->flag |= GP_STROKE_RECALC_CACHES;
+ BLI_addtail(&gpf_dst->strokes, gps_dst);
}
/* return new frame */
- return dst;
+ return gpf_dst;
}
+/* make a copy of a given gpencil brush */
+bGPDbrush *BKE_gpencil_brush_duplicate(const bGPDbrush *brush_src)
+{
+ bGPDbrush *brush_dst;
+
+ /* error checking */
+ if (brush_src == NULL) {
+ return NULL;
+ }
+
+ /* make a copy of source brush */
+ brush_dst = MEM_dupallocN(brush_src);
+ brush_dst->prev = brush_dst->next = NULL;
+ /* make a copy of curves */
+ brush_dst->cur_sensitivity = curvemapping_copy(brush_src->cur_sensitivity);
+ brush_dst->cur_strength = curvemapping_copy(brush_src->cur_strength);
+ brush_dst->cur_jitter = curvemapping_copy(brush_src->cur_jitter);
+
+ /* return new brush */
+ return brush_dst;
+}
+
+/* make a copy of a given gpencil palette */
+bGPDpalette *BKE_gpencil_palette_duplicate(const bGPDpalette *palette_src)
+{
+ bGPDpalette *palette_dst;
+ const bGPDpalettecolor *palcolor_src;
+ bGPDpalettecolor *palcolord_dst;
+
+ /* error checking */
+ if (palette_src == NULL) {
+ return NULL;
+ }
+
+ /* make a copy of source palette */
+ palette_dst = MEM_dupallocN(palette_src);
+ palette_dst->prev = palette_dst->next = NULL;
+
+ /* copy colors */
+ BLI_listbase_clear(&palette_dst->colors);
+ for (palcolor_src = palette_src->colors.first; palcolor_src; palcolor_src = palcolor_src->next) {
+ /* make a copy of source */
+ palcolord_dst = MEM_dupallocN(palcolor_src);
+ BLI_addtail(&palette_dst->colors, palcolord_dst);
+ }
+
+ /* return new palette */
+ return palette_dst;
+}
/* make a copy of a given gpencil layer */
-bGPDlayer *gpencil_layer_duplicate(bGPDlayer *src)
+bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src)
{
- bGPDframe *gpf, *gpfd;
- bGPDlayer *dst;
+ const bGPDframe *gpf_src;
+ bGPDframe *gpf_dst;
+ bGPDlayer *gpl_dst;
/* error checking */
- if (src == NULL)
+ if (gpl_src == NULL) {
return NULL;
+ }
/* make a copy of source layer */
- dst = MEM_dupallocN(src);
- dst->prev = dst->next = NULL;
+ gpl_dst = MEM_dupallocN(gpl_src);
+ gpl_dst->prev = gpl_dst->next = NULL;
/* copy frames */
- BLI_listbase_clear(&dst->frames);
- for (gpf = src->frames.first; gpf; gpf = gpf->next) {
+ BLI_listbase_clear(&gpl_dst->frames);
+ for (gpf_src = gpl_src->frames.first; gpf_src; gpf_src = gpf_src->next) {
/* make a copy of source frame */
- gpfd = gpencil_frame_duplicate(gpf);
- BLI_addtail(&dst->frames, gpfd);
+ gpf_dst = BKE_gpencil_frame_duplicate(gpf_src);
+ BLI_addtail(&gpl_dst->frames, gpf_dst);
/* if source frame was the current layer's 'active' frame, reassign that too */
- if (gpf == dst->actframe)
- dst->actframe = gpfd;
+ if (gpf_src == gpl_dst->actframe)
+ gpl_dst->actframe = gpf_dst;
}
/* return new layer */
- return dst;
+ return gpl_dst;
}
/* make a copy of a given gpencil datablock */
-bGPdata *gpencil_data_duplicate(bGPdata *src, bool internal_copy)
+bGPdata *BKE_gpencil_data_duplicate(Main *bmain, bGPdata *gpd_src, bool internal_copy)
{
- bGPDlayer *gpl, *gpld;
- bGPdata *dst;
-
+ const bGPDlayer *gpl_src;
+ bGPDlayer *gpl_dst;
+ bGPdata *gpd_dst;
+
/* error checking */
- if (src == NULL)
+ if (gpd_src == NULL) {
return NULL;
+ }
/* make a copy of the base-data */
if (internal_copy) {
/* make a straight copy for undo buffers used during stroke drawing */
- dst = MEM_dupallocN(src);
+ gpd_dst = MEM_dupallocN(gpd_src);
}
else {
/* make a copy when others use this */
- dst = BKE_libblock_copy(&src->id);
+ gpd_dst = BKE_libblock_copy(bmain, &gpd_src->id);
}
/* copy layers */
- BLI_listbase_clear(&dst->layers);
- for (gpl = src->layers.first; gpl; gpl = gpl->next) {
+ BLI_listbase_clear(&gpd_dst->layers);
+ for (gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) {
/* make a copy of source layer and its data */
- gpld = gpencil_layer_duplicate(gpl);
- BLI_addtail(&dst->layers, gpld);
+ gpl_dst = BKE_gpencil_layer_duplicate(gpl_src);
+ BLI_addtail(&gpd_dst->layers, gpl_dst);
+ }
+ if (!internal_copy) {
+ /* copy palettes */
+ bGPDpalette *palette_src, *palette_dst;
+ BLI_listbase_clear(&gpd_dst->palettes);
+ for (palette_src = gpd_src->palettes.first; palette_src; palette_src = palette_src->next) {
+ palette_dst = BKE_gpencil_palette_duplicate(palette_src);
+ BLI_addtail(&gpd_dst->palettes, palette_dst);
+ }
}
/* return new */
- return dst;
+ return gpd_dst;
+}
+
+void BKE_gpencil_make_local(Main *bmain, bGPdata *gpd, const bool lib_local)
+{
+ BKE_id_make_local_generic(bmain, &gpd->id, true, lib_local);
}
/* -------- GP-Stroke API --------- */
/* ensure selection status of stroke is in sync with its points */
-void gpencil_stroke_sync_selection(bGPDstroke *gps)
+void BKE_gpencil_stroke_sync_selection(bGPDstroke *gps)
{
bGPDspoint *pt;
int i;
@@ -420,7 +827,7 @@ void gpencil_stroke_sync_selection(bGPDstroke *gps)
/* -------- GP-Frame API ---------- */
/* delete the last stroke of the given frame */
-void gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf)
+void BKE_gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf)
{
bGPDstroke *gps = (gpf) ? gpf->strokes.last : NULL;
int cfra = (gpf) ? gpf->framenum : 0; /* assume that the current frame was not locked */
@@ -436,8 +843,8 @@ void gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf)
/* if frame has no strokes after this, delete it */
if (BLI_listbase_is_empty(&gpf->strokes)) {
- gpencil_layer_delframe(gpl, gpf);
- gpencil_layer_getframe(gpl, cfra, 0);
+ BKE_gpencil_layer_delframe(gpl, gpf);
+ BKE_gpencil_layer_getframe(gpl, cfra, 0);
}
}
@@ -455,7 +862,7 @@ bool gpencil_layer_is_editable(const bGPDlayer *gpl)
/* Opacity must be sufficiently high that it is still "visible"
* Otherwise, it's not really "visible" to the user, so no point editing...
*/
- if ((gpl->color[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gpl->fill[3] > GPENCIL_ALPHA_OPACITY_THRESH)) {
+ if (gpl->opacity > GPENCIL_ALPHA_OPACITY_THRESH) {
return true;
}
}
@@ -485,7 +892,7 @@ bGPDframe *BKE_gpencil_layer_find_frame(bGPDlayer *gpl, int cframe)
* - this sets the layer's actframe var (if allowed to)
* - extension beyond range (if first gp-frame is after all frame in interest and cannot add)
*/
-bGPDframe *gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew)
+bGPDframe *BKE_gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew)
{
bGPDframe *gpf = NULL;
short found = 0;
@@ -524,9 +931,9 @@ bGPDframe *gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode
if ((found) && (gpf->framenum == cframe))
gpl->actframe = gpf;
else if (addnew == GP_GETFRAME_ADD_COPY)
- gpl->actframe = gpencil_frame_addcopy(gpl, cframe);
+ gpl->actframe = BKE_gpencil_frame_addcopy(gpl, cframe);
else
- gpl->actframe = gpencil_frame_addnew(gpl, cframe);
+ gpl->actframe = BKE_gpencil_frame_addnew(gpl, cframe);
}
else if (found)
gpl->actframe = gpf;
@@ -546,9 +953,9 @@ bGPDframe *gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode
if ((found) && (gpf->framenum == cframe))
gpl->actframe = gpf;
else if (addnew == GP_GETFRAME_ADD_COPY)
- gpl->actframe = gpencil_frame_addcopy(gpl, cframe);
+ gpl->actframe = BKE_gpencil_frame_addcopy(gpl, cframe);
else
- gpl->actframe = gpencil_frame_addnew(gpl, cframe);
+ gpl->actframe = BKE_gpencil_frame_addnew(gpl, cframe);
}
else if (found)
gpl->actframe = gpf;
@@ -585,7 +992,7 @@ bGPDframe *gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode
if ((found) && (gpf->framenum == cframe))
gpl->actframe = gpf;
else
- gpl->actframe = gpencil_frame_addnew(gpl, cframe);
+ gpl->actframe = BKE_gpencil_frame_addnew(gpl, cframe);
}
else if (found)
gpl->actframe = gpf;
@@ -598,7 +1005,7 @@ bGPDframe *gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode
else {
/* currently no frames (add if allowed to) */
if (addnew)
- gpl->actframe = gpencil_frame_addnew(gpl, cframe);
+ gpl->actframe = BKE_gpencil_frame_addnew(gpl, cframe);
else {
/* don't do anything... this may be when no frames yet! */
/* gpl->actframe should still be NULL */
@@ -610,7 +1017,7 @@ bGPDframe *gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode
}
/* delete the given frame from a layer */
-bool gpencil_layer_delframe(bGPDlayer *gpl, bGPDframe *gpf)
+bool BKE_gpencil_layer_delframe(bGPDlayer *gpl, bGPDframe *gpf)
{
bool changed = false;
@@ -627,14 +1034,14 @@ bool gpencil_layer_delframe(bGPDlayer *gpl, bGPDframe *gpf)
gpl->actframe = NULL;
/* free the frame and its data */
- changed = free_gpencil_strokes(gpf);
+ changed = BKE_gpencil_free_strokes(gpf);
BLI_freelinkN(&gpl->frames, gpf);
return changed;
}
/* get the active gp-layer for editing */
-bGPDlayer *gpencil_layer_getactive(bGPdata *gpd)
+bGPDlayer *BKE_gpencil_layer_getactive(bGPdata *gpd)
{
bGPDlayer *gpl;
@@ -653,7 +1060,7 @@ bGPDlayer *gpencil_layer_getactive(bGPdata *gpd)
}
/* set the active gp-layer */
-void gpencil_layer_setactive(bGPdata *gpd, bGPDlayer *active)
+void BKE_gpencil_layer_setactive(bGPdata *gpd, bGPDlayer *active)
{
bGPDlayer *gpl;
@@ -670,15 +1077,255 @@ void gpencil_layer_setactive(bGPdata *gpd, bGPDlayer *active)
}
/* delete the active gp-layer */
-void gpencil_layer_delete(bGPdata *gpd, bGPDlayer *gpl)
+void BKE_gpencil_layer_delete(bGPdata *gpd, bGPDlayer *gpl)
{
/* error checking */
if (ELEM(NULL, gpd, gpl))
return;
/* free layer */
- free_gpencil_frames(gpl);
+ BKE_gpencil_free_frames(gpl);
BLI_freelinkN(&gpd->layers, gpl);
}
/* ************************************************** */
+/* get the active gp-brush for editing */
+bGPDbrush *BKE_gpencil_brush_getactive(ToolSettings *ts)
+{
+ bGPDbrush *brush;
+
+ /* error checking */
+ if (ELEM(NULL, ts, ts->gp_brushes.first)) {
+ return NULL;
+ }
+
+ /* loop over brushes until found (assume only one active) */
+ for (brush = ts->gp_brushes.first; brush; brush = brush->next) {
+ if (brush->flag & GP_BRUSH_ACTIVE) {
+ return brush;
+ }
+ }
+
+ /* no active brush found */
+ return NULL;
+}
+
+/* set the active gp-brush */
+void BKE_gpencil_brush_setactive(ToolSettings *ts, bGPDbrush *active)
+{
+ bGPDbrush *brush;
+
+ /* error checking */
+ if (ELEM(NULL, ts, ts->gp_brushes.first, active)) {
+ return;
+ }
+
+ /* loop over brushes deactivating all */
+ for (brush = ts->gp_brushes.first; brush; brush = brush->next) {
+ brush->flag &= ~GP_BRUSH_ACTIVE;
+ }
+
+ /* set as active one */
+ active->flag |= GP_BRUSH_ACTIVE;
+}
+
+/* delete the active gp-brush */
+void BKE_gpencil_brush_delete(ToolSettings *ts, bGPDbrush *brush)
+{
+ /* error checking */
+ if (ELEM(NULL, ts, brush)) {
+ return;
+ }
+
+ /* free curves */
+ if (brush->cur_sensitivity) {
+ curvemapping_free(brush->cur_sensitivity);
+ }
+ if (brush->cur_strength) {
+ curvemapping_free(brush->cur_strength);
+ }
+ if (brush->cur_jitter) {
+ curvemapping_free(brush->cur_jitter);
+ }
+
+ /* free */
+ BLI_freelinkN(&ts->gp_brushes, brush);
+}
+
+/* ************************************************** */
+/* get the active gp-palette for editing */
+bGPDpalette *BKE_gpencil_palette_getactive(bGPdata *gpd)
+{
+ bGPDpalette *palette;
+
+ /* error checking */
+ if (ELEM(NULL, gpd, gpd->palettes.first)) {
+ return NULL;
+ }
+
+ /* loop over palettes until found (assume only one active) */
+ for (palette = gpd->palettes.first; palette; palette = palette->next) {
+ if (palette->flag & PL_PALETTE_ACTIVE)
+ return palette;
+ }
+
+ /* no active palette found */
+ return NULL;
+}
+
+/* set the active gp-palette */
+void BKE_gpencil_palette_setactive(bGPdata *gpd, bGPDpalette *active)
+{
+ bGPDpalette *palette;
+
+ /* error checking */
+ if (ELEM(NULL, gpd, gpd->palettes.first, active)) {
+ return;
+ }
+
+ /* loop over palettes deactivating all */
+ for (palette = gpd->palettes.first; palette; palette = palette->next) {
+ palette->flag &= ~PL_PALETTE_ACTIVE;
+ }
+
+ /* set as active one */
+ active->flag |= PL_PALETTE_ACTIVE;
+ /* force color recalc */
+ BKE_gpencil_palette_change_strokes(gpd);
+}
+
+/* delete the active gp-palette */
+void BKE_gpencil_palette_delete(bGPdata *gpd, bGPDpalette *palette)
+{
+ /* error checking */
+ if (ELEM(NULL, gpd, palette)) {
+ return;
+ }
+
+ /* free colors */
+ free_gpencil_colors(palette);
+ BLI_freelinkN(&gpd->palettes, palette);
+ /* force color recalc */
+ BKE_gpencil_palette_change_strokes(gpd);
+}
+
+/* Set all strokes to recalc the palette color */
+void BKE_gpencil_palette_change_strokes(bGPdata *gpd)
+{
+ bGPDlayer *gpl;
+ bGPDframe *gpf;
+ bGPDstroke *gps;
+
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ gps->flag |= GP_STROKE_RECALC_COLOR;
+ }
+ }
+ }
+}
+
+
+/* get the active gp-palettecolor for editing */
+bGPDpalettecolor *BKE_gpencil_palettecolor_getactive(bGPDpalette *palette)
+{
+ bGPDpalettecolor *palcolor;
+
+ /* error checking */
+ if (ELEM(NULL, palette, palette->colors.first)) {
+ return NULL;
+ }
+
+ /* loop over colors until found (assume only one active) */
+ for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+ if (palcolor->flag & PC_COLOR_ACTIVE) {
+ return palcolor;
+ }
+ }
+
+ /* no active color found */
+ return NULL;
+}
+/* get the gp-palettecolor looking for name */
+bGPDpalettecolor *BKE_gpencil_palettecolor_getbyname(bGPDpalette *palette, char *name)
+{
+ /* error checking */
+ if (ELEM(NULL, palette, name)) {
+ return NULL;
+ }
+
+ return BLI_findstring(&palette->colors, name, offsetof(bGPDpalettecolor, info));
+}
+
+/* Change color name in all strokes */
+void BKE_gpencil_palettecolor_changename(bGPdata *gpd, char *oldname, const char *newname)
+{
+ bGPDlayer *gpl;
+ bGPDframe *gpf;
+ bGPDstroke *gps;
+
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ if (STREQ(gps->colorname, oldname)) {
+ BLI_strncpy(gps->colorname, newname, sizeof(gps->colorname));
+ }
+ }
+ }
+ }
+
+}
+
+/* Delete all strokes of the color */
+void BKE_gpencil_palettecolor_delete_strokes(struct bGPdata *gpd, char *name)
+{
+ bGPDlayer *gpl;
+ bGPDframe *gpf;
+ bGPDstroke *gps, *gpsn;
+
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+
+ if (STREQ(gps->colorname, name)) {
+ if (gps->points) MEM_freeN(gps->points);
+ if (gps->triangles) MEM_freeN(gps->triangles);
+ BLI_freelinkN(&gpf->strokes, gps);
+ }
+ }
+ }
+ }
+
+}
+
+/* set the active gp-palettecolor */
+void BKE_gpencil_palettecolor_setactive(bGPDpalette *palette, bGPDpalettecolor *active)
+{
+ bGPDpalettecolor *palcolor;
+
+ /* error checking */
+ if (ELEM(NULL, palette, palette->colors.first, active)) {
+ return;
+ }
+
+ /* loop over colors deactivating all */
+ for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+ palcolor->flag &= ~PC_COLOR_ACTIVE;
+ }
+
+ /* set as active one */
+ active->flag |= PC_COLOR_ACTIVE;
+}
+
+/* delete the active gp-palettecolor */
+void BKE_gpencil_palettecolor_delete(bGPDpalette *palette, bGPDpalettecolor *palcolor)
+{
+ /* error checking */
+ if (ELEM(NULL, palette, palcolor)) {
+ return;
+ }
+
+ /* free */
+ BLI_freelinkN(&palette->colors, palcolor);
+}
diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c
index a44eb1df9fe..9b011dbb003 100644
--- a/source/blender/blenkernel/intern/group.c
+++ b/source/blender/blenkernel/intern/group.c
@@ -60,79 +60,19 @@ static void free_group_object(GroupObject *go)
MEM_freeN(go);
}
-
+/** Free (or release) any data used by this group (does not free the group itself). */
void BKE_group_free(Group *group)
{
/* don't free group itself */
GroupObject *go;
- BKE_previewimg_free(&group->preview);
+ /* No animdata here. */
while ((go = BLI_pophead(&group->gobject))) {
free_group_object(go);
}
-}
-void BKE_group_unlink(Main *bmain, Group *group)
-{
- Material *ma;
- Object *ob;
- Scene *sce;
- SceneRenderLayer *srl;
- ParticleSystem *psys;
-
- for (ma = bmain->mat.first; ma; ma = ma->id.next) {
- if (ma->group == group)
- ma->group = NULL;
- }
- for (ma = bmain->mat.first; ma; ma = ma->id.next) {
- if (ma->group == group)
- ma->group = NULL;
- }
- for (sce = bmain->scene.first; sce; sce = sce->id.next) {
- Base *base = sce->base.first;
-
- /* ensure objects are not in this group */
- for (; base; base = base->next) {
- if (BKE_group_object_unlink(group, base->object, sce, base) &&
- BKE_group_object_find(NULL, base->object) == NULL)
- {
- base->object->flag &= ~OB_FROMGROUP;
- base->flag &= ~OB_FROMGROUP;
- }
- }
-
- for (srl = sce->r.layers.first; srl; srl = srl->next) {
- FreestyleLineSet *lineset;
-
- if (srl->light_override == group)
- srl->light_override = NULL;
- for (lineset = srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
- if (lineset->group == group)
- lineset->group = NULL;
- }
- }
- }
-
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
-
- if (ob->dup_group == group) {
- ob->dup_group = NULL;
- }
-
- for (psys = ob->particlesystem.first; psys; psys = psys->next) {
- if (psys->part->dup_group == group)
- psys->part->dup_group = NULL;
-#if 0 /* not used anymore, only keps for readfile.c, no need to account for this */
- if (psys->part->eff_group == group)
- psys->part->eff_group = NULL;
-#endif
- }
- }
-
- /* group stays in library, but no members */
- BKE_group_free(group);
- group->id.us = 0;
+ BKE_previewimg_free(&group->preview);
}
Group *BKE_group_add(Main *bmain, const char *name)
@@ -147,23 +87,26 @@ Group *BKE_group_add(Main *bmain, const char *name)
return group;
}
-Group *BKE_group_copy(Group *group)
+Group *BKE_group_copy(Main *bmain, Group *group)
{
Group *groupn;
- groupn = BKE_libblock_copy(&group->id);
+ groupn = BKE_libblock_copy(bmain, &group->id);
BLI_duplicatelist(&groupn->gobject, &group->gobject);
/* Do not copy group's preview (same behavior as for objects). */
groupn->preview = NULL;
- if (group->id.lib) {
- BKE_id_lib_local_paths(G.main, group->id.lib, &groupn->id);
- }
+ BKE_id_copy_ensure_local(bmain, &group->id, &groupn->id);
return groupn;
}
+void BKE_group_make_local(Main *bmain, Group *group, const bool lib_local)
+{
+ BKE_id_make_local_generic(bmain, &group->id, true, lib_local);
+}
+
/* external */
static bool group_object_add_internal(Group *group, Object *ob)
{
diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c
index f3e86b44459..7669c4ba112 100644
--- a/source/blender/blenkernel/intern/icons.c
+++ b/source/blender/blenkernel/intern/icons.c
@@ -143,7 +143,7 @@ static PreviewImage *previewimg_create_ex(size_t deferred_data_size)
memset(prv_img, 0, sizeof(*prv_img)); /* leave deferred data dirty */
if (deferred_data_size) {
- prv_img->use_deferred = true;
+ prv_img->tag |= PRV_TAG_DEFFERED;
}
for (i = 0; i < NUM_ICON_SIZES; ++i) {
@@ -221,6 +221,24 @@ PreviewImage *BKE_previewimg_copy(PreviewImage *prv)
return prv_img;
}
+/** Duplicate preview image from \a id and clear icon_id, to be used by datablock copy functions. */
+void BKE_previewimg_id_copy(ID *new_id, ID *old_id)
+{
+ PreviewImage **old_prv_p = BKE_previewimg_id_get_p(old_id);
+ PreviewImage **new_prv_p = BKE_previewimg_id_get_p(new_id);
+
+ if (old_prv_p && *old_prv_p) {
+ BLI_assert(new_prv_p != NULL && ELEM(*new_prv_p, NULL, *old_prv_p));
+// const int new_icon_id = get_next_free_id();
+
+// if (new_icon_id == 0) {
+// return; /* Failure. */
+// }
+ *new_prv_p = BKE_previewimg_copy(*old_prv_p);
+ new_id->icon_id = (*new_prv_p)->icon_id = 0;
+ }
+}
+
PreviewImage **BKE_previewimg_id_get_p(ID *id)
{
switch (GS(id->name)) {
@@ -337,11 +355,14 @@ PreviewImage *BKE_previewimg_cached_thumbnail_read(
return prv;
}
-void BKE_previewimg_cached_release(const char *name)
+void BKE_previewimg_cached_release_pointer(PreviewImage *prv)
{
- PreviewImage *prv = BLI_ghash_popkey(gCachedPreviews, name, MEM_freeN);
-
if (prv) {
+ if (prv->tag & PRV_TAG_DEFFERED_RENDERING) {
+ /* We cannot delete the preview while it is being loaded in another thread... */
+ prv->tag |= PRV_TAG_DEFFERED_DELETE;
+ return;
+ }
if (prv->icon_id) {
BKE_icon_delete(prv->icon_id);
}
@@ -349,11 +370,18 @@ void BKE_previewimg_cached_release(const char *name)
}
}
+void BKE_previewimg_cached_release(const char *name)
+{
+ PreviewImage *prv = BLI_ghash_popkey(gCachedPreviews, name, MEM_freeN);
+
+ BKE_previewimg_cached_release_pointer(prv);
+}
+
/** Handle deferred (lazy) loading/generation of preview image, if needed.
* For now, only used with file thumbnails. */
void BKE_previewimg_ensure(PreviewImage *prv, const int size)
{
- if (prv->use_deferred) {
+ if ((prv->tag & PRV_TAG_DEFFERED) != 0) {
const bool do_icon = ((size == ICON_SIZE_ICON) && !prv->rect[ICON_SIZE_ICON]);
const bool do_preview = ((size == ICON_SIZE_PREVIEW) && !prv->rect[ICON_SIZE_PREVIEW]);
@@ -423,10 +451,26 @@ void BKE_icon_changed(int id)
}
}
-int BKE_icon_id_ensure(struct ID *id)
+static int icon_id_ensure_create_icon(struct ID *id)
{
Icon *new_icon = NULL;
+ new_icon = MEM_mallocN(sizeof(Icon), __func__);
+
+ new_icon->obj = id;
+ new_icon->type = GS(id->name);
+
+ /* next two lines make sure image gets created */
+ new_icon->drawinfo = NULL;
+ new_icon->drawinfo_free = NULL;
+
+ BLI_ghash_insert(gIcons, SET_INT_IN_POINTER(id->icon_id), new_icon);
+
+ return id->icon_id;
+}
+
+int BKE_icon_id_ensure(struct ID *id)
+{
if (!id || G.background)
return 0;
@@ -440,32 +484,39 @@ int BKE_icon_id_ensure(struct ID *id)
return 0;
}
- new_icon = MEM_mallocN(sizeof(Icon), __func__);
-
- new_icon->obj = id;
- new_icon->type = GS(id->name);
-
- /* next two lines make sure image gets created */
- new_icon->drawinfo = NULL;
- new_icon->drawinfo_free = NULL;
+ /* Ensure we synchronize ID icon_id with its previewimage if it has one. */
+ PreviewImage **p_prv = BKE_previewimg_id_get_p(id);
+ if (p_prv && *p_prv) {
+ BLI_assert(ELEM((*p_prv)->icon_id, 0, id->icon_id));
+ (*p_prv)->icon_id = id->icon_id;
+ }
- BLI_ghash_insert(gIcons, SET_INT_IN_POINTER(id->icon_id), new_icon);
-
- return id->icon_id;
+ return icon_id_ensure_create_icon(id);
}
/**
* Return icon id of given preview, or create new icon if not found.
*/
-int BKE_icon_preview_ensure(PreviewImage *preview)
+int BKE_icon_preview_ensure(ID *id, PreviewImage *preview)
{
Icon *new_icon = NULL;
if (!preview || G.background)
return 0;
- if (preview->icon_id)
+ if (id) {
+ BLI_assert(BKE_previewimg_id_ensure(id) == preview);
+ }
+
+ if (preview->icon_id) {
+ BLI_assert(!id || !id->icon_id || id->icon_id == preview->icon_id);
return preview->icon_id;
+ }
+
+ if (id && id->icon_id) {
+ preview->icon_id = id->icon_id;
+ return preview->icon_id;
+ }
preview->icon_id = get_next_free_id();
@@ -474,6 +525,12 @@ int BKE_icon_preview_ensure(PreviewImage *preview)
return 0;
}
+ /* Ensure we synchronize ID icon_id with its previewimage if available, and generate suitable 'ID' icon. */
+ if (id) {
+ id->icon_id = preview->icon_id;
+ return icon_id_ensure_create_icon(id);
+ }
+
new_icon = MEM_mallocN(sizeof(Icon), __func__);
new_icon->obj = preview;
diff --git a/source/blender/blenkernel/intern/idcode.c b/source/blender/blenkernel/intern/idcode.c
index 68a741bc3fc..70d037d85f3 100644
--- a/source/blender/blenkernel/intern/idcode.c
+++ b/source/blender/blenkernel/intern/idcode.c
@@ -39,6 +39,7 @@
#include "BLT_translation.h"
+#include "BKE_library.h"
#include "BKE_idcode.h"
typedef struct {
@@ -54,14 +55,15 @@ typedef struct {
/* plural need to match rna_main.c's MainCollectionDef */
/* WARNING! Keep it in sync with i18n contexts in BLT_translation.h */
static IDType idtypes[] = {
+ /** ID's directly below must all be in #Main, and be kept in sync with #MAX_LIBARRAY (membership, not order) */
{ ID_AC, "Action", "actions", BLT_I18NCONTEXT_ID_ACTION, IDTYPE_FLAGS_ISLINKABLE },
{ ID_AR, "Armature", "armatures", BLT_I18NCONTEXT_ID_ARMATURE, IDTYPE_FLAGS_ISLINKABLE },
{ ID_BR, "Brush", "brushes", BLT_I18NCONTEXT_ID_BRUSH, IDTYPE_FLAGS_ISLINKABLE },
{ ID_CA, "Camera", "cameras", BLT_I18NCONTEXT_ID_CAMERA, IDTYPE_FLAGS_ISLINKABLE },
+ { ID_CF, "CacheFile", "cache_files", BLT_I18NCONTEXT_ID_CACHEFILE, IDTYPE_FLAGS_ISLINKABLE },
{ ID_CU, "Curve", "curves", BLT_I18NCONTEXT_ID_CURVE, IDTYPE_FLAGS_ISLINKABLE },
{ ID_GD, "GPencil", "grease_pencil", BLT_I18NCONTEXT_ID_GPENCIL, IDTYPE_FLAGS_ISLINKABLE }, /* rename gpencil */
{ ID_GR, "Group", "groups", BLT_I18NCONTEXT_ID_GROUP, IDTYPE_FLAGS_ISLINKABLE },
- { ID_ID, "ID", "ids", BLT_I18NCONTEXT_ID_ID, 0 }, /* plural is fake */
{ ID_IM, "Image", "images", BLT_I18NCONTEXT_ID_IMAGE, IDTYPE_FLAGS_ISLINKABLE },
{ ID_IP, "Ipo", "ipos", "", IDTYPE_FLAGS_ISLINKABLE }, /* deprecated */
{ ID_KE, "Key", "shape_keys", BLT_I18NCONTEXT_ID_SHAPEKEY, 0 },
@@ -89,8 +91,14 @@ static IDType idtypes[] = {
{ ID_VF, "VFont", "fonts", BLT_I18NCONTEXT_ID_VFONT, IDTYPE_FLAGS_ISLINKABLE },
{ ID_WO, "World", "worlds", BLT_I18NCONTEXT_ID_WORLD, IDTYPE_FLAGS_ISLINKABLE },
{ ID_WM, "WindowManager", "window_managers", BLT_I18NCONTEXT_ID_WINDOWMANAGER, 0 },
+
+ /** Keep last, not an ID exactly, only include for completeness */
+ { ID_ID, "ID", "ids", BLT_I18NCONTEXT_ID_ID, 0 }, /* plural is fake */
};
+/* -1 for ID_ID */
+BLI_STATIC_ASSERT((ARRAY_SIZE(idtypes) - 1 == MAX_LIBARRAY), "Missing IDType");
+
static IDType *idtype_from_name(const char *str)
{
int i = ARRAY_SIZE(idtypes);
@@ -117,7 +125,7 @@ static IDType *idtype_from_code(short idcode)
/**
* Return if the ID code is a valid ID code.
*
- * \param code The code to check.
+ * \param idcode: The code to check.
* \return Boolean, 0 when invalid.
*/
bool BKE_idcode_is_valid(short idcode)
@@ -128,7 +136,7 @@ bool BKE_idcode_is_valid(short idcode)
/**
* Return non-zero when an ID type is linkable.
*
- * \param code The code to check.
+ * \param idcode: The code to check.
* \return Boolean, 0 when non linkable.
*/
bool BKE_idcode_is_linkable(short idcode)
@@ -141,7 +149,7 @@ bool BKE_idcode_is_linkable(short idcode)
/**
* Convert an idcode into a name.
*
- * \param code The code to convert.
+ * \param idcode: The code to convert.
* \return A static string representing the name of
* the code.
*/
@@ -177,6 +185,7 @@ int BKE_idcode_to_idfilter(const short idcode)
CASE_IDFILTER(AR);
CASE_IDFILTER(BR);
CASE_IDFILTER(CA);
+ CASE_IDFILTER(CF);
CASE_IDFILTER(CU);
CASE_IDFILTER(GD);
CASE_IDFILTER(GR);
@@ -220,6 +229,7 @@ short BKE_idcode_from_idfilter(const int idfilter)
CASE_IDFILTER(AR);
CASE_IDFILTER(BR);
CASE_IDFILTER(CA);
+ CASE_IDFILTER(CF);
CASE_IDFILTER(CU);
CASE_IDFILTER(GD);
CASE_IDFILTER(GR);
@@ -252,9 +262,59 @@ short BKE_idcode_from_idfilter(const int idfilter)
}
/**
+ * Convert an idcode into an index (e.g. ID_OB -> INDEX_ID_OB).
+ */
+int BKE_idcode_to_index(const short idcode)
+{
+#define CASE_IDINDEX(_id) case ID_##_id: return INDEX_ID_##_id
+
+ switch ((ID_Type)idcode) {
+ CASE_IDINDEX(AC);
+ CASE_IDINDEX(AR);
+ CASE_IDINDEX(BR);
+ CASE_IDINDEX(CA);
+ CASE_IDINDEX(CF);
+ CASE_IDINDEX(CU);
+ CASE_IDINDEX(GD);
+ CASE_IDINDEX(GR);
+ CASE_IDINDEX(IM);
+ CASE_IDINDEX(KE);
+ CASE_IDINDEX(IP);
+ CASE_IDINDEX(LA);
+ CASE_IDINDEX(LI);
+ CASE_IDINDEX(LS);
+ CASE_IDINDEX(LT);
+ CASE_IDINDEX(MA);
+ CASE_IDINDEX(MB);
+ CASE_IDINDEX(MC);
+ CASE_IDINDEX(ME);
+ CASE_IDINDEX(MSK);
+ CASE_IDINDEX(NT);
+ CASE_IDINDEX(OB);
+ CASE_IDINDEX(PA);
+ CASE_IDINDEX(PAL);
+ CASE_IDINDEX(PC);
+ CASE_IDINDEX(SCE);
+ CASE_IDINDEX(SCR);
+ CASE_IDINDEX(SPK);
+ CASE_IDINDEX(SO);
+ CASE_IDINDEX(TE);
+ CASE_IDINDEX(TXT);
+ CASE_IDINDEX(VF);
+ CASE_IDINDEX(WM);
+ CASE_IDINDEX(WO);
+ }
+
+ BLI_assert(0);
+ return -1;
+
+#undef CASE_IDINDEX
+}
+
+/**
* Convert an idcode into a name (plural).
*
- * \param code The code to convert.
+ * \param idcode: The code to convert.
* \return A static string representing the name of
* the code.
*/
@@ -268,7 +328,7 @@ const char *BKE_idcode_to_name_plural(short idcode)
/**
* Convert an idcode into its translations' context.
*
- * \param code The code to convert.
+ * \param idcode: The code to convert.
* \return A static string representing the i18n context of the code.
*/
const char *BKE_idcode_to_translation_context(short idcode)
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c
index 86d010f5f7c..b2641b110f8 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -940,17 +940,18 @@ IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char *
prop->subtype = IDP_STRING_SUB_BYTE;
}
else {
- if (st == NULL) {
+ if (st == NULL || val->string.len <= 1) {
prop->data.pointer = MEM_mallocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1");
*IDP_String(prop) = '\0';
prop->totallen = DEFAULT_ALLOC_FOR_NULL_STRINGS;
prop->len = 1; /*NULL string, has len of 1 to account for null byte.*/
}
else {
- int stlen = (int)strlen(st) + 1;
- prop->data.pointer = MEM_mallocN((size_t)stlen, "id property string 3");
- prop->len = prop->totallen = stlen;
- memcpy(prop->data.pointer, st, (size_t)stlen);
+ BLI_assert((int)val->string.len <= (int)strlen(st) + 1);
+ prop->data.pointer = MEM_mallocN((size_t)val->string.len, "id property string 3");
+ memcpy(prop->data.pointer, st, (size_t)val->string.len - 1);
+ IDP_String(prop)[val->string.len - 1] = '\0';
+ prop->len = prop->totallen = val->string.len;
}
prop->subtype = IDP_STRING_SUB_UTF8;
}
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index d4551fd0b2c..df3a7630bb0 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -72,6 +72,8 @@
#include "BKE_icons.h"
#include "BKE_image.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_packedFile.h"
#include "BKE_report.h"
@@ -95,8 +97,6 @@
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
-#include "WM_api.h"
-
static SpinLock image_spin;
/* prototypes */
@@ -109,8 +109,8 @@ static void image_add_view(Image *ima, const char *viewname, const char *filepat
#define IMA_NO_INDEX 0x7FEFEFEF
/* quick lookup: supports 1 million frames, thousand passes */
-#define IMA_MAKE_INDEX(frame, index) ((frame) << 10) + index
-#define IMA_INDEX_FRAME(index) (index >> 10)
+#define IMA_MAKE_INDEX(frame, index) (((frame) << 10) + (index))
+#define IMA_INDEX_FRAME(index) ((index) >> 10)
/*
#define IMA_INDEX_PASS(index) (index & ~1023)
*/
@@ -324,20 +324,16 @@ void BKE_image_free_buffers(Image *ima)
ima->ok = IMA_OK;
}
-/* called by library too, do not free ima itself */
+/** Free (or release) any data used by this image (does not free the image itself). */
void BKE_image_free(Image *ima)
{
int a;
+ /* Also frees animdata. */
BKE_image_free_buffers(ima);
image_free_packedfiles(ima);
- BKE_icon_id_delete(&ima->id);
- ima->id.icon_id = 0;
-
- BKE_previewimg_free(&ima->preview);
-
for (a = 0; a < IMA_MAX_RENDER_SLOT; a++) {
if (ima->renders[a]) {
RE_FreeRenderResult(ima->renders[a]);
@@ -346,7 +342,10 @@ void BKE_image_free(Image *ima)
}
BKE_image_free_views(ima);
- MEM_freeN(ima->stereo3d_format);
+ MEM_SAFE_FREE(ima->stereo3d_format);
+
+ BKE_icon_id_delete(&ima->id);
+ BKE_previewimg_free(&ima->preview);
}
/* only image block itself */
@@ -437,6 +436,7 @@ static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src)
Image *BKE_image_copy(Main *bmain, Image *ima)
{
Image *nima = image_alloc(bmain, ima->id.name + 2, ima->source, ima->type);
+ ima->id.newid = &nima->id;
BLI_strncpy(nima->name, ima->name, sizeof(ima->name));
@@ -457,178 +457,20 @@ Image *BKE_image_copy(Main *bmain, Image *ima)
copy_image_packedfiles(&nima->packedfiles, &ima->packedfiles);
- nima->stereo3d_format = MEM_dupallocN(ima->stereo3d_format);
+ /* nima->stere3d_format is already allocated by image_alloc... */
+ *nima->stereo3d_format = *ima->stereo3d_format;
BLI_duplicatelist(&nima->views, &ima->views);
- if (ima->id.lib) {
- BKE_id_lib_local_paths(bmain, ima->id.lib, &nima->id);
- }
+ BKE_previewimg_id_copy(&nima->id, &ima->id);
+
+ BKE_id_copy_ensure_local(bmain, &ima->id, &nima->id);
return nima;
}
-static void extern_local_image(Image *UNUSED(ima))
+void BKE_image_make_local(Main *bmain, Image *ima, const bool lib_local)
{
- /* Nothing to do: images don't link to other IDs. This function exists to
- * match id_make_local pattern. */
-}
-
-void BKE_image_make_local(struct Image *ima)
-{
- Main *bmain = G.main;
- Tex *tex;
- Brush *brush;
- Mesh *me;
- bool is_local = false, is_lib = false;
-
- /* - only lib users: do nothing
- * - only local users: set flag
- * - mixed: make copy
- */
-
- if (ima->id.lib == NULL) return;
-
- /* Can't take short cut here: must check meshes at least because of bogus
- * texface ID refs. - z0r */
-#if 0
- if (ima->id.us == 1) {
- id_clear_lib_data(bmain, &ima->id);
- extern_local_image(ima);
- return;
- }
-#endif
-
- for (tex = bmain->tex.first; tex; tex = tex->id.next) {
- if (tex->ima == ima) {
- if (tex->id.lib) is_lib = true;
- else is_local = true;
- }
- }
- for (brush = bmain->brush.first; brush; brush = brush->id.next) {
- if (brush->clone.image == ima) {
- if (brush->id.lib) is_lib = true;
- else is_local = true;
- }
- }
- for (me = bmain->mesh.first; me; me = me->id.next) {
- if (me->mtface) {
- MTFace *tface;
- int a, i;
-
- for (i = 0; i < me->fdata.totlayer; i++) {
- if (me->fdata.layers[i].type == CD_MTFACE) {
- tface = (MTFace *)me->fdata.layers[i].data;
-
- for (a = 0; a < me->totface; a++, tface++) {
- if (tface->tpage == ima) {
- if (me->id.lib) is_lib = true;
- else is_local = true;
- }
- }
- }
- }
- }
-
- if (me->mtpoly) {
- MTexPoly *mtpoly;
- int a, i;
-
- for (i = 0; i < me->pdata.totlayer; i++) {
- if (me->pdata.layers[i].type == CD_MTEXPOLY) {
- mtpoly = (MTexPoly *)me->pdata.layers[i].data;
-
- for (a = 0; a < me->totpoly; a++, mtpoly++) {
- if (mtpoly->tpage == ima) {
- if (me->id.lib) is_lib = true;
- else is_local = true;
- }
- }
- }
- }
- }
-
- }
-
- if (is_local && is_lib == false) {
- id_clear_lib_data(bmain, &ima->id);
- extern_local_image(ima);
- }
- else if (is_local && is_lib) {
- Image *ima_new = BKE_image_copy(bmain, ima);
-
- ima_new->id.us = 0;
-
- /* Remap paths of new ID using old library as base. */
- BKE_id_lib_local_paths(bmain, ima->id.lib, &ima_new->id);
-
- tex = bmain->tex.first;
- while (tex) {
- if (tex->id.lib == NULL) {
- if (tex->ima == ima) {
- tex->ima = ima_new;
- id_us_plus(&ima_new->id);
- id_us_min(&ima->id);
- }
- }
- tex = tex->id.next;
- }
- brush = bmain->brush.first;
- while (brush) {
- if (brush->id.lib == NULL) {
- if (brush->clone.image == ima) {
- brush->clone.image = ima_new;
- id_us_plus(&ima_new->id);
- id_us_min(&ima->id);
- }
- }
- brush = brush->id.next;
- }
- /* Transfer references in texfaces. Texfaces don't add to image ID
- * user count *unless* there are no other users. See
- * readfile.c:lib_link_mtface. */
- me = bmain->mesh.first;
- while (me) {
- if (me->mtface) {
- MTFace *tface;
- int a, i;
-
- for (i = 0; i < me->fdata.totlayer; i++) {
- if (me->fdata.layers[i].type == CD_MTFACE) {
- tface = (MTFace *)me->fdata.layers[i].data;
-
- for (a = 0; a < me->totface; a++, tface++) {
- if (tface->tpage == ima) {
- tface->tpage = ima_new;
- id_us_ensure_real((ID *)ima_new);
- id_lib_extern((ID *)ima_new);
- }
- }
- }
- }
- }
-
- if (me->mtpoly) {
- MTexPoly *mtpoly;
- int a, i;
-
- for (i = 0; i < me->pdata.totlayer; i++) {
- if (me->pdata.layers[i].type == CD_MTEXPOLY) {
- mtpoly = (MTexPoly *)me->pdata.layers[i].data;
-
- for (a = 0; a < me->totpoly; a++, mtpoly++) {
- if (mtpoly->tpage == ima) {
- mtpoly->tpage = ima_new;
- id_us_ensure_real((ID *)ima_new);
- id_lib_extern((ID *)ima_new);
- }
- }
- }
- }
- }
-
- me = me->id.next;
- }
- }
+ BKE_id_make_local_generic(bmain, &ima->id, true, lib_local);
}
void BKE_image_merge(Image *dest, Image *source)
@@ -1215,43 +1057,55 @@ int BKE_image_imtype_to_ftype(const char imtype, ImbFormatOptions *r_options)
{
memset(r_options, 0, sizeof(*r_options));
- if (imtype == R_IMF_IMTYPE_TARGA)
+ if (imtype == R_IMF_IMTYPE_TARGA) {
return IMB_FTYPE_TGA;
+ }
else if (imtype == R_IMF_IMTYPE_RAWTGA) {
r_options->flag = RAWTGA;
return IMB_FTYPE_TGA;
}
- else if (imtype == R_IMF_IMTYPE_IRIS)
+ else if (imtype == R_IMF_IMTYPE_IRIS) {
return IMB_FTYPE_IMAGIC;
+ }
#ifdef WITH_HDR
- else if (imtype == R_IMF_IMTYPE_RADHDR)
+ else if (imtype == R_IMF_IMTYPE_RADHDR) {
return IMB_FTYPE_RADHDR;
+ }
#endif
else if (imtype == R_IMF_IMTYPE_PNG) {
r_options->quality = 15;
return IMB_FTYPE_PNG;
}
#ifdef WITH_DDS
- else if (imtype == R_IMF_IMTYPE_DDS)
+ else if (imtype == R_IMF_IMTYPE_DDS) {
return IMB_FTYPE_DDS;
+ }
#endif
- else if (imtype == R_IMF_IMTYPE_BMP)
+ else if (imtype == R_IMF_IMTYPE_BMP) {
return IMB_FTYPE_BMP;
+ }
#ifdef WITH_TIFF
- else if (imtype == R_IMF_IMTYPE_TIFF)
+ else if (imtype == R_IMF_IMTYPE_TIFF) {
return IMB_FTYPE_TIF;
+ }
#endif
- else if (imtype == R_IMF_IMTYPE_OPENEXR || imtype == R_IMF_IMTYPE_MULTILAYER)
+ else if (imtype == R_IMF_IMTYPE_OPENEXR || imtype == R_IMF_IMTYPE_MULTILAYER) {
return IMB_FTYPE_OPENEXR;
+ }
#ifdef WITH_CINEON
- else if (imtype == R_IMF_IMTYPE_CINEON)
+ else if (imtype == R_IMF_IMTYPE_CINEON) {
return IMB_FTYPE_CINEON;
- else if (imtype == R_IMF_IMTYPE_DPX)
+ }
+ else if (imtype == R_IMF_IMTYPE_DPX) {
return IMB_FTYPE_DPX;
+ }
#endif
#ifdef WITH_OPENJPEG
- else if (imtype == R_IMF_IMTYPE_JP2)
+ else if (imtype == R_IMF_IMTYPE_JP2) {
+ r_options->flag |= JP2_JP2;
+ r_options->quality = 90;
return IMB_FTYPE_JP2;
+ }
#endif
else {
r_options->quality = 90;
@@ -1261,46 +1115,60 @@ int BKE_image_imtype_to_ftype(const char imtype, ImbFormatOptions *r_options)
char BKE_image_ftype_to_imtype(const int ftype, const ImbFormatOptions *options)
{
- if (ftype == 0)
+ if (ftype == 0) {
return R_IMF_IMTYPE_TARGA;
- else if (ftype == IMB_FTYPE_IMAGIC)
+ }
+ else if (ftype == IMB_FTYPE_IMAGIC) {
return R_IMF_IMTYPE_IRIS;
+ }
#ifdef WITH_HDR
- else if (ftype == IMB_FTYPE_RADHDR)
+ else if (ftype == IMB_FTYPE_RADHDR) {
return R_IMF_IMTYPE_RADHDR;
+ }
#endif
- else if (ftype == IMB_FTYPE_PNG)
+ else if (ftype == IMB_FTYPE_PNG) {
return R_IMF_IMTYPE_PNG;
+ }
#ifdef WITH_DDS
- else if (ftype == IMB_FTYPE_DDS)
+ else if (ftype == IMB_FTYPE_DDS) {
return R_IMF_IMTYPE_DDS;
+ }
#endif
- else if (ftype == IMB_FTYPE_BMP)
+ else if (ftype == IMB_FTYPE_BMP) {
return R_IMF_IMTYPE_BMP;
+ }
#ifdef WITH_TIFF
- else if (ftype == IMB_FTYPE_TIF)
+ else if (ftype == IMB_FTYPE_TIF) {
return R_IMF_IMTYPE_TIFF;
+ }
#endif
- else if (ftype == IMB_FTYPE_OPENEXR)
+ else if (ftype == IMB_FTYPE_OPENEXR) {
return R_IMF_IMTYPE_OPENEXR;
+ }
#ifdef WITH_CINEON
- else if (ftype == IMB_FTYPE_CINEON)
+ else if (ftype == IMB_FTYPE_CINEON) {
return R_IMF_IMTYPE_CINEON;
- else if (ftype == IMB_FTYPE_DPX)
+ }
+ else if (ftype == IMB_FTYPE_DPX) {
return R_IMF_IMTYPE_DPX;
+ }
#endif
else if (ftype == IMB_FTYPE_TGA) {
- if (options && (options->flag & RAWTGA))
+ if (options && (options->flag & RAWTGA)) {
return R_IMF_IMTYPE_RAWTGA;
- else
+ }
+ else {
return R_IMF_IMTYPE_TARGA;
+ }
}
#ifdef WITH_OPENJPEG
- else if (ftype == IMB_FTYPE_JP2)
+ else if (ftype == IMB_FTYPE_JP2) {
return R_IMF_IMTYPE_JP2;
+ }
#endif
- else
+ else {
return R_IMF_IMTYPE_JPEG90;
+ }
}
@@ -1457,7 +1325,7 @@ char BKE_imtype_from_arg(const char *imtype_arg)
else if (STREQ(imtype_arg, "EXR")) return R_IMF_IMTYPE_OPENEXR;
else if (STREQ(imtype_arg, "MULTILAYER")) return R_IMF_IMTYPE_MULTILAYER;
#endif
- else if (STREQ(imtype_arg, "MPEG")) return R_IMF_IMTYPE_FFMPEG;
+ else if (STREQ(imtype_arg, "FFMPEG")) return R_IMF_IMTYPE_FFMPEG;
else if (STREQ(imtype_arg, "FRAMESERVER")) return R_IMF_IMTYPE_FRAMESERVER;
#ifdef WITH_CINEON
else if (STREQ(imtype_arg, "CINEON")) return R_IMF_IMTYPE_CINEON;
@@ -1712,24 +1580,7 @@ void BKE_imbuf_to_image_format(struct ImageFormatData *im_format, const ImBuf *i
}
/* planes */
- /* TODO(sergey): Channels doesn't correspond actual planes used for image buffer
- * For example byte buffer will have 4 channels but it might easily
- * be BW or RGB image.
- *
- * Need to use im_format->planes = imbuf->planes instead?
- */
- switch (imbuf->channels) {
- case 0:
- case 4: im_format->planes = R_IMF_PLANES_RGBA;
- break;
- case 3: im_format->planes = R_IMF_PLANES_RGB;
- break;
- case 1: im_format->planes = R_IMF_PLANES_BW;
- break;
- default: im_format->planes = R_IMF_PLANES_RGB;
- break;
- }
-
+ im_format->planes = imbuf->planes;
}
@@ -1748,6 +1599,7 @@ typedef struct StampData {
char scene[STAMP_NAME_SIZE];
char strip[STAMP_NAME_SIZE];
char rendertime[STAMP_NAME_SIZE];
+ char memory[STAMP_NAME_SIZE];
} StampData;
#undef STAMP_NAME_SIZE
@@ -1869,6 +1721,13 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d
else {
stamp_data->rendertime[0] = '\0';
}
+
+ if (stats && (scene->r.stamp & R_STAMP_MEMORY)) {
+ BLI_snprintf(stamp_data->memory, sizeof(stamp_data->memory), do_prefix ? "Peak Memory %.2fM" : "%.2fM", stats->mem_peak);
+ }
+ else {
+ stamp_data->memory[0] = '\0';
+ }
}
}
@@ -1943,6 +1802,12 @@ static void stampdata_from_template(StampData *stamp_data,
else {
stamp_data->rendertime[0] = '\0';
}
+ if (scene->r.stamp & R_STAMP_MEMORY) {
+ BLI_snprintf(stamp_data->memory, sizeof(stamp_data->memory), "Peak Memory %s", stamp_data_template->memory);
+ }
+ else {
+ stamp_data->memory[0] = '\0';
+ }
}
void BKE_image_stamp_buf(
@@ -1984,7 +1849,7 @@ void BKE_image_stamp_buf(
display = IMB_colormanagement_display_get_named(display_device);
if (stamp_data_template == NULL) {
- stampdata(scene, camera, &stamp_data, 1);
+ stampdata(scene, camera, &stamp_data, (scene->r.stamp & R_STAMP_HIDE_LABELS) == 0);
}
else {
stampdata_from_template(&stamp_data, scene, stamp_data_template);
@@ -2056,6 +1921,21 @@ void BKE_image_stamp_buf(
}
/* Top left corner, below File, Date, Rendertime */
+ if (TEXT_SIZE_CHECK(stamp_data.memory, w, h)) {
+ y -= h;
+
+ /* and space for background. */
+ buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display,
+ 0, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y);
+
+ BLF_position(mono, x, y + y_ofs, 0.0);
+ BLF_draw_buffer(mono, stamp_data.memory, BLF_DRAW_STR_DUMMY_MAX);
+
+ /* the extra pixel for background. */
+ y -= BUFF_MARGIN_Y * 2;
+ }
+
+ /* Top left corner, below File, Date, Memory, Rendertime */
BLF_enable(mono, BLF_WORD_WRAP);
if (TEXT_SIZE_CHECK_WORD_WRAP(stamp_data.note, w, h)) {
y -= h;
@@ -2219,6 +2099,7 @@ void BKE_stamp_info_callback(void *data, struct StampData *stamp_data, StampCall
CALL(scene, "Scene");
CALL(strip, "Strip");
CALL(rendertime, "RenderTime");
+ CALL(memory, "Memory");
#undef CALL
}
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index 362f41335d2..6cdeaf5e59b 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -58,6 +58,7 @@
#include "BKE_key.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
+#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_editmesh.h"
#include "BKE_scene.h"
@@ -74,11 +75,13 @@
#define IPO_BEZTRIPLE 100
#define IPO_BPOINT 101
+
+/** Free (or release) any data used by this shapekey (does not free the key itself). */
void BKE_key_free(Key *key)
{
KeyBlock *kb;
-
- BKE_animdata_free((ID *)key);
+
+ BKE_animdata_free((ID *)key, false);
while ((kb = BLI_pophead(&key->block))) {
if (kb->data)
@@ -147,14 +150,12 @@ Key *BKE_key_add(ID *id) /* common function */
return key;
}
-Key *BKE_key_copy(Key *key)
+Key *BKE_key_copy(Main *bmain, Key *key)
{
Key *keyn;
KeyBlock *kbn, *kb;
- if (key == NULL) return NULL;
-
- keyn = BKE_libblock_copy(&key->id);
+ keyn = BKE_libblock_copy(bmain, &key->id);
BLI_duplicatelist(&keyn->block, &key->block);
@@ -169,22 +170,16 @@ Key *BKE_key_copy(Key *key)
kb = kb->next;
}
- if (key->id.lib) {
- BKE_id_lib_local_paths(G.main, key->id.lib, &keyn->id);
- }
+ BKE_id_copy_ensure_local(bmain, &key->id, &keyn->id);
return keyn;
}
-
Key *BKE_key_copy_nolib(Key *key)
{
Key *keyn;
KeyBlock *kbn, *kb;
- if (key == NULL)
- return NULL;
-
keyn = MEM_dupallocN(key);
keyn->adt = NULL;
@@ -205,19 +200,6 @@ Key *BKE_key_copy_nolib(Key *key)
return keyn;
}
-void BKE_key_make_local(Key *key)
-{
-
- /* - only lib users: do nothing
- * - only local users: set flag
- * - mixed: make copy
- */
- if (key == NULL) return;
-
- key->id.lib = NULL;
- new_id(NULL, &key->id, NULL);
-}
-
/* Sort shape keys and Ipo curves after a change. This assumes that at most
* one key was moved, which is a valid assumption for the places it's
* currently being called.
diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c
index 49a573489ef..d098366aef4 100644
--- a/source/blender/blenkernel/intern/lamp.c
+++ b/source/blender/blenkernel/intern/lamp.c
@@ -50,6 +50,8 @@
#include "BKE_global.h"
#include "BKE_lamp.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_node.h"
@@ -114,12 +116,12 @@ Lamp *BKE_lamp_add(Main *bmain, const char *name)
return la;
}
-Lamp *BKE_lamp_copy(Lamp *la)
+Lamp *BKE_lamp_copy(Main *bmain, Lamp *la)
{
Lamp *lan;
int a;
- lan = BKE_libblock_copy(&la->id);
+ lan = BKE_libblock_copy(bmain, &la->id);
for (a = 0; a < MAX_MTEX; a++) {
if (lan->mtex[a]) {
@@ -132,14 +134,11 @@ Lamp *BKE_lamp_copy(Lamp *la)
lan->curfalloff = curvemapping_copy(la->curfalloff);
if (la->nodetree)
- lan->nodetree = ntreeCopyTree(la->nodetree);
-
- if (la->preview)
- lan->preview = BKE_previewimg_copy(la->preview);
-
- if (la->id.lib) {
- BKE_id_lib_local_paths(G.main, la->id.lib, &lan->id);
- }
+ lan->nodetree = ntreeCopyTree(bmain, la->nodetree);
+
+ BKE_previewimg_id_copy(&lan->id, &la->id);
+
+ BKE_id_copy_ensure_local(bmain, &la->id, &lan->id);
return lan;
}
@@ -155,8 +154,6 @@ Lamp *localize_lamp(Lamp *la)
if (lan->mtex[a]) {
lan->mtex[a] = MEM_mallocN(sizeof(MTex), "localize_lamp");
memcpy(lan->mtex[a], la->mtex[a], sizeof(MTex));
- /* free lamp decrements */
- id_us_plus((ID *)lan->mtex[a]->tex);
}
}
@@ -166,59 +163,13 @@ Lamp *localize_lamp(Lamp *la)
lan->nodetree = ntreeLocalize(la->nodetree);
lan->preview = NULL;
-
+
return lan;
}
-void BKE_lamp_make_local(Lamp *la)
+void BKE_lamp_make_local(Main *bmain, Lamp *la, const bool lib_local)
{
- Main *bmain = G.main;
- Object *ob;
- bool is_local = false, is_lib = false;
-
- /* - only lib users: do nothing
- * - only local users: set flag
- * - mixed: make copy
- */
-
- if (la->id.lib == NULL) return;
- if (la->id.us == 1) {
- id_clear_lib_data(bmain, &la->id);
- return;
- }
-
- ob = bmain->object.first;
- while (ob) {
- if (ob->data == la) {
- if (ob->id.lib) is_lib = true;
- else is_local = true;
- }
- ob = ob->id.next;
- }
-
- if (is_local && is_lib == false) {
- id_clear_lib_data(bmain, &la->id);
- }
- else if (is_local && is_lib) {
- Lamp *la_new = BKE_lamp_copy(la);
- la_new->id.us = 0;
-
- /* Remap paths of new ID using old library as base. */
- BKE_id_lib_local_paths(bmain, la->id.lib, &la_new->id);
-
- ob = bmain->object.first;
- while (ob) {
- if (ob->data == la) {
-
- if (ob->id.lib == NULL) {
- ob->data = la_new;
- id_us_plus(&la_new->id);
- id_us_min(&la->id);
- }
- }
- ob = ob->id.next;
- }
- }
+ BKE_id_make_local_generic(bmain, &la->id, true, lib_local);
}
void BKE_lamp_free(Lamp *la)
@@ -234,7 +185,7 @@ void BKE_lamp_free(Lamp *la)
MEM_freeN(mtex);
}
- BKE_animdata_free((ID *)la);
+ BKE_animdata_free((ID *)la, false);
curvemapping_free(la->curfalloff);
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index 57c02ec6329..b0671f33094 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -59,6 +59,8 @@
#include "BKE_key.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
@@ -275,15 +277,17 @@ Lattice *BKE_lattice_add(Main *bmain, const char *name)
return lt;
}
-Lattice *BKE_lattice_copy(Lattice *lt)
+Lattice *BKE_lattice_copy(Main *bmain, Lattice *lt)
{
Lattice *ltn;
- ltn = BKE_libblock_copy(&lt->id);
+ ltn = BKE_libblock_copy(bmain, &lt->id);
ltn->def = MEM_dupallocN(lt->def);
- ltn->key = BKE_key_copy(ltn->key);
- if (ltn->key) ltn->key->from = (ID *)ltn;
+ if (lt->key) {
+ ltn->key = BKE_key_copy(bmain, ltn->key);
+ ltn->key->from = (ID *)ltn;
+ }
if (lt->dvert) {
int tot = lt->pntsu * lt->pntsv * lt->pntsw;
@@ -293,79 +297,39 @@ Lattice *BKE_lattice_copy(Lattice *lt)
ltn->editlatt = NULL;
- if (lt->id.lib) {
- BKE_id_lib_local_paths(G.main, lt->id.lib, &ltn->id);
- }
+ BKE_id_copy_ensure_local(bmain, &lt->id, &ltn->id);
return ltn;
}
+/** Free (or release) any data used by this lattice (does not free the lattice itself). */
void BKE_lattice_free(Lattice *lt)
{
- if (lt->def) MEM_freeN(lt->def);
- if (lt->dvert) BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
+ BKE_animdata_free(&lt->id, false);
+
+ MEM_SAFE_FREE(lt->def);
+ if (lt->dvert) {
+ BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
+ lt->dvert = NULL;
+ }
if (lt->editlatt) {
Lattice *editlt = lt->editlatt->latt;
- if (editlt->def) MEM_freeN(editlt->def);
- if (editlt->dvert) BKE_defvert_array_free(editlt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
+ if (editlt->def)
+ MEM_freeN(editlt->def);
+ if (editlt->dvert)
+ BKE_defvert_array_free(editlt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
MEM_freeN(editlt);
MEM_freeN(lt->editlatt);
- }
-
- /* free animation data */
- if (lt->adt) {
- BKE_animdata_free(&lt->id);
- lt->adt = NULL;
+ lt->editlatt = NULL;
}
}
-void BKE_lattice_make_local(Lattice *lt)
+void BKE_lattice_make_local(Main *bmain, Lattice *lt, const bool lib_local)
{
- Main *bmain = G.main;
- Object *ob;
- bool is_local = false, is_lib = false;
-
- /* - only lib users: do nothing
- * - only local users: set flag
- * - mixed: make copy
- */
-
- if (lt->id.lib == NULL) return;
- if (lt->id.us == 1) {
- id_clear_lib_data(bmain, &lt->id);
- return;
- }
-
- for (ob = bmain->object.first; ob && ELEM(false, is_lib, is_local); ob = ob->id.next) {
- if (ob->data == lt) {
- if (ob->id.lib) is_lib = true;
- else is_local = true;
- }
- }
-
- if (is_local && is_lib == false) {
- id_clear_lib_data(bmain, &lt->id);
- }
- else if (is_local && is_lib) {
- Lattice *lt_new = BKE_lattice_copy(lt);
- lt_new->id.us = 0;
-
- /* Remap paths of new ID using old library as base. */
- BKE_id_lib_local_paths(bmain, lt->id.lib, &lt_new->id);
-
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- if (ob->data == lt) {
- if (ob->id.lib == NULL) {
- ob->data = lt_new;
- id_us_plus(&lt_new->id);
- id_us_min(&lt->id);
- }
- }
- }
- }
+ BKE_id_make_local_generic(bmain, &lt->id, true, lib_local);
}
typedef struct LatticeDeformData {
@@ -1082,6 +1046,7 @@ void BKE_lattice_modifiers_calc(Scene *scene, Object *ob)
md->scene = scene;
+ if (!(mti->flags & eModifierTypeFlag_AcceptsLattice)) continue;
if (!(md->mode & eModifierMode_Realtime)) continue;
if (editmode && !(md->mode & eModifierMode_Editmode)) continue;
if (mti->isDisabled && mti->isDisabled(md, 0)) continue;
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 9e81cded9f5..14612151a8e 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -45,6 +45,7 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_brush_types.h"
+#include "DNA_cachefile_types.h"
#include "DNA_camera_types.h"
#include "DNA_group_types.h"
#include "DNA_gpencil_types.h"
@@ -56,6 +57,7 @@
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meta_types.h"
+#include "DNA_modifier_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_mask_types.h"
#include "DNA_node_types.h"
@@ -71,6 +73,8 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_linklist.h"
+#include "BLI_memarena.h"
#include "BLI_threads.h"
#include "BLT_translation.h"
@@ -81,10 +85,10 @@
#include "BKE_bpath.h"
#include "BKE_brush.h"
#include "BKE_camera.h"
+#include "BKE_cachefile.h"
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_depsgraph.h"
-#include "BKE_fcurve.h"
#include "BKE_font.h"
#include "BKE_global.h"
#include "BKE_group.h"
@@ -92,27 +96,26 @@
#include "BKE_idcode.h"
#include "BKE_idprop.h"
#include "BKE_image.h"
-#include "BKE_ipo.h"
#include "BKE_key.h"
#include "BKE_lamp.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_linestyle.h"
#include "BKE_mesh.h"
#include "BKE_material.h"
#include "BKE_main.h"
#include "BKE_mball.h"
-#include "BKE_movieclip.h"
#include "BKE_mask.h"
+#include "BKE_movieclip.h"
#include "BKE_node.h"
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
#include "BKE_packedFile.h"
-#include "BKE_speaker.h"
#include "BKE_sound.h"
-#include "BKE_screen.h"
+#include "BKE_speaker.h"
#include "BKE_scene.h"
#include "BKE_text.h"
#include "BKE_texture.h"
@@ -125,10 +128,6 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
-#ifdef WITH_PYTHON
-#include "BPY_extern.h"
-#endif
-
/* GS reads the memory pointed at in a specific ordering.
* only use this definition, makes little and big endian systems
* work fine, in conjunction with MAKE_ID */
@@ -152,7 +151,7 @@ void BKE_id_lib_local_paths(Main *bmain, Library *lib, ID *id)
void id_lib_extern(ID *id)
{
- if (id) {
+ if (id && ID_IS_LINKED_DATABLOCK(id)) {
BLI_assert(BKE_idcode_is_linkable(GS(id->name)));
if (id->tag & LIB_TAG_INDIRECT) {
id->tag -= LIB_TAG_INDIRECT;
@@ -182,7 +181,6 @@ void id_us_ensure_real(ID *id)
}
}
-/* Unused currently... */
void id_us_clear_real(ID *id)
{
if (id && (id->tag & LIB_TAG_EXTRAUSER)) {
@@ -232,9 +230,7 @@ void id_us_min(ID *id)
if (id->us <= limit) {
printf("ID user decrement error: %s (from '%s'): %d <= %d\n",
id->name, id->lib ? id->lib->filepath : "[Main]", id->us, limit);
- /* We cannot assert here, because of how we 'delete' datablocks currently (setting their usercount to zero),
- * this is weak but it's how it works for now. */
- /* BLI_assert(0); */
+ BLI_assert(0);
id->us = limit;
}
else {
@@ -264,99 +260,186 @@ void id_fake_user_clear(ID *id)
}
}
-/* calls the appropriate make_local method for the block, unless test. Returns true
- * if the block can be made local. */
-bool id_make_local(ID *id, bool test)
+static int id_expand_local_callback(
+ void *UNUSED(user_data), struct ID *UNUSED(id_self), struct ID **id_pointer, int UNUSED(cd_flag))
+{
+ if (*id_pointer) {
+ id_lib_extern(*id_pointer);
+ }
+
+ return IDWALK_RET_NOP;
+}
+
+/**
+ * Expand ID usages of given id as 'extern' (and no more indirect) linked data. Used by ID copy/make_local functions.
+ */
+void BKE_id_expand_local(ID *id)
+{
+ BKE_library_foreach_ID_link(id, id_expand_local_callback, NULL, 0);
+}
+
+/**
+ * Ensure new (copied) ID is fully made local.
+ */
+void BKE_id_copy_ensure_local(Main *bmain, ID *old_id, ID *new_id)
+{
+ if (ID_IS_LINKED_DATABLOCK(old_id)) {
+ BKE_id_expand_local(new_id);
+ BKE_id_lib_local_paths(bmain, old_id->lib, new_id);
+ }
+}
+
+/**
+ * Generic 'make local' function, works for most of datablock types...
+ */
+void BKE_id_make_local_generic(Main *bmain, ID *id, const bool id_in_mainlist, const bool lib_local)
+{
+ bool is_local = false, is_lib = false;
+
+ /* - only lib users: do nothing (unless force_local is set)
+ * - only local users: set flag
+ * - mixed: make copy
+ * In case we make a whole lib's content local, we always want to localize, and we skip remapping (done later).
+ */
+
+ if (!ID_IS_LINKED_DATABLOCK(id)) {
+ return;
+ }
+
+ BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
+
+ if (lib_local || is_local) {
+ if (!is_lib) {
+ id_clear_lib_data_ex(bmain, id, id_in_mainlist);
+ BKE_id_expand_local(id);
+ }
+ else {
+ ID *id_new;
+
+ /* Should not fail in expected usecases, but id_copy does not copy Scene e.g. */
+ if (id_copy(bmain, id, &id_new, false)) {
+ id_new->us = 0;
+
+ if (!lib_local) {
+ BKE_libblock_remap(bmain, id, id_new, ID_REMAP_SKIP_INDIRECT_USAGE);
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Calls the appropriate make_local method for the block, unless test is set.
+ *
+ * \param lib_local Special flag used when making a whole library's content local, it needs specific handling.
+ *
+ * \return true if the block can be made local.
+ */
+bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local)
{
- if (id->tag & LIB_TAG_INDIRECT)
+ /* We don't care whether ID is directly or indirectly linked in case we are making a whole lib local... */
+ if (!lib_local && (id->tag & LIB_TAG_INDIRECT)) {
return false;
+ }
- switch (GS(id->name)) {
+ switch ((ID_Type)GS(id->name)) {
case ID_SCE:
- return false; /* not implemented */
- case ID_LI:
- return false; /* can't be linked */
+ /* Partially implemented (has no copy...). */
+ if (!test) BKE_scene_make_local(bmain, (Scene *)id, lib_local);
+ return true;
case ID_OB:
- if (!test) BKE_object_make_local((Object *)id);
+ if (!test) BKE_object_make_local(bmain, (Object *)id, lib_local);
return true;
case ID_ME:
- if (!test) {
- BKE_mesh_make_local((Mesh *)id);
- BKE_key_make_local(((Mesh *)id)->key);
- }
+ if (!test) BKE_mesh_make_local(bmain, (Mesh *)id, lib_local);
return true;
case ID_CU:
- if (!test) {
- BKE_curve_make_local((Curve *)id);
- BKE_key_make_local(((Curve *)id)->key);
- }
+ if (!test) BKE_curve_make_local(bmain, (Curve *)id, lib_local);
return true;
case ID_MB:
- if (!test) BKE_mball_make_local((MetaBall *)id);
+ if (!test) BKE_mball_make_local(bmain, (MetaBall *)id, lib_local);
return true;
case ID_MA:
- if (!test) BKE_material_make_local((Material *)id);
+ if (!test) BKE_material_make_local(bmain, (Material *)id, lib_local);
return true;
case ID_TE:
- if (!test) BKE_texture_make_local((Tex *)id);
+ if (!test) BKE_texture_make_local(bmain, (Tex *)id, lib_local);
return true;
case ID_IM:
- if (!test) BKE_image_make_local((Image *)id);
+ if (!test) BKE_image_make_local(bmain, (Image *)id, lib_local);
return true;
case ID_LT:
- if (!test) {
- BKE_lattice_make_local((Lattice *)id);
- BKE_key_make_local(((Lattice *)id)->key);
- }
+ if (!test) BKE_lattice_make_local(bmain, (Lattice *)id, lib_local);
return true;
case ID_LA:
- if (!test) BKE_lamp_make_local((Lamp *)id);
+ if (!test) BKE_lamp_make_local(bmain, (Lamp *)id, lib_local);
return true;
case ID_CA:
- if (!test) BKE_camera_make_local((Camera *)id);
+ if (!test) BKE_camera_make_local(bmain, (Camera *)id, lib_local);
return true;
case ID_SPK:
- if (!test) BKE_speaker_make_local((Speaker *)id);
- return true;
- case ID_IP:
- return false; /* deprecated */
- case ID_KE:
- if (!test) BKE_key_make_local((Key *)id);
+ if (!test) BKE_speaker_make_local(bmain, (Speaker *)id, lib_local);
return true;
case ID_WO:
- if (!test) BKE_world_make_local((World *)id);
+ if (!test) BKE_world_make_local(bmain, (World *)id, lib_local);
return true;
- case ID_SCR:
- return false; /* can't be linked */
case ID_VF:
- return false; /* not implemented */
+ /* Partially implemented (has no copy...). */
+ if (!test) BKE_vfont_make_local(bmain, (VFont *)id, lib_local);
+ return true;
case ID_TXT:
- return false; /* not implemented */
+ if (!test) BKE_text_make_local(bmain, (Text *)id, lib_local);
+ return true;
case ID_SO:
- return false; /* not implemented */
+ /* Partially implemented (has no copy...). */
+ if (!test) BKE_sound_make_local(bmain, (bSound *)id, lib_local);
+ return true;
case ID_GR:
- return false; /* not implemented */
+ if (!test) BKE_group_make_local(bmain, (Group *)id, lib_local);
+ return true;
case ID_AR:
- if (!test) BKE_armature_make_local((bArmature *)id);
+ if (!test) BKE_armature_make_local(bmain, (bArmature *)id, lib_local);
return true;
case ID_AC:
- if (!test) BKE_action_make_local((bAction *)id);
+ if (!test) BKE_action_make_local(bmain, (bAction *)id, lib_local);
return true;
case ID_NT:
- if (!test) ntreeMakeLocal((bNodeTree *)id, true);
+ if (!test) ntreeMakeLocal(bmain, (bNodeTree *)id, true, lib_local);
return true;
case ID_BR:
- if (!test) BKE_brush_make_local((Brush *)id);
+ if (!test) BKE_brush_make_local(bmain, (Brush *)id, lib_local);
return true;
case ID_PA:
- if (!test) BKE_particlesettings_make_local((ParticleSettings *)id);
+ if (!test) BKE_particlesettings_make_local(bmain, (ParticleSettings *)id, lib_local);
return true;
- case ID_WM:
- return false; /* can't be linked */
case ID_GD:
- return false; /* not implemented */
+ if (!test) BKE_gpencil_make_local(bmain, (bGPdata *)id, lib_local);
+ return true;
+ case ID_MC:
+ if (!test) BKE_movieclip_make_local(bmain, (MovieClip *)id, lib_local);
+ return true;
+ case ID_MSK:
+ if (!test) BKE_mask_make_local(bmain, (Mask *)id, lib_local);
+ return true;
case ID_LS:
- return false; /* not implemented */
+ if (!test) BKE_linestyle_make_local(bmain, (FreestyleLineStyle *)id, lib_local);
+ return true;
+ case ID_PAL:
+ if (!test) BKE_palette_make_local(bmain, (Palette *)id, lib_local);
+ return true;
+ case ID_PC:
+ if (!test) BKE_paint_curve_make_local(bmain, (PaintCurve *)id, lib_local);
+ return true;
+ case ID_CF:
+ if (!test) BKE_cachefile_make_local(bmain, (CacheFile *)id, lib_local);
+ return true;
+ case ID_SCR:
+ case ID_LI:
+ case ID_KE:
+ case ID_WM:
+ return false; /* can't be linked */
+ case ID_IP:
+ return false; /* deprecated */
}
return false;
@@ -366,133 +449,112 @@ bool id_make_local(ID *id, bool test)
* Invokes the appropriate copy method for the block and returns the result in
* newid, unless test. Returns true if the block can be copied.
*/
-bool id_copy(ID *id, ID **newid, bool test)
+bool id_copy(Main *bmain, ID *id, ID **newid, bool test)
{
- if (!test) *newid = NULL;
+ if (!test) {
+ *newid = NULL;
+ }
/* conventions:
* - make shallow copy, only this ID block
* - id.us of the new ID is set to 1 */
- switch (GS(id->name)) {
- case ID_SCE:
- return false; /* can't be copied from here */
- case ID_LI:
- return false; /* can't be copied from here */
+ switch ((ID_Type)GS(id->name)) {
case ID_OB:
- if (!test) *newid = (ID *)BKE_object_copy((Object *)id);
+ if (!test) *newid = (ID *)BKE_object_copy(bmain, (Object *)id);
return true;
case ID_ME:
- if (!test) *newid = (ID *)BKE_mesh_copy((Mesh *)id);
+ if (!test) *newid = (ID *)BKE_mesh_copy(bmain, (Mesh *)id);
return true;
case ID_CU:
- if (!test) *newid = (ID *)BKE_curve_copy((Curve *)id);
+ if (!test) *newid = (ID *)BKE_curve_copy(bmain, (Curve *)id);
return true;
case ID_MB:
- if (!test) *newid = (ID *)BKE_mball_copy((MetaBall *)id);
+ if (!test) *newid = (ID *)BKE_mball_copy(bmain, (MetaBall *)id);
return true;
case ID_MA:
- if (!test) *newid = (ID *)BKE_material_copy((Material *)id);
+ if (!test) *newid = (ID *)BKE_material_copy(bmain, (Material *)id);
return true;
case ID_TE:
- if (!test) *newid = (ID *)BKE_texture_copy((Tex *)id);
+ if (!test) *newid = (ID *)BKE_texture_copy(bmain, (Tex *)id);
return true;
case ID_IM:
- if (!test) *newid = (ID *)BKE_image_copy(G.main, (Image *)id);
+ if (!test) *newid = (ID *)BKE_image_copy(bmain, (Image *)id);
return true;
case ID_LT:
- if (!test) *newid = (ID *)BKE_lattice_copy((Lattice *)id);
+ if (!test) *newid = (ID *)BKE_lattice_copy(bmain, (Lattice *)id);
return true;
case ID_LA:
- if (!test) *newid = (ID *)BKE_lamp_copy((Lamp *)id);
+ if (!test) *newid = (ID *)BKE_lamp_copy(bmain, (Lamp *)id);
return true;
case ID_SPK:
- if (!test) *newid = (ID *)BKE_speaker_copy((Speaker *)id);
+ if (!test) *newid = (ID *)BKE_speaker_copy(bmain, (Speaker *)id);
return true;
case ID_CA:
- if (!test) *newid = (ID *)BKE_camera_copy((Camera *)id);
+ if (!test) *newid = (ID *)BKE_camera_copy(bmain, (Camera *)id);
return true;
- case ID_IP:
- return false; /* deprecated */
case ID_KE:
- if (!test) *newid = (ID *)BKE_key_copy((Key *)id);
+ if (!test) *newid = (ID *)BKE_key_copy(bmain, (Key *)id);
return true;
case ID_WO:
- if (!test) *newid = (ID *)BKE_world_copy((World *)id);
+ if (!test) *newid = (ID *)BKE_world_copy(bmain, (World *)id);
return true;
- case ID_SCR:
- return false; /* can't be copied from here */
- case ID_VF:
- return false; /* not implemented */
case ID_TXT:
- if (!test) *newid = (ID *)BKE_text_copy(G.main, (Text *)id);
+ if (!test) *newid = (ID *)BKE_text_copy(bmain, (Text *)id);
return true;
- case ID_SO:
- return false; /* not implemented */
case ID_GR:
- if (!test) *newid = (ID *)BKE_group_copy((Group *)id);
+ if (!test) *newid = (ID *)BKE_group_copy(bmain, (Group *)id);
return true;
case ID_AR:
- if (!test) *newid = (ID *)BKE_armature_copy((bArmature *)id);
+ if (!test) *newid = (ID *)BKE_armature_copy(bmain, (bArmature *)id);
return true;
case ID_AC:
- if (!test) *newid = (ID *)BKE_action_copy((bAction *)id);
+ if (!test) *newid = (ID *)BKE_action_copy(bmain, (bAction *)id);
return true;
case ID_NT:
- if (!test) *newid = (ID *)ntreeCopyTree((bNodeTree *)id);
+ if (!test) *newid = (ID *)ntreeCopyTree(bmain, (bNodeTree *)id);
return true;
case ID_BR:
- if (!test) *newid = (ID *)BKE_brush_copy((Brush *)id);
+ if (!test) *newid = (ID *)BKE_brush_copy(bmain, (Brush *)id);
return true;
case ID_PA:
- if (!test) *newid = (ID *)BKE_particlesettings_copy((ParticleSettings *)id);
+ if (!test) *newid = (ID *)BKE_particlesettings_copy(bmain, (ParticleSettings *)id);
return true;
- case ID_WM:
- return false; /* can't be copied from here */
case ID_GD:
- if (!test) *newid = (ID *)gpencil_data_duplicate((bGPdata *)id, false);
+ if (!test) *newid = (ID *)BKE_gpencil_data_duplicate(bmain, (bGPdata *)id, false);
+ return true;
+ case ID_MC:
+ if (!test) *newid = (ID *)BKE_movieclip_copy(bmain, (MovieClip *)id);
return true;
case ID_MSK:
- if (!test) *newid = (ID *)BKE_mask_copy((Mask *)id);
+ if (!test) *newid = (ID *)BKE_mask_copy(bmain, (Mask *)id);
return true;
case ID_LS:
- if (!test) *newid = (ID *)BKE_linestyle_copy(G.main, (FreestyleLineStyle *)id);
+ if (!test) *newid = (ID *)BKE_linestyle_copy(bmain, (FreestyleLineStyle *)id);
return true;
+ case ID_PAL:
+ if (!test) *newid = (ID *)BKE_palette_copy(bmain, (Palette *)id);
+ return true;
+ case ID_PC:
+ if (!test) *newid = (ID *)BKE_paint_curve_copy(bmain, (PaintCurve *)id);
+ return true;
+ case ID_CF:
+ if (!test) *newid = (ID *)BKE_cachefile_copy(bmain, (CacheFile *)id);
+ return true;
+ case ID_SCE:
+ case ID_LI:
+ case ID_SCR:
+ case ID_WM:
+ return false; /* can't be copied from here */
+ case ID_VF:
+ case ID_SO:
+ return false; /* not implemented */
+ case ID_IP:
+ return false; /* deprecated */
}
return false;
}
-bool id_unlink(ID *id, int test)
-{
- Main *mainlib = G.main;
- short type = GS(id->name);
-
- switch (type) {
- case ID_TXT:
- if (test) return true;
- BKE_text_unlink(mainlib, (Text *)id);
- break;
- case ID_GR:
- if (test) return true;
- BKE_group_unlink(mainlib, (Group *)id);
- break;
- case ID_OB:
- if (test) return true;
- BKE_object_unlink(mainlib, (Object *)id);
- break;
- }
-
- if (id->us == 0) {
- if (test) return true;
-
- BKE_libblock_free(mainlib, id);
-
- return true;
- }
-
- return false;
-}
-
bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
{
ID *newid = NULL;
@@ -501,7 +563,7 @@ bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
if (id) {
/* if property isn't editable, we're going to have an extra block hanging around until we save */
if (RNA_property_editable(ptr, prop)) {
- if (id_copy(id, &newid, false) && newid) {
+ if (id_copy(CTX_data_main(C), id, &newid, false) && newid) {
/* copy animation actions too */
BKE_animdata_copy_id_action(id);
/* us is 1 by convention, but RNA_property_pointer_set
@@ -523,7 +585,7 @@ bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
ListBase *which_libbase(Main *mainlib, short type)
{
- switch (type) {
+ switch ((ID_Type)type) {
case ID_SCE:
return &(mainlib->scene);
case ID_LI:
@@ -590,6 +652,8 @@ ListBase *which_libbase(Main *mainlib, short type)
return &(mainlib->palettes);
case ID_PC:
return &(mainlib->paintcurves);
+ case ID_CF:
+ return &(mainlib->cachefiles);
}
return NULL;
}
@@ -674,7 +738,7 @@ void BKE_main_lib_objects_recalc_all(Main *bmain)
/* flag for full recalc */
for (ob = bmain->object.first; ob; ob = ob->id.next) {
- if (ob->id.lib) {
+ if (ID_IS_LINKED_DATABLOCK(ob)) {
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
}
}
@@ -691,59 +755,56 @@ void BKE_main_lib_objects_recalc_all(Main *bmain)
* \note MAX_LIBARRAY define should match this code */
int set_listbasepointers(Main *main, ListBase **lb)
{
- int a = 0;
-
/* BACKWARDS! also watch order of free-ing! (mesh<->mat), first items freed last.
* This is important because freeing data decreases usercounts of other datablocks,
* if this data is its self freed it can crash. */
- lb[a++] = &(main->library); /* Libraries may be accessed from pretty much any other ID... */
- lb[a++] = &(main->ipo);
- lb[a++] = &(main->action); /* moved here to avoid problems when freeing with animato (aligorith) */
- lb[a++] = &(main->key);
- lb[a++] = &(main->gpencil); /* referenced by nodes, objects, view, scene etc, before to free after. */
- lb[a++] = &(main->nodetree);
- lb[a++] = &(main->image);
- lb[a++] = &(main->tex);
- lb[a++] = &(main->mat);
- lb[a++] = &(main->vfont);
+ lb[INDEX_ID_LI] = &(main->library); /* Libraries may be accessed from pretty much any other ID... */
+ lb[INDEX_ID_IP] = &(main->ipo);
+ lb[INDEX_ID_AC] = &(main->action); /* moved here to avoid problems when freeing with animato (aligorith) */
+ lb[INDEX_ID_KE] = &(main->key);
+ lb[INDEX_ID_GD] = &(main->gpencil); /* referenced by nodes, objects, view, scene etc, before to free after. */
+ lb[INDEX_ID_NT] = &(main->nodetree);
+ lb[INDEX_ID_IM] = &(main->image);
+ lb[INDEX_ID_TE] = &(main->tex);
+ lb[INDEX_ID_MA] = &(main->mat);
+ lb[INDEX_ID_VF] = &(main->vfont);
/* Important!: When adding a new object type,
* the specific data should be inserted here
*/
- lb[a++] = &(main->armature);
-
- lb[a++] = &(main->mesh);
- lb[a++] = &(main->curve);
- lb[a++] = &(main->mball);
-
- lb[a++] = &(main->latt);
- lb[a++] = &(main->lamp);
- lb[a++] = &(main->camera);
-
- lb[a++] = &(main->text);
- lb[a++] = &(main->sound);
- lb[a++] = &(main->group);
- lb[a++] = &(main->palettes);
- lb[a++] = &(main->paintcurves);
- lb[a++] = &(main->brush);
- lb[a++] = &(main->particle);
- lb[a++] = &(main->speaker);
-
- lb[a++] = &(main->world);
- lb[a++] = &(main->movieclip);
- lb[a++] = &(main->screen);
- lb[a++] = &(main->object);
- lb[a++] = &(main->linestyle); /* referenced by scenes */
- lb[a++] = &(main->scene);
- lb[a++] = &(main->wm);
- lb[a++] = &(main->mask);
+ lb[INDEX_ID_AR] = &(main->armature);
+
+ lb[INDEX_ID_CF] = &(main->cachefiles);
+ lb[INDEX_ID_ME] = &(main->mesh);
+ lb[INDEX_ID_CU] = &(main->curve);
+ lb[INDEX_ID_MB] = &(main->mball);
+
+ lb[INDEX_ID_LT] = &(main->latt);
+ lb[INDEX_ID_LA] = &(main->lamp);
+ lb[INDEX_ID_CA] = &(main->camera);
+
+ lb[INDEX_ID_TXT] = &(main->text);
+ lb[INDEX_ID_SO] = &(main->sound);
+ lb[INDEX_ID_GR] = &(main->group);
+ lb[INDEX_ID_PAL] = &(main->palettes);
+ lb[INDEX_ID_PC] = &(main->paintcurves);
+ lb[INDEX_ID_BR] = &(main->brush);
+ lb[INDEX_ID_PA] = &(main->particle);
+ lb[INDEX_ID_SPK] = &(main->speaker);
+
+ lb[INDEX_ID_WO] = &(main->world);
+ lb[INDEX_ID_MC] = &(main->movieclip);
+ lb[INDEX_ID_SCR] = &(main->screen);
+ lb[INDEX_ID_OB] = &(main->object);
+ lb[INDEX_ID_LS] = &(main->linestyle); /* referenced by scenes */
+ lb[INDEX_ID_SCE] = &(main->scene);
+ lb[INDEX_ID_WM] = &(main->wm);
+ lb[INDEX_ID_MSK] = &(main->mask);
- lb[a] = NULL;
-
- BLI_assert(a + 1 == MAX_LIBARRAY);
+ lb[INDEX_ID_NULL] = NULL;
- return a;
+ return (MAX_LIBARRAY - 1);
}
/* *********** ALLOC AND FREE *****************
@@ -764,7 +825,7 @@ void *BKE_libblock_alloc_notest(short type)
{
ID *id = NULL;
- switch (type) {
+ switch ((ID_Type)type) {
case ID_SCE:
id = MEM_callocN(sizeof(Scene), "scene");
break;
@@ -864,6 +925,9 @@ void *BKE_libblock_alloc_notest(short type)
case ID_PC:
id = MEM_callocN(sizeof(PaintCurve), "Paint Curve");
break;
+ case ID_CF:
+ id = MEM_callocN(sizeof(CacheFile), "Cache File");
+ break;
}
return id;
}
@@ -901,7 +965,7 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name)
void BKE_libblock_init_empty(ID *id)
{
/* Note that only ID types that are not valid when filled of zero should have a callback here. */
- switch (GS(id->name)) {
+ switch ((ID_Type)GS(id->name)) {
case ID_SCE:
BKE_scene_init((Scene *)id);
break;
@@ -945,15 +1009,6 @@ void BKE_libblock_init_empty(ID *id)
case ID_CA:
BKE_camera_init((Camera *)id);
break;
- case ID_IP:
- /* Should not be needed - animation from lib pre-2.5 is broken anyway. */
- BLI_assert(0);
- break;
- case ID_KE:
- /* Shapekeys are a complex topic too - they depend on their 'user' data type...
- * They are not linkable, though, so it should never reach here anyway. */
- BLI_assert(0);
- break;
case ID_WO:
BKE_world_init((World *)id);
break;
@@ -990,10 +1045,6 @@ void BKE_libblock_init_empty(ID *id)
case ID_PC:
/* Nothing to do. */
break;
- case ID_WM:
- /* We should never reach this. */
- BLI_assert(0);
- break;
case ID_GD:
/* Nothing to do. */
break;
@@ -1003,6 +1054,24 @@ void BKE_libblock_init_empty(ID *id)
case ID_LS:
BKE_linestyle_init((FreestyleLineStyle *)id);
break;
+ case ID_CF:
+ BKE_cachefile_init((CacheFile *)id);
+ break;
+ case ID_KE:
+ /* Shapekeys are a complex topic too - they depend on their 'user' data type...
+ * They are not linkable, though, so it should never reach here anyway. */
+ BLI_assert(0);
+ break;
+ case ID_WM:
+ /* We should never reach this. */
+ BLI_assert(0);
+ break;
+ case ID_IP:
+ /* Should not be needed - animation from lib pre-2.5 is broken anyway. */
+ BLI_assert(0);
+ break;
+ default:
+ BLI_assert(0); /* Should never reach this point... */
}
}
@@ -1029,7 +1098,7 @@ void BKE_libblock_copy_data(ID *id, const ID *id_from, const bool do_action)
}
/* used everywhere in blenkernel */
-void *BKE_libblock_copy_ex(Main *bmain, ID *id)
+void *BKE_libblock_copy(Main *bmain, ID *id)
{
ID *idn;
size_t idn_len;
@@ -1081,11 +1150,6 @@ void *BKE_libblock_copy_nolib(ID *id, const bool do_action)
return idn;
}
-void *BKE_libblock_copy(ID *id)
-{
- return BKE_libblock_copy_ex(G.main, id);
-}
-
static int id_relink_looper(void *UNUSED(user_data), ID *UNUSED(self_id), ID **id_pointer, const int cd_flag)
{
ID *id = *id_pointer;
@@ -1105,240 +1169,18 @@ static int id_relink_looper(void *UNUSED(user_data), ID *UNUSED(self_id), ID **i
void BKE_libblock_relink(ID *id)
{
- if (id->lib)
+ if (ID_IS_LINKED_DATABLOCK(id))
return;
BKE_library_foreach_ID_link(id, id_relink_looper, NULL, 0);
}
-static void BKE_library_free(Library *lib)
+void BKE_library_free(Library *lib)
{
if (lib->packedfile)
freePackedFile(lib->packedfile);
}
-static BKE_library_free_window_manager_cb free_windowmanager_cb = NULL;
-
-void BKE_library_callback_free_window_manager_set(BKE_library_free_window_manager_cb func)
-{
- free_windowmanager_cb = func;
-}
-
-static BKE_library_free_notifier_reference_cb free_notifier_reference_cb = NULL;
-
-void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func)
-{
- free_notifier_reference_cb = func;
-}
-
-static BKE_library_free_editor_id_reference_cb free_editor_id_reference_cb = NULL;
-
-void BKE_library_callback_free_editor_id_reference_set(BKE_library_free_editor_id_reference_cb func)
-{
- free_editor_id_reference_cb = func;
-}
-
-static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata)
-{
- ChannelDriver *driver;
- FCurve *fcu;
-
- /* find the driver this belongs to and update it */
- for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
- driver = fcu->driver;
-
- if (driver) {
- DriverVar *dvar;
- for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
- DRIVER_TARGETS_USED_LOOPER(dvar)
- {
- if (dtar->id == userdata)
- dtar->id = NULL;
- }
- DRIVER_TARGETS_LOOPER_END
- }
- }
- }
-}
-
-void BKE_libblock_free_data(Main *bmain, ID *id)
-{
- if (id->properties) {
- IDP_FreeProperty(id->properties);
- MEM_freeN(id->properties);
- }
-
- /* this ID may be a driver target! */
- BKE_animdata_main_cb(bmain, animdata_dtar_clear_cb, (void *)id);
-}
-
-/* used in headerbuttons.c image.c mesh.c screen.c sound.c and library.c */
-void BKE_libblock_free_ex(Main *bmain, void *idv, bool do_id_user)
-{
- ID *id = idv;
- short type = GS(id->name);
- ListBase *lb = which_libbase(bmain, type);
-
- DAG_id_type_tag(bmain, type);
-
-#ifdef WITH_PYTHON
- BPY_id_release(id);
-#endif
-
- switch (type) { /* GetShort from util.h */
- case ID_SCE:
- BKE_scene_free((Scene *)id);
- break;
- case ID_LI:
- BKE_library_free((Library *)id);
- break;
- case ID_OB:
- BKE_object_free_ex((Object *)id, do_id_user);
- break;
- case ID_ME:
- BKE_mesh_free((Mesh *)id, 1);
- break;
- case ID_CU:
- BKE_curve_free((Curve *)id);
- break;
- case ID_MB:
- BKE_mball_free((MetaBall *)id);
- break;
- case ID_MA:
- BKE_material_free((Material *)id);
- break;
- case ID_TE:
- BKE_texture_free((Tex *)id);
- break;
- case ID_IM:
- BKE_image_free((Image *)id);
- break;
- case ID_LT:
- BKE_lattice_free((Lattice *)id);
- break;
- case ID_LA:
- BKE_lamp_free((Lamp *)id);
- break;
- case ID_CA:
- BKE_camera_free((Camera *) id);
- break;
- case ID_IP:
- BKE_ipo_free((Ipo *)id);
- break;
- case ID_KE:
- BKE_key_free((Key *)id);
- break;
- case ID_WO:
- BKE_world_free((World *)id);
- break;
- case ID_SCR:
- BKE_screen_free((bScreen *)id);
- break;
- case ID_VF:
- BKE_vfont_free((VFont *)id);
- break;
- case ID_TXT:
- BKE_text_free((Text *)id);
- break;
- case ID_SPK:
- BKE_speaker_free((Speaker *)id);
- break;
- case ID_SO:
- BKE_sound_free((bSound *)id);
- break;
- case ID_GR:
- BKE_group_free((Group *)id);
- break;
- case ID_AR:
- BKE_armature_free((bArmature *)id);
- break;
- case ID_AC:
- BKE_action_free((bAction *)id);
- break;
- case ID_NT:
- ntreeFreeTree_ex((bNodeTree *)id, do_id_user);
- break;
- case ID_BR:
- BKE_brush_free((Brush *)id);
- break;
- case ID_PA:
- BKE_particlesettings_free((ParticleSettings *)id);
- break;
- case ID_WM:
- if (free_windowmanager_cb)
- free_windowmanager_cb(NULL, (wmWindowManager *)id);
- break;
- case ID_GD:
- BKE_gpencil_free((bGPdata *)id);
- break;
- case ID_MC:
- BKE_movieclip_free((MovieClip *)id);
- break;
- case ID_MSK:
- BKE_mask_free(bmain, (Mask *)id);
- break;
- case ID_LS:
- BKE_linestyle_free((FreestyleLineStyle *)id);
- break;
- case ID_PAL:
- BKE_palette_free((Palette *)id);
- break;
- case ID_PC:
- BKE_paint_curve_free((PaintCurve *)id);
- break;
- }
-
- /* avoid notifying on removed data */
- BKE_main_lock(bmain);
-
- if (free_notifier_reference_cb) {
- free_notifier_reference_cb(id);
- }
-
- if (free_editor_id_reference_cb) {
- free_editor_id_reference_cb(id);
- }
-
- BLI_remlink(lb, id);
-
- BKE_libblock_free_data(bmain, id);
- BKE_main_unlock(bmain);
-
- MEM_freeN(id);
-}
-
-void BKE_libblock_free(Main *bmain, void *idv)
-{
- BKE_libblock_free_ex(bmain, idv, true);
-}
-
-void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */
-{
- ID *id = idv;
-
- id_us_min(id);
-
- /* XXX This is a temp (2.77) hack so that we keep same behavior as in 2.76 regarding groups when deleting an object.
- * Since only 'user_one' usage of objects is groups, and only 'real user' usage of objects is scenes,
- * removing that 'user_one' tag when there is no more real (scene) users of an object ensures it gets
- * fully unlinked.
- * Otherwise, there is no real way to get rid of an object anymore - better handling of this is TODO.
- */
- if ((GS(id->name) == ID_OB) && (id->us == 1)) {
- id_us_clear_real(id);
- }
-
- if (id->us == 0) {
- switch (GS(id->name)) {
- case ID_OB:
- BKE_object_unlink(bmain, (Object *)id);
- break;
- }
-
- BKE_libblock_free(bmain, id);
- }
-}
-
Main *BKE_main_new(void)
{
Main *bmain = MEM_callocN(sizeof(Main), "new main");
@@ -1402,6 +1244,7 @@ void BKE_main_free(Main *mainvar)
case 31: BKE_libblock_free_ex(mainvar, id, false); break;
case 32: BKE_libblock_free_ex(mainvar, id, false); break;
case 33: BKE_libblock_free_ex(mainvar, id, false); break;
+ case 34: BKE_libblock_free_ex(mainvar, id, false); break;
default:
BLI_assert(0);
break;
@@ -1541,7 +1384,7 @@ static ID *is_dupid(ListBase *lb, ID *id, const char *name)
for (idtest = lb->first; idtest; idtest = idtest->next) {
/* if idtest is not a lib */
- if (id != idtest && idtest->lib == NULL) {
+ if (id != idtest && !ID_IS_LINKED_DATABLOCK(idtest)) {
/* do not test alphabetic! */
/* optimized */
if (idtest->name[2] == name[0]) {
@@ -1601,7 +1444,7 @@ static bool check_for_dupid(ListBase *lb, ID *id, char *name)
for (idtest = lb->first; idtest; idtest = idtest->next) {
int nrtest;
if ( (id != idtest) &&
- (idtest->lib == NULL) &&
+ !ID_IS_LINKED_DATABLOCK(idtest) &&
(*name == *(idtest->name + 2)) &&
STREQLEN(name, idtest->name + 2, left_len) &&
(BLI_split_name_num(leftest, &nrtest, idtest->name + 2, '.') == left_len)
@@ -1683,7 +1526,7 @@ bool new_id(ListBase *lb, ID *id, const char *tname)
char name[MAX_ID_NAME - 2];
/* if library, don't rename */
- if (id->lib)
+ if (ID_IS_LINKED_DATABLOCK(id))
return false;
/* if no libdata given, look up based on ID */
@@ -1728,9 +1571,10 @@ bool new_id(ListBase *lb, ID *id, const char *tname)
* Pull an ID out of a library (make it local). Only call this for IDs that
* don't have other library users.
*/
-void id_clear_lib_data_ex(Main *bmain, ID *id, bool id_in_mainlist)
+void id_clear_lib_data_ex(Main *bmain, ID *id, const bool id_in_mainlist)
{
bNodeTree *ntree = NULL;
+ Key *key = NULL;
BKE_id_lib_local_paths(bmain, id->lib, id);
@@ -1741,22 +1585,14 @@ void id_clear_lib_data_ex(Main *bmain, ID *id, bool id_in_mainlist)
if (id_in_mainlist)
new_id(which_libbase(bmain, GS(id->name)), id, NULL);
- /* internal bNodeTree blocks inside ID types below
- * also stores id->lib, make sure this stays in sync.
- */
- ntree = ntreeFromID(id);
-
- if (ntree) {
- ntreeMakeLocal(ntree, false);
+ /* Internal bNodeTree blocks inside datablocks also stores id->lib, make sure this stays in sync. */
+ if ((ntree = ntreeFromID(id))) {
+ id_clear_lib_data_ex(bmain, &ntree->id, false); /* Datablocks' nodetree is never in Main. */
}
- if (GS(id->name) == ID_OB) {
- Object *object = (Object *)id;
- if (object->proxy_from != NULL) {
- object->proxy_from->proxy = NULL;
- object->proxy_from->proxy_group = NULL;
- }
- object->proxy = object->proxy_from = object->proxy_group = NULL;
+ /* Same goes for shapekeys. */
+ if ((key = BKE_key_from_id(id))) {
+ id_clear_lib_data_ex(bmain, &key->id, id_in_mainlist); /* sigh, why are keys in Main? */
}
}
@@ -1783,87 +1619,73 @@ void BKE_main_id_clear_newpoins(Main *bmain)
}
}
-static void lib_indirect_test_id(ID *id, Library *lib)
-{
-#define LIBTAG(a) \
- if (a && a->id.lib) { a->id.tag &= ~LIB_TAG_INDIRECT; a->id.tag |= LIB_TAG_EXTERN; } (void)0
-
- if (id->lib) {
- /* datablocks that were indirectly related are now direct links
- * without this, appending data that has a link to other data will fail to write */
- if (lib && id->lib->parent == lib) {
- id_lib_extern(id);
- }
- return;
- }
-
- if (GS(id->name) == ID_OB) {
- Object *ob = (Object *)id;
- Mesh *me;
-
- int a;
-
-#if 0 /* XXX OLD ANIMSYS, NLASTRIPS ARE NO LONGER USED */
- /* XXX old animation system! -------------------------------------- */
- {
- bActionStrip *strip;
- for (strip = ob->nlastrips.first; strip; strip = strip->next) {
- LIBTAG(strip->object);
- LIBTAG(strip->act);
- LIBTAG(strip->ipo);
- }
- }
- /* XXX: new animation system needs something like this? */
-#endif
-
- for (a = 0; a < ob->totcol; a++) {
- LIBTAG(ob->mat[a]);
- }
-
- LIBTAG(ob->dup_group);
- LIBTAG(ob->proxy);
-
- me = ob->data;
- LIBTAG(me);
- }
-
-#undef LIBTAG
-}
-
-/* if lib!=NULL, only all from lib local
- * bmain is almost certainly G.main */
-void BKE_library_make_local(Main *bmain, Library *lib, bool untagged_only, bool set_fake)
+/** Make linked datablocks local.
+ *
+ * \param bmain Almost certainly G.main.
+ * \param lib If not NULL, only make local datablocks from this library.
+ * \param untagged_only If true, only make local datablocks not tagged with LIB_TAG_PRE_EXISTING.
+ * \param set_fake If true, set fake user on all localized datablocks (except group and objects ones).
+ */
+/* XXX TODO This function should probably be reworked.
+ *
+ * Old (2.77) version was simply making (tagging) datablocks as local, without actually making any check whether
+ * they were also indirectly used or not...
+ *
+ * Current version uses regular id_make_local callback, but this is not super-efficient since this ends up
+ * duplicating some IDs and then removing original ones (due to missing knowledge of which ID uses some other ID).
+ *
+ * We could first check all IDs and detect those to be made local that are only used by other local or future-local
+ * datablocks, and directly tag those as local (instead of going through id_make_local) maybe...
+ *
+ * We'll probably need at some point a true dependency graph between datablocks, but for now this should work
+ * good enough (performances is not a critical point here anyway).
+ */
+void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged_only, const bool set_fake)
{
ListBase *lbarray[MAX_LIBARRAY];
- ID *id, *idn;
+ ID *id, *id_next;
int a;
- a = set_listbasepointers(bmain, lbarray);
- while (a--) {
+ LinkNode *copied_ids = NULL;
+ LinkNode *linked_loop_candidates = NULL;
+ MemArena *linklist_mem = BLI_memarena_new(256 * sizeof(copied_ids), __func__);
+
+ for (a = set_listbasepointers(bmain, lbarray); a--; ) {
id = lbarray[a]->first;
-
- while (id) {
+
+ /* Do not explicitly make local non-linkable IDs (shapekeys, in fact), they are assumed to be handled
+ * by real datablocks responsible of them. */
+ const bool do_skip = (id && !BKE_idcode_is_linkable(GS(id->name)));
+
+ for (; id; id = id_next) {
id->newid = NULL;
- idn = id->next; /* id is possibly being inserted again */
-
+ id->tag &= ~LIB_TAG_DOIT;
+ id_next = id->next; /* id is possibly being inserted again */
+
/* The check on the second line (LIB_TAG_PRE_EXISTING) is done so its
* possible to tag data you don't want to be made local, used for
* appending data, so any libdata already linked wont become local
* (very nasty to discover all your links are lost after appending)
* */
- if (id->tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW) &&
+ if (!do_skip && id->tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW) &&
((untagged_only == false) || !(id->tag & LIB_TAG_PRE_EXISTING)))
{
if (lib == NULL || id->lib == lib) {
if (id->lib) {
- /* for Make Local > All we should be calling id_make_local,
- * but doing that breaks append (see #36003 and #36006), we
- * we should make it work with all datablocks and id.us==0 */
- id_clear_lib_data(bmain, id); /* sets 'id->tag' */
-
- /* why sort alphabetically here but not in
- * id_clear_lib_data() ? - campbell */
- id_sort_by_name(lbarray[a], id);
+ /* In this specific case, we do want to make ID local even if it has no local usage yet... */
+ if (GS(id->name) == ID_OB) {
+ /* Special case for objects because we don't want proxy pointers to be
+ * cleared yet. This will happen down the road in this function.
+ */
+ BKE_object_make_local_ex(bmain, (Object*)id, true, false);
+ }
+ else {
+ id_make_local(bmain, id, false, true);
+ }
+
+ if (id->newid) {
+ BLI_linklist_prepend_arena(&copied_ids, id, linklist_mem);
+ }
}
else {
id->tag &= ~(LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW);
@@ -1877,16 +1699,128 @@ void BKE_library_make_local(Main *bmain, Library *lib, bool untagged_only, bool
}
}
}
+ }
+ }
+
+ /* We have to remap local usages of old (linked) ID to new (local) id in a second loop, as lbarray ordering is not
+ * enough to ensure us we did catch all dependencies (e.g. if making local a parent object before its child...).
+ * See T48907. */
+ for (LinkNode *it = copied_ids; it; it = it->next) {
+ id = it->link;
+
+ BLI_assert(id->newid != NULL);
+ BLI_assert(id->lib != NULL);
+
+ BKE_libblock_remap(bmain, id, id->newid, ID_REMAP_SKIP_INDIRECT_USAGE);
+ }
+
+ /* Third step: remove datablocks that have been copied to be localized and are no more used in the end...
+ * Note that we may have to loop more than once here, to tackle dependencies between linked objects... */
+ bool do_loop = true;
+ while (do_loop) {
+ do_loop = false;
+ for (LinkNode *it = copied_ids; it; it = it->next) {
+ if ((id = it->link) == NULL) {
+ continue;
+ }
+
+ bool is_local = false, is_lib = false;
+
+ BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
+
+ /* Attempt to re-link copied proxy objects. This allows appending of an entire scene
+ * from another blend file into this one, even when that blend file contains proxified
+ * armatures that have local references. Since the proxified object needs to be linked
+ * (not local), this will only work when the "Localize all" checkbox is disabled.
+ * TL;DR: this is a dirty hack on top of an already weak feature (proxies). */
+ if (GS(id->name) == ID_OB && ((Object *)id)->proxy != NULL) {
+ Object *ob = (Object *)id;
+ Object *ob_new = (Object *)id->newid;
- id = idn;
+ /* Proxies only work when the proxified object is linked-in from a library. */
+ if (ob->proxy->id.lib == NULL) {
+ printf("Warning, proxy object %s will loose its link to %s, because the "
+ "proxified object is local.\n", id->newid->name, ob->proxy->id.name);
+ }
+ /* We can only switch the proxy'ing to a made-local proxy if it is no longer
+ * referred to from a library. Not checking for local use; if new local proxy
+ * was not used locally would be a nasty bug! */
+ else if (is_local || is_lib) {
+ printf("Warning, made-local proxy object %s will loose its link to %s, "
+ "because the linked-in proxy is referenced (is_local=%i, is_lib=%i).\n",
+ id->newid->name, ob->proxy->id.name, is_local, is_lib);
+ }
+ else {
+ /* we can switch the proxy'ing from the linked-in to the made-local proxy.
+ * BKE_object_make_proxy() shouldn't be used here, as it allocates memory that
+ * was already allocated by BKE_object_make_local_ex() (which called BKE_object_copy_ex). */
+ ob_new->proxy = ob->proxy;
+ ob_new->proxy_group = ob->proxy_group;
+ ob_new->proxy_from = ob->proxy_from;
+ ob_new->proxy->proxy_from = ob_new;
+ ob->proxy = ob->proxy_from = ob->proxy_group = NULL;
+ }
+ }
+ /* Special hack for groups... Thing is, since we can't instantiate them here, we need to ensure
+ * they remain 'alive' (only instantiation is a real group 'user'... *sigh* See T49722. */
+ else if (GS(id->name) == ID_GR && (id->tag & LIB_TAG_INDIRECT) != 0) {
+ id_us_ensure_real(id->newid);
+ }
+
+ if (!is_local) {
+ if (!is_lib) { /* Not used at all, we can free it! */
+ BKE_libblock_free(bmain, id);
+ it->link = NULL;
+ do_loop = true;
+ }
+ else { /* Only used by linked data, potential candidate to ugly lib-only dependency cycles... */
+ /* Note that we store the node, not directly ID pointer, that way if it->link is set to NULL
+ * later we can skip it in lib-dependency cycles search later. */
+ BLI_linklist_prepend_arena(&linked_loop_candidates, it, linklist_mem);
+ id->tag |= LIB_TAG_DOIT;
+
+ /* Grrrrrrr... those half-datablocks-stuff... grrrrrrrrrrr...
+ * Here we have to also tag them as potential candidates, otherwise they would falsy report
+ * ID they used as 'directly used' in fourth step. */
+ ID *ntree = (ID *)ntreeFromID(id);
+ if (ntree != NULL) {
+ ntree->tag |= LIB_TAG_DOIT;
+ }
+ }
+ }
}
}
- a = set_listbasepointers(bmain, lbarray);
- while (a--) {
- for (id = lbarray[a]->first; id; id = id->next)
- lib_indirect_test_id(id, lib);
+ /* Fourth step: Try to find circle dependencies between indirectly-linked-only datablocks.
+ * Those are fake 'usages' that prevent their deletion. See T49775 for nice ugly case. */
+ BKE_library_tag_unused_linked_data(bmain, false);
+ for (LinkNode *it = linked_loop_candidates; it; it = it->next) {
+ if (it->link == NULL) {
+ continue;
+ }
+ if ((id = ((LinkNode *)it->link)->link) == NULL) {
+ it->link = NULL;
+ continue;
+ }
+
+ /* Note: in theory here we are only handling datablocks forming exclusive linked dependency-cycles-based
+ * archipelagos, so no need to check again after we have deleted one, as done in previous step. */
+ if (id->tag & LIB_TAG_DOIT) {
+ /* Note: *in theory* IDs tagged here are fully *outside* of file scope, totally unused, so we can
+ * directly wipe them out without caring about clearing their usages.
+ * However, this is a highly-risky presumption, and nice crasher in case something goes wrong here.
+ * So for 2.78a will keep the safe option, and switch to more efficient one in master later. */
+#if 0
+ BKE_libblock_free_ex(bmain, id, false);
+#else
+ BKE_libblock_unlink(bmain, id, false, false);
+ BKE_libblock_free(bmain, id);
+#endif
+ it->link = NULL;
+ }
}
+
+ BLI_memarena_free(linklist_mem);
}
/**
diff --git a/source/blender/blenkernel/intern/library_idmap.c b/source/blender/blenkernel/intern/library_idmap.c
new file mode 100644
index 00000000000..daf097b9f0b
--- /dev/null
+++ b/source/blender/blenkernel/intern/library_idmap.c
@@ -0,0 +1,176 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 *****
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+#include "BLI_listbase.h"
+
+#include "DNA_ID.h"
+
+#include "BKE_idcode.h"
+#include "BKE_library.h"
+#include "BKE_library_idmap.h" /* own include */
+
+/** \file blender/blenkernel/intern/library_idmap.c
+ * \ingroup bke
+ *
+ * Utility functions for faster ID lookups.
+ */
+
+/** \name BKE_main_idmap API
+ *
+ * Cache ID (name, library lookups).
+ * This doesn't account for adding/removing data-blocks,
+ * and should only be used when performing many lookups.
+ *
+ * \note GHash's are initialized on demand,
+ * since its likely some types will never have lookups run on them,
+ * so its a waste to create and never use.
+ * \{ */
+
+struct IDNameLib_Key {
+ /** ``ID.name + 2``: without the ID type prefix, since each id type gets it's own 'map' */
+ const char *name;
+ /** ``ID.lib``: */
+ const Library *lib;
+};
+
+struct IDNameLib_TypeMap {
+ GHash *map;
+ short id_type;
+ /* only for storage of keys in the ghash, avoid many single allocs */
+ struct IDNameLib_Key *keys;
+};
+
+/**
+ * Opaque structure, external API users only see this.
+ */
+struct IDNameLib_Map {
+ struct IDNameLib_TypeMap type_maps[MAX_LIBARRAY];
+ struct Main *bmain;
+};
+
+static struct IDNameLib_TypeMap *main_idmap_from_idcode(struct IDNameLib_Map *id_map, short id_type)
+{
+ for (int i = 0; i < MAX_LIBARRAY; i++) {
+ if (id_map->type_maps[i].id_type == id_type) {
+ return &id_map->type_maps[i];
+ }
+ }
+ return NULL;
+}
+
+struct IDNameLib_Map *BKE_main_idmap_create(struct Main *bmain)
+{
+ struct IDNameLib_Map *id_map = MEM_mallocN(sizeof(*id_map), __func__);
+
+ int index = 0;
+ while (index < MAX_LIBARRAY) {
+ struct IDNameLib_TypeMap *type_map = &id_map->type_maps[index];
+ type_map->map = NULL;
+ type_map->id_type = BKE_idcode_iter_step(&index);
+ BLI_assert(type_map->id_type != 0);
+ }
+ BLI_assert(index == MAX_LIBARRAY);
+
+ id_map->bmain = bmain;
+
+ return id_map;
+}
+
+struct Main *BKE_main_idmap_main_get(struct IDNameLib_Map *id_map)
+{
+ return id_map->bmain;
+}
+
+static unsigned int idkey_hash(const void *ptr)
+{
+ const struct IDNameLib_Key *idkey = ptr;
+ unsigned int key = BLI_ghashutil_strhash(idkey->name);
+ if (idkey->lib) {
+ key ^= BLI_ghashutil_ptrhash(idkey->lib);
+ }
+ return key;
+}
+
+static bool idkey_cmp(const void *a, const void *b)
+{
+ const struct IDNameLib_Key *idkey_a = a;
+ const struct IDNameLib_Key *idkey_b = b;
+ return strcmp(idkey_a->name, idkey_b->name) || (idkey_a->lib != idkey_b->lib);
+}
+
+ID *BKE_main_idmap_lookup(struct IDNameLib_Map *id_map, short id_type, const char *name, const Library *lib)
+{
+ struct IDNameLib_TypeMap *type_map = main_idmap_from_idcode(id_map, id_type);
+
+ if (UNLIKELY(type_map == NULL)) {
+ return NULL;
+ }
+
+ /* lazy init */
+ if (type_map->map == NULL) {
+ ListBase *lb = which_libbase(id_map->bmain, id_type);
+ const int lb_len = BLI_listbase_count(lb);
+ if (lb_len == 0) {
+ return NULL;
+ }
+ type_map->map = BLI_ghash_new_ex(idkey_hash, idkey_cmp, __func__, lb_len);
+ type_map->keys = MEM_mallocN(sizeof(struct IDNameLib_Key) * lb_len, __func__);
+
+ GHash *map = type_map->map;
+ struct IDNameLib_Key *key = type_map->keys;
+
+ for (ID *id = lb->first; id; id = id->next, key++) {
+ key->name = id->name + 2;
+ key->lib = id->lib;
+ BLI_ghash_insert(map, key, id);
+ }
+ }
+
+ const struct IDNameLib_Key key_lookup = {name, lib};
+ return BLI_ghash_lookup(type_map->map, &key_lookup);
+}
+
+ID *BKE_main_idmap_lookup_id(struct IDNameLib_Map *id_map, const ID *id)
+{
+ return BKE_main_idmap_lookup(id_map, GS(id->name), id->name + 2, id->lib);
+}
+
+void BKE_main_idmap_destroy(struct IDNameLib_Map *id_map)
+{
+ struct IDNameLib_TypeMap *type_map = id_map->type_maps;
+ for (int i = 0; i < MAX_LIBARRAY; i++, type_map++) {
+ if (type_map->map) {
+ BLI_ghash_free(type_map->map, NULL, NULL);
+ type_map->map = NULL;
+ MEM_freeN(type_map->keys);
+ }
+ }
+
+ MEM_freeN(id_map);
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index d29d2191602..cec7fbacd80 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -29,6 +29,7 @@
#include <stdlib.h>
+#include "MEM_guardedalloc.h"
#include "DNA_actuator_types.h"
#include "DNA_anim_types.h"
@@ -44,6 +45,7 @@
#include "DNA_linestyle_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
#include "DNA_meta_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_mask_types.h"
@@ -61,6 +63,7 @@
#include "DNA_world_types.h"
#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
#include "BLI_ghash.h"
#include "BLI_linklist_stack.h"
@@ -69,6 +72,7 @@
#include "BKE_fcurve.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_particle.h"
#include "BKE_rigidbody.h"
@@ -84,7 +88,7 @@
if (!((_data)->status & IDWALK_STOP)) { \
const int _flag = (_data)->flag; \
ID *old_id = *(id_pp); \
- const int callback_return = (_data)->callback((_data)->user_data, (_data)->self_id, id_pp, cb_flag); \
+ const int callback_return = (_data)->callback((_data)->user_data, (_data)->self_id, id_pp, cb_flag | (_data)->cd_flag); \
if (_flag & IDWALK_READONLY) { \
BLI_assert(*(id_pp) == old_id); \
} \
@@ -125,6 +129,7 @@ enum {
typedef struct LibraryForeachIDData {
ID *self_id;
int flag;
+ int cd_flag;
LibraryIDLinkCallback callback;
void *user_data;
int status;
@@ -198,9 +203,24 @@ static void library_foreach_actuatorsObjectLooper(
FOREACH_FINALIZE_VOID;
}
+static void library_foreach_nla_strip(LibraryForeachIDData *data, NlaStrip *strip)
+{
+ NlaStrip *substrip;
+
+ FOREACH_CALLBACK_INVOKE(data, strip->act, IDWALK_USER);
+
+ for (substrip = strip->strips.first; substrip; substrip = substrip->next) {
+ library_foreach_nla_strip(data, substrip);
+ }
+
+ FOREACH_FINALIZE_VOID;
+}
+
static void library_foreach_animationData(LibraryForeachIDData *data, AnimData *adt)
{
FCurve *fcu;
+ NlaTrack *nla_track;
+ NlaStrip *nla_strip;
for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
ChannelDriver *driver = fcu->driver;
@@ -216,6 +236,15 @@ static void library_foreach_animationData(LibraryForeachIDData *data, AnimData *
}
}
+ FOREACH_CALLBACK_INVOKE(data, adt->action, IDWALK_USER);
+ FOREACH_CALLBACK_INVOKE(data, adt->tmpact, IDWALK_USER);
+
+ for (nla_track = adt->nla_tracks.first; nla_track; nla_track = nla_track->next) {
+ for (nla_strip = nla_track->strips.first; nla_strip; nla_strip = nla_strip->next) {
+ library_foreach_nla_strip(data, nla_strip);
+ }
+ }
+
FOREACH_FINALIZE_VOID;
}
@@ -227,6 +256,29 @@ static void library_foreach_mtex(LibraryForeachIDData *data, MTex *mtex)
FOREACH_FINALIZE_VOID;
}
+static void library_foreach_paint(LibraryForeachIDData *data, Paint *paint)
+{
+ FOREACH_CALLBACK_INVOKE(data, paint->brush, IDWALK_USER);
+ FOREACH_CALLBACK_INVOKE(data, paint->palette, IDWALK_USER);
+
+ FOREACH_FINALIZE_VOID;
+}
+
+static void library_foreach_ID_as_subdata_link(
+ ID *id, LibraryIDLinkCallback callback, void *user_data, int flag, LibraryForeachIDData *data)
+{
+ if (flag & IDWALK_RECURSE) {
+ /* Defer handling into main loop, recursively calling BKE_library_foreach_ID_link in IDWALK_RECURSE case is
+ * troublesome, see T49553. */
+ if (!BLI_gset_haskey(data->ids_handled, id)) {
+ BLI_gset_add(data->ids_handled, id);
+ BLI_LINKSTACK_PUSH(data->ids_todo, id);
+ }
+ }
+ else {
+ BKE_library_foreach_ID_link(id, callback, user_data, flag);
+ }
+}
/**
* Loop over all of the ID's this datablock links to.
@@ -244,6 +296,8 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
data.ids_handled = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
BLI_LINKSTACK_INIT(data.ids_todo);
+
+ BLI_gset_add(data.ids_handled, id);
}
else {
data.ids_handled = NULL;
@@ -261,13 +315,20 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
do {
data.self_id = id;
+ data.cd_flag = ID_IS_LINKED_DATABLOCK(id) ? IDWALK_INDIRECT_USAGE : 0;
AnimData *adt = BKE_animdata_from_id(id);
if (adt) {
library_foreach_animationData(&data, adt);
}
- switch (GS(id->name)) {
+ switch ((ID_Type)GS(id->name)) {
+ case ID_LI:
+ {
+ Library *lib = (Library *) id;
+ CALLBACK_INVOKE(lib->parent, IDWALK_NOP);
+ break;
+ }
case ID_SCE:
{
Scene *scene = (Scene *) id;
@@ -278,8 +339,11 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
CALLBACK_INVOKE(scene->camera, IDWALK_NOP);
CALLBACK_INVOKE(scene->world, IDWALK_USER);
CALLBACK_INVOKE(scene->set, IDWALK_NOP);
- CALLBACK_INVOKE(scene->clip, IDWALK_NOP);
- CALLBACK_INVOKE(scene->nodetree, IDWALK_NOP);
+ CALLBACK_INVOKE(scene->clip, IDWALK_USER);
+ if (scene->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ library_foreach_ID_as_subdata_link((ID *)scene->nodetree, callback, user_data, flag, &data);
+ }
/* DO NOT handle scene->basact here, it's doubling with the loop over whole scene->base later,
* since basact is just a pointer to one of those items. */
CALLBACK_INVOKE(scene->obedit, IDWALK_NOP);
@@ -318,6 +382,9 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
CALLBACK_INVOKE(seq->clip, IDWALK_USER);
CALLBACK_INVOKE(seq->mask, IDWALK_USER);
CALLBACK_INVOKE(seq->sound, IDWALK_USER);
+ for (SequenceModifierData *smd = seq->modifiers.first; smd; smd = smd->next) {
+ CALLBACK_INVOKE(smd->mask_id, IDWALK_USER);
+ }
}
SEQ_END
}
@@ -328,30 +395,34 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
CALLBACK_INVOKE(base->object, IDWALK_USER);
}
+ for (TimeMarker *marker = scene->markers.first; marker; marker = marker->next) {
+ CALLBACK_INVOKE(marker->camera, IDWALK_NOP);
+ }
+
if (toolsett) {
CALLBACK_INVOKE(toolsett->skgen_template, IDWALK_NOP);
+
CALLBACK_INVOKE(toolsett->particle.scene, IDWALK_NOP);
CALLBACK_INVOKE(toolsett->particle.object, IDWALK_NOP);
CALLBACK_INVOKE(toolsett->particle.shape_object, IDWALK_NOP);
- CALLBACK_INVOKE(toolsett->imapaint.stencil, IDWALK_NOP);
- CALLBACK_INVOKE(toolsett->imapaint.clone, IDWALK_NOP);
- CALLBACK_INVOKE(toolsett->imapaint.canvas, IDWALK_NOP);
+
+ library_foreach_paint(&data, &toolsett->imapaint.paint);
+ CALLBACK_INVOKE(toolsett->imapaint.stencil, IDWALK_USER);
+ CALLBACK_INVOKE(toolsett->imapaint.clone, IDWALK_USER);
+ CALLBACK_INVOKE(toolsett->imapaint.canvas, IDWALK_USER);
+
if (toolsett->vpaint) {
- CALLBACK_INVOKE(toolsett->vpaint->paint.brush, IDWALK_NOP);
- CALLBACK_INVOKE(toolsett->vpaint->paint.palette, IDWALK_NOP);
+ library_foreach_paint(&data, &toolsett->vpaint->paint);
}
if (toolsett->wpaint) {
- CALLBACK_INVOKE(toolsett->wpaint->paint.brush, IDWALK_NOP);
- CALLBACK_INVOKE(toolsett->wpaint->paint.palette, IDWALK_NOP);
+ library_foreach_paint(&data, &toolsett->wpaint->paint);
}
if (toolsett->sculpt) {
- CALLBACK_INVOKE(toolsett->sculpt->paint.brush, IDWALK_NOP);
- CALLBACK_INVOKE(toolsett->sculpt->paint.palette, IDWALK_NOP);
+ library_foreach_paint(&data, &toolsett->sculpt->paint);
CALLBACK_INVOKE(toolsett->sculpt->gravity_object, IDWALK_NOP);
}
if (toolsett->uvsculpt) {
- CALLBACK_INVOKE(toolsett->uvsculpt->paint.brush, IDWALK_NOP);
- CALLBACK_INVOKE(toolsett->uvsculpt->paint.palette, IDWALK_NOP);
+ library_foreach_paint(&data, &toolsett->uvsculpt->paint);
}
}
@@ -369,7 +440,12 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
Object *object = (Object *) id;
ParticleSystem *psys;
+ /* Object is special, proxies make things hard... */
+ const int data_cd_flag = data.cd_flag;
+ const int proxy_cd_flag = (object->proxy || object->proxy_group) ? IDWALK_INDIRECT_USAGE : 0;
+
/* object data special case */
+ data.cd_flag |= proxy_cd_flag;
if (object->type == OB_EMPTY) {
/* empty can have NULL or Image */
CALLBACK_INVOKE_ID(object->data, IDWALK_USER);
@@ -380,17 +456,31 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
CALLBACK_INVOKE_ID(object->data, IDWALK_USER | IDWALK_NEVER_NULL);
}
}
+ data.cd_flag = data_cd_flag;
CALLBACK_INVOKE(object->parent, IDWALK_NOP);
CALLBACK_INVOKE(object->track, IDWALK_NOP);
/* object->proxy is refcounted, but not object->proxy_group... *sigh* */
CALLBACK_INVOKE(object->proxy, IDWALK_USER);
CALLBACK_INVOKE(object->proxy_group, IDWALK_NOP);
+
+ /* Special case!
+ * Since this field is set/owned by 'user' of this ID (and not ID itself), it is only indirect usage
+ * if proxy object is linked... Twisted. */
+ if (object->proxy_from) {
+ data.cd_flag = ID_IS_LINKED_DATABLOCK(object->proxy_from) ? IDWALK_INDIRECT_USAGE : 0;
+ }
CALLBACK_INVOKE(object->proxy_from, IDWALK_NOP);
+ data.cd_flag = data_cd_flag;
+
CALLBACK_INVOKE(object->poselib, IDWALK_USER);
+
+ data.cd_flag |= proxy_cd_flag;
for (i = 0; i < object->totcol; i++) {
CALLBACK_INVOKE(object->mat[i], IDWALK_USER);
}
+ data.cd_flag = data_cd_flag;
+
CALLBACK_INVOKE(object->gpd, IDWALK_USER);
CALLBACK_INVOKE(object->dup_group, IDWALK_USER);
@@ -398,13 +488,17 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
CALLBACK_INVOKE(object->pd->tex, IDWALK_USER);
CALLBACK_INVOKE(object->pd->f_source, IDWALK_NOP);
}
+ /* Note that ob->effect is deprecated, so no need to handle it here. */
if (object->pose) {
bPoseChannel *pchan;
+
+ data.cd_flag |= proxy_cd_flag;
for (pchan = object->pose->chanbase.first; pchan; pchan = pchan->next) {
CALLBACK_INVOKE(pchan->custom, IDWALK_USER);
BKE_constraints_id_loop(&pchan->constraints, library_foreach_constraintObjectLooper, &data);
}
+ data.cd_flag = data_cd_flag;
}
if (object->rigidbody_constraint) {
@@ -426,6 +520,14 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, &data);
}
+ if (object->soft) {
+ CALLBACK_INVOKE(object->soft->collision_group, IDWALK_NOP);
+
+ if (object->soft->effector_weights) {
+ CALLBACK_INVOKE(object->soft->effector_weights->group, IDWALK_NOP);
+ }
+ }
+
BKE_sca_sensors_id_loop(&object->sensors, library_foreach_sensorsObjectLooper, &data);
BKE_sca_controllers_id_loop(&object->controllers, library_foreach_controllersObjectLooper, &data);
BKE_sca_actuators_id_loop(&object->actuators, library_foreach_actuatorsObjectLooper, &data);
@@ -440,6 +542,31 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
for (i = 0; i < mesh->totcol; i++) {
CALLBACK_INVOKE(mesh->mat[i], IDWALK_USER);
}
+
+ /* XXX Really not happy with this - probably texface should rather use some kind of
+ * 'texture slots' and just set indices in each poly/face item - would also save some memory.
+ * Maybe a nice TODO for blender2.8? */
+ if (mesh->mtface || mesh->mtpoly) {
+ for (i = 0; i < mesh->pdata.totlayer; i++) {
+ if (mesh->pdata.layers[i].type == CD_MTEXPOLY) {
+ MTexPoly *txface = (MTexPoly *)mesh->pdata.layers[i].data;
+
+ for (int j = 0; j < mesh->totpoly; j++, txface++) {
+ CALLBACK_INVOKE(txface->tpage, IDWALK_USER_ONE);
+ }
+ }
+ }
+
+ for (i = 0; i < mesh->fdata.totlayer; i++) {
+ if (mesh->fdata.layers[i].type == CD_MTFACE) {
+ MTFace *tface = (MTFace *)mesh->fdata.layers[i].data;
+
+ for (int j = 0; j < mesh->totface; j++, tface++) {
+ CALLBACK_INVOKE(tface->tpage, IDWALK_USER_ONE);
+ }
+ }
+ }
+ }
break;
}
@@ -477,7 +604,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
library_foreach_mtex(&data, material->mtex[i]);
}
}
- CALLBACK_INVOKE(material->nodetree, IDWALK_NOP);
+ if (material->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ library_foreach_ID_as_subdata_link((ID *)material->nodetree, callback, user_data, flag, &data);
+ }
CALLBACK_INVOKE(material->group, IDWALK_USER);
break;
}
@@ -485,7 +615,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
case ID_TE:
{
Tex *texture = (Tex *) id;
- CALLBACK_INVOKE(texture->nodetree, IDWALK_NOP);
+ if (texture->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ library_foreach_ID_as_subdata_link((ID *)texture->nodetree, callback, user_data, flag, &data);
+ }
CALLBACK_INVOKE(texture->ima, IDWALK_USER);
if (texture->env) {
CALLBACK_INVOKE(texture->env->object, IDWALK_NOP);
@@ -515,7 +648,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
library_foreach_mtex(&data, lamp->mtex[i]);
}
}
- CALLBACK_INVOKE(lamp->nodetree, IDWALK_NOP);
+ if (lamp->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ library_foreach_ID_as_subdata_link((ID *)lamp->nodetree, callback, user_data, flag, &data);
+ }
break;
}
@@ -528,6 +664,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
case ID_KE:
{
+ /* XXX Only ID pointer from shapekeys is the 'from' one, which is not actually ID usage.
+ * Maybe we should even nuke it from here, not 100% sure yet...
+ * (see also foreach_libblock_id_users_callback).
+ */
Key *key = (Key *) id;
CALLBACK_INVOKE_ID(key->from, IDWALK_NOP);
break;
@@ -548,7 +688,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
library_foreach_mtex(&data, world->mtex[i]);
}
}
- CALLBACK_INVOKE(world->nodetree, IDWALK_NOP);
+ if (world->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ library_foreach_ID_as_subdata_link((ID *)world->nodetree, callback, user_data, flag, &data);
+ }
break;
}
@@ -597,6 +740,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
CALLBACK_INVOKE(psett->dup_group, IDWALK_NOP);
CALLBACK_INVOKE(psett->dup_ob, IDWALK_NOP);
CALLBACK_INVOKE(psett->bb_ob, IDWALK_NOP);
+ CALLBACK_INVOKE(psett->collision_group, IDWALK_NOP);
for (i = 0; i < MAX_MTEX; i++) {
if (psett->mtex[i]) {
@@ -608,6 +752,15 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
CALLBACK_INVOKE(psett->effector_weights->group, IDWALK_NOP);
}
+ if (psett->pd) {
+ CALLBACK_INVOKE(psett->pd->tex, IDWALK_USER);
+ CALLBACK_INVOKE(psett->pd->f_source, IDWALK_NOP);
+ }
+ if (psett->pd2) {
+ CALLBACK_INVOKE(psett->pd2->tex, IDWALK_USER);
+ CALLBACK_INVOKE(psett->pd2->f_source, IDWALK_NOP);
+ }
+
if (psett->boids) {
BoidState *state;
BoidRule *rule;
@@ -625,7 +778,6 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
}
}
}
-
break;
}
@@ -634,16 +786,23 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
MovieClip *clip = (MovieClip *) id;
MovieTracking *tracking = &clip->tracking;
MovieTrackingObject *object;
+ MovieTrackingTrack *track;
+ MovieTrackingPlaneTrack *plane_track;
CALLBACK_INVOKE(clip->gpd, IDWALK_USER);
- for (object = tracking->objects.first; object; object = object->next) {
- ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
- MovieTrackingTrack *track;
- for (track = tracksbase->first; track; track = track->next) {
+ for (track = tracking->tracks.first; track; track = track->next) {
+ CALLBACK_INVOKE(track->gpd, IDWALK_USER);
+ }
+ for (object = tracking->objects.first; object; object = object->next) {
+ for (track = object->tracks.first; track; track = track->next) {
CALLBACK_INVOKE(track->gpd, IDWALK_USER);
}
}
+
+ for (plane_track = tracking->plane_tracks.first; plane_track; plane_track = plane_track->next) {
+ CALLBACK_INVOKE(plane_track->image, IDWALK_USER);
+ }
break;
}
@@ -673,7 +832,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
library_foreach_mtex(&data, linestyle->mtex[i]);
}
}
- CALLBACK_INVOKE(linestyle->nodetree, IDWALK_NOP);
+ if (linestyle->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ library_foreach_ID_as_subdata_link((ID *)linestyle->nodetree, callback, user_data, flag, &data);
+ }
for (lsm = linestyle->color_modifiers.first; lsm; lsm = lsm->next) {
if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
@@ -701,6 +863,33 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
}
break;
}
+ case ID_AC:
+ {
+ bAction *act = (bAction *) id;
+
+ for (TimeMarker *marker = act->markers.first; marker; marker = marker->next) {
+ CALLBACK_INVOKE(marker->camera, IDWALK_NOP);
+ }
+ break;
+ }
+
+ /* Nothing needed for those... */
+ case ID_IM:
+ case ID_VF:
+ case ID_TXT:
+ case ID_SO:
+ case ID_AR:
+ case ID_GD:
+ case ID_WM:
+ case ID_PAL:
+ case ID_PC:
+ case ID_CF:
+ break;
+
+ /* Deprecated. */
+ case ID_IP:
+ break;
+
}
} while ((id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : NULL));
@@ -731,6 +920,100 @@ void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cd_flag)
}
}
+/**
+ * Say whether given \a id_type_owner can use (in any way) a datablock of \a id_type_used.
+ *
+ * This is a 'simplified' abstract version of #BKE_library_foreach_ID_link() above, quite useful to reduce
+ * useless iterations in some cases.
+ */
+/* XXX This has to be fully rethink, basing check on ID type is not really working anymore (and even worth once
+ * IDProps will support ID pointers), we'll have to do some quick checks on IDs themselves... */
+bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id_type_used)
+{
+ if (id_type_can_have_animdata(id_type_owner)) {
+ return true; /* AnimationData can use virtually any kind of datablocks, through drivers especially. */
+ }
+
+ switch ((ID_Type)id_type_owner) {
+ case ID_LI:
+ return ELEM(id_type_used, ID_LI);
+ case ID_SCE:
+ return (ELEM(id_type_used, ID_OB, ID_WO, ID_SCE, ID_MC, ID_MA, ID_GR, ID_TXT,
+ ID_LS, ID_MSK, ID_SO, ID_GD, ID_BR, ID_PAL, ID_IM, ID_NT) ||
+ BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+ case ID_OB:
+ /* Could be the following, but simpler to just always say 'yes' here. */
+#if 0
+ return ELEM(id_type_used, ID_ME, ID_CU, ID_MB, ID_LT, ID_SPK, ID_AR, ID_LA, ID_CA, /* obdata */
+ ID_OB, ID_MA, ID_GD, ID_GR, ID_TE, ID_PA, ID_TXT, ID_SO, ID_MC, ID_IM, ID_AC
+ /* + constraints, modifiers and game logic ID types... */);
+#else
+ return true;
+#endif
+ case ID_ME:
+ return ELEM(id_type_used, ID_ME, ID_KE, ID_MA);
+ case ID_CU:
+ return ELEM(id_type_used, ID_OB, ID_KE, ID_MA, ID_VF);
+ case ID_MB:
+ return ELEM(id_type_used, ID_MA);
+ case ID_MA:
+ return (ELEM(id_type_used, ID_TE, ID_GR) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+ case ID_TE:
+ return (ELEM(id_type_used, ID_IM, ID_OB) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+ case ID_LT:
+ return ELEM(id_type_used, ID_KE);
+ case ID_LA:
+ return (ELEM(id_type_used, ID_TE) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+ case ID_CA:
+ return ELEM(id_type_used, ID_OB);
+ case ID_KE:
+ return ELEM(id_type_used, ID_ME, ID_CU, ID_LT); /* Warning! key->from, could be more types in future? */
+ case ID_SCR:
+ return ELEM(id_type_used, ID_SCE);
+ case ID_WO:
+ return (ELEM(id_type_used, ID_TE) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+ case ID_SPK:
+ return ELEM(id_type_used, ID_SO);
+ case ID_GR:
+ return ELEM(id_type_used, ID_OB);
+ case ID_NT:
+ /* Could be the following, but node.id has no type restriction... */
+#if 0
+ return ELEM(id_type_used, ID_GD /* + node.id types... */);
+#else
+ return true;
+#endif
+ case ID_BR:
+ return ELEM(id_type_used, ID_BR, ID_IM, ID_PC, ID_TE);
+ case ID_PA:
+ return ELEM(id_type_used, ID_OB, ID_GR, ID_TE);
+ case ID_MC:
+ return ELEM(id_type_used, ID_GD, ID_IM);
+ case ID_MSK:
+ return ELEM(id_type_used, ID_MC); /* WARNING! mask->parent.id, not typed. */
+ case ID_LS:
+ return (ELEM(id_type_used, ID_TE, ID_OB) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+ case ID_IM:
+ case ID_VF:
+ case ID_TXT:
+ case ID_SO:
+ case ID_AR:
+ case ID_AC:
+ case ID_GD:
+ case ID_WM:
+ case ID_PAL:
+ case ID_PC:
+ case ID_CF:
+ /* Those types never use/reference other IDs... */
+ return false;
+ case ID_IP:
+ /* Deprecated... */
+ return false;
+ }
+ return false;
+}
+
+
/* ***** ID users iterator. ***** */
typedef struct IDUsersIter {
ID *id;
@@ -739,15 +1022,40 @@ typedef struct IDUsersIter {
int lb_idx;
ID *curr_id;
- int count; /* Set by callback. */
+ int count_direct, count_indirect; /* Set by callback. */
} IDUsersIter;
-static int foreach_libblock_id_users_callback(void *user_data, ID *UNUSED(self_id), ID **id_p, int UNUSED(cb_flag))
+static int foreach_libblock_id_users_callback(void *user_data, ID *self_id, ID **id_p, int cb_flag)
{
IDUsersIter *iter = user_data;
- if (*id_p && (*id_p == iter->id)) {
- iter->count++;
+ if (*id_p) {
+ /* XXX This is actually some kind of hack...
+ * Issue is, shapekeys' 'from' ID pointer is not actually ID usage.
+ * Maybe we should even nuke it from BKE_library_foreach_ID_link, not 100% sure yet...
+ */
+ if ((GS(self_id->name) == ID_KE) && (((Key *)self_id)->from == *id_p)) {
+ return IDWALK_RET_NOP;
+ }
+ /* XXX another hack, for similar reasons as above one. */
+ if ((GS(self_id->name) == ID_OB) && (((Object *)self_id)->proxy_from == (Object *)*id_p)) {
+ return IDWALK_RET_NOP;
+ }
+
+ if (*id_p == iter->id) {
+#if 0
+ printf("%s uses %s (refcounted: %d, userone: %d, used_one: %d, used_one_active: %d, indirect_usage: %d)\n",
+ iter->curr_id->name, iter->id->name, (cb_flag & IDWALK_USER) ? 1 : 0, (cb_flag & IDWALK_USER_ONE) ? 1 : 0,
+ (iter->id->tag & LIB_TAG_EXTRAUSER) ? 1 : 0, (iter->id->tag & LIB_TAG_EXTRAUSER_SET) ? 1 : 0,
+ (cb_flag & IDWALK_INDIRECT_USAGE) ? 1 : 0);
+#endif
+ if (cb_flag & IDWALK_INDIRECT_USAGE) {
+ iter->count_indirect++;
+ }
+ else {
+ iter->count_direct++;
+ }
+ }
}
return IDWALK_RET_NOP;
@@ -770,9 +1078,162 @@ int BKE_library_ID_use_ID(ID *id_user, ID *id_used)
/* We do not care about iter.lb_array/lb_idx here... */
iter.id = id_used;
iter.curr_id = id_user;
- iter.count = 0;
+ iter.count_direct = iter.count_indirect = 0;
BKE_library_foreach_ID_link(iter.curr_id, foreach_libblock_id_users_callback, (void *)&iter, IDWALK_NOP);
- return iter.count;
+ return iter.count_direct + iter.count_indirect;
+}
+
+static bool library_ID_is_used(Main *bmain, void *idv, const bool check_linked)
+{
+ IDUsersIter iter;
+ ListBase *lb_array[MAX_LIBARRAY];
+ ID *id = idv;
+ int i = set_listbasepointers(bmain, lb_array);
+ bool is_defined = false;
+
+ iter.id = id;
+ iter.count_direct = iter.count_indirect = 0;
+ while (i-- && !is_defined) {
+ ID *id_curr = lb_array[i]->first;
+
+ if (!id_curr || !BKE_library_idtype_can_use_idtype(GS(id_curr->name), GS(id->name))) {
+ continue;
+ }
+
+ for (; id_curr && !is_defined; id_curr = id_curr->next) {
+ if (id_curr == id) {
+ /* We are not interested in self-usages (mostly from drivers or bone constraints...). */
+ continue;
+ }
+ iter.curr_id = id_curr;
+ BKE_library_foreach_ID_link(
+ id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_NOP);
+
+ is_defined = ((check_linked ? iter.count_indirect : iter.count_direct) != 0);
+ }
+ }
+
+ return is_defined;
+}
+
+/**
+ * Check whether given ID is used locally (i.e. by another non-linked ID).
+ */
+bool BKE_library_ID_is_locally_used(Main *bmain, void *idv)
+{
+ return library_ID_is_used(bmain, idv, false);
+}
+
+/**
+ * Check whether given ID is used indirectly (i.e. by another linked ID).
+ */
+bool BKE_library_ID_is_indirectly_used(Main *bmain, void *idv)
+{
+ return library_ID_is_used(bmain, idv, true);
+}
+
+/**
+ * Combine \a BKE_library_ID_is_locally_used() and \a BKE_library_ID_is_indirectly_used() in a single call.
+ */
+void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *is_used_local, bool *is_used_linked)
+{
+ IDUsersIter iter;
+ ListBase *lb_array[MAX_LIBARRAY];
+ ID *id = idv;
+ int i = set_listbasepointers(bmain, lb_array);
+ bool is_defined = false;
+
+ iter.id = id;
+ iter.count_direct = iter.count_indirect = 0;
+ while (i-- && !is_defined) {
+ ID *id_curr = lb_array[i]->first;
+
+ if (!id_curr || !BKE_library_idtype_can_use_idtype(GS(id_curr->name), GS(id->name))) {
+ continue;
+ }
+
+ for (; id_curr && !is_defined; id_curr = id_curr->next) {
+ if (id_curr == id) {
+ /* We are not interested in self-usages (mostly from drivers or bone constraints...). */
+ continue;
+ }
+ iter.curr_id = id_curr;
+ BKE_library_foreach_ID_link(id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_NOP);
+
+ is_defined = (iter.count_direct != 0 && iter.count_indirect != 0);
+ }
+ }
+
+ *is_used_local = (iter.count_direct != 0);
+ *is_used_linked = (iter.count_indirect != 0);
+}
+
+
+static int foreach_libblock_tag_unused_linked_data_callback(void *user_data, ID *self_id, ID **id_p, int UNUSED(cb_flag))
+{
+ bool *is_changed = user_data;
+
+ if (*id_p) {
+ /* XXX This is actually some kind of hack...
+ * Issue is, shapekeys' 'from' ID pointer is not actually ID usage.
+ * Maybe we should even nuke it from BKE_library_foreach_ID_link, not 100% sure yet...
+ */
+ if ((GS(self_id->name) == ID_KE) && (((Key *)self_id)->from == *id_p)) {
+ return IDWALK_RET_NOP;
+ }
+ /* XXX another hack, for similar reasons as above one. */
+ if ((GS(self_id->name) == ID_OB) && (((Object *)self_id)->proxy_from == (Object *)*id_p)) {
+ return IDWALK_RET_NOP;
+ }
+
+ /* If checked id is used by an assumed used ID, then it is also used and not part of any linked archipelago. */
+ if (!(self_id->tag & LIB_TAG_DOIT) && ((*id_p)->tag & LIB_TAG_DOIT)) {
+ (*id_p)->tag &= ~LIB_TAG_DOIT;
+ *is_changed = true;
+ }
+ }
+
+ return IDWALK_RET_NOP;
+}
+
+/**
+ * Detect orphaned linked data blocks (i.e. linked data not used (directly or indirectly) in any way by any local data),
+ * including complex cases like 'linked archipelagoes', i.e. linked datablocks that use each other in loops,
+ * which prevents their deletion by 'basic' usage checks...
+ *
+ * \param do_init_tag if \a true, all linked data are checked, if \a false, only linked datablocks already tagged with
+ * LIB_TAG_DOIT are checked.
+ */
+void BKE_library_tag_unused_linked_data(Main *bmain, const bool do_init_tag)
+{
+ ListBase *lb_array[MAX_LIBARRAY];
+
+ if (do_init_tag) {
+ int i = set_listbasepointers(bmain, lb_array);
+
+ while (i--) {
+ for (ID *id = lb_array[i]->first; id; id = id->next) {
+ if (id->lib && (id->tag & LIB_TAG_INDIRECT) != 0) {
+ id->tag |= LIB_TAG_DOIT;
+ }
+ else {
+ id->tag &= ~LIB_TAG_DOIT;
+ }
+ }
+ }
+ }
+
+ bool do_loop = true;
+ while (do_loop) {
+ int i = set_listbasepointers(bmain, lb_array);
+ do_loop = false;
+
+ while (i--) {
+ for (ID *id = lb_array[i]->first; id; id = id->next) {
+ BKE_library_foreach_ID_link(id, foreach_libblock_tag_unused_linked_data_callback, &do_loop, IDWALK_NOP);
+ }
+ }
+ }
}
diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c
new file mode 100644
index 00000000000..b468e6436c8
--- /dev/null
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -0,0 +1,926 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/library_remap.c
+ * \ingroup bke
+ *
+ * Contains management of ID's and libraries remap, unlink and free logic.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <assert.h>
+
+#include "MEM_guardedalloc.h"
+
+/* all types are needed here, in order to do memory operations */
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_brush_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_cachefile_types.h"
+#include "DNA_group_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_linestyle_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_movieclip_types.h"
+#include "DNA_mask_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_speaker_types.h"
+#include "DNA_sound_types.h"
+#include "DNA_text_types.h"
+#include "DNA_vfont_types.h"
+#include "DNA_windowmanager_types.h"
+#include "DNA_world_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_action.h"
+#include "BKE_animsys.h"
+#include "BKE_armature.h"
+#include "BKE_brush.h"
+#include "BKE_camera.h"
+#include "BKE_cachefile.h"
+#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
+#include "BKE_fcurve.h"
+#include "BKE_font.h"
+#include "BKE_group.h"
+#include "BKE_gpencil.h"
+#include "BKE_idprop.h"
+#include "BKE_image.h"
+#include "BKE_ipo.h"
+#include "BKE_key.h"
+#include "BKE_lamp.h"
+#include "BKE_lattice.h"
+#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
+#include "BKE_linestyle.h"
+#include "BKE_mesh.h"
+#include "BKE_material.h"
+#include "BKE_main.h"
+#include "BKE_mask.h"
+#include "BKE_mball.h"
+#include "BKE_modifier.h"
+#include "BKE_movieclip.h"
+#include "BKE_multires.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_particle.h"
+#include "BKE_sca.h"
+#include "BKE_speaker.h"
+#include "BKE_sound.h"
+#include "BKE_screen.h"
+#include "BKE_scene.h"
+#include "BKE_text.h"
+#include "BKE_texture.h"
+#include "BKE_world.h"
+
+#ifdef WITH_PYTHON
+#include "BPY_extern.h"
+#endif
+
+static BKE_library_free_window_manager_cb free_windowmanager_cb = NULL;
+
+void BKE_library_callback_free_window_manager_set(BKE_library_free_window_manager_cb func)
+{
+ free_windowmanager_cb = func;
+}
+
+static BKE_library_free_notifier_reference_cb free_notifier_reference_cb = NULL;
+
+void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func)
+{
+ free_notifier_reference_cb = func;
+}
+
+static BKE_library_remap_editor_id_reference_cb remap_editor_id_reference_cb = NULL;
+
+void BKE_library_callback_remap_editor_id_reference_set(BKE_library_remap_editor_id_reference_cb func)
+{
+ remap_editor_id_reference_cb = func;
+}
+
+typedef struct IDRemap {
+ Main *bmain; /* Only used to trigger depsgraph updates in the right bmain. */
+ ID *old_id;
+ ID *new_id;
+ ID *id; /* The ID in which we are replacing old_id by new_id usages. */
+ short flag;
+
+ /* 'Output' data. */
+ short status;
+ int skipped_direct; /* Number of direct usecases that could not be remapped (e.g.: obdata when in edit mode). */
+ int skipped_indirect; /* Number of indirect usecases that could not be remapped. */
+ int skipped_refcounted; /* Number of skipped usecases that refcount the datablock. */
+} IDRemap;
+
+/* IDRemap->flag enums defined in BKE_library.h */
+
+/* IDRemap->status */
+enum {
+ /* *** Set by callback. *** */
+ ID_REMAP_IS_LINKED_DIRECT = 1 << 0, /* new_id is directly linked in current .blend. */
+ ID_REMAP_IS_USER_ONE_SKIPPED = 1 << 1, /* There was some skipped 'user_one' usages of old_id. */
+};
+
+static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id_p, int cb_flag)
+{
+ IDRemap *id_remap_data = user_data;
+ ID *old_id = id_remap_data->old_id;
+ ID *new_id = id_remap_data->new_id;
+ ID *id = id_remap_data->id;
+
+ if (!old_id) { /* Used to cleanup all IDs used by a specific one. */
+ BLI_assert(!new_id);
+ old_id = *id_p;
+ }
+
+ if (*id_p && (*id_p == old_id)) {
+ const bool is_indirect = (cb_flag & IDWALK_INDIRECT_USAGE) != 0;
+ const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
+ /* Note: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct,
+ * on the other hand since they get reset to lib data on file open/reload it is indirect too...
+ * Edit Mode is also a 'skip direct' case. */
+ const bool is_obj = (GS(id->name) == ID_OB);
+ const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id));
+ const bool is_never_null = ((cb_flag & IDWALK_NEVER_NULL) && (new_id == NULL) &&
+ (id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0);
+ const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0;
+
+#ifdef DEBUG_PRINT
+ printf("In %s: Remapping %s (%p) to %s (%p) (skip_indirect: %d)\n",
+ id->name, old_id->name, old_id, new_id ? new_id->name : "<NONE>", new_id, skip_indirect);
+#endif
+
+ if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) && (cb_flag & IDWALK_NEVER_NULL)) {
+ id->tag |= LIB_TAG_DOIT;
+ }
+
+ /* Special hack in case it's Object->data and we are in edit mode (skipped_direct too). */
+ if ((is_never_null && skip_never_null) ||
+ (is_obj_editmode && (((Object *)id)->data == *id_p)) ||
+ (skip_indirect && is_indirect))
+ {
+ if (is_indirect) {
+ id_remap_data->skipped_indirect++;
+ }
+ else if (is_never_null || is_obj_editmode) {
+ id_remap_data->skipped_direct++;
+ }
+ else {
+ BLI_assert(0);
+ }
+ if (cb_flag & IDWALK_USER) {
+ id_remap_data->skipped_refcounted++;
+ }
+ else if (cb_flag & IDWALK_USER_ONE) {
+ /* No need to count number of times this happens, just a flag is enough. */
+ id_remap_data->status |= ID_REMAP_IS_USER_ONE_SKIPPED;
+ }
+ }
+ else {
+ if (!is_never_null) {
+ *id_p = new_id;
+ DAG_id_tag_update_ex(id_remap_data->bmain, id_self, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ }
+ if (cb_flag & IDWALK_USER) {
+ id_us_min(old_id);
+ /* We do not want to handle LIB_TAG_INDIRECT/LIB_TAG_EXTERN here. */
+ if (new_id)
+ new_id->us++;
+ }
+ else if (cb_flag & IDWALK_USER_ONE) {
+ id_us_ensure_real(new_id);
+ /* We cannot affect old_id->us directly, LIB_TAG_EXTRAUSER(_SET) are assumed to be set as needed,
+ * that extra user is processed in final handling... */
+ }
+ if (!is_indirect) {
+ id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT;
+ }
+ }
+ }
+
+ return IDWALK_RET_NOP;
+}
+
+/* Some reamapping unfortunately require extra and/or specific handling, tackle those here. */
+static void libblock_remap_data_preprocess_scene_base_unlink(
+ IDRemap *r_id_remap_data, Scene *sce, Base *base, const bool skip_indirect, const bool is_indirect)
+{
+ if (skip_indirect && is_indirect) {
+ r_id_remap_data->skipped_indirect++;
+ r_id_remap_data->skipped_refcounted++;
+ }
+ else {
+ id_us_min((ID *)base->object);
+ BKE_scene_base_unlink(sce, base);
+ MEM_freeN(base);
+ if (!is_indirect) {
+ r_id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT;
+ }
+ }
+}
+
+static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data)
+{
+ switch (GS(r_id_remap_data->id->name)) {
+ case ID_SCE:
+ {
+ Scene *sce = (Scene *)r_id_remap_data->id;
+
+ if (!r_id_remap_data->new_id) {
+ const bool is_indirect = (sce->id.lib != NULL);
+ const bool skip_indirect = (r_id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
+
+ /* In case we are unlinking... */
+ if (!r_id_remap_data->old_id) {
+ /* ... everything from scene. */
+ Base *base, *base_next;
+ for (base = sce->base.first; base; base = base_next) {
+ base_next = base->next;
+ libblock_remap_data_preprocess_scene_base_unlink(
+ r_id_remap_data, sce, base, skip_indirect, is_indirect);
+ }
+ }
+ else if (GS(r_id_remap_data->old_id->name) == ID_OB) {
+ /* ... a specific object from scene. */
+ Object *old_ob = (Object *)r_id_remap_data->old_id;
+ Base *base = BKE_scene_base_find(sce, old_ob);
+
+ if (base) {
+ libblock_remap_data_preprocess_scene_base_unlink(
+ r_id_remap_data, sce, base, skip_indirect, is_indirect);
+ }
+ }
+ }
+ break;
+ }
+ case ID_OB:
+ {
+ ID *old_id = r_id_remap_data->old_id;
+ if (!old_id || GS(old_id->name) == ID_AR) {
+ Object *ob = (Object *)r_id_remap_data->id;
+ /* Object's pose holds reference to armature bones... sic */
+ /* Note that in theory, we should have to bother about linked/non-linked/never-null/etc. flags/states.
+ * Fortunately, this is just a tag, so we can accept to 'over-tag' a bit for pose recalc, and avoid
+ * another complex and risky condition nightmare like the one we have in
+ * foreach_libblock_remap_callback()... */
+ if (ob->pose && (!old_id || ob->data == old_id)) {
+ BLI_assert(ob->type == OB_ARMATURE);
+ ob->pose->flag |= POSE_RECALC;
+ /* We need to clear pose bone pointers immediately, things like undo writefile may be called
+ * before pose is actually recomputed, can lead to segfault... */
+ BKE_pose_clear_pointers(ob->pose);
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static void libblock_remap_data_postprocess_object_fromgroup_update(Main *bmain, Object *old_ob, Object *new_ob)
+{
+ if (old_ob->flag & OB_FROMGROUP) {
+ /* Note that for Scene's BaseObject->flag, either we:
+ * - unlinked old_ob (i.e. new_ob is NULL), in which case scenes' bases have been removed already.
+ * - remapped old_ob by new_ob, in which case scenes' bases are still valid as is.
+ * So in any case, no need to update them here. */
+ if (BKE_group_object_find(NULL, old_ob) == NULL) {
+ old_ob->flag &= ~OB_FROMGROUP;
+ }
+ if (new_ob == NULL) { /* We need to remove NULL-ified groupobjects... */
+ for (Group *group = bmain->group.first; group; group = group->id.next) {
+ BKE_group_object_unlink(group, NULL, NULL, NULL);
+ }
+ }
+ else {
+ new_ob->flag |= OB_FROMGROUP;
+ }
+ }
+}
+
+static void libblock_remap_data_postprocess_group_scene_unlink(Main *UNUSED(bmain), Scene *sce, ID *old_id)
+{
+ /* Note that here we assume no object has no base (i.e. all objects are assumed instanced
+ * in one scene...). */
+ for (Base *base = sce->base.first; base; base = base->next) {
+ if (base->flag & OB_FROMGROUP) {
+ Object *ob = base->object;
+
+ if (ob->flag & OB_FROMGROUP) {
+ Group *grp = BKE_group_object_find(NULL, ob);
+
+ /* Unlinked group (old_id) is still in bmain... */
+ if (grp && (&grp->id == old_id || grp->id.us == 0)) {
+ grp = BKE_group_object_find(grp, ob);
+ }
+ if (!grp) {
+ ob->flag &= ~OB_FROMGROUP;
+ }
+ }
+ if (!(ob->flag & OB_FROMGROUP)) {
+ base->flag &= ~OB_FROMGROUP;
+ }
+ }
+ }
+}
+
+static void libblock_remap_data_postprocess_obdata_relink(Main *UNUSED(bmain), Object *ob, ID *new_id)
+{
+ if (ob->data == new_id) {
+ switch (GS(new_id->name)) {
+ case ID_ME:
+ multires_force_update(ob);
+ break;
+ case ID_CU:
+ BKE_curve_type_test(ob);
+ break;
+ default:
+ break;
+ }
+ test_object_modifiers(ob);
+ test_object_materials(ob, new_id);
+ }
+}
+
+/**
+ * Execute the 'data' part of the remapping (that is, all ID pointers from other ID datablocks).
+ *
+ * Behavior differs depending on whether given \a id is NULL or not:
+ * - \a id NULL: \a old_id must be non-NULL, \a new_id may be NULL (unlinking \a old_id) or not
+ * (remapping \a old_id to \a new_id). The whole \a bmain database is checked, and all pointers to \a old_id
+ * are remapped to \a new_id.
+ * - \a id is non-NULL:
+ * + If \a old_id is NULL, \a new_id must also be NULL, and all ID pointers from \a id are cleared (i.e. \a id
+ * does not references any other datablock anymore).
+ * + If \a old_id is non-NULL, behavior is as with a NULL \a id, but only within given \a id.
+ *
+ * \param bmain: the Main data storage to operate on (must never be NULL).
+ * \param id: the datablock to operate on (can be NULL, in which case we operate over all IDs from given bmain).
+ * \param old_id: the datablock to dereference (may be NULL if \a id is non-NULL).
+ * \param new_id: the new datablock to replace \a old_id references with (may be NULL).
+ * \param r_id_remap_data: if non-NULL, the IDRemap struct to use (uselful to retrieve info about remapping process).
+ */
+ATTR_NONNULL(1) static void libblock_remap_data(
+ Main *bmain, ID *id, ID *old_id, ID *new_id, const short remap_flags, IDRemap *r_id_remap_data)
+{
+ IDRemap id_remap_data;
+ ListBase *lb_array[MAX_LIBARRAY];
+ int i;
+
+ if (r_id_remap_data == NULL) {
+ r_id_remap_data = &id_remap_data;
+ }
+ r_id_remap_data->bmain = bmain;
+ r_id_remap_data->old_id = old_id;
+ r_id_remap_data->new_id = new_id;
+ r_id_remap_data->id = NULL;
+ r_id_remap_data->flag = remap_flags;
+ r_id_remap_data->status = 0;
+ r_id_remap_data->skipped_direct = 0;
+ r_id_remap_data->skipped_indirect = 0;
+ r_id_remap_data->skipped_refcounted = 0;
+
+ if (id) {
+#ifdef DEBUG_PRINT
+ printf("\tchecking id %s (%p, %p)\n", id->name, id, id->lib);
+#endif
+ r_id_remap_data->id = id;
+ libblock_remap_data_preprocess(r_id_remap_data);
+ BKE_library_foreach_ID_link(id, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
+ }
+ else {
+ i = set_listbasepointers(bmain, lb_array);
+
+ /* Note that this is a very 'bruteforce' approach, maybe we could use some depsgraph to only process
+ * objects actually using given old_id... sounds rather unlikely currently, though, so this will do for now. */
+
+ while (i--) {
+ ID *id_curr = lb_array[i]->first;
+
+ if (!id_curr || !BKE_library_idtype_can_use_idtype(GS(id_curr->name), GS(old_id->name))) {
+ continue;
+ }
+
+ for (; id_curr; id_curr = id_curr->next) {
+ /* Note that we cannot skip indirect usages of old_id here (if requested), we still need to check it for
+ * the user count handling...
+ * XXX No more true (except for debug usage of those skipping counters). */
+ r_id_remap_data->id = id_curr;
+ libblock_remap_data_preprocess(r_id_remap_data);
+ BKE_library_foreach_ID_link(
+ id_curr, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
+ }
+ }
+ }
+
+ if (old_id && GS(old_id->name) == ID_OB) {
+ BKE_sca_logic_links_remap(bmain, (Object *)old_id, (Object *)new_id);
+ }
+
+ /* XXX We may not want to always 'transfer' fakeuser from old to new id... Think for now it's desired behavior
+ * though, we can always add an option (flag) to control this later if needed. */
+ if (old_id && (old_id->flag & LIB_FAKEUSER)) {
+ id_fake_user_clear(old_id);
+ id_fake_user_set(new_id);
+ }
+
+ id_us_clear_real(old_id);
+
+ if (new_id && (new_id->tag & LIB_TAG_INDIRECT) && (r_id_remap_data->status & ID_REMAP_IS_LINKED_DIRECT)) {
+ new_id->tag &= ~LIB_TAG_INDIRECT;
+ new_id->tag |= LIB_TAG_EXTERN;
+ }
+
+#ifdef DEBUG_PRINT
+ printf("%s: %d occurences skipped (%d direct and %d indirect ones)\n", __func__,
+ r_id_remap_data->skipped_direct + r_id_remap_data->skipped_indirect,
+ r_id_remap_data->skipped_direct, r_id_remap_data->skipped_indirect);
+#endif
+}
+
+/**
+ * Replace all references in given Main to \a old_id by \a new_id
+ * (if \a new_id is NULL, it unlinks \a old_id).
+ */
+void BKE_libblock_remap_locked(
+ Main *bmain, void *old_idv, void *new_idv,
+ const short remap_flags)
+{
+ IDRemap id_remap_data;
+ ID *old_id = old_idv;
+ ID *new_id = new_idv;
+ int skipped_direct, skipped_refcounted;
+
+ BLI_assert(old_id != NULL);
+ BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name));
+ BLI_assert(old_id != new_id);
+
+ libblock_remap_data(bmain, NULL, old_id, new_id, remap_flags, &id_remap_data);
+
+ if (free_notifier_reference_cb) {
+ free_notifier_reference_cb(old_id);
+ }
+
+ /* We assume editors do not hold references to their IDs... This is false in some cases
+ * (Image is especially tricky here), editors' code is to handle refcount (id->us) itself then. */
+ if (remap_editor_id_reference_cb) {
+ remap_editor_id_reference_cb(old_id, new_id);
+ }
+
+ skipped_direct = id_remap_data.skipped_direct;
+ skipped_refcounted = id_remap_data.skipped_refcounted;
+
+ /* If old_id was used by some ugly 'user_one' stuff (like Image or Clip editors...), and user count has actually
+ * been incremented for that, we have to decrease once more its user count... unless we had to skip
+ * some 'user_one' cases. */
+ if ((old_id->tag & LIB_TAG_EXTRAUSER_SET) && !(id_remap_data.status & ID_REMAP_IS_USER_ONE_SKIPPED)) {
+ id_us_min(old_id);
+ old_id->tag &= ~LIB_TAG_EXTRAUSER_SET;
+ }
+
+ BLI_assert(old_id->us - skipped_refcounted >= 0);
+ UNUSED_VARS_NDEBUG(skipped_refcounted);
+
+ if (skipped_direct == 0) {
+ /* old_id is assumed to not be used directly anymore... */
+ if (old_id->lib && (old_id->tag & LIB_TAG_EXTERN)) {
+ old_id->tag &= ~LIB_TAG_EXTERN;
+ old_id->tag |= LIB_TAG_INDIRECT;
+ }
+ }
+
+ /* Some after-process updates.
+ * This is a bit ugly, but cannot see a way to avoid it. Maybe we should do a per-ID callback for this instead?
+ */
+ switch (GS(old_id->name)) {
+ case ID_OB:
+ libblock_remap_data_postprocess_object_fromgroup_update(bmain, (Object *)old_id, (Object *)new_id);
+ break;
+ case ID_GR:
+ if (!new_id) { /* Only affects us in case group was unlinked. */
+ for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) {
+ libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, old_id);
+ }
+ }
+ break;
+ case ID_ME:
+ case ID_CU:
+ case ID_MB:
+ if (new_id) { /* Only affects us in case obdata was relinked (changed). */
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ libblock_remap_data_postprocess_obdata_relink(bmain, ob, new_id);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* Full rebuild of DAG! */
+ DAG_relations_tag_update(bmain);
+}
+
+void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, const short remap_flags)
+{
+ BKE_main_lock(bmain);
+
+ BKE_libblock_remap_locked(bmain, old_idv, new_idv, remap_flags);
+
+ BKE_main_unlock(bmain);
+}
+
+/**
+ * Unlink given \a id from given \a bmain (does not touch to indirect, i.e. library, usages of the ID).
+ *
+ * \param do_flag_never_null: If true, all IDs using \a idv in a 'non-NULL' way are flagged by \a LIB_TAG_DOIT flag
+ * (quite obviously, 'non-NULL' usages can never be unlinked by this function...).
+ */
+void BKE_libblock_unlink(Main *bmain, void *idv, const bool do_flag_never_null, const bool do_skip_indirect)
+{
+ const short remap_flags = (do_skip_indirect ? ID_REMAP_SKIP_INDIRECT_USAGE : 0) |
+ (do_flag_never_null ? ID_REMAP_FLAG_NEVER_NULL_USAGE : 0);
+
+ BKE_main_lock(bmain);
+
+ BKE_libblock_remap_locked(bmain, idv, NULL, remap_flags);
+
+ BKE_main_unlock(bmain);
+}
+
+/** Similar to libblock_remap, but only affects IDs used by given \a idv ID.
+ *
+ * \param old_idv: Unlike BKE_libblock_remap, can be NULL,
+ * in which case all ID usages by given \a idv will be cleared.
+ * \param us_min_never_null: If \a true and new_id is NULL,
+ * 'NEVER_NULL' ID usages keep their old id, but this one still gets its user count decremented
+ * (needed when given \a idv is going to be deleted right after being unlinked).
+ */
+/* Should be able to replace all _relink() funcs (constraints, rigidbody, etc.) ? */
+/* XXX Arg! Naming... :(
+ * _relink? avoids confusion with _remap, but is confusing with _unlink
+ * _remap_used_ids?
+ * _remap_datablocks?
+ * BKE_id_remap maybe?
+ * ... sigh
+ */
+void BKE_libblock_relink_ex(
+ Main *bmain, void *idv, void *old_idv, void *new_idv, const bool us_min_never_null)
+{
+ ID *id = idv;
+ ID *old_id = old_idv;
+ ID *new_id = new_idv;
+ int remap_flags = us_min_never_null ? 0 : ID_REMAP_SKIP_NEVER_NULL_USAGE;
+
+ /* No need to lock here, we are only affecting given ID, not bmain database. */
+
+ BLI_assert(id);
+ if (old_id) {
+ BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name));
+ BLI_assert(old_id != new_id);
+ }
+ else {
+ BLI_assert(new_id == NULL);
+ }
+
+ libblock_remap_data(bmain, id, old_id, new_id, remap_flags, NULL);
+
+ /* Some after-process updates.
+ * This is a bit ugly, but cannot see a way to avoid it. Maybe we should do a per-ID callback for this instead?
+ */
+ switch (GS(id->name)) {
+ case ID_SCE:
+ {
+ Scene *sce = (Scene *)id;
+
+ if (old_id) {
+ switch (GS(old_id->name)) {
+ case ID_OB:
+ {
+ libblock_remap_data_postprocess_object_fromgroup_update(
+ bmain, (Object *)old_id, (Object *)new_id);
+ break;
+ }
+ case ID_GR:
+ if (!new_id) { /* Only affects us in case group was unlinked. */
+ libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, old_id);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ else {
+ /* No choice but to check whole objects/groups. */
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ libblock_remap_data_postprocess_object_fromgroup_update(bmain, ob, NULL);
+ }
+ for (Group *grp = bmain->group.first; grp; grp = grp->id.next) {
+ libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, NULL);
+ }
+ }
+ break;
+ }
+ case ID_OB:
+ if (new_id) { /* Only affects us in case obdata was relinked (changed). */
+ libblock_remap_data_postprocess_obdata_relink(bmain, (Object *)id, new_id);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata)
+{
+ ChannelDriver *driver;
+ FCurve *fcu;
+
+ /* find the driver this belongs to and update it */
+ for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
+ driver = fcu->driver;
+
+ if (driver) {
+ DriverVar *dvar;
+ for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
+ DRIVER_TARGETS_USED_LOOPER(dvar)
+ {
+ if (dtar->id == userdata)
+ dtar->id = NULL;
+ }
+ DRIVER_TARGETS_LOOPER_END
+ }
+ }
+ }
+}
+
+void BKE_libblock_free_data(Main *bmain, ID *id)
+{
+ if (id->properties) {
+ IDP_FreeProperty(id->properties);
+ MEM_freeN(id->properties);
+ }
+
+ /* this ID may be a driver target! */
+ BKE_animdata_main_cb(bmain, animdata_dtar_clear_cb, (void *)id);
+}
+
+/**
+ * used in headerbuttons.c image.c mesh.c screen.c sound.c and library.c
+ *
+ * \param do_id_user: if \a true, try to release other ID's 'references' hold by \a idv.
+ */
+void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user)
+{
+ ID *id = idv;
+ short type = GS(id->name);
+ ListBase *lb = which_libbase(bmain, type);
+
+ DAG_id_type_tag(bmain, type);
+
+#ifdef WITH_PYTHON
+ BPY_id_release(id);
+#endif
+
+ if (do_id_user) {
+ BKE_libblock_relink_ex(bmain, id, NULL, NULL, true);
+ }
+
+ switch (type) {
+ case ID_SCE:
+ BKE_scene_free((Scene *)id);
+ break;
+ case ID_LI:
+ BKE_library_free((Library *)id);
+ break;
+ case ID_OB:
+ BKE_object_free((Object *)id);
+ break;
+ case ID_ME:
+ BKE_mesh_free((Mesh *)id);
+ break;
+ case ID_CU:
+ BKE_curve_free((Curve *)id);
+ break;
+ case ID_MB:
+ BKE_mball_free((MetaBall *)id);
+ break;
+ case ID_MA:
+ BKE_material_free((Material *)id);
+ break;
+ case ID_TE:
+ BKE_texture_free((Tex *)id);
+ break;
+ case ID_IM:
+ BKE_image_free((Image *)id);
+ break;
+ case ID_LT:
+ BKE_lattice_free((Lattice *)id);
+ break;
+ case ID_LA:
+ BKE_lamp_free((Lamp *)id);
+ break;
+ case ID_CA:
+ BKE_camera_free((Camera *) id);
+ break;
+ case ID_IP: /* Deprecated. */
+ BKE_ipo_free((Ipo *)id);
+ break;
+ case ID_KE:
+ BKE_key_free((Key *)id);
+ break;
+ case ID_WO:
+ BKE_world_free((World *)id);
+ break;
+ case ID_SCR:
+ BKE_screen_free((bScreen *)id);
+ break;
+ case ID_VF:
+ BKE_vfont_free((VFont *)id);
+ break;
+ case ID_TXT:
+ BKE_text_free((Text *)id);
+ break;
+ case ID_SPK:
+ BKE_speaker_free((Speaker *)id);
+ break;
+ case ID_SO:
+ BKE_sound_free((bSound *)id);
+ break;
+ case ID_GR:
+ BKE_group_free((Group *)id);
+ break;
+ case ID_AR:
+ BKE_armature_free((bArmature *)id);
+ break;
+ case ID_AC:
+ BKE_action_free((bAction *)id);
+ break;
+ case ID_NT:
+ ntreeFreeTree((bNodeTree *)id);
+ break;
+ case ID_BR:
+ BKE_brush_free((Brush *)id);
+ break;
+ case ID_PA:
+ BKE_particlesettings_free((ParticleSettings *)id);
+ break;
+ case ID_WM:
+ if (free_windowmanager_cb)
+ free_windowmanager_cb(NULL, (wmWindowManager *)id);
+ break;
+ case ID_GD:
+ BKE_gpencil_free((bGPdata *)id, true);
+ break;
+ case ID_MC:
+ BKE_movieclip_free((MovieClip *)id);
+ break;
+ case ID_MSK:
+ BKE_mask_free((Mask *)id);
+ break;
+ case ID_LS:
+ BKE_linestyle_free((FreestyleLineStyle *)id);
+ break;
+ case ID_PAL:
+ BKE_palette_free((Palette *)id);
+ break;
+ case ID_PC:
+ BKE_paint_curve_free((PaintCurve *)id);
+ break;
+ case ID_CF:
+ BKE_cachefile_free((CacheFile *)id);
+ break;
+ }
+
+ /* avoid notifying on removed data */
+ BKE_main_lock(bmain);
+
+ if (free_notifier_reference_cb) {
+ free_notifier_reference_cb(id);
+ }
+
+ if (remap_editor_id_reference_cb) {
+ remap_editor_id_reference_cb(id, NULL);
+ }
+
+ BLI_remlink(lb, id);
+
+ BKE_libblock_free_data(bmain, id);
+ BKE_main_unlock(bmain);
+
+ MEM_freeN(id);
+}
+
+void BKE_libblock_free(Main *bmain, void *idv)
+{
+ BKE_libblock_free_ex(bmain, idv, true);
+}
+
+void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */
+{
+ ID *id = idv;
+
+ id_us_min(id);
+
+ /* XXX This is a temp (2.77) hack so that we keep same behavior as in 2.76 regarding groups when deleting an object.
+ * Since only 'user_one' usage of objects is groups, and only 'real user' usage of objects is scenes,
+ * removing that 'user_one' tag when there is no more real (scene) users of an object ensures it gets
+ * fully unlinked.
+ * Otherwise, there is no real way to get rid of an object anymore - better handling of this is TODO.
+ */
+ if ((GS(id->name) == ID_OB) && (id->us == 1)) {
+ id_us_clear_real(id);
+ }
+
+ if (id->us == 0) {
+ BKE_libblock_unlink(bmain, id, false, false);
+
+ BKE_libblock_free(bmain, id);
+ }
+}
+
+void BKE_libblock_delete(Main *bmain, void *idv)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ int base_count, i;
+
+ base_count = set_listbasepointers(bmain, lbarray);
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+
+ /* First tag all datablocks directly from target lib.
+ * Note that we go forward here, since we want to check dependencies before users (e.g. meshes before objects).
+ * Avoids to have to loop twice. */
+ for (i = 0; i < base_count; i++) {
+ ListBase *lb = lbarray[i];
+ ID *id;
+
+ for (id = lb->first; id; id = id->next) {
+ /* Note: in case we delete a library, we also delete all its datablocks! */
+ if ((id == (ID *)idv) || (id->lib == (Library *)idv) || (id->tag & LIB_TAG_DOIT)) {
+ id->tag |= LIB_TAG_DOIT;
+ /* Will tag 'never NULL' users of this ID too.
+ * Note that we cannot use BKE_libblock_unlink() here, since it would ignore indirect (and proxy!)
+ * links, this can lead to nasty crashing here in second, actual deleting loop.
+ * Also, this will also flag users of deleted data that cannot be unlinked
+ * (object using deleted obdata, etc.), so that they also get deleted. */
+ BKE_libblock_remap(bmain, id, NULL, ID_REMAP_FLAG_NEVER_NULL_USAGE | ID_REMAP_FORCE_NEVER_NULL_USAGE);
+ }
+ }
+ }
+
+ /* In usual reversed order, such that all usage of a given ID, even 'never NULL' ones, have been already cleared
+ * when we reach it (e.g. Objects being processed before meshes, they'll have already released their 'reference'
+ * over meshes when we come to freeing obdata). */
+ for (i = base_count; i--; ) {
+ ListBase *lb = lbarray[i];
+ ID *id, *id_next;
+
+ for (id = lb->first; id; id = id_next) {
+ id_next = id->next;
+ if (id->tag & LIB_TAG_DOIT) {
+ if (id->us != 0) {
+#ifdef DEBUG_PRINT
+ printf("%s: deleting %s (%d)\n", __func__, id->name, id->us);
+#endif
+ BLI_assert(id->us == 0);
+ }
+ BKE_libblock_free(bmain, id);
+ }
+ }
+ }
+}
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index 5a1dfc04045..bd21215f91e 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -125,26 +125,25 @@ FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name)
return linestyle;
}
+/** Free (or release) any data used by this linestyle (does not free the linestyle itself). */
void BKE_linestyle_free(FreestyleLineStyle *linestyle)
{
LineStyleModifier *m;
-
- MTex *mtex;
int a;
+ BKE_animdata_free(&linestyle->id, false);
+
for (a = 0; a < MAX_MTEX; a++) {
- mtex = linestyle->mtex[a];
- if (mtex && mtex->tex)
- id_us_min(&mtex->tex->id);
- if (mtex)
- MEM_freeN(mtex);
+ MEM_SAFE_FREE(linestyle->mtex[a]);
}
+
+ /* is no lib link block, but linestyle extension */
if (linestyle->nodetree) {
ntreeFreeTree(linestyle->nodetree);
MEM_freeN(linestyle->nodetree);
+ linestyle->nodetree = NULL;
}
- BKE_animdata_free(&linestyle->id);
while ((m = (LineStyleModifier *)linestyle->color_modifiers.first))
BKE_linestyle_color_modifier_remove(linestyle, m);
while ((m = (LineStyleModifier *)linestyle->alpha_modifiers.first))
@@ -172,7 +171,7 @@ FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, FreestyleLineStyle *l
}
}
if (linestyle->nodetree) {
- new_linestyle->nodetree = ntreeCopyTree(linestyle->nodetree);
+ new_linestyle->nodetree = ntreeCopyTree(bmain, linestyle->nodetree);
}
new_linestyle->r = linestyle->r;
@@ -219,13 +218,16 @@ FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, FreestyleLineStyle *l
for (m = (LineStyleModifier *)linestyle->geometry_modifiers.first; m; m = m->next)
BKE_linestyle_geometry_modifier_copy(new_linestyle, m);
- if (linestyle->id.lib) {
- BKE_id_lib_local_paths(G.main, linestyle->id.lib, &new_linestyle->id);
- }
+ BKE_id_copy_ensure_local(bmain, &linestyle->id, &new_linestyle->id);
return new_linestyle;
}
+void BKE_linestyle_make_local(struct Main *bmain, FreestyleLineStyle *linestyle, const bool lib_local)
+{
+ BKE_id_make_local_generic(bmain, &linestyle->id, true, lib_local);
+}
+
FreestyleLineStyle *BKE_linestyle_active_from_scene(Scene *scene)
{
SceneRenderLayer *actsrl = BLI_findlink(&scene->r.layers, scene->r.actlay);
@@ -1341,33 +1343,25 @@ int BKE_linestyle_geometry_modifier_remove(FreestyleLineStyle *linestyle, LineSt
return 0;
}
-static void move_modifier(ListBase *lb, LineStyleModifier *modifier, int direction)
-{
- BLI_remlink(lb, modifier);
- if (direction > 0)
- BLI_insertlinkbefore(lb, modifier->prev, modifier);
- else
- BLI_insertlinkafter(lb, modifier->next, modifier);
-}
-
-void BKE_linestyle_color_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
+/**
+ * Reinsert \a modifier in modifier list with an offset of \a direction.
+ * \return if position of \a modifier has changed.
+ */
+bool BKE_linestyle_color_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
{
- move_modifier(&linestyle->color_modifiers, modifier, direction);
+ return BLI_listbase_link_move(&linestyle->color_modifiers, modifier, direction);
}
-
-void BKE_linestyle_alpha_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
+bool BKE_linestyle_alpha_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
{
- move_modifier(&linestyle->alpha_modifiers, modifier, direction);
+ return BLI_listbase_link_move(&linestyle->alpha_modifiers, modifier, direction);
}
-
-void BKE_linestyle_thickness_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
+bool BKE_linestyle_thickness_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
{
- move_modifier(&linestyle->thickness_modifiers, modifier, direction);
+ return BLI_listbase_link_move(&linestyle->thickness_modifiers, modifier, direction);
}
-
-void BKE_linestyle_geometry_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
+bool BKE_linestyle_geometry_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
{
- move_modifier(&linestyle->geometry_modifiers, modifier, direction);
+ return BLI_listbase_link_move(&linestyle->geometry_modifiers, modifier, direction);
}
void BKE_linestyle_modifier_list_color_ramps(FreestyleLineStyle *linestyle, ListBase *listbase)
@@ -1452,33 +1446,6 @@ char *BKE_linestyle_path_to_color_ramp(FreestyleLineStyle *linestyle, ColorBand
return NULL;
}
-void BKE_linestyle_target_object_unlink(FreestyleLineStyle *linestyle, struct Object *ob)
-{
- LineStyleModifier *m;
-
- for (m = (LineStyleModifier *)linestyle->color_modifiers.first; m; m = m->next) {
- if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
- if (((LineStyleColorModifier_DistanceFromObject *)m)->target == ob) {
- ((LineStyleColorModifier_DistanceFromObject *)m)->target = NULL;
- }
- }
- }
- for (m = (LineStyleModifier *)linestyle->alpha_modifiers.first; m; m = m->next) {
- if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
- if (((LineStyleAlphaModifier_DistanceFromObject *)m)->target == ob) {
- ((LineStyleAlphaModifier_DistanceFromObject *)m)->target = NULL;
- }
- }
- }
- for (m = (LineStyleModifier *)linestyle->thickness_modifiers.first; m; m = m->next) {
- if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
- if (((LineStyleThicknessModifier_DistanceFromObject *)m)->target == ob) {
- ((LineStyleThicknessModifier_DistanceFromObject *)m)->target = NULL;
- }
- }
- }
-}
-
bool BKE_linestyle_use_textures(FreestyleLineStyle *linestyle, const bool use_shading_nodes)
{
if (use_shading_nodes) {
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index 930a3c487ec..21023d9f53c 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -533,7 +533,6 @@ void BKE_mask_point_segment_co(MaskSpline *spline, MaskSplinePoint *point, float
MaskSplinePoint *points_array = BKE_mask_spline_point_array_from_point(spline, point);
BezTriple *bezt = &point->bezt, *bezt_next;
- float q0[2], q1[2], q2[2], r0[2], r1[2];
bezt_next = BKE_mask_spline_point_next_bezt(spline, points_array, point);
@@ -542,14 +541,7 @@ void BKE_mask_point_segment_co(MaskSpline *spline, MaskSplinePoint *point, float
return;
}
- interp_v2_v2v2(q0, bezt->vec[1], bezt->vec[2], u);
- interp_v2_v2v2(q1, bezt->vec[2], bezt_next->vec[0], u);
- interp_v2_v2v2(q2, bezt_next->vec[0], bezt_next->vec[1], u);
-
- interp_v2_v2v2(r0, q0, q1, u);
- interp_v2_v2v2(r1, q1, q2, u);
-
- interp_v2_v2v2(co, r0, r1, u);
+ interp_v2_v2v2v2v2_cubic(co, bezt->vec[1], bezt->vec[2], bezt_next->vec[0], bezt_next->vec[1], u);
}
BLI_INLINE void orthogonal_direction_get(float vec[2], float result[2])
@@ -848,11 +840,11 @@ Mask *BKE_mask_copy_nolib(Mask *mask)
return mask_new;
}
-Mask *BKE_mask_copy(Mask *mask)
+Mask *BKE_mask_copy(Main *bmain, Mask *mask)
{
Mask *mask_new;
- mask_new = BKE_libblock_copy(&mask->id);
+ mask_new = BKE_libblock_copy(bmain, &mask->id);
BLI_listbase_clear(&mask_new->masklayers);
@@ -861,13 +853,16 @@ Mask *BKE_mask_copy(Mask *mask)
/* enable fake user by default */
id_fake_user_set(&mask->id);
- if (mask->id.lib) {
- BKE_id_lib_local_paths(G.main, mask->id.lib, &mask_new->id);
- }
+ BKE_id_copy_ensure_local(bmain, &mask->id, &mask_new->id);
return mask_new;
}
+void BKE_mask_make_local(Main *bmain, Mask *mask, const bool lib_local)
+{
+ BKE_id_make_local_generic(bmain, &mask->id, true, lib_local);
+}
+
void BKE_mask_point_free(MaskSplinePoint *point)
{
if (point->uw)
@@ -1010,63 +1005,10 @@ void BKE_mask_layer_free_list(ListBase *masklayers)
}
}
-/** free for temp copy, but don't manage unlinking from other pointers */
-void BKE_mask_free_nolib(Mask *mask)
+/** Free (or release) any data used by this mask (does not free the mask itself). */
+void BKE_mask_free(Mask *mask)
{
- BKE_mask_layer_free_list(&mask->masklayers);
-}
-
-void BKE_mask_free(Main *bmain, Mask *mask)
-{
- bScreen *scr;
- ScrArea *area;
- SpaceLink *sl;
- Scene *scene;
-
- 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) {
- switch (sl->spacetype) {
- case SPACE_CLIP:
- {
- SpaceClip *sc = (SpaceClip *)sl;
-
- if (sc->mask_info.mask == mask) {
- sc->mask_info.mask = NULL;
- }
- break;
- }
- case SPACE_IMAGE:
- {
- SpaceImage *sima = (SpaceImage *)sl;
-
- if (sima->mask_info.mask == mask) {
- sima->mask_info.mask = NULL;
- }
- break;
- }
- }
- }
- }
- }
-
- for (scene = bmain->scene.first; scene; scene = scene->id.next) {
- if (scene->ed) {
- Sequence *seq;
-
- SEQ_BEGIN (scene->ed, seq)
- {
- if (seq->mask == mask) {
- seq->mask = NULL;
- }
- }
- SEQ_END
- }
- }
-
- FOREACH_NODETREE(bmain, ntree, id) {
- BKE_node_tree_unlink_id((ID *)mask, ntree);
- } FOREACH_NODETREE_END
+ BKE_animdata_free((ID *)mask, false);
/* free mask data */
BKE_mask_layer_free_list(&mask->masklayers);
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 1fec725dbb7..54945242fe4 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -58,9 +58,12 @@
#include "BKE_animsys.h"
#include "BKE_displist.h"
#include "BKE_global.h"
+#include "BKE_depsgraph.h"
#include "BKE_icons.h"
#include "BKE_image.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
@@ -81,47 +84,33 @@ void init_def_material(void)
BKE_material_init(&defmaterial);
}
-/* not material itself */
+/** Free (or release) any data used by this material (does not free the material itself). */
void BKE_material_free(Material *ma)
{
- BKE_material_free_ex(ma, true);
-}
-
-/* not material itself */
-void BKE_material_free_ex(Material *ma, bool do_id_user)
-{
- MTex *mtex;
int a;
+
+ BKE_animdata_free((ID *)ma, false);
for (a = 0; a < MAX_MTEX; a++) {
- mtex = ma->mtex[a];
- if (do_id_user && mtex && mtex->tex)
- id_us_min(&mtex->tex->id);
- if (mtex)
- MEM_freeN(mtex);
+ MEM_SAFE_FREE(ma->mtex[a]);
}
- if (ma->ramp_col) MEM_freeN(ma->ramp_col);
- if (ma->ramp_spec) MEM_freeN(ma->ramp_spec);
-
- BKE_animdata_free((ID *)ma);
-
- if (ma->preview)
- BKE_previewimg_free(&ma->preview);
- BKE_icon_id_delete((struct ID *)ma);
- ma->id.icon_id = 0;
+ MEM_SAFE_FREE(ma->ramp_col);
+ MEM_SAFE_FREE(ma->ramp_spec);
/* is no lib link block, but material extension */
if (ma->nodetree) {
- ntreeFreeTree_ex(ma->nodetree, do_id_user);
+ ntreeFreeTree(ma->nodetree);
MEM_freeN(ma->nodetree);
+ ma->nodetree = NULL;
}
- if (ma->texpaintslot)
- MEM_freeN(ma->texpaintslot);
+ MEM_SAFE_FREE(ma->texpaintslot);
+
+ GPU_material_free(&ma->gpumaterial);
- if (ma->gpumaterial.first)
- GPU_material_free(&ma->gpumaterial);
+ BKE_icon_id_delete((ID *)ma);
+ BKE_previewimg_free(&ma->preview);
}
void BKE_material_init(Material *ma)
@@ -231,12 +220,12 @@ Material *BKE_material_add(Main *bmain, const char *name)
}
/* XXX keep synced with next function */
-Material *BKE_material_copy(Material *ma)
+Material *BKE_material_copy(Main *bmain, Material *ma)
{
Material *man;
int a;
- man = BKE_libblock_copy(&ma->id);
+ man = BKE_libblock_copy(bmain, &ma->id);
id_lib_extern((ID *)man->group);
@@ -251,17 +240,15 @@ Material *BKE_material_copy(Material *ma)
if (ma->ramp_col) man->ramp_col = MEM_dupallocN(ma->ramp_col);
if (ma->ramp_spec) man->ramp_spec = MEM_dupallocN(ma->ramp_spec);
- if (ma->preview) man->preview = BKE_previewimg_copy(ma->preview);
-
if (ma->nodetree) {
- man->nodetree = ntreeCopyTree(ma->nodetree);
+ man->nodetree = ntreeCopyTree(bmain, ma->nodetree);
}
+ BKE_previewimg_id_copy(&man->id, &ma->id);
+
BLI_listbase_clear(&man->gpumaterial);
-
- if (ma->id.lib) {
- BKE_id_lib_local_paths(G.main, ma->id.lib, &man->id);
- }
+
+ BKE_id_copy_ensure_local(bmain, &ma->id, &man->id);
return man;
}
@@ -296,181 +283,9 @@ Material *localize_material(Material *ma)
return man;
}
-static void extern_local_material(Material *ma)
+void BKE_material_make_local(Main *bmain, Material *ma, const bool lib_local)
{
- int i;
- for (i = 0; i < MAX_MTEX; i++) {
- if (ma->mtex[i]) id_lib_extern((ID *)ma->mtex[i]->tex);
- }
-}
-
-void BKE_material_make_local(Material *ma)
-{
- Main *bmain = G.main;
- Object *ob;
- Mesh *me;
- Curve *cu;
- MetaBall *mb;
- int a;
- bool is_local = false, is_lib = false;
-
- /* - only lib users: do nothing
- * - only local users: set flag
- * - mixed: make copy
- */
-
- if (ma->id.lib == NULL) return;
-
- /* One local user; set flag and return. */
- if (ma->id.us == 1) {
- id_clear_lib_data(bmain, &ma->id);
- extern_local_material(ma);
- return;
- }
-
- /* Check which other IDs reference this one to determine if it's used by
- * lib or local */
- /* test objects */
- ob = bmain->object.first;
- while (ob) {
- if (ob->mat) {
- for (a = 0; a < ob->totcol; a++) {
- if (ob->mat[a] == ma) {
- if (ob->id.lib) is_lib = true;
- else is_local = true;
- }
- }
- }
- ob = ob->id.next;
- }
- /* test meshes */
- me = bmain->mesh.first;
- while (me) {
- if (me->mat) {
- for (a = 0; a < me->totcol; a++) {
- if (me->mat[a] == ma) {
- if (me->id.lib) is_lib = true;
- else is_local = true;
- }
- }
- }
- me = me->id.next;
- }
- /* test curves */
- cu = bmain->curve.first;
- while (cu) {
- if (cu->mat) {
- for (a = 0; a < cu->totcol; a++) {
- if (cu->mat[a] == ma) {
- if (cu->id.lib) is_lib = true;
- else is_local = true;
- }
- }
- }
- cu = cu->id.next;
- }
- /* test mballs */
- mb = bmain->mball.first;
- while (mb) {
- if (mb->mat) {
- for (a = 0; a < mb->totcol; a++) {
- if (mb->mat[a] == ma) {
- if (mb->id.lib) is_lib = true;
- else is_local = true;
- }
- }
- }
- mb = mb->id.next;
- }
-
- /* Only local users. */
- if (is_local && is_lib == false) {
- id_clear_lib_data(bmain, &ma->id);
- extern_local_material(ma);
- }
- /* Both user and local, so copy. */
- else if (is_local && is_lib) {
- Material *ma_new = BKE_material_copy(ma);
-
- ma_new->id.us = 0;
-
- /* Remap paths of new ID using old library as base. */
- BKE_id_lib_local_paths(bmain, ma->id.lib, &ma_new->id);
-
- /* do objects */
- ob = bmain->object.first;
- while (ob) {
- if (ob->mat) {
- for (a = 0; a < ob->totcol; a++) {
- if (ob->mat[a] == ma) {
- if (ob->id.lib == NULL) {
- ob->mat[a] = ma_new;
- id_us_plus(&ma_new->id);
- id_us_min(&ma->id);
- }
- }
- }
- }
- ob = ob->id.next;
- }
- /* do meshes */
- me = bmain->mesh.first;
- while (me) {
- if (me->mat) {
- for (a = 0; a < me->totcol; a++) {
- if (me->mat[a] == ma) {
- if (me->id.lib == NULL) {
- me->mat[a] = ma_new;
- id_us_plus(&ma_new->id);
- id_us_min(&ma->id);
- }
- }
- }
- }
- me = me->id.next;
- }
- /* do curves */
- cu = bmain->curve.first;
- while (cu) {
- if (cu->mat) {
- for (a = 0; a < cu->totcol; a++) {
- if (cu->mat[a] == ma) {
- if (cu->id.lib == NULL) {
- cu->mat[a] = ma_new;
- id_us_plus(&ma_new->id);
- id_us_min(&ma->id);
- }
- }
- }
- }
- cu = cu->id.next;
- }
- /* do mballs */
- mb = bmain->mball.first;
- while (mb) {
- if (mb->mat) {
- for (a = 0; a < mb->totcol; a++) {
- if (mb->mat[a] == ma) {
- if (mb->id.lib == NULL) {
- mb->mat[a] = ma_new;
- id_us_plus(&ma_new->id);
- id_us_min(&ma->id);
- }
- }
- }
- }
- mb = mb->id.next;
- }
- }
-}
-
-/* for curve, mball, mesh types */
-void extern_local_matarar(struct Material **matar, short totcol)
-{
- short i;
- for (i = 0; i < totcol; i++) {
- id_lib_extern((ID *)matar[i]);
- }
+ BKE_id_make_local_generic(bmain, &ma->id, true, lib_local);
}
Material ***give_matarar(Object *ob)
@@ -584,7 +399,7 @@ static void material_data_index_clear_id(ID *id)
}
}
-void BKE_material_resize_id(struct ID *id, short totcol, bool do_id_user)
+void BKE_material_resize_id(Main *bmain, ID *id, short totcol, bool do_id_user)
{
Material ***matar = give_matarar_id(id);
short *totcolp = give_totcolp_id(id);
@@ -610,9 +425,11 @@ void BKE_material_resize_id(struct ID *id, short totcol, bool do_id_user)
*matar = MEM_recallocN(*matar, sizeof(void *) * totcol);
}
*totcolp = totcol;
+
+ DAG_relations_tag_update(bmain);
}
-void BKE_material_append_id(ID *id, Material *ma)
+void BKE_material_append_id(Main *bmain, ID *id, Material *ma)
{
Material ***matar;
if ((matar = give_matarar_id(id))) {
@@ -625,11 +442,12 @@ void BKE_material_append_id(ID *id, Material *ma)
(*matar)[(*totcol)++] = ma;
id_us_plus((ID *)ma);
- test_object_materials(G.main, id);
+ test_all_objects_materials(bmain, id);
+ DAG_relations_tag_update(bmain);
}
}
-Material *BKE_material_pop_id(ID *id, int index_i, bool update_data)
+Material *BKE_material_pop_id(Main *bmain, ID *id, int index_i, bool update_data)
{
short index = (short)index_i;
Material *ret = NULL;
@@ -651,20 +469,22 @@ Material *BKE_material_pop_id(ID *id, int index_i, bool update_data)
(*totcol)--;
*matar = MEM_reallocN(*matar, sizeof(void *) * (*totcol));
- test_object_materials(G.main, id);
+ test_all_objects_materials(G.main, id);
}
if (update_data) {
/* decrease mat_nr index */
material_data_index_remove_id(id, index);
}
+
+ DAG_relations_tag_update(bmain);
}
}
return ret;
}
-void BKE_material_clear_id(struct ID *id, bool update_data)
+void BKE_material_clear_id(Main *bmain, ID *id, bool update_data)
{
Material ***matar;
if ((matar = give_matarar_id(id))) {
@@ -683,6 +503,8 @@ void BKE_material_clear_id(struct ID *id, bool update_data)
/* decrease mat_nr index */
material_data_index_clear_id(id);
}
+
+ DAG_relations_tag_update(bmain);
}
}
@@ -727,18 +549,6 @@ Material *give_current_material(Object *ob, short act)
return ma;
}
-ID *material_from(Object *ob, short act)
-{
-
- if (ob == NULL) return NULL;
-
- if (ob->totcol == 0) return ob->data;
- if (act == 0) act = 1;
-
- if (ob->matbits[act - 1]) return (ID *)ob;
- else return ob->data;
-}
-
Material *give_node_material(Material *ma)
{
if (ma && ma->use_nodes && ma->nodetree) {
@@ -751,7 +561,7 @@ Material *give_node_material(Material *ma)
return NULL;
}
-void BKE_material_resize_object(Object *ob, const short totcol, bool do_id_user)
+void BKE_material_resize_object(Main *bmain, Object *ob, const short totcol, bool do_id_user)
{
Material **newmatar;
char *newmatbits;
@@ -788,9 +598,23 @@ void BKE_material_resize_object(Object *ob, const short totcol, bool do_id_user)
ob->totcol = totcol;
if (ob->totcol && ob->actcol == 0) ob->actcol = 1;
if (ob->actcol > ob->totcol) ob->actcol = ob->totcol;
+
+ DAG_relations_tag_update(bmain);
}
-void test_object_materials(Main *bmain, ID *id)
+void test_object_materials(Object *ob, ID *id)
+{
+ /* make the ob mat-array same size as 'ob->data' mat-array */
+ const short *totcol;
+
+ if (id == NULL || (totcol = give_totcolp_id(id)) == NULL) {
+ return;
+ }
+
+ BKE_material_resize_object(G.main, ob, *totcol, false);
+}
+
+void test_all_objects_materials(Main *bmain, ID *id)
{
/* make the ob mat-array same size as 'ob->data' mat-array */
Object *ob;
@@ -803,7 +627,7 @@ void test_object_materials(Main *bmain, ID *id)
BKE_main_lock(bmain);
for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->data == id) {
- BKE_material_resize_object(ob, *totcol, false);
+ BKE_material_resize_object(bmain, ob, *totcol, false);
}
}
BKE_main_unlock(bmain);
@@ -853,7 +677,7 @@ void assign_material_id(ID *id, Material *ma, short act)
if (ma)
id_us_plus(&ma->id);
- test_object_materials(G.main, id);
+ test_all_objects_materials(G.main, id);
}
void assign_material(Object *ob, Material *ma, short act, int assign_type)
@@ -866,8 +690,8 @@ void assign_material(Object *ob, Material *ma, short act, int assign_type)
if (act < 1) act = 1;
/* prevent crashing when using accidentally */
- BLI_assert(ob->id.lib == NULL);
- if (ob->id.lib) return;
+ BLI_assert(!ID_IS_LINKED_DATABLOCK(ob));
+ if (ID_IS_LINKED_DATABLOCK(ob)) return;
/* test arraylens */
@@ -928,17 +752,18 @@ void assign_material(Object *ob, Material *ma, short act, int assign_type)
if (mao)
id_us_min(&mao->id);
ob->mat[act - 1] = ma;
+ test_object_materials(ob, ob->data);
}
else { /* in data */
mao = (*matarar)[act - 1];
if (mao)
id_us_min(&mao->id);
(*matarar)[act - 1] = ma;
+ test_all_objects_materials(G.main, ob->data); /* Data may be used by several objects... */
}
if (ma)
id_us_plus(&ma->id);
- test_object_materials(G.main, ob->data);
}
@@ -1032,7 +857,11 @@ void assign_matarar(struct Object *ob, struct Material ***matar, short totcol)
int actcol_orig = ob->actcol;
short i;
- while (object_remove_material_slot(ob)) {}
+ while ((ob->totcol > totcol) &&
+ BKE_object_material_slot_remove(ob))
+ {
+ /* pass */
+ }
/* now we have the right number of slots */
for (i = 0; i < totcol; i++)
@@ -1045,7 +874,7 @@ void assign_matarar(struct Object *ob, struct Material ***matar, short totcol)
}
-short find_material_index(Object *ob, Material *ma)
+short BKE_object_material_slot_find_index(Object *ob, Material *ma)
{
Material ***matarar;
short a, *totcolp;
@@ -1065,7 +894,7 @@ short find_material_index(Object *ob, Material *ma)
return 0;
}
-bool object_add_material_slot(Object *ob)
+bool BKE_object_material_slot_add(Object *ob)
{
if (ob == NULL) return false;
if (ob->totcol >= MAXMAT) return false;
@@ -1135,7 +964,7 @@ static void do_init_render_material(Material *ma, int r_mode, float *amb)
Group *group;
for (group = G.main->group.first; group; group = group->id.next) {
- if (!group->id.lib && STREQ(group->id.name, ma->group->id.name)) {
+ if (!ID_IS_LINKED_DATABLOCK(group) && STREQ(group->id.name, ma->group->id.name)) {
ma->group = group;
}
}
@@ -1148,7 +977,6 @@ static void init_render_nodetree(bNodeTree *ntree, Material *basemat, int r_mode
/* parses the geom+tex nodes */
ntreeShaderGetTexcoMode(ntree, r_mode, &basemat->texco, &basemat->mode_l);
- basemat->nmap_tangent_names_count = 0;
for (node = ntree->nodes.first; node; node = node->next) {
if (node->id) {
if (GS(node->id->name) == ID_MA) {
@@ -1199,7 +1027,7 @@ void init_render_material(Material *mat, int r_mode, float *amb)
* mode_l will have it set when all node materials are shadeless. */
mat->mode_l = (mat->mode & MA_MODE_PIPELINE) | MA_SHLESS;
mat->mode2_l = mat->mode2 & MA_MODE2_PIPELINE;
-
+ mat->nmap_tangent_names_count = 0;
init_render_nodetree(mat->nodetree, mat, r_mode, amb);
if (!mat->nodetree->execdata)
@@ -1348,7 +1176,7 @@ void material_drivers_update(Scene *scene, Material *ma, float ctime)
ma->id.tag &= ~LIB_TAG_DOIT;
}
-bool object_remove_material_slot(Object *ob)
+bool BKE_object_material_slot_remove(Object *ob)
{
Material *mao, ***matarar;
Object *obt;
@@ -1841,7 +1669,7 @@ void free_matcopybuf(void)
matcopybuf.ramp_spec = NULL;
if (matcopybuf.nodetree) {
- ntreeFreeTree_ex(matcopybuf.nodetree, false);
+ ntreeFreeTree(matcopybuf.nodetree);
MEM_freeN(matcopybuf.nodetree);
matcopybuf.nodetree = NULL;
}
@@ -2063,7 +1891,7 @@ static short mesh_getmaterialnumber(Mesh *me, Material *ma)
/* append material */
static short mesh_addmaterial(Mesh *me, Material *ma)
{
- BKE_material_append_id(&me->id, NULL);
+ BKE_material_append_id(G.main, &me->id, NULL);
me->mat[me->totcol - 1] = ma;
id_us_plus(&ma->id);
@@ -2173,7 +2001,7 @@ static void convert_tfacematerial(Main *main, Material *ma)
}
/* create a new material */
else {
- mat_new = BKE_material_copy(ma);
+ mat_new = BKE_material_copy(main, ma);
if (mat_new) {
/* rename the material*/
BLI_strncpy(mat_new->id.name, idname, sizeof(mat_new->id.name));
@@ -2202,7 +2030,7 @@ static void convert_tfacematerial(Main *main, Material *ma)
/* remove material from mesh */
for (a = 0; a < me->totcol; ) {
if (me->mat[a] == ma) {
- BKE_material_pop_id(&me->id, a, true);
+ BKE_material_pop_id(main, &me->id, a, true);
}
else {
a++;
@@ -2245,7 +2073,7 @@ int do_version_tface(Main *main)
/* 1st part: marking mesh materials to update */
for (me = main->mesh.first; me; me = me->id.next) {
- if (me->id.lib) continue;
+ if (ID_IS_LINKED_DATABLOCK(me)) continue;
/* get the active tface layer */
index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE);
@@ -2299,7 +2127,7 @@ int do_version_tface(Main *main)
* at doversion time: direct_link might not have happened on it,
* so ma->mtex is not pointing to valid memory yet.
* later we could, but it's better not */
- else if (ma->id.lib)
+ else if (ID_IS_LINKED_DATABLOCK(ma))
continue;
/* material already marked as disputed */
@@ -2364,7 +2192,7 @@ int do_version_tface(Main *main)
/* we shouldn't loop through the materials created in the loop. make the loop stop at its original length) */
for (ma = main->mat.first, a = 0; ma; ma = ma->id.next, a++) {
- if (ma->id.lib) continue;
+ if (ID_IS_LINKED_DATABLOCK(ma)) continue;
/* disputed material */
if (ma->game.flag == MAT_BGE_DISPUTED) {
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index d7019aa8458..8d024ea9aa5 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -59,6 +59,8 @@
#include "BKE_depsgraph.h"
#include "BKE_scene.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_displist.h"
#include "BKE_mball.h"
#include "BKE_object.h"
@@ -66,28 +68,13 @@
/* Functions */
-void BKE_mball_unlink(MetaBall *mb)
+/** Free (or release) any data used by this mball (does not free the mball itself). */
+void BKE_mball_free(MetaBall *mb)
{
- int a;
-
- for (a = 0; a < mb->totcol; a++) {
- if (mb->mat[a])
- id_us_min(&mb->mat[a]->id);
- mb->mat[a] = NULL;
- }
-}
+ BKE_animdata_free((ID *)mb, false);
+ MEM_SAFE_FREE(mb->mat);
-/* do not free mball itself */
-void BKE_mball_free(MetaBall *mb)
-{
- BKE_mball_unlink(mb);
-
- if (mb->adt) {
- BKE_animdata_free((ID *)mb);
- mb->adt = NULL;
- }
- if (mb->mat) MEM_freeN(mb->mat);
BLI_freelistN(&mb->elems);
if (mb->disp.first) BKE_displist_free(&mb->disp);
}
@@ -115,12 +102,12 @@ MetaBall *BKE_mball_add(Main *bmain, const char *name)
return mb;
}
-MetaBall *BKE_mball_copy(MetaBall *mb)
+MetaBall *BKE_mball_copy(Main *bmain, MetaBall *mb)
{
MetaBall *mbn;
int a;
- mbn = BKE_libblock_copy(&mb->id);
+ mbn = BKE_libblock_copy(bmain, &mb->id);
BLI_duplicatelist(&mbn->elems, &mb->elems);
@@ -132,67 +119,14 @@ MetaBall *BKE_mball_copy(MetaBall *mb)
mbn->editelems = NULL;
mbn->lastelem = NULL;
- if (mb->id.lib) {
- BKE_id_lib_local_paths(G.main, mb->id.lib, &mbn->id);
- }
+ BKE_id_copy_ensure_local(bmain, &mb->id, &mbn->id);
return mbn;
}
-static void extern_local_mball(MetaBall *mb)
-{
- if (mb->mat) {
- extern_local_matarar(mb->mat, mb->totcol);
- }
-}
-
-void BKE_mball_make_local(MetaBall *mb)
+void BKE_mball_make_local(Main *bmain, MetaBall *mb, const bool lib_local)
{
- Main *bmain = G.main;
- Object *ob;
- bool is_local = false, is_lib = false;
-
- /* - only lib users: do nothing
- * - only local users: set flag
- * - mixed: make copy
- */
-
- if (mb->id.lib == NULL) return;
- if (mb->id.us == 1) {
- id_clear_lib_data(bmain, &mb->id);
- extern_local_mball(mb);
-
- return;
- }
-
- for (ob = G.main->object.first; ob && ELEM(0, is_lib, is_local); ob = ob->id.next) {
- if (ob->data == mb) {
- if (ob->id.lib) is_lib = true;
- else is_local = true;
- }
- }
-
- if (is_local && is_lib == false) {
- id_clear_lib_data(bmain, &mb->id);
- extern_local_mball(mb);
- }
- else if (is_local && is_lib) {
- MetaBall *mb_new = BKE_mball_copy(mb);
- mb_new->id.us = 0;
-
- /* Remap paths of new ID using old library as base. */
- BKE_id_lib_local_paths(bmain, mb->id.lib, &mb_new->id);
-
- for (ob = G.main->object.first; ob; ob = ob->id.next) {
- if (ob->data == mb) {
- if (ob->id.lib == NULL) {
- ob->data = mb_new;
- id_us_plus(&mb_new->id);
- id_us_min(&mb->id);
- }
- }
- }
- }
+ BKE_id_make_local_generic(bmain, &mb->id, true, lib_local);
}
/* most simple meta-element adding function
diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c
index e8418e876bb..2068854421f 100644
--- a/source/blender/blenkernel/intern/mball_tessellate.c
+++ b/source/blender/blenkernel/intern/mball_tessellate.c
@@ -1159,7 +1159,7 @@ static void init_meta(EvaluationContext *eval_ctx, PROCESS *process, Scene *scen
new_ml->imat = BLI_memarena_alloc(process->pgn_elements, 4 * 4 * sizeof(float));
/* too big stiffness seems only ugly due to linear interpolation
- * no need to have possibility for too big stiffness */
+ * no need to have possibility for too big stiffness */
if (ml->s > 10.0f) new_ml->s = 10.0f;
else new_ml->s = ml->s;
@@ -1294,7 +1294,7 @@ void BKE_mball_polygonize(EvaluationContext *eval_ctx, Scene *scene, Object *ob,
build_bvh_spatial(&process, &process.metaball_bvh, 0, process.totelem, &process.allbb);
/* don't polygonize metaballs with too high resolution (base mball to small)
- * note: Eps was 0.0001f but this was giving problems for blood animation for durian, using 0.00001f */
+ * note: Eps was 0.0001f but this was giving problems for blood animation for durian, using 0.00001f */
if (ob->size[0] > 0.00001f * (process.allbb.max[0] - process.allbb.min[0]) ||
ob->size[1] > 0.00001f * (process.allbb.max[1] - process.allbb.min[1]) ||
ob->size[2] > 0.00001f * (process.allbb.max[2] - process.allbb.min[2]))
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 2af78cca79f..d21f43ac484 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -31,6 +31,7 @@
#include "DNA_scene_types.h"
#include "DNA_material_types.h"
+#include "DNA_meta_types.h"
#include "DNA_object_types.h"
#include "DNA_key_types.h"
#include "DNA_mesh_types.h"
@@ -49,6 +50,8 @@
#include "BKE_mesh.h"
#include "BKE_displist.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_material.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
@@ -427,38 +430,10 @@ bool BKE_mesh_has_custom_loop_normals(Mesh *me)
}
}
-/* Note: unlinking is called when me->id.us is 0, question remains how
- * much unlinking of Library data in Mesh should be done... probably
- * we need a more generic method, like the expand() functions in
- * readfile.c */
-
-void BKE_mesh_unlink(Mesh *me)
-{
- int a;
-
- if (me == NULL) return;
-
- if (me->mat) {
- for (a = 0; a < me->totcol; a++) {
- if (me->mat[a])
- id_us_min(&me->mat[a]->id);
- me->mat[a] = NULL;
- }
- }
-
- if (me->key) {
- id_us_min(&me->key->id);
- }
- me->key = NULL;
-
- if (me->texcomesh) me->texcomesh = NULL;
-}
-
-/* do not free mesh itself */
-void BKE_mesh_free(Mesh *me, int unlink)
+/** Free (or release) any data used by this mesh (does not free the mesh itself). */
+void BKE_mesh_free(Mesh *me)
{
- if (unlink)
- BKE_mesh_unlink(me);
+ BKE_animdata_free(&me->id, false);
CustomData_free(&me->vdata, me->totvert);
CustomData_free(&me->edata, me->totedge);
@@ -466,16 +441,10 @@ void BKE_mesh_free(Mesh *me, int unlink)
CustomData_free(&me->ldata, me->totloop);
CustomData_free(&me->pdata, me->totpoly);
- if (me->adt) {
- BKE_animdata_free(&me->id);
- me->adt = NULL;
- }
-
- if (me->mat) MEM_freeN(me->mat);
-
- if (me->bb) MEM_freeN(me->bb);
- if (me->mselect) MEM_freeN(me->mselect);
- if (me->edit_btmesh) MEM_freeN(me->edit_btmesh);
+ MEM_SAFE_FREE(me->mat);
+ MEM_SAFE_FREE(me->bb);
+ MEM_SAFE_FREE(me->mselect);
+ MEM_SAFE_FREE(me->edit_btmesh);
}
static void mesh_tessface_clear_intern(Mesh *mesh, int free_customdata)
@@ -525,15 +494,13 @@ Mesh *BKE_mesh_add(Main *bmain, const char *name)
return me;
}
-Mesh *BKE_mesh_copy_ex(Main *bmain, Mesh *me)
+Mesh *BKE_mesh_copy(Main *bmain, Mesh *me)
{
Mesh *men;
- MTFace *tface;
- MTexPoly *txface;
- int a, i;
+ int a;
const int do_tessface = ((me->totface != 0) && (me->totpoly == 0)); /* only do tessface if we have no polys */
- men = BKE_libblock_copy_ex(bmain, &me->id);
+ men = BKE_libblock_copy(bmain, &me->id);
men->mat = MEM_dupallocN(me->mat);
for (a = 0; a < men->totcol; a++) {
@@ -554,53 +521,29 @@ Mesh *BKE_mesh_copy_ex(Main *bmain, Mesh *me)
BKE_mesh_update_customdata_pointers(men, do_tessface);
- /* ensure indirect linked data becomes lib-extern */
- for (i = 0; i < me->fdata.totlayer; i++) {
- if (me->fdata.layers[i].type == CD_MTFACE) {
- tface = (MTFace *)me->fdata.layers[i].data;
-
- for (a = 0; a < me->totface; a++, tface++)
- if (tface->tpage)
- id_lib_extern((ID *)tface->tpage);
- }
- }
-
- for (i = 0; i < me->pdata.totlayer; i++) {
- if (me->pdata.layers[i].type == CD_MTEXPOLY) {
- txface = (MTexPoly *)me->pdata.layers[i].data;
-
- for (a = 0; a < me->totpoly; a++, txface++)
- if (txface->tpage)
- id_lib_extern((ID *)txface->tpage);
- }
- }
-
men->edit_btmesh = NULL;
men->mselect = MEM_dupallocN(men->mselect);
men->bb = MEM_dupallocN(men->bb);
-
- men->key = BKE_key_copy(me->key);
- if (men->key) men->key->from = (ID *)men;
- if (me->id.lib) {
- BKE_id_lib_local_paths(bmain, me->id.lib, &men->id);
+ if (me->key) {
+ men->key = BKE_key_copy(bmain, me->key);
+ men->key->from = (ID *)men;
}
- return men;
-}
+ BKE_id_copy_ensure_local(bmain, &me->id, &men->id);
-Mesh *BKE_mesh_copy(Mesh *me)
-{
- return BKE_mesh_copy_ex(G.main, me);
+ return men;
}
-BMesh *BKE_mesh_to_bmesh(Mesh *me, Object *ob, const bool add_key_index)
+BMesh *BKE_mesh_to_bmesh(
+ Mesh *me, Object *ob,
+ const bool add_key_index, const struct BMeshCreateParams *params)
{
BMesh *bm;
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me);
- bm = BM_mesh_create(&allocsize);
+ bm = BM_mesh_create(&allocsize, params);
BM_mesh_bm_from_me(
bm, me, (&(struct BMeshFromMeshParams){
@@ -610,90 +553,9 @@ BMesh *BKE_mesh_to_bmesh(Mesh *me, Object *ob, const bool add_key_index)
return bm;
}
-static void expand_local_mesh(Mesh *me)
-{
- id_lib_extern((ID *)me->texcomesh);
-
- if (me->mtface || me->mtpoly) {
- int a, i;
-
- for (i = 0; i < me->pdata.totlayer; i++) {
- if (me->pdata.layers[i].type == CD_MTEXPOLY) {
- MTexPoly *txface = (MTexPoly *)me->pdata.layers[i].data;
-
- for (a = 0; a < me->totpoly; a++, txface++) {
- /* special case: ima always local immediately */
- if (txface->tpage) {
- id_lib_extern((ID *)txface->tpage);
- }
- }
- }
- }
-
- for (i = 0; i < me->fdata.totlayer; i++) {
- if (me->fdata.layers[i].type == CD_MTFACE) {
- MTFace *tface = (MTFace *)me->fdata.layers[i].data;
-
- for (a = 0; a < me->totface; a++, tface++) {
- /* special case: ima always local immediately */
- if (tface->tpage) {
- id_lib_extern((ID *)tface->tpage);
- }
- }
- }
- }
- }
-
- if (me->mat) {
- extern_local_matarar(me->mat, me->totcol);
- }
-}
-
-void BKE_mesh_make_local(Mesh *me)
+void BKE_mesh_make_local(Main *bmain, Mesh *me, const bool lib_local)
{
- Main *bmain = G.main;
- Object *ob;
- bool is_local = false, is_lib = false;
-
- /* - only lib users: do nothing
- * - only local users: set flag
- * - mixed: make copy
- */
-
- if (me->id.lib == NULL) return;
- if (me->id.us == 1) {
- id_clear_lib_data(bmain, &me->id);
- expand_local_mesh(me);
- return;
- }
-
- for (ob = bmain->object.first; ob && ELEM(0, is_lib, is_local); ob = ob->id.next) {
- if (me == ob->data) {
- if (ob->id.lib) is_lib = true;
- else is_local = true;
- }
- }
-
- if (is_local && is_lib == false) {
- id_clear_lib_data(bmain, &me->id);
- expand_local_mesh(me);
- }
- else if (is_local && is_lib) {
- Mesh *me_new = BKE_mesh_copy(me);
- me_new->id.us = 0;
-
-
- /* Remap paths of new ID using old library as base. */
- BKE_id_lib_local_paths(bmain, me->id.lib, &me_new->id);
-
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- if (me == ob->data) {
- if (ob->id.lib == NULL) {
- BKE_mesh_assign_object(ob, me_new);
- }
- }
- }
- }
+ BKE_id_make_local_generic(bmain, &me->id, true, lib_local);
}
bool BKE_mesh_uv_cdlayer_rename_index(Mesh *me, const int poly_index, const int loop_index, const int face_index,
@@ -1042,7 +904,7 @@ void BKE_mesh_assign_object(Object *ob, Mesh *me)
id_us_plus((ID *)me);
}
- test_object_materials(G.main, (ID *)me);
+ test_object_materials(ob, (ID *)me);
test_object_modifiers(ob);
}
@@ -1497,7 +1359,7 @@ void BKE_mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const bool use
}
/* make mesh */
- me = BKE_mesh_add(G.main, "Mesh");
+ me = BKE_mesh_add(bmain, "Mesh");
me->totvert = totvert;
me->totedge = totedge;
me->totloop = totloop;
@@ -1517,7 +1379,7 @@ void BKE_mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const bool use
BKE_mesh_calc_normals(me);
}
else {
- me = BKE_mesh_add(G.main, "Mesh");
+ me = BKE_mesh_add(bmain, "Mesh");
DM_to_mesh(dm, me, ob, CD_MASK_MESH, false);
}
@@ -2335,9 +2197,10 @@ Mesh *BKE_mesh_new_from_object(
{
Mesh *tmpmesh;
Curve *tmpcu = NULL, *copycu;
- Object *tmpobj = NULL;
- int render = settings == eModifierMode_Render, i;
- int cage = !apply_modifiers;
+ int i;
+ const bool render = (settings == eModifierMode_Render);
+ const bool cage = !apply_modifiers;
+ bool do_mat_id_data_us = true;
/* perform the mesh extraction based on type */
switch (ob->type) {
@@ -2350,7 +2213,7 @@ Mesh *BKE_mesh_new_from_object(
int uv_from_orco;
/* copies object and modifiers (but not the data) */
- tmpobj = BKE_object_copy_ex(bmain, ob, true);
+ Object *tmpobj = BKE_object_copy_ex(bmain, ob, true);
tmpcu = (Curve *)tmpobj->data;
id_us_min(&tmpcu->id);
@@ -2372,7 +2235,7 @@ Mesh *BKE_mesh_new_from_object(
BKE_object_free_modifiers(tmpobj);
/* copies the data */
- copycu = tmpobj->data = BKE_curve_copy((Curve *) ob->data);
+ copycu = tmpobj->data = BKE_curve_copy(bmain, (Curve *) ob->data);
/* temporarily set edit so we get updates from edit mode, but
* also because for text datablocks copying it while in edit
@@ -2407,6 +2270,12 @@ Mesh *BKE_mesh_new_from_object(
BKE_mesh_texspace_copy_from_object(tmpmesh, ob);
BKE_libblock_free_us(bmain, tmpobj);
+
+ /* XXX The curve to mesh conversion is convoluted... But essentially, BKE_mesh_from_nurbs_displist()
+ * already transfers the ownership of materials from the temp copy of the Curve ID to the new
+ * Mesh ID, so we do not want to increase materials' usercount later. */
+ do_mat_id_data_us = false;
+
break;
}
@@ -2453,15 +2322,18 @@ Mesh *BKE_mesh_new_from_object(
/* copies object and modifiers (but not the data) */
if (cage) {
/* copies the data */
- tmpmesh = BKE_mesh_copy_ex(bmain, ob->data);
- /* if not getting the original caged mesh, get final derived mesh */
+ tmpmesh = BKE_mesh_copy(bmain, ob->data);
+
+ /* XXX BKE_mesh_copy() already handles materials usercount. */
+ do_mat_id_data_us = false;
}
+ /* if not getting the original caged mesh, get final derived mesh */
else {
/* Make a dummy mesh, saves copying */
DerivedMesh *dm;
/* CustomDataMask mask = CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL; */
CustomDataMask mask = CD_MASK_MESH; /* this seems more suitable, exporter,
- * for example, needs CD_MASK_MDEFORMVERT */
+ * for example, needs CD_MASK_MDEFORMVERT */
if (calc_undeformed)
mask |= CD_MASK_ORCO;
@@ -2496,33 +2368,34 @@ Mesh *BKE_mesh_new_from_object(
if (tmpcu->mat) {
for (i = tmpcu->totcol; i-- > 0; ) {
/* are we an object material or data based? */
+ tmpmesh->mat[i] = give_current_material(ob, i + 1);
- tmpmesh->mat[i] = ob->matbits[i] ? ob->mat[i] : tmpcu->mat[i];
-
- if (tmpmesh->mat[i]) {
+ if (((ob->matbits && ob->matbits[i]) || do_mat_id_data_us) && tmpmesh->mat[i]) {
id_us_plus(&tmpmesh->mat[i]->id);
}
}
}
break;
-#if 0
- /* Crashes when assigning the new material, not sure why */
case OB_MBALL:
- tmpmb = (MetaBall *)ob->data;
+ {
+ MetaBall *tmpmb = (MetaBall *)ob->data;
+ tmpmesh->mat = MEM_dupallocN(tmpmb->mat);
tmpmesh->totcol = tmpmb->totcol;
/* free old material list (if it exists) and adjust user counts */
if (tmpmb->mat) {
for (i = tmpmb->totcol; i-- > 0; ) {
- tmpmesh->mat[i] = tmpmb->mat[i]; /* CRASH HERE ??? */
- if (tmpmesh->mat[i]) {
- id_us_plus(&tmpmb->mat[i]->id);
+ /* are we an object material or data based? */
+ tmpmesh->mat[i] = give_current_material(ob, i + 1);
+
+ if (((ob->matbits && ob->matbits[i]) || do_mat_id_data_us) && tmpmesh->mat[i]) {
+ id_us_plus(&tmpmesh->mat[i]->id);
}
}
}
break;
-#endif
+ }
case OB_MESH:
if (!cage) {
@@ -2534,9 +2407,9 @@ Mesh *BKE_mesh_new_from_object(
if (origmesh->mat) {
for (i = origmesh->totcol; i-- > 0; ) {
/* are we an object material or data based? */
- tmpmesh->mat[i] = ob->matbits[i] ? ob->mat[i] : origmesh->mat[i];
+ tmpmesh->mat[i] = give_current_material(ob, i + 1);
- if (tmpmesh->mat[i]) {
+ if (((ob->matbits && ob->matbits[i]) || do_mat_id_data_us) && tmpmesh->mat[i]) {
id_us_plus(&tmpmesh->mat[i]->id);
}
}
@@ -2550,9 +2423,6 @@ Mesh *BKE_mesh_new_from_object(
BKE_mesh_tessface_ensure(tmpmesh);
}
- /* make sure materials get updated in objects */
- test_object_materials(bmain, &tmpmesh->id);
-
return tmpmesh;
}
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index 577a21285f8..fa113ef5eef 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -434,7 +434,7 @@ MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr)
}
/* This threshold is a bit touchy (usual float precision issue), this value seems OK. */
-#define LNOR_SPACE_TRIGO_THRESHOLD (1.0f - 1e-6f)
+#define LNOR_SPACE_TRIGO_THRESHOLD (1.0f - 1e-4f)
/* Should only be called once.
* Beware, this modifies ref_vec and other_vec in place!
@@ -677,7 +677,7 @@ static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopS
*/
copy_v3_v3(*lnor, polynors[mp_index]);
- /* printf("BASIC: handling loop %d / edge %d / vert %d\n", ml_curr_index, ml_curr->e, ml_curr->v); */
+ /* printf("BASIC: handling loop %d / edge %d / vert %d / poly %d\n", ml_curr_index, ml_curr->e, ml_curr->v, mp_index); */
/* If needed, generate this (simple!) lnor space. */
if (lnors_spacearr) {
@@ -3262,14 +3262,14 @@ void BKE_mesh_mdisp_flip(MDisps *md, const bool use_loop_mdisp_flip)
*/
void BKE_mesh_polygon_flip_ex(
MPoly *mpoly, MLoop *mloop, CustomData *ldata,
- MDisps *mdisp, const bool use_loop_mdisp_flip)
+ float (*lnors)[3], MDisps *mdisp, const bool use_loop_mdisp_flip)
{
int loopstart = mpoly->loopstart;
int loopend = loopstart + mpoly->totloop - 1;
const bool loops_in_ldata = (CustomData_get_layer(ldata, CD_MLOOP) == mloop);
if (mdisp) {
- for (int i = mpoly->loopstart; i <= loopend; i++) {
+ for (int i = loopstart; i <= loopend; i++) {
BKE_mesh_mdisp_flip(&mdisp[i], use_loop_mdisp_flip);
}
}
@@ -3288,6 +3288,9 @@ void BKE_mesh_polygon_flip_ex(
if (!loops_in_ldata) {
SWAP(MLoop, mloop[loopstart], mloop[loopend]);
}
+ if (lnors) {
+ swap_v3_v3(lnors[loopstart], lnors[loopend]);
+ }
CustomData_swap(ldata, loopstart, loopend);
}
/* Even if we did not swap the other 'pivot' loop, we need to set its swapped edge. */
@@ -3299,7 +3302,7 @@ void BKE_mesh_polygon_flip_ex(
void BKE_mesh_polygon_flip(MPoly *mpoly, MLoop *mloop, CustomData *ldata)
{
MDisps *mdisp = CustomData_get_layer(ldata, CD_MDISPS);
- BKE_mesh_polygon_flip_ex(mpoly, mloop, ldata, mdisp, true);
+ BKE_mesh_polygon_flip_ex(mpoly, mloop, ldata, NULL, mdisp, true);
}
/**
@@ -3315,7 +3318,7 @@ void BKE_mesh_polygons_flip(
int i;
for (mp = mpoly, i = 0; i < totpoly; mp++, i++) {
- BKE_mesh_polygon_flip_ex(mp, mloop, ldata, mdisp, true);
+ BKE_mesh_polygon_flip_ex(mp, mloop, ldata, NULL, mdisp, true);
}
}
diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c
index c8bb2e0e758..8562988b5e1 100644
--- a/source/blender/blenkernel/intern/mesh_mapping.c
+++ b/source/blender/blenkernel/intern/mesh_mapping.c
@@ -262,6 +262,51 @@ void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map, int **r_mem,
}
/**
+ * Generates a map where the key is the edge and the value is a list of looptris that use that edge.
+ * The lists are allocated from one memory pool.
+ */
+void BKE_mesh_vert_looptri_map_create(
+ MeshElemMap **r_map, int **r_mem,
+ const MVert *UNUSED(mvert), const int totvert,
+ const MLoopTri *mlooptri, const int totlooptri,
+ const MLoop *mloop, const int UNUSED(totloop))
+{
+ MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totvert, __func__);
+ int *indices = MEM_mallocN(sizeof(int) * (size_t)totlooptri * 3, __func__);
+ int *index_step;
+ const MLoopTri *mlt;
+ int i;
+
+ /* count face users */
+ for (i = 0, mlt = mlooptri; i < totlooptri; mlt++, i++) {
+ for (int j = 3; j--;) {
+ map[mloop[mlt->tri[j]].v].count++;
+ }
+ }
+
+ /* create offsets */
+ index_step = indices;
+ for (i = 0; i < totvert; i++) {
+ map[i].indices = index_step;
+ index_step += map[i].count;
+
+ /* re-count, using this as an index below */
+ map[i].count = 0;
+ }
+
+ /* assign looptri-edge users */
+ for (i = 0, mlt = mlooptri; i < totlooptri; mlt++, i++) {
+ for (int j = 3; j--;) {
+ MeshElemMap *map_ele = &map[mloop[mlt->tri[j]].v];
+ map_ele->indices[map_ele->count++] = i;
+ }
+ }
+
+ *r_map = map;
+ *r_mem = indices;
+}
+
+/**
* Generates a map where the key is the vertex and the value is a list of edges that use that vertex as an endpoint.
* The lists are allocated from one memory pool.
*/
@@ -348,6 +393,60 @@ void BKE_mesh_vert_edge_vert_map_create(
}
/**
+ * Generates a map where the key is the edge and the value is a list of loops that use that edge.
+ * Loops indices of a same poly are contiguous and in winding order.
+ * The lists are allocated from one memory pool.
+ */
+void BKE_mesh_edge_loop_map_create(MeshElemMap **r_map, int **r_mem,
+ const MEdge *UNUSED(medge), const int totedge,
+ const MPoly *mpoly, const int totpoly,
+ const MLoop *mloop, const int totloop)
+{
+ MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totedge, "edge-poly map");
+ int *indices = MEM_mallocN(sizeof(int) * (size_t)totloop * 2, "edge-poly map mem");
+ int *index_step;
+ const MPoly *mp;
+ int i;
+
+ /* count face users */
+ for (i = 0, mp = mpoly; i < totpoly; mp++, i++) {
+ const MLoop *ml;
+ int j = mp->totloop;
+ for (ml = &mloop[mp->loopstart]; j--; ml++) {
+ map[ml->e].count += 2;
+ }
+ }
+
+ /* create offsets */
+ index_step = indices;
+ for (i = 0; i < totedge; i++) {
+ map[i].indices = index_step;
+ index_step += map[i].count;
+
+ /* re-count, using this as an index below */
+ map[i].count = 0;
+ }
+
+ /* assign loop-edge users */
+ for (i = 0, mp = mpoly; i < totpoly; mp++, i++) {
+ const MLoop *ml;
+ MeshElemMap *map_ele;
+ const int max_loop = mp->loopstart + mp->totloop;
+ int j = mp->loopstart;
+ for (ml = &mloop[j]; j < max_loop; j++, ml++) {
+ map_ele = &map[ml->e];
+ map_ele->indices[map_ele->count++] = j;
+ map_ele->indices[map_ele->count++] = j + 1;
+ }
+ /* last edge/loop of poly, must point back to first loop! */
+ map_ele->indices[map_ele->count - 1] = mp->loopstart;
+ }
+
+ *r_map = map;
+ *r_mem = indices;
+}
+
+/**
* Generates a map where the key is the edge and the value is a list of polygons that use that edge.
* The lists are allocated from one memory pool.
*/
@@ -494,12 +593,12 @@ void BKE_mesh_origindex_map_create_looptri(
*/
typedef bool (*MeshRemap_CheckIslandBoundary)(
const struct MPoly *mpoly, const struct MLoop *mloop, const struct MEdge *medge,
- const int nbr_egde_users);
+ const int nbr_egde_users, void *user_data);
static void poly_edge_loop_islands_calc(
const MEdge *medge, const int totedge, const MPoly *mpoly, const int totpoly,
const MLoop *mloop, const int totloop, MeshElemMap *edge_poly_map,
- const bool use_bitflags, MeshRemap_CheckIslandBoundary edge_boundary_check,
+ const bool use_bitflags, MeshRemap_CheckIslandBoundary edge_boundary_check, void *edge_boundary_check_data,
int **r_poly_groups, int *r_totgroup, BLI_bitmap **r_edge_borders, int *r_totedgeborder)
{
int *poly_groups;
@@ -581,7 +680,7 @@ static void poly_edge_loop_islands_calc(
const MeshElemMap *map_ele = &edge_poly_map[me_idx];
const int *p = map_ele->indices;
int i = map_ele->count;
- if (!edge_boundary_check(mp, ml, me, i)) {
+ if (!edge_boundary_check(mp, ml, me, i, edge_boundary_check_data)) {
for (; i--; p++) {
/* if we meet other non initialized its a bug */
BLI_assert(ELEM(poly_groups[*p], 0, poly_group_id));
@@ -673,7 +772,7 @@ static void poly_edge_loop_islands_calc(
}
static bool poly_is_island_boundary_smooth_cb(
- const MPoly *mp, const MLoop *UNUSED(ml), const MEdge *me, const int nbr_egde_users)
+ const MPoly *mp, const MLoop *UNUSED(ml), const MEdge *me, const int nbr_egde_users, void *UNUSED(user_data))
{
/* Edge is sharp if its poly is sharp, or edge itself is sharp, or edge is not used by exactly two polygons. */
return (!(mp->flag & ME_SMOOTH) || (me->flag & ME_SHARP) || (nbr_egde_users != 2));
@@ -696,7 +795,7 @@ int *BKE_mesh_calc_smoothgroups(const MEdge *medge, const int totedge,
poly_edge_loop_islands_calc(
medge, totedge, mpoly, totpoly, mloop, totloop, NULL, use_bitflags,
- poly_is_island_boundary_smooth_cb, &poly_groups, r_totgroup, NULL, NULL);
+ poly_is_island_boundary_smooth_cb, NULL, &poly_groups, r_totgroup, NULL, NULL);
return poly_groups;
}
@@ -803,28 +902,60 @@ void BKE_mesh_loop_islands_add(
* Would make things much more complex though, and each UVMap would then need its own mesh mapping,
* not sure we want that at all!
*/
+typedef struct MeshCheckIslandBoundaryUv {
+ const MLoop *loops;
+ const MLoopUV *luvs;
+ const MeshElemMap *edge_loop_map;
+} MeshCheckIslandBoundaryUv;
+
static bool mesh_check_island_boundary_uv(
- const MPoly *UNUSED(mp), const MLoop *UNUSED(ml), const MEdge *me, const int UNUSED(nbr_egde_users))
+ const MPoly *UNUSED(mp), const MLoop *ml, const MEdge *me,
+ const int UNUSED(nbr_egde_users), void *user_data)
{
- /* Edge is UV boundary if tagged as seam. */
- return (me->flag & ME_SEAM) != 0;
+ if (user_data) {
+ const MeshCheckIslandBoundaryUv *data = user_data;
+ const MLoop *loops = data->loops;
+ const MLoopUV *luvs = data->luvs;
+ const MeshElemMap *edge_to_loops = &data->edge_loop_map[ml->e];
+
+ BLI_assert(edge_to_loops->count >= 2 && (edge_to_loops->count % 2) == 0);
+
+ const unsigned int v1 = loops[edge_to_loops->indices[0]].v;
+ const unsigned int v2 = loops[edge_to_loops->indices[1]].v;
+ const float *uvco_v1 = luvs[edge_to_loops->indices[0]].uv;
+ const float *uvco_v2 = luvs[edge_to_loops->indices[1]].uv;
+ for (int i = 2; i < edge_to_loops->count; i += 2) {
+ if (loops[edge_to_loops->indices[i]].v == v1) {
+ if (!equals_v2v2(uvco_v1, luvs[edge_to_loops->indices[i]].uv) ||
+ !equals_v2v2(uvco_v2, luvs[edge_to_loops->indices[i + 1]].uv))
+ {
+ return true;
+ }
+ }
+ else {
+ BLI_assert(loops[edge_to_loops->indices[i]].v == v2);
+ UNUSED_VARS_NDEBUG(v2);
+ if (!equals_v2v2(uvco_v2, luvs[edge_to_loops->indices[i]].uv) ||
+ !equals_v2v2(uvco_v1, luvs[edge_to_loops->indices[i + 1]].uv))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ else {
+ /* Edge is UV boundary if tagged as seam. */
+ return (me->flag & ME_SEAM) != 0;
+ }
}
-/**
- * Calculate UV islands.
- *
- * \note Currently we only consider edges tagges as seams as UV boundaries. This has the advantages of simplicity,
- * and being valid/common to all UV maps. However, it means actual UV islands whithout matching UV seams
- * will not be handled correctly...
- *
- * \note All this could be optimized...
- * Not sure it would be worth the more complex code, though, those loops are supposed to be really quick to do...
- */
-bool BKE_mesh_calc_islands_loop_poly_uv(
+static bool mesh_calc_islands_loop_poly_uv(
MVert *UNUSED(verts), const int UNUSED(totvert),
MEdge *edges, const int totedge,
MPoly *polys, const int totpoly,
MLoop *loops, const int totloop,
+ const MLoopUV *luvs,
MeshIslandStore *r_island_store)
{
int *poly_groups = NULL;
@@ -834,6 +965,11 @@ bool BKE_mesh_calc_islands_loop_poly_uv(
MeshElemMap *edge_poly_map;
int *edge_poly_mem;
+ MeshElemMap *edge_loop_map;
+ int *edge_loop_mem;
+
+ MeshCheckIslandBoundaryUv edge_boundary_check_data;
+
int *poly_indices;
int *loop_indices;
int num_pidx, num_lidx;
@@ -854,9 +990,18 @@ bool BKE_mesh_calc_islands_loop_poly_uv(
BKE_mesh_edge_poly_map_create(&edge_poly_map, &edge_poly_mem,
edges, totedge, polys, totpoly, loops, totloop);
+ if (luvs) {
+ BKE_mesh_edge_loop_map_create(&edge_loop_map, &edge_loop_mem,
+ edges, totedge, polys, totpoly, loops, totloop);
+ edge_boundary_check_data.loops = loops;
+ edge_boundary_check_data.luvs = luvs;
+ edge_boundary_check_data.edge_loop_map = edge_loop_map;
+ }
+
poly_edge_loop_islands_calc(
- edges, totedge, polys, totpoly, loops, totloop, edge_poly_map, false,
- mesh_check_island_boundary_uv, &poly_groups, &num_poly_groups, &edge_borders, &num_edge_borders);
+ edges, totedge, polys, totpoly, loops, totloop, edge_poly_map, false,
+ mesh_check_island_boundary_uv, luvs ? &edge_boundary_check_data : NULL,
+ &poly_groups, &num_poly_groups, &edge_borders, &num_edge_borders);
if (!num_poly_groups) {
/* Should never happen... */
@@ -913,6 +1058,11 @@ bool BKE_mesh_calc_islands_loop_poly_uv(
MEM_freeN(edge_poly_map);
MEM_freeN(edge_poly_mem);
+ if (luvs) {
+ MEM_freeN(edge_loop_map);
+ MEM_freeN(edge_loop_mem);
+ }
+
MEM_freeN(poly_indices);
MEM_freeN(loop_indices);
MEM_freeN(poly_groups);
@@ -928,4 +1078,42 @@ bool BKE_mesh_calc_islands_loop_poly_uv(
return true;
}
+/**
+ * Calculate 'generic' UV islands, i.e. based only on actual geometry data (edge seams), not some UV layers coordinates.
+ */
+bool BKE_mesh_calc_islands_loop_poly_edgeseam(
+ MVert *verts, const int totvert,
+ MEdge *edges, const int totedge,
+ MPoly *polys, const int totpoly,
+ MLoop *loops, const int totloop,
+ MeshIslandStore *r_island_store)
+{
+ return mesh_calc_islands_loop_poly_uv(
+ verts, totvert, edges, totedge, polys, totpoly, loops, totloop, NULL, r_island_store);
+}
+
+/**
+ * Calculate UV islands.
+ *
+ * \note If no MLoopUV layer is passed, we only consider edges tagged as seams as UV boundaries.
+ * This has the advantages of simplicity, and being valid/common to all UV maps.
+ * However, it means actual UV islands whithout matching UV seams will not be handled correctly...
+ * If a valid UV layer is passed as \a luvs parameter, UV coordinates are also used to detect islands boundaries.
+ *
+ * \note All this could be optimized...
+ * Not sure it would be worth the more complex code, though, those loops are supposed to be really quick to do...
+ */
+bool BKE_mesh_calc_islands_loop_poly_uvmap(
+ MVert *verts, const int totvert,
+ MEdge *edges, const int totedge,
+ MPoly *polys, const int totpoly,
+ MLoop *loops, const int totloop,
+ const MLoopUV *luvs,
+ MeshIslandStore *r_island_store)
+{
+ BLI_assert(luvs != NULL);
+ return mesh_calc_islands_loop_poly_uv(
+ verts, totvert, edges, totedge, polys, totpoly, loops, totloop, luvs, r_island_store);
+}
+
/** \} */
diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c
index 49dd0b104ab..ba890b005d8 100644
--- a/source/blender/blenkernel/intern/mesh_validate.c
+++ b/source/blender/blenkernel/intern/mesh_validate.c
@@ -284,7 +284,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
bool fix_normal = true;
for (j = 0; j < 3; j++) {
- if (!finite(mv->co[j])) {
+ if (!isfinite(mv->co[j])) {
PRINT_ERR("\tVertex %u: has invalid coordinate\n", i);
if (do_fixes) {
@@ -765,7 +765,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
for (j = 0, dw = dv->dw; j < dv->totweight; j++, dw++) {
/* note, greater than max defgroups is accounted for in our code, but not < 0 */
- if (!finite(dw->weight)) {
+ if (!isfinite(dw->weight)) {
PRINT_ERR("\tVertex deform %u, group %d has weight: %f\n", i, dw->def_nr, dw->weight);
if (do_fixes) {
dw->weight = 0.0f;
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 716da14cae6..41e4c21d814 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -707,7 +707,7 @@ void test_object_modifiers(Object *ob)
*/
const char *modifier_path_relbase(Object *ob)
{
- if (G.relbase_valid || ob->id.lib) {
+ if (G.relbase_valid || ID_IS_LINKED_DATABLOCK(ob)) {
return ID_BLEND_PATH(G.main, &ob->id);
}
else {
diff --git a/source/blender/blenkernel/intern/modifiers_bmesh.c b/source/blender/blenkernel/intern/modifiers_bmesh.c
index 18f3db6bd15..0838630a6cb 100644
--- a/source/blender/blenkernel/intern/modifiers_bmesh.c
+++ b/source/blender/blenkernel/intern/modifiers_bmesh.c
@@ -211,7 +211,9 @@ BMEditMesh *DM_to_editbmesh(DerivedMesh *dm, BMEditMesh *existing, const bool do
bm = em->bm;
}
else {
- bm = BM_mesh_create(&bm_mesh_allocsize_default);
+ bm = BM_mesh_create(
+ &bm_mesh_allocsize_default,
+ &((struct BMeshCreateParams){.use_toolflags = false,}));
}
DM_to_bmesh_ex(dm, bm, do_tessellate);
@@ -233,7 +235,9 @@ BMesh *DM_to_bmesh(DerivedMesh *dm, const bool calc_face_normal)
BMesh *bm;
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_DM(dm);
- bm = BM_mesh_create(&allocsize);
+ bm = BM_mesh_create(
+ &allocsize,
+ &((struct BMeshCreateParams){.use_toolflags = false,}));
DM_to_bmesh_ex(dm, bm, calc_face_normal);
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index a8d3c600817..6794a8e8f93 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -608,7 +608,7 @@ static MovieClip *movieclip_alloc(Main *bmain, const char *name)
return clip;
}
-static void movieclip_load_get_szie(MovieClip *clip)
+static void movieclip_load_get_size(MovieClip *clip)
{
int width, height;
MovieClipUser user = {0};
@@ -670,7 +670,7 @@ MovieClip *BKE_movieclip_file_add(Main *bmain, const char *name)
detect_clip_source(clip);
- movieclip_load_get_szie(clip);
+ movieclip_load_get_size(clip);
if (clip->lastsize[0]) {
int width = clip->lastsize[0];
@@ -1033,7 +1033,7 @@ static ImBuf *get_stable_cached_frame(MovieClip *clip, MovieClipUser *user, ImBu
stableibuf = cache->stabilized.ibuf;
- BKE_tracking_stabilization_data_get(&clip->tracking, clip_framenr, stableibuf->x, stableibuf->y, tloc, &tscale, &tangle);
+ BKE_tracking_stabilization_data_get(clip, clip_framenr, stableibuf->x, stableibuf->y, tloc, &tscale, &tangle);
/* check for stabilization parameters */
if (tscale != cache->stabilized.scale ||
@@ -1057,7 +1057,7 @@ static ImBuf *put_stabilized_frame_to_cache(MovieClip *clip, MovieClipUser *user
float tloc[2], tscale, tangle;
int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, framenr);
- stableibuf = BKE_tracking_stabilize_frame(&clip->tracking, clip_framenr, ibuf, tloc, &tscale, &tangle);
+ stableibuf = BKE_tracking_stabilize_frame(clip, clip_framenr, ibuf, tloc, &tscale, &tangle);
copy_v2_v2(cache->stabilized.loc, tloc);
@@ -1247,8 +1247,6 @@ static void free_buffers(MovieClip *clip)
IMB_free_anim(clip->anim);
clip->anim = NULL;
}
-
- BKE_animdata_free((ID *) clip);
}
void BKE_movieclip_clear_cache(MovieClip *clip)
@@ -1270,13 +1268,11 @@ void BKE_movieclip_reload(MovieClip *clip)
/* clear cache */
free_buffers(clip);
- clip->tracking.stabilization.ok = false;
-
/* update clip source */
detect_clip_source(clip);
clip->lastsize[0] = clip->lastsize[1] = 0;
- movieclip_load_get_szie(clip);
+ movieclip_load_get_size(clip);
movieclip_calc_length(clip);
@@ -1482,78 +1478,40 @@ void BKE_movieclip_build_proxy_frame_for_ibuf(MovieClip *clip, ImBuf *ibuf, stru
}
}
+/** Free (or release) any data used by this movie clip (does not free the clip itself). */
void BKE_movieclip_free(MovieClip *clip)
{
+ /* Also frees animdata. */
free_buffers(clip);
BKE_tracking_free(&clip->tracking);
+ BKE_animdata_free((ID *) clip, false);
}
-void BKE_movieclip_unlink(Main *bmain, MovieClip *clip)
+MovieClip *BKE_movieclip_copy(Main *bmain, MovieClip *clip)
{
- bScreen *scr;
- ScrArea *area;
- SpaceLink *sl;
- Scene *sce;
- Object *ob;
+ MovieClip *clip_new;
- 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) {
- if (sl->spacetype == SPACE_CLIP) {
- SpaceClip *sc = (SpaceClip *) sl;
+ clip_new = BKE_libblock_copy(bmain, &clip->id);
- if (sc->clip == clip)
- sc->clip = NULL;
- }
- else if (sl->spacetype == SPACE_VIEW3D) {
- View3D *v3d = (View3D *) sl;
- BGpic *bgpic;
+ clip_new->anim = NULL;
+ clip_new->cache = NULL;
- for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
- if (bgpic->clip == clip)
- bgpic->clip = NULL;
- }
- }
- }
- }
- }
+ BKE_tracking_copy(&clip_new->tracking, &clip->tracking);
+ clip_new->tracking_context = NULL;
- for (sce = bmain->scene.first; sce; sce = sce->id.next) {
- if (sce->clip == clip)
- sce->clip = NULL;
- }
+ id_us_plus((ID *)clip_new->gpd);
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- bConstraint *con;
+ BKE_color_managed_colorspace_settings_copy(&clip_new->colorspace_settings, &clip->colorspace_settings);
- for (con = ob->constraints.first; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_FOLLOWTRACK) {
- bFollowTrackConstraint *data = (bFollowTrackConstraint *) con->data;
+ BKE_id_copy_ensure_local(bmain, &clip->id, &clip_new->id);
- if (data->clip == clip)
- data->clip = NULL;
- }
- else if (con->type == CONSTRAINT_TYPE_CAMERASOLVER) {
- bCameraSolverConstraint *data = (bCameraSolverConstraint *) con->data;
-
- if (data->clip == clip)
- data->clip = NULL;
- }
- else if (con->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
- bObjectSolverConstraint *data = (bObjectSolverConstraint *) con->data;
-
- if (data->clip == clip)
- data->clip = NULL;
- }
- }
- }
-
- FOREACH_NODETREE(bmain, ntree, id) {
- BKE_node_tree_unlink_id((ID *)clip, ntree);
- } FOREACH_NODETREE_END
+ return clip_new;
+}
- clip->id.us = 0;
+void BKE_movieclip_make_local(Main *bmain, MovieClip *clip, const bool lib_local)
+{
+ BKE_id_make_local_generic(bmain, &clip->id, true, lib_local);
}
float BKE_movieclip_remap_scene_to_clip_frame(MovieClip *clip, float framenr)
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index 0527df67033..c321bc92a71 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -183,7 +183,7 @@ NlaStrip *copy_nlastrip(NlaStrip *strip, const bool use_same_action)
}
else {
/* use a copy of the action instead (user count shouldn't have changed yet) */
- strip_d->act = BKE_action_copy(strip_d->act);
+ strip_d->act = BKE_action_copy(G.main, strip_d->act);
}
}
@@ -1291,7 +1291,7 @@ void BKE_nlastrip_recalculate_bounds(NlaStrip *strip)
if (IS_EQF(mapping, 0.0f) == 0)
strip->end = (actlen * mapping) + strip->start;
- /* make sure we don't overlap our neighbours */
+ /* make sure we don't overlap our neighbors */
nlastrip_fix_resize_overlaps(strip);
}
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 88de93aa934..f7e828e1ddc 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -58,6 +58,8 @@
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_node.h"
@@ -1291,11 +1293,10 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool ski
/* is ntree part of library? */
if (bmain && !skip_database && BLI_findindex(&bmain->nodetree, ntree) >= 0) {
- newtree = BKE_libblock_copy(&ntree->id);
+ newtree = BKE_libblock_copy(bmain, &ntree->id);
}
else {
newtree = BKE_libblock_copy_nolib(&ntree->id, true);
- newtree->id.lib = NULL; /* same as owning datablock id.lib */
}
id_us_plus((ID *)newtree->gpd);
@@ -1375,9 +1376,7 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool ski
/* node tree will generate its own interface type */
newtree->interface_type = NULL;
- if (ntree->id.lib) {
- BKE_id_lib_local_paths(bmain, ntree->id.lib, &newtree->id);
- }
+ BKE_id_copy_ensure_local(bmain, &ntree->id, &newtree->id);
return newtree;
}
@@ -1386,9 +1385,9 @@ bNodeTree *ntreeCopyTree_ex(bNodeTree *ntree, Main *bmain, const bool do_id_user
{
return ntreeCopyTree_internal(ntree, bmain, false, do_id_user, true, true);
}
-bNodeTree *ntreeCopyTree(bNodeTree *ntree)
+bNodeTree *ntreeCopyTree(Main *bmain, bNodeTree *ntree)
{
- return ntreeCopyTree_ex(ntree, G.main, true);
+ return ntreeCopyTree_ex(ntree, bmain, true);
}
/* use when duplicating scenes */
@@ -1868,21 +1867,21 @@ static void free_localized_node_groups(bNodeTree *ntree)
for (node = ntree->nodes.first; node; node = node->next) {
if (node->type == NODE_GROUP && node->id) {
bNodeTree *ngroup = (bNodeTree *)node->id;
- ntreeFreeTree_ex(ngroup, false);
+ ntreeFreeTree(ngroup);
MEM_freeN(ngroup);
}
}
}
-/* do not free ntree itself here, BKE_libblock_free calls this function too */
-void ntreeFreeTree_ex(bNodeTree *ntree, const bool do_id_user)
+/** Free (or release) any data used by this nodetree (does not free the nodetree itself). */
+void ntreeFreeTree(bNodeTree *ntree)
{
bNodeTree *tntree;
bNode *node, *next;
bNodeSocket *sock, *nextsock;
-
- if (ntree == NULL) return;
-
+
+ BKE_animdata_free((ID *)ntree, false);
+
/* XXX hack! node trees should not store execution graphs at all.
* This should be removed when old tree types no longer require it.
* Currently the execution data for texture nodes remains in the tree
@@ -1906,29 +1905,10 @@ void ntreeFreeTree_ex(bNodeTree *ntree, const bool do_id_user)
/* unregister associated RNA types */
ntreeInterfaceTypeFree(ntree);
- BKE_animdata_free((ID *)ntree);
-
- id_us_min((ID *)ntree->gpd);
-
BLI_freelistN(&ntree->links); /* do first, then unlink_node goes fast */
for (node = ntree->nodes.first; node; node = next) {
next = node->next;
-
- /* ntreeUserIncrefID inline */
-
- /* XXX, this is correct, however when freeing the entire database
- * this ends up accessing freed data which isn't properly unlinking
- * its self from scene nodes, SO - for now prefer invalid usercounts
- * on free rather then bad memory access - Campbell */
-#if 0
- if (do_id_user) {
- id_us_min(node->id);
- }
-#else
- (void)do_id_user;
-#endif
-
node_free_node_ex(ntree, node, false, false);
}
@@ -1960,11 +1940,6 @@ void ntreeFreeTree_ex(bNodeTree *ntree, const bool do_id_user)
BKE_libblock_free_data(G.main, &ntree->id);
}
}
-/* same as ntreeFreeTree_ex but always manage users */
-void ntreeFreeTree(bNodeTree *ntree)
-{
- ntreeFreeTree_ex(ntree, true);
-}
void ntreeFreeCache(bNodeTree *ntree)
{
@@ -2058,71 +2033,9 @@ bNodeTree *ntreeFromID(ID *id)
}
}
-static void extern_local_ntree(bNodeTree *ntree)
+void ntreeMakeLocal(Main *bmain, bNodeTree *ntree, bool id_in_mainlist, const bool lib_local)
{
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
- if (node->id) {
- id_lib_extern(node->id);
- }
- }
-}
-
-void ntreeMakeLocal(bNodeTree *ntree, bool id_in_mainlist)
-{
- Main *bmain = G.main;
- bool lib = false, local = false;
-
- /* - only lib users: do nothing
- * - only local users: set flag
- * - mixed: make copy
- */
-
- if (ntree->id.lib == NULL) return;
- if (ntree->id.us == 1) {
- id_clear_lib_data_ex(bmain, (ID *)ntree, id_in_mainlist);
- extern_local_ntree(ntree);
- return;
- }
-
- /* now check users of groups... again typedepending, callback... */
- FOREACH_NODETREE(G.main, tntree, owner_id) {
- bNode *node;
- /* find if group is in tree */
- for (node = tntree->nodes.first; node; node = node->next) {
- if (node->id == (ID *)ntree) {
- if (owner_id->lib)
- lib = true;
- else
- local = true;
- }
- }
- } FOREACH_NODETREE_END
-
- /* if all users are local, we simply make tree local */
- if (local && !lib) {
- id_clear_lib_data_ex(bmain, (ID *)ntree, id_in_mainlist);
- extern_local_ntree(ntree);
- }
- else if (local && lib) {
- /* this is the mixed case, we copy the tree and assign it to local users */
- bNodeTree *newtree = ntreeCopyTree(ntree);
-
- newtree->id.us = 0;
-
- FOREACH_NODETREE(G.main, tntree, owner_id) {
- bNode *node;
- /* find if group is in tree */
- for (node = tntree->nodes.first; node; node = node->next) {
- if (node->id == (ID *)ntree) {
- if (owner_id->lib == NULL) {
- node->id = (ID *)newtree;
- id_us_plus(&newtree->id);
- id_us_min(&ntree->id);
- }
- }
- }
- } FOREACH_NODETREE_END
- }
+ BKE_id_make_local_generic(bmain, &ntree->id, id_in_mainlist, lib_local);
}
int ntreeNodeExists(bNodeTree *ntree, bNode *testnode)
@@ -2251,7 +2164,7 @@ void ntreeLocalMerge(bNodeTree *localtree, bNodeTree *ntree)
if (ntree->typeinfo->local_merge)
ntree->typeinfo->local_merge(localtree, ntree);
- ntreeFreeTree_ex(localtree, false);
+ ntreeFreeTree(localtree);
MEM_freeN(localtree);
}
}
@@ -2504,15 +2417,21 @@ void ntreeInterfaceTypeUpdate(bNodeTree *ntree)
/* ************ find stuff *************** */
+bNode *ntreeFindType(const bNodeTree *ntree, int type)
+{
+ if (ntree) {
+ for (bNode * node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == type) {
+ return node;
+ }
+ }
+ }
+ return NULL;
+}
+
bool ntreeHasType(const bNodeTree *ntree, int type)
{
- bNode *node;
-
- if (ntree)
- for (node = ntree->nodes.first; node; node = node->next)
- if (node->type == type)
- return true;
- return false;
+ return ntreeFindType(ntree, type) != NULL;
}
bool ntreeHasTree(const bNodeTree *ntree, const bNodeTree *lookup)
@@ -2819,7 +2738,7 @@ void BKE_node_clipboard_add_node(bNode *node)
node_info->id = node->id;
if (node->id) {
BLI_strncpy(node_info->id_name, node->id->name, sizeof(node_info->id_name));
- if (node->id->lib) {
+ if (ID_IS_LINKED_DATABLOCK(node->id)) {
BLI_strncpy(node_info->library_name, node->id->lib->filepath, sizeof(node_info->library_name));
}
else {
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 1ba4852623c..5bcf31ba45b 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -93,6 +93,8 @@
#include "BKE_lamp.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_linestyle.h"
#include "BKE_mesh.h"
#include "BKE_editmesh.h"
@@ -244,6 +246,11 @@ bool BKE_object_support_modifier_type_check(Object *ob, int modifier_type)
mti = modifierType_getInfo(modifier_type);
+
+ if (ob->type == OB_LATTICE && (mti->flags & eModifierTypeFlag_AcceptsLattice) == 0) {
+ return false;
+ }
+
if (!((mti->flags & eModifierTypeFlag_AcceptsCVs) ||
(ob->type == OB_MESH && (mti->flags & eModifierTypeFlag_AcceptsMesh))))
{
@@ -312,14 +319,14 @@ void BKE_object_free_derived_caches(Object *ob)
if (ob->type == OB_MESH) {
Mesh *me = ob->data;
- if (me->bb) {
+ if (me && me->bb) {
me->bb->flag |= BOUNDBOX_DIRTY;
}
}
else if (ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) {
Curve *cu = ob->data;
- if (cu->bb) {
+ if (cu && cu->bb) {
cu->bb->flag |= BOUNDBOX_DIRTY;
}
}
@@ -388,77 +395,52 @@ void BKE_object_free_caches(Object *object)
}
}
-/* do not free object itself */
-void BKE_object_free_ex(Object *ob, bool do_id_user)
+/** Free (or release) any data used by this object (does not free the object itself). */
+void BKE_object_free(Object *ob)
{
- int a;
-
+ BKE_animdata_free((ID *)ob, false);
+
BKE_object_free_modifiers(ob);
-
- /* disconnect specific data, but not for lib data (might be indirect data, can get relinked) */
- if (ob->data) {
- ID *id = ob->data;
- id_us_min(id);
- if (id->us == 0 && id->lib == NULL) {
- switch (ob->type) {
- case OB_MESH:
- BKE_mesh_unlink((Mesh *)id);
- break;
- case OB_CURVE:
- BKE_curve_unlink((Curve *)id);
- break;
- case OB_MBALL:
- BKE_mball_unlink((MetaBall *)id);
- break;
- }
- }
- ob->data = NULL;
- }
- if (ob->mat) {
- for (a = 0; a < ob->totcol; a++) {
- if (ob->mat[a])
- id_us_min(&ob->mat[a]->id);
- }
- MEM_freeN(ob->mat);
+ MEM_SAFE_FREE(ob->mat);
+ MEM_SAFE_FREE(ob->matbits);
+ MEM_SAFE_FREE(ob->iuser);
+ MEM_SAFE_FREE(ob->bb);
+
+ BLI_freelistN(&ob->defbase);
+ if (ob->pose) {
+ BKE_pose_free_ex(ob->pose, false);
+ ob->pose = NULL;
}
- if (ob->matbits) MEM_freeN(ob->matbits);
- ob->mat = NULL;
- ob->matbits = NULL;
- if (ob->iuser) MEM_freeN(ob->iuser);
- ob->iuser = NULL;
- if (ob->bb) MEM_freeN(ob->bb);
- ob->bb = NULL;
- if (ob->adt) BKE_animdata_free((ID *)ob);
- if (ob->poselib)
- id_us_min(&ob->poselib->id);
- if (ob->gpd)
- id_us_min(&ob->gpd->id);
- if (ob->defbase.first)
- BLI_freelistN(&ob->defbase);
- if (ob->pose)
- BKE_pose_free_ex(ob->pose, do_id_user);
- if (ob->mpath)
+ if (ob->mpath) {
animviz_free_motionpath(ob->mpath);
+ ob->mpath = NULL;
+ }
BKE_bproperty_free_list(&ob->prop);
-
+
free_sensors(&ob->sensors);
free_controllers(&ob->controllers);
free_actuators(&ob->actuators);
- BKE_constraints_free_ex(&ob->constraints, do_id_user);
+ BKE_constraints_free_ex(&ob->constraints, false);
free_partdeflect(ob->pd);
BKE_rigidbody_free_object(ob);
BKE_rigidbody_free_constraint(ob);
- if (ob->soft) sbFree(ob->soft);
- if (ob->bsoft) bsbFree(ob->bsoft);
- if (ob->gpulamp.first) GPU_lamp_free(ob);
+ if (ob->soft) {
+ sbFree(ob->soft);
+ ob->soft = NULL;
+ }
+ if (ob->bsoft) {
+ bsbFree(ob->bsoft);
+ ob->bsoft = NULL;
+ }
+ GPU_lamp_free(ob);
BKE_sculptsession_free(ob);
- if (ob->pc_ids.first) BLI_freelistN(&ob->pc_ids);
+ BLI_freelistN(&ob->pc_ids);
BLI_freelistN(&ob->lodlevels);
@@ -468,398 +450,12 @@ void BKE_object_free_ex(Object *ob, bool do_id_user)
if (ob->curve_cache->path)
free_path(ob->curve_cache->path);
MEM_freeN(ob->curve_cache);
+ ob->curve_cache = NULL;
}
BKE_previewimg_free(&ob->preview);
}
-void BKE_object_free(Object *ob)
-{
- BKE_object_free_ex(ob, true);
-}
-
-static void unlink_object__unlinkModifierLinks(void *userData, Object *ob, Object **obpoin, int UNUSED(cd_flag))
-{
- Object *unlinkOb = userData;
-
- if (*obpoin == unlinkOb) {
- *obpoin = NULL;
- // XXX: should this just be OB_RECALC_DATA?
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
- }
-}
-
-void BKE_object_unlink(Main *bmain, Object *ob)
-{
- Object *obt;
- Material *mat;
- World *wrld;
- bScreen *sc;
- Scene *sce;
- SceneRenderLayer *srl;
- FreestyleLineSet *lineset;
- bNodeTree *ntree;
- Curve *cu;
- Tex *tex;
- Group *group;
- Camera *camera;
- bConstraint *con;
- //bActionStrip *strip; // XXX animsys
- ModifierData *md;
- ARegion *ar;
- RegionView3D *rv3d;
- LodLevel *lod;
- int a, found;
-
- unlink_controllers(&ob->controllers);
- unlink_actuators(&ob->actuators);
-
- /* check all objects: parents en bevels and fields, also from libraries */
- /* FIXME: need to check all animation blocks (drivers) */
- obt = bmain->object.first;
- while (obt) {
- if (obt->proxy == ob)
- obt->proxy = NULL;
- if (obt->proxy_from == ob) {
- obt->proxy_from = NULL;
- DAG_id_tag_update(&obt->id, OB_RECALC_OB);
- }
- if (obt->proxy_group == ob)
- obt->proxy_group = NULL;
-
- if (obt->parent == ob) {
- obt->parent = NULL;
- DAG_id_tag_update(&obt->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
- }
-
- modifiers_foreachObjectLink(obt, unlink_object__unlinkModifierLinks, ob);
-
- if (ELEM(obt->type, OB_CURVE, OB_FONT)) {
- cu = obt->data;
-
- if (cu->bevobj == ob) {
- cu->bevobj = NULL;
- DAG_id_tag_update(&obt->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
- }
- if (cu->taperobj == ob) {
- cu->taperobj = NULL;
- DAG_id_tag_update(&obt->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
- }
- if (cu->textoncurve == ob) {
- cu->textoncurve = NULL;
- DAG_id_tag_update(&obt->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
- }
- }
- else if (obt->type == OB_ARMATURE && obt->pose) {
- bPoseChannel *pchan;
- for (pchan = obt->pose->chanbase.first; pchan; pchan = pchan->next) {
- for (con = pchan->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(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->tar = NULL;
- ct->subtarget[0] = '\0';
- DAG_id_tag_update(&obt->id, OB_RECALC_DATA);
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 0);
- }
- }
- if (pchan->custom == ob)
- pchan->custom = NULL;
- }
- }
- else if (ELEM(OB_MBALL, ob->type, obt->type)) {
- if (BKE_mball_is_basis_for(obt, ob))
- DAG_id_tag_update(&obt->id, OB_RECALC_DATA);
- }
-
- sca_remove_ob_poin(obt, ob);
-
- for (con = obt->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(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->tar = NULL;
- ct->subtarget[0] = '\0';
- DAG_id_tag_update(&obt->id, OB_RECALC_DATA);
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 0);
- }
- }
-
- /* object is deflector or field */
- if (ob->pd) {
- if (obt->soft)
- DAG_id_tag_update(&obt->id, OB_RECALC_DATA);
-
- /* cloth */
- for (md = obt->modifiers.first; md; md = md->next)
- if (md->type == eModifierType_Cloth)
- DAG_id_tag_update(&obt->id, OB_RECALC_DATA);
- }
-
- /* strips */
-#if 0 // XXX old animation system
- for (strip = obt->nlastrips.first; strip; strip = strip->next) {
- if (strip->object == ob)
- strip->object = NULL;
-
- if (strip->modifiers.first) {
- bActionModifier *amod;
- for (amod = strip->modifiers.first; amod; amod = amod->next)
- if (amod->ob == ob)
- amod->ob = NULL;
- }
- }
-#endif // XXX old animation system
-
- /* particle systems */
- if (obt->particlesystem.first) {
- ParticleSystem *tpsys = obt->particlesystem.first;
- for (; tpsys; tpsys = tpsys->next) {
- BoidState *state = NULL;
- BoidRule *rule = NULL;
-
- ParticleTarget *pt = tpsys->targets.first;
- for (; pt; pt = pt->next) {
- if (pt->ob == ob) {
- pt->ob = NULL;
- DAG_id_tag_update(&obt->id, OB_RECALC_DATA);
- break;
- }
- }
-
- if (tpsys->target_ob == ob) {
- tpsys->target_ob = NULL;
- DAG_id_tag_update(&obt->id, OB_RECALC_DATA);
- }
-
- if (tpsys->part->dup_ob == ob)
- tpsys->part->dup_ob = NULL;
-
- if (tpsys->part->phystype == PART_PHYS_BOIDS) {
- ParticleData *pa;
- BoidParticle *bpa;
- int p;
-
- for (p = 0, pa = tpsys->particles; p < tpsys->totpart; p++, pa++) {
- bpa = pa->boid;
- if (bpa->ground == ob)
- bpa->ground = NULL;
- }
- }
- if (tpsys->part->boids) {
- for (state = tpsys->part->boids->states.first; state; state = state->next) {
- for (rule = state->rules.first; rule; rule = rule->next) {
- if (rule->type == eBoidRuleType_Avoid) {
- BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule;
- if (gabr->ob == ob)
- gabr->ob = NULL;
- }
- else if (rule->type == eBoidRuleType_FollowLeader) {
- BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule;
- if (flbr->ob == ob)
- flbr->ob = NULL;
- }
- }
- }
- }
-
- if (tpsys->parent == ob)
- tpsys->parent = NULL;
- }
- if (ob->pd)
- DAG_id_tag_update(&obt->id, OB_RECALC_DATA);
- }
-
- /* levels of detail */
- for (lod = obt->lodlevels.first; lod; lod = lod->next) {
- if (lod->source == ob)
- lod->source = NULL;
- }
-
- obt = obt->id.next;
- }
-
- /* materials */
- for (mat = bmain->mat.first; mat; mat = mat->id.next) {
- if (mat->nodetree) {
- ntreeSwitchID(mat->nodetree, &ob->id, NULL);
- }
- for (a = 0; a < MAX_MTEX; a++) {
- if (mat->mtex[a] && ob == mat->mtex[a]->object) {
- /* actually, test for lib here... to do */
- mat->mtex[a]->object = NULL;
- }
- }
- }
-
- /* node trees */
- for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) {
- if (ntree->type == NTREE_SHADER)
- ntreeSwitchID(ntree, &ob->id, NULL);
- }
-
- /* textures */
- for (tex = bmain->tex.first; tex; tex = tex->id.next) {
- if (tex->env && (ob == tex->env->object)) tex->env->object = NULL;
- if (tex->pd && (ob == tex->pd->object)) tex->pd->object = NULL;
- if (tex->vd && (ob == tex->vd->object)) tex->vd->object = NULL;
- }
-
- /* worlds */
- wrld = bmain->world.first;
- while (wrld) {
- if (wrld->id.lib == NULL) {
- for (a = 0; a < MAX_MTEX; a++) {
- if (wrld->mtex[a] && ob == wrld->mtex[a]->object)
- wrld->mtex[a]->object = NULL;
- }
- }
-
- wrld = wrld->id.next;
- }
-
- /* scenes */
- sce = bmain->scene.first;
- while (sce) {
- if (sce->id.lib == NULL) {
- if (sce->camera == ob) sce->camera = NULL;
- if (sce->toolsettings->skgen_template == ob) sce->toolsettings->skgen_template = NULL;
- if (sce->toolsettings->particle.object == ob) sce->toolsettings->particle.object = NULL;
- if (sce->toolsettings->particle.shape_object == ob) sce->toolsettings->particle.shape_object = NULL;
-
-#ifdef DURIAN_CAMERA_SWITCH
- {
- TimeMarker *m;
-
- for (m = sce->markers.first; m; m = m->next) {
- if (m->camera == ob)
- m->camera = NULL;
- }
- }
-#endif
- if (sce->ed) {
- Sequence *seq;
- SEQ_BEGIN(sce->ed, seq)
- {
- if (seq->scene_camera == ob) {
- seq->scene_camera = NULL;
- }
- }
- SEQ_END
- }
-
- for (srl = sce->r.layers.first; srl; srl = srl->next) {
- for (lineset = (FreestyleLineSet *)srl->freestyleConfig.linesets.first;
- lineset; lineset = lineset->next)
- {
- if (lineset->linestyle) {
- BKE_linestyle_target_object_unlink(lineset->linestyle, ob);
- }
- }
- }
- }
-
- sce = sce->id.next;
- }
-
- /* screens */
- sc = bmain->screen.first;
- while (sc) {
- ScrArea *sa = sc->areabase.first;
- while (sa) {
- SpaceLink *sl;
-
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
- if (sl->spacetype == SPACE_VIEW3D) {
- View3D *v3d = (View3D *) sl;
-
- /* found doesn't need to be set here */
- if (v3d->ob_centre == ob) {
- v3d->ob_centre = NULL;
- v3d->ob_centre_bone[0] = '\0';
- }
- if (v3d->localvd && v3d->localvd->ob_centre == ob) {
- v3d->localvd->ob_centre = NULL;
- v3d->localvd->ob_centre_bone[0] = '\0';
- }
-
- found = 0;
- if (v3d->camera == ob) {
- v3d->camera = NULL;
- found = 1;
- }
- if (v3d->localvd && v3d->localvd->camera == ob) {
- v3d->localvd->camera = NULL;
- found += 2;
- }
-
- if (found) {
- if (sa->spacetype == SPACE_VIEW3D) {
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->regiontype == RGN_TYPE_WINDOW) {
- rv3d = (RegionView3D *)ar->regiondata;
- if (found == 1 || found == 3) {
- if (rv3d->persp == RV3D_CAMOB)
- rv3d->persp = RV3D_PERSP;
- }
- if (found == 2 || found == 3) {
- if (rv3d->localvd && rv3d->localvd->persp == RV3D_CAMOB)
- rv3d->localvd->persp = RV3D_PERSP;
- }
- }
- }
- }
- }
- }
-#if 0
- else if (ELEM(sl->spacetype, SPACE_OUTLINER, SPACE_BUTS, SPACE_NODE)) {
- /* now handled by WM_main_remove_editor_id_reference */
- }
-#endif
- }
-
- sa = sa->next;
- }
- sc = sc->id.next;
- }
-
- /* groups */
- group = bmain->group.first;
- while (group) {
- BKE_group_object_unlink(group, ob, NULL, NULL);
- group = group->id.next;
- }
-
- /* cameras */
- camera = bmain->camera.first;
- while (camera) {
- if (camera->dof_ob == ob) {
- camera->dof_ob = NULL;
- }
- camera = camera->id.next;
- }
-}
-
/* actual check for internal data, not context or flags */
bool BKE_object_is_in_editmode(Object *ob)
{
@@ -1498,7 +1094,7 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches)
ModifierData *md;
int a;
- obn = BKE_libblock_copy_ex(bmain, &ob->id);
+ obn = BKE_libblock_copy(bmain, &ob->id);
if (ob->totcol) {
obn->mat = MEM_dupallocN(ob->mat);
@@ -1522,11 +1118,9 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches)
BLI_listbase_clear(&obn->prop);
BKE_bproperty_copy_list(&obn->prop, &ob->prop);
-
- copy_sensors(&obn->sensors, &ob->sensors);
- copy_controllers(&obn->controllers, &ob->controllers);
- copy_actuators(&obn->actuators, &ob->actuators);
-
+
+ BKE_sca_logic_copy(obn, ob);
+
if (ob->pose) {
copy_object_pose(obn, ob);
/* backwards compat... non-armatures can get poses in older files? */
@@ -1542,7 +1136,7 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches)
/* increase user numbers */
id_us_plus((ID *)obn->data);
id_us_plus((ID *)obn->gpd);
- id_lib_extern((ID *)obn->dup_group);
+ id_us_plus((ID *)obn->dup_group);
for (a = 0; a < obn->totcol; a++) id_us_plus((ID *)obn->mat[a]);
@@ -1570,13 +1164,10 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches)
copy_object_lod(obn, ob);
-
/* Copy runtime surve data. */
obn->curve_cache = NULL;
- if (ob->id.lib) {
- BKE_id_lib_local_paths(bmain, ob->id.lib, &obn->id);
- }
+ BKE_id_copy_ensure_local(bmain, &ob->id, &obn->id);
/* Do not copy object's preview (mostly due to the fact renderers create temp copy of objects). */
obn->preview = NULL;
@@ -1585,121 +1176,69 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches)
}
/* copy objects, will re-initialize cached simulation data */
-Object *BKE_object_copy(Object *ob)
+Object *BKE_object_copy(Main *bmain, Object *ob)
{
- return BKE_object_copy_ex(G.main, ob, false);
+ return BKE_object_copy_ex(bmain, ob, false);
}
-static void extern_local_object__modifiersForeachIDLink(
- void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int UNUSED(cd_flag))
+void BKE_object_make_local_ex(Main *bmain, Object *ob, const bool lib_local, const bool clear_proxy)
{
- if (*idpoin) {
- /* intentionally omit ID_OB */
- if (ELEM(GS((*idpoin)->name), ID_IM, ID_TE)) {
- id_lib_extern(*idpoin);
- }
- }
-}
-
-static void extern_local_object(Object *ob)
-{
- ParticleSystem *psys;
-
- id_lib_extern((ID *)ob->data);
- id_lib_extern((ID *)ob->dup_group);
- id_lib_extern((ID *)ob->poselib);
- id_lib_extern((ID *)ob->gpd);
-
- extern_local_matarar(ob->mat, ob->totcol);
-
- for (psys = ob->particlesystem.first; psys; psys = psys->next)
- id_lib_extern((ID *)psys->part);
-
- modifiers_foreachIDLink(ob, extern_local_object__modifiersForeachIDLink, NULL);
-
- ob->preview = NULL;
-}
-
-void BKE_object_make_local(Object *ob)
-{
- Main *bmain = G.main;
- Scene *sce;
- Base *base;
bool is_local = false, is_lib = false;
- /* - only lib users: do nothing
+ /* - only lib users: do nothing (unless force_local is set)
* - only local users: set flag
* - mixed: make copy
+ * In case we make a whole lib's content local, we always want to localize, and we skip remapping (done later).
*/
- if (ob->id.lib == NULL) return;
-
- ob->proxy = ob->proxy_from = ob->proxy_group = NULL;
-
- if (ob->id.us == 1) {
- id_clear_lib_data(bmain, &ob->id);
- extern_local_object(ob);
+ if (!ID_IS_LINKED_DATABLOCK(ob)) {
+ return;
}
- else {
- for (sce = bmain->scene.first; sce && ELEM(0, is_lib, is_local); sce = sce->id.next) {
- if (BKE_scene_base_find(sce, ob)) {
- if (sce->id.lib) is_lib = true;
- else is_local = true;
- }
- }
- if (is_local && is_lib == false) {
+ BKE_library_ID_test_usages(bmain, ob, &is_local, &is_lib);
+
+ if (lib_local || is_local) {
+ if (!is_lib) {
id_clear_lib_data(bmain, &ob->id);
- extern_local_object(ob);
+ BKE_id_expand_local(&ob->id);
+ if (clear_proxy) {
+ if (ob->proxy_from != NULL) {
+ ob->proxy_from->proxy = NULL;
+ ob->proxy_from->proxy_group = NULL;
+ }
+ ob->proxy = ob->proxy_from = ob->proxy_group = NULL;
+ }
}
- else if (is_local && is_lib) {
- Object *ob_new = BKE_object_copy(ob);
+ else {
+ Object *ob_new = BKE_object_copy(bmain, ob);
ob_new->id.us = 0;
-
- /* Remap paths of new ID using old library as base. */
- BKE_id_lib_local_paths(bmain, ob->id.lib, &ob_new->id);
-
- sce = bmain->scene.first;
- while (sce) {
- if (sce->id.lib == NULL) {
- base = sce->base.first;
- while (base) {
- if (base->object == ob) {
- base->object = ob_new;
- id_us_plus(&ob_new->id);
- id_us_min(&ob->id);
- }
- base = base->next;
- }
- }
- sce = sce->id.next;
+ ob_new->proxy = ob_new->proxy_from = ob_new->proxy_group = NULL;
+
+ if (!lib_local) {
+ BKE_libblock_remap(bmain, ob, ob_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}
}
}
}
-/*
- * Returns true if the Object is a from an external blend file (libdata)
- */
+void BKE_object_make_local(Main *bmain, Object *ob, const bool lib_local)
+{
+ BKE_object_make_local_ex(bmain, ob, lib_local, true);
+}
+
+/* Returns true if the Object is from an external blend file (libdata) */
bool BKE_object_is_libdata(Object *ob)
{
- if (!ob) return false;
- if (ob->proxy) return false;
- if (ob->id.lib) return true;
- return false;
+ return (ob && ID_IS_LINKED_DATABLOCK(ob));
}
-/* Returns true if the Object data is a from an external blend file (libdata) */
+/* Returns true if the Object data is from an external blend file (libdata) */
bool BKE_object_obdata_is_libdata(Object *ob)
{
- if (!ob) return false;
- if (ob->proxy && (ob->data == NULL || ((ID *)ob->data)->lib == NULL)) return false;
- if (ob->id.lib) return true;
- if (ob->data == NULL) return false;
- if (((ID *)ob->data)->lib) return true;
-
- return false;
+ /* Linked objects with local obdata are forbidden! */
+ BLI_assert(!ob || !ob->data || (ID_IS_LINKED_DATABLOCK(ob) ? ID_IS_LINKED_DATABLOCK(ob->data) : true));
+ return (ob && ob->data && ID_IS_LINKED_DATABLOCK(ob->data));
}
/* *************** PROXY **************** */
@@ -1746,7 +1285,7 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target)
/* only on local objects because this causes indirect links
* 'a -> b -> c', blend to point directly to a.blend
* when a.blend has a proxy thats linked into c.blend */
- if (ob->id.lib == NULL)
+ if (!ID_IS_LINKED_DATABLOCK(ob))
id_lib_extern((ID *)dtar->id);
}
}
@@ -1764,7 +1303,7 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target)
void BKE_object_make_proxy(Object *ob, Object *target, Object *gob)
{
/* paranoia checks */
- if (ob->id.lib || target->id.lib == NULL) {
+ if (ID_IS_LINKED_DATABLOCK(ob) || !ID_IS_LINKED_DATABLOCK(target)) {
printf("cannot make proxy\n");
return;
}
@@ -3141,7 +2680,7 @@ void BKE_object_handle_update_ex(EvaluationContext *eval_ctx,
printf("recalcob %s\n", ob->id.name + 2);
/* handle proxy copy for target */
- if (ob->id.lib && ob->proxy_from) {
+ if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from) {
// printf("ob proxy copy, lib ob %s proxy %s\n", ob->id.name, ob->proxy_from->id.name);
if (ob->proxy_from->proxy_group) { /* transform proxy into group space */
Object *obg = ob->proxy_from->proxy_group;
@@ -3685,6 +3224,14 @@ static bool constructive_modifier_is_deform_modified(ModifierData *md)
ScrewModifierData *smd = (ScrewModifierData *)md;
return smd->ob_axis != NULL && object_moves_in_time(smd->ob_axis);
}
+ else if (md->type == eModifierType_MeshSequenceCache) {
+ /* NOTE: Not ideal because it's unknown whether topology changes or not.
+ * This will be detected later, so by assuming it's only deformation
+ * going on here we allow to bake deform-only mesh to Alembic and have
+ * proper motion blur after that.
+ */
+ return true;
+ }
return false;
}
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index 63c37fddc60..14cc5ec0849 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -80,7 +80,6 @@ typedef struct DupliContext {
int persistent_id[MAX_DUPLI_RECUR];
int level;
- int index;
const struct DupliGenerator *gen;
@@ -222,31 +221,39 @@ static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChild
if (ctx->group) {
unsigned int lay = ctx->group->layer;
+ int groupid = 0;
GroupObject *go;
- for (go = ctx->group->gobject.first; go; go = go->next) {
+ for (go = ctx->group->gobject.first; go; go = go->next, groupid++) {
Object *ob = go->ob;
if ((ob->lay & lay) && ob != obedit && is_child(ob, parent)) {
+ DupliContext pctx;
+ copy_dupli_context(&pctx, ctx, ctx->object, NULL, groupid, false);
+
/* mballs have a different dupli handling */
if (ob->type != OB_MBALL)
ob->flag |= OB_DONE; /* doesnt render */
- make_child_duplis_cb(ctx, userdata, ob);
+ make_child_duplis_cb(&pctx, userdata, ob);
}
}
}
else {
unsigned int lay = ctx->scene->lay;
+ int baseid = 0;
Base *base;
- for (base = ctx->scene->base.first; base; base = base->next) {
+ for (base = ctx->scene->base.first; base; base = base->next, baseid++) {
Object *ob = base->object;
if ((base->lay & lay) && ob != obedit && is_child(ob, parent)) {
+ DupliContext pctx;
+ copy_dupli_context(&pctx, ctx, ctx->object, NULL, baseid, false);
+
/* mballs have a different dupli handling */
if (ob->type != OB_MBALL)
ob->flag |= OB_DONE; /* doesnt render */
- make_child_duplis_cb(ctx, userdata, ob);
+ make_child_duplis_cb(&pctx, userdata, ob);
}
}
}
@@ -851,7 +858,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
if (part == NULL)
return;
- if (!psys_check_enabled(par, psys))
+ if (!psys_check_enabled(par, psys, (ctx->eval_ctx->mode == DAG_EVAL_RENDER)))
return;
if (!for_render)
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index 03348adeabc..5cb704e4737 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -203,7 +203,7 @@ void BKE_object_handle_data_update(EvaluationContext *eval_ctx,
break;
}
case OB_ARMATURE:
- if (ob->id.lib && ob->proxy_from) {
+ if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from) {
if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) {
printf("Proxy copy error, lib Object: %s proxy Object: %s\n",
ob->id.name + 2, ob->proxy_from->id.name + 2);
@@ -269,7 +269,7 @@ void BKE_object_handle_data_update(EvaluationContext *eval_ctx,
psys_changed_type(ob, psys);
}
- if (psys_check_enabled(ob, psys)) {
+ if (psys_check_enabled(ob, psys, eval_ctx->mode == DAG_EVAL_RENDER)) {
/* check use of dupli objects here */
if (psys->part && (psys->part->draw_as == PART_DRAW_REND || eval_ctx->mode == DAG_EVAL_RENDER) &&
((psys->part->ren_as == PART_DRAW_OB && psys->part->dup_ob) ||
@@ -278,7 +278,7 @@ void BKE_object_handle_data_update(EvaluationContext *eval_ctx,
ob->transflag |= OB_DUPLIPARTS;
}
- particle_system_update(scene, ob, psys);
+ particle_system_update(scene, ob, psys, (eval_ctx->mode == DAG_EVAL_RENDER));
psys = psys->next;
}
else if (psys->flag & PSYS_DELETE) {
@@ -315,7 +315,7 @@ void BKE_object_eval_uber_transform(EvaluationContext *UNUSED(eval_ctx),
// XXX: it's almost redundant now...
/* Handle proxy copy for target, */
- if (ob->id.lib && ob->proxy_from) {
+ if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from) {
if (ob->proxy_from->proxy_group) {
/* Transform proxy into group space. */
Object *obg = ob->proxy_from->proxy_group;
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index c5179e5a428..621ac9c2480 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -531,7 +531,7 @@ static void ocean_compute_htilda(void *userdata, const int i)
}
}
-static void ocean_compute_displacement_y(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
+static void ocean_compute_displacement_y(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
{
OceanSimulateData *osd = BLI_task_pool_userdata(pool);
const Ocean *o = osd->o;
@@ -539,7 +539,7 @@ static void ocean_compute_displacement_y(TaskPool *pool, void *UNUSED(taskdata),
fftw_execute(o->_disp_y_plan);
}
-static void ocean_compute_displacement_x(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
+static void ocean_compute_displacement_x(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
{
OceanSimulateData *osd = BLI_task_pool_userdata(pool);
const Ocean *o = osd->o;
@@ -567,7 +567,7 @@ static void ocean_compute_displacement_x(TaskPool *pool, void *UNUSED(taskdata),
fftw_execute(o->_disp_x_plan);
}
-static void ocean_compute_displacement_z(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
+static void ocean_compute_displacement_z(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
{
OceanSimulateData *osd = BLI_task_pool_userdata(pool);
const Ocean *o = osd->o;
@@ -595,7 +595,7 @@ static void ocean_compute_displacement_z(TaskPool *pool, void *UNUSED(taskdata),
fftw_execute(o->_disp_z_plan);
}
-static void ocean_compute_jacobian_jxx(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
+static void ocean_compute_jacobian_jxx(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
{
OceanSimulateData *osd = BLI_task_pool_userdata(pool);
const Ocean *o = osd->o;
@@ -627,7 +627,7 @@ static void ocean_compute_jacobian_jxx(TaskPool *pool, void *UNUSED(taskdata), i
}
}
-static void ocean_compute_jacobian_jzz(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
+static void ocean_compute_jacobian_jzz(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
{
OceanSimulateData *osd = BLI_task_pool_userdata(pool);
const Ocean *o = osd->o;
@@ -659,7 +659,7 @@ static void ocean_compute_jacobian_jzz(TaskPool *pool, void *UNUSED(taskdata), i
}
}
-static void ocean_compute_jacobian_jxz(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
+static void ocean_compute_jacobian_jxz(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
{
OceanSimulateData *osd = BLI_task_pool_userdata(pool);
const Ocean *o = osd->o;
@@ -685,7 +685,7 @@ static void ocean_compute_jacobian_jxz(TaskPool *pool, void *UNUSED(taskdata), i
fftw_execute(o->_Jxz_plan);
}
-static void ocean_compute_normal_x(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
+static void ocean_compute_normal_x(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
{
OceanSimulateData *osd = BLI_task_pool_userdata(pool);
const Ocean *o = osd->o;
@@ -704,7 +704,7 @@ static void ocean_compute_normal_x(TaskPool *pool, void *UNUSED(taskdata), int U
fftw_execute(o->_N_x_plan);
}
-static void ocean_compute_normal_z(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
+static void ocean_compute_normal_z(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
{
OceanSimulateData *osd = BLI_task_pool_userdata(pool);
const Ocean *o = osd->o;
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
index 1c318dfd115..489fc2f3710 100644
--- a/source/blender/blenkernel/intern/packedFile.c
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -232,7 +232,7 @@ void packAll(Main *bmain, ReportList *reports, bool verbose)
int tot = 0;
for (ima = bmain->image.first; ima; ima = ima->id.next) {
- if (BKE_image_has_packedfile(ima) == false && ima->id.lib == NULL) {
+ if (BKE_image_has_packedfile(ima) == false && !ID_IS_LINKED_DATABLOCK(ima)) {
if (ima->source == IMA_SRC_FILE) {
BKE_image_packfiles(reports, ima, ID_BLEND_PATH(bmain, &ima->id));
tot ++;
@@ -245,14 +245,14 @@ void packAll(Main *bmain, ReportList *reports, bool verbose)
}
for (vfont = bmain->vfont.first; vfont; vfont = vfont->id.next) {
- if (vfont->packedfile == NULL && vfont->id.lib == NULL && BKE_vfont_is_builtin(vfont) == false) {
+ if (vfont->packedfile == NULL && !ID_IS_LINKED_DATABLOCK(vfont) && BKE_vfont_is_builtin(vfont) == false) {
vfont->packedfile = newPackedFile(reports, vfont->name, bmain->name);
tot ++;
}
}
for (sound = bmain->sound.first; sound; sound = sound->id.next) {
- if (sound->packedfile == NULL && sound->id.lib == NULL) {
+ if (sound->packedfile == NULL && !ID_IS_LINKED_DATABLOCK(sound)) {
sound->packedfile = newPackedFile(reports, sound->name, bmain->name);
tot++;
}
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 3a2663c5d48..6b954f060d3 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -298,13 +298,11 @@ void BKE_paint_brush_set(Paint *p, Brush *br)
}
}
+/** Free (or release) any data used by this paint curve (does not free the pcurve itself). */
void BKE_paint_curve_free(PaintCurve *pc)
{
- if (pc->points) {
- MEM_freeN(pc->points);
- pc->points = NULL;
- pc->tot_points = 0;
- }
+ MEM_SAFE_FREE(pc->points);
+ pc->tot_points = 0;
}
PaintCurve *BKE_paint_curve_add(Main *bmain, const char *name)
@@ -316,6 +314,26 @@ PaintCurve *BKE_paint_curve_add(Main *bmain, const char *name)
return pc;
}
+PaintCurve *BKE_paint_curve_copy(Main *bmain, PaintCurve *pc)
+{
+ PaintCurve *pc_new;
+
+ pc_new = BKE_libblock_copy(bmain, &pc->id);
+
+ if (pc->tot_points != 0) {
+ pc_new->points = MEM_dupallocN(pc->points);
+ }
+
+ BKE_id_copy_ensure_local(bmain, &pc->id, &pc_new->id);
+
+ return pc_new;
+}
+
+void BKE_paint_curve_make_local(Main *bmain, PaintCurve *pc, const bool lib_local)
+{
+ BKE_id_make_local_generic(bmain, &pc->id, true, lib_local);
+}
+
Palette *BKE_paint_palette(Paint *p)
{
return p ? p->palette : NULL;
@@ -378,6 +396,25 @@ Palette *BKE_palette_add(Main *bmain, const char *name)
return palette;
}
+Palette *BKE_palette_copy(Main *bmain, Palette *palette)
+{
+ Palette *palette_new;
+
+ palette_new = BKE_libblock_copy(bmain, &palette->id);
+
+ BLI_duplicatelist(&palette_new->colors, &palette->colors);
+
+ BKE_id_copy_ensure_local(bmain, &palette->id, &palette_new->id);
+
+ return palette_new;
+}
+
+void BKE_palette_make_local(Main *bmain, Palette *palette, const bool lib_local)
+{
+ BKE_id_make_local_generic(bmain, &palette->id, true, lib_local);
+}
+
+/** Free (or release) any data used by this palette (does not free the palette itself). */
void BKE_palette_free(Palette *palette)
{
BLI_freelistN(&palette->colors);
@@ -493,8 +530,6 @@ void BKE_paint_init(Scene *sce, PaintMode mode, const char col[3])
void BKE_paint_free(Paint *paint)
{
- id_us_min((ID *)paint->brush);
- id_us_min((ID *)paint->palette);
curvemapping_free(paint->cavity_curve);
}
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 098700495a0..1ea27558545 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -76,6 +76,8 @@
#include "BKE_material.h"
#include "BKE_key.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_depsgraph.h"
#include "BKE_modifier.h"
#include "BKE_mesh.h"
@@ -141,6 +143,11 @@ int count_particles_mod(ParticleSystem *psys, int totgr, int cur)
#define PATH_CACHE_BUF_SIZE 1024
+static ParticleCacheKey *pcache_key_segment_endpoint_safe(ParticleCacheKey *key)
+{
+ return (key->segments > 0) ? (key + (key->segments - 1)) : key;
+}
+
static ParticleCacheKey **psys_alloc_path_cache_buffers(ListBase *bufs, int tot, int totkeys)
{
LinkData *buf;
@@ -278,7 +285,7 @@ bool psys_in_edit_mode(Scene *scene, ParticleSystem *psys)
{
return (scene->basact && (scene->basact->object->mode & OB_MODE_PARTICLE_EDIT) && psys == psys_get_current((scene->basact)->object) && (psys->edit || psys->pointcache->edit) && !psys->renderdata);
}
-bool psys_check_enabled(Object *ob, ParticleSystem *psys)
+bool psys_check_enabled(Object *ob, ParticleSystem *psys, const bool use_render_params)
{
ParticleSystemModifierData *psmd;
@@ -286,7 +293,7 @@ bool psys_check_enabled(Object *ob, ParticleSystem *psys)
return 0;
psmd = psys_get_modifier(ob, psys);
- if (psys->renderdata || G.is_rendering) {
+ if (psys->renderdata || use_render_params) {
if (!(psmd->modifier.mode & eModifierMode_Render))
return 0;
}
@@ -311,16 +318,24 @@ void psys_check_group_weights(ParticleSettings *part)
int current = 0;
if (part->ren_as == PART_DRAW_GR && part->dup_group && part->dup_group->gobject.first) {
- /* first remove all weights that don't have an object in the group */
+ /* First try to find NULL objects from their index,
+ * and remove all weights that don't have an object in the group. */
dw = part->dupliweights.first;
while (dw) {
- if (!BKE_group_object_exists(part->dup_group, dw->ob)) {
- tdw = dw->next;
- BLI_freelinkN(&part->dupliweights, dw);
- dw = tdw;
+ if (dw->ob == NULL || !BKE_group_object_exists(part->dup_group, dw->ob)) {
+ go = (GroupObject *)BLI_findlink(&part->dup_group->gobject, dw->index);
+ if (go) {
+ dw->ob = go->ob;
+ }
+ else {
+ tdw = dw->next;
+ BLI_freelinkN(&part->dupliweights, dw);
+ dw = tdw;
+ }
}
- else
+ else {
dw = dw->next;
+ }
}
/* then add objects in the group to new list */
@@ -371,12 +386,17 @@ static void fluid_free_settings(SPHFluidSettings *fluid)
MEM_freeN(fluid);
}
+/** Free (or release) any data used by this particle settings (does not free the partsett itself). */
void BKE_particlesettings_free(ParticleSettings *part)
{
- MTex *mtex;
int a;
- BKE_animdata_free(&part->id);
+
+ BKE_animdata_free((ID *)part, false);
+ for (a = 0; a < MAX_MTEX; a++) {
+ MEM_SAFE_FREE(part->mtex[a]);
+ }
+
if (part->clumpcurve)
curvemapping_free(part->clumpcurve);
if (part->roughcurve)
@@ -385,21 +405,12 @@ void BKE_particlesettings_free(ParticleSettings *part)
free_partdeflect(part->pd);
free_partdeflect(part->pd2);
- if (part->effector_weights)
- MEM_freeN(part->effector_weights);
+ MEM_SAFE_FREE(part->effector_weights);
BLI_freelistN(&part->dupliweights);
boid_free_settings(part->boids);
fluid_free_settings(part->fluid);
-
- for (a = 0; a < MAX_MTEX; a++) {
- mtex = part->mtex[a];
- if (mtex && mtex->tex)
- id_us_min(&mtex->tex->id);
- if (mtex)
- MEM_freeN(mtex);
- }
}
void free_hair(Object *UNUSED(ob), ParticleSystem *psys, int dynamics)
@@ -492,7 +503,9 @@ void psys_free_particles(ParticleSystem *psys)
PARTICLE_P;
if (psys->particles) {
- if (psys->part->type == PART_HAIR) {
+ /* Even though psys->part should never be NULL, this can happen as an exception during deletion.
+ * See ID_REMAP_SKIP/FORCE/FLAG_NEVER_NULL_USAGE in BKE_library_remap. */
+ if (psys->part && psys->part->type == PART_HAIR) {
LOOP_PARTICLES {
if (pa->hair)
MEM_freeN(pa->hair);
@@ -568,10 +581,7 @@ void psys_free(Object *ob, ParticleSystem *psys)
if (!nr)
ob->transflag &= ~OB_DUPLIPARTS;
- if (psys->part) {
- id_us_min(&psys->part->id);
- psys->part = NULL;
- }
+ psys->part = NULL;
BKE_ptcache_free_list(&psys->ptcaches);
psys->pointcache = NULL;
@@ -877,6 +887,9 @@ static void get_pointcache_keys_for_time(Object *UNUSED(ob), PointCache *cache,
index2 = BKE_ptcache_mem_index_find(pm, index);
index1 = BKE_ptcache_mem_index_find(pm->prev, index);
+ if (index2 < 0) {
+ return;
+ }
BKE_ptcache_make_particle_key(key2, index2, pm->data, (float)pm->frame);
if (index1 < 0)
@@ -887,6 +900,9 @@ static void get_pointcache_keys_for_time(Object *UNUSED(ob), PointCache *cache,
else if (cache->mem_cache.first) {
pm = cache->mem_cache.first;
index2 = BKE_ptcache_mem_index_find(pm, index);
+ if (index2 < 0) {
+ return;
+ }
BKE_ptcache_make_particle_key(key2, index2, pm->data, (float)pm->frame);
copy_particle_key(key1, key2, 1);
}
@@ -2009,7 +2025,7 @@ float *psys_cache_vgroup(DerivedMesh *dm, ParticleSystem *psys, int vgroup)
}
return vg;
}
-void psys_find_parents(ParticleSimulationData *sim)
+void psys_find_parents(ParticleSimulationData *sim, const bool use_render_params)
{
ParticleSystem *psys = sim->psys;
ParticleSettings *part = sim->psys->part;
@@ -2021,7 +2037,7 @@ void psys_find_parents(ParticleSimulationData *sim)
int from = PART_FROM_FACE;
totparent = (int)(totchild * part->parents * 0.3f);
- if ((sim->psys->renderdata || G.is_rendering) && part->child_nbr && part->ren_child_nbr)
+ if ((sim->psys->renderdata || use_render_params) && part->child_nbr && part->ren_child_nbr)
totparent *= (float)part->child_nbr / (float)part->ren_child_nbr;
/* hard limit, workaround for it being ignored above */
@@ -2052,7 +2068,9 @@ void psys_find_parents(ParticleSimulationData *sim)
BLI_kdtree_free(tree);
}
-static bool psys_thread_context_init_path(ParticleThreadContext *ctx, ParticleSimulationData *sim, Scene *scene, float cfra, int editupdate)
+static bool psys_thread_context_init_path(
+ ParticleThreadContext *ctx, ParticleSimulationData *sim, Scene *scene,
+ float cfra, const bool editupdate, const bool use_render_params)
{
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
@@ -2066,7 +2084,7 @@ static bool psys_thread_context_init_path(ParticleThreadContext *ctx, ParticleSi
if (psys_in_edit_mode(scene, psys)) {
ParticleEditSettings *pset = &scene->toolsettings->particle;
- if ((psys->renderdata == 0 && G.is_rendering == 0) && (psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0)
+ if ((psys->renderdata == 0 && use_render_params == 0) && (psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0)
totchild = 0;
segments = 1 << pset->draw_step;
@@ -2075,14 +2093,14 @@ static bool psys_thread_context_init_path(ParticleThreadContext *ctx, ParticleSi
if (totchild && part->childtype == PART_CHILD_FACES) {
totparent = (int)(totchild * part->parents * 0.3f);
- if ((psys->renderdata || G.is_rendering) && part->child_nbr && part->ren_child_nbr)
+ if ((psys->renderdata || use_render_params) && part->child_nbr && part->ren_child_nbr)
totparent *= (float)part->child_nbr / (float)part->ren_child_nbr;
/* part->parents could still be 0 so we can't test with totparent */
between = 1;
}
- if (psys->renderdata || G.is_rendering)
+ if (psys->renderdata || use_render_params)
segments = 1 << part->ren_step;
else {
totchild = (int)((float)totchild * (float)part->disp / 100.0f);
@@ -2205,20 +2223,22 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
/* modify weights to create parting */
if (p_fac > 0.f) {
+ const ParticleCacheKey *key_0_last = pcache_key_segment_endpoint_safe(key[0]);
for (w = 0; w < 4; w++) {
- if (w && weight[w] > 0.f) {
+ if (w && (weight[w] > 0.f)) {
+ const ParticleCacheKey *key_w_last = pcache_key_segment_endpoint_safe(key[w]);
float d;
if (part->flag & PART_CHILD_LONG_HAIR) {
/* For long hair use tip distance/root distance as parting factor instead of root to tip angle. */
float d1 = len_v3v3(key[0]->co, key[w]->co);
- float d2 = len_v3v3((key[0] + key[0]->segments - 1)->co, (key[w] + key[w]->segments - 1)->co);
+ float d2 = len_v3v3(key_0_last->co, key_w_last->co);
d = d1 > 0.f ? d2 / d1 - 1.f : 10000.f;
}
else {
float v1[3], v2[3];
- sub_v3_v3v3(v1, (key[0] + key[0]->segments - 1)->co, key[0]->co);
- sub_v3_v3v3(v2, (key[w] + key[w]->segments - 1)->co, key[w]->co);
+ sub_v3_v3v3(v1, key_0_last->co, key[0]->co);
+ sub_v3_v3v3(v2, key_w_last->co, key[w]->co);
normalize_v3(v1);
normalize_v3(v2);
@@ -2417,7 +2437,9 @@ static void exec_child_path_cache(TaskPool * __restrict UNUSED(pool), void *task
}
}
-void psys_cache_child_paths(ParticleSimulationData *sim, float cfra, int editupdate)
+void psys_cache_child_paths(
+ ParticleSimulationData *sim, float cfra,
+ const bool editupdate, const bool use_render_params)
{
TaskScheduler *task_scheduler;
TaskPool *task_pool;
@@ -2430,7 +2452,7 @@ void psys_cache_child_paths(ParticleSimulationData *sim, float cfra, int editupd
return;
/* create a task pool for child path tasks */
- if (!psys_thread_context_init_path(&ctx, sim, sim->scene, cfra, editupdate))
+ if (!psys_thread_context_init_path(&ctx, sim, sim->scene, cfra, editupdate, use_render_params))
return;
task_scheduler = BLI_task_scheduler_get();
@@ -2522,7 +2544,7 @@ static void cache_key_incremental_rotation(ParticleCacheKey *key0, ParticleCache
* - Useful for making use of opengl vertex arrays for super fast strand drawing.
* - Makes child strands possible and creates them too into the cache.
* - Cached path data is also used to determine cut position for the editmode tool. */
-void psys_cache_paths(ParticleSimulationData *sim, float cfra)
+void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_render_params)
{
PARTICLE_PSMD;
ParticleEditSettings *pset = &sim->scene->toolsettings->particle;
@@ -2546,7 +2568,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
float prev_tangent[3] = {0.0f, 0.0f, 0.0f}, hairmat[4][4];
float rotmat[3][3];
int k;
- int segments = (int)pow(2.0, (double)((psys->renderdata || G.is_rendering) ? part->ren_step : part->draw_step));
+ int segments = (int)pow(2.0, (double)((psys->renderdata || use_render_params) ? part->ren_step : part->draw_step));
int totpart = psys->totpart;
float length, vec[3];
float *vg_effector = NULL;
@@ -2725,7 +2747,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
if (vg_length)
MEM_freeN(vg_length);
}
-void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cfra)
+void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cfra, const bool use_render_params)
{
ParticleCacheKey *ca, **cache = edit->pathcache;
ParticleEditSettings *pset = &scene->toolsettings->particle;
@@ -2921,7 +2943,7 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf
sim.psys = psys;
sim.psmd = psys_get_modifier(ob, psys);
- psys_cache_child_paths(&sim, cfra, 1);
+ psys_cache_child_paths(&sim, cfra, true, use_render_params);
}
/* clear recalc flag if set here */
@@ -3166,6 +3188,9 @@ void object_remove_particle_system(Scene *UNUSED(scene), Object *ob)
/* clear particle system */
BLI_remlink(&ob->particlesystem, psys);
+ if (psys->part) {
+ id_us_min(&psys->part->id);
+ }
psys_free(ob, psys);
if (ob->particlesystem.first)
@@ -3300,12 +3325,13 @@ void BKE_particlesettings_rough_curve_init(ParticleSettings *part)
part->roughcurve = cumap;
}
-ParticleSettings *BKE_particlesettings_copy(ParticleSettings *part)
+ParticleSettings *BKE_particlesettings_copy(Main *bmain, ParticleSettings *part)
{
ParticleSettings *partn;
int a;
- partn = BKE_libblock_copy(&part->id);
+ partn = BKE_libblock_copy(bmain, &part->id);
+
partn->pd = MEM_dupallocN(part->pd);
partn->pd2 = MEM_dupallocN(part->pd2);
partn->effector_weights = MEM_dupallocN(part->effector_weights);
@@ -3328,75 +3354,14 @@ ParticleSettings *BKE_particlesettings_copy(ParticleSettings *part)
BLI_duplicatelist(&partn->dupliweights, &part->dupliweights);
- if (part->id.lib) {
- BKE_id_lib_local_paths(G.main, part->id.lib, &partn->id);
- }
+ BKE_id_copy_ensure_local(bmain, &part->id, &partn->id);
return partn;
}
-static void expand_local_particlesettings(ParticleSettings *part)
+void BKE_particlesettings_make_local(Main *bmain, ParticleSettings *part, const bool lib_local)
{
- int i;
- id_lib_extern((ID *)part->dup_group);
-
- for (i = 0; i < MAX_MTEX; i++) {
- if (part->mtex[i]) id_lib_extern((ID *)part->mtex[i]->tex);
- }
-}
-
-void BKE_particlesettings_make_local(ParticleSettings *part)
-{
- Main *bmain = G.main;
- Object *ob;
- bool is_local = false, is_lib = false;
-
- /* - only lib users: do nothing
- * - only local users: set flag
- * - mixed: make copy
- */
-
- if (part->id.lib == 0) return;
- if (part->id.us == 1) {
- id_clear_lib_data(bmain, &part->id);
- expand_local_particlesettings(part);
- return;
- }
-
- /* test objects */
- for (ob = bmain->object.first; ob && ELEM(false, is_lib, is_local); ob = ob->id.next) {
- ParticleSystem *psys = ob->particlesystem.first;
- for (; psys; psys = psys->next) {
- if (psys->part == part) {
- if (ob->id.lib) is_lib = true;
- else is_local = true;
- }
- }
- }
-
- if (is_local && is_lib == false) {
- id_clear_lib_data(bmain, &part->id);
- expand_local_particlesettings(part);
- }
- else if (is_local && is_lib) {
- ParticleSettings *part_new = BKE_particlesettings_copy(part);
- part_new->id.us = 0;
-
- /* Remap paths of new ID using old library as base. */
- BKE_id_lib_local_paths(bmain, part->id.lib, &part_new->id);
-
- /* do objects */
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- ParticleSystem *psys;
- for (psys = ob->particlesystem.first; psys; psys = psys->next) {
- if (psys->part == part && ob->id.lib == 0) {
- psys->part = part_new;
- id_us_plus(&part_new->id);
- id_us_min(&part->id);
- }
- }
- }
- }
+ BKE_id_make_local_generic(bmain, &part->id, true, lib_local);
}
/************************************************/
@@ -4104,13 +4069,16 @@ void psys_get_dupli_texture(ParticleSystem *psys, ParticleSettings *part,
uv[0] = uv[1] = 0.f;
+ /* Grid distribution doesn't support UV or emit from vertex mode */
+ bool is_grid = (part->distr == PART_DISTR_GRID && part->from != PART_FROM_VERT);
+
if (cpa) {
if ((part->childtype == PART_CHILD_FACES) && (psmd->dm_final != NULL)) {
CustomData *mtf_data = psmd->dm_final->getTessFaceDataLayout(psmd->dm_final);
const int uv_idx = CustomData_get_render_layer(mtf_data, CD_MTFACE);
mtface = CustomData_get_layer_n(mtf_data, CD_MTFACE, uv_idx);
- if (mtface) {
+ if (mtface && !is_grid) {
mface = psmd->dm_final->getTessFaceData(psmd->dm_final, cpa->num, CD_MFACE);
mtface += cpa->num;
psys_interpolate_uvs(mtface, mface->v4, cpa->fuv, uv);
@@ -4124,7 +4092,7 @@ void psys_get_dupli_texture(ParticleSystem *psys, ParticleSettings *part,
}
}
- if ((part->from == PART_FROM_FACE) && (psmd->dm_final != NULL)) {
+ if ((part->from == PART_FROM_FACE) && (psmd->dm_final != NULL) && !is_grid) {
CustomData *mtf_data = psmd->dm_final->getTessFaceDataLayout(psmd->dm_final);
const int uv_idx = CustomData_get_render_layer(mtf_data, CD_MTFACE);
mtface = CustomData_get_layer_n(mtf_data, CD_MTFACE, uv_idx);
@@ -4225,8 +4193,8 @@ void psys_make_billboard(ParticleBillboardData *bb, float xvec[3], float yvec[3]
/* can happen with bad pointcache or physics calculation
* since this becomes geometry, nan's and inf's crash raytrace code.
* better not allow this. */
- if ((!finite(bb->vec[0])) || (!finite(bb->vec[1])) || (!finite(bb->vec[2])) ||
- (!finite(bb->vel[0])) || (!finite(bb->vel[1])) || (!finite(bb->vel[2])) )
+ if ((!isfinite(bb->vec[0])) || (!isfinite(bb->vec[1])) || (!isfinite(bb->vec[2])) ||
+ (!isfinite(bb->vel[0])) || (!isfinite(bb->vel[1])) || (!isfinite(bb->vel[2])) )
{
zero_v3(bb->vec);
zero_v3(bb->vel);
diff --git a/source/blender/blenkernel/intern/particle_child.c b/source/blender/blenkernel/intern/particle_child.c
index ec5f73f87ce..842de869291 100644
--- a/source/blender/blenkernel/intern/particle_child.c
+++ b/source/blender/blenkernel/intern/particle_child.c
@@ -136,7 +136,7 @@ static void do_kink_spiral_deform(ParticleKey *state, const float dir[3], const
*
* The "density" parameter b is defined by the shape parameter
* and goes up to the Golden Spiral for 1.0
- * http://en.wikipedia.org/wiki/Golden_spiral
+ * https://en.wikipedia.org/wiki/Golden_spiral
*/
const float b = shape * (1.0f + sqrtf(5.0f)) / (float)M_PI * 0.25f;
/* angle of the spiral against the curve (rotated opposite to make a smooth transition) */
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index f6bddfa6f99..44cf5b119c1 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -392,22 +392,25 @@ static int distribute_binary_search(float *sum, int n, float value)
{
int mid, low = 0, high = n - 1;
+ if (high == low)
+ return low;
+
if (sum[low] >= value)
return low;
- if (sum[high] < value)
+ if (sum[high - 1] < value)
return high;
while (low < high) {
mid = (low + high) / 2;
- if ((sum[mid] < value) && (sum[mid + 1] >= value))
+ if ((sum[mid] >= value) && (sum[mid - 1] < value))
return mid;
- if (sum[mid] >= value) {
+ if (sum[mid] > value) {
high = mid - 1;
}
- else if (sum[mid] < value) {
+ else {
low = mid + 1;
}
}
@@ -1008,23 +1011,23 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
int totmapped = 0;
totweight = 0.0f;
for (i = 0; i < totelem; i++) {
- if (element_weight[i] != 0.0f) {
+ if (element_weight[i] > 0.0f) {
totmapped++;
+ totweight += element_weight[i];
}
- totweight += element_weight[i];
}
- if (totweight == 0.0f) {
+ if (totmapped == 0) {
/* We are not allowed to distribute particles anywhere... */
return 0;
}
- inv_totweight = (totweight > 0.f ? 1.f/totweight : 0.f);
+ inv_totweight = 1.0f / totweight;
/* Calculate cumulative weights.
* We remove all null-weighted elements from element_sum, and create a new mapping
* 'activ'_elem_index -> orig_elem_index.
- * This simplifies greatly the filtering of zero-weighted items - and can be much mor efficient
+ * This simplifies greatly the filtering of zero-weighted items - and can be much more efficient
* especially in random case (reducing a lot the size of binary-searched array)...
*/
float *element_sum = MEM_mallocN(sizeof(*element_sum) * totmapped, __func__);
@@ -1036,24 +1039,27 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
element_map[i_mapped] = i;
i_mapped++;
for (i++; i < totelem; i++) {
- if (element_weight[i] != 0.0f) {
+ if (element_weight[i] > 0.0f) {
element_sum[i_mapped] = element_sum[i_mapped - 1] + element_weight[i] * inv_totweight;
- element_map[i_mapped] = i;
- i_mapped++;
+ /* Skip elements which weight is so small that it does not affect the sum. */
+ if (element_sum[i_mapped] > element_sum[i_mapped - 1]) {
+ element_map[i_mapped] = i;
+ i_mapped++;
+ }
}
}
+ totmapped = i_mapped;
- BLI_assert(i_mapped == totmapped);
-
/* Finally assign elements to particles */
if ((part->flag & PART_TRAND) || (part->simplify_flag & PART_SIMPLIFY_ENABLE)) {
- float pos;
-
for (p = 0; p < totpart; p++) {
- /* In theory element_sum[totelem - 1] should be 1.0,
+ /* In theory element_sum[totmapped - 1] should be 1.0,
* but due to float errors this is not necessarily always true, so scale pos accordingly. */
- pos = BLI_frand() * element_sum[totmapped - 1];
- particle_element[p] = element_map[distribute_binary_search(element_sum, totmapped, pos)];
+ const float pos = BLI_frand() * element_sum[totmapped - 1];
+ const int eidx = distribute_binary_search(element_sum, totmapped, pos);
+ particle_element[p] = element_map[eidx];
+ BLI_assert(pos <= element_sum[eidx]);
+ BLI_assert(eidx ? (pos > element_sum[eidx - 1]) : (pos >= 0.0f));
jitter_offset[particle_element[p]] = pos;
}
}
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index 1ca68f714c8..ee435051151 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -230,7 +230,7 @@ static void realloc_particles(ParticleSimulationData *sim, int new_totpart)
newboids= MEM_callocN(totpart*sizeof(BoidParticle), "boid particles");
if (newboids == NULL) {
- /* allocation error! */
+ /* allocation error! */
if (newpars)
MEM_freeN(newpars);
return;
@@ -2180,10 +2180,9 @@ static void basic_rotate(ParticleSettings *part, ParticleData *pa, float dfra, f
* The algorithm is roughly:
* 1. Use a BVH tree to search for faces that a particle may collide with.
* 2. Use Newton's method to find the exact time at which the collision occurs.
- * http://en.wikipedia.org/wiki/Newton's_method
+ * https://en.wikipedia.org/wiki/Newton's_method
*
************************************************/
-#define COLLISION_MAX_COLLISIONS 10
#define COLLISION_MIN_RADIUS 0.001f
#define COLLISION_MIN_DISTANCE 0.0001f
#define COLLISION_ZERO 0.00001f
@@ -2570,10 +2569,6 @@ void BKE_psys_collision_neartest_cb(void *userdata, int index, const BVHTreeRay
pce.inside = 0;
pce.index = index;
- /* don't collide with same face again */
- if (col->hit == col->current && col->pce.index == index && col->pce.tot == 3)
- return;
-
collision = collision_sphere_to_tri(col, ray->radius, &pce, &t);
if (col->pce.inside == 0) {
collision += collision_sphere_to_edges(col, ray->radius, &pce, &t);
@@ -2609,8 +2604,17 @@ static int collision_detect(ParticleData *pa, ParticleCollision *col, BVHTreeRay
hit->dist = col->original_ray_length = 0.000001f;
for (coll = colliders->first; coll; coll=coll->next) {
- /* for boids: don't check with current ground object */
- if (coll->ob == col->skip)
+ /* for boids: don't check with current ground object; also skip if permeated */
+ bool skip = false;
+
+ for (int i = 0; i < col->skip_count; i++) {
+ if (coll->ob == col->skip[i]) {
+ skip = true;
+ break;
+ }
+ }
+
+ if (skip)
continue;
/* particles should not collide with emitter at birth */
@@ -2746,7 +2750,7 @@ static int collision_response(ParticleData *pa, ParticleCollision *col, BVHTreeR
if (through==0 && ((vc_dot>0.0f && v0_dot>0.0f && vc_dot>v0_dot) || (vc_dot<0.0f && v0_dot<0.0f && vc_dot<v0_dot)))
mul_v3_v3fl(v0_nor, pce->nor, vc_dot);
else if (v0_dot > 0.f)
- mul_v3_v3fl(v0_nor, pce->nor, vc_dot + (through ? -1.0f : 1.0f) * v0_dot);
+ mul_v3_v3fl(v0_nor, pce->nor, vc_dot + v0_dot);
else
mul_v3_v3fl(v0_nor, pce->nor, vc_dot + (through ? 1.0f : -1.0f) * v0_dot);
@@ -2801,8 +2805,10 @@ static int collision_response(ParticleData *pa, ParticleCollision *col, BVHTreeR
col->f = f;
}
- col->prev = col->hit;
- col->prev_index = hit->index;
+ /* if permeability random roll succeeded, disable collider for this sim step */
+ if (through) {
+ col->skip[col->skip_count++] = col->hit;
+ }
return 1;
}
@@ -2863,16 +2869,16 @@ static void collision_check(ParticleSimulationData *sim, int p, float dfra, floa
if (part->phystype == PART_PHYS_BOIDS && part->boids->options & BOID_ALLOW_LAND) {
col.boid = 1;
col.boid_z = pa->state.co[2];
- col.skip = pa->boid->ground;
+ col.skip[col.skip_count++] = pa->boid->ground;
}
/* 10 iterations to catch multiple collisions */
- while (collision_count < COLLISION_MAX_COLLISIONS) {
+ while (collision_count < PARTICLE_COLLISION_MAX_COLLISIONS) {
if (collision_detect(pa, &col, &hit, sim->colliders)) {
collision_count++;
- if (collision_count == COLLISION_MAX_COLLISIONS)
+ if (collision_count == PARTICLE_COLLISION_MAX_COLLISIONS)
collision_fail(pa, &col);
else if (collision_response(pa, &col, &hit, part->flag & PART_DIE_ON_COL, part->flag & PART_ROT_DYN)==0)
return;
@@ -2885,7 +2891,7 @@ static void collision_check(ParticleSimulationData *sim, int p, float dfra, floa
/* Hair */
/************************************************/
/* check if path cache or children need updating and do it if needed */
-static void psys_update_path_cache(ParticleSimulationData *sim, float cfra)
+static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, const bool use_render_params)
{
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
@@ -2909,7 +2915,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra)
distribute_particles(sim, PART_FROM_CHILD);
if (part->childtype==PART_CHILD_FACES && part->parents != 0.0f)
- psys_find_parents(sim);
+ psys_find_parents(sim, use_render_params);
}
}
else
@@ -2947,7 +2953,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra)
}
if (!skip) {
- psys_cache_paths(sim, cfra);
+ psys_cache_paths(sim, cfra, use_render_params);
/* for render, child particle paths are computed on the fly */
if (part->childtype) {
@@ -2957,7 +2963,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra)
skip = 1;
if (!skip)
- psys_cache_child_paths(sim, cfra, 0);
+ psys_cache_child_paths(sim, cfra, 0, use_render_params);
}
}
else if (psys->pathcache)
@@ -3193,7 +3199,7 @@ static void do_hair_dynamics(ParticleSimulationData *sim)
/* restore cloth effector weights */
psys->clmd->sim_parms->effector_weights = clmd_effweights;
}
-static void hair_step(ParticleSimulationData *sim, float cfra)
+static void hair_step(ParticleSimulationData *sim, float cfra, const bool use_render_params)
{
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
@@ -3225,7 +3231,7 @@ static void hair_step(ParticleSimulationData *sim, float cfra)
/* following lines were removed r29079 but cause bug [#22811], see report for details */
psys_update_effectors(sim);
- psys_update_path_cache(sim, cfra);
+ psys_update_path_cache(sim, cfra, use_render_params);
psys->flag |= PSYS_HAIR_UPDATED;
}
@@ -3311,7 +3317,7 @@ static float get_base_time_step(ParticleSettings *part)
return 1.0f / (float) (part->subframes + 1);
}
/* Update time step size to suit current conditions. */
-static float update_timestep(ParticleSystem *psys, ParticleSimulationData *sim, float t_frac)
+static void update_timestep(ParticleSystem *psys, ParticleSimulationData *sim)
{
float dt_target;
if (sim->courant_num == 0.0f)
@@ -3331,7 +3337,10 @@ static float update_timestep(ParticleSystem *psys, ParticleSimulationData *sim,
psys->dt_frac = interpf(dt_target, psys->dt_frac, TIMESTEP_EXPANSION_FACTOR);
else
psys->dt_frac = dt_target;
+}
+static float sync_timestep(ParticleSystem *psys, float t_frac)
+{
/* Sync with frame end if it's close. */
if (t_frac == 1.0f)
return psys->dt_frac;
@@ -3493,7 +3502,7 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
psys_update_effectors(sim);
if (part->type != PART_HAIR)
- sim->colliders = get_collider_cache(sim->scene, sim->ob, NULL);
+ sim->colliders = get_collider_cache(sim->scene, sim->ob, part->collision_group);
/* initialize physics type specific stuff */
switch (part->phystype) {
@@ -3732,7 +3741,7 @@ static void cached_step(ParticleSimulationData *sim, float cfra)
}
}
-static void particles_fluid_step(ParticleSimulationData *sim, int UNUSED(cfra))
+static void particles_fluid_step(ParticleSimulationData *sim, int UNUSED(cfra), const bool use_render_params)
{
ParticleSystem *psys = sim->psys;
if (psys->particles) {
@@ -3775,7 +3784,7 @@ static void particles_fluid_step(ParticleSimulationData *sim, int UNUSED(cfra))
}
gzread(gzf, &totpart, sizeof(totpart));
- totpart = (G.is_rendering)?totpart:(part->disp*totpart) / 100;
+ totpart = (use_render_params) ? totpart:(part->disp*totpart) / 100;
part->totpart= totpart;
part->sta=part->end = 1.0f;
@@ -3836,6 +3845,8 @@ static void particles_fluid_step(ParticleSimulationData *sim, int UNUSED(cfra))
} // fluid sim particles done
}
+#else
+ UNUSED_VARS(use_render_params);
#endif // WITH_MOD_FLUID
}
@@ -3857,7 +3868,7 @@ static int emit_particles(ParticleSimulationData *sim, PTCacheID *pid, float UNU
* 2. Check cache (if used) and return if frame is cached
* 3. Do dynamics
* 4. Save to cache */
-static void system_step(ParticleSimulationData *sim, float cfra)
+static void system_step(ParticleSimulationData *sim, float cfra, const bool use_render_params)
{
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
@@ -3914,12 +3925,12 @@ static void system_step(ParticleSimulationData *sim, float cfra)
/* 2. try to read from the cache */
if (pid) {
- int cache_result = BKE_ptcache_read(pid, cache_cfra);
+ int cache_result = BKE_ptcache_read(pid, cache_cfra, true);
if (ELEM(cache_result, PTCACHE_READ_EXACT, PTCACHE_READ_INTERPOLATED)) {
cached_step(sim, cfra);
update_children(sim);
- psys_update_path_cache(sim, cfra);
+ psys_update_path_cache(sim, cfra, use_render_params);
BKE_ptcache_validate(cache, (int)cache_cfra);
@@ -3989,7 +4000,9 @@ static void system_step(ParticleSimulationData *sim, float cfra)
printf("%f,%f,%f,%f\n", cfra+dframe+t_frac - 1.f, t_frac, dt_frac, sim->courant_num);
#endif
if (part->time_flag & PART_TIME_AUTOSF)
- dt_frac = update_timestep(psys, sim, t_frac);
+ update_timestep(psys, sim);
+ /* Even without AUTOSF dt_frac may not add up to 1.0 due to float precision. */
+ dt_frac = sync_timestep(psys, t_frac);
}
}
}
@@ -4137,7 +4150,7 @@ static int hair_needs_recalc(ParticleSystem *psys)
/* main particle update call, checks that things are ok on the large scale and
* then advances in to actual particle calculations depending on particle type */
-void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
+void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys, const bool use_render_params)
{
ParticleSimulationData sim= {0};
ParticleSettings *part = psys->part;
@@ -4146,7 +4159,7 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
/* drawdata is outdated after ANY change */
if (psys->pdd) psys->pdd->flag &= ~PARTICLE_DRAW_DATA_UPDATED;
- if (!psys_check_enabled(ob, psys))
+ if (!psys_check_enabled(ob, psys, use_render_params))
return;
cfra= BKE_scene_frame_get(scene);
@@ -4215,7 +4228,7 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
hcfra=100.0f*(float)i/(float)psys->part->hair_step;
if ((part->flag & PART_HAIR_REGROW)==0)
BKE_animsys_evaluate_animdata(scene, &part->id, part->adt, hcfra, ADT_RECALC_ANIM);
- system_step(&sim, hcfra);
+ system_step(&sim, hcfra, use_render_params);
psys->cfra = hcfra;
psys->recalc = 0;
save_hair(&sim, hcfra);
@@ -4228,12 +4241,12 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
psys->flag |= PSYS_HAIR_DONE;
if (psys->flag & PSYS_HAIR_DONE)
- hair_step(&sim, cfra);
+ hair_step(&sim, cfra, use_render_params);
break;
}
case PART_FLUID:
{
- particles_fluid_step(&sim, (int)cfra);
+ particles_fluid_step(&sim, (int)cfra, use_render_params);
break;
}
default:
@@ -4280,14 +4293,14 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
if (part->phystype == PART_PHYS_KEYED) {
psys_count_keyed_targets(&sim);
set_keyed_keys(&sim);
- psys_update_path_cache(&sim,(int)cfra);
+ psys_update_path_cache(&sim, (int)cfra, use_render_params);
}
break;
}
default:
{
/* the main dynamic particle system step */
- system_step(&sim, cfra);
+ system_step(&sim, cfra, use_render_params);
break;
}
}
@@ -4323,7 +4336,9 @@ void BKE_particlesystem_id_loop(ParticleSystem *psys, ParticleSystemIDFunc func,
func(psys, (ID **)&pt->ob, userdata, IDWALK_NOP);
}
- if (psys->part->phystype == PART_PHYS_BOIDS) {
+ /* Even though psys->part should never be NULL, this can happen as an exception during deletion.
+ * See ID_REMAP_SKIP/FORCE/FLAG_NEVER_NULL_USAGE in BKE_library_remap. */
+ if (psys->part && psys->part->phystype == PART_PHYS_BOIDS) {
ParticleData *pa;
int p;
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index d73f087a3fe..ff69f381b06 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -276,16 +276,14 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node)
/* reserve size is rough guess */
GHash *map = BLI_ghash_int_new_ex("build_mesh_leaf_node gh", 2 * totface);
- int (*face_vert_indices)[4] = MEM_callocN(sizeof(int[4]) * totface,
+ int (*face_vert_indices)[3] = MEM_mallocN(sizeof(int[3]) * totface,
"bvh node face vert indices");
- node->face_vert_indices = (const int (*)[4])face_vert_indices;
+ node->face_vert_indices = (const int (*)[3])face_vert_indices;
for (int i = 0; i < totface; ++i) {
const MLoopTri *lt = &bvh->looptri[node->prim_indices[i]];
- const int sides = 3;
-
- for (int j = 0; j < sides; ++j) {
+ for (int j = 0; j < 3; ++j) {
face_vert_indices[i][j] =
map_insert_vert(bvh, map, &node->face_verts,
&node->uniq_verts, bvh->mloop[lt->tri[j]].v);
@@ -637,6 +635,7 @@ void BKE_pbvh_free(PBVH *bvh)
BLI_gset_free(node->bm_other_verts, NULL);
}
}
+ GPU_free_pbvh_buffer_multires(&bvh->grid_common_gpu_buffer);
if (bvh->deformed) {
if (bvh->verts) {
@@ -689,8 +688,7 @@ static void pbvh_stack_push(PBVHIter *iter, PBVHNode *node, bool revisiting)
{
if (UNLIKELY(iter->stacksize == iter->stackspace)) {
iter->stackspace *= 2;
-
- if (iter->stackspace != STACK_FIXED_DEPTH) {
+ if (iter->stackspace != (STACK_FIXED_DEPTH * 2)) {
iter->stack = MEM_reallocN(iter->stack, sizeof(PBVHStack) * iter->stackspace);
}
else {
@@ -1100,7 +1098,7 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
node->totprim,
bvh->grid_hidden,
bvh->gridkey.grid_size,
- &bvh->gridkey);
+ &bvh->gridkey, &bvh->grid_common_gpu_buffer);
break;
case PBVH_FACES:
node->draw_buffers =
@@ -1495,12 +1493,18 @@ typedef struct {
static bool ray_aabb_intersect(PBVHNode *node, void *data_v)
{
RaycastData *rcd = data_v;
- float bb_min[3], bb_max[3];
+ const float *bb_min, *bb_max;
- if (rcd->original)
- BKE_pbvh_node_get_original_BB(node, bb_min, bb_max);
- else
- BKE_pbvh_node_get_BB(node, bb_min, bb_max);
+ if (rcd->original) {
+ /* BKE_pbvh_node_get_original_BB */
+ bb_min = node->orig_vb.bmin;
+ bb_max = node->orig_vb.bmax;
+ }
+ else {
+ /* BKE_pbvh_node_get_BB */
+ bb_min = node->vb.bmin;
+ bb_max = node->vb.bmax;
+ }
return isect_ray_aabb_v3(&rcd->ray, bb_min, bb_max, &node->tmin);
}
@@ -1800,17 +1804,21 @@ static PlaneAABBIsect test_planes_aabb(const float bb_min[3],
bool BKE_pbvh_node_planes_contain_AABB(PBVHNode *node, void *data)
{
- float bb_min[3], bb_max[3];
+ const float *bb_min, *bb_max;
+ /* BKE_pbvh_node_get_BB */
+ bb_min = node->vb.bmin;
+ bb_max = node->vb.bmax;
- BKE_pbvh_node_get_BB(node, bb_min, bb_max);
return test_planes_aabb(bb_min, bb_max, data) != ISECT_OUTSIDE;
}
bool BKE_pbvh_node_planes_exclude_AABB(PBVHNode *node, void *data)
{
- float bb_min[3], bb_max[3];
+ const float *bb_min, *bb_max;
+ /* BKE_pbvh_node_get_BB */
+ bb_min = node->vb.bmin;
+ bb_max = node->vb.bmax;
- BKE_pbvh_node_get_BB(node, bb_min, bb_max);
return test_planes_aabb(bb_min, bb_max, data) != ISECT_INSIDE;
}
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index 88dc63d6cb2..55f9f384081 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -69,11 +69,134 @@
static void pbvh_bmesh_verify(PBVH *bvh);
#endif
+/** \name BMesh Utility API
+ *
+ * Use some local functions which assume triangles.
+ * \{ */
+
+/**
+ * Typically using BM_LOOPS_OF_VERT and BM_FACES_OF_VERT iterators are fine,
+ * however this is an area where performance matters so do it in-line.
+ *
+ * Take care since 'break' won't works as expected within these macros!
+ */
+
+#define BM_LOOPS_OF_VERT_ITER_BEGIN(l_iter_radial_, v_) \
+{ \
+ struct { BMVert *v; BMEdge *e_iter, *e_first; BMLoop *l_iter_radial; } _iter; \
+ _iter.v = v_; \
+ if (_iter.v->e) { \
+ _iter.e_iter = _iter.e_first = _iter.v->e; \
+ do { \
+ if (_iter.e_iter->l) { \
+ _iter.l_iter_radial = _iter.e_iter->l; \
+ do { \
+ if (_iter.l_iter_radial->v == _iter.v) { \
+ l_iter_radial_ = _iter.l_iter_radial;
+
+#define BM_LOOPS_OF_VERT_ITER_END \
+ } \
+ } while ((_iter.l_iter_radial = _iter.l_iter_radial->radial_next) != _iter.e_iter->l); \
+ } \
+ } while ((_iter.e_iter = BM_DISK_EDGE_NEXT(_iter.e_iter, _iter.v)) != _iter.e_first); \
+ } \
+} ((void)0)
+
+#define BM_FACES_OF_VERT_ITER_BEGIN(f_iter_, v_) \
+{ \
+ BMLoop *l_iter_radial_; \
+ BM_LOOPS_OF_VERT_ITER_BEGIN(l_iter_radial_, v_) { \
+ f_iter_ = l_iter_radial_->f; \
+
+#define BM_FACES_OF_VERT_ITER_END \
+ } \
+ BM_LOOPS_OF_VERT_ITER_END; \
+}
+
+static void bm_edges_from_tri(BMesh *bm, BMVert *v_tri[3], BMEdge *e_tri[3])
+{
+ e_tri[0] = BM_edge_create(bm, v_tri[0], v_tri[1], NULL, BM_CREATE_NO_DOUBLE);
+ e_tri[1] = BM_edge_create(bm, v_tri[1], v_tri[2], NULL, BM_CREATE_NO_DOUBLE);
+ e_tri[2] = BM_edge_create(bm, v_tri[2], v_tri[0], NULL, BM_CREATE_NO_DOUBLE);
+}
+
+BLI_INLINE void bm_face_as_array_index_tri(BMFace *f, int r_index[3])
+{
+ BMLoop *l = BM_FACE_FIRST_LOOP(f);
+
+ BLI_assert(f->len == 3);
+
+ r_index[0] = BM_elem_index_get(l->v); l = l->next;
+ r_index[1] = BM_elem_index_get(l->v); l = l->next;
+ r_index[2] = BM_elem_index_get(l->v);
+}
+
+/**
+ * A version of #BM_face_exists, optimized for triangles
+ * when we know the loop and the opposite vertex.
+ *
+ * Check if any triangle is formed by (l_radial_first->v, l_radial_first->next->v, v_opposite),
+ * at either winding (since its a triangle no special checks are needed).
+ *
+ * <pre>
+ * l_radial_first->v & l_radial_first->next->v
+ * +---+
+ * | /
+ * | /
+ * + v_opposite
+ * </pre>
+ *
+ * Its assumed that \a l_radial_first is never forming the target face.
+ */
+static bool bm_face_exists_tri_from_loop_vert(
+ BMLoop *l_radial_first, BMVert *v_opposite, BMFace **r_face_existing)
+{
+ BLI_assert(!ELEM(v_opposite, l_radial_first->v, l_radial_first->next->v, l_radial_first->prev->v));
+ if (l_radial_first->radial_next != l_radial_first) {
+ BMLoop *l_radial_iter = l_radial_first->radial_next;
+ do {
+ BLI_assert(l_radial_iter->f->len == 3);
+ if (l_radial_iter->prev->v == v_opposite) {
+ *r_face_existing = l_radial_iter->f;
+ return true;
+ }
+ } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first);
+ }
+ return false;
+}
+
+/**
+ * Uses a map of vertices to lookup the final target.
+ * References can't point to previous items (would cause infinite loop).
+ */
+static BMVert *bm_vert_hash_lookup_chain(GHash *deleted_verts, BMVert *v)
+{
+ while (true) {
+ BMVert **v_next_p = (BMVert **)BLI_ghash_lookup_p(deleted_verts, v);
+ if (v_next_p == NULL) {
+ /* not remapped*/
+ return v;
+ }
+ else if (*v_next_p == NULL) {
+ /* removed and not remapped */
+ return NULL;
+ }
+ else {
+ /* remapped */
+ v = *v_next_p;
+ }
+ }
+}
+
+/** \} */
+
/****************************** Building ******************************/
/* Update node data after splitting */
-static void pbvh_bmesh_node_finalize(PBVH *bvh, int node_index, const int cd_vert_node_offset, const int cd_face_node_offset)
+static void pbvh_bmesh_node_finalize(
+ PBVH *bvh, const int node_index,
+ const int cd_vert_node_offset, const int cd_face_node_offset)
{
GSetIterator gs_iter;
PBVHNode *n = &bvh->nodes[node_index];
@@ -200,7 +323,7 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde
break;
}
}
-
+
/* Clear this node */
/* Mark this node's unique verts as unclaimed */
@@ -224,18 +347,18 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde
if (n->layer_disp)
MEM_freeN(n->layer_disp);
-
+
n->bm_faces = NULL;
n->bm_unique_verts = NULL;
n->bm_other_verts = NULL;
n->layer_disp = NULL;
-
+
if (n->draw_buffers) {
GPU_free_pbvh_buffers(n->draw_buffers);
n->draw_buffers = NULL;
}
n->flag &= ~PBVH_Leaf;
-
+
/* Recurse */
pbvh_bmesh_node_split(bvh, bbc_array, children);
pbvh_bmesh_node_split(bvh, bbc_array, children + 1);
@@ -292,6 +415,7 @@ static bool pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index)
/**********************************************************************/
+#if 0
static int pbvh_bmesh_node_offset_from_elem(PBVH *bvh, BMElem *ele)
{
switch (ele->head.htype) {
@@ -304,7 +428,7 @@ static int pbvh_bmesh_node_offset_from_elem(PBVH *bvh, BMElem *ele)
}
-static int pbvh_bmesh_node_lookup_index(PBVH *bvh, void *key)
+static int pbvh_bmesh_node_index_from_elem(PBVH *bvh, void *key)
{
const int cd_node_offset = pbvh_bmesh_node_offset_from_elem(bvh, key);
const int node_index = BM_ELEM_CD_GET_INT((BMElem *)key, cd_node_offset);
@@ -316,18 +440,45 @@ static int pbvh_bmesh_node_lookup_index(PBVH *bvh, void *key)
return node_index;
}
-static PBVHNode *pbvh_bmesh_node_lookup(PBVH *bvh, void *key)
+static PBVHNode *pbvh_bmesh_node_from_elem(PBVH *bvh, void *key)
{
- return &bvh->nodes[pbvh_bmesh_node_lookup_index(bvh, key)];
+ return &bvh->nodes[pbvh_bmesh_node_index_from_elem(bvh, key)];
}
/* typecheck */
-#define pbvh_bmesh_node_lookup_index(bvh, key) ( \
+#define pbvh_bmesh_node_index_from_elem(bvh, key) ( \
CHECK_TYPE_ANY(key, BMFace *, BMVert *), \
- pbvh_bmesh_node_lookup_index(bvh, key))
-#define pbvh_bmesh_node_lookup(bvh, key) ( \
+ pbvh_bmesh_node_index_from_elem(bvh, key))
+#define pbvh_bmesh_node_from_elem(bvh, key) ( \
CHECK_TYPE_ANY(key, BMFace *, BMVert *), \
- pbvh_bmesh_node_lookup(bvh, key))
+ pbvh_bmesh_node_from_elem(bvh, key))
+#endif
+
+BLI_INLINE int pbvh_bmesh_node_index_from_vert(PBVH *bvh, const BMVert *key)
+{
+ const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, bvh->cd_vert_node_offset);
+ BLI_assert(node_index != DYNTOPO_NODE_NONE);
+ BLI_assert(node_index < bvh->totnode);
+ return node_index;
+}
+
+BLI_INLINE int pbvh_bmesh_node_index_from_face(PBVH *bvh, const BMFace *key)
+{
+ const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, bvh->cd_face_node_offset);
+ BLI_assert(node_index != DYNTOPO_NODE_NONE);
+ BLI_assert(node_index < bvh->totnode);
+ return node_index;
+}
+
+BLI_INLINE PBVHNode *pbvh_bmesh_node_from_vert(PBVH *bvh, const BMVert *key)
+{
+ return &bvh->nodes[pbvh_bmesh_node_index_from_vert(bvh, key)];
+}
+
+BLI_INLINE PBVHNode *pbvh_bmesh_node_from_face(PBVH *bvh, const BMFace *key)
+{
+ return &bvh->nodes[pbvh_bmesh_node_index_from_face(bvh, key)];
+}
static BMVert *pbvh_bmesh_vert_create(
@@ -357,6 +508,9 @@ static BMVert *pbvh_bmesh_vert_create(
return v;
}
+/**
+ * \note Callers are responsible for checking if the face exists before adding.
+ */
static BMFace *pbvh_bmesh_face_create(
PBVH *bvh, int node_index,
BMVert *v_tri[3], BMEdge *e_tri[3],
@@ -367,7 +521,7 @@ static BMFace *pbvh_bmesh_face_create(
/* ensure we never add existing face */
BLI_assert(BM_face_exists(v_tri, 3, NULL) == false);
- BMFace *f = BM_face_create(bvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NO_DOUBLE);
+ BMFace *f = BM_face_create(bvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP);
f->head.hflag = f_example->head.hflag;
BLI_gset_insert(node->bm_faces, f);
@@ -387,16 +541,16 @@ static BMFace *pbvh_bmesh_face_create(
#if 0
static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v)
{
- BMIter bm_iter;
BMFace *f;
int count = 0;
- BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
- PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f);
+ BM_FACES_OF_VERT_ITER_BEGIN(f, v) {
+ PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f);
if (f_node == node) {
count++;
}
}
+ BM_FACES_OF_VERT_ITER_END;
return count;
}
@@ -407,19 +561,19 @@ static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v)
static int pbvh_bmesh_node_vert_use_count_ex(PBVH *bvh, PBVHNode *node, BMVert *v, const int count_max)
{
- BMIter bm_iter;
- BMFace *f;
int count = 0;
+ BMFace *f;
- BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
- PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f);
+ BM_FACES_OF_VERT_ITER_BEGIN(f, v) {
+ PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f);
if (f_node == node) {
count++;
if (count == count_max) {
- break;
+ return count;
}
}
}
+ BM_FACES_OF_VERT_ITER_END;
return count;
}
@@ -427,16 +581,17 @@ static int pbvh_bmesh_node_vert_use_count_ex(PBVH *bvh, PBVHNode *node, BMVert *
/* Return a node that uses vertex 'v' other than its current owner */
static PBVHNode *pbvh_bmesh_vert_other_node_find(PBVH *bvh, BMVert *v)
{
- BMIter bm_iter;
+ PBVHNode *current_node = pbvh_bmesh_node_from_vert(bvh, v);
BMFace *f;
- PBVHNode *current_node = pbvh_bmesh_node_lookup(bvh, v);
- BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
- PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f);
+ BM_FACES_OF_VERT_ITER_BEGIN(f, v) {
+ PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f);
- if (f_node != current_node)
+ if (f_node != current_node) {
return f_node;
+ }
}
+ BM_FACES_OF_VERT_ITER_END;
return NULL;
}
@@ -445,7 +600,7 @@ static void pbvh_bmesh_vert_ownership_transfer(
PBVH *bvh, PBVHNode *new_owner,
BMVert *v)
{
- PBVHNode *current_owner = pbvh_bmesh_node_lookup(bvh, v);
+ PBVHNode *current_owner = pbvh_bmesh_node_from_vert(bvh, v);
/* mark node for update */
current_owner->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
@@ -469,36 +624,36 @@ static void pbvh_bmesh_vert_remove(PBVH *bvh, BMVert *v)
/* never match for first time */
int f_node_index_prev = DYNTOPO_NODE_NONE;
- PBVHNode *v_node = pbvh_bmesh_node_lookup(bvh, v);
+ PBVHNode *v_node = pbvh_bmesh_node_from_vert(bvh, v);
BLI_gset_remove(v_node->bm_unique_verts, v, NULL);
BM_ELEM_CD_SET_INT(v, bvh->cd_vert_node_offset, DYNTOPO_NODE_NONE);
/* Have to check each neighboring face's node */
- BMIter bm_iter;
BMFace *f;
- BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
- const int f_node_index = pbvh_bmesh_node_lookup_index(bvh, f);
+ BM_FACES_OF_VERT_ITER_BEGIN(f, v) {
+ const int f_node_index = pbvh_bmesh_node_index_from_face(bvh, f);
/* faces often share the same node,
* quick check to avoid redundant #BLI_gset_remove calls */
- if (f_node_index_prev == f_node_index)
- continue;
- f_node_index_prev = f_node_index;
+ if (f_node_index_prev != f_node_index) {
+ f_node_index_prev = f_node_index;
- PBVHNode *f_node = &bvh->nodes[f_node_index];
- f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
+ PBVHNode *f_node = &bvh->nodes[f_node_index];
+ f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
- /* Remove current ownership */
- BLI_gset_remove(f_node->bm_other_verts, v, NULL);
+ /* Remove current ownership */
+ BLI_gset_remove(f_node->bm_other_verts, v, NULL);
- BLI_assert(!BLI_gset_haskey(f_node->bm_unique_verts, v));
- BLI_assert(!BLI_gset_haskey(f_node->bm_other_verts, v));
+ BLI_assert(!BLI_gset_haskey(f_node->bm_unique_verts, v));
+ BLI_assert(!BLI_gset_haskey(f_node->bm_other_verts, v));
+ }
}
+ BM_FACES_OF_VERT_ITER_END;
}
static void pbvh_bmesh_face_remove(PBVH *bvh, BMFace *f)
{
- PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f);
+ PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f);
/* Check if any of this face's vertices need to be removed
* from the node */
@@ -923,13 +1078,6 @@ static void short_edge_queue_create(
/*************************** Topology update **************************/
-static void bm_edges_from_tri(BMesh *bm, BMVert *v_tri[3], BMEdge *e_tri[3])
-{
- e_tri[0] = BM_edge_create(bm, v_tri[0], v_tri[1], NULL, BM_CREATE_NO_DOUBLE);
- e_tri[1] = BM_edge_create(bm, v_tri[1], v_tri[2], NULL, BM_CREATE_NO_DOUBLE);
- e_tri[2] = BM_edge_create(bm, v_tri[2], v_tri[0], NULL, BM_CREATE_NO_DOUBLE);
-}
-
static void pbvh_bmesh_split_edge(
EdgeQueueContext *eq_ctx, PBVH *bvh,
BMEdge *e, BLI_Buffer *edge_loops)
@@ -1101,15 +1249,16 @@ static bool pbvh_bmesh_subdivide_long_edges(
static void pbvh_bmesh_collapse_edge(
PBVH *bvh, BMEdge *e,
BMVert *v1, BMVert *v2,
- GSet *deleted_verts,
+ GHash *deleted_verts,
BLI_Buffer *deleted_faces,
EdgeQueueContext *eq_ctx)
{
BMVert *v_del, *v_conn;
- float mask_v1 = BM_ELEM_CD_GET_FLOAT(v1, eq_ctx->cd_vert_mask_offset);
/* one of the two vertices may be masked, select the correct one for deletion */
- if (mask_v1 < 1.0f) {
+ if (BM_ELEM_CD_GET_FLOAT(v1, eq_ctx->cd_vert_mask_offset) <
+ BM_ELEM_CD_GET_FLOAT(v2, eq_ctx->cd_vert_mask_offset))
+ {
v_del = v1;
v_conn = v2;
}
@@ -1141,33 +1290,43 @@ static void pbvh_bmesh_collapse_edge(
* really buy anything. */
BLI_buffer_empty(deleted_faces);
- BMIter bm_iter;
- BMFace *f;
+ BMLoop *l;
- BM_ITER_ELEM (f, &bm_iter, v_del, BM_FACES_OF_VERT) {
- BMVert *v_tri[3];
+ BM_LOOPS_OF_VERT_ITER_BEGIN(l, v_del) {
BMFace *existing_face;
/* Get vertices, replace use of v_del with v_conn */
// BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f, (void **)v_tri, 3);
+ BMFace *f = l->f;
+#if 0
+ BMVert *v_tri[3];
BM_face_as_array_vert_tri(f, v_tri);
for (int i = 0; i < 3; i++) {
if (v_tri[i] == v_del) {
v_tri[i] = v_conn;
}
}
+#endif
/* Check if a face using these vertices already exists. If so,
* skip adding this face and mark the existing one for
* deletion as well. Prevents extraneous "flaps" from being
* created. */
- if (BM_face_exists(v_tri, 3, &existing_face)) {
+#if 0
+ if (UNLIKELY(BM_face_exists(v_tri, 3, &existing_face)))
+#else
+ if (UNLIKELY(bm_face_exists_tri_from_loop_vert(l->next, v_conn, &existing_face)))
+#endif
+ {
BLI_assert(existing_face);
BLI_buffer_append(deleted_faces, BMFace *, existing_face);
}
else {
+ BMVert *v_tri[3] = {v_conn, l->next->v, l->prev->v};
+
+ BLI_assert(BM_face_exists(v_tri, 3, NULL) == false);
BMEdge *e_tri[3];
- PBVHNode *n = pbvh_bmesh_node_lookup(bvh, f);
+ PBVHNode *n = pbvh_bmesh_node_from_face(bvh, f);
int ni = n - bvh->nodes;
bm_edges_from_tri(bvh->bm, v_tri, e_tri);
pbvh_bmesh_face_create(bvh, ni, v_tri, e_tri, f);
@@ -1180,6 +1339,7 @@ static void pbvh_bmesh_collapse_edge(
BLI_buffer_append(deleted_faces, BMFace *, f);
}
+ BM_LOOPS_OF_VERT_ITER_END;
/* Delete the tagged faces */
for (int i = 0; i < deleted_faces->count; i++) {
@@ -1209,10 +1369,14 @@ static void pbvh_bmesh_collapse_edge(
* remove them from the PBVH */
for (int j = 0; j < 3; j++) {
if ((v_tri[j] != v_del) && (v_tri[j]->e == NULL)) {
- BLI_gset_insert(deleted_verts, v_tri[j]);
pbvh_bmesh_vert_remove(bvh, v_tri[j]);
BM_log_vert_removed(bvh->bm_log, v_tri[j], eq_ctx->cd_vert_mask_offset);
+
+ if (v_tri[j] == v_conn) {
+ v_conn = NULL;
+ }
+ BLI_ghash_insert(deleted_verts, v_tri[j], NULL);
BM_vert_kill(bvh->bm, v_tri[j]);
}
}
@@ -1220,17 +1384,26 @@ static void pbvh_bmesh_collapse_edge(
/* Move v_conn to the midpoint of v_conn and v_del (if v_conn still exists, it
* may have been deleted above) */
- if (!BLI_gset_haskey(deleted_verts, v_conn)) {
+ if (v_conn != NULL) {
BM_log_vert_before_modified(bvh->bm_log, v_conn, eq_ctx->cd_vert_mask_offset);
mid_v3_v3v3(v_conn->co, v_conn->co, v_del->co);
add_v3_v3(v_conn->no, v_del->no);
normalize_v3(v_conn->no);
+
+ /* update boundboxes attached to the connected vertex
+ * note that we can often get-away without this but causes T48779 */
+ BM_LOOPS_OF_VERT_ITER_BEGIN(l, v_conn) {
+ PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, l->f);
+ f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals | PBVH_UpdateBB;
+ }
+ BM_LOOPS_OF_VERT_ITER_END;
}
/* Delete v_del */
BLI_assert(!BM_vert_face_check(v_del));
- BLI_gset_insert(deleted_verts, v_del);
BM_log_vert_removed(bvh->bm_log, v_del, eq_ctx->cd_vert_mask_offset);
+ /* v_conn == NULL is OK */
+ BLI_ghash_insert(deleted_verts, v_del, v_conn);
BM_vert_kill(bvh->bm, v_del);
}
@@ -1241,17 +1414,19 @@ static bool pbvh_bmesh_collapse_short_edges(
{
const float min_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len;
bool any_collapsed = false;
- GSet *deleted_verts = BLI_gset_ptr_new("deleted_verts");
+ /* deleted verts point to vertices they were merged into, or NULL when removed. */
+ GHash *deleted_verts = BLI_ghash_ptr_new("deleted_verts");
while (!BLI_heap_is_empty(eq_ctx->q->heap)) {
BMVert **pair = BLI_heap_popmin(eq_ctx->q->heap);
- BMVert *v1 = pair[0], *v2 = pair[1];
+ BMVert *v1 = pair[0], *v2 = pair[1];
BLI_mempool_free(eq_ctx->pool, pair);
pair = NULL;
/* Check the verts still exist */
- if (BLI_gset_haskey(deleted_verts, v1) ||
- BLI_gset_haskey(deleted_verts, v2))
+ if (!(v1 = bm_vert_hash_lookup_chain(deleted_verts, v1)) ||
+ !(v2 = bm_vert_hash_lookup_chain(deleted_verts, v2)) ||
+ (v1 == v2))
{
continue;
}
@@ -1285,7 +1460,7 @@ static bool pbvh_bmesh_collapse_short_edges(
deleted_faces, eq_ctx);
}
- BLI_gset_free(deleted_verts, NULL);
+ BLI_ghash_free(deleted_verts, NULL, NULL);
return any_collapsed;
}
@@ -1406,18 +1581,23 @@ void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode)
}
}
-typedef struct FastNodeBuildInfo {
+struct FastNodeBuildInfo {
int totface; /* number of faces */
int start; /* start of faces in array */
struct FastNodeBuildInfo *child1;
struct FastNodeBuildInfo *child2;
-} FastNodeBuildInfo;
+};
-/* Recursively split the node if it exceeds the leaf_limit. This function is multithreadabe since each invocation applies
- * to a sub part of the arrays */
-static void pbvh_bmesh_node_limit_ensure_fast(PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, FastNodeBuildInfo *node, MemArena *arena)
+/**
+ * Recursively split the node if it exceeds the leaf_limit.
+ * This function is multithreadabe since each invocation applies
+ * to a sub part of the arrays
+ */
+static void pbvh_bmesh_node_limit_ensure_fast(
+ PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, struct FastNodeBuildInfo *node,
+ MemArena *arena)
{
- FastNodeBuildInfo *child1, *child2;
+ struct FastNodeBuildInfo *child1, *child2;
if (node->totface <= bvh->leaf_limit) {
return;
@@ -1497,8 +1677,8 @@ static void pbvh_bmesh_node_limit_ensure_fast(PBVH *bvh, BMFace **nodeinfo, BBC
* each sequential part belonging to one node only */
BLI_assert((num_child1 + num_child2) == node->totface);
- node->child1 = child1 = BLI_memarena_alloc(arena, sizeof(FastNodeBuildInfo));
- node->child2 = child2 = BLI_memarena_alloc(arena, sizeof(FastNodeBuildInfo));
+ node->child1 = child1 = BLI_memarena_alloc(arena, sizeof(struct FastNodeBuildInfo));
+ node->child2 = child2 = BLI_memarena_alloc(arena, sizeof(struct FastNodeBuildInfo));
child1->totface = num_child1;
child1->start = node->start;
@@ -1510,7 +1690,9 @@ static void pbvh_bmesh_node_limit_ensure_fast(PBVH *bvh, BMFace **nodeinfo, BBC
pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, child2, arena);
}
-static void pbvh_bmesh_create_nodes_fast_recursive(PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, FastNodeBuildInfo *node, int node_index)
+static void pbvh_bmesh_create_nodes_fast_recursive(
+ PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array,
+ struct FastNodeBuildInfo *node, int node_index)
{
PBVHNode *n = bvh->nodes + node_index;
/* two cases, node does not have children or does have children */
@@ -1651,7 +1833,7 @@ void BKE_pbvh_build_bmesh(
bm->elem_index_dirty |= BM_FACE;
/* setup root node */
- FastNodeBuildInfo rootnode = {0};
+ struct FastNodeBuildInfo rootnode = {0};
rootnode.totface = bm->totface;
/* start recursion, assign faces to nodes accordingly */
@@ -1693,12 +1875,14 @@ bool BKE_pbvh_bmesh_update_topology(
if (mode & PBVH_Collapse) {
EdgeQueue q;
BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *[2]), 0, 128, BLI_MEMPOOL_NOP);
- EdgeQueueContext eq_ctx = {&q, queue_pool, bvh->bm, cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset};
+ EdgeQueueContext eq_ctx = {
+ &q, queue_pool, bvh->bm,
+ cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset,
+ };
short_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius);
- modified |= !BLI_heap_is_empty(q.heap);
- pbvh_bmesh_collapse_short_edges(&eq_ctx, bvh,
- &deleted_faces);
+ modified |= pbvh_bmesh_collapse_short_edges(
+ &eq_ctx, bvh, &deleted_faces);
BLI_heap_free(q.heap, NULL);
BLI_mempool_destroy(queue_pool);
}
@@ -1706,15 +1890,18 @@ bool BKE_pbvh_bmesh_update_topology(
if (mode & PBVH_Subdivide) {
EdgeQueue q;
BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *[2]), 0, 128, BLI_MEMPOOL_NOP);
- EdgeQueueContext eq_ctx = {&q, queue_pool, bvh->bm, cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset};
+ EdgeQueueContext eq_ctx = {
+ &q, queue_pool, bvh->bm,
+ cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset,
+ };
long_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius);
- modified |= !BLI_heap_is_empty(q.heap);
- pbvh_bmesh_subdivide_long_edges(&eq_ctx, bvh, &edge_loops);
+ modified |= pbvh_bmesh_subdivide_long_edges(
+ &eq_ctx, bvh, &edge_loops);
BLI_heap_free(q.heap, NULL);
BLI_mempool_destroy(queue_pool);
}
-
+
/* Unmark nodes */
for (int n = 0; n < bvh->totnode; n++) {
PBVHNode *node = &bvh->nodes[n];
@@ -1735,16 +1922,6 @@ bool BKE_pbvh_bmesh_update_topology(
return modified;
}
-BLI_INLINE void bm_face_as_array_index_tri(BMFace *f, int r_index[3])
-{
- BMLoop *l = BM_FACE_FIRST_LOOP(f);
-
- BLI_assert(f->len == 3);
-
- r_index[0] = BM_elem_index_get(l->v); l = l->next;
- r_index[1] = BM_elem_index_get(l->v); l = l->next;
- r_index[2] = BM_elem_index_get(l->v);
-}
/* In order to perform operations on the original node coordinates
* (currently just raycast), store the node's triangles and vertices.
@@ -1858,8 +2035,8 @@ static void pbvh_bmesh_print(PBVH *bvh)
BMFace *f;
BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) {
fprintf(stderr, " %d -> %d\n",
- BM_elem_index_get(v),
- pbvh_bmesh_node_lookup_index(bvh, f));
+ BM_elem_index_get(f),
+ pbvh_bmesh_node_index_from_face(bvh, f));
}
fprintf(stderr, "bm_vert_to_node:\n");
@@ -1867,7 +2044,7 @@ static void pbvh_bmesh_print(PBVH *bvh)
BM_ITER_MESH(v, &iter, bvh->bm, BM_FACES_OF_MESH) {
fprintf(stderr, " %d -> %d\n",
BM_elem_index_get(v),
- pbvh_bmesh_node_lookup_index(bvh, v));
+ pbvh_bmesh_node_index_from_vert(bvh, v));
}
for (int n = 0; n < bvh->totnode; n++) {
@@ -1909,17 +2086,23 @@ static void pbvh_bmesh_verify(PBVH *bvh)
{
/* build list of faces & verts to lookup */
GSet *faces_all = BLI_gset_ptr_new_ex(__func__, bvh->bm->totface);
- BMFace *f;
BMIter iter;
- BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) {
- BLI_gset_insert(faces_all, f);
+
+ {
+ BMFace *f;
+ BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) {
+ BLI_assert(BM_ELEM_CD_GET_INT(f, bvh->cd_face_node_offset) != DYNTOPO_NODE_NONE);
+ BLI_gset_insert(faces_all, f);
+ }
}
GSet *verts_all = BLI_gset_ptr_new_ex(__func__, bvh->bm->totvert);
- BMVert *v;
- BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) {
- if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
- BLI_gset_insert(verts_all, v);
+ {
+ BMVert *v;
+ BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) {
+ if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
+ BLI_gset_insert(verts_all, v);
+ }
}
}
@@ -1936,76 +2119,83 @@ static void pbvh_bmesh_verify(PBVH *bvh)
BLI_assert(totvert == BLI_gset_size(verts_all));
}
- BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) {
- BMIter bm_iter;
- BMVert *v;
- PBVHNode *n = pbvh_bmesh_node_lookup(bvh, f);
+ {
+ BMFace *f;
+ BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) {
+ BMIter bm_iter;
+ BMVert *v;
+ PBVHNode *n = pbvh_bmesh_node_lookup(bvh, f);
- /* Check that the face's node is a leaf */
- BLI_assert(n->flag & PBVH_Leaf);
+ /* Check that the face's node is a leaf */
+ BLI_assert(n->flag & PBVH_Leaf);
- /* Check that the face's node knows it owns the face */
- BLI_assert(BLI_gset_haskey(n->bm_faces, f));
+ /* Check that the face's node knows it owns the face */
+ BLI_assert(BLI_gset_haskey(n->bm_faces, f));
- /* Check the face's vertices... */
- BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) {
- PBVHNode *nv;
+ /* Check the face's vertices... */
+ BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) {
+ PBVHNode *nv;
- /* Check that the vertex is in the node */
- BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v) ^
- BLI_gset_haskey(n->bm_other_verts, v));
+ /* Check that the vertex is in the node */
+ BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v) ^
+ BLI_gset_haskey(n->bm_other_verts, v));
- /* Check that the vertex has a node owner */
- nv = pbvh_bmesh_node_lookup(bvh, v);
+ /* Check that the vertex has a node owner */
+ nv = pbvh_bmesh_node_lookup(bvh, v);
- /* Check that the vertex's node knows it owns the vert */
- BLI_assert(BLI_gset_haskey(nv->bm_unique_verts, v));
+ /* Check that the vertex's node knows it owns the vert */
+ BLI_assert(BLI_gset_haskey(nv->bm_unique_verts, v));
- /* Check that the vertex isn't duplicated as an 'other' vert */
- BLI_assert(!BLI_gset_haskey(nv->bm_other_verts, v));
+ /* Check that the vertex isn't duplicated as an 'other' vert */
+ BLI_assert(!BLI_gset_haskey(nv->bm_other_verts, v));
+ }
}
}
/* Check verts */
- BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) {
- /* vertex isn't tracked */
- if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) == DYNTOPO_NODE_NONE) {
- continue;
- }
+ {
+ BMVert *v;
+ BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) {
+ /* vertex isn't tracked */
+ if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) == DYNTOPO_NODE_NONE) {
+ continue;
+ }
- PBVHNode *n = pbvh_bmesh_node_lookup(bvh, v);
+ PBVHNode *n = pbvh_bmesh_node_lookup(bvh, v);
- /* Check that the vert's node is a leaf */
- BLI_assert(n->flag & PBVH_Leaf);
+ /* Check that the vert's node is a leaf */
+ BLI_assert(n->flag & PBVH_Leaf);
- /* Check that the vert's node knows it owns the vert */
- BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v));
+ /* Check that the vert's node knows it owns the vert */
+ BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v));
- /* Check that the vertex isn't duplicated as an 'other' vert */
- BLI_assert(!BLI_gset_haskey(n->bm_other_verts, v));
+ /* Check that the vertex isn't duplicated as an 'other' vert */
+ BLI_assert(!BLI_gset_haskey(n->bm_other_verts, v));
- /* Check that the vert's node also contains one of the vert's
- * adjacent faces */
- bool found = false;
- BMIter bm_iter;
- BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
- if (pbvh_bmesh_node_lookup(bvh, f) == n) {
- found = true;
- break;
+ /* Check that the vert's node also contains one of the vert's
+ * adjacent faces */
+ bool found = false;
+ BMIter bm_iter;
+ BMFace *f = NULL;
+ BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
+ if (pbvh_bmesh_node_lookup(bvh, f) == n) {
+ found = true;
+ break;
+ }
}
- }
- BLI_assert(found);
+ BLI_assert(found || f == NULL);
#if 1
- /* total freak stuff, check if node exists somewhere else */
- /* Slow */
- for (int i = 0; i < bvh->totnode; i++) {
- PBVHNode *n_other = &bvh->nodes[i];
- if ((n != n_other) && (n_other->bm_unique_verts)) {
- BLI_assert(!BLI_gset_haskey(n_other->bm_unique_verts, v));
+ /* total freak stuff, check if node exists somewhere else */
+ /* Slow */
+ for (int i = 0; i < bvh->totnode; i++) {
+ PBVHNode *n_other = &bvh->nodes[i];
+ if ((n != n_other) && (n_other->bm_unique_verts)) {
+ BLI_assert(!BLI_gset_haskey(n_other->bm_unique_verts, v));
+ }
}
- }
#endif
+ }
}
#if 0
@@ -2049,7 +2239,8 @@ static void pbvh_bmesh_verify(PBVH *bvh)
GSET_ITER (gs_iter, n->bm_other_verts) {
BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
- BLI_assert(!BM_vert_face_check(v));
+ /* this happens sometimes and seems harmless */
+ // BLI_assert(!BM_vert_face_check(v));
BLI_assert(BLI_gset_haskey(verts_all, v));
}
}
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index bae323dedef..19d3b31bd31 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -83,12 +83,11 @@ struct PBVHNode {
* array. The array is sized to match 'totprim', and each of
* the face's corners gets an index into the vert_indices
* array, in the same order as the corners in the original
- * MFace. The fourth value should not be used if the original
- * face is a triangle.
+ * MLoopTri.
*
* Used for leaf nodes in a mesh-based PBVH (not multires.)
*/
- const int (*face_vert_indices)[4];
+ const int (*face_vert_indices)[3];
/* Indicates whether this node is a leaf or not; also used for
* marking various updates that need to be applied. */
@@ -145,6 +144,11 @@ struct PBVH {
const DMFlagMat *grid_flag_mats;
int totgrid;
BLI_bitmap **grid_hidden;
+ /* index_buf of GPU_PBVH_Buffers can be the same for all 'fully drawn' nodes (same size).
+ * Previously was stored in a static var in gpu_buffer.c, but this breaks in case we handle several different
+ * objects in sculpt mode with different sizes at the same time, so now storing that common gpu buffer
+ * in an opaque pointer per pbvh. See T47637. */
+ struct GridCommonGPUBuffer *grid_common_gpu_buffer;
/* Only used during BVH build and update,
* don't need to remain valid after */
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index f0ba63e35b4..30eb8dcb287 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -55,8 +55,6 @@
#include "PIL_time.h"
-#include "WM_api.h"
-
#include "BKE_appdir.h"
#include "BKE_anim.h"
#include "BKE_cloth.h"
@@ -388,9 +386,9 @@ static void ptcache_particle_interpolate(int index, void *psys_v, void **data, f
}
}
- /* determine rotation from velocity */
+ /* default to no rotation */
if (data[BPHYS_DATA_LOCATION] && !data[BPHYS_DATA_ROTATION]) {
- vec_to_quat(keys[2].rot, keys[2].vel, OB_NEGX, OB_POSZ);
+ unit_qt(keys[2].rot);
}
if (cfra > pa->time)
@@ -1139,13 +1137,13 @@ static int ptcache_smoke_openvdb_read(struct OpenVDBReader *reader, void *smoke_
OpenVDB_import_grid_fl(reader, "density", &dens, sds->res_wt);
- if (fluid_fields & SM_ACTIVE_FIRE) {
+ if (cache_fields & SM_ACTIVE_FIRE) {
OpenVDB_import_grid_fl(reader, "flame", &flame, sds->res_wt);
OpenVDB_import_grid_fl(reader, "fuel", &fuel, sds->res_wt);
OpenVDB_import_grid_fl(reader, "react", &react, sds->res_wt);
}
- if (fluid_fields & SM_ACTIVE_COLORS) {
+ if (cache_fields & SM_ACTIVE_COLORS) {
OpenVDB_import_grid_vec(reader, "color", &r, &g, &b, sds->res_wt);
}
@@ -2501,7 +2499,7 @@ static int ptcache_read_openvdb_stream(PTCacheID *pid, int cfra)
#ifdef WITH_OPENVDB
char filename[FILE_MAX * 2];
- /* save blend file before using disk pointcache */
+ /* save blend file before using disk pointcache */
if (!G.relbase_valid && (pid->cache->flag & PTCACHE_EXTERNAL) == 0)
return 0;
@@ -2634,7 +2632,7 @@ static int ptcache_interpolate(PTCacheID *pid, float cfra, int cfra1, int cfra2)
}
/* reads cache from disk or memory */
/* possible to get old or interpolated result */
-int BKE_ptcache_read(PTCacheID *pid, float cfra)
+int BKE_ptcache_read(PTCacheID *pid, float cfra, bool no_extrapolate_old)
{
int cfrai = (int)floor(cfra), cfra1=0, cfra2=0;
int ret = 0;
@@ -2660,10 +2658,17 @@ int BKE_ptcache_read(PTCacheID *pid, float cfra)
return 0;
/* don't read old cache if already simulated past cached frame */
- if (cfra1 == 0 && cfra2 && cfra2 <= pid->cache->simframe)
- return 0;
- if (cfra1 && cfra1 == cfra2)
- return 0;
+ if (no_extrapolate_old) {
+ if (cfra1 == 0 && cfra2 && cfra2 <= pid->cache->simframe)
+ return 0;
+ if (cfra1 && cfra1 == cfra2)
+ return 0;
+ }
+ else {
+ /* avoid calling interpolate between the same frame values */
+ if (cfra1 && cfra1 == cfra2)
+ cfra1 = 0;
+ }
if (cfra1) {
if (pid->file_type == PTCACHE_FILE_OPENVDB && pid->read_openvdb_stream) {
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index 0f1f9b4bdf7..c3ae5736aa9 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -1560,14 +1560,16 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime)
/* try to read from cache */
// RB_TODO deal with interpolated, old and baked results
- if (BKE_ptcache_read(&pid, ctime)) {
+ bool can_simulate = (ctime == rbw->ltime + 1) && !(cache->flag & PTCACHE_BAKED);
+
+ if (BKE_ptcache_read(&pid, ctime, can_simulate)) {
BKE_ptcache_validate(cache, (int)ctime);
rbw->ltime = ctime;
return;
}
/* advance simulation, we can only step one frame forward */
- if (ctime == rbw->ltime + 1 && !(cache->flag & PTCACHE_BAKED)) {
+ if (can_simulate) {
/* write cache for first frame when on second frame */
if (rbw->ltime == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact == 0)) {
BKE_ptcache_write(&pid, startframe);
diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c
index e90a39e8c0e..c7f406089d9 100644
--- a/source/blender/blenkernel/intern/sca.c
+++ b/source/blender/blenkernel/intern/sca.c
@@ -44,7 +44,9 @@
#include "DNA_object_types.h"
#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
#include "BLI_math.h"
+
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_library.h"
@@ -653,74 +655,158 @@ void set_sca_new_poins(void)
}
}
-void sca_remove_ob_poin(Object *obt, Object *ob)
+/**
+ * Try to remap logic links to new object... Very, *very* weak.
+ */
+/* XXX Logick bricks... I don't have words to say what I think about this behavior.
+ * They have silent hidden ugly inter-objects dependencies (a sensor can link into any other
+ * object's controllers, and same between controllers and actuators, without *any* explicit reference
+ * to data-block involved).
+ * This is bad, bad, bad!!!
+ * ...and forces us to add yet another very ugly hack to get remapping with logic bricks working. */
+void BKE_sca_logic_links_remap(Main *bmain, Object *ob_old, Object *ob_new)
{
- bSensor *sens;
- bMessageSensor *ms;
- bActuator *act;
- bCameraActuator *ca;
- bObjectActuator *oa;
- bSceneActuator *sa;
- bEditObjectActuator *eoa;
- bPropertyActuator *pa;
- bMessageActuator *ma;
- bParentActuator *para;
- bArmatureActuator *aa;
- bSteeringActuator *sta;
+ if (ob_new == NULL || (ob_old->controllers.first == NULL && ob_old->actuators.first == NULL)) {
+ /* Nothing to do here... */
+ return;
+ }
+ GHash *controllers_map = ob_old->controllers.first ?
+ BLI_ghash_ptr_new_ex(__func__, BLI_listbase_count(&ob_old->controllers)) : NULL;
+ GHash *actuators_map = ob_old->actuators.first ?
+ BLI_ghash_ptr_new_ex(__func__, BLI_listbase_count(&ob_old->actuators)) : NULL;
+
+ /* We try to remap old controllers/actuators to new ones - in a very basic way. */
+ for (bController *cont_old = ob_old->controllers.first, *cont_new = ob_new->controllers.first;
+ cont_old;
+ cont_old = cont_old->next)
+ {
+ bController *cont_new2 = cont_new;
+
+ if (cont_old->mynew != NULL) {
+ cont_new2 = cont_old->mynew;
+ if (!(cont_new2 == cont_new || BLI_findindex(&ob_new->controllers, cont_new2) >= 0)) {
+ cont_new2 = NULL;
+ }
+ }
+ else if (cont_new && cont_old->type != cont_new->type) {
+ cont_new2 = NULL;
+ }
- sens= obt->sensors.first;
- while (sens) {
- switch (sens->type) {
- case SENS_MESSAGE:
- ms= sens->data;
- if (ms->fromObject==ob) ms->fromObject= NULL;
+ BLI_ghash_insert(controllers_map, cont_old, cont_new2);
+
+ if (cont_new) {
+ cont_new = cont_new->next;
}
- sens= sens->next;
}
- act= obt->actuators.first;
- while (act) {
- switch (act->type) {
- case ACT_CAMERA:
- ca= act->data;
- if (ca->ob==ob) ca->ob= NULL;
- break;
- case ACT_OBJECT:
- oa= act->data;
- if (oa->reference==ob) oa->reference= NULL;
- break;
- case ACT_PROPERTY:
- pa= act->data;
- if (pa->ob==ob) pa->ob= NULL;
- break;
- case ACT_SCENE:
- sa= act->data;
- if (sa->camera==ob) sa->camera= NULL;
- break;
- case ACT_EDIT_OBJECT:
- eoa= act->data;
- if (eoa->ob==ob) eoa->ob= NULL;
- break;
- case ACT_MESSAGE:
- ma= act->data;
- if (ma->toObject==ob) ma->toObject= NULL;
- break;
- case ACT_PARENT:
- para = act->data;
- if (para->ob==ob) para->ob = NULL;
- break;
- case ACT_ARMATURE:
- aa = act->data;
- if (aa->target == ob) aa->target = NULL;
- if (aa->subtarget == ob) aa->subtarget = NULL;
- break;
- case ACT_STEERING:
- sta = act->data;
- if (sta->navmesh == ob) sta->navmesh = NULL;
- if (sta->target == ob) sta->target = NULL;
+ for (bActuator *act_old = ob_old->actuators.first, *act_new = ob_new->actuators.first;
+ act_old;
+ act_old = act_old->next)
+ {
+ bActuator *act_new2 = act_new;
+
+ if (act_old->mynew != NULL) {
+ act_new2 = act_old->mynew;
+ if (!(act_new2 == act_new || BLI_findindex(&ob_new->actuators, act_new2) >= 0)) {
+ act_new2 = NULL;
+ }
+ }
+ else if (act_new && act_old->type != act_new->type) {
+ act_new2 = NULL;
+ }
+
+ BLI_ghash_insert(actuators_map, act_old, act_new2);
+
+ if (act_new) {
+ act_new = act_new->next;
+ }
+ }
+
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ if (controllers_map != NULL) {
+ for (bSensor *sens = ob->sensors.first; sens; sens = sens->next) {
+ for (int a = 0; a < sens->totlinks; a++) {
+ if (sens->links[a]) {
+ bController *old_link = sens->links[a];
+ bController **new_link_p = (bController **)BLI_ghash_lookup_p(controllers_map, old_link);
+
+ if (new_link_p == NULL) {
+ /* old_link is *not* in map's keys (i.e. not to any ob_old->controllers),
+ * which means we ignore it totally here. */
+ }
+ else if (*new_link_p == NULL) {
+ unlink_logicbricks((void **)&old_link, (void ***)&(sens->links), &sens->totlinks);
+ a--;
+ }
+ else {
+ sens->links[a] = *new_link_p;
+ }
+ }
+ }
+ }
+ }
+
+ if (actuators_map != NULL) {
+ for (bController *cont = ob->controllers.first; cont; cont = cont->next) {
+ for (int a = 0; a < cont->totlinks; a++) {
+ if (cont->links[a]) {
+ bActuator *old_link = cont->links[a];
+ bActuator **new_link_p = (bActuator **)BLI_ghash_lookup_p(actuators_map, old_link);
+
+ if (new_link_p == NULL) {
+ /* old_link is *not* in map's keys (i.e. not to any ob_old->actuators),
+ * which means we ignore it totally here. */
+ }
+ else if (*new_link_p == NULL) {
+ unlink_logicbricks((void **)&old_link, (void ***)&(cont->links), &cont->totlinks);
+ a--;
+ }
+ else {
+ cont->links[a] = *new_link_p;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (controllers_map) {
+ BLI_ghash_free(controllers_map, NULL, NULL);
+ }
+ if (actuators_map) {
+ BLI_ghash_free(actuators_map, NULL, NULL);
+ }
+}
+
+/**
+ * Handle the copying of logic data into a new object, including internal logic links update.
+ * External links (links between logic bricks of different objects) must be handled separately.
+ */
+void BKE_sca_logic_copy(Object *ob_new, Object *ob)
+{
+ copy_sensors(&ob_new->sensors, &ob->sensors);
+ copy_controllers(&ob_new->controllers, &ob->controllers);
+ copy_actuators(&ob_new->actuators, &ob->actuators);
+
+ for (bSensor *sens = ob_new->sensors.first; sens; sens = sens->next) {
+ if (sens->flag & SENS_NEW) {
+ for (int a = 0; a < sens->totlinks; a++) {
+ if (sens->links[a] && sens->links[a]->mynew) {
+ sens->links[a] = sens->links[a]->mynew;
+ }
+ }
+ }
+ }
+
+ for (bController *cont = ob_new->controllers.first; cont; cont = cont->next) {
+ if (cont->flag & CONT_NEW) {
+ for (int a = 0; a < cont->totlinks; a++) {
+ if (cont->links[a] && cont->links[a]->mynew) {
+ cont->links[a] = cont->links[a]->mynew;
+ }
+ }
}
- act= act->next;
}
}
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index dce4effc21c..6e1f11cb526 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -49,6 +49,7 @@
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
#include "DNA_windowmanager_types.h"
+#include "DNA_gpencil_types.h"
#include "BLI_math.h"
#include "BLI_blenlib.h"
@@ -64,6 +65,7 @@
#include "BKE_animsys.h"
#include "BKE_action.h"
#include "BKE_armature.h"
+#include "BKE_cachefile.h"
#include "BKE_colortools.h"
#include "BKE_depsgraph.h"
#include "BKE_editmesh.h"
@@ -101,11 +103,6 @@
#include "bmesh.h"
-#ifdef WIN32
-#else
-# include <sys/time.h>
-#endif
-
const char *RE_engine_id_BLENDER_RENDER = "BLENDER_RENDER";
const char *RE_engine_id_BLENDER_GAME = "BLENDER_GAME";
const char *RE_engine_id_CYCLES = "CYCLES";
@@ -155,7 +152,7 @@ static void remove_sequencer_fcurves(Scene *sce)
}
}
-Scene *BKE_scene_copy(Scene *sce, int type)
+Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
{
Scene *scen;
SceneRenderLayer *srl, *new_srl;
@@ -165,8 +162,7 @@ Scene *BKE_scene_copy(Scene *sce, int type)
if (type == SCE_COPY_EMPTY) {
ListBase rl, rv;
- /* XXX. main should become an arg */
- scen = BKE_scene_add(G.main, sce->id.name + 2);
+ scen = BKE_scene_add(bmain, sce->id.name + 2);
rl = scen->r.layers;
rv = scen->r.views;
@@ -187,10 +183,10 @@ Scene *BKE_scene_copy(Scene *sce, int type)
BKE_sound_destroy_scene(scen);
}
else {
- scen = BKE_libblock_copy(&sce->id);
+ scen = BKE_libblock_copy(bmain, &sce->id);
BLI_duplicatelist(&(scen->base), &(sce->base));
- BKE_main_id_clear_newpoins(G.main);
+ BKE_main_id_clear_newpoins(bmain);
id_us_plus((ID *)scen->world);
id_us_plus((ID *)scen->set);
@@ -214,7 +210,7 @@ Scene *BKE_scene_copy(Scene *sce, int type)
if (sce->nodetree) {
/* ID's are managed on both copy and switch */
- scen->nodetree = ntreeCopyTree(sce->nodetree);
+ scen->nodetree = ntreeCopyTree(bmain, sce->nodetree);
ntreeSwitchID(scen->nodetree, &sce->id, &scen->id);
}
@@ -242,7 +238,7 @@ Scene *BKE_scene_copy(Scene *sce, int type)
for (lineset = new_srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
if (lineset->linestyle) {
id_us_plus((ID *)lineset->linestyle);
- lineset->linestyle = BKE_linestyle_copy(G.main, lineset->linestyle);
+ lineset->linestyle = BKE_linestyle_copy(bmain, lineset->linestyle);
}
}
}
@@ -291,6 +287,13 @@ Scene *BKE_scene_copy(Scene *sce, int type)
ts->imapaint.paintcursor = NULL;
id_us_plus((ID *)ts->imapaint.stencil);
ts->particle.paintcursor = NULL;
+ /* duplicate Grease Pencil Drawing Brushes */
+ BLI_listbase_clear(&ts->gp_brushes);
+ for (bGPDbrush *brush = sce->toolsettings->gp_brushes.first; brush; brush = brush->next) {
+ bGPDbrush *newbrush = BKE_gpencil_brush_duplicate(brush);
+ BLI_addtail(&ts->gp_brushes, newbrush);
+ }
+
}
/* make a private copy of the avicodecdata */
@@ -325,7 +328,7 @@ Scene *BKE_scene_copy(Scene *sce, int type)
if (type == SCE_COPY_FULL) {
if (scen->world) {
id_us_plus((ID *)scen->world);
- scen->world = BKE_world_copy(scen->world);
+ scen->world = BKE_world_copy(bmain, scen->world);
BKE_animdata_copy_id_action((ID *)scen->world);
}
@@ -339,7 +342,7 @@ Scene *BKE_scene_copy(Scene *sce, int type)
/* grease pencil */
if (scen->gpd) {
if (type == SCE_COPY_FULL) {
- scen->gpd = gpencil_data_duplicate(scen->gpd, false);
+ scen->gpd = BKE_gpencil_data_duplicate(bmain, scen->gpd, false);
}
else if (type == SCE_COPY_EMPTY) {
scen->gpd = NULL;
@@ -349,9 +352,7 @@ Scene *BKE_scene_copy(Scene *sce, int type)
}
}
- if (sce->preview) {
- scen->preview = BKE_previewimg_copy(sce->preview);
- }
+ BKE_previewimg_id_copy(&scen->id, &sce->id);
return scen;
}
@@ -362,41 +363,41 @@ void BKE_scene_groups_relink(Scene *sce)
BKE_rigidbody_world_groups_relink(sce->rigidbody_world);
}
-/* do not free scene itself */
+void BKE_scene_make_local(Main *bmain, Scene *sce, const bool lib_local)
+{
+ /* For now should work, may need more work though to support all possible corner cases
+ * (also scene_copy probably needs some love). */
+ BKE_id_make_local_generic(bmain, &sce->id, true, lib_local);
+}
+
+/** Free (or release) any data used by this scene (does not free the scene itself). */
void BKE_scene_free(Scene *sce)
{
- Base *base;
SceneRenderLayer *srl;
+ BKE_animdata_free((ID *)sce, false);
+
/* check all sequences */
BKE_sequencer_clear_scene_in_allseqs(G.main, sce);
- base = sce->base.first;
- while (base) {
- id_us_min(&base->object->id);
- base = base->next;
- }
- /* do not free objects! */
-
- if (sce->gpd) {
-#if 0 /* removed since this can be invalid memory when freeing everything */
- /* since the grease pencil data is freed before the scene.
- * since grease pencil data is not (yet?), shared between objects
- * its probably safe not to do this, some save and reload will free this. */
- id_us_min(&sce->gpd->id);
-#endif
- sce->gpd = NULL;
- }
-
+ sce->basact = NULL;
BLI_freelistN(&sce->base);
BKE_sequencer_editing_free(sce);
- BKE_animdata_free((ID *)sce);
BKE_keyingsets_free(&sce->keyingsets);
-
- if (sce->rigidbody_world)
+
+ /* is no lib link block, but scene extension */
+ if (sce->nodetree) {
+ ntreeFreeTree(sce->nodetree);
+ MEM_freeN(sce->nodetree);
+ sce->nodetree = NULL;
+ }
+
+ if (sce->rigidbody_world) {
BKE_rigidbody_free_world(sce->rigidbody_world);
-
+ sce->rigidbody_world = NULL;
+ }
+
if (sce->r.avicodecdata) {
free_avicodecdata(sce->r.avicodecdata);
MEM_freeN(sce->r.avicodecdata);
@@ -439,6 +440,10 @@ void BKE_scene_free(Scene *sce)
BKE_paint_free(&sce->toolsettings->uvsculpt->paint);
MEM_freeN(sce->toolsettings->uvsculpt);
}
+ /* free Grease Pencil Drawing Brushes */
+ BKE_gpencil_free_brushes(&sce->toolsettings->gp_brushes);
+ BLI_freelistN(&sce->toolsettings->gp_brushes);
+
BKE_paint_free(&sce->toolsettings->imapaint.paint);
MEM_freeN(sce->toolsettings);
@@ -449,15 +454,8 @@ void BKE_scene_free(Scene *sce)
if (sce->depsgraph)
DEG_graph_free(sce->depsgraph);
- if (sce->nodetree) {
- ntreeFreeTree(sce->nodetree);
- MEM_freeN(sce->nodetree);
- }
-
- if (sce->stats)
- MEM_freeN(sce->stats);
- if (sce->fps_info)
- MEM_freeN(sce->fps_info);
+ MEM_SAFE_FREE(sce->stats);
+ MEM_SAFE_FREE(sce->fps_info);
BKE_sound_destroy_scene(sce);
@@ -550,7 +548,7 @@ void BKE_scene_init(Scene *sce)
sce->r.bake.im_format.compress = 15;
sce->r.scemode = R_DOCOMP | R_DOSEQ | R_EXTENSION;
- sce->r.stamp = R_STAMP_TIME | R_STAMP_FRAME | R_STAMP_DATE | R_STAMP_CAMERA | R_STAMP_SCENE | R_STAMP_FILENAME | R_STAMP_RENDERTIME;
+ sce->r.stamp = R_STAMP_TIME | R_STAMP_FRAME | R_STAMP_DATE | R_STAMP_CAMERA | R_STAMP_SCENE | R_STAMP_FILENAME | R_STAMP_RENDERTIME | R_STAMP_MEMORY;
sce->r.stamp_font_id = 12;
sce->r.fg_stamp[0] = sce->r.fg_stamp[1] = sce->r.fg_stamp[2] = 0.8f;
sce->r.fg_stamp[3] = 1.0f;
@@ -778,6 +776,11 @@ void BKE_scene_init(Scene *sce)
gp_brush->strength = 0.5f;
gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_STRENGTH];
+ gp_brush->size = 25;
+ gp_brush->strength = 0.5f;
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+
gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_GRAB];
gp_brush->size = 50;
gp_brush->strength = 0.3f;
@@ -816,6 +819,8 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
Scene *sce;
sce = BKE_libblock_alloc(bmain, ID_SCE, name);
+ id_us_min(&sce->id);
+ id_us_ensure_real(&sce->id);
BKE_scene_init(sce);
@@ -901,7 +906,7 @@ Scene *BKE_scene_set_name(Main *bmain, const char *name)
Scene *sce = (Scene *)BKE_libblock_find_name_ex(bmain, ID_SCE, name);
if (sce) {
BKE_scene_set_background(bmain, sce);
- printf("Scene switch: '%s' in file: '%s'\n", name, bmain->name);
+ printf("Scene switch for render: '%s' in file: '%s'\n", name, bmain->name);
return sce;
}
@@ -909,40 +914,6 @@ Scene *BKE_scene_set_name(Main *bmain, const char *name)
return NULL;
}
-void BKE_scene_unlink(Main *bmain, Scene *sce, Scene *newsce)
-{
- Scene *sce1;
- bScreen *screen;
-
- /* check all sets */
- for (sce1 = bmain->scene.first; sce1; sce1 = sce1->id.next)
- if (sce1->set == sce)
- sce1->set = NULL;
-
- for (sce1 = bmain->scene.first; sce1; sce1 = sce1->id.next) {
- bNode *node;
-
- if (sce1 == sce || !sce1->nodetree)
- continue;
-
- for (node = sce1->nodetree->nodes.first; node; node = node->next) {
- if (node->id == &sce->id)
- node->id = NULL;
- }
- }
-
- /* all screens */
- for (screen = bmain->screen.first; screen; screen = screen->id.next) {
- if (screen->scene == sce) {
- screen->scene = newsce;
- }
-
- /* editors are handled by WM_main_remove_editor_id_reference */
- }
-
- BKE_libblock_free(bmain, sce);
-}
-
/* Used by metaballs, return *all* objects (including duplis) existing in the scene (including scene's sets) */
int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter,
Scene **scene, int val, Base **base, Object **ob)
@@ -1178,7 +1149,7 @@ char *BKE_scene_find_last_marker_name(Scene *scene, int frame)
Base *BKE_scene_base_add(Scene *sce, Object *ob)
{
- Base *b = MEM_callocN(sizeof(*b), "BKE_scene_base_add");
+ Base *b = MEM_callocN(sizeof(*b), __func__);
BLI_addhead(&sce->base, b);
b->object = ob;
@@ -1198,6 +1169,8 @@ void BKE_scene_base_unlink(Scene *sce, Base *base)
BKE_rigidbody_remove_object(sce, base->object);
BLI_remlink(&sce->base, base);
+ if (sce->basact == base)
+ sce->basact = NULL;
}
void BKE_scene_base_deselect_all(Scene *sce)
@@ -1588,10 +1561,11 @@ static void print_threads_statistics(ThreadedObjectUpdateState *state)
#else
finish_time = PIL_check_seconds_timer();
tot_thread = BLI_system_thread_count();
+ int total_objects = 0;
for (i = 0; i < tot_thread; i++) {
- int total_objects = 0;
- double total_time = 0.0;
+ int thread_total_objects = 0;
+ double thread_total_time = 0.0;
StatisicsEntry *entry;
if (state->has_updated_objects) {
@@ -1600,11 +1574,14 @@ static void print_threads_statistics(ThreadedObjectUpdateState *state)
entry;
entry = entry->next)
{
- total_objects++;
- total_time += entry->duration;
+ thread_total_objects++;
+ thread_total_time += entry->duration;
}
- printf("Thread %d: total %d objects in %f sec.\n", i, total_objects, total_time);
+ printf("Thread %d: total %d objects in %f sec.\n",
+ i,
+ thread_total_objects,
+ thread_total_time);
for (entry = state->statistics[i].first;
entry;
@@ -1612,12 +1589,16 @@ static void print_threads_statistics(ThreadedObjectUpdateState *state)
{
printf(" %s in %f sec\n", entry->object->id.name + 2, entry->duration);
}
+
+ total_objects += thread_total_objects;
}
BLI_freelistN(&state->statistics[i]);
}
if (state->has_updated_objects) {
- printf("Scene update in %f sec\n", finish_time - state->base_time);
+ printf("Scene updated %d objects in %f sec\n",
+ total_objects,
+ finish_time - state->base_time);
}
#endif
}
@@ -1955,6 +1936,9 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
BKE_mask_evaluate_all_masks(bmain, ctime, true);
+ /* Update animated cache files for modifiers. */
+ BKE_cachefile_update_frame(bmain, sce, ctime, (((double)sce->r.frs_sec) / (double)sce->r.frs_sec_base));
+
#ifdef POSE_ANIMATION_WORKAROUND
scene_armature_depsgraph_workaround(bmain);
#endif
@@ -2198,6 +2182,13 @@ bool BKE_scene_use_shading_nodes_custom(Scene *scene)
return (type && type->flag & RE_USE_SHADING_NODES_CUSTOM);
}
+bool BKE_scene_use_world_space_shading(Scene *scene)
+{
+ const RenderEngineType *type = RE_engines_find(scene->r.engine);
+ return ((scene->r.mode & R_USE_WS_SHADING) ||
+ (type && (type->flag & RE_USE_SHADING_NODES)));
+}
+
bool BKE_scene_use_spherical_stereo(Scene *scene)
{
RenderEngineType *type = RE_engines_find(scene->r.engine);
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index 139c6670f74..857bd5447c8 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -273,17 +273,18 @@ void BKE_spacedata_draw_locks(int set)
}
}
-static void (*spacedata_id_unref_cb)(struct SpaceLink *sl, const struct ID *id) = NULL;
+static void (*spacedata_id_remap_cb)(struct ScrArea *sa, struct SpaceLink *sl, ID *old_id, ID *new_id) = NULL;
-void BKE_spacedata_callback_id_unref_set(void (*func)(struct SpaceLink *sl, const struct ID *))
+void BKE_spacedata_callback_id_remap_set(void (*func)(ScrArea *sa, SpaceLink *sl, ID *, ID *))
{
- spacedata_id_unref_cb = func;
+ spacedata_id_remap_cb = func;
}
-void BKE_spacedata_id_unref(struct SpaceLink *sl, const struct ID *id)
+/* UNUSED!!! */
+void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID *id)
{
- if (spacedata_id_unref_cb) {
- spacedata_id_unref_cb(sl, id);
+ if (spacedata_id_remap_cb) {
+ spacedata_id_remap_cb(sa, sl, id, NULL);
}
}
@@ -358,11 +359,13 @@ void BKE_screen_area_free(ScrArea *sa)
BLI_freelistN(&sa->actionzones);
}
-/* don't free screen itself */
+/** Free (or release) any data used by this screen (does not free the screen itself). */
void BKE_screen_free(bScreen *sc)
{
ScrArea *sa, *san;
ARegion *ar;
+
+ /* No animdata here. */
for (ar = sc->regionbase.first; ar; ar = ar->next)
BKE_area_region_free(NULL, ar);
diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c
index 3de4a426973..ce7c520438a 100644
--- a/source/blender/blenkernel/intern/seqeffects.c
+++ b/source/blender/blenkernel/intern/seqeffects.c
@@ -123,28 +123,34 @@ static ImBuf *prepare_effect_imbufs(const SeqRenderData *context, ImBuf *ibuf1,
out = IMB_allocImBuf(x, y, 32, IB_rect);
}
- if (ibuf1 && !ibuf1->rect_float && out->rect_float) {
- BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf1, true);
- }
- if (ibuf2 && !ibuf2->rect_float && out->rect_float) {
- BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf2, true);
- }
- if (ibuf3 && !ibuf3->rect_float && out->rect_float) {
- BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf3, true);
- }
+ if (out->rect_float) {
+ if (ibuf1 && !ibuf1->rect_float) {
+ BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf1, true);
+ }
+
+ if (ibuf2 && !ibuf2->rect_float) {
+ BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf2, true);
+ }
+
+ if (ibuf3 && !ibuf3->rect_float) {
+ BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf3, true);
+ }
- if (ibuf1 && !ibuf1->rect && !out->rect_float) {
- IMB_rect_from_float(ibuf1);
- }
- if (ibuf2 && !ibuf2->rect && !out->rect_float) {
- IMB_rect_from_float(ibuf2);
- }
- if (ibuf3 && !ibuf3->rect && !out->rect_float) {
- IMB_rect_from_float(ibuf3);
+ IMB_colormanagement_assign_float_colorspace(out, scene->sequencer_colorspace_settings.name);
}
+ else {
+ if (ibuf1 && !ibuf1->rect) {
+ IMB_rect_from_float(ibuf1);
+ }
- if (out->rect_float)
- IMB_colormanagement_assign_float_colorspace(out, scene->sequencer_colorspace_settings.name);
+ if (ibuf2 && !ibuf2->rect) {
+ IMB_rect_from_float(ibuf2);
+ }
+
+ if (ibuf3 && !ibuf3->rect) {
+ IMB_rect_from_float(ibuf3);
+ }
+ }
/* If effect only affecting a single channel, forward input's metadata to the output. */
if (ibuf1 != NULL && ibuf1 == ibuf2 && ibuf2 == ibuf3) {
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index c82f3a3af23..65d751a8a72 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -1308,41 +1308,40 @@ StripElem *BKE_sequencer_give_stripelem(Sequence *seq, int cfra)
static int evaluate_seq_frame_gen(Sequence **seq_arr, ListBase *seqbase, int cfra, int chanshown)
{
- Sequence *seq;
- Sequence *effect_inputs[MAXSEQ + 1];
- int i, totseq = 0, num_effect_inputs = 0;
+ /* Use arbitrary sized linked list, the size could be over MAXSEQ. */
+ LinkNodePair effect_inputs = {NULL, NULL};
+ int totseq = 0;
memset(seq_arr, 0, sizeof(Sequence *) * (MAXSEQ + 1));
- seq = seqbase->first;
- while (seq) {
- if (seq->startdisp <= cfra && seq->enddisp > cfra) {
+ for (Sequence *seq = seqbase->first; seq; seq = seq->next) {
+ if ((seq->startdisp <= cfra) && (seq->enddisp > cfra)) {
if ((seq->type & SEQ_TYPE_EFFECT) && !(seq->flag & SEQ_MUTE)) {
+
if (seq->seq1) {
- effect_inputs[num_effect_inputs++] = seq->seq1;
+ BLI_linklist_append_alloca(&effect_inputs, seq->seq1);
}
if (seq->seq2) {
- effect_inputs[num_effect_inputs++] = seq->seq2;
+ BLI_linklist_append_alloca(&effect_inputs, seq->seq2);
}
if (seq->seq3) {
- effect_inputs[num_effect_inputs++] = seq->seq3;
+ BLI_linklist_append_alloca(&effect_inputs, seq->seq3);
}
}
seq_arr[seq->machine] = seq;
totseq++;
}
- seq = seq->next;
}
/* Drop strips which are used for effect inputs, we don't want
* them to blend into render stack in any other way than effect
* string rendering.
*/
- for (i = 0; i < num_effect_inputs; i++) {
- seq = effect_inputs[i];
+ for (LinkNode *seq_item = effect_inputs.list; seq_item; seq_item = seq_item->next) {
+ Sequence *seq = seq_item->link;
/* It's possible that effetc strip would be placed to the same
* 'machine' as it's inputs. We don't want to clear such strips
* from the stack.
@@ -1657,6 +1656,9 @@ static bool seq_proxy_get_fname(Editing *ed, Sequence *seq, int cfra, int render
else if ((proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR) && (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE)) {
BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
}
+ else if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) {
+ BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
+ }
else if (sanim && sanim->anim && (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR)) {
char fname[FILE_MAXFILE];
BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
@@ -1676,13 +1678,21 @@ static bool seq_proxy_get_fname(Editing *ed, Sequence *seq, int cfra, int render
if (view_id > 0)
BLI_snprintf(suffix, sizeof(suffix), "_%d", view_id);
- if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE && sanim && sanim->anim &&
+ if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE &&
ed->proxy_storage != SEQ_EDIT_PROXY_DIR_STORAGE)
{
- BLI_join_dirfile(name, PROXY_MAXFILE,
- dir, proxy->file);
- BLI_path_abs(name, G.main->name);
- BLI_snprintf(name, PROXY_MAXFILE, "%s_%s", name, suffix);
+ char fname[FILE_MAXFILE];
+ BLI_join_dirfile(fname, PROXY_MAXFILE, dir, proxy->file);
+ BLI_path_abs(fname, G.main->name);
+ if (suffix[0] != '\0') {
+ /* TODO(sergey): This will actually append suffix after extension
+ * which is weird but how was originally coded in multiview branch.
+ */
+ BLI_snprintf(name, PROXY_MAXFILE, "%s_%s", fname, suffix);
+ }
+ else {
+ BLI_strncpy(name, fname, PROXY_MAXFILE);
+ }
return true;
}
@@ -1826,8 +1836,10 @@ static void seq_proxy_build_frame(
IMB_freeImBuf(ibuf);
}
-/* returns whether the file this context would read from even exist, if not, don't create the context
-*/
+/**
+ * Returns whether the file this context would read from even exist,
+ * if not, don't create the context
+ */
static bool seq_proxy_multiview_context_invalid(Sequence *seq, Scene *scene, const int view_id)
{
if ((scene->r.scemode & R_MULTIVIEW) == 0)
@@ -1862,8 +1874,9 @@ static bool seq_proxy_multiview_context_invalid(Sequence *seq, Scene *scene, con
return false;
}
-/** This returns the maximum possible number of required contexts
-*/
+/**
+ * This returns the maximum possible number of required contexts
+ */
static int seq_proxy_context_count(Sequence *seq, Scene *scene)
{
int num_views = 1;
@@ -3092,7 +3105,7 @@ static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr
BKE_maskrasterize_handle_init(mr_handle, mask_temp, context->rectx, context->recty, true, true, true);
- BKE_mask_free_nolib(mask_temp);
+ BKE_mask_free(mask_temp);
MEM_freeN(mask_temp);
BKE_maskrasterize_buffer(mr_handle, context->rectx, context->recty, maskbuf);
@@ -3434,7 +3447,13 @@ static ImBuf *do_render_strip_uncached(
state->scene_parents = &scene_parent;
/* end check */
- ibuf = do_render_strip_seqbase(context, state, seq, nr, use_preprocess);
+ /* Use the Scene Seq's scene for the context when rendering the scene's sequences
+ * (necessary for Multicam Selector among others).
+ */
+ SeqRenderData local_context = *context;
+ local_context.scene = seq->scene;
+
+ ibuf = do_render_strip_seqbase(&local_context, state, seq, nr, use_preprocess);
/* step back in the list */
state->scene_parents = state->scene_parents->next;
@@ -3556,7 +3575,7 @@ static ImBuf *seq_render_strip(
if (ibuf == NULL) {
/* MOVIECLIPs have their own proxy management */
- if (ibuf == NULL && seq->type != SEQ_TYPE_MOVIECLIP) {
+ if (seq->type != SEQ_TYPE_MOVIECLIP) {
ibuf = seq_proxy_fetch(context, seq, cfra);
is_proxy_image = (ibuf != NULL);
}
@@ -5154,7 +5173,7 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad
info = AUD_getInfo(sound->playback_handle);
if (info.specs.channels == AUD_CHANNELS_INVALID) {
- BKE_sound_delete(bmain, sound);
+ BKE_libblock_free(bmain, sound);
#if 0
if (op)
BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
@@ -5593,3 +5612,31 @@ int BKE_sequencer_find_next_prev_edit(
return best_frame;
}
+
+static void sequencer_all_free_anim_ibufs(ListBase *seqbase, int cfra)
+{
+ for (Sequence *seq = seqbase->first; seq != NULL; seq = seq->next) {
+ if (seq->enddisp < cfra || seq->startdisp > cfra) {
+ BKE_sequence_free_anim(seq);
+ }
+ if (seq->type == SEQ_TYPE_META) {
+ sequencer_all_free_anim_ibufs(&seq->seqbase, cfra);
+ }
+ }
+}
+
+void BKE_sequencer_all_free_anim_ibufs(int cfra)
+{
+ BKE_sequencer_cache_cleanup();
+ for (Scene *scene = G.main->scene.first;
+ scene != NULL;
+ scene = scene->id.next)
+ {
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ if (ed == NULL) {
+ /* Ignore scenes without sequencer. */
+ continue;
+ }
+ sequencer_all_free_anim_ibufs(&ed->seqbase, cfra);
+ }
+}
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index e855f6faa22..7094d5a3547 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -44,6 +44,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLI_task.h"
#include "BKE_shrinkwrap.h"
#include "BKE_DerivedMesh.h"
@@ -58,7 +59,7 @@
/* for timing... */
#if 0
-# include "PIL_time.h"
+# include "PIL_time_utildefines.h"
#else
# define TIMEIT_BENCH(expr, id) (expr)
#endif
@@ -66,16 +67,88 @@
/* Util macros */
#define OUT_OF_MEMORY() ((void)printf("Shrinkwrap: Out of memory\n"))
+typedef struct ShrinkwrapCalcCBData {
+ ShrinkwrapCalcData *calc;
+
+ void *treeData;
+ void *auxData;
+ BVHTree *targ_tree;
+ BVHTree *aux_tree;
+ void *targ_callback;
+ void *aux_callback;
+
+ float *proj_axis;
+ SpaceTransform *local2aux;
+} ShrinkwrapCalcCBData;
+
/*
* Shrinkwrap to the nearest vertex
*
* it builds a kdtree of vertexs we can attach to and then
* for each vertex performs a nearest vertex search on the tree
*/
-static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
+static void shrinkwrap_calc_nearest_vertex_cb_ex(
+ void *userdata, void *userdata_chunk, const int i, const int UNUSED(threadid))
{
- int i;
+ ShrinkwrapCalcCBData *data = userdata;
+
+ ShrinkwrapCalcData *calc = data->calc;
+ BVHTreeFromMesh *treeData = data->treeData;
+ BVHTreeNearest *nearest = userdata_chunk;
+
+ float *co = calc->vertexCos[i];
+ float tmp_co[3];
+ float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);
+
+ if (calc->invert_vgroup) {
+ weight = 1.0f - weight;
+ }
+
+ if (weight == 0.0f) {
+ return;
+ }
+
+ /* Convert the vertex to tree coordinates */
+ if (calc->vert) {
+ copy_v3_v3(tmp_co, calc->vert[i].co);
+ }
+ else {
+ copy_v3_v3(tmp_co, co);
+ }
+ BLI_space_transform_apply(&calc->local2target, tmp_co);
+
+ /* Use local proximity heuristics (to reduce the nearest search)
+ *
+ * If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex
+ * so we can initiate the "nearest.dist" with the expected value to that last hit.
+ * This will lead in pruning of the search tree. */
+ if (nearest->index != -1)
+ nearest->dist_sq = len_squared_v3v3(tmp_co, nearest->co);
+ else
+ nearest->dist_sq = FLT_MAX;
+
+ BLI_bvhtree_find_nearest(treeData->tree, tmp_co, nearest, treeData->nearest_callback, treeData);
+
+
+ /* Found the nearest vertex */
+ if (nearest->index != -1) {
+ /* Adjusting the vertex weight,
+ * so that after interpolating it keeps a certain distance from the nearest position */
+ if (nearest->dist_sq > FLT_EPSILON) {
+ const float dist = sqrtf(nearest->dist_sq);
+ weight *= (dist - calc->keepDist) / dist;
+ }
+
+ /* Convert the coordinates back to mesh coordinates */
+ copy_v3_v3(tmp_co, nearest->co);
+ BLI_space_transform_invert(&calc->local2target, tmp_co);
+
+ interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */
+ }
+}
+static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
+{
BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh;
BVHTreeNearest nearest = NULL_BVHTreeNearest;
@@ -89,61 +162,11 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
/* Setup nearest */
nearest.index = -1;
nearest.dist_sq = FLT_MAX;
-#ifndef __APPLE__
-#pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(treeData, calc) schedule(static) if (calc->numVerts > BKE_MESH_OMP_LIMIT)
-#endif
- for (i = 0; i < calc->numVerts; ++i) {
- float *co = calc->vertexCos[i];
- float tmp_co[3];
- float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);
-
- if (calc->invert_vgroup) {
- weight = 1.0f - weight;
- }
-
- if (weight == 0.0f) {
- continue;
- }
-
-
- /* Convert the vertex to tree coordinates */
- if (calc->vert) {
- copy_v3_v3(tmp_co, calc->vert[i].co);
- }
- else {
- copy_v3_v3(tmp_co, co);
- }
- BLI_space_transform_apply(&calc->local2target, tmp_co);
-
- /* Use local proximity heuristics (to reduce the nearest search)
- *
- * If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex
- * so we can initiate the "nearest.dist" with the expected value to that last hit.
- * This will lead in pruning of the search tree. */
- if (nearest.index != -1)
- nearest.dist_sq = len_squared_v3v3(tmp_co, nearest.co);
- else
- nearest.dist_sq = FLT_MAX;
-
- BLI_bvhtree_find_nearest(treeData.tree, tmp_co, &nearest, treeData.nearest_callback, &treeData);
-
-
- /* Found the nearest vertex */
- if (nearest.index != -1) {
- /* Adjusting the vertex weight,
- * so that after interpolating it keeps a certain distance from the nearest position */
- if (nearest.dist_sq > FLT_EPSILON) {
- const float dist = sqrtf(nearest.dist_sq);
- weight *= (dist - calc->keepDist) / dist;
- }
-
- /* Convert the coordinates back to mesh coordinates */
- copy_v3_v3(tmp_co, nearest.co);
- BLI_space_transform_invert(&calc->local2target, tmp_co);
- interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */
- }
- }
+ ShrinkwrapCalcCBData data = {.calc = calc, .treeData = &treeData};
+ BLI_task_parallel_range_ex(
+ 0, calc->numVerts, &data, &nearest, sizeof(nearest), shrinkwrap_calc_nearest_vertex_cb_ex,
+ calc->numVerts > BKE_MESH_OMP_LIMIT, false);
free_bvhtree_from_mesh(&treeData);
}
@@ -230,13 +253,109 @@ bool BKE_shrinkwrap_project_normal(
return false;
}
+static void shrinkwrap_calc_normal_projection_cb_ex(
+ void *userdata, void *userdata_chunk, const int i, const int UNUSED(threadid))
+{
+ ShrinkwrapCalcCBData *data = userdata;
+
+ ShrinkwrapCalcData *calc = data->calc;
+ void *treeData = data->treeData;
+ void *auxData = data->auxData;
+ BVHTree *targ_tree = data->targ_tree;
+ BVHTree *aux_tree = data->aux_tree;
+ void *targ_callback = data->targ_callback;
+ void *aux_callback = data->aux_callback;
+
+ float *proj_axis = data->proj_axis;
+ SpaceTransform *local2aux = data->local2aux;
+
+ BVHTreeRayHit *hit = userdata_chunk;
+
+ const float proj_limit_squared = calc->smd->projLimit * calc->smd->projLimit;
+ float *co = calc->vertexCos[i];
+ float tmp_co[3], tmp_no[3];
+ float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);
+
+ if (calc->invert_vgroup) {
+ weight = 1.0f - weight;
+ }
+
+ if (weight == 0.0f) {
+ return;
+ }
+
+ if (calc->vert) {
+ /* calc->vert contains verts from derivedMesh */
+ /* this coordinated are deformed by vertexCos only for normal projection (to get correct normals) */
+ /* for other cases calc->varts contains undeformed coordinates and vertexCos should be used */
+ if (calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) {
+ copy_v3_v3(tmp_co, calc->vert[i].co);
+ normal_short_to_float_v3(tmp_no, calc->vert[i].no);
+ }
+ else {
+ copy_v3_v3(tmp_co, co);
+ copy_v3_v3(tmp_no, proj_axis);
+ }
+ }
+ else {
+ copy_v3_v3(tmp_co, co);
+ copy_v3_v3(tmp_no, proj_axis);
+ }
+
+
+ hit->index = -1;
+ hit->dist = BVH_RAYCAST_DIST_MAX; /* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */
+
+ /* Project over positive direction of axis */
+ if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR) {
+ if (aux_tree) {
+ BKE_shrinkwrap_project_normal(
+ 0, tmp_co, tmp_no,
+ local2aux, aux_tree, hit,
+ aux_callback, auxData);
+ }
+
+ BKE_shrinkwrap_project_normal(
+ calc->smd->shrinkOpts, tmp_co, tmp_no,
+ &calc->local2target, targ_tree, hit,
+ targ_callback, treeData);
+ }
+
+ /* Project over negative direction of axis */
+ if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR) {
+ float inv_no[3];
+ negate_v3_v3(inv_no, tmp_no);
+
+ if (aux_tree) {
+ BKE_shrinkwrap_project_normal(
+ 0, tmp_co, inv_no,
+ local2aux, aux_tree, hit,
+ aux_callback, auxData);
+ }
+
+ BKE_shrinkwrap_project_normal(
+ calc->smd->shrinkOpts, tmp_co, inv_no,
+ &calc->local2target, targ_tree, hit,
+ targ_callback, treeData);
+ }
+
+ /* don't set the initial dist (which is more efficient),
+ * because its calculated in the targets space, we want the dist in our own space */
+ if (proj_limit_squared != 0.0f) {
+ if (len_squared_v3v3(hit->co, co) > proj_limit_squared) {
+ hit->index = -1;
+ }
+ }
+
+ if (hit->index != -1) {
+ madd_v3_v3v3fl(hit->co, hit->co, tmp_no, calc->keepDist);
+ interp_v3_v3v3(co, co, hit->co, weight);
+ }
+}
static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for_render)
{
- int i;
-
/* Options about projection direction */
- const float proj_limit_squared = calc->smd->projLimit * calc->smd->projLimit;
float proj_axis[3] = {0.0f, 0.0f, 0.0f};
/* Raycast and tree stuff */
@@ -286,139 +405,80 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
/* use editmesh to avoid array allocation */
BMEditMesh *emtarget = NULL, *emaux = NULL;
- BVHTreeFromEditMesh emtreedata_stack, emauxdata_stack;
- BVHTreeFromMesh dmtreedata_stack, dmauxdata_stack;
+ union {
+ BVHTreeFromEditMesh emtreedata;
+ BVHTreeFromMesh dmtreedata;
+ } treedata_stack, auxdata_stack;
+
BVHTree *targ_tree;
void *targ_callback;
if (calc->smd->target && calc->target->type == DM_TYPE_EDITBMESH) {
emtarget = BKE_editmesh_from_object(calc->smd->target);
- if ((targ_tree = bvhtree_from_editmesh_looptri(&emtreedata_stack, emtarget, 0.0, 4, 6))) {
- targ_callback = emtreedata_stack.raycast_callback;
- treeData = &emtreedata_stack;
+ if ((targ_tree = bvhtree_from_editmesh_looptri(
+ &treedata_stack.emtreedata, emtarget, 0.0, 4, 6, &calc->target->bvhCache)))
+ {
+ targ_callback = treedata_stack.emtreedata.raycast_callback;
+ treeData = &treedata_stack.emtreedata;
}
}
else {
- if ((targ_tree = bvhtree_from_mesh_looptri(&dmtreedata_stack, calc->target, 0.0, 4, 6))) {
- targ_callback = dmtreedata_stack.raycast_callback;
- treeData = &dmtreedata_stack;
+ if ((targ_tree = bvhtree_from_mesh_looptri(
+ &treedata_stack.dmtreedata, calc->target, 0.0, 4, 6)))
+ {
+ targ_callback = treedata_stack.dmtreedata.raycast_callback;
+ treeData = &treedata_stack.dmtreedata;
}
}
if (targ_tree) {
BVHTree *aux_tree = NULL;
- void *aux_callback;
+ void *aux_callback = NULL;
if (auxMesh != NULL) {
/* use editmesh to avoid array allocation */
if (calc->smd->auxTarget && auxMesh->type == DM_TYPE_EDITBMESH) {
emaux = BKE_editmesh_from_object(calc->smd->auxTarget);
- if ((aux_tree = bvhtree_from_editmesh_looptri(&emauxdata_stack, emaux, 0.0, 4, 6)) != NULL) {
- aux_callback = emauxdata_stack.raycast_callback;
- auxData = &emauxdata_stack;
+ if ((aux_tree = bvhtree_from_editmesh_looptri(
+ &auxdata_stack.emtreedata, emaux, 0.0, 4, 6, &auxMesh->bvhCache)))
+ {
+ aux_callback = auxdata_stack.emtreedata.raycast_callback;
+ auxData = &auxdata_stack.emtreedata;
}
}
else {
- if ((aux_tree = bvhtree_from_mesh_looptri(&dmauxdata_stack, calc->target, 0.0, 4, 6)) != NULL) {
- aux_callback = dmauxdata_stack.raycast_callback;
- auxData = &dmauxdata_stack;
+ if ((aux_tree = bvhtree_from_mesh_looptri(&auxdata_stack.dmtreedata, auxMesh, 0.0, 4, 6)) != NULL) {
+ aux_callback = auxdata_stack.dmtreedata.raycast_callback;
+ auxData = &auxdata_stack.dmtreedata;
}
}
}
/* After sucessufuly build the trees, start projection vertexs */
-
-#ifndef __APPLE__
-#pragma omp parallel for private(i, hit) schedule(static) if (calc->numVerts > BKE_MESH_OMP_LIMIT)
-#endif
- for (i = 0; i < calc->numVerts; ++i) {
- float *co = calc->vertexCos[i];
- float tmp_co[3], tmp_no[3];
- float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);
-
- if (calc->invert_vgroup) {
- weight = 1.0f - weight;
- }
-
- if (weight == 0.0f) {
- continue;
- }
-
- if (calc->vert) {
- /* calc->vert contains verts from derivedMesh */
- /* this coordinated are deformed by vertexCos only for normal projection (to get correct normals) */
- /* for other cases calc->varts contains undeformed coordinates and vertexCos should be used */
- if (calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) {
- copy_v3_v3(tmp_co, calc->vert[i].co);
- normal_short_to_float_v3(tmp_no, calc->vert[i].no);
- }
- else {
- copy_v3_v3(tmp_co, co);
- copy_v3_v3(tmp_no, proj_axis);
- }
- }
- else {
- copy_v3_v3(tmp_co, co);
- copy_v3_v3(tmp_no, proj_axis);
- }
-
-
- hit.index = -1;
- hit.dist = BVH_RAYCAST_DIST_MAX; /* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */
-
- /* Project over positive direction of axis */
- if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR) {
-
- if (aux_tree) {
- BKE_shrinkwrap_project_normal(
- 0, tmp_co, tmp_no,
- &local2aux, aux_tree, &hit,
- aux_callback, auxData);
- }
-
- BKE_shrinkwrap_project_normal(
- calc->smd->shrinkOpts, tmp_co, tmp_no,
- &calc->local2target, targ_tree, &hit,
- targ_callback, treeData);
- }
-
- /* Project over negative direction of axis */
- if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR) {
- float inv_no[3];
- negate_v3_v3(inv_no, tmp_no);
-
- if (aux_tree) {
- BKE_shrinkwrap_project_normal(
- 0, tmp_co, inv_no,
- &local2aux, aux_tree, &hit,
- aux_callback, auxData);
- }
-
- BKE_shrinkwrap_project_normal(
- calc->smd->shrinkOpts, tmp_co, inv_no,
- &calc->local2target, targ_tree, &hit,
- targ_callback, treeData);
- }
-
- /* don't set the initial dist (which is more efficient),
- * because its calculated in the targets space, we want the dist in our own space */
- if (proj_limit_squared != 0.0f) {
- if (len_squared_v3v3(hit.co, co) > proj_limit_squared) {
- hit.index = -1;
- }
- }
-
- if (hit.index != -1) {
- madd_v3_v3v3fl(hit.co, hit.co, tmp_no, calc->keepDist);
- interp_v3_v3v3(co, co, hit.co, weight);
- }
- }
+ ShrinkwrapCalcCBData data = {
+ .calc = calc,
+ .treeData = treeData, .targ_tree = targ_tree, .targ_callback = targ_callback,
+ .auxData = auxData, .aux_tree = aux_tree, .aux_callback = aux_callback,
+ .proj_axis = proj_axis, .local2aux = &local2aux,
+ };
+ BLI_task_parallel_range_ex(
+ 0, calc->numVerts, &data, &hit, sizeof(hit), shrinkwrap_calc_normal_projection_cb_ex,
+ calc->numVerts > BKE_MESH_OMP_LIMIT, false);
}
/* free data structures */
if (treeData) {
- if (emtarget) free_bvhtree_from_editmesh(treeData);
- else free_bvhtree_from_mesh(treeData);
+ if (emtarget) {
+ free_bvhtree_from_editmesh(treeData);
+ }
+ else {
+ free_bvhtree_from_mesh(treeData);
+ }
}
+
if (auxData) {
- if (emaux) free_bvhtree_from_editmesh(auxData);
- else free_bvhtree_from_mesh(auxData);
+ if (emaux) {
+ free_bvhtree_from_editmesh(auxData);
+ }
+ else {
+ free_bvhtree_from_mesh(auxData);
+ }
}
}
@@ -428,10 +488,75 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
* it builds a BVHTree from the target mesh and then performs a
* NN matches for each vertex
*/
-static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
+static void shrinkwrap_calc_nearest_surface_point_cb_ex(
+ void *userdata, void *userdata_chunk, const int i, const int UNUSED(threadid))
{
- int i;
+ ShrinkwrapCalcCBData *data = userdata;
+
+ ShrinkwrapCalcData *calc = data->calc;
+ BVHTreeFromMesh *treeData = data->treeData;
+ BVHTreeNearest *nearest = userdata_chunk;
+ float *co = calc->vertexCos[i];
+ float tmp_co[3];
+ float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);
+
+ if (calc->invert_vgroup) {
+ weight = 1.0f - weight;
+ }
+
+ if (weight == 0.0f) {
+ return;
+ }
+
+ /* Convert the vertex to tree coordinates */
+ if (calc->vert) {
+ copy_v3_v3(tmp_co, calc->vert[i].co);
+ }
+ else {
+ copy_v3_v3(tmp_co, co);
+ }
+ BLI_space_transform_apply(&calc->local2target, tmp_co);
+
+ /* Use local proximity heuristics (to reduce the nearest search)
+ *
+ * If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex
+ * so we can initiate the "nearest.dist" with the expected value to that last hit.
+ * This will lead in pruning of the search tree. */
+ if (nearest->index != -1)
+ nearest->dist_sq = len_squared_v3v3(tmp_co, nearest->co);
+ else
+ nearest->dist_sq = FLT_MAX;
+
+ BLI_bvhtree_find_nearest(treeData->tree, tmp_co, nearest, treeData->nearest_callback, treeData);
+
+ /* Found the nearest vertex */
+ if (nearest->index != -1) {
+ if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE) {
+ /* Make the vertex stay on the front side of the face */
+ madd_v3_v3v3fl(tmp_co, nearest->co, nearest->no, calc->keepDist);
+ }
+ else {
+ /* Adjusting the vertex weight,
+ * so that after interpolating it keeps a certain distance from the nearest position */
+ const float dist = sasqrt(nearest->dist_sq);
+ if (dist > FLT_EPSILON) {
+ /* linear interpolation */
+ interp_v3_v3v3(tmp_co, tmp_co, nearest->co, (dist - calc->keepDist) / dist);
+ }
+ else {
+ copy_v3_v3(tmp_co, nearest->co);
+ }
+ }
+
+ /* Convert the coordinates back to mesh coordinates */
+ BLI_space_transform_invert(&calc->local2target, tmp_co);
+ interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */
+ }
+}
+
+static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
+{
BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh;
BVHTreeNearest nearest = NULL_BVHTreeNearest;
@@ -446,67 +571,11 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
nearest.index = -1;
nearest.dist_sq = FLT_MAX;
-
/* Find the nearest vertex */
-#ifndef __APPLE__
-#pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(calc, treeData) schedule(static) if (calc->numVerts > BKE_MESH_OMP_LIMIT)
-#endif
- for (i = 0; i < calc->numVerts; ++i) {
- float *co = calc->vertexCos[i];
- float tmp_co[3];
- float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);
-
- if (calc->invert_vgroup) {
- weight = 1.0f - weight;
- }
-
- if (weight == 0.0f) continue;
-
- /* Convert the vertex to tree coordinates */
- if (calc->vert) {
- copy_v3_v3(tmp_co, calc->vert[i].co);
- }
- else {
- copy_v3_v3(tmp_co, co);
- }
- BLI_space_transform_apply(&calc->local2target, tmp_co);
-
- /* Use local proximity heuristics (to reduce the nearest search)
- *
- * If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex
- * so we can initiate the "nearest.dist" with the expected value to that last hit.
- * This will lead in pruning of the search tree. */
- if (nearest.index != -1)
- nearest.dist_sq = len_squared_v3v3(tmp_co, nearest.co);
- else
- nearest.dist_sq = FLT_MAX;
-
- BLI_bvhtree_find_nearest(treeData.tree, tmp_co, &nearest, treeData.nearest_callback, &treeData);
-
- /* Found the nearest vertex */
- if (nearest.index != -1) {
- if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE) {
- /* Make the vertex stay on the front side of the face */
- madd_v3_v3v3fl(tmp_co, nearest.co, nearest.no, calc->keepDist);
- }
- else {
- /* Adjusting the vertex weight,
- * so that after interpolating it keeps a certain distance from the nearest position */
- const float dist = sasqrt(nearest.dist_sq);
- if (dist > FLT_EPSILON) {
- /* linear interpolation */
- interp_v3_v3v3(tmp_co, tmp_co, nearest.co, (dist - calc->keepDist) / dist);
- }
- else {
- copy_v3_v3(tmp_co, nearest.co);
- }
- }
-
- /* Convert the coordinates back to mesh coordinates */
- BLI_space_transform_invert(&calc->local2target, tmp_co);
- interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */
- }
- }
+ ShrinkwrapCalcCBData data = {.calc = calc, .treeData = &treeData};
+ BLI_task_parallel_range_ex(
+ 0, calc->numVerts, &data, &nearest, sizeof(nearest), shrinkwrap_calc_nearest_surface_point_cb_ex,
+ calc->numVerts > BKE_MESH_OMP_LIMIT, false);
free_bvhtree_from_mesh(&treeData);
}
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index d20994a2e39..05540f51588 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -536,6 +536,14 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
#endif
smd->domain->data_depth = 0;
smd->domain->cache_file_format = PTCACHE_FILE_PTCACHE;
+
+ smd->domain->display_thickness = 1.0f;
+ smd->domain->slice_method = MOD_SMOKE_SLICE_VIEW_ALIGNED;
+ smd->domain->axis_slice_method = AXIS_SLICE_FULL;
+ smd->domain->slice_per_voxel = 5.0f;
+ smd->domain->slice_depth = 0.5f;
+ smd->domain->slice_axis = 0;
+ smd->domain->vector_scale = 1.0f;
}
else if (smd->type & MOD_SMOKE_TYPE_FLOW)
{
@@ -629,6 +637,15 @@ void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData
tsmd->domain->openvdb_comp = smd->domain->openvdb_comp;
tsmd->domain->data_depth = smd->domain->data_depth;
tsmd->domain->cache_file_format = smd->domain->cache_file_format;
+
+ tsmd->domain->slice_method = smd->domain->slice_method;
+ tsmd->domain->axis_slice_method = smd->domain->axis_slice_method;
+ tsmd->domain->slice_per_voxel = smd->domain->slice_per_voxel;
+ tsmd->domain->slice_depth = smd->domain->slice_depth;
+ tsmd->domain->slice_axis = smd->domain->slice_axis;
+ tsmd->domain->draw_velocity = smd->domain->draw_velocity;
+ tsmd->domain->vector_draw_type = smd->domain->vector_draw_type;
+ tsmd->domain->vector_scale = smd->domain->vector_scale;
}
else if (tsmd->flow) {
tsmd->flow->psys = smd->flow->psys;
@@ -707,6 +724,7 @@ typedef struct ObstaclesFromDMData {
bool has_velocity;
float *vert_vel;
float *velocityX, *velocityY, *velocityZ;
+ int *num_obstacles;
} ObstaclesFromDMData;
static void obstacles_from_derivedmesh_task_cb(void *userdata, const int z)
@@ -755,8 +773,10 @@ static void obstacles_from_derivedmesh_task_cb(void *userdata, const int z)
/* tag obstacle cells */
data->obstacle_map[index] = 1;
- if (data->has_velocity)
+ if (data->has_velocity) {
data->obstacle_map[index] |= 8;
+ data->num_obstacles[index]++;
+ }
}
}
}
@@ -764,7 +784,7 @@ static void obstacles_from_derivedmesh_task_cb(void *userdata, const int z)
static void obstacles_from_derivedmesh(
Object *coll_ob, SmokeDomainSettings *sds, SmokeCollSettings *scs,
- unsigned char *obstacle_map, float *velocityX, float *velocityY, float *velocityZ, float dt)
+ unsigned char *obstacle_map, float *velocityX, float *velocityY, float *velocityZ, int *num_obstacles, float dt)
{
if (!scs->dm) return;
{
@@ -835,7 +855,8 @@ static void obstacles_from_derivedmesh(
.sds = sds, .mvert = mvert, .mloop = mloop, .looptri = looptri,
.tree = &treeData, .obstacle_map = obstacle_map,
.has_velocity = has_velocity, .vert_vel = vert_vel,
- .velocityX = velocityX, .velocityY = velocityY, .velocityZ = velocityZ
+ .velocityX = velocityX, .velocityY = velocityY, .velocityZ = velocityZ,
+ .num_obstacles = num_obstacles
};
BLI_task_parallel_range(
sds->res_min[2], sds->res_max[2], &data, obstacles_from_derivedmesh_task_cb, true);
@@ -871,6 +892,8 @@ static void update_obstacles(Scene *scene, Object *ob, SmokeDomainSettings *sds,
float *b = smoke_get_color_b(sds->fluid);
unsigned int z;
+ int *num_obstacles = MEM_callocN(sizeof(int) * sds->res[0] * sds->res[1] * sds->res[2], "smoke_num_obstacles");
+
smoke_get_ob_velocity(sds->fluid, &velx, &vely, &velz);
// TODO: delete old obstacle flags
@@ -900,7 +923,7 @@ static void update_obstacles(Scene *scene, Object *ob, SmokeDomainSettings *sds,
if ((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll)
{
SmokeCollSettings *scs = smd2->coll;
- obstacles_from_derivedmesh(collob, sds, scs, obstacles, velx, vely, velz, dt);
+ obstacles_from_derivedmesh(collob, sds, scs, obstacles, velx, vely, velz, num_obstacles, dt);
}
}
@@ -926,7 +949,15 @@ static void update_obstacles(Scene *scene, Object *ob, SmokeDomainSettings *sds,
b[z] = 0;
}
}
+ /* average velocities from multiple obstacles in one cell */
+ if (num_obstacles[z]) {
+ velx[z] /= num_obstacles[z];
+ vely[z] /= num_obstacles[z];
+ velz[z] /= num_obstacles[z];
+ }
}
+
+ MEM_freeN(num_obstacles);
}
/**********************************************************
@@ -2723,19 +2754,18 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object *
return;
}
+ /* only calculate something when we advanced a single frame */
+ /* don't simulate if viewing start frame, but scene frame is not real start frame */
+ bool can_simulate = (framenr == (int)smd->time + 1) && (framenr == scene->r.cfra);
+
/* try to read from cache */
- if (BKE_ptcache_read(&pid, (float)framenr) == PTCACHE_READ_EXACT) {
+ if (BKE_ptcache_read(&pid, (float)framenr, can_simulate) == PTCACHE_READ_EXACT) {
BKE_ptcache_validate(cache, framenr);
smd->time = framenr;
return;
}
- /* only calculate something when we advanced a single frame */
- if (framenr != (int)smd->time + 1)
- return;
-
- /* don't simulate if viewing start frame, but scene frame is not real start frame */
- if (framenr != scene->r.cfra)
+ if (!can_simulate)
return;
#ifdef DEBUG_TIME
@@ -2772,8 +2802,7 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object *
// create shadows before writing cache so they get stored
smoke_calc_transparency(sds, scene);
- if (sds->wt)
- {
+ if (sds->wt && sds->total_cells > 1) {
smoke_turbulence_step(sds->wt, sds->fluid);
}
@@ -3039,9 +3068,15 @@ float smoke_get_velocity_at(struct Object *ob, float position[3], float velocity
int smoke_get_data_flags(SmokeDomainSettings *sds)
{
int flags = 0;
- if (smoke_has_heat(sds->fluid)) flags |= SM_ACTIVE_HEAT;
- if (smoke_has_fuel(sds->fluid)) flags |= SM_ACTIVE_FIRE;
- if (smoke_has_colors(sds->fluid)) flags |= SM_ACTIVE_COLORS;
+
+ if (sds->fluid) {
+ if (smoke_has_heat(sds->fluid))
+ flags |= SM_ACTIVE_HEAT;
+ if (smoke_has_fuel(sds->fluid))
+ flags |= SM_ACTIVE_FIRE;
+ if (smoke_has_colors(sds->fluid))
+ flags |= SM_ACTIVE_COLORS;
+ }
return flags;
}
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index 25a4fdc0cc7..03cf33083da 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -63,6 +63,7 @@ variables on the UI for now
#include "DNA_curve_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_group_types.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -496,59 +497,98 @@ static void ccd_mesh_free(ccd_Mesh *ccdm)
}
}
-static void ccd_build_deflector_hash(Scene *scene, Object *vertexowner, GHash *hash)
+static void ccd_build_deflector_hash_single(GHash *hash, Object *ob)
+{
+ /* only with deflecting set */
+ if (ob->pd && ob->pd->deflect) {
+ void **val_p;
+ if (!BLI_ghash_ensure_p(hash, ob, &val_p)) {
+ ccd_Mesh *ccdmesh = ccd_mesh_make(ob);
+ *val_p = ccdmesh;
+ }
+ }
+}
+
+/**
+ * \note group overrides scene when not NULL.
+ */
+static void ccd_build_deflector_hash(Scene *scene, Group *group, Object *vertexowner, GHash *hash)
{
- Base *base= scene->base.first;
Object *ob;
if (!hash) return;
- while (base) {
- /*Only proceed for mesh object in same layer */
- if (base->object->type==OB_MESH && (base->lay & vertexowner->lay)) {
- ob= base->object;
- if ((vertexowner) && (ob == vertexowner)) {
- /* if vertexowner is given we don't want to check collision with owner object */
- base = base->next;
+
+ if (group) {
+ /* Explicit collision group */
+ for (GroupObject *go = group->gobject.first; go; go = go->next) {
+ ob = go->ob;
+
+ if (ob == vertexowner || ob->type != OB_MESH)
continue;
- }
- /*+++ only with deflecting set */
- if (ob->pd && ob->pd->deflect && BLI_ghash_lookup(hash, ob) == NULL) {
- ccd_Mesh *ccdmesh = ccd_mesh_make(ob);
- BLI_ghash_insert(hash, ob, ccdmesh);
- }/*--- only with deflecting set */
+ ccd_build_deflector_hash_single(hash, ob);
+ }
+ }
+ else {
+ for (Base *base = scene->base.first; base; base = base->next) {
+ /*Only proceed for mesh object in same layer */
+ if (base->object->type == OB_MESH && (base->lay & vertexowner->lay)) {
+ ob= base->object;
+ if ((vertexowner) && (ob == vertexowner)) {
+ /* if vertexowner is given we don't want to check collision with owner object */
+ continue;
+ }
- }/* mesh && layer*/
- base = base->next;
- } /* while (base) */
+ ccd_build_deflector_hash_single(hash, ob);
+ }
+ }
+ }
}
-static void ccd_update_deflector_hash(Scene *scene, Object *vertexowner, GHash *hash)
+static void ccd_update_deflector_hash_single(GHash *hash, Object *ob)
+{
+ if (ob->pd && ob->pd->deflect) {
+ ccd_Mesh *ccdmesh = BLI_ghash_lookup(hash, ob);
+ if (ccdmesh) {
+ ccd_mesh_update(ob, ccdmesh);
+ }
+ }
+}
+
+/**
+ * \note group overrides scene when not NULL.
+ */
+static void ccd_update_deflector_hash(Scene *scene, Group *group, Object *vertexowner, GHash *hash)
{
- Base *base= scene->base.first;
Object *ob;
if ((!hash) || (!vertexowner)) return;
- while (base) {
- /*Only proceed for mesh object in same layer */
- if (base->object->type==OB_MESH && (base->lay & vertexowner->lay)) {
- ob= base->object;
- if (ob == vertexowner) {
- /* if vertexowner is given we don't want to check collision with owner object */
- base = base->next;
+
+ if (group) {
+ /* Explicit collision group */
+ for (GroupObject *go = group->gobject.first; go; go = go->next) {
+ ob = go->ob;
+
+ if (ob == vertexowner || ob->type != OB_MESH)
continue;
- }
- /*+++ only with deflecting set */
- if (ob->pd && ob->pd->deflect) {
- ccd_Mesh *ccdmesh = BLI_ghash_lookup(hash, ob);
- if (ccdmesh)
- ccd_mesh_update(ob, ccdmesh);
- }/*--- only with deflecting set */
+ ccd_update_deflector_hash_single(hash, ob);
+ }
+ }
+ else {
+ for (Base *base = scene->base.first; base; base = base->next) {
+ /*Only proceed for mesh object in same layer */
+ if (base->object->type == OB_MESH && (base->lay & vertexowner->lay)) {
+ ob= base->object;
+ if (ob == vertexowner) {
+ /* if vertexowner is given we don't want to check collision with owner object */
+ continue;
+ }
- }/* mesh && layer*/
- base = base->next;
- } /* while (base) */
+ ccd_update_deflector_hash_single(hash, ob);
+ }
+ }
+ }
}
@@ -934,22 +974,32 @@ static void free_softbody_intern(SoftBody *sb)
/* +++ dependency information functions*/
-static int are_there_deflectors(Scene *scene, unsigned int layer)
+/**
+ * \note group overrides scene when not NULL.
+ */
+static bool are_there_deflectors(Scene *scene, Group *group, unsigned int layer)
{
- Base *base;
-
- for (base = scene->base.first; base; base= base->next) {
- if ( (base->lay & layer) && base->object->pd) {
- if (base->object->pd->deflect)
+ if (group) {
+ for (GroupObject *go = group->gobject.first; go; go = go->next) {
+ if (go->ob->pd && go->ob->pd->deflect)
return 1;
}
}
+ else {
+ for (Base *base = scene->base.first; base; base= base->next) {
+ if ( (base->lay & layer) && base->object->pd) {
+ if (base->object->pd->deflect)
+ return 1;
+ }
+ }
+ }
+
return 0;
}
-static int query_external_colliders(Scene *scene, Object *me)
+static int query_external_colliders(Scene *scene, Group *group, Object *me)
{
- return(are_there_deflectors(scene, me->lay));
+ return(are_there_deflectors(scene, group, me->lay));
}
/* --- dependency information functions*/
@@ -2197,7 +2247,7 @@ static void softbody_calc_forcesEx(Scene *scene, Object *ob, float forcetime, fl
/* gravity = sb->grav * sb_grav_force_scale(ob); */ /* UNUSED */
/* check conditions for various options */
- do_deflector= query_external_colliders(scene, ob);
+ do_deflector= query_external_colliders(scene, sb->collision_group, ob);
/* do_selfcollision=((ob->softflag & OB_SB_EDGES) && (sb->bspring)&& (ob->softflag & OB_SB_SELF)); */ /* UNUSED */
do_springcollision=do_deflector && (ob->softflag & OB_SB_EDGES) &&(ob->softflag & OB_SB_EDGECOLL);
do_aero=((sb->aeroedge)&& (ob->softflag & OB_SB_EDGES));
@@ -2243,7 +2293,7 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
.. keeping G.debug_value==17 0x11 option for old files 'needing' the bug*/
/* rule we never alter free variables :bp->vec bp->pos in here !
- * this will ruin adaptive stepsize AKA heun! (BM)
+ * this will ruin adaptive stepsize AKA heun! (BM)
*/
SoftBody *sb= ob->soft; /* is supposed to be there */
BodyPoint *bp;
@@ -2261,7 +2311,7 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
}
/* check conditions for various options */
- do_deflector= query_external_colliders(scene, ob);
+ do_deflector= query_external_colliders(scene, sb->collision_group, ob);
do_selfcollision=((ob->softflag & OB_SB_EDGES) && (sb->bspring)&& (ob->softflag & OB_SB_SELF));
do_springcollision=do_deflector && (ob->softflag & OB_SB_EDGES) &&(ob->softflag & OB_SB_EDGECOLL);
do_aero=((sb->aeroedge)&& (ob->softflag & OB_SB_EDGES));
@@ -3472,11 +3522,11 @@ static void softbody_step(Scene *scene, Object *ob, SoftBody *sb, float dtime)
*/
if (dtime < 0 || dtime > 10.5f) return;
- ccd_update_deflector_hash(scene, ob, sb->scratch->colliderhash);
+ ccd_update_deflector_hash(scene, sb->collision_group, ob, sb->scratch->colliderhash);
if (sb->scratch->needstobuildcollider) {
- if (query_external_colliders(scene, ob)) {
- ccd_build_deflector_hash(scene, ob, sb->scratch->colliderhash);
+ if (query_external_colliders(scene, sb->collision_group, ob)) {
+ ccd_build_deflector_hash(scene, sb->collision_group, ob, sb->scratch->colliderhash);
}
sb->scratch->needstobuildcollider=0;
}
@@ -3669,9 +3719,12 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i
}
/* try to read from cache */
- cache_result = BKE_ptcache_read(&pid, (float)framenr+scene->r.subframe);
+ bool can_simulate = (framenr == sb->last_frame+1) && !(cache->flag & PTCACHE_BAKED);
+
+ cache_result = BKE_ptcache_read(&pid, (float)framenr+scene->r.subframe, can_simulate);
- if (cache_result == PTCACHE_READ_EXACT || cache_result == PTCACHE_READ_INTERPOLATED) {
+ if (cache_result == PTCACHE_READ_EXACT || cache_result == PTCACHE_READ_INTERPOLATED ||
+ (!can_simulate && cache_result == PTCACHE_READ_OLD)) {
softbody_to_object(ob, vertexCos, numVerts, sb->local);
BKE_ptcache_validate(cache, framenr);
@@ -3692,7 +3745,7 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i
return;
}
- if (framenr!=sb->last_frame+1)
+ if (!can_simulate)
return;
/* if on second frame, write cache for first frame */
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index b016f8a49ed..3132a8e27e7 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -123,8 +123,11 @@ bSound *BKE_sound_new_file_exists(struct Main *bmain, const char *filepath)
return BKE_sound_new_file_exists_ex(bmain, filepath, NULL);
}
+/** Free (or release) any data used by this sound (does not free the sound itself). */
void BKE_sound_free(bSound *sound)
{
+ /* No animdata here. */
+
if (sound->packedfile) {
freePackedFile(sound->packedfile);
sound->packedfile = NULL;
@@ -148,11 +151,15 @@ void BKE_sound_free(bSound *sound)
BLI_spin_end(sound->spinlock);
MEM_freeN(sound->spinlock);
sound->spinlock = NULL;
- }
-
+ }
#endif /* WITH_AUDASPACE */
}
+void BKE_sound_make_local(Main *bmain, bSound *sound, const bool lib_local)
+{
+ BKE_id_make_local_generic(bmain, &sound->id, true, lib_local);
+}
+
#ifdef WITH_AUDASPACE
static const char *force_device = NULL;
@@ -315,15 +322,6 @@ bSound *BKE_sound_new_limiter(struct Main *bmain, bSound *source, float start, f
}
#endif
-void BKE_sound_delete(struct Main *bmain, bSound *sound)
-{
- if (sound) {
- BKE_sound_free(sound);
-
- BKE_libblock_free(bmain, sound);
- }
-}
-
void BKE_sound_cache(bSound *sound)
{
sound->flags |= SOUND_FLAGS_CACHING;
@@ -867,7 +865,7 @@ char **BKE_sound_get_device_names(void)
audio_device_names = AUD_getDeviceNames();
#else
static const char *names[] = {
- "Null", "SDL", "OpenAL", "Jack", NULL
+ "Null", "SDL", "OpenAL", "JACK", NULL
};
audio_device_names = (char **)names;
#endif
diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c
index c452065fbad..ee6886e3fb2 100644
--- a/source/blender/blenkernel/intern/speaker.c
+++ b/source/blender/blenkernel/intern/speaker.c
@@ -34,6 +34,8 @@
#include "BKE_animsys.h"
#include "BKE_global.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_speaker.h"
@@ -66,83 +68,26 @@ void *BKE_speaker_add(Main *bmain, const char *name)
return spk;
}
-Speaker *BKE_speaker_copy(Speaker *spk)
+Speaker *BKE_speaker_copy(Main *bmain, Speaker *spk)
{
Speaker *spkn;
- spkn = BKE_libblock_copy(&spk->id);
+ spkn = BKE_libblock_copy(bmain, &spk->id);
+
if (spkn->sound)
id_us_plus(&spkn->sound->id);
- if (spk->id.lib) {
- BKE_id_lib_local_paths(G.main, spk->id.lib, &spkn->id);
- }
+ BKE_id_copy_ensure_local(bmain, &spk->id, &spkn->id);
return spkn;
}
-static void extern_local_speaker(Speaker *spk)
+void BKE_speaker_make_local(Main *bmain, Speaker *spk, const bool lib_local)
{
- id_lib_extern((ID *)spk->sound);
-}
-
-void BKE_speaker_make_local(Speaker *spk)
-{
- Main *bmain = G.main;
- Object *ob;
- bool is_local = false, is_lib = false;
-
- /* - only lib users: do nothing
- * - only local users: set flag
- * - mixed: make copy
- */
-
- if (spk->id.lib == NULL) return;
- if (spk->id.us == 1) {
- id_clear_lib_data(bmain, &spk->id);
- extern_local_speaker(spk);
- return;
- }
-
- ob = bmain->object.first;
- while (ob) {
- if (ob->data == spk) {
- if (ob->id.lib) is_lib = true;
- else is_local = true;
- }
- ob = ob->id.next;
- }
-
- if (is_local && is_lib == false) {
- id_clear_lib_data(bmain, &spk->id);
- extern_local_speaker(spk);
- }
- else if (is_local && is_lib) {
- Speaker *spk_new = BKE_speaker_copy(spk);
- spk_new->id.us = 0;
-
- /* Remap paths of new ID using old library as base. */
- BKE_id_lib_local_paths(bmain, spk->id.lib, &spk_new->id);
-
- ob = bmain->object.first;
- while (ob) {
- if (ob->data == spk) {
-
- if (ob->id.lib == NULL) {
- ob->data = spk_new;
- id_us_plus(&spk_new->id);
- id_us_min(&spk->id);
- }
- }
- ob = ob->id.next;
- }
- }
+ BKE_id_make_local_generic(bmain, &spk->id, true, lib_local);
}
void BKE_speaker_free(Speaker *spk)
{
- if (spk->sound)
- id_us_min(&spk->sound->id);
-
- BKE_animdata_free((ID *)spk);
+ BKE_animdata_free((ID *)spk, false);
}
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index a84b8352417..6d57c5f09e8 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -794,14 +794,20 @@ static void ss_sync_osd_from_derivedmesh(CCGSubSurf *ss,
static void ss_sync_from_derivedmesh(CCGSubSurf *ss,
DerivedMesh *dm,
float (*vertexCos)[3],
- int use_flat_subdiv)
+ int use_flat_subdiv,
+ bool use_subdiv_uvs)
{
+#ifndef WITH_OPENSUBDIV
+ UNUSED_VARS(use_subdiv_uvs);
+#endif
+
#ifdef WITH_OPENSUBDIV
/* Reset all related descriptors if actual mesh topology changed or if
* other evaluation-related settings changed.
*/
if (!ccgSubSurf_needGrids(ss)) {
/* TODO(sergey): Use vertex coordinates and flat subdiv flag. */
+ ccgSubSurf__sync_subdivUvs(ss, use_subdiv_uvs);
ccgSubSurf_checkTopologyChanged(ss, dm);
ss_sync_osd_from_derivedmesh(ss, dm);
}
@@ -1801,7 +1807,7 @@ static void ccgDM_drawEdges(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEd
#ifdef WITH_OPENSUBDIV
if (ccgdm->useGpuBackend) {
/* TODO(sergey): We currently only support all edges drawing. */
- if (ccgSubSurf_prepareGLMesh(ccgdm->ss, true)) {
+ if (ccgSubSurf_prepareGLMesh(ccgdm->ss, true, -1)) {
ccgSubSurf_drawGLMesh(ccgdm->ss, false, -1, -1);
}
return;
@@ -2619,7 +2625,6 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)
if (BKE_pbvh_has_faces(ccgdm->pbvh)) {
BKE_pbvh_draw(ccgdm->pbvh, partial_redraw_planes, NULL,
setMaterial, false, fast);
- glShadeModel(GL_FLAT);
}
return;
@@ -2639,7 +2644,7 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)
int mat_nr = -1;
bool draw_smooth = false;
int start_draw_patch = -1, num_draw_patches = 0;
- if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, setMaterial != NULL) == false)) {
+ if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, setMaterial != NULL, -1) == false)) {
return;
}
if (setMaterial == NULL) {
@@ -2694,6 +2699,7 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)
num_draw_patches);
}
}
+ glShadeModel(GL_SMOOTH);
return;
}
#endif
@@ -2701,7 +2707,6 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)
GPU_vertex_setup(dm);
GPU_normal_setup(dm);
GPU_triangle_setup(dm);
- glShadeModel(GL_SMOOTH);
for (a = 0; a < dm->drawObject->totmaterial; a++) {
if (!setMaterial || setMaterial(dm->drawObject->materials[a].mat_nr + 1, NULL)) {
GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, dm->drawObject->materials[a].start,
@@ -2751,7 +2756,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
bool draw_smooth = false;
int start_draw_patch = -1, num_draw_patches = 0;
GPU_draw_update_fvar_offset(dm);
- if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, false) == false)) {
+ if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, false, -1) == false)) {
return;
}
for (i = 0; i < num_base_faces; ++i) {
@@ -2800,12 +2805,11 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
num_draw_patches);
}
}
+ glShadeModel(GL_SMOOTH);
return;
}
#endif
- glShadeModel(GL_SMOOTH);
-
CCG_key_top_level(&key, ss);
ccgdm_pbvh_update(ccgdm);
@@ -2816,12 +2820,13 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
int matnr = -1;
int do_draw = 0;
-#define PASSATTRIB(dx, dy, vert) { \
- if (attribs.totorco) \
- index = getFaceIndex(ss, f, S, x + dx, y + dy, edgeSize, gridSize); \
- else \
- index = 0; \
- DM_draw_attrib_vertex(&attribs, a, index, vert, ((a) * 4) + vert); \
+#define PASSATTRIB(dx, dy, vert) { \
+ if (attribs.totorco) \
+ index = getFaceIndex(ss, f, S, x + dx, y + dy, edgeSize, gridSize); \
+ else \
+ index = 0; \
+ DM_draw_attrib_vertex(&attribs, a, index, vert, ((a) * 4) + vert); \
+ DM_draw_attrib_vertex_uniforms(&attribs); \
} (void)0
totpoly = ccgSubSurf_getNumFaces(ss);
@@ -2958,6 +2963,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
}
}
+ glShadeModel(GL_SMOOTH);
#undef PASSATTRIB
}
else {
@@ -2996,6 +3002,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
if (matconv[a].attribs.totorco && matconv[a].attribs.orco.array) {
matconv[a].datatypes[numdata].index = matconv[a].attribs.orco.gl_index;
+ matconv[a].datatypes[numdata].info_index = matconv[a].attribs.orco.gl_info_index;
matconv[a].datatypes[numdata].size = 3;
matconv[a].datatypes[numdata].type = GL_FLOAT;
numdata++;
@@ -3003,6 +3010,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
for (b = 0; b < matconv[a].attribs.tottface; b++) {
if (matconv[a].attribs.tface[b].array) {
matconv[a].datatypes[numdata].index = matconv[a].attribs.tface[b].gl_index;
+ matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tface[b].gl_info_index;
matconv[a].datatypes[numdata].size = 2;
matconv[a].datatypes[numdata].type = GL_FLOAT;
numdata++;
@@ -3011,6 +3019,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
for (b = 0; b < matconv[a].attribs.totmcol; b++) {
if (matconv[a].attribs.mcol[b].array) {
matconv[a].datatypes[numdata].index = matconv[a].attribs.mcol[b].gl_index;
+ matconv[a].datatypes[numdata].info_index = matconv[a].attribs.mcol[b].gl_info_index;
matconv[a].datatypes[numdata].size = 4;
matconv[a].datatypes[numdata].type = GL_UNSIGNED_BYTE;
numdata++;
@@ -3019,6 +3028,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
for (b = 0; b < matconv[a].attribs.tottang; b++) {
if (matconv[a].attribs.tottang && matconv[a].attribs.tang[b].array) {
matconv[a].datatypes[numdata].index = matconv[a].attribs.tang[b].gl_index;
+ matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tang[b].gl_info_index;
matconv[a].datatypes[numdata].size = 4;
matconv[a].datatypes[numdata].type = GL_FLOAT;
numdata++;
@@ -3159,8 +3169,6 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
MEM_freeN(mat_orig_to_new);
MEM_freeN(matconv);
}
-
- glShadeModel(GL_FLAT);
}
static void ccgDM_drawFacesGLSL(DerivedMesh *dm, DMSetMaterial setMaterial)
@@ -3187,24 +3195,63 @@ static void ccgDM_drawMappedFacesMat(DerivedMesh *dm,
#ifdef WITH_OPENSUBDIV
if (ccgdm->useGpuBackend) {
- int new_matnr;
- bool draw_smooth;
+ const int level = ccgSubSurf_getSubdivisionLevels(ss);
+ const int face_side = 1 << level;
+ const int grid_side = 1 << (level - 1);
+ const int face_patches = face_side * face_side;
+ const int grid_patches = grid_side * grid_side;
+ const int num_base_faces = ccgSubSurf_getNumGLMeshBaseFaces(ss);
+ int current_patch = 0;
+ int mat_nr = -1;
+ bool draw_smooth = false;
+ int start_draw_patch = -1, num_draw_patches = 0;
GPU_draw_update_fvar_offset(dm);
- if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true) == false)) {
+ if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, -1) == false)) {
return;
}
- /* TODO(sergey): Single matierial currently. */
- if (faceFlags) {
- draw_smooth = (faceFlags[0].flag & ME_SMOOTH);
- new_matnr = (faceFlags[0].mat_nr + 1);
+ for (i = 0; i < num_base_faces; ++i) {
+ const int num_face_verts = ccgSubSurf_getNumGLMeshBaseFaceVerts(ss, i);
+ const int num_patches = (num_face_verts == 4) ? face_patches
+ : num_face_verts * grid_patches;
+ int new_matnr;
+ bool new_draw_smooth;
+
+ if (faceFlags) {
+ new_draw_smooth = (faceFlags[i].flag & ME_SMOOTH);
+ new_matnr = (faceFlags[i].mat_nr + 1);
+ }
+ else {
+ new_draw_smooth = true;
+ new_matnr = 1;
+ }
+ if (new_draw_smooth != draw_smooth || new_matnr != mat_nr) {
+ if (num_draw_patches != 0) {
+ setMaterial(userData, mat_nr, &gattribs);
+ glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
+ ccgSubSurf_drawGLMesh(ss,
+ true,
+ start_draw_patch,
+ num_draw_patches);
+ }
+ start_draw_patch = current_patch;
+ num_draw_patches = num_patches;
+ mat_nr = new_matnr;
+ draw_smooth = new_draw_smooth;
+ }
+ else {
+ num_draw_patches += num_patches;
+ }
+ current_patch += num_patches;
}
- else {
- draw_smooth = true;
- new_matnr = 1;
+ if (num_draw_patches != 0) {
+ setMaterial(userData, mat_nr, &gattribs);
+ glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
+ ccgSubSurf_drawGLMesh(ss,
+ true,
+ start_draw_patch,
+ num_draw_patches);
}
- glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
- setMaterial(userData, new_matnr, &gattribs);
- ccgSubSurf_drawGLMesh(ss, true, -1, -1);
+ glShadeModel(GL_SMOOTH);
return;
}
#endif
@@ -3214,12 +3261,13 @@ static void ccgDM_drawMappedFacesMat(DerivedMesh *dm,
matnr = -1;
-#define PASSATTRIB(dx, dy, vert) { \
- if (attribs.totorco) \
- index = getFaceIndex(ss, f, S, x + dx, y + dy, edgeSize, gridSize); \
- else \
- index = 0; \
- DM_draw_attrib_vertex(&attribs, a, index, vert, ((a) * 4) + vert); \
+#define PASSATTRIB(dx, dy, vert) { \
+ if (attribs.totorco) \
+ index = getFaceIndex(ss, f, S, x + dx, y + dy, edgeSize, gridSize); \
+ else \
+ index = 0; \
+ DM_draw_attrib_vertex(&attribs, a, index, vert, ((a) * 4) + vert); \
+ DM_draw_attrib_vertex_uniforms(&attribs); \
} (void)0
totface = ccgSubSurf_getNumFaces(ss);
@@ -3357,6 +3405,7 @@ static void ccgDM_drawMappedFacesMat(DerivedMesh *dm,
}
}
+ glShadeModel(GL_SMOOTH);
#undef PASSATTRIB
}
@@ -3370,24 +3419,107 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
CCGSubSurf *ss = ccgdm->ss;
CCGKey key;
int colType;
- const MLoopCol *mloopcol;
+ const MLoopCol *mloopcol = NULL;
MTexPoly *mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY);
DMFlagMat *faceFlags = ccgdm->faceFlags;
DMDrawOption draw_option;
int i, totpoly;
bool flush;
- bool use_tface = (flag & DM_DRAW_USE_ACTIVE_UV) != 0;
+ const bool use_tface = (flag & DM_DRAW_USE_ACTIVE_UV) != 0;
+ const bool use_colors = (flag & DM_DRAW_USE_COLORS) != 0;
unsigned int next_actualFace;
unsigned int gridFaces = ccgSubSurf_getGridSize(ss) - 1;
int mat_index;
int tot_element, start_element, tot_drawn;
+ if (use_colors) {
+ colType = CD_TEXTURE_MLOOPCOL;
+ mloopcol = dm->getLoopDataArray(dm, colType);
+ if (!mloopcol) {
+ colType = CD_PREVIEW_MLOOPCOL;
+ mloopcol = dm->getLoopDataArray(dm, colType);
+ }
+ if (!mloopcol) {
+ colType = CD_MLOOPCOL;
+ mloopcol = dm->getLoopDataArray(dm, colType);
+ }
+ }
+
#ifdef WITH_OPENSUBDIV
if (ccgdm->useGpuBackend) {
- if (ccgSubSurf_prepareGLMesh(ss, true) == false) {
+ const int active_uv_layer = CustomData_get_active_layer_index(&dm->loopData, CD_MLOOPUV);
+ if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, active_uv_layer) == false)) {
+ return;
+ }
+ if (drawParams == NULL) {
+ ccgSubSurf_drawGLMesh(ss, true, -1, -1);
return;
}
- ccgSubSurf_drawGLMesh(ss, true, -1, -1);
+ const int level = ccgSubSurf_getSubdivisionLevels(ss);
+ const int face_side = 1 << level;
+ const int grid_side = 1 << (level - 1);
+ const int face_patches = face_side * face_side;
+ const int grid_patches = grid_side * grid_side;
+ const int num_base_faces = ccgSubSurf_getNumGLMeshBaseFaces(ss);
+ int current_patch = 0;
+ int mat_nr = -1;
+ int start_draw_patch = 0, num_draw_patches = 0;
+ bool draw_smooth = false;
+ for (i = 0; i < num_base_faces; ++i) {
+ const int num_face_verts = ccgSubSurf_getNumGLMeshBaseFaceVerts(ss, i);
+ const int num_patches = (num_face_verts == 4) ? face_patches
+ : num_face_verts * grid_patches;
+ if (faceFlags) {
+ mat_nr = faceFlags[i].mat_nr;
+ draw_smooth = (faceFlags[i].flag & ME_SMOOTH);
+ }
+ else {
+ mat_nr = 0;
+ draw_smooth = false;
+ }
+
+ if (drawParams != NULL) {
+ MTexPoly *tp = (use_tface && mtexpoly) ? &mtexpoly[i] : NULL;
+ draw_option = drawParams(tp, (mloopcol != NULL), mat_nr);
+ }
+ else {
+ draw_option = (drawParamsMapped)
+ ? drawParamsMapped(userData, i, mat_nr)
+ : DM_DRAW_OPTION_NORMAL;
+ }
+
+ flush = (draw_option == DM_DRAW_OPTION_SKIP) || (i == num_base_faces - 1);
+
+ const int next_face = min_ii(i + 1, num_base_faces - 1);
+ if (!flush && compareDrawOptions) {
+ flush |= compareDrawOptions(userData, i, next_face) == 0;
+ }
+ if (!flush && faceFlags) {
+ bool new_draw_smooth = (faceFlags[next_face].flag & ME_SMOOTH);
+ flush |= (new_draw_smooth != draw_smooth);
+ }
+
+ current_patch += num_patches;
+
+ if (flush) {
+ if (draw_option != DM_DRAW_OPTION_SKIP) {
+ num_draw_patches += num_patches;
+ }
+ if (num_draw_patches != 0) {
+ glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
+ ccgSubSurf_drawGLMesh(ss,
+ true,
+ start_draw_patch,
+ num_draw_patches);
+ }
+ start_draw_patch = current_patch;
+ num_draw_patches = 0;
+ }
+ else {
+ num_draw_patches += num_patches;
+ }
+ }
+ glShadeModel(GL_SMOOTH);
return;
}
#endif
@@ -3395,17 +3527,6 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
CCG_key_top_level(&key, ss);
ccgdm_pbvh_update(ccgdm);
- colType = CD_TEXTURE_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- if (!mloopcol) {
- colType = CD_PREVIEW_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- }
- if (!mloopcol) {
- colType = CD_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- }
-
GPU_vertex_setup(dm);
GPU_normal_setup(dm);
GPU_triangle_setup(dm);
@@ -3419,7 +3540,6 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
next_actualFace = 0;
- glShadeModel(GL_SMOOTH);
/* lastFlag = 0; */ /* UNUSED */
for (mat_index = 0; mat_index < dm->drawObject->totmaterial; mat_index++) {
GPUBufferMaterial *bufmat = dm->drawObject->materials + mat_index;
@@ -3466,7 +3586,7 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
if (!flush && compareDrawOptions) {
/* also compare draw options and flush buffer if they're different
- * need for face selection highlight in edit mode */
+ * need for face selection highlight in edit mode */
flush |= compareDrawOptions(userData, actualFace, next_actualFace) == 0;
}
@@ -3575,7 +3695,7 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm,
*/
glColor3f(0.8f, 0.8f, 0.8f);
}
- if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true) == false)) {
+ if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, -1) == false)) {
return;
}
if (faceFlags) {
@@ -3597,6 +3717,7 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm,
if (do_draw) {
glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
ccgSubSurf_drawGLMesh(ss, true, -1, -1);
+ glShadeModel(GL_SMOOTH);
}
return;
}
@@ -3659,10 +3780,6 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm,
GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_QUARTTONE);
}
- /* no need to set shading mode to flat because
- * normals are already used to change shading */
- glShadeModel(GL_SMOOTH);
-
for (S = 0; S < numVerts; S++) {
CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
if (ln) {
@@ -3774,7 +3891,7 @@ static void ccgDM_drawMappedEdges(DerivedMesh *dm,
#ifdef WITH_OPENSUBDIV
if (ccgdm->useGpuBackend) {
/* TODO(sergey): Only draw edges from base mesh. */
- if (ccgSubSurf_prepareGLMesh(ccgdm->ss, true)) {
+ if (ccgSubSurf_prepareGLMesh(ccgdm->ss, true, -1)) {
if (!setDrawOptions || (setDrawOptions(userData, 0) != DM_DRAW_OPTION_SKIP)) {
ccgSubSurf_drawGLMesh(ccgdm->ss, false, -1, -1);
}
@@ -4964,7 +5081,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
#ifdef WITH_OPENSUBDIV
ccgSubSurf_setSkipGrids(smd->emCache, use_gpu_backend);
#endif
- ss_sync_from_derivedmesh(smd->emCache, dm, vertCos, useSimple);
+ ss_sync_from_derivedmesh(smd->emCache, dm, vertCos, useSimple, useSubsurfUv);
result = getCCGDerivedMesh(smd->emCache,
drawInteriorEdges,
useSubsurfUv, dm, use_gpu_backend);
@@ -4979,7 +5096,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
ss = _getSubSurf(NULL, levels, 3, useSimple | CCG_USE_ARENA | CCG_CALC_NORMALS);
- ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple);
+ ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv);
result = getCCGDerivedMesh(ss,
drawInteriorEdges, useSubsurfUv, dm, false);
@@ -5010,7 +5127,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
if (useIncremental && (flags & SUBSURF_IS_FINAL_CALC)) {
smd->mCache = ss = _getSubSurf(smd->mCache, levels, 3, useSimple | useAging | CCG_CALC_NORMALS);
- ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple);
+ ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv);
result = getCCGDerivedMesh(smd->mCache,
drawInteriorEdges,
@@ -5050,7 +5167,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
#ifdef WITH_OPENSUBDIV
ccgSubSurf_setSkipGrids(ss, use_gpu_backend);
#endif
- ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple);
+ ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv);
result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm, use_gpu_backend);
@@ -5079,7 +5196,7 @@ void subsurf_calculate_limit_positions(Mesh *me, float (*r_positions)[3])
CCGVertIterator vi;
DerivedMesh *dm = CDDM_from_mesh(me);
- ss_sync_from_derivedmesh(ss, dm, NULL, 0);
+ ss_sync_from_derivedmesh(ss, dm, NULL, 0, 0);
for (ccgSubSurf_initVertIterator(ss, &vi); !ccgVertIterator_isStopped(&vi); ccgVertIterator_next(&vi)) {
CCGVert *v = ccgVertIterator_getCurrent(&vi);
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 6def9e3e503..1636042f479 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -171,14 +171,17 @@ void BKE_text_free_lines(Text *text)
text->curl = text->sell = NULL;
}
+/** Free (or release) any data used by this text (does not free the text itself). */
void BKE_text_free(Text *text)
{
+ /* No animdata here. */
+
BKE_text_free_lines(text);
- if (text->name) MEM_freeN(text->name);
- MEM_freeN(text->undo_buf);
+ MEM_SAFE_FREE(text->name);
+ MEM_SAFE_FREE(text->undo_buf);
#ifdef WITH_PYTHON
- if (text->compiled) BPY_text_free_code(text);
+ BPY_text_free_code(text);
#endif
}
@@ -449,7 +452,7 @@ Text *BKE_text_copy(Main *bmain, Text *ta)
Text *tan;
TextLine *line, *tmp;
- tan = BKE_libblock_copy(&ta->id);
+ tan = BKE_libblock_copy(bmain, &ta->id);
/* file name can be NULL */
if (ta->name) {
@@ -488,196 +491,14 @@ Text *BKE_text_copy(Main *bmain, Text *ta)
init_undo_text(tan);
- if (ta->id.lib) {
- BKE_id_lib_local_paths(bmain, ta->id.lib, &tan->id);
- }
+ BKE_id_copy_ensure_local(bmain, &ta->id, &tan->id);
return tan;
}
-void BKE_text_unlink(Main *bmain, Text *text)
-{
- bScreen *scr;
- ScrArea *area;
- SpaceLink *sl;
- Object *ob;
- bController *cont;
- bActuator *act;
- bConstraint *con;
- bNodeTree *ntree;
- bNode *node;
- Material *mat;
- Lamp *la;
- Tex *te;
- World *wo;
- FreestyleLineStyle *linestyle;
- Scene *sce;
- SceneRenderLayer *srl;
- FreestyleModuleConfig *module;
- bool update;
-
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- /* game controllers */
- for (cont = ob->controllers.first; cont; cont = cont->next) {
- if (cont->type == CONT_PYTHON) {
- bPythonCont *pc;
-
- pc = cont->data;
- if (pc->text == text) pc->text = NULL;
- }
- }
- /* game actuators */
- for (act = ob->actuators.first; act; act = act->next) {
- if (act->type == ACT_2DFILTER) {
- bTwoDFilterActuator *tfa;
-
- tfa = act->data;
- if (tfa->text == text) tfa->text = NULL;
- }
- }
-
- /* pyconstraints */
- update = 0;
-
- if (ob->type == OB_ARMATURE && ob->pose) {
- bPoseChannel *pchan;
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- for (con = pchan->constraints.first; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_PYTHON) {
- bPythonConstraint *data = con->data;
- if (data->text == text) data->text = NULL;
- update = 1;
-
- }
- }
- }
- }
-
- for (con = ob->constraints.first; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_PYTHON) {
- bPythonConstraint *data = con->data;
- if (data->text == text) data->text = NULL;
- update = 1;
- }
- }
-
- if (update)
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
-
- /* nodes */
- for (la = bmain->lamp.first; la; la = la->id.next) {
- ntree = la->nodetree;
- if (!ntree)
- continue;
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == NODE_FRAME) {
- if ((Text *)node->id == text) {
- node->id = NULL;
- }
- }
- }
- }
-
- for (linestyle = bmain->linestyle.first; linestyle; linestyle = linestyle->id.next) {
- ntree = linestyle->nodetree;
- if (!ntree)
- continue;
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == NODE_FRAME) {
- if ((Text *)node->id == text) {
- node->id = NULL;
- }
- }
- }
- }
-
- for (mat = bmain->mat.first; mat; mat = mat->id.next) {
- ntree = mat->nodetree;
- if (!ntree)
- continue;
- for (node = ntree->nodes.first; node; node = node->next) {
- if (ELEM(node->type, SH_NODE_SCRIPT, NODE_FRAME)) {
- if ((Text *)node->id == text) {
- node->id = NULL;
- }
- }
- }
- }
-
- for (te = bmain->tex.first; te; te = te->id.next) {
- ntree = te->nodetree;
- if (!ntree)
- continue;
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == NODE_FRAME) {
- if ((Text *)node->id == text) {
- node->id = NULL;
- }
- }
- }
- }
-
- for (wo = bmain->world.first; wo; wo = wo->id.next) {
- ntree = wo->nodetree;
- if (!ntree)
- continue;
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == NODE_FRAME) {
- if ((Text *)node->id == text) {
- node->id = NULL;
- }
- }
- }
- }
-
- for (sce = bmain->scene.first; sce; sce = sce->id.next) {
- ntree = sce->nodetree;
- if (!ntree)
- continue;
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == NODE_FRAME) {
- Text *ntext = (Text *)node->id;
- if (ntext == text) node->id = NULL;
- }
- }
-
- /* Freestyle (while looping over the scene) */
- for (srl = sce->r.layers.first; srl; srl = srl->next) {
- for (module = srl->freestyleConfig.modules.first; module; module = module->next) {
- if (module->script == text)
- module->script = NULL;
- }
- }
- }
-
- for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) {
- for (node = ntree->nodes.first; node; node = node->next) {
- if (ELEM(node->type, SH_NODE_SCRIPT, NODE_FRAME)) {
- if ((Text *)node->id == text) {
- node->id = NULL;
- }
- }
- }
- }
-
- /* text space */
- 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) {
- if (sl->spacetype == SPACE_TEXT) {
- SpaceText *st = (SpaceText *) sl;
-
- if (st->text == text) {
- st->text = NULL;
- st->top = 0;
- }
- }
- }
- }
- }
-
- text->id.us = 0;
+void BKE_text_make_local(Main *bmain, Text *text, const bool lib_local)
+{
+ BKE_id_make_local_generic(bmain, &text->id, true, lib_local);
}
void BKE_text_clear(Text *text) /* called directly from rna */
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index d353042b711..2d3ecad19ad 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -59,6 +59,8 @@
#include "BKE_main.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_image.h"
#include "BKE_material.h"
#include "BKE_texture.h"
@@ -557,23 +559,38 @@ int colorband_element_remove(struct ColorBand *coba, int index)
/* ******************* TEX ************************ */
+/** Free (or release) any data used by this texture (does not free the texure itself). */
void BKE_texture_free(Tex *tex)
{
- if (tex->coba) MEM_freeN(tex->coba);
- if (tex->env) BKE_texture_envmap_free(tex->env);
- if (tex->pd) BKE_texture_pointdensity_free(tex->pd);
- if (tex->vd) BKE_texture_voxeldata_free(tex->vd);
- if (tex->ot) BKE_texture_ocean_free(tex->ot);
- BKE_animdata_free((struct ID *)tex);
-
- BKE_previewimg_free(&tex->preview);
- BKE_icon_id_delete((struct ID *)tex);
- tex->id.icon_id = 0;
-
+ BKE_animdata_free((ID *)tex, false);
+
+ /* is no lib link block, but texture extension */
if (tex->nodetree) {
ntreeFreeTree(tex->nodetree);
MEM_freeN(tex->nodetree);
+ tex->nodetree = NULL;
+ }
+
+ MEM_SAFE_FREE(tex->coba);
+ if (tex->env) {
+ BKE_texture_envmap_free(tex->env);
+ tex->env = NULL;
+ }
+ if (tex->pd) {
+ BKE_texture_pointdensity_free(tex->pd);
+ tex->pd = NULL;
}
+ if (tex->vd) {
+ BKE_texture_voxeldata_free(tex->vd);
+ tex->vd = NULL;
+ }
+ if (tex->ot) {
+ BKE_texture_ocean_free(tex->ot);
+ tex->ot = NULL;
+ }
+
+ BKE_icon_id_delete((ID *)tex);
+ BKE_previewimg_free(&tex->preview);
}
/* ------------------------------------------------------------------------- */
@@ -829,11 +846,11 @@ MTex *BKE_texture_mtex_add_id(ID *id, int slot)
/* ------------------------------------------------------------------------- */
-Tex *BKE_texture_copy(Tex *tex)
+Tex *BKE_texture_copy(Main *bmain, Tex *tex)
{
Tex *texn;
- texn = BKE_libblock_copy(&tex->id);
+ texn = BKE_libblock_copy(bmain, &tex->id);
if (BKE_texture_is_image_user(tex)) {
id_us_plus((ID *)texn->ima);
}
@@ -846,19 +863,18 @@ Tex *BKE_texture_copy(Tex *tex)
if (texn->pd) texn->pd = BKE_texture_pointdensity_copy(texn->pd);
if (texn->vd) texn->vd = MEM_dupallocN(texn->vd);
if (texn->ot) texn->ot = BKE_texture_ocean_copy(texn->ot);
- if (tex->preview) texn->preview = BKE_previewimg_copy(tex->preview);
if (tex->nodetree) {
if (tex->nodetree->execdata) {
ntreeTexEndExecTree(tex->nodetree->execdata);
}
- texn->nodetree = ntreeCopyTree(tex->nodetree);
- }
-
- if (tex->id.lib) {
- BKE_id_lib_local_paths(G.main, tex->id.lib, &texn->id);
+ texn->nodetree = ntreeCopyTree(bmain, tex->nodetree);
}
+ BKE_previewimg_id_copy(&texn->id, &tex->id);
+
+ BKE_id_copy_ensure_local(bmain, &tex->id, &texn->id);
+
return texn;
}
@@ -898,195 +914,9 @@ Tex *BKE_texture_localize(Tex *tex)
/* ------------------------------------------------------------------------- */
-static void extern_local_texture(Tex *tex)
+void BKE_texture_make_local(Main *bmain, Tex *tex, const bool lib_local)
{
- id_lib_extern((ID *)tex->ima);
-}
-
-void BKE_texture_make_local(Tex *tex)
-{
- Main *bmain = G.main;
- Material *ma;
- World *wrld;
- Lamp *la;
- Brush *br;
- ParticleSettings *pa;
- FreestyleLineStyle *ls;
- int a;
- bool is_local = false, is_lib = false;
-
- /* - only lib users: do nothing
- * - only local users: set flag
- * - mixed: make copy
- */
-
- if (tex->id.lib == NULL) return;
-
- if (tex->id.us == 1) {
- id_clear_lib_data(bmain, &tex->id);
- extern_local_texture(tex);
- return;
- }
-
- ma = bmain->mat.first;
- while (ma) {
- for (a = 0; a < MAX_MTEX; a++) {
- if (ma->mtex[a] && ma->mtex[a]->tex == tex) {
- if (ma->id.lib) is_lib = true;
- else is_local = true;
- }
- }
- ma = ma->id.next;
- }
- la = bmain->lamp.first;
- while (la) {
- for (a = 0; a < MAX_MTEX; a++) {
- if (la->mtex[a] && la->mtex[a]->tex == tex) {
- if (la->id.lib) is_lib = true;
- else is_local = true;
- }
- }
- la = la->id.next;
- }
- wrld = bmain->world.first;
- while (wrld) {
- for (a = 0; a < MAX_MTEX; a++) {
- if (wrld->mtex[a] && wrld->mtex[a]->tex == tex) {
- if (wrld->id.lib) is_lib = true;
- else is_local = true;
- }
- }
- wrld = wrld->id.next;
- }
- br = bmain->brush.first;
- while (br) {
- if (br->mtex.tex == tex) {
- if (br->id.lib) is_lib = true;
- else is_local = true;
- }
- if (br->mask_mtex.tex == tex) {
- if (br->id.lib) is_lib = true;
- else is_local = true;
- }
- br = br->id.next;
- }
- pa = bmain->particle.first;
- while (pa) {
- for (a = 0; a < MAX_MTEX; a++) {
- if (pa->mtex[a] && pa->mtex[a]->tex == tex) {
- if (pa->id.lib) is_lib = true;
- else is_local = true;
- }
- }
- pa = pa->id.next;
- }
- ls = bmain->linestyle.first;
- while (ls) {
- for (a = 0; a < MAX_MTEX; a++) {
- if (ls->mtex[a] && ls->mtex[a]->tex == tex) {
- if (ls->id.lib) is_lib = true;
- else is_local = true;
- }
- }
- ls = ls->id.next;
- }
-
- if (is_local && is_lib == false) {
- id_clear_lib_data(bmain, &tex->id);
- extern_local_texture(tex);
- }
- else if (is_local && is_lib) {
- Tex *tex_new = BKE_texture_copy(tex);
-
- tex_new->id.us = 0;
-
- /* Remap paths of new ID using old library as base. */
- BKE_id_lib_local_paths(bmain, tex->id.lib, &tex_new->id);
-
- ma = bmain->mat.first;
- while (ma) {
- for (a = 0; a < MAX_MTEX; a++) {
- if (ma->mtex[a] && ma->mtex[a]->tex == tex) {
- if (ma->id.lib == NULL) {
- ma->mtex[a]->tex = tex_new;
- id_us_plus(&tex_new->id);
- id_us_min(&tex->id);
- }
- }
- }
- ma = ma->id.next;
- }
- la = bmain->lamp.first;
- while (la) {
- for (a = 0; a < MAX_MTEX; a++) {
- if (la->mtex[a] && la->mtex[a]->tex == tex) {
- if (la->id.lib == NULL) {
- la->mtex[a]->tex = tex_new;
- id_us_plus(&tex_new->id);
- id_us_min(&tex->id);
- }
- }
- }
- la = la->id.next;
- }
- wrld = bmain->world.first;
- while (wrld) {
- for (a = 0; a < MAX_MTEX; a++) {
- if (wrld->mtex[a] && wrld->mtex[a]->tex == tex) {
- if (wrld->id.lib == NULL) {
- wrld->mtex[a]->tex = tex_new;
- id_us_plus(&tex_new->id);
- id_us_min(&tex->id);
- }
- }
- }
- wrld = wrld->id.next;
- }
- br = bmain->brush.first;
- while (br) {
- if (br->mtex.tex == tex) {
- if (br->id.lib == NULL) {
- br->mtex.tex = tex_new;
- id_us_plus(&tex_new->id);
- id_us_min(&tex->id);
- }
- }
- if (br->mask_mtex.tex == tex) {
- if (br->id.lib == NULL) {
- br->mask_mtex.tex = tex_new;
- id_us_plus(&tex_new->id);
- id_us_min(&tex->id);
- }
- }
- br = br->id.next;
- }
- pa = bmain->particle.first;
- while (pa) {
- for (a = 0; a < MAX_MTEX; a++) {
- if (pa->mtex[a] && pa->mtex[a]->tex == tex) {
- if (pa->id.lib == NULL) {
- pa->mtex[a]->tex = tex_new;
- id_us_plus(&tex_new->id);
- id_us_min(&tex->id);
- }
- }
- }
- pa = pa->id.next;
- }
- ls = bmain->linestyle.first;
- while (ls) {
- for (a = 0; a < MAX_MTEX; a++) {
- if (ls->mtex[a] && ls->mtex[a]->tex == tex) {
- if (ls->id.lib == NULL) {
- ls->mtex[a]->tex = tex_new;
- id_us_plus(&tex_new->id);
- id_us_min(&tex->id);
- }
- }
- }
- ls = ls->id.next;
- }
- }
+ BKE_id_make_local_generic(bmain, &tex->id, true, lib_local);
}
Tex *give_current_object_texture(Object *ob)
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index 3b76e456ff7..96ab8693122 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -44,6 +44,8 @@
#include "DNA_scene_types.h"
#include "BLI_utildefines.h"
+#include "BLI_bitmap_draw_2d.h"
+#include "BLI_ghash.h"
#include "BLI_math.h"
#include "BLI_math_base.h"
#include "BLI_listbase.h"
@@ -55,6 +57,7 @@
#include "BKE_fcurve.h"
#include "BKE_tracking.h"
+#include "BKE_library.h"
#include "BKE_movieclip.h"
#include "BKE_object.h"
#include "BKE_scene.h"
@@ -186,8 +189,131 @@ void BKE_tracking_free(MovieTracking *tracking)
tracking_dopesheet_free(&tracking->dopesheet);
}
+/* Copy the whole list of tracks. */
+static void tracking_tracks_copy(ListBase *tracks_dst, ListBase *tracks_src, GHash *tracks_mapping)
+{
+ MovieTrackingTrack *track_dst, *track_src;
+
+ BLI_listbase_clear(tracks_dst);
+ BLI_ghash_clear(tracks_mapping, NULL, NULL);
+
+ for (track_src = tracks_src->first; track_src != NULL; track_src = track_src->next) {
+ track_dst = MEM_dupallocN(track_src);
+ if (track_src->markers) {
+ track_dst->markers = MEM_dupallocN(track_src->markers);
+ }
+ id_us_plus(&track_dst->gpd->id);
+ BLI_addtail(tracks_dst, track_dst);
+ BLI_ghash_insert(tracks_mapping, track_src, track_dst);
+ }
+}
+
+/* copy the whole list of plane tracks (need whole MovieTracking structures due to embedded pointers to tracks).
+ * WARNING: implies tracking_[dst/src] and their tracks have already been copied. */
+static void tracking_plane_tracks_copy(ListBase *plane_tracks_dst, ListBase *plane_tracks_src, GHash *tracks_mapping)
+{
+ MovieTrackingPlaneTrack *plane_track_dst, *plane_track_src;
+
+ BLI_listbase_clear(plane_tracks_dst);
+
+ for (plane_track_src = plane_tracks_src->first; plane_track_src != NULL; plane_track_src = plane_track_src->next) {
+ plane_track_dst = MEM_dupallocN(plane_tracks_src);
+ if (plane_track_src->markers) {
+ plane_track_dst->markers = MEM_dupallocN(plane_track_src->markers);
+ }
+ plane_track_dst->point_tracks = MEM_mallocN(sizeof(*plane_track_dst->point_tracks) * plane_track_dst->point_tracksnr, __func__);
+ for (int i = 0; i < plane_track_dst->point_tracksnr; i++) {
+ plane_track_dst->point_tracks[i] = BLI_ghash_lookup(tracks_mapping, plane_track_src->point_tracks[i]);
+ }
+ id_us_plus(&plane_track_dst->image->id);
+ BLI_addtail(plane_tracks_dst, plane_track_dst);
+ }
+}
+
+/* Copy reconstruction structure. */
+static void tracking_reconstruction_copy(
+ MovieTrackingReconstruction *reconstruction_dst, MovieTrackingReconstruction *reconstruction_src)
+{
+ *reconstruction_dst = *reconstruction_src;
+ if (reconstruction_src->cameras) {
+ reconstruction_dst->cameras = MEM_dupallocN(reconstruction_src->cameras);
+ }
+}
+
+/* Copy stabilization structure. */
+static void tracking_stabilization_copy(
+ MovieTrackingStabilization *stabilization_dst, MovieTrackingStabilization *stabilization_src)
+{
+ *stabilization_dst = *stabilization_src;
+}
+
+/* Copy tracking object. */
+static void tracking_object_copy(
+ MovieTrackingObject *object_dst, MovieTrackingObject *object_src, GHash *tracks_mapping)
+{
+ *object_dst = *object_src;
+ tracking_tracks_copy(&object_dst->tracks, &object_src->tracks, tracks_mapping);
+ tracking_plane_tracks_copy(&object_dst->plane_tracks, &object_src->plane_tracks, tracks_mapping);
+ tracking_reconstruction_copy(&object_dst->reconstruction, &object_src->reconstruction);
+}
+
+/* Copy list of tracking objects. */
+static void tracking_objects_copy(ListBase *objects_dst, ListBase *objects_src, GHash *tracks_mapping)
+{
+ MovieTrackingObject *object_dst, *object_src;
+
+ BLI_listbase_clear(objects_dst);
+
+ for (object_src = objects_src->first; object_src != NULL; object_src = object_src->next) {
+ object_dst = MEM_mallocN(sizeof(*object_dst), __func__);
+ tracking_object_copy(object_dst, object_src, tracks_mapping);
+ BLI_addtail(objects_dst, object_dst);
+ }
+}
+
+/* Copy tracking structure content. */
+void BKE_tracking_copy(MovieTracking *tracking_dst, MovieTracking *tracking_src)
+{
+ GHash *tracks_mapping = BLI_ghash_ptr_new(__func__);
+
+ *tracking_dst = *tracking_src;
+
+ tracking_tracks_copy(&tracking_dst->tracks, &tracking_src->tracks, tracks_mapping);
+ tracking_plane_tracks_copy(&tracking_dst->plane_tracks, &tracking_src->plane_tracks, tracks_mapping);
+ tracking_reconstruction_copy(&tracking_dst->reconstruction, &tracking_src->reconstruction);
+ tracking_stabilization_copy(&tracking_dst->stabilization, &tracking_src->stabilization);
+ if (tracking_src->act_track) {
+ tracking_dst->act_track = BLI_ghash_lookup(tracks_mapping, tracking_src->act_track);
+ }
+ if (tracking_src->act_plane_track) {
+ MovieTrackingPlaneTrack *plane_track_src, *plane_track_dst;
+ for (plane_track_src = tracking_src->plane_tracks.first, plane_track_dst = tracking_dst->plane_tracks.first;
+ !ELEM(NULL, plane_track_src, plane_track_dst);
+ plane_track_src = plane_track_src->next, plane_track_dst = plane_track_dst->next)
+ {
+ if (plane_track_src == tracking_src->act_plane_track) {
+ tracking_dst->act_plane_track = plane_track_dst;
+ break;
+ }
+ }
+ }
+
+ /* Warning! Will override tracks_mapping. */
+ tracking_objects_copy(&tracking_dst->objects, &tracking_src->objects, tracks_mapping);
+
+ /* Those remaining are runtime data, they will be reconstructed as needed, do not bother copying them. */
+ tracking_dst->dopesheet.ok = false;
+ BLI_listbase_clear(&tracking_dst->dopesheet.channels);
+ BLI_listbase_clear(&tracking_dst->dopesheet.coverage_segments);
+
+ tracking_dst->camera.intrinsics = NULL;
+ tracking_dst->stats = NULL;
+
+ BLI_ghash_free(tracks_mapping, NULL, NULL);
+}
+
/* Initialize motion tracking settings to default values,
- * used when new movie clip datablock is creating.
+ * used when new movie clip datablock is created.
*/
void BKE_tracking_settings_init(MovieTracking *tracking)
{
@@ -205,10 +331,22 @@ void BKE_tracking_settings_init(MovieTracking *tracking)
tracking->settings.object_distance = 1;
tracking->stabilization.scaleinf = 1.0f;
+ tracking->stabilization.anchor_frame = 1;
+ zero_v2(tracking->stabilization.target_pos);
+ tracking->stabilization.target_rot = 0.0f;
+ tracking->stabilization.scale = 1.0f;
+
+ tracking->stabilization.act_track = 0;
+ tracking->stabilization.act_rot_track = 0;
+ tracking->stabilization.tot_track = 0;
+ tracking->stabilization.tot_rot_track = 0;
+
+ tracking->stabilization.scaleinf = 1.0f;
tracking->stabilization.locinf = 1.0f;
tracking->stabilization.rotinf = 1.0f;
tracking->stabilization.maxscale = 2.0f;
tracking->stabilization.filter = TRACKING_FILTER_BILINEAR;
+ tracking->stabilization.flag |= TRACKING_SHOW_STAB_TRACKS;
BKE_tracking_object_add(tracking, "Camera");
}
@@ -423,6 +561,7 @@ MovieTrackingTrack *BKE_tracking_track_add(MovieTracking *tracking, ListBase *tr
track->flag = settings->default_flag;
track->algorithm_flag = settings->default_algorithm_flag;
track->weight = settings->default_weight;
+ track->weight_stab = settings->default_weight;
memset(&marker, 0, sizeof(marker));
marker.pos[0] = x;
@@ -461,6 +600,12 @@ MovieTrackingTrack *BKE_tracking_track_duplicate(MovieTrackingTrack *track)
new_track->markers = MEM_dupallocN(new_track->markers);
+ /* Orevent duplicate from being used for 2D stabilization.
+ * If necessary, it shall be added explicitly.
+ */
+ new_track->flag &= ~TRACK_USE_2D_STAB;
+ new_track->flag &= ~TRACK_USE_2D_STAB_ROT;
+
return new_track;
}
@@ -853,9 +998,10 @@ static void track_mask_gpencil_layer_rasterize(int frame_width, int frame_height
point[1] = (stroke_points[i].y - marker->search_min[1]) * frame_height;
}
/* TODO: add an option to control whether AA is enabled or not */
- fill_poly_v2i_n(0, 0, mask_width, mask_height,
- (const int (*)[2])mask_points, stroke->totpoints,
- track_mask_set_pixel_cb, &data);
+ BLI_bitmap_draw_2d_poly_v2i_n(
+ 0, 0, mask_width, mask_height,
+ (const int (*)[2])mask_points, stroke->totpoints,
+ track_mask_set_pixel_cb, &data);
MEM_freeN(mask_points);
}
stroke = stroke->next;
diff --git a/source/blender/blenkernel/intern/tracking_auto.c b/source/blender/blenkernel/intern/tracking_auto.c
index 9df30a8acc9..3b56ea271d0 100644
--- a/source/blender/blenkernel/intern/tracking_auto.c
+++ b/source/blender/blenkernel/intern/tracking_auto.c
@@ -376,6 +376,9 @@ bool BKE_autotrack_context_step(AutoTrackContext *context)
#pragma omp parallel for if (context->num_tracks > 1)
for (track = 0; track < context->num_tracks; ++track) {
AutoTrackOptions *options = &context->options[track];
+ if (options->is_failed) {
+ continue;
+ }
libmv_Marker libmv_current_marker,
libmv_reference_marker,
libmv_tracked_marker;
@@ -463,16 +466,25 @@ void BKE_autotrack_context_sync(AutoTrackContext *context)
AutoTrackOptions *options = &context->options[track];
int track_frame = BKE_movieclip_remap_scene_to_clip_frame(
context->clips[options->clip_index], frame);
- if (options->is_failed && options->failed_frame == track_frame) {
- MovieTrackingMarker *prev_marker =
- BKE_tracking_marker_get_exact(options->track, frame);
- if (prev_marker) {
- marker = *prev_marker;
- marker.framenr = context->backwards ?
- track_frame - 1 :
- track_frame + 1;
- marker.flag |= MARKER_DISABLED;
- BKE_tracking_marker_insert(options->track, &marker);
+ if (options->is_failed) {
+ if (options->failed_frame == track_frame) {
+ MovieTrackingMarker *prev_marker =
+ BKE_tracking_marker_get_exact(
+ options->track,
+ context->backwards
+ ? frame + 1
+ : frame - 1);
+ if (prev_marker) {
+ marker = *prev_marker;
+ marker.framenr = track_frame;
+ marker.flag |= MARKER_DISABLED;
+ BKE_tracking_marker_insert(options->track, &marker);
+ continue;
+ }
+ }
+ if ((context->backwards && options->failed_frame > track_frame) ||
+ (!context->backwards && options->failed_frame < track_frame))
+ {
continue;
}
}
diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c
index eb224020977..b8949f9a0de 100644
--- a/source/blender/blenkernel/intern/tracking_stabilize.c
+++ b/source/blender/blenkernel/intern/tracking_stabilize.c
@@ -21,6 +21,7 @@
* Contributor(s): Blender Foundation,
* Sergey Sharybin
* Keir Mierle
+ * Ichthyostega
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -28,292 +29,1484 @@
/** \file blender/blenkernel/intern/tracking_stabilize.c
* \ingroup bke
*
- * This file contains implementation of 2D frame stabilization.
+ * This file contains implementation of 2D image stabilization.
*/
#include <limits.h>
#include "DNA_movieclip_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_anim_types.h"
+#include "RNA_access.h"
#include "BLI_utildefines.h"
+#include "BLI_sort_utils.h"
+#include "BLI_math_vector.h"
#include "BLI_math.h"
#include "BKE_tracking.h"
+#include "BKE_movieclip.h"
+#include "BKE_fcurve.h"
+#include "BLI_ghash.h"
+#include "MEM_guardedalloc.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
-/* Calculate median point of markers of tracks marked as used for
- * 2D stabilization.
- *
- * NOTE: frame number should be in clip space, not scene space
+
+/* == Parameterization constants == */
+
+/* When measuring the scale changes relative to the rotation pivot point, it
+ * might happen accidentally that a probe point (tracking point), which doesn't
+ * actually move on a circular path, gets very close to the pivot point, causing
+ * the measured scale contribution to go toward infinity. We damp this undesired
+ * effect by adding a bias (floor) to the measured distances, which will
+ * dominate very small distances and thus cause the corresponding track's
+ * contribution to diminish.
+ * Measurements happen in normalized (0...1) coordinates within a frame.
+ */
+static float SCALE_ERROR_LIMIT_BIAS = 0.01f;
+
+/* When to consider a track as completely faded out.
+ * This is used in conjunction with the "disabled" flag of the track
+ * to determine start positions, end positions and gaps
+ */
+static float EPSILON_WEIGHT = 0.005f;
+
+
+
+/* == private working data == */
+
+/* Per track baseline for stabilization, defined at reference frame.
+ * A track's reference frame is chosen as close as possible to the (global)
+ * anchor_frame. Baseline holds the constant part of each track's contribution
+ * to the observed movement; it is calculated at initialization pass, using the
+ * measurement value at reference frame plus the average contribution to fill
+ * the gap between global anchor_frame and the reference frame for this track.
+ * This struct with private working data is associated to the local call context
+ * via `StabContext::private_track_data`
*/
-static bool stabilization_median_point_get(MovieTracking *tracking, int framenr, float median[2])
+typedef struct TrackStabilizationBase {
+ float stabilization_offset_base[2];
+
+ /* measured relative to translated pivot */
+ float stabilization_rotation_base[2][2];
+
+ /* measured relative to translated pivot */
+ float stabilization_scale_base;
+
+ bool is_init_for_stabilization;
+ FCurve *track_weight_curve;
+} TrackStabilizationBase;
+
+/* Tracks are reordered for initialization, starting as close as possible to
+ * anchor_frame
+ */
+typedef struct TrackInitOrder {
+ int sort_value;
+ int reference_frame;
+ MovieTrackingTrack *data;
+} TrackInitOrder;
+
+/* Per frame private working data, for accessing possibly animated values. */
+typedef struct StabContext {
+ MovieClip *clip;
+ MovieTracking *tracking;
+ MovieTrackingStabilization *stab;
+ GHash *private_track_data;
+ FCurve *locinf;
+ FCurve *rotinf;
+ FCurve *scaleinf;
+ FCurve *target_pos[2];
+ FCurve *target_rot;
+ FCurve *target_scale;
+ bool use_animation;
+} StabContext;
+
+
+static TrackStabilizationBase *access_stabilization_baseline_data(
+ StabContext *ctx,
+ MovieTrackingTrack *track)
{
- bool ok = false;
- float min[2], max[2];
- MovieTrackingTrack *track;
+ return BLI_ghash_lookup(ctx->private_track_data, track);
+}
- INIT_MINMAX2(min, max);
+static void attach_stabilization_baseline_data(
+ StabContext *ctx,
+ MovieTrackingTrack *track,
+ TrackStabilizationBase *private_data)
+{
+ BLI_ghash_insert(ctx->private_track_data, track, private_data);
+}
- track = tracking->tracks.first;
- while (track) {
- if (track->flag & TRACK_USE_2D_STAB) {
- MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
+static void discard_stabilization_baseline_data(void *val)
+{
+ if (val != NULL) {
+ MEM_freeN(val);
+ }
+}
+
+
+/* == access animated values for given frame == */
+
+static FCurve *retrieve_stab_animation(MovieClip *clip,
+ const char *data_path,
+ int idx)
+{
+ return id_data_find_fcurve(&clip->id,
+ &clip->tracking.stabilization,
+ &RNA_MovieTrackingStabilization,
+ data_path,
+ idx,
+ NULL);
+}
+
+static FCurve *retrieve_track_weight_animation(MovieClip *clip,
+ MovieTrackingTrack *track)
+{
+ return id_data_find_fcurve(&clip->id,
+ track,
+ &RNA_MovieTrackingTrack,
+ "weight_stab",
+ 0,
+ NULL);
+}
+
+static float fetch_from_fcurve(FCurve *animationCurve,
+ int framenr,
+ StabContext *ctx,
+ float default_value)
+{
+ if (ctx && ctx->use_animation && animationCurve) {
+ int scene_framenr = BKE_movieclip_remap_clip_to_scene_frame(ctx->clip,
+ framenr);
+ return evaluate_fcurve(animationCurve, scene_framenr);
+ }
+ return default_value;
+}
+
+
+static float get_animated_locinf(StabContext *ctx, int framenr)
+{
+ return fetch_from_fcurve(ctx->locinf, framenr, ctx, ctx->stab->locinf);
+}
+
+static float get_animated_rotinf(StabContext *ctx, int framenr)
+{
+ return fetch_from_fcurve(ctx->rotinf, framenr, ctx, ctx->stab->rotinf);
+}
+
+static float get_animated_scaleinf(StabContext *ctx, int framenr)
+{
+ return fetch_from_fcurve(ctx->scaleinf, framenr, ctx, ctx->stab->scaleinf);
+}
+
+static void get_animated_target_pos(StabContext *ctx,
+ int framenr,
+ float target_pos[2])
+{
+ target_pos[0] = fetch_from_fcurve(ctx->target_pos[0],
+ framenr,
+ ctx,
+ ctx->stab->target_pos[0]);
+ target_pos[1] = fetch_from_fcurve(ctx->target_pos[1],
+ framenr,
+ ctx,
+ ctx->stab->target_pos[1]);
+}
+
+static float get_animated_target_rot(StabContext *ctx, int framenr)
+{
+ return fetch_from_fcurve(ctx->target_rot,
+ framenr,
+ ctx,
+ ctx->stab->target_rot);
+}
+
+static float get_animated_target_scale(StabContext *ctx, int framenr)
+{
+ return fetch_from_fcurve(ctx->target_scale, framenr, ctx, ctx->stab->scale);
+}
+
+static float get_animated_weight(StabContext *ctx,
+ MovieTrackingTrack *track,
+ int framenr)
+{
+ TrackStabilizationBase *working_data =
+ access_stabilization_baseline_data(ctx, track);
+ if (working_data && working_data->track_weight_curve) {
+ int scene_framenr = BKE_movieclip_remap_clip_to_scene_frame(ctx->clip,
+ framenr);
+ return evaluate_fcurve(working_data->track_weight_curve, scene_framenr);
+ }
+ /* Use weight at global 'current frame' as fallback default. */
+ return track->weight_stab;
+}
+
+static void use_values_from_fcurves(StabContext *ctx, bool toggle)
+{
+ if (ctx != NULL) {
+ ctx->use_animation = toggle;
+ }
+}
+
+
+/* Prepare per call private working area.
+ * Used for access to possibly animated values: retrieve available F-curves.
+ */
+static StabContext *initialize_stabilization_working_context(MovieClip *clip)
+{
+ StabContext *ctx = MEM_callocN(sizeof(StabContext),
+ "2D stabilization animation runtime data");
+ ctx->clip = clip;
+ ctx->tracking = &clip->tracking;
+ ctx->stab = &clip->tracking.stabilization;
+ ctx->private_track_data = BLI_ghash_ptr_new(
+ "2D stabilization per track private working data");
+ ctx->locinf = retrieve_stab_animation(clip, "influence_location", 0);
+ ctx->rotinf = retrieve_stab_animation(clip, "influence_rotation", 0);
+ ctx->scaleinf = retrieve_stab_animation(clip, "influence_scale", 0);
+ ctx->target_pos[0] = retrieve_stab_animation(clip, "target_pos", 0);
+ ctx->target_pos[1] = retrieve_stab_animation(clip, "target_pos", 1);
+ ctx->target_rot = retrieve_stab_animation(clip, "target_rot", 0);
+ ctx->target_scale = retrieve_stab_animation(clip, "target_zoom", 0);
+ ctx->use_animation = true;
+ return ctx;
+}
+
+/* Discard all private working data attached to this call context.
+ * NOTE: We allocate the record for the per track baseline contribution
+ * locally for each call context (i.e. call to
+ * BKE_tracking_stabilization_data_get()
+ * Thus it is correct to discard all allocations found within the
+ * corresponding _local_ GHash
+ */
+static void discard_stabilization_working_context(StabContext *ctx)
+{
+ if (ctx != NULL) {
+ BLI_ghash_free(ctx->private_track_data,
+ NULL,
+ discard_stabilization_baseline_data);
+ MEM_freeN(ctx);
+ }
+}
+
+static bool is_init_for_stabilization(StabContext *ctx,
+ MovieTrackingTrack *track)
+{
+ TrackStabilizationBase *working_data =
+ access_stabilization_baseline_data(ctx, track);
+ return (working_data != NULL && working_data->is_init_for_stabilization);
+}
+
+static bool is_usable_for_stabilization(StabContext *ctx,
+ MovieTrackingTrack *track)
+{
+ return (track->flag & TRACK_USE_2D_STAB) &&
+ is_init_for_stabilization(ctx, track);
+}
+
+static bool is_effectively_disabled(StabContext *ctx,
+ MovieTrackingTrack *track,
+ MovieTrackingMarker *marker)
+{
+ return (marker->flag & MARKER_DISABLED) ||
+ (EPSILON_WEIGHT > get_animated_weight(ctx, track, marker->framenr));
+}
+
+
+static int search_closest_marker_index(MovieTrackingTrack *track,
+ int ref_frame)
+{
+ MovieTrackingMarker *markers = track->markers;
+ int end = track->markersnr;
+ int i = track->last_marker;
+
+ i = MAX2(0, i);
+ i = MIN2(i, end - 1);
+ for ( ; i < end - 1 && markers[i].framenr <= ref_frame; ++i);
+ for ( ; 0 < i && markers[i].framenr > ref_frame; --i);
+
+ track->last_marker = i;
+ return i;
+}
+
+static void retrieve_next_higher_usable_frame(StabContext *ctx,
+ MovieTrackingTrack *track,
+ int i,
+ int ref_frame,
+ int *next_higher)
+{
+ MovieTrackingMarker *markers = track->markers;
+ int end = track->markersnr;
+ BLI_assert(0 <= i && i < end);
+
+ while (i < end &&
+ (markers[i].framenr < ref_frame ||
+ is_effectively_disabled(ctx, track, &markers[i])))
+ {
+ ++i;
+ }
+ if (i < end && markers[i].framenr < *next_higher) {
+ BLI_assert(markers[i].framenr >= ref_frame);
+ *next_higher = markers[i].framenr;
+ }
+}
- minmax_v2v2_v2(min, max, marker->pos);
+static void retrieve_next_lower_usable_frame(StabContext *ctx,
+ MovieTrackingTrack *track,
+ int i,
+ int ref_frame,
+ int *next_lower)
+{
+ MovieTrackingMarker *markers = track->markers;
+ BLI_assert(0 <= i && i < track->markersnr);
+ while (i >= 0 &&
+ (markers[i].framenr > ref_frame ||
+ is_effectively_disabled(ctx, track, &markers[i])))
+ {
+ --i;
+ }
+ if (0 <= i && markers[i].framenr > *next_lower) {
+ BLI_assert(markers[i].framenr <= ref_frame);
+ *next_lower = markers[i].framenr;
+ }
+}
- ok = true;
+/* Find closest frames with usable stabilization data.
+ * A frame counts as _usable_ when there is at least one track marked for
+ * translation stabilization, which has an enabled tracking marker at this very
+ * frame. We search both for the next lower and next higher position, to allow
+ * the caller to interpolate gaps and to extrapolate at the ends of the
+ * definition range.
+ *
+ * NOTE: Regarding performance note that the individual tracks will cache the
+ * last search position.
+ */
+static void find_next_working_frames(StabContext *ctx,
+ int framenr,
+ int *next_lower,
+ int *next_higher)
+{
+ for (MovieTrackingTrack *track = ctx->tracking->tracks.first;
+ track != NULL;
+ track = track->next)
+ {
+ if (is_usable_for_stabilization(ctx, track)) {
+ int startpoint = search_closest_marker_index(track, framenr);
+ retrieve_next_higher_usable_frame(ctx,
+ track,
+ startpoint,
+ framenr,
+ next_higher);
+ retrieve_next_lower_usable_frame(ctx,
+ track,
+ startpoint,
+ framenr,
+ next_lower);
}
+ }
+}
- track = track->next;
+
+/* Find active (enabled) marker closest to the reference frame. */
+static MovieTrackingMarker *get_closest_marker(StabContext *ctx,
+ MovieTrackingTrack *track,
+ int ref_frame)
+{
+ int next_lower = MINAFRAME;
+ int next_higher = MAXFRAME;
+ int i = search_closest_marker_index(track, ref_frame);
+ retrieve_next_higher_usable_frame(ctx, track, i, ref_frame, &next_higher);
+ retrieve_next_lower_usable_frame(ctx, track, i, ref_frame, &next_lower);
+
+ if ((next_higher - ref_frame) < (ref_frame - next_lower)) {
+ return BKE_tracking_marker_get_exact(track, next_higher);
}
+ else {
+ return BKE_tracking_marker_get_exact(track, next_lower);
+ }
+}
- median[0] = (max[0] + min[0]) / 2.0f;
- median[1] = (max[1] + min[1]) / 2.0f;
- return ok;
+/* Retrieve tracking data, if available and applicable for this frame.
+ * The returned weight value signals the validity; data recorded for this
+ * tracking marker on the exact requested frame is output with the full weight
+ * of this track, while gaps in the data sequence cause the weight to go to zero.
+ */
+static MovieTrackingMarker *get_tracking_data_point(
+ StabContext *ctx,
+ MovieTrackingTrack *track,
+ int framenr,
+ float *r_weight)
+{
+ MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, framenr);
+ if (marker != NULL && !(marker->flag & MARKER_DISABLED)) {
+ *r_weight = get_animated_weight(ctx, track, framenr);
+ return marker;
+ }
+ else {
+ /* No marker at this frame (=gap) or marker disabled. */
+ *r_weight = 0.0f;
+ return NULL;
+ }
}
-/* Calculate stabilization data (translation, scale and rotation) from
- * given median of first and current frame medians, tracking data and
- * frame number.
+
+/* Define the reference point for rotation/scale measurement and compensation.
+ * The stabilizator works by assuming the image was distorted by a affine linear
+ * transform, i.e. it was rotated and stretched around this reference point
+ * (pivot point) and then shifted laterally. Any scale and orientation changes
+ * will be picked up relative to this point. And later the image will be
+ * stabilized by rotating around this point. The result can only be as
+ * accurate as this pivot point actually matches the real rotation center
+ * of the actual movements. Thus any scheme to define a pivot point is
+ * always guesswork.
*
- * NOTE: frame number should be in clip space, not scene space
+ * As a simple default, we use the weighted average of the location markers
+ * of the current frame as pivot point. TODO It is planned to add further
+ * options, like e.g. anchoring the pivot point at the canvas. Moreover,
+ * it is planned to allow for a user controllable offset.
*/
-static void stabilization_calculate_data(MovieTracking *tracking, int framenr, int width, int height,
- const float firstmedian[2], const float median[2],
- float translation[2], float *scale, float *angle)
+static void setup_pivot(const float ref_pos[2], float r_pivot[2])
{
- MovieTrackingStabilization *stab = &tracking->stabilization;
+ zero_v2(r_pivot); /* TODO: add an animated offset position here. */
+ add_v2_v2(r_pivot, ref_pos);
+}
- *scale = (stab->scale - 1.0f) * stab->scaleinf + 1.0f;
- *angle = 0.0f;
- translation[0] = (firstmedian[0] - median[0]) * width * (*scale);
- translation[1] = (firstmedian[1] - median[1]) * height * (*scale);
+/* Calculate the contribution of a single track at the time position (frame) of
+ * the given marker. Each track has a local reference frame, which is as close
+ * as possible to the global anchor_frame. Thus the translation contribution is
+ * comprised of the offset relative to the image position at that reference
+ * frame, plus a guess of the contribution for the time span between the
+ * anchor_frame and the local reference frame of this track. The constant part
+ * of this contribution is precomputed initially. At the anchor_frame, by
+ * definition the contribution of all tracks is zero, keeping the frame in place.
+ *
+ * track_ref is per track baseline contribution at reference frame; filled in at
+ * initialization
+ * marker is tracking data to use as contribution for current frame.
+ * result_offset is a total cumulated contribution of this track,
+ * relative to the stabilization anchor_frame,
+ * in normalized (0...1) coordinates.
+ */
+static void translation_contribution(TrackStabilizationBase *track_ref,
+ MovieTrackingMarker *marker,
+ float result_offset[2])
+{
+ add_v2_v2v2(result_offset,
+ track_ref->stabilization_offset_base,
+ marker->pos);
+}
+
+/* Similar to the ::translation_contribution(), the rotation contribution is
+ * comprised of the contribution by this individual track, and the averaged
+ * contribution from anchor_frame to the ref point of this track.
+ * - Contribution is in terms of angles, -pi < angle < +pi, and all averaging
+ * happens in this domain.
+ * - Yet the actual measurement happens as vector between pivot and the current
+ * tracking point
+ * - Currently we use the center of frame as approximation for the rotation pivot
+ * point.
+ * - Moreover, the pivot point has to be compensated for the already determined
+ * shift offset, in order to get the pure rotation around the pivot.
+ * To turn this into a _contribution_, the likewise corrected angle at the
+ * reference frame has to be subtracted, to get only the pure angle difference
+ * this tracking point has captured.
+ * - To get from vectors to angles, we have to go through an arcus tangens,
+ * which involves the issue of the definition range: the resulting angles will
+ * flip by 360deg when the measured vector passes from the 2nd to the third
+ * quadrant, thus messing up the average calculation. Since _any_ tracking
+ * point might be used, these problems are quite common in practice.
+ * - Thus we perform the subtraction of the reference and the addition of the
+ * baseline contribution in polar coordinates as simple addition of angles;
+ * since these parts are fixed, we can bake them into a rotation matrix.
+ * With this approach, the border of the arcus tangens definition range will
+ * be reached only, when the _whole_ contribution approaches +- 180deg,
+ * meaning we've already tilted the frame upside down. This situation is way
+ * less common and can be tolerated.
+ * - As an additional feature, when activated, also changes in image scale
+ * relative to the rotation center can be picked up. To handle those values
+ * in the same framework, we average the scales as logarithms.
+ *
+ * aspect is a total aspect ratio of the undistorted image (includes fame and
+ * pixel aspect). The function returns a quality factor, which can be used
+ * to damp the contributions of points in close proximity to the pivot point,
+ * since such contributions might be dominated by rounding errors and thus
+ * poison the calculated average. When the quality factor goes towards zero,
+ * the weight of this contribution should be reduced accordingly.
+ */
+static float rotation_contribution(TrackStabilizationBase *track_ref,
+ MovieTrackingMarker *marker,
+ const float aspect,
+ const float pivot[2],
+ float *result_angle,
+ float *result_scale)
+{
+ float len, quality;
+ float pos[2];
+ sub_v2_v2v2(pos, marker->pos, pivot);
- mul_v2_fl(translation, stab->locinf);
+ pos[0] *= aspect;
+ mul_m2v2(track_ref->stabilization_rotation_base, pos);
- if ((stab->flag & TRACKING_STABILIZE_ROTATION) && stab->rot_track && stab->rotinf) {
- MovieTrackingMarker *marker;
- float a[2], b[2];
- float x0 = (float)width / 2.0f, y0 = (float)height / 2.0f;
- float x = median[0] * width, y = median[1] * height;
+ *result_angle = atan2f(pos[1],pos[0]);
- marker = BKE_tracking_marker_get(stab->rot_track, 1);
- sub_v2_v2v2(a, marker->pos, firstmedian);
- a[0] *= width;
- a[1] *= height;
+ len = len_v2(pos);
- marker = BKE_tracking_marker_get(stab->rot_track, framenr);
- sub_v2_v2v2(b, marker->pos, median);
- b[0] *= width;
- b[1] *= height;
+ /* prevent points very close to the pivot point from poisoning the result */
+ quality = 1 - expf(-len*len / SCALE_ERROR_LIMIT_BIAS*SCALE_ERROR_LIMIT_BIAS);
+ len += SCALE_ERROR_LIMIT_BIAS;
- *angle = -atan2f(a[0] * b[1] - a[1] * b[0], a[0] * b[0] + a[1] * b[1]);
- *angle *= stab->rotinf;
+ *result_scale = len * track_ref->stabilization_scale_base;
+ BLI_assert(0.0 < *result_scale);
- /* convert to rotation around image center */
- translation[0] -= (x0 + (x - x0) * cosf(*angle) - (y - y0) * sinf(*angle) - x) * (*scale);
- translation[1] -= (y0 + (x - x0) * sinf(*angle) + (y - y0) * cosf(*angle) - y) * (*scale);
- }
+ return quality;
}
-/* Calculate factor of a scale, which will eliminate black areas
- * appearing on the frame caused by frame translation.
+
+/* Workaround to allow for rotation around an arbitrary pivot point.
+ * Currently, the public API functions do not support this flexibility.
+ * Rather, rotation will always be applied around a fixed origin.
+ * As a workaround, we shift the image after rotation to match the
+ * desired rotation centre. And since this offset needs to be applied
+ * after the rotation and scaling, we can collapse it with the
+ * translation compensation, which is also a lateral shift (offset).
+ * The offset to apply is intended_pivot - rotated_pivot
*/
-static float stabilization_calculate_autoscale_factor(MovieTracking *tracking, int width, int height)
+static void compensate_rotation_center(const int size, float aspect,
+ const float angle,
+ const float scale,
+ const float pivot[2],
+ float result_translation[2])
{
- float firstmedian[2];
+ const float origin[2] = {0.5f*aspect*size, 0.5f*size};
+ float intended_pivot[2], rotated_pivot[2];
+ float rotation_mat[2][2];
+
+ copy_v2_v2(intended_pivot, pivot);
+ copy_v2_v2(rotated_pivot, pivot);
+ rotate_m2(rotation_mat, +angle);
+ sub_v2_v2(rotated_pivot, origin);
+ mul_m2v2(rotation_mat, rotated_pivot);
+ mul_v2_fl(rotated_pivot, scale);
+ add_v2_v2(rotated_pivot, origin);
+ add_v2_v2(result_translation, intended_pivot);
+ sub_v2_v2(result_translation, rotated_pivot);
+}
+
+
+/* Weighted average of the per track cumulated contributions at given frame.
+ * Returns truth if all desired calculations could be done and all averages are
+ * available.
+ *
+ * NOTE: Even if the result is not `true`, the returned translation and angle
+ * are always sensible and as good as can be. Especially in the
+ * initialization phase we might not be able to get any average (yet) or
+ * get only a translation value. Since initialization visits tracks in a
+ * specific order, starting from anchor_frame, the result is logically
+ * correct non the less. But under normal operation conditions,
+ * a result of `false` should disable the stabilization function
+ */
+static bool average_track_contributions(StabContext *ctx,
+ int framenr,
+ float aspect,
+ float r_translation[2],
+ float r_pivot[2],
+ float *r_angle,
+ float *r_scale_step)
+{
+ bool ok;
+ float weight_sum;
+ MovieTrackingTrack *track;
+ MovieTracking *tracking = ctx->tracking;
MovieTrackingStabilization *stab = &tracking->stabilization;
- float aspect = tracking->camera.pixel_aspect;
-
- /* Early output if stabilization data is already up-to-date. */
- if (stab->ok)
- return stab->scale;
-
- /* See comment in BKE_tracking_stabilization_data_get about first frame. */
- if (stabilization_median_point_get(tracking, 1, firstmedian)) {
- int sfra = INT_MAX, efra = INT_MIN, cfra;
- float scale = 1.0f;
- MovieTrackingTrack *track;
-
- stab->scale = 1.0f;
-
- /* Calculate frame range of tracks used for stabilization. */
- track = tracking->tracks.first;
- while (track) {
- if (track->flag & TRACK_USE_2D_STAB ||
- ((stab->flag & TRACKING_STABILIZE_ROTATION) && track == stab->rot_track))
- {
- sfra = min_ii(sfra, track->markers[0].framenr);
- efra = max_ii(efra, track->markers[track->markersnr - 1].framenr);
- }
+ float ref_pos[2];
+ BLI_assert(stab->flag & TRACKING_2D_STABILIZATION);
- track = track->next;
+ zero_v2(r_translation);
+ *r_scale_step = 0.0f; /* logarithm */
+ *r_angle = 0.0f;
+
+ zero_v2(ref_pos);
+
+ ok = false;
+ weight_sum = 0.0f;
+ for (track = tracking->tracks.first; track; track = track->next) {
+ if (!is_init_for_stabilization(ctx, track)) {
+ continue;
+ }
+ if (track->flag & TRACK_USE_2D_STAB) {
+ float weight = 0.0f;
+ MovieTrackingMarker *marker = get_tracking_data_point(ctx,
+ track,
+ framenr,
+ &weight);
+ if (marker) {
+ TrackStabilizationBase *stabilization_base =
+ access_stabilization_baseline_data(ctx, track);
+ BLI_assert(stabilization_base != NULL);
+ float offset[2];
+ weight_sum += weight;
+ translation_contribution(stabilization_base, marker, offset);
+ r_translation[0] += weight * offset[0];
+ r_translation[1] += weight * offset[1];
+ ref_pos[0] += weight * marker->pos[0];
+ ref_pos[1] += weight * marker->pos[1];
+ ok |= (weight_sum > EPSILON_WEIGHT);
+ }
}
+ }
+ if (!ok) {
+ return false;
+ }
+
+ ref_pos[0] /= weight_sum;
+ ref_pos[1] /= weight_sum;
+ r_translation[0] /= weight_sum;
+ r_translation[1] /= weight_sum;
+ setup_pivot(ref_pos, r_pivot);
+
+ if (!(stab->flag & TRACKING_STABILIZE_ROTATION)) {
+ return ok;
+ }
- /* For every frame we calculate scale factor needed to eliminate black
- * area and choose largest scale factor as final one.
+ ok = false;
+ weight_sum = 0.0f;
+ for (track = tracking->tracks.first; track; track = track->next) {
+ if (!is_init_for_stabilization(ctx, track)) {
+ continue;
+ }
+ if (track->flag & TRACK_USE_2D_STAB_ROT) {
+ float weight = 0.0f;
+ MovieTrackingMarker *marker = get_tracking_data_point(ctx,
+ track,
+ framenr,
+ &weight);
+ if (marker) {
+ TrackStabilizationBase *stabilization_base =
+ access_stabilization_baseline_data(ctx, track);
+ BLI_assert(stabilization_base != NULL);
+ float rotation, scale, quality;
+ quality = rotation_contribution(stabilization_base,
+ marker,
+ aspect,
+ r_pivot,
+ &rotation,
+ &scale);
+ weight *= quality;
+ weight_sum += weight;
+ *r_angle += rotation * weight;
+ if (stab->flag & TRACKING_STABILIZE_SCALE) {
+ *r_scale_step += logf(scale) * weight;
+ }
+ else {
+ *r_scale_step = 0;
+ }
+ ok |= (weight_sum > EPSILON_WEIGHT);
+ }
+ }
+ }
+ if (ok) {
+ *r_scale_step /= weight_sum;
+ *r_angle /= weight_sum;
+ }
+ else {
+ /* We reach this point because translation could be calculated,
+ * but rotation/scale found no data to work on.
*/
- for (cfra = sfra; cfra <= efra; cfra++) {
- float median[2];
- float translation[2], angle, tmp_scale;
- int i;
- float mat[4][4];
- float points[4][2] = {{0.0f, 0.0f}, {0.0f, height}, {width, height}, {width, 0.0f}};
- float si, co;
+ *r_scale_step = 0.0f;
+ *r_angle = 0.0f;
+ }
+ return true;
+}
- stabilization_median_point_get(tracking, cfra, median);
- stabilization_calculate_data(tracking, cfra, width, height, firstmedian, median, translation,
- &tmp_scale, &angle);
+/* Calculate weight center of location tracks for given frame.
+ * This function performs similar calculations as average_track_contributions(),
+ * but does not require the tracks to be initialized for stabilisation. Moreover,
+ * when there is no usable tracking data for the given frame number, data from
+ * a neighbouring frame is used. Thus this function can be used to calculate
+ * a starting point on initialization.
+ */
+static void average_marker_positions(StabContext *ctx, int framenr, float r_ref_pos[2])
+{
+ bool ok = false;
+ float weight_sum;
+ MovieTrackingTrack *track;
+ MovieTracking *tracking = ctx->tracking;
- BKE_tracking_stabilization_data_to_mat4(width, height, aspect, translation, 1.0f, angle, mat);
+ zero_v2(r_ref_pos);
+ weight_sum = 0.0f;
+ for (track = tracking->tracks.first; track; track = track->next) {
+ if (track->flag & TRACK_USE_2D_STAB) {
+ float weight = 0.0f;
+ MovieTrackingMarker *marker =
+ get_tracking_data_point(ctx, track, framenr, &weight);
+ if (marker) {
+ weight_sum += weight;
+ r_ref_pos[0] += weight * marker->pos[0];
+ r_ref_pos[1] += weight * marker->pos[1];
+ ok |= (weight_sum > EPSILON_WEIGHT);
+ }
+ }
+ }
+ if (ok) {
+ r_ref_pos[0] /= weight_sum;
+ r_ref_pos[1] /= weight_sum;
+ } else {
+ /* No usable tracking data on any track on this frame.
+ * Use data from neighbouring frames to extrapolate...
+ */
+ int next_lower = MINAFRAME;
+ int next_higher = MAXFRAME;
+ use_values_from_fcurves(ctx, true);
+ for (track = tracking->tracks.first; track; track = track->next) {
+ /* Note: we deliberately do not care if this track
+ * is already initialized for stabilisation */
+ if (track->flag & TRACK_USE_2D_STAB) {
+ int startpoint = search_closest_marker_index(track, framenr);
+ retrieve_next_higher_usable_frame(ctx,
+ track,
+ startpoint,
+ framenr,
+ &next_higher);
+ retrieve_next_lower_usable_frame(ctx,
+ track,
+ startpoint,
+ framenr,
+ &next_lower);
+ }
+ }
+ if (next_lower >= MINFRAME) {
+ /* use next usable frame to the left.
+ * Also default to this frame when we're in a gap */
+ average_marker_positions(ctx, next_lower, r_ref_pos);
- si = sinf(angle);
- co = cosf(angle);
+ } else if (next_higher < MAXFRAME) {
+ average_marker_positions(ctx, next_higher, r_ref_pos);
+ }
+ use_values_from_fcurves(ctx, false);
+ }
+}
- for (i = 0; i < 4; i++) {
- int j;
- float a[3] = {0.0f, 0.0f, 0.0f}, b[3] = {0.0f, 0.0f, 0.0f};
- copy_v3_v3(a, points[i]);
- copy_v3_v3(b, points[(i + 1) % 4]);
+/* Linear interpolation of data retrieved at two measurement points.
+ * This function is used to fill gaps in the middle of the covered area,
+ * at frames without any usable tracks for stabilization.
+ *
+ * framenr is a position to interpolate for.
+ * frame_a is a valid measurement point below framenr
+ * frame_b is a valid measurement point above framenr
+ * Returns truth if both measurements could actually be retrieved.
+ * Otherwise output parameters remain unaltered
+ */
+static bool interpolate_averaged_track_contributions(StabContext *ctx,
+ int framenr,
+ int frame_a,
+ int frame_b,
+ const float aspect,
+ float r_translation[2],
+ float r_pivot[2],
+ float *r_angle,
+ float *r_scale_step)
+{
+ float t, s;
+ float trans_a[2], trans_b[2];
+ float angle_a, angle_b;
+ float scale_a, scale_b;
+ float pivot_a[2], pivot_b[2];
+ bool success = false;
+
+ BLI_assert(frame_a <= frame_b);
+ BLI_assert(frame_a <= framenr);
+ BLI_assert(framenr <= frame_b);
+
+ t = ((float)framenr - frame_a) / (frame_b - frame_a);
+ s = 1.0f - t;
+
+ success = average_track_contributions(ctx, frame_a, aspect, trans_a, pivot_a, &angle_a, &scale_a);
+ if (!success) {
+ return false;
+ }
+ success = average_track_contributions(ctx, frame_b, aspect, trans_b, pivot_b, &angle_b, &scale_b);
+ if (!success) {
+ return false;
+ }
- mul_m4_v3(mat, a);
- mul_m4_v3(mat, b);
+ interp_v2_v2v2(r_translation, trans_a, trans_b, t);
+ interp_v2_v2v2(r_pivot, pivot_a, pivot_b, t);
+ *r_scale_step = s * scale_a + t * scale_b;
+ *r_angle = s * angle_a + t * angle_b;
+ return true;
+}
- for (j = 0; j < 4; j++) {
- float point[3] = {points[j][0], points[j][1], 0.0f};
- float v1[3], v2[3];
- sub_v3_v3v3(v1, b, a);
- sub_v3_v3v3(v2, point, a);
+/* Reorder tracks starting with those providing a tracking data frame
+ * closest to the global anchor_frame. Tracks with a gap at anchor_frame or
+ * starting farer away from anchor_frame altogether will be visited later.
+ * This allows to build up baseline contributions incrementally.
+ *
+ * order is an array for sorting the tracks. Must be of suitable size to hold
+ * all tracks.
+ * Returns number of actually usable tracks, can be less than the overall number
+ * of tracks.
+ *
+ * NOTE: After returning, the order array holds entries up to the number of
+ * usable tracks, appropriately sorted starting with the closest tracks.
+ * Initialization includes disabled tracks, since they might be enabled
+ * through automation later.
+ */
+static int establish_track_initialization_order(StabContext *ctx,
+ TrackInitOrder *order)
+{
+ size_t tracknr = 0;
+ MovieTrackingTrack *track;
+ MovieTracking *tracking = ctx->tracking;
+ int anchor_frame = tracking->stabilization.anchor_frame;
- if (cross_v2v2(v1, v2) >= 0.0f) {
- const float rotDx[4][2] = {{1.0f, 0.0f}, {0.0f, -1.0f}, {-1.0f, 0.0f}, {0.0f, 1.0f}};
- const float rotDy[4][2] = {{0.0f, 1.0f}, {1.0f, 0.0f}, {0.0f, -1.0f}, {-1.0f, 0.0f}};
+ for (track = tracking->tracks.first; track != NULL; track = track->next) {
+ MovieTrackingMarker *marker;
+ order[tracknr].data = track;
+ marker = get_closest_marker(ctx, track, anchor_frame);
+ if (marker != NULL &&
+ (track->flag & (TRACK_USE_2D_STAB | TRACK_USE_2D_STAB_ROT)))
+ {
+ order[tracknr].sort_value = abs(marker->framenr - anchor_frame);
+ order[tracknr].reference_frame = marker->framenr;
+ ++tracknr;
+ }
+ }
+ if (tracknr) {
+ qsort(order, tracknr, sizeof(TrackInitOrder), BLI_sortutil_cmp_int);
+ }
+ return tracknr;
+}
- float dx = translation[0] * rotDx[j][0] + translation[1] * rotDx[j][1],
- dy = translation[0] * rotDy[j][0] + translation[1] * rotDy[j][1];
- float w, h, E, F, G, H, I, J, K, S;
+/* Setup the constant part of this track's contribution to the determined frame
+ * movement. Tracks usually don't provide tracking data for every frame. Thus,
+ * for determining data at a given frame, we split up the contribution into a
+ * part covered by actual measurements on this track, and the initial gap
+ * between this track's reference frame and the global anchor_frame.
+ * The (missing) data for the gap can be substituted by the average offset
+ * observed by the other tracks covering the gap. This approximation doesn't
+ * introduce wrong data, but it records data with incorrect weight. A totally
+ * correct solution would require us to average the contribution per frame, and
+ * then integrate stepwise over all frames -- which of course would be way more
+ * expensive, especially for longer clips. To the contrary, our solution
+ * cumulates the total contribution per track and averages afterwards over all
+ * tracks; it can thus be calculated just based on the data of a single frame,
+ * plus the "baseline" for the reference frame, which is what we are computing
+ * here.
+ *
+ * Since we're averaging _contributions_, we have to calculate the _difference_
+ * of the measured position at current frame and the position at the reference
+ * frame. But the "reference" part of this difference is constant and can thus
+ * be packed together with the baseline contribution into a single precomputed
+ * vector per track.
+ *
+ * In case of the rotation contribution, the principle is the same, but we have
+ * to compensate for the already determined translation and measure the pure
+ * rotation, simply because this is how we model the offset: shift plus rotation
+ * around the shifted rotation center. To circumvent problems with the
+ * definition range of the arcus tangens function, we perform this baseline
+ * addition and reference angle subtraction in polar coordinates and bake this
+ * operation into a precomputed rotation matrix.
+ *
+ * track is a track to be initialized to initialize
+ * reference_frame is a local frame for this track, the closest pick to the
+ * global anchor_frame.
+ * aspect is a total aspect ratio of the undistorted image (includes fame and
+ * pixel aspect).
+ * target_pos is a possibly animated target position as set by the user for
+ * the reference_frame
+ * average_translation is a value observed by the _other_ tracks for the gap
+ * between reference_frame and anchor_frame. This
+ * average must not contain contributions of frames
+ * not yet initialized
+ * average_angle in a similar way, the rotation value observed by the
+ * _other_ tracks.
+ * average_scale_step is an image scale factor observed on average by the other
+ * tracks for this frame. This value is recorded and
+ * averaged as logarithm. The recorded scale changes
+ * are damped for very small contributions, to limit
+ * the effect of probe points approaching the pivot
+ * too closely.
+ *
+ * NOTE: when done, this track is marked as initialized
+ */
+static void initialize_track_for_stabilization(StabContext *ctx,
+ MovieTrackingTrack *track,
+ int reference_frame,
+ float aspect,
+ const float average_translation[2],
+ const float pivot[2],
+ const float average_angle,
+ const float average_scale_step)
+{
+ float pos[2], angle, len;
+ TrackStabilizationBase *local_data =
+ access_stabilization_baseline_data(ctx, track);
+ MovieTrackingMarker *marker =
+ BKE_tracking_marker_get_exact(track, reference_frame);
+ /* Logic for initialization order ensures there *is* a marker on that
+ * very frame.
+ */
+ BLI_assert(marker != NULL);
+ BLI_assert(local_data != NULL);
- if (j % 2) {
- w = (float)height / 2.0f;
- h = (float)width / 2.0f;
- }
- else {
- w = (float)width / 2.0f;
- h = (float)height / 2.0f;
- }
+ /* Per track baseline value for translation. */
+ sub_v2_v2v2(local_data->stabilization_offset_base,
+ average_translation,
+ marker->pos);
- E = -w * co + h * si;
- F = -h * co - w * si;
+ /* Per track baseline value for rotation. */
+ sub_v2_v2v2(pos, marker->pos, pivot);
- if ((i % 2) == (j % 2)) {
- G = -w * co - h * si;
- H = h * co - w * si;
- }
- else {
- G = w * co + h * si;
- H = -h * co + w * si;
- }
+ pos[0] *= aspect;
+ angle = average_angle - atan2f(pos[1],pos[0]);
+ rotate_m2(local_data->stabilization_rotation_base, angle);
- I = F - H;
- J = G - E;
- K = G * F - E * H;
+ /* Per track baseline value for zoom. */
+ len = len_v2(pos) + SCALE_ERROR_LIMIT_BIAS;
+ local_data->stabilization_scale_base = expf(average_scale_step) / len;
- S = (-w * I - h * J) / (dx * I + dy * J + K);
+ local_data->is_init_for_stabilization = true;
+}
- scale = max_ff(scale, S);
- }
- }
- }
+
+static void initialize_all_tracks(StabContext *ctx, float aspect)
+{
+ size_t i, track_cnt = 0;
+ MovieClip *clip = ctx->clip;
+ MovieTracking *tracking = ctx->tracking;
+ MovieTrackingTrack *track;
+ TrackInitOrder *order;
+
+ /* Attempt to start initialization at anchor_frame.
+ * By definition, offset contribution is zero there.
+ */
+ int reference_frame = tracking->stabilization.anchor_frame;
+ float average_angle=0, average_scale_step=0;
+ float average_translation[2], average_pos[2], pivot[2];
+ zero_v2(average_translation);
+ zero_v2(pivot);
+
+ /* Initialize private working data. */
+ for (track = tracking->tracks.first; track != NULL; track = track->next) {
+ TrackStabilizationBase *local_data =
+ access_stabilization_baseline_data(ctx, track);
+ if (!local_data) {
+ local_data = MEM_callocN(sizeof(TrackStabilizationBase),
+ "2D stabilization per track baseline data");
+ attach_stabilization_baseline_data(ctx, track, local_data);
}
+ BLI_assert(local_data != NULL);
+ local_data->track_weight_curve = retrieve_track_weight_animation(clip,
+ track);
+ local_data->is_init_for_stabilization = false;
- stab->scale = scale;
+ ++track_cnt;
+ }
+ if (!track_cnt) {
+ return;
+ }
- if (stab->maxscale > 0.0f)
- stab->scale = min_ff(stab->scale, stab->maxscale);
+ order = MEM_mallocN(track_cnt * sizeof(TrackInitOrder),
+ "stabilization track order");
+ if (!order) {
+ return;
}
- else {
- stab->scale = 1.0f;
+
+ track_cnt = establish_track_initialization_order(ctx, order);
+ if (track_cnt == 0) {
+ goto cleanup;
}
- stab->ok = true;
+ /* starting point for pivot, before having initialized any track */
+ average_marker_positions(ctx, reference_frame, average_pos);
+ setup_pivot(average_pos, pivot);
+
+ for (i = 0; i < track_cnt; ++i) {
+ track = order[i].data;
+ if (reference_frame != order[i].reference_frame) {
+ reference_frame = order[i].reference_frame;
+ average_track_contributions(ctx,
+ reference_frame,
+ aspect,
+ average_translation,
+ pivot,
+ &average_angle,
+ &average_scale_step);
+ }
+ initialize_track_for_stabilization(ctx,
+ track,
+ reference_frame,
+ aspect,
+ average_translation,
+ pivot,
+ average_angle,
+ average_scale_step);
+ }
- return stab->scale;
+cleanup:
+ MEM_freeN(order);
}
-/* Get stabilization data (translation, scaling and angle) for a given frame.
+
+/* Retrieve the measurement of frame movement by averaging contributions of
+ * active tracks.
*
- * NOTE: frame number should be in clip space, not scene space
+ * translation is a measurement in normalized 0..1 coordinates.
+ * angle is a measurement in radians -pi..+pi counter clockwise relative to
+ * translation compensated frame center
+ * scale_step is a measurement of image scale changes, in logarithmic scale
+ * (zero means scale == 1)
+ * Returns calculation enabled and all data retrieved as expected for this frame.
+ *
+ * NOTE: when returning `false`, output parameters are reset to neutral values.
*/
-void BKE_tracking_stabilization_data_get(MovieTracking *tracking, int framenr, int width, int height,
- float translation[2], float *scale, float *angle)
+static bool stabilization_determine_offset_for_frame(StabContext *ctx,
+ int framenr,
+ float aspect,
+ float r_translation[2],
+ float r_pivot[2],
+ float *r_angle,
+ float *r_scale_step)
{
- float firstmedian[2], median[2];
- MovieTrackingStabilization *stab = &tracking->stabilization;
+ bool success = false;
/* Early output if stabilization is disabled. */
- if ((stab->flag & TRACKING_2D_STABILIZATION) == 0) {
- zero_v2(translation);
- *scale = 1.0f;
- *angle = 0.0f;
+ if ((ctx->stab->flag & TRACKING_2D_STABILIZATION) == 0) {
+ zero_v2(r_translation);
+ *r_scale_step = 0.0f;
+ *r_angle = 0.0f;
+ return false;
+ }
- return;
+ success = average_track_contributions(ctx,
+ framenr,
+ aspect,
+ r_translation,
+ r_pivot,
+ r_angle,
+ r_scale_step);
+ if (!success) {
+ /* Try to hold extrapolated settings beyond the definition range
+ * and to interpolate in gaps without any usable tracking data
+ * to prevent sudden jump to image zero position.
+ */
+ int next_lower = MINAFRAME;
+ int next_higher = MAXFRAME;
+ use_values_from_fcurves(ctx, true);
+ find_next_working_frames(ctx, framenr, &next_lower, &next_higher);
+ if (next_lower >= MINFRAME && next_higher < MAXFRAME) {
+ success = interpolate_averaged_track_contributions(ctx,
+ framenr,
+ next_lower,
+ next_higher,
+ aspect,
+ r_translation,
+ r_pivot,
+ r_angle,
+ r_scale_step);
+ }
+ else if (next_higher < MAXFRAME) {
+ /* Before start of stabilized range: extrapolate start point
+ * settings.
+ */
+ success = average_track_contributions(ctx,
+ next_higher,
+ aspect,
+ r_translation,
+ r_pivot,
+ r_angle,
+ r_scale_step);
+ }
+ else if (next_lower >= MINFRAME) {
+ /* After end of stabilized range: extrapolate end point settings. */
+ success = average_track_contributions(ctx,
+ next_lower,
+ aspect,
+ r_translation,
+ r_pivot,
+ r_angle,
+ r_scale_step);
+ }
+ use_values_from_fcurves(ctx, false);
}
+ return success;
+}
- /* Even if tracks does not start at frame 1, their position will
- * be estimated at this frame, which will give reasonable result
- * in most of cases.
- *
- * However, it's still better to replace this with real first
- * frame number at which tracks are appearing.
+/* Calculate stabilization data (translation, scale and rotation) from given raw
+ * measurements. Result is in absolute image dimensions (expanded image, square
+ * pixels), includes automatic or manual scaling and compensates for a target
+ * frame position, if given.
+ *
+ * size is a size of the expanded image, the width in pixels is size * aspect.
+ * aspect is a ratio (width / height) of the effective canvas (square pixels).
+ * do_compensate denotes whether to actually output values necessary to
+ * _compensate_ the determined frame movement.
+ * Otherwise, the effective target movement is returned.
+ */
+static void stabilization_calculate_data(StabContext *ctx,
+ int framenr,
+ int size,
+ float aspect,
+ bool do_compensate,
+ float scale_step,
+ float r_translation[2],
+ float r_pivot[2],
+ float *r_scale,
+ float *r_angle)
+{
+ float target_pos[2], target_scale;
+ float scaleinf = get_animated_scaleinf(ctx, framenr);
+
+ if (ctx->stab->flag & TRACKING_STABILIZE_SCALE) {
+ *r_scale = expf(scale_step * scaleinf); /* Averaged in log scale */
+ } else {
+ *r_scale = 1.0f;
+ }
+
+ mul_v2_fl(r_translation, get_animated_locinf(ctx, framenr));
+ *r_angle *= get_animated_rotinf(ctx, framenr);
+
+ /* Compensate for a target frame position.
+ * This allows to follow tracking / panning shots in a semi manual fashion,
+ * when animating the settings for the target frame position.
*/
- if (stabilization_median_point_get(tracking, 1, firstmedian)) {
- stabilization_median_point_get(tracking, framenr, median);
+ get_animated_target_pos(ctx, framenr, target_pos);
+ sub_v2_v2(r_translation, target_pos);
+ *r_angle -= get_animated_target_rot(ctx,framenr);
+ target_scale = get_animated_target_scale(ctx,framenr);
+ if (target_scale != 0.0f) {
+ *r_scale /= target_scale;
+ /* target_scale is an expected/intended reference zoom value */
+ }
+
+ /* Convert from relative to absolute coordinates, square pixels. */
+ r_translation[0] *= (float)size * aspect;
+ r_translation[1] *= (float)size;
+ r_pivot[0] *= (float)size * aspect;
+ r_pivot[1] *= (float)size;
+
+ /* Output measured data, or inverse of the measured values for
+ * compensation?
+ */
+ if (do_compensate) {
+ mul_v2_fl(r_translation, -1.0f);
+ *r_angle *= -1.0f;
+ if (*r_scale != 0.0f) {
+ *r_scale = 1.0f / *r_scale;
+ }
+ }
+}
+
+static void stabilization_data_to_mat4(float pixel_aspect,
+ const float pivot[2],
+ const float translation[2],
+ float scale,
+ float angle,
+ float r_mat[4][4])
+{
+ float translation_mat[4][4], rotation_mat[4][4], scale_mat[4][4],
+ pivot_mat[4][4], inv_pivot_mat[4][4],
+ aspect_mat[4][4], inv_aspect_mat[4][4];
+ float scale_vector[3] = {scale, scale, 1.0f};
- if ((stab->flag & TRACKING_AUTOSCALE) == 0)
- stab->scale = 1.0f;
+ unit_m4(translation_mat);
+ unit_m4(rotation_mat);
+ unit_m4(scale_mat);
+ unit_m4(aspect_mat);
+ unit_m4(pivot_mat);
+ unit_m4(inv_pivot_mat);
- if (!stab->ok) {
- if (stab->flag & TRACKING_AUTOSCALE)
- stabilization_calculate_autoscale_factor(tracking, width, height);
+ /* aspect ratio correction matrix */
+ aspect_mat[0][0] /= pixel_aspect;
+ invert_m4_m4(inv_aspect_mat, aspect_mat);
- stabilization_calculate_data(tracking, framenr, width, height, firstmedian, median,
- translation, scale, angle);
+ add_v2_v2(pivot_mat[3], pivot);
+ sub_v2_v2(inv_pivot_mat[3], pivot);
- stab->ok = true;
+ size_to_mat4(scale_mat, scale_vector); /* scale matrix */
+ add_v2_v2(translation_mat[3], translation); /* translation matrix */
+ rotate_m4(rotation_mat, 'Z', angle); /* rotation matrix */
+
+ /* Compose transformation matrix. */
+ mul_m4_series(r_mat, aspect_mat, translation_mat,
+ pivot_mat, scale_mat, rotation_mat, inv_pivot_mat,
+ inv_aspect_mat);
+}
+
+/* Calculate scale factor necessary to eliminate black image areas
+ * caused by the compensating movements of the stabilizator.
+ * This function visits every frame where stabilisation data is
+ * available and determines the factor for this frame. The overall
+ * largest factor found is returned as result.
+ *
+ * NOTE: all tracks need to be initialized before calling this function.
+ */
+static float calculate_autoscale_factor(StabContext *ctx,
+ int size,
+ float aspect)
+{
+ MovieTrackingStabilization *stab = ctx->stab;
+ float pixel_aspect = ctx->tracking->camera.pixel_aspect;
+ int height = size, width = aspect*size;
+
+ int sfra = INT_MAX, efra = INT_MIN, cfra;
+ float scale = 1.0f, scale_step = 0.0f;
+ MovieTrackingTrack *track;
+
+ /* Calculate maximal frame range of tracks where stabilization is active. */
+ for (track = ctx->tracking->tracks.first; track; track = track->next) {
+ if ((track->flag & TRACK_USE_2D_STAB) ||
+ ((stab->flag & TRACKING_STABILIZE_ROTATION) &&
+ (track->flag & TRACK_USE_2D_STAB_ROT)))
+ {
+ int first_frame = track->markers[0].framenr;
+ int last_frame = track->markers[track->markersnr - 1].framenr;
+ sfra = min_ii(sfra, first_frame);
+ efra = max_ii(efra, last_frame);
}
- else {
- stabilization_calculate_data(tracking, framenr, width, height, firstmedian, median,
- translation, scale, angle);
+ }
+
+ use_values_from_fcurves(ctx, true);
+ for (cfra = sfra; cfra <= efra; cfra++) {
+ float translation[2], pivot[2], angle, tmp_scale;
+ float mat[4][4];
+ const float points[4][2] = {{0.0f, 0.0f},
+ {0.0f, height},
+ {width, height},
+ {width, 0.0f}};
+ const bool do_compensate = true;
+ /* Calculate stabilization parameters for the current frame. */
+ stabilization_determine_offset_for_frame(ctx,
+ cfra,
+ aspect,
+ translation,
+ pivot,
+ &angle,
+ &scale_step);
+ stabilization_calculate_data(ctx,
+ cfra,
+ size,
+ aspect,
+ do_compensate,
+ scale_step,
+ translation,
+ pivot,
+ &tmp_scale,
+ &angle);
+ /* Compose transformation matrix. */
+ /* NOTE: Here we operate in NON-COMPENSATED coordinates, meaning we have
+ * to construct transformation matrix using proper pivot point.
+ * Compensation for that will happen later on.
+ */
+ stabilization_data_to_mat4(pixel_aspect,
+ pivot,
+ translation,
+ tmp_scale,
+ angle,
+ mat);
+ /* Investigate the transformed border lines for this frame;
+ * find out, where it cuts the original frame.
+ */
+ for (int edge_index = 0; edge_index < 4; edge_index++) {
+ /* Calculate coordinates of stabilized frame edge points.
+ * Use matrix multiplication here so we operate in homogeneous
+ * coordinates.
+ */
+ float stable_edge_p1[3], stable_edge_p2[3];
+ copy_v2_v2(stable_edge_p1, points[edge_index]);
+ copy_v2_v2(stable_edge_p2, points[(edge_index + 1) % 4]);
+ stable_edge_p1[2] = stable_edge_p2[2] = 0.0f;
+ mul_m4_v3(mat, stable_edge_p1);
+ mul_m4_v3(mat, stable_edge_p2);
+ /* Now we iterate over all original frame corners (we call them
+ * 'point' here) to see if there's black area between stabilized
+ * frame edge and original point.
+ */
+ for (int point_index = 0; point_index < 4; point_index++) {
+ const float point[3] = {points[point_index][0],
+ points[point_index][1],
+ 0.0f};
+ /* Calculate vector which goes from first edge point to
+ * second one.
+ */
+ float stable_edge_vec[3];
+ sub_v3_v3v3(stable_edge_vec, stable_edge_p2, stable_edge_p1);
+ /* Calculate vector which connects current frame point to
+ * first edge point.
+ */
+ float point_to_edge_start_vec[3];
+ sub_v3_v3v3(point_to_edge_start_vec, point, stable_edge_p1);
+ /* Use this two vectors to check whether frame point is inside
+ * of the stabilized frame or not.
+ * If the point is inside, there is no black area happening
+ * and no scaling required for it.
+ */
+ if (cross_v2v2(stable_edge_vec, point_to_edge_start_vec) >= 0.0f) {
+ /* We are scaling around motion-compensated pivot point. */
+ float scale_pivot[2];
+ add_v2_v2v2(scale_pivot, pivot, translation);
+ /* Calculate line which goes via `point` and parallel to
+ * the stabilized frame edge. This line is coming via
+ * `point` and `point2` at the end.
+ */
+ float point2[2];
+ add_v2_v2v2(point2, point, stable_edge_vec);
+ /* Calculate actual distance between pivot point and
+ * the stabilized frame edge. Then calculate distance
+ * between pivot point and line which goes via actual
+ * corner and is parallel to the edge.
+ *
+ * Dividing one by another will give us required scale
+ * factor to get rid of black areas.
+ */
+ float real_dist = dist_to_line_v2(scale_pivot,
+ stable_edge_p1,
+ stable_edge_p2);
+ float required_dist = dist_to_line_v2(scale_pivot,
+ point,
+ point2);
+ const float S = required_dist / real_dist;
+ scale = max_ff(scale, S);
+ }
+ }
}
}
+ if (stab->maxscale > 0.0f) {
+ scale = min_ff(scale, stab->maxscale);
+ }
+ use_values_from_fcurves(ctx, false);
+
+ return scale;
+}
+
+
+/* Prepare working data and determine reference point for each track.
+ *
+ * NOTE: These calculations _could_ be cached and reused for all frames of the
+ * same clip. However, since proper initialization depends on (weight)
+ * animation and setup of tracks, ensuring consistency of cached init data
+ * turns out to be tricky, hard to maintain and generally not worth the
+ * effort. Thus we'll re-initialize on every frame.
+ */
+static StabContext *init_stabilizer(MovieClip *clip, int size, float aspect)
+{
+ StabContext *ctx = initialize_stabilization_working_context(clip);
+ BLI_assert(ctx != NULL);
+ initialize_all_tracks(ctx, aspect);
+ if (ctx->stab->flag & TRACKING_AUTOSCALE) {
+ ctx->stab->scale = 1.0;
+ ctx->stab->scale = calculate_autoscale_factor(ctx, size, aspect);
+ }
+ /* By default, just use values for the global current frame. */
+ use_values_from_fcurves(ctx, false);
+ return ctx;
+}
+
+
+/* === public interface functions === */
+
+/* Get stabilization data (translation, scaling and angle) for a given frame.
+ * Returned data describes how to compensate the detected movement, but with any
+ * chosen scale factor already applied and any target frame position already
+ * compensated. In case stabilization fails or is disabled, neutral values are
+ * returned.
+ *
+ * framenr is a frame number, relative to the clip (not relative to the scene
+ * timeline)
+ * width is an effective width of the canvas (square pixels), used to scale the
+ * determined translation
+ *
+ * Outputs:
+ * - translation of the lateral shift, absolute canvas coordinates
+ * (square pixels).
+ * - scale of the scaling to apply
+ * - angle of the rotation angle, relative to the frame center
+ */
+/* TODO(sergey): Use r_ prefix for output parameters here. */
+void BKE_tracking_stabilization_data_get(MovieClip *clip,
+ int framenr,
+ int width,
+ int height,
+ float translation[2],
+ float *scale,
+ float *angle)
+{
+ StabContext *ctx = NULL;
+ MovieTracking *tracking = &clip->tracking;
+ bool enabled = (tracking->stabilization.flag & TRACKING_2D_STABILIZATION);
+ /* Might become a parameter of a stabilization compositor node. */
+ bool do_compensate = true;
+ float scale_step = 0.0f;
+ float pixel_aspect = tracking->camera.pixel_aspect;
+ float aspect = (float)width * pixel_aspect / height;
+ int size = height;
+ float pivot[2];
+
+ if (enabled) {
+ ctx = init_stabilizer(clip, size, aspect);
+ }
+
+ if (enabled &&
+ stabilization_determine_offset_for_frame(ctx,
+ framenr,
+ aspect,
+ translation,
+ pivot,
+ angle,
+ &scale_step))
+ {
+ stabilization_calculate_data(ctx,
+ framenr,
+ size,
+ aspect,
+ do_compensate,
+ scale_step,
+ translation,
+ pivot,
+ scale,
+ angle);
+ compensate_rotation_center(size,
+ aspect,
+ *angle,
+ *scale,
+ pivot,
+ translation);
+ }
else {
zero_v2(translation);
*scale = 1.0f;
*angle = 0.0f;
}
+ discard_stabilization_working_context(ctx);
}
-/* Stabilize given image buffer using stabilization data for
- * a specified frame number.
+/* Stabilize given image buffer using stabilization data for a specified
+ * frame number.
*
- * NOTE: frame number should be in clip space, not scene space
+ * NOTE: frame number should be in clip space, not scene space.
*/
-ImBuf *BKE_tracking_stabilize_frame(MovieTracking *tracking, int framenr, ImBuf *ibuf,
- float translation[2], float *scale, float *angle)
+/* TODO(sergey): Use r_ prefix for output parameters here. */
+ImBuf *BKE_tracking_stabilize_frame(MovieClip *clip,
+ int framenr,
+ ImBuf *ibuf,
+ float translation[2],
+ float *scale,
+ float *angle)
{
float tloc[2], tscale, tangle;
+ MovieTracking *tracking = &clip->tracking;
MovieTrackingStabilization *stab = &tracking->stabilization;
ImBuf *tmpibuf;
int width = ibuf->x, height = ibuf->y;
- float aspect = tracking->camera.pixel_aspect;
+ float pixel_aspect = tracking->camera.pixel_aspect;
float mat[4][4];
int j, filter = tracking->stabilization.filter;
void (*interpolation)(struct ImBuf *, struct ImBuf *, float, float, int, int) = NULL;
@@ -349,8 +1542,12 @@ ImBuf *BKE_tracking_stabilize_frame(MovieTracking *tracking, int framenr, ImBuf
tmpibuf = IMB_allocImBuf(ibuf->x, ibuf->y, ibuf->planes, ibuf_flags);
/* Calculate stabilization matrix. */
- BKE_tracking_stabilization_data_get(tracking, framenr, width, height, tloc, &tscale, &tangle);
- BKE_tracking_stabilization_data_to_mat4(ibuf->x, ibuf->y, aspect, tloc, tscale, tangle, mat);
+ BKE_tracking_stabilization_data_get(clip, framenr, width, height, tloc, &tscale, &tangle);
+ BKE_tracking_stabilization_data_to_mat4(ibuf->x, ibuf->y, pixel_aspect, tloc, tscale, tangle, mat);
+
+ /* The following code visits each nominal target grid position
+ * and picks interpolated data "backwards" from source.
+ * thus we need the inverse of the transformation to apply. */
invert_m4(mat);
if (filter == TRACKING_FILTER_NEAREST)
@@ -397,48 +1594,44 @@ ImBuf *BKE_tracking_stabilize_frame(MovieTracking *tracking, int framenr, ImBuf
return tmpibuf;
}
-/* Get 4x4 transformation matrix which corresponds to
- * stabilization data and used for easy coordinate
- * transformation.
+
+/* Build a 4x4 transformation matrix based on the given 2D stabilization data.
+ * mat is a 4x4 matrix in homogeneous coordinates, adapted to the
+ * final image buffer size and compensated for pixel aspect ratio,
+ * ready for direct OpenGL drawing.
*
- * NOTE: The reason it is 4x4 matrix is because it's
- * used for OpenGL drawing directly.
+ * TODO(sergey): The signature of this function should be changed. we actually
+ * don't need the dimensions of the image buffer. Instead we
+ * should consider to provide the pivot point of the rotation as a
+ * further stabilization data parameter.
*/
-void BKE_tracking_stabilization_data_to_mat4(int width, int height, float aspect,
- float translation[2], float scale, float angle,
- float mat[4][4])
+void BKE_tracking_stabilization_data_to_mat4(int buffer_width,
+ int buffer_height,
+ float pixel_aspect,
+ float translation[2],
+ float scale,
+ float angle,
+ float r_mat[4][4])
{
- float translation_mat[4][4], rotation_mat[4][4], scale_mat[4][4],
- center_mat[4][4], inv_center_mat[4][4],
- aspect_mat[4][4], inv_aspect_mat[4][4];
- float scale_vector[3] = {scale, scale, scale};
-
- unit_m4(translation_mat);
- unit_m4(rotation_mat);
- unit_m4(scale_mat);
- unit_m4(center_mat);
- unit_m4(aspect_mat);
-
- /* aspect ratio correction matrix */
- aspect_mat[0][0] = 1.0f / aspect;
- invert_m4_m4(inv_aspect_mat, aspect_mat);
-
- /* image center as rotation center
- *
- * Rotation matrix is constructing in a way rotation happens around image center,
- * and it's matter of calculating translation in a way, that applying translation
- * after rotation would make it so rotation happens around median point of tracks
- * used for translation stabilization.
+ /* Since we cannot receive the real pivot point coordinates (API limitation),
+ * we perform the rotation/scale around the center of frame.
+ * Then we correct by an additional shift, which was calculated in
+ * compensate_rotation_center() and "sneaked in" as additional offset
+ * in the translation parameter. This works, since translation needs to be
+ * applied after rotation/scale anyway. Thus effectively the image gets
+ * rotated around the desired pivot point
*/
- center_mat[3][0] = (float)width / 2.0f;
- center_mat[3][1] = (float)height / 2.0f;
- invert_m4_m4(inv_center_mat, center_mat);
-
- size_to_mat4(scale_mat, scale_vector); /* scale matrix */
- add_v2_v2(translation_mat[3], translation); /* translation matrix */
- rotate_m4(rotation_mat, 'Z', angle); /* rotation matrix */
-
- /* compose transformation matrix */
- mul_m4_series(mat, translation_mat, center_mat, aspect_mat, rotation_mat, inv_aspect_mat,
- scale_mat, inv_center_mat);
+ /* TODO(sergey) pivot shouldn't be calculated here, rather received
+ * as a parameter.
+ */
+ float pivot[2];
+ pivot[0] = 0.5f * pixel_aspect * buffer_width;
+ pivot[1] = 0.5f * buffer_height;
+ /* Compose transformation matrix. */
+ stabilization_data_to_mat4(pixel_aspect,
+ pivot,
+ translation,
+ scale,
+ angle,
+ r_mat);
}
diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c
index 3c2444b0ef1..a90b1dee927 100644
--- a/source/blender/blenkernel/intern/tracking_util.c
+++ b/source/blender/blenkernel/intern/tracking_util.c
@@ -529,7 +529,7 @@ typedef struct AccessCacheKey {
static unsigned int accesscache_hashhash(const void *key_v)
{
const AccessCacheKey *key = (const AccessCacheKey *) key_v;
- /* TODP(sergey): Need better hasing here for faster frame access. */
+ /* TODP(sergey): Need better hashing here for faster frame access. */
return key->clip_index << 16 | key->frame;
}
@@ -762,8 +762,8 @@ static ImBuf *accessor_get_ibuf(TrackingImageAccessor *accessor,
final_ibuf = IMB_dupImBuf(orig_ibuf);
}
IMB_scaleImBuf(final_ibuf,
- ibuf->x / (1 << downscale),
- ibuf->y / (1 << downscale));
+ orig_ibuf->x / (1 << downscale),
+ orig_ibuf->y / (1 << downscale));
}
if (transform != NULL) {
@@ -780,7 +780,7 @@ static ImBuf *accessor_get_ibuf(TrackingImageAccessor *accessor,
}
if (input_mode == LIBMV_IMAGE_MODE_RGBA) {
- BLI_assert(ibuf->channels == 3 || ibuf->channels == 4);
+ BLI_assert(orig_ibuf->channels == 3 || orig_ibuf->channels == 4);
/* pass */
}
else /* if (input_mode == LIBMV_IMAGE_MODE_MONO) */ {
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index 17a2e7f14fd..caa9a1e357f 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -46,44 +46,36 @@
#include "BKE_global.h"
#include "BKE_icons.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_world.h"
#include "GPU_material.h"
-void BKE_world_free_ex(World *wrld, bool do_id_user)
+/** Free (or release) any data used by this world (does not free the world itself). */
+void BKE_world_free(World *wrld)
{
- MTex *mtex;
int a;
-
+
+ BKE_animdata_free((ID *)wrld, false);
+
for (a = 0; a < MAX_MTEX; a++) {
- mtex = wrld->mtex[a];
- if (do_id_user && mtex && mtex->tex)
- id_us_min(&mtex->tex->id);
- if (mtex)
- MEM_freeN(mtex);
+ MEM_SAFE_FREE(wrld->mtex[a]);
}
- BKE_previewimg_free(&wrld->preview);
-
- BKE_animdata_free((ID *)wrld);
/* is no lib link block, but world extension */
if (wrld->nodetree) {
- ntreeFreeTree_ex(wrld->nodetree, do_id_user);
+ ntreeFreeTree(wrld->nodetree);
MEM_freeN(wrld->nodetree);
+ wrld->nodetree = NULL;
}
- if (wrld->gpumaterial.first)
- GPU_material_free(&wrld->gpumaterial);
+ GPU_material_free(&wrld->gpumaterial);
BKE_icon_id_delete((struct ID *)wrld);
- wrld->id.icon_id = 0;
-}
-
-void BKE_world_free(World *wrld)
-{
- BKE_world_free_ex(wrld, true);
+ BKE_previewimg_free(&wrld->preview);
}
void BKE_world_init(World *wrld)
@@ -127,12 +119,12 @@ World *add_world(Main *bmain, const char *name)
return wrld;
}
-World *BKE_world_copy(World *wrld)
+World *BKE_world_copy(Main *bmain, World *wrld)
{
World *wrldn;
int a;
- wrldn = BKE_libblock_copy(&wrld->id);
+ wrldn = BKE_libblock_copy(bmain, &wrld->id);
for (a = 0; a < MAX_MTEX; a++) {
if (wrld->mtex[a]) {
@@ -143,17 +135,14 @@ World *BKE_world_copy(World *wrld)
}
if (wrld->nodetree) {
- wrldn->nodetree = ntreeCopyTree(wrld->nodetree);
+ wrldn->nodetree = ntreeCopyTree(bmain, wrld->nodetree);
}
- if (wrld->preview)
- wrldn->preview = BKE_previewimg_copy(wrld->preview);
+ BKE_previewimg_id_copy(&wrldn->id, &wrld->id);
BLI_listbase_clear(&wrldn->gpumaterial);
- if (wrld->id.lib) {
- BKE_id_lib_local_paths(G.main, wrld->id.lib, &wrldn->id);
- }
+ BKE_id_copy_ensure_local(bmain, &wrld->id, &wrldn->id);
return wrldn;
}
@@ -169,8 +158,6 @@ World *localize_world(World *wrld)
if (wrld->mtex[a]) {
wrldn->mtex[a] = MEM_mallocN(sizeof(MTex), "localize_world");
memcpy(wrldn->mtex[a], wrld->mtex[a], sizeof(MTex));
- /* free world decrements */
- id_us_plus((ID *)wrldn->mtex[a]->tex);
}
}
@@ -184,48 +171,7 @@ World *localize_world(World *wrld)
return wrldn;
}
-void BKE_world_make_local(World *wrld)
+void BKE_world_make_local(Main *bmain, World *wrld, const bool lib_local)
{
- Main *bmain = G.main;
- Scene *sce;
- bool is_local = false, is_lib = false;
-
- /* - only lib users: do nothing
- * - only local users: set flag
- * - mixed: make copy
- */
-
- if (wrld->id.lib == NULL) return;
- if (wrld->id.us == 1) {
- id_clear_lib_data(bmain, &wrld->id);
- return;
- }
-
- for (sce = bmain->scene.first; sce && ELEM(false, is_lib, is_local); sce = sce->id.next) {
- if (sce->world == wrld) {
- if (sce->id.lib) is_lib = true;
- else is_local = true;
- }
- }
-
- if (is_local && is_lib == false) {
- id_clear_lib_data(bmain, &wrld->id);
- }
- else if (is_local && is_lib) {
- World *wrld_new = BKE_world_copy(wrld);
- wrld_new->id.us = 0;
-
- /* Remap paths of new ID using old library as base. */
- BKE_id_lib_local_paths(bmain, wrld->id.lib, &wrld_new->id);
-
- for (sce = bmain->scene.first; sce; sce = sce->id.next) {
- if (sce->world == wrld) {
- if (sce->id.lib == NULL) {
- sce->world = wrld_new;
- id_us_plus(&wrld_new->id);
- id_us_min(&wrld->id);
- }
- }
- }
- }
+ BKE_id_make_local_generic(bmain, &wrld->id, true, lib_local);
}
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index edeccf472c8..b0ab6f707fa 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -69,10 +69,14 @@ typedef struct FFMpegContext {
int ffmpeg_video_bitrate;
int ffmpeg_audio_bitrate;
int ffmpeg_gop_size;
+ int ffmpeg_max_b_frames;
int ffmpeg_autosplit;
int ffmpeg_autosplit_count;
bool ffmpeg_preview;
+ int ffmpeg_crf; /* set to 0 to not use CRF mode; we have another flag for lossless anyway. */
+ int ffmpeg_preset; /* see FFMpegPreset */
+
AVFormatContext *outfile;
AVStream *video_stream;
AVStream *audio_stream;
@@ -560,10 +564,37 @@ static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int
}
c->gop_size = context->ffmpeg_gop_size;
- c->bit_rate = context->ffmpeg_video_bitrate * 1000;
- c->rc_max_rate = rd->ffcodecdata.rc_max_rate * 1000;
- c->rc_min_rate = rd->ffcodecdata.rc_min_rate * 1000;
- c->rc_buffer_size = rd->ffcodecdata.rc_buffer_size * 1024;
+ c->max_b_frames = context->ffmpeg_max_b_frames;
+
+ if (context->ffmpeg_crf >= 0) {
+ ffmpeg_dict_set_int(&opts, "crf", context->ffmpeg_crf);
+ } else {
+ c->bit_rate = context->ffmpeg_video_bitrate * 1000;
+ c->rc_max_rate = rd->ffcodecdata.rc_max_rate * 1000;
+ c->rc_min_rate = rd->ffcodecdata.rc_min_rate * 1000;
+ c->rc_buffer_size = rd->ffcodecdata.rc_buffer_size * 1024;
+ }
+
+ if (context->ffmpeg_preset) {
+ char const * preset_name;
+ switch(context->ffmpeg_preset) {
+ case FFM_PRESET_ULTRAFAST: preset_name = "ultrafast"; break;
+ case FFM_PRESET_SUPERFAST: preset_name = "superfast"; break;
+ case FFM_PRESET_VERYFAST: preset_name = "veryfast"; break;
+ case FFM_PRESET_FASTER: preset_name = "faster"; break;
+ case FFM_PRESET_FAST: preset_name = "fast"; break;
+ case FFM_PRESET_MEDIUM: preset_name = "medium"; break;
+ case FFM_PRESET_SLOW: preset_name = "slow"; break;
+ case FFM_PRESET_SLOWER: preset_name = "slower"; break;
+ case FFM_PRESET_VERYSLOW: preset_name = "veryslow"; break;
+ default:
+ printf("Unknown preset number %i, ignoring.\n", context->ffmpeg_preset);
+ preset_name = NULL;
+ }
+ if (preset_name != NULL) {
+ av_dict_set(&opts, "preset", preset_name, 0);
+ }
+ }
#if 0
/* this options are not set in ffmpeg.c and leads to artifacts with MPEG-4
@@ -819,6 +850,12 @@ static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int
context->ffmpeg_audio_bitrate = rd->ffcodecdata.audio_bitrate;
context->ffmpeg_gop_size = rd->ffcodecdata.gop_size;
context->ffmpeg_autosplit = rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT;
+ context->ffmpeg_crf = rd->ffcodecdata.constant_rate_factor;
+ context->ffmpeg_preset = rd->ffcodecdata.ffmpeg_preset;
+
+ if ((rd->ffcodecdata.flags & FFMPEG_USE_MAX_B_FRAMES) != 0) {
+ context->ffmpeg_max_b_frames = rd->ffcodecdata.max_b_frames;
+ }
/* Determine the correct filename */
ffmpeg_filepath_get(context, name, rd, context->ffmpeg_preview, suffix);
@@ -852,12 +889,16 @@ static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int
/* Returns after this must 'goto fail;' */
of->oformat = fmt;
- of->packet_size = rd->ffcodecdata.mux_packet_size;
- if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE) {
- ffmpeg_dict_set_int(&opts, "muxrate", rd->ffcodecdata.mux_rate);
- }
- else {
- av_dict_set(&opts, "muxrate", "0", 0);
+
+ /* Only bother with setting packet size & mux rate when CRF is not used. */
+ if (context->ffmpeg_crf == 0) {
+ of->packet_size = rd->ffcodecdata.mux_packet_size;
+ if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE) {
+ ffmpeg_dict_set_int(&opts, "muxrate", rd->ffcodecdata.mux_rate);
+ }
+ else {
+ av_dict_set(&opts, "muxrate", "0", 0);
+ }
}
ffmpeg_dict_set_int(&opts, "preload", (int)(0.5 * AV_TIME_BASE));
@@ -1393,7 +1434,7 @@ int BKE_ffmpeg_property_add_string(RenderData *rd, const char *type, const char
avcodec_get_context_defaults3(&c, NULL);
- strncpy(name_, str, sizeof(name_));
+ BLI_strncpy(name_, str, sizeof(name_));
name = name_;
while (*name == ' ') name++;
@@ -1503,14 +1544,6 @@ static void ffmpeg_set_expert_options(RenderData *rd)
BKE_ffmpeg_property_add_string(rd, "video", "fast-pskip:1");
BKE_ffmpeg_property_add_string(rd, "video", "wpredp:2");
#endif
-
- if (rd->ffcodecdata.flags & FFMPEG_LOSSLESS_OUTPUT) {
-#ifdef FFMPEG_HAVE_DEPRECATED_FLAGS2
- BKE_ffmpeg_property_add_string(rd, "video", "cqp:0");
-#else
- BKE_ffmpeg_property_add_string(rd, "video", "qp:0");
-#endif
- }
}
else if (codec_id == AV_CODEC_ID_DNXHD) {
if (rd->ffcodecdata.flags & FFMPEG_LOSSLESS_OUTPUT)
@@ -1622,9 +1655,10 @@ void BKE_ffmpeg_image_type_verify(RenderData *rd, ImageFormatData *imf)
rd->ffcodecdata.audio_codec <= 0 ||
rd->ffcodecdata.video_bitrate <= 1)
{
- rd->ffcodecdata.codec = AV_CODEC_ID_MPEG2VIDEO;
-
- BKE_ffmpeg_preset_set(rd, FFMPEG_PRESET_DVD);
+ BKE_ffmpeg_preset_set(rd, FFMPEG_PRESET_H264);
+ rd->ffcodecdata.constant_rate_factor = FFM_CRF_MEDIUM;
+ rd->ffcodecdata.ffmpeg_preset = FFM_PRESET_MEDIUM;
+ rd->ffcodecdata.type = FFMPEG_MKV;
}
if (rd->ffcodecdata.type == FFMPEG_OGG) {
rd->ffcodecdata.type = FFMPEG_MPEG2;
@@ -1672,9 +1706,6 @@ bool BKE_ffmpeg_alpha_channel_is_supported(RenderData *rd)
if (codec == AV_CODEC_ID_PNG)
return true;
- if (codec == AV_CODEC_ID_PNG)
- return true;
-
if (codec == AV_CODEC_ID_HUFFYUV)
return true;
diff --git a/source/blender/blenlib/BLI_array_store.h b/source/blender/blenlib/BLI_array_store.h
new file mode 100644
index 00000000000..f4cbc07bf26
--- /dev/null
+++ b/source/blender/blenlib/BLI_array_store.h
@@ -0,0 +1,66 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLI_ARRAY_STORE_H__
+#define __BLI_ARRAY_STORE_H__
+
+/** \file BLI_array_store.h
+ * \ingroup bli
+ * \brief Efficient in-memory storage of multiple similar arrays.
+ */
+
+typedef struct BArrayStore BArrayStore;
+typedef struct BArrayState BArrayState;
+
+BArrayStore *BLI_array_store_create(
+ unsigned int stride, unsigned int chunk_count);
+void BLI_array_store_destroy(
+ BArrayStore *bs);
+void BLI_array_store_clear(
+ BArrayStore *bs);
+
+/* find the memory used by all states (expanded & real) */
+size_t BLI_array_store_calc_size_expanded_get(
+ const BArrayStore *bs);
+size_t BLI_array_store_calc_size_compacted_get(
+ const BArrayStore *bs);
+
+BArrayState *BLI_array_store_state_add(
+ BArrayStore *bs,
+ const void *data, const size_t data_len,
+ const BArrayState *state_reference);
+void BLI_array_store_state_remove(
+ BArrayStore *bs,
+ BArrayState *state);
+
+size_t BLI_array_store_state_size_get(
+ BArrayState *state);
+void BLI_array_store_state_data_get(
+ BArrayState *state,
+ void *data);
+void *BLI_array_store_state_data_get_alloc(
+ BArrayState *state,
+ size_t *r_data_len);
+
+/* only for tests */
+bool BLI_array_store_is_valid(
+ BArrayStore *bs);
+
+#endif /* __BLI_ARRAY_STORE_H__ */
diff --git a/source/blender/blenlib/BLI_array_store_utils.h b/source/blender/blenlib/BLI_array_store_utils.h
new file mode 100644
index 00000000000..6b2a28846f4
--- /dev/null
+++ b/source/blender/blenlib/BLI_array_store_utils.h
@@ -0,0 +1,50 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLI_ARRAY_STORE_UTILS_H__
+#define __BLI_ARRAY_STORE_UTILS_H__
+
+/** \file BLI_array_store_utils.h
+ * \ingroup bli
+ */
+
+struct BArrayStore;
+
+struct BArrayStore_AtSize {
+ struct BArrayStore **stride_table;
+ int stride_table_len;
+};
+
+BArrayStore *BLI_array_store_at_size_ensure(
+ struct BArrayStore_AtSize *bs_stride,
+ const int stride, const int chunk_size);
+
+BArrayStore *BLI_array_store_at_size_get(
+ struct BArrayStore_AtSize *bs_stride,
+ const int stride);
+
+void BLI_array_store_at_size_clear(
+ struct BArrayStore_AtSize *bs_stride);
+
+void BLI_array_store_at_size_calc_memory_usage(
+ struct BArrayStore_AtSize *bs_stride,
+ size_t *r_size_expanded, size_t *r_size_compacted);
+
+#endif /* __BLI_ARRAY_STORE_UTILS_H__ */
diff --git a/source/blender/blenlib/BLI_array_utils.h b/source/blender/blenlib/BLI_array_utils.h
index 5ef8421c003..a46c87cec40 100644
--- a/source/blender/blenlib/BLI_array_utils.h
+++ b/source/blender/blenlib/BLI_array_utils.h
@@ -48,6 +48,10 @@ int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_strid
#define BLI_array_findindex(arr, arr_len, p) \
_bli_array_findindex(arr, arr_len, sizeof(*(arr)), p)
+int _bli_array_rfindindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p);
+#define BLI_array_rfindindex(arr, arr_len, p) \
+ _bli_array_rfindindex(arr, arr_len, sizeof(*(arr)), p)
+
void _bli_array_binary_and(
void *arr, const void *arr_a, const void *arr_b,
unsigned int arr_len, size_t arr_stride);
diff --git a/source/blender/blenlib/BLI_bitmap_draw_2d.h b/source/blender/blenlib/BLI_bitmap_draw_2d.h
new file mode 100644
index 00000000000..fe890e94f1b
--- /dev/null
+++ b/source/blender/blenlib/BLI_bitmap_draw_2d.h
@@ -0,0 +1,37 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLI_BITMAP_DRAW_2D_H__
+#define __BLI_BITMAP_DRAW_2D_H__
+
+/** \file BLI_bitmap_draw_2d.h
+ * \ingroup bli
+ */
+
+void BLI_bitmap_draw_2d_line_v2v2i(
+ const int p1[2], const int p2[2],
+ bool (*callback)(int, int, void *), void *userData);
+
+void BLI_bitmap_draw_2d_poly_v2i_n(
+ const int xmin, const int ymin, const int xmax, const int ymax,
+ const int polyXY[][2], const int polyCorners,
+ void (*callback)(int x, int x_end, int y, void *), void *userData);
+
+#endif /* __BLI_BITMAP_DRAW_2D_H__ */
diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h
index fb8c2520e67..91d39801645 100644
--- a/source/blender/blenlib/BLI_kdopbvh.h
+++ b/source/blender/blenlib/BLI_kdopbvh.h
@@ -96,7 +96,8 @@ typedef void (*BVHTree_NearestPointCallback)(void *userdata, int index, const fl
typedef void (*BVHTree_RayCastCallback)(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit);
/* callback must update nearest in case it finds a nearest result */
-typedef void (*BVHTree_NearestToRayCallback)(void *userdata, int index, const BVHTreeRay *ray, BVHTreeNearest *nearest);
+typedef void (*BVHTree_NearestToRayCallback)(void *userdata, const float ray_co[3], const float ray_dir[3],
+ const float scale[3], int index, BVHTreeNearest *nearest);
/* callback to check if 2 nodes overlap (use thread if intersection results need to be stored) */
typedef bool (*BVHTree_OverlapCallback)(void *userdata, int index_a, int index_b, int thread);
@@ -142,8 +143,16 @@ int BLI_bvhtree_find_nearest(
BVHTree *tree, const float co[3], BVHTreeNearest *nearest,
BVHTree_NearestPointCallback callback, void *userdata);
+int BLI_bvhtree_find_nearest_to_ray_angle(
+ BVHTree *tree, const float co[3], const float dir[3],
+ const bool ray_is_normalized, const float scale[3],
+ BVHTreeNearest *nearest,
+ BVHTree_NearestToRayCallback callback, void *userdata);
+
int BLI_bvhtree_find_nearest_to_ray(
- BVHTree *tree, const float co[3], const float dir[3], BVHTreeNearest *nearest,
+ BVHTree *tree, const float co[3], const float dir[3],
+ const bool ray_is_normalized, const float scale[3],
+ BVHTreeNearest *nearest,
BVHTree_NearestToRayCallback callback, void *userdata);
int BLI_bvhtree_ray_cast_ex(
diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h
index 9dfa80006de..96349a7b066 100644
--- a/source/blender/blenlib/BLI_listbase.h
+++ b/source/blender/blenlib/BLI_listbase.h
@@ -69,6 +69,7 @@ void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnew
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1);
void BLI_listbase_sort(struct ListBase *listbase, int (*cmp)(const void *, const void *)) ATTR_NONNULL(1, 2);
void BLI_listbase_sort_r(ListBase *listbase, int (*cmp)(void *, const void *, const void *), void *thunk) ATTR_NONNULL(1, 2);
+bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step) ATTR_NONNULL();
void BLI_freelist(struct ListBase *listbase) ATTR_NONNULL(1);
int BLI_listbase_count_ex(const struct ListBase *listbase, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h
index 20b76354f58..e97a250cd24 100644
--- a/source/blender/blenlib/BLI_math_base.h
+++ b/source/blender/blenlib/BLI_math_base.h
@@ -37,10 +37,6 @@
#include <math.h>
#include "BLI_math_inline.h"
-#ifdef __sun__
-#include <ieeefp.h> /* for finite() */
-#endif
-
#ifndef M_PI
#define M_PI 3.14159265358979323846 /* pi */
#endif
@@ -146,12 +142,6 @@ static const int NAN_INT = 0x7FC00000;
#endif /* C99, POSIX.1-2001 or MSVC12 (partial C99) */
-#ifdef WIN32
-# if defined(_MSC_VER)
-# define finite(n) _finite(n)
-# endif
-#endif
-
#if BLI_MATH_DO_INLINE
#include "intern/math_base_inline.c"
#endif
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index 45edaca544d..514b0300274 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -115,6 +115,13 @@ float dist_signed_squared_to_corner_v3v3v3(
const float p[3],
const float v1[3], const float v2[3], const float v3[3],
const float axis_ref[3]);
+float dist_squared_to_ray_v3(
+ const float ray_origin[3], const float ray_direction[3],
+ const float co[3], float *r_depth);
+float dist_squared_ray_to_seg_v3(
+ const float ray_origin[3], const float ray_direction[3],
+ const float v0[3], const float v1[3],
+ float r_point[3], float *r_depth);
float closest_to_line_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2]);
float closest_to_line_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3]);
void closest_to_line_segment_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2]);
@@ -318,11 +325,6 @@ bool clip_segment_v3_plane_n(
const float p1[3], const float p2[3], const float plane_array[][4], const int plane_tot,
float r_p1[3], float r_p2[3]);
-void plot_line_v2v2i(const int p1[2], const int p2[2], bool (*callback)(int, int, void *), void *userData);
-void fill_poly_v2i_n(
- const int xmin, const int ymin, const int xmax, const int ymax,
- const int polyXY[][2], const int polyCorners,
- void (*callback)(int x, int x_end, int y, void *), void *userData);
/****************************** Interpolation ********************************/
/* tri or quad, d can be NULL */
@@ -470,6 +472,10 @@ MINLINE float shell_v2v2_normalized_to_dist(const float a[2], const float b[2]);
MINLINE float shell_v3v3_mid_normalized_to_dist(const float a[3], const float b[3]);
MINLINE float shell_v2v2_mid_normalized_to_dist(const float a[2], const float b[2]);
+/********************************* Cubic (Bezier) *******************************/
+
+float cubic_tangent_factor_circle_v3(const float tan_l[3], const float tan_r[3]);
+
/**************************** Inline Definitions ******************************/
#if BLI_MATH_DO_INLINE
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index 6fb983a622e..8124e07dd47 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -138,10 +138,14 @@ bool invert_m3_m3(float R[3][3], float A[3][3]);
bool invert_m4(float R[4][4]);
bool invert_m4_m4(float R[4][4], float A[4][4]);
-/* double ariphmetics */
+/* double arithmetic (mixed float/double) */
void mul_m4_v4d(float M[4][4], double r[4]);
void mul_v4d_m4v4d(double r[4], float M[4][4], double v[4]);
+/* double matrix functions (no mixing types) */
+void mul_v3_m3v3_db(double r[3], double M[3][3], const double a[3]);
+void mul_m3_v3_db(double M[3][3], double r[3]);
+
/****************************** Linear Algebra *******************************/
@@ -246,6 +250,9 @@ bool is_negative_m4(float mat[4][4]);
bool is_zero_m3(float mat[3][3]);
bool is_zero_m4(float mat[4][4]);
+bool equals_m3m3(float mat1[3][3], float mat2[3][3]);
+bool equals_m4m4(float mat1[4][4], float mat2[4][4]);
+
/* SpaceTransform helper */
typedef struct SpaceTransform {
float local2target[4][4];
@@ -266,7 +273,7 @@ void BLI_space_transform_invert_normal(const struct SpaceTransform *data, float
/*********************************** Other ***********************************/
void print_m3(const char *str, float M[3][3]);
-void print_m4(const char *str, float M[3][4]);
+void print_m4(const char *str, float M[4][4]);
#define print_m3_id(M) print_m3(STRINGIFY(M), M)
#define print_m4_id(M) print_m4(STRINGIFY(M), M)
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index c44fcf47fdb..d15fe1a95dc 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -148,6 +148,7 @@ MINLINE void negate_v4(float r[4]);
MINLINE void negate_v4_v4(float r[4], const float a[3]);
MINLINE void negate_v3_short(short r[3]);
+MINLINE void negate_v3_db(double r[3]);
MINLINE void invert_v2(float r[2]);
@@ -190,6 +191,12 @@ MINLINE float len_manhattan_v3v3(const float a[3], const float b[3]) ATTR_WARN_U
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT;
+MINLINE float normalize_v2_length(float r[2], const float unit_scale);
+MINLINE float normalize_v2_v2_length(float r[2], const float a[2], const float unit_scale);
+MINLINE float normalize_v3_length(float r[3], const float unit_scale);
+MINLINE float normalize_v3_v3_length(float r[3], const float a[3], const float unit_scale);
+MINLINE double normalize_v3_length_d(double n[3], const double unit_scale);
+
MINLINE float normalize_v2(float r[2]);
MINLINE float normalize_v2_v2(float r[2], const float a[2]);
MINLINE float normalize_v3(float r[3]);
@@ -214,6 +221,10 @@ bool interp_v2_v2v2_slerp(float target[2], const float a[2], const float b[2], c
void interp_v3_v3v3_slerp_safe(float target[3], const float a[3], const float b[3], const float t);
void interp_v2_v2v2_slerp_safe(float target[2], const float a[2], const float b[2], const float t);
+void interp_v2_v2v2v2v2_cubic(
+ float p[2], const float v1[2], const float v2[2], const float v3[2], const float v4[2],
+ const float u);
+
void interp_v3_v3v3_char(char target[3], const char a[3], const char b[3], const float t);
void interp_v3_v3v3_uchar(unsigned char target[3], const unsigned char a[3], const unsigned char b[3], const float t);
void interp_v4_v4v4_char(char target[4], const char a[4], const char b[4], const float t);
@@ -231,15 +242,16 @@ void flip_v4_v4v4(float v[4], const float v1[4], const float v2[4]);
void flip_v3_v3v3(float v[3], const float v1[3], const float v2[3]);
void flip_v2_v2v2(float v[2], const float v1[2], const float v2[2]);
+
/********************************* Comparison ********************************/
MINLINE bool is_zero_v2(const float a[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE bool is_zero_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE bool is_zero_v4(const float a[4]) ATTR_WARN_UNUSED_RESULT;
-MINLINE bool is_finite_v2(const float a[3]) ATTR_WARN_UNUSED_RESULT;
-MINLINE bool is_finite_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT;
-MINLINE bool is_finite_v4(const float a[4]) ATTR_WARN_UNUSED_RESULT;
+bool is_finite_v2(const float a[3]) ATTR_WARN_UNUSED_RESULT;
+bool is_finite_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT;
+bool is_finite_v4(const float a[4]) ATTR_WARN_UNUSED_RESULT;
MINLINE bool is_one_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT;
@@ -282,18 +294,18 @@ void angle_poly_v3(float *angles, const float *verts[3], int len);
/********************************* Geometry **********************************/
-void project_v2_v2v2(float c[2], const float v1[2], const float v2[2]);
-void project_v3_v3v3(float r[3], const float p[3], const float n[3]);
-void project_plane_v3_v3v3(float c[3], const float v[3], const float v_plane[3]);
-void project_plane_v2_v2v2(float c[2], const float v[2], const float v_plane[2]);
-void project_v3_plane(float v[3], const float n[3], const float p[3]);
-void reflect_v3_v3v3(float r[3], const float v[3], const float n[3]);
+void project_v2_v2v2(float out[2], const float p[2], const float v_proj[2]);
+void project_v3_v3v3(float out[3], const float p[3], const float v_proj[3]);
+void project_plane_v3_v3v3(float out[3], const float p[3], const float v_plane[3]);
+void project_plane_v2_v2v2(float out[2], const float p[2], const float v_plane[2]);
+void project_v3_plane(float out[3], const float plane_no[3], const float plane_co[3]);
+void reflect_v3_v3v3(float out[3], const float vec[3], const float normal[3]);
void ortho_basis_v3v3_v3(float r_n1[3], float r_n2[3], const float n[3]);
-void ortho_v3_v3(float p[3], const float v[3]);
-void ortho_v2_v2(float p[2], const float v[2]);
+void ortho_v3_v3(float out[3], const float v[3]);
+void ortho_v2_v2(float out[2], const float v[2]);
void bisect_v3_v3v3v3(float r[3], const float a[3], const float b[3], const float c[3]);
void rotate_v3_v3v3fl(float v[3], const float p[3], const float axis[3], const float angle);
-void rotate_normalized_v3_v3v3fl(float v[3], const float p[3], const float axis[3], const float angle);
+void rotate_normalized_v3_v3v3fl(float out[3], const float p[3], const float axis[3], const float angle);
/*********************************** Other ***********************************/
diff --git a/source/blender/blenlib/BLI_quadric.h b/source/blender/blenlib/BLI_quadric.h
index eaf9c7a0738..d46a221d108 100644
--- a/source/blender/blenlib/BLI_quadric.h
+++ b/source/blender/blenlib/BLI_quadric.h
@@ -39,8 +39,7 @@ typedef struct Quadric {
/* conversion */
void BLI_quadric_from_plane(Quadric *q, const double v[4]);
-void BLI_quadric_to_tensor_m3(const Quadric *q, float m[3][3]);
-void BLI_quadric_to_vector_v3(const Quadric *q, float v[3]);
+void BLI_quadric_to_vector_v3(const Quadric *q, double v[3]);
void BLI_quadric_clear(Quadric *q);
@@ -50,7 +49,7 @@ void BLI_quadric_add_qu_ququ(Quadric *r, const Quadric *a, const Quadric *b);
void BLI_quadric_mul(Quadric *a, const double scalar);
/* solve */
-double BLI_quadric_evaluate(const Quadric *q, const float v_fl[3]);
-bool BLI_quadric_optimize(const Quadric *q, float v[3], const float epsilon);
+double BLI_quadric_evaluate(const Quadric *q, const double v[3]);
+bool BLI_quadric_optimize(const Quadric *q, double v[3], const double epsilon);
#endif /* __BLI_QUADRIC_H__ */
diff --git a/source/blender/blenlib/BLI_rand.h b/source/blender/blenlib/BLI_rand.h
index 7b84dddcb68..f36d2faa1b8 100644
--- a/source/blender/blenlib/BLI_rand.h
+++ b/source/blender/blenlib/BLI_rand.h
@@ -49,6 +49,7 @@ void BLI_rng_free(struct RNG *rng) ATTR_NONNULL(1);
void BLI_rng_seed(struct RNG *rng, unsigned int seed) ATTR_NONNULL(1);
void BLI_rng_srandom(struct RNG *rng, unsigned int seed) ATTR_NONNULL(1);
+void BLI_rng_get_char_n(RNG *rng, char *bytes, size_t bytes_len) ATTR_NONNULL(1, 2);
int BLI_rng_get_int(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
unsigned int BLI_rng_get_uint(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
double BLI_rng_get_double(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
diff --git a/source/blender/blenlib/BLI_stackdefines.h b/source/blender/blenlib/BLI_stackdefines.h
index b26dc3e26aa..42b11eb9a2b 100644
--- a/source/blender/blenlib/BLI_stackdefines.h
+++ b/source/blender/blenlib/BLI_stackdefines.h
@@ -31,28 +31,28 @@
/* only validate array-bounds in debug mode */
#ifdef DEBUG
# define STACK_DECLARE(stack) unsigned int _##stack##_index, _##stack##_totalloc
-# define STACK_INIT(stack, tot) ((void)stack, (void)((_##stack##_index) = 0), (void)((_##stack##_totalloc) = tot))
-# define _STACK_SIZETEST(stack, off) (BLI_assert((_##stack##_index) + off <= _##stack##_totalloc))
+# define STACK_INIT(stack, tot) ((void)stack, (void)((_##stack##_index) = 0), (void)((_##stack##_totalloc) = (tot)))
+# define _STACK_SIZETEST(stack, off) (BLI_assert((_##stack##_index) + (off) <= _##stack##_totalloc))
# define _STACK_SWAP_TOTALLOC(stack_a, stack_b) SWAP(unsigned int, _##stack_a##_totalloc, _##stack_b##_totalloc)
#else
# define STACK_DECLARE(stack) unsigned int _##stack##_index
-# define STACK_INIT(stack, tot) ((void)stack, (void)((_##stack##_index) = 0), (void)(0 ? tot : 0))
+# define STACK_INIT(stack, tot) ((void)stack, (void)((_##stack##_index) = 0), (void)(0 ? (tot) : 0))
# define _STACK_SIZETEST(stack, off) (void)(stack), (void)(off)
# define _STACK_SWAP_TOTALLOC(stack_a, stack_b) (void)(stack_a), (void)(stack_b)
#endif
-#define _STACK_BOUNDSTEST(stack, index) ((void)stack, BLI_assert((unsigned int)index < _##stack##_index))
+#define _STACK_BOUNDSTEST(stack, index) ((void)stack, BLI_assert((unsigned int)(index) < _##stack##_index))
#define STACK_SIZE(stack) ((void)stack, (_##stack##_index))
#define STACK_CLEAR(stack) {(void)stack; _##stack##_index = 0; } ((void)0)
/** add item to stack */
-#define STACK_PUSH(stack, val) ((void)stack, _STACK_SIZETEST(stack, 1), ((stack)[(_##stack##_index)++] = val))
+#define STACK_PUSH(stack, val) ((void)stack, _STACK_SIZETEST(stack, 1), ((stack)[(_##stack##_index)++] = (val)))
#define STACK_PUSH_RET(stack) ((void)stack, _STACK_SIZETEST(stack, 1), ((stack)[(_##stack##_index)++]))
#define STACK_PUSH_RET_PTR(stack) ((void)stack, _STACK_SIZETEST(stack, 1), &((stack)[(_##stack##_index)++]))
/** take last item from stack */
#define STACK_POP(stack) ((_##stack##_index) ? ((stack)[--(_##stack##_index)]) : NULL)
#define STACK_POP_PTR(stack) ((_##stack##_index) ? &((stack)[--(_##stack##_index)]) : NULL)
-#define STACK_POP_DEFAULT(stack, r) ((_##stack##_index) ? ((stack)[--(_##stack##_index)]) : r)
+#define STACK_POP_DEFAULT(stack, r) ((_##stack##_index) ? ((stack)[--(_##stack##_index)]) : (r))
/** look at last item (assumes non-empty stack) */
#define STACK_PEEK(stack) (BLI_assert(_##stack##_index), ((stack)[_##stack##_index - 1]))
#define STACK_PEEK_PTR(stack) (BLI_assert(_##stack##_index), &((stack)[_##stack##_index - 1]))
diff --git a/source/blender/blenlib/BLI_system.h b/source/blender/blenlib/BLI_system.h
index cb8cb6f5a0d..f51b9623803 100644
--- a/source/blender/blenlib/BLI_system.h
+++ b/source/blender/blenlib/BLI_system.h
@@ -21,15 +21,14 @@
#ifndef __BLI_SYSTEM_H__
#define __BLI_SYSTEM_H__
+#include <stdio.h>
+
/** \file BLI_system.h
* \ingroup bli
*/
int BLI_cpu_support_sse2(void);
-
-#if defined(NDEBUG) || !defined(__BLI_UTILDEFINES_H__)
void BLI_system_backtrace(FILE *fp);
-#endif
/* getpid */
#ifdef WIN32
diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h
index 4cf1d8baaf0..967e0be6d0a 100644
--- a/source/blender/blenlib/BLI_task.h
+++ b/source/blender/blenlib/BLI_task.h
@@ -21,6 +21,9 @@
#ifndef __BLI_TASK_H__
#define __BLI_TASK_H__
+struct Link;
+struct ListBase;
+
/** \file BLI_task.h
* \ingroup bli
*/
@@ -116,11 +119,13 @@ size_t BLI_task_pool_tasks_done(TaskPool *pool);
/* Parallel for routines */
typedef void (*TaskParallelRangeFunc)(void *userdata, const int iter);
typedef void (*TaskParallelRangeFuncEx)(void *userdata, void *userdata_chunk, const int iter, const int thread_id);
+typedef void (*TaskParallelRangeFuncFinalize)(void *userdata, void *userdata_chunk);
void BLI_task_parallel_range_ex(
int start, int stop,
void *userdata,
void *userdata_chunk,
- const size_t userdata_chunk_size, TaskParallelRangeFuncEx func_ex,
+ const size_t userdata_chunk_size,
+ TaskParallelRangeFuncEx func_ex,
const bool use_threading,
const bool use_dynamic_scheduling);
void BLI_task_parallel_range(
@@ -129,6 +134,25 @@ void BLI_task_parallel_range(
TaskParallelRangeFunc func,
const bool use_threading);
+void BLI_task_parallel_range_finalize(
+ int start, int stop,
+ void *userdata,
+ void *userdata_chunk,
+ const size_t userdata_chunk_size,
+ TaskParallelRangeFuncEx func_ex,
+ TaskParallelRangeFuncFinalize func_finalize,
+ const bool use_threading,
+ const bool use_dynamic_scheduling);
+
+typedef void (*TaskParallelListbaseFunc)(void *userdata,
+ struct Link *iter,
+ int index);
+void BLI_task_parallel_listbase(
+ struct ListBase *listbase,
+ void *userdata,
+ TaskParallelListbaseFunc func,
+ const bool use_threading);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_threads.h b/source/blender/blenlib/BLI_threads.h
index b4a465bbc74..0b1b4d8ee8c 100644
--- a/source/blender/blenlib/BLI_threads.h
+++ b/source/blender/blenlib/BLI_threads.h
@@ -42,7 +42,7 @@ extern "C" {
#endif
/* for tables, button in UI, etc */
-#define BLENDER_MAX_THREADS 64
+#define BLENDER_MAX_THREADS 1024
struct ListBase;
struct TaskScheduler;
diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h
index d504e503c68..746eb922c65 100644
--- a/source/blender/blenlib/BLI_utildefines.h
+++ b/source/blender/blenlib/BLI_utildefines.h
@@ -633,7 +633,7 @@ extern bool BLI_memory_is_zero(const void *arr, const size_t arr_size);
* for aborting need to define WITH_ASSERT_ABORT
*/
#ifndef NDEBUG
-extern void BLI_system_backtrace(FILE *fp);
+# include "BLI_system.h"
# ifdef WITH_ASSERT_ABORT
# define _BLI_DUMMY_ABORT abort
# else
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 944ba60eb58..6e717a3ae7e 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -52,8 +52,11 @@ set(SRC
intern/BLI_memarena.c
intern/BLI_mempool.c
intern/DLRB_tree.c
+ intern/array_store.c
+ intern/array_store_utils.c
intern/array_utils.c
intern/astar.c
+ intern/bitmap_draw_2d.c
intern/boxpack2d.c
intern/buffer.c
intern/callbacks.c
@@ -120,9 +123,12 @@ set(SRC
BLI_alloca.h
BLI_args.h
BLI_array.h
+ BLI_array_store.h
+ BLI_array_store_utils.h
BLI_array_utils.h
BLI_astar.h
BLI_bitmap.h
+ BLI_bitmap_draw_2d.h
BLI_blenlib.h
BLI_boxpack2d.h
BLI_buffer.h
diff --git a/source/blender/blenlib/intern/BLI_filelist.c b/source/blender/blenlib/intern/BLI_filelist.c
index 527d9934797..76de52bda66 100644
--- a/source/blender/blenlib/intern/BLI_filelist.c
+++ b/source/blender/blenlib/intern/BLI_filelist.c
@@ -352,8 +352,6 @@ void BLI_filelist_entry_datetime_to_string(
/**
* Deep-duplicate of a single direntry.
- *
- * \param dup_poin If given, called for each non-NULL direntry->poin. Otherwise, pointer is always simply copied over.
*/
void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *src)
{
@@ -368,8 +366,6 @@ void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *s
/**
* Deep-duplicate of an array of direntries, including the array itself.
- *
- * \param dup_poin If given, called for each non-NULL direntry->poin. Otherwise, pointer is always simply copied over.
*/
void BLI_filelist_duplicate(
struct direntry **dest_filelist, struct direntry * const src_filelist, const unsigned int nrentries)
diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c
index 06946e520a8..944ee18e6b2 100644
--- a/source/blender/blenlib/intern/BLI_ghash.c
+++ b/source/blender/blenlib/intern/BLI_ghash.c
@@ -69,7 +69,7 @@ const unsigned int hashsizes[] = {
/**
* \note Max load #GHASH_LIMIT_GROW used to be 3. (pre 2.74).
- * Python uses 0.6666, tommyhaslib even goes down to 0.5.
+ * Python uses 0.6666, tommyhashlib even goes down to 0.5.
* Reducing our from 3 to 0.75 gives huge speedup (about twice quicker pure GHash insertions/lookup,
* about 25% - 30% quicker 'dynamic-topology' stroke drawing e.g.).
* Min load #GHASH_LIMIT_SHRINK is a quarter of max load, to avoid resizing to quickly.
@@ -1588,7 +1588,7 @@ double BLI_ghash_calc_quality_ex(
if (r_variance) {
/* We already know our mean (i.e. load factor), easy to compute variance.
- * See http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Two-pass_algorithm
+ * See https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Two-pass_algorithm
*/
double sum = 0.0;
for (i = 0; i < gh->nbuckets; i++) {
diff --git a/source/blender/blenlib/intern/BLI_heap.c b/source/blender/blenlib/intern/BLI_heap.c
index 4bd404e5d73..d7fd1caa8da 100644
--- a/source/blender/blenlib/intern/BLI_heap.c
+++ b/source/blender/blenlib/intern/BLI_heap.c
@@ -32,7 +32,6 @@
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
-#include "BLI_memarena.h"
#include "BLI_heap.h"
#include "BLI_strict_flags.h"
@@ -44,15 +43,38 @@ struct HeapNode {
unsigned int index;
};
+struct HeapNode_Chunk {
+ struct HeapNode_Chunk *prev;
+ unsigned int size;
+ unsigned int bufsize;
+ struct HeapNode buf[0];
+};
+
+/**
+ * Number of nodes to include per #HeapNode_Chunk when no reserved size is passed,
+ * or we allocate past the reserved number.
+ *
+ * \note Optimize number for 64kb allocs.
+ * \note keep type in sync with tot_nodes in heap_node_alloc_chunk.
+ */
+#define HEAP_CHUNK_DEFAULT_NUM \
+ ((unsigned int)((MEM_SIZE_OPTIMAL((1 << 16) - sizeof(struct HeapNode_Chunk))) / sizeof(HeapNode)))
+
struct Heap {
unsigned int size;
unsigned int bufsize;
- MemArena *arena;
- HeapNode *freenodes;
HeapNode **tree;
+
+ struct {
+ /* Always keep at least one chunk (never NULL) */
+ struct HeapNode_Chunk *chunk;
+ /* when NULL, allocate a new chunk */
+ HeapNode *free;
+ } nodes;
};
-/* internal functions */
+/** \name Internal Functions
+ * \{ */
#define HEAP_PARENT(i) (((i) - 1) >> 1)
#define HEAP_LEFT(i) (((i) << 1) + 1)
@@ -92,11 +114,13 @@ static void heap_down(Heap *heap, unsigned int i)
smallest = ((l < size) && HEAP_COMPARE(heap->tree[l], heap->tree[i])) ? l : i;
- if ((r < size) && HEAP_COMPARE(heap->tree[r], heap->tree[smallest]))
+ if ((r < size) && HEAP_COMPARE(heap->tree[r], heap->tree[smallest])) {
smallest = r;
+ }
- if (smallest == i)
+ if (smallest == i) {
break;
+ }
heap_swap(heap, i, smallest);
i = smallest;
@@ -108,25 +132,73 @@ static void heap_up(Heap *heap, unsigned int i)
while (i > 0) {
const unsigned int p = HEAP_PARENT(i);
- if (HEAP_COMPARE(heap->tree[p], heap->tree[i]))
+ if (HEAP_COMPARE(heap->tree[p], heap->tree[i])) {
break;
-
+ }
heap_swap(heap, p, i);
i = p;
}
}
+/** \} */
-/***/
+
+/** \name Internal Memory Management
+ * \{ */
+
+static struct HeapNode_Chunk *heap_node_alloc_chunk(
+ unsigned int tot_nodes, struct HeapNode_Chunk *chunk_prev)
+{
+ struct HeapNode_Chunk *chunk = MEM_mallocN(
+ sizeof(struct HeapNode_Chunk) + (sizeof(HeapNode) * tot_nodes), __func__);
+ chunk->prev = chunk_prev;
+ chunk->bufsize = tot_nodes;
+ chunk->size = 0;
+ return chunk;
+}
+
+static struct HeapNode *heap_node_alloc(Heap *heap)
+{
+ HeapNode *node;
+
+ if (heap->nodes.free) {
+ node = heap->nodes.free;
+ heap->nodes.free = heap->nodes.free->ptr;
+ }
+ else {
+ struct HeapNode_Chunk *chunk = heap->nodes.chunk;
+ if (UNLIKELY(chunk->size == chunk->bufsize)) {
+ chunk = heap->nodes.chunk = heap_node_alloc_chunk(HEAP_CHUNK_DEFAULT_NUM, chunk);
+ }
+ node = &chunk->buf[chunk->size++];
+ }
+
+ return node;
+}
+
+static void heap_node_free(Heap *heap, HeapNode *node)
+{
+ node->ptr = heap->nodes.free;
+ heap->nodes.free = node;
+}
+
+/** \} */
+
+
+/** \name Public Heap API
+ * \{ */
/* use when the size of the heap is known in advance */
Heap *BLI_heap_new_ex(unsigned int tot_reserve)
{
- Heap *heap = (Heap *)MEM_callocN(sizeof(Heap), __func__);
+ Heap *heap = MEM_mallocN(sizeof(Heap), __func__);
/* ensure we have at least one so we can keep doubling it */
+ heap->size = 0;
heap->bufsize = MAX2(1u, tot_reserve);
- heap->tree = (HeapNode **)MEM_mallocN(heap->bufsize * sizeof(HeapNode *), "BLIHeapTree");
- heap->arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "heap arena");
+ heap->tree = MEM_mallocN(heap->bufsize * sizeof(HeapNode *), "BLIHeapTree");
+
+ heap->nodes.chunk = heap_node_alloc_chunk((tot_reserve > 1) ? tot_reserve : HEAP_CHUNK_DEFAULT_NUM, NULL);
+ heap->nodes.free = NULL;
return heap;
}
@@ -146,8 +218,15 @@ void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp)
}
}
+ struct HeapNode_Chunk *chunk = heap->nodes.chunk;
+ do {
+ struct HeapNode_Chunk *chunk_prev;
+ chunk_prev = chunk->prev;
+ MEM_freeN(chunk);
+ chunk = chunk_prev;
+ } while (chunk);
+
MEM_freeN(heap->tree);
- BLI_memarena_free(heap->arena);
MEM_freeN(heap);
}
@@ -160,10 +239,16 @@ void BLI_heap_clear(Heap *heap, HeapFreeFP ptrfreefp)
ptrfreefp(heap->tree[i]->ptr);
}
}
-
heap->size = 0;
- BLI_memarena_clear(heap->arena);
- heap->freenodes = NULL;
+
+ /* Remove all except the last chunk */
+ while (heap->nodes.chunk->prev) {
+ struct HeapNode_Chunk *chunk_prev = heap->nodes.chunk->prev;
+ MEM_freeN(heap->nodes.chunk);
+ heap->nodes.chunk = chunk_prev;
+ }
+ heap->nodes.chunk->size = 0;
+ heap->nodes.free = NULL;
}
HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr)
@@ -175,13 +260,7 @@ HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr)
heap->tree = MEM_reallocN(heap->tree, heap->bufsize * sizeof(*heap->tree));
}
- if (heap->freenodes) {
- node = heap->freenodes;
- heap->freenodes = heap->freenodes->ptr;
- }
- else {
- node = (HeapNode *)BLI_memarena_alloc(heap->arena, sizeof(*node));
- }
+ node = heap_node_alloc(heap);
node->ptr = ptr;
node->value = value;
@@ -217,8 +296,7 @@ void *BLI_heap_popmin(Heap *heap)
BLI_assert(heap->size != 0);
- heap->tree[0]->ptr = heap->freenodes;
- heap->freenodes = heap->tree[0];
+ heap_node_free(heap, heap->tree[0]);
if (--heap->size) {
heap_swap(heap, 0, heap->size);
@@ -254,3 +332,4 @@ void *BLI_heap_node_ptr(HeapNode *node)
return node->ptr;
}
+/** \} */
diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c
index 5f64c137ce6..b14007a88cb 100644
--- a/source/blender/blenlib/intern/BLI_kdopbvh.c
+++ b/source/blender/blenlib/intern/BLI_kdopbvh.c
@@ -163,12 +163,23 @@ typedef struct BVHNearestRayData {
BVHTree *tree;
BVHTree_NearestToRayCallback callback;
void *userdata;
- BVHTreeRay ray;
- struct NearestRayToAABB_Precalc nearest_precalc;
+ struct {
+ bool sign[3];
+ float origin[3];
+ float direction[3];
+
+ float direction_scaled_square[3];
+ float inv_dir[3];
+
+ float cdot_axis[3];
+ } ray;
bool pick_smallest[3];
+
BVHTreeNearest nearest;
+
+ float scale[3];
} BVHNearestRayData;
/** \} */
@@ -1573,7 +1584,7 @@ int BLI_bvhtree_find_nearest(
/* Determines the distance that the ray must travel to hit the bounding volume of the given node */
-static float ray_nearest_hit(BVHRayCastData *data, const float bv[6])
+static float ray_nearest_hit(const BVHRayCastData *data, const float bv[6])
{
int i;
@@ -1889,58 +1900,374 @@ void BLI_bvhtree_ray_cast_all(
/* -------------------------------------------------------------------- */
-/** \name BLI_bvhtree_find_nearest_to_ray
+/** \name BLI_bvhtree_find_nearest_to_ray functions
*
* \{ */
+static void dist_squared_ray_to_aabb_scaled_v3_precalc(
+ BVHNearestRayData *data,
+ const float ray_origin[3], const float ray_direction[3],
+ const bool ray_is_normalized, const float scale[3])
+{
+ if (scale) {
+ copy_v3_v3(data->scale, scale);
+ }
+ else {
+ copy_v3_fl(data->scale, 1.0f);
+ }
+ /* un-normalize ray */
+ if (ray_is_normalized && scale &&
+ (data->scale[0] != 1.0f || data->scale[1] != 1.0f || data->scale[2] != 1.0f))
+ {
+ data->ray.direction[0] = ray_direction[0] * data->scale[0];
+ data->ray.direction[1] = ray_direction[1] * data->scale[1];
+ data->ray.direction[2] = ray_direction[2] * data->scale[2];
+
+ mul_v3_v3fl(data->ray.direction, ray_direction, 1 / len_v3(data->ray.direction));
+ }
+ else {
+ copy_v3_v3(data->ray.direction, ray_direction);
+ }
+
+ float dir_sq[3];
+
+ for (int i = 0; i < 3; i++) {
+ data->ray.origin[i] = ray_origin[i];
+ data->ray.inv_dir[i] = (data->ray.direction[i] != 0.0f) ?
+ (1.0f / data->ray.direction[i]) : FLT_MAX;
+ /* It has to be in function of `ray.inv_dir`,
+ * since the division of 1 by 0.0f, can be -inf or +inf */
+ data->ray.sign[i] = (data->ray.inv_dir[i] < 0.0f);
+
+ data->ray.direction_scaled_square[i] = data->ray.direction[i] * data->scale[i];
+
+ dir_sq[i] = SQUARE(data->ray.direction_scaled_square[i]);
+
+ data->ray.direction_scaled_square[i] *= data->scale[i];
+ }
+
+ /* `diag_sq` Length square of each face diagonal */
+ float diag_sq[3] = {
+ dir_sq[1] + dir_sq[2],
+ dir_sq[0] + dir_sq[2],
+ dir_sq[0] + dir_sq[1],
+ };
+
+ data->ray.cdot_axis[0] = (diag_sq[0] != 0.0f) ? data->ray.direction[0] / diag_sq[0] : FLT_MAX;
+ data->ray.cdot_axis[1] = (diag_sq[1] != 0.0f) ? data->ray.direction[1] / diag_sq[1] : FLT_MAX;
+ data->ray.cdot_axis[2] = (diag_sq[2] != 0.0f) ? data->ray.direction[2] / diag_sq[2] : FLT_MAX;
+}
+
+/**
+ * Returns the squared distance from a ray to a bound-box `AABB`.
+ * It is based on `fast_ray_nearest_hit` solution to obtain
+ * the coordinates of the nearest edge of Bound Box to the ray
+ */
+MINLINE float dist_squared_ray_to_aabb_scaled_v3__impl(
+ const BVHNearestRayData *data,
+ const float bv[6], float *r_depth_sq, bool r_axis_closest[3])
+{
+
+ /* `tmin` is a vector that has the smaller distances to each of the
+ * infinite planes of the `AABB` faces (hit in nearest face X plane,
+ * nearest face Y plane and nearest face Z plane) */
+ float local_bvmin[3], local_bvmax[3];
+
+ if (data->ray.sign[0]) {
+ local_bvmin[0] = bv[1];
+ local_bvmax[0] = bv[0];
+ }
+ else {
+ local_bvmin[0] = bv[0];
+ local_bvmax[0] = bv[1];
+ }
+
+ if (data->ray.sign[1]) {
+ local_bvmin[1] = bv[3];
+ local_bvmax[1] = bv[2];
+ }
+ else {
+ local_bvmin[1] = bv[2];
+ local_bvmax[1] = bv[3];
+ }
+
+ if (data->ray.sign[2]) {
+ local_bvmin[2] = bv[5];
+ local_bvmax[2] = bv[4];
+ }
+ else {
+ local_bvmin[2] = bv[4];
+ local_bvmax[2] = bv[5];
+ }
+
+ sub_v3_v3(local_bvmin, data->ray.origin);
+ sub_v3_v3(local_bvmax, data->ray.origin);
+
+ const float tmin[3] = {
+ local_bvmin[0] * data->ray.inv_dir[0],
+ local_bvmin[1] * data->ray.inv_dir[1],
+ local_bvmin[2] * data->ray.inv_dir[2],
+ };
+
+ /* `tmax` is a vector that has the longer distances to each of the
+ * infinite planes of the `AABB` faces (hit in farthest face X plane,
+ * farthest face Y plane and farthest face Z plane) */
+ const float tmax[3] = {
+ local_bvmax[0] * data->ray.inv_dir[0],
+ local_bvmax[1] * data->ray.inv_dir[1],
+ local_bvmax[2] * data->ray.inv_dir[2],
+ };
+ /* `v1` and `v3` is be the coordinates of the nearest `AABB` edge to the ray*/
+ float v1[3], v2[3];
+ /* `rtmin` is the highest value of the smaller distances. == max_axis_v3(tmin)
+ * `rtmax` is the lowest value of longer distances. == min_axis_v3(tmax)*/
+ float rtmin, rtmax, mul;
+ /* `main_axis` is the axis equivalent to edge close to the ray */
+ int main_axis;
+
+ r_axis_closest[0] = false;
+ r_axis_closest[1] = false;
+ r_axis_closest[2] = false;
+
+ /* *** min_axis_v3(tmax) *** */
+ if ((tmax[0] <= tmax[1]) && (tmax[0] <= tmax[2])) {
+ // printf("# Hit in X %s\n", data->sign[0] ? "min", "max");
+ rtmax = tmax[0];
+ v1[0] = v2[0] = local_bvmax[0];
+ mul = local_bvmax[0] * data->ray.direction_scaled_square[0];
+ main_axis = 3;
+ r_axis_closest[0] = data->ray.sign[0];
+ }
+ else if ((tmax[1] <= tmax[0]) && (tmax[1] <= tmax[2])) {
+ // printf("# Hit in Y %s\n", data->sign[1] ? "min", "max");
+ rtmax = tmax[1];
+ v1[1] = v2[1] = local_bvmax[1];
+ mul = local_bvmax[1] * data->ray.direction_scaled_square[1];
+ main_axis = 2;
+ r_axis_closest[1] = data->ray.sign[1];
+ }
+ else {
+ // printf("# Hit in Z %s\n", data->sign[2] ? "min", "max");
+ rtmax = tmax[2];
+ v1[2] = v2[2] = local_bvmax[2];
+ mul = local_bvmax[2] * data->ray.direction_scaled_square[2];
+ main_axis = 1;
+ r_axis_closest[2] = data->ray.sign[2];
+ }
+
+ /* *** max_axis_v3(tmin) *** */
+ if ((tmin[0] >= tmin[1]) && (tmin[0] >= tmin[2])) {
+ // printf("# To X %s\n", data->sign[0] ? "max", "min");
+ rtmin = tmin[0];
+ v1[0] = v2[0] = local_bvmin[0];
+ mul += local_bvmin[0] * data->ray.direction_scaled_square[0];
+ main_axis -= 3;
+ r_axis_closest[0] = !data->ray.sign[0];
+ }
+ else if ((tmin[1] >= tmin[0]) && (tmin[1] >= tmin[2])) {
+ // printf("# To Y %s\n", data->sign[1] ? "max", "min");
+ rtmin = tmin[1];
+ v1[1] = v2[1] = local_bvmin[1];
+ mul += local_bvmin[1] * data->ray.direction_scaled_square[1];
+ main_axis -= 1;
+ r_axis_closest[1] = !data->ray.sign[1];
+ }
+ else {
+ // printf("# To Z %s\n", data->sign[2] ? "max", "min");
+ rtmin = tmin[2];
+ v1[2] = v2[2] = local_bvmin[2];
+ mul += local_bvmin[2] * data->ray.direction_scaled_square[2];
+ main_axis -= 2;
+ r_axis_closest[2] = !data->ray.sign[2];
+ }
+ /* *** end min/max axis *** */
+
+ if (main_axis < 0)
+ main_axis += 3;
+
+ /* if rtmin < rtmax, ray intersect `AABB` */
+ if (rtmin <= rtmax) {
+#ifdef IGNORE_BEHIND_RAY
+ /* `if rtmax < depth_min`, the whole `AABB` is behind us */
+ if (rtmax < min_depth) {
+ return fallback;
+ }
+#endif
+ const float proj = rtmin * data->ray.direction[main_axis];
+
+ if (data->ray.sign[main_axis])
+ r_axis_closest[main_axis] = (proj - local_bvmax[main_axis]) < (local_bvmin[main_axis] - proj);
+ else
+ r_axis_closest[main_axis] = (proj - local_bvmin[main_axis]) < (local_bvmax[main_axis] - proj);
+
+ //if (r_depth_sq)
+ // *r_depth_sq = SQUARE(rtmin);
+
+ return 0.0f;
+ }
+#ifdef IGNORE_BEHIND_RAY
+ /* `if rtmin < depth_min`, the whole `AABB` is behing us */
+ else if (rtmin < min_depth) {
+ return fallback;
+ }
+#endif
+
+ if (data->ray.sign[main_axis]) {
+ v1[main_axis] = local_bvmax[main_axis];
+ v2[main_axis] = local_bvmin[main_axis];
+ }
+ else {
+ v1[main_axis] = local_bvmin[main_axis];
+ v2[main_axis] = local_bvmax[main_axis];
+ }
+ {
+ /* `proj` equals to nearest point on the ray closest to the edge `v1 v2` of the `AABB`. */
+ const float proj = mul * data->ray.cdot_axis[main_axis];
+ float depth_sq, r_point[3];
+ if (v1[main_axis] > proj) { /* the nearest point to the ray is the point v1 */
+ r_axis_closest[main_axis] = true;
+ /* `depth` is equivalent the distance of the the projection of v1 on the ray */
+ depth_sq = mul + data->ray.direction_scaled_square[main_axis] * v1[main_axis];
+
+ copy_v3_v3(r_point, v1);
+ }
+ else if (v2[main_axis] < proj) { /* the nearest point of the ray is the point v2 */
+ r_axis_closest[main_axis] = false;
+
+ depth_sq = mul + data->ray.direction_scaled_square[main_axis] * v2[main_axis];
+
+ copy_v3_v3(r_point, v2);
+ }
+ else { /* the nearest point of the ray is on the edge of the `AABB`. */
+ r_axis_closest[main_axis] = (proj - v1[main_axis]) < (v2[main_axis] - proj);
+
+ depth_sq = mul + data->ray.direction_scaled_square[main_axis] * proj;
+#if 0
+ r_point[0] = main_axis == 0 ? proj : v2[0];
+ r_point[1] = main_axis == 1 ? proj : v2[1];
+ r_point[2] = main_axis == 2 ? proj : v2[2];
+#else
+ v2[main_axis] = proj;
+ copy_v3_v3(r_point, v2);
+#endif
+ }
+ depth_sq *= depth_sq;
+
+ if (r_depth_sq)
+ *r_depth_sq = depth_sq;
+
+ /* TODO: scale can be optional */
+ r_point[0] *= data->scale[0];
+ r_point[1] *= data->scale[1];
+ r_point[2] *= data->scale[2];
+
+ return len_squared_v3(r_point) - depth_sq;
+ }
+}
+
+/**
+ * <pre>
+ * + r_point
+ * |
+ * | dist
+ * |
+ * +----depth----+orig <-- dir
+ *
+ * tangent = dist/depth
+ * </pre>
+ */
+static float calc_tangent_sq(BVHNearestRayData *data, BVHNode *node)
+{
+ float depth_sq;
+ const float dist_sq = dist_squared_ray_to_aabb_scaled_v3__impl(
+ data, node->bv, &depth_sq, data->pick_smallest);
+
+ return (dist_sq != 0.0f) ? (dist_sq / depth_sq) : 0.0f;
+}
+
static float calc_dist_sq_to_ray(BVHNearestRayData *data, BVHNode *node)
{
- const float *bv = node->bv;
- const float bb_min[3] = {bv[0], bv[2], bv[4]};
- const float bb_max[3] = {bv[1], bv[3], bv[5]};
- return dist_squared_ray_to_aabb_v3(&data->nearest_precalc, bb_min, bb_max, data->pick_smallest);
+ return dist_squared_ray_to_aabb_scaled_v3__impl(
+ data, node->bv, NULL,
+ data->pick_smallest);
}
-static void dfs_find_nearest_to_ray_dfs(BVHNearestRayData *data, BVHNode *node)
+static void dfs_find_lowest_tangent_dfs(BVHNearestRayData *data, BVHNode *node)
{
if (node->totnode == 0) {
if (data->callback) {
- data->callback(data->userdata, node->index, &data->ray, &data->nearest);
+ data->callback(data->userdata, data->ray.origin, data->ray.direction,
+ data->scale, node->index, &data->nearest);
+ }
+ else {
+ data->nearest.index = node->index;
+ data->nearest.dist_sq = calc_tangent_sq(data, node);
+ /* TODO: return a value to the data->nearest.co
+ * not urgent however since users currently define own callbacks */
+ }
+ }
+ else {
+ int i;
+ /* First pick the closest node to dive on */
+ if (data->pick_smallest[node->main_axis]) {
+ for (i = 0; i != node->totnode; i++) {
+ if (calc_tangent_sq(data, node->children[i]) < data->nearest.dist_sq) {
+ dfs_find_lowest_tangent_dfs(data, node->children[i]);
+ }
+ }
}
else {
- const float dist_sq = calc_dist_sq_to_ray(data, node);
- if (dist_sq != FLT_MAX) { /* not an invalid ray */
- data->nearest.index = node->index;
- data->nearest.dist_sq = dist_sq;
- /* TODO: return a value to the data->nearest.co
- * not urgent however since users currently define own callbacks */
+ for (i = node->totnode - 1; i >= 0; i--) {
+ if (calc_tangent_sq(data, node->children[i]) < data->nearest.dist_sq) {
+ dfs_find_lowest_tangent_dfs(data, node->children[i]);
+ }
}
}
}
+}
+
+static void dfs_find_nearest_to_ray_dfs(BVHNearestRayData *data, BVHNode *node)
+{
+ if (node->totnode == 0) {
+ if (data->callback) {
+ data->callback(data->userdata, data->ray.origin, data->ray.direction,
+ data->scale, node->index, &data->nearest);
+ }
+ else {
+ data->nearest.index = node->index;
+ data->nearest.dist_sq = calc_dist_sq_to_ray(data, node);
+ /* TODO: return a value to the data->nearest.co
+ * not urgent however since users currently define own callbacks */
+ }
+ }
else {
int i;
/* First pick the closest node to dive on */
if (data->pick_smallest[node->main_axis]) {
for (i = 0; i != node->totnode; i++) {
- if (calc_dist_sq_to_ray(data, node->children[i]) >= data->nearest.dist_sq) {
- continue;
+ if (calc_dist_sq_to_ray(data, node->children[i]) < data->nearest.dist_sq) {
+ dfs_find_nearest_to_ray_dfs(data, node->children[i]);
}
- dfs_find_nearest_to_ray_dfs(data, node->children[i]);
}
}
else {
for (i = node->totnode - 1; i >= 0; i--) {
- if (calc_dist_sq_to_ray(data, node->children[i]) >= data->nearest.dist_sq) {
- continue;
+ if (calc_dist_sq_to_ray(data, node->children[i]) < data->nearest.dist_sq) {
+ dfs_find_nearest_to_ray_dfs(data, node->children[i]);
}
- dfs_find_nearest_to_ray_dfs(data, node->children[i]);
}
}
}
}
-int BLI_bvhtree_find_nearest_to_ray(
- BVHTree *tree, const float co[3], const float dir[3], BVHTreeNearest *nearest,
+/**
+ * Returns the point whose tangent defined by the angle between the point and ray is the lowest
+ * nearest.dist_sq returns the angle's tangent
+ */
+int BLI_bvhtree_find_nearest_to_ray_angle(
+ BVHTree *tree, const float co[3], const float dir[3],
+ const bool ray_is_normalized, const float scale[3],
+ BVHTreeNearest *nearest,
BVHTree_NearestToRayCallback callback, void *userdata)
{
BVHNearestRayData data;
@@ -1951,11 +2278,46 @@ int BLI_bvhtree_find_nearest_to_ray(
data.callback = callback;
data.userdata = userdata;
- copy_v3_v3(data.ray.origin, co);
- copy_v3_v3(data.ray.direction, dir);
- data.ray.radius = 0.0f; /* unused here */
+ dist_squared_ray_to_aabb_scaled_v3_precalc(&data, co, dir, ray_is_normalized, scale);
+
+ if (nearest) {
+ memcpy(&data.nearest, nearest, sizeof(*nearest));
+ }
+ else {
+ data.nearest.index = -1;
+ data.nearest.dist_sq = FLT_MAX;
+ }
+
+ /* dfs search */
+ if (root) {
+ if (calc_tangent_sq(&data, root) < data.nearest.dist_sq)
+ dfs_find_lowest_tangent_dfs(&data, root);
+ }
+
+ /* copy back results */
+ if (nearest) {
+ memcpy(nearest, &data.nearest, sizeof(*nearest));
+ }
+
+ return data.nearest.index;
+}
+
+/* return the nearest point to ray */
+int BLI_bvhtree_find_nearest_to_ray(
+ BVHTree *tree, const float co[3], const float dir[3],
+ const bool ray_is_normalized, const float scale[3],
+ BVHTreeNearest *nearest,
+ BVHTree_NearestToRayCallback callback, void *userdata)
+{
+ BVHNearestRayData data;
+ BVHNode *root = tree->nodes[tree->totleaf];
+
+ data.tree = tree;
+
+ data.callback = callback;
+ data.userdata = userdata;
- dist_squared_ray_to_aabb_v3_precalc(&data.nearest_precalc, co, dir);
+ dist_squared_ray_to_aabb_scaled_v3_precalc(&data, co, dir, ray_is_normalized, scale);
if (nearest) {
memcpy(&data.nearest, nearest, sizeof(*nearest));
diff --git a/source/blender/blenlib/intern/BLI_mempool.c b/source/blender/blenlib/intern/BLI_mempool.c
index 7338804c685..783dba5510c 100644
--- a/source/blender/blenlib/intern/BLI_mempool.c
+++ b/source/blender/blenlib/intern/BLI_mempool.c
@@ -57,12 +57,29 @@
#ifdef __BIG_ENDIAN__
/* Big Endian */
# define MAKE_ID(a, b, c, d) ( (int)(a) << 24 | (int)(b) << 16 | (c) << 8 | (d) )
+# define MAKE_ID_8(a, b, c, d, e, f, g, h) \
+ ((int64_t)(a) << 56 | (int64_t)(b) << 48 | (int64_t)(c) << 40 | (int64_t)(d) << 32 | \
+ (int64_t)(e) << 24 | (int64_t)(f) << 16 | (int64_t)(g) << 8 | (h) )
#else
/* Little Endian */
# define MAKE_ID(a, b, c, d) ( (int)(d) << 24 | (int)(c) << 16 | (b) << 8 | (a) )
+# define MAKE_ID_8(a, b, c, d, e, f, g, h) \
+ ((int64_t)(h) << 56 | (int64_t)(g) << 48 | (int64_t)(f) << 40 | (int64_t)(e) << 32 | \
+ (int64_t)(d) << 24 | (int64_t)(c) << 16 | (int64_t)(b) << 8 | (a) )
#endif
-#define FREEWORD MAKE_ID('f', 'r', 'e', 'e')
+/**
+ * Important that this value is an is _not_ aligned with ``sizeof(void *)``.
+ * So having a pointer to 2/4/8... aligned memory is enough to ensure the freeword will never be used.
+ * To be safe, use a word thats the same in both directions.
+ */
+#define FREEWORD ((sizeof(void *) > sizeof(int32_t)) ? \
+ MAKE_ID_8('e', 'e', 'r', 'f', 'f', 'r', 'e', 'e') : \
+ MAKE_ID('e', 'f', 'f', 'e'))
+
+/**
+ * The 'used' word just needs to be set to something besides FREEWORD.
+ */
#define USEDWORD MAKE_ID('u', 's', 'e', 'd')
/* currently totalloc isnt used */
@@ -87,7 +104,7 @@ static bool mempool_debug_memset = false;
*/
typedef struct BLI_freenode {
struct BLI_freenode *next;
- int freeword; /* used to identify this as a freed node */
+ intptr_t freeword; /* used to identify this as a freed node */
} BLI_freenode;
/**
@@ -588,19 +605,26 @@ void *BLI_mempool_iterstep(BLI_mempool_iter *iter)
*/
void *BLI_mempool_iterstep(BLI_mempool_iter *iter)
{
- BLI_freenode *ret;
+ if (UNLIKELY(iter->curchunk == NULL)) {
+ return NULL;
+ }
+ const unsigned int esize = iter->pool->esize;
+ BLI_freenode *curnode = POINTER_OFFSET(CHUNK_DATA(iter->curchunk), (esize * iter->curindex));
+ BLI_freenode *ret;
do {
- if (LIKELY(iter->curchunk)) {
- ret = (BLI_freenode *)(((char *)CHUNK_DATA(iter->curchunk)) + (iter->pool->esize * iter->curindex));
+ ret = curnode;
+
+ if (++iter->curindex != iter->pool->pchunk) {
+ curnode = POINTER_OFFSET(curnode, esize);
}
else {
- return NULL;
- }
-
- if (UNLIKELY(++iter->curindex == iter->pool->pchunk)) {
iter->curindex = 0;
iter->curchunk = iter->curchunk->next;
+ if (iter->curchunk == NULL) {
+ return (ret->freeword == FREEWORD) ? NULL : ret;
+ }
+ curnode = CHUNK_DATA(iter->curchunk);
}
} while (ret->freeword == FREEWORD);
diff --git a/source/blender/blenlib/intern/array_store.c b/source/blender/blenlib/intern/array_store.c
new file mode 100644
index 00000000000..21ddddad32e
--- /dev/null
+++ b/source/blender/blenlib/intern/array_store.c
@@ -0,0 +1,1811 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenlib/intern/array_store.c
+ * \ingroup bli
+ * \brief Array storage to minimize duplication.
+ *
+ * This is done by splitting arrays into chunks and using copy-on-write (COW),
+ * to de-duplicate chunks,
+ * from the users perspective this is an implementation detail.
+ *
+ *
+ * Overview
+ * ========
+ *
+ *
+ * Data Structure
+ * --------------
+ *
+ * This diagram is an overview of the structure of a single array-store.
+ *
+ * \note The only 2 structures here which are referenced externally are the.
+ *
+ * - BArrayStore: The whole array store.
+ * - BArrayState: Represents a single state (array) of data.
+ * These can be add using a reference state, while this could be considered the previous or parent state.
+ * no relationship is kept, so the caller is free to add any state from the same BArrayStore as a reference.
+ *
+ * <pre>
+ * <+> BArrayStore: root data-structure,
+ * | can store many 'states', which share memory.
+ * |
+ * | This can store many arrays, however they must share the same 'stride'.
+ * | Arrays of different types will need to use a new BArrayStore.
+ * |
+ * +- <+> states (Collection of BArrayState's):
+ * | | Each represents an array added by the user of this API.
+ * | | and references a chunk_list (each state is a chunk_list user).
+ * | | Note that the list order has no significance.
+ * | |
+ * | +- <+> chunk_list (BChunkList):
+ * | | The chunks that make up this state.
+ * | | Each state is a chunk_list user,
+ * | | avoids duplicating lists when there is no change between states.
+ * | |
+ * | +- chunk_refs (List of BChunkRef): Each chunk_ref links to a a BChunk.
+ * | Each reference is a chunk user,
+ * | avoids duplicating smaller chunks of memory found in multiple states.
+ * |
+ * +- info (BArrayInfo):
+ * | Sizes and offsets for this array-store.
+ * | Also caches some variables for reuse.
+ * |
+ * +- <+> memory (BArrayMemory):
+ * | Memory pools for storing BArrayStore data.
+ * |
+ * +- chunk_list (Pool of BChunkList):
+ * | All chunk_lists, (reference counted, used by BArrayState).
+ * |
+ * +- chunk_ref (Pool of BChunkRef):
+ * | All chunk_refs (link between BChunkList & BChunk).
+ * |
+ * +- chunks (Pool of BChunk):
+ * All chunks, (reference counted, used by BChunkList).
+ * These have their headers hashed for reuse so we can quickly check for duplicates.
+ * </pre>
+ *
+ *
+ * De-Duplication
+ * --------------
+ *
+ * When creating a new state, a previous state can be given as a reference,
+ * matching chunks from this state are re-used in the new state.
+ *
+ * First matches at either end of the array are detected.
+ * For identical arrays this is all thats needed.
+ *
+ * De-duplication is performed on any remaining chunks, by hashing the first few bytes of the chunk
+ * (see: BCHUNK_HASH_TABLE_ACCUMULATE_STEPS).
+ *
+ * \note This is cached for reuse since the referenced data never changes.
+ *
+ * An array is created to store hash values at every 'stride',
+ * then stepped over to search for matching chunks.
+ *
+ * Once a match is found, there is a high chance next chunks match too,
+ * so this is checked to avoid performing so many hash-lookups.
+ * Otherwise new chunks are created.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+#include "BLI_mempool.h"
+
+#include "BLI_strict_flags.h"
+
+#include "BLI_array_store.h" /* own include */
+
+/* only for BLI_array_store_is_valid */
+#include "BLI_ghash.h"
+
+/** \name Defines
+ *
+ * Some of the logic for merging is quite involved,
+ * support disabling some parts of this.
+ * \{ */
+
+/* Scan first chunks (happy path when beginning of the array matches).
+ * When the array is a perfect match, we can re-use the entire list.
+ *
+ * Note that disabling makes some tests fail that check for output-size.
+ */
+#define USE_FASTPATH_CHUNKS_FIRST
+
+/* Scan last chunks (happy path when end of the array matches).
+ * When the end of the array matches, we can quickly add these chunks.
+ * note that we will add contiguous matching chunks
+ * so this isn't as useful as USE_FASTPATH_CHUNKS_FIRST,
+ * however it avoids adding matching chunks into the lookup table,
+ * so creating the lookup table won't be as expensive.
+ */
+#ifdef USE_FASTPATH_CHUNKS_FIRST
+# define USE_FASTPATH_CHUNKS_LAST
+#endif
+
+/* For arrays of matching length, test that *enough* of the chunks are aligned,
+ * and simply step over both arrays, using matching chunks.
+ * This avoids overhead of using a lookup table for cases when we can assume they're mostly aligned.
+ */
+#define USE_ALIGN_CHUNKS_TEST
+
+/* Accumulate hashes from right to left so we can create a hash for the chunk-start.
+ * This serves to increase uniqueness and will help when there is many values which are the same.
+ */
+#define USE_HASH_TABLE_ACCUMULATE
+
+#ifdef USE_HASH_TABLE_ACCUMULATE
+/* Number of times to propagate hashes back.
+ * Effectively a 'triangle-number'.
+ * so 4 -> 7, 5 -> 10, 6 -> 15... etc.
+ */
+# define BCHUNK_HASH_TABLE_ACCUMULATE_STEPS 4
+#else
+/* How many items to hash (multiplied by stride)
+ */
+# define BCHUNK_HASH_LEN 4
+#endif
+
+/* Calculate the key once and reuse it
+ */
+#define USE_HASH_TABLE_KEY_CACHE
+#ifdef USE_HASH_TABLE_KEY_CACHE
+# define HASH_TABLE_KEY_UNSET ((uint64_t)-1)
+# define HASH_TABLE_KEY_FALLBACK ((uint64_t)-2)
+#endif
+
+/* How much larger the table is then the total number of chunks.
+ */
+#define BCHUNK_HASH_TABLE_MUL 3
+
+/* Merge too small/large chunks:
+ *
+ * Using this means chunks below a threshold will be merged together.
+ * Even though short term this uses more memory,
+ * long term the overhead of maintaining many small chunks is reduced.
+ * This is defined by setting the minimum chunk size (as a fraction of the regular chunk size).
+ *
+ * Chunks may also become too large (when incrementally growing an array),
+ * this also enables chunk splitting.
+ */
+#define USE_MERGE_CHUNKS
+
+#ifdef USE_MERGE_CHUNKS
+/* Merge chunks smaller then: (chunk_size / BCHUNK_MIN_SIZE_DIV)
+ */
+# define BCHUNK_SIZE_MIN_DIV 8
+
+/* Disallow chunks bigger then the regular chunk size scaled by this value
+ * note: must be at least 2!
+ * however, this code runs wont run in tests unless its ~1.1 ugh.
+ * so lower only to check splitting works.
+ */
+# define BCHUNK_SIZE_MAX_MUL 2
+#endif /* USE_MERGE_CHUNKS */
+
+/* slow (keep disabled), but handy for debugging */
+// #define USE_VALIDATE_LIST_SIZE
+
+// #define USE_VALIDATE_LIST_DATA_PARTIAL
+
+// #define USE_PARANOID_CHECKS
+
+/** \} */
+
+
+/** \name Internal Structs
+ * \{ */
+
+typedef unsigned int uint;
+typedef unsigned char ubyte;
+
+typedef uint64_t hash_key;
+
+
+typedef struct BArrayInfo {
+ size_t chunk_stride;
+ uint chunk_count;
+
+ /* pre-calculated */
+ size_t chunk_byte_size;
+ /* min/max limits (inclusive) */
+ size_t chunk_byte_size_min;
+ size_t chunk_byte_size_max;
+
+ size_t accum_read_ahead_bytes;
+#ifdef USE_HASH_TABLE_ACCUMULATE
+ size_t accum_steps;
+ size_t accum_read_ahead_len;
+#endif
+} BArrayInfo;
+
+typedef struct BArrayMemory {
+ BLI_mempool *chunk_list; /* BChunkList */
+ BLI_mempool *chunk_ref; /* BChunkRef */
+ BLI_mempool *chunk; /* BChunk */
+} BArrayMemory;
+
+/**
+ * Main storage for all states
+ */
+struct BArrayStore {
+ /* static */
+ BArrayInfo info;
+
+ /* memory storage */
+ BArrayMemory memory;
+
+ /**
+ * #BArrayState may be in any order (logic should never depend on state order).
+ */
+ ListBase states;
+};
+
+/**
+ * A single instance of an array.
+ *
+ * This is how external API's hold a reference to an in-memory state,
+ * although the struct is private.
+ *
+ * \note Currently each 'state' is allocated separately.
+ * While this could be moved to a memory pool,
+ * it makes it easier to trace invalid usage, so leave as-is for now.
+ */
+struct BArrayState {
+ /** linked list in #BArrayStore.states */
+ struct BArrayState *next, *prev;
+
+ struct BChunkList *chunk_list; /* BChunkList's */
+
+};
+
+typedef struct BChunkList {
+ ListBase chunk_refs; /* BChunkRef's */
+ uint chunk_refs_len; /* BLI_listbase_count(chunks), store for reuse. */
+ size_t total_size; /* size of all chunks */
+
+ /** number of #BArrayState using this. */
+ int users;
+} BChunkList;
+
+/* a chunk of an array */
+typedef struct BChunk {
+ const ubyte *data;
+ size_t data_len;
+ /** number of #BChunkList using this. */
+ int users;
+
+#ifdef USE_HASH_TABLE_KEY_CACHE
+ hash_key key;
+#endif
+} BChunk;
+
+/**
+ * Links to store #BChunk data in #BChunkList.chunks.
+ */
+typedef struct BChunkRef {
+ struct BChunkRef *next, *prev;
+ BChunk *link;
+} BChunkRef;
+
+/**
+ * Single linked list used when putting chunks into a temporary table,
+ * used for lookups.
+ *
+ * Point to the #BChunkRef, not the #BChunk,
+ * to allow talking down the chunks in-order until a mis-match is found,
+ * this avoids having to do so many table lookups.
+ */
+typedef struct BTableRef {
+ struct BTableRef *next;
+ const BChunkRef *cref;
+} BTableRef;
+
+/** \} */
+
+
+static size_t bchunk_list_size(const BChunkList *chunk_list);
+
+
+/** \name Internal BChunk API
+ * \{ */
+
+static BChunk *bchunk_new(
+ BArrayMemory *bs_mem, const ubyte *data, const size_t data_len)
+{
+ BChunk *chunk = BLI_mempool_alloc(bs_mem->chunk);
+ chunk->data = data;
+ chunk->data_len = data_len;
+ chunk->users = 0;
+#ifdef USE_HASH_TABLE_KEY_CACHE
+ chunk->key = HASH_TABLE_KEY_UNSET;
+#endif
+ return chunk;
+}
+
+static BChunk *bchunk_new_copydata(
+ BArrayMemory *bs_mem, const ubyte *data, const size_t data_len)
+{
+ ubyte *data_copy = MEM_mallocN(data_len, __func__);
+ memcpy(data_copy, data, data_len);
+ return bchunk_new(bs_mem, data_copy, data_len);
+}
+
+static void bchunk_decref(
+ BArrayMemory *bs_mem, BChunk *chunk)
+{
+ BLI_assert(chunk->users > 0);
+ if (chunk->users == 1) {
+ MEM_freeN((void *)chunk->data);
+ BLI_mempool_free(bs_mem->chunk, chunk);
+ }
+ else {
+ chunk->users -= 1;
+ }
+}
+
+static bool bchunk_data_compare(
+ const BChunk *chunk,
+ const ubyte *data_base, const size_t data_base_len,
+ const size_t offset)
+{
+ if (offset + (size_t)chunk->data_len <= data_base_len) {
+ return (memcmp(&data_base[offset], chunk->data, chunk->data_len) == 0);
+ }
+ else {
+ return false;
+ }
+}
+
+/** \} */
+
+
+/** \name Internal BChunkList API
+ * \{ */
+
+static BChunkList *bchunk_list_new(
+ BArrayMemory *bs_mem, size_t total_size)
+{
+ BChunkList *chunk_list = BLI_mempool_alloc(bs_mem->chunk_list);
+
+ BLI_listbase_clear(&chunk_list->chunk_refs);
+ chunk_list->chunk_refs_len = 0;
+ chunk_list->total_size = total_size;
+ chunk_list->users = 0;
+ return chunk_list;
+}
+
+static void bchunk_list_decref(
+ BArrayMemory *bs_mem, BChunkList *chunk_list)
+{
+ BLI_assert(chunk_list->users > 0);
+ if (chunk_list->users == 1) {
+ for (BChunkRef *cref = chunk_list->chunk_refs.first, *cref_next; cref; cref = cref_next) {
+ cref_next = cref->next;
+ bchunk_decref(bs_mem, cref->link);
+ BLI_mempool_free(bs_mem->chunk_ref, cref);
+ }
+
+ BLI_mempool_free(bs_mem->chunk_list, chunk_list);
+ }
+ else {
+ chunk_list->users -= 1;
+ }
+}
+
+#ifdef USE_VALIDATE_LIST_SIZE
+# ifndef NDEBUG
+# define ASSERT_CHUNKLIST_SIZE(chunk_list, n) BLI_assert(bchunk_list_size(chunk_list) == n)
+# endif
+#endif
+#ifndef ASSERT_CHUNKLIST_SIZE
+# define ASSERT_CHUNKLIST_SIZE(chunk_list, n) (EXPR_NOP(chunk_list), EXPR_NOP(n))
+#endif
+
+
+#ifdef USE_VALIDATE_LIST_DATA_PARTIAL
+static size_t bchunk_list_data_check(
+ const BChunkList *chunk_list, const ubyte *data)
+{
+ size_t total_size = 0;
+ for (BChunkRef *cref = chunk_list->chunk_refs.first; cref; cref = cref->next) {
+ if (memcmp(&data[total_size], cref->link->data, cref->link->data_len) != 0) {
+ return false;
+ }
+ total_size += cref->link->data_len;
+ }
+ return true;
+}
+# define ASSERT_CHUNKLIST_DATA(chunk_list, data) BLI_assert(bchunk_list_data_check(chunk_list, data))
+#else
+# define ASSERT_CHUNKLIST_DATA(chunk_list, data) (EXPR_NOP(chunk_list), EXPR_NOP(data))
+#endif
+
+
+#ifdef USE_MERGE_CHUNKS
+static void bchunk_list_ensure_min_size_last(
+ const BArrayInfo *info, BArrayMemory *bs_mem,
+ BChunkList *chunk_list)
+{
+ BChunkRef *cref = chunk_list->chunk_refs.last;
+ if (cref && cref->prev) {
+ /* both are decref'd after use (end of this block) */
+ BChunk *chunk_curr = cref->link;
+ BChunk *chunk_prev = cref->prev->link;
+
+ if (MIN2(chunk_prev->data_len, chunk_curr->data_len) < info->chunk_byte_size_min) {
+ const size_t data_merge_len = chunk_prev->data_len + chunk_curr->data_len;
+ /* we could pass, but no need */
+ if (data_merge_len <= info->chunk_byte_size_max) {
+ /* we have enough space to merge */
+
+ /* remove last from linklist */
+ BLI_assert(chunk_list->chunk_refs.last != chunk_list->chunk_refs.first);
+ cref->prev->next = NULL;
+ chunk_list->chunk_refs.last = cref->prev;
+ chunk_list->chunk_refs_len -= 1;
+
+ ubyte *data_merge = MEM_mallocN(data_merge_len, __func__);
+ memcpy(data_merge, chunk_prev->data, chunk_prev->data_len);
+ memcpy(&data_merge[chunk_prev->data_len], chunk_curr->data, chunk_curr->data_len);
+
+ cref->prev->link = bchunk_new(bs_mem, data_merge, data_merge_len);
+ cref->prev->link->users += 1;
+
+ BLI_mempool_free(bs_mem->chunk_ref, cref);
+ }
+ else {
+ /* If we always merge small slices, we should _almost_ never end up having very large chunks.
+ * Gradual expanding on contracting will cause this.
+ *
+ * if we do, the code below works (test by setting 'BCHUNK_SIZE_MAX_MUL = 1.2') */
+
+ /* keep chunk on the left hand side a regular size */
+ const size_t split = info->chunk_byte_size;
+
+ /* merge and split */
+ const size_t data_prev_len = split;
+ const size_t data_curr_len = data_merge_len - split;
+ ubyte *data_prev = MEM_mallocN(data_prev_len, __func__);
+ ubyte *data_curr = MEM_mallocN(data_curr_len, __func__);
+
+ if (data_prev_len <= chunk_prev->data_len) {
+ const size_t data_curr_shrink_len = chunk_prev->data_len - data_prev_len;
+
+ /* setup 'data_prev' */
+ memcpy(data_prev, chunk_prev->data, data_prev_len);
+
+ /* setup 'data_curr' */
+ memcpy(data_curr, &chunk_prev->data[data_prev_len], data_curr_shrink_len);
+ memcpy(&data_curr[data_curr_shrink_len], chunk_curr->data, chunk_curr->data_len);
+ }
+ else {
+ BLI_assert(data_curr_len <= chunk_curr->data_len);
+ BLI_assert(data_prev_len >= chunk_prev->data_len);
+
+ const size_t data_prev_grow_len = data_prev_len - chunk_prev->data_len;
+
+ /* setup 'data_prev' */
+ memcpy(data_prev, chunk_prev->data, chunk_prev->data_len);
+ memcpy(&data_prev[chunk_prev->data_len], chunk_curr->data, data_prev_grow_len);
+
+ /* setup 'data_curr' */
+ memcpy(data_curr, &chunk_curr->data[data_prev_grow_len], data_curr_len);
+ }
+
+ cref->prev->link = bchunk_new(bs_mem, data_prev, data_prev_len);
+ cref->prev->link->users += 1;
+
+ cref->link = bchunk_new(bs_mem, data_curr, data_curr_len);
+ cref->link->users += 1;
+ }
+
+ /* free zero users */
+ bchunk_decref(bs_mem, chunk_curr);
+ bchunk_decref(bs_mem, chunk_prev);
+ }
+ }
+}
+#endif /* USE_MERGE_CHUNKS */
+
+
+/**
+ * Split length into 2 values
+ * \param r_data_trim_len: Length which is aligned to the #BArrayInfo.chunk_byte_size
+ * \param r_data_last_chunk_len: The remaining bytes.
+ *
+ * \note This function ensures the size of \a r_data_last_chunk_len
+ * is larger than #BArrayInfo.chunk_byte_size_min.
+ */
+static void bchunk_list_calc_trim_len(
+ const BArrayInfo *info, const size_t data_len,
+ size_t *r_data_trim_len, size_t *r_data_last_chunk_len)
+{
+ size_t data_last_chunk_len = 0;
+ size_t data_trim_len = data_len;
+
+#ifdef USE_MERGE_CHUNKS
+ /* avoid creating too-small chunks
+ * more efficient then merging after */
+ if (data_len > info->chunk_byte_size) {
+ data_last_chunk_len = (data_trim_len % info->chunk_byte_size);
+ data_trim_len = data_trim_len - data_last_chunk_len;
+ if (data_last_chunk_len) {
+ if (data_last_chunk_len < info->chunk_byte_size_min) {
+ /* may be zero and thats OK */
+ data_trim_len -= info->chunk_byte_size;
+ data_last_chunk_len += info->chunk_byte_size;
+ }
+ }
+ }
+ else {
+ data_trim_len = 0;
+ data_last_chunk_len = data_len;
+ }
+
+ BLI_assert((data_trim_len == 0) || (data_trim_len >= info->chunk_byte_size));
+#else
+ data_last_chunk_len = (data_trim_len % info->chunk_byte_size);
+ data_trim_len = data_trim_len - data_last_chunk_len;
+#endif
+
+ BLI_assert(data_trim_len + data_last_chunk_len == data_len);
+
+ *r_data_trim_len = data_trim_len;
+ *r_data_last_chunk_len = data_last_chunk_len;
+}
+
+/**
+ * Append and don't manage merging small chunks.
+ */
+static void bchunk_list_append_only(
+ BArrayMemory *bs_mem,
+ BChunkList *chunk_list, BChunk *chunk)
+{
+ BChunkRef *cref = BLI_mempool_alloc(bs_mem->chunk_ref);
+ BLI_addtail(&chunk_list->chunk_refs, cref);
+ cref->link = chunk;
+ chunk_list->chunk_refs_len += 1;
+ chunk->users += 1;
+}
+
+/**
+ * \note This is for writing single chunks,
+ * use #bchunk_list_append_data_n when writing large blocks of memory into many chunks.
+ */
+static void bchunk_list_append_data(
+ const BArrayInfo *info, BArrayMemory *bs_mem,
+ BChunkList *chunk_list,
+ const ubyte *data, const size_t data_len)
+{
+ BLI_assert(data_len != 0);
+
+ // printf("data_len: %d\n", data_len);
+#ifdef USE_MERGE_CHUNKS
+ BLI_assert(data_len <= info->chunk_byte_size_max);
+
+ if (!BLI_listbase_is_empty(&chunk_list->chunk_refs)) {
+ BChunkRef *cref = chunk_list->chunk_refs.last;
+ BChunk *chunk_prev = cref->link;
+
+ if (MIN2(chunk_prev->data_len, data_len) < info->chunk_byte_size_min) {
+ const size_t data_merge_len = chunk_prev->data_len + data_len;
+ /* realloc for single user */
+ if (cref->link->users == 1) {
+ ubyte *data_merge = MEM_reallocN((void *)cref->link->data, data_merge_len);
+ memcpy(&data_merge[chunk_prev->data_len], data, data_len);
+ cref->link->data = data_merge;
+ cref->link->data_len = data_merge_len;
+ }
+ else {
+ ubyte *data_merge = MEM_mallocN(data_merge_len, __func__);
+ memcpy(data_merge, chunk_prev->data, chunk_prev->data_len);
+ memcpy(&data_merge[chunk_prev->data_len], data, data_len);
+ cref->link = bchunk_new(bs_mem, data_merge, data_merge_len);
+ cref->link->users += 1;
+ bchunk_decref(bs_mem, chunk_prev);
+ }
+ return;
+ }
+ }
+#else
+ UNUSED_VARS(info);
+#endif /* USE_MERGE_CHUNKS */
+
+ BChunk *chunk = bchunk_new_copydata(bs_mem, data, data_len);
+ bchunk_list_append_only(bs_mem, chunk_list, chunk);
+
+ /* don't run this, instead preemptively avoid creating a chunk only to merge it (above). */
+#if 0
+#ifdef USE_MERGE_CHUNKS
+ bchunk_list_ensure_min_size_last(info, bs_mem, chunk_list, chunk_size_min);
+#endif
+#endif
+}
+
+/**
+ * Similar to #bchunk_list_append_data, but handle multiple chunks.
+ * Use for adding arrays of arbitrary sized memory at once.
+ *
+ * \note This function takes care not to perform redundant chunk-merging checks,
+ * so we can write successive fixed size chunks quickly.
+ */
+static void bchunk_list_append_data_n(
+ const BArrayInfo *info, BArrayMemory *bs_mem,
+ BChunkList *chunk_list,
+ const ubyte *data, size_t data_len)
+{
+ size_t data_trim_len, data_last_chunk_len;
+ bchunk_list_calc_trim_len(info, data_len, &data_trim_len, &data_last_chunk_len);
+
+ if (data_trim_len != 0) {
+ size_t i_prev;
+
+ {
+ const size_t i = info->chunk_byte_size;
+ bchunk_list_append_data(info, bs_mem, chunk_list, data, i);
+ i_prev = i;
+ }
+
+ while (i_prev != data_trim_len) {
+ const size_t i = i_prev + info->chunk_byte_size;
+ BChunk *chunk = bchunk_new_copydata(bs_mem, &data[i_prev], i - i_prev);
+ bchunk_list_append_only(bs_mem, chunk_list, chunk);
+ i_prev = i;
+ }
+
+ if (data_last_chunk_len) {
+ BChunk *chunk = bchunk_new_copydata(bs_mem, &data[i_prev], data_last_chunk_len);
+ bchunk_list_append_only(bs_mem, chunk_list, chunk);
+ // i_prev = data_len; /* UNUSED */
+ }
+ }
+ else {
+ /* if we didn't write any chunks previously,
+ * we may need to merge with the last. */
+ if (data_last_chunk_len) {
+ bchunk_list_append_data(info, bs_mem, chunk_list, data, data_last_chunk_len);
+ // i_prev = data_len; /* UNUSED */
+ }
+ }
+
+#ifdef USE_MERGE_CHUNKS
+ if (data_len > info->chunk_byte_size) {
+ BLI_assert(((BChunkRef *)chunk_list->chunk_refs.last)->link->data_len >= info->chunk_byte_size_min);
+ }
+#endif
+}
+
+static void bchunk_list_append(
+ const BArrayInfo *info, BArrayMemory *bs_mem,
+ BChunkList *chunk_list,
+ BChunk *chunk)
+{
+ bchunk_list_append_only(bs_mem, chunk_list, chunk);
+
+#ifdef USE_MERGE_CHUNKS
+ bchunk_list_ensure_min_size_last(info, bs_mem, chunk_list);
+#else
+ UNUSED_VARS(info);
+#endif
+}
+
+static void bchunk_list_fill_from_array(
+ const BArrayInfo *info, BArrayMemory *bs_mem,
+ BChunkList *chunk_list,
+ const ubyte *data,
+ const size_t data_len)
+{
+ BLI_assert(BLI_listbase_is_empty(&chunk_list->chunk_refs));
+
+ size_t data_trim_len, data_last_chunk_len;
+ bchunk_list_calc_trim_len(info, data_len, &data_trim_len, &data_last_chunk_len);
+
+ size_t i_prev = 0;
+ while (i_prev != data_trim_len) {
+ const size_t i = i_prev + info->chunk_byte_size;
+ BChunk *chunk = bchunk_new_copydata(bs_mem, &data[i_prev], i - i_prev);
+ bchunk_list_append_only(bs_mem, chunk_list, chunk);
+ i_prev = i;
+ }
+
+ if (data_last_chunk_len) {
+ BChunk *chunk = bchunk_new_copydata(bs_mem, &data[i_prev], data_last_chunk_len);
+ bchunk_list_append_only(bs_mem, chunk_list, chunk);
+ // i_prev = data_len;
+ }
+
+#ifdef USE_MERGE_CHUNKS
+ if (data_len > info->chunk_byte_size) {
+ BLI_assert(((BChunkRef *)chunk_list->chunk_refs.last)->link->data_len >= info->chunk_byte_size_min);
+ }
+#endif
+
+ /* works but better avoid redundant re-alloc */
+#if 0
+#ifdef USE_MERGE_CHUNKS
+ bchunk_list_ensure_min_size_last(info, bs_mem, chunk_list);
+#endif
+#endif
+
+ ASSERT_CHUNKLIST_SIZE(chunk_list, data_len);
+ ASSERT_CHUNKLIST_DATA(chunk_list, data);
+}
+
+
+/* ---------------------------------------------------------------------------
+ * Internal Table Lookup Functions
+ */
+
+/** \name Internal Hashing/De-Duplication API
+ *
+ * Only used by #bchunk_list_from_data_merge
+ * \{ */
+
+#define HASH_INIT (5381)
+
+BLI_INLINE uint hash_data_single(const ubyte p)
+{
+ return (HASH_INIT << 5) + HASH_INIT + (unsigned int)p;
+}
+
+/* hash bytes, from BLI_ghashutil_strhash_n */
+static uint hash_data(const ubyte *key, size_t n)
+{
+ const signed char *p;
+ unsigned int h = HASH_INIT;
+
+ for (p = (const signed char *)key; n--; p++) {
+ h = (h << 5) + h + (unsigned int)*p;
+ }
+
+ return h;
+}
+
+#undef HASH_INIT
+
+
+#ifdef USE_HASH_TABLE_ACCUMULATE
+static void hash_array_from_data(
+ const BArrayInfo *info, const ubyte *data_slice, const size_t data_slice_len,
+ hash_key *hash_array)
+{
+ if (info->chunk_stride != 1) {
+ for (size_t i = 0, i_step = 0; i_step < data_slice_len; i++, i_step += info->chunk_stride) {
+ hash_array[i] = hash_data(&data_slice[i_step], info->chunk_stride);
+ }
+ }
+ else {
+ /* fast-path for bytes */
+ for (size_t i = 0; i < data_slice_len; i++) {
+ hash_array[i] = hash_data_single(data_slice[i]);
+ }
+ }
+}
+
+/*
+ * Similar to hash_array_from_data,
+ * but able to step into the next chunk if we run-out of data.
+ */
+static void hash_array_from_cref(
+ const BArrayInfo *info, const BChunkRef *cref, const size_t data_len,
+ hash_key *hash_array)
+{
+ const size_t hash_array_len = data_len / info->chunk_stride;
+ size_t i = 0;
+ do {
+ size_t i_next = hash_array_len - i;
+ size_t data_trim_len = i_next * info->chunk_stride;
+ if (data_trim_len > cref->link->data_len) {
+ data_trim_len = cref->link->data_len;
+ i_next = data_trim_len / info->chunk_stride;
+ }
+ BLI_assert(data_trim_len <= cref->link->data_len);
+ hash_array_from_data(info, cref->link->data, data_trim_len, &hash_array[i]);
+ i += i_next;
+ cref = cref->next;
+ } while ((i < hash_array_len) && (cref != NULL));
+
+ /* If this isn't equal, the caller didn't properly check
+ * that there was enough data left in all chunks */
+ BLI_assert(i == hash_array_len);
+}
+
+static void hash_accum(hash_key *hash_array, const size_t hash_array_len, size_t iter_steps)
+{
+ /* _very_ unlikely, can happen if you select a chunk-size of 1 for example. */
+ if (UNLIKELY((iter_steps > hash_array_len))) {
+ iter_steps = hash_array_len;
+ }
+
+ const size_t hash_array_search_len = hash_array_len - iter_steps;
+ while (iter_steps != 0) {
+ const size_t hash_offset = iter_steps;
+ for (uint i = 0; i < hash_array_search_len; i++) {
+ hash_array[i] += (hash_array[i + hash_offset]) * ((hash_array[i] & 0xff) + 1);
+ }
+ iter_steps -= 1;
+ }
+}
+
+/**
+ * When we only need a single value, can use a small optimization.
+ * we can avoid accumulating the tail of the array a little, each iteration.
+ */
+static void hash_accum_single(hash_key *hash_array, const size_t hash_array_len, size_t iter_steps)
+{
+ BLI_assert(iter_steps <= hash_array_len);
+ if (UNLIKELY(!(iter_steps <= hash_array_len))) {
+ /* while this shouldn't happen, avoid crashing */
+ iter_steps = hash_array_len;
+ }
+ /* We can increase this value each step to avoid accumulating quite as much
+ * while getting the same results as hash_accum */
+ size_t iter_steps_sub = iter_steps;
+
+ while (iter_steps != 0) {
+ const size_t hash_array_search_len = hash_array_len - iter_steps_sub;
+ const size_t hash_offset = iter_steps;
+ for (uint i = 0; i < hash_array_search_len; i++) {
+ hash_array[i] += (hash_array[i + hash_offset]) * ((hash_array[i] & 0xff) + 1);
+ }
+ iter_steps -= 1;
+ iter_steps_sub += iter_steps;
+ }
+}
+
+static hash_key key_from_chunk_ref(
+ const BArrayInfo *info, const BChunkRef *cref,
+ /* avoid reallicating each time */
+ hash_key *hash_store, const size_t hash_store_len)
+{
+ /* in C, will fill in a reusable array */
+ BChunk *chunk = cref->link;
+ BLI_assert(info->accum_read_ahead_bytes * info->chunk_stride);
+
+ if (info->accum_read_ahead_bytes <= chunk->data_len) {
+ hash_key key;
+
+#ifdef USE_HASH_TABLE_KEY_CACHE
+ key = chunk->key;
+ if (key != HASH_TABLE_KEY_UNSET) {
+ /* Using key cache!
+ * avoids calculating every time */
+ }
+ else {
+ hash_array_from_cref(info, cref, info->accum_read_ahead_bytes, hash_store);
+ hash_accum_single(hash_store, hash_store_len, info->accum_steps);
+ key = hash_store[0];
+
+ /* cache the key */
+ if (key == HASH_TABLE_KEY_UNSET) {
+ key = HASH_TABLE_KEY_FALLBACK;
+ }
+ chunk->key = key;
+ }
+#else
+ hash_array_from_cref(info, cref, info->accum_read_ahead_bytes, hash_store);
+ hash_accum_single(hash_store, hash_store_len, info->accum_steps);
+ key = hash_store[0];
+#endif
+ return key;
+ }
+ else {
+ /* corner case - we're too small, calculate the key each time. */
+
+ hash_array_from_cref(info, cref, info->accum_read_ahead_bytes, hash_store);
+ hash_accum_single(hash_store, hash_store_len, info->accum_steps);
+ hash_key key = hash_store[0];
+
+#ifdef USE_HASH_TABLE_KEY_CACHE
+ if (UNLIKELY(key == HASH_TABLE_KEY_UNSET)) {
+ key = HASH_TABLE_KEY_FALLBACK;
+ }
+#endif
+ return key;
+ }
+}
+
+static const BChunkRef *table_lookup(
+ const BArrayInfo *info, BTableRef **table, const size_t table_len, const size_t i_table_start,
+ const ubyte *data, const size_t data_len, const size_t offset, const hash_key *table_hash_array)
+{
+ size_t size_left = data_len - offset;
+ hash_key key = table_hash_array[((offset - i_table_start) / info->chunk_stride)];
+ size_t key_index = (size_t)(key % (hash_key)table_len);
+ for (BTableRef *tref = table[key_index]; tref; tref = tref->next) {
+ const BChunkRef *cref = tref->cref;
+#ifdef USE_HASH_TABLE_KEY_CACHE
+ if (cref->link->key == key)
+#endif
+ {
+ BChunk *chunk_test = cref->link;
+ if (chunk_test->data_len <= size_left) {
+ if (bchunk_data_compare(chunk_test, data, data_len, offset)) {
+ /* we could remove the chunk from the table, to avoid multiple hits */
+ return cref;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+#else /* USE_HASH_TABLE_ACCUMULATE */
+
+/* NON USE_HASH_TABLE_ACCUMULATE code (simply hash each chunk) */
+
+static hash_key key_from_chunk_ref(const BArrayInfo *info, const BChunkRef *cref)
+{
+ const size_t data_hash_len = BCHUNK_HASH_LEN * info->chunk_stride;
+ hash_key key;
+ BChunk *chunk = cref->link;
+
+#ifdef USE_HASH_TABLE_KEY_CACHE
+ key = chunk->key;
+ if (key != HASH_TABLE_KEY_UNSET) {
+ /* Using key cache!
+ * avoids calculating every time */
+ }
+ else {
+ /* cache the key */
+ key = hash_data(chunk->data, data_hash_len);
+ if (key == HASH_TABLE_KEY_UNSET) {
+ key = HASH_TABLE_KEY_FALLBACK;
+ }
+ chunk->key = key;
+ }
+#else
+ key = hash_data(chunk->data, data_hash_len);
+#endif
+
+ return key;
+}
+
+static const BChunkRef *table_lookup(
+ const BArrayInfo *info, BTableRef **table, const size_t table_len, const uint UNUSED(i_table_start),
+ const ubyte *data, const size_t data_len, const size_t offset, const hash_key *UNUSED(table_hash_array))
+{
+ const size_t data_hash_len = BCHUNK_HASH_LEN * info->chunk_stride; /* TODO, cache */
+
+ size_t size_left = data_len - offset;
+ hash_key key = hash_data(&data[offset], MIN2(data_hash_len, size_left));
+ size_t key_index = (size_t)(key % (hash_key)table_len);
+ for (BTableRef *tref = table[key_index]; tref; tref = tref->next) {
+ const BChunkRef *cref = tref->cref;
+#ifdef USE_HASH_TABLE_KEY_CACHE
+ if (cref->link->key == key)
+#endif
+ {
+ BChunk *chunk_test = cref->link;
+ if (chunk_test->data_len <= size_left) {
+ if (bchunk_data_compare(chunk_test, data, data_len, offset)) {
+ /* we could remove the chunk from the table, to avoid multiple hits */
+ return cref;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+#endif /* USE_HASH_TABLE_ACCUMULATE */
+
+/* End Table Lookup
+ * ---------------- */
+
+/** \} */
+
+/**
+ * \param data: Data to store in the returned value.
+ * \param data_len_original: Length of data in bytes.
+ * \param chunk_list_reference: Reuse this list or chunks within it, don't modify its content.
+ * \note Caller is responsible for adding the user.
+ */
+static BChunkList *bchunk_list_from_data_merge(
+ const BArrayInfo *info, BArrayMemory *bs_mem,
+ const ubyte *data, const size_t data_len_original,
+ const BChunkList *chunk_list_reference)
+{
+ ASSERT_CHUNKLIST_SIZE(chunk_list_reference, chunk_list_reference->total_size);
+
+ /* -----------------------------------------------------------------------
+ * Fast-Path for exact match
+ * Check for exact match, if so, return the current list.
+ */
+
+ const BChunkRef *cref_match_first = NULL;
+
+ uint chunk_list_reference_skip_len = 0;
+ size_t chunk_list_reference_skip_bytes = 0;
+ size_t i_prev = 0;
+
+#ifdef USE_FASTPATH_CHUNKS_FIRST
+ bool full_match = false;
+
+ {
+ full_match = true;
+
+ const BChunkRef *cref = chunk_list_reference->chunk_refs.first;
+ while (i_prev < data_len_original) {
+ if (cref != NULL && bchunk_data_compare(cref->link, data, data_len_original, i_prev)) {
+ cref_match_first = cref;
+ chunk_list_reference_skip_len += 1;
+ chunk_list_reference_skip_bytes += cref->link->data_len;
+ i_prev += cref->link->data_len;
+ cref = cref->next;
+ }
+ else {
+ full_match = false;
+ break;
+ }
+ }
+
+ if (full_match) {
+ if (chunk_list_reference->total_size == data_len_original) {
+ return (BChunkList *)chunk_list_reference;
+ }
+ }
+ }
+
+ /* End Fast-Path (first)
+ * --------------------- */
+
+#endif /* USE_FASTPATH_CHUNKS_FIRST */
+
+ /* Copy until we have a mismatch */
+ BChunkList *chunk_list = bchunk_list_new(bs_mem, data_len_original);
+ if (cref_match_first != NULL) {
+ size_t chunk_size_step = 0;
+ const BChunkRef *cref = chunk_list_reference->chunk_refs.first;
+ while (true) {
+ BChunk *chunk = cref->link;
+ chunk_size_step += chunk->data_len;
+ bchunk_list_append_only(bs_mem, chunk_list, chunk);
+ ASSERT_CHUNKLIST_SIZE(chunk_list, chunk_size_step);
+ ASSERT_CHUNKLIST_DATA(chunk_list, data);
+ if (cref == cref_match_first) {
+ break;
+ }
+ else {
+ cref = cref->next;
+ }
+ }
+ /* happens when bytes are removed from the end of the array */
+ if (chunk_size_step == data_len_original) {
+ return chunk_list;
+ }
+
+ i_prev = chunk_size_step;
+ }
+ else {
+ i_prev = 0;
+ }
+
+ /* ------------------------------------------------------------------------
+ * Fast-Path for end chunks
+ *
+ * Check for trailing chunks
+ */
+
+ /* In this case use 'chunk_list_reference_last' to define the last index
+ * index_match_last = -1 */
+
+ /* warning, from now on don't use len(data)
+ * since we want to ignore chunks already matched */
+ size_t data_len = data_len_original;
+#define data_len_original invalid_usage
+#ifdef data_len_original /* quiet warning */
+#endif
+
+ const BChunkRef *chunk_list_reference_last = NULL;
+
+#ifdef USE_FASTPATH_CHUNKS_LAST
+ if (!BLI_listbase_is_empty(&chunk_list_reference->chunk_refs)) {
+ const BChunkRef *cref = chunk_list_reference->chunk_refs.last;
+ while ((cref->prev != NULL) &&
+ (cref != cref_match_first) &&
+ (cref->link->data_len <= data_len - i_prev))
+ {
+ BChunk *chunk_test = cref->link;
+ size_t offset = data_len - chunk_test->data_len;
+ if (bchunk_data_compare(chunk_test, data, data_len, offset)) {
+ data_len = offset;
+ chunk_list_reference_last = cref;
+ chunk_list_reference_skip_len += 1;
+ chunk_list_reference_skip_bytes += cref->link->data_len;
+ cref = cref->prev;
+ }
+ else {
+ break;
+ }
+ }
+ }
+
+ /* End Fast-Path (last)
+ * -------------------- */
+#endif /* USE_FASTPATH_CHUNKS_LAST */
+
+ /* -----------------------------------------------------------------------
+ * Check for aligned chunks
+ *
+ * This saves a lot of searching, so use simple heuristics to detect aligned arrays.
+ * (may need to tweak exact method).
+ */
+
+ bool use_aligned = false;
+
+#ifdef USE_ALIGN_CHUNKS_TEST
+ if (chunk_list->total_size == chunk_list_reference->total_size) {
+ /* if we're already a quarter aligned */
+ if (data_len - i_prev <= chunk_list->total_size / 4) {
+ use_aligned = true;
+ }
+ else {
+ /* TODO, walk over chunks and check if some arbitrary amount align */
+ }
+ }
+#endif /* USE_ALIGN_CHUNKS_TEST */
+
+ /* End Aligned Chunk Case
+ * ----------------------- */
+
+ if (use_aligned) {
+ /* Copy matching chunks, creates using the same 'layout' as the reference */
+ const BChunkRef *cref = cref_match_first ? cref_match_first->next : chunk_list_reference->chunk_refs.first;
+ while (i_prev != data_len) {
+ const size_t i = i_prev + cref->link->data_len;
+ BLI_assert(i != i_prev);
+
+ if ((cref != chunk_list_reference_last) &&
+ bchunk_data_compare(cref->link, data, data_len, i_prev))
+ {
+ bchunk_list_append(info, bs_mem, chunk_list, cref->link);
+ ASSERT_CHUNKLIST_SIZE(chunk_list, i);
+ ASSERT_CHUNKLIST_DATA(chunk_list, data);
+ }
+ else {
+ bchunk_list_append_data(info, bs_mem, chunk_list, &data[i_prev], i - i_prev);
+ ASSERT_CHUNKLIST_SIZE(chunk_list, i);
+ ASSERT_CHUNKLIST_DATA(chunk_list, data);
+ }
+
+ cref = cref->next;
+
+ i_prev = i;
+ }
+ }
+ else if ((data_len - i_prev >= info->chunk_byte_size) &&
+ (chunk_list_reference->chunk_refs_len >= chunk_list_reference_skip_len) &&
+ (chunk_list_reference->chunk_refs.first != NULL))
+ {
+
+ /* --------------------------------------------------------------------
+ * Non-Aligned Chunk De-Duplication */
+
+ /* only create a table if we have at least one chunk to search
+ * otherwise just make a new one.
+ *
+ * Support re-arranged chunks */
+
+#ifdef USE_HASH_TABLE_ACCUMULATE
+ size_t i_table_start = i_prev;
+ const size_t table_hash_array_len = (data_len - i_prev) / info->chunk_stride;
+ hash_key *table_hash_array = MEM_mallocN(sizeof(*table_hash_array) * table_hash_array_len, __func__);
+ hash_array_from_data(info, &data[i_prev], data_len - i_prev, table_hash_array);
+
+ hash_accum(table_hash_array, table_hash_array_len, info->accum_steps);
+#else
+ /* dummy vars */
+ uint i_table_start = 0;
+ hash_key *table_hash_array = NULL;
+#endif
+
+ const uint chunk_list_reference_remaining_len =
+ (chunk_list_reference->chunk_refs_len - chunk_list_reference_skip_len) + 1;
+ BTableRef *table_ref_stack = MEM_mallocN(chunk_list_reference_remaining_len * sizeof(BTableRef), __func__);
+ uint table_ref_stack_n = 0;
+
+ const size_t table_len = chunk_list_reference_remaining_len * BCHUNK_HASH_TABLE_MUL;
+ BTableRef **table = MEM_callocN(table_len * sizeof(*table), __func__);
+
+ /* table_make - inline
+ * include one matching chunk, to allow for repeating values */
+ {
+#ifdef USE_HASH_TABLE_ACCUMULATE
+ const size_t hash_store_len = info->accum_read_ahead_len;
+ hash_key *hash_store = MEM_mallocN(sizeof(hash_key) * hash_store_len, __func__);
+#endif
+
+ const BChunkRef *cref;
+ size_t chunk_list_reference_bytes_remaining =
+ chunk_list_reference->total_size - chunk_list_reference_skip_bytes;
+
+ if (cref_match_first) {
+ cref = cref_match_first;
+ chunk_list_reference_bytes_remaining += cref->link->data_len;
+ }
+ else {
+ cref = chunk_list_reference->chunk_refs.first;
+ }
+
+#ifdef USE_PARANOID_CHECKS
+ {
+ size_t test_bytes_len = 0;
+ const BChunkRef *cr = cref;
+ while (cr != chunk_list_reference_last) {
+ test_bytes_len += cr->link->data_len;
+ cr = cr->next;
+ }
+ BLI_assert(test_bytes_len == chunk_list_reference_bytes_remaining);
+ }
+#endif
+
+ while ((cref != chunk_list_reference_last) &&
+ (chunk_list_reference_bytes_remaining >= info->accum_read_ahead_bytes))
+ {
+ hash_key key = key_from_chunk_ref(info, cref
+
+#ifdef USE_HASH_TABLE_ACCUMULATE
+ , hash_store, hash_store_len
+#endif
+ );
+ size_t key_index = (size_t)(key % (hash_key)table_len);
+ BTableRef *tref_prev = table[key_index];
+ BLI_assert(table_ref_stack_n < chunk_list_reference_remaining_len);
+ BTableRef *tref = &table_ref_stack[table_ref_stack_n++];
+ tref->cref = cref;
+ tref->next = tref_prev;
+ table[key_index] = tref;
+
+ chunk_list_reference_bytes_remaining -= cref->link->data_len;
+ cref = cref->next;
+ }
+
+ BLI_assert(table_ref_stack_n <= chunk_list_reference_remaining_len);
+
+#ifdef USE_HASH_TABLE_ACCUMULATE
+ MEM_freeN(hash_store);
+#endif
+ }
+ /* done making the table */
+
+ BLI_assert(i_prev <= data_len);
+ for (size_t i = i_prev; i < data_len; ) {
+ /* Assumes exiting chunk isnt a match! */
+
+ const BChunkRef *cref_found = table_lookup(
+ info,
+ table, table_len, i_table_start,
+ data, data_len, i, table_hash_array);
+ if (cref_found != NULL) {
+ BLI_assert(i < data_len);
+ if (i != i_prev) {
+ bchunk_list_append_data_n(info, bs_mem, chunk_list, &data[i_prev], i - i_prev);
+ i_prev = i;
+ }
+
+ /* now add the reference chunk */
+ {
+ BChunk *chunk_found = cref_found->link;
+ i += chunk_found->data_len;
+ bchunk_list_append(info, bs_mem, chunk_list, chunk_found);
+ }
+ i_prev = i;
+ BLI_assert(i_prev <= data_len);
+ ASSERT_CHUNKLIST_SIZE(chunk_list, i_prev);
+ ASSERT_CHUNKLIST_DATA(chunk_list, data);
+
+ /* its likely that the next chunk in the list will be a match, so check it! */
+ while ((cref_found->next != NULL) &&
+ (cref_found->next != chunk_list_reference_last))
+ {
+ cref_found = cref_found->next;
+ BChunk *chunk_found = cref_found->link;
+
+ if (bchunk_data_compare(chunk_found, data, data_len, i_prev)) {
+ /* may be useful to remove table data, assuming we dont have repeating memory
+ * where it would be useful to re-use chunks. */
+ i += chunk_found->data_len;
+ bchunk_list_append(info, bs_mem, chunk_list, chunk_found);
+ /* chunk_found may be freed! */
+ i_prev = i;
+ BLI_assert(i_prev <= data_len);
+ ASSERT_CHUNKLIST_SIZE(chunk_list, i_prev);
+ ASSERT_CHUNKLIST_DATA(chunk_list, data);
+ }
+ else {
+ break;
+ }
+ }
+ }
+ else {
+ i = i + info->chunk_stride;
+ }
+ }
+
+#ifdef USE_HASH_TABLE_ACCUMULATE
+ MEM_freeN(table_hash_array);
+#endif
+ MEM_freeN(table);
+ MEM_freeN(table_ref_stack);
+
+ /* End Table Lookup
+ * ---------------- */
+ }
+
+ ASSERT_CHUNKLIST_SIZE(chunk_list, i_prev);
+ ASSERT_CHUNKLIST_DATA(chunk_list, data);
+
+ /* -----------------------------------------------------------------------
+ * No Duplicates to copy, write new chunks
+ *
+ * Trailing chunks, no matches found in table lookup above.
+ * Write all new data. */
+ if (i_prev != data_len) {
+ bchunk_list_append_data_n(info, bs_mem, chunk_list, &data[i_prev], data_len - i_prev);
+ i_prev = data_len;
+ }
+
+ BLI_assert(i_prev == data_len);
+
+#ifdef USE_FASTPATH_CHUNKS_LAST
+ if (chunk_list_reference_last != NULL) {
+ /* write chunk_list_reference_last since it hasn't been written yet */
+ const BChunkRef *cref = chunk_list_reference_last;
+ while (cref != NULL) {
+ BChunk *chunk = cref->link;
+ // BLI_assert(bchunk_data_compare(chunk, data, data_len, i_prev));
+ i_prev += chunk->data_len;
+ /* use simple since we assume the references chunks have already been sized correctly. */
+ bchunk_list_append_only(bs_mem, chunk_list, chunk);
+ ASSERT_CHUNKLIST_DATA(chunk_list, data);
+ cref = cref->next;
+ }
+ }
+#endif
+
+#undef data_len_original
+
+ BLI_assert(i_prev == data_len_original);
+
+ /* check we're the correct size and that we didn't accidentally modify the reference */
+ ASSERT_CHUNKLIST_SIZE(chunk_list, data_len_original);
+ ASSERT_CHUNKLIST_SIZE(chunk_list_reference, chunk_list_reference->total_size);
+
+ ASSERT_CHUNKLIST_DATA(chunk_list, data);
+
+ return chunk_list;
+}
+/* end private API */
+
+/** \} */
+
+
+/** \name Main Array Storage API
+ * \{ */
+
+
+/**
+ * Create a new array store, which can store any number of arrays
+ * as long as their stride matches.
+ *
+ * \param stride: ``sizeof()`` each element,
+ *
+ * \note while a stride of ``1`` will always work,
+ * its less efficient since duplicate chunks of memory will be searched
+ * at positions unaligned with the array data.
+ *
+ * \param chunk_count: Number of elements to split each chunk into.
+ * - A small value increases the ability to de-duplicate chunks,
+ * but adds overhead by increasing the number of chunks to look-up when searching for duplicates,
+ * as well as some overhead constructing the original array again, with more calls to ``memcpy``.
+ * - Larger values reduce the *book keeping* overhead,
+ * but increase the chance a small, isolated change will cause a larger amount of data to be duplicated.
+ *
+ * \return A new array store, to be freed with #BLI_array_store_destroy.
+ */
+BArrayStore *BLI_array_store_create(
+ uint stride,
+ uint chunk_count)
+{
+ BArrayStore *bs = MEM_callocN(sizeof(BArrayStore), __func__);
+
+ bs->info.chunk_stride = stride;
+ bs->info.chunk_count = chunk_count;
+
+ bs->info.chunk_byte_size = chunk_count * stride;
+#ifdef USE_MERGE_CHUNKS
+ bs->info.chunk_byte_size_min = MAX2(1u, chunk_count / BCHUNK_SIZE_MIN_DIV) * stride;
+ bs->info.chunk_byte_size_max = (chunk_count * BCHUNK_SIZE_MAX_MUL) * stride;
+#endif
+
+#ifdef USE_HASH_TABLE_ACCUMULATE
+ bs->info.accum_steps = BCHUNK_HASH_TABLE_ACCUMULATE_STEPS - 1;
+ /* Triangle number, identifying now much read-ahead we need:
+ * https://en.wikipedia.org/wiki/Triangular_number (+ 1) */
+ bs->info.accum_read_ahead_len = (uint)((((bs->info.accum_steps * (bs->info.accum_steps + 1))) / 2) + 1);
+ bs->info.accum_read_ahead_bytes = bs->info.accum_read_ahead_len * stride;
+#else
+ bs->info.accum_read_ahead_bytes = BCHUNK_HASH_LEN * stride;
+#endif
+
+ bs->memory.chunk_list = BLI_mempool_create(sizeof(BChunkList), 0, 512, BLI_MEMPOOL_NOP);
+ bs->memory.chunk_ref = BLI_mempool_create(sizeof(BChunkRef), 0, 512, BLI_MEMPOOL_NOP);
+ /* allow iteration to simplify freeing, otherwise its not needed
+ * (we could loop over all states as an alternative). */
+ bs->memory.chunk = BLI_mempool_create(sizeof(BChunk), 0, 512, BLI_MEMPOOL_ALLOW_ITER);
+
+ return bs;
+}
+
+static void array_store_free_data(BArrayStore *bs)
+{
+ /* free chunk data */
+ {
+ BLI_mempool_iter iter;
+ BChunk *chunk;
+ BLI_mempool_iternew(bs->memory.chunk, &iter);
+ while ((chunk = BLI_mempool_iterstep(&iter))) {
+ BLI_assert(chunk->users > 0);
+ MEM_freeN((void *)chunk->data);
+ }
+ }
+
+ /* free states */
+ for (BArrayState *state = bs->states.first, *state_next; state; state = state_next) {
+ state_next = state->next;
+ MEM_freeN(state);
+ }
+}
+
+/**
+ * Free the #BArrayStore, including all states and chunks.
+ */
+void BLI_array_store_destroy(
+ BArrayStore *bs)
+{
+ array_store_free_data(bs);
+
+ BLI_mempool_destroy(bs->memory.chunk_list);
+ BLI_mempool_destroy(bs->memory.chunk_ref);
+ BLI_mempool_destroy(bs->memory.chunk);
+
+ MEM_freeN(bs);
+}
+
+/**
+ * Clear all contents, allowing reuse of \a bs.
+ */
+void BLI_array_store_clear(
+ BArrayStore *bs)
+{
+ array_store_free_data(bs);
+
+ BLI_listbase_clear(&bs->states);
+
+ BLI_mempool_clear(bs->memory.chunk_list);
+ BLI_mempool_clear(bs->memory.chunk_ref);
+ BLI_mempool_clear(bs->memory.chunk);
+}
+
+/** \name BArrayStore Statistics
+ * \{ */
+
+/**
+ * \return the total amount of memory that would be used by getting the arrays for all states.
+ */
+size_t BLI_array_store_calc_size_expanded_get(
+ const BArrayStore *bs)
+{
+ size_t size_accum = 0;
+ for (const BArrayState *state = bs->states.first; state; state = state->next) {
+ size_accum += state->chunk_list->total_size;
+ }
+ return size_accum;
+}
+
+/**
+ * \return the amount of memory used by all #BChunk.data
+ * (duplicate chunks are only counted once).
+ */
+size_t BLI_array_store_calc_size_compacted_get(
+ const BArrayStore *bs)
+{
+ size_t size_total = 0;
+ BLI_mempool_iter iter;
+ BChunk *chunk;
+ BLI_mempool_iternew(bs->memory.chunk, &iter);
+ while ((chunk = BLI_mempool_iterstep(&iter))) {
+ BLI_assert(chunk->users > 0);
+ size_total += (size_t)chunk->data_len;
+ }
+ return size_total;
+}
+
+/** \} */
+
+
+/** \name BArrayState Access
+ * \{ */
+
+/**
+ *
+ * \param data: Data used to create
+ * \param state_reference: The state to use as a reference when adding the new state,
+ * typically this is the previous state,
+ * however it can be any previously created state from this \a bs.
+ *
+ * \return The new state, which is used by the caller as a handle to get back the contents of \a data.
+ * This may be removed using #BLI_array_store_state_remove,
+ * otherwise it will be removed with #BLI_array_store_destroy.
+ */
+BArrayState *BLI_array_store_state_add(
+ BArrayStore *bs,
+ const void *data, const size_t data_len,
+ const BArrayState *state_reference)
+{
+ /* ensure we're aligned to the stride */
+ BLI_assert((data_len % bs->info.chunk_stride) == 0);
+
+#ifdef USE_PARANOID_CHECKS
+ if (state_reference) {
+ BLI_assert(BLI_findindex(&bs->states, state_reference) != -1);
+ }
+#endif
+
+ BChunkList *chunk_list;
+ if (state_reference) {
+ chunk_list = bchunk_list_from_data_merge(
+ &bs->info, &bs->memory,
+ (const ubyte *)data, data_len,
+ /* re-use reference chunks */
+ state_reference->chunk_list);
+ }
+ else {
+ chunk_list = bchunk_list_new(&bs->memory, data_len);
+ bchunk_list_fill_from_array(
+ &bs->info, &bs->memory,
+ chunk_list,
+ (const ubyte *)data, data_len);
+ }
+
+ chunk_list->users += 1;
+
+ BArrayState *state = MEM_callocN(sizeof(BArrayState), __func__);
+ state->chunk_list = chunk_list;
+
+ BLI_addtail(&bs->states, state);
+
+#ifdef USE_PARANOID_CHECKS
+ {
+ size_t data_test_len;
+ void *data_test = BLI_array_store_state_data_get_alloc(state, &data_test_len);
+ BLI_assert(data_test_len == data_len);
+ BLI_assert(memcmp(data_test, data, data_len) == 0);
+ MEM_freeN(data_test);
+ }
+#endif
+
+ return state;
+}
+
+/**
+ * Remove a state and free any unused #BChunk data.
+ *
+ * The states can be freed in any order.
+ */
+void BLI_array_store_state_remove(
+ BArrayStore *bs,
+ BArrayState *state)
+{
+#ifdef USE_PARANOID_CHECKS
+ BLI_assert(BLI_findindex(&bs->states, state) != -1);
+#endif
+
+ bchunk_list_decref(&bs->memory, state->chunk_list);
+ BLI_remlink(&bs->states, state);
+
+ MEM_freeN(state);
+}
+
+/**
+ * \return the expanded size of the array,
+ * use this to know how much memory to allocate #BLI_array_store_state_data_get's argument.
+ */
+size_t BLI_array_store_state_size_get(
+ BArrayState *state)
+{
+ return state->chunk_list->total_size;
+}
+
+/**
+ * Fill in existing allocated memory with the contents of \a state.
+ */
+void BLI_array_store_state_data_get(
+ BArrayState *state,
+ void *data)
+{
+#ifdef USE_PARANOID_CHECKS
+ size_t data_test_len = 0;
+ for (BChunkRef *cref = state->chunk_list->chunk_refs.first; cref; cref = cref->next) {
+ data_test_len += cref->link->data_len;
+ }
+ BLI_assert(data_test_len == state->chunk_list->total_size);
+#endif
+
+ ubyte *data_step = (ubyte *)data;
+ for (BChunkRef *cref = state->chunk_list->chunk_refs.first; cref; cref = cref->next) {
+ BLI_assert(cref->link->users > 0);
+ memcpy(data_step, cref->link->data, cref->link->data_len);
+ data_step += cref->link->data_len;
+ }
+}
+
+/**
+ * Allocate an array for \a state and return it.
+ */
+void *BLI_array_store_state_data_get_alloc(
+ BArrayState *state,
+ size_t *r_data_len)
+{
+ void *data = MEM_mallocN(state->chunk_list->total_size, __func__);
+ BLI_array_store_state_data_get(state, data);
+ *r_data_len = state->chunk_list->total_size;
+ return data;
+}
+
+/** \} */
+
+
+/** \name Debugging API (for testing).
+ * \{ */
+
+/* only for test validation */
+static size_t bchunk_list_size(const BChunkList *chunk_list)
+{
+ size_t total_size = 0;
+ for (BChunkRef *cref = chunk_list->chunk_refs.first; cref; cref = cref->next) {
+ total_size += cref->link->data_len;
+ }
+ return total_size;
+}
+
+bool BLI_array_store_is_valid(
+ BArrayStore *bs)
+{
+ bool ok = true;
+
+ /* Check Length
+ * ------------ */
+
+ for (BArrayState *state = bs->states.first; state; state = state->next) {
+ BChunkList *chunk_list = state->chunk_list;
+ if (!(bchunk_list_size(chunk_list) == chunk_list->total_size)) {
+ return false;
+ }
+
+ if (BLI_listbase_count(&chunk_list->chunk_refs) != (int)chunk_list->chunk_refs_len) {
+ return false;
+ }
+
+#ifdef USE_MERGE_CHUNKS
+ /* ensure we merge all chunks that could be merged */
+ if (chunk_list->total_size > bs->info.chunk_byte_size_min) {
+ for (BChunkRef *cref = chunk_list->chunk_refs.first; cref; cref = cref->next) {
+ if (cref->link->data_len < bs->info.chunk_byte_size_min) {
+ return false;
+ }
+ }
+ }
+#endif
+ }
+
+ {
+ BLI_mempool_iter iter;
+ BChunk *chunk;
+ BLI_mempool_iternew(bs->memory.chunk, &iter);
+ while ((chunk = BLI_mempool_iterstep(&iter))) {
+ if (!(MEM_allocN_len(chunk->data) >= chunk->data_len)) {
+ return false;
+ }
+ }
+ }
+
+ /* Check User Count & Lost References
+ * ---------------------------------- */
+ {
+ GHashIterator gh_iter;
+
+#define GHASH_PTR_ADD_USER(gh, pt) \
+ { \
+ void **val; \
+ if (BLI_ghash_ensure_p((gh), (pt), &val)) { \
+ *((int *)val) += 1; \
+ } \
+ else { \
+ *((int *)val) = 1; \
+ } \
+ } ((void)0)
+
+ /* count chunk_list's */
+ GHash *chunk_list_map = BLI_ghash_ptr_new(__func__);
+ GHash *chunk_map = BLI_ghash_ptr_new(__func__);
+
+ int totrefs = 0;
+ for (BArrayState *state = bs->states.first; state; state = state->next) {
+ GHASH_PTR_ADD_USER(chunk_list_map, state->chunk_list);
+ }
+ GHASH_ITER (gh_iter, chunk_list_map) {
+ const struct BChunkList *chunk_list = BLI_ghashIterator_getKey(&gh_iter);
+ const int users = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(&gh_iter));
+ if (!(chunk_list->users == users)) {
+ ok = false;
+ goto user_finally;
+ }
+ }
+ if (!(BLI_mempool_count(bs->memory.chunk_list) == (int)BLI_ghash_size(chunk_list_map))) {
+ ok = false;
+ goto user_finally;
+ }
+
+ /* count chunk's */
+ GHASH_ITER (gh_iter, chunk_list_map) {
+ const struct BChunkList *chunk_list = BLI_ghashIterator_getKey(&gh_iter);
+ for (const BChunkRef *cref = chunk_list->chunk_refs.first; cref; cref = cref->next) {
+ GHASH_PTR_ADD_USER(chunk_map, cref->link);
+ totrefs += 1;
+ }
+ }
+ if (!(BLI_mempool_count(bs->memory.chunk) == (int)BLI_ghash_size(chunk_map))) {
+ ok = false;
+ goto user_finally;
+ }
+ if (!(BLI_mempool_count(bs->memory.chunk_ref) == totrefs)) {
+ ok = false;
+ goto user_finally;
+ }
+
+ GHASH_ITER (gh_iter, chunk_map) {
+ const struct BChunk *chunk = BLI_ghashIterator_getKey(&gh_iter);
+ const int users = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(&gh_iter));
+ if (!(chunk->users == users)) {
+ ok = false;
+ goto user_finally;
+ }
+ }
+
+#undef GHASH_PTR_ADD_USER
+
+user_finally:
+ BLI_ghash_free(chunk_list_map, NULL, NULL);
+ BLI_ghash_free(chunk_map, NULL, NULL);
+ }
+
+
+ return ok;
+ /* TODO, dangling pointer checks */
+}
+
+/** \} */
diff --git a/source/blender/blenlib/intern/array_store_utils.c b/source/blender/blenlib/intern/array_store_utils.c
new file mode 100644
index 00000000000..83cd28ddf11
--- /dev/null
+++ b/source/blender/blenlib/intern/array_store_utils.c
@@ -0,0 +1,103 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenlib/intern/array_store_utils.c
+ * \ingroup bli
+ * \brief Helper functions for BLI_array_store API.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
+#include "BLI_array_store.h"
+#include "BLI_array_store_utils.h" /* own include */
+
+#include "BLI_math_base.h"
+
+BArrayStore *BLI_array_store_at_size_ensure(
+ struct BArrayStore_AtSize *bs_stride,
+ const int stride, const int chunk_size)
+{
+ if (bs_stride->stride_table_len < stride) {
+ bs_stride->stride_table_len = stride;
+ bs_stride->stride_table = MEM_recallocN(bs_stride->stride_table, sizeof(*bs_stride->stride_table) * stride);
+ }
+ BArrayStore **bs_p = &bs_stride->stride_table[stride - 1];
+
+ if ((*bs_p) == NULL) {
+#if 0
+ unsigned int chunk_count = chunk_size;
+#else
+ /* calculate best chunk-count to fit a power of two */
+ unsigned int chunk_count = chunk_size;
+ {
+ unsigned int size = chunk_count * stride;
+ size = power_of_2_max_u(size);
+ size = MEM_SIZE_OPTIMAL(size);
+ chunk_count = size / stride;
+ }
+#endif
+
+ (*bs_p) = BLI_array_store_create(stride, chunk_count);
+ }
+ return *bs_p;
+}
+
+BArrayStore *BLI_array_store_at_size_get(
+ struct BArrayStore_AtSize *bs_stride,
+ const int stride)
+{
+ BLI_assert(stride > 0 && stride <= bs_stride->stride_table_len);
+ return bs_stride->stride_table[stride - 1];
+}
+
+void BLI_array_store_at_size_clear(
+ struct BArrayStore_AtSize *bs_stride)
+{
+ for (int i = 0; i < bs_stride->stride_table_len; i += 1) {
+ if (bs_stride->stride_table[i]) {
+ BLI_array_store_destroy(bs_stride->stride_table[i]);
+ }
+ }
+
+ MEM_freeN(bs_stride->stride_table);
+ bs_stride->stride_table = NULL;
+ bs_stride->stride_table_len = 0;
+}
+
+
+void BLI_array_store_at_size_calc_memory_usage(
+ struct BArrayStore_AtSize *bs_stride,
+ size_t *r_size_expanded, size_t *r_size_compacted)
+{
+ size_t size_compacted = 0;
+ size_t size_expanded = 0;
+ for (int i = 0; i < bs_stride->stride_table_len; i++) {
+ BArrayStore *bs = bs_stride->stride_table[i];
+ if (bs) {
+ size_compacted += BLI_array_store_calc_size_compacted_get(bs);
+ size_expanded += BLI_array_store_calc_size_expanded_get(bs);
+ }
+ }
+
+ *r_size_expanded = size_expanded;
+ *r_size_compacted = size_compacted;
+}
diff --git a/source/blender/blenlib/intern/array_utils.c b/source/blender/blenlib/intern/array_utils.c
index 5d485e2033d..32f0111babd 100644
--- a/source/blender/blenlib/intern/array_utils.c
+++ b/source/blender/blenlib/intern/array_utils.c
@@ -134,8 +134,22 @@ void _bli_array_permute(
int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p)
{
const char *arr_step = (const char *)arr;
- unsigned int i;
- for (i = 0; i < arr_len; i++, arr_step += arr_stride) {
+ for (unsigned int i = 0; i < arr_len; i++, arr_step += arr_stride) {
+ if (memcmp(arr_step, p, arr_stride) == 0) {
+ return (int)i;
+ }
+ }
+ return -1;
+}
+
+/**
+ * A version of #BLI_array_findindex that searches from the end of the list.
+ */
+int _bli_array_rfindindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p)
+{
+ const char *arr_step = (const char *)arr + (arr_stride * arr_len);
+ for (unsigned int i = arr_len; i-- != 0; ) {
+ arr_step -= arr_stride;
if (memcmp(arr_step, p, arr_stride) == 0) {
return (int)i;
}
@@ -183,7 +197,7 @@ void _bli_array_binary_or(
* \param user_data: User data for \a test_fn.
* \param span_step: Indices to iterate over,
* initialize both values to the array length to initialize iteration.
- * \param: r_span_len: The length of the span, useful when \a use_wrap is enabled,
+ * \param r_span_len: The length of the span, useful when \a use_wrap is enabled,
* where calculating the length isnt a simple subtraction.
*/
bool _bli_array_iter_span(
diff --git a/source/blender/blenlib/intern/astar.c b/source/blender/blenlib/intern/astar.c
index 21d974de1c4..0020dbe4612 100644
--- a/source/blender/blenlib/intern/astar.c
+++ b/source/blender/blenlib/intern/astar.c
@@ -35,7 +35,7 @@
* in addition to distance already walked. This heuristic allows more efficiency
* in finding optimal path.
*
- * Implementation based on Wikipedia A* page [http://en.wikipedia.org/wiki/A*_search_algorithm].
+ * Implementation based on Wikipedia A* page [https://en.wikipedia.org/wiki/A*_search_algorithm].
*
* Note that most memory handling here is done through two different MemArena's. Those should also be used to allocate
* custom data needed to a specific use of A*.
diff --git a/source/blender/blenlib/intern/bitmap_draw_2d.c b/source/blender/blenlib/intern/bitmap_draw_2d.c
new file mode 100644
index 00000000000..afc54511d13
--- /dev/null
+++ b/source/blender/blenlib/intern/bitmap_draw_2d.c
@@ -0,0 +1,331 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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: some of this file.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ * */
+
+/** \file blender/blenlib/intern/bitmap_draw_2d.c
+ * \ingroup bli
+ *
+ * Utility functions for primitive drawing operations.
+ */
+
+#include <limits.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_bitmap_draw_2d.h"
+
+#include "BLI_math_base.h"
+#include "BLI_sort.h"
+#include "BLI_utildefines.h"
+
+#include "BLI_strict_flags.h"
+
+/* -------------------------------------------------------------------- */
+/* Draw Line */
+
+/**
+ * Plot a line from \a p1 to \a p2 (inclusive).
+ */
+void BLI_bitmap_draw_2d_line_v2v2i(
+ const int p1[2], const int p2[2],
+ bool (*callback)(int, int, void *), void *userData)
+{
+ /* Bresenham's line algorithm. */
+ int x1 = p1[0];
+ int y1 = p1[1];
+ int x2 = p2[0];
+ int y2 = p2[1];
+
+ int ix;
+ int iy;
+
+ /* if x1 == x2 or y1 == y2, then it does not matter what we set here */
+ int delta_x = (x2 > x1 ? ((void)(ix = 1), x2 - x1) : ((void)(ix = -1), x1 - x2)) << 1;
+ int delta_y = (y2 > y1 ? ((void)(iy = 1), y2 - y1) : ((void)(iy = -1), y1 - y2)) << 1;
+
+ if (callback(x1, y1, userData) == 0) {
+ return;
+ }
+
+ if (delta_x >= delta_y) {
+ /* error may go below zero */
+ int error = delta_y - (delta_x >> 1);
+
+ while (x1 != x2) {
+ if (error >= 0) {
+ if (error || (ix > 0)) {
+ y1 += iy;
+ error -= delta_x;
+ }
+ /* else do nothing */
+ }
+ /* else do nothing */
+
+ x1 += ix;
+ error += delta_y;
+
+ if (callback(x1, y1, userData) == 0) {
+ return;
+ }
+ }
+ }
+ else {
+ /* error may go below zero */
+ int error = delta_x - (delta_y >> 1);
+
+ while (y1 != y2) {
+ if (error >= 0) {
+ if (error || (iy > 0)) {
+ x1 += ix;
+ error -= delta_y;
+ }
+ /* else do nothing */
+ }
+ /* else do nothing */
+
+ y1 += iy;
+ error += delta_x;
+
+ if (callback(x1, y1, userData) == 0) {
+ return;
+ }
+ }
+ }
+}
+
+
+/* -------------------------------------------------------------------- */
+/* Draw Filled Polygon */
+
+/* sort edge-segments on y, then x axis */
+static int draw_poly_v2i_n__span_y_sort(const void *a_p, const void *b_p, void *verts_p)
+{
+ const int (*verts)[2] = verts_p;
+ const int *a = a_p;
+ const int *b = b_p;
+ const int *co_a = verts[a[0]];
+ const int *co_b = verts[b[0]];
+
+ if (co_a[1] < co_b[1]) {
+ return -1;
+ }
+ else if (co_a[1] > co_b[1]) {
+ return 1;
+ }
+ else if (co_a[0] < co_b[0]) {
+ return -1;
+ }
+ else if (co_a[0] > co_b[0]) {
+ return 1;
+ }
+ else {
+ /* co_a & co_b are identical, use the line closest to the x-min */
+ const int *co = co_a;
+ co_a = verts[a[1]];
+ co_b = verts[b[1]];
+ int ord = (((co_b[0] - co[0]) * (co_a[1] - co[1])) -
+ ((co_a[0] - co[0]) * (co_b[1] - co[1])));
+ if (ord > 0) {
+ return -1;
+ }
+ if (ord < 0) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Draws a filled polyon with support for self intersections.
+ *
+ * \param callback: Takes the x, y coords and x-span (\a x_end is not inclusive),
+ * note that \a x_end will always be greater than \a x, so we can use:
+ *
+ * \code{.c}
+ * do {
+ * func(x, y);
+ * } while (++x != x_end);
+ * \endcode
+ */
+void BLI_bitmap_draw_2d_poly_v2i_n(
+ const int xmin, const int ymin, const int xmax, const int ymax,
+ const int verts[][2], const int nr,
+ void (*callback)(int x, int x_end, int y, void *), void *userData)
+{
+ /* Originally by Darel Rex Finley, 2007.
+ * Optimized by Campbell Barton, 2016 to track sorted intersections. */
+
+ int (*span_y)[2] = MEM_mallocN(sizeof(*span_y) * (size_t)nr, __func__);
+ int span_y_len = 0;
+
+ for (int i_curr = 0, i_prev = nr - 1; i_curr < nr; i_prev = i_curr++) {
+ const int *co_prev = verts[i_prev];
+ const int *co_curr = verts[i_curr];
+
+ if (co_prev[1] != co_curr[1]) {
+ /* Any segments entirely above or below the area of interest can be skipped. */
+ if ((min_ii(co_prev[1], co_curr[1]) >= ymax) ||
+ (max_ii(co_prev[1], co_curr[1]) < ymin))
+ {
+ continue;
+ }
+
+ int *s = span_y[span_y_len++];
+ if (co_prev[1] < co_curr[1]) {
+ s[0] = i_prev;
+ s[1] = i_curr;
+ }
+ else {
+ s[0] = i_curr;
+ s[1] = i_prev;
+ }
+ }
+ }
+
+ BLI_qsort_r(span_y, (size_t)span_y_len, sizeof(*span_y), draw_poly_v2i_n__span_y_sort, (void *)verts);
+
+ struct NodeX {
+ int span_y_index;
+ int x;
+ } *node_x = MEM_mallocN(sizeof(*node_x) * (size_t)(nr + 1), __func__);
+ int node_x_len = 0;
+
+ int span_y_index = 0;
+ if (span_y_len != 0 && verts[span_y[0][0]][1] < ymin) {
+ while ((span_y_index < span_y_len) &&
+ (verts[span_y[span_y_index][0]][1] < ymin))
+ {
+ BLI_assert(verts[span_y[span_y_index][0]][1] <
+ verts[span_y[span_y_index][1]][1]);
+ if (verts[span_y[span_y_index][1]][1] >= ymin) {
+ struct NodeX *n = &node_x[node_x_len++];
+ n->span_y_index = span_y_index;
+ }
+ span_y_index += 1;
+ }
+ }
+
+ /* Loop through the rows of the image. */
+ for (int pixel_y = ymin; pixel_y < ymax; pixel_y++) {
+ bool is_sorted = true;
+ bool do_remove = false;
+
+ for (int i = 0, x_ix_prev = INT_MIN; i < node_x_len; i++) {
+ struct NodeX *n = &node_x[i];
+ const int *s = span_y[n->span_y_index];
+ const int *co_prev = verts[s[0]];
+ const int *co_curr = verts[s[1]];
+
+ BLI_assert(co_prev[1] < pixel_y && co_curr[1] >= pixel_y);
+
+ const double x = (co_prev[0] - co_curr[0]);
+ const double y = (co_prev[1] - co_curr[1]);
+ const double y_px = (pixel_y - co_curr[1]);
+ const int x_ix = (int)((double)co_curr[0] + ((y_px / y) * x));
+ n->x = x_ix;
+
+ if (is_sorted && (x_ix_prev > x_ix)) {
+ is_sorted = false;
+ }
+ if (do_remove == false && co_curr[1] == pixel_y) {
+ do_remove = true;
+ }
+ x_ix_prev = x_ix;
+ }
+
+ /* Sort the nodes, via a simple "Bubble" sort. */
+ if (is_sorted == false) {
+ int i = 0;
+ const int node_x_end = node_x_len - 1;
+ while (i < node_x_end) {
+ if (node_x[i].x > node_x[i + 1].x) {
+ SWAP(struct NodeX, node_x[i], node_x[i + 1]);
+ if (i != 0) {
+ i -= 1;
+ }
+ }
+ else {
+ i += 1;
+ }
+ }
+ }
+
+ /* Fill the pixels between node pairs. */
+ for (int i = 0; i < node_x_len; i += 2) {
+ int x_src = node_x[i].x;
+ int x_dst = node_x[i + 1].x;
+
+ if (x_src >= xmax) {
+ break;
+ }
+
+ if (x_dst > xmin) {
+ if (x_src < xmin) {
+ x_src = xmin;
+ }
+ if (x_dst > xmax) {
+ x_dst = xmax;
+ }
+ /* for single call per x-span */
+ if (x_src < x_dst) {
+ callback(x_src - xmin, x_dst - xmin, pixel_y - ymin, userData);
+ }
+ }
+ }
+
+ /* Clear finalized nodes in one pass, only when needed
+ * (avoids excessive array-resizing). */
+ if (do_remove == true) {
+ int i_dst = 0;
+ for (int i_src = 0; i_src < node_x_len; i_src += 1) {
+ const int *s = span_y[node_x[i_src].span_y_index];
+ const int *co = verts[s[1]];
+ if (co[1] != pixel_y) {
+ if (i_dst != i_src) {
+ /* x is initialized for the next pixel_y (no need to adjust here) */
+ node_x[i_dst].span_y_index = node_x[i_src].span_y_index;
+ }
+ i_dst += 1;
+ }
+ }
+ node_x_len = i_dst;
+ }
+
+ /* Scan for new x-nodes */
+ while ((span_y_index < span_y_len) &&
+ (verts[span_y[span_y_index][0]][1] == pixel_y))
+ {
+ /* note, node_x these are just added at the end,
+ * not ideal but sorting once will resolve. */
+
+ /* x is initialized for the next pixel_y */
+ struct NodeX *n = &node_x[node_x_len++];
+ n->span_y_index = span_y_index;
+ span_y_index += 1;
+ }
+ }
+
+ MEM_freeN(span_y);
+ MEM_freeN(node_x);
+}
diff --git a/source/blender/blenlib/intern/hash_md5.c b/source/blender/blenlib/intern/hash_md5.c
index d98b915983c..c73fe7a3ff1 100644
--- a/source/blender/blenlib/intern/hash_md5.c
+++ b/source/blender/blenlib/intern/hash_md5.c
@@ -112,7 +112,7 @@ static void md5_init_ctx(struct md5_ctx *ctx)
* the 'ctx' context for the next 'len' bytes starting at 'buffer'.
* It is necessary that 'len' is a multiple of 64!!!
*/
-static void md5_process_block (const void *buffer, size_t len, struct md5_ctx *ctx)
+static void md5_process_block(const void *buffer, size_t len, struct md5_ctx *ctx)
{
/* These are the four functions used in the four steps of the MD5 algorithm and defined in the RFC 1321.
* The first function is a little bit optimized (as found in Colin Plumbs public domain implementation).
diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c
index ebee2c7941c..c9bf4976ae8 100644
--- a/source/blender/blenlib/intern/listbase.c
+++ b/source/blender/blenlib/intern/listbase.c
@@ -342,6 +342,44 @@ void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink)
}
}
+/**
+ * Reinsert \a vlink relative to its current position but offset by \a step. Doesn't move
+ * item if new position would exceed list (could optionally move to head/tail).
+ *
+ * \param step: Absolute value defines step size, sign defines direction. E.g pass -1
+ * to move \a vlink before previous, or 1 to move behind next.
+ * \return If position of \a vlink has changed.
+ */
+bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step)
+{
+ Link *link = vlink;
+ Link *hook = link;
+ const bool is_up = step < 0;
+
+ if (step == 0) {
+ return false;
+ }
+ BLI_assert(BLI_findindex(listbase, link) != -1);
+
+ /* find link to insert before/after */
+ for (int i = 0; i < ABS(step); i++) {
+ hook = is_up ? hook->prev : hook->next;
+ if (!hook) {
+ return false;
+ }
+ }
+
+ /* reinsert link */
+ BLI_remlink(listbase, vlink);
+ if (is_up) {
+ BLI_insertlinkbefore(listbase, hook, vlink);
+ }
+ else {
+ BLI_insertlinkafter(listbase, hook, vlink);
+ }
+ return true;
+}
+
/**
* Removes and disposes of the entire contents of listbase using direct free(3).
diff --git a/source/blender/blenlib/intern/math_base.c b/source/blender/blenlib/intern/math_base.c
index 0a1e9e8a8a1..14eba3e61a4 100644
--- a/source/blender/blenlib/intern/math_base.c
+++ b/source/blender/blenlib/intern/math_base.c
@@ -56,7 +56,7 @@ double double_round(double x, int ndigits)
pow2 = 1.0;
y = (x * pow1) * pow2;
/* if y overflows, then rounded value is exactly x */
- if (!finite(y))
+ if (!isfinite(y))
return x;
}
else {
diff --git a/source/blender/blenlib/intern/math_color_inline.c b/source/blender/blenlib/intern/math_color_inline.c
index 180d62105c4..01a805a09b6 100644
--- a/source/blender/blenlib/intern/math_color_inline.c
+++ b/source/blender/blenlib/intern/math_color_inline.c
@@ -65,7 +65,7 @@ MALWAYS_INLINE __m128 linearrgb_to_srgb_v4_simd(const __m128 c)
MINLINE void srgb_to_linearrgb_v3_v3(float linear[3], const float srgb[3])
{
- float r[4] = {srgb[0], srgb[1], srgb[2], 0.0f};
+ float r[4] = {srgb[0], srgb[1], srgb[2], 1.0f};
__m128 *rv = (__m128 *)&r;
*rv = srgb_to_linearrgb_v4_simd(*rv);
linear[0] = r[0];
@@ -75,7 +75,7 @@ MINLINE void srgb_to_linearrgb_v3_v3(float linear[3], const float srgb[3])
MINLINE void linearrgb_to_srgb_v3_v3(float srgb[3], const float linear[3])
{
- float r[4] = {linear[0], linear[1], linear[2], 0.0f};
+ float r[4] = {linear[0], linear[1], linear[2], 1.0f};
__m128 *rv = (__m128 *)&r;
*rv = linearrgb_to_srgb_v4_simd(*rv);
srgb[0] = r[0];
@@ -269,7 +269,7 @@ MINLINE void cpack_cpy_3ub(unsigned char r_col[3], const unsigned int pack)
/**
* ITU-R BT.709 primaries
- * http://en.wikipedia.org/wiki/Relative_luminance
+ * https://en.wikipedia.org/wiki/Relative_luminance
*
* Real values are:
* ``Y = 0.2126390059(R) + 0.7151686788(G) + 0.0721923154(B)``
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index f80099bee1b..f31d0935b77 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -572,6 +572,67 @@ float dist_signed_squared_to_corner_v3v3v3(
}
}
+/**
+ * return the distance squared of a point to a ray.
+ */
+float dist_squared_to_ray_v3(
+ const float ray_origin[3], const float ray_direction[3],
+ const float co[3], float *r_depth)
+{
+ float dvec[3];
+ sub_v3_v3v3(dvec, co, ray_origin);
+ *r_depth = dot_v3v3(dvec, ray_direction);
+ return len_squared_v3(dvec) - SQUARE(*r_depth);
+}
+/**
+ * Find the closest point in a seg to a ray and return the distance squared.
+ * \param r_point : Is the point on segment closest to ray (or to ray_origin if the ray and the segment are parallel).
+ * \param depth: the distance of r_point projection on ray to the ray_origin.
+ */
+float dist_squared_ray_to_seg_v3(
+ const float ray_origin[3], const float ray_direction[3],
+ const float v0[3], const float v1[3],
+ float r_point[3], float *r_depth)
+{
+ float a[3], t[3], n[3], lambda;
+ sub_v3_v3v3(a, v1, v0);
+ sub_v3_v3v3(t, v0, ray_origin);
+ cross_v3_v3v3(n, a, ray_direction);
+ const float nlen = len_squared_v3(n);
+
+ /* if (nlen == 0.0f) the lines are parallel,
+ * has no nearest point, only distance squared.*/
+ if (nlen == 0.0f) {
+ /* Calculate the distance to the point v0 then */
+ copy_v3_v3(r_point, v0);
+ *r_depth = dot_v3v3(t, ray_direction);
+ }
+ else {
+ float c[3], cray[3];
+ sub_v3_v3v3(c, n, t);
+ cross_v3_v3v3(cray, c, ray_direction);
+ lambda = dot_v3v3(cray, n) / nlen;
+ if (lambda <= 0) {
+ copy_v3_v3(r_point, v0);
+
+ *r_depth = dot_v3v3(t, ray_direction);
+ }
+ else if (lambda >= 1) {
+ copy_v3_v3(r_point, v1);
+
+ sub_v3_v3v3(t, v1, ray_origin);
+ *r_depth = dot_v3v3(t, ray_direction);
+ }
+ else {
+ madd_v3_v3v3fl(r_point, v0, a, lambda);
+
+ sub_v3_v3v3(t, r_point, ray_origin);
+ *r_depth = dot_v3v3(t, ray_direction);
+ }
+ }
+ return len_squared_v3(t) - SQUARE(*r_depth);
+}
+
/* Adapted from "Real-Time Collision Detection" by Christer Ericson,
* published by Morgan Kaufmann Publishers, copyright 2005 Elsevier Inc.
*
@@ -2692,7 +2753,7 @@ bool isect_point_tri_prism_v3(const float p[3], const float v1[3], const float v
}
/**
- * \param r_vi The point \a p projected onto the triangle.
+ * \param r_isect_co: The point \a p projected onto the triangle.
* \return True when \a p is inside the triangle.
* \note Its up to the caller to check the distance between \a p and \a r_vi against an error margin.
*/
@@ -2824,142 +2885,6 @@ bool clip_segment_v3_plane_n(
return true;
}
-void plot_line_v2v2i(const int p1[2], const int p2[2], bool (*callback)(int, int, void *), void *userData)
-{
- int x1 = p1[0];
- int y1 = p1[1];
- int x2 = p2[0];
- int y2 = p2[1];
-
- signed char ix;
- signed char iy;
-
- /* if x1 == x2 or y1 == y2, then it does not matter what we set here */
- int delta_x = (x2 > x1 ? ((void)(ix = 1), x2 - x1) : ((void)(ix = -1), x1 - x2)) << 1;
- int delta_y = (y2 > y1 ? ((void)(iy = 1), y2 - y1) : ((void)(iy = -1), y1 - y2)) << 1;
-
- if (callback(x1, y1, userData) == 0) {
- return;
- }
-
- if (delta_x >= delta_y) {
- /* error may go below zero */
- int error = delta_y - (delta_x >> 1);
-
- while (x1 != x2) {
- if (error >= 0) {
- if (error || (ix > 0)) {
- y1 += iy;
- error -= delta_x;
- }
- /* else do nothing */
- }
- /* else do nothing */
-
- x1 += ix;
- error += delta_y;
-
- if (callback(x1, y1, userData) == 0) {
- return;
- }
- }
- }
- else {
- /* error may go below zero */
- int error = delta_x - (delta_y >> 1);
-
- while (y1 != y2) {
- if (error >= 0) {
- if (error || (iy > 0)) {
- x1 += ix;
- error -= delta_y;
- }
- /* else do nothing */
- }
- /* else do nothing */
-
- y1 += iy;
- error += delta_x;
-
- if (callback(x1, y1, userData) == 0) {
- return;
- }
- }
- }
-}
-
-/**
- * \param callback: Takes the x, y coords and x-span (\a x_end is not inclusive),
- * note that \a x_end will always be greater than \a x, so we can use:
- *
- * \code{.c}
- * do {
- * func(x, y);
- * } while (++x != x_end);
- * \endcode
- */
-void fill_poly_v2i_n(
- const int xmin, const int ymin, const int xmax, const int ymax,
- const int verts[][2], const int nr,
- void (*callback)(int x, int x_end, int y, void *), void *userData)
-{
- /* originally by Darel Rex Finley, 2007 */
-
- int nodes, pixel_y, i, j, swap;
- int *node_x = MEM_mallocN(sizeof(*node_x) * (size_t)(nr + 1), __func__);
-
- /* Loop through the rows of the image. */
- for (pixel_y = ymin; pixel_y < ymax; pixel_y++) {
-
- /* Build a list of nodes. */
- nodes = 0; j = nr - 1;
- for (i = 0; i < nr; i++) {
- if ((verts[i][1] < pixel_y && verts[j][1] >= pixel_y) ||
- (verts[j][1] < pixel_y && verts[i][1] >= pixel_y))
- {
- node_x[nodes++] = (int)(verts[i][0] +
- ((double)(pixel_y - verts[i][1]) / (verts[j][1] - verts[i][1])) *
- (verts[j][0] - verts[i][0]));
- }
- j = i;
- }
-
- /* Sort the nodes, via a simple "Bubble" sort. */
- i = 0;
- while (i < nodes - 1) {
- if (node_x[i] > node_x[i + 1]) {
- SWAP_TVAL(swap, node_x[i], node_x[i + 1]);
- if (i) i--;
- }
- else {
- i++;
- }
- }
-
- /* Fill the pixels between node pairs. */
- for (i = 0; i < nodes; i += 2) {
- if (node_x[i] >= xmax) break;
- if (node_x[i + 1] > xmin) {
- if (node_x[i ] < xmin) node_x[i ] = xmin;
- if (node_x[i + 1] > xmax) node_x[i + 1] = xmax;
-
-#if 0
- /* for many x/y calls */
- for (j = node_x[i]; j < node_x[i + 1]; j++) {
- callback(j - xmin, pixel_y - ymin, userData);
- }
-#else
- /* for single call per x-span */
- if (node_x[i] < node_x[i + 1]) {
- callback(node_x[i] - xmin, node_x[i + 1] - xmin, pixel_y - ymin, userData);
- }
-#endif
- }
- }
- }
- MEM_freeN(node_x);
-}
-
/****************************** Axis Utils ********************************/
/**
@@ -4988,3 +4913,39 @@ int is_quad_flip_v3(const float v1[3], const float v2[3], const float v3[3], con
return ret;
}
+
+/**
+ * Return the value which the distance between points will need to be scaled by,
+ * to define a handle, given both points are on a perfect circle.
+ *
+ * Use when we want a bezier curve to match a circle as closely as possible.
+ *
+ * \note the return value will need to be divided by 0.75 for correct results.
+ */
+float cubic_tangent_factor_circle_v3(const float tan_l[3], const float tan_r[3])
+{
+ BLI_ASSERT_UNIT_V3(tan_l);
+ BLI_ASSERT_UNIT_V3(tan_r);
+
+ /* -7f causes instability/glitches with Bendy Bones + Custom Refs */
+ const float eps = 1e-5f;
+
+ const float tan_dot = dot_v3v3(tan_l, tan_r);
+ if (tan_dot > 1.0f - eps) {
+ /* no angle difference (use fallback, length wont make any difference) */
+ return (1.0f / 3.0f) * 0.75f;
+ }
+ else if (tan_dot < -1.0f + eps) {
+ /* parallele tangents (half-circle) */
+ return (1.0f / 2.0f);
+ }
+ else {
+ /* non-aligned tangents, calculate handle length */
+ const float angle = acosf(tan_dot) / 2.0f;
+
+ /* could also use 'angle_sin = len_vnvn(tan_l, tan_r, dims) / 2.0' */
+ const float angle_sin = sinf(angle);
+ const float angle_cos = cosf(angle);
+ return ((1.0f - angle_cos) / (angle_sin * 2.0f)) / angle_sin;
+ }
+}
diff --git a/source/blender/blenlib/intern/math_interp.c b/source/blender/blenlib/intern/math_interp.c
index 069d23e7147..8c361673715 100644
--- a/source/blender/blenlib/intern/math_interp.c
+++ b/source/blender/blenlib/intern/math_interp.c
@@ -284,16 +284,19 @@ BLI_INLINE void bilinear_interpolation(const unsigned char *byte_buffer, const f
if (x1 < 0) x1 = width - 1;
if (x2 >= width) x2 = 0;
}
+ else if (x2 < 0 || x1 >= width) {
+ copy_vn_fl(float_output, components, 0.0f);
+ return;
+ }
+
if (wrap_y) {
if (y1 < 0) y1 = height - 1;
if (y2 >= height) y2 = 0;
}
-
- CLAMP(x1, 0, width - 1);
- CLAMP(x2, 0, width - 1);
-
- CLAMP(y1, 0, height - 1);
- CLAMP(y2, 0, height - 1);
+ else if (y2 < 0 || y1 >= height) {
+ copy_vn_fl(float_output, components, 0.0f);
+ return;
+ }
/* sample including outside of edges of image */
if (x1 < 0 || y1 < 0) row1 = empty;
@@ -331,8 +334,21 @@ BLI_INLINE void bilinear_interpolation(const unsigned char *byte_buffer, const f
const unsigned char *row1, *row2, *row3, *row4;
unsigned char empty[4] = {0, 0, 0, 0};
- /* sample area entirely outside image? */
- if (x2 < 0 || x1 > width - 1 || y2 < 0 || y1 > height - 1) {
+ /* pixel value must be already wrapped, however values at boundaries may flip */
+ if (wrap_x) {
+ if (x1 < 0) x1 = width - 1;
+ if (x2 >= width) x2 = 0;
+ }
+ else if (x2 < 0 || x1 >= width) {
+ copy_vn_uchar(byte_output, components, 0);
+ return;
+ }
+
+ if (wrap_y) {
+ if (y1 < 0) y1 = height - 1;
+ if (y2 >= height) y2 = 0;
+ }
+ else if (y2 < 0 || y1 >= height) {
copy_vn_uchar(byte_output, components, 0);
return;
}
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index 52ff6fd3e8a..c9c61d5c878 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -587,6 +587,15 @@ void mul_v3_m3v3(float r[3], float M[3][3], const float a[3])
r[2] = M[0][2] * a[0] + M[1][2] * a[1] + M[2][2] * a[2];
}
+void mul_v3_m3v3_db(double r[3], double M[3][3], const double a[3])
+{
+ BLI_assert(r != a);
+
+ r[0] = M[0][0] * a[0] + M[1][0] * a[1] + M[2][0] * a[2];
+ r[1] = M[0][1] * a[0] + M[1][1] * a[1] + M[2][1] * a[2];
+ r[2] = M[0][2] * a[0] + M[1][2] * a[1] + M[2][2] * a[2];
+}
+
void mul_v2_m3v3(float r[2], float M[3][3], const float a[3])
{
BLI_assert(r != a);
@@ -597,10 +606,12 @@ void mul_v2_m3v3(float r[2], float M[3][3], const float a[3])
void mul_m3_v3(float M[3][3], float r[3])
{
- float tmp[3];
+ mul_v3_m3v3(r, M, (const float[3]){UNPACK3(r)});
+}
- mul_v3_m3v3(tmp, M, r);
- copy_v3_v3(r, tmp);
+void mul_m3_v3_db(double M[3][3], double r[3])
+{
+ mul_v3_m3v3_db(r, M, (const double[3]){UNPACK3(r)});
}
void mul_transposed_m3_v3(float mat[3][3], float vec[3])
@@ -1828,6 +1839,21 @@ bool is_zero_m4(float mat[4][4])
is_zero_v4(mat[3]));
}
+bool equals_m3m3(float mat1[3][3], float mat2[3][3])
+{
+ return (equals_v3v3(mat1[0], mat2[0]) &&
+ equals_v3v3(mat1[1], mat2[1]) &&
+ equals_v3v3(mat1[2], mat2[2]));
+}
+
+bool equals_m4m4(float mat1[4][4], float mat2[4][4])
+{
+ return (equals_v4v4(mat1[0], mat2[0]) &&
+ equals_v4v4(mat1[1], mat2[1]) &&
+ equals_v4v4(mat1[2], mat2[2]) &&
+ equals_v4v4(mat1[3], mat2[3]));
+}
+
/* make a 4x4 matrix out of 3 transform components */
/* matrices are made in the order: scale * rot * loc */
/* TODO: need to have a version that allows for rotation order... */
diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c
index d962e4f0fa7..b285a74b8ac 100644
--- a/source/blender/blenlib/intern/math_rotation.c
+++ b/source/blender/blenlib/intern/math_rotation.c
@@ -200,8 +200,7 @@ void mul_fac_qt_fl(float q[4], const float fac)
const float co = cosf(angle);
const float si = sinf(angle);
q[0] = co;
- normalize_v3(q + 1);
- mul_v3_fl(q + 1, si);
+ normalize_v3_length(q + 1, si);
}
/* skip error check, currently only needed by mat3_to_quat_is_ok */
diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c
index 3e464327b2e..95d5c9fde87 100644
--- a/source/blender/blenlib/intern/math_vector.c
+++ b/source/blender/blenlib/intern/math_vector.c
@@ -164,6 +164,27 @@ void interp_v2_v2v2_slerp_safe(float target[2], const float a[2], const float b[
}
}
+/** \name Cubic curve interpolation (bezier spline).
+ * \{ */
+
+void interp_v2_v2v2v2v2_cubic(
+ float p[2], const float v1[2], const float v2[2], const float v3[2], const float v4[2],
+ const float u)
+{
+ float q0[2], q1[2], q2[2], r0[2], r1[2];
+
+ interp_v2_v2v2(q0, v1, v2, u);
+ interp_v2_v2v2(q1, v2, v3, u);
+ interp_v2_v2v2(q2, v3, v4, u);
+
+ interp_v2_v2v2(r0, q0, q1, u);
+ interp_v2_v2v2(r1, q1, q2, u);
+
+ interp_v2_v2v2(p, r0, r1, u);
+}
+
+/** \} */
+
/* weight 3 vectors,
* 'w' must be unit length but is not a vector, just 3 weights */
void interp_v3_v3v3v3(float p[3], const float v1[3], const float v2[3], const float v3[3], const float w[3])
@@ -336,6 +357,25 @@ void flip_v2_v2v2(float v[2], const float v1[2], const float v2[2])
v[1] = v1[1] + (v1[1] - v2[1]);
}
+
+/********************************* Comparison ********************************/
+
+bool is_finite_v2(const float v[2])
+{
+ return (isfinite(v[0]) && isfinite(v[1]));
+}
+
+bool is_finite_v3(const float v[3])
+{
+ return (isfinite(v[0]) && isfinite(v[1]) && isfinite(v[2]));
+}
+
+bool is_finite_v4(const float v[4])
+{
+ return (isfinite(v[0]) && isfinite(v[1]) && isfinite(v[2]) && isfinite(v[3]));
+}
+
+
/********************************** Angles ***********************************/
/* Return the angle in radians between vecs 1-2 and 2-3 in radians
@@ -566,23 +606,27 @@ void angle_poly_v3(float *angles, const float *verts[3], int len)
/********************************* Geometry **********************************/
-/* Project v1 on v2 */
-void project_v2_v2v2(float c[2], const float v1[2], const float v2[2])
+/**
+ * Project \a p onto \a v_proj
+ */
+void project_v2_v2v2(float out[2], const float p[2], const float v_proj[2])
{
- const float mul = dot_v2v2(v1, v2) / dot_v2v2(v2, v2);
+ const float mul = dot_v2v2(p, v_proj) / dot_v2v2(v_proj, v_proj);
- c[0] = mul * v2[0];
- c[1] = mul * v2[1];
+ out[0] = mul * v_proj[0];
+ out[1] = mul * v_proj[1];
}
-/* Project v1 on v2 */
-void project_v3_v3v3(float c[3], const float v1[3], const float v2[3])
+/**
+ * Project \a p onto \a v_proj
+ */
+void project_v3_v3v3(float out[3], const float p[3], const float v_proj[3])
{
- const float mul = dot_v3v3(v1, v2) / dot_v3v3(v2, v2);
+ const float mul = dot_v3v3(p, v_proj) / dot_v3v3(v_proj, v_proj);
- c[0] = mul * v2[0];
- c[1] = mul * v2[1];
- c[2] = mul * v2[2];
+ out[0] = mul * v_proj[0];
+ out[1] = mul * v_proj[1];
+ out[2] = mul * v_proj[2];
}
/**
@@ -598,35 +642,35 @@ void project_v3_v3v3(float c[3], const float v1[3], const float v2[3])
* sub_v3_v3v3(c, v, c);
* \endcode
*/
-void project_plane_v3_v3v3(float c[3], const float v[3], const float v_plane[3])
+void project_plane_v3_v3v3(float out[3], const float p[3], const float v_plane[3])
{
- const float mul = dot_v3v3(v, v_plane) / dot_v3v3(v_plane, v_plane);
+ const float mul = dot_v3v3(p, v_plane) / dot_v3v3(v_plane, v_plane);
- c[0] = v[0] - (mul * v_plane[0]);
- c[1] = v[1] - (mul * v_plane[1]);
- c[2] = v[2] - (mul * v_plane[2]);
+ out[0] = p[0] - (mul * v_plane[0]);
+ out[1] = p[1] - (mul * v_plane[1]);
+ out[2] = p[2] - (mul * v_plane[2]);
}
-void project_plane_v2_v2v2(float c[2], const float v[2], const float v_plane[2])
+void project_plane_v2_v2v2(float out[2], const float p[2], const float v_plane[2])
{
- const float mul = dot_v2v2(v, v_plane) / dot_v2v2(v_plane, v_plane);
+ const float mul = dot_v2v2(p, v_plane) / dot_v2v2(v_plane, v_plane);
- c[0] = v[0] - (mul * v_plane[0]);
- c[1] = v[1] - (mul * v_plane[1]);
+ out[0] = p[0] - (mul * v_plane[0]);
+ out[1] = p[1] - (mul * v_plane[1]);
}
/* project a vector on a plane defined by normal and a plane point p */
-void project_v3_plane(float v[3], const float n[3], const float p[3])
+void project_v3_plane(float out[3], const float plane_no[3], const float plane_co[3])
{
float vector[3];
float mul;
- sub_v3_v3v3(vector, v, p);
- mul = dot_v3v3(vector, n) / len_squared_v3(n);
+ sub_v3_v3v3(vector, out, plane_co);
+ mul = dot_v3v3(vector, plane_no) / len_squared_v3(plane_no);
- mul_v3_v3fl(vector, n, mul);
+ mul_v3_v3fl(vector, plane_no, mul);
- sub_v3_v3(v, vector);
+ sub_v3_v3(out, vector);
}
/* Returns a vector bisecting the angle at v2 formed by v1, v2 and v3 */
@@ -645,15 +689,15 @@ void bisect_v3_v3v3v3(float out[3], const float v1[3], const float v2[3], const
* Returns a reflection vector from a vector and a normal vector
* reflect = vec - ((2 * DotVecs(vec, mirror)) * mirror)
*/
-void reflect_v3_v3v3(float out[3], const float vec[3], const float normal[3])
+void reflect_v3_v3v3(float out[3], const float v[3], const float normal[3])
{
- const float dot2 = 2.0f * dot_v3v3(vec, normal);
+ const float dot2 = 2.0f * dot_v3v3(v, normal);
BLI_ASSERT_UNIT_V3(normal);
- out[0] = vec[0] - (dot2 * normal[0]);
- out[1] = vec[1] - (dot2 * normal[1]);
- out[2] = vec[2] - (dot2 * normal[2]);
+ out[0] = v[0] - (dot2 * normal[0]);
+ out[1] = v[1] - (dot2 * normal[1]);
+ out[2] = v[2] - (dot2 * normal[2]);
}
/**
@@ -669,7 +713,7 @@ void ortho_basis_v3v3_v3(float r_n1[3], float r_n2[3], const float n[3])
if (f > eps) {
const float d = 1.0f / sqrtf(f);
- BLI_assert(finite(d));
+ BLI_assert(isfinite(d));
r_n1[0] = n[1] * d;
r_n1[1] = -n[0] * d;
@@ -691,27 +735,27 @@ void ortho_basis_v3v3_v3(float r_n1[3], float r_n2[3], const float n[3])
*
* \note return vector won't maintain same length.
*/
-void ortho_v3_v3(float p[3], const float v[3])
+void ortho_v3_v3(float out[3], const float v[3])
{
const int axis = axis_dominant_v3_single(v);
- BLI_assert(p != v);
+ BLI_assert(out != v);
switch (axis) {
case 0:
- p[0] = -v[1] - v[2];
- p[1] = v[0];
- p[2] = v[0];
+ out[0] = -v[1] - v[2];
+ out[1] = v[0];
+ out[2] = v[0];
break;
case 1:
- p[0] = v[1];
- p[1] = -v[0] - v[2];
- p[2] = v[1];
+ out[0] = v[1];
+ out[1] = -v[0] - v[2];
+ out[2] = v[1];
break;
case 2:
- p[0] = v[2];
- p[1] = v[2];
- p[2] = -v[0] - v[1];
+ out[0] = v[2];
+ out[1] = v[2];
+ out[2] = -v[0] - v[1];
break;
}
}
@@ -719,18 +763,19 @@ void ortho_v3_v3(float p[3], const float v[3])
/**
* no brainer compared to v3, just have for consistency.
*/
-void ortho_v2_v2(float p[2], const float v[2])
+void ortho_v2_v2(float out[2], const float v[2])
{
- BLI_assert(p != v);
+ BLI_assert(out != v);
- p[0] = -v[1];
- p[1] = v[0];
+ out[0] = -v[1];
+ out[1] = v[0];
}
-/* Rotate a point p by angle theta around an arbitrary axis r
+/**
+ * Rotate a point \a p by \a angle around an arbitrary unit length \a axis.
* http://local.wasp.uwa.edu.au/~pbourke/geometry/
*/
-void rotate_normalized_v3_v3v3fl(float r[3], const float p[3], const float axis[3], const float angle)
+void rotate_normalized_v3_v3v3fl(float out[3], const float p[3], const float axis[3], const float angle)
{
const float costheta = cosf(angle);
const float sintheta = sinf(angle);
@@ -738,17 +783,17 @@ void rotate_normalized_v3_v3v3fl(float r[3], const float p[3], const float axis[
/* double check they are normalized */
BLI_ASSERT_UNIT_V3(axis);
- r[0] = ((costheta + (1 - costheta) * axis[0] * axis[0]) * p[0]) +
- (((1 - costheta) * axis[0] * axis[1] - axis[2] * sintheta) * p[1]) +
- (((1 - costheta) * axis[0] * axis[2] + axis[1] * sintheta) * p[2]);
+ out[0] = ((costheta + (1 - costheta) * axis[0] * axis[0]) * p[0]) +
+ (((1 - costheta) * axis[0] * axis[1] - axis[2] * sintheta) * p[1]) +
+ (((1 - costheta) * axis[0] * axis[2] + axis[1] * sintheta) * p[2]);
- r[1] = (((1 - costheta) * axis[0] * axis[1] + axis[2] * sintheta) * p[0]) +
- ((costheta + (1 - costheta) * axis[1] * axis[1]) * p[1]) +
- (((1 - costheta) * axis[1] * axis[2] - axis[0] * sintheta) * p[2]);
+ out[1] = (((1 - costheta) * axis[0] * axis[1] + axis[2] * sintheta) * p[0]) +
+ ((costheta + (1 - costheta) * axis[1] * axis[1]) * p[1]) +
+ (((1 - costheta) * axis[1] * axis[2] - axis[0] * sintheta) * p[2]);
- r[2] = (((1 - costheta) * axis[0] * axis[2] - axis[1] * sintheta) * p[0]) +
- (((1 - costheta) * axis[1] * axis[2] + axis[0] * sintheta) * p[1]) +
- ((costheta + (1 - costheta) * axis[2] * axis[2]) * p[2]);
+ out[2] = (((1 - costheta) * axis[0] * axis[2] - axis[1] * sintheta) * p[0]) +
+ (((1 - costheta) * axis[1] * axis[2] + axis[0] * sintheta) * p[1]) +
+ ((costheta + (1 - costheta) * axis[2] * axis[2]) * p[2]);
}
void rotate_v3_v3v3fl(float r[3], const float p[3], const float axis[3], const float angle)
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index 17e2da3f1cb..e9fb77f6302 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -633,6 +633,13 @@ MINLINE void negate_v3_short(short r[3])
r[2] = (short)-r[2];
}
+MINLINE void negate_v3_db(double r[3])
+{
+ r[0] = -r[0];
+ r[1] = -r[1];
+ r[2] = -r[2];
+}
+
MINLINE void invert_v2(float r[2])
{
BLI_assert(!ELEM(0.0f, r[0], r[1]));
@@ -852,13 +859,13 @@ MINLINE float len_v3v3(const float a[3], const float b[3])
return len_v3(d);
}
-MINLINE float normalize_v2_v2(float r[2], const float a[2])
+MINLINE float normalize_v2_v2_length(float r[2], const float a[2], const float unit_length)
{
float d = dot_v2v2(a, a);
if (d > 1.0e-35f) {
d = sqrtf(d);
- mul_v2_v2fl(r, a, 1.0f / d);
+ mul_v2_v2fl(r, a, unit_length / d);
}
else {
zero_v2(r);
@@ -867,13 +874,22 @@ MINLINE float normalize_v2_v2(float r[2], const float a[2])
return d;
}
+MINLINE float normalize_v2_v2(float r[2], const float a[2])
+{
+ return normalize_v2_v2_length(r, a, 1.0f);
+}
MINLINE float normalize_v2(float n[2])
{
return normalize_v2_v2(n, n);
}
-MINLINE float normalize_v3_v3(float r[3], const float a[3])
+MINLINE float normalize_v2_length(float n[2], const float unit_length)
+{
+ return normalize_v2_v2_length(n, n, unit_length);
+}
+
+MINLINE float normalize_v3_v3_length(float r[3], const float a[3], const float unit_length)
{
float d = dot_v3v3(a, a);
@@ -881,7 +897,7 @@ MINLINE float normalize_v3_v3(float r[3], const float a[3])
* scaled down models with camera extreme close */
if (d > 1.0e-35f) {
d = sqrtf(d);
- mul_v3_v3fl(r, a, 1.0f / d);
+ mul_v3_v3fl(r, a, unit_length / d);
}
else {
zero_v3(r);
@@ -890,8 +906,12 @@ MINLINE float normalize_v3_v3(float r[3], const float a[3])
return d;
}
+MINLINE float normalize_v3_v3(float r[3], const float a[3])
+{
+ return normalize_v3_v3_length(r, a, 1.0f);
+}
-MINLINE double normalize_v3_d(double n[3])
+MINLINE double normalize_v3_length_d(double n[3], const double unit_length)
{
double d = n[0] * n[0] + n[1] * n[1] + n[2] * n[2];
@@ -901,7 +921,7 @@ MINLINE double normalize_v3_d(double n[3])
double mul;
d = sqrt(d);
- mul = 1.0 / d;
+ mul = unit_length / d;
n[0] *= mul;
n[1] *= mul;
@@ -914,6 +934,15 @@ MINLINE double normalize_v3_d(double n[3])
return d;
}
+MINLINE double normalize_v3_d(double n[3])
+{
+ return normalize_v3_length_d(n, 1.0);
+}
+
+MINLINE float normalize_v3_length(float n[3], const float unit_length)
+{
+ return normalize_v3_v3_length(n, n, unit_length);
+}
MINLINE float normalize_v3(float n[3])
{
@@ -952,21 +981,6 @@ MINLINE bool is_zero_v4(const float v[4])
return (v[0] == 0.0f && v[1] == 0.0f && v[2] == 0.0f && v[3] == 0.0f);
}
-MINLINE bool is_finite_v2(const float v[2])
-{
- return (finite(v[0]) && finite(v[1]));
-}
-
-MINLINE bool is_finite_v3(const float v[3])
-{
- return (finite(v[0]) && finite(v[1]) && finite(v[2]));
-}
-
-MINLINE bool is_finite_v4(const float v[4])
-{
- return (finite(v[0]) && finite(v[1]) && finite(v[2]) && finite(v[3]));
-}
-
MINLINE bool is_one_v3(const float v[3])
{
return (v[0] == 1.0f && v[1] == 1.0f && v[2] == 1.0f);
diff --git a/source/blender/blenlib/intern/noise.c b/source/blender/blenlib/intern/noise.c
index c3a0c44d7c5..f834c5b4c74 100644
--- a/source/blender/blenlib/intern/noise.c
+++ b/source/blender/blenlib/intern/noise.c
@@ -1048,8 +1048,8 @@ static float noise3_perlin(float vec[3])
b01 = p[i + by1];
b11 = p[j + by1];
-#define VALUE_AT(rx, ry, rz) (rx * q[0] + ry * q[1] + rz * q[2])
-#define SURVE(t) (t * t * (3.0f - 2.0f * t))
+#define VALUE_AT(rx, ry, rz) ((rx) * q[0] + (ry) * q[1] + (rz) * q[2])
+#define SURVE(t) ((t) * (t) * (3.0f - 2.0f * (t)))
/* lerp moved to improved perlin above */
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index 2b793841c38..f0d0bd00dea 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -310,7 +310,7 @@ static int BLI_path_unc_prefix_len(const char *path); /* defined below in same f
/**
* Remove redundant characters from \a path and optionally make absolute.
*
- * \param relbase: The path this is relative to, or ignored when NULL.
+ * \param relabase: The path this is relative to, or ignored when NULL.
* \param path: Can be any input, and this function converts it to a regular full path.
* Also removes garbage from directory paths, like `/../` or double slashes etc.
*
@@ -430,7 +430,7 @@ void BLI_cleanup_file(const char *relabase, char *path)
* \return true if \a fname was changed, false otherwise.
*
* For now, simply replaces reserved chars (as listed in
- * http://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words )
+ * https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words )
* by underscores ('_').
*
* \note Space case ' ' is a bit of an edge case here - in theory it is allowed, but again can be an issue
diff --git a/source/blender/blenlib/intern/polyfill2d_beautify.c b/source/blender/blenlib/intern/polyfill2d_beautify.c
index 46f9251bea7..896177f436c 100644
--- a/source/blender/blenlib/intern/polyfill2d_beautify.c
+++ b/source/blender/blenlib/intern/polyfill2d_beautify.c
@@ -239,8 +239,9 @@ static void polyedge_beauty_cost_update_single(
const float cost = polyedge_rotate_beauty_calc(coords, tris, e);
/* We can get cases where both choices generate very small negative costs, which leads to infinite loop.
* Anyway, costs above that are not worth recomputing, maybe we could even optimize it to a smaller limit?
- * See T43578. */
- if (cost < -FLT_EPSILON) {
+ * Actually, FLT_EPSILON is too small in some cases, 1e-6f seems to work OK hopefully?
+ * See T43578, T49478. */
+ if (cost < -1e-6f) {
eheap_table[i] = BLI_heap_insert(eheap, cost, e);
}
else {
diff --git a/source/blender/blenlib/intern/quadric.c b/source/blender/blenlib/intern/quadric.c
index 588cd9c2cb5..c9d27494455 100644
--- a/source/blender/blenlib/intern/quadric.c
+++ b/source/blender/blenlib/intern/quadric.c
@@ -63,26 +63,68 @@ void BLI_quadric_from_plane(Quadric *q, const double v[4])
q->d2 = v[3] * v[3];
}
-void BLI_quadric_to_tensor_m3(const Quadric *q, float m[3][3])
+#if 0 /* UNUSED */
+
+static void quadric_to_tensor_m3(const Quadric *q, double m[3][3])
{
- m[0][0] = (float)q->a2;
- m[0][1] = (float)q->ab;
- m[0][2] = (float)q->ac;
+ m[0][0] = q->a2;
+ m[0][1] = q->ab;
+ m[0][2] = q->ac;
- m[1][0] = (float)q->ab;
- m[1][1] = (float)q->b2;
- m[1][2] = (float)q->bc;
+ m[1][0] = q->ab;
+ m[1][1] = q->b2;
+ m[1][2] = q->bc;
- m[2][0] = (float)q->ac;
- m[2][1] = (float)q->bc;
- m[2][2] = (float)q->c2;
+ m[2][0] = q->ac;
+ m[2][1] = q->bc;
+ m[2][2] = q->c2;
}
-void BLI_quadric_to_vector_v3(const Quadric *q, float v[3])
+#endif
+
+/**
+ * Inline inverse matrix creation.
+ * Equivalent of:
+ *
+ * \code{.c}
+ * quadric_to_tensor_m3(q, m);
+ * invert_m3_db(m, eps);
+ * \endcode
+ */
+static bool quadric_to_tensor_m3_inverse(const Quadric *q, double m[3][3], double epsilon)
{
- v[0] = (float)q->ad;
- v[1] = (float)q->bd;
- v[2] = (float)q->cd;
+ const double det =
+ (q->a2 * (q->b2 * q->c2 - q->bc * q->bc) -
+ q->ab * (q->ab * q->c2 - q->ac * q->bc) +
+ q->ac * (q->ab * q->bc - q->ac * q->b2));
+
+ if (fabs(det) > epsilon) {
+ const double invdet = 1.0 / det;
+
+ m[0][0] = (q->b2 * q->c2 - q->bc * q->bc) * invdet;
+ m[1][0] = (q->bc * q->ac - q->ab * q->c2) * invdet;
+ m[2][0] = (q->ab * q->bc - q->b2 * q->ac) * invdet;
+
+ m[0][1] = (q->ac * q->bc - q->ab * q->c2) * invdet;
+ m[1][1] = (q->a2 * q->c2 - q->ac * q->ac) * invdet;
+ m[2][1] = (q->ab * q->ac - q->a2 * q->bc) * invdet;
+
+ m[0][2] = (q->ab * q->bc - q->ac * q->b2) * invdet;
+ m[1][2] = (q->ac * q->ab - q->a2 * q->bc) * invdet;
+ m[2][2] = (q->a2 * q->b2 - q->ab * q->ab) * invdet;
+
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+void BLI_quadric_to_vector_v3(const Quadric *q, double v[3])
+{
+ v[0] = q->ad;
+ v[1] = q->bd;
+ v[2] = q->cd;
}
void BLI_quadric_clear(Quadric *q)
@@ -105,26 +147,22 @@ void BLI_quadric_mul(Quadric *a, const double scalar)
mul_vn_db((double *)a, QUADRIC_FLT_TOT, scalar);
}
-double BLI_quadric_evaluate(const Quadric *q, const float v_fl[3])
+double BLI_quadric_evaluate(const Quadric *q, const double v[3])
{
- const double v[3] = {UNPACK3(v_fl)};
return ((q->a2 * v[0] * v[0]) + (q->ab * 2 * v[0] * v[1]) + (q->ac * 2 * v[0] * v[2]) + (q->ad * 2 * v[0]) +
(q->b2 * v[1] * v[1]) + (q->bc * 2 * v[1] * v[2]) + (q->bd * 2 * v[1]) +
(q->c2 * v[2] * v[2]) + (q->cd * 2 * v[2]) +
(q->d2));
}
-bool BLI_quadric_optimize(const Quadric *q, float v[3], const float epsilon)
+bool BLI_quadric_optimize(const Quadric *q, double v[3], const double epsilon)
{
- float m[3][3];
+ double m[3][3];
- BLI_quadric_to_tensor_m3(q, m);
-
- if (invert_m3_ex(m, epsilon)) {
+ if (quadric_to_tensor_m3_inverse(q, m, epsilon)) {
BLI_quadric_to_vector_v3(q, v);
- mul_m3_v3(m, v);
- negate_v3(v);
-
+ mul_m3_v3_db(m, v);
+ negate_v3_db(v);
return true;
}
else {
diff --git a/source/blender/blenlib/intern/rand.c b/source/blender/blenlib/intern/rand.c
index 66c568a7ff3..40d9a3da3d9 100644
--- a/source/blender/blenlib/intern/rand.c
+++ b/source/blender/blenlib/intern/rand.c
@@ -46,6 +46,7 @@
#define MULTIPLIER 0x5DEECE66Dll
#define MASK 0x0000FFFFFFFFFFFFll
+#define MASK_BYTES 2
#define ADDEND 0xB
#define LOWSEED 0x330E
@@ -107,6 +108,45 @@ BLI_INLINE void rng_step(RNG *rng)
rng->X = (MULTIPLIER * rng->X + ADDEND) & MASK;
}
+void BLI_rng_get_char_n(RNG *rng, char *bytes, size_t bytes_len)
+{
+ size_t last_len = 0;
+ size_t trim_len = bytes_len;
+
+#define RAND_STRIDE (sizeof(rng->X) - MASK_BYTES)
+
+ if (trim_len > RAND_STRIDE) {
+ last_len = trim_len % RAND_STRIDE;
+ trim_len = trim_len - last_len;
+ }
+ else {
+ trim_len = 0;
+ last_len = bytes_len;
+ }
+
+ const char *data_src = (void *)&(rng->X);
+ size_t i = 0;
+ while (i != trim_len) {
+ BLI_assert(i < trim_len);
+#ifdef __BIG_ENDIAN__
+ for (size_t j = (RAND_STRIDE + MASK_BYTES) - 1; j != MASK_BYTES - 1; j--)
+#else
+ for (size_t j = 0; j != RAND_STRIDE; j++)
+#endif
+ {
+ bytes[i++] = data_src[j];
+ }
+ rng_step(rng);
+ }
+ if (last_len) {
+ for (size_t j = 0; j != last_len; j++) {
+ bytes[i++] = data_src[j];
+ }
+ }
+
+#undef RAND_STRIDE
+}
+
int BLI_rng_get_int(RNG *rng)
{
rng_step(rng);
diff --git a/source/blender/blenlib/intern/scanfill_utils.c b/source/blender/blenlib/intern/scanfill_utils.c
index 059d5cb05a4..3b6ab99ae86 100644
--- a/source/blender/blenlib/intern/scanfill_utils.c
+++ b/source/blender/blenlib/intern/scanfill_utils.c
@@ -257,7 +257,7 @@ static bool scanfill_preprocess_self_isect(
if (UNLIKELY(e_ls == NULL)) {
/* only happens in very rare cases (entirely overlapping splines).
- * in this case se can't do much useful. but at least don't crash */
+ * in this case we can't do much useful. but at least don't crash */
continue;
}
diff --git a/source/blender/blenlib/intern/smallhash.c b/source/blender/blenlib/intern/smallhash.c
index 0b976e9612e..ccac221d836 100644
--- a/source/blender/blenlib/intern/smallhash.c
+++ b/source/blender/blenlib/intern/smallhash.c
@@ -34,7 +34,7 @@
* based on a doubling hashing approach (non-chaining) which uses more buckets then entries
* stepping over buckets when two keys share the same hash so any key can find a free bucket.
*
- * See: http://en.wikipedia.org/wiki/Double_hashing
+ * See: https://en.wikipedia.org/wiki/Double_hashing
*
* \warning This should _only_ be used for small hashes where allocating a hash every time is unacceptable.
* Otherwise #GHash should be used instead.
diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c
index aba7c9d5ee2..3edc00a8c1a 100644
--- a/source/blender/blenlib/intern/storage.c
+++ b/source/blender/blenlib/intern/storage.c
@@ -389,7 +389,7 @@ LinkNode *BLI_file_read_as_lines(const char *name)
/*
* size = because on win32 reading
* all the bytes in the file will return
- * less bytes because of crnl changes.
+ * less bytes because of `CRNL` changes.
*/
size = fread(buf, 1, size, fp);
for (i = 0; i <= size; i++) {
diff --git a/source/blender/blenlib/intern/system.c b/source/blender/blenlib/intern/system.c
index 5d1bdd6d978..863622f2546 100644
--- a/source/blender/blenlib/intern/system.c
+++ b/source/blender/blenlib/intern/system.c
@@ -25,6 +25,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include "BLI_utildefines.h"
#include "BLI_system.h"
#include "MEM_guardedalloc.h"
@@ -34,7 +35,7 @@
# include <execinfo.h>
#elif defined(WIN32)
# include <windows.h>
-# include <DbgHelp.h>
+# include <dbghelp.h>
#endif
int BLI_cpu_support_sse2(void)
diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c
index bebf331e0c1..436cd2b8fde 100644
--- a/source/blender/blenlib/intern/task.c
+++ b/source/blender/blenlib/intern/task.c
@@ -28,6 +28,8 @@
#include "MEM_guardedalloc.h"
+#include "DNA_listBase.h"
+
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_task.h"
@@ -290,15 +292,17 @@ static bool task_scheduler_thread_wait_pop(TaskScheduler *scheduler, Task **task
continue;
}
- if (pool->num_threads == 0 ||
- pool->currently_running_tasks < pool->num_threads)
+ if (atomic_add_z(&pool->currently_running_tasks, 1) <= pool->num_threads ||
+ pool->num_threads == 0)
{
*task = current_task;
found_task = true;
- atomic_add_z(&pool->currently_running_tasks, 1);
BLI_remlink(&scheduler->queue, *task);
break;
}
+ else {
+ atomic_sub_z(&pool->currently_running_tasks, 1);
+ }
}
if (!found_task)
BLI_condition_wait(&scheduler->queue_cond, &scheduler->queue_mutex);
@@ -750,16 +754,13 @@ size_t BLI_task_pool_tasks_done(TaskPool *pool)
*
* Main functions:
* - #BLI_task_parallel_range
+ * - #BLI_task_parallel_listbase (#ListBase - double linked list)
*
* TODO:
- * - #BLI_task_parallel_foreach_listbase (#ListBase - double linked list)
* - #BLI_task_parallel_foreach_link (#Link - single linked list)
* - #BLI_task_parallel_foreach_ghash/gset (#GHash/#GSet - hash & set)
* - #BLI_task_parallel_foreach_mempool (#BLI_mempool - iterate over mempools)
*
- * Possible improvements:
- *
- * - Chunk iterations to reduce number of spin locks.
*/
/* Allows to avoid using malloc for userdata_chunk in tasks, when small enough. */
@@ -769,8 +770,6 @@ size_t BLI_task_pool_tasks_done(TaskPool *pool)
typedef struct ParallelRangeState {
int start, stop;
void *userdata;
- void *userdata_chunk;
- size_t userdata_chunk_size;
TaskParallelRangeFunc func;
TaskParallelRangeFuncEx func_ex;
@@ -783,45 +782,27 @@ BLI_INLINE bool parallel_range_next_iter_get(
ParallelRangeState * __restrict state,
int * __restrict iter, int * __restrict count)
{
- uint32_t n, olditer, previter, newiter;
-
- if (state->iter >= state->stop) {
- return false;
- }
-
- do {
- olditer = state->iter;
- n = min_ii(state->chunk_size, state->stop - state->iter);
- newiter = olditer + n;
- previter = atomic_cas_uint32((uint32_t *)&state->iter, olditer, newiter);
- } while (UNLIKELY(previter != olditer));
+ uint32_t uval = atomic_fetch_and_add_uint32((uint32_t *)(&state->iter), state->chunk_size);
+ int previter = *(int32_t*)&uval;
*iter = previter;
- *count = n;
+ *count = max_ii(0, min_ii(state->chunk_size, state->stop - previter));
- return (n != 0);
+ return (previter < state->stop);
}
static void parallel_range_func(
TaskPool * __restrict pool,
- void *UNUSED(taskdata),
+ void *userdata_chunk,
int threadid)
{
ParallelRangeState * __restrict state = BLI_task_pool_userdata(pool);
int iter, count;
- const bool use_userdata_chunk = (state->func_ex != NULL) &&
- (state->userdata_chunk_size != 0) && (state->userdata_chunk != NULL);
- void *userdata_chunk = use_userdata_chunk ? MALLOCA(state->userdata_chunk_size) : NULL;
-
while (parallel_range_next_iter_get(state, &iter, &count)) {
int i;
if (state->func_ex) {
- if (use_userdata_chunk) {
- memcpy(userdata_chunk, state->userdata_chunk, state->userdata_chunk_size);
- }
-
for (i = 0; i < count; ++i) {
state->func_ex(state->userdata, userdata_chunk, iter + i, threadid);
}
@@ -832,8 +813,6 @@ static void parallel_range_func(
}
}
}
-
- MALLOCA_FREE(userdata_chunk, state->userdata_chunk_size);
}
/**
@@ -848,6 +827,7 @@ static void task_parallel_range_ex(
const size_t userdata_chunk_size,
TaskParallelRangeFunc func,
TaskParallelRangeFuncEx func_ex,
+ TaskParallelRangeFuncFinalize func_finalize,
const bool use_threading,
const bool use_dynamic_scheduling)
{
@@ -856,6 +836,10 @@ static void task_parallel_range_ex(
ParallelRangeState state;
int i, num_threads, num_tasks;
+ void *userdata_chunk_local = NULL;
+ void *userdata_chunk_array = NULL;
+ const bool use_userdata_chunk = (func_ex != NULL) && (userdata_chunk_size != 0) && (userdata_chunk != NULL);
+
if (start == stop) {
return;
}
@@ -871,16 +855,17 @@ static void task_parallel_range_ex(
*/
if (!use_threading) {
if (func_ex) {
- const bool use_userdata_chunk = (userdata_chunk_size != 0) && (userdata_chunk != NULL);
- void *userdata_chunk_local = NULL;
-
if (use_userdata_chunk) {
userdata_chunk_local = MALLOCA(userdata_chunk_size);
memcpy(userdata_chunk_local, userdata_chunk, userdata_chunk_size);
}
for (i = start; i < stop; ++i) {
- func_ex(userdata, userdata_chunk, i, 0);
+ func_ex(userdata, userdata_chunk_local, i, 0);
+ }
+
+ if (func_finalize) {
+ func_finalize(userdata, userdata_chunk_local);
}
MALLOCA_FREE(userdata_chunk_local, userdata_chunk_size);
@@ -907,8 +892,6 @@ static void task_parallel_range_ex(
state.start = start;
state.stop = stop;
state.userdata = userdata;
- state.userdata_chunk = userdata_chunk;
- state.userdata_chunk_size = userdata_chunk_size;
state.func = func;
state.func_ex = func_ex;
state.iter = start;
@@ -920,21 +903,40 @@ static void task_parallel_range_ex(
}
num_tasks = min_ii(num_tasks, (stop - start) / state.chunk_size);
+ atomic_fetch_and_add_uint32((uint32_t *)(&state.iter), 0);
+
+ if (use_userdata_chunk) {
+ userdata_chunk_array = MALLOCA(userdata_chunk_size * num_tasks);
+ }
for (i = 0; i < num_tasks; i++) {
+ if (use_userdata_chunk) {
+ userdata_chunk_local = (char *)userdata_chunk_array + (userdata_chunk_size * i);
+ memcpy(userdata_chunk_local, userdata_chunk, userdata_chunk_size);
+ }
/* Use this pool's pre-allocated tasks. */
BLI_task_pool_push_from_thread(task_pool,
parallel_range_func,
- NULL, false,
+ userdata_chunk_local, false,
TASK_PRIORITY_HIGH, 0);
}
BLI_task_pool_work_and_wait(task_pool);
BLI_task_pool_free(task_pool);
+
+ if (use_userdata_chunk) {
+ if (func_finalize) {
+ for (i = 0; i < num_tasks; i++) {
+ userdata_chunk_local = (char *)userdata_chunk_array + (userdata_chunk_size * i);
+ func_finalize(userdata, userdata_chunk_local);
+ }
+ }
+ MALLOCA_FREE(userdata_chunk_array, userdata_chunk_size * num_tasks);
+ }
}
/**
- * This function allows to parallelized for loops in a similar way to OpenMP's 'parallel for' statement.
+ * This function allows to parallelize for loops in a similar way to OpenMP's 'parallel for' statement.
*
* \param start First index to process.
* \param stop Index to stop looping (excluded).
@@ -958,7 +960,7 @@ void BLI_task_parallel_range_ex(
const bool use_dynamic_scheduling)
{
task_parallel_range_ex(
- start, stop, userdata, userdata_chunk, userdata_chunk_size, NULL, func_ex,
+ start, stop, userdata, userdata_chunk, userdata_chunk_size, NULL, func_ex, NULL,
use_threading, use_dynamic_scheduling);
}
@@ -979,9 +981,154 @@ void BLI_task_parallel_range(
TaskParallelRangeFunc func,
const bool use_threading)
{
- task_parallel_range_ex(start, stop, userdata, NULL, 0, func, NULL, use_threading, false);
+ task_parallel_range_ex(start, stop, userdata, NULL, 0, func, NULL, NULL, use_threading, false);
+}
+
+/**
+ * This function allows to parallelize for loops in a similar way to OpenMP's 'parallel for' statement,
+ * with an additional 'finalize' func called from calling thread once whole range have been processed.
+ *
+ * \param start First index to process.
+ * \param stop Index to stop looping (excluded).
+ * \param userdata Common userdata passed to all instances of \a func.
+ * \param userdata_chunk Optional, each instance of looping chunks will get a copy of this data
+ * (similar to OpenMP's firstprivate).
+ * \param userdata_chunk_size Memory size of \a userdata_chunk.
+ * \param func_ex Callback function (advanced version).
+ * \param func_finalize Callback function, called after all workers have finished,
+ * useful to finalize accumulative tasks.
+ * \param use_threading If \a true, actually split-execute loop in threads, else just do a sequential forloop
+ * (allows caller to use any kind of test to switch on parallelization or not).
+ * \param use_dynamic_scheduling If \a true, the whole range is divided in a lot of small chunks (of size 32 currently),
+ * otherwise whole range is split in a few big chunks (num_threads * 2 chunks currently).
+ */
+void BLI_task_parallel_range_finalize(
+ int start, int stop,
+ void *userdata,
+ void *userdata_chunk,
+ const size_t userdata_chunk_size,
+ TaskParallelRangeFuncEx func_ex,
+ TaskParallelRangeFuncFinalize func_finalize,
+ const bool use_threading,
+ const bool use_dynamic_scheduling)
+{
+ task_parallel_range_ex(
+ start, stop, userdata, userdata_chunk, userdata_chunk_size, NULL, func_ex, func_finalize,
+ use_threading, use_dynamic_scheduling);
}
#undef MALLOCA
#undef MALLOCA_FREE
+typedef struct ParallelListbaseState {
+ void *userdata;
+ TaskParallelListbaseFunc func;
+
+ int chunk_size;
+ int index;
+ Link *link;
+ SpinLock lock;
+} ParallelListState;
+
+BLI_INLINE Link *parallel_listbase_next_iter_get(
+ ParallelListState * __restrict state,
+ int * __restrict index,
+ int * __restrict count)
+{
+ int task_count = 0;
+ BLI_spin_lock(&state->lock);
+ Link *result = state->link;
+ if (LIKELY(result != NULL)) {
+ *index = state->index;
+ while (state->link != NULL && task_count < state->chunk_size) {
+ ++task_count;
+ state->link = state->link->next;
+ }
+ state->index += task_count;
+ }
+ BLI_spin_unlock(&state->lock);
+ *count = task_count;
+ return result;
+}
+
+static void parallel_listbase_func(
+ TaskPool * __restrict pool,
+ void *UNUSED(taskdata),
+ int UNUSED(threadid))
+{
+ ParallelListState * __restrict state = BLI_task_pool_userdata(pool);
+ Link *link;
+ int index, count;
+
+ while ((link = parallel_listbase_next_iter_get(state, &index, &count)) != NULL) {
+ for (int i = 0; i < count; ++i) {
+ state->func(state->userdata, link, index + i);
+ link = link->next;
+ }
+ }
+}
+
+/**
+ * This function allows to parallelize for loops over ListBase items.
+ *
+ * \param listbase The double linked list to loop over.
+ * \param userdata Common userdata passed to all instances of \a func.
+ * \param func Callback function.
+ * \param use_threading If \a true, actually split-execute loop in threads, else just do a sequential forloop
+ * (allows caller to use any kind of test to switch on parallelization or not).
+ *
+ * \note There is no static scheduling here, since it would need another full loop over items to count them...
+ */
+void BLI_task_parallel_listbase(
+ struct ListBase *listbase,
+ void *userdata,
+ TaskParallelListbaseFunc func,
+ const bool use_threading)
+{
+ TaskScheduler *task_scheduler;
+ TaskPool *task_pool;
+ ParallelListState state;
+ int i, num_threads, num_tasks;
+
+ if (BLI_listbase_is_empty(listbase)) {
+ return;
+ }
+
+ if (!use_threading) {
+ i = 0;
+ for (Link *link = listbase->first; link != NULL; link = link->next, ++i) {
+ func(userdata, link, i);
+ }
+ return;
+ }
+
+ task_scheduler = BLI_task_scheduler_get();
+ task_pool = BLI_task_pool_create(task_scheduler, &state);
+ num_threads = BLI_task_scheduler_num_threads(task_scheduler);
+
+ /* The idea here is to prevent creating task for each of the loop iterations
+ * and instead have tasks which are evenly distributed across CPU cores and
+ * pull next iter to be crunched using the queue.
+ */
+ num_tasks = num_threads * 2;
+
+ state.index = 0;
+ state.link = listbase->first;
+ state.userdata = userdata;
+ state.func = func;
+ state.chunk_size = 32;
+ BLI_spin_init(&state.lock);
+
+ for (i = 0; i < num_tasks; i++) {
+ /* Use this pool's pre-allocated tasks. */
+ BLI_task_pool_push_from_thread(task_pool,
+ parallel_listbase_func,
+ NULL, false,
+ TASK_PRIORITY_HIGH, 0);
+ }
+
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
+
+ BLI_spin_end(&state.lock);
+}
diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h
index bf47682297d..c85cf128643 100644
--- a/source/blender/blenloader/BLO_readfile.h
+++ b/source/blender/blenloader/BLO_readfile.h
@@ -100,7 +100,8 @@ struct ID *BLO_library_link_named_part(struct Main *mainl, BlendHandle **bh, con
struct ID *BLO_library_link_named_part_ex(
struct Main *mainl, BlendHandle **bh,
const short idcode, const char *name, const short flag,
- struct Scene *scene, struct View3D *v3d);
+ struct Scene *scene, struct View3D *v3d,
+ const bool use_placeholders, const bool force_indirect);
void BLO_library_link_end(struct Main *mainl, BlendHandle **bh, short flag, struct Scene *scene, struct View3D *v3d);
void BLO_library_link_copypaste(struct Main *mainl, BlendHandle *bh);
diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt
index 8364df38208..8cb9ef837b2 100644
--- a/source/blender/blenloader/CMakeLists.txt
+++ b/source/blender/blenloader/CMakeLists.txt
@@ -35,6 +35,10 @@ set(INC
../nodes
../render/extern/include
../../../intern/guardedalloc
+
+ # for writefile.c: dna_type_offsets.h
+ ${CMAKE_BINARY_DIR}/source/blender/makesdna/intern
+
)
set(INC_SYS
@@ -73,4 +77,14 @@ if(WITH_CODEC_FFMPEG)
add_definitions(-DWITH_FFMPEG)
endif()
+if(WITH_ALEMBIC)
+ list(APPEND INC
+ ../alembic
+ )
+ add_definitions(-DWITH_ALEMBIC)
+endif()
+
blender_add_lib(bf_blenloader "${SRC}" "${INC}" "${INC_SYS}")
+
+# needed so writefile.c can use dna_type_offsets.h
+add_dependencies(bf_blenloader bf_dna)
diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c
index 3cae95d418e..be893177b3b 100644
--- a/source/blender/blenloader/intern/readblenentry.c
+++ b/source/blender/blenloader/intern/readblenentry.c
@@ -411,22 +411,23 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain, const char *filename, MemFil
/* Even though directly used libs have been already moved to new main, indirect ones have not.
* This is a bit annoying, but we have no choice but to keep them all for now - means some now unused
* data may remain in memory, but think we'll have to live with it. */
- Main *libmain;
+ Main *libmain, *libmain_next;
Main *newmain = bfd->main;
ListBase new_mainlist = {newmain, newmain};
- for (libmain = oldmain->next; libmain; libmain = libmain->next) {
+ for (libmain = oldmain->next; libmain; libmain = libmain_next) {
+ libmain_next = libmain->next;
/* Note that LIB_INDIRECT does not work with libraries themselves, so we use non-NULL parent
* to detect indirect-linked ones... */
if (libmain->curlib && (libmain->curlib->parent != NULL)) {
BLI_remlink(&old_mainlist, libmain);
BLI_addtail(&new_mainlist, libmain);
}
-#if 0
else {
+#ifdef PRINT_DEBUG
printf("Dropped Main for lib: %s\n", libmain->curlib->id.name);
- }
#endif
+ }
}
/* In any case, we need to move all lib datablocks themselves - those are 'first level data',
* getting rid of them would imply updating spaces & co to prevent invalid pointers access. */
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index e2d3805831a..0de883fe7bf 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -59,6 +59,7 @@
#include "DNA_actuator_types.h"
#include "DNA_brush_types.h"
#include "DNA_camera_types.h"
+#include "DNA_cachefile_types.h"
#include "DNA_cloth_types.h"
#include "DNA_controller_types.h"
#include "DNA_constraint_types.h"
@@ -114,6 +115,7 @@
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_brush.h"
+#include "BKE_cachefile.h"
#include "BKE_cloth.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
@@ -124,6 +126,7 @@
#include "BKE_global.h" // for G
#include "BKE_group.h"
#include "BKE_library.h" // for which_libbase
+#include "BKE_library_idmap.h"
#include "BKE_library_query.h"
#include "BKE_idcode.h"
#include "BKE_material.h"
@@ -143,7 +146,7 @@
#include "BKE_sequencer.h"
#include "BKE_outliner_treehash.h"
#include "BKE_sound.h"
-
+#include "BKE_colortools.h"
#include "NOD_common.h"
#include "NOD_socket.h"
@@ -159,69 +162,74 @@
#include <errno.h>
-/*
- * Remark: still a weak point is the newaddress() function, that doesnt solve reading from
- * multiple files at the same time
- *
- * (added remark: oh, i thought that was solved? will look at that... (ton)
- *
+/**
* READ
- * - Existing Library (Main) push or free
- * - allocate new Main
+ * ====
+ *
+ * - Existing Library (#Main) push or free
+ * - allocate new #Main
* - load file
- * - read SDNA
+ * - read #SDNA
* - for each LibBlock
- * - read LibBlock
- * - if a Library
- * - make a new Main
- * - attach ID's to it
- * - else
- * - read associated 'direct data'
- * - link direct data (internal and to LibBlock)
- * - read FileGlobal
- * - read USER data, only when indicated (file is ~/X.XX/startup.blend)
+ * - read LibBlock
+ * - if a Library
+ * - make a new #Main
+ * - attach ID's to it
+ * - else
+ * - read associated 'direct data'
+ * - link direct data (internal and to LibBlock)
+ * - read #FileGlobal
+ * - read #USER data, only when indicated (file is ``~/X.XX/startup.blend``)
* - free file
- * - per Library (per Main)
- * - read file
- * - read SDNA
- * - find LibBlocks and attach IDs to Main
- * - if external LibBlock
- * - search all Main's
- * - or it's already read,
- * - or not read yet
- * - or make new Main
- * - per LibBlock
- * - read recursive
- * - read associated direct data
- * - link direct data (internal and to LibBlock)
- * - free file
+ * - per Library (per #Main)
+ * - read file
+ * - read #SDNA
+ * - find LibBlocks and attach #ID's to #Main
+ * - if external LibBlock
+ * - search all #Main's
+ * - or it's already read,
+ * - or not read yet
+ * - or make new #Main
+ * - per LibBlock
+ * - read recursive
+ * - read associated direct data
+ * - link direct data (internal and to LibBlock)
+ * - free file
* - per Library with unread LibBlocks
- * - read file
- * - read SDNA
- * - per LibBlock
- * - read recursive
- * - read associated direct data
- * - link direct data (internal and to LibBlock)
- * - free file
- * - join all Mains
+ * - read file
+ * - read #SDNA
+ * - per LibBlock
+ * - read recursive
+ * - read associated direct data
+ * - link direct data (internal and to LibBlock)
+ * - free file
+ * - join all #Main's
* - link all LibBlocks and indirect pointers to libblocks
- * - initialize FileGlobal and copy pointers to Global
+ * - initialize #FileGlobal and copy pointers to #Global
+ *
+ * \note Still a weak point is the new-address function, that doesnt solve reading from
+ * multiple files at the same time.
+ * (added remark: oh, i thought that was solved? will look at that... (ton).
*/
/* use GHash for BHead name-based lookups (speeds up linking) */
#define USE_GHASH_BHEAD
+/* Use GHash for restoring pointers by name */
+#define USE_GHASH_RESTORE_POINTER
+
/***/
typedef struct OldNew {
- void *old, *newp;
+ const void *old;
+ void *newp;
int nr;
} OldNew;
typedef struct OldNewMap {
OldNew *entries;
int nentries, entriessize;
- int sorted;
+ bool sorted;
int lasthit;
} OldNewMap;
@@ -287,12 +295,13 @@ static int verg_oldnewmap(const void *v1, const void *v2)
static void oldnewmap_sort(FileData *fd)
{
+ BLI_assert(fd->libmap->sorted == false);
qsort(fd->libmap->entries, fd->libmap->nentries, sizeof(OldNew), verg_oldnewmap);
fd->libmap->sorted = 1;
}
/* nr is zero for data, and ID code for libdata */
-static void oldnewmap_insert(OldNewMap *onm, void *oldaddr, void *newaddr, int nr)
+static void oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr, int nr)
{
OldNew *entry;
@@ -309,7 +318,7 @@ static void oldnewmap_insert(OldNewMap *onm, void *oldaddr, void *newaddr, int n
entry->nr = nr;
}
-void blo_do_versions_oldnewmap_insert(OldNewMap *onm, void *oldaddr, void *newaddr, int nr)
+void blo_do_versions_oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr, int nr)
{
oldnewmap_insert(onm, oldaddr, newaddr, nr);
}
@@ -364,7 +373,7 @@ static int oldnewmap_lookup_entry_full(const OldNewMap *onm, const void *addr, i
return -1;
}
-static void *oldnewmap_lookup_and_inc(OldNewMap *onm, void *addr, bool increase_users)
+static void *oldnewmap_lookup_and_inc(OldNewMap *onm, const void *addr, bool increase_users)
{
int i;
@@ -394,7 +403,7 @@ static void *oldnewmap_lookup_and_inc(OldNewMap *onm, void *addr, bool increase_
}
/* for libdata, nr has ID code, no increment */
-static void *oldnewmap_liblookup(OldNewMap *onm, void *addr, void *lib)
+static void *oldnewmap_liblookup(OldNewMap *onm, const void *addr, const void *lib)
{
if (addr == NULL) {
return NULL;
@@ -402,11 +411,8 @@ static void *oldnewmap_liblookup(OldNewMap *onm, void *addr, void *lib)
/* lasthit works fine for non-libdata, linking there is done in same sequence as writing */
if (onm->sorted) {
- OldNew entry_s, *entry;
-
- entry_s.old = addr;
-
- entry = bsearch(&entry_s, onm->entries, onm->nentries, sizeof(OldNew), verg_oldnewmap);
+ const OldNew entry_s = {.old = addr};
+ OldNew *entry = bsearch(&entry_s, onm->entries, onm->nentries, sizeof(OldNew), verg_oldnewmap);
if (entry) {
ID *id = entry->newp;
@@ -486,53 +492,57 @@ void blo_join_main(ListBase *mainlist)
}
}
-static void split_libdata(ListBase *lb, Main *first)
+static void split_libdata(ListBase *lb_src, Main **lib_main_array, const unsigned int lib_main_array_len)
{
- ListBase *lbn;
- ID *id, *idnext;
- Main *mainvar;
-
- id = lb->first;
- while (id) {
+ for (ID *id = lb_src->first, *idnext; id; id = idnext) {
idnext = id->next;
+
if (id->lib) {
- mainvar = first;
- while (mainvar) {
- if (mainvar->curlib == id->lib) {
- lbn= which_libbase(mainvar, GS(id->name));
- BLI_remlink(lb, id);
- BLI_addtail(lbn, id);
- break;
- }
- mainvar = mainvar->next;
+ if (((unsigned int)id->lib->temp_index < lib_main_array_len) &&
+ /* this check should never fail, just incase 'id->lib' is a dangling pointer. */
+ (lib_main_array[id->lib->temp_index]->curlib == id->lib))
+ {
+ Main *mainvar = lib_main_array[id->lib->temp_index];
+ ListBase *lb_dst = which_libbase(mainvar, GS(id->name));
+ BLI_remlink(lb_src, id);
+ BLI_addtail(lb_dst, id);
+ }
+ else {
+ printf("%s: invalid library for '%s'\n", __func__, id->name);
+ BLI_assert(0);
}
- if (mainvar == NULL) printf("error split_libdata\n");
}
- id = idnext;
}
}
void blo_split_main(ListBase *mainlist, Main *main)
{
- ListBase *lbarray[MAX_LIBARRAY];
- Library *lib;
- int i;
-
mainlist->first = mainlist->last = main;
main->next = NULL;
if (BLI_listbase_is_empty(&main->library))
return;
- for (lib = main->library.first; lib; lib = lib->id.next) {
+ /* (Library.temp_index -> Main), lookup table */
+ const unsigned int lib_main_array_len = BLI_listbase_count(&main->library);
+ Main **lib_main_array = MEM_mallocN(lib_main_array_len * sizeof(*lib_main_array), __func__);
+
+ int i = 0;
+ for (Library *lib = main->library.first; lib; lib = lib->id.next, i++) {
Main *libmain = BKE_main_new();
libmain->curlib = lib;
BLI_addtail(mainlist, libmain);
+ lib->temp_index = i;
+ lib_main_array[i] = libmain;
}
+ ListBase *lbarray[MAX_LIBARRAY];
i = set_listbasepointers(main, lbarray);
- while (i--)
- split_libdata(lbarray[i], main->next);
+ while (i--) {
+ split_libdata(lbarray[i], lib_main_array, lib_main_array_len);
+ }
+
+ MEM_freeN(lib_main_array);
}
static void read_file_version(FileData *fd, Main *main)
@@ -871,8 +881,6 @@ static void decode_blender_header(FileData *fd)
if (readsize == sizeof(header)) {
if (STREQLEN(header, "BLENDER", 7)) {
- int remove_this_endian_test = 1;
-
fd->flags |= FD_FLAGS_FILE_OK;
/* what size are pointers in the file ? */
@@ -891,7 +899,7 @@ static void decode_blender_header(FileData *fd)
/* is the file saved in a different endian
* than we need ?
*/
- if (((((char *)&remove_this_endian_test)[0] == 1) ? L_ENDIAN : B_ENDIAN) != ((header[8] == 'v') ? L_ENDIAN : B_ENDIAN)) {
+ if (((header[8] == 'v') ? L_ENDIAN : B_ENDIAN) != ENDIAN_ORDER) {
fd->flags |= FD_FLAGS_SWITCH_ENDIAN;
}
@@ -903,7 +911,10 @@ static void decode_blender_header(FileData *fd)
}
}
-static int read_file_dna(FileData *fd)
+/**
+ * \return Success if the file is read correctly, else set \a r_error_message.
+ */
+static bool read_file_dna(FileData *fd, const char **r_error_message)
{
BHead *bhead;
@@ -911,20 +922,25 @@ static int read_file_dna(FileData *fd)
if (bhead->code == DNA1) {
const bool do_endian_swap = (fd->flags & FD_FLAGS_SWITCH_ENDIAN) != 0;
- fd->filesdna = DNA_sdna_from_data(&bhead[1], bhead->len, do_endian_swap);
+ fd->filesdna = DNA_sdna_from_data(&bhead[1], bhead->len, do_endian_swap, true, r_error_message);
if (fd->filesdna) {
fd->compflags = DNA_struct_get_compareflags(fd->filesdna, fd->memsdna);
/* used to retrieve ID names from (bhead+1) */
fd->id_name_offs = DNA_elem_offset(fd->filesdna, "ID", "char", "name[]");
+
+ return true;
+ }
+ else {
+ return false;
}
- return 1;
}
else if (bhead->code == ENDB)
break;
}
- return 0;
+ *r_error_message = "Missing DNA block";
+ return false;
}
static int *read_file_thumbnail(FileData *fd)
@@ -1066,13 +1082,9 @@ static FileData *filedata_new(void)
fd->filedes = -1;
fd->gzfiledes = NULL;
-
- /* XXX, this doesn't need to be done all the time,
- * but it keeps us re-entrant, remove once we have
- * a lib that provides a nice lock. - zr
- */
- fd->memsdna = DNA_sdna_from_data(DNAstr, DNAlen, false);
-
+
+ fd->memsdna = DNA_sdna_current_get();
+
fd->datamap = oldnewmap_new();
fd->globmap = oldnewmap_new();
fd->libmap = oldnewmap_new();
@@ -1085,8 +1097,11 @@ static FileData *blo_decode_and_check(FileData *fd, ReportList *reports)
decode_blender_header(fd);
if (fd->flags & FD_FLAGS_FILE_OK) {
- if (!read_file_dna(fd)) {
- BKE_reportf(reports, RPT_ERROR, "Failed to read blend file '%s', incomplete", fd->relabase);
+ const char *error_message = NULL;
+ if (read_file_dna(fd, &error_message) == false) {
+ BKE_reportf(reports, RPT_ERROR,
+ "Failed to read blend file '%s': %s",
+ fd->relabase, error_message);
blo_freefiledata(fd);
fd = NULL;
}
@@ -1251,7 +1266,7 @@ void blo_freefiledata(FileData *fd)
}
if (fd->strm.next_in) {
- if (inflateEnd (&fd->strm) != Z_OK) {
+ if (inflateEnd(&fd->strm) != Z_OK) {
printf("close gzip stream error\n");
}
}
@@ -1263,13 +1278,11 @@ void blo_freefiledata(FileData *fd)
// Free all BHeadN data blocks
BLI_freelistN(&fd->listbase);
-
- if (fd->memsdna)
- DNA_sdna_free(fd->memsdna);
+
if (fd->filesdna)
DNA_sdna_free(fd->filesdna);
if (fd->compflags)
- MEM_freeN(fd->compflags);
+ MEM_freeN((void *)fd->compflags);
if (fd->datamap)
oldnewmap_free(fd->datamap);
@@ -1317,6 +1330,7 @@ bool BLO_has_bfile_extension(const char *str)
*
* \param path the full path to explode.
* \param r_dir the string that'll contain path up to blend file itself ('library' path).
+ * WARNING! Must be FILE_MAX_LIBEXTRA long (it also stores group and name strings)!
* \param r_group the string that'll contain 'group' part of the path, if any. May be NULL.
* \param r_name the string that'll contain data's name part of the path, if any. May be NULL.
* \return true if path contains a blend file.
@@ -1413,7 +1427,7 @@ BlendThumbnail *BLO_thumbnail_from_file(const char *filepath)
/* ************** OLD POINTERS ******************* */
-static void *newdataadr(FileData *fd, void *adr) /* only direct databocks */
+static void *newdataadr(FileData *fd, const void *adr) /* only direct databocks */
{
return oldnewmap_lookup_and_inc(fd->datamap, adr, true);
}
@@ -1430,7 +1444,7 @@ static void *newdataadr(FileData *fd, void *adr) /* only direct databocks */
* fcurve group pointer and keeps lasthit optimal for linking all further
* fcurves.
*/
-static void *newdataadr_ex(FileData *fd, void *adr, bool increase_lasthit) /* only direct databocks */
+static void *newdataadr_ex(FileData *fd, const void *adr, bool increase_lasthit) /* only direct databocks */
{
if (increase_lasthit) {
return newdataadr(fd, adr);
@@ -1443,38 +1457,38 @@ static void *newdataadr_ex(FileData *fd, void *adr, bool increase_lasthit) /* o
}
}
-static void *newdataadr_no_us(FileData *fd, void *adr) /* only direct databocks */
+static void *newdataadr_no_us(FileData *fd, const void *adr) /* only direct databocks */
{
return oldnewmap_lookup_and_inc(fd->datamap, adr, false);
}
-static void *newglobadr(FileData *fd, void *adr) /* direct datablocks with global linking */
+static void *newglobadr(FileData *fd, const void *adr) /* direct datablocks with global linking */
{
return oldnewmap_lookup_and_inc(fd->globmap, adr, true);
}
-static void *newimaadr(FileData *fd, void *adr) /* used to restore image data after undo */
+static void *newimaadr(FileData *fd, const void *adr) /* used to restore image data after undo */
{
if (fd->imamap && adr)
return oldnewmap_lookup_and_inc(fd->imamap, adr, true);
return NULL;
}
-static void *newmclipadr(FileData *fd, void *adr) /* used to restore movie clip data after undo */
+static void *newmclipadr(FileData *fd, const void *adr) /* used to restore movie clip data after undo */
{
if (fd->movieclipmap && adr)
return oldnewmap_lookup_and_inc(fd->movieclipmap, adr, true);
return NULL;
}
-static void *newsoundadr(FileData *fd, void *adr) /* used to restore sound data after undo */
+static void *newsoundadr(FileData *fd, const void *adr) /* used to restore sound data after undo */
{
if (fd->soundmap && adr)
return oldnewmap_lookup_and_inc(fd->soundmap, adr, true);
return NULL;
}
-static void *newpackedadr(FileData *fd, void *adr) /* used to restore packed data after undo */
+static void *newpackedadr(FileData *fd, const void *adr) /* used to restore packed data after undo */
{
if (fd->packedmap && adr)
return oldnewmap_lookup_and_inc(fd->packedmap, adr, true);
@@ -1483,17 +1497,17 @@ static void *newpackedadr(FileData *fd, void *adr) /* used to restore packe
}
-static void *newlibadr(FileData *fd, void *lib, void *adr) /* only lib data */
+static void *newlibadr(FileData *fd, const void *lib, const void *adr) /* only lib data */
{
return oldnewmap_liblookup(fd->libmap, adr, lib);
}
-void *blo_do_versions_newlibadr(FileData *fd, void *lib, void *adr) /* only lib data */
+void *blo_do_versions_newlibadr(FileData *fd, const void *lib, const void *adr) /* only lib data */
{
return newlibadr(fd, lib, adr);
}
-static void *newlibadr_us(FileData *fd, void *lib, void *adr) /* increases user number */
+static void *newlibadr_us(FileData *fd, const void *lib, const void *adr) /* increases user number */
{
ID *id = newlibadr(fd, lib, adr);
@@ -1502,15 +1516,27 @@ static void *newlibadr_us(FileData *fd, void *lib, void *adr) /* increases user
return id;
}
-void *blo_do_versions_newlibadr_us(FileData *fd, void *lib, void *adr) /* increases user number */
+void *blo_do_versions_newlibadr_us(FileData *fd, const void *lib, const void *adr) /* increases user number */
{
return newlibadr_us(fd, lib, adr);
}
-static void change_idid_adr_fd(FileData *fd, void *old, void *new)
+static void *newlibadr_real_us(FileData *fd, const void *lib, const void *adr) /* ensures real user */
+{
+ ID *id = newlibadr(fd, lib, adr);
+
+ id_us_ensure_real(id);
+
+ return id;
+}
+
+static void change_idid_adr_fd(FileData *fd, const void *old, void *new)
{
int i;
+ /* use a binary search if we have a sorted libmap, for now it's not needed. */
+ BLI_assert(fd->libmap->sorted == false);
+
for (i = 0; i < fd->libmap->nentries; i++) {
OldNew *entry = &fd->libmap->entries[i];
@@ -1825,7 +1851,7 @@ void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd)
/* ********** END OLD POINTERS ****************** */
/* ********** READ FILE ****************** */
-static void switch_endian_structs(struct SDNA *filesdna, BHead *bhead)
+static void switch_endian_structs(const struct SDNA *filesdna, BHead *bhead)
{
int blocksize, nblocks;
char *data;
@@ -2120,6 +2146,8 @@ static PreviewImage *direct_link_preview_image(FileData *fd, PreviewImage *old_p
}
prv->gputexture[i] = NULL;
}
+ prv->icon_id = 0;
+ prv->tag = 0;
}
return prv;
@@ -2165,9 +2193,10 @@ static void lib_link_brush(FileData *fd, Main *main)
if (brush->id.tag & LIB_TAG_NEED_LINK) {
brush->id.tag &= ~LIB_TAG_NEED_LINK;
+ /* brush->(mask_)mtex.obj is ignored on purpose? */
brush->mtex.tex = newlibadr_us(fd, brush->id.lib, brush->mtex.tex);
brush->mask_mtex.tex = newlibadr_us(fd, brush->id.lib, brush->mask_mtex.tex);
- brush->clone.image = newlibadr_us(fd, brush->id.lib, brush->clone.image);
+ brush->clone.image = newlibadr(fd, brush->id.lib, brush->clone.image);
brush->toggle_brush = newlibadr(fd, brush->id.lib, brush->toggle_brush);
brush->paint_curve = newlibadr_us(fd, brush->id.lib, brush->paint_curve);
}
@@ -2483,6 +2512,12 @@ static void lib_link_action(FileData *fd, Main *main)
// >>> XXX deprecated - old animation system
lib_link_fcurves(fd, &act->id, &act->curves);
+
+ for (TimeMarker *marker = act->markers.first; marker; marker = marker->next) {
+ if (marker->camera) {
+ marker->camera = newlibadr(fd, act->id.lib, marker->camera);
+ }
+ }
}
}
}
@@ -2665,6 +2700,38 @@ static void direct_link_animdata(FileData *fd, AnimData *adt)
adt->actstrip = newdataadr(fd, adt->actstrip);
}
+/* ************ READ CACHEFILES *************** */
+
+static void lib_link_cachefiles(FileData *fd, Main *bmain)
+{
+ CacheFile *cache_file;
+
+ /* only link ID pointers */
+ for (cache_file = bmain->cachefiles.first; cache_file; cache_file = cache_file->id.next) {
+ if (cache_file->id.tag & LIB_TAG_NEED_LINK) {
+ cache_file->id.tag &= ~LIB_TAG_NEED_LINK;
+ }
+
+ BLI_listbase_clear(&cache_file->object_paths);
+ cache_file->handle = NULL;
+ cache_file->handle_mutex = NULL;
+
+ if (cache_file->adt) {
+ lib_link_animdata(fd, &cache_file->id, cache_file->adt);
+ }
+ }
+}
+
+static void direct_link_cachefile(FileData *fd, CacheFile *cache_file)
+{
+ cache_file->handle = NULL;
+ cache_file->handle_mutex = NULL;
+
+ /* relink animdata */
+ cache_file->adt = newdataadr(fd, cache_file->adt);
+ direct_link_animdata(fd, cache_file->adt);
+}
+
/* ************ READ MOTION PATHS *************** */
/* direct data for cache */
@@ -2687,7 +2754,7 @@ static void lib_link_node_socket(FileData *fd, ID *UNUSED(id), bNodeSocket *sock
IDP_LibLinkProperty(sock->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
}
-/* singe node tree (also used for material/scene trees), ntree is not NULL */
+/* Single node tree (also used for material/scene trees), ntree is not NULL */
static void lib_link_ntree(FileData *fd, ID *id, bNodeTree *ntree)
{
bNode *node;
@@ -2730,22 +2797,6 @@ static void lib_link_nodetree(FileData *fd, Main *main)
}
}
-/* get node tree stored locally in other IDs */
-static bNodeTree *nodetree_from_id(ID *id)
-{
- if (!id)
- return NULL;
- switch (GS(id->name)) {
- case ID_SCE: return ((Scene *)id)->nodetree;
- case ID_MA: return ((Material *)id)->nodetree;
- case ID_WO: return ((World *)id)->nodetree;
- case ID_LA: return ((Lamp *)id)->nodetree;
- case ID_TE: return ((Tex *)id)->nodetree;
- case ID_LS: return ((FreestyleLineStyle *)id)->nodetree;
- }
- return NULL;
-}
-
/* updates group node socket identifier so that
* external links to/from the group node are preserved.
*/
@@ -3801,7 +3852,7 @@ static void lib_link_texture(FileData *fd, Main *main)
lib_link_animdata(fd, &tex->id, tex->adt);
tex->ima = newlibadr_us(fd, tex->id.lib, tex->ima);
- tex->ipo = newlibadr_us(fd, tex->id.lib, tex->ipo);
+ tex->ipo = newlibadr_us(fd, tex->id.lib, tex->ipo); // XXX deprecated - old animation system
if (tex->env)
tex->env->object = newlibadr(fd, tex->id.lib, tex->env->object);
if (tex->pd)
@@ -3885,7 +3936,7 @@ static void lib_link_material(FileData *fd, Main *main)
* of library blocks that implement this.*/
IDP_LibLinkProperty(ma->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
- ma->ipo = newlibadr_us(fd, ma->id.lib, ma->ipo);
+ ma->ipo = newlibadr_us(fd, ma->id.lib, ma->ipo); // XXX deprecated - old animation system
ma->group = newlibadr_us(fd, ma->id.lib, ma->group);
for (a = 0; a < MAX_MTEX; a++) {
@@ -3954,7 +4005,7 @@ static void direct_link_pointcache_cb(FileData *fd, void *data)
/* the cache saves non-struct data without DNA */
if (pm->data[i] && ptcache_data_struct[i][0]=='\0' && (fd->flags & FD_FLAGS_SWITCH_ENDIAN)) {
- int tot = (BKE_ptcache_data_size (i) * pm->totpoint) / sizeof(int); /* data_size returns bytes */
+ int tot = (BKE_ptcache_data_size(i) * pm->totpoint) / sizeof(int); /* data_size returns bytes */
int *poin = pm->data[i];
BLI_endian_switch_int32_array(poin, tot);
@@ -4034,13 +4085,18 @@ static void lib_link_particlesettings(FileData *fd, Main *main)
part->dup_group = newlibadr(fd, part->id.lib, part->dup_group);
part->eff_group = newlibadr(fd, part->id.lib, part->eff_group);
part->bb_ob = newlibadr(fd, part->id.lib, part->bb_ob);
+ part->collision_group = newlibadr(fd, part->id.lib, part->collision_group);
lib_link_partdeflect(fd, &part->id, part->pd);
lib_link_partdeflect(fd, &part->id, part->pd2);
- if (part->effector_weights)
+ if (part->effector_weights) {
part->effector_weights->group = newlibadr(fd, part->id.lib, part->effector_weights->group);
-
+ }
+ else {
+ part->effector_weights = BKE_add_effector_weights(part->eff_group);
+ }
+
if (part->dupliweights.first && part->dup_group) {
int index_ok = 0;
/* check for old files without indices (all indexes 0) */
@@ -4060,8 +4116,14 @@ static void lib_link_particlesettings(FileData *fd, Main *main)
if (index_ok) {
/* if we have indexes, let's use them */
for (dw = part->dupliweights.first; dw; dw = dw->next) {
- GroupObject *go = (GroupObject *)BLI_findlink(&part->dup_group->gobject, dw->index);
- dw->ob = go ? go->ob : NULL;
+ /* Do not try to restore pointer here, we have to search for group objects in another
+ * separated step.
+ * Reason is, the used group may be linked from another library, which has not yet
+ * been 'lib_linked'.
+ * Since dw->ob is not considered as an object user (it does not make objet directly linked),
+ * we may have no valid way to retrieve it yet.
+ * See T49273. */
+ dw->ob = NULL;
}
}
else {
@@ -4220,12 +4282,15 @@ static void direct_link_particlesystems(FileData *fd, ListBase *particles)
psys->flag &= ~PSYS_KEYED;
}
-
+
if (psys->particles && psys->particles->boid) {
pa = psys->particles;
pa->boid = newdataadr(fd, pa->boid);
- for (a=1, pa++; a<psys->totpart; a++, pa++)
- pa->boid = (pa-1)->boid + 1;
+ pa->boid->ground = NULL; /* This is purely runtime data, but still can be an issue if left dangling. */
+ for (a = 1, pa++; a < psys->totpart; a++, pa++) {
+ pa->boid = (pa - 1)->boid + 1;
+ pa->boid->ground = NULL;
+ }
}
else if (psys->particles) {
for (a=0, pa=psys->particles; a<psys->totpart; a++, pa++)
@@ -4288,8 +4353,7 @@ static void lib_link_mtface(FileData *fd, Mesh *me, MTFace *mtface, int totface)
* little bogus; it would be better if each mesh consistently added one ref
* to each image it used. - z0r */
for (i = 0; i < totface; i++, tf++) {
- tf->tpage= newlibadr(fd, me->id.lib, tf->tpage);
- id_us_ensure_real(&tf->tpage->id);
+ tf->tpage = newlibadr_real_us(fd, me->id.lib, tf->tpage);
}
}
@@ -4317,8 +4381,7 @@ static void lib_link_customdata_mtpoly(FileData *fd, Mesh *me, CustomData *pdata
int j;
for (j = 0; j < totface; j++, tf++) {
- tf->tpage = newlibadr(fd, me->id.lib, tf->tpage);
- id_us_ensure_real((ID *)tf->tpage);
+ tf->tpage = newlibadr_real_us(fd, me->id.lib, tf->tpage);
}
}
}
@@ -4733,7 +4796,7 @@ static void lib_link_object(FileData *fd, Main *main)
/* Only expand so as not to loose any object materials that might be set. */
if (totcol_data && (*totcol_data > ob->totcol)) {
/* printf("'%s' %d -> %d\n", ob->id.name, ob->totcol, *totcol_data); */
- BKE_material_resize_object(ob, *totcol_data, false);
+ BKE_material_resize_object(main, ob, *totcol_data, false);
}
}
@@ -4868,7 +4931,7 @@ static void lib_link_object(FileData *fd, Main *main)
FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim);
if (fluidmd && fluidmd->fss)
- fluidmd->fss->ipo = newlibadr_us(fd, ob->id.lib, fluidmd->fss->ipo);
+ fluidmd->fss->ipo = newlibadr_us(fd, ob->id.lib, fluidmd->fss->ipo); // XXX deprecated - old animation system
}
{
@@ -4883,8 +4946,11 @@ static void lib_link_object(FileData *fd, Main *main)
if (ob->pd)
lib_link_partdeflect(fd, &ob->id, ob->pd);
- if (ob->soft)
+ if (ob->soft) {
+ ob->soft->collision_group = newlibadr(fd, ob->id.lib, ob->soft->collision_group);
+
ob->soft->effector_weights->group = newlibadr(fd, ob->id.lib, ob->soft->effector_weights->group);
+ }
lib_link_particlesystems(fd, ob, &ob->id, &ob->particlesystem);
lib_link_modifiers(fd, ob);
@@ -4930,6 +4996,9 @@ static void direct_link_pose(FileData *fd, bPose *pose)
pchan->child = newdataadr(fd, pchan->child);
pchan->custom_tx = newdataadr(fd, pchan->custom_tx);
+ pchan->bbone_prev = newdataadr(fd, pchan->bbone_prev);
+ pchan->bbone_next = newdataadr(fd, pchan->bbone_next);
+
direct_link_constraints(fd, &pchan->constraints);
pchan->prop = newdataadr(fd, pchan->prop);
@@ -5131,6 +5200,7 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
collmd->time_x = collmd->time_xnew = -1000;
collmd->mvert_num = 0;
collmd->tri_num = 0;
+ collmd->is_static = false;
collmd->bvhtree = NULL;
collmd->tri = NULL;
@@ -5254,6 +5324,9 @@ static void direct_link_object(FileData *fd, Object *ob)
*/
ob->recalc = 0;
+ /* XXX This should not be needed - but seems like it can happen in some cases, so for now play safe... */
+ ob->proxy_from = NULL;
+
/* loading saved files with editmode enabled works, but for undo we like
* to stay in object mode during undo presses so keep editmode disabled.
*
@@ -5550,7 +5623,6 @@ static void lib_link_scene(FileData *fd, Main *main)
Base *base, *next;
Sequence *seq;
SceneRenderLayer *srl;
- TimeMarker *marker;
FreestyleModuleConfig *fmc;
FreestyleLineSet *fls;
@@ -5602,7 +5674,6 @@ static void lib_link_scene(FileData *fd, Main *main)
for (base = sce->base.first; base; base = next) {
next = base->next;
- /* base->object= newlibadr_us(fd, sce->id.lib, base->object); */
base->object = newlibadr_us(fd, sce->id.lib, base->object);
if (base->object == NULL) {
@@ -5616,7 +5687,7 @@ static void lib_link_scene(FileData *fd, Main *main)
SEQ_BEGIN (sce->ed, seq)
{
- if (seq->ipo) seq->ipo = newlibadr_us(fd, sce->id.lib, seq->ipo);
+ if (seq->ipo) seq->ipo = newlibadr_us(fd, sce->id.lib, seq->ipo); // XXX deprecated - old animation system
seq->scene_sound = NULL;
if (seq->scene) {
seq->scene = newlibadr(fd, sce->id.lib, seq->scene);
@@ -5652,15 +5723,11 @@ static void lib_link_scene(FileData *fd, Main *main)
}
SEQ_END
-#ifdef DURIAN_CAMERA_SWITCH
- for (marker = sce->markers.first; marker; marker = marker->next) {
+ for (TimeMarker *marker = sce->markers.first; marker; marker = marker->next) {
if (marker->camera) {
marker->camera = newlibadr(fd, sce->id.lib, marker->camera);
}
}
-#else
- (void)marker;
-#endif
BKE_sequencer_update_muting(sce->ed);
BKE_sequencer_update_sound_bounds_all(sce);
@@ -5858,6 +5925,22 @@ static void direct_link_scene(FileData *fd, Scene *sce)
sce->toolsettings->wpaint->wpaint_prev = NULL;
sce->toolsettings->wpaint->tot = 0;
}
+ /* relink grease pencil drawing brushes */
+ link_list(fd, &sce->toolsettings->gp_brushes);
+ for (bGPDbrush *brush = sce->toolsettings->gp_brushes.first; brush; brush = brush->next) {
+ brush->cur_sensitivity = newdataadr(fd, brush->cur_sensitivity);
+ if (brush->cur_sensitivity) {
+ direct_link_curvemapping(fd, brush->cur_sensitivity);
+ }
+ brush->cur_strength = newdataadr(fd, brush->cur_strength);
+ if (brush->cur_strength) {
+ direct_link_curvemapping(fd, brush->cur_strength);
+ }
+ brush->cur_jitter = newdataadr(fd, brush->cur_jitter);
+ if (brush->cur_jitter) {
+ direct_link_curvemapping(fd, brush->cur_jitter);
+ }
+ }
}
if (sce->ed) {
@@ -6140,7 +6223,8 @@ static void direct_link_gpencil(FileData *fd, bGPdata *gpd)
bGPDlayer *gpl;
bGPDframe *gpf;
bGPDstroke *gps;
-
+ bGPDpalette *palette;
+
/* we must firstly have some grease-pencil data to link! */
if (gpd == NULL)
return;
@@ -6148,11 +6232,19 @@ static void direct_link_gpencil(FileData *fd, bGPdata *gpd)
/* relink animdata */
gpd->adt = newdataadr(fd, gpd->adt);
direct_link_animdata(fd, gpd->adt);
-
+
+ /* relink palettes */
+ link_list(fd, &gpd->palettes);
+ for (palette = gpd->palettes.first; palette; palette = palette->next) {
+ link_list(fd, &palette->colors);
+ }
+
/* relink layers */
link_list(fd, &gpd->layers);
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* parent */
+ gpl->parent = newlibadr(fd, gpd->id.lib, gpl->parent);
/* relink frames */
link_list(fd, &gpl->frames);
gpl->actframe = newdataadr(fd, gpl->actframe);
@@ -6165,9 +6257,12 @@ static void direct_link_gpencil(FileData *fd, bGPdata *gpd)
gps->points = newdataadr(fd, gps->points);
/* the triangulation is not saved, so need to be recalculated */
- gps->flag |= GP_STROKE_RECALC_CACHES;
gps->triangles = NULL;
gps->tot_triangles = 0;
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ /* the color pointer is not saved, so need to be recalculated using the color name */
+ gps->palcolor = NULL;
+ gps->flag |= GP_STROKE_RECALC_COLOR;
}
}
}
@@ -6256,8 +6351,8 @@ static void lib_link_screen(FileData *fd, Main *main)
else if (sl->spacetype == SPACE_IMAGE) {
SpaceImage *sima = (SpaceImage *)sl;
- sima->image = newlibadr_us(fd, sc->id.lib, sima->image);
- sima->mask_info.mask = newlibadr_us(fd, sc->id.lib, sima->mask_info.mask);
+ sima->image = newlibadr_real_us(fd, sc->id.lib, sima->image);
+ sima->mask_info.mask = newlibadr_real_us(fd, sc->id.lib, sima->mask_info.mask);
/* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data
* so fingers crossed this works fine!
@@ -6324,12 +6419,8 @@ static void lib_link_screen(FileData *fd, Main *main)
snode->id = newlibadr(fd, sc->id.lib, snode->id);
snode->from = newlibadr(fd, sc->id.lib, snode->from);
- ntree = nodetree_from_id(snode->id);
- if (ntree)
- snode->nodetree = ntree;
- else {
- snode->nodetree = newlibadr_us(fd, sc->id.lib, snode->nodetree);
- }
+ ntree = snode->id ? ntreeFromID(snode->id) : NULL;
+ snode->nodetree = ntree ? ntree : newlibadr_us(fd, sc->id.lib, snode->nodetree);
for (path = snode->treepath.first; path; path = path->next) {
if (path == snode->treepath.first) {
@@ -6363,8 +6454,8 @@ static void lib_link_screen(FileData *fd, Main *main)
else if (sl->spacetype == SPACE_CLIP) {
SpaceClip *sclip = (SpaceClip *)sl;
- sclip->clip = newlibadr_us(fd, sc->id.lib, sclip->clip);
- sclip->mask_info.mask = newlibadr_us(fd, sc->id.lib, sclip->mask_info.mask);
+ sclip->clip = newlibadr_real_us(fd, sc->id.lib, sclip->clip);
+ sclip->mask_info.mask = newlibadr_real_us(fd, sc->id.lib, sclip->mask_info.mask);
}
else if (sl->spacetype == SPACE_LOGIC) {
SpaceLogic *slogic = (SpaceLogic *)sl;
@@ -6384,68 +6475,96 @@ typedef enum ePointerUserMode {
USER_REAL = 1, /* ensure at least one real user (fake user ignored) */
} ePointerUserMode;
-static bool restore_pointer(ID *id, ID *newid, ePointerUserMode user)
+static void restore_pointer_user(ID *id, ID *newid, ePointerUserMode user)
{
- if (STREQ(newid->name + 2, id->name + 2)) {
- if (newid->lib == id->lib) {
- if (user == USER_REAL) {
- id_us_ensure_real(newid);
+ BLI_assert(STREQ(newid->name + 2, id->name + 2));
+ BLI_assert(newid->lib == id->lib);
+ UNUSED_VARS_NDEBUG(id);
+
+ if (user == USER_REAL) {
+ id_us_ensure_real(newid);
+ }
+}
+
+#ifndef USE_GHASH_RESTORE_POINTER
+/**
+ * A version of #restore_pointer_by_name that performs a full search (slow!).
+ * Use only for limited lookups, when the overhead of
+ * creating a #IDNameLib_Map for a single lookup isn't worthwhile.
+ */
+static void *restore_pointer_by_name_main(Main *mainp, ID *id, ePointerUserMode user)
+{
+ if (id) {
+ ListBase *lb = which_libbase(mainp, GS(id->name));
+ if (lb) { /* there's still risk of checking corrupt mem (freed Ids in oops) */
+ ID *idn = lb->first;
+ for (; idn; idn = idn->next) {
+ if (STREQ(idn->name + 2, id->name + 2)) {
+ if (idn->lib == id->lib) {
+ restore_pointer_user(id, idn, user);
+ break;
+ }
+ }
}
- return true;
+ return idn;
}
}
- return false;
+ return NULL;
}
+#endif
/**
* Only for undo files, or to restore a screen after reading without UI...
*
- * user
+ * \param user:
* - USER_IGNORE: no usercount change
* - USER_REAL: ensure a real user (even if a fake one is set)
+ * \param id_map: lookup table, use when performing many lookups.
+ * this could be made an optional argument (falling back to a full lookup),
+ * however at the moment it's always available.
*/
-static void *restore_pointer_by_name(Main *mainp, ID *id, ePointerUserMode user)
+static void *restore_pointer_by_name(struct IDNameLib_Map *id_map, ID *id, ePointerUserMode user)
{
+#ifdef USE_GHASH_RESTORE_POINTER
if (id) {
- ListBase *lb = which_libbase(mainp, GS(id->name));
- if (lb) { // there's still risk of checking corrupt mem (freed Ids in oops)
- ID *idn = lb->first;
-
- for (; idn; idn = idn->next) {
- if (restore_pointer(id, idn, user))
- break;
- }
-
- return idn;
+ /* use fast lookup when available */
+ ID *idn = BKE_main_idmap_lookup_id(id_map, id);
+ if (idn) {
+ restore_pointer_user(id, idn, user);
}
+ return idn;
}
return NULL;
+#else
+ Main *mainp = BKE_main_idmap_main_get(id_map);
+ return restore_pointer_by_name_main(mainp, id, user);
+#endif
}
-static void lib_link_seq_clipboard_pt_restore(ID *id, Main *newmain)
+static void lib_link_seq_clipboard_pt_restore(ID *id, struct IDNameLib_Map *id_map)
{
if (id) {
/* clipboard must ensure this */
BLI_assert(id->newid != NULL);
- id->newid = restore_pointer_by_name(newmain, (ID *)id->newid, USER_REAL);
+ id->newid = restore_pointer_by_name(id_map, id->newid, USER_REAL);
}
}
static int lib_link_seq_clipboard_cb(Sequence *seq, void *arg_pt)
{
- Main *newmain = (Main *)arg_pt;
+ struct IDNameLib_Map *id_map = arg_pt;
- lib_link_seq_clipboard_pt_restore((ID *)seq->scene, newmain);
- lib_link_seq_clipboard_pt_restore((ID *)seq->scene_camera, newmain);
- lib_link_seq_clipboard_pt_restore((ID *)seq->clip, newmain);
- lib_link_seq_clipboard_pt_restore((ID *)seq->mask, newmain);
- lib_link_seq_clipboard_pt_restore((ID *)seq->sound, newmain);
+ lib_link_seq_clipboard_pt_restore((ID *)seq->scene, id_map);
+ lib_link_seq_clipboard_pt_restore((ID *)seq->scene_camera, id_map);
+ lib_link_seq_clipboard_pt_restore((ID *)seq->clip, id_map);
+ lib_link_seq_clipboard_pt_restore((ID *)seq->mask, id_map);
+ lib_link_seq_clipboard_pt_restore((ID *)seq->sound, id_map);
return 1;
}
-static void lib_link_clipboard_restore(Main *newmain)
+static void lib_link_clipboard_restore(struct IDNameLib_Map *id_map)
{
/* update IDs stored in sequencer clipboard */
- BKE_sequencer_base_recursive_apply(&seqbase_clipboard, lib_link_seq_clipboard_cb, newmain);
+ BKE_sequencer_base_recursive_apply(&seqbase_clipboard, lib_link_seq_clipboard_cb, id_map);
}
/* called from kernel/blender.c */
@@ -6457,11 +6576,13 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
wmWindowManager *wm;
bScreen *sc;
ScrArea *sa;
-
+
+ struct IDNameLib_Map *id_map = BKE_main_idmap_create(newmain);
+
/* first windowmanager */
for (wm = newmain->wm.first; wm; wm = wm->id.next) {
for (win= wm->windows.first; win; win= win->next) {
- win->screen = restore_pointer_by_name(newmain, (ID *)win->screen, USER_REAL);
+ win->screen = restore_pointer_by_name(id_map, (ID *)win->screen, USER_REAL);
if (win->screen == NULL)
win->screen = curscreen;
@@ -6474,7 +6595,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
for (sc = newmain->screen.first; sc; sc = sc->id.next) {
Scene *oldscene = sc->scene;
- sc->scene= restore_pointer_by_name(newmain, (ID *)sc->scene, USER_REAL);
+ sc->scene= restore_pointer_by_name(id_map, (ID *)sc->scene, USER_REAL);
if (sc->scene == NULL)
sc->scene = curscene;
@@ -6493,16 +6614,16 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
if (v3d->scenelock)
v3d->camera = NULL; /* always get from scene */
else
- v3d->camera = restore_pointer_by_name(newmain, (ID *)v3d->camera, USER_REAL);
+ v3d->camera = restore_pointer_by_name(id_map, (ID *)v3d->camera, USER_REAL);
if (v3d->camera == NULL)
v3d->camera = sc->scene->camera;
- v3d->ob_centre = restore_pointer_by_name(newmain, (ID *)v3d->ob_centre, USER_REAL);
+ v3d->ob_centre = restore_pointer_by_name(id_map, (ID *)v3d->ob_centre, USER_REAL);
for (bgpic= v3d->bgpicbase.first; bgpic; bgpic= bgpic->next) {
- if ((bgpic->ima = restore_pointer_by_name(newmain, (ID *)bgpic->ima, USER_IGNORE))) {
+ if ((bgpic->ima = restore_pointer_by_name(id_map, (ID *)bgpic->ima, USER_IGNORE))) {
id_us_plus((ID *)bgpic->ima);
}
- if ((bgpic->clip = restore_pointer_by_name(newmain, (ID *)bgpic->clip, USER_IGNORE))) {
+ if ((bgpic->clip = restore_pointer_by_name(id_map, (ID *)bgpic->clip, USER_IGNORE))) {
id_us_plus((ID *)bgpic->clip);
}
}
@@ -6546,10 +6667,10 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
bDopeSheet *ads = sipo->ads;
if (ads) {
- ads->source = restore_pointer_by_name(newmain, (ID *)ads->source, USER_REAL);
+ ads->source = restore_pointer_by_name(id_map, (ID *)ads->source, USER_REAL);
if (ads->filter_grp)
- ads->filter_grp = restore_pointer_by_name(newmain, (ID *)ads->filter_grp, USER_IGNORE);
+ ads->filter_grp = restore_pointer_by_name(id_map, (ID *)ads->filter_grp, USER_IGNORE);
}
/* force recalc of list of channels (i.e. includes calculating F-Curve colors)
@@ -6559,7 +6680,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
}
else if (sl->spacetype == SPACE_BUTS) {
SpaceButs *sbuts = (SpaceButs *)sl;
- sbuts->pinid = restore_pointer_by_name(newmain, sbuts->pinid, USER_IGNORE);
+ sbuts->pinid = restore_pointer_by_name(id_map, sbuts->pinid, USER_IGNORE);
if (sbuts->pinid == NULL) {
sbuts->flag &= ~SB_PIN_CONTEXT;
}
@@ -6576,11 +6697,11 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
else if (sl->spacetype == SPACE_ACTION) {
SpaceAction *saction = (SpaceAction *)sl;
- saction->action = restore_pointer_by_name(newmain, (ID *)saction->action, USER_REAL);
- saction->ads.source = restore_pointer_by_name(newmain, (ID *)saction->ads.source, USER_REAL);
+ saction->action = restore_pointer_by_name(id_map, (ID *)saction->action, USER_REAL);
+ saction->ads.source = restore_pointer_by_name(id_map, (ID *)saction->ads.source, USER_REAL);
if (saction->ads.filter_grp)
- saction->ads.filter_grp = restore_pointer_by_name(newmain, (ID *)saction->ads.filter_grp, USER_IGNORE);
+ saction->ads.filter_grp = restore_pointer_by_name(id_map, (ID *)saction->ads.filter_grp, USER_IGNORE);
/* force recalc of list of channels, potentially updating the active action
@@ -6591,23 +6712,26 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
else if (sl->spacetype == SPACE_IMAGE) {
SpaceImage *sima = (SpaceImage *)sl;
- sima->image = restore_pointer_by_name(newmain, (ID *)sima->image, USER_REAL);
+ sima->image = restore_pointer_by_name(id_map, (ID *)sima->image, USER_REAL);
/* this will be freed, not worth attempting to find same scene,
* since it gets initialized later */
sima->iuser.scene = NULL;
- sima->scopes.waveform_1 = NULL;
- sima->scopes.waveform_2 = NULL;
- sima->scopes.waveform_3 = NULL;
- sima->scopes.vecscope = NULL;
+#if 0
+ /* Those are allocated and freed by space code, no need to handle them here. */
+ MEM_SAFE_FREE(sima->scopes.waveform_1);
+ MEM_SAFE_FREE(sima->scopes.waveform_2);
+ MEM_SAFE_FREE(sima->scopes.waveform_3);
+ MEM_SAFE_FREE(sima->scopes.vecscope);
+#endif
sima->scopes.ok = 0;
/* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data
* so assume that here we're doing for undo only...
*/
- sima->gpd = restore_pointer_by_name(newmain, (ID *)sima->gpd, USER_REAL);
- sima->mask_info.mask = restore_pointer_by_name(newmain, (ID *)sima->mask_info.mask, USER_REAL);
+ sima->gpd = restore_pointer_by_name(id_map, (ID *)sima->gpd, USER_REAL);
+ sima->mask_info.mask = restore_pointer_by_name(id_map, (ID *)sima->mask_info.mask, USER_REAL);
}
else if (sl->spacetype == SPACE_SEQ) {
SpaceSeq *sseq = (SpaceSeq *)sl;
@@ -6615,29 +6739,29 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
/* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data
* so assume that here we're doing for undo only...
*/
- sseq->gpd = restore_pointer_by_name(newmain, (ID *)sseq->gpd, USER_REAL);
+ sseq->gpd = restore_pointer_by_name(id_map, (ID *)sseq->gpd, USER_REAL);
}
else if (sl->spacetype == SPACE_NLA) {
SpaceNla *snla = (SpaceNla *)sl;
bDopeSheet *ads = snla->ads;
if (ads) {
- ads->source = restore_pointer_by_name(newmain, (ID *)ads->source, USER_REAL);
+ ads->source = restore_pointer_by_name(id_map, (ID *)ads->source, USER_REAL);
if (ads->filter_grp)
- ads->filter_grp = restore_pointer_by_name(newmain, (ID *)ads->filter_grp, USER_IGNORE);
+ ads->filter_grp = restore_pointer_by_name(id_map, (ID *)ads->filter_grp, USER_IGNORE);
}
}
else if (sl->spacetype == SPACE_TEXT) {
SpaceText *st = (SpaceText *)sl;
- st->text = restore_pointer_by_name(newmain, (ID *)st->text, USER_REAL);
+ st->text = restore_pointer_by_name(id_map, (ID *)st->text, USER_REAL);
if (st->text == NULL) st->text = newmain->text.first;
}
else if (sl->spacetype == SPACE_SCRIPT) {
SpaceScript *scpt = (SpaceScript *)sl;
- scpt->script = restore_pointer_by_name(newmain, (ID *)scpt->script, USER_REAL);
+ scpt->script = restore_pointer_by_name(id_map, (ID *)scpt->script, USER_REAL);
/*sc->script = NULL; - 2.45 set to null, better re-run the script */
if (scpt->script) {
@@ -6647,7 +6771,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
else if (sl->spacetype == SPACE_OUTLINER) {
SpaceOops *so= (SpaceOops *)sl;
- so->search_tse.id = restore_pointer_by_name(newmain, so->search_tse.id, USER_IGNORE);
+ so->search_tse.id = restore_pointer_by_name(id_map, so->search_tse.id, USER_IGNORE);
if (so->treestore) {
TreeStoreElem *tselem;
@@ -6657,7 +6781,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
while ((tselem = BLI_mempool_iterstep(&iter))) {
/* Do not try to restore pointers to drivers/sequence/etc., can crash in undo case! */
if (TSE_IS_REAL_ID(tselem)) {
- tselem->id = restore_pointer_by_name(newmain, tselem->id, USER_IGNORE);
+ tselem->id = restore_pointer_by_name(id_map, tselem->id, USER_IGNORE);
}
else {
tselem->id = NULL;
@@ -6675,14 +6799,11 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
bNodeTree *ntree;
/* node tree can be stored locally in id too, link this first */
- snode->id = restore_pointer_by_name(newmain, snode->id, USER_REAL);
- snode->from = restore_pointer_by_name(newmain, snode->from, USER_IGNORE);
+ snode->id = restore_pointer_by_name(id_map, snode->id, USER_REAL);
+ snode->from = restore_pointer_by_name(id_map, snode->from, USER_IGNORE);
- ntree = nodetree_from_id(snode->id);
- if (ntree)
- snode->nodetree = ntree;
- else
- snode->nodetree = restore_pointer_by_name(newmain, (ID*)snode->nodetree, USER_REAL);
+ ntree = snode->id ? ntreeFromID(snode->id) : NULL;
+ snode->nodetree = ntree ? ntree : restore_pointer_by_name(id_map, (ID *)snode->nodetree, USER_REAL);
for (path = snode->treepath.first; path; path = path->next) {
if (path == snode->treepath.first) {
@@ -6690,7 +6811,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
path->nodetree = snode->nodetree;
}
else
- path->nodetree= restore_pointer_by_name(newmain, (ID*)path->nodetree, USER_REAL);
+ path->nodetree= restore_pointer_by_name(id_map, (ID*)path->nodetree, USER_REAL);
if (!path->nodetree)
break;
@@ -6716,22 +6837,24 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
else if (sl->spacetype == SPACE_CLIP) {
SpaceClip *sclip = (SpaceClip *)sl;
- sclip->clip = restore_pointer_by_name(newmain, (ID *)sclip->clip, USER_REAL);
- sclip->mask_info.mask = restore_pointer_by_name(newmain, (ID *)sclip->mask_info.mask, USER_REAL);
+ sclip->clip = restore_pointer_by_name(id_map, (ID *)sclip->clip, USER_REAL);
+ sclip->mask_info.mask = restore_pointer_by_name(id_map, (ID *)sclip->mask_info.mask, USER_REAL);
sclip->scopes.ok = 0;
}
else if (sl->spacetype == SPACE_LOGIC) {
SpaceLogic *slogic = (SpaceLogic *)sl;
- slogic->gpd = restore_pointer_by_name(newmain, (ID *)slogic->gpd, USER_REAL);
+ slogic->gpd = restore_pointer_by_name(id_map, (ID *)slogic->gpd, USER_REAL);
}
}
}
}
/* update IDs stored in all possible clipboards */
- lib_link_clipboard_restore(newmain);
+ lib_link_clipboard_restore(id_map);
+
+ BKE_main_idmap_destroy(id_map);
}
static void direct_link_region(FileData *fd, ARegion *ar, int spacetype)
@@ -6936,6 +7059,7 @@ static bool direct_link_screen(FileData *fd, bScreen *sc)
/* render can be quite heavy, set to solid on load */
if (v3d->drawtype == OB_RENDER)
v3d->drawtype = OB_SOLID;
+ v3d->prev_drawtype = OB_SOLID;
if (v3d->fx_settings.dof)
v3d->fx_settings.dof = newdataadr(fd, v3d->fx_settings.dof);
@@ -6984,11 +7108,7 @@ static bool direct_link_screen(FileData *fd, bScreen *sc)
}
else if (sl->spacetype == SPACE_IMAGE) {
SpaceImage *sima = (SpaceImage *)sl;
-
- sima->cumap = newdataadr(fd, sima->cumap);
- if (sima->cumap)
- direct_link_curvemapping(fd, sima->cumap);
-
+
sima->iuser.scene = NULL;
sima->iuser.ok = 1;
sima->scopes.waveform_1 = NULL;
@@ -7303,12 +7423,11 @@ static void lib_link_group(FileData *fd, Main *main)
add_us = false;
for (go = group->gobject.first; go; go = go->next) {
- go->ob= newlibadr(fd, group->id.lib, go->ob);
+ go->ob = newlibadr_real_us(fd, group->id.lib, go->ob);
if (go->ob) {
go->ob->flag |= OB_FROMGROUP;
/* if group has an object, it increments user... */
add_us = true;
- id_us_ensure_real(&go->ob->id);
}
}
if (add_us) {
@@ -7383,7 +7502,7 @@ static void direct_link_movieclip(FileData *fd, MovieClip *clip)
clip->tracking_context = NULL;
clip->tracking.stats = NULL;
- clip->tracking.stabilization.ok = 0;
+ /* Needed for proper versioning, will be NULL for all newer files anyway. */
clip->tracking.stabilization.rot_track = newdataadr(fd, clip->tracking.stabilization.rot_track);
clip->tracking.dopesheet.ok = 0;
@@ -7435,6 +7554,7 @@ static void lib_link_movieclip(FileData *fd, Main *main)
for (object = tracking->objects.first; object; object = object->next) {
lib_link_movieTracks(fd, clip, &object->tracks);
+ lib_link_moviePlaneTracks(fd, clip, &object->plane_tracks);
}
clip->id.tag &= ~LIB_TAG_NEED_LINK;
@@ -7848,6 +7968,7 @@ static const char *dataname(short id_code)
case ID_MC: return "Data from MC";
case ID_MSK: return "Data from MSK";
case ID_LS: return "Data from LS";
+ case ID_CF: return "Data from CF";
}
return "Data from Lib Block";
@@ -7880,7 +8001,7 @@ static BHead *read_data_into_oldnewmap(FileData *fd, BHead *bhead, const char *a
return bhead;
}
-static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID **r_id)
+static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short tag, ID **r_id)
{
/* this routine reads a libblock and its direct data. Use link functions to connect it all
*/
@@ -7892,21 +8013,27 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID
/* In undo case, most libs and linked data should be kept as is from previous state (see BLO_read_from_memfile).
* However, some needed by the snapshot being read may have been removed in previous one, and would go missing.
* This leads e.g. to desappearing objects in some undo/redo case, see T34446.
- * That means we have to carefully check whether current lib or libdata already exits in old main, if it does
- * we merely copy it over into new main area, otherwise we have to do a full read of that bhead... */
+ * That means we have to carefully check whether current lib or libdata already exits in old main, if it does
+ * we merely copy it over into new main area, otherwise we have to do a full read of that bhead... */
if (fd->memfile && ELEM(bhead->code, ID_LI, ID_ID)) {
const char *idname = bhead_id_name(fd, bhead);
- /* printf("Checking %s...\n", idname); */
+#ifdef PRINT_DEBUG
+ printf("Checking %s...\n", idname);
+#endif
if (bhead->code == ID_LI) {
Main *libmain = fd->old_mainlist->first;
/* Skip oldmain itself... */
for (libmain = libmain->next; libmain; libmain = libmain->next) {
- /* printf("... against %s: ", libmain->curlib ? libmain->curlib->id.name : "<NULL>"); */
+#ifdef PRINT_DEBUG
+ printf("... against %s: ", libmain->curlib ? libmain->curlib->id.name : "<NULL>");
+#endif
if (libmain->curlib && STREQ(idname, libmain->curlib->id.name)) {
Main *oldmain = fd->old_mainlist->first;
- /* printf("FOUND!\n"); */
+#ifdef PRINT_DEBUG
+ printf("FOUND!\n");
+#endif
/* In case of a library, we need to re-add its main to fd->mainlist, because if we have later
* a missing ID_ID, we need to get the correct lib it is linked to!
* Order is crucial, we cannot bulk-add it in BLO_read_from_memfile() like it used to be... */
@@ -7920,13 +8047,19 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID
}
return blo_nextbhead(fd, bhead);
}
- /* printf("nothing...\n"); */
+#ifdef PRINT_DEBUG
+ printf("nothing...\n");
+#endif
}
}
else {
- /* printf("... in %s (%s): ", main->curlib ? main->curlib->id.name : "<NULL>", main->curlib ? main->curlib->name : "<NULL>"); */
+#ifdef PRINT_DEBUG
+ printf("... in %s (%s): ", main->curlib ? main->curlib->id.name : "<NULL>", main->curlib ? main->curlib->name : "<NULL>");
+#endif
if ((id = BKE_libblock_find_name_ex(main, GS(idname), idname + 2))) {
- /* printf("FOUND!\n"); */
+#ifdef PRINT_DEBUG
+ printf("FOUND!\n");
+#endif
/* Even though we found our linked ID, there is no guarantee its address is still the same... */
if (id != bhead->old) {
oldnewmap_insert(fd->libmap, bhead->old, id, GS(id->name));
@@ -7938,7 +8071,9 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID
}
return blo_nextbhead(fd, bhead);
}
- /* printf("nothing...\n"); */
+#ifdef PRINT_DEBUG
+ printf("nothing...\n");
+#endif
}
}
@@ -7966,7 +8101,7 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID
if (!id)
return blo_nextbhead(fd, bhead);
- id->tag = flag | LIB_TAG_NEED_LINK;
+ id->tag = tag | LIB_TAG_NEED_LINK;
id->lib = main->curlib;
id->us = ID_FAKE_USERS(id);
id->icon_id = 0;
@@ -8085,6 +8220,9 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID
case ID_PC:
direct_link_paint_curve(fd, (PaintCurve *)id);
break;
+ case ID_CF:
+ direct_link_cachefile(fd, (CacheFile *)id);
+ break;
}
oldnewmap_free_unused(fd->datamap);
@@ -8278,6 +8416,7 @@ static void lib_link_all(FileData *fd, Main *main)
lib_link_mask(fd, main);
lib_link_linestyle(fd, main);
lib_link_gpencil(fd, main);
+ lib_link_cachefiles(fd, main);
lib_link_mesh(fd, main); /* as last: tpage images with users at zero */
@@ -8452,7 +8591,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
struct BHeadSort {
BHead *bhead;
- void *old;
+ const void *old;
};
static int verg_bheadsort(const void *v1, const void *v2)
@@ -8731,6 +8870,12 @@ static void expand_action(FileData *fd, Main *mainvar, bAction *act)
/* F-Curves in Action */
expand_fcurves(fd, mainvar, &act->curves);
+
+ for (TimeMarker *marker = act->markers.first; marker; marker = marker->next) {
+ if (marker->camera) {
+ expand_doit(fd, mainvar, marker->camera);
+ }
+ }
}
static void expand_keyingsets(FileData *fd, Main *mainvar, ListBase *list)
@@ -8789,6 +8934,7 @@ static void expand_particlesettings(FileData *fd, Main *mainvar, ParticleSetting
expand_doit(fd, mainvar, part->dup_group);
expand_doit(fd, mainvar, part->eff_group);
expand_doit(fd, mainvar, part->bb_ob);
+ expand_doit(fd, mainvar, part->collision_group);
if (part->adt)
expand_animdata(fd, mainvar, part->adt);
@@ -8799,6 +8945,37 @@ static void expand_particlesettings(FileData *fd, Main *mainvar, ParticleSetting
expand_doit(fd, mainvar, part->mtex[a]->object);
}
}
+
+ if (part->effector_weights) {
+ expand_doit(fd, mainvar, part->effector_weights->group);
+ }
+
+ if (part->pd) {
+ expand_doit(fd, mainvar, part->pd->tex);
+ expand_doit(fd, mainvar, part->pd->f_source);
+ }
+ if (part->pd2) {
+ expand_doit(fd, mainvar, part->pd2->tex);
+ expand_doit(fd, mainvar, part->pd2->f_source);
+ }
+
+ if (part->boids) {
+ BoidState *state;
+ BoidRule *rule;
+
+ for (state = part->boids->states.first; state; state = state->next) {
+ for (rule = state->rules.first; rule; rule = rule->next) {
+ if (rule->type == eBoidRuleType_Avoid) {
+ BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule;
+ expand_doit(fd, mainvar, gabr->ob);
+ }
+ else if (rule->type == eBoidRuleType_FollowLeader) {
+ BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule;
+ expand_doit(fd, mainvar, flbr->ob);
+ }
+ }
+ }
+ }
}
static void expand_group(FileData *fd, Main *mainvar, Group *group)
@@ -9162,7 +9339,7 @@ static void expand_object(FileData *fd, Main *mainvar, Object *ob)
for (psys = ob->particlesystem.first; psys; psys = psys->next)
expand_doit(fd, mainvar, psys->part);
-
+
for (sens = ob->sensors.first; sens; sens = sens->next) {
if (sens->type == SENS_MESSAGE) {
bMessageSensor *ms = sens->data;
@@ -9241,8 +9418,18 @@ static void expand_object(FileData *fd, Main *mainvar, Object *ob)
}
}
- if (ob->pd && ob->pd->tex)
+ if (ob->pd) {
expand_doit(fd, mainvar, ob->pd->tex);
+ expand_doit(fd, mainvar, ob->pd->f_source);
+ }
+
+ if (ob->soft) {
+ expand_doit(fd, mainvar, ob->soft->collision_group);
+
+ if (ob->soft->effector_weights) {
+ expand_doit(fd, mainvar, ob->soft->effector_weights->group);
+ }
+ }
if (ob->rigidbody_constraint) {
expand_doit(fd, mainvar, ob->rigidbody_constraint->ob1);
@@ -9319,17 +9506,11 @@ static void expand_scene(FileData *fd, Main *mainvar, Scene *sce)
expand_doit(fd, mainvar, sce->rigidbody_world->constraints);
}
-#ifdef DURIAN_CAMERA_SWITCH
- {
- TimeMarker *marker;
-
- for (marker = sce->markers.first; marker; marker = marker->next) {
- if (marker->camera) {
- expand_doit(fd, mainvar, marker->camera);
- }
+ for (TimeMarker *marker = sce->markers.first; marker; marker = marker->next) {
+ if (marker->camera) {
+ expand_doit(fd, mainvar, marker->camera);
}
}
-#endif
expand_doit(fd, mainvar, sce->clip);
}
@@ -9342,6 +9523,13 @@ static void expand_camera(FileData *fd, Main *mainvar, Camera *ca)
expand_animdata(fd, mainvar, ca->adt);
}
+static void expand_cachefile(FileData *fd, Main *mainvar, CacheFile *cache_file)
+{
+ if (cache_file->adt) {
+ expand_animdata(fd, mainvar, cache_file->adt);
+ }
+}
+
static void expand_speaker(FileData *fd, Main *mainvar, Speaker *spk)
{
expand_doit(fd, mainvar, spk->sound);
@@ -9537,6 +9725,9 @@ void BLO_expand_main(void *fdhandle, Main *mainvar)
case ID_GD:
expand_gpencil(fd, mainvar, (bGPdata *)id);
break;
+ case ID_CF:
+ expand_cachefile(fd, mainvar, (CacheFile *)id);
+ break;
}
do_it = true;
@@ -9644,16 +9835,16 @@ static void give_base_to_groups(
}
}
-static ID *create_placeholder(Main *mainvar, const char *idname, const short flag)
+static ID *create_placeholder(Main *mainvar, const short idcode, const char *idname, const short tag)
{
- const short idcode = GS(idname);
ListBase *lb = which_libbase(mainvar, idcode);
ID *ph_id = BKE_libblock_alloc_notest(idcode);
- memcpy(ph_id->name, idname, sizeof(ph_id->name));
+ *((short *)ph_id->name) = idcode;
+ BLI_strncpy(ph_id->name + 2, idname, sizeof(ph_id->name) - 2);
BKE_libblock_init_empty(ph_id);
ph_id->lib = mainvar->curlib;
- ph_id->tag = flag | LIB_TAG_MISSING;
+ ph_id->tag = tag | LIB_TAG_MISSING;
ph_id->us = ID_FAKE_USERS(ph_id);
ph_id->icon_id = 0;
@@ -9665,7 +9856,9 @@ static ID *create_placeholder(Main *mainvar, const char *idname, const short fla
/* returns true if the item was found
* but it may already have already been appended/linked */
-static ID *link_named_part(Main *mainl, FileData *fd, const short idcode, const char *name)
+static ID *link_named_part(
+ Main *mainl, FileData *fd, const short idcode, const char *name,
+ const bool use_placeholders, const bool force_indirect)
{
BHead *bhead = find_bhead_from_code_name(fd, idcode, name);
ID *id;
@@ -9676,7 +9869,7 @@ static ID *link_named_part(Main *mainl, FileData *fd, const short idcode, const
id = is_yet_read(fd, mainl, bhead);
if (id == NULL) {
/* not read yet */
- read_libblock(fd, mainl, bhead, LIB_TAG_TESTEXT, &id);
+ read_libblock(fd, mainl, bhead, force_indirect ? LIB_TAG_TESTIND : LIB_TAG_TESTEXT, &id);
if (id) {
/* sort by name in list */
@@ -9689,18 +9882,22 @@ static ID *link_named_part(Main *mainl, FileData *fd, const short idcode, const
if (G.debug)
printf("append: already linked\n");
oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code);
- if (id->tag & LIB_TAG_INDIRECT) {
+ if (!force_indirect && (id->tag & LIB_TAG_INDIRECT)) {
id->tag &= ~LIB_TAG_INDIRECT;
id->tag |= LIB_TAG_EXTERN;
}
}
}
+ else if (use_placeholders) {
+ /* XXX flag part is weak! */
+ id = create_placeholder(mainl, idcode, name, force_indirect ? LIB_TAG_INDIRECT : LIB_TAG_EXTERN);
+ }
else {
id = NULL;
}
/* if we found the id but the id is NULL, this is really bad */
- BLI_assert((bhead != NULL) == (id != NULL));
+ BLI_assert(!((bhead != NULL) && (id == NULL)));
return id;
}
@@ -9772,9 +9969,9 @@ void BLO_library_link_copypaste(Main *mainl, BlendHandle *bh)
static ID *link_named_part_ex(
Main *mainl, FileData *fd, const short idcode, const char *name, const short flag,
- Scene *scene, View3D *v3d)
+ Scene *scene, View3D *v3d, const bool use_placeholders, const bool force_indirect)
{
- ID *id = link_named_part(mainl, fd, idcode, name);
+ ID *id = link_named_part(mainl, fd, idcode, name, use_placeholders, force_indirect);
if (id && (GS(id->name) == ID_OB)) { /* loose object: give a base */
link_object_postprocess(id, scene, v3d, flag);
@@ -9800,7 +9997,7 @@ static ID *link_named_part_ex(
ID *BLO_library_link_named_part(Main *mainl, BlendHandle **bh, const short idcode, const char *name)
{
FileData *fd = (FileData*)(*bh);
- return link_named_part(mainl, fd, idcode, name);
+ return link_named_part(mainl, fd, idcode, name, false, false);
}
/**
@@ -9814,15 +10011,18 @@ ID *BLO_library_link_named_part(Main *mainl, BlendHandle **bh, const short idcod
* \param flag Options for linking, used for instantiating.
* \param scene The scene in which to instantiate objects/groups (if NULL, no instantiation is done).
* \param v3d The active View3D (only to define active layers for instantiated objects & groups, can be NULL).
+ * \param use_placeholders If true, generate a placeholder (empty ID) if not found in current lib file.
+ * \param force_indirect If true, force loaded ID to be tagged as LIB_TAG_INDIRECT (used in reload context only).
* \return the linked ID when found.
*/
ID *BLO_library_link_named_part_ex(
Main *mainl, BlendHandle **bh,
const short idcode, const char *name, const short flag,
- Scene *scene, View3D *v3d)
+ Scene *scene, View3D *v3d,
+ const bool use_placeholders, const bool force_indirect)
{
FileData *fd = (FileData*)(*bh);
- return link_named_part_ex(mainl, fd, idcode, name, flag, scene, v3d);
+ return link_named_part_ex(mainl, fd, idcode, name, flag, scene, v3d, use_placeholders, force_indirect);
}
static void link_id_part(ReportList *reports, FileData *fd, Main *mainvar, ID *id, ID **r_id)
@@ -9862,7 +10062,7 @@ static void link_id_part(ReportList *reports, FileData *fd, Main *mainvar, ID *i
/* Generate a placeholder for this ID (simplified version of read_libblock actually...). */
if (r_id) {
- *r_id = is_valid ? create_placeholder(mainvar, id->name, id->tag) : NULL;
+ *r_id = is_valid ? create_placeholder(mainvar, GS(id->name), id->name + 2, id->tag) : NULL;
}
}
}
@@ -9992,21 +10192,22 @@ void *BLO_library_read_struct(FileData *fd, BHead *bh, const char *blockname)
/* ************* READ LIBRARY ************** */
-static int mainvar_count_libread_blocks(Main *mainvar)
+static int mainvar_id_tag_any_check(Main *mainvar, const short tag)
{
ListBase *lbarray[MAX_LIBARRAY];
- int a, tot = 0;
+ int a;
a = set_listbasepointers(mainvar, lbarray);
while (a--) {
ID *id;
for (id = lbarray[a]->first; id; id = id->next) {
- if (id->tag & LIB_TAG_READ)
- tot++;
+ if (id->tag & tag) {
+ return true;
+ }
}
}
- return tot;
+ return false;
}
static void read_libraries(FileData *basefd, ListBase *mainlist)
@@ -10026,10 +10227,9 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
/* test 1: read libdata */
mainptr= mainl->next;
while (mainptr) {
- int tot = mainvar_count_libread_blocks(mainptr);
-
- // printf("found LIB_TAG_READ %s\n", mainptr->curlib->name);
- if (tot) {
+ if (mainvar_id_tag_any_check(mainptr, LIB_TAG_READ)) {
+ // printf("found LIB_TAG_READ %s\n", mainptr->curlib->name);
+
FileData *fd = mainptr->curlib->filedata;
if (fd == NULL) {
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index f5c19f5ee22..7719aaa2b0d 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -74,8 +74,8 @@ typedef struct FileData {
// general reading variables
struct SDNA *filesdna;
- struct SDNA *memsdna;
- char *compflags; /* array of eSDNA_StructCompare */
+ const struct SDNA *memsdna;
+ const char *compflags; /* array of eSDNA_StructCompare */
int fileversion;
int id_name_offs; /* used to retrieve ID names from (bhead+1) */
@@ -156,9 +156,9 @@ const char *bhead_id_name(const FileData *fd, const BHead *bhead);
void blo_reportf_wrap(struct ReportList *reports, ReportType type, const char *format, ...) ATTR_PRINTF_FORMAT(3, 4);
-void blo_do_versions_oldnewmap_insert(struct OldNewMap *onm, void *oldaddr, void *newaddr, int nr);
-void *blo_do_versions_newlibadr(struct FileData *fd, void *lib, void *adr);
-void *blo_do_versions_newlibadr_us(struct FileData *fd, void *lib, void *adr);
+void blo_do_versions_oldnewmap_insert(struct OldNewMap *onm, const void *oldaddr, void *newaddr, int nr);
+void *blo_do_versions_newlibadr(struct FileData *fd, const void *lib, const void *adr);
+void *blo_do_versions_newlibadr_us(struct FileData *fd, const void *lib, const void *adr);
struct PartEff *blo_do_version_give_parteff_245(struct Object *ob);
void blo_do_version_old_trackto_to_constraints(struct Object *ob);
diff --git a/source/blender/blenloader/intern/undofile.c b/source/blender/blenloader/intern/undofile.c
index d0dc9a88cc0..c191e48a143 100644
--- a/source/blender/blenloader/intern/undofile.c
+++ b/source/blender/blenloader/intern/undofile.c
@@ -80,20 +80,6 @@ void BLO_memfile_merge(MemFile *first, MemFile *second)
BLO_memfile_free(first);
}
-static int my_memcmp(const int *mem1, const int *mem2, const int len)
-{
- register int a = len;
- register const int *mema = mem1;
- register const int *memb = mem2;
-
- while (a--) {
- if (*mema != *memb) return 1;
- mema++;
- memb++;
- }
- return 0;
-}
-
void memfile_chunk_add(MemFile *compare, MemFile *current, const char *buf, unsigned int size)
{
static MemFileChunk *compchunk = NULL;
@@ -118,7 +104,7 @@ void memfile_chunk_add(MemFile *compare, MemFile *current, const char *buf, unsi
/* we compare compchunk with buf */
if (compchunk) {
if (compchunk->size == curchunk->size) {
- if (my_memcmp((int *)compchunk->buf, (const int *)buf, size / 4) == 0) {
+ if (memcmp(compchunk->buf, buf, size) == 0) {
curchunk->buf = compchunk->buf;
curchunk->ident = 1;
}
diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c
index 43ebab7856c..1956a17d57b 100644
--- a/source/blender/blenloader/intern/versioning_250.c
+++ b/source/blender/blenloader/intern/versioning_250.c
@@ -1108,6 +1108,8 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
sce->gm.flag |= GAME_GLSL_NO_NODES;
if (fd->fileflags & G_FILE_GLSL_NO_EXTRA_TEX)
sce->gm.flag |= GAME_GLSL_NO_EXTRA_TEX;
+ if (fd->fileflags & G_FILE_GLSL_NO_ENV_LIGHTING)
+ sce->gm.flag |= GAME_GLSL_NO_ENV_LIGHTING;
if (fd->fileflags & G_FILE_IGNORE_DEPRECATION_WARNINGS)
sce->gm.flag |= GAME_IGNORE_DEPRECATION_WARNINGS;
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index efd167d49d5..14e02c9ffb6 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -34,6 +34,7 @@
/* allow readfile to use deprecated functionality */
#define DNA_DEPRECATED_ALLOW
+#include "DNA_armature_types.h"
#include "DNA_brush_types.h"
#include "DNA_camera_types.h"
#include "DNA_cloth_types.h"
@@ -51,6 +52,7 @@
#include "DNA_linestyle_types.h"
#include "DNA_actuator_types.h"
#include "DNA_view3d_types.h"
+#include "DNA_smoke_types.h"
#include "DNA_genfile.h"
@@ -62,6 +64,8 @@
#include "BKE_scene.h"
#include "BKE_sequencer.h"
#include "BKE_screen.h"
+#include "BKE_tracking.h"
+#include "BKE_gpencil.h"
#include "BLI_math.h"
#include "BLI_listbase.h"
@@ -73,6 +77,23 @@
#include "MEM_guardedalloc.h"
+/**
+ * Setup rotation stabilization from ancient single track spec.
+ * Former Version of 2D stabilization used a single tracking marker to determine the rotation
+ * to be compensated. Now several tracks can contribute to rotation detection and this feature
+ * is enabled by the MovieTrackingTrack#flag on a per track base.
+ */
+static void migrate_single_rot_stabilization_track_settings(MovieTrackingStabilization *stab)
+{
+ if (stab->rot_track) {
+ if (!(stab->rot_track->flag & TRACK_USE_2D_STAB_ROT)) {
+ stab->tot_rot_track++;
+ stab->rot_track->flag |= TRACK_USE_2D_STAB_ROT;
+ }
+ }
+ stab->rot_track = NULL; /* this field is now ignored */
+}
+
static void do_version_constraints_radians_degrees_270_1(ListBase *lb)
{
bConstraint *con;
@@ -161,6 +182,16 @@ static void do_version_action_editor_properties_region(ListBase *regionbase)
}
}
+static void do_version_bones_super_bbone(ListBase *lb)
+{
+ for (Bone *bone = lb->first; bone; bone = bone->next) {
+ bone->scaleIn = 1.0f;
+ bone->scaleOut = 1.0f;
+
+ do_version_bones_super_bbone(&bone->childbase);
+ }
+}
+
void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
{
if (!MAIN_VERSION_ATLEAST(main, 270, 0)) {
@@ -1064,15 +1095,6 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- /* init grease pencil smooth level iterations */
- for (bGPdata *gpd = main->gpencil.first; gpd; gpd = gpd->id.next) {
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- if (gpl->draw_smoothlvl == 0) {
- gpl->draw_smoothlvl = 1;
- }
- }
- }
-
for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) {
for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
@@ -1151,4 +1173,270 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
}
+
+ if (!MAIN_VERSION_ATLEAST(main, 277, 2)) {
+ if (!DNA_struct_elem_find(fd->filesdna, "Bone", "float", "scaleIn")) {
+ for (bArmature *arm = main->armature.first; arm; arm = arm->id.next) {
+ do_version_bones_super_bbone(&arm->bonebase);
+ }
+ }
+ if (!DNA_struct_elem_find(fd->filesdna, "bPoseChannel", "float", "scaleIn")) {
+ for (Object *ob = main->object.first; ob; ob = ob->id.next) {
+ if (ob->pose) {
+ for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ /* see do_version_bones_super_bbone()... */
+ pchan->scaleIn = 1.0f;
+ pchan->scaleOut = 1.0f;
+
+ /* also make sure some legacy (unused for over a decade) flags are unset,
+ * so that we can reuse them for stuff that matters now...
+ * (i.e. POSE_IK_MAT, (unknown/unused x 4), POSE_HAS_IK)
+ *
+ * These seem to have been runtime flags used by the IK solver, but that stuff
+ * should be able to be recalculated automatically anyway, so it should be fine.
+ */
+ pchan->flag &= ~((1 << 3) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8));
+ }
+ }
+ }
+ }
+
+ for (Camera *camera = main->camera.first; camera != NULL; camera = camera->id.next) {
+ if (camera->stereo.pole_merge_angle_from == 0.0f &&
+ camera->stereo.pole_merge_angle_to == 0.0f)
+ {
+ camera->stereo.pole_merge_angle_from = DEG2RADF(60.0f);
+ camera->stereo.pole_merge_angle_to = DEG2RADF(75.0f);
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "NormalEditModifierData", "float", "mix_limit")) {
+ Object *ob;
+
+ for (ob = main->object.first; ob; ob = ob->id.next) {
+ ModifierData *md;
+ for (md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_NormalEdit) {
+ NormalEditModifierData *nemd = (NormalEditModifierData *)md;
+ nemd->mix_limit = DEG2RADF(180.0f);
+ }
+ }
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "BooleanModifierData", "float", "double_threshold")) {
+ Object *ob;
+ for (ob = main->object.first; ob; ob = ob->id.next) {
+ ModifierData *md;
+ for (md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Boolean) {
+ BooleanModifierData *bmd = (BooleanModifierData *)md;
+ bmd->double_threshold = 1e-6f;
+ }
+ }
+ }
+ }
+
+ for (Brush *br = main->brush.first; br; br = br->id.next) {
+ if (br->sculpt_tool == SCULPT_TOOL_FLATTEN) {
+ br->flag |= BRUSH_ACCUMULATE;
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "ClothSimSettings", "float", "time_scale")) {
+ Object *ob;
+ ModifierData *md;
+ for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Cloth) {
+ ClothModifierData *clmd = (ClothModifierData *)md;
+ clmd->sim_parms->time_scale = 1.0f;
+ }
+ else if (md->type == eModifierType_ParticleSystem) {
+ ParticleSystemModifierData *pmd = (ParticleSystemModifierData *)md;
+ if (pmd->psys->clmd) {
+ pmd->psys->clmd->sim_parms->time_scale = 1.0f;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(main, 277, 3)) {
+ /* ------- init of grease pencil initialization --------------- */
+ if (!DNA_struct_elem_find(fd->filesdna, "bGPDstroke", "bGPDpalettecolor", "*palcolor")) {
+ for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ ToolSettings *ts = scene->toolsettings;
+ /* initialize use position for sculpt brushes */
+ ts->gp_sculpt.flag |= GP_BRUSHEDIT_FLAG_APPLY_POSITION;
+ /* initialize selected vertices alpha factor */
+ ts->gp_sculpt.alpha = 1.0f;
+
+ /* new strength sculpt brush */
+ if (ts->gp_sculpt.brush[0].size >= 11) {
+ GP_BrushEdit_Settings *gset = &ts->gp_sculpt;
+ GP_EditBrush_Data *brush;
+
+ brush = &gset->brush[GP_EDITBRUSH_TYPE_STRENGTH];
+ brush->size = 25;
+ brush->strength = 0.5f;
+ brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ }
+ }
+ /* create a default grease pencil drawing brushes set */
+ if (!BLI_listbase_is_empty(&main->gpencil)) {
+ for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ ToolSettings *ts = scene->toolsettings;
+ if (BLI_listbase_is_empty(&ts->gp_brushes)) {
+ BKE_gpencil_brush_init_presets(ts);
+ }
+ }
+ }
+ /* Convert Grease Pencil to new palettes/brushes
+ * Loop all strokes and create the palette and all colors
+ */
+ for (bGPdata *gpd = main->gpencil.first; gpd; gpd = gpd->id.next) {
+ if (BLI_listbase_is_empty(&gpd->palettes)) {
+ /* create palette */
+ bGPDpalette *palette = BKE_gpencil_palette_addnew(gpd, "GP_Palette", true);
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* create color using layer name */
+ bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_addnew(palette, gpl->info, true);
+ if (palcolor != NULL) {
+ /* set color attributes */
+ copy_v4_v4(palcolor->color, gpl->color);
+ copy_v4_v4(palcolor->fill, gpl->fill);
+
+ if (gpl->flag & GP_LAYER_HIDE) palcolor->flag |= PC_COLOR_HIDE;
+ if (gpl->flag & GP_LAYER_LOCKED) palcolor->flag |= PC_COLOR_LOCKED;
+ if (gpl->flag & GP_LAYER_ONIONSKIN) palcolor->flag |= PC_COLOR_ONIONSKIN;
+ if (gpl->flag & GP_LAYER_VOLUMETRIC) palcolor->flag |= PC_COLOR_VOLUMETRIC;
+ if (gpl->flag & GP_LAYER_HQ_FILL) palcolor->flag |= PC_COLOR_HQ_FILL;
+
+ /* set layer opacity to 1 */
+ gpl->opacity = 1.0f;
+
+ /* set tint color */
+ ARRAY_SET_ITEMS(gpl->tintcolor, 0.0f, 0.0f, 0.0f, 0.0f);
+
+ /* flush relevant layer-settings to strokes */
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* set stroke to palette and force recalculation */
+ BLI_strncpy(gps->colorname, gpl->info, sizeof(gps->colorname));
+ gps->palcolor = NULL;
+ gps->flag |= GP_STROKE_RECALC_COLOR;
+ gps->thickness = gpl->thickness;
+
+ /* set alpha strength to 1 */
+ for (int i = 0; i < gps->totpoints; i++) {
+ gps->points[i].strength = 1.0f;
+ }
+ }
+ }
+ }
+
+ /* set thickness to 0 (now it is a factor to override stroke thickness) */
+ gpl->thickness = 0.0f;
+ }
+ /* set first color as active */
+ if (palette->colors.first)
+ BKE_gpencil_palettecolor_setactive(palette, palette->colors.first);
+ }
+ }
+ }
+ /* ------- end of grease pencil initialization --------------- */
+ }
+
+ if (!MAIN_VERSION_ATLEAST(main, 278, 0)) {
+ if (!DNA_struct_elem_find(fd->filesdna, "MovieTrackingTrack", "float", "weight_stab")) {
+ MovieClip *clip;
+ for (clip = main->movieclip.first; clip; clip = clip->id.next) {
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *tracking_object;
+ for (tracking_object = tracking->objects.first;
+ tracking_object != NULL;
+ tracking_object = tracking_object->next)
+ {
+ ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
+ MovieTrackingTrack *track;
+ for (track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ track->weight_stab = track->weight;
+ }
+ }
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "MovieTrackingStabilization", "int", "tot_rot_track")) {
+ MovieClip *clip;
+ for (clip = main->movieclip.first; clip != NULL; clip = clip->id.next) {
+ if (clip->tracking.stabilization.rot_track) {
+ migrate_single_rot_stabilization_track_settings(&clip->tracking.stabilization);
+ }
+ if (clip->tracking.stabilization.scale == 0.0f) {
+ /* ensure init.
+ * Was previously used for autoscale only,
+ * now used always (as "target scale") */
+ clip->tracking.stabilization.scale = 1.0f;
+ }
+ /* blender prefers 1-based frame counting;
+ * thus using frame 1 as reference typically works best */
+ clip->tracking.stabilization.anchor_frame = 1;
+ /* by default show the track lists expanded, to improve "discoverability" */
+ clip->tracking.stabilization.flag |= TRACKING_SHOW_STAB_TRACKS;
+ /* deprecated, not used anymore */
+ clip->tracking.stabilization.ok = false;
+ }
+ }
+ }
+ if (!MAIN_VERSION_ATLEAST(main, 278, 2)) {
+ if (!DNA_struct_elem_find(fd->filesdna, "FFMpegCodecData", "int", "ffmpeg_preset")) {
+ for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ /* "medium" is the preset FFmpeg uses when no presets are given. */
+ scene->r.ffcodecdata.ffmpeg_preset = FFM_PRESET_MEDIUM;
+ }
+ }
+ if (!DNA_struct_elem_find(fd->filesdna, "FFMpegCodecData", "int", "constant_rate_factor")) {
+ for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ /* fall back to behaviour from before we introduced CRF for old files */
+ scene->r.ffcodecdata.constant_rate_factor = FFM_CRF_NONE;
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "SmokeModifierData", "float", "slice_per_voxel")) {
+ Object *ob;
+ ModifierData *md;
+
+ for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Smoke) {
+ SmokeModifierData *smd = (SmokeModifierData *)md;
+ if (smd->domain) {
+ smd->domain->slice_per_voxel = 5.0f;
+ smd->domain->slice_depth = 0.5f;
+ smd->domain->display_thickness = 1.0f;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ {
+ for (Scene *scene = main->scene.first; scene != NULL; scene = scene->id.next) {
+ if (scene->toolsettings != NULL) {
+ ToolSettings *ts = scene->toolsettings;
+ ParticleEditSettings *pset = &ts->particle;
+ for (int a = 0; a < PE_TOT_BRUSH; a++) {
+ if (pset->brush[a].count == 0) {
+ pset->brush[a].count = 10;
+ }
+ }
+ }
+ }
+ }
}
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index ad7a3c5b9c4..99d9e140481 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -108,6 +108,11 @@ void BLO_update_defaults_startup_blend(Main *bmain)
brush->strength = 0.5f;
brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ brush = &gset->brush[GP_EDITBRUSH_TYPE_STRENGTH];
+ brush->size = 25;
+ brush->strength = 0.5f;
+ brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+
brush = &gset->brush[GP_EDITBRUSH_TYPE_GRAB];
brush->size = 50;
brush->strength = 0.3f;
@@ -142,6 +147,7 @@ void BLO_update_defaults_startup_blend(Main *bmain)
ParticleEditSettings *pset = &ts->particle;
for (int a = 0; a < PE_TOT_BRUSH; a++) {
pset->brush[a].strength = 0.5f;
+ pset->brush[a].count = 10;
}
pset->brush[PE_BRUSH_CUT].strength = 1.0f;
}
@@ -256,6 +262,11 @@ void BLO_update_defaults_startup_blend(Main *bmain)
if (br) {
br->alpha = 1.0f;
}
+
+ br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Flatten/Contrast");
+ if (br) {
+ br->flag |= BRUSH_ACCUMULATE;
+ }
}
}
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 92371cefb4c..b02b76118a2 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -29,46 +29,56 @@
*/
-/*
- * FILEFORMAT: IFF-style structure (but not IFF compatible!)
+/**
+ *
+ * FILE FORMAT
+ * ===========
+ *
+ * IFF-style structure (but not IFF compatible!)
*
* start file:
+ * <pre>
* BLENDER_V100 12 bytes (versie 1.00)
* V = big endian, v = little endian
* _ = 4 byte pointer, - = 8 byte pointer
+ * </pre>
*
- * datablocks: also see struct BHead
+ * datablocks: (also see struct #BHead).
+ * <pre>
* <bh.code> 4 chars
* <bh.len> int, len data after BHead
* <bh.old> void, old pointer
* <bh.SDNAnr> int
- * <bh.nr> int, in case of array: amount of structs
+ * <bh.nr> int, in case of array: number of structs
* data
* ...
* ...
+ * </pre>
*
* Almost all data in Blender are structures. Each struct saved
* gets a BHead header. With BHead the struct can be linked again
* and compared with StructDNA .
*
+ *
* WRITE
+ * =====
*
* Preferred writing order: (not really a must, but why would you do it random?)
* Any case: direct data is ALWAYS after the lib block
*
* (Local file data)
* - for each LibBlock
- * - write LibBlock
- * - write associated direct data
+ * - write LibBlock
+ * - write associated direct data
* (External file data)
* - per library
- * - write library block
- * - per LibBlock
- * - write the ID of LibBlock
- * - write TEST (128x128, blend file preview, optional)
- * - write FileGlobal (some global vars)
- * - write SDNA
- * - write USER if filename is ~/X.XX/config/startup.blend
+ * - write library block
+ * - per LibBlock
+ * - write the ID of LibBlock
+ * - write #TEST (#RenderInfo struct. 128x128 blend file preview is optional).
+ * - write #GLOB (#FileGlobal struct) (some global vars).
+ * - write #DNA1 (#SDNA struct)
+ * - write #USER (#UserDef struct) if filename is ``~/X.XX/config/startup.blend``.
*/
@@ -97,6 +107,7 @@
#include "DNA_armature_types.h"
#include "DNA_actuator_types.h"
#include "DNA_brush_types.h"
+#include "DNA_cachefile_types.h"
#include "DNA_camera_types.h"
#include "DNA_cloth_types.h"
#include "DNA_constraint_types.h"
@@ -163,7 +174,7 @@
#include "BKE_mesh.h"
#ifdef USE_NODE_COMPAT_CUSTOMNODES
-#include "NOD_socket.h" /* for sock->default_value data */
+#include "NOD_socket.h" /* for sock->default_value data */
#endif
@@ -174,13 +185,16 @@
#include "readfile.h"
+/* for SDNA_TYPE_FROM_STRUCT() macro */
+#include "dna_type_offsets.h"
+
#include <errno.h>
/* ********* my write, buffered writing with minimum size chunks ************ */
-#define MYWRITE_BUFFER_SIZE 100000
-#define MYWRITE_MAX_CHUNK 32768
-
+/* Use optimal allocation since blocks of this size are kept in memory for undo. */
+#define MYWRITE_BUFFER_SIZE (MEM_SIZE_OPTIMAL(1 << 17)) /* 128kb */
+#define MYWRITE_MAX_CHUNK (MEM_SIZE_OPTIMAL(1 << 15)) /* ~32kb */
/** \name Small API to handle compression.
@@ -290,12 +304,13 @@ static void ww_handle_init(eWriteWrapType ww_type, WriteWrap *r_ww)
typedef struct {
- struct SDNA *sdna;
+ const struct SDNA *sdna;
unsigned char *buf;
MemFile *compare, *current;
-
- int tot, count, error;
+
+ int tot, count;
+ bool error;
/* Wrap writing, so we can use zlib or
* other compression types later, see: G_FILE_COMPRESS
@@ -303,33 +318,32 @@ typedef struct {
WriteWrap *ww;
#ifdef USE_BMESH_SAVE_AS_COMPAT
- char use_mesh_compat; /* option to save with older mesh format */
+ bool use_mesh_compat; /* option to save with older mesh format */
#endif
} WriteData;
static WriteData *writedata_new(WriteWrap *ww)
{
- WriteData *wd= MEM_callocN(sizeof(*wd), "writedata");
-
- /* XXX, see note about this in readfile.c, remove
- * once we have an xp lock - zr
- */
+ WriteData *wd = MEM_callocN(sizeof(*wd), "writedata");
- if (wd == NULL) return NULL;
-
- wd->sdna = DNA_sdna_from_data(DNAstr, DNAlen, false);
+ wd->sdna = DNA_sdna_current_get();
wd->ww = ww;
- wd->buf= MEM_mallocN(MYWRITE_BUFFER_SIZE, "wd->buf");
+ wd->buf = MEM_mallocN(MYWRITE_BUFFER_SIZE, "wd->buf");
return wd;
}
static void writedata_do_write(WriteData *wd, const void *mem, int memlen)
{
- if ((wd == NULL) || wd->error || (mem == NULL) || memlen < 1) return;
- if (wd->error) return;
+ if ((wd == NULL) || wd->error || (mem == NULL) || memlen < 1) {
+ return;
+ }
+
+ if (UNLIKELY(wd->error)) {
+ return;
+ }
/* memory based save */
if (wd->current) {
@@ -337,15 +351,13 @@ static void writedata_do_write(WriteData *wd, const void *mem, int memlen)
}
else {
if (wd->ww->write(wd->ww, mem, memlen) != memlen) {
- wd->error = 1;
+ wd->error = true;
}
}
}
static void writedata_free(WriteData *wd)
{
- DNA_sdna_free(wd->sdna);
-
MEM_freeN(wd->buf);
MEM_freeN(wd);
}
@@ -353,39 +365,46 @@ static void writedata_free(WriteData *wd)
/***/
/**
+ * Flush helps the de-duplicating memory for undo-save by logically segmenting data,
+ * so differences in one part of memory won't cause unrelated data to be duplicated.
+ */
+static void mywrite_flush(WriteData *wd)
+{
+ if (wd->count) {
+ writedata_do_write(wd, wd->buf, wd->count);
+ wd->count = 0;
+ }
+}
+
+/**
* Low level WRITE(2) wrapper that buffers data
* \param adr Pointer to new chunk of data
* \param len Length of new chunk of data
* \warning Talks to other functions with global parameters
*/
-
-#define MYWRITE_FLUSH NULL
-
static void mywrite(WriteData *wd, const void *adr, int len)
{
- if (wd->error) return;
+ if (UNLIKELY(wd->error)) {
+ return;
+ }
- /* flush helps compression for undo-save */
- if (adr==MYWRITE_FLUSH) {
- if (wd->count) {
- writedata_do_write(wd, wd->buf, wd->count);
- wd->count= 0;
- }
+ if (adr == NULL) {
+ BLI_assert(0);
return;
}
- wd->tot+= len;
-
+ wd->tot += len;
+
/* if we have a single big chunk, write existing data in
* buffer and write out big chunk in smaller pieces */
- if (len>MYWRITE_MAX_CHUNK) {
+ if (len > MYWRITE_MAX_CHUNK) {
if (wd->count) {
writedata_do_write(wd, wd->buf, wd->count);
- wd->count= 0;
+ wd->count = 0;
}
do {
- int writelen= MIN2(len, MYWRITE_MAX_CHUNK);
+ int writelen = MIN2(len, MYWRITE_MAX_CHUNK);
writedata_do_write(wd, adr, writelen);
adr = (const char *)adr + writelen;
len -= writelen;
@@ -395,14 +414,14 @@ static void mywrite(WriteData *wd, const void *adr, int len)
}
/* if data would overflow buffer, write out the buffer */
- if (len+wd->count>MYWRITE_BUFFER_SIZE-1) {
+ if (len + wd->count > MYWRITE_BUFFER_SIZE - 1) {
writedata_do_write(wd, wd->buf, wd->count);
- wd->count= 0;
+ wd->count = 0;
}
/* append data at end of buffer */
memcpy(&wd->buf[wd->count], adr, len);
- wd->count+= len;
+ wd->count += len;
}
/**
@@ -414,15 +433,17 @@ static void mywrite(WriteData *wd, const void *adr, int len)
*/
static WriteData *bgnwrite(WriteWrap *ww, MemFile *compare, MemFile *current)
{
- WriteData *wd= writedata_new(ww);
+ WriteData *wd = writedata_new(ww);
- if (wd == NULL) return NULL;
+ if (wd == NULL) {
+ return NULL;
+ }
- wd->compare= compare;
- wd->current= current;
+ wd->compare = compare;
+ wd->current = current;
/* this inits comparing */
memfile_chunk_add(compare, NULL, NULL, 0);
-
+
return wd;
}
@@ -432,16 +453,14 @@ static WriteData *bgnwrite(WriteWrap *ww, MemFile *compare, MemFile *current)
* \return unknown global variable otherwise
* \warning Talks to other functions with global parameters
*/
-static int endwrite(WriteData *wd)
+static bool endwrite(WriteData *wd)
{
- int err;
-
if (wd->count) {
writedata_do_write(wd, wd->buf, wd->count);
- wd->count= 0;
+ wd->count = 0;
}
-
- err= wd->error;
+
+ const bool err = wd->error;
writedata_free(wd);
return err;
@@ -449,51 +468,82 @@ static int endwrite(WriteData *wd)
/* ********** WRITE FILE ****************** */
-static void writestruct_at_address(WriteData *wd, int filecode, const char *structname, int nr, void *adr, void *data)
+static void writestruct_at_address_nr(
+ WriteData *wd, int filecode, const int struct_nr, int nr,
+ const void *adr, const void *data)
{
BHead bh;
const short *sp;
- if (adr==NULL || data==NULL || nr==0) return;
-
- /* init BHead */
- bh.code= filecode;
- bh.old= adr;
- bh.nr= nr;
+ BLI_assert(struct_nr > 0 && struct_nr < SDNA_TYPE_MAX);
- bh.SDNAnr= DNA_struct_find_nr(wd->sdna, structname);
- if (bh.SDNAnr== -1) {
- printf("error: can't find SDNA code <%s>\n", structname);
+ if (adr == NULL || data == NULL || nr == 0) {
return;
}
- sp= wd->sdna->structs[bh.SDNAnr];
- bh.len= nr*wd->sdna->typelens[sp[0]];
+ /* init BHead */
+ bh.code = filecode;
+ bh.old = adr;
+ bh.nr = nr;
+
+ bh.SDNAnr = struct_nr;
+ sp = wd->sdna->structs[bh.SDNAnr];
- if (bh.len==0) return;
+ bh.len = nr * wd->sdna->typelens[sp[0]];
+
+ if (bh.len == 0) {
+ return;
+ }
mywrite(wd, &bh, sizeof(BHead));
mywrite(wd, data, bh.len);
}
-static void writestruct(WriteData *wd, int filecode, const char *structname, int nr, void *adr)
+static void writestruct_at_address_id(
+ WriteData *wd, int filecode, const char *structname, int nr,
+ const void *adr, const void *data)
{
- writestruct_at_address(wd, filecode, structname, nr, adr, adr);
+ if (adr == NULL || data == NULL || nr == 0) {
+ return;
+ }
+
+ const int SDNAnr = DNA_struct_find_nr(wd->sdna, structname);
+ if (UNLIKELY(SDNAnr == -1)) {
+ printf("error: can't find SDNA code <%s>\n", structname);
+ return;
+ }
+
+ writestruct_at_address_nr(wd, filecode, SDNAnr, nr, adr, data);
+}
+
+static void writestruct_nr(
+ WriteData *wd, int filecode, const int struct_nr, int nr,
+ const void *adr)
+{
+ writestruct_at_address_nr(wd, filecode, struct_nr, nr, adr, adr);
+}
+
+static void writestruct_id(
+ WriteData *wd, int filecode, const char *structname, int nr,
+ const void *adr)
+{
+ writestruct_at_address_id(wd, filecode, structname, nr, adr, adr);
}
static void writedata(WriteData *wd, int filecode, int len, const void *adr) /* do not use for structs */
{
BHead bh;
- if (adr==NULL) return;
- if (len==0) return;
+ if (adr == NULL || len == 0) {
+ return;
+ }
/* align to 4 (writes uninitialized bytes in some cases) */
len = (len + 3) & ~3;
/* init BHead */
bh.code = filecode;
- bh.old = (void *)adr; /* this is safe to cast from const */
+ bh.old = adr;
bh.nr = 1;
bh.SDNAnr = 0;
bh.len = len;
@@ -503,68 +553,99 @@ static void writedata(WriteData *wd, int filecode, int len, const void *adr) /*
}
/* use this to force writing of lists in same order as reading (using link_list) */
-static void writelist(WriteData *wd, int filecode, const char *structname, ListBase *lb)
+static void writelist_nr(WriteData *wd, int filecode, const int struct_nr, const ListBase *lb)
{
- Link *link = lb->first;
-
+ const Link *link = lb->first;
+
while (link) {
- writestruct(wd, filecode, structname, 1, link);
+ writestruct_nr(wd, filecode, struct_nr, 1, link);
link = link->next;
}
}
+#if 0
+static void writelist_id(WriteData *wd, int filecode, const char *structname, const ListBase *lb)
+{
+ const Link *link = lb->first;
+ if (link) {
+
+ const int struct_nr = DNA_struct_find_nr(wd->sdna, structname);
+ if (struct_nr == -1) {
+ printf("error: can't find SDNA code <%s>\n", structname);
+ return;
+ }
+
+ while (link) {
+ writestruct_nr(wd, filecode, struct_nr, 1, link);
+ link = link->next;
+ }
+ }
+}
+#endif
+
+#define writestruct_at_address(wd, filecode, struct_id, nr, adr, data) \
+ writestruct_at_address_nr(wd, filecode, SDNA_TYPE_FROM_STRUCT(struct_id), nr, adr, data)
+
+#define writestruct(wd, filecode, struct_id, nr, adr) \
+ writestruct_nr(wd, filecode, SDNA_TYPE_FROM_STRUCT(struct_id), nr, adr)
+
+#define writelist(wd, filecode, struct_id, lb) \
+ writelist_nr(wd, filecode, SDNA_TYPE_FROM_STRUCT(struct_id), lb)
+
/* *************** writing some direct data structs used in more code parts **************** */
/*These functions are used by blender's .blend system for file saving/loading.*/
-void IDP_WriteProperty_OnlyData(IDProperty *prop, void *wd);
-void IDP_WriteProperty(IDProperty *prop, void *wd);
+void IDP_WriteProperty_OnlyData(const IDProperty *prop, void *wd);
+void IDP_WriteProperty(const IDProperty *prop, void *wd);
-static void IDP_WriteArray(IDProperty *prop, void *wd)
+static void IDP_WriteArray(const IDProperty *prop, void *wd)
{
/*REMEMBER to set totalen to len in the linking code!!*/
if (prop->data.pointer) {
writedata(wd, DATA, MEM_allocN_len(prop->data.pointer), prop->data.pointer);
if (prop->subtype == IDP_GROUP) {
- IDProperty **array= prop->data.pointer;
+ IDProperty **array = prop->data.pointer;
int a;
- for (a=0; a<prop->len; a++)
+ for (a = 0; a < prop->len; a++) {
IDP_WriteProperty(array[a], wd);
+ }
}
}
}
-static void IDP_WriteIDPArray(IDProperty *prop, void *wd)
+static void IDP_WriteIDPArray(const IDProperty *prop, void *wd)
{
/*REMEMBER to set totalen to len in the linking code!!*/
if (prop->data.pointer) {
- IDProperty *array = prop->data.pointer;
+ const IDProperty *array = prop->data.pointer;
int a;
- writestruct(wd, DATA, "IDProperty", prop->len, array);
+ writestruct(wd, DATA, IDProperty, prop->len, array);
- for (a=0; a<prop->len; a++)
+ for (a = 0; a < prop->len; a++) {
IDP_WriteProperty_OnlyData(&array[a], wd);
+ }
}
}
-static void IDP_WriteString(IDProperty *prop, void *wd)
+static void IDP_WriteString(const IDProperty *prop, void *wd)
{
/*REMEMBER to set totalen to len in the linking code!!*/
writedata(wd, DATA, prop->len, prop->data.pointer);
}
-static void IDP_WriteGroup(IDProperty *prop, void *wd)
+static void IDP_WriteGroup(const IDProperty *prop, void *wd)
{
IDProperty *loop;
- for (loop=prop->data.group.first; loop; loop=loop->next) {
+ for (loop = prop->data.group.first; loop; loop = loop->next) {
IDP_WriteProperty(loop, wd);
}
}
/* Functions to read/write ID Properties */
-void IDP_WriteProperty_OnlyData(IDProperty *prop, void *wd)
+void IDP_WriteProperty_OnlyData(const IDProperty *prop, void *wd)
{
switch (prop->type) {
case IDP_GROUP:
@@ -582,35 +663,38 @@ void IDP_WriteProperty_OnlyData(IDProperty *prop, void *wd)
}
}
-void IDP_WriteProperty(IDProperty *prop, void *wd)
+void IDP_WriteProperty(const IDProperty *prop, void *wd)
{
- writestruct(wd, DATA, "IDProperty", 1, prop);
+ writestruct(wd, DATA, IDProperty, 1, prop);
IDP_WriteProperty_OnlyData(prop, wd);
}
-static void write_previews(WriteData *wd, PreviewImage *prv)
+static void write_iddata(void *wd, const ID *id)
+{
+ /* ID_WM's id->properties are considered runtime only, and never written in .blend file. */
+ if (id->properties && !ELEM(GS(id->name), ID_WM)) {
+ IDP_WriteProperty(id->properties, wd);
+ }
+}
+
+static void write_previews(WriteData *wd, const PreviewImage *prv_orig)
{
/* Never write previews when doing memsave (i.e. undo/redo)! */
- if (prv && !wd->current) {
- short w = prv->w[1];
- short h = prv->h[1];
- unsigned int *rect = prv->rect[1];
+ if (prv_orig && !wd->current) {
+ PreviewImage prv = *prv_orig;
/* don't write out large previews if not requested */
if (!(U.flag & USER_SAVE_PREVIEWS)) {
- prv->w[1] = 0;
- prv->h[1] = 0;
- prv->rect[1] = NULL;
+ prv.w[1] = 0;
+ prv.h[1] = 0;
+ prv.rect[1] = NULL;
}
- writestruct(wd, DATA, "PreviewImage", 1, prv);
- if (prv->rect[0]) writedata(wd, DATA, prv->w[0] * prv->h[0] * sizeof(unsigned int), prv->rect[0]);
- if (prv->rect[1]) writedata(wd, DATA, prv->w[1] * prv->h[1] * sizeof(unsigned int), prv->rect[1]);
-
- /* restore preview, we still want to keep it in memory even if not saved to file */
- if (!(U.flag & USER_SAVE_PREVIEWS) ) {
- prv->w[1] = w;
- prv->h[1] = h;
- prv->rect[1] = rect;
+ writestruct_at_address(wd, DATA, PreviewImage, 1, prv_orig, &prv);
+ if (prv.rect[0]) {
+ writedata(wd, DATA, prv.w[0] * prv.h[0] * sizeof(unsigned int), prv.rect[0]);
+ }
+ if (prv.rect[1]) {
+ writedata(wd, DATA, prv.w[1] * prv.h[1] * sizeof(unsigned int), prv.rect[1]);
}
}
}
@@ -618,45 +702,47 @@ static void write_previews(WriteData *wd, PreviewImage *prv)
static void write_fmodifiers(WriteData *wd, ListBase *fmodifiers)
{
FModifier *fcm;
-
+
/* Write all modifiers first (for faster reloading) */
- writelist(wd, DATA, "FModifier", fmodifiers);
-
+ writelist(wd, DATA, FModifier, fmodifiers);
+
/* Modifiers */
- for (fcm= fmodifiers->first; fcm; fcm= fcm->next) {
- const FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
-
+ for (fcm = fmodifiers->first; fcm; fcm = fcm->next) {
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
+
/* Write the specific data */
if (fmi && fcm->data) {
/* firstly, just write the plain fmi->data struct */
- writestruct(wd, DATA, fmi->structName, 1, fcm->data);
-
+ writestruct_id(wd, DATA, fmi->structName, 1, fcm->data);
+
/* do any modifier specific stuff */
switch (fcm->type) {
case FMODIFIER_TYPE_GENERATOR:
{
- FMod_Generator *data= (FMod_Generator *)fcm->data;
-
+ FMod_Generator *data = fcm->data;
+
/* write coefficients array */
- if (data->coefficients)
- writedata(wd, DATA, sizeof(float)*(data->arraysize), data->coefficients);
+ if (data->coefficients) {
+ writedata(wd, DATA, sizeof(float) * (data->arraysize), data->coefficients);
+ }
break;
}
case FMODIFIER_TYPE_ENVELOPE:
{
- FMod_Envelope *data= (FMod_Envelope *)fcm->data;
-
+ FMod_Envelope *data = fcm->data;
+
/* write envelope data */
- if (data->data)
- writestruct(wd, DATA, "FCM_EnvelopeData", data->totvert, data->data);
+ if (data->data) {
+ writestruct(wd, DATA, FCM_EnvelopeData, data->totvert, data->data);
+ }
break;
}
case FMODIFIER_TYPE_PYTHON:
{
- FMod_Python *data = (FMod_Python *)fcm->data;
-
+ FMod_Python *data = fcm->data;
+
/* Write ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
IDP_WriteProperty(data->prop, wd);
@@ -671,37 +757,41 @@ static void write_fmodifiers(WriteData *wd, ListBase *fmodifiers)
static void write_fcurves(WriteData *wd, ListBase *fcurves)
{
FCurve *fcu;
-
- writelist(wd, DATA, "FCurve", fcurves);
- for (fcu=fcurves->first; fcu; fcu=fcu->next) {
+
+ writelist(wd, DATA, FCurve, fcurves);
+ for (fcu = fcurves->first; fcu; fcu = fcu->next) {
/* curve data */
- if (fcu->bezt)
- writestruct(wd, DATA, "BezTriple", fcu->totvert, fcu->bezt);
- if (fcu->fpt)
- writestruct(wd, DATA, "FPoint", fcu->totvert, fcu->fpt);
-
- if (fcu->rna_path)
- writedata(wd, DATA, strlen(fcu->rna_path)+1, fcu->rna_path);
-
+ if (fcu->bezt) {
+ writestruct(wd, DATA, BezTriple, fcu->totvert, fcu->bezt);
+ }
+ if (fcu->fpt) {
+ writestruct(wd, DATA, FPoint, fcu->totvert, fcu->fpt);
+ }
+
+ if (fcu->rna_path) {
+ writedata(wd, DATA, strlen(fcu->rna_path) + 1, fcu->rna_path);
+ }
+
/* driver data */
if (fcu->driver) {
- ChannelDriver *driver= fcu->driver;
+ ChannelDriver *driver = fcu->driver;
DriverVar *dvar;
-
- writestruct(wd, DATA, "ChannelDriver", 1, driver);
-
+
+ writestruct(wd, DATA, ChannelDriver, 1, driver);
+
/* variables */
- writelist(wd, DATA, "DriverVar", &driver->variables);
- for (dvar= driver->variables.first; dvar; dvar= dvar->next) {
+ writelist(wd, DATA, DriverVar, &driver->variables);
+ for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
DRIVER_TARGETS_USED_LOOPER(dvar)
{
- if (dtar->rna_path)
- writedata(wd, DATA, strlen(dtar->rna_path)+1, dtar->rna_path);
+ if (dtar->rna_path) {
+ writedata(wd, DATA, strlen(dtar->rna_path) + 1, dtar->rna_path);
+ }
}
DRIVER_TARGETS_LOOPER_END
}
}
-
+
/* write F-Modifiers */
write_fmodifiers(wd, &fcu->modifiers);
}
@@ -709,47 +799,47 @@ static void write_fcurves(WriteData *wd, ListBase *fcurves)
static void write_actions(WriteData *wd, ListBase *idbase)
{
- bAction *act;
+ bAction *act;
bActionGroup *grp;
TimeMarker *marker;
-
- for (act=idbase->first; act; act= act->id.next) {
- if (act->id.us>0 || wd->current) {
- writestruct(wd, ID_AC, "bAction", 1, act);
- if (act->id.properties) IDP_WriteProperty(act->id.properties, wd);
-
+
+ for (act = idbase->first; act; act = act->id.next) {
+ if (act->id.us > 0 || wd->current) {
+ writestruct(wd, ID_AC, bAction, 1, act);
+ write_iddata(wd, &act->id);
+
write_fcurves(wd, &act->curves);
-
- for (grp=act->groups.first; grp; grp=grp->next) {
- writestruct(wd, DATA, "bActionGroup", 1, grp);
+
+ for (grp = act->groups.first; grp; grp = grp->next) {
+ writestruct(wd, DATA, bActionGroup, 1, grp);
}
-
- for (marker=act->markers.first; marker; marker=marker->next) {
- writestruct(wd, DATA, "TimeMarker", 1, marker);
+
+ for (marker = act->markers.first; marker; marker = marker->next) {
+ writestruct(wd, DATA, TimeMarker, 1, marker);
}
}
}
-
- /* flush helps the compression for undo-save */
- mywrite(wd, MYWRITE_FLUSH, 0);
+
+ mywrite_flush(wd);
}
static void write_keyingsets(WriteData *wd, ListBase *list)
{
KeyingSet *ks;
KS_Path *ksp;
-
- for (ks= list->first; ks; ks= ks->next) {
+
+ for (ks = list->first; ks; ks = ks->next) {
/* KeyingSet */
- writestruct(wd, DATA, "KeyingSet", 1, ks);
-
+ writestruct(wd, DATA, KeyingSet, 1, ks);
+
/* Paths */
- for (ksp= ks->paths.first; ksp; ksp= ksp->next) {
+ for (ksp = ks->paths.first; ksp; ksp = ksp->next) {
/* Path */
- writestruct(wd, DATA, "KS_Path", 1, ksp);
-
- if (ksp->rna_path)
- writedata(wd, DATA, strlen(ksp->rna_path)+1, ksp->rna_path);
+ writestruct(wd, DATA, KS_Path, 1, ksp);
+
+ if (ksp->rna_path) {
+ writedata(wd, DATA, strlen(ksp->rna_path) + 1, ksp->rna_path);
+ }
}
}
}
@@ -757,13 +847,13 @@ static void write_keyingsets(WriteData *wd, ListBase *list)
static void write_nlastrips(WriteData *wd, ListBase *strips)
{
NlaStrip *strip;
-
- writelist(wd, DATA, "NlaStrip", strips);
- for (strip= strips->first; strip; strip= strip->next) {
+
+ writelist(wd, DATA, NlaStrip, strips);
+ for (strip = strips->first; strip; strip = strip->next) {
/* write the strip's F-Curves and modifiers */
write_fcurves(wd, &strip->fcurves);
write_fmodifiers(wd, &strip->modifiers);
-
+
/* write the strip's children */
write_nlastrips(wd, &strip->strips);
}
@@ -772,12 +862,12 @@ static void write_nlastrips(WriteData *wd, ListBase *strips)
static void write_nladata(WriteData *wd, ListBase *nlabase)
{
NlaTrack *nlt;
-
+
/* write all the tracks */
- for (nlt= nlabase->first; nlt; nlt= nlt->next) {
+ for (nlt = nlabase->first; nlt; nlt = nlt->next) {
/* write the track first */
- writestruct(wd, DATA, "NlaTrack", 1, nlt);
-
+ writestruct(wd, DATA, NlaTrack, 1, nlt);
+
/* write the track's strips */
write_nlastrips(wd, &nlt->strips);
}
@@ -786,38 +876,37 @@ static void write_nladata(WriteData *wd, ListBase *nlabase)
static void write_animdata(WriteData *wd, AnimData *adt)
{
AnimOverride *aor;
-
+
/* firstly, just write the AnimData block */
- writestruct(wd, DATA, "AnimData", 1, adt);
-
+ writestruct(wd, DATA, AnimData, 1, adt);
+
/* write drivers */
write_fcurves(wd, &adt->drivers);
-
+
/* write overrides */
// FIXME: are these needed?
- for (aor= adt->overrides.first; aor; aor= aor->next) {
+ for (aor = adt->overrides.first; aor; aor = aor->next) {
/* overrides consist of base data + rna_path */
- writestruct(wd, DATA, "AnimOverride", 1, aor);
- writedata(wd, DATA, strlen(aor->rna_path)+1, aor->rna_path);
+ writestruct(wd, DATA, AnimOverride, 1, aor);
+ writedata(wd, DATA, strlen(aor->rna_path) + 1, aor->rna_path);
}
-
+
// TODO write the remaps (if they are needed)
-
+
/* write NLA data */
write_nladata(wd, &adt->nla_tracks);
}
static void write_curvemapping_curves(WriteData *wd, CurveMapping *cumap)
{
- int a;
-
- for (a = 0; a < CM_TOT; a++)
- writestruct(wd, DATA, "CurveMapPoint", cumap->cm[a].totpoint, cumap->cm[a].curve);
+ for (int a = 0; a < CM_TOT; a++) {
+ writestruct(wd, DATA, CurveMapPoint, cumap->cm[a].totpoint, cumap->cm[a].curve);
+ }
}
static void write_curvemapping(WriteData *wd, CurveMapping *cumap)
{
- writestruct(wd, DATA, "CurveMapping", 1, cumap);
+ writestruct(wd, DATA, CurveMapping, 1, cumap);
write_curvemapping_curves(wd, cumap);
}
@@ -827,14 +916,14 @@ static void write_node_socket(WriteData *wd, bNodeTree *UNUSED(ntree), bNode *no
#ifdef USE_NODE_COMPAT_CUSTOMNODES
/* forward compatibility code, so older blenders still open */
sock->stack_type = 1;
-
+
if (node->type == NODE_GROUP) {
bNodeTree *ngroup = (bNodeTree *)node->id;
if (ngroup) {
/* for node groups: look up the deprecated groupsock pointer */
sock->groupsock = ntreeFindSocketInterface(ngroup, sock->in_out, sock->identifier);
BLI_assert(sock->groupsock != NULL);
-
+
/* node group sockets now use the generic identifier string to verify group nodes,
* old blender uses the own_index.
*/
@@ -844,20 +933,22 @@ static void write_node_socket(WriteData *wd, bNodeTree *UNUSED(ntree), bNode *no
#endif
/* actual socket writing */
- writestruct(wd, DATA, "bNodeSocket", 1, sock);
+ writestruct(wd, DATA, bNodeSocket, 1, sock);
- if (sock->prop)
+ if (sock->prop) {
IDP_WriteProperty(sock->prop, wd);
-
- if (sock->default_value)
+ }
+
+ if (sock->default_value) {
writedata(wd, DATA, MEM_allocN_len(sock->default_value), sock->default_value);
+ }
}
static void write_node_socket_interface(WriteData *wd, bNodeTree *UNUSED(ntree), bNodeSocket *sock)
{
#ifdef USE_NODE_COMPAT_CUSTOMNODES
/* forward compatibility code, so older blenders still open */
sock->stack_type = 1;
-
+
/* Reconstruct the deprecated default_value structs in socket interface DNA. */
if (sock->default_value == NULL && sock->typeinfo) {
node_socket_init_default_value(sock);
@@ -865,13 +956,15 @@ static void write_node_socket_interface(WriteData *wd, bNodeTree *UNUSED(ntree),
#endif
/* actual socket writing */
- writestruct(wd, DATA, "bNodeSocket", 1, sock);
+ writestruct(wd, DATA, bNodeSocket, 1, sock);
- if (sock->prop)
+ if (sock->prop) {
IDP_WriteProperty(sock->prop, wd);
-
- if (sock->default_value)
+ }
+
+ if (sock->default_value) {
writedata(wd, DATA, MEM_allocN_len(sock->default_value), sock->default_value);
+ }
}
/* this is only direct data, tree itself should have been written */
static void write_nodetree(WriteData *wd, bNodeTree *ntree)
@@ -879,42 +972,50 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree)
bNode *node;
bNodeSocket *sock;
bNodeLink *link;
-
+
/* for link_list() speed, we write per list */
-
- if (ntree->adt) write_animdata(wd, ntree->adt);
-
+
+ if (ntree->adt) {
+ write_animdata(wd, ntree->adt);
+ }
+
for (node = ntree->nodes.first; node; node = node->next) {
- writestruct(wd, DATA, "bNode", 1, node);
+ writestruct(wd, DATA, bNode, 1, node);
- if (node->prop)
+ if (node->prop) {
IDP_WriteProperty(node->prop, wd);
+ }
- for (sock= node->inputs.first; sock; sock= sock->next)
+ for (sock = node->inputs.first; sock; sock = sock->next) {
write_node_socket(wd, ntree, node, sock);
- for (sock= node->outputs.first; sock; sock= sock->next)
+ }
+ for (sock = node->outputs.first; sock; sock = sock->next) {
write_node_socket(wd, ntree, node, sock);
-
- for (link = node->internal_links.first; link; link = link->next)
- writestruct(wd, DATA, "bNodeLink", 1, link);
+ }
+
+ for (link = node->internal_links.first; link; link = link->next) {
+ writestruct(wd, DATA, bNodeLink, 1, link);
+ }
+
if (node->storage) {
/* could be handlerized at some point, now only 1 exception still */
if (ntree->type==NTREE_SHADER) {
- if (node->type==SH_NODE_CURVE_VEC || node->type==SH_NODE_CURVE_RGB)
+ if (ELEM(node->type, SH_NODE_CURVE_VEC, SH_NODE_CURVE_RGB)) {
write_curvemapping(wd, node->storage);
+ }
else if (node->type==SH_NODE_SCRIPT) {
NodeShaderScript *nss = (NodeShaderScript *)node->storage;
if (nss->bytecode)
writedata(wd, DATA, strlen(nss->bytecode)+1, nss->bytecode);
- writestruct(wd, DATA, node->typeinfo->storagename, 1, node->storage);
+ writestruct_id(wd, DATA, node->typeinfo->storagename, 1, node->storage);
}
else if (node->type==SH_NODE_OPENVDB) {
NodeShaderOpenVDB *vdb = (NodeShaderOpenVDB *)node->storage;
- writelist(wd, DATA, "OpenVDBGridInfo", &vdb->grid_info);
- writestruct(wd, DATA, node->typeinfo->storagename, 1, node->storage);
+ writelist(wd, DATA, OpenVDBGridInfo, &vdb->grid_info);
+ writestruct_id(wd, DATA, node->typeinfo->storagename, 1, node->storage);
}
else
- writestruct(wd, DATA, node->typeinfo->storagename, 1, node->storage);
+ writestruct_id(wd, DATA, node->typeinfo->storagename, 1, node->storage);
}
else if (ntree->type==NTREE_COMPOSIT) {
if (ELEM(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT))
@@ -923,35 +1024,40 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree)
/* pass */
}
else
- writestruct(wd, DATA, node->typeinfo->storagename, 1, node->storage);
+ writestruct_id(wd, DATA, node->typeinfo->storagename, 1, node->storage);
}
else if (ntree->type==NTREE_TEXTURE) {
if (node->type==TEX_NODE_CURVE_RGB || node->type==TEX_NODE_CURVE_TIME)
write_curvemapping(wd, node->storage);
else
- writestruct(wd, DATA, node->typeinfo->storagename, 1, node->storage);
+ writestruct_id(wd, DATA, node->typeinfo->storagename, 1, node->storage);
}
}
-
- if (node->type==CMP_NODE_OUTPUT_FILE) {
+
+ if (node->type == CMP_NODE_OUTPUT_FILE) {
/* inputs have own storage data */
- for (sock = node->inputs.first; sock; sock = sock->next)
- writestruct(wd, DATA, "NodeImageMultiFileSocket", 1, sock->storage);
+ for (sock = node->inputs.first; sock; sock = sock->next) {
+ writestruct(wd, DATA, NodeImageMultiFileSocket, 1, sock->storage);
+ }
}
- if (node->type==CMP_NODE_IMAGE) {
+ if (node->type == CMP_NODE_IMAGE) {
/* write extra socket info */
- for (sock = node->outputs.first; sock; sock = sock->next)
- writestruct(wd, DATA, "NodeImageLayer", 1, sock->storage);
+ for (sock = node->outputs.first; sock; sock = sock->next) {
+ writestruct(wd, DATA, NodeImageLayer, 1, sock->storage);
+ }
}
}
-
- for (link= ntree->links.first; link; link= link->next)
- writestruct(wd, DATA, "bNodeLink", 1, link);
-
- for (sock = ntree->inputs.first; sock; sock = sock->next)
+
+ for (link = ntree->links.first; link; link = link->next) {
+ writestruct(wd, DATA, bNodeLink, 1, link);
+ }
+
+ for (sock = ntree->inputs.first; sock; sock = sock->next) {
write_node_socket_interface(wd, ntree, sock);
- for (sock = ntree->outputs.first; sock; sock = sock->next)
+ }
+ for (sock = ntree->outputs.first; sock; sock = sock->next) {
write_node_socket_interface(wd, ntree, sock);
+ }
}
/**
@@ -1006,9 +1112,11 @@ static void write_renderinfo(WriteData *wd, Main *mainvar)
/* XXX in future, handle multiple windows with multiple screens? */
current_screen_compat(mainvar, &curscreen, false);
- if (curscreen) curscene = curscreen->scene;
-
- for (sce= mainvar->scene.first; sce; sce= sce->id.next) {
+ if (curscreen) {
+ curscene = curscreen->scene;
+ }
+
+ for (sce = mainvar->scene.first; sce; sce = sce->id.next) {
if (sce->id.lib == NULL && (sce == curscene || (sce->r.scemode & R_BG_RENDER))) {
data.sfra = sce->r.sfra;
data.efra = sce->r.efra;
@@ -1023,9 +1131,10 @@ static void write_renderinfo(WriteData *wd, Main *mainvar)
static void write_keymapitem(WriteData *wd, wmKeyMapItem *kmi)
{
- writestruct(wd, DATA, "wmKeyMapItem", 1, kmi);
- if (kmi->properties)
+ writestruct(wd, DATA, wmKeyMapItem, 1, kmi);
+ if (kmi->properties) {
IDP_WriteProperty(kmi->properties, wd);
+ }
}
static void write_userdef(WriteData *wd)
@@ -1037,75 +1146,82 @@ static void write_userdef(WriteData *wd)
bAddon *bext;
bPathCompare *path_cmp;
uiStyle *style;
-
- writestruct(wd, USER, "UserDef", 1, &U);
- for (btheme= U.themes.first; btheme; btheme=btheme->next)
- writestruct(wd, DATA, "bTheme", 1, btheme);
+ writestruct(wd, USER, UserDef, 1, &U);
- for (keymap= U.user_keymaps.first; keymap; keymap=keymap->next) {
- writestruct(wd, DATA, "wmKeyMap", 1, keymap);
+ for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+ writestruct(wd, DATA, bTheme, 1, btheme);
+ }
- for (kmdi=keymap->diff_items.first; kmdi; kmdi=kmdi->next) {
- writestruct(wd, DATA, "wmKeyMapDiffItem", 1, kmdi);
- if (kmdi->remove_item)
+ for (keymap = U.user_keymaps.first; keymap; keymap = keymap->next) {
+ writestruct(wd, DATA, wmKeyMap, 1, keymap);
+
+ for (kmdi = keymap->diff_items.first; kmdi; kmdi = kmdi->next) {
+ writestruct(wd, DATA, wmKeyMapDiffItem, 1, kmdi);
+ if (kmdi->remove_item) {
write_keymapitem(wd, kmdi->remove_item);
- if (kmdi->add_item)
+ }
+ if (kmdi->add_item) {
write_keymapitem(wd, kmdi->add_item);
+ }
}
- for (kmi=keymap->items.first; kmi; kmi=kmi->next)
+ for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
write_keymapitem(wd, kmi);
+ }
}
- for (bext= U.addons.first; bext; bext=bext->next) {
- writestruct(wd, DATA, "bAddon", 1, bext);
+ for (bext = U.addons.first; bext; bext = bext->next) {
+ writestruct(wd, DATA, bAddon, 1, bext);
if (bext->prop) {
IDP_WriteProperty(bext->prop, wd);
}
}
for (path_cmp = U.autoexec_paths.first; path_cmp; path_cmp = path_cmp->next) {
- writestruct(wd, DATA, "bPathCompare", 1, path_cmp);
+ writestruct(wd, DATA, bPathCompare, 1, path_cmp);
}
-
- for (style= U.uistyles.first; style; style= style->next) {
- writestruct(wd, DATA, "uiStyle", 1, style);
+
+ for (style = U.uistyles.first; style; style = style->next) {
+ writestruct(wd, DATA, uiStyle, 1, style);
}
}
static void write_boid_state(WriteData *wd, BoidState *state)
{
BoidRule *rule = state->rules.first;
- //BoidCondition *cond = state->conditions.first;
- writestruct(wd, DATA, "BoidState", 1, state);
+ writestruct(wd, DATA, BoidState, 1, state);
- for (; rule; rule=rule->next) {
+ for (; rule; rule = rule->next) {
switch (rule->type) {
case eBoidRuleType_Goal:
case eBoidRuleType_Avoid:
- writestruct(wd, DATA, "BoidRuleGoalAvoid", 1, rule);
+ writestruct(wd, DATA, BoidRuleGoalAvoid, 1, rule);
break;
case eBoidRuleType_AvoidCollision:
- writestruct(wd, DATA, "BoidRuleAvoidCollision", 1, rule);
+ writestruct(wd, DATA, BoidRuleAvoidCollision, 1, rule);
break;
case eBoidRuleType_FollowLeader:
- writestruct(wd, DATA, "BoidRuleFollowLeader", 1, rule);
+ writestruct(wd, DATA, BoidRuleFollowLeader, 1, rule);
break;
case eBoidRuleType_AverageSpeed:
- writestruct(wd, DATA, "BoidRuleAverageSpeed", 1, rule);
+ writestruct(wd, DATA, BoidRuleAverageSpeed, 1, rule);
break;
case eBoidRuleType_Fight:
- writestruct(wd, DATA, "BoidRuleFight", 1, rule);
+ writestruct(wd, DATA, BoidRuleFight, 1, rule);
break;
default:
- writestruct(wd, DATA, "BoidRule", 1, rule);
+ writestruct(wd, DATA, BoidRule, 1, rule);
break;
}
}
- //for (; cond; cond=cond->next)
- // writestruct(wd, DATA, "BoidCondition", 1, cond);
+#if 0
+ BoidCondition *cond = state->conditions.first;
+ for (; cond; cond = cond->next) {
+ writestruct(wd, DATA, BoidCondition, 1, cond);
+ }
+#endif
}
/* update this also to readfile.c */
@@ -1128,31 +1244,34 @@ static void write_pointcaches(WriteData *wd, ListBase *ptcaches)
PointCache *cache = ptcaches->first;
int i;
- for (; cache; cache=cache->next) {
- writestruct(wd, DATA, "PointCache", 1, cache);
+ for (; cache; cache = cache->next) {
+ writestruct(wd, DATA, PointCache, 1, cache);
- if ((cache->flag & PTCACHE_DISK_CACHE)==0) {
+ if ((cache->flag & PTCACHE_DISK_CACHE) == 0) {
PTCacheMem *pm = cache->mem_cache.first;
- for (; pm; pm=pm->next) {
+ for (; pm; pm = pm->next) {
PTCacheExtra *extra = pm->extradata.first;
- writestruct(wd, DATA, "PTCacheMem", 1, pm);
-
- for (i=0; i<BPHYS_TOT_DATA; i++) {
- if (pm->data[i] && pm->data_types & (1<<i)) {
- if (ptcache_data_struct[i][0] == '\0')
+ writestruct(wd, DATA, PTCacheMem, 1, pm);
+
+ for (i = 0; i < BPHYS_TOT_DATA; i++) {
+ if (pm->data[i] && pm->data_types & (1 << i)) {
+ if (ptcache_data_struct[i][0] == '\0') {
writedata(wd, DATA, MEM_allocN_len(pm->data[i]), pm->data[i]);
- else
- writestruct(wd, DATA, ptcache_data_struct[i], pm->totpoint, pm->data[i]);
+ }
+ else {
+ writestruct_id(wd, DATA, ptcache_data_struct[i], pm->totpoint, pm->data[i]);
+ }
}
}
- for (; extra; extra=extra->next) {
- if (ptcache_extra_struct[extra->type][0] == '\0')
+ for (; extra; extra = extra->next) {
+ if (ptcache_extra_struct[extra->type][0] == '\0') {
continue;
- writestruct(wd, DATA, "PTCacheExtra", 1, extra);
- writestruct(wd, DATA, ptcache_extra_struct[extra->type], extra->totdata, extra->data);
+ }
+ writestruct(wd, DATA, PTCacheExtra, 1, extra);
+ writestruct_id(wd, DATA, ptcache_extra_struct[extra->type], extra->totdata, extra->data);
}
}
}
@@ -1165,90 +1284,107 @@ static void write_particlesettings(WriteData *wd, ListBase *idbase)
GroupObject *go;
int a;
- part= idbase->first;
+ part = idbase->first;
while (part) {
- if (part->id.us>0 || wd->current) {
+ if (part->id.us > 0 || wd->current) {
/* write LibData */
- writestruct(wd, ID_PA, "ParticleSettings", 1, part);
- if (part->id.properties) IDP_WriteProperty(part->id.properties, wd);
- if (part->adt) write_animdata(wd, part->adt);
- writestruct(wd, DATA, "PartDeflect", 1, part->pd);
- writestruct(wd, DATA, "PartDeflect", 1, part->pd2);
- writestruct(wd, DATA, "EffectorWeights", 1, part->effector_weights);
-
- if (part->clumpcurve)
+ writestruct(wd, ID_PA, ParticleSettings, 1, part);
+ write_iddata(wd, &part->id);
+
+ if (part->adt) {
+ write_animdata(wd, part->adt);
+ }
+ writestruct(wd, DATA, PartDeflect, 1, part->pd);
+ writestruct(wd, DATA, PartDeflect, 1, part->pd2);
+ writestruct(wd, DATA, EffectorWeights, 1, part->effector_weights);
+
+ if (part->clumpcurve) {
write_curvemapping(wd, part->clumpcurve);
- if (part->roughcurve)
+ }
+ if (part->roughcurve) {
write_curvemapping(wd, part->roughcurve);
-
+ }
+
dw = part->dupliweights.first;
- for (; dw; dw=dw->next) {
- /* update indices */
- dw->index = 0;
- if (part->dup_group) { /* can be NULL if lining fails or set to None */
- go = part->dup_group->gobject.first;
- while (go && go->ob != dw->ob) {
- go=go->next;
- dw->index++;
+ for (; dw; dw = dw->next) {
+ /* update indices, but only if dw->ob is set (can be NULL after loading e.g.) */
+ if (dw->ob != NULL) {
+ dw->index = 0;
+ if (part->dup_group) { /* can be NULL if lining fails or set to None */
+ for (go = part->dup_group->gobject.first; go && go->ob != dw->ob; go = go->next, dw->index++);
}
}
- writestruct(wd, DATA, "ParticleDupliWeight", 1, dw);
+ writestruct(wd, DATA, ParticleDupliWeight, 1, dw);
}
if (part->boids && part->phystype == PART_PHYS_BOIDS) {
BoidState *state = part->boids->states.first;
- writestruct(wd, DATA, "BoidSettings", 1, part->boids);
+ writestruct(wd, DATA, BoidSettings, 1, part->boids);
- for (; state; state=state->next)
+ for (; state; state = state->next) {
write_boid_state(wd, state);
+ }
}
if (part->fluid && part->phystype == PART_PHYS_FLUID) {
- writestruct(wd, DATA, "SPHFluidSettings", 1, part->fluid);
+ writestruct(wd, DATA, SPHFluidSettings, 1, part->fluid);
}
- for (a=0; a<MAX_MTEX; a++) {
- if (part->mtex[a]) writestruct(wd, DATA, "MTex", 1, part->mtex[a]);
+ for (a = 0; a < MAX_MTEX; a++) {
+ if (part->mtex[a]) {
+ writestruct(wd, DATA, MTex, 1, part->mtex[a]);
+ }
}
}
- part= part->id.next;
+ part = part->id.next;
}
}
static void write_particlesystems(WriteData *wd, ListBase *particles)
{
- ParticleSystem *psys= particles->first;
+ ParticleSystem *psys = particles->first;
ParticleTarget *pt;
int a;
- for (; psys; psys=psys->next) {
- writestruct(wd, DATA, "ParticleSystem", 1, psys);
+ for (; psys; psys = psys->next) {
+ writestruct(wd, DATA, ParticleSystem, 1, psys);
if (psys->particles) {
- writestruct(wd, DATA, "ParticleData", psys->totpart, psys->particles);
+ writestruct(wd, DATA, ParticleData, psys->totpart, psys->particles);
if (psys->particles->hair) {
ParticleData *pa = psys->particles;
- for (a=0; a<psys->totpart; a++, pa++)
- writestruct(wd, DATA, "HairKey", pa->totkey, pa->hair);
+ for (a = 0; a < psys->totpart; a++, pa++) {
+ writestruct(wd, DATA, HairKey, pa->totkey, pa->hair);
+ }
}
- if (psys->particles->boid && psys->part->phystype == PART_PHYS_BOIDS)
- writestruct(wd, DATA, "BoidParticle", psys->totpart, psys->particles->boid);
+ if (psys->particles->boid &&
+ (psys->part->phystype == PART_PHYS_BOIDS))
+ {
+ writestruct(wd, DATA, BoidParticle, psys->totpart, psys->particles->boid);
+ }
- if (psys->part->fluid && psys->part->phystype == PART_PHYS_FLUID && (psys->part->fluid->flag & SPH_VISCOELASTIC_SPRINGS))
- writestruct(wd, DATA, "ParticleSpring", psys->tot_fluidsprings, psys->fluid_springs);
+ if (psys->part->fluid &&
+ (psys->part->phystype == PART_PHYS_FLUID) &&
+ (psys->part->fluid->flag & SPH_VISCOELASTIC_SPRINGS))
+ {
+ writestruct(wd, DATA, ParticleSpring, psys->tot_fluidsprings, psys->fluid_springs);
+ }
}
pt = psys->targets.first;
- for (; pt; pt=pt->next)
- writestruct(wd, DATA, "ParticleTarget", 1, pt);
+ for (; pt; pt = pt->next) {
+ writestruct(wd, DATA, ParticleTarget, 1, pt);
+ }
- if (psys->child) writestruct(wd, DATA, "ChildParticle", psys->totchild, psys->child);
+ if (psys->child) {
+ writestruct(wd, DATA, ChildParticle, psys->totchild, psys->child);
+ }
if (psys->clmd) {
- writestruct(wd, DATA, "ClothModifierData", 1, psys->clmd);
- writestruct(wd, DATA, "ClothSimSettings", 1, psys->clmd->sim_parms);
- writestruct(wd, DATA, "ClothCollSettings", 1, psys->clmd->coll_parms);
+ writestruct(wd, DATA, ClothModifierData, 1, psys->clmd);
+ writestruct(wd, DATA, ClothSimSettings, 1, psys->clmd->sim_parms);
+ writestruct(wd, DATA, ClothCollSettings, 1, psys->clmd->coll_parms);
}
write_pointcaches(wd, &psys->ptcaches);
@@ -1259,14 +1395,15 @@ static void write_properties(WriteData *wd, ListBase *lb)
{
bProperty *prop;
- prop= lb->first;
+ prop = lb->first;
while (prop) {
- writestruct(wd, DATA, "bProperty", 1, prop);
+ writestruct(wd, DATA, bProperty, 1, prop);
- if (prop->poin && prop->poin != &prop->data)
+ if (prop->poin && prop->poin != &prop->data) {
writedata(wd, DATA, MEM_allocN_len(prop->poin), prop->poin);
+ }
- prop= prop->next;
+ prop = prop->next;
}
}
@@ -1274,57 +1411,57 @@ static void write_sensors(WriteData *wd, ListBase *lb)
{
bSensor *sens;
- sens= lb->first;
+ sens = lb->first;
while (sens) {
- writestruct(wd, DATA, "bSensor", 1, sens);
+ writestruct(wd, DATA, bSensor, 1, sens);
- writedata(wd, DATA, sizeof(void *)*sens->totlinks, sens->links);
+ writedata(wd, DATA, sizeof(void *) * sens->totlinks, sens->links);
switch (sens->type) {
- case SENS_NEAR:
- writestruct(wd, DATA, "bNearSensor", 1, sens->data);
- break;
- case SENS_MOUSE:
- writestruct(wd, DATA, "bMouseSensor", 1, sens->data);
- break;
- case SENS_KEYBOARD:
- writestruct(wd, DATA, "bKeyboardSensor", 1, sens->data);
- break;
- case SENS_PROPERTY:
- writestruct(wd, DATA, "bPropertySensor", 1, sens->data);
- break;
- case SENS_ARMATURE:
- writestruct(wd, DATA, "bArmatureSensor", 1, sens->data);
- break;
- case SENS_ACTUATOR:
- writestruct(wd, DATA, "bActuatorSensor", 1, sens->data);
- break;
- case SENS_DELAY:
- writestruct(wd, DATA, "bDelaySensor", 1, sens->data);
- break;
- case SENS_COLLISION:
- writestruct(wd, DATA, "bCollisionSensor", 1, sens->data);
- break;
- case SENS_RADAR:
- writestruct(wd, DATA, "bRadarSensor", 1, sens->data);
- break;
- case SENS_RANDOM:
- writestruct(wd, DATA, "bRandomSensor", 1, sens->data);
- break;
- case SENS_RAY:
- writestruct(wd, DATA, "bRaySensor", 1, sens->data);
- break;
- case SENS_MESSAGE:
- writestruct(wd, DATA, "bMessageSensor", 1, sens->data);
- break;
- case SENS_JOYSTICK:
- writestruct(wd, DATA, "bJoystickSensor", 1, sens->data);
- break;
- default:
- ; /* error: don't know how to write this file */
+ case SENS_NEAR:
+ writestruct(wd, DATA, bNearSensor, 1, sens->data);
+ break;
+ case SENS_MOUSE:
+ writestruct(wd, DATA, bMouseSensor, 1, sens->data);
+ break;
+ case SENS_KEYBOARD:
+ writestruct(wd, DATA, bKeyboardSensor, 1, sens->data);
+ break;
+ case SENS_PROPERTY:
+ writestruct(wd, DATA, bPropertySensor, 1, sens->data);
+ break;
+ case SENS_ARMATURE:
+ writestruct(wd, DATA, bArmatureSensor, 1, sens->data);
+ break;
+ case SENS_ACTUATOR:
+ writestruct(wd, DATA, bActuatorSensor, 1, sens->data);
+ break;
+ case SENS_DELAY:
+ writestruct(wd, DATA, bDelaySensor, 1, sens->data);
+ break;
+ case SENS_COLLISION:
+ writestruct(wd, DATA, bCollisionSensor, 1, sens->data);
+ break;
+ case SENS_RADAR:
+ writestruct(wd, DATA, bRadarSensor, 1, sens->data);
+ break;
+ case SENS_RANDOM:
+ writestruct(wd, DATA, bRandomSensor, 1, sens->data);
+ break;
+ case SENS_RAY:
+ writestruct(wd, DATA, bRaySensor, 1, sens->data);
+ break;
+ case SENS_MESSAGE:
+ writestruct(wd, DATA, bMessageSensor, 1, sens->data);
+ break;
+ case SENS_JOYSTICK:
+ writestruct(wd, DATA, bJoystickSensor, 1, sens->data);
+ break;
+ default:
+ ; /* error: don't know how to write this file */
}
- sens= sens->next;
+ sens = sens->next;
}
}
@@ -1332,24 +1469,24 @@ static void write_controllers(WriteData *wd, ListBase *lb)
{
bController *cont;
- cont= lb->first;
+ cont = lb->first;
while (cont) {
- writestruct(wd, DATA, "bController", 1, cont);
+ writestruct(wd, DATA, bController, 1, cont);
- writedata(wd, DATA, sizeof(void *)*cont->totlinks, cont->links);
+ writedata(wd, DATA, sizeof(void *) * cont->totlinks, cont->links);
switch (cont->type) {
- case CONT_EXPRESSION:
- writestruct(wd, DATA, "bExpressionCont", 1, cont->data);
- break;
- case CONT_PYTHON:
- writestruct(wd, DATA, "bPythonCont", 1, cont->data);
- break;
- default:
- ; /* error: don't know how to write this file */
+ case CONT_EXPRESSION:
+ writestruct(wd, DATA, bExpressionCont, 1, cont->data);
+ break;
+ case CONT_PYTHON:
+ writestruct(wd, DATA, bPythonCont, 1, cont->data);
+ break;
+ default:
+ ; /* error: don't know how to write this file */
}
- cont= cont->next;
+ cont = cont->next;
}
}
@@ -1357,133 +1494,135 @@ static void write_actuators(WriteData *wd, ListBase *lb)
{
bActuator *act;
- act= lb->first;
+ act = lb->first;
while (act) {
- writestruct(wd, DATA, "bActuator", 1, act);
+ writestruct(wd, DATA, bActuator, 1, act);
switch (act->type) {
- case ACT_ACTION:
- case ACT_SHAPEACTION:
- writestruct(wd, DATA, "bActionActuator", 1, act->data);
- break;
- case ACT_SOUND:
- writestruct(wd, DATA, "bSoundActuator", 1, act->data);
- break;
- case ACT_OBJECT:
- writestruct(wd, DATA, "bObjectActuator", 1, act->data);
- break;
- case ACT_PROPERTY:
- writestruct(wd, DATA, "bPropertyActuator", 1, act->data);
- break;
- case ACT_CAMERA:
- writestruct(wd, DATA, "bCameraActuator", 1, act->data);
- break;
- case ACT_CONSTRAINT:
- writestruct(wd, DATA, "bConstraintActuator", 1, act->data);
- break;
- case ACT_EDIT_OBJECT:
- writestruct(wd, DATA, "bEditObjectActuator", 1, act->data);
- break;
- case ACT_SCENE:
- writestruct(wd, DATA, "bSceneActuator", 1, act->data);
- break;
- case ACT_GROUP:
- writestruct(wd, DATA, "bGroupActuator", 1, act->data);
- break;
- case ACT_RANDOM:
- writestruct(wd, DATA, "bRandomActuator", 1, act->data);
- break;
- case ACT_MESSAGE:
- writestruct(wd, DATA, "bMessageActuator", 1, act->data);
- break;
- case ACT_GAME:
- writestruct(wd, DATA, "bGameActuator", 1, act->data);
- break;
- case ACT_VISIBILITY:
- writestruct(wd, DATA, "bVisibilityActuator", 1, act->data);
- break;
- case ACT_2DFILTER:
- writestruct(wd, DATA, "bTwoDFilterActuator", 1, act->data);
- break;
- case ACT_PARENT:
- writestruct(wd, DATA, "bParentActuator", 1, act->data);
- break;
- case ACT_STATE:
- writestruct(wd, DATA, "bStateActuator", 1, act->data);
- break;
- case ACT_ARMATURE:
- writestruct(wd, DATA, "bArmatureActuator", 1, act->data);
- break;
- case ACT_STEERING:
- writestruct(wd, DATA, "bSteeringActuator", 1, act->data);
- break;
- case ACT_MOUSE:
- writestruct(wd, DATA, "bMouseActuator", 1, act->data);
- break;
- default:
- ; /* error: don't know how to write this file */
+ case ACT_ACTION:
+ case ACT_SHAPEACTION:
+ writestruct(wd, DATA, bActionActuator, 1, act->data);
+ break;
+ case ACT_SOUND:
+ writestruct(wd, DATA, bSoundActuator, 1, act->data);
+ break;
+ case ACT_OBJECT:
+ writestruct(wd, DATA, bObjectActuator, 1, act->data);
+ break;
+ case ACT_PROPERTY:
+ writestruct(wd, DATA, bPropertyActuator, 1, act->data);
+ break;
+ case ACT_CAMERA:
+ writestruct(wd, DATA, bCameraActuator, 1, act->data);
+ break;
+ case ACT_CONSTRAINT:
+ writestruct(wd, DATA, bConstraintActuator, 1, act->data);
+ break;
+ case ACT_EDIT_OBJECT:
+ writestruct(wd, DATA, bEditObjectActuator, 1, act->data);
+ break;
+ case ACT_SCENE:
+ writestruct(wd, DATA, bSceneActuator, 1, act->data);
+ break;
+ case ACT_GROUP:
+ writestruct(wd, DATA, bGroupActuator, 1, act->data);
+ break;
+ case ACT_RANDOM:
+ writestruct(wd, DATA, bRandomActuator, 1, act->data);
+ break;
+ case ACT_MESSAGE:
+ writestruct(wd, DATA, bMessageActuator, 1, act->data);
+ break;
+ case ACT_GAME:
+ writestruct(wd, DATA, bGameActuator, 1, act->data);
+ break;
+ case ACT_VISIBILITY:
+ writestruct(wd, DATA, bVisibilityActuator, 1, act->data);
+ break;
+ case ACT_2DFILTER:
+ writestruct(wd, DATA, bTwoDFilterActuator, 1, act->data);
+ break;
+ case ACT_PARENT:
+ writestruct(wd, DATA, bParentActuator, 1, act->data);
+ break;
+ case ACT_STATE:
+ writestruct(wd, DATA, bStateActuator, 1, act->data);
+ break;
+ case ACT_ARMATURE:
+ writestruct(wd, DATA, bArmatureActuator, 1, act->data);
+ break;
+ case ACT_STEERING:
+ writestruct(wd, DATA, bSteeringActuator, 1, act->data);
+ break;
+ case ACT_MOUSE:
+ writestruct(wd, DATA, bMouseActuator, 1, act->data);
+ break;
+ default:
+ ; /* error: don't know how to write this file */
}
- act= act->next;
+ act = act->next;
}
}
static void write_motionpath(WriteData *wd, bMotionPath *mpath)
{
/* sanity checks */
- if (mpath == NULL)
+ if (mpath == NULL) {
return;
-
+ }
+
/* firstly, just write the motionpath struct */
- writestruct(wd, DATA, "bMotionPath", 1, mpath);
-
+ writestruct(wd, DATA, bMotionPath, 1, mpath);
+
/* now write the array of data */
- writestruct(wd, DATA, "bMotionPathVert", mpath->length, mpath->points);
+ writestruct(wd, DATA, bMotionPathVert, mpath->length, mpath->points);
}
static void write_constraints(WriteData *wd, ListBase *conlist)
{
bConstraint *con;
- for (con=conlist->first; con; con=con->next) {
- const bConstraintTypeInfo *cti= BKE_constraint_typeinfo_get(con);
-
+ for (con = conlist->first; con; con = con->next) {
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+
/* Write the specific data */
if (cti && con->data) {
/* firstly, just write the plain con->data struct */
- writestruct(wd, DATA, cti->structName, 1, con->data);
-
+ writestruct_id(wd, DATA, cti->structName, 1, con->data);
+
/* do any constraint specific stuff */
switch (con->type) {
case CONSTRAINT_TYPE_PYTHON:
{
- bPythonConstraint *data = (bPythonConstraint *)con->data;
+ bPythonConstraint *data = con->data;
bConstraintTarget *ct;
-
+
/* write targets */
- for (ct= data->targets.first; ct; ct= ct->next)
- writestruct(wd, DATA, "bConstraintTarget", 1, ct);
-
+ for (ct = data->targets.first; ct; ct = ct->next) {
+ writestruct(wd, DATA, bConstraintTarget, 1, ct);
+ }
+
/* Write ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
IDP_WriteProperty(data->prop, wd);
break;
}
- case CONSTRAINT_TYPE_SPLINEIK:
+ case CONSTRAINT_TYPE_SPLINEIK:
{
- bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
-
+ bSplineIKConstraint *data = con->data;
+
/* write points array */
- writedata(wd, DATA, sizeof(float)*(data->numpoints), data->points);
+ writedata(wd, DATA, sizeof(float) * (data->numpoints), data->points);
break;
}
}
}
-
+
/* Write the constraint */
- writestruct(wd, DATA, "bConstraint", 1, con);
+ writestruct(wd, DATA, bConstraint, 1, con);
}
}
@@ -1493,176 +1632,191 @@ static void write_pose(WriteData *wd, bPose *pose)
bActionGroup *grp;
/* Write each channel */
- if (!pose)
+ if (pose == NULL) {
return;
+ }
/* Write channels */
- for (chan=pose->chanbase.first; chan; chan=chan->next) {
+ for (chan = pose->chanbase.first; chan; chan = chan->next) {
/* Write ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
- if (chan->prop)
+ if (chan->prop) {
IDP_WriteProperty(chan->prop, wd);
-
+ }
+
write_constraints(wd, &chan->constraints);
-
+
write_motionpath(wd, chan->mpath);
-
- /* prevent crashes with autosave, when a bone duplicated in editmode has not yet been assigned to its posechannel */
- if (chan->bone)
- chan->selectflag= chan->bone->flag & BONE_SELECTED; /* gets restored on read, for library armatures */
-
- writestruct(wd, DATA, "bPoseChannel", 1, chan);
+
+ /* prevent crashes with autosave,
+ * when a bone duplicated in editmode has not yet been assigned to its posechannel */
+ if (chan->bone) {
+ /* gets restored on read, for library armatures */
+ chan->selectflag = chan->bone->flag & BONE_SELECTED;
+ }
+
+ writestruct(wd, DATA, bPoseChannel, 1, chan);
}
-
+
/* Write groups */
- for (grp=pose->agroups.first; grp; grp=grp->next)
- writestruct(wd, DATA, "bActionGroup", 1, grp);
+ for (grp = pose->agroups.first; grp; grp = grp->next) {
+ writestruct(wd, DATA, bActionGroup, 1, grp);
+ }
/* write IK param */
if (pose->ikparam) {
const char *structname = BKE_pose_ikparam_get_name(pose);
- if (structname)
- writestruct(wd, DATA, structname, 1, pose->ikparam);
+ if (structname) {
+ writestruct_id(wd, DATA, structname, 1, pose->ikparam);
+ }
}
/* Write this pose */
- writestruct(wd, DATA, "bPose", 1, pose);
+ writestruct(wd, DATA, bPose, 1, pose);
}
static void write_defgroups(WriteData *wd, ListBase *defbase)
{
- bDeformGroup *defgroup;
-
- for (defgroup=defbase->first; defgroup; defgroup=defgroup->next)
- writestruct(wd, DATA, "bDeformGroup", 1, defgroup);
+ for (bDeformGroup *defgroup = defbase->first; defgroup; defgroup = defgroup->next) {
+ writestruct(wd, DATA, bDeformGroup, 1, defgroup);
+ }
}
static void write_modifiers(WriteData *wd, ListBase *modbase)
{
ModifierData *md;
- if (modbase == NULL) return;
- for (md=modbase->first; md; md= md->next) {
+ if (modbase == NULL) {
+ return;
+ }
+
+ for (md = modbase->first; md; md = md->next) {
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- if (mti == NULL) return;
-
- writestruct(wd, DATA, mti->structName, 1, md);
-
- if (md->type==eModifierType_Hook) {
- HookModifierData *hmd = (HookModifierData*) md;
-
+ if (mti == NULL) {
+ return;
+ }
+
+ writestruct_id(wd, DATA, mti->structName, 1, md);
+
+ if (md->type == eModifierType_Hook) {
+ HookModifierData *hmd = (HookModifierData *)md;
+
if (hmd->curfalloff) {
write_curvemapping(wd, hmd->curfalloff);
}
- writedata(wd, DATA, sizeof(int)*hmd->totindex, hmd->indexar);
+ writedata(wd, DATA, sizeof(int) * hmd->totindex, hmd->indexar);
}
- else if (md->type==eModifierType_Cloth) {
- ClothModifierData *clmd = (ClothModifierData*) md;
-
- writestruct(wd, DATA, "ClothSimSettings", 1, clmd->sim_parms);
- writestruct(wd, DATA, "ClothCollSettings", 1, clmd->coll_parms);
- writestruct(wd, DATA, "EffectorWeights", 1, clmd->sim_parms->effector_weights);
+ else if (md->type == eModifierType_Cloth) {
+ ClothModifierData *clmd = (ClothModifierData *)md;
+
+ writestruct(wd, DATA, ClothSimSettings, 1, clmd->sim_parms);
+ writestruct(wd, DATA, ClothCollSettings, 1, clmd->coll_parms);
+ writestruct(wd, DATA, EffectorWeights, 1, clmd->sim_parms->effector_weights);
write_pointcaches(wd, &clmd->ptcaches);
}
- else if (md->type==eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData*) md;
-
+ else if (md->type == eModifierType_Smoke) {
+ SmokeModifierData *smd = (SmokeModifierData *)md;
+
if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
if (smd->domain) {
write_pointcaches(wd, &(smd->domain->ptcaches[0]));
/* create fake pointcache so that old blender versions can read it */
smd->domain->point_cache[1] = BKE_ptcache_add(&smd->domain->ptcaches[1]);
- smd->domain->point_cache[1]->flag |= PTCACHE_DISK_CACHE|PTCACHE_FAKE_SMOKE;
+ smd->domain->point_cache[1]->flag |= PTCACHE_DISK_CACHE | PTCACHE_FAKE_SMOKE;
smd->domain->point_cache[1]->step = 1;
write_pointcaches(wd, &(smd->domain->ptcaches[1]));
}
-
- writestruct(wd, DATA, "SmokeDomainSettings", 1, smd->domain);
+
+ writestruct(wd, DATA, SmokeDomainSettings, 1, smd->domain);
if (smd->domain) {
/* cleanup the fake pointcache */
BKE_ptcache_free_list(&smd->domain->ptcaches[1]);
smd->domain->point_cache[1] = NULL;
-
- writestruct(wd, DATA, "EffectorWeights", 1, smd->domain->effector_weights);
+
+ writestruct(wd, DATA, EffectorWeights, 1, smd->domain->effector_weights);
}
}
- else if (smd->type & MOD_SMOKE_TYPE_FLOW)
- writestruct(wd, DATA, "SmokeFlowSettings", 1, smd->flow);
- else if (smd->type & MOD_SMOKE_TYPE_COLL)
- writestruct(wd, DATA, "SmokeCollSettings", 1, smd->coll);
+ else if (smd->type & MOD_SMOKE_TYPE_FLOW) {
+ writestruct(wd, DATA, SmokeFlowSettings, 1, smd->flow);
+ }
+ else if (smd->type & MOD_SMOKE_TYPE_COLL) {
+ writestruct(wd, DATA, SmokeCollSettings, 1, smd->coll);
+ }
}
- else if (md->type==eModifierType_Fluidsim) {
- FluidsimModifierData *fluidmd = (FluidsimModifierData*) md;
-
- writestruct(wd, DATA, "FluidsimSettings", 1, fluidmd->fss);
+ else if (md->type == eModifierType_Fluidsim) {
+ FluidsimModifierData *fluidmd = (FluidsimModifierData *)md;
+
+ writestruct(wd, DATA, FluidsimSettings, 1, fluidmd->fss);
}
- else if (md->type==eModifierType_DynamicPaint) {
- DynamicPaintModifierData *pmd = (DynamicPaintModifierData*) md;
-
+ else if (md->type == eModifierType_DynamicPaint) {
+ DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
+
if (pmd->canvas) {
DynamicPaintSurface *surface;
- writestruct(wd, DATA, "DynamicPaintCanvasSettings", 1, pmd->canvas);
-
+ writestruct(wd, DATA, DynamicPaintCanvasSettings, 1, pmd->canvas);
+
/* write surfaces */
- for (surface=pmd->canvas->surfaces.first; surface; surface=surface->next)
- writestruct(wd, DATA, "DynamicPaintSurface", 1, surface);
+ for (surface = pmd->canvas->surfaces.first; surface; surface = surface->next) {
+ writestruct(wd, DATA, DynamicPaintSurface, 1, surface);
+ }
/* write caches and effector weights */
- for (surface=pmd->canvas->surfaces.first; surface; surface=surface->next) {
+ for (surface = pmd->canvas->surfaces.first; surface; surface = surface->next) {
write_pointcaches(wd, &(surface->ptcaches));
- writestruct(wd, DATA, "EffectorWeights", 1, surface->effector_weights);
+ writestruct(wd, DATA, EffectorWeights, 1, surface->effector_weights);
}
}
if (pmd->brush) {
- writestruct(wd, DATA, "DynamicPaintBrushSettings", 1, pmd->brush);
- writestruct(wd, DATA, "ColorBand", 1, pmd->brush->paint_ramp);
- writestruct(wd, DATA, "ColorBand", 1, pmd->brush->vel_ramp);
+ writestruct(wd, DATA, DynamicPaintBrushSettings, 1, pmd->brush);
+ writestruct(wd, DATA, ColorBand, 1, pmd->brush->paint_ramp);
+ writestruct(wd, DATA, ColorBand, 1, pmd->brush->vel_ramp);
}
}
- else if (md->type==eModifierType_Collision) {
-
+ else if (md->type == eModifierType_Collision) {
+
#if 0
- CollisionModifierData *collmd = (CollisionModifierData*) md;
- // TODO: CollisionModifier should use pointcache
+ CollisionModifierData *collmd = (CollisionModifierData *)md;
+ // TODO: CollisionModifier should use pointcache
// + have proper reset events before enabling this
- writestruct(wd, DATA, "MVert", collmd->numverts, collmd->x);
- writestruct(wd, DATA, "MVert", collmd->numverts, collmd->xnew);
- writestruct(wd, DATA, "MFace", collmd->numfaces, collmd->mfaces);
+ writestruct(wd, DATA, MVert, collmd->numverts, collmd->x);
+ writestruct(wd, DATA, MVert, collmd->numverts, collmd->xnew);
+ writestruct(wd, DATA, MFace, collmd->numfaces, collmd->mfaces);
#endif
}
- else if (md->type==eModifierType_MeshDeform) {
- MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
+ else if (md->type == eModifierType_MeshDeform) {
+ MeshDeformModifierData *mmd = (MeshDeformModifierData *)md;
int size = mmd->dyngridsize;
- writestruct(wd, DATA, "MDefInfluence", mmd->totinfluence, mmd->bindinfluences);
+ writestruct(wd, DATA, MDefInfluence, mmd->totinfluence, mmd->bindinfluences);
writedata(wd, DATA, sizeof(int) * (mmd->totvert + 1), mmd->bindoffsets);
writedata(wd, DATA, sizeof(float) * 3 * mmd->totcagevert,
- mmd->bindcagecos);
- writestruct(wd, DATA, "MDefCell", size*size*size, mmd->dyngrid);
- writestruct(wd, DATA, "MDefInfluence", mmd->totinfluence, mmd->dyninfluences);
- writedata(wd, DATA, sizeof(int)*mmd->totvert, mmd->dynverts);
+ mmd->bindcagecos);
+ writestruct(wd, DATA, MDefCell, size * size * size, mmd->dyngrid);
+ writestruct(wd, DATA, MDefInfluence, mmd->totinfluence, mmd->dyninfluences);
+ writedata(wd, DATA, sizeof(int) * mmd->totvert, mmd->dynverts);
}
- else if (md->type==eModifierType_Warp) {
- WarpModifierData *tmd = (WarpModifierData*) md;
+ else if (md->type == eModifierType_Warp) {
+ WarpModifierData *tmd = (WarpModifierData *)md;
if (tmd->curfalloff) {
write_curvemapping(wd, tmd->curfalloff);
}
}
- else if (md->type==eModifierType_WeightVGEdit) {
- WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
+ else if (md->type == eModifierType_WeightVGEdit) {
+ WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md;
- if (wmd->cmap_curve)
+ if (wmd->cmap_curve) {
write_curvemapping(wd, wmd->cmap_curve);
+ }
}
- else if (md->type==eModifierType_LaplacianDeform) {
- LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData*) md;
+ else if (md->type == eModifierType_LaplacianDeform) {
+ LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData *)md;
- writedata(wd, DATA, sizeof(float)*lmd->total_verts * 3, lmd->vertexco);
+ writedata(wd, DATA, sizeof(float) * lmd->total_verts * 3, lmd->vertexco);
}
else if (md->type == eModifierType_CorrectiveSmooth) {
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
@@ -1677,22 +1831,21 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
static void write_objects(WriteData *wd, ListBase *idbase)
{
Object *ob;
-
- ob= idbase->first;
+
+ ob = idbase->first;
while (ob) {
- if (ob->id.us>0 || wd->current) {
+ if (ob->id.us > 0 || wd->current) {
/* write LibData */
- writestruct(wd, ID_OB, "Object", 1, ob);
-
- /* Write ID Properties -- and copy this comment EXACTLY for easy finding
- * of library blocks that implement this.*/
- if (ob->id.properties) IDP_WriteProperty(ob->id.properties, wd);
-
- if (ob->adt) write_animdata(wd, ob->adt);
-
+ writestruct(wd, ID_OB, Object, 1, ob);
+ write_iddata(wd, &ob->id);
+
+ if (ob->adt) {
+ write_animdata(wd, ob->adt);
+ }
+
/* direct data */
- writedata(wd, DATA, sizeof(void *)*ob->totcol, ob->mat);
- writedata(wd, DATA, sizeof(char)*ob->totcol, ob->matbits);
+ writedata(wd, DATA, sizeof(void *) * ob->totcol, ob->mat);
+ writedata(wd, DATA, sizeof(char) * ob->totcol, ob->matbits);
/* write_effects(wd, &ob->effect); */ /* not used anymore */
write_properties(wd, &ob->prop);
write_sensors(wd, &ob->sensors);
@@ -1710,67 +1863,68 @@ static void write_objects(WriteData *wd, ListBase *idbase)
write_defgroups(wd, &ob->defbase);
write_constraints(wd, &ob->constraints);
write_motionpath(wd, ob->mpath);
-
- writestruct(wd, DATA, "PartDeflect", 1, ob->pd);
- writestruct(wd, DATA, "SoftBody", 1, ob->soft);
+
+ writestruct(wd, DATA, PartDeflect, 1, ob->pd);
+ writestruct(wd, DATA, SoftBody, 1, ob->soft);
if (ob->soft) {
write_pointcaches(wd, &ob->soft->ptcaches);
- writestruct(wd, DATA, "EffectorWeights", 1, ob->soft->effector_weights);
+ writestruct(wd, DATA, EffectorWeights, 1, ob->soft->effector_weights);
}
- writestruct(wd, DATA, "BulletSoftBody", 1, ob->bsoft);
-
+ writestruct(wd, DATA, BulletSoftBody, 1, ob->bsoft);
+
if (ob->rigidbody_object) {
- // TODO: if any extra data is added to handle duplis, will need separate function then
- writestruct(wd, DATA, "RigidBodyOb", 1, ob->rigidbody_object);
+ /* TODO: if any extra data is added to handle duplis, will need separate function then */
+ writestruct(wd, DATA, RigidBodyOb, 1, ob->rigidbody_object);
}
if (ob->rigidbody_constraint) {
- writestruct(wd, DATA, "RigidBodyCon", 1, ob->rigidbody_constraint);
+ writestruct(wd, DATA, RigidBodyCon, 1, ob->rigidbody_constraint);
}
if (ob->type == OB_EMPTY && ob->empty_drawtype == OB_EMPTY_IMAGE) {
- writestruct(wd, DATA, "ImageUser", 1, ob->iuser);
+ writestruct(wd, DATA, ImageUser, 1, ob->iuser);
}
write_particlesystems(wd, &ob->particlesystem);
write_modifiers(wd, &ob->modifiers);
- writelist(wd, DATA, "LinkData", &ob->pc_ids);
- writelist(wd, DATA, "LodLevel", &ob->lodlevels);
+ writelist(wd, DATA, LinkData, &ob->pc_ids);
+ writelist(wd, DATA, LodLevel, &ob->lodlevels);
}
write_previews(wd, ob->preview);
- ob= ob->id.next;
+ ob = ob->id.next;
}
- /* flush helps the compression for undo-save */
- mywrite(wd, MYWRITE_FLUSH, 0);
+ mywrite_flush(wd);
}
static void write_vfonts(WriteData *wd, ListBase *idbase)
{
VFont *vf;
- PackedFile * pf;
+ PackedFile *pf;
- vf= idbase->first;
+ vf = idbase->first;
while (vf) {
- if (vf->id.us>0 || wd->current) {
+ if (vf->id.us > 0 || wd->current) {
/* write LibData */
- writestruct(wd, ID_VF, "VFont", 1, vf);
- if (vf->id.properties) IDP_WriteProperty(vf->id.properties, wd);
+ writestruct(wd, ID_VF, VFont, 1, vf);
+ write_iddata(wd, &vf->id);
/* direct data */
if (vf->packedfile) {
pf = vf->packedfile;
- writestruct(wd, DATA, "PackedFile", 1, pf);
+ writestruct(wd, DATA, PackedFile, 1, pf);
writedata(wd, DATA, pf->size, pf->data);
}
}
- vf= vf->id.next;
+ vf = vf->id.next;
}
+
+ mywrite_flush(wd);
}
@@ -1779,45 +1933,51 @@ static void write_keys(WriteData *wd, ListBase *idbase)
Key *key;
KeyBlock *kb;
- key= idbase->first;
+ key = idbase->first;
while (key) {
- if (key->id.us>0 || wd->current) {
+ if (key->id.us > 0 || wd->current) {
/* write LibData */
- writestruct(wd, ID_KE, "Key", 1, key);
- if (key->id.properties) IDP_WriteProperty(key->id.properties, wd);
-
- if (key->adt) write_animdata(wd, key->adt);
-
+ writestruct(wd, ID_KE, Key, 1, key);
+ write_iddata(wd, &key->id);
+
+ if (key->adt) {
+ write_animdata(wd, key->adt);
+ }
+
/* direct data */
- kb= key->block.first;
+ kb = key->block.first;
while (kb) {
- writestruct(wd, DATA, "KeyBlock", 1, kb);
- if (kb->data) writedata(wd, DATA, kb->totelem*key->elemsize, kb->data);
- kb= kb->next;
+ writestruct(wd, DATA, KeyBlock, 1, kb);
+ if (kb->data) {
+ writedata(wd, DATA, kb->totelem * key->elemsize, kb->data);
+ }
+ kb = kb->next;
}
}
- key= key->id.next;
+ key = key->id.next;
}
- /* flush helps the compression for undo-save */
- mywrite(wd, MYWRITE_FLUSH, 0);
+
+ mywrite_flush(wd);
}
static void write_cameras(WriteData *wd, ListBase *idbase)
{
Camera *cam;
- cam= idbase->first;
+ cam = idbase->first;
while (cam) {
- if (cam->id.us>0 || wd->current) {
+ if (cam->id.us > 0 || wd->current) {
/* write LibData */
- writestruct(wd, ID_CA, "Camera", 1, cam);
- if (cam->id.properties) IDP_WriteProperty(cam->id.properties, wd);
-
- if (cam->adt) write_animdata(wd, cam->adt);
+ writestruct(wd, ID_CA, Camera, 1, cam);
+ write_iddata(wd, &cam->id);
+
+ if (cam->adt) {
+ write_animdata(wd, cam->adt);
+ }
}
- cam= cam->id.next;
+ cam = cam->id.next;
}
}
@@ -1826,24 +1986,26 @@ static void write_mballs(WriteData *wd, ListBase *idbase)
MetaBall *mb;
MetaElem *ml;
- mb= idbase->first;
+ mb = idbase->first;
while (mb) {
- if (mb->id.us>0 || wd->current) {
+ if (mb->id.us > 0 || wd->current) {
/* write LibData */
- writestruct(wd, ID_MB, "MetaBall", 1, mb);
- if (mb->id.properties) IDP_WriteProperty(mb->id.properties, wd);
+ writestruct(wd, ID_MB, MetaBall, 1, mb);
+ write_iddata(wd, &mb->id);
/* direct data */
- writedata(wd, DATA, sizeof(void *)*mb->totcol, mb->mat);
- if (mb->adt) write_animdata(wd, mb->adt);
+ writedata(wd, DATA, sizeof(void *) * mb->totcol, mb->mat);
+ if (mb->adt) {
+ write_animdata(wd, mb->adt);
+ }
- ml= mb->elems.first;
+ ml = mb->elems.first;
while (ml) {
- writestruct(wd, DATA, "MetaElem", 1, ml);
- ml= ml->next;
+ writestruct(wd, DATA, MetaElem, 1, ml);
+ ml = ml->next;
}
}
- mb= mb->id.next;
+ mb = mb->id.next;
}
}
@@ -1852,61 +2014,67 @@ static void write_curves(WriteData *wd, ListBase *idbase)
Curve *cu;
Nurb *nu;
- cu= idbase->first;
+ cu = idbase->first;
while (cu) {
- if (cu->id.us>0 || wd->current) {
+ if (cu->id.us > 0 || wd->current) {
/* write LibData */
- writestruct(wd, ID_CU, "Curve", 1, cu);
-
+ writestruct(wd, ID_CU, Curve, 1, cu);
+ write_iddata(wd, &cu->id);
+
/* direct data */
- writedata(wd, DATA, sizeof(void *)*cu->totcol, cu->mat);
- if (cu->id.properties) IDP_WriteProperty(cu->id.properties, wd);
- if (cu->adt) write_animdata(wd, cu->adt);
-
+ writedata(wd, DATA, sizeof(void *) * cu->totcol, cu->mat);
+ if (cu->adt) {
+ write_animdata(wd, cu->adt);
+ }
+
if (cu->vfont) {
writedata(wd, DATA, cu->len + 1, cu->str);
- writestruct(wd, DATA, "CharInfo", cu->len_wchar + 1, cu->strinfo);
- writestruct(wd, DATA, "TextBox", cu->totbox, cu->tb);
+ writestruct(wd, DATA, CharInfo, cu->len_wchar + 1, cu->strinfo);
+ writestruct(wd, DATA, TextBox, cu->totbox, cu->tb);
}
else {
/* is also the order of reading */
- nu= cu->nurb.first;
+ nu = cu->nurb.first;
while (nu) {
- writestruct(wd, DATA, "Nurb", 1, nu);
- nu= nu->next;
+ writestruct(wd, DATA, Nurb, 1, nu);
+ nu = nu->next;
}
- nu= cu->nurb.first;
+ nu = cu->nurb.first;
while (nu) {
- if (nu->type == CU_BEZIER)
- writestruct(wd, DATA, "BezTriple", nu->pntsu, nu->bezt);
+ if (nu->type == CU_BEZIER) {
+ writestruct(wd, DATA, BezTriple, nu->pntsu, nu->bezt);
+ }
else {
- writestruct(wd, DATA, "BPoint", nu->pntsu*nu->pntsv, nu->bp);
- if (nu->knotsu) writedata(wd, DATA, KNOTSU(nu)*sizeof(float), nu->knotsu);
- if (nu->knotsv) writedata(wd, DATA, KNOTSV(nu)*sizeof(float), nu->knotsv);
+ writestruct(wd, DATA, BPoint, nu->pntsu * nu->pntsv, nu->bp);
+ if (nu->knotsu) {
+ writedata(wd, DATA, KNOTSU(nu) * sizeof(float), nu->knotsu);
+ }
+ if (nu->knotsv) {
+ writedata(wd, DATA, KNOTSV(nu) * sizeof(float), nu->knotsv);
+ }
}
- nu= nu->next;
+ nu = nu->next;
}
}
}
- cu= cu->id.next;
+ cu = cu->id.next;
}
- /* flush helps the compression for undo-save */
- mywrite(wd, MYWRITE_FLUSH, 0);
+ mywrite_flush(wd);
}
static void write_dverts(WriteData *wd, int count, MDeformVert *dvlist)
{
if (dvlist) {
- int i;
-
+
/* Write the dvert list */
- writestruct(wd, DATA, "MDeformVert", count, dvlist);
-
+ writestruct(wd, DATA, MDeformVert, count, dvlist);
+
/* Write deformation data for each dvert */
- for (i=0; i<count; i++) {
- if (dvlist[i].dw)
- writestruct(wd, DATA, "MDeformWeight", dvlist[i].totweight, dvlist[i].dw);
+ for (int i = 0; i < count; i++) {
+ if (dvlist[i].dw) {
+ writestruct(wd, DATA, MDeformWeight, dvlist[i].totweight, dvlist[i].dw);
+ }
}
}
}
@@ -1915,17 +2083,19 @@ static void write_mdisps(WriteData *wd, int count, MDisps *mdlist, int external)
{
if (mdlist) {
int i;
-
- writestruct(wd, DATA, "MDisps", count, mdlist);
+
+ writestruct(wd, DATA, MDisps, count, mdlist);
for (i = 0; i < count; ++i) {
MDisps *md = &mdlist[i];
if (md->disps) {
- if (!external)
+ if (!external) {
writedata(wd, DATA, sizeof(float) * 3 * md->totdisp, md->disps);
+ }
}
-
- if (md->hidden)
+
+ if (md->hidden) {
writedata(wd, DATA, BLI_BITMAP_SIZE(md->totdisp), md->hidden);
+ }
}
}
}
@@ -1934,8 +2104,8 @@ static void write_grid_paint_mask(WriteData *wd, int count, GridPaintMask *grid_
{
if (grid_paint_mask) {
int i;
-
- writestruct(wd, DATA, "GridPaintMask", count, grid_paint_mask);
+
+ writestruct(wd, DATA, GridPaintMask, count, grid_paint_mask);
for (i = 0; i < count; ++i) {
GridPaintMask *gpm = &grid_paint_mask[i];
if (gpm->data) {
@@ -1955,11 +2125,12 @@ static void write_customdata(
int i;
/* write external customdata (not for undo) */
- if (data->external && !wd->current)
+ if (data->external && !wd->current) {
CustomData_external_write(data, id, CD_MASK_MESH, count, 0);
+ }
+
+ writestruct_at_address(wd, DATA, CustomDataLayer, data->totlayer, data->layers, layers);
- writestruct_at_address(wd, DATA, "CustomDataLayer", data->totlayer, data->layers, layers);
-
for (i = 0; i < data->totlayer; i++) {
CustomDataLayer *layer = &layers[i];
const char *structname;
@@ -1985,10 +2156,14 @@ static void write_customdata(
/* when using partial visibility, the MEdge and MFace layers
* are smaller than the original, so their type and count is
* passed to make this work */
- if (layer->type != partial_type) datasize= structnum*count;
- else datasize= structnum*partial_count;
+ if (layer->type != partial_type) {
+ datasize = structnum * count;
+ }
+ else {
+ datasize = structnum * partial_count;
+ }
- writestruct(wd, DATA, structname, datasize, layer->data);
+ writestruct_id(wd, DATA, structname, datasize, layer->data);
}
else {
printf("%s error: layer '%s':%d - can't be written to file\n",
@@ -1997,20 +2172,21 @@ static void write_customdata(
}
}
- if (data->external)
- writestruct(wd, DATA, "CustomDataExternal", 1, data->external);
+ if (data->external) {
+ writestruct(wd, DATA, CustomDataExternal, 1, data->external);
+ }
}
static void write_meshes(WriteData *wd, ListBase *idbase)
{
Mesh *mesh;
- int save_for_old_blender= 0;
+ bool save_for_old_blender = false;
#ifdef USE_BMESH_SAVE_AS_COMPAT
save_for_old_blender = wd->use_mesh_compat; /* option to save with older mesh format */
#endif
- mesh= idbase->first;
+ mesh = idbase->first;
while (mesh) {
CustomDataLayer *vlayers = NULL, vlayers_buff[CD_TEMP_CHUNK_SIZE];
CustomDataLayer *elayers = NULL, elayers_buff[CD_TEMP_CHUNK_SIZE];
@@ -2018,7 +2194,7 @@ static void write_meshes(WriteData *wd, ListBase *idbase)
CustomDataLayer *llayers = NULL, llayers_buff[CD_TEMP_CHUNK_SIZE];
CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE];
- if (mesh->id.us>0 || wd->current) {
+ if (mesh->id.us > 0 || wd->current) {
/* write LibData */
if (!save_for_old_blender) {
/* write a copy of the mesh, don't modify in place because it is
@@ -2051,13 +2227,15 @@ static void write_meshes(WriteData *wd, ListBase *idbase)
CustomData_file_write_prepare(&mesh->ldata, &llayers, llayers_buff, ARRAY_SIZE(llayers_buff));
CustomData_file_write_prepare(&mesh->pdata, &players, players_buff, ARRAY_SIZE(players_buff));
- writestruct_at_address(wd, ID_ME, "Mesh", 1, old_mesh, mesh);
+ writestruct_at_address(wd, ID_ME, Mesh, 1, old_mesh, mesh);
+ write_iddata(wd, &mesh->id);
/* direct data */
- if (mesh->id.properties) IDP_WriteProperty(mesh->id.properties, wd);
- if (mesh->adt) write_animdata(wd, mesh->adt);
+ if (mesh->adt) {
+ write_animdata(wd, mesh->adt);
+ }
- writedata(wd, DATA, sizeof(void *)*mesh->totcol, mesh->mat);
+ writedata(wd, DATA, sizeof(void *) * mesh->totcol, mesh->mat);
writedata(wd, DATA, sizeof(MSelect) * mesh->totselect, mesh->mselect);
write_customdata(wd, &mesh->id, mesh->totvert, &mesh->vdata, vlayers, -1, 0);
@@ -2090,7 +2268,7 @@ static void write_meshes(WriteData *wd, ListBase *idbase)
mesh->edit_btmesh = NULL;
/* now fill in polys to mfaces */
- /* XXX This breaks writing desing, by using temp allocated memory, which will likely generate
+ /* XXX This breaks writing design, by using temp allocated memory, which will likely generate
* duplicates in stored 'old' addresses.
* This is very bad, but do not see easy way to avoid this, aside from generating those data
* outside of save process itself.
@@ -2109,13 +2287,15 @@ static void write_meshes(WriteData *wd, ListBase *idbase)
CustomData_file_write_prepare(&mesh->pdata, &players, players_buff, ARRAY_SIZE(players_buff));
#endif
- writestruct_at_address(wd, ID_ME, "Mesh", 1, old_mesh, mesh);
+ writestruct_at_address(wd, ID_ME, Mesh, 1, old_mesh, mesh);
+ write_iddata(wd, &mesh->id);
/* direct data */
- if (mesh->id.properties) IDP_WriteProperty(mesh->id.properties, wd);
- if (mesh->adt) write_animdata(wd, mesh->adt);
+ if (mesh->adt) {
+ write_animdata(wd, mesh->adt);
+ }
- writedata(wd, DATA, sizeof(void *)*mesh->totcol, mesh->mat);
+ writedata(wd, DATA, sizeof(void *) * mesh->totcol, mesh->mat);
/* writedata(wd, DATA, sizeof(MSelect) * mesh->totselect, mesh->mselect); */ /* pre-bmesh NULL's */
write_customdata(wd, &mesh->id, mesh->totvert, &mesh->vdata, vlayers, -1, 0);
@@ -2152,44 +2332,50 @@ static void write_meshes(WriteData *wd, ListBase *idbase)
MEM_freeN(players);
}
- mesh= mesh->id.next;
+ mesh = mesh->id.next;
}
+
+ mywrite_flush(wd);
}
static void write_lattices(WriteData *wd, ListBase *idbase)
{
Lattice *lt;
-
- lt= idbase->first;
+
+ lt = idbase->first;
while (lt) {
- if (lt->id.us>0 || wd->current) {
+ if (lt->id.us > 0 || wd->current) {
/* write LibData */
- writestruct(wd, ID_LT, "Lattice", 1, lt);
- if (lt->id.properties) IDP_WriteProperty(lt->id.properties, wd);
-
+ writestruct(wd, ID_LT, Lattice, 1, lt);
+ write_iddata(wd, &lt->id);
+
/* write animdata */
- if (lt->adt) write_animdata(wd, lt->adt);
-
+ if (lt->adt) {
+ write_animdata(wd, lt->adt);
+ }
+
/* direct data */
- writestruct(wd, DATA, "BPoint", lt->pntsu*lt->pntsv*lt->pntsw, lt->def);
-
- write_dverts(wd, lt->pntsu*lt->pntsv*lt->pntsw, lt->dvert);
-
+ writestruct(wd, DATA, BPoint, lt->pntsu * lt->pntsv * lt->pntsw, lt->def);
+
+ write_dverts(wd, lt->pntsu * lt->pntsv * lt->pntsw, lt->dvert);
+
}
- lt= lt->id.next;
+ lt = lt->id.next;
}
+
+ mywrite_flush(wd);
}
static void write_images(WriteData *wd, ListBase *idbase)
{
Image *ima;
- PackedFile * pf;
+ PackedFile *pf;
ImageView *iv;
ImagePackedFile *imapf;
- ima= idbase->first;
+ ima = idbase->first;
while (ima) {
- if (ima->id.us>0 || wd->current) {
+ if (ima->id.us > 0 || wd->current) {
/* Some trickery to keep forward compatibility of packed images. */
BLI_assert(ima->packedfile == NULL);
if (ima->packedfiles.first != NULL) {
@@ -2198,69 +2384,83 @@ static void write_images(WriteData *wd, ListBase *idbase)
}
/* write LibData */
- writestruct(wd, ID_IM, "Image", 1, ima);
- if (ima->id.properties) IDP_WriteProperty(ima->id.properties, wd);
+ writestruct(wd, ID_IM, Image, 1, ima);
+ write_iddata(wd, &ima->id);
for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next) {
- writestruct(wd, DATA, "ImagePackedFile", 1, imapf);
+ writestruct(wd, DATA, ImagePackedFile, 1, imapf);
if (imapf->packedfile) {
pf = imapf->packedfile;
- writestruct(wd, DATA, "PackedFile", 1, pf);
+ writestruct(wd, DATA, PackedFile, 1, pf);
writedata(wd, DATA, pf->size, pf->data);
}
}
write_previews(wd, ima->preview);
- for (iv = ima->views.first; iv; iv = iv->next)
- writestruct(wd, DATA, "ImageView", 1, iv);
- writestruct(wd, DATA, "Stereo3dFormat", 1, ima->stereo3d_format);
+ for (iv = ima->views.first; iv; iv = iv->next) {
+ writestruct(wd, DATA, ImageView, 1, iv);
+ }
+ writestruct(wd, DATA, Stereo3dFormat, 1, ima->stereo3d_format);
ima->packedfile = NULL;
}
- ima= ima->id.next;
+ ima = ima->id.next;
}
- /* flush helps the compression for undo-save */
- mywrite(wd, MYWRITE_FLUSH, 0);
+
+ mywrite_flush(wd);
}
static void write_textures(WriteData *wd, ListBase *idbase)
{
Tex *tex;
- tex= idbase->first;
+ tex = idbase->first;
while (tex) {
- if (tex->id.us>0 || wd->current) {
+ if (tex->id.us > 0 || wd->current) {
/* write LibData */
- writestruct(wd, ID_TE, "Tex", 1, tex);
- if (tex->id.properties) IDP_WriteProperty(tex->id.properties, wd);
+ writestruct(wd, ID_TE, Tex, 1, tex);
+ write_iddata(wd, &tex->id);
- if (tex->adt) write_animdata(wd, tex->adt);
+ if (tex->adt) {
+ write_animdata(wd, tex->adt);
+ }
/* direct data */
- if (tex->coba) writestruct(wd, DATA, "ColorBand", 1, tex->coba);
- if (tex->type == TEX_ENVMAP && tex->env) writestruct(wd, DATA, "EnvMap", 1, tex->env);
+ if (tex->coba) {
+ writestruct(wd, DATA, ColorBand, 1, tex->coba);
+ }
+ if (tex->type == TEX_ENVMAP && tex->env) {
+ writestruct(wd, DATA, EnvMap, 1, tex->env);
+ }
if (tex->type == TEX_POINTDENSITY && tex->pd) {
- writestruct(wd, DATA, "PointDensity", 1, tex->pd);
- if (tex->pd->coba) writestruct(wd, DATA, "ColorBand", 1, tex->pd->coba);
- if (tex->pd->falloff_curve) write_curvemapping(wd, tex->pd->falloff_curve);
+ writestruct(wd, DATA, PointDensity, 1, tex->pd);
+ if (tex->pd->coba) {
+ writestruct(wd, DATA, ColorBand, 1, tex->pd->coba);
+ }
+ if (tex->pd->falloff_curve) {
+ write_curvemapping(wd, tex->pd->falloff_curve);
+ }
}
- if (tex->type == TEX_VOXELDATA) writestruct(wd, DATA, "VoxelData", 1, tex->vd);
- if (tex->type == TEX_OCEAN && tex->ot) writestruct(wd, DATA, "OceanTex", 1, tex->ot);
-
+ if (tex->type == TEX_VOXELDATA) {
+ writestruct(wd, DATA, VoxelData, 1, tex->vd);
+ }
+ if (tex->type == TEX_OCEAN && tex->ot) {
+ writestruct(wd, DATA, OceanTex, 1, tex->ot);
+ }
+
/* nodetree is integral part of texture, no libdata */
if (tex->nodetree) {
- writestruct(wd, DATA, "bNodeTree", 1, tex->nodetree);
+ writestruct(wd, DATA, bNodeTree, 1, tex->nodetree);
write_nodetree(wd, tex->nodetree);
}
-
+
write_previews(wd, tex->preview);
}
- tex= tex->id.next;
+ tex = tex->id.next;
}
- /* flush helps the compression for undo-save */
- mywrite(wd, MYWRITE_FLUSH, 0);
+ mywrite_flush(wd);
}
static void write_materials(WriteData *wd, ListBase *idbase)
@@ -2268,36 +2468,39 @@ static void write_materials(WriteData *wd, ListBase *idbase)
Material *ma;
int a;
- ma= idbase->first;
+ ma = idbase->first;
while (ma) {
- if (ma->id.us>0 || wd->current) {
+ if (ma->id.us > 0 || wd->current) {
/* write LibData */
- writestruct(wd, ID_MA, "Material", 1, ma);
-
- /* Write ID Properties -- and copy this comment EXACTLY for easy finding
- * of library blocks that implement this.*/
- /* manually set head group property to IDP_GROUP, just in case it hadn't been
- * set yet :) */
- if (ma->id.properties) IDP_WriteProperty(ma->id.properties, wd);
-
- if (ma->adt) write_animdata(wd, ma->adt);
-
- for (a=0; a<MAX_MTEX; a++) {
- if (ma->mtex[a]) writestruct(wd, DATA, "MTex", 1, ma->mtex[a]);
- }
-
- if (ma->ramp_col) writestruct(wd, DATA, "ColorBand", 1, ma->ramp_col);
- if (ma->ramp_spec) writestruct(wd, DATA, "ColorBand", 1, ma->ramp_spec);
-
+ writestruct(wd, ID_MA, Material, 1, ma);
+ write_iddata(wd, &ma->id);
+
+ if (ma->adt) {
+ write_animdata(wd, ma->adt);
+ }
+
+ for (a = 0; a < MAX_MTEX; a++) {
+ if (ma->mtex[a]) {
+ writestruct(wd, DATA, MTex, 1, ma->mtex[a]);
+ }
+ }
+
+ if (ma->ramp_col) {
+ writestruct(wd, DATA, ColorBand, 1, ma->ramp_col);
+ }
+ if (ma->ramp_spec) {
+ writestruct(wd, DATA, ColorBand, 1, ma->ramp_spec);
+ }
+
/* nodetree is integral part of material, no libdata */
if (ma->nodetree) {
- writestruct(wd, DATA, "bNodeTree", 1, ma->nodetree);
+ writestruct(wd, DATA, bNodeTree, 1, ma->nodetree);
write_nodetree(wd, ma->nodetree);
}
write_previews(wd, ma->preview);
}
- ma= ma->id.next;
+ ma = ma->id.next;
}
}
@@ -2306,28 +2509,32 @@ static void write_worlds(WriteData *wd, ListBase *idbase)
World *wrld;
int a;
- wrld= idbase->first;
+ wrld = idbase->first;
while (wrld) {
- if (wrld->id.us>0 || wd->current) {
+ if (wrld->id.us > 0 || wd->current) {
/* write LibData */
- writestruct(wd, ID_WO, "World", 1, wrld);
- if (wrld->id.properties) IDP_WriteProperty(wrld->id.properties, wd);
-
- if (wrld->adt) write_animdata(wd, wrld->adt);
-
- for (a=0; a<MAX_MTEX; a++) {
- if (wrld->mtex[a]) writestruct(wd, DATA, "MTex", 1, wrld->mtex[a]);
+ writestruct(wd, ID_WO, World, 1, wrld);
+ write_iddata(wd, &wrld->id);
+
+ if (wrld->adt) {
+ write_animdata(wd, wrld->adt);
+ }
+
+ for (a = 0; a < MAX_MTEX; a++) {
+ if (wrld->mtex[a]) {
+ writestruct(wd, DATA, MTex, 1, wrld->mtex[a]);
+ }
}
/* nodetree is integral part of world, no libdata */
if (wrld->nodetree) {
- writestruct(wd, DATA, "bNodeTree", 1, wrld->nodetree);
+ writestruct(wd, DATA, bNodeTree, 1, wrld->nodetree);
write_nodetree(wd, wrld->nodetree);
}
-
+
write_previews(wd, wrld->preview);
}
- wrld= wrld->id.next;
+ wrld = wrld->id.next;
}
}
@@ -2336,34 +2543,41 @@ static void write_lamps(WriteData *wd, ListBase *idbase)
Lamp *la;
int a;
- la= idbase->first;
+ la = idbase->first;
while (la) {
- if (la->id.us>0 || wd->current) {
+ if (la->id.us > 0 || wd->current) {
/* write LibData */
- writestruct(wd, ID_LA, "Lamp", 1, la);
- if (la->id.properties) IDP_WriteProperty(la->id.properties, wd);
-
- if (la->adt) write_animdata(wd, la->adt);
-
+ writestruct(wd, ID_LA, Lamp, 1, la);
+ write_iddata(wd, &la->id);
+
+ if (la->adt) {
+ write_animdata(wd, la->adt);
+ }
+
/* direct data */
- for (a=0; a<MAX_MTEX; a++) {
- if (la->mtex[a]) writestruct(wd, DATA, "MTex", 1, la->mtex[a]);
+ for (a = 0; a < MAX_MTEX; a++) {
+ if (la->mtex[a]) {
+ writestruct(wd, DATA, MTex, 1, la->mtex[a]);
+ }
}
-
- if (la->curfalloff)
+
+ if (la->curfalloff) {
write_curvemapping(wd, la->curfalloff);
-
+ }
+
/* nodetree is integral part of lamps, no libdata */
if (la->nodetree) {
- writestruct(wd, DATA, "bNodeTree", 1, la->nodetree);
+ writestruct(wd, DATA, bNodeTree, 1, la->nodetree);
write_nodetree(wd, la->nodetree);
}
write_previews(wd, la->preview);
-
+
}
- la= la->id.next;
+ la = la->id.next;
}
+
+ mywrite_flush(wd);
}
static void write_sequence_modifiers(WriteData *wd, ListBase *modbase)
@@ -2374,21 +2588,21 @@ static void write_sequence_modifiers(WriteData *wd, ListBase *modbase)
const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
if (smti) {
- writestruct(wd, DATA, smti->struct_name, 1, smd);
+ writestruct_id(wd, DATA, smti->struct_name, 1, smd);
if (smd->type == seqModifierType_Curves) {
- CurvesModifierData *cmd = (CurvesModifierData *) smd;
+ CurvesModifierData *cmd = (CurvesModifierData *)smd;
write_curvemapping(wd, &cmd->curve_mapping);
}
else if (smd->type == seqModifierType_HueCorrect) {
- HueCorrectModifierData *hcmd = (HueCorrectModifierData *) smd;
+ HueCorrectModifierData *hcmd = (HueCorrectModifierData *)smd;
write_curvemapping(wd, &hcmd->curve_mapping);
}
}
else {
- writestruct(wd, DATA, "SequenceModifierData", 1, smd);
+ writestruct(wd, DATA, SequenceModifierData, 1, smd);
}
}
}
@@ -2402,8 +2616,9 @@ static void write_view_settings(WriteData *wd, ColorManagedViewSettings *view_se
static void write_paint(WriteData *wd, Paint *p)
{
- if (p->cavity_curve)
+ if (p->cavity_curve) {
write_curvemapping(wd, p->cavity_curve);
+ }
}
static void write_scenes(WriteData *wd, ListBase *scebase)
@@ -2421,106 +2636,128 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
ToolSettings *tos;
FreestyleModuleConfig *fmc;
FreestyleLineSet *fls;
-
- sce= scebase->first;
+
+ sce = scebase->first;
while (sce) {
/* write LibData */
- writestruct(wd, ID_SCE, "Scene", 1, sce);
- if (sce->id.properties) IDP_WriteProperty(sce->id.properties, wd);
-
- if (sce->adt) write_animdata(wd, sce->adt);
+ writestruct(wd, ID_SCE, Scene, 1, sce);
+ write_iddata(wd, &sce->id);
+
+ if (sce->adt) {
+ write_animdata(wd, sce->adt);
+ }
write_keyingsets(wd, &sce->keyingsets);
-
+
/* direct data */
- base= sce->base.first;
+ base = sce->base.first;
while (base) {
- writestruct(wd, DATA, "Base", 1, base);
- base= base->next;
+ writestruct(wd, DATA, Base, 1, base);
+ base = base->next;
}
-
+
tos = sce->toolsettings;
- writestruct(wd, DATA, "ToolSettings", 1, tos);
+ writestruct(wd, DATA, ToolSettings, 1, tos);
if (tos->vpaint) {
- writestruct(wd, DATA, "VPaint", 1, tos->vpaint);
- write_paint (wd, &tos->vpaint->paint);
+ writestruct(wd, DATA, VPaint, 1, tos->vpaint);
+ write_paint(wd, &tos->vpaint->paint);
}
if (tos->wpaint) {
- writestruct(wd, DATA, "VPaint", 1, tos->wpaint);
- write_paint (wd, &tos->wpaint->paint);
+ writestruct(wd, DATA, VPaint, 1, tos->wpaint);
+ write_paint(wd, &tos->wpaint->paint);
}
if (tos->sculpt) {
- writestruct(wd, DATA, "Sculpt", 1, tos->sculpt);
- write_paint (wd, &tos->sculpt->paint);
+ writestruct(wd, DATA, Sculpt, 1, tos->sculpt);
+ write_paint(wd, &tos->sculpt->paint);
}
if (tos->uvsculpt) {
- writestruct(wd, DATA, "UvSculpt", 1, tos->uvsculpt);
- write_paint (wd, &tos->uvsculpt->paint);
+ writestruct(wd, DATA, UvSculpt, 1, tos->uvsculpt);
+ write_paint(wd, &tos->uvsculpt->paint);
+ }
+ /* write grease-pencil drawing brushes to file */
+ writelist(wd, DATA, bGPDbrush, &tos->gp_brushes);
+ for (bGPDbrush *brush = tos->gp_brushes.first; brush; brush = brush->next) {
+ if (brush->cur_sensitivity) {
+ write_curvemapping(wd, brush->cur_sensitivity);
+ }
+ if (brush->cur_strength) {
+ write_curvemapping(wd, brush->cur_strength);
+ }
+ if (brush->cur_jitter) {
+ write_curvemapping(wd, brush->cur_jitter);
+ }
}
+
write_paint(wd, &tos->imapaint.paint);
- ed= sce->ed;
+ ed = sce->ed;
if (ed) {
- writestruct(wd, DATA, "Editing", 1, ed);
-
+ writestruct(wd, DATA, Editing, 1, ed);
+
/* reset write flags too */
-
- SEQ_BEGIN (ed, seq)
+
+ SEQ_BEGIN(ed, seq)
{
- if (seq->strip) seq->strip->done = false;
- writestruct(wd, DATA, "Sequence", 1, seq);
+ if (seq->strip) {
+ seq->strip->done = false;
+ }
+ writestruct(wd, DATA, Sequence, 1, seq);
}
SEQ_END
-
- SEQ_BEGIN (ed, seq)
+
+ SEQ_BEGIN(ed, seq)
{
- if (seq->strip && seq->strip->done==0) {
+ if (seq->strip && seq->strip->done == 0) {
/* write strip with 'done' at 0 because readfile */
-
+
if (seq->effectdata) {
switch (seq->type) {
- case SEQ_TYPE_COLOR:
- writestruct(wd, DATA, "SolidColorVars", 1, seq->effectdata);
- break;
- case SEQ_TYPE_SPEED:
- writestruct(wd, DATA, "SpeedControlVars", 1, seq->effectdata);
- break;
- case SEQ_TYPE_WIPE:
- writestruct(wd, DATA, "WipeVars", 1, seq->effectdata);
- break;
- case SEQ_TYPE_GLOW:
- writestruct(wd, DATA, "GlowVars", 1, seq->effectdata);
- break;
- case SEQ_TYPE_TRANSFORM:
- writestruct(wd, DATA, "TransformVars", 1, seq->effectdata);
- break;
- case SEQ_TYPE_GAUSSIAN_BLUR:
- writestruct(wd, DATA, "GaussianBlurVars", 1, seq->effectdata);
- break;
- case SEQ_TYPE_TEXT:
- writestruct(wd, DATA, "TextVars", 1, seq->effectdata);
- break;
+ case SEQ_TYPE_COLOR:
+ writestruct(wd, DATA, SolidColorVars, 1, seq->effectdata);
+ break;
+ case SEQ_TYPE_SPEED:
+ writestruct(wd, DATA, SpeedControlVars, 1, seq->effectdata);
+ break;
+ case SEQ_TYPE_WIPE:
+ writestruct(wd, DATA, WipeVars, 1, seq->effectdata);
+ break;
+ case SEQ_TYPE_GLOW:
+ writestruct(wd, DATA, GlowVars, 1, seq->effectdata);
+ break;
+ case SEQ_TYPE_TRANSFORM:
+ writestruct(wd, DATA, TransformVars, 1, seq->effectdata);
+ break;
+ case SEQ_TYPE_GAUSSIAN_BLUR:
+ writestruct(wd, DATA, GaussianBlurVars, 1, seq->effectdata);
+ break;
+ case SEQ_TYPE_TEXT:
+ writestruct(wd, DATA, TextVars, 1, seq->effectdata);
+ break;
}
}
- writestruct(wd, DATA, "Stereo3dFormat", 1, seq->stereo3d_format);
+ writestruct(wd, DATA, Stereo3dFormat, 1, seq->stereo3d_format);
- strip= seq->strip;
- writestruct(wd, DATA, "Strip", 1, strip);
+ strip = seq->strip;
+ writestruct(wd, DATA, Strip, 1, strip);
if (seq->flag & SEQ_USE_CROP && strip->crop) {
- writestruct(wd, DATA, "StripCrop", 1, strip->crop);
+ writestruct(wd, DATA, StripCrop, 1, strip->crop);
}
if (seq->flag & SEQ_USE_TRANSFORM && strip->transform) {
- writestruct(wd, DATA, "StripTransform", 1, strip->transform);
+ writestruct(wd, DATA, StripTransform, 1, strip->transform);
}
if (seq->flag & SEQ_USE_PROXY && strip->proxy) {
- writestruct(wd, DATA, "StripProxy", 1, strip->proxy);
+ writestruct(wd, DATA, StripProxy, 1, strip->proxy);
}
- if (seq->type==SEQ_TYPE_IMAGE)
- writestruct(wd, DATA, "StripElem", MEM_allocN_len(strip->stripdata) / sizeof(struct StripElem), strip->stripdata);
- else if (seq->type==SEQ_TYPE_MOVIE || seq->type==SEQ_TYPE_SOUND_RAM || seq->type == SEQ_TYPE_SOUND_HD)
- writestruct(wd, DATA, "StripElem", 1, strip->stripdata);
-
+ if (seq->type == SEQ_TYPE_IMAGE) {
+ writestruct(wd, DATA, StripElem,
+ MEM_allocN_len(strip->stripdata) / sizeof(struct StripElem),
+ strip->stripdata);
+ }
+ else if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) {
+ writestruct(wd, DATA, StripElem, 1, strip->stripdata);
+ }
+
strip->done = true;
}
@@ -2531,70 +2768,79 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
write_sequence_modifiers(wd, &seq->modifiers);
}
SEQ_END
-
+
/* new; meta stack too, even when its nasty restore code */
- for (ms= ed->metastack.first; ms; ms= ms->next) {
- writestruct(wd, DATA, "MetaStack", 1, ms);
+ for (ms = ed->metastack.first; ms; ms = ms->next) {
+ writestruct(wd, DATA, MetaStack, 1, ms);
}
}
-
+
if (sce->r.avicodecdata) {
- writestruct(wd, DATA, "AviCodecData", 1, sce->r.avicodecdata);
- if (sce->r.avicodecdata->lpFormat) writedata(wd, DATA, sce->r.avicodecdata->cbFormat, sce->r.avicodecdata->lpFormat);
- if (sce->r.avicodecdata->lpParms) writedata(wd, DATA, sce->r.avicodecdata->cbParms, sce->r.avicodecdata->lpParms);
+ writestruct(wd, DATA, AviCodecData, 1, sce->r.avicodecdata);
+ if (sce->r.avicodecdata->lpFormat) {
+ writedata(wd, DATA, sce->r.avicodecdata->cbFormat, sce->r.avicodecdata->lpFormat);
+ }
+ if (sce->r.avicodecdata->lpParms) {
+ writedata(wd, DATA, sce->r.avicodecdata->cbParms, sce->r.avicodecdata->lpParms);
+ }
}
if (sce->r.qtcodecdata) {
- writestruct(wd, DATA, "QuicktimeCodecData", 1, sce->r.qtcodecdata);
- if (sce->r.qtcodecdata->cdParms) writedata(wd, DATA, sce->r.qtcodecdata->cdSize, sce->r.qtcodecdata->cdParms);
+ writestruct(wd, DATA, QuicktimeCodecData, 1, sce->r.qtcodecdata);
+ if (sce->r.qtcodecdata->cdParms) {
+ writedata(wd, DATA, sce->r.qtcodecdata->cdSize, sce->r.qtcodecdata->cdParms);
+ }
}
if (sce->r.ffcodecdata.properties) {
IDP_WriteProperty(sce->r.ffcodecdata.properties, wd);
}
/* writing dynamic list of TimeMarkers to the blend file */
- for (marker= sce->markers.first; marker; marker= marker->next)
- writestruct(wd, DATA, "TimeMarker", 1, marker);
-
+ for (marker = sce->markers.first; marker; marker = marker->next) {
+ writestruct(wd, DATA, TimeMarker, 1, marker);
+ }
+
/* writing dynamic list of TransformOrientations to the blend file */
- for (ts = sce->transform_spaces.first; ts; ts = ts->next)
- writestruct(wd, DATA, "TransformOrientation", 1, ts);
-
+ for (ts = sce->transform_spaces.first; ts; ts = ts->next) {
+ writestruct(wd, DATA, TransformOrientation, 1, ts);
+ }
+
for (srl = sce->r.layers.first; srl; srl = srl->next) {
- writestruct(wd, DATA, "SceneRenderLayer", 1, srl);
+ writestruct(wd, DATA, SceneRenderLayer, 1, srl);
for (fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) {
- writestruct(wd, DATA, "FreestyleModuleConfig", 1, fmc);
+ writestruct(wd, DATA, FreestyleModuleConfig, 1, fmc);
}
for (fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) {
- writestruct(wd, DATA, "FreestyleLineSet", 1, fls);
+ writestruct(wd, DATA, FreestyleLineSet, 1, fls);
}
}
/* writing MultiView to the blend file */
- for (srv = sce->r.views.first; srv; srv = srv->next)
- writestruct(wd, DATA, "SceneRenderView", 1, srv);
-
+ for (srv = sce->r.views.first; srv; srv = srv->next) {
+ writestruct(wd, DATA, SceneRenderView, 1, srv);
+ }
+
if (sce->nodetree) {
- writestruct(wd, DATA, "bNodeTree", 1, sce->nodetree);
+ writestruct(wd, DATA, bNodeTree, 1, sce->nodetree);
write_nodetree(wd, sce->nodetree);
}
write_view_settings(wd, &sce->view_settings);
-
+
/* writing RigidBodyWorld data to the blend file */
if (sce->rigidbody_world) {
- writestruct(wd, DATA, "RigidBodyWorld", 1, sce->rigidbody_world);
- writestruct(wd, DATA, "EffectorWeights", 1, sce->rigidbody_world->effector_weights);
+ writestruct(wd, DATA, RigidBodyWorld, 1, sce->rigidbody_world);
+ writestruct(wd, DATA, EffectorWeights, 1, sce->rigidbody_world->effector_weights);
write_pointcaches(wd, &(sce->rigidbody_world->ptcaches));
}
-
+
write_previews(wd, sce->preview);
write_curvemapping_curves(wd, &sce->r.mblur_shutter_curve);
- sce= sce->id.next;
+ sce = sce->id.next;
}
- /* flush helps the compression for undo-save */
- mywrite(wd, MYWRITE_FLUSH, 0);
+
+ mywrite_flush(wd);
}
static void write_gpencils(WriteData *wd, ListBase *lb)
@@ -2603,63 +2849,81 @@ static void write_gpencils(WriteData *wd, ListBase *lb)
bGPDlayer *gpl;
bGPDframe *gpf;
bGPDstroke *gps;
-
- for (gpd= lb->first; gpd; gpd= gpd->id.next) {
- if (gpd->id.us>0 || wd->current) {
+ bGPDpalette *palette;
+
+ for (gpd = lb->first; gpd; gpd = gpd->id.next) {
+ if (gpd->id.us > 0 || wd->current) {
/* write gpd data block to file */
- writestruct(wd, ID_GD, "bGPdata", 1, gpd);
-
- if (gpd->adt) write_animdata(wd, gpd->adt);
-
+ writestruct(wd, ID_GD, bGPdata, 1, gpd);
+ write_iddata(wd, &gpd->id);
+
+ if (gpd->adt) {
+ write_animdata(wd, gpd->adt);
+ }
+
/* write grease-pencil layers to file */
- writelist(wd, DATA, "bGPDlayer", &gpd->layers);
- for (gpl= gpd->layers.first; gpl; gpl= gpl->next) {
-
+ writelist(wd, DATA, bGPDlayer, &gpd->layers);
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+
/* write this layer's frames to file */
- writelist(wd, DATA, "bGPDframe", &gpl->frames);
- for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
-
+ writelist(wd, DATA, bGPDframe, &gpl->frames);
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+
/* write strokes */
- writelist(wd, DATA, "bGPDstroke", &gpf->strokes);
- for (gps= gpf->strokes.first; gps; gps= gps->next) {
- writestruct(wd, DATA, "bGPDspoint", gps->totpoints, gps->points);
+ writelist(wd, DATA, bGPDstroke, &gpf->strokes);
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ writestruct(wd, DATA, bGPDspoint, gps->totpoints, gps->points);
}
}
}
+ /* write grease-pencil palettes */
+ writelist(wd, DATA, bGPDpalette, &gpd->palettes);
+ for (palette = gpd->palettes.first; palette; palette = palette->next) {
+ writelist(wd, DATA, bGPDpalettecolor, &palette->colors);
+ }
}
}
+
+ mywrite_flush(wd);
}
static void write_windowmanagers(WriteData *wd, ListBase *lb)
{
wmWindowManager *wm;
wmWindow *win;
-
- for (wm= lb->first; wm; wm= wm->id.next) {
- writestruct(wd, ID_WM, "wmWindowManager", 1, wm);
-
- for (win= wm->windows.first; win; win= win->next) {
- writestruct(wd, DATA, "wmWindow", 1, win);
- writestruct(wd, DATA, "Stereo3dFormat", 1, win->stereo3d_format);
+
+ for (wm = lb->first; wm; wm = wm->id.next) {
+ writestruct(wd, ID_WM, wmWindowManager, 1, wm);
+ write_iddata(wd, &wm->id);
+
+ for (win = wm->windows.first; win; win = win->next) {
+ writestruct(wd, DATA, wmWindow, 1, win);
+ writestruct(wd, DATA, Stereo3dFormat, 1, win->stereo3d_format);
}
}
+
+ /* typically flushing wouldn't be needed however this data _always_ changes,
+ * so flush here for more efficient undo. */
+ mywrite_flush(wd);
}
static void write_region(WriteData *wd, ARegion *ar, int spacetype)
-{
- writestruct(wd, DATA, "ARegion", 1, ar);
-
+{
+ writestruct(wd, DATA, ARegion, 1, ar);
+
if (ar->regiondata) {
switch (spacetype) {
case SPACE_VIEW3D:
- if (ar->regiontype==RGN_TYPE_WINDOW) {
- RegionView3D *rv3d= ar->regiondata;
- writestruct(wd, DATA, "RegionView3D", 1, rv3d);
-
- if (rv3d->localvd)
- writestruct(wd, DATA, "RegionView3D", 1, rv3d->localvd);
- if (rv3d->clipbb)
- writestruct(wd, DATA, "BoundBox", 1, rv3d->clipbb);
+ if (ar->regiontype == RGN_TYPE_WINDOW) {
+ RegionView3D *rv3d = ar->regiondata;
+ writestruct(wd, DATA, RegionView3D, 1, rv3d);
+
+ if (rv3d->localvd) {
+ writestruct(wd, DATA, RegionView3D, 1, rv3d->localvd);
+ }
+ if (rv3d->clipbb) {
+ writestruct(wd, DATA, BoundBox, 1, rv3d->clipbb);
+ }
}
else
@@ -2673,53 +2937,53 @@ static void write_region(WriteData *wd, ARegion *ar, int spacetype)
static void write_uilist(WriteData *wd, uiList *ui_list)
{
- writestruct(wd, DATA, "uiList", 1, ui_list);
+ writestruct(wd, DATA, uiList, 1, ui_list);
if (ui_list->properties) {
IDP_WriteProperty(ui_list->properties, wd);
}
}
-static void write_soops(WriteData *wd, SpaceOops *so, LinkNode **tmp_mem_list)
+static void write_soops(WriteData *wd, SpaceOops *so)
{
BLI_mempool *ts = so->treestore;
-
+
if (ts) {
+ SpaceOops so_flat = *so;
+
int elems = BLI_mempool_count(ts);
/* linearize mempool to array */
TreeStoreElem *data = elems ? BLI_mempool_as_arrayN(ts, "TreeStoreElem") : NULL;
if (data) {
- TreeStore *ts_flat = MEM_callocN(sizeof(TreeStore), "TreeStore");
-
- ts_flat->usedelem = elems;
- ts_flat->totelem = elems;
- ts_flat->data = data;
-
- /* temporarily replace mempool-treestore by flat-treestore */
- so->treestore = (BLI_mempool *)ts_flat;
- writestruct(wd, DATA, "SpaceOops", 1, so);
-
- writestruct(wd, DATA, "TreeStore", 1, ts_flat);
- writestruct(wd, DATA, "TreeStoreElem", elems, data);
-
- /* we do not free the pointers immediately, because if we have multiple
- * outliners in a screen we might get the same address on the next
- * malloc, which makes the address no longer unique and so invalid for
- * lookups on file read, causing crashes or double frees */
- BLI_linklist_prepend(tmp_mem_list, ts_flat);
- BLI_linklist_prepend(tmp_mem_list, data);
+ /* In this block we use the memory location of the treestore
+ * but _not_ its data, the addresses in this case are UUID's,
+ * since we can't rely on malloc giving us different values each time.
+ */
+ TreeStore ts_flat = {0};
+
+ /* we know the treestore is at least as big as a pointer,
+ * so offsetting works to give us a UUID. */
+ void *data_addr = (void *)POINTER_OFFSET(ts, sizeof(void *));
+
+ ts_flat.usedelem = elems;
+ ts_flat.totelem = elems;
+ ts_flat.data = data_addr;
+
+ writestruct(wd, DATA, SpaceOops, 1, so);
+
+ writestruct_at_address(wd, DATA, TreeStore, 1, ts, &ts_flat);
+ writestruct_at_address(wd, DATA, TreeStoreElem, elems, data_addr, data);
+
+ MEM_freeN(data);
}
else {
- so->treestore = NULL;
- writestruct(wd, DATA, "SpaceOops", 1, so);
+ so_flat.treestore = NULL;
+ writestruct_at_address(wd, DATA, SpaceOops, 1, so, &so_flat);
}
-
- /* restore old treestore */
- so->treestore = ts;
}
else {
- writestruct(wd, DATA, "SpaceOops", 1, so);
+ writestruct(wd, DATA, SpaceOops, 1, so);
}
}
@@ -2729,276 +2993,226 @@ static void write_screens(WriteData *wd, ListBase *scrbase)
ScrArea *sa;
ScrVert *sv;
ScrEdge *se;
- LinkNode *tmp_mem_list = NULL;
- sc= scrbase->first;
+ sc = scrbase->first;
while (sc) {
-
+
/* write LibData */
/* in 2.50+ files, the file identifier for screens is patched, forward compatibility */
- writestruct(wd, ID_SCRN, "Screen", 1, sc);
- if (sc->id.properties)
- IDP_WriteProperty(sc->id.properties, wd);
-
+ writestruct(wd, ID_SCRN, bScreen, 1, sc);
+ write_iddata(wd, &sc->id);
+
/* direct data */
- for (sv= sc->vertbase.first; sv; sv= sv->next)
- writestruct(wd, DATA, "ScrVert", 1, sv);
-
- for (se= sc->edgebase.first; se; se= se->next)
- writestruct(wd, DATA, "ScrEdge", 1, se);
-
- for (sa= sc->areabase.first; sa; sa= sa->next) {
+ for (sv = sc->vertbase.first; sv; sv = sv->next) {
+ writestruct(wd, DATA, ScrVert, 1, sv);
+ }
+
+ for (se = sc->edgebase.first; se; se = se->next) {
+ writestruct(wd, DATA, ScrEdge, 1, se);
+ }
+
+ for (sa = sc->areabase.first; sa; sa = sa->next) {
SpaceLink *sl;
Panel *pa;
uiList *ui_list;
uiPreview *ui_preview;
PanelCategoryStack *pc_act;
ARegion *ar;
-
- writestruct(wd, DATA, "ScrArea", 1, sa);
-
- for (ar= sa->regionbase.first; ar; ar= ar->next) {
+
+ writestruct(wd, DATA, ScrArea, 1, sa);
+
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
write_region(wd, ar, sa->spacetype);
-
- for (pa= ar->panels.first; pa; pa= pa->next)
- writestruct(wd, DATA, "Panel", 1, pa);
-
- for (pc_act = ar->panels_category_active.first; pc_act; pc_act = pc_act->next)
- writestruct(wd, DATA, "PanelCategoryStack", 1, pc_act);
-
- for (ui_list = ar->ui_lists.first; ui_list; ui_list = ui_list->next)
+
+ for (pa = ar->panels.first; pa; pa = pa->next) {
+ writestruct(wd, DATA, Panel, 1, pa);
+ }
+
+ for (pc_act = ar->panels_category_active.first; pc_act; pc_act = pc_act->next) {
+ writestruct(wd, DATA, PanelCategoryStack, 1, pc_act);
+ }
+
+ for (ui_list = ar->ui_lists.first; ui_list; ui_list = ui_list->next) {
write_uilist(wd, ui_list);
+ }
- for (ui_preview = ar->ui_previews.first; ui_preview; ui_preview = ui_preview->next)
- writestruct(wd, DATA, "uiPreview", 1, ui_preview);
+ for (ui_preview = ar->ui_previews.first; ui_preview; ui_preview = ui_preview->next) {
+ writestruct(wd, DATA, uiPreview, 1, ui_preview);
+ }
}
-
- sl= sa->spacedata.first;
+
+ sl = sa->spacedata.first;
while (sl) {
- for (ar= sl->regionbase.first; ar; ar= ar->next)
+ for (ar = sl->regionbase.first; ar; ar = ar->next) {
write_region(wd, ar, sl->spacetype);
-
- if (sl->spacetype==SPACE_VIEW3D) {
- View3D *v3d= (View3D *) sl;
+ }
+
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
BGpic *bgpic;
- writestruct(wd, DATA, "View3D", 1, v3d);
- for (bgpic= v3d->bgpicbase.first; bgpic; bgpic= bgpic->next)
- writestruct(wd, DATA, "BGpic", 1, bgpic);
- if (v3d->localvd) writestruct(wd, DATA, "View3D", 1, v3d->localvd);
-
- if (v3d->fx_settings.ssao)
- writestruct(wd, DATA, "GPUSSAOSettings", 1, v3d->fx_settings.ssao);
- if (v3d->fx_settings.dof)
- writestruct(wd, DATA, "GPUDOFSettings", 1, v3d->fx_settings.dof);
- }
- else if (sl->spacetype==SPACE_IPO) {
- SpaceIpo *sipo= (SpaceIpo *)sl;
+ writestruct(wd, DATA, View3D, 1, v3d);
+ for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
+ writestruct(wd, DATA, BGpic, 1, bgpic);
+ }
+ if (v3d->localvd) {
+ writestruct(wd, DATA, View3D, 1, v3d->localvd);
+ }
+
+ if (v3d->fx_settings.ssao) {
+ writestruct(wd, DATA, GPUSSAOSettings, 1, v3d->fx_settings.ssao);
+ }
+ if (v3d->fx_settings.dof) {
+ writestruct(wd, DATA, GPUDOFSettings, 1, v3d->fx_settings.dof);
+ }
+ }
+ else if (sl->spacetype == SPACE_IPO) {
+ SpaceIpo *sipo = (SpaceIpo *)sl;
ListBase tmpGhosts = sipo->ghostCurves;
-
+
/* temporarily disable ghost curves when saving */
- sipo->ghostCurves.first= sipo->ghostCurves.last= NULL;
-
- writestruct(wd, DATA, "SpaceIpo", 1, sl);
- if (sipo->ads) writestruct(wd, DATA, "bDopeSheet", 1, sipo->ads);
-
+ sipo->ghostCurves.first = sipo->ghostCurves.last = NULL;
+
+ writestruct(wd, DATA, SpaceIpo, 1, sl);
+ if (sipo->ads) {
+ writestruct(wd, DATA, bDopeSheet, 1, sipo->ads);
+ }
+
/* reenable ghost curves */
- sipo->ghostCurves= tmpGhosts;
+ sipo->ghostCurves = tmpGhosts;
}
- else if (sl->spacetype==SPACE_BUTS) {
- writestruct(wd, DATA, "SpaceButs", 1, sl);
+ else if (sl->spacetype == SPACE_BUTS) {
+ writestruct(wd, DATA, SpaceButs, 1, sl);
}
- else if (sl->spacetype==SPACE_FILE) {
- SpaceFile *sfile= (SpaceFile *)sl;
+ else if (sl->spacetype == SPACE_FILE) {
+ SpaceFile *sfile = (SpaceFile *)sl;
- writestruct(wd, DATA, "SpaceFile", 1, sl);
- if (sfile->params)
- writestruct(wd, DATA, "FileSelectParams", 1, sfile->params);
+ writestruct(wd, DATA, SpaceFile, 1, sl);
+ if (sfile->params) {
+ writestruct(wd, DATA, FileSelectParams, 1, sfile->params);
+ }
}
- else if (sl->spacetype==SPACE_SEQ) {
- writestruct(wd, DATA, "SpaceSeq", 1, sl);
+ else if (sl->spacetype == SPACE_SEQ) {
+ writestruct(wd, DATA, SpaceSeq, 1, sl);
}
- else if (sl->spacetype==SPACE_OUTLINER) {
- SpaceOops *so= (SpaceOops *)sl;
- write_soops(wd, so, &tmp_mem_list);
+ else if (sl->spacetype == SPACE_OUTLINER) {
+ SpaceOops *so = (SpaceOops *)sl;
+ write_soops(wd, so);
}
- else if (sl->spacetype==SPACE_IMAGE) {
- SpaceImage *sima= (SpaceImage *)sl;
-
- writestruct(wd, DATA, "SpaceImage", 1, sl);
- if (sima->cumap)
- write_curvemapping(wd, sima->cumap);
+ else if (sl->spacetype == SPACE_IMAGE) {
+ writestruct(wd, DATA, SpaceImage, 1, sl);
}
- else if (sl->spacetype==SPACE_TEXT) {
- writestruct(wd, DATA, "SpaceText", 1, sl);
+ else if (sl->spacetype == SPACE_TEXT) {
+ writestruct(wd, DATA, SpaceText, 1, sl);
}
- else if (sl->spacetype==SPACE_SCRIPT) {
- SpaceScript *scr = (SpaceScript*)sl;
+ else if (sl->spacetype == SPACE_SCRIPT) {
+ SpaceScript *scr = (SpaceScript *)sl;
scr->but_refs = NULL;
- writestruct(wd, DATA, "SpaceScript", 1, sl);
+ writestruct(wd, DATA, SpaceScript, 1, sl);
}
- else if (sl->spacetype==SPACE_ACTION) {
- writestruct(wd, DATA, "SpaceAction", 1, sl);
+ else if (sl->spacetype == SPACE_ACTION) {
+ writestruct(wd, DATA, SpaceAction, 1, sl);
}
- else if (sl->spacetype==SPACE_NLA) {
- SpaceNla *snla= (SpaceNla *)sl;
-
- writestruct(wd, DATA, "SpaceNla", 1, snla);
- if (snla->ads) writestruct(wd, DATA, "bDopeSheet", 1, snla->ads);
+ else if (sl->spacetype == SPACE_NLA) {
+ SpaceNla *snla = (SpaceNla *)sl;
+
+ writestruct(wd, DATA, SpaceNla, 1, snla);
+ if (snla->ads) {
+ writestruct(wd, DATA, bDopeSheet, 1, snla->ads);
+ }
}
- else if (sl->spacetype==SPACE_TIME) {
- writestruct(wd, DATA, "SpaceTime", 1, sl);
+ else if (sl->spacetype == SPACE_TIME) {
+ writestruct(wd, DATA, SpaceTime, 1, sl);
}
- else if (sl->spacetype==SPACE_NODE) {
+ else if (sl->spacetype == SPACE_NODE) {
SpaceNode *snode = (SpaceNode *)sl;
bNodeTreePath *path;
- writestruct(wd, DATA, "SpaceNode", 1, snode);
-
- for (path=snode->treepath.first; path; path=path->next)
- writestruct(wd, DATA, "bNodeTreePath", 1, path);
+ writestruct(wd, DATA, SpaceNode, 1, snode);
+
+ for (path = snode->treepath.first; path; path = path->next) {
+ writestruct(wd, DATA, bNodeTreePath, 1, path);
+ }
}
- else if (sl->spacetype==SPACE_LOGIC) {
- writestruct(wd, DATA, "SpaceLogic", 1, sl);
+ else if (sl->spacetype == SPACE_LOGIC) {
+ writestruct(wd, DATA, SpaceLogic, 1, sl);
}
- else if (sl->spacetype==SPACE_CONSOLE) {
- SpaceConsole *con = (SpaceConsole*)sl;
+ else if (sl->spacetype == SPACE_CONSOLE) {
+ SpaceConsole *con = (SpaceConsole *)sl;
ConsoleLine *cl;
- for (cl=con->history.first; cl; cl=cl->next) {
+ for (cl = con->history.first; cl; cl = cl->next) {
/* 'len_alloc' is invalid on write, set from 'len' on read */
- writestruct(wd, DATA, "ConsoleLine", 1, cl);
- writedata(wd, DATA, cl->len+1, cl->line);
+ writestruct(wd, DATA, ConsoleLine, 1, cl);
+ writedata(wd, DATA, cl->len + 1, cl->line);
}
- writestruct(wd, DATA, "SpaceConsole", 1, sl);
+ writestruct(wd, DATA, SpaceConsole, 1, sl);
}
- else if (sl->spacetype==SPACE_USERPREF) {
- writestruct(wd, DATA, "SpaceUserPref", 1, sl);
+ else if (sl->spacetype == SPACE_USERPREF) {
+ writestruct(wd, DATA, SpaceUserPref, 1, sl);
}
- else if (sl->spacetype==SPACE_CLIP) {
- writestruct(wd, DATA, "SpaceClip", 1, sl);
+ else if (sl->spacetype == SPACE_CLIP) {
+ writestruct(wd, DATA, SpaceClip, 1, sl);
}
else if (sl->spacetype == SPACE_INFO) {
- writestruct(wd, DATA, "SpaceInfo", 1, sl);
+ writestruct(wd, DATA, SpaceInfo, 1, sl);
}
- sl= sl->next;
+ sl = sl->next;
}
}
- sc= sc->id.next;
+ sc = sc->id.next;
}
- BLI_linklist_freeN(tmp_mem_list);
-
- /* flush helps the compression for undo-save */
- mywrite(wd, MYWRITE_FLUSH, 0);
-}
-
-static void write_libraries(WriteData *wd, Main *main)
-{
- ListBase *lbarray[MAX_LIBARRAY];
- ID *id;
- int a, tot;
- bool found_one;
-
- for (; main; main= main->next) {
-
- a=tot= set_listbasepointers(main, lbarray);
-
- /* test: is lib being used */
- if (main->curlib && main->curlib->packedfile)
- found_one = true;
- else {
- found_one = false;
- while (tot--) {
- for (id= lbarray[tot]->first; id; id= id->next) {
- if (id->us > 0 && (id->tag & LIB_TAG_EXTERN)) {
- found_one = true;
- break;
- }
- }
- if (found_one) break;
- }
- }
-
- /* to be able to restore quit.blend and temp saves, the packed blend has to be in undo buffers... */
- /* XXX needs rethink, just like save UI in undo files now - would be nice to append things only for the]
- * quit.blend and temp saves */
- if (found_one) {
- writestruct(wd, ID_LI, "Library", 1, main->curlib);
-
- if (main->curlib->packedfile) {
- PackedFile *pf = main->curlib->packedfile;
- writestruct(wd, DATA, "PackedFile", 1, pf);
- writedata(wd, DATA, pf->size, pf->data);
- if (wd->current == NULL)
- printf("write packed .blend: %s\n", main->curlib->name);
- }
-
- while (a--) {
- for (id= lbarray[a]->first; id; id= id->next) {
- if (id->us > 0 && (id->tag & LIB_TAG_EXTERN)) {
- if (!BKE_idcode_is_linkable(GS(id->name))) {
- printf("ERROR: write file: datablock '%s' from lib '%s' is not linkable "
- "but is flagged as directly linked", id->name, main->curlib->filepath);
- BLI_assert(0);
- }
- writestruct(wd, ID_ID, "ID", 1, id);
- }
- }
- }
- }
- }
+ mywrite_flush(wd);
}
static void write_bone(WriteData *wd, Bone *bone)
{
- Bone* cbone;
-
- // PATCH for upward compatibility after 2.37+ armature recode
+ /* PATCH for upward compatibility after 2.37+ armature recode */
bone->size[0] = bone->size[1] = bone->size[2] = 1.0f;
-
- // Write this bone
- writestruct(wd, DATA, "Bone", 1, bone);
+
+ /* Write this bone */
+ writestruct(wd, DATA, Bone, 1, bone);
/* Write ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
- if (bone->prop)
+ if (bone->prop) {
IDP_WriteProperty(bone->prop, wd);
-
- // Write Children
- cbone= bone->childbase.first;
- while (cbone) {
+ }
+
+ /* Write Children */
+ for (Bone *cbone = bone->childbase.first; cbone; cbone = cbone->next) {
write_bone(wd, cbone);
- cbone= cbone->next;
}
}
static void write_armatures(WriteData *wd, ListBase *idbase)
{
- bArmature *arm;
- Bone *bone;
+ bArmature *arm;
+ Bone *bone;
- arm=idbase->first;
+ arm = idbase->first;
while (arm) {
- if (arm->id.us>0 || wd->current) {
- writestruct(wd, ID_AR, "bArmature", 1, arm);
- if (arm->id.properties) IDP_WriteProperty(arm->id.properties, wd);
+ if (arm->id.us > 0 || wd->current) {
+ writestruct(wd, ID_AR, bArmature, 1, arm);
+ write_iddata(wd, &arm->id);
- if (arm->adt) write_animdata(wd, arm->adt);
+ if (arm->adt) {
+ write_animdata(wd, arm->adt);
+ }
/* Direct data */
- bone= arm->bonebase.first;
+ bone = arm->bonebase.first;
while (bone) {
write_bone(wd, bone);
- bone=bone->next;
+ bone = bone->next;
}
}
- arm=arm->id.next;
+ arm = arm->id.next;
}
- /* flush helps the compression for undo-save */
- mywrite(wd, MYWRITE_FLUSH, 0);
+ mywrite_flush(wd);
}
static void write_texts(WriteData *wd, ListBase *idbase)
@@ -3006,52 +3220,58 @@ static void write_texts(WriteData *wd, ListBase *idbase)
Text *text;
TextLine *tmp;
- text= idbase->first;
+ text = idbase->first;
while (text) {
- if ( (text->flags & TXT_ISMEM) && (text->flags & TXT_ISEXT)) text->flags &= ~TXT_ISEXT;
+ if ( (text->flags & TXT_ISMEM) && (text->flags & TXT_ISEXT)) {
+ text->flags &= ~TXT_ISEXT;
+ }
/* write LibData */
- writestruct(wd, ID_TXT, "Text", 1, text);
- if (text->name) writedata(wd, DATA, strlen(text->name)+1, text->name);
- if (text->id.properties) IDP_WriteProperty(text->id.properties, wd);
+ writestruct(wd, ID_TXT, Text, 1, text);
+ write_iddata(wd, &text->id);
+
+ if (text->name) {
+ writedata(wd, DATA, strlen(text->name) + 1, text->name);
+ }
if (!(text->flags & TXT_ISEXT)) {
/* now write the text data, in two steps for optimization in the readfunction */
- tmp= text->lines.first;
+ tmp = text->lines.first;
while (tmp) {
- writestruct(wd, DATA, "TextLine", 1, tmp);
- tmp= tmp->next;
+ writestruct(wd, DATA, TextLine, 1, tmp);
+ tmp = tmp->next;
}
- tmp= text->lines.first;
+ tmp = text->lines.first;
while (tmp) {
- writedata(wd, DATA, tmp->len+1, tmp->line);
- tmp= tmp->next;
+ writedata(wd, DATA, tmp->len + 1, tmp->line);
+ tmp = tmp->next;
}
}
- text= text->id.next;
+ text = text->id.next;
}
- /* flush helps the compression for undo-save */
- mywrite(wd, MYWRITE_FLUSH, 0);
+ mywrite_flush(wd);
}
static void write_speakers(WriteData *wd, ListBase *idbase)
{
Speaker *spk;
- spk= idbase->first;
+ spk = idbase->first;
while (spk) {
- if (spk->id.us>0 || wd->current) {
+ if (spk->id.us > 0 || wd->current) {
/* write LibData */
- writestruct(wd, ID_SPK, "Speaker", 1, spk);
- if (spk->id.properties) IDP_WriteProperty(spk->id.properties, wd);
+ writestruct(wd, ID_SPK, Speaker, 1, spk);
+ write_iddata(wd, &spk->id);
- if (spk->adt) write_animdata(wd, spk->adt);
+ if (spk->adt) {
+ write_animdata(wd, spk->adt);
+ }
}
- spk= spk->id.next;
+ spk = spk->id.next;
}
}
@@ -3059,26 +3279,25 @@ static void write_sounds(WriteData *wd, ListBase *idbase)
{
bSound *sound;
- PackedFile * pf;
+ PackedFile *pf;
- sound= idbase->first;
+ sound = idbase->first;
while (sound) {
- if (sound->id.us>0 || wd->current) {
+ if (sound->id.us > 0 || wd->current) {
/* write LibData */
- writestruct(wd, ID_SO, "bSound", 1, sound);
- if (sound->id.properties) IDP_WriteProperty(sound->id.properties, wd);
+ writestruct(wd, ID_SO, bSound, 1, sound);
+ write_iddata(wd, &sound->id);
if (sound->packedfile) {
pf = sound->packedfile;
- writestruct(wd, DATA, "PackedFile", 1, pf);
+ writestruct(wd, DATA, PackedFile, 1, pf);
writedata(wd, DATA, pf->size, pf->data);
}
}
- sound= sound->id.next;
+ sound = sound->id.next;
}
- /* flush helps the compression for undo-save */
- mywrite(wd, MYWRITE_FLUSH, 0);
+ mywrite_flush(wd);
}
static void write_groups(WriteData *wd, ListBase *idbase)
@@ -3086,35 +3305,37 @@ static void write_groups(WriteData *wd, ListBase *idbase)
Group *group;
GroupObject *go;
- for (group= idbase->first; group; group= group->id.next) {
- if (group->id.us>0 || wd->current) {
+ for (group = idbase->first; group; group = group->id.next) {
+ if (group->id.us > 0 || wd->current) {
/* write LibData */
- writestruct(wd, ID_GR, "Group", 1, group);
- if (group->id.properties) IDP_WriteProperty(group->id.properties, wd);
+ writestruct(wd, ID_GR, Group, 1, group);
+ write_iddata(wd, &group->id);
write_previews(wd, group->preview);
- go= group->gobject.first;
+ go = group->gobject.first;
while (go) {
- writestruct(wd, DATA, "GroupObject", 1, go);
- go= go->next;
+ writestruct(wd, DATA, GroupObject, 1, go);
+ go = go->next;
}
}
}
+
+ mywrite_flush(wd);
}
static void write_nodetrees(WriteData *wd, ListBase *idbase)
{
bNodeTree *ntree;
-
- for (ntree=idbase->first; ntree; ntree= ntree->id.next) {
- if (ntree->id.us>0 || wd->current) {
- writestruct(wd, ID_NT, "bNodeTree", 1, ntree);
+
+ for (ntree = idbase->first; ntree; ntree = ntree->id.next) {
+ if (ntree->id.us > 0 || wd->current) {
+ writestruct(wd, ID_NT, bNodeTree, 1, ntree);
+ /* Note that trees directly used by other IDs (materials etc.) are not 'real' ID, they cannot
+ * be linked, etc., so we write actual id data here only, for 'real' ID trees. */
+ write_iddata(wd, &ntree->id);
+
write_nodetree(wd, ntree);
-
- if (ntree->id.properties) IDP_WriteProperty(ntree->id.properties, wd);
-
- if (ntree->adt) write_animdata(wd, ntree->adt);
}
}
}
@@ -3124,11 +3345,12 @@ static void customnodes_add_deprecated_data(Main *mainvar)
{
FOREACH_NODETREE(mainvar, ntree, id) {
bNodeLink *link, *last_link = ntree->links.last;
-
+
/* only do this for node groups */
- if (id != &ntree->id)
+ if (id != &ntree->id) {
continue;
-
+ }
+
/* Forward compatibility for group nodes: add links to node tree interface sockets.
* These links are invalid by new rules (missing node pointer)!
* They will be removed again in customnodes_free_deprecated_data,
@@ -3139,7 +3361,7 @@ static void customnodes_add_deprecated_data(Main *mainvar)
for (link = ntree->links.first; link; link = link->next) {
bNode *fromnode = link->fromnode, *tonode = link->tonode;
bNodeSocket *fromsock = link->fromsock, *tosock = link->tosock;
-
+
/* check both sides of the link, to handle direct input-to-output links */
if (fromnode->type == NODE_GROUP_INPUT) {
fromnode = NULL;
@@ -3150,22 +3372,23 @@ static void customnodes_add_deprecated_data(Main *mainvar)
tonode = NULL;
tosock = ntreeFindSocketInterface(ntree, SOCK_OUT, tosock->identifier);
}
-
+
if (!fromnode || !tonode) {
/* Note: not using nodeAddLink here, it asserts existing node pointers */
bNodeLink *tlink = MEM_callocN(sizeof(bNodeLink), "group node link");
tlink->fromnode = fromnode;
tlink->fromsock = fromsock;
tlink->tonode = tonode;
- tlink->tosock= tosock;
+ tlink->tosock = tosock;
tosock->link = tlink;
tlink->flag |= NODE_LINK_VALID;
BLI_addtail(&ntree->links, tlink);
}
-
+
/* don't check newly created compatibility links */
- if (link == last_link)
+ if (link == last_link) {
break;
+ }
}
}
FOREACH_NODETREE_END
@@ -3175,11 +3398,12 @@ static void customnodes_free_deprecated_data(Main *mainvar)
{
FOREACH_NODETREE(mainvar, ntree, id) {
bNodeLink *link, *next_link;
-
+
for (link = ntree->links.first; link; link = next_link) {
next_link = link->next;
- if (link->fromnode == NULL || link->tonode == NULL)
+ if (link->fromnode == NULL || link->tonode == NULL) {
nodeRemLink(ntree, link);
+ }
}
}
FOREACH_NODETREE_END
@@ -3189,16 +3413,18 @@ static void customnodes_free_deprecated_data(Main *mainvar)
static void write_brushes(WriteData *wd, ListBase *idbase)
{
Brush *brush;
-
- for (brush=idbase->first; brush; brush= brush->id.next) {
- if (brush->id.us>0 || wd->current) {
- writestruct(wd, ID_BR, "Brush", 1, brush);
- if (brush->id.properties) IDP_WriteProperty(brush->id.properties, wd);
-
- if (brush->curve)
+
+ for (brush = idbase->first; brush; brush = brush->id.next) {
+ if (brush->id.us > 0 || wd->current) {
+ writestruct(wd, ID_BR, Brush, 1, brush);
+ write_iddata(wd, &brush->id);
+
+ if (brush->curve) {
write_curvemapping(wd, brush->curve);
- if (brush->gradient)
- writestruct(wd, DATA, "ColorBand", 1, brush->gradient);
+ }
+ if (brush->gradient) {
+ writestruct(wd, DATA, ColorBand, 1, brush->gradient);
+ }
}
}
}
@@ -3210,11 +3436,12 @@ static void write_palettes(WriteData *wd, ListBase *idbase)
for (palette = idbase->first; palette; palette = palette->id.next) {
if (palette->id.us > 0 || wd->current) {
PaletteColor *color;
- writestruct(wd, ID_PAL, "Palette", 1, palette);
- if (palette->id.properties) IDP_WriteProperty(palette->id.properties, wd);
+ writestruct(wd, ID_PAL, Palette, 1, palette);
+ write_iddata(wd, &palette->id);
- for (color = palette->colors.first; color; color= color->next)
- writestruct(wd, DATA, "PaletteColor", 1, color);
+ for (color = palette->colors.first; color; color = color->next) {
+ writestruct(wd, DATA, PaletteColor, 1, color);
+ }
}
}
}
@@ -3225,10 +3452,10 @@ static void write_paintcurves(WriteData *wd, ListBase *idbase)
for (pc = idbase->first; pc; pc = pc->id.next) {
if (pc->id.us > 0 || wd->current) {
- writestruct(wd, ID_PC, "PaintCurve", 1, pc);
+ writestruct(wd, ID_PC, PaintCurve, 1, pc);
+ write_iddata(wd, &pc->id);
- writestruct(wd, DATA, "PaintCurvePoint", pc->tot_points, pc->points);
- if (pc->id.properties) IDP_WriteProperty(pc->id.properties, wd);
+ writestruct(wd, DATA, PaintCurvePoint, pc->tot_points, pc->points);
}
}
}
@@ -3237,14 +3464,15 @@ static void write_movieTracks(WriteData *wd, ListBase *tracks)
{
MovieTrackingTrack *track;
- track= tracks->first;
+ track = tracks->first;
while (track) {
- writestruct(wd, DATA, "MovieTrackingTrack", 1, track);
+ writestruct(wd, DATA, MovieTrackingTrack, 1, track);
- if (track->markers)
- writestruct(wd, DATA, "MovieTrackingMarker", track->markersnr, track->markers);
+ if (track->markers) {
+ writestruct(wd, DATA, MovieTrackingMarker, track->markersnr, track->markers);
+ }
- track= track->next;
+ track = track->next;
}
}
@@ -3256,57 +3484,57 @@ static void write_moviePlaneTracks(WriteData *wd, ListBase *plane_tracks_base)
plane_track;
plane_track = plane_track->next)
{
- writestruct(wd, DATA, "MovieTrackingPlaneTrack", 1, plane_track);
+ writestruct(wd, DATA, MovieTrackingPlaneTrack, 1, plane_track);
writedata(wd, DATA, sizeof(MovieTrackingTrack *) * plane_track->point_tracksnr, plane_track->point_tracks);
- writestruct(wd, DATA, "MovieTrackingPlaneMarker", plane_track->markersnr, plane_track->markers);
+ writestruct(wd, DATA, MovieTrackingPlaneMarker, plane_track->markersnr, plane_track->markers);
}
}
static void write_movieReconstruction(WriteData *wd, MovieTrackingReconstruction *reconstruction)
{
- if (reconstruction->camnr)
- writestruct(wd, DATA, "MovieReconstructedCamera", reconstruction->camnr, reconstruction->cameras);
+ if (reconstruction->camnr) {
+ writestruct(wd, DATA, MovieReconstructedCamera, reconstruction->camnr, reconstruction->cameras);
+ }
}
static void write_movieclips(WriteData *wd, ListBase *idbase)
{
MovieClip *clip;
- clip= idbase->first;
+ clip = idbase->first;
while (clip) {
- if (clip->id.us>0 || wd->current) {
- MovieTracking *tracking= &clip->tracking;
+ if (clip->id.us > 0 || wd->current) {
+ MovieTracking *tracking = &clip->tracking;
MovieTrackingObject *object;
- writestruct(wd, ID_MC, "MovieClip", 1, clip);
- if (clip->id.properties)
- IDP_WriteProperty(clip->id.properties, wd);
+ writestruct(wd, ID_MC, MovieClip, 1, clip);
+ write_iddata(wd, &clip->id);
- if (clip->adt)
+ if (clip->adt) {
write_animdata(wd, clip->adt);
+ }
write_movieTracks(wd, &tracking->tracks);
write_moviePlaneTracks(wd, &tracking->plane_tracks);
write_movieReconstruction(wd, &tracking->reconstruction);
- object= tracking->objects.first;
+ object = tracking->objects.first;
while (object) {
- writestruct(wd, DATA, "MovieTrackingObject", 1, object);
+ writestruct(wd, DATA, MovieTrackingObject, 1, object);
write_movieTracks(wd, &object->tracks);
write_moviePlaneTracks(wd, &object->plane_tracks);
write_movieReconstruction(wd, &object->reconstruction);
- object= object->next;
+ object = object->next;
}
}
- clip= clip->id.next;
+ clip = clip->id.next;
}
- /* flush helps the compression for undo-save */
- mywrite(wd, MYWRITE_FLUSH, 0);
+ mywrite_flush(wd);
}
static void write_masks(WriteData *wd, ListBase *idbase)
@@ -3318,16 +3546,18 @@ static void write_masks(WriteData *wd, ListBase *idbase)
if (mask->id.us > 0 || wd->current) {
MaskLayer *masklay;
- writestruct(wd, ID_MSK, "Mask", 1, mask);
+ writestruct(wd, ID_MSK, Mask, 1, mask);
+ write_iddata(wd, &mask->id);
- if (mask->adt)
+ if (mask->adt) {
write_animdata(wd, mask->adt);
+ }
for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
MaskSpline *spline;
MaskLayerShape *masklay_shape;
- writestruct(wd, DATA, "MaskLayer", 1, masklay);
+ writestruct(wd, DATA, MaskLayer, 1, masklay);
for (spline = masklay->splines.first; spline; spline = spline->next) {
int i;
@@ -3335,22 +3565,28 @@ static void write_masks(WriteData *wd, ListBase *idbase)
void *points_deform = spline->points_deform;
spline->points_deform = NULL;
- writestruct(wd, DATA, "MaskSpline", 1, spline);
- writestruct(wd, DATA, "MaskSplinePoint", spline->tot_point, spline->points);
+ writestruct(wd, DATA, MaskSpline, 1, spline);
+ writestruct(wd, DATA, MaskSplinePoint, spline->tot_point, spline->points);
spline->points_deform = points_deform;
for (i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
- if (point->tot_uw)
- writestruct(wd, DATA, "MaskSplinePointUW", point->tot_uw, point->uw);
+ if (point->tot_uw) {
+ writestruct(wd, DATA, MaskSplinePointUW, point->tot_uw, point->uw);
+ }
}
}
- for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) {
- writestruct(wd, DATA, "MaskLayerShape", 1, masklay_shape);
- writedata(wd, DATA, masklay_shape->tot_vert * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE, masklay_shape->data);
+ for (masklay_shape = masklay->splines_shapes.first;
+ masklay_shape;
+ masklay_shape = masklay_shape->next)
+ {
+ writestruct(wd, DATA, MaskLayerShape, 1, masklay_shape);
+ writedata(wd, DATA,
+ masklay_shape->tot_vert * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE,
+ masklay_shape->data);
}
}
}
@@ -3358,72 +3594,71 @@ static void write_masks(WriteData *wd, ListBase *idbase)
mask = mask->id.next;
}
- /* flush helps the compression for undo-save */
- mywrite(wd, MYWRITE_FLUSH, 0);
+ mywrite_flush(wd);
}
static void write_linestyle_color_modifiers(WriteData *wd, ListBase *modifiers)
{
LineStyleModifier *m;
- const char *struct_name;
for (m = modifiers->first; m; m = m->next) {
+ int struct_nr;
switch (m->type) {
- case LS_MODIFIER_ALONG_STROKE:
- struct_name = "LineStyleColorModifier_AlongStroke";
- break;
- case LS_MODIFIER_DISTANCE_FROM_CAMERA:
- struct_name = "LineStyleColorModifier_DistanceFromCamera";
- break;
- case LS_MODIFIER_DISTANCE_FROM_OBJECT:
- struct_name = "LineStyleColorModifier_DistanceFromObject";
- break;
- case LS_MODIFIER_MATERIAL:
- struct_name = "LineStyleColorModifier_Material";
- break;
- case LS_MODIFIER_TANGENT:
- struct_name = "LineStyleColorModifier_Tangent";
- break;
- case LS_MODIFIER_NOISE:
- struct_name = "LineStyleColorModifier_Noise";
- break;
- case LS_MODIFIER_CREASE_ANGLE:
- struct_name = "LineStyleColorModifier_CreaseAngle";
- break;
- case LS_MODIFIER_CURVATURE_3D:
- struct_name = "LineStyleColorModifier_Curvature_3D";
- break;
- default:
- struct_name = "LineStyleColorModifier"; /* this should not happen */
+ case LS_MODIFIER_ALONG_STROKE:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_AlongStroke);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_DistanceFromCamera);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_DistanceFromObject);
+ break;
+ case LS_MODIFIER_MATERIAL:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_Material);
+ break;
+ case LS_MODIFIER_TANGENT:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_Tangent);
+ break;
+ case LS_MODIFIER_NOISE:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_Noise);
+ break;
+ case LS_MODIFIER_CREASE_ANGLE:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_CreaseAngle);
+ break;
+ case LS_MODIFIER_CURVATURE_3D:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_Curvature_3D);
+ break;
+ default:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleModifier); /* this should not happen */
}
- writestruct(wd, DATA, struct_name, 1, m);
+ writestruct_nr(wd, DATA, struct_nr, 1, m);
}
for (m = modifiers->first; m; m = m->next) {
switch (m->type) {
- case LS_MODIFIER_ALONG_STROKE:
- writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_AlongStroke *)m)->color_ramp);
- break;
- case LS_MODIFIER_DISTANCE_FROM_CAMERA:
- writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_DistanceFromCamera *)m)->color_ramp);
- break;
- case LS_MODIFIER_DISTANCE_FROM_OBJECT:
- writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_DistanceFromObject *)m)->color_ramp);
- break;
- case LS_MODIFIER_MATERIAL:
- writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_Material *)m)->color_ramp);
- break;
- case LS_MODIFIER_TANGENT:
- writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_Tangent *)m)->color_ramp);
- break;
- case LS_MODIFIER_NOISE:
- writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_Noise *)m)->color_ramp);
- break;
- case LS_MODIFIER_CREASE_ANGLE:
- writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_CreaseAngle *)m)->color_ramp);
- break;
- case LS_MODIFIER_CURVATURE_3D:
- writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_Curvature_3D *)m)->color_ramp);
- break;
+ case LS_MODIFIER_ALONG_STROKE:
+ writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_AlongStroke *)m)->color_ramp);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_DistanceFromCamera *)m)->color_ramp);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_DistanceFromObject *)m)->color_ramp);
+ break;
+ case LS_MODIFIER_MATERIAL:
+ writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_Material *)m)->color_ramp);
+ break;
+ case LS_MODIFIER_TANGENT:
+ writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_Tangent *)m)->color_ramp);
+ break;
+ case LS_MODIFIER_NOISE:
+ writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_Noise *)m)->color_ramp);
+ break;
+ case LS_MODIFIER_CREASE_ANGLE:
+ writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_CreaseAngle *)m)->color_ramp);
+ break;
+ case LS_MODIFIER_CURVATURE_3D:
+ writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_Curvature_3D *)m)->color_ramp);
+ break;
}
}
}
@@ -3431,65 +3666,65 @@ static void write_linestyle_color_modifiers(WriteData *wd, ListBase *modifiers)
static void write_linestyle_alpha_modifiers(WriteData *wd, ListBase *modifiers)
{
LineStyleModifier *m;
- const char *struct_name;
for (m = modifiers->first; m; m = m->next) {
+ int struct_nr;
switch (m->type) {
- case LS_MODIFIER_ALONG_STROKE:
- struct_name = "LineStyleAlphaModifier_AlongStroke";
- break;
- case LS_MODIFIER_DISTANCE_FROM_CAMERA:
- struct_name = "LineStyleAlphaModifier_DistanceFromCamera";
- break;
- case LS_MODIFIER_DISTANCE_FROM_OBJECT:
- struct_name = "LineStyleAlphaModifier_DistanceFromObject";
- break;
- case LS_MODIFIER_MATERIAL:
- struct_name = "LineStyleAlphaModifier_Material";
- break;
- case LS_MODIFIER_TANGENT:
- struct_name = "LineStyleAlphaModifier_Tangent";
- break;
- case LS_MODIFIER_NOISE:
- struct_name = "LineStyleAlphaModifier_Noise";
- break;
- case LS_MODIFIER_CREASE_ANGLE:
- struct_name = "LineStyleAlphaModifier_CreaseAngle";
- break;
- case LS_MODIFIER_CURVATURE_3D:
- struct_name = "LineStyleAlphaModifier_Curvature_3D";
- break;
- default:
- struct_name = "LineStyleAlphaModifier"; /* this should not happen */
+ case LS_MODIFIER_ALONG_STROKE:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_AlongStroke);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_DistanceFromCamera);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_DistanceFromObject);
+ break;
+ case LS_MODIFIER_MATERIAL:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_Material);
+ break;
+ case LS_MODIFIER_TANGENT:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_Tangent);
+ break;
+ case LS_MODIFIER_NOISE:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_Noise);
+ break;
+ case LS_MODIFIER_CREASE_ANGLE:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_CreaseAngle);
+ break;
+ case LS_MODIFIER_CURVATURE_3D:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_Curvature_3D);
+ break;
+ default:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleModifier); /* this should not happen */
}
- writestruct(wd, DATA, struct_name, 1, m);
+ writestruct_nr(wd, DATA, struct_nr, 1, m);
}
for (m = modifiers->first; m; m = m->next) {
switch (m->type) {
- case LS_MODIFIER_ALONG_STROKE:
- write_curvemapping(wd, ((LineStyleAlphaModifier_AlongStroke *)m)->curve);
- break;
- case LS_MODIFIER_DISTANCE_FROM_CAMERA:
- write_curvemapping(wd, ((LineStyleAlphaModifier_DistanceFromCamera *)m)->curve);
- break;
- case LS_MODIFIER_DISTANCE_FROM_OBJECT:
- write_curvemapping(wd, ((LineStyleAlphaModifier_DistanceFromObject *)m)->curve);
- break;
- case LS_MODIFIER_MATERIAL:
- write_curvemapping(wd, ((LineStyleAlphaModifier_Material *)m)->curve);
- break;
- case LS_MODIFIER_TANGENT:
- write_curvemapping(wd, ((LineStyleAlphaModifier_Tangent *)m)->curve);
- break;
- case LS_MODIFIER_NOISE:
- write_curvemapping(wd, ((LineStyleAlphaModifier_Noise *)m)->curve);
- break;
- case LS_MODIFIER_CREASE_ANGLE:
- write_curvemapping(wd, ((LineStyleAlphaModifier_CreaseAngle *)m)->curve);
- break;
- case LS_MODIFIER_CURVATURE_3D:
- write_curvemapping(wd, ((LineStyleAlphaModifier_Curvature_3D *)m)->curve);
- break;
+ case LS_MODIFIER_ALONG_STROKE:
+ write_curvemapping(wd, ((LineStyleAlphaModifier_AlongStroke *)m)->curve);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ write_curvemapping(wd, ((LineStyleAlphaModifier_DistanceFromCamera *)m)->curve);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ write_curvemapping(wd, ((LineStyleAlphaModifier_DistanceFromObject *)m)->curve);
+ break;
+ case LS_MODIFIER_MATERIAL:
+ write_curvemapping(wd, ((LineStyleAlphaModifier_Material *)m)->curve);
+ break;
+ case LS_MODIFIER_TANGENT:
+ write_curvemapping(wd, ((LineStyleAlphaModifier_Tangent *)m)->curve);
+ break;
+ case LS_MODIFIER_NOISE:
+ write_curvemapping(wd, ((LineStyleAlphaModifier_Noise *)m)->curve);
+ break;
+ case LS_MODIFIER_CREASE_ANGLE:
+ write_curvemapping(wd, ((LineStyleAlphaModifier_CreaseAngle *)m)->curve);
+ break;
+ case LS_MODIFIER_CURVATURE_3D:
+ write_curvemapping(wd, ((LineStyleAlphaModifier_Curvature_3D *)m)->curve);
+ break;
}
}
}
@@ -3497,65 +3732,65 @@ static void write_linestyle_alpha_modifiers(WriteData *wd, ListBase *modifiers)
static void write_linestyle_thickness_modifiers(WriteData *wd, ListBase *modifiers)
{
LineStyleModifier *m;
- const char *struct_name;
for (m = modifiers->first; m; m = m->next) {
+ int struct_nr;
switch (m->type) {
- case LS_MODIFIER_ALONG_STROKE:
- struct_name = "LineStyleThicknessModifier_AlongStroke";
- break;
- case LS_MODIFIER_DISTANCE_FROM_CAMERA:
- struct_name = "LineStyleThicknessModifier_DistanceFromCamera";
- break;
- case LS_MODIFIER_DISTANCE_FROM_OBJECT:
- struct_name = "LineStyleThicknessModifier_DistanceFromObject";
- break;
- case LS_MODIFIER_MATERIAL:
- struct_name = "LineStyleThicknessModifier_Material";
- break;
- case LS_MODIFIER_CALLIGRAPHY:
- struct_name = "LineStyleThicknessModifier_Calligraphy";
- break;
- case LS_MODIFIER_TANGENT:
- struct_name = "LineStyleThicknessModifier_Tangent";
- break;
- case LS_MODIFIER_NOISE:
- struct_name = "LineStyleThicknessModifier_Noise";
- break;
- case LS_MODIFIER_CREASE_ANGLE:
- struct_name = "LineStyleThicknessModifier_CreaseAngle";
- break;
- case LS_MODIFIER_CURVATURE_3D:
- struct_name = "LineStyleThicknessModifier_Curvature_3D";
- break;
- default:
- struct_name = "LineStyleThicknessModifier"; /* this should not happen */
+ case LS_MODIFIER_ALONG_STROKE:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_AlongStroke);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_DistanceFromCamera);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_DistanceFromObject);
+ break;
+ case LS_MODIFIER_MATERIAL:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_Material);
+ break;
+ case LS_MODIFIER_CALLIGRAPHY:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_Calligraphy);
+ break;
+ case LS_MODIFIER_TANGENT:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_Tangent);
+ break;
+ case LS_MODIFIER_NOISE:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_Noise);
+ break;
+ case LS_MODIFIER_CREASE_ANGLE:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_CreaseAngle);
+ break;
+ case LS_MODIFIER_CURVATURE_3D:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_Curvature_3D);
+ break;
+ default:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleModifier); /* this should not happen */
}
- writestruct(wd, DATA, struct_name, 1, m);
+ writestruct_nr(wd, DATA, struct_nr, 1, m);
}
for (m = modifiers->first; m; m = m->next) {
switch (m->type) {
- case LS_MODIFIER_ALONG_STROKE:
- write_curvemapping(wd, ((LineStyleThicknessModifier_AlongStroke *)m)->curve);
- break;
- case LS_MODIFIER_DISTANCE_FROM_CAMERA:
- write_curvemapping(wd, ((LineStyleThicknessModifier_DistanceFromCamera *)m)->curve);
- break;
- case LS_MODIFIER_DISTANCE_FROM_OBJECT:
- write_curvemapping(wd, ((LineStyleThicknessModifier_DistanceFromObject *)m)->curve);
- break;
- case LS_MODIFIER_MATERIAL:
- write_curvemapping(wd, ((LineStyleThicknessModifier_Material *)m)->curve);
- break;
- case LS_MODIFIER_TANGENT:
- write_curvemapping(wd, ((LineStyleThicknessModifier_Tangent *)m)->curve);
- break;
- case LS_MODIFIER_CREASE_ANGLE:
- write_curvemapping(wd, ((LineStyleThicknessModifier_CreaseAngle *)m)->curve);
- break;
- case LS_MODIFIER_CURVATURE_3D:
- write_curvemapping(wd, ((LineStyleThicknessModifier_Curvature_3D *)m)->curve);
- break;
+ case LS_MODIFIER_ALONG_STROKE:
+ write_curvemapping(wd, ((LineStyleThicknessModifier_AlongStroke *)m)->curve);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ write_curvemapping(wd, ((LineStyleThicknessModifier_DistanceFromCamera *)m)->curve);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ write_curvemapping(wd, ((LineStyleThicknessModifier_DistanceFromObject *)m)->curve);
+ break;
+ case LS_MODIFIER_MATERIAL:
+ write_curvemapping(wd, ((LineStyleThicknessModifier_Material *)m)->curve);
+ break;
+ case LS_MODIFIER_TANGENT:
+ write_curvemapping(wd, ((LineStyleThicknessModifier_Tangent *)m)->curve);
+ break;
+ case LS_MODIFIER_CREASE_ANGLE:
+ write_curvemapping(wd, ((LineStyleThicknessModifier_CreaseAngle *)m)->curve);
+ break;
+ case LS_MODIFIER_CURVATURE_3D:
+ write_curvemapping(wd, ((LineStyleThicknessModifier_Curvature_3D *)m)->curve);
+ break;
}
}
}
@@ -3563,56 +3798,56 @@ static void write_linestyle_thickness_modifiers(WriteData *wd, ListBase *modifie
static void write_linestyle_geometry_modifiers(WriteData *wd, ListBase *modifiers)
{
LineStyleModifier *m;
- const char *struct_name;
for (m = modifiers->first; m; m = m->next) {
+ int struct_nr;
switch (m->type) {
- case LS_MODIFIER_SAMPLING:
- struct_name = "LineStyleGeometryModifier_Sampling";
- break;
- case LS_MODIFIER_BEZIER_CURVE:
- struct_name = "LineStyleGeometryModifier_BezierCurve";
- break;
- case LS_MODIFIER_SINUS_DISPLACEMENT:
- struct_name = "LineStyleGeometryModifier_SinusDisplacement";
- break;
- case LS_MODIFIER_SPATIAL_NOISE:
- struct_name = "LineStyleGeometryModifier_SpatialNoise";
- break;
- case LS_MODIFIER_PERLIN_NOISE_1D:
- struct_name = "LineStyleGeometryModifier_PerlinNoise1D";
- break;
- case LS_MODIFIER_PERLIN_NOISE_2D:
- struct_name = "LineStyleGeometryModifier_PerlinNoise2D";
- break;
- case LS_MODIFIER_BACKBONE_STRETCHER:
- struct_name = "LineStyleGeometryModifier_BackboneStretcher";
- break;
- case LS_MODIFIER_TIP_REMOVER:
- struct_name = "LineStyleGeometryModifier_TipRemover";
- break;
- case LS_MODIFIER_POLYGONIZATION:
- struct_name = "LineStyleGeometryModifier_Polygonalization";
- break;
- case LS_MODIFIER_GUIDING_LINES:
- struct_name = "LineStyleGeometryModifier_GuidingLines";
- break;
- case LS_MODIFIER_BLUEPRINT:
- struct_name = "LineStyleGeometryModifier_Blueprint";
- break;
- case LS_MODIFIER_2D_OFFSET:
- struct_name = "LineStyleGeometryModifier_2DOffset";
- break;
- case LS_MODIFIER_2D_TRANSFORM:
- struct_name = "LineStyleGeometryModifier_2DTransform";
- break;
- case LS_MODIFIER_SIMPLIFICATION:
- struct_name = "LineStyleGeometryModifier_Simplification";
- break;
- default:
- struct_name = "LineStyleGeometryModifier"; /* this should not happen */
+ case LS_MODIFIER_SAMPLING:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_Sampling);
+ break;
+ case LS_MODIFIER_BEZIER_CURVE:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_BezierCurve);
+ break;
+ case LS_MODIFIER_SINUS_DISPLACEMENT:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_SinusDisplacement);
+ break;
+ case LS_MODIFIER_SPATIAL_NOISE:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_SpatialNoise);
+ break;
+ case LS_MODIFIER_PERLIN_NOISE_1D:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_PerlinNoise1D);
+ break;
+ case LS_MODIFIER_PERLIN_NOISE_2D:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_PerlinNoise2D);
+ break;
+ case LS_MODIFIER_BACKBONE_STRETCHER:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_BackboneStretcher);
+ break;
+ case LS_MODIFIER_TIP_REMOVER:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_TipRemover);
+ break;
+ case LS_MODIFIER_POLYGONIZATION:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_Polygonalization);
+ break;
+ case LS_MODIFIER_GUIDING_LINES:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_GuidingLines);
+ break;
+ case LS_MODIFIER_BLUEPRINT:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_Blueprint);
+ break;
+ case LS_MODIFIER_2D_OFFSET:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_2DOffset);
+ break;
+ case LS_MODIFIER_2D_TRANSFORM:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_2DTransform);
+ break;
+ case LS_MODIFIER_SIMPLIFICATION:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_Simplification);
+ break;
+ default:
+ struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleModifier); /* this should not happen */
}
- writestruct(wd, DATA, struct_name, 1, m);
+ writestruct_nr(wd, DATA, struct_nr, 1, m);
}
}
@@ -3622,27 +3857,111 @@ static void write_linestyles(WriteData *wd, ListBase *idbase)
int a;
for (linestyle = idbase->first; linestyle; linestyle = linestyle->id.next) {
- if (linestyle->id.us>0 || wd->current) {
- writestruct(wd, ID_LS, "FreestyleLineStyle", 1, linestyle);
- if (linestyle->id.properties)
- IDP_WriteProperty(linestyle->id.properties, wd);
- if (linestyle->adt)
+ if (linestyle->id.us > 0 || wd->current) {
+ writestruct(wd, ID_LS, FreestyleLineStyle, 1, linestyle);
+ write_iddata(wd, &linestyle->id);
+
+ if (linestyle->adt) {
write_animdata(wd, linestyle->adt);
+ }
+
write_linestyle_color_modifiers(wd, &linestyle->color_modifiers);
write_linestyle_alpha_modifiers(wd, &linestyle->alpha_modifiers);
write_linestyle_thickness_modifiers(wd, &linestyle->thickness_modifiers);
write_linestyle_geometry_modifiers(wd, &linestyle->geometry_modifiers);
- for (a=0; a<MAX_MTEX; a++) {
- if (linestyle->mtex[a]) writestruct(wd, DATA, "MTex", 1, linestyle->mtex[a]);
+ for (a = 0; a < MAX_MTEX; a++) {
+ if (linestyle->mtex[a]) {
+ writestruct(wd, DATA, MTex, 1, linestyle->mtex[a]);
+ }
}
if (linestyle->nodetree) {
- writestruct(wd, DATA, "bNodeTree", 1, linestyle->nodetree);
+ writestruct(wd, DATA, bNodeTree, 1, linestyle->nodetree);
write_nodetree(wd, linestyle->nodetree);
}
}
}
}
+static void write_cachefiles(WriteData *wd, ListBase *idbase)
+{
+ CacheFile *cache_file;
+
+ for (cache_file = idbase->first; cache_file; cache_file = cache_file->id.next) {
+ if (cache_file->id.us > 0 || wd->current) {
+ writestruct(wd, ID_CF, CacheFile, 1, cache_file);
+
+ if (cache_file->adt) {
+ write_animdata(wd, cache_file->adt);
+ }
+ }
+ }
+}
+
+/* Keep it last of write_foodata functions. */
+static void write_libraries(WriteData *wd, Main *main)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ ID *id;
+ int a, tot;
+ bool found_one;
+
+ for (; main; main = main->next) {
+
+ a = tot = set_listbasepointers(main, lbarray);
+
+ /* test: is lib being used */
+ if (main->curlib && main->curlib->packedfile) {
+ found_one = true;
+ }
+ else {
+ found_one = false;
+ while (tot--) {
+ for (id = lbarray[tot]->first; id; id = id->next) {
+ if (id->us > 0 && (id->tag & LIB_TAG_EXTERN)) {
+ found_one = true;
+ break;
+ }
+ }
+ if (found_one) {
+ break;
+ }
+ }
+ }
+
+ /* to be able to restore quit.blend and temp saves, the packed blend has to be in undo buffers... */
+ /* XXX needs rethink, just like save UI in undo files now - would be nice to append things only for the]
+ * quit.blend and temp saves */
+ if (found_one) {
+ writestruct(wd, ID_LI, Library, 1, main->curlib);
+ write_iddata(wd, &main->curlib->id);
+
+ if (main->curlib->packedfile) {
+ PackedFile *pf = main->curlib->packedfile;
+ writestruct(wd, DATA, PackedFile, 1, pf);
+ writedata(wd, DATA, pf->size, pf->data);
+ if (wd->current == NULL) {
+ printf("write packed .blend: %s\n", main->curlib->name);
+ }
+ }
+
+ while (a--) {
+ for (id = lbarray[a]->first; id; id = id->next) {
+ if (id->us > 0 && (id->tag & LIB_TAG_EXTERN)) {
+ if (!BKE_idcode_is_linkable(GS(id->name))) {
+ printf("ERROR: write file: data-block '%s' from lib '%s' is not linkable "
+ "but is flagged as directly linked", id->name, main->curlib->filepath);
+ BLI_assert(0);
+ }
+ writestruct(wd, ID_ID, ID, 1, id);
+ }
+ }
+ }
+ }
+ }
+
+ mywrite_flush(wd);
+}
+
/* context is usually defined by WM, two cases where no WM is available:
* - for forward compatibility, curscreen has to be saved
* - for undofile, curscene needs to be saved */
@@ -3652,7 +3971,7 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar)
FileGlobal fg;
bScreen *screen;
char subvstr[8];
-
+
/* prevent mem checkers from complaining */
memset(fg.pad, 0, sizeof(fg.pad));
memset(fg.filename, 0, sizeof(fg.filename));
@@ -3661,20 +3980,20 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar)
current_screen_compat(mainvar, &screen, is_undo);
/* XXX still remap G */
- fg.curscreen= screen;
- fg.curscene= screen ? screen->scene : NULL;
+ fg.curscreen = screen;
+ fg.curscene = screen ? screen->scene : NULL;
/* prevent to save this, is not good convention, and feature with concerns... */
- fg.fileflags= (fileflags & ~G_FILE_FLAGS_RUNTIME);
+ fg.fileflags = (fileflags & ~G_FILE_FLAGS_RUNTIME);
- fg.globalf= G.f;
+ fg.globalf = G.f;
BLI_strncpy(fg.filename, mainvar->name, sizeof(fg.filename));
sprintf(subvstr, "%4d", BLENDER_SUBVERSION);
memcpy(fg.subvstr, subvstr, 4);
-
- fg.subversion= BLENDER_SUBVERSION;
- fg.minversion= BLENDER_MINVERSION;
- fg.minsubversion= BLENDER_MINSUBVERSION;
+
+ fg.subversion = BLENDER_SUBVERSION;
+ fg.minversion = BLENDER_MINVERSION;
+ fg.minsubversion = BLENDER_MINSUBVERSION;
#ifdef WITH_BUILDINFO
{
extern unsigned long build_commit_timestamp;
@@ -3687,7 +4006,7 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar)
fg.build_commit_timestamp = 0;
BLI_strncpy(fg.build_hash, "unknown", sizeof(fg.build_hash));
#endif
- writestruct(wd, GLOB, "FileGlobal", 1, &fg);
+ writestruct(wd, GLOB, FileGlobal, 1, &fg);
}
/* preview image, first 2 values are width and height
@@ -3702,11 +4021,11 @@ static void write_thumb(WriteData *wd, const BlendThumbnail *thumb)
}
/* if MemFile * there's filesave to memory */
-static int write_file_handle(
+static bool write_file_handle(
Main *mainvar,
WriteWrap *ww,
MemFile *compare, MemFile *current,
- int write_user_block, int write_flags, const BlendThumbnail *thumb)
+ int write_flags, const BlendThumbnail *thumb)
{
BHead bhead;
ListBase mainlist;
@@ -3740,44 +4059,55 @@ static int write_file_handle(
write_thumb(wd, thumb);
write_global(wd, write_flags, mainvar);
+ /* The windowmanager and screen often change,
+ * avoid thumbnail detecting changes because of this. */
+ mywrite_flush(wd);
+
write_windowmanagers(wd, &mainvar->wm);
- write_screens (wd, &mainvar->screen);
- write_movieclips (wd, &mainvar->movieclip);
- write_masks (wd, &mainvar->mask);
- write_scenes (wd, &mainvar->scene);
- write_curves (wd, &mainvar->curve);
- write_mballs (wd, &mainvar->mball);
- write_images (wd, &mainvar->image);
- write_cameras (wd, &mainvar->camera);
- write_lamps (wd, &mainvar->lamp);
- write_lattices (wd, &mainvar->latt);
- write_vfonts (wd, &mainvar->vfont);
- write_keys (wd, &mainvar->key);
- write_worlds (wd, &mainvar->world);
- write_texts (wd, &mainvar->text);
- write_speakers (wd, &mainvar->speaker);
- write_sounds (wd, &mainvar->sound);
- write_groups (wd, &mainvar->group);
+ write_screens(wd, &mainvar->screen);
+ write_movieclips(wd, &mainvar->movieclip);
+ write_masks(wd, &mainvar->mask);
+ write_scenes(wd, &mainvar->scene);
+ write_curves(wd, &mainvar->curve);
+ write_mballs(wd, &mainvar->mball);
+ write_images(wd, &mainvar->image);
+ write_cameras(wd, &mainvar->camera);
+ write_lamps(wd, &mainvar->lamp);
+ write_lattices(wd, &mainvar->latt);
+ write_vfonts(wd, &mainvar->vfont);
+ write_keys(wd, &mainvar->key);
+ write_worlds(wd, &mainvar->world);
+ write_texts(wd, &mainvar->text);
+ write_speakers(wd, &mainvar->speaker);
+ write_sounds(wd, &mainvar->sound);
+ write_groups(wd, &mainvar->group);
write_armatures(wd, &mainvar->armature);
- write_actions (wd, &mainvar->action);
- write_objects (wd, &mainvar->object);
+ write_actions(wd, &mainvar->action);
+ write_objects(wd, &mainvar->object);
write_materials(wd, &mainvar->mat);
- write_textures (wd, &mainvar->tex);
- write_meshes (wd, &mainvar->mesh);
+ write_textures(wd, &mainvar->tex);
+ write_meshes(wd, &mainvar->mesh);
write_particlesettings(wd, &mainvar->particle);
write_nodetrees(wd, &mainvar->nodetree);
- write_brushes (wd, &mainvar->brush);
- write_palettes (wd, &mainvar->palettes);
- write_paintcurves (wd, &mainvar->paintcurves);
- write_gpencils (wd, &mainvar->gpencil);
+ write_brushes(wd, &mainvar->brush);
+ write_palettes(wd, &mainvar->palettes);
+ write_paintcurves(wd, &mainvar->paintcurves);
+ write_gpencils(wd, &mainvar->gpencil);
write_linestyles(wd, &mainvar->linestyle);
+ write_cachefiles(wd, &mainvar->cachefiles);
write_libraries(wd, mainvar->next);
- if (write_user_block) {
+ /* So changes above don't cause a 'DNA1' to be detected as changed on undo. */
+ mywrite_flush(wd);
+
+ if (write_flags & G_FILE_USERPREFS) {
write_userdef(wd);
}
-
- /* dna as last, because (to be implemented) test for which structs are written */
+
+ /* Write DNA last, because (to be implemented) test for which structs are written.
+ *
+ * Note that we *borrow* the pointer to 'DNAstr',
+ * so writing each time uses the same address and doesn't cause unnecessary undo overhead. */
writedata(wd, DNA1, wd->sdna->datalen, wd->sdna->data);
#ifdef USE_NODE_COMPAT_CUSTOMNODES
@@ -3793,7 +4123,7 @@ static int write_file_handle(
/* end of file */
memset(&bhead, 0, sizeof(BHead));
- bhead.code= ENDB;
+ bhead.code = ENDB;
mywrite(wd, &bhead, sizeof(BHead));
blo_join_main(&mainlist);
@@ -3806,16 +4136,19 @@ static int write_file_handle(
static bool do_history(const char *name, ReportList *reports)
{
char tempname1[FILE_MAX], tempname2[FILE_MAX];
- int hisnr= U.versions;
-
- if (U.versions==0) return 0;
- if (strlen(name)<2) {
+ int hisnr = U.versions;
+
+ if (U.versions == 0) {
+ return 0;
+ }
+
+ if (strlen(name) < 2) {
BKE_report(reports, RPT_ERROR, "Unable to make version backup: filename too short");
return 1;
}
while (hisnr > 1) {
- BLI_snprintf(tempname1, sizeof(tempname1), "%s%d", name, hisnr-1);
+ BLI_snprintf(tempname1, sizeof(tempname1), "%s%d", name, hisnr - 1);
if (BLI_exists(tempname1)) {
BLI_snprintf(tempname2, sizeof(tempname2), "%s%d", name, hisnr);
@@ -3847,8 +4180,7 @@ bool BLO_write_file(
Main *mainvar, const char *filepath, int write_flags,
ReportList *reports, const BlendThumbnail *thumb)
{
- char tempname[FILE_MAX+1];
- int err, write_user_block;
+ char tempname[FILE_MAX + 1];
eWriteWrapType ww_type;
WriteWrap ww;
@@ -3903,13 +4235,13 @@ bool BLO_write_file(
}
}
- write_user_block= write_flags & G_FILE_USERPREFS;
-
- if (write_flags & G_FILE_RELATIVE_REMAP)
- BKE_bpath_relative_convert(mainvar, filepath, NULL); /* note, making relative to something OTHER then G.main->name */
+ if (write_flags & G_FILE_RELATIVE_REMAP) {
+ /* note, making relative to something OTHER then G.main->name */
+ BKE_bpath_relative_convert(mainvar, filepath, NULL);
+ }
/* actual file writing */
- err = write_file_handle(mainvar, &ww, NULL, NULL, write_user_block, write_flags, thumb);
+ const bool err = write_file_handle(mainvar, &ww, NULL, NULL, write_flags, thumb);
ww.close(&ww);
@@ -3948,9 +4280,9 @@ bool BLO_write_file(
*/
bool BLO_write_file_mem(Main *mainvar, MemFile *compare, MemFile *current, int write_flags)
{
- int err;
+ write_flags &= ~G_FILE_USERPREFS;
- err = write_file_handle(mainvar, NULL, compare, current, 0, write_flags, NULL);
+ const bool err = write_file_handle(mainvar, NULL, compare, current, write_flags, NULL);
return (err == 0);
}
diff --git a/source/blender/blentranslation/BLT_translation.h b/source/blender/blentranslation/BLT_translation.h
index 3838e8c827c..1d76077c9f1 100644
--- a/source/blender/blentranslation/BLT_translation.h
+++ b/source/blender/blentranslation/BLT_translation.h
@@ -120,6 +120,7 @@ bool BLT_lang_is_ime_supported(void);
#define BLT_I18NCONTEXT_ID_ARMATURE "Armature"
#define BLT_I18NCONTEXT_ID_BRUSH "Brush"
#define BLT_I18NCONTEXT_ID_CAMERA "Camera"
+#define BLT_I18NCONTEXT_ID_CACHEFILE "CacheFile"
#define BLT_I18NCONTEXT_ID_CURVE "Curve"
#define BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE "FreestyleLineStyle"
#define BLT_I18NCONTEXT_ID_GPENCIL "GPencil"
@@ -171,6 +172,7 @@ typedef struct {
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_ARMATURE, "id_armature"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_BRUSH, "id_brush"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_CAMERA, "id_camera"), \
+ BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_CACHEFILE, "id_cachefile"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_CURVE, "id_curve"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE, "id_fs_linestyle"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_GPENCIL, "id_gpencil"), \
diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h
index e3caeedd2c9..72ea7bd7f5d 100644
--- a/source/blender/bmesh/bmesh_class.h
+++ b/source/blender/bmesh/bmesh_class.h
@@ -89,7 +89,6 @@ BLI_STATIC_ASSERT((sizeof(BMHeader) <= 16), "BMHeader size has grown!");
typedef struct BMVert {
BMHeader head;
- struct BMFlagLayer *oflags; /* keep after header, an array of flags, mostly used by the operator stack */
float co[3]; /* vertex coordinates */
float no[3]; /* vertex normal */
@@ -102,6 +101,11 @@ typedef struct BMVert {
struct BMEdge *e;
} BMVert;
+typedef struct BMVert_OFlag {
+ BMVert base;
+ struct BMFlagLayer *oflags;
+} BMVert_OFlag;
+
/* disk link structure, only used by edges */
typedef struct BMDiskLink {
struct BMEdge *next, *prev;
@@ -109,7 +113,6 @@ typedef struct BMDiskLink {
typedef struct BMEdge {
BMHeader head;
- struct BMFlagLayer *oflags; /* keep after header, an array of flags, mostly used by the operator stack */
struct BMVert *v1, *v2; /* vertices (unordered) */
@@ -122,6 +125,11 @@ typedef struct BMEdge {
BMDiskLink v1_disk_link, v2_disk_link;
} BMEdge;
+typedef struct BMEdge_OFlag {
+ BMEdge base;
+ struct BMFlagLayer *oflags;
+} BMEdge_OFlag;
+
typedef struct BMLoop {
BMHeader head;
/* notice no flags layer */
@@ -142,10 +150,6 @@ typedef struct BMLoop {
/* can cast BMFace/BMEdge/BMVert, but NOT BMLoop, since these don't have a flag layer */
typedef struct BMElemF {
BMHeader head;
-
- /* keep directly after header,
- * optional array of flags, only used by the operator stack */
- struct BMFlagLayer *oflags;
} BMElemF;
/* can cast anything to this, including BMLoop */
@@ -163,7 +167,6 @@ typedef struct BMLoopList {
typedef struct BMFace {
BMHeader head;
- struct BMFlagLayer *oflags; /* an array of flags, mostly used by the operator stack */
#ifdef USE_BMESH_HOLES
int totbounds; /*total boundaries, is one plus the number of holes in the face*/
@@ -177,6 +180,11 @@ typedef struct BMFace {
// short _pad[3];
} BMFace;
+typedef struct BMFace_OFlag {
+ BMFace base;
+ struct BMFlagLayer *oflags;
+} BMFace_OFlag;
+
typedef struct BMFlagLayer {
short f; /* flags */
} BMFlagLayer;
@@ -217,6 +225,8 @@ typedef struct BMesh {
/* operator api stuff (must be all NULL or all alloc'd) */
struct BLI_mempool *vtoolflagpool, *etoolflagpool, *ftoolflagpool;
+ unsigned int use_toolflags : 1;
+
int toolflag_index;
struct BMOperator *currentop;
@@ -259,10 +269,12 @@ enum {
/* args for _Generic */
#define _BM_GENERIC_TYPE_ELEM_NONCONST \
void *, BMVert *, BMEdge *, BMLoop *, BMFace *, \
+ BMVert_OFlag *, BMEdge_OFlag *, BMFace_OFlag *, \
BMElem *, BMElemF *, BMHeader *
#define _BM_GENERIC_TYPE_ELEM_CONST \
const void *, const BMVert *, const BMEdge *, const BMLoop *, const BMFace *, \
+ const BMVert_OFlag *, const BMEdge_OFlag *, const BMFace_OFlag *, \
const BMElem *, const BMElemF *, const BMHeader *, \
void * const, BMVert * const, BMEdge * const, BMLoop * const, BMFace * const, \
BMElem * const, BMElemF * const, BMHeader * const
@@ -276,6 +288,27 @@ enum {
#define BM_CHECK_TYPE_ELEM(ele) \
CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_ELEM_NONCONST, _BM_GENERIC_TYPE_ELEM_CONST)
+/* vert */
+#define _BM_GENERIC_TYPE_VERT_NONCONST BMVert *, BMVert_OFlag *
+#define _BM_GENERIC_TYPE_VERT_CONST const BMVert *, const BMVert_OFlag *
+#define BM_CHECK_TYPE_VERT_CONST(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_VERT_CONST)
+#define BM_CHECK_TYPE_VERT_NONCONST(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_ELEM_NONCONST)
+#define BM_CHECK_TYPE_VERT(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_VERT_NONCONST, _BM_GENERIC_TYPE_VERT_CONST)
+/* edge */
+#define _BM_GENERIC_TYPE_EDGE_NONCONST BMEdge *, BMEdge_OFlag *
+#define _BM_GENERIC_TYPE_EDGE_CONST const BMEdge *, const BMEdge_OFlag *
+#define BM_CHECK_TYPE_EDGE_CONST(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_EDGE_CONST)
+#define BM_CHECK_TYPE_EDGE_NONCONST(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_ELEM_NONCONST)
+#define BM_CHECK_TYPE_EDGE(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_EDGE_NONCONST, _BM_GENERIC_TYPE_EDGE_CONST)
+/* face */
+#define _BM_GENERIC_TYPE_FACE_NONCONST BMFace *, BMFace_OFlag *
+#define _BM_GENERIC_TYPE_FACE_CONST const BMFace *, const BMFace_OFlag *
+#define BM_CHECK_TYPE_FACE_CONST(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_FACE_CONST)
+#define BM_CHECK_TYPE_FACE_NONCONST(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_ELEM_NONCONST)
+#define BM_CHECK_TYPE_FACE(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_FACE_NONCONST, _BM_GENERIC_TYPE_FACE_CONST)
+
+
+
/* Assignment from a void* to a typed pointer is not allowed in C++,
* casting the LHS to void works fine though.
*/
diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c
index fdad93ee90d..4d92baab6eb 100644
--- a/source/blender/bmesh/intern/bmesh_construct.c
+++ b/source/blender/bmesh/intern/bmesh_construct.c
@@ -714,7 +714,9 @@ BMesh *BM_mesh_copy(BMesh *bm_old)
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_BM(bm_old);
/* allocate a bmesh */
- bm_new = BM_mesh_create(&allocsize);
+ bm_new = BM_mesh_create(
+ &allocsize,
+ &((struct BMeshCreateParams){.use_toolflags = bm_old->use_toolflags,}));
BM_mesh_copy_init_customdata(bm_new, bm_old, &allocsize);
diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c
index c03b882abb2..e83b752947c 100644
--- a/source/blender/bmesh/intern/bmesh_core.c
+++ b/source/blender/bmesh/intern/bmesh_core.c
@@ -81,7 +81,9 @@ BMVert *BM_vert_create(
v->head.api_flag = 0;
/* allocate flags */
- v->oflags = bm->vtoolflagpool ? BLI_mempool_calloc(bm->vtoolflagpool) : NULL;
+ if (bm->use_toolflags) {
+ ((BMVert_OFlag *)v)->oflags = bm->vtoolflagpool ? BLI_mempool_calloc(bm->vtoolflagpool) : NULL;
+ }
/* 'v->no' is handled by BM_elem_attrs_copy */
if (co) {
@@ -174,7 +176,9 @@ BMEdge *BM_edge_create(
e->head.api_flag = 0;
/* allocate flags */
- e->oflags = bm->etoolflagpool ? BLI_mempool_calloc(bm->etoolflagpool) : NULL;
+ if (bm->use_toolflags) {
+ ((BMEdge_OFlag *)e)->oflags = bm->etoolflagpool ? BLI_mempool_calloc(bm->etoolflagpool) : NULL;
+ }
e->v1 = v1;
e->v2 = v2;
@@ -386,7 +390,9 @@ BLI_INLINE BMFace *bm_face_create__internal(BMesh *bm)
f->head.api_flag = 0;
/* allocate flags */
- f->oflags = bm->ftoolflagpool ? BLI_mempool_calloc(bm->ftoolflagpool) : NULL;
+ if (bm->use_toolflags) {
+ ((BMFace_OFlag *)f)->oflags = bm->ftoolflagpool ? BLI_mempool_calloc(bm->ftoolflagpool) : NULL;
+ }
#ifdef USE_BMESH_HOLES
BLI_listbase_clear(&f->loops);
@@ -758,7 +764,7 @@ static void bm_kill_only_vert(BMesh *bm, BMVert *v)
CustomData_bmesh_free_block(&bm->vdata, &v->head.data);
if (bm->vtoolflagpool) {
- BLI_mempool_free(bm->vtoolflagpool, v->oflags);
+ BLI_mempool_free(bm->vtoolflagpool, ((BMVert_OFlag *)v)->oflags);
}
BLI_mempool_free(bm->vpool, v);
}
@@ -779,7 +785,7 @@ static void bm_kill_only_edge(BMesh *bm, BMEdge *e)
CustomData_bmesh_free_block(&bm->edata, &e->head.data);
if (bm->etoolflagpool) {
- BLI_mempool_free(bm->etoolflagpool, e->oflags);
+ BLI_mempool_free(bm->etoolflagpool, ((BMEdge_OFlag *)e)->oflags);
}
BLI_mempool_free(bm->epool, e);
}
@@ -803,7 +809,7 @@ static void bm_kill_only_face(BMesh *bm, BMFace *f)
CustomData_bmesh_free_block(&bm->pdata, &f->head.data);
if (bm->ftoolflagpool) {
- BLI_mempool_free(bm->ftoolflagpool, f->oflags);
+ BLI_mempool_free(bm->ftoolflagpool, ((BMFace_OFlag *)f)->oflags);
}
BLI_mempool_free(bm->fpool, f);
}
@@ -1246,7 +1252,6 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
BLI_array_staticdeclare(deledges, BM_DEFAULT_NGON_STACK_SIZE);
BLI_array_staticdeclare(delverts, BM_DEFAULT_NGON_STACK_SIZE);
BMVert *v1 = NULL, *v2 = NULL;
- const char *err = NULL;
int i, tote = 0;
const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
@@ -1267,7 +1272,7 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
int rlen = bm_loop_systag_count_radial(l_iter, _FLAG_JF);
if (rlen > 2) {
- err = N_("Input faces do not form a contiguous manifold region");
+ /* Input faces do not form a contiguous manifold region */
goto error;
}
else if (rlen == 1) {
@@ -1328,9 +1333,8 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
/* create region face */
f_new = tote ? BM_face_create_ngon(bm, v1, v2, edges, tote, faces[0], BM_CREATE_NOP) : NULL;
- if (UNLIKELY(!f_new || BMO_error_occurred(bm))) {
- if (!BMO_error_occurred(bm))
- err = N_("Invalid boundary region to join faces");
+ if (UNLIKELY(f_new == NULL)) {
+ /* Invalid boundary region to join faces */
goto error;
}
@@ -1403,9 +1407,7 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
}
for (i = 0; i < BLI_array_count(delverts); i++) {
- if (delverts[i]->e == NULL) {
- BM_vert_kill(bm, delverts[i]);
- }
+ BM_vert_kill(bm, delverts[i]);
}
}
else {
@@ -1428,9 +1430,6 @@ error:
BLI_array_free(deledges);
BLI_array_free(delverts);
- if (err) {
- BMO_error_raise(bm, bm->currentop, BMERR_DISSOLVEFACES_FAILED, err);
- }
return NULL;
}
@@ -2203,7 +2202,7 @@ BMFace *bmesh_jfke(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e)
/* deallocate edge and its two loops as well as f2 */
if (bm->etoolflagpool) {
- BLI_mempool_free(bm->etoolflagpool, l_f1->e->oflags);
+ BLI_mempool_free(bm->etoolflagpool, ((BMEdge_OFlag *)l_f1->e)->oflags);
}
BLI_mempool_free(bm->epool, l_f1->e);
bm->totedge--;
@@ -2212,7 +2211,7 @@ BMFace *bmesh_jfke(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e)
BLI_mempool_free(bm->lpool, l_f2);
bm->totloop--;
if (bm->ftoolflagpool) {
- BLI_mempool_free(bm->ftoolflagpool, f2->oflags);
+ BLI_mempool_free(bm->ftoolflagpool, ((BMFace_OFlag *)f2)->oflags);
}
BLI_mempool_free(bm->fpool, f2);
bm->totface--;
diff --git a/source/blender/bmesh/intern/bmesh_delete.c b/source/blender/bmesh/intern/bmesh_delete.c
index 882d78ce6b3..1449a6ef9d7 100644
--- a/source/blender/bmesh/intern/bmesh_delete.c
+++ b/source/blender/bmesh/intern/bmesh_delete.c
@@ -54,7 +54,7 @@ static void bmo_remove_tagged_faces(BMesh *bm, const short oflag)
BMIter iter;
BM_ITER_MESH_MUTABLE (f, f_next, &iter, bm, BM_FACES_OF_MESH) {
- if (BMO_elem_flag_test(bm, f, oflag)) {
+ if (BMO_face_flag_test(bm, f, oflag)) {
BM_face_kill(bm, f);
}
}
@@ -66,7 +66,7 @@ static void bmo_remove_tagged_edges(BMesh *bm, const short oflag)
BMIter iter;
BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) {
- if (BMO_elem_flag_test(bm, e, oflag)) {
+ if (BMO_edge_flag_test(bm, e, oflag)) {
BM_edge_kill(bm, e);
}
}
@@ -78,7 +78,7 @@ static void bmo_remove_tagged_verts(BMesh *bm, const short oflag)
BMIter iter;
BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) {
- if (BMO_elem_flag_test(bm, v, oflag)) {
+ if (BMO_vert_flag_test(bm, v, oflag)) {
BM_vert_kill(bm, v);
}
}
@@ -90,7 +90,7 @@ static void bmo_remove_tagged_verts_loose(BMesh *bm, const short oflag)
BMIter iter;
BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) {
- if (BMO_elem_flag_test(bm, v, oflag) && (v->e == NULL)) {
+ if (BMO_vert_flag_test(bm, v, oflag) && (v->e == NULL)) {
BM_vert_kill(bm, v);
}
}
@@ -132,9 +132,9 @@ void BMO_mesh_delete_oflag_context(BMesh *bm, const short oflag, const int type)
{
/* flush down to vert */
BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
- if (BMO_elem_flag_test(bm, e, oflag)) {
- BMO_elem_flag_enable(bm, e->v1, oflag);
- BMO_elem_flag_enable(bm, e->v2, oflag);
+ if (BMO_edge_flag_test(bm, e, oflag)) {
+ BMO_vert_flag_enable(bm, e->v1, oflag);
+ BMO_vert_flag_enable(bm, e->v2, oflag);
}
}
bmo_remove_tagged_edges(bm, oflag);
@@ -165,27 +165,27 @@ void BMO_mesh_delete_oflag_context(BMesh *bm, const short oflag, const int type)
{
/* go through and mark all edges and all verts of all faces for delete */
BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
- if (BMO_elem_flag_test(bm, f, oflag)) {
+ if (BMO_face_flag_test(bm, f, oflag)) {
BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
BMLoop *l_iter;
l_iter = l_first;
do {
- BMO_elem_flag_enable(bm, l_iter->v, oflag);
- BMO_elem_flag_enable(bm, l_iter->e, oflag);
+ BMO_vert_flag_enable(bm, l_iter->v, oflag);
+ BMO_edge_flag_enable(bm, l_iter->e, oflag);
} while ((l_iter = l_iter->next) != l_first);
}
}
/* now go through and mark all remaining faces all edges for keeping */
BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
- if (!BMO_elem_flag_test(bm, f, oflag)) {
+ if (!BMO_face_flag_test(bm, f, oflag)) {
BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
BMLoop *l_iter;
l_iter = l_first;
do {
- BMO_elem_flag_disable(bm, l_iter->v, oflag);
- BMO_elem_flag_disable(bm, l_iter->e, oflag);
+ BMO_vert_flag_disable(bm, l_iter->v, oflag);
+ BMO_edge_flag_disable(bm, l_iter->e, oflag);
} while ((l_iter = l_iter->next) != l_first);
}
}
@@ -195,13 +195,13 @@ void BMO_mesh_delete_oflag_context(BMesh *bm, const short oflag, const int type)
/* Only exception to normal 'DEL_FACES' logic. */
if (type == DEL_FACES_KEEP_BOUNDARY) {
if (BM_edge_is_boundary(e)) {
- BMO_elem_flag_disable(bm, e, oflag);
+ BMO_edge_flag_disable(bm, e, oflag);
}
}
- if (!BMO_elem_flag_test(bm, e, oflag)) {
- BMO_elem_flag_disable(bm, e->v1, oflag);
- BMO_elem_flag_disable(bm, e->v2, oflag);
+ if (!BMO_edge_flag_test(bm, e, oflag)) {
+ BMO_vert_flag_disable(bm, e->v1, oflag);
+ BMO_vert_flag_disable(bm, e->v2, oflag);
}
}
diff --git a/source/blender/bmesh/intern/bmesh_iterators.c b/source/blender/bmesh/intern/bmesh_iterators.c
index 4ba462f2165..961b10d848a 100644
--- a/source/blender/bmesh/intern/bmesh_iterators.c
+++ b/source/blender/bmesh/intern/bmesh_iterators.c
@@ -272,7 +272,7 @@ int BM_iter_mesh_bitmap_from_filter(
}
}
- return i;
+ return bitmap_enabled;
}
/**
@@ -339,16 +339,43 @@ int BMO_iter_elem_count_flag(
const short oflag, const bool value)
{
BMIter iter;
- BMElemF *ele;
int count = 0;
/* loops have no header flags */
BLI_assert(bm_iter_itype_htype_map[itype] != BM_LOOP);
- BM_ITER_ELEM (ele, &iter, data, itype) {
- if (BMO_elem_flag_test_bool(bm, ele, oflag) == value) {
- count++;
+ switch (bm_iter_itype_htype_map[itype]) {
+ case BM_VERT:
+ {
+ BMVert *ele;
+ BM_ITER_ELEM (ele, &iter, data, itype) {
+ if (BMO_vert_flag_test_bool(bm, ele, oflag) == value) {
+ count++;
+ }
+ }
+ break;
}
+ case BM_EDGE:
+ {
+ BMEdge *ele;
+ BM_ITER_ELEM (ele, &iter, data, itype) {
+ if (BMO_edge_flag_test_bool(bm, ele, oflag) == value) {
+ count++;
+ }
+ }
+ break;
+ }
+ case BM_FACE:
+ {
+ BMFace *ele;
+ BM_ITER_ELEM (ele, &iter, data, itype) {
+ if (BMO_face_flag_test_bool(bm, ele, oflag) == value) {
+ count++;
+ }
+ }
+ break;
+ }
+
}
return count;
}
diff --git a/source/blender/bmesh/intern/bmesh_log.c b/source/blender/bmesh/intern/bmesh_log.c
index 1f64f7b74cc..2591c33fc73 100644
--- a/source/blender/bmesh/intern/bmesh_log.c
+++ b/source/blender/bmesh/intern/bmesh_log.c
@@ -45,7 +45,7 @@
#include "bmesh.h"
#include "bmesh_log.h"
-#include "range_tree_c_api.h"
+#include "range_tree.h"
#include "BLI_strict_flags.h"
diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c
index 3fe888736f0..7178a8132d2 100644
--- a/source/blender/bmesh/intern/bmesh_marking.c
+++ b/source/blender/bmesh/intern/bmesh_marking.c
@@ -842,7 +842,7 @@ void BM_editselection_normal(BMEditSelection *ese, float r_normal[3])
/* the 2 vertex normals will be close but not at rightangles to the edge
* for rotate about edge we want them to be at right angles, so we need to
- * do some extra colculation to correct the vert normals,
+ * do some extra calculation to correct the vert normals,
* we need the plane for this */
cross_v3_v3v3(vec, r_normal, plane);
cross_v3_v3v3(r_normal, plane, vec);
@@ -904,7 +904,7 @@ void BM_editselection_plane(BMEditSelection *ese, float r_plane[3])
}
else if (ese->htype == BM_FACE) {
BMFace *efa = (BMFace *)ese->ele;
- BM_face_calc_plane(efa, r_plane);
+ BM_face_calc_tangent_auto(efa, r_plane);
}
}
diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c
index ed1bd16b2e4..57a6d8d2e1a 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.c
+++ b/source/blender/bmesh/intern/bmesh_mesh.c
@@ -48,16 +48,52 @@
const BMAllocTemplate bm_mesh_allocsize_default = {512, 1024, 2048, 512};
const BMAllocTemplate bm_mesh_chunksize_default = {512, 1024, 2048, 512};
-static void bm_mempool_init(BMesh *bm, const BMAllocTemplate *allocsize)
+static void bm_mempool_init_ex(
+ const BMAllocTemplate *allocsize, const bool use_toolflags,
+ BLI_mempool **r_vpool, BLI_mempool **r_epool, BLI_mempool **r_lpool, BLI_mempool **r_fpool)
{
- bm->vpool = BLI_mempool_create(sizeof(BMVert), allocsize->totvert,
- bm_mesh_chunksize_default.totvert, BLI_MEMPOOL_ALLOW_ITER);
- bm->epool = BLI_mempool_create(sizeof(BMEdge), allocsize->totedge,
- bm_mesh_chunksize_default.totedge, BLI_MEMPOOL_ALLOW_ITER);
- bm->lpool = BLI_mempool_create(sizeof(BMLoop), allocsize->totloop,
- bm_mesh_chunksize_default.totloop, BLI_MEMPOOL_NOP);
- bm->fpool = BLI_mempool_create(sizeof(BMFace), allocsize->totface,
- bm_mesh_chunksize_default.totface, BLI_MEMPOOL_ALLOW_ITER);
+ size_t vert_size, edge_size, loop_size, face_size;
+
+ if (use_toolflags == true) {
+ vert_size = sizeof(BMVert_OFlag);
+ edge_size = sizeof(BMEdge_OFlag);
+ loop_size = sizeof(BMLoop);
+ face_size = sizeof(BMFace_OFlag);
+ }
+ else {
+ vert_size = sizeof(BMVert);
+ edge_size = sizeof(BMEdge);
+ loop_size = sizeof(BMLoop);
+ face_size = sizeof(BMFace);
+ }
+
+ if (r_vpool) {
+ *r_vpool = BLI_mempool_create(
+ vert_size, allocsize->totvert,
+ bm_mesh_chunksize_default.totvert, BLI_MEMPOOL_ALLOW_ITER);
+ }
+ if (r_epool) {
+ *r_epool = BLI_mempool_create(
+ edge_size, allocsize->totedge,
+ bm_mesh_chunksize_default.totedge, BLI_MEMPOOL_ALLOW_ITER);
+ }
+ if (r_lpool) {
+ *r_lpool = BLI_mempool_create(
+ loop_size, allocsize->totloop,
+ bm_mesh_chunksize_default.totloop, BLI_MEMPOOL_NOP);
+ }
+ if (r_fpool) {
+ *r_fpool = BLI_mempool_create(
+ face_size, allocsize->totface,
+ bm_mesh_chunksize_default.totface, BLI_MEMPOOL_ALLOW_ITER);
+ }
+}
+
+static void bm_mempool_init(BMesh *bm, const BMAllocTemplate *allocsize, const bool use_toolflags)
+{
+ bm_mempool_init_ex(
+ allocsize, use_toolflags,
+ &bm->vpool, &bm->epool, &bm->lpool, &bm->fpool);
#ifdef USE_BMESH_HOLES
bm->looplistpool = BLI_mempool_create(sizeof(BMLoopList), 512, 512, BLI_MEMPOOL_NOP);
@@ -66,6 +102,8 @@ static void bm_mempool_init(BMesh *bm, const BMAllocTemplate *allocsize)
void BM_mesh_elem_toolflags_ensure(BMesh *bm)
{
+ BLI_assert(bm->use_toolflags);
+
if (bm->vtoolflagpool && bm->etoolflagpool && bm->ftoolflagpool) {
return;
}
@@ -80,7 +118,7 @@ void BM_mesh_elem_toolflags_ensure(BMesh *bm)
{
BLI_mempool *toolflagpool = bm->vtoolflagpool;
BMIter iter;
- BMElemF *ele;
+ BMVert_OFlag *ele;
BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
ele->oflags = BLI_mempool_calloc(toolflagpool);
}
@@ -89,7 +127,7 @@ void BM_mesh_elem_toolflags_ensure(BMesh *bm)
{
BLI_mempool *toolflagpool = bm->etoolflagpool;
BMIter iter;
- BMElemF *ele;
+ BMEdge_OFlag *ele;
BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
ele->oflags = BLI_mempool_calloc(toolflagpool);
}
@@ -98,7 +136,7 @@ void BM_mesh_elem_toolflags_ensure(BMesh *bm)
{
BLI_mempool *toolflagpool = bm->ftoolflagpool;
BMIter iter;
- BMElemF *ele;
+ BMFace_OFlag *ele;
BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
ele->oflags = BLI_mempool_calloc(toolflagpool);
}
@@ -134,15 +172,18 @@ void BM_mesh_elem_toolflags_clear(BMesh *bm)
*
* \note ob is needed by multires
*/
-BMesh *BM_mesh_create(const BMAllocTemplate *allocsize)
+BMesh *BM_mesh_create(
+ const BMAllocTemplate *allocsize,
+ const struct BMeshCreateParams *params)
{
/* allocate the structure */
BMesh *bm = MEM_callocN(sizeof(BMesh), __func__);
/* allocate the memory pools for the mesh elements */
- bm_mempool_init(bm, allocsize);
+ bm_mempool_init(bm, allocsize, params->use_toolflags);
/* allocate one flag pool that we don't get rid of. */
+ bm->use_toolflags = params->use_toolflags;
bm->toolflag_index = 0;
bm->totflags = 0;
@@ -239,13 +280,16 @@ void BM_mesh_data_free(BMesh *bm)
*/
void BM_mesh_clear(BMesh *bm)
{
+ const bool use_toolflags = bm->use_toolflags;
+
/* free old mesh */
BM_mesh_data_free(bm);
memset(bm, 0, sizeof(BMesh));
/* allocate the memory pools for the mesh elements */
- bm_mempool_init(bm, &bm_mesh_allocsize_default);
+ bm_mempool_init(bm, &bm_mesh_allocsize_default, use_toolflags);
+ bm->use_toolflags = use_toolflags;
bm->toolflag_index = 0;
bm->totflags = 0;
@@ -1706,3 +1750,262 @@ void BM_mesh_remap(
if (fptr_map)
BLI_ghash_free(fptr_map, NULL, NULL);
}
+
+/**
+ * Use new memory pools for this mesh.
+ *
+ * \note needed for re-sizing elements (adding/removing tool flags)
+ * but could also be used for packing fragmented bmeshes.
+ */
+void BM_mesh_rebuild(
+ BMesh *bm, const struct BMeshCreateParams *params,
+ BLI_mempool *vpool_dst, BLI_mempool *epool_dst, BLI_mempool *lpool_dst, BLI_mempool *fpool_dst)
+{
+ const char remap =
+ (vpool_dst ? BM_VERT : 0) |
+ (epool_dst ? BM_EDGE : 0) |
+ (lpool_dst ? BM_LOOP : 0) |
+ (fpool_dst ? BM_FACE : 0);
+
+ BMVert **vtable_dst = (remap & BM_VERT) ? MEM_mallocN(bm->totvert * sizeof(BMVert *), __func__) : NULL;
+ BMEdge **etable_dst = (remap & BM_EDGE) ? MEM_mallocN(bm->totedge * sizeof(BMEdge *), __func__) : NULL;
+ BMLoop **ltable_dst = (remap & BM_LOOP) ? MEM_mallocN(bm->totloop * sizeof(BMLoop *), __func__) : NULL;
+ BMFace **ftable_dst = (remap & BM_FACE) ? MEM_mallocN(bm->totface * sizeof(BMFace *), __func__) : NULL;
+
+ const bool use_toolflags = params->use_toolflags;
+
+ if (remap & BM_VERT) {
+ BMIter iter;
+ int index;
+ BMVert *v_src;
+ BM_ITER_MESH_INDEX (v_src, &iter, bm, BM_VERTS_OF_MESH, index) {
+ BMVert *v_dst = BLI_mempool_alloc(vpool_dst);
+ memcpy(v_dst, v_src, sizeof(BMVert));
+ if (use_toolflags) {
+ ((BMVert_OFlag *)v_dst)->oflags = bm->vtoolflagpool ? BLI_mempool_calloc(bm->vtoolflagpool) : NULL;
+ }
+
+ vtable_dst[index] = v_dst;
+ BM_elem_index_set(v_src, index); /* set_ok */
+ }
+ }
+
+ if (remap & BM_EDGE) {
+ BMIter iter;
+ int index;
+ BMEdge *e_src;
+ BM_ITER_MESH_INDEX (e_src, &iter, bm, BM_EDGES_OF_MESH, index) {
+ BMEdge *e_dst = BLI_mempool_alloc(epool_dst);
+ memcpy(e_dst, e_src, sizeof(BMEdge));
+ if (use_toolflags) {
+ ((BMEdge_OFlag *)e_dst)->oflags = bm->etoolflagpool ? BLI_mempool_calloc(bm->etoolflagpool) : NULL;
+ }
+
+ etable_dst[index] = e_dst;
+ BM_elem_index_set(e_src, index); /* set_ok */
+ }
+ }
+
+ if (remap & (BM_LOOP | BM_FACE)) {
+ BMIter iter;
+ int index, index_loop = 0;
+ BMFace *f_src;
+ BM_ITER_MESH_INDEX (f_src, &iter, bm, BM_FACES_OF_MESH, index) {
+
+ if (remap & BM_FACE) {
+ BMFace *f_dst = BLI_mempool_alloc(fpool_dst);
+ memcpy(f_dst, f_src, sizeof(BMFace));
+ if (use_toolflags) {
+ ((BMFace_OFlag *)f_dst)->oflags = bm->ftoolflagpool ? BLI_mempool_calloc(bm->ftoolflagpool) : NULL;
+ }
+
+ ftable_dst[index] = f_dst;
+ BM_elem_index_set(f_src, index); /* set_ok */
+ }
+
+ /* handle loops */
+ if (remap & BM_LOOP) {
+ BMLoop *l_iter_src, *l_first_src;
+ l_iter_src = l_first_src = BM_FACE_FIRST_LOOP((BMFace *)f_src);
+ do {
+ BMLoop *l_dst = BLI_mempool_alloc(lpool_dst);
+ memcpy(l_dst, l_iter_src, sizeof(BMLoop));
+ ltable_dst[index_loop] = l_dst;
+ BM_elem_index_set(l_iter_src, index_loop++); /* set_ok */
+ } while ((l_iter_src = l_iter_src->next) != l_first_src);
+ }
+ }
+ }
+
+#define MAP_VERT(ele) vtable_dst[BM_elem_index_get(ele)]
+#define MAP_EDGE(ele) etable_dst[BM_elem_index_get(ele)]
+#define MAP_LOOP(ele) ltable_dst[BM_elem_index_get(ele)]
+#define MAP_FACE(ele) ftable_dst[BM_elem_index_get(ele)]
+
+#define REMAP_VERT(ele) { if (remap & BM_VERT) { ele = MAP_VERT(ele); }} ((void)0)
+#define REMAP_EDGE(ele) { if (remap & BM_EDGE) { ele = MAP_EDGE(ele); }} ((void)0)
+#define REMAP_LOOP(ele) { if (remap & BM_LOOP) { ele = MAP_LOOP(ele); }} ((void)0)
+#define REMAP_FACE(ele) { if (remap & BM_FACE) { ele = MAP_FACE(ele); }} ((void)0)
+
+ /* verts */
+ {
+ for (int i = 0; i < bm->totvert; i++) {
+ BMVert *v = vtable_dst[i];
+ if (v->e) {
+ REMAP_EDGE(v->e);
+ }
+ }
+ }
+
+ /* edges */
+ {
+ for (int i = 0; i < bm->totedge; i++) {
+ BMEdge *e = etable_dst[i];
+ REMAP_VERT(e->v1);
+ REMAP_VERT(e->v2);
+ REMAP_EDGE(e->v1_disk_link.next);
+ REMAP_EDGE(e->v1_disk_link.prev);
+ REMAP_EDGE(e->v2_disk_link.next);
+ REMAP_EDGE(e->v2_disk_link.prev);
+ if (e->l) {
+ REMAP_LOOP(e->l);
+ }
+ }
+ }
+
+ /* faces */
+ {
+ for (int i = 0; i < bm->totface; i++) {
+ BMFace *f = ftable_dst[i];
+ REMAP_LOOP(f->l_first);
+
+ {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP((BMFace *)f);
+ do {
+ REMAP_VERT(l_iter->v);
+ REMAP_EDGE(l_iter->e);
+ REMAP_FACE(l_iter->f);
+
+ REMAP_LOOP(l_iter->radial_next);
+ REMAP_LOOP(l_iter->radial_prev);
+ REMAP_LOOP(l_iter->next);
+ REMAP_LOOP(l_iter->prev);
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+ }
+ }
+
+ for (BMEditSelection *ese = bm->selected.first; ese; ese = ese->next) {
+ switch (ese->htype) {
+ case BM_VERT:
+ if (remap & BM_VERT) {
+ ese->ele = (BMElem *)MAP_VERT(ese->ele);
+ }
+ break;
+ case BM_EDGE:
+ if (remap & BM_EDGE) {
+ ese->ele = (BMElem *)MAP_EDGE(ese->ele);
+ }
+ break;
+ case BM_FACE:
+ if (remap & BM_FACE) {
+ ese->ele = (BMElem *)MAP_FACE(ese->ele);
+ }
+ break;
+ }
+ }
+
+ if (bm->act_face) {
+ REMAP_FACE(bm->act_face);
+ }
+
+#undef MAP_VERT
+#undef MAP_EDGE
+#undef MAP_LOOP
+#undef MAP_EDGE
+
+#undef REMAP_VERT
+#undef REMAP_EDGE
+#undef REMAP_LOOP
+#undef REMAP_EDGE
+
+ /* Cleanup, re-use local tables if the current mesh had tables allocated.
+ * could use irrespective but it may use more memory then the caller wants (and not be needed). */
+ if (remap & BM_VERT) {
+ if (bm->vtable) {
+ SWAP(BMVert **, vtable_dst, bm->vtable);
+ bm->vtable_tot = bm->totvert;
+ bm->elem_table_dirty &= ~BM_VERT;
+ }
+ MEM_freeN(vtable_dst);
+ BLI_mempool_destroy(bm->vpool);
+ bm->vpool = vpool_dst;
+ }
+
+ if (remap & BM_EDGE) {
+ if (bm->etable) {
+ SWAP(BMEdge **, etable_dst, bm->etable);
+ bm->etable_tot = bm->totedge;
+ bm->elem_table_dirty &= ~BM_EDGE;
+ }
+ MEM_freeN(etable_dst);
+ BLI_mempool_destroy(bm->epool);
+ bm->epool = epool_dst;
+ }
+
+ if (remap & BM_LOOP) {
+ /* no loop table */
+ MEM_freeN(ltable_dst);
+ BLI_mempool_destroy(bm->lpool);
+ bm->lpool = lpool_dst;
+ }
+
+ if (remap & BM_FACE) {
+ if (bm->ftable) {
+ SWAP(BMFace **, ftable_dst, bm->ftable);
+ bm->ftable_tot = bm->totface;
+ bm->elem_table_dirty &= ~BM_FACE;
+ }
+ MEM_freeN(ftable_dst);
+ BLI_mempool_destroy(bm->fpool);
+ bm->fpool = fpool_dst;
+ }
+}
+
+/**
+ * Re-allocates mesh data with/without toolflags.
+ */
+void BM_mesh_toolflags_set(BMesh *bm, bool use_toolflags)
+{
+ if (bm->use_toolflags == use_toolflags) {
+ return;
+ }
+
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_BM(bm);
+
+ BLI_mempool *vpool_dst = NULL;
+ BLI_mempool *epool_dst = NULL;
+ BLI_mempool *fpool_dst = NULL;
+
+ bm_mempool_init_ex(
+ &allocsize, use_toolflags,
+ &vpool_dst, &epool_dst, NULL, &fpool_dst);
+
+ if (use_toolflags == false) {
+ BLI_mempool_destroy(bm->vtoolflagpool);
+ BLI_mempool_destroy(bm->etoolflagpool);
+ BLI_mempool_destroy(bm->ftoolflagpool);
+
+ bm->vtoolflagpool = NULL;
+ bm->etoolflagpool = NULL;
+ bm->ftoolflagpool = NULL;
+ }
+
+ BM_mesh_rebuild(
+ bm,
+ &((struct BMeshCreateParams){.use_toolflags = use_toolflags,}),
+ vpool_dst, epool_dst, NULL, fpool_dst);
+
+ bm->use_toolflags = use_toolflags;
+} \ No newline at end of file
diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h
index b9cdc4ccf66..6a9540c3b60 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.h
+++ b/source/blender/bmesh/intern/bmesh_mesh.h
@@ -32,7 +32,14 @@ struct MLoopNorSpaceArray;
void BM_mesh_elem_toolflags_ensure(BMesh *bm);
void BM_mesh_elem_toolflags_clear(BMesh *bm);
-BMesh *BM_mesh_create(const struct BMAllocTemplate *allocsize);
+
+struct BMeshCreateParams {
+ unsigned int use_toolflags : 1;
+};
+
+BMesh *BM_mesh_create(
+ const struct BMAllocTemplate *allocsize,
+ const struct BMeshCreateParams *params);
void BM_mesh_free(BMesh *bm);
void BM_mesh_data_free(BMesh *bm);
@@ -53,6 +60,8 @@ void BM_mesh_elem_index_validate(
BMesh *bm, const char *location, const char *func,
const char *msg_a, const char *msg_b);
+void BM_mesh_toolflags_set(BMesh *bm, bool use_toolflags);
+
#ifndef NDEBUG
bool BM_mesh_elem_table_check(BMesh *bm);
#endif
@@ -83,6 +92,10 @@ void BM_mesh_remap(
const unsigned int *edge_idx,
const unsigned int *face_idx);
+void BM_mesh_rebuild(
+ BMesh *bm, const struct BMeshCreateParams *params,
+ struct BLI_mempool *vpool, struct BLI_mempool *epool, struct BLI_mempool *lpool, struct BLI_mempool *fpool);
+
typedef struct BMAllocTemplate {
int totvert, totedge, totloop, totface;
} BMAllocTemplate;
@@ -113,10 +126,4 @@ extern const BMAllocTemplate bm_mesh_chunksize_default;
#define BMALLOC_TEMPLATE_FROM_DM(...) VA_NARGS_CALL_OVERLOAD(_VA_BMALLOC_TEMPLATE_FROM_DM_, __VA_ARGS__)
-
-
-enum {
- BM_MESH_CREATE_USE_TOOLFLAGS = (1 << 0)
-};
-
#endif /* __BMESH_MESH_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.c b/source/blender/bmesh/intern/bmesh_mesh_conv.c
index 7b102c9283b..bb61f66e267 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_conv.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_conv.c
@@ -804,10 +804,10 @@ void BM_mesh_bm_to_me(
BMEditSelection *selected;
me->totselect = BLI_listbase_count(&(bm->selected));
- if (me->mselect) MEM_freeN(me->mselect);
-
- me->mselect = MEM_callocN(sizeof(MSelect) * me->totselect, "Mesh selection history");
-
+ MEM_SAFE_FREE(me->mselect);
+ if (me->totselect != 0) {
+ me->mselect = MEM_mallocN(sizeof(MSelect) * me->totselect, "Mesh selection history");
+ }
for (i = 0, selected = bm->selected.first; selected; i++, selected = selected->next) {
if (selected->htype == BM_VERT) {
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
index 79c2f80d6aa..0d0fdda2c4c 100644
--- a/source/blender/bmesh/intern/bmesh_opdefines.c
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -1635,7 +1635,8 @@ static BMOpDefine bmo_create_icosphere_def = {
static BMOpDefine bmo_create_monkey_def = {
"create_monkey",
/* slots_in */
- {{"matrix", BMO_OP_SLOT_MAT}, /* matrix to multiply the new geometry with */
+ {{"matrix", BMO_OP_SLOT_MAT}, /* matrix to multiply the new geometry with */
+ {"calc_uvs", BMO_OP_SLOT_BOOL}, /* calculate default UVs */
{{'\0'}},
},
/* slots_out */
diff --git a/source/blender/bmesh/intern/bmesh_operator_api.h b/source/blender/bmesh/intern/bmesh_operator_api.h
index cf93fe0935e..30cd1df9c4e 100644
--- a/source/blender/bmesh/intern/bmesh_operator_api.h
+++ b/source/blender/bmesh/intern/bmesh_operator_api.h
@@ -75,15 +75,74 @@ extern "C" {
struct GHashIterator;
-#define BMO_elem_flag_test( bm, ele, oflag) _bmo_elem_flag_test (bm, (ele)->oflags, oflag)
-#define BMO_elem_flag_test_bool(bm, ele, oflag) _bmo_elem_flag_test_bool(bm, (ele)->oflags, oflag)
-#define BMO_elem_flag_enable( bm, ele, oflag) _bmo_elem_flag_enable (bm, (ele)->oflags, oflag)
-#define BMO_elem_flag_disable( bm, ele, oflag) _bmo_elem_flag_disable (bm, (ele)->oflags, oflag)
-#define BMO_elem_flag_set( bm, ele, oflag, val) _bmo_elem_flag_set (bm, (ele)->oflags, oflag, val)
-#define BMO_elem_flag_toggle( bm, ele, oflag) _bmo_elem_flag_toggle (bm, (ele)->oflags, oflag)
-
-BLI_INLINE short _bmo_elem_flag_test( BMesh *bm, BMFlagLayer *oflags, const short oflag);
-BLI_INLINE bool _bmo_elem_flag_test_bool(BMesh *bm, BMFlagLayer *oflags, const short oflag);
+BLI_INLINE BMFlagLayer *BMO_elem_flag_from_header(BMHeader *ele_head)
+{
+ switch (ele_head->htype) {
+ case BM_VERT: return ((BMVert_OFlag *)ele_head)->oflags;
+ case BM_EDGE: return ((BMEdge_OFlag *)ele_head)->oflags;
+ default: return ((BMFace_OFlag *)ele_head)->oflags;
+ }
+}
+
+#define BMO_elem_flag_test(bm, ele, oflag) \
+ _bmo_elem_flag_test(bm, BMO_elem_flag_from_header(&(ele)->head), oflag)
+#define BMO_elem_flag_test_bool(bm, ele, oflag) \
+ _bmo_elem_flag_test_bool(bm, BMO_elem_flag_from_header(&(ele)->head), oflag)
+#define BMO_elem_flag_enable(bm, ele, oflag) \
+ _bmo_elem_flag_enable(bm, (BM_CHECK_TYPE_ELEM_NONCONST(ele), BMO_elem_flag_from_header(&(ele)->head)), oflag)
+#define BMO_elem_flag_disable(bm, ele, oflag) \
+ _bmo_elem_flag_disable(bm, (BM_CHECK_TYPE_ELEM_NONCONST(ele), BMO_elem_flag_from_header(&(ele)->head)), oflag)
+#define BMO_elem_flag_set(bm, ele, oflag, val) \
+ _bmo_elem_flag_set(bm, (BM_CHECK_TYPE_ELEM_NONCONST(ele), BMO_elem_flag_from_header(&(ele)->head)), oflag, val)
+#define BMO_elem_flag_toggle(bm, ele, oflag) \
+ _bmo_elem_flag_toggle(bm, (BM_CHECK_TYPE_ELEM_NONCONST(ele), BMO_elem_flag_from_header(&(ele)->head)), oflag)
+
+/* take care not to instansiate args multiple times */
+#ifdef __GNUC___
+#define _BMO_CAST_V_CONST(e) ({ typeof(e) _e = e; \
+ (BM_CHECK_TYPE_VERT(_e), BLI_assert(((const BMHeader *)_e)->htype == BM_VERT), (const BMVert_OFlag *)_e); })
+#define _BMO_CAST_E_CONST(e) ({ typeof(e) _e = e; \
+ (BM_CHECK_TYPE_EDGE(_e), BLI_assert(((const BMHeader *)_e)->htype == BM_EDGE), (const BMEdge_OFlag *)_e); })
+#define _BMO_CAST_F_CONST(e) ({ typeof(e) _e = e; \
+ (BM_CHECK_TYPE_FACE(_e), BLI_assert(((const BMHeader *)_e)->htype == BM_FACE), (const BMFace_OFlag *)_e); })
+#define _BMO_CAST_V(e) ({ typeof(e) _e = e; \
+ (BM_CHECK_TYPE_VERT_NONCONST(_e), BLI_assert(((BMHeader *)_e)->htype == BM_VERT), (BMVert_OFlag *)_e); })
+#define _BMO_CAST_E(e) ({ typeof(e) _e = e; \
+ (BM_CHECK_TYPE_EDGE_NONCONST(_e), BLI_assert(((BMHeader *)_e)->htype == BM_EDGE), (BMEdge_OFlag *)_e); })
+#define _BMO_CAST_F(e) ({ typeof(e) _e = e; \
+ (BM_CHECK_TYPE_FACE_NONCONST(_e), BLI_assert(((BMHeader *)_e)->htype == BM_FACE), (BMFace_OFlag *)_e); })
+#else
+#define _BMO_CAST_V_CONST(e) (BM_CHECK_TYPE_VERT(e), (const BMVert_OFlag *)e)
+#define _BMO_CAST_E_CONST(e) (BM_CHECK_TYPE_EDGE(e), (const BMEdge_OFlag *)e)
+#define _BMO_CAST_F_CONST(e) (BM_CHECK_TYPE_FACE(e), (const BMFace_OFlag *)e)
+#define _BMO_CAST_V(e) (BM_CHECK_TYPE_VERT_NONCONST(e), (BMVert_OFlag *)e)
+#define _BMO_CAST_E(e) (BM_CHECK_TYPE_EDGE_NONCONST(e), (BMEdge_OFlag *)e)
+#define _BMO_CAST_F(e) (BM_CHECK_TYPE_FACE_NONCONST(e), (BMFace_OFlag *)e)
+#endif
+
+#define BMO_vert_flag_test( bm, e, oflag) _bmo_elem_flag_test (bm, _BMO_CAST_V_CONST(e)->oflags, oflag)
+#define BMO_vert_flag_test_bool(bm, e, oflag) _bmo_elem_flag_test_bool(bm, _BMO_CAST_V_CONST(e)->oflags, oflag)
+#define BMO_vert_flag_enable( bm, e, oflag) _bmo_elem_flag_enable (bm, _BMO_CAST_V(e)->oflags, oflag)
+#define BMO_vert_flag_disable( bm, e, oflag) _bmo_elem_flag_disable (bm, _BMO_CAST_V(e)->oflags, oflag)
+#define BMO_vert_flag_set( bm, e, oflag, val) _bmo_elem_flag_set (bm, _BMO_CAST_V(e)->oflags, oflag, val)
+#define BMO_vert_flag_toggle( bm, e, oflag) _bmo_elem_flag_toggle (bm, _BMO_CAST_V(e)->oflags, oflag)
+
+#define BMO_edge_flag_test( bm, e, oflag) _bmo_elem_flag_test (bm, _BMO_CAST_E_CONST(e)->oflags, oflag)
+#define BMO_edge_flag_test_bool(bm, e, oflag) _bmo_elem_flag_test_bool(bm, _BMO_CAST_E_CONST(e)->oflags, oflag)
+#define BMO_edge_flag_enable( bm, e, oflag) _bmo_elem_flag_enable (bm, _BMO_CAST_E(e)->oflags, oflag)
+#define BMO_edge_flag_disable( bm, e, oflag) _bmo_elem_flag_disable (bm, _BMO_CAST_E(e)->oflags, oflag)
+#define BMO_edge_flag_set( bm, e, oflag, val) _bmo_elem_flag_set (bm, _BMO_CAST_E(e)->oflags, oflag, val)
+#define BMO_edge_flag_toggle( bm, e, oflag) _bmo_elem_flag_toggle (bm, _BMO_CAST_E(e)->oflags, oflag)
+
+#define BMO_face_flag_test( bm, e, oflag) _bmo_elem_flag_test (bm, _BMO_CAST_F_CONST(e)->oflags, oflag)
+#define BMO_face_flag_test_bool(bm, e, oflag) _bmo_elem_flag_test_bool(bm, _BMO_CAST_F_CONST(e)->oflags, oflag)
+#define BMO_face_flag_enable( bm, e, oflag) _bmo_elem_flag_enable (bm, _BMO_CAST_F(e)->oflags, oflag)
+#define BMO_face_flag_disable( bm, e, oflag) _bmo_elem_flag_disable (bm, _BMO_CAST_F(e)->oflags, oflag)
+#define BMO_face_flag_set( bm, e, oflag, val) _bmo_elem_flag_set (bm, _BMO_CAST_F(e)->oflags, oflag, val)
+#define BMO_face_flag_toggle( bm, e, oflag) _bmo_elem_flag_toggle (bm, _BMO_CAST_F(e)->oflags, oflag)
+
+BLI_INLINE short _bmo_elem_flag_test( BMesh *bm, const BMFlagLayer *oflags, const short oflag);
+BLI_INLINE bool _bmo_elem_flag_test_bool(BMesh *bm, const BMFlagLayer *oflags, const short oflag);
BLI_INLINE void _bmo_elem_flag_enable( BMesh *bm, BMFlagLayer *oflags, const short oflag);
BLI_INLINE void _bmo_elem_flag_disable( BMesh *bm, BMFlagLayer *oflags, const short oflag);
BLI_INLINE void _bmo_elem_flag_set( BMesh *bm, BMFlagLayer *oflags, const short oflag, int val);
diff --git a/source/blender/bmesh/intern/bmesh_operator_api_inline.h b/source/blender/bmesh/intern/bmesh_operator_api_inline.h
index 00fcd9e7a9b..eb1c161f19d 100644
--- a/source/blender/bmesh/intern/bmesh_operator_api_inline.h
+++ b/source/blender/bmesh/intern/bmesh_operator_api_inline.h
@@ -39,32 +39,37 @@
/* flags 15 and 16 (1 << 14 and 1 << 15) are reserved for bmesh api use */
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2)
-BLI_INLINE short _bmo_elem_flag_test(BMesh *bm, BMFlagLayer *oflags, const short oflag)
+BLI_INLINE short _bmo_elem_flag_test(BMesh *bm, const BMFlagLayer *oflags, const short oflag)
{
+ BLI_assert(bm->use_toolflags);
return oflags[bm->toolflag_index].f & oflag;
}
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2)
-BLI_INLINE bool _bmo_elem_flag_test_bool(BMesh *bm, BMFlagLayer *oflags, const short oflag)
+BLI_INLINE bool _bmo_elem_flag_test_bool(BMesh *bm, const BMFlagLayer *oflags, const short oflag)
{
+ BLI_assert(bm->use_toolflags);
return (oflags[bm->toolflag_index].f & oflag) != 0;
}
ATTR_NONNULL(1, 2)
BLI_INLINE void _bmo_elem_flag_enable(BMesh *bm, BMFlagLayer *oflags, const short oflag)
{
+ BLI_assert(bm->use_toolflags);
oflags[bm->toolflag_index].f |= oflag;
}
ATTR_NONNULL(1, 2)
BLI_INLINE void _bmo_elem_flag_disable(BMesh *bm, BMFlagLayer *oflags, const short oflag)
{
+ BLI_assert(bm->use_toolflags);
oflags[bm->toolflag_index].f &= (short)~oflag;
}
ATTR_NONNULL(1, 2)
BLI_INLINE void _bmo_elem_flag_set(BMesh *bm, BMFlagLayer *oflags, const short oflag, int val)
{
+ BLI_assert(bm->use_toolflags);
if (val) oflags[bm->toolflag_index].f |= oflag;
else oflags[bm->toolflag_index].f &= (short)~oflag;
}
@@ -72,6 +77,7 @@ BLI_INLINE void _bmo_elem_flag_set(BMesh *bm, BMFlagLayer *oflags, const short o
ATTR_NONNULL(1, 2)
BLI_INLINE void _bmo_elem_flag_toggle(BMesh *bm, BMFlagLayer *oflags, const short oflag)
{
+ BLI_assert(bm->use_toolflags);
oflags[bm->toolflag_index].f ^= oflag;
}
diff --git a/source/blender/bmesh/intern/bmesh_operators.c b/source/blender/bmesh/intern/bmesh_operators.c
index 960ff568e93..706a7f74ed2 100644
--- a/source/blender/bmesh/intern/bmesh_operators.c
+++ b/source/blender/bmesh/intern/bmesh_operators.c
@@ -548,27 +548,44 @@ static int bmo_mesh_flag_count(
BMesh *bm, const char htype, const short oflag,
const bool test_for_enabled)
{
- const char iter_types[3] = {BM_VERTS_OF_MESH,
- BM_EDGES_OF_MESH,
- BM_FACES_OF_MESH};
+ int count_vert = 0, count_edge = 0, count_face = 0;
- const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
-
- BMIter iter;
- int count = 0;
- BMElemF *ele_f;
- int i;
-
- for (i = 0; i < 3; i++) {
- if (htype & flag_types[i]) {
- BM_ITER_MESH (ele_f, &iter, bm, iter_types[i]) {
- if (BMO_elem_flag_test_bool(bm, ele_f, oflag) == test_for_enabled)
- count++;
+#pragma omp parallel sections if ((bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT) && \
+ (ELEM(htype, BM_VERT, BM_EDGE, BM_FACE) == 0))
+ {
+#pragma omp section
+ if (htype & BM_VERT) {
+ BMIter iter;
+ BMVert *ele;
+ BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BMO_vert_flag_test_bool(bm, ele, oflag) == test_for_enabled) {
+ count_vert++;
+ }
+ }
+ }
+#pragma omp section
+ if (htype & BM_EDGE) {
+ BMIter iter;
+ BMEdge *ele;
+ BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BMO_edge_flag_test_bool(bm, ele, oflag) == test_for_enabled) {
+ count_edge++;
+ }
+ }
+ }
+#pragma omp section
+ if (htype & BM_FACE) {
+ BMIter iter;
+ BMFace *ele;
+ BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
+ if (BMO_face_flag_test_bool(bm, ele, oflag) == test_for_enabled) {
+ count_face++;
+ }
}
}
}
- return count;
+ return (count_vert + count_edge + count_face);
}
@@ -584,21 +601,32 @@ int BMO_mesh_disabled_flag_count(BMesh *bm, const char htype, const short oflag)
void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *UNUSED(op), const char htype, const short oflag)
{
- const char iter_types[3] = {BM_VERTS_OF_MESH,
- BM_EDGES_OF_MESH,
- BM_FACES_OF_MESH};
-
- const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
- BMElemF *ele;
- int i;
-
-#pragma omp parallel for schedule(static) if (bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT)
- for (i = 0; i < 3; i++) {
- if (htype & flag_types[i]) {
+#pragma omp parallel sections if ((bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT) && \
+ (ELEM(htype, BM_VERT, BM_EDGE, BM_FACE) == 0))
+ {
+#pragma omp section
+ if (htype & BM_VERT) {
BMIter iter;
- BM_ITER_MESH (ele, &iter, bm, iter_types[i]) {
- BMO_elem_flag_disable(bm, ele, oflag);
+ BMVert *ele;
+ BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
+ BMO_vert_flag_disable(bm, ele, oflag);
+ }
+ }
+#pragma omp section
+ if (htype & BM_EDGE) {
+ BMIter iter;
+ BMEdge *ele;
+ BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
+ BMO_edge_flag_disable(bm, ele, oflag);
+ }
+ }
+#pragma omp section
+ if (htype & BM_FACE) {
+ BMIter iter;
+ BMFace *ele;
+ BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
+ BMO_face_flag_disable(bm, ele, oflag);
}
}
}
@@ -1007,7 +1035,7 @@ static void bmo_slot_buffer_from_flag(
if (htype & BM_VERT) {
BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
- if (BMO_elem_flag_test_bool(bm, (BMElemF *)ele, oflag) == test_for_enabled) {
+ if (BMO_vert_flag_test_bool(bm, (BMVert *)ele, oflag) == test_for_enabled) {
ele_array[i] = ele;
i++;
}
@@ -1016,7 +1044,7 @@ static void bmo_slot_buffer_from_flag(
if (htype & BM_EDGE) {
BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
- if (BMO_elem_flag_test_bool(bm, (BMElemF *)ele, oflag) == test_for_enabled) {
+ if (BMO_edge_flag_test_bool(bm, (BMEdge *)ele, oflag) == test_for_enabled) {
ele_array[i] = ele;
i++;
}
@@ -1025,7 +1053,7 @@ static void bmo_slot_buffer_from_flag(
if (htype & BM_FACE) {
BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
- if (BMO_elem_flag_test_bool(bm, (BMElemF *)ele, oflag) == test_for_enabled) {
+ if (BMO_face_flag_test_bool(bm, (BMFace *)ele, oflag) == test_for_enabled) {
ele_array[i] = ele;
i++;
}
@@ -1213,7 +1241,7 @@ static void bmo_flag_layer_alloc(BMesh *bm)
#pragma omp section
{
BMIter iter;
- BMElemF *ele;
+ BMVert_OFlag *ele;
int i;
BLI_mempool *newpool = bm->vtoolflagpool;
@@ -1223,14 +1251,14 @@ static void bmo_flag_layer_alloc(BMesh *bm)
void *oldflags = ele->oflags;
ele->oflags = BLI_mempool_calloc(newpool);
memcpy(ele->oflags, oldflags, old_totflags_size);
- BM_elem_index_set(ele, i); /* set_inline */
+ BM_elem_index_set(&ele->base, i); /* set_inline */
BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele);
}
}
#pragma omp section
{
BMIter iter;
- BMElemF *ele;
+ BMEdge_OFlag *ele;
int i;
BLI_mempool *newpool = bm->etoolflagpool;
@@ -1239,14 +1267,14 @@ static void bmo_flag_layer_alloc(BMesh *bm)
void *oldflags = ele->oflags;
ele->oflags = BLI_mempool_calloc(newpool);
memcpy(ele->oflags, oldflags, old_totflags_size);
- BM_elem_index_set(ele, i); /* set_inline */
+ BM_elem_index_set(&ele->base, i); /* set_inline */
BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele);
}
}
#pragma omp section
{
BMIter iter;
- BMElemF *ele;
+ BMFace_OFlag *ele;
int i;
BLI_mempool *newpool = bm->ftoolflagpool;
@@ -1255,7 +1283,7 @@ static void bmo_flag_layer_alloc(BMesh *bm)
void *oldflags = ele->oflags;
ele->oflags = BLI_mempool_calloc(newpool);
memcpy(ele->oflags, oldflags, old_totflags_size);
- BM_elem_index_set(ele, i); /* set_inline */
+ BM_elem_index_set(&ele->base, i); /* set_inline */
BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele);
}
}
@@ -1292,7 +1320,7 @@ static void bmo_flag_layer_free(BMesh *bm)
#pragma omp section
{
BMIter iter;
- BMElemF *ele;
+ BMVert_OFlag *ele;
int i;
BLI_mempool *newpool = bm->vtoolflagpool;
@@ -1302,14 +1330,14 @@ static void bmo_flag_layer_free(BMesh *bm)
void *oldflags = ele->oflags;
ele->oflags = BLI_mempool_alloc(newpool);
memcpy(ele->oflags, oldflags, new_totflags_size);
- BM_elem_index_set(ele, i); /* set_inline */
+ BM_elem_index_set(&ele->base, i); /* set_inline */
BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele);
}
}
#pragma omp section
{
BMIter iter;
- BMElemF *ele;
+ BMEdge_OFlag *ele;
int i;
BLI_mempool *newpool = bm->etoolflagpool;
@@ -1318,14 +1346,14 @@ static void bmo_flag_layer_free(BMesh *bm)
void *oldflags = ele->oflags;
ele->oflags = BLI_mempool_alloc(newpool);
memcpy(ele->oflags, oldflags, new_totflags_size);
- BM_elem_index_set(ele, i); /* set_inline */
+ BM_elem_index_set(&ele->base, i); /* set_inline */
BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele);
}
}
#pragma omp section
{
BMIter iter;
- BMElemF *ele;
+ BMFace_OFlag *ele;
int i;
BLI_mempool *newpool = bm->ftoolflagpool;
@@ -1334,7 +1362,7 @@ static void bmo_flag_layer_free(BMesh *bm)
void *oldflags = ele->oflags;
ele->oflags = BLI_mempool_alloc(newpool);
memcpy(ele->oflags, oldflags, new_totflags_size);
- BM_elem_index_set(ele, i); /* set_inline */
+ BM_elem_index_set(&ele->base, i); /* set_inline */
BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele);
}
}
@@ -1361,31 +1389,31 @@ static void bmo_flag_layer_clear(BMesh *bm)
#pragma omp section
{
BMIter iter;
- BMElemF *ele;
+ BMVert_OFlag *ele;
int i;
BM_ITER_MESH_INDEX (ele, &iter, bm, BM_VERTS_OF_MESH, i) {
ele->oflags[totflags_offset] = zero_flag;
- BM_elem_index_set(ele, i); /* set_inline */
+ BM_elem_index_set(&ele->base, i); /* set_inline */
}
}
#pragma omp section
{
BMIter iter;
- BMElemF *ele;
+ BMEdge_OFlag *ele;
int i;
BM_ITER_MESH_INDEX (ele, &iter, bm, BM_EDGES_OF_MESH, i) {
ele->oflags[totflags_offset] = zero_flag;
- BM_elem_index_set(ele, i); /* set_inline */
+ BM_elem_index_set(&ele->base, i); /* set_inline */
}
}
#pragma omp section
{
BMIter iter;
- BMElemF *ele;
+ BMFace_OFlag *ele;
int i;
BM_ITER_MESH_INDEX (ele, &iter, bm, BM_FACES_OF_MESH, i) {
ele->oflags[totflags_offset] = zero_flag;
- BM_elem_index_set(ele, i); /* set_inline */
+ BM_elem_index_set(&ele->base, i); /* set_inline */
}
}
}
diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c
index 62b29e61d08..c500d7b9ec2 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.c
+++ b/source/blender/bmesh/intern/bmesh_polygon.c
@@ -48,31 +48,6 @@
#include "intern/bmesh_private.h"
/**
- * \brief TEST EDGE SIDE and POINT IN TRIANGLE
- *
- * Point in triangle tests stolen from scanfill.c.
- * Used for tessellator
- */
-
-static bool testedgesidef(const float v1[2], const float v2[2], const float v3[2])
-{
- /* is v3 to the right of v1 - v2 ? With exception: v3 == v1 || v3 == v2 */
- double inp;
-
- //inp = (v2[cox] - v1[cox]) * (v1[coy] - v3[coy]) + (v1[coy] - v2[coy]) * (v1[cox] - v3[cox]);
- inp = (v2[0] - v1[0]) * (v1[1] - v3[1]) + (v1[1] - v2[1]) * (v1[0] - v3[0]);
-
- if (inp < 0.0) {
- return false;
- }
- else if (inp == 0) {
- if (v1[0] == v3[0] && v1[1] == v3[1]) return false;
- if (v2[0] == v3[0] && v2[1] == v3[1]) return false;
- }
- return true;
-}
-
-/**
* \brief COMPUTE POLY NORMAL (BMFace)
*
* Same as #normal_poly_v3 but operates directly on a bmesh face.
@@ -286,64 +261,258 @@ float BM_face_calc_perimeter(const BMFace *f)
return perimeter;
}
-void BM_vert_tri_calc_plane(BMVert *verts[3], float r_plane[3])
+/**
+ * Utility function to calculate the edge which is most different from the other two.
+ *
+ * \return The first edge index, where the second vertex is ``(index + 1) % 3``.
+ */
+static int bm_vert_tri_find_unique_edge(BMVert *verts[3])
{
- float lens[3];
+ /* find the most 'unique' loop, (greatest difference to others) */
+#if 1
+ /* optimized version that avoids sqrt */
float difs[3];
- int order[3] = {0, 1, 2};
+ for (int i_prev = 1, i_curr = 2, i_next = 0;
+ i_next < 3;
+ i_prev = i_curr, i_curr = i_next++)
+ {
+ const float *co = verts[i_curr]->co;
+ const float *co_other[2] = {verts[i_prev]->co, verts[i_next]->co};
+ float proj_dir[3];
+ mid_v3_v3v3(proj_dir, co_other[0], co_other[1]);
+ sub_v3_v3(proj_dir, co);
+
+ float proj_pair[2][3];
+ project_v3_v3v3(proj_pair[0], co_other[0], proj_dir);
+ project_v3_v3v3(proj_pair[1], co_other[1], proj_dir);
+ difs[i_next] = len_squared_v3v3(proj_pair[0], proj_pair[1]);
+ }
+#else
+ const float lens[3] = {
+ len_v3v3(verts[0]->co, verts[1]->co),
+ len_v3v3(verts[1]->co, verts[2]->co),
+ len_v3v3(verts[2]->co, verts[0]->co),
+ };
+ const float difs[3] = {
+ fabsf(lens[1] - lens[2]),
+ fabsf(lens[2] - lens[0]),
+ fabsf(lens[0] - lens[1]),
+ };
+#endif
- lens[0] = len_v3v3(verts[0]->co, verts[1]->co);
- lens[1] = len_v3v3(verts[1]->co, verts[2]->co);
- lens[2] = len_v3v3(verts[2]->co, verts[0]->co);
+ int order[3] = {0, 1, 2};
+ axis_sort_v3(difs, order);
- /* find the shortest or the longest loop */
- difs[0] = fabsf(lens[1] - lens[2]);
- difs[1] = fabsf(lens[2] - lens[0]);
- difs[2] = fabsf(lens[0] - lens[1]);
+ return order[0];
+}
- axis_sort_v3(difs, order);
- sub_v3_v3v3(r_plane, verts[order[0]]->co, verts[(order[0] + 1) % 3]->co);
+/**
+ * Calculate a tangent from any 3 vertices.
+ *
+ * The tangent aligns to the most *unique* edge
+ * (the edge most unlike the other two).
+ *
+ * \param r_tangent: Calculated unit length tangent (return value).
+ */
+void BM_vert_tri_calc_tangent_edge(BMVert *verts[3], float r_tangent[3])
+{
+ const int index = bm_vert_tri_find_unique_edge(verts);
+
+ sub_v3_v3v3(r_tangent, verts[index]->co, verts[(index + 1) % 3]->co);
+
+ normalize_v3(r_tangent);
}
/**
- * Compute a meaningful direction along the face (use for manipulator axis).
- * \note result isnt normalized.
+ * Calculate a tangent from any 3 vertices,
+ *
+ * The tangent follows the center-line formed by the most unique edges center
+ * and the opposite vertex.
+ *
+ * \param r_tangent: Calculated unit length tangent (return value).
+ */
+void BM_vert_tri_calc_tangent_edge_pair(BMVert *verts[3], float r_tangent[3])
+{
+ const int index = bm_vert_tri_find_unique_edge(verts);
+
+ const float *v_a = verts[index]->co;
+ const float *v_b = verts[(index + 1) % 3]->co;
+ const float *v_other = verts[(index + 2) % 3]->co;
+
+ mid_v3_v3v3(r_tangent, v_a, v_b);
+ sub_v3_v3v3(r_tangent, v_other, r_tangent);
+
+ normalize_v3(r_tangent);
+}
+
+/**
+ * Compute the tangent of the face, using the longest edge.
+ */
+void BM_face_calc_tangent_edge(const BMFace *f, float r_tangent[3])
+{
+ const BMLoop *l_long = BM_face_find_longest_loop((BMFace *)f);
+
+ sub_v3_v3v3(r_tangent, l_long->v->co, l_long->next->v->co);
+
+ normalize_v3(r_tangent);
+
+}
+
+/**
+ * Compute the tangent of the face, using the two longest disconnected edges.
+ *
+ * \param r_tangent: Calculated unit length tangent (return value).
*/
-void BM_face_calc_plane(const BMFace *f, float r_plane[3])
+void BM_face_calc_tangent_edge_pair(const BMFace *f, float r_tangent[3])
{
if (f->len == 3) {
BMVert *verts[3];
BM_face_as_array_vert_tri((BMFace *)f, verts);
- BM_vert_tri_calc_plane(verts, r_plane);
+ BM_vert_tri_calc_tangent_edge_pair(verts, r_tangent);
}
else if (f->len == 4) {
+ /* Use longest edge pair */
BMVert *verts[4];
float vec[3], vec_a[3], vec_b[3];
- // BM_iter_as_array(NULL, BM_VERTS_OF_FACE, efa, (void **)verts, 4);
BM_face_as_array_vert_quad((BMFace *)f, verts);
sub_v3_v3v3(vec_a, verts[3]->co, verts[2]->co);
sub_v3_v3v3(vec_b, verts[0]->co, verts[1]->co);
- add_v3_v3v3(r_plane, vec_a, vec_b);
+ add_v3_v3v3(r_tangent, vec_a, vec_b);
sub_v3_v3v3(vec_a, verts[0]->co, verts[3]->co);
sub_v3_v3v3(vec_b, verts[1]->co, verts[2]->co);
add_v3_v3v3(vec, vec_a, vec_b);
- /* use the biggest edge length */
- if (len_squared_v3(r_plane) < len_squared_v3(vec)) {
- copy_v3_v3(r_plane, vec);
+ /* use the longest edge length */
+ if (len_squared_v3(r_tangent) < len_squared_v3(vec)) {
+ copy_v3_v3(r_tangent, vec);
}
}
else {
- const BMLoop *l_long = BM_face_find_longest_loop((BMFace *)f);
+ /* For ngons use two longest disconnected edges */
+ BMLoop *l_long = BM_face_find_longest_loop((BMFace *)f);
+ BMLoop *l_long_other = NULL;
+
+ float len_max_sq = 0.0f;
+ float vec_a[3], vec_b[3];
- sub_v3_v3v3(r_plane, l_long->v->co, l_long->next->v->co);
+ BMLoop *l_iter = l_long->prev->prev;
+ BMLoop *l_last = l_long->next;
+
+ do {
+ const float len_sq = len_squared_v3v3(l_iter->v->co, l_iter->next->v->co);
+ if (len_sq >= len_max_sq) {
+ l_long_other = l_iter;
+ len_max_sq = len_sq;
+ }
+ } while ((l_iter = l_iter->prev) != l_last);
+
+ sub_v3_v3v3(vec_a, l_long->next->v->co, l_long->v->co);
+ sub_v3_v3v3(vec_b, l_long_other->v->co, l_long_other->next->v->co);
+ add_v3_v3v3(r_tangent, vec_a, vec_b);
+
+ /* Edges may not be opposite side of the ngon,
+ * this could cause problems for ngons with multiple-aligned edges of the same length.
+ * Fallback to longest edge. */
+ if (UNLIKELY(normalize_v3(r_tangent) == 0.0f)) {
+ normalize_v3_v3(r_tangent, vec_a);
+ }
}
+}
+
+/**
+ * Compute the tangent of the face, using the edge farthest away from any vertex in the face.
+ *
+ * \param r_tangent: Calculated unit length tangent (return value).
+ */
+void BM_face_calc_tangent_edge_diagonal(const BMFace *f, float r_tangent[3])
+{
+ BMLoop *l_iter, *l_first;
- normalize_v3(r_plane);
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+
+ /* incase of degenerate faces */
+ zero_v3(r_tangent);
+
+ /* warning: O(n^2) loop here, take care! */
+ float dist_max_sq = 0.0f;
+ do {
+ BMLoop *l_iter_other = l_iter->next;
+ BMLoop *l_iter_last = l_iter->prev;
+ do {
+ BLI_assert(!ELEM(l_iter->v->co, l_iter_other->v->co, l_iter_other->next->v->co));
+ float co_other[3], vec[3];
+ closest_to_line_segment_v3(co_other, l_iter->v->co, l_iter_other->v->co, l_iter_other->next->v->co);
+ sub_v3_v3v3(vec, l_iter->v->co, co_other);
+
+ const float dist_sq = len_squared_v3(vec);
+ if (dist_sq > dist_max_sq) {
+ dist_max_sq = dist_sq;
+ copy_v3_v3(r_tangent, vec);
+ }
+ } while ((l_iter_other = l_iter_other->next) != l_iter_last);
+ } while ((l_iter = l_iter->next) != l_first);
+
+ normalize_v3(r_tangent);
+}
+
+/**
+ * Compute the tangent of the face, using longest distance between vertices on the face.
+ *
+ * \note The logic is almost identical to #BM_face_calc_tangent_edge_diagonal
+ */
+void BM_face_calc_tangent_vert_diagonal(const BMFace *f, float r_tangent[3])
+{
+ BMLoop *l_iter, *l_first;
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+
+ /* incase of degenerate faces */
+ zero_v3(r_tangent);
+
+ /* warning: O(n^2) loop here, take care! */
+ float dist_max_sq = 0.0f;
+ do {
+ BMLoop *l_iter_other = l_iter->next;
+ do {
+ float vec[3];
+ sub_v3_v3v3(vec, l_iter->v->co, l_iter_other->v->co);
+
+ const float dist_sq = len_squared_v3(vec);
+ if (dist_sq > dist_max_sq) {
+ dist_max_sq = dist_sq;
+ copy_v3_v3(r_tangent, vec);
+ }
+ } while ((l_iter_other = l_iter_other->next) != l_iter);
+ } while ((l_iter = l_iter->next) != l_first);
+
+ normalize_v3(r_tangent);
+}
+
+/**
+ * Compute a meaningful direction along the face (use for manipulator axis).
+ *
+ * \note Callers shouldn't depend on the *exact* method used here.
+ */
+void BM_face_calc_tangent_auto(const BMFace *f, float r_tangent[3])
+{
+ if (f->len == 3) {
+ /* most 'unique' edge of a triangle */
+ BMVert *verts[3];
+ BM_face_as_array_vert_tri((BMFace *)f, verts);
+ BM_vert_tri_calc_tangent_edge(verts, r_tangent);
+ }
+ else if (f->len == 4) {
+ /* longest edge pair of a quad */
+ BM_face_calc_tangent_edge_pair((BMFace *)f, r_tangent);
+ }
+ else {
+ /* longest edge of an ngon */
+ BM_face_calc_tangent_edge((BMFace *)f, r_tangent);
+ }
}
/**
@@ -409,29 +578,6 @@ void BM_face_calc_center_mean_weighted(const BMFace *f, float r_cent[3])
}
/**
- * \brief BM LEGAL EDGES
- *
- * takes in a face and a list of edges, and sets to NULL any edge in
- * the list that bridges a concave region of the face or intersects
- * any of the faces's edges.
- */
-static void scale_edge_v2f(float v1[2], float v2[2], const float fac)
-{
- float mid[2];
-
- mid_v2_v2v2(mid, v1, v2);
-
- sub_v2_v2v2(v1, v1, mid);
- sub_v2_v2v2(v2, v2, mid);
-
- mul_v2_fl(v1, fac);
- mul_v2_fl(v2, fac);
-
- add_v2_v2v2(v1, v1, mid);
- add_v2_v2v2(v2, v2, mid);
-}
-
-/**
* \brief POLY ROTATE PLANE
*
* Rotates a polygon so that it's
@@ -716,67 +862,6 @@ void BM_face_normal_flip(BMesh *bm, BMFace *f)
BM_face_normal_flip_ex(bm, f, cd_loop_mdisp_offset, true);
}
-/* detects if two line segments cross each other (intersects).
- * note, there could be more winding cases then there needs to be. */
-static bool line_crosses_v2f(const float v1[2], const float v2[2], const float v3[2], const float v4[2])
-{
-
-#define GETMIN2_AXIS(a, b, ma, mb, axis) \
- { \
- ma[axis] = min_ff(a[axis], b[axis]); \
- mb[axis] = max_ff(a[axis], b[axis]); \
- } (void)0
-
-#define GETMIN2(a, b, ma, mb) \
- { \
- GETMIN2_AXIS(a, b, ma, mb, 0); \
- GETMIN2_AXIS(a, b, ma, mb, 1); \
- } (void)0
-
-#define EPS (FLT_EPSILON * 15)
-
- int w1, w2, w3, w4, w5 /*, re */;
- float mv1[2], mv2[2], mv3[2], mv4[2];
-
- /* now test winding */
- w1 = testedgesidef(v1, v3, v2);
- w2 = testedgesidef(v2, v4, v1);
- w3 = !testedgesidef(v1, v2, v3);
- w4 = testedgesidef(v3, v2, v4);
- w5 = !testedgesidef(v3, v1, v4);
-
- if (w1 == w2 && w2 == w3 && w3 == w4 && w4 == w5) {
- return true;
- }
-
- GETMIN2(v1, v2, mv1, mv2);
- GETMIN2(v3, v4, mv3, mv4);
-
- /* do an interval test on the x and y axes */
- /* first do x axis */
- if (fabsf(v1[1] - v2[1]) < EPS &&
- fabsf(v3[1] - v4[1]) < EPS &&
- fabsf(v1[1] - v3[1]) < EPS)
- {
- return (mv4[0] >= mv1[0] && mv3[0] <= mv2[0]);
- }
-
- /* now do y axis */
- if (fabsf(v1[0] - v2[0]) < EPS &&
- fabsf(v3[0] - v4[0]) < EPS &&
- fabsf(v1[0] - v3[0]) < EPS)
- {
- return (mv4[1] >= mv1[1] && mv3[1] <= mv2[1]);
- }
-
- return false;
-
-#undef GETMIN2_AXIS
-#undef GETMIN2
-#undef EPS
-
-}
-
/**
* BM POINT IN FACE
*
@@ -842,6 +927,7 @@ void BM_face_triangulate(
const int quad_method,
const int ngon_method,
const bool use_tag,
+ /* use for ngons only! */
MemArena *pf_arena,
/* use for MOD_TRIANGULATE_NGON_BEAUTY only! */
@@ -1073,121 +1159,103 @@ void BM_face_triangulate(
*/
void BM_face_splits_check_legal(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int len)
{
- const int len2 = len * 2;
- BMLoop *l;
- float v1[2], v2[2], v3[2], mid[2], *p1, *p2, *p3, *p4;
float out[2] = {-FLT_MAX, -FLT_MAX};
+ float center[2] = {0.0f, 0.0f};
float axis_mat[3][3];
float (*projverts)[2] = BLI_array_alloca(projverts, f->len);
- float (*edgeverts)[2] = BLI_array_alloca(edgeverts, len2);
- float fac1 = 1.0000001f, fac2 = 0.9f; //9999f; //0.999f;
- int i, j, a = 0, clen;
+ const float *(*edgeverts)[2] = BLI_array_alloca(edgeverts, len);
+ BMLoop *l;
+ int i, i_prev, j;
BLI_assert(BM_face_is_normal_valid(f));
axis_dominant_v3_to_m3(axis_mat, f->no);
for (i = 0, l = BM_FACE_FIRST_LOOP(f); i < f->len; i++, l = l->next) {
- BM_elem_index_set(l, i); /* set_dirty */
mul_v2_m3v3(projverts[i], axis_mat, l->v->co);
+ add_v2_v2(center, projverts[i]);
}
- bm->elem_index_dirty |= BM_LOOP;
/* first test for completely convex face */
if (is_poly_convex_v2((const float (*)[2])projverts, f->len)) {
return;
}
+ mul_v2_fl(center, 1.0f / f->len);
+
for (i = 0, l = BM_FACE_FIRST_LOOP(f); i < f->len; i++, l = l->next) {
+ BM_elem_index_set(l, i); /* set_dirty */
+
+ /* center the projection for maximum accuracy */
+ sub_v2_v2(projverts[i], center);
+
out[0] = max_ff(out[0], projverts[i][0]);
out[1] = max_ff(out[1], projverts[i][1]);
}
+ bm->elem_index_dirty |= BM_LOOP;
/* ensure we are well outside the face bounds (value is arbitrary) */
add_v2_fl(out, 1.0f);
for (i = 0; i < len; i++) {
- copy_v2_v2(edgeverts[a + 0], projverts[BM_elem_index_get(loops[i][0])]);
- copy_v2_v2(edgeverts[a + 1], projverts[BM_elem_index_get(loops[i][1])]);
- scale_edge_v2f(edgeverts[a + 0], edgeverts[a + 1], fac2);
- a += 2;
+ edgeverts[i][0] = projverts[BM_elem_index_get(loops[i][0])];
+ edgeverts[i][1] = projverts[BM_elem_index_get(loops[i][1])];
}
/* do convexity test */
for (i = 0; i < len; i++) {
- copy_v2_v2(v2, edgeverts[i * 2 + 0]);
- copy_v2_v2(v3, edgeverts[i * 2 + 1]);
-
- mid_v2_v2v2(mid, v2, v3);
+ float mid[2];
+ mid_v2_v2v2(mid, edgeverts[i][0], edgeverts[i][1]);
- clen = 0;
- for (j = 0; j < f->len; j++) {
- p1 = projverts[j];
- p2 = projverts[(j + 1) % f->len];
-
-#if 0
- copy_v2_v2(v1, p1);
- copy_v2_v2(v2, p2);
-
- scale_edge_v2f(v1, v2, fac1);
- if (line_crosses_v2f(v1, v2, mid, out)) {
- clen++;
- }
-#else
- if (line_crosses_v2f(p1, p2, mid, out)) {
- clen++;
+ int isect = 0;
+ int j_prev;
+ for (j = 0, j_prev = f->len - 1; j < f->len; j_prev = j++) {
+ const float *f_edge[2] = {projverts[j_prev], projverts[j]};
+ if (isect_seg_seg_v2(UNPACK2(f_edge), mid, out) == ISECT_LINE_LINE_CROSS) {
+ isect++;
}
-#endif
}
- if (clen % 2 == 0) {
+ if (isect % 2 == 0) {
loops[i][0] = NULL;
}
}
- /* do line crossing tests */
- for (i = 0; i < f->len; i++) {
- p1 = projverts[i];
- p2 = projverts[(i + 1) % f->len];
-
- copy_v2_v2(v1, p1);
- copy_v2_v2(v2, p2);
-
- scale_edge_v2f(v1, v2, fac1);
+#define EDGE_SHARE_VERT(e1, e2) \
+ ((ELEM((e1)[0], (e2)[0], (e2)[1])) || \
+ (ELEM((e1)[1], (e2)[0], (e2)[1])))
+ /* do line crossing tests */
+ for (i = 0, i_prev = f->len - 1; i < f->len; i_prev = i++) {
+ const float *f_edge[2] = {projverts[i_prev], projverts[i]};
for (j = 0; j < len; j++) {
- if (!loops[j][0]) {
- continue;
- }
-
- p3 = edgeverts[j * 2];
- p4 = edgeverts[j * 2 + 1];
-
- if (line_crosses_v2f(v1, v2, p3, p4)) {
- loops[j][0] = NULL;
+ if ((loops[j][0] != NULL) &&
+ !EDGE_SHARE_VERT(f_edge, edgeverts[j]))
+ {
+ if (isect_seg_seg_v2(UNPACK2(f_edge), UNPACK2(edgeverts[j])) == ISECT_LINE_LINE_CROSS) {
+ loops[j][0] = NULL;
+ }
}
}
}
+ /* self intersect tests */
for (i = 0; i < len; i++) {
- for (j = 0; j < len; j++) {
- if (j != i && loops[i][0] && loops[j][0]) {
- p1 = edgeverts[i * 2];
- p2 = edgeverts[i * 2 + 1];
- p3 = edgeverts[j * 2];
- p4 = edgeverts[j * 2 + 1];
-
- copy_v2_v2(v1, p1);
- copy_v2_v2(v2, p2);
-
- scale_edge_v2f(v1, v2, fac1);
-
- if (line_crosses_v2f(v1, v2, p3, p4)) {
- loops[i][0] = NULL;
+ if (loops[i][0]) {
+ for (j = i + 1; j < len; j++) {
+ if ((loops[j][0] != NULL) &&
+ !EDGE_SHARE_VERT(edgeverts[i], edgeverts[j]))
+ {
+ if (isect_seg_seg_v2(UNPACK2(edgeverts[i]), UNPACK2(edgeverts[j])) == ISECT_LINE_LINE_CROSS) {
+ loops[i][0] = NULL;
+ break;
+ }
}
}
}
}
+
+#undef EDGE_SHARE_VERT
}
/**
diff --git a/source/blender/bmesh/intern/bmesh_polygon.h b/source/blender/bmesh/intern/bmesh_polygon.h
index 8f0df81af73..1e50a504875 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.h
+++ b/source/blender/bmesh/intern/bmesh_polygon.h
@@ -45,7 +45,11 @@ float BM_face_calc_normal_vcos(
float BM_face_calc_normal_subset(const BMLoop *l_first, const BMLoop *l_last, float r_no[3]) ATTR_NONNULL();
float BM_face_calc_area(const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
float BM_face_calc_perimeter(const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-void BM_face_calc_plane(const BMFace *f, float r_plane[3]) ATTR_NONNULL();
+void BM_face_calc_tangent_edge(const BMFace *f, float r_plane[3]) ATTR_NONNULL();
+void BM_face_calc_tangent_edge_pair(const BMFace *f, float r_plane[3]) ATTR_NONNULL();
+void BM_face_calc_tangent_edge_diagonal(const BMFace *f, float r_plane[3]) ATTR_NONNULL();
+void BM_face_calc_tangent_vert_diagonal(const BMFace *f, float r_plane[3]) ATTR_NONNULL();
+void BM_face_calc_tangent_auto(const BMFace *f, float r_plane[3]) ATTR_NONNULL();
void BM_face_calc_center_bounds(const BMFace *f, float center[3]) ATTR_NONNULL();
void BM_face_calc_center_mean(const BMFace *f, float center[3]) ATTR_NONNULL();
void BM_face_calc_center_mean_vcos(
@@ -90,6 +94,7 @@ void BM_face_as_array_vert_quad(BMFace *f, BMVert *r_verts[4]) ATTR_NONNULL();
void BM_face_as_array_loop_tri(BMFace *f, BMLoop *r_loops[3]) ATTR_NONNULL();
void BM_face_as_array_loop_quad(BMFace *f, BMLoop *r_loops[4]) ATTR_NONNULL();
-void BM_vert_tri_calc_plane(BMVert *verts[3], float r_plane[3]);
+void BM_vert_tri_calc_tangent_edge(BMVert *verts[3], float r_tangent[3]);
+void BM_vert_tri_calc_tangent_edge_pair(BMVert *verts[3], float r_tangent[3]);
#endif /* __BMESH_POLYGON_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
index c224a1ad587..6ce7c100b0d 100644
--- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
+++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
@@ -97,15 +97,27 @@ static BMLoop *bm_edge_flagged_radial_first(BMEdge *e)
return NULL;
}
+static void normalize_v2_m3_v3v3(float out[2], float axis_mat[3][3], const float v1[3], const float v2[3])
+{
+ float dir[3];
+ sub_v3_v3v3(dir, v1, v2);
+ mul_v2_m3v3(out, axis_mat, dir);
+ normalize_v2(out);
+}
+
+
+/**
+ * \note Be sure to update #bm_face_split_edgenet_find_loop_pair_exists
+ * when making changed to edge picking logic.
+ */
static bool bm_face_split_edgenet_find_loop_pair(
- BMVert *v_init, const float face_normal[3],
+ BMVert *v_init,
+ const float face_normal[3], float face_normal_matrix[3][3],
BMEdge *e_pair[2])
{
/* Always find one boundary edge (to determine winding)
* and one wire (if available), otherwise another boundary.
*/
- BMIter iter;
- BMEdge *e;
/* detect winding */
BMLoop *l_walk;
@@ -116,18 +128,22 @@ static bool bm_face_split_edgenet_find_loop_pair(
int edges_boundary_len = 0;
int edges_wire_len = 0;
- BM_ITER_ELEM (e, &iter, v_init, BM_EDGES_OF_VERT) {
- if (BM_ELEM_API_FLAG_TEST(e, EDGE_NET)) {
- const unsigned int count = bm_edge_flagged_radial_count(e);
- if (count == 1) {
- BLI_SMALLSTACK_PUSH(edges_boundary, e);
- edges_boundary_len++;
- }
- else if (count == 0) {
- BLI_SMALLSTACK_PUSH(edges_wire, e);
- edges_wire_len++;
+ {
+ BMEdge *e, *e_first;
+ e = e_first = v_init->e;
+ do {
+ if (BM_ELEM_API_FLAG_TEST(e, EDGE_NET)) {
+ const unsigned int count = bm_edge_flagged_radial_count(e);
+ if (count == 1) {
+ BLI_SMALLSTACK_PUSH(edges_boundary, e);
+ edges_boundary_len++;
+ }
+ else if (count == 0) {
+ BLI_SMALLSTACK_PUSH(edges_wire, e);
+ edges_wire_len++;
+ }
}
- }
+ } while ((e = BM_DISK_EDGE_NEXT(e, v_init)) != e_first);
}
/* first edge should always be boundary */
@@ -136,10 +152,17 @@ static bool bm_face_split_edgenet_find_loop_pair(
}
e_pair[0] = BLI_SMALLSTACK_POP(edges_boundary);
+ /* use to hold boundary OR wire edges */
+ BLI_SMALLSTACK_DECLARE(edges_search, BMEdge *);
+
/* attempt one boundary and one wire, or 2 boundary */
if (edges_wire_len == 0) {
- if (edges_boundary_len >= 2) {
+ if (edges_boundary_len > 1) {
e_pair[1] = BLI_SMALLSTACK_POP(edges_boundary);
+
+ if (edges_boundary_len > 2) {
+ BLI_SMALLSTACK_SWAP(edges_search, edges_boundary);
+ }
}
else {
/* one boundary and no wire */
@@ -148,27 +171,37 @@ static bool bm_face_split_edgenet_find_loop_pair(
}
else {
e_pair[1] = BLI_SMALLSTACK_POP(edges_wire);
-
if (edges_wire_len > 1) {
- BMVert *v_prev = BM_edge_other_vert(e_pair[0], v_init);
- BMVert *v_next;
- float angle_best;
-
- v_next = BM_edge_other_vert(e_pair[1], v_init);
- angle_best = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal);
-
- while ((e = BLI_SMALLSTACK_POP(edges_wire))) {
- float angle_test;
- v_next = BM_edge_other_vert(e, v_init);
- angle_test = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal);
- if (angle_test < angle_best) {
- angle_best = angle_test;
- e_pair[1] = e;
- }
- }
+ BLI_SMALLSTACK_SWAP(edges_search, edges_wire);
}
}
+ /* if we swapped above, search this list for the best edge */
+ if (!BLI_SMALLSTACK_IS_EMPTY(edges_search)) {
+ /* find the best edge in 'edge_list' to use for 'e_pair[1]' */
+ const BMVert *v_prev = BM_edge_other_vert(e_pair[0], v_init);
+ const BMVert *v_next = BM_edge_other_vert(e_pair[1], v_init);
+
+ float dir_prev[2], dir_next[2];
+
+ normalize_v2_m3_v3v3(dir_prev, face_normal_matrix, v_prev->co, v_init->co);
+ normalize_v2_m3_v3v3(dir_next, face_normal_matrix, v_next->co, v_init->co);
+ float angle_best_cos = dot_v2v2(dir_next, dir_prev);
+
+ BMEdge *e;
+ while ((e = BLI_SMALLSTACK_POP(edges_search))) {
+ v_next = BM_edge_other_vert(e, v_init);
+ float dir_test[2];
+
+ normalize_v2_m3_v3v3(dir_test, face_normal_matrix, v_next->co, v_init->co);
+ const float angle_test_cos = dot_v2v2(dir_prev, dir_test);
+
+ if (angle_test_cos > angle_best_cos) {
+ angle_best_cos = angle_test_cos;
+ e_pair[1] = e;
+ }
+ }
+ }
/* flip based on winding */
l_walk = bm_edge_flagged_radial_first(e_pair[0]);
@@ -186,6 +219,58 @@ static bool bm_face_split_edgenet_find_loop_pair(
return true;
}
+/**
+ * A reduced version of #bm_face_split_edgenet_find_loop_pair
+ * that only checks if it would return true.
+ *
+ * \note There is no use in caching resulting edges here,
+ * since between this check and running #bm_face_split_edgenet_find_loop,
+ * the selected edges may have had faces attached.
+ */
+static bool bm_face_split_edgenet_find_loop_pair_exists(
+ BMVert *v_init)
+{
+ int edges_boundary_len = 0;
+ int edges_wire_len = 0;
+
+ {
+ BMEdge *e, *e_first;
+ e = e_first = v_init->e;
+ do {
+ if (BM_ELEM_API_FLAG_TEST(e, EDGE_NET)) {
+ const unsigned int count = bm_edge_flagged_radial_count(e);
+ if (count == 1) {
+ edges_boundary_len++;
+ }
+ else if (count == 0) {
+ edges_wire_len++;
+ }
+ }
+ } while ((e = BM_DISK_EDGE_NEXT(e, v_init)) != e_first);
+ }
+
+ /* first edge should always be boundary */
+ if (edges_boundary_len == 0) {
+ return false;
+ }
+
+ /* attempt one boundary and one wire, or 2 boundary */
+ if (edges_wire_len == 0) {
+ if (edges_boundary_len >= 2) {
+ /* pass */
+ }
+ else {
+ /* one boundary and no wire */
+ return false;
+ }
+ }
+ else {
+ /* pass */
+ }
+
+ return true;
+}
+
static bool bm_face_split_edgenet_find_loop_walk(
BMVert *v_init, const float face_normal[3],
/* cache to avoid realloc every time */
@@ -232,9 +317,6 @@ static bool bm_face_split_edgenet_find_loop_walk(
* alternatives are stored in the 'vert_stack'.
*/
while ((v = BLI_SMALLSTACK_POP_EX(vert_stack, vert_stack_next))) {
- BMIter eiter;
- BMEdge *e_next;
-
#ifdef USE_FASTPATH_NOFORK
walk_nofork:
#else
@@ -250,35 +332,42 @@ walk_nofork:
goto finally;
}
- BM_ITER_ELEM (e_next, &eiter, v, BM_EDGES_OF_VERT) {
- if ((v->e != e_next) &&
- (BM_ELEM_API_FLAG_TEST(e_next, EDGE_NET)) &&
- (bm_edge_flagged_radial_count(e_next) < 2))
- {
- BMVert *v_next;
+ BMEdge *e_next, *e_first;
+ e_first = v->e;
+ e_next = BM_DISK_EDGE_NEXT(e_first, v); /* always skip this verts edge */
+
+ /* in rare cases there may be edges with a single connecting vertex */
+ if (e_next != e_first) {
+ do {
+ if ((BM_ELEM_API_FLAG_TEST(e_next, EDGE_NET)) &&
+ (bm_edge_flagged_radial_count(e_next) < 2))
+ {
+ BMVert *v_next;
- v_next = BM_edge_other_vert(e_next, v);
+ v_next = BM_edge_other_vert(e_next, v);
+ BLI_assert(v->e != e_next);
#ifdef DEBUG_PRINT
- /* indent and print */
- {
- BMVert *_v = v;
- do {
- printf(" ");
- } while ((_v = BM_edge_other_vert(_v->e, _v)) != v_init);
- printf("vert %d -> %d (add=%d)\n",
- BM_elem_index_get(v), BM_elem_index_get(v_next),
- BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT) == 0);
- }
+ /* indent and print */
+ {
+ BMVert *_v = v;
+ do {
+ printf(" ");
+ } while ((_v = BM_edge_other_vert(_v->e, _v)) != v_init);
+ printf("vert %d -> %d (add=%d)\n",
+ BM_elem_index_get(v), BM_elem_index_get(v_next),
+ BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT) == 0);
+ }
#endif
- if (!BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT)) {
- eo = STACK_PUSH_RET_PTR(edge_order);
- eo->v = v_next;
+ if (!BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT)) {
+ eo = STACK_PUSH_RET_PTR(edge_order);
+ eo->v = v_next;
- v_next->e = e_next;
+ v_next->e = e_next;
+ }
}
- }
+ } while ((e_next = BM_DISK_EDGE_NEXT(e_next, v)) != e_first);
}
#ifdef USE_FASTPATH_NOFORK
@@ -329,7 +418,7 @@ finally:
}
static bool bm_face_split_edgenet_find_loop(
- BMVert *v_init, const float face_normal[3],
+ BMVert *v_init, const float face_normal[3], float face_normal_matrix[3][3],
/* cache to avoid realloc every time */
struct VertOrder *edge_order, const unsigned int edge_order_len,
BMVert **r_face_verts, int *r_face_verts_len)
@@ -337,7 +426,7 @@ static bool bm_face_split_edgenet_find_loop(
BMEdge *e_pair[2];
BMVert *v;
- if (!bm_face_split_edgenet_find_loop_pair(v_init, face_normal, e_pair)) {
+ if (!bm_face_split_edgenet_find_loop_pair(v_init, face_normal, face_normal_matrix, e_pair)) {
return false;
}
@@ -432,12 +521,18 @@ bool BM_face_split_edgenet(
BM_ELEM_API_FLAG_ENABLE(l_iter->e, EDGE_NET);
} while ((l_iter = l_iter->next) != l_first);
+ float face_normal_matrix[3][3];
+ axis_dominant_v3_to_m3(face_normal_matrix, f->no);
+
/* any vert can be used to begin with */
STACK_PUSH(vert_queue, l_first->v);
while ((v = STACK_POP(vert_queue))) {
- if (bm_face_split_edgenet_find_loop(v, f->no, edge_order, edge_order_len, face_verts, &face_verts_len)) {
+ if (bm_face_split_edgenet_find_loop(
+ v, f->no, face_normal_matrix,
+ edge_order, edge_order_len, face_verts, &face_verts_len))
+ {
BMFace *f_new;
f_new = BM_face_create_verts(bm, face_verts, face_verts_len, f, BM_CREATE_NOP, false);
@@ -447,7 +542,6 @@ bool BM_face_split_edgenet(
}
if (f_new) {
- bool l_prev_is_boundary;
BLI_array_append(face_arr, f_new);
copy_v3_v3(f_new->no, f->no);
@@ -463,13 +557,10 @@ bool BM_face_split_edgenet(
/* add new verts to keep finding loops for
* (verts between boundary and manifold edges) */
l_iter = l_first = BM_FACE_FIRST_LOOP(f_new);
- l_prev_is_boundary = (bm_edge_flagged_radial_count(l_iter->prev->e) == 1);
do {
- bool l_iter_is_boundary = (bm_edge_flagged_radial_count(l_iter->e) == 1);
- if (l_prev_is_boundary != l_iter_is_boundary) {
+ if (bm_face_split_edgenet_find_loop_pair_exists(l_iter->v)) {
STACK_PUSH(vert_queue, l_iter->v);
}
- l_prev_is_boundary = l_iter_is_boundary;
} while ((l_iter = l_iter->next) != l_first);
}
}
diff --git a/source/blender/bmesh/intern/bmesh_private.h b/source/blender/bmesh/intern/bmesh_private.h
index 9b3a147301d..d8d297c9298 100644
--- a/source/blender/bmesh/intern/bmesh_private.h
+++ b/source/blender/bmesh/intern/bmesh_private.h
@@ -67,12 +67,13 @@ enum {
_FLAG_MV = (1 << 1), /* make face, vertex */
_FLAG_OVERLAP = (1 << 2), /* general overlap flag */
_FLAG_WALK = (1 << 3), /* general walk flag (keep clean) */
+ _FLAG_WALK_ALT = (1 << 4), /* same as _FLAG_WALK, for when a second tag is needed */
_FLAG_ELEM_CHECK = (1 << 7), /* reserved for bmesh_elem_check */
};
#define BM_ELEM_API_FLAG_ENABLE(element, f) { ((element)->head.api_flag |= (f)); } (void)0
-#define BM_ELEM_API_FLAG_DISABLE(element, f) { ((element)->head.api_flag &= ~(f)); } (void)0
+#define BM_ELEM_API_FLAG_DISABLE(element, f) { ((element)->head.api_flag &= (unsigned char)~(f)); } (void)0
#define BM_ELEM_API_FLAG_TEST(element, f) ((element)->head.api_flag & (f))
#define BM_ELEM_API_FLAG_CLEAR(element) { ((element)->head.api_flag = 0); } (void)0
diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c
index 9b074dc4db4..b5f9575aff5 100644
--- a/source/blender/bmesh/intern/bmesh_queries.c
+++ b/source/blender/bmesh/intern/bmesh_queries.c
@@ -2065,7 +2065,7 @@ bool BM_face_exists_multi(BMVert **varr, BMEdge **earr, int len)
}
/* 2) loop over non-boundary edges that use boundary verts,
- * check each have 2 tagges faces connected (faces that only use 'varr' verts) */
+ * check each have 2 tagged faces connected (faces that only use 'varr' verts) */
ok = true;
for (i = 0; i < len; i++) {
BM_ITER_ELEM (e, &fiter, varr[i], BM_EDGES_OF_VERT) {
diff --git a/source/blender/bmesh/intern/bmesh_queries_inline.h b/source/blender/bmesh/intern/bmesh_queries_inline.h
index 430ba10fb42..09cf39b526d 100644
--- a/source/blender/bmesh/intern/bmesh_queries_inline.h
+++ b/source/blender/bmesh/intern/bmesh_queries_inline.h
@@ -146,6 +146,13 @@ BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_b)
return (ELEM(l_b, l_a->next, l_a->prev));
}
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
+BLI_INLINE bool BM_loop_is_manifold(const BMLoop *l)
+{
+ return ((l != l->radial_next) &&
+ (l == l->radial_next->radial_next));
+}
+
/**
* Check if we have a single wire edge user.
*/
diff --git a/source/blender/bmesh/intern/bmesh_walkers.h b/source/blender/bmesh/intern/bmesh_walkers.h
index f5a801a31c3..b2373a069db 100644
--- a/source/blender/bmesh/intern/bmesh_walkers.h
+++ b/source/blender/bmesh/intern/bmesh_walkers.h
@@ -125,6 +125,7 @@ enum {
BMW_LOOPDATA_ISLAND,
BMW_ISLANDBOUND,
BMW_ISLAND,
+ BMW_ISLAND_MANIFOLD,
BMW_CONNECTED_VERTEX,
/* end of array index enum vals */
diff --git a/source/blender/bmesh/intern/bmesh_walkers_impl.c b/source/blender/bmesh/intern/bmesh_walkers_impl.c
index 627f8358410..279440984bb 100644
--- a/source/blender/bmesh/intern/bmesh_walkers_impl.c
+++ b/source/blender/bmesh/intern/bmesh_walkers_impl.c
@@ -49,7 +49,7 @@ static bool bmw_mask_check_vert(BMWalker *walker, BMVert *v)
if ((walker->flag & BMW_FLAG_TEST_HIDDEN) && BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
return false;
}
- else if (walker->mask_vert && !BMO_elem_flag_test(walker->bm, v, walker->mask_vert)) {
+ else if (walker->mask_vert && !BMO_vert_flag_test(walker->bm, v, walker->mask_vert)) {
return false;
}
else {
@@ -62,7 +62,7 @@ static bool bmw_mask_check_edge(BMWalker *walker, BMEdge *e)
if ((walker->flag & BMW_FLAG_TEST_HIDDEN) && BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
return false;
}
- else if (walker->mask_edge && !BMO_elem_flag_test(walker->bm, e, walker->mask_edge)) {
+ else if (walker->mask_edge && !BMO_edge_flag_test(walker->bm, e, walker->mask_edge)) {
return false;
}
else {
@@ -75,7 +75,7 @@ static bool bmw_mask_check_face(BMWalker *walker, BMFace *f)
if ((walker->flag & BMW_FLAG_TEST_HIDDEN) && BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
return false;
}
- else if (walker->mask_face && !BMO_elem_flag_test(walker->bm, f, walker->mask_face)) {
+ else if (walker->mask_face && !BMO_face_flag_test(walker->bm, f, walker->mask_face)) {
return false;
}
else {
@@ -223,7 +223,7 @@ static void *bmw_VertShellWalker_step(BMWalker *walker)
do {
if (!BLI_gset_haskey(walker->visit_set, curedge)) {
if (!walker->restrictflag ||
- (walker->restrictflag && BMO_elem_flag_test(walker->bm, curedge, walker->restrictflag)))
+ (walker->restrictflag && BMO_edge_flag_test(walker->bm, curedge, walker->restrictflag)))
{
BMwShellWalker *newstate;
@@ -711,13 +711,6 @@ static void *bmw_IslandboundWalker_step(BMWalker *walker)
e = l->e;
v = BM_edge_other_vert(e, iwalk->lastv);
-
- if (!BM_vert_is_manifold(v)) {
- BMW_reset(walker);
- BMO_error_raise(walker->bm, NULL, BMERR_WALKER_FAILED,
- "Non-manifold vert while searching region boundary");
- return NULL;
- }
/* pop off current state */
BMW_state_remove(walker);
@@ -726,7 +719,7 @@ static void *bmw_IslandboundWalker_step(BMWalker *walker)
while (1) {
l = BM_loop_other_edge_loop(l, v);
- if (l != l->radial_next) {
+ if (BM_loop_is_manifold(l)) {
l = l->radial_next;
f = l->f;
e = l->e;
@@ -737,6 +730,7 @@ static void *bmw_IslandboundWalker_step(BMWalker *walker)
}
}
else {
+ /* treat non-manifold edges as boundaries */
f = l->f;
e = l->e;
break;
@@ -754,7 +748,7 @@ static void *bmw_IslandboundWalker_step(BMWalker *walker)
iwalk = BMW_state_add(walker);
iwalk->base = owalk.base;
- //if (!BMO_elem_flag_test(walker->bm, l->f, walker->restrictflag))
+ //if (!BMO_face_flag_test(walker->bm, l->f, walker->restrictflag))
// iwalk->curloop = l->radial_next;
iwalk->curloop = l; //else iwalk->curloop = l;
iwalk->lastv = v;
@@ -791,25 +785,44 @@ static void *bmw_IslandWalker_yield(BMWalker *walker)
return iwalk->cur;
}
-static void *bmw_IslandWalker_step(BMWalker *walker)
+static void *bmw_IslandWalker_step_ex(BMWalker *walker, bool only_manifold)
{
BMwIslandWalker *iwalk, owalk;
- BMIter iter, liter;
- BMFace *f;
- BMLoop *l;
+ BMLoop *l_iter, *l_first;
BMW_state_remove_r(walker, &owalk);
iwalk = &owalk;
- l = BM_iter_new(&liter, walker->bm, BM_LOOPS_OF_FACE, iwalk->cur);
- for ( ; l; l = BM_iter_step(&liter)) {
+ l_iter = l_first = BM_FACE_FIRST_LOOP(iwalk->cur);
+ do {
/* could skip loop here too, but don't add unless we need it */
- if (!bmw_mask_check_edge(walker, l->e)) {
+ if (!bmw_mask_check_edge(walker, l_iter->e)) {
continue;
}
- f = BM_iter_new(&iter, walker->bm, BM_FACES_OF_EDGE, l->e);
- for ( ; f; f = BM_iter_step(&iter)) {
+ BMLoop *l_radial_iter;
+
+ if (only_manifold && (l_iter->radial_next != l_iter)) {
+ int face_count = 1;
+ /* check other faces (not this one), ensure only one other can be walked onto. */
+ l_radial_iter = l_iter->radial_next;
+ do {
+ if (bmw_mask_check_face(walker, l_radial_iter->f)) {
+ face_count++;
+ if (face_count == 3) {
+ break;
+ }
+ }
+ } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter);
+
+ if (face_count != 2) {
+ continue;
+ }
+ }
+
+ l_radial_iter = l_iter;
+ while ((l_radial_iter = l_radial_iter->radial_next) != l_iter) {
+ BMFace *f = l_radial_iter->f;
if (!bmw_mask_check_face(walker, f)) {
continue;
@@ -823,17 +836,30 @@ static void *bmw_IslandWalker_step(BMWalker *walker)
if (BLI_gset_haskey(walker->visit_set, f)) {
continue;
}
-
+
iwalk = BMW_state_add(walker);
iwalk->cur = f;
BLI_gset_insert(walker->visit_set, f);
break;
}
- }
-
+ } while ((l_iter = l_iter->next) != l_first);
+
return owalk.cur;
}
+static void *bmw_IslandWalker_step(BMWalker *walker)
+{
+ return bmw_IslandWalker_step_ex(walker, false);
+}
+
+/**
+ * Ignore edges that don't have 2x usable faces.
+ */
+static void *bmw_IslandManifoldWalker_step(BMWalker *walker)
+{
+ return bmw_IslandWalker_step_ex(walker, true);
+}
+
/** \} */
@@ -1608,6 +1634,16 @@ static BMWalker bmw_IslandWalker_Type = {
BM_EDGE | BM_FACE, /* valid restrict masks */
};
+static BMWalker bmw_IslandManifoldWalker_Type = {
+ BM_FACE,
+ bmw_IslandWalker_begin,
+ bmw_IslandManifoldWalker_step, /* only difference with BMW_ISLAND */
+ bmw_IslandWalker_yield,
+ sizeof(BMwIslandWalker),
+ BMW_BREADTH_FIRST,
+ BM_EDGE | BM_FACE, /* valid restrict masks */
+};
+
static BMWalker bmw_EdgeLoopWalker_Type = {
BM_EDGE,
bmw_EdgeLoopWalker_begin,
@@ -1680,6 +1716,7 @@ BMWalker *bm_walker_types[] = {
&bmw_UVEdgeWalker_Type, /* BMW_LOOPDATA_ISLAND */
&bmw_IslandboundWalker_Type, /* BMW_ISLANDBOUND */
&bmw_IslandWalker_Type, /* BMW_ISLAND */
+ &bmw_IslandManifoldWalker_Type, /* BMW_ISLAND_MANIFOLD */
&bmw_ConnectedVertexWalker_Type, /* BMW_CONNECTED_VERTEX */
};
diff --git a/source/blender/bmesh/operators/bmo_beautify.c b/source/blender/bmesh/operators/bmo_beautify.c
index 4a292c33472..c68d92ea5e0 100644
--- a/source/blender/bmesh/operators/bmo_beautify.c
+++ b/source/blender/bmesh/operators/bmo_beautify.c
@@ -52,7 +52,7 @@ void bmo_beautify_fill_exec(BMesh *bm, BMOperator *op)
int edge_array_len = 0;
BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) {
if (f->len == 3) {
- BMO_elem_flag_enable(bm, f, FACE_MARK);
+ BMO_face_flag_enable(bm, f, FACE_MARK);
}
}
@@ -68,8 +68,8 @@ void bmo_beautify_fill_exec(BMesh *bm, BMOperator *op)
/* edge is manifold and can be rotated */
if (BM_edge_rotate_check(e) &&
/* faces are tagged */
- BMO_elem_flag_test(bm, e->l->f, FACE_MARK) &&
- BMO_elem_flag_test(bm, e->l->radial_next->f, FACE_MARK))
+ BMO_face_flag_test(bm, e->l->f, FACE_MARK) &&
+ BMO_face_flag_test(bm, e->l->radial_next->f, FACE_MARK))
{
edge_array[edge_array_len] = e;
edge_array_len++;
diff --git a/source/blender/bmesh/operators/bmo_bridge.c b/source/blender/bmesh/operators/bmo_bridge.c
index a0149a41921..6ef0fd6b084 100644
--- a/source/blender/bmesh/operators/bmo_bridge.c
+++ b/source/blender/bmesh/operators/bmo_bridge.c
@@ -131,13 +131,13 @@ static void bm_face_edges_tag_out(BMesh *bm, BMFace *f)
BMLoop *l_iter, *l_first;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
- BMO_elem_flag_enable(bm, l_iter->e, EDGE_OUT);
+ BMO_edge_flag_enable(bm, l_iter->e, EDGE_OUT);
} while ((l_iter = l_iter->next) != l_first);
}
static bool bm_edge_test_cb(BMEdge *e, void *bm_v)
{
- return BMO_elem_flag_test((BMesh *)bm_v, e, EDGE_MARK);
+ return BMO_edge_flag_test((BMesh *)bm_v, e, EDGE_MARK);
}
static void bridge_loop_pair(
@@ -425,7 +425,7 @@ static void bridge_loop_pair(
if (f_example && (f_example != f)) {
BM_elem_attrs_copy(bm, bm, f_example, f);
}
- BMO_elem_flag_enable(bm, f, FACE_OUT);
+ BMO_face_flag_enable(bm, f, FACE_OUT);
BM_elem_flag_enable(f, BM_ELEM_TAG);
/* tag all edges of the face, untag the loop edges after */
@@ -486,7 +486,7 @@ static void bridge_loop_pair(
BMOIter siter;
BMFace *f;
BMO_ITER (f, &siter, op_sub.slots_in, "faces", BM_FACE) {
- BMO_elem_flag_enable(bm, f, FACE_OUT);
+ BMO_face_flag_enable(bm, f, FACE_OUT);
bm_face_edges_tag_out(bm, f);
}
}
@@ -498,7 +498,7 @@ static void bridge_loop_pair(
BMOIter siter;
BMFace *f;
BMO_ITER (f, &siter, op_sub.slots_out, "geom.out", BM_FACE) {
- BMO_elem_flag_enable(bm, f, FACE_OUT);
+ BMO_face_flag_enable(bm, f, FACE_OUT);
bm_face_edges_tag_out(bm, f);
}
}
@@ -520,7 +520,7 @@ static void bridge_loop_pair(
if (el_next) {
if (el->data != el_next->data) {
BMEdge *e = BM_edge_exists(el->data, el_next->data);
- BMO_elem_flag_disable(bm, e, EDGE_OUT);
+ BMO_edge_flag_disable(bm, e, EDGE_OUT);
}
}
}
diff --git a/source/blender/bmesh/operators/bmo_connect.c b/source/blender/bmesh/operators/bmo_connect.c
index 0213329118c..5c9cd8dc3fa 100644
--- a/source/blender/bmesh/operators/bmo_connect.c
+++ b/source/blender/bmesh/operators/bmo_connect.c
@@ -62,10 +62,10 @@ static int bm_face_connect_verts(BMesh *bm, BMFace *f, const bool check_degenera
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
- if (BMO_elem_flag_test(bm, l_iter->v, VERT_INPUT) &&
+ if (BMO_vert_flag_test(bm, l_iter->v, VERT_INPUT) &&
/* ensure this vertex isnt part of a contiguous group */
- ((BMO_elem_flag_test(bm, l_iter->prev->v, VERT_INPUT) == 0) ||
- (BMO_elem_flag_test(bm, l_iter->next->v, VERT_INPUT) == 0)))
+ ((BMO_vert_flag_test(bm, l_iter->prev->v, VERT_INPUT) == 0) ||
+ (BMO_vert_flag_test(bm, l_iter->next->v, VERT_INPUT) == 0)))
{
if (!l_tag_prev) {
l_tag_prev = l_tag_first = l_iter;
@@ -75,7 +75,7 @@ static int bm_face_connect_verts(BMesh *bm, BMFace *f, const bool check_degenera
if (!BM_loop_is_adjacent(l_tag_prev, l_iter)) {
BMEdge *e;
e = BM_edge_exists(l_tag_prev->v, l_iter->v);
- if (e == NULL || !BMO_elem_flag_test(bm, e, EDGE_OUT)) {
+ if (e == NULL || !BMO_edge_flag_test(bm, e, EDGE_OUT)) {
BMLoop **l_pair = STACK_PUSH_RET(loops_split);
l_pair[0] = l_tag_prev;
l_pair[1] = l_iter;
@@ -138,8 +138,8 @@ static int bm_face_connect_verts(BMesh *bm, BMFace *f, const bool check_degenera
if (!l_new || !f_new) {
return -1;
}
- // BMO_elem_flag_enable(bm, f_new, FACE_NEW);
- BMO_elem_flag_enable(bm, l_new->e, EDGE_OUT);
+ // BMO_face_flag_enable(bm, f_new, FACE_NEW);
+ BMO_edge_flag_enable(bm, l_new->e, EDGE_OUT);
}
return 1;
@@ -164,12 +164,12 @@ void bmo_connect_verts_exec(BMesh *bm, BMOperator *op)
BMIter iter;
BMLoop *l_iter;
- BMO_elem_flag_enable(bm, v, VERT_INPUT);
+ BMO_vert_flag_enable(bm, v, VERT_INPUT);
BM_ITER_ELEM (l_iter, &iter, v, BM_LOOPS_OF_VERT) {
f = l_iter->f;
- if (!BMO_elem_flag_test(bm, f, FACE_EXCLUDE)) {
- if (!BMO_elem_flag_test(bm, f, FACE_TAG)) {
- BMO_elem_flag_enable(bm, f, FACE_TAG);
+ if (!BMO_face_flag_test(bm, f, FACE_EXCLUDE)) {
+ if (!BMO_face_flag_test(bm, f, FACE_TAG)) {
+ BMO_face_flag_enable(bm, f, FACE_TAG);
if (f->len > 3) {
BLI_LINKSTACK_PUSH(faces, f);
}
@@ -179,11 +179,11 @@ void bmo_connect_verts_exec(BMesh *bm, BMOperator *op)
/* flag edges even if these are not newly created
* this way cut-pairs that include co-linear edges will get
* predictable output. */
- if (BMO_elem_flag_test(bm, l_iter->prev->v, VERT_INPUT)) {
- BMO_elem_flag_enable(bm, l_iter->prev->e, EDGE_OUT_ADJ);
+ if (BMO_vert_flag_test(bm, l_iter->prev->v, VERT_INPUT)) {
+ BMO_edge_flag_enable(bm, l_iter->prev->e, EDGE_OUT_ADJ);
}
- if (BMO_elem_flag_test(bm, l_iter->next->v, VERT_INPUT)) {
- BMO_elem_flag_enable(bm, l_iter->e, EDGE_OUT_ADJ);
+ if (BMO_vert_flag_test(bm, l_iter->next->v, VERT_INPUT)) {
+ BMO_edge_flag_enable(bm, l_iter->e, EDGE_OUT_ADJ);
}
}
}
diff --git a/source/blender/bmesh/operators/bmo_connect_concave.c b/source/blender/bmesh/operators/bmo_connect_concave.c
index 34f59aad4f1..9bb67ed9341 100644
--- a/source/blender/bmesh/operators/bmo_connect_concave.c
+++ b/source/blender/bmesh/operators/bmo_connect_concave.c
@@ -85,7 +85,7 @@ static bool bm_face_split_by_concave(
BMFace **faces_array = BLI_array_alloca(faces_array, faces_array_tot);
BMEdge **edges_array = BLI_array_alloca(edges_array, edges_array_tot);
const int quad_method = 0, ngon_method = 0; /* beauty */
- LinkNode *r_faces_double = NULL;
+ LinkNode *faces_double = NULL;
float normal[3];
BLI_assert(f_base->len > 3);
@@ -96,7 +96,7 @@ static bool bm_face_split_by_concave(
bm, f_base,
faces_array, &faces_array_tot,
edges_array, &edges_array_tot,
- &r_faces_double,
+ &faces_double,
quad_method, ngon_method, false,
pf_arena,
pf_heap, pf_ehash);
@@ -107,10 +107,10 @@ static bool bm_face_split_by_concave(
int i;
for (i = 0; i < faces_array_tot; i++) {
BMFace *f = faces_array[i];
- BMO_elem_flag_enable(bm, f, FACE_OUT);
+ BMO_face_flag_enable(bm, f, FACE_OUT);
}
}
- BMO_elem_flag_enable(bm, f_base, FACE_OUT);
+ BMO_face_flag_enable(bm, f_base, FACE_OUT);
if (edges_array_tot) {
int i;
@@ -120,7 +120,7 @@ static bool bm_face_split_by_concave(
for (i = 0; i < edges_array_tot; i++) {
BMLoop *l_pair[2];
BMEdge *e = edges_array[i];
- BMO_elem_flag_enable(bm, e, EDGE_OUT);
+ BMO_edge_flag_enable(bm, e, EDGE_OUT);
if (BM_edge_is_contiguous(e) &&
BM_edge_loop_pair(e, &l_pair[0], &l_pair[1]))
@@ -153,7 +153,7 @@ static bool bm_face_split_by_concave(
BMFace *f_new, *f_pair[2] = {l_pair[0]->f, l_pair[1]->f};
f_new = BM_faces_join(bm, f_pair, 2, true);
if (f_new) {
- BMO_elem_flag_enable(bm, f_new, FACE_OUT);
+ BMO_face_flag_enable(bm, f_new, FACE_OUT);
}
}
}
@@ -163,6 +163,13 @@ static bool bm_face_split_by_concave(
BLI_heap_clear(pf_heap, NULL);
BLI_edgehash_clear_ex(pf_ehash, NULL, BLI_POLYFILL_ALLOC_NGON_RESERVE);
+ while (faces_double) {
+ LinkNode *next = faces_double->next;
+ BM_face_kill(bm, faces_double->link);
+ MEM_freeN(faces_double);
+ faces_double = next;
+ }
+
return true;
}
diff --git a/source/blender/bmesh/operators/bmo_connect_nonplanar.c b/source/blender/bmesh/operators/bmo_connect_nonplanar.c
index c80fb95c44a..b8acc9d09b8 100644
--- a/source/blender/bmesh/operators/bmo_connect_nonplanar.c
+++ b/source/blender/bmesh/operators/bmo_connect_nonplanar.c
@@ -63,7 +63,7 @@ static float bm_face_subset_calc_planar(BMLoop *l_first, BMLoop *l_last, const f
return delta_z;
}
-static bool bm_face_split_find(BMesh *bm, BMFace *f, BMLoop *l_pair[2], float *r_angle)
+static bool bm_face_split_find(BMesh *bm, BMFace *f, BMLoop *l_pair[2], float *r_angle_cos)
{
BMLoop *l_iter, *l_first;
BMLoop **l_arr = BLI_array_alloca(l_arr, f->len);
@@ -73,7 +73,7 @@ static bool bm_face_split_find(BMesh *bm, BMFace *f, BMLoop *l_pair[2], float *r
/* angle finding */
float err_best = FLT_MAX;
- float angle_best = FLT_MAX;
+ float angle_best_cos = -FLT_MAX;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
i_a = 0;
@@ -108,7 +108,7 @@ static bool bm_face_split_find(BMesh *bm, BMFace *f, BMLoop *l_pair[2], float *r
l_pair[0] = l_a;
l_pair[1] = l_b;
- angle_best = angle_normalized_v3v3(no_a, no_b);
+ angle_best_cos = dot_v3v3(no_a, no_b);
found = true;
}
}
@@ -117,17 +117,17 @@ static bool bm_face_split_find(BMesh *bm, BMFace *f, BMLoop *l_pair[2], float *r
}
}
- *r_angle = angle_best;
+ *r_angle_cos = angle_best_cos;
return found;
}
-static bool bm_face_split_by_angle(BMesh *bm, BMFace *f, BMFace *r_f_pair[2], const float angle_limit)
+static bool bm_face_split_by_angle(BMesh *bm, BMFace *f, BMFace *r_f_pair[2], const float angle_limit_cos)
{
BMLoop *l_pair[2];
- float angle;
+ float angle_cos;
- if (bm_face_split_find(bm, f, l_pair, &angle) && (angle > angle_limit)) {
+ if (bm_face_split_find(bm, f, l_pair, &angle_cos) && (angle_cos < angle_limit_cos)) {
BMFace *f_new;
BMLoop *l_new;
@@ -136,9 +136,9 @@ static bool bm_face_split_by_angle(BMesh *bm, BMFace *f, BMFace *r_f_pair[2], co
r_f_pair[0] = f;
r_f_pair[1] = f_new;
- BMO_elem_flag_enable(bm, f, FACE_OUT);
- BMO_elem_flag_enable(bm, f_new, FACE_OUT);
- BMO_elem_flag_enable(bm, l_new->e, EDGE_OUT);
+ BMO_face_flag_enable(bm, f, FACE_OUT);
+ BMO_face_flag_enable(bm, f_new, FACE_OUT);
+ BMO_edge_flag_enable(bm, l_new->e, EDGE_OUT);
return true;
}
}
@@ -154,7 +154,7 @@ void bmo_connect_verts_nonplanar_exec(BMesh *bm, BMOperator *op)
bool changed = false;
BLI_LINKSTACK_DECLARE(fstack, BMFace *);
- const float angle_limit = BMO_slot_float_get(op->slots_in, "angle_limit");
+ const float angle_limit_cos = cosf(BMO_slot_float_get(op->slots_in, "angle_limit"));
BLI_LINKSTACK_INIT(fstack);
@@ -166,7 +166,7 @@ void bmo_connect_verts_nonplanar_exec(BMesh *bm, BMOperator *op)
while ((f = BLI_LINKSTACK_POP(fstack))) {
BMFace *f_pair[2];
- if (bm_face_split_by_angle(bm, f, f_pair, angle_limit)) {
+ if (bm_face_split_by_angle(bm, f, f_pair, angle_limit_cos)) {
int j;
for (j = 0; j < 2; j++) {
BM_face_normal_update(f_pair[j]);
diff --git a/source/blender/bmesh/operators/bmo_connect_pair.c b/source/blender/bmesh/operators/bmo_connect_pair.c
index 3b860778e1c..a73c86fd122 100644
--- a/source/blender/bmesh/operators/bmo_connect_pair.c
+++ b/source/blender/bmesh/operators/bmo_connect_pair.c
@@ -48,7 +48,7 @@
* - store a heap of paths which are being scanned (#PathContext.states).
* - continuously search the shortest path in the heap.
* - never step over the same element twice (tag elements as #ELE_TOUCHED).
- * this avoids going into an eternal loop of there are many possible branches (see T45582).
+ * this avoids going into an eternal loop if there are many possible branches (see T45582).
* - when running into a branch, create a new #PathLinkState state and add to the heap.
* - when the target is reached, finish - since none of the other paths can be shorter then the one just found.
* - if the connection can't be found - fail.
@@ -67,18 +67,29 @@
#define ELE_TOUCHED 4
#define FACE_WALK_TEST(f) (CHECK_TYPE_INLINE(f, BMFace *), \
- BMO_elem_flag_test(pc->bm_bmoflag, f, FACE_EXCLUDE) == 0)
+ BMO_face_flag_test(pc->bm_bmoflag, f, FACE_EXCLUDE) == 0)
#define VERT_WALK_TEST(v) (CHECK_TYPE_INLINE(v, BMVert *), \
- BMO_elem_flag_test(pc->bm_bmoflag, v, VERT_EXCLUDE) == 0)
+ BMO_vert_flag_test(pc->bm_bmoflag, v, VERT_EXCLUDE) == 0)
+#if 0
#define ELE_TOUCH_TEST(e) \
(CHECK_TYPE_ANY(e, BMVert *, BMEdge *, BMElem *, BMElemF *), \
BMO_elem_flag_test(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED))
+#endif
#define ELE_TOUCH_MARK(e) \
{ CHECK_TYPE_ANY(e, BMVert *, BMEdge *, BMElem *, BMElemF *); \
BMO_elem_flag_enable(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED); } ((void)0)
+#define ELE_TOUCH_TEST_VERT(v) BMO_vert_flag_test(pc->bm_bmoflag, v, ELE_TOUCHED)
+// #define ELE_TOUCH_MARK_VERT(v) BMO_vert_flag_enable(pc->bm_bmoflag, (BMElemF *)v, ELE_TOUCHED)
+
+#define ELE_TOUCH_TEST_EDGE(e) BMO_edge_flag_test(pc->bm_bmoflag, e, ELE_TOUCHED)
+// #define ELE_TOUCH_MARK_EDGE(e) BMO_edge_flag_enable(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED)
+
+// #define ELE_TOUCH_TEST_FACE(f) BMO_face_flag_test(pc->bm_bmoflag, f, ELE_TOUCHED)
+// #define ELE_TOUCH_MARK_FACE(f) BMO_face_flag_enable(pc->bm_bmoflag, (BMElemF *)f, ELE_TOUCHED)
+
// #define DEBUG_PRINT
typedef struct PathContext {
@@ -113,8 +124,8 @@ typedef struct PathLinkState {
} PathLinkState;
/**
- \name Min Dist Dir Util
-
+ * \name Min Dist Dir Util
+ *
* Simply getting the closest intersecting vert/edge is _not_ good enough. see T43792
* we need to get the closest in both directions since the absolute closest may be a dead-end.
*
@@ -352,7 +363,7 @@ static PathLinkState *state_step__face_edges(
BMElem *ele_next_from = (BMElem *)l_iter->f;
if (FACE_WALK_TEST((BMFace *)ele_next_from) &&
- (ELE_TOUCH_TEST(ele_next) == false))
+ (ELE_TOUCH_TEST_EDGE((BMEdge *)ele_next) == false))
{
min_dist_dir_update(mddir, dist_dir);
mddir->dist_min[index] = dist_test;
@@ -397,7 +408,7 @@ static PathLinkState *state_step__face_verts(
BMElem *ele_next_from = (BMElem *)l_iter->f;
if (FACE_WALK_TEST((BMFace *)ele_next_from) &&
- (ELE_TOUCH_TEST(ele_next) == false))
+ (ELE_TOUCH_TEST_VERT((BMVert *)ele_next) == false))
{
min_dist_dir_update(mddir, dist_dir);
mddir->dist_min[index] = dist_test;
@@ -480,7 +491,7 @@ static bool state_step(PathContext *pc, PathLinkState *state)
if (state_isect_co_exact(pc, v_other->co)) {
BMElem *ele_next = (BMElem *)v_other;
BMElem *ele_next_from = (BMElem *)e;
- if (ELE_TOUCH_TEST(ele_next) == false) {
+ if (ELE_TOUCH_TEST_VERT((BMVert *)ele_next) == false) {
state = state_link_add_test(pc, state, &state_orig, ele_next, ele_next_from);
}
}
@@ -650,7 +661,7 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op)
while (!BLI_heap_is_empty(pc.states)) {
#ifdef DEBUG_PRINT
- printf("\n%s: stepping %d\n", __func__, BLI_heap_size(pc.states));
+ printf("\n%s: stepping %u\n", __func__, BLI_heap_size(pc.states));
#endif
while (!BLI_heap_is_empty(pc.states)) {
@@ -703,11 +714,11 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op)
BMVert *v_new;
float e_fac = state_calc_co_pair_fac(&pc, e->v1->co, e->v2->co);
v_new = BM_edge_split(bm, e, e->v1, NULL, e_fac);
- BMO_elem_flag_enable(bm, v_new, VERT_OUT);
+ BMO_vert_flag_enable(bm, v_new, VERT_OUT);
}
else if (link->ele->head.htype == BM_VERT) {
BMVert *v = (BMVert *)link->ele;
- BMO_elem_flag_enable(bm, v, VERT_OUT);
+ BMO_vert_flag_enable(bm, v, VERT_OUT);
}
else {
BLI_assert(0);
@@ -715,8 +726,8 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op)
} while ((link = link->next));
}
- BMO_elem_flag_enable(bm, pc.v_a, VERT_OUT);
- BMO_elem_flag_enable(bm, pc.v_b, VERT_OUT);
+ BMO_vert_flag_enable(bm, pc.v_a, VERT_OUT);
+ BMO_vert_flag_enable(bm, pc.v_b, VERT_OUT);
BLI_mempool_destroy(pc.link_pool);
diff --git a/source/blender/bmesh/operators/bmo_create.c b/source/blender/bmesh/operators/bmo_create.c
index a1e20dab63e..7b8cb36ab59 100644
--- a/source/blender/bmesh/operators/bmo_create.c
+++ b/source/blender/bmesh/operators/bmo_create.c
@@ -52,12 +52,19 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op)
/* count number of each element type we were passe */
BMO_ITER (h, &oiter, op->slots_in, "geom", BM_VERT | BM_EDGE | BM_FACE) {
switch (h->htype) {
- case BM_VERT: totv++; break;
- case BM_EDGE: tote++; break;
- case BM_FACE: totf++; break;
+ case BM_VERT:
+ BMO_vert_flag_enable(bm, (BMVert *)h, ELE_NEW);
+ totv++;
+ break;
+ case BM_EDGE:
+ BMO_edge_flag_enable(bm, (BMEdge *)h, ELE_NEW);
+ tote++;
+ break;
+ case BM_FACE:
+ BMO_face_flag_enable(bm, (BMFace *)h, ELE_NEW);
+ totf++;
+ break;
}
-
- BMO_elem_flag_enable(bm, (BMElemF *)h, ELE_NEW);
}
/* --- Support Edge Creation ---
@@ -71,7 +78,7 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op)
/* create edge */
e = BM_edge_create(bm, verts[0], verts[1], NULL, BM_CREATE_NO_DOUBLE);
- BMO_elem_flag_enable(bm, e, ELE_OUT);
+ BMO_edge_flag_enable(bm, e, ELE_OUT);
tote += 1;
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, ELE_OUT);
return;
@@ -131,10 +138,10 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op)
BMEdge *e;
e = BM_edge_create(bm, v_free, v_a, NULL, BM_CREATE_NO_DOUBLE);
- BMO_elem_flag_enable(bm, e, ELE_NEW);
+ BMO_edge_flag_enable(bm, e, ELE_NEW);
e = BM_edge_create(bm, v_free, v_b, NULL, BM_CREATE_NO_DOUBLE);
- BMO_elem_flag_enable(bm, e, ELE_NEW);
+ BMO_edge_flag_enable(bm, e, ELE_NEW);
tote += 2;
}
}
@@ -236,7 +243,7 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op)
for (ese = bm->selected.first; ese; ese = ese->next) {
if (ese->htype == BM_VERT) {
- if (BMO_elem_flag_test(bm, (BMElemF *)ese->ele, ELE_NEW)) {
+ if (BMO_vert_flag_test(bm, (BMVert *)ese->ele, ELE_NEW)) {
tot_ese_v++;
}
else {
@@ -256,7 +263,7 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op)
BMVert *v = (BMVert *)ese->ele;
if (v_prev) {
BMEdge *e = BM_edge_create(bm, v, v_prev, NULL, BM_CREATE_NO_DOUBLE);
- BMO_elem_flag_enable(bm, e, ELE_OUT);
+ BMO_edge_flag_enable(bm, e, ELE_OUT);
}
v_prev = v;
}
@@ -286,7 +293,7 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op)
f = BM_face_create_ngon_vcloud(bm, vert_arr, totv, NULL, BM_CREATE_NO_DOUBLE);
if (f) {
- BMO_elem_flag_enable(bm, f, ELE_OUT);
+ BMO_face_flag_enable(bm, f, ELE_OUT);
f->mat_nr = mat_nr;
if (use_smooth) {
BM_elem_flag_enable(f, BM_ELEM_SMOOTH);
diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c
index c8dff4a8598..05efb14a699 100644
--- a/source/blender/bmesh/operators/bmo_dissolve.c
+++ b/source/blender/bmesh/operators/bmo_dissolve.c
@@ -43,6 +43,7 @@
#define FACE_MARK 1
#define FACE_ORIG 2
#define FACE_NEW 4
+#define FACE_TAG 8
#define EDGE_MARK 1
#define EDGE_TAG 2
@@ -73,10 +74,10 @@ static bool UNUSED_FUNCTION(check_hole_in_region) (BMesh *bm, BMFace *f)
for (f2 = BMW_begin(&regwalker, f); f2; f2 = BMW_step(&regwalker)) {
BM_ITER_ELEM (l2, &liter2, f2, BM_LOOPS_OF_FACE) {
l3 = l2->radial_next;
- if (BMO_elem_flag_test(bm, l3->f, FACE_MARK) !=
- BMO_elem_flag_test(bm, l2->f, FACE_MARK))
+ if (BMO_face_flag_test(bm, l3->f, FACE_MARK) !=
+ BMO_face_flag_test(bm, l2->f, FACE_MARK))
{
- if (!BMO_elem_flag_test(bm, l2->e, EDGE_MARK)) {
+ if (!BMO_edge_flag_test(bm, l2->e, EDGE_MARK)) {
return false;
}
}
@@ -98,14 +99,14 @@ static void bm_face_split(BMesh *bm, const short oflag, bool use_edge_delete)
}
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- if (BMO_elem_flag_test(bm, v, oflag)) {
+ if (BMO_vert_flag_test(bm, v, oflag)) {
if (BM_vert_is_edge_pair(v) == false) {
BMIter liter;
BMLoop *l;
BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
if (l->f->len > 3) {
- if (BMO_elem_flag_test(bm, l->next->v, oflag) == 0 &&
- BMO_elem_flag_test(bm, l->prev->v, oflag) == 0)
+ if (BMO_vert_flag_test(bm, l->next->v, oflag) == 0 &&
+ BMO_vert_flag_test(bm, l->prev->v, oflag) == 0)
{
BM_face_split(bm, l->f, l->next, l->prev, NULL, NULL, true);
}
@@ -152,23 +153,23 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op)
BMVert *v;
BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
- BMO_elem_flag_set(bm, v, VERT_MARK, !BM_vert_is_edge_pair(v));
+ BMO_vert_flag_set(bm, v, VERT_MARK, !BM_vert_is_edge_pair(v));
}
}
- BMO_slot_buffer_flag_enable(bm, op->slots_in, "faces", BM_FACE, FACE_MARK);
+ BMO_slot_buffer_flag_enable(bm, op->slots_in, "faces", BM_FACE, FACE_MARK | FACE_TAG);
/* collect region */
BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) {
BMFace *f_iter;
- if (!BMO_elem_flag_test(bm, f, FACE_MARK)) {
+ if (!BMO_face_flag_test(bm, f, FACE_TAG)) {
continue;
}
BLI_array_empty(faces);
faces = NULL; /* forces different allocatio */
- BMW_init(&regwalker, bm, BMW_ISLAND,
+ BMW_init(&regwalker, bm, BMW_ISLAND_MANIFOLD,
BMW_MASK_NOP, BMW_MASK_NOP, FACE_MARK,
BMW_FLAG_NOP, /* no need to check BMW_FLAG_TEST_HIDDEN, faces are already marked by the bmo */
BMW_NIL_LAY);
@@ -180,8 +181,8 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op)
for (i = 0; i < BLI_array_count(faces); i++) {
f_iter = faces[i];
- BMO_elem_flag_disable(bm, f_iter, FACE_MARK);
- BMO_elem_flag_enable(bm, f_iter, FACE_ORIG);
+ BMO_face_flag_disable(bm, f_iter, FACE_TAG);
+ BMO_face_flag_enable(bm, f_iter, FACE_ORIG);
}
if (BMO_error_occurred(bm)) {
@@ -193,7 +194,10 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op)
BLI_array_append(faces, NULL);
BLI_array_append(regions, faces);
}
-
+
+ /* track how many faces we should end up with */
+ int totface_target = bm->totface;
+
for (i = 0; i < BLI_array_count(regions); i++) {
BMFace *f_new;
int tot = 0;
@@ -215,6 +219,7 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op)
if (act_face && bm->act_face == NULL) {
bm->act_face = f_new;
}
+ totface_target -= tot - 1;
}
else {
BMO_error_raise(bm, op, BMERR_DISSOLVEFACES_FAILED,
@@ -224,20 +229,21 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op)
/* if making the new face failed (e.g. overlapping test)
* unmark the original faces for deletion */
- BMO_elem_flag_disable(bm, f_new, FACE_ORIG);
- BMO_elem_flag_enable(bm, f_new, FACE_NEW);
-
+ BMO_face_flag_disable(bm, f_new, FACE_ORIG);
+ BMO_face_flag_enable(bm, f_new, FACE_NEW);
}
- BMO_op_callf(bm, op->flag, "delete geom=%ff context=%i", FACE_ORIG, DEL_FACES);
-
+ /* Typically no faces need to be deleted */
+ if (totface_target != bm->totface) {
+ BMO_op_callf(bm, op->flag, "delete geom=%ff context=%i", FACE_ORIG, DEL_FACES);
+ }
if (use_verts) {
BMIter viter;
BMVert *v, *v_next;
BM_ITER_MESH_MUTABLE (v, v_next, &viter, bm, BM_VERTS_OF_MESH) {
- if (BMO_elem_flag_test(bm, v, VERT_MARK)) {
+ if (BMO_vert_flag_test(bm, v, VERT_MARK)) {
if (BM_vert_is_edge_pair(v)) {
BM_vert_collapse_edge(bm, v->e, v, true, true);
}
@@ -279,14 +285,14 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op)
BMIter itersub;
int untag_count = 0;
BM_ITER_ELEM (e, &itersub, v, BM_EDGES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, e, EDGE_TAG)) {
+ if (!BMO_edge_flag_test(bm, e, EDGE_TAG)) {
untag_count++;
}
}
/* check that we have 2 edges remaining after dissolve */
if (untag_count <= 2) {
- BMO_elem_flag_enable(bm, v, VERT_TAG);
+ BMO_vert_flag_enable(bm, v, VERT_TAG);
}
}
@@ -295,7 +301,7 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op)
if (use_verts) {
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- BMO_elem_flag_set(bm, v, VERT_MARK, !BM_vert_is_edge_pair(v));
+ BMO_vert_flag_set(bm, v, VERT_MARK, !BM_vert_is_edge_pair(v));
}
}
@@ -308,8 +314,8 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op)
BMLoop *l_first, *l_iter;
l_iter = l_first = BM_FACE_FIRST_LOOP(f_pair[j]);
do {
- BMO_elem_flag_enable(bm, l_iter->v, VERT_ISGC);
- BMO_elem_flag_enable(bm, l_iter->e, EDGE_ISGC);
+ BMO_vert_flag_enable(bm, l_iter->v, VERT_ISGC);
+ BMO_edge_flag_enable(bm, l_iter->e, EDGE_ISGC);
} while ((l_iter = l_iter->next) != l_first);
}
}
@@ -335,12 +341,12 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op)
/* Cleanup geometry (#BM_faces_join_pair, but it removes geometry we're looping on)
* so do this in a separate pass instead. */
BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) {
- if ((e->l == NULL) && BMO_elem_flag_test(bm, e, EDGE_ISGC)) {
+ if ((e->l == NULL) && BMO_edge_flag_test(bm, e, EDGE_ISGC)) {
BM_edge_kill(bm, e);
}
}
BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) {
- if ((v->e == NULL) && BMO_elem_flag_test(bm, v, VERT_ISGC)) {
+ if ((v->e == NULL) && BMO_vert_flag_test(bm, v, VERT_ISGC)) {
BM_vert_kill(bm, v);
}
}
@@ -349,7 +355,7 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op)
if (use_verts) {
BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) {
- if (BMO_elem_flag_test(bm, v, VERT_MARK)) {
+ if (BMO_vert_flag_test(bm, v, VERT_MARK)) {
if (BM_vert_is_edge_pair(v)) {
BM_vert_collapse_edge(bm, v->e, v, true, true);
}
@@ -370,7 +376,7 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op)
const bool use_boundary_tear = BMO_slot_bool_get(op->slots_in, "use_boundary_tear");
BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) {
- BMO_elem_flag_enable(bm, v, VERT_MARK | VERT_ISGC);
+ BMO_vert_flag_enable(bm, v, VERT_MARK | VERT_ISGC);
}
if (use_face_split) {
@@ -382,7 +388,7 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op)
if (!BM_vert_is_edge_pair(v)) {
BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
if (BM_edge_is_boundary(e)) {
- BMO_elem_flag_enable(bm, v, VERT_MARK_TEAR);
+ BMO_vert_flag_enable(bm, v, VERT_MARK_TEAR);
break;
}
}
@@ -400,8 +406,8 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op)
BMLoop *l_iter;
l_iter = l_first;
do {
- BMO_elem_flag_enable(bm, l_iter->v, VERT_ISGC);
- BMO_elem_flag_enable(bm, l_iter->e, EDGE_ISGC);
+ BMO_vert_flag_enable(bm, l_iter->v, VERT_ISGC);
+ BMO_edge_flag_enable(bm, l_iter->e, EDGE_ISGC);
} while ((l_iter = l_iter->next) != l_first);
e_first = l_first->e;
@@ -422,14 +428,14 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op)
BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) {
/* tag here so we avoid feedback loop (checking topology as we edit) */
if (BM_vert_is_edge_pair(v)) {
- BMO_elem_flag_enable(bm, v, VERT_MARK_PAIR);
+ BMO_vert_flag_enable(bm, v, VERT_MARK_PAIR);
}
}
BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) {
BMIter itersub;
- if (!BMO_elem_flag_test(bm, v, VERT_MARK_PAIR)) {
+ if (!BMO_vert_flag_test(bm, v, VERT_MARK_PAIR)) {
BM_ITER_ELEM (e, &itersub, v, BM_EDGES_OF_VERT) {
BMFace *fa, *fb;
if (BM_edge_face_pair(e, &fa, &fb)) {
@@ -450,7 +456,7 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op)
/* Cleanup geometry (#BM_faces_join_pair, but it removes geometry we're looping on)
* so do this in a separate pass instead. */
BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) {
- if ((e->l == NULL) && BMO_elem_flag_test(bm, e, EDGE_ISGC)) {
+ if ((e->l == NULL) && BMO_edge_flag_test(bm, e, EDGE_ISGC)) {
BM_edge_kill(bm, e);
}
}
@@ -463,7 +469,7 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op)
}
BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) {
- if ((v->e == NULL) && BMO_elem_flag_test(bm, v, VERT_ISGC)) {
+ if ((v->e == NULL) && BMO_vert_flag_test(bm, v, VERT_ISGC)) {
BM_vert_kill(bm, v);
}
}
@@ -512,9 +518,9 @@ void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op)
/* collapse zero length edges, this accounts for zero area faces too */
found = false;
BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
- if (BMO_elem_flag_test(bm, e, EDGE_MARK)) {
+ if (BMO_edge_flag_test(bm, e, EDGE_MARK)) {
if (BM_edge_calc_length_squared(e) < dist_sq) {
- BMO_elem_flag_enable(bm, e, EDGE_COLLAPSE);
+ BMO_edge_flag_enable(bm, e, EDGE_COLLAPSE);
found = true;
}
}
@@ -537,7 +543,7 @@ void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op)
/* clip degenerate ears from the face */
found = false;
BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
- if (e->l && BMO_elem_flag_test(bm, e, EDGE_MARK)) {
+ if (e->l && BMO_edge_flag_test(bm, e, EDGE_MARK)) {
BMLoop *l_iter, *l_first;
l_iter = l_first = e->l;
do {
@@ -547,11 +553,11 @@ void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op)
((void)BM_elem_flag_enable(l_iter, BM_ELEM_TAG),
/* check we're marked to tested (radial edge already tested) */
- BMO_elem_flag_test(bm, l_iter->prev->e, EDGE_MARK) &&
+ BMO_edge_flag_test(bm, l_iter->prev->e, EDGE_MARK) &&
/* check edges are not already going to be collapsed */
- !BMO_elem_flag_test(bm, l_iter->e, EDGE_COLLAPSE) &&
- !BMO_elem_flag_test(bm, l_iter->prev->e, EDGE_COLLAPSE)))
+ !BMO_edge_flag_test(bm, l_iter->e, EDGE_COLLAPSE) &&
+ !BMO_edge_flag_test(bm, l_iter->prev->e, EDGE_COLLAPSE)))
{
/* test if the faces loop (ear) is degenerate */
float dir_prev[3], len_prev;
@@ -571,14 +577,14 @@ void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op)
/* both edges the same length */
if (l_iter->f->len == 3) {
/* ideally this would have been discovered with short edge test above */
- BMO_elem_flag_enable(bm, l_iter->next->e, EDGE_COLLAPSE);
+ BMO_edge_flag_enable(bm, l_iter->next->e, EDGE_COLLAPSE);
found = true;
}
else {
/* add a joining edge and tag for removal */
BMLoop *l_split;
if (BM_face_split(bm, l_iter->f, l_iter->prev, l_iter->next, &l_split, NULL, true)) {
- BMO_elem_flag_enable(bm, l_split->e, EDGE_COLLAPSE);
+ BMO_edge_flag_enable(bm, l_split->e, EDGE_COLLAPSE);
found = true;
reset = true;
}
@@ -593,7 +599,7 @@ void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op)
BLI_assert(v_new == l_iter->next->v);
(void)v_new;
if (BM_face_split(bm, l_iter->f, l_iter->prev, l_iter->next, &l_split, NULL, true)) {
- BMO_elem_flag_enable(bm, l_split->e, EDGE_COLLAPSE);
+ BMO_edge_flag_enable(bm, l_split->e, EDGE_COLLAPSE);
found = true;
}
reset = true;
@@ -607,7 +613,7 @@ void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op)
BLI_assert(v_new == l_iter->prev->v);
(void)v_new;
if (BM_face_split(bm, l_iter->f, l_iter->prev, l_iter->next, &l_split, NULL, true)) {
- BMO_elem_flag_enable(bm, l_split->e, EDGE_COLLAPSE);
+ BMO_edge_flag_enable(bm, l_split->e, EDGE_COLLAPSE);
found = true;
}
reset = true;
diff --git a/source/blender/bmesh/operators/bmo_dupe.c b/source/blender/bmesh/operators/bmo_dupe.c
index fd430de80f9..56639a097b6 100644
--- a/source/blender/bmesh/operators/bmo_dupe.c
+++ b/source/blender/bmesh/operators/bmo_dupe.c
@@ -63,7 +63,7 @@ static BMVert *bmo_vert_copy(
BM_elem_attrs_copy(bm_src, bm_dst, v_src, v_dst);
/* Mark the vert for output */
- BMO_elem_flag_enable(bm_dst, v_dst, DUPE_NEW);
+ BMO_vert_flag_enable(bm_dst, v_dst, DUPE_NEW);
return v_dst;
}
@@ -94,7 +94,7 @@ static BMEdge *bmo_edge_copy(
BMLoop *l_iter_src, *l_first_src;
l_iter_src = l_first_src = e_src->l;
do {
- if (BMO_elem_flag_test(bm_src, l_iter_src->f, DUPE_INPUT)) {
+ if (BMO_face_flag_test(bm_src, l_iter_src->f, DUPE_INPUT)) {
rlen++;
}
} while ((l_iter_src = l_iter_src->radial_next) != l_first_src);
@@ -123,7 +123,7 @@ static BMEdge *bmo_edge_copy(
BM_elem_attrs_copy(bm_src, bm_dst, e_src, e_dst);
/* Mark the edge for output */
- BMO_elem_flag_enable(bm_dst, e_dst, DUPE_NEW);
+ BMO_edge_flag_enable(bm_dst, e_dst, DUPE_NEW);
return e_dst;
}
@@ -175,7 +175,7 @@ static BMFace *bmo_face_copy(
(l_iter_src = l_iter_src->next) != l_first_src);
/* Mark the face for output */
- BMO_elem_flag_enable(bm_dst, f_dst, DUPE_NEW);
+ BMO_face_flag_enable(bm_dst, f_dst, DUPE_NEW);
return f_dst;
}
@@ -209,8 +209,8 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src)
/* duplicate flagged vertices */
BM_ITER_MESH (v, &viter, bm_src, BM_VERTS_OF_MESH) {
- if (BMO_elem_flag_test(bm_src, v, DUPE_INPUT) &&
- !BMO_elem_flag_test(bm_src, v, DUPE_DONE))
+ if (BMO_vert_flag_test(bm_src, v, DUPE_INPUT) &&
+ BMO_vert_flag_test(bm_src, v, DUPE_DONE) == false)
{
BMIter iter;
bool isolated = true;
@@ -218,7 +218,7 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src)
v2 = bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, v, vhash);
BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
- if (BMO_elem_flag_test(bm_src, f, DUPE_INPUT)) {
+ if (BMO_face_flag_test(bm_src, f, DUPE_INPUT)) {
isolated = false;
break;
}
@@ -226,7 +226,7 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src)
if (isolated) {
BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
- if (BMO_elem_flag_test(bm_src, e, DUPE_INPUT)) {
+ if (BMO_edge_flag_test(bm_src, e, DUPE_INPUT)) {
isolated = false;
break;
}
@@ -237,53 +237,53 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src)
BMO_slot_map_elem_insert(op, slot_isovert_map_out, v, v2);
}
- BMO_elem_flag_enable(bm_src, v, DUPE_DONE);
+ BMO_vert_flag_enable(bm_src, v, DUPE_DONE);
}
}
/* now we dupe all the edges */
BM_ITER_MESH (e, &eiter, bm_src, BM_EDGES_OF_MESH) {
- if (BMO_elem_flag_test(bm_src, e, DUPE_INPUT) &&
- !BMO_elem_flag_test(bm_src, e, DUPE_DONE))
+ if (BMO_edge_flag_test(bm_src, e, DUPE_INPUT) &&
+ BMO_edge_flag_test(bm_src, e, DUPE_DONE) == false)
{
/* make sure that verts are copied */
- if (!BMO_elem_flag_test(bm_src, e->v1, DUPE_DONE)) {
+ if (!BMO_vert_flag_test(bm_src, e->v1, DUPE_DONE)) {
bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, e->v1, vhash);
- BMO_elem_flag_enable(bm_src, e->v1, DUPE_DONE);
+ BMO_vert_flag_enable(bm_src, e->v1, DUPE_DONE);
}
- if (!BMO_elem_flag_test(bm_src, e->v2, DUPE_DONE)) {
+ if (!BMO_vert_flag_test(bm_src, e->v2, DUPE_DONE)) {
bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, e->v2, vhash);
- BMO_elem_flag_enable(bm_src, e->v2, DUPE_DONE);
+ BMO_vert_flag_enable(bm_src, e->v2, DUPE_DONE);
}
/* now copy the actual edge */
bmo_edge_copy(op, slot_edge_map_out, slot_boundary_map_out,
bm_dst, bm_src, e, vhash, ehash);
- BMO_elem_flag_enable(bm_src, e, DUPE_DONE);
+ BMO_edge_flag_enable(bm_src, e, DUPE_DONE);
}
}
/* first we dupe all flagged faces and their elements from source */
BM_ITER_MESH (f, &fiter, bm_src, BM_FACES_OF_MESH) {
- if (BMO_elem_flag_test(bm_src, f, DUPE_INPUT)) {
+ if (BMO_face_flag_test(bm_src, f, DUPE_INPUT)) {
/* vertex pass */
BM_ITER_ELEM (v, &viter, f, BM_VERTS_OF_FACE) {
- if (!BMO_elem_flag_test(bm_src, v, DUPE_DONE)) {
+ if (!BMO_vert_flag_test(bm_src, v, DUPE_DONE)) {
bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, v, vhash);
- BMO_elem_flag_enable(bm_src, v, DUPE_DONE);
+ BMO_vert_flag_enable(bm_src, v, DUPE_DONE);
}
}
/* edge pass */
BM_ITER_ELEM (e, &eiter, f, BM_EDGES_OF_FACE) {
- if (!BMO_elem_flag_test(bm_src, e, DUPE_DONE)) {
+ if (!BMO_edge_flag_test(bm_src, e, DUPE_DONE)) {
bmo_edge_copy(op, slot_edge_map_out, slot_boundary_map_out,
bm_dst, bm_src, e, vhash, ehash);
- BMO_elem_flag_enable(bm_src, e, DUPE_DONE);
+ BMO_edge_flag_enable(bm_src, e, DUPE_DONE);
}
}
bmo_face_copy(op, slot_face_map_out, bm_dst, bm_src, f, vhash, ehash);
- BMO_elem_flag_enable(bm_src, f, DUPE_DONE);
+ BMO_face_flag_enable(bm_src, f, DUPE_DONE);
}
}
@@ -408,26 +408,26 @@ void bmo_split_exec(BMesh *bm, BMOperator *op)
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
bool found = false;
BM_ITER_ELEM (f, &iter2, e, BM_FACES_OF_EDGE) {
- if (!BMO_elem_flag_test(bm, f, SPLIT_INPUT)) {
+ if (!BMO_face_flag_test(bm, f, SPLIT_INPUT)) {
found = true;
break;
}
}
if (found == false) {
- BMO_elem_flag_enable(bm, e, SPLIT_INPUT);
+ BMO_edge_flag_enable(bm, e, SPLIT_INPUT);
}
}
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
bool found = false;
BM_ITER_ELEM (e, &iter2, v, BM_EDGES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, e, SPLIT_INPUT)) {
+ if (!BMO_edge_flag_test(bm, e, SPLIT_INPUT)) {
found = true;
break;
}
}
if (found == false) {
- BMO_elem_flag_enable(bm, v, SPLIT_INPUT);
+ BMO_vert_flag_enable(bm, v, SPLIT_INPUT);
}
}
}
diff --git a/source/blender/bmesh/operators/bmo_edgenet.c b/source/blender/bmesh/operators/bmo_edgenet.c
index f348014cead..64b092da5c8 100644
--- a/source/blender/bmesh/operators/bmo_edgenet.c
+++ b/source/blender/bmesh/operators/bmo_edgenet.c
@@ -94,8 +94,8 @@ static BMEdge *edge_next(BMesh *bm, BMEdge *e)
for (i = 0; i < 2; i++) {
BM_ITER_ELEM (e2, &iter, i ? e->v2 : e->v1, BM_EDGES_OF_VERT) {
- if ((BMO_elem_flag_test(bm, e2, EDGE_MARK)) &&
- (!BMO_elem_flag_test(bm, e2, EDGE_VIS)) &&
+ if ((BMO_edge_flag_test(bm, e2, EDGE_MARK)) &&
+ (BMO_edge_flag_test(bm, e2, EDGE_VIS) == false) &&
(e2 != e))
{
return e2;
@@ -144,7 +144,7 @@ void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op)
count = 0;
while (1) {
BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) {
- if (!BMO_elem_flag_test(bm, e, EDGE_VIS)) {
+ if (!BMO_edge_flag_test(bm, e, EDGE_VIS)) {
if (BMO_iter_elem_count_flag(bm, BM_EDGES_OF_VERT, e->v1, EDGE_MARK, true) == 1 ||
BMO_iter_elem_count_flag(bm, BM_EDGES_OF_VERT, e->v2, EDGE_MARK, true) == 1)
{
@@ -169,7 +169,7 @@ void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op)
i = 0;
while (e) {
- BMO_elem_flag_enable(bm, e, EDGE_VIS);
+ BMO_edge_flag_enable(bm, e, EDGE_VIS);
BLI_array_grow_one(edges);
edges[i] = e;
@@ -258,9 +258,9 @@ void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op)
}
e = BM_edge_create(bm, v1, v3, NULL, BM_CREATE_NO_DOUBLE);
- BMO_elem_flag_enable(bm, e, ELE_NEW);
+ BMO_edge_flag_enable(bm, e, ELE_NEW);
e = BM_edge_create(bm, v2, v4, NULL, BM_CREATE_NO_DOUBLE);
- BMO_elem_flag_enable(bm, e, ELE_NEW);
+ BMO_edge_flag_enable(bm, e, ELE_NEW);
}
else if (edges1) {
BMVert *v1, *v2;
@@ -270,7 +270,7 @@ void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op)
i = BLI_array_count(edges1) - 1;
v2 = BM_vert_in_edge(edges1[i - 1], edges1[i]->v1) ? edges1[i]->v2 : edges1[i]->v1;
e = BM_edge_create(bm, v1, v2, NULL, BM_CREATE_NO_DOUBLE);
- BMO_elem_flag_enable(bm, e, ELE_NEW);
+ BMO_edge_flag_enable(bm, e, ELE_NEW);
}
}
diff --git a/source/blender/bmesh/operators/bmo_extrude.c b/source/blender/bmesh/operators/bmo_extrude.c
index 5a3bef6ba81..87369472df7 100644
--- a/source/blender/bmesh/operators/bmo_extrude.c
+++ b/source/blender/bmesh/operators/bmo_extrude.c
@@ -70,10 +70,10 @@ void bmo_extrude_discrete_faces_exec(BMesh *bm, BMOperator *op)
BMLoop *l_org, *l_org_first;
BMLoop *l_new;
- BMO_elem_flag_enable(bm, f_org, EXT_DEL);
+ BMO_face_flag_enable(bm, f_org, EXT_DEL);
f_new = BM_face_copy(bm, bm, f_org, true, true);
- BMO_elem_flag_enable(bm, f_new, EXT_KEEP);
+ BMO_face_flag_enable(bm, f_new, EXT_KEEP);
if (select_history_map) {
BMEditSelection *ese;
@@ -188,9 +188,9 @@ void bmo_extrude_edge_only_exec(BMesh *bm, BMOperator *op)
BMEdge *e, *e_new;
BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) {
- BMO_elem_flag_enable(bm, e, EXT_INPUT);
- BMO_elem_flag_enable(bm, e->v1, EXT_INPUT);
- BMO_elem_flag_enable(bm, e->v2, EXT_INPUT);
+ BMO_edge_flag_enable(bm, e, EXT_INPUT);
+ BMO_vert_flag_enable(bm, e->v1, EXT_INPUT);
+ BMO_vert_flag_enable(bm, e->v2, EXT_INPUT);
}
BMO_op_initf(
@@ -228,13 +228,14 @@ void bmo_extrude_edge_only_exec(BMesh *bm, BMOperator *op)
f = BM_face_create_verts(bm, f_verts, 4, NULL, BM_CREATE_NOP, true);
bm_extrude_copy_face_loop_attributes(bm, f);
- if (BMO_elem_flag_test(bm, e, EXT_INPUT))
+ if (BMO_edge_flag_test(bm, e, EXT_INPUT)) {
e = e_new;
+ }
- BMO_elem_flag_enable(bm, f, EXT_KEEP);
- BMO_elem_flag_enable(bm, e, EXT_KEEP);
- BMO_elem_flag_enable(bm, e->v1, EXT_KEEP);
- BMO_elem_flag_enable(bm, e->v2, EXT_KEEP);
+ BMO_face_flag_enable(bm, f, EXT_KEEP);
+ BMO_edge_flag_enable(bm, e, EXT_KEEP);
+ BMO_vert_flag_enable(bm, e->v1, EXT_KEEP);
+ BMO_vert_flag_enable(bm, e->v2, EXT_KEEP);
}
@@ -258,7 +259,7 @@ void bmo_extrude_vert_indiv_exec(BMesh *bm, BMOperator *op)
for (v = BMO_iter_new(&siter, op->slots_in, "verts", BM_VERT); v; v = BMO_iter_step(&siter)) {
dupev = BM_vert_create(bm, v->co, v, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, dupev, EXT_KEEP);
+ BMO_vert_flag_enable(bm, dupev, EXT_KEEP);
if (has_vskin)
bm_extrude_disable_skin_root(bm, v);
@@ -279,7 +280,7 @@ void bmo_extrude_vert_indiv_exec(BMesh *bm, BMOperator *op)
}
e = BM_edge_create(bm, v, dupev, NULL, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, e, EXT_KEEP);
+ BMO_edge_flag_enable(bm, e, EXT_KEEP);
}
if (select_history_map) {
@@ -350,7 +351,7 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
int edge_face_tot;
- if (!BMO_elem_flag_test(bm, e, EXT_INPUT)) {
+ if (!BMO_edge_flag_test(bm, e, EXT_INPUT)) {
continue;
}
@@ -358,7 +359,7 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
edge_face_tot = 0; /* edge/face count */
BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
- if (!BMO_elem_flag_test(bm, f, EXT_INPUT)) {
+ if (!BMO_face_flag_test(bm, f, EXT_INPUT)) {
found = true;
delorig = true;
break;
@@ -369,7 +370,7 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
if ((edge_face_tot > 1) && (found == false)) {
/* edge has a face user, that face isn't extrude input */
- BMO_elem_flag_enable(bm, e, EXT_DEL);
+ BMO_edge_flag_enable(bm, e, EXT_DEL);
}
}
}
@@ -380,7 +381,9 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
found = false;
BM_ITER_ELEM (e, &viter, v, BM_EDGES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, e, EXT_INPUT) || !BMO_elem_flag_test(bm, e, EXT_DEL)) {
+ if (!BMO_edge_flag_test(bm, e, EXT_INPUT) ||
+ !BMO_edge_flag_test(bm, e, EXT_DEL))
+ {
found = true;
break;
}
@@ -389,7 +392,7 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
/* avoid an extra loop */
if (found == true) {
BM_ITER_ELEM (f, &viter, v, BM_FACES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, f, EXT_INPUT)) {
+ if (!BMO_face_flag_test(bm, f, EXT_INPUT)) {
found = true;
break;
}
@@ -397,14 +400,14 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
}
if (found == false) {
- BMO_elem_flag_enable(bm, v, EXT_DEL);
+ BMO_vert_flag_enable(bm, v, EXT_DEL);
}
}
}
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (BMO_elem_flag_test(bm, f, EXT_INPUT)) {
- BMO_elem_flag_enable(bm, f, EXT_DEL);
+ if (BMO_face_flag_test(bm, f, EXT_INPUT)) {
+ BMO_face_flag_enable(bm, f, EXT_DEL);
}
}
@@ -426,7 +429,7 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
}
slot_facemap_out = BMO_slot_get(dupeop.slots_out, "face_map.out");
- if (bm->act_face && BMO_elem_flag_test(bm, bm->act_face, EXT_INPUT)) {
+ if (bm->act_face && BMO_face_flag_test(bm, bm->act_face, EXT_INPUT)) {
bm->act_face = BMO_slot_map_elem_get(slot_facemap_out, bm->act_face);
}
@@ -437,7 +440,7 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
/* if not delorig, reverse loops of original face */
if (!delorig) {
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (BMO_elem_flag_test(bm, f, EXT_INPUT)) {
+ if (BMO_face_flag_test(bm, f, EXT_INPUT)) {
BM_face_normal_flip(bm, f);
}
}
@@ -583,7 +586,7 @@ static void calc_solidify_normals(BMesh *bm)
BM_mesh_elem_index_ensure(bm, BM_EDGE);
BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
- if (!BMO_elem_flag_test(bm, f, FACE_MARK)) {
+ if (!BMO_face_flag_test(bm, f, FACE_MARK)) {
continue;
}
@@ -591,15 +594,15 @@ static void calc_solidify_normals(BMesh *bm)
/* And mark all edges and vertices on the
* marked faces */
- BMO_elem_flag_enable(bm, e, EDGE_MARK);
- BMO_elem_flag_enable(bm, e->v1, VERT_MARK);
- BMO_elem_flag_enable(bm, e->v2, VERT_MARK);
+ BMO_edge_flag_enable(bm, e, EDGE_MARK);
+ BMO_vert_flag_enable(bm, e->v1, VERT_MARK);
+ BMO_vert_flag_enable(bm, e->v2, VERT_MARK);
edge_face_count[BM_elem_index_get(e)]++;
}
}
BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
- if (!BMO_elem_flag_test(bm, e, EDGE_MARK)) {
+ if (!BMO_edge_flag_test(bm, e, EDGE_MARK)) {
continue;
}
@@ -608,9 +611,9 @@ static void calc_solidify_normals(BMesh *bm)
if (i == 0 || i > 2) {
/* Edge & vertices are non-manifold even when considering
* only marked faces */
- BMO_elem_flag_enable(bm, e, EDGE_NONMAN);
- BMO_elem_flag_enable(bm, e->v1, VERT_NONMAN);
- BMO_elem_flag_enable(bm, e->v2, VERT_NONMAN);
+ BMO_edge_flag_enable(bm, e, EDGE_NONMAN);
+ BMO_vert_flag_enable(bm, e->v1, VERT_NONMAN);
+ BMO_vert_flag_enable(bm, e->v2, VERT_NONMAN);
}
}
MEM_freeN(edge_face_count);
@@ -618,11 +621,11 @@ static void calc_solidify_normals(BMesh *bm)
BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
if (!BM_vert_is_manifold(v)) {
- BMO_elem_flag_enable(bm, v, VERT_NONMAN);
+ BMO_vert_flag_enable(bm, v, VERT_NONMAN);
continue;
}
- if (BMO_elem_flag_test(bm, v, VERT_MARK)) {
+ if (BMO_vert_flag_test(bm, v, VERT_MARK)) {
zero_v3(v->no);
}
}
@@ -631,20 +634,20 @@ static void calc_solidify_normals(BMesh *bm)
/* If the edge is not part of a the solidify region
* its normal should not be considered */
- if (!BMO_elem_flag_test(bm, e, EDGE_MARK)) {
+ if (!BMO_edge_flag_test(bm, e, EDGE_MARK)) {
continue;
}
/* If the edge joins more than two marked faces high
* quality normal computation won't work */
- if (BMO_elem_flag_test(bm, e, EDGE_NONMAN)) {
+ if (BMO_edge_flag_test(bm, e, EDGE_NONMAN)) {
continue;
}
f1 = f2 = NULL;
BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
- if (BMO_elem_flag_test(bm, f, FACE_MARK)) {
+ if (BMO_face_flag_test(bm, f, FACE_MARK)) {
if (f1 == NULL) {
f1 = f;
}
@@ -664,8 +667,7 @@ static void calc_solidify_normals(BMesh *bm)
/* two faces using this edge, calculate the edge normal
* using the angle between the faces as a weighting */
add_v3_v3v3(edge_normal, f1->no, f2->no);
- normalize_v3(edge_normal);
- mul_v3_fl(edge_normal, angle);
+ normalize_v3_length(edge_normal, angle);
}
else {
/* can't do anything useful here!
@@ -689,11 +691,11 @@ static void calc_solidify_normals(BMesh *bm)
/* normalize accumulated vertex normal */
BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
- if (!BMO_elem_flag_test(bm, v, VERT_MARK)) {
+ if (!BMO_vert_flag_test(bm, v, VERT_MARK)) {
continue;
}
- if (BMO_elem_flag_test(bm, v, VERT_NONMAN)) {
+ if (BMO_vert_flag_test(bm, v, VERT_NONMAN)) {
/* use standard normals for vertices connected to non-manifold edges */
BM_vert_normal_update(v);
}
@@ -701,7 +703,7 @@ static void calc_solidify_normals(BMesh *bm)
/* exceptional case, totally flat. use the normal
* of any marked face around the vertex */
BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) {
- if (BMO_elem_flag_test(bm, f, FACE_MARK)) {
+ if (BMO_face_flag_test(bm, f, FACE_MARK)) {
break;
}
}
@@ -726,7 +728,7 @@ static void solidify_add_thickness(BMesh *bm, const float dist)
BM_mesh_elem_index_ensure(bm, BM_VERT);
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (BMO_elem_flag_test(bm, f, FACE_MARK)) {
+ if (BMO_face_flag_test(bm, f, FACE_MARK)) {
/* array for passing verts to angle_poly_v3 */
float *face_angles = BLI_buffer_reinit_data(&face_angles_buf, float, f->len);
diff --git a/source/blender/bmesh/operators/bmo_fill_edgeloop.c b/source/blender/bmesh/operators/bmo_fill_edgeloop.c
index 0fbaf5ff11a..c68130bc11d 100644
--- a/source/blender/bmesh/operators/bmo_fill_edgeloop.c
+++ b/source/blender/bmesh/operators/bmo_fill_edgeloop.c
@@ -59,14 +59,14 @@ void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op)
i = 0;
BMO_ITER (e, &oiter, op->slots_in, "edges", BM_EDGE) {
BMIter viter;
- BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ BMO_edge_flag_enable(bm, e, EDGE_MARK);
BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) {
- if (BMO_elem_flag_test(bm, v, VERT_USED) == false) {
+ if (BMO_vert_flag_test(bm, v, VERT_USED) == false) {
if (i == tote) {
goto cleanup;
}
- BMO_elem_flag_enable(bm, v, VERT_USED);
+ BMO_vert_flag_enable(bm, v, VERT_USED);
verts[i++] = v;
}
}
@@ -103,21 +103,21 @@ void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op)
while (totv_used < totv) {
for (i = 0; i < totv; i++) {
v = verts[i];
- if (BMO_elem_flag_test(bm, v, VERT_USED)) {
+ if (BMO_vert_flag_test(bm, v, VERT_USED)) {
break;
}
}
/* this should never fail, as long as (totv_used < totv)
* we should have marked verts available */
- BLI_assert(BMO_elem_flag_test(bm, v, VERT_USED));
+ BLI_assert(BMO_vert_flag_test(bm, v, VERT_USED));
/* watch it, 'i' is used for final face length */
i = 0;
do {
/* we know that there are 2 edges per vertex so no need to check */
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- if (BMO_elem_flag_test(bm, e, EDGE_MARK)) {
+ if (BMO_edge_flag_test(bm, e, EDGE_MARK)) {
if (e != e_prev) {
e_next = e;
break;
@@ -127,7 +127,7 @@ void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op)
/* fill in the array */
f_verts[i] = v;
- BMO_elem_flag_disable(bm, v, VERT_USED);
+ BMO_vert_flag_disable(bm, v, VERT_USED);
totv_used++;
/* step over the edges */
@@ -141,7 +141,7 @@ void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op)
/* don't use calc_edges option because we already have the edges */
f = BM_face_create_ngon_verts(bm, f_verts, i, NULL, BM_CREATE_NOP, true, false);
- BMO_elem_flag_enable(bm, f, ELE_OUT);
+ BMO_face_flag_enable(bm, f, ELE_OUT);
f->mat_nr = mat_nr;
if (use_smooth) {
BM_elem_flag_enable(f, BM_ELEM_SMOOTH);
diff --git a/source/blender/bmesh/operators/bmo_fill_grid.c b/source/blender/bmesh/operators/bmo_fill_grid.c
index 77556591728..04ae915b707 100644
--- a/source/blender/bmesh/operators/bmo_fill_grid.c
+++ b/source/blender/bmesh/operators/bmo_fill_grid.c
@@ -466,7 +466,7 @@ static void bm_grid_fill_array(
/* end interp */
- BMO_elem_flag_enable(bm, f, FACE_OUT);
+ BMO_face_flag_enable(bm, f, FACE_OUT);
f->mat_nr = mat_nr;
if (use_smooth) {
BM_elem_flag_enable(f, BM_ELEM_SMOOTH);
@@ -585,7 +585,7 @@ static void bm_edgeloop_flag_set(struct BMEdgeLoopStore *estore, char hflag, boo
static bool bm_edge_test_cb(BMEdge *e, void *bm_v)
{
- return BMO_elem_flag_test_bool((BMesh *)bm_v, e, EDGE_MARK);
+ return BMO_edge_flag_test_bool((BMesh *)bm_v, e, EDGE_MARK);
}
static bool bm_edge_test_rail_cb(BMEdge *e, void *UNUSED(bm_v))
diff --git a/source/blender/bmesh/operators/bmo_hull.c b/source/blender/bmesh/operators/bmo_hull.c
index 2dfad5a1f47..9c41e4f2115 100644
--- a/source/blender/bmesh/operators/bmo_hull.c
+++ b/source/blender/bmesh/operators/bmo_hull.c
@@ -81,7 +81,7 @@ static void hull_add_triangle(
/* Mark triangles vertices as not interior */
for (i = 0; i < 3; i++)
- BMO_elem_flag_disable(bm, t->v[i], HULL_FLAG_INTERIOR_ELE);
+ BMO_vert_flag_disable(bm, t->v[i], HULL_FLAG_INTERIOR_ELE);
BLI_gset_insert(hull_triangles, t);
normal_tri_v3(t->no, v1->co, v2->co, v3->co);
@@ -93,8 +93,8 @@ static BMFace *hull_find_example_face(BMesh *bm, BMEdge *e)
BMFace *f;
BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) {
- if (BMO_elem_flag_test(bm, f, HULL_FLAG_INPUT) ||
- !BMO_elem_flag_test(bm, f, HULL_FLAG_OUTPUT_GEOM))
+ if (BMO_face_flag_test(bm, f, HULL_FLAG_INPUT) ||
+ BMO_face_flag_test(bm, f, HULL_FLAG_OUTPUT_GEOM) == false)
{
return f;
}
@@ -124,9 +124,9 @@ static void hull_output_triangles(BMesh *bm, GSet *hull_triangles)
* disabled, but an output face in the hull is the
* same as a face in the existing mesh, it should not
* be marked as unused or interior. */
- BMO_elem_flag_enable(bm, f, HULL_FLAG_OUTPUT_GEOM);
- BMO_elem_flag_disable(bm, f, HULL_FLAG_HOLE);
- BMO_elem_flag_disable(bm, f, HULL_FLAG_INTERIOR_ELE);
+ BMO_face_flag_enable(bm, f, HULL_FLAG_OUTPUT_GEOM);
+ BMO_face_flag_disable(bm, f, HULL_FLAG_HOLE);
+ BMO_face_flag_disable(bm, f, HULL_FLAG_INTERIOR_ELE);
}
else {
/* Look for an adjacent face that existed before the hull */
@@ -140,12 +140,12 @@ static void hull_output_triangles(BMesh *bm, GSet *hull_triangles)
BM_face_copy_shared(bm, f, NULL, NULL);
}
/* Mark face for 'geom.out' slot and select */
- BMO_elem_flag_enable(bm, f, HULL_FLAG_OUTPUT_GEOM);
+ BMO_face_flag_enable(bm, f, HULL_FLAG_OUTPUT_GEOM);
BM_face_select_set(bm, f, true);
/* Mark edges for 'geom.out' slot */
for (i = 0; i < 3; i++) {
- BMO_elem_flag_enable(bm, edges[i], HULL_FLAG_OUTPUT_GEOM);
+ BMO_edge_flag_enable(bm, edges[i], HULL_FLAG_OUTPUT_GEOM);
}
}
else {
@@ -154,17 +154,17 @@ static void hull_output_triangles(BMesh *bm, GSet *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_edge_flag_test(bm, e, HULL_FLAG_INPUT) &&
+ !BMO_edge_flag_test(bm, e, HULL_FLAG_HOLE))
{
- BMO_elem_flag_enable(bm, e, HULL_FLAG_OUTPUT_GEOM);
+ BMO_edge_flag_enable(bm, e, HULL_FLAG_OUTPUT_GEOM);
}
}
}
/* Mark verts for 'geom.out' slot */
for (i = 0; i < 3; i++) {
- BMO_elem_flag_enable(bm, t->v[i], HULL_FLAG_OUTPUT_GEOM);
+ BMO_vert_flag_enable(bm, t->v[i], HULL_FLAG_OUTPUT_GEOM);
}
}
}
@@ -292,8 +292,8 @@ static void hull_remove_overlapping(
BM_vert_in_face(t->v[2], f) && f_on_hull)
{
t->skip = true;
- BMO_elem_flag_disable(bm, f, HULL_FLAG_INTERIOR_ELE);
- BMO_elem_flag_enable(bm, f, HULL_FLAG_HOLE);
+ BMO_face_flag_disable(bm, f, HULL_FLAG_INTERIOR_ELE);
+ BMO_face_flag_enable(bm, f, HULL_FLAG_HOLE);
}
}
}
@@ -310,13 +310,13 @@ static void hull_mark_interior_elements(
/* Check for interior edges too */
BMO_ITER (e, &oiter, op->slots_in, "input", BM_EDGE) {
if (!hull_final_edges_lookup(final_edges, e->v1, e->v2))
- BMO_elem_flag_enable(bm, e, HULL_FLAG_INTERIOR_ELE);
+ BMO_edge_flag_enable(bm, e, HULL_FLAG_INTERIOR_ELE);
}
/* Mark all input faces as interior, some may be unmarked in
* hull_remove_overlapping() */
BMO_ITER (f, &oiter, op->slots_in, "input", BM_FACE) {
- BMO_elem_flag_enable(bm, f, HULL_FLAG_INTERIOR_ELE);
+ BMO_face_flag_enable(bm, f, HULL_FLAG_INTERIOR_ELE);
}
}
@@ -333,47 +333,50 @@ static void hull_tag_unused(BMesh *bm, BMOperator *op)
* the hull), but that aren't also used by elements outside the
* input set */
BMO_ITER (v, &oiter, op->slots_in, "input", BM_VERT) {
- if (BMO_elem_flag_test(bm, v, HULL_FLAG_INTERIOR_ELE)) {
+ if (BMO_vert_flag_test(bm, v, HULL_FLAG_INTERIOR_ELE)) {
bool del = true;
BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, e, HULL_FLAG_INPUT)) {
+ if (!BMO_edge_flag_test(bm, e, HULL_FLAG_INPUT)) {
del = false;
break;
}
}
BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, f, HULL_FLAG_INPUT)) {
+ if (!BMO_face_flag_test(bm, f, HULL_FLAG_INPUT)) {
del = false;
break;
}
}
- if (del)
- BMO_elem_flag_enable(bm, v, HULL_FLAG_DEL);
+ if (del) {
+ BMO_vert_flag_enable(bm, v, HULL_FLAG_DEL);
+ }
}
}
BMO_ITER (e, &oiter, op->slots_in, "input", BM_EDGE) {
- if (BMO_elem_flag_test(bm, e, HULL_FLAG_INTERIOR_ELE)) {
+ if (BMO_edge_flag_test(bm, e, HULL_FLAG_INTERIOR_ELE)) {
bool del = true;
BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) {
- if (!BMO_elem_flag_test(bm, f, HULL_FLAG_INPUT)) {
+ if (!BMO_face_flag_test(bm, f, HULL_FLAG_INPUT)) {
del = false;
break;
}
}
- if (del)
- BMO_elem_flag_enable(bm, e, HULL_FLAG_DEL);
+ if (del) {
+ BMO_edge_flag_enable(bm, e, HULL_FLAG_DEL);
+ }
}
}
BMO_ITER (f, &oiter, op->slots_in, "input", BM_FACE) {
- if (BMO_elem_flag_test(bm, f, HULL_FLAG_INTERIOR_ELE))
- BMO_elem_flag_enable(bm, f, HULL_FLAG_DEL);
+ if (BMO_face_flag_test(bm, f, HULL_FLAG_INTERIOR_ELE)) {
+ BMO_face_flag_enable(bm, f, HULL_FLAG_DEL);
+ }
}
}
@@ -387,10 +390,10 @@ static void hull_tag_holes(BMesh *bm, BMOperator *op)
/* Unmark any hole faces if they are isolated or part of a
* border */
BMO_ITER (f, &oiter, op->slots_in, "input", BM_FACE) {
- if (BMO_elem_flag_test(bm, f, HULL_FLAG_HOLE)) {
+ if (BMO_face_flag_test(bm, f, HULL_FLAG_HOLE)) {
BM_ITER_ELEM (e, &iter, f, BM_EDGES_OF_FACE) {
if (BM_edge_is_boundary(e)) {
- BMO_elem_flag_disable(bm, f, HULL_FLAG_HOLE);
+ BMO_face_flag_disable(bm, f, HULL_FLAG_HOLE);
break;
}
}
@@ -405,14 +408,14 @@ static void hull_tag_holes(BMesh *bm, BMOperator *op)
BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) {
any_faces = true;
- if (!BMO_elem_flag_test(bm, f, HULL_FLAG_HOLE)) {
+ if (!BMO_face_flag_test(bm, f, HULL_FLAG_HOLE)) {
hole = false;
break;
}
}
if (hole && any_faces)
- BMO_elem_flag_enable(bm, e, HULL_FLAG_HOLE);
+ BMO_edge_flag_enable(bm, e, HULL_FLAG_HOLE);
}
}
@@ -578,11 +581,17 @@ void bmo_convex_hull_exec(BMesh *bm, BMOperator *op)
/* Tag input elements */
BMO_ITER (ele, &oiter, op->slots_in, "input", BM_ALL) {
- BMO_elem_flag_enable(bm, ele, HULL_FLAG_INPUT);
-
+
/* Mark all vertices as interior to begin with */
- if (ele->head.htype == BM_VERT)
- BMO_elem_flag_enable(bm, ele, HULL_FLAG_INTERIOR_ELE);
+ if (ele->head.htype == BM_VERT) {
+ BMO_vert_flag_enable(bm, (BMVert *)ele, HULL_FLAG_INPUT | HULL_FLAG_INTERIOR_ELE);
+ }
+ else if (ele->head.htype == BM_EDGE) {
+ BMO_edge_flag_enable(bm, (BMEdge *)ele, HULL_FLAG_INPUT);
+ }
+ else {
+ BMO_face_flag_enable(bm, (BMFace *)ele, HULL_FLAG_INPUT);
+ }
}
hull_pool = BLI_mempool_create(sizeof(HullTriangle), 0, 128, BLI_MEMPOOL_NOP);
diff --git a/source/blender/bmesh/operators/bmo_inset.c b/source/blender/bmesh/operators/bmo_inset.c
index ef5d90e6acb..c52c608e671 100644
--- a/source/blender/bmesh/operators/bmo_inset.c
+++ b/source/blender/bmesh/operators/bmo_inset.c
@@ -313,7 +313,7 @@ static void bmo_face_inset_individual(
l_iter->next->v,
l_iter->v,
f, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, f_new_outer, ELE_NEW);
+ BMO_face_flag_enable(bm, f_new_outer, ELE_NEW);
/* copy loop data */
l_other = l_iter->radial_next;
@@ -1037,7 +1037,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
/* no need to check doubles, we KNOW there won't be any */
/* yes - reverse face is correct in this case */
f = BM_face_create_verts(bm, varr, j, es->l->f, BM_CREATE_NOP, true);
- BMO_elem_flag_enable(bm, f, ELE_NEW);
+ BMO_face_flag_enable(bm, f, ELE_NEW);
/* copy for loop data, otherwise UV's and vcols are no good.
* tiny speedup here we could be more clever and copy from known adjacent data
diff --git a/source/blender/bmesh/operators/bmo_join_triangles.c b/source/blender/bmesh/operators/bmo_join_triangles.c
index 3718f14276c..bc620e4a020 100644
--- a/source/blender/bmesh/operators/bmo_join_triangles.c
+++ b/source/blender/bmesh/operators/bmo_join_triangles.c
@@ -315,7 +315,7 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op)
/* flag all edges of all input face */
BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) {
if (f->len == 3) {
- BMO_elem_flag_enable(bm, f, FACE_INPUT);
+ BMO_face_flag_enable(bm, f, FACE_INPUT);
}
}
@@ -323,11 +323,11 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op)
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
BMFace *f_a, *f_b;
if (BM_edge_face_pair(e, &f_a, &f_b) &&
- (BMO_elem_flag_test(bm, f_a, FACE_INPUT) &&
- BMO_elem_flag_test(bm, f_b, FACE_INPUT)))
+ (BMO_face_flag_test(bm, f_a, FACE_INPUT) &&
+ BMO_face_flag_test(bm, f_b, FACE_INPUT)))
{
if (!bm_edge_is_delimit(e, &delimit_data)) {
- BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ BMO_edge_flag_enable(bm, e, EDGE_MARK);
totedge_tag++;
}
}
@@ -345,7 +345,7 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op)
const BMVert *verts[4];
float error;
- if (!BMO_elem_flag_test(bm, e, EDGE_MARK))
+ if (!BMO_edge_flag_test(bm, e, EDGE_MARK))
continue;
bm_edge_to_quad_verts(e, verts);
@@ -372,7 +372,7 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op)
BMFace *f_new;
f_new = BM_faces_join_pair(bm, f_a, f_b, e, true);
if (f_new) {
- BMO_elem_flag_enable(bm, f_new, FACE_OUT);
+ BMO_face_flag_enable(bm, f_new, FACE_OUT);
}
}
}
diff --git a/source/blender/bmesh/operators/bmo_normals.c b/source/blender/bmesh/operators/bmo_normals.c
index 6044960265b..73dbee25be3 100644
--- a/source/blender/bmesh/operators/bmo_normals.c
+++ b/source/blender/bmesh/operators/bmo_normals.c
@@ -86,7 +86,7 @@ static int recalc_face_normals_find_index(BMesh *bm, BMFace **faces, const int f
int f_start_index;
int i;
- /* Search for the best loop. Members are comapred in-order defined here. */
+ /* Search for the best loop. Members are compared in-order defined here. */
struct {
/* Squared distance from the center to the loops vertex 'l->v'.
* The normalized direction between the center and this vertex is also used for the dot-products below. */
@@ -111,7 +111,7 @@ static int recalc_face_normals_find_index(BMesh *bm, BMFace **faces, const int f
madd_v3_v3fl(cent, f_cent, cent_fac * f_area);
cent_area_accum += f_area;
- BLI_assert(BMO_elem_flag_test(bm, faces[i], FACE_TEMP) == 0);
+ BLI_assert(BMO_face_flag_test(bm, faces[i], FACE_TEMP) == 0);
BLI_assert(BM_face_is_normal_valid(faces[i]));
}
@@ -209,7 +209,7 @@ static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int f
f_start_index = recalc_face_normals_find_index(bm, faces, faces_len, &is_flip);
if (is_flip) {
- BMO_elem_flag_enable(bm, faces[f_start_index], FACE_FLIP);
+ BMO_face_flag_enable(bm, faces[f_start_index], FACE_FLIP);
}
/* now that we've found our starting face, make all connected faces
@@ -219,10 +219,10 @@ static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int f
BLI_LINKSTACK_INIT(fstack);
BLI_LINKSTACK_PUSH(fstack, faces[f_start_index]);
- BMO_elem_flag_enable(bm, faces[f_start_index], FACE_TEMP);
+ BMO_face_flag_enable(bm, faces[f_start_index], FACE_TEMP);
while ((f = BLI_LINKSTACK_POP(fstack))) {
- const bool flip_state = BMO_elem_flag_test_bool(bm, f, FACE_FLIP);
+ const bool flip_state = BMO_face_flag_test_bool(bm, f, FACE_FLIP);
BMLoop *l_iter, *l_first;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
@@ -230,9 +230,9 @@ static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int f
BMLoop *l_other = l_iter->radial_next;
if ((l_other != l_iter) && bmo_recalc_normal_loop_filter_cb(l_iter, NULL)) {
- if (!BMO_elem_flag_test(bm, l_other->f, FACE_TEMP)) {
- BMO_elem_flag_enable(bm, l_other->f, FACE_TEMP);
- BMO_elem_flag_set(bm, l_other->f, FACE_FLIP, (l_other->v == l_iter->v) != flip_state);
+ if (!BMO_face_flag_test(bm, l_other->f, FACE_TEMP)) {
+ BMO_face_flag_enable(bm, l_other->f, FACE_TEMP);
+ BMO_face_flag_set(bm, l_other->f, FACE_FLIP, (l_other->v == l_iter->v) != flip_state);
BLI_LINKSTACK_PUSH(fstack, l_other->f);
}
}
@@ -243,10 +243,10 @@ static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int f
/* apply flipping to oflag'd faces */
for (i = 0; i < faces_len; i++) {
- if (BMO_elem_flag_test(bm, faces[i], oflag_flip) == oflag_flip) {
+ if (BMO_face_flag_test(bm, faces[i], oflag_flip) == oflag_flip) {
BM_face_normal_flip(bm, faces[i]);
}
- BMO_elem_flag_disable(bm, faces[i], FACE_TEMP);
+ BMO_face_flag_disable(bm, faces[i], FACE_TEMP);
}
}
@@ -284,7 +284,7 @@ void bmo_recalc_face_normals_exec(BMesh *bm, BMOperator *op)
faces_grp[j] = BM_face_at_index(bm, groups_array[fg_sta + j]);
if (is_calc == false) {
- is_calc = BMO_elem_flag_test_bool(bm, faces_grp[j], FACE_FLAG);
+ is_calc = BMO_face_flag_test_bool(bm, faces_grp[j], FACE_FLAG);
}
}
diff --git a/source/blender/bmesh/operators/bmo_offset_edgeloops.c b/source/blender/bmesh/operators/bmo_offset_edgeloops.c
index 8f4bc5ef3ad..7a6f779b34f 100644
--- a/source/blender/bmesh/operators/bmo_offset_edgeloops.c
+++ b/source/blender/bmesh/operators/bmo_offset_edgeloops.c
@@ -178,7 +178,7 @@ void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op)
#ifdef USE_CAP_OPTION
if (v_edges_num_untag == 1) {
- BMO_elem_flag_enable(bm, v, ELE_VERT_ENDPOINT);
+ BMO_vert_flag_enable(bm, v, ELE_VERT_ENDPOINT);
}
CLAMP_MIN(v_edges_max, v_edges_num);
@@ -201,7 +201,7 @@ void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op)
(BM_elem_index_get(l->prev->v) == -1))
{
#ifdef USE_CAP_OPTION
- if (use_cap_endpoint || (BMO_elem_flag_test(bm, v, ELE_VERT_ENDPOINT) == 0))
+ if (use_cap_endpoint || (BMO_vert_flag_test(bm, v, ELE_VERT_ENDPOINT) == 0))
#endif
{
BMLoop *l_new;
@@ -209,7 +209,7 @@ void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op)
BLI_assert(f_cmp == l->f);
BLI_assert(f_cmp != l_new->f);
UNUSED_VARS_NDEBUG(f_cmp);
- BMO_elem_flag_enable(bm, l_new->e, ELE_NEW);
+ BMO_edge_flag_enable(bm, l_new->e, ELE_NEW);
}
}
else if (l->f->len > 4) {
@@ -222,7 +222,7 @@ void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op)
BM_face_split(bm, l->f, l->prev->prev, l->next, &l_new, NULL, true);
BLI_assert(f_cmp == l->f);
BLI_assert(f_cmp != l_new->f);
- BMO_elem_flag_enable(bm, l_new->e, ELE_NEW);
+ BMO_edge_flag_enable(bm, l_new->e, ELE_NEW);
BM_elem_flag_disable(l->f, BM_ELEM_TAG);
}
else {
@@ -230,7 +230,7 @@ void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op)
BMLoop *l_new;
bm_face_split_walk_back(bm, l, &l_new);
do {
- BMO_elem_flag_enable(bm, l_new->e, ELE_NEW);
+ BMO_edge_flag_enable(bm, l_new->e, ELE_NEW);
l_new = l_new->next;
} while (BM_vert_is_edge_pair(l_new->v));
BM_elem_flag_disable(l->f, BM_ELEM_TAG);
diff --git a/source/blender/bmesh/operators/bmo_planar_faces.c b/source/blender/bmesh/operators/bmo_planar_faces.c
index 2856d3d18a6..a0951455fb4 100644
--- a/source/blender/bmesh/operators/bmo_planar_faces.c
+++ b/source/blender/bmesh/operators/bmo_planar_faces.c
@@ -71,13 +71,13 @@ void bmo_planar_faces_exec(BMesh *bm, BMOperator *op)
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
- if (!BMO_elem_flag_test(bm, l_iter->v, ELE_VERT_ADJUST)) {
- BMO_elem_flag_enable(bm, l_iter->v, ELE_VERT_ADJUST);
+ if (!BMO_vert_flag_test(bm, l_iter->v, ELE_VERT_ADJUST)) {
+ BMO_vert_flag_enable(bm, l_iter->v, ELE_VERT_ADJUST);
shared_vert_num += 1;
}
} while ((l_iter = l_iter->next) != l_first);
- BMO_elem_flag_enable(bm, f, ELE_FACE_ADJUST);
+ BMO_face_flag_enable(bm, f, ELE_FACE_ADJUST);
}
vert_accum_pool = BLI_mempool_create(sizeof(struct VertAccum), 0, 512, BLI_MEMPOOL_NOP);
@@ -91,10 +91,10 @@ void bmo_planar_faces_exec(BMesh *bm, BMOperator *op)
BMLoop *l_iter, *l_first;
float plane[4];
- if (!BMO_elem_flag_test(bm, f, ELE_FACE_ADJUST)) {
+ if (!BMO_face_flag_test(bm, f, ELE_FACE_ADJUST)) {
continue;
}
- BMO_elem_flag_disable(bm, f, ELE_FACE_ADJUST);
+ BMO_face_flag_disable(bm, f, ELE_FACE_ADJUST);
BLI_assert(f->len != 3);
@@ -130,7 +130,7 @@ void bmo_planar_faces_exec(BMesh *bm, BMOperator *op)
BMIter iter;
if (len_squared_v3v3(v->co, va->co) > eps_sq) {
- BMO_elem_flag_enable(bm, v, ELE_VERT_ADJUST);
+ BMO_vert_flag_enable(bm, v, ELE_VERT_ADJUST);
interp_v3_v3v3(v->co, v->co, va->co, fac);
changed = true;
}
@@ -138,7 +138,7 @@ void bmo_planar_faces_exec(BMesh *bm, BMOperator *op)
/* tag for re-calculation */
BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
if (f->len != 3) {
- BMO_elem_flag_enable(bm, f, ELE_FACE_ADJUST);
+ BMO_face_flag_enable(bm, f, ELE_FACE_ADJUST);
}
}
}
diff --git a/source/blender/bmesh/operators/bmo_poke.c b/source/blender/bmesh/operators/bmo_poke.c
index 4d86d6e8e5b..32ad25b7b82 100644
--- a/source/blender/bmesh/operators/bmo_poke.c
+++ b/source/blender/bmesh/operators/bmo_poke.c
@@ -87,7 +87,7 @@ void bmo_poke_exec(BMesh *bm, BMOperator *op)
bm_face_calc_center_fn(f, f_center);
v_center = BM_vert_create(bm, f_center, NULL, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, v_center, ELE_NEW);
+ BMO_vert_flag_enable(bm, v_center, ELE_NEW);
if (cd_loop_mdisp_offset != -1) {
if (center_mode == BMOP_POKE_MEAN) {
@@ -128,7 +128,7 @@ void bmo_poke_exec(BMesh *bm, BMOperator *op)
BM_elem_attrs_copy(bm, bm, l_iter, l_new);
BM_elem_attrs_copy(bm, bm, l_iter->next, l_new->next);
- BMO_elem_flag_enable(bm, f_new, ELE_NEW);
+ BMO_face_flag_enable(bm, f_new, ELE_NEW);
if (cd_loop_mdisp_offset != -1) {
float f_new_center[3];
diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c
index e3be4db804b..7b32921f8cf 100644
--- a/source/blender/bmesh/operators/bmo_primitive.c
+++ b/source/blender/bmesh/operators/bmo_primitive.c
@@ -78,6 +78,31 @@ static const short icoface[20][3] = {
{10, 9, 11}
};
+static const float icouvs[60][2] =
+{
+ {0.818181f, 0.000000f}, {0.727272f, 0.157461f}, {0.909090f, 0.157461f},
+ {0.727272f, 0.157461f}, {0.636363f, 0.000000f}, {0.545454f, 0.157461f},
+ {0.090909f, 0.000000f}, {0.000000f, 0.157461f}, {0.181818f, 0.157461f},
+ {0.272727f, 0.000000f}, {0.181818f, 0.157461f}, {0.363636f, 0.157461f},
+ {0.454545f, 0.000000f}, {0.363636f, 0.157461f}, {0.545454f, 0.157461f},
+ {0.727272f, 0.157461f}, {0.545454f, 0.157461f}, {0.636363f, 0.314921f},
+ {0.909090f, 0.157461f}, {0.727272f, 0.157461f}, {0.818181f, 0.314921f},
+ {0.181818f, 0.157461f}, {0.000000f, 0.157461f}, {0.090909f, 0.314921f},
+ {0.363636f, 0.157461f}, {0.181818f, 0.157461f}, {0.272727f, 0.314921f},
+ {0.545454f, 0.157461f}, {0.363636f, 0.157461f}, {0.454545f, 0.314921f},
+ {0.727272f, 0.157461f}, {0.636363f, 0.314921f}, {0.818181f, 0.314921f},
+ {0.909090f, 0.157461f}, {0.818181f, 0.314921f}, {1.000000f, 0.314921f},
+ {0.181818f, 0.157461f}, {0.090909f, 0.314921f}, {0.272727f, 0.314921f},
+ {0.363636f, 0.157461f}, {0.272727f, 0.314921f}, {0.454545f, 0.314921f},
+ {0.545454f, 0.157461f}, {0.454545f, 0.314921f}, {0.636363f, 0.314921f},
+ {0.818181f, 0.314921f}, {0.636363f, 0.314921f}, {0.727272f, 0.472382f},
+ {1.000000f, 0.314921f}, {0.818181f, 0.314921f}, {0.909090f, 0.472382f},
+ {0.272727f, 0.314921f}, {0.090909f, 0.314921f}, {0.181818f, 0.472382f},
+ {0.454545f, 0.314921f}, {0.272727f, 0.314921f}, {0.363636f, 0.472382f},
+ {0.636363f, 0.314921f}, {0.454545f, 0.314921f}, {0.545454f, 0.472382f}
+};
+
+
static const int monkeyo = 4;
static const int monkeynv = 271;
static const int monkeynf = 250;
@@ -218,6 +243,510 @@ static signed char monkeyf[250][4] = {
{-68, -67, 24, -33},
};
+static const float monkeyuvs[] =
+{
+ 0.890955f, 0.590063f, 0.870622f, 0.589649f, 0.860081f, 0.560115f, 0.904571f, 0.559404f,
+ 0.856226f, 0.850547f, 0.868067f, 0.821510f, 0.888398f, 0.821999f, 0.900640f, 0.853232f,
+ 0.904571f, 0.559404f, 0.860081f, 0.560115f, 0.853018f, 0.521562f, 0.920166f, 0.524546f,
+ 0.847458f, 0.888748f, 0.856226f, 0.850547f, 0.900640f, 0.853232f, 0.914672f, 0.888748f,
+ 0.860081f, 0.560115f, 0.828900f, 0.590771f, 0.798481f, 0.569535f, 0.853018f, 0.521562f,
+ 0.795104f, 0.838402f, 0.826436f, 0.818537f, 0.856226f, 0.850547f, 0.847458f, 0.888748f,
+ 0.870622f, 0.589649f, 0.854402f, 0.604754f, 0.828900f, 0.590771f, 0.860081f, 0.560115f,
+ 0.826436f, 0.818537f, 0.852534f, 0.805700f, 0.868067f, 0.821510f, 0.856226f, 0.850547f,
+ 0.854402f, 0.604754f, 0.854107f, 0.625459f, 0.828171f, 0.633354f, 0.828900f, 0.590771f,
+ 0.827598f, 0.775964f, 0.853157f, 0.785002f, 0.852534f, 0.805700f, 0.826436f, 0.818537f,
+ 0.828900f, 0.590771f, 0.828171f, 0.633354f, 0.791018f, 0.645443f, 0.798481f, 0.569535f,
+ 0.791018f, 0.762238f, 0.827598f, 0.775964f, 0.826436f, 0.818537f, 0.795104f, 0.838402f,
+ 0.828171f, 0.633354f, 0.855181f, 0.668527f, 0.842358f, 0.702491f, 0.791018f, 0.645443f,
+ 0.844839f, 0.707525f, 0.856142f, 0.742025f, 0.827598f, 0.775964f, 0.791018f, 0.762238f,
+ 0.854107f, 0.625459f, 0.867508f, 0.642291f, 0.855181f, 0.668527f, 0.828171f, 0.633354f,
+ 0.856142f, 0.742025f, 0.867293f, 0.768782f, 0.853157f, 0.785002f, 0.827598f, 0.775964f,
+ 0.867508f, 0.642291f, 0.890474f, 0.641909f, 0.900375f, 0.666964f, 0.855181f, 0.668527f,
+ 0.901223f, 0.745592f, 0.890219f, 0.770183f, 0.867293f, 0.768782f, 0.856142f, 0.742025f,
+ 0.855181f, 0.668527f, 0.900375f, 0.666964f, 0.918898f, 0.699697f, 0.842358f, 0.702491f,
+ 0.921180f, 0.713713f, 0.901223f, 0.745592f, 0.856142f, 0.742025f, 0.844839f, 0.707525f,
+ 0.900375f, 0.666964f, 0.931889f, 0.636832f, 0.968392f, 0.645333f, 0.918898f, 0.699697f,
+ 0.968213f, 0.770220f, 0.931368f, 0.777093f, 0.901223f, 0.745592f, 0.921180f, 0.713713f,
+ 0.890474f, 0.641909f, 0.905882f, 0.627902f, 0.931889f, 0.636832f, 0.900375f, 0.666964f,
+ 0.931368f, 0.777093f, 0.904990f, 0.784860f, 0.890219f, 0.770183f, 0.901223f, 0.745592f,
+ 0.905882f, 0.627902f, 0.906232f, 0.605742f, 0.933717f, 0.593037f, 0.931889f, 0.636832f,
+ 0.931250f, 0.820926f, 0.904357f, 0.807013f, 0.904990f, 0.784860f, 0.931368f, 0.777093f,
+ 0.931889f, 0.636832f, 0.933717f, 0.593037f, 0.968392f, 0.573812f, 0.968392f, 0.645333f,
+ 0.965038f, 0.841671f, 0.931250f, 0.820926f, 0.931368f, 0.777093f, 0.968213f, 0.770220f,
+ 0.933717f, 0.593037f, 0.904571f, 0.559404f, 0.920166f, 0.524546f, 0.968392f, 0.573812f,
+ 0.914672f, 0.888748f, 0.900640f, 0.853232f, 0.931250f, 0.820926f, 0.965038f, 0.841671f,
+ 0.906232f, 0.605742f, 0.890955f, 0.590063f, 0.904571f, 0.559404f, 0.933717f, 0.593037f,
+ 0.900640f, 0.853232f, 0.888398f, 0.821999f, 0.904357f, 0.807013f, 0.931250f, 0.820926f,
+ 0.890955f, 0.590063f, 0.906232f, 0.605742f, 0.902359f, 0.607909f, 0.889591f, 0.593275f,
+ 0.900583f, 0.804677f, 0.904357f, 0.807013f, 0.888398f, 0.821999f, 0.887178f, 0.818729f,
+ 0.906232f, 0.605742f, 0.905882f, 0.627902f, 0.899781f, 0.626257f, 0.902359f, 0.607909f,
+ 0.898822f, 0.786233f, 0.904990f, 0.784860f, 0.904357f, 0.807013f, 0.900583f, 0.804677f,
+ 0.905882f, 0.627902f, 0.890474f, 0.641909f, 0.887842f, 0.636527f, 0.899781f, 0.626257f,
+ 0.887351f, 0.775442f, 0.890219f, 0.770183f, 0.904990f, 0.784860f, 0.898822f, 0.786233f,
+ 0.890474f, 0.641909f, 0.867508f, 0.642291f, 0.870908f, 0.635245f, 0.887842f, 0.636527f,
+ 0.870376f, 0.775972f, 0.867293f, 0.768782f, 0.890219f, 0.770183f, 0.887351f, 0.775442f,
+ 0.867508f, 0.642291f, 0.854107f, 0.625459f, 0.859881f, 0.623942f, 0.870908f, 0.635245f,
+ 0.858859f, 0.786774f, 0.853157f, 0.785002f, 0.867293f, 0.768782f, 0.870376f, 0.775972f,
+ 0.854107f, 0.625459f, 0.854402f, 0.604754f, 0.859664f, 0.608186f, 0.859881f, 0.623942f,
+ 0.857942f, 0.802505f, 0.852534f, 0.805700f, 0.853157f, 0.785002f, 0.858859f, 0.786774f,
+ 0.854402f, 0.604754f, 0.870622f, 0.589649f, 0.871664f, 0.593961f, 0.859664f, 0.608186f,
+ 0.869299f, 0.817249f, 0.868067f, 0.821510f, 0.852534f, 0.805700f, 0.857942f, 0.802505f,
+ 0.870622f, 0.589649f, 0.890955f, 0.590063f, 0.889591f, 0.593275f, 0.871664f, 0.593961f,
+ 0.887178f, 0.818729f, 0.888398f, 0.821999f, 0.868067f, 0.821510f, 0.869299f, 0.817249f,
+ 0.879400f, 0.616512f, 0.871664f, 0.593961f, 0.889591f, 0.593275f,
+ 0.887178f, 0.818729f, 0.869299f, 0.817249f, 0.878029f, 0.795063f,
+ 0.859664f, 0.608186f, 0.871664f, 0.593961f, 0.879400f, 0.616512f,
+ 0.878029f, 0.795063f, 0.869299f, 0.817249f, 0.857942f, 0.802505f,
+ 0.879400f, 0.616512f, 0.859881f, 0.623942f, 0.859664f, 0.608186f,
+ 0.857942f, 0.802505f, 0.858859f, 0.786774f, 0.878029f, 0.795063f,
+ 0.879400f, 0.616512f, 0.870908f, 0.635245f, 0.859881f, 0.623942f,
+ 0.858859f, 0.786774f, 0.870376f, 0.775972f, 0.878029f, 0.795063f,
+ 0.879400f, 0.616512f, 0.887842f, 0.636527f, 0.870908f, 0.635245f,
+ 0.870376f, 0.775972f, 0.887351f, 0.775442f, 0.878029f, 0.795063f,
+ 0.879400f, 0.616512f, 0.899781f, 0.626257f, 0.887842f, 0.636527f,
+ 0.887351f, 0.775442f, 0.898822f, 0.786233f, 0.878029f, 0.795063f,
+ 0.879400f, 0.616512f, 0.902359f, 0.607909f, 0.899781f, 0.626257f,
+ 0.898822f, 0.786233f, 0.900583f, 0.804677f, 0.878029f, 0.795063f,
+ 0.879400f, 0.616512f, 0.889591f, 0.593275f, 0.902359f, 0.607909f,
+ 0.900583f, 0.804677f, 0.887178f, 0.818729f, 0.878029f, 0.795063f,
+ 0.540260f, 0.053805f, 0.536419f, 0.062072f, 0.518925f, 0.059681f, 0.518916f, 0.050294f,
+ 0.518925f, 0.059681f, 0.501452f, 0.062043f, 0.497626f, 0.053770f, 0.518916f, 0.050294f,
+ 0.551930f, 0.058338f, 0.542788f, 0.064089f, 0.536419f, 0.062072f, 0.540260f, 0.053805f,
+ 0.501452f, 0.062043f, 0.495083f, 0.064047f, 0.485955f, 0.058273f, 0.497626f, 0.053770f,
+ 0.555073f, 0.061900f, 0.546290f, 0.072669f, 0.542788f, 0.064089f, 0.551930f, 0.058338f,
+ 0.495083f, 0.064047f, 0.491565f, 0.072625f, 0.482805f, 0.061829f, 0.485955f, 0.058273f,
+ 0.563812f, 0.076586f, 0.548333f, 0.084893f, 0.546290f, 0.072669f, 0.555073f, 0.061900f,
+ 0.491565f, 0.072625f, 0.489507f, 0.084858f, 0.474014f, 0.076511f, 0.482805f, 0.061829f,
+ 0.583135f, 0.108495f, 0.555621f, 0.121749f, 0.548333f, 0.084893f, 0.563812f, 0.076586f,
+ 0.489507f, 0.084858f, 0.482177f, 0.121781f, 0.454527f, 0.108481f, 0.474014f, 0.076511f,
+ 0.605512f, 0.165134f, 0.647395f, 0.200502f, 0.621513f, 0.227818f, 0.553118f, 0.209599f,
+ 0.416514f, 0.229490f, 0.389677f, 0.201890f, 0.432024f, 0.165644f, 0.485339f, 0.210053f,
+ 0.647395f, 0.200502f, 0.676379f, 0.233241f, 0.664761f, 0.253225f, 0.621513f, 0.227818f,
+ 0.372747f, 0.256357f, 0.360308f, 0.235899f, 0.389677f, 0.201890f, 0.416514f, 0.229490f,
+ 0.676379f, 0.233241f, 0.715342f, 0.265392f, 0.683908f, 0.279995f, 0.664761f, 0.253225f,
+ 0.353696f, 0.284606f, 0.320452f, 0.270303f, 0.360308f, 0.235899f, 0.372747f, 0.256357f,
+ 0.715342f, 0.265392f, 0.707254f, 0.310054f, 0.687515f, 0.311539f, 0.683908f, 0.279995f,
+ 0.351187f, 0.317440f, 0.330721f, 0.316853f, 0.320452f, 0.270303f, 0.353696f, 0.284606f,
+ 0.707254f, 0.310054f, 0.697446f, 0.332673f, 0.676824f, 0.323937f, 0.687515f, 0.311539f,
+ 0.362723f, 0.329722f, 0.341964f, 0.339667f, 0.330721f, 0.316853f, 0.351187f, 0.317440f,
+ 0.697446f, 0.332673f, 0.662817f, 0.372521f, 0.639050f, 0.357330f, 0.676824f, 0.323937f,
+ 0.402772f, 0.362131f, 0.379297f, 0.378686f, 0.341964f, 0.339667f, 0.362723f, 0.329722f,
+ 0.662817f, 0.372521f, 0.626842f, 0.395792f, 0.618316f, 0.375151f, 0.639050f, 0.357330f,
+ 0.424583f, 0.379267f, 0.416915f, 0.400552f, 0.379297f, 0.378686f, 0.402772f, 0.362131f,
+ 0.626842f, 0.395792f, 0.604826f, 0.397804f, 0.600808f, 0.377857f, 0.618316f, 0.375151f,
+ 0.442396f, 0.381222f, 0.439252f, 0.401540f, 0.416915f, 0.400552f, 0.424583f, 0.379267f,
+ 0.604826f, 0.397804f, 0.553095f, 0.390512f, 0.559674f, 0.357011f, 0.600808f, 0.377857f,
+ 0.482938f, 0.358497f, 0.490934f, 0.391862f, 0.439252f, 0.401540f, 0.442396f, 0.381222f,
+ 0.553095f, 0.390512f, 0.521923f, 0.386009f, 0.521086f, 0.343868f, 0.559674f, 0.357011f,
+ 0.521086f, 0.343868f, 0.521923f, 0.386009f, 0.490934f, 0.391862f, 0.482938f, 0.358497f,
+ 0.577279f, 0.340156f, 0.599845f, 0.344815f, 0.600808f, 0.377857f, 0.559674f, 0.357011f,
+ 0.442396f, 0.381222f, 0.441977f, 0.347815f, 0.464579f, 0.342230f, 0.482938f, 0.358497f,
+ 0.599845f, 0.344815f, 0.615546f, 0.342005f, 0.618316f, 0.375151f, 0.600808f, 0.377857f,
+ 0.424583f, 0.379267f, 0.425972f, 0.345582f, 0.441977f, 0.347815f, 0.442396f, 0.381222f,
+ 0.634472f, 0.332311f, 0.639050f, 0.357330f, 0.618316f, 0.375151f, 0.615546f, 0.342005f,
+ 0.424583f, 0.379267f, 0.402772f, 0.362131f, 0.406362f, 0.336480f, 0.425972f, 0.345582f,
+ 0.662406f, 0.312804f, 0.676824f, 0.323937f, 0.639050f, 0.357330f, 0.634472f, 0.332311f,
+ 0.402772f, 0.362131f, 0.362723f, 0.329722f, 0.377061f, 0.317685f, 0.406362f, 0.336480f,
+ 0.668440f, 0.297958f, 0.687515f, 0.311539f, 0.676824f, 0.323937f, 0.662406f, 0.312804f,
+ 0.362723f, 0.329722f, 0.351187f, 0.317440f, 0.370304f, 0.302644f, 0.377061f, 0.317685f,
+ 0.664101f, 0.277872f, 0.683908f, 0.279995f, 0.687515f, 0.311539f, 0.668440f, 0.297958f,
+ 0.351187f, 0.317440f, 0.353696f, 0.284606f, 0.374100f, 0.281778f, 0.370304f, 0.302644f,
+ 0.639236f, 0.253047f, 0.664761f, 0.253225f, 0.683908f, 0.279995f, 0.664101f, 0.277872f,
+ 0.353696f, 0.284606f, 0.372747f, 0.256357f, 0.398938f, 0.255633f, 0.374100f, 0.281778f,
+ 0.613992f, 0.242662f, 0.621513f, 0.227818f, 0.664761f, 0.253225f, 0.639236f, 0.253047f,
+ 0.372747f, 0.256357f, 0.416514f, 0.229490f, 0.424464f, 0.244473f, 0.398938f, 0.255633f,
+ 0.572941f, 0.258564f, 0.553118f, 0.209599f, 0.621513f, 0.227818f, 0.613992f, 0.242662f,
+ 0.416514f, 0.229490f, 0.485339f, 0.210053f, 0.466409f, 0.259709f, 0.424464f, 0.244473f,
+ 0.572941f, 0.258564f, 0.563905f, 0.272007f, 0.519760f, 0.248864f, 0.553118f, 0.209599f,
+ 0.519760f, 0.248864f, 0.475886f, 0.273078f, 0.466409f, 0.259709f, 0.485339f, 0.210053f,
+ 0.577279f, 0.340156f, 0.559674f, 0.357011f, 0.521086f, 0.343868f, 0.558527f, 0.316594f,
+ 0.521086f, 0.343868f, 0.482938f, 0.358497f, 0.464579f, 0.342230f, 0.482619f, 0.317843f,
+ 0.558527f, 0.316594f, 0.521086f, 0.343868f, 0.520277f, 0.294764f, 0.556923f, 0.291214f,
+ 0.520277f, 0.294764f, 0.521086f, 0.343868f, 0.482619f, 0.317843f, 0.483433f, 0.292249f,
+ 0.519760f, 0.248864f, 0.563905f, 0.272007f, 0.556923f, 0.291214f, 0.520277f, 0.294764f,
+ 0.483433f, 0.292249f, 0.475886f, 0.273078f, 0.519760f, 0.248864f, 0.520277f, 0.294764f,
+ 0.525483f, 0.068967f, 0.518928f, 0.067899f, 0.518925f, 0.059681f, 0.536419f, 0.062072f,
+ 0.518925f, 0.059681f, 0.518928f, 0.067899f, 0.512375f, 0.068956f, 0.501452f, 0.062043f,
+ 0.531231f, 0.073829f, 0.525483f, 0.068967f, 0.536419f, 0.062072f, 0.542788f, 0.064089f,
+ 0.501452f, 0.062043f, 0.512375f, 0.068956f, 0.506626f, 0.073811f, 0.495083f, 0.064047f,
+ 0.531019f, 0.087431f, 0.531231f, 0.073829f, 0.542788f, 0.064089f, 0.546290f, 0.072669f,
+ 0.495083f, 0.064047f, 0.506626f, 0.073811f, 0.506827f, 0.087416f, 0.491565f, 0.072625f,
+ 0.555621f, 0.121749f, 0.532042f, 0.127713f, 0.532669f, 0.090920f, 0.548333f, 0.084893f,
+ 0.505177f, 0.090908f, 0.505828f, 0.127728f, 0.482177f, 0.121781f, 0.489507f, 0.084858f,
+ 0.531019f, 0.087431f, 0.546290f, 0.072669f, 0.548333f, 0.084893f, 0.532669f, 0.090920f,
+ 0.489507f, 0.084858f, 0.491565f, 0.072625f, 0.506827f, 0.087416f, 0.505177f, 0.090908f,
+ 0.538112f, 0.158382f, 0.518981f, 0.151749f, 0.518941f, 0.128358f, 0.532042f, 0.127713f,
+ 0.518941f, 0.128358f, 0.518981f, 0.151749f, 0.499851f, 0.158434f, 0.505828f, 0.127728f,
+ 0.532669f, 0.090920f, 0.532042f, 0.127713f, 0.518941f, 0.128358f, 0.518925f, 0.093952f,
+ 0.518941f, 0.128358f, 0.505828f, 0.127728f, 0.505177f, 0.090908f, 0.518925f, 0.093952f,
+ 0.518927f, 0.085180f, 0.531019f, 0.087431f, 0.532669f, 0.090920f, 0.518925f, 0.093952f,
+ 0.505177f, 0.090908f, 0.506827f, 0.087416f, 0.518927f, 0.085180f, 0.518925f, 0.093952f,
+ 0.548362f, 0.173560f, 0.537959f, 0.175966f, 0.535214f, 0.166808f, 0.538112f, 0.158382f,
+ 0.502799f, 0.166857f, 0.500100f, 0.176033f, 0.489683f, 0.173693f, 0.499851f, 0.158434f,
+ 0.544281f, 0.193366f, 0.537248f, 0.187577f, 0.537959f, 0.175966f, 0.548362f, 0.173560f,
+ 0.500100f, 0.176033f, 0.500890f, 0.187571f, 0.493996f, 0.193428f, 0.489683f, 0.173693f,
+ 0.519841f, 0.200843f, 0.528757f, 0.191785f, 0.537248f, 0.187577f, 0.544281f, 0.193366f,
+ 0.500890f, 0.187571f, 0.509219f, 0.191626f, 0.519841f, 0.200843f, 0.493996f, 0.193428f,
+ 0.517577f, 0.190607f, 0.519132f, 0.185382f, 0.528757f, 0.191785f, 0.519841f, 0.200843f,
+ 0.509219f, 0.191626f, 0.519132f, 0.185382f, 0.517577f, 0.190607f, 0.519841f, 0.200843f,
+ 0.518981f, 0.151749f, 0.538112f, 0.158382f, 0.535214f, 0.166808f, 0.518998f, 0.159028f,
+ 0.502799f, 0.166857f, 0.499851f, 0.158434f, 0.518981f, 0.151749f, 0.518998f, 0.159028f,
+ 0.518998f, 0.159028f, 0.535214f, 0.166808f, 0.531131f, 0.171631f, 0.519016f, 0.165599f,
+ 0.506910f, 0.171667f, 0.502799f, 0.166857f, 0.518998f, 0.159028f, 0.519016f, 0.165599f,
+ 0.519132f, 0.185382f, 0.519099f, 0.179457f, 0.528222f, 0.186316f, 0.528757f, 0.191785f,
+ 0.509787f, 0.186260f, 0.519099f, 0.179457f, 0.519132f, 0.185382f, 0.509219f, 0.191626f,
+ 0.528757f, 0.191785f, 0.528222f, 0.186316f, 0.533528f, 0.184215f, 0.537248f, 0.187577f,
+ 0.504547f, 0.184206f, 0.509787f, 0.186260f, 0.509219f, 0.191626f, 0.500890f, 0.187571f,
+ 0.537248f, 0.187577f, 0.533528f, 0.184215f, 0.533449f, 0.176739f, 0.537959f, 0.175966f,
+ 0.504604f, 0.176791f, 0.504547f, 0.184206f, 0.500890f, 0.187571f, 0.500100f, 0.176033f,
+ 0.537959f, 0.175966f, 0.533449f, 0.176739f, 0.531131f, 0.171631f, 0.535214f, 0.166808f,
+ 0.506910f, 0.171667f, 0.504604f, 0.176791f, 0.500100f, 0.176033f, 0.502799f, 0.166857f,
+ 0.519099f, 0.179457f, 0.533449f, 0.176739f, 0.533528f, 0.184215f, 0.528222f, 0.186316f,
+ 0.504547f, 0.184206f, 0.504604f, 0.176791f, 0.519099f, 0.179457f, 0.509787f, 0.186260f,
+ 0.519099f, 0.179457f, 0.519016f, 0.165599f, 0.531131f, 0.171631f, 0.533449f, 0.176739f,
+ 0.506910f, 0.171667f, 0.519016f, 0.165599f, 0.519099f, 0.179457f, 0.504604f, 0.176791f,
+ 0.519841f, 0.200843f, 0.544281f, 0.193366f, 0.553118f, 0.209599f, 0.519760f, 0.248864f,
+ 0.485339f, 0.210053f, 0.493996f, 0.193428f, 0.519841f, 0.200843f, 0.519760f, 0.248864f,
+ 0.544281f, 0.193366f, 0.548362f, 0.173560f, 0.561572f, 0.167779f, 0.553118f, 0.209599f,
+ 0.476363f, 0.167996f, 0.489683f, 0.173693f, 0.493996f, 0.193428f, 0.485339f, 0.210053f,
+ 0.548362f, 0.173560f, 0.538112f, 0.158382f, 0.559475f, 0.149319f, 0.561572f, 0.167779f,
+ 0.478371f, 0.149447f, 0.499851f, 0.158434f, 0.489683f, 0.173693f, 0.476363f, 0.167996f,
+ 0.538112f, 0.158382f, 0.532042f, 0.127713f, 0.555621f, 0.121749f, 0.559475f, 0.149319f,
+ 0.482177f, 0.121781f, 0.505828f, 0.127728f, 0.499851f, 0.158434f, 0.478371f, 0.149447f,
+ 0.583135f, 0.108495f, 0.596138f, 0.133426f, 0.559475f, 0.149319f, 0.555621f, 0.121749f,
+ 0.478371f, 0.149447f, 0.441395f, 0.133592f, 0.454527f, 0.108481f, 0.482177f, 0.121781f,
+ 0.596138f, 0.133426f, 0.601169f, 0.147885f, 0.561572f, 0.167779f, 0.559475f, 0.149319f,
+ 0.476363f, 0.167996f, 0.436337f, 0.148194f, 0.441395f, 0.133592f, 0.478371f, 0.149447f,
+ 0.605512f, 0.165134f, 0.553118f, 0.209599f, 0.561572f, 0.167779f, 0.601169f, 0.147885f,
+ 0.476363f, 0.167996f, 0.485339f, 0.210053f, 0.432024f, 0.165644f, 0.436337f, 0.148194f,
+ 0.531019f, 0.087431f, 0.518927f, 0.085180f, 0.518925f, 0.083865f, 0.528933f, 0.084957f,
+ 0.518925f, 0.083865f, 0.518927f, 0.085180f, 0.506827f, 0.087416f, 0.508915f, 0.084945f,
+ 0.531231f, 0.073829f, 0.531019f, 0.087431f, 0.528933f, 0.084957f, 0.529036f, 0.075429f,
+ 0.508915f, 0.084945f, 0.506827f, 0.087416f, 0.506626f, 0.073811f, 0.508820f, 0.075415f,
+ 0.525483f, 0.068967f, 0.531231f, 0.073829f, 0.529036f, 0.075429f, 0.523751f, 0.070508f,
+ 0.508820f, 0.075415f, 0.506626f, 0.073811f, 0.512375f, 0.068956f, 0.514106f, 0.070501f,
+ 0.518928f, 0.067899f, 0.525483f, 0.068967f, 0.523751f, 0.070508f, 0.518929f, 0.069468f,
+ 0.514106f, 0.070501f, 0.512375f, 0.068956f, 0.518928f, 0.067899f, 0.518929f, 0.069468f,
+ 0.518929f, 0.069468f, 0.523751f, 0.070508f, 0.521560f, 0.074970f, 0.518928f, 0.074259f,
+ 0.516297f, 0.074966f, 0.514106f, 0.070501f, 0.518929f, 0.069468f, 0.518928f, 0.074259f,
+ 0.523751f, 0.070508f, 0.529036f, 0.075429f, 0.524236f, 0.076691f, 0.521560f, 0.074970f,
+ 0.513619f, 0.076684f, 0.508820f, 0.075415f, 0.514106f, 0.070501f, 0.516297f, 0.074966f,
+ 0.529036f, 0.075429f, 0.528933f, 0.084957f, 0.524601f, 0.079886f, 0.524236f, 0.076691f,
+ 0.513252f, 0.079879f, 0.508915f, 0.084945f, 0.508820f, 0.075415f, 0.513619f, 0.076684f,
+ 0.528933f, 0.084957f, 0.518925f, 0.083865f, 0.518926f, 0.079331f, 0.524601f, 0.079886f,
+ 0.518926f, 0.079331f, 0.518925f, 0.083865f, 0.508915f, 0.084945f, 0.513252f, 0.079879f,
+ 0.518926f, 0.079331f, 0.518928f, 0.074259f, 0.521560f, 0.074970f, 0.524601f, 0.079886f,
+ 0.516297f, 0.074966f, 0.518928f, 0.074259f, 0.518926f, 0.079331f, 0.513252f, 0.079879f,
+ 0.524601f, 0.079886f, 0.521560f, 0.074970f, 0.524236f, 0.076691f,
+ 0.513619f, 0.076684f, 0.516297f, 0.074966f, 0.513252f, 0.079879f,
+ 0.556923f, 0.291214f, 0.563905f, 0.272007f, 0.571787f, 0.277295f, 0.568351f, 0.292904f,
+ 0.468070f, 0.278617f, 0.475886f, 0.273078f, 0.483433f, 0.292249f, 0.471978f, 0.294282f,
+ 0.558527f, 0.316594f, 0.556923f, 0.291214f, 0.568351f, 0.292904f, 0.573085f, 0.311386f,
+ 0.471978f, 0.294282f, 0.483433f, 0.292249f, 0.482619f, 0.317843f, 0.467790f, 0.313081f,
+ 0.577279f, 0.340156f, 0.558527f, 0.316594f, 0.573085f, 0.311386f, 0.584855f, 0.327708f,
+ 0.467790f, 0.313081f, 0.482619f, 0.317843f, 0.464579f, 0.342230f, 0.456477f, 0.329961f,
+ 0.563905f, 0.272007f, 0.572941f, 0.258564f, 0.580734f, 0.266620f, 0.571787f, 0.277295f,
+ 0.458737f, 0.268049f, 0.466409f, 0.259709f, 0.475886f, 0.273078f, 0.468070f, 0.278617f,
+ 0.572941f, 0.258564f, 0.613992f, 0.242662f, 0.611720f, 0.255725f, 0.580734f, 0.266620f,
+ 0.427062f, 0.257728f, 0.424464f, 0.244473f, 0.466409f, 0.259709f, 0.458737f, 0.268049f,
+ 0.613992f, 0.242662f, 0.639236f, 0.253047f, 0.632494f, 0.262853f, 0.611720f, 0.255725f,
+ 0.406068f, 0.265508f, 0.398938f, 0.255633f, 0.424464f, 0.244473f, 0.427062f, 0.257728f,
+ 0.639236f, 0.253047f, 0.664101f, 0.277872f, 0.653658f, 0.279971f, 0.632494f, 0.262853f,
+ 0.384904f, 0.283634f, 0.374100f, 0.281778f, 0.398938f, 0.255633f, 0.406068f, 0.265508f,
+ 0.664101f, 0.277872f, 0.668440f, 0.297958f, 0.656064f, 0.297636f, 0.653658f, 0.279971f,
+ 0.383015f, 0.301864f, 0.370304f, 0.302644f, 0.374100f, 0.281778f, 0.384904f, 0.283634f,
+ 0.668440f, 0.297958f, 0.662406f, 0.312804f, 0.652752f, 0.310186f, 0.656064f, 0.297636f,
+ 0.386858f, 0.314615f, 0.377061f, 0.317685f, 0.370304f, 0.302644f, 0.383015f, 0.301864f,
+ 0.662406f, 0.312804f, 0.634472f, 0.332311f, 0.629040f, 0.323864f, 0.652752f, 0.310186f,
+ 0.411556f, 0.327673f, 0.406362f, 0.336480f, 0.377061f, 0.317685f, 0.386858f, 0.314615f,
+ 0.634472f, 0.332311f, 0.615546f, 0.342005f, 0.614408f, 0.331972f, 0.629040f, 0.323864f,
+ 0.426727f, 0.335361f, 0.425972f, 0.345582f, 0.406362f, 0.336480f, 0.411556f, 0.327673f,
+ 0.615546f, 0.342005f, 0.599845f, 0.344815f, 0.601033f, 0.333624f, 0.614408f, 0.331972f,
+ 0.440344f, 0.336537f, 0.441977f, 0.347815f, 0.425972f, 0.345582f, 0.426727f, 0.335361f,
+ 0.599845f, 0.344815f, 0.577279f, 0.340156f, 0.584855f, 0.327708f, 0.601033f, 0.333624f,
+ 0.456477f, 0.329961f, 0.464579f, 0.342230f, 0.441977f, 0.347815f, 0.440344f, 0.336537f,
+ 0.601033f, 0.333624f, 0.584855f, 0.327708f, 0.590644f, 0.321516f, 0.601799f, 0.328453f,
+ 0.450408f, 0.323919f, 0.456477f, 0.329961f, 0.440344f, 0.336537f, 0.439372f, 0.331331f,
+ 0.614408f, 0.331972f, 0.601033f, 0.333624f, 0.601799f, 0.328453f, 0.613335f, 0.327083f,
+ 0.439372f, 0.331331f, 0.440344f, 0.336537f, 0.426727f, 0.335361f, 0.427623f, 0.330358f,
+ 0.629040f, 0.323864f, 0.614408f, 0.331972f, 0.613335f, 0.327083f, 0.626851f, 0.320513f,
+ 0.427623f, 0.330358f, 0.426727f, 0.335361f, 0.411556f, 0.327673f, 0.413648f, 0.324175f,
+ 0.652752f, 0.310186f, 0.629040f, 0.323864f, 0.626851f, 0.320513f, 0.646248f, 0.306421f,
+ 0.413648f, 0.324175f, 0.411556f, 0.327673f, 0.386858f, 0.314615f, 0.393381f, 0.310510f,
+ 0.656064f, 0.297636f, 0.652752f, 0.310186f, 0.646248f, 0.306421f, 0.649541f, 0.296225f,
+ 0.393381f, 0.310510f, 0.386858f, 0.314615f, 0.383015f, 0.301864f, 0.389662f, 0.300183f,
+ 0.653658f, 0.279971f, 0.656064f, 0.297636f, 0.649541f, 0.296225f, 0.647785f, 0.283486f,
+ 0.389662f, 0.300183f, 0.383015f, 0.301864f, 0.384904f, 0.283634f, 0.391040f, 0.287071f,
+ 0.632494f, 0.262853f, 0.653658f, 0.279971f, 0.647785f, 0.283486f, 0.629829f, 0.267263f,
+ 0.391040f, 0.287071f, 0.384904f, 0.283634f, 0.406068f, 0.265508f, 0.408893f, 0.269959f,
+ 0.611720f, 0.255725f, 0.632494f, 0.262853f, 0.629829f, 0.267263f, 0.612641f, 0.261560f,
+ 0.408893f, 0.269959f, 0.406068f, 0.265508f, 0.427062f, 0.257728f, 0.426254f, 0.263693f,
+ 0.580734f, 0.266620f, 0.611720f, 0.255725f, 0.612641f, 0.261560f, 0.585166f, 0.270991f,
+ 0.426254f, 0.263693f, 0.427062f, 0.257728f, 0.458737f, 0.268049f, 0.454369f, 0.272583f,
+ 0.571787f, 0.277295f, 0.580734f, 0.266620f, 0.585166f, 0.270991f, 0.578124f, 0.281900f,
+ 0.454369f, 0.272583f, 0.458737f, 0.268049f, 0.468070f, 0.278617f, 0.461798f, 0.283441f,
+ 0.584855f, 0.327708f, 0.573085f, 0.311386f, 0.579548f, 0.309340f, 0.590644f, 0.321516f,
+ 0.461204f, 0.311233f, 0.467790f, 0.313081f, 0.456477f, 0.329961f, 0.450408f, 0.323919f,
+ 0.573085f, 0.311386f, 0.568351f, 0.292904f, 0.577524f, 0.293776f, 0.579548f, 0.309340f,
+ 0.462754f, 0.295432f, 0.471978f, 0.294282f, 0.467790f, 0.313081f, 0.461204f, 0.311233f,
+ 0.568351f, 0.292904f, 0.571787f, 0.277295f, 0.578124f, 0.281900f, 0.577524f, 0.293776f,
+ 0.461798f, 0.283441f, 0.468070f, 0.278617f, 0.471978f, 0.294282f, 0.462754f, 0.295432f,
+ 0.521923f, 0.386009f, 0.553095f, 0.390512f, 0.553209f, 0.433063f, 0.523031f, 0.433628f,
+ 0.492809f, 0.434538f, 0.490934f, 0.391862f, 0.521923f, 0.386009f, 0.523031f, 0.433628f,
+ 0.553095f, 0.390512f, 0.604826f, 0.397804f, 0.609819f, 0.431516f, 0.553209f, 0.433063f,
+ 0.435860f, 0.435740f, 0.439252f, 0.401540f, 0.490934f, 0.391862f, 0.492809f, 0.434538f,
+ 0.604826f, 0.397804f, 0.626842f, 0.395792f, 0.648174f, 0.419316f, 0.609819f, 0.431516f,
+ 0.396518f, 0.425416f, 0.416915f, 0.400552f, 0.439252f, 0.401540f, 0.435860f, 0.435740f,
+ 0.626842f, 0.395792f, 0.662817f, 0.372521f, 0.692106f, 0.388274f, 0.648174f, 0.419316f,
+ 0.350292f, 0.396229f, 0.379297f, 0.378686f, 0.416915f, 0.400552f, 0.396518f, 0.425416f,
+ 0.662817f, 0.372521f, 0.697446f, 0.332673f, 0.726332f, 0.341754f, 0.692106f, 0.388274f,
+ 0.312756f, 0.350588f, 0.341964f, 0.339667f, 0.379297f, 0.378686f, 0.350292f, 0.396229f,
+ 0.697446f, 0.332673f, 0.707254f, 0.310054f, 0.735879f, 0.312112f, 0.726332f, 0.341754f,
+ 0.301067f, 0.320593f, 0.330721f, 0.316853f, 0.341964f, 0.339667f, 0.312756f, 0.350588f,
+ 0.707254f, 0.310054f, 0.715342f, 0.265392f, 0.729900f, 0.256393f, 0.735879f, 0.312112f,
+ 0.304876f, 0.261087f, 0.320452f, 0.270303f, 0.330721f, 0.316853f, 0.301067f, 0.320593f,
+ 0.715342f, 0.265392f, 0.676379f, 0.233241f, 0.698172f, 0.216906f, 0.729900f, 0.256393f,
+ 0.337414f, 0.219179f, 0.360308f, 0.235899f, 0.320452f, 0.270303f, 0.304876f, 0.261087f,
+ 0.676379f, 0.233241f, 0.647395f, 0.200502f, 0.663103f, 0.190671f, 0.698172f, 0.216906f,
+ 0.373474f, 0.191872f, 0.389677f, 0.201890f, 0.360308f, 0.235899f, 0.337414f, 0.219179f,
+ 0.626908f, 0.015608f, 0.649444f, 0.022378f, 0.660451f, 0.076084f, 0.621440f, 0.048089f,
+ 0.376796f, 0.075296f, 0.388827f, 0.021586f, 0.411318f, 0.015131f, 0.416419f, 0.047631f,
+ 0.567460f, 0.000144f, 0.626908f, 0.015608f, 0.621440f, 0.048089f, 0.577206f, 0.032801f,
+ 0.416419f, 0.047631f, 0.411318f, 0.015131f, 0.470636f, 0.000144f, 0.460782f, 0.032656f,
+ 0.518922f, 0.024886f, 0.567460f, 0.000144f, 0.577206f, 0.032801f, 0.547413f, 0.041724f,
+ 0.460782f, 0.032656f, 0.470636f, 0.000144f, 0.518922f, 0.024886f, 0.490511f, 0.041669f,
+ 0.540260f, 0.053805f, 0.518916f, 0.050294f, 0.518922f, 0.024886f, 0.547413f, 0.041724f,
+ 0.518922f, 0.024886f, 0.518916f, 0.050294f, 0.497626f, 0.053770f, 0.490511f, 0.041669f,
+ 0.551930f, 0.058338f, 0.540260f, 0.053805f, 0.547413f, 0.041724f, 0.558059f, 0.053871f,
+ 0.490511f, 0.041669f, 0.497626f, 0.053770f, 0.485955f, 0.058273f, 0.479842f, 0.053785f,
+ 0.555073f, 0.061900f, 0.551930f, 0.058338f, 0.558059f, 0.053871f, 0.576951f, 0.057998f,
+ 0.479842f, 0.053785f, 0.485955f, 0.058273f, 0.482805f, 0.061829f, 0.460920f, 0.057845f,
+ 0.563812f, 0.076586f, 0.555073f, 0.061900f, 0.576951f, 0.057998f, 0.611687f, 0.078268f,
+ 0.460920f, 0.057845f, 0.482805f, 0.061829f, 0.474014f, 0.076511f, 0.425932f, 0.077985f,
+ 0.576951f, 0.057998f, 0.577206f, 0.032801f, 0.621440f, 0.048089f, 0.611687f, 0.078268f,
+ 0.416419f, 0.047631f, 0.460782f, 0.032656f, 0.460920f, 0.057845f, 0.425932f, 0.077985f,
+ 0.576951f, 0.057998f, 0.558059f, 0.053871f, 0.547413f, 0.041724f, 0.577206f, 0.032801f,
+ 0.490511f, 0.041669f, 0.479842f, 0.053785f, 0.460920f, 0.057845f, 0.460782f, 0.032656f,
+ 0.626663f, 0.111357f, 0.611687f, 0.078268f, 0.621440f, 0.048089f, 0.660451f, 0.076084f,
+ 0.416419f, 0.047631f, 0.425932f, 0.077985f, 0.410618f, 0.111244f, 0.376796f, 0.075296f,
+ 0.583135f, 0.108495f, 0.563812f, 0.076586f, 0.611687f, 0.078268f, 0.626663f, 0.111357f,
+ 0.425932f, 0.077985f, 0.474014f, 0.076511f, 0.454527f, 0.108481f, 0.410618f, 0.111244f,
+ 0.596138f, 0.133426f, 0.629482f, 0.130456f, 0.623495f, 0.146796f, 0.601169f, 0.147885f,
+ 0.413741f, 0.147158f, 0.407648f, 0.130594f, 0.441395f, 0.133592f, 0.436337f, 0.148194f,
+ 0.583135f, 0.108495f, 0.626663f, 0.111357f, 0.629482f, 0.130456f, 0.596138f, 0.133426f,
+ 0.407648f, 0.130594f, 0.410618f, 0.111244f, 0.454527f, 0.108481f, 0.441395f, 0.133592f,
+ 0.605512f, 0.165134f, 0.601169f, 0.147885f, 0.623495f, 0.146796f, 0.619303f, 0.159841f,
+ 0.413741f, 0.147158f, 0.436337f, 0.148194f, 0.432024f, 0.165644f, 0.418035f, 0.160361f,
+ 0.605512f, 0.165134f, 0.619303f, 0.159841f, 0.663103f, 0.190671f, 0.647395f, 0.200502f,
+ 0.373474f, 0.191872f, 0.418035f, 0.160361f, 0.432024f, 0.165644f, 0.389677f, 0.201890f,
+ 0.945900f, 0.079569f, 0.886245f, 0.121777f, 0.849114f, 0.099732f, 0.891780f, 0.036916f,
+ 0.183115f, 0.092127f, 0.141314f, 0.112482f, 0.078961f, 0.060719f, 0.142277f, 0.021467f,
+ 0.891780f, 0.036916f, 0.849114f, 0.099732f, 0.788458f, 0.080826f, 0.805584f, 0.010786f,
+ 0.246353f, 0.076510f, 0.183115f, 0.092127f, 0.142277f, 0.021467f, 0.232648f, 0.003484f,
+ 0.805584f, 0.010786f, 0.788458f, 0.080826f, 0.687018f, 0.077204f, 0.672384f, 0.022201f,
+ 0.349875f, 0.075955f, 0.246353f, 0.076510f, 0.232648f, 0.003484f, 0.365979f, 0.020991f,
+ 0.672384f, 0.022201f, 0.687018f, 0.077204f, 0.660451f, 0.076084f, 0.649444f, 0.022378f,
+ 0.376796f, 0.075296f, 0.349875f, 0.075955f, 0.365979f, 0.020991f, 0.388827f, 0.021586f,
+ 0.626663f, 0.111357f, 0.660451f, 0.076084f, 0.687018f, 0.077204f, 0.629482f, 0.130456f,
+ 0.349875f, 0.075955f, 0.376796f, 0.075296f, 0.410618f, 0.111244f, 0.407648f, 0.130594f,
+ 0.729900f, 0.256393f, 0.698172f, 0.216906f, 0.760215f, 0.193244f, 0.789046f, 0.233323f,
+ 0.271553f, 0.193871f, 0.337414f, 0.219179f, 0.304876f, 0.261087f, 0.241255f, 0.236977f,
+ 0.994525f, 0.167705f, 0.909112f, 0.183261f, 0.886245f, 0.121777f, 0.945900f, 0.079569f,
+ 0.141314f, 0.112482f, 0.107928f, 0.179083f, 0.011829f, 0.155367f, 0.078961f, 0.060719f,
+ 0.911671f, 0.402429f, 0.862868f, 0.338556f, 0.894128f, 0.301884f, 0.962901f, 0.344752f,
+ 0.123776f, 0.315519f, 0.160557f, 0.356821f, 0.106400f, 0.432652f, 0.043968f, 0.367038f,
+ 0.962901f, 0.344752f, 0.894128f, 0.301884f, 0.915360f, 0.259804f, 0.999856f, 0.254640f,
+ 0.098965f, 0.266968f, 0.123776f, 0.315519f, 0.043968f, 0.367038f, 0.000144f, 0.259113f,
+ 0.999856f, 0.254640f, 0.915360f, 0.259804f, 0.909112f, 0.183261f, 0.994525f, 0.167705f,
+ 0.107928f, 0.179083f, 0.098965f, 0.266968f, 0.000144f, 0.259113f, 0.011829f, 0.155367f,
+ 0.749542f, 0.334683f, 0.735879f, 0.312112f, 0.766337f, 0.300809f, 0.789162f, 0.313727f,
+ 0.267408f, 0.310142f, 0.301067f, 0.320593f, 0.288183f, 0.346496f, 0.242992f, 0.325552f,
+ 0.789162f, 0.313727f, 0.766337f, 0.300809f, 0.815314f, 0.276388f, 0.846174f, 0.293397f,
+ 0.213065f, 0.285164f, 0.267408f, 0.310142f, 0.242992f, 0.325552f, 0.178537f, 0.304983f,
+ 0.846174f, 0.293397f, 0.815314f, 0.276388f, 0.845007f, 0.256352f, 0.873517f, 0.265922f,
+ 0.179662f, 0.263312f, 0.213065f, 0.285164f, 0.178537f, 0.304983f, 0.147089f, 0.274284f,
+ 0.873517f, 0.265922f, 0.845007f, 0.256352f, 0.859075f, 0.228168f, 0.886999f, 0.233769f,
+ 0.162803f, 0.231720f, 0.179662f, 0.263312f, 0.147089f, 0.274284f, 0.131514f, 0.237587f,
+ 0.842355f, 0.195160f, 0.875030f, 0.184705f, 0.886999f, 0.233769f, 0.859075f, 0.228168f,
+ 0.131514f, 0.237587f, 0.145224f, 0.182749f, 0.176788f, 0.196179f, 0.162803f, 0.231720f,
+ 0.909112f, 0.183261f, 0.915360f, 0.259804f, 0.886999f, 0.233769f, 0.875030f, 0.184705f,
+ 0.131514f, 0.237587f, 0.098965f, 0.266968f, 0.107928f, 0.179083f, 0.145224f, 0.182749f,
+ 0.915360f, 0.259804f, 0.894128f, 0.301884f, 0.873517f, 0.265922f, 0.886999f, 0.233769f,
+ 0.147089f, 0.274284f, 0.123776f, 0.315519f, 0.098965f, 0.266968f, 0.131514f, 0.237587f,
+ 0.894128f, 0.301884f, 0.862868f, 0.338556f, 0.846174f, 0.293397f, 0.873517f, 0.265922f,
+ 0.178537f, 0.304983f, 0.160557f, 0.356821f, 0.123776f, 0.315519f, 0.147089f, 0.274284f,
+ 0.862868f, 0.338556f, 0.794286f, 0.364062f, 0.789162f, 0.313727f, 0.846174f, 0.293397f,
+ 0.242992f, 0.325552f, 0.239776f, 0.382592f, 0.160557f, 0.356821f, 0.178537f, 0.304983f,
+ 0.770185f, 0.379538f, 0.749542f, 0.334683f, 0.789162f, 0.313727f, 0.794286f, 0.364062f,
+ 0.242992f, 0.325552f, 0.288183f, 0.346496f, 0.268122f, 0.398737f, 0.239776f, 0.382592f,
+ 0.845499f, 0.449967f, 0.794286f, 0.364062f, 0.862868f, 0.338556f, 0.911671f, 0.402429f,
+ 0.160557f, 0.356821f, 0.239776f, 0.382592f, 0.185281f, 0.484099f, 0.106400f, 0.432652f,
+ 0.815858f, 0.445381f, 0.770572f, 0.444261f, 0.755700f, 0.418603f, 0.770185f, 0.379538f,
+ 0.287033f, 0.442912f, 0.271364f, 0.473316f, 0.219260f, 0.477186f, 0.268122f, 0.398737f,
+ 0.815858f, 0.445381f, 0.770185f, 0.379538f, 0.794286f, 0.364062f, 0.845499f, 0.449967f,
+ 0.239776f, 0.382592f, 0.268122f, 0.398737f, 0.219260f, 0.477186f, 0.185281f, 0.484099f,
+ 0.819845f, 0.468071f, 0.815858f, 0.445381f, 0.845499f, 0.449967f,
+ 0.185281f, 0.484099f, 0.219260f, 0.477186f, 0.215894f, 0.503605f,
+ 0.735879f, 0.312112f, 0.729900f, 0.256393f, 0.789046f, 0.233323f, 0.766337f, 0.300809f,
+ 0.241255f, 0.236977f, 0.304876f, 0.261087f, 0.301067f, 0.320593f, 0.267408f, 0.310142f,
+ 0.789046f, 0.233323f, 0.809631f, 0.233887f, 0.815314f, 0.276388f, 0.766337f, 0.300809f,
+ 0.213065f, 0.285164f, 0.219168f, 0.237388f, 0.241255f, 0.236977f, 0.267408f, 0.310142f,
+ 0.809631f, 0.233887f, 0.829287f, 0.219562f, 0.845007f, 0.256352f, 0.815314f, 0.276388f,
+ 0.179662f, 0.263312f, 0.199067f, 0.222464f, 0.219168f, 0.237388f, 0.213065f, 0.285164f,
+ 0.842355f, 0.195160f, 0.859075f, 0.228168f, 0.845007f, 0.256352f, 0.829287f, 0.219562f,
+ 0.179662f, 0.263312f, 0.162803f, 0.231720f, 0.176788f, 0.196179f, 0.199067f, 0.222464f,
+ 0.687018f, 0.077204f, 0.788458f, 0.080826f, 0.786480f, 0.117591f, 0.715482f, 0.139727f,
+ 0.246666f, 0.114850f, 0.246353f, 0.076510f, 0.349875f, 0.075955f, 0.319538f, 0.139409f,
+ 0.760215f, 0.193244f, 0.715482f, 0.139727f, 0.786480f, 0.117591f, 0.785486f, 0.152330f,
+ 0.246666f, 0.114850f, 0.319538f, 0.139409f, 0.271553f, 0.193871f, 0.245969f, 0.151002f,
+ 0.698172f, 0.216906f, 0.663103f, 0.190671f, 0.715482f, 0.139727f, 0.760215f, 0.193244f,
+ 0.319538f, 0.139409f, 0.373474f, 0.191872f, 0.337414f, 0.219179f, 0.271553f, 0.193871f,
+ 0.663103f, 0.190671f, 0.623495f, 0.146796f, 0.629482f, 0.130456f, 0.715482f, 0.139727f,
+ 0.407648f, 0.130594f, 0.413741f, 0.147158f, 0.373474f, 0.191872f, 0.319538f, 0.139409f,
+ 0.629482f, 0.130456f, 0.687018f, 0.077204f, 0.715482f, 0.139727f,
+ 0.319538f, 0.139409f, 0.349875f, 0.075955f, 0.407648f, 0.130594f,
+ 0.663103f, 0.190671f, 0.619303f, 0.159841f, 0.623495f, 0.146796f,
+ 0.413741f, 0.147158f, 0.418035f, 0.160361f, 0.373474f, 0.191872f,
+ 0.842355f, 0.195160f, 0.837382f, 0.156361f, 0.858171f, 0.137775f, 0.875030f, 0.184705f,
+ 0.171653f, 0.132294f, 0.196622f, 0.155241f, 0.176788f, 0.196179f, 0.145224f, 0.182749f,
+ 0.909112f, 0.183261f, 0.875030f, 0.184705f, 0.858171f, 0.137775f, 0.886245f, 0.121777f,
+ 0.171653f, 0.132294f, 0.145224f, 0.182749f, 0.107928f, 0.179083f, 0.141314f, 0.112482f,
+ 0.785486f, 0.152330f, 0.786480f, 0.117591f, 0.858171f, 0.137775f, 0.837382f, 0.156361f,
+ 0.171653f, 0.132294f, 0.246666f, 0.114850f, 0.245969f, 0.151002f, 0.196622f, 0.155241f,
+ 0.788458f, 0.080826f, 0.849114f, 0.099732f, 0.858171f, 0.137775f, 0.786480f, 0.117591f,
+ 0.171653f, 0.132294f, 0.183115f, 0.092127f, 0.246353f, 0.076510f, 0.246666f, 0.114850f,
+ 0.886245f, 0.121777f, 0.858171f, 0.137775f, 0.849114f, 0.099732f,
+ 0.183115f, 0.092127f, 0.171653f, 0.132294f, 0.141314f, 0.112482f,
+ 0.506166f, 0.904851f, 0.432388f, 0.894943f, 0.438797f, 0.870229f, 0.491058f, 0.881714f,
+ 0.315867f, 0.868209f, 0.321637f, 0.893225f, 0.247207f, 0.901159f, 0.263032f, 0.878321f,
+ 0.506166f, 0.904851f, 0.491058f, 0.881714f, 0.572792f, 0.860484f, 0.604825f, 0.879946f,
+ 0.181486f, 0.854693f, 0.263032f, 0.878321f, 0.247207f, 0.901159f, 0.148729f, 0.873349f,
+ 0.604825f, 0.879946f, 0.572792f, 0.860484f, 0.586396f, 0.793977f, 0.619962f, 0.791615f,
+ 0.169745f, 0.787474f, 0.181486f, 0.854693f, 0.148729f, 0.873349f, 0.136063f, 0.784093f,
+ 0.619962f, 0.791615f, 0.586396f, 0.793977f, 0.549027f, 0.746412f, 0.563786f, 0.739211f,
+ 0.208656f, 0.740879f, 0.169745f, 0.787474f, 0.136063f, 0.784093f, 0.194086f, 0.733241f,
+ 0.563786f, 0.739211f, 0.549027f, 0.746412f, 0.500314f, 0.711729f, 0.508270f, 0.697693f,
+ 0.258399f, 0.707497f, 0.208656f, 0.740879f, 0.194086f, 0.733241f, 0.250811f, 0.693249f,
+ 0.508270f, 0.697693f, 0.500314f, 0.711729f, 0.438641f, 0.680683f, 0.434803f, 0.658882f,
+ 0.320962f, 0.677959f, 0.258399f, 0.707497f, 0.250811f, 0.693249f, 0.325318f, 0.656224f,
+ 0.500314f, 0.711729f, 0.505666f, 0.730944f, 0.452955f, 0.700023f, 0.438641f, 0.680683f,
+ 0.306136f, 0.696976f, 0.252524f, 0.726592f, 0.258399f, 0.707497f, 0.320962f, 0.677959f,
+ 0.549027f, 0.746412f, 0.542850f, 0.755753f, 0.505666f, 0.730944f, 0.500314f, 0.711729f,
+ 0.252524f, 0.726592f, 0.214575f, 0.750414f, 0.208656f, 0.740879f, 0.258399f, 0.707497f,
+ 0.586396f, 0.793977f, 0.568148f, 0.787367f, 0.542850f, 0.755753f, 0.549027f, 0.746412f,
+ 0.214575f, 0.750414f, 0.188269f, 0.781375f, 0.169745f, 0.787474f, 0.208656f, 0.740879f,
+ 0.572792f, 0.860484f, 0.555495f, 0.826352f, 0.568148f, 0.787367f, 0.586396f, 0.793977f,
+ 0.188269f, 0.781375f, 0.199850f, 0.820889f, 0.181486f, 0.854693f, 0.169745f, 0.787474f,
+ 0.491058f, 0.881714f, 0.501231f, 0.844356f, 0.555495f, 0.826352f, 0.572792f, 0.860484f,
+ 0.199850f, 0.820889f, 0.253846f, 0.840502f, 0.263032f, 0.878321f, 0.181486f, 0.854693f,
+ 0.491058f, 0.881714f, 0.438797f, 0.870229f, 0.457832f, 0.840040f, 0.501231f, 0.844356f,
+ 0.297562f, 0.837358f, 0.315867f, 0.868209f, 0.263032f, 0.878321f, 0.253846f, 0.840502f,
+ 0.760215f, 0.193244f, 0.785486f, 0.152330f, 0.796021f, 0.176969f, 0.783193f, 0.187449f,
+ 0.233625f, 0.175620f, 0.245969f, 0.151002f, 0.271553f, 0.193871f, 0.246955f, 0.187075f,
+ 0.391039f, 0.611891f, 0.434803f, 0.658882f, 0.438641f, 0.680683f, 0.394766f, 0.686125f,
+ 0.320962f, 0.677959f, 0.325318f, 0.656224f, 0.369913f, 0.610196f, 0.364838f, 0.684445f,
+ 0.789046f, 0.233323f, 0.760215f, 0.193244f, 0.783193f, 0.187449f, 0.809631f, 0.233887f,
+ 0.246955f, 0.187075f, 0.271553f, 0.193871f, 0.241255f, 0.236977f, 0.219168f, 0.237388f,
+ 0.391747f, 0.862097f, 0.401605f, 0.841460f, 0.438797f, 0.870229f, 0.432388f, 0.894943f,
+ 0.315867f, 0.868209f, 0.354026f, 0.840297f, 0.363377f, 0.861308f, 0.321637f, 0.893225f,
+ 0.438641f, 0.680683f, 0.452955f, 0.700023f, 0.435018f, 0.718280f, 0.394766f, 0.686125f,
+ 0.323658f, 0.715731f, 0.306136f, 0.696976f, 0.320962f, 0.677959f, 0.364838f, 0.684445f,
+ 0.433669f, 0.729661f, 0.384658f, 0.710299f, 0.394766f, 0.686125f, 0.435018f, 0.718280f,
+ 0.364838f, 0.684445f, 0.374400f, 0.708969f, 0.324726f, 0.727177f, 0.323658f, 0.715731f,
+ 0.410995f, 0.747662f, 0.384658f, 0.710299f, 0.433669f, 0.729661f, 0.427812f, 0.742828f,
+ 0.324726f, 0.727177f, 0.374400f, 0.708969f, 0.347028f, 0.745816f, 0.330270f, 0.740536f,
+ 0.418086f, 0.784946f, 0.384657f, 0.795423f, 0.384658f, 0.710299f, 0.410995f, 0.747662f,
+ 0.374400f, 0.708969f, 0.372270f, 0.794472f, 0.338952f, 0.783073f, 0.347028f, 0.745816f,
+ 0.401605f, 0.841460f, 0.384657f, 0.795423f, 0.418086f, 0.784946f, 0.431333f, 0.817535f,
+ 0.338952f, 0.783073f, 0.372270f, 0.794472f, 0.354026f, 0.840297f, 0.324790f, 0.815460f,
+ 0.438797f, 0.870229f, 0.401605f, 0.841460f, 0.431333f, 0.817535f, 0.457832f, 0.840040f,
+ 0.324790f, 0.815460f, 0.354026f, 0.840297f, 0.315867f, 0.868209f, 0.297562f, 0.837358f,
+ 0.809631f, 0.233887f, 0.816266f, 0.203086f, 0.825107f, 0.209762f, 0.829287f, 0.219562f,
+ 0.199767f, 0.214827f, 0.209828f, 0.206161f, 0.219168f, 0.237388f, 0.199067f, 0.222464f,
+ 0.809631f, 0.233887f, 0.783193f, 0.187449f, 0.802192f, 0.184609f, 0.816266f, 0.203086f,
+ 0.226485f, 0.183086f, 0.246955f, 0.187075f, 0.219168f, 0.237388f, 0.209828f, 0.206161f,
+ 0.783193f, 0.187449f, 0.796021f, 0.176969f, 0.802192f, 0.184609f,
+ 0.226485f, 0.183086f, 0.233625f, 0.175620f, 0.246955f, 0.187075f,
+ 0.457832f, 0.840040f, 0.431333f, 0.817535f, 0.448505f, 0.804621f, 0.473386f, 0.824700f,
+ 0.307886f, 0.802031f, 0.324790f, 0.815460f, 0.297562f, 0.837358f, 0.282357f, 0.821525f,
+ 0.431333f, 0.817535f, 0.418086f, 0.784946f, 0.435868f, 0.779569f, 0.448505f, 0.804621f,
+ 0.321237f, 0.777208f, 0.338952f, 0.783073f, 0.324790f, 0.815460f, 0.307886f, 0.802031f,
+ 0.418086f, 0.784946f, 0.410995f, 0.747662f, 0.423718f, 0.754191f, 0.435868f, 0.779569f,
+ 0.334089f, 0.752045f, 0.347028f, 0.745816f, 0.338952f, 0.783073f, 0.321237f, 0.777208f,
+ 0.410995f, 0.747662f, 0.427812f, 0.742828f, 0.437950f, 0.749777f, 0.423718f, 0.754191f,
+ 0.319919f, 0.747250f, 0.330270f, 0.740536f, 0.347028f, 0.745816f, 0.334089f, 0.752045f,
+ 0.427812f, 0.742828f, 0.433669f, 0.729661f, 0.445392f, 0.731997f, 0.437950f, 0.749777f,
+ 0.312907f, 0.729222f, 0.324726f, 0.727177f, 0.330270f, 0.740536f, 0.319919f, 0.747250f,
+ 0.433669f, 0.729661f, 0.435018f, 0.718280f, 0.440995f, 0.724383f, 0.445392f, 0.731997f,
+ 0.317510f, 0.721697f, 0.323658f, 0.715731f, 0.324726f, 0.727177f, 0.312907f, 0.729222f,
+ 0.435018f, 0.718280f, 0.452955f, 0.700023f, 0.455277f, 0.713731f, 0.440995f, 0.724383f,
+ 0.303460f, 0.710657f, 0.306136f, 0.696976f, 0.323658f, 0.715731f, 0.317510f, 0.721697f,
+ 0.501231f, 0.844356f, 0.457832f, 0.840040f, 0.473386f, 0.824700f, 0.512485f, 0.828811f,
+ 0.282357f, 0.821525f, 0.297562f, 0.837358f, 0.253846f, 0.840502f, 0.242975f, 0.824574f,
+ 0.555495f, 0.826352f, 0.501231f, 0.844356f, 0.512485f, 0.828811f, 0.550942f, 0.811814f,
+ 0.242975f, 0.824574f, 0.253846f, 0.840502f, 0.199850f, 0.820889f, 0.204839f, 0.806417f,
+ 0.568148f, 0.787367f, 0.555495f, 0.826352f, 0.550942f, 0.811814f, 0.552139f, 0.787682f,
+ 0.204839f, 0.806417f, 0.199850f, 0.820889f, 0.188269f, 0.781375f, 0.204331f, 0.782156f,
+ 0.542850f, 0.755753f, 0.568148f, 0.787367f, 0.552139f, 0.787682f, 0.539407f, 0.764539f,
+ 0.204331f, 0.782156f, 0.188269f, 0.781375f, 0.214575f, 0.750414f, 0.217774f, 0.759319f,
+ 0.505666f, 0.730944f, 0.542850f, 0.755753f, 0.539407f, 0.764539f, 0.508439f, 0.743135f,
+ 0.217774f, 0.759319f, 0.214575f, 0.750414f, 0.252524f, 0.726592f, 0.249419f, 0.738732f,
+ 0.452955f, 0.700023f, 0.505666f, 0.730944f, 0.508439f, 0.743135f, 0.455277f, 0.713731f,
+ 0.249419f, 0.738732f, 0.252524f, 0.726592f, 0.306136f, 0.696976f, 0.303460f, 0.710657f,
+ 0.437950f, 0.749777f, 0.445392f, 0.731997f, 0.470841f, 0.748408f, 0.454776f, 0.761665f,
+ 0.286960f, 0.745020f, 0.312907f, 0.729222f, 0.319919f, 0.747250f, 0.302729f, 0.758742f,
+ 0.454776f, 0.761665f, 0.470841f, 0.748408f, 0.488870f, 0.770464f, 0.475403f, 0.783904f,
+ 0.268291f, 0.766661f, 0.286960f, 0.745020f, 0.302729f, 0.758742f, 0.281439f, 0.780511f,
+ 0.475403f, 0.783904f, 0.488870f, 0.770464f, 0.503673f, 0.787562f, 0.494476f, 0.802470f,
+ 0.252972f, 0.783410f, 0.268291f, 0.766661f, 0.281439f, 0.780511f, 0.261790f, 0.798626f,
+ 0.494476f, 0.802470f, 0.503673f, 0.787562f, 0.518562f, 0.791602f, 0.516802f, 0.807339f,
+ 0.237920f, 0.787045f, 0.252972f, 0.783410f, 0.261790f, 0.798626f, 0.239243f, 0.802891f,
+ 0.512485f, 0.828811f, 0.473386f, 0.824700f, 0.494476f, 0.802470f, 0.516802f, 0.807339f,
+ 0.261790f, 0.798626f, 0.282357f, 0.821525f, 0.242975f, 0.824574f, 0.239243f, 0.802891f,
+ 0.448505f, 0.804621f, 0.475403f, 0.783904f, 0.494476f, 0.802470f, 0.473386f, 0.824700f,
+ 0.261790f, 0.798626f, 0.281439f, 0.780511f, 0.307886f, 0.802031f, 0.282357f, 0.821525f,
+ 0.448505f, 0.804621f, 0.435868f, 0.779569f, 0.454776f, 0.761665f, 0.475403f, 0.783904f,
+ 0.302729f, 0.758742f, 0.321237f, 0.777208f, 0.307886f, 0.802031f, 0.281439f, 0.780511f,
+ 0.437950f, 0.749777f, 0.454776f, 0.761665f, 0.435868f, 0.779569f, 0.423718f, 0.754191f,
+ 0.321237f, 0.777208f, 0.302729f, 0.758742f, 0.319919f, 0.747250f, 0.334089f, 0.752045f,
+ 0.440995f, 0.724383f, 0.455277f, 0.713731f, 0.470841f, 0.748408f, 0.445392f, 0.731997f,
+ 0.286960f, 0.745020f, 0.303460f, 0.710657f, 0.317510f, 0.721697f, 0.312907f, 0.729222f,
+ 0.508439f, 0.743135f, 0.488870f, 0.770464f, 0.470841f, 0.748408f, 0.455277f, 0.713731f,
+ 0.286960f, 0.745020f, 0.268291f, 0.766661f, 0.249419f, 0.738732f, 0.303460f, 0.710657f,
+ 0.539407f, 0.764539f, 0.503673f, 0.787562f, 0.488870f, 0.770464f, 0.508439f, 0.743135f,
+ 0.268291f, 0.766661f, 0.252972f, 0.783410f, 0.217774f, 0.759319f, 0.249419f, 0.738732f,
+ 0.552139f, 0.787682f, 0.518562f, 0.791602f, 0.503673f, 0.787562f, 0.539407f, 0.764539f,
+ 0.252972f, 0.783410f, 0.237920f, 0.787045f, 0.204331f, 0.782156f, 0.217774f, 0.759319f,
+ 0.550942f, 0.811814f, 0.516802f, 0.807339f, 0.518562f, 0.791602f, 0.552139f, 0.787682f,
+ 0.237920f, 0.787045f, 0.239243f, 0.802891f, 0.204839f, 0.806417f, 0.204331f, 0.782156f,
+ 0.512485f, 0.828811f, 0.516802f, 0.807339f, 0.550942f, 0.811814f,
+ 0.204839f, 0.806417f, 0.239243f, 0.802891f, 0.242975f, 0.824574f,
+ 0.508270f, 0.697693f, 0.434803f, 0.658882f, 0.484068f, 0.628776f, 0.543385f, 0.683538f,
+ 0.276936f, 0.625067f, 0.325318f, 0.656224f, 0.250811f, 0.693249f, 0.216123f, 0.678120f,
+ 0.563786f, 0.739211f, 0.508270f, 0.697693f, 0.543385f, 0.683538f, 0.581052f, 0.726933f,
+ 0.216123f, 0.678120f, 0.250811f, 0.693249f, 0.194086f, 0.733241f, 0.177176f, 0.720426f,
+ 0.619962f, 0.791615f, 0.563786f, 0.739211f, 0.581052f, 0.726933f, 0.616701f, 0.759965f,
+ 0.177176f, 0.720426f, 0.194086f, 0.733241f, 0.136063f, 0.784093f, 0.140379f, 0.752377f,
+ 0.707492f, 0.759884f, 0.619962f, 0.791615f, 0.616701f, 0.759965f, 0.660647f, 0.741167f,
+ 0.140379f, 0.752377f, 0.136063f, 0.784093f, 0.049526f, 0.748824f, 0.097038f, 0.732052f,
+ 0.745511f, 0.652100f, 0.707492f, 0.759884f, 0.660647f, 0.741167f, 0.677256f, 0.670436f,
+ 0.097038f, 0.732052f, 0.049526f, 0.748824f, 0.019409f, 0.639749f, 0.083564f, 0.662038f,
+ 0.740843f, 0.572428f, 0.745511f, 0.652100f, 0.677256f, 0.670436f, 0.671403f, 0.592656f,
+ 0.083564f, 0.662038f, 0.019409f, 0.639749f, 0.033664f, 0.564403f, 0.092820f, 0.589862f,
+ 0.677256f, 0.670436f, 0.543385f, 0.683538f, 0.484068f, 0.628776f, 0.671403f, 0.592656f,
+ 0.276936f, 0.625067f, 0.216123f, 0.678120f, 0.083564f, 0.662038f, 0.092820f, 0.589862f,
+ 0.677256f, 0.670436f, 0.660647f, 0.741167f, 0.581052f, 0.726933f, 0.543385f, 0.683538f,
+ 0.177176f, 0.720426f, 0.097038f, 0.732052f, 0.083564f, 0.662038f, 0.216123f, 0.678120f,
+ 0.660647f, 0.741167f, 0.616701f, 0.759965f, 0.581052f, 0.726933f,
+ 0.177176f, 0.720426f, 0.140379f, 0.752377f, 0.097038f, 0.732052f,
+ 0.842355f, 0.195160f, 0.829287f, 0.219562f, 0.834578f, 0.206879f, 0.834705f, 0.206959f,
+ 0.033664f, 0.564403f, 0.051216f, 0.522659f, 0.145041f, 0.562595f, 0.092820f, 0.589862f,
+ 0.620420f, 0.565675f, 0.671403f, 0.592656f, 0.484068f, 0.628776f, 0.498072f, 0.552315f,
+ 0.276936f, 0.625067f, 0.092820f, 0.589862f, 0.145041f, 0.562595f, 0.264218f, 0.550140f,
+ 0.391039f, 0.611891f, 0.498072f, 0.552315f, 0.484068f, 0.628776f, 0.434803f, 0.658882f,
+ 0.276936f, 0.625067f, 0.264218f, 0.550140f, 0.369913f, 0.610196f, 0.325318f, 0.656224f
+};
+
#define VERT_MARK 1
#define EDGE_ORIG 1
@@ -259,7 +788,7 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op)
vec[0] = ((x * xtot_inv2) - 1.0f) * dia;
mul_v3_m4v3(tvec, mat, vec);
varr[i] = BM_vert_create(bm, tvec, NULL, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, varr[i], VERT_MARK);
+ BMO_vert_flag_enable(bm, varr[i], VERT_MARK);
i++;
}
}
@@ -277,7 +806,7 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op)
f = BM_face_create_verts(bm, vquad, 4, NULL, BM_CREATE_NOP, true);
if (calc_uvs) {
- BMO_elem_flag_enable(bm, f, FACE_MARK);
+ BMO_face_flag_enable(bm, f, FACE_MARK);
}
}
}
@@ -315,7 +844,7 @@ void BM_mesh_calc_uvs_grid(BMesh *bm, const unsigned int x_segments, const unsig
BLI_assert(cd_loop_uv_offset != -1);
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (!BMO_elem_flag_test(bm, f, oflag))
+ if (!BMO_face_flag_test(bm, f, oflag))
continue;
BM_ITER_ELEM_INDEX (l, &liter, f, BM_LOOPS_OF_FACE, loop_index) {
@@ -380,11 +909,11 @@ void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op)
vec[1] = dia * sinf(phi);
vec[2] = dia * cosf(phi);
eve = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, eve, VERT_MARK);
+ BMO_vert_flag_enable(bm, eve, VERT_MARK);
if (a != 0) {
e = BM_edge_create(bm, preveve, eve, NULL, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, e, EDGE_ORIG);
+ BMO_edge_flag_enable(bm, e, EDGE_ORIG);
}
phi += phid;
@@ -442,14 +971,14 @@ void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op)
bool valid = true;
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- if (!BMO_elem_flag_test(bm, l->v, VERT_MARK)) {
+ if (!BMO_vert_flag_test(bm, l->v, VERT_MARK)) {
valid = false;
break;
}
}
if (valid) {
- BMO_elem_flag_enable(bm, f, FACE_MARK);
+ BMO_face_flag_enable(bm, f, FACE_MARK);
}
}
@@ -458,7 +987,7 @@ void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op)
/* and now do imat */
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
- if (BMO_elem_flag_test(bm, eve, VERT_MARK)) {
+ if (BMO_vert_flag_test(bm, eve, VERT_MARK)) {
mul_m4_v3(mat, eve->co);
}
}
@@ -493,24 +1022,36 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op)
vec[2] = dia_div * icovert[a][2];
eva[a] = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, eva[a], VERT_MARK);
+ BMO_vert_flag_enable(bm, eva[a], VERT_MARK);
}
+ int uvi = 0;
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
for (a = 0; a < 20; a++) {
- BMFace *eftemp;
+ BMFace *f;
BMVert *v1, *v2, *v3;
v1 = eva[icoface[a][0]];
v2 = eva[icoface[a][1]];
v3 = eva[icoface[a][2]];
- eftemp = BM_face_create_quad_tri(bm, v1, v2, v3, NULL, NULL, BM_CREATE_NOP);
+ f = BM_face_create_quad_tri(bm, v1, v2, v3, NULL, NULL, BM_CREATE_NOP);
- BM_ITER_ELEM (l, &liter, eftemp, BM_LOOPS_OF_FACE) {
- BMO_elem_flag_enable(bm, l->e, EDGE_MARK);
+ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
+ BMO_edge_flag_enable(bm, l->e, EDGE_MARK);
}
- BMO_elem_flag_enable(bm, eftemp, FACE_MARK);
+ /* Set the UVs here, the iteration order of the faces is not guaranteed,
+ * so it's best to set the UVs right after the face is created. */
+ if (calc_uvs) {
+ int loop_index;
+ BM_ITER_ELEM_INDEX (l, &liter, f, BM_LOOPS_OF_FACE, loop_index) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->uv[0] = icouvs[uvi][0];
+ luv->uv[1] = icouvs[uvi][1];
+ uvi++;
+ }
+ }
}
if (subdiv > 1) {
@@ -530,33 +1071,11 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op)
BMO_op_finish(bm, &bmop);
}
- if (calc_uvs) {
- BMFace *f;
- BMIter fiter;
-
- /* We cannot tag faces for UVs computing above, so we have to do it now, based on all its vertices
- * being tagged. */
- BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
- bool valid = true;
- BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- if (!BMO_elem_flag_test(bm, l->v, VERT_MARK)) {
- valid = false;
- break;
- }
- }
-
- if (valid) {
- BMO_elem_flag_enable(bm, f, FACE_MARK);
- }
- }
-
- BM_mesh_calc_uvs_sphere(bm, FACE_MARK);
- }
/* must transform after because of sphere subdivision */
BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
- if (BMO_elem_flag_test(bm, v, VERT_MARK)) {
+ if (BMO_vert_flag_test(bm, v, VERT_MARK)) {
mul_m4_v3(mat, v->co);
}
}
@@ -564,7 +1083,7 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op)
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK);
}
-static void bm_mesh_calc_uvs_sphere_face(BMFace *f, float mat_rot[3][3], const int cd_loop_uv_offset)
+static void bm_mesh_calc_uvs_sphere_face(BMFace *f, const int cd_loop_uv_offset)
{
float *uvs[4];
BMLoop *l;
@@ -574,12 +1093,42 @@ static void bm_mesh_calc_uvs_sphere_face(BMFace *f, float mat_rot[3][3], const i
BLI_assert(f->len <= 4);
+ /* If face has 3 vertices, it's a polar face, in which case we need to
+ * compute a nearbye to determine its latitude. */
+ float avgx = 0.0f, avgy = 0.0f;
+ BM_ITER_ELEM_INDEX (l, &iter, f, BM_LOOPS_OF_FACE, loop_index) {
+ if (f->len == 3) {
+ avgx += l->v->co[0];
+ avgy += l->v->co[1];
+ }
+ }
+ avgx /= 3.0f;
+ avgy /= 3.0f;
+
BM_ITER_ELEM_INDEX (l, &iter, f, BM_LOOPS_OF_FACE, loop_index) {
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- float vco[3];
+ float x = l->v->co[0];
+ float y = l->v->co[1];
+ float z = l->v->co[2];
+ float len = len_v3(l->v->co);
+
+ /* Use neigboring point to compute angle for poles. */
+ float theta;
+ if (f->len == 3 && fabsf(x) < 0.0001f && fabsf(y) < 0.0001f) {
+ theta = atan2f(avgy, avgx);
+ }
+ else {
+ theta = atan2f(y, x);
+ }
+
+ /* Shift borderline coordinates to the left. */
+ if (fabsf(theta - M_PI) < 0.0001f) {
+ theta = -M_PI;
+ }
- mul_v3_m3v3(vco, mat_rot, l->v->co);
- map_to_sphere(&luv->uv[0], &luv->uv[1], vco[0], vco[1], vco[2]);
+ float phi = saacos(z / len);
+ luv->uv[0] = 0.5f + theta / ((float)M_PI * 2);
+ luv->uv[1] = 1.0f - phi / (float)M_PI;
uvs[loop_index] = luv->uv;
}
@@ -615,21 +1164,38 @@ void BM_mesh_calc_uvs_sphere(BMesh *bm, const short oflag)
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
- /* We apply a 'magic' rotationto vcos before mapping them to sphere,
- * those values seem to give best results for both ico and uv sphere projections. */
- float mat_rot[3][3];
- const float axis[3] = {0.806f, 0.329f, 0.491f};
- const float angle = DEG2RADF(120.0f);
+ BLI_assert(cd_loop_uv_offset != -1); /* caller is responsible for giving us UVs */
- axis_angle_to_mat3(mat_rot, axis, angle);
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (!BMO_face_flag_test(bm, f, oflag))
+ continue;
- BLI_assert(cd_loop_uv_offset != -1); /* caller is responsible for giving us UVs */
+ bm_mesh_calc_uvs_sphere_face(f, cd_loop_uv_offset);
+ }
+
+ BMIter iter2;
+ BMLoop* l;
+ int loop_index;
+ float minx = 1.0f;
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (!BMO_elem_flag_test(bm, f, oflag))
+ if (!BMO_face_flag_test(bm, f, oflag))
continue;
+ BM_ITER_ELEM_INDEX (l, &iter2, f, BM_LOOPS_OF_FACE, loop_index) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (luv->uv[0] < minx) {
+ minx = luv->uv[0];
+ }
+ }
+ }
- bm_mesh_calc_uvs_sphere_face(f, mat_rot, cd_loop_uv_offset);
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (!BMO_face_flag_test(bm, f, oflag))
+ continue;
+ BM_ITER_ELEM_INDEX (l, &iter2, f, BM_LOOPS_OF_FACE, loop_index) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->uv[0] -= minx;
+ }
}
}
@@ -640,6 +1206,7 @@ void bmo_create_monkey_exec(BMesh *bm, BMOperator *op)
int i;
BMO_slot_mat4_get(op->slots_in, "matrix", mat);
+ const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs");
for (i = 0; i < monkeynv; i++) {
float v[3];
@@ -650,7 +1217,7 @@ void bmo_create_monkey_exec(BMesh *bm, BMOperator *op)
v[1] = monkeyv[i][2] / -128.0;
tv[i] = BM_vert_create(bm, v, NULL, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, tv[i], VERT_MARK);
+ BMO_vert_flag_enable(bm, tv[i], VERT_MARK);
if (fabsf(v[0] = -v[0]) < 0.001f) {
tv[monkeynv + i] = tv[i];
@@ -661,25 +1228,48 @@ void bmo_create_monkey_exec(BMesh *bm, BMOperator *op)
tv[monkeynv + i] = eve;
}
- BMO_elem_flag_enable(bm, tv[monkeynv + i], VERT_MARK);
+ BMO_vert_flag_enable(bm, tv[monkeynv + i], VERT_MARK);
mul_m4_v3(mat, tv[i]->co);
}
+ int uvi = 0;
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
for (i = 0; i < monkeynf; i++) {
- BM_face_create_quad_tri(bm,
+ BMFace* temp1 = BM_face_create_quad_tri(bm,
tv[monkeyf[i][0] + i - monkeyo],
tv[monkeyf[i][1] + i - monkeyo],
tv[monkeyf[i][2] + i - monkeyo],
(monkeyf[i][3] != monkeyf[i][2]) ? tv[monkeyf[i][3] + i - monkeyo] : NULL,
NULL, BM_CREATE_NOP);
- BM_face_create_quad_tri(bm,
+ BMFace* temp2 = BM_face_create_quad_tri(bm,
tv[monkeynv + monkeyf[i][2] + i - monkeyo],
tv[monkeynv + monkeyf[i][1] + i - monkeyo],
tv[monkeynv + monkeyf[i][0] + i - monkeyo],
(monkeyf[i][3] != monkeyf[i][2]) ? tv[monkeynv + monkeyf[i][3] + i - monkeyo] : NULL,
NULL, BM_CREATE_NOP);
+
+ /* Set the UVs here, the iteration order of the faces is not guaranteed,
+ * so it's best to set the UVs right after the face is created. */
+ if(calc_uvs) {
+ BMLoop* l;
+ BMIter liter;
+ int loop_index;
+ BM_ITER_ELEM_INDEX (l, &liter, temp1, BM_LOOPS_OF_FACE, loop_index) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->uv[0] = monkeyuvs[uvi*2 + 0];
+ luv->uv[1] = monkeyuvs[uvi*2 + 1];
+ uvi++;
+ }
+ BM_ITER_ELEM_INDEX (l, &liter, temp2, BM_LOOPS_OF_FACE, loop_index) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->uv[0] = monkeyuvs[uvi*2 + 0];
+ luv->uv[1] = monkeyuvs[uvi*2 + 1];
+ uvi++;
+ }
+
+ }
}
MEM_freeN(tv);
@@ -713,7 +1303,7 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op)
mul_m4_v3(mat, vec);
cent1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, cent1, VERT_MARK);
+ BMO_vert_flag_enable(bm, cent1, VERT_MARK);
}
for (a = 0; a < segs; a++, phi += phid) {
@@ -724,7 +1314,7 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op)
mul_m4_v3(mat, vec);
v1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, v1, VERT_MARK);
+ BMO_vert_flag_enable(bm, v1, VERT_MARK);
if (lastv1)
BM_edge_create(bm, v1, lastv1, NULL, BM_CREATE_NOP);
@@ -733,7 +1323,7 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op)
BMFace *f;
f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, f, FACE_NEW);
+ BMO_face_flag_enable(bm, f, FACE_NEW);
}
if (!firstv1)
@@ -751,7 +1341,7 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op)
BMFace *f;
f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, f, FACE_NEW);
+ BMO_face_flag_enable(bm, f, FACE_NEW);
if (calc_uvs) {
BM_mesh_calc_uvs_circle(bm, mat, dia, FACE_NEW);
@@ -791,7 +1381,7 @@ void BM_mesh_calc_uvs_circle(BMesh *bm, float mat[4][4], const float radius, con
invert_m4_m4(inv_mat, mat);
BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
- if (!BMO_elem_flag_test(bm, f, oflag))
+ if (!BMO_face_flag_test(bm, f, oflag))
continue;
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
@@ -845,8 +1435,8 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
cent2 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, cent1, VERT_MARK);
- BMO_elem_flag_enable(bm, cent2, VERT_MARK);
+ BMO_vert_flag_enable(bm, cent1, VERT_MARK);
+ BMO_vert_flag_enable(bm, cent2, VERT_MARK);
}
for (a = 0; a < segs; a++, phi += phid) {
@@ -862,27 +1452,27 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
mul_m4_v3(mat, vec);
v2 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, v1, VERT_MARK);
- BMO_elem_flag_enable(bm, v2, VERT_MARK);
+ BMO_vert_flag_enable(bm, v1, VERT_MARK);
+ BMO_vert_flag_enable(bm, v2, VERT_MARK);
if (a) {
if (cap_ends) {
f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, BM_CREATE_NOP);
if (calc_uvs) {
- BMO_elem_flag_enable(bm, f, FACE_MARK);
+ BMO_face_flag_enable(bm, f, FACE_MARK);
}
- BMO_elem_flag_enable(bm, f, FACE_NEW);
+ BMO_face_flag_enable(bm, f, FACE_NEW);
f = BM_face_create_quad_tri(bm, cent2, v2, lastv2, NULL, NULL, BM_CREATE_NOP);
if (calc_uvs) {
- BMO_elem_flag_enable(bm, f, FACE_MARK);
+ BMO_face_flag_enable(bm, f, FACE_MARK);
}
- BMO_elem_flag_enable(bm, f, FACE_NEW);
+ BMO_face_flag_enable(bm, f, FACE_NEW);
}
f = BM_face_create_quad_tri(bm, lastv1, lastv2, v2, v1, NULL, BM_CREATE_NOP);
if (calc_uvs) {
- BMO_elem_flag_enable(bm, f, FACE_MARK);
+ BMO_face_flag_enable(bm, f, FACE_MARK);
}
}
else {
@@ -900,20 +1490,20 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
if (cap_ends) {
f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, BM_CREATE_NOP);
if (calc_uvs) {
- BMO_elem_flag_enable(bm, f, FACE_MARK);
+ BMO_face_flag_enable(bm, f, FACE_MARK);
}
- BMO_elem_flag_enable(bm, f, FACE_NEW);
+ BMO_face_flag_enable(bm, f, FACE_NEW);
f = BM_face_create_quad_tri(bm, cent2, firstv2, v2, NULL, NULL, BM_CREATE_NOP);
if (calc_uvs) {
- BMO_elem_flag_enable(bm, f, FACE_MARK);
+ BMO_face_flag_enable(bm, f, FACE_MARK);
}
- BMO_elem_flag_enable(bm, f, FACE_NEW);
+ BMO_face_flag_enable(bm, f, FACE_NEW);
}
f = BM_face_create_quad_tri(bm, v1, v2, firstv2, firstv1, NULL, BM_CREATE_NOP);
if (calc_uvs) {
- BMO_elem_flag_enable(bm, f, FACE_MARK);
+ BMO_face_flag_enable(bm, f, FACE_MARK);
}
if (calc_uvs) {
@@ -981,7 +1571,7 @@ void BM_mesh_calc_uvs_cone(
y = 1.0f - uv_height;
BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
- if (!BMO_elem_flag_test(bm, f, oflag))
+ if (!BMO_face_flag_test(bm, f, oflag))
continue;
if (f->len == 4 && radius_top && radius_bottom) {
@@ -1042,13 +1632,14 @@ void bmo_create_cube_exec(BMesh *bm, BMOperator *op)
float off = BMO_slot_float_get(op->slots_in, "size") / 2.0f;
const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs");
int i, x, y, z;
+ /* rotation order set to match 'BM_mesh_calc_uvs_cube' */
const char faces[6][4] = {
- {1, 3, 2, 0},
- {3, 7, 6, 2},
- {7, 5, 4, 6},
- {5, 1, 0, 4},
- {0, 2, 6, 4},
- {5, 7, 3, 1},
+ {0, 1, 3, 2},
+ {2, 3, 7, 6},
+ {6, 7, 5, 4},
+ {4, 5, 1, 0},
+ {2, 6, 4, 0},
+ {7, 3, 1, 5},
};
BMO_slot_mat4_get(op->slots_in, "matrix", mat);
@@ -1062,7 +1653,7 @@ void bmo_create_cube_exec(BMesh *bm, BMOperator *op)
float vec[3] = {(float)x * off, (float)y * off, (float)z * off};
mul_m4_v3(mat, vec);
verts[i] = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP);
- BMO_elem_flag_enable(bm, verts[i], VERT_MARK);
+ BMO_vert_flag_enable(bm, verts[i], VERT_MARK);
i++;
}
}
@@ -1079,7 +1670,7 @@ void bmo_create_cube_exec(BMesh *bm, BMOperator *op)
f = BM_face_create_verts(bm, quad, 4, NULL, BM_CREATE_NOP, true);
if (calc_uvs) {
- BMO_elem_flag_enable(bm, f, FACE_MARK);
+ BMO_face_flag_enable(bm, f, FACE_MARK);
}
}
@@ -1093,7 +1684,8 @@ void bmo_create_cube_exec(BMesh *bm, BMOperator *op)
/**
* Fills first available UVmap with cube-like UVs for all faces OpFlag-ged by given flag.
*
- * \note Expects tagged faces to be six quads...
+ * \note Expects tagged faces to be six quads.
+ * \note Caller must order faces for correct alignment.
*
* \param bm The BMesh to operate on.
* \param oflag The flag to check faces with.
@@ -1115,7 +1707,7 @@ void BM_mesh_calc_uvs_cube(BMesh *bm, const short oflag)
BLI_assert(cd_loop_uv_offset != -1); /* the caller can ensure that we have UVs */
BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
- if (!BMO_elem_flag_test(bm, f, oflag)) {
+ if (!BMO_face_flag_test(bm, f, oflag)) {
continue;
}
diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c
index a1f40b31fc7..6da591b23a0 100644
--- a/source/blender/bmesh/operators/bmo_removedoubles.c
+++ b/source/blender/bmesh/operators/bmo_removedoubles.c
@@ -98,7 +98,7 @@ static BMFace *remdoubles_createface(BMesh *bm, BMFace *f, BMOpSlot *slot_target
{
#define LOOP_MAP_VERT_INIT(l_init, v_map, is_del) \
v_map = l_init->v; \
- is_del = BMO_elem_flag_test_bool(bm, v_map, ELE_DEL); \
+ is_del = BMO_vert_flag_test_bool(bm, v_map, ELE_DEL); \
if (is_del) { \
v_map = BMO_slot_map_elem_get(slot_targetmap, v_map); \
} ((void)0)
@@ -131,12 +131,12 @@ static BMFace *remdoubles_createface(BMesh *bm, BMFace *f, BMOpSlot *slot_target
}
if (e_new) {
- if (UNLIKELY(BMO_elem_flag_test(bm, v_curr, VERT_IN_FACE))) {
+ if (UNLIKELY(BMO_vert_flag_test(bm, v_curr, VERT_IN_FACE))) {
/* we can't make the face, bail out */
STACK_CLEAR(edges);
goto finally;
}
- BMO_elem_flag_enable(bm, v_curr, VERT_IN_FACE);
+ BMO_vert_flag_enable(bm, v_curr, VERT_IN_FACE);
STACK_PUSH(edges, e_new);
STACK_PUSH(loops, l_curr);
@@ -155,7 +155,7 @@ finally:
{
unsigned int i;
for (i = 0; i < STACK_SIZE(verts); i++) {
- BMO_elem_flag_disable(bm, verts[i], VERT_IN_FACE);
+ BMO_vert_flag_disable(bm, verts[i], VERT_IN_FACE);
}
}
@@ -198,7 +198,7 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op)
/* mark merge verts for deletion */
BM_ITER_MESH (v1, &iter, bm, BM_VERTS_OF_MESH) {
if ((v2 = BMO_slot_map_elem_get(slot_targetmap, v1))) {
- BMO_elem_flag_enable(bm, v1, ELE_DEL);
+ BMO_vert_flag_enable(bm, v1, ELE_DEL);
/* merge the vertex flags, else we get randomly selected/unselected verts */
BM_elem_flag_merge(v1, v2);
@@ -212,8 +212,8 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op)
}
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- const bool is_del_v1 = BMO_elem_flag_test_bool(bm, (v1 = e->v1), ELE_DEL);
- const bool is_del_v2 = BMO_elem_flag_test_bool(bm, (v2 = e->v2), ELE_DEL);
+ const bool is_del_v1 = BMO_vert_flag_test_bool(bm, (v1 = e->v1), ELE_DEL);
+ const bool is_del_v2 = BMO_vert_flag_test_bool(bm, (v2 = e->v2), ELE_DEL);
if (is_del_v1 || is_del_v2) {
if (is_del_v1)
@@ -222,27 +222,18 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op)
v2 = BMO_slot_map_elem_get(slot_targetmap, v2);
if (v1 == v2) {
- BMO_elem_flag_enable(bm, e, EDGE_COL);
+ BMO_edge_flag_enable(bm, e, EDGE_COL);
}
- else if (!BM_edge_exists(v1, v2)) {
- BMEdge *e_new = BM_edge_create(bm, v1, v2, e, BM_CREATE_NOP);
-
- /* low level selection, not essential but means we can keep
- * edge selection valid on auto-merge for example. */
- if ((BM_elem_flag_test(e, BM_ELEM_SELECT) == true) &&
- (BM_elem_flag_test(e_new, BM_ELEM_SELECT) == false))
- {
- BM_elem_flag_disable(e, BM_ELEM_SELECT);
- BM_elem_flag_merge_into(e_new, e_new, e);
- BM_elem_flag_enable(e_new, BM_ELEM_SELECT);
- /* bm->totedgesel remains valid */
- }
- else {
- BM_elem_flag_merge_into(e_new, e_new, e);
+ else {
+ /* always merge flags, even for edges we already created */
+ BMEdge *e_new = BM_edge_exists(v1, v2);
+ if (e_new == NULL) {
+ e_new = BM_edge_create(bm, v1, v2, e, BM_CREATE_NOP);
}
+ BM_elem_flag_merge(e_new, e);
}
- BMO_elem_flag_enable(bm, e, ELE_DEL);
+ BMO_edge_flag_enable(bm, e, ELE_DEL);
}
}
@@ -253,16 +244,16 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op)
int edge_collapse = 0;
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- if (BMO_elem_flag_test(bm, l->v, ELE_DEL)) {
+ if (BMO_vert_flag_test(bm, l->v, ELE_DEL)) {
vert_delete = true;
}
- if (BMO_elem_flag_test(bm, l->e, EDGE_COL)) {
+ if (BMO_edge_flag_test(bm, l->e, EDGE_COL)) {
edge_collapse++;
}
}
if (vert_delete) {
- BMO_elem_flag_enable(bm, f, ELE_DEL);
+ BMO_face_flag_enable(bm, f, ELE_DEL);
if (f->len - edge_collapse >= 3) {
BMFace *f_new = remdoubles_createface(bm, f, slot_targetmap);
@@ -270,8 +261,12 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op)
/* do this so we don't need to return a list of created faces */
if (f_new) {
bmesh_face_swap_data(f_new, f);
- SWAP(BMFlagLayer *, f->oflags, f_new->oflags);
- BMO_elem_flag_disable(bm, f, ELE_DEL);
+
+ if (bm->use_toolflags) {
+ SWAP(BMFlagLayer *, ((BMFace_OFlag *)f)->oflags, ((BMFace_OFlag *)f_new)->oflags);
+ }
+
+ BMO_face_flag_disable(bm, f, ELE_DEL);
BM_face_kill(bm, f_new);
}
@@ -448,7 +443,7 @@ void bmo_collapse_exec(BMesh *bm, BMOperator *op)
float min[3], max[3], center[3];
BMVert *v_tar;
- if (!BMO_elem_flag_test(bm, e, EDGE_MARK))
+ if (!BMO_edge_flag_test(bm, e, EDGE_MARK))
continue;
BLI_assert(BLI_stack_is_empty(edge_stack));
@@ -519,7 +514,7 @@ static void bmo_collapsecon_do_layer(BMesh *bm, const int layer, const short ofl
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- if (BMO_elem_flag_test(bm, l->e, oflag)) {
+ if (BMO_edge_flag_test(bm, l->e, oflag)) {
/* walk */
BLI_assert(BLI_stack_is_empty(block_stack));
@@ -615,7 +610,7 @@ static void bmesh_find_doubles_common(
for (i = 0; i < verts_len; i++) {
BMVert *v_check = verts[i];
- if (BMO_elem_flag_test(bm, v_check, VERT_DOUBLE | VERT_TARGET)) {
+ if (BMO_vert_flag_test(bm, v_check, VERT_DOUBLE | VERT_TARGET)) {
continue;
}
@@ -623,7 +618,7 @@ static void bmesh_find_doubles_common(
BMVert *v_other = verts[j];
/* a match has already been found, (we could check which is best, for now don't) */
- if (BMO_elem_flag_test(bm, v_other, VERT_DOUBLE | VERT_TARGET)) {
+ if (BMO_vert_flag_test(bm, v_other, VERT_DOUBLE | VERT_TARGET)) {
continue;
}
@@ -637,19 +632,19 @@ static void bmesh_find_doubles_common(
}
if (keepvert) {
- if (BMO_elem_flag_test(bm, v_other, VERT_KEEP) == BMO_elem_flag_test(bm, v_check, VERT_KEEP))
+ if (BMO_vert_flag_test(bm, v_other, VERT_KEEP) == BMO_vert_flag_test(bm, v_check, VERT_KEEP))
continue;
}
if (compare_len_squared_v3v3(v_check->co, v_other->co, dist_sq)) {
/* If one vert is marked as keep, make sure it will be the target */
- if (BMO_elem_flag_test(bm, v_other, VERT_KEEP)) {
+ if (BMO_vert_flag_test(bm, v_other, VERT_KEEP)) {
SWAP(BMVert *, v_check, v_other);
}
- BMO_elem_flag_enable(bm, v_other, VERT_DOUBLE);
- BMO_elem_flag_enable(bm, v_check, VERT_TARGET);
+ BMO_vert_flag_enable(bm, v_other, VERT_DOUBLE);
+ BMO_vert_flag_enable(bm, v_check, VERT_TARGET);
BMO_slot_map_elem_insert(optarget, optarget_slot, v_other, v_check);
}
@@ -692,8 +687,8 @@ void bmo_automerge_exec(BMesh *bm, BMOperator *op)
* as VERT_KEEP. */
BMO_slot_buffer_flag_enable(bm, op->slots_in, "verts", BM_VERT, VERT_IN);
BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
- if (!BMO_elem_flag_test(bm, v, VERT_IN)) {
- BMO_elem_flag_enable(bm, v, VERT_KEEP);
+ if (!BMO_vert_flag_test(bm, v, VERT_IN)) {
+ BMO_vert_flag_enable(bm, v, VERT_KEEP);
}
}
diff --git a/source/blender/bmesh/operators/bmo_similar.c b/source/blender/bmesh/operators/bmo_similar.c
index 708d57a7a08..454d6d8c6c8 100644
--- a/source/blender/bmesh/operators/bmo_similar.c
+++ b/source/blender/bmesh/operators/bmo_similar.c
@@ -121,8 +121,8 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op)
* and n is the total number of faces
*/
BMO_ITER (fs, &fs_iter, op->slots_in, "faces", BM_FACE) {
- if (!BMO_elem_flag_test(bm, fs, FACE_MARK)) { /* is this really needed ? */
- BMO_elem_flag_enable(bm, fs, FACE_MARK);
+ if (!BMO_face_flag_test(bm, fs, FACE_MARK)) { /* is this really needed ? */
+ BMO_face_flag_enable(bm, fs, FACE_MARK);
num_sels++;
}
}
@@ -134,7 +134,7 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op)
/* loop through all the faces and fill the faces/indices structure */
BM_ITER_MESH (fm, &fm_iter, bm, BM_FACES_OF_MESH) {
f_ext[i].f = fm;
- if (BMO_elem_flag_test(bm, fm, FACE_MARK)) {
+ if (BMO_face_flag_test(bm, fm, FACE_MARK)) {
indices[idx] = i;
idx++;
}
@@ -179,21 +179,21 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op)
/* now select the rest (if any) */
for (i = 0; i < num_total; i++) {
fm = f_ext[i].f;
- if (!BMO_elem_flag_test(bm, fm, FACE_MARK) && !BM_elem_flag_test(fm, BM_ELEM_HIDDEN)) {
+ if (!BMO_face_flag_test(bm, fm, FACE_MARK) && !BM_elem_flag_test(fm, BM_ELEM_HIDDEN)) {
bool cont = true;
for (idx = 0; idx < num_sels && cont == true; idx++) {
fs = f_ext[indices[idx]].f;
switch (type) {
case SIMFACE_MATERIAL:
if (fm->mat_nr == fs->mat_nr) {
- BMO_elem_flag_enable(bm, fm, FACE_MARK);
+ BMO_face_flag_enable(bm, fm, FACE_MARK);
cont = false;
}
break;
case SIMFACE_IMAGE:
if (f_ext[i].t == f_ext[indices[idx]].t) {
- BMO_elem_flag_enable(bm, fm, FACE_MARK);
+ BMO_face_flag_enable(bm, fm, FACE_MARK);
cont = false;
}
break;
@@ -201,7 +201,7 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op)
case SIMFACE_NORMAL:
angle = angle_normalized_v3v3(fs->no, fm->no); /* if the angle between the normals -> 0 */
if (angle <= thresh_radians) {
- BMO_elem_flag_enable(bm, fm, FACE_MARK);
+ BMO_face_flag_enable(bm, fm, FACE_MARK);
cont = false;
}
break;
@@ -218,7 +218,7 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op)
if (angle <= thresh_radians) { /* and dot product difference -> 0 */
delta_fl = f_ext[i].d - (f_ext[indices[idx]].d * sign);
if (bm_sel_similar_cmp_fl(delta_fl, thresh, compare)) {
- BMO_elem_flag_enable(bm, fm, FACE_MARK);
+ BMO_face_flag_enable(bm, fm, FACE_MARK);
cont = false;
}
}
@@ -227,7 +227,7 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op)
case SIMFACE_AREA:
delta_fl = f_ext[i].area - f_ext[indices[idx]].area;
if (bm_sel_similar_cmp_fl(delta_fl, thresh, compare)) {
- BMO_elem_flag_enable(bm, fm, FACE_MARK);
+ BMO_face_flag_enable(bm, fm, FACE_MARK);
cont = false;
}
break;
@@ -235,7 +235,7 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op)
case SIMFACE_SIDES:
delta_i = fm->len - fs->len;
if (bm_sel_similar_cmp_i(delta_i, compare)) {
- BMO_elem_flag_enable(bm, fm, FACE_MARK);
+ BMO_face_flag_enable(bm, fm, FACE_MARK);
cont = false;
}
break;
@@ -243,14 +243,14 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op)
case SIMFACE_PERIMETER:
delta_fl = f_ext[i].perim - f_ext[indices[idx]].perim;
if (bm_sel_similar_cmp_fl(delta_fl, thresh, compare)) {
- BMO_elem_flag_enable(bm, fm, FACE_MARK);
+ BMO_face_flag_enable(bm, fm, FACE_MARK);
cont = false;
}
break;
case SIMFACE_SMOOTH:
if (BM_elem_flag_test(fm, BM_ELEM_SMOOTH) == BM_elem_flag_test(fs, BM_ELEM_SMOOTH)) {
- BMO_elem_flag_enable(bm, fm, FACE_MARK);
+ BMO_face_flag_enable(bm, fm, FACE_MARK);
cont = false;
}
break;
@@ -263,7 +263,7 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op)
ffa2 = CustomData_bmesh_get(&bm->pdata, fm->head.data, CD_FREESTYLE_FACE);
if (ffa1 && ffa2 && (ffa1->flag & FREESTYLE_FACE_MARK) == (ffa2->flag & FREESTYLE_FACE_MARK)) {
- BMO_elem_flag_enable(bm, fm, FACE_MARK);
+ BMO_face_flag_enable(bm, fm, FACE_MARK);
cont = false;
}
}
@@ -350,7 +350,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op)
/* iterate through all selected edges and mark them */
BMO_ITER (es, &es_iter, op->slots_in, "edges", BM_EDGE) {
- BMO_elem_flag_enable(bm, es, EDGE_MARK);
+ BMO_edge_flag_enable(bm, es, EDGE_MARK);
num_sels++;
}
@@ -361,7 +361,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op)
/* loop through all the edges and fill the edges/indices structure */
BM_ITER_MESH (e, &e_iter, bm, BM_EDGES_OF_MESH) {
e_ext[i].e = e;
- if (BMO_elem_flag_test(bm, e, EDGE_MARK)) {
+ if (BMO_edge_flag_test(bm, e, EDGE_MARK)) {
indices[idx] = i;
idx++;
}
@@ -397,7 +397,9 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op)
/* select the edges if any */
for (i = 0; i < num_total; i++) {
e = e_ext[i].e;
- if (!BMO_elem_flag_test(bm, e, EDGE_MARK) && !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
+ if (!BMO_edge_flag_test(bm, e, EDGE_MARK) &&
+ !BM_elem_flag_test(e, BM_ELEM_HIDDEN))
+ {
bool cont = true;
for (idx = 0; idx < num_sels && cont == true; idx++) {
es = e_ext[indices[idx]].e;
@@ -405,7 +407,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op)
case SIMEDGE_LENGTH:
delta_fl = e_ext[i].length - e_ext[indices[idx]].length;
if (bm_sel_similar_cmp_fl(delta_fl, thresh, compare)) {
- BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ BMO_edge_flag_enable(bm, e, EDGE_MARK);
cont = false;
}
break;
@@ -418,7 +420,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op)
angle = fabsf(angle - (float)M_PI);
if (angle / (float)M_PI_2 <= thresh) {
- BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ BMO_edge_flag_enable(bm, e, EDGE_MARK);
cont = false;
}
break;
@@ -426,7 +428,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op)
case SIMEDGE_FACE:
delta_i = e_ext[i].faces - e_ext[indices[idx]].faces;
if (bm_sel_similar_cmp_i(delta_i, compare)) {
- BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ BMO_edge_flag_enable(bm, e, EDGE_MARK);
cont = false;
}
break;
@@ -435,7 +437,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op)
if (e_ext[i].faces == 2) {
if (e_ext[indices[idx]].faces == 2) {
if (fabsf(e_ext[i].angle - e_ext[indices[idx]].angle) <= thresh) {
- BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ BMO_edge_flag_enable(bm, e, EDGE_MARK);
cont = false;
}
}
@@ -454,7 +456,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op)
delta_fl = *c1 - *c2;
if (bm_sel_similar_cmp_fl(delta_fl, thresh, compare)) {
- BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ BMO_edge_flag_enable(bm, e, EDGE_MARK);
cont = false;
}
}
@@ -469,7 +471,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op)
delta_fl = *c1 - *c2;
if (bm_sel_similar_cmp_fl(delta_fl, thresh, compare)) {
- BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ BMO_edge_flag_enable(bm, e, EDGE_MARK);
cont = false;
}
}
@@ -477,14 +479,14 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op)
case SIMEDGE_SEAM:
if (BM_elem_flag_test(e, BM_ELEM_SEAM) == BM_elem_flag_test(es, BM_ELEM_SEAM)) {
- BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ BMO_edge_flag_enable(bm, e, EDGE_MARK);
cont = false;
}
break;
case SIMEDGE_SHARP:
if (BM_elem_flag_test(e, BM_ELEM_SMOOTH) == BM_elem_flag_test(es, BM_ELEM_SMOOTH)) {
- BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ BMO_edge_flag_enable(bm, e, EDGE_MARK);
cont = false;
}
break;
@@ -497,7 +499,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op)
fed2 = CustomData_bmesh_get(&bm->edata, es->head.data, CD_FREESTYLE_EDGE);
if (fed1 && fed2 && (fed1->flag & FREESTYLE_EDGE_MARK) == (fed2->flag & FREESTYLE_EDGE_MARK)) {
- BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ BMO_edge_flag_enable(bm, e, EDGE_MARK);
cont = false;
}
}
@@ -562,7 +564,7 @@ void bmo_similar_verts_exec(BMesh *bm, BMOperator *op)
/* iterate through all selected edges and mark them */
BMO_ITER (vs, &vs_iter, op->slots_in, "verts", BM_VERT) {
- BMO_elem_flag_enable(bm, vs, VERT_MARK);
+ BMO_vert_flag_enable(bm, vs, VERT_MARK);
num_sels++;
}
@@ -573,7 +575,7 @@ void bmo_similar_verts_exec(BMesh *bm, BMOperator *op)
/* loop through all the vertices and fill the vertices/indices structure */
BM_ITER_MESH (v, &v_iter, bm, BM_VERTS_OF_MESH) {
v_ext[i].v = v;
- if (BMO_elem_flag_test(bm, v, VERT_MARK)) {
+ if (BMO_vert_flag_test(bm, v, VERT_MARK)) {
indices[idx] = i;
idx++;
}
@@ -599,7 +601,9 @@ void bmo_similar_verts_exec(BMesh *bm, BMOperator *op)
/* select the vertices if any */
for (i = 0; i < num_total; i++) {
v = v_ext[i].v;
- if (!BMO_elem_flag_test(bm, v, VERT_MARK) && !BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
+ if (!BMO_vert_flag_test(bm, v, VERT_MARK) &&
+ !BM_elem_flag_test(v, BM_ELEM_HIDDEN))
+ {
bool cont = true;
for (idx = 0; idx < num_sels && cont == true; idx++) {
vs = v_ext[indices[idx]].v;
@@ -607,7 +611,7 @@ void bmo_similar_verts_exec(BMesh *bm, BMOperator *op)
case SIMVERT_NORMAL:
/* compare the angle between the normals */
if (angle_normalized_v3v3(v->no, vs->no) <= thresh_radians) {
- BMO_elem_flag_enable(bm, v, VERT_MARK);
+ BMO_vert_flag_enable(bm, v, VERT_MARK);
cont = false;
}
break;
@@ -615,7 +619,7 @@ void bmo_similar_verts_exec(BMesh *bm, BMOperator *op)
/* number of adjacent faces */
delta_i = v_ext[i].num_faces - v_ext[indices[idx]].num_faces;
if (bm_sel_similar_cmp_i(delta_i, compare)) {
- BMO_elem_flag_enable(bm, v, VERT_MARK);
+ BMO_vert_flag_enable(bm, v, VERT_MARK);
cont = false;
}
break;
@@ -623,7 +627,7 @@ void bmo_similar_verts_exec(BMesh *bm, BMOperator *op)
case SIMVERT_VGROUP:
if (v_ext[i].dvert != NULL && v_ext[indices[idx]].dvert != NULL) {
if (defvert_find_shared(v_ext[i].dvert, v_ext[indices[idx]].dvert) != -1) {
- BMO_elem_flag_enable(bm, v, VERT_MARK);
+ BMO_vert_flag_enable(bm, v, VERT_MARK);
cont = false;
}
}
@@ -632,7 +636,7 @@ void bmo_similar_verts_exec(BMesh *bm, BMOperator *op)
/* number of adjacent edges */
delta_i = v_ext[i].num_edges - v_ext[indices[idx]].num_edges;
if (bm_sel_similar_cmp_i(delta_i, compare)) {
- BMO_elem_flag_enable(bm, v, VERT_MARK);
+ BMO_vert_flag_enable(bm, v, VERT_MARK);
cont = false;
}
break;
diff --git a/source/blender/bmesh/operators/bmo_subdivide.c b/source/blender/bmesh/operators/bmo_subdivide.c
index 38fa2cfdcc8..894129b4a33 100644
--- a/source/blender/bmesh/operators/bmo_subdivide.c
+++ b/source/blender/bmesh/operators/bmo_subdivide.c
@@ -254,8 +254,7 @@ static void alter_co(
copy_v3_v3(co, v->co);
if (UNLIKELY(params->use_sphere)) { /* subdivide sphere */
- normalize_v3(co);
- mul_v3_fl(co, params->smooth);
+ normalize_v3_length(co, params->smooth);
}
else if (params->use_smooth) {
/* calculating twice and blending gives smoother results,
@@ -384,7 +383,7 @@ static BMVert *bm_subdivide_edge_addvert(
v_new = BM_edge_split(bm, edge, edge->v1, r_edge, factor_edge_split);
- BMO_elem_flag_enable(bm, v_new, ELE_INNER);
+ BMO_vert_flag_enable(bm, v_new, ELE_INNER);
/* offset for smooth or sphere or fractal */
alter_co(v_new, e_orig, params, factor_subd, v_a, v_b);
@@ -419,7 +418,7 @@ static BMVert *subdivide_edge_num(
BMVert *v_new;
float factor_edge_split, factor_subd;
- if (BMO_elem_flag_test(bm, edge, EDGE_PERCENT) && totpoint == 1) {
+ if (BMO_edge_flag_test(bm, edge, EDGE_PERCENT) && totpoint == 1) {
factor_edge_split = BMO_slot_map_float_get(params->slot_edge_percents, edge);
factor_subd = 0.0f;
}
@@ -449,9 +448,9 @@ static void bm_subdivide_multicut(
for (i = 0; i < numcuts; i++) {
v = subdivide_edge_num(bm, eed, &e_tmp, i, params->numcuts, params, v_a, v_b, &e_new);
- BMO_elem_flag_enable(bm, v, SUBD_SPLIT | ELE_SPLIT);
- BMO_elem_flag_enable(bm, eed, SUBD_SPLIT | ELE_SPLIT);
- BMO_elem_flag_enable(bm, e_new, SUBD_SPLIT | ELE_SPLIT);
+ BMO_vert_flag_enable(bm, v, SUBD_SPLIT | ELE_SPLIT);
+ BMO_edge_flag_enable(bm, eed, SUBD_SPLIT | ELE_SPLIT);
+ BMO_edge_flag_enable(bm, e_new, SUBD_SPLIT | ELE_SPLIT);
BM_CHECK_ELEMENT(v);
if (v->e) BM_CHECK_ELEMENT(v->e);
@@ -698,8 +697,8 @@ static void quad_4edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts
if (!e)
continue;
- BMO_elem_flag_enable(bm, e, ELE_INNER);
- BMO_elem_flag_enable(bm, f_new, ELE_INNER);
+ BMO_edge_flag_enable(bm, e, ELE_INNER);
+ BMO_face_flag_enable(bm, f_new, ELE_INNER);
v1 = lines[(i + 1) * s] = verts[a];
@@ -711,7 +710,7 @@ static void quad_4edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts
BMESH_ASSERT(v != NULL);
- BMO_elem_flag_enable(bm, e_new, ELE_INNER);
+ BMO_edge_flag_enable(bm, e_new, ELE_INNER);
lines[(i + 1) * s + a + 1] = v;
}
}
@@ -724,8 +723,8 @@ static void quad_4edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts
if (!e)
continue;
- BMO_elem_flag_enable(bm, e, ELE_INNER);
- BMO_elem_flag_enable(bm, f_new, ELE_INNER);
+ BMO_edge_flag_enable(bm, e, ELE_INNER);
+ BMO_face_flag_enable(bm, f_new, ELE_INNER);
}
}
@@ -802,8 +801,8 @@ static void tri_3edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts,
e = connect_smallest_face(bm, verts[a], verts[b], &f_new);
if (!e) goto cleanup;
- BMO_elem_flag_enable(bm, e, ELE_INNER);
- BMO_elem_flag_enable(bm, f_new, ELE_INNER);
+ BMO_edge_flag_enable(bm, e, ELE_INNER);
+ BMO_face_flag_enable(bm, f_new, ELE_INNER);
lines[i + 1][0] = verts[a];
lines[i + 1][i + 1] = verts[b];
@@ -817,7 +816,7 @@ static void tri_3edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts,
v = subdivide_edge_num(bm, e, &e_tmp, j, i, params, verts[a], verts[b], &e_new);
lines[i + 1][j + 1] = v;
- BMO_elem_flag_enable(bm, e_new, ELE_INNER);
+ BMO_edge_flag_enable(bm, e_new, ELE_INNER);
}
}
@@ -837,13 +836,13 @@ static void tri_3edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts,
for (j = 0; j < i; j++) {
e = connect_smallest_face(bm, lines[i][j], lines[i + 1][j + 1], &f_new);
- BMO_elem_flag_enable(bm, e, ELE_INNER);
- BMO_elem_flag_enable(bm, f_new, ELE_INNER);
+ BMO_edge_flag_enable(bm, e, ELE_INNER);
+ BMO_face_flag_enable(bm, f_new, ELE_INNER);
e = connect_smallest_face(bm, lines[i][j + 1], lines[i + 1][j + 1], &f_new);
- BMO_elem_flag_enable(bm, e, ELE_INNER);
- BMO_elem_flag_enable(bm, f_new, ELE_INNER);
+ BMO_edge_flag_enable(bm, e, ELE_INNER);
+ BMO_face_flag_enable(bm, f_new, ELE_INNER);
}
}
@@ -1023,7 +1022,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
edges[i] = l_new->e;
verts[i] = l_new->v;
- if (BMO_elem_flag_test(bm, edges[i], SUBD_SPLIT)) {
+ if (BMO_edge_flag_test(bm, edges[i], SUBD_SPLIT)) {
if (!e1) e1 = edges[i];
else e2 = edges[i];
@@ -1043,13 +1042,13 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
}
}
- if (BMO_elem_flag_test(bm, face, FACE_CUSTOMFILL)) {
+ if (BMO_face_flag_test(bm, face, FACE_CUSTOMFILL)) {
pat = *BMO_slot_map_data_get(params.slot_custom_patterns, face);
for (i = 0; i < pat->len; i++) {
matched = 1;
for (j = 0; j < pat->len; j++) {
a = (j + i) % pat->len;
- if ((!!BMO_elem_flag_test(bm, edges[a], SUBD_SPLIT)) != (!!pat->seledges[j])) {
+ if ((!!BMO_edge_flag_test(bm, edges[a], SUBD_SPLIT)) != (!!pat->seledges[j])) {
matched = 0;
break;
}
@@ -1062,7 +1061,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
fd->start = verts[i];
fd->face = face;
fd->totedgesel = totesel;
- BMO_elem_flag_enable(bm, face, SUBD_SPLIT);
+ BMO_face_flag_enable(bm, face, SUBD_SPLIT);
break;
}
}
@@ -1082,7 +1081,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
matched = 1;
for (b = 0; b < pat->len; b++) {
j = (b + a) % pat->len;
- if ((!!BMO_elem_flag_test(bm, edges[j], SUBD_SPLIT)) != (!!pat->seledges[b])) {
+ if ((!!BMO_edge_flag_test(bm, edges[j], SUBD_SPLIT)) != (!!pat->seledges[b])) {
matched = 0;
break;
}
@@ -1094,7 +1093,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
if (matched) {
SubDFaceData *fd;
- BMO_elem_flag_enable(bm, face, SUBD_SPLIT);
+ BMO_face_flag_enable(bm, face, SUBD_SPLIT);
fd = BLI_stack_push_r(facedata);
fd->pat = pat;
@@ -1110,7 +1109,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
if (!matched && totesel) {
SubDFaceData *fd;
- BMO_elem_flag_enable(bm, face, SUBD_SPLIT);
+ BMO_face_flag_enable(bm, face, SUBD_SPLIT);
/* must initialize all members here */
fd = BLI_stack_push_r(facedata);
@@ -1162,22 +1161,22 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
/* find the boundary of one of the split edges */
for (a = 1; a < vlen; a++) {
- if (!BMO_elem_flag_test(bm, loops[a - 1]->v, ELE_INNER) &&
- BMO_elem_flag_test(bm, loops[a]->v, ELE_INNER))
+ if (!BMO_vert_flag_test(bm, loops[a - 1]->v, ELE_INNER) &&
+ BMO_vert_flag_test(bm, loops[a]->v, ELE_INNER))
{
break;
}
}
- if (BMO_elem_flag_test(bm, loops[(a + numcuts + 1) % vlen]->v, ELE_INNER)) {
+ if (BMO_vert_flag_test(bm, loops[(a + numcuts + 1) % vlen]->v, ELE_INNER)) {
b = (a + numcuts + 1) % vlen;
}
else {
/* find the boundary of the other edge. */
for (j = 0; j < vlen; j++) {
b = (j + a + numcuts + 1) % vlen;
- if (!BMO_elem_flag_test(bm, loops[b == 0 ? vlen - 1 : b - 1]->v, ELE_INNER) &&
- BMO_elem_flag_test(bm, loops[b]->v, ELE_INNER))
+ if (!BMO_vert_flag_test(bm, loops[b == 0 ? vlen - 1 : b - 1]->v, ELE_INNER) &&
+ BMO_vert_flag_test(bm, loops[b]->v, ELE_INNER))
{
break;
}
@@ -1245,7 +1244,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
BLI_assert(BM_edge_exists(loops_split[j][0]->v, loops_split[j][1]->v) == NULL);
f_new = BM_face_split(bm, face, loops_split[j][0], loops_split[j][1], &l_new, NULL, false);
if (f_new) {
- BMO_elem_flag_enable(bm, l_new->e, ELE_INNER);
+ BMO_edge_flag_enable(bm, l_new->e, ELE_INNER);
}
}
}
diff --git a/source/blender/bmesh/operators/bmo_subdivide_edgering.c b/source/blender/bmesh/operators/bmo_subdivide_edgering.c
index b5a95ad6283..ce031e1c230 100644
--- a/source/blender/bmesh/operators/bmo_subdivide_edgering.c
+++ b/source/blender/bmesh/operators/bmo_subdivide_edgering.c
@@ -128,7 +128,7 @@ static void bmo_edgeloop_vert_tag(BMesh *bm, struct BMEdgeLoopStore *el_store, c
{
LinkData *node = BM_edgeloop_verts_get(el_store)->first;
do {
- BMO_elem_flag_set(bm, (BMVert *)node->data, oflag, tag);
+ BMO_vert_flag_set(bm, (BMVert *)node->data, oflag, tag);
} while ((node = node->next));
}
@@ -137,7 +137,7 @@ static bool bmo_face_is_vert_tag_all(BMesh *bm, BMFace *f, short oflag)
BMLoop *l_iter, *l_first;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
- if (!BMO_elem_flag_test(bm, l_iter->v, oflag)) {
+ if (!BMO_vert_flag_test(bm, l_iter->v, oflag)) {
return false;
}
} while ((l_iter = l_iter->next) != l_first);
@@ -150,7 +150,7 @@ static bool bm_vert_is_tag_edge_connect(BMesh *bm, BMVert *v)
BMEdge *e;
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- if (BMO_elem_flag_test(bm, e, EDGE_RING)) {
+ if (BMO_edge_flag_test(bm, e, EDGE_RING)) {
BMVert *v_other = BM_edge_other_vert(e, v);
if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
return true;
@@ -243,7 +243,7 @@ static GSet *bm_edgering_pair_calc(BMesh *bm, ListBase *eloops_rim)
BMVert *v = ((LinkData *)BM_edgeloop_verts_get(el_store)->first)->data;
BM_ITER_ELEM (e, &eiter, (BMVert *)v, BM_EDGES_OF_VERT) {
- if (BMO_elem_flag_test(bm, e, EDGE_RING)) {
+ if (BMO_edge_flag_test(bm, e, EDGE_RING)) {
struct BMEdgeLoopStore *el_store_other;
BMVert *v_other = BM_edge_other_vert(e, v);
GHashPair pair_test;
@@ -339,7 +339,7 @@ static void bm_vert_calc_surface_tangent(BMesh *bm, BMVert *v, float r_no[3])
if (UNLIKELY(BM_edge_is_wire(e))) {
/* pass - this may confuse things */
}
- else if (BMO_elem_flag_test(bm, e, EDGE_RIM)) {
+ else if (BMO_edge_flag_test(bm, e, EDGE_RIM)) {
BMIter liter;
BMLoop *l;
BM_ITER_ELEM (l, &liter, e, BM_LOOPS_OF_EDGE) {
@@ -347,7 +347,7 @@ static void bm_vert_calc_surface_tangent(BMesh *bm, BMVert *v, float r_no[3])
float no[3];
// BM_face_normal_update(l->f);
BM_edge_calc_face_tangent(e, l, no);
- if (BMO_elem_flag_test(bm, l->f, FACE_SHARED)) {
+ if (BMO_face_flag_test(bm, l->f, FACE_SHARED)) {
add_v3_v3(no_inner, no);
found_inner = true;
}
@@ -356,7 +356,7 @@ static void bm_vert_calc_surface_tangent(BMesh *bm, BMVert *v, float r_no[3])
found_outer = true;
/* other side is used too, blend midway */
- if (BMO_elem_flag_test(bm, l->f, FACE_OUT)) {
+ if (BMO_face_flag_test(bm, l->f, FACE_OUT)) {
found_outer_tag = true;
}
}
@@ -400,9 +400,9 @@ static void bm_faces_share_tag_flush(BMesh *bm, BMEdge **e_arr, const unsigned i
l_iter = l_first = e->l;
do {
- if (!BMO_elem_flag_test(bm, l_iter->f, FACE_SHARED)) {
+ if (!BMO_face_flag_test(bm, l_iter->f, FACE_SHARED)) {
if (bmo_face_is_vert_tag_all(bm, l_iter->f, VERT_SHARED)) {
- BMO_elem_flag_enable(bm, l_iter->f, FACE_SHARED);
+ BMO_face_flag_enable(bm, l_iter->f, FACE_SHARED);
}
}
} while ((l_iter = l_iter->radial_next) != l_first);
@@ -422,7 +422,7 @@ static void bm_faces_share_tag_clear(BMesh *bm, BMEdge **e_arr_iter, const unsig
l_iter = l_first = e->l;
do {
- BMO_elem_flag_disable(bm, l_iter->f, FACE_SHARED);
+ BMO_face_flag_disable(bm, l_iter->f, FACE_SHARED);
} while ((l_iter = l_iter->radial_next) != l_first);
}
}
@@ -834,8 +834,8 @@ static void bm_face_slice(BMesh *bm, BMLoop *l, const int cuts)
if (l_new->f->len < l_new->radial_next->f->len) {
l_new = l_new->radial_next;
}
- BMO_elem_flag_enable(bm, l_new->f, FACE_OUT);
- BMO_elem_flag_enable(bm, l_new->radial_next->f, FACE_OUT);
+ BMO_face_flag_enable(bm, l_new->f, FACE_OUT);
+ BMO_face_flag_enable(bm, l_new->radial_next->f, FACE_OUT);
}
}
@@ -903,7 +903,7 @@ static void bm_edgering_pair_order(
node = lb_a->first;
BM_ITER_ELEM (e, &eiter, (BMVert *)node->data, BM_EDGES_OF_VERT) {
- if (BMO_elem_flag_test(bm, e, EDGE_RING)) {
+ if (BMO_edge_flag_test(bm, e, EDGE_RING)) {
v_other = BM_edge_other_vert(e, (BMVert *)node->data);
if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
break;
@@ -938,7 +938,7 @@ static void bm_edgering_pair_order(
/* if we dont share and edge - flip */
BMEdge *e = BM_edge_exists(((LinkData *)lb_a->first)->data,
((LinkData *)lb_b->first)->data);
- if (e == NULL || !BMO_elem_flag_test(bm, e, EDGE_RING)) {
+ if (e == NULL || !BMO_edge_flag_test(bm, e, EDGE_RING)) {
BM_edgeloop_flip(bm, el_store_b);
}
}
@@ -983,19 +983,19 @@ static void bm_edgering_pair_subdiv(
BMIter eiter;
BM_ITER_ELEM (e, &eiter, (BMVert *)node->data, BM_EDGES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, e, EDGE_IN_STACK)) {
+ if (!BMO_edge_flag_test(bm, e, EDGE_IN_STACK)) {
BMVert *v_other = BM_edge_other_vert(e, (BMVert *)node->data);
if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
BMIter fiter;
- BMO_elem_flag_enable(bm, e, EDGE_IN_STACK);
+ BMO_edge_flag_enable(bm, e, EDGE_IN_STACK);
STACK_PUSH(edges_ring_arr, e);
/* add faces to the stack */
BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
- if (BMO_elem_flag_test(bm, f, FACE_OUT)) {
- if (!BMO_elem_flag_test(bm, f, FACE_IN_STACK)) {
- BMO_elem_flag_enable(bm, f, FACE_IN_STACK);
+ if (BMO_face_flag_test(bm, f, FACE_OUT)) {
+ if (!BMO_face_flag_test(bm, f, FACE_IN_STACK)) {
+ BMO_face_flag_enable(bm, f, FACE_IN_STACK);
STACK_PUSH(faces_ring_arr, f);
}
}
@@ -1009,10 +1009,10 @@ static void bm_edgering_pair_subdiv(
/* found opposite edge */
BMVert *v_other;
- BMO_elem_flag_disable(bm, e, EDGE_IN_STACK);
+ BMO_edge_flag_disable(bm, e, EDGE_IN_STACK);
/* unrelated to subdiv, but if we _don't_ clear flag, multiple rings fail */
- BMO_elem_flag_disable(bm, e, EDGE_RING);
+ BMO_edge_flag_disable(bm, e, EDGE_RING);
v_other = BM_elem_flag_test(e->v1, BM_ELEM_TAG) ? e->v1 : e->v2;
bm_edge_subdiv_as_loop(bm, eloops_ring, e, v_other, cuts);
@@ -1021,12 +1021,12 @@ static void bm_edgering_pair_subdiv(
while ((f = STACK_POP(faces_ring_arr))) {
BMLoop *l_iter, *l_first;
- BMO_elem_flag_disable(bm, f, FACE_IN_STACK);
+ BMO_face_flag_disable(bm, f, FACE_IN_STACK);
/* Check each edge of the face */
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
- if (BMO_elem_flag_test(bm, l_iter->e, EDGE_RIM)) {
+ if (BMO_edge_flag_test(bm, l_iter->e, EDGE_RIM)) {
bm_face_slice(bm, l_iter, cuts);
break;
}
@@ -1064,7 +1064,7 @@ static void bm_edgering_pair_ringsubd(
static bool bm_edge_rim_test_cb(BMEdge *e, void *bm_v)
{
BMesh *bm = bm_v;
- return BMO_elem_flag_test_bool(bm, e, EDGE_RIM);
+ return BMO_edge_flag_test_bool(bm, e, EDGE_RIM);
}
@@ -1099,25 +1099,26 @@ void bmo_subdivide_edgering_exec(BMesh *bm, BMOperator *op)
BMFace *f;
BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
- if (!BMO_elem_flag_test(bm, f, FACE_OUT)) {
+ /* could support ngons, other areas would need updating too, see T48926. */
+ if ((f->len <= 4) && !BMO_face_flag_test(bm, f, FACE_OUT)) {
BMIter liter;
BMLoop *l;
bool ok = false;
/* check at least 2 edges in the face are rings */
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- if (BMO_elem_flag_test(bm, l->e, EDGE_RING) && e != l->e) {
+ if (BMO_edge_flag_test(bm, l->e, EDGE_RING) && e != l->e) {
ok = true;
break;
}
}
if (ok) {
- BMO_elem_flag_enable(bm, f, FACE_OUT);
+ BMO_face_flag_enable(bm, f, FACE_OUT);
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- if (!BMO_elem_flag_test(bm, l->e, EDGE_RING)) {
- BMO_elem_flag_enable(bm, l->e, EDGE_RIM);
+ if (!BMO_edge_flag_test(bm, l->e, EDGE_RING)) {
+ BMO_edge_flag_enable(bm, l->e, EDGE_RIM);
}
}
}
diff --git a/source/blender/bmesh/operators/bmo_triangulate.c b/source/blender/bmesh/operators/bmo_triangulate.c
index 6fb09c76ea4..8938d086c1a 100644
--- a/source/blender/bmesh/operators/bmo_triangulate.c
+++ b/source/blender/bmesh/operators/bmo_triangulate.c
@@ -91,7 +91,7 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op)
BMVert **e_verts = &e->v1;
unsigned int i;
- BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ BMO_edge_flag_enable(bm, e, EDGE_MARK);
calc_winding = (calc_winding || BM_edge_is_boundary(e));
@@ -132,7 +132,7 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op)
add_v3_v3(normal, v->no);
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- if (BMO_elem_flag_test(bm, e, EDGE_MARK)) {
+ if (BMO_edge_flag_test(bm, e, EDGE_MARK)) {
if (e_index == 2) {
e_index = 0;
break;
@@ -203,7 +203,7 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op)
for (i = 0, i_prev = 2; i < 3; i_prev = i++) {
e = BM_edge_exists(v_tri[i], v_tri[i_prev]);
- if (e && BM_edge_is_boundary(e) && BMO_elem_flag_test(bm, e, EDGE_MARK)) {
+ if (e && BM_edge_is_boundary(e) && BMO_edge_flag_test(bm, e, EDGE_MARK)) {
winding_votes += (e->l->v == v_tri[i]) ? 1 : -1;
}
}
@@ -226,10 +226,10 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op)
sf_tri->v1->tmp.p, sf_tri->v2->tmp.p, sf_tri->v3->tmp.p, NULL,
NULL, BM_CREATE_NO_DOUBLE);
- BMO_elem_flag_enable(bm, f, ELE_NEW);
+ BMO_face_flag_enable(bm, f, ELE_NEW);
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- if (!BMO_elem_flag_test(bm, l->e, EDGE_MARK)) {
- BMO_elem_flag_enable(bm, l->e, ELE_NEW);
+ if (!BMO_edge_flag_test(bm, l->e, EDGE_MARK)) {
+ BMO_edge_flag_enable(bm, l->e, ELE_NEW);
}
}
}
@@ -244,29 +244,33 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op)
BMO_slot_buffer_flag_enable(bm, bmop.slots_out, "geom.out", BM_FACE | BM_EDGE, ELE_NEW);
BMO_op_finish(bm, &bmop);
}
-
- BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_EDGE | BM_FACE, ELE_NEW);
if (use_dissolve) {
- BMO_ITER (e, &siter, op->slots_out, "geom.out", BM_EDGE) {
- if (LIKELY(e->l)) { /* in rare cases the edges face will have already been removed from the edge */
- BMFace *f_new;
- f_new = BM_faces_join_pair(bm, e->l->f,
- e->l->radial_next->f, e,
- false); /* join faces */
- if (f_new) {
- BMO_elem_flag_enable(bm, f_new, ELE_NEW);
- BM_edge_kill(bm, e);
+ BMEdge *e_next;
+ BMIter iter;
+
+ BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BMO_edge_flag_test(bm, e, ELE_NEW)) {
+ /* in rare cases the edges face will have already been removed from the edge */
+ if (LIKELY(e->l)) {
+ BMFace *f_new = BM_faces_join_pair(
+ bm, e->l->f,
+ e->l->radial_next->f, e,
+ false); /* join faces */
+ if (f_new) {
+ BMO_face_flag_enable(bm, f_new, ELE_NEW);
+ BM_edge_kill(bm, e);
+ }
+ else {
+ BMO_error_clear(bm);
+ }
}
else {
- BMO_error_clear(bm);
+ BM_edge_kill(bm, e);
}
}
- else {
- BM_edge_kill(bm, e);
- }
}
-
- BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_EDGE | BM_FACE, ELE_NEW);
}
+
+ BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_EDGE | BM_FACE, ELE_NEW);
}
diff --git a/source/blender/bmesh/operators/bmo_utils.c b/source/blender/bmesh/operators/bmo_utils.c
index e596032663e..aa1e4bc7523 100644
--- a/source/blender/bmesh/operators/bmo_utils.c
+++ b/source/blender/bmesh/operators/bmo_utils.c
@@ -48,7 +48,7 @@ void bmo_create_vert_exec(BMesh *bm, BMOperator *op)
BMO_slot_vec_get(op->slots_in, "co", vec);
- BMO_elem_flag_enable(bm, BM_vert_create(bm, vec, NULL, BM_CREATE_NOP), ELE_NEW);
+ BMO_vert_flag_enable(bm, BM_vert_create(bm, vec, NULL, BM_CREATE_NOP), ELE_NEW);
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "vert.out", BM_VERT, ELE_NEW);
}
@@ -74,7 +74,7 @@ void bmo_transform_exec(BMesh *UNUSED(bm), BMOperator *op)
void bmo_translate_exec(BMesh *bm, BMOperator *op)
{
float mat[4][4], vec[3];
-
+
BMO_slot_vec_get(op->slots_in, "vec", vec);
unit_m4(mat);
@@ -86,7 +86,7 @@ void bmo_translate_exec(BMesh *bm, BMOperator *op)
void bmo_scale_exec(BMesh *bm, BMOperator *op)
{
float mat[3][3], vec[3];
-
+
BMO_slot_vec_get(op->slots_in, "vec", vec);
unit_m3(mat);
@@ -143,18 +143,18 @@ void bmo_rotate_edges_exec(BMesh *bm, BMOperator *op)
if (BM_edge_face_pair(e, &fa, &fb)) {
/* check we're untouched */
- if (BMO_elem_flag_test(bm, fa, FACE_TAINT) == false &&
- BMO_elem_flag_test(bm, fb, FACE_TAINT) == false)
+ if (BMO_face_flag_test(bm, fa, FACE_TAINT) == false &&
+ BMO_face_flag_test(bm, fb, FACE_TAINT) == false)
{
/* don't touch again (faces will be freed so run before rotating the edge) */
- BMO_elem_flag_enable(bm, fa, FACE_TAINT);
- BMO_elem_flag_enable(bm, fb, FACE_TAINT);
+ BMO_face_flag_enable(bm, fa, FACE_TAINT);
+ BMO_face_flag_enable(bm, fb, FACE_TAINT);
if (!(e2 = BM_edge_rotate(bm, e, use_ccw, check_flag))) {
- BMO_elem_flag_disable(bm, fa, FACE_TAINT);
- BMO_elem_flag_disable(bm, fb, FACE_TAINT);
+ BMO_face_flag_disable(bm, fa, FACE_TAINT);
+ BMO_face_flag_disable(bm, fb, FACE_TAINT);
#if 0
BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, "Could not rotate edge");
return;
@@ -163,7 +163,7 @@ void bmo_rotate_edges_exec(BMesh *bm, BMOperator *op)
continue;
}
- BMO_elem_flag_enable(bm, e2, EDGE_OUT);
+ BMO_edge_flag_enable(bm, e2, EDGE_OUT);
}
}
}
@@ -184,11 +184,11 @@ static void bmo_face_flag_set_flush(BMesh *bm, BMFace *f, const short oflag, con
BMLoop *l_iter;
BMLoop *l_first;
- BMO_elem_flag_set(bm, f, oflag, value);
+ BMO_face_flag_set(bm, f, oflag, value);
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
- BMO_elem_flag_set(bm, l_iter->e, oflag, value);
- BMO_elem_flag_set(bm, l_iter->v, oflag, value);
+ BMO_edge_flag_set(bm, l_iter->e, oflag, value);
+ BMO_vert_flag_set(bm, l_iter->v, oflag, value);
} while ((l_iter = l_iter->next) != l_first);
}
@@ -210,7 +210,9 @@ static void bmo_region_extend_expand(
BMEdge *e;
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, e, SEL_ORIG) && !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
+ if (!BMO_edge_flag_test(bm, e, SEL_ORIG) &&
+ !BM_elem_flag_test(e, BM_ELEM_HIDDEN))
+ {
found = true;
break;
}
@@ -223,9 +225,11 @@ static void bmo_region_extend_expand(
BMEdge *e;
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, e, SEL_FLAG) && !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
- BMO_elem_flag_enable(bm, e, SEL_FLAG);
- BMO_elem_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG);
+ if (!BMO_edge_flag_test(bm, e, SEL_FLAG) &&
+ !BM_elem_flag_test(e, BM_ELEM_HIDDEN))
+ {
+ BMO_edge_flag_enable(bm, e, SEL_FLAG);
+ BMO_vert_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG);
}
}
}
@@ -234,7 +238,9 @@ static void bmo_region_extend_expand(
BMFace *f;
BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, f, SEL_FLAG) && !BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
+ if (!BMO_face_flag_test(bm, f, SEL_FLAG) &&
+ !BM_elem_flag_test(f, BM_ELEM_HIDDEN))
+ {
bmo_face_flag_set_flush(bm, f, SEL_FLAG, true);
}
}
@@ -245,9 +251,11 @@ static void bmo_region_extend_expand(
BMEdge *e;
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
if (BM_edge_is_wire(e)) {
- if (!BMO_elem_flag_test(bm, e, SEL_FLAG) && !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
- BMO_elem_flag_enable(bm, e, SEL_FLAG);
- BMO_elem_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG);
+ if (!BMO_edge_flag_test(bm, e, SEL_FLAG) &&
+ !BM_elem_flag_test(e, BM_ELEM_HIDDEN))
+ {
+ BMO_edge_flag_enable(bm, e, SEL_FLAG);
+ BMO_vert_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG);
}
}
}
@@ -269,10 +277,10 @@ static void bmo_region_extend_expand(
BMFace *f_other;
BM_ITER_ELEM (f_other, &fiter, l->e, BM_FACES_OF_EDGE) {
- if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG) &&
+ if (!BMO_face_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG) &&
!BM_elem_flag_test(f_other, BM_ELEM_HIDDEN))
{
- BMO_elem_flag_enable(bm, f_other, SEL_FLAG);
+ BMO_face_flag_enable(bm, f_other, SEL_FLAG);
}
}
}
@@ -281,10 +289,10 @@ static void bmo_region_extend_expand(
BMFace *f_other;
BM_ITER_ELEM (f_other, &fiter, l->v, BM_FACES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG) &&
+ if (!BMO_face_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG) &&
!BM_elem_flag_test(f_other, BM_ELEM_HIDDEN))
{
- BMO_elem_flag_enable(bm, f_other, SEL_FLAG);
+ BMO_face_flag_enable(bm, f_other, SEL_FLAG);
}
}
}
@@ -310,7 +318,7 @@ static void bmo_region_extend_contract(
BMEdge *e;
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, e, SEL_ORIG)) {
+ if (!BMO_edge_flag_test(bm, e, SEL_ORIG)) {
found = true;
break;
}
@@ -321,7 +329,7 @@ static void bmo_region_extend_contract(
BMFace *f;
BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, f, SEL_ORIG)) {
+ if (!BMO_face_flag_test(bm, f, SEL_ORIG)) {
found = true;
break;
}
@@ -334,7 +342,7 @@ static void bmo_region_extend_contract(
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
if (BM_edge_is_wire(e)) {
- if (!BMO_elem_flag_test(bm, e, SEL_ORIG)) {
+ if (!BMO_edge_flag_test(bm, e, SEL_ORIG)) {
found = true;
break;
}
@@ -347,10 +355,10 @@ static void bmo_region_extend_contract(
BMIter eiter;
BMEdge *e;
- BMO_elem_flag_enable(bm, v, SEL_FLAG);
+ BMO_vert_flag_enable(bm, v, SEL_FLAG);
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- BMO_elem_flag_enable(bm, e, SEL_FLAG);
+ BMO_edge_flag_enable(bm, e, SEL_FLAG);
}
}
}
@@ -369,8 +377,8 @@ static void bmo_region_extend_contract(
BMFace *f_other;
BM_ITER_ELEM (f_other, &fiter, l->e, BM_FACES_OF_EDGE) {
- if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG)) {
- BMO_elem_flag_enable(bm, f, SEL_FLAG);
+ if (!BMO_face_flag_test(bm, f_other, SEL_ORIG)) {
+ BMO_face_flag_enable(bm, f, SEL_FLAG);
break;
}
}
@@ -380,8 +388,8 @@ static void bmo_region_extend_contract(
BMFace *f_other;
BM_ITER_ELEM (f_other, &fiter, l->v, BM_FACES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG)) {
- BMO_elem_flag_enable(bm, f, SEL_FLAG);
+ if (!BMO_face_flag_test(bm, f_other, SEL_ORIG)) {
+ BMO_face_flag_enable(bm, f, SEL_FLAG);
break;
}
}
@@ -420,7 +428,7 @@ void bmo_smooth_vert_exec(BMesh *UNUSED(bm), BMOperator *op)
const float fac = BMO_slot_float_get(op->slots_in, "factor");
int i, j, clipx, clipy, clipz;
int xaxis, yaxis, zaxis;
-
+
clipx = BMO_slot_bool_get(op->slots_in, "mirror_clip_x");
clipy = BMO_slot_bool_get(op->slots_in, "mirror_clip_y");
clipz = BMO_slot_bool_get(op->slots_in, "mirror_clip_z");
@@ -441,7 +449,7 @@ void bmo_smooth_vert_exec(BMesh *UNUSED(bm), BMOperator *op)
add_v3_v3v3(co, co, co2);
j += 1;
}
-
+
if (!j) {
copy_v3_v3(co, v->co);
i++;
diff --git a/source/blender/bmesh/tools/bmesh_beautify.c b/source/blender/bmesh/tools/bmesh_beautify.c
index 19fe492c670..3e3a6547b75 100644
--- a/source/blender/bmesh/tools/bmesh_beautify.c
+++ b/source/blender/bmesh/tools/bmesh_beautify.c
@@ -424,11 +424,13 @@ void BM_mesh_beautify_fill(
flag, method);
/* update flags */
- if (oflag_edge)
- BMO_elem_flag_enable(bm, e, oflag_edge);
+ if (oflag_edge) {
+ BMO_edge_flag_enable(bm, e, oflag_edge);
+ }
+
if (oflag_face) {
- BMO_elem_flag_enable(bm, e->l->f, oflag_face);
- BMO_elem_flag_enable(bm, e->l->radial_next->f, oflag_face);
+ BMO_face_flag_enable(bm, e->l->f, oflag_face);
+ BMO_face_flag_enable(bm, e->l->radial_next->f, oflag_face);
}
}
}
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index 5a7788c0b62..6c168bd9114 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -198,6 +198,12 @@ typedef struct BevelParams {
// #include "bevdebug.c"
+/* some flags to re-enable old behavior for a while, in case fixes broke things not caught by regression tests */
+static int bev_debug_flags = 0;
+#define DEBUG_OLD_PLANE_SPECIAL (bev_debug_flags & 1)
+#define DEBUG_OLD_PROJ_TO_PERP_PLANE (bev_debug_flags & 2)
+#define DEBUG_OLD_FLAT_MID (bev_debug_flags & 4)
+
/* Make a new BoundVert of the given kind, insert it at the end of the circular linked
* list with entry point bv->boundstart, and return it. */
static BoundVert *add_new_bound_vert(MemArena *mem_arena, VMesh *vm, const float co[3])
@@ -345,6 +351,36 @@ static EdgeHalf *next_bev(BevVert *bv, EdgeHalf *from_e)
return NULL;
}
+/* return count of edges between e1 and e2 when going around bv CCW */
+static int count_ccw_edges_between(EdgeHalf *e1, EdgeHalf *e2)
+{
+ int cnt = 0;
+ EdgeHalf *e = e1;
+
+ do {
+ if (e == e2)
+ break;
+ e = e->next;
+ cnt++;
+ } while (e != e1);
+ return cnt;
+}
+
+/* Assume bme1 and bme2 both share some vert. Do they share a face?
+ * If they share a face then there is some loop around bme1 that is in a face
+ * where the next or previous edge in the face must be bme2. */
+static bool edges_face_connected_at_vert(BMEdge *bme1, BMEdge *bme2)
+{
+ BMLoop *l;
+ BMIter iter;
+
+ BM_ITER_ELEM(l, &iter, bme1, BM_LOOPS_OF_EDGE) {
+ if (l->prev->e == bme2 || l->next->e == bme2)
+ return true;
+ }
+ return false;
+}
+
/* Return a good representative face (for materials, etc.) for faces
* created around/near BoundVert v.
* Sometimes care about a second choice, if there is one.
@@ -1015,15 +1051,21 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv)
sub_v3_v3v3(pro->proj_dir, e->e->v1->co, e->e->v2->co);
normalize_v3(pro->proj_dir);
project_to_edge(e->e, co1, co2, pro->midco);
- /* put arc endpoints on plane with normal proj_dir, containing midco */
- add_v3_v3v3(co3, co1, pro->proj_dir);
- if (!isect_line_plane_v3(pro->coa, co1, co3, pro->midco, pro->proj_dir)) {
- /* shouldn't happen */
- copy_v3_v3(pro->coa, co1);
+ if (DEBUG_OLD_PROJ_TO_PERP_PLANE) {
+ /* put arc endpoints on plane with normal proj_dir, containing midco */
+ add_v3_v3v3(co3, co1, pro->proj_dir);
+ if (!isect_line_plane_v3(pro->coa, co1, co3, pro->midco, pro->proj_dir)) {
+ /* shouldn't happen */
+ copy_v3_v3(pro->coa, co1);
+ }
+ add_v3_v3v3(co3, co2, pro->proj_dir);
+ if (!isect_line_plane_v3(pro->cob, co2, co3, pro->midco, pro->proj_dir)) {
+ /* shouldn't happen */
+ copy_v3_v3(pro->cob, co2);
+ }
}
- add_v3_v3v3(co3, co2, pro->proj_dir);
- if (!isect_line_plane_v3(pro->cob, co2, co3, pro->midco, pro->proj_dir)) {
- /* shouldn't happen */
+ else {
+ copy_v3_v3(pro->coa, co1);
copy_v3_v3(pro->cob, co2);
}
/* default plane to project onto is the one with triangle co1 - midco - co2 in it */
@@ -1036,19 +1078,48 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv)
if (l <= BEVEL_EPSILON_BIG) {
/* co1 - midco -co2 are collinear.
* Should be case that beveled edge is coplanar with two boundary verts.
+ * We want to move the profile to that common plane, if possible.
+ * That makes the multi-segment bevels curve nicely in that plane, as users expect.
+ * The new midco should be either v (when neighbor edges are unbeveled)
+ * or the intersection of the offset lines (if they are).
* If the profile is going to lead into unbeveled edges on each side
* (that is, both BoundVerts are "on-edge" points on non-beveled edges)
- * then in order to get curve in multi-segment case, change projection plane
- * to be that common plane, projection dir to be the plane normal,
- * and mid to be the original vertex.
- * Otherwise, we just want to linearly interpolate between co1 and co2.
*/
- if (e->prev->is_bev || e->next->is_bev) {
+ if (DEBUG_OLD_PLANE_SPECIAL && (e->prev->is_bev || e->next->is_bev)) {
do_linear_interp = true;
}
else {
- copy_v3_v3(pro->coa, co1);
- copy_v3_v3(pro->midco, bv->v->co);
+ if (DEBUG_OLD_PROJ_TO_PERP_PLANE) {
+ copy_v3_v3(pro->coa, co1);
+ copy_v3_v3(pro->cob, co2);
+ }
+ if (DEBUG_OLD_FLAT_MID) {
+ copy_v3_v3(pro->midco, bv->v->co);
+ }
+ else {
+ copy_v3_v3(pro->midco, bv->v->co);
+ if (e->prev->is_bev && e->next->is_bev && bv->selcount >= 3) {
+ /* want mid at the meet point of next and prev offset edges */
+ float d3[3], d4[3], co4[3], meetco[3], isect2[3];
+ int isect_kind;
+
+ sub_v3_v3v3(d3, e->prev->e->v1->co, e->prev->e->v2->co);
+ sub_v3_v3v3(d4, e->next->e->v1->co, e->next->e->v2->co);
+ normalize_v3(d3);
+ normalize_v3(d4);
+ add_v3_v3v3(co3, co1, d3);
+ add_v3_v3v3(co4, co2, d4);
+ isect_kind = isect_line_line_v3(co1, co3, co2, co4, meetco, isect2);
+ if (isect_kind != 0) {
+ copy_v3_v3(pro->midco, meetco);
+ }
+ else {
+ /* offset lines are collinear - want linear interpolation */
+ mid_v3_v3v3(pro->midco, co1, co2);
+ do_linear_interp = true;
+ }
+ }
+ }
copy_v3_v3(pro->cob, co2);
sub_v3_v3v3(d1, pro->midco, co1);
normalize_v3(d1);
@@ -1557,7 +1628,7 @@ static void build_boundary_vertex_only(BevelParams *bp, BevVert *bv, bool constr
if (construct) {
v = add_new_bound_vert(bp->mem_arena, vm, co);
v->efirst = v->elast = e;
- e->leftv = v;
+ e->leftv = e->rightv = v;
}
else {
adjust_bound_vert(e->leftv, co);
@@ -1577,9 +1648,11 @@ static void build_boundary_vertex_only(BevelParams *bp, BevVert *bv, bool constr
}
}
-/* Special case of build_boundary when a single edge is beveled.
- * The 'width adjust' part of build_boundary has been done already, and
- * efirst is the first beveled edge at vertex bv. */
+/**
+ * Special case of build_boundary when a single edge is beveled.
+ * The 'width adjust' part of build_boundary has been done already,
+ * and \a efirst is the first beveled edge at vertex \a bv.
+*/
static void build_boundary_terminal_edge(BevelParams *bp, BevVert *bv, EdgeHalf *efirst, bool construct)
{
MemArena *mem_arena = bp->mem_arena;
@@ -1637,7 +1710,7 @@ static void build_boundary_terminal_edge(BevelParams *bp, BevVert *bv, EdgeHalf
v->efirst = e->prev;
v->elast = v->ebev = e;
e->leftv = v;
- e->prev->leftv = v;
+ e->prev->leftv = e->prev->rightv = v;
}
else {
adjust_bound_vert(e->leftv, co);
@@ -1648,7 +1721,7 @@ static void build_boundary_terminal_edge(BevelParams *bp, BevVert *bv, EdgeHalf
v = add_new_bound_vert(mem_arena, vm, co);
v->efirst = e->prev;
v->elast = e;
- e->leftv = v;
+ e->leftv = e->rightv = v;
e->prev->rightv = v;
}
else {
@@ -1661,7 +1734,7 @@ static void build_boundary_terminal_edge(BevelParams *bp, BevVert *bv, EdgeHalf
if (construct) {
v = add_new_bound_vert(mem_arena, vm, co);
v->efirst = v->elast = e;
- e->leftv = v;
+ e->leftv = e->rightv = v;
}
else {
adjust_bound_vert(e->leftv, co);
@@ -1778,11 +1851,11 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
do {
BLI_assert(e->is_bev);
/* Make the BoundVert for the right side of e; other side will be made
- * when the beveled edge to the left of e is handled.
- * Analyze edges until next beveled edge.
- * They are either "in plane" (preceding and subsequent faces are coplanar)
- * or not. The "non-in-plane" edges effect silhouette and we prefer to slide
- * along one of those if possible. */
+ * when the beveled edge to the left of e is handled.
+ * Analyze edges until next beveled edge.
+ * They are either "in plane" (preceding and subsequent faces are coplanar)
+ * or not. The "non-in-plane" edges effect silhouette and we prefer to slide
+ * along one of those if possible. */
nip = nnip = 0; /* counts of in-plane / not-in-plane */
enip = eip = NULL; /* representatives of each */
for (e2 = e->next; !e2->is_bev; e2 = e2->next) {
@@ -2121,10 +2194,13 @@ static void fill_vmesh_fracs(VMesh *vm, float *frac, int i)
total += len_v3v3(mesh_vert(vm, i, 0, k)->co, mesh_vert(vm, i, 0, k + 1)->co);
frac[k + 1] = total;
}
- if (total > BEVEL_EPSILON) {
+ if (total > 0.0f) {
for (k = 1; k <= ns; k++)
frac[k] /= total;
}
+ else {
+ frac[ns] = 1.0f;
+ }
}
/* Like fill_vmesh_fracs but want fractions for profile points of bndv, with ns segments */
@@ -2142,11 +2218,14 @@ static void fill_profile_fracs(BevelParams *bp, BoundVert *bndv, float *frac, in
frac[k + 1] = total;
copy_v3_v3(co, nextco);
}
- if (total > BEVEL_EPSILON) {
+ if (total > 0.0f) {
for (k = 1; k <= ns; k++) {
frac[k] /= total;
}
}
+ else {
+ frac[ns] = 1.0f;
+ }
}
/* Return i such that frac[i] <= f <= frac[i + 1], where frac[n] == 1.0
@@ -3237,6 +3316,11 @@ static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv)
if (!weld)
create_mesh_bmvert(bm, vm, i, 0, k, bv->v);
}
+ else if (n == 2 && !v->ebev && vm->mesh_kind != M_ADJ) {
+ /* case of one edge beveled and this is the v without ebev */
+ /* want to copy the verts from other v, in reverse order */
+ copy_mesh_vert(vm, i, 0, k, 1 - i, 0, ns - k);
+ }
}
} while ((v = v->next) != vm->boundstart);
@@ -3305,6 +3389,220 @@ static float edge_face_angle(EdgeHalf *e)
#define BM_BEVEL_EDGE_TAG_DISABLE(bme) BM_ELEM_API_FLAG_DISABLE( (bme), _FLAG_OVERLAP)
#define BM_BEVEL_EDGE_TAG_TEST(bme) BM_ELEM_API_FLAG_TEST( (bme), _FLAG_OVERLAP)
+/* Try to extend the bv->edges[] array beyond i by finding more successor edges.
+ * This is a possibly exponential-time search, but it is only exponential in the number
+ * of "internal faces" at a vertex -- i.e., faces that bridge between the edges that naturally
+ * form a manifold cap around bv. It is rare to have more than one of these, so unlikely
+ * that the exponential time case will be hit in practice.
+ * Returns the new index i' where bv->edges[i'] ends the best path found.
+ * The path will have the tags of all of its edges set. */
+static int bevel_edge_order_extend(BMesh *bm, BevVert *bv, int i)
+{
+ BMEdge *bme, *bme2, *nextbme;
+ BMLoop *l;
+ BMIter iter;
+ int j, tryj, bestj, nsucs, sucindex, k;
+ BMEdge **sucs = NULL;
+ BMEdge **save_path = NULL;
+ BLI_array_staticdeclare(sucs, 4); /* likely very few faces attached to same edge */
+ BLI_array_staticdeclare(save_path, BM_DEFAULT_NGON_STACK_SIZE);
+
+ bme = bv->edges[i].e;
+ /* fill sucs with all unmarked edges of bmes */
+ BM_ITER_ELEM(l, &iter, bme, BM_LOOPS_OF_EDGE) {
+ bme2 = (l->v == bv->v) ? l->prev->e : l->next->e;
+ if (!BM_BEVEL_EDGE_TAG_TEST(bme2)) {
+ BLI_array_append(sucs, bme2);
+ }
+ }
+ nsucs = BLI_array_count(sucs);
+
+ bestj = j = i;
+ for (sucindex = 0; sucindex < nsucs; sucindex++) {
+ nextbme = sucs[sucindex];
+ BLI_assert(nextbme != NULL);
+ BLI_assert(!BM_BEVEL_EDGE_TAG_TEST(nextbme));
+ BLI_assert(j + 1 < bv->edgecount);
+ bv->edges[j + 1].e = nextbme;
+ BM_BEVEL_EDGE_TAG_ENABLE(nextbme);
+ tryj = bevel_edge_order_extend(bm, bv, j + 1);
+ if (tryj > bestj || (tryj == bestj && edges_face_connected_at_vert(bv->edges[tryj].e, bv->edges[0].e))) {
+ bestj = tryj;
+ BLI_array_empty(save_path);
+ for (k = j + 1; k <= bestj; k++) {
+ BLI_array_append(save_path, bv->edges[k].e);
+ }
+ }
+ /* now reset to path only-going-to-j state */
+ for (k = j + 1; k <= tryj; k++) {
+ BM_BEVEL_EDGE_TAG_DISABLE(bv->edges[k].e);
+ bv->edges[k].e = NULL;
+ }
+ }
+ /* at this point we should be back at invariant on entrance: path up to j */
+ if (bestj > j) {
+ /* save_path should have from j + 1 to bestj inclusive edges to add to edges[] before returning */
+ for (k = j + 1; k <= bestj; k++) {
+ BLI_assert(save_path[k - (j + 1)] != NULL);
+ bv->edges[k].e = save_path[k - (j + 1)];
+ BM_BEVEL_EDGE_TAG_ENABLE(bv->edges[k].e);
+ }
+ }
+ BLI_array_free(sucs);
+ BLI_array_free(save_path);
+ return bestj;
+}
+
+/* See if we have usual case for bevel edge order:
+ * there is an ordering such that all the faces are between
+ * successive edges and form a manifold "cap" at bv.
+ * If this is the case, set bv->edges to such an order
+ * and return true; else return unmark any partial path and return false.
+ * Assume the first edge is already in bv->edges[0].e and it is tagged. */
+#ifdef FASTER_FASTORDER
+/* The alternative older code is O(n^2) where n = # of edges incident to bv->v.
+ * This implementation is O(n * m) where m = average number of faces attached to an edge incident to bv->v,
+ * which is almost certainly a small constant except in very strange cases. But this code produces different
+ * choices of ordering than the legacy system, leading to differences in vertex orders etc. in user models,
+ * so for now will continue to use the legacy code. */
+static bool fast_bevel_edge_order(BevVert *bv)
+{
+ int j, k, nsucs;
+ BMEdge *bme, *bme2, *bmenext;
+ BMIter iter;
+ BMLoop *l;
+
+ for (j = 1; j < bv->edgecount; j++) {
+ bme = bv->edges[j - 1].e;
+ bmenext = NULL;
+ nsucs = 0;
+ BM_ITER_ELEM(l, &iter, bme, BM_LOOPS_OF_EDGE) {
+ bme2 = (l->v == bv->v) ? l->prev->e : l->next->e;
+ if (!BM_BEVEL_EDGE_TAG_TEST(bme2)) {
+ nsucs++;
+ if (bmenext == NULL)
+ bmenext = bme2;
+ }
+ }
+ if (nsucs == 0 || (nsucs == 2 && j != 1) || nsucs > 2 ||
+ (j == bv->edgecount - 1 && !edges_face_connected_at_vert(bmenext, bv->edges[0].e)))
+ {
+ for (k = 1; k < j; k++) {
+ BM_BEVEL_EDGE_TAG_DISABLE(bv->edges[k].e);
+ bv->edges[k].e = NULL;
+ }
+ return false;
+ }
+ bv->edges[j].e = bmenext;
+ BM_BEVEL_EDGE_TAG_ENABLE(bmenext);
+ }
+ return true;
+}
+#else
+static bool fast_bevel_edge_order(BevVert *bv)
+{
+ BMEdge *bme, *bme2, *first_suc;
+ BMIter iter, iter2;
+ BMFace *f;
+ EdgeHalf *e;
+ int i, k, ntot, num_shared_face;
+
+ ntot = bv->edgecount;
+
+ /* add edges to bv->edges in order that keeps adjacent edges sharing
+ * a unique face, if possible */
+ e = &bv->edges[0];
+ bme = e->e;
+ if (!bme->l)
+ return false;
+ for (i = 1; i < ntot; i++) {
+ /* find an unflagged edge bme2 that shares a face f with previous bme */
+ num_shared_face = 0;
+ first_suc = NULL; /* keep track of first successor to match legacy behavior */
+ BM_ITER_ELEM (bme2, &iter, bv->v, BM_EDGES_OF_VERT) {
+ if (BM_BEVEL_EDGE_TAG_TEST(bme2))
+ continue;
+ BM_ITER_ELEM (f, &iter2, bme2, BM_FACES_OF_EDGE) {
+ if (BM_face_edge_share_loop(f, bme)) {
+ num_shared_face++;
+ if (first_suc == NULL)
+ first_suc = bme2;
+ }
+ }
+ if (num_shared_face >= 3)
+ break;
+ }
+ if (num_shared_face == 1 || (i == 1 && num_shared_face == 2)) {
+ e = &bv->edges[i];
+ e->e = bme = first_suc;
+ BM_BEVEL_EDGE_TAG_ENABLE(bme);
+ }
+ else {
+ for (k = 1; k < i; k++) {
+ BM_BEVEL_EDGE_TAG_DISABLE(bv->edges[k].e);
+ bv->edges[k].e = NULL;
+ }
+ return false;
+ }
+ }
+ return true;
+}
+#endif
+
+/* Fill in bv->edges with a good ordering of non-wire edges around bv->v.
+ * Use only edges where BM_BEVEL_EDGE_TAG is disabled so far
+ * (if edge beveling, others are wire).
+ * first_bme is a good edge to start with.*/
+static void find_bevel_edge_order(BMesh *bm, BevVert *bv, BMEdge *first_bme)
+{
+ BMEdge *bme, *bme2;
+ BMIter iter;
+ BMFace *f;
+ EdgeHalf *e;
+ EdgeHalf *e2;
+ BMLoop *l;
+ int i, ntot;
+
+ ntot = bv->edgecount;
+ i = 0;
+ for (;;) {
+ BLI_assert(first_bme != NULL);
+ bv->edges[i].e = first_bme;
+ BM_BEVEL_EDGE_TAG_ENABLE(first_bme);
+ if (i == 0 && fast_bevel_edge_order(bv))
+ break;
+ i = bevel_edge_order_extend(bm, bv, i);
+ i++;
+ if (i >= bv->edgecount)
+ break;
+ /* Not done yet: find a new first_bme */
+ first_bme = NULL;
+ BM_ITER_ELEM(bme, &iter, bv->v, BM_EDGES_OF_VERT) {
+ if (BM_BEVEL_EDGE_TAG_TEST(bme))
+ continue;
+ if (!first_bme)
+ first_bme = bme;
+ if (BM_edge_face_count(bme) == 1) {
+ first_bme = bme;
+ break;
+ }
+ }
+ }
+ /* now fill in the faces ... */
+ for (i = 0; i < ntot; i++) {
+ e = &bv->edges[i];
+ e2 = (i == bv->edgecount - 1) ? &bv->edges[0] : &bv->edges[i + 1];
+ bme = e->e;
+ bme2 = e2->e;
+ BLI_assert(bme != NULL);
+ BM_ITER_ELEM(l, &iter, bme, BM_LOOPS_OF_EDGE) {
+ f = l->f;
+ if ((l->prev->e == bme2 || l->next->e == bme2) && !e->fnext && !e2->fprev)
+ e->fnext = e2->fprev = f;
+ }
+ }
+}
+
/*
* Construction around the vertex
*/
@@ -3312,13 +3610,12 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
{
BMEdge *bme;
BevVert *bv;
- BMEdge *bme2, *unflagged_bme, *first_bme;
- BMFace *f;
+ BMEdge *first_bme;
BMVert *v1, *v2;
- BMIter iter, iter2;
+ BMIter iter;
EdgeHalf *e;
float weight, z;
- int i, found_shared_face, ccw_test_sum;
+ int i, ccw_test_sum;
int nsel = 0;
int ntot = 0;
int nwire = 0;
@@ -3398,47 +3695,12 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
}
BLI_ghash_insert(bp->vert_hash, v, bv);
- /* add edges to bv->edges in order that keeps adjacent edges sharing
- * a face, if possible */
- i = 0;
+ find_bevel_edge_order(bm, bv, first_bme);
- bme = first_bme;
- BM_BEVEL_EDGE_TAG_ENABLE(bme);
- e = &bv->edges[0];
- e->e = bme;
+ /* fill in other attributes of EdgeHalfs */
for (i = 0; i < ntot; i++) {
- if (i > 0) {
- /* find an unflagged edge bme2 that shares a face f with previous bme */
- found_shared_face = 0;
- unflagged_bme = NULL;
- BM_ITER_ELEM (bme2, &iter, v, BM_EDGES_OF_VERT) {
- if (BM_BEVEL_EDGE_TAG_TEST(bme2))
- continue;
- if (!unflagged_bme)
- unflagged_bme = bme2;
- if (!bme->l)
- continue;
- BM_ITER_ELEM (f, &iter2, bme2, BM_FACES_OF_EDGE) {
- if (BM_face_edge_share_loop(f, bme)) {
- found_shared_face = 1;
- break;
- }
- }
- if (found_shared_face)
- break;
- }
- e = &bv->edges[i];
- if (found_shared_face) {
- e->e = bme2;
- e->fprev = f;
- bv->edges[i - 1].fnext = f;
- }
- else {
- e->e = unflagged_bme;
- }
- }
+ e = &bv->edges[i];
bme = e->e;
- BM_BEVEL_EDGE_TAG_ENABLE(bme);
if (BM_elem_flag_test(bme, BM_ELEM_TAG) && !bp->vertex_only) {
e->is_bev = true;
e->seg = bp->seg;
@@ -3449,16 +3711,6 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
}
e->is_rev = (bme->v2 == v);
}
- /* find wrap-around shared face */
- BM_ITER_ELEM (f, &iter2, bme, BM_FACES_OF_EDGE) {
- if (bv->edges[0].e->l && BM_face_edge_share_loop(f, bv->edges[0].e)) {
- if (bv->edges[0].fnext == f)
- continue; /* if two shared faces, want the other one now */
- bv->edges[ntot - 1].fnext = f;
- bv->edges[0].fprev = f;
- break;
- }
- }
/* now done with tag flag */
BM_ITER_ELEM (bme, &iter, v, BM_EDGES_OF_VERT) {
@@ -3586,6 +3838,7 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f)
VMesh *vm;
int i, k, n;
bool do_rebuild = false;
+ bool go_ccw, corner3special;
BMVert *bmv;
BMEdge *bme, *bme_new, *bme_prev;
BMFace *f_new;
@@ -3600,47 +3853,89 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f)
if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
lprev = l->prev;
bv = find_bevvert(bp, l->v);
+ vm = bv->vmesh;
e = find_edge_half(bv, l->e);
+ BLI_assert(e != NULL);
bme = e->e;
eprev = find_edge_half(bv, lprev->e);
- BLI_assert(e != NULL && eprev != NULL);
- vstart = eprev->leftv;
- if (e->is_bev)
- vend = e->rightv;
- else
+ BLI_assert(eprev != NULL);
+
+ /* which direction around our vertex do we travel to match orientation of f? */
+ if (e->prev == eprev) {
+ if (eprev->prev == e) {
+ /* valence 2 vertex: use f is one of e->fnext or e->fprev to break tie */
+ go_ccw = (e->fnext != f);
+ }
+ else {
+ go_ccw = true; /* going ccw around bv to trace this corner */
+ }
+ }
+ else if (eprev->prev == e) {
+ go_ccw = false; /* going cw around bv to trace this corner */
+ }
+ else {
+ /* edges in face are non-contiguous in our ordering around bv.
+ * Which way should we go when going from eprev to e? */
+ if (count_ccw_edges_between(eprev, e) < count_ccw_edges_between(e, eprev)) {
+ /* go counterclockewise from eprev to e */
+ go_ccw = true;
+ }
+ else {
+ /* go clockwise from eprev to e */
+ go_ccw = false;
+ }
+ }
+ if (go_ccw) {
+ vstart = eprev->rightv;
vend = e->leftv;
+ }
+ else {
+ vstart = eprev->leftv;
+ vend = e->rightv;
+ }
+ BLI_assert(vstart != NULL && vend != NULL);
v = vstart;
- vm = bv->vmesh;
BLI_array_append(vv, v->nv.v);
BLI_array_append(ee, bme);
+ /* check for special case: multisegment 3rd face opposite a beveled edge with no vmesh */
+ corner3special = (vm->mesh_kind == M_NONE && v->ebev != e && v->ebev != eprev);
while (v != vend) {
- if (vm->mesh_kind == M_NONE && v->ebev && v->ebev->seg > 1 && v->ebev != e && v->ebev != eprev) {
- /* case of 3rd face opposite a beveled edge, with no vmesh */
- i = v->index;
- e = v->ebev;
- for (k = 1; k < e->seg; k++) {
- bmv = mesh_vert(vm, i, 0, k)->v;
- BLI_array_append(vv, bmv);
- BLI_array_append(ee, bme);
- /* may want to merge UVs of these later */
- if (!e->is_seam)
- BLI_array_append(vv_fix, bmv);
+ if (go_ccw) {
+ if (vm->seg > 1) {
+ if (vm->mesh_kind == M_ADJ || bp->vertex_only || corner3special) {
+ i = v->index;
+ for (k = 1; k < vm->seg; k++) {
+ bmv = mesh_vert(vm, i, 0, k)->v;
+ BLI_array_append(vv, bmv);
+ BLI_array_append(ee, bme); /* TODO: maybe better edge here */
+ if (corner3special && v->ebev && !v->ebev->is_seam)
+ BLI_array_append(vv_fix, bmv);
+ }
+ }
}
+ v = v->next;
}
- else if ((vm->mesh_kind == M_ADJ || bp->vertex_only) && vm->seg > 1 && !e->is_bev && !eprev->is_bev) {
- BLI_assert(v->prev == vend);
- i = vend->index;
- for (k = vm->seg - 1; k > 0; k--) {
- bmv = mesh_vert(vm, i, 0, k)->v;
- BLI_array_append(vv, bmv);
- BLI_array_append(ee, bme);
+ else {
+ /* going cw */
+ if (vm->seg > 1) {
+ if (vm->mesh_kind == M_ADJ || bp->vertex_only ||
+ (vm->mesh_kind == M_NONE && v->ebev != e && v->ebev != eprev))
+ {
+ i = v->prev->index;
+ for (k = vm->seg - 1; k > 0; k--) {
+ bmv = mesh_vert(vm, i, 0, k)->v;
+ BLI_array_append(vv, bmv);
+ BLI_array_append(ee, bme);
+ if (corner3special && v->ebev && !v->ebev->is_seam)
+ BLI_array_append(vv_fix, bmv);
+ }
+ }
}
+ v = v->prev;
}
- v = v->prev;
BLI_array_append(vv, v->nv.v);
BLI_array_append(ee, bme);
}
-
do_rebuild = true;
}
else {
diff --git a/source/blender/bmesh/tools/bmesh_bisect_plane.c b/source/blender/bmesh/tools/bmesh_bisect_plane.c
index 9fb6d39a008..51b92a3c45e 100644
--- a/source/blender/bmesh/tools/bmesh_bisect_plane.c
+++ b/source/blender/bmesh/tools/bmesh_bisect_plane.c
@@ -155,9 +155,9 @@ static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], con
BM_face_split(bm, f, l_a, l_b, &l_new, NULL, true);
if (l_new) {
if (oflag_center) {
- BMO_elem_flag_enable(bm, l_new->e, oflag_center);
- BMO_elem_flag_enable(bm, l_new->f, oflag_center);
- BMO_elem_flag_enable(bm, f, oflag_center);
+ BMO_edge_flag_enable(bm, l_new->e, oflag_center);
+ BMO_face_flag_enable(bm, l_new->f, oflag_center);
+ BMO_face_flag_enable(bm, f, oflag_center);
}
}
}
@@ -270,9 +270,9 @@ static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], con
if (l_new) {
if (oflag_center) {
- BMO_elem_flag_enable(bm, l_new->e, oflag_center);
- BMO_elem_flag_enable(bm, l_new->f, oflag_center);
- BMO_elem_flag_enable(bm, face_split_arr[j], oflag_center);
+ BMO_edge_flag_enable(bm, l_new->e, oflag_center);
+ BMO_face_flag_enable(bm, l_new->f, oflag_center);
+ BMO_face_flag_enable(bm, face_split_arr[j], oflag_center);
}
}
@@ -372,7 +372,7 @@ void BM_mesh_bisect_plane(
if (BM_VERT_DIR(v) == 0) {
if (oflag_center) {
- BMO_elem_flag_enable(bm, v, oflag_center);
+ BMO_vert_flag_enable(bm, v, oflag_center);
}
if (use_snap_center) {
closest_to_plane_v3(v->co, plane, v->co);
@@ -407,7 +407,7 @@ void BM_mesh_bisect_plane(
v_new = BM_edge_split(bm, e, e->v1, NULL, e_fac);
vert_is_center_enable(v_new);
if (oflag_center) {
- BMO_elem_flag_enable(bm, v_new, oflag_center);
+ BMO_vert_flag_enable(bm, v_new, oflag_center);
}
BM_VERT_DIR(v_new) = 0;
@@ -439,7 +439,7 @@ void BM_mesh_bisect_plane(
/* if both verts are on the center - tag it */
if (oflag_center) {
if (side[0] == 0 && side[1] == 0) {
- BMO_elem_flag_enable(bm, e, oflag_center);
+ BMO_edge_flag_enable(bm, e, oflag_center);
}
}
}
diff --git a/source/blender/bmesh/tools/bmesh_decimate_collapse.c b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
index 0a5e5aba86b..372d341f223 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_collapse.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
@@ -34,6 +34,14 @@
#include "BLI_math.h"
#include "BLI_quadric.h"
#include "BLI_heap.h"
+#include "BLI_linklist.h"
+#include "BLI_alloca.h"
+#include "BLI_memarena.h"
+#include "BLI_edgehash.h"
+#include "BLI_polyfill2d.h"
+#include "BLI_polyfill2d_beautify.h"
+#include "BLI_stackdefines.h"
+
#include "BKE_customdata.h"
@@ -55,14 +63,14 @@
/* if the cost from #BLI_quadric_evaluate is 'noise', fallback to topology */
#define USE_TOPOLOGY_FALLBACK
#ifdef USE_TOPOLOGY_FALLBACK
-# define TOPOLOGY_FALLBACK_EPS FLT_EPSILON
+/* cost is calculated with double precision, it's ok to use a very small epsilon, see T48154. */
+# define TOPOLOGY_FALLBACK_EPS 1e-12f
#endif
-/* these checks are for rare cases that we can't avoid since they are valid meshes still */
-#define USE_SAFETY_CHECKS
-
#define BOUNDARY_PRESERVE_WEIGHT 100.0f
-#define OPTIMIZE_EPS 0.01f /* FLT_EPSILON is too small, see [#33106] */
+/* Uses double precision, impacts behavior on near-flat surfaces,
+ * cane give issues with very small faces. 1e-2 is too big, see: T48154. */
+#define OPTIMIZE_EPS 1e-8
#define COST_INVALID FLT_MAX
typedef enum CD_UseFlag {
@@ -134,8 +142,8 @@ static void bm_decim_build_quadrics(BMesh *bm, Quadric *vquadrics)
}
-static void bm_decim_calc_target_co(
- BMEdge *e, float optimize_co[3],
+static void bm_decim_calc_target_co_db(
+ BMEdge *e, double optimize_co[3],
const Quadric *vquadrics)
{
/* compute an edge contraction target for edge 'e'
@@ -152,10 +160,22 @@ static void bm_decim_calc_target_co(
return; /* all is good */
}
else {
- mid_v3_v3v3(optimize_co, e->v1->co, e->v2->co);
+ optimize_co[0] = 0.5 * ((double)e->v1->co[0] + (double)e->v2->co[0]);
+ optimize_co[1] = 0.5 * ((double)e->v1->co[1] + (double)e->v2->co[1]);
+ optimize_co[2] = 0.5 * ((double)e->v1->co[2] + (double)e->v2->co[2]);
}
}
+static void bm_decim_calc_target_co_fl(
+ BMEdge *e, float optimize_co[3],
+ const Quadric *vquadrics)
+{
+ double optimize_co_db[3];
+ bm_decim_calc_target_co_db(e, optimize_co_db, vquadrics);
+ copy_v3fl_v3db(optimize_co, optimize_co_db);
+}
+
+
static bool bm_edge_collapse_is_degenerate_flip(BMEdge *e, const float optimize_co[3])
{
BMIter liter;
@@ -234,8 +254,6 @@ static void bm_decim_build_edge_cost_single(
const float *vweights, const float vweight_factor,
Heap *eheap, HeapNode **eheap_table)
{
- const Quadric *q1, *q2;
- float optimize_co[3];
float cost;
if (eheap_table[BM_elem_index_get(e)]) {
@@ -273,15 +291,17 @@ static void bm_decim_build_edge_cost_single(
}
/* end sanity check */
+ {
+ double optimize_co[3];
+ bm_decim_calc_target_co_db(e, optimize_co, vquadrics);
- bm_decim_calc_target_co(e, optimize_co, vquadrics);
-
- q1 = &vquadrics[BM_elem_index_get(e->v1)];
- q2 = &vquadrics[BM_elem_index_get(e->v2)];
-
- cost = (BLI_quadric_evaluate(q1, optimize_co) +
- BLI_quadric_evaluate(q2, optimize_co));
+ const Quadric *q1, *q2;
+ q1 = &vquadrics[BM_elem_index_get(e->v1)];
+ q2 = &vquadrics[BM_elem_index_get(e->v2)];
+ cost = (BLI_quadric_evaluate(q1, optimize_co) +
+ BLI_quadric_evaluate(q2, optimize_co));
+ }
/* note, 'cost' shouldn't be negative but happens sometimes with small values.
* this can cause faces that make up a flat surface to over-collapse, see [#37121] */
@@ -410,7 +430,7 @@ static int *bm_edge_symmetry_map(BMesh *bm, unsigned int symmetry_axis, float li
tree = BLI_kdtree_new(bm->totedge);
- etable = MEM_mallocN(sizeof(BMEdge **) * bm->totedge, __func__);
+ etable = MEM_mallocN(sizeof(*etable) * bm->totedge, __func__);
edge_symmetry_map = MEM_mallocN(sizeof(*edge_symmetry_map) * bm->totedge, __func__);
BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
@@ -472,12 +492,58 @@ static int *bm_edge_symmetry_map(BMesh *bm, unsigned int symmetry_axis, float li
*
* \return true if any faces were triangulated.
*/
+static bool bm_face_triangulate(
+ BMesh *bm, BMFace *f_base, LinkNode **r_faces_double, int *r_edges_tri_tot,
-static bool bm_decim_triangulate_begin(BMesh *bm)
+ MemArena *pf_arena,
+ /* use for MOD_TRIANGULATE_NGON_BEAUTY only! */
+ struct Heap *pf_heap, struct EdgeHash *pf_ehash)
+{
+ const int f_base_len = f_base->len;
+ int faces_array_tot = f_base_len - 3;
+ int edges_array_tot = f_base_len - 3;
+ BMFace **faces_array = BLI_array_alloca(faces_array, faces_array_tot);
+ BMEdge **edges_array = BLI_array_alloca(edges_array, edges_array_tot);
+ const int quad_method = 0, ngon_method = 0; /* beauty */
+
+ bool has_cut = false;
+
+ const int f_index = BM_elem_index_get(f_base);
+
+ BM_face_triangulate(
+ bm, f_base,
+ faces_array, &faces_array_tot,
+ edges_array, &edges_array_tot,
+ r_faces_double,
+ quad_method, ngon_method, false,
+ pf_arena,
+ pf_heap, pf_ehash);
+
+ for (int i = 0; i < edges_array_tot; i++) {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = edges_array[i]->l;
+ do {
+ BM_elem_index_set(l_iter, f_index); /* set_dirty */
+ has_cut = true;
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+
+ for (int i = 0; i < faces_array_tot; i++) {
+ BM_face_normal_update(faces_array[i]);
+ }
+
+ *r_edges_tri_tot += edges_array_tot;
+
+ return has_cut;
+}
+
+
+static bool bm_decim_triangulate_begin(BMesh *bm, int *r_edges_tri_tot)
{
BMIter iter;
BMFace *f;
- // bool has_quad; // could optimize this a little
+ bool has_quad = false;
+ bool has_ngon = false;
bool has_cut = false;
BLI_assert((bm->elem_index_dirty & BM_VERT) == 0);
@@ -492,98 +558,104 @@ static bool bm_decim_triangulate_begin(BMesh *bm)
BM_elem_index_set(l_iter, -1); /* set_dirty */
} while ((l_iter = l_iter->next) != l_first);
- // has_quad |= (f->len == 4)
+ has_quad |= (f->len > 3);
+ has_ngon |= (f->len > 4);
}
bm->elem_index_dirty |= BM_LOOP;
- /* adding new faces as we loop over faces
- * is normally best avoided, however in this case its not so bad because any face touched twice
- * will already be triangulated*/
- BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (f->len == 4) {
- BMLoop *f_l[4];
- BMLoop *l_a, *l_b;
+ {
+ MemArena *pf_arena;
+ Heap *pf_heap;
+ EdgeHash *pf_ehash;
- {
- BMLoop *l_iter = BM_FACE_FIRST_LOOP(f);
+ LinkNode *faces_double = NULL;
- f_l[0] = l_iter; l_iter = l_iter->next;
- f_l[1] = l_iter; l_iter = l_iter->next;
- f_l[2] = l_iter; l_iter = l_iter->next;
- f_l[3] = l_iter;
- }
+ if (has_ngon) {
+ pf_arena = BLI_memarena_new(BLI_POLYFILL_ARENA_SIZE, __func__);
+ pf_heap = BLI_heap_new_ex(BLI_POLYFILL_ALLOC_NGON_RESERVE);
+ pf_ehash = BLI_edgehash_new_ex(__func__, BLI_POLYFILL_ALLOC_NGON_RESERVE);
+ }
+ else {
+ pf_arena = NULL;
+ pf_heap = NULL;
+ pf_ehash = NULL;
+ }
- if (len_squared_v3v3(f_l[0]->v->co, f_l[2]->v->co) <
- len_squared_v3v3(f_l[1]->v->co, f_l[3]->v->co))
- {
- l_a = f_l[0];
- l_b = f_l[2];
+ /* adding new faces as we loop over faces
+ * is normally best avoided, however in this case its not so bad because any face touched twice
+ * will already be triangulated*/
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (f->len > 3) {
+ has_cut |= bm_face_triangulate(
+ bm, f, &faces_double,
+ r_edges_tri_tot,
+
+ pf_arena,
+ pf_heap, pf_ehash);
}
- else {
- l_a = f_l[1];
- l_b = f_l[3];
- }
-
-#ifdef USE_SAFETY_CHECKS
- if (BM_edge_exists(l_a->v, l_b->v) == NULL)
-#endif
- {
- BMFace *f_new;
- BMLoop *l_new;
-
- /* warning, NO_DOUBLE option here isn't handled as nice as it could be
- * - if there is a quad that has a free standing edge joining it along
- * where we want to split the face, there isnt a good way we can handle this.
- * currently that edge will get removed when joining the tris back into a quad. */
- f_new = BM_face_split(bm, f, l_a, l_b, &l_new, NULL, false);
-
- if (f_new) {
- /* the value of this doesn't matter, only that the 2 loops match and have unique values */
- const int f_index = BM_elem_index_get(f);
-
- /* since we just split theres only ever 2 loops */
- BLI_assert(BM_edge_is_manifold(l_new->e));
-
- BM_elem_index_set(l_new, f_index); /* set_dirty */
- BM_elem_index_set(l_new->radial_next, f_index); /* set_dirty */
+ }
- BM_face_normal_update(f);
- BM_face_normal_update(f_new);
+ while (faces_double) {
+ LinkNode *next = faces_double->next;
+ BM_face_kill(bm, faces_double->link);
+ MEM_freeN(faces_double);
+ faces_double = next;
+ }
- has_cut = true;
- }
- }
+ if (has_ngon) {
+ BLI_memarena_free(pf_arena);
+ BLI_heap_free(pf_heap, NULL);
+ BLI_edgehash_free(pf_ehash, NULL);
}
- }
- BLI_assert((bm->elem_index_dirty & BM_VERT) == 0);
+ BLI_assert((bm->elem_index_dirty & BM_VERT) == 0);
- if (has_cut) {
- /* now triangulation is done we need to correct index values */
- BM_mesh_elem_index_ensure(bm, BM_EDGE | BM_FACE);
+ if (has_cut) {
+ /* now triangulation is done we need to correct index values */
+ BM_mesh_elem_index_ensure(bm, BM_EDGE | BM_FACE);
+ }
}
return has_cut;
}
-static void bm_decim_triangulate_end(BMesh *bm)
+
+static void bm_decim_triangulate_end(BMesh *bm, const int edges_tri_tot)
{
/* decimation finished, now re-join */
BMIter iter;
- BMEdge *e, *e_next;
+ BMEdge *e;
+
+ /* we need to collect before merging for ngons since the loops indices will be lost */
+ BMEdge **edges_tri = MEM_mallocN(MIN2(edges_tri_tot, bm->totedge) * sizeof(*edges_tri), __func__);
+ STACK_DECLARE(edges_tri);
+
+ STACK_INIT(edges_tri, MIN2(edges_tri_tot, bm->totedge));
/* boundary edges */
- BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) {
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
BMLoop *l_a, *l_b;
if (BM_edge_loop_pair(e, &l_a, &l_b)) {
const int l_a_index = BM_elem_index_get(l_a);
if (l_a_index != -1) {
const int l_b_index = BM_elem_index_get(l_b);
if (l_a_index == l_b_index) {
- if (LIKELY(l_a->f->len == 3 && l_b->f->len == 3)) {
- if (l_a->v != l_b->v) { /* if this is the case, faces have become flipped */
- /* check we are not making a degenerate quad */
+ if (l_a->v != l_b->v) { /* if this is the case, faces have become flipped */
+ /* check we are not making a degenerate quad */
+
+#define CAN_LOOP_MERGE(l) \
+ (BM_loop_is_manifold(l) && \
+ ((l)->v != (l)->radial_next->v) && \
+ (l_a_index == BM_elem_index_get(l)) && \
+ (l_a_index == BM_elem_index_get((l)->radial_next)))
+
+ if ((l_a->f->len == 3 && l_b->f->len == 3) &&
+ (!CAN_LOOP_MERGE(l_a->next)) &&
+ (!CAN_LOOP_MERGE(l_a->prev)) &&
+ (!CAN_LOOP_MERGE(l_b->next)) &&
+ (!CAN_LOOP_MERGE(l_b->prev)))
+ {
BMVert *vquad[4] = {
e->v1,
BM_vert_in_edge(e, l_a->next->v) ? l_a->prev->v : l_a->next->v,
@@ -596,17 +668,32 @@ static void bm_decim_triangulate_end(BMesh *bm)
BLI_assert(ELEM(vquad[2], vquad[1], vquad[0], vquad[3]) == false);
BLI_assert(ELEM(vquad[3], vquad[1], vquad[2], vquad[0]) == false);
- if (is_quad_convex_v3(vquad[0]->co, vquad[1]->co, vquad[2]->co, vquad[3]->co)) {
- /* highly unlikely to fail, but prevents possible double-ups */
- BMFace *f[2] = {l_a->f, l_b->f};
- BM_faces_join(bm, f, 2, true);
+ if (!is_quad_convex_v3(vquad[0]->co, vquad[1]->co, vquad[2]->co, vquad[3]->co)) {
+ continue;
}
}
+#undef CAN_LOOP_MERGE
+
+ /* highly unlikely to fail, but prevents possible double-ups */
+ STACK_PUSH(edges_tri, e);
}
}
}
}
}
+
+ for (int i = 0; i < STACK_SIZE(edges_tri); i++) {
+ BMLoop *l_a, *l_b;
+ e = edges_tri[i];
+ if (BM_edge_loop_pair(e, &l_a, &l_b)) {
+ BMFace *f_array[2] = {l_a->f, l_b->f};
+ BM_faces_join(bm, f_array, 2, false);
+ if (e->l == NULL) {
+ BM_edge_kill(bm, e);
+ }
+ }
+ }
+ MEM_freeN(edges_tri);
}
#endif /* USE_TRIANGULATE */
@@ -1083,7 +1170,7 @@ static bool bm_decim_edge_collapse(
return false;
}
- bm_decim_calc_target_co(e, optimize_co, vquadrics);
+ bm_decim_calc_target_co_fl(e, optimize_co, vquadrics);
/* check if this would result in an overlapping face */
if (UNLIKELY(bm_edge_collapse_is_degenerate_flip(e, optimize_co))) {
@@ -1205,7 +1292,8 @@ static bool bm_decim_edge_collapse(
* \param factor face count multiplier [0 - 1]
* \param vweights Optional array of vertex aligned weights [0 - 1],
* a vertex group is the usual source for this.
- * \param axis: Axis of symmetry, -1 to disable mirror decimate.
+ * \param symmetry_axis: Axis of symmetry, -1 to disable mirror decimate.
+ * \param symmetry_eps: Threshold when matching mirror verts.
*/
void BM_mesh_decimate_collapse(
BMesh *bm,
@@ -1219,7 +1307,6 @@ void BM_mesh_decimate_collapse(
Quadric *vquadrics; /* vert index aligned quadrics */
int tot_edge_orig;
int face_tot_target;
- bool use_triangulate;
CD_UseFlag customdata_flag = 0;
@@ -1229,8 +1316,11 @@ void BM_mesh_decimate_collapse(
#endif
#ifdef USE_TRIANGULATE
+ int edges_tri_tot = 0;
/* temp convert quads to triangles */
- use_triangulate = bm_decim_triangulate_begin(bm);
+ bool use_triangulate = bm_decim_triangulate_begin(bm, &edges_tri_tot);
+#else
+ UNUSED_VARS(do_triangulate);
#endif
@@ -1352,7 +1442,7 @@ void BM_mesh_decimate_collapse(
goto invalidate;
}
- bm_decim_calc_target_co(e, optimize_co, vquadrics);
+ bm_decim_calc_target_co_fl(e, optimize_co, vquadrics);
if (e_index_mirr == e_index) {
optimize_co[symmetry_axis] = 0.0f;
@@ -1415,7 +1505,7 @@ invalidate:
/* its possible we only had triangles, skip this step in that case */
if (LIKELY(use_triangulate)) {
/* temp convert quads to triangles */
- bm_decim_triangulate_end(bm);
+ bm_decim_triangulate_end(bm, edges_tri_tot);
}
}
#endif
diff --git a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
index ad35d57f35b..978cceee37c 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
@@ -335,7 +335,7 @@ void BM_mesh_decimate_dissolve_ex(
/* update normal */
BM_face_normal_update(f_new);
if (oflag_out) {
- BMO_elem_flag_enable(bm, f_new, oflag_out);
+ BMO_face_flag_enable(bm, f_new, oflag_out);
}
/* re-calculate costs */
diff --git a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
index db60b3e15e1..0fc571bc0a8 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
@@ -213,7 +213,7 @@ void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const bool
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(v, BM_ELEM_TAG) && bm_vert_dissolve_fan_test(v)) {
#ifdef USE_WALKER
- BMO_elem_flag_enable(bm, v, ELE_VERT_TAG);
+ BMO_vert_flag_enable(bm, v, ELE_VERT_TAG);
#endif
BM_elem_index_set(v, VERT_INDEX_INIT); /* set_dirty! */
}
@@ -238,7 +238,7 @@ void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const bool
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
if (v->e && (BM_elem_index_get(v) == VERT_INDEX_INIT)) {
#ifdef USE_WALKER
- if (BMO_elem_flag_test(bm, v, ELE_VERT_TAG))
+ if (BMO_vert_flag_test(bm, v, ELE_VERT_TAG))
#endif
{
/* check again incase the topology changed */
diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c
index e6437aa6c59..58234ddf3bd 100644
--- a/source/blender/bmesh/tools/bmesh_intersect.c
+++ b/source/blender/bmesh/tools/bmesh_intersect.c
@@ -53,6 +53,8 @@
#include "BLI_buffer.h"
#include "bmesh.h"
+#include "intern/bmesh_private.h"
+
#include "bmesh_intersect.h" /* own include */
#include "tools/bmesh_edgesplit.h"
@@ -85,6 +87,8 @@
/* insert bl_debug_draw_quad_clear... here */
#endif
+// #define USE_DUMP
+
static void tri_v3_scale(
float v1[3], float v2[3], float v3[3],
const float t)
@@ -533,8 +537,6 @@ static void bm_isect_tri_tri(
const float *f_b_cos[3] = {UNPACK3_EX(, fv_b, ->co)};
float f_a_nor[3];
float f_b_nor[3];
- int a_mask = 0;
- int b_mask = 0;
unsigned int i;
@@ -554,6 +556,22 @@ static void bm_isect_tri_tri(
STACK_INIT(iv_ls_a, ARRAY_SIZE(iv_ls_a));
STACK_INIT(iv_ls_b, ARRAY_SIZE(iv_ls_b));
+#define VERT_VISIT_A _FLAG_WALK
+#define VERT_VISIT_B _FLAG_WALK_ALT
+
+#define STACK_PUSH_TEST_A(ele) \
+ if (BM_ELEM_API_FLAG_TEST(ele, VERT_VISIT_A) == 0) { \
+ BM_ELEM_API_FLAG_ENABLE(ele, VERT_VISIT_A); \
+ STACK_PUSH(iv_ls_a, ele); \
+ } ((void)0)
+
+#define STACK_PUSH_TEST_B(ele) \
+ if (BM_ELEM_API_FLAG_TEST(ele, VERT_VISIT_B) == 0) { \
+ BM_ELEM_API_FLAG_ENABLE(ele, VERT_VISIT_B); \
+ STACK_PUSH(iv_ls_b, ele); \
+ } ((void)0)
+
+
/* vert-vert
* --------- */
{
@@ -565,22 +583,18 @@ static void bm_isect_tri_tri(
unsigned int i_b;
for (i_b = 0; i_b < 3; i_b++) {
if (len_squared_v3v3(fv_a[i_a]->co, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) {
- if (!((1 << i_a) & a_mask)) {
- STACK_PUSH(iv_ls_a, fv_a[i_a]);
- a_mask |= (1 << i_a);
#ifdef USE_DUMP
+ if (BM_ELEM_API_FLAG_TEST(fv_a[i_a], VERT_VISIT) == 0) {
printf(" ('VERT-VERT-A') %d, %d),\n",
i_a, BM_elem_index_get(fv_a[i_a]));
-#endif
}
- if (!((1 << i_b) & b_mask)) {
- STACK_PUSH(iv_ls_b, fv_b[i_b]);
- b_mask |= (1 << i_b);
-#ifdef USE_DUMP
+ if (BM_ELEM_API_FLAG_TEST(fv_b[i_b], VERT_VISIT) == 0) {
printf(" ('VERT-VERT-B') %d, %d),\n",
i_b, BM_elem_index_get(fv_b[i_b]));
-#endif
}
+#endif
+ STACK_PUSH_TEST_A(fv_a[i_a]);
+ STACK_PUSH_TEST_B(fv_b[i_b]);
}
}
}
@@ -591,22 +605,25 @@ static void bm_isect_tri_tri(
{
unsigned int i_a;
for (i_a = 0; i_a < 3; i_a++) {
- if (!((1 << i_a) & a_mask)) {
+ if (BM_ELEM_API_FLAG_TEST(fv_a[i_a], VERT_VISIT_A) == 0) {
unsigned int i_b_e0;
for (i_b_e0 = 0; i_b_e0 < 3; i_b_e0++) {
unsigned int i_b_e1 = (i_b_e0 + 1) % 3;
- float fac;
- if (((1 << i_b_e0) | (1 << i_b_e1)) & b_mask)
+
+ if (BM_ELEM_API_FLAG_TEST(fv_b[i_b_e0], VERT_VISIT_B) ||
+ BM_ELEM_API_FLAG_TEST(fv_b[i_b_e1], VERT_VISIT_B))
+ {
continue;
- fac = line_point_factor_v3(fv_a[i_a]->co, fv_b[i_b_e0]->co, fv_b[i_b_e1]->co);
+ }
+
+ const float fac = line_point_factor_v3(fv_a[i_a]->co, fv_b[i_b_e0]->co, fv_b[i_b_e1]->co);
if ((fac > 0.0f - s->epsilon.eps) && (fac < 1.0f + s->epsilon.eps)) {
float ix[3];
interp_v3_v3v3(ix, fv_b[i_b_e0]->co, fv_b[i_b_e1]->co, fac);
if (len_squared_v3v3(ix, fv_a[i_a]->co) <= s->epsilon.eps2x_sq) {
BMEdge *e;
- STACK_PUSH(iv_ls_b, fv_a[i_a]);
- // STACK_PUSH(iv_ls_a, fv_a[i_a]);
- a_mask |= (1 << i_a);
+ STACK_PUSH_TEST_B(fv_a[i_a]);
+ // STACK_PUSH_TEST_A(fv_a[i_a]);
e = BM_edge_exists(fv_b[i_b_e0], fv_b[i_b_e1]);
#ifdef USE_DUMP
printf(" ('VERT-EDGE-A', %d, %d),\n",
@@ -629,22 +646,25 @@ static void bm_isect_tri_tri(
{
unsigned int i_b;
for (i_b = 0; i_b < 3; i_b++) {
- if (!((1 << i_b) & b_mask)) {
+ if (BM_ELEM_API_FLAG_TEST(fv_b[i_b], VERT_VISIT_B) == 0) {
unsigned int i_a_e0;
for (i_a_e0 = 0; i_a_e0 < 3; i_a_e0++) {
unsigned int i_a_e1 = (i_a_e0 + 1) % 3;
- float fac;
- if (((1 << i_a_e0) | (1 << i_a_e1)) & a_mask)
+
+ if (BM_ELEM_API_FLAG_TEST(fv_a[i_a_e0], VERT_VISIT_A) ||
+ BM_ELEM_API_FLAG_TEST(fv_a[i_a_e1], VERT_VISIT_A))
+ {
continue;
- fac = line_point_factor_v3(fv_b[i_b]->co, fv_a[i_a_e0]->co, fv_a[i_a_e1]->co);
+ }
+
+ const float fac = line_point_factor_v3(fv_b[i_b]->co, fv_a[i_a_e0]->co, fv_a[i_a_e1]->co);
if ((fac > 0.0f - s->epsilon.eps) && (fac < 1.0f + s->epsilon.eps)) {
float ix[3];
interp_v3_v3v3(ix, fv_a[i_a_e0]->co, fv_a[i_a_e1]->co, fac);
if (len_squared_v3v3(ix, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) {
BMEdge *e;
- STACK_PUSH(iv_ls_a, fv_b[i_b]);
- // STACK_PUSH(iv_ls_b, fv_b[i_b]);
- b_mask |= (1 << i_b);
+ STACK_PUSH_TEST_A(fv_b[i_b]);
+ // STACK_PUSH_NOTEST(iv_ls_b, fv_b[i_b]);
e = BM_edge_exists(fv_a[i_a_e0], fv_a[i_a_e1]);
#ifdef USE_DUMP
printf(" ('VERT-EDGE-B', %d, %d),\n",
@@ -652,7 +672,7 @@ static void bm_isect_tri_tri(
#endif
if (e) {
#ifdef USE_DUMP
- printf(" adding to edge %d\n", BM_elem_index_get(e));
+ printf("# adding to edge %d\n", BM_elem_index_get(e));
#endif
edge_verts_add(s, e, fv_b[i_b], true);
}
@@ -678,17 +698,15 @@ static void bm_isect_tri_tri(
// second check for verts intersecting the triangle
for (i_a = 0; i_a < 3; i_a++) {
- float ix[3];
- if ((1 << i_a) & a_mask)
+ if (BM_ELEM_API_FLAG_TEST(fv_a[i_a], VERT_VISIT_A)) {
continue;
+ }
+
+ float ix[3];
if (isect_point_tri_v3(fv_a[i_a]->co, UNPACK3(t_scale), ix)) {
if (len_squared_v3v3(ix, fv_a[i_a]->co) <= s->epsilon.eps2x_sq) {
- BLI_assert(BLI_array_findindex(iv_ls_a, STACK_SIZE(iv_ls_a), fv_a[i_a]) == -1);
- BLI_assert(BLI_array_findindex(iv_ls_b, STACK_SIZE(iv_ls_b), fv_a[i_a]) == -1);
-
- STACK_PUSH(iv_ls_a, fv_a[i_a]);
- STACK_PUSH(iv_ls_b, fv_a[i_a]);
- a_mask |= (1 << i_a);
+ STACK_PUSH_TEST_A(fv_a[i_a]);
+ STACK_PUSH_TEST_B(fv_a[i_a]);
#ifdef USE_DUMP
printf(" 'VERT TRI-A',\n");
#endif
@@ -707,18 +725,15 @@ static void bm_isect_tri_tri(
tri_v3_scale(UNPACK3(t_scale), 1.0f - s->epsilon.eps2x);
for (i_b = 0; i_b < 3; i_b++) {
- float ix[3];
- if ((1 << i_b) & b_mask)
+ if (BM_ELEM_API_FLAG_TEST(fv_b[i_b], VERT_VISIT_B)) {
continue;
+ }
+ float ix[3];
if (isect_point_tri_v3(fv_b[i_b]->co, UNPACK3(t_scale), ix)) {
if (len_squared_v3v3(ix, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) {
- BLI_assert(BLI_array_findindex((void **)iv_ls_a, STACK_SIZE(iv_ls_a), fv_b[i_b]) == -1);
- BLI_assert(BLI_array_findindex((void **)iv_ls_b, STACK_SIZE(iv_ls_b), fv_b[i_b]) == -1);
-
- STACK_PUSH(iv_ls_a, fv_b[i_b]);
- STACK_PUSH(iv_ls_b, fv_b[i_b]);
- b_mask |= (1 << i_b);
+ STACK_PUSH_TEST_A(fv_b[i_b]);
+ STACK_PUSH_TEST_B(fv_b[i_b]);
#ifdef USE_DUMP
printf(" 'VERT TRI-B',\n");
#endif
@@ -733,7 +748,7 @@ static void bm_isect_tri_tri(
#ifdef USE_DUMP
printf("# OVERLAP\n");
#endif
- return;
+ goto finally;
}
normal_tri_v3(f_a_nor, UNPACK3(f_a_cos));
@@ -742,43 +757,45 @@ static void bm_isect_tri_tri(
/* edge-tri & edge-edge
* -------------------- */
{
- unsigned int i_e0;
- for (i_e0 = 0; i_e0 < 3; i_e0++) {
- unsigned int i_e1 = (i_e0 + 1) % 3;
+ for (unsigned int i_a_e0 = 0; i_a_e0 < 3; i_a_e0++) {
+ unsigned int i_a_e1 = (i_a_e0 + 1) % 3;
enum ISectType side;
BMVert *iv;
- if (((1 << i_e0) | (1 << i_e1)) & a_mask)
+
+ if (BM_ELEM_API_FLAG_TEST(fv_a[i_a_e0], VERT_VISIT_A) ||
+ BM_ELEM_API_FLAG_TEST(fv_a[i_a_e1], VERT_VISIT_A))
+ {
continue;
- iv = bm_isect_edge_tri(s, fv_a[i_e0], fv_a[i_e1], fv_b, b_index, f_b_cos, f_b_nor, &side);
+ }
+
+ iv = bm_isect_edge_tri(s, fv_a[i_a_e0], fv_a[i_a_e1], fv_b, b_index, f_b_cos, f_b_nor, &side);
if (iv) {
- BLI_assert(BLI_array_findindex((void **)iv_ls_a, STACK_SIZE(iv_ls_a), iv) == -1);
- BLI_assert(BLI_array_findindex((void **)iv_ls_b, STACK_SIZE(iv_ls_b), iv) == -1);
- STACK_PUSH(iv_ls_a, iv);
- STACK_PUSH(iv_ls_b, iv);
+ STACK_PUSH_TEST_A(iv);
+ STACK_PUSH_TEST_B(iv);
#ifdef USE_DUMP
printf(" ('EDGE-TRI-A', %d),\n", side);
#endif
}
}
- for (i_e0 = 0; i_e0 < 3; i_e0++) {
- unsigned int i_e1 = (i_e0 + 1) % 3;
+ for (unsigned int i_b_e0 = 0; i_b_e0 < 3; i_b_e0++) {
+ unsigned int i_b_e1 = (i_b_e0 + 1) % 3;
enum ISectType side;
BMVert *iv;
- if (((1 << i_e0) | (1 << i_e1)) & b_mask)
+
+ if (BM_ELEM_API_FLAG_TEST(fv_b[i_b_e0], VERT_VISIT_B) ||
+ BM_ELEM_API_FLAG_TEST(fv_b[i_b_e1], VERT_VISIT_B))
+ {
continue;
- iv = bm_isect_edge_tri(s, fv_b[i_e0], fv_b[i_e1], fv_a, a_index, f_a_cos, f_a_nor, &side);
+ }
+
+ iv = bm_isect_edge_tri(s, fv_b[i_b_e0], fv_b[i_b_e1], fv_a, a_index, f_a_cos, f_a_nor, &side);
if (iv) {
- /* check this wasn't handled above */
- if (!(side >= IX_EDGE_TRI_EDGE0 && side <= IX_EDGE_TRI_EDGE2)) {
- BLI_assert(BLI_array_findindex((void **)iv_ls_a, STACK_SIZE(iv_ls_a), iv) == -1);
- BLI_assert(BLI_array_findindex((void **)iv_ls_b, STACK_SIZE(iv_ls_b), iv) == -1);
- STACK_PUSH(iv_ls_a, iv);
- STACK_PUSH(iv_ls_b, iv);
+ STACK_PUSH_TEST_A(iv);
+ STACK_PUSH_TEST_B(iv);
#ifdef USE_DUMP
- printf(" ('EDGE-RAY-B', %d),\n", side);
+ printf(" ('EDGE-TRI-B', %d),\n", side);
#endif
- }
}
}
}
@@ -828,6 +845,15 @@ static void bm_isect_tri_tri(
// BLI_assert(len(ie_vs) <= 2)
}
}
+
+finally:
+ for (i = 0; i < STACK_SIZE(iv_ls_a); i++) {
+ BM_ELEM_API_FLAG_DISABLE(iv_ls_a[i], VERT_VISIT_A); \
+ }
+ for (i = 0; i < STACK_SIZE(iv_ls_b); i++) {
+ BM_ELEM_API_FLAG_DISABLE(iv_ls_b[i], VERT_VISIT_B); \
+ }
+
}
#ifdef USE_BVH
@@ -873,7 +899,7 @@ static void raycast_callback(void *userdata,
#endif
#ifdef USE_DUMP
- printf("%s: Adding depth %f\n", __func__, depth);
+ printf("%s: Adding depth %f\n", __func__, dist);
#endif
BLI_buffer_append(raycast_data->z_buffer, float, dist);
}
@@ -909,7 +935,7 @@ static int isect_bvhtree_point_v3(
&raycast_data);
#ifdef USE_DUMP
- printf("%s: Total intersections: %d\n", __func__, raycast_data.num_isect);
+ printf("%s: Total intersections: %d\n", __func__, z_buffer.count);
#endif
int num_isect;
diff --git a/source/blender/collada/ArmatureExporter.cpp b/source/blender/collada/ArmatureExporter.cpp
index 36ab85b9b5b..4f5cf83f5ca 100644
--- a/source/blender/collada/ArmatureExporter.cpp
+++ b/source/blender/collada/ArmatureExporter.cpp
@@ -67,12 +67,19 @@ void ArmatureExporter::add_armature_bones(Object *ob_arm, Scene *sce,
std::list<Object *>& child_objects)
{
// write bone nodes
+
+ bArmature * armature = (bArmature *)ob_arm->data;
+ ED_armature_to_edit(armature);
+
bArmature *arm = (bArmature *)ob_arm->data;
for (Bone *bone = (Bone *)arm->bonebase.first; bone; bone = bone->next) {
// start from root bones
if (!bone->parent)
add_bone_node(bone, ob_arm, sce, se, child_objects);
}
+
+ ED_armature_from_edit(armature);
+ ED_armature_edit_free(armature);
}
void ArmatureExporter::write_bone_URLs(COLLADASW::InstanceController &ins, Object *ob_arm, Bone *bone)
@@ -167,12 +174,30 @@ void ArmatureExporter::add_bone_node(Bone *bone, Object *ob_arm, Scene *sce,
node.setNodeName(node_name);
node.setNodeSid(node_sid);
-#if 0
- if (BLI_listbase_is_empty(&bone->childbase) || BLI_listbase_count_ex(&bone->childbase, 2) == 2) {
- add_blender_leaf_bone( bone, ob_arm, node);
+ if (this->export_settings->use_blender_profile)
+ {
+ if (bone->parent) {
+ if (bone->flag & BONE_CONNECTED) {
+ node.addExtraTechniqueParameter("blender", "connect", true);
+ }
+ }
+ std::string layers = BoneExtended::get_bone_layers(bone->layer);
+ node.addExtraTechniqueParameter("blender", "layer", layers);
+
+ bArmature *armature = (bArmature *)ob_arm->data;
+ EditBone *ebone = bc_get_edit_bone(armature, bone->name);
+ if (ebone && ebone->roll != 0)
+ {
+ node.addExtraTechniqueParameter("blender", "roll", ebone->roll);
+ }
+ if (bc_is_leaf_bone(bone))
+ {
+ node.addExtraTechniqueParameter("blender", "tip_x", bone->arm_tail[0] - bone->arm_head[0]);
+ node.addExtraTechniqueParameter("blender", "tip_y", bone->arm_tail[1] - bone->arm_head[1]);
+ node.addExtraTechniqueParameter("blender", "tip_z", bone->arm_tail[2] - bone->arm_head[2]);
+ }
}
- else {
-#endif
+
node.start();
add_bone_transform(ob_arm, bone, node);
@@ -227,25 +252,6 @@ void ArmatureExporter::add_bone_node(Bone *bone, Object *ob_arm, Scene *sce,
}
}
-//#if 1
-void ArmatureExporter::add_blender_leaf_bone(Bone *bone, Object *ob_arm, COLLADASW::Node& node)
-{
- node.start();
-
- add_bone_transform(ob_arm, bone, node);
-
- node.addExtraTechniqueParameter("blender", "tip_x", bone->tail[0]);
- node.addExtraTechniqueParameter("blender", "tip_y", bone->tail[1]);
- node.addExtraTechniqueParameter("blender", "tip_z", bone->tail[2]);
-
- /*for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
- add_bone_node(child, ob_arm, sce, se, child_objects);
- }*/
- node.end();
-
-}
-//#endif
-
void ArmatureExporter::add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW::Node& node)
{
//bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, bone->name);
diff --git a/source/blender/collada/ArmatureExporter.h b/source/blender/collada/ArmatureExporter.h
index 931cc5d2988..883a6aca847 100644
--- a/source/blender/collada/ArmatureExporter.h
+++ b/source/blender/collada/ArmatureExporter.h
@@ -92,8 +92,6 @@ private:
void add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW::Node& node);
- void add_blender_leaf_bone(Bone *bone, Object *ob_arm, COLLADASW::Node& node);
-
std::string get_controller_id(Object *ob_arm, Object *ob);
void write_bone_URLs(COLLADASW::InstanceController &ins, Object *ob_arm, Bone *bone);
diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp
index fd08e1ebfab..ae43c0a69d2 100644
--- a/source/blender/collada/ArmatureImporter.cpp
+++ b/source/blender/collada/ArmatureImporter.cpp
@@ -50,38 +50,16 @@ static const char *bc_get_joint_name(T *node)
return id.size() ? id.c_str() : node->getOriginalId().c_str();
}
-static EditBone *get_edit_bone(bArmature * armature, char *name) {
- EditBone *eBone;
-
- for (eBone = (EditBone *)armature->edbo->first; eBone; eBone = eBone->next) {
- if (STREQ(name, eBone->name))
- return eBone;
- }
-
- return NULL;
-
-}
-
-
ArmatureImporter::ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, Scene *sce, const ImportSettings *import_settings) :
- import_settings(import_settings),
+ TransformReader(conv),
+ scene(sce),
unit_converter(conv),
- TransformReader(conv),
- scene(sce),
+ import_settings(import_settings),
empty(NULL),
mesh_importer(mesh) {
}
-void ArmatureImporter::clear_extended_boneset()
-{
- for (std::map<std::string, BoneExtended *>::iterator it = extended_bones.begin(); it != extended_bones.end(); ++it) {
- if (it->second != NULL)
- delete it->second;
- }
- extended_bones.clear();
-}
-
ArmatureImporter::~ArmatureImporter()
{
// free skin controller data if we forget to do this earlier
@@ -89,7 +67,6 @@ ArmatureImporter::~ArmatureImporter()
for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) {
it->second.free();
}
- clear_extended_boneset();
}
#if 0
@@ -110,7 +87,7 @@ JointData *ArmatureImporter::get_joint_data(COLLADAFW::Node *node);
#endif
int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBone *parent, int totchild,
- float parent_mat[4][4], bArmature *arm)
+ float parent_mat[4][4], bArmature *arm, std::vector<std::string> &layer_labels)
{
float mat[4][4];
float joint_inv_bind_mat[4][4];
@@ -120,27 +97,39 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
std::vector<COLLADAFW::Node *>::iterator it;
it = std::find(finished_joints.begin(), finished_joints.end(), node);
if (it != finished_joints.end()) return chain_length;
-
- // JointData* jd = get_joint_data(node);
- // TODO rename from Node "name" attrs later
EditBone *bone = ED_armature_edit_bone_add(arm, (char *)bc_get_joint_name(node));
totbone++;
- if (skin && skin->get_joint_inv_bind_matrix(joint_inv_bind_mat, node)) {
- // get original world-space matrix
- invert_m4_m4(mat, joint_inv_bind_mat);
+ /*
+ * We use the inv_bind_shape matrix to apply the armature bind pose as its rest pose.
+ */
+
+ std::map<COLLADAFW::UniqueId, SkinInfo>::iterator skin_it;
+ bool bone_is_not_skinned = true;
+ for (skin_it = skin_by_data_uid.begin(); skin_it != skin_by_data_uid.end(); skin_it++) {
+
+ SkinInfo *b = &skin_it->second;
+ if (b->get_joint_inv_bind_matrix(joint_inv_bind_mat, node)) {
+
+ // get original world-space matrix
+ invert_m4_m4(mat, joint_inv_bind_mat);
- // And make local to armature
- Object *ob_arm = skin->BKE_armature_from_object();
- if (ob_arm) {
- float invmat[4][4];
- invert_m4_m4(invmat, ob_arm->obmat);
- mul_m4_m4m4(mat, invmat, mat);
+ // And make local to armature
+ Object *ob_arm = skin->BKE_armature_from_object();
+ if (ob_arm) {
+ float invmat[4][4];
+ invert_m4_m4(invmat, ob_arm->obmat);
+ mul_m4_m4m4(mat, invmat, mat);
+ }
+
+ bone_is_not_skinned = false;
+ break;
}
}
+
// create a bone even if there's no joint data for it (i.e. it has no influence)
- else {
+ if (bone_is_not_skinned) {
float obmat[4][4];
// bone-space
get_node_mat(obmat, node, NULL, NULL);
@@ -157,22 +146,40 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
if (parent) bone->parent = parent;
float loc[3], size[3], rot[3][3];
- float angle;
- float vec[3] = {0.0f, 0.5f, 0.0f};
- mat4_to_loc_rot_size(loc, rot, size, mat);
- //copy_m3_m4(bonemat,mat);
- mat3_to_vec_roll(rot, vec, &angle);
-
- bone->roll = angle;
- // set head
- copy_v3_v3(bone->head, mat[3]);
+ BoneExtensionMap &extended_bones = bone_extension_manager.getExtensionMap(arm);
+ BoneExtended &be = add_bone_extended(bone, node, totchild, layer_labels, extended_bones);
+ int layer = be.get_bone_layers();
+ if (layer) bone->layer = layer;
+ arm->layer |= layer; // ensure that all populated bone layers are visible after import
+
+ float *tail = be.get_tail();
+ int use_connect = be.get_use_connect();
+
+ switch (use_connect) {
+ case 1: bone->flag |= BONE_CONNECTED;
+ break;
+ case 0: bone->flag &= ~BONE_CONNECTED;
+ case -1: break; // not defined
+ }
- // set tail, don't set it to head because 0-length bones are not allowed
- add_v3_v3v3(bone->tail, bone->head, vec);
+ if (be.has_roll()) {
+ bone->roll = be.get_roll();
+ }
+ else {
+ float angle;
+ mat4_to_loc_rot_size(loc, rot, size, mat);
+ mat3_to_vec_roll(rot, NULL, &angle);
+ }
+ copy_v3_v3(bone->head, mat[3]);
+ add_v3_v3v3(bone->tail, bone->head, tail); //tail must be non zero
/* find smallest bone length in armature (used later for leaf bone length) */
if (parent) {
+ if (use_connect == 1) {
+ copy_v3_v3(parent->tail, bone->head);
+ }
+
/* guess reasonable leaf bone length */
float length = len_v3v3(parent->head, bone->head);
if ((length < leaf_bone_length || totbone == 0) && length > MINIMUM_BONE_LENGTH) {
@@ -182,16 +189,12 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
COLLADAFW::NodePointerArray& children = node->getChildNodes();
- BoneExtended &be = add_bone_extended(bone, node);
- be.set_leaf_bone(true);
-
for (unsigned int i = 0; i < children.getCount(); i++) {
- int cl = create_bone(skin, children[i], bone, children.getCount(), mat, arm);
+ int cl = create_bone(skin, children[i], bone, children.getCount(), mat, arm, layer_labels);
if (cl > chain_length)
chain_length = cl;
}
-
bone->length = len_v3v3(bone->head, bone->tail);
joint_by_uid[node->getUniqueId()] = node;
finished_joints.push_back(node);
@@ -207,35 +210,43 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
* tail locations for the affected bones (nodes which don't have any connected child)
* Hint: The extended_bones set gets populated in ArmatureImporter::create_bone
**/
-void ArmatureImporter::fix_leaf_bones(bArmature *armature, Bone *bone)
+void ArmatureImporter::fix_leaf_bone_hierarchy(bArmature *armature, Bone *bone, bool fix_orientation)
{
- /* armature has no bones */
if (bone == NULL)
return;
- BoneExtended *be = extended_bones[bone->name];
- if (be != NULL && be->is_leaf_bone() ) {
+ if (bc_is_leaf_bone(bone)) {
+ BoneExtensionMap &extended_bones = bone_extension_manager.getExtensionMap(armature);
+ BoneExtended *be = extended_bones[bone->name];
+ EditBone *ebone = bc_get_edit_bone(armature, bone->name);
+ fix_leaf_bone(armature, ebone, be, fix_orientation);
+ }
+
+ for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
+ fix_leaf_bone_hierarchy(armature, child, fix_orientation);
+ }
+}
+
+void ArmatureImporter::fix_leaf_bone(bArmature *armature, EditBone *ebone, BoneExtended *be , bool fix_orientation)
+{
+ if (be == NULL || !be->has_tail()) {
+
/* Collada only knows Joints, Here we guess a reasonable leaf bone length */
float leaf_length = (leaf_bone_length == FLT_MAX) ? 1.0 : leaf_bone_length;
- EditBone *ebone = get_edit_bone(armature, bone->name);
+
float vec[3];
- if (this->import_settings->fix_orientation) {
- if (ebone->parent != NULL) {
- EditBone *parent = ebone->parent;
- sub_v3_v3v3(vec, ebone->head, parent->tail);
- if (len_squared_v3(vec) < MINIMUM_BONE_LENGTH)
- {
- sub_v3_v3v3(vec, parent->tail, parent->head);
- }
- }
- else {
- vec[2] = 0.1f;
- sub_v3_v3v3(vec, ebone->tail, ebone->head);
+ if (fix_orientation && ebone->parent != NULL) {
+ EditBone *parent = ebone->parent;
+ sub_v3_v3v3(vec, ebone->head, parent->head);
+ if (len_squared_v3(vec) < MINIMUM_BONE_LENGTH)
+ {
+ sub_v3_v3v3(vec, parent->tail, parent->head);
}
}
else {
+ vec[2] = 0.1f;
sub_v3_v3v3(vec, ebone->tail, ebone->head);
}
@@ -243,9 +254,20 @@ void ArmatureImporter::fix_leaf_bones(bArmature *armature, Bone *bone)
mul_v3_fl(vec, leaf_length);
add_v3_v3v3(ebone->tail, ebone->head, vec);
}
+}
+
+void ArmatureImporter::fix_parent_connect(bArmature *armature, Bone *bone)
+{
+ /* armature has no bones */
+ if (bone == NULL)
+ return;
+
+ if (bone->parent && bone->flag & BONE_CONNECTED) {
+ copy_v3_v3(bone->parent->tail, bone->head);
+ }
for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
- fix_leaf_bones(armature, child);
+ fix_parent_connect(armature, child);
}
}
@@ -253,6 +275,7 @@ void ArmatureImporter::fix_leaf_bones(bArmature *armature, Bone *bone)
void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone, int clip)
{
+ BoneExtensionMap &extended_bones = bone_extension_manager.getExtensionMap(armature);
BoneExtended *dominant_child = NULL;
int maxlen = 0;
Bone *child;
@@ -281,8 +304,8 @@ void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone
BoneExtended *pbe = extended_bones[parentbone->name];
if (dominant_child != NULL) {
/* Found a valid chain. Now connect current bone with that chain.*/
- EditBone *pebone = get_edit_bone(armature, parentbone->name);
- EditBone *cebone = get_edit_bone(armature, dominant_child->get_name());
+ EditBone *pebone = bc_get_edit_bone(armature, parentbone->name);
+ EditBone *cebone = bc_get_edit_bone(armature, dominant_child->get_name());
if (pebone && !(cebone->flag & BONE_CONNECTED)) {
float vec[3];
@@ -418,11 +441,11 @@ ArmatureJoints& ArmatureImporter::get_armature_joints(Object *ob_arm)
return armature_joints.back();
}
#endif
-void ArmatureImporter::create_armature_bones( )
+void ArmatureImporter::create_armature_bones(std::vector<Object *> &ob_arms)
{
std::vector<COLLADAFW::Node *>::iterator ri;
+ std::vector<std::string> layer_labels;
- leaf_bone_length = FLT_MAX;
//if there is an armature created for root_joint next root_joint
for (ri = root_joints.begin(); ri != root_joints.end(); ri++) {
if (get_armature_for_joint(*ri) != NULL) continue;
@@ -442,32 +465,36 @@ void ArmatureImporter::create_armature_bones( )
continue;
}
- clear_extended_boneset();
-
ED_armature_to_edit(armature);
+ armature->layer = 0; // layer is set according to imported bone set in create_bone()
- create_bone(NULL, *ri , NULL, (*ri)->getChildNodes().getCount(), NULL, armature);
+ create_bone(NULL, *ri , NULL, (*ri)->getChildNodes().getCount(), NULL, armature, layer_labels);
+ if (this->import_settings->find_chains) {
+ connect_bone_chains(armature, (Bone *)armature->bonebase.first, UNLIMITED_CHAIN_MAX);
+ }
/* exit armature edit mode to populate the Armature object */
ED_armature_from_edit(armature);
ED_armature_edit_free(armature);
- /* and step back to edit mode to fix the leaf nodes */
ED_armature_to_edit(armature);
- connect_bone_chains(armature, (Bone *)armature->bonebase.first, UNLIMITED_CHAIN_MAX);
- fix_leaf_bones(armature, (Bone *)armature->bonebase.first);
-
- // exit armature edit mode
+ fix_leaf_bone_hierarchy(armature, (Bone *)armature->bonebase.first, this->import_settings->fix_orientation);
unskinned_armature_map[(*ri)->getUniqueId()] = ob_arm;
ED_armature_from_edit(armature);
ED_armature_edit_free(armature);
+
+ int index = std::find(ob_arms.begin(), ob_arms.end(), ob_arm) - ob_arms.begin();
+ if (index == 0) {
+ ob_arms.push_back(ob_arm);
+ }
+
DAG_id_tag_update(&ob_arm->id, OB_RECALC_OB | OB_RECALC_DATA);
}
}
-void ArmatureImporter::create_armature_bones(SkinInfo& skin)
+Object *ArmatureImporter::create_armature_bones(SkinInfo& skin)
{
// just do like so:
// - get armature
@@ -513,6 +540,7 @@ void ArmatureImporter::create_armature_bones(SkinInfo& skin)
SkinInfo *a = &skin;
Object *shared = NULL;
std::vector<COLLADAFW::Node *> skin_root_joints;
+ std::vector<std::string> layer_labels;
std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it;
for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) {
@@ -558,11 +586,8 @@ void ArmatureImporter::create_armature_bones(SkinInfo& skin)
bArmature * armature = (bArmature *)ob_arm->data;
ED_armature_to_edit(armature);
- clear_extended_boneset();
-
totbone = 0;
// bone_direction_row = 1; // TODO: don't default to Y but use asset and based on it decide on default row
- leaf_bone_length = FLT_MAX;
// create bones
/*
@@ -578,7 +603,8 @@ void ArmatureImporter::create_armature_bones(SkinInfo& skin)
// since root_joints may contain joints for multiple controllers, we need to filter
if (skin.uses_joint_or_descendant(*ri)) {
- create_bone(&skin, *ri, NULL, (*ri)->getChildNodes().getCount(), NULL, armature);
+
+ create_bone(&skin, *ri, NULL, (*ri)->getChildNodes().getCount(), NULL, armature, layer_labels);
if (joint_parent_map.find((*ri)->getUniqueId()) != joint_parent_map.end() && !skin.get_parent())
skin.set_parent(joint_parent_map[(*ri)->getUniqueId()]);
@@ -589,18 +615,17 @@ void ArmatureImporter::create_armature_bones(SkinInfo& skin)
ED_armature_from_edit(armature);
ED_armature_edit_free(armature);
- /* and step back to edit mode to fix the leaf nodes */
ED_armature_to_edit(armature);
-
- if (armature->bonebase.first) {
- /* Do this only if Armature has bones */
+ if (this->import_settings->find_chains) {
connect_bone_chains(armature, (Bone *)armature->bonebase.first, UNLIMITED_CHAIN_MAX);
- fix_leaf_bones(armature, (Bone *)armature->bonebase.first);
}
- // exit armature edit mode
+ fix_leaf_bone_hierarchy(armature, (Bone *)armature->bonebase.first, this->import_settings->fix_orientation);
ED_armature_from_edit(armature);
ED_armature_edit_free(armature);
+
DAG_id_tag_update(&ob_arm->id, OB_RECALC_OB | OB_RECALC_DATA);
+
+ return ob_arm;
}
void ArmatureImporter::set_pose(Object *ob_arm, COLLADAFW::Node *root_node, const char *parentname, float parent_mat[4][4])
@@ -675,22 +700,42 @@ void ArmatureImporter::add_root_joint(COLLADAFW::Node *node)
#endif
// here we add bones to armatures, having armatures previously created in write_controller
-void ArmatureImporter::make_armatures(bContext *C)
+void ArmatureImporter::make_armatures(bContext *C, std::vector<Object *> &objects_to_scale)
{
+ std::vector<Object *> ob_arms;
std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it;
+
+ leaf_bone_length = FLT_MAX; /*TODO: Make this work for more than one armature in the import file*/
+
for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) {
SkinInfo& skin = it->second;
- create_armature_bones(skin);
+ Object *ob_arm = create_armature_bones(skin);
// link armature with a mesh object
const COLLADAFW::UniqueId &uid = skin.get_controller_uid();
const COLLADAFW::UniqueId *guid = get_geometry_uid(uid);
if (guid != NULL) {
Object *ob = mesh_importer->get_object_by_geom_uid(*guid);
- if (ob)
+ if (ob) {
skin.link_armature(C, ob, joint_by_uid, this);
+
+ std::vector<Object *>::iterator ob_it = std::find(objects_to_scale.begin(), objects_to_scale.end(), ob);
+
+ if (ob_it != objects_to_scale.end()) {
+ int index = ob_it - objects_to_scale.begin();
+ objects_to_scale.erase(objects_to_scale.begin() + index);
+ }
+
+ if (std::find(objects_to_scale.begin(), objects_to_scale.end(), ob_arm) == objects_to_scale.end()) {
+ objects_to_scale.push_back(ob_arm);
+ }
+
+ if (std::find(ob_arms.begin(), ob_arms.end(), ob_arm) == ob_arms.end()) {
+ ob_arms.push_back(ob_arm);
+ }
+ }
else
fprintf(stderr, "Cannot find object to link armature with.\n");
}
@@ -707,7 +752,23 @@ void ArmatureImporter::make_armatures(bContext *C)
}
//for bones without skins
- create_armature_bones();
+ create_armature_bones(ob_arms);
+
+ // Fix bone relations
+ std::vector<Object *>::iterator ob_arm_it;
+ for (ob_arm_it = ob_arms.begin(); ob_arm_it != ob_arms.end(); ob_arm_it++) {
+
+ Object *ob_arm = *ob_arm_it;
+ bArmature *armature = (bArmature *)ob_arm->data;
+
+ /* and step back to edit mode to fix the leaf nodes */
+ ED_armature_to_edit(armature);
+
+ fix_parent_connect(armature, (Bone *)armature->bonebase.first);
+
+ ED_armature_from_edit(armature);
+ ED_armature_edit_free(armature);
+ }
}
#if 0
@@ -894,70 +955,55 @@ bool ArmatureImporter::get_joint_bind_mat(float m[4][4], COLLADAFW::Node *joint)
return found;
}
-
-/**
- * BoneExtended is a helper class needed for the Bone chain finder
- * See ArmatureImporter::fix_leaf_bones()
- * and ArmatureImporter::connect_bone_chains()
- **/
-
-BoneExtended::BoneExtended(EditBone *aBone)
+BoneExtended &ArmatureImporter::add_bone_extended(EditBone *bone, COLLADAFW::Node *node, int sibcount, std::vector<std::string> &layer_labels, BoneExtensionMap &extended_bones)
{
- this->set_name(aBone->name);
- this->chain_length = 0;
- this->is_leaf = false;
-}
+ BoneExtended *be = new BoneExtended(bone);
+ extended_bones[bone->name] = be;
-char *BoneExtended::get_name()
-{
- return name;
-}
+ TagsMap::iterator etit;
+ ExtraTags *et = 0;
+ etit = uid_tags_map.find(node->getUniqueId().toAscii());
-void BoneExtended::set_name(char *aName)
-{
- BLI_strncpy(name, aName, MAXBONENAME);
-}
+ bool has_connect = false;
+ int connect_type = -1;
-int BoneExtended::get_chain_length()
-{
- return chain_length;
-}
+ if (etit != uid_tags_map.end()) {
-void BoneExtended::set_chain_length(const int aLength)
-{
- chain_length = aLength;
-}
+ float tail[3] = { FLT_MAX, FLT_MAX, FLT_MAX };
+ float roll = 0;
+ std::string layers;
+ et = etit->second;
-void BoneExtended::set_leaf_bone(bool state)
-{
- is_leaf = state;
-}
+ bool has_tail = false;
+ has_tail |= et->setData("tip_x", &tail[0]);
+ has_tail |= et->setData("tip_y", &tail[1]);
+ has_tail |= et->setData("tip_z", &tail[2]);
-bool BoneExtended::is_leaf_bone()
-{
- return is_leaf;
-}
+ has_connect = et->setData("connect", &connect_type);
+ bool has_roll = et->setData("roll", &roll);
+
+ layers = et->setData("layer", layers);
-BoneExtended &ArmatureImporter::add_bone_extended(EditBone *bone, COLLADAFW::Node *node)
-{
+ if (has_tail && !has_connect)
+ {
+ /* got a bone tail definition but no connect info -> bone is not connected */
+ has_connect = true;
+ connect_type = 0;
+ }
- TagsMap::iterator etit;
- ExtraTags *et = 0;
- etit = uid_tags_map.find(node->getUniqueId().toAscii());
- if (etit != uid_tags_map.end()) {
- float x, y, z;
+ be->set_bone_layers(layers, layer_labels);
+ if (has_tail) be->set_tail(tail);
+ if (has_roll) be->set_roll(roll);
+ }
- et = etit->second;
- et->setData("tip_x", &x);
- et->setData("tip_y", &y);
- et->setData("tip_z", &z);
- float vec[3] = { x, y, z };
- copy_v3_v3(bone->tail, bone->head);
- add_v3_v3v3(bone->tail, bone->head, vec);
+ if (!has_connect && this->import_settings->auto_connect) {
+ /* auto connect only whyen parent has exactly one child*/
+ connect_type = sibcount == 1;
}
- BoneExtended *be = new BoneExtended(bone);
- extended_bones[bone->name] = be;
+ be->set_use_connect(connect_type);
+ be->set_leaf_bone(true);
+
return *be;
}
diff --git a/source/blender/collada/ArmatureImporter.h b/source/blender/collada/ArmatureImporter.h
index 732fda80ff1..17173f157e5 100644
--- a/source/blender/collada/ArmatureImporter.h
+++ b/source/blender/collada/ArmatureImporter.h
@@ -59,25 +59,6 @@ extern "C" {
#define UNLIMITED_CHAIN_MAX INT_MAX
#define MINIMUM_BONE_LENGTH 0.000001f
-class BoneExtended {
-
-private:
- char name[MAXBONENAME];
- int chain_length;
- bool is_leaf;
-
-public:
-
- BoneExtended(EditBone *aBone);
- char *get_name();
- int get_chain_length();
-
- void set_name(char *aName);
- void set_chain_length(const int aLength);
- void set_leaf_bone(bool state);
- bool is_leaf_bone();
-};
-
class ArmatureImporter : private TransformReader
{
private:
@@ -87,8 +68,7 @@ private:
// std::map<int, JointData> joint_index_to_joint_info_map;
// std::map<COLLADAFW::UniqueId, int> joint_id_to_joint_index_map;
-
- std::map<std::string, BoneExtended *> extended_bones;
+ BoneExtensionManager bone_extension_manager;
// int bone_direction_row; // XXX not used
float leaf_bone_length;
int totbone;
@@ -125,17 +105,17 @@ private:
#endif
int create_bone(SkinInfo* skin, COLLADAFW::Node *node, EditBone *parent, int totchild,
- float parent_mat[4][4], bArmature *arm);
+ float parent_mat[4][4], bArmature *arm, std::vector<std::string> &layer_labels);
- BoneExtended &add_bone_extended(EditBone *bone, COLLADAFW::Node * node);
- void clear_extended_boneset();
+ BoneExtended &add_bone_extended(EditBone *bone, COLLADAFW::Node * node, int sibcount, std::vector<std::string> &layer_labels, BoneExtensionMap &extended_bones);
- void fix_leaf_bones(bArmature *armature, Bone *bone);
+ void fix_leaf_bone_hierarchy(bArmature *armature, Bone *bone, bool fix_orientation);
+ void fix_leaf_bone(bArmature *armature, EditBone *ebone, BoneExtended *be, bool fix_orientation);
+ void fix_parent_connect(bArmature *armature, Bone *bone);
void connect_bone_chains(bArmature *armature, Bone *bone, const int max_chain_length);
void set_pose( Object *ob_arm, COLLADAFW::Node *root_node, const char *parentname, float parent_mat[4][4]);
-
#if 0
void set_leaf_bone_shapes(Object *ob_arm);
void set_euler_rotmode();
@@ -149,8 +129,8 @@ private:
ArmatureJoints& get_armature_joints(Object *ob_arm);
#endif
- void create_armature_bones(SkinInfo& skin);
- void create_armature_bones( );
+ Object *create_armature_bones(SkinInfo& skin);
+ void create_armature_bones(std::vector<Object *> &arm_objs);
/** TagsMap typedef for uid_tags_map. */
typedef std::map<std::string, ExtraTags*> TagsMap;
@@ -163,7 +143,7 @@ public:
void add_root_joint(COLLADAFW::Node *node, Object *parent);
// here we add bones to armatures, having armatures previously created in write_controller
- void make_armatures(bContext *C);
+ void make_armatures(bContext *C, std::vector<Object *> &objects_to_scale);
void make_shape_keys();
diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp
index 45dcf436473..226f319cefd 100644
--- a/source/blender/collada/DocumentImporter.cpp
+++ b/source/blender/collada/DocumentImporter.cpp
@@ -239,7 +239,7 @@ void DocumentImporter::finish()
mesh_importer.optimize_material_assignements();
armature_importer.set_tags_map(this->uid_tags_map);
- armature_importer.make_armatures(mContext);
+ armature_importer.make_armatures(mContext, *objects_to_scale);
armature_importer.make_shape_keys();
DAG_relations_tag_update(bmain);
@@ -416,7 +416,7 @@ Object *DocumentImporter::create_instance_node(Object *source_ob, COLLADAFW::Nod
{
fprintf(stderr, "create <instance_node> under node id=%s from node id=%s\n", instance_node ? instance_node->getOriginalId().c_str() : NULL, source_node ? source_node->getOriginalId().c_str() : NULL);
- Object *obn = BKE_object_copy(source_ob);
+ Object *obn = BKE_object_copy(G.main, source_ob);
DAG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
BKE_scene_base_add(sce, obn);
@@ -517,7 +517,7 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA
name.c_str());
if (is_joint) {
- if (parent_node == NULL) {
+ if (parent_node == NULL && !is_library_node) {
// A Joint on root level is a skeleton without root node.
// Here we add the armature "on the fly":
par = bc_add_object(sce, OB_ARMATURE, std::string("Armature").c_str());
@@ -904,6 +904,7 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia
i++;
}
}
+
// EMISSION
// color
if (ef->getEmission().isColor()) {
@@ -919,8 +920,22 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia
i++;
}
}
-
- if (ef->getOpacity().isTexture()) {
+
+ // TRANSPARENT
+ // color
+ if (ef->getOpacity().isColor()) {
+ col = ef->getTransparent().getColor();
+ float alpha = ef->getTransparency().getFloatValue();
+ if (col.isValid()) {
+ alpha *= col.getAlpha(); // Assuming A_ONE opaque mode
+ }
+ if (col.isValid() || alpha < 1.0) {
+ ma->alpha = alpha;
+ ma->mode |= MA_ZTRANSP | MA_TRANSP;
+ }
+ }
+ // texture
+ else if (ef->getOpacity().isTexture()) {
COLLADAFW::Texture ctex = ef->getOpacity().getTexture();
mtex = create_texture(ef, ctex, ma, i, texindex_texarray_map);
if (mtex != NULL) {
@@ -930,22 +945,7 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia
ma->mode |= MA_ZTRANSP | MA_TRANSP;
}
}
- // TRANSPARENT
- // color
-#if 0
- if (ef->getOpacity().isColor()) {
- // XXX don't know what to do here
- }
- // texture
- else if (ef->getOpacity().isTexture()) {
- ctex = ef->getOpacity().getTexture();
- if (mtex != NULL) mtex->mapto &= MAP_ALPHA;
- else {
- mtex = create_texture(ef, ctex, ma, i, texindex_texarray_map);
- if (mtex != NULL) mtex->mapto = MAP_ALPHA;
- }
- }
-#endif
+
material_texture_mapping_map[ma] = texindex_texarray_map;
}
diff --git a/source/blender/collada/EffectExporter.cpp b/source/blender/collada/EffectExporter.cpp
index 13dc1eda580..76b51148509 100644
--- a/source/blender/collada/EffectExporter.cpp
+++ b/source/blender/collada/EffectExporter.cpp
@@ -30,6 +30,7 @@
#include <set>
#include "COLLADASWEffectProfile.h"
+#include "COLLADAFWColorOrTexture.h"
#include "EffectExporter.h"
#include "DocumentExporter.h"
@@ -217,9 +218,9 @@ void EffectsExporter::operator()(Material *ma, Object *ob)
// transparency
if (ma->mode & MA_TRANSP) {
// Tod: because we are in A_ONE mode transparency is calculated like this:
- ep.setTransparency(ma->alpha, false, "transparency");
- // cot = getcol(1.0f, 1.0f, 1.0f, 1.0f);
- // ep.setTransparent(cot);
+ cot = getcol(1.0f, 1.0f, 1.0f, ma->alpha);
+ ep.setTransparent(cot);
+ ep.setOpaque(COLLADASW::EffectProfile::A_ONE);
}
// emission
diff --git a/source/blender/collada/ErrorHandler.cpp b/source/blender/collada/ErrorHandler.cpp
index b271604f839..98aa85f8a9b 100644
--- a/source/blender/collada/ErrorHandler.cpp
+++ b/source/blender/collada/ErrorHandler.cpp
@@ -79,7 +79,7 @@ bool ErrorHandler::handleError(const COLLADASaxFWL::IError *error)
COLLADASaxFWL::SaxFWLError *saxFWLError = (COLLADASaxFWL::SaxFWLError *) error;
/*
* Accept non critical errors as warnings (i.e. texture not found)
- * This makes the importer more gracefull, so it now imports what makes sense.
+ * This makes the importer more graceful, so it now imports what makes sense.
*/
if (saxFWLError->getSeverity() == COLLADASaxFWL::IError::SEVERITY_ERROR_NONCRITICAL) {
isError = false;
diff --git a/source/blender/collada/ExportSettings.h b/source/blender/collada/ExportSettings.h
index 3dc7e74379e..9451cac9dae 100644
--- a/source/blender/collada/ExportSettings.h
+++ b/source/blender/collada/ExportSettings.h
@@ -48,6 +48,7 @@ public:
bool triangulate;
bool use_object_instantiation;
+ bool use_blender_profile;
bool sort_by_name;
BC_export_transformation_type export_transformation_type;
bool open_sim;
diff --git a/source/blender/collada/ExtraTags.cpp b/source/blender/collada/ExtraTags.cpp
index 6af61432fda..ea225d8a4ae 100644
--- a/source/blender/collada/ExtraTags.cpp
+++ b/source/blender/collada/ExtraTags.cpp
@@ -85,32 +85,45 @@ std::string ExtraTags::asString(std::string tag, bool *ok)
}
-void ExtraTags::setData(std::string tag, short *data)
+bool ExtraTags::setData(std::string tag, short *data)
{
bool ok = false;
int tmp = asInt(tag, &ok);
if (ok)
*data = (short)tmp;
+ return ok;
}
-void ExtraTags::setData(std::string tag, int *data)
+
+bool ExtraTags::setData(std::string tag, int *data)
{
bool ok = false;
int tmp = asInt(tag, &ok);
if (ok)
*data = tmp;
+ return ok;
}
-void ExtraTags::setData(std::string tag, float *data)
+
+bool ExtraTags::setData(std::string tag, float *data)
{
bool ok = false;
float tmp = asFloat(tag, &ok);
if (ok)
*data = tmp;
+ return ok;
}
-void ExtraTags::setData(std::string tag, char *data)
+
+bool ExtraTags::setData(std::string tag, char *data)
{
bool ok = false;
int tmp = asInt(tag, &ok);
if (ok)
*data = (char)tmp;
+ return ok;
+}
+
+std::string ExtraTags::setData(std::string tag, std::string &data)
+{
+ bool ok = false;
+ std::string tmp = asString(tag, &ok);
+ return (ok) ? tmp : data;
}
-
diff --git a/source/blender/collada/ExtraTags.h b/source/blender/collada/ExtraTags.h
index 03a311a7e86..ad272dcba65 100644
--- a/source/blender/collada/ExtraTags.h
+++ b/source/blender/collada/ExtraTags.h
@@ -43,17 +43,18 @@ public:
bool addTag(std::string tag, std::string data);
/** Set given short pointer to value of tag, if it exists. */
- void setData(std::string tag, short *data);
+ bool setData(std::string tag, short *data);
/** Set given int pointer to value of tag, if it exists. */
- void setData(std::string tag, int *data);
+ bool setData(std::string tag, int *data);
/** Set given float pointer to value of tag, if it exists. */
- void setData(std::string tag, float *data);
+ bool setData(std::string tag, float *data);
/** Set given char pointer to value of tag, if it exists. */
- void setData(std::string tag, char *data);
-
+ bool setData(std::string tag, char *data);
+ std::string setData(std::string tag, std::string &data);
+
/** Return true if the extra tags is for specified profile. */
bool isProfile(std::string profile);
diff --git a/source/blender/collada/ImportSettings.h b/source/blender/collada/ImportSettings.h
index 783f58e6bff..2c52d73e756 100644
--- a/source/blender/collada/ImportSettings.h
+++ b/source/blender/collada/ImportSettings.h
@@ -33,6 +33,7 @@ struct ImportSettings {
public:
bool import_units;
bool find_chains;
+ bool auto_connect;
bool fix_orientation;
int min_chain_length;
char *filepath;
diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp
index a884268fd5e..6ff6de33d56 100644
--- a/source/blender/collada/MeshImporter.cpp
+++ b/source/blender/collada/MeshImporter.cpp
@@ -172,8 +172,7 @@ void UVDataWrapper::getUV(int uv_index, float *uv)
}
}
-VCOLDataWrapper::VCOLDataWrapper(COLLADAFW::MeshVertexData& vdata) : mVData(&vdata){
-}
+VCOLDataWrapper::VCOLDataWrapper(COLLADAFW::MeshVertexData& vdata) : mVData(&vdata) {}
void VCOLDataWrapper::get_vcol(int v_index, MLoopCol *mloopcol)
{
@@ -211,15 +210,27 @@ void VCOLDataWrapper::get_vcol(int v_index, MLoopCol *mloopcol)
MeshImporter::MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Scene *sce) : unitconverter(unitconv), scene(sce), armature_importer(arm) {
}
-void MeshImporter::set_poly_indices(MPoly *mpoly, MLoop *mloop, int loop_index, unsigned int *indices, int loop_count)
+bool MeshImporter::set_poly_indices(MPoly *mpoly, MLoop *mloop, int loop_index, unsigned int *indices, int loop_count)
{
mpoly->loopstart = loop_index;
mpoly->totloop = loop_count;
-
+ bool broken_loop = false;
for (int index=0; index < loop_count; index++) {
+
+ /* Test if loop defines a hole */
+ if (!broken_loop) {
+ for (int i = 0; i < index; i++) {
+ if (indices[i] == indices[index]) {
+ // duplicate index -> not good
+ broken_loop = true;
+ }
+ }
+ }
+
mloop->v = indices[index];
mloop++;
}
+ return broken_loop;
}
void MeshImporter::set_vcol(MLoopCol *mlc, VCOLDataWrapper &vob, int loop_index, COLLADAFW::IndexList &index_list, int count)
@@ -259,29 +270,41 @@ bool MeshImporter::is_nice_mesh(COLLADAFW::Mesh *mesh) // checks if mesh has su
COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives();
const std::string &name = bc_get_dae_name(mesh);
-
+
for (unsigned i = 0; i < prim_arr.getCount(); i++) {
-
+
COLLADAFW::MeshPrimitive *mp = prim_arr[i];
COLLADAFW::MeshPrimitive::PrimitiveType type = mp->getPrimitiveType();
const char *type_str = bc_primTypeToStr(type);
-
+
// OpenCollada passes POLYGONS type for <polylist>
if (type == COLLADAFW::MeshPrimitive::POLYLIST || type == COLLADAFW::MeshPrimitive::POLYGONS) {
COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons *)mp;
COLLADAFW::Polygons::VertexCountArray& vca = mpvc->getGroupedVerticesVertexCountArray();
-
+
+ int hole_count = 0;
+ int nonface_count = 0;
+
for (unsigned int j = 0; j < vca.getCount(); j++) {
int count = vca[j];
- if (count < 3) {
- fprintf(stderr, "Primitive %s in %s has at least one face with vertex count < 3\n",
- type_str, name.c_str());
- return false;
+ if (abs(count) < 3) {
+ nonface_count++;
+ }
+
+ if (count < 0) {
+ hole_count ++;
}
}
-
+
+ if (hole_count > 0) {
+ fprintf(stderr, "WARNING: Primitive %s in %s: %d holes not imported (unsupported)\n", type_str, name.c_str(), hole_count);
+ }
+
+ if (nonface_count > 0) {
+ fprintf(stderr, "WARNING: Primitive %s in %s: %d faces with vertex count < 3 (rejected)\n", type_str, name.c_str(), nonface_count);
+ }
}
else if (type == COLLADAFW::MeshPrimitive::LINES) {
@@ -289,13 +312,13 @@ bool MeshImporter::is_nice_mesh(COLLADAFW::Mesh *mesh) // checks if mesh has su
}
else if (type != COLLADAFW::MeshPrimitive::TRIANGLES && type != COLLADAFW::MeshPrimitive::TRIANGLE_FANS) {
- fprintf(stderr, "Primitive type %s is not supported.\n", type_str);
+ fprintf(stderr, "ERROR: Primitive type %s is not supported.\n", type_str);
return false;
}
}
if (mesh->getPositions().empty()) {
- fprintf(stderr, "Mesh %s has no vertices.\n", name.c_str());
+ fprintf(stderr, "ERROR: Mesh %s has no vertices.\n", name.c_str());
return false;
}
@@ -409,11 +432,18 @@ void MeshImporter::allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me)
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);
+ for (int index=0; index < prim_poly_count; index++)
+ {
+ int vcount = get_vertex_count(mpvc, index);
+ if (vcount > 0) {
+ prim_loop_count += vcount;
+ total_poly_count++;
+ }
+ else {
+ // TODO: this is a hole and not another polygon!
+ }
}
- total_poly_count += prim_poly_count;
total_loop_count += prim_loop_count;
break;
@@ -682,12 +712,20 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me)
COLLADAFW::IndexListArray& index_list_array_uvcoord = mp->getUVCoordIndicesArray();
COLLADAFW::IndexListArray& index_list_array_vcolor = mp->getColorIndicesArray();
+ int invalid_loop_holes = 0;
for (unsigned int j = 0; j < prim_totpoly; j++) {
-
+
// Vertices in polygon:
int vcount = get_vertex_count(mpvc, j);
- set_poly_indices(mpoly, mloop, loop_index, position_indices, vcount);
+ if (vcount < 0) {
+ continue; // TODO: add support for holes
+ }
+ bool broken_loop = set_poly_indices(mpoly, mloop, loop_index, position_indices, vcount);
+ if (broken_loop)
+ {
+ invalid_loop_holes += 1;
+ }
for (unsigned int uvset_index = 0; uvset_index < index_list_array_uvcoord.getCount(); uvset_index++) {
// get mtface by face index and uv set index
@@ -735,6 +773,11 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me)
position_indices += vcount;
}
+
+ if (invalid_loop_holes > 0)
+ {
+ fprintf(stderr, "Collada import: Mesh [%s] : contains %d unsupported loops (holes).\n", me->id.name, invalid_loop_holes);
+ }
}
else if (collada_meshtype == COLLADAFW::MeshPrimitive::LINES) {
diff --git a/source/blender/collada/MeshImporter.h b/source/blender/collada/MeshImporter.h
index 9d5fefb83f2..d6426fbaf56 100644
--- a/source/blender/collada/MeshImporter.h
+++ b/source/blender/collada/MeshImporter.h
@@ -109,7 +109,7 @@ private:
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_poly_indices(MPoly *mpoly,
+ bool set_poly_indices(MPoly *mpoly,
MLoop *mloop,
int loop_index,
unsigned int *indices,
diff --git a/source/blender/collada/SkinInfo.cpp b/source/blender/collada/SkinInfo.cpp
index 71875d6274a..7242a24523c 100644
--- a/source/blender/collada/SkinInfo.cpp
+++ b/source/blender/collada/SkinInfo.cpp
@@ -230,6 +230,7 @@ void SkinInfo::link_armature(bContext *C, Object *ob, std::map<COLLADAFW::Unique
ModifierData *md = ED_object_modifier_add(NULL, bmain, scene, ob, NULL, eModifierType_Armature);
ArmatureModifierData *amd = (ArmatureModifierData *)md;
amd->object = ob_arm;
+ struct bArmature *armature = (bArmature *)ob_arm->data;
#if 1
bc_set_parent(ob, ob_arm, C);
diff --git a/source/blender/collada/TransformWriter.cpp b/source/blender/collada/TransformWriter.cpp
index e205608a365..b16e2e2b0d3 100644
--- a/source/blender/collada/TransformWriter.cpp
+++ b/source/blender/collada/TransformWriter.cpp
@@ -49,6 +49,7 @@ void TransformWriter::add_node_transform(COLLADASW::Node& node, float mat[4][4],
double dmat[4][4];
UnitConverter *converter = new UnitConverter();
converter->mat4_to_dae_double(dmat, local);
+ delete converter;
TransformBase::decompose(local, loc, rot, NULL, scale);
diff --git a/source/blender/collada/collada.cpp b/source/blender/collada/collada.cpp
index b64b10e0833..fe8b1d2320a 100644
--- a/source/blender/collada/collada.cpp
+++ b/source/blender/collada/collada.cpp
@@ -46,6 +46,7 @@ int collada_import(bContext *C,
const char *filepath,
int import_units,
int find_chains,
+ int auto_connect,
int fix_orientation,
int min_chain_length)
{
@@ -53,6 +54,7 @@ int collada_import(bContext *C,
ImportSettings import_settings;
import_settings.filepath = (char *)filepath;
import_settings.import_units = import_units != 0;
+ import_settings.auto_connect = auto_connect != 0;
import_settings.find_chains = find_chains != 0;
import_settings.fix_orientation = fix_orientation != 0;
import_settings.min_chain_length = min_chain_length;
@@ -81,8 +83,9 @@ int collada_export(Scene *sce,
int use_texture_copies,
int triangulate,
- int use_object_instantiation,
- int sort_by_name,
+ int use_object_instantiation,
+ int use_blender_profile,
+ int sort_by_name,
BC_export_transformation_type export_transformation_type,
int open_sim)
{
@@ -105,6 +108,7 @@ int collada_export(Scene *sce,
export_settings.triangulate = triangulate != 0;
export_settings.use_object_instantiation = use_object_instantiation != 0;
+ export_settings.use_blender_profile = use_blender_profile != 0;
export_settings.sort_by_name = sort_by_name != 0;
export_settings.export_transformation_type = export_transformation_type;
export_settings.open_sim = open_sim != 0;
diff --git a/source/blender/collada/collada.h b/source/blender/collada/collada.h
index 6819a62fdf0..0017c66836a 100644
--- a/source/blender/collada/collada.h
+++ b/source/blender/collada/collada.h
@@ -57,6 +57,7 @@ int collada_import(struct bContext *C,
const char *filepath,
int import_units,
int find_chains,
+ int auto_connect,
int fix_orientation,
int min_chain_length);
@@ -78,6 +79,7 @@ int collada_export(struct Scene *sce,
int triangulate,
int use_object_instantiation,
+ int use_blender_profile,
int sort_by_name,
BC_export_transformation_type export_transformation_type,
int open_sim);
diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp
index f8feed8145c..2efa8b21d81 100644
--- a/source/blender/collada/collada_utils.cpp
+++ b/source/blender/collada/collada_utils.cpp
@@ -54,6 +54,8 @@ extern "C" {
#include "BKE_scene.h"
#include "BKE_DerivedMesh.h"
+#include "ED_armature.h"
+
#include "WM_api.h" // XXX hrm, see if we can do without this
#include "WM_types.h"
@@ -355,8 +357,11 @@ void bc_triangulate_mesh(Mesh *me)
bool use_beauty = false;
bool tag_only = false;
int quad_method = MOD_TRIANGULATE_QUAD_SHORTEDGE; /* XXX: The triangulation method selection could be offered in the UI */
-
- BMesh *bm = BM_mesh_create(&bm_mesh_allocsize_default);
+
+ const struct BMeshCreateParams bm_create_params = {0};
+ BMesh *bm = BM_mesh_create(
+ &bm_mesh_allocsize_default,
+ &bm_create_params);
BMeshFromMeshParams bm_from_me_params = {0};
bm_from_me_params.calc_face_normal = true;
BM_mesh_bm_from_me(bm, me, &bm_from_me_params);
@@ -366,3 +371,244 @@ void bc_triangulate_mesh(Mesh *me)
BM_mesh_bm_to_me(bm, me, &bm_to_me_params);
BM_mesh_free(bm);
}
+
+/*
+ * A bone is a leaf when it has no children or all children are not connected.
+ */
+bool bc_is_leaf_bone(Bone *bone)
+{
+ for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
+ if (child->flag & BONE_CONNECTED)
+ return false;
+ }
+ return true;
+}
+
+EditBone *bc_get_edit_bone(bArmature * armature, char *name) {
+ EditBone *eBone;
+
+ for (eBone = (EditBone *)armature->edbo->first; eBone; eBone = eBone->next) {
+ if (STREQ(name, eBone->name))
+ return eBone;
+ }
+
+ return NULL;
+
+}
+int bc_set_layer(int bitfield, int layer)
+{
+ return bc_set_layer(bitfield, layer, true); /* enable */
+}
+
+int bc_set_layer(int bitfield, int layer, bool enable)
+{
+ int bit = 1u << layer;
+
+ if (enable)
+ bitfield |= bit;
+ else
+ bitfield &= ~bit;
+
+ return bitfield;
+}
+
+/*
+ | This method creates a new extension map when needed.
+ | Note: The ~BoneExtensionManager destructor takes care
+ | to delete the created maps when the manager is removed.
+*/
+BoneExtensionMap &BoneExtensionManager::getExtensionMap(bArmature *armature)
+{
+ std::string key = armature->id.name;
+ BoneExtensionMap *result = extended_bone_maps[key];
+ if (result == NULL)
+ {
+ result = new BoneExtensionMap();
+ extended_bone_maps[key] = result;
+ }
+ return *result;
+}
+
+BoneExtensionManager::~BoneExtensionManager()
+{
+ std::map<std::string, BoneExtensionMap *>::iterator map_it;
+ for (map_it = extended_bone_maps.begin(); map_it != extended_bone_maps.end(); ++map_it)
+ {
+ BoneExtensionMap *extended_bones = map_it->second;
+ for (BoneExtensionMap::iterator ext_it = extended_bones->begin(); ext_it != extended_bones->end(); ++ext_it) {
+ if (ext_it->second != NULL)
+ delete ext_it->second;
+ }
+ extended_bones->clear();
+ delete extended_bones;
+ }
+}
+
+/**
+ * BoneExtended is a helper class needed for the Bone chain finder
+ * See ArmatureImporter::fix_leaf_bones()
+ * and ArmatureImporter::connect_bone_chains()
+ */
+
+BoneExtended::BoneExtended(EditBone *aBone)
+{
+ this->set_name(aBone->name);
+ this->chain_length = 0;
+ this->is_leaf = false;
+ this->tail[0] = 0.0f;
+ this->tail[1] = 0.5f;
+ this->tail[2] = 0.0f;
+ this->use_connect = -1;
+ this->roll = 0;
+ this->bone_layers = 0;
+
+ this->has_custom_tail = false;
+ this->has_custom_roll = false;
+}
+
+char *BoneExtended::get_name()
+{
+ return name;
+}
+
+void BoneExtended::set_name(char *aName)
+{
+ BLI_strncpy(name, aName, MAXBONENAME);
+}
+
+int BoneExtended::get_chain_length()
+{
+ return chain_length;
+}
+
+void BoneExtended::set_chain_length(const int aLength)
+{
+ chain_length = aLength;
+}
+
+void BoneExtended::set_leaf_bone(bool state)
+{
+ is_leaf = state;
+}
+
+bool BoneExtended::is_leaf_bone()
+{
+ return is_leaf;
+}
+
+void BoneExtended::set_roll(float roll)
+{
+ this->roll = roll;
+ this->has_custom_roll = true;
+}
+
+bool BoneExtended::has_roll()
+{
+ return this->has_custom_roll;
+}
+
+float BoneExtended::get_roll()
+{
+ return this->roll;
+}
+
+void BoneExtended::set_tail(float vec[])
+{
+ this->tail[0] = vec[0];
+ this->tail[1] = vec[1];
+ this->tail[2] = vec[2];
+ this->has_custom_tail = true;
+}
+
+bool BoneExtended::has_tail()
+{
+ return this->has_custom_tail;
+}
+
+float *BoneExtended::get_tail()
+{
+ return this->tail;
+}
+
+inline bool isInteger(const std::string & s)
+{
+ if (s.empty() || ((!isdigit(s[0])) && (s[0] != '-') && (s[0] != '+'))) return false;
+
+ char * p;
+ strtol(s.c_str(), &p, 10);
+
+ return (*p == 0);
+}
+
+void BoneExtended::set_bone_layers(std::string layerString, std::vector<std::string> &layer_labels)
+{
+ std::stringstream ss(layerString);
+ std::string layer;
+ int pos;
+
+ while (ss >> layer) {
+
+ /* Blender uses numbers to specify layers*/
+ if (isInteger(layer))
+ {
+ pos = atoi(layer.c_str());
+ if (pos >= 0 && pos < 32) {
+ this->bone_layers = bc_set_layer(this->bone_layers, pos);
+ continue;
+ }
+ }
+
+ /* layer uses labels (not supported by blender). Map to layer numbers:*/
+ pos = find(layer_labels.begin(), layer_labels.end(), layer) - layer_labels.begin();
+ if (pos >= layer_labels.size()) {
+ layer_labels.push_back(layer); /* remember layer number for future usage*/
+ }
+
+ if (pos > 31)
+ {
+ fprintf(stderr, "Too many layers in Import. Layer %s mapped to Blender layer 31\n", layer.c_str());
+ pos = 31;
+ }
+
+ /* If numeric layers and labeled layers are used in parallel (unlikely),
+ * we get a potential mixup. Just leave as is for now.
+ */
+ this->bone_layers = bc_set_layer(this->bone_layers, pos);
+
+ }
+}
+
+std::string BoneExtended::get_bone_layers(int bitfield)
+{
+ std::string result = "";
+ std::string sep = "";
+ int bit = 1u;
+
+ std::ostringstream ss;
+ for (int i = 0; i < 32; i++)
+ {
+ if (bit & bitfield)
+ {
+ ss << sep << i;
+ sep = " ";
+ }
+ bit = bit << 1;
+ }
+ return ss.str();
+}
+
+int BoneExtended::get_bone_layers()
+{
+ return (bone_layers == 0) ? 1 : bone_layers; // ensure that the bone is in at least one bone layer!
+}
+
+
+void BoneExtended::set_use_connect(int use_connect)
+{
+ this->use_connect = use_connect;
+}
+
+int BoneExtended::get_use_connect()
+{
+ return this->use_connect;
+}
diff --git a/source/blender/collada/collada_utils.h b/source/blender/collada/collada_utils.h
index 4bc2f55cf33..7fdbef3b6cb 100644
--- a/source/blender/collada/collada_utils.h
+++ b/source/blender/collada/collada_utils.h
@@ -34,6 +34,7 @@
#include <vector>
#include <map>
+#include <algorithm>
extern "C" {
#include "DNA_object_types.h"
@@ -46,6 +47,7 @@ extern "C" {
#include "BLI_linklist.h"
#include "BLI_utildefines.h"
+#include "BLI_string.h"
#include "BKE_context.h"
#include "BKE_object.h"
@@ -87,7 +89,10 @@ extern void bc_match_scale(Object *ob, UnitConverter &bc_unit, bool scale_to_sce
extern void bc_match_scale(std::vector<Object *> *objects_done, UnitConverter &unit_converter, bool scale_to_scene);
extern void bc_triangulate_mesh(Mesh *me);
-
+extern bool bc_is_leaf_bone(Bone *bone);
+extern EditBone *bc_get_edit_bone(bArmature * armature, char *name);
+extern int bc_set_layer(int bitfield, int layer, bool enable);
+extern int bc_set_layer(int bitfield, int layer);
class BCPolygonNormalsIndices
{
@@ -105,4 +110,67 @@ class BCPolygonNormalsIndices
};
+class BoneExtended {
+
+private:
+ char name[MAXBONENAME];
+ int chain_length;
+ bool is_leaf;
+ float tail[3];
+ float roll;
+
+ int bone_layers;
+ int use_connect;
+ bool has_custom_tail;
+ bool has_custom_roll;
+
+public:
+
+ BoneExtended(EditBone *aBone);
+
+ void set_name(char *aName);
+ char *get_name();
+
+ void set_chain_length(const int aLength);
+ int get_chain_length();
+
+ void set_leaf_bone(bool state);
+ bool is_leaf_bone();
+
+ void set_bone_layers(std::string layers, std::vector<std::string> &layer_labels);
+ int get_bone_layers();
+ static std::string get_bone_layers(int bitfield);
+
+ void set_roll(float roll);
+ bool has_roll();
+ float get_roll();
+
+ void set_tail(float *vec);
+ float *get_tail();
+ bool has_tail();
+
+ void set_use_connect(int use_connect);
+ int get_use_connect();
+};
+
+/* a map to store bone extension maps
+| std:string : an armature name
+| BoneExtended * : a map that contains extra data for bones
+*/
+typedef std::map<std::string, BoneExtended *> BoneExtensionMap;
+
+/*
+| A class to organise bone extendion data for multiple Armatures.
+| this is needed for the case where a Collada file contains 2 or more
+| separate armatures.
+*/
+class BoneExtensionManager {
+private:
+ std::map<std::string, BoneExtensionMap *> extended_bone_maps;
+
+public:
+ BoneExtensionMap &getExtensionMap(bArmature *armature);
+ ~BoneExtensionManager();
+};
+
#endif
diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.h b/source/blender/compositor/intern/COM_OpenCLDevice.h
index a513954ee0d..ad40b4851fb 100644
--- a/source/blender/compositor/intern/COM_OpenCLDevice.h
+++ b/source/blender/compositor/intern/COM_OpenCLDevice.h
@@ -95,9 +95,9 @@ public:
void execute(WorkPackage *work);
/**
- * @brief determine an image format
- * @param memorybuffer
- */
+ * @brief determine an image format
+ * @param memorybuffer
+ */
static const cl_image_format *determineImageFormat(MemoryBuffer *memoryBuffer);
cl_context getContext() { return this->m_context; }
diff --git a/source/blender/compositor/intern/COM_WorkScheduler.cpp b/source/blender/compositor/intern/COM_WorkScheduler.cpp
index e5b9f58ee93..39147f3ab84 100644
--- a/source/blender/compositor/intern/COM_WorkScheduler.cpp
+++ b/source/blender/compositor/intern/COM_WorkScheduler.cpp
@@ -187,7 +187,7 @@ void WorkScheduler::schedule(ExecutionGroup *group, int chunkNumber)
{
WorkPackage *package = new WorkPackage(group, chunkNumber);
#if COM_CURRENT_THREADING_MODEL == COM_TM_NOTHREAD
- CPUDevice device;
+ CPUDevice device(0);
device.execute(package);
delete package;
#elif COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
@@ -277,6 +277,7 @@ bool WorkScheduler::hasGPUDevices()
#endif
}
+#if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
static void CL_CALLBACK clContextError(const char *errinfo,
const void * /*private_info*/,
size_t /*cb*/,
@@ -284,6 +285,7 @@ static void CL_CALLBACK clContextError(const char *errinfo,
{
printf("OPENCL error: %s\n", errinfo);
}
+#endif
void WorkScheduler::initialize(bool use_opencl, int num_cpu_threads)
{
diff --git a/source/blender/compositor/nodes/COM_FilterNode.cpp b/source/blender/compositor/nodes/COM_FilterNode.cpp
index 7493f24ba6b..e8b08ce2ce1 100644
--- a/source/blender/compositor/nodes/COM_FilterNode.cpp
+++ b/source/blender/compositor/nodes/COM_FilterNode.cpp
@@ -49,7 +49,7 @@ void FilterNode::convertToOperations(NodeConverter &converter, const CompositorC
operation->set3x3Filter(-1, -1, -1, -1, 9, -1, -1, -1, -1);
break;
case CMP_FILT_LAPLACE:
- operation = new ConvolutionFilterOperation();
+ operation = new ConvolutionEdgeFilterOperation();
operation->set3x3Filter(-1 / 8.0f, -1 / 8.0f, -1 / 8.0f, -1 / 8.0f, 1.0f, -1 / 8.0f, -1 / 8.0f, -1 / 8.0f, -1 / 8.0f);
break;
case CMP_FILT_SOBEL:
diff --git a/source/blender/compositor/nodes/COM_MovieClipNode.cpp b/source/blender/compositor/nodes/COM_MovieClipNode.cpp
index 933223dacac..b3f1b5a4458 100644
--- a/source/blender/compositor/nodes/COM_MovieClipNode.cpp
+++ b/source/blender/compositor/nodes/COM_MovieClipNode.cpp
@@ -91,7 +91,7 @@ void MovieClipNode::convertToOperations(NodeConverter &converter, const Composit
if (stab->flag & TRACKING_2D_STABILIZATION) {
int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(movieClip, context.getFramenumber());
- BKE_tracking_stabilization_data_get(&movieClip->tracking, clip_framenr, ibuf->x, ibuf->y, loc, &scale, &angle);
+ BKE_tracking_stabilization_data_get(movieClip, clip_framenr, ibuf->x, ibuf->y, loc, &scale, &angle);
}
}
diff --git a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp
index 76afedf4b2a..ca3c5f7b069 100644
--- a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp
+++ b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp
@@ -20,6 +20,8 @@
* Monique Dewanchand
*/
+#include <stdlib.h>
+
#include "COM_DoubleEdgeMaskOperation.h"
#include "BLI_math.h"
#include "DNA_node_types.h"
@@ -1151,12 +1153,13 @@ void DoubleEdgeMaskOperation::doDoubleEdgeMask(float *imask, float *omask, float
if (true) { // if both input sockets have some data coming in...
- t = (this->getWidth() * this->getHeight()) - 1; // determine size of the frame
+ rw = this->getWidth(); // width of a row of pixels
+ t = (rw * this->getHeight()) - 1; // determine size of the frame
+ memset(res, 0, sizeof(float) * (t + 1)); // clear output buffer (not all pixels will be written later)
lres = (unsigned int *)res; // unsigned int pointer to output buffer (for bit level ops)
limask = (unsigned int *)imask; // unsigned int pointer to input mask (for bit level ops)
lomask = (unsigned int *)omask; // unsigned int pointer to output mask (for bit level ops)
- rw = this->getWidth(); // width of a row of pixels
/*
diff --git a/source/blender/compositor/operations/COM_ImageOperation.cpp b/source/blender/compositor/operations/COM_ImageOperation.cpp
index 624378f2ae9..7d59358831c 100644
--- a/source/blender/compositor/operations/COM_ImageOperation.cpp
+++ b/source/blender/compositor/operations/COM_ImageOperation.cpp
@@ -160,10 +160,10 @@ static void sampleImageAtLocation(ImBuf *ibuf, float x, float y, PixelSampler sa
void ImageOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
{
int ix = x, iy = y;
- if (ix < 0 || iy < 0 || ix >= this->m_buffer->x || iy >= this->m_buffer->y) {
+ if (this->m_imageFloatBuffer == NULL && this->m_imageByteBuffer == NULL) {
zero_v4(output);
}
- else if (this->m_imageFloatBuffer == NULL && this->m_imageByteBuffer == NULL) {
+ else if (ix < 0 || iy < 0 || ix >= this->m_buffer->x || iy >= this->m_buffer->y) {
zero_v4(output);
}
else {
diff --git a/source/blender/compositor/operations/COM_MaskOperation.cpp b/source/blender/compositor/operations/COM_MaskOperation.cpp
index 220b4e908a6..caafdfe8f0c 100644
--- a/source/blender/compositor/operations/COM_MaskOperation.cpp
+++ b/source/blender/compositor/operations/COM_MaskOperation.cpp
@@ -1,5 +1,4 @@
/*
-
* Copyright 2012, Blender Foundation.
*
* This program is free software; you can redistribute it and/or
@@ -94,7 +93,7 @@ void MaskOperation::initExecution()
frame_iter += frame_step;
}
- BKE_mask_free_nolib(mask_temp);
+ BKE_mask_free(mask_temp);
MEM_freeN(mask_temp);
}
}
diff --git a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp
index 5ddf15f7684..41f7da7c49f 100644
--- a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp
+++ b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp
@@ -47,7 +47,7 @@ void MovieClipAttributeOperation::executePixelSampled(float output[4],
angle = 0.0f;
if (this->m_clip) {
int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(this->m_clip, this->m_framenumber);
- BKE_tracking_stabilization_data_get(&this->m_clip->tracking, clip_framenr, getWidth(), getHeight(), loc, &scale, &angle);
+ BKE_tracking_stabilization_data_get(this->m_clip, clip_framenr, getWidth(), getHeight(), loc, &scale, &angle);
}
switch (this->m_attribute) {
case MCA_SCALE:
diff --git a/source/blender/compositor/operations/COM_SunBeamsOperation.cpp b/source/blender/compositor/operations/COM_SunBeamsOperation.cpp
index a681583809c..70e0b2cfb57 100644
--- a/source/blender/compositor/operations/COM_SunBeamsOperation.cpp
+++ b/source/blender/compositor/operations/COM_SunBeamsOperation.cpp
@@ -186,8 +186,8 @@ struct BufferLineAccumulator {
}
/* TODO implement proper filtering here, see
- * http://en.wikipedia.org/wiki/Lanczos_resampling
- * http://en.wikipedia.org/wiki/Sinc_function
+ * https://en.wikipedia.org/wiki/Lanczos_resampling
+ * https://en.wikipedia.org/wiki/Sinc_function
*
* using lanczos with x = distance from the line segment,
* normalized to a == 0.5f, could give a good result
diff --git a/source/blender/compositor/operations/COM_TextureOperation.cpp b/source/blender/compositor/operations/COM_TextureOperation.cpp
index 665bffc2c1c..bba5c8702b8 100644
--- a/source/blender/compositor/operations/COM_TextureOperation.cpp
+++ b/source/blender/compositor/operations/COM_TextureOperation.cpp
@@ -110,8 +110,18 @@ void TextureBaseOperation::executePixelSampled(float output[4], float x, float y
int retval;
const float cx = this->getWidth() / 2;
const float cy = this->getHeight() / 2;
- const float u = (x - cx) / this->getWidth() * 2;
- const float v = (y - cy) / this->getHeight() * 2;
+ float u = (x - cx) / this->getWidth() * 2;
+ float v = (y - cy) / this->getHeight() * 2;
+
+ /* When no interpolation/filtering happens in multitex() foce nearest interpolation.
+ * We do it here because (a) we can't easily say multitex() that we want nearest
+ * interpolaiton and (b) in such configuration multitex() sinply floor's the value
+ * which often produces artifacts.
+ */
+ if ((m_texture->imaflag & TEX_INTERPOL) == 0) {
+ u += 0.5f / cx;
+ v += 0.5f / cy;
+ }
this->m_inputSize->readSampled(textureSize, x, y, sampler);
this->m_inputOffset->readSampled(textureOffset, x, y, sampler);
diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt
index e1dc8b020fb..fd2a521bec5 100644
--- a/source/blender/depsgraph/CMakeLists.txt
+++ b/source/blender/depsgraph/CMakeLists.txt
@@ -25,8 +25,6 @@
set(INC
.
- intern
- util
../blenkernel
../blenlib
../bmesh
@@ -42,48 +40,55 @@ set(INC_SYS
)
set(SRC
+ intern/builder/deg_builder.cc
+ intern/builder/deg_builder_cycle.cc
+ intern/builder/deg_builder_nodes.cc
+ intern/builder/deg_builder_pchanmap.cc
+ intern/builder/deg_builder_relations.cc
+ intern/builder/deg_builder_transitive.cc
+ intern/debug/deg_debug_graphviz.cc
+ intern/eval/deg_eval.cc
+ intern/eval/deg_eval_debug.cc
+ intern/eval/deg_eval_flush.cc
+ intern/nodes/deg_node.cc
+ intern/nodes/deg_node_component.cc
+ intern/nodes/deg_node_operation.cc
intern/depsgraph.cc
- intern/depsnode.cc
- intern/depsnode_component.cc
- intern/depsnode_operation.cc
intern/depsgraph_build.cc
- intern/depsgraph_build_nodes.cc
- intern/depsgraph_build_relations.cc
intern/depsgraph_debug.cc
intern/depsgraph_eval.cc
intern/depsgraph_query.cc
- intern/depsgraph_queue.cc
intern/depsgraph_tag.cc
intern/depsgraph_type_defines.cc
- util/depsgraph_util_cycle.cc
- util/depsgraph_util_pchanmap.cc
- util/depsgraph_util_transitive.cc
DEG_depsgraph.h
DEG_depsgraph_build.h
DEG_depsgraph_debug.h
DEG_depsgraph_query.h
+
+ intern/builder/deg_builder.h
+ intern/builder/deg_builder_cycle.h
+ intern/builder/deg_builder_nodes.h
+ intern/builder/deg_builder_pchanmap.h
+ intern/builder/deg_builder_relations.h
+ intern/builder/deg_builder_transitive.h
+ intern/eval/deg_eval.h
+ intern/eval/deg_eval_debug.h
+ intern/eval/deg_eval_flush.h
+ intern/nodes/deg_node.h
+ intern/nodes/deg_node_component.h
+ intern/nodes/deg_node_operation.h
intern/depsgraph.h
- intern/depsnode.h
- intern/depsnode_component.h
- intern/depsnode_operation.h
- intern/depsnode_opcodes.h
- intern/depsgraph_build.h
- intern/depsgraph_debug.h
intern/depsgraph_intern.h
- intern/depsgraph_queue.h
intern/depsgraph_types.h
- util/depsgraph_util_cycle.h
- util/depsgraph_util_function.h
- util/depsgraph_util_hash.h
- util/depsgraph_util_map.h
- util/depsgraph_util_pchanmap.h
- util/depsgraph_util_set.h
- util/depsgraph_util_transitive.h
+ util/deg_util_function.h
+ util/deg_util_hash.h
)
-if(HAVE_STD_UNORDERED_MAP_HEADER)
+if(WITH_CXX11)
+ add_definitions(-DDEG_STD_UNORDERED_MAP)
+elseif(HAVE_STD_UNORDERED_MAP_HEADER)
if(HAVE_UNORDERED_MAP_IN_STD_NAMESPACE)
add_definitions(-DDEG_STD_UNORDERED_MAP)
else()
diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h
index f37ba71ab65..945a4785b9c 100644
--- a/source/blender/depsgraph/DEG_depsgraph.h
+++ b/source/blender/depsgraph/DEG_depsgraph.h
@@ -131,9 +131,6 @@ void DEG_ids_clear_recalc(struct Main *bmain);
/* Update Flushing ------------------------------- */
-/* Flush updates */
-void DEG_graph_flush_updates(struct Main *bmain, Depsgraph *graph);
-
/* Flush updates for all IDs */
void DEG_ids_flush_tagged(struct Main *bmain);
@@ -144,11 +141,6 @@ void DEG_ids_check_recalc(struct Main *bmain,
struct Scene *scene,
bool time);
-/* Clear all update tags
- * - For aborted updates, or after successful evaluation
- */
-void DEG_graph_clear_tags(Depsgraph *graph);
-
/* ************************************************ */
/* Evaluation Engine API */
@@ -176,7 +168,7 @@ void DEG_evaluate_on_framechange(struct EvaluationContext *eval_ctx,
struct Main *bmain,
Depsgraph *graph,
float ctime,
- const int layer);
+ const unsigned int layer);
/* Data changed recalculation entry point.
* < context_type: context to perform evaluation for
@@ -184,7 +176,7 @@ void DEG_evaluate_on_framechange(struct EvaluationContext *eval_ctx,
*/
void DEG_evaluate_on_refresh_ex(struct EvaluationContext *eval_ctx,
Depsgraph *graph,
- const int layers);
+ const unsigned int layers);
/* Data changed recalculation entry point.
* < context_type: context to perform evaluation for
diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h
index f680c47247a..0945da439ef 100644
--- a/source/blender/depsgraph/DEG_depsgraph_build.h
+++ b/source/blender/depsgraph/DEG_depsgraph_build.h
@@ -42,9 +42,8 @@ struct Depsgraph;
struct Main;
struct Scene;
-
-struct PointerRNA;
-struct PropertyRNA;
+struct Group;
+struct EffectorWeights;
#ifdef __cplusplus
extern "C" {
@@ -82,6 +81,7 @@ void DEG_scene_graph_free(struct Scene *scene);
*/
struct DepsNodeHandle;
+struct CacheFile;
struct Object;
typedef enum eDepsSceneComponentType {
@@ -103,15 +103,23 @@ typedef enum eDepsObjectComponentType {
DEG_OB_COMP_EVAL_PARTICLES, /* Particle Systems Component */
DEG_OB_COMP_SHADING, /* Material Shading Component */
+ DEG_OB_COMP_CACHE, /* Cache Component */
} eDepsObjectComponentType;
void DEG_add_scene_relation(struct DepsNodeHandle *node, struct Scene *scene, eDepsSceneComponentType component, const char *description);
void DEG_add_object_relation(struct DepsNodeHandle *node, struct Object *ob, eDepsObjectComponentType component, const char *description);
void DEG_add_bone_relation(struct DepsNodeHandle *handle, struct Object *ob, const char *bone_name, eDepsObjectComponentType component, const char *description);
+void DEG_add_object_cache_relation(struct DepsNodeHandle *handle, struct CacheFile *cache_file, eDepsObjectComponentType component, const char *description);
/* TODO(sergey): Remove once all geometry update is granular. */
void DEG_add_special_eval_flag(struct Depsgraph *graph, struct ID *id, short flag);
+/* Utility functions for physics modifiers */
+typedef bool (*DEG_CollobjFilterFunction)(struct Object *obj, struct ModifierData *md);
+
+void DEG_add_collision_relations(struct DepsNodeHandle *handle, struct Scene *scene, Object *ob, struct Group *group, int layer, unsigned int modifier_type, DEG_CollobjFilterFunction fn, bool dupli, const char *name);
+void DEG_add_forcefield_relations(struct DepsNodeHandle *handle, struct Scene *scene, Object *ob, struct EffectorWeights *eff, bool add_absorption, int skip_forcefield, const char *name);
+
/* ************************************************ */
#ifdef __cplusplus
diff --git a/source/blender/depsgraph/DEG_depsgraph_debug.h b/source/blender/depsgraph/DEG_depsgraph_debug.h
index 374fad63c34..0d19b8e1e97 100644
--- a/source/blender/depsgraph/DEG_depsgraph_debug.h
+++ b/source/blender/depsgraph/DEG_depsgraph_debug.h
@@ -39,13 +39,10 @@
extern "C" {
#endif
-struct DepsgraphSettings;
struct GHash;
struct ID;
struct Depsgraph;
-struct DepsNode;
-struct DepsRelation;
/* ************************************************ */
/* Statistics */
diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h
index 60d673d4c5b..ccd204a2083 100644
--- a/source/blender/depsgraph/DEG_depsgraph_query.h
+++ b/source/blender/depsgraph/DEG_depsgraph_query.h
@@ -19,7 +19,7 @@
* All rights reserved.
*
* Original Author: Joshua Leung
- * Contributor(s): None Yet
+ * Contributor(s): Sergey Sharybin
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -33,155 +33,14 @@
#ifndef __DEG_DEPSGRAPH_QUERY_H__
#define __DEG_DEPSGRAPH_QUERY_H__
-struct ListBase;
struct ID;
struct Depsgraph;
-struct DepsNode;
-struct DepsRelation;
#ifdef __cplusplus
extern "C" {
#endif
-/* ************************************************ */
-/* Type Defines */
-
-/* FilterPredicate Callback
- *
- * Defines a callback function which can be supplied to check whether a
- * node is relevant or not.
- *
- * < graph: Depsgraph that we're traversing
- * < node: The node to check
- * < userdata: FilterPredicate state data (as needed)
- * > returns: True if node is relevant
- */
-typedef bool (*DEG_FilterPredicate)(const struct Depsgraph *graph, const struct DepsNode *node, void *userdata);
-
-
-/* Node Operation
- *
- * Performs some action on the given node, provided that the node was
- * deemed to be relevant to operate on.
- *
- * < graph: Depsgraph that we're traversing
- * < node: The node to perform operation on/with
- * < userdata: Node Operation's state data (as needed)
- * > returns: True if traversal should be aborted at this point
- */
-typedef bool (*DEG_NodeOperation)(const struct Depsgraph *graph, struct DepsNode *node, void *userdata);
-
-/* ************************************************ */
-/* Low-Level Filtering API */
-
-/* Create a filtered copy of the given graph which contains only the
- * nodes which fulfill the criteria specified using the FilterPredicate
- * passed in.
- *
- * < graph: The graph to be copied and filtered
- * < filter: FilterPredicate used to check which nodes should be included
- * (If null, full graph is copied as-is)
- * < userdata: State data for filter (as necessary)
- *
- * > returns: a full copy of all the relevant nodes - the matching subgraph
- */
-// XXX: is there any need for extra settings/options for how the filtering goes?
-Depsgraph *DEG_graph_filter(const struct Depsgraph *graph, DEG_FilterPredicate *filter, void *userdata);
-
-
-/* Traverse nodes in graph which are deemed relevant,
- * performing the provided operation on the nodes.
- *
- * < graph: The graph to perform operations on
- * < filter: FilterPredicate used to check which nodes should be included
- * (If null, all nodes are considered valid targets)
- * < filter_data: Custom state data for FilterPredicate
- * (Note: This can be the same as op_data, where appropriate)
- * < op: NodeOperation to perform on each node
- * (If null, no graph traversal is performed for efficiency)
- * < op_data: Custom state data for NodeOperation
- * (Note: This can be the same as filter_data, where appropriate)
- */
-void DEG_graph_traverse(const struct Depsgraph *graph,
- DEG_FilterPredicate *filter, void *filter_data,
- DEG_NodeOperation *op, void *op_data);
-
-/* ************************************************ */
-/* Node-Based Operations */
-// XXX: do we want to be able to attach conditional requirements here?
-
-/* Find an (outer) node matching given conditions
- * ! Assumes that there will only be one such node, or that only the first one matters
- *
- * < graph: a dependency graph which may or may not contain a node matching these requirements
- * < query: query conditions for the criteria that the node must satisfy
- */
-//DepsNode *DEG_node_find(const Depsgraph *graph, DEG_QueryConditions *query);
-
-/* Topology Queries (Direct) ---------------------- */
-
-/* Get list of nodes which directly depend on given node
- *
- * > result: list to write results to
- * < node: the node to find the children/dependents of
- */
-void DEG_node_get_children(struct ListBase *result, const struct DepsNode *node);
-
-
-/* Get list of nodes which given node directly depends on
- *
- * > result: list to write results to
- * < node: the node to find the dependencies of
- */
-void DEG_node_get_dependencies(struct ListBase *result, const struct DepsNode *node);
-
-
-/* Topology Queries (Subgraph) -------------------- */
-// XXX: given that subgraphs potentially involve many interconnected nodes, we currently
-// just spit out a copy of the subgraph which matches. This works well for the cases
-// where these are used - mostly for efficient updating of subsets of the nodes.
-
-// XXX: allow supplying a filter predicate to provide further filtering/pruning?
-
-
-/* Get all descendants of a node
- *
- * That is, get the subgraph / subset of nodes which are dependent
- * on the results of the given node.
- */
-Depsgraph *DEG_node_get_descendants(const struct Depsgraph *graph, const struct DepsNode *node);
-
-
-/* Get all ancestors of a node
- *
- * That is, get the subgraph / subset of nodes which the given node
- * is dependent on in order to be evaluated.
- */
-Depsgraph *DEG_node_get_ancestors(const struct Depsgraph *graph, const struct DepsNode *node);
-
-/* ************************************************ */
-/* Higher-Level Queries */
-
-/* Get ID-blocks which would be affected if specified ID is modified
- * < only_direct: True = Only ID-blocks with direct relationships to ID-block will be returned
- *
- * > result: (LinkData : ID) a list of ID-blocks matching the specified criteria
- * > returns: number of matching ID-blocks
- */
-size_t DEG_query_affected_ids(struct ListBase *result, const struct ID *id, const bool only_direct);
-
-
-/* Get ID-blocks which are needed to update/evaluate specified ID
- * < only_direct: True = Only ID-blocks with direct relationships to ID-block will be returned
- *
- * > result: (LinkData : ID) a list of ID-blocks matching the specified criteria
- * > returns: number of matching ID-blocks
- */
-size_t DEG_query_required_ids(struct ListBase *result, const struct ID *id, const bool only_direct);
-
-/* ************************************************ */
-
/* Check if given ID type was tagged for update. */
bool DEG_id_type_tagged(struct Main *bmain, short idtype);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc
new file mode 100644
index 00000000000..6169100d574
--- /dev/null
+++ b/source/blender/depsgraph/intern/builder/deg_builder.cc
@@ -0,0 +1,129 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Sergey Sharybin
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/builder/deg_builder.cc
+ * \ingroup depsgraph
+ */
+
+#include "intern/builder/deg_builder.h"
+
+// TODO(sergey): Use own wrapper over STD.
+#include <stack>
+
+#include "DNA_anim_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+
+#include "intern/depsgraph.h"
+#include "intern/depsgraph_types.h"
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+
+#include "util/deg_util_foreach.h"
+
+namespace DEG {
+
+string deg_fcurve_id_name(const FCurve *fcu)
+{
+ char index_buf[32];
+ // TODO(sergey): Use int-to-string utility or so.
+ BLI_snprintf(index_buf, sizeof(index_buf), "[%d]", fcu->array_index);
+ return string(fcu->rna_path) + index_buf;
+}
+
+void deg_graph_build_finalize(Depsgraph *graph)
+{
+ std::stack<OperationDepsNode *> stack;
+
+ foreach (OperationDepsNode *node, graph->operations) {
+ IDDepsNode *id_node = node->owner->owner;
+ node->done = 0;
+ node->num_links_pending = 0;
+ foreach (DepsRelation *rel, node->outlinks) {
+ if ((rel->from->type == DEPSNODE_TYPE_OPERATION) &&
+ (rel->flag & DEPSREL_FLAG_CYCLIC) == 0)
+ {
+ ++node->num_links_pending;
+ }
+ }
+ if (node->num_links_pending == 0) {
+ stack.push(node);
+ node->done = 1;
+ }
+ node->owner->layers = id_node->layers;
+ id_node->id->tag |= LIB_TAG_DOIT;
+ }
+
+ while (!stack.empty()) {
+ OperationDepsNode *node = stack.top();
+ stack.pop();
+ /* Flush layers to parents. */
+ foreach (DepsRelation *rel, node->inlinks) {
+ if (rel->from->type == DEPSNODE_TYPE_OPERATION) {
+ OperationDepsNode *from = (OperationDepsNode *)rel->from;
+ from->owner->layers |= node->owner->layers;
+ }
+ }
+ /* Schedule parent nodes. */
+ foreach (DepsRelation *rel, node->inlinks) {
+ if (rel->from->type == DEPSNODE_TYPE_OPERATION) {
+ OperationDepsNode *from = (OperationDepsNode *)rel->from;
+ if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
+ BLI_assert(from->num_links_pending > 0);
+ --from->num_links_pending;
+ }
+ if (from->num_links_pending == 0 && from->done == 0) {
+ stack.push(from);
+ from->done = 1;
+ }
+ }
+ }
+ }
+
+ /* Re-tag IDs for update if it was tagged before the relations update tag. */
+ GHASH_FOREACH_BEGIN(IDDepsNode *, id_node, graph->id_hash)
+ {
+ GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp, id_node->components)
+ {
+ id_node->layers |= comp->layers;
+ }
+ GHASH_FOREACH_END();
+
+ ID *id = id_node->id;
+ if (id->tag & LIB_TAG_ID_RECALC_ALL &&
+ id->tag & LIB_TAG_DOIT)
+ {
+ id_node->tag_update(graph);
+ id->tag &= ~LIB_TAG_DOIT;
+ }
+ id_node->finalize_build();
+ }
+ GHASH_FOREACH_END();
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.h b/source/blender/depsgraph/intern/builder/deg_builder.h
new file mode 100644
index 00000000000..bdc030e3810
--- /dev/null
+++ b/source/blender/depsgraph/intern/builder/deg_builder.h
@@ -0,0 +1,46 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Sergey Sharybin
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/builder/deg_builder.h
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+#include "intern/depsgraph_types.h"
+
+struct FCurve;
+
+namespace DEG {
+
+struct Depsgraph;
+
+/* Get unique identifier for FCurves and Drivers */
+string deg_fcurve_id_name(const FCurve *fcu);
+
+void deg_graph_build_finalize(struct Depsgraph *graph);
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/util/depsgraph_util_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
index 5eae8c087ad..225cc64ae4d 100644
--- a/source/blender/depsgraph/util/depsgraph_util_cycle.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
@@ -23,28 +23,30 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/util/depsgraph_util_cycle.cc
+/** \file blender/depsgraph/intern/builder/deg_builder_cycle.cc
* \ingroup depsgraph
*/
+#include "intern/builder/deg_builder_cycle.h"
+
+// TOO(sergey): Use some wrappers over those?
#include <cstdio>
#include <cstdlib>
#include <stack>
extern "C" {
#include "BLI_utildefines.h"
+}
-#include "DNA_ID.h"
+#include "util/deg_util_foreach.h"
-#include "RNA_access.h"
-#include "RNA_types.h"
-}
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
-#include "depsgraph_util_cycle.h"
-#include "depsgraph.h"
-#include "depsnode.h"
-#include "depsnode_component.h"
-#include "depsnode_operation.h"
+#include "intern/depsgraph.h"
+
+namespace DEG {
struct StackEntry {
OperationDepsNode *node;
@@ -62,17 +64,9 @@ void deg_graph_detect_cycles(Depsgraph *graph)
const int NODE_IN_STACK = 2;
std::stack<StackEntry> traversal_stack;
- for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
- it_op != graph->operations.end();
- ++it_op)
- {
- OperationDepsNode *node = *it_op;
+ foreach (OperationDepsNode *node, graph->operations) {
bool has_inlinks = false;
- for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin();
- it_rel != node->inlinks.end();
- ++it_rel)
- {
- DepsRelation *rel = *it_rel;
+ foreach (DepsRelation *rel, node->inlinks) {
if (rel->from->type == DEPSNODE_TYPE_OPERATION) {
has_inlinks = true;
}
@@ -94,11 +88,7 @@ void deg_graph_detect_cycles(Depsgraph *graph)
StackEntry &entry = traversal_stack.top();
OperationDepsNode *node = entry.node;
bool all_child_traversed = true;
- for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
- it_rel != node->outlinks.end();
- ++it_rel)
- {
- DepsRelation *rel = *it_rel;
+ foreach (DepsRelation *rel, node->outlinks) {
if (rel->to->type == DEPSNODE_TYPE_OPERATION) {
OperationDepsNode *to = (OperationDepsNode *)rel->to;
if (to->done == NODE_IN_STACK) {
@@ -138,3 +128,5 @@ void deg_graph_detect_cycles(Depsgraph *graph)
}
}
}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/util/depsgraph_util_cycle.h b/source/blender/depsgraph/intern/builder/deg_builder_cycle.h
index fac38b61057..386fbd80d19 100644
--- a/source/blender/depsgraph/util/depsgraph_util_cycle.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.h
@@ -23,15 +23,18 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/util/depsgraph_util_cycle.h
+/** \file blender/depsgraph/intern/builder/deg_builder_cycle.h
* \ingroup depsgraph
*/
-#ifndef __DEPSGRAPH_UTIL_CYCLE_H__
-#define __DEPSGRAPH_UTIL_CYCLE_H__
+
+#pragma once
+
+namespace DEG {
struct Depsgraph;
+/* Detect and solve dependency cycles. */
void deg_graph_detect_cycles(Depsgraph *graph);
-#endif /* __DEPSGRAPH_UTIL_CYCLE_H__ */
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_build_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index be706ffb338..1812384440f 100644
--- a/source/blender/depsgraph/intern/depsgraph_build_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -24,12 +24,14 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/depsgraph_build_nodes.cc
+/** \file blender/depsgraph/intern/builder/deg_builder_nodes.cc
* \ingroup depsgraph
*
* Methods for constructing depsgraph's nodes
*/
+#include "intern/builder/deg_builder_nodes.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -44,6 +46,7 @@ extern "C" {
#include "DNA_action_types.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
+#include "DNA_cachefile_types.h"
#include "DNA_camera_types.h"
#include "DNA_constraint_types.h"
#include "DNA_curve_types.h"
@@ -97,12 +100,14 @@ extern "C" {
#include "RNA_types.h"
} /* extern "C" */
-#include "depsnode.h"
-#include "depsnode_component.h"
-#include "depsnode_operation.h"
-#include "depsgraph_types.h"
-#include "depsgraph_build.h"
-#include "depsgraph_intern.h"
+#include "intern/builder/deg_builder.h"
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+#include "intern/depsgraph_types.h"
+#include "intern/depsgraph_intern.h"
+
+namespace DEG {
/* ************ */
/* Node Builder */
@@ -217,6 +222,17 @@ OperationDepsNode *DepsgraphNodeBuilder::add_operation_node(
return add_operation_node(comp_node, optype, op, opcode, description);
}
+OperationDepsNode *DepsgraphNodeBuilder::add_operation_node(
+ ID *id,
+ eDepsNode_Type comp_type,
+ eDepsOperation_Type optype,
+ DepsEvalOperationCb op,
+ eDepsOperation_Code opcode,
+ const string& description)
+{
+ return add_operation_node(id, comp_type, "", optype, op, opcode, description);
+}
+
bool DepsgraphNodeBuilder::has_operation_node(ID *id,
eDepsNode_Type comp_type,
const string &comp_name,
@@ -237,6 +253,14 @@ OperationDepsNode *DepsgraphNodeBuilder::find_operation_node(
return comp_node->has_operation(opcode, description);
}
+OperationDepsNode *DepsgraphNodeBuilder::find_operation_node(
+ ID *id,
+ eDepsNode_Type comp_type,
+ eDepsOperation_Code opcode,
+ const string& description)
+{
+ return find_operation_node(id, comp_type, "", opcode, description);
+}
/* **** Build functions for entity nodes **** */
@@ -316,6 +340,14 @@ void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene)
if (scene->gpd) {
build_gpencil(scene->gpd);
}
+
+ /* cache files */
+ for (CacheFile *cachefile = static_cast<CacheFile *>(bmain->cachefiles.first);
+ cachefile;
+ cachefile = static_cast<CacheFile *>(cachefile->id.next))
+ {
+ build_cachefile(cachefile);
+ }
}
void DepsgraphNodeBuilder::build_group(Scene *scene,
@@ -343,7 +375,7 @@ SubgraphDepsNode *DepsgraphNodeBuilder::build_subgraph(Group *group)
return NULL;
/* create new subgraph's data */
- Depsgraph *subgraph = DEG_graph_new();
+ Depsgraph *subgraph = reinterpret_cast<Depsgraph *>(DEG_graph_new());
DepsgraphNodeBuilder subgraph_builder(m_bmain, subgraph);
@@ -375,17 +407,17 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob)
{
if (ob->id.tag & LIB_TAG_DOIT) {
IDDepsNode *id_node = m_graph->find_id_node(&ob->id);
- id_node->layers = base->lay;
+ id_node->layers |= base->lay;
return;
}
IDDepsNode *id_node = add_id_node(&ob->id);
- id_node->layers = base->lay;
+ id_node->layers |= base->lay;
+ ob->customdata_mask = 0;
/* standard components */
build_object_transform(scene, ob);
-
/* object data */
if (ob->data) {
/* type-specific data... */
@@ -419,7 +451,7 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob)
}
case OB_ARMATURE: /* Pose */
- if (ob->id.lib != NULL && ob->proxy_from != NULL) {
+ if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from != NULL) {
build_proxy_rig(ob);
}
else {
@@ -957,11 +989,6 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
// TODO: "Done" operation
- /* ShapeKeys */
- Key *key = BKE_key_from_object(ob);
- if (key)
- build_shapekeys(key);
-
/* Modifiers */
if (ob->modifiers.first) {
ModifierData *md;
@@ -997,6 +1024,12 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
return;
}
+ /* ShapeKeys */
+ Key *key = BKE_key_from_object(ob);
+ if (key) {
+ build_shapekeys(key);
+ }
+
build_animdata(obdata);
/* nodes for result of obdata's evaluation, and geometry evaluation on object */
@@ -1234,3 +1267,19 @@ void DepsgraphNodeBuilder::build_gpencil(bGPdata *gpd)
*/
build_animdata(gpd_id);
}
+
+void DepsgraphNodeBuilder::build_cachefile(CacheFile *cache_file)
+{
+ ID *cache_file_id = &cache_file->id;
+
+ add_component_node(cache_file_id, DEPSNODE_TYPE_CACHE);
+
+ add_operation_node(cache_file_id, DEPSNODE_TYPE_CACHE,
+ DEPSOP_TYPE_EXEC, NULL,
+ DEG_OPCODE_PLACEHOLDER, "Cache File Update");
+
+ add_id_node(cache_file_id);
+ build_animdata(cache_file_id);
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
new file mode 100644
index 00000000000..f378f076804
--- /dev/null
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
@@ -0,0 +1,155 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.
+ *
+ * Original Author: Lukas Toenne
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/builder/deg_builder_nodes.h
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+#include "intern/depsgraph_types.h"
+
+struct Base;
+struct CacheFile;
+struct bGPdata;
+struct ListBase;
+struct GHash;
+struct ID;
+struct FCurve;
+struct Group;
+struct Key;
+struct Main;
+struct Material;
+struct MTex;
+struct bNodeTree;
+struct Object;
+struct bPoseChannel;
+struct bConstraint;
+struct Scene;
+struct Tex;
+struct World;
+
+struct PropertyRNA;
+
+namespace DEG {
+
+struct Depsgraph;
+struct DepsNode;
+struct RootDepsNode;
+struct SubgraphDepsNode;
+struct IDDepsNode;
+struct TimeSourceDepsNode;
+struct ComponentDepsNode;
+struct OperationDepsNode;
+
+struct DepsgraphNodeBuilder {
+ DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph);
+ ~DepsgraphNodeBuilder();
+
+ RootDepsNode *add_root_node();
+ IDDepsNode *add_id_node(ID *id);
+ TimeSourceDepsNode *add_time_source(ID *id);
+
+ ComponentDepsNode *add_component_node(ID *id,
+ eDepsNode_Type comp_type,
+ const string& comp_name = "");
+
+ OperationDepsNode *add_operation_node(ComponentDepsNode *comp_node,
+ eDepsOperation_Type optype,
+ DepsEvalOperationCb op,
+ eDepsOperation_Code opcode,
+ const string& description = "");
+ OperationDepsNode *add_operation_node(ID *id,
+ eDepsNode_Type comp_type,
+ const string& comp_name,
+ eDepsOperation_Type optype,
+ DepsEvalOperationCb op,
+ eDepsOperation_Code opcode,
+ const string& description = "");
+ OperationDepsNode *add_operation_node(ID *id,
+ eDepsNode_Type comp_type,
+ eDepsOperation_Type optype,
+ DepsEvalOperationCb op,
+ eDepsOperation_Code opcode,
+ const string& description = "");
+
+ bool has_operation_node(ID *id,
+ eDepsNode_Type comp_type,
+ const string& comp_name,
+ eDepsOperation_Code opcode,
+ const string& description = "");
+
+ OperationDepsNode *find_operation_node(ID *id,
+ eDepsNode_Type comp_type,
+ const string &comp_name,
+ eDepsOperation_Code opcode,
+ const string &description = "");
+
+ OperationDepsNode *find_operation_node(ID *id,
+ eDepsNode_Type comp_type,
+ eDepsOperation_Code opcode,
+ const string &description = "");
+
+ void build_scene(Main *bmain, Scene *scene);
+ SubgraphDepsNode *build_subgraph(Group *group);
+ void build_group(Scene *scene, Base *base, Group *group);
+ void build_object(Scene *scene, Base *base, Object *ob);
+ void build_object_transform(Scene *scene, Object *ob);
+ void build_object_constraints(Scene *scene, Object *ob);
+ void build_pose_constraints(Object *ob, bPoseChannel *pchan);
+ void build_rigidbody(Scene *scene);
+ void build_particles(Scene *scene, Object *ob);
+ void build_animdata(ID *id);
+ OperationDepsNode *build_driver(ID *id, FCurve *fcurve);
+ void build_ik_pose(Scene *scene,
+ Object *ob,
+ bPoseChannel *pchan,
+ bConstraint *con);
+ void build_splineik_pose(Scene *scene,
+ Object *ob,
+ bPoseChannel *pchan,
+ bConstraint *con);
+ void build_rig(Scene *scene, Object *ob);
+ void build_proxy_rig(Object *ob);
+ void build_shapekeys(Key *key);
+ void build_obdata_geom(Scene *scene, Object *ob);
+ void build_camera(Object *ob);
+ void build_lamp(Object *ob);
+ void build_nodetree(DepsNode *owner_node, bNodeTree *ntree);
+ void build_material(DepsNode *owner_node, Material *ma);
+ void build_texture(DepsNode *owner_node, Tex *tex);
+ void build_texture_stack(DepsNode *owner_node, MTex **texture_stack);
+ void build_world(World *world);
+ void build_compositor(Scene *scene);
+ void build_gpencil(bGPdata *gpd);
+ void build_cachefile(CacheFile *cache_file);
+
+protected:
+ Main *m_bmain;
+ Depsgraph *m_graph;
+};
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/util/depsgraph_util_pchanmap.cc b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
index 80b37ec622d..f870a33fb68 100644
--- a/source/blender/depsgraph/util/depsgraph_util_pchanmap.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
@@ -24,11 +24,11 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/util/depsgraph_util_pchanmap.cc
+/** \file blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
* \ingroup depsgraph
*/
-#include "depsgraph_util_pchanmap.h"
+#include "intern/builder/deg_builder_pchanmap.h"
#include <stdio.h>
#include <string.h>
@@ -38,6 +38,8 @@ extern "C" {
#include "BLI_ghash.h"
}
+namespace DEG {
+
static void free_rootpchanmap_valueset(void *val)
{
/* Just need to free the set itself - the names stored are all references. */
@@ -48,13 +50,13 @@ static void free_rootpchanmap_valueset(void *val)
RootPChanMap::RootPChanMap()
{
/* Just create empty map. */
- m_map = BLI_ghash_str_new("RootPChanMap");
+ map_ = BLI_ghash_str_new("RootPChanMap");
}
RootPChanMap::~RootPChanMap()
{
/* Free the map, and all the value sets. */
- BLI_ghash_free(m_map, NULL, free_rootpchanmap_valueset);
+ BLI_ghash_free(map_, NULL, free_rootpchanmap_valueset);
}
/* Debug contents of map */
@@ -64,7 +66,7 @@ void RootPChanMap::print_debug()
GSetIterator it2;
printf("Root PChan Map:\n");
- GHASH_ITER(it1, m_map) {
+ GHASH_ITER(it1, map_) {
const char *item = (const char *)BLI_ghashIterator_getKey(&it1);
GSet *values = (GSet *)BLI_ghashIterator_getValue(&it1);
@@ -80,11 +82,11 @@ void RootPChanMap::print_debug()
/* Add a mapping. */
void RootPChanMap::add_bone(const char *bone, const char *root)
{
- if (BLI_ghash_haskey(m_map, bone)) {
+ if (BLI_ghash_haskey(map_, bone)) {
/* Add new entry, but only add the root if it doesn't already
* exist in there.
*/
- GSet *values = (GSet *)BLI_ghash_lookup(m_map, bone);
+ GSet *values = (GSet *)BLI_ghash_lookup(map_, bone);
BLI_gset_add(values, (void *)root);
}
else {
@@ -92,7 +94,7 @@ void RootPChanMap::add_bone(const char *bone, const char *root)
GSet *values = BLI_gset_new(BLI_ghashutil_strhash_p,
BLI_ghashutil_strcmp,
"RootPChanMap Value Set");
- BLI_ghash_insert(m_map, (void *)bone, (void *)values);
+ BLI_ghash_insert(map_, (void *)bone, (void *)values);
/* Add new entry now. */
BLI_gset_insert(values, (void *)root);
@@ -103,20 +105,20 @@ void RootPChanMap::add_bone(const char *bone, const char *root)
bool RootPChanMap::has_common_root(const char *bone1, const char *bone2)
{
/* Ensure that both are in the map... */
- if (BLI_ghash_haskey(m_map, bone1) == false) {
+ if (BLI_ghash_haskey(map_, bone1) == false) {
//fprintf("RootPChanMap: bone1 '%s' not found (%s => %s)\n", bone1, bone1, bone2);
//print_debug();
return false;
}
- if (BLI_ghash_haskey(m_map, bone2) == false) {
+ if (BLI_ghash_haskey(map_, bone2) == false) {
//fprintf("RootPChanMap: bone2 '%s' not found (%s => %s)\n", bone2, bone1, bone2);
//print_debug();
return false;
}
- GSet *bone1_roots = (GSet *)BLI_ghash_lookup(m_map, (void *)bone1);
- GSet *bone2_roots = (GSet *)BLI_ghash_lookup(m_map, (void *)bone2);
+ GSet *bone1_roots = (GSet *)BLI_ghash_lookup(map_, (void *)bone1);
+ GSet *bone2_roots = (GSet *)BLI_ghash_lookup(map_, (void *)bone2);
GSetIterator it1, it2;
GSET_ITER(it1, bone1_roots) {
@@ -134,3 +136,5 @@ bool RootPChanMap::has_common_root(const char *bone1, const char *bone2)
//fprintf("RootPChanMap: No common root found (%s => %s)\n", bone1, bone2);
return false;
}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/util/depsgraph_util_pchanmap.h b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h
index b7f4c495933..233d8602fce 100644
--- a/source/blender/depsgraph/util/depsgraph_util_pchanmap.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h
@@ -24,12 +24,15 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/util/depsgraph_util_pchanmap.h
+/** \file blender/depsgraph/intern/builder/deg_builder_pchanmap.h
* \ingroup depsgraph
*/
-#ifndef __DEPSGRAPH_UTIL_PCHANMAP_H__
-#define __DEPSGRAPH_UTIL_PCHANMAP_H__
+#pragma once
+
+struct GHash;
+
+namespace DEG {
struct RootPChanMap {
/* ctor and dtor - Create and free the internal map respectively. */
@@ -45,7 +48,7 @@ struct RootPChanMap {
/* Check if there's a common root bone between two bones. */
bool has_common_root(const char *bone1, const char *bone2);
-private:
+protected:
/* The actual map:
* - Keys are "strings" (const char *) - not dynamically allocated.
* - Values are "sets" (const char *) - not dynamically allocated.
@@ -53,7 +56,7 @@ private:
* We don't use the C++ maps here, as it's more convenient to use
* Blender's GHash and be able to compare by-value instead of by-ref.
*/
- struct GHash *m_map;
+ struct GHash *map_;
};
-#endif /* __DEPSGRAPH_UTIL_PCHANMAP_H__ */
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_build_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 226991e7b11..09c7d9ab9de 100644
--- a/source/blender/depsgraph/intern/depsgraph_build_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -24,12 +24,14 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/depsgraph_build_relations.cc
+/** \file blender/depsgraph/intern/builder/deg_builder_relations.cc
* \ingroup depsgraph
*
* Methods for constructing depsgraph
*/
+#include "intern/builder/deg_builder_relations.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -45,6 +47,7 @@ extern "C" {
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_camera_types.h"
+#include "DNA_cachefile_types.h"
#include "DNA_constraint_types.h"
#include "DNA_curve_types.h"
#include "DNA_effect_types.h"
@@ -62,6 +65,7 @@ extern "C" {
#include "DNA_scene_types.h"
#include "DNA_texture_types.h"
#include "DNA_world_types.h"
+#include "DNA_object_force.h"
#include "BKE_action.h"
#include "BKE_armature.h"
@@ -69,6 +73,7 @@ extern "C" {
#include "BKE_constraint.h"
#include "BKE_curve.h"
#include "BKE_effect.h"
+#include "BKE_collision.h"
#include "BKE_fcurve.h"
#include "BKE_group.h"
#include "BKE_key.h"
@@ -93,19 +98,49 @@ extern "C" {
#include "RNA_types.h"
} /* extern "C" */
-#include "depsnode.h"
-#include "depsnode_component.h"
-#include "depsnode_operation.h"
-#include "depsgraph_build.h"
-#include "depsgraph_debug.h"
-#include "depsgraph_intern.h"
-#include "depsgraph_types.h"
+#include "intern/builder/deg_builder.h"
+#include "intern/builder/deg_builder_pchanmap.h"
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+
+#include "intern/depsgraph_intern.h"
+#include "intern/depsgraph_types.h"
-#include "depsgraph_util_pchanmap.h"
+#include "util/deg_util_foreach.h"
+
+namespace DEG {
/* ***************** */
/* Relations Builder */
+/* TODO(sergey): This is somewhat weak, but we don't want neither false-positive
+ * time dependencies nor special exceptions in the depsgraph evaluation.
+ */
+static bool python_driver_depends_on_time(ChannelDriver *driver)
+{
+ if (driver->expression[0] == '\0') {
+ /* Empty expression depends on nothing. */
+ return false;
+ }
+ if (strchr(driver->expression, '(') != NULL) {
+ /* Function calls are considered dependent on a time. */
+ return true;
+ }
+ if (strstr(driver->expression, "time") != NULL) {
+ /* Variable `time` depends on time. */
+ /* TODO(sergey): This is a bit weak, but not sure about better way of
+ * handling this.
+ */
+ return true;
+ }
+ /* Possible indirect time relation s should be handled via variable
+ * targets.
+ */
+ return false;
+}
+
/* **** General purpose functions **** */
RNAPathKey::RNAPathKey(ID *id, const char *path) :
@@ -236,6 +271,69 @@ void DepsgraphRelationBuilder::add_operation_relation(
}
}
+void DepsgraphRelationBuilder::add_collision_relations(const OperationKey &key, Scene *scene, Object *ob, Group *group, int layer, bool dupli, const char *name)
+{
+ unsigned int numcollobj;
+ Object **collobjs = get_collisionobjects_ext(scene, ob, group, layer, &numcollobj, eModifierType_Collision, dupli);
+
+ for (unsigned int i = 0; i < numcollobj; i++)
+ {
+ Object *ob1 = collobjs[i];
+
+ ComponentKey trf_key(&ob1->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(trf_key, key, DEPSREL_TYPE_STANDARD, name);
+
+ ComponentKey coll_key(&ob1->id, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(coll_key, key, DEPSREL_TYPE_STANDARD, name);
+ }
+
+ if (collobjs)
+ MEM_freeN(collobjs);
+}
+
+void DepsgraphRelationBuilder::add_forcefield_relations(const OperationKey &key, Scene *scene, Object *ob, ParticleSystem *psys, EffectorWeights *eff, bool add_absorption, const char *name)
+{
+ ListBase *effectors = pdInitEffectors(scene, ob, psys, eff, false);
+
+ if (effectors) {
+ for (EffectorCache *eff = (EffectorCache *)effectors->first; eff; eff = eff->next) {
+ if (eff->ob != ob) {
+ ComponentKey eff_key(&eff->ob->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(eff_key, key, DEPSREL_TYPE_STANDARD, name);
+ }
+
+ if (eff->psys) {
+ if (eff->ob != ob) {
+ ComponentKey eff_key(&eff->ob->id, DEPSNODE_TYPE_EVAL_PARTICLES);
+ add_relation(eff_key, key, DEPSREL_TYPE_STANDARD, name);
+
+ /* TODO: remove this when/if EVAL_PARTICLES is sufficient for up to date particles */
+ ComponentKey mod_key(&eff->ob->id, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(mod_key, key, DEPSREL_TYPE_STANDARD, name);
+ }
+ else if (eff->psys != psys) {
+ OperationKey eff_key(&eff->ob->id, DEPSNODE_TYPE_EVAL_PARTICLES, DEG_OPCODE_PSYS_EVAL, eff->psys->name);
+ add_relation(eff_key, key, DEPSREL_TYPE_STANDARD, name);
+ }
+ }
+
+ if (eff->pd->forcefield == PFIELD_SMOKEFLOW && eff->pd->f_source) {
+ ComponentKey trf_key(&eff->pd->f_source->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(trf_key, key, DEPSREL_TYPE_STANDARD, "Smoke Force Domain");
+
+ ComponentKey eff_key(&eff->pd->f_source->id, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(eff_key, key, DEPSREL_TYPE_STANDARD, "Smoke Force Domain");
+ }
+
+ if (add_absorption && (eff->pd->flag & PFIELD_VISIBILITY)) {
+ add_collision_relations(key, scene, ob, NULL, eff->ob->lay, true, "Force Absorption");
+ }
+ }
+ }
+
+ pdEndEffectors(&effectors);
+}
+
/* **** Functions to build relations between entities **** */
void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene)
@@ -244,6 +342,13 @@ void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene)
* created or not.
*/
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+ /* XXX nested node trees are not included in tag-clearing above,
+ * so we need to do this manually.
+ */
+ FOREACH_NODETREE(bmain, nodetree, id) {
+ if (id != (ID *)nodetree)
+ nodetree->id.tag &= ~LIB_TAG_DOIT;
+ } FOREACH_NODETREE_END
if (scene->set) {
// TODO: link set to scene, especially our timesource...
@@ -258,6 +363,7 @@ void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene)
/* object that this is a proxy for */
if (ob->proxy) {
+ ob->proxy->proxy_from = ob;
build_object(bmain, scene, ob->proxy);
/* TODO(sergey): This is an inverted relation, matches old depsgraph
* behavior and need to be investigated if it still need to be inverted.
@@ -297,6 +403,19 @@ void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene)
if (scene->gpd) {
build_gpencil(&scene->id, scene->gpd);
}
+
+ for (Depsgraph::OperationNodes::const_iterator it_op = m_graph->operations.begin();
+ it_op != m_graph->operations.end();
+ ++it_op)
+ {
+ OperationDepsNode *node = *it_op;
+ IDDepsNode *id_node = node->owner->owner;
+ ID *id = id_node->id;
+ if (GS(id->name) == ID_OB) {
+ Object *object = (Object *)id;
+ object->customdata_mask |= node->customdata_mask;
+ }
+ }
}
void DepsgraphRelationBuilder::build_group(Main *bmain,
@@ -407,9 +526,8 @@ void DepsgraphRelationBuilder::build_object(Main *bmain, Scene *scene, Object *o
break;
}
-
case OB_ARMATURE: /* Pose */
- if (ob->id.lib != NULL && ob->proxy_from != NULL) {
+ if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from != NULL) {
build_proxy_rig(ob);
}
else {
@@ -466,8 +584,12 @@ void DepsgraphRelationBuilder::build_object_parent(Object *ob)
{
ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_GEOMETRY);
add_relation(parent_key, ob_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Vertex Parent");
+
/* XXX not sure what this is for or how you could be done properly - lukas */
- //parent_node->customdata_mask |= CD_MASK_ORIGINDEX;
+ OperationDepsNode *parent_node = find_operation_node(parent_key);
+ if (parent_node != NULL) {
+ parent_node->customdata_mask |= CD_MASK_ORIGINDEX;
+ }
ComponentKey transform_key(&ob->parent->id, DEPSNODE_TYPE_TRANSFORM);
add_relation(transform_key, ob_key, DEPSREL_TYPE_TRANSFORM, "Vertex Parent TFM");
@@ -569,6 +691,18 @@ void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode
TimeSourceKey time_src_key;
add_relation(time_src_key, constraint_op_key, DEPSREL_TYPE_TIME, "[TimeSrc -> Animation]");
}
+ else if (cti->type == CONSTRAINT_TYPE_TRANSFORM_CACHE) {
+ /* TODO(kevin): This is more a TimeSource -> CacheFile -> Constraint dependency chain. */
+ TimeSourceKey time_src_key;
+ add_relation(time_src_key, constraint_op_key, DEPSREL_TYPE_TIME, "[TimeSrc -> Animation]");
+
+ bTransformCacheConstraint *data = (bTransformCacheConstraint *)con->data;
+
+ if (data->cache_file) {
+ ComponentKey cache_key(&data->cache_file->id, DEPSNODE_TYPE_CACHE);
+ add_relation(cache_key, constraint_op_key, DEPSREL_TYPE_CACHE, cti->name);
+ }
+ }
else if (cti->get_constraint_targets) {
ListBase targets = {NULL, NULL};
cti->get_constraint_targets(con, &targets);
@@ -618,7 +752,10 @@ void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode
add_relation(target_key, constraint_op_key, DEPSREL_TYPE_GEOMETRY_EVAL, cti->name);
if (ct->tar->type == OB_MESH) {
- //node2->customdata_mask |= CD_MASK_MDEFORMVERT;
+ OperationDepsNode *node2 = find_operation_node(target_key);
+ if (node2 != NULL) {
+ node2->customdata_mask |= CD_MASK_MDEFORMVERT;
+ }
}
}
else if (con->type == CONSTRAINT_TYPE_SHRINKWRAP) {
@@ -759,8 +896,7 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
if (arm_node && bone_name) {
/* find objects which use this, and make their eval callbacks depend on this */
- DEPSNODE_RELATIONS_ITER_BEGIN(arm_node->outlinks, rel)
- {
+ foreach (DepsRelation *rel, arm_node->outlinks) {
IDDepsNode *to_node = (IDDepsNode *)rel->to;
/* we only care about objects with pose data which use this... */
@@ -774,7 +910,6 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
}
}
}
- DEPSNODE_RELATIONS_ITER_END;
/* free temp data */
MEM_freeN(bone_name);
@@ -889,6 +1024,12 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
}
}
else {
+ if (dtar->id == id) {
+ /* Ignore input dependency if we're driving properties of the same ID,
+ * otherwise we'll be ending up in a cyclic dependency here.
+ */
+ continue;
+ }
/* resolve path to get node */
RNAPathKey target_key(dtar->id, dtar->rna_path ? dtar->rna_path : "");
add_relation(target_key, driver_key, DEPSREL_TYPE_DRIVER_TARGET, "[RNA Target -> Driver]");
@@ -901,7 +1042,9 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
* so for now we'll be quite conservative here about optimization and consider
* all python drivers to be depending on time.
*/
- if (driver->type == DRIVER_TYPE_PYTHON) {
+ if ((driver->type == DRIVER_TYPE_PYTHON) &&
+ python_driver_depends_on_time(driver))
+ {
TimeSourceKey time_src_key;
add_relation(time_src_key, driver_key, DEPSREL_TYPE_TIME, "[TimeSrc -> Driver]");
}
@@ -1038,7 +1181,7 @@ void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob)
OperationKey psys_key(&ob->id, DEPSNODE_TYPE_EVAL_PARTICLES, DEG_OPCODE_PSYS_EVAL, psys->name);
/* XXX: if particle system is later re-enabled, we must do full rebuild? */
- if (!psys_check_enabled(ob, psys))
+ if (!psys_check_enabled(ob, psys, G.is_rendering))
continue;
/* TODO(sergey): Are all particle systems depends on time?
@@ -1087,20 +1230,13 @@ void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob)
}
#endif
- /* effectors */
- ListBase *effectors = pdInitEffectors(scene, ob, psys, part->effector_weights, false);
-
- if (effectors) {
- for (EffectorCache *eff = (EffectorCache *)effectors->first; eff; eff = eff->next) {
- if (eff->psys) {
- // XXX: DAG_RL_DATA_DATA | DAG_RL_OB_DATA
- ComponentKey eff_key(&eff->ob->id, DEPSNODE_TYPE_GEOMETRY); // xxx: particles instead?
- add_relation(eff_key, psys_key, DEPSREL_TYPE_STANDARD, "Particle Field");
- }
- }
+ /* collisions */
+ if (part->type != PART_HAIR) {
+ add_collision_relations(psys_key, scene, ob, part->collision_group, ob->lay, true, "Particle Collision");
}
- pdEndEffectors(&effectors);
+ /* effectors */
+ add_forcefield_relations(psys_key, scene, ob, psys, part->effector_weights, part->type == PART_HAIR, "Particle Field");
/* boids */
if (part->boids) {
@@ -1195,7 +1331,10 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name);
if (data->tar->type == OB_MESH) {
- //node2->customdata_mask |= CD_MASK_MDEFORMVERT;
+ OperationDepsNode *node2 = find_operation_node(target_key);
+ if (node2 != NULL) {
+ node2->customdata_mask |= CD_MASK_MDEFORMVERT;
+ }
}
}
else {
@@ -1227,7 +1366,10 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name);
if (data->poletar->type == OB_MESH) {
- //node2->customdata_mask |= CD_MASK_MDEFORMVERT;
+ OperationDepsNode *node2 = find_operation_node(target_key);
+ if (node2 != NULL) {
+ node2->customdata_mask |= CD_MASK_MDEFORMVERT;
+ }
}
}
else {
@@ -1274,10 +1416,12 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result");
}
+ else {
+ OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
+ add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "IK Solver Result");
+ }
parchan->flag |= POSE_DONE;
- OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
- add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "IK Solver Result");
root_map->add_bone(parchan->name, rootchan->name);
@@ -1389,20 +1533,20 @@ void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob)
}
/* IK Solvers...
- * - These require separate processing steps are pose-level
- * to be executed between chains of bones (i.e. once the
- * base transforms of a bunch of bones is done)
- *
- * - We build relations for these before the dependencies
- * between ops in the same component as it is necessary
- * to check whether such bones are in the same IK chain
- * (or else we get weird issues with either in-chain
- * references, or with bones being parented to IK'd bones)
- *
- * Unsolved Issues:
- * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building
- * - Animated chain-lengths are a problem...
- */
+ * - These require separate processing steps are pose-level
+ * to be executed between chains of bones (i.e. once the
+ * base transforms of a bunch of bones is done)
+ *
+ * - We build relations for these before the dependencies
+ * between ops in the same component as it is necessary
+ * to check whether such bones are in the same IK chain
+ * (or else we get weird issues with either in-chain
+ * references, or with bones being parented to IK'd bones)
+ *
+ * Unsolved Issues:
+ * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building
+ * - Animated chain-lengths are a problem...
+ */
RootPChanMap root_map;
bool pose_depends_on_local_transform = false;
for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
@@ -1603,13 +1747,18 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje
if (mti->updateDepsgraph) {
DepsNodeHandle handle = create_node_handle(mod_key);
- mti->updateDepsgraph(md, bmain, scene, ob, &handle);
+ mti->updateDepsgraph(
+ md,
+ bmain,
+ scene,
+ ob,
+ reinterpret_cast< ::DepsNodeHandle* >(&handle));
}
if (BKE_object_modifier_use_time(ob, md)) {
TimeSourceKey time_src_key;
add_relation(time_src_key, mod_key, DEPSREL_TYPE_TIME, "Time Source");
-
+
/* Hacky fix for T45633 (Animated modifiers aren't updated)
*
* This check works because BKE_object_modifier_use_time() tests
@@ -1683,7 +1832,9 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje
if (mom != ob) {
/* non-motherball -> cannot be directly evaluated! */
ComponentKey mom_key(&mom->id, DEPSNODE_TYPE_GEOMETRY);
+ ComponentKey transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM);
add_relation(geom_key, mom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Metaball Motherball");
+ add_relation(transform_key, mom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Metaball Motherball");
}
break;
}
@@ -1917,3 +2068,4 @@ bool DepsgraphRelationBuilder::needs_animdata_node(ID *id)
return false;
}
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_build.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index c5b04ec299c..5240aa24b54 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -24,12 +24,26 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/depsgraph_build.h
+/** \file blender/depsgraph/intern/builder/deg_builder_relations.h
* \ingroup depsgraph
*/
-#ifndef __DEPSGRAPH_BUILD_H__
-#define __DEPSGRAPH_BUILD_H__
+#pragma once
+
+#include <cstdio>
+
+#include "intern/depsgraph_types.h"
+
+#include "DNA_ID.h"
+
+#include "RNA_access.h"
+#include "RNA_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_string.h"
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_operation.h"
struct Base;
struct bGPdata;
@@ -49,9 +63,13 @@ struct bConstraint;
struct Scene;
struct Tex;
struct World;
+struct EffectorWeights;
+struct ParticleSystem;
struct PropertyRNA;
+namespace DEG {
+
struct Depsgraph;
struct DepsNode;
struct DepsNodeHandle;
@@ -63,75 +81,6 @@ struct ComponentDepsNode;
struct OperationDepsNode;
struct RootPChanMap;
-struct DepsgraphNodeBuilder {
- DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph);
- ~DepsgraphNodeBuilder();
-
- RootDepsNode *add_root_node();
- IDDepsNode *add_id_node(ID *id);
- TimeSourceDepsNode *add_time_source(ID *id);
-
- ComponentDepsNode *add_component_node(ID *id, eDepsNode_Type comp_type, const string &comp_name = "");
-
- OperationDepsNode *add_operation_node(ComponentDepsNode *comp_node, eDepsOperation_Type optype,
- DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &description = "");
- OperationDepsNode *add_operation_node(ID *id, eDepsNode_Type comp_type, const string &comp_name, eDepsOperation_Type optype,
- DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &description = "");
- OperationDepsNode *add_operation_node(ID *id, eDepsNode_Type comp_type, eDepsOperation_Type optype,
- DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &description = "")
- {
- return add_operation_node(id, comp_type, "", optype, op, opcode, description);
- }
-
- bool has_operation_node(ID *id, eDepsNode_Type comp_type, const string &comp_name,
- eDepsOperation_Code opcode, const string &description = "");
-
- OperationDepsNode *find_operation_node(ID *id,
- eDepsNode_Type comp_type,
- const string &comp_name,
- eDepsOperation_Code opcode,
- const string &description = "");
-
- OperationDepsNode *find_operation_node(ID *id,
- eDepsNode_Type comp_type,
- eDepsOperation_Code opcode,
- const string &description = "")
- {
- return find_operation_node(id, comp_type, "", opcode, description);
- }
-
- void build_scene(Main *bmain, Scene *scene);
- SubgraphDepsNode *build_subgraph(Group *group);
- void build_group(Scene *scene, Base *base, Group *group);
- void build_object(Scene *scene, Base *base, Object *ob);
- void build_object_transform(Scene *scene, Object *ob);
- void build_object_constraints(Scene *scene, Object *ob);
- void build_pose_constraints(Object *ob, bPoseChannel *pchan);
- void build_rigidbody(Scene *scene);
- void build_particles(Scene *scene, Object *ob);
- void build_animdata(ID *id);
- OperationDepsNode *build_driver(ID *id, FCurve *fcurve);
- void build_ik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con);
- void build_splineik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con);
- void build_rig(Scene *scene, Object *ob);
- void build_proxy_rig(Object *ob);
- void build_shapekeys(Key *key);
- void build_obdata_geom(Scene *scene, Object *ob);
- void build_camera(Object *ob);
- void build_lamp(Object *ob);
- void build_nodetree(DepsNode *owner_node, bNodeTree *ntree);
- void build_material(DepsNode *owner_node, Material *ma);
- void build_texture(DepsNode *owner_node, Tex *tex);
- void build_texture_stack(DepsNode *owner_node, MTex **texture_stack);
- void build_world(World *world);
- void build_compositor(Scene *scene);
- void build_gpencil(bGPdata *gpd);
-
-private:
- Main *m_bmain;
- Depsgraph *m_graph;
-};
-
struct RootKey
{
RootKey() {}
@@ -164,7 +113,7 @@ struct ComponentKey
const char *idname = (id) ? id->name : "<None>";
char typebuf[5];
- sprintf(typebuf, "%d", type);
+ BLI_snprintf(typebuf, sizeof(typebuf), "%d", type);
return string("ComponentKey(") + idname + ", " + typebuf + ", '" + name + "')";
}
@@ -204,7 +153,7 @@ struct OperationKey
string identifier() const
{
char typebuf[5];
- sprintf(typebuf, "%d", component_type);
+ BLI_snprintf(typebuf, sizeof(typebuf), "%d", component_type);
return string("OperationKey(") + "t: " + typebuf + ", cn: '" + component_name + "', c: " + DEG_OPNAMES[opcode] + ", n: '" + name + "')";
}
@@ -245,30 +194,45 @@ struct DepsgraphRelationBuilder
DepsgraphRelationBuilder(Depsgraph *graph);
template <typename KeyFrom, typename KeyTo>
- void add_relation(const KeyFrom &key_from, const KeyTo &key_to,
- eDepsRelation_Type type, const char *description);
+ void add_relation(const KeyFrom& key_from,
+ const KeyTo& key_to,
+ eDepsRelation_Type type,
+ const char *description);
template <typename KeyTo>
- void add_relation(const TimeSourceKey &key_from, const KeyTo &key_to,
- eDepsRelation_Type type, const char *description);
+ void add_relation(const TimeSourceKey& key_from,
+ const KeyTo& key_to,
+ eDepsRelation_Type type,
+ const char *description);
template <typename KeyType>
- void add_node_handle_relation(const KeyType &key_from, const DepsNodeHandle *handle,
- eDepsRelation_Type type, const char *description);
+ void add_node_handle_relation(const KeyType& key_from,
+ const DepsNodeHandle *handle,
+ eDepsRelation_Type type,
+ const char *description);
void build_scene(Main *bmain, Scene *scene);
void build_group(Main *bmain, Scene *scene, Object *object, Group *group);
void build_object(Main *bmain, Scene *scene, Object *ob);
void build_object_parent(Object *ob);
- void build_constraints(Scene *scene, ID *id, eDepsNode_Type component_type, const char *component_subdata,
- ListBase *constraints, RootPChanMap *root_map);
+ void build_constraints(Scene *scene, ID *id,
+ eDepsNode_Type component_type,
+ const char *component_subdata,
+ ListBase *constraints,
+ RootPChanMap *root_map);
void build_animdata(ID *id);
void build_driver(ID *id, FCurve *fcurve);
void build_world(World *world);
void build_rigidbody(Scene *scene);
void build_particles(Scene *scene, Object *ob);
- void build_ik_pose(Object *ob, bPoseChannel *pchan, bConstraint *con, RootPChanMap *root_map);
- void build_splineik_pose(Object *ob, bPoseChannel *pchan, bConstraint *con, RootPChanMap *root_map);
+ void build_ik_pose(Object *ob,
+ bPoseChannel *pchan,
+ bConstraint *con,
+ RootPChanMap *root_map);
+ void build_splineik_pose(Object *ob,
+ bPoseChannel *pchan,
+ bConstraint *con,
+ RootPChanMap *root_map);
void build_rig(Scene *scene, Object *ob);
void build_proxy_rig(Object *ob);
void build_shapekeys(ID *obdata, Key *key);
@@ -282,6 +246,12 @@ struct DepsgraphRelationBuilder
void build_compositor(Scene *scene);
void build_gpencil(ID *owner, bGPdata *gpd);
+ void add_collision_relations(const OperationKey &key, Scene *scene, Object *ob, Group *group, int layer, bool dupli, const char *name);
+ void add_forcefield_relations(const OperationKey &key, Scene *scene, Object *ob, ParticleSystem *psys, EffectorWeights *eff, bool add_absorption, const char *name);
+
+ template <typename KeyType>
+ OperationDepsNode *find_operation_node(const KeyType &key);
+
protected:
RootDepsNode *find_node(const RootKey &key) const;
TimeSourceDepsNode *find_node(const TimeSourceKey &key) const;
@@ -290,12 +260,17 @@ protected:
DepsNode *find_node(const RNAPathKey &key) const;
OperationDepsNode *has_node(const OperationKey &key) const;
- void add_time_relation(TimeSourceDepsNode *timesrc, DepsNode *node_to, const char *description);
- void add_operation_relation(OperationDepsNode *node_from, OperationDepsNode *node_to,
- eDepsRelation_Type type, const char *description);
+ void add_time_relation(TimeSourceDepsNode *timesrc,
+ DepsNode *node_to,
+ const char *description);
+ void add_operation_relation(OperationDepsNode *node_from,
+ OperationDepsNode *node_to,
+ eDepsRelation_Type type,
+ const char *description);
template <typename KeyType>
- DepsNodeHandle create_node_handle(const KeyType &key, const string &default_name = "");
+ DepsNodeHandle create_node_handle(const KeyType& key,
+ const string& default_name = "");
bool needs_animdata_node(ID *id);
@@ -320,8 +295,12 @@ struct DepsNodeHandle
/* Utilities for Builders ----------------------------------------------------- */
-/* Get unique identifier for FCurves and Drivers */
-string deg_fcurve_id_name(const FCurve *fcu);
+template <typename KeyType>
+OperationDepsNode *DepsgraphRelationBuilder::find_operation_node(const KeyType& key)
+{
+ DepsNode *node = find_node(key);
+ return node != NULL ? node->get_exit_operation() : NULL;
+}
template <typename KeyFrom, typename KeyTo>
void DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from,
@@ -377,10 +356,11 @@ void DepsgraphRelationBuilder::add_relation(const TimeSourceKey &key_from,
}
template <typename KeyType>
-void DepsgraphRelationBuilder::add_node_handle_relation(const KeyType &key_from,
- const DepsNodeHandle *handle,
- eDepsRelation_Type type,
- const char *description)
+void DepsgraphRelationBuilder::add_node_handle_relation(
+ const KeyType &key_from,
+ const DepsNodeHandle *handle,
+ eDepsRelation_Type type,
+ const char *description)
{
DepsNode *node_from = find_node(key_from);
OperationDepsNode *op_from = node_from ? node_from->get_exit_operation() : NULL;
@@ -390,19 +370,22 @@ void DepsgraphRelationBuilder::add_node_handle_relation(const KeyType &key_from,
}
else {
if (!op_from) {
- /* XXX TODO handle as error or report if needed */
+ fprintf(stderr, "add_node_handle_relation(%d, %s) - Could not find op_from (%s)\n",
+ type, description, key_from.identifier().c_str());
}
if (!op_to) {
- /* XXX TODO handle as error or report if needed */
+ fprintf(stderr, "add_node_handle_relation(%d, %s) - Could not find op_to (%s)\n",
+ type, description, key_from.identifier().c_str());
}
}
}
template <typename KeyType>
-DepsNodeHandle DepsgraphRelationBuilder::create_node_handle(const KeyType &key,
- const string &default_name)
+DepsNodeHandle DepsgraphRelationBuilder::create_node_handle(
+ const KeyType &key,
+ const string &default_name)
{
return DepsNodeHandle(this, find_node(key), default_name);
}
-#endif /* __DEPSGRAPH_BUILD_H__ */
+} // namespace DEG
diff --git a/source/blender/depsgraph/util/depsgraph_util_transitive.cc b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
index 98192a9540f..da71db09f3d 100644
--- a/source/blender/depsgraph/util/depsgraph_util_transitive.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
@@ -24,31 +24,30 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/util/depsgraph_util_transitive.cc
+/** \file blender/depsgraph/intern/builder/deg_builder_transitive.cc
* \ingroup depsgraph
*/
+#include "intern/builder/deg_builder_transitive.h"
+
extern "C" {
#include "MEM_guardedalloc.h"
+}
-#include "BLI_utildefines.h"
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
-#include "DNA_ID.h"
+#include "intern/depsgraph.h"
-#include "RNA_access.h"
-#include "RNA_types.h"
-}
+#include "util/deg_util_foreach.h"
-#include "depsgraph_util_transitive.h"
-#include "depsgraph.h"
-#include "depsnode.h"
-#include "depsnode_component.h"
-#include "depsnode_operation.h"
+namespace DEG {
/* -------------------------------------------------- */
/* Performs a transitive reduction to remove redundant relations.
- * http://en.wikipedia.org/wiki/Transitive_reduction
+ * https://en.wikipedia.org/wiki/Transitive_reduction
*
* XXX The current implementation is somewhat naive and has O(V*E) worst case
* runtime.
@@ -67,16 +66,11 @@ enum {
static void deg_graph_tag_paths_recursive(DepsNode *node)
{
- if (node->done & OP_VISITED)
+ if (node->done & OP_VISITED) {
return;
+ }
node->done |= OP_VISITED;
-
- for (OperationDepsNode::Relations::const_iterator it = node->inlinks.begin();
- it != node->inlinks.end();
- ++it)
- {
- DepsRelation *rel = *it;
-
+ foreach (DepsRelation *rel, node->inlinks) {
deg_graph_tag_paths_recursive(rel->from);
/* Do this only in inlinks loop, so the target node does not get
* flagged.
@@ -87,18 +81,9 @@ static void deg_graph_tag_paths_recursive(DepsNode *node)
void deg_graph_transitive_reduction(Depsgraph *graph)
{
- for (Depsgraph::OperationNodes::const_iterator it_target = graph->operations.begin();
- it_target != graph->operations.end();
- ++it_target)
- {
- OperationDepsNode *target = *it_target;
-
+ foreach (OperationDepsNode *target, graph->operations) {
/* Clear tags. */
- for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
- it != graph->operations.end();
- ++it)
- {
- OperationDepsNode *node = *it;
+ foreach (OperationDepsNode *node, graph->operations) {
node->done = 0;
}
@@ -107,16 +92,11 @@ void deg_graph_transitive_reduction(Depsgraph *graph)
* flagged.
*/
target->done |= OP_VISITED;
- for (OperationDepsNode::Relations::const_iterator it = target->inlinks.begin();
- it != target->inlinks.end();
- ++it)
- {
- DepsRelation *rel = *it;
-
+ foreach (DepsRelation *rel, target->inlinks) {
deg_graph_tag_paths_recursive(rel->from);
}
- /* Eemove redundant paths to the target. */
+ /* Remove redundant paths to the target. */
for (DepsNode::Relations::const_iterator it_rel = target->inlinks.begin();
it_rel != target->inlinks.end();
)
@@ -137,3 +117,5 @@ void deg_graph_transitive_reduction(Depsgraph *graph)
}
}
}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/util/depsgraph_util_transitive.h b/source/blender/depsgraph/intern/builder/deg_builder_transitive.h
index a80a1d783d7..be9d7c3ca9c 100644
--- a/source/blender/depsgraph/util/depsgraph_util_transitive.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.h
@@ -24,15 +24,17 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/util/depsgraph_util_transitive.h
+/** \file blender/depsgraph/intern/builder/deg_builder_transitive.h
* \ingroup depsgraph
*/
-#ifndef __DEPSGRAPH_UTIL_TRANSITIVE_H__
-#define __DEPSGRAPH_UTIL_TRANSITIVE_H__
+#pragma once
+
+namespace DEG {
struct Depsgraph;
+/* Performs a transitive reduction to remove redundant relations. */
void deg_graph_transitive_reduction(Depsgraph *graph);
-#endif /* __DEPSGRAPH_UTIL_TRANSITIVE_H__ */
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc
new file mode 100644
index 00000000000..70cd5f11a47
--- /dev/null
+++ b/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc
@@ -0,0 +1,590 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Lukas Toenne
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/debug/deg_debug_graphviz.cc
+ * \ingroup depsgraph
+ *
+ * Implementation of tools for debugging the depsgraph
+ */
+
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+
+extern "C" {
+#include "DNA_listBase.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_debug.h"
+} /* extern "C" */
+
+#include "intern/depsgraph_intern.h"
+#include "util/deg_util_foreach.h"
+
+/* ****************** */
+/* Graphviz Debugging */
+
+namespace DEG {
+
+#define NL "\r\n"
+
+/* Only one should be enabled, defines whether graphviz nodes
+ * get colored by individual types or classes.
+ */
+#define COLOR_SCHEME_NODE_CLASS 1
+//#define COLOR_SCHEME_NODE_TYPE 2
+
+static const char *deg_debug_graphviz_fontname = "helvetica";
+static float deg_debug_graphviz_graph_label_size = 20.0f;
+static float deg_debug_graphviz_node_label_size = 14.0f;
+static const int deg_debug_max_colors = 12;
+#ifdef COLOR_SCHEME_NODE_TYPE
+static const char *deg_debug_colors[] = {
+ "#a6cee3", "#1f78b4", "#b2df8a",
+ "#33a02c", "#fb9a99", "#e31a1c",
+ "#fdbf6f", "#ff7f00", "#cab2d6",
+ "#6a3d9a", "#ffff99", "#b15928",
+};
+#endif
+static const char *deg_debug_colors_light[] = {
+ "#8dd3c7", "#ffffb3", "#bebada",
+ "#fb8072", "#80b1d3", "#fdb462",
+ "#b3de69", "#fccde5", "#d9d9d9",
+ "#bc80bd", "#ccebc5", "#ffed6f",
+};
+
+#ifdef COLOR_SCHEME_NODE_TYPE
+static const int deg_debug_node_type_color_map[][2] = {
+ {DEPSNODE_TYPE_ROOT, 0},
+ {DEPSNODE_TYPE_TIMESOURCE, 1},
+ {DEPSNODE_TYPE_ID_REF, 2},
+ {DEPSNODE_TYPE_SUBGRAPH, 3},
+
+ /* Outer Types */
+ {DEPSNODE_TYPE_PARAMETERS, 4},
+ {DEPSNODE_TYPE_PROXY, 5},
+ {DEPSNODE_TYPE_ANIMATION, 6},
+ {DEPSNODE_TYPE_TRANSFORM, 7},
+ {DEPSNODE_TYPE_GEOMETRY, 8},
+ {DEPSNODE_TYPE_SEQUENCER, 9},
+ {DEPSNODE_TYPE_SHADING, 10},
+ {DEPSNODE_TYPE_CACHE, 11},
+ {-1, 0}
+};
+#endif
+
+static int deg_debug_node_color_index(const DepsNode *node)
+{
+#ifdef COLOR_SCHEME_NODE_CLASS
+ /* Some special types. */
+ switch (node->type) {
+ case DEPSNODE_TYPE_ID_REF:
+ return 5;
+ case DEPSNODE_TYPE_OPERATION:
+ {
+ OperationDepsNode *op_node = (OperationDepsNode *)node;
+ if (op_node->is_noop())
+ return 8;
+ break;
+ }
+
+ default:
+ break;
+ }
+ /* Do others based on class. */
+ switch (node->tclass) {
+ case DEPSNODE_CLASS_OPERATION:
+ return 4;
+ case DEPSNODE_CLASS_COMPONENT:
+ return 1;
+ default:
+ return 9;
+ }
+#endif
+
+#ifdef COLOR_SCHEME_NODE_TYPE
+ const int (*pair)[2];
+ for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) {
+ if ((*pair)[0] == node->type) {
+ return (*pair)[1];
+ }
+ }
+ return -1;
+#endif
+}
+
+struct DebugContext {
+ FILE *file;
+ bool show_tags;
+ bool show_eval_priority;
+};
+
+static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...) ATTR_PRINTF_FORMAT(2, 3);
+static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ vfprintf(ctx.file, fmt, args);
+ va_end(args);
+}
+
+static void deg_debug_graphviz_legend_color(const DebugContext &ctx,
+ const char *name,
+ const char *color)
+{
+ deg_debug_fprintf(ctx, "<TR>");
+ deg_debug_fprintf(ctx, "<TD>%s</TD>", name);
+ deg_debug_fprintf(ctx, "<TD BGCOLOR=\"%s\"></TD>", color);
+ deg_debug_fprintf(ctx, "</TR>" NL);
+}
+
+static void deg_debug_graphviz_legend(const DebugContext &ctx)
+{
+ deg_debug_fprintf(ctx, "{" NL);
+ deg_debug_fprintf(ctx, "rank = sink;" NL);
+ deg_debug_fprintf(ctx, "Legend [shape=none, margin=0, label=<" NL);
+ deg_debug_fprintf(ctx, " <TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\" CELLPADDING=\"4\">" NL);
+ deg_debug_fprintf(ctx, "<TR><TD COLSPAN=\"2\"><B>Legend</B></TD></TR>" NL);
+
+#ifdef COLOR_SCHEME_NODE_CLASS
+ const char **colors = deg_debug_colors_light;
+ deg_debug_graphviz_legend_color(ctx, "Operation", colors[4]);
+ deg_debug_graphviz_legend_color(ctx, "Component", colors[1]);
+ deg_debug_graphviz_legend_color(ctx, "ID Node", colors[5]);
+ deg_debug_graphviz_legend_color(ctx, "NOOP", colors[8]);
+#endif
+
+#ifdef COLOR_SCHEME_NODE_TYPE
+ const int (*pair)[2];
+ for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) {
+ DepsNodeFactory *nti = DEG_get_node_factory((eDepsNode_Type)(*pair)[0]);
+ deg_debug_graphviz_legend_color(ctx,
+ nti->tname().c_str(),
+ deg_debug_colors_light[(*pair)[1] % deg_debug_max_colors]);
+ }
+#endif
+
+ deg_debug_fprintf(ctx, "</TABLE>" NL);
+ deg_debug_fprintf(ctx, ">" NL);
+ deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname);
+ deg_debug_fprintf(ctx, "];" NL);
+ deg_debug_fprintf(ctx, "}" NL);
+}
+
+static void deg_debug_graphviz_node_color(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ const char *color_default = "black";
+ const char *color_modified = "orangered4";
+ const char *color_update = "dodgerblue3";
+ const char *color = color_default;
+ if (ctx.show_tags) {
+ if (node->tclass == DEPSNODE_CLASS_OPERATION) {
+ OperationDepsNode *op_node = (OperationDepsNode *)node;
+ if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) {
+ color = color_modified;
+ }
+ else if (op_node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
+ color = color_update;
+ }
+ }
+ }
+ deg_debug_fprintf(ctx, "\"%s\"", color);
+}
+
+static void deg_debug_graphviz_node_penwidth(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ float penwidth_default = 1.0f;
+ float penwidth_modified = 4.0f;
+ float penwidth_update = 4.0f;
+ float penwidth = penwidth_default;
+ if (ctx.show_tags) {
+ if (node->tclass == DEPSNODE_CLASS_OPERATION) {
+ OperationDepsNode *op_node = (OperationDepsNode *)node;
+ if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) {
+ penwidth = penwidth_modified;
+ }
+ else if (op_node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
+ penwidth = penwidth_update;
+ }
+ }
+ }
+ deg_debug_fprintf(ctx, "\"%f\"", penwidth);
+}
+
+static void deg_debug_graphviz_node_fillcolor(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ const char *defaultcolor = "gainsboro";
+ int color_index = deg_debug_node_color_index(node);
+ const char *fillcolor = color_index < 0 ? defaultcolor : deg_debug_colors_light[color_index % deg_debug_max_colors];
+ deg_debug_fprintf(ctx, "\"%s\"", fillcolor);
+}
+
+static void deg_debug_graphviz_relation_color(const DebugContext &ctx,
+ const DepsRelation *rel)
+{
+ const char *color_default = "black";
+ const char *color_error = "red4";
+ const char *color = color_default;
+ if (rel->flag & DEPSREL_FLAG_CYCLIC) {
+ color = color_error;
+ }
+ deg_debug_fprintf(ctx, "%s", color);
+}
+
+static void deg_debug_graphviz_node_style(const DebugContext &ctx, const DepsNode *node)
+{
+ const char *base_style = "filled"; /* default style */
+ if (ctx.show_tags) {
+ if (node->tclass == DEPSNODE_CLASS_OPERATION) {
+ OperationDepsNode *op_node = (OperationDepsNode *)node;
+ if (op_node->flag & (DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE)) {
+ base_style = "striped";
+ }
+ }
+ }
+ switch (node->tclass) {
+ case DEPSNODE_CLASS_GENERIC:
+ deg_debug_fprintf(ctx, "\"%s\"", base_style);
+ break;
+ case DEPSNODE_CLASS_COMPONENT:
+ deg_debug_fprintf(ctx, "\"%s\"", base_style);
+ break;
+ case DEPSNODE_CLASS_OPERATION:
+ deg_debug_fprintf(ctx, "\"%s,rounded\"", base_style);
+ break;
+ }
+}
+
+static void deg_debug_graphviz_node_single(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ const char *shape = "box";
+ string name = node->identifier();
+ float priority = -1.0f;
+ if (node->type == DEPSNODE_TYPE_ID_REF) {
+ IDDepsNode *id_node = (IDDepsNode *)node;
+ char buf[256];
+ BLI_snprintf(buf, sizeof(buf), " (Layers: %u)", id_node->layers);
+ name += buf;
+ }
+ if (ctx.show_eval_priority && node->tclass == DEPSNODE_CLASS_OPERATION) {
+ priority = ((OperationDepsNode *)node)->eval_priority;
+ }
+ deg_debug_fprintf(ctx, "// %s\n", name.c_str());
+ deg_debug_fprintf(ctx, "\"node_%p\"", node);
+ deg_debug_fprintf(ctx, "[");
+// deg_debug_fprintf(ctx, "label=<<B>%s</B>>", name);
+ if (priority >= 0.0f) {
+ deg_debug_fprintf(ctx, "label=<%s<BR/>(<I>%.2f</I>)>",
+ name.c_str(),
+ priority);
+ }
+ else {
+ deg_debug_fprintf(ctx, "label=<%s>", name.c_str());
+ }
+ deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname);
+ deg_debug_fprintf(ctx, ",fontsize=%f", deg_debug_graphviz_node_label_size);
+ deg_debug_fprintf(ctx, ",shape=%s", shape);
+ deg_debug_fprintf(ctx, ",style="); deg_debug_graphviz_node_style(ctx, node);
+ deg_debug_fprintf(ctx, ",color="); deg_debug_graphviz_node_color(ctx, node);
+ deg_debug_fprintf(ctx, ",fillcolor="); deg_debug_graphviz_node_fillcolor(ctx, node);
+ deg_debug_fprintf(ctx, ",penwidth="); deg_debug_graphviz_node_penwidth(ctx, node);
+ deg_debug_fprintf(ctx, "];" NL);
+ deg_debug_fprintf(ctx, NL);
+}
+
+static void deg_debug_graphviz_node_cluster_begin(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ string name = node->identifier().c_str();
+ if (node->type == DEPSNODE_TYPE_ID_REF) {
+ IDDepsNode *id_node = (IDDepsNode *)node;
+ char buf[256];
+ BLI_snprintf(buf, sizeof(buf), " (Layers: %u)", id_node->layers);
+ name += buf;
+ }
+ deg_debug_fprintf(ctx, "// %s\n", name.c_str());
+ deg_debug_fprintf(ctx, "subgraph \"cluster_%p\" {" NL, node);
+// deg_debug_fprintf(ctx, "label=<<B>%s</B>>;" NL, name);
+ deg_debug_fprintf(ctx, "label=<%s>;" NL, name.c_str());
+ deg_debug_fprintf(ctx, "fontname=\"%s\";" NL, deg_debug_graphviz_fontname);
+ deg_debug_fprintf(ctx, "fontsize=%f;" NL, deg_debug_graphviz_node_label_size);
+ deg_debug_fprintf(ctx, "margin=\"%d\";" NL, 16);
+ deg_debug_fprintf(ctx, "style="); deg_debug_graphviz_node_style(ctx, node); deg_debug_fprintf(ctx, ";" NL);
+ deg_debug_fprintf(ctx, "color="); deg_debug_graphviz_node_color(ctx, node); deg_debug_fprintf(ctx, ";" NL);
+ deg_debug_fprintf(ctx, "fillcolor="); deg_debug_graphviz_node_fillcolor(ctx, node); deg_debug_fprintf(ctx, ";" NL);
+ deg_debug_fprintf(ctx, "penwidth="); deg_debug_graphviz_node_penwidth(ctx, node); deg_debug_fprintf(ctx, ";" NL);
+ /* dummy node, so we can add edges between clusters */
+ deg_debug_fprintf(ctx, "\"node_%p\"", node);
+ deg_debug_fprintf(ctx, "[");
+ deg_debug_fprintf(ctx, "shape=%s", "point");
+ deg_debug_fprintf(ctx, ",style=%s", "invis");
+ deg_debug_fprintf(ctx, "];" NL);
+ deg_debug_fprintf(ctx, NL);
+}
+
+static void deg_debug_graphviz_node_cluster_end(const DebugContext &ctx)
+{
+ deg_debug_fprintf(ctx, "}" NL);
+ deg_debug_fprintf(ctx, NL);
+}
+
+static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx,
+ const Depsgraph *graph);
+static void deg_debug_graphviz_graph_relations(const DebugContext &ctx,
+ const Depsgraph *graph);
+
+static void deg_debug_graphviz_node(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ switch (node->type) {
+ case DEPSNODE_TYPE_ID_REF:
+ {
+ const IDDepsNode *id_node = (const IDDepsNode *)node;
+ if (BLI_ghash_size(id_node->components) == 0) {
+ deg_debug_graphviz_node_single(ctx, node);
+ }
+ else {
+ deg_debug_graphviz_node_cluster_begin(ctx, node);
+ GHASH_FOREACH_BEGIN(const ComponentDepsNode *, comp, id_node->components)
+ {
+ deg_debug_graphviz_node(ctx, comp);
+ }
+ GHASH_FOREACH_END();
+ deg_debug_graphviz_node_cluster_end(ctx);
+ }
+ break;
+ }
+ case DEPSNODE_TYPE_SUBGRAPH:
+ {
+ SubgraphDepsNode *sub_node = (SubgraphDepsNode *)node;
+ if (sub_node->graph) {
+ deg_debug_graphviz_node_cluster_begin(ctx, node);
+ deg_debug_graphviz_graph_nodes(ctx, sub_node->graph);
+ deg_debug_graphviz_node_cluster_end(ctx);
+ }
+ else {
+ deg_debug_graphviz_node_single(ctx, node);
+ }
+ break;
+ }
+ case DEPSNODE_TYPE_PARAMETERS:
+ case DEPSNODE_TYPE_ANIMATION:
+ case DEPSNODE_TYPE_TRANSFORM:
+ case DEPSNODE_TYPE_PROXY:
+ case DEPSNODE_TYPE_GEOMETRY:
+ case DEPSNODE_TYPE_SEQUENCER:
+ case DEPSNODE_TYPE_EVAL_POSE:
+ case DEPSNODE_TYPE_BONE:
+ case DEPSNODE_TYPE_SHADING:
+ case DEPSNODE_TYPE_CACHE:
+ case DEPSNODE_TYPE_EVAL_PARTICLES:
+ {
+ ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
+ if (!comp_node->operations.empty()) {
+ deg_debug_graphviz_node_cluster_begin(ctx, node);
+ foreach (DepsNode *op_node, comp_node->operations) {
+ deg_debug_graphviz_node(ctx, op_node);
+ }
+ deg_debug_graphviz_node_cluster_end(ctx);
+ }
+ else {
+ deg_debug_graphviz_node_single(ctx, node);
+ }
+ break;
+ }
+ default:
+ deg_debug_graphviz_node_single(ctx, node);
+ break;
+ }
+}
+
+static bool deg_debug_graphviz_is_cluster(const DepsNode *node)
+{
+ switch (node->type) {
+ case DEPSNODE_TYPE_ID_REF:
+ {
+ const IDDepsNode *id_node = (const IDDepsNode *)node;
+ return BLI_ghash_size(id_node->components) > 0;
+ }
+ case DEPSNODE_TYPE_SUBGRAPH:
+ {
+ SubgraphDepsNode *sub_node = (SubgraphDepsNode *)node;
+ return sub_node->graph != NULL;
+ }
+ case DEPSNODE_TYPE_PARAMETERS:
+ case DEPSNODE_TYPE_ANIMATION:
+ case DEPSNODE_TYPE_TRANSFORM:
+ case DEPSNODE_TYPE_PROXY:
+ case DEPSNODE_TYPE_GEOMETRY:
+ case DEPSNODE_TYPE_SEQUENCER:
+ case DEPSNODE_TYPE_EVAL_POSE:
+ case DEPSNODE_TYPE_BONE:
+ {
+ ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
+ return !comp_node->operations.empty();
+ }
+ default:
+ return false;
+ }
+}
+
+static bool deg_debug_graphviz_is_owner(const DepsNode *node,
+ const DepsNode *other)
+{
+ switch (node->tclass) {
+ case DEPSNODE_CLASS_COMPONENT:
+ {
+ ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
+ if (comp_node->owner == other)
+ return true;
+ break;
+ }
+ case DEPSNODE_CLASS_OPERATION:
+ {
+ OperationDepsNode *op_node = (OperationDepsNode *)node;
+ if (op_node->owner == other)
+ return true;
+ else if (op_node->owner->owner == other)
+ return true;
+ break;
+ }
+ default: break;
+ }
+ return false;
+}
+
+static void deg_debug_graphviz_node_relations(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ foreach (DepsRelation *rel, node->inlinks) {
+ float penwidth = 2.0f;
+
+ const DepsNode *tail = rel->to; /* same as node */
+ const DepsNode *head = rel->from;
+ deg_debug_fprintf(ctx, "// %s -> %s\n",
+ head->identifier().c_str(),
+ tail->identifier().c_str());
+ deg_debug_fprintf(ctx, "\"node_%p\"", head);
+ deg_debug_fprintf(ctx, " -> ");
+ deg_debug_fprintf(ctx, "\"node_%p\"", tail);
+
+ deg_debug_fprintf(ctx, "[");
+ /* Note: without label an id seem necessary to avoid bugs in graphviz/dot */
+ deg_debug_fprintf(ctx, "id=\"%s\"", rel->name);
+ deg_debug_fprintf(ctx, ",color="); deg_debug_graphviz_relation_color(ctx, rel);
+ deg_debug_fprintf(ctx, ",penwidth=\"%f\"", penwidth);
+ /* NOTE: edge from node to own cluster is not possible and gives graphviz
+ * warning, avoid this here by just linking directly to the invisible
+ * placeholder node
+ */
+ if (deg_debug_graphviz_is_cluster(tail) && !deg_debug_graphviz_is_owner(head, tail)) {
+ deg_debug_fprintf(ctx, ",ltail=\"cluster_%p\"", tail);
+ }
+ if (deg_debug_graphviz_is_cluster(head) && !deg_debug_graphviz_is_owner(tail, head)) {
+ deg_debug_fprintf(ctx, ",lhead=\"cluster_%p\"", head);
+ }
+ deg_debug_fprintf(ctx, "];" NL);
+ deg_debug_fprintf(ctx, NL);
+ }
+}
+
+static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx,
+ const Depsgraph *graph)
+{
+ if (graph->root_node) {
+ deg_debug_graphviz_node(ctx, graph->root_node);
+ }
+ GHASH_FOREACH_BEGIN (DepsNode *, node, graph->id_hash)
+ {
+ deg_debug_graphviz_node(ctx, node);
+ }
+ GHASH_FOREACH_END();
+ TimeSourceDepsNode *time_source = graph->find_time_source(NULL);
+ if (time_source != NULL) {
+ deg_debug_graphviz_node(ctx, time_source);
+ }
+}
+
+static void deg_debug_graphviz_graph_relations(const DebugContext &ctx,
+ const Depsgraph *graph)
+{
+ GHASH_FOREACH_BEGIN(IDDepsNode *, id_node, graph->id_hash)
+ {
+ GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, id_node->components)
+ {
+ foreach (OperationDepsNode *op_node, comp_node->operations) {
+ deg_debug_graphviz_node_relations(ctx, op_node);
+ }
+ }
+ GHASH_FOREACH_END();
+ }
+ GHASH_FOREACH_END();
+
+ TimeSourceDepsNode *time_source = graph->find_time_source(NULL);
+ if (time_source != NULL) {
+ deg_debug_graphviz_node_relations(ctx, time_source);
+ }
+}
+
+} // namespace DEG
+
+void DEG_debug_graphviz(const Depsgraph *graph, FILE *f, const char *label, bool show_eval)
+{
+ if (!graph) {
+ return;
+ }
+
+ const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph);
+
+ DEG::DebugContext ctx;
+ ctx.file = f;
+ ctx.show_tags = show_eval;
+ ctx.show_eval_priority = show_eval;
+
+ DEG::deg_debug_fprintf(ctx, "digraph depgraph {" NL);
+ DEG::deg_debug_fprintf(ctx, "rankdir=LR;" NL);
+ DEG::deg_debug_fprintf(ctx, "graph [");
+ DEG::deg_debug_fprintf(ctx, "compound=true");
+ DEG::deg_debug_fprintf(ctx, ",labelloc=\"t\"");
+ DEG::deg_debug_fprintf(ctx, ",fontsize=%f", DEG::deg_debug_graphviz_graph_label_size);
+ DEG::deg_debug_fprintf(ctx, ",fontname=\"%s\"", DEG::deg_debug_graphviz_fontname);
+ DEG::deg_debug_fprintf(ctx, ",label=\"%s\"", label);
+ DEG::deg_debug_fprintf(ctx, ",splines=ortho");
+ DEG::deg_debug_fprintf(ctx, ",overlap=scalexy"); // XXX: only when using neato
+ DEG::deg_debug_fprintf(ctx, "];" NL);
+
+ DEG::deg_debug_graphviz_graph_nodes(ctx, deg_graph);
+ DEG::deg_debug_graphviz_graph_relations(ctx, deg_graph);
+
+ DEG::deg_debug_graphviz_legend(ctx);
+
+ DEG::deg_debug_fprintf(ctx, "}" NL);
+}
+
+#undef NL
diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc
index d293d03f63d..2b7c63767ab 100644
--- a/source/blender/depsgraph/intern/depsgraph.cc
+++ b/source/blender/depsgraph/intern/depsgraph.cc
@@ -30,10 +30,14 @@
* Core routines for how the Depsgraph works.
*/
+#include "intern/depsgraph.h" /* own include */
+
#include <string.h>
#include "MEM_guardedalloc.h"
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
#include "BLI_listbase.h"
extern "C" {
@@ -50,11 +54,15 @@ extern "C" {
}
#include "DEG_depsgraph.h"
-#include "depsgraph.h" /* own include */
-#include "depsnode.h"
-#include "depsnode_operation.h"
-#include "depsnode_component.h"
-#include "depsgraph_intern.h"
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+
+#include "intern/depsgraph_intern.h"
+#include "util/deg_util_foreach.h"
+
+namespace DEG {
static DEG_EditorUpdateIDCb deg_editor_update_id_cb = NULL;
static DEG_EditorUpdateSceneCb deg_editor_update_scene_cb = NULL;
@@ -66,6 +74,9 @@ Depsgraph::Depsgraph()
layers(0)
{
BLI_spin_init(&lock);
+ id_hash = BLI_ghash_ptr_new("Depsgraph id hash");
+ subgraphs = BLI_gset_ptr_new("Depsgraph subgraphs");
+ entry_tags = BLI_gset_ptr_new("Depsgraph entry_tags");
}
Depsgraph::~Depsgraph()
@@ -73,6 +84,9 @@ Depsgraph::~Depsgraph()
/* Free root node - it won't have been freed yet... */
clear_id_nodes();
clear_subgraph_nodes();
+ BLI_ghash_free(id_hash, NULL, NULL);
+ BLI_gset_free(subgraphs, NULL);
+ BLI_gset_free(entry_tags, NULL);
if (this->root_node != NULL) {
OBJECT_GUARDED_DELETE(this->root_node, RootDepsNode);
}
@@ -235,10 +249,16 @@ DepsNode *Depsgraph::find_node_from_pointer(const PointerRNA *ptr,
/* Node Management ---------------------------- */
+static void id_node_deleter(void *value)
+{
+ IDDepsNode *id_node = reinterpret_cast<IDDepsNode *>(value);
+ OBJECT_GUARDED_DELETE(id_node, IDDepsNode);
+}
+
RootDepsNode *Depsgraph::add_root_node()
{
if (!root_node) {
- DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_ROOT);
+ DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_ROOT);
root_node = (RootDepsNode *)factory->create_node(NULL, "", "Root (Scene)");
}
return root_node;
@@ -267,12 +287,12 @@ TimeSourceDepsNode *Depsgraph::find_time_source(const ID *id) const
SubgraphDepsNode *Depsgraph::add_subgraph_node(const ID *id)
{
- DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_SUBGRAPH);
+ DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_SUBGRAPH);
SubgraphDepsNode *subgraph_node =
(SubgraphDepsNode *)factory->create_node(id, "", id->name + 2);
/* Add to subnodes list. */
- this->subgraphs.insert(subgraph_node);
+ BLI_gset_insert(subgraphs, subgraph_node);
/* if there's an ID associated, add to ID-nodes lookup too */
if (id) {
@@ -289,37 +309,34 @@ SubgraphDepsNode *Depsgraph::add_subgraph_node(const ID *id)
void Depsgraph::remove_subgraph_node(SubgraphDepsNode *subgraph_node)
{
- subgraphs.erase(subgraph_node);
+ BLI_gset_remove(subgraphs, subgraph_node, NULL);
OBJECT_GUARDED_DELETE(subgraph_node, SubgraphDepsNode);
}
void Depsgraph::clear_subgraph_nodes()
{
- for (Subgraphs::iterator it = subgraphs.begin();
- it != subgraphs.end();
- ++it)
+ GSET_FOREACH_BEGIN(SubgraphDepsNode *, subgraph_node, subgraphs)
{
- SubgraphDepsNode *subgraph_node = *it;
OBJECT_GUARDED_DELETE(subgraph_node, SubgraphDepsNode);
}
- subgraphs.clear();
+ GSET_FOREACH_END();
+ BLI_gset_clear(subgraphs, NULL);
}
IDDepsNode *Depsgraph::find_id_node(const ID *id) const
{
- IDNodeMap::const_iterator it = this->id_hash.find(id);
- return it != this->id_hash.end() ? it->second : NULL;
+ return reinterpret_cast<IDDepsNode *>(BLI_ghash_lookup(id_hash, id));
}
IDDepsNode *Depsgraph::add_id_node(ID *id, const string &name)
{
IDDepsNode *id_node = find_id_node(id);
if (!id_node) {
- DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_ID_REF);
+ DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_ID_REF);
id_node = (IDDepsNode *)factory->create_node(id, "", name);
id->tag |= LIB_TAG_DOIT;
/* register */
- this->id_hash[id] = id_node;
+ BLI_ghash_insert(id_hash, id, id_node);
}
return id_node;
}
@@ -329,21 +346,14 @@ void Depsgraph::remove_id_node(const ID *id)
IDDepsNode *id_node = find_id_node(id);
if (id_node) {
/* unregister */
- this->id_hash.erase(id);
+ BLI_ghash_remove(id_hash, id, NULL, NULL);
OBJECT_GUARDED_DELETE(id_node, IDDepsNode);
}
}
void Depsgraph::clear_id_nodes()
{
- for (IDNodeMap::const_iterator it = id_hash.begin();
- it != id_hash.end();
- ++it)
- {
- IDDepsNode *id_node = it->second;
- OBJECT_GUARDED_DELETE(id_node, IDDepsNode);
- }
- id_hash.clear();
+ BLI_ghash_clear(id_hash, NULL, id_node_deleter);
}
/* Add new relationship between two nodes. */
@@ -449,33 +459,52 @@ void Depsgraph::add_entry_tag(OperationDepsNode *node)
/* Add to graph-level set of directly modified nodes to start searching from.
* NOTE: this is necessary since we have several thousand nodes to play with...
*/
- this->entry_tags.insert(node);
+ BLI_gset_insert(entry_tags, node);
}
void Depsgraph::clear_all_nodes()
{
clear_id_nodes();
clear_subgraph_nodes();
- id_hash.clear();
+ BLI_ghash_clear(id_hash, NULL, NULL);
if (this->root_node) {
OBJECT_GUARDED_DELETE(this->root_node, RootDepsNode);
root_node = NULL;
}
}
+void deg_editors_id_update(Main *bmain, ID *id)
+{
+ if (deg_editor_update_id_cb != NULL) {
+ deg_editor_update_id_cb(bmain, id);
+ }
+}
+
+void deg_editors_scene_update(Main *bmain, Scene *scene, bool updated)
+{
+ if (deg_editor_update_scene_cb != NULL) {
+ deg_editor_update_scene_cb(bmain, scene, updated);
+ }
+}
+
+} // namespace DEG
+
/* **************** */
/* Public Graph API */
/* Initialize a new Depsgraph */
Depsgraph *DEG_graph_new()
{
- return OBJECT_GUARDED_NEW(Depsgraph);
+ DEG::Depsgraph *deg_depsgraph = OBJECT_GUARDED_NEW(DEG::Depsgraph);
+ return reinterpret_cast<Depsgraph *>(deg_depsgraph);
}
/* Free graph's contents and graph itself */
void DEG_graph_free(Depsgraph *graph)
{
- OBJECT_GUARDED_DELETE(graph, Depsgraph);
+ using DEG::Depsgraph;
+ DEG::Depsgraph *deg_depsgraph = reinterpret_cast<DEG::Depsgraph *>(graph);
+ OBJECT_GUARDED_DELETE(deg_depsgraph, Depsgraph);
}
/* Set callbacks which are being called when depsgraph changes. */
@@ -483,28 +512,14 @@ void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func,
DEG_EditorUpdateSceneCb scene_func,
DEG_EditorUpdateScenePreCb scene_pre_func)
{
- deg_editor_update_id_cb = id_func;
- deg_editor_update_scene_cb = scene_func;
- deg_editor_update_scene_pre_cb = scene_pre_func;
+ DEG::deg_editor_update_id_cb = id_func;
+ DEG::deg_editor_update_scene_cb = scene_func;
+ DEG::deg_editor_update_scene_pre_cb = scene_pre_func;
}
void DEG_editors_update_pre(Main *bmain, Scene *scene, bool time)
{
- if (deg_editor_update_scene_pre_cb != NULL) {
- deg_editor_update_scene_pre_cb(bmain, scene, time);
- }
-}
-
-void deg_editors_id_update(Main *bmain, ID *id)
-{
- if (deg_editor_update_id_cb != NULL) {
- deg_editor_update_id_cb(bmain, id);
- }
-}
-
-void deg_editors_scene_update(Main *bmain, Scene *scene, bool updated)
-{
- if (deg_editor_update_scene_cb != NULL) {
- deg_editor_update_scene_cb(bmain, scene, updated);
+ if (DEG::deg_editor_update_scene_pre_cb != NULL) {
+ DEG::deg_editor_update_scene_pre_cb(bmain, scene, time);
}
}
diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h
index 9533fbd10d5..08b264f8497 100644
--- a/source/blender/depsgraph/intern/depsgraph.h
+++ b/source/blender/depsgraph/intern/depsgraph.h
@@ -34,19 +34,20 @@
* in the graph.
*/
-#ifndef __DEPSGRAPH_H__
-#define __DEPSGRAPH_H__
+#pragma once
#include "BLI_threads.h" /* for SpinLock */
-#include "depsgraph_types.h"
-
-#include "depsgraph_util_map.h"
-#include "depsgraph_util_set.h"
+#include "intern/depsgraph_types.h"
+struct ID;
+struct GHash;
+struct GSet;
struct PointerRNA;
struct PropertyRNA;
+namespace DEG {
+
struct DepsNode;
struct RootDepsNode;
struct TimeSourceDepsNode;
@@ -94,9 +95,6 @@ struct DepsRelation {
/* Dependency Graph object */
struct Depsgraph {
- typedef unordered_map<const ID *, IDDepsNode *> IDNodeMap;
- typedef unordered_set<SubgraphDepsNode *> Subgraphs;
- typedef unordered_set<OperationDepsNode *> EntryTags;
typedef vector<OperationDepsNode *> OperationNodes;
Depsgraph();
@@ -163,13 +161,13 @@ struct Depsgraph {
/* <ID : IDDepsNode> mapping from ID blocks to nodes representing these blocks
* (for quick lookups). */
- IDNodeMap id_hash;
+ GHash *id_hash;
/* "root" node - the one where all evaluation enters from. */
RootDepsNode *root_node;
/* Subgraphs referenced in tree. */
- Subgraphs subgraphs;
+ GSet *subgraphs;
/* Indicates whether relations needs to be updated. */
bool need_update;
@@ -177,7 +175,7 @@ struct Depsgraph {
/* Quick-Access Temp Data ............. */
/* Nodes which have been tagged as "directly modified". */
- EntryTags entry_tags;
+ GSet *entry_tags;
/* Convenience Data ................... */
@@ -193,32 +191,9 @@ struct Depsgraph {
/* Layers Visibility .................. */
/* Visible layers bitfield, used for skipping invisible objects updates. */
- int layers;
+ unsigned int layers;
// XXX: additional stuff like eval contexts, mempools for allocating nodes from, etc.
};
-/**
- * Helper macros for iterating over set of relationship links
- * incident on each node.
- *
- * \note it is safe to perform removal operations here...
- *
- * relations_set[in]: (DepsNode::Relations) set of relationships (in/out links)
- * relation[out]: (DepsRelation *) identifier where DepsRelation that we're
- * currently accessing comes up
- */
-#define DEPSNODE_RELATIONS_ITER_BEGIN(relations_set_, relation_) \
- { \
- OperationDepsNode::Relations::const_iterator __rel_iter = relations_set_.begin(); \
- while (__rel_iter != relations_set_.end()) { \
- DepsRelation *relation_ = *__rel_iter; \
- ++__rel_iter; \
-
- /* ... code for iterator body can be written here ... */
-
-#define DEPSNODE_RELATIONS_ITER_END \
- } \
- } ((void)0)
-
-#endif /* __DEPSGRAPH_H__ */
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
index 877ce6e52e9..7a3b19e82c6 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -30,137 +30,148 @@
* Methods for constructing depsgraph.
*/
-#include <stack>
-
#include "MEM_guardedalloc.h"
extern "C" {
-#include "BLI_blenlib.h"
-#include "BLI_string.h"
-#include "BLI_utildefines.h"
-
-#include "DNA_action_types.h"
-#include "DNA_anim_types.h"
-#include "DNA_armature_types.h"
-#include "DNA_camera_types.h"
-#include "DNA_constraint_types.h"
-#include "DNA_curve_types.h"
-#include "DNA_effect_types.h"
-#include "DNA_group_types.h"
-#include "DNA_key_types.h"
-#include "DNA_lamp_types.h"
-#include "DNA_material_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meta_types.h"
-#include "DNA_node_types.h"
-#include "DNA_particle_types.h"
+#include "DNA_cachefile_types.h"
#include "DNA_object_types.h"
-#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
-#include "DNA_texture_types.h"
-#include "DNA_world_types.h"
-
-#include "BKE_action.h"
-#include "BKE_armature.h"
-#include "BKE_animsys.h"
-#include "BKE_constraint.h"
-#include "BKE_curve.h"
-#include "BKE_effect.h"
-#include "BKE_fcurve.h"
-#include "BKE_group.h"
-#include "BKE_key.h"
-#include "BKE_library.h"
+#include "DNA_object_force.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+
#include "BKE_main.h"
-#include "BKE_material.h"
-#include "BKE_mball.h"
+#include "BKE_collision.h"
+#include "BKE_effect.h"
#include "BKE_modifier.h"
-#include "BKE_node.h"
-#include "BKE_object.h"
-#include "BKE_particle.h"
-#include "BKE_rigidbody.h"
-#include "BKE_sound.h"
-#include "BKE_texture.h"
-#include "BKE_tracking.h"
-#include "BKE_world.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_debug.h"
#include "DEG_depsgraph_build.h"
-#include "RNA_access.h"
-#include "RNA_types.h"
} /* extern "C" */
-#include "depsnode.h"
-#include "depsnode_component.h"
-#include "depsgraph_debug.h"
-#include "depsnode_operation.h"
-#include "depsgraph_types.h"
-#include "depsgraph_build.h"
-#include "depsgraph_intern.h"
+#include "builder/deg_builder.h"
+#include "builder/deg_builder_cycle.h"
+#include "builder/deg_builder_nodes.h"
+#include "builder/deg_builder_relations.h"
+#include "builder/deg_builder_transitive.h"
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
-#include "depsgraph_util_cycle.h"
-#include "depsgraph_util_transitive.h"
+#include "intern/depsgraph_types.h"
+#include "intern/depsgraph_intern.h"
+
+#include "util/deg_util_foreach.h"
/* ****************** */
/* External Build API */
-static eDepsNode_Type deg_build_scene_component_type(eDepsSceneComponentType component)
+static DEG::eDepsNode_Type deg_build_scene_component_type(
+ eDepsSceneComponentType component)
{
switch (component) {
- case DEG_SCENE_COMP_PARAMETERS: return DEPSNODE_TYPE_PARAMETERS;
- case DEG_SCENE_COMP_ANIMATION: return DEPSNODE_TYPE_ANIMATION;
- case DEG_SCENE_COMP_SEQUENCER: return DEPSNODE_TYPE_SEQUENCER;
+ case DEG_SCENE_COMP_PARAMETERS: return DEG::DEPSNODE_TYPE_PARAMETERS;
+ case DEG_SCENE_COMP_ANIMATION: return DEG::DEPSNODE_TYPE_ANIMATION;
+ case DEG_SCENE_COMP_SEQUENCER: return DEG::DEPSNODE_TYPE_SEQUENCER;
}
- return DEPSNODE_TYPE_UNDEFINED;
+ return DEG::DEPSNODE_TYPE_UNDEFINED;
}
-static eDepsNode_Type deg_build_object_component_type(eDepsObjectComponentType component)
+static DEG::eDepsNode_Type deg_build_object_component_type(
+ eDepsObjectComponentType component)
{
switch (component) {
- case DEG_OB_COMP_PARAMETERS: return DEPSNODE_TYPE_PARAMETERS;
- case DEG_OB_COMP_PROXY: return DEPSNODE_TYPE_PROXY;
- case DEG_OB_COMP_ANIMATION: return DEPSNODE_TYPE_ANIMATION;
- case DEG_OB_COMP_TRANSFORM: return DEPSNODE_TYPE_TRANSFORM;
- case DEG_OB_COMP_GEOMETRY: return DEPSNODE_TYPE_GEOMETRY;
- case DEG_OB_COMP_EVAL_POSE: return DEPSNODE_TYPE_EVAL_POSE;
- case DEG_OB_COMP_BONE: return DEPSNODE_TYPE_BONE;
- case DEG_OB_COMP_EVAL_PARTICLES: return DEPSNODE_TYPE_EVAL_PARTICLES;
- case DEG_OB_COMP_SHADING: return DEPSNODE_TYPE_SHADING;
+ case DEG_OB_COMP_PARAMETERS: return DEG::DEPSNODE_TYPE_PARAMETERS;
+ case DEG_OB_COMP_PROXY: return DEG::DEPSNODE_TYPE_PROXY;
+ case DEG_OB_COMP_ANIMATION: return DEG::DEPSNODE_TYPE_ANIMATION;
+ case DEG_OB_COMP_TRANSFORM: return DEG::DEPSNODE_TYPE_TRANSFORM;
+ case DEG_OB_COMP_GEOMETRY: return DEG::DEPSNODE_TYPE_GEOMETRY;
+ case DEG_OB_COMP_EVAL_POSE: return DEG::DEPSNODE_TYPE_EVAL_POSE;
+ case DEG_OB_COMP_BONE: return DEG::DEPSNODE_TYPE_BONE;
+ case DEG_OB_COMP_EVAL_PARTICLES: return DEG::DEPSNODE_TYPE_EVAL_PARTICLES;
+ case DEG_OB_COMP_SHADING: return DEG::DEPSNODE_TYPE_SHADING;
+ case DEG_OB_COMP_CACHE: return DEG::DEPSNODE_TYPE_CACHE;
}
- return DEPSNODE_TYPE_UNDEFINED;
+ return DEG::DEPSNODE_TYPE_UNDEFINED;
}
-void DEG_add_scene_relation(DepsNodeHandle *handle, struct Scene *scene, eDepsSceneComponentType component, const char *description)
+static DEG::DepsNodeHandle *get_handle(DepsNodeHandle *handle)
{
- eDepsNode_Type type = deg_build_scene_component_type(component);
- ComponentKey comp_key(&scene->id, type);
- handle->builder->add_node_handle_relation(comp_key, handle, DEPSREL_TYPE_GEOMETRY_EVAL, description);
+ return reinterpret_cast<DEG::DepsNodeHandle *>(handle);
}
-void DEG_add_object_relation(DepsNodeHandle *handle, struct Object *ob, eDepsObjectComponentType component, const char *description)
+void DEG_add_scene_relation(DepsNodeHandle *handle,
+ Scene *scene,
+ eDepsSceneComponentType component,
+ const char *description)
{
- eDepsNode_Type type = deg_build_object_component_type(component);
- ComponentKey comp_key(&ob->id, type);
- handle->builder->add_node_handle_relation(comp_key, handle, DEPSREL_TYPE_GEOMETRY_EVAL, description);
+ DEG::eDepsNode_Type type = deg_build_scene_component_type(component);
+ DEG::ComponentKey comp_key(&scene->id, type);
+ DEG::DepsNodeHandle *deg_handle = get_handle(handle);
+ deg_handle->builder->add_node_handle_relation(comp_key,
+ deg_handle,
+ DEG::DEPSREL_TYPE_GEOMETRY_EVAL,
+ description);
}
-void DEG_add_bone_relation(DepsNodeHandle *handle, struct Object *ob, const char *bone_name, eDepsObjectComponentType component, const char *description)
+void DEG_add_object_relation(DepsNodeHandle *handle,
+ Object *ob,
+ eDepsObjectComponentType component,
+ const char *description)
{
- eDepsNode_Type type = deg_build_object_component_type(component);
- ComponentKey comp_key(&ob->id, type, bone_name);
+ DEG::eDepsNode_Type type = deg_build_object_component_type(component);
+ DEG::ComponentKey comp_key(&ob->id, type);
+ DEG::DepsNodeHandle *deg_handle = get_handle(handle);
+ deg_handle->builder->add_node_handle_relation(comp_key,
+ deg_handle,
+ DEG::DEPSREL_TYPE_GEOMETRY_EVAL,
+ description);
+}
- // XXX: "Geometry Eval" might not always be true, but this only gets called from modifier building now
- handle->builder->add_node_handle_relation(comp_key, handle, DEPSREL_TYPE_GEOMETRY_EVAL, description);
+void DEG_add_object_cache_relation(DepsNodeHandle *handle,
+ CacheFile *cache_file,
+ eDepsObjectComponentType component,
+ const char *description)
+{
+ DEG::eDepsNode_Type type = deg_build_object_component_type(component);
+ DEG::ComponentKey comp_key(&cache_file->id, type);
+ DEG::DepsNodeHandle *deg_handle = get_handle(handle);
+ deg_handle->builder->add_node_handle_relation(comp_key,
+ deg_handle,
+ DEG::DEPSREL_TYPE_CACHE,
+ description);
+}
+
+void DEG_add_bone_relation(DepsNodeHandle *handle,
+ Object *ob,
+ const char *bone_name,
+ eDepsObjectComponentType component,
+ const char *description)
+{
+ DEG::eDepsNode_Type type = deg_build_object_component_type(component);
+ DEG::ComponentKey comp_key(&ob->id, type, bone_name);
+ DEG::DepsNodeHandle *deg_handle = get_handle(handle);
+ /* XXX: "Geometry Eval" might not always be true, but this only gets called
+ * from modifier building now.
+ */
+ deg_handle->builder->add_node_handle_relation(comp_key,
+ deg_handle,
+ DEG::DEPSREL_TYPE_GEOMETRY_EVAL,
+ description);
}
void DEG_add_special_eval_flag(Depsgraph *graph, ID *id, short flag)
{
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
if (graph == NULL) {
BLI_assert(!"Graph should always be valid");
return;
}
- IDDepsNode *id_node = graph->find_id_node(id);
+ DEG::IDDepsNode *id_node = deg_graph->find_id_node(id);
if (id_node == NULL) {
BLI_assert(!"ID should always be valid");
return;
@@ -168,110 +179,21 @@ void DEG_add_special_eval_flag(Depsgraph *graph, ID *id, short flag)
id_node->eval_flags |= flag;
}
-/* ********************** */
-/* Utilities for Builders */
-
-/* Get unique identifier for FCurves and Drivers */
-string deg_fcurve_id_name(const FCurve *fcu)
-{
- char index_buf[32];
- sprintf(index_buf, "[%d]", fcu->array_index);
-
- return string(fcu->rna_path) + index_buf;
-}
-
-static void deg_graph_build_finalize(Depsgraph *graph)
-{
- std::stack<OperationDepsNode *> stack;
-
- for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
- it_op != graph->operations.end();
- ++it_op)
- {
- OperationDepsNode *node = *it_op;
- node->done = 0;
- node->num_links_pending = 0;
- for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin();
- it_rel != node->inlinks.end();
- ++it_rel)
- {
- DepsRelation *rel = *it_rel;
- if ((rel->from->type == DEPSNODE_TYPE_OPERATION) &&
- (rel->flag & DEPSREL_FLAG_CYCLIC) == 0)
- {
- ++node->num_links_pending;
- }
- }
- if (node->num_links_pending == 0) {
- stack.push(node);
- }
- IDDepsNode *id_node = node->owner->owner;
- id_node->id->tag |= LIB_TAG_DOIT;
- }
-
- while (!stack.empty()) {
- OperationDepsNode *node = stack.top();
- if (node->done == 0 && node->outlinks.size() != 0) {
- for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
- it_rel != node->outlinks.end();
- ++it_rel)
- {
- DepsRelation *rel = *it_rel;
- if (rel->to->type == DEPSNODE_TYPE_OPERATION) {
- OperationDepsNode *to = (OperationDepsNode *)rel->to;
- if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
- BLI_assert(to->num_links_pending > 0);
- --to->num_links_pending;
- }
- if (to->num_links_pending == 0) {
- stack.push(to);
- }
- }
- }
- node->done = 1;
- }
- else {
- stack.pop();
- IDDepsNode *id_node = node->owner->owner;
- for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
- it_rel != node->outlinks.end();
- ++it_rel)
- {
- DepsRelation *rel = *it_rel;
- if (rel->to->type == DEPSNODE_TYPE_OPERATION) {
- OperationDepsNode *to = (OperationDepsNode *)rel->to;
- IDDepsNode *id_to = to->owner->owner;
- id_node->layers |= id_to->layers;
- }
- }
- }
- }
-
- /* Re-tag IDs for update if it was tagged before the relations update tag. */
- for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
- it != graph->id_hash.end();
- ++it)
- {
- IDDepsNode *id_node = it->second;
- ID *id = id_node->id;
- if (id->tag & LIB_TAG_ID_RECALC_ALL &&
- id->tag & LIB_TAG_DOIT)
- {
- id_node->tag_update(graph);
- id->tag &= ~LIB_TAG_DOIT;
- }
- }
-}
-
/* ******************** */
/* Graph Building API's */
-/* Build depsgraph for the given scene, and dump results in given graph container */
-// XXX: assume that this is called from outside, given the current scene as the "main" scene
+/* Build depsgraph for the given scene, and dump results in given
+ * graph container.
+ */
+/* XXX: assume that this is called from outside, given the current scene as
+ * the "main" scene.
+ */
void DEG_graph_build_from_scene(Depsgraph *graph, Main *bmain, Scene *scene)
{
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+
/* 1) Generate all the nodes in the graph first */
- DepsgraphNodeBuilder node_builder(bmain, graph);
+ DEG::DepsgraphNodeBuilder node_builder(bmain, deg_graph);
/* create root node for scene first
* - this way it should be the first in the graph,
* reflecting its role as the entrypoint
@@ -279,29 +201,40 @@ void DEG_graph_build_from_scene(Depsgraph *graph, Main *bmain, Scene *scene)
node_builder.add_root_node();
node_builder.build_scene(bmain, scene);
- /* 2) Hook up relationships between operations - to determine evaluation order */
- DepsgraphRelationBuilder relation_builder(graph);
- /* hook scene up to the root node as entrypoint to graph */
+ /* 2) Hook up relationships between operations - to determine evaluation
+ * order.
+ */
+ DEG::DepsgraphRelationBuilder relation_builder(deg_graph);
+ /* Hook scene up to the root node as entrypoint to graph. */
/* XXX what does this relation actually mean?
- * it doesnt add any operations anyway and is not clear what part of the scene is to be connected.
+ * it doesnt add any operations anyway and is not clear what part of the
+ * scene is to be connected.
*/
- //relation_builder.add_relation(RootKey(), IDKey(scene), DEPSREL_TYPE_ROOT_TO_ACTIVE, "Root to Active Scene");
+#if 0
+ relation_builder.add_relation(RootKey(),
+ IDKey(scene),
+ DEPSREL_TYPE_ROOT_TO_ACTIVE,
+ "Root to Active Scene");
+#endif
relation_builder.build_scene(bmain, scene);
/* Detect and solve cycles. */
- deg_graph_detect_cycles(graph);
+ DEG::deg_graph_detect_cycles(deg_graph);
- /* 3) Simplify the graph by removing redundant relations (to optimise traversal later) */
- // TODO: it would be useful to have an option to disable this in cases where it is causing trouble
+ /* 3) Simplify the graph by removing redundant relations (to optimize
+ * traversal later). */
+ /* TODO: it would be useful to have an option to disable this in cases where
+ * it is causing trouble.
+ */
if (G.debug_value == 799) {
- deg_graph_transitive_reduction(graph);
+ DEG::deg_graph_transitive_reduction(deg_graph);
}
/* 4) Flush visibility layer and re-schedule nodes for update. */
- deg_graph_build_finalize(graph);
+ DEG::deg_graph_build_finalize(deg_graph);
#if 0
- if (!DEG_debug_consistency_check(graph)) {
+ if (!DEG_debug_consistency_check(deg_graph)) {
printf("Consistency validation failed, ABORTING!\n");
abort();
}
@@ -311,7 +244,8 @@ void DEG_graph_build_from_scene(Depsgraph *graph, Main *bmain, Scene *scene)
/* Tag graph relations for update. */
void DEG_graph_tag_relations_update(Depsgraph *graph)
{
- graph->need_update = true;
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+ deg_graph->need_update = true;
}
/* Tag all relations for update. */
@@ -339,7 +273,7 @@ void DEG_scene_relations_update(Main *bmain, Scene *scene)
return;
}
- Depsgraph *graph = scene->depsgraph;
+ DEG::Depsgraph *graph = reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph);
if (!graph->need_update) {
/* Graph is up to date, nothing to do. */
return;
@@ -348,10 +282,12 @@ void DEG_scene_relations_update(Main *bmain, Scene *scene)
/* Clear all previous nodes and operations. */
graph->clear_all_nodes();
graph->operations.clear();
- graph->entry_tags.clear();
+ BLI_gset_clear(graph->entry_tags, NULL);
/* Build new nodes and relations. */
- DEG_graph_build_from_scene(graph, bmain, scene);
+ DEG_graph_build_from_scene(reinterpret_cast< ::Depsgraph * >(graph),
+ bmain,
+ scene);
graph->need_update = false;
}
@@ -372,3 +308,52 @@ void DEG_scene_graph_free(Scene *scene)
scene->depsgraph = NULL;
}
}
+
+void DEG_add_collision_relations(DepsNodeHandle *handle, Scene *scene, Object *ob, Group *group, int layer, unsigned int modifier_type, DEG_CollobjFilterFunction fn, bool dupli, const char *name)
+{
+ unsigned int numcollobj;
+ Object **collobjs = get_collisionobjects_ext(scene, ob, group, layer, &numcollobj, modifier_type, dupli);
+
+ for (unsigned int i = 0; i < numcollobj; i++) {
+ Object *ob1 = collobjs[i];
+
+ if (!fn || fn(ob1, modifiers_findByType(ob1, (ModifierType)modifier_type))) {
+ DEG_add_object_relation(handle, ob1, DEG_OB_COMP_TRANSFORM, name);
+ DEG_add_object_relation(handle, ob1, DEG_OB_COMP_GEOMETRY, name);
+ }
+ }
+
+ if (collobjs)
+ MEM_freeN(collobjs);
+}
+
+void DEG_add_forcefield_relations(DepsNodeHandle *handle, Scene *scene, Object *ob, EffectorWeights *effector_weights, bool add_absorption, int skip_forcefield, const char *name)
+{
+ ListBase *effectors = pdInitEffectors(scene, ob, NULL, effector_weights, false);
+
+ if (effectors) {
+ for (EffectorCache *eff = (EffectorCache*)effectors->first; eff; eff = eff->next) {
+ if (eff->ob != ob && eff->pd->forcefield != skip_forcefield) {
+ DEG_add_object_relation(handle, eff->ob, DEG_OB_COMP_TRANSFORM, name);
+
+ if (eff->psys) {
+ DEG_add_object_relation(handle, eff->ob, DEG_OB_COMP_EVAL_PARTICLES, name);
+
+ /* TODO: remove this when/if EVAL_PARTICLES is sufficient for up to date particles */
+ DEG_add_object_relation(handle, eff->ob, DEG_OB_COMP_GEOMETRY, name);
+ }
+
+ if (eff->pd->forcefield == PFIELD_SMOKEFLOW && eff->pd->f_source) {
+ DEG_add_object_relation(handle, eff->pd->f_source, DEG_OB_COMP_TRANSFORM, "Smoke Force Domain");
+ DEG_add_object_relation(handle, eff->pd->f_source, DEG_OB_COMP_GEOMETRY, "Smoke Force Domain");
+ }
+
+ if (add_absorption && (eff->pd->flag & PFIELD_VISIBILITY)) {
+ DEG_add_collision_relations(handle, scene, ob, NULL, eff->ob->lay, eModifierType_Collision, NULL, true, "Force Absorption");
+ }
+ }
+ }
+ }
+
+ pdEndEffectors(&effectors);
+}
diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc
index efb3e330857..d3b48930779 100644
--- a/source/blender/depsgraph/intern/depsgraph_debug.cc
+++ b/source/blender/depsgraph/intern/depsgraph_debug.cc
@@ -30,956 +30,39 @@
* Implementation of tools for debugging the depsgraph
*/
-//#include <stdlib.h>
-#include <string.h>
-
-extern "C" {
#include "BLI_utildefines.h"
-#include "BLI_listbase.h"
#include "BLI_ghash.h"
-#include "BLI_string.h"
+extern "C" {
#include "DNA_scene_types.h"
-#include "DNA_userdef_types.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_debug.h"
#include "DEG_depsgraph_build.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
} /* extern "C" */
-#include "depsgraph_debug.h"
-#include "depsnode.h"
-#include "depsnode_component.h"
-#include "depsnode_operation.h"
-#include "depsgraph_intern.h"
-
-/* ****************** */
-/* Graphviz Debugging */
-
-#define NL "\r\n"
-
-/* Only one should be enabled, defines whether graphviz nodes
- * get colored by individual types or classes.
- */
-#define COLOR_SCHEME_NODE_CLASS 1
-//#define COLOR_SCHEME_NODE_TYPE 2
-
-static const char *deg_debug_graphviz_fontname = "helvetica";
-static float deg_debug_graphviz_graph_label_size = 20.0f;
-static float deg_debug_graphviz_node_label_size = 14.0f;
-static const int deg_debug_max_colors = 12;
-#if 0
-static const char *deg_debug_colors_dark[] = {
- "#6e8997", "#144f77", "#76945b",
- "#216a1d", "#a76665", "#971112",
- "#a87f49", "#0a9540", "#86768e",
- "#462866", "#a9a965", "#753b1a",
-};
-#endif
-#ifdef COLOR_SCHEME_NODE_TYPE
-static const char *deg_debug_colors[] = {
- "#a6cee3", "#1f78b4", "#b2df8a",
- "#33a02c", "#fb9a99", "#e31a1c",
- "#fdbf6f", "#ff7f00", "#cab2d6",
- "#6a3d9a", "#ffff99", "#b15928",
-};
-#endif
-static const char *deg_debug_colors_light[] = {
- "#8dd3c7", "#ffffb3", "#bebada",
- "#fb8072", "#80b1d3", "#fdb462",
- "#b3de69", "#fccde5", "#d9d9d9",
- "#bc80bd", "#ccebc5", "#ffed6f",
-};
-
-#ifdef COLOR_SCHEME_NODE_TYPE
-static const int deg_debug_node_type_color_map[][2] = {
- {DEPSNODE_TYPE_ROOT, 0},
- {DEPSNODE_TYPE_TIMESOURCE, 1},
- {DEPSNODE_TYPE_ID_REF, 2},
- {DEPSNODE_TYPE_SUBGRAPH, 3},
-
- /* Outer Types */
- {DEPSNODE_TYPE_PARAMETERS, 4},
- {DEPSNODE_TYPE_PROXY, 5},
- {DEPSNODE_TYPE_ANIMATION, 6},
- {DEPSNODE_TYPE_TRANSFORM, 7},
- {DEPSNODE_TYPE_GEOMETRY, 8},
- {DEPSNODE_TYPE_SEQUENCER, 9},
- {DEPSNODE_TYPE_SHADING, 10},
- {-1, 0}
-};
-#endif
-
-#if 0 /* unused */
-static const int deg_debug_relation_type_color_map[][2] = {
- {DEPSREL_TYPE_STANDARD, 0},
- {DEPSREL_TYPE_ROOT_TO_ACTIVE, 1},
- {DEPSREL_TYPE_DATABLOCK, 2},
- {DEPSREL_TYPE_TIME, 3},
- {DEPSREL_TYPE_COMPONENT_ORDER, 4},
- {DEPSREL_TYPE_OPERATION, 5},
- {DEPSREL_TYPE_DRIVER, 6},
- {DEPSREL_TYPE_DRIVER_TARGET, 7},
- {DEPSREL_TYPE_TRANSFORM, 8},
- {DEPSREL_TYPE_GEOMETRY_EVAL, 9},
- {DEPSREL_TYPE_UPDATE, 10},
- {DEPSREL_TYPE_UPDATE_UI, 11},
- {-1, 0}
-};
-#endif
-
-static int deg_debug_node_color_index(const DepsNode *node)
-{
-#ifdef COLOR_SCHEME_NODE_CLASS
- /* Some special types. */
- switch (node->type) {
- case DEPSNODE_TYPE_ID_REF:
- return 5;
- case DEPSNODE_TYPE_OPERATION:
- {
- OperationDepsNode *op_node = (OperationDepsNode *)node;
- if (op_node->is_noop())
- return 8;
- break;
- }
-
- default:
- break;
- }
- /* Do others based on class. */
- switch (node->tclass) {
- case DEPSNODE_CLASS_OPERATION:
- return 4;
- case DEPSNODE_CLASS_COMPONENT:
- return 1;
- default:
- return 9;
- }
-#endif
-
-#ifdef COLOR_SCHEME_NODE_TYPE
- const int (*pair)[2];
- for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) {
- if ((*pair)[0] == node->type) {
- return (*pair)[1];
- }
- }
- return -1;
-#endif
-}
-
-struct DebugContext {
- FILE *file;
- bool show_tags;
- bool show_eval_priority;
-};
-
-static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...) ATTR_PRINTF_FORMAT(2, 3);
-static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...)
-{
- va_list args;
- va_start(args, fmt);
- vfprintf(ctx.file, fmt, args);
- va_end(args);
-}
-
-static void deg_debug_graphviz_legend_color(const DebugContext &ctx,
- const char *name,
- const char *color)
-{
- deg_debug_fprintf(ctx, "<TR>");
- deg_debug_fprintf(ctx, "<TD>%s</TD>", name);
- deg_debug_fprintf(ctx, "<TD BGCOLOR=\"%s\"></TD>", color);
- deg_debug_fprintf(ctx, "</TR>" NL);
-}
-
-#if 0
-static void deg_debug_graphviz_legend_line(const DebugContext &ctx,
- const char *name,
- const char *color,
- const char *style)
-{
- /* XXX TODO */
- deg_debug_fprintf(ctx, "" NL);
-}
-
-static void deg_debug_graphviz_legend_cluster(const DebugContext &ctx,
- const char *name,
- const char *color,
- const char *style)
-{
- deg_debug_fprintf(ctx, "<TR>");
- deg_debug_fprintf(ctx, "<TD>%s</TD>", name);
- deg_debug_fprintf(ctx, "<TD CELLPADDING=\"4\"><TABLE BORDER=\"1\" CELLBORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\">");
- deg_debug_fprintf(ctx, "<TR><TD BGCOLOR=\"%s\"></TD></TR>", color);
- deg_debug_fprintf(ctx, "</TABLE></TD>");
- deg_debug_fprintf(ctx, "</TR>" NL);
-}
-#endif
-
-static void deg_debug_graphviz_legend(const DebugContext &ctx)
-{
- deg_debug_fprintf(ctx, "{" NL);
- deg_debug_fprintf(ctx, "rank = sink;" NL);
- deg_debug_fprintf(ctx, "Legend [shape=none, margin=0, label=<" NL);
- deg_debug_fprintf(ctx, " <TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\" CELLPADDING=\"4\">" NL);
- deg_debug_fprintf(ctx, "<TR><TD COLSPAN=\"2\"><B>Legend</B></TD></TR>" NL);
-
-#ifdef COLOR_SCHEME_NODE_CLASS
- const char **colors = deg_debug_colors_light;
- deg_debug_graphviz_legend_color(ctx, "Operation", colors[4]);
- deg_debug_graphviz_legend_color(ctx, "Component", colors[1]);
- deg_debug_graphviz_legend_color(ctx, "ID Node", colors[5]);
- deg_debug_graphviz_legend_color(ctx, "NOOP", colors[8]);
-#endif
-
-#ifdef COLOR_SCHEME_NODE_TYPE
- const int (*pair)[2];
- for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) {
- DepsNodeFactory *nti = DEG_get_node_factory((eDepsNode_Type)(*pair)[0]);
- deg_debug_graphviz_legend_color(ctx,
- nti->tname().c_str(),
- deg_debug_colors_light[(*pair)[1] % deg_debug_max_colors]);
- }
-#endif
-
- deg_debug_fprintf(ctx, "</TABLE>" NL);
- deg_debug_fprintf(ctx, ">" NL);
- deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname);
- deg_debug_fprintf(ctx, "];" NL);
- deg_debug_fprintf(ctx, "}" NL);
-}
-
-#if 0 /* unused */
-static int deg_debug_relation_type_color_index(eDepsRelation_Type type)
-{
- const int (*pair)[2];
- for (pair = deg_debug_relation_type_color_map; (*pair)[0] >= 0; ++pair) {
- if ((*pair)[0] == type) {
- return (*pair)[1];
- }
- }
- return -1;
-}
-#endif
-
-static void deg_debug_graphviz_node_color(const DebugContext &ctx,
- const DepsNode *node)
-{
- const char *color_default = "black";
- const char *color_modified = "orangered4";
- const char *color_update = "dodgerblue3";
- const char *color = color_default;
- if (ctx.show_tags) {
- if (node->tclass == DEPSNODE_CLASS_OPERATION) {
- OperationDepsNode *op_node = (OperationDepsNode *)node;
- if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) {
- color = color_modified;
- }
- else if (op_node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
- color = color_update;
- }
- }
- }
- deg_debug_fprintf(ctx, "\"%s\"", color);
-}
-
-static void deg_debug_graphviz_node_penwidth(const DebugContext &ctx,
- const DepsNode *node)
-{
- float penwidth_default = 1.0f;
- float penwidth_modified = 4.0f;
- float penwidth_update = 4.0f;
- float penwidth = penwidth_default;
- if (ctx.show_tags) {
- if (node->tclass == DEPSNODE_CLASS_OPERATION) {
- OperationDepsNode *op_node = (OperationDepsNode *)node;
- if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) {
- penwidth = penwidth_modified;
- }
- else if (op_node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
- penwidth = penwidth_update;
- }
- }
- }
- deg_debug_fprintf(ctx, "\"%f\"", penwidth);
-}
-
-static void deg_debug_graphviz_node_fillcolor(const DebugContext &ctx,
- const DepsNode *node)
-{
- const char *defaultcolor = "gainsboro";
- int color_index = deg_debug_node_color_index(node);
- const char *fillcolor = color_index < 0 ? defaultcolor : deg_debug_colors_light[color_index % deg_debug_max_colors];
- deg_debug_fprintf(ctx, "\"%s\"", fillcolor);
-}
-
-#if 0 /* implementation using stripes, a bit too noisy ... */
-static void deg_debug_graphviz_node_fillcolor(const DebugContext &ctx,
- const DepsNode *node)
-{
- const char *defaultcolor = "gainsboro";
- const char *color_needs_update = "orange";
- const int num_stripes = 10;
- int color_index = deg_debug_node_color_index(node);
- const char *base_color = color_index < 0 ? defaultcolor : deg_debug_colors_light[color_index % deg_debug_max_colors];
- if (ctx.show_tags &&
- (node->flag & (DEPSNODE_FLAG_DIRECTLY_MODIFIED | DEPSNODE_FLAG_NEEDS_UPDATE)))
- {
- deg_debug_fprintf(ctx, "\"");
- for (int i = 0; i < num_stripes; ++i) {
- if (i > 0) {
- deg_debug_fprintf(ctx, ":");
- }
- deg_debug_fprintf(ctx, "%s:%s", base_color, color_needs_update);
- }
- deg_debug_fprintf(ctx, "\"");
- }
- else {
- deg_debug_fprintf(ctx, "\"%s\"", base_color);
- }
-}
-#endif
-
-static void deg_debug_graphviz_relation_color(const DebugContext &ctx,
- const DepsRelation *rel)
-{
- const char *color_default = "black";
- const char *color_error = "red4";
- const char *color = color_default;
-#if 0 /* disabled for now, edge colors are hardly distinguishable */
- int color = deg_debug_relation_type_color_index(rel->type);
- if (color < 0) {
- deg_debug_fprintf(ctx, "%s", defaultcolor);
- }
- else {
- deg_debug_fprintf(ctx, "\"%s\"", deg_debug_colors_dark[color % deg_debug_max_colors]);
- }
-#else
- if (rel->flag & DEPSREL_FLAG_CYCLIC)
- color = color_error;
-
- deg_debug_fprintf(ctx, "%s", color);
-#endif
-}
-
-static void deg_debug_graphviz_node_style(const DebugContext &ctx, const DepsNode *node)
-{
- const char *base_style = "filled"; /* default style */
- if (ctx.show_tags) {
- if (node->tclass == DEPSNODE_CLASS_OPERATION) {
- OperationDepsNode *op_node = (OperationDepsNode *)node;
- if (op_node->flag & (DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE)) {
- base_style = "striped";
- }
- }
- }
- switch (node->tclass) {
- case DEPSNODE_CLASS_GENERIC:
- deg_debug_fprintf(ctx, "\"%s\"", base_style);
- break;
- case DEPSNODE_CLASS_COMPONENT:
- deg_debug_fprintf(ctx, "\"%s\"", base_style);
- break;
- case DEPSNODE_CLASS_OPERATION:
- deg_debug_fprintf(ctx, "\"%s,rounded\"", base_style);
- break;
- }
-}
-
-static void deg_debug_graphviz_node_single(const DebugContext &ctx,
- const DepsNode *node)
-{
- const char *shape = "box";
- string name = node->identifier();
- float priority = -1.0f;
- if (node->type == DEPSNODE_TYPE_ID_REF) {
- IDDepsNode *id_node = (IDDepsNode *)node;
- char buf[256];
- BLI_snprintf(buf, sizeof(buf), " (Layers: %d)", id_node->layers);
- name += buf;
- }
- if (ctx.show_eval_priority && node->tclass == DEPSNODE_CLASS_OPERATION) {
- priority = ((OperationDepsNode *)node)->eval_priority;
- }
- deg_debug_fprintf(ctx, "// %s\n", name.c_str());
- deg_debug_fprintf(ctx, "\"node_%p\"", node);
- deg_debug_fprintf(ctx, "[");
-// deg_debug_fprintf(ctx, "label=<<B>%s</B>>", name);
- if (priority >= 0.0f) {
- deg_debug_fprintf(ctx, "label=<%s<BR/>(<I>%.2f</I>)>",
- name.c_str(),
- priority);
- }
- else {
- deg_debug_fprintf(ctx, "label=<%s>", name.c_str());
- }
- deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname);
- deg_debug_fprintf(ctx, ",fontsize=%f", deg_debug_graphviz_node_label_size);
- deg_debug_fprintf(ctx, ",shape=%s", shape);
- deg_debug_fprintf(ctx, ",style="); deg_debug_graphviz_node_style(ctx, node);
- deg_debug_fprintf(ctx, ",color="); deg_debug_graphviz_node_color(ctx, node);
- deg_debug_fprintf(ctx, ",fillcolor="); deg_debug_graphviz_node_fillcolor(ctx, node);
- deg_debug_fprintf(ctx, ",penwidth="); deg_debug_graphviz_node_penwidth(ctx, node);
- deg_debug_fprintf(ctx, "];" NL);
- deg_debug_fprintf(ctx, NL);
-}
-
-static void deg_debug_graphviz_node_cluster_begin(const DebugContext &ctx,
- const DepsNode *node)
-{
- string name = node->identifier().c_str();
- if (node->type == DEPSNODE_TYPE_ID_REF) {
- IDDepsNode *id_node = (IDDepsNode *)node;
- char buf[256];
- BLI_snprintf(buf, sizeof(buf), " (Layers: %d)", id_node->layers);
- name += buf;
- }
- deg_debug_fprintf(ctx, "// %s\n", name.c_str());
- deg_debug_fprintf(ctx, "subgraph \"cluster_%p\" {" NL, node);
-// deg_debug_fprintf(ctx, "label=<<B>%s</B>>;" NL, name);
- deg_debug_fprintf(ctx, "label=<%s>;" NL, name.c_str());
- deg_debug_fprintf(ctx, "fontname=\"%s\";" NL, deg_debug_graphviz_fontname);
- deg_debug_fprintf(ctx, "fontsize=%f;" NL, deg_debug_graphviz_node_label_size);
- deg_debug_fprintf(ctx, "margin=\"%d\";" NL, 16);
- deg_debug_fprintf(ctx, "style="); deg_debug_graphviz_node_style(ctx, node); deg_debug_fprintf(ctx, ";" NL);
- deg_debug_fprintf(ctx, "color="); deg_debug_graphviz_node_color(ctx, node); deg_debug_fprintf(ctx, ";" NL);
- deg_debug_fprintf(ctx, "fillcolor="); deg_debug_graphviz_node_fillcolor(ctx, node); deg_debug_fprintf(ctx, ";" NL);
- deg_debug_fprintf(ctx, "penwidth="); deg_debug_graphviz_node_penwidth(ctx, node); deg_debug_fprintf(ctx, ";" NL);
- /* dummy node, so we can add edges between clusters */
- deg_debug_fprintf(ctx, "\"node_%p\"", node);
- deg_debug_fprintf(ctx, "[");
- deg_debug_fprintf(ctx, "shape=%s", "point");
- deg_debug_fprintf(ctx, ",style=%s", "invis");
- deg_debug_fprintf(ctx, "];" NL);
- deg_debug_fprintf(ctx, NL);
-}
-
-static void deg_debug_graphviz_node_cluster_end(const DebugContext &ctx)
-{
- deg_debug_fprintf(ctx, "}" NL);
- deg_debug_fprintf(ctx, NL);
-}
-
-static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx,
- const Depsgraph *graph);
-static void deg_debug_graphviz_graph_relations(const DebugContext &ctx,
- const Depsgraph *graph);
-
-static void deg_debug_graphviz_node(const DebugContext &ctx,
- const DepsNode *node)
-{
- switch (node->type) {
- case DEPSNODE_TYPE_ID_REF:
- {
- const IDDepsNode *id_node = (const IDDepsNode *)node;
- if (id_node->components.empty()) {
- deg_debug_graphviz_node_single(ctx, node);
- }
- else {
- deg_debug_graphviz_node_cluster_begin(ctx, node);
- for (IDDepsNode::ComponentMap::const_iterator it = id_node->components.begin();
- it != id_node->components.end();
- ++it)
- {
- const ComponentDepsNode *comp = it->second;
- deg_debug_graphviz_node(ctx, comp);
- }
- deg_debug_graphviz_node_cluster_end(ctx);
- }
- break;
- }
- case DEPSNODE_TYPE_SUBGRAPH:
- {
- SubgraphDepsNode *sub_node = (SubgraphDepsNode *)node;
- if (sub_node->graph) {
- deg_debug_graphviz_node_cluster_begin(ctx, node);
- deg_debug_graphviz_graph_nodes(ctx, sub_node->graph);
- deg_debug_graphviz_node_cluster_end(ctx);
- }
- else {
- deg_debug_graphviz_node_single(ctx, node);
- }
- break;
- }
- case DEPSNODE_TYPE_PARAMETERS:
- case DEPSNODE_TYPE_ANIMATION:
- case DEPSNODE_TYPE_TRANSFORM:
- case DEPSNODE_TYPE_PROXY:
- case DEPSNODE_TYPE_GEOMETRY:
- case DEPSNODE_TYPE_SEQUENCER:
- case DEPSNODE_TYPE_EVAL_POSE:
- case DEPSNODE_TYPE_BONE:
- case DEPSNODE_TYPE_SHADING:
- case DEPSNODE_TYPE_EVAL_PARTICLES:
- {
- ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
- if (!comp_node->operations.empty()) {
- deg_debug_graphviz_node_cluster_begin(ctx, node);
- for (ComponentDepsNode::OperationMap::const_iterator it = comp_node->operations.begin();
- it != comp_node->operations.end();
- ++it)
- {
- const DepsNode *op_node = it->second;
- deg_debug_graphviz_node(ctx, op_node);
- }
- deg_debug_graphviz_node_cluster_end(ctx);
- }
- else {
- deg_debug_graphviz_node_single(ctx, node);
- }
- break;
- }
- default:
- deg_debug_graphviz_node_single(ctx, node);
- break;
- }
-}
-
-static bool deg_debug_graphviz_is_cluster(const DepsNode *node)
-{
- switch (node->type) {
- case DEPSNODE_TYPE_ID_REF:
- {
- const IDDepsNode *id_node = (const IDDepsNode *)node;
- return !id_node->components.empty();
- }
- case DEPSNODE_TYPE_SUBGRAPH:
- {
- SubgraphDepsNode *sub_node = (SubgraphDepsNode *)node;
- return sub_node->graph != NULL;
- }
- case DEPSNODE_TYPE_PARAMETERS:
- case DEPSNODE_TYPE_ANIMATION:
- case DEPSNODE_TYPE_TRANSFORM:
- case DEPSNODE_TYPE_PROXY:
- case DEPSNODE_TYPE_GEOMETRY:
- case DEPSNODE_TYPE_SEQUENCER:
- case DEPSNODE_TYPE_EVAL_POSE:
- case DEPSNODE_TYPE_BONE:
- {
- ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
- return !comp_node->operations.empty();
- }
- default:
- return false;
- }
-}
-
-static bool deg_debug_graphviz_is_owner(const DepsNode *node,
- const DepsNode *other)
-{
- switch (node->tclass) {
- case DEPSNODE_CLASS_COMPONENT:
- {
- ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
- if (comp_node->owner == other)
- return true;
- break;
- }
- case DEPSNODE_CLASS_OPERATION:
- {
- OperationDepsNode *op_node = (OperationDepsNode *)node;
- if (op_node->owner == other)
- return true;
- else if (op_node->owner->owner == other)
- return true;
- break;
- }
- default: break;
- }
- return false;
-}
-
-static void deg_debug_graphviz_node_relations(const DebugContext &ctx,
- const DepsNode *node)
-{
- DEPSNODE_RELATIONS_ITER_BEGIN(node->inlinks, rel)
- {
- float penwidth = 2.0f;
-
- const DepsNode *tail = rel->to; /* same as node */
- const DepsNode *head = rel->from;
- deg_debug_fprintf(ctx, "// %s -> %s\n",
- head->identifier().c_str(),
- tail->identifier().c_str());
- deg_debug_fprintf(ctx, "\"node_%p\"", head);
- deg_debug_fprintf(ctx, " -> ");
- deg_debug_fprintf(ctx, "\"node_%p\"", tail);
-
- deg_debug_fprintf(ctx, "[");
- /* XXX labels on relations are not very helpful:
- * - they tend to appear too far away to be associated with the edge lines
- * - names are mostly redundant, reflecting simply their from/to nodes
- * - no behavior or typing of relations themselves to justify labels
- */
-#if 0
- deg_debug_fprintf(ctx, "label=\"%s\"", rel->name);
- deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname);
-#else
- /* Note: without label an id seem necessary to avoid bugs in graphviz/dot */
- deg_debug_fprintf(ctx, "id=\"%s\"", rel->name);
-#endif
- deg_debug_fprintf(ctx, ",color="); deg_debug_graphviz_relation_color(ctx, rel);
- deg_debug_fprintf(ctx, ",penwidth=\"%f\"", penwidth);
- /* NOTE: edge from node to own cluster is not possible and gives graphviz
- * warning, avoid this here by just linking directly to the invisible
- * placeholder node
- */
- if (deg_debug_graphviz_is_cluster(tail) && !deg_debug_graphviz_is_owner(head, tail)) {
- deg_debug_fprintf(ctx, ",ltail=\"cluster_%p\"", tail);
- }
- if (deg_debug_graphviz_is_cluster(head) && !deg_debug_graphviz_is_owner(tail, head)) {
- deg_debug_fprintf(ctx, ",lhead=\"cluster_%p\"", head);
- }
- deg_debug_fprintf(ctx, "];" NL);
- deg_debug_fprintf(ctx, NL);
- }
- DEPSNODE_RELATIONS_ITER_END;
-
-#if 0
- if (node->tclass == DEPSNODE_CLASS_COMPONENT) {
- const ComponentDepsNode *comp_node = (const ComponentDepsNode *)node;
- for (ComponentDepsNode::OperationMap::const_iterator it = comp_node->operations.begin();
- it != comp_node->operations.end();
- ++it)
- {
- OperationDepsNode *op_node = it->second;
- deg_debug_graphviz_node_relations(ctx, op_node);
- }
- }
- else if (node->type == DEPSNODE_TYPE_ID_REF) {
- const IDDepsNode *id_node = (const IDDepsNode *)node;
- for (IDDepsNode::ComponentMap::const_iterator it = id_node->components.begin();
- it != id_node->components.end();
- ++it)
- {
- const ComponentDepsNode *comp = it->second;
- deg_debug_graphviz_node_relations(ctx, comp);
- }
- }
- else if (node->type == DEPSNODE_TYPE_SUBGRAPH) {
- SubgraphDepsNode *sub_node = (SubgraphDepsNode *)node;
- if (sub_node->graph) {
- deg_debug_graphviz_graph_relations(ctx, sub_node->graph);
- }
- }
-#endif
-}
-
-static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx,
- const Depsgraph *graph)
-{
- if (graph->root_node) {
- deg_debug_graphviz_node(ctx, graph->root_node);
- }
- for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
- it != graph->id_hash.end();
- ++it)
- {
- DepsNode *node = it->second;
- deg_debug_graphviz_node(ctx, node);
- }
- TimeSourceDepsNode *time_source = graph->find_time_source(NULL);
- if (time_source != NULL) {
- deg_debug_graphviz_node(ctx, time_source);
- }
-}
-
-static void deg_debug_graphviz_graph_relations(const DebugContext &ctx,
- const Depsgraph *graph)
-{
-#if 0
- if (graph->root_node) {
- deg_debug_graphviz_node_relations(ctx, graph->root_node);
- }
- for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
- it != graph->id_hash.end();
- ++it)
- {
- DepsNode *id_node = it->second;
- deg_debug_graphviz_node_relations(ctx, id_node);
- }
-#else
- /* XXX not in use yet */
-// for (Depsgraph::OperationNodes::const_iterator it = graph->all_opnodes.begin();
-// it != graph->all_opnodes.end();
-// ++it)
-// {
-// OperationDepsNode *op_node = *it;
-// deg_debug_graphviz_node_relations(ctx, op_node);
-// }
- for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
- it != graph->id_hash.end();
- ++it)
- {
- IDDepsNode *id_node = it->second;
- for (IDDepsNode::ComponentMap::const_iterator it = id_node->components.begin();
- it != id_node->components.end();
- ++it)
- {
- ComponentDepsNode *comp_node = it->second;
- for (ComponentDepsNode::OperationMap::const_iterator it = comp_node->operations.begin();
- it != comp_node->operations.end();
- ++it)
- {
- OperationDepsNode *op_node = it->second;
- deg_debug_graphviz_node_relations(ctx, op_node);
- }
- }
- }
-
- TimeSourceDepsNode *time_source = graph->find_time_source(NULL);
- if (time_source != NULL) {
- deg_debug_graphviz_node_relations(ctx, time_source);
- }
-#endif
-}
-
-void DEG_debug_graphviz(const Depsgraph *graph, FILE *f, const char *label, bool show_eval)
-{
-#if 0 /* generate shaded color set */
- static char colors[][3] = {{0xa6, 0xce, 0xe3},{0x1f, 0x78, 0xb4},{0xb2, 0xdf, 0x8a},{0x33, 0xa0, 0x2c},
- {0xfb, 0x9a, 0x99},{0xe3, 0x1a, 0x1c},{0xfd, 0xbf, 0x6f},{0xff, 0x7f, 0x00},
- {0xca, 0xb2, 0xd6},{0x6a, 0x3d, 0x9a},{0xff, 0xff, 0x99},{0xb1, 0x59, 0x28}};
- int i;
- const float factor = 0.666f;
- for (i=0; i < 12; ++i)
- printf("\"#%x%x%x\"\n", (char)(colors[i][0] * factor), (char)(colors[i][1] * factor), (char)(colors[i][2] * factor));
-#endif
-
- if (!graph) {
- return;
- }
-
- DebugContext ctx;
- ctx.file = f;
- ctx.show_tags = show_eval;
- ctx.show_eval_priority = show_eval;
-
- deg_debug_fprintf(ctx, "digraph depgraph {" NL);
- deg_debug_fprintf(ctx, "rankdir=LR;" NL);
- deg_debug_fprintf(ctx, "graph [");
- deg_debug_fprintf(ctx, "compound=true");
- deg_debug_fprintf(ctx, ",labelloc=\"t\"");
- deg_debug_fprintf(ctx, ",fontsize=%f", deg_debug_graphviz_graph_label_size);
- deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname);
- deg_debug_fprintf(ctx, ",label=\"%s\"", label);
- deg_debug_fprintf(ctx, ",splines=ortho");
- deg_debug_fprintf(ctx, ",overlap=scalexy"); // XXX: only when using neato
- deg_debug_fprintf(ctx, "];" NL);
-
- deg_debug_graphviz_graph_nodes(ctx, graph);
- deg_debug_graphviz_graph_relations(ctx, graph);
-
- deg_debug_graphviz_legend(ctx);
-
- deg_debug_fprintf(ctx, "}" NL);
-}
-
-#undef NL
+#include "intern/eval/deg_eval_debug.h"
+#include "intern/depsgraph_intern.h"
+#include "util/deg_util_foreach.h"
/* ************************************************ */
-static string get_component_name(eDepsNode_Type type, const string &name = "")
-{
- DepsNodeFactory *factory = DEG_get_node_factory(type);
- if (name.empty()) {
- return string(factory->tname());
- }
- else {
- return string(factory->tname()) + " | " + name;
- }
-}
-
-static void times_clear(DepsgraphStatsTimes &times)
-{
- times.duration_last = 0.0f;
-}
-
-static void times_add(DepsgraphStatsTimes &times, float time)
-{
- times.duration_last += time;
-}
-
-void DepsgraphDebug::eval_begin(const EvaluationContext *UNUSED(eval_ctx))
-{
- /* TODO(sergey): Stats are currently globally disabled. */
- /* verify_stats(); */
- reset_stats();
-}
-
-void DepsgraphDebug::eval_end(const EvaluationContext *UNUSED(eval_ctx))
-{
- WM_main_add_notifier(NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
-}
-
-void DepsgraphDebug::eval_step(const EvaluationContext *UNUSED(eval_ctx),
- const char *message)
-{
-#ifdef DEG_DEBUG_BUILD
- if (deg_debug_eval_cb)
- deg_debug_eval_cb(deg_debug_eval_userdata, message);
-#else
- (void)message; /* Ignored. */
-#endif
-}
-
-void DepsgraphDebug::task_started(Depsgraph *graph,
- const OperationDepsNode *node)
-{
- if (stats) {
- BLI_spin_lock(&graph->lock);
-
- ComponentDepsNode *comp = node->owner;
- ID *id = comp->owner->id;
-
- DepsgraphStatsID *id_stats = get_id_stats(id, true);
- times_clear(id_stats->times);
-
- /* XXX TODO use something like: if (id->flag & ID_DEG_DETAILS) {...} */
- if (0) {
- /* XXX component name usage needs cleanup! currently mixes identifier and description strings! */
- DepsgraphStatsComponent *comp_stats = get_component_stats(id, get_component_name(comp->type, comp->name), true);
- times_clear(comp_stats->times);
- }
-
- BLI_spin_unlock(&graph->lock);
- }
-}
-
-void DepsgraphDebug::task_completed(Depsgraph *graph,
- const OperationDepsNode *node,
- double time)
-{
- if (stats) {
- BLI_spin_lock(&graph->lock);
-
- ComponentDepsNode *comp = node->owner;
- ID *id = comp->owner->id;
-
- DepsgraphStatsID *id_stats = get_id_stats(id, true);
- times_add(id_stats->times, time);
-
- /* XXX TODO use something like: if (id->flag & ID_DEG_DETAILS) {...} */
- if (0) {
- /* XXX component name usage needs cleanup! currently mixes identifier and description strings! */
- DepsgraphStatsComponent *comp_stats = get_component_stats(id, get_component_name(comp->type, comp->name), true);
- times_add(comp_stats->times, time);
- }
-
- BLI_spin_unlock(&graph->lock);
- }
-}
-
-/* ********** */
-/* Statistics */
-
-DepsgraphStats *DepsgraphDebug::stats = NULL;
-
-/* GHash callback */
-static void deg_id_stats_free(void *val)
-{
- DepsgraphStatsID *id_stats = (DepsgraphStatsID *)val;
-
- if (id_stats) {
- BLI_freelistN(&id_stats->components);
- MEM_freeN(id_stats);
- }
-}
-
-void DepsgraphDebug::stats_init()
-{
- if (!stats) {
- stats = (DepsgraphStats *)MEM_callocN(sizeof(DepsgraphStats), "Depsgraph Stats");
- stats->id_stats = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "Depsgraph ID Stats Hash");
- }
-}
-
-void DepsgraphDebug::stats_free()
-{
- if (stats) {
- BLI_ghash_free(stats->id_stats, NULL, deg_id_stats_free);
- MEM_freeN(stats);
- stats = NULL;
- }
-}
-
-void DepsgraphDebug::verify_stats()
-{
- stats_init();
-}
-
-void DepsgraphDebug::reset_stats()
-{
- if (!stats) {
- return;
- }
-
- /* XXX this doesn't work, will immediately clear all info,
- * since most depsgraph updates have none or very few updates to handle.
- *
- * Could consider clearing only zero-user ID blocks here
- */
-// BLI_ghash_clear(stats->id_stats, NULL, deg_id_stats_free);
-}
-
-DepsgraphStatsID *DepsgraphDebug::get_id_stats(ID *id, bool create)
-{
- DepsgraphStatsID *id_stats = (DepsgraphStatsID *)BLI_ghash_lookup(stats->id_stats, id);
-
- if (!id_stats && create) {
- id_stats = (DepsgraphStatsID *)MEM_callocN(sizeof(DepsgraphStatsID), "Depsgraph ID Stats");
- id_stats->id = id;
-
- BLI_ghash_insert(stats->id_stats, id, id_stats);
- }
-
- return id_stats;
-}
-
-DepsgraphStatsComponent *DepsgraphDebug::get_component_stats(
- DepsgraphStatsID *id_stats,
- const string &name,
- bool create)
-{
- DepsgraphStatsComponent *comp_stats;
- for (comp_stats = (DepsgraphStatsComponent *)id_stats->components.first;
- comp_stats != NULL;
- comp_stats = comp_stats->next)
- {
- if (STREQ(comp_stats->name, name.c_str()))
- break;
- }
- if (!comp_stats && create) {
- comp_stats = (DepsgraphStatsComponent *)MEM_callocN(sizeof(DepsgraphStatsComponent), "Depsgraph Component Stats");
- BLI_strncpy(comp_stats->name, name.c_str(), sizeof(comp_stats->name));
- BLI_addtail(&id_stats->components, comp_stats);
- }
- return comp_stats;
-}
-
-/* ------------------------------------------------ */
-
DepsgraphStats *DEG_stats(void)
{
- return DepsgraphDebug::stats;
+ return DEG::DepsgraphDebug::stats;
}
void DEG_stats_verify()
{
- DepsgraphDebug::verify_stats();
+ DEG::DepsgraphDebug::verify_stats();
}
DepsgraphStatsID *DEG_stats_id(ID *id)
{
- if (!DepsgraphDebug::stats) {
+ if (!DEG::DepsgraphDebug::stats) {
return NULL;
}
- return DepsgraphDebug::get_id_stats(id, false);
+ return DEG::DepsgraphDebug::get_id_stats(id, false);
}
bool DEG_debug_compare(const struct Depsgraph *graph1,
@@ -987,7 +70,9 @@ bool DEG_debug_compare(const struct Depsgraph *graph1,
{
BLI_assert(graph1 != NULL);
BLI_assert(graph2 != NULL);
- if (graph1->operations.size() != graph2->operations.size()) {
+ const DEG::Depsgraph *deg_graph1 = reinterpret_cast<const DEG::Depsgraph *>(graph1);
+ const DEG::Depsgraph *deg_graph2 = reinterpret_cast<const DEG::Depsgraph *>(graph2);
+ if (deg_graph1->operations.size() != deg_graph2->operations.size()) {
return false;
}
/* TODO(sergey): Currently we only do real stupid check,
@@ -1017,34 +102,21 @@ bool DEG_debug_scene_relations_validate(Main *bmain,
bool DEG_debug_consistency_check(Depsgraph *graph)
{
- /* Validate links exists in both directions. */
- for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
- it_op != graph->operations.end();
- ++it_op)
- {
- OperationDepsNode *node = *it_op;
- for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
- it_rel != node->outlinks.end();
- ++it_rel)
- {
- DepsRelation *rel = *it_rel;
+ const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph);
+ /* Validate links exists in both directions. */
+ foreach (DEG::OperationDepsNode *node, deg_graph->operations) {
+ foreach (DEG::DepsRelation *rel, node->outlinks) {
int counter1 = 0;
- for (OperationDepsNode::Relations::const_iterator tmp_rel = node->outlinks.begin();
- tmp_rel != node->outlinks.end();
- ++tmp_rel)
- {
- if (*tmp_rel == rel) {
+ foreach (DEG::DepsRelation *tmp_rel, node->outlinks) {
+ if (tmp_rel == rel) {
++counter1;
}
}
int counter2 = 0;
- for (OperationDepsNode::Relations::const_iterator tmp_rel = rel->to->inlinks.begin();
- tmp_rel != rel->to->inlinks.end();
- ++tmp_rel)
- {
- if (*tmp_rel == rel) {
+ foreach (DEG::DepsRelation *tmp_rel, rel->to->inlinks) {
+ if (tmp_rel == rel) {
++counter2;
}
}
@@ -1057,33 +129,18 @@ bool DEG_debug_consistency_check(Depsgraph *graph)
}
}
- for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
- it_op != graph->operations.end();
- ++it_op)
- {
- OperationDepsNode *node = *it_op;
- for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin();
- it_rel != node->inlinks.end();
- ++it_rel)
- {
- DepsRelation *rel = *it_rel;
-
+ foreach (DEG::OperationDepsNode *node, deg_graph->operations) {
+ foreach (DEG::DepsRelation *rel, node->inlinks) {
int counter1 = 0;
- for (OperationDepsNode::Relations::const_iterator tmp_rel = node->inlinks.begin();
- tmp_rel != node->inlinks.end();
- ++tmp_rel)
- {
- if (*tmp_rel == rel) {
+ foreach (DEG::DepsRelation *tmp_rel, node->inlinks) {
+ if (tmp_rel == rel) {
++counter1;
}
}
int counter2 = 0;
- for (OperationDepsNode::Relations::const_iterator tmp_rel = rel->from->outlinks.begin();
- tmp_rel != rel->from->outlinks.end();
- ++tmp_rel)
- {
- if (*tmp_rel == rel) {
+ foreach (DEG::DepsRelation *tmp_rel, rel->from->outlinks) {
+ if (tmp_rel == rel) {
++counter2;
}
}
@@ -1096,32 +153,20 @@ bool DEG_debug_consistency_check(Depsgraph *graph)
}
/* Validate node valency calculated in both directions. */
- for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
- it_op != graph->operations.end();
- ++it_op)
- {
- OperationDepsNode *node = *it_op;
+ foreach (DEG::OperationDepsNode *node, deg_graph->operations) {
node->num_links_pending = 0;
node->done = 0;
}
- for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
- it_op != graph->operations.end();
- ++it_op)
- {
- OperationDepsNode *node = *it_op;
+ foreach (DEG::OperationDepsNode *node, deg_graph->operations) {
if (node->done) {
printf("Node %s is twice in the operations!\n",
node->identifier().c_str());
return false;
}
- for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
- it_rel != node->outlinks.end();
- ++it_rel)
- {
- DepsRelation *rel = *it_rel;
- if (rel->to->type == DEPSNODE_TYPE_OPERATION) {
- OperationDepsNode *to = (OperationDepsNode *)rel->to;
+ foreach (DEG::DepsRelation *rel, node->outlinks) {
+ if (rel->to->type == DEG::DEPSNODE_TYPE_OPERATION) {
+ DEG::OperationDepsNode *to = (DEG::OperationDepsNode *)rel->to;
BLI_assert(to->num_links_pending < to->inlinks.size());
++to->num_links_pending;
}
@@ -1129,18 +174,10 @@ bool DEG_debug_consistency_check(Depsgraph *graph)
node->done = 1;
}
- for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
- it_op != graph->operations.end();
- ++it_op)
- {
- OperationDepsNode *node = *it_op;
+ foreach (DEG::OperationDepsNode *node, deg_graph->operations) {
int num_links_pending = 0;
- for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin();
- it_rel != node->inlinks.end();
- ++it_rel)
- {
- DepsRelation *rel = *it_rel;
- if (rel->from->type == DEPSNODE_TYPE_OPERATION) {
+ foreach (DEG::DepsRelation *rel, node->inlinks) {
+ if (rel->from->type == DEG::DEPSNODE_TYPE_OPERATION) {
++num_links_pending;
}
}
@@ -1166,12 +203,14 @@ bool DEG_debug_consistency_check(Depsgraph *graph)
void DEG_stats_simple(const Depsgraph *graph, size_t *r_outer,
size_t *r_operations, size_t *r_relations)
{
+ const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph);
+
/* number of operations */
if (r_operations) {
/* All operations should be in this list, allowing us to count the total
* number of nodes.
*/
- *r_operations = graph->operations.size();
+ *r_operations = deg_graph->operations.size();
}
/* Count number of outer nodes and/or relations between these. */
@@ -1179,29 +218,21 @@ void DEG_stats_simple(const Depsgraph *graph, size_t *r_outer,
size_t tot_outer = 0;
size_t tot_rels = 0;
- for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
- it != graph->id_hash.end();
- ++it)
+ GHASH_FOREACH_BEGIN(DEG::IDDepsNode *, id_node, deg_graph->id_hash)
{
- IDDepsNode *id_node = it->second;
tot_outer++;
- for (IDDepsNode::ComponentMap::const_iterator it = id_node->components.begin();
- it != id_node->components.end();
- ++it)
+ GHASH_FOREACH_BEGIN(DEG::ComponentDepsNode *, comp_node, id_node->components)
{
- ComponentDepsNode *comp_node = it->second;
tot_outer++;
- for (ComponentDepsNode::OperationMap::const_iterator it = comp_node->operations.begin();
- it != comp_node->operations.end();
- ++it)
- {
- OperationDepsNode *op_node = it->second;
+ foreach (DEG::OperationDepsNode *op_node, comp_node->operations) {
tot_rels += op_node->inlinks.size();
}
}
+ GHASH_FOREACH_END();
}
+ GHASH_FOREACH_END();
- TimeSourceDepsNode *time_source = graph->find_time_source(NULL);
+ DEG::TimeSourceDepsNode *time_source = deg_graph->find_time_source(NULL);
if (time_source != NULL) {
tot_rels += time_source->inlinks.size();
}
@@ -1210,4 +241,3 @@ void DEG_stats_simple(const Depsgraph *graph, size_t *r_outer,
if (r_outer) *r_outer = tot_outer;
}
}
-
diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc
index 66535f5214b..c41f28b07e8 100644
--- a/source/blender/depsgraph/intern/depsgraph_eval.cc
+++ b/source/blender/depsgraph/intern/depsgraph_eval.cc
@@ -32,11 +32,11 @@
#include "MEM_guardedalloc.h"
-#include "PIL_time.h"
-
extern "C" {
+#include "DNA_scene_types.h"
+
#include "BLI_utildefines.h"
-#include "BLI_task.h"
+#include "BLI_ghash.h"
#include "BKE_depsgraph.h"
#include "BKE_scene.h"
@@ -44,13 +44,13 @@ extern "C" {
#include "DEG_depsgraph.h"
} /* extern "C" */
-#include "atomic_ops.h"
+#include "intern/eval/deg_eval.h"
+#include "intern/eval/deg_eval_flush.h"
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_operation.h"
-#include "depsgraph.h"
-#include "depsnode.h"
-#include "depsnode_component.h"
-#include "depsnode_operation.h"
-#include "depsgraph_debug.h"
+#include "intern/depsgraph.h"
#ifdef WITH_LEGACY_DEPSGRAPH
static bool use_legacy_depsgraph = true;
@@ -118,359 +118,23 @@ void DEG_evaluation_context_free(EvaluationContext *eval_ctx)
MEM_freeN(eval_ctx);
}
-/* ********************** */
-/* Evaluation Entrypoints */
-
-/* Forward declarations. */
-static void schedule_children(TaskPool *pool,
- Depsgraph *graph,
- OperationDepsNode *node,
- const int layers,
- const int thread_id);
-
-struct DepsgraphEvalState {
- EvaluationContext *eval_ctx;
- Depsgraph *graph;
- int layers;
-};
-
-static void deg_task_run_func(TaskPool *pool,
- void *taskdata,
- int thread_id)
-{
- DepsgraphEvalState *state = (DepsgraphEvalState *)BLI_task_pool_userdata(pool);
- OperationDepsNode *node = (OperationDepsNode *)taskdata;
-
- BLI_assert(!node->is_noop() && "NOOP nodes should not actually be scheduled");
-
- /* Should only be the case for NOOPs, which never get to this point. */
- BLI_assert(node->evaluate);
-
- while (true) {
- /* Get context. */
- // TODO: who initialises this? "Init" operations aren't able to initialise it!!!
- /* TODO(sergey): We don't use component contexts at this moment. */
- /* ComponentDepsNode *comp = node->owner; */
- BLI_assert(node->owner != NULL);
-
- /* Since we're not leaving the thread for until the graph branches it is
- * possible to have NO-OP on the way. for which evaluate() will be NULL.
- * but that's all fine, we'll just scheduler it's children.
- */
- if (node->evaluate) {
- /* Take note of current time. */
- double start_time = PIL_check_seconds_timer();
- DepsgraphDebug::task_started(state->graph, node);
-
- /* Perform operation. */
- node->evaluate(state->eval_ctx);
-
- /* Note how long this took. */
- double end_time = PIL_check_seconds_timer();
- DepsgraphDebug::task_completed(state->graph,
- node,
- end_time - start_time);
- }
-
- /* If there's only one outgoing link we try to immediately switch to
- * that node evaluation, without leaving the thread.
- *
- * It's only doable if the child don't have extra relations or all they
- * are satisfied.
- *
- * TODO(sergey): Checks here can be de-duplicated with the ones from
- * schedule_node(), however, how to do it nicely?
- */
- if (node->outlinks.size() == 1) {
- DepsRelation *rel = node->outlinks[0];
- OperationDepsNode *child = (OperationDepsNode *)rel->to;
- BLI_assert(child->type == DEPSNODE_TYPE_OPERATION);
- if (!child->scheduled) {
- int id_layers = child->owner->owner->layers;
- if (!((child->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0 &&
- (id_layers & state->layers) != 0))
- {
- /* Node does not need an update, so can;t continue with the
- * chain and need to switch to another one by leaving the
- * thread.
- */
- break;
- }
- if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
- BLI_assert(child->num_links_pending > 0);
- atomic_sub_uint32(&child->num_links_pending, 1);
- }
- if (child->num_links_pending == 0) {
- bool is_scheduled = atomic_fetch_and_or_uint8((uint8_t *)&child->scheduled, (uint8_t)true);
- if (!is_scheduled) {
- /* Node was not scheduled, switch to it! */
- node = child;
- }
- else {
- /* Someone else scheduled the node, leaving us
- * unemployed in this thread, we're leaving.
- */
- break;
- }
- }
- else {
- /* There are other dependencies on the child, can't do
- * anything in the current thread.
- */
- break;
- }
- }
- else {
- /* Happens when having cyclic dependencies.
- *
- * Nothing to do here, single child was already scheduled, we
- * can leave the thread now.
- */
- break;
- }
- }
- else {
- /* TODO(sergey): It's possible to use one of the outgoing relations
- * as a chain which we'll try to keep alive, but it's a bit more
- * involved change.
- */
- schedule_children(pool, state->graph, node, state->layers, thread_id);
- break;
- }
- }
-}
-
-typedef struct CalculatePengindData {
- Depsgraph *graph;
- int layers;
-} CalculatePengindData;
-
-static void calculate_pending_func(void *data_v, int i)
-{
- CalculatePengindData *data = (CalculatePengindData *)data_v;
- Depsgraph *graph = data->graph;
- int layers = data->layers;
- OperationDepsNode *node = graph->operations[i];
- IDDepsNode *id_node = node->owner->owner;
-
- node->num_links_pending = 0;
- node->scheduled = false;
-
- /* count number of inputs that need updates */
- if ((id_node->layers & layers) != 0 &&
- (node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
- {
- DEPSNODE_RELATIONS_ITER_BEGIN(node->inlinks, rel)
- {
- if (rel->from->type == DEPSNODE_TYPE_OPERATION &&
- (rel->flag & DEPSREL_FLAG_CYCLIC) == 0)
- {
- OperationDepsNode *from = (OperationDepsNode *)rel->from;
- IDDepsNode *id_from_node = from->owner->owner;
- if ((id_from_node->layers & layers) != 0 &&
- (from->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
- {
- ++node->num_links_pending;
- }
- }
- }
- DEPSNODE_RELATIONS_ITER_END;
- }
-}
-
-static void calculate_pending_parents(Depsgraph *graph, int layers)
-{
- const int num_operations = graph->operations.size();
- const bool do_threads = num_operations > 256;
- CalculatePengindData data;
- data.graph = graph;
- data.layers = layers;
- BLI_task_parallel_range(0, num_operations, &data, calculate_pending_func, do_threads);
-}
-
-#ifdef USE_EVAL_PRIORITY
-static void calculate_eval_priority(OperationDepsNode *node)
-{
- if (node->done) {
- return;
- }
- node->done = 1;
-
- if (node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
- /* XXX standard cost of a node, could be estimated somewhat later on */
- const float cost = 1.0f;
- /* NOOP nodes have no cost */
- node->eval_priority = node->is_noop() ? cost : 0.0f;
-
- for (OperationDepsNode::Relations::const_iterator it = node->outlinks.begin();
- it != node->outlinks.end();
- ++it)
- {
- DepsRelation *rel = *it;
- OperationDepsNode *to = (OperationDepsNode *)rel->to;
- BLI_assert(to->type == DEPSNODE_TYPE_OPERATION);
- calculate_eval_priority(to);
- node->eval_priority += to->eval_priority;
- }
- }
- else {
- node->eval_priority = 0.0f;
- }
-}
-#endif
-
-/* Schedule a node if it needs evaluation.
- * dec_parents: Decrement pending parents count, true when child nodes are scheduled
- * after a task has been completed.
- */
-static void schedule_node(TaskPool *pool, Depsgraph *graph, int layers,
- OperationDepsNode *node, bool dec_parents,
- const int thread_id)
-{
- int id_layers = node->owner->owner->layers;
-
- if ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0 &&
- (id_layers & layers) != 0)
- {
- if (dec_parents) {
- BLI_assert(node->num_links_pending > 0);
- atomic_sub_uint32(&node->num_links_pending, 1);
- }
-
- if (node->num_links_pending == 0) {
- bool is_scheduled = atomic_fetch_and_or_uint8((uint8_t *)&node->scheduled, (uint8_t)true);
- if (!is_scheduled) {
- if (node->is_noop()) {
- /* skip NOOP node, schedule children right away */
- schedule_children(pool, graph, node, layers, thread_id);
- }
- else {
- /* children are scheduled once this task is completed */
- BLI_task_pool_push_from_thread(pool,
- deg_task_run_func,
- node,
- false,
- TASK_PRIORITY_LOW,
- thread_id);
- }
- }
- }
- }
-}
-
-static void schedule_graph(TaskPool *pool,
- Depsgraph *graph,
- const int layers)
-{
- for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
- it != graph->operations.end();
- ++it)
- {
- OperationDepsNode *node = *it;
- schedule_node(pool, graph, layers, node, false, 0);
- }
-}
-
-static void schedule_children(TaskPool *pool,
- Depsgraph *graph,
- OperationDepsNode *node,
- const int layers,
- const int thread_id)
-{
- DEPSNODE_RELATIONS_ITER_BEGIN(node->outlinks, rel)
- {
- OperationDepsNode *child = (OperationDepsNode *)rel->to;
- BLI_assert(child->type == DEPSNODE_TYPE_OPERATION);
- if (child->scheduled) {
- /* Happens when having cyclic dependencies. */
- continue;
- }
- schedule_node(pool, graph, layers, child, (rel->flag & DEPSREL_FLAG_CYCLIC) == 0, thread_id);
- }
- DEPSNODE_RELATIONS_ITER_END;
-}
-
-/**
- * Evaluate all nodes tagged for updating,
- * \warning This is usually done as part of main loop, but may also be
- * called from frame-change update.
- *
- * \note Time sources should be all valid!
- */
-void DEG_evaluate_on_refresh_ex(EvaluationContext *eval_ctx,
- Depsgraph *graph,
- const int layers)
-{
- /* Generate base evaluation context, upon which all the others are derived. */
- // TODO: this needs both main and scene access...
-
- /* Nothing to update, early out. */
- if (graph->entry_tags.size() == 0) {
- return;
- }
-
- /* Set time for the current graph evaluation context. */
- TimeSourceDepsNode *time_src = graph->find_time_source();
- eval_ctx->ctime = time_src->cfra;
-
- /* XXX could use a separate pool for each eval context */
- DepsgraphEvalState state;
- state.eval_ctx = eval_ctx;
- state.graph = graph;
- state.layers = layers;
-
- TaskScheduler *task_scheduler = BLI_task_scheduler_get();
- TaskPool *task_pool = BLI_task_pool_create(task_scheduler, &state);
-
- if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) {
- BLI_pool_set_num_threads(task_pool, 1);
- }
-
- calculate_pending_parents(graph, layers);
-
- /* Clear tags. */
- for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
- it != graph->operations.end();
- ++it)
- {
- OperationDepsNode *node = *it;
- node->done = 0;
- }
-
- /* Calculate priority for operation nodes. */
-#ifdef USE_EVAL_PRIORITY
- for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
- it != graph->operations.end();
- ++it)
- {
- OperationDepsNode *node = *it;
- calculate_eval_priority(node);
- }
-#endif
-
- DepsgraphDebug::eval_begin(eval_ctx);
-
- schedule_graph(task_pool, graph, layers);
-
- BLI_task_pool_work_and_wait(task_pool);
- BLI_task_pool_free(task_pool);
-
- DepsgraphDebug::eval_end(eval_ctx);
-
- /* Clear any uncleared tags - just in case. */
- DEG_graph_clear_tags(graph);
-}
-
/* Evaluate all nodes tagged for updating. */
void DEG_evaluate_on_refresh(EvaluationContext *eval_ctx,
Depsgraph *graph,
Scene *scene)
{
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
/* Update time on primary timesource. */
- TimeSourceDepsNode *tsrc = graph->find_time_source();
+ DEG::TimeSourceDepsNode *tsrc = deg_graph->find_time_source();
tsrc->cfra = BKE_scene_frame_get(scene);
-
- DEG_evaluate_on_refresh_ex(eval_ctx, graph, graph->layers);
+ unsigned int layers = deg_graph->layers;
+ /* XXX(sergey): This works around missing updates in temp scenes used
+ * by various scripts, but is weak and needs closer investigation.
+ */
+ if (layers == 0) {
+ layers = scene->lay;
+ }
+ DEG::deg_evaluate_on_refresh(eval_ctx, deg_graph, layers);
}
/* Frame-change happened for root scene that graph belongs to. */
@@ -478,21 +142,20 @@ void DEG_evaluate_on_framechange(EvaluationContext *eval_ctx,
Main *bmain,
Depsgraph *graph,
float ctime,
- const int layers)
+ const unsigned int layers)
{
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
/* Update time on primary timesource. */
- TimeSourceDepsNode *tsrc = graph->find_time_source();
+ DEG::TimeSourceDepsNode *tsrc = deg_graph->find_time_source();
tsrc->cfra = ctime;
-
- tsrc->tag_update(graph);
-
- DEG_graph_flush_updates(bmain, graph);
-
+ tsrc->tag_update(deg_graph);
+ DEG::deg_graph_flush_updates(bmain, deg_graph);
/* Perform recalculation updates. */
- DEG_evaluate_on_refresh_ex(eval_ctx, graph, layers);
+ DEG::deg_evaluate_on_refresh(eval_ctx, deg_graph, layers);
}
bool DEG_needs_eval(Depsgraph *graph)
{
- return graph->entry_tags.size() != 0;
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+ return BLI_gset_size(deg_graph->entry_tags) != 0;
}
diff --git a/source/blender/depsgraph/intern/depsgraph_intern.h b/source/blender/depsgraph/intern/depsgraph_intern.h
index 7fdc2454564..e5d3d1f5861 100644
--- a/source/blender/depsgraph/intern/depsgraph_intern.h
+++ b/source/blender/depsgraph/intern/depsgraph_intern.h
@@ -31,65 +31,26 @@
* - Also, defines for "Node Type Info"
*/
-#ifndef __DEPSGRAPH_INTERN_H__
-#define __DEPSGRAPH_INTERN_H__
+#pragma once
#include <cstdlib>
#include "MEM_guardedalloc.h"
-#include "depsgraph.h"
-#include "depsnode.h"
+extern "C" {
+#include "BKE_global.h"
+}
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+#include "intern/depsgraph.h"
struct Main;
struct Group;
struct Scene;
-/* Graph Building ======================================================== */
-
-/**
- * Build depsgraph for the given group, and dump results in given graph container
- * This is usually used for building subgraphs for groups to use...
- */
-void DEG_graph_build_from_group(Depsgraph *graph, struct Main *bmain, struct Group *group);
-
-/* Build subgraph for group */
-DepsNode *DEG_graph_build_group_subgraph(Depsgraph *graph_main, struct Main *bmain, struct Group *group);
-
-/* Graph Copying ========================================================= */
-/* (Part of the Filtering API) */
-
-/**
- * Depsgraph Copying Context (dcc)
- *
- * Keeps track of node relationships/links/etc. during the copy
- * operation so that they can be safely remapped...
- */
-typedef struct DepsgraphCopyContext {
- struct GHash *nodes_hash; /* <DepsNode, DepsNode> mapping from src node to dst node */
- struct GHash *rels_hash; // XXX: same for relationships?
-
- // XXX: filtering criteria...
-} DepsgraphCopyContext;
-
-/* Internal Filtering API ---------------------------------------------- */
-
-/* Create filtering context */
-// XXX: needs params for conditions?
-DepsgraphCopyContext *DEG_filter_init(void);
-
-/* Free filtering context once filtering is done */
-void DEG_filter_cleanup(DepsgraphCopyContext *dcc);
-
-
-/* Data Copy Operations ------------------------------------------------ */
-
-/**
- * Make a (deep) copy of provided node and it's little subgraph
- * \warning Newly created node is not added to the existing graph
- * \param dcc: Context info for helping resolve links
- */
-DepsNode *DEG_copy_node(DepsgraphCopyContext *dcc, const DepsNode *src);
+namespace DEG {
/* Node Types Handling ================================================= */
@@ -101,8 +62,9 @@ struct DepsNodeFactory {
virtual eDepsNode_Class tclass() const = 0;
virtual const char *tname() const = 0;
- virtual DepsNode *create_node(const ID *id, const string &subdata, const string &name) const = 0;
- virtual DepsNode *copy_node(DepsgraphCopyContext *dcc, const DepsNode *copy) const = 0;
+ virtual DepsNode *create_node(const ID *id,
+ const string &subdata,
+ const string &name) const = 0;
};
template <class NodeType>
@@ -130,34 +92,18 @@ struct DepsNodeFactoryImpl : public DepsNodeFactory {
return node;
}
-
- virtual DepsNode *copy_node(DepsgraphCopyContext *dcc, const DepsNode *copy) const
- {
- BLI_assert(copy->type == type());
- DepsNode *node = OBJECT_GUARDED_NEW(NodeType);
-
- /* populate base node settings */
- node->type = type();
- node->tclass = tclass();
- // XXX: need to review the name here, as we can't have exact duplicates...
- node->name = copy->name;
-
- node->copy(dcc, static_cast<const NodeType *>(copy));
-
- return node;
- }
};
/* Typeinfo Management -------------------------------------------------- */
/* Register typeinfo */
-void DEG_register_node_typeinfo(DepsNodeFactory *factory);
+void deg_register_node_typeinfo(DepsNodeFactory *factory);
/* Get typeinfo for specified type */
-DepsNodeFactory *DEG_get_node_factory(const eDepsNode_Type type);
+DepsNodeFactory *deg_get_node_factory(const eDepsNode_Type type);
/* Get typeinfo for provided node */
-DepsNodeFactory *DEG_node_get_factory(const DepsNode *node);
+DepsNodeFactory *deg_node_get_factory(const DepsNode *node);
/* Editors Integration -------------------------------------------------- */
@@ -165,4 +111,11 @@ void deg_editors_id_update(struct Main *bmain, struct ID *id);
void deg_editors_scene_update(struct Main *bmain, struct Scene *scene, bool updated);
-#endif /* __DEPSGRAPH_INTERN_H__ */
+#define DEG_DEBUG_PRINTF(...) \
+ do { \
+ if (G.debug & G_DEBUG_DEPSGRAPH) { \
+ fprintf(stderr, __VA_ARGS__); \
+ } \
+ } while (0)
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc
index 73193747b93..7f2f6a65f5e 100644
--- a/source/blender/depsgraph/intern/depsgraph_query.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query.cc
@@ -33,166 +33,17 @@
#include "MEM_guardedalloc.h"
extern "C" {
-#include "BLI_utildefines.h"
-#include "BLI_ghash.h"
-
+#include "BKE_idcode.h"
#include "BKE_main.h"
#include "DEG_depsgraph_query.h"
} /* extern "C" */
-#include "depsgraph_queue.h"
-#include "depsnode.h"
-#include "depsnode_operation.h"
-#include "depsgraph_intern.h"
-
-/* ************************* */
-/* Low-Level Graph Traversal */
-
-#if 0
-/* Prepare for graph traversal, by tagging nodes, etc. */
-static void DEG_graph_traverse_begin(Depsgraph * /*graph*/)
-{
- /* go over all nodes, initialising the valence counts */
- // XXX: this will end up being O(|V|), which is bad when we're just updating a few nodes...
-}
-
-/* Perform a traversal of graph from given starting node (in execution order) */
-// TODO: additional flags for controlling the process?
-void DEG_graph_traverse_from_node(Depsgraph *graph, OperationDepsNode *start_node,
- DEG_FilterPredicate filter, void *filter_data,
- DEG_NodeOperation op, void *operation_data)
-{
- DepsgraphQueue *q;
-
- /* sanity checks */
- if (ELEM(NULL, graph, start_node, op))
- return;
-
- /* add node as starting node to be evaluated, with value of 0 */
- q = DEG_queue_new();
-
- start_node->num_links_pending = 0;
- DEG_queue_push(q, start_node, 0.0f);
-
- /* while we still have nodes in the queue, grab and work on next one */
- do {
- /* grab item at front of queue */
- // XXX: in practice, we may need to wait until one becomes available...
- OperationDepsNode *node = (OperationDepsNode *)DEG_queue_pop(q);
-
- /* perform operation on node */
- op(graph, node, operation_data);
-
- /* schedule up operations which depend on this */
- DEPSNODE_RELATIONS_ITER_BEGIN(node->outlinks, rel)
- {
- /* ensure that relationship is not tagged for ignoring (i.e. cyclic, etc.) */
- // TODO: cyclic refs should probably all get clustered towards the end, so that we can just stop on the first one
- if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
- OperationDepsNode *child_node = (OperationDepsNode *)rel->to;
-
- /* only visit node if the filtering function agrees */
- if ((filter == NULL) || filter(graph, child_node, filter_data)) {
- /* schedule up node... */
- child_node->num_links_pending--;
- DEG_queue_push(q, child_node, (float)child_node->num_links_pending);
- }
- }
- }
- DEPSNODE_RELATIONS_ITER_END;
- } while (DEG_queue_is_empty(q) == false);
-
- /* cleanup */
- DEG_queue_free(q);
-}
-#endif
-
-/* ************************************************************** */
-/* Filtering API - Basically, making a copy of the existing graph */
-
-/* Create filtering context */
-// TODO: allow passing in a number of criteria?
-DepsgraphCopyContext *DEG_filter_init()
-{
- DepsgraphCopyContext *dcc = (DepsgraphCopyContext *)MEM_callocN(sizeof(DepsgraphCopyContext), "DepsgraphCopyContext");
-
- /* init hashes for easy lookups */
- dcc->nodes_hash = BLI_ghash_ptr_new("Depsgraph Filter NodeHash");
- dcc->rels_hash = BLI_ghash_ptr_new("Depsgraph Filter Relationship Hash"); // XXX?
-
- /* store filtering criteria? */
- // xxx...
-
- return dcc;
-}
-
-/* Cleanup filtering context */
-void DEG_filter_cleanup(DepsgraphCopyContext *dcc)
-{
- /* sanity check */
- if (dcc == NULL)
- return;
-
- /* free hashes - contents are weren't copied, so are ok... */
- BLI_ghash_free(dcc->nodes_hash, NULL, NULL);
- BLI_ghash_free(dcc->rels_hash, NULL, NULL);
-
- /* clear filtering criteria */
- // ...
-
- /* free dcc itself */
- MEM_freeN(dcc);
-}
-
-/* -------------------------------------------------- */
-
-/* Create a copy of provided node */
-// FIXME: the handling of sub-nodes and links will need to be subject to filtering options...
-// XXX: perhaps this really shouldn't be exposed, as it will just be a sub-step of the evaluation process?
-DepsNode *DEG_copy_node(DepsgraphCopyContext *dcc, const DepsNode *src)
-{
- /* sanity check */
- if (src == NULL)
- return NULL;
-
- DepsNodeFactory *factory = DEG_get_node_factory(src->type);
- BLI_assert(factory != NULL);
- DepsNode *dst = factory->copy_node(dcc, src);
-
- /* add this node-pair to the hash... */
- BLI_ghash_insert(dcc->nodes_hash, (DepsNode *)src, dst);
-
-#if 0 /* XXX TODO */
- /* now, fix up any links in standard "node header" (i.e. DepsNode struct, that all
- * all others are derived from) that are now corrupt
- */
- {
- /* relationships to other nodes... */
- // FIXME: how to handle links? We may only have partial set of all nodes still?
- // XXX: the exact details of how to handle this are really part of the querying API...
-
- // XXX: BUT, for copying subgraphs, we'll need to define an API for doing this stuff anyways
- // (i.e. for resolving and patching over links that exist within subtree...)
- dst->inlinks.clear();
- dst->outlinks.clear();
-
- /* clear traversal data */
- dst->num_links_pending = 0;
- dst->lasttime = 0;
- }
-
- /* fix links */
- // XXX...
-#endif
-
- /* return copied node */
- return dst;
-}
+#include "intern/depsgraph_intern.h"
bool DEG_id_type_tagged(Main *bmain, short idtype)
{
- return bmain->id_tag_update[((unsigned char *)&idtype)[0]] != 0;
+ return bmain->id_tag_update[BKE_idcode_to_index(idtype)] != 0;
}
short DEG_get_eval_flags_for_id(Depsgraph *graph, ID *id)
@@ -207,7 +58,9 @@ short DEG_get_eval_flags_for_id(Depsgraph *graph, ID *id)
return 0;
}
- IDDepsNode *id_node = graph->find_id_node(id);
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+
+ DEG::IDDepsNode *id_node = deg_graph->find_id_node(id);
if (id_node == NULL) {
/* TODO(sergey): Does it mean we need to check set scene? */
return 0;
diff --git a/source/blender/depsgraph/intern/depsgraph_queue.cc b/source/blender/depsgraph/intern/depsgraph_queue.cc
deleted file mode 100644
index da60d73bc46..00000000000
--- a/source/blender/depsgraph/intern/depsgraph_queue.cc
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2013 Blender Foundation.
- * All rights reserved.
- *
- * Original Author: Joshua Leung
- * Contributor(s): None Yet
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/depsgraph/intern/depsgraph_queue.cc
- * \ingroup depsgraph
- *
- * Implementation of special queue type for use in Depsgraph traversals.
- */
-
-#include <stdlib.h>
-
-#include "MEM_guardedalloc.h"
-
-extern "C" {
-#include "BLI_utildefines.h"
-#include "BLI_heap.h"
-#include "BLI_ghash.h"
-} /* extern "C" */
-
-#include "depsgraph_queue.h"
-
-/* ****************************** */
-/* Depsgraph Queue implementation */
-
-/* Data Management ----------------------------------------- */
-
-DepsgraphQueue *DEG_queue_new(void)
-{
- DepsgraphQueue *q = (DepsgraphQueue *)MEM_callocN(sizeof(DepsgraphQueue), "DEG_queue_new()");
-
- /* init data structures for use here */
- q->pending_heap = BLI_heap_new();
- q->pending_hash = BLI_ghash_ptr_new("DEG Queue Pending Hash");
-
- q->ready_heap = BLI_heap_new();
-
- /* init settings */
- q->idx = 0;
- q->tot = 0;
-
- /* return queue */
- return q;
-}
-
-void DEG_queue_free(DepsgraphQueue *q)
-{
- /* free data structures */
- BLI_assert(BLI_heap_size(q->pending_heap) == 0);
- BLI_assert(BLI_heap_size(q->ready_heap) == 0);
- BLI_assert(BLI_ghash_size(q->pending_hash) == 0);
-
- BLI_heap_free(q->pending_heap, NULL);
- BLI_heap_free(q->ready_heap, NULL);
- BLI_ghash_free(q->pending_hash, NULL, NULL);
-
- /* free queue itself */
- MEM_freeN(q);
-}
-
-/* Statistics --------------------------------------------- */
-
-/* Get the number of nodes which are we should visit, but are not able to yet */
-size_t DEG_queue_num_pending(DepsgraphQueue *q)
-{
- return BLI_heap_size(q->pending_heap);
-}
-
-/* Get the number of nodes which are now ready to be visited */
-size_t DEG_queue_num_ready(DepsgraphQueue *q)
-{
- return BLI_heap_size(q->ready_heap);
-}
-
-/* Get total size of queue */
-size_t DEG_queue_size(DepsgraphQueue *q)
-{
- return DEG_queue_num_pending(q) + DEG_queue_num_ready(q);
-}
-
-/* Check if queue has any items in it (still passing through) */
-bool DEG_queue_is_empty(DepsgraphQueue *q)
-{
- return DEG_queue_size(q) == 0;
-}
-
-/* Queue Operations --------------------------------------- */
-
-/**
- * Add DepsNode to the queue
- * \param dnode: ``(DepsNode *)`` node to add to the queue
- * Each node is only added once to the queue; Subsequent pushes
- * merely update its status (e.g. moving it from "pending" to "ready")
- * \param cost: new "num_links_pending" count for node *after* it has encountered
- * via an outlink from the node currently being visited
- * (i.e. we're one of the dependencies which may now be able to be processed)
- */
-void DEG_queue_push(DepsgraphQueue *q, void *dnode, float cost)
-{
- HeapNode *hnode = NULL;
-
- /* Shortcut: Directly add to ready if node isn't waiting on anything now... */
- if (cost == 0) {
- /* node is now ready to be visited - schedule it up for such */
- if (BLI_ghash_haskey(q->pending_hash, dnode)) {
- /* remove from pending queue - we're moving it to the scheduling queue */
- hnode = (HeapNode *)BLI_ghash_lookup(q->pending_hash, dnode);
- BLI_heap_remove(q->pending_heap, hnode);
-
- BLI_ghash_remove(q->pending_hash, dnode, NULL, NULL);
- }
-
- /* schedule up node using latest count (of ready nodes) */
- BLI_heap_insert(q->ready_heap, (float)q->idx, dnode);
- q->idx++;
- }
- else {
- /* node is still waiting on some other ancestors,
- * so add it to the pending heap in the meantime...
- */
- // XXX: is this even necessary now?
- if (BLI_ghash_haskey(q->pending_hash, dnode)) {
- /* just update cost on pending node */
- hnode = (HeapNode *)BLI_ghash_lookup(q->pending_hash, dnode);
- BLI_heap_remove(q->pending_heap, hnode);
- BLI_heap_insert(q->pending_heap, cost, hnode);
- }
- else {
- /* add new node to pending queue, and increase size of overall queue */
- hnode = BLI_heap_insert(q->pending_heap, cost, dnode);
- q->tot++;
- }
- }
-}
-
-/* Grab a "ready" node from the queue */
-void *DEG_queue_pop(DepsgraphQueue *q)
-{
- /* sanity check: if there are no "ready" nodes,
- * start pulling from "pending" to keep things moving,
- * but throw a warning so that we know that something's up here...
- */
- if (BLI_heap_is_empty(q->ready_heap)) {
- // XXX: this should never happen
- // XXX: if/when it does happen, we may want instead to just wait until something pops up here...
- printf("DepsgraphHeap Warning: No more ready nodes available. Trying from pending (idx = %d, tot = %d, pending = %d, ready = %d)\n",
- (int)q->idx, (int)q->tot, (int)DEG_queue_num_pending(q), (int)DEG_queue_num_ready(q));
-
- return BLI_heap_popmin(q->pending_heap);
- }
- else {
- /* only grab "ready" nodes */
- return BLI_heap_popmin(q->ready_heap);
- }
-}
diff --git a/source/blender/depsgraph/intern/depsgraph_queue.h b/source/blender/depsgraph/intern/depsgraph_queue.h
deleted file mode 100644
index b85d46bd173..00000000000
--- a/source/blender/depsgraph/intern/depsgraph_queue.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2013 Blender Foundation.
- * All rights reserved.
- *
- * Original Author: Joshua Leung
- * Contributor(s): None Yet
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/depsgraph/intern/depsgraph_queue.h
- * \ingroup depsgraph
- *
- * Defines for special queue type for use in Depsgraph traversals.
- */
-
-#ifndef __DEPSGRAPH_QUEUE_H__
-#define __DEPSGRAPH_QUEUE_H__
-
-struct DepsNode;
-
-struct Heap;
-struct GHash;
-
-/* *********************************************** */
-/* Dependency Graph Traversal Queue
- *
- * There are two parts to this:
- * a) "Pending" Nodes - This part contains the set of nodes
- * which are related to those which have been visited
- * previously, but are not yet ready to actually be visited.
- * b) "Scheduled" Nodes - These are the nodes whose ancestors
- * have all been evaluated already, which means that any
- * or all of them can be picked (in practically in order) to
- * be visited immediately.
- *
- * Internally, the queue makes sure that each node in the graph
- * only gets added to the queue once. This is because there can
- * be multiple inlinks to each node given the way that the relations
- * work.
- */
-
-/* Depsgraph Queue Type */
-typedef struct DepsgraphQueue {
- /* Pending */
- struct Heap *pending_heap; /* (valence:int, DepsNode*) */
- struct GHash *pending_hash; /* (DepsNode* : HeapNode*>) */
-
- /* Ready to be visited - fifo */
- struct Heap *ready_heap; /* (idx:int, DepsNode*) */
-
- /* Size/Order counts */
- size_t idx; /* total number of nodes which are/have been ready so far (including those already visited) */
- size_t tot; /* total number of nodes which have passed through queue; mainly for debug */
-} DepsgraphQueue;
-
-/* ************************** */
-/* Depsgraph Queue Operations */
-
-/* Data management */
-DepsgraphQueue *DEG_queue_new(void);
-void DEG_queue_free(DepsgraphQueue *q);
-
-/* Statistics */
-size_t DEG_queue_num_pending(DepsgraphQueue *q);
-size_t DEG_queue_num_ready(DepsgraphQueue *q);
-
-size_t DEG_queue_size(DepsgraphQueue *q);
-bool DEG_queue_is_empty(DepsgraphQueue *q);
-
-/* Operations */
-void DEG_queue_push(DepsgraphQueue *q, void *dnode, float cost = 0.0f);
-void *DEG_queue_pop(DepsgraphQueue *q);
-
-#endif /* DEPSGRAPH_QUEUE_H */
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index 3ca23965749..4f27dab258d 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -44,6 +44,7 @@ extern "C" {
#include "BLI_task.h"
+#include "BKE_idcode.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_node.h"
@@ -55,11 +56,14 @@ extern "C" {
#include "DEG_depsgraph.h"
} /* extern "C" */
-#include "depsgraph_debug.h"
-#include "depsnode.h"
-#include "depsnode_component.h"
-#include "depsnode_operation.h"
-#include "depsgraph_intern.h"
+#include "intern/eval/deg_eval_flush.h"
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+
+#include "intern/depsgraph_intern.h"
+#include "util/deg_util_foreach.h"
/* *********************** */
/* Update Tagging/Flushing */
@@ -154,19 +158,21 @@ void depsgraph_legacy_handle_update_tag(Main *bmain, ID *id, short flag)
*/
void DEG_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id)
{
- IDDepsNode *node = graph->find_id_node(id);
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+ DEG::IDDepsNode *node = deg_graph->find_id_node(id);
lib_id_recalc_tag(bmain, id);
if (node != NULL) {
- node->tag_update(graph);
+ node->tag_update(deg_graph);
}
}
/* Tag nodes related to a specific piece of data */
void DEG_graph_data_tag_update(Depsgraph *graph, const PointerRNA *ptr)
{
- DepsNode *node = graph->find_node_from_pointer(ptr, NULL);
- if (node) {
- node->tag_update(graph);
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+ DEG::DepsNode *node = deg_graph->find_node_from_pointer(ptr, NULL);
+ if (node != NULL) {
+ node->tag_update(deg_graph);
}
else {
printf("Missing node in %s\n", __func__);
@@ -179,9 +185,10 @@ void DEG_graph_property_tag_update(Depsgraph *graph,
const PointerRNA *ptr,
const PropertyRNA *prop)
{
- DepsNode *node = graph->find_node_from_pointer(ptr, prop);
- if (node) {
- node->tag_update(graph);
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+ DEG::DepsNode *node = deg_graph->find_node_from_pointer(ptr, prop);
+ if (node != NULL) {
+ node->tag_update(deg_graph);
}
else {
printf("Missing node in %s\n", __func__);
@@ -228,6 +235,9 @@ void DEG_id_tag_update_ex(Main *bmain, ID *id, short flag)
if (flag & (OB_RECALC_OB | OB_RECALC_DATA)) {
DEG_graph_id_tag_update(bmain, graph, id);
}
+ else if (flag & OB_RECALC_TIME) {
+ DEG_graph_id_tag_update(bmain, graph, id);
+ }
}
}
@@ -253,135 +263,8 @@ void DEG_id_type_tag(Main *bmain, short idtype)
DEG_id_type_tag(bmain, ID_WO);
DEG_id_type_tag(bmain, ID_SCE);
}
- /* We tag based on first ID type character to avoid
- * looping over all ID's in case there are no tags.
- */
- bmain->id_tag_update[((unsigned char *)&idtype)[0]] = 1;
-}
-
-/* Update Flushing ---------------------------------- */
-
-/* FIFO queue for tagged nodes that need flushing */
-/* XXX This may get a dedicated implementation later if needed - lukas */
-typedef std::queue<OperationDepsNode *> FlushQueue;
-
-static void flush_init_func(void *data_v, int i)
-{
- /* ID node's done flag is used to avoid multiple editors update
- * for the same ID.
- */
- Depsgraph *graph = (Depsgraph *)data_v;
- OperationDepsNode *node = graph->operations[i];
- IDDepsNode *id_node = node->owner->owner;
- id_node->done = 0;
- node->scheduled = false;
- node->owner->flags &= ~DEPSCOMP_FULLY_SCHEDULED;
-}
-
-/* Flush updates from tagged nodes outwards until all affected nodes are tagged. */
-void DEG_graph_flush_updates(Main *bmain, Depsgraph *graph)
-{
- /* sanity check */
- if (graph == NULL)
- return;
-
- /* Nothing to update, early out. */
- if (graph->entry_tags.size() == 0) {
- return;
- }
-
- /* TODO(sergey): With a bit of flag magic we can get rid of this
- * extra loop.
- */
- const int num_operations = graph->operations.size();
- const bool do_threads = num_operations > 256;
- BLI_task_parallel_range(0, num_operations, graph, flush_init_func, do_threads);
-
- FlushQueue queue;
- /* Starting from the tagged "entry" nodes, flush outwards... */
- /* NOTE: Also need to ensure that for each of these, there is a path back to
- * root, or else they won't be done.
- * NOTE: Count how many nodes we need to handle - entry nodes may be
- * component nodes which don't count for this purpose!
- */
- for (Depsgraph::EntryTags::const_iterator it = graph->entry_tags.begin();
- it != graph->entry_tags.end();
- ++it)
- {
- OperationDepsNode *node = *it;
- IDDepsNode *id_node = node->owner->owner;
- queue.push(node);
- if (id_node->done == 0) {
- deg_editors_id_update(bmain, id_node->id);
- id_node->done = 1;
- }
- node->scheduled = true;
- }
-
- while (!queue.empty()) {
- OperationDepsNode *node = queue.front();
- queue.pop();
- IDDepsNode *id_node = node->owner->owner;
- lib_id_recalc_tag(bmain, id_node->id);
- /* TODO(sergey): For until we've got proper data nodes in the graph. */
- lib_id_recalc_data_tag(bmain, id_node->id);
-
- ID *id = id_node->id;
- /* This code is used to preserve those areas which does direct
- * object update,
- *
- * Plus it ensures visibility changes and relations and layers
- * visibility update has proper flags to work with.
- */
- if (GS(id->name) == ID_OB) {
- Object *object = (Object *)id;
- ComponentDepsNode *comp_node = node->owner;
- if (comp_node->type == DEPSNODE_TYPE_ANIMATION) {
- object->recalc |= OB_RECALC_TIME;
- }
- else if (comp_node->type == DEPSNODE_TYPE_TRANSFORM) {
- object->recalc |= OB_RECALC_OB;
- }
- else {
- object->recalc |= OB_RECALC_DATA;
- }
- }
-
- /* Flush to nodes along links... */
- for (OperationDepsNode::Relations::const_iterator it = node->outlinks.begin();
- it != node->outlinks.end();
- ++it)
- {
- DepsRelation *rel = *it;
- OperationDepsNode *to_node = (OperationDepsNode *)rel->to;
- if (to_node->scheduled == false) {
- to_node->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
- queue.push(to_node);
- to_node->scheduled = true;
- if (id_node->done == 0) {
- deg_editors_id_update(bmain, id_node->id);
- id_node->done = 1;
- }
- }
- }
-
- /* TODO(sergey): For until incremental updates are possible
- * witin a component at least we tag the whole component
- * for update.
- */
- ComponentDepsNode *component = node->owner;
- if ((component->flags & DEPSCOMP_FULLY_SCHEDULED) == 0) {
- for (ComponentDepsNode::OperationMap::iterator it = component->operations.begin();
- it != node->owner->operations.end();
- ++it)
- {
- OperationDepsNode *op = it->second;
- op->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
- }
- component->flags |= DEPSCOMP_FULLY_SCHEDULED;
- }
- }
+ bmain->id_tag_update[BKE_idcode_to_index(idtype)] = 1;
}
/* Recursively push updates out to all nodes dependent on this,
@@ -395,34 +278,17 @@ void DEG_ids_flush_tagged(Main *bmain)
{
/* TODO(sergey): Only visible scenes? */
if (scene->depsgraph != NULL) {
- DEG_graph_flush_updates(bmain, scene->depsgraph);
+ DEG::deg_graph_flush_updates(
+ bmain,
+ reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph));
}
}
}
-static void graph_clear_func(void *data_v, int i)
-{
- Depsgraph *graph = (Depsgraph *)data_v;
- OperationDepsNode *node = graph->operations[i];
- /* Clear node's "pending update" settings. */
- node->flag &= ~(DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE);
-}
-
-/* Clear tags from all operation nodes. */
-void DEG_graph_clear_tags(Depsgraph *graph)
-{
- /* Go over all operation nodes, clearing tags. */
- const int num_operations = graph->operations.size();
- const bool do_threads = num_operations > 256;
- BLI_task_parallel_range(0, num_operations, graph, graph_clear_func, do_threads);
- /* Clear any entry tags which haven't been flushed. */
- graph->entry_tags.clear();
-}
-
/* Update dependency graph when visible scenes/layers changes. */
void DEG_graph_on_visible_update(Main *bmain, Scene *scene)
{
- Depsgraph *graph = scene->depsgraph;
+ DEG::Depsgraph *graph = reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph);
wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
int old_layers = graph->layers;
if (wm != NULL) {
@@ -450,11 +316,8 @@ void DEG_graph_on_visible_update(Main *bmain, Scene *scene)
* This is mainly needed on file load only, after that updates of invisible objects
* will be stored in the pending list.
*/
- for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
- it != graph->id_hash.end();
- ++it)
+ GHASH_FOREACH_BEGIN(DEG::IDDepsNode *, id_node, graph->id_hash)
{
- IDDepsNode *id_node = it->second;
ID *id = id_node->id;
if ((id->tag & LIB_TAG_ID_RECALC_ALL) != 0 ||
(id_node->layers & scene->lay_updated) == 0)
@@ -472,14 +335,15 @@ void DEG_graph_on_visible_update(Main *bmain, Scene *scene)
(object->recalc & OB_RECALC_ALL) != 0)
{
id_node->tag_update(graph);
- ComponentDepsNode *anim_comp =
- id_node->find_component(DEPSNODE_TYPE_ANIMATION);
+ DEG::ComponentDepsNode *anim_comp =
+ id_node->find_component(DEG::DEPSNODE_TYPE_ANIMATION);
if (anim_comp != NULL && object->recalc & OB_RECALC_TIME) {
anim_comp->tag_update(graph);
}
}
}
}
+ GHASH_FOREACH_END();
}
scene->lay_updated |= graph->layers;
}
@@ -511,16 +375,13 @@ void DEG_ids_check_recalc(Main *bmain, Scene *scene, bool time)
ListBase *lb = lbarray[a];
ID *id = (ID *)lb->first;
- /* We tag based on first ID type character to avoid
- * looping over all ID's in case there are no tags.
- */
- if (id && bmain->id_tag_update[(unsigned char)id->name[0]]) {
+ if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) {
updated = true;
break;
}
}
- deg_editors_scene_update(bmain, scene, (updated || time));
+ DEG::deg_editors_scene_update(bmain, scene, (updated || time));
}
void DEG_ids_clear_recalc(Main *bmain)
@@ -539,10 +400,7 @@ void DEG_ids_clear_recalc(Main *bmain)
ListBase *lb = lbarray[a];
ID *id = (ID *)lb->first;
- /* We tag based on first ID type character to avoid
- * looping over all ID's in case there are no tags.
- */
- if (id && bmain->id_tag_update[(unsigned char)id->name[0]]) {
+ if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) {
for (; id; id = (ID *)id->next) {
id->tag &= ~(LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA);
diff --git a/source/blender/depsgraph/intern/depsgraph_type_defines.cc b/source/blender/depsgraph/intern/depsgraph_type_defines.cc
index 5a3048a4aa3..4ce91516c84 100644
--- a/source/blender/depsgraph/intern/depsgraph_type_defines.cc
+++ b/source/blender/depsgraph/intern/depsgraph_type_defines.cc
@@ -30,6 +30,8 @@
* Defines and code for core node types.
*/
+#include <cstdlib> // for BLI_assert()
+
extern "C" {
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -37,10 +39,13 @@ extern "C" {
#include "DEG_depsgraph.h"
} /* extern "C" */
-#include "depsgraph_intern.h"
-#include "depsnode.h"
-#include "depsnode_component.h"
-#include "depsnode_operation.h"
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+
+#include "intern/depsgraph_intern.h"
+
+namespace DEG {
/* ************ */
/* External API */
@@ -59,44 +64,110 @@ static GHash *_depsnode_typeinfo_registry = NULL;
/* Registration ------------------------------------------- */
/* Register node type */
-void DEG_register_node_typeinfo(DepsNodeFactory *factory)
+void deg_register_node_typeinfo(DepsNodeFactory *factory)
{
BLI_assert(factory != NULL);
BLI_ghash_insert(_depsnode_typeinfo_registry, SET_INT_IN_POINTER(factory->type()), factory);
}
-/* Register all node types */
-void DEG_register_node_types(void)
+/* Getters ------------------------------------------------- */
+
+/* Get typeinfo for specified type */
+DepsNodeFactory *deg_get_node_factory(const eDepsNode_Type type)
{
- /* initialise registry */
- _depsnode_typeinfo_registry = BLI_ghash_int_new("Depsgraph Node Type Registry");
+ /* look up type - at worst, it doesn't exist in table yet, and we fail */
+ return (DepsNodeFactory *)BLI_ghash_lookup(_depsnode_typeinfo_registry, SET_INT_IN_POINTER(type));
+}
- /* register node types */
- DEG_register_base_depsnodes();
- DEG_register_component_depsnodes();
- DEG_register_operation_depsnodes();
+/* Get typeinfo for provided node */
+DepsNodeFactory *deg_node_get_factory(const DepsNode *node)
+{
+ if (node != NULL) {
+ return NULL;
+ }
+ return deg_get_node_factory(node->type);
}
-/* Free registry on exit */
-void DEG_free_node_types(void)
+/* Stringified opcodes ------------------------------------- */
+
+DepsOperationStringifier DEG_OPNAMES;
+
+static const char *stringify_opcode(eDepsOperation_Code opcode)
{
- BLI_ghash_free(_depsnode_typeinfo_registry, NULL, NULL);
+ switch (opcode) {
+#define STRINGIFY_OPCODE(name) case DEG_OPCODE_##name: return #name
+ STRINGIFY_OPCODE(OPERATION);
+ STRINGIFY_OPCODE(PLACEHOLDER);
+ STRINGIFY_OPCODE(NOOP);
+ STRINGIFY_OPCODE(ANIMATION);
+ STRINGIFY_OPCODE(DRIVER);
+ //STRINGIFY_OPCODE(PROXY);
+ STRINGIFY_OPCODE(TRANSFORM_LOCAL);
+ STRINGIFY_OPCODE(TRANSFORM_PARENT);
+ STRINGIFY_OPCODE(TRANSFORM_CONSTRAINTS);
+ //STRINGIFY_OPCODE(TRANSFORM_CONSTRAINTS_INIT);
+ //STRINGIFY_OPCODE(TRANSFORM_CONSTRAINT);
+ //STRINGIFY_OPCODE(TRANSFORM_CONSTRAINTS_DONE);
+ STRINGIFY_OPCODE(RIGIDBODY_REBUILD);
+ STRINGIFY_OPCODE(RIGIDBODY_SIM);
+ STRINGIFY_OPCODE(TRANSFORM_RIGIDBODY);
+ STRINGIFY_OPCODE(TRANSFORM_FINAL);
+ STRINGIFY_OPCODE(OBJECT_UBEREVAL);
+ STRINGIFY_OPCODE(GEOMETRY_UBEREVAL);
+ STRINGIFY_OPCODE(GEOMETRY_MODIFIER);
+ STRINGIFY_OPCODE(GEOMETRY_PATH);
+ STRINGIFY_OPCODE(POSE_INIT);
+ STRINGIFY_OPCODE(POSE_DONE);
+ STRINGIFY_OPCODE(POSE_IK_SOLVER);
+ STRINGIFY_OPCODE(POSE_SPLINE_IK_SOLVER);
+ STRINGIFY_OPCODE(BONE_LOCAL);
+ STRINGIFY_OPCODE(BONE_POSE_PARENT);
+ STRINGIFY_OPCODE(BONE_CONSTRAINTS);
+ //STRINGIFY_OPCODE(BONE_CONSTRAINTS_INIT);
+ //STRINGIFY_OPCODE(BONE_CONSTRAINT);
+ //STRINGIFY_OPCODE(BONE_CONSTRAINTS_DONE);
+ STRINGIFY_OPCODE(BONE_READY);
+ STRINGIFY_OPCODE(BONE_DONE);
+ STRINGIFY_OPCODE(PSYS_EVAL);
+
+ case DEG_NUM_OPCODES: return "SpecialCase";
+#undef STRINGIFY_OPCODE
+ }
+ return "UNKNOWN";
}
-/* Getters ------------------------------------------------- */
+DepsOperationStringifier::DepsOperationStringifier()
+{
+ for (int i = 0; i < DEG_NUM_OPCODES; ++i) {
+ names_[i] = stringify_opcode((eDepsOperation_Code)i);
+ }
+}
-/* Get typeinfo for specified type */
-DepsNodeFactory *DEG_get_node_factory(const eDepsNode_Type type)
+const char *DepsOperationStringifier::operator[](eDepsOperation_Code opcode)
{
- /* look up type - at worst, it doesn't exist in table yet, and we fail */
- return (DepsNodeFactory *)BLI_ghash_lookup(_depsnode_typeinfo_registry, SET_INT_IN_POINTER(type));
+ BLI_assert((opcode > 0) && (opcode < DEG_NUM_OPCODES));
+ if (opcode >= 0 && opcode < DEG_NUM_OPCODES) {
+ return names_[opcode];
+ }
+ return "UnknownOpcode";
}
-/* Get typeinfo for provided node */
-DepsNodeFactory *DEG_node_get_factory(const DepsNode *node)
+} // namespace DEG
+
+/* Register all node types */
+void DEG_register_node_types(void)
{
- if (!node)
- return NULL;
+ /* initialise registry */
+ DEG::_depsnode_typeinfo_registry = BLI_ghash_int_new("Depsgraph Node Type Registry");
- return DEG_get_node_factory(node->type);
+ /* register node types */
+ DEG::deg_register_base_depsnodes();
+ DEG::deg_register_component_depsnodes();
+ DEG::deg_register_operation_depsnodes();
+}
+
+/* Free registry on exit */
+void DEG_free_node_types(void)
+{
+ BLI_ghash_free(DEG::_depsnode_typeinfo_registry, NULL, NULL);
}
diff --git a/source/blender/depsgraph/intern/depsgraph_types.h b/source/blender/depsgraph/intern/depsgraph_types.h
index f5fbf0bcc76..effd34a0eb9 100644
--- a/source/blender/depsgraph/intern/depsgraph_types.h
+++ b/source/blender/depsgraph/intern/depsgraph_types.h
@@ -34,10 +34,9 @@
* in the graph.
*/
-#ifndef __DEPSGRAPH_TYPES_H__
-#define __DEPSGRAPH_TYPES_H__
+#pragma once
-#include "depsgraph_util_function.h"
+#include "util/deg_util_function.h"
/* TODO(sergey): Ideally we'll just use char* and statically allocated strings
* to avoid any possible overhead caused by string (re)allocation/formatting.
@@ -55,69 +54,234 @@ struct PointerRNA;
struct EvaluationContext;
struct FCurve;
+namespace DEG {
+
/* Evaluation Operation for atomic operation */
// XXX: move this to another header that can be exposed?
typedef function<void(struct EvaluationContext *)> DepsEvalOperationCb;
-/* Metatype of Nodes - The general "level" in the graph structure the node serves */
+/* Metatype of Nodes - The general "level" in the graph structure
+ * the node serves.
+ */
typedef enum eDepsNode_Class {
- DEPSNODE_CLASS_GENERIC = 0, /* Types generally unassociated with user-visible entities, but needed for graph functioning */
-
- DEPSNODE_CLASS_COMPONENT = 1, /* [Outer Node] An "aspect" of evaluating/updating an ID-Block, requiring certain types of evaluation behaviours */
- DEPSNODE_CLASS_OPERATION = 2, /* [Inner Node] A glorified function-pointer/callback for scheduling up evaluation operations for components, subject to relationship requirements */
+ /* Types generally unassociated with user-visible entities,
+ * but needed for graph functioning.
+ */
+ DEPSNODE_CLASS_GENERIC = 0,
+ /* [Outer Node] An "aspect" of evaluating/updating an ID-Block, requiring
+ * certain types of evaluation behavior.
+ */
+ DEPSNODE_CLASS_COMPONENT = 1,
+ /* [Inner Node] A glorified function-pointer/callback for scheduling up
+ * evaluation operations for components, subject to relationship
+ * requirements.
+ */
+ DEPSNODE_CLASS_OPERATION = 2,
} eDepsNode_Class;
/* Types of Nodes */
typedef enum eDepsNode_Type {
- DEPSNODE_TYPE_UNDEFINED = -1, /* fallback type for invalid return value */
+ /* Fallback type for invalid return value */
+ DEPSNODE_TYPE_UNDEFINED = -1,
+ /* Inner Node (Operation) */
+ DEPSNODE_TYPE_OPERATION = 0,
+
+ /* **** Generic Types **** */
+
+ /* "Current Scene" - basically whatever kicks off the evaluation process. */
+ DEPSNODE_TYPE_ROOT = 1,
+ /* Time-Source */
+ DEPSNODE_TYPE_TIMESOURCE = 2,
+ /* ID-Block reference - used as landmarks/collection point for components,
+ * but not usually part of main graph.
+ */
+ DEPSNODE_TYPE_ID_REF = 3,
+ /* Isolated sub-graph - used for keeping instanced data separate from
+ * instances using them.
+ */
+ DEPSNODE_TYPE_SUBGRAPH = 4,
+
+ /* **** Outer Types **** */
+
+ /* Parameters Component - Default when nothing else fits
+ * (i.e. just SDNA property setting).
+ */
+ DEPSNODE_TYPE_PARAMETERS = 11,
+ /* Generic "Proxy-Inherit" Component
+ * XXX: Also for instancing of subgraphs?
+ */
+ DEPSNODE_TYPE_PROXY = 12,
+ /* Animation Component
+ *
+ * XXX: merge in with parameters?
+ */
+ DEPSNODE_TYPE_ANIMATION = 13,
+ /* Transform Component (Parenting/Constraints) */
+ DEPSNODE_TYPE_TRANSFORM = 14,
+ /* Geometry Component (DerivedMesh/Displist) */
+ DEPSNODE_TYPE_GEOMETRY = 15,
+ /* Sequencer Component (Scene Only) */
+ DEPSNODE_TYPE_SEQUENCER = 16,
+
+ /* **** Evaluation-Related Outer Types (with Subdata) **** */
+
+ /* Pose Component - Owner/Container of Bones Eval */
+ DEPSNODE_TYPE_EVAL_POSE = 21,
+ /* Bone Component - Child/Subcomponent of Pose */
+ DEPSNODE_TYPE_BONE = 22,
+ /* Particle Systems Component */
+ DEPSNODE_TYPE_EVAL_PARTICLES = 23,
+ /* Material Shading Component */
+ DEPSNODE_TYPE_SHADING = 24,
+ /* Cache Component */
+ DEPSNODE_TYPE_CACHE = 25,
+} eDepsNode_Type;
+
+/* Identifiers for common operations (as an enum). */
+typedef enum eDepsOperation_Code {
+ /* Generic Operations ------------------------------ */
- DEPSNODE_TYPE_OPERATION = 0, /* Inner Node (Operation) */
+ /* Placeholder for operations which don't need special mention */
+ DEG_OPCODE_OPERATION = 0,
- /* Generic Types */
- DEPSNODE_TYPE_ROOT = 1, /* "Current Scene" - basically whatever kicks off the evaluation process */
- DEPSNODE_TYPE_TIMESOURCE = 2, /* Time-Source */
+ // XXX: Placeholder while porting depsgraph code
+ DEG_OPCODE_PLACEHOLDER,
- DEPSNODE_TYPE_ID_REF = 3, /* ID-Block reference - used as landmarks/collection point for components, but not usually part of main graph */
- DEPSNODE_TYPE_SUBGRAPH = 4, /* Isolated sub-graph - used for keeping instanced data separate from instances using them */
+ DEG_OPCODE_NOOP,
- /* Outer Types */
- DEPSNODE_TYPE_PARAMETERS = 11, /* Parameters Component - Default when nothing else fits (i.e. just SDNA property setting) */
- DEPSNODE_TYPE_PROXY = 12, /* Generic "Proxy-Inherit" Component */ // XXX: Also for instancing of subgraphs?
- DEPSNODE_TYPE_ANIMATION = 13, /* Animation Component */ // XXX: merge in with parameters?
- DEPSNODE_TYPE_TRANSFORM = 14, /* Transform Component (Parenting/Constraints) */
- DEPSNODE_TYPE_GEOMETRY = 15, /* Geometry Component (DerivedMesh/Displist) */
- DEPSNODE_TYPE_SEQUENCER = 16, /* Sequencer Component (Scene Only) */
+ /* Animation, Drivers, etc. ------------------------ */
- /* Evaluation-Related Outer Types (with Subdata) */
- DEPSNODE_TYPE_EVAL_POSE = 21, /* Pose Component - Owner/Container of Bones Eval */
- DEPSNODE_TYPE_BONE = 22, /* Bone Component - Child/Subcomponent of Pose */
+ /* NLA + Action */
+ DEG_OPCODE_ANIMATION,
- DEPSNODE_TYPE_EVAL_PARTICLES = 23, /* Particle Systems Component */
- DEPSNODE_TYPE_SHADING = 24, /* Material Shading Component */
-} eDepsNode_Type;
+ /* Driver */
+ DEG_OPCODE_DRIVER,
-/* Identifiers for common operations (as an enum) */
-typedef enum eDepsOperation_Code {
-#define DEF_DEG_OPCODE(label) DEG_OPCODE_##label,
-#include "depsnode_opcodes.h"
-#undef DEF_DEG_OPCODE
+ /* Proxy Inherit? */
+ //DEG_OPCODE_PROXY,
+
+ /* Transform --------------------------------------- */
+
+ /* Transform entry point - local transforms only */
+ DEG_OPCODE_TRANSFORM_LOCAL,
+
+ /* Parenting */
+ DEG_OPCODE_TRANSFORM_PARENT,
+
+ /* Constraints */
+ DEG_OPCODE_TRANSFORM_CONSTRAINTS,
+ //DEG_OPCODE_TRANSFORM_CONSTRAINTS_INIT,
+ //DEG_OPCODE_TRANSFORM_CONSTRAINT,
+ //DEG_OPCODE_TRANSFORM_CONSTRAINTS_DONE,
+
+ /* Rigidbody Sim - Perform Sim */
+ DEG_OPCODE_RIGIDBODY_REBUILD,
+ DEG_OPCODE_RIGIDBODY_SIM,
+
+ /* Rigidbody Sim - Copy Results to Object */
+ DEG_OPCODE_TRANSFORM_RIGIDBODY,
+
+ /* Transform exitpoint */
+ DEG_OPCODE_TRANSFORM_FINAL,
+
+ /* XXX: ubereval is for temporary porting purposes only */
+ DEG_OPCODE_OBJECT_UBEREVAL,
+
+ /* Geometry ---------------------------------------- */
+
+ /* XXX: Placeholder - UberEval */
+ DEG_OPCODE_GEOMETRY_UBEREVAL,
+
+ /* Modifier */
+ DEG_OPCODE_GEOMETRY_MODIFIER,
+
+ /* Curve Objects - Path Calculation (used for path-following tools, */
+ DEG_OPCODE_GEOMETRY_PATH,
+
+ /* Pose -------------------------------------------- */
+
+ /* Init IK Trees, etc. */
+ DEG_OPCODE_POSE_INIT,
+
+ /* Free IK Trees + Compute Deform Matrices */
+ DEG_OPCODE_POSE_DONE,
+
+ /* IK/Spline Solvers */
+ DEG_OPCODE_POSE_IK_SOLVER,
+ DEG_OPCODE_POSE_SPLINE_IK_SOLVER,
+
+ /* Bone -------------------------------------------- */
+
+ /* Bone local transforms - Entrypoint */
+ DEG_OPCODE_BONE_LOCAL,
+
+ /* Pose-space conversion (includes parent + restpose, */
+ DEG_OPCODE_BONE_POSE_PARENT,
+
+ /* Constraints */
+ DEG_OPCODE_BONE_CONSTRAINTS,
+ //DEG_OPCODE_BONE_CONSTRAINTS_INIT,
+ //DEG_OPCODE_BONE_CONSTRAINT,
+ //DEG_OPCODE_BONE_CONSTRAINTS_DONE,
+
+ /* Bone transforms are ready
+ *
+ * - "READY" This (internal, noop is used to signal that all pre-IK
+ * operations are done. Its role is to help mediate situations
+ * where cyclic relations may otherwise form (i.e. one bone in
+ * chain targetting another in same chain,
+ *
+ * - "DONE" This noop is used to signal that the bone's final pose
+ * transform can be read by others
+ */
+ // TODO: deform mats could get calculated in the final_transform ops...
+ DEG_OPCODE_BONE_READY,
+ DEG_OPCODE_BONE_DONE,
+
+ /* Particles --------------------------------------- */
+
+ /* XXX: placeholder - Particle System eval */
+ DEG_OPCODE_PSYS_EVAL,
+
+ DEG_NUM_OPCODES,
} eDepsOperation_Code;
-/* String defines for these opcodes, defined in depsnode_operation.cpp */
-extern const char *DEG_OPNAMES[];
+/* Some magic to stringify operation codes. */
+class DepsOperationStringifier {
+public:
+ DepsOperationStringifier();
+ const char *operator[](eDepsOperation_Code opcodex);
+protected:
+ const char *names_[DEG_NUM_OPCODES];
+};
+/* String defines for these opcodes, defined in depsgraph_type_defines.cpp */
+extern DepsOperationStringifier DEG_OPNAMES;
/* Type of operation */
typedef enum eDepsOperation_Type {
- /* Primary operation types */
- DEPSOP_TYPE_INIT = 0, /* initialise evaluation data */
- DEPSOP_TYPE_EXEC = 1, /* standard evaluation step */
- DEPSOP_TYPE_POST = 2, /* cleanup evaluation data + flush results */
-
- /* Additional operation types */
- DEPSOP_TYPE_OUT = 3, /* indicator for outputting a temporary result that other components can use */ // XXX?
- DEPSOP_TYPE_SIM = 4, /* indicator for things like IK Solvers and Rigidbody Sim steps which modify final results of separate entities at once */
- DEPSOP_TYPE_REBUILD = 5, /* rebuild internal evaluation data - used for Rigidbody Reset and Armature Rebuild-On-Load */
+ /* **** Primary operation types **** */
+
+ /* Initialise evaluation data */
+ DEPSOP_TYPE_INIT = 0,
+ /* Standard evaluation step */
+ DEPSOP_TYPE_EXEC = 1,
+ /* Cleanup evaluation data + flush results */
+ DEPSOP_TYPE_POST = 2,
+
+ /* **** Additional operation types **** */
+ /* Indicator for outputting a temporary result that other components
+ * can use. // XXX?
+ */
+ DEPSOP_TYPE_OUT = 3,
+ /* Indicator for things like IK Solvers and Rigidbody Sim steps which
+ * modify final results of separate entities at once.
+ */
+ DEPSOP_TYPE_SIM = 4,
+ /* Rebuild internal evaluation data - used for Rigidbody Reset and
+ * Armature Rebuild-On-Load.
+ */
+ DEPSOP_TYPE_REBUILD = 5,
} eDepsOperation_Type;
/* Types of relationships between nodes
@@ -168,6 +332,9 @@ typedef enum eDepsRelation_Type {
/* relationship is used to trigger editor/screen updates */
DEPSREL_TYPE_UPDATE_UI,
+
+ /* cache dependency */
+ DEPSREL_TYPE_CACHE,
} eDepsRelation_Type;
-#endif /* __DEPSGRAPH_TYPES_H__ */
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsnode_opcodes.h b/source/blender/depsgraph/intern/depsnode_opcodes.h
deleted file mode 100644
index b81822c0ac5..00000000000
--- a/source/blender/depsgraph/intern/depsnode_opcodes.h
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2014 Blender Foundation.
- * All rights reserved.
- *
- * Original Author: Joshua Leung
- * Contributor(s): None Yet
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/depsgraph/intern/depsnode_opcodes.h
- * \ingroup depsgraph
- *
- * \par OpCodes for OperationDepsNodes
- *
- * This file defines all the "operation codes" (opcodes) used to identify
- * common operation node types. The intention of these defines is to have
- * a fast and reliable way of identifying the relevant nodes within a component
- * without having to use fragile dynamic strings.
- *
- * This file is meant to be used like UI_icons.h. That is, before including
- * the file, the host file must define the DEG_OPCODE(_label) macro, which
- * is responsible for converting the define into whatever form is suitable.
- * Therefore, it intentionally doesn't have header guards.
- */
-
-
-/* Example macro define: */
-/* #define DEF_DEG_OPCODE(label) DEG_OPCODE_##label, */
-
-/* Generic Operations ------------------------------ */
-
-/* Placeholder for operations which don't need special mention */
-DEF_DEG_OPCODE(OPERATION)
-
-// XXX: Placeholder while porting depsgraph code
-DEF_DEG_OPCODE(PLACEHOLDER)
-
-DEF_DEG_OPCODE(NOOP)
-
-/* Animation, Drivers, etc. ------------------------ */
-
-/* NLA + Action */
-DEF_DEG_OPCODE(ANIMATION)
-
-/* Driver */
-DEF_DEG_OPCODE(DRIVER)
-
-/* Proxy Inherit? */
-//DEF_DEG_OPCODE(PROXY)
-
-/* Transform --------------------------------------- */
-
-/* Transform entry point - local transforms only */
-DEF_DEG_OPCODE(TRANSFORM_LOCAL)
-
-/* Parenting */
-DEF_DEG_OPCODE(TRANSFORM_PARENT)
-
-/* Constraints */
-DEF_DEG_OPCODE(TRANSFORM_CONSTRAINTS)
-//DEF_DEG_OPCODE(TRANSFORM_CONSTRAINTS_INIT)
-//DEF_DEG_OPCODE(TRANSFORM_CONSTRAINT)
-//DEF_DEG_OPCODE(TRANSFORM_CONSTRAINTS_DONE)
-
-/* Rigidbody Sim - Perform Sim */
-DEF_DEG_OPCODE(RIGIDBODY_REBUILD)
-DEF_DEG_OPCODE(RIGIDBODY_SIM)
-
-/* Rigidbody Sim - Copy Results to Object */
-DEF_DEG_OPCODE(TRANSFORM_RIGIDBODY)
-
-/* Transform exitpoint */
-DEF_DEG_OPCODE(TRANSFORM_FINAL)
-
-/* XXX: ubereval is for temporary porting purposes only */
-DEF_DEG_OPCODE(OBJECT_UBEREVAL)
-
-/* Geometry ---------------------------------------- */
-
-/* XXX: Placeholder - UberEval */
-DEF_DEG_OPCODE(GEOMETRY_UBEREVAL)
-
-/* Modifier */
-DEF_DEG_OPCODE(GEOMETRY_MODIFIER)
-
-/* Curve Objects - Path Calculation (used for path-following tools) */
-DEF_DEG_OPCODE(GEOMETRY_PATH)
-
-/* Pose -------------------------------------------- */
-
-/* Init IK Trees, etc. */
-DEF_DEG_OPCODE(POSE_INIT)
-
-/* Free IK Trees + Compute Deform Matrices */
-DEF_DEG_OPCODE(POSE_DONE)
-
-/* IK/Spline Solvers */
-DEF_DEG_OPCODE(POSE_IK_SOLVER)
-DEF_DEG_OPCODE(POSE_SPLINE_IK_SOLVER)
-
-/* Bone -------------------------------------------- */
-
-/* Bone local transforms - Entrypoint */
-DEF_DEG_OPCODE(BONE_LOCAL)
-
-/* Pose-space conversion (includes parent + restpose) */
-DEF_DEG_OPCODE(BONE_POSE_PARENT)
-
-/* Constraints */
-DEF_DEG_OPCODE(BONE_CONSTRAINTS)
-//DEF_DEG_OPCODE(BONE_CONSTRAINTS_INIT)
-//DEF_DEG_OPCODE(BONE_CONSTRAINT)
-//DEF_DEG_OPCODE(BONE_CONSTRAINTS_DONE)
-
-/* Bone transforms are ready
- * - "READY" This (internal) noop is used to signal that all pre-IK operations are done.
- * Its role is to help mediate situations where cyclic relations may otherwise form
- * (i.e. one bone in chain targetting another in same chain)
- * - "DONE" This noop is used to signal that the bone's final pose transform can be read by others
- */
-// TODO: deform mats could get calculated in the final_transform ops...
-DEF_DEG_OPCODE(BONE_READY)
-DEF_DEG_OPCODE(BONE_DONE)
-
-/* Particles --------------------------------------- */
-
-/* XXX: placeholder - Particle System eval */
-DEF_DEG_OPCODE(PSYS_EVAL)
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc
new file mode 100644
index 00000000000..c3fd202d832
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval.cc
@@ -0,0 +1,409 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/eval/deg_eval.cc
+ * \ingroup depsgraph
+ *
+ * Evaluation engine entrypoints for Depsgraph Engine.
+ */
+
+#include "intern/eval/deg_eval.h"
+
+#include "PIL_time.h"
+
+extern "C" {
+#include "BLI_utildefines.h"
+#include "BLI_task.h"
+#include "BLI_ghash.h"
+
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+
+#include "DEG_depsgraph.h"
+} /* extern "C" */
+
+#include "atomic_ops.h"
+
+#include "intern/eval/deg_eval_debug.h"
+#include "intern/eval/deg_eval_flush.h"
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+#include "intern/depsgraph.h"
+#include "util/deg_util_foreach.h"
+
+/* Unfinished and unused, and takes quite some pre-processing time. */
+#undef USE_EVAL_PRIORITY
+
+/* Use integrated debugger to keep track how much each of the nodes was
+ * evaluating.
+ */
+#undef USE_DEBUGGER
+
+namespace DEG {
+
+/* ********************** */
+/* Evaluation Entrypoints */
+
+/* Forward declarations. */
+static void schedule_children(TaskPool *pool,
+ Depsgraph *graph,
+ OperationDepsNode *node,
+ const unsigned int layers,
+ const int thread_id);
+
+struct DepsgraphEvalState {
+ EvaluationContext *eval_ctx;
+ Depsgraph *graph;
+ unsigned int layers;
+};
+
+static void deg_task_run_func(TaskPool *pool,
+ void *taskdata,
+ int thread_id)
+{
+ DepsgraphEvalState *state =
+ reinterpret_cast<DepsgraphEvalState *>(BLI_task_pool_userdata(pool));
+ OperationDepsNode *node = reinterpret_cast<OperationDepsNode *>(taskdata);
+
+ BLI_assert(!node->is_noop() && "NOOP nodes should not actually be scheduled");
+
+ /* Should only be the case for NOOPs, which never get to this point. */
+ BLI_assert(node->evaluate);
+
+ while (true) {
+ /* Get context. */
+ /* TODO: Who initialises this? "Init" operations aren't able to
+ * initialise it!!!
+ */
+ /* TODO(sergey): We don't use component contexts at this moment. */
+ /* ComponentDepsNode *comp = node->owner; */
+ BLI_assert(node->owner != NULL);
+
+ /* Since we're not leaving the thread for until the graph branches it is
+ * possible to have NO-OP on the way. for which evaluate() will be NULL.
+ * but that's all fine, we'll just scheduler it's children.
+ */
+ if (node->evaluate) {
+ /* Take note of current time. */
+#ifdef USE_DEBUGGER
+ double start_time = PIL_check_seconds_timer();
+ DepsgraphDebug::task_started(state->graph, node);
+#endif
+
+ /* Perform operation. */
+ node->evaluate(state->eval_ctx);
+
+ /* Note how long this took. */
+#ifdef USE_DEBUGGER
+ double end_time = PIL_check_seconds_timer();
+ DepsgraphDebug::task_completed(state->graph,
+ node,
+ end_time - start_time);
+#endif
+ }
+
+ /* If there's only one outgoing link we try to immediately switch to
+ * that node evaluation, without leaving the thread.
+ *
+ * It's only doable if the child don't have extra relations or all they
+ * are satisfied.
+ *
+ * TODO(sergey): Checks here can be de-duplicated with the ones from
+ * schedule_node(), however, how to do it nicely?
+ */
+ if (node->outlinks.size() == 1) {
+ DepsRelation *rel = node->outlinks[0];
+ OperationDepsNode *child = (OperationDepsNode *)rel->to;
+ BLI_assert(child->type == DEPSNODE_TYPE_OPERATION);
+ if (!child->scheduled) {
+ unsigned int id_layers = child->owner->owner->layers;
+ if (!((child->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0 &&
+ (id_layers & state->layers) != 0))
+ {
+ /* Node does not need an update, so can;t continue with the
+ * chain and need to switch to another one by leaving the
+ * thread.
+ */
+ break;
+ }
+ if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
+ BLI_assert(child->num_links_pending > 0);
+ atomic_sub_uint32(&child->num_links_pending, 1);
+ }
+ if (child->num_links_pending == 0) {
+ bool is_scheduled = atomic_fetch_and_or_uint8(
+ (uint8_t *)&child->scheduled, (uint8_t)true);
+ if (!is_scheduled) {
+ /* Node was not scheduled, switch to it! */
+ node = child;
+ }
+ else {
+ /* Someone else scheduled the node, leaving us
+ * unemployed in this thread, we're leaving.
+ */
+ break;
+ }
+ }
+ else {
+ /* There are other dependencies on the child, can't do
+ * anything in the current thread.
+ */
+ break;
+ }
+ }
+ else {
+ /* Happens when having cyclic dependencies.
+ *
+ * Nothing to do here, single child was already scheduled, we
+ * can leave the thread now.
+ */
+ break;
+ }
+ }
+ else {
+ /* TODO(sergey): It's possible to use one of the outgoing relations
+ * as a chain which we'll try to keep alive, but it's a bit more
+ * involved change.
+ */
+ schedule_children(pool, state->graph, node, state->layers, thread_id);
+ break;
+ }
+ }
+}
+
+typedef struct CalculatePengindData {
+ Depsgraph *graph;
+ unsigned int layers;
+} CalculatePengindData;
+
+static void calculate_pending_func(void *data_v, int i)
+{
+ CalculatePengindData *data = (CalculatePengindData *)data_v;
+ Depsgraph *graph = data->graph;
+ unsigned int layers = data->layers;
+ OperationDepsNode *node = graph->operations[i];
+ IDDepsNode *id_node = node->owner->owner;
+
+ node->num_links_pending = 0;
+ node->scheduled = false;
+
+ /* count number of inputs that need updates */
+ if ((id_node->layers & layers) != 0 &&
+ (node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
+ {
+ foreach (DepsRelation *rel, node->inlinks) {
+ if (rel->from->type == DEPSNODE_TYPE_OPERATION &&
+ (rel->flag & DEPSREL_FLAG_CYCLIC) == 0)
+ {
+ OperationDepsNode *from = (OperationDepsNode *)rel->from;
+ IDDepsNode *id_from_node = from->owner->owner;
+ if ((id_from_node->layers & layers) != 0 &&
+ (from->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
+ {
+ ++node->num_links_pending;
+ }
+ }
+ }
+ }
+}
+
+static void calculate_pending_parents(Depsgraph *graph, unsigned int layers)
+{
+ const int num_operations = graph->operations.size();
+ const bool do_threads = num_operations > 256;
+ CalculatePengindData data;
+ data.graph = graph;
+ data.layers = layers;
+ BLI_task_parallel_range(0,
+ num_operations,
+ &data,
+ calculate_pending_func,
+ do_threads);
+}
+
+#ifdef USE_EVAL_PRIORITY
+static void calculate_eval_priority(OperationDepsNode *node)
+{
+ if (node->done) {
+ return;
+ }
+ node->done = 1;
+
+ if (node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
+ /* XXX standard cost of a node, could be estimated somewhat later on */
+ const float cost = 1.0f;
+ /* NOOP nodes have no cost */
+ node->eval_priority = node->is_noop() ? cost : 0.0f;
+
+ foreach (DepsRelation *rel, node->outlinks) {
+ OperationDepsNode *to = (OperationDepsNode *)rel->to;
+ BLI_assert(to->type == DEPSNODE_TYPE_OPERATION);
+ calculate_eval_priority(to);
+ node->eval_priority += to->eval_priority;
+ }
+ }
+ else {
+ node->eval_priority = 0.0f;
+ }
+}
+#endif
+
+/* Schedule a node if it needs evaluation.
+ * dec_parents: Decrement pending parents count, true when child nodes are
+ * scheduled after a task has been completed.
+ */
+static void schedule_node(TaskPool *pool, Depsgraph *graph, unsigned int layers,
+ OperationDepsNode *node, bool dec_parents,
+ const int thread_id)
+{
+ unsigned int id_layers = node->owner->owner->layers;
+
+ if ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0 &&
+ (id_layers & layers) != 0)
+ {
+ if (dec_parents) {
+ BLI_assert(node->num_links_pending > 0);
+ atomic_sub_uint32(&node->num_links_pending, 1);
+ }
+
+ if (node->num_links_pending == 0) {
+ bool is_scheduled = atomic_fetch_and_or_uint8(
+ (uint8_t *)&node->scheduled, (uint8_t)true);
+ if (!is_scheduled) {
+ if (node->is_noop()) {
+ /* skip NOOP node, schedule children right away */
+ schedule_children(pool, graph, node, layers, thread_id);
+ }
+ else {
+ /* children are scheduled once this task is completed */
+ BLI_task_pool_push_from_thread(pool,
+ deg_task_run_func,
+ node,
+ false,
+ TASK_PRIORITY_LOW,
+ thread_id);
+ }
+ }
+ }
+ }
+}
+
+static void schedule_graph(TaskPool *pool,
+ Depsgraph *graph,
+ const unsigned int layers)
+{
+ foreach (OperationDepsNode *node, graph->operations) {
+ schedule_node(pool, graph, layers, node, false, 0);
+ }
+}
+
+static void schedule_children(TaskPool *pool,
+ Depsgraph *graph,
+ OperationDepsNode *node,
+ const unsigned int layers,
+ const int thread_id)
+{
+ foreach (DepsRelation *rel, node->outlinks) {
+ OperationDepsNode *child = (OperationDepsNode *)rel->to;
+ BLI_assert(child->type == DEPSNODE_TYPE_OPERATION);
+ if (child->scheduled) {
+ /* Happens when having cyclic dependencies. */
+ continue;
+ }
+ schedule_node(pool,
+ graph,
+ layers,
+ child,
+ (rel->flag & DEPSREL_FLAG_CYCLIC) == 0,
+ thread_id);
+ }
+}
+
+/**
+ * Evaluate all nodes tagged for updating,
+ * \warning This is usually done as part of main loop, but may also be
+ * called from frame-change update.
+ *
+ * \note Time sources should be all valid!
+ */
+void deg_evaluate_on_refresh(EvaluationContext *eval_ctx,
+ Depsgraph *graph,
+ const unsigned int layers)
+{
+ /* Generate base evaluation context, upon which all the others are derived. */
+ // TODO: this needs both main and scene access...
+
+ /* Nothing to update, early out. */
+ if (BLI_gset_size(graph->entry_tags) == 0) {
+ return;
+ }
+
+ /* Set time for the current graph evaluation context. */
+ TimeSourceDepsNode *time_src = graph->find_time_source();
+ eval_ctx->ctime = time_src->cfra;
+
+ /* XXX could use a separate pool for each eval context */
+ DepsgraphEvalState state;
+ state.eval_ctx = eval_ctx;
+ state.graph = graph;
+ state.layers = layers;
+
+ TaskScheduler *task_scheduler = BLI_task_scheduler_get();
+ TaskPool *task_pool = BLI_task_pool_create(task_scheduler, &state);
+
+ if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) {
+ BLI_pool_set_num_threads(task_pool, 1);
+ }
+
+ calculate_pending_parents(graph, layers);
+
+ /* Clear tags. */
+ foreach (OperationDepsNode *node, graph->operations) {
+ node->done = 0;
+ }
+
+ /* Calculate priority for operation nodes. */
+#ifdef USE_EVAL_PRIORITY
+ foreach (OperationDepsNode *node, graph->operations) {
+ calculate_eval_priority(node);
+ }
+#endif
+
+ DepsgraphDebug::eval_begin(eval_ctx);
+
+ schedule_graph(task_pool, graph, layers);
+
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
+
+ DepsgraphDebug::eval_end(eval_ctx);
+
+ /* Clear any uncleared tags - just in case. */
+ deg_graph_clear_tags(graph);
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.h b/source/blender/depsgraph/intern/eval/deg_eval.h
new file mode 100644
index 00000000000..49c0379939e
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval.h
@@ -0,0 +1,52 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/eval/deg_eval.h
+ * \ingroup depsgraph
+ *
+ * Evaluation engine entrypoints for Depsgraph Engine.
+ */
+
+#pragma once
+
+struct EvaluationContext;
+
+namespace DEG {
+
+struct Depsgraph;
+
+/**
+ * Evaluate all nodes tagged for updating,
+ * \warning This is usually done as part of main loop, but may also be
+ * called from frame-change update.
+ *
+ * \note Time sources should be all valid!
+ */
+void deg_evaluate_on_refresh(EvaluationContext *eval_ctx,
+ Depsgraph *graph,
+ const unsigned int layers);
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_debug.cc b/source/blender/depsgraph/intern/eval/deg_eval_debug.cc
new file mode 100644
index 00000000000..67d64aae8bf
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_debug.cc
@@ -0,0 +1,249 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Lukas Toenne
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/eval/deg_eval_debug.cc
+ * \ingroup depsgraph
+ *
+ * Implementation of tools for debugging the depsgraph
+ */
+
+#include <cstring>
+
+#include "intern/eval/deg_eval_debug.h"
+
+extern "C" {
+#include "BLI_listbase.h"
+#include "BLI_ghash.h"
+
+#include "DEG_depsgraph_debug.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+} /* extern "C" */
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+#include "intern/depsgraph_intern.h"
+
+namespace DEG {
+
+DepsgraphStats *DepsgraphDebug::stats = NULL;
+
+static string get_component_name(eDepsNode_Type type, const string &name = "")
+{
+ DepsNodeFactory *factory = deg_get_node_factory(type);
+ if (name.empty()) {
+ return string(factory->tname());
+ }
+ else {
+ return string(factory->tname()) + " | " + name;
+ }
+}
+
+static void times_clear(DepsgraphStatsTimes &times)
+{
+ times.duration_last = 0.0f;
+}
+
+static void times_add(DepsgraphStatsTimes &times, float time)
+{
+ times.duration_last += time;
+}
+
+void DepsgraphDebug::eval_begin(const EvaluationContext *UNUSED(eval_ctx))
+{
+ /* TODO(sergey): Stats are currently globally disabled. */
+ /* verify_stats(); */
+ reset_stats();
+}
+
+void DepsgraphDebug::eval_end(const EvaluationContext *UNUSED(eval_ctx))
+{
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
+}
+
+void DepsgraphDebug::eval_step(const EvaluationContext *UNUSED(eval_ctx),
+ const char *message)
+{
+#ifdef DEG_DEBUG_BUILD
+ if (deg_debug_eval_cb)
+ deg_debug_eval_cb(deg_debug_eval_userdata, message);
+#else
+ (void)message; /* Ignored. */
+#endif
+}
+
+void DepsgraphDebug::task_started(Depsgraph *graph,
+ const OperationDepsNode *node)
+{
+ if (stats) {
+ BLI_spin_lock(&graph->lock);
+
+ ComponentDepsNode *comp = node->owner;
+ ID *id = comp->owner->id;
+
+ DepsgraphStatsID *id_stats = get_id_stats(id, true);
+ times_clear(id_stats->times);
+
+ /* XXX TODO use something like: if (id->flag & ID_DEG_DETAILS) {...} */
+ if (0) {
+ /* XXX component name usage needs cleanup! currently mixes identifier
+ * and description strings!
+ */
+ DepsgraphStatsComponent *comp_stats =
+ get_component_stats(id, get_component_name(comp->type,
+ comp->name),
+ true);
+ times_clear(comp_stats->times);
+ }
+
+ BLI_spin_unlock(&graph->lock);
+ }
+}
+
+void DepsgraphDebug::task_completed(Depsgraph *graph,
+ const OperationDepsNode *node,
+ double time)
+{
+ if (stats) {
+ BLI_spin_lock(&graph->lock);
+
+ ComponentDepsNode *comp = node->owner;
+ ID *id = comp->owner->id;
+
+ DepsgraphStatsID *id_stats = get_id_stats(id, true);
+ times_add(id_stats->times, time);
+
+ /* XXX TODO use something like: if (id->flag & ID_DEG_DETAILS) {...} */
+ if (0) {
+ /* XXX component name usage needs cleanup! currently mixes identifier
+ * and description strings!
+ */
+ DepsgraphStatsComponent *comp_stats =
+ get_component_stats(id,
+ get_component_name(comp->type,
+ comp->name),
+ true);
+ times_add(comp_stats->times, time);
+ }
+
+ BLI_spin_unlock(&graph->lock);
+ }
+}
+
+/* ********** */
+/* Statistics */
+
+
+/* GHash callback */
+static void deg_id_stats_free(void *val)
+{
+ DepsgraphStatsID *id_stats = (DepsgraphStatsID *)val;
+
+ if (id_stats) {
+ BLI_freelistN(&id_stats->components);
+ MEM_freeN(id_stats);
+ }
+}
+
+void DepsgraphDebug::stats_init()
+{
+ if (!stats) {
+ stats = (DepsgraphStats *)MEM_callocN(sizeof(DepsgraphStats),
+ "Depsgraph Stats");
+ stats->id_stats = BLI_ghash_new(BLI_ghashutil_ptrhash,
+ BLI_ghashutil_ptrcmp,
+ "Depsgraph ID Stats Hash");
+ }
+}
+
+void DepsgraphDebug::stats_free()
+{
+ if (stats) {
+ BLI_ghash_free(stats->id_stats, NULL, deg_id_stats_free);
+ MEM_freeN(stats);
+ stats = NULL;
+ }
+}
+
+void DepsgraphDebug::verify_stats()
+{
+ stats_init();
+}
+
+void DepsgraphDebug::reset_stats()
+{
+ if (!stats) {
+ return;
+ }
+
+ /* XXX this doesn't work, will immediately clear all info,
+ * since most depsgraph updates have none or very few updates to handle.
+ *
+ * Could consider clearing only zero-user ID blocks here
+ */
+// BLI_ghash_clear(stats->id_stats, NULL, deg_id_stats_free);
+}
+
+DepsgraphStatsID *DepsgraphDebug::get_id_stats(ID *id, bool create)
+{
+ DepsgraphStatsID *id_stats = (DepsgraphStatsID *)BLI_ghash_lookup(stats->id_stats, id);
+
+ if (!id_stats && create) {
+ id_stats = (DepsgraphStatsID *)MEM_callocN(sizeof(DepsgraphStatsID),
+ "Depsgraph ID Stats");
+ id_stats->id = id;
+
+ BLI_ghash_insert(stats->id_stats, id, id_stats);
+ }
+
+ return id_stats;
+}
+
+DepsgraphStatsComponent *DepsgraphDebug::get_component_stats(
+ DepsgraphStatsID *id_stats,
+ const string &name,
+ bool create)
+{
+ DepsgraphStatsComponent *comp_stats;
+ for (comp_stats = (DepsgraphStatsComponent *)id_stats->components.first;
+ comp_stats != NULL;
+ comp_stats = comp_stats->next)
+ {
+ if (STREQ(comp_stats->name, name.c_str()))
+ break;
+ }
+ if (!comp_stats && create) {
+ comp_stats = (DepsgraphStatsComponent *)MEM_callocN(sizeof(DepsgraphStatsComponent),
+ "Depsgraph Component Stats");
+ BLI_strncpy(comp_stats->name, name.c_str(), sizeof(comp_stats->name));
+ BLI_addtail(&id_stats->components, comp_stats);
+ }
+ return comp_stats;
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_debug.h b/source/blender/depsgraph/intern/eval/deg_eval_debug.h
index 64b97855f57..9109019eb2d 100644
--- a/source/blender/depsgraph/intern/depsgraph_debug.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_debug.h
@@ -24,27 +24,26 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/depsgraph_debug.h
+/** \file blender/depsgraph/intern/eval/deg_eval_debug.h
* \ingroup depsgraph
*/
-#ifndef __DEPSGRAPH_DEBUG_H__
-#define __DEPSGRAPH_DEBUG_H__
+#pragma once
-#include "depsgraph_types.h"
+#include "intern/depsgraph_types.h"
-extern "C" {
-#include "BKE_global.h"
-}
+struct ID;
+struct EvaluationContext;
struct DepsgraphStats;
struct DepsgraphStatsID;
struct DepsgraphStatsComponent;
-struct DepsgraphSettings;
-struct EvaluationContext;
-struct OperationDepsNode;
+
+namespace DEG {
struct Depsgraph;
+struct DepsgraphSettings;
+struct OperationDepsNode;
struct DepsgraphDebug {
static DepsgraphStats *stats;
@@ -77,11 +76,4 @@ struct DepsgraphDebug {
}
};
-#define DEG_DEBUG_PRINTF(...) \
- { \
- if (G.debug & G_DEBUG_DEPSGRAPH) { \
- fprintf(stderr, __VA_ARGS__); \
- } \
- } \
-
-#endif /* __DEPSGRAPH_DEBUG_H__ */
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
new file mode 100644
index 00000000000..7c6c25bef0d
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
@@ -0,0 +1,227 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/eval/deg_eval_flush.cc
+ * \ingroup depsgraph
+ *
+ * Core routines for how the Depsgraph works.
+ */
+
+#include "intern/eval/deg_eval_flush.h"
+
+// TODO(sergey): Use some sort of wrapper.
+#include <deque>
+
+extern "C" {
+#include "DNA_object_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_task.h"
+#include "BLI_ghash.h"
+
+#include "DEG_depsgraph.h"
+} /* extern "C" */
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+
+#include "intern/depsgraph_intern.h"
+#include "util/deg_util_foreach.h"
+
+namespace DEG {
+
+namespace {
+
+// TODO(sergey): De-duplicate with depsgraph_tag,cc
+void lib_id_recalc_tag(Main *bmain, ID *id)
+{
+ id->tag |= LIB_TAG_ID_RECALC;
+ DEG_id_type_tag(bmain, GS(id->name));
+}
+
+void lib_id_recalc_data_tag(Main *bmain, ID *id)
+{
+ id->tag |= LIB_TAG_ID_RECALC_DATA;
+ DEG_id_type_tag(bmain, GS(id->name));
+}
+
+} /* namespace */
+
+typedef std::deque<OperationDepsNode *> FlushQueue;
+
+static void flush_init_func(void *data_v, int i)
+{
+ /* ID node's done flag is used to avoid multiple editors update
+ * for the same ID.
+ */
+ Depsgraph *graph = (Depsgraph *)data_v;
+ OperationDepsNode *node = graph->operations[i];
+ ComponentDepsNode *comp_node = node->owner;
+ IDDepsNode *id_node = comp_node->owner;
+ id_node->done = 0;
+ comp_node->done = 0;
+ node->scheduled = false;
+}
+
+/* Flush updates from tagged nodes outwards until all affected nodes
+ * are tagged.
+ */
+void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
+{
+ /* Sanity check. */
+ if (graph == NULL) {
+ return;
+ }
+
+ /* Nothing to update, early out. */
+ if (BLI_gset_size(graph->entry_tags) == 0) {
+ return;
+ }
+
+ /* TODO(sergey): With a bit of flag magic we can get rid of this
+ * extra loop.
+ */
+ const int num_operations = graph->operations.size();
+ const bool do_threads = num_operations > 256;
+ BLI_task_parallel_range(0,
+ num_operations,
+ graph,
+ flush_init_func,
+ do_threads);
+
+ FlushQueue queue;
+ /* Starting from the tagged "entry" nodes, flush outwards... */
+ /* NOTE: Also need to ensure that for each of these, there is a path back to
+ * root, or else they won't be done.
+ * NOTE: Count how many nodes we need to handle - entry nodes may be
+ * component nodes which don't count for this purpose!
+ */
+ GSET_FOREACH_BEGIN(OperationDepsNode *, node, graph->entry_tags)
+ {
+ queue.push_back(node);
+ node->scheduled = true;
+ }
+ GSET_FOREACH_END();
+
+ int num_flushed_objects = 0;
+ while (!queue.empty()) {
+ OperationDepsNode *node = queue.front();
+ queue.pop_front();
+
+ for (;;) {
+ node->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
+
+ ComponentDepsNode *comp_node = node->owner;
+ IDDepsNode *id_node = comp_node->owner;
+
+ ID *id = id_node->id;
+ if(id_node->done == 0) {
+ deg_editors_id_update(bmain, id);
+ lib_id_recalc_tag(bmain, id);
+ /* TODO(sergey): For until we've got proper data nodes in the graph. */
+ lib_id_recalc_data_tag(bmain, id);
+ }
+
+ if(comp_node->done == 0) {
+ Object *object = NULL;
+ if (GS(id->name) == ID_OB) {
+ object = (Object *)id;
+ if(id_node->done == 0) {
+ ++num_flushed_objects;
+ }
+ }
+ foreach (OperationDepsNode *op, comp_node->operations) {
+ op->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
+ }
+ if (object != NULL) {
+ /* This code is used to preserve those areas which does
+ * direct object update,
+ *
+ * Plus it ensures visibility changes and relations and
+ * layers visibility update has proper flags to work with.
+ */
+ if (comp_node->type == DEPSNODE_TYPE_ANIMATION) {
+ object->recalc |= OB_RECALC_TIME;
+ }
+ else if (comp_node->type == DEPSNODE_TYPE_TRANSFORM) {
+ object->recalc |= OB_RECALC_OB;
+ }
+ else {
+ object->recalc |= OB_RECALC_DATA;
+ }
+ }
+ }
+
+ id_node->done = 1;
+ comp_node->done = 1;
+
+ /* Flush to nodes along links... */
+ if (node->outlinks.size() == 1) {
+ OperationDepsNode *to_node = (OperationDepsNode *)node->outlinks[0]->to;
+ if (to_node->scheduled == false) {
+ to_node->scheduled = true;
+ node = to_node;
+ }
+ else {
+ break;
+ }
+ }
+ else {
+ foreach (DepsRelation *rel, node->outlinks) {
+ OperationDepsNode *to_node = (OperationDepsNode *)rel->to;
+ if (to_node->scheduled == false) {
+ queue.push_front(to_node);
+ to_node->scheduled = true;
+ }
+ }
+ break;
+ }
+ }
+ }
+ DEG_DEBUG_PRINTF("Update flushed to %d objects\n", num_flushed_objects);
+}
+
+static void graph_clear_func(void *data_v, int i)
+{
+ Depsgraph *graph = (Depsgraph *)data_v;
+ OperationDepsNode *node = graph->operations[i];
+ /* Clear node's "pending update" settings. */
+ node->flag &= ~(DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE);
+}
+
+/* Clear tags from all operation nodes. */
+void deg_graph_clear_tags(Depsgraph *graph)
+{
+ /* Go over all operation nodes, clearing tags. */
+ const int num_operations = graph->operations.size();
+ const bool do_threads = num_operations > 256;
+ BLI_task_parallel_range(0, num_operations, graph, graph_clear_func, do_threads);
+ /* Clear any entry tags which haven't been flushed. */
+ BLI_gset_clear(graph->entry_tags, NULL);
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.h b/source/blender/depsgraph/intern/eval/deg_eval_flush.h
new file mode 100644
index 00000000000..ecd3a5ec660
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.h
@@ -0,0 +1,49 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/eval/deg_eval_flush.h
+ * \ingroup depsgraph
+ *
+ * Core routines for how the Depsgraph works.
+ */
+
+#pragma once
+
+struct Main;
+
+namespace DEG {
+
+struct Depsgraph;
+
+/* Flush updates from tagged nodes outwards until all affected nodes
+ * are tagged.
+ */
+void deg_graph_flush_updates(struct Main *bmain, struct Depsgraph *graph);
+
+/* Clear tags from all operation nodes. */
+void deg_graph_clear_tags(struct Depsgraph *graph);
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsnode.cc b/source/blender/depsgraph/intern/nodes/deg_node.cc
index 8aa1059d2dc..eb408f293de 100644
--- a/source/blender/depsgraph/intern/depsnode.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node.cc
@@ -24,14 +24,17 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/depsnode.cc
+/** \file blender/depsgraph/intern/nodes/deg_node.cc
* \ingroup depsgraph
*/
+#include "intern/nodes/deg_node.h"
+
#include <stdio.h>
#include <string.h>
#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
extern "C" {
#include "DNA_ID.h"
@@ -42,10 +45,13 @@ extern "C" {
#include "DEG_depsgraph.h"
}
-#include "depsnode.h" /* own include */
-#include "depsnode_component.h"
-#include "depsnode_operation.h"
-#include "depsgraph_intern.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+#include "intern/depsgraph_intern.h"
+#include "util/deg_util_foreach.h"
+#include "util/deg_util_hash.h"
+
+namespace DEG {
/* *************** */
/* Node Management */
@@ -66,7 +72,7 @@ DepsNode::TypeInfo::TypeInfo(eDepsNode_Type type, const char *tname)
DepsNode::DepsNode()
{
- this->name[0] = '\0';
+ name[0] = '\0';
}
DepsNode::~DepsNode()
@@ -76,11 +82,9 @@ DepsNode::~DepsNode()
* when we're trying to free same link from both it's sides. We don't have
* dangling links so this is not a problem from memory leaks point of view.
*/
- DEPSNODE_RELATIONS_ITER_BEGIN(this->inlinks, rel)
- {
+ foreach (DepsRelation *rel, inlinks) {
OBJECT_GUARDED_DELETE(rel, DepsRelation);
}
- DEPSNODE_RELATIONS_ITER_END;
}
@@ -100,11 +104,7 @@ string DepsNode::identifier() const
void TimeSourceDepsNode::tag_update(Depsgraph *graph)
{
- for (DepsNode::Relations::const_iterator it = outlinks.begin();
- it != outlinks.end();
- ++it)
- {
- DepsRelation *rel = *it;
+ foreach (DepsRelation *rel, outlinks) {
DepsNode *node = rel->to;
node->tag_update(graph);
}
@@ -125,7 +125,7 @@ RootDepsNode::~RootDepsNode()
TimeSourceDepsNode *RootDepsNode::add_time_source(const string &name)
{
if (!time_source) {
- DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_TIMESOURCE);
+ DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_TIMESOURCE);
time_source = (TimeSourceDepsNode *)factory->create_node(NULL, "", name);
/*time_source->owner = this;*/ // XXX
}
@@ -142,6 +142,36 @@ static DepsNodeFactoryImpl<TimeSourceDepsNode> DNTI_TIMESOURCE;
/* ID Node ================================================ */
+static unsigned int id_deps_node_hash_key(const void *key_v)
+{
+ const IDDepsNode::ComponentIDKey *key =
+ reinterpret_cast<const IDDepsNode::ComponentIDKey *>(key_v);
+ return hash_combine(BLI_ghashutil_uinthash(key->type),
+ BLI_ghashutil_strhash_p(key->name.c_str()));
+}
+
+static bool id_deps_node_hash_key_cmp(const void *a, const void *b)
+{
+ const IDDepsNode::ComponentIDKey *key_a =
+ reinterpret_cast<const IDDepsNode::ComponentIDKey *>(a);
+ const IDDepsNode::ComponentIDKey *key_b =
+ reinterpret_cast<const IDDepsNode::ComponentIDKey *>(b);
+ return !(*key_a == *key_b);
+}
+
+static void id_deps_node_hash_key_free(void *key_v)
+{
+ typedef IDDepsNode::ComponentIDKey ComponentIDKey;
+ ComponentIDKey *key = reinterpret_cast<ComponentIDKey *>(key_v);
+ OBJECT_GUARDED_DELETE(key, ComponentIDKey);
+}
+
+static void id_deps_node_hash_value_free(void *value_v)
+{
+ ComponentDepsNode *comp_node = reinterpret_cast<ComponentDepsNode *>(value_v);
+ OBJECT_GUARDED_DELETE(comp_node, ComponentDepsNode);
+}
+
/* Initialize 'id' node - from pointer data given. */
void IDDepsNode::init(const ID *id, const string &UNUSED(subdata))
{
@@ -151,6 +181,15 @@ void IDDepsNode::init(const ID *id, const string &UNUSED(subdata))
this->layers = (1 << 20) - 1;
this->eval_flags = 0;
+ /* For object we initialize layers to layer from base. */
+ if (GS(id->name) == ID_OB) {
+ this->layers = 0;
+ }
+
+ components = BLI_ghash_new(id_deps_node_hash_key,
+ id_deps_node_hash_key_cmp,
+ "Depsgraph id components hash");
+
/* NOTE: components themselves are created if/when needed.
* This prevents problems with components getting added
* twice if an ID-Ref needs to be created to house it...
@@ -161,51 +200,27 @@ void IDDepsNode::init(const ID *id, const string &UNUSED(subdata))
IDDepsNode::~IDDepsNode()
{
clear_components();
-}
-
-/* Copy 'id' node. */
-void IDDepsNode::copy(DepsgraphCopyContext *dcc, const IDDepsNode *src)
-{
- (void)src; /* Ignored. */
- /* Iterate over items in original hash, adding them to new hash. */
- for (IDDepsNode::ComponentMap::const_iterator it = this->components.begin();
- it != this->components.end();
- ++it)
- {
- /* Get current <type : component> mapping. */
- ComponentIDKey c_key = it->first;
- DepsNode *old_component = it->second;
-
- /* Make a copy of component. */
- ComponentDepsNode *component = (ComponentDepsNode *)DEG_copy_node(dcc, old_component);
-
- /* Add new node to hash... */
- this->components[c_key] = component;
- }
-
- // TODO: perform a second loop to fix up links?
- BLI_assert(!"Not expected to be used");
+ BLI_ghash_free(components, id_deps_node_hash_key_free, NULL);
}
ComponentDepsNode *IDDepsNode::find_component(eDepsNode_Type type,
const string &name) const
{
ComponentIDKey key(type, name);
- ComponentMap::const_iterator it = components.find(key);
- return it != components.end() ? it->second : NULL;
+ return reinterpret_cast<ComponentDepsNode *>(BLI_ghash_lookup(components, &key));
}
ComponentDepsNode *IDDepsNode::add_component(eDepsNode_Type type,
const string &name)
{
- ComponentIDKey key(type, name);
ComponentDepsNode *comp_node = find_component(type, name);
if (!comp_node) {
- DepsNodeFactory *factory = DEG_get_node_factory(type);
+ DepsNodeFactory *factory = deg_get_node_factory(type);
comp_node = (ComponentDepsNode *)factory->create_node(this->id, "", name);
/* Register. */
- this->components[key] = comp_node;
+ ComponentIDKey *key = OBJECT_GUARDED_NEW(ComponentIDKey, type, name);
+ BLI_ghash_insert(components, key, comp_node);
comp_node->owner = this;
}
return comp_node;
@@ -213,34 +228,28 @@ ComponentDepsNode *IDDepsNode::add_component(eDepsNode_Type type,
void IDDepsNode::remove_component(eDepsNode_Type type, const string &name)
{
- ComponentIDKey key(type, name);
ComponentDepsNode *comp_node = find_component(type, name);
if (comp_node) {
/* Unregister. */
- this->components.erase(key);
- OBJECT_GUARDED_DELETE(comp_node, ComponentDepsNode);
+ ComponentIDKey key(type, name);
+ BLI_ghash_remove(components,
+ &key,
+ id_deps_node_hash_key_free,
+ id_deps_node_hash_value_free);
}
}
void IDDepsNode::clear_components()
{
- for (ComponentMap::const_iterator it = components.begin();
- it != components.end();
- ++it)
- {
- ComponentDepsNode *comp_node = it->second;
- OBJECT_GUARDED_DELETE(comp_node, ComponentDepsNode);
- }
- components.clear();
+ BLI_ghash_clear(components,
+ id_deps_node_hash_key_free,
+ id_deps_node_hash_value_free);
}
void IDDepsNode::tag_update(Depsgraph *graph)
{
- for (ComponentMap::const_iterator it = components.begin();
- it != components.end();
- ++it)
+ GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, components)
{
- ComponentDepsNode *comp_node = it->second;
/* TODO(sergey): What about drievrs? */
bool do_component_tag = comp_node->type != DEPSNODE_TYPE_ANIMATION;
if (comp_node->type == DEPSNODE_TYPE_ANIMATION) {
@@ -254,6 +263,16 @@ void IDDepsNode::tag_update(Depsgraph *graph)
comp_node->tag_update(graph);
}
}
+ GHASH_FOREACH_END();
+}
+
+void IDDepsNode::finalize_build()
+{
+ GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, components)
+ {
+ comp_node->finalize_build();
+ }
+ GHASH_FOREACH_END();
}
DEG_DEPSNODE_DEFINE(IDDepsNode, DEPSNODE_TYPE_ID_REF, "ID Node");
@@ -281,31 +300,21 @@ SubgraphDepsNode::~SubgraphDepsNode()
// XXX: prune these flags a bit...
if ((this->flag & SUBGRAPH_FLAG_FIRSTREF) || !(this->flag & SUBGRAPH_FLAG_SHARED)) {
/* Free the referenced graph. */
- DEG_graph_free(this->graph);
- this->graph = NULL;
+ DEG_graph_free(reinterpret_cast< ::Depsgraph* >(graph));
+ graph = NULL;
}
}
-/* Copy 'subgraph' node - Assume that the subgraph doesn't get copied for now... */
-void SubgraphDepsNode::copy(DepsgraphCopyContext * /*dcc*/,
- const SubgraphDepsNode * /*src*/)
-{
- //const SubgraphDepsNode *src_node = (const SubgraphDepsNode *)src;
- //SubgraphDepsNode *dst_node = (SubgraphDepsNode *)dst;
-
- /* for now, subgraph itself isn't copied... */
- BLI_assert(!"Not expected to be used");
-}
-
DEG_DEPSNODE_DEFINE(SubgraphDepsNode, DEPSNODE_TYPE_SUBGRAPH, "Subgraph Node");
static DepsNodeFactoryImpl<SubgraphDepsNode> DNTI_SUBGRAPH;
-
-void DEG_register_base_depsnodes()
+void deg_register_base_depsnodes()
{
- DEG_register_node_typeinfo(&DNTI_ROOT);
- DEG_register_node_typeinfo(&DNTI_TIMESOURCE);
+ deg_register_node_typeinfo(&DNTI_ROOT);
+ deg_register_node_typeinfo(&DNTI_TIMESOURCE);
- DEG_register_node_typeinfo(&DNTI_ID_REF);
- DEG_register_node_typeinfo(&DNTI_SUBGRAPH);
+ deg_register_node_typeinfo(&DNTI_ID_REF);
+ deg_register_node_typeinfo(&DNTI_SUBGRAPH);
}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsnode.h b/source/blender/depsgraph/intern/nodes/deg_node.h
index 4a464955384..b2262c4bd12 100644
--- a/source/blender/depsgraph/intern/depsnode.h
+++ b/source/blender/depsgraph/intern/nodes/deg_node.h
@@ -24,25 +24,22 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/depsnode.h
+/** \file depsgraph/intern/nodes/deg_node.h
* \ingroup depsgraph
*/
-#ifndef __DEPSNODE_H__
-#define __DEPSNODE_H__
+#pragma once
-#include "depsgraph_types.h"
-
-#include "depsgraph_util_hash.h"
-#include "depsgraph_util_map.h"
-#include "depsgraph_util_set.h"
+#include "intern/depsgraph_types.h"
struct ID;
+struct GHash;
struct Scene;
+namespace DEG {
+
struct Depsgraph;
struct DepsRelation;
-struct DepsgraphCopyContext;
struct OperationDepsNode;
/* *********************************** */
@@ -94,8 +91,6 @@ struct DepsNode {
virtual void init(const ID * /*id*/,
const string &/*subdata*/) {}
- virtual void copy(DepsgraphCopyContext * /*dcc*/,
- const DepsNode * /*src*/) {}
virtual void tag_update(Depsgraph * /*graph*/) {}
@@ -160,24 +155,7 @@ struct IDDepsNode : public DepsNode {
string name;
};
- /* XXX can't specialize std::hash for this purpose, because ComponentIDKey is
- * a nested type ...
- *
- * http://stackoverflow.com/a/951245
- */
- struct component_key_hash {
- bool operator() (const ComponentIDKey &key) const
- {
- return hash_combine(hash<int>()(key.type), hash<string>()(key.name));
- }
- };
-
- typedef unordered_map<ComponentIDKey,
- ComponentDepsNode *,
- component_key_hash> ComponentMap;
-
void init(const ID *id, const string &subdata);
- void copy(DepsgraphCopyContext *dcc, const IDDepsNode *src);
~IDDepsNode();
ComponentDepsNode *find_component(eDepsNode_Type type,
@@ -189,14 +167,16 @@ struct IDDepsNode : public DepsNode {
void tag_update(Depsgraph *graph);
+ void finalize_build();
+
/* ID Block referenced. */
ID *id;
/* Hash to make it faster to look up components. */
- ComponentMap components;
+ GHash *components;
/* Layers of this node with accumulated layers of it's output relations. */
- int layers;
+ unsigned int layers;
/* Additional flags needed for scene evaluation.
* TODO(sergey): Only needed for until really granular updates
@@ -210,7 +190,6 @@ struct IDDepsNode : public DepsNode {
/* Subgraph Reference. */
struct SubgraphDepsNode : public DepsNode {
void init(const ID *id, const string &subdata);
- void copy(DepsgraphCopyContext *dcc, const SubgraphDepsNode *src);
~SubgraphDepsNode();
/* Instanced graph. */
@@ -243,6 +222,6 @@ typedef enum eSubgraphRef_Flag {
SUBGRAPH_FLAG_FIRSTREF = (1 << 1),
} eSubgraphRef_Flag;
-void DEG_register_base_depsnodes();
+void deg_register_base_depsnodes();
-#endif /* __DEPSNODE_H__ */
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsnode_component.cc b/source/blender/depsgraph/intern/nodes/deg_node_component.cc
index a47a0d29228..01f33b6368b 100644
--- a/source/blender/depsgraph/intern/depsnode_component.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node_component.cc
@@ -24,10 +24,12 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/depsnode_component.cc
+/** \file blender/depsgraph/intern/nodes/deg_node_component.cc
* \ingroup depsgraph
*/
+#include "intern/nodes/deg_node_component.h"
+
#include <stdio.h>
#include <string.h>
@@ -39,20 +41,56 @@ extern "C" {
#include "BKE_action.h"
} /* extern "C" */
-#include "depsnode_component.h" /* own include */
-#include "depsnode_operation.h"
-#include "depsgraph_intern.h"
+#include "intern/nodes/deg_node_operation.h"
+#include "intern/depsgraph_intern.h"
+#include "util/deg_util_foreach.h"
+#include "util/deg_util_hash.h"
+
+namespace DEG {
/* *********** */
/* Outer Nodes */
/* Standard Component Methods ============================= */
+static unsigned int comp_node_hash_key(const void *key_v)
+{
+ const ComponentDepsNode::OperationIDKey *key =
+ reinterpret_cast<const ComponentDepsNode::OperationIDKey *>(key_v);
+ return hash_combine(BLI_ghashutil_uinthash(key->opcode),
+ BLI_ghashutil_strhash_p(key->name.c_str()));
+}
+
+static bool comp_node_hash_key_cmp(const void *a, const void *b)
+{
+ const ComponentDepsNode::OperationIDKey *key_a =
+ reinterpret_cast<const ComponentDepsNode::OperationIDKey *>(a);
+ const ComponentDepsNode::OperationIDKey *key_b =
+ reinterpret_cast<const ComponentDepsNode::OperationIDKey *>(b);
+ return !(*key_a == *key_b);
+}
+
+static void comp_node_hash_key_free(void *key_v)
+{
+ typedef ComponentDepsNode::OperationIDKey OperationIDKey;
+ OperationIDKey *key = reinterpret_cast<OperationIDKey *>(key_v);
+ OBJECT_GUARDED_DELETE(key, OperationIDKey);
+}
+
+static void comp_node_hash_value_free(void *value_v)
+{
+ OperationDepsNode *op_node = reinterpret_cast<OperationDepsNode *>(value_v);
+ OBJECT_GUARDED_DELETE(op_node, OperationDepsNode);
+}
+
ComponentDepsNode::ComponentDepsNode() :
entry_operation(NULL),
exit_operation(NULL),
- flags(0)
+ layers(0)
{
+ operations_map = BLI_ghash_new(comp_node_hash_key,
+ comp_node_hash_key_cmp,
+ "Depsgraph id hash");
}
/* Initialize 'component' node - from pointer data given */
@@ -63,55 +101,35 @@ void ComponentDepsNode::init(const ID * /*id*/,
// XXX: maybe this needs a special API?
}
-/* Copy 'component' node */
-void ComponentDepsNode::copy(DepsgraphCopyContext * /*dcc*/,
- const ComponentDepsNode * /*src*/)
-{
-#if 0 // XXX: remove all this
- /* duplicate list of operation nodes */
- this->operations.clear();
-
- for (OperationMap::const_iterator it = src->operations.begin(); it != src->operations.end(); ++it) {
- const string &pchan_name = it->first;
- OperationDepsNode *src_op = it->second;
-
- /* recursive copy */
- DepsNodeFactory *factory = DEG_node_get_factory(src_op);
- OperationDepsNode *dst_op = (OperationDepsNode *)factory->copy_node(dcc, src_op);
- this->operations[pchan_name] = dst_op;
-
- /* fix links... */
- // ...
- }
-
- /* copy evaluation contexts */
- //
-#endif
- BLI_assert(!"Not expected to be called");
-}
-
/* Free 'component' node */
ComponentDepsNode::~ComponentDepsNode()
{
clear_operations();
+ if (operations_map != NULL) {
+ BLI_ghash_free(operations_map,
+ comp_node_hash_key_free,
+ comp_node_hash_value_free);
+ }
}
string ComponentDepsNode::identifier() const
{
string &idname = this->owner->name;
- char typebuf[7];
+ char typebuf[16];
sprintf(typebuf, "(%d)", type);
- return string(typebuf) + name + " : " + idname;
+ char layers[16];
+ sprintf(layers, "%u", this->layers);
+
+ return string(typebuf) + name + " : " + idname + " (Layers: " + layers + ")";
}
OperationDepsNode *ComponentDepsNode::find_operation(OperationIDKey key) const
{
- OperationMap::const_iterator it = this->operations.find(key);
-
- if (it != this->operations.end()) {
- return it->second;
+ OperationDepsNode *node = reinterpret_cast<OperationDepsNode *>(BLI_ghash_lookup(operations_map, &key));
+ if (node != NULL) {
+ return node;
}
else {
fprintf(stderr, "%s: find_operation(%s) failed\n",
@@ -129,11 +147,7 @@ OperationDepsNode *ComponentDepsNode::find_operation(eDepsOperation_Code opcode,
OperationDepsNode *ComponentDepsNode::has_operation(OperationIDKey key) const
{
- OperationMap::const_iterator it = this->operations.find(key);
- if (it != this->operations.end()) {
- return it->second;
- }
- return NULL;
+ return reinterpret_cast<OperationDepsNode *>(BLI_ghash_lookup(operations_map, &key));
}
OperationDepsNode *ComponentDepsNode::has_operation(eDepsOperation_Code opcode,
@@ -147,12 +161,12 @@ OperationDepsNode *ComponentDepsNode::add_operation(eDepsOperation_Type optype,
{
OperationDepsNode *op_node = has_operation(opcode, name);
if (!op_node) {
- DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_OPERATION);
+ DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_OPERATION);
op_node = (OperationDepsNode *)factory->create_node(this->owner->id, "", name);
/* register opnode in this component's operation set */
- OperationIDKey key(opcode, name);
- this->operations[key] = op_node;
+ OperationIDKey *key = OBJECT_GUARDED_NEW(OperationIDKey, opcode, name);
+ BLI_ghash_insert(operations_map, key, op_node);
/* set as entry/exit node of component (if appropriate) */
if (optype == DEPSOP_TYPE_INIT) {
@@ -185,18 +199,22 @@ OperationDepsNode *ComponentDepsNode::add_operation(eDepsOperation_Type optype,
void ComponentDepsNode::remove_operation(eDepsOperation_Code opcode, const string &name)
{
- OperationDepsNode *op_node = find_operation(opcode, name);
- if (op_node) {
- /* unregister */
- this->operations.erase(OperationIDKey(opcode, name));
- OBJECT_GUARDED_DELETE(op_node, OperationDepsNode);
- }
+ /* unregister */
+ OperationIDKey key(opcode, name);
+ BLI_ghash_remove(operations_map,
+ &key,
+ comp_node_hash_key_free,
+ comp_node_hash_key_free);
}
void ComponentDepsNode::clear_operations()
{
- for (OperationMap::const_iterator it = operations.begin(); it != operations.end(); ++it) {
- OperationDepsNode *op_node = it->second;
+ if (operations_map != NULL) {
+ BLI_ghash_clear(operations_map,
+ comp_node_hash_key_free,
+ comp_node_hash_value_free);
+ }
+ foreach (OperationDepsNode *op_node, operations) {
OBJECT_GUARDED_DELETE(op_node, OperationDepsNode);
}
operations.clear();
@@ -208,30 +226,79 @@ void ComponentDepsNode::tag_update(Depsgraph *graph)
if (entry_op != NULL && entry_op->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
return;
}
- for (OperationMap::const_iterator it = operations.begin(); it != operations.end(); ++it) {
- OperationDepsNode *op_node = it->second;
+ foreach (OperationDepsNode *op_node, operations) {
op_node->tag_update(graph);
}
+ // It is possible that tag happens before finalization.
+ if (operations_map != NULL) {
+ GHASH_FOREACH_BEGIN(OperationDepsNode *, op_node, operations_map)
+ {
+ op_node->tag_update(graph);
+ }
+ GHASH_FOREACH_END();
+ }
}
OperationDepsNode *ComponentDepsNode::get_entry_operation()
{
- if (entry_operation)
+ if (entry_operation) {
return entry_operation;
- else if (operations.size() == 1)
- return operations.begin()->second;
+ }
+ else if (operations_map != NULL && BLI_ghash_size(operations_map) == 1) {
+ OperationDepsNode *op_node = NULL;
+ /* TODO(sergey): This is somewhat slow. */
+ GHASH_FOREACH_BEGIN(OperationDepsNode *, tmp, operations_map)
+ {
+ op_node = tmp;
+ }
+ GHASH_FOREACH_END();
+ /* Cache for the subsequent usage. */
+ entry_operation = op_node;
+ return op_node;
+ }
+ else if (operations.size() == 1) {
+ return operations[0];
+ }
return NULL;
}
OperationDepsNode *ComponentDepsNode::get_exit_operation()
{
- if (exit_operation)
+ if (exit_operation) {
return exit_operation;
- else if (operations.size() == 1)
- return operations.begin()->second;
+ }
+ else if (operations_map != NULL && BLI_ghash_size(operations_map) == 1) {
+ OperationDepsNode *op_node = NULL;
+ /* TODO(sergey): This is somewhat slow. */
+ GHASH_FOREACH_BEGIN(OperationDepsNode *, tmp, operations_map)
+ {
+ op_node = tmp;
+ }
+ GHASH_FOREACH_END();
+ /* Cache for the subsequent usage. */
+ exit_operation = op_node;
+ return op_node;
+ }
+ else if (operations.size() == 1) {
+ return operations[0];
+ }
return NULL;
}
+void ComponentDepsNode::finalize_build()
+{
+ operations.reserve(BLI_ghash_size(operations_map));
+ GHASH_FOREACH_BEGIN(OperationDepsNode *, op_node, operations_map)
+ {
+ operations.push_back(op_node);
+ }
+ GHASH_FOREACH_END();
+ BLI_ghash_free(operations_map,
+ comp_node_hash_key_free,
+ NULL);
+ operations_map = NULL;
+}
+
/* Parameter Component Defines ============================ */
DEG_DEPSNODE_DEFINE(ParametersComponentDepsNode, DEPSNODE_TYPE_PARAMETERS, "Parameters Component");
@@ -299,21 +366,30 @@ static DepsNodeFactoryImpl<ParticlesComponentDepsNode> DNTI_EVAL_PARTICLES;
DEG_DEPSNODE_DEFINE(ShadingComponentDepsNode, DEPSNODE_TYPE_SHADING, "Shading Component");
static DepsNodeFactoryImpl<ShadingComponentDepsNode> DNTI_SHADING;
+/* Cache Component Defines ============================ */
+
+DEG_DEPSNODE_DEFINE(CacheComponentDepsNode, DEPSNODE_TYPE_CACHE, "Cache Component");
+static DepsNodeFactoryImpl<CacheComponentDepsNode> DNTI_CACHE;
+
/* Node Types Register =================================== */
-void DEG_register_component_depsnodes()
+void deg_register_component_depsnodes()
{
- DEG_register_node_typeinfo(&DNTI_PARAMETERS);
- DEG_register_node_typeinfo(&DNTI_PROXY);
- DEG_register_node_typeinfo(&DNTI_ANIMATION);
- DEG_register_node_typeinfo(&DNTI_TRANSFORM);
- DEG_register_node_typeinfo(&DNTI_GEOMETRY);
- DEG_register_node_typeinfo(&DNTI_SEQUENCER);
-
- DEG_register_node_typeinfo(&DNTI_EVAL_POSE);
- DEG_register_node_typeinfo(&DNTI_BONE);
-
- DEG_register_node_typeinfo(&DNTI_EVAL_PARTICLES);
- DEG_register_node_typeinfo(&DNTI_SHADING);
+ deg_register_node_typeinfo(&DNTI_PARAMETERS);
+ deg_register_node_typeinfo(&DNTI_PROXY);
+ deg_register_node_typeinfo(&DNTI_ANIMATION);
+ deg_register_node_typeinfo(&DNTI_TRANSFORM);
+ deg_register_node_typeinfo(&DNTI_GEOMETRY);
+ deg_register_node_typeinfo(&DNTI_SEQUENCER);
+
+ deg_register_node_typeinfo(&DNTI_EVAL_POSE);
+ deg_register_node_typeinfo(&DNTI_BONE);
+
+ deg_register_node_typeinfo(&DNTI_EVAL_PARTICLES);
+ deg_register_node_typeinfo(&DNTI_SHADING);
+
+ deg_register_node_typeinfo(&DNTI_CACHE);
}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsnode_component.h b/source/blender/depsgraph/intern/nodes/deg_node_component.h
index 7f44c0ed03f..7dec8eaaa90 100644
--- a/source/blender/depsgraph/intern/depsnode_component.h
+++ b/source/blender/depsgraph/intern/nodes/deg_node_component.h
@@ -24,35 +24,29 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/depsnode_component.h
+/** \file blender/depsgraph/intern/nodes/deg_node_component.h
* \ingroup depsgraph
*/
-#ifndef __DEPSNODE_COMPONENT_H__
-#define __DEPSNODE_COMPONENT_H__
+#pragma once
-#include "depsnode.h"
+#include "intern/nodes/deg_node.h"
-#include "depsgraph_util_hash.h"
-#include "depsgraph_util_map.h"
-#include "depsgraph_util_set.h"
+#include "BLI_utildefines.h"
+#include "BLI_string.h"
struct ID;
struct bPoseChannel;
+struct GHash;
-struct Depsgraph;
-struct DepsgraphCopyContext;
struct EvaluationContext;
+
+namespace DEG {
+
+struct Depsgraph;
struct OperationDepsNode;
struct BoneComponentDepsNode;
-typedef enum eDepsComponent_Flag {
- /* Temporary flags, meaning all the component's operations has been
- * scheduled for update.
- */
- DEPSCOMP_FULLY_SCHEDULED = 1,
-} eDepsComponent_Flag;
-
/* ID Component - Base type for all components */
struct ComponentDepsNode : public DepsNode {
/* Key used to look up operations within a component */
@@ -75,7 +69,7 @@ struct ComponentDepsNode : public DepsNode {
string identifier() const
{
char codebuf[5];
- sprintf(codebuf, "%d", opcode);
+ BLI_snprintf(codebuf, sizeof(codebuf), "%d", opcode);
return string("OperationIDKey(") + codebuf + ", " + name + ")";
}
@@ -86,47 +80,41 @@ struct ComponentDepsNode : public DepsNode {
}
};
- /* XXX can't specialize std::hash for this purpose, because ComponentKey is a nested type ...
- * http://stackoverflow.com/a/951245
- */
- struct operation_key_hash {
- bool operator() (const OperationIDKey &key) const
- {
- return hash_combine(hash<int>()(key.opcode), hash<string>()(key.name));
- }
- };
-
/* Typedef for container of operations */
- typedef unordered_map<OperationIDKey, OperationDepsNode *, operation_key_hash> OperationMap;
-
-
ComponentDepsNode();
~ComponentDepsNode();
void init(const ID *id, const string &subdata);
- void copy(DepsgraphCopyContext *dcc, const ComponentDepsNode *src);
string identifier() const;
/* Find an existing operation, will throw an assert() if it does not exist. */
OperationDepsNode *find_operation(OperationIDKey key) const;
- OperationDepsNode *find_operation(eDepsOperation_Code opcode, const string &name) const;
+ OperationDepsNode *find_operation(eDepsOperation_Code opcode,
+ const string &name) const;
/* Check operation exists and return it. */
OperationDepsNode *has_operation(OperationIDKey key) const;
- OperationDepsNode *has_operation(eDepsOperation_Code opcode, const string &name) const;
+ OperationDepsNode *has_operation(eDepsOperation_Code opcode,
+ const string &name) const;
/**
* Create a new node for representing an operation and add this to graph
- * \warning If an existing node is found, it will be modified. This helps when node may
- * have been partially created earlier (e.g. parent ref before parent item is added)
+ * \warning If an existing node is found, it will be modified. This helps
+ * when node may have been partially created earlier (e.g. parent ref before
+ * parent item is added)
*
- * \param type: Operation node type (corresponding to context/component that it operates in)
- * \param optype: Role that operation plays within component (i.e. where in eval process)
+ * \param type: Operation node type (corresponding to context/component that
+ * it operates in)
+ * \param optype: Role that operation plays within component
+ * (i.e. where in eval process)
* \param op: The operation to perform
* \param name: Identifier for operation - used to find/locate it again
*/
- OperationDepsNode *add_operation(eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &name);
+ OperationDepsNode *add_operation(eDepsOperation_Type optype,
+ DepsEvalOperationCb op,
+ eDepsOperation_Code opcode,
+ const string &name);
void remove_operation(eDepsOperation_Code opcode, const string &name);
void clear_operations();
@@ -135,9 +123,13 @@ struct ComponentDepsNode : public DepsNode {
/* Evaluation Context Management .................. */
- /* Initialize component's evaluation context used for the specified purpose */
+ /* Initialize component's evaluation context used for the specified
+ * purpose.
+ */
virtual bool eval_context_init(EvaluationContext * /*eval_ctx*/) { return false; }
- /* Free data in component's evaluation context which is used for the specified purpose
+ /* Free data in component's evaluation context which is used for
+ * the specified purpose
+ *
* NOTE: this does not free the actual context in question
*/
virtual void eval_context_free(EvaluationContext * /*eval_ctx*/) {}
@@ -145,15 +137,29 @@ struct ComponentDepsNode : public DepsNode {
OperationDepsNode *get_entry_operation();
OperationDepsNode *get_exit_operation();
+ void finalize_build();
+
IDDepsNode *owner;
- OperationMap operations; /* inner nodes for this component */
+ /* ** Inner nodes for this component ** */
+
+ /* Operations stored as a hash map, for faster build.
+ * This hash map will be freed when graph is fully built.
+ */
+ GHash *operations_map;
+
+ /* This is a "normal" list of operations, used by evaluation
+ * and other routines after construction.
+ */
+ vector<OperationDepsNode *> operations;
+
OperationDepsNode *entry_operation;
OperationDepsNode *exit_operation;
// XXX: a poll() callback to check if component's first node can be started?
- int flags;
+ /* Temporary bitmask, used during graph construction. */
+ unsigned int layers;
};
/* ---------------------------------------- */
@@ -203,7 +209,11 @@ struct ShadingComponentDepsNode : public ComponentDepsNode {
DEG_DEPSNODE_DECLARE;
};
+struct CacheComponentDepsNode : public ComponentDepsNode {
+ DEG_DEPSNODE_DECLARE;
+};
+
-void DEG_register_component_depsnodes();
+void deg_register_component_depsnodes();
-#endif /* __DEPSNODE_COMPONENT_H__ */
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsnode_operation.cc b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc
index 6aeb163356b..5847af29ac2 100644
--- a/source/blender/depsgraph/intern/depsnode_operation.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc
@@ -24,39 +24,31 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/depsnode_operation.cc
+/** \file blender/depsgraph/intern/nodes/deg_node_operation.cc
* \ingroup depsgraph
*/
+#include "intern/nodes/deg_node_operation.h"
+
#include "MEM_guardedalloc.h"
extern "C" {
#include "BLI_utildefines.h"
} /* extern "C" */
-#include "depsnode_operation.h" /* own include */
-#include "depsnode_component.h"
-#include "depsgraph.h"
-#include "depsgraph_intern.h"
-
-/* ******************************************************************* */
-/* OpNode Identifiers Array - Exported to other depsgraph files too... */
+#include "intern/depsgraph.h"
+#include "intern/depsgraph_intern.h"
+#include "util/deg_util_hash.h"
-/* identifiers for operations */
-const char *DEG_OPNAMES[] = {
-#define DEF_DEG_OPCODE(label) #label,
-#include "depsnode_opcodes.h"
-#undef DEF_DEG_OPCODE
-
- "<Invalid>"
-};
+namespace DEG {
/* *********** */
/* Inner Nodes */
OperationDepsNode::OperationDepsNode() :
eval_priority(0.0f),
- flag(0)
+ flag(0),
+ customdata_mask(0)
{
}
@@ -66,7 +58,6 @@ OperationDepsNode::~OperationDepsNode()
string OperationDepsNode::identifier() const
{
- BLI_assert((opcode > 0) && (opcode < ARRAY_SIZE(DEG_OPNAMES)));
return string(DEG_OPNAMES[opcode]) + "(" + name + ")";
}
@@ -98,7 +89,9 @@ void OperationDepsNode::tag_update(Depsgraph *graph)
DEG_DEPSNODE_DEFINE(OperationDepsNode, DEPSNODE_TYPE_OPERATION, "Operation");
static DepsNodeFactoryImpl<OperationDepsNode> DNTI_OPERATION;
-void DEG_register_operation_depsnodes()
+void deg_register_operation_depsnodes()
{
- DEG_register_node_typeinfo(&DNTI_OPERATION);
+ deg_register_node_typeinfo(&DNTI_OPERATION);
}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsnode_operation.h b/source/blender/depsgraph/intern/nodes/deg_node_operation.h
index 1119e10805d..598393054db 100644
--- a/source/blender/depsgraph/intern/depsnode_operation.h
+++ b/source/blender/depsgraph/intern/nodes/deg_node_operation.h
@@ -24,19 +24,19 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/depsnode_operation.h
+/** \file blender/depsgraph/intern/nodes/deg_node_operation.h
* \ingroup depsgraph
*/
-#ifndef __DEPSNODE_OPERATION_H__
-#define __DEPSNODE_OPERATION_H__
+#pragma once
-#include "depsnode.h"
+#include "intern/nodes/deg_node.h"
struct ID;
struct Depsgraph;
-struct DepsgraphCopyContext;
+
+namespace DEG {
/* Flags for Depsgraph Nodes */
typedef enum eDepsOperation_Flag {
@@ -44,10 +44,14 @@ typedef enum eDepsOperation_Flag {
DEPSOP_FLAG_NEEDS_UPDATE = (1 << 0),
/* node was directly modified, causing need for update */
- /* XXX: intention is to make it easier to tell when we just need to take subgraphs */
+ /* XXX: intention is to make it easier to tell when we just need to
+ * take subgraphs.
+ */
DEPSOP_FLAG_DIRECTLY_MODIFIED = (1 << 1),
- /* Operation is evaluated using CPython; has GIL and security implications... */
+ /* Operation is evaluated using CPython; has GIL and security
+ * implications...
+ */
DEPSOP_FLAG_USES_PYTHON = (1 << 2),
} eDepsOperation_Flag;
@@ -68,23 +72,33 @@ struct OperationDepsNode : public DepsNode {
OperationDepsNode *get_entry_operation() { return this; }
OperationDepsNode *get_exit_operation() { return this; }
- ComponentDepsNode *owner; /* component that contains the operation */
+ /* Component that contains the operation. */
+ ComponentDepsNode *owner;
- DepsEvalOperationCb evaluate; /* callback for operation */
+ /* Callback for operation. */
+ DepsEvalOperationCb evaluate;
- uint32_t num_links_pending; /* how many inlinks are we still waiting on before we can be evaluated... */
+ /* How many inlinks are we still waiting on before we can be evaluated. */
+ uint32_t num_links_pending;
float eval_priority;
bool scheduled;
- short optype; /* (eDepsOperation_Type) stage of evaluation */
- int opcode; /* (eDepsOperation_Code) identifier for the operation being performed */
+ /* Stage of evaluation */
+ eDepsOperation_Type optype;
+
+ /* Identifier for the operation being performed. */
+ eDepsOperation_Code opcode;
+
+ /* (eDepsOperation_Flag) extra settings affecting evaluation. */
+ int flag;
- int flag; /* (eDepsOperation_Flag) extra settings affecting evaluation */
+ /* Extra customdata mask which needs to be evaluated for the object. */
+ uint64_t customdata_mask;
DEG_DEPSNODE_DECLARE;
};
-void DEG_register_operation_depsnodes();
+void deg_register_operation_depsnodes();
-#endif /* __DEPSNODE_OPERATION_H__ */
+} // namespace DEG
diff --git a/source/blender/depsgraph/util/deg_util_foreach.h b/source/blender/depsgraph/util/deg_util_foreach.h
new file mode 100644
index 00000000000..14cf4fc11ed
--- /dev/null
+++ b/source/blender/depsgraph/util/deg_util_foreach.h
@@ -0,0 +1,68 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Sergey Sharybin
+ * Contributor(s):
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/util/deg_util_foreach.h
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+#if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
+# define foreach(x, y) for(x : y)
+#elif defined(HAVE_BOOST_FUNCTION_BINDINGS)
+# include <boost/foreach.hpp>
+# define foreach BOOST_FOREACH
+#else
+#pragma message("No available foreach() implementation. Using stub instead, disabling new depsgraph")
+
+#ifndef WITH_LEGACY_DEPSGRAPH
+# error "Unable to build new depsgraph and legacy one is disabled."
+#endif
+
+#define DISABLE_NEW_DEPSGRAPH
+
+# define foreach(x, y) for (x; false; (void)y)
+#endif
+
+#define GHASH_FOREACH_BEGIN(type, var, what) \
+ do { \
+ GHashIterator gh_iter##var; \
+ GHASH_ITER(gh_iter##var, what) { \
+ type var = reinterpret_cast<type>(BLI_ghashIterator_getValue(&gh_iter##var)); \
+
+#define GHASH_FOREACH_END() \
+ } \
+ } while(0)
+
+#define GSET_FOREACH_BEGIN(type, var, what) \
+ do { \
+ GSetIterator gh_iter##var; \
+ GSET_ITER(gh_iter##var, what) { \
+ type var = reinterpret_cast<type>(BLI_gsetIterator_getKey(&gh_iter##var)); \
+
+#define GSET_FOREACH_END() \
+ } \
+ } while(0)
diff --git a/source/blender/depsgraph/util/depsgraph_util_function.h b/source/blender/depsgraph/util/deg_util_function.h
index a4301833408..1e34ae04d9a 100644
--- a/source/blender/depsgraph/util/depsgraph_util_function.h
+++ b/source/blender/depsgraph/util/deg_util_function.h
@@ -24,12 +24,11 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/util/depsgraph_util_function.h
+/** \file blender/depsgraph/util/deg_util_function.h
* \ingroup depsgraph
*/
-#ifndef __DEPSGRAPH_UTIL_FUNCTION_H__
-#define __DEPSGRAPH_UTIL_FUNCTION_H__
+#pragma once
#if (__cplusplus > 199711L)
@@ -57,6 +56,7 @@ using boost::function;
#define DISABLE_NEW_DEPSGRAPH
+#include "BLI_utildefines.h"
#include <cstdlib>
template<typename T>
@@ -108,5 +108,3 @@ void *function_bind(T func,
#define _4 Wrap()
#endif
-
-#endif /* __DEPSGRAPH_UTIL_FUNCTION_H__ */
diff --git a/source/blender/depsgraph/util/depsgraph_util_set.h b/source/blender/depsgraph/util/deg_util_hash.h
index 008ec6b74ca..e490be1a7a1 100644
--- a/source/blender/depsgraph/util/depsgraph_util_set.h
+++ b/source/blender/depsgraph/util/deg_util_hash.h
@@ -24,43 +24,18 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/util/depsgraph_util_set.h
+/** \file blender/depsgraph/util/deg_util_hash.h
* \ingroup depsgraph
*/
-#ifndef __DEPSGRAPH_UTIL_SET_H__
-#define __DEPSGRAPH_UTIL_SET_H__
+#pragma once
-#include <set>
+#include "BLI_utildefines.h"
-#include "depsgraph_util_hash.h"
+#include "BLI_ghash.h"
-using std::set;
-
-#if defined(DEG_NO_UNORDERED_MAP)
-# include <set>
-typedef std::set unordered_set;
-#endif
-
-#if defined(DEG_TR1_UNORDERED_MAP)
-# include <tr1/unordered_set>
-using std::tr1::unordered_set;
-#endif
-
-#if defined(DEG_STD_UNORDERED_MAP)
-# include <unordered_set>
-using std::unordered_set;
-#endif
-
-#if defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
-# include <unordered_set>
-using std::tr1::unordered_set;
-#endif
-
-#if !defined(DEG_NO_UNORDERED_MAP) && !defined(DEG_TR1_UNORDERED_MAP) && \
- !defined(DEG_STD_UNORDERED_MAP) && !defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) // NOLINT
-# error One of: DEG_NO_UNORDERED_MAP, DEG_TR1_UNORDERED_MAP,\
- DEG_STD_UNORDERED_MAP, DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE must be defined! // NOLINT
-#endif
-
-#endif /* __DEPSGRAPH_UTIL_SET_H__ */
+/* XXX this might require 2 different variants for sizeof(size_t) (32 vs 64 bit) */
+BLI_INLINE size_t hash_combine(size_t hash_a, size_t hash_b)
+{
+ return hash_a ^ (hash_b + 0x9e3779b9 + (hash_a << 6) + (hash_a >> 2));
+}
diff --git a/source/blender/depsgraph/util/depsgraph_util_hash.h b/source/blender/depsgraph/util/depsgraph_util_hash.h
deleted file mode 100644
index bc75627a026..00000000000
--- a/source/blender/depsgraph/util/depsgraph_util_hash.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2014 Blender Foundation.
- * All rights reserved.
- *
- * Original Author: Brecht van Lommel
- * Contributor(s): Lukas Toenne
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/depsgraph/util/depsgraph_util_hash.h
- * \ingroup depsgraph
- */
-
-#ifndef __DEPSGRAPH_UTIL_HASH_H__
-#define __DEPSGRAPH_UTIL_HASH_H__
-
-#if defined(DEG_NO_UNORDERED_MAP)
-# define DEG_HASH_NAMESPACE_BEGIN
-# define DEG_HASH_NAMESPACE_END
-#endif
-
-#if defined(DEG_TR1_UNORDERED_MAP)
-# include <tr1/unordered_map>
-# define DEG_HASH_NAMESPACE_BEGIN namespace std { namespace tr1 {
-# define DEG_HASH_NAMESPACE_END } }
-using std::tr1::hash;
-#endif
-
-#if defined(DEG_STD_UNORDERED_MAP)
-# include <unordered_map>
-# define DEG_HASH_NAMESPACE_BEGIN namespace std {
-# define DEG_HASH_NAMESPACE_END }
-using std::hash;
-#endif
-
-#if defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
-# include <unordered_map>
-# define DEG_HASH_NAMESPACE_BEGIN namespace std { namespace tr1 {
-# define DEG_HASH_NAMESPACE_END } }
-using std::tr1::hash;
-#endif
-
-#if !defined(DEG_NO_UNORDERED_MAP) && !defined(DEG_TR1_UNORDERED_MAP) && \
- !defined(DEG_STD_UNORDERED_MAP) && !defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) // NOLINT
-# error One of: DEG_NO_UNORDERED_MAP, DEG_TR1_UNORDERED_MAP,\
- DEG_STD_UNORDERED_MAP, DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE must be defined! // NOLINT
-#endif
-
-/* XXX this might require 2 different variants for sizeof(size_t) (32 vs 64 bit) */
-inline size_t hash_combine(size_t hash_a, size_t hash_b)
-{
- return hash_a ^ (hash_b + 0x9e3779b9 + (hash_a << 6) + (hash_a >> 2));
-}
-
-#endif /* __DEPSGRAPH_UTIL_HASH_H__ */
diff --git a/source/blender/depsgraph/util/depsgraph_util_map.h b/source/blender/depsgraph/util/depsgraph_util_map.h
deleted file mode 100644
index 0eae1d79e34..00000000000
--- a/source/blender/depsgraph/util/depsgraph_util_map.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2014 Blender Foundation.
- * All rights reserved.
- *
- * Original Author: Brecht van Lommel
- * Contributor(s): Lukas Toenne
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/depsgraph/util/depsgraph_util_map.h
- * \ingroup depsgraph
- */
-
-#ifndef __DEPSGRAPH_UTIL_MAP_H__
-#define __DEPSGRAPH_UTIL_MAP_H__
-
-#include <map>
-
-#include "depsgraph_util_hash.h"
-
-using std::map;
-using std::pair;
-
-#if defined(DEG_NO_UNORDERED_MAP)
-# include <map>
-typedef std::map unordered_map;
-#endif
-
-#if defined(DEG_TR1_UNORDERED_MAP)
-# include <tr1/unordered_map>
-using std::tr1::unordered_map;
-#endif
-
-#if defined(DEG_STD_UNORDERED_MAP)
-# include <unordered_map>
-using std::unordered_map;
-#endif
-
-#if defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
-# include <unordered_map>
-using std::tr1::unordered_map;
-#endif
-
-#if !defined(DEG_NO_UNORDERED_MAP) && !defined(DEG_TR1_UNORDERED_MAP) && \
- !defined(DEG_STD_UNORDERED_MAP) && !defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) // NOLINT
-# error One of: DEG_NO_UNORDERED_MAP, DEG_TR1_UNORDERED_MAP,\
- DEG_STD_UNORDERED_MAP, DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE must be defined! // NOLINT
-#endif
-
-#endif /* __DEPSGRAPH_UTIL_MAP_H__ */
diff --git a/source/blender/editors/CMakeLists.txt b/source/blender/editors/CMakeLists.txt
index 084006ce277..1559512d713 100644
--- a/source/blender/editors/CMakeLists.txt
+++ b/source/blender/editors/CMakeLists.txt
@@ -19,6 +19,10 @@
# ***** END GPL LICENSE BLOCK *****
if(WITH_BLENDER)
+ if(WITH_INPUT_NDOF)
+ add_definitions(-DWITH_INPUT_NDOF)
+ endif()
+
add_subdirectory(animation)
add_subdirectory(armature)
add_subdirectory(curve)
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index ea2f7fc5588..57302c18a88 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -40,6 +40,7 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
+#include "DNA_cachefile_types.h"
#include "DNA_camera_types.h"
#include "DNA_object_types.h"
#include "DNA_particle_types.h"
@@ -389,7 +390,10 @@ static bool acf_generic_dataexpand_setting_valid(bAnimContext *ac, bAnimListElem
/* select is ok for most "ds*" channels (e.g. dsmat) */
case ACHANNEL_SETTING_SELECT:
return true;
-
+
+ case ACHANNEL_SETTING_ALWAYS_VISIBLE:
+ return true;
+
/* other flags are never supported */
default:
return false;
@@ -528,7 +532,10 @@ static bool acf_scene_setting_valid(bAnimContext *ac, bAnimListElem *UNUSED(ale)
case ACHANNEL_SETTING_SELECT:
case ACHANNEL_SETTING_EXPAND:
return true;
-
+
+ case ACHANNEL_SETTING_ALWAYS_VISIBLE:
+ return false;
+
default:
return false;
}
@@ -554,7 +561,7 @@ static int acf_scene_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Setting
case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */
*neg = true;
return ADT_CURVES_NOT_VISIBLE;
-
+
default: /* unsupported */
return 0;
}
@@ -681,7 +688,10 @@ static bool acf_object_setting_valid(bAnimContext *ac, bAnimListElem *ale, eAnim
case ACHANNEL_SETTING_SELECT:
case ACHANNEL_SETTING_EXPAND:
return true;
-
+
+ case ACHANNEL_SETTING_ALWAYS_VISIBLE:
+ return ((ac) && (ac->spacetype == SPACE_IPO) && (ob->adt));
+
default:
return false;
}
@@ -707,7 +717,10 @@ static int acf_object_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settin
case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */
*neg = true;
return ADT_CURVES_NOT_VISIBLE;
-
+
+ case ACHANNEL_SETTING_ALWAYS_VISIBLE:
+ return ADT_CURVES_ALWAYS_VISIBLE;
+
default: /* unsupported */
return 0;
}
@@ -731,6 +744,7 @@ static void *acf_object_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings se
case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */
case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */
+ case ACHANNEL_SETTING_ALWAYS_VISIBLE:
if (ob->adt)
return GET_ACF_FLAG_PTR(ob->adt->flag, type);
return NULL;
@@ -838,7 +852,10 @@ static bool acf_group_setting_valid(bAnimContext *ac, bAnimListElem *UNUSED(ale)
/* conditionally supported */
case ACHANNEL_SETTING_VISIBLE: /* Only available in Graph Editor */
return (ac->spacetype == SPACE_IPO);
-
+
+ case ACHANNEL_SETTING_ALWAYS_VISIBLE:
+ return (ac->spacetype == SPACE_IPO);
+
default: /* always supported */
return true;
}
@@ -878,7 +895,10 @@ static int acf_group_setting_flag(bAnimContext *ac, eAnimChannel_Settings settin
case ACHANNEL_SETTING_VISIBLE: /* visibility - graph editor */
*neg = 1;
return AGRP_NOTVISIBLE;
-
+
+ case ACHANNEL_SETTING_ALWAYS_VISIBLE:
+ return ADT_CURVES_ALWAYS_VISIBLE;
+
default:
/* this shouldn't happen */
return 0;
@@ -964,7 +984,10 @@ static bool acf_fcurve_setting_valid(bAnimContext *ac, bAnimListElem *ale, eAnim
case ACHANNEL_SETTING_VISIBLE: /* Only available in Graph Editor */
return (ac->spacetype == SPACE_IPO);
-
+
+ case ACHANNEL_SETTING_ALWAYS_VISIBLE:
+ return false;
+
/* always available */
default:
return true;
@@ -1578,6 +1601,88 @@ static bAnimChannelType ACF_DSTEX =
/* Camera Expander ------------------------------------------- */
// TODO: just get this from RNA?
+static int acf_dscachefile_icon(bAnimListElem *ale)
+{
+ UNUSED_VARS(ale);
+ return ICON_FILE;
+}
+
+/* get the appropriate flag(s) for the setting when it is valid */
+static int acf_dscachefile_setting_flag(bAnimContext *ac, eAnimChannel_Settings setting, bool *neg)
+{
+ /* clear extra return data first */
+ *neg = false;
+
+ switch (setting) {
+ case ACHANNEL_SETTING_EXPAND: /* expanded */
+ return CACHEFILE_DS_EXPAND;
+
+ case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */
+ return ADT_NLA_EVAL_OFF;
+
+ case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */
+ *neg = true;
+ return ADT_CURVES_NOT_VISIBLE;
+
+ case ACHANNEL_SETTING_SELECT: /* selected */
+ return ADT_UI_SELECTED;
+
+ default: /* unsupported */
+ return 0;
+ }
+
+ UNUSED_VARS(ac);
+}
+
+/* get pointer to the setting */
+static void *acf_dscachefile_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type)
+{
+ CacheFile *cache_file = (CacheFile *)ale->data;
+
+ /* clear extra return data first */
+ *type = 0;
+
+ switch (setting) {
+ case ACHANNEL_SETTING_EXPAND: /* expanded */
+ return GET_ACF_FLAG_PTR(cache_file->flag, type);
+
+ case ACHANNEL_SETTING_SELECT: /* selected */
+ case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */
+ case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */
+ if (cache_file->adt) {
+ return GET_ACF_FLAG_PTR(cache_file->adt->flag, type);
+ }
+
+ return NULL;
+
+ default: /* unsupported */
+ return NULL;
+ }
+}
+
+/* CacheFile expander type define. */
+static bAnimChannelType ACF_DSCACHEFILE =
+{
+ "Cache File Expander", /* type name */
+ ACHANNEL_ROLE_EXPANDER, /* role */
+
+ acf_generic_dataexpand_color, /* backdrop color */
+ acf_generic_dataexpand_backdrop, /* backdrop */
+ acf_generic_indention_1, /* indent level */
+ acf_generic_basic_offset, /* offset */
+
+ acf_generic_idblock_name, /* name */
+ acf_generic_idfill_name_prop, /* name prop */
+ acf_dscachefile_icon, /* icon */
+
+ acf_generic_dataexpand_setting_valid, /* has setting */
+ acf_dscachefile_setting_flag, /* flag for setting */
+ acf_dscachefile_setting_ptr /* pointer for setting */
+};
+
+/* Camera Expander ------------------------------------------- */
+
+// TODO: just get this from RNA?
static int acf_dscam_icon(bAnimListElem *UNUSED(ale))
{
return ICON_CAMERA_DATA;
@@ -1602,7 +1707,10 @@ static int acf_dscam_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Setting
case ACHANNEL_SETTING_SELECT: /* selected */
return ADT_UI_SELECTED;
-
+
+ case ACHANNEL_SETTING_ALWAYS_VISIBLE:
+ return ADT_CURVES_ALWAYS_VISIBLE;
+
default: /* unsupported */
return 0;
}
@@ -1623,6 +1731,7 @@ static void *acf_dscam_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings set
case ACHANNEL_SETTING_SELECT: /* selected */
case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */
case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */
+ case ACHANNEL_SETTING_ALWAYS_VISIBLE:
if (ca->adt)
return GET_ACF_FLAG_PTR(ca->adt->flag, type);
return NULL;
@@ -2597,6 +2706,84 @@ static bAnimChannelType ACF_DSGPENCIL =
acf_dsgpencil_setting_ptr /* pointer for setting */
};
+/* World Expander ------------------------------------------- */
+
+// TODO: just get this from RNA?
+static int acf_dsmclip_icon(bAnimListElem *UNUSED(ale))
+{
+ return ICON_SEQUENCE;
+}
+
+/* get the appropriate flag(s) for the setting when it is valid */
+static int acf_dsmclip_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg)
+{
+ /* clear extra return data first */
+ *neg = false;
+
+ switch (setting) {
+ case ACHANNEL_SETTING_EXPAND: /* expanded */
+ return MCLIP_DATA_EXPAND;
+
+ case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */
+ return ADT_NLA_EVAL_OFF;
+
+ case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */
+ *neg = true;
+ return ADT_CURVES_NOT_VISIBLE;
+
+ case ACHANNEL_SETTING_SELECT: /* selected */
+ return ADT_UI_SELECTED;
+
+ default: /* unsupported */
+ return 0;
+ }
+}
+
+/* get pointer to the setting */
+static void *acf_dsmclip_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type)
+{
+ MovieClip *clip = (MovieClip *)ale->data;
+
+ /* clear extra return data first */
+ *type = 0;
+
+ switch (setting) {
+ case ACHANNEL_SETTING_EXPAND: /* expanded */
+ return GET_ACF_FLAG_PTR(clip->flag, type);
+
+ case ACHANNEL_SETTING_SELECT: /* selected */
+ case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */
+ case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */
+ if (clip->adt != NULL) {
+ return GET_ACF_FLAG_PTR(clip->adt->flag, type);
+ }
+ return NULL;
+
+ default: /* unsupported */
+ return NULL;
+ }
+}
+
+/* world expander type define */
+static bAnimChannelType ACF_DSMCLIP =
+{
+ "Movieclip Expander", /* type name */
+ ACHANNEL_ROLE_EXPANDER, /* role */
+
+ acf_generic_dataexpand_color, /* backdrop color */
+ acf_generic_dataexpand_backdrop, /* backdrop */
+ acf_generic_indention_1, /* indent level */
+ acf_generic_basic_offset, /* offset */
+
+ acf_generic_idblock_name , /* name */
+ acf_generic_idfill_name_prop, /* name prop */
+ acf_dsmclip_icon, /* icon */
+
+ acf_generic_dataexpand_setting_valid, /* has setting */
+ acf_dsmclip_setting_flag, /* flag for setting */
+ acf_dsmclip_setting_ptr /* pointer for setting */
+};
+
/* ShapeKey Entry ------------------------------------------- */
/* name for ShapeKey */
@@ -3388,6 +3575,7 @@ static void ANIM_init_channel_typeinfo_data(void)
animchannelTypeInfo[type++] = &ACF_DSMAT; /* Material Channel */
animchannelTypeInfo[type++] = &ACF_DSLAM; /* Lamp Channel */
animchannelTypeInfo[type++] = &ACF_DSCAM; /* Camera Channel */
+ animchannelTypeInfo[type++] = &ACF_DSCACHEFILE; /* CacheFile Channel */
animchannelTypeInfo[type++] = &ACF_DSCUR; /* Curve Channel */
animchannelTypeInfo[type++] = &ACF_DSSKEY; /* ShapeKey Channel */
animchannelTypeInfo[type++] = &ACF_DSWOR; /* World Channel */
@@ -3401,6 +3589,7 @@ static void ANIM_init_channel_typeinfo_data(void)
animchannelTypeInfo[type++] = &ACF_DSLINESTYLE; /* LineStyle Channel */
animchannelTypeInfo[type++] = &ACF_DSSPK; /* Speaker Channel */
animchannelTypeInfo[type++] = &ACF_DSGPENCIL; /* GreasePencil Channel */
+ animchannelTypeInfo[type++] = &ACF_DSMCLIP; /* MovieClip Channel */
animchannelTypeInfo[type++] = &ACF_SHAPEKEY; /* ShapeKey */
@@ -3665,7 +3854,9 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
* - in Grease Pencil mode, color swatches for layer color
*/
if (ac->sl) {
- if ((ac->spacetype == SPACE_IPO) && acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE)) {
+ if ((ac->spacetype == SPACE_IPO) &&
+ (acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE) ||
+ acf->has_setting(ac, ale, ACHANNEL_SETTING_ALWAYS_VISIBLE))) {
/* for F-Curves, draw color-preview of curve behind checkbox */
if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
FCurve *fcu = (FCurve *)ale->data;
@@ -3679,9 +3870,13 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
*/
glRectf(offset, yminc, offset + ICON_WIDTH, ymaxc);
}
-
/* icon is drawn as widget now... */
- offset += ICON_WIDTH;
+ if (acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE)) {
+ offset += ICON_WIDTH;
+ }
+ if (acf->has_setting(ac, ale, ACHANNEL_SETTING_ALWAYS_VISIBLE)) {
+ offset += ICON_WIDTH;
+ }
}
else if ((ac->spacetype == SPACE_NLA) && acf->has_setting(ac, ale, ACHANNEL_SETTING_SOLO)) {
/* just skip - drawn as widget now */
@@ -3817,7 +4012,12 @@ static void achannel_setting_flush_widget_cb(bContext *C, void *ale_npoin, void
/* send notifiers before doing anything else... */
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
-
+
+ /* verify that we have a channel to operate on. */
+ if (!ale_setting) {
+ return;
+ }
+
if (ale_setting->type == ANIMTYPE_GPLAYER)
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL);
@@ -3825,17 +4025,13 @@ static void achannel_setting_flush_widget_cb(bContext *C, void *ale_npoin, void
if (ANIM_animdata_get_context(C, &ac) == 0)
return;
- /* verify that we have a channel to operate on, and that it has all we need */
- if (ale_setting) {
- /* check if the setting is on... */
- on = ANIM_channel_setting_get(&ac, ale_setting, setting);
-
- /* on == -1 means setting not found... */
- if (on == -1)
- return;
- }
- else
+ /* check if the setting is on... */
+ on = ANIM_channel_setting_get(&ac, ale_setting, setting);
+
+ /* on == -1 means setting not found... */
+ if (on == -1) {
return;
+ }
/* get all channels that can possibly be chosen - but ignore hierarchy */
filter = ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS;
@@ -4025,6 +4221,11 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, const bAni
tooltip = TIP_("Channels are visible in Graph Editor for editing");
break;
+ case ACHANNEL_SETTING_ALWAYS_VISIBLE:
+ icon = ICON_UNPINNED;
+ tooltip = TIP_("Channels are visible in Graph Editor for editing");
+ break;
+
case ACHANNEL_SETTING_MOD_OFF: /* modifiers disabled */
icon = ICON_MODIFIER;
usetoggle = false;
@@ -4040,7 +4241,7 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, const bAni
case ACHANNEL_SETTING_SOLO: /* NLA Tracks only */
//icon = ((enabled) ? ICON_SOLO_OFF : ICON_SOLO_ON);
icon = ICON_SOLO_OFF;
- tooltip = TIP_("NLA Track is the only one evaluated in this Animation Data block, with all others muted");
+ tooltip = TIP_("NLA Track is the only one evaluated in this animation data-block, with all others muted");
break;
/* --- */
@@ -4134,6 +4335,7 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, const bAni
case ACHANNEL_SETTING_MUTE: /* General - muting flags */
case ACHANNEL_SETTING_PINNED: /* NLA Actions - 'map/nomap' */
case ACHANNEL_SETTING_MOD_OFF:
+ case ACHANNEL_SETTING_ALWAYS_VISIBLE:
UI_but_funcN_set(but, achannel_setting_flush_widget_cb, MEM_dupallocN(ale), SET_INT_IN_POINTER(setting));
break;
@@ -4197,10 +4399,20 @@ void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListEle
* - in Grease Pencil mode, color swatches for layer color
*/
if (ac->sl) {
- if ((ac->spacetype == SPACE_IPO) && acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE)) {
+ if ((ac->spacetype == SPACE_IPO) &&
+ (acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE) ||
+ acf->has_setting(ac, ale, ACHANNEL_SETTING_ALWAYS_VISIBLE)))
+ {
+ /* pin toggle */
+ if (acf->has_setting(ac, ale, ACHANNEL_SETTING_ALWAYS_VISIBLE)) {
+ draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_ALWAYS_VISIBLE);
+ offset += ICON_WIDTH;
+ }
/* visibility toggle */
- draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_VISIBLE);
- offset += ICON_WIDTH;
+ if (acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE)) {
+ draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_VISIBLE);
+ offset += ICON_WIDTH;
+ }
}
else if ((ac->spacetype == SPACE_NLA) && acf->has_setting(ac, ale, ACHANNEL_SETTING_SOLO)) {
/* 'solo' setting for NLA Tracks */
@@ -4208,6 +4420,8 @@ void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListEle
offset += ICON_WIDTH;
}
else if (ale->type == ANIMTYPE_GPLAYER) {
+#if 0
+ /* XXX: Maybe need a better design */
/* color swatch for layer color */
bGPDlayer *gpl = (bGPDlayer *)ale->data;
PointerRNA ptr;
@@ -4216,7 +4430,6 @@ void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListEle
RNA_pointer_create(ale->id, &RNA_GPencilLayer, ale->data, &ptr);
UI_block_align_begin(block);
-
UI_block_emboss_set(block, RNA_boolean_get(&ptr, "is_stroke_visible") ? UI_EMBOSS : UI_EMBOSS_NONE);
uiDefButR(block, UI_BTYPE_COLOR, 1, "", offset, yminc, w, ICON_WIDTH,
&ptr, "color", -1,
@@ -4226,11 +4439,11 @@ void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListEle
uiDefButR(block, UI_BTYPE_COLOR, 1, "", offset + w, yminc, w, ICON_WIDTH,
&ptr, "fill_color", -1,
0, 0, 0, 0, gpl->info);
-
UI_block_emboss_set(block, UI_EMBOSS_NONE);
UI_block_align_end(block);
-
+
offset += ICON_WIDTH;
+#endif
}
}
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index 8822c8511de..117b8549712 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -120,6 +120,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
case ANIMTYPE_DSLAM:
case ANIMTYPE_DSCAM:
+ case ANIMTYPE_DSCACHEFILE:
case ANIMTYPE_DSCUR:
case ANIMTYPE_DSSKEY:
case ANIMTYPE_DSWOR:
@@ -132,6 +133,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
case ANIMTYPE_DSLINESTYLE:
case ANIMTYPE_DSSPK:
case ANIMTYPE_DSGPENCIL:
+ case ANIMTYPE_DSMCLIP:
{
/* need to verify that this data is valid for now */
if (ale->adt) {
@@ -175,6 +177,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
case ANIMTYPE_DSLAM:
case ANIMTYPE_DSCAM:
+ case ANIMTYPE_DSCACHEFILE:
case ANIMTYPE_DSCUR:
case ANIMTYPE_DSSKEY:
case ANIMTYPE_DSWOR:
@@ -188,6 +191,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
case ANIMTYPE_DSNTREE:
case ANIMTYPE_DSTEX:
case ANIMTYPE_DSGPENCIL:
+ case ANIMTYPE_DSMCLIP:
{
/* need to verify that this data is valid for now */
if (ale && ale->adt) {
@@ -275,6 +279,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d
case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
case ANIMTYPE_DSLAM:
case ANIMTYPE_DSCAM:
+ case ANIMTYPE_DSCACHEFILE:
case ANIMTYPE_DSCUR:
case ANIMTYPE_DSSKEY:
case ANIMTYPE_DSWOR:
@@ -288,6 +293,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d
case ANIMTYPE_DSLINESTYLE:
case ANIMTYPE_DSSPK:
case ANIMTYPE_DSGPENCIL:
+ case ANIMTYPE_DSMCLIP:
{
if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED))
sel = ACHANNEL_SETFLAG_CLEAR;
@@ -370,6 +376,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d
case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
case ANIMTYPE_DSLAM:
case ANIMTYPE_DSCAM:
+ case ANIMTYPE_DSCACHEFILE:
case ANIMTYPE_DSCUR:
case ANIMTYPE_DSSKEY:
case ANIMTYPE_DSWOR:
@@ -383,6 +390,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d
case ANIMTYPE_DSLINESTYLE:
case ANIMTYPE_DSSPK:
case ANIMTYPE_DSGPENCIL:
+ case ANIMTYPE_DSMCLIP:
{
/* need to verify that this data is valid for now */
if (ale->adt) {
@@ -431,7 +439,11 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAn
/* sanity check */
if (ELEM(NULL, anim_data, anim_data->first))
return;
-
+
+ if (setting == ACHANNEL_SETTING_ALWAYS_VISIBLE) {
+ return;
+ }
+
/* find the channel that got changed */
for (ale = anim_data->first; ale; ale = ale->next) {
/* compare data, and type as main way of identifying the channel */
@@ -1686,7 +1698,7 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
bGPDlayer *gpl = (bGPDlayer *)ale->data;
/* try to delete the layer's data and the layer itself */
- free_gpencil_frames(gpl);
+ BKE_gpencil_free_frames(gpl);
BLI_freelinkN(&gpd->layers, gpl);
break;
}
@@ -2119,7 +2131,7 @@ static int animchannels_clean_empty_exec(bContext *C, wmOperator *UNUSED(op))
/* remove AnimData? */
if (action_empty && nla_empty && drivers_empty) {
- BKE_animdata_free(id);
+ BKE_animdata_free(id, true);
}
}
@@ -2137,7 +2149,7 @@ static void ANIM_OT_channels_clean_empty(wmOperatorType *ot)
/* identifiers */
ot->name = "Remove Empty Animation Data";
ot->idname = "ANIM_OT_channels_clean_empty";
- ot->description = "Delete all empty animation data containers from visible datablocks";
+ ot->description = "Delete all empty animation data containers from visible data-blocks";
/* api callbacks */
ot->exec = animchannels_clean_empty_exec;
@@ -2356,7 +2368,7 @@ static void borderselect_anim_channels(bAnimContext *ac, rcti *rect, short selec
}
else {
ymin = 0.0f;
- ymax = (float)(-ACHANNEL_HEIGHT);
+ ymax = (float)(-ACHANNEL_HEIGHT(ac));
}
/* convert border-region to view coordinates */
@@ -2372,7 +2384,7 @@ static void borderselect_anim_channels(bAnimContext *ac, rcti *rect, short selec
if (ac->datatype == ANIMCONT_NLA)
ymin = ymax - NLACHANNEL_STEP(snla);
else
- ymin = ymax - ACHANNEL_STEP;
+ ymin = ymax - ACHANNEL_STEP(ac);
/* if channel is within border-select region, alter it */
if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
@@ -2573,7 +2585,7 @@ static int animchannels_channel_get(bAnimContext *ac, const int mval[2])
UI_view2d_listview_view_to_cell(v2d, NLACHANNEL_NAMEWIDTH, NLACHANNEL_STEP(snla), 0, (float)NLACHANNEL_HEIGHT_HALF(snla), x, y, NULL, &channel_index);
}
else {
- UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index);
+ UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP(ac), 0, (float)ACHANNEL_HEIGHT_HALF(ac), x, y, NULL, &channel_index);
}
return channel_index;
@@ -2705,6 +2717,10 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
if ((adt) && (adt->flag & ADT_UI_SELECTED))
adt->flag |= ADT_UI_ACTIVE;
+ /* ensure we exit editmode on whatever object was active before to avoid getting stuck there - T48747 */
+ if (ob != sce->obedit)
+ ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO);
+
notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
break;
}
@@ -2712,6 +2728,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
case ANIMTYPE_DSLAM:
case ANIMTYPE_DSCAM:
+ case ANIMTYPE_DSCACHEFILE:
case ANIMTYPE_DSCUR:
case ANIMTYPE_DSSKEY:
case ANIMTYPE_DSWOR:
@@ -2725,6 +2742,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
case ANIMTYPE_DSLINESTYLE:
case ANIMTYPE_DSSPK:
case ANIMTYPE_DSGPENCIL:
+ case ANIMTYPE_DSMCLIP:
{
/* sanity checking... */
if (ale->adt) {
@@ -2988,7 +3006,7 @@ static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, const wmE
* ACHANNEL_HEIGHT_HALF.
*/
UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, &y);
- UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index);
+ UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP(&ac), 0, (float)ACHANNEL_HEIGHT_HALF(&ac), x, y, NULL, &channel_index);
/* handle mouse-click in the relevant channel then */
notifierFlags = mouse_anim_channels(C, &ac, channel_index, selectmode);
diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c
index 5665ce59783..437dd2b2de2 100644
--- a/source/blender/editors/animation/anim_deps.c
+++ b/source/blender/editors/animation/anim_deps.c
@@ -399,7 +399,13 @@ void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data)
ANIM_list_elem_update(ac->scene, ale);
}
}
-
+ else if (ale->datatype == ALE_NLASTRIP) {
+ if (ale->update & ANIM_UPDATE_DEPS) {
+ ale->update &= ~ANIM_UPDATE_DEPS;
+ ANIM_list_elem_update(ac->scene, ale);
+ }
+ }
+
BLI_assert(ale->update == 0);
}
}
diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c
index dbc9c8b4f23..33e44d73894 100644
--- a/source/blender/editors/animation/anim_draw.c
+++ b/source/blender/editors/animation/anim_draw.c
@@ -343,12 +343,17 @@ static float normalization_factor_get(Scene *scene, FCurve *fcu, short flag, flo
}
}
- range = max_coord - min_coord;
-
- if (range > FLT_EPSILON) {
- factor = 2.0f / range;
+ if (max_coord > min_coord) {
+ range = max_coord - min_coord;
+ if (range > FLT_EPSILON) {
+ factor = 2.0f / range;
+ }
+ offset = -min_coord - range / 2.0f;
+ }
+ else if (max_coord == min_coord) {
+ factor = 1.0f;
+ offset = -min_coord;
}
- offset = -min_coord - range / 2.0f;
}
BLI_assert(factor != 0.0f);
if (r_offset) {
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index 910e195173c..c12a050e9ba 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -53,6 +53,7 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_camera_types.h"
+#include "DNA_cachefile_types.h"
#include "DNA_lamp_types.h"
#include "DNA_lattice_types.h"
#include "DNA_linestyle_types.h"
@@ -61,6 +62,7 @@
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meta_types.h"
+#include "DNA_movieclip_types.h"
#include "DNA_node_types.h"
#include "DNA_particle_types.h"
#include "DNA_space_types.h"
@@ -71,6 +73,7 @@
#include "DNA_world_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_object_types.h"
+#include "DNA_userdef_types.h"
#include "MEM_guardedalloc.h"
@@ -97,9 +100,30 @@
#include "ED_anim_api.h"
#include "ED_markers.h"
+#include "UI_resources.h" /* for TH_KEYFRAME_SCALE lookup */
+
/* ************************************************************ */
/* Blender Context <-> Animation Context mapping */
+/* ----------- Private Stuff - General -------------------- */
+
+/* Get vertical scaling factor (i.e. typically used for keyframe size) */
+static void animedit_get_yscale_factor(bAnimContext *ac)
+{
+ bTheme *btheme = UI_GetTheme();
+
+ /* grab scale factor directly from action editor setting
+ * NOTE: This theme setting doesn't have an ID, as it cannot be accessed normally
+ * since it is a float, and the theem settings methods can only handle chars.
+ */
+ ac->yscale_fac = btheme->tact.keyframe_scale_fac;
+
+ /* clamp to avoid problems with uninitialised values... */
+ if (ac->yscale_fac < 0.1f)
+ ac->yscale_fac = 1.0f;
+ //printf("yscale_fac = %f\n", ac->yscale_fac);
+}
+
/* ----------- Private Stuff - Action Editor ------------- */
/* Get shapekey data being edited (for Action Editor -> ShapeKey mode) */
@@ -177,6 +201,16 @@ static bool actedit_get_context(bAnimContext *ac, SpaceAction *saction)
ac->mode = saction->mode;
return true;
+
+ case SACTCONT_CACHEFILE: /* Cache File */ /* XXX review how this mode is handled... */
+ /* update scene-pointer (no need to check for pinning yet, as not implemented) */
+ saction->ads.source = (ID *)ac->scene;
+
+ ac->datatype = ANIMCONT_CHANNEL;
+ ac->data = &saction->ads;
+
+ ac->mode = saction->mode;
+ return true;
case SACTCONT_MASK: /* Mask */ /* XXX review how this mode is handled... */
{
@@ -352,6 +386,9 @@ bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
ac->spacetype = (sa) ? sa->spacetype : 0;
ac->regiontype = (ar) ? ar->regiontype : 0;
+ /* initialise default y-scale factor */
+ animedit_get_yscale_factor(ac);
+
/* get data context info */
// XXX: if the below fails, try to grab this info from context instead... (to allow for scripting)
return ANIM_animdata_context_getdata(ac);
@@ -635,6 +672,19 @@ static bAnimListElem *make_new_animlistelem(void *data, short datatype, ID *owne
ale->adt = BKE_animdata_from_id(data);
break;
}
+ case ANIMTYPE_DSCACHEFILE:
+ {
+ CacheFile *cache_file = (CacheFile *)data;
+ AnimData *adt = cache_file->adt;
+
+ ale->flag = FILTER_CACHEFILE_OBJD(cache_file);
+
+ ale->key_data = (adt) ? adt->action : NULL;
+ ale->datatype = ALE_ACT;
+
+ ale->adt = BKE_animdata_from_id(data);
+ break;
+ }
case ANIMTYPE_DSCUR:
{
Curve *cu = (Curve *)data;
@@ -793,6 +843,19 @@ static bAnimListElem *make_new_animlistelem(void *data, short datatype, ID *owne
ale->adt = BKE_animdata_from_id(data);
break;
}
+ case ANIMTYPE_DSMCLIP:
+ {
+ MovieClip *clip = (MovieClip *)data;
+ AnimData *adt = clip->adt;
+
+ ale->flag = EXPANDED_MCLIP(clip);
+
+ ale->key_data = (adt) ? adt->action : NULL;
+ ale->datatype = ALE_ACT;
+
+ ale->adt = BKE_animdata_from_id(data);
+ break;
+ }
case ANIMTYPE_NLACONTROLS:
{
AnimData *adt = (AnimData *)data;
@@ -903,6 +966,9 @@ static bAnimListElem *make_new_animlistelem(void *data, short datatype, ID *owne
*/
static bool skip_fcurve_selected_data(bDopeSheet *ads, FCurve *fcu, ID *owner_id, int filter_mode)
{
+ if (fcu->grp != NULL && fcu->grp->flag & ADT_CURVES_ALWAYS_VISIBLE) {
+ return false;
+ }
/* hidden items should be skipped if we only care about visible data, but we aren't interested in hidden stuff */
const bool skip_hidden = (filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN);
@@ -1255,7 +1321,7 @@ static size_t animfilter_action(bAnimContext *ac, ListBase *anim_data, bDopeShee
/* don't include anything from this action if it is linked in from another file,
* and we're getting stuff for editing...
*/
- if ((filter_mode & ANIMFILTER_FOREDIT) && (act->id.lib))
+ if ((filter_mode & ANIMFILTER_FOREDIT) && ID_IS_LINKED_DATABLOCK(act))
return 0;
/* do groups */
@@ -1726,6 +1792,42 @@ static size_t animdata_filter_ds_gpencil(bAnimContext *ac, ListBase *anim_data,
return items;
}
+/* Helper for Cache File data integrated with main DopeSheet */
+static size_t animdata_filter_ds_cachefile(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, CacheFile *cache_file, int filter_mode)
+{
+ ListBase tmp_data = {NULL, NULL};
+ size_t tmp_items = 0;
+ size_t items = 0;
+
+ /* add relevant animation channels for Cache File */
+ BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_CACHEFILE_OBJD(cache_file))
+ {
+ /* add animation channels */
+ tmp_items += animfilter_block_data(ac, &tmp_data, ads, &cache_file->id, filter_mode);
+ }
+ END_ANIMFILTER_SUBCHANNELS;
+
+ /* did we find anything? */
+ if (tmp_items) {
+ /* include data-expand widget first */
+ if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
+ /* check if filtering by active status */
+ // XXX: active check here needs checking
+ if (ANIMCHANNEL_ACTIVEOK(cache_file)) {
+ ANIMCHANNEL_NEW_CHANNEL(cache_file, ANIMTYPE_DSCACHEFILE, cache_file);
+ }
+ }
+
+ /* now add the list of collected channels */
+ BLI_movelisttolist(anim_data, &tmp_data);
+ BLI_assert(BLI_listbase_is_empty(&tmp_data));
+ items += tmp_items;
+ }
+
+ /* return the number of items added to the list */
+ return items;
+}
+
/* Helper for Mask Editing - mask layers */
static size_t animdata_filter_mask_data(ListBase *anim_data, Mask *mask, const int filter_mode)
{
@@ -2705,11 +2807,159 @@ static size_t animdata_filter_dopesheet_scene(bAnimContext *ac, ListBase *anim_d
return items;
}
+static size_t animdata_filter_ds_movieclip(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, MovieClip *clip, int filter_mode)
+{
+ ListBase tmp_data = {NULL, NULL};
+ size_t tmp_items = 0;
+ size_t items = 0;
+ /* add world animation channels */
+ BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_MCLIP(clip))
+ {
+ /* animation data filtering */
+ tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)clip, filter_mode);
+ }
+ END_ANIMFILTER_SUBCHANNELS;
+ /* did we find anything? */
+ if (tmp_items) {
+ /* include data-expand widget first */
+ if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
+ /* check if filtering by active status */
+ if (ANIMCHANNEL_ACTIVEOK(clip)) {
+ ANIMCHANNEL_NEW_CHANNEL(clip, ANIMTYPE_DSMCLIP, clip);
+ }
+ }
+ /* now add the list of collected channels */
+ BLI_movelisttolist(anim_data, &tmp_data);
+ BLI_assert(BLI_listbase_is_empty(&tmp_data));
+ items += tmp_items;
+ }
+ /* return the number of items added to the list */
+ return items;
+}
+
+static size_t animdata_filter_dopesheet_movieclips(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, int filter_mode)
+{
+ size_t items = 0;
+ MovieClip *clip;
+ for (clip = G.main->movieclip.first; clip != NULL; clip = clip->id.next) {
+ /* only show if gpd is used by something... */
+ if (ID_REAL_USERS(clip) < 1) {
+ continue;
+ }
+ items += animdata_filter_ds_movieclip(ac, anim_data, ads, clip, filter_mode);
+ }
+ /* return the number of items added to the list */
+ return items;
+}
+
+/* Helper for animdata_filter_dopesheet() - For checking if an object should be included or not */
+static bool animdata_filter_base_is_ok(bDopeSheet *ads, Scene *scene, Base *base, int filter_mode)
+{
+ Object *ob = base->object;
+
+ if (base->object == NULL)
+ return false;
+
+ /* firstly, check if object can be included, by the following factors:
+ * - if only visible, must check for layer and also viewport visibility
+ * --> while tools may demand only visible, user setting takes priority
+ * as user option controls whether sets of channels get included while
+ * tool-flag takes into account collapsed/open channels too
+ * - if only selected, must check if object is selected
+ * - there must be animation data to edit (this is done recursively as we
+ * try to add the channels)
+ */
+ if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
+ /* layer visibility - we check both object and base, since these may not be in sync yet */
+ if ((scene->lay & (ob->lay | base->lay)) == 0)
+ return false;
+
+ /* outliner restrict-flag */
+ if (ob->restrictflag & OB_RESTRICT_VIEW)
+ return false;
+ }
+
+ /* if only F-Curves with visible flags set can be shown, check that
+ * datablock hasn't been set to invisible
+ */
+ if (filter_mode & ANIMFILTER_CURVE_VISIBLE) {
+ if ((ob->adt) && (ob->adt->flag & ADT_CURVES_NOT_VISIBLE))
+ return false;
+ }
+
+ /* Pinned curves are visible regardless of selection flags. */
+ if ((ob->adt) && (ob->adt->flag & ADT_CURVES_ALWAYS_VISIBLE)) {
+ return true;
+ }
+
+ /* Special case.
+ * We don't do recursive checks for pin, but we need to deal with tricky
+ * setup like animated camera lens without animated camera location.
+ * Without such special handle here we wouldn't be able to bin such
+ * camera data only animation to the editor.
+ */
+ if (ob->adt == NULL && ob->data != NULL) {
+ AnimData *data_adt = BKE_animdata_from_id(ob->data);
+ if (data_adt != NULL && (data_adt->flag & ADT_CURVES_ALWAYS_VISIBLE)) {
+ return true;
+ }
+ }
+
+ /* check selection and object type filters */
+ if ((ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & SELECT) /*|| (base == sce->basact)*/)) {
+ /* only selected should be shown */
+ return false;
+ }
+
+ /* check if object belongs to the filtering group if option to filter
+ * objects by the grouped status is on
+ * - used to ease the process of doing multiple-character choreographies
+ */
+ if (ads->filterflag & ADS_FILTER_ONLYOBGROUP) {
+ if (BKE_group_object_exists(ads->filter_grp, ob) == 0)
+ return false;
+ }
+
+ /* no reason to exclude this object... */
+ return true;
+}
+
+/* Helper for animdata_filter_ds_sorted_bases() - Comparison callback for two Base pointers... */
+static int ds_base_sorting_cmp(const void *base1_ptr, const void *base2_ptr)
+{
+ const Base *b1 = *((const Base **)base1_ptr);
+ const Base *b2 = *((const Base **)base2_ptr);
+
+ return strcmp(b1->object->id.name + 2, b2->object->id.name + 2);
+}
+
+/* Get a sorted list of all the bases - for inclusion in dopesheet (when drawing channels) */
+static Base **animdata_filter_ds_sorted_bases(bDopeSheet *ads, Scene *scene, int filter_mode, size_t *r_usable_bases)
+{
+ /* Create an array with space for all the bases, but only containing the usable ones */
+ size_t tot_bases = BLI_listbase_count(&scene->base);
+ size_t num_bases = 0;
+
+ Base **sorted_bases = MEM_mallocN(sizeof(Base *) * tot_bases, "Dopesheet Usable Sorted Bases");
+ for (Base *base = scene->base.first; base; base = base->next) {
+ if (animdata_filter_base_is_ok(ads, scene, base, filter_mode)) {
+ sorted_bases[num_bases++] = base;
+ }
+ }
+
+ /* Sort this list of pointers (based on the names) */
+ qsort(sorted_bases, num_bases, sizeof(Base *), ds_base_sorting_cmp);
+
+ /* Return list of sorted bases */
+ *r_usable_bases = num_bases;
+ return sorted_bases;
+}
+
+
// TODO: implement pinning... (if and when pinning is done, what we need to do is to provide freeing mechanisms - to protect against data that was deleted)
static size_t animdata_filter_dopesheet(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, int filter_mode)
{
- Scene *sce = (Scene *)ads->source;
- Base *base;
+ Scene *scene = (Scene *)ads->source;
size_t items = 0;
/* check that we do indeed have a scene */
@@ -2728,57 +2978,55 @@ static size_t animdata_filter_dopesheet(bAnimContext *ac, ListBase *anim_data, b
filter_mode |= ANIMFILTER_SELEDIT;
}
+ /* Cache files level animations (frame duration and such). */
+ CacheFile *cache_file = G.main->cachefiles.first;
+ for (; cache_file; cache_file = cache_file->id.next) {
+ items += animdata_filter_ds_cachefile(ac, anim_data, ads, cache_file, filter_mode);
+ }
+
+ /* movie clip's animation */
+ items += animdata_filter_dopesheet_movieclips(ac, anim_data, ads, filter_mode);
+
/* scene-linked animation - e.g. world, compositing nodes, scene anim (including sequencer currently) */
- items += animdata_filter_dopesheet_scene(ac, anim_data, ads, sce, filter_mode);
-
- /* loop over all bases (i.e.objects) in the scene */
- for (base = sce->base.first; base; base = base->next) {
- /* check if there's an object (all the relevant checks are done in the ob-function) */
- if (base->object) {
- Object *ob = base->object;
-
- /* firstly, check if object can be included, by the following factors:
- * - if only visible, must check for layer and also viewport visibility
- * --> while tools may demand only visible, user setting takes priority
- * as user option controls whether sets of channels get included while
- * tool-flag takes into account collapsed/open channels too
- * - if only selected, must check if object is selected
- * - there must be animation data to edit (this is done recursively as we
- * try to add the channels)
- */
- if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
- /* layer visibility - we check both object and base, since these may not be in sync yet */
- if ((sce->lay & (ob->lay | base->lay)) == 0) continue;
-
- /* outliner restrict-flag */
- if (ob->restrictflag & OB_RESTRICT_VIEW) continue;
- }
-
- /* if only F-Curves with visible flags set can be shown, check that
- * datablock hasn't been set to invisible
- */
- if (filter_mode & ANIMFILTER_CURVE_VISIBLE) {
- if ((ob->adt) && (ob->adt->flag & ADT_CURVES_NOT_VISIBLE))
- continue;
+ items += animdata_filter_dopesheet_scene(ac, anim_data, ads, scene, filter_mode);
+
+ /* If filtering for channel drawing, we want the objects in alphabetical order,
+ * to make it easier to predict where items are in the hierarchy
+ * - This order only really matters if we need to show all channels in the list (e.g. for drawing)
+ * (XXX: What about lingering "active" flags? The order may now become unpredictable)
+ * - Don't do this if this behaviour has been turned off (i.e. due to it being too slow)
+ * - Don't do this if there's just a single object
+ */
+ if ((filter_mode & ANIMFILTER_LIST_CHANNELS) && !(ads->flag & ADS_FLAG_NO_DB_SORT) &&
+ (scene->base.first != scene->base.last))
+ {
+ /* Filter list of bases (i.e. objects), sort them, then add their contents normally... */
+ // TODO: Cache the old sorted order - if the set of bases hasn't changed, don't re-sort...
+ Base **sorted_bases;
+ size_t num_bases;
+
+ sorted_bases = animdata_filter_ds_sorted_bases(ads, scene, filter_mode, &num_bases);
+ if (sorted_bases) {
+ /* Add the necessary channels for these bases... */
+ for (size_t i = 0; i < num_bases; i++) {
+ items += animdata_filter_dopesheet_ob(ac, anim_data, ads, sorted_bases[i], filter_mode);
}
- /* check selection and object type filters */
- if ( (ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & SELECT) /*|| (base == sce->basact)*/) ) {
- /* only selected should be shown */
- continue;
- }
+ // TODO: store something to validate whether any changes are needed?
- /* check if object belongs to the filtering group if option to filter
- * objects by the grouped status is on
- * - used to ease the process of doing multiple-character choreographies
- */
- if (ads->filterflag & ADS_FILTER_ONLYOBGROUP) {
- if (BKE_group_object_exists(ads->filter_grp, ob) == 0)
- continue;
+ /* free temporary data */
+ MEM_freeN(sorted_bases);
+ }
+ }
+ else {
+ /* Filter and add contents of each base (i.e. object) without them sorting first
+ * NOTE: This saves performance in cases where order doesn't matter
+ */
+ for (Base *base = scene->base.first; base; base = base->next) {
+ if (animdata_filter_base_is_ok(ads, scene, base, filter_mode)) {
+ /* since we're still here, this object should be usable */
+ items += animdata_filter_dopesheet_ob(ac, anim_data, ads, base, filter_mode);
}
-
- /* since we're still here, this object should be usable */
- items += animdata_filter_dopesheet_ob(ac, anim_data, ads, base, filter_mode);
}
}
@@ -2850,7 +3098,11 @@ static size_t animdata_filter_animchan(bAnimContext *ac, ListBase *anim_data, bD
case ANIMTYPE_OBJECT:
items += animdata_filter_dopesheet_ob(ac, anim_data, ads, channel->data, filter_mode);
break;
-
+
+ case ANIMTYPE_DSCACHEFILE:
+ items += animdata_filter_ds_cachefile(ac, anim_data, ads, channel->data, filter_mode);
+ break;
+
case ANIMTYPE_ANIMDATA:
items += animfilter_block_data(ac, anim_data, ads, channel->id, filter_mode);
break;
diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c
index ae6894ac546..fc6f4036d02 100644
--- a/source/blender/editors/animation/anim_ipo_utils.c
+++ b/source/blender/editors/animation/anim_ipo_utils.c
@@ -192,7 +192,7 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu)
#define HSV_BANDWIDTH 0.3f
/* used to determine the color of F-Curves with FCURVE_COLOR_AUTO_RAINBOW set */
-//void fcurve_rainbow (unsigned int cur, unsigned int tot, float *out)
+// void fcurve_rainbow(unsigned int cur, unsigned int tot, float *out)
void getcolor_fcurve_rainbow(int cur, int tot, float out[3])
{
float hsv[3], fac;
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index 40376c38c3b..823cde75334 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -39,6 +39,8 @@
#include "BLI_math_base.h"
#include "BLI_utildefines.h"
+#include "BLT_translation.h"
+
#include "BKE_context.h"
#include "BKE_fcurve.h"
#include "BKE_main.h"
@@ -685,7 +687,7 @@ static void ed_marker_move_update_header(bContext *C, wmOperator *op)
MarkerMove *mm = op->customdata;
TimeMarker *marker, *selmarker = NULL;
const int offs = RNA_int_get(op->ptr, "frames");
- char str[256];
+ char str[UI_MAX_DRAW_STR];
char str_offs[NUM_STR_REP_LEN];
int totmark;
const bool use_time = ed_marker_move_use_time(mm);
@@ -710,14 +712,14 @@ static void ed_marker_move_update_header(bContext *C, wmOperator *op)
if (totmark == 1 && selmarker) {
/* we print current marker value */
if (use_time) {
- BLI_snprintf(str, sizeof(str), "Marker %.2f offset %s", FRA2TIME(selmarker->frame), str_offs);
+ BLI_snprintf(str, sizeof(str), IFACE_("Marker %.2f offset %s"), FRA2TIME(selmarker->frame), str_offs);
}
else {
- BLI_snprintf(str, sizeof(str), "Marker %d offset %s", selmarker->frame, str_offs);
+ BLI_snprintf(str, sizeof(str), IFACE_("Marker %d offset %s"), selmarker->frame, str_offs);
}
}
else {
- BLI_snprintf(str, sizeof(str), "Marker offset %s", str_offs);
+ BLI_snprintf(str, sizeof(str), IFACE_("Marker offset %s"), str_offs);
}
ED_area_headerprint(CTX_wm_area(C), str);
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index afc4e5c9e61..21c25f829b1 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -158,7 +158,7 @@ static int add_driver_with_target(
ReportList *UNUSED(reports),
ID *dst_id, const char dst_path[], int dst_index,
ID *src_id, const char src_path[], int src_index,
- PointerRNA *UNUSED(dst_ptr), PropertyRNA *dst_prop,
+ PointerRNA *dst_ptr, PropertyRNA *dst_prop,
PointerRNA *src_ptr, PropertyRNA *src_prop,
short flag, int driver_type)
{
@@ -207,11 +207,15 @@ static int add_driver_with_target(
/* Create a driver variable for the target
* - For transform properties, we want to automatically use "transform channel" instead
* (The only issue is with quat rotations vs euler channels...)
+ * - To avoid problems with transform properties depending on the final transform that they
+ * control (thus creating pseudo-cycles - see T48734), we don't use transform channels
+ * when both the source and destinations are in same places.
*/
dvar = driver_add_new_variable(driver);
if (ELEM(src_ptr->type, &RNA_Object, &RNA_PoseBone) &&
- (STREQ(prop_name, "location") || STREQ(prop_name, "scale") || STRPREFIX(prop_name, "rotation_")))
+ (STREQ(prop_name, "location") || STREQ(prop_name, "scale") || STRPREFIX(prop_name, "rotation_")) &&
+ (src_ptr->data != dst_ptr->data))
{
/* Transform Channel */
DriverTarget *dtar;
@@ -753,7 +757,7 @@ EnumPropertyItem prop_driver_create_mapping_types[] = {
"Create drivers for each pair of corresponding elements"},
{CREATEDRIVER_MAPPING_NONE_ALL, "NONE_ALL", ICON_HAND, "Manually Create Later",
- "Create drivers for all properites without assigning any targets yet"},
+ "Create drivers for all properties without assigning any targets yet"},
{CREATEDRIVER_MAPPING_NONE, "NONE_SINGLE", 0, "Manually Create Later (Single)",
"Create driver for this property only and without assigning any targets yet"},
{0, NULL, 0, NULL, NULL}
@@ -866,7 +870,7 @@ static int add_driver_button_exec(bContext *C, wmOperator *op)
}
/* Show menu or create drivers */
-static int add_driver_button_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int add_driver_button_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
PropertyRNA *prop;
@@ -877,7 +881,8 @@ static int add_driver_button_invoke(bContext *C, wmOperator *op, const wmEvent *
else {
/* Show menu */
// TODO: This should get filtered by the enum filter
- return WM_menu_invoke(C, op, event);
+ /* important to execute in the region we're currently in */
+ return WM_menu_invoke_ex(C, op, WM_OP_INVOKE_DEFAULT);
}
}
diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c
index 6f1883cff55..5f675e690b9 100644
--- a/source/blender/editors/animation/keyframes_draw.c
+++ b/source/blender/editors/animation/keyframes_draw.c
@@ -40,9 +40,11 @@
#include "MEM_guardedalloc.h"
#include "BLI_dlrbTree.h"
+#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "DNA_anim_types.h"
+#include "DNA_cachefile_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_gpencil_types.h"
@@ -282,6 +284,9 @@ static ActKeyBlock *bezts_to_new_actkeyblock(BezTriple *prev, BezTriple *beztn)
ab->sel = (BEZT_ISSEL_ANY(prev) || BEZT_ISSEL_ANY(beztn)) ? SELECT : 0;
ab->modified = 1;
+ if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD)
+ ab->flag |= ACTKEYBLOCK_FLAG_MOVING_HOLD;
+
return ab;
}
@@ -305,16 +310,28 @@ static void add_bezt_to_keyblocks_list(DLRBT_Tree *blocks, BezTriple *first_bezt
}
- /* check if block needed - same value(s)?
- * -> firstly, handles must have same central value as each other
- * -> secondly, handles which control that section of the curve must be constant
- */
+ /* check if block needed */
if (prev == NULL) return;
- if (IS_EQF(beztn->vec[1][1], prev->vec[1][1]) == 0) return;
-
- if (IS_EQF(beztn->vec[1][1], beztn->vec[0][1]) == 0) return;
- if (IS_EQF(prev->vec[1][1], prev->vec[2][1]) == 0) return;
+ if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD) {
+ /* Animator tagged a "moving hold"
+ * - Previous key must also be tagged as a moving hold, otherwise
+ * we're just dealing with the first of a pair, and we don't
+ * want to be creating any phantom holds...
+ */
+ if (BEZKEYTYPE(prev) != BEZT_KEYTYPE_MOVEHOLD)
+ return;
+ }
+ else {
+ /* Check for same values...
+ * - Handles must have same central value as each other
+ * - Handles which control that section of the curve must be constant
+ */
+ if (IS_EQF(beztn->vec[1][1], prev->vec[1][1]) == 0) return;
+
+ if (IS_EQF(beztn->vec[1][1], beztn->vec[0][1]) == 0) return;
+ if (IS_EQF(prev->vec[1][1], prev->vec[2][1]) == 0) return;
+ }
/* if there are no blocks already, just add as root */
if (blocks->root == NULL) {
@@ -340,7 +357,13 @@ static void add_bezt_to_keyblocks_list(DLRBT_Tree *blocks, BezTriple *first_bezt
*/
if (IS_EQT(ab->start, prev->vec[1][0], BEZT_BINARYSEARCH_THRESH)) {
/* set selection status and 'touched' status */
- if (BEZT_ISSEL_ANY(beztn)) ab->sel = SELECT;
+ if (BEZT_ISSEL_ANY(beztn))
+ ab->sel = SELECT;
+
+ /* XXX: only when the first one was a moving hold? */
+ if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD)
+ ab->flag |= ACTKEYBLOCK_FLAG_MOVING_HOLD;
+
ab->modified++;
/* done... no need to insert */
@@ -485,7 +508,27 @@ void draw_keyframe_shape(float x, float y, float xscale, float hsize, short sel,
/* tweak size of keyframe shape according to type of keyframe
* - 'proper' keyframes have key_type = 0, so get drawn at full size
*/
- hsize -= 0.5f * key_type;
+ switch (key_type) {
+ case BEZT_KEYTYPE_KEYFRAME: /* must be full size */
+ break;
+
+ case BEZT_KEYTYPE_BREAKDOWN: /* slightly smaller than normal keyframe */
+ hsize *= 0.85f;
+ break;
+
+ case BEZT_KEYTYPE_MOVEHOLD: /* slightly smaller than normal keyframes (but by less than for breakdowns) */
+ //hsize *= 0.72f;
+ hsize *= 0.95f;
+ break;
+
+ case BEZT_KEYTYPE_EXTREME: /* slightly larger */
+ hsize *= 1.2f;
+ break;
+
+ default:
+ hsize -= 0.5f * key_type;
+ break;
+ }
/* adjust view transform before starting */
glTranslatef(x, y, 0.0f);
@@ -518,6 +561,15 @@ void draw_keyframe_shape(float x, float y, float xscale, float hsize, short sel,
else UI_GetThemeColor4fv(TH_KEYTYPE_JITTER, inner_col);
break;
}
+ case BEZT_KEYTYPE_MOVEHOLD: /* similar to traditional keyframes, but different... */
+ {
+ /* XXX: Should these get their own theme options instead? */
+ if (sel) UI_GetThemeColorShade4fv(TH_STRIP_SELECT, 35, inner_col);
+ else UI_GetThemeColorShade4fv(TH_STRIP, 50, inner_col);
+
+ inner_col[3] = 1.0f; /* full opacity, to avoid problems with visual glitches */
+ break;
+ }
case BEZT_KEYTYPE_KEYFRAME: /* traditional yellowish frames (default theme) */
default:
{
@@ -557,13 +609,16 @@ void draw_keyframe_shape(float x, float y, float xscale, float hsize, short sel,
glTranslatef(-x, -y, 0.0f);
}
-static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, DLRBT_Tree *blocks, float ypos, short channelLocked)
+static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, DLRBT_Tree *blocks, float ypos, float yscale_fac, bool channelLocked)
{
ActKeyColumn *ak;
ActKeyBlock *ab;
float alpha;
float xscale;
- float iconsize = U.widget_unit / 4.0f;
+
+ const float iconsize = (U.widget_unit / 4.0f) * yscale_fac;
+ const float mhsize = iconsize * 0.7f;
+
glEnable(GL_BLEND);
/* get View2D scaling factor */
@@ -576,6 +631,7 @@ static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, DLRBT_Tree *blocks, floa
/* draw keyblocks */
if (blocks) {
float sel_color[4], unsel_color[4];
+ float sel_mhcol[4], unsel_mhcol[4];
/* cache colours first */
UI_GetThemeColor4fv(TH_STRIP_SELECT, sel_color);
@@ -584,16 +640,32 @@ static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, DLRBT_Tree *blocks, floa
sel_color[3] *= alpha;
unsel_color[3] *= alpha;
+ copy_v4_v4(sel_mhcol, sel_color);
+ sel_mhcol[3] *= 0.8f;
+ copy_v4_v4(unsel_mhcol, unsel_color);
+ unsel_mhcol[3] *= 0.8f;
+
/* NOTE: the tradeoff for changing colors between each draw is dwarfed by the cost of checking validity */
for (ab = blocks->first; ab; ab = ab->next) {
if (actkeyblock_is_valid(ab, keys)) {
- /* draw block */
- if (ab->sel)
- glColor4fv(sel_color);
- else
- glColor4fv(unsel_color);
-
- glRectf(ab->start, ypos - iconsize, ab->end, ypos + iconsize);
+ if (ab->flag & ACTKEYBLOCK_FLAG_MOVING_HOLD) {
+ /* draw "moving hold" long-keyframe block - slightly smaller */
+ if (ab->sel)
+ glColor4fv(sel_mhcol);
+ else
+ glColor4fv(unsel_mhcol);
+
+ glRectf(ab->start, ypos - mhsize, ab->end, ypos + mhsize);
+ }
+ else {
+ /* draw standard long-keyframe block */
+ if (ab->sel)
+ glColor4fv(sel_color);
+ else
+ glColor4fv(unsel_color);
+
+ glRectf(ab->start, ypos - iconsize, ab->end, ypos + iconsize);
+ }
}
}
}
@@ -619,7 +691,7 @@ static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, DLRBT_Tree *blocks, floa
/* *************************** Channel Drawing Funcs *************************** */
-void draw_summary_channel(View2D *v2d, bAnimContext *ac, float ypos)
+void draw_summary_channel(View2D *v2d, bAnimContext *ac, float ypos, float yscale_fac)
{
DLRBT_Tree keys, blocks;
@@ -631,13 +703,13 @@ void draw_summary_channel(View2D *v2d, bAnimContext *ac, float ypos)
BLI_dlrbTree_linkedlist_sync(&keys);
BLI_dlrbTree_linkedlist_sync(&blocks);
- draw_keylist(v2d, &keys, &blocks, ypos, 0);
+ draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, false);
BLI_dlrbTree_free(&keys);
BLI_dlrbTree_free(&blocks);
}
-void draw_scene_channel(View2D *v2d, bDopeSheet *ads, Scene *sce, float ypos)
+void draw_scene_channel(View2D *v2d, bDopeSheet *ads, Scene *sce, float ypos, float yscale_fac)
{
DLRBT_Tree keys, blocks;
@@ -649,13 +721,13 @@ void draw_scene_channel(View2D *v2d, bDopeSheet *ads, Scene *sce, float ypos)
BLI_dlrbTree_linkedlist_sync(&keys);
BLI_dlrbTree_linkedlist_sync(&blocks);
- draw_keylist(v2d, &keys, &blocks, ypos, 0);
+ draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, false);
BLI_dlrbTree_free(&keys);
BLI_dlrbTree_free(&blocks);
}
-void draw_object_channel(View2D *v2d, bDopeSheet *ads, Object *ob, float ypos)
+void draw_object_channel(View2D *v2d, bDopeSheet *ads, Object *ob, float ypos, float yscale_fac)
{
DLRBT_Tree keys, blocks;
@@ -667,19 +739,19 @@ void draw_object_channel(View2D *v2d, bDopeSheet *ads, Object *ob, float ypos)
BLI_dlrbTree_linkedlist_sync(&keys);
BLI_dlrbTree_linkedlist_sync(&blocks);
- draw_keylist(v2d, &keys, &blocks, ypos, 0);
+ draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, false);
BLI_dlrbTree_free(&keys);
BLI_dlrbTree_free(&blocks);
}
-void draw_fcurve_channel(View2D *v2d, AnimData *adt, FCurve *fcu, float ypos)
+void draw_fcurve_channel(View2D *v2d, AnimData *adt, FCurve *fcu, float ypos, float yscale_fac)
{
DLRBT_Tree keys, blocks;
- short locked = (fcu->flag & FCURVE_PROTECTED) ||
- ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)) ||
- ((adt && adt->action) && (adt->action->id.lib));
+ bool locked = (fcu->flag & FCURVE_PROTECTED) ||
+ ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)) ||
+ ((adt && adt->action) && ID_IS_LINKED_DATABLOCK(adt->action));
BLI_dlrbTree_init(&keys);
BLI_dlrbTree_init(&blocks);
@@ -689,18 +761,18 @@ void draw_fcurve_channel(View2D *v2d, AnimData *adt, FCurve *fcu, float ypos)
BLI_dlrbTree_linkedlist_sync(&keys);
BLI_dlrbTree_linkedlist_sync(&blocks);
- draw_keylist(v2d, &keys, &blocks, ypos, locked);
+ draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, locked);
BLI_dlrbTree_free(&keys);
BLI_dlrbTree_free(&blocks);
}
-void draw_agroup_channel(View2D *v2d, AnimData *adt, bActionGroup *agrp, float ypos)
+void draw_agroup_channel(View2D *v2d, AnimData *adt, bActionGroup *agrp, float ypos, float yscale_fac)
{
DLRBT_Tree keys, blocks;
- short locked = (agrp->flag & AGRP_PROTECTED) ||
- ((adt && adt->action) && (adt->action->id.lib));
+ bool locked = (agrp->flag & AGRP_PROTECTED) ||
+ ((adt && adt->action) && ID_IS_LINKED_DATABLOCK(adt->action));
BLI_dlrbTree_init(&keys);
BLI_dlrbTree_init(&blocks);
@@ -710,17 +782,17 @@ void draw_agroup_channel(View2D *v2d, AnimData *adt, bActionGroup *agrp, float y
BLI_dlrbTree_linkedlist_sync(&keys);
BLI_dlrbTree_linkedlist_sync(&blocks);
- draw_keylist(v2d, &keys, &blocks, ypos, locked);
+ draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, locked);
BLI_dlrbTree_free(&keys);
BLI_dlrbTree_free(&blocks);
}
-void draw_action_channel(View2D *v2d, AnimData *adt, bAction *act, float ypos)
+void draw_action_channel(View2D *v2d, AnimData *adt, bAction *act, float ypos, float yscale_fac)
{
DLRBT_Tree keys, blocks;
- short locked = (act && act->id.lib != NULL);
+ bool locked = (act && ID_IS_LINKED_DATABLOCK(act));
BLI_dlrbTree_init(&keys);
BLI_dlrbTree_init(&blocks);
@@ -730,13 +802,13 @@ void draw_action_channel(View2D *v2d, AnimData *adt, bAction *act, float ypos)
BLI_dlrbTree_linkedlist_sync(&keys);
BLI_dlrbTree_linkedlist_sync(&blocks);
- draw_keylist(v2d, &keys, &blocks, ypos, locked);
+ draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, locked);
BLI_dlrbTree_free(&keys);
BLI_dlrbTree_free(&blocks);
}
-void draw_gpencil_channel(View2D *v2d, bDopeSheet *ads, bGPdata *gpd, float ypos)
+void draw_gpencil_channel(View2D *v2d, bDopeSheet *ads, bGPdata *gpd, float ypos, float yscale_fac)
{
DLRBT_Tree keys;
@@ -746,38 +818,42 @@ void draw_gpencil_channel(View2D *v2d, bDopeSheet *ads, bGPdata *gpd, float ypos
BLI_dlrbTree_linkedlist_sync(&keys);
- draw_keylist(v2d, &keys, NULL, ypos, 0);
+ draw_keylist(v2d, &keys, NULL, ypos, yscale_fac, false);
BLI_dlrbTree_free(&keys);
}
-void draw_gpl_channel(View2D *v2d, bDopeSheet *ads, bGPDlayer *gpl, float ypos)
+void draw_gpl_channel(View2D *v2d, bDopeSheet *ads, bGPDlayer *gpl, float ypos, float yscale_fac)
{
DLRBT_Tree keys;
+ bool locked = (gpl->flag & GP_LAYER_LOCKED) != 0;
+
BLI_dlrbTree_init(&keys);
gpl_to_keylist(ads, gpl, &keys);
BLI_dlrbTree_linkedlist_sync(&keys);
- draw_keylist(v2d, &keys, NULL, ypos, (gpl->flag & GP_LAYER_LOCKED));
+ draw_keylist(v2d, &keys, NULL, ypos, yscale_fac, locked);
BLI_dlrbTree_free(&keys);
}
-void draw_masklay_channel(View2D *v2d, bDopeSheet *ads, MaskLayer *masklay, float ypos)
+void draw_masklay_channel(View2D *v2d, bDopeSheet *ads, MaskLayer *masklay, float ypos, float yscale_fac)
{
DLRBT_Tree keys;
-
+
+ bool locked = (masklay->flag & MASK_LAYERFLAG_LOCKED) != 0;
+
BLI_dlrbTree_init(&keys);
-
+
mask_to_keylist(ads, masklay, &keys);
-
+
BLI_dlrbTree_linkedlist_sync(&keys);
-
- draw_keylist(v2d, &keys, NULL, ypos, (masklay->flag & MASK_LAYERFLAG_LOCKED));
-
+
+ draw_keylist(v2d, &keys, NULL, ypos, yscale_fac, locked);
+
BLI_dlrbTree_free(&keys);
}
@@ -890,6 +966,37 @@ void ob_to_keylist(bDopeSheet *ads, Object *ob, DLRBT_Tree *keys, DLRBT_Tree *bl
ANIM_animdata_freelist(&anim_data);
}
+void cachefile_to_keylist(bDopeSheet *ads, CacheFile *cache_file, DLRBT_Tree *keys, DLRBT_Tree *blocks)
+{
+ if (cache_file == NULL) {
+ return;
+ }
+
+ /* create a dummy wrapper data to work with */
+ bAnimListElem dummychan = {NULL};
+ dummychan.type = ANIMTYPE_DSCACHEFILE;
+ dummychan.data = cache_file;
+ dummychan.id = &cache_file->id;
+ dummychan.adt = cache_file->adt;
+
+ bAnimContext ac = {NULL};
+ ac.ads = ads;
+ ac.data = &dummychan;
+ ac.datatype = ANIMCONT_CHANNEL;
+
+ /* get F-Curves to take keyframes from */
+ ListBase anim_data = { NULL, NULL };
+ int filter = ANIMFILTER_DATA_VISIBLE; // curves only
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ /* loop through each F-Curve, grabbing the keyframes */
+ for (bAnimListElem *ale = anim_data.first; ale; ale = ale->next) {
+ fcurve_to_keylist(ale->adt, ale->data, keys, blocks);
+ }
+
+ ANIM_animdata_freelist(&anim_data);
+}
+
void fcurve_to_keylist(AnimData *adt, FCurve *fcu, DLRBT_Tree *keys, DLRBT_Tree *blocks)
{
BezTriple *bezt;
diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c
index 08a7355694b..4571df0f077 100644
--- a/source/blender/editors/animation/keyframes_edit.c
+++ b/source/blender/editors/animation/keyframes_edit.c
@@ -539,10 +539,10 @@ static short ok_bezier_region(KeyframeEditData *ked, BezTriple *bezt)
}
/**
- * only called from #ok_bezier_region_lasso
+ * Called from #ok_bezier_region_lasso and #ok_bezier_channel_lasso
*/
-static bool bezier_region_lasso_test(
- const struct KeyframeEdit_LassoData *data_lasso,
+bool keyframe_region_lasso_test(
+ const KeyframeEdit_LassoData *data_lasso,
const float xy[2])
{
if (BLI_rctf_isect_pt_v(data_lasso->rectf_scaled, xy)) {
@@ -564,7 +564,7 @@ static short ok_bezier_region_lasso(KeyframeEditData *ked, BezTriple *bezt)
if (ked->data) {
short ok = 0;
-#define KEY_CHECK_OK(_index) bezier_region_lasso_test(ked->data, bezt->vec[_index])
+#define KEY_CHECK_OK(_index) keyframe_region_lasso_test(ked->data, bezt->vec[_index])
KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
#undef KEY_CHECK_OK
@@ -575,11 +575,38 @@ static short ok_bezier_region_lasso(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
+static short ok_bezier_channel_lasso(KeyframeEditData *ked, BezTriple *bezt)
+{
+ /* check for lasso customdata (KeyframeEdit_LassoData) */
+ if (ked->data) {
+ KeyframeEdit_LassoData *data = ked->data;
+ float pt[2];
+
+ /* late-binding remap of the x values (for summary channels) */
+ /* XXX: Ideally we reset, but it should be fine just leaving it as-is
+ * as the next channel will reset it properly, while the next summary-channel
+ * curve will also reset by itself...
+ */
+ if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) {
+ data->rectf_scaled->xmin = ked->f1;
+ data->rectf_scaled->xmax = ked->f2;
+ }
+
+ /* only use the x-coordinate of the point; the y is the channel range... */
+ pt[0] = bezt->vec[1][0];
+ pt[1] = ked->channel_y;
+
+ if (keyframe_region_lasso_test(data, pt))
+ return KEYFRAME_OK_KEY;
+ }
+ return 0;
+}
+
/**
- * only called from #ok_bezier_region_circle
+ * Called from #ok_bezier_region_circle and #ok_bezier_channel_circle
*/
-static bool bezier_region_circle_test(
- const struct KeyframeEdit_CircleData *data_circle,
+bool keyframe_region_circle_test(
+ const KeyframeEdit_CircleData *data_circle,
const float xy[2])
{
if (BLI_rctf_isect_pt_v(data_circle->rectf_scaled, xy)) {
@@ -602,7 +629,7 @@ static short ok_bezier_region_circle(KeyframeEditData *ked, BezTriple *bezt)
if (ked->data) {
short ok = 0;
-#define KEY_CHECK_OK(_index) bezier_region_circle_test(ked->data, bezt->vec[_index])
+#define KEY_CHECK_OK(_index) keyframe_region_circle_test(ked->data, bezt->vec[_index])
KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
#undef KEY_CHECK_OK
@@ -613,6 +640,33 @@ static short ok_bezier_region_circle(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
+static short ok_bezier_channel_circle(KeyframeEditData *ked, BezTriple *bezt)
+{
+ /* check for circle select customdata (KeyframeEdit_CircleData) */
+ if (ked->data) {
+ KeyframeEdit_CircleData *data = ked->data;
+ float pt[2];
+
+ /* late-binding remap of the x values (for summary channels) */
+ /* XXX: Ideally we reset, but it should be fine just leaving it as-is
+ * as the next channel will reset it properly, while the next summary-channel
+ * curve will also reset by itself...
+ */
+ if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) {
+ data->rectf_scaled->xmin = ked->f1;
+ data->rectf_scaled->xmax = ked->f2;
+ }
+
+ /* only use the x-coordinate of the point; the y is the channel range... */
+ pt[0] = bezt->vec[1][0];
+ pt[1] = ked->channel_y;
+
+ if (keyframe_region_circle_test(data, pt))
+ return KEYFRAME_OK_KEY;
+ }
+ return 0;
+}
+
KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
{
@@ -634,6 +688,10 @@ KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
return ok_bezier_region_lasso;
case BEZT_OK_REGION_CIRCLE: /* only if the point falls within KeyframeEdit_CircleData defined data */
return ok_bezier_region_circle;
+ case BEZT_OK_CHANNEL_LASSO: /* same as BEZT_OK_REGION_LASSO, but we're only using the x-value of the points */
+ return ok_bezier_channel_lasso;
+ case BEZT_OK_CHANNEL_CIRCLE: /* same as BEZT_OK_REGION_CIRCLE, but we're only using the x-value of the points */
+ return ok_bezier_channel_circle;
default: /* nothing was ok */
return NULL;
}
@@ -1150,6 +1208,13 @@ static short set_keytype_jitter(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
return 0;
}
+static short set_keytype_moving_hold(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
+{
+ if (bezt->f2 & SELECT)
+ BEZKEYTYPE(bezt) = BEZT_KEYTYPE_MOVEHOLD;
+ return 0;
+}
+
/* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
KeyframeEditFunc ANIM_editkeyframes_keytype(short code)
{
@@ -1163,6 +1228,9 @@ KeyframeEditFunc ANIM_editkeyframes_keytype(short code)
case BEZT_KEYTYPE_JITTER: /* jitter keyframe */
return set_keytype_jitter;
+ case BEZT_KEYTYPE_MOVEHOLD: /* moving hold */
+ return set_keytype_moving_hold;
+
case BEZT_KEYTYPE_KEYFRAME: /* proper keyframe */
default:
return set_keytype_keyframe;
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 6a19cf679be..f2a35bb1553 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -930,11 +930,18 @@ bool insert_keyframe_direct(ReportList *reports, PointerRNA ptr, PropertyRNA *pr
/* update F-Curve flags to ensure proper behaviour for property type */
update_autoflags_fcurve_direct(fcu, prop);
-
+
/* adjust frame on which to add keyframe */
if ((flag & INSERTKEY_DRIVER) && (fcu->driver)) {
- /* for making it easier to add corrective drivers... */
- cfra = evaluate_driver(fcu->driver, cfra);
+ PathResolvedRNA anim_rna;
+
+ if (RNA_path_resolved_create(&ptr, prop, fcu->array_index, &anim_rna)) {
+ /* for making it easier to add corrective drivers... */
+ cfra = evaluate_driver(&anim_rna, fcu->driver, cfra);
+ }
+ else {
+ cfra = 0.0f;
+ }
}
/* obtain value to give keyframe */
@@ -1069,6 +1076,9 @@ short insert_keyframe(ReportList *reports, ID *id, bAction *act, const char grou
if (ELEM(RNA_property_subtype(prop), PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR, PROP_COORDS)) {
fcu->color_mode = FCURVE_COLOR_AUTO_RGB;
}
+ else if (RNA_property_subtype(prop), PROP_QUATERNION) {
+ fcu->color_mode = FCURVE_COLOR_AUTO_YRGB;
+ }
}
/* insert keyframe */
@@ -1761,8 +1771,10 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
flag = ANIM_get_keyframing_flags(scene, 1);
/* try to insert keyframe using property retrieved from UI */
- but = UI_context_active_but_get(C);
- UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+ if (!(but = UI_context_active_but_prop_get(C, &ptr, &prop, &index))) {
+ /* pass event on if no active button found */
+ return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
+ }
if ((ptr.id.data && ptr.data && prop) && RNA_property_animateable(&ptr, prop)) {
if (ptr.type == &RNA_NlaStrip) {
@@ -1863,7 +1875,10 @@ static int delete_key_button_exec(bContext *C, wmOperator *op)
const bool all = RNA_boolean_get(op->ptr, "all");
/* try to insert keyframe using property retrieved from UI */
- UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+ if (!UI_context_active_but_prop_get(C, &ptr, &prop, &index)) {
+ /* pass event on if no active button found */
+ return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
+ }
if (ptr.id.data && ptr.data && prop) {
if (ptr.type == &RNA_NlaStrip) {
@@ -1963,7 +1978,10 @@ static int clear_key_button_exec(bContext *C, wmOperator *op)
const bool all = RNA_boolean_get(op->ptr, "all");
/* try to insert keyframe using property retrieved from UI */
- UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+ if (!UI_context_active_but_prop_get(C, &ptr, &prop, &index)) {
+ /* pass event on if no active button found */
+ return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
+ }
if (ptr.id.data && ptr.data && prop) {
path = RNA_path_from_ID_to_property(&ptr, prop);
@@ -2024,17 +2042,25 @@ bool autokeyframe_cfra_can_key(Scene *scene, ID *id)
/* only filter if auto-key mode requires this */
if (IS_AUTOKEY_ON(scene) == 0)
return false;
-
- if (IS_AUTOKEY_MODE(scene, NORMAL)) {
- /* can insert anytime we like... */
- return true;
- }
- else { /* REPLACE */
- /* for whole block - only key if there's a keyframe on that frame already
- * this is a valid assumption when we're blocking + tweaking
+
+ if (IS_AUTOKEY_MODE(scene, EDITKEYS)) {
+ /* Replace Mode:
+ * For whole block, only key if there's a keyframe on that frame already
+ * This is a valid assumption when we're blocking + tweaking
*/
return id_frame_has_keyframe(id, cfra, ANIMFILTER_KEYS_LOCAL);
}
+ else {
+ /* Normal Mode (or treat as being normal mode):
+ *
+ * Just in case the flags aren't set properly (i.e. only on/off is set, without a mode)
+ * let's set the "normal" flag too, so that it will all be sane everywhere...
+ */
+ scene->toolsettings->autokey_mode = AUTOKEY_MODE_NORMAL;
+
+ /* Can insert anytime we like... */
+ return true;
+ }
}
/* ******************************************* */
diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c
index b907ad150aa..4408ec26b3f 100644
--- a/source/blender/editors/animation/keyingsets.c
+++ b/source/blender/editors/animation/keyingsets.c
@@ -296,6 +296,12 @@ static int add_keyingset_button_exec(bContext *C, wmOperator *op)
int index = 0, pflag = 0;
const bool all = RNA_boolean_get(op->ptr, "all");
+ /* try to add to keyingset using property retrieved from UI */
+ if (!UI_context_active_but_prop_get(C, &ptr, &prop, &index)) {
+ /* pass event on if no active button found */
+ return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
+ }
+
/* verify the Keying Set to use:
* - use the active one for now (more control over this can be added later)
* - add a new one if it doesn't exist
@@ -326,9 +332,6 @@ static int add_keyingset_button_exec(bContext *C, wmOperator *op)
ks = BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1);
}
- /* try to add to keyingset using property retrieved from UI */
- UI_context_active_but_prop_get(C, &ptr, &prop, &index);
-
/* check if property is able to be added */
if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
path = RNA_path_from_ID_to_property(&ptr, prop);
@@ -396,6 +399,12 @@ static int remove_keyingset_button_exec(bContext *C, wmOperator *op)
short success = 0;
int index = 0;
+ /* try to add to keyingset using property retrieved from UI */
+ if (UI_context_active_but_prop_get(C, &ptr, &prop, &index)) {
+ /* pass event on if no active button found */
+ return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
+ }
+
/* verify the Keying Set to use:
* - use the active one for now (more control over this can be added later)
* - return error if it doesn't exist
@@ -412,9 +421,6 @@ static int remove_keyingset_button_exec(bContext *C, wmOperator *op)
ks = BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1);
}
- /* try to add to keyingset using property retrieved from UI */
- UI_context_active_but_prop_get(C, &ptr, &prop, &index);
-
if (ptr.id.data && ptr.data && prop) {
path = RNA_path_from_ID_to_property(&ptr, prop);
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index 218f215a350..559d93c7eb1 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -83,6 +83,15 @@ EditBone *ED_armature_edit_bone_add(bArmature *arm, const char *name)
bone->segments = 1;
bone->layer = arm->layer;
+ bone->roll1 = 0.0f;
+ bone->roll2 = 0.0f;
+ bone->curveInX = 0.0f;
+ bone->curveInY = 0.0f;
+ bone->curveOutX = 0.0f;
+ bone->curveOutY = 0.0f;
+ bone->scaleIn = 1.0f;
+ bone->scaleOut = 1.0f;
+
return bone;
}
@@ -291,12 +300,8 @@ void preEditBoneDuplicate(ListBase *editbones)
/**
* Helper function for #postEditBoneDuplicate,
* return the destination pchan from the original.
- *
- * \param use_orig_fallback: return the input value if no new channel is found.
*/
-static bPoseChannel *pchan_duplicate_map(
- const bPose *pose, GHash *name_map,
- bPoseChannel *pchan_src, bool use_orig_fallback)
+static bPoseChannel *pchan_duplicate_map(const bPose *pose, GHash *name_map, bPoseChannel *pchan_src)
{
bPoseChannel *pchan_dst = NULL;
const char *name_src = pchan_src->name;
@@ -305,7 +310,7 @@ static bPoseChannel *pchan_duplicate_map(
pchan_dst = BKE_pose_channel_find_name(pose, name_dst);
}
- if ((pchan_dst == NULL) && use_orig_fallback) {
+ if (pchan_dst == NULL) {
pchan_dst = pchan_src;
}
@@ -325,6 +330,9 @@ void postEditBoneDuplicate(struct ListBase *editbones, Object *ob)
for (EditBone *ebone_src = editbones->first; ebone_src; ebone_src = ebone_src->next) {
EditBone *ebone_dst = ebone_src->temp.ebone;
+ if (!ebone_dst) {
+ ebone_dst = ED_armature_bone_get_mirrored(editbones, ebone_src);
+ }
if (ebone_dst) {
BLI_ghash_insert(name_map, ebone_src->name, ebone_dst->name);
}
@@ -338,7 +346,13 @@ void postEditBoneDuplicate(struct ListBase *editbones, Object *ob)
bPoseChannel *pchan_dst = BKE_pose_channel_find_name(ob->pose, ebone_dst->name);
if (pchan_dst) {
if (pchan_src->custom_tx) {
- pchan_dst->custom_tx = pchan_duplicate_map(ob->pose, name_map, pchan_src->custom_tx, true);
+ pchan_dst->custom_tx = pchan_duplicate_map(ob->pose, name_map, pchan_src->custom_tx);
+ }
+ if (pchan_src->bbone_prev) {
+ pchan_dst->bbone_prev = pchan_duplicate_map(ob->pose, name_map, pchan_src->bbone_prev);
+ }
+ if (pchan_src->bbone_next) {
+ pchan_dst->bbone_next = pchan_duplicate_map(ob->pose, name_map, pchan_src->bbone_next);
}
}
}
@@ -682,7 +696,7 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
}
}
- /* Run though the list and fix the pointers */
+ /* Run through the list and fix the pointers */
for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
if (ebone_iter->temp.ebone) {
/* copy all flags except for ... */
@@ -891,6 +905,16 @@ static int armature_extrude_exec(bContext *C, wmOperator *op)
newbone->segments = 1;
newbone->layer = ebone->layer;
+ newbone->roll1 = ebone->roll1;
+ newbone->roll2 = ebone->roll2;
+ newbone->curveInX = ebone->curveInX;
+ newbone->curveInY = ebone->curveInY;
+ newbone->curveOutX = ebone->curveOutX;
+ newbone->curveOutY = ebone->curveOutY;
+ newbone->scaleIn = ebone->scaleIn;
+ newbone->scaleOut = ebone->scaleOut;
+
+
BLI_strncpy(newbone->name, ebone->name, sizeof(newbone->name));
if (flipbone && forked) { // only set if mirror edit
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
index b1c23fb4cac..ece0f18e96e 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -317,9 +317,10 @@ static int armature_calc_roll_exec(bContext *C, wmOperator *op)
float cursor_local[3];
const float *cursor = ED_view3d_cursor3d_get(scene, v3d);
-
+ invert_m4_m4(ob->imat, ob->obmat);
copy_v3_v3(cursor_local, cursor);
- mul_m3_v3(imat, cursor_local);
+ mul_m4_v3(ob->imat, cursor_local);
+
/* cursor */
for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
@@ -409,6 +410,7 @@ static int armature_calc_roll_exec(bContext *C, wmOperator *op)
if (type < 3) vec[type] = 1.0f;
else vec[type - 2] = -1.0f;
mul_m3_v3(imat, vec);
+ normalize_v3(vec);
}
if (axis_flip) negate_v3(vec);
diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h
index ac150b9af74..b39b4bd81ee 100644
--- a/source/blender/editors/armature/armature_intern.h
+++ b/source/blender/editors/armature/armature_intern.h
@@ -170,6 +170,11 @@ typedef struct tPChanFCurveLink {
float oldangle;
float oldaxis[3];
+ float roll1, roll2; /* old bbone values (to be restored along with the transform properties) */
+ float curveInX, curveInY; /* (NOTE: we haven't renamed these this time, as their names are already long enough) */
+ float curveOutX, curveOutY;
+ float scaleIn, scaleOut;
+
struct IDProperty *oldprops; /* copy of custom properties at start of operator (to be restored before each modal step) */
} tPChanFCurveLink;
@@ -196,6 +201,7 @@ void POSELIB_OT_action_sanitize(struct wmOperatorType *ot);
void POSELIB_OT_pose_add(struct wmOperatorType *ot);
void POSELIB_OT_pose_remove(struct wmOperatorType *ot);
void POSELIB_OT_pose_rename(struct wmOperatorType *ot);
+void POSELIB_OT_pose_move(struct wmOperatorType *ot);
void POSELIB_OT_browse_interactive(struct wmOperatorType *ot);
void POSELIB_OT_apply_pose(struct wmOperatorType *ot);
diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c
index ed5f96a5829..5622cd0437d 100644
--- a/source/blender/editors/armature/armature_ops.c
+++ b/source/blender/editors/armature/armature_ops.c
@@ -151,6 +151,7 @@ void ED_operatortypes_armature(void)
WM_operatortype_append(POSELIB_OT_pose_add);
WM_operatortype_append(POSELIB_OT_pose_remove);
WM_operatortype_append(POSELIB_OT_pose_rename);
+ WM_operatortype_append(POSELIB_OT_pose_move);
WM_operatortype_append(POSELIB_OT_new);
WM_operatortype_append(POSELIB_OT_unlink);
diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c
index 85c6835a8bb..6979a324b69 100644
--- a/source/blender/editors/armature/armature_utils.c
+++ b/source/blender/editors/armature/armature_utils.c
@@ -367,6 +367,8 @@ void transform_armature_mirror_update(Object *obedit)
eboflip->tail[2] = ebo->tail[2];
eboflip->rad_tail = ebo->rad_tail;
eboflip->roll = -ebo->roll;
+ eboflip->curveOutX = -ebo->curveOutX;
+ eboflip->roll2 = -ebo->roll2;
/* Also move connected children, in case children's name aren't mirrored properly */
for (children = arm->edbo->first; children; children = children->next) {
@@ -382,6 +384,8 @@ void transform_armature_mirror_update(Object *obedit)
eboflip->head[2] = ebo->head[2];
eboflip->rad_head = ebo->rad_head;
eboflip->roll = -ebo->roll;
+ eboflip->curveInX = -ebo->curveInX;
+ eboflip->roll1 = -ebo->roll1;
/* Also move connected parent, in case parent's name isn't mirrored properly */
if (eboflip->parent && eboflip->flag & BONE_CONNECTED) {
@@ -395,6 +399,11 @@ void transform_armature_mirror_update(Object *obedit)
eboflip->roll = -ebo->roll;
eboflip->xwidth = ebo->xwidth;
eboflip->zwidth = ebo->zwidth;
+
+ eboflip->curveInX = -ebo->curveInX;
+ eboflip->curveOutX = -ebo->curveOutX;
+ eboflip->roll1 = -ebo->roll1;
+ eboflip->roll2 = -ebo->roll2;
}
}
}
@@ -415,7 +424,9 @@ EditBone *make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent, Bone
for (curBone = bones->first; curBone; curBone = curBone->next) {
eBone = MEM_callocN(sizeof(EditBone), "make_editbone");
- /* Copy relevant data from bone to eBone */
+ /* Copy relevant data from bone to eBone
+ * Keep selection logic in sync with ED_armature_sync_selection.
+ */
eBone->parent = parent;
BLI_strncpy(eBone->name, curBone->name, sizeof(eBone->name));
eBone->flag = curBone->flag;
@@ -426,11 +437,11 @@ EditBone *make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent, Bone
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;
}
+
+ /* For connected bones, take care when changing the selection when we have a connected parent,
+ * this flag is a copy of '(eBone->parent->flag & BONE_TIPSEL)'. */
+ eBone->flag |= BONE_ROOTSEL;
}
else {
/* if the bone is not selected, but connected to its parent
@@ -456,7 +467,16 @@ EditBone *make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent, Bone
eBone->rad_tail = curBone->rad_tail;
eBone->segments = curBone->segments;
eBone->layer = curBone->layer;
-
+
+ eBone->roll1 = curBone->roll1;
+ eBone->roll2 = curBone->roll2;
+ eBone->curveInX = curBone->curveInX;
+ eBone->curveInY = curBone->curveInY;
+ eBone->curveOutX = curBone->curveOutX;
+ eBone->curveOutY = curBone->curveOutY;
+ eBone->scaleIn = curBone->scaleIn;
+ eBone->scaleOut = curBone->scaleOut;
+
if (curBone->prop)
eBone->prop = IDP_CopyProperty(curBone->prop);
@@ -611,7 +631,17 @@ void ED_armature_from_edit(bArmature *arm)
newBone->rad_tail = eBone->rad_tail;
newBone->segments = eBone->segments;
newBone->layer = eBone->layer;
-
+
+ newBone->roll1 = eBone->roll1;
+ newBone->roll2 = eBone->roll2;
+ newBone->curveInX = eBone->curveInX;
+ newBone->curveInY = eBone->curveInY;
+ newBone->curveOutX = eBone->curveOutX;
+ newBone->curveOutY = eBone->curveOutY;
+ newBone->scaleIn = eBone->scaleIn;
+ newBone->scaleOut = eBone->scaleOut;
+
+
if (eBone->prop)
newBone->prop = IDP_CopyProperty(eBone->prop);
}
diff --git a/source/blender/editors/armature/editarmature_retarget.c b/source/blender/editors/armature/editarmature_retarget.c
index 7c09ad49f35..fa7bf6e7ad4 100644
--- a/source/blender/editors/armature/editarmature_retarget.c
+++ b/source/blender/editors/armature/editarmature_retarget.c
@@ -1451,6 +1451,15 @@ static EditBone *add_editbonetolist(char *name, ListBase *list)
bone->segments = 1;
bone->layer = 1; //arm->layer;
+ bone->roll1 = 0.0f;
+ bone->roll2 = 0.0f;
+ bone->curveInX = 0.0f;
+ bone->curveInY = 0.0f;
+ bone->curveOutX = 0.0f;
+ bone->curveOutY = 0.0f;
+ bone->scaleIn = 1.0f;
+ bone->scaleOut = 1.0f;
+
return bone;
}
#endif
diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c
index 7685829db9b..cc4c1809fbc 100644
--- a/source/blender/editors/armature/editarmature_sketch.c
+++ b/source/blender/editors/armature/editarmature_sketch.c
@@ -975,19 +975,23 @@ static int sk_getStrokeSnapPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, S
CTX_wm_region(C), CTX_wm_view3d(C));
float mvalf[2] = {UNPACK2(dd->mval)};
- float r_loc[3], dummy_no[3];
+ float loc[3], dummy_no[3];
if (ts->snap_mode == SCE_SNAP_MODE_VOLUME) {
float size;
if (peelObjectsSnapContext(
- snap_context, mvalf, SNAP_ALL,
+ snap_context, mvalf,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_NOT_SELECTED,
+ .use_object_edit_cage = false,
+ },
(ts->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0,
- r_loc, dummy_no, &size))
+ loc, dummy_no, &size))
{
pt->type = dd->type;
pt->mode = PT_SNAP;
pt->size = size / 2;
- copy_v3_v3(pt->p, r_loc);
+ copy_v3_v3(pt->p, loc);
point_added = 1;
}
@@ -1017,16 +1021,17 @@ static int sk_getStrokeSnapPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, S
{
if (ED_transform_snap_object_project_view3d(
snap_context,
+ ts->snap_mode,
&(const struct SnapObjectParams){
.snap_select = SNAP_NOT_SELECTED,
- .snap_to = ts->snap_mode,
+ .use_object_edit_cage = false,
},
mvalf, &dist_px, NULL,
- r_loc, dummy_no))
+ loc, dummy_no))
{
pt->type = dd->type;
pt->mode = PT_SNAP;
- copy_v3_v3(pt->p, r_loc);
+ copy_v3_v3(pt->p, loc);
point_added = 1;
}
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index a929507929f..5015829f868 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -86,7 +86,7 @@ void ED_armature_enter_posemode(bContext *C, Base *base)
ReportList *reports = CTX_wm_reports(C);
Object *ob = base->object;
- if (ob->id.lib) {
+ if (ID_IS_LINKED_DATABLOCK(ob)) {
BKE_report(reports, RPT_WARNING, "Cannot pose libdata");
return;
}
diff --git a/source/blender/editors/armature/pose_group.c b/source/blender/editors/armature/pose_group.c
index 4d9df06f33f..c492772b282 100644
--- a/source/blender/editors/armature/pose_group.c
+++ b/source/blender/editors/armature/pose_group.c
@@ -292,7 +292,6 @@ static int group_move_exec(bContext *C, wmOperator *op)
bPoseChannel *pchan;
bActionGroup *grp;
int dir = RNA_enum_get(op->ptr, "direction");
- int grpIndexA, grpIndexB;
if (ELEM(NULL, ob, pose))
return OPERATOR_CANCELLED;
@@ -305,51 +304,33 @@ static int group_move_exec(bContext *C, wmOperator *op)
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++;
- }
+ if (BLI_listbase_link_move(&pose->agroups, grp, dir)) {
+ int grpIndexA = pose->active_group;
+ int grpIndexB = grpIndexA + dir;
+
+ pose->active_group += dir;
+ /* 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;
+ }
+ }
- /* 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);
}
- /* 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", ""},
+ {-1, "UP", 0, "Up", ""},
+ {1, "DOWN", 0, "Down", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -365,7 +346,8 @@ void POSE_OT_group_move(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_enum(ot->srna, "direction", group_slot_move, 0, "Direction", "Direction to move, UP or DOWN");
+ RNA_def_enum(ot->srna, "direction", group_slot_move, 0, "Direction",
+ "Direction to move the active Bone Group towards");
}
/* bone group sort element */
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index a984e5d1ccd..9309592bb46 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -183,7 +183,7 @@ static int has_poselib_pose_data_poll(bContext *C)
static int has_poselib_pose_data_for_editing_poll(bContext *C)
{
Object *ob = get_poselib_object(C);
- return (ob && ob->poselib && !ob->poselib->id.lib);
+ return (ob && ob->poselib && !ID_IS_LINKED_DATABLOCK(ob->poselib));
}
/* ----------------------------------- */
@@ -385,7 +385,7 @@ static int poselib_add_poll(bContext *C)
if (ED_operator_posemode(C)) {
Object *ob = get_poselib_object(C);
if (ob) {
- if ((ob->poselib == NULL) || (ob->poselib->id.lib == 0)) {
+ if ((ob->poselib == NULL) || !ID_IS_LINKED_DATABLOCK(ob->poselib)) {
return true;
}
}
@@ -461,7 +461,7 @@ static int poselib_add_exec(bContext *C, wmOperator *op)
bAction *act = poselib_validate(ob);
bPose *pose = (ob) ? ob->pose : NULL;
TimeMarker *marker;
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_WHOLE_CHARACTER_ID); /* this includes custom props :)*/
+ KeyingSet *ks;
int frame = RNA_int_get(op->ptr, "frame");
char name[64];
@@ -495,8 +495,7 @@ static int poselib_add_exec(bContext *C, wmOperator *op)
BLI_uniquename(&act->markers, marker, DATA_("Pose"), '.', offsetof(TimeMarker, name), sizeof(marker->name));
/* use Keying Set to determine what to store for the pose */
- /* FIXME: in the past, the Keying Set respected selections (LocRotScale), but the current one doesn't
- * (WholeCharacter) so perhaps we need either a new Keying Set, or just to add overrides here... */
+ ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_WHOLE_CHARACTER_SELECTED_ID); /* this includes custom props :)*/
ANIM_apply_keyingset(C, NULL, act, ks, MODIFYKEY_MODE_INSERT, (float)frame);
/* store new 'active' pose number */
@@ -733,6 +732,89 @@ void POSELIB_OT_pose_rename(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
}
+static int poselib_move_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = get_poselib_object(C);
+ bAction *act = (ob) ? ob->poselib : NULL;
+ TimeMarker *marker;
+ int marker_index;
+ int dir;
+ PropertyRNA *prop;
+
+ /* check if valid poselib */
+ if (act == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Object does not have pose lib data");
+ return OPERATOR_CANCELLED;
+ }
+
+ prop = RNA_struct_find_property(op->ptr, "pose");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ marker_index = RNA_property_enum_get(op->ptr, prop);
+ }
+ else {
+ marker_index = act->active_marker - 1;
+ }
+
+ /* get index (and pointer) of pose to remove */
+ marker = BLI_findlink(&act->markers, marker_index);
+ if (marker == NULL) {
+ BKE_reportf(op->reports, RPT_ERROR, "Invalid pose specified %d", marker_index);
+ return OPERATOR_CANCELLED;
+ }
+
+ dir = RNA_enum_get(op->ptr, "direction");
+
+ /* move pose */
+ if (BLI_listbase_link_move(&act->markers, marker, dir)) {
+ act->active_marker = marker_index + dir + 1;
+
+ /* send notifiers for this - using keyframe editing notifiers, since action
+ * may be being shown in anim editors as active action
+ */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* done */
+ return OPERATOR_FINISHED;
+}
+
+void POSELIB_OT_pose_move(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+ static EnumPropertyItem pose_lib_pose_move[] = {
+ {-1, "UP", 0, "Up", ""},
+ {1, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "PoseLib Move Pose";
+ ot->idname = "POSELIB_OT_pose_move";
+ ot->description = "Move the pose up or down in the active Pose Library";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = poselib_move_exec;
+ ot->poll = has_poselib_pose_data_for_editing_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_enum(ot->srna, "pose", DummyRNA_NULL_items, 0, "Pose", "The pose to move");
+ RNA_def_enum_funcs(prop, poselib_stored_pose_itemf);
+ RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
+ ot->prop = prop;
+
+ RNA_def_enum(ot->srna, "direction", pose_lib_pose_move, 0, "Direction",
+ "Direction to move the chosen pose towards");
+}
+
+
+
/* ************************************************************* */
/* Pose-Lib Browsing/Previewing Operator */
@@ -762,7 +844,7 @@ typedef struct tPoseLib_PreviewData {
char searchstr[64]; /* (Part of) Name to search for to filter poses that get shown */
char searchold[64]; /* Previously set searchstr (from last loop run), so that we can detected when to rebuild searchp */
- char headerstr[200]; /* Info-text to print in header */
+ char headerstr[UI_MAX_DRAW_STR]; /* Info-text to print in header */
} tPoseLib_PreviewData;
/* defines for tPoseLib_PreviewData->state values */
@@ -1016,7 +1098,7 @@ static void poselib_preview_apply(bContext *C, wmOperator *op)
if (pld->state == PL_PREVIEW_RUNNING) {
if (pld->flag & PL_PREVIEW_SHOWORIGINAL) {
BLI_strncpy(pld->headerstr,
- "PoseLib Previewing Pose: [Showing Original Pose] | Use Tab to start previewing poses again",
+ IFACE_("PoseLib Previewing Pose: [Showing Original Pose] | Use Tab to start previewing poses again"),
sizeof(pld->headerstr));
ED_area_headerprint(pld->sa, pld->headerstr);
}
@@ -1041,16 +1123,16 @@ static void poselib_preview_apply(bContext *C, wmOperator *op)
BLI_strncpy(markern, pld->marker ? pld->marker->name : "No Matches", sizeof(markern));
BLI_snprintf(pld->headerstr, sizeof(pld->headerstr),
- "PoseLib Previewing Pose: Filter - [%s] | "
- "Current Pose - \"%s\" | "
- "Use ScrollWheel or PageUp/Down to change",
+ IFACE_("PoseLib Previewing Pose: Filter - [%s] | "
+ "Current Pose - \"%s\" | "
+ "Use ScrollWheel or PageUp/Down to change"),
tempstr, markern);
ED_area_headerprint(pld->sa, pld->headerstr);
}
else {
BLI_snprintf(pld->headerstr, sizeof(pld->headerstr),
- "PoseLib Previewing Pose: \"%s\" | "
- "Use ScrollWheel or PageUp/Down to change",
+ IFACE_("PoseLib Previewing Pose: \"%s\" | "
+ "Use ScrollWheel or PageUp/Down to change"),
pld->marker->name);
ED_area_headerprint(pld->sa, pld->headerstr);
}
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index 16ba1483e38..cd0ea23e2d3 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -51,6 +51,8 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "UI_interface.h"
+
#include "ED_armature.h"
#include "ED_keyframes_draw.h"
#include "ED_markers.h"
@@ -301,8 +303,8 @@ static void pose_slide_apply_vec3(tPoseSlideOp *pso, tPChanFCurveLink *pfl, floa
MEM_freeN(path);
}
-/* helper for apply() - perform sliding for custom properties */
-static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
+/* helper for apply() - perform sliding for custom properties or bbone properties */
+static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl, const char prop_prefix[])
{
PointerRNA ptr = {{NULL}};
LinkData *ld;
@@ -311,8 +313,10 @@ static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
/* setup pointer RNA for resolving paths */
RNA_pointer_create(NULL, &RNA_PoseBone, pfl->pchan, &ptr);
- /* custom properties are just denoted using ["..."][etc.] after the end of the base path,
- * so just check for opening pair after the end of the path
+ /* - custom properties are just denoted using ["..."][etc.] after the end of the base path,
+ * so just check for opening pair after the end of the path
+ * - bbone properties are similar, but they always start with a prefix "bbone_*",
+ * so a similar method should work here for those too
*/
for (ld = pfl->fcurves.first; ld; ld = ld->next) {
FCurve *fcu = (FCurve *)ld->data;
@@ -326,7 +330,7 @@ static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
* - pPtr is the chunk of the path which is left over
*/
bPtr = strstr(fcu->rna_path, pfl->pchan_path) + len;
- pPtr = strstr(bPtr, "[\""); /* dummy " for texteditor bugs */
+ pPtr = strstr(bPtr, prop_prefix);
if (pPtr) {
/* use RNA to try and get a handle on this property, then, assuming that it is just
@@ -515,9 +519,16 @@ static void pose_slide_apply(bContext *C, tPoseSlideOp *pso)
}
}
+ if (pchan->flag & POSE_BBONE_SHAPE) {
+ /* bbone properties - they all start a "bbone_" prefix */
+ pose_slide_apply_props(pso, pfl, "bbone_");
+ }
+
if (pfl->oldprops) {
- /* not strictly a transform, but contributes to the pose produced in many rigs */
- pose_slide_apply_props(pso, pfl);
+ /* not strictly a transform, but custom properties contribute to the pose produced in many rigs
+ * (e.g. the facial rigs used in Sintel)
+ */
+ pose_slide_apply_props(pso, pfl, "[\""); /* dummy " for texteditor bugs */
}
}
@@ -544,7 +555,7 @@ static void pose_slide_reset(tPoseSlideOp *pso)
/* draw percentage indicator in header */
static void pose_slide_draw_status(tPoseSlideOp *pso)
{
- char status_str[256];
+ char status_str[UI_MAX_DRAW_STR];
char mode_str[32];
switch (pso->mode) {
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index 01e16df9f08..b645f1fb2f3 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -39,7 +39,9 @@
#include "BKE_animsys.h"
#include "BKE_action.h"
+#include "BKE_appdir.h"
#include "BKE_armature.h"
+#include "BKE_blender_copybuffer.h"
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_depsgraph.h"
@@ -248,29 +250,6 @@ void POSE_OT_visual_transform_apply(wmOperatorType *ot)
/* ********************************************** */
/* 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)
*/
@@ -367,10 +346,26 @@ static bPoseChannel *pose_bone_do_paste(Object *ob, bPoseChannel *chan, const bo
axis_angle_to_quat(pchan->quat, chan->rotAxis, pchan->rotAngle);
}
+ /* B-Bone posing options should also be included... */
+ pchan->curveInX = chan->curveInX;
+ pchan->curveInY = chan->curveInY;
+ pchan->curveOutX = chan->curveOutX;
+ pchan->curveOutY = chan->curveOutY;
+
+ pchan->roll1 = chan->roll1;
+ pchan->roll2 = chan->roll2;
+ pchan->scaleIn = chan->scaleIn;
+ pchan->scaleOut = chan->scaleOut;
+
/* paste flipped pose? */
if (flip) {
pchan->loc[0] *= -1;
+ pchan->curveInX *= -1;
+ pchan->curveOutX *= -1;
+ pchan->roll1 *= -1; // XXX?
+ pchan->roll2 *= -1; // XXX?
+
/* has to be done as eulers... */
if (pchan->rotmode > 0) {
pchan->eul[1] *= -1;
@@ -420,21 +415,45 @@ static bPoseChannel *pose_bone_do_paste(Object *ob, bPoseChannel *chan, const bo
static int pose_copy_exec(bContext *C, wmOperator *op)
{
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
-
- /* sanity checking */
+ char str[FILE_MAX];
+ /* 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);
-
-
+ /* Sets chan->flag to POSE_KEY if bone selected. */
+ set_pose_keys(ob);
+ /* Construct a local bmain and only put object and it's data into it,
+ * o this way we don't expand any other objects into the copy buffer
+ * file.
+ *
+ * TODO(sergey): Find an easier way to tell copy buffer to only store
+ * data we are actually interested in. Maybe pass it a flag to skip
+ * any datablock expansion?
+ */
+ Main *temp_bmain = BKE_main_new();
+ Object ob_copy = *ob;
+ bArmature arm_copy = *((bArmature *)ob->data);
+ ob_copy.data = &arm_copy;
+ BLI_addtail(&temp_bmain->object, &ob_copy);
+ BLI_addtail(&temp_bmain->armature, &arm_copy);
+ /* begin copy buffer on a temp bmain. */
+ BKE_copybuffer_begin(temp_bmain);
+ /* Store the whole object to the copy buffer because pose can't be
+ * existing on it's own.
+ */
+ BKE_copybuffer_tag_ID(&ob_copy.id);
+ BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer_pose.blend");
+ BKE_copybuffer_save(temp_bmain, str, op->reports);
+ /* We clear the lists so no datablocks gets freed,
+ * This is required because objects in temp bmain shares same pointers
+ * as the real ones.
+ */
+ BLI_listbase_clear(&temp_bmain->object);
+ BLI_listbase_clear(&temp_bmain->armature);
+ BKE_main_free(temp_bmain);
+ /* We are all done! */
+ BKE_report(op->reports, RPT_INFO, "Copied pose to buffer");
return OPERATOR_FINISHED;
}
@@ -462,44 +481,60 @@ static int pose_paste_exec(bContext *C, wmOperator *op)
bPoseChannel *chan;
const bool flip = RNA_boolean_get(op->ptr, "flipped");
bool selOnly = RNA_boolean_get(op->ptr, "selected_mask");
-
- /* get KeyingSet to use */
+ /* Get KeyingSet to use. */
KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_WHOLE_CHARACTER_ID);
-
- /* sanity checks */
- if (ELEM(NULL, ob, ob->pose))
+ /* Sanity checks. */
+ if (ELEM(NULL, ob, ob->pose)) {
return OPERATOR_CANCELLED;
-
- if (g_posebuf == NULL) {
+ }
+ /* Read copy buffer .blend file. */
+ char str[FILE_MAX];
+ Main *tmp_bmain = BKE_main_new();
+ BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer_pose.blend");
+ if (!BKE_copybuffer_read(tmp_bmain, str, op->reports)) {
BKE_report(op->reports, RPT_ERROR, "Copy buffer is empty");
+ BKE_main_free(tmp_bmain);
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
+ /* Make sure data from this file is usable for pose paste. */
+ if (BLI_listbase_count_ex(&tmp_bmain->object, 2) != 1) {
+ BKE_report(op->reports, RPT_ERROR, "Copy buffer is not from pose mode");
+ BKE_main_free(tmp_bmain);
+ return OPERATOR_CANCELLED;
+ }
+ Object *object_from = tmp_bmain->object.first;
+ bPose *pose_from = object_from->pose;
+ if (pose_from == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Copy buffer has no pose");
+ BKE_main_free(tmp_bmain);
+ 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;
+ if (CTX_DATA_COUNT(C, selected_pose_bones) == 0) {
+ selOnly = false;
+ }
}
-
- /* Safely merge all of the channels in the buffer pose into any existing pose */
- for (chan = g_posebuf->chanbase.first; chan; chan = chan->next) {
+ /* Safely merge all of the channels in the buffer pose into any
+ * existing pose.
+ */
+ for (chan = pose_from->chanbase.first; chan; chan = chan->next) {
if (chan->flag & POSE_KEY) {
- /* try to perform paste on this bone */
+ /* Try to perform paste on this bone. */
bPoseChannel *pchan = pose_bone_do_paste(ob, chan, selOnly, flip);
-
- if (pchan) {
- /* keyframing tagging for successful paste */
+ if (pchan != NULL) {
+ /* Keyframing tagging for successful paste, */
ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
}
}
}
-
- /* Update event for pose and deformation children */
+ BKE_main_free(tmp_bmain);
+ /* Update event for pose and deformation children. */
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
-
- /* notifiers for updates */
+ /* Notifiers for updates, */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
return OPERATOR_FINISHED;
@@ -540,6 +575,9 @@ static void pchan_clear_scale(bPoseChannel *pchan)
pchan->size[1] = 1.0f;
if ((pchan->protectflag & OB_LOCK_SCALEZ) == 0)
pchan->size[2] = 1.0f;
+
+ pchan->scaleIn = 1.0f;
+ pchan->scaleOut = 1.0f;
}
/* clear location of pose-channel */
@@ -650,6 +688,15 @@ static void pchan_clear_rot(bPoseChannel *pchan)
zero_v3(pchan->eul);
}
}
+
+ /* Clear also Bendy Bone stuff - Roll is obvious, but Curve X/Y stuff is also kindof rotational in nature... */
+ pchan->roll1 = 0.0f;
+ pchan->roll2 = 0.0f;
+
+ pchan->curveInX = 0.0f;
+ pchan->curveInY = 0.0f;
+ pchan->curveOutX = 0.0f;
+ pchan->curveOutY = 0.0f;
}
/* clear loc/rot/scale of pose-channel */
diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c
index 2ba1eedd33b..b960bec3603 100644
--- a/source/blender/editors/armature/pose_utils.c
+++ b/source/blender/editors/armature/pose_utils.c
@@ -71,7 +71,7 @@ static void fcurves_to_pchan_links_get(ListBase *pfLinks, Object *ob, bAction *a
ListBase curves = {NULL, NULL};
int transFlags = action_get_item_transforms(act, ob, pchan, &curves);
- pchan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE);
+ pchan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE | POSE_BBONE_SHAPE);
/* check if any transforms found... */
if (transFlags) {
@@ -96,6 +96,8 @@ static void fcurves_to_pchan_links_get(ListBase *pfLinks, Object *ob, bAction *a
pchan->flag |= POSE_ROT;
if (transFlags & ACT_TRANS_SCALE)
pchan->flag |= POSE_SIZE;
+ if (transFlags & ACT_TRANS_BBONE)
+ pchan->flag |= POSE_BBONE_SHAPE;
/* store current transforms */
copy_v3_v3(pfl->oldloc, pchan->loc);
@@ -105,6 +107,16 @@ static void fcurves_to_pchan_links_get(ListBase *pfLinks, Object *ob, bAction *a
copy_v3_v3(pfl->oldaxis, pchan->rotAxis);
pfl->oldangle = pchan->rotAngle;
+ /* store current bbone values */
+ pfl->roll1 = pchan->roll1;
+ pfl->roll2 = pchan->roll2;
+ pfl->curveInX = pchan->curveInX;
+ pfl->curveInY = pchan->curveInY;
+ pfl->curveOutX = pchan->curveOutX;
+ pfl->curveOutY = pchan->curveOutY;
+ pfl->scaleIn = pchan->scaleIn;
+ pfl->scaleOut = pchan->scaleOut;
+
/* make copy of custom properties */
if (pchan->prop && (transFlags & ACT_TRANS_PROP))
pfl->oldprops = IDP_CopyProperty(pchan->prop);
@@ -133,6 +145,7 @@ void poseAnim_mapping_get(bContext *C, ListBase *pfLinks, Object *ob, bAction *a
fcurves_to_pchan_links_get(pfLinks, ob, act, pchan);
}
CTX_DATA_END;
+
}
}
@@ -199,6 +212,16 @@ void poseAnim_mapping_reset(ListBase *pfLinks)
copy_v3_v3(pchan->rotAxis, pfl->oldaxis);
pchan->rotAngle = pfl->oldangle;
+ /* store current bbone values */
+ pchan->roll1 = pfl->roll1;
+ pchan->roll2 = pfl->roll2;
+ pchan->curveInX = pfl->curveInX;
+ pchan->curveInY = pfl->curveInY;
+ pchan->curveOutX = pfl->curveOutX;
+ pchan->curveOutY = pfl->curveOutY;
+ pchan->scaleIn = pfl->scaleIn;
+ pchan->scaleOut = pfl->scaleOut;
+
/* just overwrite values of properties from the stored copies (there should be some) */
if (pfl->oldprops)
IDP_SyncGroupValues(pfl->pchan->prop, pfl->oldprops);
diff --git a/source/blender/editors/curve/CMakeLists.txt b/source/blender/editors/curve/CMakeLists.txt
index ebdf6bb43ff..2f5b2ab6e87 100644
--- a/source/blender/editors/curve/CMakeLists.txt
+++ b/source/blender/editors/curve/CMakeLists.txt
@@ -43,6 +43,7 @@ set(SRC
editcurve_paint.c
editcurve_select.c
editfont.c
+ editfont_undo.c
curve_intern.h
)
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 18fdcb546b0..e40dde24ce2 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -1301,7 +1301,7 @@ static int separate_exec(bContext *C, wmOperator *op)
DAG_relations_tag_update(bmain);
newob = newbase->object;
- newcu = newob->data = BKE_curve_copy(oldcu);
+ newcu = newob->data = BKE_curve_copy(bmain, oldcu);
newcu->editnurb = NULL;
id_us_min(&oldcu->id); /* because new curve is a copy: reduce user count */
@@ -5004,9 +5004,10 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
ED_transform_snap_object_project_view3d_mixed(
snap_context,
+ SCE_SELECT_FACE,
&(const struct SnapObjectParams){
- .snap_select = SNAP_NOT_OBEDIT,
- .snap_to_flag = SCE_SELECT_FACE,
+ .snap_select = (vc.scene->obedit != NULL) ? SNAP_NOT_ACTIVE : SNAP_ALL,
+ .use_object_edit_cage = false,
},
mval, NULL, true,
location, NULL);
@@ -5842,7 +5843,7 @@ static int curve_dissolve_exec(bContext *C, wmOperator *UNUSED(op))
normalize_v3(tan_r);
curve_fit_cubic_to_points_single_fl(
- points, points_len, dims, FLT_EPSILON,
+ points, points_len, NULL, dims, FLT_EPSILON,
tan_l, tan_r,
bezt_prev->vec[2], bezt_next->vec[0],
&error_sq_dummy);
@@ -6033,9 +6034,8 @@ int join_curve_exec(bContext *C, wmOperator *op)
BLI_movelisttolist(&cu->nurb, &tempbase);
DAG_relations_tag_update(bmain); // because we removed object(s), call before editmode!
-
- ED_object_editmode_enter(C, EM_WAITCURSOR);
- ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO);
+
+ DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c
index bb7cc61f580..2d8fc76ee7e 100644
--- a/source/blender/editors/curve/editcurve_paint.c
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -55,6 +55,8 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
#define USE_SPLINE_FIT
#ifdef USE_SPLINE_FIT
@@ -62,8 +64,11 @@
#endif
/* Distance between input samples */
-#define STROKE_SAMPLE_DIST_MIN_PX 3
-#define STROKE_SAMPLE_DIST_MAX_PX 6
+#define STROKE_SAMPLE_DIST_MIN_PX 1
+#define STROKE_SAMPLE_DIST_MAX_PX 3
+
+/* Distance between start/end points to consider cyclic */
+#define STROKE_CYCLIC_DIST_PX 8
/* -------------------------------------------------------------------- */
@@ -730,6 +735,11 @@ static void curve_draw_exec_precalc(wmOperator *op)
const CurvePaintSettings *cps = &cdd->vc.scene->toolsettings->curve_paint_settings;
PropertyRNA *prop;
+ prop = RNA_struct_find_property(op->ptr, "fit_method");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_enum_set(op->ptr, prop, cps->fit_method);
+ }
+
prop = RNA_struct_find_property(op->ptr, "corner_angle");
if (!RNA_property_is_set(op->ptr, prop)) {
const float corner_angle = (cps->flag & CURVE_PAINT_FLAG_CORNERS_DETECT) ? cps->corner_angle : (float)M_PI;
@@ -759,6 +769,32 @@ static void curve_draw_exec_precalc(wmOperator *op)
RNA_property_float_set(op->ptr, prop, error_threshold);
}
+ prop = RNA_struct_find_property(op->ptr, "use_cyclic");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ bool use_cyclic = false;
+
+ if (BLI_mempool_count(cdd->stroke_elem_pool) > 2) {
+ BLI_mempool_iter iter;
+ const struct StrokeElem *selem, *selem_first, *selem_last;
+
+ BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
+ selem_first = BLI_mempool_iterstep(&iter);
+ for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter)) {
+ selem_last = selem;
+ }
+
+ if (len_squared_v2v2(
+ selem_first->mval,
+ selem_last->mval) <= SQUARE(STROKE_CYCLIC_DIST_PX * U.pixelsize))
+ {
+ use_cyclic = true;
+ }
+ }
+
+ RNA_property_boolean_set(op->ptr, prop, use_cyclic);
+ }
+
+
if ((cps->radius_taper_start != 0.0f) ||
(cps->radius_taper_end != 0.0f))
{
@@ -868,8 +904,10 @@ static int curve_draw_exec(bContext *C, wmOperator *op)
unsigned int cubic_spline_len = 0;
/* error in object local space */
+ const int fit_method = RNA_enum_get(op->ptr, "fit_method");
const float error_threshold = RNA_float_get(op->ptr, "error_threshold");
const float corner_angle = RNA_float_get(op->ptr, "corner_angle");
+ const bool use_cyclic = RNA_boolean_get(op->ptr, "use_cyclic");
{
BLI_mempool_iter iter;
@@ -894,14 +932,14 @@ static int curve_draw_exec(bContext *C, wmOperator *op)
unsigned int *corners = NULL;
unsigned int corners_len = 0;
- if (corner_angle < (float)M_PI) {
+ if ((fit_method == CURVE_PAINT_FIT_METHOD_SPLIT) && (corner_angle < (float)M_PI)) {
/* this could be configurable... */
const float corner_radius_min = error_threshold / 8;
const float corner_radius_max = error_threshold * 2;
const unsigned int samples_max = 16;
curve_fit_corners_detect_fl(
- (const float *)coords, stroke_len, dims,
+ coords, stroke_len, dims,
corner_radius_min, corner_radius_max,
samples_max, corner_angle,
&corners, &corners_len);
@@ -909,13 +947,29 @@ static int curve_draw_exec(bContext *C, wmOperator *op)
unsigned int *corners_index = NULL;
unsigned int corners_index_len = 0;
+ unsigned int calc_flag = CURVE_FIT_CALC_HIGH_QUALIY;
- const int result = curve_fit_cubic_to_points_fl(
- coords, stroke_len, dims, error_threshold,
- corners, corners_len,
- &cubic_spline, &cubic_spline_len,
- NULL,
- &corners_index, &corners_index_len);
+ if ((stroke_len > 2) && use_cyclic) {
+ calc_flag |= CURVE_FIT_CALC_CYCLIC;
+ }
+
+ int result;
+ if (fit_method == CURVE_PAINT_FIT_METHOD_REFIT) {
+ result = curve_fit_cubic_to_points_refit_fl(
+ coords, stroke_len, dims, error_threshold, calc_flag,
+ NULL, 0, corner_angle,
+ &cubic_spline, &cubic_spline_len,
+ NULL,
+ &corners_index, &corners_index_len);
+ }
+ else {
+ result = curve_fit_cubic_to_points_fl(
+ coords, stroke_len, dims, error_threshold, calc_flag,
+ corners, corners_len,
+ &cubic_spline, &cubic_spline_len,
+ NULL,
+ &corners_index, &corners_index_len);
+ }
MEM_freeN(coords);
if (corners) {
@@ -950,11 +1004,24 @@ static int curve_draw_exec(bContext *C, wmOperator *op)
if (corners_index) {
/* ignore the first and last */
- for (unsigned int i = 1; i < corners_index_len - 1; i++) {
+ unsigned int i_start = 0, i_end = corners_index_len;
+
+ if ((corners_index_len >= 2) &&
+ (calc_flag & CURVE_FIT_CALC_CYCLIC) == 0)
+ {
+ i_start += 1;
+ i_end -= 1;
+ }
+
+ for (unsigned int i = i_start; i < i_end; i++) {
bezt = &nu->bezt[corners_index[i]];
bezt->h1 = bezt->h2 = HD_FREE;
}
}
+
+ if (calc_flag & CURVE_FIT_CALC_CYCLIC) {
+ nu->flagu |= CU_NURB_CYCLIC;
+ }
}
if (corners_index) {
@@ -1220,13 +1287,19 @@ void CURVE_OT_draw(wmOperatorType *ot)
0.0001f, 10.0f);
RNA_def_property_ui_range(prop, 0.0, 10, 1, 4);
+ RNA_def_enum(ot->srna, "fit_method", rna_enum_curve_fit_method_items, CURVE_PAINT_FIT_METHOD_REFIT,
+ "Fit Method", "");
+
prop = RNA_def_float_distance(
ot->srna, "corner_angle", DEG2RADF(70.0f), 0.0f, M_PI, "Corner Angle", "", 0.0f, M_PI);
RNA_def_property_subtype(prop, PROP_ANGLE);
- prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
+ prop = RNA_def_boolean(ot->srna, "use_cyclic", true, "Cyclic", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/curve/editcurve_select.c b/source/blender/editors/curve/editcurve_select.c
index a29266294b4..cad70443657 100644
--- a/source/blender/editors/curve/editcurve_select.c
+++ b/source/blender/editors/curve/editcurve_select.c
@@ -294,11 +294,11 @@ static void select_adjacent_cp(
if (next < 0) bezt = &nu->bezt[a - 1];
while (a--) {
if (a - abs(next) < 0) break;
- if ((lastsel == 0) && (bezt->hide == 0) && ((bezt->f2 & SELECT) || (selstatus == DESELECT))) {
+ if ((lastsel == false) && (bezt->hide == 0) && ((bezt->f2 & SELECT) || (selstatus == DESELECT))) {
bezt += next;
if (!(bezt->f2 & SELECT) || (selstatus == DESELECT)) {
- short sel = select_beztriple(bezt, selstatus, SELECT, VISIBLE);
- if ((sel == 1) && (cont == 0)) lastsel = true;
+ bool sel = select_beztriple(bezt, selstatus, SELECT, VISIBLE);
+ if (sel && !cont) lastsel = true;
}
}
else {
@@ -315,11 +315,11 @@ static void select_adjacent_cp(
if (next < 0) bp = &nu->bp[a - 1];
while (a--) {
if (a - abs(next) < 0) break;
- if ((lastsel == 0) && (bp->hide == 0) && ((bp->f1 & SELECT) || (selstatus == DESELECT))) {
+ if ((lastsel == false) && (bp->hide == 0) && ((bp->f1 & SELECT) || (selstatus == DESELECT))) {
bp += next;
if (!(bp->f1 & SELECT) || (selstatus == DESELECT)) {
- short sel = select_bpoint(bp, selstatus, SELECT, VISIBLE);
- if ((sel == 1) && (cont == 0)) lastsel = true;
+ bool sel = select_bpoint(bp, selstatus, SELECT, VISIBLE);
+ if (sel && !cont) lastsel = true;
}
}
else {
@@ -820,7 +820,7 @@ static int select_less_exec(bContext *C, wmOperator *UNUSED(op))
BezTriple *bezt;
int a;
int sel = 0;
- short lastsel = false;
+ bool lastsel = false;
if (obedit->type == OB_SURF) {
for (nu = editnurb->first; nu; nu = nu->next) {
@@ -935,9 +935,8 @@ static int select_less_exec(bContext *C, wmOperator *UNUSED(op))
a = nu->pntsu * nu->pntsv;
bp = nu->bp;
while (a--) {
- if ((lastsel == 0) && (bp->hide == 0) && (bp->f1 & SELECT)) {
- if (lastsel != 0) sel = 1;
- else sel = 0;
+ if ((lastsel == false) && (bp->hide == 0) && (bp->f1 & SELECT)) {
+ sel = 0;
/* first and last are exceptions */
if (a == nu->pntsu * nu->pntsv - 1) {
diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c
index 7c1fe0cadf0..57e731874b4 100644
--- a/source/blender/editors/curve/editfont.c
+++ b/source/blender/editors/curve/editfont.c
@@ -1695,7 +1695,7 @@ static int font_open_exec(bContext *C, wmOperator *op)
if (pprop->prop) {
/* when creating new ID blocks, use is already 1, but RNA
- * pointer se also increases user, so this compensates it */
+ * pointer use also increases user, so this compensates it */
id_us_min(&font->id);
RNA_id_pointer_create(&font->id, &idptr);
@@ -1788,70 +1788,12 @@ void FONT_OT_unlink(wmOperatorType *ot)
/* identifiers */
ot->name = "Unlink";
ot->idname = "FONT_OT_unlink";
- ot->description = "Unlink active font data block";
+ ot->description = "Unlink active font data-block";
/* api callbacks */
ot->exec = font_unlink_exec;
}
-
-/* **************** undo for font object ************** */
-
-static void undoFont_to_editFont(void *strv, void *ecu, void *UNUSED(obdata))
-{
- Curve *cu = (Curve *)ecu;
- EditFont *ef = cu->editfont;
- const char *str = strv;
-
- ef->pos = *((const short *)str);
- ef->len = *((const short *)(str + 2));
-
- memcpy(ef->textbuf, str + 4, (ef->len + 1) * sizeof(wchar_t));
- memcpy(ef->textbufinfo, str + 4 + (ef->len + 1) * sizeof(wchar_t), ef->len * sizeof(CharInfo));
-
- ef->selstart = ef->selend = 0;
-
-}
-
-static void *editFont_to_undoFont(void *ecu, void *UNUSED(obdata))
-{
- Curve *cu = (Curve *)ecu;
- EditFont *ef = cu->editfont;
- char *str;
-
- /* The undo buffer includes [MAXTEXT+6]=actual string and [MAXTEXT+4]*sizeof(CharInfo)=charinfo */
- str = MEM_callocN((MAXTEXT + 6) * sizeof(wchar_t) + (MAXTEXT + 4) * sizeof(CharInfo), "string undo");
-
- /* Copy the string and string information */
- memcpy(str + 4, ef->textbuf, (ef->len + 1) * sizeof(wchar_t));
- memcpy(str + 4 + (ef->len + 1) * sizeof(wchar_t), ef->textbufinfo, ef->len * sizeof(CharInfo));
-
- *((short *)(str + 0)) = ef->pos;
- *((short *)(str + 2)) = ef->len;
-
- return str;
-}
-
-static void free_undoFont(void *strv)
-{
- MEM_freeN(strv);
-}
-
-static void *get_undoFont(bContext *C)
-{
- Object *obedit = CTX_data_edit_object(C);
- if (obedit && obedit->type == OB_FONT) {
- return obedit->data;
- }
- return NULL;
-}
-
-/* and this is all the undo system needs to know */
-void undo_push_font(bContext *C, const char *name)
-{
- undo_editmode_push(C, name, get_undoFont, free_undoFont, undoFont_to_editFont, editFont_to_undoFont, NULL);
-}
-
/**
* TextBox selection
*/
diff --git a/source/blender/editors/curve/editfont_undo.c b/source/blender/editors/curve/editfont_undo.c
new file mode 100644
index 00000000000..a61f863b61e
--- /dev/null
+++ b/source/blender/editors/curve/editfont_undo.c
@@ -0,0 +1,311 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/curve/editfont_undo.c
+ * \ingroup edcurve
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_context.h"
+#include "BKE_font.h"
+
+#include "ED_curve.h"
+#include "ED_util.h"
+
+#define USE_ARRAY_STORE
+
+#ifdef USE_ARRAY_STORE
+// # define DEBUG_PRINT
+# include "BLI_array_store.h"
+# include "BLI_array_store_utils.h"
+# include "BLI_listbase.h"
+# define ARRAY_CHUNK_SIZE 32
+#endif
+
+typedef struct UndoFont {
+ wchar_t *textbuf;
+ struct CharInfo *textbufinfo;
+
+ int len, pos;
+
+#ifdef USE_ARRAY_STORE
+ struct {
+ BArrayState *textbuf;
+ BArrayState *textbufinfo;
+ } store;
+#endif
+} UndoFont;
+
+
+#ifdef USE_ARRAY_STORE
+
+/** \name Array Store
+ * \{ */
+
+static struct {
+ struct BArrayStore_AtSize bs_stride;
+ int users;
+
+ /* We could have the undo API pass in the previous state, for now store a local list */
+ ListBase local_links;
+
+} uf_arraystore = {{NULL}};
+
+/**
+ * \param create: When false, only free the arrays.
+ * This is done since when reading from an undo state, they must be temporarily expanded.
+ * then discarded afterwards, having this argument avoids having 2x code paths.
+ */
+static void uf_arraystore_compact_ex(
+ UndoFont *uf, const UndoFont *uf_ref,
+ bool create)
+{
+#define STATE_COMPACT(uf, id, len) \
+ if ((uf)->id) { \
+ BLI_assert(create == ((uf)->store.id == NULL)); \
+ if (create) { \
+ BArrayState *state_reference = uf_ref ? uf_ref->store.id : NULL; \
+ const size_t stride = sizeof(*(uf)->id); \
+ BArrayStore *bs = BLI_array_store_at_size_ensure(&uf_arraystore.bs_stride, stride, ARRAY_CHUNK_SIZE); \
+ (uf)->store.id = BLI_array_store_state_add( \
+ bs, (uf)->id, (size_t)(len) * stride, state_reference); \
+ } \
+ /* keep uf->len for validation */ \
+ MEM_freeN((uf)->id); \
+ (uf)->id = NULL; \
+ } ((void)0)
+
+ STATE_COMPACT(uf, textbuf, uf->len + 1);
+ STATE_COMPACT(uf, textbufinfo, uf->len + 1);
+
+#undef STATE_COMPACT
+
+ if (create) {
+ uf_arraystore.users += 1;
+ }
+}
+
+/**
+ * Move data from allocated arrays to de-duplicated states and clear arrays.
+ */
+static void uf_arraystore_compact(UndoFont *um, const UndoFont *uf_ref)
+{
+ uf_arraystore_compact_ex(um, uf_ref, true);
+}
+
+static void uf_arraystore_compact_with_info(UndoFont *um, const UndoFont *uf_ref)
+{
+#ifdef DEBUG_PRINT
+ size_t size_expanded_prev, size_compacted_prev;
+ BLI_array_store_at_size_calc_memory_usage(&uf_arraystore.bs_stride, &size_expanded_prev, &size_compacted_prev);
+#endif
+
+ uf_arraystore_compact(um, uf_ref);
+
+#ifdef DEBUG_PRINT
+ {
+ size_t size_expanded, size_compacted;
+ BLI_array_store_at_size_calc_memory_usage(&uf_arraystore.bs_stride, &size_expanded, &size_compacted);
+
+ const double percent_total = size_expanded ?
+ (((double)size_compacted / (double)size_expanded) * 100.0) : -1.0;
+
+ size_t size_expanded_step = size_expanded - size_expanded_prev;
+ size_t size_compacted_step = size_compacted - size_compacted_prev;
+ const double percent_step = size_expanded_step ?
+ (((double)size_compacted_step / (double)size_expanded_step) * 100.0) : -1.0;
+
+ printf("overall memory use: %.8f%% of expanded size\n", percent_total);
+ printf("step memory use: %.8f%% of expanded size\n", percent_step);
+ }
+#endif
+}
+
+/**
+ * Remove data we only expanded for temporary use.
+ */
+static void uf_arraystore_expand_clear(UndoFont *um)
+{
+ uf_arraystore_compact_ex(um, NULL, false);
+}
+
+static void uf_arraystore_expand(UndoFont *uf)
+{
+#define STATE_EXPAND(uf, id, len) \
+ if ((uf)->store.id) { \
+ const size_t stride = sizeof(*(uf)->id); \
+ BArrayState *state = (uf)->store.id; \
+ size_t state_len; \
+ (uf)->id = BLI_array_store_state_data_get_alloc(state, &state_len); \
+ BLI_assert((len) == (state_len / stride)); \
+ UNUSED_VARS_NDEBUG(stride); \
+ } ((void)0)
+
+ STATE_EXPAND(uf, textbuf, uf->len + 1);
+ STATE_EXPAND(uf, textbufinfo, uf->len + 1);
+
+#undef STATE_EXPAND
+}
+
+static void uf_arraystore_free(UndoFont *uf)
+{
+#define STATE_FREE(uf, id) \
+ if ((uf)->store.id) { \
+ const size_t stride = sizeof(*(uf)->id); \
+ BArrayStore *bs = BLI_array_store_at_size_get(&uf_arraystore.bs_stride, stride); \
+ BArrayState *state = (uf)->store.id; \
+ BLI_array_store_state_remove(bs, state); \
+ (uf)->store.id = NULL; \
+ } ((void)0)
+
+ STATE_FREE(uf, textbuf);
+ STATE_FREE(uf, textbufinfo);
+
+#undef STATE_FREE
+
+ uf_arraystore.users -= 1;
+
+ BLI_assert(uf_arraystore.users >= 0);
+
+ if (uf_arraystore.users == 0) {
+#ifdef DEBUG_PRINT
+ printf("editfont undo store: freeing all data!\n");
+#endif
+
+ BLI_array_store_at_size_clear(&uf_arraystore.bs_stride);
+ }
+
+}
+
+/** \} */
+
+#endif /* USE_ARRAY_STORE */
+
+static void undoFont_to_editFont(void *uf_v, void *ecu, void *UNUSED(obdata))
+{
+ Curve *cu = (Curve *)ecu;
+ EditFont *ef = cu->editfont;
+ const UndoFont *uf = uf_v;
+
+ size_t final_size;
+
+#ifdef USE_ARRAY_STORE
+ uf_arraystore_expand(uf_v);
+#endif
+
+ final_size = sizeof(wchar_t) * (uf->len + 1);
+ memcpy(ef->textbuf, uf->textbuf, final_size);
+
+ final_size = sizeof(CharInfo) * (uf->len + 1);
+ memcpy(ef->textbufinfo, uf->textbufinfo, final_size);
+
+ ef->pos = uf->pos;
+ ef->len = uf->len;
+
+ ef->selstart = ef->selend = 0;
+
+#ifdef USE_ARRAY_STORE
+ uf_arraystore_expand_clear(uf_v);
+#endif
+}
+
+static void *editFont_to_undoFont(void *ecu, void *UNUSED(obdata))
+{
+ Curve *cu = (Curve *)ecu;
+ EditFont *ef = cu->editfont;
+
+ UndoFont *uf = MEM_callocN(sizeof(*uf), __func__);
+
+ size_t final_size;
+
+ final_size = sizeof(wchar_t) * (ef->len + 1);
+ uf->textbuf = MEM_mallocN(final_size, __func__);
+ memcpy(uf->textbuf, ef->textbuf, final_size);
+
+ final_size = sizeof(CharInfo) * (ef->len + 1);
+ uf->textbufinfo = MEM_mallocN(final_size, __func__);
+ memcpy(uf->textbufinfo, ef->textbufinfo, final_size);
+
+ uf->pos = ef->pos;
+ uf->len = ef->len;
+
+#ifdef USE_ARRAY_STORE
+ {
+ const UndoFont *uf_ref = uf_arraystore.local_links.last ?
+ ((LinkData *)uf_arraystore.local_links.last)->data : NULL;
+
+ /* add oursrlves */
+ BLI_addtail(&uf_arraystore.local_links, BLI_genericNodeN(uf));
+
+ uf_arraystore_compact_with_info(uf, uf_ref);
+ }
+#endif
+
+ return uf;
+}
+
+static void free_undoFont(void *uf_v)
+{
+ UndoFont *uf = uf_v;
+
+#ifdef USE_ARRAY_STORE
+ {
+ LinkData *link = BLI_findptr(&uf_arraystore.local_links, uf, offsetof(LinkData, data));
+ BLI_remlink(&uf_arraystore.local_links, link);
+ MEM_freeN(link);
+ }
+ uf_arraystore_free(uf);
+#endif
+
+ if (uf->textbuf) {
+ MEM_freeN(uf->textbuf);
+ }
+ if (uf->textbufinfo) {
+ MEM_freeN(uf->textbufinfo);
+ }
+
+ MEM_freeN(uf);
+}
+
+static void *get_undoFont(bContext *C)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ if (obedit && obedit->type == OB_FONT) {
+ return obedit->data;
+ }
+ return NULL;
+}
+
+/* and this is all the undo system needs to know */
+void undo_push_font(bContext *C, const char *name)
+{
+ undo_editmode_push(C, name, get_undoFont, free_undoFont, undoFont_to_editFont, editFont_to_undoFont, NULL);
+}
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 0329598d711..48786e08f85 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -18,7 +18,7 @@
* The Original Code is Copyright (C) 2008, Blender Foundation
* This is a new part of Blender
*
- * Contributor(s): Joshua Leung
+ * Contributor(s): Joshua Leung, Antonio Vazquez
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -52,6 +52,7 @@
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
#include "DNA_userdef_types.h"
+#include "DNA_object_types.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -65,6 +66,7 @@
#include "ED_gpencil.h"
#include "ED_screen.h"
#include "ED_view3d.h"
+#include "ED_space_api.h"
#include "UI_interface_icons.h"
#include "UI_resources.h"
@@ -73,7 +75,6 @@
/* GREASE PENCIL DRAWING */
/* ----- General Defines ------ */
-
/* flags for sflag */
typedef enum eDrawStrokeFlags {
GP_DRAWDATA_NOSTATUS = (1 << 0), /* don't draw status info */
@@ -94,9 +95,32 @@ typedef enum eDrawStrokeFlags {
#define GP_DRAWTHICKNESS_SPECIAL 3
/* ----- Tool Buffer Drawing ------ */
+/* helper function to set color of buffer point */
+static void gp_set_tpoint_color(tGPspoint *pt, float ink[4])
+{
+ float alpha = ink[3] * pt->strength;
+ CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
+ glColor4f(ink[0], ink[1], ink[2], alpha);
+}
+
+/* helper function to set color of point */
+static void gp_set_point_color(bGPDspoint *pt, float ink[4])
+{
+ float alpha = ink[3] * pt->strength;
+ CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
+ glColor4f(ink[0], ink[1], ink[2], alpha);
+}
+
+/* helper function to set color and point */
+static void gp_set_color_and_tpoint(tGPspoint *pt, float ink[4])
+{
+ gp_set_tpoint_color(pt, ink);
+ glVertex2iv(&pt->x);
+}
/* draw stroke defined in buffer (simple ogl lines/points for now, as dotted lines) */
-static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickness, short dflag, short sflag)
+static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickness,
+ short dflag, short sflag, float ink[4])
{
tGPspoint *pt;
int i;
@@ -113,7 +137,8 @@ static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickn
/* if drawing a single point, draw it larger */
glPointSize((float)(thickness + 2) * points->pressure);
glBegin(GL_POINTS);
- glVertex2iv(&points->x);
+
+ gp_set_color_and_tpoint(points, ink);
glEnd();
}
else if (sflag & GP_STROKE_ERASER) {
@@ -138,15 +163,18 @@ static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickn
glBegin(GL_LINE_STRIP);
/* need to roll-back one point to ensure that there are no gaps in the stroke */
- if (i != 0) glVertex2iv(&(pt - 1)->x);
+ if (i != 0) {
+ gp_set_color_and_tpoint((pt - 1), ink);
+ }
/* now the point we want... */
- glVertex2iv(&pt->x);
+ gp_set_color_and_tpoint(pt, ink);
oldpressure = pt->pressure;
}
- else
- glVertex2iv(&pt->x);
+ else {
+ gp_set_color_and_tpoint(pt, ink);
+ }
}
glEnd();
@@ -155,37 +183,35 @@ static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickn
}
/* --------- 2D Stroke Drawing Helpers --------- */
-
-/* helper function to calculate x-y drawing coordinates for 2D points */
-static void gp_calc_2d_stroke_xy(bGPDspoint *pt, short sflag, int offsx, int offsy, int winx, int winy, float r_co[2])
+/* change in parameter list */
+static void gp_calc_2d_stroke_fxy(float pt[3], short sflag, int offsx, int offsy, int winx, int winy, float r_co[2])
{
if (sflag & GP_STROKE_2DSPACE) {
- r_co[0] = pt->x;
- r_co[1] = pt->y;
+ r_co[0] = pt[0];
+ r_co[1] = pt[1];
}
else if (sflag & GP_STROKE_2DIMAGE) {
- const float x = (float)((pt->x * winx) + offsx);
- const float y = (float)((pt->y * winy) + offsy);
-
+ const float x = (float)((pt[0] * winx) + offsx);
+ const float y = (float)((pt[1] * winy) + offsy);
+
r_co[0] = x;
r_co[1] = y;
}
else {
- const float x = (float)(pt->x / 100 * winx) + offsx;
- const float y = (float)(pt->y / 100 * winy) + offsy;
-
+ const float x = (float)(pt[0] / 100 * winx) + offsx;
+ const float y = (float)(pt[1] / 100 * winy) + offsy;
+
r_co[0] = x;
r_co[1] = y;
}
}
-
/* ----------- Volumetric Strokes --------------- */
/* draw a 2D buffer stroke in "volumetric" style
* NOTE: the stroke buffer doesn't have any coordinate offsets/transforms
*/
static void gp_draw_stroke_volumetric_buffer(tGPspoint *points, int totpoints, short thickness,
- short dflag, short UNUSED(sflag))
+ short dflag, short UNUSED(sflag), float ink[4])
{
GLUquadricObj *qobj = gluNewQuadric();
float modelview[4][4];
@@ -216,6 +242,7 @@ static void gp_draw_stroke_volumetric_buffer(tGPspoint *points, int totpoints, s
glLoadMatrixf((float *)modelview);
/* draw the disk using the current state... */
+ gp_set_tpoint_color(pt, ink);
gluDisk(qobj, 0.0, pt->pressure * thickness, 32, 1);
@@ -229,7 +256,8 @@ static void gp_draw_stroke_volumetric_buffer(tGPspoint *points, int totpoints, s
/* draw a 2D strokes in "volumetric" style */
static void gp_draw_stroke_volumetric_2d(bGPDspoint *points, int totpoints, short thickness,
short dflag, short sflag,
- int offsx, int offsy, int winx, int winy)
+ int offsx, int offsy, int winx, int winy,
+ float diff_mat[4][4], float ink[4])
{
GLUquadricObj *qobj = gluNewQuadric();
float modelview[4][4];
@@ -238,7 +266,7 @@ static void gp_draw_stroke_volumetric_2d(bGPDspoint *points, int totpoints, shor
bGPDspoint *pt;
int i;
-
+ float fpt[3];
/* HACK: We need a scale factor for the drawing in the image editor,
* which seems to use 1 unit as it's maximum size, whereas everything
@@ -256,10 +284,14 @@ static void gp_draw_stroke_volumetric_2d(bGPDspoint *points, int totpoints, shor
glPushMatrix();
for (i = 0, pt = points; i < totpoints; i++, pt++) {
+ /* color of point */
+ gp_set_point_color(pt, ink);
+
/* set the transformed position */
float co[2];
- gp_calc_2d_stroke_xy(pt, sflag, offsx, offsy, winx, winy, co);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co);
translate_m4(modelview, co[0], co[1], 0.0f);
glLoadMatrixf((float *)modelview);
@@ -276,8 +308,9 @@ static void gp_draw_stroke_volumetric_2d(bGPDspoint *points, int totpoints, shor
}
/* draw a 3D stroke in "volumetric" style */
-static void gp_draw_stroke_volumetric_3d(bGPDspoint *points, int totpoints, short thickness,
- short UNUSED(dflag), short UNUSED(sflag))
+static void gp_draw_stroke_volumetric_3d(
+ bGPDspoint *points, int totpoints, short thickness,
+ short UNUSED(dflag), short UNUSED(sflag), float diff_mat[4][4], float ink[4])
{
GLUquadricObj *qobj = gluNewQuadric();
@@ -286,7 +319,7 @@ static void gp_draw_stroke_volumetric_3d(bGPDspoint *points, int totpoints, shor
bGPDspoint *pt;
int i;
-
+ float fpt[3];
/* Get the basic modelview matrix we use for performing calculations */
glGetFloatv(GL_MODELVIEW_MATRIX, (float *)base_modelview);
@@ -305,8 +338,13 @@ static void gp_draw_stroke_volumetric_3d(bGPDspoint *points, int totpoints, shor
glPushMatrix();
for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
+ /* color of point */
+ gp_set_point_color(pt, ink);
+
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+
/* apply translation to base_modelview, so that the translated point is put in the right place */
- translate_m4(base_modelview, pt->x, pt->y, pt->z);
+ translate_m4(base_modelview, fpt[0], fpt[1], fpt[2]);
/* copy the translation component to the billboard matrix we're going to use,
* then reset the base matrix to the original values so that we can do the same
@@ -378,9 +416,9 @@ static void gp_stroke_2d_flat(bGPDspoint *points, int totpoints, float(*points2d
static void gp_triangulate_stroke_fill(bGPDstroke *gps)
{
BLI_assert(gps->totpoints >= 3);
- gps->tot_triangles = gps->totpoints - 2;
-
+
/* allocate memory for temporary areas */
+ gps->tot_triangles = gps->totpoints - 2;
unsigned int (*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles, "GP Stroke temp triangulation");
float (*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints, "GP Stroke temp 2d points");
@@ -390,6 +428,8 @@ static void gp_triangulate_stroke_fill(bGPDstroke *gps)
gp_stroke_2d_flat(gps->points, gps->totpoints, points2d, &direction);
BLI_polyfill_calc((const float(*)[2])points2d, (unsigned int)gps->totpoints, direction, (unsigned int(*)[3])tmp_triangles);
+ /* Number of triangles */
+ gps->tot_triangles = gps->totpoints - 2;
/* save triangulation data in stroke cache */
if (gps->tot_triangles > 0) {
if (gps->triangles == NULL) {
@@ -399,9 +439,7 @@ static void gp_triangulate_stroke_fill(bGPDstroke *gps)
gps->triangles = MEM_recallocN(gps->triangles, sizeof(*gps->triangles) * gps->tot_triangles);
}
- int i;
-
- for (i = 0; i < gps->tot_triangles; i++) {
+ for (int i = 0; i < gps->tot_triangles; i++) {
bGPDtriangle *stroke_triangle = &gps->triangles[i];
stroke_triangle->v1 = tmp_triangles[i][0];
stroke_triangle->v2 = tmp_triangles[i][1];
@@ -428,21 +466,27 @@ static void gp_triangulate_stroke_fill(bGPDstroke *gps)
/* draw fills for shapes */
-static void gp_draw_stroke_fill(bGPDstroke *gps, short UNUSED(thickness), short dflag, int offsx, int offsy, int winx, int winy)
+static void gp_draw_stroke_fill(
+ bGPdata *gpd, bGPDstroke *gps,
+ int offsx, int offsy, int winx, int winy, float diff_mat[4][4])
{
+ bGPDpalettecolor *palcolor;
+ int i;
+ float fpt[3];
+
BLI_assert(gps->totpoints >= 3);
-
+
+ palcolor = ED_gpencil_stroke_getcolor(gpd, gps);
+
/* Triangulation fill if high quality flag is enabled */
- if (dflag & GP_DRAWDATA_HQ_FILL) {
+ if (palcolor->flag & PC_COLOR_HQ_FILL) {
bGPDtriangle *stroke_triangle;
bGPDspoint *pt;
- int i;
-
+
/* Calculate triangles cache for filling area (must be done only after changes) */
if ((gps->flag & GP_STROKE_RECALC_CACHES) || (gps->tot_triangles == 0) || (gps->triangles == NULL)) {
gp_triangulate_stroke_fill(gps);
}
-
/* Draw all triangles for filling the polygon (cache must be calculated before) */
BLI_assert(gps->tot_triangles >= 1);
glBegin(GL_TRIANGLES);
@@ -450,32 +494,33 @@ static void gp_draw_stroke_fill(bGPDstroke *gps, short UNUSED(thickness), short
if (gps->flag & GP_STROKE_3DSPACE) {
/* vertex 1 */
pt = &gps->points[stroke_triangle->v1];
- glVertex3fv(&pt->x);
-
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ glVertex3fv(fpt);
/* vertex 2 */
pt = &gps->points[stroke_triangle->v2];
- glVertex3fv(&pt->x);
-
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ glVertex3fv(fpt);
/* vertex 3 */
pt = &gps->points[stroke_triangle->v3];
- glVertex3fv(&pt->x);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ glVertex3fv(fpt);
}
else {
float co[2];
-
/* vertex 1 */
pt = &gps->points[stroke_triangle->v1];
- gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
glVertex2fv(co);
-
/* vertex 2 */
pt = &gps->points[stroke_triangle->v2];
- gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
glVertex2fv(co);
-
/* vertex 3 */
pt = &gps->points[stroke_triangle->v3];
- gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
glVertex2fv(co);
}
}
@@ -483,30 +528,31 @@ static void gp_draw_stroke_fill(bGPDstroke *gps, short UNUSED(thickness), short
}
else {
/* As an initial implementation, we use the OpenGL filled polygon drawing
- * here since it's the easiest option to implement for this case. It does
- * come with limitations (notably for concave shapes), though it works well
- * enough for many simple situations.
- *
- * We keep this legacy implementation around despite now having the high quality
- * fills, as this is necessary for keeping everything working nicely for files
- * created using old versions of Blender which may have depended on the artifacts
- * the old fills created.
- */
+ * here since it's the easiest option to implement for this case. It does
+ * come with limitations (notably for concave shapes), though it shouldn't
+ * be much of an issue in most cases.
+ *
+ * We keep this legacy implementation around despite now having the high quality
+ * fills, as this is necessary for keeping everything working nicely for files
+ * created using old versions of Blender which may have depended on the artifacts
+ * the old fills created.
+ */
bGPDspoint *pt;
- int i;
-
+
glBegin(GL_POLYGON);
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if (gps->flag & GP_STROKE_3DSPACE) {
- glVertex3fv(&pt->x);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ glVertex3fv(fpt);
}
else {
float co[2];
-
- gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
glVertex2fv(co);
}
}
+
glEnd();
}
}
@@ -514,23 +560,33 @@ static void gp_draw_stroke_fill(bGPDstroke *gps, short UNUSED(thickness), short
/* ----- Existing Strokes Drawing (3D and Point) ------ */
/* draw a given stroke - just a single dot (only one point) */
-static void gp_draw_stroke_point(bGPDspoint *points, short thickness, short dflag, short sflag,
- int offsx, int offsy, int winx, int winy)
+static void gp_draw_stroke_point(
+ bGPDspoint *points, short thickness, short dflag, short sflag,
+ int offsx, int offsy, int winx, int winy, float diff_mat[4][4], float ink[4])
{
+ float fpt[3];
+ bGPDspoint *pt = &points[0];
+
+ /* color of point */
+ gp_set_point_color(pt, ink);
+
/* set point thickness (since there's only one of these) */
glPointSize((float)(thickness + 2) * points->pressure);
+ /* get final position using parent matrix */
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+
/* draw point */
if (sflag & GP_STROKE_3DSPACE) {
glBegin(GL_POINTS);
- glVertex3fv(&points->x);
+ glVertex3fv(fpt);
glEnd();
}
else {
float co[2];
/* get coordinates of point */
- gp_calc_2d_stroke_xy(points, sflag, offsx, offsy, winx, winy, co);
+ gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co);
/* if thickness is less than GP_DRAWTHICKNESS_SPECIAL, simple dot looks ok
* - also mandatory in if Image Editor 'image-based' dot
@@ -559,16 +615,21 @@ static void gp_draw_stroke_point(bGPDspoint *points, short thickness, short dfla
}
/* draw a given stroke in 3d (i.e. in 3d-space), using simple ogl lines */
-static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness, bool debug, short UNUSED(sflag))
+static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness, bool debug,
+ short UNUSED(sflag), float diff_mat[4][4], float ink[4], bool cyclic)
{
- bGPDspoint *pt;
+ bGPDspoint *pt, *pt2;
float curpressure = points[0].pressure;
int i;
-
+ float fpt[3];
+ float cyclic_fpt[3];
+
/* draw stroke curve */
glLineWidth(max_ff(curpressure * thickness, 1.0f));
glBegin(GL_LINE_STRIP);
for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
+ gp_set_point_color(pt, ink);
+
/* if there was a significant pressure change, stop the curve, change the thickness of the stroke,
* and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP)
* Note: we want more visible levels of pressures when thickness is bigger.
@@ -580,14 +641,28 @@ static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness
glBegin(GL_LINE_STRIP);
/* need to roll-back one point to ensure that there are no gaps in the stroke */
- if (i != 0) glVertex3fv(&(pt - 1)->x);
+ if (i != 0) {
+ pt2 = pt - 1;
+ mul_v3_m4v3(fpt, diff_mat, &pt2->x);
+ glVertex3fv(fpt);
+ }
/* now the point we want... */
- glVertex3fv(&pt->x);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ glVertex3fv(fpt);
}
else {
- glVertex3fv(&pt->x);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ glVertex3fv(fpt);
}
+ /* saves first point to use in cyclic */
+ if (i == 0) {
+ copy_v3_v3(cyclic_fpt, fpt);
+ }
+ }
+ /* if cyclic draw line to first point */
+ if (cyclic) {
+ glVertex3fv(cyclic_fpt);
}
glEnd();
@@ -597,9 +672,12 @@ static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness
glPointSize((float)(thickness + 2));
glBegin(GL_POINTS);
- for (i = 0, pt = points; i < totpoints && pt; i++, pt++)
- glVertex3fv(&pt->x);
+ for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ glVertex3fv(fpt);
+ }
glEnd();
+
}
}
@@ -607,7 +685,7 @@ static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness
/* draw a given stroke in 2d */
static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag,
- bool debug, int offsx, int offsy, int winx, int winy)
+ bool debug, int offsx, int offsy, int winx, int winy, float diff_mat[4][4], float ink[4])
{
/* otherwise thickness is twice that of the 3D view */
float thickness = (float)thickness_s * 0.5f;
@@ -625,6 +703,7 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
bGPDspoint *pt1, *pt2;
float pm[2];
int i;
+ float fpt[3];
glShadeModel(GL_FLAT);
glBegin(GL_QUADS);
@@ -635,10 +714,13 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
float m1[2], m2[2]; /* gradient and normal */
float mt[2], sc[2]; /* gradient for thickness, point for end-cap */
float pthick; /* thickness at segment point */
-
+
/* get x and y coordinates from points */
- gp_calc_2d_stroke_xy(pt1, sflag, offsx, offsy, winx, winy, s0);
- gp_calc_2d_stroke_xy(pt2, sflag, offsx, offsy, winx, winy, s1);
+ mul_v3_m4v3(fpt, diff_mat, &pt1->x);
+ gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, s0);
+
+ mul_v3_m4v3(fpt, diff_mat, &pt2->x);
+ gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, s1);
/* calculate gradient and normal - 'angle'=(ny/nx) */
m1[1] = s1[1] - s0[1];
@@ -650,6 +732,9 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
/* always use pressure from first point here */
pthick = (pt1->pressure * thickness * scalefac);
+ /* color of point */
+ gp_set_point_color(pt1, ink);
+
/* if the first segment, start of segment is segment's normal */
if (i == 0) {
/* draw start cap first
@@ -725,6 +810,9 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
/* for once, we use second point's pressure (otherwise it won't be drawn) */
pthick = (pt2->pressure * thickness * scalefac);
+ /* color of point */
+ gp_set_point_color(pt2, ink);
+
/* calculate points for end of segment */
mt[0] = m2[0] * pthick;
mt[1] = m2[1] * pthick;
@@ -763,20 +851,22 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
}
glEnd();
+ glShadeModel(GL_SMOOTH);
}
/* draw debug points of curve on top? (original stroke points) */
if (debug) {
bGPDspoint *pt;
int i;
-
+ float fpt[3];
+
glPointSize((float)(thickness_s + 2));
glBegin(GL_POINTS);
for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
float co[2];
-
- gp_calc_2d_stroke_xy(pt, sflag, offsx, offsy, winx, winy, co);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co);
glVertex2fv(co);
}
glEnd();
@@ -817,26 +907,45 @@ static bool gp_can_draw_stroke(const bGPDstroke *gps, const int dflag)
}
/* draw a set of strokes */
-static void gp_draw_strokes(bGPDframe *gpf, int offsx, int offsy, int winx, int winy, int dflag,
- bool debug, short lthick, const float color[4], const float fill_color[4])
+static void gp_draw_strokes(
+ bGPdata *gpd, bGPDframe *gpf, int offsx, int offsy, int winx, int winy, int dflag,
+ bool debug, short lthick, const float opacity, const float tintcolor[4],
+ const bool onion, const bool custonion, float diff_mat[4][4])
{
bGPDstroke *gps;
-
+ float tcolor[4];
+ float tfill[4];
+ short sthickness;
+ float ink[4];
+
for (gps = gpf->strokes.first; gps; gps = gps->next) {
/* check if stroke can be drawn */
- if (gp_can_draw_stroke(gps, dflag) == false)
+ if (gp_can_draw_stroke(gps, dflag) == false) {
continue;
-
+ }
+ /* check if the color is visible */
+ bGPDpalettecolor *palcolor = ED_gpencil_stroke_getcolor(gpd, gps);
+ if ((palcolor == NULL) ||
+ (palcolor->flag & PC_COLOR_HIDE) ||
+ /* if onion and ghost flag do not draw*/
+ (onion && (palcolor->flag & PC_COLOR_ONIONSKIN)))
+ {
+ continue;
+ }
+
+ /* calculate thickness */
+ sthickness = gps->thickness + lthick;
+
/* check which stroke-drawer to use */
if (dflag & GP_DRAWDATA_ONLY3D) {
const int no_xray = (dflag & GP_DRAWDATA_NO_XRAY);
int mask_orig = 0;
-
+
if (no_xray) {
glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
glDepthMask(0);
glEnable(GL_DEPTH_TEST);
-
+
/* first arg is normally rv3d->dist, but this isn't
* available here and seems to work quite well without */
bglPolygonOffset(1.0f, 1.0f);
@@ -845,34 +954,65 @@ static void gp_draw_strokes(bGPDframe *gpf, int offsx, int offsy, int winx, int
glPolygonOffset(-1.0f, -1.0f);
#endif
}
-
+
/* 3D Fill */
- if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) {
- glColor4fv(fill_color);
- gp_draw_stroke_fill(gps, lthick, dflag, offsx, offsy, winx, winy);
+ //if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) {
+ if (gps->totpoints >= 3) {
+ /* set color using palette, tint color and opacity */
+ interp_v3_v3v3(tfill, palcolor->fill, tintcolor, tintcolor[3]);
+ tfill[3] = palcolor->fill[3] * opacity;
+ if (tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) {
+ if (!onion) {
+ glColor4fv(tfill);
+ }
+ else {
+ if (custonion) {
+ glColor4fv(tintcolor);
+ }
+ else {
+ ARRAY_SET_ITEMS(tfill, UNPACK3(palcolor->fill), tintcolor[3]);
+ glColor4fv(tfill);
+ }
+ }
+ gp_draw_stroke_fill(gpd, gps, offsx, offsy, winx, winy, diff_mat);
+ }
}
-
+
/* 3D Stroke */
- glColor4fv(color);
-
- if (dflag & GP_DRAWDATA_VOLUMETRIC) {
+ /* set color using palette, tint color and opacity */
+ if (!onion) {
+ interp_v3_v3v3(tcolor, palcolor->color, tintcolor, tintcolor[3]);
+ tcolor[3] = palcolor->color[3] * opacity;
+ copy_v4_v4(ink, tcolor);
+ }
+ else {
+ if (custonion) {
+ copy_v4_v4(ink, tintcolor);
+ }
+ else {
+ ARRAY_SET_ITEMS(tcolor, palcolor->color[0], palcolor->color[1], palcolor->color[2], opacity);
+ copy_v4_v4(ink, tcolor);
+ }
+ }
+ if (palcolor->flag & PC_COLOR_VOLUMETRIC) {
/* volumetric stroke drawing */
- gp_draw_stroke_volumetric_3d(gps->points, gps->totpoints, lthick, dflag, gps->flag);
+ gp_draw_stroke_volumetric_3d(gps->points, gps->totpoints, sthickness, dflag, gps->flag, diff_mat, ink);
}
else {
/* 3D Lines - OpenGL primitives-based */
if (gps->totpoints == 1) {
- gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
+ gp_draw_stroke_point(gps->points, sthickness, dflag, gps->flag, offsx, offsy, winx, winy,
+ diff_mat, ink);
}
else {
- gp_draw_stroke_3d(gps->points, gps->totpoints, lthick, debug, gps->flag);
+ gp_draw_stroke_3d(gps->points, gps->totpoints, sthickness, debug, gps->flag,
+ diff_mat, ink, gps->flag & GP_STROKE_CYCLIC);
}
}
-
if (no_xray) {
glDepthMask(mask_orig);
glDisable(GL_DEPTH_TEST);
-
+
bglPolygonOffset(0.0, 0.0);
#if 0
glDisable(GL_POLYGON_OFFSET_LINE);
@@ -882,25 +1022,58 @@ static void gp_draw_strokes(bGPDframe *gpf, int offsx, int offsy, int winx, int
}
else {
/* 2D - Fill */
- if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) {
- glColor4fv(fill_color);
- gp_draw_stroke_fill(gps, lthick, dflag, offsx, offsy, winx, winy);
+ if (gps->totpoints >= 3) {
+ /* set color using palette, tint color and opacity */
+ interp_v3_v3v3(tfill, palcolor->fill, tintcolor, tintcolor[3]);
+ tfill[3] = palcolor->fill[3] * opacity;
+ if (tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) {
+ if (!onion) {
+ glColor4fv(tfill);
+ }
+ else {
+ if (custonion) {
+ glColor4fv(tintcolor);
+ }
+ else {
+ ARRAY_SET_ITEMS(tfill, palcolor->fill[0], palcolor->fill[1], palcolor->fill[2],
+ tintcolor[3]);
+ glColor4fv(tfill);
+ }
+ }
+ gp_draw_stroke_fill(gpd, gps, offsx, offsy, winx, winy, diff_mat);
+ }
}
-
+
/* 2D Strokes... */
- glColor4fv(color);
-
- if (dflag & GP_DRAWDATA_VOLUMETRIC) {
+ /* set color using palette, tint color and opacity */
+ if (!onion) {
+ interp_v3_v3v3(tcolor, palcolor->color, tintcolor, tintcolor[3]);
+ tcolor[3] = palcolor->color[3] * opacity;
+ copy_v4_v4(ink, tcolor);
+ }
+ else {
+ if (custonion) {
+ copy_v4_v4(ink, tintcolor);
+ }
+ else {
+ ARRAY_SET_ITEMS(tcolor, palcolor->color[0], palcolor->color[1], palcolor->color[2], opacity);
+ copy_v4_v4(ink, tcolor);
+ }
+ }
+ if (palcolor->flag & PC_COLOR_VOLUMETRIC) {
/* blob/disk-based "volumetric" drawing */
- gp_draw_stroke_volumetric_2d(gps->points, gps->totpoints, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
+ gp_draw_stroke_volumetric_2d(gps->points, gps->totpoints, sthickness, dflag, gps->flag,
+ offsx, offsy, winx, winy, diff_mat, ink);
}
else {
/* normal 2D strokes */
if (gps->totpoints == 1) {
- gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
+ gp_draw_stroke_point(gps->points, sthickness, dflag, gps->flag, offsx, offsy, winx, winy,
+ diff_mat, ink);
}
else {
- gp_draw_stroke_2d(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, offsx, offsy, winx, winy);
+ gp_draw_stroke_2d(gps->points, gps->totpoints, sthickness, dflag, gps->flag, debug,
+ offsx, offsy, winx, winy, diff_mat, ink);
}
}
}
@@ -908,13 +1081,19 @@ static void gp_draw_strokes(bGPDframe *gpf, int offsx, int offsy, int winx, int
}
/* Draw selected verts for strokes being edited */
-static void gp_draw_strokes_edit(bGPDframe *gpf, int offsx, int offsy, int winx, int winy, short dflag, const float tcolor[3])
+static void gp_draw_strokes_edit(
+ bGPdata *gpd, bGPDframe *gpf, int offsx, int offsy, int winx, int winy, short dflag,
+ short lflag, float diff_mat[4][4], float alpha)
{
bGPDstroke *gps;
+ /* if alpha 0 do not draw */
+ if (alpha == 0.0f)
+ return;
+
const bool no_xray = (dflag & GP_DRAWDATA_NO_XRAY) != 0;
int mask_orig = 0;
-
+
/* set up depth masks... */
if (dflag & GP_DRAWDATA_ONLY3D) {
if (no_xray) {
@@ -938,7 +1117,8 @@ static void gp_draw_strokes_edit(bGPDframe *gpf, int offsx, int offsy, int winx,
bGPDspoint *pt;
float vsize, bsize;
int i;
-
+ float fpt[3];
+
/* check if stroke can be drawn */
if (gp_can_draw_stroke(gps, dflag) == false)
continue;
@@ -950,6 +1130,19 @@ static void gp_draw_strokes_edit(bGPDframe *gpf, int offsx, int offsy, int winx,
if ((gps->flag & GP_STROKE_SELECT) == 0)
continue;
+ /* verify palette color lock */
+ {
+ bGPDpalettecolor *palcolor = ED_gpencil_stroke_getcolor(gpd, gps);
+ if (palcolor != NULL) {
+ if (palcolor->flag & PC_COLOR_HIDE) {
+ continue;
+ }
+ if (((lflag & GP_LAYER_UNLOCK_COLOR) == 0) && (palcolor->flag & PC_COLOR_LOCKED)) {
+ continue;
+ }
+ }
+ }
+
/* Get size of verts:
* - The selected state needs to be larger than the unselected state so that
* they stand out more.
@@ -965,25 +1158,23 @@ static void gp_draw_strokes_edit(bGPDframe *gpf, int offsx, int offsy, int winx,
}
/* First Pass: Draw all the verts (i.e. these become the unselected state) */
- if (tcolor != NULL) {
- /* for now, we assume that the base color of the points is not too close to the real color */
- glColor3fv(tcolor);
- }
- else {
- /* this doesn't work well with the default theme and black strokes... */
- UI_ThemeColor(TH_GP_VERTEX);
- }
+ /* for now, we assume that the base color of the points is not too close to the real color */
+ /* set color using palette */
+ bGPDpalettecolor *palcolor = ED_gpencil_stroke_getcolor(gpd, gps);
+ glColor3fv(palcolor->color);
+
glPointSize(bsize);
glBegin(GL_POINTS);
for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) {
if (gps->flag & GP_STROKE_3DSPACE) {
- glVertex3fv(&pt->x);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ glVertex3fv(fpt);
}
else {
float co[2];
-
- gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
glVertex2fv(co);
}
}
@@ -991,24 +1182,54 @@ static void gp_draw_strokes_edit(bGPDframe *gpf, int offsx, int offsy, int winx,
/* Second Pass: Draw only verts which are selected */
- UI_ThemeColor(TH_GP_VERTEX_SELECT);
+ float curColor[4];
+ UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, curColor);
+ glColor4f(curColor[0], curColor[1], curColor[2], alpha);
+
glPointSize(vsize);
glBegin(GL_POINTS);
for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) {
if (pt->flag & GP_SPOINT_SELECT) {
if (gps->flag & GP_STROKE_3DSPACE) {
- glVertex3fv(&pt->x);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ glVertex3fv(fpt);
}
else {
float co[2];
- gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
glVertex2fv(co);
}
}
}
glEnd();
+
+ /* Draw start and end point if enabled stroke direction hint */
+ if ((gpd->flag & GP_DATA_SHOW_DIRECTION) && (gps->totpoints > 1)) {
+ bGPDspoint *p;
+
+ glPointSize(vsize + 4);
+ glBegin(GL_POINTS);
+
+ /* start point in green bigger */
+ glColor3f(0.0f, 1.0f, 0.0f);
+ p = &gps->points[0];
+ mul_v3_m4v3(fpt, diff_mat, &p->x);
+ glVertex3fv(fpt);
+ glEnd();
+
+ /* end point in red smaller */
+ glPointSize(vsize + 1);
+ glBegin(GL_POINTS);
+
+ glColor3f(1.0f, 0.0f, 0.0f);
+ p = &gps->points[gps->totpoints - 1];
+ mul_v3_m4v3(fpt, diff_mat, &p->x);
+ glVertex3fv(fpt);
+ glEnd();
+ }
}
@@ -1030,18 +1251,20 @@ static void gp_draw_strokes_edit(bGPDframe *gpf, int offsx, int offsy, int winx,
/* ----- General Drawing ------ */
/* draw onion-skinning for a layer */
-static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int offsy, int winx, int winy,
- int UNUSED(cfra), int dflag, bool debug, short lthick)
+static void gp_draw_onionskins(
+ bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, int offsx, int offsy, int winx, int winy,
+ int UNUSED(cfra), int dflag, bool debug, float diff_mat[4][4])
{
- const float alpha = gpl->color[3];
+ const float default_color[3] = {UNPACK3(U.gpencil_new_layer_col)};
+ const float alpha = 1.0f;
float color[4];
-
+
/* 1) Draw Previous Frames First */
if (gpl->flag & GP_LAYER_GHOST_PREVCOL) {
copy_v3_v3(color, gpl->gcolor_prev);
}
else {
- copy_v3_v3(color, gpl->color);
+ copy_v3_v3(color, default_color);
}
if (gpl->gstep > 0) {
@@ -1055,7 +1278,8 @@ static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int of
/* alpha decreases with distance from curframe index */
fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1));
color[3] = alpha * fac * 0.66f;
- gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, color, color);
+ gp_draw_strokes(gpd, gf, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color,
+ true, gpl->flag & GP_LAYER_GHOST_PREVCOL, diff_mat);
}
else
break;
@@ -1065,7 +1289,8 @@ static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int of
/* draw the strokes for the ghost frames (at half of the alpha set by user) */
if (gpf->prev) {
color[3] = (alpha / 7);
- gp_draw_strokes(gpf->prev, offsx, offsy, winx, winy, dflag, debug, lthick, color, color);
+ gp_draw_strokes(gpd, gpf->prev, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color,
+ true, gpl->flag & GP_LAYER_GHOST_PREVCOL, diff_mat);
}
}
else {
@@ -1078,7 +1303,7 @@ static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int of
copy_v3_v3(color, gpl->gcolor_next);
}
else {
- copy_v3_v3(color, gpl->color);
+ copy_v3_v3(color, default_color);
}
if (gpl->gstep_next > 0) {
@@ -1092,7 +1317,8 @@ static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int of
/* alpha decreases with distance from curframe index */
fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep_next + 1));
color[3] = alpha * fac * 0.66f;
- gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, color, color);
+ gp_draw_strokes(gpd, gf, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color,
+ true, gpl->flag & GP_LAYER_GHOST_NEXTCOL, diff_mat);
}
else
break;
@@ -1102,34 +1328,71 @@ static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int of
/* draw the strokes for the ghost frames (at half of the alpha set by user) */
if (gpf->next) {
color[3] = (alpha / 4);
- gp_draw_strokes(gpf->next, offsx, offsy, winx, winy, dflag, debug, lthick, color, color);
+ gp_draw_strokes(gpd, gpf->next, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color,
+ true, gpl->flag & GP_LAYER_GHOST_NEXTCOL, diff_mat);
}
}
else {
/* don't draw - disabled */
}
- /* 3) restore alpha */
- glColor4fv(gpl->color);
+}
+
+/* draw interpolate strokes (used only while operator is running) */
+void ED_gp_draw_interpolation(tGPDinterpolate *tgpi, const int type)
+{
+ tGPDinterpolate_layer *tgpil;
+ float diff_mat[4][4];
+ float color[4];
+
+ int offsx = 0;
+ int offsy = 0;
+ int winx = tgpi->ar->winx;
+ int winy = tgpi->ar->winy;
+
+ UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, color);
+ color[3] = 0.6f;
+ int dflag = 0;
+ /* if 3d stuff, enable flags */
+ if (type == REGION_DRAW_POST_VIEW) {
+ dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS);
+ }
+
+ /* turn on alpha-blending */
+ glEnable(GL_BLEND);
+ for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
+ /* calculate parent position */
+ ED_gpencil_parent_location(tgpil->gpl, diff_mat);
+ if (tgpil->interFrame) {
+ gp_draw_strokes(tgpi->gpd, tgpil->interFrame, offsx, offsy, winx, winy, dflag, false,
+ tgpil->gpl->thickness, 1.0f, color, true, true, diff_mat);
+ }
+ }
+ glDisable(GL_BLEND);
}
/* loop over gpencil data layers, drawing them */
-static void gp_draw_data_layers(bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag)
+static void gp_draw_data_layers(
+ bGPDbrush *brush, float alpha, bGPdata *gpd,
+ int offsx, int offsy, int winx, int winy, int cfra, int dflag)
{
bGPDlayer *gpl;
-
+ float diff_mat[4][4];
+
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
bGPDframe *gpf;
-
+ /* calculate parent position */
+ ED_gpencil_parent_location(gpl, diff_mat);
+
bool debug = (gpl->flag & GP_LAYER_DRAWDEBUG) ? true : false;
- short lthick = gpl->thickness;
+ short lthick = brush->thickness + gpl->thickness;
/* don't draw layer if hidden */
if (gpl->flag & GP_LAYER_HIDE)
continue;
/* get frame to draw */
- gpf = gpencil_layer_getframe(gpl, cfra, 0);
+ gpf = BKE_gpencil_layer_getframe(gpl, cfra, 0);
if (gpf == NULL)
continue;
@@ -1154,9 +1417,6 @@ static void gp_draw_data_layers(bGPdata *gpd, int offsx, int offsy, int winx, in
/* HQ fills... */
GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_HQ_FILL), GP_DRAWDATA_HQ_FILL);
- /* fill strokes... */
- // XXX: this is not a very good limit
- GP_DRAWFLAG_APPLY((gpl->fill[3] > GPENCIL_ALPHA_OPACITY_THRESH), GP_DRAWDATA_FILL);
#undef GP_DRAWFLAG_APPLY
/* draw 'onionskins' (frame left + right) */
@@ -1164,11 +1424,12 @@ static void gp_draw_data_layers(bGPdata *gpd, int offsx, int offsy, int winx, in
/* Drawing method - only immediately surrounding (gstep = 0),
* or within a frame range on either side (gstep > 0)
*/
- gp_draw_onionskins(gpl, gpf, offsx, offsy, winx, winy, cfra, dflag, debug, lthick);
+ gp_draw_onionskins(gpd, gpl, gpf, offsx, offsy, winx, winy, cfra, dflag, debug, diff_mat);
}
/* draw the strokes already in active frame */
- gp_draw_strokes(gpf, offsx, offsy, winx, winy, dflag, debug, lthick, gpl->color, gpl->fill);
+ gp_draw_strokes(gpd, gpf, offsx, offsy, winx, winy, dflag, debug, gpl->thickness,
+ gpl->opacity, gpl->tintcolor, false, false, diff_mat);
/* Draw verts of selected strokes
* - when doing OpenGL renders, we don't want to be showing these, as that ends up flickering
@@ -1182,8 +1443,7 @@ static void gp_draw_data_layers(bGPdata *gpd, int offsx, int offsy, int winx, in
(gpl->flag & GP_LAYER_LOCKED) == 0 &&
(gpd->flag & GP_DATA_STROKE_EDITMODE))
{
- gp_draw_strokes_edit(gpf, offsx, offsy, winx, winy, dflag,
- (gpl->color[3] < 0.95f) ? gpl->color : NULL);
+ gp_draw_strokes_edit(gpd, gpf, offsx, offsy, winx, winy, dflag, gpl->flag, diff_mat, alpha);
}
/* Check if may need to draw the active stroke cache, only if this layer is the active layer
@@ -1193,7 +1453,7 @@ static void gp_draw_data_layers(bGPdata *gpd, int offsx, int offsy, int winx, in
(gpf->flag & GP_FRAME_PAINT))
{
/* Set color for drawing buffer stroke - since this may not be set yet */
- glColor4fv(gpl->color);
+ // glColor4fv(gpl->color);
/* Buffer stroke needs to be drawn with a different linestyle
* to help differentiate them from normal strokes.
@@ -1201,11 +1461,12 @@ static void gp_draw_data_layers(bGPdata *gpd, int offsx, int offsy, int winx, in
* It should also be noted that sbuffer contains temporary point types
* i.e. tGPspoints NOT bGPDspoints
*/
- if (gpl->flag & GP_LAYER_VOLUMETRIC) {
- gp_draw_stroke_volumetric_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag);
+ if (gpd->sflag & PC_COLOR_VOLUMETRIC) {
+ gp_draw_stroke_volumetric_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick,
+ dflag, gpd->sbuffer_sflag, gpd->scolor);
}
else {
- gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag);
+ gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag, gpd->scolor);
}
}
}
@@ -1257,7 +1518,9 @@ static void gp_draw_status_text(bGPdata *gpd, ARegion *ar)
}
/* draw grease-pencil datablock */
-static void gp_draw_data(bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag)
+static void gp_draw_data(
+ bGPDbrush *brush, float alpha, bGPdata *gpd,
+ int offsx, int offsy, int winx, int winy, int cfra, int dflag)
{
/* reset line drawing style (in case previous user didn't reset) */
setlinestyle(0);
@@ -1275,7 +1538,7 @@ static void gp_draw_data(bGPdata *gpd, int offsx, int offsy, int winx, int winy,
glEnable(GL_BLEND);
/* draw! */
- gp_draw_data_layers(gpd, offsx, offsy, winx, winy, cfra, dflag);
+ gp_draw_data_layers(brush, alpha, gpd, offsx, offsy, winx, winy, cfra, dflag);
/* turn off alpha blending, then smooth lines */
glDisable(GL_BLEND); // alpha blending
@@ -1302,14 +1565,25 @@ static void gp_draw_data_all(Scene *scene, bGPdata *gpd, int offsx, int offsy, i
}
if (gpd_source) {
- gp_draw_data(gpd_source, offsx, offsy, winx, winy, cfra, dflag);
+ ToolSettings *ts = scene->toolsettings;
+ bGPDbrush *brush = BKE_gpencil_brush_getactive(ts);
+ if (brush != NULL) {
+ gp_draw_data(brush, ts->gp_sculpt.alpha, gpd_source,
+ offsx, offsy, winx, winy, cfra, dflag);
+ }
+
}
}
/* scene/clip data has already been drawn, only object/track data is drawn here
* if gpd_source == gpd, we don't have any object/track data and we can skip */
if (gpd_source == NULL || (gpd_source && gpd_source != gpd)) {
- gp_draw_data(gpd, offsx, offsy, winx, winy, cfra, dflag);
+ ToolSettings *ts = scene->toolsettings;
+ bGPDbrush *brush = BKE_gpencil_brush_getactive(ts);
+ if (brush != NULL) {
+ gp_draw_data(brush, ts->gp_sculpt.alpha, gpd,
+ offsx, offsy, winx, winy, cfra, dflag);
+ }
}
}
@@ -1478,6 +1752,7 @@ void ED_gpencil_draw_view3d(wmWindowManager *wm, Scene *scene, View3D *v3d, AReg
/* draw it! */
gp_draw_data_all(scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype);
+
}
void ED_gpencil_draw_ex(Scene *scene, bGPdata *gpd, int winx, int winy, const int cfra, const char spacetype)
diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c
index a49b3362155..bd4856f1b93 100644
--- a/source/blender/editors/gpencil/editaction_gpencil.c
+++ b/source/blender/editors/gpencil/editaction_gpencil.c
@@ -205,6 +205,36 @@ void ED_gplayer_frames_select_border(bGPDlayer *gpl, float min, float max, short
}
}
+/* select the frames in this layer that occur within the lasso/circle region specified */
+void ED_gplayer_frames_select_region(KeyframeEditData *ked, bGPDlayer *gpl, short tool, short select_mode)
+{
+ bGPDframe *gpf;
+
+ if (gpl == NULL)
+ return;
+
+ /* only select frames which are within the region */
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ /* construct a dummy point coordinate to do this testing with */
+ float pt[2] = {0};
+
+ pt[0] = gpf->framenum;
+ pt[1] = ked->channel_y;
+
+ /* check the necessary regions */
+ if (tool == BEZT_OK_CHANNEL_LASSO) {
+ /* Lasso */
+ if (keyframe_region_lasso_test(ked->data, pt))
+ gpframe_select(gpf, select_mode);
+ }
+ else if (tool == BEZT_OK_CHANNEL_CIRCLE) {
+ /* Circle */
+ if (keyframe_region_circle_test(ked->data, pt))
+ gpframe_select(gpf, select_mode);
+ }
+ }
+}
+
/* ***************************************** */
/* Frame Editing Tools */
@@ -223,7 +253,7 @@ bool ED_gplayer_frames_delete(bGPDlayer *gpl)
gpfn = gpf->next;
if (gpf->flag & GP_FRAME_SELECT)
- changed |= gpencil_layer_delframe(gpl, gpf);
+ changed |= BKE_gpencil_layer_delframe(gpl, gpf);
}
return changed;
@@ -247,7 +277,7 @@ void ED_gplayer_frames_duplicate(bGPDlayer *gpl)
bGPDframe *gpfd;
/* duplicate frame, and deselect self */
- gpfd = gpencil_frame_duplicate(gpf);
+ gpfd = BKE_gpencil_frame_duplicate(gpf);
gpf->flag &= ~GP_FRAME_SELECT;
BLI_insertlinkafter(&gpl->frames, gpf, gpfd);
@@ -293,7 +323,7 @@ static int gp_anim_copy_cfra = 0;
/* This function frees any MEM_calloc'ed copy/paste buffer data */
void ED_gpencil_anim_copybuf_free(void)
{
- free_gpencil_layers(&gp_anim_copybuf);
+ BKE_gpencil_free_layers(&gp_anim_copybuf);
BLI_listbase_clear(&gp_anim_copybuf);
gp_anim_copy_firstframe = 999999999;
@@ -334,7 +364,7 @@ bool ED_gpencil_anim_copybuf_copy(bAnimContext *ac)
/* if frame is selected, make duplicate it and its strokes */
if (gpf->flag & GP_FRAME_SELECT) {
/* make a copy of this frame */
- bGPDframe *new_frame = gpencil_frame_duplicate(gpf);
+ bGPDframe *new_frame = BKE_gpencil_frame_duplicate(gpf);
BLI_addtail(&copied_frames, new_frame);
/* extend extents for keyframes encountered */
@@ -445,7 +475,7 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
gpfs->framenum += offset;
/* get frame to copy data into (if no frame returned, then just ignore) */
- gpf = gpencil_layer_getframe(gpld, gpfs->framenum, 1);
+ gpf = BKE_gpencil_layer_getframe(gpld, gpfs->framenum, 1);
if (gpf) {
bGPDstroke *gps, *gpsn;
@@ -468,7 +498,7 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
/* if no strokes (i.e. new frame) added, free gpf */
if (BLI_listbase_is_empty(&gpf->strokes))
- gpencil_layer_delframe(gpld, gpf);
+ BKE_gpencil_layer_delframe(gpld, gpf);
}
/* unapply offset from buffer-frame */
diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c
index 561a8e4b61c..8576cbca239 100644
--- a/source/blender/editors/gpencil/gpencil_brush.c
+++ b/source/blender/editors/gpencil/gpencil_brush.c
@@ -18,7 +18,7 @@
* The Original Code is Copyright (C) 2015, Blender Foundation
* This is a new part of Blender
*
- * Contributor(s): Joshua Leung
+ * Contributor(s): Joshua Leung, Antonio Vazquez
*
* ***** END GPL LICENSE BLOCK *****
*
@@ -51,6 +51,7 @@
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_object_types.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -223,9 +224,26 @@ static bool gp_brush_smooth_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i
GP_EditBrush_Data *brush = gso->brush;
float inf = gp_brush_influence_calc(gso, radius, co);
bool affect_pressure = (brush->flag & GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE) != 0;
-
+ /* need one flag enabled by default */
+ if ((gso->settings->flag & (GP_BRUSHEDIT_FLAG_APPLY_POSITION |
+ GP_BRUSHEDIT_FLAG_APPLY_STRENGTH |
+ GP_BRUSHEDIT_FLAG_APPLY_THICKNESS)) == 0)
+ {
+ gso->settings->flag |= GP_BRUSHEDIT_FLAG_APPLY_POSITION;
+ }
+
/* perform smoothing */
- return gp_smooth_stroke(gps, i, inf, affect_pressure);
+ if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_POSITION) {
+ gp_smooth_stroke(gps, i, inf, affect_pressure);
+ }
+ if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_STRENGTH) {
+ gp_smooth_stroke_strength(gps, i, inf);
+ }
+ if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_THICKNESS) {
+ gp_smooth_stroke_thickness(gps, i, inf);
+ }
+
+ return true;
}
/* ----------------------------------------------- */
@@ -268,6 +286,41 @@ static bool gp_brush_thickness_apply(tGP_BrushEditData *gso, bGPDstroke *gps, in
/* ----------------------------------------------- */
+/* Color Strength Brush */
+
+/* Make color more or less transparent by the specified amounts */
+static bool gp_brush_strength_apply(
+ tGP_BrushEditData *gso, bGPDstroke *gps, int i,
+ const int radius, const int co[2])
+{
+ bGPDspoint *pt = gps->points + i;
+ float inf;
+
+ /* Compute strength of effect
+ * - We divide the strength by 10, so that users can set "sane" values.
+ * Otherwise, good default values are in the range of 0.093
+ */
+ inf = gp_brush_influence_calc(gso, radius, co) / 10.0f;
+
+ /* apply */
+ // XXX: this is much too strong, and it should probably do some smoothing with the surrounding stuff
+ if (gp_brush_invert_check(gso)) {
+ /* make line thinner - reduce stroke pressure */
+ pt->strength -= inf;
+ }
+ else {
+ /* make line thicker - increase stroke pressure */
+ pt->strength += inf;
+ }
+
+ /* Strength should stay within [0.0, 1.0] */
+ CLAMP(pt->strength, 0.0f, 1.0f);
+
+ return true;
+}
+
+
+/* ----------------------------------------------- */
/* Grab Brush */
/* Custom data per stroke for the Grab Brush
@@ -373,11 +426,12 @@ static void gp_brush_grab_calc_dvec(tGP_BrushEditData *gso)
}
/* Apply grab transform to all relevant points of the affected strokes */
-static void gp_brush_grab_apply_cached(tGP_BrushEditData *gso, bGPDstroke *gps)
+static void gp_brush_grab_apply_cached(
+ tGP_BrushEditData *gso, bGPDstroke *gps, bool parented, float diff_mat[4][4])
{
tGPSB_Grab_StrokeData *data = BLI_ghash_lookup(gso->stroke_customdata, gps);
int i;
-
+
/* Apply dvec to all of the stored points */
for (i = 0; i < data->size; i++) {
bGPDspoint *pt = &gps->points[data->points[i]];
@@ -385,9 +439,23 @@ static void gp_brush_grab_apply_cached(tGP_BrushEditData *gso, bGPDstroke *gps)
/* adjust the amount of displacement to apply */
mul_v3_v3fl(delta, gso->dvec, data->weights[i]);
+ if (!parented) {
+ /* apply */
+ add_v3_v3(&pt->x, delta);
+ }
+ else {
+ float fpt[3];
+ /* apply transformation */
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ /* apply */
+ add_v3_v3(fpt, delta);
+ copy_v3_v3(&pt->x, fpt);
+ /* undo transformation to the init parent position */
+ float inverse_diff_mat[4][4];
+ invert_m4_m4(inverse_diff_mat, diff_mat);
+ mul_m4_v3(inverse_diff_mat, &pt->x);
+ }
- /* apply */
- add_v3_v3(&pt->x, delta);
}
}
@@ -592,62 +660,92 @@ static bool gp_brush_randomize_apply(tGP_BrushEditData *gso, bGPDstroke *gps, in
*/
const float inf = gp_brush_influence_calc(gso, radius, co) / 2.0f;
const float fac = BLI_frand() * inf;
-
- /* Jitter is applied perpendicular to the mouse movement vector
- * - We compute all effects in screenspace (since it's easier)
- * and then project these to get the points/distances in
- * viewspace as needed
- */
- float mvec[2], svec[2];
-
- /* mouse movement in ints -> floats */
- mvec[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
- mvec[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
-
- /* rotate mvec by 90 degrees... */
- svec[0] = -mvec[1];
- svec[1] = mvec[0];
-
- //printf("svec = %f %f, ", svec[0], svec[1]);
-
- /* scale the displacement by the random displacement, and apply */
- if (BLI_frand() > 0.5f) {
- mul_v2_fl(svec, -fac);
- }
- else {
- mul_v2_fl(svec, fac);
+ /* need one flag enabled by default */
+ if ((gso->settings->flag & (GP_BRUSHEDIT_FLAG_APPLY_POSITION |
+ GP_BRUSHEDIT_FLAG_APPLY_STRENGTH |
+ GP_BRUSHEDIT_FLAG_APPLY_THICKNESS)) == 0)
+ {
+ gso->settings->flag |= GP_BRUSHEDIT_FLAG_APPLY_POSITION;
}
-
- //printf("%f %f (%f), nco = {%f %f}, co = %d %d\n", svec[0], svec[1], fac, nco[0], nco[1], co[0], co[1]);
-
- /* convert to dataspace */
- if (gps->flag & GP_STROKE_3DSPACE) {
- /* 3D: Project to 3D space */
- if (gso->sa->spacetype == SPACE_VIEW3D) {
- bool flip;
- RegionView3D *rv3d = gso->ar->regiondata;
- float zfac = ED_view3d_calc_zfac(rv3d, &pt->x, &flip);
- if (flip == false) {
- float dvec[3];
- ED_view3d_win_to_delta(gso->gsc.ar, svec, dvec, zfac);
- add_v3_v3(&pt->x, dvec);
+
+ /* apply random to position */
+ if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_POSITION) {
+ /* Jitter is applied perpendicular to the mouse movement vector
+ * - We compute all effects in screenspace (since it's easier)
+ * and then project these to get the points/distances in
+ * viewspace as needed
+ */
+ float mvec[2], svec[2];
+
+ /* mouse movement in ints -> floats */
+ mvec[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
+ mvec[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
+
+ /* rotate mvec by 90 degrees... */
+ svec[0] = -mvec[1];
+ svec[1] = mvec[0];
+
+ /* scale the displacement by the random displacement, and apply */
+ if (BLI_frand() > 0.5f) {
+ mul_v2_fl(svec, -fac);
+ }
+ else {
+ mul_v2_fl(svec, fac);
+ }
+
+ //printf("%f %f (%f), nco = {%f %f}, co = %d %d\n", svec[0], svec[1], fac, nco[0], nco[1], co[0], co[1]);
+
+ /* convert to dataspace */
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ /* 3D: Project to 3D space */
+ if (gso->sa->spacetype == SPACE_VIEW3D) {
+ bool flip;
+ RegionView3D *rv3d = gso->ar->regiondata;
+ float zfac = ED_view3d_calc_zfac(rv3d, &pt->x, &flip);
+ if (flip == false) {
+ float dvec[3];
+ ED_view3d_win_to_delta(gso->gsc.ar, svec, dvec, zfac);
+ add_v3_v3(&pt->x, dvec);
+ }
+ }
+ else {
+ /* ERROR */
+ BLI_assert("3D stroke being sculpted in non-3D view");
}
}
else {
- /* ERROR */
- BLI_assert("3D stroke being sculpted in non-3D view");
+ /* 2D: As-is */
+ // XXX: v2d scaling/offset?
+ float nco[2];
+ nco[0] = (float)co[0] + svec[0];
+ nco[1] = (float)co[1] + svec[1];
+
+ copy_v2_v2(&pt->x, nco);
}
}
- else {
- /* 2D: As-is */
- // XXX: v2d scaling/offset?
- float nco[2];
- nco[0] = (float)co[0] + svec[0];
- nco[1] = (float)co[1] + svec[1];
-
- copy_v2_v2(&pt->x, nco);
+ /* apply random to strength */
+ if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_STRENGTH) {
+ if (BLI_frand() > 0.5f) {
+ pt->strength += fac;
+ }
+ else {
+ pt->strength -= fac;
+ }
+ CLAMP_MIN(pt->strength, 0.0f);
+ CLAMP_MAX(pt->strength, 1.0f);
}
-
+ /* apply random to thickness (use pressure) */
+ if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_THICKNESS) {
+ if (BLI_frand() > 0.5f) {
+ pt->pressure += fac;
+ }
+ else {
+ pt->pressure -= fac;
+ }
+ /* only limit lower value */
+ CLAMP_MIN(pt->pressure, 0.0f);
+ }
+
/* done */
return true;
}
@@ -743,7 +841,7 @@ static void gp_brush_clone_add(bContext *C, tGP_BrushEditData *gso)
Scene *scene = gso->scene;
bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
- bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, true);
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, true);
bGPDstroke *gps;
float delta[3];
@@ -866,14 +964,18 @@ static void gp_brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customda
glTranslatef((float)x, (float)y, 0.0f);
- /* TODO: toggle between add and remove? */
- glColor4ub(255, 255, 255, 128);
-
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
+ /* Inner Ring: Light color for action of the brush */
+ /* TODO: toggle between add and remove? */
+ glColor4ub(255, 255, 255, 200);
glutil_draw_lined_arc(0.0, M_PI * 2.0, brush->size, 40);
+ /* Outer Ring: Dark color for contrast on light backgrounds (e.g. gray on white) */
+ glColor3ub(30, 30, 30);
+ glutil_draw_lined_arc(0.0, M_PI * 2.0, brush->size + 1, 40);
+
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
@@ -906,7 +1008,7 @@ static void gpencil_toggle_brush_cursor(bContext *C, bool enable)
static void gpsculpt_brush_header_set(bContext *C, tGP_BrushEditData *gso)
{
const char *brush_name = NULL;
- char str[256] = "";
+ char str[UI_MAX_DRAW_STR] = "";
RNA_enum_name(rna_enum_gpencil_sculpt_brush_items, gso->brush_type, &brush_name);
@@ -1083,7 +1185,7 @@ static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso)
*/
// XXX: should this be allowed when framelock is enabled?
if (gpf->framenum != cfra) {
- gpencil_frame_addcopy(gpl, cfra);
+ BKE_gpencil_frame_addcopy(gpl, cfra);
}
}
}
@@ -1095,7 +1197,9 @@ static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso)
/* Apply ----------------------------------------------- */
/* Apply brush operation to points in this stroke */
-static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, bGPDstroke *gps, GP_BrushApplyCb apply)
+static bool gpsculpt_brush_do_stroke(
+ tGP_BrushEditData *gso, bGPDstroke *gps, bool parented,
+ float diff_mat[4][4], GP_BrushApplyCb apply)
{
GP_SpaceConversion *gsc = &gso->gsc;
rcti *rect = &gso->brush_rect;
@@ -1107,9 +1211,16 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, bGPDstroke *gps, GP
int i;
bool include_last = false;
bool changed = false;
-
+
if (gps->totpoints == 1) {
- gp_point_to_xy(gsc, gps, gps->points, &pc1[0], &pc1[1]);
+ if (!parented) {
+ gp_point_to_xy(gsc, gps, gps->points, &pc1[0], &pc1[1]);
+ }
+ else {
+ bGPDspoint pt_temp;
+ gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
+ gp_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
+ }
/* do boundbox check first */
if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
@@ -1136,10 +1247,20 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, bGPDstroke *gps, GP
continue;
}
}
-
- gp_point_to_xy(gsc, gps, pt1, &pc1[0], &pc1[1]);
- gp_point_to_xy(gsc, gps, pt2, &pc2[0], &pc2[1]);
-
+ if (!parented) {
+ gp_point_to_xy(gsc, gps, pt1, &pc1[0], &pc1[1]);
+ gp_point_to_xy(gsc, gps, pt2, &pc2[0], &pc2[1]);
+ }
+ else {
+ bGPDspoint npt;
+ gp_point_to_parent_space(pt1, diff_mat, &npt);
+ gp_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]);
+
+ gp_point_to_parent_space(pt2, diff_mat, &npt);
+ gp_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]);
+ }
+
+
/* Check that point segment of the boundbox of the selection stroke */
if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1])))
@@ -1224,76 +1345,107 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso)
/* Find visible strokes, and perform operations on those if hit */
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ float diff_mat[4][4];
+ bool parented = false;
+
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
{
- switch (gso->brush_type) {
- case GP_EDITBRUSH_TYPE_SMOOTH: /* Smooth strokes */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, gp_brush_smooth_apply);
- break;
- }
-
- case GP_EDITBRUSH_TYPE_THICKNESS: /* Adjust stroke thickness */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, gp_brush_thickness_apply);
- break;
+ bGPDframe *gpf = gpl->actframe;
+ if (gpf == NULL)
+ continue;
+
+ /* calculate difference matrix if parent object */
+ if (gpl->parent != NULL) {
+ ED_gpencil_parent_location(gpl, diff_mat);
+ parented = true;
+ }
+ else {
+ parented = false;
+ }
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
+ continue;
}
-
- case GP_EDITBRUSH_TYPE_GRAB: /* Grab points */
- {
- if (gso->first) {
- /* First time this brush stroke is being applied:
- * 1) Prepare data buffers (init/clear) for this stroke
- * 2) Use the points now under the cursor
- */
- gp_brush_grab_stroke_init(gso, gps);
- changed |= gpsculpt_brush_do_stroke(gso, gps, gp_brush_grab_store_points);
+
+ switch (gso->brush_type) {
+ case GP_EDITBRUSH_TYPE_SMOOTH: /* Smooth strokes */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_smooth_apply);
+ break;
}
- else {
- /* Apply effect to the stored points */
- gp_brush_grab_apply_cached(gso, gps);
- changed |= true;
+
+ case GP_EDITBRUSH_TYPE_THICKNESS: /* Adjust stroke thickness */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_thickness_apply);
+ break;
}
- break;
- }
-
- case GP_EDITBRUSH_TYPE_PUSH: /* Push points */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, gp_brush_push_apply);
- break;
- }
-
- case GP_EDITBRUSH_TYPE_PINCH: /* Pinch points */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, gp_brush_pinch_apply);
- break;
- }
-
- case GP_EDITBRUSH_TYPE_TWIST: /* Twist points around midpoint */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, gp_brush_twist_apply);
- break;
+
+ case GP_EDITBRUSH_TYPE_STRENGTH: /* Adjust stroke color strength */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_strength_apply);
+ break;
+ }
+
+ case GP_EDITBRUSH_TYPE_GRAB: /* Grab points */
+ {
+ if (gso->first) {
+ /* First time this brush stroke is being applied:
+ * 1) Prepare data buffers (init/clear) for this stroke
+ * 2) Use the points now under the cursor
+ */
+ gp_brush_grab_stroke_init(gso, gps);
+ changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_grab_store_points);
+ }
+ else {
+ /* Apply effect to the stored points */
+ gp_brush_grab_apply_cached(gso, gps, parented, diff_mat);
+ changed |= true;
+ }
+ break;
+ }
+
+ case GP_EDITBRUSH_TYPE_PUSH: /* Push points */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_push_apply);
+ break;
+ }
+
+ case GP_EDITBRUSH_TYPE_PINCH: /* Pinch points */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_pinch_apply);
+ break;
+ }
+
+ case GP_EDITBRUSH_TYPE_TWIST: /* Twist points around midpoint */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_twist_apply);
+ break;
+ }
+
+ case GP_EDITBRUSH_TYPE_RANDOMIZE: /* Apply jitter */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_randomize_apply);
+ break;
+ }
+
+ default:
+ printf("ERROR: Unknown type of GPencil Sculpt brush - %u\n", gso->brush_type);
+ break;
}
-
- case GP_EDITBRUSH_TYPE_RANDOMIZE: /* Apply jitter */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, gp_brush_randomize_apply);
- break;
+ /* Triangulation must be calculated if changed */
+ if (changed) {
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ gps->tot_triangles = 0;
}
-
- default:
- printf("ERROR: Unknown type of GPencil Sculpt brush - %u\n", gso->brush_type);
- break;
- }
-
- /* Triangulation must be calculated if changed */
- if (changed) {
- gps->flag |= GP_STROKE_RECALC_CACHES;
- gps->tot_triangles = 0;
}
}
CTX_DATA_END;
-
+
return changed;
}
@@ -1437,6 +1589,11 @@ static int gpsculpt_brush_invoke(bContext *C, wmOperator *op, const wmEvent *eve
needs_timer = true;
break;
+ case GP_EDITBRUSH_TYPE_STRENGTH:
+ brush_rate = 0.01f; // XXX: hardcoded
+ needs_timer = true;
+ break;
+
case GP_EDITBRUSH_TYPE_PINCH:
brush_rate = 0.001f; // XXX: hardcoded
needs_timer = true;
diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c
index c47985ebc1b..c502ed1aa83 100644
--- a/source/blender/editors/gpencil/gpencil_convert.c
+++ b/source/blender/editors/gpencil/gpencil_convert.c
@@ -142,12 +142,31 @@ static EnumPropertyItem *rna_GPConvert_mode_items(bContext *UNUSED(C), PointerRN
/* convert the coordinates from the given stroke point into 3d-coordinates
* - assumes that the active space is the 3D-View
*/
-static void gp_strokepoint_convertcoords(bContext *C, bGPDstroke *gps, bGPDspoint *pt, float p3d[3], rctf *subrect)
+static void gp_strokepoint_convertcoords(
+ bContext *C, bGPDlayer *gpl, bGPDstroke *gps, bGPDspoint *source_pt,
+ float p3d[3], const rctf *subrect)
{
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
ARegion *ar = CTX_wm_region(C);
-
+ bGPDspoint mypt, *pt;
+
+ float diff_mat[4][4];
+ pt = &mypt;
+
+ /* calculate difference matrix if parent object */
+ if (gpl->parent == NULL) {
+ copy_v3_v3(&pt->x, &source_pt->x);
+ }
+ else {
+ /* apply parent transform */
+ float fpt[3];
+ ED_gpencil_parent_location(gpl, diff_mat);
+ mul_v3_m4v3(fpt, diff_mat, &source_pt->x);
+ copy_v3_v3(&pt->x, fpt);
+ }
+
+
if (gps->flag & GP_STROKE_3DSPACE) {
/* directly use 3d-coordinates */
copy_v3_v3(p3d, &pt->x);
@@ -628,7 +647,7 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv
bp = &nu->bp[old_nbp - 1];
/* First point */
- gp_strokepoint_convertcoords(C, gps, gps->points, p, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, gps->points, p, subrect);
if (prev_bp) {
interp_v3_v3v3(p1, bp->vec, prev_bp->vec, -GAP_DFAC);
if (do_gtd) {
@@ -649,7 +668,7 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv
/* Second point */
/* Note dt2 is always negative, which marks the gap. */
if (gps->totpoints > 1) {
- gp_strokepoint_convertcoords(C, gps, gps->points + 1, next_p, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, gps->points + 1, next_p, subrect);
interp_v3_v3v3(p2, p, next_p, -GAP_DFAC);
if (do_gtd) {
dt2 = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
@@ -670,9 +689,9 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv
float p[3], next_p[3];
float dt = 0.0f;
- gp_strokepoint_convertcoords(C, gps, gps->points, p, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, gps->points, p, subrect);
if (gps->totpoints > 1) {
- gp_strokepoint_convertcoords(C, gps, gps->points + 1, next_p, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, gps->points + 1, next_p, subrect);
interp_v3_v3v3(p, p, next_p, -GAP_DFAC);
if (do_gtd) {
dt = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
@@ -701,10 +720,10 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv
i++, pt++, bp++)
{
float p[3];
- float width = pt->pressure * gpl->thickness * WIDTH_CORR_FAC;
+ float width = pt->pressure * (gps->thickness + gpl->thickness) * WIDTH_CORR_FAC;
/* get coordinates to add at */
- gp_strokepoint_convertcoords(C, gps, pt, p, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, pt, p, subrect);
gp_stroke_to_path_add_point(gtd, bp, p, (prev_bp) ? prev_bp->vec : p, do_gtd, gps->inittime, pt->time,
width, rad_fac, minmax_weights);
@@ -816,12 +835,12 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu
/* get initial coordinates */
pt = gps->points;
if (tot) {
- gp_strokepoint_convertcoords(C, gps, pt, (stitch) ? p3d_prev : p3d_cur, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, pt, (stitch) ? p3d_prev : p3d_cur, subrect);
if (tot > 1) {
- gp_strokepoint_convertcoords(C, gps, pt + 1, (stitch) ? p3d_cur : p3d_next, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, pt + 1, (stitch) ? p3d_cur : p3d_next, subrect);
}
if (stitch && tot > 2) {
- gp_strokepoint_convertcoords(C, gps, pt + 2, p3d_next, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, pt + 2, p3d_next, subrect);
}
}
@@ -940,7 +959,7 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu
/* add points */
for (i = stitch ? 1 : 0, bezt = &nu->bezt[old_nbezt]; i < tot; i++, pt++, bezt++) {
- float width = pt->pressure * gpl->thickness * WIDTH_CORR_FAC;
+ float width = pt->pressure * (gps->thickness + gpl->thickness) * WIDTH_CORR_FAC;
if (i || old_nbezt) {
interp_v3_v3v3(h1, p3d_cur, p3d_prev, BEZT_HANDLE_FAC);
@@ -964,7 +983,7 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu
copy_v3_v3(p3d_cur, p3d_next);
if (i + 2 < tot) {
- gp_strokepoint_convertcoords(C, gps, pt + 2, p3d_next, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, pt + 2, p3d_next, subrect);
}
prev_bezt = bezt;
@@ -1104,7 +1123,7 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG
struct Main *bmain = CTX_data_main(C);
View3D *v3d = CTX_wm_view3d(C); /* may be NULL */
Scene *scene = CTX_data_scene(C);
- bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, 0);
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0);
bGPDstroke *gps, *prev_gps = NULL;
Object *ob;
Curve *cu;
@@ -1216,7 +1235,7 @@ static bool gp_convert_check_has_valid_timing(bContext *C, bGPDlayer *gpl, wmOpe
int i;
bool valid = true;
- if (!gpl || !(gpf = gpencil_layer_getframe(gpl, CFRA, 0)) || !(gps = gpf->strokes.first))
+ if (!gpl || !(gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0)) || !(gps = gpf->strokes.first))
return false;
do {
@@ -1273,8 +1292,8 @@ static int gp_convert_poll(bContext *C)
* and if we are not in edit mode!
*/
return ((sa && sa->spacetype == SPACE_VIEW3D) &&
- (gpl = gpencil_layer_getactive(gpd)) &&
- (gpf = gpencil_layer_getframe(gpl, CFRA, 0)) &&
+ (gpl = BKE_gpencil_layer_getactive(gpd)) &&
+ (gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0)) &&
(gpf->strokes.first) &&
(scene->obedit == NULL));
}
@@ -1283,7 +1302,7 @@ static int gp_convert_layer_exec(bContext *C, wmOperator *op)
{
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "use_timing_data");
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
Scene *scene = CTX_data_scene(C);
const int mode = RNA_enum_get(op->ptr, "type");
const bool norm_weights = RNA_boolean_get(op->ptr, "use_normalize_weights");
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index 746497f0ff5..7dcbe2cc24c 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -18,7 +18,7 @@
* The Original Code is Copyright (C) 2008, Blender Foundation, Joshua Leung
* This is a new part of Blender
*
- * Contributor(s): Joshua Leung
+ * Contributor(s): Joshua Leung, Antonio Vazquez
*
* ***** END GPL LICENSE BLOCK *****
*
@@ -40,6 +40,8 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+#include "BLI_math.h"
#include "BLT_translation.h"
@@ -57,6 +59,7 @@
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
+#include "BKE_colortools.h"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -72,7 +75,6 @@
#include "gpencil_intern.h"
-
/* ************************************************ */
/* Datablock Operators */
@@ -92,7 +94,7 @@ static int gp_data_add_exec(bContext *C, wmOperator *op)
bGPdata *gpd = (*gpd_ptr);
id_us_min(&gpd->id);
- *gpd_ptr = gpencil_data_addnew(DATA_("GPencil"));
+ *gpd_ptr = BKE_gpencil_data_addnew(DATA_("GPencil"));
}
/* notifiers */
@@ -106,7 +108,7 @@ void GPENCIL_OT_data_add(wmOperatorType *ot)
/* identifiers */
ot->name = "Grease Pencil Add New";
ot->idname = "GPENCIL_OT_data_add";
- ot->description = "Add new Grease Pencil datablock";
+ ot->description = "Add new Grease Pencil data-block";
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* callbacks */
@@ -154,7 +156,7 @@ void GPENCIL_OT_data_unlink(wmOperatorType *ot)
/* identifiers */
ot->name = "Grease Pencil Unlink";
ot->idname = "GPENCIL_OT_data_unlink";
- ot->description = "Unlink active Grease Pencil datablock";
+ ot->description = "Unlink active Grease Pencil data-block";
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* callbacks */
@@ -179,10 +181,10 @@ static int gp_layer_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
if (*gpd_ptr == NULL)
- *gpd_ptr = gpencil_data_addnew(DATA_("GPencil"));
+ *gpd_ptr = BKE_gpencil_data_addnew(DATA_("GPencil"));
/* add new layer now */
- gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), true);
+ BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), true);
/* notifiers */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -195,7 +197,7 @@ void GPENCIL_OT_layer_add(wmOperatorType *ot)
/* identifiers */
ot->name = "Add New Layer";
ot->idname = "GPENCIL_OT_layer_add";
- ot->description = "Add new Grease Pencil layer for the active Grease Pencil datablock";
+ ot->description = "Add new Grease Pencil layer for the active Grease Pencil data-block";
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -209,7 +211,7 @@ void GPENCIL_OT_layer_add(wmOperatorType *ot)
static int gp_layer_remove_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
/* sanity checks */
if (ELEM(NULL, gpd, gpl))
@@ -225,12 +227,12 @@ static int gp_layer_remove_exec(bContext *C, wmOperator *op)
* - if this is the only layer, this naturally becomes NULL
*/
if (gpl->prev)
- gpencil_layer_setactive(gpd, gpl->prev);
+ BKE_gpencil_layer_setactive(gpd, gpl->prev);
else
- gpencil_layer_setactive(gpd, gpl->next);
+ BKE_gpencil_layer_setactive(gpd, gpl->next);
/* delete the layer now... */
- gpencil_layer_delete(gpd, gpl);
+ BKE_gpencil_layer_delete(gpd, gpl);
/* notifiers */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -262,7 +264,7 @@ enum {
static int gp_layer_move_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
int direction = RNA_enum_get(op->ptr, "type");
@@ -270,21 +272,11 @@ static int gp_layer_move_exec(bContext *C, wmOperator *op)
if (ELEM(NULL, gpd, gpl))
return OPERATOR_CANCELLED;
- /* up or down? */
- if (direction == GP_LAYER_MOVE_UP) {
- /* up */
- BLI_remlink(&gpd->layers, gpl);
- BLI_insertlinkbefore(&gpd->layers, gpl->prev, gpl);
- }
- else {
- /* down */
- BLI_remlink(&gpd->layers, gpl);
- BLI_insertlinkafter(&gpd->layers, gpl->next, gpl);
+ BLI_assert(ELEM(direction, -1, 0, 1)); /* we use value below */
+ if (BLI_listbase_link_move(&gpd->layers, gpl, direction)) {
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
return OPERATOR_FINISHED;
}
@@ -316,7 +308,7 @@ void GPENCIL_OT_layer_move(wmOperatorType *ot)
static int gp_layer_copy_exec(bContext *C, wmOperator *UNUSED(op))
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
bGPDlayer *new_layer;
/* sanity checks */
@@ -324,12 +316,12 @@ static int gp_layer_copy_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
/* make copy of layer, and add it immediately after the existing layer */
- new_layer = gpencil_layer_duplicate(gpl);
+ new_layer = BKE_gpencil_layer_duplicate(gpl);
BLI_insertlinkafter(&gpd->layers, gpl, new_layer);
/* ensure new layer has a unique name, and is now the active layer */
BLI_uniquename(&gpd->layers, new_layer, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(new_layer->info));
- gpencil_layer_setactive(gpd, new_layer);
+ BKE_gpencil_layer_setactive(gpd, new_layer);
/* notifiers */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -357,7 +349,7 @@ void GPENCIL_OT_layer_duplicate(wmOperatorType *ot)
static int gp_hide_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *layer = gpencil_layer_getactive(gpd);
+ bGPDlayer *layer = BKE_gpencil_layer_getactive(gpd);
bool unselected = RNA_boolean_get(op->ptr, "unselected");
/* sanity checks */
@@ -525,7 +517,7 @@ void GPENCIL_OT_unlock_all(wmOperatorType *ot)
static int gp_isolate_layer_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *layer = gpencil_layer_getactive(gpd);
+ bGPDlayer *layer = BKE_gpencil_layer_getactive(gpd);
bGPDlayer *gpl;
int flags = GP_LAYER_LOCKED;
bool isolate = false;
@@ -596,6 +588,61 @@ void GPENCIL_OT_layer_isolate(wmOperatorType *ot)
"In addition to toggling the editability, also affect the visibility");
}
+/* ********************** Merge Layer with the next layer **************************** */
+
+static int gp_merge_layer_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl_current = BKE_gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl_next = gpl_current->next;
+
+ if (ELEM(NULL, gpd, gpl_current, gpl_next)) {
+ BKE_report(op->reports, RPT_ERROR, "No layers to merge");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Collect frames of gpl_current in hash table to avoid O(n^2) lookups */
+ GHash *gh_frames_cur = BLI_ghash_int_new_ex(__func__, 64);
+ for (bGPDframe *gpf = gpl_current->frames.first; gpf; gpf = gpf->next) {
+ BLI_ghash_insert(gh_frames_cur, SET_INT_IN_POINTER(gpf->framenum), gpf);
+ }
+
+ /* read all frames from next layer */
+ for (bGPDframe *gpf = gpl_next->frames.first; gpf; gpf = gpf->next) {
+ /* try to find frame in active layer */
+ bGPDframe *frame = BLI_ghash_lookup(gh_frames_cur, SET_INT_IN_POINTER(gpf->framenum));
+ if (!frame) {
+ /* nothing found, create new */
+ frame = BKE_gpencil_frame_addnew(gpl_current, gpf->framenum);
+ }
+ /* add to tail all strokes */
+ BLI_movelisttolist(&frame->strokes, &gpf->strokes);
+ }
+ /* Now delete next layer */
+ BKE_gpencil_layer_delete(gpd, gpl_next);
+ BLI_ghash_free(gh_frames_cur, NULL, NULL);
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_layer_merge(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Merge Down";
+ ot->idname = "GPENCIL_OT_layer_merge";
+ ot->description = "Merge the current layer with the layer below";
+
+ /* callbacks */
+ ot->exec = gp_merge_layer_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/* ********************** Change Layer ***************************** */
static int gp_layer_change_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt))
@@ -621,7 +668,7 @@ static int gp_layer_change_exec(bContext *C, wmOperator *op)
/* Get layer or create new one */
if (layer_num == -1) {
/* Create layer */
- gpl = gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
+ gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
}
else {
/* Try to get layer */
@@ -634,7 +681,7 @@ static int gp_layer_change_exec(bContext *C, wmOperator *op)
}
/* Set active layer */
- gpencil_layer_setactive(gpd, gpl);
+ BKE_gpencil_layer_setactive(gpd, gpl);
/* updates */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -663,3 +710,1314 @@ void GPENCIL_OT_layer_change(wmOperatorType *ot)
}
/* ************************************************ */
+
+/* ******************* Arrange Stroke Up/Down in drawing order ************************** */
+
+enum {
+ GP_STROKE_MOVE_UP = -1,
+ GP_STROKE_MOVE_DOWN = 1,
+ GP_STROKE_MOVE_TOP = 2,
+ GP_STROKE_MOVE_BOTTOM = 3
+};
+
+static int gp_stroke_arrange_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPDstroke *gps;
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, gpl, gpl->actframe)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ bGPDframe *gpf = gpl->actframe;
+ /* temp listbase to store selected strokes */
+ ListBase selected = {NULL};
+ const int direction = RNA_enum_get(op->ptr, "direction");
+
+ /* verify if any selected stroke is in the extreme of the stack and select to move */
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* only if selected */
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
+ continue;
+ }
+ /* some stroke is already at front*/
+ if ((direction == GP_STROKE_MOVE_TOP) || (direction == GP_STROKE_MOVE_UP)) {
+ if (gps == gpf->strokes.last) {
+ return OPERATOR_CANCELLED;
+ }
+ }
+ /* some stroke is already at botom */
+ if ((direction == GP_STROKE_MOVE_BOTTOM) || (direction == GP_STROKE_MOVE_DOWN)) {
+ if (gps == gpf->strokes.first) {
+ return OPERATOR_CANCELLED;
+ }
+ }
+ /* add to list */
+ BLI_addtail(&selected, BLI_genericNodeN(gps));
+ }
+ }
+
+ /* Now do the movement of the stroke */
+ switch (direction) {
+ /* Bring to Front */
+ case GP_STROKE_MOVE_TOP:
+ for (LinkData *link = selected.first; link; link = link->next) {
+ gps = link->data;
+ BLI_remlink(&gpf->strokes, gps);
+ BLI_addtail(&gpf->strokes, gps);
+ }
+ break;
+ /* Bring Forward */
+ case GP_STROKE_MOVE_UP:
+ for (LinkData *link = selected.last; link; link = link->prev) {
+ gps = link->data;
+ BLI_listbase_link_move(&gpf->strokes, gps, 1);
+ }
+ break;
+ /* Send Backward */
+ case GP_STROKE_MOVE_DOWN:
+ for (LinkData *link = selected.first; link; link = link->next) {
+ gps = link->data;
+ BLI_listbase_link_move(&gpf->strokes, gps, -1);
+ }
+ break;
+ /* Send to Back */
+ case GP_STROKE_MOVE_BOTTOM:
+ for (LinkData *link = selected.last; link; link = link->prev) {
+ gps = link->data;
+ BLI_remlink(&gpf->strokes, gps);
+ BLI_addhead(&gpf->strokes, gps);
+ }
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+ BLI_freelistN(&selected);
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_arrange(wmOperatorType *ot)
+{
+ static EnumPropertyItem slot_move[] = {
+ {GP_STROKE_MOVE_UP, "UP", 0, "Bring Forward", ""},
+ {GP_STROKE_MOVE_DOWN, "DOWN", 0, "Send Backward", ""},
+ {GP_STROKE_MOVE_TOP, "TOP", 0, "Bring to Front", ""},
+ {GP_STROKE_MOVE_BOTTOM, "BOTTOM", 0, "Send to Back", ""},
+ {0, NULL, 0, NULL, NULL }
+ };
+
+ /* identifiers */
+ ot->name = "Arrange Stroke";
+ ot->idname = "GPENCIL_OT_stroke_arrange";
+ ot->description = "Arrange selected strokes up/down in the drawing order of the active layer";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_arrange_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna, "direction", slot_move, GP_STROKE_MOVE_UP, "Direction", "");
+}
+/* ******************* Move Stroke to new color ************************** */
+
+static int gp_stroke_change_color_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDpalette *palette;
+ bGPDpalettecolor *color;
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ palette = BKE_gpencil_palette_getactive(gpd);
+ color = BKE_gpencil_palettecolor_getactive(palette);
+ if (ELEM(NULL, palette, color)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* loop all strokes */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* only editable and visible layers are considered */
+ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
+ /* only if selected */
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(gpl, gps) == false)
+ continue;
+
+ /* asign new color (only if different) */
+ if ((STREQ(gps->colorname, color->info) == false) || (gps->palcolor != color)) {
+ BLI_strncpy(gps->colorname, color->info, sizeof(gps->colorname));
+ gps->palcolor = color;
+ }
+ }
+ }
+ }
+ }
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_change_color(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Change Stroke Color";
+ ot->idname = "GPENCIL_OT_stroke_change_color";
+ ot->description = "Move selected strokes to active color";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_change_color_exec;
+ ot->poll = gp_active_layer_poll;
+}
+
+/* ******************* Lock color of non selected Strokes colors ************************** */
+
+static int gp_stroke_lock_color_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDpalette *palette;
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
+
+ palette = BKE_gpencil_palette_getactive(gpd);
+ if (ELEM(NULL, palette))
+ return OPERATOR_CANCELLED;
+
+ /* first lock all colors */
+ for (bGPDpalettecolor *palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+ palcolor->flag |= PC_COLOR_LOCKED;
+ }
+
+ /* loop all selected strokes and unlock any color */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* only editable and visible layers are considered */
+ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
+ /* only if selected */
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* unlock color */
+ if (gps->palcolor != NULL) {
+ gps->palcolor->flag &= ~PC_COLOR_LOCKED;
+ }
+ }
+ }
+ }
+ }
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_lock_color(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Lock Unused Colors";
+ ot->idname = "GPENCIL_OT_stroke_lock_color";
+ ot->description = "Lock any color not used in any selected stroke";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_lock_color_exec;
+ ot->poll = gp_active_layer_poll;
+}
+
+/* ************************************************ */
+/* Drawing Brushes Operators */
+
+/* ******************* Add New Brush ************************ */
+
+/* add new brush - wrapper around API */
+static int gp_brush_add_exec(bContext *C, wmOperator *op)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ /* if there's no existing container */
+ if (ts == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Nowhere for brush data to go");
+ return OPERATOR_CANCELLED;
+ }
+ /* add new brush now */
+ BKE_gpencil_brush_addnew(ts, DATA_("GP_Brush"), true);
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_brush_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Brush";
+ ot->idname = "GPENCIL_OT_brush_add";
+ ot->description = "Add new Grease Pencil drawing brush for the active Grease Pencil data-block";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_brush_add_exec;
+ ot->poll = gp_add_poll;
+}
+
+/* ******************* Remove Active Brush ************************* */
+
+static int gp_brush_remove_exec(bContext *C, wmOperator *op)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ bGPDbrush *brush = BKE_gpencil_brush_getactive(ts);
+
+ /* sanity checks */
+ if (ELEM(NULL, ts, brush))
+ return OPERATOR_CANCELLED;
+
+ if (BLI_listbase_count_ex(&ts->gp_brushes, 2) < 2) {
+ BKE_report(op->reports, RPT_ERROR, "Grease Pencil needs a brush, unable to delete the last one");
+ return OPERATOR_CANCELLED;
+ }
+
+
+ /* make the brush before this the new active brush
+ * - use the one after if this is the first
+ * - if this is the only brush, this naturally becomes NULL
+ */
+ if (brush->prev)
+ BKE_gpencil_brush_setactive(ts, brush->prev);
+ else
+ BKE_gpencil_brush_setactive(ts, brush->next);
+
+ /* delete the brush now... */
+ BKE_gpencil_brush_delete(ts, brush);
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_brush_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Brush";
+ ot->idname = "GPENCIL_OT_brush_remove";
+ ot->description = "Remove active Grease Pencil drawing brush";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_brush_remove_exec;
+ ot->poll = gp_active_brush_poll;
+}
+
+/* ********************** Change Brush ***************************** */
+
+static int gp_brush_change_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt))
+{
+ uiPopupMenu *pup;
+ uiLayout *layout;
+
+ /* call the menu, which will call this operator again, hence the canceled */
+ pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
+ uiItemsEnumO(layout, "GPENCIL_OT_brush_change", "brush");
+ UI_popup_menu_end(C, pup);
+
+ return OPERATOR_INTERFACE;
+}
+
+static int gp_brush_change_exec(bContext *C, wmOperator *op)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ bGPDbrush *brush = NULL;
+ int brush_num = RNA_enum_get(op->ptr, "brush");
+
+ /* Get brush or create new one */
+ if (brush_num == -1) {
+ /* Create brush */
+ brush = BKE_gpencil_brush_addnew(ts, DATA_("GP_Brush"), true);
+ }
+ else {
+ /* Try to get brush */
+ brush = BLI_findlink(&ts->gp_brushes, brush_num);
+
+ if (brush == NULL) {
+ BKE_reportf(op->reports, RPT_ERROR, "Cannot change to non-existent brush (index = %d)", brush_num);
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ /* Set active brush */
+ BKE_gpencil_brush_setactive(ts, brush);
+
+ /* updates */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_brush_change(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Change Brush";
+ ot->idname = "GPENCIL_OT_brush_change";
+ ot->description = "Change active Grease Pencil drawing brush";
+
+ /* callbacks */
+ ot->invoke = gp_brush_change_invoke;
+ ot->exec = gp_brush_change_exec;
+ ot->poll = gp_active_brush_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* gp brush to use (dynamic enum) */
+ ot->prop = RNA_def_enum(ot->srna, "brush", DummyRNA_DEFAULT_items, 0, "Grease Pencil Brush", "");
+ RNA_def_enum_funcs(ot->prop, ED_gpencil_brushes_enum_itemf);
+}
+
+/* ******************* Move Brush Up/Down ************************** */
+
+enum {
+ GP_BRUSH_MOVE_UP = -1,
+ GP_BRUSH_MOVE_DOWN = 1
+};
+
+static int gp_brush_move_exec(bContext *C, wmOperator *op)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ bGPDbrush *brush = BKE_gpencil_brush_getactive(ts);
+
+ int direction = RNA_enum_get(op->ptr, "type");
+
+ /* sanity checks */
+ if (ELEM(NULL, ts, brush)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* up or down? */
+ if (direction == GP_BRUSH_MOVE_UP) {
+ /* up */
+ BLI_remlink(&ts->gp_brushes, brush);
+ BLI_insertlinkbefore(&ts->gp_brushes, brush->prev, brush);
+ }
+ else if (direction == GP_BRUSH_MOVE_DOWN) {
+ /* down */
+ BLI_remlink(&ts->gp_brushes, brush);
+ BLI_insertlinkafter(&ts->gp_brushes, brush->next, brush);
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_brush_move(wmOperatorType *ot)
+{
+ static EnumPropertyItem slot_move[] = {
+ {GP_BRUSH_MOVE_UP, "UP", 0, "Up", ""},
+ {GP_BRUSH_MOVE_DOWN, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL }
+ };
+
+ /* identifiers */
+ ot->name = "Move Brush";
+ ot->idname = "GPENCIL_OT_brush_move";
+ ot->description = "Move the active Grease Pencil drawing brush up/down in the list";
+
+ /* api callbacks */
+ ot->exec = gp_brush_move_exec;
+ ot->poll = gp_active_brush_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna, "type", slot_move, GP_BRUSH_MOVE_UP, "Type", "");
+}
+
+/* ******************* Brush create presets ************************** */
+
+static int gp_brush_presets_create_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ BKE_gpencil_brush_init_presets(ts);
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_brush_presets_create(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Create Preset Brushes";
+ ot->idname = "GPENCIL_OT_brush_presets_create";
+ ot->description = "Create a set of predefined Grease Pencil drawing brushes";
+
+ /* api callbacks */
+ ot->exec = gp_brush_presets_create_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+}
+
+/* ***************** Copy Brush ************************ */
+
+static int gp_brush_copy_exec(bContext *C, wmOperator *op)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ /* if there's no existing container */
+ if (ts == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Nowhere for brush data to go");
+ return OPERATOR_CANCELLED;
+ }
+
+ bGPDbrush *brush = BKE_gpencil_brush_getactive(ts);
+ bGPDbrush *newbrush;
+
+ /* sanity checks */
+ if (ELEM(NULL, brush))
+ return OPERATOR_CANCELLED;
+
+ /* create a brush and duplicate data */
+ newbrush = BKE_gpencil_brush_addnew(ts, brush->info, true);
+ newbrush->thickness = brush->thickness;
+ newbrush->draw_smoothfac = brush->draw_smoothfac;
+ newbrush->draw_smoothlvl = brush->draw_smoothlvl;
+ newbrush->sublevel = brush->sublevel;
+ newbrush->flag = brush->flag;
+ newbrush->draw_sensitivity = brush->draw_sensitivity;
+ newbrush->draw_strength = brush->draw_strength;
+ newbrush->draw_jitter = brush->draw_jitter;
+ newbrush->draw_angle = brush->draw_angle;
+ newbrush->draw_angle_factor = brush->draw_angle_factor;
+ newbrush->draw_random_press = brush->draw_random_press;
+ newbrush->draw_random_sub = brush->draw_random_sub;
+
+ /* free automatic curves created by default (replaced by copy) */
+ curvemapping_free(newbrush->cur_sensitivity);
+ curvemapping_free(newbrush->cur_strength);
+ curvemapping_free(newbrush->cur_jitter);
+
+ /* make a copy of curves */
+ newbrush->cur_sensitivity = curvemapping_copy(brush->cur_sensitivity);
+ newbrush->cur_strength = curvemapping_copy(brush->cur_strength);
+ newbrush->cur_jitter = curvemapping_copy(brush->cur_jitter);
+
+ BKE_gpencil_brush_setactive(ts, newbrush);
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_brush_copy(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Copy Brush";
+ ot->idname = "GPENCIL_OT_brush_copy";
+ ot->description = "Copy current Grease Pencil drawing brush";
+
+ /* callbacks */
+ ot->exec = gp_brush_copy_exec;
+ ot->poll = gp_active_brush_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ***************** Select Brush ************************ */
+
+static int gp_brush_select_exec(bContext *C, wmOperator *op)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ /* if there's no existing container */
+ if (ts == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Nowhere to go");
+ return OPERATOR_CANCELLED;
+ }
+
+ const int index = RNA_int_get(op->ptr, "index");
+ bGPDbrush *brush = BLI_findlink(&ts->gp_brushes, index);
+ /* sanity checks */
+ if (ELEM(NULL, brush)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_gpencil_brush_setactive(ts, brush);
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_brush_select(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Brush";
+ ot->idname = "GPENCIL_OT_brush_select";
+ ot->description = "Select a Grease Pencil drawing brush";
+
+ /* callbacks */
+ ot->exec = gp_brush_select_exec;
+ ot->poll = gp_active_brush_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Index of Drawing Brush", 0, INT_MAX);
+}
+
+/* ************************************************ */
+/* Palette Operators */
+
+/* ******************* Add New Palette ************************ */
+
+/* add new palette - wrapper around API */
+static int gp_palette_add_exec(bContext *C, wmOperator *op)
+{
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
+
+ /* if there's no existing Grease-Pencil data there, add some */
+ if (gpd_ptr == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
+ return OPERATOR_CANCELLED;
+ }
+ if (*gpd_ptr == NULL)
+ *gpd_ptr = BKE_gpencil_data_addnew(DATA_("GPencil"));
+
+ /* add new palette now */
+ BKE_gpencil_palette_addnew(*gpd_ptr, DATA_("GP_Palette"), true);
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palette_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Palette";
+ ot->idname = "GPENCIL_OT_palette_add";
+ ot->description = "Add new Grease Pencil palette for the active Grease Pencil data-block";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_palette_add_exec;
+ ot->poll = gp_add_poll;
+}
+
+/* ******************* Remove Active Palette ************************* */
+
+static int gp_palette_remove_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, palette))
+ return OPERATOR_CANCELLED;
+
+ if (BLI_listbase_count_ex(&gpd->palettes, 2) < 2) {
+ BKE_report(op->reports, RPT_ERROR, "Grease Pencil needs a palette, unable to delete the last one");
+ return OPERATOR_CANCELLED;
+ }
+
+
+ /* make the palette before this the new active palette
+ * - use the one after if this is the first
+ * - if this is the only palette, this naturally becomes NULL
+ */
+ if (palette->prev)
+ BKE_gpencil_palette_setactive(gpd, palette->prev);
+ else
+ BKE_gpencil_palette_setactive(gpd, palette->next);
+
+ /* delete the palette now... */
+ BKE_gpencil_palette_delete(gpd, palette);
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palette_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove palette";
+ ot->idname = "GPENCIL_OT_palette_remove";
+ ot->description = "Remove active Grease Pencil palette";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_palette_remove_exec;
+ ot->poll = gp_active_palette_poll;
+}
+
+/* ********************** Change Palette ***************************** */
+
+static int gp_palette_change_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt))
+{
+ uiPopupMenu *pup;
+ uiLayout *layout;
+
+ /* call the menu, which will call this operator again, hence the canceled */
+ pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
+ uiItemsEnumO(layout, "GPENCIL_OT_palette_change", "palette");
+ UI_popup_menu_end(C, pup);
+
+ return OPERATOR_INTERFACE;
+}
+
+static int gp_palette_change_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ bGPDpalette *palette = NULL;
+ int palette_num = RNA_enum_get(op->ptr, "palette");
+
+ /* Get palette or create new one */
+ if (palette_num == -1) {
+ /* Create palette */
+ palette = BKE_gpencil_palette_addnew(gpd, DATA_("GP_Palette"), true);
+ }
+ else {
+ /* Try to get palette */
+ palette = BLI_findlink(&gpd->palettes, palette_num);
+
+ if (palette == NULL) {
+ BKE_reportf(op->reports, RPT_ERROR, "Cannot change to non-existent palette (index = %d)", palette_num);
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ /* Set active palette */
+ BKE_gpencil_palette_setactive(gpd, palette);
+
+ /* updates */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palette_change(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Change Palette";
+ ot->idname = "GPENCIL_OT_palette_change";
+ ot->description = "Change active Grease Pencil palette";
+
+ /* callbacks */
+ ot->invoke = gp_palette_change_invoke;
+ ot->exec = gp_palette_change_exec;
+ ot->poll = gp_active_palette_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* gp palette to use (dynamic enum) */
+ ot->prop = RNA_def_enum(ot->srna, "palette", DummyRNA_DEFAULT_items, 0, "Grease Pencil Palette", "");
+ RNA_def_enum_funcs(ot->prop, ED_gpencil_palettes_enum_itemf);
+}
+
+/* ******************* Lock and hide any color non used in current layer ************************** */
+
+static int gp_palette_lock_layer_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDpalette *palette;
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
+
+ palette = BKE_gpencil_palette_getactive(gpd);
+ if (ELEM(NULL, palette))
+ return OPERATOR_CANCELLED;
+
+ /* first lock and hide all colors */
+ for (bGPDpalettecolor *palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+ palcolor->flag |= PC_COLOR_LOCKED;
+ palcolor->flag |= PC_COLOR_HIDE;
+ }
+
+ /* loop all selected strokes and unlock any color used in active layer */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* only editable and visible layers are considered */
+ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL) && (gpl->flag & GP_LAYER_ACTIVE)) {
+ for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
+ /* unlock/unhide color if not unlocked before */
+ if (gps->palcolor != NULL) {
+ gps->palcolor->flag &= ~PC_COLOR_LOCKED;
+ gps->palcolor->flag &= ~PC_COLOR_HIDE;
+ }
+ }
+ }
+ }
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palette_lock_layer(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Disable Unused Layer Colors";
+ ot->idname = "GPENCIL_OT_palette_lock_layer";
+ ot->description = "Lock and hide any color not used in any layer";
+
+ /* api callbacks */
+ ot->exec = gp_palette_lock_layer_exec;
+ ot->poll = gp_active_layer_poll;
+}
+
+/* ************************************************ */
+/* Palette Colors Operators */
+
+/* ******************* Add New Palette ************************ */
+
+/* add new palette - wrapper around API */
+static int gp_palettecolor_add_exec(bContext *C, wmOperator *op)
+{
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
+
+ /* if there's no existing Grease-Pencil data there, add some */
+ if (gpd_ptr == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
+ return OPERATOR_CANCELLED;
+ }
+ if (*gpd_ptr == NULL)
+ *gpd_ptr = BKE_gpencil_data_addnew(DATA_("GPencil"));
+
+ /* verify palette */
+ bGPDpalette *palette = BKE_gpencil_palette_getactive(*gpd_ptr);
+ if (palette == NULL)
+ palette = BKE_gpencil_palette_addnew(*gpd_ptr, DATA_("GP_Palette"), true);
+
+ /* add new palette color now */
+ BKE_gpencil_palettecolor_addnew(palette, DATA_("Color"), true);
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palettecolor_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Palette Color";
+ ot->idname = "GPENCIL_OT_palettecolor_add";
+ ot->description = "Add new Grease Pencil palette color for the active Grease Pencil data-block";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_palettecolor_add_exec;
+ ot->poll = gp_add_poll;
+}
+
+/* ******************* Remove Active Palette color ************************* */
+
+static int gp_palettecolor_remove_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
+ bGPDpalettecolor *color = BKE_gpencil_palettecolor_getactive(palette);
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, palette, color))
+ return OPERATOR_CANCELLED;
+
+ /* make the palette color before this the new active color
+ * - use the one after if this is the first
+ * - if this is the only color, this naturally becomes NULL
+ */
+ if (color->prev)
+ BKE_gpencil_palettecolor_setactive(palette, color->prev);
+ else
+ BKE_gpencil_palettecolor_setactive(palette, color->next);
+
+ /* delete the strokes */
+ BKE_gpencil_palettecolor_delete_strokes(gpd, color->info);
+
+ /* delete the palette color now... */
+ BKE_gpencil_palettecolor_delete(palette, color);
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palettecolor_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove palette color";
+ ot->idname = "GPENCIL_OT_palettecolor_remove";
+ ot->description = "Remove active Grease Pencil palette color";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_palettecolor_remove_exec;
+ ot->poll = gp_active_palettecolor_poll;
+}
+
+/* ********************** Isolate palette color **************************** */
+
+static int gp_isolate_palettecolor_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
+ bGPDpalettecolor *active_color = BKE_gpencil_palettecolor_getactive(palette);
+ bGPDpalettecolor *palcolor;
+
+ int flags = PC_COLOR_LOCKED;
+ bool isolate = false;
+
+ if (RNA_boolean_get(op->ptr, "affect_visibility"))
+ flags |= PC_COLOR_HIDE;
+
+ if (ELEM(NULL, gpd, active_color)) {
+ BKE_report(op->reports, RPT_ERROR, "No active color to isolate");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Test whether to isolate or clear all flags */
+ for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+ /* Skip if this is the active one */
+ if (palcolor == active_color)
+ continue;
+
+ /* If the flags aren't set, that means that the color is
+ * not alone, so we have some colors to isolate still
+ */
+ if ((palcolor->flag & flags) == 0) {
+ isolate = true;
+ break;
+ }
+ }
+
+ /* Set/Clear flags as appropriate */
+ if (isolate) {
+ /* Set flags on all "other" colors */
+ for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+ if (palcolor == active_color)
+ continue;
+ else
+ palcolor->flag |= flags;
+ }
+ }
+ else {
+ /* Clear flags - Restore everything else */
+ for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+ palcolor->flag &= ~flags;
+ }
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palettecolor_isolate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Isolate Palette Color";
+ ot->idname = "GPENCIL_OT_palettecolor_isolate";
+ ot->description = "Toggle whether the active color is the only one that is editable and/or visible";
+
+ /* callbacks */
+ ot->exec = gp_isolate_palettecolor_exec;
+ ot->poll = gp_active_palettecolor_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "affect_visibility", false, "Affect Visibility", "In addition to toggling "
+ "the editability, also affect the visibility");
+}
+
+/* *********************** Hide Palette colors ******************************** */
+
+static int gp_palettecolor_hide_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
+ bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette);
+
+ bool unselected = RNA_boolean_get(op->ptr, "unselected");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, palette, palcolor))
+ return OPERATOR_CANCELLED;
+
+ if (unselected) {
+ bGPDpalettecolor *color;
+
+ /* hide unselected */
+ for (color = palette->colors.first; color; color = color->next) {
+ if (color != palcolor) {
+ color->flag |= PC_COLOR_HIDE;
+ }
+ }
+ }
+ else {
+ /* hide selected/active */
+ palcolor->flag |= PC_COLOR_HIDE;
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palettecolor_hide(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Hide Color(s)";
+ ot->idname = "GPENCIL_OT_palettecolor_hide";
+ ot->description = "Hide selected/unselected Grease Pencil colors";
+
+ /* callbacks */
+ ot->exec = gp_palettecolor_hide_exec;
+ ot->poll = gp_active_palettecolor_poll; /* NOTE: we need an active color to play with */
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected colors");
+}
+
+/* ********************** Show All Colors ***************************** */
+
+/* poll callback for showing colors */
+static int gp_palettecolor_reveal_poll(bContext *C)
+{
+ return ED_gpencil_data_get_active(C) != NULL;
+}
+
+static int gp_palettecolor_reveal_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
+ bGPDpalettecolor *palcolor;
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, palette))
+ return OPERATOR_CANCELLED;
+
+ /* make all colors visible */
+ for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+ palcolor->flag &= ~PC_COLOR_HIDE;
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palettecolor_reveal(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Show All Colors";
+ ot->idname = "GPENCIL_OT_palettecolor_reveal";
+ ot->description = "Unhide all hidden Grease Pencil palette colors";
+
+ /* callbacks */
+ ot->exec = gp_palettecolor_reveal_exec;
+ ot->poll = gp_palettecolor_reveal_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ***************** Lock/Unlock All Palette colors ************************ */
+
+static int gp_palettecolor_lock_all_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
+ bGPDpalettecolor *palcolor;
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, palette))
+ return OPERATOR_CANCELLED;
+
+ /* make all layers non-editable */
+ for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+ palcolor->flag |= PC_COLOR_LOCKED;
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palettecolor_lock_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Lock All Colors";
+ ot->idname = "GPENCIL_OT_palettecolor_lock_all";
+ ot->description = "Lock all Grease Pencil colors to prevent them from being accidentally modified";
+
+ /* callbacks */
+ ot->exec = gp_palettecolor_lock_all_exec;
+ ot->poll = gp_palettecolor_reveal_poll; /* XXX: could use dedicated poll later */
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* -------------------------- */
+
+static int gp_palettecolor_unlock_all_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
+ bGPDpalettecolor *palcolor;
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, palette))
+ return OPERATOR_CANCELLED;
+
+ /* make all layers editable again*/
+ for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+ palcolor->flag &= ~PC_COLOR_LOCKED;
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palettecolor_unlock_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Unlock All Colors";
+ ot->idname = "GPENCIL_OT_palettecolor_unlock_all";
+ ot->description = "Unlock all Grease Pencil colors so that they can be edited";
+
+ /* callbacks */
+ ot->exec = gp_palettecolor_unlock_all_exec;
+ ot->poll = gp_palettecolor_reveal_poll; /* XXX: could use dedicated poll later */
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ******************* Move Color Up/Down ************************** */
+
+enum {
+ GP_COLOR_MOVE_UP = -1,
+ GP_COLOR_MOVE_DOWN = 1
+};
+
+static int gp_palettecolor_move_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
+ bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette);
+
+ int direction = RNA_enum_get(op->ptr, "direction");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, palette, palcolor))
+ return OPERATOR_CANCELLED;
+
+ /* up or down? */
+ if (direction == GP_COLOR_MOVE_UP) {
+ /* up */
+ BLI_remlink(&palette->colors, palcolor);
+ BLI_insertlinkbefore(&palette->colors, palcolor->prev, palcolor);
+ }
+ else if (direction == GP_COLOR_MOVE_DOWN) {
+ /* down */
+ BLI_remlink(&palette->colors, palcolor);
+ BLI_insertlinkafter(&palette->colors, palcolor->next, palcolor);
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palettecolor_move(wmOperatorType *ot)
+{
+ static EnumPropertyItem slot_move[] = {
+ {GP_COLOR_MOVE_UP, "UP", 0, "Up", ""},
+ {GP_COLOR_MOVE_DOWN, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Move Palette color";
+ ot->idname = "GPENCIL_OT_palettecolor_move";
+ ot->description = "Move the active Grease Pencil palette color up/down in the list";
+
+ /* api callbacks */
+ ot->exec = gp_palettecolor_move_exec;
+ ot->poll = gp_palettecolor_reveal_poll; /* XXX: could use dedicated poll later */
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna, "direction", slot_move, GP_COLOR_MOVE_UP, "Direction", "");
+}
+
+/* ***************** Select all strokes using Palette color ************************ */
+
+static int gp_palettecolor_select_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
+ bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette);
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, palette, palcolor))
+ return OPERATOR_CANCELLED;
+
+ /* read all strokes and select*/
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* only editable and visible layers are considered */
+ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ /* verify something to do */
+ for (bGPDstroke *gps = gpl->actframe->strokes.first; gps; gps = gps->next) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(gpl, gps) == false)
+ continue;
+
+ /* select */
+ if (strcmp(palcolor->info, gps->colorname) == 0) {
+ bGPDspoint *pt;
+ int i;
+
+ gps->flag |= GP_STROKE_SELECT;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+ }
+ }
+ }
+ }
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palettecolor_select(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Color";
+ ot->idname = "GPENCIL_OT_palettecolor_select";
+ ot->description = "Select all Grease Pencil strokes using current color";
+
+ /* callbacks */
+ ot->exec = gp_palettecolor_select_exec;
+ ot->poll = gp_palettecolor_reveal_poll; /* XXX: could use dedicated poll later */
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ***************** Copy Palette color ************************ */
+
+static int gp_palettecolor_copy_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
+ bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette);
+ bGPDpalettecolor *newcolor;
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, palette, palcolor))
+ return OPERATOR_CANCELLED;
+
+ /* create a new color and duplicate data */
+ newcolor = BKE_gpencil_palettecolor_addnew(palette, palcolor->info, true);
+ copy_v4_v4(newcolor->color, palcolor->color);
+ copy_v4_v4(newcolor->fill, palcolor->fill);
+ newcolor->flag = palcolor->flag;
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palettecolor_copy(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Copy Color";
+ ot->idname = "GPENCIL_OT_palettecolor_copy";
+ ot->description = "Copy current Grease Pencil palette color";
+
+ /* callbacks */
+ ot->exec = gp_palettecolor_copy_exec;
+ ot->poll = gp_active_palettecolor_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index bd1697b9a54..12d837dfb29 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -18,7 +18,7 @@
* The Original Code is Copyright (C) 2008, Blender Foundation, Joshua Leung
* This is a new part of Blender
*
- * Contributor(s): Joshua Leung
+ * Contributor(s): Joshua Leung, Antonio Vazquez
*
* ***** END GPL LICENSE BLOCK *****
*
@@ -72,7 +72,10 @@
#include "ED_gpencil.h"
#include "ED_object.h"
+#include "ED_screen.h"
#include "ED_view3d.h"
+#include "ED_screen.h"
+#include "ED_space_api.h"
#include "gpencil_intern.h"
@@ -125,10 +128,48 @@ static int gp_stroke_edit_poll(bContext *C)
return CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0;
}
+/* ************ Stroke Hide selection Toggle ************** */
+
+static int gpencil_hideselect_toggle_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ if (ts == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* Just toggle alpha... */
+ if (ts->gp_sculpt.alpha > 0.0f) {
+ ts->gp_sculpt.alpha = 0.0f;
+ }
+ else {
+ ts->gp_sculpt.alpha = 1.0f;
+ }
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_selection_opacity_toggle(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Hide Selection";
+ ot->idname = "GPENCIL_OT_selection_opacity_toggle";
+ ot->description = "Hide/Unhide selected points for Grease Pencil strokes setting alpha factor";
+
+ /* callbacks */
+ ot->exec = gpencil_hideselect_toggle_exec;
+ ot->poll = gp_stroke_edit_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
+}
+
/* ************** Duplicate Selected Strokes **************** */
/* Make copies of selected point segments in a selected stroke */
-static void gp_duplicate_points(const bGPDstroke *gps, ListBase *new_strokes)
+static void gp_duplicate_points(const bGPDstroke *gps, ListBase *new_strokes, const char *layername)
{
bGPDspoint *pt;
int i;
@@ -169,6 +210,7 @@ static void gp_duplicate_points(const bGPDstroke *gps, ListBase *new_strokes)
/* make a stupid copy first of the entire stroke (to get the flags too) */
gpsd = MEM_dupallocN(gps);
+ BLI_strncpy(gpsd->tmp_layerinfo, layername, sizeof(gpsd->tmp_layerinfo)); /* saves original layer name */
/* initialize triangle memory - will be calculated on next redraw */
gpsd->triangles = NULL;
@@ -216,8 +258,9 @@ static int gp_duplicate_exec(bContext *C, wmOperator *op)
/* make copies of selected strokes, and deselect these once we're done */
for (gps = gpf->strokes.first; gps; gps = gps->next) {
/* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false)
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
continue;
+ }
if (gps->flag & GP_STROKE_SELECT) {
if (gps->totpoints == 1) {
@@ -226,8 +269,9 @@ static int gp_duplicate_exec(bContext *C, wmOperator *op)
/* make direct copies of the stroke and its points */
gpsd = MEM_dupallocN(gps);
+ BLI_strncpy(gpsd->tmp_layerinfo, gpl->info, sizeof(gpsd->tmp_layerinfo));
gpsd->points = MEM_dupallocN(gps->points);
-
+
/* triangle information - will be calculated on next redraw */
gpsd->flag |= GP_STROKE_RECALC_CACHES;
gpsd->triangles = NULL;
@@ -238,7 +282,7 @@ static int gp_duplicate_exec(bContext *C, wmOperator *op)
}
else {
/* delegate to a helper, as there's too much to fit in here (for copying subsets)... */
- gp_duplicate_points(gps, &new_strokes);
+ gp_duplicate_points(gps, &new_strokes, gpl->info);
}
/* deselect original stroke, or else the originals get moved too
@@ -345,6 +389,7 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
/* make direct copies of the stroke and its points */
gpsd = MEM_dupallocN(gps);
+ BLI_strncpy(gpsd->tmp_layerinfo, gpl->info, sizeof(gpsd->tmp_layerinfo)); /* saves original layer name */
gpsd->points = MEM_dupallocN(gps->points);
/* triangles cache - will be recalculated on next redraw */
@@ -358,7 +403,7 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
}
else {
/* delegate to a helper, as there's too much to fit in here (for copying subsets)... */
- gp_duplicate_points(gps, &gp_strokes_copypastebuf);
+ gp_duplicate_points(gps, &gp_strokes_copypastebuf, gpl->info);
}
}
}
@@ -389,19 +434,28 @@ void GPENCIL_OT_copy(wmOperatorType *ot)
static int gp_strokes_paste_poll(bContext *C)
{
- /* 1) Must have GP layer to paste to...
+ /* 1) Must have GP datablock to paste to
+ * - We don't need to have an active layer though, as that can easily get added
+ * - If the active layer is locked, we can't paste there, but that should prompt a warning instead
* 2) Copy buffer must at least have something (though it may be the wrong sort...)
*/
- return (CTX_data_active_gpencil_layer(C) != NULL) && (!BLI_listbase_is_empty(&gp_strokes_copypastebuf));
+ return (ED_gpencil_data_get_active(C) != NULL) && (!BLI_listbase_is_empty(&gp_strokes_copypastebuf));
}
+typedef enum eGP_PasteMode {
+ GP_COPY_ONLY = -1,
+ GP_COPY_MERGE = 1
+} eGP_PasteMode;
+
static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+ bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); /* only use active for copy merge */
bGPDframe *gpf;
+ eGP_PasteMode type = RNA_enum_get(op->ptr, "type");
+
/* check for various error conditions */
if (gpd == NULL) {
BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
@@ -413,9 +467,9 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
}
else if (gpl == NULL) {
/* no active layer - let's just create one */
- gpl = gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
+ gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
}
- else if (gpencil_layer_is_editable(gpl) == false) {
+ else if ((gpencil_layer_is_editable(gpl) == false) && (type == GP_COPY_MERGE)) {
BKE_report(op->reports, RPT_ERROR, "Can not paste strokes when active layer is hidden or locked");
return OPERATOR_CANCELLED;
}
@@ -458,20 +512,26 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
- /* Ensure we have a frame to draw into
- * NOTE: Since this is an op which creates strokes,
- * we are obliged to add a new frame if one
- * doesn't exist already
- */
- gpf = gpencil_layer_getframe(gpl, CFRA, true);
-
- if (gpf) {
- bGPDstroke *gps;
-
- /* Copy each stroke into the layer */
- for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
- if (ED_gpencil_stroke_can_use(C, gps)) {
+ for (bGPDstroke *gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
+ if (ED_gpencil_stroke_can_use(C, gps)) {
+ /* Need to verify if layer exists */
+ if (type != GP_COPY_MERGE) {
+ gpl = BLI_findstring(&gpd->layers, gps->tmp_layerinfo, offsetof(bGPDlayer, info));
+ if (gpl == NULL) {
+ /* no layer - use active (only if layer deleted before paste) */
+ gpl = CTX_data_active_gpencil_layer(C);
+ }
+ }
+
+ /* Ensure we have a frame to draw into
+ * NOTE: Since this is an op which creates strokes,
+ * we are obliged to add a new frame if one
+ * doesn't exist already
+ */
+ gpf = BKE_gpencil_layer_getframe(gpl, CFRA, true);
+ if (gpf) {
bGPDstroke *new_stroke = MEM_dupallocN(gps);
+ new_stroke->tmp_layerinfo[0] = '\0';
new_stroke->points = MEM_dupallocN(gps->points);
@@ -492,10 +552,16 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_paste(wmOperatorType *ot)
{
+ static EnumPropertyItem copy_type[] = {
+ {GP_COPY_ONLY, "COPY", 0, "Copy", ""},
+ {GP_COPY_MERGE, "MERGE", 0, "Merge", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
/* identifiers */
ot->name = "Paste Strokes";
ot->idname = "GPENCIL_OT_paste";
- ot->description = "Paste previously copied strokes into active layer";
+ ot->description = "Paste previously copied strokes or copy and merge in active layer";
/* callbacks */
ot->exec = gp_strokes_paste_exec;
@@ -503,6 +569,9 @@ void GPENCIL_OT_paste(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", copy_type, 0, "Type", "");
}
/* ******************* Move To Layer ****************************** */
@@ -532,7 +601,7 @@ static int gp_move_to_layer_exec(bContext *C, wmOperator *op)
/* Get layer or create new one */
if (layer_num == -1) {
/* Create layer */
- target_layer = gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
+ target_layer = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
}
else {
/* Try to get layer */
@@ -577,7 +646,7 @@ static int gp_move_to_layer_exec(bContext *C, wmOperator *op)
/* Paste them all in one go */
if (strokes.first) {
Scene *scene = CTX_data_scene(C);
- bGPDframe *gpf = gpencil_layer_getframe(target_layer, CFRA, true);
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(target_layer, CFRA, true);
BLI_movelisttolist(&gpf->strokes, &strokes);
BLI_assert((strokes.first == strokes.last) && (strokes.first == NULL));
@@ -614,7 +683,7 @@ void GPENCIL_OT_move_to_layer(wmOperatorType *ot)
static int gp_actframe_delete_poll(bContext *C)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
/* only if there's an active layer with an active frame */
return (gpl && gpl->actframe);
@@ -625,8 +694,8 @@ static int gp_actframe_delete_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = gpencil_layer_getactive(gpd);
- bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, 0);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0);
/* if there's no existing Grease-Pencil data there, add some */
if (gpd == NULL) {
@@ -639,7 +708,7 @@ static int gp_actframe_delete_exec(bContext *C, wmOperator *op)
}
/* delete it... */
- gpencil_layer_delframe(gpl, gpf);
+ BKE_gpencil_layer_delframe(gpl, gpf);
/* notifiers */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -652,7 +721,7 @@ void GPENCIL_OT_active_frame_delete(wmOperatorType *ot)
/* identifiers */
ot->name = "Delete Active Frame";
ot->idname = "GPENCIL_OT_active_frame_delete";
- ot->description = "Delete the active frame for the active Grease Pencil datablock";
+ ot->description = "Delete the active frame for the active Grease Pencil Layer";
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -661,6 +730,64 @@ void GPENCIL_OT_active_frame_delete(wmOperatorType *ot)
ot->poll = gp_actframe_delete_poll;
}
+/* **************** Delete All Active Frames ****************** */
+
+static int gp_actframe_delete_all_poll(bContext *C)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+
+ /* 1) There must be grease pencil data
+ * 2) Hopefully some of the layers have stuff we can use
+ */
+ return (gpd && gpd->layers.first);
+}
+
+static int gp_actframe_delete_all_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ bool success = false;
+
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ /* try to get the "active" frame - but only if it actually occurs on this frame */
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0);
+
+ if (gpf == NULL)
+ continue;
+
+ /* delete it... */
+ BKE_gpencil_layer_delframe(gpl, gpf);
+
+ /* we successfully modified something */
+ success = true;
+ }
+ CTX_DATA_END;
+
+ /* updates */
+ if (success) {
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "No active frame(s) to delete");
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void GPENCIL_OT_active_frames_delete_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Delete All Active Frames";
+ ot->idname = "GPENCIL_OT_active_frames_delete_all";
+ ot->description = "Delete the active frame(s) of all editable Grease Pencil layers";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_actframe_delete_all_exec;
+ ot->poll = gp_actframe_delete_all_poll;
+}
+
/* ******************* Delete Operator ************************ */
typedef enum eGP_DeleteMode {
@@ -1011,7 +1138,7 @@ void GPENCIL_OT_delete(wmOperatorType *ot)
};
/* identifiers */
- ot->name = "Delete...";
+ ot->name = "Delete";
ot->idname = "GPENCIL_OT_delete";
ot->description = "Delete selected Grease Pencil strokes, vertices, or frames";
@@ -1065,26 +1192,59 @@ static int gp_snap_poll(bContext *C)
static int gp_snap_to_grid(bContext *C, wmOperator *UNUSED(op))
{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
RegionView3D *rv3d = CTX_wm_region_data(C);
- float gridf = rv3d->gridview;
+ const float gridf = rv3d->gridview;
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
- {
- bGPDspoint *pt;
- int i;
-
- // TOOD: if entire stroke is selected, offset entire stroke by same amount?
-
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- /* only if point is selected.. */
- if (pt->flag & GP_SPOINT_SELECT) {
- pt->x = gridf * floorf(0.5f + pt->x / gridf);
- pt->y = gridf * floorf(0.5f + pt->y / gridf);
- pt->z = gridf * floorf(0.5f + pt->z / gridf);
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* only editable and visible layers are considered */
+ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ bGPDframe *gpf = gpl->actframe;
+ float diff_mat[4][4];
+
+ /* calculate difference matrix if parent object */
+ if (gpl->parent != NULL) {
+ ED_gpencil_parent_location(gpl, diff_mat);
+ }
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ bGPDspoint *pt;
+ int i;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(gpl, gps) == false)
+ continue;
+
+ // TODO: if entire stroke is selected, offset entire stroke by same amount?
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ /* only if point is selected */
+ if (pt->flag & GP_SPOINT_SELECT) {
+ if (gpl->parent == NULL) {
+ pt->x = gridf * floorf(0.5f + pt->x / gridf);
+ pt->y = gridf * floorf(0.5f + pt->y / gridf);
+ pt->z = gridf * floorf(0.5f + pt->z / gridf);
+ }
+ else {
+ /* apply parent transformations */
+ float fpt[3];
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+
+ fpt[0] = gridf * floorf(0.5f + fpt[0] / gridf);
+ fpt[1] = gridf * floorf(0.5f + fpt[1] / gridf);
+ fpt[2] = gridf * floorf(0.5f + fpt[2] / gridf);
+
+ /* return data */
+ copy_v3_v3(&pt->x, fpt);
+ gp_apply_parent_point(gpl, pt);
+ }
+ }
+ }
}
}
}
- CTX_DATA_END;
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -1109,43 +1269,66 @@ void GPENCIL_OT_snap_to_grid(wmOperatorType *ot)
static int gp_snap_to_cursor(bContext *C, wmOperator *op)
{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
const bool use_offset = RNA_boolean_get(op->ptr, "use_offset");
const float *cursor_global = ED_view3d_cursor3d_get(scene, v3d);
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
- {
- bGPDspoint *pt;
- int i;
-
- /* only continue if this stroke is selected (editable doesn't guarantee this)... */
- if ((gps->flag & GP_STROKE_SELECT) == 0)
- continue;
-
- if (use_offset) {
- float offset[3];
-
- /* compute offset from first point of stroke to cursor */
- /* TODO: Allow using midpoint instead? */
- sub_v3_v3v3(offset, cursor_global, &gps->points->x);
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* only editable and visible layers are considered */
+ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ bGPDframe *gpf = gpl->actframe;
+ float diff_mat[4][4];
- /* apply offset to all points in the stroke */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- add_v3_v3(&pt->x, offset);
+ /* calculate difference matrix if parent object */
+ if (gpl->parent != NULL) {
+ ED_gpencil_parent_location(gpl, diff_mat);
}
- }
- else {
- /* affect each selected point */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->flag & GP_SPOINT_SELECT) {
- copy_v3_v3(&pt->x, cursor_global);
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ bGPDspoint *pt;
+ int i;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(gpl, gps) == false)
+ continue;
+ /* only continue if this stroke is selected (editable doesn't guarantee this)... */
+ if ((gps->flag & GP_STROKE_SELECT) == 0)
+ continue;
+
+ if (use_offset) {
+ float offset[3];
+
+ /* compute offset from first point of stroke to cursor */
+ /* TODO: Allow using midpoint instead? */
+ sub_v3_v3v3(offset, cursor_global, &gps->points->x);
+
+ /* apply offset to all points in the stroke */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ add_v3_v3(&pt->x, offset);
+ }
+ }
+ else {
+ /* affect each selected point */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ copy_v3_v3(&pt->x, cursor_global);
+ if (gpl->parent != NULL) {
+ gp_apply_parent_point(gpl, pt);
+ }
+ }
+ }
}
}
+
}
}
- CTX_DATA_END;
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -1174,6 +1357,8 @@ void GPENCIL_OT_snap_to_cursor(wmOperatorType *ot)
static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op))
{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
@@ -1185,24 +1370,52 @@ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op))
INIT_MINMAX(min, max);
/* calculate midpoints from selected points */
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
- {
- bGPDspoint *pt;
- int i;
-
- /* only continue if this stroke is selected (editable doesn't guarantee this)... */
- if ((gps->flag & GP_STROKE_SELECT) == 0)
- continue;
-
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->flag & GP_SPOINT_SELECT) {
- add_v3_v3(centroid, &pt->x);
- minmax_v3v3_v3(min, max, &pt->x);
- count++;
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* only editable and visible layers are considered */
+ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ bGPDframe *gpf = gpl->actframe;
+ float diff_mat[4][4];
+
+ /* calculate difference matrix if parent object */
+ if (gpl->parent != NULL) {
+ ED_gpencil_parent_location(gpl, diff_mat);
+ }
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ bGPDspoint *pt;
+ int i;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(gpl, gps) == false)
+ continue;
+ /* only continue if this stroke is selected (editable doesn't guarantee this)... */
+ if ((gps->flag & GP_STROKE_SELECT) == 0)
+ continue;
+
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ if (gpl->parent == NULL) {
+ add_v3_v3(centroid, &pt->x);
+ minmax_v3v3_v3(min, max, &pt->x);
+ }
+ else {
+ /* apply parent transformations */
+ float fpt[3];
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+
+ add_v3_v3(centroid, fpt);
+ minmax_v3v3_v3(min, max, fpt);
+ }
+ count++;
+ }
+ }
+
}
}
}
- CTX_DATA_END;
if (v3d->around == V3D_AROUND_CENTER_MEAN && count) {
mul_v3_fl(centroid, 1.0f / (float)count);
@@ -1232,5 +1445,1322 @@ void GPENCIL_OT_snap_cursor_to_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/* ******************* Apply layer thickness change to strokes ************************** */
-/* ************************************************ */
+static int gp_stroke_apply_thickness_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, gpl, gpl->frames.first))
+ return OPERATOR_CANCELLED;
+
+ /* loop all strokes */
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* Apply thickness */
+ gps->thickness = gps->thickness + gpl->thickness;
+ }
+ }
+ /* clear value */
+ gpl->thickness = 0.0f;
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_apply_thickness(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Apply Stroke Thickness";
+ ot->idname = "GPENCIL_OT_stroke_apply_thickness";
+ ot->description = "Apply the thickness change of the layer to its strokes";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_apply_thickness_exec;
+ ot->poll = gp_active_layer_poll;
+}
+
+/* ******************* Close Strokes ************************** */
+
+enum {
+ GP_STROKE_CYCLIC_CLOSE = 1,
+ GP_STROKE_CYCLIC_OPEN = 2,
+ GP_STROKE_CYCLIC_TOGGLE = 3
+};
+
+static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ const int type = RNA_enum_get(op->ptr, "type");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
+
+ /* loop all selected strokes */
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ if (gpl->actframe == NULL)
+ continue;
+
+ for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
+ bGPDpalettecolor *palcolor = gps->palcolor;
+
+ /* skip strokes that are not selected or invalid for current view */
+ if (((gps->flag & GP_STROKE_SELECT) == 0) || ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+ /* skip hidden or locked colors */
+ if (!palcolor || (palcolor->flag & PC_COLOR_HIDE) || (palcolor->flag & PC_COLOR_LOCKED))
+ continue;
+
+ switch (type) {
+ case GP_STROKE_CYCLIC_CLOSE:
+ /* Close all (enable) */
+ gps->flag |= GP_STROKE_CYCLIC;
+ break;
+ case GP_STROKE_CYCLIC_OPEN:
+ /* Open all (disable) */
+ gps->flag &= ~GP_STROKE_CYCLIC;
+ break;
+ case GP_STROKE_CYCLIC_TOGGLE:
+ /* Just toggle flag... */
+ gps->flag ^= GP_STROKE_CYCLIC;
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+/**
+ * Similar to #CURVE_OT_cyclic_toggle or #MASK_OT_cyclic_toggle, but with
+ * option to force opened/closed strokes instead of just toggle behavior.
+ */
+void GPENCIL_OT_stroke_cyclical_set(wmOperatorType *ot)
+{
+ static EnumPropertyItem cyclic_type[] = {
+ {GP_STROKE_CYCLIC_CLOSE, "CLOSE", 0, "Close all", ""},
+ {GP_STROKE_CYCLIC_OPEN, "OPEN", 0, "Open all", ""},
+ {GP_STROKE_CYCLIC_TOGGLE, "TOGGLE", 0, "Toggle", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Set Cyclical State";
+ ot->idname = "GPENCIL_OT_stroke_cyclical_set";
+ ot->description = "Close or open the selected stroke adding an edge from last to first point";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_cyclical_set_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", cyclic_type, GP_STROKE_CYCLIC_TOGGLE, "Type", "");
+}
+
+/* ******************* Stroke join ************************** */
+
+/* Helper: flip stroke */
+static void gpencil_flip_stroke(bGPDstroke *gps)
+{
+ int end = gps->totpoints - 1;
+
+ for (int i = 0; i < gps->totpoints / 2; i++) {
+ bGPDspoint *point, *point2;
+ bGPDspoint pt;
+
+ /* save first point */
+ point = &gps->points[i];
+ pt.x = point->x;
+ pt.y = point->y;
+ pt.z = point->z;
+ pt.flag = point->flag;
+ pt.pressure = point->pressure;
+ pt.strength = point->strength;
+ pt.time = point->time;
+
+ /* replace first point with last point */
+ point2 = &gps->points[end];
+ point->x = point2->x;
+ point->y = point2->y;
+ point->z = point2->z;
+ point->flag = point2->flag;
+ point->pressure = point2->pressure;
+ point->strength = point2->strength;
+ point->time = point2->time;
+
+ /* replace last point with first saved before */
+ point = &gps->points[end];
+ point->x = pt.x;
+ point->y = pt.y;
+ point->z = pt.z;
+ point->flag = pt.flag;
+ point->pressure = pt.pressure;
+ point->strength = pt.strength;
+ point->time = pt.time;
+
+ end--;
+ }
+}
+
+/* Helper: copy point between strokes */
+static void gpencil_stroke_copy_point(bGPDstroke *gps, bGPDspoint *point, float delta[3],
+ float pressure, float strength, float deltatime)
+{
+ bGPDspoint *newpoint;
+
+ gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1));
+ gps->totpoints++;
+
+ newpoint = &gps->points[gps->totpoints - 1];
+ newpoint->x = point->x * delta[0];
+ newpoint->y = point->y * delta[1];
+ newpoint->z = point->z * delta[2];
+ newpoint->flag = point->flag;
+ newpoint->pressure = pressure;
+ newpoint->strength = strength;
+ newpoint->time = point->time + deltatime;
+}
+
+/* Helper: join two strokes using the shortest distance (reorder stroke if necessary ) */
+static void gpencil_stroke_join_strokes(bGPDstroke *gps_a, bGPDstroke *gps_b, const bool leave_gaps)
+{
+ bGPDspoint point;
+ bGPDspoint *pt;
+ int i;
+ float delta[3] = {1.0f, 1.0f, 1.0f};
+ float deltatime = 0.0f;
+
+ /* sanity checks */
+ if (ELEM(NULL, gps_a, gps_b))
+ return;
+
+ if ((gps_a->totpoints == 0) || (gps_b->totpoints == 0))
+ return;
+
+ /* define start and end points of each stroke */
+ float sa[3], sb[3], ea[3], eb[3];
+ pt = &gps_a->points[0];
+ copy_v3_v3(sa, &pt->x);
+
+ pt = &gps_a->points[gps_a->totpoints - 1];
+ copy_v3_v3(ea, &pt->x);
+
+ pt = &gps_b->points[0];
+ copy_v3_v3(sb, &pt->x);
+
+ pt = &gps_b->points[gps_b->totpoints - 1];
+ copy_v3_v3(eb, &pt->x);
+
+ /* review if need flip stroke B */
+ float ea_sb = len_squared_v3v3(ea, sb);
+ float ea_eb = len_squared_v3v3(ea, eb);
+ /* flip if distance to end point is shorter */
+ if (ea_eb < ea_sb) {
+ gpencil_flip_stroke(gps_b);
+ }
+
+ /* don't visibly link the first and last points? */
+ if (leave_gaps) {
+ /* 1st: add one tail point to start invisible area */
+ point = gps_a->points[gps_a->totpoints - 1];
+ deltatime = point.time;
+ gpencil_stroke_copy_point(gps_a, &point, delta, 0.0f, 0.0f, 0.0f);
+
+ /* 2nd: add one head point to finish invisible area */
+ point = gps_b->points[0];
+ gpencil_stroke_copy_point(gps_a, &point, delta, 0.0f, 0.0f, deltatime);
+ }
+
+ /* 3rd: add all points */
+ for (i = 0, pt = gps_b->points; i < gps_b->totpoints && pt; i++, pt++) {
+ /* check if still room in buffer */
+ if (gps_a->totpoints <= GP_STROKE_BUFFER_MAX - 2) {
+ gpencil_stroke_copy_point(gps_a, pt, delta, pt->pressure, pt->strength, deltatime);
+ }
+ }
+}
+
+static int gp_stroke_join_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *activegpl = BKE_gpencil_layer_getactive(gpd);
+ bGPDstroke *gps, *gpsn;
+ bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
+ bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette);
+
+ bGPDframe *gpf_a = NULL;
+ bGPDstroke *stroke_a = NULL;
+ bGPDstroke *stroke_b = NULL;
+ bGPDstroke *new_stroke = NULL;
+
+ const int type = RNA_enum_get(op->ptr, "type");
+ const bool leave_gaps = RNA_boolean_get(op->ptr, "leave_gaps");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
+
+ if (activegpl->flag & GP_LAYER_LOCKED)
+ return OPERATOR_CANCELLED;
+
+ BLI_assert(ELEM(type, GP_STROKE_JOIN, GP_STROKE_JOINCOPY));
+
+
+ /* read all selected strokes */
+ bool first = false;
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ bGPDframe *gpf = gpl->actframe;
+ if (gpf == NULL)
+ continue;
+
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
+ continue;
+ }
+
+ /* to join strokes, cyclic must be disabled */
+ gps->flag &= ~GP_STROKE_CYCLIC;
+
+ /* saves first frame and stroke */
+ if (!first) {
+ first = true;
+ gpf_a = gpf;
+ stroke_a = gps;
+ }
+ else {
+ stroke_b = gps;
+
+ /* create a new stroke if was not created before (only created if something to join) */
+ if (new_stroke == NULL) {
+ new_stroke = MEM_dupallocN(stroke_a);
+ new_stroke->points = MEM_dupallocN(stroke_a->points);
+ new_stroke->triangles = NULL;
+ new_stroke->tot_triangles = 0;
+ new_stroke->flag |= GP_STROKE_RECALC_CACHES;
+
+ /* if new, set current color */
+ if (type == GP_STROKE_JOINCOPY) {
+ new_stroke->palcolor = palcolor;
+ BLI_strncpy(new_stroke->colorname, palcolor->info, sizeof(new_stroke->colorname));
+ new_stroke->flag |= GP_STROKE_RECALC_COLOR;
+ }
+ }
+
+ /* join new_stroke and stroke B. New stroke will contain all the previous data */
+ gpencil_stroke_join_strokes(new_stroke, stroke_b, leave_gaps);
+
+ /* if join only, delete old strokes */
+ if (type == GP_STROKE_JOIN) {
+ if (stroke_a) {
+ BLI_insertlinkbefore(&gpf_a->strokes, stroke_a, new_stroke);
+ BLI_remlink(&gpf->strokes, stroke_a);
+ BKE_gpencil_free_stroke(stroke_a);
+ stroke_a = NULL;
+ }
+ if (stroke_b) {
+ BLI_remlink(&gpf->strokes, stroke_b);
+ BKE_gpencil_free_stroke(stroke_b);
+ stroke_b = NULL;
+ }
+ }
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* add new stroke if was not added before */
+ if (type == GP_STROKE_JOINCOPY) {
+ if (new_stroke) {
+ /* Add a new frame if needed */
+ if (activegpl->actframe == NULL)
+ activegpl->actframe = BKE_gpencil_frame_addnew(activegpl, gpf_a->framenum);
+
+ BLI_addtail(&activegpl->actframe->strokes, new_stroke);
+ }
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_join(wmOperatorType *ot)
+{
+ static EnumPropertyItem join_type[] = {
+ {GP_STROKE_JOIN, "JOIN", 0, "Join", ""},
+ {GP_STROKE_JOINCOPY, "JOINCOPY", 0, "Join and Copy", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Join Strokes";
+ ot->idname = "GPENCIL_OT_stroke_join";
+ ot->description = "Join selected strokes (optionally as new stroke)";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_join_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", join_type, GP_STROKE_JOIN, "Type", "");
+ RNA_def_boolean(ot->srna, "leave_gaps", false, "Leave Gaps", "Leave gaps between joined strokes instead of linking them");
+}
+
+/* ******************* Stroke flip ************************** */
+
+static int gp_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
+
+ /* read all selected strokes */
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ bGPDframe *gpf = gpl->actframe;
+ if (gpf == NULL)
+ continue;
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
+ continue;
+ }
+
+ /* flip stroke */
+ gpencil_flip_stroke(gps);
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_flip(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Flip Stroke";
+ ot->idname = "GPENCIL_OT_stroke_flip";
+ ot->description = "Change direction of the points of the selected strokes";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_flip_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ***************** Reproject Strokes ********************** */
+
+static int gp_strokes_reproject_poll(bContext *C)
+{
+ /* 2 Requirements:
+ * - 1) Editable GP data
+ * - 2) 3D View only (2D editors don't have projection issues)
+ */
+ return (gp_stroke_edit_poll(C) && ED_operator_view3d_active(C));
+}
+
+static int gp_strokes_reproject_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ GP_SpaceConversion gsc = {NULL};
+
+ /* init space conversion stuff */
+ gp_point_conversion_init(C, &gsc);
+
+ /* Go through each editable + selected stroke, adjusting each of its points one by one... */
+ GP_EDITABLE_STROKES_BEGIN(C, gpl, gps)
+ {
+ if (gps->flag & GP_STROKE_SELECT) {
+ bGPDspoint *pt;
+ int i;
+ float inverse_diff_mat[4][4];
+
+ /* Compute inverse matrix for unapplying parenting once instead of doing per-point */
+ /* TODO: add this bit to the iteration macro? */
+ if (gpl->parent) {
+ invert_m4_m4(inverse_diff_mat, diff_mat);
+ }
+
+ /* Adjust each point */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ float xy[2];
+
+ /* 3D to Screenspace */
+ /* Note: We can't use gp_point_to_xy() here because that uses ints for the screenspace
+ * coordinates, resulting in lost precision, which in turn causes stairstepping
+ * artifacts in the final points.
+ */
+ if (gpl->parent == NULL) {
+ gp_point_to_xy_fl(&gsc, gps, pt, &xy[0], &xy[1]);
+ }
+ else {
+ bGPDspoint pt2;
+ gp_point_to_parent_space(pt, diff_mat, &pt2);
+ gp_point_to_xy_fl(&gsc, gps, &pt2, &xy[0], &xy[1]);
+ }
+
+ /* Project screenspace back to 3D space (from current perspective)
+ * so that all points have been treated the same way
+ */
+ gp_point_xy_to_3d(&gsc, scene, xy, &pt->x);
+
+ /* Unapply parent corrections */
+ if (gpl->parent) {
+ mul_m4_v3(inverse_diff_mat, &pt->x);
+ }
+ }
+ }
+ }
+ GP_EDITABLE_STROKES_END;
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_reproject(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Reproject Strokes";
+ ot->idname = "GPENCIL_OT_reproject";
+ ot->description = "Reproject the selected strokes from the current viewpoint to get all points on the same plane again "
+ "(e.g. to fix problems from accidental 3D cursor movement, or viewport changes)";
+
+ /* callbacks */
+ ot->exec = gp_strokes_reproject_exec;
+ ot->poll = gp_strokes_reproject_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ******************* Stroke subdivide ************************** */
+/* helper: Count how many points need to be inserted */
+static int gp_count_subdivision_cuts(bGPDstroke *gps)
+{
+ bGPDspoint *pt;
+ int i;
+ int totnewpoints = 0;
+ for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ if (i + 1 < gps->totpoints){
+ if (gps->points[i + 1].flag & GP_SPOINT_SELECT) {
+ ++totnewpoints;
+ };
+ }
+ }
+ }
+
+ return totnewpoints;
+}
+static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDspoint *temp_points;
+ const int cuts = RNA_int_get(op->ptr, "number_cuts");
+
+ int totnewpoints, oldtotpoints;
+ int i2;
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
+
+ /* Go through each editable + selected stroke */
+ GP_EDITABLE_STROKES_BEGIN(C, gpl, gps)
+ {
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* loop as many times as cuts */
+ for (int s = 0; s < cuts; s++) {
+ totnewpoints = gp_count_subdivision_cuts(gps);
+ if (totnewpoints == 0) {
+ continue;
+ }
+ /* duplicate points in a temp area */
+ temp_points = MEM_dupallocN(gps->points);
+ oldtotpoints = gps->totpoints;
+
+ /* resize the points arrys */
+ gps->totpoints += totnewpoints;
+ gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+
+ /* loop and interpolate */
+ i2 = 0;
+ for (int i = 0; i < oldtotpoints; i++) {
+ bGPDspoint *pt = &temp_points[i];
+ bGPDspoint *pt_final = &gps->points[i2];
+
+ /* copy current point */
+ copy_v3_v3(&pt_final->x, &pt->x);
+ pt_final->pressure = pt->pressure;
+ pt_final->strength = pt->strength;
+ pt_final->time = pt->time;
+ pt_final->flag = pt->flag;
+ ++i2;
+
+ /* if next point is selected add a half way point */
+ if (pt->flag & GP_SPOINT_SELECT) {
+ if (i + 1 < oldtotpoints){
+ if (temp_points[i + 1].flag & GP_SPOINT_SELECT) {
+ pt_final = &gps->points[i2];
+ /* Interpolate all values */
+ bGPDspoint *next = &temp_points[i + 1];
+ interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
+ pt_final->pressure = interpf(pt->pressure, next->pressure, 0.5f);
+ pt_final->strength = interpf(pt->strength, next->strength, 0.5f);
+ CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ pt_final->time = interpf(pt->time, next->time, 0.5f);
+ pt_final->flag |= GP_SPOINT_SELECT;
+ ++i2;
+ };
+ }
+ }
+ }
+ /* free temp memory */
+ MEM_freeN(temp_points);
+ }
+ }
+ }
+ GP_EDITABLE_STROKES_END;
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_subdivide(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Subdivide Stroke";
+ ot->idname = "GPENCIL_OT_stroke_subdivide";
+ ot->description = "Subdivide between continuous selected points of the stroke adding a point half way between them";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_subdivide_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ /* properties */
+ prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 10, "Number of Cuts", "", 1, 5);
+ /* avoid re-using last var because it can cause _very_ high value and annoy users */
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+}
+
+/* ========= Interpolation operators ========================== */
+/* Helper: Update point with interpolation */
+static void gp_interpolate_update_points(bGPDstroke *gps_from, bGPDstroke *gps_to, bGPDstroke *new_stroke, float factor)
+{
+ bGPDspoint *prev, *pt, *next;
+
+ /* update points */
+ for (int i = 0; i < new_stroke->totpoints; i++) {
+ prev = &gps_from->points[i];
+ pt = &new_stroke->points[i];
+ next = &gps_to->points[i];
+
+ /* Interpolate all values */
+ interp_v3_v3v3(&pt->x, &prev->x, &next->x, factor);
+ pt->pressure = interpf(prev->pressure, next->pressure, factor);
+ pt->strength = interpf(prev->strength, next->strength, factor);
+ CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ }
+}
+
+/* Helper: Update all strokes interpolated */
+static void gp_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgpi)
+{
+ tGPDinterpolate_layer *tgpil;
+ bGPDstroke *new_stroke, *gps_from, *gps_to;
+ int cStroke;
+ float factor;
+ float shift = tgpi->shift;
+
+ for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
+ factor = tgpil->factor + shift;
+ for (new_stroke = tgpil->interFrame->strokes.first; new_stroke; new_stroke = new_stroke->next) {
+ if (new_stroke->totpoints == 0) {
+ continue;
+ }
+ /* get strokes to interpolate */
+ cStroke = BLI_findindex(&tgpil->interFrame->strokes, new_stroke);
+ gps_from = BLI_findlink(&tgpil->prevFrame->strokes, cStroke);
+ gps_to = BLI_findlink(&tgpil->nextFrame->strokes, cStroke);
+ /* update points position */
+ if ((gps_from) && (gps_to)) {
+ gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor);
+ }
+ }
+ }
+
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+}
+
+/* Helper: Verify valid strokes for interpolation */
+static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ int flag = ts->gp_sculpt.flag;
+
+ bGPDlayer *gpl;
+ bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C);
+ bGPDstroke *gps_from, *gps_to;
+ int fFrame;
+
+ /* get layers */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* all layers or only active */
+ if (((flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS) == 0) && (gpl != active_gpl)) {
+ continue;
+ }
+ /* only editable and visible layers are considered */
+ if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
+ continue;
+ }
+ /* read strokes */
+ for (gps_from = gpl->actframe->strokes.first; gps_from; gps_from = gps_from->next) {
+ /* only selected */
+ if ((flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) {
+ continue;
+ }
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps_from) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(gpl, gps_from) == false) {
+ continue;
+ }
+ /* get final stroke to interpolate */
+ fFrame = BLI_findindex(&gpl->actframe->strokes, gps_from);
+ gps_to = BLI_findlink(&gpl->actframe->next->strokes, fFrame);
+ if (gps_to == NULL) {
+ continue;
+ }
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Helper: Create internal strokes interpolated */
+static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
+{
+ bGPDlayer *gpl;
+ bGPdata *gpd = tgpi->gpd;
+ tGPDinterpolate_layer *tgpil;
+ bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C);
+ bGPDstroke *gps_from, *gps_to, *new_stroke;
+ int fFrame;
+
+ /* save initial factor for active layer to define shift limits */
+ tgpi->init_factor = (float)(tgpi->cframe - active_gpl->actframe->framenum) / (active_gpl->actframe->next->framenum - active_gpl->actframe->framenum + 1);
+ /* limits are 100% below 0 and 100% over the 100% */
+ tgpi->low_limit = -1.0f - tgpi->init_factor;
+ tgpi->high_limit = 2.0f - tgpi->init_factor;
+
+ /* set layers */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* all layers or only active */
+ if (((tgpi->flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS) == 0) && (gpl != active_gpl)) {
+ continue;
+ }
+ /* only editable and visible layers are considered */
+ if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
+ continue;
+ }
+ /* create temp data for each layer */
+ tgpil = NULL;
+ tgpil = MEM_callocN(sizeof(tGPDinterpolate_layer), "GPencil Interpolate Layer");
+
+ tgpil->gpl = gpl;
+ tgpil->prevFrame = gpl->actframe;
+ tgpil->nextFrame = gpl->actframe->next;
+
+ BLI_addtail(&tgpi->ilayers, tgpil);
+ /* create a new temporary frame */
+ tgpil->interFrame = MEM_callocN(sizeof(bGPDframe), "bGPDframe");
+ tgpil->interFrame->framenum = tgpi->cframe;
+
+ /* get interpolation factor by layer (usually must be equal for all layers, but not sure) */
+ tgpil->factor = (float)(tgpi->cframe - tgpil->prevFrame->framenum) / (tgpil->nextFrame->framenum - tgpil->prevFrame->framenum + 1);
+ /* create new strokes data with interpolated points reading original stroke */
+ for (gps_from = tgpil->prevFrame->strokes.first; gps_from; gps_from = gps_from->next) {
+ bool valid = true;
+ /* only selected */
+ if ((tgpi->flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) {
+ valid = false;
+ }
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps_from) == false) {
+ valid = false;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(tgpil->gpl, gps_from) == false) {
+ valid = false;
+ }
+ /* get final stroke to interpolate */
+ fFrame = BLI_findindex(&tgpil->prevFrame->strokes, gps_from);
+ gps_to = BLI_findlink(&tgpil->nextFrame->strokes, fFrame);
+ if (gps_to == NULL) {
+ valid = false;
+ }
+ /* create new stroke */
+ new_stroke = MEM_dupallocN(gps_from);
+ new_stroke->points = MEM_dupallocN(gps_from->points);
+ new_stroke->triangles = MEM_dupallocN(gps_from->triangles);
+ if (valid) {
+ /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */
+ if (gps_from->totpoints > gps_to->totpoints) {
+ new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points) * gps_to->totpoints);
+ new_stroke->totpoints = gps_to->totpoints;
+ new_stroke->tot_triangles = 0;
+ new_stroke->flag |= GP_STROKE_RECALC_CACHES;
+ }
+ /* update points position */
+ gp_interpolate_update_points(gps_from, gps_to, new_stroke, tgpil->factor);
+ }
+ else {
+ /* need an empty stroke to keep index correct for lookup, but resize to smallest size */
+ new_stroke->totpoints = 0;
+ new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points));
+ new_stroke->tot_triangles = 0;
+ new_stroke->triangles = MEM_recallocN(new_stroke->triangles, sizeof(*new_stroke->triangles));
+ }
+ /* add to strokes */
+ BLI_addtail(&tgpil->interFrame->strokes, new_stroke);
+ }
+ }
+}
+
+/* Helper: calculate shift based on position of mouse (we only use x-axis for now.
+* since this is more convenient for users to do), and store new shift value
+*/
+static void gpencil_mouse_update_shift(tGPDinterpolate *tgpi, wmOperator *op, const wmEvent *event)
+{
+ float mid = (float)(tgpi->ar->winx - tgpi->ar->winrct.xmin) / 2.0f;
+ float mpos = event->x - tgpi->ar->winrct.xmin;
+ if (mpos >= mid) {
+ tgpi->shift = ((mpos - mid) * tgpi->high_limit) / mid;
+ }
+ else {
+ tgpi->shift = tgpi->low_limit - ((mpos * tgpi->low_limit) / mid);
+ }
+
+ CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit);
+ RNA_float_set(op->ptr, "shift", tgpi->shift);
+}
+
+/* Helper: Draw status message while the user is running the operator */
+static void gpencil_interpolate_status_indicators(tGPDinterpolate *p)
+{
+ Scene *scene = p->scene;
+ char status_str[UI_MAX_DRAW_STR];
+ char msg_str[UI_MAX_DRAW_STR];
+ BLI_strncpy(msg_str, IFACE_("GPencil Interpolation: ESC/RMB to cancel, Enter/LMB to confirm, WHEEL/MOVE to adjust, Factor"), UI_MAX_DRAW_STR);
+
+ if (hasNumInput(&p->num)) {
+ char str_offs[NUM_STR_REP_LEN];
+
+ outputNumInput(&p->num, str_offs, &scene->unit);
+
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", msg_str, str_offs);
+ }
+ else {
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %d %%", msg_str, (int)((p->init_factor + p->shift) * 100.0f));
+ }
+
+ ED_area_headerprint(p->sa, status_str);
+}
+
+/* Helper: Update screen and stroke */
+static void gpencil_interpolate_update(bContext *C, wmOperator *op, tGPDinterpolate *tgpi)
+{
+ /* update shift indicator in header */
+ gpencil_interpolate_status_indicators(tgpi);
+ /* apply... */
+ tgpi->shift = RNA_float_get(op->ptr, "shift");
+ /* update points position */
+ gp_interpolate_update_strokes(C, tgpi);
+}
+
+/* init new temporary interpolation data */
+static bool gp_interpolate_set_init_values(bContext *C, wmOperator *op, tGPDinterpolate *tgpi)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+
+ /* set current scene and window */
+ tgpi->scene = CTX_data_scene(C);
+ tgpi->sa = CTX_wm_area(C);
+ tgpi->ar = CTX_wm_region(C);
+ tgpi->flag = ts->gp_sculpt.flag;
+
+ /* set current frame number */
+ tgpi->cframe = tgpi->scene->r.cfra;
+
+ /* set GP datablock */
+ tgpi->gpd = gpd;
+
+ /* set interpolation weight */
+ tgpi->shift = RNA_float_get(op->ptr, "shift");
+ /* set layers */
+ gp_interpolate_set_points(C, tgpi);
+
+ return 1;
+}
+
+/* Poll handler: check if context is suitable for interpolation */
+static int gpencil_interpolate_poll(bContext *C)
+{
+ bGPdata * gpd = CTX_data_gpencil_data(C);
+ bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+ /* only 3D view */
+ if (CTX_wm_area(C)->spacetype != SPACE_VIEW3D) {
+ return 0;
+ }
+ /* need data to interpolate */
+ if (ELEM(NULL, gpd, gpl)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Allocate memory and initialize values */
+static tGPDinterpolate *gp_session_init_interpolation(bContext *C, wmOperator *op)
+{
+ tGPDinterpolate *tgpi = NULL;
+
+ /* create new context data */
+ tgpi = MEM_callocN(sizeof(tGPDinterpolate), "GPencil Interpolate Data");
+
+ /* define initial values */
+ gp_interpolate_set_init_values(C, op, tgpi);
+
+ /* return context data for running operator */
+ return tgpi;
+}
+
+/* Exit and free memory */
+static void gpencil_interpolate_exit(bContext *C, wmOperator *op)
+{
+ tGPDinterpolate *tgpi = op->customdata;
+ tGPDinterpolate_layer *tgpil;
+
+ /* don't assume that operator data exists at all */
+ if (tgpi) {
+ /* remove drawing handler */
+ if (tgpi->draw_handle_screen) {
+ ED_region_draw_cb_exit(tgpi->ar->type, tgpi->draw_handle_screen);
+ }
+ if (tgpi->draw_handle_3d) {
+ ED_region_draw_cb_exit(tgpi->ar->type, tgpi->draw_handle_3d);
+ }
+ /* clear status message area */
+ ED_area_headerprint(tgpi->sa, NULL);
+ /* finally, free memory used by temp data */
+ for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
+ BKE_gpencil_free_strokes(tgpil->interFrame);
+ MEM_freeN(tgpil->interFrame);
+ }
+
+ BLI_freelistN(&tgpi->ilayers);
+ MEM_freeN(tgpi);
+ }
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+
+ /* clear pointer */
+ op->customdata = NULL;
+}
+
+/* Cancel handler */
+static void gpencil_interpolate_cancel(bContext *C, wmOperator *op)
+{
+ /* this is just a wrapper around exit() */
+ gpencil_interpolate_exit(C, op);
+}
+
+/* Init interpolation: Allocate memory and set init values */
+static int gpencil_interpolate_init(bContext *C, wmOperator *op)
+{
+ tGPDinterpolate *tgpi;
+ /* check context */
+ tgpi = op->customdata = gp_session_init_interpolation(C, op);
+ if (tgpi == NULL) {
+ /* something wasn't set correctly in context */
+ gpencil_interpolate_exit(C, op);
+ return 0;
+ }
+
+ /* everything is now setup ok */
+ return 1;
+}
+
+/* ********************** custom drawcall api ***************** */
+/* Helper: drawing callback for modal operator in screen mode */
+static void gpencil_interpolate_draw_screen(const struct bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
+{
+ wmOperator *op = arg;
+ struct tGPDinterpolate *tgpi = op->customdata;
+ ED_gp_draw_interpolation(tgpi, REGION_DRAW_POST_PIXEL);
+}
+
+/* Helper: drawing callback for modal operator in 3d mode */
+static void gpencil_interpolate_draw_3d(const struct bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
+{
+ wmOperator *op = arg;
+ struct tGPDinterpolate *tgpi = op->customdata;
+ ED_gp_draw_interpolation(tgpi, REGION_DRAW_POST_VIEW);
+}
+
+/* Invoke handler: Initialize the operator */
+static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ wmWindow *win = CTX_wm_window(C);
+ Scene *scene = CTX_data_scene(C);
+ bGPdata * gpd = CTX_data_gpencil_data(C);
+ bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+ tGPDinterpolate *tgpi = NULL;
+
+ /* cannot interpolate if not between 2 frames */
+ if ((gpl->actframe == NULL) || (gpl->actframe->next == NULL)) {
+ BKE_report(op->reports, RPT_ERROR, "Interpolation requires to be between two grease pencil frames in active layer");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* cannot interpolate in extremes */
+ if ((gpl->actframe->framenum == scene->r.cfra) || (gpl->actframe->next->framenum == scene->r.cfra)) {
+ BKE_report(op->reports, RPT_ERROR, "Interpolation requires to be between two grease pencil frames in active layer");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* need editable strokes */
+ if (!gp_interpolate_check_todo(C, gpd)) {
+ BKE_report(op->reports, RPT_ERROR, "Interpolation requires some editable stroke");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* try to initialize context data needed */
+ if (!gpencil_interpolate_init(C, op)) {
+ if (op->customdata)
+ MEM_freeN(op->customdata);
+ return OPERATOR_CANCELLED;
+ }
+ else
+ tgpi = op->customdata;
+
+ /* enable custom drawing handlers. It needs 2 handlers because can be strokes in 3d space and screen space and each handler use different
+ coord system */
+ tgpi->draw_handle_screen = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_interpolate_draw_screen, op, REGION_DRAW_POST_PIXEL);
+ tgpi->draw_handle_3d = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_interpolate_draw_3d, op, REGION_DRAW_POST_VIEW);
+ /* set cursor to indicate modal */
+ WM_cursor_modal_set(win, BC_EW_SCROLLCURSOR);
+ /* update shift indicator in header */
+ gpencil_interpolate_status_indicators(tgpi);
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+
+ /* add a modal handler for this operator */
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* Modal handler: Events handling during interactive part */
+static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ tGPDinterpolate *tgpi = op->customdata;
+ wmWindow *win = CTX_wm_window(C);
+ bGPDframe *gpf_dst;
+ bGPDstroke *gps_src, *gps_dst;
+ tGPDinterpolate_layer *tgpil;
+ const bool has_numinput = hasNumInput(&tgpi->num);
+
+ switch (event->type) {
+ case LEFTMOUSE: /* confirm */
+ case RETKEY:
+ {
+ /* return to normal cursor and header status */
+ ED_area_headerprint(tgpi->sa, NULL);
+ WM_cursor_modal_restore(win);
+
+ /* insert keyframes as required... */
+ for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
+ gpf_dst = BKE_gpencil_layer_getframe(tgpil->gpl, tgpi->cframe, GP_GETFRAME_ADD_NEW);
+ gpf_dst->key_type = BEZT_KEYTYPE_BREAKDOWN;
+
+ /* copy strokes */
+ BLI_listbase_clear(&gpf_dst->strokes);
+ for (gps_src = tgpil->interFrame->strokes.first; gps_src; gps_src = gps_src->next) {
+ if (gps_src->totpoints == 0) {
+ continue;
+ }
+ /* make copy of source stroke, then adjust pointer to points too */
+ gps_dst = MEM_dupallocN(gps_src);
+ gps_dst->points = MEM_dupallocN(gps_src->points);
+ gps_dst->triangles = MEM_dupallocN(gps_src->triangles);
+ gps_dst->flag |= GP_STROKE_RECALC_CACHES;
+ BLI_addtail(&gpf_dst->strokes, gps_dst);
+ }
+ }
+ /* clean up temp data */
+ gpencil_interpolate_exit(C, op);
+
+ /* done! */
+ return OPERATOR_FINISHED;
+ }
+
+ case ESCKEY: /* cancel */
+ case RIGHTMOUSE:
+ {
+ /* return to normal cursor and header status */
+ ED_area_headerprint(tgpi->sa, NULL);
+ WM_cursor_modal_restore(win);
+
+ /* clean up temp data */
+ gpencil_interpolate_exit(C, op);
+
+ /* canceled! */
+ return OPERATOR_CANCELLED;
+ }
+ case WHEELUPMOUSE:
+ {
+ tgpi->shift = tgpi->shift + 0.01f;
+ CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit);
+ RNA_float_set(op->ptr, "shift", tgpi->shift);
+ /* update screen */
+ gpencil_interpolate_update(C, op, tgpi);
+ break;
+ }
+ case WHEELDOWNMOUSE:
+ {
+ tgpi->shift = tgpi->shift - 0.01f;
+ CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit);
+ RNA_float_set(op->ptr, "shift", tgpi->shift);
+ /* update screen */
+ gpencil_interpolate_update(C, op, tgpi);
+ break;
+ }
+ case MOUSEMOVE: /* calculate new position */
+ {
+ /* only handle mousemove if not doing numinput */
+ if (has_numinput == false) {
+ /* update shift based on position of mouse */
+ gpencil_mouse_update_shift(tgpi, op, event);
+ /* update screen */
+ gpencil_interpolate_update(C, op, tgpi);
+ }
+ break;
+ }
+ default:
+ if ((event->val == KM_PRESS) && handleNumInput(C, &tgpi->num, event)) {
+ float value;
+ float factor = tgpi->init_factor;
+
+ /* Grab shift from numeric input, and store this new value (the user see an int) */
+ value = (factor + tgpi->shift) * 100.0f;
+ applyNumInput(&tgpi->num, &value);
+ tgpi->shift = value / 100.0f;
+ /* recalculate the shift to get the right value in the frame scale */
+ tgpi->shift = tgpi->shift - factor;
+
+ CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit);
+ RNA_float_set(op->ptr, "shift", tgpi->shift);
+
+ /* update screen */
+ gpencil_interpolate_update(C, op, tgpi);
+
+ break;
+ }
+ else {
+ /* unhandled event - allow to pass through */
+ return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
+ }
+ }
+
+ /* still running... */
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* Define modal operator for interpolation */
+void GPENCIL_OT_interpolate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Grease Pencil Interpolation";
+ ot->idname = "GPENCIL_OT_interpolate";
+ ot->description = "Interpolate grease pencil strokes between frames";
+
+ /* api callbacks */
+ ot->invoke = gpencil_interpolate_invoke;
+ ot->modal = gpencil_interpolate_modal;
+ ot->cancel = gpencil_interpolate_cancel;
+ ot->poll = gpencil_interpolate_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ RNA_def_float_percentage(ot->srna, "shift", 0.0f, -1.0f, 1.0f, "Shift", "Displacement factor for the interpolate operation", -0.9f, 0.9f);
+}
+
+/* =============== Interpolate sequence ===============*/
+/* Create Sequence Interpolation */
+static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ bGPdata * gpd = CTX_data_gpencil_data(C);
+ bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C);
+ bGPDlayer *gpl;
+ bGPDframe *prevFrame, *nextFrame, *interFrame;
+ bGPDstroke *gps_from, *gps_to, *new_stroke;
+ float factor;
+ int cframe, fFrame;
+ int flag = ts->gp_sculpt.flag;
+
+ /* cannot interpolate if not between 2 frames */
+ if ((active_gpl->actframe == NULL) || (active_gpl->actframe->next == NULL)) {
+ BKE_report(op->reports, RPT_ERROR, "Interpolation requires to be between two grease pencil frames");
+ return OPERATOR_CANCELLED;
+ }
+ /* cannot interpolate in extremes */
+ if ((active_gpl->actframe->framenum == scene->r.cfra) || (active_gpl->actframe->next->framenum == scene->r.cfra)) {
+ BKE_report(op->reports, RPT_ERROR, "Interpolation requires to be between two grease pencil frames");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* loop all layer to check if need interpolation */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* all layers or only active */
+ if (((flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS) == 0) && (gpl != active_gpl)) {
+ continue;
+ }
+ /* only editable and visible layers are considered */
+ if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
+ continue;
+ }
+ /* store extremes */
+ prevFrame = gpl->actframe;
+ nextFrame = gpl->actframe->next;
+ /* Loop over intermediary frames and create the interpolation */
+ for (cframe = prevFrame->framenum + 1; cframe < nextFrame->framenum; cframe++) {
+ interFrame = NULL;
+
+ /* get interpolation factor */
+ factor = (float)(cframe - prevFrame->framenum) / (nextFrame->framenum - prevFrame->framenum + 1);
+
+ /* create new strokes data with interpolated points reading original stroke */
+ for (gps_from = prevFrame->strokes.first; gps_from; gps_from = gps_from->next) {
+ /* only selected */
+ if ((flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) {
+ continue;
+ }
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps_from) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(gpl, gps_from) == false) {
+ continue;
+ }
+ /* get final stroke to interpolate */
+ fFrame = BLI_findindex(&prevFrame->strokes, gps_from);
+ gps_to = BLI_findlink(&nextFrame->strokes, fFrame);
+ if (gps_to == NULL) {
+ continue;
+ }
+ /* create a new frame if needed */
+ if (interFrame == NULL) {
+ interFrame = BKE_gpencil_layer_getframe(gpl, cframe, GP_GETFRAME_ADD_NEW);
+ interFrame->key_type = BEZT_KEYTYPE_BREAKDOWN;
+ }
+ /* create new stroke */
+ new_stroke = MEM_dupallocN(gps_from);
+ new_stroke->points = MEM_dupallocN(gps_from->points);
+ new_stroke->triangles = MEM_dupallocN(gps_from->triangles);
+ /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */
+ if (gps_from->totpoints > gps_to->totpoints) {
+ new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points) * gps_to->totpoints);
+ new_stroke->totpoints = gps_to->totpoints;
+ new_stroke->tot_triangles = 0;
+ new_stroke->flag |= GP_STROKE_RECALC_CACHES;
+ }
+ /* update points position */
+ gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor);
+
+ /* add to strokes */
+ BLI_addtail(&interFrame->strokes, new_stroke);
+ }
+ }
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+/* Define sequence interpolation */
+void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Grease Pencil Sequence Interpolation";
+ ot->idname = "GPENCIL_OT_interpolate_sequence";
+ ot->description = "Interpolate full grease pencil strokes sequence between frames";
+
+ /* api callbacks */
+ ot->exec = gpencil_interpolate_seq_exec;
+ ot->poll = gpencil_interpolate_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+/* ========= End Interpolation operators ========================== */
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index dd28f6ac531..e2e5fc28710 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -101,6 +101,35 @@ void gp_point_to_xy(GP_SpaceConversion *settings, struct bGPDstroke *gps, struct
int *r_x, int *r_y);
/**
+ * Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screenspace (2D)
+ *
+ * Just like gp_point_to_xy(), except the resulting coordinates are floats not ints.
+ * Use this version to solve "stair-step" artifacts which may arise when roundtripping the calculations.
+ *
+ * \param[out] r_x The screen-space x-coordinate of the point
+ * \param[out] r_y The screen-space y-coordinate of the point
+ */
+void gp_point_to_xy_fl(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt,
+ float *r_x, float *r_y);
+
+/**
+ * Convert point to parent space
+ *
+ * \param pt Original point
+ * \param diff_mat Matrix with the difference between original parent matrix
+ * \param[out] r_pt Pointer to new point after apply matrix
+ */
+void gp_point_to_parent_space(bGPDspoint *pt, float diff_mat[4][4], bGPDspoint *r_pt);
+/**
+ * Change points position relative to parent object
+ */
+void gp_apply_parent(bGPDlayer *gpl, bGPDstroke *gps);
+/**
+ * Change point position relative to parent object
+ */
+void gp_apply_parent_point(bGPDlayer *gpl, bGPDspoint *pt);
+
+/**
* Convert a screenspace point to a 3D Grease Pencil coordinate.
*
* For use with editing tools where it is easier to perform the operations in 2D,
@@ -116,6 +145,10 @@ bool gp_point_xy_to_3d(GP_SpaceConversion *gsc, struct Scene *scene, const float
int gp_add_poll(struct bContext *C);
int gp_active_layer_poll(struct bContext *C);
+int gp_active_brush_poll(struct bContext *C);
+int gp_active_palette_poll(struct bContext *C);
+int gp_active_palettecolor_poll(struct bContext *C);
+int gp_brush_crt_presets_poll(bContext *C);
/* Copy/Paste Buffer --------------------------------- */
/* gpencil_edit.c */
@@ -137,17 +170,48 @@ void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke
bool gp_smooth_stroke(bGPDstroke *gps, int i, float inf, bool affect_pressure);
/**
+* Apply smooth for strength to stroke point
+* \param gps Stroke to smooth
+* \param i Point index
+* \param inf Amount of smoothing to apply
+*/
+bool gp_smooth_stroke_strength(bGPDstroke *gps, int i, float inf);
+
+/**
+* Apply smooth for thickness to stroke point (use pressure)
+* \param gps Stroke to smooth
+* \param i Point index
+* \param inf Amount of smoothing to apply
+*/
+bool gp_smooth_stroke_thickness(bGPDstroke *gps, int i, float inf);
+
+/**
* Subdivide a stroke once, by adding points at the midpoint between each pair of points
* \param gps Stroke data
* \param new_totpoints Total number of points (after subdividing)
*/
void gp_subdivide_stroke(bGPDstroke *gps, const int new_totpoints);
+/**
+* Add randomness to stroke
+* \param gps Stroke data
+* \param brush Brush data
+*/
+void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush);
+
/* Layers Enums -------------------------------------- */
struct EnumPropertyItem *ED_gpencil_layers_enum_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
struct EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
+/* Enums of GP Brushes */
+EnumPropertyItem *ED_gpencil_brushes_enum_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
+ bool *r_free);
+
+/* Enums of GP palettes */
+EnumPropertyItem *ED_gpencil_palettes_enum_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
+ bool *r_free);
+
/* ***************************************************** */
/* Operator Defines */
@@ -155,7 +219,7 @@ struct EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(struct bContext *
void GPENCIL_OT_draw(struct wmOperatorType *ot);
-/* Paint Modes for operator*/
+/* Paint Modes for operator */
typedef enum eGPencil_PaintModes {
GP_PAINTMODE_DRAW = 0,
GP_PAINTMODE_ERASER,
@@ -163,9 +227,13 @@ typedef enum eGPencil_PaintModes {
GP_PAINTMODE_DRAW_POLY
} eGPencil_PaintModes;
+/* maximum sizes of gp-session buffer */
+#define GP_STROKE_BUFFER_MAX 5000
+
/* stroke editing ----- */
void GPENCIL_OT_editmode_toggle(struct wmOperatorType *ot);
+void GPENCIL_OT_selection_opacity_toggle(struct wmOperatorType *ot);
void GPENCIL_OT_select(struct wmOperatorType *ot);
void GPENCIL_OT_select_all(struct wmOperatorType *ot);
@@ -194,6 +262,7 @@ void GPENCIL_OT_snap_to_cursor(struct wmOperatorType *ot);
void GPENCIL_OT_snap_cursor_to_selected(struct wmOperatorType *ot);
void GPENCIL_OT_snap_cursor_to_center(struct wmOperatorType *ot);
+void GPENCIL_OT_reproject(struct wmOperatorType *ot);
/* stroke sculpting -- */
@@ -216,18 +285,63 @@ void GPENCIL_OT_lock_all(struct wmOperatorType *ot);
void GPENCIL_OT_unlock_all(struct wmOperatorType *ot);
void GPENCIL_OT_layer_isolate(struct wmOperatorType *ot);
+void GPENCIL_OT_layer_merge(struct wmOperatorType *ot);
void GPENCIL_OT_active_frame_delete(struct wmOperatorType *ot);
+void GPENCIL_OT_active_frames_delete_all(struct wmOperatorType *ot);
void GPENCIL_OT_convert(struct wmOperatorType *ot);
+enum {
+ GP_STROKE_JOIN = -1,
+ GP_STROKE_JOINCOPY = 1
+};
+
+void GPENCIL_OT_stroke_arrange(struct wmOperatorType *ot);
+void GPENCIL_OT_stroke_change_color(struct wmOperatorType *ot);
+void GPENCIL_OT_stroke_lock_color(struct wmOperatorType *ot);
+void GPENCIL_OT_stroke_apply_thickness(struct wmOperatorType *ot);
+void GPENCIL_OT_stroke_cyclical_set(struct wmOperatorType *ot);
+void GPENCIL_OT_stroke_join(struct wmOperatorType *ot);
+void GPENCIL_OT_stroke_flip(struct wmOperatorType *ot);
+void GPENCIL_OT_stroke_subdivide(struct wmOperatorType *ot);
+
+void GPENCIL_OT_brush_add(struct wmOperatorType *ot);
+void GPENCIL_OT_brush_remove(struct wmOperatorType *ot);
+void GPENCIL_OT_brush_change(struct wmOperatorType *ot);
+void GPENCIL_OT_brush_move(struct wmOperatorType *ot);
+void GPENCIL_OT_brush_presets_create(struct wmOperatorType *ot);
+void GPENCIL_OT_brush_copy(struct wmOperatorType *ot);
+void GPENCIL_OT_brush_select(struct wmOperatorType *ot);
+
+void GPENCIL_OT_palette_add(struct wmOperatorType *ot);
+void GPENCIL_OT_palette_remove(struct wmOperatorType *ot);
+void GPENCIL_OT_palette_change(struct wmOperatorType *ot);
+void GPENCIL_OT_palette_lock_layer(struct wmOperatorType *ot);
+
+void GPENCIL_OT_palettecolor_add(struct wmOperatorType *ot);
+void GPENCIL_OT_palettecolor_remove(struct wmOperatorType *ot);
+void GPENCIL_OT_palettecolor_isolate(struct wmOperatorType *ot);
+void GPENCIL_OT_palettecolor_hide(struct wmOperatorType *ot);
+void GPENCIL_OT_palettecolor_reveal(struct wmOperatorType *ot);
+void GPENCIL_OT_palettecolor_lock_all(struct wmOperatorType *ot);
+void GPENCIL_OT_palettecolor_unlock_all(struct wmOperatorType *ot);
+void GPENCIL_OT_palettecolor_move(struct wmOperatorType *ot);
+void GPENCIL_OT_palettecolor_select(struct wmOperatorType *ot);
+void GPENCIL_OT_palettecolor_copy(struct wmOperatorType *ot);
+
/* undo stack ---------- */
void gpencil_undo_init(struct bGPdata *gpd);
void gpencil_undo_push(struct bGPdata *gpd);
void gpencil_undo_finish(void);
-/******************************************************* */
+/* interpolation ---------- */
+
+void GPENCIL_OT_interpolate(struct wmOperatorType *ot);
+void GPENCIL_OT_interpolate_sequence(struct wmOperatorType *ot);
+
+/* ****************************************************** */
/* FILTERED ACTION DATA - TYPES ---> XXX DEPRECEATED OLD ANIM SYSTEM CODE! */
/* XXX - TODO: replace this with the modern bAnimListElem... */
@@ -249,7 +363,7 @@ typedef struct bActListElem {
short ownertype; /* type of owner */
} bActListElem;
-/******************************************************* */
+/* ****************************************************** */
/* FILTER ACTION DATA - METHODS/TYPES */
/* filtering flags - under what circumstances should a channel be added */
@@ -272,4 +386,44 @@ typedef enum ACTCONT_TYPES {
ACTCONT_GPENCIL
} ACTCONT_TYPES;
+/* ****************************************************** */
+/* Stroke Iteration Utilities */
+
+/**
+* Iterate over all editable strokes in the current context,
+* stopping on each usable layer + stroke pair (i.e. gpl and gps)
+* to perform some operations on the stroke.
+*
+* \param gpl The identifier to use for the layer of the stroke being processed.
+* Choose a suitable value to avoid name clashes.
+* \param gps The identifier to use for current stroke being processed.
+* Choose a suitable value to avoid name clashes.
+*/
+#define GP_EDITABLE_STROKES_BEGIN(C, gpl, gps) \
+{ \
+ CTX_DATA_BEGIN(C, bGPDlayer*, gpl, editable_gpencil_layers) \
+ { \
+ if (gpl->actframe == NULL) \
+ continue; \
+ /* calculate difference matrix if parent object */ \
+ float diff_mat[4][4]; \
+ ED_gpencil_parent_location(gpl, diff_mat); \
+ /* loop over strokes */ \
+ for (bGPDstroke *gps = gpl->actframe->strokes.first; gps; gps = gps->next) { \
+ /* skip strokes that are invalid for current view */ \
+ if (ED_gpencil_stroke_can_use(C, gps) == false) \
+ continue; \
+ /* check if the color is editable */ \
+ if (ED_gpencil_stroke_color_use(gpl, gps) == false) \
+ continue; \
+ /* ... Do Stuff With Strokes ... */
+
+#define GP_EDITABLE_STROKES_END \
+ } \
+ } \
+ CTX_DATA_END; \
+} (void)0
+
+/* ****************************************************** */
+
#endif /* __GPENCIL_INTERN_H__ */
diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c
index 7241d4bb632..057d53ea458 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -18,7 +18,7 @@
* The Original Code is Copyright (C) 2009, Blender Foundation, Joshua Leung
* This is a new part of Blender
*
- * Contributor(s): Joshua Leung
+ * Contributor(s): Joshua Leung, Antonio Vazquez
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -79,7 +79,6 @@ static void ed_keymap_gpencil_general(wmKeyConfig *keyconf)
RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_ERASER);
RNA_boolean_set(kmi->ptr, "wait_for_input", false);
-
/* Tablet Mappings for Drawing ------------------ */
/* For now, only support direct drawing using the eraser, as most users using a tablet
* may still want to use that as their primary pointing device!
@@ -102,6 +101,10 @@ static void ed_keymap_gpencil_general(wmKeyConfig *keyconf)
/* Pie Menu - For standard tools */
WM_keymap_add_menu_pie(keymap, "GPENCIL_PIE_tool_palette", QKEY, KM_PRESS, 0, DKEY);
WM_keymap_add_menu_pie(keymap, "GPENCIL_PIE_settings_palette", WKEY, KM_PRESS, 0, DKEY);
+
+ /* Delete Active Frame - For easier video tutorials/review sessions */
+ /* NOTE: This works even when not in EditMode */
+ WM_keymap_add_item(keymap, "GPENCIL_OT_active_frames_delete_all", XKEY, KM_PRESS, 0, DKEY);
}
/* ==================== */
@@ -136,10 +139,43 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
* that the only data being edited is that of the Grease Pencil strokes
*/
- /* FKEY = Eraser Radius */
- kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, 0, 0);
+ /* CTRL + FKEY = Eraser Radius */
+ kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_CTRL, 0);
RNA_string_set(kmi->ptr, "data_path_primary", "user_preferences.edit.grease_pencil_eraser_radius");
+ /* Interpolation */
+ WM_keymap_add_item(keymap, "GPENCIL_OT_interpolate", EKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
+ WM_keymap_add_item(keymap, "GPENCIL_OT_interpolate_sequence", EKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
+
+ /* Sculpting ------------------------------------- */
+
+ /* Brush-Based Editing:
+ * EKEY + LMB = Single stroke, draw immediately
+ * + Other Modifiers (Ctrl/Shift) = Invert, Smooth, etc.
+ *
+ * For the modal version, use D+E -> Sculpt
+ */
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, 0, EKEY);
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, KM_CTRL, EKEY);
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+ /*RNA_boolean_set(kmi->ptr, "use_invert", true);*/
+
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, KM_SHIFT, EKEY);
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+ /*RNA_boolean_set(kmi->ptr, "use_smooth", true);*/
+
+
+ /* Shift-FKEY = Sculpt Strength */
+ kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.brush.strength");
+
+ /* FKEY = Sculpt Brush Size */
+ kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, 0, 0);
+ RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.brush.size");
+
+
/* Selection ------------------------------------- */
/* select all */
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_all", AKEY, KM_PRESS, 0, 0);
@@ -200,10 +236,21 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
/* delete */
WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_gpencil_delete", XKEY, KM_PRESS, 0, 0);
WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_gpencil_delete", DELKEY, KM_PRESS, 0, 0);
-
+
WM_keymap_add_item(keymap, "GPENCIL_OT_dissolve", XKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "GPENCIL_OT_dissolve", DELKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "GPENCIL_OT_active_frames_delete_all", XKEY, KM_PRESS, KM_SHIFT, 0);
+
+ /* menu edit specials */
+ WM_keymap_add_menu(keymap, "GPENCIL_MT_gpencil_edit_specials", WKEY, KM_PRESS, 0, 0);
+
+ /* join strokes */
+ WM_keymap_add_item(keymap, "GPENCIL_OT_stroke_join", JKEY, KM_PRESS, KM_CTRL, 0);
+
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_stroke_join", JKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
+ RNA_enum_set(kmi->ptr, "type", GP_STROKE_JOINCOPY);
+
/* copy + paste */
WM_keymap_add_item(keymap, "GPENCIL_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "GPENCIL_OT_paste", VKEY, KM_PRESS, KM_CTRL, 0);
@@ -230,44 +277,37 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_hide", HKEY, KM_PRESS, KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "unselected", true);
+
+ WM_keymap_add_item(keymap, "GPENCIL_OT_selection_opacity_toggle", HKEY, KM_PRESS, KM_CTRL, 0);
/* Isolate Layer */
WM_keymap_add_item(keymap, "GPENCIL_OT_layer_isolate", PADASTERKEY, KM_PRESS, 0, 0);
/* Move to Layer */
WM_keymap_add_item(keymap, "GPENCIL_OT_move_to_layer", MKEY, KM_PRESS, 0, 0);
-
-
-
- /* Brush-Based Editing:
- * EKEY + LMB = Single stroke, draw immediately
- * + Other Modifiers (Ctrl/Shift) = Invert, Smooth, etc.
- *
- * For the modal version, use D+E -> Sculpt
- */
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, 0, EKEY);
- RNA_boolean_set(kmi->ptr, "wait_for_input", false);
-
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, KM_CTRL, EKEY);
- RNA_boolean_set(kmi->ptr, "wait_for_input", false);
- /*RNA_boolean_set(kmi->ptr, "use_invert", true);*/
-
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, KM_SHIFT, EKEY);
- RNA_boolean_set(kmi->ptr, "wait_for_input", false);
- /*RNA_boolean_set(kmi->ptr, "use_smooth", true);*/
-
-
- /* Shift-FKEY = Sculpt Strength */
- kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.brush.strength");
-
- /* Ctrl-FKEY = Sculpt Brush Size */
- kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_CTRL, 0);
- RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.brush.size");
-
-
-
-
+
+ /* Select drawing brush using index */
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_select", ONEKEY, KM_PRESS, 0, 0);
+ RNA_int_set(kmi->ptr, "index", 0);
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_select", TWOKEY, KM_PRESS, 0, 0);
+ RNA_int_set(kmi->ptr, "index", 1);
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_select", THREEKEY, KM_PRESS, 0, 0);
+ RNA_int_set(kmi->ptr, "index", 2);
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_select", FOURKEY, KM_PRESS, 0, 0);
+ RNA_int_set(kmi->ptr, "index", 3);
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_select", FIVEKEY, KM_PRESS, 0, 0);
+ RNA_int_set(kmi->ptr, "index", 4);
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_select", SIXKEY, KM_PRESS, 0, 0);
+ RNA_int_set(kmi->ptr, "index", 5);
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_select", SEVENKEY, KM_PRESS, 0, 0);
+ RNA_int_set(kmi->ptr, "index", 6);
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_select", EIGHTKEY, KM_PRESS, 0, 0);
+ RNA_int_set(kmi->ptr, "index", 7);
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_select", NINEKEY, KM_PRESS, 0, 0);
+ RNA_int_set(kmi->ptr, "index", 8);
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_select", ZEROKEY, KM_PRESS, 0, 0);
+ RNA_int_set(kmi->ptr, "index", 9);
+
/* Transform Tools */
kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", GKEY, KM_PRESS, 0, 0);
@@ -312,7 +352,8 @@ void ED_operatortypes_gpencil(void)
/* Editing (Strokes) ------------ */
WM_operatortype_append(GPENCIL_OT_editmode_toggle);
-
+ WM_operatortype_append(GPENCIL_OT_selection_opacity_toggle);
+
WM_operatortype_append(GPENCIL_OT_select);
WM_operatortype_append(GPENCIL_OT_select_all);
WM_operatortype_append(GPENCIL_OT_select_circle);
@@ -339,6 +380,8 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_snap_to_cursor);
WM_operatortype_append(GPENCIL_OT_snap_cursor_to_selected);
+ WM_operatortype_append(GPENCIL_OT_reproject);
+
WM_operatortype_append(GPENCIL_OT_brush_paint);
/* Editing (Buttons) ------------ */
@@ -356,12 +399,50 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_lock_all);
WM_operatortype_append(GPENCIL_OT_unlock_all);
WM_operatortype_append(GPENCIL_OT_layer_isolate);
-
+ WM_operatortype_append(GPENCIL_OT_layer_merge);
+
WM_operatortype_append(GPENCIL_OT_active_frame_delete);
+ WM_operatortype_append(GPENCIL_OT_active_frames_delete_all);
WM_operatortype_append(GPENCIL_OT_convert);
+ WM_operatortype_append(GPENCIL_OT_stroke_arrange);
+ WM_operatortype_append(GPENCIL_OT_stroke_change_color);
+ WM_operatortype_append(GPENCIL_OT_stroke_lock_color);
+ WM_operatortype_append(GPENCIL_OT_stroke_apply_thickness);
+ WM_operatortype_append(GPENCIL_OT_stroke_cyclical_set);
+ WM_operatortype_append(GPENCIL_OT_stroke_join);
+ WM_operatortype_append(GPENCIL_OT_stroke_flip);
+ WM_operatortype_append(GPENCIL_OT_stroke_subdivide);
+
+ WM_operatortype_append(GPENCIL_OT_palette_add);
+ WM_operatortype_append(GPENCIL_OT_palette_remove);
+ WM_operatortype_append(GPENCIL_OT_palette_change);
+ WM_operatortype_append(GPENCIL_OT_palette_lock_layer);
+ WM_operatortype_append(GPENCIL_OT_palettecolor_add);
+ WM_operatortype_append(GPENCIL_OT_palettecolor_remove);
+ WM_operatortype_append(GPENCIL_OT_palettecolor_isolate);
+ WM_operatortype_append(GPENCIL_OT_palettecolor_hide);
+ WM_operatortype_append(GPENCIL_OT_palettecolor_reveal);
+ WM_operatortype_append(GPENCIL_OT_palettecolor_lock_all);
+ WM_operatortype_append(GPENCIL_OT_palettecolor_unlock_all);
+ WM_operatortype_append(GPENCIL_OT_palettecolor_move);
+ WM_operatortype_append(GPENCIL_OT_palettecolor_select);
+ WM_operatortype_append(GPENCIL_OT_palettecolor_copy);
+
+ WM_operatortype_append(GPENCIL_OT_brush_add);
+ WM_operatortype_append(GPENCIL_OT_brush_remove);
+ WM_operatortype_append(GPENCIL_OT_brush_change);
+ WM_operatortype_append(GPENCIL_OT_brush_move);
+ WM_operatortype_append(GPENCIL_OT_brush_presets_create);
+ WM_operatortype_append(GPENCIL_OT_brush_copy);
+ WM_operatortype_append(GPENCIL_OT_brush_select);
+
/* Editing (Time) --------------- */
+
+ /* Interpolation */
+ WM_operatortype_append(GPENCIL_OT_interpolate);
+ WM_operatortype_append(GPENCIL_OT_interpolate_sequence);
}
void ED_operatormacros_gpencil(void)
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index fba2f30e715..c23bfb1ff60 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -18,7 +18,7 @@
* The Original Code is Copyright (C) 2008, Blender Foundation, Joshua Leung
* This is a new part of Blender
*
- * Contributor(s): Joshua Leung
+ * Contributor(s): Joshua Leung, Antonio Vazquez
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -39,21 +39,27 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLI_rand.h"
+#include "BLI_math_geom.h"
#include "BLT_translation.h"
#include "PIL_time.h"
+#include "BKE_main.h"
+#include "BKE_paint.h"
#include "BKE_gpencil.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_report.h"
#include "BKE_screen.h"
#include "BKE_tracking.h"
+#include "BKE_colortools.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_brush_types.h"
#include "DNA_windowmanager_types.h"
#include "UI_view2d.h"
@@ -97,7 +103,8 @@ typedef enum eGP_StrokeAdd_Result {
typedef enum eGPencil_PaintFlags {
GP_PAINTFLAG_FIRSTRUN = (1 << 0), /* operator just started */
GP_PAINTFLAG_STROKEADDED = (1 << 1),
- GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2)
+ GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2),
+ GP_PAINTFLAG_SELECTMASK = (1 << 3),
} eGPencil_PaintFlags;
@@ -150,13 +157,15 @@ typedef struct tGPsdata {
float custom_color[4]; /* custom color - hack for enforcing a particular color for track/mask editing */
void *erasercursor; /* radial cursor data for drawing eraser */
+
+ bGPDpalettecolor *palettecolor; /* current palette color */
+ bGPDbrush *brush; /* current drawing brush */
+ short straight[2]; /* 1: line horizontal, 2: line vertical, other: not defined, second element position */
+ int lock_axis; /* lock drawing to one axis */
} tGPsdata;
/* ------ */
-/* maximum sizes of gp-session buffer */
-#define GP_STROKE_BUFFER_MAX 5000
-
/* Macros for accessing sensitivity thresholds... */
/* minimum number of pixels mouse should move before new point created */
#define MIN_MANHATTEN_PX (U.gp_manhattendist)
@@ -271,6 +280,64 @@ static bool gp_stroke_filtermval(tGPsdata *p, const int mval[2], int pmval[2])
return false;
}
+/* reproject the points of the stroke to a plane locked to axis to avoid stroke offset */
+static void gp_project_points_to_plane(RegionView3D *rv3d, bGPDstroke *gps, const float origin[3], const int axis)
+{
+ float plane_normal[3];
+ float vn[3];
+
+ float ray[3];
+ float rpoint[3];
+
+ /* normal vector for a plane locked to axis */
+ zero_v3(plane_normal);
+ plane_normal[axis] = 1.0f;
+
+ /* Reproject the points in the plane */
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+
+ /* get a vector from the point with the current view direction of the viewport */
+ ED_view3d_global_to_vector(rv3d, &pt->x, vn);
+
+ /* calculate line extrem point to create a ray that cross the plane */
+ mul_v3_fl(vn, -50.0f);
+ add_v3_v3v3(ray, &pt->x, vn);
+
+ /* if the line never intersect, the point is not changed */
+ if (isect_line_plane_v3(rpoint, &pt->x, ray, origin, plane_normal)) {
+ copy_v3_v3(&pt->x, rpoint);
+ }
+ }
+}
+
+/* reproject stroke to plane locked to axis in 3d cursor location */
+static void gp_reproject_toplane(tGPsdata *p, bGPDstroke *gps)
+{
+ bGPdata *gpd = p->gpd;
+ float origin[3];
+ float cursor[3];
+ RegionView3D *rv3d = p->ar->regiondata;
+
+ /* verify the stroke mode is CURSOR 3d space mode */
+ if ((gpd->sbuffer_sflag & GP_STROKE_3DSPACE) == 0) {
+ return;
+ }
+ if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) {
+ return;
+ }
+ if ((*p->align_flag & GP_PROJECT_DEPTH_VIEW) || (*p->align_flag & GP_PROJECT_DEPTH_STROKE)) {
+ return;
+ }
+
+ /* get 3d cursor and set origin for locked axis only. Uses axis-1 because the enum for XYZ start with 1 */
+ gp_get_3d_reference(p, cursor);
+ zero_v3(origin);
+ origin[p->lock_axis - 1] = cursor[p->lock_axis - 1];
+
+ gp_project_points_to_plane(rv3d, gps, origin, p->lock_axis - 1);
+}
+
/* convert screen-coordinates to buffer-coordinates */
/* XXX this method needs a total overhaul! */
static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3], float *depth)
@@ -332,10 +399,90 @@ static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3]
}
}
+/* apply jitter to stroke */
+static void gp_brush_jitter(bGPdata *gpd, bGPDbrush *brush, tGPspoint *pt, const int mval[2], int r_mval[2])
+{
+ float pressure = pt->pressure;
+ float tmp_pressure = pt->pressure;
+ if (brush->draw_jitter > 0.0f) {
+ float curvef = curvemapping_evaluateF(brush->cur_jitter, 0, pressure);
+ tmp_pressure = curvef * brush->draw_sensitivity;
+ }
+ const float exfactor = (brush->draw_jitter + 2.0f) * (brush->draw_jitter + 2.0f); /* exponential value */
+ const float fac = BLI_frand() * exfactor * tmp_pressure;
+ /* Jitter is applied perpendicular to the mouse movement vector (2D space) */
+ float mvec[2], svec[2];
+ /* mouse movement in ints -> floats */
+ if (gpd->sbuffer_size > 1) {
+ mvec[0] = (float)(mval[0] - (pt - 1)->x);
+ mvec[1] = (float)(mval[1] - (pt - 1)->y);
+ normalize_v2(mvec);
+ }
+ else {
+ mvec[0] = 0.0f;
+ mvec[1] = 0.0f;
+ }
+ /* rotate mvec by 90 degrees... */
+ svec[0] = -mvec[1];
+ svec[1] = mvec[0];
+ /* scale the displacement by the random, and apply */
+ if (BLI_frand() > 0.5f) {
+ mul_v2_fl(svec, -fac);
+ }
+ else {
+ mul_v2_fl(svec, fac);
+ }
+
+ r_mval[0] = mval[0] + svec[0];
+ r_mval[1] = mval[1] + svec[1];
+
+}
+
+/* apply pressure change depending of the angle of the stroke to simulate a pen with shape */
+static void gp_brush_angle(bGPdata *gpd, bGPDbrush *brush, tGPspoint *pt, const int mval[2])
+{
+ float mvec[2];
+ float sen = brush->draw_angle_factor; /* sensitivity */;
+ float fac;
+ float mpressure;
+
+ float angle = brush->draw_angle; /* default angle of brush in radians */;
+ float v0[2] = { cos(angle), sin(angle) }; /* angle vector of the brush with full thickness */
+
+ /* Apply to first point (only if there are 2 points because before no data to do it ) */
+ if (gpd->sbuffer_size == 1) {
+ mvec[0] = (float)(mval[0] - (pt - 1)->x);
+ mvec[1] = (float)(mval[1] - (pt - 1)->y);
+ normalize_v2(mvec);
+
+ /* uses > 1.0f to get a smooth transition in first point */
+ fac = 1.4f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */
+ (pt - 1)->pressure = (pt - 1)->pressure - (sen * fac);
+
+ CLAMP((pt - 1)->pressure, GPENCIL_ALPHA_OPACITY_THRESH, 1.0f);
+ }
+
+ /* apply from second point */
+ if (gpd->sbuffer_size >= 1) {
+ mvec[0] = (float)(mval[0] - (pt - 1)->x);
+ mvec[1] = (float)(mval[1] - (pt - 1)->y);
+ normalize_v2(mvec);
+
+ fac = 1.0f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */
+ /* interpolate with previous point for smoother transitions */
+ mpressure = interpf(pt->pressure - (sen * fac), (pt - 1)->pressure, 0.3f);
+ pt->pressure = mpressure;
+
+ CLAMP(pt->pressure, GPENCIL_ALPHA_OPACITY_THRESH, 1.0f);
+ }
+
+}
+
/* add current stroke-point to buffer (returns whether point was successfully added) */
static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure, double curtime)
{
bGPdata *gpd = p->gpd;
+ bGPDbrush *brush = p->brush;
tGPspoint *pt;
/* check painting mode */
@@ -348,6 +495,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
/* store settings */
copy_v2_v2_int(&pt->x, mval);
pt->pressure = 1.0f; /* T44932 - Pressure vals are unreliable, so ignore for now */
+ pt->strength = 1.0f;
pt->time = (float)(curtime - p->inittime);
/* increment buffer size */
@@ -362,6 +510,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
/* store settings */
copy_v2_v2_int(&pt->x, mval);
pt->pressure = 1.0f; /* T44932 - Pressure vals are unreliable, so ignore for now */
+ pt->strength = 1.0f;
pt->time = (float)(curtime - p->inittime);
/* now the buffer has 2 points (and shouldn't be allowed to get any larger) */
@@ -380,8 +529,65 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
pt = ((tGPspoint *)(gpd->sbuffer) + gpd->sbuffer_size);
/* store settings */
- copy_v2_v2_int(&pt->x, mval);
- pt->pressure = pressure;
+ /* pressure */
+ if (brush->flag & GP_BRUSH_USE_PRESSURE) {
+ float curvef = curvemapping_evaluateF(brush->cur_sensitivity, 0, pressure);
+ pt->pressure = curvef * brush->draw_sensitivity;
+ }
+ else {
+ pt->pressure = 1.0f;
+ }
+ /* Apply jitter to position */
+ if (brush->draw_jitter > 0.0f) {
+ int r_mval[2];
+ gp_brush_jitter(gpd, brush, pt, mval, r_mval);
+ copy_v2_v2_int(&pt->x, r_mval);
+ }
+ else {
+ copy_v2_v2_int(&pt->x, mval);
+ }
+ /* apply randomness to pressure */
+ if ((brush->draw_random_press > 0.0f) && (brush->flag & GP_BRUSH_USE_RANDOM_PRESSURE)) {
+ float curvef = curvemapping_evaluateF(brush->cur_sensitivity, 0, pressure);
+ float tmp_pressure = curvef * brush->draw_sensitivity;
+ if (BLI_frand() > 0.5f) {
+ pt->pressure -= tmp_pressure * brush->draw_random_press * BLI_frand();
+ }
+ else {
+ pt->pressure += tmp_pressure * brush->draw_random_press * BLI_frand();
+ }
+ CLAMP(pt->pressure, GPENCIL_STRENGTH_MIN, 1.0f);
+ }
+
+ /* apply angle of stroke to brush size */
+ if (brush->draw_angle_factor > 0.0f) {
+ gp_brush_angle(gpd, brush, pt, mval);
+ }
+
+ /* color strength */
+ if (brush->flag & GP_BRUSH_USE_STENGTH_PRESSURE) {
+ float curvef = curvemapping_evaluateF(brush->cur_strength, 0, pressure);
+ float tmp_pressure = curvef * brush->draw_sensitivity;
+
+ pt->strength = tmp_pressure * brush->draw_strength;
+ }
+ else {
+ pt->strength = brush->draw_strength;
+ }
+ CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+
+ /* apply randomness to color strength */
+ if ((brush->draw_random_press > 0.0f) && (brush->flag & GP_BRUSH_USE_RANDOM_STRENGTH)) {
+ if (BLI_frand() > 0.5f) {
+ pt->strength -= pt->strength * brush->draw_random_press * BLI_frand();
+ }
+ else {
+ pt->strength += pt->strength * brush->draw_random_press * BLI_frand();
+ }
+ CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ }
+
+ /* point time */
pt->time = (float)(curtime - p->inittime);
/* increment counters */
@@ -394,12 +600,15 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
return GP_STROKEADD_NORMAL;
}
else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
+
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
/* get pointer to destination point */
pt = (tGPspoint *)(gpd->sbuffer);
/* store settings */
copy_v2_v2_int(&pt->x, mval);
pt->pressure = 1.0f; /* T44932 - Pressure vals are unreliable, so ignore for now */
+ pt->strength = 1.0f;
pt->time = (float)(curtime - p->inittime);
/* if there's stroke for this poly line session add (or replace last) point
@@ -432,10 +641,20 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
/* convert screen-coordinates to appropriate coordinates (and store them) */
gp_stroke_convertcoords(p, &pt->x, &pts->x, NULL);
-
+ /* if axis locked, reproject to plane locked (only in 3d space) */
+ if (p->lock_axis > GP_LOCKAXIS_NONE) {
+ gp_reproject_toplane(p, gps);
+ }
+ /* if parented change position relative to parent object */
+ if (gpl->parent != NULL) {
+ gp_apply_parent_point(gpl, pts);
+ }
/* copy pressure and time */
pts->pressure = pt->pressure;
+ pts->strength = pt->strength;
pts->time = pt->time;
+ /* force fill recalc */
+ gps->flag |= GP_STROKE_RECALC_CACHES;
}
/* increment counters */
@@ -524,7 +743,6 @@ static void gp_stroke_simplify(tGPsdata *p)
MEM_freeN(old_points);
}
-
/* make a new stroke from the buffer data */
static void gp_stroke_newfrombuffer(tGPsdata *p)
{
@@ -533,6 +751,8 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
bGPDstroke *gps;
bGPDspoint *pt;
tGPspoint *ptc;
+ bGPDbrush *brush = p->brush;
+ ToolSettings *ts = p->scene->toolsettings;
int i, totelem;
/* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */
@@ -568,7 +788,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* copy appropriate settings for stroke */
gps->totpoints = totelem;
- gps->thickness = p->gpl->thickness;
+ gps->thickness = brush->thickness;
gps->flag = gpd->sbuffer_sflag;
gps->inittime = p->inittime;
@@ -576,7 +796,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
gps->flag |= GP_STROKE_RECALC_CACHES;
/* allocate enough memory for a continuous array for storage points */
- int sublevel = gpl->sublevel;
+ int sublevel = brush->sublevel;
int new_totpoints = gps->totpoints;
for (i = 0; i < sublevel; i++) {
@@ -599,9 +819,18 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* convert screen-coordinates to appropriate coordinates (and store them) */
gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
-
+ /* if axis locked, reproject to plane locked (only in 3d space) */
+ if (p->lock_axis > GP_LOCKAXIS_NONE) {
+ gp_reproject_toplane(p, gps);
+ }
+ /* if parented change position relative to parent object */
+ if (gpl->parent != NULL) {
+ gp_apply_parent_point(gpl, pt);
+ }
/* copy pressure and time */
pt->pressure = ptc->pressure;
+ pt->strength = ptc->strength;
+ CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
pt->time = ptc->time;
pt++;
@@ -613,9 +842,19 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* convert screen-coordinates to appropriate coordinates (and store them) */
gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
-
+ /* if axis locked, reproject to plane locked (only in 3d space) */
+ if (p->lock_axis > GP_LOCKAXIS_NONE) {
+ gp_reproject_toplane(p, gps);
+ }
+ /* if parented change position relative to parent object */
+ if (gpl->parent != NULL) {
+ gp_apply_parent_point(gpl, pt);
+ }
+
/* copy pressure and time */
pt->pressure = ptc->pressure;
+ pt->strength = ptc->strength;
+ CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
pt->time = ptc->time;
}
}
@@ -625,37 +864,46 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* convert screen-coordinates to appropriate coordinates (and store them) */
gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
-
+ /* if axis locked, reproject to plane locked (only in 3d space) */
+ if (p->lock_axis > GP_LOCKAXIS_NONE) {
+ gp_reproject_toplane(p, gps);
+ }
+ /* if parented change position relative to parent object */
+ if (gpl->parent != NULL) {
+ gp_apply_parent_point(gpl, pt);
+ }
/* copy pressure and time */
pt->pressure = ptc->pressure;
+ pt->strength = ptc->strength;
+ CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
pt->time = ptc->time;
}
else {
float *depth_arr = NULL;
-
+
/* get an array of depths, far depths are blended */
if (gpencil_project_check(p)) {
- int mval[2], mval_prev[2] = {0};
+ int mval[2], mval_prev[2] = { 0 };
int interp_depth = 0;
int found_depth = 0;
-
+
depth_arr = MEM_mallocN(sizeof(float) * gpd->sbuffer_size, "depth_points");
-
+
for (i = 0, ptc = gpd->sbuffer; i < gpd->sbuffer_size; i++, ptc++, pt++) {
copy_v2_v2_int(mval, &ptc->x);
-
+
if ((ED_view3d_autodist_depth(p->ar, mval, depth_margin, depth_arr + i) == 0) &&
- (i && (ED_view3d_autodist_depth_seg(p->ar, mval, mval_prev, depth_margin + 1, depth_arr + i) == 0)))
+ (i && (ED_view3d_autodist_depth_seg(p->ar, mval, mval_prev, depth_margin + 1, depth_arr + i) == 0)))
{
interp_depth = true;
}
else {
found_depth = true;
}
-
+
copy_v2_v2_int(mval_prev, mval);
}
-
+
if (found_depth == false) {
/* eeh... not much we can do.. :/, ignore depth in this case, use the 3D cursor */
for (i = gpd->sbuffer_size - 1; i >= 0; i--)
@@ -666,77 +914,105 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* remove all info between the valid endpoints */
int first_valid = 0;
int last_valid = 0;
-
+
for (i = 0; i < gpd->sbuffer_size; i++) {
if (depth_arr[i] != FLT_MAX)
break;
}
first_valid = i;
-
+
for (i = gpd->sbuffer_size - 1; i >= 0; i--) {
if (depth_arr[i] != FLT_MAX)
break;
}
last_valid = i;
-
+
/* invalidate non-endpoints, so only blend between first and last */
for (i = first_valid + 1; i < last_valid; i++)
depth_arr[i] = FLT_MAX;
-
+
interp_depth = true;
}
-
+
if (interp_depth) {
interp_sparse_array(depth_arr, gpd->sbuffer_size, FLT_MAX);
}
}
}
-
-
+
+
pt = gps->points;
-
+
/* convert all points (normal behavior) */
for (i = 0, ptc = gpd->sbuffer; i < gpd->sbuffer_size && ptc; i++, ptc++, pt++) {
/* convert screen-coordinates to appropriate coordinates (and store them) */
gp_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr + i : NULL);
-
+
/* copy pressure and time */
pt->pressure = ptc->pressure;
+ pt->strength = ptc->strength;
+ CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
pt->time = ptc->time;
}
-
+
/* subdivide the stroke */
if (sublevel > 0) {
int totpoints = gps->totpoints;
for (i = 0; i < sublevel; i++) {
/* we're adding one new point between each pair of verts on each step */
totpoints += totpoints - 1;
-
+
gp_subdivide_stroke(gps, totpoints);
}
}
-
- /* smooth stroke after subdiv - only if there's something to do
- * for each iteration, the factor is reduced to get a better smoothing without changing too much
+ /* apply randomness to stroke */
+ if (brush->draw_random_sub > 0.0f) {
+ gp_randomize_stroke(gps, brush);
+ }
+
+ /* smooth stroke after subdiv - only if there's something to do
+ * for each iteration, the factor is reduced to get a better smoothing without changing too much
* the original stroke
*/
- if (gpl->draw_smoothfac > 0.0f) {
+ if (brush->draw_smoothfac > 0.0f) {
float reduce = 0.0f;
- for (int r = 0; r < gpl->draw_smoothlvl; ++r) {
+ for (int r = 0; r < brush->draw_smoothlvl; ++r) {
for (i = 0; i < gps->totpoints; i++) {
/* NOTE: No pressure smoothing, or else we get annoying thickness changes while drawing... */
- gp_smooth_stroke(gps, i, gpl->draw_smoothfac - reduce, false);
+ gp_smooth_stroke(gps, i, brush->draw_smoothfac - reduce, false);
}
reduce += 0.25f; // reduce the factor
}
}
-
+
+ /* if axis locked, reproject to plane locked (only in 3d space) */
+ if (p->lock_axis > GP_LOCKAXIS_NONE) {
+ gp_reproject_toplane(p, gps);
+ }
+ /* if parented change position relative to parent object */
+ if (gpl->parent != NULL) {
+ gp_apply_parent(gpl, gps);
+ }
+
if (depth_arr)
MEM_freeN(depth_arr);
}
+ /* Save palette color */
+ bGPDpalette *palette = BKE_gpencil_palette_getactive(p->gpd);
+ bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette);
+ gps->palcolor = palcolor;
+ BLI_strncpy(gps->colorname, palcolor->info, sizeof(gps->colorname));
- /* add stroke to frame */
- BLI_addtail(&p->gpf->strokes, gps);
+ /* add stroke to frame, usually on tail of the listbase, but if on back is enabled the stroke is added on listbase head
+ * because the drawing order is inverse and the head stroke is the first to draw. This is very useful for artist
+ * when drawing the background
+ */
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode != GP_PAINTMODE_DRAW_POLY)) {
+ BLI_addhead(&p->gpf->strokes, gps);
+ }
+ else {
+ BLI_addtail(&p->gpf->strokes, gps);
+ }
gp_stroke_added_enable(p);
}
@@ -760,12 +1036,21 @@ static bool gp_stroke_eraser_is_occluded(tGPsdata *p, const bGPDspoint *pt, cons
(p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH))
{
RegionView3D *rv3d = p->ar->regiondata;
+ bGPDlayer *gpl = p->gpl;
+
const int mval[2] = {x, y};
float mval_3d[3];
-
+ float fpt[3];
+
+ float diff_mat[4][4];
+ /* calculate difference matrix if parent object */
+ ED_gpencil_parent_location(gpl, diff_mat);
+
if (ED_view3d_autodist_simple(p->ar, mval, mval_3d, 0, NULL)) {
const float depth_mval = view3d_point_depth(rv3d, mval_3d);
- const float depth_pt = view3d_point_depth(rv3d, &pt->x);
+
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ const float depth_pt = view3d_point_depth(rv3d, fpt);
if (depth_pt > depth_mval) {
return true;
@@ -803,7 +1088,13 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
int pc1[2] = {0};
int pc2[2] = {0};
int i;
-
+ float diff_mat[4][4];
+
+ /* calculate difference matrix if parent object */
+ if (gpl->parent != NULL) {
+ ED_gpencil_parent_location(gpl, diff_mat);
+ }
+
if (gps->totpoints == 0) {
/* just free stroke */
if (gps->points)
@@ -813,18 +1104,27 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
BLI_freelinkN(&gpf->strokes, gps);
}
else if (gps->totpoints == 1) {
- gp_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]);
-
- /* do boundbox check first */
- if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
- /* only check if point is inside */
- if (len_v2v2_int(mval, pc1) <= radius) {
- /* free stroke */
- // XXX: pressure sensitive eraser should apply here too?
- MEM_freeN(gps->points);
- if (gps->triangles)
- MEM_freeN(gps->triangles);
- BLI_freelinkN(&gpf->strokes, gps);
+ /* only process if it hasn't been masked out... */
+ if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) {
+ if (gpl->parent == NULL) {
+ gp_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]);
+ }
+ else {
+ bGPDspoint pt_temp;
+ gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
+ gp_point_to_xy(&p->gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
+ }
+ /* do boundbox check first */
+ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
+ /* only check if point is inside */
+ if (len_v2v2_int(mval, pc1) <= radius) {
+ /* free stroke */
+ // XXX: pressure sensitive eraser should apply here too?
+ MEM_freeN(gps->points);
+ if (gps->triangles)
+ MEM_freeN(gps->triangles);
+ BLI_freelinkN(&gpf->strokes, gps);
+ }
}
}
}
@@ -832,7 +1132,7 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
/* Pressure threshold at which stroke should be culled: Calculated as pressure value
* below which we would have invisible strokes
*/
- const float cull_thresh = (gpl->thickness) ? 1.0f / ((float)gpl->thickness) : 1.0f;
+ const float cull_thresh = (gps->thickness) ? 1.0f / ((float)gps->thickness) : 1.0f;
/* Amount to decrease the pressure of each point with each stroke */
// TODO: Fetch from toolsettings, or compute based on thickness instead?
@@ -861,10 +1161,24 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
/* get points to work with */
pt1 = gps->points + i;
pt2 = gps->points + i + 1;
+
+ /* only process if it hasn't been masked out... */
+ if ((p->flags & GP_PAINTFLAG_SELECTMASK) && !(gps->points->flag & GP_SPOINT_SELECT))
+ continue;
- gp_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]);
- gp_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]);
-
+ if (gpl->parent == NULL) {
+ gp_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]);
+ gp_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]);
+ }
+ else {
+ bGPDspoint npt;
+ gp_point_to_parent_space(pt1, diff_mat, &npt);
+ gp_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]);
+
+ gp_point_to_parent_space(pt2, diff_mat, &npt);
+ gp_point_to_xy(&p->gsc, gps, &npt, &pc2[0], &pc2[1]);
+ }
+
/* Check that point segment of the boundbox of the eraser stroke */
if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1])))
@@ -946,7 +1260,10 @@ static void gp_stroke_doeraser(tGPsdata *p)
/* loop over strokes, checking segments for intersections */
for (gps = gpf->strokes.first; gps; gps = gpn) {
gpn = gps->next;
-
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
+ continue;
+ }
/* Not all strokes in the datablock may be valid in the current editor/context
* (e.g. 2D space strokes in the 3D view, if the same datablock is shared)
*/
@@ -985,6 +1302,78 @@ static void gp_session_validatebuffer(tGPsdata *p)
p->inittime = 0.0;
}
+/* create a new palette color */
+static bGPDpalettecolor *gp_create_new_color(bGPDpalette *palette)
+{
+ bGPDpalettecolor *palcolor;
+
+ palcolor = BKE_gpencil_palettecolor_addnew(palette, DATA_("Color"), true);
+
+ return palcolor;
+}
+
+/* initialize a drawing brush */
+static void gp_init_drawing_brush(ToolSettings *ts, tGPsdata *p)
+{
+ bGPDbrush *brush;
+
+ /* if not exist, create a new one */
+ if (BLI_listbase_is_empty(&ts->gp_brushes)) {
+ /* create new brushes */
+ BKE_gpencil_brush_init_presets(ts);
+ brush = BKE_gpencil_brush_getactive(ts);
+ }
+ else {
+ /* Use the current */
+ brush = BKE_gpencil_brush_getactive(ts);
+ }
+ /* be sure curves are initializated */
+ curvemapping_initialize(brush->cur_sensitivity);
+ curvemapping_initialize(brush->cur_strength);
+ curvemapping_initialize(brush->cur_jitter);
+
+ /* asign to temp tGPsdata */
+ p->brush = brush;
+}
+
+
+/* initialize a paint palette brush and a default color if not exist */
+static void gp_init_palette(tGPsdata *p)
+{
+ bGPdata *gpd;
+ bGPDpalette *palette;
+ bGPDpalettecolor *palcolor;
+
+ gpd = p->gpd;
+
+ /* if not exist, create a new palette */
+ if (BLI_listbase_is_empty(&gpd->palettes)) {
+ /* create new palette */
+ palette = BKE_gpencil_palette_addnew(gpd, DATA_("GP_Palette"), true);
+ /* now create a default color */
+ palcolor = gp_create_new_color(palette);
+ }
+ else {
+ /* Use the current palette and color */
+ palette = BKE_gpencil_palette_getactive(gpd);
+ /* the palette needs one color */
+ if (BLI_listbase_is_empty(&palette->colors)) {
+ palcolor = gp_create_new_color(palette);
+ }
+ else {
+ palcolor = BKE_gpencil_palettecolor_getactive(palette);
+ }
+ /* in some situations can be null, so use first */
+ if (palcolor == NULL) {
+ BKE_gpencil_palettecolor_setactive(palette, palette->colors.first);
+ palcolor = palette->colors.first;
+ }
+ }
+
+ /* asign to temp tGPsdata */
+ p->palettecolor = palcolor;
+}
+
/* (re)init new painting data */
static bool gp_session_initdata(bContext *C, tGPsdata *p)
{
@@ -1136,7 +1525,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
else {
/* if no existing GPencil block exists, add one */
if (*gpd_ptr == NULL)
- *gpd_ptr = gpencil_data_addnew("GPencil");
+ *gpd_ptr = BKE_gpencil_data_addnew("GPencil");
p->gpd = *gpd_ptr;
}
@@ -1149,7 +1538,18 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
/* clear out buffer (stored in gp-data), in case something contaminated it */
gp_session_validatebuffer(p);
-
+ /* set brush and create a new one if null */
+ gp_init_drawing_brush(ts, p);
+ /* set palette info and create a new one if null */
+ gp_init_palette(p);
+ /* set palette colors */
+ bGPDpalettecolor *palcolor = p->palettecolor;
+ bGPdata *pdata = p->gpd;
+ copy_v4_v4(pdata->scolor, palcolor->color);
+ pdata->sflag = palcolor->flag;
+ /* lock axis */
+ p->lock_axis = ts->gp_sculpt.lock_axis;
+
return 1;
}
@@ -1168,7 +1568,7 @@ static tGPsdata *gp_session_initpaint(bContext *C)
* erase size won't get lost
*/
p->radius = U.gp_eraser;
-
+
/* return context data for running paint operator */
return p;
}
@@ -1199,11 +1599,12 @@ static void gp_session_cleanup(tGPsdata *p)
static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
{
Scene *scene = p->scene;
+ ToolSettings *ts = scene->toolsettings;
/* get active layer (or add a new one if non-existent) */
- p->gpl = gpencil_layer_getactive(p->gpd);
+ p->gpl = BKE_gpencil_layer_getactive(p->gpd);
if (p->gpl == NULL) {
- p->gpl = gpencil_layer_addnew(p->gpd, "GP_Layer", true);
+ p->gpl = BKE_gpencil_layer_addnew(p->gpd, "GP_Layer", true);
if (p->custom_color[3])
copy_v3_v3(p->gpl->color, p->custom_color);
@@ -1231,7 +1632,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
/* Add a new frame if needed (and based off the active frame,
* as we need some existing strokes to erase)
*/
- gpl->actframe = gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_COPY);
+ gpl->actframe = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_COPY);
/* XXX: we omit GP_FRAME_PAINT here for now,
* as it is only really useful for doing
@@ -1242,6 +1643,15 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
/* Ensure this gets set... */
p->gpf = p->gpl->actframe;
+ /* Restrict eraser to only affecting selected strokes, if the "selection mask" is on
+ * (though this is only available in editmode)
+ */
+ if (p->gpd->flag & GP_DATA_STROKE_EDITMODE) {
+ if (ts->gp_sculpt.flag & GP_BRUSHEDIT_FLAG_SELECT_MASK) {
+ p->flags |= GP_PAINTFLAG_SELECTMASK;
+ }
+ }
+
if (p->gpf == NULL) {
p->status = GP_STATUS_ERROR;
//if (G.debug & G_DEBUG)
@@ -1251,7 +1661,6 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
}
else {
/* Drawing Modes - Add a new frame if needed on the active layer */
- ToolSettings *ts = p->scene->toolsettings;
short add_frame_mode;
if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST)
@@ -1259,7 +1668,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
else
add_frame_mode = GP_GETFRAME_ADD_NEW;
- p->gpf = gpencil_layer_getframe(p->gpl, CFRA, add_frame_mode);
+ p->gpf = BKE_gpencil_layer_getframe(p->gpl, CFRA, add_frame_mode);
if (p->gpf == NULL) {
p->status = GP_STATUS_ERROR;
@@ -1477,7 +1886,6 @@ static bool gpencil_is_tablet_eraser_active(const wmEvent *event)
/* ------------------------------- */
-
static void gpencil_draw_exit(bContext *C, wmOperator *op)
{
tGPsdata *p = op->customdata;
@@ -1495,7 +1903,7 @@ static void gpencil_draw_exit(bContext *C, wmOperator *op)
/* turn off radial brush cursor */
gpencil_draw_toggle_eraser_cursor(C, p, false);
}
-
+
/* always store the new eraser size to be used again next time
* NOTE: Do this even when not in eraser mode, as eraser may
* have been toggled at some point.
@@ -1582,7 +1990,7 @@ static void gpencil_draw_status_indicators(tGPsdata *p)
break;
case GP_PAINTMODE_DRAW:
ED_area_headerprint(p->sa, IFACE_("Grease Pencil Freehand Session: Hold and drag LMB to draw | "
- "ESC/Enter to end (or click outside this area)"));
+ "E/ESC/Enter to end (or click outside this area)"));
break;
case GP_PAINTMODE_DRAW_POLY:
ED_area_headerprint(p->sa, IFACE_("Grease Pencil Poly Session: LMB click to place next stroke vertex | "
@@ -1673,6 +2081,31 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event)
*/
p->mval[0] = event->mval[0] + 1;
p->mval[1] = event->mval[1] + 1;
+
+ /* verify key status for straight lines */
+ if ((event->ctrl > 0) || (event->alt > 0)) {
+ if (p->straight[0] == 0) {
+ int dx = abs(p->mval[0] - p->mvalo[0]);
+ int dy = abs(p->mval[1] - p->mvalo[1]);
+ if ((dx > 0) || (dy > 0)) {
+ /* check mouse direction to replace the other coordinate with previous values */
+ if (dx >= dy) {
+ /* horizontal */
+ p->straight[0] = 1;
+ p->straight[1] = p->mval[1]; /* save y */
+ }
+ else {
+ /* vertical */
+ p->straight[0] = 2;
+ p->straight[1] = p->mval[0]; /* save x */
+ }
+ }
+ }
+ }
+ else {
+ p->straight[0] = 0;
+ }
+
p->curtime = PIL_check_seconds_timer();
/* handle pressure sensitivity (which is supplied by tablets) */
@@ -1707,7 +2140,9 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event)
p->mvalo[1] = p->mval[1];
p->opressure = p->pressure;
p->inittime = p->ocurtime = p->curtime;
-
+ p->straight[0] = 0;
+ p->straight[1] = 0;
+
/* special exception here for too high pressure values on first touch in
* windows for some tablets, then we just skip first touch...
*/
@@ -1715,6 +2150,18 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event)
return;
}
+ /* check if alt key is pressed and limit to straight lines */
+ if (p->straight[0] != 0) {
+ if (p->straight[0] == 1) {
+ /* horizontal */
+ p->mval[1] = p->straight[1]; /* replace y */
+ }
+ else {
+ /* vertical */
+ p->mval[0] = p->straight[1]; /* replace x */
+ }
+ }
+
/* fill in stroke data (not actually used directly by gpencil_draw_apply) */
RNA_collection_add(op->ptr, "stroke", &itemptr);
@@ -1837,21 +2284,21 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
if (p->paintmode == GP_PAINTMODE_ERASER) {
gpencil_draw_toggle_eraser_cursor(C, p, true);
}
-
/* set cursor
* NOTE: This may change later (i.e. intentionally via brush toggle,
* or unintentionally if the user scrolls outside the area)...
*/
gpencil_draw_cursor_set(p);
-
+
/* only start drawing immediately if we're allowed to do so... */
if (RNA_boolean_get(op->ptr, "wait_for_input") == false) {
/* hotkey invoked - start drawing */
/* printf("\tGP - set first spot\n"); */
p->status = GP_STATUS_PAINTING;
-
+
/* handle the initial drawing - i.e. for just doing a simple dot */
gpencil_draw_apply_event(op, event);
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
}
else {
/* toolbar invoked - don't start drawing yet... */
@@ -1919,10 +2366,33 @@ static void gpencil_stroke_end(wmOperator *op)
p->gpf = NULL;
}
+/* Move last stroke in the listbase to the head to be drawn below all previous strokes in the layer */
+static void gpencil_move_last_stroke_to_back(bContext *C)
+{
+ /* move last stroke (the polygon) to head of the listbase stroke to draw on back of all previous strokes */
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, gpl, gpl->actframe)) {
+ return;
+ }
+
+ bGPDframe *gpf = gpl->actframe;
+ bGPDstroke *gps = gpf->strokes.last;
+ if (ELEM(NULL, gps)) {
+ return;
+ }
+
+ BLI_remlink(&gpf->strokes, gps);
+ BLI_insertlinkbefore(&gpf->strokes, gpf->strokes.first, gps);
+}
+
/* events handling during interactive drawing part of operator */
static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
tGPsdata *p = op->customdata;
+ ToolSettings *ts = CTX_data_tool_settings(C);
int estate = OPERATOR_PASS_THROUGH; /* default exit state - pass through to support MMB view nav, etc. */
/* if (event->type == NDOF_MOTION)
@@ -1958,6 +2428,10 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
* is essential for ensuring that they can quickly return to that view
*/
}
+ else if ((ELEM(event->type, DKEY)) && (event->val == KM_RELEASE)) {
+ /* enable continuous if release D key in mid drawing */
+ p->scene->toolsettings->gpencil_flags |= GP_TOOL_FLAG_PAINTSESSIONS_ON;
+ }
else {
estate = OPERATOR_RUNNING_MODAL;
}
@@ -1968,9 +2442,17 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* exit painting mode (and/or end current stroke)
* NOTE: cannot do RIGHTMOUSE (as is standard for canceling) as that would break polyline [#32647]
*/
- if (ELEM(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY)) {
+ if (ELEM(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY, EKEY)) {
/* exit() ends the current stroke before cleaning up */
/* printf("\t\tGP - end of paint op + end of stroke\n"); */
+ /* if drawing polygon and enable on back, must move stroke */
+ if (ts) {
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) {
+ if (p->flags & GP_PAINTFLAG_STROKEADDED) {
+ gpencil_move_last_stroke_to_back(C);
+ }
+ }
+ }
p->status = GP_STATUS_DONE;
estate = OPERATOR_FINISHED;
}
@@ -2027,6 +2509,14 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
else {
/* printf("\t\tGP - end of stroke + op\n"); */
+ /* if drawing polygon and enable on back, must move stroke */
+ if (ts) {
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) {
+ if (p->flags & GP_PAINTFLAG_STROKEADDED) {
+ gpencil_move_last_stroke_to_back(C);
+ }
+ }
+ }
p->status = GP_STATUS_DONE;
estate = OPERATOR_FINISHED;
}
@@ -2107,6 +2597,14 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
* NOTE: Don't eter this case if an error occurred while finding the
* region (as above)
*/
+ /* if drawing polygon and enable on back, must move stroke */
+ if (ts) {
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) {
+ if (p->flags & GP_PAINTFLAG_STROKEADDED) {
+ gpencil_move_last_stroke_to_back(C);
+ }
+ }
+ }
p->status = GP_STATUS_DONE;
estate = OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index b6482786b4f..45dbde80284 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -36,6 +36,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
#include "BLI_lasso.h"
#include "BLI_utildefines.h"
#include "BLI_math_vector.h"
@@ -43,6 +44,7 @@
#include "DNA_gpencil_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
+#include "DNA_object_types.h"
#include "BKE_context.h"
#include "BKE_gpencil.h"
@@ -252,6 +254,9 @@ typedef enum eGP_SelectGrouped {
/* Select strokes in the same layer */
GP_SEL_SAME_LAYER = 0,
+ /* Select strokes with the same color */
+ GP_SEL_SAME_COLOR = 1,
+
/* TODO: All with same prefix - Useful for isolating all layers for a particular character for instance */
/* TODO: All with same appearance - colour/opacity/volumetric/fills ? */
} eGP_SelectGrouped;
@@ -265,7 +270,7 @@ static void gp_select_same_layer(bContext *C)
CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
{
- bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, 0);
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0);
bGPDstroke *gps;
bool found = false;
@@ -301,6 +306,43 @@ static void gp_select_same_layer(bContext *C)
CTX_DATA_END;
}
+/* Select all strokes with same colors as selected ones */
+static void gp_select_same_color(bContext *C)
+{
+ /* First, build set containing all the colors of selected strokes
+ * - We use the palette names, so that we can select all strokes with one
+ * (potentially missing) color, and remap them to something else
+ */
+ GSet *selected_colors = BLI_gset_str_new("GP Selected Colors");
+
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* add instead of insert here, otherwise the uniqueness check gets skipped,
+ * and we get many duplicate entries...
+ */
+ BLI_gset_add(selected_colors, gps->colorname);
+ }
+ }
+ CTX_DATA_END;
+
+ /* Second, select any visible stroke that uses these colors */
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ if (BLI_gset_haskey(selected_colors, gps->colorname)) {
+ /* select this stroke */
+ bGPDspoint *pt;
+ int i;
+
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+
+ gps->flag |= GP_STROKE_SELECT;
+ }
+ }
+ CTX_DATA_END;
+}
/* ----------------------------------- */
@@ -313,6 +355,9 @@ static int gpencil_select_grouped_exec(bContext *C, wmOperator *op)
case GP_SEL_SAME_LAYER:
gp_select_same_layer(C);
break;
+ case GP_SEL_SAME_COLOR:
+ gp_select_same_color(C);
+ break;
default:
BLI_assert(!"unhandled select grouped gpencil mode");
@@ -328,6 +373,7 @@ void GPENCIL_OT_select_grouped(wmOperatorType *ot)
{
static EnumPropertyItem prop_select_grouped_types[] = {
{GP_SEL_SAME_LAYER, "LAYER", 0, "Layer", "Shared layers"},
+ {GP_SEL_SAME_COLOR, "COLOR", 0, "Color", "Shared colors"},
{0, NULL, 0, NULL, NULL}
};
@@ -337,7 +383,7 @@ void GPENCIL_OT_select_grouped(wmOperatorType *ot)
ot->description = "Select all strokes with similar characteristics";
/* callbacks */
- //ot->invoke = WM_menu_invoke;
+ ot->invoke = WM_menu_invoke;
ot->exec = gpencil_select_grouped_exec;
ot->poll = gpencil_select_poll;
@@ -616,9 +662,10 @@ void GPENCIL_OT_select_less(wmOperatorType *ot)
/* NOTE: Code here is adapted (i.e. copied directly) from gpencil_paint.c::gp_stroke_eraser_dostroke()
* It would be great to de-duplicate the logic here sometime, but that can wait...
*/
-static bool gp_stroke_do_circle_sel(bGPDstroke *gps, GP_SpaceConversion *gsc,
- const int mx, const int my, const int radius,
- const bool select, rcti *rect)
+static bool gp_stroke_do_circle_sel(
+ bGPDstroke *gps, GP_SpaceConversion *gsc,
+ const int mx, const int my, const int radius,
+ const bool select, rcti *rect, const bool parented, float diff_mat[4][4])
{
bGPDspoint *pt1, *pt2;
int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
@@ -626,7 +673,14 @@ static bool gp_stroke_do_circle_sel(bGPDstroke *gps, GP_SpaceConversion *gsc,
bool changed = false;
if (gps->totpoints == 1) {
- gp_point_to_xy(gsc, gps, gps->points, &x0, &y0);
+ if (!parented) {
+ gp_point_to_xy(gsc, gps, gps->points, &x0, &y0);
+ }
+ else {
+ bGPDspoint pt_temp;
+ gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
+ gp_point_to_xy(gsc, gps, &pt_temp, &x0, &y0);
+ }
/* do boundbox check first */
if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) {
@@ -654,9 +708,18 @@ static bool gp_stroke_do_circle_sel(bGPDstroke *gps, GP_SpaceConversion *gsc,
/* get points to work with */
pt1 = gps->points + i;
pt2 = gps->points + i + 1;
-
- gp_point_to_xy(gsc, gps, pt1, &x0, &y0);
- gp_point_to_xy(gsc, gps, pt2, &x1, &y1);
+ if (!parented) {
+ gp_point_to_xy(gsc, gps, pt1, &x0, &y0);
+ gp_point_to_xy(gsc, gps, pt2, &x1, &y1);
+ }
+ else {
+ bGPDspoint npt;
+ gp_point_to_parent_space(pt1, diff_mat, &npt);
+ gp_point_to_xy(gsc, gps, &npt, &x0, &y0);
+
+ gp_point_to_parent_space(pt2, diff_mat, &npt);
+ gp_point_to_xy(gsc, gps, &npt, &x1, &y1);
+ }
/* check that point segment of the boundbox of the selection stroke */
if (((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) ||
@@ -691,7 +754,7 @@ static bool gp_stroke_do_circle_sel(bGPDstroke *gps, GP_SpaceConversion *gsc,
}
/* Ensure that stroke selection is in sync with its points */
- gpencil_stroke_sync_selection(gps);
+ BKE_gpencil_stroke_sync_selection(gps);
}
return changed;
@@ -733,12 +796,14 @@ static int gpencil_circle_select_exec(bContext *C, wmOperator *op)
/* find visible strokes, and select if hit */
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ GP_EDITABLE_STROKES_BEGIN(C, gpl, gps)
{
- changed |= gp_stroke_do_circle_sel(gps, &gsc, mx, my, radius, select, &rect);
+ changed |= gp_stroke_do_circle_sel(
+ gps, &gsc, mx, my, radius, select, &rect,
+ (gpl->parent != NULL), diff_mat);
}
- CTX_DATA_END;
-
+ GP_EDITABLE_STROKES_END;
+
/* updates */
if (changed) {
WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
@@ -818,17 +883,25 @@ static int gpencil_border_select_exec(bContext *C, wmOperator *op)
WM_operator_properties_border_to_rcti(op, &rect);
/* select/deselect points */
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ GP_EDITABLE_STROKES_BEGIN(C, gpl, gps)
{
+
bGPDspoint *pt;
int i;
-
+
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
int x0, y0;
-
+
/* convert point coords to screenspace */
- gp_point_to_xy(&gsc, gps, pt, &x0, &y0);
-
+ if (gpl->parent == NULL) {
+ gp_point_to_xy(&gsc, gps, pt, &x0, &y0);
+ }
+ else {
+ bGPDspoint pt2;
+ gp_point_to_parent_space(pt, diff_mat, &pt2);
+ gp_point_to_xy(&gsc, gps, &pt2, &x0, &y0);
+ }
+
/* test if in selection rect */
if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&rect, x0, y0)) {
if (select) {
@@ -837,16 +910,16 @@ static int gpencil_border_select_exec(bContext *C, wmOperator *op)
else {
pt->flag &= ~GP_SPOINT_SELECT;
}
-
+
changed = true;
}
}
-
+
/* Ensure that stroke selection is in sync with its points */
- gpencil_stroke_sync_selection(gps);
+ BKE_gpencil_stroke_sync_selection(gps);
}
- CTX_DATA_END;
-
+ GP_EDITABLE_STROKES_END;
+
/* updates */
if (changed) {
WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
@@ -920,20 +993,26 @@ static int gpencil_lasso_select_exec(bContext *C, wmOperator *op)
}
/* select/deselect points */
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ GP_EDITABLE_STROKES_BEGIN(C, gpl, gps)
{
bGPDspoint *pt;
int i;
-
+
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
int x0, y0;
-
+
/* convert point coords to screenspace */
- gp_point_to_xy(&gsc, gps, pt, &x0, &y0);
-
+ if (gpl->parent == NULL) {
+ gp_point_to_xy(&gsc, gps, pt, &x0, &y0);
+ }
+ else {
+ bGPDspoint pt2;
+ gp_point_to_parent_space(pt, diff_mat, &pt2);
+ gp_point_to_xy(&gsc, gps, &pt2, &x0, &y0);
+ }
/* test if in lasso boundbox + within the lasso noose */
if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&rect, x0, y0) &&
- BLI_lasso_is_point_inside(mcords, mcords_tot, x0, y0, INT_MAX))
+ BLI_lasso_is_point_inside(mcords, mcords_tot, x0, y0, INT_MAX))
{
if (select) {
pt->flag |= GP_SPOINT_SELECT;
@@ -941,16 +1020,16 @@ static int gpencil_lasso_select_exec(bContext *C, wmOperator *op)
else {
pt->flag &= ~GP_SPOINT_SELECT;
}
-
+
changed = true;
}
}
-
+
/* Ensure that stroke selection is in sync with its points */
- gpencil_stroke_sync_selection(gps);
+ BKE_gpencil_stroke_sync_selection(gps);
}
- CTX_DATA_END;
-
+ GP_EDITABLE_STROKES_END;
+
/* cleanup */
MEM_freeN((void *)mcords);
@@ -1020,35 +1099,42 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
/* First Pass: Find stroke point which gets hit */
/* XXX: maybe we should go from the top of the stack down instead... */
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ GP_EDITABLE_STROKES_BEGIN(C, gpl, gps)
{
bGPDspoint *pt;
int i;
-
+
/* firstly, check for hit-point */
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
int xy[2];
-
- gp_point_to_xy(&gsc, gps, pt, &xy[0], &xy[1]);
-
+
+ if (gpl->parent == NULL) {
+ gp_point_to_xy(&gsc, gps, pt, &xy[0], &xy[1]);
+ }
+ else {
+ bGPDspoint pt2;
+ gp_point_to_parent_space(pt, diff_mat, &pt2);
+ gp_point_to_xy(&gsc, gps, &pt2, &xy[0], &xy[1]);
+ }
+
/* do boundbox check first */
if (!ELEM(V2D_IS_CLIPPED, xy[0], xy[1])) {
const int pt_distance = len_manhattan_v2v2_int(mval, xy);
-
+
/* check if point is inside */
if (pt_distance <= radius_squared) {
/* only use this point if it is a better match than the current hit - T44685 */
if (pt_distance < hit_distance) {
hit_stroke = gps;
- hit_point = pt;
+ hit_point = pt;
hit_distance = pt_distance;
}
}
}
}
}
- CTX_DATA_END;
-
+ GP_EDITABLE_STROKES_END;
+
/* Abort if nothing hit... */
if (ELEM(NULL, hit_stroke, hit_point)) {
return OPERATOR_CANCELLED;
@@ -1111,7 +1197,7 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
hit_point->flag &= ~GP_SPOINT_SELECT;
/* ensure that stroke is selected correctly */
- gpencil_stroke_sync_selection(hit_stroke);
+ BKE_gpencil_stroke_sync_selection(hit_stroke);
}
}
diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c
index c39a3aa5cfc..7a9ad2b32c0 100644
--- a/source/blender/editors/gpencil/gpencil_undo.c
+++ b/source/blender/editors/gpencil/gpencil_undo.c
@@ -43,7 +43,9 @@
#include "BKE_blender_undo.h"
#include "BKE_context.h"
+#include "BKE_global.h"
#include "BKE_gpencil.h"
+#include "BKE_main.h"
#include "ED_gpencil.h"
@@ -98,14 +100,14 @@ int ED_undo_gpencil_step(bContext *C, int step, const char *name)
bGPdata *gpd = *gpd_ptr;
bGPDlayer *gpl, *gpld;
- free_gpencil_layers(&gpd->layers);
+ BKE_gpencil_free_layers(&gpd->layers);
/* copy layers */
BLI_listbase_clear(&gpd->layers);
for (gpl = new_gpd->layers.first; gpl; gpl = gpl->next) {
/* make a copy of source layer and its data */
- gpld = gpencil_layer_duplicate(gpl);
+ gpld = BKE_gpencil_layer_duplicate(gpl);
BLI_addtail(&gpd->layers, gpld);
}
}
@@ -122,6 +124,17 @@ void gpencil_undo_init(bGPdata *gpd)
gpencil_undo_push(gpd);
}
+static void gpencil_undo_free_node(bGPundonode *undo_node)
+{
+ /* HACK: animdata wasn't duplicated, so it shouldn't be freed here,
+ * or else the real copy will segfault when accessed
+ */
+ undo_node->gpd->adt = NULL;
+
+ BKE_gpencil_free(undo_node->gpd, false);
+ MEM_freeN(undo_node->gpd);
+}
+
void gpencil_undo_push(bGPdata *gpd)
{
bGPundonode *undo_node;
@@ -135,23 +148,39 @@ void gpencil_undo_push(bGPdata *gpd)
while (undo_node) {
bGPundonode *next_node = undo_node->next;
- /* HACK: animdata wasn't duplicated, so it shouldn't be freed here,
- * or else the real copy will segfault when accessed
- */
- undo_node->gpd->adt = NULL;
-
- BKE_gpencil_free(undo_node->gpd);
- MEM_freeN(undo_node->gpd);
-
+ gpencil_undo_free_node(undo_node);
BLI_freelinkN(&undo_nodes, undo_node);
undo_node = next_node;
}
}
+ /* limit number of undo steps to the maximum undo steps
+ * - to prevent running out of memory during **really**
+ * long drawing sessions (triggering swapping)
+ */
+ /* TODO: Undo-memory constraint is not respected yet, but can be added if we have any need for it */
+ if (U.undosteps && !BLI_listbase_is_empty(&undo_nodes)) {
+ /* remove anything older than n-steps before cur_node */
+ int steps = 0;
+
+ undo_node = (cur_node) ? cur_node : undo_nodes.last;
+ while (undo_node) {
+ bGPundonode *prev_node = undo_node->prev;
+
+ if (steps >= U.undosteps) {
+ gpencil_undo_free_node(undo_node);
+ BLI_freelinkN(&undo_nodes, undo_node);
+ }
+
+ steps++;
+ undo_node = prev_node;
+ }
+ }
+
/* create new undo node */
undo_node = MEM_callocN(sizeof(bGPundonode), "gpencil undo node");
- undo_node->gpd = gpencil_data_duplicate(gpd, true);
+ undo_node->gpd = BKE_gpencil_data_duplicate(G.main, gpd, true);
cur_node = undo_node;
@@ -163,14 +192,7 @@ void gpencil_undo_finish(void)
bGPundonode *undo_node = undo_nodes.first;
while (undo_node) {
- /* HACK: animdata wasn't duplicated, so it shouldn't be freed here,
- * or else the real copy will segfault when accessed
- */
- undo_node->gpd->adt = NULL;
-
- BKE_gpencil_free(undo_node->gpd);
- MEM_freeN(undo_node->gpd);
-
+ gpencil_undo_free_node(undo_node);
undo_node = undo_node->next;
}
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index b2c6107ab61..564ba639983 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -17,7 +17,7 @@
*
* The Original Code is Copyright (C) 2014, Blender Foundation
*
- * Contributor(s): Joshua Leung
+ * Contributor(s): Joshua Leung, Antonio Vazquez
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -32,9 +32,13 @@
#include <stddef.h>
#include <math.h>
+#include "MEM_guardedalloc.h"
+
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLT_translation.h"
+#include "BLI_rand.h"
#include "DNA_gpencil_types.h"
#include "DNA_object_types.h"
@@ -46,6 +50,7 @@
#include "BKE_context.h"
#include "BKE_gpencil.h"
#include "BKE_tracking.h"
+#include "BKE_action.h"
#include "WM_api.h"
@@ -220,7 +225,7 @@ bool ED_gpencil_has_keyframe_v3d(Scene *scene, Object *ob, int cfra)
/* just check both for now... */
// XXX: this could get confusing (e.g. if only on the object, but other places don't show this)
if (scene->gpd) {
- bGPDlayer *gpl = gpencil_layer_getactive(scene->gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(scene->gpd);
if (gpl) {
if (gpl->actframe) {
// XXX: assumes that frame has been fetched already
@@ -234,7 +239,7 @@ bool ED_gpencil_has_keyframe_v3d(Scene *scene, Object *ob, int cfra)
}
if (ob && ob->gpd) {
- bGPDlayer *gpl = gpencil_layer_getactive(ob->gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(ob->gpd);
if (gpl) {
if (gpl->actframe) {
// XXX: assumes that frame has been fetched already
@@ -264,11 +269,39 @@ int gp_add_poll(bContext *C)
int gp_active_layer_poll(bContext *C)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
return (gpl != NULL);
}
+/* poll callback for checking if there is an active brush */
+int gp_active_brush_poll(bContext *C)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ bGPDbrush *brush = BKE_gpencil_brush_getactive(ts);
+
+ return (brush != NULL);
+}
+
+/* poll callback for checking if there is an active palette */
+int gp_active_palette_poll(bContext *C)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
+
+ return (palette != NULL);
+}
+
+/* poll callback for checking if there is an active palette color */
+int gp_active_palettecolor_poll(bContext *C)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
+ bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette);
+
+ return (palcolor != NULL);
+}
+
/* ******************************************************** */
/* Dynamic Enums of GP Layers */
/* NOTE: These include an option to create a new layer and use that... */
@@ -412,6 +445,60 @@ bool ED_gpencil_stroke_can_use(const bContext *C, const bGPDstroke *gps)
return ED_gpencil_stroke_can_use_direct(sa, gps);
}
+/* Check whether given stroke can be edited for the current color */
+bool ED_gpencil_stroke_color_use(const bGPDlayer *gpl, const bGPDstroke *gps)
+{
+ /* check if the color is editable */
+ bGPDpalettecolor *palcolor = gps->palcolor;
+ if (palcolor != NULL) {
+ if (palcolor->flag & PC_COLOR_HIDE)
+ return false;
+ if (((gpl->flag & GP_LAYER_UNLOCK_COLOR) == 0) && (palcolor->flag & PC_COLOR_LOCKED))
+ return false;
+ }
+
+ return true;
+}
+
+/* Get palette color or create a new one */
+bGPDpalettecolor *ED_gpencil_stroke_getcolor(bGPdata *gpd, bGPDstroke *gps)
+{
+ bGPDpalette *palette;
+ bGPDpalettecolor *palcolor;
+
+ if ((gps->palcolor != NULL) && ((gps->flag & GP_STROKE_RECALC_COLOR) == 0))
+ return gps->palcolor;
+
+ /* get palette */
+ palette = BKE_gpencil_palette_getactive(gpd);
+ if (palette == NULL) {
+ palette = BKE_gpencil_palette_addnew(gpd, DATA_("GP_Palette"), true);
+ }
+ /* get color */
+ palcolor = BKE_gpencil_palettecolor_getbyname(palette, gps->colorname);
+ if (palcolor == NULL) {
+ if (gps->palcolor == NULL) {
+ palcolor = BKE_gpencil_palettecolor_addnew(palette, DATA_("Color"), true);
+ /* set to a different color */
+ ARRAY_SET_ITEMS(palcolor->color, 1.0f, 0.0f, 1.0f, 0.9f);
+ }
+ else {
+ palcolor = BKE_gpencil_palettecolor_addnew(palette, gps->colorname, true);
+ /* set old color and attributes */
+ bGPDpalettecolor *gpscolor = gps->palcolor;
+ copy_v4_v4(palcolor->color, gpscolor->color);
+ copy_v4_v4(palcolor->fill, gpscolor->fill);
+ palcolor->flag = gpscolor->flag;
+ }
+ }
+
+ /* clear flag and set pointer */
+ gps->flag &= ~GP_STROKE_RECALC_COLOR;
+ gps->palcolor = palcolor;
+
+ return palcolor;
+}
+
/* ******************************************************** */
/* Space Conversion */
@@ -451,6 +538,50 @@ void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
}
}
+/* convert point to parent space */
+void gp_point_to_parent_space(bGPDspoint *pt, float diff_mat[4][4], bGPDspoint *r_pt)
+{
+ float fpt[3];
+
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ copy_v3_v3(&r_pt->x, fpt);
+}
+
+/* Change position relative to parent object */
+void gp_apply_parent(bGPDlayer *gpl, bGPDstroke *gps)
+{
+ bGPDspoint *pt;
+ int i;
+
+ /* undo matrix */
+ float diff_mat[4][4];
+ float inverse_diff_mat[4][4];
+ float fpt[3];
+
+ ED_gpencil_parent_location(gpl, diff_mat);
+ invert_m4_m4(inverse_diff_mat, diff_mat);
+
+ for (i = 0; i < gps->totpoints; i++) {
+ pt = &gps->points[i];
+ mul_v3_m4v3(fpt, inverse_diff_mat, &pt->x);
+ copy_v3_v3(&pt->x, fpt);
+ }
+}
+
+/* Change point position relative to parent object */
+void gp_apply_parent_point(bGPDlayer *gpl, bGPDspoint *pt)
+{
+ /* undo matrix */
+ float diff_mat[4][4];
+ float inverse_diff_mat[4][4];
+ float fpt[3];
+
+ ED_gpencil_parent_location(gpl, diff_mat);
+ invert_m4_m4(inverse_diff_mat, diff_mat);
+
+ mul_v3_m4v3(fpt, inverse_diff_mat, &pt->x);
+ copy_v3_v3(&pt->x, fpt);
+}
/* Convert Grease Pencil points to screen-space values
* WARNING: This assumes that the caller has already checked whether the stroke in question can be drawn
@@ -497,6 +628,63 @@ void gp_point_to_xy(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt,
}
}
+/* Convert Grease Pencil points to screen-space values (as floats)
+ * WARNING: This assumes that the caller has already checked whether the stroke in question can be drawn
+ */
+void gp_point_to_xy_fl(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt,
+ float *r_x, float *r_y)
+{
+ ARegion *ar = gsc->ar;
+ View2D *v2d = gsc->v2d;
+ rctf *subrect = gsc->subrect;
+ float xyval[2];
+
+ /* sanity checks */
+ BLI_assert(!(gps->flag & GP_STROKE_3DSPACE) || (gsc->sa->spacetype == SPACE_VIEW3D));
+ BLI_assert(!(gps->flag & GP_STROKE_2DSPACE) || (gsc->sa->spacetype != SPACE_VIEW3D));
+
+
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ if (ED_view3d_project_float_global(ar, &pt->x, xyval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
+ *r_x = xyval[0];
+ *r_y = xyval[1];
+ }
+ else {
+ *r_x = 0.0f;
+ *r_y = 0.0f;
+ }
+ }
+ else if (gps->flag & GP_STROKE_2DSPACE) {
+ float vec[3] = {pt->x, pt->y, 0.0f};
+ int t_x, t_y;
+
+ mul_m4_v3(gsc->mat, vec);
+ UI_view2d_view_to_region_clip(v2d, vec[0], vec[1], &t_x, &t_y);
+
+ if ((t_x == t_y) && (t_x == V2D_IS_CLIPPED)) {
+ /* XXX: Or should we just always use the values as-is? */
+ *r_x = 0.0f;
+ *r_y = 0.0f;
+ }
+ else {
+ *r_x = (float)t_x;
+ *r_y = (float)t_y;
+ }
+ }
+ else {
+ if (subrect == NULL) {
+ /* normal 3D view (or view space) */
+ *r_x = (pt->x / 100.0f * ar->winx);
+ *r_y = (pt->y / 100.0f * ar->winy);
+ }
+ else {
+ /* camera view, use subrect */
+ *r_x = ((pt->x / 100.0f) * BLI_rctf_size_x(subrect)) + subrect->xmin;
+ *r_y = ((pt->y / 100.0f) * BLI_rctf_size_y(subrect)) + subrect->ymin;
+ }
+ }
+}
+
/**
* Project screenspace coordinates to 3D-space
*
@@ -552,8 +740,8 @@ bool gp_smooth_stroke(bGPDstroke *gps, int i, float inf, bool affect_pressure)
}
/* Only affect endpoints by a fraction of the normal strength,
- * to prevent the stroke from shrinking too much
- */
+ * to prevent the stroke from shrinking too much
+ */
if ((i == 0) || (i == gps->totpoints - 1)) {
inf *= 0.1f;
}
@@ -591,25 +779,107 @@ bool gp_smooth_stroke(bGPDstroke *gps, int i, float inf, bool affect_pressure)
madd_v3_v3fl(sco, &pt1->x, average_fac);
madd_v3_v3fl(sco, &pt2->x, average_fac);
+#if 0
+ /* XXX: Disabled because get weird result */
/* do pressure too? */
if (affect_pressure) {
pressure += pt1->pressure * average_fac;
pressure += pt2->pressure * average_fac;
}
+#endif
}
}
/* Based on influence factor, blend between original and optimal smoothed coordinate */
interp_v3_v3v3(&pt->x, &pt->x, sco, inf);
+#if 0
+ /* XXX: Disabled because get weird result */
if (affect_pressure) {
pt->pressure = pressure;
}
+#endif
return true;
}
/**
+* Apply smooth for strength to stroke point
+* \param gps Stroke to smooth
+* \param i Point index
+* \param inf Amount of smoothing to apply
+*/
+bool gp_smooth_stroke_strength(bGPDstroke *gps, int i, float inf)
+{
+ bGPDspoint *ptb = &gps->points[i];
+
+ /* Do nothing if not enough points */
+ if (gps->totpoints <= 2) {
+ return false;
+ }
+
+ /* Compute theoretical optimal value using distances */
+ bGPDspoint *pta, *ptc;
+ int before = i - 1;
+ int after = i + 1;
+
+ CLAMP_MIN(before, 0);
+ CLAMP_MAX(after, gps->totpoints - 1);
+
+ pta = &gps->points[before];
+ ptc = &gps->points[after];
+
+ /* the optimal value is the corresponding to the interpolation of the strength
+ * at the distance of point b
+ */
+ const float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
+ const float optimal = (1.0f - fac) * pta->strength + fac * ptc->strength;
+
+ /* Based on influence factor, blend between original and optimal */
+ ptb->strength = (1.0f - inf) * ptb->strength + inf * optimal;
+
+ return true;
+}
+
+/**
+* Apply smooth for thickness to stroke point (use pressure)
+* \param gps Stroke to smooth
+* \param i Point index
+* \param inf Amount of smoothing to apply
+*/
+bool gp_smooth_stroke_thickness(bGPDstroke *gps, int i, float inf)
+{
+ bGPDspoint *ptb = &gps->points[i];
+
+ /* Do nothing if not enough points */
+ if (gps->totpoints <= 2) {
+ return false;
+ }
+
+ /* Compute theoretical optimal value using distances */
+ bGPDspoint *pta, *ptc;
+ int before = i - 1;
+ int after = i + 1;
+
+ CLAMP_MIN(before, 0);
+ CLAMP_MAX(after, gps->totpoints - 1);
+
+ pta = &gps->points[before];
+ ptc = &gps->points[after];
+
+ /* the optimal value is the corresponding to the interpolation of the pressure
+ * at the distance of point b
+ */
+ float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
+ float optimal = (1.0f - fac) * pta->pressure + fac * ptc->pressure;
+
+ /* Based on influence factor, blend between original and optimal */
+ ptb->pressure = (1.0f - inf) * ptb->pressure + inf * optimal;
+
+ return true;
+}
+
+/**
* Subdivide a stroke once, by adding a point half way between each pair of existing points
* \param gps Stroke data
* \param new_totpoints Total number of points (after subdividing)
@@ -633,16 +903,101 @@ void gp_subdivide_stroke(bGPDstroke *gps, const int new_totpoints)
interp_v3_v3v3(&pt->x, &prev->x, &next->x, 0.5f);
pt->pressure = interpf(prev->pressure, next->pressure, 0.5f);
- pt->time = interpf(prev->time, next->time, 0.5f);
+ pt->strength = interpf(prev->strength, next->strength, 0.5f);
+ CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ pt->time = interpf(prev->time, next->time, 0.5f);
}
/* Update to new total number of points */
gps->totpoints = new_totpoints;
}
-/* ******************************************************** */
+/**
+ * Add randomness to stroke
+ * \param gps Stroke data
+ * \param brsuh Brush data
+ */
+void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush)
+{
+ bGPDspoint *pt1, *pt2, *pt3;
+ float v1[3];
+ float v2[3];
+ if (gps->totpoints < 3) {
+ return;
+ }
+
+ /* get two vectors using 3 points */
+ pt1 = &gps->points[0];
+ pt2 = &gps->points[1];
+ pt3 = &gps->points[(int)(gps->totpoints * 0.75)];
+
+ sub_v3_v3v3(v1, &pt2->x, &pt1->x);
+ sub_v3_v3v3(v2, &pt3->x, &pt2->x);
+ normalize_v3(v1);
+ normalize_v3(v2);
+
+ /* get normal vector to plane created by two vectors */
+ float normal[3];
+ cross_v3_v3v3(normal, v1, v2);
+ normalize_v3(normal);
+
+ /* get orthogonal vector to plane to rotate random effect */
+ float ortho[3];
+ cross_v3_v3v3(ortho, v1, normal);
+ normalize_v3(ortho);
+
+ /* Read all points and apply shift vector (first and last point not modified) */
+ for (int i = 1; i < gps->totpoints - 1; ++i) {
+ bGPDspoint *pt = &gps->points[i];
+ /* get vector with shift (apply a division because random is too sensitive */
+ const float fac = BLI_frand() * (brush->draw_random_sub / 10.0f);
+ float svec[3];
+ copy_v3_v3(svec, ortho);
+ if (BLI_frand() > 0.5f) {
+ mul_v3_fl(svec, -fac);
+ }
+ else {
+ mul_v3_fl(svec, fac);
+ }
+ /* apply shift */
+ add_v3_v3(&pt->x, svec);
+ }
+
+}
+/* calculate difference matrix */
+void ED_gpencil_parent_location(bGPDlayer *gpl, float diff_mat[4][4])
+{
+ Object *ob = gpl->parent;
+ if (ob == NULL) {
+ unit_m4(diff_mat);
+ return;
+ }
+ else {
+ if ((gpl->partype == PAROBJECT) || (gpl->partype == PARSKEL)) {
+ mul_m4_m4m4(diff_mat, ob->obmat, gpl->inverse);
+ return;
+ }
+ else if (gpl->partype == PARBONE) {
+ bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, gpl->parsubstr);
+ if (pchan) {
+ float tmp_mat[4][4];
+ mul_m4_m4m4(tmp_mat, ob->obmat, pchan->pose_mat);
+ mul_m4_m4m4(diff_mat, tmp_mat, gpl->inverse);
+ }
+ else {
+ mul_m4_m4m4(diff_mat, ob->obmat, gpl->inverse); /* if bone not found use object (armature) */
+ }
+ return;
+ }
+ else {
+ unit_m4(diff_mat); /* not defined type */
+ }
+ }
+}
+
+/* ******************************************************** */
bool ED_gpencil_stroke_minmax(
const bGPDstroke *gps, const bool use_select,
float r_min[3], float r_max[3])
@@ -659,3 +1014,74 @@ bool ED_gpencil_stroke_minmax(
}
return changed;
}
+
+/* Dynamic Enums of GP Brushes */
+EnumPropertyItem *ED_gpencil_brushes_enum_itemf(
+ bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ bGPDbrush *brush;
+ EnumPropertyItem *item = NULL, item_tmp = { 0 };
+ int totitem = 0;
+ int i = 0;
+
+ if (ELEM(NULL, C, ts)) {
+ return DummyRNA_DEFAULT_items;
+ }
+
+ /* Existing brushes */
+ for (brush = ts->gp_brushes.first; brush; brush = brush->next, i++) {
+ item_tmp.identifier = brush->info;
+ item_tmp.name = brush->info;
+ item_tmp.value = i;
+
+ if (brush->flag & GP_BRUSH_ACTIVE)
+ item_tmp.icon = ICON_BRUSH_DATA;
+ else
+ item_tmp.icon = ICON_NONE;
+
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+/* Dynamic Enums of GP Palettes */
+EnumPropertyItem *ED_gpencil_palettes_enum_itemf(
+ bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ bGPDpalette *palette;
+ EnumPropertyItem *item = NULL, item_tmp = { 0 };
+ int totitem = 0;
+ int i = 0;
+
+ if (ELEM(NULL, C, gpd)) {
+ return DummyRNA_DEFAULT_items;
+ }
+
+ /* Existing palettes */
+ for (palette = gpd->palettes.first; palette; palette = palette->next, i++) {
+ item_tmp.identifier = palette->info;
+ item_tmp.name = palette->info;
+ item_tmp.value = i;
+
+ if (palette->flag & PL_PALETTE_ACTIVE)
+ item_tmp.icon = ICON_COLOR;
+ else
+ item_tmp.icon = ICON_NONE;
+
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+/* ******************************************************** */
diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h
index 0ac5c17a552..d3d2c465d46 100644
--- a/source/blender/editors/include/BIF_glutil.h
+++ b/source/blender/editors/include/BIF_glutil.h
@@ -94,6 +94,7 @@ void glutil_draw_filled_arc(float start, float angle, float radius, int nsegment
* The param must cause only one value to be gotten from GL.
*/
float glaGetOneFloat(int param);
+int glaGetOneInt(int param);
/**
* Functions like glRasterPos2i, except ensures that the resulting
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index fb4897c6532..4a4ab832b28 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -74,6 +74,7 @@ typedef struct bAnimContext {
short mode; /* editor->mode */
short spacetype; /* sa->spacetype */
short regiontype; /* active region -> type (channels or main) */
+
struct ScrArea *sa; /* editor host */
struct SpaceLink *sl; /* editor data */
struct ARegion *ar; /* region within editor */
@@ -85,6 +86,8 @@ typedef struct bAnimContext {
ListBase *markers; /* active set of markers */
struct ReportList *reports; /* pointer to current reports list */
+
+ float yscale_fac; /* scale factor for height of channels (i.e. based on the size of keyframes) */
} bAnimContext;
/* Main Data container types */
@@ -153,6 +156,7 @@ typedef enum eAnim_ChannelType {
ANIMTYPE_DSMAT,
ANIMTYPE_DSLAM,
ANIMTYPE_DSCAM,
+ ANIMTYPE_DSCACHEFILE,
ANIMTYPE_DSCUR,
ANIMTYPE_DSSKEY,
ANIMTYPE_DSWOR,
@@ -166,6 +170,7 @@ typedef enum eAnim_ChannelType {
ANIMTYPE_DSLINESTYLE,
ANIMTYPE_DSSPK,
ANIMTYPE_DSGPENCIL,
+ ANIMTYPE_DSMCLIP,
ANIMTYPE_SHAPEKEY,
@@ -272,6 +277,7 @@ typedef enum eAnimFilter_Flags {
#define FILTER_MAT_OBJD(ma) (CHECK_TYPE_INLINE(ma, Material *), ((ma->flag & MA_DS_EXPAND)))
#define FILTER_LAM_OBJD(la) (CHECK_TYPE_INLINE(la, Lamp *), ((la->flag & LA_DS_EXPAND)))
#define FILTER_CAM_OBJD(ca) (CHECK_TYPE_INLINE(ca, Camera *), ((ca->flag & CAM_DS_EXPAND)))
+#define FILTER_CACHEFILE_OBJD(cf) (CHECK_TYPE_INLINE(cf, CacheFile *), ((cf->flag & CACHEFILE_DS_EXPAND)))
#define FILTER_CUR_OBJD(cu) (CHECK_TYPE_INLINE(cu, Curve *), ((cu->flag & CU_DS_EXPAND)))
#define FILTER_PART_OBJD(part) (CHECK_TYPE_INLINE(part, ParticleSettings *), ((part->flag & PART_DS_EXPAND)))
#define FILTER_MBALL_OBJD(mb) (CHECK_TYPE_INLINE(mb, MetaBall *), ((mb->flag2 & MB_DS_EXPAND)))
@@ -324,6 +330,8 @@ typedef enum eAnimFilter_Flags {
#define SEL_NLT(nlt) (nlt->flag & NLATRACK_SELECTED)
#define EDITABLE_NLT(nlt) ((nlt->flag & NLATRACK_PROTECTED) == 0)
+/* Movie clip only */
+#define EXPANDED_MCLIP(clip) (clip->flag & MCLIP_DATA_EXPAND)
/* AnimData - NLA mostly... */
#define SEL_ANIMDATA(adt) (adt->flag & ADT_UI_SELECTED)
@@ -331,11 +339,11 @@ typedef enum eAnimFilter_Flags {
/* -------------- Channel Defines -------------- */
/* channel heights */
-#define ACHANNEL_FIRST (-0.8f * U.widget_unit)
-#define ACHANNEL_HEIGHT (0.8f * U.widget_unit)
-#define ACHANNEL_HEIGHT_HALF (0.4f * U.widget_unit)
-#define ACHANNEL_SKIP (0.1f * U.widget_unit)
-#define ACHANNEL_STEP (ACHANNEL_HEIGHT + ACHANNEL_SKIP)
+#define ACHANNEL_FIRST(ac) (-0.8f * (ac)->yscale_fac * U.widget_unit)
+#define ACHANNEL_HEIGHT(ac) (0.8f * (ac)->yscale_fac * U.widget_unit)
+#define ACHANNEL_HEIGHT_HALF(ac) (0.4f * (ac)->yscale_fac * U.widget_unit)
+#define ACHANNEL_SKIP (0.1f * U.widget_unit)
+#define ACHANNEL_STEP(ac) (ACHANNEL_HEIGHT(ac) + ACHANNEL_SKIP)
/* channel widths */
#define ACHANNEL_NAMEWIDTH (10 * U.widget_unit)
@@ -347,7 +355,6 @@ typedef enum eAnimFilter_Flags {
/* -------------- NLA Channel Defines -------------- */
/* NLA channel heights */
-// XXX: NLACHANNEL_FIRST isn't used?
#define NLACHANNEL_FIRST (-0.8f * U.widget_unit)
#define NLACHANNEL_HEIGHT(snla) ((snla && (snla->flag & SNLA_NOSTRIPCURVES)) ? (0.8f * U.widget_unit) : (1.2f * U.widget_unit))
#define NLACHANNEL_HEIGHT_HALF(snla) ((snla && (snla->flag & SNLA_NOSTRIPCURVES)) ? (0.4f * U.widget_unit) : (0.6f * U.widget_unit))
@@ -413,7 +420,8 @@ typedef enum eAnimChannel_Settings {
ACHANNEL_SETTING_VISIBLE = 4, /* only for Graph Editor */
ACHANNEL_SETTING_SOLO = 5, /* only for NLA Tracks */
ACHANNEL_SETTING_PINNED = 6, /* only for NLA Actions */
- ACHANNEL_SETTING_MOD_OFF = 7
+ ACHANNEL_SETTING_MOD_OFF = 7,
+ ACHANNEL_SETTING_ALWAYS_VISIBLE = 8, /* channel is pinned and always visible */
} eAnimChannel_Settings;
@@ -608,7 +616,7 @@ typedef enum eAnimUnitConv_Flags {
ANIM_UNITCONV_SKIPKNOTS = (1 << 4),
/* Scale FCurve i a way it fits to -1..1 space */
ANIM_UNITCONV_NORMALIZE = (1 << 5),
- /* Only whennormalization is used: use scale factor from previous run,
+ /* Only when normalization is used: use scale factor from previous run,
* prevents curves from jumping all over the place when tweaking them.
*/
ANIM_UNITCONV_NORMALIZE_FREEZE = (1 << 6),
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 15c68378b9a..904132b8876 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -74,7 +74,10 @@ typedef struct EditBone {
float xwidth, length, zwidth; /* put them in order! transform uses this as scale */
float ease1, ease2;
float rad_head, rad_tail;
-
+ float roll1, roll2;
+ float curveOutX, curveOutY;
+ float curveInX, curveInY;
+ float scaleIn, scaleOut;
float oldlength; /* for envelope scaling */
short segments;
diff --git a/source/blender/editors/include/ED_buttons.h b/source/blender/editors/include/ED_buttons.h
index 9a987d7618c..64c16605dec 100644
--- a/source/blender/editors/include/ED_buttons.h
+++ b/source/blender/editors/include/ED_buttons.h
@@ -37,6 +37,4 @@ bool ED_texture_context_check_particles(const struct bContext *C);
bool ED_texture_context_check_linestyle(const struct bContext *C);
bool ED_texture_context_check_others(const struct bContext *C);
-void ED_buttons_id_unref(struct SpaceButs *sbuts, const struct ID *id);
-
#endif /* __ED_BUTTONS_H__ */
diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h
index 278e3f97ba7..859d45e9c86 100644
--- a/source/blender/editors/include/ED_curve.h
+++ b/source/blender/editors/include/ED_curve.h
@@ -72,8 +72,7 @@ void ED_curve_deselect_all(struct EditNurb *editnurb);
void ED_curve_select_all(struct EditNurb *editnurb);
void ED_curve_select_swap(struct EditNurb *editnurb, bool hide_handles);
-/* editfont.h */
-void undo_push_font(struct bContext *C, const char *name);
+/* editfont.c */
void ED_curve_editfont_load(struct Object *obedit);
void ED_curve_editfont_make(struct Object *obedit);
void ED_curve_editfont_free(struct Object *obedit);
@@ -89,6 +88,9 @@ bool ED_curve_active_center(struct Curve *cu, float center[3]);
bool ED_curve_editfont_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
+/* editfont_undo.c */
+void undo_push_font(struct bContext *C, const char *name);
+
#if 0
/* debug only */
void printknots(struct Object *obedit);
diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h
index 186a2a26825..92acfa6c1d2 100644
--- a/source/blender/editors/include/ED_fileselect.h
+++ b/source/blender/editors/include/ED_fileselect.h
@@ -104,11 +104,12 @@ void ED_fileselect_clear(struct wmWindowManager *wm, struct ScrArea *sa, struct
void ED_fileselect_exit(struct wmWindowManager *wm, struct ScrArea *sa, struct SpaceFile *sfile);
-int ED_file_extension_icon(const char *relname);
+int ED_path_extension_type(const char *path);
+int ED_file_extension_icon(const char *path);
void ED_file_read_bookmarks(void);
-void ED_file_change_dir(struct bContext *C, const bool checkdir);
+void ED_file_change_dir(struct bContext *C);
/* File menu stuff */
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 255827db373..bc93b5622cb 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -30,6 +30,8 @@
#ifndef __ED_GPENCIL_H__
#define __ED_GPENCIL_H__
+#include "ED_numinput.h"
+
struct ID;
struct ListBase;
struct bContext;
@@ -41,13 +43,46 @@ struct bGPdata;
struct bGPDlayer;
struct bGPDframe;
struct bGPDstroke;
+struct bGPDpalette;
+struct bGPDpalettecolor;
struct bAnimContext;
+struct KeyframeEditData;
struct PointerRNA;
struct wmWindowManager;
struct wmKeyConfig;
/* ------------- Grease-Pencil Helpers ---------------- */
+typedef struct tGPDinterpolate_layer {
+ struct tGPDinterpolate_layer *next, *prev;
+
+ struct bGPDlayer *gpl; /* layer */
+ struct bGPDframe *prevFrame; /* frame before current frame (interpolate-from) */
+ struct bGPDframe *nextFrame; /* frame after current frame (interpolate-to) */
+ struct bGPDframe *interFrame; /* interpolated frame */
+ float factor; /* interpolate factor */
+
+} tGPDinterpolate_layer;
+
+/* Temporary interpolate operation data */
+typedef struct tGPDinterpolate {
+ struct Scene *scene; /* current scene from context */
+ struct ScrArea *sa; /* area where painting originated */
+ struct ARegion *ar; /* region where painting originated */
+ struct bGPdata *gpd; /* current GP datablock */
+
+ int cframe; /* current frame number */
+ ListBase ilayers; /* (tGPDinterpolate_layer) layers to be interpolated */
+ float shift; /* value for determining the displacement influence */
+ float init_factor; /* initial interpolation factor for active layer */
+ float low_limit; /* shift low limit (-100%) */
+ float high_limit; /* shift upper limit (200%) */
+ int flag; /* flag from toolsettings */
+
+ NumInput num; /* numeric input */
+ void *draw_handle_3d; /* handle for drawing strokes while operator is running 3d stuff */
+ void *draw_handle_screen; /* handle for drawing strokes while operator is running screen stuff */
+} tGPDinterpolate;
/* Temporary 'Stroke Point' data
*
@@ -56,6 +91,7 @@ struct wmKeyConfig;
typedef struct tGPspoint {
int x, y; /* x and y coordinates of cursor (in relative to area) */
float pressure; /* pressure of tablet at this point */
+ float strength; /* pressure of tablet at this point for alpha factor */
float time; /* Time relative to stroke start (used when converting to path) */
} tGPspoint;
@@ -85,6 +121,9 @@ bool ED_gpencil_has_keyframe_v3d(struct Scene *scene, struct Object *ob, int cfr
bool ED_gpencil_stroke_can_use_direct(const struct ScrArea *sa, const struct bGPDstroke *gps);
bool ED_gpencil_stroke_can_use(const struct bContext *C, const struct bGPDstroke *gps);
+bool ED_gpencil_stroke_color_use(const struct bGPDlayer *gpl, const struct bGPDstroke *gps);
+
+struct bGPDpalettecolor *ED_gpencil_stroke_getcolor(struct bGPdata *gpd, struct bGPDstroke *gps);
bool ED_gpencil_stroke_minmax(
const struct bGPDstroke *gps, const bool use_select,
@@ -111,6 +150,7 @@ void ED_gpencil_draw_view2d(const struct bContext *C, bool onlyv2d);
void ED_gpencil_draw_view3d(struct wmWindowManager *wm, struct Scene *scene, struct View3D *v3d, struct ARegion *ar, bool only3d);
void ED_gpencil_draw_ex(struct Scene *scene, struct bGPdata *gpd, int winx, int winy,
const int cfra, const char spacetype);
+void ED_gp_draw_interpolation(struct tGPDinterpolate *tgpi, const int type);
/* ----------- Grease-Pencil AnimEdit API ------------------ */
bool ED_gplayer_frames_looper(struct bGPDlayer *gpl, struct Scene *scene,
@@ -120,6 +160,7 @@ void ED_gplayer_make_cfra_list(struct bGPDlayer *gpl, ListBase *elems, bool only
bool ED_gplayer_frame_select_check(struct bGPDlayer *gpl);
void ED_gplayer_frame_select_set(struct bGPDlayer *gpl, short mode);
void ED_gplayer_frames_select_border(struct bGPDlayer *gpl, float min, float max, short select_mode);
+void ED_gplayer_frames_select_region(struct KeyframeEditData *ked, struct bGPDlayer *gpl, short tool, short select_mode);
void ED_gpencil_select_frames(struct bGPDlayer *gpl, short select_mode);
void ED_gpencil_select_frame(struct bGPDlayer *gpl, int selx, short select_mode);
@@ -140,4 +181,10 @@ bool ED_gpencil_anim_copybuf_paste(struct bAnimContext *ac, const short copy_mod
int ED_gpencil_session_active(void);
int ED_undo_gpencil_step(struct bContext *C, int step, const char *name);
+/* ------------ Transformation Utilities ------------ */
+
+/* get difference matrix using parent */
+void ED_gpencil_parent_location(struct bGPDlayer *gpl, float diff_mat[4][4]);
+
+
#endif /* __ED_GPENCIL_H__ */
diff --git a/source/blender/editors/include/ED_keyframes_draw.h b/source/blender/editors/include/ED_keyframes_draw.h
index 7d163da0db0..c478a8b17e5 100644
--- a/source/blender/editors/include/ED_keyframes_draw.h
+++ b/source/blender/editors/include/ED_keyframes_draw.h
@@ -34,6 +34,7 @@
struct bAnimContext;
struct AnimData;
+struct CacheFile;
struct FCurve;
struct bDopeSheet;
struct bAction;
@@ -80,7 +81,7 @@ typedef struct ActKeyBlock {
/* key-block info */
char sel;
- short handle_type;
+ short flag;
float val;
float start, end;
@@ -89,6 +90,12 @@ typedef struct ActKeyBlock {
short totcurve;
} ActKeyBlock;
+/* ActKeyBlock - Flag */
+typedef enum eActKeyBlock_Flag {
+ /* Key block represents a moving hold */
+ ACTKEYBLOCK_FLAG_MOVING_HOLD = (1 << 0),
+} eActKeyBlock_Flag;
+
/* *********************** Keyframe Drawing ****************************** */
/* options for keyframe shape drawing */
@@ -108,23 +115,23 @@ void draw_keyframe_shape(float x, float y, float xscale, float hsize, short sel,
/* Channel Drawing ------------------ */
/* F-Curve */
-void draw_fcurve_channel(struct View2D *v2d, struct AnimData *adt, struct FCurve *fcu, float ypos);
+void draw_fcurve_channel(struct View2D *v2d, struct AnimData *adt, struct FCurve *fcu, float ypos, float yscale_fac);
/* Action Group Summary */
-void draw_agroup_channel(struct View2D *v2d, struct AnimData *adt, struct bActionGroup *agrp, float ypos);
+void draw_agroup_channel(struct View2D *v2d, struct AnimData *adt, struct bActionGroup *agrp, float ypos, float yscale_fac);
/* Action Summary */
-void draw_action_channel(struct View2D *v2d, struct AnimData *adt, struct bAction *act, float ypos);
+void draw_action_channel(struct View2D *v2d, struct AnimData *adt, struct bAction *act, float ypos, float yscale_fac);
/* Object Summary */
-void draw_object_channel(struct View2D *v2d, struct bDopeSheet *ads, struct Object *ob, float ypos);
+void draw_object_channel(struct View2D *v2d, struct bDopeSheet *ads, struct Object *ob, float ypos, float yscale_fac);
/* Scene Summary */
-void draw_scene_channel(struct View2D *v2d, struct bDopeSheet *ads, struct Scene *sce, float ypos);
+void draw_scene_channel(struct View2D *v2d, struct bDopeSheet *ads, struct Scene *sce, float ypos, float yscale_fac);
/* DopeSheet Summary */
-void draw_summary_channel(struct View2D *v2d, struct bAnimContext *ac, float ypos);
+void draw_summary_channel(struct View2D *v2d, struct bAnimContext *ac, float ypos, float yscale_fac);
/* Grease Pencil datablock summary */
-void draw_gpencil_channel(struct View2D *v2d, struct bDopeSheet *ads, struct bGPdata *gpd, float ypos);
+void draw_gpencil_channel(struct View2D *v2d, struct bDopeSheet *ads, struct bGPdata *gpd, float ypos, float yscale_fac);
/* Grease Pencil Layer */
-void draw_gpl_channel(struct View2D *v2d, struct bDopeSheet *ads, struct bGPDlayer *gpl, float ypos);
+void draw_gpl_channel(struct View2D *v2d, struct bDopeSheet *ads, struct bGPDlayer *gpl, float ypos, float yscale_fac);
/* Mask Layer */
-void draw_masklay_channel(struct View2D *v2d, struct bDopeSheet *ads, struct MaskLayer *masklay, float ypos);
+void draw_masklay_channel(struct View2D *v2d, struct bDopeSheet *ads, struct MaskLayer *masklay, float ypos, float yscale_fac);
/* Keydata Generation --------------- */
/* F-Curve */
@@ -135,6 +142,8 @@ void agroup_to_keylist(struct AnimData *adt, struct bActionGroup *agrp, struct D
void action_to_keylist(struct AnimData *adt, struct bAction *act, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
/* Object */
void ob_to_keylist(struct bDopeSheet *ads, struct Object *ob, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
+/* Cache File */
+void cachefile_to_keylist(struct bDopeSheet *ads, struct CacheFile *cache_file, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
/* Scene */
void scene_to_keylist(struct bDopeSheet *ads, struct Scene *sce, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
/* DopeSheet Summary */
diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h
index fae3e3677a0..c0eb88cd982 100644
--- a/source/blender/editors/include/ED_keyframes_edit.h
+++ b/source/blender/editors/include/ED_keyframes_edit.h
@@ -45,14 +45,21 @@ struct Scene;
/* bezt validation */
typedef enum eEditKeyframes_Validate {
+ /* Frame range */
BEZT_OK_FRAME = 1,
BEZT_OK_FRAMERANGE,
+ /* Selection status */
BEZT_OK_SELECTED,
+ /* Values (y-val) only */
BEZT_OK_VALUE,
BEZT_OK_VALUERANGE,
+ /* For graph editor keyframes (2D tests) */
BEZT_OK_REGION,
BEZT_OK_REGION_LASSO,
BEZT_OK_REGION_CIRCLE,
+ /* Only for keyframes a certain Dopesheet channel */
+ BEZT_OK_CHANNEL_LASSO,
+ BEZT_OK_CHANNEL_CIRCLE,
} eEditKeyframes_Validate;
/* ------------ */
@@ -97,20 +104,20 @@ typedef enum eEditKeyframes_Mirror {
} eEditKeyframes_Mirror;
/* use with BEZT_OK_REGION_LASSO */
-struct KeyframeEdit_LassoData {
- const rctf *rectf_scaled;
+typedef struct KeyframeEdit_LassoData {
+ rctf *rectf_scaled;
const rctf *rectf_view;
const int (*mcords)[2];
int mcords_tot;
-};
+} KeyframeEdit_LassoData;
/* use with BEZT_OK_REGION_CIRCLE */
-struct KeyframeEdit_CircleData {
- const rctf *rectf_scaled;
+typedef struct KeyframeEdit_CircleData {
+ rctf *rectf_scaled;
const rctf *rectf_view;
float mval[2];
float radius_squared;
-};
+} KeyframeEdit_CircleData;
/* ************************************************ */
@@ -157,7 +164,8 @@ typedef struct KeyframeEditData {
/* current iteration data */
struct FCurve *fcu; /* F-Curve that is being iterated over */
int curIndex; /* index of current keyframe being iterated over */
-
+ float channel_y; /* y-position of midpoint of the channel (for the dopesheet) */
+
/* flags */
eKeyframeVertOk curflags; /* current flags for the keyframe we're reached in the iteration process */
eKeyframeIterFlags iterflags; /* settings for iteration process */
@@ -258,6 +266,18 @@ short bezt_to_cfraelem(KeyframeEditData *ked, struct BezTriple *bezt);
*/
void bezt_remap_times(KeyframeEditData *ked, struct BezTriple *bezt);
+/* ------ 1.5-D Region Testing Uitls (Lasso/Circle Select) ------- */
+/* XXX: These are temporary, until we can unify GP/Mask Keyframe handling and standard FCurve Keyframe handling */
+
+bool keyframe_region_lasso_test(
+ const KeyframeEdit_LassoData *data_lasso,
+ const float xy[2]);
+
+bool keyframe_region_circle_test(
+ const KeyframeEdit_CircleData *data_circle,
+ const float xy[2]);
+
+
/* ************************************************ */
/* Destructive Editing API (keyframes_general.c) */
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index 81e2558e765..07cdff687a3 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -325,18 +325,18 @@ bool ANIM_driver_vars_paste(struct ReportList *reports, struct FCurve *fcu, bool
/* Notes:
* - All the defines for this (User-Pref settings and Per-Scene settings)
* are defined in DNA_userdef_types.h
- * - Scene settings take presidence over those for userprefs, with old files
+ * - Scene settings take precedence over those for userprefs, with old files
* inheriting userpref settings for the scene settings
* - "On/Off + Mode" are stored per Scene, but "settings" are currently stored
* as userprefs
*/
/* Auto-Keying macros for use by various tools */
-/* check if auto-keyframing is enabled (per scene takes presidence) */
+/* check if auto-keyframing is enabled (per scene takes precedence) */
#define IS_AUTOKEY_ON(scene) ((scene) ? (scene->toolsettings->autokey_mode & AUTOKEY_ON) : (U.autokey_mode & AUTOKEY_ON))
-/* check the mode for auto-keyframing (per scene takes presidence) */
+/* check the mode for auto-keyframing (per scene takes precedence) */
#define IS_AUTOKEY_MODE(scene, mode) ((scene) ? (scene->toolsettings->autokey_mode == AUTOKEY_MODE_##mode) : (U.autokey_mode == AUTOKEY_MODE_##mode))
-/* check if a flag is set for auto-keyframing (per scene takes presidence) */
+/* check if a flag is set for auto-keyframing (per scene takes precedence) */
#define IS_AUTOKEY_FLAG(scene, flag) \
((scene) ? \
((scene->toolsettings->autokey_flag & AUTOKEY_FLAG_##flag) || (U.autokey_flag & AUTOKEY_FLAG_##flag)) \
@@ -389,6 +389,7 @@ bool ED_autokeyframe_pchan(struct bContext *C, struct Scene *scene, struct Objec
#define ANIM_KS_LOC_ROT_SCALE_ID "LocRotScale"
#define ANIM_KS_AVAILABLE_ID "Available"
#define ANIM_KS_WHOLE_CHARACTER_ID "WholeCharacter"
+#define ANIM_KS_WHOLE_CHARACTER_SELECTED_ID "WholeCharacterSelected"
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h
index 1f13b46ff2a..2ab788d5e2a 100644
--- a/source/blender/editors/include/ED_mask.h
+++ b/source/blender/editors/include/ED_mask.h
@@ -35,6 +35,7 @@ struct bContext;
struct wmKeyConfig;
struct MaskLayer;
struct MaskLayerShape;
+struct KeyframeEditData;
/* mask_edit.c */
void ED_mask_get_size(struct ScrArea *sa, int *width, int *height);
@@ -80,6 +81,7 @@ void ED_masklayer_make_cfra_list(struct MaskLayer *masklay, ListBase *elems, boo
bool ED_masklayer_frame_select_check(struct MaskLayer *masklay);
void ED_masklayer_frame_select_set(struct MaskLayer *masklay, short mode);
void ED_masklayer_frames_select_border(struct MaskLayer *masklay, float min, float max, short select_mode);
+void ED_masklayer_frames_select_region(struct KeyframeEditData *ked, struct MaskLayer *masklay, short tool, short select_mode);
void ED_mask_select_frames(struct MaskLayer *masklay, short select_mode);
void ED_mask_select_frame(struct MaskLayer *masklay, int selx, short select_mode);
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index 7fe9a0c320c..f7b9d6b4f9e 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -103,8 +103,6 @@ void ED_node_set_active(struct Main *bmain, struct bNodeTree *ntree, struct bNod
void ED_node_composite_job(const struct bContext *C, struct bNodeTree *nodetree, struct Scene *scene_owner);
-void ED_node_id_unref(struct SpaceNode *snode, const ID *id);
-
/* node_ops.c */
void ED_operatormacros_node(void);
diff --git a/source/blender/editors/include/ED_numinput.h b/source/blender/editors/include/ED_numinput.h
index f9a22429fc2..00558a3a787 100644
--- a/source/blender/editors/include/ED_numinput.h
+++ b/source/blender/editors/include/ED_numinput.h
@@ -30,6 +30,8 @@
#define NUM_STR_REP_LEN 64
#define NUM_MAX_ELEMENTS 3
+struct wmEvent;
+
typedef struct NumInput {
short idx_max; /* idx_max < NUM_MAX_ELEMENTS */
int unit_sys;
diff --git a/source/blender/editors/include/ED_outliner.h b/source/blender/editors/include/ED_outliner.h
index af4af8e2f5d..73ee2542247 100644
--- a/source/blender/editors/include/ED_outliner.h
+++ b/source/blender/editors/include/ED_outliner.h
@@ -27,10 +27,4 @@
#ifndef __ED_OUTLINER_H__
#define __ED_OUTLINER_H__
-struct ID;
-struct SpaceOops;
-
-/* Used to check whether a given texture context is valid in current context. */
-void ED_outliner_id_unref(struct SpaceOops *so, const struct ID *id);
-
#endif /* __ED_OUTLINER_H__ */
diff --git a/source/blender/editors/include/ED_physics.h b/source/blender/editors/include/ED_physics.h
index 584e9a92bb6..fed842c969e 100644
--- a/source/blender/editors/include/ED_physics.h
+++ b/source/blender/editors/include/ED_physics.h
@@ -45,12 +45,12 @@ int PE_hair_poll(struct bContext *C);
int PE_poll_view3d(struct bContext *C);
/* rigidbody_object.c */
-bool ED_rigidbody_object_add(struct Scene *scene, struct Object *ob, int type, struct ReportList *reports);
-void ED_rigidbody_object_remove(struct Scene *scene, struct Object *ob);
+bool ED_rigidbody_object_add(struct Main *bmain, struct Scene *scene, struct Object *ob, int type, struct ReportList *reports);
+void ED_rigidbody_object_remove(struct Main *bmain, struct Scene *scene, struct Object *ob);
/* rigidbody_constraint.c */
-bool ED_rigidbody_constraint_add(struct Scene *scene, struct Object *ob, int type, struct ReportList *reports);
-void ED_rigidbody_constraint_remove(struct Scene *scene, struct Object *ob);
+bool ED_rigidbody_constraint_add(struct Main *bmain, struct Scene *scene, struct Object *ob, int type, struct ReportList *reports);
+void ED_rigidbody_constraint_remove(struct Main *bmain, struct Scene *scene, struct Object *ob);
/* operators */
void ED_operatortypes_physics(void);
diff --git a/source/blender/editors/include/ED_screen_types.h b/source/blender/editors/include/ED_screen_types.h
index effecf43839..1c41b14a874 100644
--- a/source/blender/editors/include/ED_screen_types.h
+++ b/source/blender/editors/include/ED_screen_types.h
@@ -42,6 +42,7 @@ typedef struct ScreenAnimData {
int sfra; /* frame that playback was started from */
int nextfra; /* next frame to go to (when ANIMPLAY_FLAG_USE_NEXT_FRAME is set) */
double last_duration; /* used for frame dropping */
+ bool from_anim_edit; /* playback was invoked from animation editor */
} ScreenAnimData;
/* for animplayer */
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index 933f480a554..ebd2a3dcb7a 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -45,6 +45,7 @@ struct wmKeyMap;
struct wmOperatorType;
struct Main;
struct SnapObjectContext;
+struct SnapObjectParams;
void transform_keymap_for_space(struct wmKeyConfig *keyconf, struct wmKeyMap *keymap, int spaceid);
void transform_operatortypes(void);
@@ -161,25 +162,27 @@ void BIF_draw_manipulator(const struct bContext *C);
typedef enum SnapSelect {
SNAP_ALL = 0,
SNAP_NOT_SELECTED = 1,
- SNAP_NOT_OBEDIT = 2
+ SNAP_NOT_ACTIVE = 2,
} SnapSelect;
#define SNAP_MIN_DISTANCE 30
bool peelObjectsTransform(
- struct TransInfo *t, const float mval[2],
- SnapSelect snap_select, bool use_peel_object,
+ struct TransInfo *t,
+ const float mval[2],
+ const bool use_peel_object,
/* return args */
float r_loc[3], float r_no[3], float *r_thickness);
bool peelObjectsSnapContext(
struct SnapObjectContext *sctx,
const float mval[2],
- SnapSelect snap_select, bool use_peel_object,
+ const struct SnapObjectParams *params,
+ const bool use_peel_object,
/* return args */
float r_loc[3], float r_no[3], float *r_thickness);
bool snapObjectsTransform(
- struct TransInfo *t, const float mval[2], SnapSelect snap_select,
+ struct TransInfo *t, const float mval[2],
float *dist_px,
/* return args */
float r_loc[3], float r_no[3]);
diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h
index 900b7593f2e..7944b434057 100644
--- a/source/blender/editors/include/ED_transform_snap_object_context.h
+++ b/source/blender/editors/include/ED_transform_snap_object_context.h
@@ -57,17 +57,12 @@ struct SnapObjectHitDepth {
unsigned int ob_uuid;
};
+/** parameters that define which objects will be used to snap. */
struct SnapObjectParams {
- int snap_select; /* SnapSelect */
- union {
- unsigned int snap_to : 4;
- /* snap_target_flag: Snap to vert/edge/face. */
- unsigned int snap_to_flag : 4;
- };
+ /* special context sensitive handling for the active or selected object */
+ char snap_select;
/* use editmode cage */
- unsigned int use_object_edit : 1;
- /* special context sensitive handling for the active object */
- unsigned int use_object_active : 1;
+ unsigned int use_object_edit_cage : 1;
};
enum {
@@ -80,7 +75,7 @@ SnapObjectContext *ED_transform_snap_object_context_create(
SnapObjectContext *ED_transform_snap_object_context_create_view3d(
struct Main *bmain, struct Scene *scene, int flag,
/* extra args for view3d */
- struct ARegion *ar, struct View3D *v3d);
+ const struct ARegion *ar, const struct View3D *v3d);
void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx);
/* callbacks to filter how snap works */
@@ -93,6 +88,7 @@ void ED_transform_snap_object_context_set_editmesh_callbacks(
bool ED_transform_snap_object_project_ray_ex(
struct SnapObjectContext *sctx,
+ const unsigned short snap_to,
const struct SnapObjectParams *params,
const float ray_start[3], const float ray_normal[3], float *ray_depth,
/* return args */
@@ -100,11 +96,13 @@ bool ED_transform_snap_object_project_ray_ex(
struct Object **r_ob, float r_obmat[4][4]);
bool ED_transform_snap_object_project_ray(
SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
const float ray_origin[3], const float ray_direction[3], float *ray_depth,
float r_co[3], float r_no[3]);
bool ED_transform_snap_object_project_ray_all(
SnapObjectContext *sctx,
+ const unsigned short snap_to,
const struct SnapObjectParams *params,
const float ray_start[3], const float ray_normal[3],
float ray_depth, bool sort,
@@ -112,12 +110,14 @@ bool ED_transform_snap_object_project_ray_all(
bool ED_transform_snap_object_project_view3d_ex(
struct SnapObjectContext *sctx,
+ const unsigned short snap_to,
const struct SnapObjectParams *params,
const float mval[2], float *dist_px,
float *ray_depth,
float r_loc[3], float r_no[3], int *r_index);
bool ED_transform_snap_object_project_view3d(
struct SnapObjectContext *sctx,
+ const unsigned short snap_to,
const struct SnapObjectParams *params,
const float mval[2], float *dist_px,
float *ray_depth,
@@ -125,6 +125,7 @@ bool ED_transform_snap_object_project_view3d(
float r_loc[3], float r_no[3]);
bool ED_transform_snap_object_project_view3d_mixed(
SnapObjectContext *sctx,
+ const unsigned short snap_to_flag,
const struct SnapObjectParams *params,
const float mval_fl[2], float *dist_px,
bool use_depth,
diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h
index f143ea478c6..f5968397f65 100644
--- a/source/blender/editors/include/ED_util.h
+++ b/source/blender/editors/include/ED_util.h
@@ -43,7 +43,7 @@ void ED_editors_exit(struct bContext *C);
bool ED_editors_flush_edits(const struct bContext *C, bool for_render);
-void ED_spacedata_id_unref(struct SpaceLink *sl, const struct ID *id);
+void ED_spacedata_id_remap(struct ScrArea *sa, struct SpaceLink *sl, struct ID *old_id, struct ID *new_id);
void ED_OT_flush_edits(struct wmOperatorType *ot);
@@ -78,9 +78,6 @@ void undo_editmode_push(struct bContext *C, const char *name,
void undo_editmode_clear(void);
-/* cut-paste buffer free */
-void ED_clipboard_posebuf_free(void);
-
/* ************** XXX OLD CRUFT WARNING ************* */
void apply_keyb_grid(int shift, int ctrl, float *val, float fac1, float fac2, float fac3, int invert);
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index c23c2eed890..48c1e2d1996 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -208,14 +208,18 @@ eV3DProjStatus ED_view3d_project_float_global(const struct ARegion *ar, const fl
eV3DProjStatus ED_view3d_project_float_object(const struct ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag);
float ED_view3d_calc_zfac(const struct RegionView3D *rv3d, const float co[3], bool *r_flip);
-bool ED_view3d_win_to_ray(const struct ARegion *ar, struct View3D *v3d, const float mval[2],
- float ray_start[3], float ray_normal[3], const bool do_clip);
-bool ED_view3d_win_to_ray_ex(const struct ARegion *ar, struct View3D *v3d, const float mval[2],
- float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip);
+bool ED_view3d_clip_segment(const struct RegionView3D *rv3d, float ray_start[3], float ray_end[3]);
+bool ED_view3d_win_to_ray(
+ const struct ARegion *ar, const struct View3D *v3d, const float mval[2],
+ float ray_start[3], float ray_normal[3], const bool do_clip);
+bool ED_view3d_win_to_ray_ex(
+ const struct ARegion *ar, const struct View3D *v3d, const float mval[2],
+ float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip);
void ED_view3d_global_to_vector(const struct RegionView3D *rv3d, const float coord[3], float vec[3]);
void ED_view3d_win_to_3d(const struct ARegion *ar, const float depth_pt[3], const float mval[2], float out[3]);
void ED_view3d_win_to_3d_int(const struct ARegion *ar, const float depth_pt[3], const int mval[2], float out[3]);
void ED_view3d_win_to_delta(const struct ARegion *ar, const float mval[2], float out[3], const float zfac);
+void ED_view3d_win_to_origin(const struct ARegion *ar, const float mval[2], float out[3]);
void ED_view3d_win_to_vector(const struct ARegion *ar, const float mval[2], float out[3]);
bool ED_view3d_win_to_segment(const struct ARegion *ar, struct View3D *v3d, const float mval[2],
float r_ray_start[3], float r_ray_end[3], const bool do_clip);
@@ -403,4 +407,6 @@ void ED_view3d_shade_update(struct Main *bmain, struct Scene *scene, struct View
#define V3D_IS_ZBUF(v3d) \
(((v3d)->flag & V3D_ZBUF_SELECT) && ((v3d)->drawtype > OB_WIRE))
+void ED_view3d_id_remap(struct View3D *v3d, const struct ID *old_id, struct ID *new_id);
+
#endif /* __ED_VIEW3D_H__ */
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index 76ff9e0fbd8..e016e014a1a 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -320,9 +320,9 @@ DEF_ICON(OUTLINER_OB_SPEAKER)
DEF_ICON(BLANK123)
DEF_ICON(BLANK124)
DEF_ICON(BLANK125)
- DEF_ICON(BLANK126)
- DEF_ICON(BLANK127)
#endif
+DEF_ICON(RESTRICT_COLOR_OFF)
+DEF_ICON(RESTRICT_COLOR_ON)
DEF_ICON(RESTRICT_VIEW_OFF)
DEF_ICON(RESTRICT_VIEW_ON)
DEF_ICON(RESTRICT_SELECT_OFF)
@@ -1020,3 +1020,26 @@ DEF_VICO(KEYTYPE_KEYFRAME_VEC)
DEF_VICO(KEYTYPE_BREAKDOWN_VEC)
DEF_VICO(KEYTYPE_EXTREME_VEC)
DEF_VICO(KEYTYPE_JITTER_VEC)
+DEF_VICO(KEYTYPE_MOVING_HOLD_VEC)
+
+DEF_VICO(COLORSET_01_VEC)
+DEF_VICO(COLORSET_02_VEC)
+DEF_VICO(COLORSET_03_VEC)
+DEF_VICO(COLORSET_04_VEC)
+DEF_VICO(COLORSET_05_VEC)
+DEF_VICO(COLORSET_06_VEC)
+DEF_VICO(COLORSET_07_VEC)
+DEF_VICO(COLORSET_08_VEC)
+DEF_VICO(COLORSET_09_VEC)
+DEF_VICO(COLORSET_10_VEC)
+DEF_VICO(COLORSET_11_VEC)
+DEF_VICO(COLORSET_12_VEC)
+DEF_VICO(COLORSET_13_VEC)
+DEF_VICO(COLORSET_14_VEC)
+DEF_VICO(COLORSET_15_VEC)
+DEF_VICO(COLORSET_16_VEC)
+DEF_VICO(COLORSET_17_VEC)
+DEF_VICO(COLORSET_18_VEC)
+DEF_VICO(COLORSET_19_VEC)
+DEF_VICO(COLORSET_20_VEC)
+
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 9aad340d2fb..fd5351394c3 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -161,13 +161,13 @@ enum {
UI_BUT_NODE_LINK = (1 << 8),
UI_BUT_NODE_ACTIVE = (1 << 9),
UI_BUT_DRAG_LOCK = (1 << 10),
- UI_BUT_DISABLED = (1 << 11),
+ UI_BUT_DISABLED = (1 << 11), /* grayed out and uneditable */
UI_BUT_COLOR_LOCK = (1 << 12),
UI_BUT_ANIMATED = (1 << 13),
UI_BUT_ANIMATED_KEY = (1 << 14),
UI_BUT_DRIVEN = (1 << 15),
UI_BUT_REDALERT = (1 << 16),
- UI_BUT_INACTIVE = (1 << 17),
+ UI_BUT_INACTIVE = (1 << 17), /* grayed out but still editable */
UI_BUT_LAST_ACTIVE = (1 << 18),
UI_BUT_UNDO = (1 << 19),
UI_BUT_IMMEDIATE = (1 << 20),
@@ -382,13 +382,19 @@ typedef bool (*uiMenuStepFunc)(struct bContext *C, int direction, void *arg1);
typedef struct uiPopupMenu uiPopupMenu;
-struct uiPopupMenu *UI_popup_menu_begin(struct bContext *C, const char *title, int icon) ATTR_NONNULL();
+uiPopupMenu *UI_popup_menu_begin(
+ struct bContext *C, const char *title, int icon) ATTR_NONNULL();
+uiPopupMenu *UI_popup_menu_begin_ex(
+ struct bContext *C, const char *title, const char *block_name,
+ int icon) ATTR_NONNULL();
void UI_popup_menu_end(struct bContext *C, struct uiPopupMenu *head);
struct uiLayout *UI_popup_menu_layout(uiPopupMenu *head);
void UI_popup_menu_reports(struct bContext *C, struct ReportList *reports) ATTR_NONNULL();
int UI_popup_menu_invoke(struct bContext *C, const char *idname, struct ReportList *reports) ATTR_NONNULL(1, 2);
+void UI_popup_menu_retval_set(const uiBlock *block, const int retval, const bool enable);
+
/* Pie menus */
typedef struct uiPieMenu uiPieMenu;
@@ -941,6 +947,7 @@ void uiTemplateReportsBanner(uiLayout *layout, struct bContext *C);
void uiTemplateKeymapItemProperties(uiLayout *layout, struct PointerRNA *ptr);
void uiTemplateComponentMenu(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name);
void uiTemplateNodeSocket(uiLayout *layout, struct bContext *C, float *color);
+void uiTemplateCacheFile(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname);
/* Default UIList class name, keep in sync with its declaration in bl_ui/__init__.py */
#define UI_UL_DEFAULT_CLASS_NAME "UI_UL_list"
@@ -1020,12 +1027,18 @@ bool UI_context_copy_to_selected_list(
/* Helpers for Operators */
uiBut *UI_context_active_but_get(const struct bContext *C);
-void UI_context_active_but_prop_get(const struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index);
+uiBut *UI_context_active_but_prop_get(
+ const struct bContext *C,
+ struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index);
void UI_context_active_but_prop_handle(struct bContext *C);
struct wmOperator *UI_context_active_operator_get(const struct bContext *C);
void UI_context_update_anim_flag(const struct bContext *C);
-void UI_context_active_but_prop_get_filebrowser(const struct bContext *C, struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, bool *r_is_undo);
-void UI_context_active_but_prop_get_templateID(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop);
+void UI_context_active_but_prop_get_filebrowser(
+ const struct bContext *C,
+ struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, bool *r_is_undo);
+void UI_context_active_but_prop_get_templateID(
+ struct bContext *C,
+ struct PointerRNA *r_ptr, struct PropertyRNA **r_prop);
/* Styled text draw */
void UI_fontstyle_set(const struct uiFontStyle *fs);
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index dc843952229..f8a5f30a596 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -298,7 +298,10 @@ enum {
TH_V3D_CLIPPING_BORDER,
TH_METADATA_BG,
- TH_METADATA_TEXT
+ TH_METADATA_TEXT,
+
+ TH_EDGE_BEVEL,
+ TH_VERTEX_BEVEL
};
/* XXX WARNING: previous is saved in file, so do not change order! */
@@ -347,6 +350,8 @@ void UI_GetThemeColorShade3ubv(int colorid, int offset, unsigned char col[3])
// get four color values, scaled to 0.0-1.0 range
void UI_GetThemeColor4fv(int colorid, float col[4]);
+// get four color values, range 0.0-1.0, complete with shading offset for the RGB components
+void UI_GetThemeColorShade4fv(int colorid, int offset, float col[4]);
// get the 3 or 4 byte values
void UI_GetThemeColor3ubv(int colorid, unsigned char col[3]);
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index fac1267cc62..6bba35e821f 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -1138,7 +1138,7 @@ static bool ui_but_event_property_operator_string(const bContext *C, uiBut *but,
* as new items are added to the menu later on. It also optimises efficiency -
* a radial menu is best kept symmetrical, with as large an angle between
* items as possible, so that the gestural mouse movements can be fast and inexact.
-
+ *
* It starts off with two opposite sides for the first two items
* then joined by the one below for the third (this way, even with three items,
* the menu seems to still be 'in order' reading left to right). Then the fourth is
@@ -1247,7 +1247,6 @@ void UI_block_end_ex(const bContext *C, uiBlock *block, const int xy[2])
if (ot == NULL || WM_operator_poll_context((bContext *)C, ot, but->opcontext) == 0) {
but->flag |= UI_BUT_DISABLED;
- but->lock = true;
}
if (but->context)
@@ -2576,9 +2575,11 @@ static void ui_set_but_soft_range(uiBut *but)
}
else if (but->poin && (but->pointype & UI_BUT_POIN_TYPES)) {
float value = ui_but_value_get(but);
- CLAMP(value, but->hardmin, but->hardmax);
- but->softmin = min_ff(but->softmin, value);
- but->softmax = max_ff(but->softmax, value);
+ if (isfinite(value)) {
+ CLAMP(value, but->hardmin, but->hardmax);
+ but->softmin = min_ff(but->softmin, value);
+ but->softmax = max_ff(but->softmax, value);
+ }
}
else {
BLI_assert(0);
@@ -3120,8 +3121,7 @@ static uiBut *ui_def_but(
but->a2 = a2;
but->tip = tip;
- but->lock = block->lock;
- but->lockstr = block->lockstr;
+ but->disabled_info = block->lockstr;
but->dt = block->dt;
but->pie_dir = UI_RADIAL_NONE;
@@ -3169,10 +3169,8 @@ static uiBut *ui_def_but(
but->drawflag |= (block->flag & UI_BUT_ALIGN);
- if (but->lock == true) {
- if (but->lockstr) {
- but->flag |= UI_BUT_DISABLED;
- }
+ if (block->lock == true) {
+ but->flag |= UI_BUT_DISABLED;
}
/* keep track of UI_interface.h */
@@ -3217,11 +3215,10 @@ void ui_def_but_icon(uiBut *but, const int icon, const int flag)
}
}
-static void ui_def_but_rna__disable(uiBut *but)
+static void ui_def_but_rna__disable(uiBut *but, const char *info)
{
but->flag |= UI_BUT_DISABLED;
- but->lock = true;
- but->lockstr = "";
+ but->disabled_info = info;
}
static void ui_def_but_rna__menu(bContext *UNUSED(C), uiLayout *layout, void *but_p)
@@ -3486,8 +3483,9 @@ static uiBut *ui_def_but_rna(
but->flag |= UI_BUT_ICON_SUBMENU;
}
- if (!RNA_property_editable(&but->rnapoin, prop)) {
- ui_def_but_rna__disable(but);
+ const char *info;
+ if (!RNA_property_editable_info(&but->rnapoin, prop, &info)) {
+ ui_def_but_rna__disable(but, info);
}
if (but->flag & UI_BUT_UNDO && (ui_but_is_rna_undo(but) == false)) {
@@ -3518,7 +3516,7 @@ static uiBut *ui_def_but_rna_propname(uiBlock *block, int type, int retval, cons
else {
but = ui_def_but(block, type, retval, propname, x, y, width, height, NULL, min, max, a1, a2, tip);
- ui_def_but_rna__disable(but);
+ ui_def_but_rna__disable(but, "Unknown Property.");
}
return but;
@@ -3546,8 +3544,7 @@ static uiBut *ui_def_but_operator_ptr(uiBlock *block, int type, wmOperatorType *
if (!ot) {
but->flag |= UI_BUT_DISABLED;
- but->lock = true;
- but->lockstr = "";
+ but->disabled_info = "";
}
return but;
@@ -4323,7 +4320,7 @@ uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxle
/**
- * \param sfunc, bfunc: both get it as \a arg.
+ * \param search_func, bfunc: both get it as \a arg.
* \param arg: user value,
* \param active: when set, button opens with this item visible and selected.
*/
diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c
index 88924495ae5..991cd54fecf 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.c
@@ -179,7 +179,7 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str)
id = (ID *)but->rnapoin.id.data;
if ((id == NULL) || (GS(id->name) == ID_MA) || (GS(id->name) == ID_TE)) {
if (G.debug & G_DEBUG)
- printf("ERROR: create expression failed - invalid id-datablock for adding drivers (%p)\n", id);
+ printf("ERROR: create expression failed - invalid data-block for adding drivers (%p)\n", id);
return false;
}
@@ -272,36 +272,6 @@ void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra)
}
}
-void ui_but_anim_insert_keyframe(bContext *C)
-{
- /* this operator calls UI_context_active_but_prop_get */
- WM_operator_name_call(C, "ANIM_OT_keyframe_insert_button", WM_OP_INVOKE_DEFAULT, NULL);
-}
-
-void ui_but_anim_delete_keyframe(bContext *C)
-{
- /* this operator calls UI_context_active_but_prop_get */
- WM_operator_name_call(C, "ANIM_OT_keyframe_delete_button", WM_OP_INVOKE_DEFAULT, NULL);
-}
-
-void ui_but_anim_clear_keyframe(bContext *C)
-{
- /* this operator calls UI_context_active_but_prop_get */
- WM_operator_name_call(C, "ANIM_OT_keyframe_clear_button", WM_OP_INVOKE_DEFAULT, NULL);
-}
-
-void ui_but_anim_add_driver(bContext *C)
-{
- /* this operator calls UI_context_active_but_prop_get */
- WM_operator_name_call(C, "ANIM_OT_driver_button_add", WM_OP_INVOKE_DEFAULT, NULL);
-}
-
-void ui_but_anim_remove_driver(bContext *C)
-{
- /* this operator calls UI_context_active_but_prop_get */
- WM_operator_name_call(C, "ANIM_OT_driver_button_remove", WM_OP_INVOKE_DEFAULT, NULL);
-}
-
void ui_but_anim_copy_driver(bContext *C)
{
/* this operator calls UI_context_active_but_prop_get */
@@ -313,15 +283,3 @@ void ui_but_anim_paste_driver(bContext *C)
/* this operator calls UI_context_active_but_prop_get */
WM_operator_name_call(C, "ANIM_OT_paste_driver_button", WM_OP_INVOKE_DEFAULT, NULL);
}
-
-void ui_but_anim_add_keyingset(bContext *C)
-{
- /* this operator calls UI_context_active_but_prop_get */
- WM_operator_name_call(C, "ANIM_OT_keyingset_button_add", WM_OP_INVOKE_DEFAULT, NULL);
-}
-
-void ui_but_anim_remove_keyingset(bContext *C)
-{
- /* this operator calls UI_context_active_but_prop_get */
- WM_operator_name_call(C, "ANIM_OT_keyingset_button_remove", WM_OP_INVOKE_DEFAULT, NULL);
-}
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index 8fbc545cb77..01ea1e953fa 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -181,7 +181,6 @@ void UI_draw_roundbox_shade_x(
coldown[1] = max_ff(0.0f, color[1] + shadedown);
coldown[2] = max_ff(0.0f, color[2] + shadedown);
- glShadeModel(GL_SMOOTH);
glBegin(mode);
/* start with corner right-bottom */
@@ -260,7 +259,6 @@ void UI_draw_roundbox_shade_x(
}
glEnd();
- glShadeModel(GL_FLAT);
}
/* linear vertical shade within button or in outline */
@@ -291,7 +289,6 @@ void UI_draw_roundbox_shade_y(
colRight[1] = max_ff(0.0f, color[1] + shadeRight);
colRight[2] = max_ff(0.0f, color[2] + shadeRight);
- glShadeModel(GL_SMOOTH);
glBegin(mode);
/* start with corner right-bottom */
@@ -367,7 +364,6 @@ void UI_draw_roundbox_shade_y(
}
glEnd();
- glShadeModel(GL_FLAT);
}
/* plain antialiased unfilled rectangle */
@@ -531,7 +527,6 @@ static void histogram_draw_one(
}
else {
/* under the curve */
- glShadeModel(GL_FLAT);
glBegin(GL_TRIANGLE_STRIP);
glVertex2f(x, y);
glVertex2f(x, y + (data[0] * h));
@@ -739,24 +734,50 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol),
CLAMP(max, rect.ymin, rect.ymax);
fdrawline(rect.xmax - 3, min, rect.xmax - 3, max);
}
+ /* RGB (3 channel) */
+ else if (scopes->wavefrm_mode == SCOPES_WAVEFRM_RGB) {
+ glBlendFunc(GL_ONE, GL_ONE);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+
+ glPushMatrix();
+
+ glTranslatef(rect.xmin, yofs, 0.f);
+ glScalef(w, h, 0.f);
+
+ glColor3fv( colors_alpha[0] );
+ glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_1);
+ glDrawArrays(GL_POINTS, 0, scopes->waveform_tot);
+
+ glColor3fv( colors_alpha[1] );
+ glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_2);
+ glDrawArrays(GL_POINTS, 0, scopes->waveform_tot);
+
+ glColor3fv( colors_alpha[2] );
+ glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_3);
+ glDrawArrays(GL_POINTS, 0, scopes->waveform_tot);
- /* RGB / YCC (3 channels) */
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glPopMatrix();
+ }
+ /* PARADE / YCC (3 channels) */
else if (ELEM(scopes->wavefrm_mode,
- SCOPES_WAVEFRM_RGB,
+ SCOPES_WAVEFRM_RGB_PARADE,
SCOPES_WAVEFRM_YCC_601,
SCOPES_WAVEFRM_YCC_709,
- SCOPES_WAVEFRM_YCC_JPEG))
+ SCOPES_WAVEFRM_YCC_JPEG
+ ))
{
- int rgb = (scopes->wavefrm_mode == SCOPES_WAVEFRM_RGB);
-
+ int rgb = (scopes->wavefrm_mode == SCOPES_WAVEFRM_RGB_PARADE);
+
glBlendFunc(GL_ONE, GL_ONE);
-
+
glPushMatrix();
glEnableClientState(GL_VERTEX_ARRAY);
-
+
glTranslatef(rect.xmin, yofs, 0.f);
glScalef(w3, h, 0.f);
-
+
glColor3fv((rgb) ? colors_alpha[0] : colorsycc_alpha[0]);
glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_1);
glDrawArrays(GL_POINTS, 0, scopes->waveform_tot);
@@ -765,19 +786,19 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol),
glColor3fv((rgb) ? colors_alpha[1] : colorsycc_alpha[1]);
glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_2);
glDrawArrays(GL_POINTS, 0, scopes->waveform_tot);
-
+
glTranslatef(1.f, 0.f, 0.f);
glColor3fv((rgb) ? colors_alpha[2] : colorsycc_alpha[2]);
glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_3);
glDrawArrays(GL_POINTS, 0, scopes->waveform_tot);
-
+
glDisableClientState(GL_VERTEX_ARRAY);
glPopMatrix();
-
-
- /* min max */
+ }
+ /* min max */
+ if (scopes->wavefrm_mode != SCOPES_WAVEFRM_LUMA ) {
for (int c = 0; c < 3; c++) {
- if (scopes->wavefrm_mode == SCOPES_WAVEFRM_RGB)
+ if (ELEM(scopes->wavefrm_mode, SCOPES_WAVEFRM_RGB_PARADE, SCOPES_WAVEFRM_RGB))
glColor3f(colors[c][0] * 0.75f, colors[c][1] * 0.75f, colors[c][2] * 0.75f);
else
glColor3f(colorsycc[c][0] * 0.75f, colorsycc[c][1] * 0.75f, colorsycc[c][2] * 0.75f);
@@ -1087,7 +1108,6 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti
GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
/* layer: color ramp */
- glShadeModel(GL_FLAT);
glEnable(GL_BLEND);
CBData *cbd = coba->data;
@@ -1133,7 +1153,6 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti
glEnd();
glDisable(GL_BLEND);
- glShadeModel(GL_SMOOTH);
/* layer: box outline */
glColor4f(0.0, 0.0, 0.0, 1.0);
@@ -1212,9 +1231,8 @@ void ui_draw_but_UNITVEC(uiBut *but, uiWidgetColors *wcol, const rcti *rect)
qobj = gluNewQuadric();
gluQuadricDrawStyle(qobj, GLU_FILL);
- glShadeModel(GL_SMOOTH);
+ GPU_basic_shader_bind(GPU_basic_shader_bound_options());
gluSphere(qobj, 100.0, 32, 24);
- glShadeModel(GL_FLAT);
gluDeleteQuadric(qobj);
glEndList();
@@ -1237,6 +1255,9 @@ void ui_draw_but_UNITVEC(uiBut *but, uiWidgetColors *wcol, const rcti *rect)
/* matrix after circle */
glPopMatrix();
+
+ /* We disabled all blender lights above, so restore them here. */
+ GPU_default_lights();
}
static void ui_draw_but_curve_grid(const rcti *rect, float zoomx, float zoomy, float offsx, float offsy, float step)
@@ -1545,10 +1566,12 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wc
BLI_rctf_size_x(&rect),
BLI_rctf_size_y(&rect));
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE);
+
for (int a = 0; a < 2; a++) {
if (a == 1) {
- glLineStipple(3, 0xaaaa);
- glEnable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_enable(GPU_SHADER_STIPPLE);
+ GPU_basic_shader_line_stipple(3, 0xAAAA);
UI_ThemeColor(TH_SEL_MARKER);
}
else {
@@ -1562,9 +1585,10 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wc
glVertex2f(0.0f, 10.0f);
glEnd();
}
+
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
}
- glDisable(GL_LINE_STIPPLE);
glPopMatrix();
ok = true;
@@ -1677,7 +1701,6 @@ static void ui_shadowbox(float minx, float miny, float maxx, float maxy, float s
void UI_draw_box_shadow(unsigned char alpha, float minx, float miny, float maxx, float maxy)
{
glEnable(GL_BLEND);
- glShadeModel(GL_SMOOTH);
glBegin(GL_QUADS);
@@ -1689,7 +1712,6 @@ void UI_draw_box_shadow(unsigned char alpha, float minx, float miny, float maxx,
glEnd();
glDisable(GL_BLEND);
- glShadeModel(GL_FLAT);
}
diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c
index 2cbc56b14d3..31598a44b09 100644
--- a/source/blender/editors/interface/interface_eyedropper.c
+++ b/source/blender/editors/interface/interface_eyedropper.c
@@ -448,8 +448,20 @@ static int eyedropper_exec(bContext *C, wmOperator *op)
static int eyedropper_poll(bContext *C)
{
- if (!CTX_wm_window(C)) return 0;
- else return 1;
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index_dummy;
+ uiBut *but;
+
+ /* Only color buttons */
+ if ((CTX_wm_window(C) != NULL) &&
+ (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
+ (but->type == UI_BTYPE_COLOR))
+ {
+ return 1;
+ }
+
+ return 0;
}
void UI_OT_eyedropper_color(wmOperatorType *ot)
@@ -727,16 +739,35 @@ static int datadropper_exec(bContext *C, wmOperator *op)
static int datadropper_poll(bContext *C)
{
- if (!CTX_wm_window(C)) return 0;
- else return 1;
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index_dummy;
+ uiBut *but;
+
+ /* data dropper only supports object data */
+ if ((CTX_wm_window(C) != NULL) &&
+ (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
+ (but->type == UI_BTYPE_SEARCH_MENU) &&
+ (but->flag & UI_BUT_SEARCH_UNLINK))
+ {
+ if (prop && RNA_property_type(prop) == PROP_POINTER) {
+ StructRNA *type = RNA_property_pointer_type(&ptr, prop);
+ const short idcode = RNA_type_to_ID_code(type);
+ if ((idcode == ID_OB) || OB_DATA_SUPPORT_ID(idcode)) {
+ return 1;
+ }
+ }
+ }
+
+ return 0;
}
void UI_OT_eyedropper_id(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Eyedropper Datablock";
+ ot->name = "Eyedropper Data-Block";
ot->idname = "UI_OT_eyedropper_id";
- ot->description = "Sample a datablock from the 3D View to store in a property";
+ ot->description = "Sample a data-block from the 3D View to store in a property";
/* api callbacks */
ot->invoke = datadropper_invoke;
@@ -805,7 +836,7 @@ static int depthdropper_init(bContext *C, wmOperator *op)
RegionView3D *rv3d = CTX_wm_region_view3d(C);
if (rv3d && rv3d->persp == RV3D_CAMOB) {
View3D *v3d = CTX_wm_view3d(C);
- if (v3d->camera && v3d->camera->data && (((ID *)v3d->camera->data)->lib == NULL)) {
+ if (v3d->camera && v3d->camera->data && !ID_IS_LINKED_DATABLOCK(v3d->camera->data)) {
RNA_id_pointer_create(v3d->camera->data, &ddr->ptr);
ddr->prop = RNA_struct_find_property(&ddr->ptr, "dof_distance");
}
@@ -1034,8 +1065,26 @@ static int depthdropper_exec(bContext *C, wmOperator *op)
static int depthdropper_poll(bContext *C)
{
- if (!CTX_wm_window(C)) return 0;
- else return 1;
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index_dummy;
+ uiBut *but;
+
+ /* check if there's an active button taking depth value */
+ if ((CTX_wm_window(C) != NULL) &&
+ (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
+ (but->type == UI_BTYPE_NUM) &&
+ (prop != NULL))
+ {
+ if ((RNA_property_type(prop) == PROP_FLOAT) &&
+ (RNA_property_subtype(prop) & PROP_UNIT_LENGTH) &&
+ (RNA_property_array_check(prop) == false))
+ {
+ return 1;
+ }
+ }
+
+ return 0;
}
void UI_OT_eyedropper_depth(wmOperatorType *ot)
@@ -1084,12 +1133,11 @@ static bool driverdropper_init(bContext *C, wmOperator *op)
{
DriverDropper *ddr;
uiBut *but;
-
+
op->customdata = ddr = MEM_callocN(sizeof(DriverDropper), "DriverDropper");
-
- UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &ddr->index);
- but = UI_context_active_but_get(C);
-
+
+ but = UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &ddr->index);
+
if ((ddr->ptr.data == NULL) ||
(ddr->prop == NULL) ||
(RNA_property_editable(&ddr->ptr, ddr->prop) == false) ||
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 10ab85a6142..863f5e3852c 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -634,6 +634,15 @@ PointerRNA *ui_handle_afterfunc_add_operator(wmOperatorType *ot, int opcontext,
return ptr;
}
+/**
+ * Check if a #uiAfterFunc is needed for this button.
+ */
+static bool ui_afterfunc_check(const uiBlock *block, const uiBut *but)
+{
+ return (but->func || but->funcN || but->rename_func || but->optype || but->rnaprop || block->handle_func ||
+ (but->type == UI_BTYPE_BUT_MENU && block->butm_func));
+}
+
static void ui_apply_but_func(bContext *C, uiBut *but)
{
uiAfterFunc *after;
@@ -643,9 +652,7 @@ static void ui_apply_but_func(bContext *C, uiBut *but)
* handling is done, i.e. menus are closed, in order to avoid conflicts
* with these functions removing the buttons we are working with */
- if (but->func || but->funcN || block->handle_func || but->rename_func ||
- (but->type == UI_BTYPE_BUT_MENU && block->butm_func) || but->optype || but->rnaprop)
- {
+ if (ui_afterfunc_check(block, but)) {
after = ui_afterfunc_new();
if (but->func && ELEM(but, but->func_arg1, but->func_arg2)) {
@@ -899,7 +906,8 @@ static void ui_apply_but_TEX(bContext *C, uiBut *but, uiHandleButtonData *data)
* having typed something already. */
but->rename_orig = BLI_strdup(data->origstr);
}
- else {
+ /* only if there are afterfuncs, otherwise 'renam_orig' isn't freed */
+ else if (ui_afterfunc_check(but->block, but)) {
but->rename_orig = data->origstr;
data->origstr = NULL;
}
@@ -1049,7 +1057,9 @@ static void ui_multibut_free(uiHandleButtonData *data, uiBlock *block)
}
}
-static bool ui_multibut_states_tag(uiBut *but_active, uiHandleButtonData *data, const wmEvent *event)
+static bool ui_multibut_states_tag(
+ uiBut *but_active,
+ uiHandleButtonData *data, const wmEvent *event)
{
uiBut *but;
float seg[2][2];
@@ -1256,6 +1266,10 @@ static bool ui_drag_toggle_set_xy_xy(
}
}
}
+ if (changed) {
+ /* apply now, not on release (or if handlers are cancelled for whatever reason) */
+ ui_apply_but_funcs_after(C);
+ }
return changed;
}
@@ -1660,7 +1674,9 @@ static bool ui_but_contains_point_px_icon(uiBut *but, ARegion *ar, const wmEvent
return BLI_rcti_isect_pt(&rect, x, y);
}
-static bool ui_but_drag_init(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static bool ui_but_drag_init(
+ bContext *C, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
/* prevent other WM gestures to start while we try to drag */
WM_gestures_remove(C);
@@ -1732,11 +1748,16 @@ static bool ui_but_drag_init(bContext *C, uiBut *but, uiHandleButtonData *data,
}
}
else {
- wmDrag *drag;
+ wmDrag *drag = WM_event_start_drag(
+ C, but->icon, but->dragtype, but->dragpoin,
+ ui_but_value_get(but), WM_DRAG_NOP);
- drag = WM_event_start_drag(C, but->icon, but->dragtype, but->dragpoin, ui_but_value_get(but), WM_DRAG_NOP);
- if (but->imb)
- WM_event_drag_image(drag, but->imb, but->imb_scale, BLI_rctf_size_x(&but->rect), BLI_rctf_size_y(&but->rect));
+ if (but->imb) {
+ WM_event_drag_image(
+ drag, but->imb, but->imb_scale,
+ BLI_rctf_size_x(&but->rect),
+ BLI_rctf_size_y(&but->rect));
+ }
}
return true;
}
@@ -1864,11 +1885,15 @@ static void ui_but_smart_controller_add(bContext *C, uiBut *from, uiBut *to)
/* (3) add a new controller */
if (WM_operator_name_call(C, "LOGIC_OT_controller_add", WM_OP_EXEC_DEFAULT, &props_ptr) & OPERATOR_FINISHED) {
cont = (bController *)ob->controllers.last;
- cont->type = CONT_LOGIC_AND; /* Quick fix to make sure we always have an AND controller. It might be nicer to make sure the operator gives us the right one though... */
+ /* Quick fix to make sure we always have an AND controller.
+ * It might be nicer to make sure the operator gives us the right one though... */
+ cont->type = CONT_LOGIC_AND;
/* (4) link the sensor->controller->actuator */
tmp_but = MEM_callocN(sizeof(uiBut), "uiBut");
- UI_but_link_set(tmp_but, (void **)&cont, (void ***)&(cont->links), &(cont->totlinks), from->link->tocode, (int)to->hardmin);
+ UI_but_link_set(
+ tmp_but, (void **)&cont, (void ***)&(cont->links),
+ &cont->totlinks, from->link->tocode, (int)to->hardmin);
tmp_but->hardmin = from->link->tocode;
tmp_but->poin = (char *)cont;
@@ -2193,32 +2218,6 @@ static void ui_but_drop(bContext *C, const wmEvent *event, uiBut *but, uiHandleB
/* ******************* copy and paste ******************** */
-static void ui_but_copy_data_path(uiBut *but, const bool full_path)
-{
- char *id_path;
-
- if (but->rnapoin.id.data == NULL) {
- return;
- }
-
- if (full_path) {
- if (but->rnaprop) {
- id_path = RNA_path_full_property_py_ex(&but->rnapoin, but->rnaprop, but->rnaindex, true);
- }
- else {
- id_path = RNA_path_full_struct_py(&but->rnapoin);
- }
- }
- else {
- id_path = RNA_path_from_ID_to_property(&but->rnapoin, but->rnaprop);
- }
-
- if (id_path) {
- WM_clipboard_text_set(id_path, false);
- MEM_freeN(id_path);
- }
-}
-
/* c = copy, v = paste */
static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, char mode)
{
@@ -2227,9 +2226,7 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
bool buf_paste_alloc = false;
bool show_report = false; /* use to display errors parsing paste input */
- if (mode == 'v' && but->lock == true) {
- return;
- }
+ BLI_assert((but->flag & UI_BUT_DISABLED) == 0); /* caller should check */
if (mode == 'c') {
/* disallow copying from any passwords */
@@ -3172,7 +3169,9 @@ static void ui_textedit_prev_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa
}
-static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static void ui_do_but_textedit(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
int retval = WM_UI_HANDLER_CONTINUE;
bool changed = false, inbox = false, update = false;
@@ -3225,7 +3224,8 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
if (data->searchbox)
inbox = ui_searchbox_inside(data->searchbox, event->x, event->y);
- /* for double click: we do a press again for when you first click on button (selects all text, no cursor pos) */
+ /* for double click: we do a press again for when you first click on button
+ * (selects all text, no cursor pos) */
if (event->val == KM_PRESS || event->val == KM_DBL_CLICK) {
float mx, my;
@@ -3469,7 +3469,9 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
ED_region_tag_redraw(data->region);
}
-static void ui_do_but_textedit_select(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static void ui_do_but_textedit_select(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
int mx, my, retval = WM_UI_HANDLER_CONTINUE;
@@ -3674,7 +3676,9 @@ static uiBut *ui_but_list_row_text_activate(
/* ***************** events for different button types *************** */
-static int ui_do_but_BUT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_BUT(
+ bContext *C, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
if (event->type == LEFTMOUSE && event->val == KM_PRESS) {
@@ -3705,7 +3709,9 @@ static int ui_do_but_BUT(bContext *C, uiBut *but, uiHandleButtonData *data, cons
return WM_UI_HANDLER_CONTINUE;
}
-static int ui_do_but_HOTKEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_HOTKEYEVT(
+ bContext *C, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
@@ -3768,7 +3774,9 @@ static int ui_do_but_HOTKEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data
return WM_UI_HANDLER_CONTINUE;
}
-static int ui_do_but_KEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_KEYEVT(
+ bContext *C, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
@@ -3794,7 +3802,9 @@ static int ui_do_but_KEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, c
return WM_UI_HANDLER_CONTINUE;
}
-static int ui_do_but_TEX(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_TEX(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
if (ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS) {
@@ -3822,7 +3832,9 @@ static int ui_do_but_TEX(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
return WM_UI_HANDLER_CONTINUE;
}
-static int ui_do_but_SEARCH_UNLINK(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_SEARCH_UNLINK(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
uiButExtraIconType extra_icon_type;
@@ -3869,7 +3881,9 @@ static int ui_do_but_SEARCH_UNLINK(bContext *C, uiBlock *block, uiBut *but, uiHa
return ui_do_but_TEX(C, block, but, data, event);
}
-static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+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) {
@@ -3936,7 +3950,9 @@ static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, cons
return WM_UI_HANDLER_CONTINUE;
}
-static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_EXIT(
+ bContext *C, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
@@ -4084,7 +4100,7 @@ static float ui_numedit_apply_snap(
static bool ui_numedit_but_NUM(
uiBut *but, uiHandleButtonData *data,
- int mx,
+ int mx, const bool is_motion,
const enum eSnapType snap, float fac)
{
float deler, tempf, softmin, softmax, softrange;
@@ -4092,8 +4108,10 @@ static bool ui_numedit_but_NUM(
bool changed = false;
const bool is_float = ui_but_is_float(but);
- /* prevent unwanted drag adjustments */
- if (ui_but_dragedit_update_mval(data, mx) == false) {
+ /* prevent unwanted drag adjustments, test motion so modifier keys refresh. */
+ if ((is_motion || data->draglock) &&
+ (ui_but_dragedit_update_mval(data, mx) == false))
+ {
return changed;
}
@@ -4234,7 +4252,9 @@ static bool ui_numedit_but_NUM(
return changed;
}
-static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_NUM(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
int mx, my; /* mouse location scaled to fit the UI */
int screen_mx, screen_my; /* mouse location kept at screen pixel coords */
@@ -4316,6 +4336,7 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
}
}
else if ((event->type == MOUSEMOVE) || ui_event_is_snap(event)) {
+ const bool is_motion = (event->type == MOUSEMOVE);
const enum eSnapType snap = ui_event_to_snap(event);
float fac;
@@ -4327,8 +4348,9 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
fac = 1.0f;
if (event->shift) fac /= 10.0f;
- if (ui_numedit_but_NUM(but, data, (ui_but_is_cursor_warp(but) ? screen_mx : mx), snap, fac))
+ if (ui_numedit_but_NUM(but, data, (ui_but_is_cursor_warp(but) ? screen_mx : mx), is_motion, snap, fac)) {
ui_numedit_apply(C, block, but, data);
+ }
#ifdef USE_DRAG_MULTINUM
else if (data->multi_data.has_mbuts) {
if (data->multi_data.init == BUTTON_MULTI_INIT_ENABLE) {
@@ -4422,7 +4444,7 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
static bool ui_numedit_but_SLI(
uiBut *but, uiHandleButtonData *data,
- int mx, const bool is_horizontal,
+ int mx, const bool is_horizontal, const bool is_motion,
const bool snap, const bool shift)
{
float deler, f, tempf, softmin, softmax, softrange;
@@ -4432,8 +4454,9 @@ static bool ui_numedit_but_SLI(
/* note, 'offs' is really from the widget drawing rounded corners see 'widget_numslider' */
float offs;
- /* prevent unwanted drag adjustments */
+ /* prevent unwanted drag adjustments, test motion so modifier keys refresh. */
if ((but->type != UI_BTYPE_SCROLL) &&
+ (is_motion || data->draglock) &&
(ui_but_dragedit_update_mval(data, mx) == false))
{
return changed;
@@ -4533,7 +4556,9 @@ static bool ui_numedit_but_SLI(
return changed;
}
-static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_SLI(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
int mx, my, click = 0;
int retval = WM_UI_HANDLER_CONTINUE;
@@ -4626,12 +4651,14 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
}
}
else if ((event->type == MOUSEMOVE) || ui_event_is_snap(event)) {
+ const bool is_motion = (event->type == MOUSEMOVE);
#ifdef USE_DRAG_MULTINUM
data->multi_data.drag_dir[0] += abs(data->draglastx - mx);
data->multi_data.drag_dir[1] += abs(data->draglasty - my);
#endif
- if (ui_numedit_but_SLI(but, data, mx, true, event->ctrl != 0, event->shift != 0))
+ if (ui_numedit_but_SLI(but, data, mx, true, is_motion, event->ctrl != 0, event->shift != 0)) {
ui_numedit_apply(C, block, but, data);
+ }
#ifdef USE_DRAG_MULTINUM
else if (data->multi_data.has_mbuts) {
@@ -4714,7 +4741,9 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
return retval;
}
-static int ui_do_but_SCROLL(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_SCROLL(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
int mx, my /*, click = 0 */;
int retval = WM_UI_HANDLER_CONTINUE;
@@ -4757,8 +4786,10 @@ static int ui_do_but_SCROLL(bContext *C, uiBlock *block, uiBut *but, uiHandleBut
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
else if (event->type == MOUSEMOVE) {
- if (ui_numedit_but_SLI(but, data, (horizontal) ? mx : my, horizontal, false, false))
+ const bool is_motion = (event->type == MOUSEMOVE);
+ if (ui_numedit_but_SLI(but, data, (horizontal) ? mx : my, horizontal, is_motion, false, false)) {
ui_numedit_apply(C, block, but, data);
+ }
}
retval = WM_UI_HANDLER_BREAK;
@@ -4767,7 +4798,9 @@ static int ui_do_but_SCROLL(bContext *C, uiBlock *block, uiBut *but, uiHandleBut
return retval;
}
-static int ui_do_but_GRIP(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_GRIP(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
int mx, my;
int retval = WM_UI_HANDLER_CONTINUE;
@@ -4818,7 +4851,9 @@ static int ui_do_but_GRIP(bContext *C, uiBlock *block, uiBut *but, uiHandleButto
return retval;
}
-static int ui_do_but_LISTROW(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_LISTROW(
+ bContext *C, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
/* hack to pass on ctrl+click and double click to overlapping text
@@ -4838,7 +4873,9 @@ static int ui_do_but_LISTROW(bContext *C, uiBut *but, uiHandleButtonData *data,
return ui_do_but_EXIT(C, but, data, event);
}
-static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_BLOCK(
+ bContext *C, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
@@ -5013,7 +5050,9 @@ static void ui_palette_set_active(uiBut *but)
}
}
-static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_COLOR(
+ bContext *C, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
/* first handle click on icondrag type button */
@@ -5146,7 +5185,9 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
return WM_UI_HANDLER_CONTINUE;
}
-static int ui_do_but_UNITVEC(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_UNITVEC(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
int mx, my;
@@ -5350,6 +5391,7 @@ static bool ui_numedit_but_HSVCUBE(
return changed;
}
+#ifdef WITH_INPUT_NDOF
static void ui_ndofedit_but_HSVCUBE(
uiBut *but, uiHandleButtonData *data,
const wmNDOFMotionData *ndof,
@@ -5422,8 +5464,11 @@ static void ui_ndofedit_but_HSVCUBE(
copy_v3_v3(data->vec, rgb);
ui_but_v3_set(but, data->vec);
}
+#endif /* WITH_INPUT_NDOF */
-static int ui_do_but_HSVCUBE(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_HSVCUBE(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
int mx, my;
@@ -5447,6 +5492,7 @@ static int ui_do_but_HSVCUBE(bContext *C, uiBlock *block, uiBut *but, uiHandleBu
return WM_UI_HANDLER_BREAK;
}
+#ifdef WITH_INPUT_NDOF
else if (event->type == NDOF_MOTION) {
const wmNDOFMotionData *ndof = event->customdata;
const enum eSnapType snap = ui_event_to_snap(event);
@@ -5458,6 +5504,7 @@ static int ui_do_but_HSVCUBE(bContext *C, uiBlock *block, uiBut *but, uiHandleBu
return WM_UI_HANDLER_BREAK;
}
+#endif /* WITH_INPUT_NDOF */
/* XXX hardcoded keymap check.... */
else if (event->type == BACKSPACEKEY && event->val == KM_PRESS) {
if (ELEM(but->a1, UI_GRAD_V_ALT, UI_GRAD_L_ALT)) {
@@ -5599,8 +5646,7 @@ static bool ui_numedit_but_HSVCIRCLE(
ui_color_picker_to_rgb_v(hsv, rgb);
if ((but->flag & UI_BUT_VEC_SIZE_LOCK) && (rgb[0] || rgb[1] || rgb[2])) {
- normalize_v3(rgb);
- mul_v3_fl(rgb, but->a2);
+ normalize_v3_length(rgb, but->a2);
}
if (use_display_colorspace)
@@ -5614,6 +5660,7 @@ static bool ui_numedit_but_HSVCIRCLE(
return changed;
}
+#ifdef WITH_INPUT_NDOF
static void ui_ndofedit_but_HSVCIRCLE(
uiBut *but, uiHandleButtonData *data,
const wmNDOFMotionData *ndof,
@@ -5676,8 +5723,7 @@ static void ui_ndofedit_but_HSVCIRCLE(
ui_color_picker_to_rgb_v(hsv, data->vec);
if ((but->flag & UI_BUT_VEC_SIZE_LOCK) && (data->vec[0] || data->vec[1] || data->vec[2])) {
- normalize_v3(data->vec);
- mul_v3_fl(data->vec, but->a2);
+ normalize_v3_length(data->vec, but->a2);
}
if (use_display_colorspace)
@@ -5685,9 +5731,11 @@ static void ui_ndofedit_but_HSVCIRCLE(
ui_but_v3_set(but, data->vec);
}
+#endif /* WITH_INPUT_NDOF */
-
-static int ui_do_but_HSVCIRCLE(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_HSVCIRCLE(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
ColorPicker *cpicker = but->custom_data;
float *hsv = cpicker->color_data;
@@ -5711,6 +5759,7 @@ static int ui_do_but_HSVCIRCLE(bContext *C, uiBlock *block, uiBut *but, uiHandle
return WM_UI_HANDLER_BREAK;
}
+#ifdef WITH_INPUT_NDOF
else if (event->type == NDOF_MOTION) {
const enum eSnapType snap = ui_event_to_snap(event);
const wmNDOFMotionData *ndof = event->customdata;
@@ -5722,6 +5771,7 @@ static int ui_do_but_HSVCIRCLE(bContext *C, uiBlock *block, uiBut *but, uiHandle
return WM_UI_HANDLER_BREAK;
}
+#endif /* WITH_INPUT_NDOF */
/* XXX hardcoded keymap check.... */
else if (event->type == BACKSPACEKEY && event->val == KM_PRESS) {
int len;
@@ -5815,7 +5865,9 @@ static bool ui_numedit_but_COLORBAND(uiBut *but, uiHandleButtonData *data, int m
return changed;
}
-static int ui_do_but_COLORBAND(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_COLORBAND(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
ColorBand *coba;
CBData *cbd;
@@ -5991,7 +6043,9 @@ static bool ui_numedit_but_CURVE(
return changed;
}
-static int ui_do_but_CURVE(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_CURVE(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
int mx, my, a;
bool changed = false;
@@ -6006,20 +6060,15 @@ static int ui_do_but_CURVE(bContext *C, uiBlock *block, uiBut *but, uiHandleButt
CurveMapping *cumap = (CurveMapping *)but->poin;
CurveMap *cuma = cumap->cm + cumap->cur;
CurveMapPoint *cmp;
- float fx, fy, zoomx, zoomy, offsx, offsy;
- float dist, mindist = 200.0f; // 14 pixels radius
+ const float m_xy[2] = {mx, my};
+ float dist_min_sq = SQUARE(14.0f); /* 14 pixels radius */
int sel = -1;
- zoomx = BLI_rctf_size_x(&but->rect) / BLI_rctf_size_x(&cumap->curr);
- zoomy = BLI_rctf_size_y(&but->rect) / BLI_rctf_size_y(&cumap->curr);
- offsx = cumap->curr.xmin;
- offsy = cumap->curr.ymin;
-
if (event->ctrl) {
- fx = ((float)mx - but->rect.xmin) / zoomx + offsx;
- fy = ((float)my - but->rect.ymin) / zoomy + offsy;
+ float f_xy[2];
+ BLI_rctf_transform_pt_v(&cumap->curr, &but->rect, f_xy, m_xy);
- curvemap_insert(cuma, fx, fy);
+ curvemap_insert(cuma, f_xy[0], f_xy[1]);
curvemapping_changed(cumap, false);
changed = true;
}
@@ -6027,33 +6076,37 @@ static int ui_do_but_CURVE(bContext *C, uiBlock *block, uiBut *but, uiHandleButt
/* check for selecting of a point */
cmp = cuma->curve; /* ctrl adds point, new malloc */
for (a = 0; a < cuma->totpoint; a++) {
- fx = but->rect.xmin + zoomx * (cmp[a].x - offsx);
- fy = but->rect.ymin + zoomy * (cmp[a].y - offsy);
- dist = (fx - mx) * (fx - mx) + (fy - my) * (fy - my);
- if (dist < mindist) {
+ float f_xy[2];
+ BLI_rctf_transform_pt_v(&but->rect, &cumap->curr, f_xy, &cmp[a].x);
+ const float dist_sq = len_squared_v2v2(m_xy, f_xy);
+ if (dist_sq < dist_min_sq) {
sel = a;
- mindist = dist;
+ dist_min_sq = dist_sq;
}
}
if (sel == -1) {
int i;
+ float f_xy[2], f_xy_prev[2];
/* if the click didn't select anything, check if it's clicked on the
* curve itself, and if so, add a point */
- fx = ((float)mx - but->rect.xmin) / zoomx + offsx;
- fy = ((float)my - but->rect.ymin) / zoomy + offsy;
-
cmp = cuma->table;
- /* loop through the curve segment table and find what's near the mouse.
- * 0.05 is kinda arbitrary, but seems to be what works nicely. */
- for (i = 0; i <= CM_TABLE; i++) {
- if ((fabsf(fx - cmp[i].x) < 0.05f) &&
- (fabsf(fy - cmp[i].y) < 0.05f))
- {
-
- curvemap_insert(cuma, fx, fy);
+ BLI_rctf_transform_pt_v(&but->rect, &cumap->curr, f_xy, &cmp[0].x);
+
+ /* with 160px height 8px should translate to the old 0.05 coefficient at no zoom */
+ dist_min_sq = SQUARE(8.0f);
+
+ /* loop through the curve segment table and find what's near the mouse. */
+ for (i = 1; i <= CM_TABLE; i++) {
+ copy_v2_v2(f_xy_prev, f_xy);
+ BLI_rctf_transform_pt_v(&but->rect, &cumap->curr, f_xy, &cmp[i].x);
+
+ if (dist_squared_to_line_segment_v2(m_xy, f_xy_prev, f_xy) < dist_min_sq) {
+ BLI_rctf_transform_pt_v(&cumap->curr, &but->rect, f_xy, m_xy);
+
+ curvemap_insert(cuma, f_xy[0], f_xy[1]);
curvemapping_changed(cumap, false);
changed = true;
@@ -6062,10 +6115,11 @@ static int ui_do_but_CURVE(bContext *C, uiBlock *block, uiBut *but, uiHandleButt
cmp = cuma->curve;
/* find newly added point and make it 'sel' */
- for (a = 0; a < cuma->totpoint; a++)
- if (cmp[a].x == fx)
+ for (a = 0; a < cuma->totpoint; a++) {
+ if (cmp[a].x == f_xy[0]) {
sel = a;
-
+ }
+ }
break;
}
}
@@ -6159,7 +6213,9 @@ static bool ui_numedit_but_HISTOGRAM(uiBut *but, uiHandleButtonData *data, int m
return changed;
}
-static int ui_do_but_HISTOGRAM(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_HISTOGRAM(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
int mx, my;
@@ -6232,7 +6288,9 @@ static bool ui_numedit_but_WAVEFORM(uiBut *but, uiHandleButtonData *data, int mx
return changed;
}
-static int ui_do_but_WAVEFORM(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_WAVEFORM(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
int mx, my;
@@ -6286,7 +6344,9 @@ static int ui_do_but_WAVEFORM(bContext *C, uiBlock *block, uiBut *but, uiHandleB
return WM_UI_HANDLER_CONTINUE;
}
-static int ui_do_but_LINK(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_LINK(
+ bContext *C, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
VECCOPY2D(but->linkto, event->mval);
@@ -6349,7 +6409,9 @@ static bool ui_numedit_but_TRACKPREVIEW(
return changed;
}
-static int ui_do_but_TRACKPREVIEW(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_TRACKPREVIEW(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
int mx, my;
@@ -6845,7 +6907,8 @@ static bool ui_but_menu(bContext *C, uiBut *but)
WM_operator_properties_create(&ptr_props, "WM_OT_doc_view");
RNA_string_set(&ptr_props, "doc_id", buf);
- uiItemFullO(layout, "WM_OT_doc_view", CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Online Python Reference"),
+ uiItemFullO(layout, "WM_OT_doc_view",
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Online Python Reference"),
ICON_NONE, ptr_props.data, WM_OP_EXEC_DEFAULT, 0);
/* XXX inactive option, not for public! */
@@ -6854,7 +6917,8 @@ static bool ui_but_menu(bContext *C, uiBut *but)
RNA_string_set(&ptr_props, "doc_id", buf);
RNA_string_set(&ptr_props, "doc_new", RNA_property_description(but->rnaprop));
- uiItemFullO(layout, "WM_OT_doc_edit", "Submit Description", ICON_NONE, ptr_props.data, WM_OP_INVOKE_DEFAULT, 0);
+ uiItemFullO(layout, "WM_OT_doc_edit",
+ "Submit Description", ICON_NONE, ptr_props.data, WM_OP_INVOKE_DEFAULT, 0);
#endif
}
}
@@ -6886,10 +6950,16 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
if (but->flag & UI_BUT_DISABLED)
return WM_UI_HANDLER_CONTINUE;
+ /* if but->pointype is set, but->poin should be too */
+ BLI_assert(!but->pointype || but->poin);
+
+ /* Only hard-coded stuff here, button interactions with configurable
+ * keymaps are handled using operators (see #ED_keymap_ui). */
+
if ((data->state == BUTTON_STATE_HIGHLIGHT) || (event->type == EVT_DROP)) {
/* handle copy-paste */
if (ELEM(event->type, CKEY, VKEY) && event->val == KM_PRESS &&
- IS_EVENT_MOD(event, ctrl, oskey))
+ IS_EVENT_MOD(event, ctrl, oskey) && !event->shift && !event->alt)
{
/* Specific handling for listrows, we try to find their overlapping tex button. */
if (but->type == UI_BTYPE_LISTROW) {
@@ -6899,13 +6969,6 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
data = but->active;
}
}
-
- /* special case, copy-data-path */
- if ((event->type == CKEY) && event->shift) {
- ui_but_copy_data_path(but, event->alt != 0);
- return WM_UI_HANDLER_BREAK;
- }
-
ui_but_copy_paste(C, but, data, (event->type == CKEY) ? 'c' : 'v');
return WM_UI_HANDLER_BREAK;
}
@@ -6913,89 +6976,6 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
else if (event->type == EVT_DROP) {
ui_but_drop(C, event, but, data);
}
- /* handle eyedropper */
- else if ((event->type == EKEY) && (event->val == KM_PRESS)) {
- if (IS_EVENT_MOD(event, shift, ctrl, alt, oskey)) {
- /* pass */
- }
- else {
- if (but->type == UI_BTYPE_COLOR) {
- WM_operator_name_call(C, "UI_OT_eyedropper_color", WM_OP_INVOKE_DEFAULT, NULL);
- return WM_UI_HANDLER_BREAK;
- }
- else if ((but->type == UI_BTYPE_SEARCH_MENU) &&
- (but->flag & UI_BUT_SEARCH_UNLINK))
- {
- if (but->rnaprop && RNA_property_type(but->rnaprop) == PROP_POINTER) {
- StructRNA *type = RNA_property_pointer_type(&but->rnapoin, but->rnaprop);
- const short idcode = RNA_type_to_ID_code(type);
- if ((idcode == ID_OB) || OB_DATA_SUPPORT_ID(idcode)) {
- WM_operator_name_call(C, "UI_OT_eyedropper_id", WM_OP_INVOKE_DEFAULT, NULL);
- return WM_UI_HANDLER_BREAK;
- }
- }
- }
- else if (but->type == UI_BTYPE_NUM) {
- if (but->rnaprop &&
- (RNA_property_type(but->rnaprop) == PROP_FLOAT) &&
- (RNA_property_subtype(but->rnaprop) & PROP_UNIT_LENGTH) &&
- (RNA_property_array_check(but->rnaprop) == false))
- {
- WM_operator_name_call(C, "UI_OT_eyedropper_depth", WM_OP_INVOKE_DEFAULT, NULL);
- return WM_UI_HANDLER_BREAK;
- }
- }
- }
- }
- /* handle keyframing */
- else if ((event->type == IKEY) &&
- !IS_EVENT_MOD(event, ctrl, oskey) &&
- (event->val == KM_PRESS))
- {
- if (event->alt) {
- if (event->shift) {
- ui_but_anim_clear_keyframe(C);
- }
- else {
- ui_but_anim_delete_keyframe(C);
- }
- }
- else {
- ui_but_anim_insert_keyframe(C);
- }
-
- ED_region_tag_redraw(data->region);
-
- return WM_UI_HANDLER_BREAK;
- }
- /* handle drivers */
- else if ((event->type == DKEY) &&
- !IS_EVENT_MOD(event, shift, oskey) &&
- (event->val == KM_PRESS))
- {
- if (event->alt)
- ui_but_anim_remove_driver(C);
- else if (event->ctrl)
- ui_but_anim_add_driver(C);
-
- ED_region_tag_redraw(data->region);
-
- return WM_UI_HANDLER_BREAK;
- }
- /* handle keyingsets */
- else if ((event->type == KKEY) &&
- !IS_EVENT_MOD(event, shift, ctrl, oskey) &&
- (event->val == KM_PRESS))
- {
- if (event->alt)
- ui_but_anim_remove_keyingset(C);
- else
- ui_but_anim_add_keyingset(C);
-
- ED_region_tag_redraw(data->region);
-
- return WM_UI_HANDLER_BREAK;
- }
/* handle menu */
else if ((event->type == RIGHTMOUSE) &&
!IS_EVENT_MOD(event, shift, ctrl, alt, oskey) &&
@@ -7008,24 +6988,6 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
}
}
- /* verify if we can edit this button */
- if (ELEM(event->type, LEFTMOUSE, RETKEY)) {
- /* this should become disabled button .. */
- if (but->lock == true) {
- if (but->lockstr) {
- WM_report(RPT_INFO, but->lockstr);
- button_activate_state(C, but, BUTTON_STATE_EXIT);
- return WM_UI_HANDLER_BREAK;
- }
- }
- else if (but->pointype && but->poin == NULL) {
- /* there's a pointer needed */
- BKE_reportf(NULL, RPT_WARNING, "DoButton pointer error: %s", but->str);
- button_activate_state(C, but, BUTTON_STATE_EXIT);
- return WM_UI_HANDLER_BREAK;
- }
- }
-
switch (but->type) {
case UI_BTYPE_BUT:
retval = ui_do_but_BUT(C, but, data, event);
@@ -7432,7 +7394,8 @@ static bool ui_but_contains_point_px(ARegion *ar, uiBut *but, int x, int y)
/**
* Can we mouse over the button or is it hidden/disabled/layout.
- * Note: ctrl is kind of a hack currently, so that non-embossed UI_BTYPE_TEXT button behaves as a label when ctrl is not pressed.
+ * \note ctrl is kind of a hack currently,
+ * so that non-embossed UI_BTYPE_TEXT button behaves as a label when ctrl is not pressed.
*/
static bool ui_but_is_interactive(const uiBut *but, const bool labeledit)
{
@@ -7626,7 +7589,9 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
if (but->block->auto_open == true) { /* test for toolbox */
time = 1;
}
- else if ((but->block->flag & UI_BLOCK_LOOP && but->type != UI_BTYPE_BLOCK) || but->block->auto_open == true) {
+ else if ((but->block->flag & UI_BLOCK_LOOP && but->type != UI_BTYPE_BLOCK) ||
+ (but->block->auto_open == true))
+ {
time = 5 * U.menuthreshold2;
}
else if (U.uiflag & USER_MENUOPENAUTO) {
@@ -8002,22 +7967,30 @@ uiBut *UI_context_active_but_get(const struct bContext *C)
return ui_context_button_active(C, NULL);
}
-/* helper function for insert keyframe, reset to default, etc operators */
-void UI_context_active_but_prop_get(const bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index)
+/**
+ * Version of #UI_context_active_but_get that also returns RNA property info.
+ * Helper function for insert keyframe, reset to default, etc operators.
+ *
+ * \return active button, NULL if none found or if it doesn't contain valid RNA data.
+ */
+uiBut *UI_context_active_but_prop_get(
+ const bContext *C,
+ struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index)
{
uiBut *activebut = ui_context_rna_button_active(C);
- memset(ptr, 0, sizeof(*ptr));
-
if (activebut && activebut->rnapoin.data) {
- *ptr = activebut->rnapoin;
- *prop = activebut->rnaprop;
- *index = activebut->rnaindex;
+ *r_ptr = activebut->rnapoin;
+ *r_prop = activebut->rnaprop;
+ *r_index = activebut->rnaindex;
}
else {
- *prop = NULL;
- *index = 0;
+ memset(r_ptr, 0, sizeof(*r_ptr));
+ *r_prop = NULL;
+ *r_index = 0;
}
+
+ return activebut;
}
void UI_context_active_but_prop_handle(bContext *C)
@@ -8428,6 +8401,7 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar,
uiListDyn *dyn_data;
int retval = WM_UI_HANDLER_CONTINUE;
int type = event->type, val = event->val;
+ bool redraw = false;
int mx, my;
ui_list = listbox->custom_data;
@@ -8517,7 +8491,7 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar,
ui_apply_but_undo(listbox);
ui_list->flag |= UILST_SCROLL_TO_ACTIVE_ITEM;
- ED_region_tag_redraw(ar);
+ redraw = true;
}
retval = WM_UI_HANDLER_BREAK;
}
@@ -8529,8 +8503,8 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar,
ui_list->list_grip += (type == WHEELUPMOUSE) ? -1 : 1;
ui_list->flag |= UILST_SCROLL_TO_ACTIVE_ITEM;
- ED_region_tag_redraw(ar);
+ redraw = true;
retval = WM_UI_HANDLER_BREAK;
}
else if (ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE)) {
@@ -8538,13 +8512,22 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar,
/* list template will clamp */
ui_list->list_scroll += (type == WHEELUPMOUSE) ? -1 : 1;
- ED_region_tag_redraw(ar);
-
+ redraw = true;
retval = WM_UI_HANDLER_BREAK;
}
}
}
+ if (redraw) {
+ if (listbox->block->flag & UI_BLOCK_POPUP) {
+ /* popups need special refreshing */
+ ED_region_tag_refresh_ui(ar);
+ }
+ else {
+ ED_region_tag_redraw(ar);
+ }
+ }
+
return retval;
}
@@ -8701,8 +8684,7 @@ static bool ui_mouse_motion_towards_check(
float delta[2];
sub_v2_v2v2(delta, oldp, cent);
- normalize_v2(delta);
- mul_v2_fl(delta, MENU_TOWARDS_WIGGLE_ROOM);
+ normalize_v2_length(delta, MENU_TOWARDS_WIGGLE_ROOM);
add_v2_v2(oldp, delta);
}
@@ -9786,11 +9768,28 @@ static int ui_handle_menus_recursive(
}
else {
uiBlock *block = menu->region->uiblocks.first;
+ uiBut *listbox = ui_list_find_mouse_over(menu->region, event);
- if (block->flag & UI_BLOCK_RADIAL)
+ if (block->flag & UI_BLOCK_RADIAL) {
retval = ui_pie_handler(C, event, menu);
- else if (event->type == LEFTMOUSE || event->val != KM_DBL_CLICK)
- retval = ui_handle_menu_event(C, event, menu, level, is_parent_inside, is_parent_menu, is_floating);
+ }
+ else if (event->type == LEFTMOUSE || event->val != KM_DBL_CLICK) {
+ bool handled = false;
+
+ if (listbox) {
+ int retval_test = ui_handle_list_event(C, event, menu->region, listbox);
+ if (retval_test != WM_UI_HANDLER_CONTINUE) {
+ retval = retval_test;
+ handled = true;
+ }
+ }
+
+ if (handled == false) {
+ retval = ui_handle_menu_event(
+ C, event, menu, level,
+ is_parent_inside, is_parent_menu, is_floating);
+ }
+ }
}
}
@@ -9801,6 +9800,17 @@ static int ui_handle_menus_recursive(
return retval;
}
+/**
+ * Allow setting menu return value from externals. E.g. WM might need to do this for exiting files correctly.
+ */
+void UI_popup_menu_retval_set(const uiBlock *block, const int retval, const bool enable)
+{
+ uiPopupBlockHandle *menu = block->handle;
+ if (menu) {
+ menu->menuretval = enable ? (menu->menuretval | retval) : (menu->menuretval & retval);
+ }
+}
+
/* *************** UI event handlers **************** */
static int ui_region_handler(bContext *C, const wmEvent *event, void *UNUSED(userdata))
@@ -10043,6 +10053,14 @@ static void ui_popup_handler_remove(bContext *C, void *userdata)
{
uiPopupBlockHandle *menu = userdata;
+ /* More correct would be to expect UI_RETURN_CANCEL here, but not wanting to
+ * cancel when removing handlers because of file exit is a rare exception.
+ * So instead of setting cancel flag for all menus before removing handlers,
+ * just explicitly flag menu with UI_RETURN_OK to avoid cancelling it. */
+ if ((menu->menuretval & UI_RETURN_OK) == 0 && menu->cancel_func) {
+ menu->cancel_func(C, menu->popup_arg);
+ }
+
/* free menu block if window is closed for some reason */
ui_popup_block_free(C, menu);
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 9093b965939..ff9d2840e9c 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -368,7 +368,6 @@ static void vicon_disclosure_tri_right_draw(int x, int y, int w, int UNUSED(h),
viconutil_set_point(pts[1], cx - d2, cy - d);
viconutil_set_point(pts[2], cx + d2, cy);
- glShadeModel(GL_SMOOTH);
glBegin(GL_TRIANGLES);
glColor4f(0.8f, 0.8f, 0.8f, alpha);
glVertex2iv(pts[0]);
@@ -376,7 +375,6 @@ static void vicon_disclosure_tri_right_draw(int x, int y, int w, int UNUSED(h),
glColor4f(0.3f, 0.3f, 0.3f, alpha);
glVertex2iv(pts[2]);
glEnd();
- glShadeModel(GL_FLAT);
glColor4f(0.0f, 0.0f, 0.0f, 1);
viconutil_draw_lineloop_smooth(pts, 3);
@@ -395,13 +393,11 @@ static void vicon_small_tri_right_draw(int x, int y, int w, int UNUSED(h), float
glColor4f(0.2f, 0.2f, 0.2f, alpha);
- glShadeModel(GL_SMOOTH);
glBegin(GL_TRIANGLES);
glVertex2iv(pts[0]);
glVertex2iv(pts[1]);
glVertex2iv(pts[2]);
glEnd();
- glShadeModel(GL_FLAT);
}
static void vicon_disclosure_tri_down_draw(int x, int y, int w, int UNUSED(h), float alpha)
@@ -415,7 +411,6 @@ static void vicon_disclosure_tri_down_draw(int x, int y, int w, int UNUSED(h), f
viconutil_set_point(pts[1], cx - d, cy + d2);
viconutil_set_point(pts[2], cx, cy - d2);
- glShadeModel(GL_SMOOTH);
glBegin(GL_TRIANGLES);
glColor4f(0.8f, 0.8f, 0.8f, alpha);
glVertex2iv(pts[0]);
@@ -423,7 +418,6 @@ static void vicon_disclosure_tri_down_draw(int x, int y, int w, int UNUSED(h), f
glColor4f(0.3f, 0.3f, 0.3f, alpha);
glVertex2iv(pts[2]);
glEnd();
- glShadeModel(GL_FLAT);
glColor4f(0.0f, 0.0f, 0.0f, 1);
viconutil_draw_lineloop_smooth(pts, 3);
@@ -511,6 +505,68 @@ static void vicon_keytype_jitter_draw(int x, int y, int w, int h, float alpha)
vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_JITTER);
}
+static void vicon_keytype_moving_hold_draw(int x, int y, int w, int h, float alpha)
+{
+ vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_MOVEHOLD);
+}
+
+static void vicon_colorset_draw(int index, int x, int y, int w, int h, float UNUSED(alpha))
+{
+ bTheme *btheme = UI_GetTheme();
+ ThemeWireColor *cs = &btheme->tarm[index];
+
+ /* Draw three bands of color: One per color
+ * x-----a-----b-----c
+ * | N | S | A |
+ * x-----a-----b-----c
+ */
+ const int a = x + w / 3;
+ const int b = x + w / 3 * 2;
+ const int c = x + w;
+
+ /* XXX: Include alpha into this... */
+ /* normal */
+ glColor3ubv((unsigned char *)cs->solid);
+ glRecti(x, y, a, y + h);
+
+ /* selected */
+ glColor3ubv((unsigned char *)cs->select);
+ glRecti(a, y, b, y + h);
+
+ /* active */
+ glColor3ubv((unsigned char *)cs->active);
+ glRecti(b, y, c, y + h);
+}
+
+#define DEF_VICON_COLORSET_DRAW_NTH(prefix, index) \
+ static void vicon_colorset_draw_##prefix(int x, int y, int w, int h, float alpha) \
+ { \
+ vicon_colorset_draw(index, x, y, w, h, alpha); \
+ }
+
+DEF_VICON_COLORSET_DRAW_NTH(01, 0)
+DEF_VICON_COLORSET_DRAW_NTH(02, 1)
+DEF_VICON_COLORSET_DRAW_NTH(03, 2)
+DEF_VICON_COLORSET_DRAW_NTH(04, 3)
+DEF_VICON_COLORSET_DRAW_NTH(05, 4)
+DEF_VICON_COLORSET_DRAW_NTH(06, 5)
+DEF_VICON_COLORSET_DRAW_NTH(07, 6)
+DEF_VICON_COLORSET_DRAW_NTH(08, 7)
+DEF_VICON_COLORSET_DRAW_NTH(09, 8)
+DEF_VICON_COLORSET_DRAW_NTH(10, 9)
+DEF_VICON_COLORSET_DRAW_NTH(11, 10)
+DEF_VICON_COLORSET_DRAW_NTH(12, 11)
+DEF_VICON_COLORSET_DRAW_NTH(13, 12)
+DEF_VICON_COLORSET_DRAW_NTH(14, 13)
+DEF_VICON_COLORSET_DRAW_NTH(15, 14)
+DEF_VICON_COLORSET_DRAW_NTH(16, 15)
+DEF_VICON_COLORSET_DRAW_NTH(17, 16)
+DEF_VICON_COLORSET_DRAW_NTH(18, 17)
+DEF_VICON_COLORSET_DRAW_NTH(19, 18)
+DEF_VICON_COLORSET_DRAW_NTH(20, 19)
+
+#undef DEF_VICON_COLORSET_DRAW_NTH
+
#ifndef WITH_HEADLESS
static void init_brush_icons(void)
@@ -741,6 +797,28 @@ static void init_internal_icons(void)
def_internal_vicon(VICO_KEYTYPE_BREAKDOWN_VEC, vicon_keytype_breakdown_draw);
def_internal_vicon(VICO_KEYTYPE_EXTREME_VEC, vicon_keytype_extreme_draw);
def_internal_vicon(VICO_KEYTYPE_JITTER_VEC, vicon_keytype_jitter_draw);
+ def_internal_vicon(VICO_KEYTYPE_MOVING_HOLD_VEC, vicon_keytype_moving_hold_draw);
+
+ def_internal_vicon(VICO_COLORSET_01_VEC, vicon_colorset_draw_01);
+ def_internal_vicon(VICO_COLORSET_02_VEC, vicon_colorset_draw_02);
+ def_internal_vicon(VICO_COLORSET_03_VEC, vicon_colorset_draw_03);
+ def_internal_vicon(VICO_COLORSET_04_VEC, vicon_colorset_draw_04);
+ def_internal_vicon(VICO_COLORSET_05_VEC, vicon_colorset_draw_05);
+ def_internal_vicon(VICO_COLORSET_06_VEC, vicon_colorset_draw_06);
+ def_internal_vicon(VICO_COLORSET_07_VEC, vicon_colorset_draw_07);
+ def_internal_vicon(VICO_COLORSET_08_VEC, vicon_colorset_draw_08);
+ def_internal_vicon(VICO_COLORSET_09_VEC, vicon_colorset_draw_09);
+ def_internal_vicon(VICO_COLORSET_10_VEC, vicon_colorset_draw_10);
+ def_internal_vicon(VICO_COLORSET_11_VEC, vicon_colorset_draw_11);
+ def_internal_vicon(VICO_COLORSET_12_VEC, vicon_colorset_draw_12);
+ def_internal_vicon(VICO_COLORSET_13_VEC, vicon_colorset_draw_13);
+ def_internal_vicon(VICO_COLORSET_14_VEC, vicon_colorset_draw_14);
+ def_internal_vicon(VICO_COLORSET_15_VEC, vicon_colorset_draw_15);
+ def_internal_vicon(VICO_COLORSET_16_VEC, vicon_colorset_draw_16);
+ def_internal_vicon(VICO_COLORSET_17_VEC, vicon_colorset_draw_17);
+ def_internal_vicon(VICO_COLORSET_18_VEC, vicon_colorset_draw_18);
+ def_internal_vicon(VICO_COLORSET_19_VEC, vicon_colorset_draw_19);
+ def_internal_vicon(VICO_COLORSET_20_VEC, vicon_colorset_draw_20);
IMB_freeImBuf(b16buf);
IMB_freeImBuf(b32buf);
@@ -983,6 +1061,9 @@ static void icon_create_rect(struct PreviewImage *prv_img, enum eIconSizes size)
}
}
+static void ui_id_preview_image_render_size(
+ const bContext *C, Scene *scene, ID *id, PreviewImage *pi, int size, const bool use_job);
+
void ui_icon_ensure_deferred(const bContext *C, const int icon_id, const bool big)
{
Icon *icon = BKE_icon_get(icon_id);
@@ -998,22 +1079,20 @@ void ui_icon_ensure_deferred(const bContext *C, const int icon_id, const bool bi
}
if (di) {
- if (di->type == ICON_TYPE_PREVIEW) {
- PreviewImage *prv = (icon->type != 0) ? BKE_previewimg_id_ensure((ID *)icon->obj) : icon->obj;
-
- if (prv) {
- const int size = big ? ICON_SIZE_PREVIEW : ICON_SIZE_ICON;
-
- if (!prv->use_deferred || prv->rect[size] || (prv->flag[size] & PRV_USER_EDITED)) {
- return;
+ switch (di->type) {
+ case ICON_TYPE_PREVIEW:
+ {
+ ID *id = (icon->type != 0) ? icon->obj : NULL;
+ PreviewImage *prv = id ? BKE_previewimg_id_ensure(id) : icon->obj;
+
+ if (prv) {
+ const int size = big ? ICON_SIZE_PREVIEW : ICON_SIZE_ICON;
+
+ if (id || (prv->tag & PRV_TAG_DEFFERED) != 0) {
+ ui_id_preview_image_render_size(C, NULL, id, prv, size, true);
+ }
}
-
- icon_create_rect(prv, size);
-
- /* Always using job (background) version. */
- ED_preview_icon_job(C, prv, NULL, prv->rect[size], prv->w[size], prv->h[size]);
-
- prv->flag[size] &= ~PRV_CHANGED;
+ break;
}
}
}
@@ -1142,8 +1221,13 @@ static void icon_draw_rect(float x, float y, int w, int h, float UNUSED(aspect),
glaDrawPixelsSafe(draw_x, draw_y, draw_w, draw_h, draw_w, GL_RGBA, GL_UNSIGNED_BYTE, rect);
}
else {
+ int bound_options;
+ GPU_BASIC_SHADER_DISABLE_AND_STORE(bound_options);
+
glRasterPos2f(draw_x, draw_y);
glDrawPixels(draw_w, draw_h, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+
+ GPU_BASIC_SHADER_ENABLE_AND_RESTORE(bound_options);
}
if (ima)
@@ -1457,6 +1541,8 @@ int UI_idcode_icon_get(const int idcode)
return ICON_BRUSH_DATA;
case ID_CA:
return ICON_CAMERA_DATA;
+ case ID_CF:
+ return ICON_FILE;
case ID_CU:
return ICON_CURVE_DATA;
case ID_GD:
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index f02aad1ff87..fcf827bdbe6 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -271,10 +271,10 @@ struct uiBut {
uiButToolTipFunc tip_func;
void *tip_argN;
- const char *lockstr;
+ /* info on why button is disabled, displayed in tooltip */
+ const char *disabled_info;
BIFIconID icon;
- bool lock;
char dt; /* drawtype: UI_EMBOSS, UI_EMBOSS_NONE ... etc, copied from the block */
signed char pie_dir; /* direction in a pie menu, used for collision detection (RadialDirection) */
char changed; /* could be made into a single flag */
@@ -548,6 +548,8 @@ struct uiPopupBlockHandle {
/* store data for refreshing popups */
struct uiPopupBlockCreate popup_create_vars;
+ /* true if we can re-create the popup using 'popup_create_vars' */
+ bool can_refresh;
struct wmTimer *scrolltimer;
@@ -727,15 +729,8 @@ void ui_block_align_calc(uiBlock *block);
/* interface_anim.c */
void ui_but_anim_flag(uiBut *but, float cfra);
-void ui_but_anim_insert_keyframe(struct bContext *C);
-void ui_but_anim_delete_keyframe(struct bContext *C);
-void ui_but_anim_clear_keyframe(struct bContext *C);
-void ui_but_anim_add_driver(struct bContext *C);
-void ui_but_anim_remove_driver(struct bContext *C);
void ui_but_anim_copy_driver(struct bContext *C);
void ui_but_anim_paste_driver(struct bContext *C);
-void ui_but_anim_add_keyingset(struct bContext *C);
-void ui_but_anim_remove_keyingset(struct bContext *C);
bool ui_but_anim_expression_get(uiBut *but, char *str, size_t maxlen);
bool ui_but_anim_expression_set(uiBut *but, const char *str);
bool ui_but_anim_expression_create(uiBut *but, const char *str);
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index e802cf82b8e..875522e01c6 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -184,11 +184,8 @@ static const char *ui_item_name_add_colon(const char *name, char namestr[UI_MAX_
return name;
}
-static int ui_item_fit(int item, int pos, int all, int available, bool is_last, int alignment, int *offset)
+static int ui_item_fit(int item, int pos, int all, int available, bool is_last, int alignment)
{
- if (offset)
- *offset = 0;
-
/* available == 0 is unlimited */
if (available == 0)
return item;
@@ -745,8 +742,7 @@ static void ui_item_disabled(uiLayout *layout, const char *name)
but = uiDefBut(block, UI_BTYPE_LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
but->flag |= UI_BUT_DISABLED;
- but->lock = true;
- but->lockstr = "";
+ but->disabled_info = "";
}
/* operator items */
@@ -2111,7 +2107,7 @@ static void ui_litem_layout_row(uiLayout *litem)
minw = ui_litem_min_width(itemw);
if (w - lastw > 0)
- neww = ui_item_fit(itemw, x, totw, w - lastw, !item->next, litem->alignment, NULL);
+ neww = ui_item_fit(itemw, x, totw, w - lastw, !item->next, litem->alignment);
else
neww = 0; /* no space left, all will need clamping to minimum size */
@@ -2145,12 +2141,12 @@ static void ui_litem_layout_row(uiLayout *litem)
if (item->flag) {
/* fixed minimum size items */
- itemw = ui_item_fit(minw, fixedx, fixedw, min_ii(w, fixedw), !item->next, litem->alignment, NULL);
+ itemw = ui_item_fit(minw, fixedx, fixedw, min_ii(w, fixedw), !item->next, litem->alignment);
fixedx += itemw;
}
else {
/* free size item */
- itemw = ui_item_fit(itemw, freex, freew, w - fixedw, !item->next, litem->alignment, NULL);
+ itemw = ui_item_fit(itemw, freex, freew, w - fixedw, !item->next, litem->alignment);
freex += itemw;
}
@@ -2470,7 +2466,7 @@ static void ui_litem_layout_column_flow(uiLayout *litem)
uiLayoutItemFlow *flow = (uiLayoutItemFlow *)litem;
uiItem *item;
int col, x, y, w, emh, emy, miny, itemw, itemh;
- int toth, totitem, offset;
+ int toth, totitem;
/* compute max needed width and total height */
toth = 0;
@@ -2492,22 +2488,27 @@ static void ui_litem_layout_column_flow(uiLayout *litem)
/* create column per column */
col = 0;
+ w = (litem->w - (flow->totcol - 1) * style->columnspace) / flow->totcol;
for (item = litem->items.first; item; item = item->next) {
- ui_item_size(item, NULL, &itemh);
- itemw = ui_item_fit(1, x - litem->x, flow->totcol, w, col == flow->totcol - 1, litem->alignment, &offset);
-
+ ui_item_size(item, &itemw, &itemh);
+
+ itemw = (litem->alignment == UI_LAYOUT_ALIGN_EXPAND) ? w : min_ii(w, itemw);
+
y -= itemh;
emy -= itemh;
- ui_item_position(item, x + offset, y, itemw, itemh);
+ ui_item_position(item, x, y, itemw, itemh);
y -= style->buttonspacey;
miny = min_ii(miny, y);
/* decide to go to next one */
if (col < flow->totcol - 1 && emy <= -emh) {
- x += itemw + style->columnspace;
+ x += w + style->columnspace;
y = litem->y;
emy = 0; /* need to reset height again for next column */
col++;
+
+ /* (< remaining width > - < space between remaining columns >) / <remamining columns > */
+ w = ((litem->w - (x - litem->x)) - (flow->totcol - col - 1) * style->columnspace) / (flow->totcol - col);
}
}
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 7a9c3e827cf..40ebc946e79 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -113,19 +113,33 @@ static int copy_data_path_button_poll(bContext *C)
return 0;
}
-static int copy_data_path_button_exec(bContext *C, wmOperator *UNUSED(op))
+static int copy_data_path_button_exec(bContext *C, wmOperator *op)
{
PointerRNA ptr;
PropertyRNA *prop;
char *path;
int index;
+ const bool full_path = RNA_boolean_get(op->ptr, "full_path");
+
/* try to create driver using property retrieved from UI */
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
- if (ptr.id.data && ptr.data && prop) {
- path = RNA_path_from_ID_to_property(&ptr, prop);
-
+ if (ptr.id.data != NULL) {
+
+ if (full_path) {
+
+ if (prop) {
+ path = RNA_path_full_property_py_ex(&ptr, prop, index, true);
+ }
+ else {
+ path = RNA_path_full_struct_py(&ptr);
+ }
+ }
+ else {
+ path = RNA_path_from_ID_to_property(&ptr, prop);
+ }
+
if (path) {
WM_clipboard_text_set(path, false);
MEM_freeN(path);
@@ -138,6 +152,8 @@ static int copy_data_path_button_exec(bContext *C, wmOperator *UNUSED(op))
static void UI_OT_copy_data_path_button(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Copy Data Path";
ot->idname = "UI_OT_copy_data_path_button";
@@ -149,6 +165,10 @@ static void UI_OT_copy_data_path_button(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER;
+
+ /* properties */
+ prop = RNA_def_boolean(ot->srna, "full_path", false, "full_path", "Copy full data path");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
static int copy_python_command_button_poll(bContext *C)
@@ -416,7 +436,7 @@ bool UI_context_copy_to_selected_list(
if ((id_data == NULL) ||
(id_data->tag & LIB_TAG_DOIT) == 0 ||
- (id_data->lib) ||
+ ID_IS_LINKED_DATABLOCK(id_data) ||
(GS(id_data->name) != id_code))
{
BLI_remlink(&lb, link);
@@ -897,7 +917,7 @@ static int edittranslation_exec(bContext *C, wmOperator *op)
}
ot = WM_operatortype_find(EDTSRC_I18N_OP_NAME, 0);
if (ot == NULL) {
- BKE_reportf(op->reports, RPT_ERROR, "Could not find operator '%s'! Please enable ui_translate addon "
+ BKE_reportf(op->reports, RPT_ERROR, "Could not find operator '%s'! Please enable ui_translate add-on "
"in the User Preferences", EDTSRC_I18N_OP_NAME);
return OPERATOR_CANCELLED;
}
@@ -1083,7 +1103,6 @@ static void UI_OT_drop_color(wmOperatorType *ot)
}
-
/* ********************************************************* */
/* Registration */
@@ -1112,12 +1131,35 @@ void ED_operatortypes_ui(void)
/**
* \brief User Interface Keymap
- *
- * For now only modal maps here, since UI uses special ui-handlers instead of operators.
*/
void ED_keymap_ui(wmKeyConfig *keyconf)
{
- WM_keymap_find(keyconf, "User Interface", 0, 0);
+ wmKeyMap *keymap = WM_keymap_find(keyconf, "User Interface", 0, 0);
+ wmKeyMapItem *kmi;
+
+ /* eyedroppers - notice they all have the same shortcut, but pass the event
+ * through until a suitable eyedropper for the active button is found */
+ WM_keymap_add_item(keymap, "UI_OT_eyedropper_color", EKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "UI_OT_eyedropper_id", EKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "UI_OT_eyedropper_depth", EKEY, KM_PRESS, 0, 0);
+
+ /* Copy Data Path */
+ WM_keymap_add_item(keymap, "UI_OT_copy_data_path_button", CKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
+ kmi = WM_keymap_add_item(keymap, "UI_OT_copy_data_path_button", CKEY, KM_PRESS, KM_CTRL | KM_SHIFT | KM_ALT, 0);
+ RNA_boolean_set(kmi->ptr, "full_path", true);
+
+ /* keyframes */
+ WM_keymap_add_item(keymap, "ANIM_OT_keyframe_insert_button", IKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "ANIM_OT_keyframe_delete_button", IKEY, KM_PRESS, KM_ALT, 0);
+ WM_keymap_add_item(keymap, "ANIM_OT_keyframe_clear_button", IKEY, KM_PRESS, KM_SHIFT | KM_ALT, 0);
+
+ /* drivers */
+ WM_keymap_add_item(keymap, "ANIM_OT_driver_button_add", DKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "ANIM_OT_driver_button_remove", DKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
+
+ /* keyingsets */
+ WM_keymap_add_item(keymap, "ANIM_OT_keyingset_button_add", KKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "ANIM_OT_keyingset_button_remove", KKEY, KM_PRESS, KM_ALT, 0);
eyedropper_modal_keymap(keyconf);
}
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 62b373c58c8..c131bcb8e14 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -1763,12 +1763,10 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active)
ui_panel_category_draw_tab(GL_LINE_STRIP, rct->xmin - px, rct->ymin - px, rct->xmax - px, rct->ymax + px,
tab_curve_radius, roundboxtype, true, true, NULL);
/* tab highlight (3d look) */
- glShadeModel(GL_SMOOTH);
glColor3ubv(is_active ? theme_col_tab_highlight : theme_col_tab_highlight_inactive);
ui_panel_category_draw_tab(GL_LINE_STRIP, rct->xmin, rct->ymin, rct->xmax, rct->ymax,
tab_curve_radius, roundboxtype, true, false,
is_active ? theme_col_back : theme_col_tab_inactive);
- glShadeModel(GL_FLAT);
}
/* tab blackline */
@@ -1843,6 +1841,52 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active)
#undef USE_FLAT_INACTIVE
}
+static int ui_handle_panel_category_cycling(const wmEvent *event, ARegion *ar, const uiBut *active_but)
+{
+ const bool is_mousewheel = ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE);
+ const bool inside_tabregion = (event->mval[0] < ((PanelCategoryDyn *)ar->panels_category.first)->rect.xmax);
+
+ /* if mouse is inside non-tab region, ctrl key is required */
+ if (is_mousewheel && !event->ctrl && !inside_tabregion)
+ return WM_UI_HANDLER_CONTINUE;
+
+
+ if (active_but && ui_but_supports_cycling(active_but)) {
+ /* skip - exception to make cycling buttons
+ * using ctrl+mousewheel work in tabbed regions */
+ }
+ else {
+ const char *category = UI_panel_category_active_get(ar, false);
+ if (LIKELY(category)) {
+ PanelCategoryDyn *pc_dyn = UI_panel_category_find(ar, category);
+ if (LIKELY(pc_dyn)) {
+ if (is_mousewheel) {
+ /* we can probably get rid of this and only allow ctrl+tabbing */
+ pc_dyn = (event->type == WHEELDOWNMOUSE) ? pc_dyn->next : pc_dyn->prev;
+ }
+ else {
+ const bool backwards = event->shift;
+ pc_dyn = backwards ? pc_dyn->prev : pc_dyn->next;
+ if (!pc_dyn) {
+ /* proper cyclic behavior, back to first/last category (only used for ctrl+tab) */
+ pc_dyn = backwards ? ar->panels_category.last : ar->panels_category.first;
+ }
+ }
+
+ if (pc_dyn) {
+ /* intentionally don't reset scroll in this case,
+ * this allows for quick browsing between tabs */
+ UI_panel_category_active_set(ar, pc_dyn->idname);
+ ED_region_tag_redraw(ar);
+ }
+ }
+ }
+ return WM_UI_HANDLER_BREAK;
+ }
+
+ return WM_UI_HANDLER_CONTINUE;
+}
+
/* XXX should become modal keymap */
/* AKey is opening/closing panels, independent of button state now */
@@ -1855,6 +1899,7 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar, cons
retval = WM_UI_HANDLER_CONTINUE;
+ /* handle category tabs */
if (has_category_tabs) {
if (event->val == KM_PRESS) {
if (event->type == LEFTMOUSE) {
@@ -1869,32 +1914,9 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar, cons
retval = WM_UI_HANDLER_BREAK;
}
}
- else if (ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE)) {
- /* mouse wheel cycle tabs */
-
- /* first check if the mouse is in the tab region */
- if (event->ctrl || (event->mval[0] < ((PanelCategoryDyn *)ar->panels_category.first)->rect.xmax)) {
- if (active_but && ui_but_supports_cycling(active_but)) {
- /* skip - exception to make cycling buttons
- * using ctrl+mousewheel work in tabbed regions */
- }
- else {
- const char *category = UI_panel_category_active_get(ar, false);
- if (LIKELY(category)) {
- PanelCategoryDyn *pc_dyn = UI_panel_category_find(ar, category);
- if (LIKELY(pc_dyn)) {
- pc_dyn = (event->type == WHEELDOWNMOUSE) ? pc_dyn->next : pc_dyn->prev;
- if (pc_dyn) {
- /* intentionally don't reset scroll in this case,
- * this allows for quick browsing between tabs */
- UI_panel_category_active_set(ar, pc_dyn->idname);
- ED_region_tag_redraw(ar);
- }
- }
- }
- retval = WM_UI_HANDLER_BREAK;
- }
- }
+ else if ((event->type == TABKEY && event->ctrl) || ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE)) {
+ /* cycle tabs */
+ retval = ui_handle_panel_category_cycling(event, ar, active_but);
}
}
}
diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c
index 9e49d7e7e90..cdf34642a8d 100644
--- a/source/blender/editors/interface/interface_regions.c
+++ b/source/blender/editors/interface/interface_regions.c
@@ -73,44 +73,12 @@
#define MENU_PADDING (int)(0.2f * UI_UNIT_Y)
#define MENU_BORDER (int)(0.3f * U.widget_unit)
-static int rna_property_enum_step(const bContext *C, PointerRNA *ptr, PropertyRNA *prop, int direction)
-{
- EnumPropertyItem *item_array;
- int totitem;
- bool free;
- int value;
- int i, i_init;
- int step = (direction < 0) ? -1 : 1;
- int step_tot = 0;
-
- RNA_property_enum_items((bContext *)C, ptr, prop, &item_array, &totitem, &free);
- value = RNA_property_enum_get(ptr, prop);
- i = RNA_enum_from_value(item_array, value);
- i_init = i;
-
- do {
- i = mod_i(i + step, totitem);
- if (item_array[i].identifier[0]) {
- step_tot += step;
- }
- } while ((i != i_init) && (step_tot != direction));
-
- if (i != i_init) {
- value = item_array[i].value;
- }
-
- if (free) {
- MEM_freeN(item_array);
- }
-
- return value;
-}
bool ui_but_menu_step_poll(const uiBut *but)
{
BLI_assert(but->type == UI_BTYPE_MENU);
- /* currenly only RNA buttons */
+ /* currently only RNA buttons */
return ((but->menu_step_func != NULL) ||
(but->rnaprop && RNA_property_type(but->rnaprop) == PROP_ENUM));
}
@@ -122,7 +90,8 @@ int ui_but_menu_step(uiBut *but, int direction)
return but->menu_step_func(but->block->evil_C, direction, but->poin);
}
else {
- return rna_property_enum_step(but->block->evil_C, &but->rnapoin, but->rnaprop, direction);
+ const int curval = RNA_property_enum_get(&but->rnapoin, but->rnaprop);
+ return RNA_property_enum_step(but->block->evil_C, &but->rnapoin, but->rnaprop, curval, direction);
}
}
@@ -454,7 +423,7 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
if (but->rnapoin.id.data) {
ID *id = but->rnapoin.id.data;
- if (id->lib) {
+ if (ID_IS_LINKED_DATABLOCK(id)) {
BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), TIP_("Library: %s"), id->lib->name);
data->format[data->totline].color_id = UI_TIP_LC_NORMAL;
data->totline++;
@@ -484,20 +453,30 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
}
MEM_freeN(str);
+ }
+
+ /* button is disabled, we may be able to tell user why */
+ if (but->flag & UI_BUT_DISABLED) {
+ const char *disabled_msg = NULL;
- /* second check if we are disabled - why */
- if (but->flag & UI_BUT_DISABLED) {
- const char *poll_msg;
+ /* if operator poll check failed, it can give pretty precise info why */
+ if (but->optype) {
CTX_wm_operator_poll_msg_set(C, NULL);
WM_operator_poll_context(C, but->optype, but->opcontext);
- poll_msg = CTX_wm_operator_poll_msg_get(C);
- if (poll_msg) {
- BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), TIP_("Disabled: %s"), poll_msg);
- data->format[data->totline].color_id = UI_TIP_LC_ALERT;
- data->totline++;
- }
+ disabled_msg = CTX_wm_operator_poll_msg_get(C);
+ }
+ /* alternatively, buttons can store some reasoning too */
+ else if (but->disabled_info) {
+ disabled_msg = TIP_(but->disabled_info);
+ }
+
+ if (disabled_msg && disabled_msg[0]) {
+ BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), TIP_("Disabled: %s"), disabled_msg);
+ data->format[data->totline].color_id = UI_TIP_LC_ALERT;
+ data->totline++;
}
}
+
if ((U.flag & USER_TOOLTIPS_PYTHON) == 0 && !but->optype && rna_struct.strinfo) {
if (rna_prop.strinfo) {
/* Struct and prop */
@@ -829,7 +808,7 @@ int UI_searchbox_size_y(void)
int UI_searchbox_size_x(void)
{
- return 10 * UI_UNIT_X;
+ return 12 * UI_UNIT_X;
}
int UI_search_items_find_index(uiSearchItems *items, const char *name)
@@ -1380,6 +1359,7 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe
rect_pre.xmax = rect_post.xmin = rect.xmin + ((rect.xmax - rect.xmin) / 4);
/* widget itself */
+ /* NOTE: i18n messages extracting tool does the same, please keep it in sync. */
{
wmOperatorType *ot = data->items.pointers[a];
@@ -1400,7 +1380,8 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe
}
rect_pre.xmax += 4; /* sneaky, avoid showing ugly margin */
- ui_draw_menu_item(&data->fstyle, &rect_pre, text_pre, data->items.icons[a], state, false);
+ ui_draw_menu_item(&data->fstyle, &rect_pre, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, text_pre),
+ data->items.icons[a], state, false);
ui_draw_menu_item(&data->fstyle, &rect_post, data->items.names[a], 0, state, data->use_sep);
}
@@ -1701,7 +1682,9 @@ static void ui_block_region_draw(const bContext *C, ARegion *ar)
ar->do_draw &= ~RGN_DRAW_REFRESH_UI;
for (block = ar->uiblocks.first; block; block = block_next) {
block_next = block->next;
- ui_popup_block_refresh((bContext *)C, block->handle, NULL, NULL);
+ if (block->handle->can_refresh) {
+ ui_popup_block_refresh((bContext *)C, block->handle, NULL, NULL);
+ }
}
}
@@ -1811,6 +1794,8 @@ uiBlock *ui_popup_block_refresh(
bContext *C, uiPopupBlockHandle *handle,
ARegion *butregion, uiBut *but)
{
+ BLI_assert(handle->can_refresh == true);
+
const int margin = UI_POPUP_MARGIN;
wmWindow *window = CTX_wm_window(C);
ARegion *ar = handle->region;
@@ -2001,6 +1986,8 @@ uiPopupBlockHandle *ui_popup_block_create(
handle->popup_create_vars.arg = arg;
handle->popup_create_vars.butregion = but ? butregion : NULL;
copy_v2_v2_int(handle->popup_create_vars.event_xy, &window->eventstate->x);
+ /* caller may free vars used to create this popup, in that case this variable should be disabled. */
+ handle->can_refresh = true;
/* create area region */
ar = ui_region_temp_add(CTX_wm_screen(C));
@@ -2327,6 +2314,12 @@ static void ui_block_colorpicker(uiBlock *block, float rgba[4], PointerRNA *ptr,
RNA_property_float_range(ptr, prop, &hardmin, &hardmax);
RNA_property_float_get_array(ptr, prop, rgba);
+ /* when the softmax isn't defined in the RNA,
+ * using very large numbers causes sRGB/linear round trip to fail. */
+ if (softmax == FLT_MAX) {
+ softmax = 1.0f;
+ }
+
switch (U.color_picker_type) {
case USER_CP_SQUARE_SV:
ui_colorpicker_square(block, ptr, prop, UI_GRAD_SV, cpicker);
@@ -2418,7 +2411,7 @@ static void ui_block_colorpicker(uiBlock *block, float rgba[4], PointerRNA *ptr,
BLI_snprintf(hexcol, sizeof(hexcol), "%02X%02X%02X", UNPACK3_EX((unsigned int), rgb_gamma_uchar, ));
yco = -3.0f * UI_UNIT_Y;
- bt = uiDefBut(block, UI_BTYPE_TEXT, 0, IFACE_("Hex: "), 0, yco, butwidth, UI_UNIT_Y, hexcol, 0, 8, 0, 0, TIP_("Hex triplet for color (#RRGGBB)"));
+ bt = uiDefBut(block, UI_BTYPE_TEXT, 0, IFACE_("Hex: "), 0, yco, butwidth, UI_UNIT_Y, hexcol, 0, 7, 0, 0, TIP_("Hex triplet for color (#RRGGBB)"));
UI_but_func_set(bt, ui_colorpicker_hex_rna_cb, bt, hexcol);
bt->custom_data = cpicker;
uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("(Gamma Corrected)"), 0, yco - UI_UNIT_Y, butwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
@@ -2794,6 +2787,7 @@ uiPopupBlockHandle *ui_popup_menu_create(
WM_event_add_mousemove(C);
}
+ handle->can_refresh = false;
MEM_freeN(pup);
return handle;
@@ -2801,14 +2795,17 @@ uiPopupBlockHandle *ui_popup_menu_create(
/******************** Popup Menu API with begin and end ***********************/
-/* only return handler, and set optional title */
-uiPopupMenu *UI_popup_menu_begin(bContext *C, const char *title, int icon)
+/**
+ * Only return handler, and set optional title.
+ * \param block_name: Assigned to uiBlock.name (useful info for debugging).
+ */
+uiPopupMenu *UI_popup_menu_begin_ex(bContext *C, const char *title, const char *block_name, int icon)
{
uiStyle *style = UI_style_get_dpi();
uiPopupMenu *pup = MEM_callocN(sizeof(uiPopupMenu), "popup menu");
uiBut *but;
- pup->block = UI_block_begin(C, NULL, __func__, UI_EMBOSS_PULLDOWN);
+ pup->block = UI_block_begin(C, NULL, block_name, UI_EMBOSS_PULLDOWN);
pup->block->flag |= UI_BLOCK_POPUP_MEMORY | UI_BLOCK_IS_FLIP;
pup->block->puphash = ui_popup_menu_hash(title);
pup->layout = UI_block_layout(pup->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, MENU_PADDING, style);
@@ -2839,6 +2836,11 @@ uiPopupMenu *UI_popup_menu_begin(bContext *C, const char *title, int icon)
return pup;
}
+uiPopupMenu *UI_popup_menu_begin(bContext *C, const char *title, int icon)
+{
+ return UI_popup_menu_begin_ex(C, title, __func__, icon);
+}
+
/* set the whole structure to work */
void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
{
@@ -2854,7 +2856,8 @@ void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
UI_popup_handlers_add(C, &window->modalhandlers, menu, 0);
WM_event_add_mousemove(C);
-
+
+ menu->can_refresh = false;
MEM_freeN(pup);
}
@@ -2985,6 +2988,7 @@ void UI_pie_menu_end(bContext *C, uiPieMenu *pie)
menu, WM_HANDLER_ACCEPT_DBL_CLICK);
WM_event_add_mousemove(C);
+ menu->can_refresh = false;
MEM_freeN(pie);
}
@@ -3197,7 +3201,8 @@ void UI_popup_menu_reports(bContext *C, ReportList *reports)
if (pup == NULL) {
char title[UI_MAX_DRAW_STR];
BLI_snprintf(title, sizeof(title), "%s: %s", IFACE_("Report"), report->typestr);
- pup = UI_popup_menu_begin(C, title, ICON_NONE);
+ /* popup_menu stuff does just what we need (but pass meaningful block name) */
+ pup = UI_popup_menu_begin_ex(C, title, __func__, ICON_NONE);
layout = UI_popup_menu_layout(pup);
}
else {
@@ -3325,6 +3330,11 @@ void UI_popup_block_close(bContext *C, wmWindow *win, uiBlock *block)
if (win) {
UI_popup_handlers_remove(&win->modalhandlers, block->handle);
ui_popup_block_free(C, block->handle);
+
+ /* In the case we have nested popups, closing one may need to redraw another, see: T48874 */
+ for (ARegion *ar = win->screen->regionbase.first; ar; ar = ar->next) {
+ ED_region_tag_refresh_ui(ar);
+ }
}
}
}
diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c
index 423c48e5f55..8b41302b5bb 100644
--- a/source/blender/editors/interface/interface_style.c
+++ b/source/blender/editors/interface/interface_style.c
@@ -417,6 +417,11 @@ void uiStyleInit(void)
blf_mono_font = -1;
}
+ if (blf_mono_font_render != -1) {
+ BLF_unload_id(blf_mono_font_render);
+ blf_mono_font_render = -1;
+ }
+
font = U.uifonts.first;
/* default builtin */
@@ -516,7 +521,12 @@ void uiStyleInit(void)
BLF_size(blf_mono_font, 12 * U.pixelsize, 72);
- /* second for rendering else we get threading problems */
+ /**
+ * Second for rendering else we get threading problems,
+ *
+ * \note This isn't good that the render font depends on the preferences,
+ * keep for now though, since without this there is no way to display many unicode chars.
+ */
if (blf_mono_font_render == -1)
blf_mono_font_render = BLF_load_mem_unique("monospace", monofont_ttf, monofont_size);
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index a3b04e1c9bc..bdad667f206 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -32,6 +32,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_cachefile_types.h"
#include "DNA_node_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
@@ -232,15 +233,17 @@ static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
/* This is for browsing and editing the ID-blocks used */
/* for new/open operators */
-void UI_context_active_but_prop_get_templateID(bContext *C, PointerRNA *ptr, PropertyRNA **prop)
+void UI_context_active_but_prop_get_templateID(
+ bContext *C,
+ PointerRNA *r_ptr, PropertyRNA **r_prop)
{
TemplateID *template;
ARegion *ar = CTX_wm_region(C);
uiBlock *block;
uiBut *but;
- memset(ptr, 0, sizeof(*ptr));
- *prop = NULL;
+ memset(r_ptr, 0, sizeof(*r_ptr));
+ *r_prop = NULL;
if (!ar)
return;
@@ -251,8 +254,8 @@ void UI_context_active_but_prop_get_templateID(bContext *C, PointerRNA *ptr, Pro
if ((but->flag & (UI_BUT_LAST_ACTIVE | UI_ACTIVE))) {
if (but->func_argN) {
template = but->func_argN;
- *ptr = template->ptr;
- *prop = template->prop;
+ *r_ptr = template->ptr;
+ *r_prop = template->prop;
return;
}
}
@@ -300,7 +303,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
break;
case UI_ID_LOCAL:
if (id) {
- if (id_make_local(id, false)) {
+ if (id_make_local(CTX_data_main(C), id, false, false)) {
/* reassign to get get proper updates/notifiers */
idptr = RNA_property_pointer_get(&template->ptr, template->prop);
RNA_property_pointer_set(&template->ptr, template->prop, idptr);
@@ -323,7 +326,9 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
}
else {
if (id) {
+ Main *bmain = CTX_data_main(C);
id_single_user(C, id, &template->ptr, template->prop);
+ DAG_relations_tag_update(bmain);
}
}
}
@@ -366,6 +371,7 @@ static const char *template_id_browse_tip(StructRNA *type)
case ID_MSK: return N_("Browse Mask to be linked");
case ID_PAL: return N_("Browse Palette Data to be linked");
case ID_PC: return N_("Browse Paint Curve Data to be linked");
+ case ID_CF: return N_("Browse Cache Files to be linked");
}
}
return N_("Browse ID data to be linked");
@@ -447,13 +453,13 @@ static void template_ID(
if (id->lib) {
if (id->tag & LIB_TAG_INDIRECT) {
but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_LIBRARY_DATA_INDIRECT, 0, 0, UI_UNIT_X, UI_UNIT_Y,
- NULL, 0, 0, 0, 0, TIP_("Indirect library datablock, cannot change"));
+ NULL, 0, 0, 0, 0, TIP_("Indirect library data-block, cannot change"));
UI_but_flag_enable(but, UI_BUT_DISABLED);
}
else {
but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_LIBRARY_DATA_DIRECT, 0, 0, UI_UNIT_X, UI_UNIT_Y,
- NULL, 0, 0, 0, 0, TIP_("Direct linked library datablock, click to make local"));
- if (!id_make_local(id, true /* test */) || (idfrom && idfrom->lib))
+ NULL, 0, 0, 0, 0, TIP_("Direct linked library data-block, click to make local"));
+ if (!id_make_local(CTX_data_main(C), id, true /* test */, false) || (idfrom && idfrom->lib))
UI_but_flag_enable(but, UI_BUT_DISABLED);
}
@@ -473,7 +479,7 @@ static void template_ID(
UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ALONE));
if (/* test only */
- (id_copy(id, NULL, true) == false) ||
+ (id_copy(CTX_data_main(C), id, NULL, true) == false) ||
(idfrom && idfrom->lib) ||
(!editable) ||
/* object in editmode - don't change data */
@@ -579,7 +585,7 @@ static void template_ID(
else {
if ((RNA_property_flag(template->prop) & PROP_NEVER_UNLINK) == 0) {
but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0,
- TIP_("Unlink datablock "
+ TIP_("Unlink data-block "
"(Shift + Click to set users to zero, data will then not be saved)"));
UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_DELETE));
@@ -870,8 +876,8 @@ static uiLayout *draw_modifier(
/* mode enabling buttons */
UI_block_align_begin(block);
- /* Softbody not allowed in this situation, enforce! */
- if (((md->type != eModifierType_Softbody && md->type != eModifierType_Collision) || !(ob->pd && ob->pd->deflect)) &&
+ /* Collision and Surface are always enabled, hide buttons! */
+ if (((md->type != eModifierType_Collision) || !(ob->pd && ob->pd->deflect)) &&
(md->type != eModifierType_Surface) )
{
uiItemR(row, &ptr, "show_render", 0, "", ICON_NONE);
@@ -972,7 +978,7 @@ static uiLayout *draw_modifier(
}
UI_block_lock_clear(block);
- UI_block_lock_set(block, ob && ob->id.lib, ERROR_LIBDATA_MESSAGE);
+ UI_block_lock_set(block, ob && ID_IS_LINKED_DATABLOCK(ob), ERROR_LIBDATA_MESSAGE);
if (!ELEM(md->type, eModifierType_Fluidsim, eModifierType_Softbody, eModifierType_ParticleSystem,
eModifierType_Cloth, eModifierType_Smoke))
@@ -1019,7 +1025,7 @@ uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr)
return NULL;
}
- UI_block_lock_set(uiLayoutGetBlock(layout), (ob && ob->id.lib), ERROR_LIBDATA_MESSAGE);
+ UI_block_lock_set(uiLayoutGetBlock(layout), (ob && ID_IS_LINKED_DATABLOCK(ob)), ERROR_LIBDATA_MESSAGE);
/* find modifier and draw it */
cageIndex = modifiers_getCageIndex(scene, ob, &lastCageIndex, 0);
@@ -1247,7 +1253,7 @@ uiLayout *uiTemplateConstraint(uiLayout *layout, PointerRNA *ptr)
return NULL;
}
- UI_block_lock_set(uiLayoutGetBlock(layout), (ob && ob->id.lib), ERROR_LIBDATA_MESSAGE);
+ UI_block_lock_set(uiLayoutGetBlock(layout), (ob && ID_IS_LINKED_DATABLOCK(ob)), ERROR_LIBDATA_MESSAGE);
/* hrms, the temporal constraint should not draw! */
if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
@@ -1609,7 +1615,7 @@ void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, const char *propname
block = uiLayoutAbsoluteBlock(layout);
id = cptr.id.data;
- UI_block_lock_set(block, (id && id->lib), ERROR_LIBDATA_MESSAGE);
+ UI_block_lock_set(block, (id && ID_IS_LINKED_DATABLOCK(id)), ERROR_LIBDATA_MESSAGE);
colorband_buttons_layout(layout, block, cptr.data, &rect, cb, expand);
@@ -1938,6 +1944,7 @@ enum {
UICURVE_FUNC_RESET_VIEW,
UICURVE_FUNC_HANDLE_VECTOR,
UICURVE_FUNC_HANDLE_AUTO,
+ UICURVE_FUNC_HANDLE_AUTO_ANIM,
UICURVE_FUNC_EXTEND_HOZ,
UICURVE_FUNC_EXTEND_EXP,
};
@@ -1958,13 +1965,16 @@ static void curvemap_tools_dofunc(bContext *C, void *cumap_v, int event)
cumap->curr = cumap->clipr;
break;
case UICURVE_FUNC_HANDLE_VECTOR: /* set vector */
- curvemap_sethandle(cuma, 1);
+ curvemap_handle_set(cuma, HD_VECT);
curvemapping_changed(cumap, false);
break;
case UICURVE_FUNC_HANDLE_AUTO: /* set auto */
- curvemap_sethandle(cuma, 0);
+ curvemap_handle_set(cuma, HD_AUTO);
curvemapping_changed(cumap, false);
break;
+ case UICURVE_FUNC_HANDLE_AUTO_ANIM: /* set auto-clamped */
+ curvemap_handle_set(cuma, HD_AUTO_ANIM);
+ curvemapping_changed(cumap, false);
case UICURVE_FUNC_EXTEND_HOZ: /* extend horiz */
cuma->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
curvemapping_changed(cumap, false);
@@ -1998,6 +2008,9 @@ static uiBlock *curvemap_tools_func(
uiDefIconTextBut(
block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Auto Handle"),
0, yco -= UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_HANDLE_AUTO, "");
+ uiDefIconTextBut(
+ block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Auto Clamped Handle"),
+ 0, yco -= UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_HANDLE_AUTO_ANIM, "");
}
if (show_extend) {
@@ -2261,7 +2274,7 @@ void uiTemplateCurveMapping(
cb->prop = prop;
id = cptr.id.data;
- UI_block_lock_set(block, (id && id->lib), ERROR_LIBDATA_MESSAGE);
+ UI_block_lock_set(block, (id && ID_IS_LINKED_DATABLOCK(id)), ERROR_LIBDATA_MESSAGE);
curvemap_buttons_layout(layout, &cptr, type, levels, brush, neg_slope, cb);
@@ -2818,7 +2831,7 @@ static void uilist_prepare(
layoutdata->end_idx = min_ii(layoutdata->start_idx + rows * columns, len);
}
-static void uilist_resize_update_cb(bContext *UNUSED(C), void *arg1, void *UNUSED(arg2))
+static void uilist_resize_update_cb(bContext *C, void *arg1, void *UNUSED(arg2))
{
uiList *ui_list = arg1;
uiListDyn *dyn_data = ui_list->dyn_data;
@@ -2831,6 +2844,9 @@ static void uilist_resize_update_cb(bContext *UNUSED(C), void *arg1, void *UNUSE
dyn_data->resize_prev += diff * UI_UNIT_Y;
ui_list->flag |= UILST_SCROLL_TO_ACTIVE_ITEM;
}
+
+ /* In case uilist is in popup, we need special refreshing */
+ ED_region_tag_refresh_ui(CTX_wm_menu(C));
}
static void *uilist_item_use_dynamic_tooltip(PointerRNA *itemptr, const char *propname)
@@ -3836,3 +3852,76 @@ void uiTemplateNodeSocket(uiLayout *layout, bContext *UNUSED(C), float *color)
UI_block_align_end(block);
}
+
+/********************************* Cache File *********************************/
+
+void uiTemplateCacheFile(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname)
+{
+ if (!ptr->data) {
+ return;
+ }
+
+ PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
+
+ if (!prop) {
+ printf("%s: property not found: %s.%s\n",
+ __func__, RNA_struct_identifier(ptr->type), propname);
+ return;
+ }
+
+ if (RNA_property_type(prop) != PROP_POINTER) {
+ printf("%s: expected pointer property for %s.%s\n",
+ __func__, RNA_struct_identifier(ptr->type), propname);
+ return;
+ }
+
+ PointerRNA fileptr = RNA_property_pointer_get(ptr, prop);
+ CacheFile *file = fileptr.data;
+
+ uiLayoutSetContextPointer(layout, "edit_cachefile", &fileptr);
+
+ uiTemplateID(layout, C, ptr, propname, NULL, "CACHEFILE_OT_open", NULL);
+
+ if (!file) {
+ return;
+ }
+
+ SpaceButs *sbuts = CTX_wm_space_buts(C);
+
+ uiLayout *row = uiLayoutRow(layout, false);
+ uiBlock *block = uiLayoutGetBlock(row);
+ uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("File Path:"), 0, 19, 145, 19, NULL, 0, 0, 0, 0, "");
+
+ row = uiLayoutRow(layout, false);
+ uiLayout *split = uiLayoutSplit(row, 0.0f, false);
+ row = uiLayoutRow(split, true);
+
+ uiItemR(row, &fileptr, "filepath", 0, "", ICON_NONE);
+ uiItemO(row, "", ICON_FILE_REFRESH, "cachefile.reload");
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, &fileptr, "is_sequence", 0, "Is Sequence", ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, &fileptr, "override_frame", 0, "Override Frame", ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiLayoutSetEnabled(row, RNA_boolean_get(&fileptr, "override_frame"));
+ uiItemR(row, &fileptr, "frame", 0, "Frame", ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiItemL(row, IFACE_("Manual Transform:"), ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiLayoutSetEnabled(row, (sbuts->mainb == BCONTEXT_CONSTRAINT));
+ uiItemR(row, &fileptr, "scale", 0, "Scale", ICON_NONE);
+
+ /* TODO: unused for now, so no need to expose. */
+#if 0
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, &fileptr, "forward_axis", 0, "Forward Axis", ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, &fileptr, "up_axis", 0, "Up Axis", ICON_NONE);
+#endif
+}
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index d1461f1acec..c285d753b96 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -712,8 +712,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
unsigned char *col_pt = col_array;
shadecolors4(col1, col2, wcol->inner, wcol->shadetop, wcol->shadedown);
-
- glShadeModel(GL_SMOOTH);
+
for (a = 0; a < wtb->totvert; a++, col_pt += 4) {
round_box_shade_col4_r(col_pt, col1, col2, wtb->inner_uv[a][wtb->draw_shadedir ? 1 : 0]);
}
@@ -725,8 +724,6 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
glDrawArrays(GL_POLYGON, 0, wtb->totvert);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
-
- glShadeModel(GL_FLAT);
}
}
@@ -859,10 +856,17 @@ static void widget_draw_icon(
else if (but->flag & UI_ACTIVE) {}
else alpha = 0.5f;
}
-
- /* extra feature allows more alpha blending */
- if ((but->type == UI_BTYPE_LABEL) && but->a1 == 1.0f)
- alpha *= but->a2;
+ else if ((but->type == UI_BTYPE_LABEL)) {
+ /* extra feature allows more alpha blending */
+ if (but->a1 == 1.0f) {
+ alpha *= but->a2;
+ }
+ }
+ else if (ELEM(but->type, UI_BTYPE_BUT)) {
+ if (but->flag & UI_BUT_DISABLED) {
+ alpha *= 0.5f;
+ }
+ }
glEnable(GL_BLEND);
@@ -2304,8 +2308,6 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti *
ui_color_picker_to_rgb(0.0f, 0.0f, hsv[2], colcent, colcent + 1, colcent + 2);
- glShadeModel(GL_SMOOTH);
-
glBegin(GL_TRIANGLE_FAN);
glColor3fv(colcent);
glVertex2f(centx, centy);
@@ -2323,8 +2325,6 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti *
}
glEnd();
- glShadeModel(GL_FLAT);
-
/* fully rounded outline */
glPushMatrix();
glTranslatef(centx, centy, 0.0f);
@@ -2356,7 +2356,6 @@ void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, cons
float col1[4][3]; /* right half, rect bottom to top */
/* draw series of gouraud rects */
- glShadeModel(GL_SMOOTH);
switch (type) {
case UI_GRAD_SV:
@@ -2479,8 +2478,6 @@ void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, cons
}
glEnd();
}
-
- glShadeModel(GL_FLAT);
}
bool ui_but_is_colorpicker_display_space(uiBut *but)
@@ -2628,6 +2625,7 @@ static void ui_draw_separator(const rcti *rect, uiWidgetColors *wcol)
glEnable(GL_BLEND);
glColor4ubv(col);
+ glLineWidth(1.0f);
sdrawline(rect->xmin, y, rect->xmax, y);
glDisable(GL_BLEND);
}
@@ -3045,7 +3043,7 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat
if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
/* Now we reduce alpha of the inner color (i.e. the color shown)
- * so that this setting can look greyed out, while retaining
+ * so that this setting can look grayed out, while retaining
* the checkboard (for transparent values). This is needed
* here as the effects of ui_widget_color_disabled() are overwritten.
*/
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index e2e2413c717..5e24dc96255 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -305,6 +305,8 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
cp = ts->vertex; break;
case TH_VERTEX_SELECT:
cp = ts->vertex_select; break;
+ case TH_VERTEX_BEVEL:
+ cp = ts->vertex_bevel; break;
case TH_VERTEX_UNREFERENCED:
cp = ts->vertex_unreferenced; break;
case TH_VERTEX_SIZE:
@@ -321,6 +323,8 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
cp = ts->edge_sharp; break;
case TH_EDGE_CREASE:
cp = ts->edge_crease; break;
+ case TH_EDGE_BEVEL:
+ cp = ts->edge_bevel; break;
case TH_EDITMESH_ACTIVE:
cp = ts->editmesh_active; break;
case TH_EDGE_FACESEL:
@@ -898,12 +902,14 @@ void ui_theme_init_default(void)
rgba_char_args_set(btheme->tv3d.transform, 0xff, 0xff, 0xff, 255);
rgba_char_args_set(btheme->tv3d.vertex, 0, 0, 0, 255);
rgba_char_args_set(btheme->tv3d.vertex_select, 255, 133, 0, 255);
+ rgba_char_args_set(btheme->tv3d.vertex_bevel, 0, 165, 255, 255);
rgba_char_args_set(btheme->tv3d.vertex_unreferenced, 0, 0, 0, 255);
btheme->tv3d.vertex_size = 3;
btheme->tv3d.outline_width = 1;
rgba_char_args_set(btheme->tv3d.edge, 0x0, 0x0, 0x0, 255);
rgba_char_args_set(btheme->tv3d.edge_select, 255, 160, 0, 255);
rgba_char_args_set(btheme->tv3d.edge_seam, 219, 37, 18, 255);
+ rgba_char_args_set(btheme->tv3d.edge_bevel, 0, 165, 255, 255);
rgba_char_args_set(btheme->tv3d.edge_facesel, 75, 75, 75, 255);
rgba_char_args_set(btheme->tv3d.face, 0, 0, 0, 18);
rgba_char_args_set(btheme->tv3d.face_select, 255, 133, 0, 60);
@@ -961,6 +967,10 @@ void ui_theme_init_default(void)
btheme->tv3d.gradients.show_grad = false;
rgba_char_args_set(btheme->tv3d.clipping_border_3d, 50, 50, 50, 255);
+
+ rgba_char_args_set(btheme->tv3d.time_keyframe, 0xDD, 0xD7, 0x00, 0xFF);
+ rgba_char_args_set(btheme->tv3d.time_gp_keyframe, 0xB5, 0xE6, 0x1D, 0xFF);
+
/* space buttons */
/* to have something initialized */
btheme->tbuts = btheme->tv3d;
@@ -1011,6 +1021,8 @@ void ui_theme_init_default(void)
rgba_char_args_set(btheme->tact.keyborder, 0, 0, 0, 255);
rgba_char_args_set(btheme->tact.keyborder_select, 0, 0, 0, 255);
+ btheme->tact.keyframe_scale_fac = 1.0f;
+
/* space nla */
btheme->tnla = btheme->tact;
@@ -1039,10 +1051,8 @@ void ui_theme_init_default(void)
rgba_char_args_set(btheme->tfile.text, 250, 250, 250, 255);
rgba_char_args_set(btheme->tfile.text_hi, 15, 15, 15, 255);
// rgba_char_args_set(btheme->tfile.panel, 145, 145, 145, 255); /* bookmark/ui regions */
- rgba_char_args_set(btheme->tfile.active, 130, 130, 130, 255); /* selected files */
rgba_char_args_set(btheme->tfile.hilite, 255, 140, 25, 255); /* selected files */
-
- rgba_char_args_set(btheme->tfile.grid, 250, 250, 250, 255);
+
rgba_char_args_set(btheme->tfile.image, 250, 250, 250, 255);
rgba_char_args_set(btheme->tfile.movie, 250, 250, 250, 255);
rgba_char_args_set(btheme->tfile.scene, 250, 250, 250, 255);
@@ -1148,8 +1158,8 @@ void ui_theme_init_default(void)
rgba_char_args_set_fl(btheme->ttime.grid, 0.36, 0.36, 0.36, 1.0);
rgba_char_args_set(btheme->ttime.shade1, 173, 173, 173, 255); /* sliders */
- rgba_char_args_set(btheme->ttime.time_keyframe, 0xDD, 0xD7, 0x00, 1.0);
- rgba_char_args_set(btheme->ttime.time_gp_keyframe, 0xB5, 0xE6, 0x1D, 1.0);
+ rgba_char_args_set(btheme->ttime.time_keyframe, 0xDD, 0xD7, 0x00, 0xFF);
+ rgba_char_args_set(btheme->ttime.time_gp_keyframe, 0xB5, 0xE6, 0x1D, 0xFF);
/* space node, re-uses syntax and console color storage */
btheme->tnode = btheme->tv3d;
@@ -1471,6 +1481,30 @@ void UI_GetThemeColor3ubv(int colorid, unsigned char col[3])
col[2] = cp[2];
}
+/* get the color, range 0.0-1.0, complete with shading offset */
+void UI_GetThemeColorShade4fv(int colorid, int offset, float col[4])
+{
+ int r, g, b, a;
+ const unsigned char *cp;
+
+ cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
+
+ r = offset + (int) cp[0];
+ CLAMP(r, 0, 255);
+ g = offset + (int) cp[1];
+ CLAMP(g, 0, 255);
+ b = offset + (int) cp[2];
+ CLAMP(b, 0, 255);
+
+ a = (int) cp[3]; /* no shading offset... */
+ CLAMP(a, 0, 255);
+
+ col[0] = ((float)r) / 255.0f;
+ col[1] = ((float)g) / 255.0f;
+ col[2] = ((float)b) / 255.0f;
+ col[3] = ((float)a) / 255.0f;
+}
+
/* get the color, in char pointer */
void UI_GetThemeColor4ubv(int colorid, unsigned char col[4])
{
@@ -2604,8 +2638,8 @@ void init_userdef_do_versions(void)
btheme->tnode.gp_vertex_size = 3;
/* Timeline Keyframe Indicators */
- rgba_char_args_set(btheme->ttime.time_keyframe, 0xDD, 0xD7, 0x00, 1.0);
- rgba_char_args_set(btheme->ttime.time_gp_keyframe, 0xB5, 0xE6, 0x1D, 1.0);
+ rgba_char_args_set(btheme->ttime.time_keyframe, 0xDD, 0xD7, 0x00, 0xFF);
+ rgba_char_args_set(btheme->ttime.time_gp_keyframe, 0xB5, 0xE6, 0x1D, 0xFF);
}
}
@@ -2685,8 +2719,8 @@ void init_userdef_do_versions(void)
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
/* 3dView Keyframe Indicators */
- rgba_char_args_set(btheme->tv3d.time_keyframe, 0xDD, 0xD7, 0x00, 1.0);
- rgba_char_args_set(btheme->tv3d.time_gp_keyframe, 0xB5, 0xE6, 0x1D, 1.0);
+ rgba_char_args_set(btheme->tv3d.time_keyframe, 0xDD, 0xD7, 0x00, 0xFF);
+ rgba_char_args_set(btheme->tv3d.time_gp_keyframe, 0xB5, 0xE6, 0x1D, 0xFF);
}
}
@@ -2699,6 +2733,22 @@ void init_userdef_do_versions(void)
}
}
}
+
+ if (!USER_VERSION_ATLEAST(277, 2)) {
+ bTheme *btheme;
+ for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+ if (btheme->tact.keyframe_scale_fac < 0.1f)
+ btheme->tact.keyframe_scale_fac = 1.0f;
+ }
+ }
+
+ if (!USER_VERSION_ATLEAST(278, 2)) {
+ bTheme *btheme;
+ for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+ rgba_char_args_set(btheme->tv3d.vertex_bevel, 0, 165, 255, 255);
+ rgba_char_args_set(btheme->tv3d.edge_bevel, 0, 165, 255, 255);
+ }
+ }
/**
* Include next version bump.
@@ -2706,6 +2756,11 @@ void init_userdef_do_versions(void)
* (keep this block even if it becomes empty).
*/
{
+ for (bTheme *btheme = U.themes.first; btheme; btheme = btheme->next) {
+ /* Keyframe Indicators (were using wrong alpha) */
+ btheme->tv3d.time_keyframe[3] = btheme->tv3d.time_gp_keyframe[3] = 255;
+ btheme->ttime.time_keyframe[3] = btheme->ttime.time_gp_keyframe[3] = 255;
+ }
}
if (U.pixelsize == 0.0f)
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index f60fed398ec..d2b2f12c1a5 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -127,6 +127,7 @@ static int view_pan_init(bContext *C, wmOperator *op)
return 1;
}
+#ifdef WITH_INPUT_NDOF
static int view_pan_poll(bContext *C)
{
ARegion *ar = CTX_wm_region(C);
@@ -144,6 +145,7 @@ static int view_pan_poll(bContext *C)
/* view can pan */
return 1;
}
+#endif
/* apply transform to view (i.e. adjust 'cur' rect) */
static void view_pan_apply_ex(bContext *C, v2dViewPanData *vpd, float dx, float dy)
@@ -1296,7 +1298,7 @@ static void VIEW2D_OT_zoom_border(wmOperatorType *ot)
WM_operator_properties_gesture_border(ot, false);
}
-
+#ifdef WITH_INPUT_NDOF
static int view2d_ndof_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (event->type != NDOF_MOTION) {
@@ -1369,6 +1371,7 @@ static void VIEW2D_OT_ndof(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_LOCK_BYPASS;
}
+#endif /* WITH_INPUT_NDOF */
/* ********************************************************* */
/* SMOOTH VIEW */
@@ -2067,7 +2070,9 @@ void ED_operatortypes_view2d(void)
WM_operatortype_append(VIEW2D_OT_zoom);
WM_operatortype_append(VIEW2D_OT_zoom_border);
+#ifdef WITH_INPUT_NDOF
WM_operatortype_append(VIEW2D_OT_ndof);
+#endif
WM_operatortype_append(VIEW2D_OT_smoothview);
@@ -2097,7 +2102,9 @@ void ED_keymap_view2d(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_down", WHEELDOWNMOUSE, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_up", WHEELUPMOUSE, KM_PRESS, KM_SHIFT, 0);
+#ifdef WITH_INPUT_NDOF
WM_keymap_add_item(keymap, "VIEW2D_OT_ndof", NDOF_MOTION, 0, 0, 0);
+#endif
/* zoom - single step */
WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_out", WHEELOUTMOUSE, KM_PRESS, 0, 0);
diff --git a/source/blender/editors/io/CMakeLists.txt b/source/blender/editors/io/CMakeLists.txt
index 828cb494eab..b3bbce939a5 100644
--- a/source/blender/editors/io/CMakeLists.txt
+++ b/source/blender/editors/io/CMakeLists.txt
@@ -28,6 +28,8 @@ set(INC
../../makesrna
../../windowmanager
../../collada
+ ../../alembic
+ ../../../../intern/guardedalloc
)
set(INC_SYS
@@ -35,9 +37,13 @@ set(INC_SYS
)
set(SRC
+ io_alembic.c
+ io_cache.c
io_collada.c
io_ops.c
+ io_alembic.h
+ io_cache.h
io_collada.h
io_ops.h
)
@@ -46,6 +52,14 @@ if(WITH_OPENCOLLADA)
add_definitions(-DWITH_COLLADA)
endif()
+if(WITH_ALEMBIC)
+ add_definitions(-DWITH_ALEMBIC)
+
+ if(WITH_ALEMBIC_HDF5)
+ add_definitions(-DWITH_ALEMBIC_HDF5)
+ endif()
+endif()
+
if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c
new file mode 100644
index 00000000000..a991f59e8e2
--- /dev/null
+++ b/source/blender/editors/io/io_alembic.c
@@ -0,0 +1,528 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+#ifdef WITH_ALEMBIC
+
+/* needed for directory lookup */
+#ifndef WIN32
+# include <dirent.h>
+#else
+# include "BLI_winstuff.h"
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_report.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math_vector.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "io_alembic.h"
+
+#include "ABC_alembic.h"
+
+static int wm_alembic_export_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ RNA_boolean_set(op->ptr, "init_scene_frame_range", true);
+
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ Main *bmain = CTX_data_main(C);
+ char filepath[FILE_MAX];
+
+ if (bmain->name[0] == '\0') {
+ BLI_strncpy(filepath, "untitled", sizeof(filepath));
+ }
+ else {
+ BLI_strncpy(filepath, bmain->name, sizeof(filepath));
+ }
+
+ BLI_replace_extension(filepath, sizeof(filepath), ".abc");
+ RNA_string_set(op->ptr, "filepath", filepath);
+ }
+
+ WM_event_add_fileselect(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+
+ UNUSED_VARS(event);
+}
+
+static int wm_alembic_export_exec(bContext *C, wmOperator *op)
+{
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ BKE_report(op->reports, RPT_ERROR, "No filename given");
+ return OPERATOR_CANCELLED;
+ }
+
+ char filename[FILE_MAX];
+ RNA_string_get(op->ptr, "filepath", filename);
+
+ const struct AlembicExportParams params = {
+ .frame_start = RNA_int_get(op->ptr, "start"),
+ .frame_end = RNA_int_get(op->ptr, "end"),
+
+ .frame_step_xform = 1.0 / (double)RNA_int_get(op->ptr, "xsamples"),
+ .frame_step_shape = 1.0 / (double)RNA_int_get(op->ptr, "gsamples"),
+
+ .shutter_open = RNA_float_get(op->ptr, "sh_open"),
+ .shutter_close = RNA_float_get(op->ptr, "sh_close"),
+
+ .selected_only = RNA_boolean_get(op->ptr, "selected"),
+ .uvs = RNA_boolean_get(op->ptr, "uvs"),
+ .normals = RNA_boolean_get(op->ptr, "normals"),
+ .vcolors = RNA_boolean_get(op->ptr, "vcolors"),
+ .apply_subdiv = RNA_boolean_get(op->ptr, "apply_subdiv"),
+ .flatten_hierarchy = RNA_boolean_get(op->ptr, "flatten"),
+ .visible_layers_only = RNA_boolean_get(op->ptr, "visible_layers_only"),
+ .renderable_only = RNA_boolean_get(op->ptr, "renderable_only"),
+ .face_sets = RNA_boolean_get(op->ptr, "face_sets"),
+ .use_subdiv_schema = RNA_boolean_get(op->ptr, "subdiv_schema"),
+ .compression_type = RNA_enum_get(op->ptr, "compression_type"),
+ .packuv = RNA_boolean_get(op->ptr, "packuv"),
+ .triangulate = RNA_boolean_get(op->ptr, "triangulate"),
+ .quad_method = RNA_enum_get(op->ptr, "quad_method"),
+ .ngon_method = RNA_enum_get(op->ptr, "ngon_method"),
+
+ .global_scale = RNA_float_get(op->ptr, "global_scale"),
+ };
+
+ ABC_export(CTX_data_scene(C), C, filename, &params);
+
+ return OPERATOR_FINISHED;
+}
+
+static void ui_alembic_export_settings(uiLayout *layout, PointerRNA *imfptr)
+{
+ uiLayout *box;
+ uiLayout *row;
+
+#ifdef WITH_ALEMBIC_HDF5
+ box = uiLayoutBox(layout);
+ row = uiLayoutRow(box, false);
+ uiItemL(row, IFACE_("Archive Options:"), ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "compression_type", 0, NULL, ICON_NONE);
+#endif
+
+ box = uiLayoutBox(layout);
+ row = uiLayoutRow(box, false);
+ uiItemL(row, IFACE_("Manual Transform:"), ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "global_scale", 0, NULL, ICON_NONE);
+
+ /* Scene Options */
+ box = uiLayoutBox(layout);
+ row = uiLayoutRow(box, false);
+ uiItemL(row, IFACE_("Scene Options:"), ICON_SCENE_DATA);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "start", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "end", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "xsamples", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "gsamples", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "sh_open", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "sh_close", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "selected", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "renderable_only", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "visible_layers_only", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "flatten", 0, NULL, ICON_NONE);
+
+ /* Object Data */
+ box = uiLayoutBox(layout);
+ row = uiLayoutRow(box, false);
+ uiItemL(row, IFACE_("Object Options:"), ICON_OBJECT_DATA);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "uvs", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "packuv", 0, NULL, ICON_NONE);
+ uiLayoutSetEnabled(row, RNA_boolean_get(imfptr, "uvs"));
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "normals", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "vcolors", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "face_sets", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "subdiv_schema", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "apply_subdiv", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "triangulate", 0, NULL, ICON_NONE);
+
+ const bool triangulate = RNA_boolean_get(imfptr, "triangulate");
+
+ row = uiLayoutRow(box, false);
+ uiLayoutSetEnabled(row, triangulate);
+ uiItemR(row, imfptr, "quad_method", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiLayoutSetEnabled(row, triangulate);
+ uiItemR(row, imfptr, "ngon_method", 0, NULL, ICON_NONE);
+}
+
+static void wm_alembic_export_draw(bContext *C, wmOperator *op)
+{
+ PointerRNA ptr;
+
+ RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
+
+ /* Conveniently set start and end frame to match the scene's frame range. */
+ Scene *scene = CTX_data_scene(C);
+
+ if (scene != NULL && RNA_boolean_get(&ptr, "init_scene_frame_range")) {
+ RNA_int_set(&ptr, "start", SFRA);
+ RNA_int_set(&ptr, "end", EFRA);
+
+ RNA_boolean_set(&ptr, "init_scene_frame_range", false);
+ }
+
+ ui_alembic_export_settings(op->layout, &ptr);
+}
+
+static bool wm_alembic_export_check(bContext *UNUSED(C), wmOperator *op)
+{
+ char filepath[FILE_MAX];
+ RNA_string_get(op->ptr, "filepath", filepath);
+
+ if (!BLI_testextensie(filepath, ".abc")) {
+ BLI_ensure_extension(filepath, FILE_MAX, ".abc");
+ RNA_string_set(op->ptr, "filepath", filepath);
+ return true;
+ }
+
+ return false;
+}
+
+void WM_OT_alembic_export(wmOperatorType *ot)
+{
+ ot->name = "Export Alembic";
+ ot->description = "Export current scene in an Alembic archive";
+ ot->idname = "WM_OT_alembic_export";
+
+ ot->invoke = wm_alembic_export_invoke;
+ ot->exec = wm_alembic_export_exec;
+ ot->poll = WM_operator_winactive;
+ ot->ui = wm_alembic_export_draw;
+ ot->check = wm_alembic_export_check;
+
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_ALEMBIC,
+ FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH,
+ FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+
+ RNA_def_int(ot->srna, "start", 1, INT_MIN, INT_MAX,
+ "Start Frame", "Start Frame", INT_MIN, INT_MAX);
+
+ RNA_def_int(ot->srna, "end", 1, INT_MIN, INT_MAX,
+ "End Frame", "End Frame", INT_MIN, INT_MAX);
+
+ RNA_def_int(ot->srna, "xsamples", 1, 1, 128,
+ "Transform Samples", "Number of times per frame transformations are sampled", 1, 128);
+
+ RNA_def_int(ot->srna, "gsamples", 1, 1, 128,
+ "Geometry Samples", "Number of times per frame object data are sampled", 1, 128);
+
+ RNA_def_float(ot->srna, "sh_open", 0.0f, -1.0f, 1.0f,
+ "Shutter Open", "Time at which the shutter is open", -1.0f, 1.0f);
+
+ RNA_def_float(ot->srna, "sh_close", 1.0f, -1.0f, 1.0f,
+ "Shutter Close", "Time at which the shutter is closed", -1.0f, 1.0f);
+
+ RNA_def_boolean(ot->srna, "selected", 0,
+ "Selected Objects Only", "Export only selected objects");
+
+ RNA_def_boolean(ot->srna, "renderable_only", 1,
+ "Renderable Objects Only",
+ "Export only objects marked renderable in the outliner");
+
+ RNA_def_boolean(ot->srna, "visible_layers_only", 0,
+ "Visible Layers Only", "Export only objects in visible layers");
+
+ RNA_def_boolean(ot->srna, "flatten", 0,
+ "Flatten Hierarchy",
+ "Do not preserve objects' parent/children relationship");
+
+ RNA_def_boolean(ot->srna, "uvs", 1, "UVs", "Export UVs");
+
+ RNA_def_boolean(ot->srna, "packuv", 1, "Pack UV Islands",
+ "Export UVs with packed island");
+
+ RNA_def_boolean(ot->srna, "normals", 1, "Normals", "Export normals");
+
+ RNA_def_boolean(ot->srna, "vcolors", 0, "Vertex Colors", "Export vertex colors");
+
+ RNA_def_boolean(ot->srna, "face_sets", 0, "Face Sets", "Export per face shading group assignments");
+
+ RNA_def_boolean(ot->srna, "subdiv_schema", 0,
+ "Use Subdivision Schema",
+ "Export meshes using Alembic's subdivision schema");
+
+ RNA_def_boolean(ot->srna, "apply_subdiv", 0,
+ "Apply Subsurf", "Export subdivision surfaces as meshes");
+
+ RNA_def_enum(ot->srna, "compression_type", rna_enum_abc_compression_items,
+ ABC_ARCHIVE_OGAWA, "Compression", "");
+
+ RNA_def_float(ot->srna, "global_scale", 1.0f, 0.0001f, 1000.0f, "Scale",
+ "Value by which to enlarge or shrink the objects with respect to the world's origin",
+ 0.0001f, 1000.0f);
+
+ RNA_def_boolean(ot->srna, "triangulate", false, "Triangulate",
+ "Export Polygons (Quads & NGons) as Triangles");
+
+ RNA_def_enum(ot->srna, "quad_method", rna_enum_modifier_triangulate_quad_method_items,
+ MOD_TRIANGULATE_QUAD_SHORTEDGE, "Quad Method", "Method for splitting the quads into triangles");
+
+ RNA_def_enum(ot->srna, "ngon_method", rna_enum_modifier_triangulate_quad_method_items,
+ MOD_TRIANGULATE_NGON_BEAUTY, "Polygon Method", "Method for splitting the polygons into triangles");
+
+ /* This dummy prop is used to check whether we need to init the start and
+ * end frame values to that of the scene's, otherwise they are reset at
+ * every change, draw update. */
+ RNA_def_boolean(ot->srna, "init_scene_frame_range", false, "", "");
+}
+
+/* ************************************************************************** */
+
+/* TODO(kevin): check on de-duplicating all this with code in image_ops.c */
+
+typedef struct CacheFrame {
+ struct CacheFrame *next, *prev;
+ int framenr;
+} CacheFrame;
+
+static int cmp_frame(const void *a, const void *b)
+{
+ const CacheFrame *frame_a = a;
+ const CacheFrame *frame_b = b;
+
+ if (frame_a->framenr < frame_b->framenr) return -1;
+ if (frame_a->framenr > frame_b->framenr) return 1;
+ return 0;
+}
+
+static int get_sequence_len(char *filename, int *ofs)
+{
+ int frame;
+ int numdigit;
+
+ if (!BLI_path_frame_get(filename, &frame, &numdigit)) {
+ return 1;
+ }
+
+ char path[FILE_MAX];
+ BLI_split_dir_part(filename, path, FILE_MAX);
+
+ DIR *dir = opendir(path);
+
+ const char *ext = ".abc";
+ const char *basename = BLI_path_basename(filename);
+ const int len = strlen(basename) - (numdigit + strlen(ext));
+
+ ListBase frames;
+ BLI_listbase_clear(&frames);
+
+ struct dirent *fname;
+ while ((fname = readdir(dir)) != NULL) {
+ /* do we have the right extension? */
+ if (!strstr(fname->d_name, ext)) {
+ continue;
+ }
+
+ if (!STREQLEN(basename, fname->d_name, len)) {
+ continue;
+ }
+
+ CacheFrame *cache_frame = MEM_callocN(sizeof(CacheFrame), "abc_frame");
+
+ BLI_path_frame_get(fname->d_name, &cache_frame->framenr, &numdigit);
+
+ BLI_addtail(&frames, cache_frame);
+ }
+
+ closedir(dir);
+
+ BLI_listbase_sort(&frames, cmp_frame);
+
+ CacheFrame *cache_frame = frames.first;
+
+ if (cache_frame) {
+ int frame_curr = cache_frame->framenr;
+ (*ofs) = frame_curr;
+
+ while (cache_frame && (cache_frame->framenr == frame_curr)) {
+ ++frame_curr;
+ cache_frame = cache_frame->next;
+ }
+
+ BLI_freelistN(&frames);
+
+ return frame_curr - (*ofs);
+ }
+
+ return 1;
+}
+
+/* ************************************************************************** */
+
+static void ui_alembic_import_settings(uiLayout *layout, PointerRNA *imfptr)
+{
+ uiLayout *box = uiLayoutBox(layout);
+ uiLayout *row = uiLayoutRow(box, false);
+ uiItemL(row, IFACE_("Manual Transform:"), ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "scale", 0, NULL, ICON_NONE);
+
+ box = uiLayoutBox(layout);
+ row = uiLayoutRow(box, false);
+ uiItemL(row, IFACE_("Options:"), ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "set_frame_range", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "is_sequence", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "validate_meshes", 0, NULL, ICON_NONE);
+}
+
+static void wm_alembic_import_draw(bContext *UNUSED(C), wmOperator *op)
+{
+ PointerRNA ptr;
+
+ RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
+ ui_alembic_import_settings(op->layout, &ptr);
+}
+
+static int wm_alembic_import_exec(bContext *C, wmOperator *op)
+{
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ BKE_report(op->reports, RPT_ERROR, "No filename given");
+ return OPERATOR_CANCELLED;
+ }
+
+ char filename[FILE_MAX];
+ RNA_string_get(op->ptr, "filepath", filename);
+
+ const float scale = RNA_float_get(op->ptr, "scale");
+ const bool is_sequence = RNA_boolean_get(op->ptr, "is_sequence");
+ const bool set_frame_range = RNA_boolean_get(op->ptr, "set_frame_range");
+ const bool validate_meshes = RNA_boolean_get(op->ptr, "validate_meshes");
+
+ int offset = 0;
+ int sequence_len = 1;
+
+ if (is_sequence) {
+ sequence_len = get_sequence_len(filename, &offset);
+ }
+
+ ABC_import(C, filename, scale, is_sequence, set_frame_range, sequence_len, offset, validate_meshes);
+
+ return OPERATOR_FINISHED;
+}
+
+void WM_OT_alembic_import(wmOperatorType *ot)
+{
+ ot->name = "Import Alembic";
+ ot->description = "Load an Alembic archive";
+ ot->idname = "WM_OT_alembic_import";
+
+ ot->invoke = WM_operator_filesel;
+ ot->exec = wm_alembic_import_exec;
+ ot->poll = WM_operator_winactive;
+ ot->ui = wm_alembic_import_draw;
+
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_ALEMBIC,
+ FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH,
+ FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+
+ RNA_def_float(ot->srna, "scale", 1.0f, 0.0001f, 1000.0f, "Scale",
+ "Value by which to enlarge or shrink the objects with respect to the world's origin",
+ 0.0001f, 1000.0f);
+
+ RNA_def_boolean(ot->srna, "set_frame_range", true,
+ "Set Frame Range",
+ "If checked, update scene's start and end frame to match those of the Alembic archive");
+
+ RNA_def_boolean(ot->srna, "validate_meshes", 0,
+ "Validate Meshes", "Check imported mesh objects for invalid data (slow)");
+
+ RNA_def_boolean(ot->srna, "is_sequence", false, "Is Sequence",
+ "Set to true if the cache is split into separate files");
+}
+
+#endif
diff --git a/source/blender/editors/io/io_alembic.h b/source/blender/editors/io/io_alembic.h
new file mode 100644
index 00000000000..5eefabef4be
--- /dev/null
+++ b/source/blender/editors/io/io_alembic.h
@@ -0,0 +1,37 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+#ifndef __IO_ALEMBIC_H__
+#define __IO_ALEMBIC_H__
+
+/** \file blender/editors/io/io_alembic.h
+ * \ingroup editor/io
+ */
+
+struct wmOperatorType;
+
+void WM_OT_alembic_export(struct wmOperatorType *ot);
+void WM_OT_alembic_import(struct wmOperatorType *ot);
+
+#endif /* __IO_ALEMBIC_H__ */
diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c
new file mode 100644
index 00000000000..ebe8898571d
--- /dev/null
+++ b/source/blender/editors/io/io_cache.c
@@ -0,0 +1,165 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_cachefile_types.h"
+#include "DNA_space_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+
+#include "BKE_cachefile.h"
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_report.h"
+
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "io_cache.h"
+
+static void cachefile_init(bContext *C, wmOperator *op)
+{
+ PropertyPointerRNA *pprop;
+
+ op->customdata = pprop = MEM_callocN(sizeof(PropertyPointerRNA), "OpenPropertyPointerRNA");
+ UI_context_active_but_prop_get_templateID(C, &pprop->ptr, &pprop->prop);
+}
+
+static int cachefile_open_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ char filepath[FILE_MAX];
+ Main *bmain = CTX_data_main(C);
+
+ BLI_strncpy(filepath, bmain->name, sizeof(filepath));
+ BLI_replace_extension(filepath, sizeof(filepath), ".abc");
+ RNA_string_set(op->ptr, "filepath", filepath);
+ }
+
+ cachefile_init(C, op);
+
+ WM_event_add_fileselect(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+
+ UNUSED_VARS(event);
+}
+
+static void open_cancel(bContext *UNUSED(C), wmOperator *op)
+{
+ MEM_freeN(op->customdata);
+ op->customdata = NULL;
+}
+
+static int cachefile_open_exec(bContext *C, wmOperator *op)
+{
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ BKE_report(op->reports, RPT_ERROR, "No filename given");
+ return OPERATOR_CANCELLED;
+ }
+
+ char filename[FILE_MAX];
+ RNA_string_get(op->ptr, "filepath", filename);
+
+ Main *bmain = CTX_data_main(C);
+
+ CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, BLI_path_basename(filename));
+ BLI_strncpy(cache_file->filepath, filename, FILE_MAX);
+ BKE_cachefile_reload(bmain, cache_file);
+
+ /* hook into UI */
+ PropertyPointerRNA *pprop = op->customdata;
+
+ if (pprop->prop) {
+ /* when creating new ID blocks, use is already 1, but RNA
+ * pointer se also increases user, so this compensates it */
+ id_us_min(&cache_file->id);
+
+ PointerRNA idptr;
+ RNA_id_pointer_create(&cache_file->id, &idptr);
+ RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr);
+ RNA_property_update(C, &pprop->ptr, pprop->prop);
+ }
+
+ MEM_freeN(op->customdata);
+
+ return OPERATOR_FINISHED;
+}
+
+void CACHEFILE_OT_open(wmOperatorType *ot)
+{
+ ot->name = "Open Cache File";
+ ot->description = "Load a cache file";
+ ot->idname = "CACHEFILE_OT_open";
+
+ ot->invoke = cachefile_open_invoke;
+ ot->exec = cachefile_open_exec;
+ ot->cancel = open_cancel;
+
+ WM_operator_properties_filesel(ot, FILE_TYPE_ALEMBIC | FILE_TYPE_FOLDER,
+ FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH,
+ FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+}
+
+/* ***************************** Reload Operator **************************** */
+
+static int cachefile_reload_exec(bContext *C, wmOperator *op)
+{
+ CacheFile *cache_file = CTX_data_edit_cachefile(C);
+
+ if (!cache_file) {
+ return OPERATOR_CANCELLED;
+ }
+
+ Main *bmain = CTX_data_main(C);
+
+ BLI_listbase_clear(&cache_file->object_paths);
+ BKE_cachefile_reload(bmain, cache_file);
+
+ return OPERATOR_FINISHED;
+
+ UNUSED_VARS(op);
+}
+
+void CACHEFILE_OT_reload(wmOperatorType *ot)
+{
+ ot->name = "Refresh Archive";
+ ot->description = "Update objects paths list with new data from the archive";
+ ot->idname = "CACHEFILE_OT_reload";
+
+ /* api callbacks */
+ ot->exec = cachefile_reload_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/io/io_cache.h b/source/blender/editors/io/io_cache.h
new file mode 100644
index 00000000000..ea270c2aba1
--- /dev/null
+++ b/source/blender/editors/io/io_cache.h
@@ -0,0 +1,37 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+#ifndef __IO_CACHE_H__
+#define __IO_CACHE_H__
+
+/** \file blender/editors/io/io_cache.h
+ * \ingroup editor/io
+ */
+
+struct wmOperatorType;
+
+void CACHEFILE_OT_open(struct wmOperatorType *ot);
+void CACHEFILE_OT_reload(struct wmOperatorType *ot);
+
+#endif /* __IO_CACHE_H__ */
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index d4c976fb544..8659100df87 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -94,6 +94,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
int triangulate;
int use_object_instantiation;
+ int use_blender_profile;
int sort_by_name;
int export_transformation_type;
int open_sim;
@@ -142,6 +143,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
triangulate = RNA_boolean_get(op->ptr, "triangulate");
use_object_instantiation = RNA_boolean_get(op->ptr, "use_object_instantiation");
+ use_blender_profile = RNA_boolean_get(op->ptr, "use_blender_profile");
sort_by_name = RNA_boolean_get(op->ptr, "sort_by_name");
export_transformation_type = RNA_enum_get(op->ptr, "export_transformation_type_selection");
open_sim = RNA_boolean_get(op->ptr, "open_sim");
@@ -167,12 +169,13 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
triangulate,
use_object_instantiation,
+ use_blender_profile,
sort_by_name,
export_transformation_type,
open_sim);
if (export_count == 0) {
- BKE_report(op->reports, RPT_WARNING, "Export file is empty");
+ BKE_report(op->reports, RPT_WARNING, "No objects selected -- Created empty export file");
return OPERATOR_CANCELLED;
}
else if (export_count < 0) {
@@ -256,6 +259,8 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr)
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, "use_blender_profile", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
split = uiLayoutSplit(row, 0.6f, UI_LAYOUT_ALIGN_RIGHT);
@@ -275,6 +280,20 @@ static void wm_collada_export_draw(bContext *UNUSED(C), wmOperator *op)
uiCollada_exportSettings(op->layout, &ptr);
}
+static bool wm_collada_export_check(bContext *UNUSED(C), wmOperator *op)
+{
+ char filepath[FILE_MAX];
+ RNA_string_get(op->ptr, "filepath", filepath);
+
+ if (!BLI_testextensie(filepath, ".dae")) {
+ BLI_ensure_extension(filepath, FILE_MAX, ".dae");
+ RNA_string_set(op->ptr, "filepath", filepath);
+ return true;
+ }
+
+ return false;
+}
+
void WM_OT_collada_export(wmOperatorType *ot)
{
static EnumPropertyItem prop_bc_export_mesh_type[] = {
@@ -297,6 +316,7 @@ void WM_OT_collada_export(wmOperatorType *ot)
ot->invoke = wm_collada_export_invoke;
ot->exec = wm_collada_export_exec;
ot->poll = WM_operator_winactive;
+ ot->check = wm_collada_export_check;
ot->flag |= OPTYPE_PRESET;
@@ -349,7 +369,10 @@ void WM_OT_collada_export(wmOperatorType *ot)
"Export Polygons (Quads & NGons) as Triangles");
RNA_def_boolean(ot->srna, "use_object_instantiation", 1, "Use Object Instances",
- "Instantiate multiple Objects from same Data");
+ "Instantiate multiple Objects from same Data");
+
+ RNA_def_boolean(ot->srna, "use_blender_profile", 1, "Use Blender Profile",
+ "Export additional Blender specific information (for material, shaders, bones, etc.)");
RNA_def_boolean(ot->srna, "sort_by_name", 0, "Sort by Object name",
"Sort exported data by Object name");
@@ -371,6 +394,7 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op)
char filename[FILE_MAX];
int import_units;
int find_chains;
+ int auto_connect;
int fix_orientation;
int min_chain_length;
@@ -382,6 +406,7 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op)
/* Options panel */
import_units = RNA_boolean_get(op->ptr, "import_units");
find_chains = RNA_boolean_get(op->ptr, "find_chains");
+ auto_connect = RNA_boolean_get(op->ptr, "auto_connect");
fix_orientation = RNA_boolean_get(op->ptr, "fix_orientation");
min_chain_length = RNA_int_get(op->ptr, "min_chain_length");
@@ -390,6 +415,7 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op)
C, filename,
import_units,
find_chains,
+ auto_connect,
fix_orientation,
min_chain_length))
{
@@ -424,6 +450,9 @@ static void uiCollada_importSettings(uiLayout *layout, PointerRNA *imfptr)
uiItemR(row, imfptr, "find_chains", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "auto_connect", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "min_chain_length", 0, NULL, ICON_NONE);
}
@@ -466,6 +495,10 @@ void WM_OT_collada_import(wmOperatorType *ot)
"find_chains", 0, "Find Bone Chains",
"Find best matching Bone Chains and ensure bones in chain are connected");
+ RNA_def_boolean(ot->srna,
+ "auto_connect", 0, "Auto Connect",
+ "Set use_connect for parent bones which have exactly one child bone");
+
RNA_def_int(ot->srna,
"min_chain_length",
0,
diff --git a/source/blender/editors/io/io_ops.c b/source/blender/editors/io/io_ops.c
index a70a51a60be..d1e933517a9 100644
--- a/source/blender/editors/io/io_ops.c
+++ b/source/blender/editors/io/io_ops.c
@@ -30,11 +30,18 @@
#include "io_ops.h" /* own include */
+#include "WM_api.h"
+
#ifdef WITH_COLLADA
# include "io_collada.h"
-# include "WM_api.h"
#endif
+#ifdef WITH_ALEMBIC
+# include "io_alembic.h"
+#endif
+
+#include "io_cache.h"
+
void ED_operatortypes_io(void)
{
#ifdef WITH_COLLADA
@@ -42,4 +49,11 @@ void ED_operatortypes_io(void)
WM_operatortype_append(WM_OT_collada_export);
WM_operatortype_append(WM_OT_collada_import);
#endif
+#ifdef WITH_ALEMBIC
+ WM_operatortype_append(WM_OT_alembic_import);
+ WM_operatortype_append(WM_OT_alembic_export);
+#endif
+
+ WM_operatortype_append(CACHEFILE_OT_open);
+ WM_operatortype_append(CACHEFILE_OT_reload);
}
diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c
index 9a8382b2136..2b4f94a37ef 100644
--- a/source/blender/editors/mask/mask_draw.c
+++ b/source/blender/editors/mask/mask_draw.c
@@ -51,6 +51,8 @@
#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "GPU_basic_shader.h"
+
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -100,10 +102,10 @@ static void draw_spline_parents(MaskLayer *UNUSED(masklay), MaskSpline *spline)
if (!spline->tot_point)
return;
- glColor3ub(0, 0, 0);
- glEnable(GL_LINE_STIPPLE);
- glLineStipple(1, 0xAAAA);
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ GPU_basic_shader_line_stipple(1, 0xAAAA);
+ glColor3ub(0, 0, 0);
glBegin(GL_LINES);
for (i = 0; i < spline->tot_point; i++) {
@@ -121,7 +123,7 @@ static void draw_spline_parents(MaskLayer *UNUSED(masklay), MaskSpline *spline)
glEnd();
- glDisable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
}
#endif
@@ -455,7 +457,8 @@ static void mask_draw_curve_type(const bContext *C, MaskSpline *spline, float (*
case MASK_DT_DASH:
default:
- glEnable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ GPU_basic_shader_line_stipple(3, 0xAAAA);
#ifdef USE_XOR
glEnable(GL_COLOR_LOGIC_OP);
@@ -463,7 +466,6 @@ static void mask_draw_curve_type(const bContext *C, MaskSpline *spline, float (*
#endif
mask_color_active_tint(rgb_tmp, rgb_spline, is_active);
glColor4ubv(rgb_tmp);
- glLineStipple(3, 0xaaaa);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, points);
glDrawArrays(draw_method, 0, tot_point);
@@ -473,10 +475,10 @@ static void mask_draw_curve_type(const bContext *C, MaskSpline *spline, float (*
#endif
mask_color_active_tint(rgb_tmp, rgb_black, is_active);
glColor4ubv(rgb_tmp);
- glLineStipple(3, 0x5555);
+ GPU_basic_shader_line_stipple(3, 0x5555);
glDrawArrays(draw_method, 0, tot_point);
- glDisable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
break;
diff --git a/source/blender/editors/mask/mask_editaction.c b/source/blender/editors/mask/mask_editaction.c
index bcf9ee5c88d..16147bdc7f8 100644
--- a/source/blender/editors/mask/mask_editaction.c
+++ b/source/blender/editors/mask/mask_editaction.c
@@ -201,6 +201,36 @@ void ED_masklayer_frames_select_border(MaskLayer *masklay, float min, float max,
}
}
+/* select the frames in this layer that occur within the lasso/circle region specified */
+void ED_masklayer_frames_select_region(KeyframeEditData *ked, MaskLayer *masklay, short tool, short select_mode)
+{
+ MaskLayerShape *masklay_shape;
+
+ if (masklay == NULL)
+ return;
+
+ /* only select frames which are within the region */
+ for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) {
+ /* construct a dummy point coordinate to do this testing with */
+ float pt[2] = {0};
+
+ pt[0] = masklay_shape->frame;
+ pt[1] = ked->channel_y;
+
+ /* check the necessary regions */
+ if (tool == BEZT_OK_CHANNEL_LASSO) {
+ /* Lasso */
+ if (keyframe_region_lasso_test(ked->data, pt))
+ masklayshape_select(masklay_shape, select_mode);
+ }
+ else if (tool == BEZT_OK_CHANNEL_CIRCLE) {
+ /* Circle */
+ if (keyframe_region_circle_test(ked->data, pt))
+ masklayshape_select(masklay_shape, select_mode);
+ }
+ }
+}
+
/* ***************************************** */
/* Frame Editing Tools */
diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt
index 0280f662a26..8783367ef7e 100644
--- a/source/blender/editors/mesh/CMakeLists.txt
+++ b/source/blender/editors/mesh/CMakeLists.txt
@@ -55,6 +55,7 @@ set(SRC
editmesh_rip_edge.c
editmesh_select.c
editmesh_tools.c
+ editmesh_undo.c
editmesh_utils.c
mesh_data.c
mesh_ops.c
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
index 01be8f848aa..c4e87614732 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -53,6 +53,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "GPU_draw.h"
#include "GPU_buffers.h"
/* own include */
@@ -433,7 +434,7 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, bool select, bool exten
if (ENDIAN_ORDER == B_ENDIAN) {
IMB_convert_rgba_to_abgr(ibuf);
}
- WM_framebuffer_to_index_array(ibuf->rect, size[0] * size[1]);
+ GPU_select_to_index_array(ibuf->rect, size[0] * size[1]);
a = size[0] * size[1];
while (a--) {
diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c
index 2a9f9c830f4..3725590c188 100644
--- a/source/blender/editors/mesh/editmesh_add.c
+++ b/source/blender/editors/mesh/editmesh_add.c
@@ -461,6 +461,7 @@ static int add_primitive_monkey_exec(bContext *C, wmOperator *op)
bool enter_editmode;
unsigned int layer;
bool was_editmode;
+ const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, &enter_editmode, &layer, NULL);
@@ -471,9 +472,13 @@ static int add_primitive_monkey_exec(bContext *C, wmOperator *op)
em = BKE_editmesh_from_object(obedit);
+ if (calc_uvs) {
+ ED_mesh_uv_texture_ensure(obedit->data, NULL);
+ }
+
if (!EDBM_op_call_and_selectf(
em, op, "verts.out", false,
- "create_monkey matrix=%m4", mat))
+ "create_monkey matrix=%m4 calc_uvs=%b", mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
@@ -498,6 +503,8 @@ void MESH_OT_primitive_monkey_add(wmOperatorType *ot)
ED_object_add_unit_props(ot);
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* props */
+ ED_object_add_mesh_props(ot);
ED_object_add_generic_props(ot, true);
}
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index 37e9a0edd00..a81add7a86e 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -44,6 +44,8 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "UI_interface.h"
+
#include "ED_mesh.h"
#include "ED_numinput.h"
#include "ED_screen.h"
@@ -56,30 +58,47 @@
#define MVAL_PIXEL_MARGIN 5.0f
+/* until implement profile = 0 case, need to clamp somewhat above zero */
+#define PROFILE_HARD_MIN 0.15f
+
+#define SEGMENTS_HARD_MAX 1000
+
+/* which value is mouse movement and numeric input controlling? */
+#define OFFSET_VALUE 0
+#define OFFSET_VALUE_PERCENT 1
+#define PROFILE_VALUE 2
+#define SEGMENTS_VALUE 3
+#define NUM_VALUE_KINDS 4
+
+static const char *value_rna_name[NUM_VALUE_KINDS] = {"offset", "offset", "profile", "segments"};
+static const float value_clamp_min[NUM_VALUE_KINDS] = {0.0f, 0.0f, PROFILE_HARD_MIN, 1.0f};
+static const float value_clamp_max[NUM_VALUE_KINDS] = {1e6, 100.0f, 1.0f, SEGMENTS_HARD_MAX};
+static const float value_start[NUM_VALUE_KINDS] = {0.0f, 0.0f, 0.5f, 1.0f};
+static const float value_scale_per_inch[NUM_VALUE_KINDS] = { 0.0f, 100.0f, 1.0f, 4.0f};
+
typedef struct {
BMEditMesh *em;
- float initial_length;
- float pixel_size; /* use when mouse input is interpreted as spatial distance */
+ float initial_length[NUM_VALUE_KINDS];
+ float scale[NUM_VALUE_KINDS];
+ NumInput num_input[NUM_VALUE_KINDS];
+ float shift_value[NUM_VALUE_KINDS]; /* The current value when shift is pressed. Negative when shift not active. */
bool is_modal;
- NumInput num_input;
- float shift_factor; /* The current factor when shift is pressed. Negative when shift not active. */
/* modal only */
float mcenter[2];
BMBackup mesh_backup;
void *draw_handle_pixel;
short twtype;
+ short value_mode; /* Which value does mouse movement and numeric input affect? */
float segments; /* Segments as float so smooth mouse pan works in small increments */
} BevelData;
-#define HEADER_LENGTH 180
-
static void edbm_bevel_update_header(bContext *C, wmOperator *op)
{
const char *str = IFACE_("Confirm: (Enter/LMB), Cancel: (Esc/RMB), Mode: %s (M), Clamp Overlap: %s (C), "
- "Vertex Only: %s (V), Offset: %s, Segments: %d");
+ "Vertex Only: %s (V), Profile Control: %s (P), Offset: %s, Segments: %d, Profile: %.3f");
- char msg[HEADER_LENGTH];
+ char msg[UI_MAX_DRAW_STR];
ScrArea *sa = CTX_wm_area(C);
Scene *sce = CTX_data_scene(C);
@@ -89,8 +108,8 @@ static void edbm_bevel_update_header(bContext *C, wmOperator *op)
const char *type_str;
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "offset_type");
- if (hasNumInput(&opdata->num_input)) {
- outputNumInput(&opdata->num_input, offset_str, &sce->unit);
+ if (hasNumInput(&opdata->num_input[OFFSET_VALUE])) {
+ outputNumInput(&opdata->num_input[OFFSET_VALUE], offset_str, &sce->unit);
}
else {
BLI_snprintf(offset_str, NUM_STR_REP_LEN, "%f", RNA_float_get(op->ptr, "offset"));
@@ -98,10 +117,11 @@ static void edbm_bevel_update_header(bContext *C, wmOperator *op)
RNA_property_enum_name_gettexted(C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &type_str);
- BLI_snprintf(msg, HEADER_LENGTH, str, type_str,
+ BLI_snprintf(msg, sizeof(msg), str, type_str,
WM_bool_as_string(RNA_boolean_get(op->ptr, "clamp_overlap")),
WM_bool_as_string(RNA_boolean_get(op->ptr, "vertex_only")),
- offset_str, RNA_int_get(op->ptr, "segments"));
+ WM_bool_as_string(opdata->value_mode == PROFILE_VALUE),
+ offset_str, RNA_int_get(op->ptr, "segments"), RNA_float_get(op->ptr, "profile"));
ED_area_headerprint(sa, msg);
}
@@ -113,6 +133,8 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
Scene *scene = CTX_data_scene(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BevelData *opdata;
+ float pixels_per_inch;
+ int i;
if (em->bm->totvertsel == 0) {
return false;
@@ -122,13 +144,26 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
opdata->em = em;
opdata->is_modal = is_modal;
- opdata->shift_factor = -1.0f;
-
- initNumInput(&opdata->num_input);
- opdata->num_input.idx_max = 0;
- opdata->num_input.val_flag[0] |= NUM_NO_NEGATIVE;
- opdata->num_input.unit_sys = scene->unit.system;
- opdata->num_input.unit_type[0] = B_UNIT_NONE; /* Not sure this is a factor or a unit? */
+ opdata->value_mode = OFFSET_VALUE;
+ opdata->segments = (float) RNA_int_get(op->ptr, "segments");
+ pixels_per_inch = U.dpi * U.pixelsize;
+
+ for (i = 0; i < NUM_VALUE_KINDS; i++) {
+ opdata->shift_value[i] = -1.0f;
+ /* note: scale for OFFSET_VALUE will get overwritten in edbm_bevel_invoke */
+ opdata->scale[i] = value_scale_per_inch[i] / pixels_per_inch;
+
+ initNumInput(&opdata->num_input[i]);
+ opdata->num_input[i].idx_max = 0;
+ opdata->num_input[i].val_flag[0] |= NUM_NO_NEGATIVE;
+ if (i == SEGMENTS_VALUE) {
+ opdata->num_input[i].val_flag[0] |= NUM_NO_FRACTION | NUM_NO_ZERO;
+ }
+ if (i == OFFSET_VALUE) {
+ opdata->num_input[i].unit_sys = scene->unit.system;
+ }
+ opdata->num_input[i].unit_type[0] = B_UNIT_NONE; /* Not sure this is a factor or a unit? */
+ }
/* avoid the cost of allocating a bm copy */
if (is_modal) {
@@ -136,7 +171,8 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
ARegion *ar = CTX_wm_region(C);
opdata->mesh_backup = EDBM_redo_state_store(em);
- opdata->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL);
+ opdata->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ED_region_draw_mouse_line_cb,
+ opdata->mcenter, REGION_DRAW_POST_PIXEL);
G.moving = G_TRANSFORM_EDIT;
if (v3d) {
@@ -167,13 +203,15 @@ static bool edbm_bevel_calc(wmOperator *op)
EDBM_redo_state_restore(opdata->mesh_backup, em, false);
}
- if (em->ob)
+ if (em->ob) {
material = CLAMPIS(material, -1, em->ob->totcol - 1);
+ }
EDBM_op_init(em, &bmop, op,
"bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i profile=%f clamp_overlap=%b "
"material=%i loop_slide=%b",
- BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile, clamp_overlap, material, loop_slide);
+ BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile,
+ clamp_overlap, material, loop_slide);
BMO_op_exec(em->bm, &bmop);
@@ -185,8 +223,9 @@ static bool edbm_bevel_calc(wmOperator *op)
}
/* no need to de-select existing geometry */
- if (!EDBM_op_finish(em, &bmop, op, true))
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
return false;
+ }
EDBM_mesh_normals_update(opdata->em);
@@ -250,12 +289,37 @@ static int edbm_bevel_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+static void edbm_bevel_calc_initial_length(wmOperator *op, const wmEvent *event, bool mode_changed)
+{
+ BevelData *opdata;
+ float mlen[2], len, value, sc, st;
+ int vmode;
+
+ opdata = op->customdata;
+ mlen[0] = opdata->mcenter[0] - event->mval[0];
+ mlen[1] = opdata->mcenter[1] - event->mval[1];
+ len = len_v2(mlen);
+ vmode = opdata->value_mode;
+ if (mode_changed) {
+ /* If current value is not default start value, adjust len so that
+ * the scaling and offset in edbm_bevel_mouse_set_value will
+ * start at current value */
+ value = (vmode == SEGMENTS_VALUE) ?
+ opdata->segments : RNA_float_get(op->ptr, value_rna_name[vmode]);
+ sc = opdata->scale[vmode];
+ st = value_start[vmode];
+ if (value != value_start[vmode]) {
+ len = (st + sc * (len - MVAL_PIXEL_MARGIN) - value) / sc;
+ }
+ }
+ opdata->initial_length[opdata->value_mode] = len;
+}
+
static int edbm_bevel_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
/* TODO make modal keymap (see fly mode) */
RegionView3D *rv3d = CTX_wm_region_view3d(C);
BevelData *opdata;
- float mlen[2];
float center_3d[3];
if (!edbm_bevel_init(C, op, true)) {
@@ -270,10 +334,10 @@ static int edbm_bevel_invoke(bContext *C, wmOperator *op, const wmEvent *event)
* ideally this will never happen and should be checked for above */
opdata->mcenter[0] = opdata->mcenter[1] = 0;
}
- mlen[0] = opdata->mcenter[0] - event->mval[0];
- mlen[1] = opdata->mcenter[1] - event->mval[1];
- opdata->initial_length = len_v2(mlen);
- opdata->pixel_size = rv3d ? ED_view3d_pixel_size(rv3d, center_3d) : 1.0f;
+ edbm_bevel_calc_initial_length(op, event, false);
+
+ /* for OFFSET_VALUE only, the scale is the size of a pixel under the mouse in 3d space */
+ opdata->scale[OFFSET_VALUE] = rv3d ? ED_view3d_pixel_size(rv3d, center_3d) : 1.0f;
edbm_bevel_update_header(C, op);
@@ -287,59 +351,72 @@ static int edbm_bevel_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
-static float edbm_bevel_mval_factor(wmOperator *op, const wmEvent *event)
+static void edbm_bevel_mouse_set_value(wmOperator *op, const wmEvent *event)
{
BevelData *opdata = op->customdata;
- bool use_dist;
- bool is_percent;
+ int vmode = opdata->value_mode;
float mdiff[2];
- float factor;
+ float value;
mdiff[0] = opdata->mcenter[0] - event->mval[0];
mdiff[1] = opdata->mcenter[1] - event->mval[1];
- is_percent = (RNA_enum_get(op->ptr, "offset_type") == BEVEL_AMT_PERCENT);
- use_dist = !is_percent;
- factor = ((len_v2(mdiff) - MVAL_PIXEL_MARGIN) - opdata->initial_length) * opdata->pixel_size;
+ value = ((len_v2(mdiff) - MVAL_PIXEL_MARGIN) - opdata->initial_length[vmode]);
+
+ /* Scale according to value mode */
+ value = value_start[vmode] + value * opdata->scale[vmode];
/* Fake shift-transform... */
if (event->shift) {
- if (opdata->shift_factor < 0.0f) {
- opdata->shift_factor = RNA_float_get(op->ptr, "offset");
- if (is_percent) {
- opdata->shift_factor /= 100.0f;
- }
+ if (opdata->shift_value[vmode] < 0.0f) {
+ opdata->shift_value[vmode] = (vmode == SEGMENTS_VALUE) ?
+ opdata->segments : RNA_float_get(op->ptr, value_rna_name[vmode]);
}
- factor = (factor - opdata->shift_factor) * 0.1f + opdata->shift_factor;
+ value = (value - opdata->shift_value[vmode]) * 0.1f + opdata->shift_value[vmode];
}
- else if (opdata->shift_factor >= 0.0f) {
- opdata->shift_factor = -1.0f;
+ else if (opdata->shift_value[vmode] >= 0.0f) {
+ opdata->shift_value[vmode] = -1.0f;
}
- /* clamp differently based on distance/factor */
- if (use_dist) {
- if (factor < 0.0f) factor = 0.0f;
+ /* clamp accordingto value mode, and store value back */
+ CLAMP(value, value_clamp_min[vmode], value_clamp_max[vmode]);
+ if (vmode == SEGMENTS_VALUE) {
+ opdata->segments = value;
+ RNA_int_set(op->ptr, "segments", (int)(value + 0.5f));
}
else {
- CLAMP(factor, 0.0f, 1.0f);
- if (is_percent) {
- factor *= 100.0f;
- }
+ RNA_float_set(op->ptr, value_rna_name[vmode], value);
}
+}
- return factor;
+static void edbm_bevel_numinput_set_value(wmOperator *op)
+{
+ BevelData *opdata = op->customdata;
+ float value;
+ int vmode;
+
+ vmode = opdata->value_mode;
+ value = (vmode == SEGMENTS_VALUE) ?
+ opdata->segments : RNA_float_get(op->ptr, value_rna_name[vmode]);
+ applyNumInput(&opdata->num_input[vmode], &value);
+ CLAMP(value, value_clamp_min[vmode], value_clamp_max[vmode]);
+ if (vmode == SEGMENTS_VALUE) {
+ opdata->segments = value;
+ RNA_int_set(op->ptr, "segments", (int)value);
+ }
+ else {
+ RNA_float_set(op->ptr, value_rna_name[vmode], value);
+ }
}
static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
BevelData *opdata = op->customdata;
- const bool has_numinput = hasNumInput(&opdata->num_input);
+ const bool has_numinput = hasNumInput(&opdata->num_input[opdata->value_mode]);
/* Modal numinput active, try to handle numeric inputs first... */
- if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &opdata->num_input, event)) {
- float value = RNA_float_get(op->ptr, "offset");
- applyNumInput(&opdata->num_input, &value);
- RNA_float_set(op->ptr, "offset", value);
+ if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &opdata->num_input[opdata->value_mode], event)) {
+ edbm_bevel_numinput_set_value(op);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
return OPERATOR_RUNNING_MODAL;
@@ -354,9 +431,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
case MOUSEMOVE:
if (!has_numinput) {
- const float factor = edbm_bevel_mval_factor(op, event);
- RNA_float_set(op->ptr, "offset", factor);
-
+ edbm_bevel_mouse_set_value(op, event);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
handled = true;
@@ -426,12 +501,18 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (type > BEVEL_AMT_PERCENT) {
type = BEVEL_AMT_OFFSET;
}
+ if (opdata->value_mode == OFFSET_VALUE && type == BEVEL_AMT_PERCENT)
+ opdata->value_mode = OFFSET_VALUE_PERCENT;
+ else if (opdata->value_mode == OFFSET_VALUE_PERCENT && type != BEVEL_AMT_PERCENT)
+ opdata->value_mode = OFFSET_VALUE;
RNA_property_enum_set(op->ptr, prop, type);
}
- /* Update factor accordingly to new offset_type. */
- if (!has_numinput) {
- RNA_float_set(op->ptr, "offset", edbm_bevel_mval_factor(op, event));
- }
+ /* Update offset accordingly to new offset_type. */
+ if (!has_numinput &&
+ (opdata->value_mode == OFFSET_VALUE || opdata->value_mode == OFFSET_VALUE_PERCENT))
+ {
+ edbm_bevel_mouse_set_value(op, event);
+ }
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
handled = true;
@@ -448,6 +529,28 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
edbm_bevel_update_header(C, op);
handled = true;
break;
+ case PKEY:
+ if (event->val == KM_RELEASE)
+ break;
+ if (opdata->value_mode == PROFILE_VALUE) {
+ opdata->value_mode = OFFSET_VALUE;
+ }
+ else {
+ opdata->value_mode = PROFILE_VALUE;
+ }
+ edbm_bevel_calc_initial_length(op, event, true);
+ break;
+ case SKEY:
+ if (event->val == KM_RELEASE)
+ break;
+ if (opdata->value_mode == SEGMENTS_VALUE) {
+ opdata->value_mode = OFFSET_VALUE;
+ }
+ else {
+ opdata->value_mode = SEGMENTS_VALUE;
+ }
+ edbm_bevel_calc_initial_length(op, event, true);
+ break;
case VKEY:
if (event->val == KM_RELEASE)
break;
@@ -464,10 +567,8 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
/* Modal numinput inactive, try to handle numeric inputs last... */
- if (!handled && event->val == KM_PRESS && handleNumInput(C, &opdata->num_input, event)) {
- float value = RNA_float_get(op->ptr, "offset");
- applyNumInput(&opdata->num_input, &value);
- RNA_float_set(op->ptr, "offset", value);
+ if (!handled && event->val == KM_PRESS && handleNumInput(C, &opdata->num_input[opdata->value_mode], event)) {
+ edbm_bevel_numinput_set_value(op);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
return OPERATOR_RUNNING_MODAL;
@@ -518,11 +619,13 @@ void MESH_OT_bevel(wmOperatorType *ot)
RNA_def_enum(ot->srna, "offset_type", offset_type_items, 0, "Amount Type", "What distance Amount measures");
prop = RNA_def_float(ot->srna, "offset", 0.0f, -1e6f, 1e6f, "Amount", "", 0.0f, 1.0f);
RNA_def_property_float_array_funcs_runtime(prop, NULL, NULL, mesh_ot_bevel_offset_range_func);
- RNA_def_int(ot->srna, "segments", 1, 1, 50, "Segments", "Segments for curved edge", 1, 8);
- RNA_def_float(ot->srna, "profile", 0.5f, 0.15f, 1.0f, "Profile", "Controls profile shape (0.5 = round)", 0.15f, 1.0f);
+ RNA_def_int(ot->srna, "segments", 1, 1, SEGMENTS_HARD_MAX, "Segments", "Segments for curved edge", 1, 8);
+ RNA_def_float(ot->srna, "profile", 0.5f, PROFILE_HARD_MIN, 1.0f, "Profile",
+ "Controls profile shape (0.5 = round)", PROFILE_HARD_MIN, 1.0f);
RNA_def_boolean(ot->srna, "vertex_only", false, "Vertex Only", "Bevel only vertices");
RNA_def_boolean(ot->srna, "clamp_overlap", false, "Clamp Overlap",
- "Do not allow beveled edges/vertices to overlap each other");
+ "Do not allow beveled edges/vertices to overlap each other");
RNA_def_boolean(ot->srna, "loop_slide", true, "Loop Slide", "Prefer slide along edge to even widths");
- RNA_def_int(ot->srna, "material", -1, -1, INT_MAX, "Material", "Material for bevel faces (-1 means use adjacent faces)", -1, 100);
+ RNA_def_int(ot->srna, "material", -1, -1, INT_MAX, "Material",
+ "Material for bevel faces (-1 means use adjacent faces)", -1, 100);
}
diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c
index 1dfb1cddd2c..d4c49833c2c 100644
--- a/source/blender/editors/mesh/editmesh_extrude.c
+++ b/source/blender/editors/mesh/editmesh_extrude.c
@@ -287,8 +287,7 @@ static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op)
short a;
/* dvec */
- normalize_v3_v3(dvec, rv3d->persinv[2]);
- mul_v3_fl(dvec, offs);
+ normalize_v3_v3_length(dvec, rv3d->persinv[2], offs);
/* base correction */
copy_m3_m4(bmat, obedit->obmat);
diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c
index 097117cce6b..3e0747f055f 100644
--- a/source/blender/editors/mesh/editmesh_inset.c
+++ b/source/blender/editors/mesh/editmesh_inset.c
@@ -44,6 +44,8 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "UI_interface.h"
+
#include "ED_mesh.h"
#include "ED_numinput.h"
#include "ED_screen.h"
@@ -54,8 +56,6 @@
#include "mesh_intern.h" /* own include */
-#define HEADER_LENGTH 180
-
typedef struct {
float old_thickness;
float old_depth;
@@ -83,7 +83,7 @@ static void edbm_inset_update_header(wmOperator *op, bContext *C)
const char *str = IFACE_("Confirm: Enter/LClick, Cancel: (Esc/RClick), Thickness: %s, "
"Depth (Ctrl to tweak): %s (%s), Outset (O): (%s), Boundary (B): (%s), Individual (I): (%s)");
- char msg[HEADER_LENGTH];
+ char msg[UI_MAX_DRAW_STR];
ScrArea *sa = CTX_wm_area(C);
Scene *sce = CTX_data_scene(C);
@@ -95,7 +95,7 @@ static void edbm_inset_update_header(wmOperator *op, bContext *C)
BLI_snprintf(flts_str, NUM_STR_REP_LEN, "%f", RNA_float_get(op->ptr, "thickness"));
BLI_snprintf(flts_str + NUM_STR_REP_LEN, NUM_STR_REP_LEN, "%f", RNA_float_get(op->ptr, "depth"));
}
- BLI_snprintf(msg, HEADER_LENGTH, str,
+ BLI_snprintf(msg, sizeof(msg), str,
flts_str,
flts_str + NUM_STR_REP_LEN,
WM_bool_as_string(opdata->modify_depth),
diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c
index 69588928253..de93211bec4 100644
--- a/source/blender/editors/mesh/editmesh_intersect.c
+++ b/source/blender/editors/mesh/editmesh_intersect.c
@@ -439,7 +439,7 @@ static void bm_face_split_by_edges_island_connect(
LinkNode *e_link, const int e_link_len,
MemArena *mem_arena_edgenet)
{
- BMEdge **edge_arr = BLI_memarena_alloc(mem_arena_edgenet, sizeof(BMEdge **) * e_link_len);
+ BMEdge **edge_arr = BLI_memarena_alloc(mem_arena_edgenet, sizeof(*edge_arr) * e_link_len);
int edge_arr_len = 0;
while (e_link) {
@@ -563,7 +563,7 @@ static BMEdge *bm_face_split_edge_find(
if (UNLIKELY(BM_edge_exists(v_pivot, l_iter->e->v1) ||
BM_edge_exists(v_pivot, l_iter->e->v2)))
{
- /* very unlikley but will cause complications splicing the verts together,
+ /* very unlikely but will cause complications splicing the verts together,
* so just skip this case */
ok = false;
}
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 0fd56fbcc4e..a84b8d9dcc8 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -2283,7 +2283,7 @@ static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfe
BMEdge **edge_array = BLI_array_alloca(edge_array, edge_array_len);
- /* point to knife edges we've created edges in, edge_array aligned */
+ /* point to knife edges we've created edges in, edge_array aligned */
KnifeEdge **kfe_array = BLI_array_alloca(kfe_array, edge_array_len);
BLI_assert(BLI_gset_size(kcd->edgenet.edge_visit) == 0);
diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c
index 31e1a22fe74..f1c1e4105d0 100644
--- a/source/blender/editors/mesh/editmesh_loopcut.c
+++ b/source/blender/editors/mesh/editmesh_loopcut.c
@@ -47,6 +47,8 @@
#include "BIF_gl.h"
+#include "UI_interface.h"
+
#include "ED_screen.h"
#include "ED_space_api.h"
#include "ED_view3d.h"
@@ -780,7 +782,7 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (show_cuts) {
Scene *sce = CTX_data_scene(C);
- char buf[64 + NUM_STR_REP_LEN * 2];
+ char buf[UI_MAX_DRAW_STR];
char str_rep[NUM_STR_REP_LEN * 2];
if (hasNumInput(&lcd->num)) {
outputNumInput(&lcd->num, str_rep, &sce->unit);
diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c
index 55ed0e521ea..4431712e720 100644
--- a/source/blender/editors/mesh/editmesh_path.c
+++ b/source/blender/editors/mesh/editmesh_path.c
@@ -588,6 +588,17 @@ static BMElem *edbm_elem_find_nearest(ViewContext *vc, const char htype)
return NULL;
}
+static BMElem *edbm_elem_active_elem_or_face_get(BMesh *bm)
+{
+ BMElem *ele = BM_mesh_active_elem_get(bm);
+
+ if ((ele == NULL) && bm->act_face && BM_elem_flag_test(bm->act_face, BM_ELEM_SELECT)) {
+ ele = (BMElem *)bm->act_face;
+ }
+
+ return ele;
+}
+
static int edbm_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (RNA_struct_property_is_set(op->ptr, "index")) {
@@ -605,7 +616,7 @@ static int edbm_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmE
view3d_operator_needs_opengl(C);
BMElem *ele_src, *ele_dst;
- if (!(ele_src = BM_mesh_active_elem_get(em->bm)) ||
+ if (!(ele_src = edbm_elem_active_elem_or_face_get(em->bm)) ||
!(ele_dst = edbm_elem_find_nearest(&vc, ele_src->head.htype)))
{
/* special case, toggle edge tags even when we don't have a path */
@@ -655,7 +666,7 @@ static int edbm_shortest_path_pick_exec(bContext *C, wmOperator *op)
}
BMElem *ele_src, *ele_dst;
- if (!(ele_src = BM_mesh_active_elem_get(em->bm)) ||
+ if (!(ele_src = edbm_elem_active_elem_or_face_get(em->bm)) ||
!(ele_dst = EDBM_elem_from_index_any(em, index)))
{
return OPERATOR_CANCELLED;
diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c
index c7a7828f3b2..e31e4096ded 100644
--- a/source/blender/editors/mesh/editmesh_rip.c
+++ b/source/blender/editors/mesh/editmesh_rip.c
@@ -77,14 +77,14 @@ static float edbm_rip_edgedist_squared(
const float dist_2d = len_v2v2(vec1, vec2);
if (dist_2d > FLT_EPSILON) {
const float dist = inset / dist_2d;
- BLI_assert(finite(dist));
+ BLI_assert(isfinite(dist));
interp_v2_v2v2(vec1, vec1, vec2, dist);
interp_v2_v2v2(vec2, vec2, vec1, dist);
}
}
dist_sq = dist_squared_to_line_segment_v2(mvalf, vec1, vec2);
- BLI_assert(finite(dist_sq));
+ BLI_assert(isfinite(dist_sq));
return dist_sq;
}
@@ -153,8 +153,7 @@ static float edbm_rip_edge_side_measure(
ED_view3d_project_float_v2_m4(ar, e->v2->co, e_v2_co, projectMat);
sub_v2_v2v2(vec, cent, mid);
- normalize_v2(vec);
- mul_v2_fl(vec, 0.01f);
+ normalize_v2_length(vec, 0.01f);
/* rather then adding to both verts, subtract from the mouse */
sub_v2_v2v2(fmval_tweak, fmval, vec);
@@ -396,7 +395,7 @@ static void edbm_ripsel_deselect_helper(BMesh *bm, EdgeLoopPair *eloop_pairs,
* return an un-ordered array of loop pairs
* use for rebuilding face-fill
*
- * \note the method currenly used fails for edges with 3+ face users and gives
+ * \note the method currently used fails for edges with 3+ face users and gives
* nasty holes in the mesh, there isnt a good way of knowing ahead of time
* which loops will be split apart (its possible to figure out but quite involved).
* So for now this is a known limitation of current rip-fill option.
@@ -463,7 +462,7 @@ static void edbm_tagged_loop_pairs_do_fill_faces(BMesh *bm, UnorderedLoopPair *u
if ((ulp->l_pair[0] && ulp->l_pair[1]) &&
(ulp->l_pair[0]->e != ulp->l_pair[1]->e))
{
- /* time has come to make a face! */
+ /* time has come to make a face! */
BMVert *v_shared = BM_edge_share_vert(ulp->l_pair[0]->e, ulp->l_pair[1]->e);
BMFace *f, *f_example = ulp->l_pair[0]->f;
BMLoop *l_iter;
@@ -749,10 +748,8 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
}
if (do_fill) {
- if (do_fill) {
- /* match extrude vert-order */
- BM_edge_create(bm, vout[1], vout[0], NULL, BM_CREATE_NOP);
- }
+ /* match extrude vert-order */
+ BM_edge_create(bm, vout[1], vout[0], NULL, BM_CREATE_NOP);
}
MEM_freeN(vout);
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index 84ae35fae6e..a6de1b284b7 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -32,6 +32,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_bitmap.h"
+#include "BLI_bitmap_draw_2d.h"
#include "BLI_listbase.h"
#include "BLI_linklist.h"
#include "BLI_linklist_stack.h"
@@ -294,7 +295,7 @@ bool EDBM_backbuf_border_mask_init(ViewContext *vc, const int mcords[][2], short
lasso_mask_data.px = dr_mask;
lasso_mask_data.width = (xmax - xmin) + 1;
- fill_poly_v2i_n(
+ BLI_bitmap_draw_2d_poly_v2i_n(
xmin, ymin, xmax + 1, ymax + 1,
mcords, tot,
edbm_mask_lasso_px_cb, &lasso_mask_data);
@@ -2453,7 +2454,7 @@ static void select_linked_delimit_begin(BMesh *bm, int delimit)
const bool is_walk_ok = (
(select_linked_delimit_test(e, delimit, &delimit_data) == false));
- BMO_elem_flag_set(bm, e, BMO_ELE_TAG, is_walk_ok);
+ BMO_edge_flag_set(bm, e, BMO_ELE_TAG, is_walk_ok);
}
}
}
@@ -2496,7 +2497,7 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op)
if (delimit) {
BMEdge *e;
BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (!BMO_elem_flag_test(bm, e, BMO_ELE_TAG)) {
+ if (!BMO_edge_flag_test(bm, e, BMO_ELE_TAG)) {
BM_elem_flag_disable(e->v1, BM_ELEM_TAG);
BM_elem_flag_disable(e->v2, BM_ELEM_TAG);
}
@@ -2552,7 +2553,7 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op)
BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
BM_elem_flag_set(
e, BM_ELEM_TAG,
- (BM_elem_flag_test(e, BM_ELEM_SELECT) && BMO_elem_flag_test(bm, e, BMO_ELE_TAG)));
+ (BM_elem_flag_test(e, BM_ELEM_SELECT) && BMO_edge_flag_test(bm, e, BMO_ELE_TAG)));
}
}
else {
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index ba17684dd39..7e31deba2c7 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -49,6 +49,7 @@
#include "BKE_material.h"
#include "BKE_context.h"
+#include "BKE_deform.h"
#include "BKE_depsgraph.h"
#include "BKE_report.h"
#include "BKE_texture.h"
@@ -79,6 +80,8 @@
#include "mesh_intern.h" /* own include */
+#include "bmesh_tools.h"
+
#define USE_FACE_CREATE_SEL_EXTEND
static int edbm_subdivide_exec(bContext *C, wmOperator *op)
@@ -312,9 +315,10 @@ void EMBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em)
if (ED_view3d_project_float_object(ar, eve->co, mval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
if (ED_transform_snap_object_project_view3d_mixed(
snap_context,
+ SCE_SELECT_FACE,
&(const struct SnapObjectParams){
- .snap_select = SNAP_NOT_OBEDIT,
- .snap_to_flag = SCE_SELECT_FACE,
+ .snap_select = SNAP_NOT_ACTIVE,
+ .use_object_edit_cage = false,
},
mval, NULL, true,
co_proj, NULL))
@@ -2909,7 +2913,7 @@ static int edbm_knife_cut_exec(bContext *C, wmOperator *op)
}
}
- BMO_elem_flag_set(bm, be, ELE_EDGE_CUT, is_cut);
+ BMO_edge_flag_set(bm, be, ELE_EDGE_CUT, is_cut);
}
@@ -2981,7 +2985,9 @@ static Base *mesh_separate_tagged(Main *bmain, Scene *scene, Base *base_old, BMe
Object *obedit = base_old->object;
BMesh *bm_new;
- bm_new = BM_mesh_create(&bm_mesh_allocsize_default);
+ bm_new = BM_mesh_create(
+ &bm_mesh_allocsize_default,
+ &((struct BMeshCreateParams){.use_toolflags = true,}));
BM_mesh_elem_toolflags_ensure(bm_new); /* needed for 'duplicate' bmo */
CustomData_copy(&bm_old->vdata, &bm_new->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
@@ -3074,7 +3080,7 @@ static void bm_mesh_hflag_flush_vert(BMesh *bm, const char hflag)
* \note This could be used for split-by-material for non mesh types.
* \note This could take material data from another object or args.
*/
-static void mesh_separate_material_assign_mat_nr(Object *ob, const short mat_nr)
+static void mesh_separate_material_assign_mat_nr(Main *bmain, Object *ob, const short mat_nr)
{
ID *obdata = ob->data;
@@ -3110,18 +3116,20 @@ static void mesh_separate_material_assign_mat_nr(Object *ob, const short mat_nr)
ma_obdata = NULL;
}
- BKE_material_clear_id(obdata, true);
- BKE_material_resize_object(ob, 1, true);
- BKE_material_resize_id(obdata, 1, true);
+ BKE_material_clear_id(bmain, obdata, true);
+ BKE_material_resize_object(bmain, ob, 1, true);
+ BKE_material_resize_id(bmain, obdata, 1, true);
ob->mat[0] = ma_ob;
+ id_us_plus((ID *)ma_ob);
ob->matbits[0] = matbit;
(*matarar)[0] = ma_obdata;
+ id_us_plus((ID *)ma_obdata);
}
else {
- BKE_material_clear_id(obdata, true);
- BKE_material_resize_object(ob, 0, true);
- BKE_material_resize_id(obdata, 0, true);
+ BKE_material_clear_id(bmain, obdata, true);
+ BKE_material_resize_object(bmain, ob, 0, true);
+ BKE_material_resize_id(bmain, obdata, 0, true);
}
}
@@ -3156,7 +3164,7 @@ static bool mesh_separate_material(Main *bmain, Scene *scene, Base *base_old, BM
/* leave the current object with some materials */
if (tot == bm_old->totface) {
- mesh_separate_material_assign_mat_nr(base_old->object, mat_nr);
+ mesh_separate_material_assign_mat_nr(bmain, base_old->object, mat_nr);
/* since we're in editmode, must set faces here */
BM_ITER_MESH (f, &iter, bm_old, BM_FACES_OF_MESH) {
@@ -3168,7 +3176,7 @@ static bool mesh_separate_material(Main *bmain, Scene *scene, Base *base_old, BM
/* Move selection into a separate object */
base_new = mesh_separate_tagged(bmain, scene, base_old, bm_old);
if (base_new) {
- mesh_separate_material_assign_mat_nr(base_new->object, mat_nr);
+ mesh_separate_material_assign_mat_nr(bmain, base_new->object, mat_nr);
}
result |= (base_new != NULL);
@@ -3289,11 +3297,13 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
Object *ob = base_iter->object;
if (ob->type == OB_MESH) {
Mesh *me = ob->data;
- if (me->id.lib == NULL) {
+ if (!ID_IS_LINKED_DATABLOCK(me)) {
BMesh *bm_old = NULL;
int retval_iter = 0;
- bm_old = BM_mesh_create(&bm_mesh_allocsize_default);
+ bm_old = BM_mesh_create(
+ &bm_mesh_allocsize_default,
+ &((struct BMeshCreateParams){.use_toolflags = true,}));
BM_mesh_bm_from_me(bm_old, me, (&(struct BMeshFromMeshParams){0}));
@@ -3974,6 +3984,196 @@ void MESH_OT_tris_convert_to_quads(wmOperatorType *ot)
join_triangle_props(ot);
}
+
+/* -------------------------------------------------------------------- */
+
+/** \name Decimate
+ *
+ * \note The function to decimate is intended for use as a modifier,
+ * while its handy allow access as a tool - this does cause access to be a little awkward
+ * (passing selection as weights for eg).
+ *
+ * \{ */
+
+static int edbm_decimate_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+
+ const float ratio = RNA_float_get(op->ptr, "ratio");
+ bool use_vertex_group = RNA_boolean_get(op->ptr, "use_vertex_group");
+ const float vertex_group_factor = RNA_float_get(op->ptr, "vertex_group_factor");
+ const bool invert_vertex_group = RNA_boolean_get(op->ptr, "invert_vertex_group");
+ const bool use_symmetry = RNA_boolean_get(op->ptr, "use_symmetry");
+ const float symmetry_eps = 0.00002f;
+ const int symmetry_axis = use_symmetry ? RNA_enum_get(op->ptr, "symmetry_axis") : -1;
+
+ /* nop */
+ if (ratio == 1.0f) {
+ return OPERATOR_FINISHED;
+ }
+
+ float *vweights = MEM_mallocN(sizeof(*vweights) * bm->totvert, __func__);
+ {
+ const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT);
+ const int defbase_act = obedit->actdef - 1;
+
+ if (use_vertex_group && (cd_dvert_offset == -1)) {
+ BKE_report(op->reports, RPT_WARNING, "No active vertex group");
+ use_vertex_group = false;
+ }
+
+ BMIter iter;
+ BMVert *v;
+ int i;
+ BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
+ float weight = 0.0f;
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ if (use_vertex_group) {
+ const MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(v, cd_dvert_offset);
+ weight = defvert_find_weight(dv, defbase_act);
+ if (invert_vertex_group) {
+ weight = 1.0f - weight;
+ }
+ }
+ else {
+ weight = 1.0f;
+ }
+ }
+
+ vweights[i] = weight;
+ BM_elem_index_set(v, i); /* set_inline */
+ }
+ bm->elem_index_dirty &= ~BM_VERT;
+ }
+
+ float ratio_adjust;
+
+ if ((bm->totface == bm->totfacesel) || (ratio == 0.0f)) {
+ ratio_adjust = ratio;
+ }
+ else {
+ /**
+ * Calculate a new ratio based on faces that could be remoevd during decimation.
+ * needed so 0..1 has a meaningful range when operating on the selection.
+ *
+ * This doesn't have to be totally accurate,
+ * but needs to be greater than the number of selected faces
+ */
+
+ int totface_basis = 0;
+ int totface_adjacent = 0;
+ BMIter iter;
+ BMFace *f;
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ /* count faces during decimation, ngons are triangulated */
+ const int f_len = f->len > 4 ? (f->len - 2) : 1;
+ totface_basis += f_len;
+
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (vweights[BM_elem_index_get(l_iter->v)] != 0.0f) {
+ totface_adjacent += f_len;
+ break;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+ ratio_adjust = ratio;
+ ratio_adjust = 1.0f - ratio_adjust;
+ ratio_adjust *= (float)totface_adjacent / (float)totface_basis;
+ ratio_adjust = 1.0f - ratio_adjust;
+ }
+
+ BM_mesh_decimate_collapse(
+ em->bm, ratio_adjust, vweights, vertex_group_factor, false,
+ symmetry_axis, symmetry_eps);
+
+ MEM_freeN(vweights);
+
+ {
+ short selectmode = em->selectmode;
+ if ((selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0) {
+ /* ensure we flush edges -> faces */
+ selectmode |= SCE_SELECT_EDGE;
+ }
+ EDBM_selectmode_flush_ex(em, selectmode);
+ }
+
+ EDBM_update_generic(em, true, true);
+
+ return OPERATOR_FINISHED;
+}
+
+
+static bool edbm_decimate_check(bContext *UNUSED(C), wmOperator *UNUSED(op))
+{
+ return true;
+}
+
+
+static void edbm_decimate_ui(bContext *UNUSED(C), wmOperator *op)
+{
+ uiLayout *layout = op->layout, *box, *row, *col;
+ PointerRNA ptr;
+
+ RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
+
+ uiItemR(layout, &ptr, "ratio", 0, NULL, ICON_NONE);
+
+ box = uiLayoutBox(layout);
+ uiItemR(box, &ptr, "use_vertex_group", 0, NULL, ICON_NONE);
+ col = uiLayoutColumn(box, false);
+ uiLayoutSetActive(col, RNA_boolean_get(&ptr, "use_vertex_group"));
+ uiItemR(col, &ptr, "vertex_group_factor", 0, NULL, ICON_NONE);
+ uiItemR(col, &ptr, "invert_vertex_group", 0, NULL, ICON_NONE);
+
+ box = uiLayoutBox(layout);
+ uiItemR(box, &ptr, "use_symmetry", 0, NULL, ICON_NONE);
+ row = uiLayoutRow(box, true);
+ uiLayoutSetActive(row, RNA_boolean_get(&ptr, "use_symmetry"));
+ uiItemR(row, &ptr, "symmetry_axis", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+}
+
+
+void MESH_OT_decimate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Decimate Geometry";
+ ot->idname = "MESH_OT_decimate";
+ ot->description = "Simplify geometry by collapsing edges";
+
+ /* api callbacks */
+ ot->exec = edbm_decimate_exec;
+ ot->check = edbm_decimate_check;
+ ot->ui = edbm_decimate_ui;
+ ot->poll = ED_operator_editmesh;
+
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* Note, keep in sync with 'rna_def_modifier_decimate' */
+ RNA_def_float(ot->srna, "ratio", 1.0f, 0.0f, 1.0f, "Ratio", "", 0.0f, 1.0f);
+
+ RNA_def_boolean(ot->srna, "use_vertex_group", false, "Vertex Group",
+ "Use active vertex group as an influence");
+ RNA_def_float(ot->srna, "vertex_group_factor", 1.0f, 0.0f, 1000.0f, "Weight",
+ "Vertex group strength", 0.0f, 10.0f);
+ RNA_def_boolean(ot->srna, "invert_vertex_group", false, "Invert",
+ "Invert vertex group influence");
+
+ RNA_def_boolean(ot->srna, "use_symmetry", false, "Symmetry",
+ "Maintain symmetry on an axis");
+
+ RNA_def_enum(ot->srna, "symmetry_axis", rna_enum_axis_xyz_items, 1, "Axis", "Axis of symmetry");
+}
+
+/** \} */
+
+
/* -------------------------------------------------------------------- */
/* Dissolve */
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
new file mode 100644
index 00000000000..c9814d189a4
--- /dev/null
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -0,0 +1,667 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/mesh/editmesh_undo.c
+ * \ingroup edmesh
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "DNA_key_types.h"
+
+#include "BLI_listbase.h"
+
+#include "BKE_DerivedMesh.h"
+#include "BKE_context.h"
+#include "BKE_key.h"
+#include "BKE_mesh.h"
+#include "BKE_editmesh.h"
+
+#include "ED_mesh.h"
+#include "ED_util.h"
+
+#define USE_ARRAY_STORE
+
+#ifdef USE_ARRAY_STORE
+// # define DEBUG_PRINT
+// # define DEBUG_TIME
+# ifdef DEBUG_TIME
+# include "PIL_time_utildefines.h"
+# endif
+
+# include "BLI_array_store.h"
+# include "BLI_array_store_utils.h"
+ /* check on best size later... */
+# define ARRAY_CHUNK_SIZE 256
+
+# define USE_ARRAY_STORE_THREAD
+#endif
+
+#ifdef USE_ARRAY_STORE_THREAD
+# include "BLI_task.h"
+#endif
+
+
+#ifdef USE_ARRAY_STORE
+
+/* Single linked list of layers stored per type */
+typedef struct BArrayCustomData {
+ struct BArrayCustomData *next;
+ CustomDataType type;
+ int states_len; /* number of layers for each type */
+ BArrayState *states[0];
+} BArrayCustomData;
+
+#endif
+
+typedef struct UndoMesh {
+ Mesh me;
+ int selectmode;
+
+ /** \note
+ * this isn't a prefect solution, if you edit keys and change shapes this works well (fixing [#32442]),
+ * but editing shape keys, going into object mode, removing or changing their order,
+ * then go back into editmode and undo will give issues - where the old index will be out of sync
+ * with the new object index.
+ *
+ * There are a few ways this could be made to work but for now its a known limitation with mixing
+ * object and editmode operations - Campbell */
+ int shapenr;
+
+#ifdef USE_ARRAY_STORE
+ /* NULL arrays are considered empty */
+ struct { /* most data is stored as 'custom' data */
+ BArrayCustomData *vdata, *edata, *ldata, *pdata;
+ BArrayState **keyblocks;
+ BArrayState *mselect;
+ } store;
+#endif /* USE_ARRAY_STORE */
+} UndoMesh;
+
+
+#ifdef USE_ARRAY_STORE
+
+/** \name Array Store
+ * \{ */
+
+static struct {
+ struct BArrayStore_AtSize bs_stride;
+ int users;
+
+ /* We could have the undo API pass in the previous state, for now store a local list */
+ ListBase local_links;
+
+#ifdef USE_ARRAY_STORE_THREAD
+ TaskPool *task_pool;
+#endif
+
+} um_arraystore = {{NULL}};
+
+static void um_arraystore_cd_compact(
+ struct CustomData *cdata, const size_t data_len,
+ bool create,
+ const BArrayCustomData *bcd_reference,
+ BArrayCustomData **r_bcd_first)
+{
+ if (data_len == 0) {
+ if (create) {
+ *r_bcd_first = NULL;
+ }
+ }
+
+ const BArrayCustomData *bcd_reference_current = bcd_reference;
+ BArrayCustomData *bcd = NULL, *bcd_first = NULL, *bcd_prev = NULL;
+ for (int layer_start = 0, layer_end; layer_start < cdata->totlayer; layer_start = layer_end) {
+ const CustomDataType type = cdata->layers[layer_start].type;
+
+ layer_end = layer_start + 1;
+ while ((layer_end < cdata->totlayer) &&
+ (type == cdata->layers[layer_end].type))
+ {
+ layer_end++;
+ }
+
+ const int stride = CustomData_sizeof(type);
+ BArrayStore *bs = create ? BLI_array_store_at_size_ensure(&um_arraystore.bs_stride, stride, ARRAY_CHUNK_SIZE) : NULL;
+ const int layer_len = layer_end - layer_start;
+
+ if (create) {
+ if (bcd_reference_current && (bcd_reference_current->type == type)) {
+ /* common case, the reference is aligned */
+ }
+ else {
+ bcd_reference_current = NULL;
+
+ /* do a full lookup when un-alligned */
+ if (bcd_reference) {
+ const BArrayCustomData *bcd_iter = bcd_reference;
+ while (bcd_iter) {
+ if (bcd_iter->type == type) {
+ bcd_reference_current = bcd_iter;
+ break;
+ }
+ bcd_iter = bcd_iter->next;
+ }
+ }
+ }
+ }
+
+ if (create) {
+ bcd = MEM_callocN(sizeof(BArrayCustomData) + (layer_len * sizeof(BArrayState *)), __func__);
+ bcd->next = NULL;
+ bcd->type = type;
+ bcd->states_len = layer_end - layer_start;
+
+ if (bcd_prev) {
+ bcd_prev->next = bcd;
+ bcd_prev = bcd;
+ }
+ else {
+ bcd_first = bcd;
+ bcd_prev = bcd;
+ }
+ }
+
+ CustomDataLayer *layer = &cdata->layers[layer_start];
+ for (int i = 0; i < layer_len; i++, layer++) {
+ if (create) {
+ if (layer->data) {
+ BArrayState *state_reference =
+ (bcd_reference_current && i < bcd_reference_current->states_len) ?
+ bcd_reference_current->states[i] : NULL;
+ bcd->states[i] = BLI_array_store_state_add(
+ bs, layer->data, (size_t)data_len * stride, state_reference);
+ }
+ else {
+ bcd->states[i] = NULL;
+ }
+ }
+
+ if (layer->data) {
+ MEM_freeN(layer->data);
+ layer->data = NULL;
+ }
+ }
+
+ if (create) {
+ if (bcd_reference_current) {
+ bcd_reference_current = bcd_reference_current->next;
+ }
+ }
+ }
+
+ if (create) {
+ *r_bcd_first = bcd_first;
+ }
+}
+
+/**
+ * \note There is no room for data going out of sync here.
+ * The layers and the states are stored together so this can be kept working.
+ */
+static void um_arraystore_cd_expand(
+ const BArrayCustomData *bcd, struct CustomData *cdata, const size_t data_len)
+{
+ CustomDataLayer *layer = cdata->layers;
+ while (bcd) {
+ const int stride = CustomData_sizeof(bcd->type);
+ for (int i = 0; i < bcd->states_len; i++) {
+ BLI_assert(bcd->type == layer->type);
+ if (bcd->states[i]) {
+ size_t state_len;
+ layer->data = BLI_array_store_state_data_get_alloc(bcd->states[i], &state_len);
+ BLI_assert(stride * data_len == state_len);
+ UNUSED_VARS_NDEBUG(stride, data_len);
+ }
+ else {
+ layer->data = NULL;
+ }
+ layer++;
+ }
+ bcd = bcd->next;
+ }
+}
+
+static void um_arraystore_cd_free(BArrayCustomData *bcd)
+{
+ while (bcd) {
+ BArrayCustomData *bcd_next = bcd->next;
+ const int stride = CustomData_sizeof(bcd->type);
+ BArrayStore *bs = BLI_array_store_at_size_get(&um_arraystore.bs_stride, stride);
+ for (int i = 0; i < bcd->states_len; i++) {
+ if (bcd->states[i]) {
+ BLI_array_store_state_remove(bs, bcd->states[i]);
+ }
+ }
+ MEM_freeN(bcd);
+ bcd = bcd_next;
+ }
+}
+
+/**
+ * \param create: When false, only free the arrays.
+ * This is done since when reading from an undo state, they must be temporarily expanded.
+ * then discarded afterwards, having this argument avoids having 2x code paths.
+ */
+static void um_arraystore_compact_ex(
+ UndoMesh *um, const UndoMesh *um_ref,
+ bool create)
+{
+ Mesh *me = &um->me;
+
+ um_arraystore_cd_compact(&me->vdata, me->totvert, create, um_ref ? um_ref->store.vdata : NULL, &um->store.vdata);
+ um_arraystore_cd_compact(&me->edata, me->totedge, create, um_ref ? um_ref->store.edata : NULL, &um->store.edata);
+ um_arraystore_cd_compact(&me->ldata, me->totloop, create, um_ref ? um_ref->store.ldata : NULL, &um->store.ldata);
+ um_arraystore_cd_compact(&me->pdata, me->totpoly, create, um_ref ? um_ref->store.pdata : NULL, &um->store.pdata);
+
+ if (me->key && me->key->totkey) {
+ const size_t stride = me->key->elemsize;
+ BArrayStore *bs = create ? BLI_array_store_at_size_ensure(&um_arraystore.bs_stride, stride, ARRAY_CHUNK_SIZE) : NULL;
+ if (create) {
+ um->store.keyblocks = MEM_mallocN(me->key->totkey * sizeof(*um->store.keyblocks), __func__);
+ }
+ KeyBlock *keyblock = me->key->block.first;
+ for (int i = 0; i < me->key->totkey; i++, keyblock = keyblock->next) {
+ if (create) {
+ BArrayState *state_reference =
+ (um_ref && um_ref->me.key && (i < um_ref->me.key->totkey)) ?
+ um_ref->store.keyblocks[i] : NULL;
+ um->store.keyblocks[i] = BLI_array_store_state_add(
+ bs, keyblock->data, (size_t)keyblock->totelem * stride,
+ state_reference);
+ }
+
+ if (keyblock->data) {
+ MEM_freeN(keyblock->data);
+ keyblock->data = NULL;
+ }
+ }
+ }
+
+ if (me->mselect && me->totselect) {
+ BLI_assert(create == (um->store.mselect == NULL));
+ if (create) {
+ BArrayState *state_reference = um_ref ? um_ref->store.mselect : NULL;
+ const size_t stride = sizeof(*me->mselect);
+ BArrayStore *bs = BLI_array_store_at_size_ensure(&um_arraystore.bs_stride, stride, ARRAY_CHUNK_SIZE);
+ um->store.mselect = BLI_array_store_state_add(
+ bs, me->mselect, (size_t)me->totselect * stride, state_reference);
+ }
+
+ /* keep me->totselect for validation */
+ MEM_freeN(me->mselect);
+ me->mselect = NULL;
+ }
+
+ if (create) {
+ um_arraystore.users += 1;
+ }
+
+ BKE_mesh_update_customdata_pointers(me, false);
+}
+
+/**
+ * Move data from allocated arrays to de-duplicated states and clear arrays.
+ */
+static void um_arraystore_compact(UndoMesh *um, const UndoMesh *um_ref)
+{
+ um_arraystore_compact_ex(um, um_ref, true);
+}
+
+static void um_arraystore_compact_with_info(UndoMesh *um, const UndoMesh *um_ref)
+{
+#ifdef DEBUG_PRINT
+ size_t size_expanded_prev, size_compacted_prev;
+ BLI_array_store_at_size_calc_memory_usage(&um_arraystore.bs_stride, &size_expanded_prev, &size_compacted_prev);
+#endif
+
+#ifdef DEBUG_TIME
+ TIMEIT_START(mesh_undo_compact);
+#endif
+
+ um_arraystore_compact(um, um_ref);
+
+#ifdef DEBUG_TIME
+ TIMEIT_END(mesh_undo_compact);
+#endif
+
+#ifdef DEBUG_PRINT
+ {
+ size_t size_expanded, size_compacted;
+ BLI_array_store_at_size_calc_memory_usage(&um_arraystore.bs_stride, &size_expanded, &size_compacted);
+
+ const double percent_total = size_expanded ?
+ (((double)size_compacted / (double)size_expanded) * 100.0) : -1.0;
+
+ size_t size_expanded_step = size_expanded - size_expanded_prev;
+ size_t size_compacted_step = size_compacted - size_compacted_prev;
+ const double percent_step = size_expanded_step ?
+ (((double)size_compacted_step / (double)size_expanded_step) * 100.0) : -1.0;
+
+ printf("overall memory use: %.8f%% of expanded size\n", percent_total);
+ printf("step memory use: %.8f%% of expanded size\n", percent_step);
+ }
+#endif
+}
+
+#ifdef USE_ARRAY_STORE_THREAD
+
+struct UMArrayData {
+ UndoMesh *um;
+ const UndoMesh *um_ref; /* can be NULL */
+};
+static void um_arraystore_compact_cb(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid))
+{
+ struct UMArrayData *um_data = taskdata;
+ um_arraystore_compact_with_info(um_data->um, um_data->um_ref);
+}
+
+#endif /* USE_ARRAY_STORE_THREAD */
+
+/**
+ * Remove data we only expanded for temporary use.
+ */
+static void um_arraystore_expand_clear(UndoMesh *um)
+{
+ um_arraystore_compact_ex(um, NULL, false);
+}
+
+static void um_arraystore_expand(UndoMesh *um)
+{
+ Mesh *me = &um->me;
+
+ um_arraystore_cd_expand(um->store.vdata, &me->vdata, me->totvert);
+ um_arraystore_cd_expand(um->store.edata, &me->edata, me->totedge);
+ um_arraystore_cd_expand(um->store.ldata, &me->ldata, me->totloop);
+ um_arraystore_cd_expand(um->store.pdata, &me->pdata, me->totpoly);
+
+ if (um->store.keyblocks) {
+ const size_t stride = me->key->elemsize;
+ KeyBlock *keyblock = me->key->block.first;
+ for (int i = 0; i < me->key->totkey; i++, keyblock = keyblock->next) {
+ BArrayState *state = um->store.keyblocks[i];
+ size_t state_len;
+ keyblock->data = BLI_array_store_state_data_get_alloc(state, &state_len);
+ BLI_assert(keyblock->totelem == (state_len / stride));
+ UNUSED_VARS_NDEBUG(stride);
+ }
+ }
+
+ if (um->store.mselect) {
+ const size_t stride = sizeof(*me->mselect);
+ BArrayState *state = um->store.mselect;
+ size_t state_len;
+ me->mselect = BLI_array_store_state_data_get_alloc(state, &state_len);
+ BLI_assert(me->totselect == (state_len / stride));
+ UNUSED_VARS_NDEBUG(stride);
+ }
+
+ /* not essential, but prevents accidental dangling pointer access */
+ BKE_mesh_update_customdata_pointers(me, false);
+}
+
+static void um_arraystore_free(UndoMesh *um)
+{
+ Mesh *me = &um->me;
+
+ um_arraystore_cd_free(um->store.vdata);
+ um_arraystore_cd_free(um->store.edata);
+ um_arraystore_cd_free(um->store.ldata);
+ um_arraystore_cd_free(um->store.pdata);
+
+ if (um->store.keyblocks) {
+ const size_t stride = me->key->elemsize;
+ BArrayStore *bs = BLI_array_store_at_size_get(&um_arraystore.bs_stride, stride);
+ for (int i = 0; i < me->key->totkey; i++) {
+ BArrayState *state = um->store.keyblocks[i];
+ BLI_array_store_state_remove(bs, state);
+ }
+ MEM_freeN(um->store.keyblocks);
+ um->store.keyblocks = NULL;
+ }
+
+ if (um->store.mselect) {
+ const size_t stride = sizeof(*me->mselect);
+ BArrayStore *bs = BLI_array_store_at_size_get(&um_arraystore.bs_stride, stride);
+ BArrayState *state = um->store.mselect;
+ BLI_array_store_state_remove(bs, state);
+ um->store.mselect = NULL;
+ }
+
+ um_arraystore.users -= 1;
+
+ BLI_assert(um_arraystore.users >= 0);
+
+ if (um_arraystore.users == 0) {
+#ifdef DEBUG_PRINT
+ printf("mesh undo store: freeing all data!\n");
+#endif
+ BLI_array_store_at_size_clear(&um_arraystore.bs_stride);
+
+#ifdef USE_ARRAY_STORE_THREAD
+ BLI_task_pool_free(um_arraystore.task_pool);
+ um_arraystore.task_pool = NULL;
+#endif
+ }
+
+}
+
+/** \} */
+
+#endif /* USE_ARRAY_STORE */
+
+
+/* for callbacks */
+/* undo simply makes copies of a bmesh */
+static void *editbtMesh_to_undoMesh(void *emv, void *obdata)
+{
+
+#ifdef USE_ARRAY_STORE_THREAD
+ /* changes this waits is low, but must have finished */
+ if (um_arraystore.task_pool) {
+ BLI_task_pool_work_and_wait(um_arraystore.task_pool);
+ }
+#endif
+
+ BMEditMesh *em = emv;
+ Mesh *obme = obdata;
+
+ UndoMesh *um = MEM_callocN(sizeof(UndoMesh), "undo Mesh");
+
+ /* make sure shape keys work */
+ um->me.key = obme->key ? BKE_key_copy_nolib(obme->key) : NULL;
+
+ /* BM_mesh_validate(em->bm); */ /* for troubleshooting */
+
+ BM_mesh_bm_to_me(
+ em->bm, &um->me, (&(struct BMeshToMeshParams){
+ .cd_mask_extra = CD_MASK_SHAPE_KEYINDEX,
+ }));
+
+ um->selectmode = em->selectmode;
+ um->shapenr = em->bm->shapenr;
+
+#ifdef USE_ARRAY_STORE
+ {
+ /* We could be more clever here,
+ * the previous undo state may be from a separate mesh. */
+ const UndoMesh *um_ref = um_arraystore.local_links.last ?
+ ((LinkData *)um_arraystore.local_links.last)->data : NULL;
+
+ /* add oursrlves */
+ BLI_addtail(&um_arraystore.local_links, BLI_genericNodeN(um));
+
+#ifdef USE_ARRAY_STORE_THREAD
+ if (um_arraystore.task_pool == NULL) {
+ TaskScheduler *scheduler = BLI_task_scheduler_get();
+ um_arraystore.task_pool = BLI_task_pool_create_background(scheduler, NULL);
+ }
+
+ struct UMArrayData *um_data = MEM_mallocN(sizeof(*um_data), __func__);
+ um_data->um = um;
+ um_data->um_ref = um_ref;
+
+ BLI_task_pool_push(
+ um_arraystore.task_pool,
+ um_arraystore_compact_cb, um_data, true, TASK_PRIORITY_LOW);
+#else
+ um_arraystore_compact_with_info(um, um_ref);
+#endif
+ }
+#endif
+
+ return um;
+}
+
+static void undoMesh_to_editbtMesh(void *um_v, void *em_v, void *obdata)
+{
+ BMEditMesh *em = em_v, *em_tmp;
+ Object *ob = em->ob;
+ UndoMesh *um = um_v;
+ BMesh *bm;
+ Key *key = ((Mesh *) obdata)->key;
+
+#ifdef USE_ARRAY_STORE
+#ifdef USE_ARRAY_STORE_THREAD
+ /* changes this waits is low, but must have finished */
+ BLI_task_pool_work_and_wait(um_arraystore.task_pool);
+#endif
+
+#ifdef DEBUG_TIME
+ TIMEIT_START(mesh_undo_expand);
+#endif
+
+ um_arraystore_expand(um);
+
+#ifdef DEBUG_TIME
+ TIMEIT_END(mesh_undo_expand);
+#endif
+#endif /* USE_ARRAY_STORE */
+
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(&um->me);
+
+ em->bm->shapenr = um->shapenr;
+
+ EDBM_mesh_free(em);
+
+ bm = BM_mesh_create(
+ &allocsize,
+ &((struct BMeshCreateParams){.use_toolflags = true,}));
+
+ BM_mesh_bm_from_me(
+ bm, &um->me, (&(struct BMeshFromMeshParams){
+ .calc_face_normal = true, .active_shapekey = um->shapenr,
+ }));
+
+ em_tmp = BKE_editmesh_create(bm, true);
+ *em = *em_tmp;
+
+ em->selectmode = um->selectmode;
+ bm->selectmode = um->selectmode;
+ em->ob = ob;
+
+ /* T35170: Restore the active key on the RealMesh. Otherwise 'fake' offset propagation happens
+ * if the active is a basis for any other. */
+ if (key && (key->type == KEY_RELATIVE)) {
+ /* Since we can't add, remove or reorder keyblocks in editmode, it's safe to assume
+ * shapenr from restored bmesh and keyblock indices are in sync. */
+ const int kb_act_idx = ob->shapenr - 1;
+
+ /* If it is, let's patch the current mesh key block to its restored value.
+ * Else, the offsets won't be computed and it won't matter. */
+ if (BKE_keyblock_is_basis(key, kb_act_idx)) {
+ KeyBlock *kb_act = BLI_findlink(&key->block, kb_act_idx);
+
+ if (kb_act->totelem != um->me.totvert) {
+ /* The current mesh has some extra/missing verts compared to the undo, adjust. */
+ MEM_SAFE_FREE(kb_act->data);
+ kb_act->data = MEM_mallocN((size_t)(key->elemsize * bm->totvert), __func__);
+ kb_act->totelem = um->me.totvert;
+ }
+
+ BKE_keyblock_update_from_mesh(&um->me, kb_act);
+ }
+ }
+
+ ob->shapenr = um->shapenr;
+
+ MEM_freeN(em_tmp);
+
+#ifdef USE_ARRAY_STORE
+ um_arraystore_expand_clear(um);
+#endif
+}
+
+static void free_undo(void *um_v)
+{
+ UndoMesh *um = um_v;
+ Mesh *me = &um->me;
+
+#ifdef USE_ARRAY_STORE
+
+#ifdef USE_ARRAY_STORE_THREAD
+ /* changes this waits is low, but must have finished */
+ BLI_task_pool_work_and_wait(um_arraystore.task_pool);
+#endif
+
+ /* we need to expand so any allocations in custom-data are freed with the mesh */
+ um_arraystore_expand(um);
+
+ {
+ LinkData *link = BLI_findptr(&um_arraystore.local_links, um, offsetof(LinkData, data));
+ BLI_remlink(&um_arraystore.local_links, link);
+ MEM_freeN(link);
+ }
+ um_arraystore_free(um);
+#endif
+
+ if (me->key) {
+ BKE_key_free(me->key);
+ MEM_freeN(me->key);
+ }
+
+ BKE_mesh_free(me);
+ MEM_freeN(me);
+}
+
+static void *getEditMesh(bContext *C)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ if (obedit && obedit->type == OB_MESH) {
+ Mesh *me = obedit->data;
+ return me->edit_btmesh;
+ }
+ return NULL;
+}
+
+/* and this is all the undo system needs to know */
+void undo_push_mesh(bContext *C, const char *name)
+{
+ /* em->ob gets out of date and crashes on mesh undo,
+ * this is an easy way to ensure its OK
+ * though we could investigate the matter further. */
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ em->ob = obedit;
+
+ undo_editmode_push(C, name, getEditMesh, free_undo, undoMesh_to_editbtMesh, editbtMesh_to_undoMesh, NULL);
+}
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 82ec93c162f..4fc61e0912e 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -45,7 +45,6 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_depsgraph.h"
-#include "BKE_key.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
@@ -60,7 +59,6 @@
#include "ED_mesh.h"
#include "ED_screen.h"
-#include "ED_util.h"
#include "ED_view3d.h"
#include "mesh_intern.h" /* own include */
@@ -356,7 +354,9 @@ void EDBM_mesh_make(ToolSettings *ts, Object *ob, const bool add_key_index)
BKE_mesh_convert_mfaces_to_mpolys(me);
}
- bm = BKE_mesh_to_bmesh(me, ob, add_key_index);
+ bm = BKE_mesh_to_bmesh(
+ me, ob, add_key_index,
+ &((struct BMeshCreateParams){.use_toolflags = true,}));
if (me->edit_btmesh) {
/* this happens when switching shape keys */
@@ -401,10 +401,25 @@ void EDBM_mesh_load(Object *ob)
BKE_mesh_tessface_calc(me);
#endif
- /* free derived mesh. usually this would happen through depsgraph but there
+ /* Free derived mesh. usually this would happen through depsgraph but there
* are exceptions like file save that will not cause this, and we want to
- * avoid ending up with an invalid derived mesh then */
- BKE_object_free_derived_caches(ob);
+ * avoid ending up with an invalid derived mesh then.
+ *
+ * Do it for all objects which shares the same mesh datablock, since their
+ * derived meshes might also be referencing data which was just freed,
+ *
+ * Annoying enough, but currently seems most efficient way to avoid access
+ * of freed data on scene update, especially in cases when there are dependency
+ * cycles.
+ */
+ for (Object *other_object = G.main->object.first;
+ other_object != NULL;
+ other_object = other_object->id.next)
+ {
+ if (other_object->data == ob->data) {
+ BKE_object_free_derived_caches(other_object);
+ }
+ }
}
/**
@@ -491,140 +506,6 @@ void EDBM_flag_enable_all(BMEditMesh *em, const char hflag)
BM_mesh_elem_hflag_enable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, hflag, true);
}
-/**************-------------- Undo ------------*****************/
-
-/* for callbacks */
-
-static void *getEditMesh(bContext *C)
-{
- Object *obedit = CTX_data_edit_object(C);
- if (obedit && obedit->type == OB_MESH) {
- Mesh *me = obedit->data;
- return me->edit_btmesh;
- }
- return NULL;
-}
-
-typedef struct UndoMesh {
- Mesh me;
- int selectmode;
-
- /** \note
- * this isn't a prefect solution, if you edit keys and change shapes this works well (fixing [#32442]),
- * but editing shape keys, going into object mode, removing or changing their order,
- * then go back into editmode and undo will give issues - where the old index will be out of sync
- * with the new object index.
- *
- * There are a few ways this could be made to work but for now its a known limitation with mixing
- * object and editmode operations - Campbell */
- int shapenr;
-} UndoMesh;
-
-/* undo simply makes copies of a bmesh */
-static void *editbtMesh_to_undoMesh(void *emv, void *obdata)
-{
- BMEditMesh *em = emv;
- Mesh *obme = obdata;
-
- UndoMesh *um = MEM_callocN(sizeof(UndoMesh), "undo Mesh");
-
- /* make sure shape keys work */
- um->me.key = obme->key ? BKE_key_copy_nolib(obme->key) : NULL;
-
- /* BM_mesh_validate(em->bm); */ /* for troubleshooting */
-
- BM_mesh_bm_to_me(
- em->bm, &um->me, (&(struct BMeshToMeshParams){
- .cd_mask_extra = CD_MASK_SHAPE_KEYINDEX,
- }));
-
- um->selectmode = em->selectmode;
- um->shapenr = em->bm->shapenr;
-
- return um;
-}
-
-static void undoMesh_to_editbtMesh(void *umv, void *em_v, void *obdata)
-{
- BMEditMesh *em = em_v, *em_tmp;
- Object *ob = em->ob;
- UndoMesh *um = umv;
- BMesh *bm;
- Key *key = ((Mesh *) obdata)->key;
-
- const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(&um->me);
-
- em->bm->shapenr = um->shapenr;
-
- EDBM_mesh_free(em);
-
- bm = BM_mesh_create(&allocsize);
-
- BM_mesh_bm_from_me(
- bm, &um->me, (&(struct BMeshFromMeshParams){
- .calc_face_normal = true, .active_shapekey = um->shapenr,
- }));
-
- em_tmp = BKE_editmesh_create(bm, true);
- *em = *em_tmp;
-
- em->selectmode = um->selectmode;
- bm->selectmode = um->selectmode;
- em->ob = ob;
-
- /* T35170: Restore the active key on the RealMesh. Otherwise 'fake' offset propagation happens
- * if the active is a basis for any other. */
- if (key && (key->type == KEY_RELATIVE)) {
- /* Since we can't add, remove or reorder keyblocks in editmode, it's safe to assume
- * shapenr from restored bmesh and keyblock indices are in sync. */
- const int kb_act_idx = ob->shapenr - 1;
-
- /* If it is, let's patch the current mesh key block to its restored value.
- * Else, the offsets won't be computed and it won't matter. */
- if (BKE_keyblock_is_basis(key, kb_act_idx)) {
- KeyBlock *kb_act = BLI_findlink(&key->block, kb_act_idx);
-
- if (kb_act->totelem != um->me.totvert) {
- /* The current mesh has some extra/missing verts compared to the undo, adjust. */
- MEM_SAFE_FREE(kb_act->data);
- kb_act->data = MEM_mallocN((size_t)(key->elemsize * bm->totvert), __func__);
- kb_act->totelem = um->me.totvert;
- }
-
- BKE_keyblock_update_from_mesh(&um->me, kb_act);
- }
- }
-
- ob->shapenr = um->shapenr;
-
- MEM_freeN(em_tmp);
-}
-
-static void free_undo(void *me_v)
-{
- Mesh *me = me_v;
- if (me->key) {
- BKE_key_free(me->key);
- MEM_freeN(me->key);
- }
-
- BKE_mesh_free(me, false);
- MEM_freeN(me);
-}
-
-/* and this is all the undo system needs to know */
-void undo_push_mesh(bContext *C, const char *name)
-{
- /* em->ob gets out of date and crashes on mesh undo,
- * this is an easy way to ensure its OK
- * though we could investigate the matter further. */
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- em->ob = obedit;
-
- undo_editmode_push(C, name, getEditMesh, free_undo, undoMesh_to_editbtMesh, editbtMesh_to_undoMesh, NULL);
-}
-
/**
* Return a new UVVertMap from the editmesh
*/
@@ -1559,13 +1440,9 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e, ARegion *ar, View3D *v
sub_v3_v3v3(dir2, origin, co2);
sub_v3_v3v3(dir3, origin, co3);
- normalize_v3(dir1);
- normalize_v3(dir2);
- normalize_v3(dir3);
-
- mul_v3_fl(dir1, epsilon);
- mul_v3_fl(dir2, epsilon);
- mul_v3_fl(dir3, epsilon);
+ normalize_v3_length(dir1, epsilon);
+ normalize_v3_length(dir2, epsilon);
+ normalize_v3_length(dir3, epsilon);
/* offset coordinates slightly along view vectors, to avoid
* hitting the faces that own the edge.*/
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index e0ddc017e93..772bb1bd308 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -511,7 +511,7 @@ static int layers_poll(bContext *C)
{
Object *ob = ED_object_context(C);
ID *data = (ob) ? ob->data : NULL;
- return (ob && !ob->id.lib && ob->type == OB_MESH && data && !data->lib);
+ return (ob && !ID_IS_LINKED_DATABLOCK(ob) && ob->type == OB_MESH && data && !ID_IS_LINKED_DATABLOCK(data));
}
static int mesh_uv_texture_add_exec(bContext *C, wmOperator *UNUSED(op))
@@ -759,7 +759,7 @@ static int mesh_customdata_mask_clear_poll(bContext *C)
return false;
}
- if (me->id.lib == NULL) {
+ if (!ID_IS_LINKED_DATABLOCK(me)) {
CustomData *data = GET_CD_DATA(me, vdata);
if (CustomData_has_layer(data, CD_PAINT_MASK)) {
return true;
@@ -813,7 +813,7 @@ static int mesh_customdata_skin_state(bContext *C)
if (ob && ob->type == OB_MESH) {
Mesh *me = ob->data;
- if (me->id.lib == NULL) {
+ if (!ID_IS_LINKED_DATABLOCK(me)) {
CustomData *data = GET_CD_DATA(me, vdata);
return CustomData_has_layer(data, CD_MVERT_SKIN);
}
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index 08b4d1aee45..300b21a052d 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -216,6 +216,7 @@ void MESH_OT_fill_holes(struct wmOperatorType *ot);
void MESH_OT_beautify_fill(struct wmOperatorType *ot);
void MESH_OT_quads_convert_to_tris(struct wmOperatorType *ot);
void MESH_OT_tris_convert_to_quads(struct wmOperatorType *ot);
+void MESH_OT_decimate(struct wmOperatorType *ot);
void MESH_OT_dissolve_verts(struct wmOperatorType *ot);
void MESH_OT_dissolve_edges(struct wmOperatorType *ot);
void MESH_OT_dissolve_faces(struct wmOperatorType *ot);
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index 2853ae3a84c..697a92f36d1 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -106,6 +106,7 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_beautify_fill);
WM_operatortype_append(MESH_OT_quads_convert_to_tris);
WM_operatortype_append(MESH_OT_tris_convert_to_quads);
+ WM_operatortype_append(MESH_OT_decimate);
WM_operatortype_append(MESH_OT_dissolve_verts);
WM_operatortype_append(MESH_OT_dissolve_edges);
WM_operatortype_append(MESH_OT_dissolve_faces);
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index 90676d2b951..b26989113d4 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -172,7 +172,7 @@ int join_mesh_exec(bContext *C, wmOperator *op)
*/
if (key) {
/* make a duplicate copy that will only be used here... (must remember to free it!) */
- nkey = BKE_key_copy(key);
+ nkey = BKE_key_copy(bmain, key);
/* for all keys in old block, clear data-arrays */
for (kb = key->block.first; kb; kb = kb->next) {
@@ -540,7 +540,7 @@ int join_mesh_exec(bContext *C, wmOperator *op)
if (matmap) MEM_freeN(matmap);
/* other mesh users */
- test_object_materials(bmain, (ID *)me);
+ test_all_objects_materials(bmain, (ID *)me);
/* free temp copy of destination shapekeys (if applicable) */
if (nkey) {
@@ -564,21 +564,10 @@ int join_mesh_exec(bContext *C, wmOperator *op)
BKE_key_sort(key);
}
-
DAG_relations_tag_update(bmain); // removed objects, need to rebuild dag
-#if 0
- ED_object_editmode_enter(C, EM_WAITCURSOR);
- ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO);
-#else
- /* toggle editmode using lower level functions so this can be called from python */
- EDBM_mesh_make(scene->toolsettings, ob, false);
- EDBM_mesh_load(ob);
- EDBM_mesh_free(me->edit_btmesh);
- MEM_freeN(me->edit_btmesh);
- me->edit_btmesh = NULL;
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
-#endif
+
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
return OPERATOR_FINISHED;
@@ -811,9 +800,9 @@ static BMVert *editbmesh_get_x_mirror_vert_spatial(Object *ob, BMEditMesh *em, c
int i;
/* ignore nan verts */
- if ((finite(co[0]) == false) ||
- (finite(co[1]) == false) ||
- (finite(co[2]) == false))
+ if ((isfinite(co[0]) == false) ||
+ (isfinite(co[1]) == false) ||
+ (isfinite(co[2]) == false))
{
return NULL;
}
@@ -902,8 +891,8 @@ static float *editmesh_get_mirror_uv(BMEditMesh *em, int axis, float *uv, float
float cent[2];
/* ignore nan verts */
- if (isnan(uv[0]) || !finite(uv[0]) ||
- isnan(uv[1]) || !finite(uv[1])
+ if (isnan(uv[0]) || !isfinite(uv[0]) ||
+ isnan(uv[1]) || !isfinite(uv[1])
)
{
return NULL;
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 88ab3450b04..9f91feee4c6 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -48,6 +48,7 @@
#include "DNA_scene_types.h"
#include "DNA_vfont_types.h"
#include "DNA_actuator_types.h"
+#include "DNA_gpencil_types.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -73,6 +74,7 @@
#include "BKE_lamp.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
#include "BKE_key.h"
#include "BKE_main.h"
#include "BKE_material.h"
@@ -996,7 +998,7 @@ static int group_instance_add_exec(bContext *C, wmOperator *op)
Object *ob = ED_object_add_type(C, OB_EMPTY, group->id.name + 2, loc, rot, false, layer);
ob->dup_group = group;
ob->transflag |= OB_DUPLIGROUP;
- id_lib_extern(&group->id);
+ id_us_plus(&group->id);
/* works without this except if you try render right after, see: 22027 */
DAG_relations_tag_update(bmain);
@@ -1108,12 +1110,18 @@ static void object_delete_check_glsl_update(Object *ob)
/* note: now unlinks constraints as well */
void ED_base_object_free_and_unlink(Main *bmain, Scene *scene, Base *base)
{
- DAG_id_type_tag(bmain, ID_OB);
+ if (BKE_library_ID_is_indirectly_used(bmain, base->object) && ID_REAL_USERS(base->object) <= 1) {
+ /* We cannot delete indirectly used object... */
+ printf("WARNING, undeletable object '%s', should have been catched before reaching this function!",
+ base->object->id.name + 2);
+ return;
+ }
+
BKE_scene_base_unlink(scene, base);
object_delete_check_glsl_update(base->object);
BKE_libblock_free_us(bmain, base->object);
- if (scene->basact == base) scene->basact = NULL;
MEM_freeN(base);
+ DAG_id_type_tag(bmain, ID_OB);
}
static int object_delete_exec(bContext *C, wmOperator *op)
@@ -1130,6 +1138,31 @@ static int object_delete_exec(bContext *C, wmOperator *op)
CTX_DATA_BEGIN (C, Base *, base, selected_bases)
{
+ const bool is_indirectly_used = BKE_library_ID_is_indirectly_used(bmain, base->object);
+ if (base->object->id.tag & LIB_TAG_INDIRECT) {
+ /* Can this case ever happen? */
+ BKE_reportf(op->reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2);
+ continue;
+ }
+ else if (is_indirectly_used && ID_REAL_USERS(base->object) <= 1) {
+ BKE_reportf(op->reports, RPT_WARNING,
+ "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user",
+ base->object->id.name + 2, scene->id.name + 2);
+ continue;
+ }
+ /* remove from Grease Pencil parent */
+ for (bGPdata *gpd = bmain->gpencil.first; gpd; gpd = gpd->id.next) {
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if (gpl->parent != NULL) {
+ Object *ob = gpl->parent;
+ Object *curob = base->object;
+ if (ob == curob) {
+ gpl->parent = NULL;
+ }
+ }
+ }
+ }
+
/* deselect object -- it could be used in other scenes */
base->object->flag &= ~SELECT;
@@ -1142,9 +1175,15 @@ static int object_delete_exec(bContext *C, wmOperator *op)
Base *base_other;
for (scene_iter = bmain->scene.first; scene_iter; scene_iter = scene_iter->id.next) {
- if (scene_iter != scene && !(scene_iter->id.lib)) {
+ if (scene_iter != scene && !ID_IS_LINKED_DATABLOCK(scene_iter)) {
base_other = BKE_scene_base_find(scene_iter, base->object);
if (base_other) {
+ if (is_indirectly_used && ID_REAL_USERS(base->object) <= 1) {
+ BKE_reportf(op->reports, RPT_WARNING,
+ "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user",
+ base->object->id.name + 2, scene_iter->id.name + 2);
+ break;
+ }
ED_base_object_free_and_unlink(bmain, scene_iter, base_other);
}
}
@@ -1273,7 +1312,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
for (dob = lb->first; dob; dob = dob->next) {
Base *basen;
- Object *ob = BKE_object_copy(dob->ob);
+ Object *ob = BKE_object_copy(bmain, dob->ob);
/* font duplis can have a totcol without material, we get them from parent
* should be implemented better...
@@ -1288,7 +1327,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
basen->object = ob;
/* make sure apply works */
- BKE_animdata_free(&ob->id);
+ BKE_animdata_free(&ob->id, true);
ob->adt = NULL;
/* Proxies are not to be copied. */
@@ -1380,7 +1419,6 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
}
}
- /* The same how BKE_object_unlink detects which object proxies to clear. */
if (base->object->transflag & OB_DUPLIGROUP && base->object->dup_group) {
for (object = bmain->object.first; object; object = object->id.next) {
if (object->proxy_group == base->object) {
@@ -1490,11 +1528,12 @@ static int convert_poll(bContext *C)
Object *obact = CTX_data_active_object(C);
Scene *scene = CTX_data_scene(C);
- return (!scene->id.lib && obact && scene->obedit != obact && (obact->flag & SELECT) && !(obact->id.lib));
+ return (!ID_IS_LINKED_DATABLOCK(scene) && obact && scene->obedit != obact &&
+ (obact->flag & SELECT) && !ID_IS_LINKED_DATABLOCK(obact));
}
/* Helper for convert_exec */
-static Base *duplibase_for_convert(Scene *scene, Base *base, Object *ob)
+static Base *duplibase_for_convert(Main *bmain, Scene *scene, Base *base, Object *ob)
{
Object *obn;
Base *basen;
@@ -1503,7 +1542,7 @@ static Base *duplibase_for_convert(Scene *scene, Base *base, Object *ob)
ob = base->object;
}
- obn = BKE_object_copy(ob);
+ obn = BKE_object_copy(bmain, ob);
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
basen = MEM_mallocN(sizeof(Base), "duplibase");
@@ -1583,7 +1622,7 @@ static int convert_exec(bContext *C, wmOperator *op)
ob->flag |= OB_DONE;
if (keep_original) {
- basen = duplibase_for_convert(scene, base, NULL);
+ basen = duplibase_for_convert(bmain, scene, base, NULL);
newob = basen->object;
/* decrement original mesh's usage count */
@@ -1591,7 +1630,7 @@ static int convert_exec(bContext *C, wmOperator *op)
id_us_min(&me->id);
/* make a new copy of the mesh */
- newob->data = BKE_mesh_copy(me);
+ newob->data = BKE_mesh_copy(bmain, me);
}
else {
newob = ob;
@@ -1601,14 +1640,14 @@ static int convert_exec(bContext *C, wmOperator *op)
if (newob->type == OB_CURVE) {
BKE_object_free_modifiers(newob); /* after derivedmesh calls! */
- ED_rigidbody_object_remove(scene, newob);
+ ED_rigidbody_object_remove(bmain, scene, newob);
}
}
else if (ob->type == OB_MESH && ob->modifiers.first) { /* converting a mesh with no modifiers causes a segfault */
ob->flag |= OB_DONE;
if (keep_original) {
- basen = duplibase_for_convert(scene, base, NULL);
+ basen = duplibase_for_convert(bmain, scene, base, NULL);
newob = basen->object;
/* decrement original mesh's usage count */
@@ -1616,7 +1655,7 @@ static int convert_exec(bContext *C, wmOperator *op)
id_us_min(&me->id);
/* make a new copy of the mesh */
- newob->data = BKE_mesh_copy(me);
+ newob->data = BKE_mesh_copy(bmain, me);
}
else {
newob = ob;
@@ -1640,14 +1679,14 @@ static int convert_exec(bContext *C, wmOperator *op)
ob->flag |= OB_DONE;
if (keep_original) {
- basen = duplibase_for_convert(scene, base, NULL);
+ basen = duplibase_for_convert(bmain, scene, base, NULL);
newob = basen->object;
/* decrement original curve's usage count */
id_us_min(&((Curve *)newob->data)->id);
/* make a new copy of the curve */
- newob->data = BKE_curve_copy(ob->data);
+ newob->data = BKE_curve_copy(bmain, ob->data);
}
else {
newob = ob;
@@ -1711,14 +1750,14 @@ static int convert_exec(bContext *C, wmOperator *op)
if (target == OB_MESH) {
if (keep_original) {
- basen = duplibase_for_convert(scene, base, NULL);
+ basen = duplibase_for_convert(bmain, scene, base, NULL);
newob = basen->object;
/* decrement original curve's usage count */
id_us_min(&((Curve *)newob->data)->id);
/* make a new copy of the curve */
- newob->data = BKE_curve_copy(ob->data);
+ newob->data = BKE_curve_copy(bmain, ob->data);
}
else {
newob = ob;
@@ -1746,7 +1785,7 @@ static int convert_exec(bContext *C, wmOperator *op)
if (!(baseob->flag & OB_DONE)) {
baseob->flag |= OB_DONE;
- basen = duplibase_for_convert(scene, base, baseob);
+ basen = duplibase_for_convert(bmain, scene, base, baseob);
newob = basen->object;
mb = newob->data;
@@ -1884,7 +1923,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
; /* nothing? */
}
else {
- obn = BKE_object_copy(ob);
+ obn = BKE_object_copy(bmain, ob);
DAG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
basen = MEM_mallocN(sizeof(Base), "duplibase");
@@ -1915,7 +1954,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
if (id) {
ID_NEW_US(obn->mat[a])
else
- obn->mat[a] = BKE_material_copy(obn->mat[a]);
+ obn->mat[a] = BKE_material_copy(bmain, obn->mat[a]);
id_us_min(id);
if (dupflag & USER_DUP_ACT) {
@@ -1931,7 +1970,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
if (id) {
ID_NEW_US(psys->part)
else
- psys->part = BKE_particlesettings_copy(psys->part);
+ psys->part = BKE_particlesettings_copy(bmain, psys->part);
if (dupflag & USER_DUP_ACT) {
BKE_animdata_copy_id_action(&psys->part->id);
@@ -1950,7 +1989,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
if (dupflag & USER_DUP_MESH) {
ID_NEW_US2(obn->data)
else {
- obn->data = BKE_mesh_copy(obn->data);
+ obn->data = BKE_mesh_copy(bmain, obn->data);
didit = 1;
}
id_us_min(id);
@@ -1960,7 +1999,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
if (dupflag & USER_DUP_CURVE) {
ID_NEW_US2(obn->data)
else {
- obn->data = BKE_curve_copy(obn->data);
+ obn->data = BKE_curve_copy(bmain, obn->data);
didit = 1;
}
id_us_min(id);
@@ -1970,7 +2009,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
if (dupflag & USER_DUP_SURF) {
ID_NEW_US2(obn->data)
else {
- obn->data = BKE_curve_copy(obn->data);
+ obn->data = BKE_curve_copy(bmain, obn->data);
didit = 1;
}
id_us_min(id);
@@ -1980,7 +2019,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
if (dupflag & USER_DUP_FONT) {
ID_NEW_US2(obn->data)
else {
- obn->data = BKE_curve_copy(obn->data);
+ obn->data = BKE_curve_copy(bmain, obn->data);
didit = 1;
}
id_us_min(id);
@@ -1990,7 +2029,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
if (dupflag & USER_DUP_MBALL) {
ID_NEW_US2(obn->data)
else {
- obn->data = BKE_mball_copy(obn->data);
+ obn->data = BKE_mball_copy(bmain, obn->data);
didit = 1;
}
id_us_min(id);
@@ -2000,7 +2039,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
if (dupflag & USER_DUP_LAMP) {
ID_NEW_US2(obn->data)
else {
- obn->data = BKE_lamp_copy(obn->data);
+ obn->data = BKE_lamp_copy(bmain, obn->data);
didit = 1;
}
id_us_min(id);
@@ -2013,7 +2052,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
if (dupflag & USER_DUP_ARM) {
ID_NEW_US2(obn->data)
else {
- obn->data = BKE_armature_copy(obn->data);
+ obn->data = BKE_armature_copy(bmain, obn->data);
BKE_pose_rebuild(obn, obn->data);
didit = 1;
}
@@ -2024,7 +2063,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
if (dupflag != 0) {
ID_NEW_US2(obn->data)
else {
- obn->data = BKE_lattice_copy(obn->data);
+ obn->data = BKE_lattice_copy(bmain, obn->data);
didit = 1;
}
id_us_min(id);
@@ -2034,7 +2073,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
if (dupflag != 0) {
ID_NEW_US2(obn->data)
else {
- obn->data = BKE_camera_copy(obn->data);
+ obn->data = BKE_camera_copy(bmain, obn->data);
didit = 1;
}
id_us_min(id);
@@ -2044,7 +2083,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
if (dupflag != 0) {
ID_NEW_US2(obn->data)
else {
- obn->data = BKE_speaker_copy(obn->data);
+ obn->data = BKE_speaker_copy(bmain, obn->data);
didit = 1;
}
id_us_min(id);
@@ -2083,7 +2122,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
if (id) {
ID_NEW_US((*matarar)[a])
else
- (*matarar)[a] = BKE_material_copy((*matarar)[a]);
+ (*matarar)[a] = BKE_material_copy(bmain, (*matarar)[a]);
id_us_min(id);
}
}
@@ -2280,7 +2319,7 @@ static int join_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
- if (!ob || ob->id.lib) return 0;
+ if (!ob || ID_IS_LINKED_DATABLOCK(ob)) return 0;
if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_ARMATURE))
return ED_operator_screenactive(C);
@@ -2333,7 +2372,7 @@ static int join_shapes_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
- if (!ob || ob->id.lib) return 0;
+ if (!ob || ID_IS_LINKED_DATABLOCK(ob)) return 0;
/* only meshes supported at the moment */
if (ob->type == OB_MESH)
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index efd1ebbd51b..59d78f13ccb 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -416,6 +416,13 @@ static void test_constraint(Object *owner, bPoseChannel *pchan, bConstraint *con
if ((data->flag & CAMERASOLVER_ACTIVECLIP) == 0 && (data->clip == NULL))
con->flag |= CONSTRAINT_DISABLE;
}
+ else if (con->type == CONSTRAINT_TYPE_TRANSFORM_CACHE) {
+ bTransformCacheConstraint *data = con->data;
+
+ if ((data->cache_file == NULL) || (data->object_path[0] == '\0')) {
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ }
/* Check targets for constraints */
if (check_targets && cti && cti->get_constraint_targets) {
@@ -584,7 +591,7 @@ static int edit_constraint_poll_generic(bContext *C, StructRNA *rna_type)
return 0;
}
- if (ob->id.lib || (ptr.id.data && ((ID *)ptr.id.data)->lib)) {
+ if (ID_IS_LINKED_DATABLOCK(ob) || (ptr.id.data && ID_IS_LINKED_DATABLOCK(ptr.id.data))) {
CTX_wm_operator_poll_msg_set(C, "Cannot edit library data");
return 0;
}
@@ -1560,12 +1567,12 @@ void OBJECT_OT_constraints_copy(wmOperatorType *ot)
/************************ add constraint operators *********************/
/* get the Object and/or PoseChannel to use as target */
-static short get_new_constraint_target(bContext *C, int con_type, Object **tar_ob, bPoseChannel **tar_pchan, short add)
+static bool get_new_constraint_target(bContext *C, int con_type, Object **tar_ob, bPoseChannel **tar_pchan, bool add)
{
Object *obact = ED_object_active_context(C);
bPoseChannel *pchanact = BKE_pose_channel_active(obact);
- short only_curve = 0, only_mesh = 0, only_ob = 0;
- short found = 0;
+ bool only_curve = false, only_mesh = false, only_ob = false;
+ bool found = false;
/* clear tar_ob and tar_pchan fields before use
* - assume for now that both always exist...
@@ -1585,7 +1592,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
case CONSTRAINT_TYPE_ROTLIMIT:
case CONSTRAINT_TYPE_SIZELIMIT:
case CONSTRAINT_TYPE_SAMEVOL:
- return 0;
+ return false;
/* restricted target-type constraints -------------- */
/* NOTE: for these, we cannot try to add a target object if no valid ones are found, since that doesn't work */
@@ -1593,26 +1600,26 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
case CONSTRAINT_TYPE_CLAMPTO:
case CONSTRAINT_TYPE_FOLLOWPATH:
case CONSTRAINT_TYPE_SPLINEIK:
- only_curve = 1;
- only_ob = 1;
- add = 0;
+ only_curve = true;
+ only_ob = true;
+ add = false;
break;
/* mesh only? */
case CONSTRAINT_TYPE_SHRINKWRAP:
- only_mesh = 1;
- only_ob = 1;
- add = 0;
+ only_mesh = true;
+ only_ob = true;
+ add = false;
break;
/* object only - add here is ok? */
case CONSTRAINT_TYPE_RIGIDBODYJOINT:
- only_ob = 1;
+ only_ob = true;
break;
}
/* if the active Object is Armature, and we can search for bones, do so... */
- if ((obact->type == OB_ARMATURE) && (only_ob == 0)) {
+ if ((obact->type == OB_ARMATURE) && (only_ob == false)) {
/* search in list of selected Pose-Channels for target */
CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
{
@@ -1620,7 +1627,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
if (pchan != pchanact) {
*tar_ob = obact;
*tar_pchan = pchan;
- found = 1;
+ found = true;
break;
}
@@ -1629,36 +1636,50 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
}
/* if not yet found, try selected Objects... */
- if (found == 0) {
+ if (found == false) {
/* search in selected objects context */
CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
{
/* just use the first object we encounter (that isn't the active object)
* and which fulfills the criteria for the object-target that we've got
*/
- if ((ob != obact) &&
- ((!only_curve) || (ob->type == OB_CURVE)) &&
- ((!only_mesh) || (ob->type == OB_MESH)))
- {
- /* set target */
- *tar_ob = ob;
- found = 1;
-
- /* perform some special operations on the target */
- if (only_curve) {
- /* Curve-Path option must be enabled for follow-path constraints to be able to work */
- Curve *cu = (Curve *)ob->data;
- cu->flag |= CU_PATH;
+ if (ob != obact) {
+ /* for armatures in pose mode, look inside the armature for the active bone
+ * so that we set up cross-armature constraints with less effort
+ */
+ if ((ob->type == OB_ARMATURE) && (ob->mode & OB_MODE_POSE) &&
+ (!only_curve && !only_mesh))
+ {
+ /* just use the active bone, and assume that it is visible + usable */
+ *tar_ob = ob;
+ *tar_pchan = BKE_pose_channel_active(ob);
+ found = true;
+
+ break;
+ }
+ else if (((!only_curve) || (ob->type == OB_CURVE)) &&
+ ((!only_mesh) || (ob->type == OB_MESH)))
+ {
+ /* set target */
+ *tar_ob = ob;
+ found = true;
+
+ /* perform some special operations on the target */
+ if (only_curve) {
+ /* Curve-Path option must be enabled for follow-path constraints to be able to work */
+ Curve *cu = (Curve *)ob->data;
+ cu->flag |= CU_PATH;
+ }
+
+ break;
}
-
- break;
}
}
CTX_DATA_END;
}
/* if still not found, add a new empty to act as a target (if allowed) */
- if ((found == 0) && (add)) {
+ if ((found == false) && (add)) {
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Base *base = BASACT, *newbase = NULL;
@@ -1692,7 +1713,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
/* make our new target the new object */
*tar_ob = obt;
- found = 1;
+ found = true;
}
/* return whether there's any target */
diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c
index 47ee6752e51..acee69daab7 100644
--- a/source/blender/editors/object/object_data_transfer.c
+++ b/source/blender/editors/object/object_data_transfer.c
@@ -300,7 +300,7 @@ static void data_transfer_exec_preprocess_objects(
}
me = ob->data;
- if (me->id.lib) {
+ if (ID_IS_LINKED_DATABLOCK(me)) {
/* Do not transfer to linked data, not supported. */
BKE_reportf(op->reports, RPT_WARNING, "Skipping object '%s', linked data '%s' cannot be modified",
ob->id.name + 2, me->id.name + 2);
@@ -330,7 +330,7 @@ static bool data_transfer_exec_is_object_valid(
me->id.tag &= ~LIB_TAG_DOIT;
return true;
}
- else if (me->id.lib == NULL) {
+ else if (!ID_IS_LINKED_DATABLOCK(me)) {
/* Do not transfer apply operation more than once. */
/* XXX This is not nice regarding vgroups, which are half-Object data... :/ */
BKE_reportf(op->reports, RPT_WARNING,
@@ -387,7 +387,7 @@ static int data_transfer_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
- if (reverse_transfer && ((ID *)(ob_src->data))->lib) {
+ if (reverse_transfer && ID_IS_LINKED_DATABLOCK(ob_src->data)) {
/* Do not transfer to linked data, not supported. */
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 06200778ee5..111afcdc7a7 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -470,7 +470,7 @@ void ED_object_editmode_enter(bContext *C, int flag)
View3D *v3d = NULL;
bool ok = false;
- if (scene->id.lib) return;
+ if (ID_IS_LINKED_DATABLOCK(scene)) return;
if (sa && sa->spacetype == SPACE_VIEW3D)
v3d = sa->spacedata.first;
@@ -539,7 +539,7 @@ void ED_object_editmode_enter(bContext *C, int flag)
* BKE_object_obdata_is_libdata that prevent the bugfix #6614, so
* i add this little hack here.
*/
- if (arm->id.lib) {
+ if (ID_IS_LINKED_DATABLOCK(arm)) {
error_libdata();
return;
}
@@ -621,7 +621,7 @@ static int editmode_toggle_poll(bContext *C)
Object *ob = CTX_data_active_object(C);
/* covers proxies too */
- if (ELEM(NULL, ob, ob->data) || ((ID *)ob->data)->lib)
+ if (ELEM(NULL, ob, ob->data) || ID_IS_LINKED_DATABLOCK(ob->data))
return 0;
/* if hidden but in edit mode, we still display */
@@ -848,7 +848,7 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event)
Nurb *nu;
bool do_depgraph_update = false;
- if (scene->id.lib) return;
+ if (ID_IS_LINKED_DATABLOCK(scene)) return;
if (!(ob = OBACT)) return;
@@ -910,7 +910,7 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event)
base->object->dup_group = ob->dup_group;
if (ob->dup_group)
- id_lib_extern(&ob->dup_group->id);
+ id_us_plus(&ob->dup_group->id);
}
else if (event == 7) { /* mass */
base->object->mass = ob->mass;
@@ -946,6 +946,7 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event)
cu1 = base->object->data;
cu1->spacemode = cu->spacemode;
+ cu1->align_y = cu->align_y;
cu1->spacing = cu->spacing;
cu1->linedist = cu->linedist;
cu1->shear = cu->shear;
@@ -1435,7 +1436,7 @@ static int shade_smooth_exec(bContext *C, wmOperator *op)
{
data = ob->data;
- if (data && data->lib) {
+ if (data && ID_IS_LINKED_DATABLOCK(data)) {
linked_data = true;
continue;
}
@@ -1518,7 +1519,7 @@ static void UNUSED_FUNCTION(image_aspect) (Scene *scene, View3D *v3d)
int a, b, done;
if (scene->obedit) return; // XXX get from context
- if (scene->id.lib) return;
+ if (ID_IS_LINKED_DATABLOCK(scene)) return;
for (base = FIRSTBASE; base; base = base->next) {
if (TESTBASELIB(v3d, base)) {
diff --git a/source/blender/editors/object/object_group.c b/source/blender/editors/object/object_group.c
index 76a8a68c42d..0fe43c44d7d 100644
--- a/source/blender/editors/object/object_group.c
+++ b/source/blender/editors/object/object_group.c
@@ -43,6 +43,7 @@
#include "BKE_depsgraph.h"
#include "BKE_group.h"
#include "BKE_library.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_object.h"
@@ -439,7 +440,7 @@ static int group_link_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
/* Early return check, if the object is already in group
- * we could sckip all the dependency check and just consider
+ * we could skip all the dependency check and just consider
* operator is finished.
*/
if (BKE_group_object_exists(group, ob)) {
@@ -527,7 +528,8 @@ static int group_unlink_exec(bContext *C, wmOperator *UNUSED(op))
if (!group)
return OPERATOR_CANCELLED;
- BKE_group_unlink(bmain, group);
+ BKE_libblock_unlink(bmain, group, false, false);
+ BKE_libblock_free(bmain, group);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index 264945b00bf..b44ddf925a8 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -817,9 +817,9 @@ int edit_modifier_poll_generic(bContext *C, StructRNA *rna_type, int obtype_flag
PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", rna_type);
Object *ob = (ptr.id.data) ? ptr.id.data : ED_object_active_context(C);
- if (!ob || ob->id.lib) return 0;
+ if (!ob || ID_IS_LINKED_DATABLOCK(ob)) return 0;
if (obtype_flag && ((1 << ob->type) & obtype_flag) == 0) return 0;
- if (ptr.id.data && ((ID *)ptr.id.data)->lib) return 0;
+ if (ptr.id.data && ID_IS_LINKED_DATABLOCK(ptr.id.data)) return 0;
return 1;
}
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index 534e59384ce..7e7e1ef182c 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -365,9 +365,21 @@ void ED_keymap_object(wmKeyConfig *keyconf)
WM_keymap_verify_item(keymap, "OBJECT_OT_constraint_add_with_targets", CKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
WM_keymap_verify_item(keymap, "OBJECT_OT_constraints_clear", CKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
- WM_keymap_verify_item(keymap, "OBJECT_OT_location_clear", GKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_verify_item(keymap, "OBJECT_OT_rotation_clear", RKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_verify_item(keymap, "OBJECT_OT_scale_clear", SKEY, KM_PRESS, KM_ALT, 0);
+
+ kmi = WM_keymap_add_item(keymap, "OBJECT_OT_location_clear", GKEY, KM_PRESS, KM_ALT, 0);
+ RNA_boolean_set(kmi->ptr, "clear_delta", false);
+ kmi = WM_keymap_add_item(keymap, "OBJECT_OT_rotation_clear", RKEY, KM_PRESS, KM_ALT, 0);
+ RNA_boolean_set(kmi->ptr, "clear_delta", false);
+ kmi = WM_keymap_add_item(keymap, "OBJECT_OT_scale_clear", SKEY, KM_PRESS, KM_ALT, 0);
+ RNA_boolean_set(kmi->ptr, "clear_delta", false);
+
+ kmi = WM_keymap_add_item(keymap, "OBJECT_OT_location_clear", GKEY, KM_PRESS, KM_ALT | KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "clear_delta", true);
+ kmi = WM_keymap_add_item(keymap, "OBJECT_OT_rotation_clear", RKEY, KM_PRESS, KM_ALT | KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "clear_delta", true);
+ kmi = WM_keymap_add_item(keymap, "OBJECT_OT_scale_clear", SKEY, KM_PRESS, KM_ALT | KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "clear_delta", true);
+
WM_keymap_verify_item(keymap, "OBJECT_OT_origin_clear", OKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "OBJECT_OT_hide_view_clear", HKEY, KM_PRESS, KM_ALT, 0);
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 2f10f83e276..d1232fd2aab 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -48,6 +48,7 @@
#include "DNA_world_types.h"
#include "DNA_object_types.h"
#include "DNA_vfont_types.h"
+#include "DNA_gpencil_types.h"
#include "BLI_math.h"
#include "BLI_listbase.h"
@@ -291,17 +292,17 @@ static int make_proxy_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Object *ob = ED_object_active_context(C);
/* sanity checks */
- if (!scene || scene->id.lib || !ob)
+ if (!scene || ID_IS_LINKED_DATABLOCK(scene) || !ob)
return OPERATOR_CANCELLED;
/* Get object to work on - use a menu if we need to... */
- if (ob->dup_group && ob->dup_group->id.lib) {
+ if (ob->dup_group && ID_IS_LINKED_DATABLOCK(ob->dup_group)) {
/* gives menu with list of objects in group */
/* proxy_group_objects_menu(C, op, ob, ob->dup_group); */
WM_enum_search_invoke(C, op, event);
return OPERATOR_CANCELLED;
}
- else if (ob->id.lib) {
+ else if (ID_IS_LINKED_DATABLOCK(ob)) {
uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("OK?"), ICON_QUESTION);
uiLayout *layout = UI_popup_menu_layout(pup);
@@ -437,7 +438,7 @@ typedef enum eObClearParentTypes {
EnumPropertyItem prop_clear_parent_types[] = {
{CLEAR_PARENT_ALL, "CLEAR", 0, "Clear Parent",
- "Completely clear the parenting relationship, including involved modifiers is any"},
+ "Completely clear the parenting relationship, including involved modifiers if any"},
{CLEAR_PARENT_KEEP_TRANSFORM, "CLEAR_KEEP_TRANSFORM", 0, "Clear and Keep Transformation",
"As 'Clear Parent', but keep the current visual transformations of the object"},
{CLEAR_PARENT_INVERSE, "CLEAR_INVERSE", 0, "Clear Parent Inverse",
@@ -1381,7 +1382,7 @@ static int move_to_layer_exec(bContext *C, wmOperator *op)
/* upper byte is used for local view */
local = base->lay & 0xFF000000;
base->lay = lay + local;
- base->object->lay = lay;
+ base->object->lay = base->lay;
/* if (base->object->type == OB_LAMP) is_lamp = true; */
}
CTX_DATA_END;
@@ -1466,7 +1467,7 @@ static int make_links_scene_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (scene_to->id.lib) {
+ if (ID_IS_LINKED_DATABLOCK(scene_to)) {
BKE_report(op->reports, RPT_ERROR, "Cannot link objects into a linked scene");
return OPERATOR_CANCELLED;
}
@@ -1564,7 +1565,7 @@ static int make_links_data_exec(bContext *C, wmOperator *op)
ob_dst->data = obdata_id;
/* if amount of material indices changed: */
- test_object_materials(bmain, ob_dst->data);
+ test_object_materials(ob_dst, ob_dst->data);
DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA);
break;
@@ -1574,12 +1575,12 @@ static int make_links_data_exec(bContext *C, wmOperator *op)
Material *ma = give_current_material(ob_src, a + 1);
assign_material(ob_dst, ma, a + 1, BKE_MAT_ASSIGN_USERPREF); /* also works with ma==NULL */
}
- DAG_id_tag_update(&ob_dst->id, 0);
+ DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA);
break;
case MAKE_LINKS_ANIMDATA:
BKE_animdata_copy_id((ID *)ob_dst, (ID *)ob_src, false);
if (ob_dst->data && ob_src->data) {
- if (obdata_id->lib) {
+ if (ID_IS_LINKED_DATABLOCK(obdata_id)) {
is_lib = true;
break;
}
@@ -1608,7 +1609,7 @@ static int make_links_data_exec(bContext *C, wmOperator *op)
case MAKE_LINKS_DUPLIGROUP:
ob_dst->dup_group = ob_src->dup_group;
if (ob_dst->dup_group) {
- id_lib_extern(&ob_dst->dup_group->id);
+ id_us_plus(&ob_dst->dup_group->id);
ob_dst->transflag |= OB_DUPLIGROUP;
}
break;
@@ -1621,7 +1622,7 @@ static int make_links_data_exec(bContext *C, wmOperator *op)
Curve *cu_src = ob_src->data;
Curve *cu_dst = ob_dst->data;
- if (obdata_id->lib) {
+ if (ID_IS_LINKED_DATABLOCK(obdata_id)) {
is_lib = true;
break;
}
@@ -1749,9 +1750,9 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in
ob = base->object;
if ((base->flag & flag) == flag) {
- if (ob->id.lib == NULL && ob->id.us > 1) {
+ if (!ID_IS_LINKED_DATABLOCK(ob) && ob->id.us > 1) {
/* base gets copy of object */
- obn = BKE_object_copy(ob);
+ obn = BKE_object_copy(bmain, ob);
base->object = obn;
if (copy_groups) {
@@ -1762,6 +1763,17 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in
else {
/* copy already clears */
}
+ /* remap gpencil parenting */
+
+ if (scene->gpd) {
+ bGPdata *gpd = scene->gpd;
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if (gpl->parent == ob) {
+ gpl->parent = obn;
+ }
+ }
+ }
+
base->flag = obn->flag;
id_us_min(&ob->id);
@@ -1784,7 +1796,7 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in
}
if (all_duplicated) {
- groupn = BKE_group_copy(group);
+ groupn = BKE_group_copy(bmain, group);
for (go = groupn->gobject.first; go; go = go->next)
go->ob = (Object *)go->ob->id.newid;
@@ -1821,21 +1833,21 @@ void ED_object_single_user(Main *bmain, Scene *scene, Object *ob)
single_object_users(bmain, scene, NULL, OB_DONE, copy_groups);
}
-static void new_id_matar(Material **matar, const int totcol)
+static void new_id_matar(Main *bmain, Material **matar, const int totcol)
{
ID *id;
int a;
for (a = 0; a < totcol; a++) {
id = (ID *)matar[a];
- if (id && id->lib == NULL) {
+ if (id && !ID_IS_LINKED_DATABLOCK(id)) {
if (id->newid) {
matar[a] = (Material *)id->newid;
id_us_plus(id->newid);
id_us_min(id);
}
else if (id->us > 1) {
- matar[a] = BKE_material_copy(matar[a]);
+ matar[a] = BKE_material_copy(bmain, matar[a]);
id_us_min(id);
id->newid = (ID *)matar[a];
}
@@ -1857,15 +1869,15 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag)
for (base = FIRSTBASE; base; base = base->next) {
ob = base->object;
- if (ob->id.lib == NULL && (base->flag & flag) == flag) {
+ if (!ID_IS_LINKED_DATABLOCK(ob) && (base->flag & flag) == flag) {
id = ob->data;
- if (id && id->us > 1 && id->lib == NULL) {
+ if (id && id->us > 1 && !ID_IS_LINKED_DATABLOCK(id)) {
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
switch (ob->type) {
case OB_LAMP:
- ob->data = la = BKE_lamp_copy(ob->data);
+ ob->data = la = BKE_lamp_copy(bmain, ob->data);
for (a = 0; a < MAX_MTEX; a++) {
if (la->mtex[a]) {
ID_NEW(la->mtex[a]->object);
@@ -1873,37 +1885,37 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag)
}
break;
case OB_CAMERA:
- ob->data = BKE_camera_copy(ob->data);
+ ob->data = BKE_camera_copy(bmain, ob->data);
break;
case OB_MESH:
- ob->data = me = BKE_mesh_copy(ob->data);
+ ob->data = me = BKE_mesh_copy(bmain, ob->data);
if (me->key)
BKE_animdata_copy_id_action((ID *)me->key);
break;
case OB_MBALL:
- ob->data = BKE_mball_copy(ob->data);
+ ob->data = BKE_mball_copy(bmain, ob->data);
break;
case OB_CURVE:
case OB_SURF:
case OB_FONT:
- ob->data = cu = BKE_curve_copy(ob->data);
+ ob->data = cu = BKE_curve_copy(bmain, ob->data);
ID_NEW(cu->bevobj);
ID_NEW(cu->taperobj);
if (cu->key)
BKE_animdata_copy_id_action((ID *)cu->key);
break;
case OB_LATTICE:
- ob->data = lat = BKE_lattice_copy(ob->data);
+ ob->data = lat = BKE_lattice_copy(bmain, ob->data);
if (lat->key)
BKE_animdata_copy_id_action((ID *)lat->key);
break;
case OB_ARMATURE:
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- ob->data = BKE_armature_copy(ob->data);
+ ob->data = BKE_armature_copy(bmain, ob->data);
BKE_pose_rebuild(ob, ob->data);
break;
case OB_SPEAKER:
- ob->data = BKE_speaker_copy(ob->data);
+ ob->data = BKE_speaker_copy(bmain, ob->data);
break;
default:
if (G.debug & G_DEBUG)
@@ -1938,14 +1950,14 @@ static void single_object_action_users(Scene *scene, const int flag)
for (base = FIRSTBASE; base; base = base->next) {
ob = base->object;
- if (ob->id.lib == NULL && (flag == 0 || (base->flag & SELECT)) ) {
+ if (!ID_IS_LINKED_DATABLOCK(ob) && (flag == 0 || (base->flag & SELECT)) ) {
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
BKE_animdata_copy_id_action(&ob->id);
}
}
}
-static void single_mat_users(Scene *scene, const int flag, const bool do_textures)
+static void single_mat_users(Main *bmain, Scene *scene, const int flag, const bool do_textures)
{
Object *ob;
Base *base;
@@ -1955,14 +1967,14 @@ static void single_mat_users(Scene *scene, const int flag, const bool do_texture
for (base = FIRSTBASE; base; base = base->next) {
ob = base->object;
- if (ob->id.lib == NULL && (flag == 0 || (base->flag & SELECT)) ) {
+ if (!ID_IS_LINKED_DATABLOCK(ob) && (flag == 0 || (base->flag & SELECT)) ) {
for (a = 1; a <= ob->totcol; a++) {
ma = give_current_material(ob, a);
if (ma) {
/* do not test for LIB_TAG_NEW: this functions guaranteed delivers single_users! */
if (ma->id.us > 1) {
- man = BKE_material_copy(ma);
+ man = BKE_material_copy(bmain, ma);
BKE_animdata_copy_id_action(&man->id);
man->id.us = 0;
@@ -1973,7 +1985,7 @@ static void single_mat_users(Scene *scene, const int flag, const bool do_texture
if (ma->mtex[b] && (tex = ma->mtex[b]->tex)) {
if (tex->id.us > 1) {
id_us_min(&tex->id);
- tex = BKE_texture_copy(tex);
+ tex = BKE_texture_copy(bmain, tex);
BKE_animdata_copy_id_action(&tex->id);
man->mtex[b]->tex = tex;
}
@@ -1987,7 +1999,7 @@ static void single_mat_users(Scene *scene, const int flag, const bool do_texture
}
}
-static void do_single_tex_user(Tex **from)
+static void do_single_tex_user(Main *bmain, Tex **from)
{
Tex *tex, *texn;
@@ -2000,7 +2012,7 @@ static void do_single_tex_user(Tex **from)
id_us_min(&tex->id);
}
else if (tex->id.us > 1) {
- texn = BKE_texture_copy(tex);
+ texn = BKE_texture_copy(bmain, tex);
BKE_animdata_copy_id_action(&texn->id);
tex->id.newid = (ID *)texn;
id_us_min(&tex->id);
@@ -2020,7 +2032,7 @@ static void single_tex_users_expand(Main *bmain)
if (ma->id.tag & LIB_TAG_NEW) {
for (b = 0; b < MAX_MTEX; b++) {
if (ma->mtex[b] && ma->mtex[b]->tex) {
- do_single_tex_user(&(ma->mtex[b]->tex));
+ do_single_tex_user(bmain, &(ma->mtex[b]->tex));
}
}
}
@@ -2030,7 +2042,7 @@ static void single_tex_users_expand(Main *bmain)
if (la->id.tag & LIB_TAG_NEW) {
for (b = 0; b < MAX_MTEX; b++) {
if (la->mtex[b] && la->mtex[b]->tex) {
- do_single_tex_user(&(la->mtex[b]->tex));
+ do_single_tex_user(bmain, &(la->mtex[b]->tex));
}
}
}
@@ -2040,7 +2052,7 @@ static void single_tex_users_expand(Main *bmain)
if (wo->id.tag & LIB_TAG_NEW) {
for (b = 0; b < MAX_MTEX; b++) {
if (wo->mtex[b] && wo->mtex[b]->tex) {
- do_single_tex_user(&(wo->mtex[b]->tex));
+ do_single_tex_user(bmain, &(wo->mtex[b]->tex));
}
}
}
@@ -2059,19 +2071,19 @@ static void single_mat_users_expand(Main *bmain)
for (ob = bmain->object.first; ob; ob = ob->id.next)
if (ob->id.tag & LIB_TAG_NEW)
- new_id_matar(ob->mat, ob->totcol);
+ new_id_matar(bmain, ob->mat, ob->totcol);
for (me = bmain->mesh.first; me; me = me->id.next)
if (me->id.tag & LIB_TAG_NEW)
- new_id_matar(me->mat, me->totcol);
+ new_id_matar(bmain, me->mat, me->totcol);
for (cu = bmain->curve.first; cu; cu = cu->id.next)
if (cu->id.tag & LIB_TAG_NEW)
- new_id_matar(cu->mat, cu->totcol);
+ new_id_matar(bmain, cu->mat, cu->totcol);
for (mb = bmain->mball.first; mb; mb = mb->id.next)
if (mb->id.tag & LIB_TAG_NEW)
- new_id_matar(mb->mat, mb->totcol);
+ new_id_matar(bmain, mb->mat, mb->totcol);
/* material imats */
for (ma = bmain->mat.first; ma; ma = ma->id.next)
@@ -2094,6 +2106,7 @@ void ED_object_single_users(Main *bmain, Scene *scene, const bool full, const bo
}
BKE_main_id_clear_newpoins(bmain);
+ DAG_relations_tag_update(bmain);
}
/******************************* Make Local ***********************************/
@@ -2104,11 +2117,11 @@ static void make_local_makelocalmaterial(Material *ma)
AnimData *adt;
int b;
- id_make_local(&ma->id, false);
+ id_make_local(G.main, &ma->id, false, false);
for (b = 0; b < MAX_MTEX; b++)
if (ma->mtex[b] && ma->mtex[b]->tex)
- id_make_local(&ma->mtex[b]->tex->id, false);
+ id_make_local(G.main, &ma->mtex[b]->tex->id, false, false);
adt = BKE_animdata_from_id(&ma->id);
if (adt) BKE_animdata_make_local(adt);
@@ -2184,7 +2197,7 @@ static bool make_local_all__instance_indirect_unused(Main *bmain, Scene *scene)
bool changed = false;
for (ob = bmain->object.first; ob; ob = ob->id.next) {
- if (ob->id.lib && (ob->id.us == 0)) {
+ if (ID_IS_LINKED_DATABLOCK(ob) && (ob->id.us == 0)) {
Base *base;
id_us_plus(&ob->id);
@@ -2237,7 +2250,7 @@ static int make_local_exec(bContext *C, wmOperator *op)
}
if (ob->id.lib)
- id_make_local(&ob->id, false);
+ id_make_local(bmain, &ob->id, false, false);
}
CTX_DATA_END;
@@ -2259,7 +2272,7 @@ static int make_local_exec(bContext *C, wmOperator *op)
id = ob->data;
if (id && (ELEM(mode, MAKE_LOCAL_SELECT_OBDATA, MAKE_LOCAL_SELECT_OBDATA_MATERIAL))) {
- id_make_local(id, false);
+ id_make_local(bmain, id, false, false);
adt = BKE_animdata_from_id(id);
if (adt) BKE_animdata_make_local(adt);
@@ -2275,7 +2288,7 @@ static int make_local_exec(bContext *C, wmOperator *op)
}
for (psys = ob->particlesystem.first; psys; psys = psys->next)
- id_make_local(&psys->part->id, false);
+ id_make_local(bmain, &psys->part->id, false, false);
adt = BKE_animdata_from_id(&ob->id);
if (adt) BKE_animdata_make_local(adt);
@@ -2294,7 +2307,7 @@ static int make_local_exec(bContext *C, wmOperator *op)
for (b = 0; b < MAX_MTEX; b++)
if (la->mtex[b] && la->mtex[b]->tex)
- id_make_local(&la->mtex[b]->tex->id, false);
+ id_make_local(bmain, &la->mtex[b]->tex->id, false, false);
}
else {
for (a = 0; a < ob->totcol; a++) {
@@ -2333,7 +2346,7 @@ void OBJECT_OT_make_local(wmOperatorType *ot)
/* identifiers */
ot->name = "Make Local";
- ot->description = "Make library linked datablocks local to this file";
+ ot->description = "Make library linked data-blocks local to this file";
ot->idname = "OBJECT_OT_make_local";
/* api callbacks */
@@ -2376,7 +2389,7 @@ static int make_single_user_exec(bContext *C, wmOperator *op)
}
if (RNA_boolean_get(op->ptr, "material")) {
- single_mat_users(scene, flag, RNA_boolean_get(op->ptr, "texture"));
+ single_mat_users(bmain, scene, flag, RNA_boolean_get(op->ptr, "texture"));
}
#if 0 /* can't do this separate from materials */
@@ -2428,7 +2441,7 @@ void OBJECT_OT_make_single_user(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "object", 0, "Object", "Make single user objects");
RNA_def_boolean(ot->srna, "obdata", 0, "Object Data", "Make single user object data");
- RNA_def_boolean(ot->srna, "material", 0, "Materials", "Make materials local to each datablock");
+ RNA_def_boolean(ot->srna, "material", 0, "Materials", "Make materials local to each data-block");
RNA_def_boolean(ot->srna, "texture", 0, "Textures",
"Make textures local to each material (needs 'Materials' to be set too)");
RNA_def_boolean(ot->srna, "animation", 0, "Object Animation", "Make animation data local to each object");
diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c
index 0cbbe46f461..f1b7186f8a1 100644
--- a/source/blender/editors/object/object_select.c
+++ b/source/blender/editors/object/object_select.c
@@ -577,7 +577,6 @@ static bool select_grouped_parent(bContext *C) /* Makes parent active and de-sel
/* can be NULL if parent in other scene */
if (baspar && BASE_SELECTABLE(v3d, baspar)) {
- ED_base_object_select(basact, BA_DESELECT);
ED_base_object_select(baspar, BA_SELECT);
ED_base_object_activate(C, baspar);
changed = true;
diff --git a/source/blender/editors/object/object_shapekey.c b/source/blender/editors/object/object_shapekey.c
index 39bd34456be..e04114761e4 100644
--- a/source/blender/editors/object/object_shapekey.c
+++ b/source/blender/editors/object/object_shapekey.c
@@ -225,7 +225,7 @@ static int shape_key_mode_poll(bContext *C)
{
Object *ob = ED_object_context(C);
ID *data = (ob) ? ob->data : NULL;
- return (ob && !ob->id.lib && data && !data->lib && ob->mode != OB_MODE_EDIT);
+ return (ob && !ID_IS_LINKED_DATABLOCK(ob) && data && !ID_IS_LINKED_DATABLOCK(data) && ob->mode != OB_MODE_EDIT);
}
static int shape_key_mode_exists_poll(bContext *C)
@@ -234,7 +234,7 @@ static int shape_key_mode_exists_poll(bContext *C)
ID *data = (ob) ? ob->data : NULL;
/* same as shape_key_mode_poll */
- return (ob && !ob->id.lib && data && !data->lib && ob->mode != OB_MODE_EDIT) &&
+ return (ob && !ID_IS_LINKED_DATABLOCK(ob) && data && !ID_IS_LINKED_DATABLOCK(data) && ob->mode != OB_MODE_EDIT) &&
/* check a keyblock exists */
(BKE_keyblock_from_object(ob) != NULL);
}
@@ -246,14 +246,15 @@ static int shape_key_move_poll(bContext *C)
ID *data = (ob) ? ob->data : NULL;
Key *key = BKE_key_from_object(ob);
- return (ob && !ob->id.lib && data && !data->lib && ob->mode != OB_MODE_EDIT && key && key->totkey > 1);
+ return (ob && !ID_IS_LINKED_DATABLOCK(ob) && data && !ID_IS_LINKED_DATABLOCK(data) &&
+ ob->mode != OB_MODE_EDIT && key && key->totkey > 1);
}
static int shape_key_poll(bContext *C)
{
Object *ob = ED_object_context(C);
ID *data = (ob) ? ob->data : NULL;
- return (ob && !ob->id.lib && data && !data->lib);
+ return (ob && !ID_IS_LINKED_DATABLOCK(ob) && data && !ID_IS_LINKED_DATABLOCK(data));
}
static int shape_key_add_exec(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index d2bbb73b597..4d7d7df0d2f 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -76,60 +76,87 @@
/*************************** Clear Transformation ****************************/
/* clear location of object */
-static void object_clear_loc(Object *ob)
+static void object_clear_loc(Object *ob, const bool clear_delta)
{
/* clear location if not locked */
- if ((ob->protectflag & OB_LOCK_LOCX) == 0)
- ob->loc[0] = ob->dloc[0] = 0.0f;
- if ((ob->protectflag & OB_LOCK_LOCY) == 0)
- ob->loc[1] = ob->dloc[1] = 0.0f;
- if ((ob->protectflag & OB_LOCK_LOCZ) == 0)
- ob->loc[2] = ob->dloc[2] = 0.0f;
+ if ((ob->protectflag & OB_LOCK_LOCX) == 0) {
+ ob->loc[0] = 0.0f;
+ if (clear_delta) ob->dloc[0] = 0.0f;
+ }
+ if ((ob->protectflag & OB_LOCK_LOCY) == 0) {
+ ob->loc[1] = 0.0f;
+ if (clear_delta) ob->dloc[1] = 0.0f;
+ }
+ if ((ob->protectflag & OB_LOCK_LOCZ) == 0) {
+ ob->loc[2] = 0.0f;
+ if (clear_delta) ob->dloc[2] = 0.0f;
+ }
}
/* clear rotation of object */
-static void object_clear_rot(Object *ob)
+static void object_clear_rot(Object *ob, const bool clear_delta)
{
/* clear rotations that aren't locked */
if (ob->protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) {
if (ob->protectflag & OB_LOCK_ROT4D) {
/* perform clamping on a component by component basis */
if (ob->rotmode == ROT_MODE_AXISANGLE) {
- if ((ob->protectflag & OB_LOCK_ROTW) == 0)
- ob->rotAngle = ob->drotAngle = 0.0f;
- if ((ob->protectflag & OB_LOCK_ROTX) == 0)
- ob->rotAxis[0] = ob->drotAxis[0] = 0.0f;
- if ((ob->protectflag & OB_LOCK_ROTY) == 0)
- ob->rotAxis[1] = ob->drotAxis[1] = 0.0f;
- if ((ob->protectflag & OB_LOCK_ROTZ) == 0)
- ob->rotAxis[2] = ob->drotAxis[2] = 0.0f;
+ if ((ob->protectflag & OB_LOCK_ROTW) == 0) {
+ ob->rotAngle = 0.0f;
+ if (clear_delta) ob->drotAngle = 0.0f;
+ }
+ if ((ob->protectflag & OB_LOCK_ROTX) == 0) {
+ ob->rotAxis[0] = 0.0f;
+ if (clear_delta) ob->drotAxis[0] = 0.0f;
+ }
+ if ((ob->protectflag & OB_LOCK_ROTY) == 0) {
+ ob->rotAxis[1] = 0.0f;
+ if (clear_delta) ob->drotAxis[1] = 0.0f;
+ }
+ if ((ob->protectflag & OB_LOCK_ROTZ) == 0) {
+ ob->rotAxis[2] = 0.0f;
+ if (clear_delta) ob->drotAxis[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(ob->rotAxis[0], ob->rotAxis[1]) && IS_EQF(ob->rotAxis[1], ob->rotAxis[2]))
ob->rotAxis[1] = 1.0f;
- if (IS_EQF(ob->drotAxis[0], ob->drotAxis[1]) && IS_EQF(ob->drotAxis[1], ob->drotAxis[2]))
+ if (IS_EQF(ob->drotAxis[0], ob->drotAxis[1]) && IS_EQF(ob->drotAxis[1], ob->drotAxis[2]) && clear_delta)
ob->drotAxis[1] = 1.0f;
}
else if (ob->rotmode == ROT_MODE_QUAT) {
- if ((ob->protectflag & OB_LOCK_ROTW) == 0)
- ob->quat[0] = ob->dquat[0] = 1.0f;
- if ((ob->protectflag & OB_LOCK_ROTX) == 0)
- ob->quat[1] = ob->dquat[1] = 0.0f;
- if ((ob->protectflag & OB_LOCK_ROTY) == 0)
- ob->quat[2] = ob->dquat[2] = 0.0f;
- if ((ob->protectflag & OB_LOCK_ROTZ) == 0)
- ob->quat[3] = ob->dquat[3] = 0.0f;
-
+ if ((ob->protectflag & OB_LOCK_ROTW) == 0) {
+ ob->quat[0] = 1.0f;
+ if (clear_delta) ob->dquat[0] = 1.0f;
+ }
+ if ((ob->protectflag & OB_LOCK_ROTX) == 0) {
+ ob->quat[1] = 0.0f;
+ if (clear_delta) ob->dquat[1] = 0.0f;
+ }
+ if ((ob->protectflag & OB_LOCK_ROTY) == 0) {
+ ob->quat[2] = 0.0f;
+ if (clear_delta) ob->dquat[2] = 0.0f;
+ }
+ if ((ob->protectflag & OB_LOCK_ROTZ) == 0) {
+ ob->quat[3] = 0.0f;
+ if (clear_delta) ob->dquat[3] = 0.0f;
+ }
/* TODO: does this quat need normalizing now? */
}
else {
/* the flag may have been set for the other modes, so just ignore the extra flag... */
- if ((ob->protectflag & OB_LOCK_ROTX) == 0)
- ob->rot[0] = ob->drot[0] = 0.0f;
- if ((ob->protectflag & OB_LOCK_ROTY) == 0)
- ob->rot[1] = ob->drot[1] = 0.0f;
- if ((ob->protectflag & OB_LOCK_ROTZ) == 0)
- ob->rot[2] = ob->drot[2] = 0.0f;
+ if ((ob->protectflag & OB_LOCK_ROTX) == 0) {
+ ob->rot[0] = 0.0f;
+ if (clear_delta) ob->drot[0] = 0.0f;
+ }
+ if ((ob->protectflag & OB_LOCK_ROTY) == 0) {
+ ob->rot[1] = 0.0f;
+ if (clear_delta) ob->drot[1] = 0.0f;
+ }
+ if ((ob->protectflag & OB_LOCK_ROTZ) == 0) {
+ ob->rot[2] = 0.0f;
+ if (clear_delta) ob->drot[2] = 0.0f;
+ }
}
}
else {
@@ -175,34 +202,34 @@ static void object_clear_rot(Object *ob)
else {
if (ob->rotmode == ROT_MODE_QUAT) {
unit_qt(ob->quat);
- unit_qt(ob->dquat);
+ if (clear_delta) unit_qt(ob->dquat);
}
else if (ob->rotmode == ROT_MODE_AXISANGLE) {
unit_axis_angle(ob->rotAxis, &ob->rotAngle);
- unit_axis_angle(ob->drotAxis, &ob->drotAngle);
+ if (clear_delta) unit_axis_angle(ob->drotAxis, &ob->drotAngle);
}
else {
zero_v3(ob->rot);
- zero_v3(ob->drot);
+ if (clear_delta) zero_v3(ob->drot);
}
}
}
/* clear scale of object */
-static void object_clear_scale(Object *ob)
+static void object_clear_scale(Object *ob, const bool clear_delta)
{
/* clear scale factors which are not locked */
if ((ob->protectflag & OB_LOCK_SCALEX) == 0) {
- ob->dscale[0] = 1.0f;
ob->size[0] = 1.0f;
+ if (clear_delta) ob->dscale[0] = 1.0f;
}
if ((ob->protectflag & OB_LOCK_SCALEY) == 0) {
- ob->dscale[1] = 1.0f;
ob->size[1] = 1.0f;
+ if (clear_delta) ob->dscale[1] = 1.0f;
}
if ((ob->protectflag & OB_LOCK_SCALEZ) == 0) {
- ob->dscale[2] = 1.0f;
ob->size[2] = 1.0f;
+ if (clear_delta) ob->dscale[2] = 1.0f;
}
}
@@ -210,10 +237,12 @@ static void object_clear_scale(Object *ob)
/* generic exec for clear-transform operators */
static int object_clear_transform_generic_exec(bContext *C, wmOperator *op,
- void (*clear_func)(Object *), const char default_ksName[])
+ void (*clear_func)(Object *, const bool),
+ const char default_ksName[])
{
Scene *scene = CTX_data_scene(C);
KeyingSet *ks;
+ const bool clear_delta = RNA_boolean_get(op->ptr, "clear_delta");
/* sanity checks */
if (ELEM(NULL, clear_func, default_ksName)) {
@@ -231,10 +260,10 @@ static int object_clear_transform_generic_exec(bContext *C, wmOperator *op,
{
if (!(ob->mode & OB_MODE_WEIGHT_PAINT)) {
/* run provided clearing function */
- clear_func(ob);
-
+ clear_func(ob, clear_delta);
+
ED_autokeyframe_object(C, scene, ob, ks);
-
+
/* tag for updates */
DAG_id_tag_update(&ob->id, OB_RECALC_OB);
}
@@ -268,6 +297,11 @@ void OBJECT_OT_location_clear(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+
+ /* properties */
+ ot->prop = RNA_def_boolean(ot->srna, "clear_delta", false, "Clear Delta",
+ "Clear delta location in addition to clearing the normal location transform");
}
static int object_rotation_clear_exec(bContext *C, wmOperator *op)
@@ -288,6 +322,10 @@ void OBJECT_OT_rotation_clear(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_boolean(ot->srna, "clear_delta", false, "Clear Delta",
+ "Clear delta rotation in addition to clearing the normal rotation transform");
}
static int object_scale_clear_exec(bContext *C, wmOperator *op)
@@ -308,6 +346,10 @@ void OBJECT_OT_scale_clear(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_boolean(ot->srna, "clear_delta", false, "Clear Delta",
+ "Clear delta scale in addition to clearing the normal scale transform");
}
/* --------------- */
@@ -391,7 +433,7 @@ static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_l
changed = false;
}
- if (obdata->lib) {
+ if (ID_IS_LINKED_DATABLOCK(obdata)) {
BKE_reportf(reports, RPT_ERROR,
"Cannot apply to library data: Object \"%s\", %s \"%s\", aborting",
ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2);
@@ -792,7 +834,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
if (ob->data == NULL) {
/* special support for dupligroups */
if ((ob->transflag & OB_DUPLIGROUP) && ob->dup_group && (ob->dup_group->id.tag & LIB_TAG_DOIT) == 0) {
- if (ob->dup_group->id.lib) {
+ if (ID_IS_LINKED_DATABLOCK(ob->dup_group)) {
tot_lib_error++;
}
else {
@@ -817,7 +859,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
}
}
}
- else if (((ID *)ob->data)->lib) {
+ else if (ID_IS_LINKED_DATABLOCK(ob->data)) {
tot_lib_error++;
}
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index 414cc476be5..bd016b7fcfb 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -2447,8 +2447,8 @@ static int vertex_group_poll(bContext *C)
Object *ob = ED_object_context(C);
ID *data = (ob) ? ob->data : NULL;
- return (ob && !ob->id.lib &&
- data && !data->lib &&
+ return (ob && !ID_IS_LINKED_DATABLOCK(ob) &&
+ data && !ID_IS_LINKED_DATABLOCK(data) &&
OB_TYPE_SUPPORT_VGROUP(ob->type) &&
ob->defbase.first);
}
@@ -2457,7 +2457,8 @@ static int vertex_group_supported_poll(bContext *C)
{
Object *ob = ED_object_context(C);
ID *data = (ob) ? ob->data : NULL;
- return (ob && !ob->id.lib && OB_TYPE_SUPPORT_VGROUP(ob->type) && data && !data->lib);
+ return (ob && !ID_IS_LINKED_DATABLOCK(ob) && OB_TYPE_SUPPORT_VGROUP(ob->type) &&
+ data && !ID_IS_LINKED_DATABLOCK(data));
}
static int vertex_group_mesh_poll(bContext *C)
@@ -2465,8 +2466,8 @@ static int vertex_group_mesh_poll(bContext *C)
Object *ob = ED_object_context(C);
ID *data = (ob) ? ob->data : NULL;
- return (ob && !ob->id.lib &&
- data && !data->lib &&
+ return (ob && !ID_IS_LINKED_DATABLOCK(ob) &&
+ data && !ID_IS_LINKED_DATABLOCK(data) &&
ob->type == OB_MESH &&
ob->defbase.first);
}
@@ -2475,7 +2476,7 @@ static int UNUSED_FUNCTION(vertex_group_mesh_supported_poll)(bContext *C)
{
Object *ob = ED_object_context(C);
ID *data = (ob) ? ob->data : NULL;
- return (ob && !ob->id.lib && ob->type == OB_MESH && data && !data->lib);
+ return (ob && !ID_IS_LINKED_DATABLOCK(ob) && ob->type == OB_MESH && data && !ID_IS_LINKED_DATABLOCK(data));
}
@@ -2484,7 +2485,7 @@ static int UNUSED_FUNCTION(vertex_group_poll_edit) (bContext *C)
Object *ob = ED_object_context(C);
ID *data = (ob) ? ob->data : NULL;
- if (!(ob && !ob->id.lib && data && !data->lib))
+ if (!(ob && !ID_IS_LINKED_DATABLOCK(ob) && data && !ID_IS_LINKED_DATABLOCK(data)))
return 0;
return BKE_object_is_in_editmode_vgroup(ob);
@@ -2496,7 +2497,7 @@ static int vertex_group_vert_select_poll_ex(bContext *C, const short ob_type_fla
Object *ob = ED_object_context(C);
ID *data = (ob) ? ob->data : NULL;
- if (!(ob && !ob->id.lib && data && !data->lib))
+ if (!(ob && !ID_IS_LINKED_DATABLOCK(ob) && data && !ID_IS_LINKED_DATABLOCK(data)))
return false;
if (ob_type_flag && (((1 << ob->type) & ob_type_flag)) == 0) {
@@ -2536,7 +2537,7 @@ static int vertex_group_vert_select_unlocked_poll(bContext *C)
Object *ob = ED_object_context(C);
ID *data = (ob) ? ob->data : NULL;
- if (!(ob && !ob->id.lib && data && !data->lib))
+ if (!(ob && !ID_IS_LINKED_DATABLOCK(ob) && data && !ID_IS_LINKED_DATABLOCK(data)))
return 0;
if (!(BKE_object_is_in_editmode_vgroup(ob) ||
@@ -2559,7 +2560,7 @@ static int vertex_group_vert_select_mesh_poll(bContext *C)
Object *ob = ED_object_context(C);
ID *data = (ob) ? ob->data : NULL;
- if (!(ob && !ob->id.lib && data && !data->lib))
+ if (!(ob && !ID_IS_LINKED_DATABLOCK(ob) && data && !ID_IS_LINKED_DATABLOCK(data)))
return 0;
/* only difference to #vertex_group_vert_select_poll */
@@ -2748,7 +2749,7 @@ static int vertex_group_select_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = ED_object_context(C);
- if (!ob || ob->id.lib)
+ if (!ob || ID_IS_LINKED_DATABLOCK(ob))
return OPERATOR_CANCELLED;
vgroup_select_verts(ob, 1);
@@ -3537,8 +3538,10 @@ static int vgroup_sort_name(const void *def_a_ptr, const void *def_b_ptr)
return BLI_natstrcmp(def_a->name, def_b->name);
}
-/* Sorts the weight groups according to the bone hierarchy of the
- associated armature (similar to how bones are ordered in the Outliner) */
+/**
+ * Sorts the weight groups according to the bone hierarchy of the
+ * associated armature (similar to how bones are ordered in the Outliner)
+ */
static void vgroup_sort_bone_hierarchy(Object *ob, ListBase *bonebase)
{
if (bonebase == NULL) {
@@ -3630,7 +3633,8 @@ static int vgroup_move_exec(bContext *C, wmOperator *op)
Object *ob = ED_object_context(C);
bDeformGroup *def;
char *name_array;
- int dir = RNA_enum_get(op->ptr, "direction"), ret;
+ int dir = RNA_enum_get(op->ptr, "direction");
+ int ret = OPERATOR_FINISHED;
def = BLI_findlink(&ob->defbase, ob->actdef - 1);
if (!def) {
@@ -3639,36 +3643,25 @@ static int vgroup_move_exec(bContext *C, wmOperator *op)
name_array = vgroup_init_remap(ob);
- if (dir == 1) { /*up*/
- void *prev = def->prev;
-
- BLI_remlink(&ob->defbase, def);
- BLI_insertlinkbefore(&ob->defbase, prev, def);
- }
- else { /*down*/
- void *next = def->next;
+ if (BLI_listbase_link_move(&ob->defbase, def, dir)) {
+ ret = vgroup_do_remap(ob, name_array, op);
- BLI_remlink(&ob->defbase, def);
- BLI_insertlinkafter(&ob->defbase, next, def);
+ if (ret != OPERATOR_CANCELLED) {
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob);
+ }
}
- ret = vgroup_do_remap(ob, name_array, op);
-
if (name_array) MEM_freeN(name_array);
- if (ret != OPERATOR_CANCELLED) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob);
- }
-
return ret;
}
void OBJECT_OT_vertex_group_move(wmOperatorType *ot)
{
static EnumPropertyItem vgroup_slot_move[] = {
- {1, "UP", 0, "Up", ""},
- {-1, "DOWN", 0, "Down", ""},
+ {-1, "UP", 0, "Up", ""},
+ {1, "DOWN", 0, "Down", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -3684,7 +3677,8 @@ void OBJECT_OT_vertex_group_move(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_enum(ot->srna, "direction", vgroup_slot_move, 0, "Direction", "Direction to move, UP or DOWN");
+ RNA_def_enum(ot->srna, "direction", vgroup_slot_move, 0, "Direction",
+ "Direction to move the active vertex group towards");
}
static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr)
diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c
index a5d2d2c8be7..3d7a45843cc 100644
--- a/source/blender/editors/physics/dynamicpaint_ops.c
+++ b/source/blender/editors/physics/dynamicpaint_ops.c
@@ -350,6 +350,9 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job)
return;
}
+ /* Show progress bar. */
+ *(job->do_update) = true;
+
/* Set frame to start point (also inits modifier data) */
frame = surface->start_frame;
orig_frame = scene->r.cfra;
@@ -357,14 +360,15 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job)
ED_update_for_newframe(job->bmain, scene, 1);
/* Init surface */
- if (!dynamicPaint_createUVSurface(scene, surface)) {
+ if (!dynamicPaint_createUVSurface(scene, surface, job->progress, job->do_update)) {
job->success = 0;
return;
}
/* Loop through selected frames */
for (frame = surface->start_frame; frame <= surface->end_frame; frame++) {
- float progress = (frame - surface->start_frame) / (float)frames;
+ /* The first 10% are for createUVSurface... */
+ const float progress = 0.1f + 0.9f * (frame - surface->start_frame) / (float)frames;
surface->current_frame = frame;
/* If user requested stop, quit baking */
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 3da3a451d66..e22a145b3a6 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -1173,7 +1173,7 @@ static void PE_update_selection(Scene *scene, Object *ob, int useflag)
}
}
- psys_cache_edit_paths(scene, ob, edit, CFRA);
+ psys_cache_edit_paths(scene, ob, edit, CFRA, G.is_rendering);
/* disable update flag */
@@ -1289,7 +1289,7 @@ void PE_update_object(Scene *scene, Object *ob, int useflag)
PE_hide_keys_time(scene, edit, CFRA);
/* regenerate path caches */
- psys_cache_edit_paths(scene, ob, edit, CFRA);
+ psys_cache_edit_paths(scene, ob, edit, CFRA, G.is_rendering);
/* disable update flag */
LOOP_POINTS {
@@ -1634,7 +1634,7 @@ static int select_random_exec(bContext *C, wmOperator *op)
int p;
int k;
- const float randfac = RNA_float_get (op->ptr, "percent") / 100.0f;
+ const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f;
const int seed = WM_operator_properties_select_random_seed_increment_get(op);
const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
RNG *rng;
@@ -2288,7 +2288,7 @@ static int remove_tagged_particles(Object *ob, ParticleSystem *psys, int mirror)
npoint= new_points= MEM_callocN(new_totpart * sizeof(PTCacheEditPoint), "PTCacheEditKey array");
if (ELEM(NULL, new_pars, new_points)) {
- /* allocation error! */
+ /* allocation error! */
if (new_pars)
MEM_freeN(new_pars);
if (new_points)
@@ -4693,7 +4693,7 @@ static int particle_edit_toggle_poll(bContext *C)
if (ob == NULL || ob->type != OB_MESH)
return 0;
- if (!ob->data || ((ID *)ob->data)->lib)
+ if (!ob->data || ID_IS_LINKED_DATABLOCK(ob->data))
return 0;
if (CTX_data_edit_object(C))
return 0;
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index 1297133e1a2..4a4474868a2 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -195,7 +195,7 @@ static int new_particle_settings_exec(bContext *C, wmOperator *UNUSED(op))
/* add or copy particle setting */
if (psys->part)
- part= BKE_particlesettings_copy(psys->part);
+ part= BKE_particlesettings_copy(bmain, psys->part);
else
part= psys_new_settings("ParticleSettings", bmain);
@@ -697,6 +697,9 @@ static bool remap_hair_emitter(Scene *scene, Object *ob, ParticleSystem *psys,
dm = target_psmd->dm_deformed;
}
target_dm = target_psmd->dm_final;
+ if (dm == NULL) {
+ return false;
+ }
/* don't modify the original vertices */
dm = CDDM_copy(dm);
@@ -974,7 +977,7 @@ static void remove_particle_systems_from_object(Object *ob_to)
if (ob_to->type != OB_MESH)
return;
- if (!ob_to->data || ((ID *)ob_to->data)->lib)
+ if (!ob_to->data || ID_IS_LINKED_DATABLOCK(ob_to->data))
return;
for (md = ob_to->modifiers.first; md; md = md_next) {
@@ -993,7 +996,13 @@ static void remove_particle_systems_from_object(Object *ob_to)
}
/* single_psys_from is optional, if NULL all psys of ob_from are copied */
-static bool copy_particle_systems_to_object(Scene *scene, Object *ob_from, ParticleSystem *single_psys_from, Object *ob_to, int space)
+static bool copy_particle_systems_to_object(Main *bmain,
+ Scene *scene,
+ Object *ob_from,
+ ParticleSystem *single_psys_from,
+ Object *ob_to,
+ int space,
+ bool duplicate_settings)
{
ModifierData *md;
ParticleSystem *psys_start = NULL, *psys, *psys_from;
@@ -1004,7 +1013,7 @@ static bool copy_particle_systems_to_object(Scene *scene, Object *ob_from, Parti
if (ob_to->type != OB_MESH)
return false;
- if (!ob_to->data || ((ID *)ob_to->data)->lib)
+ if (!ob_to->data || ID_IS_LINKED_DATABLOCK(ob_to->data))
return false;
/* For remapping we need a valid DM.
@@ -1070,6 +1079,11 @@ static bool copy_particle_systems_to_object(Scene *scene, Object *ob_from, Parti
if (psys_from->edit)
copy_particle_edit(scene, ob_to, psys, psys_from);
+
+ if (duplicate_settings) {
+ id_us_min(&psys->part->id);
+ psys->part = BKE_particlesettings_copy(bmain, psys->part);
+ }
}
MEM_freeN(tmp_psys);
@@ -1097,8 +1111,9 @@ static bool copy_particle_systems_to_object(Scene *scene, Object *ob_from, Parti
BLI_assert(false);
break;
}
-
- remap_hair_emitter(scene, ob_from, psys_from, ob_to, psys, psys->edit, from_mat, to_mat, psys_from->flag & PSYS_GLOBAL_HAIR, psys->flag & PSYS_GLOBAL_HAIR);
+ if (ob_from != ob_to) {
+ remap_hair_emitter(scene, ob_from, psys_from, ob_to, psys, psys->edit, from_mat, to_mat, psys_from->flag & PSYS_GLOBAL_HAIR, psys->flag & PSYS_GLOBAL_HAIR);
+ }
/* tag for recalc */
// psys->recalc |= PSYS_RECALC_RESET;
@@ -1130,6 +1145,7 @@ static int copy_particle_systems_exec(bContext *C, wmOperator *op)
const int space = RNA_enum_get(op->ptr, "space");
const bool remove_target_particles = RNA_boolean_get(op->ptr, "remove_target_particles");
const bool use_active = RNA_boolean_get(op->ptr, "use_active");
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob_from = ED_object_active_context(C);
ParticleSystem *psys_from = use_active ? CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data : NULL;
@@ -1145,7 +1161,7 @@ static int copy_particle_systems_exec(bContext *C, wmOperator *op)
remove_particle_systems_from_object(ob_to);
changed = true;
}
- if (copy_particle_systems_to_object(scene, ob_from, psys_from, ob_to, space))
+ if (copy_particle_systems_to_object(bmain, scene, ob_from, psys_from, ob_to, space, false))
changed = true;
else
fail++;
@@ -1187,3 +1203,42 @@ void PARTICLE_OT_copy_particle_systems(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "remove_target_particles", true, "Remove Target Particles", "Remove particle systems on the target objects");
RNA_def_boolean(ot->srna, "use_active", false, "Use Active", "Use the active particle system from the context");
}
+
+static int duplicate_particle_systems_poll(bContext *C)
+{
+ if (!ED_operator_object_active_editable(C)) {
+ return false;
+ }
+ Object *ob = ED_object_active_context(C);
+ if (BLI_listbase_is_empty(&ob->particlesystem)) {
+ return false;
+ }
+ return true;
+}
+
+static int duplicate_particle_systems_exec(bContext *C, wmOperator *op)
+{
+ const bool duplicate_settings = RNA_boolean_get(op->ptr, "use_duplicate_settings");
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = ED_object_active_context(C);
+ ParticleSystem *psys = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data;
+ copy_particle_systems_to_object(CTX_data_main(C), scene, ob, psys, ob,
+ PAR_COPY_SPACE_OBJECT, duplicate_settings);
+ return OPERATOR_FINISHED;
+}
+
+void PARTICLE_OT_duplicate_particle_system(wmOperatorType *ot)
+{
+ ot->name = "Duplicate Particle Systems";
+ ot->description = "Duplicate particle system within the active object";
+ ot->idname = "PARTICLE_OT_duplicate_particle_system";
+
+ ot->poll = duplicate_particle_systems_poll;
+ ot->exec = duplicate_particle_systems_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "use_duplicate_settings", false, "Duplicate Settings",
+ "Duplicate settings as well, so new particle system uses own settings");
+}
diff --git a/source/blender/editors/physics/physics_intern.h b/source/blender/editors/physics/physics_intern.h
index 361c058647a..6b6df15e987 100644
--- a/source/blender/editors/physics/physics_intern.h
+++ b/source/blender/editors/physics/physics_intern.h
@@ -75,6 +75,7 @@ void PARTICLE_OT_target_move_down(struct wmOperatorType *ot);
void PARTICLE_OT_connect_hair(struct wmOperatorType *ot);
void PARTICLE_OT_disconnect_hair(struct wmOperatorType *ot);
void PARTICLE_OT_copy_particle_systems(struct wmOperatorType *ot);
+void PARTICLE_OT_duplicate_particle_system(struct wmOperatorType *ot);
void PARTICLE_OT_dupliob_copy(struct wmOperatorType *ot);
void PARTICLE_OT_dupliob_remove(struct wmOperatorType *ot);
diff --git a/source/blender/editors/physics/physics_ops.c b/source/blender/editors/physics/physics_ops.c
index 5074a41ad20..7ba4b2be43b 100644
--- a/source/blender/editors/physics/physics_ops.c
+++ b/source/blender/editors/physics/physics_ops.c
@@ -83,6 +83,7 @@ static void operatortypes_particle(void)
WM_operatortype_append(PARTICLE_OT_connect_hair);
WM_operatortype_append(PARTICLE_OT_disconnect_hair);
WM_operatortype_append(PARTICLE_OT_copy_particle_systems);
+ WM_operatortype_append(PARTICLE_OT_duplicate_particle_system);
WM_operatortype_append(PARTICLE_OT_dupliob_copy);
WM_operatortype_append(PARTICLE_OT_dupliob_remove);
diff --git a/source/blender/editors/physics/rigidbody_constraint.c b/source/blender/editors/physics/rigidbody_constraint.c
index f95599592b2..1bfc162a331 100644
--- a/source/blender/editors/physics/rigidbody_constraint.c
+++ b/source/blender/editors/physics/rigidbody_constraint.c
@@ -41,6 +41,7 @@
#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_group.h"
+#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_rigidbody.h"
@@ -70,7 +71,7 @@ static int ED_operator_rigidbody_con_active_poll(bContext *C)
}
-bool ED_rigidbody_constraint_add(Scene *scene, Object *ob, int type, ReportList *reports)
+bool ED_rigidbody_constraint_add(Main *bmain, Scene *scene, Object *ob, int type, ReportList *reports)
{
RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
@@ -81,7 +82,7 @@ bool ED_rigidbody_constraint_add(Scene *scene, Object *ob, int type, ReportList
}
/* create constraint group if it doesn't already exits */
if (rbw->constraints == NULL) {
- rbw->constraints = BKE_group_add(G.main, "RigidBodyConstraints");
+ rbw->constraints = BKE_group_add(bmain, "RigidBodyConstraints");
}
/* make rigidbody constraint settings */
ob->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, ob, type);
@@ -90,11 +91,12 @@ bool ED_rigidbody_constraint_add(Scene *scene, Object *ob, int type, ReportList
/* add constraint to rigid body constraint group */
BKE_group_object_add(rbw->constraints, ob, scene, NULL);
+ DAG_relations_tag_update(bmain);
DAG_id_tag_update(&ob->id, OB_RECALC_OB);
return true;
}
-void ED_rigidbody_constraint_remove(Scene *scene, Object *ob)
+void ED_rigidbody_constraint_remove(Main *bmain, Scene *scene, Object *ob)
{
RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
@@ -102,6 +104,7 @@ void ED_rigidbody_constraint_remove(Scene *scene, Object *ob)
if (rbw)
BKE_group_object_unlink(rbw->constraints, ob, scene, NULL);
+ DAG_relations_tag_update(bmain);
DAG_id_tag_update(&ob->id, OB_RECALC_OB);
}
@@ -112,6 +115,7 @@ void ED_rigidbody_constraint_remove(Scene *scene, Object *ob)
static int rigidbody_con_add_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
Object *ob = (scene) ? OBACT : NULL;
@@ -124,7 +128,7 @@ static int rigidbody_con_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
/* apply to active object */
- changed = ED_rigidbody_constraint_add(scene, ob, type, op->reports);
+ changed = ED_rigidbody_constraint_add(bmain, scene, ob, type, op->reports);
if (changed) {
/* send updates */
@@ -160,6 +164,7 @@ void RIGIDBODY_OT_constraint_add(wmOperatorType *ot)
static int rigidbody_con_remove_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob = (scene) ? OBACT : NULL;
@@ -173,7 +178,7 @@ static int rigidbody_con_remove_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
else {
- ED_rigidbody_constraint_remove(scene, ob);
+ ED_rigidbody_constraint_remove(bmain, scene, ob);
}
/* send updates */
diff --git a/source/blender/editors/physics/rigidbody_object.c b/source/blender/editors/physics/rigidbody_object.c
index 26d8af82b2d..30597d95497 100644
--- a/source/blender/editors/physics/rigidbody_object.c
+++ b/source/blender/editors/physics/rigidbody_object.c
@@ -46,6 +46,7 @@
#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_group.h"
+#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_rigidbody.h"
@@ -87,7 +88,7 @@ static int ED_operator_rigidbody_add_poll(bContext *C)
/* ----------------- */
-bool ED_rigidbody_object_add(Scene *scene, Object *ob, int type, ReportList *reports)
+bool ED_rigidbody_object_add(Main *bmain, Scene *scene, Object *ob, int type, ReportList *reports)
{
RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
@@ -107,7 +108,7 @@ bool ED_rigidbody_object_add(Scene *scene, Object *ob, int type, ReportList *rep
scene->rigidbody_world = rbw;
}
if (rbw->group == NULL) {
- rbw->group = BKE_group_add(G.main, "RigidBodyWorld");
+ rbw->group = BKE_group_add(bmain, "RigidBodyWorld");
}
/* make rigidbody object settings */
@@ -120,12 +121,13 @@ bool ED_rigidbody_object_add(Scene *scene, Object *ob, int type, ReportList *rep
/* add object to rigid body group */
BKE_group_object_add(rbw->group, ob, scene, NULL);
+ DAG_relations_tag_update(bmain);
DAG_id_tag_update(&ob->id, OB_RECALC_OB);
return true;
}
-void ED_rigidbody_object_remove(Scene *scene, Object *ob)
+void ED_rigidbody_object_remove(Main *bmain, Scene *scene, Object *ob)
{
RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
@@ -133,6 +135,7 @@ void ED_rigidbody_object_remove(Scene *scene, Object *ob)
if (rbw)
BKE_group_object_unlink(rbw->group, ob, scene, NULL);
+ DAG_relations_tag_update(bmain);
DAG_id_tag_update(&ob->id, OB_RECALC_OB);
}
@@ -143,13 +146,14 @@ void ED_rigidbody_object_remove(Scene *scene, Object *ob)
static int rigidbody_object_add_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob = ED_object_active_context(C);
int type = RNA_enum_get(op->ptr, "type");
bool changed;
/* apply to active object */
- changed = ED_rigidbody_object_add(scene, ob, type, op->reports);
+ changed = ED_rigidbody_object_add(bmain, scene, ob, type, op->reports);
if (changed) {
/* send updates */
@@ -186,13 +190,14 @@ void RIGIDBODY_OT_object_add(wmOperatorType *ot)
static int rigidbody_object_remove_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob = ED_object_active_context(C);
bool changed = false;
/* apply to active object */
if (!ELEM(NULL, ob, ob->rigidbody_object)) {
- ED_rigidbody_object_remove(scene, ob);
+ ED_rigidbody_object_remove(bmain, scene, ob);
changed = true;
}
@@ -232,13 +237,14 @@ void RIGIDBODY_OT_object_remove(wmOperatorType *ot)
static int rigidbody_objects_add_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
int type = RNA_enum_get(op->ptr, "type");
bool changed = false;
/* create rigid body objects and add them to the world's group */
CTX_DATA_BEGIN(C, Object *, ob, selected_objects) {
- changed |= ED_rigidbody_object_add(scene, ob, type, op->reports);
+ changed |= ED_rigidbody_object_add(bmain, scene, ob, type, op->reports);
}
CTX_DATA_END;
@@ -277,6 +283,7 @@ void RIGIDBODY_OT_objects_add(wmOperatorType *ot)
static int rigidbody_objects_remove_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
bool changed = false;
@@ -284,7 +291,7 @@ static int rigidbody_objects_remove_exec(bContext *C, wmOperator *UNUSED(op))
CTX_DATA_BEGIN(C, Object *, ob, selected_objects)
{
if (ob->rigidbody_object) {
- ED_rigidbody_object_remove(scene, ob);
+ ED_rigidbody_object_remove(bmain, scene, ob);
changed = true;
}
}
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index 1203889cf0e..8c5d25ad44d 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -1482,7 +1482,7 @@ static void render_view3d_do(RenderEngine *engine, const bContext *C)
void render_view3d_update(RenderEngine *engine, const bContext *C)
{
/* this shouldn't be needed and causes too many database rebuilds, but we
- * aren't actually tracking updates for all relevent datablocks so this is
+ * aren't actually tracking updates for all relevant datablocks so this is
* a catch-all for updates */
engine->update_flag |= RE_ENGINE_UPDATE_DATABASE;
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index 992b827113d..9d9ccf2f3ba 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -40,9 +40,11 @@
#include "BLI_utildefines.h"
#include "BLI_jitter.h"
#include "BLI_threads.h"
+#include "BLI_task.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
#include "BKE_camera.h"
#include "BKE_context.h"
@@ -73,9 +75,19 @@
#include "GPU_compositing.h"
#include "GPU_framebuffer.h"
-
#include "render_intern.h"
+/* Define this to get timing information. */
+// #undef DEBUG_TIME
+
+#ifdef DEBUG_TIME
+# include "PIL_time.h"
+#endif
+
+// TODO(sergey): Find better approximation of the scheduled frames.
+// For really highres renders it might fail still.
+#define MAX_SCHEDULED_FRAMES 8
+
typedef struct OGLRender {
Main *bmain;
Render *re;
@@ -122,6 +134,19 @@ typedef struct OGLRender {
wmTimer *timer; /* use to check if running modal or not (invoke'd or exec'd)*/
void **movie_ctx_arr;
+
+ TaskScheduler *task_scheduler;
+ TaskPool *task_pool;
+ bool pool_ok;
+ bool is_animation;
+ SpinLock reports_lock;
+ unsigned int num_scheduled_frames;
+ ThreadMutex task_mutex;
+ ThreadCondition task_condition;
+
+#ifdef DEBUG_TIME
+ double time_start;
+#endif
} OGLRender;
/* added because v3d is not always valid */
@@ -181,6 +206,9 @@ static void screen_opengl_views_setup(OGLRender *oglrender)
if (rv_del->rectz)
MEM_freeN(rv_del->rectz);
+ if (rv_del->rect32)
+ MEM_freeN(rv_del->rect32);
+
MEM_freeN(rv_del);
}
}
@@ -193,8 +221,6 @@ static void screen_opengl_views_setup(OGLRender *oglrender)
while (rv) {
srv = BLI_findstring(&rd->views, rv->name, offsetof(SceneRenderView, name));
if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
- if (rv->rectf == NULL)
- rv->rectf = MEM_callocN(sizeof(float) * 4 * oglrender->sizex * oglrender->sizey, "screen_opengl_render_init rect");
rv = rv->prev;
}
else {
@@ -209,6 +235,9 @@ static void screen_opengl_views_setup(OGLRender *oglrender)
if (rv_del->rectz)
MEM_freeN(rv_del->rectz);
+ if (rv_del->rect32)
+ MEM_freeN(rv_del->rect32);
+
MEM_freeN(rv_del);
}
}
@@ -228,12 +257,6 @@ static void screen_opengl_views_setup(OGLRender *oglrender)
}
}
- for (rv = rr->views.first; rv; rv = rv->next) {
- if (rv->rectf == NULL) {
- rv->rectf = MEM_callocN(sizeof(float) * 4 * oglrender->sizex * oglrender->sizey, "screen_opengl_render_init rect");
- }
- }
-
BLI_lock_thread(LOCK_DRAW_IMAGE);
if (!(is_multiview && BKE_scene_multiview_is_stereo3d(rd)))
oglrender->iuser.flag &= ~IMA_SHOW_STEREO;
@@ -265,6 +288,7 @@ static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr)
bool draw_sky = (scene->r.alphamode == R_ADDSKY);
unsigned char *rect = NULL;
const char *viewname = RE_GetActiveRenderView(oglrender->re);
+ ImBuf *ibuf_result = NULL;
if (oglrender->is_sequencer) {
SpaceSeq *sseq = oglrender->sseq;
@@ -348,46 +372,20 @@ static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr)
}
if (ibuf_view) {
- /* steal rect reference from ibuf */
+ ibuf_result = ibuf_view;
rect = (unsigned char *)ibuf_view->rect;
- ibuf_view->mall &= ~IB_rect;
-
- IMB_freeImBuf(ibuf_view);
}
else {
fprintf(stderr, "%s: failed to get buffer, %s\n", __func__, err_out);
}
}
- /* note on color management:
- *
- * OpenGL renders into sRGB colors, but render buffers are expected to be
- * linear So we convert to linear here, so the conversion back to bytes can make it
- * sRGB (or other display space) again, and so that e.g. openexr saving also saves the
- * correct linear float buffer.
- */
-
- if (rect) {
- int profile_to;
- float *rectf = RE_RenderViewGetById(rr, oglrender->view_id)->rectf;
-
- if (BKE_scene_check_color_management_enabled(scene))
- profile_to = IB_PROFILE_LINEAR_RGB;
- else
- profile_to = IB_PROFILE_SRGB;
-
- /* sequencer has got trickier conversion happened above
- * also assume opengl's space matches byte buffer color space */
- IMB_buffer_float_from_byte(rectf, rect,
- profile_to, IB_PROFILE_SRGB, true,
- oglrender->sizex, oglrender->sizey, oglrender->sizex, oglrender->sizex);
-
- /* rr->rectf is now filled with image data */
-
- if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW))
- BKE_image_stamp_buf(scene, camera, NULL, rect, rectf, rr->rectx, rr->recty, 4);
-
- MEM_freeN(rect);
+ if (ibuf_result != NULL) {
+ if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) {
+ BKE_image_stamp_buf(scene, camera, NULL, rect, NULL, rr->rectx, rr->recty, 4);
+ }
+ RE_render_result_rect_from_ibuf(rr, &scene->r, ibuf_result, oglrender->view_id);
+ IMB_freeImBuf(ibuf_result);
}
}
@@ -414,6 +412,104 @@ static void screen_opengl_render_write(OGLRender *oglrender)
else printf("OpenGL Render failed to write '%s'\n", name);
}
+static void addAlphaOverFloat(float dest[4], const float source[4])
+{
+ /* d = s + (1-alpha_s)d*/
+ float mul;
+
+ mul = 1.0f - source[3];
+
+ dest[0] = (mul * dest[0]) + source[0];
+ dest[1] = (mul * dest[1]) + source[1];
+ dest[2] = (mul * dest[2]) + source[2];
+ dest[3] = (mul * dest[3]) + source[3];
+
+}
+
+/* add renderlayer and renderpass for each grease pencil layer for using in composition */
+static void add_gpencil_renderpass(OGLRender *oglrender, RenderResult *rr, RenderView *rv)
+{
+ bGPdata *gpd = oglrender->scene->gpd;
+ Scene *scene = oglrender->scene;
+
+ /* sanity checks */
+ if (gpd == NULL) {
+ return;
+ }
+ if (scene == NULL) {
+ return;
+ }
+ if (BLI_listbase_is_empty(&gpd->layers)) {
+ return;
+ }
+ if (oglrender->v3d != NULL && (oglrender->v3d->flag2 & V3D_SHOW_GPENCIL) == 0) {
+ return;
+ }
+
+ /* save old alpha mode */
+ short oldalphamode = scene->r.alphamode;
+ /* set alpha transparent for gp */
+ scene->r.alphamode = R_ALPHAPREMUL;
+
+ /* saves layer status */
+ short *oldsts = MEM_mallocN(BLI_listbase_count(&gpd->layers) * sizeof(short), "temp_gplayers_flag");
+ int i = 0;
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ oldsts[i] = gpl->flag;
+ ++i;
+ }
+ /* loop all layers to create separate render */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* dont draw layer if hidden */
+ if (gpl->flag & GP_LAYER_HIDE)
+ continue;
+ /* hide all layer except current */
+ for (bGPDlayer *gph = gpd->layers.first; gph; gph = gph->next) {
+ if (gpl != gph) {
+ gph->flag |= GP_LAYER_HIDE;
+ }
+ }
+
+ /* render this gp layer */
+ screen_opengl_render_doit(oglrender, rr);
+
+ /* add RendePass composite */
+ RenderPass *rp = RE_create_gp_pass(rr, gpl->info, rv->name);
+
+ /* copy image data from rectf */
+ // XXX: Needs conversion.
+ unsigned char *src = (unsigned char *)RE_RenderViewGetById(rr, oglrender->view_id)->rect32;
+ float *dest = rp->rect;
+
+ int x, y, rectx, recty;
+ rectx = rr->rectx;
+ recty = rr->recty;
+ for (y = 0; y < recty; y++) {
+ for (x = 0; x < rectx; x++) {
+ unsigned char *pixSrc = src + 4 * (rectx * y + x);
+ if (pixSrc[3] > 0) {
+ float *pixDest = dest + 4 * (rectx * y + x);
+ float float_src[4];
+ srgb_to_linearrgb_uchar4(float_src, pixSrc);
+ addAlphaOverFloat(pixDest, float_src);
+ }
+ }
+ }
+
+ /* back layer status */
+ i = 0;
+ for (bGPDlayer *gph = gpd->layers.first; gph; gph = gph->next) {
+ gph->flag = oldsts[i];
+ ++i;
+ }
+ }
+ /* free memory */
+ MEM_freeN(oldsts);
+
+ /* back default alpha mode */
+ scene->r.alphamode = oldalphamode;
+}
+
static void screen_opengl_render_apply(OGLRender *oglrender)
{
RenderResult *rr;
@@ -449,6 +545,9 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
BLI_assert(view_id < oglrender->views_len);
RE_SetActiveRenderView(oglrender->re, rv->name);
oglrender->view_id = view_id;
+ /* add grease pencil passes */
+ add_gpencil_renderpass(oglrender, rr, rv);
+ /* render composite */
screen_opengl_render_doit(oglrender, rr);
}
@@ -544,6 +643,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
oglrender->cfrao = scene->r.cfra;
oglrender->write_still = is_write_still && !is_animation;
+ oglrender->is_animation = is_animation;
oglrender->views_len = BKE_scene_multiview_num_views_get(&scene->r);
@@ -598,6 +698,35 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
oglrender->mh = NULL;
oglrender->movie_ctx_arr = NULL;
+ if (is_animation) {
+ TaskScheduler *task_scheduler = BLI_task_scheduler_get();
+ if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
+ task_scheduler = BLI_task_scheduler_create(1);
+ oglrender->task_scheduler = task_scheduler;
+ oglrender->task_pool = BLI_task_pool_create_background(task_scheduler,
+ oglrender);
+ BLI_pool_set_num_threads(oglrender->task_pool, 1);
+ }
+ else {
+ oglrender->task_scheduler = NULL;
+ oglrender->task_pool = BLI_task_pool_create(task_scheduler,
+ oglrender);
+ }
+ oglrender->pool_ok = true;
+ BLI_spin_init(&oglrender->reports_lock);
+ }
+ else {
+ oglrender->task_scheduler = NULL;
+ oglrender->task_pool = NULL;
+ }
+ oglrender->num_scheduled_frames = 0;
+ BLI_mutex_init(&oglrender->task_mutex);
+ BLI_condition_init(&oglrender->task_condition);
+
+#ifdef DEBUG_TIME
+ oglrender->time_start = PIL_check_seconds_timer();
+#endif
+
return true;
}
@@ -607,6 +736,22 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
Scene *scene = oglrender->scene;
int i;
+ if (oglrender->is_animation) {
+ BLI_task_pool_work_and_wait(oglrender->task_pool);
+ BLI_task_pool_free(oglrender->task_pool);
+ /* Depending on various things we might or might not use global scheduler. */
+ if (oglrender->task_scheduler != NULL) {
+ BLI_task_scheduler_free(oglrender->task_scheduler);
+ }
+ BLI_spin_end(&oglrender->reports_lock);
+ }
+ BLI_mutex_end(&oglrender->task_mutex);
+ BLI_condition_end(&oglrender->task_condition);
+
+#ifdef DEBUG_TIME
+ printf("Total render time: %f\n", PIL_check_seconds_timer() - oglrender->time_start);
+#endif
+
if (oglrender->mh) {
if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
for (i = 0; i < oglrender->totvideos; i++) {
@@ -701,6 +846,123 @@ static bool screen_opengl_render_anim_initialize(bContext *C, wmOperator *op)
return true;
}
+typedef struct WriteTaskData {
+ RenderResult *rr;
+ int cfra;
+} WriteTaskData;
+
+static void write_result_func(TaskPool * __restrict pool,
+ void *task_data_v,
+ int UNUSED(thread_id))
+{
+ OGLRender *oglrender = (OGLRender *) BLI_task_pool_userdata(pool);
+ WriteTaskData *task_data = (WriteTaskData *) task_data_v;
+ Scene *scene = oglrender->scene;
+ RenderResult *rr = task_data->rr;
+ const bool is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype);
+ const int cfra = task_data->cfra;
+ bool ok;
+ /* Don't attempt to write if we've got an error. */
+ if (!oglrender->pool_ok) {
+ RE_FreeRenderResult(rr);
+ BLI_mutex_lock(&oglrender->task_mutex);
+ oglrender->num_scheduled_frames--;
+ BLI_condition_notify_all(&oglrender->task_condition);
+ BLI_mutex_unlock(&oglrender->task_mutex);
+ return;
+ }
+ /* Construct local thread0safe copy of reports structure which we can
+ * safely pass to the underlying functions.
+ */
+ ReportList reports;
+ BKE_reports_init(&reports, oglrender->reports->flag & ~RPT_PRINT);
+ /* Do actual save logic here, depending on the file format. */
+ if (is_movie) {
+ /* We have to construct temporary scene with proper scene->r.cfra.
+ * This is because underlying calls do not use r.cfra but use scene
+ * for that.
+ */
+ Scene tmp_scene = *scene;
+ tmp_scene.r.cfra = cfra;
+ ok = RE_WriteRenderViewsMovie(&reports,
+ rr,
+ &tmp_scene,
+ &tmp_scene.r,
+ oglrender->mh,
+ oglrender->movie_ctx_arr,
+ oglrender->totvideos,
+ PRVRANGEON != 0);
+ }
+ else {
+ /* TODO(sergey): We can in theory save some CPU ticks here because we
+ * calculate file name again here.
+ */
+ char name[FILE_MAX];
+ BKE_image_path_from_imformat(name,
+ scene->r.pic,
+ oglrender->bmain->name,
+ cfra,
+ &scene->r.im_format,
+ (scene->r.scemode & R_EXTENSION) != 0,
+ true,
+ NULL);
+
+ BKE_render_result_stamp_info(scene, scene->camera, rr, false);
+ ok = RE_WriteRenderViewsImage(NULL, rr, scene, true, name);
+ if (!ok) {
+ BKE_reportf(&reports,
+ RPT_ERROR,
+ "Write error: cannot save %s",
+ name);
+ }
+ }
+ if (reports.list.first != NULL) {
+ BLI_spin_lock(&oglrender->reports_lock);
+ for (Report *report = reports.list.first;
+ report != NULL;
+ report = report->next)
+ {
+ BKE_report(oglrender->reports,
+ report->type,
+ report->message);
+ }
+ BLI_spin_unlock(&oglrender->reports_lock);
+ }
+ if (!ok) {
+ oglrender->pool_ok = false;
+ }
+ RE_FreeRenderResult(rr);
+ BLI_mutex_lock(&oglrender->task_mutex);
+ oglrender->num_scheduled_frames--;
+ BLI_condition_notify_all(&oglrender->task_condition);
+ BLI_mutex_unlock(&oglrender->task_mutex);
+}
+
+static bool schedule_write_result(OGLRender *oglrender, RenderResult *rr)
+{
+ if (!oglrender->pool_ok) {
+ RE_FreeRenderResult(rr);
+ return false;
+ }
+ Scene *scene = oglrender->scene;
+ WriteTaskData *task_data = MEM_mallocN(sizeof(WriteTaskData), "write task data");
+ task_data->rr = rr;
+ task_data->cfra = scene->r.cfra;
+ BLI_mutex_lock(&oglrender->task_mutex);
+ oglrender->num_scheduled_frames++;
+ if (oglrender->num_scheduled_frames > MAX_SCHEDULED_FRAMES) {
+ BLI_condition_wait(&oglrender->task_condition,
+ &oglrender->task_mutex);
+ }
+ BLI_mutex_unlock(&oglrender->task_mutex);
+ BLI_task_pool_push(oglrender->task_pool,
+ write_result_func,
+ task_data,
+ true,
+ TASK_PRIORITY_LOW);
+ return true;
+}
+
static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -733,7 +995,9 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
&scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true, NULL);
if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(name)) {
+ BLI_spin_lock(&oglrender->reports_lock);
BKE_reportf(op->reports, RPT_INFO, "Skipping existing frame \"%s\"", name);
+ BLI_spin_unlock(&oglrender->reports_lock);
ok = true;
goto finally;
}
@@ -761,34 +1025,10 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
/* save to disk */
rr = RE_AcquireResultRead(oglrender->re);
-
- if (is_movie) {
- ok = RE_WriteRenderViewsMovie(oglrender->reports, rr, scene, &scene->r, oglrender->mh,
- oglrender->movie_ctx_arr, oglrender->totvideos, PRVRANGEON != 0);
- if (ok) {
- printf("Append frame %d", scene->r.cfra);
- BKE_reportf(op->reports, RPT_INFO, "Appended frame: %d", scene->r.cfra);
- }
- }
- else {
- BKE_render_result_stamp_info(scene, scene->camera, rr, false);
- ok = RE_WriteRenderViewsImage(op->reports, rr, scene, true, name);
- if (ok) {
- printf("Saved: %s", name);
- BKE_reportf(op->reports, RPT_INFO, "Saved file: %s", name);
- }
- else {
- printf("Write error: cannot save %s\n", name);
- BKE_reportf(op->reports, RPT_ERROR, "Write error: cannot save %s", name);
- }
- }
-
+ RenderResult *new_rr = RE_DuplicateRenderResult(rr);
RE_ReleaseResult(oglrender->re);
-
- /* movie stats prints have no line break */
- printf("\n");
-
+ ok = schedule_write_result(oglrender, new_rr);
finally: /* Step the frame and bail early if needed */
@@ -814,6 +1054,7 @@ static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent
switch (event->type) {
case ESCKEY:
/* cancel */
+ oglrender->pool_ok = false; /* Flag pool for cancel. */
screen_opengl_render_end(C, op->customdata);
return OPERATOR_FINISHED;
case TIMER:
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index f4260a0cd33..87c08dc6583 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -70,6 +70,7 @@
#include "BKE_icons.h"
#include "BKE_lamp.h"
#include "BKE_library.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_node.h"
@@ -525,7 +526,7 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty
BKE_node_preview_init_tree(origwrld->nodetree, sp->sizex, sp->sizey, true);
}
}
-
+
return sce;
}
@@ -830,7 +831,7 @@ static void shader_preview_free(void *customdata)
/* get rid of copied material */
BLI_remlink(&pr_main->mat, sp->matcopy);
- BKE_material_free_ex(sp->matcopy, false);
+ BKE_material_free(sp->matcopy);
properties = IDP_GetProperties((ID *)sp->matcopy, false);
if (properties) {
@@ -862,7 +863,7 @@ static void shader_preview_free(void *customdata)
/* get rid of copied world */
BLI_remlink(&pr_main->world, sp->worldcopy);
- BKE_world_free_ex(sp->worldcopy, true); /* [#32865] - we need to unlink the texture copies, unlike for materials */
+ BKE_world_free(sp->worldcopy);
properties = IDP_GetProperties((ID *)sp->worldcopy, false);
if (properties) {
@@ -1079,13 +1080,19 @@ static void icon_preview_add_size(IconPreview *ip, unsigned int *rect, int sizex
static void icon_preview_startjob_all_sizes(void *customdata, short *stop, short *do_update, float *progress)
{
IconPreview *ip = (IconPreview *)customdata;
- IconPreviewSize *cur_size = ip->sizes.first;
+ IconPreviewSize *cur_size;
const bool use_new_shading = BKE_scene_use_new_shading_nodes(ip->scene);
- while (cur_size) {
+ for (cur_size = ip->sizes.first; cur_size; cur_size = cur_size->next) {
PreviewImage *prv = ip->owner;
+
+ if (prv->tag & PRV_TAG_DEFFERED_DELETE) {
+ /* Non-thread-protected reading is not an issue here. */
+ continue;
+ }
+
ShaderPreview *sp = MEM_callocN(sizeof(ShaderPreview), "Icon ShaderPreview");
- const bool is_render = !prv->use_deferred;
+ const bool is_render = !(prv->tag & PRV_TAG_DEFFERED);
/* construct shader preview from image size and previewcustomdata */
sp->scene = ip->scene;
@@ -1116,8 +1123,6 @@ static void icon_preview_startjob_all_sizes(void *customdata, short *stop, short
common_preview_startjob(sp, stop, do_update, progress);
shader_preview_free(sp);
-
- cur_size = cur_size->next;
}
}
@@ -1146,6 +1151,15 @@ static void icon_preview_endjob(void *customdata)
}
#endif
}
+
+ if (ip->owner) {
+ PreviewImage *prv_img = ip->owner;
+ prv_img->tag &= ~PRV_TAG_DEFFERED_RENDERING;
+ if (prv_img->tag & PRV_TAG_DEFFERED_DELETE) {
+ BLI_assert(prv_img->tag & PRV_TAG_DEFFERED);
+ BKE_previewimg_cached_release_pointer(prv_img);
+ }
+ }
}
static void icon_preview_free(void *customdata)
@@ -1204,9 +1218,17 @@ void ED_preview_icon_job(const bContext *C, void *owner, ID *id, unsigned int *r
icon_preview_add_size(ip, rect, sizex, sizey);
+ /* Special threading hack: warn main code that this preview is being rendered and cannot be freed... */
+ {
+ PreviewImage *prv_img = owner;
+ if (prv_img->tag & PRV_TAG_DEFFERED) {
+ prv_img->tag |= PRV_TAG_DEFFERED_RENDERING;
+ }
+ }
+
/* setup job */
WM_jobs_customdata_set(wm_job, ip, icon_preview_free);
- WM_jobs_timer(wm_job, 0.1, NC_MATERIAL, NC_MATERIAL);
+ WM_jobs_timer(wm_job, 0.1, NC_WINDOW, NC_WINDOW);
WM_jobs_callbacks(wm_job, icon_preview_startjob_all_sizes, NULL, NULL, icon_preview_endjob);
WM_jobs_start(CTX_wm_manager(C), wm_job);
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index 1d20ecf2d99..837573ad175 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -102,7 +102,7 @@ static int material_slot_add_exec(bContext *C, wmOperator *UNUSED(op))
if (!ob)
return OPERATOR_CANCELLED;
- object_add_material_slot(ob);
+ BKE_object_material_slot_add(ob);
if (ob->mode & OB_MODE_TEXTURE_PAINT) {
Scene *scene = CTX_data_scene(C);
@@ -145,7 +145,7 @@ static int material_slot_remove_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- object_remove_material_slot(ob);
+ BKE_object_material_slot_remove(ob);
if (ob->mode & OB_MODE_TEXTURE_PAINT) {
Scene *scene = CTX_data_scene(C);
@@ -449,7 +449,8 @@ void OBJECT_OT_material_slot_move(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_enum(ot->srna, "direction", material_slot_move, 0, "Direction", "Direction to move, UP or DOWN");
+ RNA_def_enum(ot->srna, "direction", material_slot_move, 0, "Direction",
+ "Direction to move the active material towards");
}
/********************** new material operator *********************/
@@ -464,7 +465,7 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
/* add or copy material */
if (ma) {
- ma = BKE_material_copy(ma);
+ ma = BKE_material_copy(bmain, ma);
}
else {
ma = BKE_material_add(bmain, DATA_("Material"));
@@ -518,7 +519,7 @@ static int new_texture_exec(bContext *C, wmOperator *UNUSED(op))
/* add or copy texture */
if (tex) {
- tex = BKE_texture_copy(tex);
+ tex = BKE_texture_copy(bmain, tex);
}
else {
tex = BKE_texture_add(bmain, DATA_("Texture"));
@@ -529,7 +530,7 @@ static int new_texture_exec(bContext *C, wmOperator *UNUSED(op))
if (prop) {
/* when creating new ID blocks, use is already 1, but RNA
- * pointer se also increases user, so this compensates it */
+ * pointer use also increases user, so this compensates it */
id_us_min(&tex->id);
if (ptr.id.data && GS(((ID *)ptr.id.data)->name) == ID_MA &&
@@ -576,7 +577,7 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op))
/* add or copy world */
if (wo) {
- wo = BKE_world_copy(wo);
+ wo = BKE_world_copy(bmain, wo);
}
else {
wo = add_world(bmain, DATA_("World"));
@@ -592,7 +593,7 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op))
if (prop) {
/* when creating new ID blocks, use is already 1, but RNA
- * pointer se also increases user, so this compensates it */
+ * pointer use also increases user, so this compensates it */
id_us_min(&wo->id);
RNA_id_pointer_create(&wo->id, &idptr);
@@ -828,14 +829,10 @@ static int freestyle_module_move_exec(bContext *C, wmOperator *op)
FreestyleModuleConfig *module = ptr.data;
int dir = RNA_enum_get(op->ptr, "direction");
- if (dir == 1) {
- BKE_freestyle_module_move_up(&srl->freestyleConfig, module);
- }
- else {
- BKE_freestyle_module_move_down(&srl->freestyleConfig, module);
+ if (BKE_freestyle_module_move(&srl->freestyleConfig, module, dir)) {
+ DAG_id_tag_update(&scene->id, 0);
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
}
- DAG_id_tag_update(&scene->id, 0);
- WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
return OPERATOR_FINISHED;
}
@@ -843,8 +840,8 @@ static int freestyle_module_move_exec(bContext *C, wmOperator *op)
void SCENE_OT_freestyle_module_move(wmOperatorType *ot)
{
static EnumPropertyItem direction_items[] = {
- {1, "UP", 0, "Up", ""},
- {-1, "DOWN", 0, "Down", ""},
+ {-1, "UP", 0, "Up", ""},
+ {1, "DOWN", 0, "Down", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -861,7 +858,8 @@ void SCENE_OT_freestyle_module_move(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
/* props */
- RNA_def_enum(ot->srna, "direction", direction_items, 0, "Direction", "Direction to move, UP or DOWN");
+ RNA_def_enum(ot->srna, "direction", direction_items, 0, "Direction",
+ "Direction to move the chosen style module towards");
}
static int freestyle_lineset_add_exec(bContext *C, wmOperator *UNUSED(op))
@@ -991,14 +989,10 @@ static int freestyle_lineset_move_exec(bContext *C, wmOperator *op)
SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
int dir = RNA_enum_get(op->ptr, "direction");
- if (dir == 1) {
- FRS_move_active_lineset_up(&srl->freestyleConfig);
+ if (FRS_move_active_lineset(&srl->freestyleConfig, dir)) {
+ DAG_id_tag_update(&scene->id, 0);
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
}
- else {
- FRS_move_active_lineset_down(&srl->freestyleConfig);
- }
- DAG_id_tag_update(&scene->id, 0);
- WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
return OPERATOR_FINISHED;
}
@@ -1006,8 +1000,8 @@ static int freestyle_lineset_move_exec(bContext *C, wmOperator *op)
void SCENE_OT_freestyle_lineset_move(wmOperatorType *ot)
{
static EnumPropertyItem direction_items[] = {
- {1, "UP", 0, "Up", ""},
- {-1, "DOWN", 0, "Down", ""},
+ {-1, "UP", 0, "Up", ""},
+ {1, "DOWN", 0, "Down", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -1024,7 +1018,8 @@ void SCENE_OT_freestyle_lineset_move(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
/* props */
- RNA_def_enum(ot->srna, "direction", direction_items, 0, "Direction", "Direction to move, UP or DOWN");
+ RNA_def_enum(ot->srna, "direction", direction_items, 0, "Direction",
+ "Direction to move the active line set towards");
}
static int freestyle_linestyle_new_exec(bContext *C, wmOperator *op)
@@ -1347,6 +1342,7 @@ static int freestyle_modifier_move_exec(bContext *C, wmOperator *op)
PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_LineStyleModifier);
LineStyleModifier *modifier = ptr.data;
int dir = RNA_enum_get(op->ptr, "direction");
+ bool changed = false;
if (!freestyle_linestyle_check_report(lineset, op->reports)) {
return OPERATOR_CANCELLED;
@@ -1354,23 +1350,26 @@ static int freestyle_modifier_move_exec(bContext *C, wmOperator *op)
switch (freestyle_get_modifier_type(&ptr)) {
case LS_MODIFIER_TYPE_COLOR:
- BKE_linestyle_color_modifier_move(lineset->linestyle, modifier, dir);
+ changed = BKE_linestyle_color_modifier_move(lineset->linestyle, modifier, dir);
break;
case LS_MODIFIER_TYPE_ALPHA:
- BKE_linestyle_alpha_modifier_move(lineset->linestyle, modifier, dir);
+ changed = BKE_linestyle_alpha_modifier_move(lineset->linestyle, modifier, dir);
break;
case LS_MODIFIER_TYPE_THICKNESS:
- BKE_linestyle_thickness_modifier_move(lineset->linestyle, modifier, dir);
+ changed = BKE_linestyle_thickness_modifier_move(lineset->linestyle, modifier, dir);
break;
case LS_MODIFIER_TYPE_GEOMETRY:
- BKE_linestyle_geometry_modifier_move(lineset->linestyle, modifier, dir);
+ changed = BKE_linestyle_geometry_modifier_move(lineset->linestyle, modifier, dir);
break;
default:
BKE_report(op->reports, RPT_ERROR, "The object the data pointer refers to is not a valid modifier");
return OPERATOR_CANCELLED;
}
- DAG_id_tag_update(&lineset->linestyle->id, 0);
- WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle);
+
+ if (changed) {
+ DAG_id_tag_update(&lineset->linestyle->id, 0);
+ WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle);
+ }
return OPERATOR_FINISHED;
}
@@ -1378,8 +1377,8 @@ static int freestyle_modifier_move_exec(bContext *C, wmOperator *op)
void SCENE_OT_freestyle_modifier_move(wmOperatorType *ot)
{
static EnumPropertyItem direction_items[] = {
- {1, "UP", 0, "Up", ""},
- {-1, "DOWN", 0, "Down", ""},
+ {-1, "UP", 0, "Up", ""},
+ {1, "DOWN", 0, "Down", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -1396,7 +1395,8 @@ void SCENE_OT_freestyle_modifier_move(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
/* props */
- RNA_def_enum(ot->srna, "direction", direction_items, 0, "Direction", "Direction to move, UP or DOWN");
+ RNA_def_enum(ot->srna, "direction", direction_items, 0, "Direction",
+ "Direction to move the chosen modifier towards");
}
static int freestyle_stroke_material_create_exec(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 3511480821a..e6bb604d387 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -580,15 +580,20 @@ void ED_region_tag_refresh_ui(ARegion *ar)
void ED_region_tag_redraw_partial(ARegion *ar, const rcti *rct)
{
if (ar && !(ar->do_draw & RGN_DRAWING)) {
- if (!(ar->do_draw & RGN_DRAW)) {
+ if (!(ar->do_draw & (RGN_DRAW | RGN_DRAW_PARTIAL))) {
/* no redraw set yet, set partial region */
ar->do_draw |= RGN_DRAW_PARTIAL;
ar->drawrct = *rct;
}
else if (ar->drawrct.xmin != ar->drawrct.xmax) {
+ BLI_assert((ar->do_draw & RGN_DRAW_PARTIAL) != 0);
/* partial redraw already set, expand region */
BLI_rcti_union(&ar->drawrct, rct);
}
+ else {
+ BLI_assert((ar->do_draw & RGN_DRAW) != 0);
+ /* Else, full redraw is already requested, nothing to do here. */
+ }
}
}
@@ -635,8 +640,8 @@ void ED_area_headerprint(ScrArea *sa, const char *str)
if (ar->regiontype == RGN_TYPE_HEADER) {
if (str) {
if (ar->headerstr == NULL)
- ar->headerstr = MEM_mallocN(256, "headerprint");
- BLI_strncpy(ar->headerstr, str, 256);
+ ar->headerstr = MEM_mallocN(UI_MAX_DRAW_STR, "headerprint");
+ BLI_strncpy(ar->headerstr, str, UI_MAX_DRAW_STR);
}
else if (ar->headerstr) {
MEM_freeN(ar->headerstr);
@@ -1362,9 +1367,12 @@ static void region_subwindow(wmWindow *win, ARegion *ar, bool activate)
static void ed_default_handlers(wmWindowManager *wm, ScrArea *sa, ListBase *handlers, int flag)
{
/* note, add-handler checks if it already exists */
-
+
/* XXX it would be good to have boundbox checks for some of these... */
if (flag & ED_KEYMAP_UI) {
+ wmKeyMap *keymap = WM_keymap_find(wm->defaultconf, "User Interface", 0, 0);
+ WM_event_add_keymap_handler(handlers, keymap);
+
/* user interface widgets */
UI_region_handlers_add(handlers);
}
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index cbf87062955..93bac3f6660 100644
--- a/source/blender/editors/screen/glutil.c
+++ b/source/blender/editors/screen/glutil.c
@@ -327,6 +327,13 @@ float glaGetOneFloat(int param)
return v;
}
+int glaGetOneInt(int param)
+{
+ GLint v;
+ glGetIntegerv(param, &v);
+ return v;
+}
+
void glaRasterPosSafe2f(float x, float y, float known_good_x, float known_good_y)
{
GLubyte dummy = 0;
@@ -579,6 +586,10 @@ void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int fo
draw_h = min_ii(img_h - off_y, ceil((scissor[3] - rast_y) / yzoom));
if (draw_w > 0 && draw_h > 0) {
+
+ int bound_options;
+ GPU_BASIC_SHADER_DISABLE_AND_STORE(bound_options);
+
/* Don't use safe RasterPos (slower) if we can avoid it. */
if (rast_x >= 0 && rast_y >= 0) {
glRasterPos2f(rast_x, rast_y);
@@ -610,6 +621,8 @@ void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int fo
}
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+
+ GPU_BASIC_SHADER_ENABLE_AND_RESTORE(bound_options);
}
}
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index f61ad348501..c165bbfd301 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -85,7 +85,8 @@ const char *screen_context_dir[] = {
"sequences", "selected_sequences", "selected_editable_sequences", /* sequencer */
"gpencil_data", "gpencil_data_owner", /* grease pencil data */
"visible_gpencil_layers", "editable_gpencil_layers", "editable_gpencil_strokes",
- "active_gpencil_layer", "active_gpencil_frame",
+ "active_gpencil_layer", "active_gpencil_frame", "active_gpencil_palette",
+ "active_gpencil_palettecolor", "active_gpencil_brush",
"active_operator",
NULL};
@@ -116,7 +117,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
else if (CTX_data_equals(member, "visible_objects") || CTX_data_equals(member, "visible_bases")) {
const unsigned int lay = context_layers(sc, scene, sa);
- int visible_objects = CTX_data_equals(member, "visible_objects");
+ const bool visible_objects = CTX_data_equals(member, "visible_objects");
for (base = scene->base.first; base; base = base->next) {
if (((base->object->restrictflag & OB_RESTRICT_VIEW) == 0) && (base->lay & lay)) {
@@ -131,7 +132,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
else if (CTX_data_equals(member, "selectable_objects") || CTX_data_equals(member, "selectable_bases")) {
const unsigned int lay = context_layers(sc, scene, sa);
- int selectable_objects = CTX_data_equals(member, "selectable_objects");
+ const bool selectable_objects = CTX_data_equals(member, "selectable_objects");
for (base = scene->base.first; base; base = base->next) {
if (base->lay & lay) {
@@ -148,7 +149,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
else if (CTX_data_equals(member, "selected_objects") || CTX_data_equals(member, "selected_bases")) {
const unsigned int lay = context_layers(sc, scene, sa);
- int selected_objects = CTX_data_equals(member, "selected_objects");
+ const bool selected_objects = CTX_data_equals(member, "selected_objects");
for (base = scene->base.first; base; base = base->next) {
if ((base->flag & SELECT) && (base->lay & lay)) {
@@ -163,7 +164,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
else if (CTX_data_equals(member, "selected_editable_objects") || CTX_data_equals(member, "selected_editable_bases")) {
const unsigned int lay = context_layers(sc, scene, sa);
- int selected_editable_objects = CTX_data_equals(member, "selected_editable_objects");
+ const bool selected_editable_objects = CTX_data_equals(member, "selected_editable_objects");
for (base = scene->base.first; base; base = base->next) {
if ((base->flag & SELECT) && (base->lay & lay)) {
@@ -182,7 +183,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
else if (CTX_data_equals(member, "editable_objects") || CTX_data_equals(member, "editable_bases")) {
const unsigned int lay = context_layers(sc, scene, sa);
- int editable_objects = CTX_data_equals(member, "editable_objects");
+ const bool editable_objects = CTX_data_equals(member, "editable_objects");
/* Visible + Editable, but not necessarily selected */
for (base = scene->base.first; base; base = base->next) {
@@ -201,7 +202,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
else if (CTX_data_equals(member, "visible_bones") || CTX_data_equals(member, "editable_bones")) {
bArmature *arm = (obedit && obedit->type == OB_ARMATURE) ? obedit->data : NULL;
EditBone *ebone, *flipbone = NULL;
- int editable_bones = CTX_data_equals(member, "editable_bones");
+ const bool editable_bones = CTX_data_equals(member, "editable_bones");
if (arm && arm->edbo) {
/* Attention: X-Axis Mirroring is also handled here... */
@@ -243,7 +244,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
else if (CTX_data_equals(member, "selected_bones") || CTX_data_equals(member, "selected_editable_bones")) {
bArmature *arm = (obedit && obedit->type == OB_ARMATURE) ? obedit->data : NULL;
EditBone *ebone, *flipbone = NULL;
- int selected_editable_bones = CTX_data_equals(member, "selected_editable_bones");
+ const bool selected_editable_bones = CTX_data_equals(member, "selected_editable_bones");
if (arm && arm->edbo) {
/* Attention: X-Axis Mirroring is also handled here... */
@@ -466,7 +467,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
if (gpd) {
- bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
if (gpl) {
CTX_data_pointer_set(result, &gpd->id, &RNA_GPencilLayer, gpl);
@@ -474,12 +475,50 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
}
}
+ else if (CTX_data_equals(member, "active_gpencil_palette")) {
+ /* XXX: see comment for gpencil_data case... */
+ bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
+
+ if (gpd) {
+ bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
+
+ if (palette) {
+ CTX_data_pointer_set(result, &gpd->id, &RNA_GPencilPalette, palette);
+ return 1;
+ }
+ }
+ }
+ else if (CTX_data_equals(member, "active_gpencil_palettecolor")) {
+ /* XXX: see comment for gpencil_data case... */
+ bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
+
+ if (gpd) {
+ bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
+
+ if (palette) {
+ bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette);
+ if (palcolor) {
+ CTX_data_pointer_set(result, &gpd->id, &RNA_GPencilPaletteColor, palcolor);
+ return 1;
+ }
+ }
+ }
+ }
+ else if (CTX_data_equals(member, "active_gpencil_brush")) {
+ /* XXX: see comment for gpencil_data case... */
+ bGPDbrush *brush = BKE_gpencil_brush_getactive(scene->toolsettings);
+
+ if (brush) {
+ CTX_data_pointer_set(result, &scene->id, &RNA_GPencilBrush, brush);
+ return 1;
+ }
+ }
else if (CTX_data_equals(member, "active_gpencil_frame")) {
/* XXX: see comment for gpencil_data case... */
bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
if (gpd) {
- bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
if (gpl) {
CTX_data_pointer_set(result, &gpd->id, &RNA_GPencilLayer, gpl->actframe);
@@ -533,6 +572,11 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
for (gps = gpf->strokes.first; gps; gps = gps->next) {
if (ED_gpencil_stroke_can_use_direct(sa, gps)) {
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
+ continue;
+ }
+
CTX_data_list_add(result, &gpd->id, &RNA_GPencilStroke, gps);
}
}
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index 23c6aa37a83..5cd0d33c365 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -45,6 +45,7 @@
#include "BKE_image.h"
#include "BKE_global.h"
#include "BKE_library.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_screen.h"
@@ -1755,7 +1756,9 @@ bool ED_screen_delete_scene(bContext *C, Scene *scene)
ED_screen_set_scene(C, CTX_wm_screen(C), newscene);
- BKE_scene_unlink(bmain, scene, newscene);
+ BKE_libblock_remap(bmain, scene, newscene, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE);
+
+ BKE_libblock_free(bmain, scene);
return true;
}
@@ -1940,6 +1943,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
sc = ED_screen_add(win, oldscreen->scene, newname);
sc->state = state;
sc->redraws_flag = oldscreen->redraws_flag;
+ sc->temp = oldscreen->temp;
/* timer */
sc->animtimer = oldscreen->animtimer;
@@ -2070,7 +2074,16 @@ void ED_screen_animation_timer(bContext *C, int redraws, int refresh, int sync,
sad->refresh = refresh;
sad->flag |= (enable < 0) ? ANIMPLAY_FLAG_REVERSE : 0;
sad->flag |= (sync == 0) ? ANIMPLAY_FLAG_NO_SYNC : (sync == 1) ? ANIMPLAY_FLAG_SYNC : 0;
-
+
+ ScrArea *sa = CTX_wm_area(C);
+
+ char spacetype = -1;
+
+ if (sa)
+ spacetype = sa->spacetype;
+
+ sad->from_anim_edit = (ELEM(spacetype, SPACE_IPO, SPACE_ACTION, SPACE_NLA, SPACE_TIME));
+
screen->animtimer->customdata = sad;
}
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index be421d779eb..860a865466a 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -168,7 +168,7 @@ int ED_operator_screen_mainwinactive(bContext *C)
int ED_operator_scene_editable(bContext *C)
{
Scene *scene = CTX_data_scene(C);
- if (scene && scene->id.lib == NULL)
+ if (scene && !ID_IS_LINKED_DATABLOCK(scene))
return 1;
return 0;
}
@@ -178,7 +178,7 @@ int ED_operator_objectmode(bContext *C)
Scene *scene = CTX_data_scene(C);
Object *obact = CTX_data_active_object(C);
- if (scene == NULL || scene->id.lib)
+ if (scene == NULL || ID_IS_LINKED_DATABLOCK(scene))
return 0;
if (CTX_data_edit_object(C))
return 0;
@@ -279,7 +279,7 @@ int ED_operator_node_editable(bContext *C)
{
SpaceNode *snode = CTX_wm_space_node(C);
- if (snode && snode->edittree && snode->edittree->id.lib == NULL)
+ if (snode && snode->edittree && !ID_IS_LINKED_DATABLOCK(snode->edittree))
return 1;
return 0;
@@ -341,20 +341,20 @@ int ED_operator_object_active(bContext *C)
int ED_operator_object_active_editable(bContext *C)
{
Object *ob = ED_object_active_context(C);
- return ((ob != NULL) && !(ob->id.lib) && !ed_object_hidden(ob));
+ return ((ob != NULL) && !ID_IS_LINKED_DATABLOCK(ob) && !ed_object_hidden(ob));
}
int ED_operator_object_active_editable_mesh(bContext *C)
{
Object *ob = ED_object_active_context(C);
- return ((ob != NULL) && !(ob->id.lib) && !ed_object_hidden(ob) &&
- (ob->type == OB_MESH) && !(((ID *)ob->data)->lib));
+ return ((ob != NULL) && !ID_IS_LINKED_DATABLOCK(ob) && !ed_object_hidden(ob) &&
+ (ob->type == OB_MESH) && !ID_IS_LINKED_DATABLOCK(ob->data));
}
int ED_operator_object_active_editable_font(bContext *C)
{
Object *ob = ED_object_active_context(C);
- return ((ob != NULL) && !(ob->id.lib) && !ed_object_hidden(ob) &&
+ return ((ob != NULL) && !ID_IS_LINKED_DATABLOCK(ob) && !ed_object_hidden(ob) &&
(ob->type == OB_FONT));
}
@@ -2479,7 +2479,7 @@ static void SCREEN_OT_screen_full_area(wmOperatorType *ot)
{
PropertyRNA *prop;
- ot->name = "Toggle Fullscreen Area";
+ ot->name = "Toggle Maximize Area";
ot->description = "Toggle display selected area as fullscreen/maximized";
ot->idname = "SCREEN_OT_screen_full_area";
@@ -3355,24 +3355,24 @@ static int match_area_with_refresh(int spacetype, int refresh)
return 0;
}
-static int match_region_with_redraws(int spacetype, int regiontype, int redraws)
+static int match_region_with_redraws(int spacetype, int regiontype, int redraws, bool from_anim_edit)
{
if (regiontype == RGN_TYPE_WINDOW) {
switch (spacetype) {
case SPACE_VIEW3D:
- if (redraws & TIME_ALL_3D_WIN)
+ if ((redraws & TIME_ALL_3D_WIN) || from_anim_edit)
return 1;
break;
case SPACE_IPO:
case SPACE_ACTION:
case SPACE_NLA:
- if (redraws & TIME_ALL_ANIM_WIN)
+ if ((redraws & TIME_ALL_ANIM_WIN) || from_anim_edit)
return 1;
break;
case SPACE_TIME:
/* if only 1 window or 3d windows, we do timeline too */
- if (redraws & (TIME_ALL_ANIM_WIN | TIME_REGION | TIME_ALL_3D_WIN))
+ if ((redraws & (TIME_ALL_ANIM_WIN | TIME_REGION | TIME_ALL_3D_WIN)) || from_anim_edit)
return 1;
break;
case SPACE_BUTS:
@@ -3380,7 +3380,7 @@ static int match_region_with_redraws(int spacetype, int regiontype, int redraws)
return 1;
break;
case SPACE_SEQ:
- if (redraws & (TIME_SEQ | TIME_ALL_ANIM_WIN))
+ if ((redraws & (TIME_SEQ | TIME_ALL_ANIM_WIN)) || from_anim_edit)
return 1;
break;
case SPACE_NODE:
@@ -3388,11 +3388,11 @@ static int match_region_with_redraws(int spacetype, int regiontype, int redraws)
return 1;
break;
case SPACE_IMAGE:
- if (redraws & TIME_ALL_IMAGE_WIN)
+ if ((redraws & TIME_ALL_IMAGE_WIN) || from_anim_edit)
return 1;
break;
case SPACE_CLIP:
- if (redraws & TIME_CLIPS)
+ if ((redraws & TIME_CLIPS) || from_anim_edit)
return 1;
break;
@@ -3467,7 +3467,7 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
if ((scene->audio.flag & AUDIO_SYNC) &&
(sad->flag & ANIMPLAY_FLAG_REVERSE) == false &&
- finite(time = BKE_sound_sync_scene(scene)))
+ isfinite(time = BKE_sound_sync_scene(scene)))
{
double newfra = (double)time * FPS;
@@ -3572,7 +3572,7 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
if (ar == sad->ar) {
redraw = true;
}
- else if (match_region_with_redraws(sa->spacetype, ar->regiontype, sad->redraws)) {
+ else if (match_region_with_redraws(sa->spacetype, ar->regiontype, sad->redraws, sad->from_anim_edit)) {
redraw = true;
}
@@ -3955,7 +3955,7 @@ static int scene_new_exec(bContext *C, wmOperator *op)
newscene = BKE_scene_add(bmain, DATA_("Scene"));
}
else { /* different kinds of copying */
- newscene = BKE_scene_copy(scene, type);
+ newscene = BKE_scene_copy(bmain, scene, type);
/* these can't be handled in blenkernel currently, so do them here */
if (type == SCE_COPY_LINK_DATA) {
@@ -4174,6 +4174,89 @@ static void SCREEN_OT_region_blend(wmOperatorType *ot)
/* properties */
}
+/* ******************** space context cycling operator ******************** */
+
+/* SCREEN_OT_space_context_cycle direction */
+enum {
+ SPACE_CONTEXT_CYCLE_PREV,
+ SPACE_CONTEXT_CYCLE_NEXT,
+};
+
+static EnumPropertyItem space_context_cycle_direction[] = {
+ {SPACE_CONTEXT_CYCLE_PREV, "PREV", 0, "Previous", ""},
+ {SPACE_CONTEXT_CYCLE_NEXT, "NEXT", 0, "Next", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static int space_context_cycle_poll(bContext *C)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ /* sa might be NULL if called out of window bounds */
+ return (sa && ELEM(sa->spacetype, SPACE_BUTS, SPACE_USERPREF));
+}
+
+/**
+ * Helper to get the correct RNA pointer/property pair for changing
+ * the display context of active space type in \a sa.
+ */
+static void context_cycle_prop_get(
+ bScreen *screen, const ScrArea *sa,
+ PointerRNA *r_ptr, PropertyRNA **r_prop)
+{
+ const char *propname;
+
+ switch (sa->spacetype) {
+ case SPACE_BUTS:
+ RNA_pointer_create(&screen->id, &RNA_SpaceProperties, sa->spacedata.first, r_ptr);
+ propname = "context";
+ break;
+ case SPACE_USERPREF:
+ RNA_pointer_create(NULL, &RNA_UserPreferences, &U, r_ptr);
+ propname = "active_section";
+ break;
+ default:
+ BLI_assert(0);
+ propname = "";
+ }
+
+ *r_prop = RNA_struct_find_property(r_ptr, propname);
+}
+
+static int space_context_cycle_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ const int direction = RNA_enum_get(op->ptr, "direction");
+
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ context_cycle_prop_get(CTX_wm_screen(C), CTX_wm_area(C), &ptr, &prop);
+
+ const int old_context = RNA_property_enum_get(&ptr, prop);
+ const int new_context = RNA_property_enum_step(
+ C, &ptr, prop, old_context,
+ direction == SPACE_CONTEXT_CYCLE_PREV ? -1 : 1);
+ RNA_property_enum_set(&ptr, prop, new_context);
+ RNA_property_update(C, &ptr, prop);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCREEN_OT_space_context_cycle(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Cycle Space Context";
+ ot->description = "Cycle through the editor context by activating the next/previous one";
+ ot->idname = "SCREEN_OT_space_context_cycle";
+
+ /* api callbacks */
+ ot->invoke = space_context_cycle_invoke;
+ ot->poll = space_context_cycle_poll;
+
+ ot->flag = 0;
+
+ RNA_def_enum(ot->srna, "direction", space_context_cycle_direction, SPACE_CONTEXT_CYCLE_NEXT, "Direction",
+ "Direction to cycle through");
+}
+
/* **************** Assigning operatortypes to global list, adding handlers **************** */
@@ -4209,6 +4292,7 @@ void ED_operatortypes_screen(void)
WM_operatortype_append(SCREEN_OT_screencast);
WM_operatortype_append(SCREEN_OT_userpref_show);
WM_operatortype_append(SCREEN_OT_region_blend);
+ WM_operatortype_append(SCREEN_OT_space_context_cycle);
/*frame changes*/
WM_operatortype_append(SCREEN_OT_frame_offset);
@@ -4331,7 +4415,12 @@ void ED_keymap_screen(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "SCREEN_OT_screenshot", F3KEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "SCREEN_OT_screencast", F3KEY, KM_PRESS, KM_ALT, 0);
-
+
+ kmi = WM_keymap_add_item(keymap, "SCREEN_OT_space_context_cycle", TABKEY, KM_PRESS, KM_CTRL, 0);
+ RNA_enum_set(kmi->ptr, "direction", SPACE_CONTEXT_CYCLE_NEXT);
+ kmi = WM_keymap_add_item(keymap, "SCREEN_OT_space_context_cycle", TABKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
+ RNA_enum_set(kmi->ptr, "direction", SPACE_CONTEXT_CYCLE_PREV);
+
/* tests */
WM_keymap_add_item(keymap, "SCREEN_OT_region_quadview", QKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_history", F3KEY, KM_PRESS, 0, 0);
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index e4e9976c10d..53c11e2a6a9 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -1016,7 +1016,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
translation[1] = y;
outline_alpha = 0.5;
outline_col = brush->add_col;
- final_radius = BKE_brush_size_get(scene, brush) * zoomx;
+ final_radius = (BKE_brush_size_get(scene, brush) * zoomx);
/* don't calculate rake angles while a stroke is active because the rake variables are global and
* we may get interference with the stroke itself. For line strokes, such interference is visible */
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index 4dd521e53ef..bf344e1f721 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -36,15 +36,12 @@
#include "MEM_guardedalloc.h"
-#ifdef WIN32
-# include "BLI_winstuff.h"
-#endif
-
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_threads.h"
+#include "BLT_translation.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -64,6 +61,7 @@
#include "BKE_paint.h"
#include "BKE_texture.h"
+#include "UI_interface.h"
#include "UI_view2d.h"
#include "ED_image.h"
@@ -403,7 +401,7 @@ static void image_undo_end(void)
UndoImageTile *tmp_tile = tile->next;
deallocsize += allocsize * ((tile->use_float) ? sizeof(float) : sizeof(char));
MEM_freeN(tile->rect.pt);
- BLI_freelinkN (lb, tile);
+ BLI_freelinkN(lb, tile);
tile = tmp_tile;
}
else {
@@ -1171,20 +1169,17 @@ typedef struct {
static void sample_color_update_header(SampleColorData *data, bContext *C)
{
-#define HEADER_LENGTH 150
- char msg[HEADER_LENGTH];
+ char msg[UI_MAX_DRAW_STR];
ScrArea *sa = CTX_wm_area(C);
if (sa) {
- BLI_snprintf(msg, HEADER_LENGTH,
- "Sample color for %s",
+ BLI_snprintf(msg, sizeof(msg),
+ IFACE_("Sample color for %s"),
!data->sample_palette ?
- "Brush. Use Left Click to sample for palette instead" :
- "Palette. Use Left Click to sample more colors");
+ IFACE_("Brush. Use Left Click to sample for palette instead") :
+ IFACE_("Palette. Use Left Click to sample more colors"));
ED_area_headerprint(sa, msg);
}
-
-#undef HEADER_LENGTH
}
static int sample_color_exec(bContext *C, wmOperator *op)
@@ -1347,7 +1342,7 @@ static int texture_paint_toggle_poll(bContext *C)
Object *ob = CTX_data_active_object(C);
if (ob == NULL || ob->type != OB_MESH)
return 0;
- if (!ob->data || ((ID *)ob->data)->lib)
+ if (!ob->data || ID_IS_LINKED_DATABLOCK(ob->data))
return 0;
if (CTX_data_edit_object(C))
return 0;
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index 080bd5b73c7..9474a46d716 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -1126,8 +1126,8 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsign
/* blend into canvas */
for (a = 0; a < tot; a++) {
ED_imapaint_dirty_region(s->image, s->canvas,
- region[a].destx, region[a].desty,
- region[a].width, region[a].height, true);
+ region[a].destx, region[a].desty,
+ region[a].width, region[a].height, true);
if (s->do_masking) {
/* masking, find original pixels tiles from undo buffer to composite over */
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index d273f8320a1..f5d115442c6 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -183,8 +183,8 @@ BLI_INLINE unsigned char f_to_char(const float val)
/* to avoid locking in tile initialization */
#define TILE_PENDING SET_INT_IN_POINTER(-1)
-/* This is mainly a convenience struct used so we can keep an array of images we use
- * Thir imbufs, etc, in 1 array, When using threads this array is copied for each thread
+/* This is mainly a convenience struct used so we can keep an array of images we use -
+ * their imbufs, etc, in 1 array, When using threads this array is copied for each thread
* because 'partRedrawRect' and 'touch' values would not be thread safe */
typedef struct ProjPaintImage {
Image *ima;
@@ -202,7 +202,7 @@ typedef struct ProjPaintImage {
*/
typedef struct ProjStrokeHandle {
/* Support for painting from multiple views at once,
- * currently used to impliment summetry painting,
+ * currently used to implement symmetry painting,
* we can assume at least the first is set while painting. */
struct ProjPaintState *ps_views[8];
int ps_views_tot;
@@ -371,6 +371,8 @@ typedef struct ProjPaintState {
*/
const MLoopUV **dm_mloopuv;
const MLoopUV **dm_mloopuv_clone; /* other UV map, use for cloning between layers */
+
+ bool use_colormanagement;
} ProjPaintState;
typedef union pixelPointer {
@@ -717,7 +719,7 @@ static bool project_paint_PickColor(
}
/**
- * Check if 'pt' is infront of the 3 verts on the Z axis (used for screenspace occlusuion test)
+ * Check if 'pt' is infront of the 3 verts on the Z axis (used for screenspace occlusion test)
* \return
* - `0`: no occlusion
* - `-1`: no occlusion but 2D intersection is true
@@ -1623,7 +1625,12 @@ static ProjPixel *project_paint_uvpixel_init(
unsigned char rgba_ub[4];
float rgba[4];
project_face_pixel(lt_other_tri_uv, ibuf_other, w, rgba_ub, NULL);
- srgb_to_linearrgb_uchar4(rgba, rgba_ub);
+ if (ps->use_colormanagement) {
+ srgb_to_linearrgb_uchar4(rgba, rgba_ub);
+ }
+ else {
+ rgba_uchar_to_float(rgba, rgba_ub);
+ }
straight_to_premul_v4_v4(((ProjPixelClone *)projPixel)->clonepx.f, rgba);
}
}
@@ -1632,7 +1639,12 @@ static ProjPixel *project_paint_uvpixel_init(
float rgba[4];
project_face_pixel(lt_other_tri_uv, ibuf_other, w, NULL, rgba);
premul_to_straight_v4(rgba);
- linearrgb_to_srgb_uchar3(((ProjPixelClone *)projPixel)->clonepx.ch, rgba);
+ if (ps->use_colormanagement) {
+ linearrgb_to_srgb_uchar3(((ProjPixelClone *)projPixel)->clonepx.ch, rgba);
+ }
+ else {
+ rgb_float_to_uchar(((ProjPixelClone *)projPixel)->clonepx.ch, rgba);
+ }
((ProjPixelClone *)projPixel)->clonepx.ch[3] = rgba[3] * 255;
}
else { /* char to char */
@@ -2174,7 +2186,7 @@ static void project_bucket_clip_face(
if ((*tot) < 3) {
/* no intersections to speak of, but more probable is that all face is just outside the
- * rectangle and culled due to float precision issues. Since above teste have failed,
+ * rectangle and culled due to float precision issues. Since above tests have failed,
* just dump triangle as is for painting */
*tot = 0;
copy_v2_v2(bucket_bounds_uv[*tot], uv1co); (*tot)++;
@@ -3717,7 +3729,7 @@ static void project_paint_prepare_all_faces(
}
/* tfbase here should be non-null! */
- BLI_assert (mloopuv_base != NULL);
+ BLI_assert(mloopuv_base != NULL);
if (is_face_sel && tpage) {
ProjPaintFaceCoSS coSS;
@@ -4359,7 +4371,12 @@ static void do_projectpaint_draw(
if (ps->is_texbrush) {
mul_v3_v3v3(rgb, texrgb, ps->paint_color_linear);
/* TODO(sergey): Support texture paint color space. */
- linearrgb_to_srgb_v3_v3(rgb, rgb);
+ if (ps->use_colormanagement) {
+ linearrgb_to_srgb_v3_v3(rgb, rgb);
+ }
+ else {
+ copy_v3_v3(rgb, rgb);
+ }
}
else {
copy_v3_v3(rgb, ps->paint_color);
@@ -4957,11 +4974,21 @@ static void paint_proj_stroke_ps(
/* handle gradient and inverted stroke color here */
if (ps->tool == PAINT_TOOL_DRAW) {
paint_brush_color_get(scene, brush, false, ps->mode == BRUSH_STROKE_INVERT, distance, pressure, ps->paint_color, NULL);
- srgb_to_linearrgb_v3_v3(ps->paint_color_linear, ps->paint_color);
+ if (ps->use_colormanagement) {
+ srgb_to_linearrgb_v3_v3(ps->paint_color_linear, ps->paint_color);
+ }
+ else {
+ copy_v3_v3(ps->paint_color_linear, ps->paint_color);
+ }
}
else if (ps->tool == PAINT_TOOL_FILL) {
copy_v3_v3(ps->paint_color, BKE_brush_color_get(scene, brush));
- srgb_to_linearrgb_v3_v3(ps->paint_color_linear, ps->paint_color);
+ if (ps->use_colormanagement) {
+ srgb_to_linearrgb_v3_v3(ps->paint_color_linear, ps->paint_color);
+ }
+ else {
+ copy_v3_v3(ps->paint_color_linear, ps->paint_color);
+ }
}
else if (ps->tool == PAINT_TOOL_MASK) {
ps->stencil_value = brush->weight;
@@ -5112,7 +5139,9 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int
ps->normal_angle_inner__cos = cosf(ps->normal_angle_inner);
ps->dither = settings->imapaint.dither;
-
+
+ ps->use_colormanagement = BKE_scene_check_color_management_enabled(CTX_data_scene(C));
+
return;
}
@@ -5783,7 +5812,7 @@ void PAINT_OT_add_texture_paint_slot(wmOperatorType *ot)
/* properties */
prop = RNA_def_enum(ot->srna, "type", layer_type_items, 0, "Type", "Merge method to use");
RNA_def_property_flag(prop, PROP_HIDDEN);
- RNA_def_string(ot->srna, "name", IMA_DEF_NAME, MAX_ID_NAME - 2, "Name", "Image datablock name");
+ RNA_def_string(ot->srna, "name", IMA_DEF_NAME, MAX_ID_NAME - 2, "Name", "Image data-block name");
prop = RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384);
RNA_def_property_subtype(prop, PROP_PIXEL);
prop = RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384);
@@ -5858,7 +5887,9 @@ static int add_simple_uvs_exec(bContext *C, wmOperator *UNUSED(op))
Mesh *me = ob->data;
bool synch_selection = (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
- BMesh *bm = BM_mesh_create(&bm_mesh_allocsize_default);
+ BMesh *bm = BM_mesh_create(
+ &bm_mesh_allocsize_default,
+ &((struct BMeshCreateParams){.use_toolflags = false,}));
/* turn synch selection off, since we are not in edit mode we need to ensure only the uv flags are tested */
scene->toolsettings->uv_flag &= ~UV_SYNC_SELECTION;
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index b6a7d671882..7e05ab929ae 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -101,6 +101,10 @@ bool ED_wpaint_fill(struct VPaint *wp, struct Object *ob, float paintweight);
bool ED_vpaint_smooth(struct Object *ob);
+typedef void (*VPaintTransform_Callback)(const float col[3], const void *user_data, float r_col[3]);
+
+bool ED_vpaint_color_transform(struct Object *ob, VPaintTransform_Callback vpaint_tx_fn, const void *user_data);
+
void PAINT_OT_weight_paint_toggle(struct wmOperatorType *ot);
void PAINT_OT_weight_paint(struct wmOperatorType *ot);
void PAINT_OT_weight_set(struct wmOperatorType *ot);
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index a47b9a0b936..a4887c579ac 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -37,6 +37,7 @@
#include "BIF_glutil.h"
+#include "BLI_bitmap_draw_2d.h"
#include "BLI_math_matrix.h"
#include "BLI_math_geom.h"
#include "BLI_utildefines.h"
@@ -439,7 +440,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
data.width = data.rect.xmax - data.rect.xmin;
data.px = BLI_BITMAP_NEW(data.width * (data.rect.ymax - data.rect.ymin), __func__);
- fill_poly_v2i_n(
+ BLI_bitmap_draw_2d_poly_v2i_n(
data.rect.xmin, data.rect.ymin, data.rect.xmax, data.rect.ymax,
mcords, mcords_tot,
mask_lasso_px_cb, &data);
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index da7667c775e..f88b64129e7 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -69,7 +69,7 @@ static int brush_add_exec(bContext *C, wmOperator *UNUSED(op))
PaintMode mode = BKE_paintmode_get_active_from_context(C);
if (br)
- br = BKE_brush_copy(br);
+ br = BKE_brush_copy(bmain, br);
else
br = BKE_brush_add(bmain, "Brush", BKE_paint_object_mode_from_paint_mode(mode));
@@ -315,6 +315,241 @@ static void PAINT_OT_vertex_color_smooth(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+/** \name Vertex Color Transformations
+ * \{ */
+
+struct VPaintTx_BrightContrastData {
+ /* pre-calculated */
+ float gain;
+ float offset;
+};
+
+static void vpaint_tx_brightness_contrast(const float col[3], const void *user_data, float r_col[3])
+{
+ const struct VPaintTx_BrightContrastData *data = user_data;
+
+ for (int i = 0; i < 3; i++) {
+ r_col[i] = data->gain * col[i] + data->offset;
+ }
+}
+
+static int vertex_color_brightness_contrast_exec(bContext *C, wmOperator *op)
+{
+ Object *obact = CTX_data_active_object(C);
+
+ float gain, offset;
+ {
+ float brightness = RNA_float_get(op->ptr, "brightness");
+ float contrast = RNA_float_get(op->ptr, "contrast");
+ brightness /= 100.0f;
+ float delta = contrast / 200.0f;
+ gain = 1.0f - delta * 2.0f;
+ /*
+ * The algorithm is by Werner D. Streidt
+ * (http://visca.com/ffactory/archives/5-99/msg00021.html)
+ * Extracted of OpenCV demhist.c
+ */
+ if (contrast > 0) {
+ gain = 1.0f / ((gain != 0.0f) ? gain : FLT_EPSILON);
+ offset = gain * (brightness - delta);
+ }
+ else {
+ delta *= -1;
+ offset = gain * (brightness + delta);
+ }
+ }
+
+ const struct VPaintTx_BrightContrastData user_data = {
+ .gain = gain,
+ .offset = offset,
+ };
+
+ if (ED_vpaint_color_transform(obact, vpaint_tx_brightness_contrast, &user_data)) {
+ ED_region_tag_redraw(CTX_wm_region(C));
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static void PAINT_OT_vertex_color_brightness_contrast(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Vertex Paint Bright/Contrast";
+ ot->idname = "PAINT_OT_vertex_color_brightness_contrast";
+ ot->description = "Adjust vertex color brightness/contrast";
+
+ /* api callbacks */
+ ot->exec = vertex_color_brightness_contrast_exec;
+ ot->poll = vertex_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* params */
+ const float min = -100, max = +100;
+ prop = RNA_def_float(ot->srna, "brightness", 0.0f, min, max, "Brightness", "", min, max);
+ prop = RNA_def_float(ot->srna, "contrast", 0.0f, min, max, "Contrast", "", min, max);
+ RNA_def_property_ui_range(prop, min, max, 1, 1);
+}
+
+struct VPaintTx_HueSatData {
+ float hue;
+ float sat;
+ float val;
+};
+
+static void vpaint_tx_hsv(const float col[3], const void *user_data, float r_col[3])
+{
+ const struct VPaintTx_HueSatData *data = user_data;
+ float hsv[3];
+ rgb_to_hsv_v(col, hsv);
+
+ hsv[0] += (data->hue - 0.5f);
+ if (hsv[0] > 1.0f) {
+ hsv[0] -= 1.0f;
+ }
+ else if (hsv[0] < 0.0f) {
+ hsv[0] += 1.0f;
+ }
+ hsv[1] *= data->sat;
+ hsv[2] *= data->val;
+
+ hsv_to_rgb_v(hsv, r_col);
+}
+
+static int vertex_color_hsv_exec(bContext *C, wmOperator *op)
+{
+ Object *obact = CTX_data_active_object(C);
+
+ const struct VPaintTx_HueSatData user_data = {
+ .hue = RNA_float_get(op->ptr, "h"),
+ .sat = RNA_float_get(op->ptr, "s"),
+ .val = RNA_float_get(op->ptr, "v"),
+ };
+
+ if (ED_vpaint_color_transform(obact, vpaint_tx_hsv, &user_data)) {
+ ED_region_tag_redraw(CTX_wm_region(C));
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static void PAINT_OT_vertex_color_hsv(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Vertex Paint Hue Saturation Value";
+ ot->idname = "PAINT_OT_vertex_color_hsv";
+ ot->description = "Adjust vertex color HSV values";
+
+ /* api callbacks */
+ ot->exec = vertex_color_hsv_exec;
+ ot->poll = vertex_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* params */
+ RNA_def_float(ot->srna, "h", 0.5f, 0.0f, 1.0f, "Hue", "", 0.0f, 1.0f);
+ RNA_def_float(ot->srna, "s", 1.0f, 0.0f, 2.0f, "Saturation", "", 0.0f, 2.0f);
+ RNA_def_float(ot->srna, "v", 1.0f, 0.0f, 2.0f, "Value", "", 0.0f, 2.0f);
+}
+
+static void vpaint_tx_invert(const float col[3], const void *UNUSED(user_data), float r_col[3])
+{
+ for (int i = 0; i < 3; i++) {
+ r_col[i] = 1.0f - col[i];
+ }
+}
+
+static int vertex_color_invert_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obact = CTX_data_active_object(C);
+
+ if (ED_vpaint_color_transform(obact, vpaint_tx_invert, NULL)) {
+ ED_region_tag_redraw(CTX_wm_region(C));
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static void PAINT_OT_vertex_color_invert(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Vertex Paint Invert";
+ ot->idname = "PAINT_OT_vertex_color_invert";
+ ot->description = "Invert RGB values";
+
+ /* api callbacks */
+ ot->exec = vertex_color_invert_exec;
+ ot->poll = vertex_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+struct VPaintTx_LevelsData {
+ float gain;
+ float offset;
+};
+
+static void vpaint_tx_levels(const float col[3], const void *user_data, float r_col[3])
+{
+ const struct VPaintTx_LevelsData *data = user_data;
+ for (int i = 0; i < 3; i++) {
+ r_col[i] = data->gain * (col[i] + data->offset);
+ }
+}
+
+static int vertex_color_levels_exec(bContext *C, wmOperator *op)
+{
+ Object *obact = CTX_data_active_object(C);
+
+ const struct VPaintTx_LevelsData user_data = {
+ .gain = RNA_float_get(op->ptr, "gain"),
+ .offset = RNA_float_get(op->ptr, "offset"),
+ };
+
+ if (ED_vpaint_color_transform(obact, vpaint_tx_levels, &user_data)) {
+ ED_region_tag_redraw(CTX_wm_region(C));
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static void PAINT_OT_vertex_color_levels(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Vertex Paint Levels";
+ ot->idname = "PAINT_OT_vertex_color_levels";
+ ot->description = "Adjust levels of vertex colors";
+
+ /* api callbacks */
+ ot->exec = vertex_color_levels_exec;
+ ot->poll = vertex_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* params */
+ RNA_def_float(ot->srna, "offset", 0.0f, -1.0f, 1.0f, "Offset", "Value to add to colors", -1.0f, 1.0f);
+ RNA_def_float(ot->srna, "gain", 1.0f, 0.0f, FLT_MAX, "Gain", "Value to multiply colors by", 0.0f, 10.0f);
+}
+
+/** \} */
+
+
static int brush_reset_exec(bContext *C, wmOperator *UNUSED(op))
{
Paint *paint = BKE_paint_get_active_from_context(C);
@@ -1112,6 +1347,11 @@ void ED_operatortypes_paint(void)
WM_operatortype_append(PAINT_OT_vertex_color_set);
WM_operatortype_append(PAINT_OT_vertex_color_smooth);
+ WM_operatortype_append(PAINT_OT_vertex_color_brightness_contrast);
+ WM_operatortype_append(PAINT_OT_vertex_color_hsv);
+ WM_operatortype_append(PAINT_OT_vertex_color_invert);
+ WM_operatortype_append(PAINT_OT_vertex_color_levels);
+
/* face-select */
WM_operatortype_append(PAINT_OT_face_select_linked);
WM_operatortype_append(PAINT_OT_face_select_linked_pick);
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 65857cccb15..05270dbfa09 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -58,6 +58,8 @@
#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "GPU_basic_shader.h"
+
#include "ED_screen.h"
#include "ED_view3d.h"
@@ -86,7 +88,6 @@ typedef struct PaintStroke {
/* Cached values */
ViewContext vc;
- bglMats mats;
Brush *brush;
UnifiedPaintSettings *ups;
@@ -160,11 +161,11 @@ static void paint_draw_line_cursor(bContext *C, int x, int y, void *customdata)
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
- glEnable(GL_LINE_STIPPLE);
- glLineStipple(3, 0xAAAA);
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ GPU_basic_shader_line_stipple(3, 0xAAAA);
+ GPU_basic_shader_line_width(3.0);
glColor4ub(0, 0, 0, paint->paint_cursor_col[3]);
- glLineWidth(3.0);
if (stroke->constrain_line) {
sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1],
stroke->constrained_pos[0], stroke->constrained_pos[1]);
@@ -175,7 +176,7 @@ static void paint_draw_line_cursor(bContext *C, int x, int y, void *customdata)
}
glColor4ub(255, 255, 255, paint->paint_cursor_col[3]);
- glLineWidth(1.0);
+ GPU_basic_shader_line_width(1.0);
if (stroke->constrain_line) {
sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1],
stroke->constrained_pos[0], stroke->constrained_pos[1]);
@@ -185,7 +186,7 @@ static void paint_draw_line_cursor(bContext *C, int x, int y, void *customdata)
x, y);
}
- glDisable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
@@ -489,31 +490,30 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const float
}
/* Returns zero if no sculpt changes should be made, non-zero otherwise */
-static int paint_smooth_stroke(PaintStroke *stroke, float output[2], float *outpressure,
- const PaintSample *sample, PaintMode mode)
+static bool paint_smooth_stroke(
+ PaintStroke *stroke, const PaintSample *sample, PaintMode mode,
+ float r_mouse[2], float *r_pressure)
{
if (paint_supports_smooth_stroke(stroke->brush, mode)) {
float radius = stroke->brush->smooth_stroke_radius * stroke->zoom_2d;
- float u = stroke->brush->smooth_stroke_factor, v = 1.0f - u;
- float dx = stroke->last_mouse_position[0] - sample->mouse[0];
- float dy = stroke->last_mouse_position[1] - sample->mouse[1];
+ float u = stroke->brush->smooth_stroke_factor;
/* If the mouse is moving within the radius of the last move,
* don't update the mouse position. This allows sharp turns. */
- if (dx * dx + dy * dy < radius * radius)
- return 0;
+ if (len_squared_v2v2(stroke->last_mouse_position, sample->mouse) < SQUARE(radius)) {
+ return false;
+ }
- output[0] = sample->mouse[0] * v + stroke->last_mouse_position[0] * u;
- output[1] = sample->mouse[1] * v + stroke->last_mouse_position[1] * u;
- *outpressure = sample->pressure * v + stroke->last_pressure * u;
+ interp_v2_v2v2(r_mouse, sample->mouse, stroke->last_mouse_position, u);
+ *r_pressure = interpf(sample->pressure, stroke->last_pressure, u);
}
else {
- output[0] = sample->mouse[0];
- output[1] = sample->mouse[1];
- *outpressure = sample->pressure;
+ r_mouse[0] = sample->mouse[0];
+ r_mouse[1] = sample->mouse[1];
+ *r_pressure = sample->pressure;
}
- return 1;
+ return true;
}
static float paint_space_stroke_spacing(const Scene *scene, PaintStroke *stroke, float size_pressure, float spacing_pressure)
@@ -674,8 +674,6 @@ PaintStroke *paint_stroke_new(bContext *C,
float zoomx, zoomy;
view3d_set_viewcontext(C, &stroke->vc);
- if (stroke->vc.v3d)
- view3d_get_transformation(stroke->vc.ar, stroke->vc.rv3d, stroke->vc.obact, &stroke->mats);
stroke->get_location = get_location;
stroke->test_start = test_start;
@@ -1101,12 +1099,14 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
paint_stroke_add_sample(p, stroke, event->mval[0], event->mval[1], pressure);
paint_stroke_sample_average(stroke, &sample_average);
+#ifdef WITH_INPUT_NDOF
/* let NDOF motion pass through to the 3D view so we can paint and rotate simultaneously!
* this isn't perfect... even when an extra MOUSEMOVE is spoofed, the stroke discards it
* since the 2D deltas are zero -- code in this file needs to be updated to use the
* post-NDOF_MOTION MOUSEMOVE */
if (event->type == NDOF_MOTION)
return OPERATOR_PASS_THROUGH;
+#endif
/* one time initialization */
if (!stroke->stroke_init) {
@@ -1156,7 +1156,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (event->val == KM_RELEASE) {
copy_v2_fl2(mouse, event->mval[0], event->mval[1]);
paint_stroke_line_constrain(stroke, mouse);
- paint_stroke_line_end (C, op, stroke, mouse);
+ paint_stroke_line_end(C, op, stroke, mouse);
stroke_done(C, op);
return OPERATOR_FINISHED;
}
@@ -1188,7 +1188,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* airbrush */
((br->flag & BRUSH_AIRBRUSH) && event->type == TIMER && event->customdata == stroke->timer))
{
- if (paint_smooth_stroke(stroke, mouse, &pressure, &sample_average, mode)) {
+ if (paint_smooth_stroke(stroke, &sample_average, mode, mouse, &pressure)) {
if (stroke->stroke_started) {
if (paint_space_stroke_enabled(br, mode)) {
if (paint_space_stroke(C, op, mouse, pressure))
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 15ab4ca04a7..991025a4d5d 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -247,7 +247,7 @@ static bool make_vertexcol(Object *ob) /* single ob */
{
Mesh *me;
- if ((ob->id.lib) ||
+ if (ID_IS_LINKED_DATABLOCK(ob) ||
((me = BKE_mesh_from_object(ob)) == NULL) ||
(me->totpoly == 0) ||
(me->edit_btmesh))
@@ -257,9 +257,7 @@ static bool make_vertexcol(Object *ob) /* single ob */
/* copies from shadedisplist to mcol */
if (!me->mloopcol && me->totloop) {
- if (!me->mloopcol) {
- CustomData_add_layer(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop);
- }
+ CustomData_add_layer(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop);
BKE_mesh_update_customdata_pointers(me, true);
}
@@ -502,6 +500,51 @@ bool ED_vpaint_smooth(Object *ob)
return true;
}
+/**
+ * Apply callback to each vertex of the active vertex color layer.
+ */
+bool ED_vpaint_color_transform(
+ struct Object *ob,
+ VPaintTransform_Callback vpaint_tx_fn,
+ const void *user_data)
+{
+ Mesh *me;
+ const MPoly *mp;
+
+ if (((me = BKE_mesh_from_object(ob)) == NULL) ||
+ (me->mloopcol == NULL && (make_vertexcol(ob) == false)))
+ {
+ return false;
+ }
+
+ const bool do_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ mp = me->mpoly;
+
+ for (int i = 0; i < me->totpoly; i++, mp++) {
+ MLoopCol *lcol = &me->mloopcol[mp->loopstart];
+
+ if (do_face_sel && !(mp->flag & ME_FACE_SEL)) {
+ continue;
+ }
+
+ for (int j = 0; j < mp->totloop; j++, lcol++) {
+ float col[3];
+ rgb_uchar_to_float(col, &lcol->r);
+
+ vpaint_tx_fn(col, user_data, col);
+
+ rgb_float_to_uchar(&lcol->r, col);
+ }
+ }
+
+ /* remove stale me->mcol, will be added later */
+ BKE_mesh_tessface_clear(me);
+
+ DAG_id_tag_update(&me->id, 0);
+
+ return true;
+}
+
/* XXX: should be re-implemented as a vertex/weight paint 'color correct' operator */
#if 0
void vpaint_dogamma(Scene *scene)
@@ -1323,7 +1366,7 @@ static bool do_weight_paint_normalize_all_locked(
/**
* \note same as function above except it does a second pass without active group
- * if nomalize fails with it.
+ * if normalize fails with it.
*/
static void do_weight_paint_normalize_all_locked_try_active(
MDeformVert *dvert, const int defbase_tot, const bool *vgroup_validmap,
@@ -1340,7 +1383,7 @@ static void do_weight_paint_normalize_all_locked_try_active(
* - With 1.0 weight painted into active:
* nonzero locked weight; first pass zeroed out unlocked weight; scale 1 down to fit.
* - With 0.0 weight painted into active:
- * no unlocked groups; first pass did nothing; increaze 0 to fit.
+ * no unlocked groups; first pass did nothing; increase 0 to fit.
*/
do_weight_paint_normalize_all_locked(dvert, defbase_tot, vgroup_validmap, lock_flags);
}
@@ -1796,7 +1839,7 @@ static int paint_poll_test(bContext *C)
Object *ob = CTX_data_active_object(C);
if (ob == NULL || ob->type != OB_MESH)
return 0;
- if (!ob->data || ((ID *)ob->data)->lib)
+ if (!ob->data || ID_IS_LINKED_DATABLOCK(ob->data))
return 0;
if (CTX_data_edit_object(C))
return 0;
@@ -2335,9 +2378,8 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
swap_m4m4(vc->rv3d->persmat, mat);
/* calculate pivot for rotation around seletion if needed */
- if (U.uiflag & USER_ORBIT_SELECTION) {
- paint_last_stroke_update(scene, vc->ar, mval);
- }
+ /* also needed for "View Selected" on last stroke */
+ paint_last_stroke_update(scene, vc->ar, mval);
DAG_id_tag_update(ob->data, 0);
ED_region_tag_redraw(vc->ar);
@@ -2813,9 +2855,8 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
}
/* calculate pivot for rotation around seletion if needed */
- if (U.uiflag & USER_ORBIT_SELECTION) {
- paint_last_stroke_update(scene, vc->ar, mval);
- }
+ /* also needed for "View Selected" on last stroke */
+ paint_last_stroke_update(scene, vc->ar, mval);
ED_region_tag_redraw(vc->ar);
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index c173156de3a..fe0fb3f5035 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -1145,7 +1145,9 @@ static void calc_area_normal_and_center(
/* Return modified brush strength. Includes the direction of the brush, positive
* values pull vertices, negative values push. Uses tablet pressure and a
* special multiplier found experimentally to scale the strength factor. */
-static float brush_strength(const Sculpt *sd, const StrokeCache *cache, const float feather, const UnifiedPaintSettings *ups)
+static float brush_strength(
+ const Sculpt *sd, const StrokeCache *cache,
+ const float feather, const UnifiedPaintSettings *ups)
{
const Scene *scene = cache->vc->scene;
const Brush *brush = BKE_paint_brush((Paint *)&sd->paint);
@@ -1237,7 +1239,7 @@ static float brush_strength(const Sculpt *sd, const StrokeCache *cache, const fl
/* Return a multiplier for brush strength on a particular vertex. */
static float tex_strength(SculptSession *ss, Brush *br,
- const float point[3],
+ const float brush_point[3],
const float len,
const short vno[3],
const float fno[3],
@@ -1249,6 +1251,9 @@ static float tex_strength(SculptSession *ss, Brush *br,
MTex *mtex = &br->mtex;
float avg = 1;
float rgba[4];
+ float point[3];
+
+ sub_v3_v3v3(point, brush_point, cache->plane_offset);
if (!mtex->tex) {
avg = 1;
@@ -3985,7 +3990,9 @@ static void sculpt_init_mirror_clipping(Object *ob, SculptSession *ss)
}
/* Initialize the stroke cache invariants from operator properties */
-static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSession *ss, wmOperator *op, const float mouse[2])
+static void sculpt_update_cache_invariants(
+ bContext *C, Sculpt *sd, SculptSession *ss,
+ wmOperator *op, const float mouse[2])
{
StrokeCache *cache = MEM_callocN(sizeof(StrokeCache), "stroke cache");
Scene *scene = CTX_data_scene(C);
@@ -4448,7 +4455,9 @@ static void sculpt_raycast_detail_cb(PBVHNode *node, void *data_v, float *tmin)
}
}
-static float sculpt_raycast_init(ViewContext *vc, const float mouse[2], float ray_start[3], float ray_end[3], float ray_normal[3], bool original)
+static float sculpt_raycast_init(
+ ViewContext *vc, const float mouse[2],
+ float ray_start[3], float ray_end[3], float ray_normal[3], bool original)
{
float obimat[4][4];
float dist;
@@ -4956,8 +4965,9 @@ void sculpt_dyntopo_node_layers_add(SculptSession *ss)
cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_INT, layer_id);
}
- ss->cd_vert_node_offset = CustomData_get_n_offset(&ss->bm->vdata, CD_PROP_INT,
- cd_node_layer_index - CustomData_get_layer_index(&ss->bm->vdata, CD_PROP_INT));
+ ss->cd_vert_node_offset = CustomData_get_n_offset(
+ &ss->bm->vdata, CD_PROP_INT,
+ cd_node_layer_index - CustomData_get_layer_index(&ss->bm->vdata, CD_PROP_INT));
ss->bm->vdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY;
@@ -4967,8 +4977,9 @@ void sculpt_dyntopo_node_layers_add(SculptSession *ss)
cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->pdata, CD_PROP_INT, layer_id);
}
- ss->cd_face_node_offset = CustomData_get_n_offset(&ss->bm->pdata, CD_PROP_INT,
- cd_node_layer_index - CustomData_get_layer_index(&ss->bm->pdata, CD_PROP_INT));
+ ss->cd_face_node_offset = CustomData_get_n_offset(
+ &ss->bm->pdata, CD_PROP_INT,
+ cd_node_layer_index - CustomData_get_layer_index(&ss->bm->pdata, CD_PROP_INT));
ss->bm->pdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY;
}
@@ -5001,7 +5012,9 @@ void sculpt_dynamic_topology_enable(bContext *C)
BKE_mesh_mselect_clear(me);
/* Create triangles-only BMesh */
- ss->bm = BM_mesh_create(&allocsize);
+ ss->bm = BM_mesh_create(
+ &allocsize,
+ &((struct BMeshCreateParams){.use_toolflags = false,}));
BM_mesh_bm_from_me(
ss->bm, me, (&(struct BMeshFromMeshParams){
@@ -5011,7 +5024,9 @@ void sculpt_dynamic_topology_enable(bContext *C)
BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
sculpt_dyntopo_node_layers_add(ss);
/* make sure the data for existing faces are initialized */
- BM_mesh_normals_update(ss->bm);
+ if (me->totpoly != ss->bm->totface) {
+ BM_mesh_normals_update(ss->bm);
+ }
/* Enable dynamic topology */
me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
@@ -5088,6 +5103,8 @@ static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(o
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
+ WM_cursor_wait(1);
+
if (ss->bm) {
sculpt_undo_push_begin("Dynamic topology disable");
sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_END);
@@ -5100,16 +5117,24 @@ static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(o
}
sculpt_undo_push_end(C);
+ WM_cursor_wait(0);
+
return OPERATOR_FINISHED;
}
+enum eDynTopoWarnFlag {
+ DYNTOPO_WARN_VDATA = (1 << 0),
+ DYNTOPO_WARN_EDATA = (1 << 1),
+ DYNTOPO_WARN_LDATA = (1 << 2),
+ DYNTOPO_WARN_MODIFIER = (1 << 3),
+};
-static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, bool vdata, bool modifiers)
+static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, enum eDynTopoWarnFlag flag)
{
uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Warning!"), ICON_ERROR);
uiLayout *layout = UI_popup_menu_layout(pup);
- if (vdata) {
+ if (flag & (DYNTOPO_WARN_VDATA | DYNTOPO_WARN_EDATA | DYNTOPO_WARN_LDATA)) {
const char *msg_error = TIP_("Vertex Data Detected!");
const char *msg = TIP_("Dyntopo will not preserve vertex colors, UVs, or other customdata");
uiItemL(layout, msg_error, ICON_INFO);
@@ -5117,7 +5142,7 @@ static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, bool vdata, bo
uiItemS(layout);
}
- if (modifiers) {
+ if (flag & DYNTOPO_WARN_MODIFIER) {
const char *msg_error = TIP_("Generative Modifiers Detected!");
const char *msg = TIP_("Keeping the modifiers will increase polycount when returning to object mode");
@@ -5133,33 +5158,35 @@ static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, bool vdata, bo
return OPERATOR_INTERFACE;
}
-
-static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+static enum eDynTopoWarnFlag sculpt_dynamic_topology_check(bContext *C)
{
Object *ob = CTX_data_active_object(C);
Mesh *me = ob->data;
SculptSession *ss = ob->sculpt;
- if (!ss->bm) {
- Scene *scene = CTX_data_scene(C);
- ModifierData *md;
- VirtualModifierData virtualModifierData;
- int i;
- bool vdata = false;
- bool modifiers = false;
-
- for (i = 0; i < CD_NUMTYPES; i++) {
- if (!ELEM(i, CD_MVERT, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX) &&
- (CustomData_has_layer(&me->vdata, i) ||
- CustomData_has_layer(&me->edata, i) ||
- CustomData_has_layer(&me->ldata, i)))
- {
- vdata = true;
- break;
+ Scene *scene = CTX_data_scene(C);
+ enum eDynTopoWarnFlag flag = 0;
+
+ BLI_assert(ss->bm == NULL);
+ UNUSED_VARS_NDEBUG(ss);
+
+ for (int i = 0; i < CD_NUMTYPES; i++) {
+ if (!ELEM(i, CD_MVERT, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX)) {
+ if (CustomData_has_layer(&me->vdata, i)) {
+ flag |= DYNTOPO_WARN_VDATA;
+ }
+ if (CustomData_has_layer(&me->edata, i)) {
+ flag |= DYNTOPO_WARN_EDATA;
+ }
+ if (CustomData_has_layer(&me->ldata, i)) {
+ flag |= DYNTOPO_WARN_LDATA;
}
}
+ }
- md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ {
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
/* exception for shape keys because we can edit those */
for (; md; md = md->next) {
@@ -5167,14 +5194,26 @@ static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, co
if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue;
if (mti->type == eModifierTypeType_Constructive) {
- modifiers = true;
+ flag |= DYNTOPO_WARN_MODIFIER;
break;
}
}
+ }
+
+ return flag;
+}
+
+static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+
+ if (!ss->bm) {
+ enum eDynTopoWarnFlag flag = sculpt_dynamic_topology_check(C);
- if (vdata || modifiers) {
+ if (flag) {
/* The mesh has customdata that will be lost, let the user confirm this is OK */
- return dyntopo_warning_popup(C, op->type, vdata, modifiers);
+ return dyntopo_warning_popup(C, op->type, flag);
}
}
@@ -5249,6 +5288,8 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op))
sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_SYMMETRIZE);
BM_log_before_all_removed(ss->bm, ss->bm_log);
+ BM_mesh_toolflags_set(ss->bm, true);
+
/* Symmetrize and re-triangulate */
BMO_op_callf(ss->bm, BMO_FLAG_DEFAULTS,
"symmetrize input=%avef direction=%i dist=%f",
@@ -5258,6 +5299,8 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op))
/* bisect operator flags edges (keep tags clean for edge queue) */
BM_mesh_elem_hflag_disable_all(ss->bm, BM_EDGE, BM_ELEM_TAG, false);
+ BM_mesh_toolflags_set(ss->bm, false);
+
/* Finish undo */
BM_log_all_added(ss->bm, ss->bm_log);
sculpt_undo_push_end(C);
@@ -5327,6 +5370,9 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
* mode to ensure the undo stack stays in a consistent
* state */
sculpt_dynamic_topology_toggle_exec(C, NULL);
+
+ /* store so we know to re-enable when entering sculpt mode */
+ me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
}
/* Leave sculptmode */
@@ -5340,12 +5386,6 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
/* Enter sculptmode */
ob->mode |= mode_flag;
- /* Remove dynamic-topology flag; this will be enabled if the
- * file was saved with dynamic topology on, but we don't
- * automatically re-enter dynamic-topology mode when loading a
- * file. */
- me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
-
if (flush_recalc)
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
@@ -5399,6 +5439,52 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
BKE_paint_init(scene, ePaintSculpt, PAINT_CURSOR_SCULPT);
paint_cursor_start(C, sculpt_poll_view3d);
+
+ /* Check dynamic-topology flag; re-enter dynamic-topology mode when changing modes,
+ * As long as no data was added that is not supported. */
+ if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
+ const char *message_unsupported = NULL;
+ if (me->totloop != me->totpoly * 3) {
+ message_unsupported = TIP_("non-triangle face");
+ }
+ else if (mmd != NULL) {
+ message_unsupported = TIP_("multi-res modifier");
+ }
+ else {
+ enum eDynTopoWarnFlag flag = sculpt_dynamic_topology_check(C);
+ if (flag == 0) {
+ /* pass */
+ }
+ else if (flag & DYNTOPO_WARN_VDATA) {
+ message_unsupported = TIP_("vertex data");
+ }
+ else if (flag & DYNTOPO_WARN_EDATA) {
+ message_unsupported = TIP_("edge data");
+ }
+ else if (flag & DYNTOPO_WARN_LDATA) {
+ message_unsupported = TIP_("face data");
+ }
+ else if (flag & DYNTOPO_WARN_MODIFIER) {
+ message_unsupported = TIP_("constructive modifier");
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+
+ if (message_unsupported == NULL) {
+ /* undo push is needed to prevent memory leak */
+ sculpt_undo_push_begin("Dynamic topology enable");
+ sculpt_dynamic_topology_enable(C);
+ sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
+ }
+ else {
+ BKE_reportf(op->reports, RPT_WARNING,
+ "Dynamic Topology found: %s, disabled",
+ message_unsupported);
+ me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
+ }
+ }
}
if (ob->derivedFinal) /* VBO no longer valid */
@@ -5592,7 +5678,8 @@ static void SCULPT_OT_sample_detail_size(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_int_array(ot->srna, "location", 2, NULL, 0, SHRT_MAX, "Location", "Screen Coordinates of sampling", 0, SHRT_MAX);
+ RNA_def_int_array(ot->srna, "location", 2, NULL, 0, SHRT_MAX,
+ "Location", "Screen Coordinates of sampling", 0, SHRT_MAX);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index ceefda99002..44bd872d107 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -366,7 +366,9 @@ static void sculpt_undo_bmesh_enable(Object *ob,
sculpt_pbvh_clear(ob);
/* Create empty BMesh and enable logging */
- ss->bm = BM_mesh_create(&bm_mesh_allocsize_default);
+ ss->bm = BM_mesh_create(
+ &bm_mesh_allocsize_default,
+ &((struct BMeshCreateParams){.use_toolflags = false,}));
BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
sculpt_dyntopo_node_layers_add(ss);
me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c
index a4d9a920cbb..432918f0e37 100644
--- a/source/blender/editors/sound/sound_ops.c
+++ b/source/blender/editors/sound/sound_ops.c
@@ -116,7 +116,7 @@ static int sound_open_exec(bContext *C, wmOperator *op)
info = AUD_getInfo(sound->playback_handle);
if (info.specs.channels == AUD_CHANNELS_INVALID) {
- BKE_sound_delete(bmain, sound);
+ BKE_libblock_free(bmain, sound);
if (op->customdata) MEM_freeN(op->customdata);
BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
return OPERATOR_CANCELLED;
@@ -136,7 +136,7 @@ static int sound_open_exec(bContext *C, wmOperator *op)
if (pprop->prop) {
/* when creating new ID blocks, use is already 1, but RNA
- * pointer se also increases user, so this compensates it */
+ * pointer use also increases user, so this compensates it */
id_us_min(&sound->id);
RNA_id_pointer_create(&sound->id, &idptr);
@@ -217,32 +217,56 @@ static void SOUND_OT_open_mono(wmOperatorType *ot)
/* ******************************************************* */
-static int sound_update_animation_flags_exec(bContext *C, wmOperator *UNUSED(op))
+static void sound_update_animation_flags(Scene *scene);
+
+static int sound_update_animation_flags_cb(Sequence *seq, void *user_data)
{
- Sequence *seq;
- Scene *scene = CTX_data_scene(C);
struct FCurve *fcu;
+ Scene *scene = (Scene *)user_data;
bool driven;
- SEQ_BEGIN(scene->ed, seq)
- {
- fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "volume", 0, &driven);
- if (fcu || driven)
- seq->flag |= SEQ_AUDIO_VOLUME_ANIMATED;
- else
- seq->flag &= ~SEQ_AUDIO_VOLUME_ANIMATED;
+ fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "volume", 0, &driven);
+ if (fcu || driven)
+ seq->flag |= SEQ_AUDIO_VOLUME_ANIMATED;
+ else
+ seq->flag &= ~SEQ_AUDIO_VOLUME_ANIMATED;
- fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "pitch", 0, &driven);
- if (fcu || driven)
- seq->flag |= SEQ_AUDIO_PITCH_ANIMATED;
- else
- seq->flag &= ~SEQ_AUDIO_PITCH_ANIMATED;
+ fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "pitch", 0, &driven);
+ if (fcu || driven)
+ seq->flag |= SEQ_AUDIO_PITCH_ANIMATED;
+ else
+ seq->flag &= ~SEQ_AUDIO_PITCH_ANIMATED;
- fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "pan", 0, &driven);
- if (fcu || driven)
- seq->flag |= SEQ_AUDIO_PAN_ANIMATED;
- else
- seq->flag &= ~SEQ_AUDIO_PAN_ANIMATED;
+ fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "pan", 0, &driven);
+ if (fcu || driven)
+ seq->flag |= SEQ_AUDIO_PAN_ANIMATED;
+ else
+ seq->flag &= ~SEQ_AUDIO_PAN_ANIMATED;
+
+ if (seq->type == SEQ_TYPE_SCENE) {
+ /* TODO(sergey): For now we do manual recursion into the scene strips,
+ * but perhaps it should be covered by recursive_apply?
+ */
+ sound_update_animation_flags(seq->scene);
+ }
+
+ return 0;
+}
+
+static void sound_update_animation_flags(Scene *scene)
+{
+ struct FCurve *fcu;
+ bool driven;
+ Sequence *seq;
+
+ if (scene->id.tag & LIB_TAG_DOIT) {
+ return;
+ }
+ scene->id.tag |= LIB_TAG_DOIT;
+
+ SEQ_BEGIN(scene->ed, seq)
+ {
+ BKE_sequencer_recursive_apply(seq, sound_update_animation_flags_cb, scene);
}
SEQ_END
@@ -251,7 +275,12 @@ static int sound_update_animation_flags_exec(bContext *C, wmOperator *UNUSED(op)
scene->audio.flag |= AUDIO_VOLUME_ANIMATED;
else
scene->audio.flag &= ~AUDIO_VOLUME_ANIMATED;
+}
+static int sound_update_animation_flags_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ BKE_main_id_tag_idcode(CTX_data_main(C), ID_SCE, LIB_TAG_DOIT, false);
+ sound_update_animation_flags(CTX_data_scene(C));
return OPERATOR_FINISHED;
}
@@ -348,10 +377,10 @@ static int sound_mixdown_exec(bContext *C, wmOperator *op)
BLI_path_abs(filename, bmain->name);
if (split)
- result = AUD_mixdown_per_channel(scene->sound_scene, SFRA * specs.rate / FPS, (EFRA - SFRA) * specs.rate / FPS,
+ result = AUD_mixdown_per_channel(scene->sound_scene, SFRA * specs.rate / FPS, (EFRA - SFRA + 1) * specs.rate / FPS,
accuracy, filename, specs, container, codec, bitrate);
else
- result = AUD_mixdown(scene->sound_scene, SFRA * specs.rate / FPS, (EFRA - SFRA) * specs.rate / FPS,
+ result = AUD_mixdown(scene->sound_scene, SFRA * specs.rate / FPS, (EFRA - SFRA + 1) * specs.rate / FPS,
accuracy, filename, specs, container, codec, bitrate);
if (result) {
@@ -784,7 +813,7 @@ static void SOUND_OT_unpack(wmOperatorType *ot)
/* properties */
RNA_def_enum(ot->srna, "method", rna_enum_unpack_method_items, PF_USE_LOCAL, "Method", "How to unpack");
- RNA_def_string(ot->srna, "id", NULL, MAX_ID_NAME - 2, "Sound Name", "Sound datablock name to unpack"); /* XXX, weark!, will fail with library, name collisions */
+ RNA_def_string(ot->srna, "id", NULL, MAX_ID_NAME - 2, "Sound Name", "Sound data-block name to unpack"); /* XXX, weark!, will fail with library, name collisions */
}
/* ******************************************************* */
diff --git a/source/blender/editors/space_action/action_buttons.c b/source/blender/editors/space_action/action_buttons.c
index 063a477d2b6..bfc808f6d83 100644
--- a/source/blender/editors/space_action/action_buttons.c
+++ b/source/blender/editors/space_action/action_buttons.c
@@ -122,7 +122,7 @@ void ACTION_OT_properties(wmOperatorType *ot)
{
ot->name = "Properties";
ot->idname = "ACTION_OT_properties";
- ot->description = "Toggle display properties panel";
+ ot->description = "Toggle the properties region visibility";
ot->exec = action_properties_toggle_exec;
ot->poll = ED_operator_action_active;
diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c
index a3be7791f9a..fdf2dfe8371 100644
--- a/source/blender/editors/space_action/action_data.c
+++ b/source/blender/editors/space_action/action_data.c
@@ -121,7 +121,7 @@ static bAction *action_create_new(bContext *C, bAction *oldact)
*/
if (oldact && GS(oldact->id.name) == ID_AC) {
/* make a copy of the existing action */
- action = BKE_action_copy(oldact);
+ action = BKE_action_copy(CTX_data_main(C), oldact);
}
else {
/* just make a new (empty) action */
@@ -669,8 +669,8 @@ void ACTION_OT_unlink(wmOperatorType *ot)
ot->poll = action_unlink_poll;
/* properties */
- prop = RNA_def_boolean(ot->srna, "force_delete", false, "Force Delete",
- "Clear Fake User and remove copy stashed in this datablock's NLA stack");
+ prop = RNA_def_boolean(ot->srna, "force_delete", false, "Force Delete", "Clear Fake User and remove "
+ "copy stashed in this data-block's NLA stack");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c
index 10748c2fe15..9fc96e06299 100644
--- a/source/blender/editors/space_action/action_draw.c
+++ b/source/blender/editors/space_action/action_draw.c
@@ -81,7 +81,7 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
- height = ((items * ACHANNEL_STEP) + (ACHANNEL_HEIGHT));
+ height = ((items * ACHANNEL_STEP(ac)) + (ACHANNEL_HEIGHT(ac)));
if (height > BLI_rcti_size_y(&v2d->mask)) {
/* don't use totrect set, as the width stays the same
* (NOTE: this is ok here, the configuration is pretty straightforward)
@@ -95,11 +95,11 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
{ /* first pass: just the standard GL-drawing for backdrop + text */
size_t channel_index = 0;
- y = (float)ACHANNEL_FIRST;
+ y = (float)ACHANNEL_FIRST(ac);
for (ale = anim_data.first; ale; ale = ale->next) {
- float yminc = (float)(y - ACHANNEL_HEIGHT_HALF);
- float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF);
+ float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac));
+ float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac));
/* check if visible */
if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
@@ -110,7 +110,7 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
}
/* adjust y-position for next one */
- y -= ACHANNEL_STEP;
+ y -= ACHANNEL_STEP(ac);
channel_index++;
}
}
@@ -118,11 +118,11 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
size_t channel_index = 0;
- y = (float)ACHANNEL_FIRST;
+ y = (float)ACHANNEL_FIRST(ac);
for (ale = anim_data.first; ale; ale = ale->next) {
- float yminc = (float)(y - ACHANNEL_HEIGHT_HALF);
- float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF);
+ float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac));
+ float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac));
/* check if visible */
if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
@@ -133,7 +133,7 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
}
/* adjust y-position for next one */
- y -= ACHANNEL_STEP;
+ y -= ACHANNEL_STEP(ac);
channel_index++;
}
@@ -195,19 +195,19 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
- height = ((items * ACHANNEL_STEP) + (ACHANNEL_HEIGHT));
+ height = ((items * ACHANNEL_STEP(ac)) + (ACHANNEL_HEIGHT(ac)));
/* don't use totrect set, as the width stays the same
* (NOTE: this is ok here, the configuration is pretty straightforward)
*/
v2d->tot.ymin = (float)(-height);
/* first backdrop strips */
- y = (float)(-ACHANNEL_HEIGHT);
+ y = (float)(-ACHANNEL_HEIGHT(ac));
glEnable(GL_BLEND);
for (ale = anim_data.first; ale; ale = ale->next) {
- const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF);
- const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF);
+ const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac));
+ const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac));
/* check if visible */
if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
@@ -260,39 +260,39 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
}
/* draw region twice: firstly backdrop, then the current range */
- glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF, v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF);
+ glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac));
if (ac->datatype == ANIMCONT_ACTION)
- glRectf(act_start, (float)y - ACHANNEL_HEIGHT_HALF, act_end, (float)y + ACHANNEL_HEIGHT_HALF);
+ glRectf(act_start, (float)y - ACHANNEL_HEIGHT_HALF(ac), act_end, (float)y + ACHANNEL_HEIGHT_HALF(ac));
}
else if (ac->datatype == ANIMCONT_GPENCIL) {
/* frames less than one get less saturated background */
if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22);
else glColor4ub(col2[0], col2[1], col2[2], 0x22);
- glRectf(0.0f, (float)y - ACHANNEL_HEIGHT_HALF, v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF);
+ glRectf(0.0f, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF(ac));
/* frames one and higher get a saturated background */
if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x44);
else glColor4ub(col2[0], col2[1], col2[2], 0x44);
- glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF, v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF);
+ glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac));
}
else if (ac->datatype == ANIMCONT_MASK) {
/* TODO --- this is a copy of gpencil */
/* frames less than one get less saturated background */
if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22);
else glColor4ub(col2[0], col2[1], col2[2], 0x22);
- glRectf(0.0f, (float)y - ACHANNEL_HEIGHT_HALF, v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF);
+ glRectf(0.0f, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF(ac));
/* frames one and higher get a saturated background */
if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x44);
else glColor4ub(col2[0], col2[1], col2[2], 0x44);
- glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF, v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF);
+ glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac));
}
}
}
/* Increment the step */
- y -= ACHANNEL_STEP;
+ y -= ACHANNEL_STEP(ac);
}
glDisable(GL_BLEND);
@@ -301,11 +301,11 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
* This is to try to optimize this for heavier data sets
* 2) Keyframes which are out of view horizontally are disregarded
*/
- y = (float)(-ACHANNEL_HEIGHT);
+ y = (float)(-ACHANNEL_HEIGHT(ac));
for (ale = anim_data.first; ale; ale = ale->next) {
- const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF);
- const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF);
+ const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac));
+ const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac));
/* check if visible */
if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
@@ -318,34 +318,34 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
/* draw 'keyframes' for each specific datatype */
switch (ale->datatype) {
case ALE_ALL:
- draw_summary_channel(v2d, ale->data, y);
+ draw_summary_channel(v2d, ale->data, y, ac->yscale_fac);
break;
case ALE_SCE:
- draw_scene_channel(v2d, ads, ale->key_data, y);
+ draw_scene_channel(v2d, ads, ale->key_data, y, ac->yscale_fac);
break;
case ALE_OB:
- draw_object_channel(v2d, ads, ale->key_data, y);
+ draw_object_channel(v2d, ads, ale->key_data, y, ac->yscale_fac);
break;
case ALE_ACT:
- draw_action_channel(v2d, adt, ale->key_data, y);
+ draw_action_channel(v2d, adt, ale->key_data, y, ac->yscale_fac);
break;
case ALE_GROUP:
- draw_agroup_channel(v2d, adt, ale->data, y);
+ draw_agroup_channel(v2d, adt, ale->data, y, ac->yscale_fac);
break;
case ALE_FCURVE:
- draw_fcurve_channel(v2d, adt, ale->key_data, y);
+ draw_fcurve_channel(v2d, adt, ale->key_data, y, ac->yscale_fac);
break;
case ALE_GPFRAME:
- draw_gpl_channel(v2d, ads, ale->data, y);
+ draw_gpl_channel(v2d, ads, ale->data, y, ac->yscale_fac);
break;
case ALE_MASKLAY:
- draw_masklay_channel(v2d, ads, ale->data, y);
+ draw_masklay_channel(v2d, ads, ale->data, y, ac->yscale_fac);
break;
}
}
}
- y -= ACHANNEL_STEP;
+ y -= ACHANNEL_STEP(ac);
}
/* free tempolary channels used for drawing */
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index c0947dacbf0..f8db35e2311 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -333,7 +333,7 @@ static bool actkeys_channels_get_selected_extents(bAnimContext *ac, float *min,
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* loop through all channels, finding the first one that's selected */
- y = (float)ACHANNEL_FIRST;
+ y = (float)ACHANNEL_FIRST(ac);
for (ale = anim_data.first; ale; ale = ale->next) {
const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
@@ -343,8 +343,8 @@ static bool actkeys_channels_get_selected_extents(bAnimContext *ac, float *min,
ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT))
{
/* update best estimate */
- *min = (float)(y - ACHANNEL_HEIGHT_HALF);
- *max = (float)(y + ACHANNEL_HEIGHT_HALF);
+ *min = (float)(y - ACHANNEL_HEIGHT_HALF(ac));
+ *max = (float)(y + ACHANNEL_HEIGHT_HALF(ac));
/* is this high enough priority yet? */
found = acf->channel_role;
@@ -358,7 +358,7 @@ static bool actkeys_channels_get_selected_extents(bAnimContext *ac, float *min,
}
/* adjust y-position for next one */
- y -= ACHANNEL_STEP;
+ y -= ACHANNEL_STEP(ac);
}
/* free all temp data */
@@ -707,10 +707,13 @@ static void insert_action_keys(bAnimContext *ac, short mode)
* so it's easier for now to just read the F-Curve directly.
* (TODO: add the full-blown PointerRNA relative parsing case here...)
*/
- if (ale->id && !ale->owner)
+ if (ale->id && !ale->owner) {
insert_keyframe(reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, ts->keyframe_type, flag);
- else
- insert_vert_fcurve(fcu, cfra, fcu->curval, ts->keyframe_type, 0);
+ }
+ else {
+ const float curval = evaluate_fcurve(fcu, cfra);
+ insert_vert_fcurve(fcu, cfra, curval, ts->keyframe_type, 0);
+ }
ale->update |= ANIM_UPDATE_DEFAULT;
}
@@ -747,7 +750,7 @@ static void insert_gpencil_keys(bAnimContext *ac, short mode)
/* insert gp frames */
for (ale = anim_data.first; ale; ale = ale->next) {
bGPDlayer *gpl = (bGPDlayer *)ale->data;
- gpencil_layer_getframe(gpl, CFRA, add_frame_mode);
+ BKE_gpencil_layer_getframe(gpl, CFRA, add_frame_mode);
}
ANIM_animdata_update(ac, &anim_data);
diff --git a/source/blender/editors/space_action/action_intern.h b/source/blender/editors/space_action/action_intern.h
index 50e10e7e154..408eb38d386 100644
--- a/source/blender/editors/space_action/action_intern.h
+++ b/source/blender/editors/space_action/action_intern.h
@@ -59,6 +59,8 @@ void draw_channel_strips(struct bAnimContext *ac, struct SpaceAction *saction, s
void ACTION_OT_select_all_toggle(struct wmOperatorType *ot);
void ACTION_OT_select_border(struct wmOperatorType *ot);
+void ACTION_OT_select_lasso(struct wmOperatorType *ot);
+void ACTION_OT_select_circle(struct wmOperatorType *ot);
void ACTION_OT_select_column(struct wmOperatorType *ot);
void ACTION_OT_select_linked(struct wmOperatorType *ot);
void ACTION_OT_select_more(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_action/action_ops.c b/source/blender/editors/space_action/action_ops.c
index f69f9944f8a..718a4fd3c38 100644
--- a/source/blender/editors/space_action/action_ops.c
+++ b/source/blender/editors/space_action/action_ops.c
@@ -59,6 +59,8 @@ void action_operatortypes(void)
WM_operatortype_append(ACTION_OT_clickselect);
WM_operatortype_append(ACTION_OT_select_all_toggle);
WM_operatortype_append(ACTION_OT_select_border);
+ WM_operatortype_append(ACTION_OT_select_lasso);
+ WM_operatortype_append(ACTION_OT_select_circle);
WM_operatortype_append(ACTION_OT_select_column);
WM_operatortype_append(ACTION_OT_select_linked);
WM_operatortype_append(ACTION_OT_select_more);
@@ -178,6 +180,14 @@ static void action_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_border", BKEY, KM_PRESS, KM_ALT, 0);
RNA_boolean_set(kmi->ptr, "axis_range", true);
+ /* region select */
+ kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0);
+ RNA_boolean_set(kmi->ptr, "deselect", false);
+ kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "deselect", true);
+
+ WM_keymap_add_item(keymap, "ACTION_OT_select_circle", CKEY, KM_PRESS, 0, 0);
+
/* column select */
RNA_enum_set(WM_keymap_add_item(keymap, "ACTION_OT_select_column", KKEY, KM_PRESS, 0, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_KEYS);
RNA_enum_set(WM_keymap_add_item(keymap, "ACTION_OT_select_column", KKEY, KM_PRESS, KM_CTRL, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_CFRA);
@@ -230,7 +240,9 @@ static void action_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
/* auto-set range */
WM_keymap_add_item(keymap, "ACTION_OT_previewrange_set", PKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
WM_keymap_add_item(keymap, "ACTION_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
+#ifdef WITH_INPUT_NDOF
WM_keymap_add_item(keymap, "ACTION_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
+#endif
WM_keymap_add_item(keymap, "ACTION_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "ACTION_OT_view_frame", PAD0, KM_PRESS, 0, 0);
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index f2813b2a8d3..553be0ad290 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -36,6 +36,7 @@
#include "BLI_blenlib.h"
#include "BLI_dlrbTree.h"
+#include "BLI_lasso.h"
#include "BLI_utildefines.h"
#include "DNA_anim_types.h"
@@ -212,7 +213,7 @@ static void borderselect_action(bAnimContext *ac, const rcti rect, short mode, s
KeyframeEditFunc ok_cb, select_cb;
View2D *v2d = &ac->ar->v2d;
rctf rectf;
- float ymin = 0, ymax = (float)(-ACHANNEL_HEIGHT_HALF);
+ float ymin = 0, ymax = (float)(-ACHANNEL_HEIGHT_HALF(ac));
/* convert mouse coordinates to frame ranges and channel coordinates corrected for view pan/zoom */
UI_view2d_region_to_view(v2d, rect.xmin, rect.ymin + 2, &rectf.xmin, &rectf.ymin);
@@ -238,7 +239,7 @@ static void borderselect_action(bAnimContext *ac, const rcti rect, short mode, s
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
/* get new vertical minimum extent of channel */
- ymin = ymax - ACHANNEL_STEP;
+ ymin = ymax - ACHANNEL_STEP(ac);
/* set horizontal range (if applicable) */
if (ELEM(mode, ACTKEYS_BORDERSEL_FRAMERANGE, ACTKEYS_BORDERSEL_ALLKEYS)) {
@@ -375,6 +376,264 @@ void ACTION_OT_select_border(wmOperatorType *ot)
ot->prop = RNA_def_boolean(ot->srna, "axis_range", 0, "Axis Range", "");
}
+/* ******************** Region Select Operators ***************************** */
+/* "Region Select" operators include the Lasso and Circle Select operators.
+ * These two ended up being lumped together, as it was easier in the
+ * original Graph Editor implementation of these to do it this way.
+ */
+
+static void region_select_action_keys(bAnimContext *ac, const rctf *rectf_view, short mode, short selectmode, void *data)
+{
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+
+ KeyframeEditData ked;
+ KeyframeEditFunc ok_cb, select_cb;
+ View2D *v2d = &ac->ar->v2d;
+ rctf rectf, scaled_rectf;
+ float ymin = 0, ymax = (float)(-ACHANNEL_HEIGHT_HALF(ac));
+
+ /* convert mouse coordinates to frame ranges and channel coordinates corrected for view pan/zoom */
+ UI_view2d_region_to_view_rctf(v2d, rectf_view, &rectf);
+
+ /* filter data */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS);
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+
+ /* get beztriple editing/validation funcs */
+ select_cb = ANIM_editkeyframes_select(selectmode);
+ ok_cb = ANIM_editkeyframes_ok(mode);
+
+ /* init editing data */
+ memset(&ked, 0, sizeof(KeyframeEditData));
+ if (mode == BEZT_OK_CHANNEL_LASSO) {
+ KeyframeEdit_LassoData *data_lasso = data;
+ data_lasso->rectf_scaled = &scaled_rectf;
+ ked.data = data_lasso;
+ }
+ else if (mode == BEZT_OK_CHANNEL_CIRCLE) {
+ KeyframeEdit_CircleData *data_circle = data;
+ data_circle->rectf_scaled = &scaled_rectf;
+ ked.data = data;
+ }
+ else {
+ ked.data = &scaled_rectf;
+ }
+
+ /* loop over data, doing region select */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt = ANIM_nla_mapping_get(ac, ale);
+
+ /* get new vertical minimum extent of channel */
+ ymin = ymax - ACHANNEL_STEP(ac);
+
+ /* compute midpoint of channel (used for testing if the key is in the region or not) */
+ ked.channel_y = ymin + ACHANNEL_HEIGHT_HALF(ac);
+
+ /* if channel is mapped in NLA, apply correction
+ * - Apply to the bounds being checked, not all the keyframe points,
+ * to avoid having scaling everything
+ * - Save result to the scaled_rect, which is all that these operators
+ * will read from
+ */
+ if (adt) {
+ ked.iterflags &= ~(KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP);
+ ked.f1 = BKE_nla_tweakedit_remap(adt, rectf.xmin, NLATIME_CONVERT_UNMAP);
+ ked.f2 = BKE_nla_tweakedit_remap(adt, rectf.xmax, NLATIME_CONVERT_UNMAP);
+ }
+ else {
+ ked.iterflags |= (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP); /* for summary tracks */
+ ked.f1 = rectf.xmin;
+ ked.f2 = rectf.xmax;
+ }
+
+ /* Update values for scaled_rectf - which is used to compute the mapping in the callbacks
+ * NOTE: Since summary tracks need late-binding remapping, the callbacks may overwrite these
+ * with the properly remapped ked.f1/f2 values, when needed
+ */
+ scaled_rectf.xmin = ked.f1;
+ scaled_rectf.xmax = ked.f2;
+ scaled_rectf.ymin = ymin;
+ scaled_rectf.ymax = ymax;
+
+ /* perform vertical suitability check (if applicable) */
+ if ((mode == ACTKEYS_BORDERSEL_FRAMERANGE) ||
+ !((ymax < rectf.ymin) || (ymin > rectf.ymax)))
+ {
+ /* loop over data selecting */
+ switch (ale->type) {
+ case ANIMTYPE_GPDATABLOCK:
+ {
+ bGPdata *gpd = ale->data;
+ bGPDlayer *gpl;
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ ED_gplayer_frames_select_region(&ked, ale->data, mode, selectmode);
+ }
+ break;
+ }
+ case ANIMTYPE_GPLAYER:
+ {
+ ED_gplayer_frames_select_region(&ked, ale->data, mode, selectmode);
+ break;
+ }
+ case ANIMTYPE_MASKDATABLOCK:
+ {
+ Mask *mask = ale->data;
+ MaskLayer *masklay;
+ for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
+ ED_masklayer_frames_select_region(&ked, masklay, mode, selectmode);
+ }
+ break;
+ }
+ case ANIMTYPE_MASKLAYER:
+ {
+ ED_masklayer_frames_select_region(&ked, ale->data, mode, selectmode);
+ break;
+ }
+ default:
+ ANIM_animchannel_keyframes_loop(&ked, ac->ads, ale, ok_cb, select_cb, NULL);
+ break;
+ }
+ }
+
+ /* set minimum extent to be the maximum of the next channel */
+ ymax = ymin;
+ }
+
+ /* cleanup */
+ ANIM_animdata_freelist(&anim_data);
+}
+
+/* ----------------------------------- */
+
+static int actkeys_lassoselect_exec(bContext *C, wmOperator *op)
+{
+ bAnimContext ac;
+
+ KeyframeEdit_LassoData data_lasso;
+ rcti rect;
+ rctf rect_fl;
+
+ short selectmode;
+ bool extend;
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ data_lasso.rectf_view = &rect_fl;
+ data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot);
+ if (data_lasso.mcords == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* clear all selection if not extending selection */
+ extend = RNA_boolean_get(op->ptr, "extend");
+ if (!extend)
+ deselect_action_keys(&ac, 1, SELECT_SUBTRACT);
+
+ if (!RNA_boolean_get(op->ptr, "deselect"))
+ selectmode = SELECT_ADD;
+ else
+ selectmode = SELECT_SUBTRACT;
+
+ /* get settings from operator */
+ BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot);
+ BLI_rctf_rcti_copy(&rect_fl, &rect);
+
+ /* apply borderselect action */
+ region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_LASSO, selectmode, &data_lasso);
+
+ MEM_freeN((void *)data_lasso.mcords);
+
+ /* send notifier that keyframe selection has changed */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_select_lasso(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Lasso Select";
+ ot->description = "Select keyframe points using lasso selection";
+ ot->idname = "ACTION_OT_select_lasso";
+
+ /* api callbacks */
+ ot->invoke = WM_gesture_lasso_invoke;
+ ot->modal = WM_gesture_lasso_modal;
+ ot->exec = actkeys_lassoselect_exec;
+ ot->poll = ED_operator_action_active;
+ ot->cancel = WM_gesture_lasso_cancel;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
+ RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Deselect rather than select items");
+ RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first");
+}
+
+/* ------------------- */
+
+static int action_circle_select_exec(bContext *C, wmOperator *op)
+{
+ bAnimContext ac;
+ const int gesture_mode = RNA_int_get(op->ptr, "gesture_mode");
+ const short selectmode = (gesture_mode == GESTURE_MODAL_SELECT) ? SELECT_ADD : SELECT_SUBTRACT;
+
+ KeyframeEdit_CircleData data = {0};
+ rctf rect_fl;
+
+ float x = RNA_int_get(op->ptr, "x");
+ float y = RNA_int_get(op->ptr, "y");
+ float radius = RNA_int_get(op->ptr, "radius");
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ data.mval[0] = x;
+ data.mval[1] = y;
+ data.radius_squared = radius * radius;
+ data.rectf_view = &rect_fl;
+
+ rect_fl.xmin = x - radius;
+ rect_fl.xmax = x + radius;
+ rect_fl.ymin = y - radius;
+ rect_fl.ymax = y + radius;
+
+ /* apply region select action */
+ region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_CIRCLE, selectmode, &data);
+
+ /* send notifier that keyframe selection has changed */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_select_circle(wmOperatorType *ot)
+{
+ ot->name = "Circle Select";
+ ot->description = "Select keyframe points using circle selection";
+ ot->idname = "ACTION_OT_select_circle";
+
+ ot->invoke = WM_gesture_circle_invoke;
+ ot->modal = WM_gesture_circle_modal;
+ ot->exec = action_circle_select_exec;
+ ot->poll = ED_operator_action_active;
+ ot->cancel = WM_gesture_circle_cancel;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
+ RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
+ RNA_def_int(ot->srna, "radius", 1, 1, INT_MAX, "Radius", "", 1, INT_MAX);
+ RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
+}
+
/* ******************** Column Select Operator **************************** */
/* This operator works in one of four ways:
* - 1) select all keyframes in the same frame as a selected one (KKEY)
@@ -1092,6 +1351,7 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_
bool found = false;
float frame = 0.0f; /* frame of keyframe under mouse - NLA corrections not applied/included */
float selx = 0.0f; /* frame of keyframe under mouse */
+ float key_hsize;
float x, y;
rctf rectf;
@@ -1101,11 +1361,16 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_
/* use View2D to determine the index of the channel (i.e a row in the list) where keyframe was */
UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
- UI_view2d_listview_view_to_cell(v2d, 0, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index);
+ UI_view2d_listview_view_to_cell(v2d, 0, ACHANNEL_STEP(ac), 0, (float)ACHANNEL_HEIGHT_HALF(ac), x, y, NULL, &channel_index);
+
+ /* x-range to check is +/- 7px for standard keyframe under standard dpi/y-scale (in screen/region-space),
+ * on either side of mouse click (size of keyframe icon)
+ */
+ key_hsize = ACHANNEL_HEIGHT(ac) * 0.8f; /* standard channel height (to allow for some slop) */
+ key_hsize = roundf(key_hsize / 2.0f); /* half-size (for either side), but rounded up to nearest int (for easier targetting) */
- /* x-range to check is +/- 7 (in screen/region-space) on either side of mouse click (size of keyframe icon) */
- UI_view2d_region_to_view(v2d, mval[0] - 7, mval[1], &rectf.xmin, &rectf.ymin);
- UI_view2d_region_to_view(v2d, mval[0] + 7, mval[1], &rectf.xmax, &rectf.ymax);
+ UI_view2d_region_to_view(v2d, mval[0] - (int)key_hsize, mval[1], &rectf.xmin, &rectf.ymin);
+ UI_view2d_region_to_view(v2d, mval[0] + (int)key_hsize, mval[1], &rectf.xmax, &rectf.ymax);
/* filter data */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c
index 60240109432..671d6bb083e 100644
--- a/source/blender/editors/space_action/space_action.c
+++ b/source/blender/editors/space_action/space_action.c
@@ -33,6 +33,7 @@
#include <stdio.h>
#include "DNA_action_types.h"
+#include "DNA_group_types.h"
#include "DNA_scene_types.h"
#include "MEM_guardedalloc.h"
@@ -614,6 +615,19 @@ static void action_refresh(const bContext *C, ScrArea *sa)
// XXX re-sizing y-extents of tot should go here?
}
+static void action_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceAction *sact = (SpaceAction *)slink;
+
+ if (!ELEM(GS(old_id->name), ID_GR)) {
+ return;
+ }
+
+ if ((ID *)sact->ads.filter_grp == old_id) {
+ sact->ads.filter_grp = (Group *)new_id;
+ }
+}
+
/* only called once, from space/spacetypes.c */
void ED_spacetype_action(void)
{
@@ -631,7 +645,8 @@ void ED_spacetype_action(void)
st->keymap = action_keymap;
st->listener = action_listener;
st->refresh = action_refresh;
-
+ st->id_remap = action_id_remap;
+
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype action region");
art->regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c
index 42e2d6b90f0..da3364d872d 100644
--- a/source/blender/editors/space_buttons/buttons_context.c
+++ b/source/blender/editors/space_buttons/buttons_context.c
@@ -1106,7 +1106,7 @@ void buttons_context_draw(const bContext *C, uiLayout *layout)
block = uiLayoutGetBlock(row);
UI_block_emboss_set(block, UI_EMBOSS_NONE);
but = uiDefIconButBitC(block, UI_BTYPE_ICON_TOGGLE, SB_PIN_CONTEXT, 0, ICON_UNPINNED, 0, 0, UI_UNIT_X, UI_UNIT_Y, &sbuts->flag,
- 0, 0, 0, 0, TIP_("Follow context or keep fixed datablock displayed"));
+ 0, 0, 0, 0, TIP_("Follow context or keep fixed data-block displayed"));
UI_but_flag_disable(but, UI_BUT_UNDO); /* skip undo on screen buttons */
UI_but_func_set(but, pin_cb, NULL, NULL);
@@ -1180,33 +1180,3 @@ ID *buttons_context_id_path(const bContext *C)
return NULL;
}
-
-void ED_buttons_id_unref(SpaceButs *sbuts, const ID *id)
-{
- if (sbuts->pinid == id) {
- sbuts->pinid = NULL;
- sbuts->flag &= ~SB_PIN_CONTEXT;
- }
-
- if (sbuts->path) {
- ButsContextPath *path = sbuts->path;
- int i;
-
- for (i = 0; i < path->len; i++) {
- if (path->ptr[i].id.data == id) {
- break;
- }
- }
-
- if (i == path->len) {
- /* pass */
- }
- else if (i == 0) {
- MEM_SAFE_FREE(sbuts->path);
- }
- else {
- memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));
- path->len = i;
- }
- }
-}
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index 126a27c36cb..e4c23ad74f8 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -45,6 +45,8 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "RNA_access.h"
+
#include "buttons_intern.h" /* own include */
/* ******************** default callbacks for buttons space ***************** */
@@ -389,6 +391,59 @@ static void buttons_area_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *
ED_area_tag_redraw(sa);
}
+static void buttons_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceButs *sbuts = (SpaceButs *)slink;
+
+ if (sbuts->pinid == old_id) {
+ sbuts->pinid = new_id;
+ if (new_id == NULL) {
+ sbuts->flag &= ~SB_PIN_CONTEXT;
+ }
+ }
+
+ if (sbuts->path) {
+ ButsContextPath *path = sbuts->path;
+ int i;
+
+ for (i = 0; i < path->len; i++) {
+ if (path->ptr[i].id.data == old_id) {
+ break;
+ }
+ }
+
+ if (i == path->len) {
+ /* pass */
+ }
+ else if (new_id == NULL) {
+ if (i == 0) {
+ MEM_SAFE_FREE(sbuts->path);
+ }
+ else {
+ memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));
+ path->len = i;
+ }
+ }
+ else {
+ RNA_id_pointer_create(new_id, &path->ptr[i]);
+ /* There is no easy way to check/make path downwards valid, just nullify it.
+ * Next redraw will rebuild this anyway. */
+ i++;
+ memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));
+ path->len = i;
+ }
+ }
+
+ if (sbuts->texuser) {
+ ButsContextTexture *ct = sbuts->texuser;
+ if ((ID *)ct->texture == old_id) {
+ ct->texture = (Tex *)new_id;
+ }
+ BLI_freelistN(&ct->users);
+ ct->user = NULL;
+ }
+}
+
/* only called once, from space/spacetypes.c */
void ED_spacetype_buttons(void)
{
@@ -406,7 +461,8 @@ void ED_spacetype_buttons(void)
st->keymap = buttons_keymap;
st->listener = buttons_area_listener;
st->context = buttons_context;
-
+ st->id_remap = buttons_id_remap;
+
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype buttons region");
art->regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c
index 1c5be3d1fb5..695d04d3850 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -336,8 +336,10 @@ static void draw_stabilization_border(SpaceClip *sc, ARegion *ar, int width, int
/* draw boundary border for frame if stabilization is enabled */
if (sc->flag & SC_SHOW_STABLE && clip->tracking.stabilization.flag & TRACKING_2D_STABILIZATION) {
glColor3f(0.0f, 0.0f, 0.0f);
- glLineStipple(3, 0xaaaa);
- glEnable(GL_LINE_STIPPLE);
+
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ GPU_basic_shader_line_stipple(3, 0xAAAA);
+
glEnable(GL_COLOR_LOGIC_OP);
glLogicOp(GL_NOR);
@@ -357,7 +359,7 @@ static void draw_stabilization_border(SpaceClip *sc, ARegion *ar, int width, int
glPopMatrix();
glDisable(GL_COLOR_LOGIC_OP);
- glDisable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
}
}
@@ -627,8 +629,8 @@ static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTra
glEnd();
glColor3f(0.0f, 0.0f, 0.0f);
- glLineStipple(3, 0xaaaa);
- glEnable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ GPU_basic_shader_line_stipple(3, 0xAAAA);
glEnable(GL_COLOR_LOGIC_OP);
glLogicOp(GL_NOR);
@@ -638,7 +640,7 @@ static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTra
glEnd();
glDisable(GL_COLOR_LOGIC_OP);
- glDisable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
}
}
@@ -647,8 +649,11 @@ static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTra
glTranslate2fv(marker_pos);
if (tiny) {
- glLineStipple(3, 0xaaaa);
- glEnable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ GPU_basic_shader_line_stipple(3, 0xAAAA);
+ }
+ else {
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE);
}
if ((track->pat_flag & SELECT) == sel && (sc->flag & SC_SHOW_MARKER_PATTERN)) {
@@ -713,8 +718,12 @@ static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTra
glEnd();
}
- if (tiny)
- glDisable(GL_LINE_STIPPLE);
+ if (tiny) {
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ }
+ else {
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE);
+ }
glPopMatrix();
}
@@ -852,16 +861,12 @@ static void draw_marker_slide_zones(SpaceClip *sc, MovieTrackingTrack *track, Mo
glLineWidth(outline ? 3.0f : 1.0f);
- glEnable(GL_LINE_STIPPLE);
- glLineStipple(3, 0xaaaa);
-
glBegin(GL_LINES);
glVertex2f(0.0f, 0.0f);
glVertex2fv(tilt_ctrl);
glEnd();
- glDisable(GL_LINE_STIPPLE);
-
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
/* slider to control pattern tilt */
draw_marker_slide_square(tilt_ctrl[0], tilt_ctrl[1], patdx, patdy, outline, px);
@@ -1133,11 +1138,14 @@ static void draw_plane_marker_ex(SpaceClip *sc, Scene *scene, MovieTrackingPlane
const bool thick = draw_outline && !tiny;
if (stipple) {
- glLineStipple(3, 0xaaaa);
- glEnable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ GPU_basic_shader_line_stipple(3, 0xAAAA);
+ }
+ else {
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE);
}
- glLineWidth(thick ? 3.0f : 1.0f);
+ GPU_basic_shader_line_width(thick ? 3.0f : 1.0f);
/* Draw rectangle itself. */
glBegin(GL_LINE_LOOP);
@@ -1169,8 +1177,12 @@ static void draw_plane_marker_ex(SpaceClip *sc, Scene *scene, MovieTrackingPlane
glPopAttrib();
}
- if (stipple)
- glDisable(GL_LINE_STIPPLE);
+ if (stipple) {
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ }
+ else {
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE);
+ }
}
/* Draw sliders. */
diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c
index 1ff656243d6..14d0f909d23 100644
--- a/source/blender/editors/space_clip/clip_editor.c
+++ b/source/blender/editors/space_clip/clip_editor.c
@@ -634,7 +634,7 @@ typedef struct PrefetchQueue {
short render_size, render_flag;
/* If true prefecthing goes forward in time,
- * othwewise it goes backwards in time (starting from current frame).
+ * otherwise it goes backwards in time (starting from current frame).
*/
bool forward;
diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h
index 2a5d959bb84..14393c6968b 100644
--- a/source/blender/editors/space_clip/clip_intern.h
+++ b/source/blender/editors/space_clip/clip_intern.h
@@ -106,7 +106,9 @@ void CLIP_OT_change_frame(wmOperatorType *ot);
void CLIP_OT_rebuild_proxy(struct wmOperatorType *ot);
void CLIP_OT_mode_set(struct wmOperatorType *ot);
+#ifdef WITH_INPUT_NDOF
void CLIP_OT_view_ndof(struct wmOperatorType *ot);
+#endif
void CLIP_OT_prefetch(struct wmOperatorType *ot);
@@ -185,7 +187,10 @@ void CLIP_OT_detect_features(struct wmOperatorType *ot);
void CLIP_OT_stabilize_2d_add(struct wmOperatorType *ot);
void CLIP_OT_stabilize_2d_remove(struct wmOperatorType *ot);
void CLIP_OT_stabilize_2d_select(struct wmOperatorType *ot);
-void CLIP_OT_stabilize_2d_set_rotation(struct wmOperatorType *ot);
+
+void CLIP_OT_stabilize_2d_rotation_add(struct wmOperatorType *ot);
+void CLIP_OT_stabilize_2d_rotation_remove(struct wmOperatorType *ot);
+void CLIP_OT_stabilize_2d_rotation_select(struct wmOperatorType *ot);
void CLIP_OT_clean_tracks(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index 085fdd57309..9430ee626ba 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -103,7 +103,7 @@ static void sclip_zoom_set(const bContext *C, float zoom, float location[2])
width *= sc->zoom;
height *= sc->zoom;
- if ((width < 4) && (height < 4))
+ if ((width < 4) && (height < 4) && sc->zoom < oldzoom)
sc->zoom = oldzoom;
else if (BLI_rcti_size_x(&ar->winrct) <= sc->zoom)
sc->zoom = oldzoom;
@@ -234,7 +234,7 @@ static int open_exec(bContext *C, wmOperator *op)
if (pprop->prop) {
/* when creating new ID blocks, use is already 1, but RNA
- * pointer se also increases user, so this compensates it */
+ * pointer use also increases user, so this compensates it */
id_us_min(&clip->id);
RNA_id_pointer_create(&clip->id, &idptr);
@@ -476,7 +476,7 @@ void CLIP_OT_view_pan(wmOperatorType *ot)
ot->poll = ED_space_clip_view_clip_poll;
/* flags */
- ot->flag = OPTYPE_BLOCKING;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
/* properties */
RNA_def_float_vector(ot->srna, "offset", 2, NULL, -FLT_MAX, FLT_MAX,
@@ -1405,6 +1405,7 @@ void CLIP_OT_mode_set(wmOperatorType *ot)
RNA_def_enum(ot->srna, "mode", rna_enum_clip_editor_mode_items, SC_MODE_TRACKING, "Mode", "");
}
+#ifdef WITH_INPUT_NDOF
/********************** NDOF operator *********************/
/* Combined pan/zoom from a 3D mouse device.
@@ -1451,6 +1452,7 @@ void CLIP_OT_view_ndof(wmOperatorType *ot)
ot->invoke = clip_view_ndof_invoke;
ot->poll = ED_space_clip_view_clip_poll;
}
+#endif /* WITH_INPUT_NDOF */
/********************** Prefetch operator *********************/
diff --git a/source/blender/editors/space_clip/clip_toolbar.c b/source/blender/editors/space_clip/clip_toolbar.c
index d31d7f53b30..b042bbe8fea 100644
--- a/source/blender/editors/space_clip/clip_toolbar.c
+++ b/source/blender/editors/space_clip/clip_toolbar.c
@@ -106,7 +106,7 @@ void CLIP_OT_properties(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Properties";
- ot->description = "Toggle clip properties panel";
+ ot->description = "Toggle the properties region visibility";
ot->idname = "CLIP_OT_properties";
/* api callbacks */
diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c
index 5964e9a898b..547c2fba66f 100644
--- a/source/blender/editors/space_clip/clip_utils.c
+++ b/source/blender/editors/space_clip/clip_utils.c
@@ -175,21 +175,14 @@ void clip_graph_tracking_iterate(SpaceClip *sc, bool selected_only, bool include
void clip_delete_track(bContext *C, MovieClip *clip, MovieTrackingTrack *track)
{
MovieTracking *tracking = &clip->tracking;
- MovieTrackingStabilization *stab = &tracking->stabilization;
MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
- bool has_bundle = false, update_stab = false;
+ bool has_bundle = false;
char track_name_escaped[MAX_NAME], prefix[MAX_NAME * 2];
if (track == act_track)
tracking->act_track = NULL;
- if (track == stab->rot_track) {
- stab->rot_track = NULL;
-
- update_stab = true;
- }
-
/* handle reconstruction display in 3d viewport */
if (track->flag & TRACK_HAS_BUNDLE)
has_bundle = true;
@@ -207,8 +200,7 @@ void clip_delete_track(bContext *C, MovieClip *clip, MovieTrackingTrack *track)
WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
- if (update_stab) {
- tracking->stabilization.ok = false;
+ if (track->flag & (TRACK_USE_2D_STAB | TRACK_USE_2D_STAB_ROT)) {
WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
}
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index e1d4e4fabc5..05e69968e35 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -45,6 +45,7 @@
#include "BKE_context.h"
#include "BKE_screen.h"
+#include "BKE_library.h"
#include "BKE_movieclip.h"
#include "BKE_tracking.h"
@@ -224,18 +225,6 @@ static void clip_scopes_check_gpencil_change(ScrArea *sa)
}
}
-static void clip_stabilization_tag_refresh(ScrArea *sa)
-{
- SpaceClip *sc = (SpaceClip *) sa->spacedata.first;
- MovieClip *clip = ED_space_clip_get_clip(sc);
-
- if (clip) {
- MovieTrackingStabilization *stab = &clip->tracking.stabilization;
-
- stab->ok = false;
- }
-}
-
/* ******************** default callbacks for clip space ***************** */
static SpaceLink *clip_new(const bContext *C)
@@ -367,7 +356,6 @@ static void clip_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
case NA_REMOVED:
case NA_EDITED:
case NA_EVALUATED:
- clip_stabilization_tag_refresh(sa);
/* fall-through */
case NA_SELECTED:
@@ -411,7 +399,6 @@ static void clip_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
case NC_SPACE:
if (wmn->data == ND_SPACE_CLIP) {
clip_scopes_tag_refresh(sa);
- clip_stabilization_tag_refresh(sa);
ED_area_tag_redraw(sa);
}
break;
@@ -442,7 +429,9 @@ static void clip_operatortypes(void)
WM_operatortype_append(CLIP_OT_change_frame);
WM_operatortype_append(CLIP_OT_rebuild_proxy);
WM_operatortype_append(CLIP_OT_mode_set);
+#ifdef WITH_INPUT_NDOF
WM_operatortype_append(CLIP_OT_view_ndof);
+#endif
WM_operatortype_append(CLIP_OT_prefetch);
WM_operatortype_append(CLIP_OT_set_scene_frames);
WM_operatortype_append(CLIP_OT_cursor_set);
@@ -456,7 +445,7 @@ static void clip_operatortypes(void)
/* navigation */
WM_operatortype_append(CLIP_OT_frame_jump);
- /* foorage */
+ /* set optical center to frame center */
WM_operatortype_append(CLIP_OT_set_center_principal);
/* selection */
@@ -504,7 +493,9 @@ static void clip_operatortypes(void)
WM_operatortype_append(CLIP_OT_stabilize_2d_add);
WM_operatortype_append(CLIP_OT_stabilize_2d_remove);
WM_operatortype_append(CLIP_OT_stabilize_2d_select);
- WM_operatortype_append(CLIP_OT_stabilize_2d_set_rotation);
+ WM_operatortype_append(CLIP_OT_stabilize_2d_rotation_add);
+ WM_operatortype_append(CLIP_OT_stabilize_2d_rotation_remove);
+ WM_operatortype_append(CLIP_OT_stabilize_2d_rotation_select);
/* clean-up */
WM_operatortype_append(CLIP_OT_clear_track_path);
@@ -633,8 +624,10 @@ static void clip_keymap(struct wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "CLIP_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0);
+#ifdef WITH_INPUT_NDOF
WM_keymap_add_item(keymap, "CLIP_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "CLIP_OT_view_ndof", NDOF_MOTION, 0, 0, 0);
+#endif
/* jump to special frame */
kmi = WM_keymap_add_item(keymap, "CLIP_OT_frame_jump", LEFTARROWKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
@@ -790,7 +783,9 @@ static void clip_keymap(struct wmKeyConfig *keyconf)
/* view */
WM_keymap_add_item(keymap, "CLIP_OT_graph_view_all", HOMEKEY, KM_PRESS, 0, 0);
+#ifdef WITH_INPUT_NDOF
WM_keymap_add_item(keymap, "CLIP_OT_graph_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
+#endif
WM_keymap_add_item(keymap, "CLIP_OT_graph_center_current_frame", PADPERIOD, KM_PRESS, 0, 0);
kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", LKEY, KM_PRESS, 0, 0);
@@ -817,11 +812,13 @@ static void clip_keymap(struct wmKeyConfig *keyconf)
keymap = WM_keymap_find(keyconf, "Clip Dopesheet Editor", SPACE_CLIP, 0);
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_dopesheet_select_channel", ACTIONMOUSE, KM_PRESS, 0, 0);
+ kmi = WM_keymap_add_item(keymap, "CLIP_OT_dopesheet_select_channel", LEFTMOUSE, KM_PRESS, 0, 0);
RNA_boolean_set(kmi->ptr, "extend", true); /* toggle */
WM_keymap_add_item(keymap, "CLIP_OT_dopesheet_view_all", HOMEKEY, KM_PRESS, 0, 0);
+#ifdef WITH_INPUT_NDOF
WM_keymap_add_item(keymap, "CLIP_OT_dopesheet_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
+#endif
}
const char *clip_context_dir[] = {"edit_movieclip", "edit_mask", NULL};
@@ -1512,6 +1509,25 @@ static void clip_properties_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED
/********************* registration ********************/
+static void clip_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceClip *sclip = (SpaceClip *)slink;
+
+ if (!ELEM(GS(old_id->name), ID_MC, ID_MSK)) {
+ return;
+ }
+
+ if ((ID *)sclip->clip == old_id) {
+ sclip->clip = (MovieClip *)new_id;
+ id_us_ensure_real(new_id);
+ }
+
+ if ((ID *)sclip->mask_info.mask == old_id) {
+ sclip->mask_info.mask = (Mask *)new_id;
+ id_us_ensure_real(new_id);
+ }
+}
+
/* only called once, from space/spacetypes.c */
void ED_spacetype_clip(void)
{
@@ -1531,6 +1547,7 @@ void ED_spacetype_clip(void)
st->context = clip_context;
st->dropboxes = clip_dropboxes;
st->refresh = clip_refresh;
+ st->id_remap = clip_id_remap;
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype clip region");
diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c
index 61bfa5b315b..d28cbe5fb1d 100644
--- a/source/blender/editors/space_clip/tracking_ops.c
+++ b/source/blender/editors/space_clip/tracking_ops.c
@@ -1509,8 +1509,10 @@ static int join_tracks_exec(bContext *C, wmOperator *op)
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
+ MovieTrackingStabilization *stab = &tracking->stabilization;
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
+ bool update_stabilization = false;
MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
if (act_track == NULL) {
@@ -1528,8 +1530,23 @@ static int join_tracks_exec(bContext *C, wmOperator *op)
if (TRACK_VIEW_SELECTED(sc, track) && track != act_track) {
BKE_tracking_tracks_join(tracking, act_track, track);
- if (tracking->stabilization.rot_track == track) {
- tracking->stabilization.rot_track = act_track;
+ if (track->flag & TRACK_USE_2D_STAB) {
+ update_stabilization = true;
+ if ((act_track->flag & TRACK_USE_2D_STAB) == 0) {
+ act_track->flag |= TRACK_USE_2D_STAB;
+ } else {
+ stab->tot_track--;
+ }
+ BLI_assert(0 <= stab->tot_track);
+ }
+ if (track->flag & TRACK_USE_2D_STAB_ROT) {
+ update_stabilization = true;
+ if ((act_track->flag & TRACK_USE_2D_STAB_ROT) == 0) {
+ act_track->flag |= TRACK_USE_2D_STAB_ROT;
+ } else {
+ stab->tot_rot_track--;
+ }
+ BLI_assert(0 <= stab->tot_rot_track);
}
for (MovieTrackingPlaneTrack *plane_track = plane_tracks_base->first;
@@ -1551,6 +1568,10 @@ static int join_tracks_exec(bContext *C, wmOperator *op)
}
}
+ if (update_stabilization) {
+ WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
+ }
+
GSetIterator gs_iter;
int framenr = ED_space_clip_get_clip_frame_number(sc);
GSET_ITER (gs_iter, point_tracks) {
diff --git a/source/blender/editors/space_clip/tracking_ops_stabilize.c b/source/blender/editors/space_clip/tracking_ops_stabilize.c
index 8d6173e1cea..35b1aead343 100644
--- a/source/blender/editors/space_clip/tracking_ops_stabilize.c
+++ b/source/blender/editors/space_clip/tracking_ops_stabilize.c
@@ -84,7 +84,6 @@ static int stabilize_2d_add_exec(bContext *C, wmOperator *UNUSED(op))
}
if (update) {
- stab->ok = 0;
DAG_id_tag_update(&clip->id, 0);
WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
}
@@ -96,7 +95,7 @@ void CLIP_OT_stabilize_2d_add(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Add Stabilization Tracks";
- ot->description = "Add selected tracks to 2D stabilization tool";
+ ot->description = "Add selected tracks to 2D translation stabilization";
ot->idname = "CLIP_OT_stabilize_2d_add";
/* api callbacks */
@@ -139,7 +138,6 @@ static int stabilize_2d_remove_exec(bContext *C, wmOperator *UNUSED(op))
}
if (update) {
- stab->ok = 0;
DAG_id_tag_update(&clip->id, 0);
WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
}
@@ -151,7 +149,7 @@ void CLIP_OT_stabilize_2d_remove(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Remove Stabilization Track";
- ot->description = "Remove selected track from stabilization";
+ ot->description = "Remove selected track from translation stabilization";
ot->idname = "CLIP_OT_stabilize_2d_remove";
/* api callbacks */
@@ -193,7 +191,7 @@ void CLIP_OT_stabilize_2d_select(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Select Stabilization Tracks";
- ot->description = "Select tracks which are used for stabilization";
+ ot->description = "Select tracks which are used for translation stabilization";
ot->idname = "CLIP_OT_stabilize_2d_select";
/* api callbacks */
@@ -204,20 +202,85 @@ void CLIP_OT_stabilize_2d_select(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/***************** set 2d stabilization rotation track operator ****************/
+/********************** add 2d stabilization tracks for rotation operator ****************/
-static int stabilize_2d_set_rotation_exec(bContext *C, wmOperator *UNUSED(op))
+static int stabilize_2d_rotation_add_exec(bContext *C, wmOperator *UNUSED(op))
{
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
- MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ MovieTrackingStabilization *stab = &tracking->stabilization;
+
+ bool update = false;
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ if (TRACK_VIEW_SELECTED(sc, track) &&
+ (track->flag & TRACK_USE_2D_STAB_ROT) == 0)
+ {
+ track->flag |= TRACK_USE_2D_STAB_ROT;
+ stab->tot_rot_track++;
+ update = true;
+ }
+ }
+
+ if (update) {
+ DAG_id_tag_update(&clip->id, 0);
+ WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_stabilize_2d_rotation_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Stabilization Rotation Tracks";
+ ot->description = "Add selected tracks to 2D rotation stabilization";
+ ot->idname = "CLIP_OT_stabilize_2d_rotation_add";
+
+ /* api callbacks */
+ ot->exec = stabilize_2d_rotation_add_exec;
+ ot->poll = stabilize_2d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/********************** remove 2d stabilization tracks for rotation operator *************/
+
+static int stabilize_2d_rotation_remove_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingStabilization *stab = &tracking->stabilization;
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ int a = 0;
+ bool update = false;
- if (act_track != NULL) {
- MovieTrackingStabilization *stab = &tracking->stabilization;
- stab->rot_track = act_track;
- stab->ok = 0;
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ if (track->flag & TRACK_USE_2D_STAB_ROT) {
+ if (a == stab->act_rot_track) {
+ track->flag &= ~TRACK_USE_2D_STAB_ROT;
+ stab->act_rot_track--;
+ stab->tot_rot_track--;
+ if (stab->act_rot_track < 0) {
+ stab->act_rot_track = 0;
+ }
+ update = true;
+ break;
+ }
+ a++;
+ }
+ }
+ if (update) {
DAG_id_tag_update(&clip->id, 0);
WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
}
@@ -225,18 +288,60 @@ static int stabilize_2d_set_rotation_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-void CLIP_OT_stabilize_2d_set_rotation(wmOperatorType *ot)
+void CLIP_OT_stabilize_2d_rotation_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Stabilization Rotation Track";
+ ot->description = "Remove selected track from rotation stabilization";
+ ot->idname = "CLIP_OT_stabilize_2d_rotation_remove";
+
+ /* api callbacks */
+ ot->exec = stabilize_2d_rotation_remove_exec;
+ ot->poll = stabilize_2d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/********************** select 2d stabilization rotation tracks operator *****************/
+
+static int stabilize_2d_rotation_select_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ bool update = false;
+
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ if (track->flag & TRACK_USE_2D_STAB_ROT) {
+ BKE_tracking_track_flag_set(track, TRACK_AREA_ALL, SELECT);
+ update = true;
+ }
+ }
+
+ if (update) {
+ WM_event_add_notifier(C, NC_MOVIECLIP | ND_SELECT, clip);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_stabilize_2d_rotation_select(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Set Rotation Track";
- ot->description = "Use active track to compensate rotation when "
- "doing 2D stabilization";
- ot->idname = "CLIP_OT_stabilize_2d_set_rotation";
+ ot->name = "Select Stabilization Rotation Tracks";
+ ot->description = "Select tracks which are used for rotation stabilization";
+ ot->idname = "CLIP_OT_stabilize_2d_rotation_select";
/* api callbacks */
- ot->exec = stabilize_2d_set_rotation_exec;
+ ot->exec = stabilize_2d_rotation_select_exec;
ot->poll = stabilize_2d_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c
index 182f2bd2e80..97a85bce006 100644
--- a/source/blender/editors/space_console/space_console.c
+++ b/source/blender/editors/space_console/space_console.c
@@ -27,10 +27,6 @@
#include <string.h>
#include <stdio.h>
-#ifdef WIN32
-# include "BLI_winstuff.h"
-#endif
-
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index d83a7d5ea62..b7228f634bf 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -208,7 +208,7 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
BLI_add_slash(params->dir);
}
- ED_file_change_dir(C, false);
+ ED_file_change_dir(C);
retval = FILE_SELECT_DIR;
}
}
@@ -826,7 +826,7 @@ static int bookmark_select_exec(bContext *C, wmOperator *op)
RNA_property_string_get(op->ptr, prop, entry);
BLI_strncpy(params->dir, entry, sizeof(params->dir));
BLI_cleanup_dir(G.main->name, params->dir);
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
@@ -1061,7 +1061,8 @@ void FILE_OT_bookmark_move(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER; /* No undo! */
- RNA_def_enum(ot->srna, "direction", slot_move, 0, "Direction", "Direction to move, UP or DOWN");
+ RNA_def_enum(ot->srna, "direction", slot_move, 0, "Direction",
+ "Direction to move the active bookmark towards");
}
static int reset_recent_exec(bContext *C, wmOperator *UNUSED(op))
@@ -1379,7 +1380,7 @@ int file_exec(bContext *C, wmOperator *exec_op)
BLI_add_slash(sfile->params->dir);
}
- ED_file_change_dir(C, false);
+ ED_file_change_dir(C);
}
/* opening file - sends events now, so things get handled on windowqueue level */
else if (sfile->op) {
@@ -1447,19 +1448,7 @@ int file_parent_exec(bContext *C, wmOperator *UNUSED(unused))
if (sfile->params) {
if (BLI_parent_dir(sfile->params->dir)) {
BLI_cleanup_dir(G.main->name, sfile->params->dir);
- /* if not browsing in .blend file, we still want to check whether the path is a directory */
- if (sfile->params->type == FILE_LOADLIB) {
- char tdir[FILE_MAX];
- if (BLO_library_path_explode(sfile->params->dir, tdir, NULL, NULL)) {
- ED_file_change_dir(C, false);
- }
- else {
- ED_file_change_dir(C, true);
- }
- }
- else {
- ED_file_change_dir(C, true);
- }
+ ED_file_change_dir(C);
if (sfile->params->recursion_level > 1) {
/* Disable 'dirtree' recursion when going up in tree. */
sfile->params->recursion_level = 0;
@@ -1529,7 +1518,7 @@ int file_previous_exec(bContext *C, wmOperator *UNUSED(unused))
folderlist_popdir(sfile->folders_prev, sfile->params->dir);
folderlist_pushdir(sfile->folders_next, sfile->params->dir);
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
}
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -1561,7 +1550,7 @@ int file_next_exec(bContext *C, wmOperator *UNUSED(unused))
// update folders_prev so we can check for it in folderlist_clear_next()
folderlist_pushdir(sfile->folders_prev, sfile->params->dir);
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
}
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -1809,7 +1798,7 @@ int file_directory_new_exec(bContext *C, wmOperator *op)
if (RNA_boolean_get(op->ptr, "open")) {
BLI_strncpy(sfile->params->dir, path, sizeof(sfile->params->dir));
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
}
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -1906,17 +1895,35 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
file_expand_directory(C);
/* special case, user may have pasted a filepath into the directory */
- if (BLI_is_file(sfile->params->dir)) {
- char path[sizeof(sfile->params->dir)];
- BLI_strncpy(path, sfile->params->dir, sizeof(path));
- BLI_split_dirfile(path, sfile->params->dir, sfile->params->file, sizeof(sfile->params->dir), sizeof(sfile->params->file));
+ if (!filelist_is_dir(sfile->files, sfile->params->dir)) {
+ char tdir[FILE_MAX_LIBEXTRA];
+ char *group, *name;
+
+ if (BLI_is_file(sfile->params->dir)) {
+ char path[sizeof(sfile->params->dir)];
+ BLI_strncpy(path, sfile->params->dir, sizeof(path));
+ BLI_split_dirfile(path, sfile->params->dir, sfile->params->file,
+ sizeof(sfile->params->dir), sizeof(sfile->params->file));
+ }
+ else if (BLO_library_path_explode(sfile->params->dir, tdir, &group, &name)) {
+ if (group) {
+ BLI_path_append(tdir, sizeof(tdir), group);
+ }
+ BLI_strncpy(sfile->params->dir, tdir, sizeof(sfile->params->dir));
+ if (name) {
+ BLI_strncpy(sfile->params->file, name, sizeof(sfile->params->file));
+ }
+ else {
+ sfile->params->file[0] = '\0';
+ }
+ }
}
BLI_cleanup_dir(G.main->name, sfile->params->dir);
- if (BLI_exists(sfile->params->dir)) {
+ if (filelist_is_dir(sfile->files, sfile->params->dir)) {
/* if directory exists, enter it immediately */
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
/* don't do for now because it selects entire text instead of
* placing cursor at the end */
@@ -1931,20 +1938,26 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
#endif
else {
const char *lastdir = folderlist_peeklastdir(sfile->folders_prev);
+ char tdir[FILE_MAX_LIBEXTRA];
- /* if not, ask to create it and enter if confirmed */
- wmOperatorType *ot = WM_operatortype_find("FILE_OT_directory_new", false);
- PointerRNA ptr;
- WM_operator_properties_create_ptr(&ptr, ot);
- RNA_string_set(&ptr, "directory", sfile->params->dir);
- RNA_boolean_set(&ptr, "open", true);
-
- if (lastdir)
+ /* If we are 'inside' a blend library, we cannot do anything... */
+ if (lastdir && BLO_library_path_explode(lastdir, tdir, NULL, NULL)) {
BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir));
-
-
- WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
- WM_operator_properties_free(&ptr);
+ }
+ else {
+ /* if not, ask to create it and enter if confirmed */
+ wmOperatorType *ot = WM_operatortype_find("FILE_OT_directory_new", false);
+ PointerRNA ptr;
+ WM_operator_properties_create_ptr(&ptr, ot);
+ RNA_string_set(&ptr, "directory", sfile->params->dir);
+ RNA_boolean_set(&ptr, "open", true);
+
+ if (lastdir)
+ BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir));
+
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
+ WM_operator_properties_free(&ptr);
+ }
}
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -1971,8 +1984,6 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg
BLI_filename_make_safe(sfile->params->file);
if (matches) {
- /* int i, numfiles = filelist_numfiles(sfile->files); */ /* XXX UNUSED */
- sfile->params->file[0] = '\0';
/* replace the pattern (or filename that the user typed in, with the first selected file of the match */
BLI_strncpy(sfile->params->file, matched_file, sizeof(sfile->params->file));
@@ -1980,30 +1991,17 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg
}
if (matches == 1) {
-
BLI_join_dirfile(filepath, sizeof(sfile->params->dir), sfile->params->dir, sfile->params->file);
/* if directory, open it and empty filename field */
- if (BLI_is_dir(filepath)) {
+ if (filelist_is_dir(sfile->files, filepath)) {
BLI_cleanup_dir(G.main->name, filepath);
BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir));
sfile->params->file[0] = '\0';
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
UI_textbutton_activate_but(C, but);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
}
- else if (sfile->params->type == FILE_LOADLIB) {
- char tdir[FILE_MAX];
- BLI_add_slash(filepath);
- if (BLO_library_path_explode(filepath, tdir, NULL, NULL)) {
- BLI_cleanup_dir(G.main->name, filepath);
- BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir));
- sfile->params->file[0] = '\0';
- ED_file_change_dir(C, false);
- UI_textbutton_activate_but(C, but);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
- }
- }
}
else if (matches > 1) {
file_draw_check(C);
diff --git a/source/blender/editors/space_file/file_utils.c b/source/blender/editors/space_file/file_utils.c
index 3c007f25da3..c1caf5ae8ac 100644
--- a/source/blender/editors/space_file/file_utils.c
+++ b/source/blender/editors/space_file/file_utils.c
@@ -25,6 +25,9 @@
*/
#include "BLI_rect.h"
+#include "BLI_fileops.h"
+
+#include "BLO_readfile.h"
#include "BKE_context.h"
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 8e1f781827a..6af36ea6778 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -309,8 +309,9 @@ typedef struct FileList {
struct BlendHandle *libfiledata;
- /* Set given path as root directory, may change given string in place to a valid value. */
- void (*checkdirf)(struct FileList *, char *);
+ /* Set given path as root directory, if last bool is true may change given string in place to a valid value.
+ * Returns True if valid dir. */
+ bool (*checkdirf)(struct FileList *, char *, const bool);
/* Fill filelist (to be called by read job). */
void (*read_jobf)(struct FileList *, const char *, short *, short *, float *, ThreadMutex *);
@@ -624,7 +625,7 @@ static bool is_filtered_file(FileListInternEntry *file, const char *UNUSED(root)
static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileListFilter *filter)
{
bool is_filtered;
- char path[FILE_MAX_LIBEXTRA], dir[FILE_MAXDIR], *group, *name;
+ char path[FILE_MAX_LIBEXTRA], dir[FILE_MAX_LIBEXTRA], *group, *name;
BLI_join_dirfile(path, sizeof(path), root, file->relpath);
@@ -697,7 +698,7 @@ void filelist_filter(FileList *filelist)
if (filelist->max_recursion) {
/* Never show lib ID 'categories' directories when we are in 'flat' mode, unless
* root path is a blend file. */
- char dir[FILE_MAXDIR];
+ char dir[FILE_MAX_LIBEXTRA];
if (!filelist_islibrary(filelist, dir, NULL)) {
filelist->filter_data.flags |= FLF_HIDE_LIB_DIR;
}
@@ -920,6 +921,8 @@ static int filelist_geticon_ex(
return ICON_FILE_BLANK;
else if (typeflag & FILE_TYPE_COLLADA)
return ICON_FILE_BLANK;
+ else if (typeflag & FILE_TYPE_ALEMBIC)
+ return ICON_FILE_BLANK;
else if (typeflag & FILE_TYPE_TEXT)
return ICON_FILE_TEXT;
else if (typeflag & FILE_TYPE_BLENDERLIB) {
@@ -940,24 +943,37 @@ int filelist_geticon(struct FileList *filelist, const int index, const bool is_m
/* ********** Main ********** */
-static void filelist_checkdir_dir(struct FileList *UNUSED(filelist), char *r_dir)
+static bool filelist_checkdir_dir(struct FileList *UNUSED(filelist), char *r_dir, const bool do_change)
{
- BLI_make_exist(r_dir);
+ if (do_change) {
+ BLI_make_exist(r_dir);
+ return true;
+ }
+ else {
+ return BLI_is_dir(r_dir);
+ }
}
-static void filelist_checkdir_lib(struct FileList *UNUSED(filelist), char *r_dir)
+static bool filelist_checkdir_lib(struct FileList *UNUSED(filelist), char *r_dir, const bool do_change)
{
- char dir[FILE_MAXDIR];
- if (!BLO_library_path_explode(r_dir, dir, NULL, NULL)) {
+ char tdir[FILE_MAX_LIBEXTRA];
+ char *name;
+
+ const bool is_valid = (BLI_is_dir(r_dir) ||
+ (BLO_library_path_explode(r_dir, tdir, NULL, &name) && BLI_is_file(tdir) && !name));
+
+ if (do_change && !is_valid) {
/* if not a valid library, we need it to be a valid directory! */
BLI_make_exist(r_dir);
+ return true;
}
+ return is_valid;
}
-static void filelist_checkdir_main(struct FileList *filelist, char *r_dir)
+static bool filelist_checkdir_main(struct FileList *filelist, char *r_dir, const bool do_change)
{
/* TODO */
- filelist_checkdir_lib(filelist, r_dir);
+ return filelist_checkdir_lib(filelist, r_dir, do_change);
}
static void filelist_entry_clear(FileDirEntry *entry)
@@ -1376,6 +1392,11 @@ const char *filelist_dir(struct FileList *filelist)
return filelist->filelist.root;
}
+bool filelist_is_dir(struct FileList *filelist, const char *path)
+{
+ return filelist->checkdirf(filelist, (char *)path, false);
+}
+
/**
* May modify in place given r_dir, which is expected to be FILE_MAX_LIBEXTRA length.
*/
@@ -1384,7 +1405,9 @@ void filelist_setdir(struct FileList *filelist, char *r_dir)
BLI_assert(strlen(r_dir) < FILE_MAX_LIBEXTRA);
BLI_cleanup_dir(G.main->name, r_dir);
- filelist->checkdirf(filelist, r_dir);
+ const bool is_valid_path = filelist->checkdirf(filelist, r_dir, true);
+ BLI_assert(is_valid_path);
+ UNUSED_VARS_NDEBUG(is_valid_path);
if (!STREQ(filelist->filelist.root, r_dir)) {
BLI_strncpy(filelist->filelist.root, r_dir, sizeof(filelist->filelist.root));
@@ -1630,6 +1653,7 @@ bool filelist_file_cache_block(struct FileList *filelist, const int index)
int start_index = max_ii(0, index - (cache_size / 2));
int end_index = min_ii(nbr_entries, index + (cache_size / 2));
int i;
+ const bool full_refresh = (filelist->flags & FL_IS_READY) == 0;
if ((index < 0) || (index >= nbr_entries)) {
// printf("Wrong index %d ([%d:%d])", index, 0, nbr_entries);
@@ -1652,8 +1676,8 @@ bool filelist_file_cache_block(struct FileList *filelist, const int index)
// start_index, end_index, index, cache->block_start_index, cache->block_end_index);
/* If we have something to (re)cache... */
- if ((start_index != cache->block_start_index) || (end_index != cache->block_end_index)) {
- if ((start_index >= cache->block_end_index) || (end_index <= cache->block_start_index)) {
+ if (full_refresh || (start_index != cache->block_start_index) || (end_index != cache->block_end_index)) {
+ if (full_refresh || (start_index >= cache->block_end_index) || (end_index <= cache->block_start_index)) {
int size1 = cache->block_end_index - cache->block_start_index;
int size2 = 0;
int idx1 = cache->block_cursor, idx2 = 0;
@@ -1925,7 +1949,8 @@ static bool file_is_blend_backup(const char *str)
return (retval);
}
-static int path_extension_type(const char *path)
+/* TODO: Maybe we should move this to BLI? On the other hand, it's using defines from spacefile area, so not sure... */
+int ED_path_extension_type(const char *path)
{
if (BLO_has_bfile_extension(path)) {
return FILE_TYPE_BLENDER;
@@ -1951,6 +1976,9 @@ static int path_extension_type(const char *path)
else if (BLI_testextensie(path, ".dae")) {
return FILE_TYPE_COLLADA;
}
+ else if (BLI_testextensie(path, ".abc")) {
+ return FILE_TYPE_ALEMBIC;
+ }
else if (BLI_testextensie_array(path, imb_ext_image) ||
(G.have_quicktime && BLI_testextensie_array(path, imb_ext_image_qt)))
{
@@ -1977,12 +2005,12 @@ static int file_extension_type(const char *dir, const char *relpath)
{
char path[FILE_MAX];
BLI_join_dirfile(path, sizeof(path), dir, relpath);
- return path_extension_type(path);
+ return ED_path_extension_type(path);
}
int ED_file_extension_icon(const char *path)
{
- int type = path_extension_type(path);
+ const int type = ED_path_extension_type(path);
switch (type) {
case FILE_TYPE_BLENDER:
@@ -2003,6 +2031,8 @@ int ED_file_extension_icon(const char *path)
return ICON_FILE_BLANK;
case FILE_TYPE_COLLADA:
return ICON_FILE_BLANK;
+ case FILE_TYPE_ALEMBIC:
+ return ICON_FILE_BLANK;
case FILE_TYPE_TEXT:
return ICON_FILE_TEXT;
default:
@@ -2112,6 +2142,7 @@ unsigned int filelist_entry_select_index_get(FileList *filelist, const int index
return 0;
}
+/* WARNING! dir must be FILE_MAX_LIBEXTRA long! */
bool filelist_islibrary(struct FileList *filelist, char *dir, char **group)
{
return BLO_library_path_explode(filelist->filelist.root, dir, group, NULL);
@@ -2207,7 +2238,7 @@ static int filelist_readjob_list_lib(const char *root, ListBase *entries, const
FileListInternEntry *entry;
LinkNode *ln, *names;
int i, nnames, idcode = 0, nbr_entries = 0;
- char dir[FILE_MAX], *group;
+ char dir[FILE_MAX_LIBEXTRA], *group;
bool ok;
struct BlendHandle *libfiledata = NULL;
diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h
index d70faab1d6a..f4304681780 100644
--- a/source/blender/editors/space_file/filelist.h
+++ b/source/blender/editors/space_file/filelist.h
@@ -86,6 +86,7 @@ void filelist_clear_ex(struct FileList *filelist, const bool do_c
void filelist_free(struct FileList *filelist);
const char * filelist_dir(struct FileList *filelist);
+bool filelist_is_dir(struct FileList *filelist, const char *path);
void filelist_setdir(struct FileList *filelist, char *r_dir);
int filelist_files_ensure(struct FileList *filelist);
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index bf90a4ea170..7abe5ff5070 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -185,6 +185,8 @@ short ED_fileselect_set_params(SpaceFile *sfile)
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_BTX : 0;
if ((prop = RNA_struct_find_property(op->ptr, "filter_collada")))
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_COLLADA : 0;
+ if ((prop = RNA_struct_find_property(op->ptr, "filter_alembic")))
+ params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_ALEMBIC : 0;
if ((prop = RNA_struct_find_property(op->ptr, "filter_glob"))) {
/* Protection against pyscripts not setting proper size limit... */
char *tmp = RNA_property_string_get_alloc(
@@ -213,7 +215,7 @@ short ED_fileselect_set_params(SpaceFile *sfile)
FILTER_ID_GR | FILTER_ID_IM | FILTER_ID_LA | FILTER_ID_LS | FILTER_ID_LT | FILTER_ID_MA |
FILTER_ID_MB | FILTER_ID_MC | FILTER_ID_ME | FILTER_ID_MSK | FILTER_ID_NT | FILTER_ID_OB |
FILTER_ID_PA | FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_SCE | FILTER_ID_SPK | FILTER_ID_SO |
- FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO;
+ FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO | FILTER_ID_CF;
if (U.uiflag & USER_HIDE_DOT) {
params->flag |= FILE_HIDE_DOT;
@@ -576,7 +578,7 @@ FileLayout *ED_fileselect_get_layout(struct SpaceFile *sfile, ARegion *ar)
return sfile->layout;
}
-void ED_file_change_dir(bContext *C, const bool checkdir)
+void ED_file_change_dir(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
@@ -590,7 +592,7 @@ void ED_file_change_dir(bContext *C, const bool checkdir)
sfile->params->filter_search[0] = '\0';
sfile->params->active_file = -1;
- if (checkdir && !BLI_is_dir(sfile->params->dir)) {
+ if (!filelist_is_dir(sfile->files, sfile->params->dir)) {
BLI_strncpy(sfile->params->dir, filelist_dir(sfile->files), sizeof(sfile->params->dir));
/* could return but just refresh the current dir */
}
@@ -618,7 +620,7 @@ int file_select_match(struct SpaceFile *sfile, const char *pattern, char *matche
*/
for (i = 0; i < n; i++) {
file = filelist_file(sfile->files, i);
- /* Do not check wether file is a file or dir here! Causes T44243 (we do accept dirs at this stage). */
+ /* Do not check whether file is a file or dir here! Causes T44243 (we do accept dirs at this stage). */
if (fnmatch(pattern, file->relpath, 0) == 0) {
filelist_entry_select_set(sfile->files, file, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
if (!match) {
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index e71c05d19c5..631ff06a77a 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -518,14 +518,18 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
CFURLEnumeratorRef volEnum = CFURLEnumeratorCreateForMountedVolumes(NULL, kCFURLEnumeratorSkipInvisibles, NULL);
while (result != kCFURLEnumeratorEnd) {
- unsigned char defPath[FILE_MAX];
+ char defPath[FILE_MAX];
result = CFURLEnumeratorGetNextURL(volEnum, &cfURL, NULL);
if (result != kCFURLEnumeratorSuccess)
continue;
CFURLGetFileSystemRepresentation(cfURL, false, (UInt8 *)defPath, FILE_MAX);
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, (char *)defPath, NULL, FS_INSERT_SORTED);
+
+ /* Add end slash for consistency with other platforms */
+ BLI_add_slash(defPath);
+
+ fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, defPath, NULL, FS_INSERT_SORTED);
}
CFRelease(volEnum);
@@ -559,6 +563,9 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
if (pathString == NULL || !CFStringGetCString(pathString, line, sizeof(line), kCFStringEncodingUTF8))
continue;
+ /* Add end slash for consistency with other platforms */
+ BLI_add_slash(line);
+
/* Exclude "all my files" as it makes no sense in blender fileselector */
/* Exclude "airdrop" if wlan not active as it would show "" ) */
if (!strstr(line, "myDocuments.cannedSearch") && (*line != '\0')) {
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index 7fb294529c9..374db92297d 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -435,6 +435,7 @@ static void file_operatortypes(void)
WM_operatortype_append(FILE_OT_bookmark_cleanup);
WM_operatortype_append(FILE_OT_bookmark_move);
WM_operatortype_append(FILE_OT_reset_recent);
+ WM_operatortype_append(FILE_OT_hidedot);
WM_operatortype_append(FILE_OT_filenum);
WM_operatortype_append(FILE_OT_directory_new);
WM_operatortype_append(FILE_OT_delete);
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index a9ab1502e16..516814b63b4 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -812,6 +812,11 @@ static void graph_panel_drivers(const bContext *C, Panel *pa)
}
col = uiLayoutColumn(pa->layout, true);
+
+ if (driver->type == DRIVER_TYPE_PYTHON) {
+ uiItemR(col, &driver_ptr, "use_self", 0, NULL, ICON_NONE);
+ }
+
/* debug setting */
uiItemR(col, &driver_ptr, "show_debug_info", 0, NULL, ICON_NONE);
@@ -1062,7 +1067,7 @@ void GRAPH_OT_properties(wmOperatorType *ot)
{
ot->name = "Properties";
ot->idname = "GRAPH_OT_properties";
- ot->description = "Toggle display properties panel";
+ ot->description = "Toggle the properties region visibility";
ot->exec = graph_properties_toggle_exec;
ot->poll = ED_operator_graphedit_active;
diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c
index 3ac90200aea..96a078b2817 100644
--- a/source/blender/editors/space_graph/graph_draw.c
+++ b/source/blender/editors/space_graph/graph_draw.c
@@ -826,7 +826,7 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
//if ((driver->flag & DRIVER_FLAG_SHOWDEBUG) == 0)
// return;
- /* No curve to modify/visualise the result?
+ /* No curve to modify/visualize the result?
* => We still want to show the 1-1 default...
*/
if ((fcu->totvert == 0) && BLI_listbase_is_empty(&fcu->modifiers)) {
@@ -1130,18 +1130,18 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
* - offset of ACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for
* start of list offset, and the second is as a correction for the scrollers.
*/
- height = (float)((items * ACHANNEL_STEP) + (ACHANNEL_HEIGHT * 2));
- UI_view2d_totRect_set(v2d, ar->winx, height);
+ height = (float)((items * ACHANNEL_STEP(ac)) + (ACHANNEL_HEIGHT(ac) * 2));
+ UI_view2d_totRect_set(v2d, BLI_rcti_size_x(&ar->v2d.mask), height);
/* loop through channels, and set up drawing depending on their type */
{ /* first pass: just the standard GL-drawing for backdrop + text */
size_t channel_index = 0;
- y = (float)ACHANNEL_FIRST;
+ y = (float)ACHANNEL_FIRST(ac);
for (ale = anim_data.first, i = 0; ale; ale = ale->next, i++) {
- const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF);
- const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF);
+ const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac));
+ const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac));
/* check if visible */
if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
@@ -1152,7 +1152,7 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
}
/* adjust y-position for next one */
- y -= ACHANNEL_STEP;
+ y -= ACHANNEL_STEP(ac);
channel_index++;
}
}
@@ -1160,15 +1160,15 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
size_t channel_index = 0;
- y = (float)ACHANNEL_FIRST;
+ y = (float)ACHANNEL_FIRST(ac);
/* set blending again, as may not be set in previous step */
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
for (ale = anim_data.first, i = 0; ale; ale = ale->next, i++) {
- const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF);
- const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF);
+ const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac));
+ const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac));
/* check if visible */
if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
@@ -1179,7 +1179,7 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
}
/* adjust y-position for next one */
- y -= ACHANNEL_STEP;
+ y -= ACHANNEL_STEP(ac);
channel_index++;
}
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index f1063996ca3..f38d36853d7 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -606,10 +606,13 @@ static void insert_graph_keys(bAnimContext *ac, eGraphKeys_InsertKey_Types mode)
* - fcu->driver != NULL: If this is set, then it's a driver. If we don't check for this, we'd end
* up adding the keyframes on a new F-Curve in the action data instead.
*/
- if (ale->id && !ale->owner && !fcu->driver)
+ if (ale->id && !ale->owner && !fcu->driver) {
insert_keyframe(reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, ts->keyframe_type, flag);
- else
- insert_vert_fcurve(fcu, cfra, fcu->curval, ts->keyframe_type, 0);
+ }
+ else {
+ const float curval = evaluate_fcurve(fcu, cfra);
+ insert_vert_fcurve(fcu, cfra, curval, ts->keyframe_type, 0);
+ }
ale->update |= ANIM_UPDATE_DEFAULT;
}
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index 6b860990c10..75f0da83e77 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -555,19 +555,20 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_ALT, 0);
RNA_boolean_set(kmi->ptr, "axis_range", true);
RNA_boolean_set(kmi->ptr, "include_handles", false);
-
+
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_CTRL, 0);
RNA_boolean_set(kmi->ptr, "axis_range", false);
RNA_boolean_set(kmi->ptr, "include_handles", true);
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
RNA_boolean_set(kmi->ptr, "axis_range", true);
RNA_boolean_set(kmi->ptr, "include_handles", true);
-
+
+ /* region select */
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0);
RNA_boolean_set(kmi->ptr, "deselect", false);
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "deselect", true);
-
+
WM_keymap_add_item(keymap, "GRAPH_OT_select_circle", CKEY, KM_PRESS, 0, 0);
/* column select */
@@ -631,7 +632,9 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
/* auto-set range */
WM_keymap_add_item(keymap, "GRAPH_OT_previewrange_set", PKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
+#ifdef WITH_INPUT_NDOF
WM_keymap_add_item(keymap, "GRAPH_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
+#endif
WM_keymap_add_item(keymap, "GRAPH_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_view_frame", PAD0, KM_PRESS, 0, 0);
diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c
index eb786d872ec..67b960bfa53 100644
--- a/source/blender/editors/space_graph/graph_select.c
+++ b/source/blender/editors/space_graph/graph_select.c
@@ -210,6 +210,8 @@ void GRAPH_OT_select_all_toggle(wmOperatorType *ot)
* -> ALT-BKEY - depending on which axis of the region was larger...
* -> 2) x-axis, so select all frames within frame range (validation with BEZT_OK_FRAMERANGE)
* -> 3) y-axis, so select all frames within channels that region included (validation with BEZT_OK_VALUERANGE)
+ *
+ * The selection backend is also reused for the Lasso and Circle select operators.
*/
/* Borderselect only selects keyframes now, as overshooting handles often get caught too,
@@ -245,12 +247,12 @@ static void borderselect_graphkeys(
/* init editing data */
memset(&ked, 0, sizeof(KeyframeEditData));
if (mode == BEZT_OK_REGION_LASSO) {
- struct KeyframeEdit_LassoData *data_lasso = data;
+ KeyframeEdit_LassoData *data_lasso = data;
data_lasso->rectf_scaled = &scaled_rectf;
ked.data = data_lasso;
}
else if (mode == BEZT_OK_REGION_CIRCLE) {
- struct KeyframeEdit_CircleData *data_circle = data;
+ KeyframeEdit_CircleData *data_circle = data;
data_circle->rectf_scaled = &scaled_rectf;
ked.data = data;
}
@@ -265,27 +267,27 @@ static void borderselect_graphkeys(
}
else
mapping_flag = ANIM_UNITCONV_ONLYKEYS;
-
+
mapping_flag |= ANIM_get_normalization_flags(ac);
-
+
/* loop over data, doing border select */
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
FCurve *fcu = (FCurve *)ale->key_data;
float offset;
float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset);
-
+
/* apply NLA mapping to all the keyframes, since it's easier than trying to
* guess when a callback might use something different
*/
if (adt)
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, incl_handles == 0);
-
+
scaled_rectf.xmin = rectf.xmin;
scaled_rectf.xmax = rectf.xmax;
scaled_rectf.ymin = rectf.ymin / unit_scale - offset;
scaled_rectf.ymax = rectf.ymax / unit_scale - offset;
-
+
/* set horizontal range (if applicable)
* NOTE: these values are only used for x-range and y-range but not region
* (which uses ked.data, i.e. rectf)
@@ -406,37 +408,41 @@ void GRAPH_OT_select_border(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "include_handles", 0, "Include Handles", "Are handles tested individually against the selection criteria");
}
+
+/* ------------------- */
+
static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
+
+ KeyframeEdit_LassoData data_lasso = {0};
rcti rect;
rctf rect_fl;
+
short selectmode;
bool incl_handles;
bool extend;
-
- struct KeyframeEdit_LassoData data_lasso;
-
+
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
-
+
data_lasso.rectf_view = &rect_fl;
data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot);
if (data_lasso.mcords == NULL)
return OPERATOR_CANCELLED;
-
+
/* clear all selection if not extending selection */
extend = RNA_boolean_get(op->ptr, "extend");
if (!extend)
deselect_graph_keys(&ac, 1, SELECT_SUBTRACT, true);
-
+
if (!RNA_boolean_get(op->ptr, "deselect"))
selectmode = SELECT_ADD;
else
selectmode = SELECT_SUBTRACT;
-
- if (ac.spacetype == SPACE_IPO) {
+
+ {
SpaceIpo *sipo = (SpaceIpo *)ac.sl;
if (selectmode == SELECT_ADD) {
incl_handles = ((sipo->flag & SIPO_SELVHANDLESONLY) ||
@@ -446,60 +452,57 @@ static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op)
incl_handles = (sipo->flag & SIPO_NOHANDLES) == 0;
}
}
- else {
- incl_handles = false;
- }
-
-
+
/* get settings from operator */
BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot);
-
BLI_rctf_rcti_copy(&rect_fl, &rect);
-
+
/* apply borderselect action */
borderselect_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_LASSO, selectmode, incl_handles, &data_lasso);
-
+
MEM_freeN((void *)data_lasso.mcords);
-
-
+
/* send notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+
return OPERATOR_FINISHED;
}
-
void GRAPH_OT_select_lasso(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Lasso Select";
ot->description = "Select keyframe points using lasso selection";
ot->idname = "GRAPH_OT_select_lasso";
-
+
/* api callbacks */
ot->invoke = WM_gesture_lasso_invoke;
ot->modal = WM_gesture_lasso_modal;
ot->exec = graphkeys_lassoselect_exec;
ot->poll = graphop_visible_keyframes_poll;
ot->cancel = WM_gesture_lasso_cancel;
-
+
/* flags */
ot->flag = OPTYPE_UNDO;
-
+
/* properties */
RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Deselect rather than select items");
RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first");
}
+/* ------------------- */
+
static int graph_circle_select_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
const int gesture_mode = RNA_int_get(op->ptr, "gesture_mode");
- short selectmode;
- bool incl_handles;
+ const short selectmode = (gesture_mode == GESTURE_MODAL_SELECT) ? SELECT_ADD : SELECT_SUBTRACT;
+ bool incl_handles = false;
+
+ KeyframeEdit_CircleData data = {0};
rctf rect_fl;
- struct KeyframeEdit_CircleData data;
+
float x = RNA_int_get(op->ptr, "x");
float y = RNA_int_get(op->ptr, "y");
float radius = RNA_int_get(op->ptr, "radius");
@@ -507,23 +510,18 @@ static int graph_circle_select_exec(bContext *C, wmOperator *op)
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
-
+
data.mval[0] = x;
data.mval[1] = y;
data.radius_squared = radius * radius;
data.rectf_view = &rect_fl;
- if (gesture_mode == GESTURE_MODAL_SELECT)
- selectmode = SELECT_ADD;
- else
- selectmode = SELECT_SUBTRACT;
-
rect_fl.xmin = x - radius;
rect_fl.xmax = x + radius;
rect_fl.ymin = y - radius;
rect_fl.ymax = y + radius;
- if (ac.spacetype == SPACE_IPO) {
+ {
SpaceIpo *sipo = (SpaceIpo *)ac.sl;
if (selectmode == SELECT_ADD) {
incl_handles = ((sipo->flag & SIPO_SELVHANDLESONLY) ||
@@ -533,10 +531,7 @@ static int graph_circle_select_exec(bContext *C, wmOperator *op)
incl_handles = (sipo->flag & SIPO_NOHANDLES) == 0;
}
}
- else {
- incl_handles = false;
- }
-
+
/* apply borderselect action */
borderselect_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_CIRCLE, selectmode, incl_handles, &data);
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index c6a8a9753d1..f12db310856 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -33,6 +33,7 @@
#include <stdio.h>
#include "DNA_anim_types.h"
+#include "DNA_group_types.h"
#include "DNA_scene_types.h"
#include "MEM_guardedalloc.h"
@@ -334,8 +335,8 @@ static void graph_channel_region_init(wmWindowManager *wm, ARegion *ar)
wmKeyMap *keymap;
/* make sure we keep the hide flags */
- ar->v2d.scroll |= (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM);
- ar->v2d.scroll &= ~(V2D_SCROLL_LEFT | V2D_SCROLL_TOP); /* prevent any noise of past */
+ ar->v2d.scroll |= V2D_SCROLL_RIGHT;
+ ar->v2d.scroll &= ~(V2D_SCROLL_LEFT | V2D_SCROLL_TOP | V2D_SCROLL_BOTTOM); /* prevent any noise of past */
ar->v2d.scroll |= V2D_SCROLL_HORIZONTAL_HIDE;
ar->v2d.scroll |= V2D_SCROLL_VERTICAL_HIDE;
@@ -524,12 +525,130 @@ static void graph_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
}
}
-
+/* Update F-Curve colors */
+static void graph_refresh_fcurve_colors(const bContext *C)
+{
+ bAnimContext ac;
+
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ size_t items;
+ int filter;
+ int i;
+
+ if (ANIM_animdata_get_context(C, &ac) == false)
+ return;
+
+ UI_SetTheme(SPACE_IPO, RGN_TYPE_WINDOW);
+
+ /* build list of F-Curves which will be visible as channels in channel-region
+ * - we don't include ANIMFILTER_CURVEVISIBLE filter, as that will result in a
+ * mismatch between channel-colors and the drawn curves
+ */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_NODUPLIS);
+ items = ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ /* loop over F-Curves, assigning colors */
+ for (ale = anim_data.first, i = 0; ale; ale = ale->next, i++) {
+ FCurve *fcu = (FCurve *)ale->data;
+
+ /* set color of curve here */
+ switch (fcu->color_mode) {
+ case FCURVE_COLOR_CUSTOM:
+ {
+ /* User has defined a custom color for this curve already (we assume it's not going to cause clashes with text colors),
+ * which should be left alone... Nothing needs to be done here.
+ */
+ break;
+ }
+ case FCURVE_COLOR_AUTO_RGB:
+ {
+ /* F-Curve's array index is automatically mapped to RGB values. This works best of 3-value vectors.
+ * TODO: find a way to module the hue so that not all curves have same color...
+ */
+ float *col = fcu->color;
+
+ switch (fcu->array_index) {
+ case 0:
+ UI_GetThemeColor3fv(TH_AXIS_X, col);
+ break;
+ case 1:
+ UI_GetThemeColor3fv(TH_AXIS_Y, col);
+ break;
+ case 2:
+ UI_GetThemeColor3fv(TH_AXIS_Z, col);
+ break;
+ default:
+ /* 'unknown' color - bluish so as to not conflict with handles */
+ col[0] = 0.3f; col[1] = 0.8f; col[2] = 1.0f;
+ break;
+ }
+ break;
+ }
+ case FCURVE_COLOR_AUTO_YRGB:
+ {
+ /* Like FCURVE_COLOR_AUTO_RGB, except this is for quaternions... */
+ float *col = fcu->color;
+
+ switch (fcu->array_index) {
+ case 1:
+ UI_GetThemeColor3fv(TH_AXIS_X, col);
+ break;
+ case 2:
+ UI_GetThemeColor3fv(TH_AXIS_Y, col);
+ break;
+ case 3:
+ UI_GetThemeColor3fv(TH_AXIS_Z, col);
+ break;
+
+ case 0:
+ {
+ /* Special Case: "W" channel should be yellowish, so blend X and Y channel colors... */
+ float c1[3], c2[3];
+ float h1[3], h2[3];
+ float hresult[3];
+
+ /* - get colors (rgb) */
+ UI_GetThemeColor3fv(TH_AXIS_X, c1);
+ UI_GetThemeColor3fv(TH_AXIS_Y, c2);
+
+ /* - perform blending in HSV space (to keep brightness similar) */
+ rgb_to_hsv_v(c1, h1);
+ rgb_to_hsv_v(c2, h2);
+
+ interp_v3_v3v3(hresult, h1, h2, 0.5f);
+
+ /* - convert back to RGB for display */
+ hsv_to_rgb_v(hresult, col);
+ break;
+ }
+
+ default:
+ /* 'unknown' color - bluish so as to not conflict with handles */
+ col[0] = 0.3f; col[1] = 0.8f; col[2] = 1.0f;
+ break;
+ }
+ break;
+ }
+ case FCURVE_COLOR_AUTO_RAINBOW:
+ default:
+ {
+ /* determine color 'automatically' using 'magic function' which uses the given args
+ * of current item index + total items to determine some RGB color
+ */
+ getcolor_fcurve_rainbow(i, items, fcu->color);
+ break;
+ }
+ }
+ }
+
+ /* free temp list */
+ ANIM_animdata_freelist(&anim_data);
+}
static void graph_refresh(const bContext *C, ScrArea *sa)
{
SpaceIpo *sipo = (SpaceIpo *)sa->spacedata.first;
- bAnimContext ac;
/* updates to data needed depends on Graph Editor mode... */
switch (sipo->mode) {
@@ -557,73 +676,19 @@ static void graph_refresh(const bContext *C, ScrArea *sa)
}
/* init/adjust F-Curve colors */
- if (ANIM_animdata_get_context(C, &ac)) {
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
- size_t items;
- int filter;
- int i;
-
- UI_SetTheme(SPACE_IPO, RGN_TYPE_WINDOW);
-
- /* build list of F-Curves which will be visible as channels in channel-region
- * - we don't include ANIMFILTER_CURVEVISIBLE filter, as that will result in a
- * mismatch between channel-colors and the drawn curves
- */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_NODUPLIS);
- items = ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
-
- /* loop over F-Curves, assigning colors */
- for (ale = anim_data.first, i = 0; ale; ale = ale->next, i++) {
- FCurve *fcu = (FCurve *)ale->data;
-
- /* set color of curve here */
- switch (fcu->color_mode) {
- case FCURVE_COLOR_CUSTOM:
- {
- /* User has defined a custom color for this curve already (we assume it's not going to cause clashes with text colors),
- * which should be left alone... Nothing needs to be done here.
- */
- break;
- }
- case FCURVE_COLOR_AUTO_RGB:
- {
- /* F-Curve's array index is automatically mapped to RGB values. This works best of 3-value vectors.
- * TODO: find a way to module the hue so that not all curves have same color...
- */
- float *col = fcu->color;
-
- switch (fcu->array_index) {
- case 0:
- UI_GetThemeColor3fv(TH_AXIS_X, col);
- break;
- case 1:
- UI_GetThemeColor3fv(TH_AXIS_Y, col);
- break;
- case 2:
- UI_GetThemeColor3fv(TH_AXIS_Z, col);
- break;
- default:
- /* 'unknown' color - bluish so as to not conflict with handles */
- col[0] = 0.3f; col[1] = 0.8f; col[2] = 1.0f;
- break;
- }
- break;
- }
- case FCURVE_COLOR_AUTO_RAINBOW:
- default:
- {
- /* determine color 'automatically' using 'magic function' which uses the given args
- * of current item index + total items to determine some RGB color
- */
- getcolor_fcurve_rainbow(i, items, fcu->color);
- break;
- }
- }
- }
-
- /* free temp list */
- ANIM_animdata_freelist(&anim_data);
+ graph_refresh_fcurve_colors(C);
+}
+
+static void graph_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceIpo *sgraph = (SpaceIpo *)slink;
+
+ if (!ELEM(GS(old_id->name), ID_GR)) {
+ return;
+ }
+
+ if (sgraph->ads && (ID *)sgraph->ads->filter_grp == old_id) {
+ sgraph->ads->filter_grp = (Group *)new_id;
}
}
@@ -644,7 +709,8 @@ void ED_spacetype_ipo(void)
st->keymap = graphedit_keymap;
st->listener = graph_listener;
st->refresh = graph_refresh;
-
+ st->id_remap = graph_id_remap;
+
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype graphedit region");
art->regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index a2db6827b0e..b9d98dfe794 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -345,6 +345,13 @@ struct ImageUI_Data {
int rpass_index;
};
+static struct ImageUI_Data *ui_imageuser_data_copy(const struct ImageUI_Data *rnd_pt_src)
+{
+ struct ImageUI_Data *rnd_pt_dst = MEM_mallocN(sizeof(*rnd_pt_src), __func__);
+ memcpy(rnd_pt_dst, rnd_pt_src, sizeof(*rnd_pt_src));
+ return rnd_pt_dst;
+}
+
static void ui_imageuser_layer_menu(bContext *UNUSED(C), uiLayout *layout, void *rnd_pt)
{
struct ImageUI_Data *rnd_data = rnd_pt;
@@ -532,9 +539,10 @@ static void ui_imageuser_view_menu_multiview(bContext *UNUSED(C), uiLayout *layo
}
/* 5 layer button callbacks... */
-static void image_multi_cb(bContext *C, void *rr_v, void *iuser_v)
+static void image_multi_cb(bContext *C, void *rnd_pt, void *rr_v)
{
- ImageUser *iuser = iuser_v;
+ struct ImageUI_Data *rnd_data = rnd_pt;
+ ImageUser *iuser = rnd_data->iuser;
BKE_image_multilayer_index(rr_v, iuser);
WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
@@ -575,6 +583,8 @@ static bool ui_imageuser_layer_menu_step(bContext *C, int direction, void *rnd_p
BLI_assert(0);
}
+ BKE_image_release_renderresult(scene, image);
+
if (changed) {
BKE_image_multilayer_index(rr, iuser);
WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
@@ -662,10 +672,11 @@ static bool ui_imageuser_pass_menu_step(bContext *C, int direction, void *rnd_pt
}
/* 5 view button callbacks... */
-static void image_multiview_cb(bContext *C, void *ima_v, void *iuser_v)
+static void image_multiview_cb(bContext *C, void *rnd_pt, void *UNUSED(arg_v))
{
- Image *ima = ima_v;
- ImageUser *iuser = iuser_v;
+ struct ImageUI_Data *rnd_data = rnd_pt;
+ Image *ima = rnd_data->image;
+ ImageUser *iuser = rnd_data->iuser;
BKE_image_multiview_index(ima, iuser);
WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
@@ -692,7 +703,7 @@ static void uiblock_layer_pass_buttons(
uiLayout *layout, Image *image, RenderResult *rr, ImageUser *iuser, int w,
short *render_slot)
{
- static struct ImageUI_Data rnd_pt; /* XXX, workaround */
+ struct ImageUI_Data rnd_pt_local, *rnd_pt = NULL;
uiBlock *block = uiLayoutGetBlock(layout);
uiBut *but;
RenderLayer *rl = NULL;
@@ -708,10 +719,10 @@ static void uiblock_layer_pass_buttons(
wmenu2 = (3 * w) / 5;
wmenu3 = (3 * w) / 6;
wmenu4 = (3 * w) / 6;
-
- rnd_pt.image = image;
- rnd_pt.iuser = iuser;
- rnd_pt.rpass_index = 0;
+
+ rnd_pt_local.image = image;
+ rnd_pt_local.iuser = iuser;
+ rnd_pt_local.rpass_index = 0;
/* menu buts */
if (render_slot) {
@@ -723,10 +734,12 @@ static void uiblock_layer_pass_buttons(
BLI_snprintf(str, sizeof(str), IFACE_("Slot %d"), *render_slot + 1);
}
+ rnd_pt = ui_imageuser_data_copy(&rnd_pt_local);
but = uiDefMenuBut(block, ui_imageuser_slot_menu, image, str, 0, 0, wmenu1, UI_UNIT_Y, TIP_("Select Slot"));
UI_but_func_menu_step_set(but, ui_imageuser_slot_menu_step);
- UI_but_func_set(but, image_multi_cb, rr, iuser);
+ UI_but_funcN_set(but, image_multi_cb, rnd_pt, rr);
UI_but_type_set_menu_from_pulldown(but);
+ rnd_pt = NULL;
}
if (rr) {
@@ -738,15 +751,18 @@ static void uiblock_layer_pass_buttons(
fake_name = ui_imageuser_layer_fake_name(rr);
rpass_index = iuser->layer - (fake_name ? 1 : 0);
rl = BLI_findlink(&rr->layers, rpass_index);
- rnd_pt.rpass_index = rpass_index;
+ rnd_pt_local.rpass_index = rpass_index;
if (RE_layers_have_name(rr)) {
display_name = rl ? rl->name : (fake_name ? fake_name : "");
- but = uiDefMenuBut(block, ui_imageuser_layer_menu, &rnd_pt, display_name,
- 0, 0, wmenu2, UI_UNIT_Y, TIP_("Select Layer"));
+ rnd_pt = ui_imageuser_data_copy(&rnd_pt_local);
+ but = uiDefMenuBut(
+ block, ui_imageuser_layer_menu, rnd_pt, display_name,
+ 0, 0, wmenu2, UI_UNIT_Y, TIP_("Select Layer"));
UI_but_func_menu_step_set(but, ui_imageuser_layer_menu_step);
- UI_but_func_set(but, image_multi_cb, rr, iuser);
+ UI_but_funcN_set(but, image_multi_cb, rnd_pt, rr);
UI_but_type_set_menu_from_pulldown(but);
+ rnd_pt = NULL;
}
/* pass */
@@ -754,11 +770,14 @@ static void uiblock_layer_pass_buttons(
rpass = (rl ? BLI_findlink(&rl->passes, iuser->pass - (fake_name ? 1 : 0)) : NULL);
display_name = rpass ? rpass->internal_name : (fake_name ? fake_name : "");
- but = uiDefMenuBut(block, ui_imageuser_pass_menu, &rnd_pt, IFACE_(display_name),
- 0, 0, wmenu3, UI_UNIT_Y, TIP_("Select Pass"));
+ rnd_pt = ui_imageuser_data_copy(&rnd_pt_local);
+ but = uiDefMenuBut(
+ block, ui_imageuser_pass_menu, rnd_pt, IFACE_(display_name),
+ 0, 0, wmenu3, UI_UNIT_Y, TIP_("Select Pass"));
UI_but_func_menu_step_set(but, ui_imageuser_pass_menu_step);
- UI_but_func_set(but, image_multi_cb, rr, iuser);
+ UI_but_funcN_set(but, image_multi_cb, rnd_pt, rr);
UI_but_type_set_menu_from_pulldown(but);
+ rnd_pt = NULL;
/* view */
if (BLI_listbase_count_ex(&rr->views, 2) > 1 &&
@@ -767,9 +786,13 @@ static void uiblock_layer_pass_buttons(
rview = BLI_findlink(&rr->views, iuser->view);
display_name = rview ? rview->name : "";
- but = uiDefMenuBut(block, ui_imageuser_view_menu_rr, &rnd_pt, display_name, 0, 0, wmenu4, UI_UNIT_Y, TIP_("Select View"));
- UI_but_func_set(but, image_multi_cb, rr, iuser);
+ rnd_pt = ui_imageuser_data_copy(&rnd_pt_local);
+ but = uiDefMenuBut(
+ block, ui_imageuser_view_menu_rr, rnd_pt, display_name,
+ 0, 0, wmenu4, UI_UNIT_Y, TIP_("Select View"));
+ UI_but_funcN_set(but, image_multi_cb, rnd_pt, rr);
UI_but_type_set_menu_from_pulldown(but);
+ rnd_pt = NULL;
}
}
@@ -787,9 +810,13 @@ static void uiblock_layer_pass_buttons(
}
}
- but = uiDefMenuBut(block, ui_imageuser_view_menu_multiview, &rnd_pt, display_name, 0, 0, wmenu1, UI_UNIT_Y, TIP_("Select View"));
- UI_but_func_set(but, image_multiview_cb, image, iuser);
+ rnd_pt = ui_imageuser_data_copy(&rnd_pt_local);
+ but = uiDefMenuBut(
+ block, ui_imageuser_view_menu_multiview, rnd_pt, display_name,
+ 0, 0, wmenu1, UI_UNIT_Y, TIP_("Select View"));
+ UI_but_funcN_set(but, image_multiview_cb, rnd_pt, NULL);
UI_but_type_set_menu_from_pulldown(but);
+ rnd_pt = NULL;
}
}
@@ -1303,7 +1330,7 @@ void IMAGE_OT_properties(wmOperatorType *ot)
{
ot->name = "Properties";
ot->idname = "IMAGE_OT_properties";
- ot->description = "Toggle display properties panel";
+ ot->description = "Toggle the properties region visibility";
ot->exec = image_properties_toggle_exec;
ot->poll = ED_operator_image_active;
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index aff0a4c3d44..e810f4db7dd 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -197,6 +197,19 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, bool color_manage, bool use_d
dx += BLF_width(blf_mono_font, str, sizeof(str));
}
+ if (channels == 1 && (cp != NULL || fp != NULL)) {
+ if (fp != NULL) {
+ BLI_snprintf(str, sizeof(str), " Val:%-.3f |", fp[0]);
+ }
+ else if (cp != NULL) {
+ BLI_snprintf(str, sizeof(str), " Val:%-.3f |", cp[0] / 255.0f);
+ }
+ glColor3ub(255, 255, 255);
+ BLF_position(blf_mono_font, dx, dy, 0);
+ BLF_draw_ascii(blf_mono_font, str, sizeof(str));
+ dx += BLF_width(blf_mono_font, str, sizeof(str));
+ }
+
if (channels >= 3) {
glColor3ubv(red);
if (fp)
diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h
index 69993c3be65..52d04ad4956 100644
--- a/source/blender/editors/space_image/image_intern.h
+++ b/source/blender/editors/space_image/image_intern.h
@@ -64,7 +64,9 @@ void IMAGE_OT_view_zoom_in(struct wmOperatorType *ot);
void IMAGE_OT_view_zoom_out(struct wmOperatorType *ot);
void IMAGE_OT_view_zoom_ratio(struct wmOperatorType *ot);
void IMAGE_OT_view_zoom_border(struct wmOperatorType *ot);
+#ifdef WITH_INPUT_NDOF
void IMAGE_OT_view_ndof(struct wmOperatorType *ot);
+#endif
void IMAGE_OT_new(struct wmOperatorType *ot);
void IMAGE_OT_open(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 88bab733013..6ca738b0e11 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -122,7 +122,7 @@ static void sima_zoom_set(SpaceImage *sima, ARegion *ar, float zoom, const float
width *= sima->zoom;
height *= sima->zoom;
- if ((width < 4) && (height < 4))
+ if ((width < 4) && (height < 4) && sima->zoom < oldzoom)
sima->zoom = oldzoom;
else if (BLI_rcti_size_x(&ar->winrct) <= sima->zoom)
sima->zoom = oldzoom;
@@ -656,6 +656,7 @@ void IMAGE_OT_view_zoom(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN);
}
+#ifdef WITH_INPUT_NDOF
/********************** NDOF operator *********************/
/* Combined pan/zoom from a 3D mouse device.
@@ -705,6 +706,7 @@ void IMAGE_OT_view_ndof(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_LOCK_BYPASS;
}
+#endif /* WITH_INPUT_NDOF */
/********************** view all operator *********************/
@@ -1061,6 +1063,12 @@ typedef struct ImageOpenData {
ImageFormatData im_format;
} ImageOpenData;
+typedef struct ImageFrameRange {
+ struct ImageFrameRange *next, *prev;
+ ListBase frames;
+ char filepath[FILE_MAX];
+} ImageFrameRange;
+
typedef struct ImageFrame {
struct ImageFrame *next, *prev;
int framenr;
@@ -1086,10 +1094,10 @@ static void image_open_cancel(bContext *UNUSED(C), wmOperator *op)
* \param frames [out] the list of frame numbers found in the files matching the first one by name
* \param path [out] the full path of the first file in the list of image files
*/
-static void image_sequence_get_frames(PointerRNA *ptr, ListBase *frames, char *path, const size_t maxlen)
+static void image_sequence_get_frame_ranges(PointerRNA *ptr, ListBase *frames_all)
{
char dir[FILE_MAXDIR];
- bool is_first_entry = true;
+ ImageFrameRange *frame_range = NULL;
RNA_string_get(ptr, "directory", dir);
RNA_BEGIN (ptr, itemptr, "files")
@@ -1101,29 +1109,26 @@ static void image_sequence_get_frames(PointerRNA *ptr, ListBase *frames, char *p
ImageFrame *frame = MEM_callocN(sizeof(ImageFrame), "image_frame");
/* use the first file in the list as base filename */
- if (is_first_entry) {
- BLI_join_dirfile(path, maxlen, dir, filename);
- frame->framenr = BLI_stringdec(filename, base_head, base_tail, &digits);
- BLI_addtail(frames, frame);
- is_first_entry = false;
+ frame->framenr = BLI_stringdec(filename, head, tail, &digits);
+
+ /* still in the same sequence */
+ if ((frame_range != NULL) &&
+ (STREQLEN(base_head, head, FILE_MAX)) &&
+ (STREQLEN(base_tail, tail, FILE_MAX)))
+ {
+ /* pass */
}
else {
- frame->framenr = BLI_stringdec(filename, head, tail, &digits);
+ /* start a new frame range */
+ frame_range = MEM_callocN(sizeof(*frame_range), __func__);
+ BLI_join_dirfile(frame_range->filepath, sizeof(frame_range->filepath), dir, filename);
+ BLI_addtail(frames_all, frame_range);
- /* still in the same sequence */
- if ((STREQLEN(base_head, head, FILE_MAX)) &&
- (STREQLEN(base_tail, tail, FILE_MAX)))
- {
- BLI_addtail(frames, frame);
- }
- else {
- /* different file base name found, is ignored */
- MEM_freeN(filename);
- MEM_freeN(frame);
- break;
- }
+ BLI_strncpy(base_head, head, sizeof(base_head));
+ BLI_strncpy(base_tail, tail, sizeof(base_tail));
}
+ BLI_addtail(&frame_range->frames, frame);
MEM_freeN(filename);
}
RNA_END
@@ -1164,6 +1169,52 @@ static int image_sequence_get_len(ListBase *frames, int *ofs)
return 0;
}
+static Image *image_open_single(
+ wmOperator *op, const char *filepath, const char *relbase,
+ bool is_relative_path, bool use_multiview, int frame_seq_len)
+{
+ bool exists = false;
+ Image *ima = NULL;
+
+ errno = 0;
+ ima = BKE_image_load_exists_ex(filepath, &exists);
+
+ if (!ima) {
+ if (op->customdata) MEM_freeN(op->customdata);
+ BKE_reportf(op->reports, RPT_ERROR, "Cannot read '%s': %s",
+ filepath, errno ? strerror(errno) : TIP_("unsupported image format"));
+ return NULL;
+ }
+
+ if (!exists) {
+ /* only image path after save, never ibuf */
+ if (is_relative_path) {
+ BLI_path_rel(ima->name, relbase);
+ }
+
+ /* handle multiview images */
+ if (use_multiview) {
+ ImageOpenData *iod = op->customdata;
+ ImageFormatData *imf = &iod->im_format;
+
+ ima->flag |= IMA_USE_VIEWS;
+ ima->views_format = imf->views_format;
+ *ima->stereo3d_format = imf->stereo3d_format;
+ }
+ else {
+ ima->flag &= ~IMA_USE_VIEWS;
+ BKE_image_free_views(ima);
+ }
+
+ if ((frame_seq_len > 1) && (ima->source == IMA_SRC_FILE)) {
+ ima->source = IMA_SRC_SEQUENCE;
+ }
+ }
+
+ return ima;
+}
+
+
static int image_open_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -1174,70 +1225,60 @@ static int image_open_exec(bContext *C, wmOperator *op)
ImageOpenData *iod = op->customdata;
PointerRNA idptr;
Image *ima = NULL;
- char path[FILE_MAX];
+ char filepath[FILE_MAX];
int frame_seq_len = 0;
int frame_ofs = 1;
- bool exists = false;
const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path");
+ const bool use_multiview = RNA_boolean_get(op->ptr, "use_multiview");
+
+ if (!op->customdata)
+ image_open_init(C, op);
- RNA_string_get(op->ptr, "filepath", path);
+ RNA_string_get(op->ptr, "filepath", filepath);
if (RNA_struct_property_is_set(op->ptr, "directory") &&
RNA_struct_property_is_set(op->ptr, "files"))
{
- /* only to pass to imbuf */
- char path_full[FILE_MAX];
- BLI_strncpy(path_full, path, sizeof(path_full));
- BLI_path_abs(path_full, G.main->name);
+ bool was_relative = BLI_path_is_rel(filepath);
+ ListBase frame_ranges_all;
- if (!IMB_isanim(path_full)) {
- bool was_relative = BLI_path_is_rel(path);
- ListBase frames;
+ BLI_listbase_clear(&frame_ranges_all);
+ image_sequence_get_frame_ranges(op->ptr, &frame_ranges_all);
+ for (ImageFrameRange *frame_range = frame_ranges_all.first; frame_range; frame_range = frame_range->next) {
+ int frame_range_ofs;
+ int frame_range_seq_len = image_sequence_get_len(&frame_range->frames, &frame_range_ofs);
+ BLI_freelistN(&frame_range->frames);
- BLI_listbase_clear(&frames);
- image_sequence_get_frames(op->ptr, &frames, path, sizeof(path));
- frame_seq_len = image_sequence_get_len(&frames, &frame_ofs);
- BLI_freelistN(&frames);
+ char filepath_range[FILE_MAX];
+ BLI_strncpy(filepath_range, frame_range->filepath, sizeof(filepath_range));
if (was_relative) {
- BLI_path_rel(path, G.main->name);
+ BLI_path_rel(filepath_range, bmain->name);
}
- }
- }
-
- errno = 0;
-
- ima = BKE_image_load_exists_ex(path, &exists);
-
- if (!ima) {
- if (op->customdata) MEM_freeN(op->customdata);
- BKE_reportf(op->reports, RPT_ERROR, "Cannot read '%s': %s",
- path, errno ? strerror(errno) : TIP_("unsupported image format"));
- return OPERATOR_CANCELLED;
- }
- if (!op->customdata)
- image_open_init(C, op);
-
- /* handle multiview images */
- if (RNA_boolean_get(op->ptr, "use_multiview")) {
- ImageFormatData *imf = &iod->im_format;
+ Image *ima_range = image_open_single(
+ op, filepath_range, bmain->name,
+ is_relative_path, use_multiview, frame_range_seq_len);
- ima->flag |= IMA_USE_VIEWS;
- ima->views_format = imf->views_format;
- *ima->stereo3d_format = imf->stereo3d_format;
+ /* take the first image */
+ if ((ima == NULL) && ima_range) {
+ ima = ima_range;
+ frame_seq_len = frame_range_seq_len;
+ frame_ofs = frame_range_ofs;
+ }
+ }
+ BLI_freelistN(&frame_ranges_all);
}
else {
- ima->flag &= ~IMA_USE_VIEWS;
- BKE_image_free_views(ima);
+ /* for drag & drop etc. */
+ ima = image_open_single(
+ op, filepath, bmain->name,
+ is_relative_path, use_multiview, 1);
}
- /* only image path after save, never ibuf */
- if (is_relative_path) {
- if (!exists) {
- BLI_path_rel(ima->name, bmain->name);
- }
+ if (ima == NULL) {
+ return OPERATOR_CANCELLED;
}
/* hook into UI */
@@ -1245,11 +1286,9 @@ static int image_open_exec(bContext *C, wmOperator *op)
if (iod->pprop.prop) {
/* when creating new ID blocks, use is already 1, but RNA
- * pointer se also increases user, so this compensates it */
+ * pointer use also increases user, so this compensates it */
id_us_min(&ima->id);
- if ((frame_seq_len > 1) && ima->source == IMA_SRC_FILE) {
- ima->source = IMA_SRC_SEQUENCE;
- }
+
RNA_id_pointer_create(&ima->id, &idptr);
RNA_property_pointer_set(&iod->pprop.ptr, iod->pprop.prop, idptr);
RNA_property_update(C, &iod->pprop.ptr, iod->pprop.prop);
@@ -1569,18 +1608,26 @@ static int save_image_options_init(SaveImageOptions *simopts, SpaceImage *sima,
/* imtype */
simopts->im_format = scene->r.im_format;
is_depth_set = true;
+ if (!BKE_image_is_multiview(ima)) {
+ /* In case multiview is disabled, render settings would be invalid for render result in this area. */
+ simopts->im_format.stereo3d_format = *ima->stereo3d_format;
+ simopts->im_format.views_format = ima->views_format;
+ }
}
else {
if (ima->source == IMA_SRC_GENERATED) {
simopts->im_format.imtype = R_IMF_IMTYPE_PNG;
simopts->im_format.compress = ibuf->foptions.quality;
+ simopts->im_format.planes = ibuf->planes;
}
else {
BKE_imbuf_to_image_format(&simopts->im_format, ibuf);
}
- }
- simopts->im_format.planes = ibuf->planes;
+ /* use the multiview image settings as the default */
+ simopts->im_format.stereo3d_format = *ima->stereo3d_format;
+ simopts->im_format.views_format = ima->views_format;
+ }
//simopts->subimtype = scene->r.subimtype; /* XXX - this is lame, we need to make these available too! */
@@ -1621,10 +1668,6 @@ static int save_image_options_init(SaveImageOptions *simopts, SpaceImage *sima,
}
}
- /* use the multiview image settings as the default */
- simopts->im_format.stereo3d_format = *ima->stereo3d_format;
- simopts->im_format.views_format = ima->views_format;
-
/* color management */
BKE_color_managed_display_settings_copy(&simopts->im_format.display_settings, &scene->display_settings);
BKE_color_managed_view_settings_copy(&simopts->im_format.view_settings, &scene->view_settings);
@@ -2359,7 +2402,7 @@ static int image_new_exec(bContext *C, wmOperator *op)
if (prop) {
/* when creating new ID blocks, use is already 1, but RNA
- * pointer se also increases user, so this compensates it */
+ * pointer use also increases user, so this compensates it */
id_us_min(&ima->id);
RNA_id_pointer_create(&ima->id, &idptr);
@@ -2503,7 +2546,7 @@ void IMAGE_OT_new(wmOperatorType *ot)
ot->flag = OPTYPE_UNDO;
/* properties */
- RNA_def_string(ot->srna, "name", IMA_DEF_NAME, MAX_ID_NAME - 2, "Name", "Image datablock name");
+ RNA_def_string(ot->srna, "name", IMA_DEF_NAME, MAX_ID_NAME - 2, "Name", "Image data-block name");
prop = RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384);
RNA_def_property_subtype(prop, PROP_PIXEL);
prop = RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384);
@@ -2804,7 +2847,7 @@ void IMAGE_OT_unpack(wmOperatorType *ot)
/* properties */
RNA_def_enum(ot->srna, "method", rna_enum_unpack_method_items, PF_USE_LOCAL, "Method", "How to unpack");
- RNA_def_string(ot->srna, "id", NULL, MAX_ID_NAME - 2, "Image Name", "Image datablock name to unpack"); /* XXX, weark!, will fail with library, name collisions */
+ RNA_def_string(ot->srna, "id", NULL, MAX_ID_NAME - 2, "Image Name", "Image data-block name to unpack"); /* XXX, weark!, will fail with library, name collisions */
}
/******************** sample image operator ********************/
@@ -2826,8 +2869,8 @@ typedef struct ImageSampleInfo {
int *zp;
float *zfp;
- int draw;
- int color_manage;
+ bool draw;
+ bool color_manage;
int use_default_view;
} ImageSampleInfo;
@@ -2901,7 +2944,7 @@ static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event
if (ibuf == NULL) {
ED_space_image_release_buffer(sima, ibuf, lock);
- info->draw = 0;
+ info->draw = false;
return;
}
@@ -2918,7 +2961,7 @@ static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event
info->x = x;
info->y = y;
- info->draw = 1;
+ info->draw = true;
info->channels = ibuf->channels;
info->colp = NULL;
@@ -2951,10 +2994,24 @@ static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event
if (ibuf->rect_float) {
fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x));
- info->colf[0] = fp[0];
- info->colf[1] = fp[1];
- info->colf[2] = fp[2];
- info->colf[3] = fp[3];
+ if (ibuf->channels == 4) {
+ info->colf[0] = fp[0];
+ info->colf[1] = fp[1];
+ info->colf[2] = fp[2];
+ info->colf[3] = fp[3];
+ }
+ else if (ibuf->channels == 3) {
+ info->colf[0] = fp[0];
+ info->colf[1] = fp[1];
+ info->colf[2] = fp[2];
+ info->colf[3] = 1.0f;
+ }
+ else {
+ info->colf[0] = fp[0];
+ info->colf[1] = fp[0];
+ info->colf[2] = fp[0];
+ info->colf[3] = 1.0f;
+ }
info->colfp = info->colf;
copy_v4_v4(info->linearcol, info->colf);
@@ -2965,10 +3022,16 @@ static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event
if (ibuf->zbuf) {
info->z = ibuf->zbuf[y * ibuf->x + x];
info->zp = &info->z;
+ if (ibuf->zbuf == (int *)ibuf->rect) {
+ info->colp = NULL;
+ }
}
if (ibuf->zbuf_float) {
info->zf = ibuf->zbuf_float[y * ibuf->x + x];
info->zfp = &info->zf;
+ if (ibuf->zbuf_float == ibuf->rect_float) {
+ info->colfp = NULL;
+ }
}
if (curve_mapping && ibuf->channels == 4) {
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 168f9c0dfdf..6ddf78290aa 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -28,6 +28,7 @@
* \ingroup spimage
*/
+#include "DNA_gpencil_types.h"
#include "DNA_mesh_types.h"
#include "DNA_mask_types.h"
#include "DNA_meshdata_types.h"
@@ -44,6 +45,7 @@
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_image.h"
+#include "BKE_library.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
@@ -233,7 +235,9 @@ static void image_operatortypes(void)
WM_operatortype_append(IMAGE_OT_view_zoom_out);
WM_operatortype_append(IMAGE_OT_view_zoom_ratio);
WM_operatortype_append(IMAGE_OT_view_zoom_border);
+#ifdef WITH_INPUT_NDOF
WM_operatortype_append(IMAGE_OT_view_ndof);
+#endif
WM_operatortype_append(IMAGE_OT_new);
WM_operatortype_append(IMAGE_OT_open);
@@ -294,8 +298,10 @@ static void image_keymap(struct wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "IMAGE_OT_view_pan", MIDDLEMOUSE, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "IMAGE_OT_view_pan", MOUSEPAN, 0, 0, 0);
+#ifdef WITH_INPUT_NDOF
WM_keymap_add_item(keymap, "IMAGE_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0); // or view selected?
WM_keymap_add_item(keymap, "IMAGE_OT_view_ndof", NDOF_MOTION, 0, 0, 0);
+#endif
WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_in", WHEELINMOUSE, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_out", WHEELOUTMOUSE, KM_PRESS, 0, 0);
@@ -981,6 +987,31 @@ static void image_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa
}
}
+static void image_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceImage *simg = (SpaceImage *)slink;
+
+ if (!ELEM(GS(old_id->name), ID_IM, ID_GD, ID_MSK)) {
+ return;
+ }
+
+ if ((ID *)simg->image == old_id) {
+ simg->image = (Image *)new_id;
+ id_us_ensure_real(new_id);
+ }
+
+ if ((ID *)simg->gpd == old_id) {
+ simg->gpd = (bGPdata *)new_id;
+ id_us_min(old_id);
+ id_us_plus(new_id);
+ }
+
+ if ((ID *)simg->mask_info.mask == old_id) {
+ simg->mask_info.mask = (Mask *)new_id;
+ id_us_ensure_real(new_id);
+ }
+}
+
/**************************** spacetype *****************************/
/* only called once, from space/spacetypes.c */
@@ -1002,7 +1033,8 @@ void ED_spacetype_image(void)
st->refresh = image_refresh;
st->listener = image_listener;
st->context = image_context;
-
+ st->id_remap = image_id_remap;
+
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype image region");
art->regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/space_logic/logic_buttons.c b/source/blender/editors/space_logic/logic_buttons.c
index 12c7ef3d3ec..e5eee21ed08 100644
--- a/source/blender/editors/space_logic/logic_buttons.c
+++ b/source/blender/editors/space_logic/logic_buttons.c
@@ -63,7 +63,7 @@ static int logic_properties_toggle_exec(bContext *C, wmOperator *UNUSED(op))
void LOGIC_OT_properties(wmOperatorType *ot)
{
ot->name = "Properties";
- ot->description = "Toggle display properties panel";
+ ot->description = "Toggle the properties region visibility";
ot->idname = "LOGIC_OT_properties";
ot->exec = logic_properties_toggle_exec;
diff --git a/source/blender/editors/space_logic/logic_ops.c b/source/blender/editors/space_logic/logic_ops.c
index 51f4a61047d..074368a82c5 100644
--- a/source/blender/editors/space_logic/logic_ops.c
+++ b/source/blender/editors/space_logic/logic_ops.c
@@ -65,7 +65,7 @@ static int edit_sensor_poll(bContext *C)
{
PointerRNA ptr = CTX_data_pointer_get_type(C, "sensor", &RNA_Sensor);
- if (ptr.data && ((ID *)ptr.id.data)->lib) return 0;
+ if (ptr.data && ID_IS_LINKED_DATABLOCK(ptr.id.data)) return 0;
return 1;
}
@@ -73,7 +73,7 @@ static int edit_controller_poll(bContext *C)
{
PointerRNA ptr = CTX_data_pointer_get_type(C, "controller", &RNA_Controller);
- if (ptr.data && ((ID *)ptr.id.data)->lib) return 0;
+ if (ptr.data && ID_IS_LINKED_DATABLOCK(ptr.id.data)) return 0;
return 1;
}
@@ -81,7 +81,7 @@ static int edit_actuator_poll(bContext *C)
{
PointerRNA ptr = CTX_data_pointer_get_type(C, "actuator", &RNA_Actuator);
- if (ptr.data && ((ID *)ptr.id.data)->lib) return 0;
+ if (ptr.data && ID_IS_LINKED_DATABLOCK(ptr.id.data)) return 0;
return 1;
}
diff --git a/source/blender/editors/space_logic/space_logic.c b/source/blender/editors/space_logic/space_logic.c
index 243a522011b..12ca141128b 100644
--- a/source/blender/editors/space_logic/space_logic.c
+++ b/source/blender/editors/space_logic/space_logic.c
@@ -38,7 +38,10 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "DNA_gpencil_types.h"
+
#include "BKE_context.h"
+#include "BKE_library.h"
#include "BKE_screen.h"
#include "ED_space_api.h"
@@ -183,7 +186,9 @@ static void logic_keymap(struct wmKeyConfig *keyconf)
WM_keymap_add_menu(keymap, "LOGIC_MT_logicbricks_add", AKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "LOGIC_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
+#ifdef WITH_INPUT_NDOF
WM_keymap_add_item(keymap, "LOGIC_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
+#endif
}
static void logic_refresh(const bContext *UNUSED(C), ScrArea *UNUSED(sa))
@@ -300,6 +305,21 @@ static void logic_header_region_draw(const bContext *C, ARegion *ar)
/**************************** spacetype *****************************/
+static void logic_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceLogic *slog = (SpaceLogic *)slink;
+
+ if (!ELEM(GS(old_id->name), ID_GD)) {
+ return;
+ }
+
+ if ((ID *)slog->gpd == old_id) {
+ slog->gpd = (bGPdata *)new_id;
+ id_us_min(old_id);
+ id_us_plus(new_id);
+ }
+}
+
/* only called once, from space/spacetypes.c */
void ED_spacetype_logic(void)
{
@@ -317,7 +337,8 @@ void ED_spacetype_logic(void)
st->keymap = logic_keymap;
st->refresh = logic_refresh;
st->context = logic_context;
-
+ st->id_remap = logic_id_remap;
+
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype logic region");
art->regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index cbdc476bee6..3243579f7d0 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -131,6 +131,7 @@ bool nla_panel_context(const bContext *C, PointerRNA *adt_ptr, PointerRNA *nlt_p
case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
case ANIMTYPE_DSLAM:
case ANIMTYPE_DSCAM:
+ case ANIMTYPE_DSCACHEFILE:
case ANIMTYPE_DSCUR:
case ANIMTYPE_DSSKEY:
case ANIMTYPE_DSWOR:
@@ -567,7 +568,7 @@ void NLA_OT_properties(wmOperatorType *ot)
{
ot->name = "Properties";
ot->idname = "NLA_OT_properties";
- ot->description = "Toggle display properties panel";
+ ot->description = "Toggle the properties region visibility";
ot->exec = nla_properties_toggle_exec;
ot->poll = ED_operator_nla_active;
diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c
index 9e73e03a664..e9c46e9d04b 100644
--- a/source/blender/editors/space_nla/nla_channels.c
+++ b/source/blender/editors/space_nla/nla_channels.c
@@ -170,6 +170,7 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, float x, int channe
case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
case ANIMTYPE_DSLAM:
case ANIMTYPE_DSCAM:
+ case ANIMTYPE_DSCACHEFILE:
case ANIMTYPE_DSCUR:
case ANIMTYPE_DSSKEY:
case ANIMTYPE_DSWOR:
@@ -424,7 +425,7 @@ static int nlachannels_pushdown_exec(bContext *C, wmOperator *op)
/* active animdata block */
if (nla_panel_context(C, &adt_ptr, NULL, NULL) == 0 || (adt_ptr.data == NULL)) {
BKE_report(op->reports, RPT_ERROR, "No active AnimData block to use "
- "(select a datablock expander first or set the appropriate flags on an AnimData block)");
+ "(select a data-block expander first or set the appropriate flags on an AnimData block)");
return OPERATOR_CANCELLED;
}
else {
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index b0adabe4d1d..5b3c062e16d 100644
--- a/source/blender/editors/space_nla/nla_draw.c
+++ b/source/blender/editors/space_nla/nla_draw.c
@@ -62,7 +62,7 @@
#include "UI_resources.h"
#include "UI_view2d.h"
-
+#include "nla_private.h"
#include "nla_intern.h" /* own include */
@@ -145,6 +145,62 @@ static void nla_action_draw_keyframes(AnimData *adt, bAction *act, View2D *v2d,
BLI_dlrbTree_free(&keys);
}
+/* Strip Markers ------------------------ */
+
+/* Markers inside an action strip */
+static void nla_actionclip_draw_markers(NlaStrip *strip, float yminc, float ymaxc)
+{
+ bAction *act = strip->act;
+ TimeMarker *marker;
+
+ if (ELEM(NULL, strip->act, strip->act->markers.first))
+ return;
+
+ for (marker = act->markers.first; marker; marker = marker->next) {
+ if ((marker->frame > strip->actstart) && (marker->frame < strip->actend)) {
+ float frame = nlastrip_get_frame(strip, marker->frame, NLATIME_CONVERT_MAP);
+
+ /* just a simple line for now */
+ // XXX: draw a triangle instead...
+ fdrawline(frame, yminc + 1, frame, ymaxc - 1);
+ }
+ }
+}
+
+/* Markers inside a NLA-Strip */
+static void nla_strip_draw_markers(NlaStrip *strip, float yminc, float ymaxc)
+{
+ glLineWidth(2.0);
+
+ if (strip->type == NLASTRIP_TYPE_CLIP) {
+ /* try not to be too conspicuous, while being visible enough when transforming */
+ if (strip->flag & NLASTRIP_FLAG_SELECT)
+ UI_ThemeColorShade(TH_STRIP_SELECT, -60);
+ else
+ UI_ThemeColorShade(TH_STRIP_SELECT, -40);
+
+ setlinestyle(3);
+
+ /* just draw the markers in this clip */
+ nla_actionclip_draw_markers(strip, yminc, ymaxc);
+
+ setlinestyle(0);
+ }
+ else if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
+ /* just a solid color, so that it is very easy to spot */
+ UI_ThemeColorShade(TH_STRIP_SELECT, 20);
+
+ /* draw the markers in the first level of strips only (if they are actions) */
+ for (NlaStrip *nls = strip->strips.first; nls; nls = nls->next) {
+ if (nls->type == NLASTRIP_TYPE_CLIP) {
+ nla_actionclip_draw_markers(nls, yminc, ymaxc);
+ }
+ }
+ }
+
+ glLineWidth(1.0);
+}
+
/* Strips (Proper) ---------------------- */
/* get colors for drawing NLA-Strips */
@@ -361,6 +417,10 @@ static void nla_draw_strip(SpaceNla *snla, AnimData *adt, NlaTrack *nlt, NlaStri
nla_draw_strip_curves(strip, yminc, ymaxc);
+ /* draw markings indicating locations of local markers (useful for lining up different actions) */
+ if ((snla->flag & SNLA_NOLOCALMARKERS) == 0)
+ nla_strip_draw_markers(strip, yminc, ymaxc);
+
/* draw strip outline
* - color used here is to indicate active vs non-active
*/
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index a2159696394..1f298373a80 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -605,8 +605,8 @@ static int nlaedit_add_actionclip_exec(bContext *C, wmOperator *op)
else if (act->idroot == 0) {
/* hopefully in this case (i.e. library of userless actions), the user knows what they're doing... */
BKE_reportf(op->reports, RPT_WARNING,
- "Action '%s' does not specify what datablocks it can be used on "
- "(try setting the 'ID Root Type' setting from the Datablocks Editor "
+ "Action '%s' does not specify what data-blocks it can be used on "
+ "(try setting the 'ID Root Type' setting from the data-blocks editor "
"for this action to avoid future problems)",
act->id.name + 2);
}
@@ -1856,6 +1856,7 @@ void NLA_OT_action_sync_length(wmOperatorType *ot)
static int nlaedit_make_single_user_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Main *bmain = CTX_data_main(C);
bAnimContext ac;
ListBase anim_data = {NULL, NULL};
@@ -1887,7 +1888,7 @@ static int nlaedit_make_single_user_exec(bContext *C, wmOperator *UNUSED(op))
/* multi-user? */
if (ID_REAL_USERS(strip->act) > 1) {
/* make a new copy of the action for us to use (it will have 1 user already) */
- bAction *new_action = BKE_action_copy(strip->act);
+ bAction *new_action = BKE_action_copy(bmain, strip->act);
/* decrement user count of our existing action */
id_us_min(&strip->act->id);
@@ -1945,6 +1946,7 @@ static short bezt_apply_nlamapping(KeyframeEditData *ked, BezTriple *bezt)
static int nlaedit_apply_scale_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Main *bmain = CTX_data_main(C);
bAnimContext ac;
ListBase anim_data = {NULL, NULL};
@@ -1974,7 +1976,7 @@ static int nlaedit_apply_scale_exec(bContext *C, wmOperator *UNUSED(op))
continue;
if (strip->act->id.us > 1) {
/* make a copy of the Action to work on */
- bAction *act = BKE_action_copy(strip->act);
+ bAction *act = BKE_action_copy(bmain, strip->act);
/* set this as the new referenced action, decrementing the users of the old one */
id_us_min(&strip->act->id);
diff --git a/source/blender/editors/space_nla/nla_ops.c b/source/blender/editors/space_nla/nla_ops.c
index 386950ead3a..48037a10b2d 100644
--- a/source/blender/editors/space_nla/nla_ops.c
+++ b/source/blender/editors/space_nla/nla_ops.c
@@ -242,7 +242,9 @@ static void nla_keymap_main(wmKeyConfig *keyconf, wmKeyMap *keymap)
WM_keymap_add_item(keymap, "NLA_OT_previewrange_set", PKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
WM_keymap_add_item(keymap, "NLA_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
+#ifdef WITH_INPUT_NDOF
WM_keymap_add_item(keymap, "NLA_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
+#endif
WM_keymap_add_item(keymap, "NLA_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "NLA_OT_view_frame", PAD0, KM_PRESS, 0, 0);
diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c
index e2b36c5b5ae..3b5604087b9 100644
--- a/source/blender/editors/space_nla/space_nla.c
+++ b/source/blender/editors/space_nla/space_nla.c
@@ -33,6 +33,7 @@
#include <stdio.h>
#include "DNA_anim_types.h"
+#include "DNA_group_types.h"
#include "DNA_scene_types.h"
#include "MEM_guardedalloc.h"
@@ -501,6 +502,19 @@ static void nla_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
}
}
+static void nla_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceNla *snla = (SpaceNla *)slink;
+
+ if (!ELEM(GS(old_id->name), ID_GR)) {
+ return;
+ }
+
+ if ((ID *)snla->ads->filter_grp == old_id) {
+ snla->ads->filter_grp = (Group *)new_id;
+ }
+}
+
/* only called once, from space/spacetypes.c */
void ED_spacetype_nla(void)
{
@@ -517,7 +531,8 @@ void ED_spacetype_nla(void)
st->operatortypes = nla_operatortypes;
st->listener = nla_listener;
st->keymap = nla_keymap;
-
+ st->id_remap = nla_id_remap;
+
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype nla region");
art->regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index dce6856af61..b0d5c3f8ef6 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -1357,7 +1357,7 @@ static void node_composit_buts_renderlayers(uiLayout *layout, bContext *C, Point
scn_ptr = RNA_pointer_get(ptr, "scene");
RNA_string_get(&scn_ptr, "name", scene_name);
-
+
WM_operator_properties_create_ptr(&op_ptr, ot);
RNA_string_set(&op_ptr, "layer", layer_name);
RNA_string_set(&op_ptr, "scene", scene_name);
diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c
index b50df02beae..d49df2afbd4 100644
--- a/source/blender/editors/space_node/node_add.c
+++ b/source/blender/editors/space_node/node_add.c
@@ -382,7 +382,7 @@ void NODE_OT_add_file(wmOperatorType *ot)
WM_operator_properties_filesel(
ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
- RNA_def_string(ot->srna, "name", "Image", MAX_ID_NAME - 2, "Name", "Datablock name to assign");
+ RNA_def_string(ot->srna, "name", "Image", MAX_ID_NAME - 2, "Name", "Data-block name to assign");
}
/* ****************** Add Mask Node Operator ******************* */
@@ -441,7 +441,7 @@ void NODE_OT_add_mask(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
- RNA_def_string(ot->srna, "name", "Mask", MAX_ID_NAME - 2, "Name", "Datablock name to assign");
+ RNA_def_string(ot->srna, "name", "Mask", MAX_ID_NAME - 2, "Name", "Data-block name to assign");
}
/********************** New node tree operator *********************/
diff --git a/source/blender/editors/space_node/node_buttons.c b/source/blender/editors/space_node/node_buttons.c
index 52b0292b9a3..f0567924edd 100644
--- a/source/blender/editors/space_node/node_buttons.c
+++ b/source/blender/editors/space_node/node_buttons.c
@@ -222,7 +222,7 @@ static int node_properties_poll(bContext *C)
void NODE_OT_properties(wmOperatorType *ot)
{
ot->name = "Properties";
- ot->description = "Toggles the properties panel display";
+ ot->description = "Toggle the properties region visibility";
ot->idname = "NODE_OT_properties";
ot->exec = node_properties_toggle_exec;
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c
index d9c51e427c8..ab40c55b59d 100644
--- a/source/blender/editors/space_node/node_draw.c
+++ b/source/blender/editors/space_node/node_draw.c
@@ -1327,8 +1327,10 @@ void drawnodespace(const bContext *C, ARegion *ar)
path = snode->treepath.last;
/* update tree path name (drawn in the bottom left) */
- if (snode->id && UNLIKELY(!STREQ(path->node_name, snode->id->name + 2))) {
- BLI_strncpy(path->node_name, snode->id->name + 2, sizeof(path->node_name));
+ ID *name_id = (path->nodetree && path->nodetree != snode->nodetree) ? &path->nodetree->id : snode->id;
+
+ if (name_id && UNLIKELY(!STREQ(path->node_name, name_id->name + 2))) {
+ BLI_strncpy(path->node_name, name_id->name + 2, sizeof(path->node_name));
}
/* current View2D center, will be set temporarily for parent node trees */
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index 6ae72e2a164..ffe510016ff 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -740,34 +740,6 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
}
}
-void ED_node_id_unref(SpaceNode *snode, const ID *id)
-{
- if (GS(id->name) == ID_SCE) {
- if (snode->id == id) {
- /* nasty DNA logic for SpaceNode:
- * ideally should be handled by editor code, but would be bad level call
- */
- bNodeTreePath *path, *path_next;
- for (path = snode->treepath.first; path; path = path_next) {
- path_next = path->next;
- MEM_freeN(path);
- }
- BLI_listbase_clear(&snode->treepath);
-
- snode->id = NULL;
- snode->from = NULL;
- snode->nodetree = NULL;
- snode->edittree = NULL;
- }
- }
- else if (GS(id->name) == ID_OB) {
- if (snode->from == id) {
- snode->flag &= ~SNODE_PIN;
- snode->from = NULL;
- }
- }
-}
-
void ED_node_post_apply_transform(bContext *UNUSED(C), bNodeTree *UNUSED(ntree))
{
/* XXX This does not work due to layout functions relying on node->block,
diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c
index 5c58e9b720c..26eeaa91dd0 100644
--- a/source/blender/editors/space_node/node_group.c
+++ b/source/blender/editors/space_node/node_group.c
@@ -255,7 +255,7 @@ static int node_group_ungroup(bNodeTree *ntree, bNode *gnode)
bAction *waction;
/* firstly, wgroup needs to temporary dummy action that can be destroyed, as it shares copies */
- waction = wgroup->adt->action = BKE_action_copy(wgroup->adt->action);
+ waction = wgroup->adt->action = BKE_action_copy(G.main, wgroup->adt->action);
/* now perform the moving */
BKE_animdata_separate_by_basepath(&wgroup->id, &ntree->id, &anim_basepaths);
@@ -794,22 +794,37 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
link->tosock = node_group_find_input_socket(gnode, iosock->identifier);
}
else if (fromselect) {
- bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket(ngroup, link->fromnode, link->fromsock);
- bNodeSocket *output_sock;
-
- /* update the group node and interface node sockets,
- * so the new interface socket can be linked.
- */
- node_group_verify(ntree, gnode, (ID *)ngroup);
- node_group_output_verify(ngroup, output_node, (ID *)ngroup);
+ /* First check whether the source of this link is already connected to an output.
+ * If yes, reuse that output instead of duplicating it. */
+ bool connected = false;
+ bNodeLink *olink;
+ for (olink = ngroup->links.first; olink; olink = olink->next) {
+ if (olink->fromsock == link->fromsock && olink->tonode == output_node) {
+ bNodeSocket *output_sock = node_group_find_output_socket(gnode, olink->tosock->identifier);
+ link->fromnode = gnode;
+ link->fromsock = output_sock;
+ connected = true;
+ }
+ }
- /* create new internal link */
- output_sock = node_group_output_find_socket(output_node, iosock->identifier);
- nodeAddLink(ngroup, link->fromnode, link->fromsock, output_node, output_sock);
-
- /* redirect external link */
- link->fromnode = gnode;
- link->fromsock = node_group_find_output_socket(gnode, iosock->identifier);
+ if (!connected) {
+ bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket(ngroup, link->fromnode, link->fromsock);
+ bNodeSocket *output_sock;
+
+ /* update the group node and interface node sockets,
+ * so the new interface socket can be linked.
+ */
+ node_group_verify(ntree, gnode, (ID *)ngroup);
+ node_group_output_verify(ngroup, output_node, (ID *)ngroup);
+
+ /* create new internal link */
+ output_sock = node_group_output_find_socket(output_node, iosock->identifier);
+ nodeAddLink(ngroup, link->fromnode, link->fromsock, output_node, output_sock);
+
+ /* redirect external link */
+ link->fromnode = gnode;
+ link->fromsock = node_group_find_output_socket(gnode, iosock->identifier);
+ }
}
}
diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c
index 7788173a8ee..5118d52efc4 100644
--- a/source/blender/editors/space_node/node_ops.c
+++ b/source/blender/editors/space_node/node_ops.c
@@ -295,7 +295,9 @@ void node_keymap(struct wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "NODE_OT_hide_socket_toggle", HKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "NODE_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
+#ifdef WITH_INPUT_NDOF
WM_keymap_add_item(keymap, "NODE_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
+#endif
WM_keymap_add_item(keymap, "NODE_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0);
kmi = WM_keymap_add_item(keymap, "NODE_OT_select_border", BKEY, KM_PRESS, 0, 0);
diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c
index 4abc7f5e71b..5f592431558 100644
--- a/source/blender/editors/space_node/node_relationships.c
+++ b/source/blender/editors/space_node/node_relationships.c
@@ -276,25 +276,16 @@ static bNodeSocket *best_socket_input(bNodeTree *ntree, bNode *node, int num, in
return NULL;
}
-static int snode_autoconnect_input(SpaceNode *snode, bNode *node_fr, bNodeSocket *sock_fr, bNode *node_to, bNodeSocket *sock_to, int replace)
+static bool snode_autoconnect_input(SpaceNode *snode, bNode *node_fr, bNodeSocket *sock_fr, bNode *node_to, bNodeSocket *sock_to, int replace)
{
bNodeTree *ntree = snode->edittree;
- bNodeLink *link;
/* then we can connect */
if (replace)
nodeRemSocketLinks(ntree, sock_to);
- link = nodeAddLink(ntree, node_fr, sock_fr, node_to, sock_to);
- /* validate the new link */
- ntreeUpdateTree(G.main, ntree);
- if (!(link->flag & NODE_LINK_VALID)) {
- nodeRemLink(ntree, link);
- return 0;
- }
-
- snode_update(snode, node_to);
- return 1;
+ nodeAddLink(ntree, node_fr, sock_fr, node_to, sock_to);
+ return true;
}
static void snode_autoconnect(SpaceNode *snode, const bool allow_multiple, const bool replace)
@@ -514,12 +505,10 @@ void NODE_OT_link_viewer(wmOperatorType *ot)
static void node_link_update_header(bContext *C, bNodeLinkDrag *UNUSED(nldrag))
{
-#define HEADER_LENGTH 256
- char header[HEADER_LENGTH];
+ char header[UI_MAX_DRAW_STR];
- BLI_strncpy(header, IFACE_("LMB: drag node link, RMB: cancel"), HEADER_LENGTH);
+ BLI_strncpy(header, IFACE_("LMB: drag node link, RMB: cancel"), sizeof(header));
ED_area_headerprint(CTX_wm_area(C), header);
-#undef HEADER_LENGTH
}
static int node_count_links(bNodeTree *ntree, bNodeSocket *sock)
@@ -1728,7 +1717,7 @@ static int node_insert_offset_modal(bContext *C, wmOperator *UNUSED(op), const w
float duration;
bool redraw = false;
- if (!snode || event->type != TIMER || iofsd->anim_timer != event->customdata)
+ if (!snode || event->type != TIMER || iofsd == NULL || iofsd->anim_timer != event->customdata)
return OPERATOR_PASS_THROUGH;
duration = (float)iofsd->anim_timer->duration;
diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c
index 09594ab543c..ec525e684b0 100644
--- a/source/blender/editors/space_node/node_templates.c
+++ b/source/blender/editors/space_node/node_templates.c
@@ -428,6 +428,20 @@ static int ui_node_item_name_compare(const void *a, const void *b)
return BLI_natstrcmp(type_a->ui_name, type_b->ui_name);
}
+static bool ui_node_item_special_poll(const bNodeTree *UNUSED(ntree),
+ const bNodeType *ntype)
+{
+ if (STREQ(ntype->idname, "ShaderNodeUVAlongStroke")) {
+ /* TODO(sergey): Currently we don't have Freestyle nodes edited from
+ * the buttons context, so can ignore it's nodes completely.
+ *
+ * However, we might want to do some extra checks here later.
+ */
+ return false;
+ }
+ return true;
+}
+
static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
{
bNodeTree *ntree = arg->ntree;
@@ -452,11 +466,17 @@ static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
BLI_array_declare(sorted_ntypes);
NODE_TYPES_BEGIN(ntype) {
- if (compatibility && !(ntype->compatibility & compatibility))
+ if (compatibility && !(ntype->compatibility & compatibility)) {
continue;
+ }
- if (ntype->nclass != nclass)
+ if (ntype->nclass != nclass) {
continue;
+ }
+
+ if (!ui_node_item_special_poll(ntree, ntype)) {
+ continue;
+ }
BLI_array_append(sorted_ntypes, ntype);
}
diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c
index df484724fc5..4ef703c8994 100644
--- a/source/blender/editors/space_node/space_node.c
+++ b/source/blender/editors/space_node/space_node.c
@@ -28,6 +28,7 @@
* \ingroup spnode
*/
+#include "DNA_gpencil_types.h"
#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
#include "DNA_node_types.h"
@@ -821,6 +822,41 @@ static int node_context(const bContext *C, const char *member, bContextDataResul
return 0;
}
+static void node_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceNode *snode = (SpaceNode *)slink;
+
+ if (GS(old_id->name) == ID_SCE) {
+ if (snode->id == old_id) {
+ /* nasty DNA logic for SpaceNode:
+ * ideally should be handled by editor code, but would be bad level call
+ */
+ BLI_freelistN(&snode->treepath);
+
+ /* XXX Untested in case new_id != NULL... */
+ snode->id = new_id;
+ snode->from = NULL;
+ snode->nodetree = NULL;
+ snode->edittree = NULL;
+ }
+ }
+ else if (GS(old_id->name) == ID_OB) {
+ if (snode->from == old_id) {
+ if (new_id == NULL) {
+ snode->flag &= ~SNODE_PIN;
+ }
+ snode->from = new_id;
+ }
+ }
+ else if (GS(old_id->name) == ID_GD) {
+ if ((ID *)snode->gpd == old_id) {
+ snode->gpd = (bGPdata *)new_id;
+ id_us_min(old_id);
+ id_us_plus(new_id);
+ }
+ }
+}
+
/* only called once, from space/spacetypes.c */
void ED_spacetype_node(void)
{
@@ -840,6 +876,7 @@ void ED_spacetype_node(void)
st->refresh = node_area_refresh;
st->context = node_context;
st->dropboxes = node_dropboxes;
+ st->id_remap = node_id_remap;
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype node region");
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index b624c7cba75..33a5a7ca7b7 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -155,7 +155,7 @@ static void restrictbutton_recursive_ebone(bContext *C, EditBone *ebone_parent,
}
}
-static void restrictbutton_recursive_bone(bContext *C, bArmature *arm, Bone *bone_parent, int flag, bool set_flag)
+static void restrictbutton_recursive_bone(Bone *bone_parent, int flag, bool set_flag)
{
Bone *bone;
for (bone = bone_parent->childbase.first; bone; bone = bone->next) {
@@ -166,7 +166,7 @@ static void restrictbutton_recursive_bone(bContext *C, bArmature *arm, Bone *bon
else {
bone->flag &= ~flag;
}
- restrictbutton_recursive_bone(C, arm, bone, flag, set_flag);
+ restrictbutton_recursive_bone(bone, flag, set_flag);
}
}
@@ -294,29 +294,27 @@ static void restrictbutton_modifier_cb(bContext *C, void *UNUSED(poin), void *po
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
}
-static void restrictbutton_bone_visibility_cb(bContext *C, void *poin, void *poin2)
+static void restrictbutton_bone_visibility_cb(bContext *C, void *UNUSED(poin), void *poin2)
{
- bArmature *arm = (bArmature *)poin;
Bone *bone = (Bone *)poin2;
if (bone->flag & BONE_HIDDEN_P)
bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
if (CTX_wm_window(C)->eventstate->ctrl) {
- restrictbutton_recursive_bone(C, arm, bone, BONE_HIDDEN_P, (bone->flag & BONE_HIDDEN_P) != 0);
+ restrictbutton_recursive_bone(bone, BONE_HIDDEN_P, (bone->flag & BONE_HIDDEN_P) != 0);
}
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
}
-static void restrictbutton_bone_select_cb(bContext *C, void *poin, void *poin2)
+static void restrictbutton_bone_select_cb(bContext *C, void *UNUSED(poin), void *poin2)
{
- bArmature *arm = (bArmature *)poin;
Bone *bone = (Bone *)poin2;
if (bone->flag & BONE_UNSELECTABLE)
bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
if (CTX_wm_window(C)->eventstate->ctrl) {
- restrictbutton_recursive_bone(C, arm, bone, BONE_UNSELECTABLE, (bone->flag & BONE_UNSELECTABLE) != 0);
+ restrictbutton_recursive_bone(bone, BONE_UNSELECTABLE, (bone->flag & BONE_UNSELECTABLE) != 0);
}
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
@@ -402,7 +400,7 @@ void restrictbutton_gr_restrict_flag(void *poin, void *poin2, int flag)
if (group_restrict_flag(gr, flag)) {
for (gob = gr->gobject.first; gob; gob = gob->next) {
- if (gob->ob->id.lib)
+ if (ID_IS_LINKED_DATABLOCK(gob->ob))
continue;
gob->ob->restrictflag &= ~flag;
@@ -414,7 +412,7 @@ void restrictbutton_gr_restrict_flag(void *poin, void *poin2, int flag)
}
else {
for (gob = gr->gobject.first; gob; gob = gob->next) {
- if (gob->ob->id.lib)
+ if (ID_IS_LINKED_DATABLOCK(gob->ob))
continue;
/* not in editmode */
@@ -502,6 +500,11 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
BKE_reportf(CTX_wm_reports(C), RPT_ERROR,
"Library path '%s' does not exist, correct this before saving", expanded);
}
+ else if (lib->id.tag & LIB_TAG_MISSING) {
+ BKE_reportf(CTX_wm_reports(C), RPT_INFO,
+ "Library path '%s' is now valid, please reload the library", expanded);
+ lib->id.tag &= ~LIB_TAG_MISSING;
+ }
}
}
else {
@@ -650,7 +653,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar
int but_flag = UI_BUT_DRAG_LOCK;
gr = (Group *)tselem->id;
- if (gr->id.lib)
+ if (ID_IS_LINKED_DATABLOCK(gr))
but_flag |= UI_BUT_DISABLED;
UI_block_emboss_set(block, UI_EMBOSS_NONE);
@@ -823,18 +826,18 @@ static void outliner_draw_userbuts(uiBlock *block, ARegion *ar, SpaceOops *soops
char buf[16] = "";
int but_flag = UI_BUT_DRAG_LOCK;
- if (id->lib)
+ if (ID_IS_LINKED_DATABLOCK(id))
but_flag |= UI_BUT_DISABLED;
UI_block_emboss_set(block, UI_EMBOSS_NONE);
if (id->flag & LIB_FAKEUSER) {
icon = ICON_FILE_TICK;
- tip = TIP_("Datablock will be retained using a fake user");
+ tip = TIP_("Data-block will be retained using a fake user");
}
else {
icon = ICON_X;
- tip = TIP_("Datablock has no users and will be deleted");
+ tip = TIP_("Data-block has no users and will be deleted");
}
bt = uiDefIconButBitS(block, UI_BTYPE_TOGGLE, LIB_FAKEUSER, 1, icon,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, UI_UNIT_Y,
@@ -847,14 +850,14 @@ static void outliner_draw_userbuts(uiBlock *block, ARegion *ar, SpaceOops *soops
bt = uiDefBut(block, UI_BTYPE_BUT, 1, buf,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys,
UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0,
- TIP_("Number of users of this datablock"));
+ TIP_("Number of users of this data-block"));
UI_but_flag_enable(bt, but_flag);
bt = uiDefButBitS(block, UI_BTYPE_TOGGLE, LIB_FAKEUSER, 1, (id->flag & LIB_FAKEUSER) ? "F" : " ",
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X, UI_UNIT_Y,
&id->flag, 0, 0, 0, 0,
- TIP_("Datablock has a 'fake' user which will keep it in the file "
+ TIP_("Data-block has a 'fake' user which will keep it in the file "
"even if nothing else uses it"));
UI_but_func_set(bt, restrictbutton_id_user_toggle, id, NULL);
UI_but_flag_enable(bt, but_flag);
@@ -888,7 +891,7 @@ static void outliner_draw_rnacols(ARegion *ar, int sizex)
miny);
}
-static void outliner_draw_rnabuts(uiBlock *block, Scene *scene, ARegion *ar, SpaceOops *soops, int sizex, ListBase *lb)
+static void outliner_draw_rnabuts(uiBlock *block, ARegion *ar, SpaceOops *soops, int sizex, ListBase *lb)
{
TreeElement *te;
TreeStoreElem *tselem;
@@ -927,7 +930,7 @@ static void outliner_draw_rnabuts(uiBlock *block, Scene *scene, ARegion *ar, Spa
}
}
- if (TSELEM_OPEN(tselem, soops)) outliner_draw_rnabuts(block, scene, ar, soops, sizex, &te->subtree);
+ if (TSELEM_OPEN(tselem, soops)) outliner_draw_rnabuts(block, ar, soops, sizex, &te->subtree);
}
UI_block_emboss_set(block, UI_EMBOSS);
@@ -988,7 +991,8 @@ static void tselem_draw_icon_uibut(struct DrawIconArg *arg, int icon)
}
else {
uiBut *but = uiDefIconBut(arg->block, UI_BTYPE_LABEL, 0, icon, arg->xb, arg->yb, UI_UNIT_X, UI_UNIT_Y, NULL,
- 0.0, 0.0, 1.0, arg->alpha, (arg->id && arg->id->lib) ? arg->id->lib->name : "");
+ 0.0, 0.0, 1.0, arg->alpha,
+ (arg->id && ID_IS_LINKED_DATABLOCK(arg->id)) ? arg->id->lib->name : "");
if (arg->id)
UI_but_drag_set_id(but, arg->id);
@@ -996,7 +1000,7 @@ static void tselem_draw_icon_uibut(struct DrawIconArg *arg, int icon)
}
-static void tselem_draw_gp_icon_uibut(struct DrawIconArg *arg, ID *id, bGPDlayer *gpl)
+static void UNUSED_FUNCTION(tselem_draw_gp_icon_uibut)(struct DrawIconArg *arg, ID *id, bGPDlayer *gpl)
{
/* restrict column clip - skip it for now... */
if (arg->x >= arg->xmax) {
@@ -1167,6 +1171,8 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
UI_icon_draw(x, y, ICON_MOD_TRIANGULATE); break;
case eModifierType_MeshCache:
UI_icon_draw(x, y, ICON_MOD_MESHDEFORM); break; /* XXX, needs own icon */
+ case eModifierType_MeshSequenceCache:
+ UI_icon_draw(x, y, ICON_MOD_MESHDEFORM); break; /* XXX, needs own icon */
case eModifierType_Wireframe:
UI_icon_draw(x, y, ICON_MOD_WIREFRAME); break;
case eModifierType_LaplacianDeform:
@@ -1227,113 +1233,116 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
else
UI_icon_draw(x, y, RNA_struct_ui_icon(te->rnaptr.type));
break;
+ /* Removed the icons from outliner. Need a better structure with Layers, Palettes and Colors */
+#if 0
case TSE_GP_LAYER:
tselem_draw_gp_icon_uibut(&arg, tselem->id, te->directdata);
break;
+#endif
default:
UI_icon_draw(x, y, ICON_DOT); break;
}
}
- else if (GS(tselem->id->name) == ID_OB) {
- Object *ob = (Object *)tselem->id;
- switch (ob->type) {
- case OB_LAMP:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_LAMP); break;
- case OB_MESH:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_MESH); break;
- case OB_CAMERA:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_CAMERA); break;
- case OB_CURVE:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_CURVE); break;
- case OB_MBALL:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_META); break;
- case OB_LATTICE:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_LATTICE); break;
- case OB_ARMATURE:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_ARMATURE); break;
- case OB_FONT:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_FONT); break;
- case OB_SURF:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_SURFACE); break;
- case OB_SPEAKER:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_SPEAKER); break;
- case OB_EMPTY:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_EMPTY); break;
-
+ else if (tselem->id) {
+ if (GS(tselem->id->name) == ID_OB) {
+ Object *ob = (Object *)tselem->id;
+ switch (ob->type) {
+ case OB_LAMP:
+ tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_LAMP); break;
+ case OB_MESH:
+ tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_MESH); break;
+ case OB_CAMERA:
+ tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_CAMERA); break;
+ case OB_CURVE:
+ tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_CURVE); break;
+ case OB_MBALL:
+ tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_META); break;
+ case OB_LATTICE:
+ tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_LATTICE); break;
+ case OB_ARMATURE:
+ tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_ARMATURE); break;
+ case OB_FONT:
+ tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_FONT); break;
+ case OB_SURF:
+ tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_SURFACE); break;
+ case OB_SPEAKER:
+ tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_SPEAKER); break;
+ case OB_EMPTY:
+ tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_EMPTY); break;
+ }
}
- }
- else {
- switch (GS(tselem->id->name)) {
- case ID_SCE:
- tselem_draw_icon_uibut(&arg, ICON_SCENE_DATA); break;
- case ID_ME:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_MESH); break;
- case ID_CU:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_CURVE); break;
- case ID_MB:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_META); break;
- case ID_LT:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_LATTICE); break;
- case ID_LA:
- {
- Lamp *la = (Lamp *)tselem->id;
-
- switch (la->type) {
- case LA_LOCAL:
- tselem_draw_icon_uibut(&arg, ICON_LAMP_POINT); break;
- case LA_SUN:
- tselem_draw_icon_uibut(&arg, ICON_LAMP_SUN); break;
- case LA_SPOT:
- tselem_draw_icon_uibut(&arg, ICON_LAMP_SPOT); break;
- case LA_HEMI:
- tselem_draw_icon_uibut(&arg, ICON_LAMP_HEMI); break;
- case LA_AREA:
- tselem_draw_icon_uibut(&arg, ICON_LAMP_AREA); break;
- default:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_LAMP); break;
+ else {
+ switch (GS(tselem->id->name)) {
+ case ID_SCE:
+ tselem_draw_icon_uibut(&arg, ICON_SCENE_DATA); break;
+ case ID_ME:
+ tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_MESH); break;
+ case ID_CU:
+ tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_CURVE); break;
+ case ID_MB:
+ tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_META); break;
+ case ID_LT:
+ tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_LATTICE); break;
+ case ID_LA:
+ {
+ Lamp *la = (Lamp *)tselem->id;
+ switch (la->type) {
+ case LA_LOCAL:
+ tselem_draw_icon_uibut(&arg, ICON_LAMP_POINT); break;
+ case LA_SUN:
+ tselem_draw_icon_uibut(&arg, ICON_LAMP_SUN); break;
+ case LA_SPOT:
+ tselem_draw_icon_uibut(&arg, ICON_LAMP_SPOT); break;
+ case LA_HEMI:
+ tselem_draw_icon_uibut(&arg, ICON_LAMP_HEMI); break;
+ case LA_AREA:
+ tselem_draw_icon_uibut(&arg, ICON_LAMP_AREA); break;
+ default:
+ tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_LAMP); break;
+ }
+ break;
}
- break;
+ case ID_MA:
+ tselem_draw_icon_uibut(&arg, ICON_MATERIAL_DATA); break;
+ case ID_TE:
+ tselem_draw_icon_uibut(&arg, ICON_TEXTURE_DATA); break;
+ case ID_IM:
+ tselem_draw_icon_uibut(&arg, ICON_IMAGE_DATA); break;
+ case ID_SPK:
+ case ID_SO:
+ tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_SPEAKER); break;
+ case ID_AR:
+ tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_ARMATURE); break;
+ case ID_CA:
+ tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_CAMERA); break;
+ case ID_KE:
+ tselem_draw_icon_uibut(&arg, ICON_SHAPEKEY_DATA); break;
+ case ID_WO:
+ tselem_draw_icon_uibut(&arg, ICON_WORLD_DATA); break;
+ case ID_AC:
+ tselem_draw_icon_uibut(&arg, ICON_ACTION); break;
+ case ID_NLA:
+ tselem_draw_icon_uibut(&arg, ICON_NLA); break;
+ case ID_TXT:
+ tselem_draw_icon_uibut(&arg, ICON_SCRIPT); break;
+ case ID_GR:
+ tselem_draw_icon_uibut(&arg, ICON_GROUP); break;
+ case ID_LI:
+ if (tselem->id->tag & LIB_TAG_MISSING) {
+ tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_BROKEN);
+ }
+ else if (((Library *)tselem->id)->parent) {
+ tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_INDIRECT);
+ }
+ else {
+ tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_DIRECT);
+ }
+ break;
+ case ID_LS:
+ tselem_draw_icon_uibut(&arg, ICON_LINE_DATA); break;
+ case ID_GD:
+ tselem_draw_icon_uibut(&arg, ICON_GREASEPENCIL); break;
}
- case ID_MA:
- tselem_draw_icon_uibut(&arg, ICON_MATERIAL_DATA); break;
- case ID_TE:
- tselem_draw_icon_uibut(&arg, ICON_TEXTURE_DATA); break;
- case ID_IM:
- tselem_draw_icon_uibut(&arg, ICON_IMAGE_DATA); break;
- case ID_SPK:
- case ID_SO:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_SPEAKER); break;
- case ID_AR:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_ARMATURE); break;
- case ID_CA:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_CAMERA); break;
- case ID_KE:
- tselem_draw_icon_uibut(&arg, ICON_SHAPEKEY_DATA); break;
- case ID_WO:
- tselem_draw_icon_uibut(&arg, ICON_WORLD_DATA); break;
- case ID_AC:
- tselem_draw_icon_uibut(&arg, ICON_ACTION); break;
- case ID_NLA:
- tselem_draw_icon_uibut(&arg, ICON_NLA); break;
- case ID_TXT:
- tselem_draw_icon_uibut(&arg, ICON_SCRIPT); break;
- case ID_GR:
- tselem_draw_icon_uibut(&arg, ICON_GROUP); break;
- case ID_LI:
- if (tselem->id->tag & LIB_TAG_MISSING) {
- tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_BROKEN);
- }
- else if (((Library *)tselem->id)->parent) {
- tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_INDIRECT);
- }
- else {
- tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_DIRECT);
- }
- break;
- case ID_LS:
- tselem_draw_icon_uibut(&arg, ICON_LINE_DATA); break;
- case ID_GD:
- tselem_draw_icon_uibut(&arg, ICON_GREASEPENCIL); break;
}
}
}
@@ -1403,7 +1412,7 @@ static void outliner_draw_iconrow(bContext *C, uiBlock *block, Scene *scene, Spa
}
/* closed tree element */
-static void outliner_set_coord_tree_element(SpaceOops *soops, TreeElement *te, int startx, int starty)
+static void outliner_set_coord_tree_element(TreeElement *te, int startx, int starty)
{
TreeElement *ten;
@@ -1412,7 +1421,7 @@ static void outliner_set_coord_tree_element(SpaceOops *soops, TreeElement *te, i
te->ys = starty;
for (ten = te->subtree.first; ten; ten = ten->next) {
- outliner_set_coord_tree_element(soops, ten, startx + UI_UNIT_X, starty);
+ outliner_set_coord_tree_element(ten, startx + UI_UNIT_X, starty);
}
}
@@ -1562,7 +1571,7 @@ static void outliner_draw_tree_element(
else
offsx += 2 * ufac;
- if (tselem->type == 0 && tselem->id->lib) {
+ if (tselem->type == 0 && ID_IS_LINKED_DATABLOCK(tselem->id)) {
glPixelTransferf(GL_ALPHA_SCALE, 0.5f);
if (tselem->id->tag & LIB_TAG_MISSING) {
UI_icon_draw((float)startx + offsx, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_BROKEN);
@@ -1579,11 +1588,19 @@ static void outliner_draw_tree_element(
glDisable(GL_BLEND);
/* name */
- if (active == OL_DRAWSEL_NORMAL) UI_ThemeColor(TH_TEXT_HI);
- else if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) UI_ThemeColorBlend(TH_BACK, TH_TEXT, 0.75f);
- else UI_ThemeColor(TH_TEXT);
-
- UI_fontstyle_draw_simple(fstyle, startx + offsx, *starty + 5 * ufac, te->name);
+ if ((tselem->flag & TSE_TEXTBUT) == 0) {
+ if (active == OL_DRAWSEL_NORMAL) {
+ UI_ThemeColor(TH_TEXT_HI);
+ }
+ else if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
+ UI_ThemeColorBlend(TH_BACK, TH_TEXT, 0.75f);
+ }
+ else {
+ UI_ThemeColor(TH_TEXT);
+ }
+
+ UI_fontstyle_draw_simple(fstyle, startx + offsx, *starty + 5 * ufac, te->name);
+ }
offsx += (int)(UI_UNIT_X + UI_fontstyle_string_width(fstyle, te->name));
@@ -1630,7 +1647,7 @@ static void outliner_draw_tree_element(
}
else {
for (ten = te->subtree.first; ten; ten = ten->next) {
- outliner_set_coord_tree_element(soops, ten, startx, *starty);
+ outliner_set_coord_tree_element(ten, startx, *starty);
}
*starty -= UI_UNIT_Y;
@@ -1671,7 +1688,7 @@ static void outliner_draw_hierarchy(SpaceOops *soops, ListBase *lb, int startx,
}
}
-static void outliner_draw_struct_marks(ARegion *ar, SpaceOops *soops, ListBase *lb, int *starty)
+static void outliner_draw_struct_marks(ARegion *ar, SpaceOops *soops, ListBase *lb, int *starty)
{
TreeElement *te;
TreeStoreElem *tselem;
@@ -1693,7 +1710,7 @@ static void outliner_draw_struct_marks(ARegion *ar, SpaceOops *soops, ListBase *
}
}
-static void outliner_draw_selection(ARegion *ar, SpaceOops *soops, ListBase *lb, int *starty)
+static void outliner_draw_selection(ARegion *ar, SpaceOops *soops, ListBase *lb, int *starty)
{
TreeElement *te;
TreeStoreElem *tselem;
@@ -1870,7 +1887,7 @@ void draw_outliner(const bContext *C)
if (ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF)) {
/* draw rna buttons */
outliner_draw_rnacols(ar, sizex_rna);
- outliner_draw_rnabuts(block, scene, ar, soops, sizex_rna, &soops->tree);
+ outliner_draw_rnabuts(block, ar, soops, sizex_rna, &soops->tree);
}
else if ((soops->outlinevis == SO_ID_ORPHANS) && !(soops->flag & SO_HIDE_RESTRICTCOLS)) {
/* draw user toggle columns */
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 2627b978b40..345ac353c11 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -29,17 +29,23 @@
* \ingroup spoutliner
*/
+#include <string.h>
+
#include "MEM_guardedalloc.h"
#include "DNA_anim_types.h"
#include "DNA_group_types.h"
+#include "DNA_ID.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_material_types.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_path_util.h"
#include "BLI_mempool.h"
+#include "BLI_stack.h"
+#include "BLI_string.h"
#include "BLT_translation.h"
@@ -47,7 +53,10 @@
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_global.h"
+#include "BKE_idcode.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_outliner_treehash.h"
#include "BKE_report.h"
@@ -55,6 +64,8 @@
#include "BKE_material.h"
#include "BKE_group.h"
+#include "../blenloader/BLO_readfile.h"
+
#include "ED_object.h"
#include "ED_outliner.h"
#include "ED_screen.h"
@@ -70,6 +81,9 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "GPU_material.h"
#include "outliner_intern.h"
@@ -103,9 +117,7 @@ static void outliner_open_reveal(SpaceOops *soops, ListBase *lb, TreeElement *te
}
#endif
-static TreeElement *outliner_dropzone_element(
- const SpaceOops *soops, TreeElement *te,
- const float fmval[2], const bool children)
+static TreeElement *outliner_dropzone_element(TreeElement *te, const float fmval[2], const bool children)
{
if ((fmval[1] > te->ys) && (fmval[1] < (te->ys + UI_UNIT_Y))) {
/* name and first icon */
@@ -115,7 +127,7 @@ static TreeElement *outliner_dropzone_element(
/* Not it. Let's look at its children. */
if (children && (TREESTORE(te)->flag & TSE_CLOSED) == 0 && (te->subtree.first)) {
for (te = te->subtree.first; te; te = te->next) {
- TreeElement *te_valid = outliner_dropzone_element(soops, te, fmval, children);
+ TreeElement *te_valid = outliner_dropzone_element(te, fmval, children);
if (te_valid)
return te_valid;
}
@@ -129,7 +141,7 @@ TreeElement *outliner_dropzone_find(const SpaceOops *soops, const float fmval[2]
TreeElement *te;
for (te = soops->tree.first; te; te = te->next) {
- TreeElement *te_valid = outliner_dropzone_element(soops, te, fmval, children);
+ TreeElement *te_valid = outliner_dropzone_element(te, fmval, children);
if (te_valid)
return te_valid;
}
@@ -150,7 +162,7 @@ static int do_outliner_item_openclose(bContext *C, SpaceOops *soops, TreeElement
/* all below close/open? */
if (all) {
tselem->flag &= ~TSE_CLOSED;
- outliner_set_flag(soops, &te->subtree, TSE_CLOSED, !outliner_has_one_flag(soops, &te->subtree, TSE_CLOSED, 1));
+ outliner_set_flag(&te->subtree, TSE_CLOSED, !outliner_has_one_flag(&te->subtree, TSE_CLOSED, 1));
}
else {
if (tselem->flag & TSE_CLOSED) tselem->flag &= ~TSE_CLOSED;
@@ -218,7 +230,7 @@ static void do_item_rename(ARegion *ar, TreeElement *te, TreeStoreElem *tselem,
else if (ELEM(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) {
BKE_report(reports, RPT_WARNING, "Cannot edit sequence name");
}
- else if (tselem->id->lib) {
+ else if (ID_IS_LINKED_DATABLOCK(tselem->id)) {
BKE_report(reports, RPT_WARNING, "Cannot edit external libdata");
}
else if (te->idcode == ID_LI && ((Library *)tselem->id)->parent) {
@@ -230,18 +242,16 @@ static void do_item_rename(ARegion *ar, TreeElement *te, TreeStoreElem *tselem,
}
}
-void item_rename_cb(bContext *C, Scene *UNUSED(scene), TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+void item_rename_cb(
+ bContext *C, ReportList *reports, Scene *UNUSED(scene), TreeElement *te,
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
ARegion *ar = CTX_wm_region(C);
- ReportList *reports = CTX_wm_reports(C); // XXX
do_item_rename(ar, te, tselem, reports);
}
-static int do_outliner_item_rename(bContext *C, ARegion *ar, SpaceOops *soops, TreeElement *te, const float mval[2])
-{
- ReportList *reports = CTX_wm_reports(C); // XXX
-
+static int do_outliner_item_rename(ReportList *reports, ARegion *ar, TreeElement *te, const float mval[2])
+{
if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
TreeStoreElem *tselem = TREESTORE(te);
@@ -254,12 +264,12 @@ static int do_outliner_item_rename(bContext *C, ARegion *ar, SpaceOops *soops, T
}
for (te = te->subtree.first; te; te = te->next) {
- if (do_outliner_item_rename(C, ar, soops, te, mval)) return 1;
+ if (do_outliner_item_rename(reports, ar, te, mval)) return 1;
}
return 0;
}
-static int outliner_item_rename(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+static int outliner_item_rename(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
@@ -270,7 +280,7 @@ static int outliner_item_rename(bContext *C, wmOperator *UNUSED(op), const wmEve
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
for (te = soops->tree.first; te; te = te->next) {
- if (do_outliner_item_rename(C, ar, soops, te, fmval)) {
+ if (do_outliner_item_rename(op->reports, ar, te, fmval)) {
changed = true;
break;
}
@@ -291,64 +301,315 @@ void OUTLINER_OT_item_rename(wmOperatorType *ot)
ot->poll = ED_operator_outliner_active;
}
-/* Library delete --------------------------------------------------- */
+/* ID delete --------------------------------------------------- */
-static void lib_delete(bContext *C, TreeElement *te, TreeStoreElem *tselem, ReportList *reports)
+static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeStoreElem *tselem)
{
- Library *lib = (Library *)tselem->id;
- ListBase *lbarray[MAX_LIBARRAY];
- int a;
+ Main *bmain = CTX_data_main(C);
+ ID *id = tselem->id;
- BLI_assert(te->idcode == ID_LI && lib != NULL);
+ BLI_assert(te->idcode != 0 && id != NULL);
+ BLI_assert(te->idcode != ID_LI || ((Library *)id)->parent == NULL);
UNUSED_VARS_NDEBUG(te);
- /* We simply set all ID from given lib (including lib itself) to zero user count.
- * It is not possible to do a proper cleanup without a save/reload in current master. */
- a = set_listbasepointers(CTX_data_main(C), lbarray);
- while (a--) {
- ListBase *lb = lbarray[a];
- ID *id;
-
- for (id = lb->first; id; id = id->next) {
- if (id->lib == lib) {
- id_fake_user_clear(id);
- id->us = 0;
+ if (id->tag & LIB_TAG_INDIRECT) {
+ BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked id '%s'", id->name);
+ return;
+ }
+ else if (BKE_library_ID_is_indirectly_used(bmain, id) && ID_REAL_USERS(id) <= 1) {
+ BKE_reportf(reports, RPT_WARNING,
+ "Cannot delete id '%s', indirectly used data-blocks need at least one user",
+ id->name);
+ return;
+ }
+
+
+ BKE_libblock_delete(bmain, id);
+
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+}
+
+void id_delete_cb(
+ bContext *C, ReportList *reports, Scene *UNUSED(scene),
+ TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+{
+ id_delete(C, reports, te, tselem);
+}
+
+static int outliner_id_delete_invoke_do(bContext *C, ReportList *reports, TreeElement *te, const float mval[2])
+{
+ if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ if (te->idcode != 0 && tselem->id) {
+ if (te->idcode == ID_LI && ((Library *)tselem->id)->parent) {
+ BKE_reportf(reports, RPT_ERROR_INVALID_INPUT,
+ "Cannot delete indirectly linked library '%s'", ((Library *)tselem->id)->filepath);
+ return OPERATOR_CANCELLED;
+ }
+ id_delete(C, reports, te, tselem);
+ return OPERATOR_FINISHED;
+ }
+ }
+ else {
+ for (te = te->subtree.first; te; te = te->next) {
+ int ret;
+ if ((ret = outliner_id_delete_invoke_do(C, reports, te, mval))) {
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int outliner_id_delete_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ARegion *ar = CTX_wm_region(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ TreeElement *te;
+ float fmval[2];
+
+ BLI_assert(ar && soops);
+
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
+
+ for (te = soops->tree.first; te; te = te->next) {
+ int ret;
+
+ if ((ret = outliner_id_delete_invoke_do(C, op->reports, te, fmval))) {
+ return ret;
+ }
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+void OUTLINER_OT_id_delete(wmOperatorType *ot)
+{
+ ot->name = "Delete Data-Block";
+ ot->idname = "OUTLINER_OT_id_delete";
+ ot->description = "Delete the ID under cursor";
+
+ ot->invoke = outliner_id_delete_invoke;
+ ot->poll = ED_operator_outliner_active;
+}
+
+/* ID remap --------------------------------------------------- */
+
+static int outliner_id_remap_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+
+ const short id_type = (short)RNA_enum_get(op->ptr, "id_type");
+ ID *old_id = BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "old_id"));
+ ID *new_id = BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "new_id"));
+
+ /* check for invalid states */
+ if (soops == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!(old_id && new_id && (old_id != new_id) && (GS(old_id->name) == GS(new_id->name)))) {
+ BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT, "Invalid old/new ID pair ('%s' / '%s')",
+ old_id ? old_id->name : "Invalid ID", new_id ? new_id->name : "Invalid ID");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (ID_IS_LINKED_DATABLOCK(old_id)) {
+ BKE_reportf(op->reports, RPT_WARNING,
+ "Old ID '%s' is linked from a library, indirect usages of this data-block will not be remapped",
+ old_id->name);
+ }
+
+ BKE_libblock_remap(bmain, old_id, new_id,
+ ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE);
+
+ BKE_main_lib_objects_recalc_all(bmain);
+
+ /* recreate dependency graph to include new objects */
+ DAG_scene_relations_rebuild(bmain, scene);
+
+ /* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */
+ GPU_materials_free();
+
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+static bool outliner_id_remap_find_tree_element(bContext *C, wmOperator *op, ListBase *tree, const float y)
+{
+ TreeElement *te;
+
+ for (te = tree->first; te; te = te->next) {
+ if (y > te->ys && y < te->ys + UI_UNIT_Y) {
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ if (tselem->type == 0 && tselem->id) {
+ printf("found id %s (%p)!\n", tselem->id->name, tselem->id);
+
+ RNA_enum_set(op->ptr, "id_type", GS(tselem->id->name));
+ RNA_enum_set_identifier(C, op->ptr, "new_id", tselem->id->name + 2);
+ RNA_enum_set_identifier(C, op->ptr, "old_id", tselem->id->name + 2);
+ return true;
}
}
+ if (outliner_id_remap_find_tree_element(C, op, &te->subtree, y)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static int outliner_id_remap_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ ARegion *ar = CTX_wm_region(C);
+ float fmval[2];
+
+ if (!RNA_property_is_set(op->ptr, RNA_struct_find_property(op->ptr, "id_type"))) {
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
+
+ outliner_id_remap_find_tree_element(C, op, &soops->tree, fmval[1]);
+ }
+
+ return WM_operator_props_dialog_popup(C, op, 200, 100);
+}
+
+static EnumPropertyItem *outliner_id_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ EnumPropertyItem item_tmp = {0}, *item = NULL;
+ int totitem = 0;
+ int i = 0;
+
+ short id_type = (short)RNA_enum_get(ptr, "id_type");
+ ID *id = which_libbase(CTX_data_main(C), id_type)->first;
+
+ for (; id; id = id->next) {
+ item_tmp.identifier = item_tmp.name = id->name + 2;
+ item_tmp.value = i++;
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
}
- BKE_reportf(reports, RPT_WARNING,
- "Please save and reload .blend file to complete deletion of '%s' library",
- ((Library *)tselem->id)->filepath);
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
}
-void lib_delete_cb(
- bContext *C, Scene *UNUSED(scene), TreeElement *te,
+void OUTLINER_OT_id_remap(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Outliner ID data Remap";
+ ot->idname = "OUTLINER_OT_id_remap";
+ ot->description = "";
+
+ /* callbacks */
+ ot->invoke = outliner_id_remap_invoke;
+ ot->exec = outliner_id_remap_exec;
+ ot->poll = ED_operator_outliner_active;
+
+ ot->flag = 0;
+
+ RNA_def_enum(ot->srna, "id_type", rna_enum_id_type_items, ID_OB, "ID Type", "");
+
+ prop = RNA_def_enum(ot->srna, "old_id", DummyRNA_NULL_items, 0, "Old ID", "Old ID to replace");
+ RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, outliner_id_itemf);
+ RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE | PROP_HIDDEN);
+
+ ot->prop = RNA_def_enum(ot->srna, "new_id", DummyRNA_NULL_items, 0,
+ "New ID", "New ID to remap all selected IDs' users to");
+ RNA_def_property_enum_funcs_runtime(ot->prop, NULL, NULL, outliner_id_itemf);
+ RNA_def_property_flag(ot->prop, PROP_ENUM_NO_TRANSLATE);
+}
+
+void id_remap_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
- lib_delete(C, te, tselem, CTX_wm_reports(C));
+ wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_id_remap", false);
+ PointerRNA op_props;
+
+ BLI_assert(tselem->id != NULL);
+
+ WM_operator_properties_create_ptr(&op_props, ot);
+
+ RNA_enum_set(&op_props, "id_type", GS(tselem->id->name));
+ RNA_enum_set_identifier(C, &op_props, "old_id", tselem->id->name + 2);
+
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_props);
+
+ WM_operator_properties_free(&op_props);
}
-static int outliner_lib_delete_invoke_do(bContext *C, ReportList *reports, TreeElement *te, const float mval[2])
+/* Library relocate/reload --------------------------------------------------- */
+
+static int lib_relocate(
+ bContext *C, TreeElement *te, TreeStoreElem *tselem, wmOperatorType *ot, const bool reload)
+{
+ PointerRNA op_props;
+ int ret = 0;
+
+ BLI_assert(te->idcode == ID_LI && tselem->id != NULL);
+ UNUSED_VARS_NDEBUG(te);
+
+ WM_operator_properties_create_ptr(&op_props, ot);
+
+ RNA_string_set(&op_props, "library", tselem->id->name + 2);
+
+ if (reload) {
+ Library *lib = (Library *)tselem->id;
+ char dir[FILE_MAXDIR], filename[FILE_MAX];
+
+ BLI_split_dirfile(lib->filepath, dir, filename, sizeof(dir), sizeof(filename));
+
+ printf("%s, %s\n", tselem->id->name, lib->filepath);
+
+ /* We assume if both paths in lib are not the same then lib->name was relative... */
+ RNA_boolean_set(&op_props, "relative_path", BLI_path_cmp(lib->filepath, lib->name) != 0);
+
+ RNA_string_set(&op_props, "directory", dir);
+ RNA_string_set(&op_props, "filename", filename);
+
+ ret = WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &op_props);
+ }
+ else {
+ ret = WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_props);
+ }
+
+ WM_operator_properties_free(&op_props);
+
+ return ret;
+}
+
+static int outliner_lib_relocate_invoke_do(
+ bContext *C, ReportList *reports, TreeElement *te, const float mval[2], const bool reload)
{
if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
TreeStoreElem *tselem = TREESTORE(te);
if (te->idcode == ID_LI && tselem->id) {
- if (((Library *)tselem->id)->parent) {
+ if (((Library *)tselem->id)->parent && !reload) {
BKE_reportf(reports, RPT_ERROR_INVALID_INPUT,
- "Cannot delete indirectly linked library '%s'", ((Library *)tselem->id)->filepath);
+ "Cannot relocate indirectly linked library '%s'", ((Library *)tselem->id)->filepath);
return OPERATOR_CANCELLED;
}
+ else {
+ wmOperatorType *ot = WM_operatortype_find(reload ? "WM_OT_lib_reload" : "WM_OT_lib_relocate", false);
- lib_delete(C, te, tselem, reports);
- return OPERATOR_FINISHED;
+ return lib_relocate(C, te, tselem, ot, reload);
+ }
}
}
else {
for (te = te->subtree.first; te; te = te->next) {
int ret;
- if ((ret = outliner_lib_delete_invoke_do(C, reports, te, mval))) {
+ if ((ret = outliner_lib_relocate_invoke_do(C, reports, te, mval, reload))) {
return ret;
}
}
@@ -357,7 +618,51 @@ static int outliner_lib_delete_invoke_do(bContext *C, ReportList *reports, TreeE
return 0;
}
-static int outliner_lib_delete_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int outliner_lib_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ARegion *ar = CTX_wm_region(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ TreeElement *te;
+ float fmval[2];
+
+ BLI_assert(ar && soops);
+
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
+
+ for (te = soops->tree.first; te; te = te->next) {
+ int ret;
+
+ if ((ret = outliner_lib_relocate_invoke_do(C, op->reports, te, fmval, false))) {
+ return ret;
+ }
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+void OUTLINER_OT_lib_relocate(wmOperatorType *ot)
+{
+ ot->name = "Relocate Library";
+ ot->idname = "OUTLINER_OT_lib_relocate";
+ ot->description = "Relocate the library under cursor";
+
+ ot->invoke = outliner_lib_relocate_invoke;
+ ot->poll = ED_operator_outliner_active;
+}
+
+/* XXX This does not work with several items
+ * (it is only called once in the end, due to the 'deferred' filebrowser invocation through event system...). */
+void lib_relocate_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te,
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+{
+ wmOperatorType *ot = WM_operatortype_find("WM_OT_lib_relocate", false);
+
+ lib_relocate(C, te, tselem, ot, false);
+}
+
+
+static int outliner_lib_reload_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
@@ -371,7 +676,7 @@ static int outliner_lib_delete_invoke(bContext *C, wmOperator *op, const wmEvent
for (te = soops->tree.first; te; te = te->next) {
int ret;
- if ((ret = outliner_lib_delete_invoke_do(C, op->reports, te, fmval))) {
+ if ((ret = outliner_lib_relocate_invoke_do(C, op->reports, te, fmval, true))) {
return ret;
}
}
@@ -379,16 +684,25 @@ static int outliner_lib_delete_invoke(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_CANCELLED;
}
-void OUTLINER_OT_lib_delete(wmOperatorType *ot)
+void OUTLINER_OT_lib_reload(wmOperatorType *ot)
{
- ot->name = "Delete Library";
- ot->idname = "OUTLINER_OT_lib_delete";
- ot->description = "Delete the library under cursor (needs a save/reload)";
+ ot->name = "Reload Library";
+ ot->idname = "OUTLINER_OT_lib_reload";
+ ot->description = "Reload the library under cursor";
- ot->invoke = outliner_lib_delete_invoke;
+ ot->invoke = outliner_lib_reload_invoke;
ot->poll = ED_operator_outliner_active;
}
+void lib_reload_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te,
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+{
+ wmOperatorType *ot = WM_operatortype_find("WM_OT_lib_reload", false);
+
+ lib_relocate(C, te, tselem, ot, true);
+}
+
/* ************************************************************** */
/* Setting Toggling Operators */
@@ -397,20 +711,20 @@ void OUTLINER_OT_lib_delete(wmOperatorType *ot)
/* Apply Settings ------------------------------- */
-static int outliner_count_levels(SpaceOops *soops, ListBase *lb, const int curlevel)
+static int outliner_count_levels(ListBase *lb, const int curlevel)
{
TreeElement *te;
int level = curlevel, lev;
for (te = lb->first; te; te = te->next) {
- lev = outliner_count_levels(soops, &te->subtree, curlevel + 1);
+ lev = outliner_count_levels(&te->subtree, curlevel + 1);
if (lev > level) level = lev;
}
return level;
}
-int outliner_has_one_flag(SpaceOops *soops, ListBase *lb, short flag, const int curlevel)
+int outliner_has_one_flag(ListBase *lb, short flag, const int curlevel)
{
TreeElement *te;
TreeStoreElem *tselem;
@@ -420,13 +734,13 @@ int outliner_has_one_flag(SpaceOops *soops, ListBase *lb, short flag, const int
tselem = TREESTORE(te);
if (tselem->flag & flag) return curlevel;
- level = outliner_has_one_flag(soops, &te->subtree, flag, curlevel + 1);
+ level = outliner_has_one_flag(&te->subtree, flag, curlevel + 1);
if (level) return level;
}
return 0;
}
-void outliner_set_flag(SpaceOops *soops, ListBase *lb, short flag, short set)
+void outliner_set_flag(ListBase *lb, short flag, short set)
{
TreeElement *te;
TreeStoreElem *tselem;
@@ -435,7 +749,7 @@ void outliner_set_flag(SpaceOops *soops, ListBase *lb, short flag, short set)
tselem = TREESTORE(te);
if (set == 0) tselem->flag &= ~flag;
else tselem->flag |= flag;
- outliner_set_flag(soops, &te->subtree, flag, set);
+ outliner_set_flag(&te->subtree, flag, set);
}
}
@@ -468,12 +782,18 @@ int common_restrict_check(bContext *C, Object *ob)
/* Toggle Visibility ---------------------------------------- */
-void object_toggle_visibility_cb(bContext *C, Scene *scene, TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+void object_toggle_visibility_cb(
+ bContext *C, ReportList *reports, Scene *scene, TreeElement *te,
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Base *base = (Base *)te->directdata;
Object *ob = (Object *)tselem->id;
-
+
+ if (ID_IS_LINKED_DATABLOCK(tselem->id)) {
+ BKE_report(reports, RPT_WARNING, "Cannot edit external libdata");
+ return;
+ }
+
/* add check for edit mode */
if (!common_restrict_check(C, ob)) return;
@@ -484,21 +804,22 @@ void object_toggle_visibility_cb(bContext *C, Scene *scene, TreeElement *te,
}
}
-void group_toggle_visibility_cb(bContext *UNUSED(C), Scene *scene, TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+void group_toggle_visibility_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Group *group = (Group *)tselem->id;
restrictbutton_gr_restrict_flag(scene, group, OB_RESTRICT_VIEW);
}
-static int outliner_toggle_visibility_exec(bContext *C, wmOperator *UNUSED(op))
+static int outliner_toggle_visibility_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
- outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_visibility_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_visibility_cb);
DAG_id_type_tag(bmain, ID_OB);
WM_event_add_notifier(C, NC_SCENE | ND_OB_VISIBLE, scene);
@@ -523,31 +844,38 @@ void OUTLINER_OT_visibility_toggle(wmOperatorType *ot)
/* Toggle Selectability ---------------------------------------- */
-void object_toggle_selectability_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+void object_toggle_selectability_cb(
+ bContext *UNUSED(C), ReportList *reports, Scene *scene, TreeElement *te,
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Base *base = (Base *)te->directdata;
-
+
+ if (ID_IS_LINKED_DATABLOCK(tselem->id)) {
+ BKE_report(reports, RPT_WARNING, "Cannot edit external libdata");
+ return;
+ }
+
if (base == NULL) base = BKE_scene_base_find(scene, (Object *)tselem->id);
if (base) {
base->object->restrictflag ^= OB_RESTRICT_SELECT;
}
}
-void group_toggle_selectability_cb(bContext *UNUSED(C), Scene *scene, TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+void group_toggle_selectability_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Group *group = (Group *)tselem->id;
restrictbutton_gr_restrict_flag(scene, group, OB_RESTRICT_SELECT);
}
-static int outliner_toggle_selectability_exec(bContext *C, wmOperator *UNUSED(op))
+static int outliner_toggle_selectability_exec(bContext *C, wmOperator *op)
{
SpaceOops *soops = CTX_wm_space_outliner(C);
Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
- outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_selectability_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_selectability_cb);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
ED_region_tag_redraw(ar);
@@ -571,31 +899,38 @@ void OUTLINER_OT_selectability_toggle(wmOperatorType *ot)
/* Toggle Renderability ---------------------------------------- */
-void object_toggle_renderability_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+void object_toggle_renderability_cb(
+ bContext *UNUSED(C), ReportList *reports, Scene *scene, TreeElement *te,
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Base *base = (Base *)te->directdata;
-
+
+ if (ID_IS_LINKED_DATABLOCK(tselem->id)) {
+ BKE_report(reports, RPT_WARNING, "Cannot edit external libdata");
+ return;
+ }
+
if (base == NULL) base = BKE_scene_base_find(scene, (Object *)tselem->id);
if (base) {
base->object->restrictflag ^= OB_RESTRICT_RENDER;
}
}
-void group_toggle_renderability_cb(bContext *UNUSED(C), Scene *scene, TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+void group_toggle_renderability_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Group *group = (Group *)tselem->id;
restrictbutton_gr_restrict_flag(scene, group, OB_RESTRICT_RENDER);
}
-static int outliner_toggle_renderability_exec(bContext *C, wmOperator *UNUSED(op))
+static int outliner_toggle_renderability_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
Scene *scene = CTX_data_scene(C);
- outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_renderability_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_renderability_cb);
DAG_id_type_tag(bmain, ID_OB);
WM_event_add_notifier(C, NC_SCENE | ND_OB_RENDER, scene);
@@ -627,10 +962,10 @@ static int outliner_toggle_expanded_exec(bContext *C, wmOperator *UNUSED(op))
SpaceOops *soops = CTX_wm_space_outliner(C);
ARegion *ar = CTX_wm_region(C);
- if (outliner_has_one_flag(soops, &soops->tree, TSE_CLOSED, 1))
- outliner_set_flag(soops, &soops->tree, TSE_CLOSED, 0);
+ if (outliner_has_one_flag(&soops->tree, TSE_CLOSED, 1))
+ outliner_set_flag(&soops->tree, TSE_CLOSED, 0);
else
- outliner_set_flag(soops, &soops->tree, TSE_CLOSED, 1);
+ outliner_set_flag(&soops->tree, TSE_CLOSED, 1);
ED_region_tag_redraw(ar);
@@ -659,10 +994,10 @@ static int outliner_toggle_selected_exec(bContext *C, wmOperator *UNUSED(op))
ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
- if (outliner_has_one_flag(soops, &soops->tree, TSE_SELECTED, 1))
- outliner_set_flag(soops, &soops->tree, TSE_SELECTED, 0);
+ if (outliner_has_one_flag(&soops->tree, TSE_SELECTED, 1))
+ outliner_set_flag(&soops->tree, TSE_SELECTED, 0);
else
- outliner_set_flag(soops, &soops->tree, TSE_SELECTED, 1);
+ outliner_set_flag(&soops->tree, TSE_SELECTED, 1);
soops->storeflag |= SO_TREESTORE_REDRAW;
@@ -760,13 +1095,13 @@ static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op))
if (obact->mode & OB_MODE_POSE) {
bPoseChannel *pchan = CTX_data_active_pose_bone(C);
if (pchan) {
- te = outliner_find_posechannel(so, &te_obact->subtree, pchan);
+ te = outliner_find_posechannel(&te_obact->subtree, pchan);
}
}
else if (obact->mode & OB_MODE_EDIT) {
EditBone *ebone = CTX_data_active_bone(C);
if (ebone) {
- te = outliner_find_editbone(so, &te_obact->subtree, ebone);
+ te = outliner_find_editbone(&te_obact->subtree, ebone);
}
}
}
@@ -961,7 +1296,7 @@ static void outliner_find_panel(Scene *UNUSED(scene), ARegion *ar, SpaceOops *so
/* Show One Level ----------------------------------------------- */
/* helper function for Show/Hide one level operator */
-static void outliner_openclose_level(SpaceOops *soops, ListBase *lb, int curlevel, int level, int open)
+static void outliner_openclose_level(ListBase *lb, int curlevel, int level, int open)
{
TreeElement *te;
TreeStoreElem *tselem;
@@ -976,7 +1311,7 @@ static void outliner_openclose_level(SpaceOops *soops, ListBase *lb, int curleve
if (curlevel >= level) tselem->flag |= TSE_CLOSED;
}
- outliner_openclose_level(soops, &te->subtree, curlevel + 1, level, open);
+ outliner_openclose_level(&te->subtree, curlevel + 1, level, open);
}
}
@@ -987,13 +1322,13 @@ static int outliner_one_level_exec(bContext *C, wmOperator *op)
const bool add = RNA_boolean_get(op->ptr, "open");
int level;
- level = outliner_has_one_flag(soops, &soops->tree, TSE_CLOSED, 1);
+ level = outliner_has_one_flag(&soops->tree, TSE_CLOSED, 1);
if (add == 1) {
- if (level) outliner_openclose_level(soops, &soops->tree, 1, level, 1);
+ if (level) outliner_openclose_level(&soops->tree, 1, level, 1);
}
else {
- if (level == 0) level = outliner_count_levels(soops, &soops->tree, 0);
- if (level) outliner_openclose_level(soops, &soops->tree, 1, level - 1, 0);
+ if (level == 0) level = outliner_count_levels(&soops->tree, 0);
+ if (level) outliner_openclose_level(&soops->tree, 1, level - 1, 0);
}
ED_region_tag_redraw(ar);
@@ -1024,7 +1359,7 @@ void OUTLINER_OT_show_one_level(wmOperatorType *ot)
/* Show Hierarchy ----------------------------------------------- */
/* helper function for tree_element_shwo_hierarchy() - recursively checks whether subtrees have any objects*/
-static int subtree_has_objects(SpaceOops *soops, ListBase *lb)
+static int subtree_has_objects(ListBase *lb)
{
TreeElement *te;
TreeStoreElem *tselem;
@@ -1032,7 +1367,7 @@ static int subtree_has_objects(SpaceOops *soops, ListBase *lb)
for (te = lb->first; te; te = te->next) {
tselem = TREESTORE(te);
if (tselem->type == 0 && te->idcode == ID_OB) return 1;
- if (subtree_has_objects(soops, &te->subtree)) return 1;
+ if (subtree_has_objects(&te->subtree)) return 1;
}
return 0;
}
@@ -1053,7 +1388,7 @@ static void tree_element_show_hierarchy(Scene *scene, SpaceOops *soops, ListBase
else tselem->flag &= ~TSE_CLOSED;
}
else if (te->idcode == ID_OB) {
- if (subtree_has_objects(soops, &te->subtree)) tselem->flag &= ~TSE_CLOSED;
+ if (subtree_has_objects(&te->subtree)) tselem->flag &= ~TSE_CLOSED;
else tselem->flag |= TSE_CLOSED;
}
}
@@ -1605,7 +1940,7 @@ static int outliner_orphans_purge_invoke(bContext *C, wmOperator *op, const wmEv
{
/* present a prompt to informing users that this change is irreversible */
return WM_operator_confirm_message(C, op,
- "Purging unused datablocks cannot be undone. "
+ "Purging unused data-blocks cannot be undone. "
"Click here to proceed...");
}
@@ -1627,7 +1962,7 @@ void OUTLINER_OT_orphans_purge(wmOperatorType *ot)
/* identifiers */
ot->idname = "OUTLINER_OT_orphans_purge";
ot->name = "Purge All";
- ot->description = "Clear all orphaned datablocks without any users from the file (cannot be undone)";
+ ot->description = "Clear all orphaned data-blocks without any users from the file (cannot be undone)";
/* callbacks */
ot->invoke = outliner_orphans_purge_invoke;
@@ -1657,7 +1992,7 @@ static int parent_drop_exec(bContext *C, wmOperator *op)
RNA_string_get(op->ptr, "child", childname);
ob = (Object *)BKE_libblock_find_name(ID_OB, childname);
- if (ob->id.lib) {
+ if (ID_IS_LINKED_DATABLOCK(ob)) {
BKE_report(op->reports, RPT_INFO, "Can't edit library linked object");
return OPERATOR_CANCELLED;
}
@@ -1705,7 +2040,7 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (ob == par) {
return OPERATOR_CANCELLED;
}
- if (ob->id.lib) {
+ if (ID_IS_LINKED_DATABLOCK(ob)) {
BKE_report(op->reports, RPT_INFO, "Can't edit library linked object");
return OPERATOR_CANCELLED;
}
@@ -1914,7 +2249,7 @@ static int scene_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
RNA_string_get(op->ptr, "object", obname);
ob = (Object *)BKE_libblock_find_name(ID_OB, obname);
- if (ELEM(NULL, ob, scene) || scene->id.lib != NULL) {
+ if (ELEM(NULL, ob, scene) || ID_IS_LINKED_DATABLOCK(scene)) {
return OPERATOR_CANCELLED;
}
@@ -2079,36 +2414,3 @@ void OUTLINER_OT_group_link(wmOperatorType *ot)
/* properties */
RNA_def_string(ot->srna, "object", "Object", MAX_ID_NAME, "Object", "Target Object");
}
-
-/******** Utils to clear any ref to freed ID... **********/
-
-void ED_outliner_id_unref(SpaceOops *so, const ID *id)
-{
- /* Some early out checks. */
- if (!TREESTORE_ID_TYPE(id)) {
- return; /* ID type is not used by outilner... */
- }
-
- if (so->search_tse.id == id) {
- so->search_tse.id = NULL;
- }
-
- if (so->treestore) {
- TreeStoreElem *tselem;
- BLI_mempool_iter iter;
- bool changed = false;
-
- BLI_mempool_iternew(so->treestore, &iter);
- while ((tselem = BLI_mempool_iterstep(&iter))) {
- if (tselem->id == id) {
- tselem->id = NULL;
- changed = true;
- }
- }
- if (so->treehash && changed) {
- /* rebuild hash table, because it depends on ids too */
- /* postpone a full rebuild because this can be called many times on-free */
- so->storeflag |= SO_TREESTORE_REBUILD;
- }
- }
-}
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index dc81be7a8e0..ccc52f2dba8 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -62,7 +62,7 @@ typedef struct TreeElement {
#define TREESTORE_ID_TYPE(_id) \
(ELEM(GS((_id)->name), ID_SCE, ID_LI, ID_OB, ID_ME, ID_CU, ID_MB, ID_NT, ID_MA, ID_TE, ID_IM, ID_LT, ID_LA, ID_CA) || \
ELEM(GS((_id)->name), ID_KE, ID_WO, ID_SPK, ID_GR, ID_AR, ID_AC, ID_BR, ID_PA, ID_GD, ID_LS) || \
- ELEM(GS((_id)->name), ID_SCR, ID_WM, ID_TXT, ID_VF, ID_SO)) /* Only in 'blendfile' mode ... :/ */
+ ELEM(GS((_id)->name), ID_SCR, ID_WM, ID_TXT, ID_VF, ID_SO, ID_CF, ID_PAL)) /* Only in 'blendfile' mode ... :/ */
/* TreeElement->flag */
#define TE_ACTIVE 1
@@ -133,8 +133,8 @@ void outliner_cleanup_tree(struct SpaceOops *soops);
TreeElement *outliner_find_tse(struct SpaceOops *soops, const TreeStoreElem *tse);
TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store_elem);
TreeElement *outliner_find_id(struct SpaceOops *soops, ListBase *lb, const struct ID *id);
-TreeElement *outliner_find_posechannel(struct SpaceOops *soops, ListBase *lb, const struct bPoseChannel *pchan);
-TreeElement *outliner_find_editbone(struct SpaceOops *soops, ListBase *lb, const struct EditBone *ebone);
+TreeElement *outliner_find_posechannel(ListBase *lb, const struct bPoseChannel *pchan);
+TreeElement *outliner_find_editbone(ListBase *lb, const struct EditBone *ebone);
struct ID *outliner_search_back(SpaceOops *soops, TreeElement *te, short idcode);
void outliner_build_tree(struct Main *mainvar, struct Scene *scene, struct SpaceOops *soops);
@@ -153,35 +153,58 @@ eOLDrawState tree_element_active(struct bContext *C, struct Scene *scene, SpaceO
int outliner_item_do_activate(struct bContext *C, int x, int y, bool extend, bool recursive);
/* outliner_edit.c ---------------------------------------------- */
+typedef void (*outliner_operation_cb)(
+ struct bContext *C, struct ReportList *, struct Scene *scene,
+ struct TreeElement *, struct TreeStoreElem *, TreeStoreElem *, void *);
void outliner_do_object_operation_ex(
- struct bContext *C, struct Scene *scene, struct SpaceOops *soops, struct ListBase *lb,
- void (*operation_cb)(struct bContext *C, struct Scene *scene,
- struct TreeElement *, struct TreeStoreElem *, TreeStoreElem *, void *),
- bool recurse_selected);
+ struct bContext *C, ReportList *reports, struct Scene *scene, struct SpaceOops *soops, struct ListBase *lb,
+ outliner_operation_cb operation_cb, bool recurse_selected);
void outliner_do_object_operation(
- struct bContext *C, struct Scene *scene, struct SpaceOops *soops, struct ListBase *lb,
- void (*operation_cb)(struct bContext *C, struct Scene *scene,
- struct TreeElement *, struct TreeStoreElem *, TreeStoreElem *, void *));
+ struct bContext *C, ReportList *reports, struct Scene *scene, struct SpaceOops *soops, struct ListBase *lb,
+ outliner_operation_cb operation_cb);
int common_restrict_check(struct bContext *C, struct Object *ob);
-int outliner_has_one_flag(struct SpaceOops *soops, ListBase *lb, short flag, const int curlevel);
-void outliner_set_flag(struct SpaceOops *soops, ListBase *lb, short flag, short set);
-
-void object_toggle_visibility_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
-void object_toggle_selectability_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
-void object_toggle_renderability_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
-
-
-void group_toggle_visibility_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
-void group_toggle_selectability_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
-void group_toggle_renderability_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
-
-void item_rename_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+int outliner_has_one_flag(ListBase *lb, short flag, const int curlevel);
+void outliner_set_flag(ListBase *lb, short flag, short set);
+
+void object_toggle_visibility_cb(
+ struct bContext *C, struct ReportList *reports, struct Scene *scene,
+ TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+void object_toggle_selectability_cb(
+ struct bContext *C, struct ReportList *reports, struct Scene *scene,
+ TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+void object_toggle_renderability_cb(
+ struct bContext *C, struct ReportList *reports, struct Scene *scene,
+ TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+
+
+void group_toggle_visibility_cb(
+ struct bContext *C, struct ReportList *reports, struct Scene *scene,
+ TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+void group_toggle_selectability_cb(
+ struct bContext *C, struct ReportList *reports, struct Scene *scene,
+ TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+void group_toggle_renderability_cb(
+ struct bContext *C, struct ReportList *reports, struct Scene *scene,
+ TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+
+void item_rename_cb(
+ struct bContext *C, struct ReportList *reports, struct Scene *scene,
+ TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+void lib_relocate_cb(
+ struct bContext *C, struct ReportList *reports, struct Scene *scene, struct TreeElement *te,
+ struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+void lib_reload_cb(
+ struct bContext *C, struct ReportList *reports, struct Scene *scene, struct TreeElement *te,
+ struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
-void lib_delete_cb(
- struct bContext *C, struct Scene *scene, struct TreeElement *te,
+void id_delete_cb(
+ struct bContext *C, struct ReportList *reports, struct Scene *scene, struct TreeElement *te,
+ struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+void id_remap_cb(
+ struct bContext *C, struct ReportList *reports, struct Scene *scene, struct TreeElement *te,
struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
TreeElement *outliner_dropzone_find(const struct SpaceOops *soops, const float fmval[2], const bool children);
@@ -190,8 +213,10 @@ TreeElement *outliner_dropzone_find(const struct SpaceOops *soops, const float f
void OUTLINER_OT_item_activate(struct wmOperatorType *ot);
void OUTLINER_OT_item_openclose(struct wmOperatorType *ot);
void OUTLINER_OT_item_rename(struct wmOperatorType *ot);
+void OUTLINER_OT_lib_relocate(struct wmOperatorType *ot);
+void OUTLINER_OT_lib_reload(struct wmOperatorType *ot);
-void OUTLINER_OT_lib_delete(struct wmOperatorType *ot);
+void OUTLINER_OT_id_delete(struct wmOperatorType *ot);
void OUTLINER_OT_show_one_level(struct wmOperatorType *ot);
void OUTLINER_OT_show_active(struct wmOperatorType *ot);
@@ -230,6 +255,7 @@ void OUTLINER_OT_object_operation(struct wmOperatorType *ot);
void OUTLINER_OT_group_operation(struct wmOperatorType *ot);
void OUTLINER_OT_lib_operation(struct wmOperatorType *ot);
void OUTLINER_OT_id_operation(struct wmOperatorType *ot);
+void OUTLINER_OT_id_remap(struct wmOperatorType *ot);
void OUTLINER_OT_data_operation(struct wmOperatorType *ot);
void OUTLINER_OT_animdata_operation(struct wmOperatorType *ot);
void OUTLINER_OT_action_set(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c
index 720cfe12567..776717c8443 100644
--- a/source/blender/editors/space_outliner/outliner_ops.c
+++ b/source/blender/editors/space_outliner/outliner_ops.c
@@ -47,13 +47,15 @@ void outliner_operatortypes(void)
WM_operatortype_append(OUTLINER_OT_select_border);
WM_operatortype_append(OUTLINER_OT_item_openclose);
WM_operatortype_append(OUTLINER_OT_item_rename);
- WM_operatortype_append(OUTLINER_OT_lib_delete);
WM_operatortype_append(OUTLINER_OT_operation);
WM_operatortype_append(OUTLINER_OT_scene_operation);
WM_operatortype_append(OUTLINER_OT_object_operation);
WM_operatortype_append(OUTLINER_OT_group_operation);
WM_operatortype_append(OUTLINER_OT_lib_operation);
+ WM_operatortype_append(OUTLINER_OT_lib_relocate);
WM_operatortype_append(OUTLINER_OT_id_operation);
+ WM_operatortype_append(OUTLINER_OT_id_delete);
+ WM_operatortype_append(OUTLINER_OT_id_remap);
WM_operatortype_append(OUTLINER_OT_data_operation);
WM_operatortype_append(OUTLINER_OT_animdata_operation);
WM_operatortype_append(OUTLINER_OT_action_set);
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index 21bee2c7cce..89df471990a 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -904,7 +904,7 @@ static bool do_outliner_item_activate(bContext *C, Scene *scene, ARegion *ar, Sp
/* all below close/open? */
if (extend) {
tselem->flag &= ~TSE_CLOSED;
- outliner_set_flag(soops, &te->subtree, TSE_CLOSED, !outliner_has_one_flag(soops, &te->subtree, TSE_CLOSED, 1));
+ outliner_set_flag(&te->subtree, TSE_CLOSED, !outliner_has_one_flag(&te->subtree, TSE_CLOSED, 1));
}
else {
if (tselem->flag & TSE_CLOSED) tselem->flag &= ~TSE_CLOSED;
@@ -1062,7 +1062,7 @@ void OUTLINER_OT_item_activate(wmOperatorType *ot)
/* ****************************************************** */
/* **************** Border Select Tool ****************** */
-static void outliner_item_border_select(Scene *scene, SpaceOops *soops, rctf *rectf, TreeElement *te, int gesture_mode)
+static void outliner_item_border_select(Scene *scene, rctf *rectf, TreeElement *te, int gesture_mode)
{
TreeStoreElem *tselem = TREESTORE(te);
@@ -1078,7 +1078,7 @@ static void outliner_item_border_select(Scene *scene, SpaceOops *soops, rctf *re
/* Look at its children. */
if ((tselem->flag & TSE_CLOSED) == 0) {
for (te = te->subtree.first; te; te = te->next) {
- outliner_item_border_select(scene, soops, rectf, te, gesture_mode);
+ outliner_item_border_select(scene, rectf, te, gesture_mode);
}
}
}
@@ -1096,7 +1096,7 @@ static int outliner_border_select_exec(bContext *C, wmOperator *op)
UI_view2d_region_to_view_rctf(&ar->v2d, &rectf, &rectf);
for (te = soops->tree.first; te; te = te->next) {
- outliner_item_border_select(scene, soops, &rectf, te, gesture_mode);
+ outliner_item_border_select(scene, &rectf, te, gesture_mode);
}
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index 83677b6bd86..13200e92e7e 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -57,6 +57,8 @@
#include "BKE_fcurve.h"
#include "BKE_group.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_scene.h"
@@ -133,15 +135,17 @@ static void set_operation_types(SpaceOops *soops, ListBase *lb,
}
}
-static void unlink_action_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
+static void unlink_action_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
{
/* just set action to NULL */
BKE_animdata_set_action(CTX_wm_reports(C), tsep->id, NULL);
}
-static void unlink_material_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *te,
- TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
+static void unlink_material_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te,
+ TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
{
Material **matar = NULL;
int a, totcol = 0;
@@ -180,8 +184,9 @@ static void unlink_material_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeEl
}
}
-static void unlink_texture_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *te,
- TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
+static void unlink_texture_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te,
+ TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
{
MTex **mtex = NULL;
int a;
@@ -217,7 +222,7 @@ static void unlink_texture_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeEle
}
static void unlink_group_cb(
- bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
{
Group *group = (Group *)tselem->id;
@@ -230,12 +235,14 @@ static void unlink_group_cb(
}
else {
Main *bmain = CTX_data_main(C);
- BKE_group_unlink(bmain, group);
+ BKE_libblock_unlink(bmain, group, false, false);
+ BKE_libblock_free(bmain, group);
}
}
-static void unlink_world_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
+static void unlink_world_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
{
Scene *parscene = (Scene *)tsep->id;
World *wo = (World *)tselem->id;
@@ -246,8 +253,8 @@ static void unlink_world_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeEleme
}
static void outliner_do_libdata_operation(
- bContext *C, Scene *scene, SpaceOops *soops, ListBase *lb,
- void (*operation_cb)(bContext *C, Scene *scene, TreeElement *, TreeStoreElem *, TreeStoreElem *, void *),
+ bContext *C, ReportList *reports, Scene *scene, SpaceOops *soops, ListBase *lb,
+ outliner_operation_cb operation_cb,
void *user_data)
{
TreeElement *te;
@@ -258,11 +265,11 @@ static void outliner_do_libdata_operation(
if (tselem->flag & TSE_SELECTED) {
if (tselem->type == 0) {
TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL;
- operation_cb(C, scene, te, tsep, tselem, user_data);
+ operation_cb(C, reports, scene, te, tsep, tselem, user_data);
}
}
if (TSELEM_OPEN(tselem, soops)) {
- outliner_do_libdata_operation(C, scene, soops, &te->subtree, operation_cb, user_data);
+ outliner_do_libdata_operation(C, reports, scene, soops, &te->subtree, operation_cb, user_data);
}
}
}
@@ -352,8 +359,9 @@ void OUTLINER_OT_scene_operation(wmOperatorType *ot)
}
/* ******************************************** */
-static void object_select_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+static void object_select_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *te,
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Base *base = (Base *)te->directdata;
@@ -364,8 +372,9 @@ static void object_select_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te,
}
}
-static void object_select_hierarchy_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
+static void object_select_hierarchy_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
{
/* From where do i get the x,y coordinate of the mouse event ? */
wmWindow *win = CTX_wm_window(C);
@@ -375,8 +384,9 @@ static void object_select_hierarchy_cb(bContext *C, Scene *UNUSED(scene), TreeEl
}
-static void object_deselect_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+static void object_deselect_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *te,
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Base *base = (Base *)te->directdata;
@@ -387,14 +397,27 @@ static void object_deselect_cb(bContext *UNUSED(C), Scene *scene, TreeElement *t
}
}
-static void object_delete_cb(bContext *C, Scene *scene, TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+static void object_delete_cb(
+ bContext *C, ReportList *reports, Scene *scene, TreeElement *te,
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Base *base = (Base *)te->directdata;
if (base == NULL)
base = BKE_scene_base_find(scene, (Object *)tselem->id);
if (base) {
+ Main *bmain = CTX_data_main(C);
+ if (base->object->id.tag & LIB_TAG_INDIRECT) {
+ BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2);
+ return;
+ }
+ else if (BKE_library_ID_is_indirectly_used(bmain, base->object) && ID_REAL_USERS(base->object) <= 1) {
+ BKE_reportf(reports, RPT_WARNING,
+ "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user",
+ base->object->id.name + 2, scene->id.name + 2);
+ return;
+ }
+
// check also library later
if (scene->obedit == base->object)
ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO);
@@ -408,45 +431,50 @@ static void object_delete_cb(bContext *C, Scene *scene, TreeElement *te,
}
}
-static void id_local_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+static void id_local_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
- if (tselem->id->lib && (tselem->id->tag & LIB_TAG_EXTERN)) {
+ if (ID_IS_LINKED_DATABLOCK(tselem->id) && (tselem->id->tag & LIB_TAG_EXTERN)) {
+ Main *bmain = CTX_data_main(C);
/* if the ID type has no special local function,
* just clear the lib */
- if (id_make_local(tselem->id, false) == false) {
- Main *bmain = CTX_data_main(C);
+ if (id_make_local(bmain, tselem->id, false, false) == false) {
id_clear_lib_data(bmain, tselem->id);
}
}
}
-static void id_fake_user_set_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+static void id_fake_user_set_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
ID *id = tselem->id;
id_fake_user_set(id);
}
-static void id_fake_user_clear_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+static void id_fake_user_clear_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
ID *id = tselem->id;
id_fake_user_clear(id);
}
-static void id_select_linked_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+static void id_select_linked_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
ID *id = tselem->id;
ED_object_select_linked_by_id(C, id);
}
-static void singleuser_action_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
+static void singleuser_action_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
{
ID *id = tselem->id;
@@ -462,8 +490,9 @@ static void singleuser_action_cb(bContext *C, Scene *UNUSED(scene), TreeElement
}
}
-static void singleuser_world_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
+static void singleuser_world_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
{
ID *id = tselem->id;
@@ -480,34 +509,29 @@ static void singleuser_world_cb(bContext *C, Scene *UNUSED(scene), TreeElement *
}
}
-static void group_linkobs2scene_cb(bContext *UNUSED(C), Scene *scene, TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+static void group_linkobs2scene_cb(
+ bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Group *group = (Group *)tselem->id;
GroupObject *gob;
Base *base;
-
+
for (gob = group->gobject.first; gob; gob = gob->next) {
base = BKE_scene_base_find(scene, gob->ob);
- if (base) {
- base->object->flag |= SELECT;
- base->flag |= SELECT;
- }
- else {
+ if (!base) {
/* link to scene */
- base = MEM_callocN(sizeof(Base), "add_base");
- BLI_addhead(&scene->base, base);
- base->lay = gob->ob->lay;
- gob->ob->flag |= SELECT;
- base->flag = gob->ob->flag;
- base->object = gob->ob;
+ base = BKE_scene_base_add(scene, gob->ob);
id_lib_extern((ID *)gob->ob); /* in case these are from a linked group */
}
+ base->object->flag |= SELECT;
+ base->flag |= SELECT;
}
}
-static void group_instance_cb(bContext *C, Scene *scene, TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+static void group_instance_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Group *group = (Group *)tselem->id;
@@ -521,10 +545,8 @@ static void group_instance_cb(bContext *C, Scene *scene, TreeElement *UNUSED(te)
* \param select_recurse: Set to false for operations which are already recursively operating on their children.
*/
void outliner_do_object_operation_ex(
- bContext *C, Scene *scene_act, SpaceOops *soops, ListBase *lb,
- void (*operation_cb)(bContext *C, Scene *scene, TreeElement *,
- TreeStoreElem *, TreeStoreElem *, void *),
- bool select_recurse)
+ bContext *C, ReportList *reports, Scene *scene_act, SpaceOops *soops, ListBase *lb,
+ outliner_operation_cb operation_cb, bool select_recurse)
{
TreeElement *te;
@@ -541,23 +563,24 @@ void outliner_do_object_operation_ex(
/* important to use 'scene_owner' not scene_act else deleting objects can crash.
* only use 'scene_act' when 'scene_owner' is NULL, which can happen when the
* outliner isn't showing scenes: Visible Layer draw mode for eg. */
- operation_cb(C, scene_owner ? scene_owner : scene_act, te, NULL, tselem, NULL);
+ operation_cb(C, reports, scene_owner ? scene_owner : scene_act, te, NULL, tselem, NULL);
select_handled = true;
}
}
if (TSELEM_OPEN(tselem, soops)) {
if ((select_handled == false) || select_recurse) {
- outliner_do_object_operation_ex(C, scene_act, soops, &te->subtree, operation_cb, select_recurse);
+ outliner_do_object_operation_ex(
+ C, reports, scene_act, soops, &te->subtree, operation_cb, select_recurse);
}
}
}
}
void outliner_do_object_operation(
- bContext *C, Scene *scene_act, SpaceOops *soops, ListBase *lb,
- void (*operation_cb)(bContext *, Scene *, TreeElement *, TreeStoreElem *, TreeStoreElem *, void *))
+ bContext *C, ReportList *reports, Scene *scene_act, SpaceOops *soops, ListBase *lb,
+ outliner_operation_cb operation_cb)
{
- outliner_do_object_operation_ex(C, scene_act, soops, lb, operation_cb, true);
+ outliner_do_object_operation_ex(C, reports, scene_act, soops, lb, operation_cb, true);
}
/* ******************************************** */
@@ -565,7 +588,7 @@ void outliner_do_object_operation(
static void clear_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te),
TreeStoreElem *tselem, void *UNUSED(arg))
{
- BKE_animdata_free(tselem->id);
+ BKE_animdata_free(tselem->id, true);
}
@@ -792,7 +815,7 @@ static void outliner_do_data_operation(SpaceOops *soops, int type, int event, Li
}
}
-static Base *outline_delete_hierarchy(bContext *C, Scene *scene, Base *base)
+static Base *outline_delete_hierarchy(bContext *C, ReportList *reports, Scene *scene, Base *base)
{
Base *child_base, *base_next;
Object *parent;
@@ -805,17 +828,30 @@ static Base *outline_delete_hierarchy(bContext *C, Scene *scene, Base *base)
base_next = child_base->next;
for (parent = child_base->object->parent; parent && (parent != base->object); parent = parent->parent);
if (parent) {
- base_next = outline_delete_hierarchy(C, scene, child_base);
+ base_next = outline_delete_hierarchy(C, reports, scene, child_base);
}
}
base_next = base->next;
+
+ Main *bmain = CTX_data_main(C);
+ if (base->object->id.tag & LIB_TAG_INDIRECT) {
+ BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2);
+ return base_next;
+ }
+ else if (BKE_library_ID_is_indirectly_used(bmain, base->object) && ID_REAL_USERS(base->object) <= 1) {
+ BKE_reportf(reports, RPT_WARNING,
+ "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user",
+ base->object->id.name + 2, scene->id.name + 2);
+ return base_next;
+ }
ED_base_object_free_and_unlink(CTX_data_main(C), scene, base);
return base_next;
}
static void object_delete_hierarchy_cb(
- bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+ bContext *C, ReportList *reports, Scene *scene,
+ TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Base *base = (Base *)te->directdata;
Object *obedit = scene->obedit;
@@ -830,7 +866,7 @@ static void object_delete_hierarchy_cb(
ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO);
}
- outline_delete_hierarchy(C, scene, base);
+ outline_delete_hierarchy(C, reports, scene, base);
/* leave for ED_outliner_id_unref to handle */
#if 0
te->directdata = NULL;
@@ -849,6 +885,7 @@ enum {
OL_OP_SELECT_HIERARCHY,
OL_OP_DELETE,
OL_OP_DELETE_HIERARCHY,
+ OL_OP_REMAP,
OL_OP_LOCALIZED, /* disabled, see below */
OL_OP_TOGVIS,
OL_OP_TOGSEL,
@@ -862,6 +899,8 @@ static EnumPropertyItem prop_object_op_types[] = {
{OL_OP_SELECT_HIERARCHY, "SELECT_HIERARCHY", 0, "Select Hierarchy", ""},
{OL_OP_DELETE, "DELETE", 0, "Delete", ""},
{OL_OP_DELETE_HIERARCHY, "DELETE_HIERARCHY", 0, "Delete Hierarchy", ""},
+ {OL_OP_REMAP, "REMAP", 0, "Remap Users",
+ "Make all users of selected data-blocks to use instead a new chosen one"},
{OL_OP_TOGVIS, "TOGVIS", 0, "Toggle Visible", ""},
{OL_OP_TOGSEL, "TOGSEL", 0, "Toggle Selectable", ""},
{OL_OP_TOGREN, "TOGREN", 0, "Toggle Renderable", ""},
@@ -885,7 +924,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
if (event == OL_OP_SELECT) {
Scene *sce = scene; // to be able to delete, scenes are set...
- outliner_do_object_operation(C, scene, soops, &soops->tree, object_select_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_select_cb);
if (scene != sce) {
ED_screen_set_scene(C, CTX_wm_screen(C), sce);
}
@@ -895,7 +934,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
}
else if (event == OL_OP_SELECT_HIERARCHY) {
Scene *sce = scene; // to be able to delete, scenes are set...
- outliner_do_object_operation_ex(C, scene, soops, &soops->tree, object_select_hierarchy_cb, false);
+ outliner_do_object_operation_ex(C, op->reports, scene, soops, &soops->tree, object_select_hierarchy_cb, false);
if (scene != sce) {
ED_screen_set_scene(C, CTX_wm_screen(C), sce);
}
@@ -903,12 +942,12 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
else if (event == OL_OP_DESELECT) {
- outliner_do_object_operation(C, scene, soops, &soops->tree, object_deselect_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_deselect_cb);
str = "Deselect Objects";
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
else if (event == OL_OP_DELETE) {
- outliner_do_object_operation(C, scene, soops, &soops->tree, object_delete_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_delete_cb);
/* XXX: tree management normally happens from draw_outliner(), but when
* you're clicking to fast on Delete object from context menu in
@@ -922,7 +961,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
}
else if (event == OL_OP_DELETE_HIERARCHY) {
- outliner_do_object_operation_ex(C, scene, soops, &soops->tree, object_delete_hierarchy_cb, false);
+ outliner_do_object_operation_ex(C, op->reports, scene, soops, &soops->tree, object_delete_hierarchy_cb, false);
/* XXX: See OL_OP_DELETE comment above. */
outliner_cleanup_tree(soops);
@@ -931,27 +970,31 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
str = "Delete Object Hierarchy";
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
}
+ else if (event == OL_OP_REMAP) {
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL);
+ str = "Remap ID";
+ }
else if (event == OL_OP_LOCALIZED) { /* disabled, see above enum (ton) */
- outliner_do_object_operation(C, scene, soops, &soops->tree, id_local_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb);
str = "Localized Objects";
}
else if (event == OL_OP_TOGVIS) {
- outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_visibility_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_visibility_cb);
str = "Toggle Visibility";
WM_event_add_notifier(C, NC_SCENE | ND_OB_VISIBLE, scene);
}
else if (event == OL_OP_TOGSEL) {
- outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_selectability_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_selectability_cb);
str = "Toggle Selectability";
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
else if (event == OL_OP_TOGREN) {
- outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_renderability_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_renderability_cb);
str = "Toggle Renderability";
WM_event_add_notifier(C, NC_SCENE | ND_OB_RENDER, scene);
}
else if (event == OL_OP_RENAME) {
- outliner_do_object_operation(C, scene, soops, &soops->tree, item_rename_cb);
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb);
str = "Rename Object";
}
else {
@@ -988,6 +1031,8 @@ typedef enum eOutliner_PropGroupOps {
OL_GROUPOP_UNLINK = 1,
OL_GROUPOP_LOCAL,
OL_GROUPOP_LINK,
+ OL_GROUPOP_DELETE,
+ OL_GROUPOP_REMAP,
OL_GROUPOP_INSTANCE,
OL_GROUPOP_TOGVIS,
OL_GROUPOP_TOGSEL,
@@ -999,6 +1044,9 @@ static EnumPropertyItem prop_group_op_types[] = {
{OL_GROUPOP_UNLINK, "UNLINK", 0, "Unlink Group", ""},
{OL_GROUPOP_LOCAL, "LOCAL", 0, "Make Local Group", ""},
{OL_GROUPOP_LINK, "LINK", 0, "Link Group Objects to Scene", ""},
+ {OL_GROUPOP_DELETE, "DELETE", 0, "Delete Group", "WARNING: no undo"},
+ {OL_GROUPOP_REMAP, "REMAP", 0, "Remap Users",
+ "Make all users of selected data-blocks to use instead current (clicked) one"},
{OL_GROUPOP_INSTANCE, "INSTANCE", 0, "Instance Groups in Scene", ""},
{OL_GROUPOP_TOGVIS, "TOGVIS", 0, "Toggle Visible Group", ""},
{OL_GROUPOP_TOGSEL, "TOGSEL", 0, "Toggle Selectable", ""},
@@ -1021,38 +1069,41 @@ static int outliner_group_operation_exec(bContext *C, wmOperator *op)
switch (event) {
case OL_GROUPOP_UNLINK:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_group_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_group_cb, NULL);
break;
case OL_GROUPOP_LOCAL:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_local_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb, NULL);
break;
case OL_GROUPOP_LINK:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_linkobs2scene_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_linkobs2scene_cb, NULL);
break;
case OL_GROUPOP_INSTANCE:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_instance_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_instance_cb, NULL);
+ /* works without this except if you try render right after, see: 22027 */
+ DAG_relations_tag_update(CTX_data_main(C));
+ break;
+ case OL_GROUPOP_DELETE:
+ WM_operator_name_call(C, "OUTLINER_OT_id_delete", WM_OP_INVOKE_REGION_WIN, NULL);
+ break;
+ case OL_GROUPOP_REMAP:
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL);
break;
case OL_GROUPOP_TOGVIS:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_visibility_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_toggle_visibility_cb, NULL);
break;
case OL_GROUPOP_TOGSEL:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_selectability_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_toggle_selectability_cb, NULL);
break;
case OL_GROUPOP_TOGREN:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_renderability_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_toggle_renderability_cb, NULL);
break;
case OL_GROUPOP_RENAME:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, item_rename_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL);
break;
default:
BLI_assert(0);
}
- if (event == 3) { /* instance */
- /* works without this except if you try render right after, see: 22027 */
- DAG_relations_tag_update(CTX_data_main(C));
- }
-
ED_undo_push(C, prop_group_op_types[event - 1].name);
WM_event_add_notifier(C, NC_GROUP, NULL);
@@ -1085,6 +1136,8 @@ typedef enum eOutlinerIdOpTypes {
OUTLINER_IDOP_UNLINK,
OUTLINER_IDOP_LOCAL,
OUTLINER_IDOP_SINGLE,
+ OUTLINER_IDOP_DELETE,
+ OUTLINER_IDOP_REMAP,
OUTLINER_IDOP_FAKE_ADD,
OUTLINER_IDOP_FAKE_CLEAR,
@@ -1098,8 +1151,11 @@ static EnumPropertyItem prop_id_op_types[] = {
{OUTLINER_IDOP_UNLINK, "UNLINK", 0, "Unlink", ""},
{OUTLINER_IDOP_LOCAL, "LOCAL", 0, "Make Local", ""},
{OUTLINER_IDOP_SINGLE, "SINGLE", 0, "Make Single User", ""},
+ {OUTLINER_IDOP_DELETE, "DELETE", 0, "Delete", "WARNING: no undo"},
+ {OUTLINER_IDOP_REMAP, "REMAP", 0, "Remap Users",
+ "Make all users of selected data-blocks to use instead current (clicked) one"},
{OUTLINER_IDOP_FAKE_ADD, "ADD_FAKE", 0, "Add Fake User",
- "Ensure datablock gets saved even if it isn't in use (e.g. for motion and material libraries)"},
+ "Ensure data-block gets saved even if it isn't in use (e.g. for motion and material libraries)"},
{OUTLINER_IDOP_FAKE_CLEAR, "CLEAR_FAKE", 0, "Clear Fake User", ""},
{OUTLINER_IDOP_RENAME, "RENAME", 0, "Rename", ""},
{OUTLINER_IDOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""},
@@ -1127,25 +1183,25 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
/* unlink datablock from its parent */
switch (idlevel) {
case ID_AC:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_action_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_action_cb, NULL);
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
ED_undo_push(C, "Unlink action");
break;
case ID_MA:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_material_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_material_cb, NULL);
WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, NULL);
ED_undo_push(C, "Unlink material");
break;
case ID_TE:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_texture_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_texture_cb, NULL);
WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, NULL);
ED_undo_push(C, "Unlink texture");
break;
case ID_WO:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_world_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_world_cb, NULL);
WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL);
ED_undo_push(C, "Unlink world");
@@ -1159,7 +1215,7 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_IDOP_LOCAL:
{
/* make local */
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_local_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb, NULL);
ED_undo_push(C, "Localized Data");
break;
}
@@ -1168,14 +1224,14 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
/* make single user */
switch (idlevel) {
case ID_AC:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, singleuser_action_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, singleuser_action_cb, NULL);
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
ED_undo_push(C, "Single-User Action");
break;
case ID_WO:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, singleuser_world_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, singleuser_world_cb, NULL);
WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL);
ED_undo_push(C, "Single-User World");
@@ -1187,10 +1243,24 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
}
break;
}
+ case OUTLINER_IDOP_DELETE:
+ {
+ if (idlevel > 0) {
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_delete_cb, NULL);
+ }
+ break;
+ }
+ case OUTLINER_IDOP_REMAP:
+ {
+ if (idlevel > 0) {
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL);
+ }
+ break;
+ }
case OUTLINER_IDOP_FAKE_ADD:
{
/* set fake user */
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_fake_user_set_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_fake_user_set_cb, NULL);
WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
ED_undo_push(C, "Add Fake User");
@@ -1199,7 +1269,7 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_IDOP_FAKE_CLEAR:
{
/* clear fake user */
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_fake_user_clear_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_fake_user_clear_cb, NULL);
WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
ED_undo_push(C, "Clear Fake User");
@@ -1208,14 +1278,14 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_IDOP_RENAME:
{
/* rename */
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, item_rename_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL);
WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
ED_undo_push(C, "Rename");
break;
}
case OUTLINER_IDOP_SELECT_LINKED:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_select_linked_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_select_linked_cb, NULL);
ED_undo_push(C, "Select");
break;
@@ -1258,13 +1328,16 @@ typedef enum eOutlinerLibOpTypes {
OL_LIB_RENAME,
OL_LIB_DELETE,
+ OL_LIB_RELOCATE,
+ OL_LIB_RELOAD,
} eOutlinerLibOpTypes;
static EnumPropertyItem outliner_lib_op_type_items[] = {
{OL_LIB_RENAME, "RENAME", 0, "Rename", ""},
- {OL_LIB_DELETE, "DELETE", 0, "Delete", "Delete this library and all its item from Blender (needs a save/reload)"},
+ {OL_LIB_DELETE, "DELETE", 0, "Delete", "Delete this library and all its item from Blender - WARNING: no undo"},
+ {OL_LIB_RELOCATE, "RELOCATE", 0, "Relocate", "Select a new path for this library, and reload all its data"},
+ {OL_LIB_RELOAD, "RELOAD", 0, "Reload", "Reload all data from this library"},
{0, NULL, 0, NULL, NULL}
-
};
static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
@@ -1272,7 +1345,7 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
- eOutlinerIdOpTypes event;
+ eOutlinerLibOpTypes event;
/* check for invalid states */
if (soops == NULL)
@@ -1286,7 +1359,7 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
case OL_LIB_RENAME:
{
/* rename */
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, item_rename_cb, NULL);
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL);
WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
ED_undo_push(C, "Rename");
@@ -1294,13 +1367,19 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
}
case OL_LIB_DELETE:
{
- /* delete */
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, lib_delete_cb, NULL);
-
- WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
- /* Note: no undo possible here really, not 100% sure why...
- * Probably because of library optimizations in undo/redo process? */
- /* ED_undo_push(C, "Rename"); */
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_delete_cb, NULL);
+ break;
+ }
+ case OL_LIB_RELOCATE:
+ {
+ /* rename */
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, lib_relocate_cb, NULL);
+ break;
+ }
+ case OL_LIB_RELOAD:
+ {
+ /* rename */
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, lib_reload_cb, NULL);
break;
}
default:
@@ -1397,8 +1476,8 @@ static int outliner_action_set_exec(bContext *C, wmOperator *op)
else if (act->idroot == 0) {
/* hopefully in this case (i.e. library of userless actions), the user knows what they're doing... */
BKE_reportf(op->reports, RPT_WARNING,
- "Action '%s' does not specify what datablocks it can be used on "
- "(try setting the 'ID Root Type' setting from the Datablocks Editor "
+ "Action '%s' does not specify what data-blocks it can be used on "
+ "(try setting the 'ID Root Type' setting from the data-blocks editor "
"for this action to avoid future problems)",
act->id.name + 2);
}
@@ -1753,8 +1832,8 @@ void OUTLINER_OT_data_operation(wmOperatorType *ot)
/* ******************** */
-static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, SpaceOops *soops,
- TreeElement *te, const wmEvent *event, const float mval[2])
+static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soops,
+ TreeElement *te, const float mval[2])
{
ReportList *reports = CTX_wm_reports(C); // XXX...
@@ -1765,8 +1844,8 @@ static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, S
/* select object that's clicked on and popup context menu */
if (!(tselem->flag & TSE_SELECTED)) {
- if (outliner_has_one_flag(soops, &soops->tree, TSE_SELECTED, 1))
- outliner_set_flag(soops, &soops->tree, TSE_SELECTED, 0);
+ if (outliner_has_one_flag(&soops->tree, TSE_SELECTED, 1))
+ outliner_set_flag(&soops->tree, TSE_SELECTED, 0);
tselem->flag |= TSE_SELECTED;
/* redraw, same as outliner_select function */
@@ -1837,7 +1916,7 @@ static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, S
}
for (te = te->subtree.first; te; te = te->next) {
- if (do_outliner_operation_event(C, scene, ar, soops, te, event, mval))
+ if (do_outliner_operation_event(C, ar, soops, te, mval))
return 1;
}
return 0;
@@ -1846,7 +1925,6 @@ static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, S
static int outliner_operation(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
- Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
uiBut *but = UI_context_active_but_get(C);
@@ -1860,7 +1938,7 @@ static int outliner_operation(bContext *C, wmOperator *UNUSED(op), const wmEvent
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
for (te = soops->tree.first; te; te = te->next) {
- if (do_outliner_operation_event(C, scene, ar, soops, te, event, fmval)) {
+ if (do_outliner_operation_event(C, ar, soops, te, fmval)) {
break;
}
}
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index a687f61d69f..015988efc42 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -38,6 +38,7 @@
#include "DNA_armature_types.h"
#include "DNA_constraint_types.h"
#include "DNA_camera_types.h"
+#include "DNA_cachefile_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_group_types.h"
#include "DNA_key_types.h"
@@ -248,7 +249,7 @@ TreeElement *outliner_find_id(SpaceOops *soops, ListBase *lb, const ID *id)
return NULL;
}
-TreeElement *outliner_find_posechannel(SpaceOops *soops, ListBase *lb, const bPoseChannel *pchan)
+TreeElement *outliner_find_posechannel(ListBase *lb, const bPoseChannel *pchan)
{
for (TreeElement *te = lb->first; te; te = te->next) {
if (te->directdata == pchan) {
@@ -257,7 +258,7 @@ TreeElement *outliner_find_posechannel(SpaceOops *soops, ListBase *lb, const bPo
TreeStoreElem *tselem = TREESTORE(te);
if (ELEM(tselem->type, TSE_POSE_BASE, TSE_POSE_CHANNEL)) {
- TreeElement *tes = outliner_find_posechannel(soops, &te->subtree, pchan);
+ TreeElement *tes = outliner_find_posechannel(&te->subtree, pchan);
if (tes) {
return tes;
}
@@ -266,7 +267,7 @@ TreeElement *outliner_find_posechannel(SpaceOops *soops, ListBase *lb, const bPo
return NULL;
}
-TreeElement *outliner_find_editbone(SpaceOops *soops, ListBase *lb, const EditBone *ebone)
+TreeElement *outliner_find_editbone(ListBase *lb, const EditBone *ebone)
{
for (TreeElement *te = lb->first; te; te = te->next) {
if (te->directdata == ebone) {
@@ -275,7 +276,7 @@ TreeElement *outliner_find_editbone(SpaceOops *soops, ListBase *lb, const EditBo
TreeStoreElem *tselem = TREESTORE(te);
if (ELEM(tselem->type, 0, TSE_EBONE)) {
- TreeElement *tes = outliner_find_editbone(soops, &te->subtree, ebone);
+ TreeElement *tes = outliner_find_editbone(&te->subtree, ebone);
if (tes) {
return tes;
}
@@ -307,7 +308,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
/* -------------------------------------------------------- */
/* special handling of hierarchical non-lib data */
-static void outliner_add_bone(SpaceOops *soops, ListBase *lb, ID *id, Bone *curBone,
+static void outliner_add_bone(SpaceOops *soops, ListBase *lb, ID *id, Bone *curBone,
TreeElement *parent, int *a)
{
TreeElement *te = outliner_add_element(soops, lb, id, parent, TSE_BONE, *a);
@@ -490,7 +491,7 @@ static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, Tree
outliner_add_element(soops, &te->subtree, ob->poselib, te, 0, 0); // XXX FIXME.. add a special type for this
- if (ob->proxy && ob->id.lib == NULL)
+ if (ob->proxy && !ID_IS_LINKED_DATABLOCK(ob))
outliner_add_element(soops, &te->subtree, ob->proxy, te, TSE_PROXY, 0);
outliner_add_element(soops, &te->subtree, ob->gpd, te, 0, 0);
@@ -746,6 +747,16 @@ static void outliner_add_id_contents(SpaceOops *soops, TreeElement *te, TreeStor
outliner_add_element(soops, &te->subtree, ca, te, TSE_ANIM_DATA, 0);
break;
}
+ case ID_CF:
+ {
+ CacheFile *cache_file = (CacheFile *)id;
+
+ if (outliner_animdata_test(cache_file->adt)) {
+ outliner_add_element(soops, &te->subtree, cache_file, te, TSE_ANIM_DATA, 0);
+ }
+
+ break;
+ }
case ID_LA:
{
Lamp *la = (Lamp *)id;
@@ -876,7 +887,7 @@ static void outliner_add_id_contents(SpaceOops *soops, TreeElement *te, TreeStor
// TODO: this function needs to be split up! It's getting a bit too large...
// Note: "ID" is not always a real ID
-static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *idv,
+static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *idv,
TreeElement *parent, short type, short index)
{
TreeElement *te;
@@ -1464,15 +1475,12 @@ static int treesort_obtype_alpha(const void *v1, const void *v2)
#endif
/* sort happens on each subtree individual */
-static void outliner_sort(SpaceOops *soops, ListBase *lb)
+static void outliner_sort(ListBase *lb)
{
TreeElement *te;
TreeStoreElem *tselem;
int totelem = 0;
- if (soops->flag & SO_SKIP_SORT_ALPHA)
- return;
-
te = lb->last;
if (te == NULL) return;
tselem = TREESTORE(te);
@@ -1526,7 +1534,7 @@ static void outliner_sort(SpaceOops *soops, ListBase *lb)
}
for (te = lb->first; te; te = te->next) {
- outliner_sort(soops, &te->subtree);
+ outliner_sort(&te->subtree);
}
}
@@ -1819,7 +1827,9 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
if (ten) ten->directdata = BASACT;
}
- outliner_sort(soops, &soops->tree);
+ if ((soops->flag & SO_SKIP_SORT_ALPHA) == 0) {
+ outliner_sort(&soops->tree);
+ }
outliner_filter_tree(soops, &soops->tree);
}
diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c
index 1dd66366e5d..759ef4e78e4 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.c
@@ -306,6 +306,7 @@ static void outliner_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(s
case ND_KEYINGSET:
case ND_FRAME:
case ND_RENDER_OPTIONS:
+ case ND_SEQUENCER:
case ND_LAYER:
case ND_WORLD:
ED_region_tag_redraw(ar);
@@ -486,6 +487,39 @@ static SpaceLink *outliner_duplicate(SpaceLink *sl)
return (SpaceLink *)soutlinern;
}
+static void outliner_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceOops *so = (SpaceOops *)slink;
+
+ /* Some early out checks. */
+ if (!TREESTORE_ID_TYPE(old_id)) {
+ return; /* ID type is not used by outilner... */
+ }
+
+ if (so->search_tse.id == old_id) {
+ so->search_tse.id = new_id;
+ }
+
+ if (so->treestore) {
+ TreeStoreElem *tselem;
+ BLI_mempool_iter iter;
+ bool changed = false;
+
+ BLI_mempool_iternew(so->treestore, &iter);
+ while ((tselem = BLI_mempool_iterstep(&iter))) {
+ if (tselem->id == old_id) {
+ tselem->id = new_id;
+ changed = true;
+ }
+ }
+ if (so->treehash && changed) {
+ /* rebuild hash table, because it depends on ids too */
+ /* postpone a full rebuild because this can be called many times on-free */
+ so->storeflag |= SO_TREESTORE_REBUILD;
+ }
+ }
+}
+
/* only called once, from space_api/spacetypes.c */
void ED_spacetype_outliner(void)
{
@@ -502,7 +536,8 @@ void ED_spacetype_outliner(void)
st->operatortypes = outliner_operatortypes;
st->keymap = outliner_keymap;
st->dropboxes = outliner_dropboxes;
-
+ st->id_remap = outliner_id_remap;
+
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype outliner region");
art->regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/space_sequencer/CMakeLists.txt b/source/blender/editors/space_sequencer/CMakeLists.txt
index 778ccf902d1..6dce962ee02 100644
--- a/source/blender/editors/space_sequencer/CMakeLists.txt
+++ b/source/blender/editors/space_sequencer/CMakeLists.txt
@@ -28,6 +28,7 @@ set(INC
../../makesdna
../../makesrna
../../windowmanager
+ ../../../../intern/atomic
../../../../intern/guardedalloc
../../../../intern/glew-mx
)
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index c11a4d2e5a3..ede6b7ce469 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -1071,7 +1071,7 @@ static int sequencer_add_effect_strip_invoke(bContext *C, wmOperator *op, const
{
bool is_type_set = RNA_struct_property_is_set(op->ptr, "type");
int type = -1;
- int prop_flag = SEQPROP_ENDFRAME;
+ int prop_flag = SEQPROP_ENDFRAME | SEQPROP_NOPATHS;
if (is_type_set) {
type = RNA_enum_get(op->ptr, "type");
@@ -1106,9 +1106,6 @@ void SEQUENCER_OT_effect_strip_add(struct wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- WM_operator_properties_filesel(
- ot, 0, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME | SEQPROP_ENDFRAME);
RNA_def_enum(ot->srna, "type", sequencer_prop_effect_types, SEQ_TYPE_CROSS, "Type", "Sequencer effect type");
RNA_def_float_vector(ot->srna, "color", 3, NULL, 0.0f, 1.0f, "Color",
diff --git a/source/blender/editors/space_sequencer/sequencer_buttons.c b/source/blender/editors/space_sequencer/sequencer_buttons.c
index 86d3fcbe1ac..b33a26db728 100644
--- a/source/blender/editors/space_sequencer/sequencer_buttons.c
+++ b/source/blender/editors/space_sequencer/sequencer_buttons.c
@@ -94,7 +94,7 @@ void SEQUENCER_OT_properties(wmOperatorType *ot)
{
ot->name = "Properties";
ot->idname = "SEQUENCER_OT_properties";
- ot->description = "Open sequencer properties panel";
+ ot->description = "Toggle the properties region visibility";
ot->exec = sequencer_properties_toggle_exec;
ot->poll = ED_operator_sequencer_active;
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 9c2d115108d..e1768e4aedc 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -471,7 +471,7 @@ static void draw_seq_handle(View2D *v2d, Sequence *seq, const float handsize_cla
}
/* draw info text on a sequence strip */
-static void draw_seq_text(View2D *v2d, Sequence *seq, float x1, float x2, float y1, float y2, const unsigned char background_col[3])
+static void draw_seq_text(View2D *v2d, SpaceSeq *sseq, Sequence *seq, float x1, float x2, float y1, float y2, const unsigned char background_col[3])
{
rctf rect;
char str[32 + FILE_MAX];
@@ -540,7 +540,12 @@ static void draw_seq_text(View2D *v2d, Sequence *seq, float x1, float x2, float
name, seq->len);
}
else if (seq->type == SEQ_TYPE_SOUND_RAM) {
- if (seq->sound) {
+ /* If a waveform is drawn, we don't want to overlay it with text,
+ * as it would make both hard to read. */
+ if ((sseq->flag & SEQ_ALL_WAVEFORMS) || (seq->flag & SEQ_AUDIO_DRAW_WAVEFORM)) {
+ str[0] = 0;
+ str_len = 0;
+ } else if (seq->sound) {
str_len = BLI_snprintf(str, sizeof(str), "%s: %s | %d",
name, seq->sound->name, seq->len);
}
@@ -593,7 +598,6 @@ void draw_shadedstrip(Sequence *seq, unsigned char col[3], float x1, float y1, f
ymid1 = (y2 - y1) * 0.25f + y1;
ymid2 = (y2 - y1) * 0.65f + y1;
- glShadeModel(GL_SMOOTH);
glBegin(GL_QUADS);
if (seq->flag & SEQ_INVALID_EFFECT) { col[0] = 255; col[1] = 0; col[2] = 255; }
@@ -840,25 +844,25 @@ static void draw_seq_strip(const bContext *C, SpaceSeq *sseq, Scene *scene, AReg
else
UI_GetColorPtrShade3ubv(col, col, outline_tint);
- glColor3ubv((GLubyte *)col);
-
+ if ((seq->type == SEQ_TYPE_META) ||
+ ((seq->type == SEQ_TYPE_SCENE) && (seq->flag & SEQ_SCENE_STRIPS)))
+ {
+ drawmeta_contents(scene, seq, x1, y1, x2, y2);
+ }
+
if (seq->flag & SEQ_MUTE) {
glEnable(GL_LINE_STIPPLE);
glLineStipple(1, 0x8888);
}
+ glColor3ubv((GLubyte *)col);
+
UI_draw_roundbox_shade_x(GL_LINE_LOOP, x1, y1, x2, y2, 0.0, 0.1, 0.0);
if (seq->flag & SEQ_MUTE) {
glDisable(GL_LINE_STIPPLE);
}
- if ((seq->type == SEQ_TYPE_META) ||
- ((seq->type == SEQ_TYPE_SCENE) && (seq->flag & SEQ_SCENE_STRIPS)))
- {
- drawmeta_contents(scene, seq, x1, y1, x2, y2);
- }
-
/* calculate if seq is long enough to print a name */
x1 = seq->startdisp + handsize_clamped;
x2 = seq->enddisp - handsize_clamped;
@@ -871,7 +875,7 @@ static void draw_seq_strip(const bContext *C, SpaceSeq *sseq, Scene *scene, AReg
/* nice text here would require changing the view matrix for texture text */
if ((x2 - x1) / pixelx > 32) {
- draw_seq_text(v2d, seq, x1, x2, y1, y2, background_col);
+ draw_seq_text(v2d, sseq, seq, x1, x2, y1, y2, background_col);
}
}
@@ -1630,7 +1634,8 @@ void draw_timeline_seq(const bContext *C, ARegion *ar)
// NOTE: the gridlines are currently spaced every 25 frames, which is only fine for 25 fps, but maybe not for 30...
UI_view2d_constant_grid_draw(v2d);
- if (sseq->draw_flag & SEQ_DRAW_BACKDROP) {
+ /* Only draw backdrop in pure sequence view. */
+ if (sseq->view == SEQ_VIEW_SEQUENCE && sseq->draw_flag & SEQ_DRAW_BACKDROP) {
draw_image_seq(C, scene, ar, sseq, scene->r.cfra, 0, false, true);
UI_view2d_view_ortho(v2d);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index e3cdedf042b..8ae89941bdb 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -1506,23 +1506,20 @@ static int sequencer_slip_exec(bContext *C, wmOperator *op)
static void sequencer_slip_update_header(Scene *scene, ScrArea *sa, SlipData *data, int offset)
{
-#define HEADER_LENGTH 40
- char msg[HEADER_LENGTH];
+ char msg[UI_MAX_DRAW_STR];
if (sa) {
if (hasNumInput(&data->num_input)) {
char num_str[NUM_STR_REP_LEN];
outputNumInput(&data->num_input, num_str, &scene->unit);
- BLI_snprintf(msg, HEADER_LENGTH, "Trim offset: %s", num_str);
+ BLI_snprintf(msg, sizeof(msg), IFACE_("Trim offset: %s"), num_str);
}
else {
- BLI_snprintf(msg, HEADER_LENGTH, "Trim offset: %d", offset);
+ BLI_snprintf(msg, sizeof(msg), IFACE_("Trim offset: %d"), offset);
}
}
ED_area_headerprint(sa, msg);
-
-#undef HEADER_LENGTH
}
static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *event)
diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c
index 655e029cfdd..a3cfcae77b8 100644
--- a/source/blender/editors/space_sequencer/sequencer_ops.c
+++ b/source/blender/editors/space_sequencer/sequencer_ops.c
@@ -201,7 +201,9 @@ void sequencer_keymap(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "SEQUENCER_OT_meta_separate", GKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "SEQUENCER_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
+#ifdef WITH_INPUT_NDOF
WM_keymap_add_item(keymap, "SEQUENCER_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
+#endif
WM_keymap_add_item(keymap, "SEQUENCER_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "SEQUENCER_OT_view_frame", PAD0, KM_PRESS, 0, 0);
@@ -340,7 +342,9 @@ void sequencer_keymap(wmKeyConfig *keyconf)
/* Preview Region ----------------------------------------------------------- */
keymap = WM_keymap_find(keyconf, "SequencerPreview", SPACE_SEQ, 0);
WM_keymap_add_item(keymap, "SEQUENCER_OT_view_all_preview", HOMEKEY, KM_PRESS, 0, 0);
+#ifdef WITH_INPUT_NDOF
WM_keymap_add_item(keymap, "SEQUENCER_OT_view_all_preview", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
+#endif
WM_keymap_add_item(keymap, "SEQUENCER_OT_view_ghost_border", OKEY, KM_PRESS, 0, 0);
diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.c b/source/blender/editors/space_sequencer/sequencer_scopes.c
index c197aabedfd..80cb42c0b3d 100644
--- a/source/blender/editors/space_sequencer/sequencer_scopes.c
+++ b/source/blender/editors/space_sequencer/sequencer_scopes.c
@@ -30,11 +30,14 @@
#include <string.h>
#include "BLI_utildefines.h"
+#include "BLI_task.h"
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
+#include "atomic_ops.h"
+
#include "sequencer_intern.h"
/* XXX, why is this function better then BLI_math version?
@@ -450,41 +453,57 @@ static void draw_histogram_bar(ImBuf *ibuf, int x, float val, int col)
#define HIS_STEPS 512
-static ImBuf *make_histogram_view_from_ibuf_byte(ImBuf *ibuf)
+typedef struct MakeHistogramViewData {
+ const ImBuf *ibuf;
+ uint32_t (*bins)[HIS_STEPS];
+} MakeHistogramViewData;
+
+static void make_histogram_view_from_ibuf_byte_cb_ex(
+ void *userdata, void *userdata_chunk, const int y, const int UNUSED(threadid))
{
- ImBuf *rval = IMB_allocImBuf(515, 128, 32, IB_rect);
- int x, y;
- unsigned int nr, ng, nb;
+ MakeHistogramViewData *data = userdata;
+ const ImBuf *ibuf = data->ibuf;
const unsigned char *src = (unsigned char *)ibuf->rect;
- unsigned int bins[3][HIS_STEPS];
-
- memset(bins, 0, sizeof(bins));
+ uint32_t (*cur_bins)[HIS_STEPS] = userdata_chunk;
-#pragma omp parallel for shared(bins, src, ibuf) private(x, y) if (ibuf->y >= 256)
- for (y = 0; y < ibuf->y; y++) {
- unsigned int cur_bins[3][HIS_STEPS];
+ for (int x = 0; x < ibuf->x; x++) {
+ const unsigned char *pixel = src + (y * ibuf->x + x) * 4;
- memset(cur_bins, 0, sizeof(cur_bins));
+ for (int j = 3; j--;) {
+ cur_bins[j][pixel[j]]++;
+ }
+ }
+}
- for (x = 0; x < ibuf->x; x++) {
- const unsigned char *pixel = src + (y * ibuf->x + x) * 4;
+static void make_histogram_view_from_ibuf_finalize(void *userdata, void *userdata_chunk)
+{
+ MakeHistogramViewData *data = userdata;
+ uint32_t (*bins)[HIS_STEPS] = data->bins;
- cur_bins[0][pixel[0]]++;
- cur_bins[1][pixel[1]]++;
- cur_bins[2][pixel[2]]++;
- }
+ uint32_t (*cur_bins)[HIS_STEPS] = userdata_chunk;
-#pragma omp critical
- {
- int i;
- for (i = 0; i < HIS_STEPS; i++) {
- bins[0][i] += cur_bins[0][i];
- bins[1][i] += cur_bins[1][i];
- bins[2][i] += cur_bins[2][i];
- }
+ for (int j = 3; j--;) {
+ for (int i = 0; i < HIS_STEPS; i++) {
+ bins[j][i] += cur_bins[j][i];
}
}
+}
+
+static ImBuf *make_histogram_view_from_ibuf_byte(ImBuf *ibuf)
+{
+ ImBuf *rval = IMB_allocImBuf(515, 128, 32, IB_rect);
+ int x;
+ unsigned int nr, ng, nb;
+
+ unsigned int bins[3][HIS_STEPS];
+
+ memset(bins, 0, sizeof(bins));
+
+ MakeHistogramViewData data = {.ibuf = ibuf, .bins = bins};
+ BLI_task_parallel_range_finalize(
+ 0, ibuf->y, &data, bins, sizeof(bins), make_histogram_view_from_ibuf_byte_cb_ex,
+ make_histogram_view_from_ibuf_finalize, ibuf->y >= 256, false);
nr = nb = ng = 0;
for (x = 0; x < HIS_STEPS; x++) {
@@ -528,40 +547,38 @@ BLI_INLINE int get_bin_float(float f)
return (int) (((f + 0.25f) / 1.5f) * 512);
}
-static ImBuf *make_histogram_view_from_ibuf_float(ImBuf *ibuf)
+static void make_histogram_view_from_ibuf_float_cb_ex(
+ void *userdata, void *userdata_chunk, const int y, const int UNUSED(threadid))
{
- ImBuf *rval = IMB_allocImBuf(515, 128, 32, IB_rect);
- int nr, ng, nb, x, y;
+ const MakeHistogramViewData *data = userdata;
+ const ImBuf *ibuf = data->ibuf;
const float *src = ibuf->rect_float;
- unsigned int bins[3][HIS_STEPS];
+ uint32_t (*cur_bins)[HIS_STEPS] = userdata_chunk;
- memset(bins, 0, sizeof(bins));
+ for (int x = 0; x < ibuf->x; x++) {
+ const float *pixel = src + (y * ibuf->x + x) * 4;
-#pragma omp parallel for shared(bins, src, ibuf) private(x, y) if (ibuf->y >= 256)
- for (y = 0; y < ibuf->y; y++) {
- unsigned int cur_bins[3][HIS_STEPS];
+ for (int j = 3; j--;) {
+ cur_bins[j][get_bin_float(pixel[j])]++;
+ }
+ }
+}
- memset(cur_bins, 0, sizeof(cur_bins));
+static ImBuf *make_histogram_view_from_ibuf_float(ImBuf *ibuf)
+{
+ ImBuf *rval = IMB_allocImBuf(515, 128, 32, IB_rect);
+ int nr, ng, nb;
+ int x;
- for (x = 0; x < ibuf->x; x++) {
- const float *pixel = src + (y * ibuf->x + x) * 4;
+ unsigned int bins[3][HIS_STEPS];
- cur_bins[0][get_bin_float(pixel[0])]++;
- cur_bins[1][get_bin_float(pixel[1])]++;
- cur_bins[2][get_bin_float(pixel[2])]++;
- }
+ memset(bins, 0, sizeof(bins));
-#pragma omp critical
- {
- int i;
- for (i = 0; i < HIS_STEPS; i++) {
- bins[0][i] += cur_bins[0][i];
- bins[1][i] += cur_bins[1][i];
- bins[2][i] += cur_bins[2][i];
- }
- }
- }
+ MakeHistogramViewData data = {.ibuf = ibuf, .bins = bins};
+ BLI_task_parallel_range_finalize(
+ 0, ibuf->y, &data, bins, sizeof(bins), make_histogram_view_from_ibuf_float_cb_ex,
+ make_histogram_view_from_ibuf_finalize, ibuf->y >= 256, false);
nr = nb = ng = 0;
for (x = 0; x < HIS_STEPS; x++) {
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index 3c2a66cd3af..48c49f36471 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -107,6 +107,7 @@ static void select_active_side(ListBase *seqbase, int sel_side, int channel, int
break;
case SEQ_SIDE_BOTH:
seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
+ seq->flag |= SELECT;
break;
}
}
@@ -812,7 +813,7 @@ static int sequencer_select_handles_exec(bContext *C, wmOperator *op)
seq->flag |= SEQ_RIGHTSEL;
break;
case SEQ_SIDE_BOTH:
- seq->flag |= SEQ_LEFTSEL + SEQ_RIGHTSEL;
+ seq->flag |= SEQ_LEFTSEL | SEQ_RIGHTSEL;
break;
}
}
@@ -942,16 +943,26 @@ void SEQUENCER_OT_select_border(wmOperatorType *ot)
/* ****** Selected Grouped ****** */
+enum {
+ SEQ_SELECT_GROUP_TYPE,
+ SEQ_SELECT_GROUP_TYPE_BASIC,
+ SEQ_SELECT_GROUP_TYPE_EFFECT,
+ SEQ_SELECT_GROUP_DATA,
+ SEQ_SELECT_GROUP_EFFECT,
+ SEQ_SELECT_GROUP_EFFECT_LINK,
+ SEQ_SELECT_GROUP_OVERLAP,
+};
+
static EnumPropertyItem sequencer_prop_select_grouped_types[] = {
- {1, "TYPE", 0, "Type", "Shared strip type"},
- {2, "TYPE_BASIC", 0, "Global Type", "All strips of same basic type (Graphical or Sound)"},
- {3, "TYPE_EFFECT", 0, "Effect Type",
+ {SEQ_SELECT_GROUP_TYPE, "TYPE", 0, "Type", "Shared strip type"},
+ {SEQ_SELECT_GROUP_TYPE_BASIC, "TYPE_BASIC", 0, "Global Type", "All strips of same basic type (Graphical or Sound)"},
+ {SEQ_SELECT_GROUP_TYPE_EFFECT, "TYPE_EFFECT", 0, "Effect Type",
"Shared strip effect type (if active strip is not an effect one, select all non-effect strips)"},
- {4, "DATA", 0, "Data", "Shared data (scene, image, sound, etc.)"},
- {5, "EFFECT", 0, "Effect", "Shared effects"},
- {6, "EFFECT_LINK", 0, "Effect/Linked",
+ {SEQ_SELECT_GROUP_DATA, "DATA", 0, "Data", "Shared data (scene, image, sound, etc.)"},
+ {SEQ_SELECT_GROUP_EFFECT, "EFFECT", 0, "Effect", "Shared effects"},
+ {SEQ_SELECT_GROUP_EFFECT_LINK, "EFFECT_LINK", 0, "Effect/Linked",
"Other strips affected by the active one (sharing some time, and below or effect-assigned)"},
- {7, "OVERLAP", 0, "Overlap", "Overlapping time"},
+ {SEQ_SELECT_GROUP_OVERLAP, "OVERLAP", 0, "Overlap", "Overlapping time"},
{0, NULL, 0, NULL, NULL}
};
@@ -961,14 +972,16 @@ static EnumPropertyItem sequencer_prop_select_grouped_types[] = {
#define SEQ_USE_DATA(_seq) (ELEM(_seq->type, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIECLIP, SEQ_TYPE_MASK) || SEQ_HAS_PATH(_seq))
-static bool select_grouped_type(Editing *ed, Sequence *actseq)
+#define SEQ_CHANNEL_CHECK(_seq, _chan) (ELEM((_chan), 0, (_seq)->machine))
+
+static bool select_grouped_type(Editing *ed, Sequence *actseq, const int channel)
{
Sequence *seq;
bool changed = false;
SEQP_BEGIN (ed, seq)
{
- if (seq->type == actseq->type) {
+ if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == actseq->type) {
seq->flag |= SELECT;
changed = true;
}
@@ -978,7 +991,7 @@ static bool select_grouped_type(Editing *ed, Sequence *actseq)
return changed;
}
-static bool select_grouped_type_basic(Editing *ed, Sequence *actseq)
+static bool select_grouped_type_basic(Editing *ed, Sequence *actseq, const int channel)
{
Sequence *seq;
bool changed = false;
@@ -986,7 +999,7 @@ static bool select_grouped_type_basic(Editing *ed, Sequence *actseq)
SEQP_BEGIN (ed, seq)
{
- if (is_sound ? SEQ_IS_SOUND(seq) : !SEQ_IS_SOUND(seq)) {
+ if (SEQ_CHANNEL_CHECK(seq, channel) && (is_sound ? SEQ_IS_SOUND(seq) : !SEQ_IS_SOUND(seq))) {
seq->flag |= SELECT;
changed = true;
}
@@ -996,7 +1009,7 @@ static bool select_grouped_type_basic(Editing *ed, Sequence *actseq)
return changed;
}
-static bool select_grouped_type_effect(Editing *ed, Sequence *actseq)
+static bool select_grouped_type_effect(Editing *ed, Sequence *actseq, const int channel)
{
Sequence *seq;
bool changed = false;
@@ -1004,7 +1017,7 @@ static bool select_grouped_type_effect(Editing *ed, Sequence *actseq)
SEQP_BEGIN (ed, seq)
{
- if (is_effect ? SEQ_IS_EFFECT(seq) : !SEQ_IS_EFFECT(seq)) {
+ if (SEQ_CHANNEL_CHECK(seq, channel) && (is_effect ? SEQ_IS_EFFECT(seq) : !SEQ_IS_EFFECT(seq))) {
seq->flag |= SELECT;
changed = true;
}
@@ -1014,7 +1027,7 @@ static bool select_grouped_type_effect(Editing *ed, Sequence *actseq)
return changed;
}
-static bool select_grouped_data(Editing *ed, Sequence *actseq)
+static bool select_grouped_data(Editing *ed, Sequence *actseq, const int channel)
{
Sequence *seq;
bool changed = false;
@@ -1026,7 +1039,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq)
if (SEQ_HAS_PATH(actseq) && dir) {
SEQP_BEGIN (ed, seq)
{
- if (SEQ_HAS_PATH(seq) && seq->strip && STREQ(seq->strip->dir, dir)) {
+ if (SEQ_CHANNEL_CHECK(seq, channel) && SEQ_HAS_PATH(seq) && seq->strip && STREQ(seq->strip->dir, dir)) {
seq->flag |= SELECT;
changed = true;
}
@@ -1037,7 +1050,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq)
Scene *sce = actseq->scene;
SEQP_BEGIN (ed, seq)
{
- if (seq->type == SEQ_TYPE_SCENE && seq->scene == sce) {
+ if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_SCENE && seq->scene == sce) {
seq->flag |= SELECT;
changed = true;
}
@@ -1048,7 +1061,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq)
MovieClip *clip = actseq->clip;
SEQP_BEGIN (ed, seq)
{
- if (seq->type == SEQ_TYPE_MOVIECLIP && seq->clip == clip) {
+ if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_MOVIECLIP && seq->clip == clip) {
seq->flag |= SELECT;
changed = true;
}
@@ -1059,7 +1072,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq)
struct Mask *mask = actseq->mask;
SEQP_BEGIN (ed, seq)
{
- if (seq->type == SEQ_TYPE_MASK && seq->mask == mask) {
+ if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_MASK && seq->mask == mask) {
seq->flag |= SELECT;
changed = true;
}
@@ -1070,7 +1083,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq)
return changed;
}
-static bool select_grouped_effect(Editing *ed, Sequence *actseq)
+static bool select_grouped_effect(Editing *ed, Sequence *actseq, const int channel)
{
Sequence *seq;
bool changed = false;
@@ -1082,7 +1095,9 @@ static bool select_grouped_effect(Editing *ed, Sequence *actseq)
SEQP_BEGIN (ed, seq)
{
- if ((seq->type & SEQ_TYPE_EFFECT) && ELEM(actseq, seq->seq1, seq->seq2, seq->seq3)) {
+ if (SEQ_CHANNEL_CHECK(seq, channel) && (seq->type & SEQ_TYPE_EFFECT) &&
+ ELEM(actseq, seq->seq1, seq->seq2, seq->seq3))
+ {
effects[seq->type] = true;
}
}
@@ -1090,7 +1105,7 @@ static bool select_grouped_effect(Editing *ed, Sequence *actseq)
SEQP_BEGIN (ed, seq)
{
- if (effects[seq->type]) {
+ if (SEQ_CHANNEL_CHECK(seq, channel) && effects[seq->type]) {
if (seq->seq1) seq->seq1->flag |= SELECT;
if (seq->seq2) seq->seq2->flag |= SELECT;
if (seq->seq3) seq->seq3->flag |= SELECT;
@@ -1119,7 +1134,7 @@ static bool select_grouped_time_overlap(Editing *ed, Sequence *actseq)
return changed;
}
-static bool select_grouped_effect_link(Editing *ed, Sequence *actseq)
+static bool select_grouped_effect_link(Editing *ed, Sequence *actseq, const int channel)
{
Sequence *seq = NULL;
bool changed = false;
@@ -1143,7 +1158,8 @@ static bool select_grouped_effect_link(Editing *ed, Sequence *actseq)
/* Ignore all seqs already selected! */
/* Ignore all seqs not sharing some time with active one. */
/* Ignore all seqs of incompatible types (audio vs video). */
- if ((seq->flag & SELECT) || (seq->startdisp >= enddisp) || (seq->enddisp < startdisp) ||
+ if (!SEQ_CHANNEL_CHECK(seq, channel) ||
+ (seq->flag & SELECT) || (seq->startdisp >= enddisp) || (seq->enddisp < startdisp) ||
(!is_audio && SEQ_IS_SOUND(seq)) ||
(is_audio && !((seq->type == SEQ_TYPE_META) || SEQ_IS_SOUND(seq))))
{
@@ -1189,17 +1205,19 @@ static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, false);
Sequence *seq, *actseq = BKE_sequencer_active_get(scene);
- int type = RNA_enum_get(op->ptr, "type");
- bool changed = false, extend;
- extend = RNA_boolean_get(op->ptr, "extend");
+ const int type = RNA_enum_get(op->ptr, "type");
+ const int channel = RNA_boolean_get(op->ptr, "use_active_channel") ? actseq->machine : 0;
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+
+ bool changed = false;
if (actseq == NULL) {
BKE_report(op->reports, RPT_ERROR, "No active sequence!");
return OPERATOR_CANCELLED;
}
- if (extend == 0) {
+ if (!extend) {
SEQP_BEGIN (ed, seq)
{
seq->flag &= ~SELECT;
@@ -1208,13 +1226,32 @@ static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
SEQ_END;
}
- if (type == 1) changed |= select_grouped_type(ed, actseq);
- else if (type == 2) changed |= select_grouped_type_basic(ed, actseq);
- else if (type == 3) changed |= select_grouped_type_effect(ed, actseq);
- else if (type == 4) changed |= select_grouped_data(ed, actseq);
- else if (type == 5) changed |= select_grouped_effect(ed, actseq);
- else if (type == 6) changed |= select_grouped_effect_link(ed, actseq);
- else if (type == 7) changed |= select_grouped_time_overlap(ed, actseq);
+ switch (type) {
+ case SEQ_SELECT_GROUP_TYPE:
+ changed |= select_grouped_type(ed, actseq, channel);
+ break;
+ case SEQ_SELECT_GROUP_TYPE_BASIC:
+ changed |= select_grouped_type_basic(ed, actseq, channel);
+ break;
+ case SEQ_SELECT_GROUP_TYPE_EFFECT:
+ changed |= select_grouped_type_effect(ed, actseq, channel);
+ break;
+ case SEQ_SELECT_GROUP_DATA:
+ changed |= select_grouped_data(ed, actseq, channel);
+ break;
+ case SEQ_SELECT_GROUP_EFFECT:
+ changed |= select_grouped_effect(ed, actseq, channel);
+ break;
+ case SEQ_SELECT_GROUP_EFFECT_LINK:
+ changed |= select_grouped_effect_link(ed, actseq, channel);
+ break;
+ case SEQ_SELECT_GROUP_OVERLAP:
+ changed |= select_grouped_time_overlap(ed, actseq);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
if (changed) {
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
@@ -1240,7 +1277,9 @@ void SEQUENCER_OT_select_grouped(wmOperatorType *ot)
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", sequencer_prop_select_grouped_types, 0, "Type", "");
+ RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting everything first");
+ RNA_def_boolean(ot->srna, "use_active_channel", false, "Same Channel",
+ "Only consider strips on the same channel as the active one");
}
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index fce40f8ca59..a2a80297041 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -32,6 +32,7 @@
#include <string.h>
#include <stdio.h>
+#include "DNA_gpencil_types.h"
#include "DNA_scene_types.h"
#include "DNA_mask_types.h"
@@ -41,6 +42,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_library.h"
#include "BKE_screen.h"
#include "BKE_sequencer.h"
#include "BKE_global.h"
@@ -687,6 +689,22 @@ static void sequencer_buttons_region_listener(bScreen *UNUSED(sc), ScrArea *UNUS
break;
}
}
+
+static void sequencer_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceSeq *sseq = (SpaceSeq *)slink;
+
+ if (!ELEM(GS(old_id->name), ID_GD)) {
+ return;
+ }
+
+ if ((ID *)sseq->gpd == old_id) {
+ sseq->gpd = (bGPdata *)new_id;
+ id_us_min(old_id);
+ id_us_plus(new_id);
+ }
+}
+
/* ************************************* */
/* only called once, from space/spacetypes.c */
@@ -708,6 +726,7 @@ void ED_spacetype_sequencer(void)
st->dropboxes = sequencer_dropboxes;
st->refresh = sequencer_refresh;
st->listener = sequencer_listener;
+ st->id_remap = sequencer_id_remap;
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region");
diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c
index 0a6a9a81e63..686a10fc785 100644
--- a/source/blender/editors/space_text/space_text.c
+++ b/source/blender/editors/space_text/space_text.c
@@ -38,6 +38,7 @@
#include "BLI_blenlib.h"
#include "BKE_context.h"
+#include "BKE_library.h"
#include "BKE_screen.h"
#include "BKE_text.h"
@@ -562,6 +563,20 @@ static void text_properties_region_draw(const bContext *C, ARegion *ar)
}
}
+static void text_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceText *stext = (SpaceText *)slink;
+
+ if (!ELEM(GS(old_id->name), ID_TXT)) {
+ return;
+ }
+
+ if ((ID *)stext->text == old_id) {
+ stext->text = (Text *)new_id;
+ id_us_ensure_real(new_id);
+ }
+}
+
/********************* registration ********************/
/* only called once, from space/spacetypes.c */
@@ -582,7 +597,8 @@ void ED_spacetype_text(void)
st->listener = text_listener;
st->context = text_context;
st->dropboxes = text_dropboxes;
-
+ st->id_remap = text_id_remap;
+
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype text region");
art->regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/space_text/text_autocomplete.c b/source/blender/editors/space_text/text_autocomplete.c
index 04cff288b03..c38c57b9528 100644
--- a/source/blender/editors/space_text/text_autocomplete.c
+++ b/source/blender/editors/space_text/text_autocomplete.c
@@ -259,10 +259,8 @@ static void confirm_suggestion(Text *text)
// for (i = 0; i < skipleft; i++)
// txt_move_left(text, 0);
- for (i = 0; i < over; i++)
- txt_move_left(text, 1);
-
- txt_insert_buf(text, sel->name);
+ BLI_assert(memcmp(sel->name, &line[i], over) == 0);
+ txt_insert_buf(text, sel->name + over);
// for (i = 0; i < skipleft; i++)
// txt_move_right(text, 0);
diff --git a/source/blender/editors/space_text/text_header.c b/source/blender/editors/space_text/text_header.c
index 91665f1a598..e06a5b5474e 100644
--- a/source/blender/editors/space_text/text_header.c
+++ b/source/blender/editors/space_text/text_header.c
@@ -92,7 +92,7 @@ void TEXT_OT_properties(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Properties";
- ot->description = "Toggle text properties panel";
+ ot->description = "Toggle the properties region visibility";
ot->idname = "TEXT_OT_properties";
/* api callbacks */
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index d404e7aaf15..83012eac39e 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -92,7 +92,7 @@ static int text_edit_poll(bContext *C)
if (!text)
return 0;
- if (text->id.lib) {
+ if (ID_IS_LINKED_DATABLOCK(text)) {
// BKE_report(op->reports, RPT_ERROR, "Cannot edit external libdata");
return 0;
}
@@ -108,7 +108,7 @@ int text_space_edit_poll(bContext *C)
if (!st || !text)
return 0;
- if (text->id.lib) {
+ if (ID_IS_LINKED_DATABLOCK(text)) {
// BKE_report(op->reports, RPT_ERROR, "Cannot edit external libdata");
return 0;
}
@@ -128,7 +128,7 @@ static int text_region_edit_poll(bContext *C)
if (!ar || ar->regiontype != RGN_TYPE_WINDOW)
return 0;
- if (text->id.lib) {
+ if (ID_IS_LINKED_DATABLOCK(text)) {
// BKE_report(op->reports, RPT_ERROR, "Cannot edit external libdata");
return 0;
}
@@ -197,7 +197,7 @@ void TEXT_OT_new(wmOperatorType *ot)
/* identifiers */
ot->name = "Create Text Block";
ot->idname = "TEXT_OT_new";
- ot->description = "Create a new text data block";
+ ot->description = "Create a new text data-block";
/* api callbacks */
ot->exec = text_new_exec;
@@ -288,7 +288,7 @@ void TEXT_OT_open(wmOperatorType *ot)
/* identifiers */
ot->name = "Open Text Block";
ot->idname = "TEXT_OT_open";
- ot->description = "Open a new text data block";
+ ot->description = "Open a new text data-block";
/* api callbacks */
ot->exec = text_open_exec;
@@ -348,7 +348,7 @@ void TEXT_OT_reload(wmOperatorType *ot)
/* identifiers */
ot->name = "Reload";
ot->idname = "TEXT_OT_reload";
- ot->description = "Reload active text data block from its file";
+ ot->description = "Reload active text data-block from its file";
/* api callbacks */
ot->exec = text_reload_exec;
@@ -384,8 +384,7 @@ static int text_unlink_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- BKE_text_unlink(bmain, text);
- BKE_libblock_free(bmain, text);
+ BKE_libblock_delete(bmain, text);
text_drawcache_tag_update(st, 1);
WM_event_add_notifier(C, NC_TEXT | NA_REMOVED, NULL);
@@ -398,7 +397,7 @@ void TEXT_OT_unlink(wmOperatorType *ot)
/* identifiers */
ot->name = "Unlink";
ot->idname = "TEXT_OT_unlink";
- ot->description = "Unlink active text data block";
+ ot->description = "Unlink active text data-block";
/* api callbacks */
ot->exec = text_unlink_exec;
@@ -513,7 +512,7 @@ void TEXT_OT_save(wmOperatorType *ot)
/* identifiers */
ot->name = "Save";
ot->idname = "TEXT_OT_save";
- ot->description = "Save active text data block";
+ ot->description = "Save active text data-block";
/* api callbacks */
ot->exec = text_save_exec;
@@ -3188,7 +3187,7 @@ void TEXT_OT_to_3d_object(wmOperatorType *ot)
/* identifiers */
ot->name = "To 3D Object";
ot->idname = "TEXT_OT_to_3d_object";
- ot->description = "Create 3D text object from active text data block";
+ ot->description = "Create 3D text object from active text data-block";
/* api callbacks */
ot->exec = text_to_3d_object_exec;
diff --git a/source/blender/editors/space_time/space_time.c b/source/blender/editors/space_time/space_time.c
index fde955c24a7..15eb154c757 100644
--- a/source/blender/editors/space_time/space_time.c
+++ b/source/blender/editors/space_time/space_time.c
@@ -32,7 +32,10 @@
#include <string.h>
#include <stdio.h>
+#include "DNA_cachefile_types.h"
+#include "DNA_constraint_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -42,7 +45,10 @@
#include "BLI_dlrbTree.h"
#include "BLI_utildefines.h"
+#include "BKE_constraint.h"
#include "BKE_context.h"
+#include "BKE_main.h"
+#include "BKE_modifier.h"
#include "BKE_screen.h"
#include "BKE_pointcache.h"
@@ -320,6 +326,9 @@ static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel)
case ID_GD:
gpencil_to_keylist(&ads, (bGPdata *)id, &keys);
break;
+ case ID_CF:
+ cachefile_to_keylist(&ads, (CacheFile *)id, &keys, NULL);
+ break;
}
/* build linked-list for searching */
@@ -344,6 +353,56 @@ static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel)
BLI_dlrbTree_free(&keys);
}
+static void time_draw_caches_keyframes(Main *bmain, Scene *scene, View2D *v2d, bool onlysel)
+{
+ CacheFile *cache_file;
+
+ for (cache_file = bmain->cachefiles.first;
+ cache_file;
+ cache_file = cache_file->id.next)
+ {
+ cache_file->draw_flag &= ~CACHEFILE_KEYFRAME_DRAWN;
+ }
+
+ for (Base *base = scene->base.first; base; base = base->next) {
+ Object *ob = base->object;
+
+ ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache);
+
+ if (md) {
+ MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
+
+ cache_file = mcmd->cache_file;
+
+ if (!cache_file || (cache_file->draw_flag & CACHEFILE_KEYFRAME_DRAWN) != 0) {
+ continue;
+ }
+
+ cache_file->draw_flag |= CACHEFILE_KEYFRAME_DRAWN;
+
+ time_draw_idblock_keyframes(v2d, (ID *)cache_file, onlysel);
+ }
+
+ for (bConstraint *con = ob->constraints.first; con; con = con->next) {
+ if (con->type != CONSTRAINT_TYPE_TRANSFORM_CACHE) {
+ continue;
+ }
+
+ bTransformCacheConstraint *data = con->data;
+
+ cache_file = data->cache_file;
+
+ if (!cache_file || (cache_file->draw_flag & CACHEFILE_KEYFRAME_DRAWN) != 0) {
+ continue;
+ }
+
+ cache_file->draw_flag |= CACHEFILE_KEYFRAME_DRAWN;
+
+ time_draw_idblock_keyframes(v2d, (ID *)cache_file, onlysel);
+ }
+ }
+}
+
/* draw keyframe lines for timeline */
static void time_draw_keyframes(const bContext *C, ARegion *ar)
{
@@ -354,7 +413,11 @@ static void time_draw_keyframes(const bContext *C, ARegion *ar)
/* set this for all keyframe lines once and for all */
glLineWidth(1.0);
-
+
+ /* draw cache files keyframes (if available) */
+ UI_ThemeColor(TH_TIME_KEYFRAME);
+ time_draw_caches_keyframes(CTX_data_main(C), scene, v2d, onlysel);
+
/* draw grease pencil keyframes (if available) */
UI_ThemeColor(TH_TIME_GP_KEYFRAME);
if (scene->gpd) {
@@ -585,6 +648,10 @@ static void time_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa),
break;
}
break;
+ case NC_GPENCIL:
+ if (wmn->data == ND_DATA)
+ ED_region_tag_redraw(ar);
+ break;
}
}
@@ -746,6 +813,7 @@ void ED_spacetype_time(void)
art->draw = time_main_region_draw;
art->listener = time_main_region_listener;
art->keymap = time_keymap;
+ art->lock = 1; /* Due to pointcache, see T4960. */
BLI_addhead(&st->regiontypes, art);
/* regions: header */
diff --git a/source/blender/editors/space_time/time_ops.c b/source/blender/editors/space_time/time_ops.c
index 7dd45327352..872793128f0 100644
--- a/source/blender/editors/space_time/time_ops.c
+++ b/source/blender/editors/space_time/time_ops.c
@@ -219,7 +219,9 @@ void time_keymap(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "TIME_OT_start_frame_set", SKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "TIME_OT_end_frame_set", EKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "TIME_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
+#ifdef WITH_INPUT_NDOF
WM_keymap_add_item(keymap, "TIME_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
+#endif
WM_keymap_add_item(keymap, "TIME_OT_view_frame", PAD0, KM_PRESS, 0, 0);
}
diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt
index 059b384a9e2..a5c60248bf1 100644
--- a/source/blender/editors/space_view3d/CMakeLists.txt
+++ b/source/blender/editors/space_view3d/CMakeLists.txt
@@ -90,6 +90,10 @@ if(WITH_FREESTYLE)
add_definitions(-DWITH_FREESTYLE)
endif()
+if(WITH_MOD_SMOKE)
+ add_definitions(-DWITH_SMOKE)
+endif()
+
if(WITH_LEGACY_DEPSGRAPH)
add_definitions(-DWITH_LEGACY_DEPSGRAPH)
endif()
diff --git a/source/blender/editors/space_view3d/drawanimviz.c b/source/blender/editors/space_view3d/drawanimviz.c
index 9872b05da63..cf738de0202 100644
--- a/source/blender/editors/space_view3d/drawanimviz.c
+++ b/source/blender/editors/space_view3d/drawanimviz.c
@@ -130,7 +130,6 @@ void draw_motion_path_instance(Scene *scene,
mpv_start = (mpath->points + sind);
/* draw curve-line of path */
- glShadeModel(GL_SMOOTH);
glBegin(GL_LINE_STRIP);
for (i = 0, mpv = mpv_start; i < len; i++, mpv++) {
@@ -187,7 +186,6 @@ void draw_motion_path_instance(Scene *scene,
}
glEnd();
- glShadeModel(GL_FLAT);
glPointSize(1.0);
diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c
index c6b2ccee85b..1d9a515a5f2 100644
--- a/source/blender/editors/space_view3d/drawarmature.c
+++ b/source/blender/editors/space_view3d/drawarmature.c
@@ -53,6 +53,7 @@
#include "BKE_global.h"
#include "BKE_modifier.h"
#include "BKE_nla.h"
+#include "BKE_curve.h"
#include "BIF_gl.h"
@@ -430,10 +431,9 @@ static void draw_bonevert_solid(void)
glNewList(displist, GL_COMPILE);
qobj = gluNewQuadric();
- gluQuadricDrawStyle(qobj, GLU_FILL);
- glShadeModel(GL_SMOOTH);
+ gluQuadricDrawStyle(qobj, GLU_FILL);
+ /* Draw tips of a bone */
gluSphere(qobj, 0.05, 8, 5);
- glShadeModel(GL_FLAT);
gluDeleteQuadric(qobj);
glEndList();
@@ -889,7 +889,6 @@ static void draw_sphere_bone(const short dt, int armflag, int boneflag, short co
GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
gluQuadricDrawStyle(qobj, GLU_FILL);
- glShadeModel(GL_SMOOTH);
}
else {
gluQuadricDrawStyle(qobj, GLU_SILHOUETTE);
@@ -967,7 +966,6 @@ static void draw_sphere_bone(const short dt, int armflag, int boneflag, short co
/* restore */
if (dt == OB_SOLID) {
- glShadeModel(GL_FLAT);
GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
@@ -985,10 +983,11 @@ static GLubyte bm_dot7[] = {0x0, 0x38, 0x7C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38};
static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned int id,
bPoseChannel *pchan, EditBone *ebone)
{
+ /* call this once, avoid constant changing */
+ BLI_assert(glaGetOneInt(GL_UNPACK_ALIGNMENT) == 1);
+
float length;
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-
if (pchan)
length = pchan->bone->length;
else
@@ -1093,20 +1092,101 @@ static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned
glPopMatrix();
}
-static void draw_b_bone_boxes(const short dt, bPoseChannel *pchan, float xwidth, float length, float zwidth)
+/* A partial copy of b_bone_spline_setup(), with just the parts for previewing editmode curve settings
+ *
+ * This assumes that prev/next bones don't have any impact (since they should all still be in the "straight"
+ * position here anyway), and that we can simply apply the bbone settings to get the desired effect...
+ */
+static void ebone_spline_preview(EditBone *ebone, Mat4 result_array[MAX_BBONE_SUBDIV])
+{
+ float h1[3], h2[3], length, hlength1, hlength2, roll1 = 0.0f, roll2 = 0.0f;
+ float mat3[3][3];
+ float data[MAX_BBONE_SUBDIV + 1][4], *fp;
+ int a;
+
+ length = ebone->length;
+
+ hlength1 = ebone->ease1 * length * 0.390464f; /* 0.5f * sqrt(2) * kappa, the handle length for near-perfect circles */
+ hlength2 = ebone->ease2 * length * 0.390464f;
+
+ /* find the handle points, since this is inside bone space, the
+ * first point = (0, 0, 0)
+ * last point = (0, length, 0)
+ *
+ * we also just apply all the "extra effects", since they're the whole reason we're doing this...
+ */
+ h1[0] = ebone->curveInX;
+ h1[1] = hlength1;
+ h1[2] = ebone->curveInY;
+ roll1 = ebone->roll1;
+
+ h2[0] = ebone->curveOutX;
+ h2[1] = -hlength2;
+ h2[2] = ebone->curveOutY;
+ roll2 = ebone->roll2;
+
+ /* make curve */
+ if (ebone->segments > MAX_BBONE_SUBDIV)
+ ebone->segments = MAX_BBONE_SUBDIV;
+
+ BKE_curve_forward_diff_bezier(0.0f, h1[0], h2[0], 0.0f, data[0], MAX_BBONE_SUBDIV, 4 * sizeof(float));
+ BKE_curve_forward_diff_bezier(0.0f, h1[1], length + h2[1], length, data[0] + 1, MAX_BBONE_SUBDIV, 4 * sizeof(float));
+ BKE_curve_forward_diff_bezier(0.0f, h1[2], h2[2], 0.0f, data[0] + 2, MAX_BBONE_SUBDIV, 4 * sizeof(float));
+ BKE_curve_forward_diff_bezier(roll1, roll1 + 0.390464f * (roll2 - roll1), roll2 - 0.390464f * (roll2 - roll1), roll2, data[0] + 3, MAX_BBONE_SUBDIV, 4 * sizeof(float));
+
+ equalize_bbone_bezier(data[0], ebone->segments); /* note: does stride 4! */
+
+ /* make transformation matrices for the segments for drawing */
+ for (a = 0, fp = data[0]; a < ebone->segments; a++, fp += 4) {
+ sub_v3_v3v3(h1, fp + 4, fp);
+ vec_roll_to_mat3(h1, fp[3], mat3); /* fp[3] is roll */
+
+ copy_m4_m3(result_array[a].mat, mat3);
+ copy_v3_v3(result_array[a].mat[3], fp);
+
+ /* "extra" scale facs... */
+ {
+ const int num_segments = ebone->segments;
+
+ const float scaleFactorIn = 1.0f + (ebone->scaleIn - 1.0f) * ((float)(num_segments - a) / (float)num_segments);
+ const float scaleFactorOut = 1.0f + (ebone->scaleOut - 1.0f) * ((float)(a + 1) / (float)num_segments);
+
+ const float scalefac = scaleFactorIn * scaleFactorOut;
+ float bscalemat[4][4], bscale[3];
+
+ bscale[0] = scalefac;
+ bscale[1] = 1.0f;
+ bscale[2] = scalefac;
+
+ size_to_mat4(bscalemat, bscale);
+
+ /* Note: don't multiply by inverse scale mat here, as it causes problems with scaling shearing and breaking segment chains */
+ mul_m4_series(result_array[a].mat, result_array[a].mat, bscalemat);
+ }
+ }
+}
+
+static void draw_b_bone_boxes(const short dt, bPoseChannel *pchan, EditBone *ebone, float xwidth, float length, float zwidth)
{
int segments = 0;
if (pchan)
segments = pchan->bone->segments;
+ else if (ebone)
+ segments = ebone->segments;
- if ((segments > 1) && (pchan)) {
+ if (segments > 1) {
float dlen = length / (float)segments;
Mat4 bbone[MAX_BBONE_SUBDIV];
int a;
-
- b_bone_spline_setup(pchan, 0, bbone);
-
+
+ if (pchan) {
+ b_bone_spline_setup(pchan, 0, bbone);
+ }
+ else if (ebone) {
+ ebone_spline_preview(ebone, bbone);
+ }
+
for (a = 0; a < segments; a++) {
glPushMatrix();
glMultMatrixf(bbone[a].mat);
@@ -1177,7 +1257,7 @@ static void draw_b_bone(const short dt, int armflag, int boneflag, short constfl
else
UI_ThemeColor(TH_BONE_SOLID);
- draw_b_bone_boxes(OB_SOLID, pchan, xwidth, length, zwidth);
+ draw_b_bone_boxes(OB_SOLID, pchan, ebone, xwidth, length, zwidth);
/* disable solid drawing */
GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
@@ -1190,7 +1270,7 @@ static void draw_b_bone(const short dt, int armflag, int boneflag, short constfl
if (set_pchan_glColor(PCHAN_COLOR_CONSTS, boneflag, constflag)) {
glEnable(GL_BLEND);
- draw_b_bone_boxes(OB_SOLID, pchan, xwidth, length, zwidth);
+ draw_b_bone_boxes(OB_SOLID, pchan, ebone, xwidth, length, zwidth);
glDisable(GL_BLEND);
}
@@ -1200,7 +1280,7 @@ static void draw_b_bone(const short dt, int armflag, int boneflag, short constfl
}
}
- draw_b_bone_boxes(OB_WIRE, pchan, xwidth, length, zwidth);
+ draw_b_bone_boxes(OB_WIRE, pchan, ebone, xwidth, length, zwidth);
}
}
@@ -1687,7 +1767,6 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
/* and draw blended distances */
if (arm->flag & ARM_POSEMODE) {
glEnable(GL_BLEND);
- //glShadeModel(GL_SMOOTH);
if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
@@ -1710,7 +1789,6 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
- //glShadeModel(GL_FLAT);
}
}
@@ -1892,7 +1970,9 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
}
/* custom bone may draw outline double-width */
- glLineWidth(1.0f);
+ if (arm->flag & ARM_POSEMODE) {
+ glLineWidth(1.0f);
+ }
/* wire draw over solid only in posemode */
if ((dt <= OB_WIRE) || (arm->flag & ARM_POSEMODE) || ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) {
@@ -2132,7 +2212,6 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt)
/* and draw blended distances */
glEnable(GL_BLEND);
- //glShadeModel(GL_SMOOTH);
if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
@@ -2147,7 +2226,6 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt)
if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
- //glShadeModel(GL_FLAT);
}
/* if solid we draw it first */
@@ -2615,6 +2693,11 @@ bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
if (v3d->flag2 & V3D_RENDER_OVERRIDE)
return true;
+ /* needed for 'draw_line_bone' which draws pixel. */
+ if (arm->drawtype == ARM_LINE) {
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ }
+
if (dt > OB_WIRE) {
/* we use color for solid lighting */
if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) {
@@ -2690,5 +2773,9 @@ bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
/* restore */
glFrontFace(GL_CCW);
+ if (arm->drawtype == ARM_LINE) {
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+ }
+
return retval;
}
diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c
index 345e47940d5..ecbfd5c7c85 100644
--- a/source/blender/editors/space_view3d/drawmesh.c
+++ b/source/blender/editors/space_view3d/drawmesh.c
@@ -237,7 +237,9 @@ static struct TextureDrawState {
bool texpaint_material; /* use material slots for texture painting */
} Gtexdraw = {NULL, NULL, NULL, false, 0, 0, 0, false, false, {0, 0, 0, 0}, false, false};
-static bool set_draw_settings_cached(int clearcache, MTexPoly *texface, Material *ma, struct TextureDrawState gtexdraw)
+static bool set_draw_settings_cached(
+ int clearcache, MTexPoly *texface, Material *ma,
+ const struct TextureDrawState *gtexdraw)
{
static Material *c_ma;
static int c_textured;
@@ -253,7 +255,7 @@ static bool set_draw_settings_cached(int clearcache, MTexPoly *texface, Material
int lit = 0;
int has_texface = texface != NULL;
bool need_set_tpage = false;
- bool texpaint = ((gtexdraw.ob->mode & OB_MODE_TEXTURE_PAINT) != 0);
+ bool texpaint = ((gtexdraw->ob->mode & OB_MODE_TEXTURE_PAINT) != 0);
Image *ima = NULL;
@@ -271,16 +273,18 @@ static bool set_draw_settings_cached(int clearcache, MTexPoly *texface, Material
c_ma = NULL;
}
else {
- textured = gtexdraw.is_tex;
+ textured = gtexdraw->is_tex;
}
/* convert number of lights into boolean */
- if (gtexdraw.is_lit) lit = 1;
+ if (gtexdraw->is_lit) {
+ lit = 1;
+ }
- backculled = gtexdraw.use_backface_culling;
+ backculled = gtexdraw->use_backface_culling;
if (ma) {
if (ma->mode & MA_SHLESS) lit = 0;
- if (gtexdraw.use_game_mat) {
+ if (gtexdraw->use_game_mat) {
backculled = backculled || (ma->game.flag & GEMAT_BACKCULL);
alphablend = ma->game.alpha_blend;
}
@@ -294,10 +298,10 @@ static bool set_draw_settings_cached(int clearcache, MTexPoly *texface, Material
alphablend = GPU_BLEND_ALPHA;
}
else if (texpaint) {
- if (gtexdraw.texpaint_material)
+ if (gtexdraw->texpaint_material)
ima = ma && ma->texpaintslot ? ma->texpaintslot[ma->paint_active_slot].ima : NULL;
else
- ima = gtexdraw.canvas;
+ ima = gtexdraw->canvas;
}
else
textured = 0;
@@ -369,15 +373,18 @@ static bool set_draw_settings_cached(int clearcache, MTexPoly *texface, Material
}
if (c_badtex) lit = 0;
- if (lit != c_lit || ma != c_ma) {
- if (lit) {
- int options = GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR;
+ if (lit != c_lit || ma != c_ma || textured != c_textured) {
+ int options = GPU_SHADER_USE_COLOR;
- if (gtexdraw.two_sided_lighting)
- options |= GPU_SHADER_TWO_SIDED;
- if (c_textured && !c_badtex)
- options |= GPU_SHADER_TEXTURE_2D;
+ if (c_textured && !c_badtex) {
+ options |= GPU_SHADER_TEXTURE_2D;
+ }
+ if (gtexdraw->two_sided_lighting) {
+ options |= GPU_SHADER_TWO_SIDED;
+ }
+ if (lit) {
+ options |= GPU_SHADER_LIGHTING;
if (!ma)
ma = give_current_material_or_def(NULL, 0); /* default material */
@@ -385,12 +392,10 @@ static bool set_draw_settings_cached(int clearcache, MTexPoly *texface, Material
mul_v3_v3fl(specular, &ma->specr, ma->spec);
GPU_basic_shader_colors(NULL, specular, ma->har, 1.0f);
- GPU_basic_shader_bind(options);
- }
- else {
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
+ GPU_basic_shader_bind(options);
+
c_lit = lit;
c_ma = ma;
}
@@ -430,12 +435,16 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O
else {
/* draw with lights in the scene otherwise */
solidtex = false;
- if (v3d->flag2 & V3D_SHADELESS_TEX)
+ if (v3d->flag2 & V3D_SHADELESS_TEX) {
Gtexdraw.is_lit = 0;
- else
- Gtexdraw.is_lit = GPU_scene_object_lights(scene, ob, v3d->lay, rv3d->viewmat, !rv3d->is_persp);
+ }
+ else {
+ Gtexdraw.is_lit = GPU_scene_object_lights(
+ scene, ob, v3d->localvd ? v3d->localvd->lay : v3d->lay,
+ rv3d->viewmat, !rv3d->is_persp);
+ }
}
-
+
rgba_float_to_uchar(obcol, ob->col);
if (solidtex || v3d->drawtype == OB_TEXTURE) is_tex = true;
@@ -494,8 +503,7 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O
Gtexdraw.two_sided_lighting = (me->flag & ME_TWOSIDED);
memcpy(Gtexdraw.obcol, obcol, sizeof(obcol));
- set_draw_settings_cached(1, NULL, NULL, Gtexdraw);
- glShadeModel(GL_SMOOTH);
+ set_draw_settings_cached(1, NULL, NULL, &Gtexdraw);
glCullFace(GL_BACK);
}
@@ -527,7 +535,6 @@ static void draw_textured_end(void)
GPU_set_tpage(NULL, 0, 0);
}
- glShadeModel(GL_FLAT);
glDisable(GL_CULL_FACE);
GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
@@ -554,7 +561,7 @@ static DMDrawOption draw_tface__set_draw_legacy(MTexPoly *mtexpoly, const bool h
if (ma && (ma->game.flag & GEMAT_INVISIBLE))
return DM_DRAW_OPTION_SKIP;
- invalidtexture = set_draw_settings_cached(0, mtexpoly, ma, Gtexdraw);
+ invalidtexture = set_draw_settings_cached(0, mtexpoly, ma, &Gtexdraw);
if (mtexpoly && invalidtexture) {
glColor3ub(0xFF, 0x00, 0xFF);
@@ -595,7 +602,7 @@ static DMDrawOption draw_tface__set_draw(MTexPoly *mtexpoly, const bool UNUSED(h
if (ma && (ma->game.flag & GEMAT_INVISIBLE)) return DM_DRAW_OPTION_SKIP;
if (mtexpoly || Gtexdraw.is_texpaint)
- set_draw_settings_cached(0, mtexpoly, ma, Gtexdraw);
+ set_draw_settings_cached(0, mtexpoly, ma, &Gtexdraw);
/* always use color from mcol, as set in update_tface_color_layer */
return DM_DRAW_OPTION_NORMAL;
@@ -665,7 +672,7 @@ static void update_tface_color_layer(DerivedMesh *dm, bool use_mcol)
copy_mode = COPY_PREV;
}
}
- else if (mtexpoly && set_draw_settings_cached(0, mtexpoly, ma, Gtexdraw)) {
+ else if (mtexpoly && set_draw_settings_cached(0, mtexpoly, ma, &Gtexdraw)) {
int loop_index = mp->loopstart;
for (j = 0; j < mp->totloop; j++, loop_index++) {
finalCol[loop_index].r = 255;
@@ -713,6 +720,8 @@ static void update_tface_color_layer(DerivedMesh *dm, bool use_mcol)
}
}
}
+
+ dm->dirty |= DM_DIRTY_MCOL_UPDATE_DRAW;
}
static DMDrawOption draw_tface_mapped__set_draw(void *userData, int origindex, int UNUSED(mat_nr))
@@ -829,7 +838,7 @@ static void draw_mesh_text(Scene *scene, Object *ob, int glsl)
}
}
else {
- badtex = set_draw_settings_cached(0, mtpoly, mat, Gtexdraw);
+ badtex = set_draw_settings_cached(0, mtpoly, mat, &Gtexdraw);
if (badtex) {
continue;
}
@@ -978,10 +987,17 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d
if (ob == OBACT) {
if (ob->mode & OB_MODE_WEIGHT_PAINT) {
dm_draw_flag |= DM_DRAW_USE_COLORS | DM_DRAW_ALWAYS_SMOOTH | DM_DRAW_SKIP_HIDDEN;
-
}
else if (ob->mode & OB_MODE_SCULPT) {
- dm_draw_flag |= DM_DRAW_SKIP_HIDDEN;
+ dm_draw_flag |= DM_DRAW_SKIP_HIDDEN | DM_DRAW_USE_COLORS;
+ }
+ else if ((ob->mode & OB_MODE_TEXTURE_PAINT) == 0) {
+ dm_draw_flag |= DM_DRAW_USE_COLORS;
+ }
+ }
+ else {
+ if ((ob->mode & OB_MODE_TEXTURE_PAINT) == 0) {
+ dm_draw_flag |= DM_DRAW_USE_COLORS;
}
}
@@ -999,7 +1015,22 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d
else {
userData.me = NULL;
- update_tface_color_layer(dm, !(ob->mode & OB_MODE_TEXTURE_PAINT));
+ /* if ((ob->mode & OB_MODE_ALL_PAINT) == 0) */ {
+
+ /* Note: this isn't efficient and runs on every redraw,
+ * its needed so material colors are used for vertex colors.
+ * In the future we will likely remove 'texface' so, just avoid running this where possible,
+ * (when vertex paint or weight paint are used).
+ *
+ * Note 2: We disable optimization for now since it causes T48788
+ * and it is now too close to release to do something smarter.
+ *
+ * TODO(sergey): Find some real solution here.
+ */
+
+ update_tface_color_layer(dm, !(ob->mode & OB_MODE_TEXTURE_PAINT));
+ }
+
dm->drawFacesTex(
dm, draw_tface__set_draw, compareDrawOptions,
&userData, dm_draw_flag);
@@ -1183,7 +1214,8 @@ void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d,
set_face_cb = NULL;
/* test if we can use glsl */
- bool glsl = (v3d->drawtype == OB_MATERIAL) && !picking;
+ const int drawtype = view3d_effective_drawtype(v3d);
+ bool glsl = (drawtype == OB_MATERIAL) && !picking;
GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL);
@@ -1299,8 +1331,8 @@ void draw_mesh_paint_weight_edges(RegionView3D *rv3d, DerivedMesh *dm,
}
glColor4ub(255, 255, 255, 96);
- glEnable(GL_LINE_STIPPLE);
- glLineStipple(1, 0xAAAA);
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ GPU_basic_shader_line_stipple(1, 0xAAAA);
dm->drawMappedEdges(dm, (DMSetDrawOptions)edgemask_cb, user_data);
@@ -1312,7 +1344,7 @@ void draw_mesh_paint_weight_edges(RegionView3D *rv3d, DerivedMesh *dm,
glEnable(GL_DEPTH_TEST);
}
- glDisable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
if (use_alpha) {
glDisable(GL_BLEND);
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 65f1f375443..ea40d4eb5e1 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -227,16 +227,25 @@ static void ob_wire_color_blend_theme_id(const unsigned char ob_wire_col[4], con
glColor3fv(col);
}
+int view3d_effective_drawtype(const struct View3D *v3d)
+{
+ if (v3d->drawtype == OB_RENDER) {
+ return v3d->prev_drawtype;
+ }
+ return v3d->drawtype;
+}
+
/* this condition has been made more complex since editmode can draw textures */
bool check_object_draw_texture(Scene *scene, View3D *v3d, const char drawtype)
{
+ const int v3d_drawtype = view3d_effective_drawtype(v3d);
/* texture and material draw modes */
- if (ELEM(v3d->drawtype, OB_TEXTURE, OB_MATERIAL) && drawtype > OB_SOLID) {
+ if (ELEM(v3d_drawtype, OB_TEXTURE, OB_MATERIAL) && drawtype > OB_SOLID) {
return true;
}
/* textured solid */
- if ((v3d->drawtype == OB_SOLID) &&
+ if ((v3d_drawtype == OB_SOLID) &&
(v3d->flag2 & V3D_SOLID_TEX) &&
(BKE_scene_use_new_shading_nodes(scene) == false))
{
@@ -298,7 +307,7 @@ bool draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, const char dt)
if (v3d->flag2 & V3D_SHOW_SOLID_MATCAP)
return true;
-
+
if (v3d->drawtype == OB_TEXTURE)
return (scene->gm.matmode == GAME_MAT_GLSL && !BKE_scene_use_new_shading_nodes(scene));
else if (v3d->drawtype == OB_MATERIAL && dt > OB_SOLID)
@@ -1200,7 +1209,7 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
if ((drawcone || drawshadowbox) && !v3d->transp) {
/* in this case we need to draw delayed */
- ED_view3d_after_add(&v3d->afterdraw_transp, base, dflag);
+ ED_view3d_after_add(v3d->xray ? &v3d->afterdraw_xraytransp : &v3d->afterdraw_transp, base, dflag);
return;
}
@@ -1392,8 +1401,8 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
float blend = z_abs * (1.0f - pow2f(la->spotblend));
/* hide line if it is zero size or overlaps with outer border,
- * previously it adjusted to always to show it but that seems
- * confusing because it doesn't show the actual blend size */
+ * previously it adjusted to always to show it but that seems
+ * confusing because it doesn't show the actual blend size */
if (blend != 0.0f && blend != z_abs) {
circ(0.0f, 0.0f, blend);
}
@@ -1583,12 +1592,9 @@ static void draw_bundle_sphere(void)
displist = glGenLists(1);
glNewList(displist, GL_COMPILE);
-
qobj = gluNewQuadric();
gluQuadricDrawStyle(qobj, GLU_FILL);
- glShadeModel(GL_SMOOTH);
gluSphere(qobj, 0.05, 8, 8);
- glShadeModel(GL_FLAT);
gluDeleteQuadric(qobj);
glEndList();
@@ -1661,7 +1667,8 @@ static void draw_viewport_object_reconstruction(
v3d->bundle_size / 0.05f / camera_size[1],
v3d->bundle_size / 0.05f / camera_size[2]);
- if (v3d->drawtype == OB_WIRE) {
+ const int v3d_drawtype = view3d_effective_drawtype(v3d);
+ if (v3d_drawtype == OB_WIRE) {
if ((dflag & DRAW_CONSTCOLOR) == 0) {
if (selected && (track->flag & TRACK_CUSTOMCOLOR) == 0) {
glColor3ubv(ob_wire_col);
@@ -1673,7 +1680,7 @@ static void draw_viewport_object_reconstruction(
drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype);
}
- else if (v3d->drawtype > OB_WIRE) {
+ else if (v3d_drawtype > OB_WIRE) {
if (v3d->bundle_drawtype == OB_EMPTY_SPHERE) {
/* selection outline */
if (selected) {
@@ -1769,8 +1776,6 @@ static void draw_viewport_reconstruction(
GPU_basic_shader_colors(NULL, NULL, 0, 1.0f);
GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
- glShadeModel(GL_SMOOTH);
-
tracking_object = tracking->objects.first;
while (tracking_object) {
draw_viewport_object_reconstruction(
@@ -1781,7 +1786,6 @@ static void draw_viewport_reconstruction(
}
/* restore */
- glShadeModel(GL_FLAT);
GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
if ((dflag & DRAW_CONSTCOLOR) == 0) {
@@ -1920,16 +1924,15 @@ static void drawcamera_stereo3d(
if (is_stereo3d_cameras) {
/* draw connecting lines */
- glPushAttrib(GL_ENABLE_BIT);
-
- glLineStipple(2, 0xAAAA);
- glEnable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ GPU_basic_shader_line_stipple(2, 0xAAAA);
glBegin(GL_LINES);
glVertex3fv(origin[0]);
glVertex3fv(origin[1]);
glEnd();
- glPopAttrib();
+
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
}
/* draw convergence plane */
@@ -2341,7 +2344,6 @@ static void drawlattice(View3D *v3d, Object *ob)
if (ob->defbase.first && lt->dvert) {
actdef_wcol = ob->actdef;
- glShadeModel(GL_SMOOTH);
}
}
@@ -2370,10 +2372,6 @@ static void drawlattice(View3D *v3d, Object *ob)
}
}
glEnd();
-
- /* restoration for weight colors */
- if (actdef_wcol)
- glShadeModel(GL_FLAT);
if (is_edit) {
BPoint *actbp = BKE_lattice_active_point_get(lt);
@@ -3081,7 +3079,7 @@ static DMDrawOption draw_dm_bweights__setDrawOptions(void *userData, int index)
if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
const float bweight = BM_ELEM_CD_GET_FLOAT(eed, data->cd_layer_offset);
if (bweight != 0.0f) {
- UI_ThemeColorBlend(TH_WIRE_EDIT, TH_EDGE_SELECT, bweight);
+ UI_ThemeColorBlend(TH_WIRE_EDIT, TH_EDGE_BEVEL, bweight);
return DM_DRAW_OPTION_NORMAL;
}
}
@@ -3097,7 +3095,7 @@ static void draw_dm_bweights__mapFunc(void *userData, int index, const float co[
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
const float bweight = BM_ELEM_CD_GET_FLOAT(eve, data->cd_layer_offset);
if (bweight != 0.0f) {
- UI_ThemeColorBlend(TH_VERTEX, TH_VERTEX_SELECT, bweight);
+ UI_ThemeColorBlend(TH_VERTEX, TH_VERTEX_BEVEL, bweight);
glVertex3fv(co);
}
}
@@ -3238,17 +3236,15 @@ static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d,
((ts->selectmode & SCE_SELECT_VERTEX) || (me->drawflag & ME_DRAWEIGHT)))
{
if (draw_dm_edges_weight_check(me, v3d)) {
- glShadeModel(GL_SMOOTH);
+ // Interpolate vertex weights
draw_dm_edges_weight_interp(em, cageDM, ts->weightuser);
- glShadeModel(GL_FLAT);
}
else if (ts->selectmode == SCE_SELECT_FACE) {
draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act);
}
else {
- glShadeModel(GL_SMOOTH);
+ // Interpolate vertex selection
draw_dm_edges_sel_interp(em, cageDM, wireCol, selCol);
- glShadeModel(GL_FLAT);
}
}
else {
@@ -3748,7 +3744,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
}
if ((dt > OB_WIRE) && (v3d->flag2 & V3D_RENDER_SHADOW)) {
- /* pass */
+ /* pass */
}
else {
/* annoying but active faces is stored differently */
@@ -4231,7 +4227,7 @@ static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3
/* If we are drawing shadows and any of the materials don't cast a shadow,
* then don't draw the object */
if (v3d->flag2 & V3D_RENDER_SHADOW) {
- for (int i = 0; i < ob->totcol; ++i) {
+ for (int i = 1; i <= ob->totcol; ++i) {
Material *ma = give_current_material(ob, i);
if (ma && !(ma->mode2 & MA_CASTSHADOW)) {
return true;
@@ -4254,12 +4250,15 @@ static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3
if (ob == obedit || drawlinked) {
DerivedMesh *finalDM, *cageDM;
- if (obedit != ob)
- finalDM = cageDM = editbmesh_get_derived_base(ob, em);
- else
+ if (obedit != ob) {
+ finalDM = cageDM = editbmesh_get_derived_base(
+ ob, em, scene->customdata_mask);
+ }
+ else {
cageDM = editbmesh_get_derived_cage_and_final(
scene, ob, em, scene->customdata_mask,
&finalDM);
+ }
const bool use_material = ((me->drawflag & ME_DRAWEIGHT) == 0);
@@ -4451,10 +4450,6 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
glEnableClientState(GL_VERTEX_ARRAY);
- if (ob->type == OB_MBALL) { /* mball always smooth shaded */
- glShadeModel(GL_SMOOTH);
- }
-
/* track current material, -1 for none (needed for lines) */
short col = -1;
@@ -4476,7 +4471,6 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
// glVertexPointer(3, GL_FLOAT, 0, dl->verts);
// glDrawArrays(GL_LINE_STRIP, 0, dl->nr);
-
glBegin(GL_LINE_STRIP);
for (int nr = dl->nr; nr; nr--, data += 3)
glVertex3fv(data);
@@ -4507,15 +4501,15 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
GPU_object_material_bind(dl->col + 1, use_glsl ? &gattribs : NULL);
col = dl->col;
}
-
- if (dl->rt & CU_SMOOTH) glShadeModel(GL_SMOOTH);
- else glShadeModel(GL_FLAT);
+ /* FLAT/SMOOTH shading for surfaces */
+ glShadeModel((dl->rt & CU_SMOOTH) ? GL_SMOOTH : GL_FLAT);
glEnableClientState(GL_NORMAL_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, dl->verts);
glNormalPointer(GL_FLOAT, 0, dl->nors);
glDrawElements(GL_QUADS, 4 * dl->totindex, GL_UNSIGNED_INT, dl->index);
glDisableClientState(GL_NORMAL_ARRAY);
+ glShadeModel(GL_SMOOTH);
}
break;
@@ -4560,7 +4554,6 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
}
glDisableClientState(GL_VERTEX_ARRAY);
- glShadeModel(GL_FLAT);
glFrontFace(GL_CCW);
if (col != -1) {
@@ -4670,7 +4663,7 @@ static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3
index3_nors_incr = true;
}
else {
- if (!render_only || (render_only && BKE_displist_has_faces(lb))) {
+ if (!render_only || BKE_displist_has_faces(lb)) {
return drawDispListwire(lb, ob->type);
}
}
@@ -5025,7 +5018,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
unsigned char tcol[4] = {0, 0, 0, 255};
/* 1. */
- if (part == NULL || !psys_check_enabled(ob, psys))
+ if (part == NULL || !psys_check_enabled(ob, psys, G.is_rendering))
return;
if (pars == NULL) return;
@@ -5733,7 +5726,7 @@ static void draw_update_ptcache_edit(Scene *scene, Object *ob, PTCacheEdit *edit
/* create path and child path cache if it doesn't exist already */
if (edit->pathcache == NULL)
- psys_cache_edit_paths(scene, ob, edit, CFRA);
+ psys_cache_edit_paths(scene, ob, edit, CFRA, G.is_rendering);
}
static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
@@ -5770,8 +5763,6 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
- glShadeModel(GL_SMOOTH);
-
if (pset->brushtype == PE_BRUSH_WEIGHT)
glLineWidth(2.0f);
@@ -5886,7 +5877,6 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
- glShadeModel(GL_FLAT);
if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
}
@@ -7344,7 +7334,7 @@ static void draw_object_wire_color(Scene *scene, Base *base, unsigned char r_ob_
}
else {
/* Sets the 'colindex' */
- if (ob->id.lib) {
+ if (ID_IS_LINKED_DATABLOCK(ob)) {
colindex = (base->flag & (SELECT + BA_WAS_SEL)) ? 2 : 1;
}
/* Sets the 'theme_id' or fallback to wire */
@@ -7597,7 +7587,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
/* maximum drawtype */
char dt = v3d->drawtype;
- if (dt == OB_RENDER) dt = OB_SOLID;
+ if (dt == OB_RENDER) dt = v3d->prev_drawtype;
dt = MIN2(dt, ob->dt);
if (v3d->zbuf == 0 && dt > OB_WIRE) dt = OB_WIRE;
short dtx = 0;
@@ -7855,122 +7845,80 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
}
}
- /* draw code for smoke */
- if (smd) {
-#if 0
- /* draw collision objects */
- if ((smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll) {
- SmokeCollSettings *scs = smd->coll;
- if (scs->points) {
- size_t i;
-
- glLoadMatrixf(rv3d->viewmat);
-
- if (col || (ob->flag & SELECT)) cpack(0xFFFFFF);
- glDepthMask(GL_FALSE);
- glEnable(GL_BLEND);
-
-
- // glPointSize(3.0);
- glBegin(GL_POINTS);
+ /* draw code for smoke, only draw domains */
+ if (smd && smd->domain) {
+ SmokeDomainSettings *sds = smd->domain;
+ float viewnormal[3];
- for (i = 0; i < scs->numpoints; i++)
- {
- glVertex3fv(&scs->points[3 * i]);
- }
+ glLoadMatrixf(rv3d->viewmat);
+ glMultMatrixf(ob->obmat);
- glEnd();
+ if (!render_override) {
+ BoundBox bb;
+ float p0[3], p1[3];
- glMultMatrixf(ob->obmat);
- glDisable(GL_BLEND);
- glDepthMask(GL_TRUE);
- if (col) cpack(col);
+ /* draw max domain bounds */
+ if ((sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN)) {
+ VECSUBFAC(p0, sds->p0, sds->cell_size, sds->adapt_res);
+ VECADDFAC(p1, sds->p1, sds->cell_size, sds->adapt_res);
+ BKE_boundbox_init_from_minmax(&bb, p0, p1);
+ draw_box(bb.vec, false);
}
- }
-#endif
- /* only draw domains */
- if (smd->domain) {
- SmokeDomainSettings *sds = smd->domain;
- float viewnormal[3];
+ /* draw a single voxel to hint the user about the resolution of the fluid */
+ copy_v3_v3(p0, sds->p0);
- glLoadMatrixf(rv3d->viewmat);
- glMultMatrixf(ob->obmat);
-
- if (!render_override) {
- BoundBox bb;
- float p0[3], p1[3];
-
- /* draw adaptive domain bounds */
- if ((sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN)) {
- /* draw domain max bounds */
- VECSUBFAC(p0, sds->p0, sds->cell_size, sds->adapt_res);
- VECADDFAC(p1, sds->p1, sds->cell_size, sds->adapt_res);
- BKE_boundbox_init_from_minmax(&bb, p0, p1);
- draw_box(bb.vec, false);
- }
+ if (sds->flags & MOD_SMOKE_HIGHRES) {
+ madd_v3_v3v3fl(p1, p0, sds->cell_size, 1.0f / (sds->amplify + 1));
+ }
+ else {
+ add_v3_v3v3(p1, p0, sds->cell_size);
+ }
-#if 0
- /* draw base resolution bounds */
- BKE_boundbox_init_from_minmax(&bb, sds->p0, sds->p1);
- draw_box(bb.vec);
-#endif
+ BKE_boundbox_init_from_minmax(&bb, p0, p1);
+ draw_box(bb.vec, false);
+ }
+ /* don't show smoke before simulation starts, this could be made an option in the future */
+ if (sds->fluid && CFRA >= sds->point_cache[0]->startframe) {
+ float p0[3], p1[3];
- /* draw a single voxel to hint the user about the resolution of the fluid */
- copy_v3_v3(p0, sds->p0);
+ /* get view vector */
+ invert_m4_m4(ob->imat, ob->obmat);
+ mul_v3_mat3_m4v3(viewnormal, ob->imat, rv3d->viewinv[2]);
+ normalize_v3(viewnormal);
- if (sds->flags & MOD_SMOKE_HIGHRES) {
- madd_v3_v3v3fl(p1, p0, sds->cell_size, 1.0f / (sds->amplify + 1));
- }
- else {
- add_v3_v3v3(p1, p0, sds->cell_size);
- }
+ /* set dynamic boundaries to draw the volume
+ * also scale cube to global space to equalize volume slicing on all axes
+ * (it's scaled back before drawing) */
+ p0[0] = (sds->p0[0] + sds->cell_size[0] * sds->res_min[0] + sds->obj_shift_f[0]) * fabsf(ob->size[0]);
+ p0[1] = (sds->p0[1] + sds->cell_size[1] * sds->res_min[1] + sds->obj_shift_f[1]) * fabsf(ob->size[1]);
+ p0[2] = (sds->p0[2] + sds->cell_size[2] * sds->res_min[2] + sds->obj_shift_f[2]) * fabsf(ob->size[2]);
+ p1[0] = (sds->p0[0] + sds->cell_size[0] * sds->res_max[0] + sds->obj_shift_f[0]) * fabsf(ob->size[0]);
+ p1[1] = (sds->p0[1] + sds->cell_size[1] * sds->res_max[1] + sds->obj_shift_f[1]) * fabsf(ob->size[1]);
+ p1[2] = (sds->p0[2] + sds->cell_size[2] * sds->res_max[2] + sds->obj_shift_f[2]) * fabsf(ob->size[2]);
- BKE_boundbox_init_from_minmax(&bb, p0, p1);
- draw_box(bb.vec, false);
+ if (!sds->wt || !(sds->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) {
+ sds->tex = NULL;
+ GPU_create_smoke(smd, 0);
+ draw_smoke_volume(sds, ob, p0, p1, viewnormal);
+ GPU_free_smoke(smd);
+ }
+ else if (sds->wt && (sds->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) {
+ sds->tex = NULL;
+ GPU_create_smoke(smd, 1);
+ draw_smoke_volume(sds, ob, p0, p1, viewnormal);
+ GPU_free_smoke(smd);
}
- /* don't show smoke before simulation starts, this could be made an option in the future */
- if (sds->fluid && CFRA >= sds->point_cache[0]->startframe) {
- float p0[3], p1[3];
-
- /* get view vector */
- invert_m4_m4(ob->imat, ob->obmat);
- mul_v3_mat3_m4v3(viewnormal, ob->imat, rv3d->viewinv[2]);
- normalize_v3(viewnormal);
-
- /* set dynamic boundaries to draw the volume
- * also scale cube to global space to equalize volume slicing on all axes
- * (it's scaled back before drawing) */
- p0[0] = (sds->p0[0] + sds->cell_size[0] * sds->res_min[0] + sds->obj_shift_f[0]) * fabsf(ob->size[0]);
- p0[1] = (sds->p0[1] + sds->cell_size[1] * sds->res_min[1] + sds->obj_shift_f[1]) * fabsf(ob->size[1]);
- p0[2] = (sds->p0[2] + sds->cell_size[2] * sds->res_min[2] + sds->obj_shift_f[2]) * fabsf(ob->size[2]);
- p1[0] = (sds->p0[0] + sds->cell_size[0] * sds->res_max[0] + sds->obj_shift_f[0]) * fabsf(ob->size[0]);
- p1[1] = (sds->p0[1] + sds->cell_size[1] * sds->res_max[1] + sds->obj_shift_f[1]) * fabsf(ob->size[1]);
- p1[2] = (sds->p0[2] + sds->cell_size[2] * sds->res_max[2] + sds->obj_shift_f[2]) * fabsf(ob->size[2]);
-
- if (!sds->wt || !(sds->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) {
- sds->tex = NULL;
- GPU_create_smoke(smd, 0);
- draw_smoke_volume(sds, ob, p0, p1, viewnormal);
- GPU_free_smoke(smd);
- }
- else if (sds->wt && (sds->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) {
- sds->tex = NULL;
- GPU_create_smoke(smd, 1);
- draw_smoke_volume(sds, ob, p0, p1, viewnormal);
- GPU_free_smoke(smd);
- }
+ /* smoke debug render */
+ if (!render_override && sds->draw_velocity) {
+ draw_smoke_velocity(sds, viewnormal);
+ }
- /* smoke debug render */
-#ifdef SMOKE_DEBUG_VELOCITY
- draw_smoke_velocity(smd->domain, ob);
-#endif
#ifdef SMOKE_DEBUG_HEAT
- draw_smoke_heat(smd->domain, ob);
+ draw_smoke_heat(smd->domain, ob);
#endif
- }
}
}
@@ -8100,7 +8048,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
!(G.f & G_RENDER_OGL))
{
/* check > 0 otherwise grease pencil can draw into the circle select which is annoying. */
- drawcentercircle(v3d, rv3d, ob->obmat[3], do_draw_center, ob->id.lib || ob->id.us > 1);
+ drawcentercircle(v3d, rv3d, ob->obmat[3], do_draw_center, ID_IS_LINKED_DATABLOCK(ob) || ob->id.us > 1);
}
}
}
@@ -8229,7 +8177,7 @@ static void bbs_obmode_mesh_verts__mapFunc(void *userData, int index, const floa
MVert *mv = &data->mvert[index];
if (!(mv->flag & ME_HIDE)) {
- WM_framebuffer_index_set(data->offset + index);
+ GPU_select_index_set(data->offset + index);
glVertex3fv(co);
}
}
@@ -8254,7 +8202,7 @@ static void bbs_mesh_verts__mapFunc(void *userData, int index, const float co[3]
BMVert *eve = BM_vert_at_index(data->bm, index);
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
- WM_framebuffer_index_set(data->offset + index);
+ GPU_select_index_set(data->offset + index);
glVertex3fv(co);
}
}
@@ -8273,7 +8221,7 @@ static DMDrawOption bbs_mesh_wire__setDrawOptions(void *userData, int index)
BMEdge *eed = BM_edge_at_index(data->bm, index);
if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- WM_framebuffer_index_set(data->offset + index);
+ GPU_select_index_set(data->offset + index);
return DM_DRAW_OPTION_NORMAL;
}
else {
@@ -8287,7 +8235,7 @@ static void bbs_mesh_wire(BMEditMesh *em, DerivedMesh *dm, int offset)
}
/**
- * dont set #WM_framebuffer_index_set. just use to mask other
+ * dont set #GPU_framebuffer_index_set. just use to mask other
*/
static DMDrawOption bbs_mesh_mask__setSolidDrawOptions(void *userData, int index)
{
@@ -8306,7 +8254,7 @@ static DMDrawOption bbs_mesh_solid__setSolidDrawOptions(void *userData, int inde
BMFace *efa = BM_face_at_index(userData, index);
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- WM_framebuffer_index_set(index + 1);
+ GPU_select_index_set(index + 1);
return DM_DRAW_OPTION_NORMAL;
}
else {
@@ -8319,7 +8267,7 @@ static void bbs_mesh_solid__drawCenter(void *userData, int index, const float ce
BMFace *efa = BM_face_at_index(userData, index);
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- WM_framebuffer_index_set(index + 1);
+ GPU_select_index_set(index + 1);
glVertex3fv(cent);
}
@@ -8350,7 +8298,7 @@ static void bbs_mesh_solid_EM(BMEditMesh *em, Scene *scene, View3D *v3d,
static DMDrawOption bbs_mesh_solid__setDrawOpts(void *UNUSED(userData), int index)
{
- WM_framebuffer_index_set(index + 1);
+ GPU_select_index_set(index + 1);
return DM_DRAW_OPTION_NORMAL;
}
@@ -8359,7 +8307,7 @@ static DMDrawOption bbs_mesh_solid_hide__setDrawOpts(void *userData, int index)
Mesh *me = userData;
if (!(me->mpoly[index].flag & ME_HIDE)) {
- WM_framebuffer_index_set(index + 1);
+ GPU_select_index_set(index + 1);
return DM_DRAW_OPTION_NORMAL;
}
else {
@@ -8367,7 +8315,7 @@ static DMDrawOption bbs_mesh_solid_hide__setDrawOpts(void *userData, int index)
}
}
-/* must have called WM_framebuffer_index_set beforehand */
+/* must have called GPU_framebuffer_index_set beforehand */
static DMDrawOption bbs_mesh_solid_hide2__setDrawOpts(void *userData, int index)
{
Mesh *me = userData;
@@ -8493,7 +8441,7 @@ static void draw_object_mesh_instance(Scene *scene, View3D *v3d, RegionView3D *r
DerivedMesh *dm = NULL, *edm = NULL;
if (ob->mode & OB_MODE_EDIT) {
- edm = editbmesh_get_derived_base(ob, me->edit_btmesh);
+ edm = editbmesh_get_derived_base(ob, me->edit_btmesh, CD_MASK_BAREMESH);
DM_update_materials(edm, ob);
}
else {
diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c
index e93d840eddd..b0e21601b9c 100644
--- a/source/blender/editors/space_view3d/drawvolume.c
+++ b/source/blender/editors/space_view3d/drawvolume.c
@@ -40,6 +40,7 @@
#include "BLI_utildefines.h"
#include "BLI_math.h"
+#include "BKE_DerivedMesh.h"
#include "BKE_particle.h"
#include "smoke_API.h"
@@ -113,6 +114,63 @@ typedef struct VolumeSlicer {
float (*verts)[3];
} VolumeSlicer;
+/* *************************** Axis Aligned Slicing ************************** */
+
+static void create_single_slice(VolumeSlicer *slicer, const float depth,
+ const int axis, const int idx)
+{
+ const float vertices[3][4][3] = {
+ {
+ { depth, slicer->min[1], slicer->min[2] },
+ { depth, slicer->max[1], slicer->min[2] },
+ { depth, slicer->max[1], slicer->max[2] },
+ { depth, slicer->min[1], slicer->max[2] }
+ },
+ {
+ { slicer->min[0], depth, slicer->min[2] },
+ { slicer->min[0], depth, slicer->max[2] },
+ { slicer->max[0], depth, slicer->max[2] },
+ { slicer->max[0], depth, slicer->min[2] }
+ },
+ {
+ { slicer->min[0], slicer->min[1], depth },
+ { slicer->min[0], slicer->max[1], depth },
+ { slicer->max[0], slicer->max[1], depth },
+ { slicer->max[0], slicer->min[1], depth }
+ }
+ };
+
+ copy_v3_v3(slicer->verts[idx + 0], vertices[axis][0]);
+ copy_v3_v3(slicer->verts[idx + 1], vertices[axis][1]);
+ copy_v3_v3(slicer->verts[idx + 2], vertices[axis][2]);
+ copy_v3_v3(slicer->verts[idx + 3], vertices[axis][0]);
+ copy_v3_v3(slicer->verts[idx + 4], vertices[axis][2]);
+ copy_v3_v3(slicer->verts[idx + 5], vertices[axis][3]);
+}
+
+static void create_axis_aligned_slices(VolumeSlicer *slicer, const int num_slices,
+ const float view_dir[3], const int axis)
+{
+ float depth, slice_size = slicer->size[axis] / num_slices;
+
+ /* always process slices in back to front order! */
+ if (view_dir[axis] > 0.0f) {
+ depth = slicer->min[axis];
+ }
+ else {
+ depth = slicer->max[axis];
+ slice_size = -slice_size;
+ }
+
+ int count = 0;
+ for (int slice = 0; slice < num_slices; slice++) {
+ create_single_slice(slicer, depth, axis, count);
+
+ count += 6;
+ depth += slice_size;
+ }
+}
+
/* *************************** View Aligned Slicing ************************** */
/* Code adapted from:
@@ -288,6 +346,108 @@ static int create_view_aligned_slices(VolumeSlicer *slicer,
return num_points;
}
+static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture *tex_spec,
+ bool use_fire, const float min[3],
+ const float ob_sizei[3], const float invsize[3])
+{
+ int invsize_location = GPU_shader_get_uniform(shader, "invsize");
+ int ob_sizei_location = GPU_shader_get_uniform(shader, "ob_sizei");
+ int min_location = GPU_shader_get_uniform(shader, "min_location");
+
+ int soot_location;
+ int stepsize_location;
+ int densityscale_location;
+ int spec_location, flame_location;
+ int shadow_location, actcol_location;
+
+ if (use_fire) {
+ spec_location = GPU_shader_get_uniform(shader, "spectrum_texture");
+ flame_location = GPU_shader_get_uniform(shader, "flame_texture");
+ }
+ else {
+ shadow_location = GPU_shader_get_uniform(shader, "shadow_texture");
+ actcol_location = GPU_shader_get_uniform(shader, "active_color");
+ soot_location = GPU_shader_get_uniform(shader, "soot_texture");
+ stepsize_location = GPU_shader_get_uniform(shader, "step_size");
+ densityscale_location = GPU_shader_get_uniform(shader, "density_scale");
+ }
+
+ GPU_shader_bind(shader);
+
+ if (use_fire) {
+ GPU_texture_bind(sds->tex_flame, 2);
+ GPU_shader_uniform_texture(shader, flame_location, sds->tex_flame);
+
+ GPU_texture_bind(tex_spec, 3);
+ GPU_shader_uniform_texture(shader, spec_location, tex_spec);
+ }
+ else {
+ float density_scale = 10.0f * sds->display_thickness;
+
+ GPU_shader_uniform_vector(shader, stepsize_location, 1, 1, &sds->dx);
+ GPU_shader_uniform_vector(shader, densityscale_location, 1, 1, &density_scale);
+
+ GPU_texture_bind(sds->tex, 0);
+ GPU_shader_uniform_texture(shader, soot_location, sds->tex);
+
+ GPU_texture_bind(sds->tex_shadow, 1);
+ GPU_shader_uniform_texture(shader, shadow_location, sds->tex_shadow);
+
+ float active_color[3] = { 0.9, 0.9, 0.9 };
+ if ((sds->active_fields & SM_ACTIVE_COLORS) == 0)
+ mul_v3_v3(active_color, sds->active_color);
+ GPU_shader_uniform_vector(shader, actcol_location, 3, 1, active_color);
+ }
+
+ GPU_shader_uniform_vector(shader, min_location, 3, 1, min);
+ GPU_shader_uniform_vector(shader, ob_sizei_location, 3, 1, ob_sizei);
+ GPU_shader_uniform_vector(shader, invsize_location, 3, 1, invsize);
+}
+
+static void unbind_shader(SmokeDomainSettings *sds, GPUTexture *tex_spec, bool use_fire)
+{
+ GPU_shader_unbind();
+
+ GPU_texture_unbind(sds->tex);
+
+ if (use_fire) {
+ GPU_texture_unbind(sds->tex_flame);
+ GPU_texture_unbind(tex_spec);
+ GPU_texture_free(tex_spec);
+ }
+ else {
+ GPU_texture_unbind(sds->tex_shadow);
+ }
+}
+
+static void draw_buffer(SmokeDomainSettings *sds, GPUShader *shader, const VolumeSlicer *slicer,
+ const float ob_sizei[3], const float invsize[3], const int num_points, const bool do_fire)
+{
+ GPUTexture *tex_spec = (do_fire) ? create_flame_spectrum_texture() : NULL;
+
+ GLuint vertex_buffer;
+ glGenBuffers(1, &vertex_buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * num_points, &slicer->verts[0][0], GL_STATIC_DRAW);
+
+ bind_shader(sds, shader, tex_spec, do_fire, slicer->min, ob_sizei, invsize);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(3, GL_FLOAT, 0, NULL);
+
+ glDrawArrays(GL_TRIANGLES, 0, num_points);
+
+ glDisableClientState(GL_VERTEX_ARRAY);
+
+ unbind_shader(sds, tex_spec, do_fire);
+
+ /* cleanup */
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ glDeleteBuffers(1, &vertex_buffer);
+}
+
void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
const float min[3], const float max[3],
const float viewnormal[3])
@@ -299,14 +459,23 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
const bool use_fire = (sds->active_fields & SM_ACTIVE_FIRE) && sds->tex_flame;
- GPUShader *shader = GPU_shader_get_builtin_shader(
- (use_fire) ? GPU_SHADER_SMOKE_FIRE : GPU_SHADER_SMOKE);
+ GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_SMOKE);
if (!shader) {
fprintf(stderr, "Unable to create GLSL smoke shader.\n");
return;
}
+ GPUShader *fire_shader = NULL;
+ if (use_fire) {
+ fire_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SMOKE_FIRE);
+
+ if (!fire_shader) {
+ fprintf(stderr, "Unable to create GLSL fire shader.\n");
+ return;
+ }
+ }
+
const float ob_sizei[3] = {
1.0f / fabsf(ob->size[0]),
1.0f / fabsf(ob->size[1]),
@@ -320,54 +489,27 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
TIMEIT_START(draw);
#endif
- /* setup smoke shader */
-
- int soot_location = GPU_shader_get_uniform(shader, "soot_texture");
- int spec_location = GPU_shader_get_uniform(shader, "spectrum_texture");
- int shadow_location = GPU_shader_get_uniform(shader, "shadow_texture");
- int flame_location = GPU_shader_get_uniform(shader, "flame_texture");
- int actcol_location = GPU_shader_get_uniform(shader, "active_color");
- int stepsize_location = GPU_shader_get_uniform(shader, "step_size");
- int densityscale_location = GPU_shader_get_uniform(shader, "density_scale");
- int invsize_location = GPU_shader_get_uniform(shader, "invsize");
- int ob_sizei_location = GPU_shader_get_uniform(shader, "ob_sizei");
- int min_location = GPU_shader_get_uniform(shader, "min_location");
-
- GPU_shader_bind(shader);
-
- GPU_texture_bind(sds->tex, 0);
- GPU_shader_uniform_texture(shader, soot_location, sds->tex);
-
- GPU_texture_bind(sds->tex_shadow, 1);
- GPU_shader_uniform_texture(shader, shadow_location, sds->tex_shadow);
+ /* setup slicing information */
- GPUTexture *tex_spec = NULL;
+ const bool view_aligned = (sds->slice_method == MOD_SMOKE_SLICE_VIEW_ALIGNED);
+ int max_slices, max_points, axis = 0;
- if (use_fire) {
- GPU_texture_bind(sds->tex_flame, 2);
- GPU_shader_uniform_texture(shader, flame_location, sds->tex_flame);
-
- tex_spec = create_flame_spectrum_texture();
- GPU_texture_bind(tex_spec, 3);
- GPU_shader_uniform_texture(shader, spec_location, tex_spec);
+ if (view_aligned) {
+ max_slices = max_iii(sds->res[0], sds->res[1], sds->res[2]) * sds->slice_per_voxel;
+ max_points = max_slices * 12;
}
+ else {
+ if (sds->axis_slice_method == AXIS_SLICE_FULL) {
+ axis = axis_dominant_v3_single(viewnormal);
+ max_slices = sds->res[axis] * sds->slice_per_voxel;
+ }
+ else {
+ axis = (sds->slice_axis == SLICE_AXIS_AUTO) ? axis_dominant_v3_single(viewnormal) : sds->slice_axis - 1;
+ max_slices = 1;
+ }
- float active_color[3] = { 0.9, 0.9, 0.9 };
- float density_scale = 10.0f;
- if ((sds->active_fields & SM_ACTIVE_COLORS) == 0)
- mul_v3_v3(active_color, sds->active_color);
-
- GPU_shader_uniform_vector(shader, actcol_location, 3, 1, active_color);
- GPU_shader_uniform_vector(shader, stepsize_location, 1, 1, &sds->dx);
- GPU_shader_uniform_vector(shader, densityscale_location, 1, 1, &density_scale);
- GPU_shader_uniform_vector(shader, min_location, 3, 1, min);
- GPU_shader_uniform_vector(shader, ob_sizei_location, 3, 1, ob_sizei);
- GPU_shader_uniform_vector(shader, invsize_location, 3, 1, invsize);
-
- /* setup slicing information */
-
- const int max_slices = 256;
- const int max_points = max_slices * 12;
+ max_points = max_slices * 6;
+ }
VolumeSlicer slicer;
copy_v3_v3(slicer.min, min);
@@ -375,52 +517,51 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
copy_v3_v3(slicer.size, size);
slicer.verts = MEM_mallocN(sizeof(float) * 3 * max_points, "smoke_slice_vertices");
- const int num_points = create_view_aligned_slices(&slicer, max_slices, viewnormal);
+ int num_points;
+
+ if (view_aligned) {
+ num_points = create_view_aligned_slices(&slicer, max_slices, viewnormal);
+ }
+ else {
+ num_points = max_points;
+
+ if (sds->axis_slice_method == AXIS_SLICE_FULL) {
+ create_axis_aligned_slices(&slicer, max_slices, viewnormal, axis);
+ }
+ else {
+ const float depth = (sds->slice_depth - 0.5f) * size[axis];
+ create_single_slice(&slicer, depth, axis, 0);
+ }
+ }
/* setup buffer and draw */
- int gl_depth = 0, gl_blend = 0;
+ int gl_depth = 0, gl_blend = 0, gl_depth_write = 0;
glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend);
glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth);
+ glGetBooleanv(GL_DEPTH_WRITEMASK, (GLboolean *)&gl_depth_write);
glEnable(GL_DEPTH_TEST);
+ glDepthMask(GL_FALSE);
glEnable(GL_BLEND);
- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
-
- GLuint vertex_buffer;
- glGenBuffers(1, &vertex_buffer);
- glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
- glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * num_points, &slicer.verts[0][0], GL_STATIC_DRAW);
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(3, GL_FLOAT, 0, NULL);
-
- glDrawArrays(GL_TRIANGLES, 0, num_points);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ draw_buffer(sds, shader, &slicer, ob_sizei, invsize, num_points, false);
- glDisableClientState(GL_VERTEX_ARRAY);
+ /* Draw fire separately (T47639). */
+ if (use_fire) {
+ glBlendFunc(GL_ONE, GL_ONE);
+ draw_buffer(sds, fire_shader, &slicer, ob_sizei, invsize, num_points, true);
+ }
#ifdef DEBUG_DRAW_TIME
printf("Draw Time: %f\n", (float)TIMEIT_VALUE(draw));
TIMEIT_END(draw);
#endif
- /* cleanup */
-
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glDeleteBuffers(1, &vertex_buffer);
-
- GPU_texture_unbind(sds->tex);
- GPU_texture_unbind(sds->tex_shadow);
-
- if (use_fire) {
- GPU_texture_unbind(sds->tex_flame);
- GPU_texture_unbind(tex_spec);
- GPU_texture_free(tex_spec);
- }
-
MEM_freeN(slicer.verts);
- GPU_shader_unbind();
+ glDepthMask(gl_depth_write);
if (!gl_blend) {
glDisable(GL_BLEND);
@@ -431,61 +572,193 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
}
}
-#ifdef SMOKE_DEBUG_VELOCITY
-void draw_smoke_velocity(SmokeDomainSettings *domain, Object *ob)
+#ifdef WITH_SMOKE
+static void add_tri(float (*verts)[3], float(*colors)[3], int *offset,
+ float p1[3], float p2[3], float p3[3], float rgb[3])
{
- float x, y, z;
- float x0, y0, z0;
- int *base_res = domain->base_res;
- int *res = domain->res;
- int *res_min = domain->res_min;
- int *res_max = domain->res_max;
- float *vel_x = smoke_get_velocity_x(domain->fluid);
- float *vel_y = smoke_get_velocity_y(domain->fluid);
- float *vel_z = smoke_get_velocity_z(domain->fluid);
+ copy_v3_v3(verts[*offset + 0], p1);
+ copy_v3_v3(verts[*offset + 1], p2);
+ copy_v3_v3(verts[*offset + 2], p3);
- float min[3];
- float *cell_size = domain->cell_size;
- float step_size = ((float)max_iii(base_res[0], base_res[1], base_res[2])) / 16.f;
- float vf = domain->scale / 16.f * 2.f; /* velocity factor */
+ copy_v3_v3(colors[*offset + 0], rgb);
+ copy_v3_v3(colors[*offset + 1], rgb);
+ copy_v3_v3(colors[*offset + 2], rgb);
- glLineWidth(1.0f);
+ *offset += 3;
+}
+
+static void add_needle(float (*verts)[3], float (*colors)[3], float center[3],
+ float dir[3], float scale, float voxel_size, int *offset)
+{
+ float len = len_v3(dir);
+
+ float rgb[3];
+ weight_to_rgb(rgb, len);
+
+ if (len != 0.0f) {
+ mul_v3_fl(dir, 1.0f / len);
+ len *= scale;
+ }
+
+ len *= voxel_size;
+
+ float corners[4][3] = {
+ { 0.0f, 0.2f, -0.5f },
+ { -0.2f * 0.866f, -0.2f * 0.5f, -0.5f },
+ { 0.2f * 0.866f, -0.2f * 0.5f, -0.5f },
+ { 0.0f, 0.0f, 0.5f }
+ };
+
+ const float up[3] = { 0.0f, 0.0f, 1.0f };
+ float rot[3][3];
+
+ rotation_between_vecs_to_mat3(rot, up, dir);
+ transpose_m3(rot);
+
+ for (int i = 0; i < 4; i++) {
+ mul_m3_v3(rot, corners[i]);
+ mul_v3_fl(corners[i], len);
+ add_v3_v3(corners[i], center);
+ }
+
+ add_tri(verts, colors, offset, corners[0], corners[1], corners[2], rgb);
+ add_tri(verts, colors, offset, corners[0], corners[1], corners[3], rgb);
+ add_tri(verts, colors, offset, corners[1], corners[2], corners[3], rgb);
+ add_tri(verts, colors, offset, corners[2], corners[0], corners[3], rgb);
+}
+
+static void add_streamline(float (*verts)[3], float(*colors)[3], float center[3],
+ float dir[3], float scale, float voxel_size, int *offset)
+{
+ const float len = len_v3(dir);
+
+ float rgb[3];
+ weight_to_rgb(rgb, len);
+
+ copy_v3_v3(colors[(*offset)], rgb);
+ copy_v3_v3(verts[(*offset)++], center);
+
+ mul_v3_fl(dir, scale * voxel_size);
+ add_v3_v3(center, dir);
+
+ copy_v3_v3(colors[(*offset)], rgb);
+ copy_v3_v3(verts[(*offset)++], center);
+}
+
+typedef void (*vector_draw_func)(float(*)[3], float(*)[3], float*, float*, float, float, int*);
+#endif /* WITH_SMOKE */
+
+void draw_smoke_velocity(SmokeDomainSettings *domain, float viewnormal[3])
+{
+#ifdef WITH_SMOKE
+ const float *vel_x = smoke_get_velocity_x(domain->fluid);
+ const float *vel_y = smoke_get_velocity_y(domain->fluid);
+ const float *vel_z = smoke_get_velocity_z(domain->fluid);
+
+ if (ELEM(NULL, vel_x, vel_y, vel_z)) {
+ return;
+ }
+
+ const int *base_res = domain->base_res;
+ const int *res = domain->res;
+ const int *res_min = domain->res_min;
+
+ int res_max[3];
+ copy_v3_v3_int(res_max, domain->res_max);
+
+ const float *cell_size = domain->cell_size;
+ const float step_size = ((float)max_iii(base_res[0], base_res[1], base_res[2])) / 16.0f;
/* set first position so that it doesn't jump when domain moves */
- x0 = res_min[0] + fmod(-(float)domain->shift[0] + res_min[0], step_size);
- y0 = res_min[1] + fmod(-(float)domain->shift[1] + res_min[1], step_size);
- z0 = res_min[2] + fmod(-(float)domain->shift[2] + res_min[2], step_size);
- if (x0 < res_min[0]) x0 += step_size;
- if (y0 < res_min[1]) y0 += step_size;
- if (z0 < res_min[2]) z0 += step_size;
- add_v3_v3v3(min, domain->p0, domain->obj_shift_f);
+ float xyz[3] = {
+ res_min[0] + fmod(-(float)domain->shift[0] + res_min[0], step_size),
+ res_min[1] + fmod(-(float)domain->shift[1] + res_min[1], step_size),
+ res_min[2] + fmod(-(float)domain->shift[2] + res_min[2], step_size)
+ };
- for (x = floor(x0); x < res_max[0]; x += step_size)
- for (y = floor(y0); y < res_max[1]; y += step_size)
- for (z = floor(z0); z < res_max[2]; z += step_size) {
+ if (xyz[0] < res_min[0]) xyz[0] += step_size;
+ if (xyz[1] < res_min[1]) xyz[1] += step_size;
+ if (xyz[2] < res_min[2]) xyz[2] += step_size;
+
+ float min[3] = {
+ domain->p0[0] - domain->cell_size[0] * domain->adapt_res,
+ domain->p0[1] - domain->cell_size[1] * domain->adapt_res,
+ domain->p0[2] - domain->cell_size[2] * domain->adapt_res,
+ };
+
+ int num_points_v[3] = {
+ ((float)(res_max[0] - floor(xyz[0])) / step_size) + 0.5f,
+ ((float)(res_max[1] - floor(xyz[1])) / step_size) + 0.5f,
+ ((float)(res_max[2] - floor(xyz[2])) / step_size) + 0.5f
+ };
+
+ if (domain->slice_method == MOD_SMOKE_SLICE_AXIS_ALIGNED &&
+ domain->axis_slice_method == AXIS_SLICE_SINGLE)
+ {
+ const int axis = (domain->slice_axis == SLICE_AXIS_AUTO) ?
+ axis_dominant_v3_single(viewnormal) : domain->slice_axis - 1;
+
+ xyz[axis] = (float)base_res[axis] * domain->slice_depth;
+ num_points_v[axis] = 1;
+ res_max[axis] = xyz[axis] + 1;
+ }
+
+ vector_draw_func func;
+ int max_points;
+
+ if (domain->vector_draw_type == VECTOR_DRAW_NEEDLE) {
+ func = add_needle;
+ max_points = (num_points_v[0] * num_points_v[1] * num_points_v[2]) * 4 * 3;
+ }
+ else {
+ func = add_streamline;
+ max_points = (num_points_v[0] * num_points_v[1] * num_points_v[2]) * 2;
+ }
+
+ float (*verts)[3] = MEM_mallocN(sizeof(float) * 3 * max_points, "");
+ float (*colors)[3] = MEM_mallocN(sizeof(float) * 3 * max_points, "");
+
+ int num_points = 0;
+
+ for (float x = floor(xyz[0]); x < res_max[0]; x += step_size) {
+ for (float y = floor(xyz[1]); y < res_max[1]; y += step_size) {
+ for (float z = floor(xyz[2]); z < res_max[2]; z += step_size) {
int index = (floor(x) - res_min[0]) + (floor(y) - res_min[1]) * res[0] + (floor(z) - res_min[2]) * res[0] * res[1];
- float pos[3] = {min[0] + ((float)x + 0.5f) * cell_size[0], min[1] + ((float)y + 0.5f) * cell_size[1], min[2] + ((float)z + 0.5f) * cell_size[2]};
- float vel = sqrtf(vel_x[index] * vel_x[index] + vel_y[index] * vel_y[index] + vel_z[index] * vel_z[index]);
+ float pos[3] = {
+ min[0] + ((float)x + 0.5f) * cell_size[0],
+ min[1] + ((float)y + 0.5f) * cell_size[1],
+ min[2] + ((float)z + 0.5f) * cell_size[2]
+ };
- /* draw heat as scaled "arrows" */
- if (vel >= 0.01f) {
- float col_g = 1.0f - vel;
- CLAMP(col_g, 0.0f, 1.0f);
- glColor3f(1.0f, col_g, 0.0f);
- glPointSize(10.0f * vel);
+ float vel[3] = {
+ vel_x[index], vel_y[index], vel_z[index]
+ };
- glBegin(GL_LINES);
- glVertex3f(pos[0], pos[1], pos[2]);
- glVertex3f(pos[0] + vel_x[index] * vf, pos[1] + vel_y[index] * vf, pos[2] + vel_z[index] * vf);
- glEnd();
- glBegin(GL_POINTS);
- glVertex3f(pos[0] + vel_x[index] * vf, pos[1] + vel_y[index] * vf, pos[2] + vel_z[index] * vf);
- glEnd();
- }
+ func(verts, colors, pos, vel, domain->vector_scale, cell_size[0], &num_points);
}
-}
+ }
+ }
+
+ glLineWidth(1.0f);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(3, GL_FLOAT, 0, verts);
+
+ glEnableClientState(GL_COLOR_ARRAY);
+ glColorPointer(3, GL_FLOAT, 0, colors);
+
+ glDrawArrays(GL_LINES, 0, num_points);
+
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+
+ MEM_freeN(verts);
+ MEM_freeN(colors);
+#else
+ UNUSED_VARS(domain, viewnormal);
#endif
+}
#ifdef SMOKE_DEBUG_HEAT
void draw_smoke_heat(SmokeDomainSettings *domain, Object *ob)
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index fa14ca96fe2..075b1faf502 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -1400,6 +1400,68 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes
return -1; /* found but not available */
}
+static void view3d_id_remap(ScrArea *sa, SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ View3D *v3d;
+ ARegion *ar;
+ bool is_local = false;
+
+ if (!ELEM(GS(old_id->name), ID_OB, ID_MA, ID_IM, ID_MC)) {
+ return;
+ }
+
+ for (v3d = (View3D *)slink; v3d; v3d = v3d->localvd, is_local = true) {
+ if ((ID *)v3d->camera == old_id) {
+ v3d->camera = (Object *)new_id;
+ if (!new_id) {
+ /* 3D view might be inactive, in that case needs to use slink->regionbase */
+ ListBase *regionbase = (slink == sa->spacedata.first) ? &sa->regionbase : &slink->regionbase;
+ for (ar = regionbase->first; ar; ar = ar->next) {
+ if (ar->regiontype == RGN_TYPE_WINDOW) {
+ RegionView3D *rv3d = is_local ? ((RegionView3D *)ar->regiondata)->localvd : ar->regiondata;
+ if (rv3d && (rv3d->persp == RV3D_CAMOB)) {
+ rv3d->persp = RV3D_PERSP;
+ }
+ }
+ }
+ }
+ }
+ if ((ID *)v3d->ob_centre == old_id) {
+ v3d->ob_centre = (Object *)new_id;
+ if (new_id == NULL) { /* Otherwise, bonename may remain valid... We could be smart and check this, too? */
+ v3d->ob_centre_bone[0] = '\0';
+ }
+ }
+
+ if ((ID *)v3d->defmaterial == old_id) {
+ v3d->defmaterial = (Material *)new_id;
+ }
+#if 0 /* XXX Deprecated? */
+ if ((ID *)v3d->gpd == old_id) {
+ v3d->gpd = (bGPData *)new_id;
+ }
+#endif
+
+ if (ELEM(GS(old_id->name), ID_IM, ID_MC)) {
+ for (BGpic *bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
+ if ((ID *)bgpic->ima == old_id) {
+ bgpic->ima = (Image *)new_id;
+ id_us_min(old_id);
+ id_us_plus(new_id);
+ }
+ if ((ID *)bgpic->clip == old_id) {
+ bgpic->clip = (MovieClip *)new_id;
+ id_us_min(old_id);
+ id_us_plus(new_id);
+ }
+ }
+ }
+
+ if (is_local) {
+ break;
+ }
+ }
+}
/* only called once, from space/spacetypes.c */
void ED_spacetype_view3d(void)
@@ -1419,7 +1481,8 @@ void ED_spacetype_view3d(void)
st->keymap = view3d_keymap;
st->dropboxes = view3d_dropboxes;
st->context = view3d_context;
-
+ st->id_remap = view3d_id_remap;
+
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype view3d main region");
art->regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c
index c52d1238163..b9c8c98b62f 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -1206,7 +1206,7 @@ static int view3d_properties_toggle_exec(bContext *C, wmOperator *UNUSED(op))
void VIEW3D_OT_properties(wmOperatorType *ot)
{
ot->name = "Properties";
- ot->description = "Toggles the properties panel display";
+ ot->description = "Toggle the properties region visibility";
ot->idname = "VIEW3D_OT_properties";
ot->exec = view3d_properties_toggle_exec;
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 184b9ff5b15..000d1fe4810 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -645,6 +645,7 @@ static void draw_view_axis(RegionView3D *rv3d, rcti *rect)
glDisable(GL_BLEND);
}
+#ifdef WITH_INPUT_NDOF
/* draw center and axis of rotation for ongoing 3D mouse navigation */
static void draw_rotation_guide(RegionView3D *rv3d)
{
@@ -657,7 +658,6 @@ static void draw_rotation_guide(RegionView3D *rv3d)
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glShadeModel(GL_SMOOTH);
glPointSize(5);
glEnable(GL_POINT_SMOOTH);
glDepthMask(0); /* don't overwrite zbuf */
@@ -750,6 +750,7 @@ static void draw_rotation_guide(RegionView3D *rv3d)
glDisable(GL_POINT_SMOOTH);
glDepthMask(1);
}
+#endif /* WITH_INPUT_NDOF */
static void draw_view_icon(RegionView3D *rv3d, rcti *rect)
{
@@ -950,9 +951,11 @@ static void draw_selected_name(Scene *scene, Object *ob, rcti *rect)
UI_ThemeColor(TH_TEXT_HI);
}
else {
- /* no object */
- /* color is always white */
- UI_ThemeColor(TH_TEXT_HI);
+ /* no object */
+ if (ED_gpencil_has_keyframe_v3d(scene, NULL, cfra))
+ UI_ThemeColor(TH_TIME_GP_KEYFRAME);
+ else
+ UI_ThemeColor(TH_TEXT_HI);
}
if (markern) {
@@ -1179,10 +1182,10 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
if (scene->r.mode & R_BORDER) {
float x3, y3, x4, y4;
- x3 = x1i + 1 + roundf(scene->r.border.xmin * (x2 - x1));
- y3 = y1i + 1 + roundf(scene->r.border.ymin * (y2 - y1));
- x4 = x1i + 1 + roundf(scene->r.border.xmax * (x2 - x1));
- y4 = y1i + 1 + roundf(scene->r.border.ymax * (y2 - y1));
+ x3 = floorf(x1 + (scene->r.border.xmin * (x2 - x1))) - 1;
+ y3 = floorf(y1 + (scene->r.border.ymin * (y2 - y1))) - 1;
+ x4 = floorf(x1 + (scene->r.border.xmax * (x2 - x1))) + (U.pixelsize - 1);
+ y4 = floorf(y1 + (scene->r.border.ymax * (y2 - y1))) + (U.pixelsize - 1);
cpack(0x4040FF);
sdrawbox(x3, y3, x4, y4);
@@ -1489,7 +1492,7 @@ unsigned int ED_view3d_backbuf_sample(ViewContext *vc, int x, int y)
BLI_endian_switch_uint32(&col);
}
- return WM_framebuffer_to_index(col);
+ return GPU_select_to_index(col);
}
/* reads full rect, converts indices */
@@ -1522,7 +1525,7 @@ ImBuf *ED_view3d_backbuf_read(ViewContext *vc, int xmin, int ymin, int xmax, int
IMB_convert_rgba_to_abgr(ibuf_clip);
}
- WM_framebuffer_to_index_array(ibuf_clip->rect, size_clip[0] * size_clip[1]);
+ GPU_select_to_index_array(ibuf_clip->rect, size_clip[0] * size_clip[1]);
if ((clip.xmin == xmin) &&
(clip.xmax == xmax) &&
@@ -2600,6 +2603,7 @@ static void gpu_update_lamps_shadows_world(Scene *scene, View3D *v3d)
GPU_mist_update_values(world->mistype, world->miststa, world->mistdist, world->misi, &world->horr);
GPU_horizon_update_color(&world->horr);
GPU_ambient_update_color(&world->ambr);
+ GPU_zenith_update_color(&world->zenr);
}
}
@@ -2608,19 +2612,20 @@ static void gpu_update_lamps_shadows_world(Scene *scene, View3D *v3d)
CustomDataMask ED_view3d_datamask(const Scene *scene, const View3D *v3d)
{
CustomDataMask mask = 0;
+ const int drawtype = view3d_effective_drawtype(v3d);
- if (ELEM(v3d->drawtype, OB_TEXTURE, OB_MATERIAL) ||
- ((v3d->drawtype == OB_SOLID) && (v3d->flag2 & V3D_SOLID_TEX)))
+ if (ELEM(drawtype, OB_TEXTURE, OB_MATERIAL) ||
+ ((drawtype == OB_SOLID) && (v3d->flag2 & V3D_SOLID_TEX)))
{
mask |= CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL;
if (BKE_scene_use_new_shading_nodes(scene)) {
- if (v3d->drawtype == OB_MATERIAL)
+ if (drawtype == OB_MATERIAL)
mask |= CD_MASK_ORCO;
}
else {
- if ((scene->gm.matmode == GAME_MAT_GLSL && v3d->drawtype == OB_TEXTURE) ||
- (v3d->drawtype == OB_MATERIAL))
+ if ((scene->gm.matmode == GAME_MAT_GLSL && drawtype == OB_TEXTURE) ||
+ (drawtype == OB_MATERIAL))
{
mask |= CD_MASK_ORCO;
}
@@ -2979,174 +2984,45 @@ void ED_view3d_draw_offscreen_init(Scene *scene, View3D *v3d)
static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar)
{
if (scene->world && (v3d->flag3 & V3D_SHOW_WORLD)) {
- bool glsl = GPU_glsl_support();
- if (glsl) {
- RegionView3D *rv3d = ar->regiondata;
- GPUMaterial *gpumat = GPU_material_world(scene, scene->world);
-
- /* calculate full shader for background */
- GPU_material_bind(gpumat, 1, 1, 1.0, false, rv3d->viewmat, rv3d->viewinv, rv3d->viewcamtexcofac, (v3d->scenelock != 0));
-
- bool material_not_bound = !GPU_material_bound(gpumat);
-
- if (material_not_bound) {
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
- glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
- }
+ RegionView3D *rv3d = ar->regiondata;
+ GPUMaterial *gpumat = GPU_material_world(scene, scene->world);
- glEnable(GL_DEPTH_TEST);
- glDepthFunc(GL_ALWAYS);
- glShadeModel(GL_SMOOTH);
- glBegin(GL_TRIANGLE_STRIP);
- glVertex3f(-1.0, -1.0, 1.0);
- glVertex3f(1.0, -1.0, 1.0);
- glVertex3f(-1.0, 1.0, 1.0);
- glVertex3f(1.0, 1.0, 1.0);
- glEnd();
- glShadeModel(GL_FLAT);
-
- if (material_not_bound) {
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
- }
-
- GPU_material_unbind(gpumat);
-
- glDepthFunc(GL_LEQUAL);
- glDisable(GL_DEPTH_TEST);
- }
- else if (scene->world->skytype & WO_SKYBLEND) { /* blend sky */
- int x, y;
- float col_hor[3];
- float col_zen[3];
-
-#define VIEWGRAD_RES_X 16
-#define VIEWGRAD_RES_Y 16
-
- GLubyte grid_col[VIEWGRAD_RES_X][VIEWGRAD_RES_Y][4];
- static float grid_pos[VIEWGRAD_RES_X][VIEWGRAD_RES_Y][3];
- static GLushort indices[VIEWGRAD_RES_X - 1][VIEWGRAD_RES_X - 1][4];
- static bool buf_calculated = false;
-
- IMB_colormanagement_pixel_to_display_space_v3(col_hor, &scene->world->horr, &scene->view_settings,
- &scene->display_settings);
- IMB_colormanagement_pixel_to_display_space_v3(col_zen, &scene->world->zenr, &scene->view_settings,
- &scene->display_settings);
+ /* calculate full shader for background */
+ GPU_material_bind(gpumat, 1, 1, 1.0, false, rv3d->viewmat, rv3d->viewinv, rv3d->viewcamtexcofac, (v3d->scenelock != 0));
+
+ bool material_not_bound = !GPU_material_bound(gpumat);
+ if (material_not_bound) {
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
+ glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
+ }
- glShadeModel(GL_SMOOTH);
-
- /* calculate buffers the first time only */
- if (!buf_calculated) {
- for (x = 0; x < VIEWGRAD_RES_X; x++) {
- for (y = 0; y < VIEWGRAD_RES_Y; y++) {
- const float xf = (float)x / (float)(VIEWGRAD_RES_X - 1);
- const float yf = (float)y / (float)(VIEWGRAD_RES_Y - 1);
-
- /* -1..1 range */
- grid_pos[x][y][0] = (xf - 0.5f) * 2.0f;
- grid_pos[x][y][1] = (yf - 0.5f) * 2.0f;
- grid_pos[x][y][2] = 1.0;
- }
- }
-
- for (x = 0; x < VIEWGRAD_RES_X - 1; x++) {
- for (y = 0; y < VIEWGRAD_RES_Y - 1; y++) {
- indices[x][y][0] = x * VIEWGRAD_RES_X + y;
- indices[x][y][1] = x * VIEWGRAD_RES_X + y + 1;
- indices[x][y][2] = (x + 1) * VIEWGRAD_RES_X + y + 1;
- indices[x][y][3] = (x + 1) * VIEWGRAD_RES_X + y;
- }
- }
-
- buf_calculated = true;
- }
-
- for (x = 0; x < VIEWGRAD_RES_X; x++) {
- for (y = 0; y < VIEWGRAD_RES_Y; y++) {
- const float xf = (float)x / (float)(VIEWGRAD_RES_X - 1);
- const float yf = (float)y / (float)(VIEWGRAD_RES_Y - 1);
- const float mval[2] = {xf * (float)ar->winx, yf * ar->winy};
- const float z_up[3] = {0.0f, 0.0f, 1.0f};
- float out[3];
- GLubyte *col_ub = grid_col[x][y];
-
- float col_fac;
- float col_fl[3];
-
- ED_view3d_win_to_vector(ar, mval, out);
-
- if (scene->world->skytype & WO_SKYPAPER) {
- if (scene->world->skytype & WO_SKYREAL) {
- col_fac = fabsf(((float)y / (float)VIEWGRAD_RES_Y) - 0.5f) * 2.0f;
- }
- else {
- col_fac = (float)y / (float)VIEWGRAD_RES_Y;
- }
- }
- else {
- if (scene->world->skytype & WO_SKYREAL) {
- col_fac = fabsf((angle_normalized_v3v3(z_up, out) / (float)M_PI) - 0.5f) * 2.0f;
- }
- else {
- col_fac = 1.0f - (angle_normalized_v3v3(z_up, out) / (float)M_PI);
- }
- }
-
- interp_v3_v3v3(col_fl, col_hor, col_zen, col_fac);
-
- rgb_float_to_uchar(col_ub, col_fl);
- col_ub[3] = 255;
- }
- }
-
- glEnable(GL_DEPTH_TEST);
- glDepthFunc(GL_ALWAYS);
-
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_COLOR_ARRAY);
- glVertexPointer(3, GL_FLOAT, 0, grid_pos);
- glColorPointer(4, GL_UNSIGNED_BYTE, 0, grid_col);
-
- glDrawElements(GL_QUADS, (VIEWGRAD_RES_X - 1) * (VIEWGRAD_RES_Y - 1) * 4, GL_UNSIGNED_SHORT, indices);
-
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_COLOR_ARRAY);
-
- glDepthFunc(GL_LEQUAL);
- glDisable(GL_DEPTH_TEST);
+ /* Draw world */
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_ALWAYS);
+ glBegin(GL_TRIANGLE_STRIP);
+ glVertex3f(-1.0, -1.0, 1.0);
+ glVertex3f(1.0, -1.0, 1.0);
+ glVertex3f(-1.0, 1.0, 1.0);
+ glVertex3f(1.0, 1.0, 1.0);
+ glEnd();
+ if (material_not_bound) {
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
-
- glShadeModel(GL_FLAT);
-
-#undef VIEWGRAD_RES_X
-#undef VIEWGRAD_RES_Y
}
- else { /* solid sky */
- float col_hor[3];
- IMB_colormanagement_pixel_to_display_space_v3(col_hor, &scene->world->horr, &scene->view_settings,
- &scene->display_settings);
- glClearColor(col_hor[0], col_hor[1], col_hor[2], 1.0);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- }
+ GPU_material_unbind(gpumat);
+
+ glDepthFunc(GL_LEQUAL);
+ glDisable(GL_DEPTH_TEST);
}
else {
if (UI_GetThemeValue(TH_SHOW_BACK_GRAD)) {
@@ -3159,7 +3035,6 @@ static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar)
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_ALWAYS);
- glShadeModel(GL_SMOOTH);
glBegin(GL_QUADS);
UI_ThemeColor(TH_LOW_GRAD);
glVertex3f(-1.0, -1.0, 1.0);
@@ -3168,8 +3043,6 @@ static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar)
glVertex3f(1.0, 1.0, 1.0);
glVertex3f(-1.0, 1.0, 1.0);
glEnd();
- glShadeModel(GL_FLAT);
-
glDepthFunc(GL_LEQUAL);
glDisable(GL_DEPTH_TEST);
@@ -3925,10 +3798,11 @@ static void view3d_main_region_draw_objects(const bContext *C, Scene *scene, Vie
BDR_drawSketch(C);
}
+#ifdef WITH_INPUT_NDOF
if ((U.ndof_flag & NDOF_SHOW_GUIDE) && ((rv3d->viewlock & RV3D_LOCKED) == 0) && (rv3d->persp != RV3D_CAMOB))
/* TODO: draw something else (but not this) during fly mode */
draw_rotation_guide(rv3d);
-
+#endif
}
static bool is_cursor_visible(Scene *scene)
@@ -4070,6 +3944,10 @@ void view3d_main_region_draw(const bContext *C, ARegion *ar)
view3d_main_region_draw_info(C, scene, ar, v3d, grid_unit, render_border);
v3d->flag |= V3D_INVALID_BACKBUF;
+
+ BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_transp));
+ BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_xray));
+ BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_xraytransp));
}
#ifdef DEBUG_DRAW
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index c7a10d65071..9e41ad6a8f6 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -41,6 +41,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_bitmap_draw_2d.h"
#include "BLI_blenlib.h"
#include "BLI_kdopbvh.h"
#include "BLI_math.h"
@@ -110,7 +111,7 @@ static bool view3d_operator_offset_lock_check(bContext *C, wmOperator *op)
bool ED_view3d_camera_lock_check(const View3D *v3d, const RegionView3D *rv3d)
{
return ((v3d->camera) &&
- (v3d->camera->id.lib == NULL) &&
+ (!ID_IS_LINKED_DATABLOCK(v3d->camera)) &&
(v3d->flag2 & V3D_LOCK_CAMERA) &&
(rv3d->persp == RV3D_CAMOB));
}
@@ -1329,6 +1330,8 @@ void VIEW3D_OT_rotate(wmOperatorType *ot)
ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
}
+#ifdef WITH_INPUT_NDOF
+
/** \name NDOF Utility Functions
* \{ */
@@ -1894,6 +1897,8 @@ void VIEW3D_OT_ndof_all(struct wmOperatorType *ot)
ot->flag = 0;
}
+#endif /* WITH_INPUT_NDOF */
+
/* ************************ viewmove ******************************** */
@@ -3079,7 +3084,9 @@ static int viewselected_exec(bContext *C, wmOperator *op)
else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) {
ok = PE_minmax(scene, min, max);
}
- else if (ob && (ob->mode & (OB_MODE_SCULPT | OB_MODE_TEXTURE_PAINT))) {
+ else if (ob &&
+ (ob->mode & (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)))
+ {
BKE_paint_stroke_get_average(scene, ob, min);
copy_v3_v3(max, min);
ok = true;
@@ -3434,12 +3441,8 @@ static int render_border_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
}
- /* drawing a border surrounding the entire camera view switches off border rendering
- * or the border covers no pixels */
- if ((border.xmin <= 0.0f && border.xmax >= 1.0f &&
- border.ymin <= 0.0f && border.ymax >= 1.0f) ||
- (border.xmin == border.xmax || border.ymin == border.ymax))
- {
+ /* drawing a border outside the camera view switches off border rendering */
+ if ((border.xmin == border.xmax || border.ymin == border.ymax)) {
if (rv3d->persp == RV3D_CAMOB)
scene->r.mode &= ~R_BORDER;
else
@@ -3620,7 +3623,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
dist_range[0] = v3d->near * 1.5f;
}
else { /* othographic */
- /* find the current window width and height */
+ /* find the current window width and height */
vb[0] = ar->winx;
vb[1] = ar->winy;
@@ -4520,7 +4523,7 @@ void VIEW3D_OT_background_image_add(wmOperatorType *ot)
/* 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->description = "Add a new background image (Ctrl for Empty Object)";
ot->idname = "VIEW3D_OT_background_image_add";
/* api callbacks */
@@ -4529,7 +4532,7 @@ void VIEW3D_OT_background_image_add(wmOperatorType *ot)
ot->poll = ED_operator_view3d_active;
/* flags */
- ot->flag = 0;
+ ot->flag = OPTYPE_UNDO;
/* properties */
RNA_def_string(ot->srna, "name", "Image", MAX_ID_NAME - 2, "Name", "Image name to assign");
@@ -4848,6 +4851,35 @@ void VIEW3D_OT_enable_manipulator(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+/* ************************* Toggle rendered shading *********************** */
+
+static int toggle_render_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d->drawtype == OB_RENDER) {
+ v3d->drawtype = v3d->prev_drawtype;
+ }
+ else {
+ v3d->prev_drawtype = v3d->drawtype;
+ v3d->drawtype = OB_RENDER;
+ }
+ ED_view3d_shade_update(CTX_data_main(C), CTX_data_scene(C), v3d, CTX_wm_area(C));
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
+ return OPERATOR_FINISHED;
+}
+
+void VIEW3D_OT_toggle_render(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Toggle Rendered Shading";
+ ot->description = "Toggle rendered shading mode of the viewport";
+ ot->idname = "VIEW3D_OT_toggle_render";
+
+ /* api callbacks */
+ ot->exec = toggle_render_exec;
+ ot->poll = ED_operator_view3d_active;
+}
+
/* ************************* below the line! *********************** */
@@ -4882,7 +4914,7 @@ static float view_autodist_depth_margin(ARegion *ar, const int mval[2], int marg
* Get the world-space 3d location from a screen-space 2d point.
*
* \param mval: Input screen-space pixel location.
- * \param mouse_worldloc: Output world-space loction.
+ * \param mouse_worldloc: Output world-space location.
* \param fallback_depth_pt: Use this points depth when no depth can be found.
*/
bool ED_view3d_autodist(
@@ -5021,7 +5053,7 @@ bool ED_view3d_autodist_depth_seg(ARegion *ar, const int mval_sta[2], const int
copy_v2_v2_int(p1, mval_sta);
copy_v2_v2_int(p2, mval_end);
- plot_line_v2v2i(p1, p2, depth_segment_cb, &data);
+ BLI_bitmap_draw_2d_line_v2v2i(p1, p2, depth_segment_cb, &data);
*depth = data.depth;
diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c
index 8418cf0980c..04a6aa215f4 100644
--- a/source/blender/editors/space_view3d/view3d_fly.c
+++ b/source/blender/editors/space_view3d/view3d_fly.c
@@ -26,8 +26,10 @@
/* defines VIEW3D_OT_fly modal operator */
-//#define NDOF_FLY_DEBUG
-//#define NDOF_FLY_DRAW_TOOMUCH /* is this needed for ndof? - commented so redraw doesnt thrash - campbell */
+#ifdef WITH_INPUT_NDOF
+//# define NDOF_FLY_DEBUG
+//# define NDOF_FLY_DRAW_TOOMUCH /* is this needed for ndof? - commented so redraw doesnt thrash - campbell */
+#endif /* WITH_INPUT_NDOF */
#include "DNA_object_types.h"
@@ -203,7 +205,10 @@ typedef struct FlyInfo {
int mval[2]; /* latest 2D mouse values */
int center_mval[2]; /* center mouse values */
float width, height; /* camera viewport dimensions */
+
+#ifdef WITH_INPUT_NDOF
wmNDOFMotionData *ndof; /* latest 3D mouse values */
+#endif
/* fly state state */
float speed; /* the speed the view is moving per redraw */
@@ -346,7 +351,7 @@ static bool initFlyInfo(bContext *C, FlyInfo *fly, wmOperator *op, const wmEvent
fly->rv3d->persp = RV3D_PERSP;
}
- if (fly->rv3d->persp == RV3D_CAMOB && fly->v3d->camera->id.lib) {
+ if (fly->rv3d->persp == RV3D_CAMOB && ID_IS_LINKED_DATABLOCK(fly->v3d->camera)) {
BKE_report(op->reports, RPT_ERROR, "Cannot fly a camera from an external library");
return false;
}
@@ -381,7 +386,10 @@ static bool initFlyInfo(bContext *C, FlyInfo *fly, wmOperator *op, const wmEvent
fly->timer = WM_event_add_timer(CTX_wm_manager(C), win, TIMER, 0.01f);
copy_v2_v2_int(fly->mval, event->mval);
+
+#ifdef WITH_INPUT_NDOF
fly->ndof = NULL;
+#endif
fly->time_lastdraw = fly->time_lastwheel = PIL_check_seconds_timer();
@@ -449,8 +457,10 @@ static int flyEnd(bContext *C, FlyInfo *fly)
rv3d->rflag &= ~RV3D_NAVIGATING;
+#ifdef WITH_INPUT_NDOF
if (fly->ndof)
MEM_freeN(fly->ndof);
+#endif
if (fly->state == FLY_CONFIRM) {
MEM_freeN(fly);
@@ -469,6 +479,7 @@ static void flyEvent(bContext *C, wmOperator *op, FlyInfo *fly, const wmEvent *e
else if (event->type == MOUSEMOVE) {
copy_v2_v2_int(fly->mval, event->mval);
}
+#ifdef WITH_INPUT_NDOF
else if (event->type == NDOF_MOTION) {
/* do these automagically get delivered? yes. */
// puts("ndof motion detected in fly mode!");
@@ -478,15 +489,15 @@ static void flyEvent(bContext *C, wmOperator *op, FlyInfo *fly, const wmEvent *e
switch (incoming_ndof->progress) {
case P_STARTING:
/* start keeping track of 3D mouse position */
-#ifdef NDOF_FLY_DEBUG
+# ifdef NDOF_FLY_DEBUG
puts("start keeping track of 3D mouse position");
-#endif
+# endif
/* fall-through */
case P_IN_PROGRESS:
/* update 3D mouse position */
-#ifdef NDOF_FLY_DEBUG
+# ifdef NDOF_FLY_DEBUG
putchar('.'); fflush(stdout);
-#endif
+# endif
if (fly->ndof == NULL) {
// fly->ndof = MEM_mallocN(sizeof(wmNDOFMotionData), tag_name);
fly->ndof = MEM_dupallocN(incoming_ndof);
@@ -498,9 +509,9 @@ static void flyEvent(bContext *C, wmOperator *op, FlyInfo *fly, const wmEvent *e
break;
case P_FINISHING:
/* stop keeping track of 3D mouse position */
-#ifdef NDOF_FLY_DEBUG
+# ifdef NDOF_FLY_DEBUG
puts("stop keeping track of 3D mouse position");
-#endif
+# endif
if (fly->ndof) {
MEM_freeN(fly->ndof);
// free(fly->ndof);
@@ -513,6 +524,7 @@ static void flyEvent(bContext *C, wmOperator *op, FlyInfo *fly, const wmEvent *e
break; /* should always be one of the above 3 */
}
}
+#endif /* WITH_INPUT_NDOF */
/* handle modal keymap first */
else if (event->type == EVT_MODAL_MAP) {
switch (event->val) {
@@ -959,6 +971,7 @@ static int flyApply(bContext *C, FlyInfo *fly)
return OPERATOR_FINISHED;
}
+#ifdef WITH_INPUT_NDOF
static void flyApply_ndof(bContext *C, FlyInfo *fly)
{
Object *lock_ob = ED_view3d_cameracontrol_object_get(fly->v3d_camera_control);
@@ -977,6 +990,7 @@ static void flyApply_ndof(bContext *C, FlyInfo *fly)
}
}
}
+#endif /* WITH_INPUT_NDOF */
static int fly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
@@ -1023,12 +1037,15 @@ static int fly_modal(bContext *C, wmOperator *op, const wmEvent *event)
flyEvent(C, op, fly, event);
+#ifdef WITH_INPUT_NDOF
if (fly->ndof) { /* 3D mouse overrules [2D mouse + timer] */
if (event->type == NDOF_MOTION) {
flyApply_ndof(C, fly);
}
}
- else if (event->type == TIMER && event->customdata == fly->timer) {
+ else
+#endif /* WITH_INPUT_NDOF */
+ if (event->type == TIMER && event->customdata == fly->timer) {
flyApply(C, fly);
}
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index 901c5c8d4c2..0e2cb95dd89 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -46,7 +46,6 @@ struct bContext;
struct bMotionPath;
struct bPoseChannel;
struct Mesh;
-struct wmNDOFMotionData;
struct wmOperatorType;
struct wmWindowManager;
struct wmKeyConfig;
@@ -76,10 +75,12 @@ void VIEW3D_OT_dolly(struct wmOperatorType *ot);
void VIEW3D_OT_zoom_camera_1_to_1(struct wmOperatorType *ot);
void VIEW3D_OT_move(struct wmOperatorType *ot);
void VIEW3D_OT_rotate(struct wmOperatorType *ot);
+#ifdef WITH_INPUT_NDOF
void VIEW3D_OT_ndof_orbit(struct wmOperatorType *ot);
void VIEW3D_OT_ndof_orbit_zoom(struct wmOperatorType *ot);
void VIEW3D_OT_ndof_pan(struct wmOperatorType *ot);
void VIEW3D_OT_ndof_all(struct wmOperatorType *ot);
+#endif /* WITH_INPUT_NDOF */
void VIEW3D_OT_view_all(struct wmOperatorType *ot);
void VIEW3D_OT_viewnumpad(struct wmOperatorType *ot);
void VIEW3D_OT_view_selected(struct wmOperatorType *ot);
@@ -103,6 +104,7 @@ void VIEW3D_OT_enable_manipulator(struct wmOperatorType *ot);
void VIEW3D_OT_render_border(struct wmOperatorType *ot);
void VIEW3D_OT_clear_render_border(struct wmOperatorType *ot);
void VIEW3D_OT_zoom_border(struct wmOperatorType *ot);
+void VIEW3D_OT_toggle_render(struct wmOperatorType *ot);
void view3d_boxview_copy(ScrArea *sa, ARegion *ar);
@@ -110,11 +112,15 @@ void view3d_orbit_apply_dyn_ofs(
float r_ofs[3], const float ofs_old[3], const float viewquat_old[4],
const float viewquat_new[4], const float dyn_ofs[3]);
+#ifdef WITH_INPUT_NDOF
+struct wmNDOFMotionData;
+
void view3d_ndof_fly(
const struct wmNDOFMotionData *ndof,
struct View3D *v3d, struct RegionView3D *rv3d,
const bool use_precision, const short protectflag,
bool *r_has_translate, bool *r_has_rotate);
+#endif /* WITH_INPUT_NDOF */
/* view3d_fly.c */
void view3d_keymap(struct wmKeyConfig *keyconf);
@@ -158,6 +164,8 @@ enum {
V3D_CACHE_TEXT_LOCALCLIP = (1 << 4)
};
+int view3d_effective_drawtype(const struct View3D *v3d);
+
/* drawarmature.c */
bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
const short dt, const short dflag, const unsigned char ob_wire_col[4],
@@ -271,6 +279,7 @@ bool ED_view3d_minmax_verts(struct Object *obedit, float min[3], float max[3]);
void VIEW3D_OT_snap_selected_to_grid(struct wmOperatorType *ot);
void VIEW3D_OT_snap_selected_to_cursor(struct wmOperatorType *ot);
+void VIEW3D_OT_snap_selected_to_active(struct wmOperatorType *ot);
void VIEW3D_OT_snap_cursor_to_grid(struct wmOperatorType *ot);
void VIEW3D_OT_snap_cursor_to_center(struct wmOperatorType *ot);
void VIEW3D_OT_snap_cursor_to_selected(struct wmOperatorType *ot);
@@ -287,12 +296,10 @@ void draw_smoke_volume(struct SmokeDomainSettings *sds, struct Object *ob,
const float min[3], const float max[3],
const float viewnormal[3]);
-//#define SMOKE_DEBUG_VELOCITY
//#define SMOKE_DEBUG_HEAT
-#ifdef SMOKE_DEBUG_VELOCITY
-void draw_smoke_velocity(struct SmokeDomainSettings *domain, struct Object *ob);
-#endif
+void draw_smoke_velocity(struct SmokeDomainSettings *domain, float viewnormal[3]);
+
#ifdef SMOKE_DEBUG_HEAT
void draw_smoke_heat(struct SmokeDomainSettings *domain, struct Object *ob);
#endif
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index c30e688f1e7..cfeb8af280e 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -164,10 +164,12 @@ void view3d_operatortypes(void)
WM_operatortype_append(VIEW3D_OT_zoom);
WM_operatortype_append(VIEW3D_OT_zoom_camera_1_to_1);
WM_operatortype_append(VIEW3D_OT_dolly);
+#ifdef WITH_INPUT_NDOF
WM_operatortype_append(VIEW3D_OT_ndof_orbit_zoom);
WM_operatortype_append(VIEW3D_OT_ndof_orbit);
WM_operatortype_append(VIEW3D_OT_ndof_pan);
WM_operatortype_append(VIEW3D_OT_ndof_all);
+#endif /* WITH_INPUT_NDOF */
WM_operatortype_append(VIEW3D_OT_view_all);
WM_operatortype_append(VIEW3D_OT_viewnumpad);
WM_operatortype_append(VIEW3D_OT_view_orbit);
@@ -214,11 +216,14 @@ void view3d_operatortypes(void)
WM_operatortype_append(VIEW3D_OT_snap_selected_to_grid);
WM_operatortype_append(VIEW3D_OT_snap_selected_to_cursor);
+ WM_operatortype_append(VIEW3D_OT_snap_selected_to_active);
WM_operatortype_append(VIEW3D_OT_snap_cursor_to_grid);
WM_operatortype_append(VIEW3D_OT_snap_cursor_to_center);
WM_operatortype_append(VIEW3D_OT_snap_cursor_to_selected);
WM_operatortype_append(VIEW3D_OT_snap_cursor_to_active);
-
+
+ WM_operatortype_append(VIEW3D_OT_toggle_render);
+
transform_operatortypes();
}
@@ -360,7 +365,7 @@ void view3d_keymap(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "VIEW3D_OT_localview", PADSLASHKEY, KM_PRESS, 0, 0);
- /* NDOF: begin */
+#ifdef WITH_INPUT_NDOF
/* note: positioned here so keymaps show keyboard keys if assigned */
/* 3D mouse */
WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_orbit_zoom", NDOF_MOTION, 0, 0, 0);
@@ -389,8 +394,7 @@ void view3d_keymap(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_TOP, KM_PRESS, KM_SHIFT, 0);
RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_TOP);
RNA_boolean_set(kmi->ptr, "align_active", true);
- /* NDOF: end */
-
+#endif /* WITH_INPUT_NDOF */
/* layers, shift + alt are properties set in invoke() */
RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", ACCENTGRAVEKEY, KM_PRESS, 0, 0)->ptr, "nr", 0);
@@ -417,10 +421,7 @@ void view3d_keymap(wmKeyConfig *keyconf)
RNA_string_set(kmi->ptr, "value_1", "SOLID");
RNA_string_set(kmi->ptr, "value_2", "TEXTURED");
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle_enum", ZKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.viewport_shade");
- RNA_string_set(kmi->ptr, "value_1", "SOLID");
- RNA_string_set(kmi->ptr, "value_2", "RENDERED");
+ WM_keymap_add_item(keymap, "VIEW3D_OT_toggle_render", ZKEY, KM_PRESS, KM_SHIFT, 0);
/* selection*/
kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c
index cbabc8e56de..7448d4c658e 100644
--- a/source/blender/editors/space_view3d/view3d_project.c
+++ b/source/blender/editors/space_view3d/view3d_project.c
@@ -217,8 +217,8 @@ eV3DProjStatus ED_view3d_project_float_ex(const ARegion *ar, float perspmat[4][4
float tvec[2];
eV3DProjStatus ret = ed_view3d_project__internal(ar, perspmat, is_local, co, tvec, flag);
if (ret == V3D_PROJ_RET_OK) {
- if (finite(tvec[0]) &&
- finite(tvec[1]))
+ if (isfinite(tvec[0]) &&
+ isfinite(tvec[1]))
{
copy_v2_v2(r_co, tvec);
}
@@ -302,8 +302,9 @@ float ED_view3d_calc_zfac(const RegionView3D *rv3d, const float co[3], bool *r_f
return zfac;
}
-static void view3d_win_to_ray_segment(const ARegion *ar, View3D *v3d, const float mval[2],
- float r_ray_co[3], float r_ray_dir[3], float r_ray_start[3], float r_ray_end[3])
+static void view3d_win_to_ray_segment(
+ const ARegion *ar, const View3D *v3d, const float mval[2],
+ float r_ray_co[3], float r_ray_dir[3], float r_ray_start[3], float r_ray_end[3])
{
RegionView3D *rv3d = ar->regiondata;
float _ray_co[3], _ray_dir[3], start_offset, end_offset;
@@ -311,25 +312,9 @@ static void view3d_win_to_ray_segment(const ARegion *ar, View3D *v3d, const floa
if (!r_ray_co) r_ray_co = _ray_co;
if (!r_ray_dir) r_ray_dir = _ray_dir;
+ ED_view3d_win_to_origin(ar, mval, r_ray_co);
ED_view3d_win_to_vector(ar, mval, r_ray_dir);
- if (rv3d->is_persp) {
- copy_v3_v3(r_ray_co, rv3d->viewinv[3]);
- }
- else {
- r_ray_co[0] = 2.0f * mval[0] / ar->winx - 1.0f;
- r_ray_co[1] = 2.0f * mval[1] / ar->winy - 1.0f;
-
- if (rv3d->persp == RV3D_CAMOB) {
- r_ray_co[2] = -1.0f;
- }
- else {
- r_ray_co[2] = 0.0f;
- }
-
- mul_project_m4_v3(rv3d->persinv, r_ray_co);
- }
-
if ((rv3d->is_persp == false) && (rv3d->persp != RV3D_CAMOB)) {
end_offset = v3d->far / 2.0f;
start_offset = -end_offset;
@@ -346,7 +331,7 @@ static void view3d_win_to_ray_segment(const ARegion *ar, View3D *v3d, const floa
}
}
-BLI_INLINE bool view3d_clip_segment(RegionView3D *rv3d, float ray_start[3], float ray_end[3])
+bool ED_view3d_clip_segment(const RegionView3D *rv3d, float ray_start[3], float ray_end[3])
{
if ((rv3d->rflag & RV3D_CLIPPING) &&
(clip_segment_v3_plane_n(ray_start, ray_end, rv3d->clip, 6,
@@ -373,8 +358,9 @@ BLI_INLINE bool view3d_clip_segment(RegionView3D *rv3d, float ray_start[3], floa
* \param do_clip Optionally clip the start of the ray by the view clipping planes.
* \return success, false if the ray is totally clipped.
*/
-bool ED_view3d_win_to_ray_ex(const ARegion *ar, View3D *v3d, const float mval[2],
- float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip)
+bool ED_view3d_win_to_ray_ex(
+ const ARegion *ar, const View3D *v3d, const float mval[2],
+ float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip)
{
float ray_end[3];
@@ -382,7 +368,7 @@ bool ED_view3d_win_to_ray_ex(const ARegion *ar, View3D *v3d, const float mval[2]
/* bounds clipping */
if (do_clip) {
- return view3d_clip_segment((RegionView3D *)ar->regiondata, r_ray_start, ray_end);
+ return ED_view3d_clip_segment(ar->regiondata, r_ray_start, ray_end);
}
return true;
@@ -401,8 +387,9 @@ bool ED_view3d_win_to_ray_ex(const ARegion *ar, View3D *v3d, const float mval[2]
* \param do_clip Optionally clip the start of the ray by the view clipping planes.
* \return success, false if the ray is totally clipped.
*/
-bool ED_view3d_win_to_ray(const ARegion *ar, View3D *v3d, const float mval[2],
- float r_ray_start[3], float r_ray_normal[3], const bool do_clip)
+bool ED_view3d_win_to_ray(
+ const ARegion *ar, const View3D *v3d, const float mval[2],
+ float r_ray_start[3], float r_ray_normal[3], const bool do_clip)
{
return ED_view3d_win_to_ray_ex(ar, v3d, mval, NULL, r_ray_normal, r_ray_start, do_clip);
}
@@ -546,6 +533,37 @@ void ED_view3d_win_to_delta(const ARegion *ar, const float mval[2], float out[3]
}
/**
+ * Calculate a 3d origin from 2d window coordinates.
+ * \note Orthographic views have a less obvious origin,
+ * Since far clip can be a very large value resulting in numeric precision issues,
+ * the origin in this case is close to zero coordinate.
+ *
+ * \param ar The region (used for the window width and height).
+ * \param mval The area relative 2d location (such as event->mval converted to floats).
+ * \param out The resulting normalized world-space direction vector.
+ */
+void ED_view3d_win_to_origin(const ARegion *ar, const float mval[2], float out[3])
+{
+ RegionView3D *rv3d = ar->regiondata;
+ if (rv3d->is_persp) {
+ copy_v3_v3(out, rv3d->viewinv[3]);
+ }
+ else {
+ out[0] = 2.0f * mval[0] / ar->winx - 1.0f;
+ out[1] = 2.0f * mval[1] / ar->winy - 1.0f;
+
+ if (rv3d->persp == RV3D_CAMOB) {
+ out[2] = -1.0f;
+ }
+ else {
+ out[2] = 0.0f;
+ }
+
+ mul_project_m4_v3(rv3d->persinv, out);
+ }
+}
+
+/**
* Calculate a 3d direction vector from 2d window coordinates.
* This direction vector starts and the view in the direction of the 2d window coordinates.
* In orthographic view all window coordinates yield the same vector.
@@ -596,7 +614,7 @@ bool ED_view3d_win_to_segment(const ARegion *ar, View3D *v3d, const float mval[2
/* bounds clipping */
if (do_clip) {
- return view3d_clip_segment((RegionView3D *)ar->regiondata, r_ray_start, r_ray_end);
+ return ED_view3d_clip_segment((RegionView3D *)ar->regiondata, r_ray_start, r_ray_end);
}
return true;
diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c
index 6789970d00f..3c13ab9d595 100644
--- a/source/blender/editors/space_view3d/view3d_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_ruler.c
@@ -35,6 +35,8 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
+#include "BLT_translation.h"
+
#include "BKE_context.h"
#include "BKE_unit.h"
#include "BKE_gpencil.h"
@@ -257,6 +259,37 @@ static bool view3d_ruler_pick(RulerInfo *ruler_info, const float mval[2],
}
}
+/**
+ * Ensure the 'snap_context' is only cached while dragging,
+ * needed since the user may toggle modes between tool use.
+ */
+static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state)
+{
+ if (state == ruler_info->state) {
+ return;
+ }
+
+ /* always remove */
+ if (ruler_info->snap_context) {
+ ED_transform_snap_object_context_destroy(ruler_info->snap_context);
+ ruler_info->snap_context = NULL;
+ }
+
+ if (state == RULER_STATE_NORMAL) {
+ /* pass */
+ }
+ else if (state == RULER_STATE_DRAG) {
+ ruler_info->snap_context = ED_transform_snap_object_context_create_view3d(
+ CTX_data_main(C), CTX_data_scene(C), SNAP_OBJECT_USE_CACHE,
+ ruler_info->ar, CTX_wm_view3d(C));
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ ruler_info->state = state;
+}
+
#define RULER_ID "RulerData3D"
static bool view3d_ruler_to_gpencil(bContext *C, RulerInfo *ruler_info)
{
@@ -264,23 +297,36 @@ static bool view3d_ruler_to_gpencil(bContext *C, RulerInfo *ruler_info)
bGPDlayer *gpl;
bGPDframe *gpf;
bGPDstroke *gps;
+ bGPDpalette *palette;
+ bGPDpalettecolor *palcolor;
RulerItem *ruler_item;
const char *ruler_name = RULER_ID;
bool changed = false;
if (scene->gpd == NULL) {
- scene->gpd = gpencil_data_addnew("GPencil");
+ scene->gpd = BKE_gpencil_data_addnew("GPencil");
}
gpl = BLI_findstring(&scene->gpd->layers, ruler_name, offsetof(bGPDlayer, info));
if (gpl == NULL) {
- gpl = gpencil_layer_addnew(scene->gpd, ruler_name, false);
+ gpl = BKE_gpencil_layer_addnew(scene->gpd, ruler_name, false);
gpl->thickness = 1;
gpl->flag |= GP_LAYER_HIDE;
}
- gpf = gpencil_layer_getframe(gpl, CFRA, true);
- free_gpencil_strokes(gpf);
+ /* try to get active palette or create a new one */
+ palette = BKE_gpencil_palette_getactive(scene->gpd);
+ if (palette == NULL) {
+ palette = BKE_gpencil_palette_addnew(scene->gpd, DATA_("GP_Palette"), true);
+ }
+ /* try to get color with the ruler name or create a new one */
+ palcolor = BKE_gpencil_palettecolor_getbyname(palette, (char *)ruler_name);
+ if (palcolor == NULL) {
+ palcolor = BKE_gpencil_palettecolor_addnew(palette, (char *)ruler_name, true);
+ }
+
+ gpf = BKE_gpencil_layer_getframe(gpl, CFRA, true);
+ BKE_gpencil_free_strokes(gpf);
for (ruler_item = ruler_info->items.first; ruler_item; ruler_item = ruler_item->next) {
bGPDspoint *pt;
@@ -294,6 +340,7 @@ static bool view3d_ruler_to_gpencil(bContext *C, RulerInfo *ruler_info)
for (j = 0; j < 3; j++) {
copy_v3_v3(&pt->x, ruler_item->co[j]);
pt->pressure = 1.0f;
+ pt->strength = 1.0f;
pt++;
}
}
@@ -303,10 +350,15 @@ static bool view3d_ruler_to_gpencil(bContext *C, RulerInfo *ruler_info)
for (j = 0; j < 3; j += 2) {
copy_v3_v3(&pt->x, ruler_item->co[j]);
pt->pressure = 1.0f;
+ pt->strength = 1.0f;
pt++;
}
}
gps->flag = GP_STROKE_3DSPACE;
+ gps->thickness = 3;
+ /* assign color to stroke */
+ BLI_strncpy(gps->colorname, palcolor->info, sizeof(gps->colorname));
+ gps->palcolor = palcolor;
BLI_addtail(&gpf->strokes, gps);
changed = true;
}
@@ -325,7 +377,7 @@ static bool view3d_ruler_from_gpencil(bContext *C, RulerInfo *ruler_info)
gpl = BLI_findstring(&scene->gpd->layers, ruler_name, offsetof(bGPDlayer, info));
if (gpl) {
bGPDframe *gpf;
- gpf = gpencil_layer_getframe(gpl, CFRA, false);
+ gpf = BKE_gpencil_layer_getframe(gpl, CFRA, false);
if (gpf) {
bGPDstroke *gps;
for (gps = gpf->strokes.first; gps; gps = gps->next) {
@@ -638,7 +690,9 @@ static void view3d_ruler_free(RulerInfo *ruler_info)
{
BLI_freelistN(&ruler_info->items);
- ED_transform_snap_object_context_destroy(ruler_info->snap_context);
+ if (ruler_info->snap_context) {
+ ED_transform_snap_object_context_destroy(ruler_info->snap_context);
+ }
MEM_freeN(ruler_info);
}
@@ -677,9 +731,10 @@ static bool view3d_ruler_item_mousemove(
if (ED_transform_snap_object_project_view3d_mixed(
ruler_info->snap_context,
+ SCE_SELECT_FACE,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
- .snap_to_flag = SCE_SELECT_FACE,
+ .use_object_edit_cage = true,
},
mval_fl, &dist_px, true,
co, ray_normal))
@@ -689,6 +744,10 @@ static bool view3d_ruler_item_mousemove(
madd_v3_v3v3fl(ray_start, co, ray_normal, eps_bias);
ED_transform_snap_object_project_ray(
ruler_info->snap_context,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_ALL,
+ .use_object_edit_cage = true,
+ },
ray_start, ray_normal, NULL,
co_other, NULL);
}
@@ -701,9 +760,10 @@ static bool view3d_ruler_item_mousemove(
if (ED_transform_snap_object_project_view3d_mixed(
ruler_info->snap_context,
+ (SCE_SELECT_VERTEX | SCE_SELECT_EDGE) | (use_depth ? SCE_SELECT_FACE : 0),
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
- .snap_to_flag = (SCE_SELECT_VERTEX | SCE_SELECT_EDGE) | (use_depth ? SCE_SELECT_FACE : 0),
+ .use_object_edit_cage = true,
},
mval_fl, &dist_px, use_depth,
co, NULL))
@@ -720,13 +780,13 @@ static bool view3d_ruler_item_mousemove(
static void view3d_ruler_header_update(ScrArea *sa)
{
- const char *text = "Ctrl+LMB: Add, "
- "Del: Remove, "
- "Ctrl+Drag: Snap, "
- "Shift+Drag: Thickness, "
- "Ctrl+C: Copy Value, "
- "Enter: Store, "
- "Esc: Cancel";
+ const char *text = IFACE_("Ctrl+LMB: Add, "
+ "Del: Remove, "
+ "Ctrl+Drag: Snap, "
+ "Shift+Drag: Thickness, "
+ "Ctrl+C: Copy Value, "
+ "Enter: Store, "
+ "Esc: Cancel");
ED_area_headerprint(sa, text);
}
@@ -749,10 +809,6 @@ static int view3d_ruler_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
op->customdata = ruler_info;
- ruler_info->snap_context = ED_transform_snap_object_context_create_view3d(
- CTX_data_main(C), CTX_data_scene(C), SNAP_OBJECT_USE_CACHE,
- ar, CTX_wm_view3d(C));
-
ruler_info->win = win;
ruler_info->sa = sa;
ruler_info->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ruler_info_draw_pixel,
@@ -810,7 +866,7 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event)
ruler_info->snap_flag &= ~RULER_SNAP_OK;
do_draw = true;
}
- ruler_info->state = RULER_STATE_NORMAL;
+ ruler_state_set(C, ruler_info, RULER_STATE_NORMAL);
}
}
else {
@@ -827,7 +883,7 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event)
RulerItem *ruler_item_prev = ruler_item_active_get(ruler_info);
RulerItem *ruler_item;
/* check if we want to drag an existing point or add a new one */
- ruler_info->state = RULER_STATE_DRAG;
+ ruler_state_set(C, ruler_info, RULER_STATE_DRAG);
ruler_item = ruler_item_add(ruler_info);
ruler_item_active_set(ruler_info, ruler_item);
@@ -869,7 +925,7 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event)
ruler_item_active_set(ruler_info, ruler_item_pick);
ruler_item_pick->flag |= RULERITEM_USE_ANGLE;
ruler_item_pick->co_index = 1;
- ruler_info->state = RULER_STATE_DRAG;
+ ruler_state_set(C, ruler_info, RULER_STATE_DRAG);
/* find the factor */
{
@@ -896,7 +952,7 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event)
else {
ruler_item_active_set(ruler_info, ruler_item_pick);
ruler_item_pick->co_index = co_index;
- ruler_info->state = RULER_STATE_DRAG;
+ ruler_state_set(C, ruler_info, RULER_STATE_DRAG);
/* store the initial depth */
copy_v3_v3(ruler_info->drag_start_co, ruler_item_pick->co[ruler_item_pick->co_index]);
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index bedcf413bfa..3239d07553f 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -94,6 +94,8 @@
#include "UI_interface.h"
+#include "GPU_draw.h"
+
#include "view3d_intern.h" /* own include */
float ED_view3d_select_dist_px(void)
@@ -1690,7 +1692,7 @@ static int do_paintvert_box_select(ViewContext *vc, rcti *rect, bool select, boo
if (ENDIAN_ORDER == B_ENDIAN) {
IMB_convert_rgba_to_abgr(ibuf);
}
- WM_framebuffer_to_index_array(ibuf->rect, size[0] * size[1]);
+ GPU_select_to_index_array(ibuf->rect, size[0] * size[1]);
a = size[0] * size[1];
while (a--) {
@@ -1952,6 +1954,9 @@ static int do_armature_box_select(ViewContext *vc, rcti *rect, bool select, bool
int index = buffer[(4 * a) + 3];
if (index != -1) {
ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
+ if ((index & 0xFFFF0000) == 0) {
+ continue;
+ }
if ((select == false) || ((ebone->flag & BONE_UNSELECTABLE) == 0)) {
if (index & BONESEL_TIP) {
ebone->flag |= BONE_DONE;
diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c
index e8e7d3c62fb..5dd69cc66eb 100644
--- a/source/blender/editors/space_view3d/view3d_snap.c
+++ b/source/blender/editors/space_view3d/view3d_snap.c
@@ -44,6 +44,7 @@
#include "BKE_main.h"
#include "BKE_mball.h"
#include "BKE_object.h"
+#include "BKE_report.h"
#include "BKE_tracking.h"
#include "WM_api.h"
@@ -204,7 +205,7 @@ void VIEW3D_OT_snap_selected_to_grid(wmOperatorType *ot)
/* *************************************************** */
-static int snap_sel_to_curs_exec(bContext *C, wmOperator *op)
+static int snap_selected_to_location(bContext *C, const float snap_target_global[3], const bool use_offset)
{
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
@@ -213,15 +214,10 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op)
TransVertStore tvs = {NULL};
TransVert *tv;
float imat[3][3], bmat[3][3];
- const float *cursor_global;
float center_global[3];
float offset_global[3];
int a;
- const bool use_offset = RNA_boolean_get(op->ptr, "use_offset");
-
- cursor_global = ED_view3d_cursor3d_get(scene, v3d);
-
if (use_offset) {
if ((v3d && v3d->around == V3D_AROUND_ACTIVE) &&
snap_calc_active_center(C, true, center_global))
@@ -231,11 +227,11 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op)
else {
snap_curs_to_sel_ex(C, center_global);
}
- sub_v3_v3v3(offset_global, cursor_global, center_global);
+ sub_v3_v3v3(offset_global, snap_target_global, center_global);
}
if (obedit) {
- float cursor_local[3];
+ float snap_target_local[3];
if (ED_transverts_check_obedit(obedit))
ED_transverts_create_from_obedit(&tvs, obedit, 0);
@@ -246,8 +242,8 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op)
invert_m3_m3(imat, bmat);
/* get the cursor in object space */
- sub_v3_v3v3(cursor_local, cursor_global, obedit->obmat[3]);
- mul_m3_v3(imat, cursor_local);
+ sub_v3_v3v3(snap_target_local, snap_target_global, obedit->obmat[3]);
+ mul_m3_v3(imat, snap_target_local);
if (use_offset) {
float offset_local[3];
@@ -262,7 +258,7 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op)
else {
tv = tvs.transverts;
for (a = 0; a < tvs.transverts_tot; a++, tv++) {
- copy_v3_v3(tv->loc, cursor_local);
+ copy_v3_v3(tv->loc, snap_target_local);
}
}
@@ -274,10 +270,10 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op)
bPoseChannel *pchan;
bArmature *arm = obact->data;
- float cursor_local[3];
+ float snap_target_local[3];
invert_m4_m4(obact->imat, obact->obmat);
- mul_v3_m4v3(cursor_local, obact->imat, cursor_global);
+ mul_v3_m4v3(snap_target_local, obact->imat, snap_target_global);
for (pchan = obact->pose->chanbase.first; pchan; pchan = pchan->next) {
if ((pchan->bone->flag & BONE_SELECTED) &&
@@ -311,7 +307,7 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op)
BKE_armature_loc_pose_to_bone(pchan, cursor_pose, cursor_pose);
}
else {
- BKE_armature_loc_pose_to_bone(pchan, cursor_local, cursor_pose);
+ BKE_armature_loc_pose_to_bone(pchan, snap_target_local, cursor_pose);
}
/* copy new position */
@@ -367,7 +363,7 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op)
add_v3_v3v3(cursor_parent, ob->obmat[3], offset_global);
}
else {
- copy_v3_v3(cursor_parent, cursor_global);
+ copy_v3_v3(cursor_parent, snap_target_global);
}
sub_v3_v3(cursor_parent, ob->obmat[3]);
@@ -401,6 +397,18 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+static int snap_selected_to_cursor_exec(bContext *C, wmOperator *op)
+{
+ const bool use_offset = RNA_boolean_get(op->ptr, "use_offset");
+
+ Scene *scene = CTX_data_scene(C);
+ View3D *v3d = CTX_wm_view3d(C);
+
+ const float *snap_target_global = ED_view3d_cursor3d_get(scene, v3d);
+
+ return snap_selected_to_location(C, snap_target_global, use_offset);
+}
+
void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot)
{
/* identifiers */
@@ -409,7 +417,7 @@ void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot)
ot->idname = "VIEW3D_OT_snap_selected_to_cursor";
/* api callbacks */
- ot->exec = snap_sel_to_curs_exec;
+ ot->exec = snap_selected_to_cursor_exec;
ot->poll = ED_operator_view3d_active;
/* flags */
@@ -419,6 +427,34 @@ void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "use_offset", 1, "Offset", "");
}
+static int snap_selected_to_active_exec(bContext *C, wmOperator *op)
+{
+ float snap_target_global[3];
+
+ if (snap_calc_active_center(C, false, snap_target_global) == false) {
+ BKE_report(op->reports, RPT_ERROR, "No active element found!");
+ return OPERATOR_CANCELLED;
+ }
+
+ return snap_selected_to_location(C, snap_target_global, false);
+}
+
+void VIEW3D_OT_snap_selected_to_active(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Snap Selection to Active";
+ ot->description = "Snap selected item(s) to the active item";
+ ot->idname = "VIEW3D_OT_snap_selected_to_active";
+
+ /* api callbacks */
+ ot->exec = snap_selected_to_active_exec;
+ ot->poll = ED_operator_view3d_active;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
/* *************************************************** */
static int snap_curs_to_grid_exec(bContext *C, wmOperator *UNUSED(op))
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index c35646b9e92..8582952d1a0 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -221,7 +221,7 @@ void ED_view3d_smooth_view_ex(
copy_v3_v3(sms.dyn_ofs, sview->dyn_ofs);
sms.use_dyn_ofs = true;
- /* calcualte the final destination offset */
+ /* calculate the final destination offset */
view3d_orbit_apply_dyn_ofs(sms.dst.ofs, sms.src.ofs, sms.src.quat, sms.dst.quat, sms.dyn_ofs);
}
@@ -507,7 +507,7 @@ static int view3d_camera_to_view_poll(bContext *C)
if (ED_view3d_context_user_region(C, &v3d, &ar)) {
RegionView3D *rv3d = ar->regiondata;
- if (v3d && v3d->camera && v3d->camera->id.lib == NULL) {
+ if (v3d && v3d->camera && !ID_IS_LINKED_DATABLOCK(v3d->camera)) {
if (rv3d && (rv3d->viewlock & RV3D_LOCKED) == 0) {
if (rv3d->persp != RV3D_CAMOB) {
return 1;
@@ -592,6 +592,54 @@ void VIEW3D_OT_camera_to_view_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+static void sync_viewport_camera_smoothview(bContext *C, View3D *v3d, Object *ob, const int smooth_viewtx)
+{
+ Main *bmain = CTX_data_main(C);
+ for (bScreen *screen = bmain->screen.first; screen != NULL; screen = screen->id.next) {
+ for (ScrArea *area = screen->areabase.first; area != NULL; area = area->next) {
+ for (SpaceLink *space_link = area->spacedata.first; space_link != NULL; space_link = space_link->next) {
+ if (space_link->spacetype == SPACE_VIEW3D) {
+ View3D *other_v3d = (View3D *)space_link;
+ if (other_v3d == v3d) {
+ continue;
+ }
+ if (other_v3d->camera == ob) {
+ continue;
+ }
+ if (v3d->scenelock) {
+ ListBase *lb = (space_link == area->spacedata.first)
+ ? &area->regionbase
+ : &space_link->regionbase;
+ for (ARegion *other_ar = lb->first; other_ar != NULL; other_ar = other_ar->next) {
+ if (other_ar->regiontype == RGN_TYPE_WINDOW) {
+ if (other_ar->regiondata) {
+ RegionView3D *other_rv3d = other_ar->regiondata;
+ if (other_rv3d->persp == RV3D_CAMOB) {
+ Object *other_camera_old = other_v3d->camera;
+ other_v3d->camera = ob;
+ ED_view3d_lastview_store(other_rv3d);
+ ED_view3d_smooth_view(
+ C, other_v3d, other_ar, smooth_viewtx,
+ &(const V3D_SmoothParams) {
+ .camera_old = other_camera_old,
+ .camera = other_v3d->camera,
+ .ofs = other_rv3d->ofs,
+ .quat = other_rv3d->viewquat,
+ .dist = &other_rv3d->dist,
+ .lens = &other_v3d->lens});
+ }
+ else {
+ other_v3d->camera = ob;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
static int view3d_setobjectascamera_exec(bContext *C, wmOperator *op)
{
@@ -627,7 +675,11 @@ static int view3d_setobjectascamera_exec(bContext *C, wmOperator *op)
.dist = &rv3d->dist, .lens = &v3d->lens});
}
- WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS | NC_OBJECT | ND_DRAW, CTX_data_scene(C));
+ if (v3d->scenelock) {
+ sync_viewport_camera_smoothview(C, v3d, ob, smooth_viewtx);
+ WM_event_add_notifier(C, NC_SCENE, scene);
+ }
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, scene);
}
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c
index 47f81678699..17c08ed4205 100644
--- a/source/blender/editors/space_view3d/view3d_walk.c
+++ b/source/blender/editors/space_view3d/view3d_walk.c
@@ -49,6 +49,7 @@
#include "ED_screen.h"
#include "ED_space_api.h"
+#include "ED_transform.h"
#include "ED_transform_snap_object_context.h"
#include "PIL_time.h" /* smoothview */
@@ -58,8 +59,10 @@
#include "view3d_intern.h" /* own include */
-//#define NDOF_WALK_DEBUG
-//#define NDOF_WALK_DRAW_TOOMUCH /* is this needed for ndof? - commented so redraw doesnt thrash - campbell */
+#ifdef WITH_INPUT_NDOF
+//# define NDOF_WALK_DEBUG
+//# define NDOF_WALK_DRAW_TOOMUCH /* is this needed for ndof? - commented so redraw doesnt thrash - campbell */
+#endif
#define USE_TABLET_SUPPORT
@@ -253,7 +256,10 @@ typedef struct WalkInfo {
int prev_mval[2]; /* previous 2D mouse values */
int center_mval[2]; /* center mouse values */
int moffset[2];
+
+#ifdef WITH_INPUT_NDOF
wmNDOFMotionData *ndof; /* latest 3D mouse values */
+#endif
/* walk state state */
float base_speed; /* the base speed without run/slow down modifications */
@@ -424,6 +430,9 @@ static bool walk_floor_distance_get(
ret = ED_transform_snap_object_project_ray(
walk->snap_context,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_ALL,
+ },
ray_start, ray_normal, r_distance,
r_location, r_normal_dummy);
@@ -455,6 +464,9 @@ static bool walk_ray_cast(
ret = ED_transform_snap_object_project_ray(
walk->snap_context,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_ALL,
+ },
ray_start, ray_normal, NULL,
r_location, r_normal);
@@ -498,7 +510,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->rv3d->persp = RV3D_PERSP;
}
- if (walk->rv3d->persp == RV3D_CAMOB && walk->v3d->camera->id.lib) {
+ if (walk->rv3d->persp == RV3D_CAMOB && ID_IS_LINKED_DATABLOCK(walk->v3d->camera)) {
BKE_report(op->reports, RPT_ERROR, "Cannot navigate a camera from an external library");
return false;
}
@@ -565,7 +577,9 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->timer = WM_event_add_timer(CTX_wm_manager(C), win, TIMER, 0.01f);
+#ifdef WITH_INPUT_NDOF
walk->ndof = NULL;
+#endif
walk->time_lastdraw = PIL_check_seconds_timer();
@@ -632,8 +646,10 @@ static int walkEnd(bContext *C, WalkInfo *walk)
rv3d->rflag &= ~RV3D_NAVIGATING;
+#ifdef WITH_INPUT_NDOF
if (walk->ndof)
MEM_freeN(walk->ndof);
+#endif
/* restore the cursor */
WM_cursor_modal_restore(win);
@@ -736,6 +752,7 @@ static void walkEvent(bContext *C, wmOperator *op, WalkInfo *walk, const wmEvent
}
}
}
+#ifdef WITH_INPUT_NDOF
else if (event->type == NDOF_MOTION) {
/* do these automagically get delivered? yes. */
// puts("ndof motion detected in walk mode!");
@@ -745,15 +762,15 @@ static void walkEvent(bContext *C, wmOperator *op, WalkInfo *walk, const wmEvent
switch (incoming_ndof->progress) {
case P_STARTING:
/* start keeping track of 3D mouse position */
-#ifdef NDOF_WALK_DEBUG
+# ifdef NDOF_WALK_DEBUG
puts("start keeping track of 3D mouse position");
-#endif
+# endif
/* fall-through */
case P_IN_PROGRESS:
/* update 3D mouse position */
-#ifdef NDOF_WALK_DEBUG
+# ifdef NDOF_WALK_DEBUG
putchar('.'); fflush(stdout);
-#endif
+# endif
if (walk->ndof == NULL) {
// walk->ndof = MEM_mallocN(sizeof(wmNDOFMotionData), tag_name);
walk->ndof = MEM_dupallocN(incoming_ndof);
@@ -765,9 +782,9 @@ static void walkEvent(bContext *C, wmOperator *op, WalkInfo *walk, const wmEvent
break;
case P_FINISHING:
/* stop keeping track of 3D mouse position */
-#ifdef NDOF_WALK_DEBUG
+# ifdef NDOF_WALK_DEBUG
puts("stop keeping track of 3D mouse position");
-#endif
+# endif
if (walk->ndof) {
MEM_freeN(walk->ndof);
// free(walk->ndof);
@@ -782,6 +799,7 @@ static void walkEvent(bContext *C, wmOperator *op, WalkInfo *walk, const wmEvent
break; /* should always be one of the above 3 */
}
}
+#endif /* WITH_INPUT_NDOF */
/* handle modal keymap first */
else if (event->type == EVT_MODAL_MAP) {
switch (event->val) {
@@ -917,8 +935,7 @@ static void walkEvent(bContext *C, wmOperator *op, WalkInfo *walk, const wmEvent
copy_v3_v3(teleport->origin, walk->rv3d->viewinv[3]);
/* stop the camera from a distance (camera height) */
- normalize_v3(nor);
- mul_v3_fl(nor, walk->view_height);
+ normalize_v3_length(nor, walk->view_height);
add_v3_v3(loc, nor);
sub_v3_v3v3(teleport->direction, loc, teleport->origin);
@@ -1317,6 +1334,7 @@ static int walkApply(bContext *C, wmOperator *op, WalkInfo *walk)
#undef WALK_BOOST_FACTOR
}
+#ifdef WITH_INPUT_NDOF
static void walkApply_ndof(bContext *C, WalkInfo *walk)
{
Object *lock_ob = ED_view3d_cameracontrol_object_get(walk->v3d_camera_control);
@@ -1335,6 +1353,7 @@ static void walkApply_ndof(bContext *C, WalkInfo *walk)
}
}
}
+#endif /* WITH_INPUT_NDOF */
/****** walk operator ******/
static int walk_invoke(bContext *C, wmOperator *op, const wmEvent *event)
@@ -1382,12 +1401,15 @@ static int walk_modal(bContext *C, wmOperator *op, const wmEvent *event)
walkEvent(C, op, walk, event);
+#ifdef WITH_INPUT_NDOF
if (walk->ndof) { /* 3D mouse overrules [2D mouse + timer] */
if (event->type == NDOF_MOTION) {
walkApply_ndof(C, walk);
}
}
- else if (event->type == TIMER && event->customdata == walk->timer) {
+ else
+#endif /* WITH_INPUT_NDOF */
+ if (event->type == TIMER && event->customdata == walk->timer) {
walkApply(C, op, walk);
}
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 29c152c2f6e..ef6cff19181 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -51,6 +51,7 @@
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_ghash.h"
+#include "BLI_stackdefines.h"
#include "BLI_memarena.h"
#include "BKE_nla.h"
@@ -80,6 +81,7 @@
#include "WM_api.h"
#include "UI_view2d.h"
+#include "UI_interface.h"
#include "UI_interface_icons.h"
#include "UI_resources.h"
@@ -93,15 +95,12 @@
/* Disabling, since when you type you know what you are doing, and being able to set it to zero is handy. */
// #define USE_NUM_NO_ZERO
-#define MAX_INFO_LEN 256
-
static void drawTransformApply(const struct bContext *C, ARegion *ar, void *arg);
static void doEdgeSlide(TransInfo *t, float perc);
static void doVertSlide(TransInfo *t, float perc);
static void drawEdgeSlide(TransInfo *t);
static void drawVertSlide(TransInfo *t);
-static void len_v3_ensure(float v[3], const float length);
static void postInputRotation(TransInfo *t, float values[3]);
static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short around);
@@ -1203,8 +1202,12 @@ int transformEvent(TransInfo *t, const wmEvent *event)
if (t->flag & T_PROP_EDIT) {
float fac = 1.0f + 0.005f *(event->y - event->prevy);
t->prop_size *= fac;
- if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO)
- t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far);
+ if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) {
+ t->prop_size = max_ff(min_ff(t->prop_size, ((View3D *)t->view)->far), T_PROP_SIZE_MIN);
+ }
+ else {
+ t->prop_size = max_ff(min_ff(t->prop_size, T_PROP_SIZE_MAX), T_PROP_SIZE_MIN);
+ }
calculatePropRatio(t);
t->redraw |= TREDRAW_HARD;
handled = true;
@@ -1213,8 +1216,12 @@ int transformEvent(TransInfo *t, const wmEvent *event)
case TFM_MODAL_PROPSIZE_UP:
if (t->flag & T_PROP_EDIT) {
t->prop_size *= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
- if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO)
+ if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) {
t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far);
+ }
+ else {
+ t->prop_size = min_ff(t->prop_size, T_PROP_SIZE_MAX);
+ }
calculatePropRatio(t);
t->redraw |= TREDRAW_HARD;
handled = true;
@@ -1223,6 +1230,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
case TFM_MODAL_PROPSIZE_DOWN:
if (t->flag & T_PROP_EDIT) {
t->prop_size /= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
+ t->prop_size = max_ff(t->prop_size, T_PROP_SIZE_MIN);
calculatePropRatio(t);
t->redraw |= TREDRAW_HARD;
handled = true;
@@ -2864,7 +2872,7 @@ static void initBend(TransInfo *t)
//copy_v3_v3(t->center, ED_view3d_cursor3d_get(t->scene, t->view));
calculateCenterCursor(t, t->center);
- calculateCenterGlobal(t);
+ calculateCenterGlobal(t, t->center, t->center_global);
t->val = 0.0f;
@@ -2910,7 +2918,7 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
float pivot[3];
float warp_end_radius[3];
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
const struct BendCustomData *data = t->custom.mode.data;
const bool is_clamp = (t->flag & T_ALT_TRANSFORM) == 0;
@@ -2948,13 +2956,13 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bend Angle: %s Radius: %s Alt, Clamp %s"),
+ BLI_snprintf(str, sizeof(str), IFACE_("Bend Angle: %s Radius: %s Alt, Clamp %s"),
&c[0], &c[NUM_STR_REP_LEN],
WM_bool_as_string(is_clamp));
}
else {
/* default header print */
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bend Angle: %.3f Radius: %.4f, Alt, Clamp %s"),
+ BLI_snprintf(str, sizeof(str), IFACE_("Bend Angle: %.3f Radius: %.4f, Alt, Clamp %s"),
RAD2DEGF(values.angle), values.scale * data->warp_init_dist,
WM_bool_as_string(is_clamp));
}
@@ -3104,7 +3112,7 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
float smat[3][3], tmat[3][3], totmat[3][3], persmat[3][3], persinv[3][3];
float value;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
const bool is_local_center = transdata_check_local_center(t, t->around);
copy_m3_m4(persmat, t->viewmat);
@@ -3124,11 +3132,11 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shear: %s %s"), c, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Shear: %s %s"), c, t->proptext);
}
else {
/* default header print */
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shear: %.3f %s (Press X or Y to set shear axis)"), value, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Shear: %.3f %s (Press X or Y to set shear axis)"), value, t->proptext);
}
unit_m3(smat);
@@ -3228,7 +3236,7 @@ static void initResize(TransInfo *t)
t->num.unit_type[2] = B_UNIT_NONE;
}
-static void headerResize(TransInfo *t, const float vec[3], char str[MAX_INFO_LEN])
+static void headerResize(TransInfo *t, const float vec[3], char str[UI_MAX_DRAW_STR])
{
char tvec[NUM_STR_REP_LEN * 3];
size_t ofs = 0;
@@ -3244,32 +3252,32 @@ static void headerResize(TransInfo *t, const float vec[3], char str[MAX_INFO_LEN
if (t->con.mode & CON_APPLY) {
switch (t->num.idx_max) {
case 0:
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Scale: %s%s %s"),
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_("Scale: %s%s %s"),
&tvec[0], t->con.text, t->proptext);
break;
case 1:
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Scale: %s : %s%s %s"),
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_("Scale: %s : %s%s %s"),
&tvec[0], &tvec[NUM_STR_REP_LEN], t->con.text, t->proptext);
break;
case 2:
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Scale: %s : %s : %s%s %s"), &tvec[0],
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_("Scale: %s : %s : %s%s %s"), &tvec[0],
&tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext);
break;
}
}
else {
if (t->flag & T_2D_EDIT) {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Scale X: %s Y: %s%s %s"),
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_("Scale X: %s Y: %s%s %s"),
&tvec[0], &tvec[NUM_STR_REP_LEN], t->con.text, t->proptext);
}
else {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Scale X: %s Y: %s Z: %s%s %s"),
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_("Scale X: %s Y: %s Z: %s%s %s"),
&tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext);
}
}
if (t->flag & T_PROP_EDIT_ALL) {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
}
}
@@ -3394,7 +3402,7 @@ static void applyResize(TransInfo *t, const int mval[2])
TransData *td;
float mat[3][3];
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
if (t->flag & T_AUTOVALUES) {
copy_v3_v3(t->values, t->auto_values);
@@ -3512,7 +3520,7 @@ static void applySkinResize(TransInfo *t, const int UNUSED(mval[2]))
TransData *td;
float size[3], mat[3][3];
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
copy_v3_fl(size, t->values[0]);
@@ -3610,7 +3618,7 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
float vec[3];
float ratio, radius;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
TransData *td = t->data;
ratio = t->values[0];
@@ -3629,11 +3637,11 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("To Sphere: %s %s"), c, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("To Sphere: %s %s"), c, t->proptext);
}
else {
/* default header print */
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("To Sphere: %.4f %s"), ratio, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("To Sphere: %.4f %s"), ratio, t->proptext);
}
@@ -3712,19 +3720,10 @@ static void initRotation(TransInfo *t)
copy_v3_v3(t->axis_orig, t->axis);
}
-static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short around)
+static void ElementRotation_ex(TransInfo *t, TransData *td, float mat[3][3], const float *center)
{
float vec[3], totmat[3][3], smat[3][3];
float eul[3], fmat[3][3], quat[4];
- const float *center;
-
- /* local constraint shouldn't alter center */
- if (transdata_check_local_center(t, around)) {
- center = td->center;
- }
- else {
- center = t->center;
- }
if (t->flag & T_POINTS) {
mul_m3_m3m3(totmat, mat, td->mtx);
@@ -3934,6 +3933,21 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short
}
}
+static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], const short around)
+{
+ const float *center;
+
+ /* local constraint shouldn't alter center */
+ if (transdata_check_local_center(t, around)) {
+ center = td->center;
+ }
+ else {
+ center = t->center;
+ }
+
+ ElementRotation_ex(t, td, mat, center);
+}
+
static void applyRotationValue(TransInfo *t, float angle, float axis[3])
{
TransData *td = t->data;
@@ -3964,7 +3978,7 @@ static void applyRotationValue(TransInfo *t, float angle, float axis[3])
static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
{
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
size_t ofs = 0;
float final;
@@ -3983,10 +3997,8 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
applySnapping(t, &final);
- if (applyNumInput(&t->num, &final)) {
- /* Clamp between -PI and PI */
- final = angle_wrap_rad(final);
- }
+ /* Used to clamp final result in [-PI, PI[ range, no idea why, inheritance from 2.4x area, see T48998. */
+ applyNumInput(&t->num, &final);
t->values[0] = final;
@@ -3995,15 +4007,15 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c, &t->scene->unit);
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Rot: %s %s %s"), &c[0], t->con.text, t->proptext);
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Rot: %s %s %s"), &c[0], t->con.text, t->proptext);
}
else {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Rot: %.2f%s %s"),
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Rot: %.2f%s %s"),
RAD2DEGF(final), t->con.text, t->proptext);
}
if (t->flag & T_PROP_EDIT_ALL) {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
}
applyRotationValue(t, final, t->axis);
@@ -4074,7 +4086,7 @@ static void applyTrackballValue(TransInfo *t, const float axis1[3], const float
static void applyTrackball(TransInfo *t, const int UNUSED(mval[2]))
{
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
size_t ofs = 0;
float axis1[3], axis2[3];
#if 0 /* UNUSED */
@@ -4100,16 +4112,16 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c, &t->scene->unit);
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Trackball: %s %s %s"),
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Trackball: %s %s %s"),
&c[0], &c[NUM_STR_REP_LEN], t->proptext);
}
else {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Trackball: %.2f %.2f %s"),
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Trackball: %.2f %.2f %s"),
RAD2DEGF(phi[0]), RAD2DEGF(phi[1]), t->proptext);
}
if (t->flag & T_PROP_EDIT_ALL) {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
}
#if 0 /* UNUSED */
@@ -4145,7 +4157,12 @@ static void initSnapSpatial(TransInfo *t, float r_snap[3])
r_snap[2] = r_snap[1] * 0.1f;
}
}
- else if (ELEM(t->spacetype, SPACE_IMAGE, SPACE_CLIP)) {
+ else if (t->spacetype == SPACE_IMAGE) {
+ r_snap[0] = 0.0f;
+ r_snap[1] = 0.0625f;
+ r_snap[2] = 0.03125f;
+ }
+ else if (t->spacetype == SPACE_CLIP) {
r_snap[0] = 0.0f;
r_snap[1] = 0.125f;
r_snap[2] = 0.0625f;
@@ -4206,7 +4223,7 @@ static void initTranslation(TransInfo *t)
}
}
-static void headerTranslation(TransInfo *t, const float vec[3], char str[MAX_INFO_LEN])
+static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_DRAW_STR])
{
size_t ofs = 0;
char tvec[NUM_STR_REP_LEN * 3];
@@ -4268,15 +4285,15 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[MAX_INF
if (t->con.mode & CON_APPLY) {
switch (t->num.idx_max) {
case 0:
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "D: %s (%s)%s %s %s",
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, "D: %s (%s)%s %s %s",
&tvec[0], distvec, t->con.text, t->proptext, autoik);
break;
case 1:
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "D: %s D: %s (%s)%s %s %s",
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, "D: %s D: %s (%s)%s %s %s",
&tvec[0], &tvec[NUM_STR_REP_LEN], distvec, t->con.text, t->proptext, autoik);
break;
case 2:
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "D: %s D: %s D: %s (%s)%s %s %s",
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, "D: %s D: %s D: %s (%s)%s %s %s",
&tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], distvec,
t->con.text, t->proptext, autoik);
break;
@@ -4284,18 +4301,18 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[MAX_INF
}
else {
if (t->flag & T_2D_EDIT) {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "Dx: %s Dy: %s (%s)%s %s",
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, "Dx: %s Dy: %s (%s)%s %s",
&tvec[0], &tvec[NUM_STR_REP_LEN], distvec, t->con.text, t->proptext);
}
else {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "Dx: %s Dy: %s Dz: %s (%s)%s %s %s",
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, "Dx: %s Dy: %s Dz: %s (%s)%s %s %s",
&tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], distvec, t->con.text,
t->proptext, autoik);
}
}
if (t->flag & T_PROP_EDIT_ALL) {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
}
if (t->spacetype == SPACE_NODE) {
@@ -4304,11 +4321,11 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[MAX_INF
if ((snode->flag & SNODE_SKIP_INSOFFSET) == 0) {
const char *str_old = BLI_strdup(str);
const char *str_dir = (snode->insert_ofs_dir == SNODE_INSERTOFS_DIR_RIGHT) ? IFACE_("right") : IFACE_("left");
- char str_km[MAX_INFO_LEN];
+ char str_km[64];
WM_modalkeymap_items_to_string(t->keymap, TFM_MODAL_INSERTOFS_TOGGLE_DIR, true, sizeof(str_km), str_km);
- ofs += BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Auto-offset set to %s - press %s to toggle direction | %s"),
+ ofs += BLI_snprintf(str, UI_MAX_DRAW_STR, IFACE_("Auto-offset set to %s - press %s to toggle direction | %s"),
str_dir, str_km, str_old);
MEM_freeN((void *)str_old);
@@ -4329,12 +4346,16 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
if (td->flag & TD_SKIP)
continue;
+ float rotate_offset[3] = {0};
+ bool use_rotate_offset = false;
+
/* handle snapping rotation before doing the translation */
if (usingSnappingNormal(t)) {
+ float mat[3][3];
+
if (validSnappingNormal(t)) {
const float *original_normal;
- float mat[3][3];
-
+
/* In pose mode, we want to align normals with Y axis of bones... */
if (t->flag & T_POSE)
original_normal = td->axismtx[1];
@@ -4342,18 +4363,19 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
original_normal = td->axismtx[2];
rotation_between_vecs_to_mat3(mat, original_normal, t->tsnap.snapNormal);
-
- ElementRotation(t, td, mat, V3D_AROUND_LOCAL_ORIGINS);
}
else {
- float mat[3][3];
-
unit_m3(mat);
-
- ElementRotation(t, td, mat, V3D_AROUND_LOCAL_ORIGINS);
+ }
+
+ ElementRotation_ex(t, td, mat, t->tsnap.snapTarget);
+
+ if (td->loc) {
+ use_rotate_offset = true;
+ sub_v3_v3v3(rotate_offset, td->loc, td->iloc);
}
}
-
+
if (t->con.applyVec) {
float pvec[3];
t->con.applyVec(t, td, vec, tvec, pvec);
@@ -4361,6 +4383,10 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
else {
copy_v3_v3(tvec, vec);
}
+
+ if (use_rotate_offset) {
+ add_v3_v3(tvec, rotate_offset);
+ }
mul_m3_v3(td->smtx, tvec);
mul_v3_fl(tvec, td->factor);
@@ -4369,14 +4395,14 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
if (td->loc)
add_v3_v3v3(td->loc, td->iloc, tvec);
-
+
constraintTransLim(t, td);
}
}
static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
{
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
float value_final[3];
if (t->flag & T_AUTOVALUES) {
@@ -4468,7 +4494,7 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
{
float distance;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
size_t ofs = 0;
TransData *td = t->data;
@@ -4481,29 +4507,29 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
t->values[0] = -distance;
/* header print for NumInput */
- ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Shrink/Fatten:"), MAX_INFO_LEN - ofs);
+ ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Shrink/Fatten:"), sizeof(str) - ofs);
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
outputNumInput(&(t->num), c, &t->scene->unit);
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, " %s", c);
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, " %s", c);
}
else {
/* default header print */
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, " %.4f", distance);
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, " %.4f", distance);
}
if (t->proptext[0]) {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, " %s", t->proptext);
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, " %s", t->proptext);
}
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, ", (");
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, ", (");
if (t->keymap) {
wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_RESIZE);
if (kmi) {
- ofs += WM_keymap_item_to_string(kmi, false, MAX_INFO_LEN - ofs, str + ofs);
+ ofs += WM_keymap_item_to_string(kmi, false, sizeof(str) - ofs, str + ofs);
}
}
- BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" or Alt) Even Thickness %s"),
+ BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_(" or Alt) Even Thickness %s"),
WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0));
/* done with header string */
@@ -4563,7 +4589,7 @@ static void applyTilt(TransInfo *t, const int UNUSED(mval[2]))
{
TransData *td = t->data;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
float final;
@@ -4580,13 +4606,13 @@ static void applyTilt(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Tilt: %s° %s"), &c[0], t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Tilt: %s° %s"), &c[0], t->proptext);
/* XXX For some reason, this seems needed for this op, else RNA prop is not updated... :/ */
t->values[0] = final;
}
else {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Tilt: %.2f° %s"), RAD2DEGF(final), t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Tilt: %.2f° %s"), RAD2DEGF(final), t->proptext);
}
for (i = 0; i < t->total; i++, td++) {
@@ -4644,7 +4670,7 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
TransData *td = t->data;
float ratio;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
ratio = t->values[0];
@@ -4659,10 +4685,10 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
char c[NUM_STR_REP_LEN];
outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shrink/Fatten: %s"), c);
+ BLI_snprintf(str, sizeof(str), IFACE_("Shrink/Fatten: %s"), c);
}
else {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shrink/Fatten: %3f"), ratio);
+ BLI_snprintf(str, sizeof(str), IFACE_("Shrink/Fatten: %3f"), ratio);
}
for (i = 0; i < t->total; i++, td++) {
@@ -4724,7 +4750,7 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
float ratio;
int i;
bool initial_feather = false;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
ratio = t->values[0];
@@ -4739,10 +4765,10 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
char c[NUM_STR_REP_LEN];
outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Feather Shrink/Fatten: %s"), c);
+ BLI_snprintf(str, sizeof(str), IFACE_("Feather Shrink/Fatten: %s"), c);
}
else {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Feather Shrink/Fatten: %3f"), ratio);
+ BLI_snprintf(str, sizeof(str), IFACE_("Feather Shrink/Fatten: %3f"), ratio);
}
/* detect if no points have feather yet */
@@ -4824,7 +4850,7 @@ static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
TransData *td = t->data;
float ratio;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
ratio = t->values[0];
@@ -4839,10 +4865,10 @@ static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
char c[NUM_STR_REP_LEN];
outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shrink/Fatten: %s"), c);
+ BLI_snprintf(str, sizeof(str), IFACE_("Shrink/Fatten: %s"), c);
}
else {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shrink/Fatten: %3f"), ratio);
+ BLI_snprintf(str, sizeof(str), IFACE_("Shrink/Fatten: %3f"), ratio);
}
for (i = 0; i < t->total; i++, td++) {
@@ -4897,7 +4923,7 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
float vec[3], axis[3];
float distance;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
TransData *td = t->data;
distance = t->values[0];
@@ -4914,11 +4940,11 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Push/Pull: %s%s %s"), c, t->con.text, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Push/Pull: %s%s %s"), c, t->con.text, t->proptext);
}
else {
/* default header print */
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Push/Pull: %.4f%s %s"), distance, t->con.text, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Push/Pull: %.4f%s %s"), distance, t->con.text, t->proptext);
}
if (t->con.applyRot && t->con.mode & CON_APPLY) {
@@ -4944,9 +4970,7 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
project_v3_v3v3(vec, vec, axis);
}
}
- normalize_v3(vec);
- mul_v3_fl(vec, distance);
- mul_v3_fl(vec, td->factor);
+ normalize_v3_length(vec, distance * td->factor);
add_v3_v3v3(td->loc, td->iloc, vec);
}
@@ -4989,7 +5013,7 @@ static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2]))
TransData *td = t->data;
float weight;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
weight = t->values[0];
@@ -5008,16 +5032,16 @@ static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c, &t->scene->unit);
if (weight >= 0.0f)
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel Weight: +%s %s"), c, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Bevel Weight: +%s %s"), c, t->proptext);
else
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel Weight: %s %s"), c, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Bevel Weight: %s %s"), c, t->proptext);
}
else {
/* default header print */
if (weight >= 0.0f)
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel Weight: +%.3f %s"), weight, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Bevel Weight: +%.3f %s"), weight, t->proptext);
else
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel Weight: %.3f %s"), weight, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Bevel Weight: %.3f %s"), weight, t->proptext);
}
for (i = 0; i < t->total; i++, td++) {
@@ -5069,7 +5093,7 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
TransData *td = t->data;
float crease;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
crease = t->values[0];
@@ -5088,16 +5112,16 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c, &t->scene->unit);
if (crease >= 0.0f)
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Crease: +%s %s"), c, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Crease: +%s %s"), c, t->proptext);
else
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Crease: %s %s"), c, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Crease: %s %s"), c, t->proptext);
}
else {
/* default header print */
if (crease >= 0.0f)
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Crease: +%.3f %s"), crease, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Crease: +%.3f %s"), crease, t->proptext);
else
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Crease: %.3f %s"), crease, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Crease: %.3f %s"), crease, t->proptext);
}
for (i = 0; i < t->total; i++, td++) {
@@ -5151,7 +5175,7 @@ static void initBoneSize(TransInfo *t)
t->num.unit_type[2] = B_UNIT_NONE;
}
-static void headerBoneSize(TransInfo *t, const float vec[3], char str[MAX_INFO_LEN])
+static void headerBoneSize(TransInfo *t, const float vec[3], char str[UI_MAX_DRAW_STR])
{
char tvec[NUM_STR_REP_LEN * 3];
if (hasNumInput(&t->num)) {
@@ -5166,13 +5190,13 @@ static void headerBoneSize(TransInfo *t, const float vec[3], char str[MAX_INFO_L
/* hmm... perhaps the y-axis values don't need to be shown? */
if (t->con.mode & CON_APPLY) {
if (t->num.idx_max == 0)
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("ScaleB: %s%s %s"), &tvec[0], t->con.text, t->proptext);
+ BLI_snprintf(str, UI_MAX_DRAW_STR, IFACE_("ScaleB: %s%s %s"), &tvec[0], t->con.text, t->proptext);
else
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("ScaleB: %s : %s : %s%s %s"),
+ BLI_snprintf(str, UI_MAX_DRAW_STR, IFACE_("ScaleB: %s : %s : %s%s %s"),
&tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext);
}
else {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("ScaleB X: %s Y: %s Z: %s%s %s"),
+ BLI_snprintf(str, UI_MAX_DRAW_STR, IFACE_("ScaleB X: %s Y: %s Z: %s%s %s"),
&tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext);
}
}
@@ -5203,7 +5227,7 @@ static void applyBoneSize(TransInfo *t, const int mval[2])
float size[3], mat[3][3];
float ratio;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
// TRANSFORM_FIX_ME MOVE TO MOUSE INPUT
/* for manipulator, center handle, the scaling can't be done relative to center */
@@ -5282,7 +5306,7 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
TransData *td = t->data;
float ratio;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
ratio = t->values[0];
@@ -5297,10 +5321,10 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
char c[NUM_STR_REP_LEN];
outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Envelope: %s"), c);
+ BLI_snprintf(str, sizeof(str), IFACE_("Envelope: %s"), c);
}
else {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Envelope: %3f"), ratio);
+ BLI_snprintf(str, sizeof(str), IFACE_("Envelope: %3f"), ratio);
}
for (i = 0; i < t->total; i++, td++) {
@@ -5362,7 +5386,9 @@ static void slide_origdata_init_data(
BMesh *bm = em->bm;
sod->origfaces = BLI_ghash_ptr_new(__func__);
- sod->bm_origfaces = BM_mesh_create(&bm_mesh_allocsize_default);
+ sod->bm_origfaces = BM_mesh_create(
+ &bm_mesh_allocsize_default,
+ &((struct BMeshCreateParams){.use_toolflags = false,}));
/* we need to have matching customdata */
BM_mesh_copy_init_customdata(sod->bm_origfaces, bm, NULL);
}
@@ -5738,13 +5764,6 @@ static void interp_line_v3_v3v3v3(float p[3], const float v1[3], const float v2[
}
}
-
-static void len_v3_ensure(float v[3], const float length)
-{
- normalize_v3(v);
- mul_v3_fl(v, length);
-}
-
/**
* Find the closest point on the ngon on the opposite side.
* used to set the edge slide distance for ngons.
@@ -5808,7 +5827,7 @@ static BMLoop *get_next_loop(BMVert *v, BMLoop *l,
if (l->e == e_next) {
if (i) {
- len_v3_ensure(vec_accum, vec_accum_len / (float)i);
+ normalize_v3_length(vec_accum, vec_accum_len / (float)i);
}
else {
/* When there is no edge to slide along,
@@ -5828,7 +5847,7 @@ static BMLoop *get_next_loop(BMVert *v, BMLoop *l,
cross_v3_v3v3(vec_accum, l_tmp->f->no, tdir);
#if 0
/* rough guess, we can do better! */
- len_v3_ensure(vec_accum, (BM_edge_calc_length(e_prev) + BM_edge_calc_length(e_next)) / 2.0f);
+ normalize_v3_length(vec_accum, (BM_edge_calc_length(e_prev) + BM_edge_calc_length(e_next)) / 2.0f);
#else
/* be clever, check the opposite ngon edge to slide into.
* this gives best results */
@@ -5843,7 +5862,7 @@ static BMLoop *get_next_loop(BMVert *v, BMLoop *l,
dist = (BM_edge_calc_length(e_prev) + BM_edge_calc_length(e_next)) / 2.0f;
}
- len_v3_ensure(vec_accum, dist);
+ normalize_v3_length(vec_accum, dist);
}
#endif
}
@@ -5864,7 +5883,7 @@ static BMLoop *get_next_loop(BMVert *v, BMLoop *l,
if (BM_loop_other_edge_loop(l, v)->e == e_next) {
if (i) {
- len_v3_ensure(vec_accum, vec_accum_len / (float)i);
+ normalize_v3_length(vec_accum, vec_accum_len / (float)i);
}
copy_v3_v3(r_slide_vec, vec_accum);
@@ -5875,7 +5894,7 @@ static BMLoop *get_next_loop(BMVert *v, BMLoop *l,
((l = l->radial_next) != l_first));
if (i) {
- len_v3_ensure(vec_accum, vec_accum_len / (float)i);
+ normalize_v3_length(vec_accum, vec_accum_len / (float)i);
}
copy_v3_v3(r_slide_vec, vec_accum);
@@ -5888,7 +5907,7 @@ static BMLoop *get_next_loop(BMVert *v, BMLoop *l,
*/
static void calcEdgeSlide_mval_range(
TransInfo *t, EdgeSlideData *sld, const int *sv_table, const int loop_nr,
- const float mval[2], const bool use_btree_disp, const bool use_calc_direction)
+ const float mval[2], const bool use_occlude_geometry, const bool use_calc_direction)
{
TransDataEdgeSlideVert *sv_array = sld->sv;
BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
@@ -5897,7 +5916,7 @@ static void calcEdgeSlide_mval_range(
View3D *v3d = NULL;
RegionView3D *rv3d = NULL;
float projectMat[4][4];
- BMBVHTree *btree;
+ BMBVHTree *bmbvh;
/* only for use_calc_direction */
float (*loop_dir)[3] = NULL, *loop_maxdist = NULL;
@@ -5921,11 +5940,11 @@ static void calcEdgeSlide_mval_range(
ED_view3d_ob_project_mat_get(rv3d, t->obedit, projectMat);
}
- if (use_btree_disp) {
- btree = BKE_bmbvh_new_from_editmesh(em, BMBVH_RESPECT_HIDDEN, NULL, false);
+ if (use_occlude_geometry) {
+ bmbvh = BKE_bmbvh_new_from_editmesh(em, BMBVH_RESPECT_HIDDEN, NULL, false);
}
else {
- btree = NULL;
+ bmbvh = NULL;
}
/* find mouse vectors, the global one, and one per loop in case we have
@@ -5960,7 +5979,7 @@ static void calcEdgeSlide_mval_range(
continue;
/* This test is only relevant if object is not wire-drawn! See [#32068]. */
- if (use_btree_disp && !BMBVH_EdgeVisible(btree, e_other, ar, v3d, t->obedit)) {
+ if (use_occlude_geometry && !BMBVH_EdgeVisible(bmbvh, e_other, ar, v3d, t->obedit)) {
continue;
}
@@ -6041,8 +6060,8 @@ static void calcEdgeSlide_mval_range(
sld->mval_end[0] = t->mval[0] + mval_end[0];
sld->mval_end[1] = t->mval[1] + mval_end[1];
- if (btree) {
- BKE_bmbvh_free(btree);
+ if (bmbvh) {
+ BKE_bmbvh_free(bmbvh);
}
}
@@ -6104,8 +6123,8 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, bool use_even, bool f
int *sv_table; /* BMVert -> sv_array index */
EdgeSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
float mval[2] = {(float)t->mval[0], (float)t->mval[1]};
- int numsel, i, j, loop_nr;
- bool use_btree_disp = false;
+ int numsel, i, loop_nr;
+ bool use_occlude_geometry = false;
View3D *v3d = NULL;
RegionView3D *rv3d = NULL;
@@ -6152,31 +6171,39 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, bool use_even, bool f
sv_table = MEM_mallocN(sizeof(*sv_table) * bm->totvert, __func__);
- j = 0;
- BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
- if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
- BM_elem_flag_enable(v, BM_ELEM_TAG);
- sv_table[i] = j;
- j += 1;
- }
- else {
- BM_elem_flag_disable(v, BM_ELEM_TAG);
- sv_table[i] = -1;
+#define INDEX_UNSET -1
+#define INDEX_INVALID -2
+
+ {
+ int j = 0;
+ BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ BM_elem_flag_enable(v, BM_ELEM_TAG);
+ sv_table[i] = INDEX_UNSET;
+ j += 1;
+ }
+ else {
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+ sv_table[i] = INDEX_INVALID;
+ }
+ BM_elem_index_set(v, i); /* set_inline */
}
- BM_elem_index_set(v, i); /* set_inline */
- }
- bm->elem_index_dirty &= ~BM_VERT;
+ bm->elem_index_dirty &= ~BM_VERT;
- if (!j) {
- MEM_freeN(sld);
- MEM_freeN(sv_table);
- return false;
+ if (!j) {
+ MEM_freeN(sld);
+ MEM_freeN(sv_table);
+ return false;
+ }
+ sv_tot = j;
}
- sv_tot = j;
sv_array = MEM_callocN(sizeof(TransDataEdgeSlideVert) * sv_tot, "sv_array");
loop_nr = 0;
+ STACK_DECLARE(sv_array);
+ STACK_INIT(sv_array, sv_tot);
+
while (1) {
float vec_a[3], vec_b[3];
BMLoop *l_a, *l_b;
@@ -6269,6 +6296,11 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, bool use_even, bool f
l_a_prev = NULL;
l_b_prev = NULL;
+#define SV_FROM_VERT(v) ( \
+ (sv_table[BM_elem_index_get(v)] == INDEX_UNSET) ? \
+ ((void)(sv_table[BM_elem_index_get(v)] = STACK_SIZE(sv_array)), STACK_PUSH_RET_PTR(sv_array)) : \
+ (&sv_array[sv_table[BM_elem_index_get(v)]]))
+
/*iterate over the loop*/
v_first = v;
do {
@@ -6280,8 +6312,8 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, bool use_even, bool f
/* XXX, 'sv' will initialize multiple times, this is suspicious. see [#34024] */
BLI_assert(v != NULL);
- BLI_assert(sv_table[BM_elem_index_get(v)] != -1);
- sv = &sv_array[sv_table[BM_elem_index_get(v)]];
+ BLI_assert(sv_table[BM_elem_index_get(v)] != INDEX_INVALID);
+ sv = SV_FROM_VERT(v);
sv->v = v;
copy_v3_v3(sv->v_co_orig, v->co);
sv->loop_nr = loop_nr;
@@ -6306,8 +6338,10 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, bool use_even, bool f
if (!e) {
BLI_assert(v != NULL);
- BLI_assert(sv_table[BM_elem_index_get(v)] != -1);
- sv = &sv_array[sv_table[BM_elem_index_get(v)]];
+
+ BLI_assert(sv_table[BM_elem_index_get(v)] != INDEX_INVALID);
+ sv = SV_FROM_VERT(v);
+
sv->v = v;
copy_v3_v3(sv->v_co_orig, v->co);
sv->loop_nr = loop_nr;
@@ -6396,6 +6430,10 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, bool use_even, bool f
BM_elem_flag_disable(v_prev, BM_ELEM_TAG);
} while ((e != v_first->e) && (l_a || l_b));
+#undef SV_FROM_VERT
+#undef INDEX_UNSET
+#undef INDEX_INVALID
+
loop_nr++;
#undef EDGESLIDE_VERT_IS_INNER
@@ -6403,6 +6441,8 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, bool use_even, bool f
/* EDBM_flag_disable_all(em, BM_ELEM_SELECT); */
+ BLI_assert(STACK_SIZE(sv_array) == sv_tot);
+
sld->sv = sv_array;
sld->totsv = sv_tot;
@@ -6410,10 +6450,10 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, bool use_even, bool f
if (t->spacetype == SPACE_VIEW3D) {
v3d = t->sa ? t->sa->spacedata.first : NULL;
rv3d = t->ar ? t->ar->regiondata : NULL;
- use_btree_disp = (v3d && t->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE);
+ use_occlude_geometry = (v3d && t->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE);
}
- calcEdgeSlide_mval_range(t, sld, sv_table, loop_nr, mval, use_btree_disp, true);
+ calcEdgeSlide_mval_range(t, sld, sv_table, loop_nr, mval, use_occlude_geometry, true);
/* create copies of faces for customdata projection */
bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
@@ -6451,7 +6491,7 @@ static bool createEdgeSlideVerts_single_side(TransInfo *t, bool use_even, bool f
EdgeSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
float mval[2] = {(float)t->mval[0], (float)t->mval[1]};
int loop_nr;
- bool use_btree_disp = false;
+ bool use_occlude_geometry = false;
View3D *v3d = NULL;
RegionView3D *rv3d = NULL;
@@ -6498,6 +6538,7 @@ static bool createEdgeSlideVerts_single_side(TransInfo *t, bool use_even, bool f
bm->elem_index_dirty &= ~BM_VERT;
if (!j) {
+ MEM_freeN(sld);
return false;
}
@@ -6612,10 +6653,10 @@ static bool createEdgeSlideVerts_single_side(TransInfo *t, bool use_even, bool f
if (t->spacetype == SPACE_VIEW3D) {
v3d = t->sa ? t->sa->spacedata.first : NULL;
rv3d = t->ar ? t->ar->regiondata : NULL;
- use_btree_disp = (v3d && t->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE);
+ use_occlude_geometry = (v3d && t->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE);
}
- calcEdgeSlide_mval_range(t, sld, sv_table, loop_nr, mval, use_btree_disp, false);
+ calcEdgeSlide_mval_range(t, sld, sv_table, loop_nr, mval, use_occlude_geometry, false);
/* create copies of faces for customdata projection */
bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
@@ -6959,7 +7000,7 @@ static void doEdgeSlide(TransInfo *t, float perc)
static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
{
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
size_t ofs = 0;
float final;
EdgeSlideData *sld = t->custom.mode.data;
@@ -6982,20 +7023,20 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
t->values[0] = final;
/* header string */
- ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Edge Slide: "), MAX_INFO_LEN - ofs);
+ ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Edge Slide: "), sizeof(str) - ofs);
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
outputNumInput(&(t->num), c, &t->scene->unit);
- ofs += BLI_strncpy_rlen(str + ofs, &c[0], MAX_INFO_LEN - ofs);
+ ofs += BLI_strncpy_rlen(str + ofs, &c[0], sizeof(str) - ofs);
}
else {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "%.4f ", final);
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, "%.4f ", final);
}
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(E)ven: %s, "), WM_bool_as_string(use_even));
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("(E)ven: %s, "), WM_bool_as_string(use_even));
if (use_even) {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(F)lipped: %s, "), WM_bool_as_string(flipped));
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("(F)lipped: %s, "), WM_bool_as_string(flipped));
}
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp));
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp));
/* done with header string */
/* do stuff here */
@@ -7527,7 +7568,7 @@ static void doVertSlide(TransInfo *t, float perc)
static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2]))
{
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
size_t ofs = 0;
float final;
VertSlideData *sld = t->custom.mode.data;
@@ -7550,20 +7591,20 @@ static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2]))
t->values[0] = final;
/* header string */
- ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Vert Slide: "), MAX_INFO_LEN - ofs);
+ ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Vert Slide: "), sizeof(str) - ofs);
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
outputNumInput(&(t->num), c, &t->scene->unit);
- ofs += BLI_strncpy_rlen(str + ofs, &c[0], MAX_INFO_LEN - ofs);
+ ofs += BLI_strncpy_rlen(str + ofs, &c[0], sizeof(str) - ofs);
}
else {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "%.4f ", final);
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, "%.4f ", final);
}
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(E)ven: %s, "), WM_bool_as_string(use_even));
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("(E)ven: %s, "), WM_bool_as_string(use_even));
if (use_even) {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(F)lipped: %s, "), WM_bool_as_string(flipped));
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("(F)lipped: %s, "), WM_bool_as_string(flipped));
}
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp));
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp));
/* done with header string */
/* do stuff here */
@@ -7607,7 +7648,7 @@ static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2]))
{
TransData *td = t->data;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
float final;
@@ -7624,10 +7665,10 @@ static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2]))
outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Roll: %s"), &c[0]);
+ BLI_snprintf(str, sizeof(str), IFACE_("Roll: %s"), &c[0]);
}
else {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Roll: %.2f"), RAD2DEGF(final));
+ BLI_snprintf(str, sizeof(str), IFACE_("Roll: %.2f"), RAD2DEGF(final));
}
/* set roll values */
@@ -7675,7 +7716,7 @@ static void applyBakeTime(TransInfo *t, const int mval[2])
TransData *td = t->data;
float time;
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
float fac = 0.1f;
@@ -7704,16 +7745,16 @@ static void applyBakeTime(TransInfo *t, const int mval[2])
outputNumInput(&(t->num), c, &t->scene->unit);
if (time >= 0.0f)
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Time: +%s %s"), c, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Time: +%s %s"), c, t->proptext);
else
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Time: %s %s"), c, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Time: %s %s"), c, t->proptext);
}
else {
/* default header print */
if (time >= 0.0f)
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Time: +%.3f %s"), time, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Time: +%.3f %s"), time, t->proptext);
else
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Time: %.3f %s"), time, t->proptext);
+ BLI_snprintf(str, sizeof(str), IFACE_("Time: %.3f %s"), time, t->proptext);
}
for (i = 0; i < t->total; i++, td++) {
@@ -7759,7 +7800,7 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2]))
TransData *td;
float size[3], mat[3][3];
int i;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
/*
* OPTIMIZATION:
@@ -7777,7 +7818,7 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2]))
t->con.applySize(t, NULL, mat);
}
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Mirror%s"), t->con.text);
+ BLI_snprintf(str, sizeof(str), IFACE_("Mirror%s"), t->con.text);
for (i = 0, td = t->data; i < t->total; i++, td++) {
if (td->flag & TD_NOACTION)
@@ -7906,7 +7947,7 @@ static void initSeqSlide(TransInfo *t)
t->num.unit_type[1] = B_UNIT_NONE;
}
-static void headerSeqSlide(TransInfo *t, const float val[2], char str[MAX_INFO_LEN])
+static void headerSeqSlide(TransInfo *t, const float val[2], char str[UI_MAX_DRAW_STR])
{
char tvec[NUM_STR_REP_LEN * 3];
size_t ofs = 0;
@@ -7918,15 +7959,15 @@ static void headerSeqSlide(TransInfo *t, const float val[2], char str[MAX_INFO_L
BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.0f, %.0f", val[0], val[1]);
}
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Sequence Slide: %s%s, ("), &tvec[0], t->con.text);
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_("Sequence Slide: %s%s, ("), &tvec[0], t->con.text);
if (t->keymap) {
wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_TRANSLATE);
if (kmi) {
- ofs += WM_keymap_item_to_string(kmi, false, MAX_INFO_LEN - ofs, str + ofs);
+ ofs += WM_keymap_item_to_string(kmi, false, UI_MAX_DRAW_STR - ofs, str + ofs);
}
}
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" or Alt) Expand to fit %s"),
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_(" or Alt) Expand to fit %s"),
WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0));
}
@@ -7948,7 +7989,7 @@ static void applySeqSlideValue(TransInfo *t, const float val[2])
static void applySeqSlide(TransInfo *t, const int mval[2])
{
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
snapSequenceBounds(t, mval);
@@ -8127,7 +8168,7 @@ static void initTimeTranslate(TransInfo *t)
t->num.unit_type[0] = B_UNIT_NONE;
}
-static void headerTimeTranslate(TransInfo *t, char str[MAX_INFO_LEN])
+static void headerTimeTranslate(TransInfo *t, char str[UI_MAX_DRAW_STR])
{
char tvec[NUM_STR_REP_LEN * 3];
int ofs = 0;
@@ -8166,10 +8207,10 @@ static void headerTimeTranslate(TransInfo *t, char str[MAX_INFO_LEN])
BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", val);
}
- ofs += BLI_snprintf(str, MAX_INFO_LEN, IFACE_("DeltaX: %s"), &tvec[0]);
+ ofs += BLI_snprintf(str, UI_MAX_DRAW_STR, IFACE_("DeltaX: %s"), &tvec[0]);
if (t->flag & T_PROP_EDIT_ALL) {
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
}
}
@@ -8231,7 +8272,7 @@ static void applyTimeTranslateValue(TransInfo *t)
static void applyTimeTranslate(TransInfo *t, const int mval[2])
{
View2D *v2d = (View2D *)t->view;
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
/* calculate translation amount from mouse movement - in 'time-grid space' */
if (t->flag & T_MODAL) {
@@ -8323,7 +8364,7 @@ static void initTimeSlide(TransInfo *t)
t->num.unit_type[0] = B_UNIT_NONE;
}
-static void headerTimeSlide(TransInfo *t, const float sval, char str[MAX_INFO_LEN])
+static void headerTimeSlide(TransInfo *t, const float sval, char str[UI_MAX_DRAW_STR])
{
char tvec[NUM_STR_REP_LEN * 3];
@@ -8343,7 +8384,7 @@ static void headerTimeSlide(TransInfo *t, const float sval, char str[MAX_INFO_LE
BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", val);
}
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("TimeSlide: %s"), &tvec[0]);
+ BLI_snprintf(str, UI_MAX_DRAW_STR, IFACE_("TimeSlide: %s"), &tvec[0]);
}
static void applyTimeSlideValue(TransInfo *t, float sval)
@@ -8400,7 +8441,7 @@ static void applyTimeSlide(TransInfo *t, const int mval[2])
const float *range = t->custom.mode.data;
float minx = range[0];
float maxx = range[1];
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
/* calculate mouse co-ordinates */
UI_view2d_region_to_view(v2d, mval[0], mval[1], &cval[0], &cval[1]);
@@ -8473,7 +8514,7 @@ static void initTimeScale(TransInfo *t)
t->num.unit_type[0] = B_UNIT_NONE;
}
-static void headerTimeScale(TransInfo *t, char str[MAX_INFO_LEN])
+static void headerTimeScale(TransInfo *t, char str[UI_MAX_DRAW_STR])
{
char tvec[NUM_STR_REP_LEN * 3];
@@ -8482,7 +8523,7 @@ static void headerTimeScale(TransInfo *t, char str[MAX_INFO_LEN])
else
BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", t->values[0]);
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("ScaleX: %s"), &tvec[0]);
+ BLI_snprintf(str, UI_MAX_DRAW_STR, IFACE_("ScaleX: %s"), &tvec[0]);
}
static void applyTimeScaleValue(TransInfo *t)
@@ -8526,7 +8567,7 @@ static void applyTimeScaleValue(TransInfo *t)
static void applyTimeScale(TransInfo *t, const int UNUSED(mval[2]))
{
- char str[MAX_INFO_LEN];
+ char str[UI_MAX_DRAW_STR];
/* handle numeric-input stuff */
t->vec[0] = t->values[0];
@@ -8558,5 +8599,3 @@ bool checkUseAxisMatrix(TransInfo *t)
return false;
}
-
-#undef MAX_INFO_LEN
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 11151a9c65a..a59f9dc43dd 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -87,7 +87,6 @@ typedef struct TransSnap {
float snapPoint[3]; /* snapping from this point */
float snapTarget[3]; /* to this point */
float snapNormal[3];
- float snapTangent[3];
char snapNodeBorder;
ListBase points;
TransSnapPoint *selectedPoint;
@@ -369,6 +368,11 @@ typedef struct TransCustomData {
unsigned int use_free : 1;
} TransCustomData;
+typedef struct TransCenterData {
+ float local[3], global[3];
+ unsigned int is_set : 1;
+} TransCenterData;
+
typedef struct TransInfo {
int mode; /* current mode */
int flag; /* generic flags for special behaviors */
@@ -396,6 +400,9 @@ typedef struct TransInfo {
float center[3]; /* center of transformation (in local-space) */
float center_global[3]; /* center of transformation (in global-space) */
float center2d[2]; /* center in screen coordinates */
+ /* Lazy initialize center data for when we need other center values.
+ * V3D_AROUND_ACTIVE + 1 (static assert checks this) */
+ TransCenterData center_cache[5];
short idx_max; /* maximum index on the input vector */
float snap[3]; /* Snapping Gears */
float snap_spatial[3]; /* Spatial snapping gears(even when rotating, scaling... etc) */
@@ -584,6 +591,10 @@ typedef struct TransInfo {
#define POINT_INIT 4
#define MULTI_POINTS 8
+/* Hard min/max for proportional size. */
+#define T_PROP_SIZE_MIN 1e-6f
+#define T_PROP_SIZE_MAX 1e12f
+
bool initTransform(struct bContext *C, struct TransInfo *t, struct wmOperator *op, const struct wmEvent *event, int mode);
void saveTransform(struct bContext *C, struct TransInfo *t, struct wmOperator *op);
int transformEvent(TransInfo *t, const struct wmEvent *event);
@@ -742,8 +753,11 @@ void restoreTransObjects(TransInfo *t);
void recalcData(TransInfo *t);
void calculateCenter2D(TransInfo *t);
-void calculateCenterGlobal(TransInfo *t);
+void calculateCenterGlobal(
+ TransInfo *t, const float center_local[3],
+ float r_center_global[3]);
+const TransCenterData *transformCenter_from_type(TransInfo *t, int around);
void calculateCenter(TransInfo *t);
/* API functions for getting center points */
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index beeba7cf10f..d7b670b6476 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -187,9 +187,7 @@ static void viewAxisCorrectCenter(TransInfo *t, float t_con_center[3])
if (l < min_dist) {
float diff[3];
- normalize_v3_v3(diff, t->viewinv[2]);
- mul_v3_fl(diff, min_dist - l);
-
+ normalize_v3_v3_length(diff, t->viewinv[2], min_dist - l);
sub_v3_v3(t_con_center, diff);
}
}
@@ -225,9 +223,8 @@ static void axisProjection(TransInfo *t, const float axis[3], const float in[3],
if (factor < 0.0f) factor *= -factor;
else factor *= factor;
- copy_v3_v3(out, axis);
- normalize_v3(out);
- mul_v3_fl(out, -factor); /* -factor makes move down going backwards */
+ /* -factor makes move down going backwards */
+ normalize_v3_v3_length(out, axis, -factor);
}
else {
float v[3], i1[3], i2[3];
@@ -267,9 +264,9 @@ static void axisProjection(TransInfo *t, const float axis[3], const float in[3],
/* possible some values become nan when
* viewpoint and object are both zero */
- if (!finite(out[0])) out[0] = 0.0f;
- if (!finite(out[1])) out[1] = 0.0f;
- if (!finite(out[2])) out[2] = 0.0f;
+ if (!isfinite(out[0])) out[0] = 0.0f;
+ if (!isfinite(out[1])) out[1] = 0.0f;
+ if (!isfinite(out[2])) out[2] = 0.0f;
}
}
}
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index fa5e86813fa..9c266890d6d 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -701,7 +701,6 @@ int count_set_pose_transflags(int *out_mode, short around, Object *ob)
bPoseChannel *pchan;
Bone *bone;
int mode = *out_mode;
- int hastranslation = 0;
int total = 0;
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
@@ -729,7 +728,7 @@ int count_set_pose_transflags(int *out_mode, short around, Object *ob)
}
}
/* now count, and check if we have autoIK or have to switch from translate to rotate */
- hastranslation = 0;
+ bool has_translation = false, has_rotation = false;
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
bone = pchan->bone;
@@ -740,20 +739,29 @@ int count_set_pose_transflags(int *out_mode, short around, Object *ob)
if (has_targetless_ik(pchan) == NULL) {
if (pchan->parent && (pchan->bone->flag & BONE_CONNECTED)) {
if (pchan->bone->flag & BONE_HINGE_CHILD_TRANSFORM)
- hastranslation = 1;
+ has_translation = true;
}
- else if ((pchan->protectflag & OB_LOCK_LOC) != OB_LOCK_LOC)
- hastranslation = 1;
+ else {
+ if ((pchan->protectflag & OB_LOCK_LOC) != OB_LOCK_LOC)
+ has_translation = true;
+ }
+ if ((pchan->protectflag & OB_LOCK_ROT) != OB_LOCK_ROT)
+ has_rotation = true;
}
else
- hastranslation = 1;
+ has_translation = true;
}
}
}
/* if there are no translatable bones, do rotation */
- if (mode == TFM_TRANSLATION && !hastranslation) {
- *out_mode = TFM_ROTATION;
+ if (mode == TFM_TRANSLATION && !has_translation) {
+ if (has_rotation) {
+ *out_mode = TFM_ROTATION;
+ }
+ else {
+ *out_mode = TFM_RESIZE;
+ }
}
return total;
@@ -2676,6 +2684,20 @@ void flushTransSeq(TransInfo *t)
BKE_sequence_calc(t->scene, seq);
}
}
+
+ /* update effects inside meta's */
+ for (a = 0, seq_prev = NULL, td = t->data, td2d = t->data2d;
+ a < t->total;
+ a++, td++, td2d++, seq_prev = seq)
+ {
+ tdsq = (TransDataSeq *)td->extra;
+ seq = tdsq->seq;
+ if ((seq != seq_prev) && (seq->depth != 0)) {
+ if (seq->seq1 || seq->seq2 || seq->seq3) {
+ BKE_sequence_calc(t->scene, seq);
+ }
+ }
+ }
}
/* need to do the overlap check in a new loop otherwise adjacent strips
@@ -3270,7 +3292,7 @@ static void posttrans_gpd_clean(bGPdata *gpd)
for (gpf = gpl->frames.first; gpf; gpf = gpfn) {
gpfn = gpf->next;
if (gpfn && gpf->framenum == gpfn->framenum) {
- gpencil_layer_delframe(gpl, gpf);
+ BKE_gpencil_layer_delframe(gpl, gpf);
}
}
}
@@ -4920,44 +4942,47 @@ static void freeSeqData(TransInfo *t, TransCustomData *custom_data)
{
int overlap = 0;
- seq_prev = NULL;
- for (a = 0; a < t->total; a++, td++) {
+ for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) {
seq = ((TransDataSeq *)td->extra)->seq;
if ((seq != seq_prev) && (seq->depth == 0) && (seq->flag & SEQ_OVERLAP)) {
overlap = 1;
break;
}
- seq_prev = seq;
}
if (overlap) {
- bool has_effect = false;
+ bool has_effect_root = false, has_effect_any = false;
for (seq = seqbasep->first; seq; seq = seq->next)
seq->tmp = NULL;
td = t->data;
- seq_prev = NULL;
- for (a = 0; a < t->total; a++, td++) {
+ for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) {
seq = ((TransDataSeq *)td->extra)->seq;
if ((seq != seq_prev)) {
/* check effects strips, we cant change their time */
if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
- has_effect = true;
+ has_effect_any = true;
+ if (seq->depth == 0) {
+ has_effect_root = true;
+ }
}
else {
- /* Tag seq with a non zero value, used by BKE_sequence_base_shuffle_time to identify the ones to shuffle */
- seq->tmp = (void *)1;
+ /* Tag seq with a non zero value,
+ * used by BKE_sequence_base_shuffle_time to identify the ones to shuffle */
+ if (seq->depth == 0) {
+ seq->tmp = (void *)1;
+ }
}
}
+
}
if (t->flag & T_ALT_TRANSFORM) {
int minframe = MAXFRAME;
td = t->data;
- seq_prev = NULL;
- for (a = 0; a < t->total; a++, td++) {
+ for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) {
seq = ((TransDataSeq *)td->extra)->seq;
- if ((seq != seq_prev)) {
+ if ((seq != seq_prev) && (seq->depth == 0)) {
minframe = min_ii(minframe, seq->startdisp);
}
}
@@ -4989,11 +5014,10 @@ static void freeSeqData(TransInfo *t, TransCustomData *custom_data)
BKE_sequence_base_shuffle_time(seqbasep, t->scene);
}
- if (has_effect) {
+ if (has_effect_any) {
/* update effects strips based on strips just moved in time */
td = t->data;
- seq_prev = NULL;
- for (a = 0; a < t->total; a++, td++) {
+ for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) {
seq = ((TransDataSeq *)td->extra)->seq;
if ((seq != seq_prev)) {
if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
@@ -5001,13 +5025,14 @@ static void freeSeqData(TransInfo *t, TransCustomData *custom_data)
}
}
}
+ }
+ if (has_effect_root) {
/* now if any effects _still_ overlap, we need to move them up */
td = t->data;
- seq_prev = NULL;
- for (a = 0; a < t->total; a++, td++) {
+ for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) {
seq = ((TransDataSeq *)td->extra)->seq;
- if ((seq != seq_prev)) {
+ if ((seq != seq_prev) && (seq->depth == 0)) {
if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
if (BKE_sequence_test_overlap(seqbasep, seq)) {
BKE_sequence_base_shuffle(seqbasep, seq, t->scene);
@@ -5256,13 +5281,9 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
skip_invert = true;
if (skip_invert == false && constinv == false) {
- if (constinv == false)
- ob->transflag |= OB_NO_CONSTRAINTS; /* BKE_object_where_is_calc_time checks this */
-
+ ob->transflag |= OB_NO_CONSTRAINTS; /* BKE_object_where_is_calc_time checks this */
BKE_object_where_is_calc(t->scene, ob);
-
- if (constinv == false)
- ob->transflag &= ~OB_NO_CONSTRAINTS;
+ ob->transflag &= ~OB_NO_CONSTRAINTS;
}
else
BKE_object_where_is_calc(t->scene, ob);
@@ -5874,6 +5895,7 @@ static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
BMesh *bm = em->bm;
char hflag;
+ bool has_face_sel = (bm->totfacesel != 0);
if (t->flag & T_MIRROR) {
TransData *td;
@@ -5897,8 +5919,10 @@ static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
EDBM_automerge(t->scene, t->obedit, true, hflag);
- if ((em->selectmode & SCE_SELECT_VERTEX) == 0) {
- EDBM_select_flush(em);
+ /* Special case, this is needed or faces won't re-select.
+ * Flush selected edges to faces. */
+ if (has_face_sel && (em->selectmode == SCE_SELECT_FACE)) {
+ EDBM_selectmode_flush_ex(em, SCE_SELECT_EDGE);
}
}
}
@@ -6409,7 +6433,7 @@ static void createTransObject(bContext *C, TransInfo *t)
}
/* select linked objects, but skip them later */
- if (ob->id.lib != NULL) {
+ if (ID_IS_LINKED_DATABLOCK(ob)) {
td->flag |= TD_SKIP;
}
@@ -7587,7 +7611,7 @@ static void createTransPaintCurveVerts(bContext *C, TransInfo *t)
for (pcp = pc->points, i = 0; i < pc->tot_points; i++, pcp++) {
if (PC_IS_ANY_SEL(pcp)) {
- PaintCurvePointToTransData (pcp, td, td2d, tdpc);
+ PaintCurvePointToTransData(pcp, td, td2d, tdpc);
if (pcp->bez.f2 & SELECT) {
td += 3;
@@ -7663,7 +7687,11 @@ static void createTransGPencil(bContext *C, TransInfo *t)
if (ED_gpencil_stroke_can_use(C, gps) == false) {
continue;
}
-
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
+ continue;
+ }
+
if (is_prop_edit) {
/* Proportional Editing... */
if (is_prop_edit_connected) {
@@ -7711,14 +7739,27 @@ static void createTransGPencil(bContext *C, TransInfo *t)
if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
bGPDframe *gpf = gpl->actframe;
bGPDstroke *gps;
+ float diff_mat[4][4];
+ float inverse_diff_mat[4][4];
+
+ /* calculate difference matrix if parent object */
+ if (gpl->parent != NULL) {
+ ED_gpencil_parent_location(gpl, diff_mat);
+ /* undo matrix */
+ invert_m4_m4(inverse_diff_mat, diff_mat);
+ }
- /* Make a new frame to work on if the layer's frame and the current scene frame don't match up
+ /* Make a new frame to work on if the layer's frame and the current scene frame don't match up
* - This is useful when animating as it saves that "uh-oh" moment when you realize you've
* spent too much time editing the wrong frame...
*/
// XXX: should this be allowed when framelock is enabled?
if (gpf->framenum != cfra) {
- gpf = gpencil_frame_addcopy(gpl, cfra);
+ gpf = BKE_gpencil_frame_addcopy(gpl, cfra);
+ /* in some weird situations (framelock enabled) return NULL */
+ if (gpf == NULL) {
+ continue;
+ }
}
/* Loop over strokes, adding TransData for points as needed... */
@@ -7731,7 +7772,10 @@ static void createTransGPencil(bContext *C, TransInfo *t)
if (ED_gpencil_stroke_can_use(C, gps) == false) {
continue;
}
-
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
+ continue;
+ }
/* What we need to include depends on proportional editing settings... */
if (is_prop_edit) {
if (is_prop_edit_connected) {
@@ -7800,9 +7844,18 @@ static void createTransGPencil(bContext *C, TransInfo *t)
/* screenspace */
td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ;
- copy_m3_m4(td->smtx, t->persmat);
- copy_m3_m4(td->mtx, t->persinv);
- unit_m3(td->axismtx);
+ /* apply parent transformations */
+ if (gpl->parent == NULL) {
+ copy_m3_m4(td->smtx, t->persmat);
+ copy_m3_m4(td->mtx, t->persinv);
+ unit_m3(td->axismtx);
+ }
+ else {
+ /* apply matrix transformation relative to parent */
+ copy_m3_m4(td->smtx, inverse_diff_mat); /* final position */
+ copy_m3_m4(td->mtx, diff_mat); /* display position */
+ copy_m3_m4(td->axismtx, diff_mat); /* axis orientation */
+ }
}
else {
/* configure 2D dataspace points so that they don't play up... */
@@ -7811,9 +7864,18 @@ static void createTransGPencil(bContext *C, TransInfo *t)
// XXX: matrices may need to be different?
}
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
- unit_m3(td->axismtx); // XXX?
+ /* apply parent transformations */
+ if (gpl->parent == NULL) {
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+ unit_m3(td->axismtx); // XXX?
+ }
+ else {
+ /* apply matrix transformation relative to parent */
+ copy_m3_m4(td->smtx, inverse_diff_mat); /* final position */
+ copy_m3_m4(td->mtx, diff_mat); /* display position */
+ copy_m3_m4(td->axismtx, diff_mat); /* axis orientation */
+ }
}
/* Triangulation must be calculated again, so save the stroke for recalc function */
td->extra = gps;
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index ed6477392d8..f78a23be7b8 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -563,7 +563,7 @@ static void recalcData_nla(TransInfo *t)
}
/* Use RNA to write the values to ensure that constraints on these are obeyed
- * (e.g. for transition strips, the values are taken from the neighbours)
+ * (e.g. for transition strips, the values are taken from the neighbors)
*
* NOTE: we write these twice to avoid truncation errors which can arise when
* moving the strips a large distance using numeric input [#33852]
@@ -975,7 +975,9 @@ static void recalcData_gpencil_strokes(TransInfo *t)
TransData *td = t->data;
for (int i = 0; i < t->total; i++, td++) {
bGPDstroke *gps = td->extra;
- gps->flag |= GP_STROKE_RECALC_CACHES;
+ if (gps != NULL) {
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ }
}
}
@@ -1610,16 +1612,18 @@ void calculateCenter2D(TransInfo *t)
}
}
-void calculateCenterGlobal(TransInfo *t)
+void calculateCenterGlobal(
+ TransInfo *t, const float center_local[3],
+ float r_center_global[3])
{
/* setting constraint center */
/* note, init functions may over-ride t->center */
if (t->flag & (T_EDIT | T_POSE)) {
Object *ob = t->obedit ? t->obedit : t->poseobj;
- mul_v3_m4v3(t->center_global, ob->obmat, t->center);
+ mul_v3_m4v3(r_center_global, ob->obmat, center_local);
}
else {
- copy_v3_v3(t->center_global, t->center);
+ copy_v3_v3(r_center_global, center_local);
}
}
@@ -1794,43 +1798,55 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3])
return ok;
}
-
-void calculateCenter(TransInfo *t)
+static void calculateCenter_FromAround(TransInfo *t, int around, float r_center[3])
{
- switch (t->around) {
+ switch (around) {
case V3D_AROUND_CENTER_BOUNDS:
- calculateCenterBound(t, t->center);
+ calculateCenterBound(t, r_center);
break;
case V3D_AROUND_CENTER_MEAN:
- calculateCenterMedian(t, t->center);
+ calculateCenterMedian(t, r_center);
break;
case V3D_AROUND_CURSOR:
if (ELEM(t->spacetype, SPACE_IMAGE, SPACE_CLIP))
- calculateCenterCursor2D(t, t->center);
+ calculateCenterCursor2D(t, r_center);
else if (t->spacetype == SPACE_IPO)
- calculateCenterCursorGraph2D(t, t->center);
+ calculateCenterCursorGraph2D(t, r_center);
else
- calculateCenterCursor(t, t->center);
+ calculateCenterCursor(t, r_center);
break;
case V3D_AROUND_LOCAL_ORIGINS:
/* Individual element center uses median center for helpline and such */
- calculateCenterMedian(t, t->center);
+ calculateCenterMedian(t, r_center);
break;
case V3D_AROUND_ACTIVE:
{
- if (calculateCenterActive(t, false, t->center)) {
+ if (calculateCenterActive(t, false, r_center)) {
/* pass */
}
else {
/* fallback */
- calculateCenterMedian(t, t->center);
+ calculateCenterMedian(t, r_center);
}
break;
}
}
+}
+
+void calculateCenter(TransInfo *t)
+{
+ calculateCenter_FromAround(t, t->around, t->center);
+ calculateCenterGlobal(t, t->center, t->center_global);
+
+ /* avoid calculating again */
+ {
+ TransCenterData *cd = &t->center_cache[t->around];
+ copy_v3_v3(cd->local, t->center);
+ copy_v3_v3(cd->global, t->center_global);
+ cd->is_set = true;
+ }
calculateCenter2D(t);
- calculateCenterGlobal(t);
/* for panning from cameraview */
if (t->flag & T_OBJECT) {
@@ -1884,6 +1900,23 @@ void calculateCenter(TransInfo *t)
}
}
+BLI_STATIC_ASSERT(ARRAY_SIZE(((TransInfo *)NULL)->center_cache) == (V3D_AROUND_ACTIVE + 1), "test size");
+
+/**
+ * Lazy initialize transform center data, when we need to access center values from other types.
+ */
+const TransCenterData *transformCenter_from_type(TransInfo *t, int around)
+{
+ BLI_assert(around <= V3D_AROUND_ACTIVE);
+ TransCenterData *cd = &t->center_cache[around];
+ if (cd->is_set == false) {
+ calculateCenter_FromAround(t, around, cd->local);
+ calculateCenterGlobal(t, cd->local, cd->global);
+ cd->is_set = true;
+ }
+ return cd;
+}
+
void calculatePropRatio(TransInfo *t)
{
TransData *td = t->data;
diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c
index 992fde0cce3..075f311db72 100644
--- a/source/blender/editors/transform/transform_manipulator.c
+++ b/source/blender/editors/transform/transform_manipulator.c
@@ -58,6 +58,7 @@
#include "BKE_pointcache.h"
#include "BKE_editmesh.h"
#include "BKE_lattice.h"
+#include "BKE_gpencil.h"
#include "BIF_gl.h"
@@ -68,6 +69,7 @@
#include "ED_curve.h"
#include "ED_particle.h"
#include "ED_view3d.h"
+#include "ED_gpencil.h"
#include "UI_resources.h"
@@ -288,24 +290,49 @@ static int calc_manipulator_stats(const bContext *C)
zero_v3(scene->twcent);
if (is_gp_edit) {
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
- {
- /* we're only interested in selected points here... */
- if (gps->flag & GP_STROKE_SELECT) {
- bGPDspoint *pt;
- int i;
-
- /* Change selection status of all points, then make the stroke match */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->flag & GP_SPOINT_SELECT) {
- calc_tw_center(scene, &pt->x);
- totsel++;
+ float diff_mat[4][4];
+ float fpt[3];
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* only editable and visible layers are considered */
+ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+
+ /* calculate difference matrix if parent object */
+ if (gpl->parent != NULL) {
+ ED_gpencil_parent_location(gpl, diff_mat);
+ }
+
+ for (bGPDstroke *gps = gpl->actframe->strokes.first; gps; gps = gps->next) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+
+ /* we're only interested in selected points here... */
+ if (gps->flag & GP_STROKE_SELECT) {
+ bGPDspoint *pt;
+ int i;
+
+ /* Change selection status of all points, then make the stroke match */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ if (gpl->parent == NULL) {
+ calc_tw_center(scene, &pt->x);
+ totsel++;
+ }
+ else {
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ calc_tw_center(scene, fpt);
+ totsel++;
+ }
+ }
+ }
}
}
}
}
- CTX_DATA_END;
-
+
+
/* selection center */
if (totsel) {
mul_v3_fl(scene->twcent, 1.0f / (float)totsel); /* centroid! */
@@ -995,8 +1022,7 @@ static void draw_manipulator_rotate(
vec[0] = 0; // XXX (float)(t->mouse.imval[0] - t->center2d[0]);
vec[1] = 0; // XXX (float)(t->mouse.imval[1] - t->center2d[1]);
vec[2] = 0.0f;
- normalize_v3(vec);
- mul_v3_fl(vec, 1.2f * size);
+ normalize_v3_length(vec, 1.2f * size);
glBegin(GL_LINES);
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3fv(vec);
@@ -1516,8 +1542,7 @@ static void draw_manipulator_rotate_cyl(
vec[0] = 0; // XXX (float)(t->mouse.imval[0] - t->center2d[0]);
vec[1] = 0; // XXX (float)(t->mouse.imval[1] - t->center2d[1]);
vec[2] = 0.0f;
- normalize_v3(vec);
- mul_v3_fl(vec, 1.2f * size);
+ normalize_v3_length(vec, 1.2f * size);
glBegin(GL_LINES);
glVertex3f(0.0, 0.0, 0.0);
glVertex3fv(vec);
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 5d49d1d9315..cbe58ddf586 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -386,7 +386,7 @@ static int transform_modal(bContext *C, wmOperator *op, const wmEvent *event)
TransInfo *t = op->customdata;
const enum TfmMode mode_prev = t->mode;
-#if 0
+#if defined(WITH_INPUT_NDOF) && 0
// stable 2D mouse coords map to different 3D coords while the 3D mouse is active
// in other words, 2D deltas are no longer good enough!
// disable until individual 'transformers' behave better
@@ -528,7 +528,8 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
prop = RNA_def_enum(ot->srna, "proportional_edit_falloff", rna_enum_proportional_falloff_items, 0,
"Proportional Editing Falloff", "Falloff type for proportional editing mode");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
- RNA_def_float(ot->srna, "proportional_size", 1, 0.00001f, FLT_MAX, "Proportional Size", "", 0.001, 100);
+ RNA_def_float(ot->srna, "proportional_size", 1, T_PROP_SIZE_MIN, T_PROP_SIZE_MAX,
+ "Proportional Size", "", 0.001f, 100.0f);
}
if (flags & P_SNAP) {
@@ -686,7 +687,7 @@ static void TRANSFORM_OT_tilt(struct wmOperatorType *ot)
{
/* identifiers */
ot->name = "Tilt";
- /* optionals -
+ /* optional -
* "Tilt selected vertices"
* "Specify an extra axis rotation for selected vertices of 3D curve" */
ot->description = "Tilt selected control vertices of 3D curve";
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 59d2485c964..90a4aa3614d 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -636,7 +636,7 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- BM_face_calc_plane(efa, vec);
+ BM_face_calc_tangent_auto(efa, vec);
add_v3_v3(normal, efa->no);
add_v3_v3(plane, vec);
}
@@ -690,7 +690,7 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3
sub_v3_v3v3(plane, v_pair[0]->co, v_pair[1]->co);
}
else {
- BM_vert_tri_calc_plane(v_tri, plane);
+ BM_vert_tri_calc_tangent_edge(v_tri, plane);
}
}
else {
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 38f1d37acd6..f8bb124e943 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -324,7 +324,7 @@ void applyProject(TransInfo *t)
if (ED_view3d_project_float_global(t->ar, iloc, mval_fl, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
if (snapObjectsTransform(
- t, mval_fl, t->tsnap.modeSelect, &dist_px,
+ t, mval_fl, &dist_px,
loc, no))
{
// if (t->flag & (T_EDIT|T_POSE)) {
@@ -553,10 +553,10 @@ static void initSnappingMode(TransInfo *t)
{
/* Exclude editmesh if using proportional edit */
if ((obedit->type == OB_MESH) && (t->flag & T_PROP_EDIT)) {
- t->tsnap.modeSelect = SNAP_NOT_OBEDIT;
+ t->tsnap.modeSelect = SNAP_NOT_ACTIVE;
}
else {
- t->tsnap.modeSelect = t->tsnap.snap_self ? SNAP_ALL : SNAP_NOT_OBEDIT;
+ t->tsnap.modeSelect = t->tsnap.snap_self ? SNAP_ALL : SNAP_NOT_ACTIVE;
}
}
/* Particles edit mode*/
@@ -599,15 +599,15 @@ static void initSnappingMode(TransInfo *t)
if (t->spacetype == SPACE_VIEW3D) {
if (t->tsnap.object_context == NULL) {
t->tsnap.object_context = ED_transform_snap_object_context_create_view3d(
- G.main, t->scene, SNAP_OBJECT_USE_CACHE,
- t->ar, t->view);
+ G.main, t->scene, SNAP_OBJECT_USE_CACHE,
+ t->ar, t->view);
ED_transform_snap_object_context_set_editmesh_callbacks(
- t->tsnap.object_context,
- (bool (*)(BMVert *, void *))BM_elem_cb_check_hflag_disabled,
- bm_edge_is_snap_target,
- bm_face_is_snap_target,
- SET_UINT_IN_POINTER((BM_ELEM_SELECT | BM_ELEM_HIDDEN)));
+ t->tsnap.object_context,
+ (bool (*)(BMVert *, void *))BM_elem_cb_check_hflag_disabled,
+ bm_edge_is_snap_target,
+ bm_face_is_snap_target,
+ SET_UINT_IN_POINTER((BM_ELEM_SELECT | BM_ELEM_HIDDEN)));
}
}
}
@@ -842,6 +842,14 @@ static void ApplySnapTranslation(TransInfo *t, float vec[3])
vec[1] = point[1] - t->tsnap.snapTarget[1];
}
else {
+ if (t->spacetype == SPACE_VIEW3D) {
+ if (t->options & CTX_PAINT_CURVE) {
+ if (ED_view3d_project_float_global(t->ar, point, point, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) {
+ zero_v3(point); /* no good answer here... */
+ }
+ }
+ }
+
sub_v3_v3v3(vec, point, t->tsnap.snapTarget);
}
}
@@ -964,27 +972,18 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
if (t->tsnap.mode == SCE_SNAP_MODE_VOLUME) {
found = peelObjectsTransform(
- t, mval, t->tsnap.modeSelect,
+ t, mval,
(t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0,
loc, no, NULL);
}
else {
zero_v3(no); /* objects won't set this */
found = snapObjectsTransform(
- t, mval, t->tsnap.modeSelect, &dist_px,
+ t, mval, &dist_px,
loc, no);
}
if (found == true) {
- float tangent[3];
-
- sub_v2_v2v2(tangent, loc, t->tsnap.snapPoint);
- tangent[2] = 0.0f;
-
- if (!is_zero_v3(tangent)) {
- copy_v3_v3(t->tsnap.snapTangent, tangent);
- }
-
copy_v3_v3(t->tsnap.snapPoint, loc);
copy_v3_v3(t->tsnap.snapNormal, no);
@@ -1207,17 +1206,16 @@ static void TargetSnapClosest(TransInfo *t)
}
bool snapObjectsTransform(
- TransInfo *t, const float mval[2], SnapSelect snap_select,
+ TransInfo *t, const float mval[2],
float *dist_px,
float r_loc[3], float r_no[3])
{
return ED_transform_snap_object_project_view3d_ex(
t->tsnap.object_context,
+ t->scene->toolsettings->snap_mode,
&(const struct SnapObjectParams){
- .snap_select = snap_select,
- .snap_to = t->scene->toolsettings->snap_mode,
- .use_object_edit = (t->flag & T_EDIT) != 0,
- .use_object_active = (t->options & CTX_GPENCIL_STROKES) == 0,
+ .snap_select = ((t->options & CTX_GPENCIL_STROKES) != 0) ? SNAP_NOT_ACTIVE : t->tsnap.modeSelect,
+ .use_object_edit_cage = (t->flag & T_EDIT) != 0,
},
mval, dist_px, NULL,
r_loc, r_no, NULL);
@@ -1228,18 +1226,16 @@ bool snapObjectsTransform(
bool peelObjectsSnapContext(
SnapObjectContext *sctx,
- const float mval[2], SnapSelect snap_select, bool use_peel_object,
+ const float mval[2],
+ const struct SnapObjectParams *params,
+ const bool use_peel_object,
/* return args */
float r_loc[3], float r_no[3], float *r_thickness)
{
ListBase depths_peel = {0};
ED_transform_snap_object_project_all_view3d_ex(
sctx,
- &(const struct SnapObjectParams){
- .snap_to = SCE_SNAP_MODE_FACE,
- .snap_select = snap_select,
- .use_object_edit = true,
- },
+ params,
mval, -1.0f, false,
&depths_peel);
@@ -1299,13 +1295,19 @@ bool peelObjectsSnapContext(
bool peelObjectsTransform(
TransInfo *t,
- const float mval[2], SnapSelect snap_select, bool use_peel_object,
+ const float mval[2],
+ const bool use_peel_object,
/* return args */
float r_loc[3], float r_no[3], float *r_thickness)
{
return peelObjectsSnapContext(
t->tsnap.object_context,
- mval, snap_select, use_peel_object,
+ mval,
+ &(const struct SnapObjectParams){
+ .snap_select = ((t->options & CTX_GPENCIL_STROKES) != 0) ? SNAP_NOT_ACTIVE : t->tsnap.modeSelect,
+ .use_object_edit_cage = (t->flag & T_EDIT) != 0,
+ },
+ use_peel_object,
r_loc, r_no, r_thickness);
}
@@ -1520,11 +1522,21 @@ static void applyGridIncrement(TransInfo *t, float *val, int max_index, const fl
/* absolute snapping on grid based on global center */
if ((t->tsnap.snap_spatial_grid) && (t->mode == TFM_TRANSLATION)) {
+ const float *center_global = t->center_global;
+
+ /* use a fallback for cursor selection,
+ * this isn't useful as a global center for absolute grid snapping
+ * since its not based on the position of the selection. */
+ if (t->around == V3D_AROUND_CURSOR) {
+ const TransCenterData *cd = transformCenter_from_type(t, V3D_AROUND_CENTER_MEAN);
+ center_global = cd->global;
+ }
+
for (i = 0; i <= max_index; i++) {
/* do not let unconstrained axis jump to absolute grid increments */
if (!(t->con.mode & CON_APPLY) || t->con.mode & (CON_AXIS0 << i)) {
const float iter_fac = fac[action] * asp[i];
- val[i] = iter_fac * roundf((val[i] + t->center_global[i]) / iter_fac) - t->center_global[i];
+ val[i] = iter_fac * roundf((val[i] + center_global[i]) / iter_fac) - center_global[i];
}
}
}
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index 17c77df58f2..02900d7022c 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -68,13 +68,13 @@ typedef struct SnapObjectData {
typedef struct SnapObjectData_Mesh {
SnapObjectData sd;
- BVHTreeFromMesh *bvh_trees[2];
+ BVHTreeFromMesh *bvh_trees[3];
} SnapObjectData_Mesh;
typedef struct SnapObjectData_EditMesh {
SnapObjectData sd;
- BVHTreeFromEditMesh *bvh_trees[2];
+ BVHTreeFromEditMesh *bvh_trees[3];
} SnapObjectData_EditMesh;
@@ -87,8 +87,8 @@ struct SnapObjectContext {
* otherwise this doesn't take viewport into account. */
bool use_v3d;
struct {
- struct View3D *v3d;
- struct ARegion *ar;
+ const struct View3D *v3d;
+ const struct ARegion *ar;
} v3d_data;
@@ -110,6 +110,12 @@ struct SnapObjectContext {
};
+enum eViewProj {
+ VIEW_PROJ_NONE = -1,
+ VIEW_PROJ_ORTHO = 0,
+ VIEW_PROJ_PERSP = -1,
+};
+
static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt);
@@ -137,10 +143,6 @@ struct RayCastAll_Data {
Object *ob;
unsigned int ob_uuid;
- /* DerivedMesh only */
- DerivedMesh *dm;
- const struct MLoopTri *dm_looptri;
-
/* output data */
ListBase *hit_list;
bool retval;
@@ -198,7 +200,7 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH
mul_m3_v3((float(*)[3])data->timat, normal);
normalize_v3(normal);
- /* currently unused, and causes issues when looptri's havn't been calculated.
+ /* currently unused, and causes issues when looptri's haven't been calculated.
* since theres some overhead in ensuring this data is valid, it may need to be optional. */
#if 0
if (data->dm) {
@@ -218,188 +220,557 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH
/* -------------------------------------------------------------------- */
-/** \name Internal Object Snapping API
+/** \Common utilities
* \{ */
-static bool snapEdge(
- ARegion *ar, const float v1co[3], const short v1no[3], const float v2co[3], const short v2no[3],
- float obmat[4][4], float timat[3][3], const float mval_fl[2], float *dist_px,
- const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], float *ray_depth,
- float r_loc[3], float r_no[3])
-{
- float intersect[3] = {0, 0, 0}, ray_end[3], dvec[3];
- int result;
- bool retval = false;
- copy_v3_v3(ray_end, ray_normal_local);
- mul_v3_fl(ray_end, 2000);
- add_v3_v3v3(ray_end, ray_start_local, ray_end);
+/**
+ * Struct that kepts basic information about a BVHTree build from a editmesh.
+ */
+typedef struct BVHTreeFromMeshType {
+ void *userdata;
+ char type;
+} BVHTreeFromMeshType;
+
+typedef struct PreDefProject {
+ float pmat[4][4]; /* perspective matrix multiplied by object matrix */
+ float win_half[2];
+ float dist_px_sq;
+} PreDefProject;
+
+static void precalc_project(
+ PreDefProject *projectdefs, const ARegion *ar,
+ const float dist_px, float obmat[4][4])
+{
+ float (*pmat)[4] = ((RegionView3D *)ar->regiondata)->persmat;
+ if (obmat) {
+ mul_m4_m4m4(projectdefs->pmat, pmat, obmat);
+ }
+ else {
+ copy_m4_m4(projectdefs->pmat, pmat);
+ }
+ projectdefs->win_half[0] = ar->winx / 2;
+ projectdefs->win_half[1] = ar->winy / 2;
+ projectdefs->dist_px_sq = SQUARE(dist_px);
+}
- /* dvec used but we don't care about result */
- result = isect_line_line_v3(v1co, v2co, ray_start_local, ray_end, intersect, dvec);
+/**
+ * From a threshold (maximum distance to snap in pixels) returns:
+ *
+ * - The *real* distance (3D) if you are in orthographic-view.
+ * - The *tangent* (view cone radius at distance 1.0) if you are in perspective-view.
+ */
+static float dist_px_to_dist3d_or_tangent(const ARegion *ar, const float dist_px)
+{
+ const RegionView3D *rv3d = ar->regiondata;
+ if (ar->winx >= ar->winy)
+ return 2 * (dist_px / ar->winx) / rv3d->winmat[0][0];
+ else
+ return 2 * (dist_px / ar->winy) / rv3d->winmat[1][1];
+}
- if (result) {
- float edge_loc[3], vec[3];
- float mul;
+static const float *get_vert_co(const BVHTreeFromMeshType *meshdata, const int index)
+{
+ switch (meshdata->type) {
+ case SNAP_MESH:
+ {
+ BVHTreeFromMesh *data = meshdata->userdata;
+ const MVert *vert = data->vert;
+ return vert[index].co;
+ }
+ case SNAP_EDIT_MESH:
+ {
+ BVHTreeFromEditMesh *data = meshdata->userdata;
+ BMVert *eve = BM_vert_at_index(data->em->bm, index);
+ return eve->co;
+ }
+ }
+ return NULL;
+}
- /* check for behind ray_start */
- sub_v3_v3v3(dvec, intersect, ray_start_local);
+static void copy_vert_no(const BVHTreeFromMeshType *meshdata, const int index, float r_no[3])
+{
+ switch (meshdata->type) {
+ case SNAP_MESH:
+ {
+ BVHTreeFromMesh *data = meshdata->userdata;
+ const MVert *vert = data->vert + index;
+ normal_short_to_float_v3(r_no, vert->no);
+ break;
+ }
+ case SNAP_EDIT_MESH:
+ {
+ BVHTreeFromEditMesh *data = meshdata->userdata;
+ BMVert *eve = BM_vert_at_index(data->em->bm, index);
+ copy_v3_v3(r_no, eve->no);
+ break;
+ }
+ }
+}
- sub_v3_v3v3(edge_loc, v1co, v2co);
- sub_v3_v3v3(vec, intersect, v2co);
+static void get_edge_verts(
+ const BVHTreeFromMeshType *meshdata, const int index,
+ const float *v_pair[2])
+{
+ switch (meshdata->type) {
+ case SNAP_MESH:
+ {
+ BVHTreeFromMesh *data = meshdata->userdata;
- mul = dot_v3v3(vec, edge_loc) / dot_v3v3(edge_loc, edge_loc);
+ const MVert *vert = data->vert;
+ const MEdge *edge = data->edge + index;
- if (mul > 1) {
- mul = 1;
- copy_v3_v3(intersect, v1co);
+ v_pair[0] = vert[edge->v1].co;
+ v_pair[1] = vert[edge->v2].co;
+ break;
}
- else if (mul < 0) {
- mul = 0;
- copy_v3_v3(intersect, v2co);
+ case SNAP_EDIT_MESH:
+ {
+ BVHTreeFromEditMesh *data = meshdata->userdata;
+ BMEdge *eed = BM_edge_at_index(data->em->bm, index);
+
+ v_pair[0] = eed->v1->co;
+ v_pair[1] = eed->v2->co;
+ break;
}
+ }
+}
- if (dot_v3v3(ray_normal_local, dvec) > 0) {
- float location[3];
- float new_depth;
- float screen_loc[2];
- float new_dist;
+#define V3_MUL_ELEM(a, b) \
+ (a)[0] * (b)[0], \
+ (a)[1] * (b)[1], \
+ (a)[2] * (b)[2]
- copy_v3_v3(location, intersect);
+static bool test_vert_dist(
+ const float vco[3], const float ray_co[3], const float ray_dir[3],
+ const float ray_depth_range[2], const float scale[3],
+ /* read/write args */
+ float *ray_depth, float *dist_to_ray_sq,
+ /* return args */
+ float r_co[3])
+{
+ const float vco_sc[3] = {V3_MUL_ELEM(vco, scale)};
+ const float origin_sc[3] = {V3_MUL_ELEM(ray_co, scale)};
+ const float dir_sc[3] = {V3_MUL_ELEM(ray_dir, scale)};
- mul_m4_v3(obmat, location);
+ float depth, dist_sq;
+ dist_sq = dist_squared_to_ray_v3(origin_sc, dir_sc, vco_sc, &depth);
- new_depth = len_v3v3(location, ray_start);
+ if (depth < ray_depth_range[0]) {
+ return false;
+ }
- if (ED_view3d_project_float_global(ar, location, screen_loc, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
- new_dist = len_manhattan_v2v2(mval_fl, screen_loc);
- }
- else {
- new_dist = TRANSFORM_DIST_MAX_PX;
- }
+ if ((dist_sq < *dist_to_ray_sq) && (depth < *ray_depth)) {
+ *dist_to_ray_sq = dist_sq;
- /* 10% threshold if edge is closer but a bit further
- * this takes care of series of connected edges a bit slanted w.r.t the viewport
- * otherwise, it would stick to the verts of the closest edge and not slide along merrily
- * */
- if (new_dist <= *dist_px && new_depth < *ray_depth * 1.001f) {
- float n1[3], n2[3];
+ copy_v3_v3(r_co, vco);
- *ray_depth = new_depth;
- retval = true;
+ *ray_depth = depth;
+ return true;
+ }
+ return false;
+}
- sub_v3_v3v3(edge_loc, v1co, v2co);
- sub_v3_v3v3(vec, intersect, v2co);
+static bool test_edge_dist(
+ const float v1[3], const float v2[3], const float ray_co[3], const float ray_dir[3],
+ const float ray_depth_range[2], const float scale[3],
+ /* read/write args */
+ float *ray_depth, float *dist_to_ray_sq,
+ /* return args */
+ float r_co[3])
+{
+ const float v1_sc[3] = {V3_MUL_ELEM(v1, scale)};
+ const float v2_sc[3] = {V3_MUL_ELEM(v2, scale)};
+ const float co_sc[3] = {V3_MUL_ELEM(ray_co, scale)};
+ const float dir_sc[3] = {V3_MUL_ELEM(ray_dir, scale)};
- mul = dot_v3v3(vec, edge_loc) / dot_v3v3(edge_loc, edge_loc);
+ float tmp_co[3], depth, dist_sq;
+ dist_sq = dist_squared_ray_to_seg_v3(co_sc, dir_sc, v1_sc, v2_sc, tmp_co, &depth);
- if (r_no) {
- normal_short_to_float_v3(n1, v1no);
- normal_short_to_float_v3(n2, v2no);
- interp_v3_v3v3(r_no, n2, n1, mul);
- mul_m3_v3(timat, r_no);
- normalize_v3(r_no);
- }
+ if (depth < ray_depth_range[0]) {
+ return false;
+ }
- copy_v3_v3(r_loc, location);
+ if ((dist_sq < *dist_to_ray_sq) && (depth < *ray_depth)) {
+ *dist_to_ray_sq = dist_sq;
- *dist_px = new_dist;
- }
+ tmp_co[0] /= scale[0];
+ tmp_co[1] /= scale[1];
+ tmp_co[2] /= scale[2];
+
+ copy_v3_v3(r_co, tmp_co);
+
+ *ray_depth = depth;
+ return true;
+ }
+ return false;
+}
+
+#undef V3_MUL_ELEM
+
+static bool test_projected_vert_dist(
+ PreDefProject *projectdefs,
+ const float co[3], const enum eViewProj view_proj,
+ const float mval[2], const float depth_range[2],
+ float r_co[3])
+{
+ float depth;
+ float(*pmat)[4] = projectdefs->pmat;
+ if (view_proj == VIEW_PROJ_PERSP) {
+ depth = mul_project_m4_v3_zfac(pmat, co);
+ if (depth < depth_range[0] || depth > depth_range[1]) {
+ return false;
}
}
- return retval;
+ float co2d[2] = {
+ (dot_m4_v3_row_x(pmat, co) + pmat[3][0]),
+ (dot_m4_v3_row_y(pmat, co) + pmat[3][1]),
+ };
+
+ if (view_proj == VIEW_PROJ_PERSP) {
+ mul_v2_fl(co2d, 1 / depth);
+ }
+
+ co2d[0] += 1.0f;
+ co2d[1] += 1.0f;
+ co2d[0] *= projectdefs->win_half[0];
+ co2d[1] *= projectdefs->win_half[1];
+
+ const float dist_sq = len_squared_v2v2(mval, co2d);
+ if (dist_sq < projectdefs->dist_px_sq) {
+ copy_v3_v3(r_co, co);
+ projectdefs->dist_px_sq = dist_sq;
+ return true;
+ }
+ return false;
}
-static bool snapVertex(
- ARegion *ar, const float vco[3], const float vno[3],
- float obmat[4][4], float timat[3][3], const float mval_fl[2], float *dist_px,
- const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], float *ray_depth,
- float r_loc[3], float r_no[3])
+static bool test_projected_edge_dist(
+ PreDefProject *projectdefs,
+ const float va[3], const float vb[3], const float ray_start[3], const float ray_normal[3],
+ const enum eViewProj view_proj, const float mval[2], const float depth_range[2],
+ float r_co[3])
{
- bool retval = false;
- float dvec[3];
- sub_v3_v3v3(dvec, vco, ray_start_local);
+ float tmp_co[3], depth;
+ dist_squared_ray_to_seg_v3(ray_start, ray_normal, va, vb, tmp_co, &depth);
+ return test_projected_vert_dist(projectdefs, tmp_co, view_proj, mval, depth_range, r_co);
+}
+
+/** \} */
- if (dot_v3v3(ray_normal_local, dvec) > 0) {
- float location[3];
- float new_depth;
- float screen_loc[2];
- float new_dist;
- copy_v3_v3(location, vco);
+/* -------------------------------------------------------------------- */
+
+/** \Walk DFS
+ * \{ */
+typedef struct Object_Nearest2dPrecalc {
+ float ray_origin_local[3];
+ float ray_direction_local[3];
+ float ray_inv_dir[3];
+
+ PreDefProject projectdefs;
+ float mval[2];
+ bool sign[3];
+ bool r_axis_closest[3];
+ float depth_range[2];
+
+ void *userdata;
+ int index;
+ float co[3];
+ float no[3];
+} Object_Nearest2dPrecalc;
+
+
+static void nearest2d_precalc(
+ Object_Nearest2dPrecalc *neasrest_precalc, const ARegion *ar,
+ const float dist_px, float obmat[4][4],
+ const float ray_origin_local[3], const float ray_direction_local[3],
+ const float mval[2], const float depth_range[2])
+{
+ precalc_project(&neasrest_precalc->projectdefs, ar, dist_px, obmat);
+ copy_v3_v3(neasrest_precalc->ray_origin_local, ray_origin_local);
+ copy_v3_v3(neasrest_precalc->ray_direction_local, ray_direction_local);
+ copy_v2_v2(neasrest_precalc->mval, mval);
+ copy_v2_v2(neasrest_precalc->depth_range, depth_range);
+
+ for (int i = 0; i < 3; i++) {
+ neasrest_precalc->ray_inv_dir[i] =
+ (neasrest_precalc->ray_direction_local[i] != 0.0f) ?
+ (1.0f / neasrest_precalc->ray_direction_local[i]) : FLT_MAX;
+ neasrest_precalc->sign[i] = (neasrest_precalc->ray_inv_dir[i] < 0.0f);
+ neasrest_precalc->r_axis_closest[i] = true;
+ }
+}
+
+static bool cb_walk_parent_snap_project(const BVHTreeAxisRange *bounds, void *user_data)
+{
+ Object_Nearest2dPrecalc *data = user_data;
+ float local_bvmin[3], local_bvmax[3];
+ if (data->sign[0]) {
+ local_bvmin[0] = bounds[0].max;
+ local_bvmax[0] = bounds[0].min;
+ }
+ else {
+ local_bvmin[0] = bounds[0].min;
+ local_bvmax[0] = bounds[0].max;
+ }
+ if (data->sign[1]) {
+ local_bvmin[1] = bounds[1].max;
+ local_bvmax[1] = bounds[1].min;
+ }
+ else {
+ local_bvmin[1] = bounds[1].min;
+ local_bvmax[1] = bounds[1].max;
+ }
+ if (data->sign[2]) {
+ local_bvmin[2] = bounds[2].max;
+ local_bvmax[2] = bounds[2].min;
+ }
+ else {
+ local_bvmin[2] = bounds[2].min;
+ local_bvmax[2] = bounds[2].max;
+ }
- mul_m4_v3(obmat, location);
+ const float tmin[3] = {
+ (local_bvmin[0] - data->ray_origin_local[0]) * data->ray_inv_dir[0],
+ (local_bvmin[1] - data->ray_origin_local[1]) * data->ray_inv_dir[1],
+ (local_bvmin[2] - data->ray_origin_local[2]) * data->ray_inv_dir[2],
+ };
+ const float tmax[3] = {
+ (local_bvmax[0] - data->ray_origin_local[0]) * data->ray_inv_dir[0],
+ (local_bvmax[1] - data->ray_origin_local[1]) * data->ray_inv_dir[1],
+ (local_bvmax[2] - data->ray_origin_local[2]) * data->ray_inv_dir[2],
+ };
+ float va[3], vb[3];
+ float rtmin, rtmax;
+ int main_axis;
+
+ if ((tmax[0] <= tmax[1]) && (tmax[0] <= tmax[2])) {
+ rtmax = tmax[0];
+ va[0] = vb[0] = local_bvmax[0];
+ main_axis = 3;
+ data->r_axis_closest[0] = data->sign[0];
+ }
+ else if ((tmax[1] <= tmax[0]) && (tmax[1] <= tmax[2])) {
+ rtmax = tmax[1];
+ va[1] = vb[1] = local_bvmax[1];
+ main_axis = 2;
+ data->r_axis_closest[1] = data->sign[1];
+ }
+ else {
+ rtmax = tmax[2];
+ va[2] = vb[2] = local_bvmax[2];
+ main_axis = 1;
+ data->r_axis_closest[2] = data->sign[2];
+ }
- new_depth = len_v3v3(location, ray_start);
+ if ((tmin[0] >= tmin[1]) && (tmin[0] >= tmin[2])) {
+ rtmin = tmin[0];
+ va[0] = vb[0] = local_bvmin[0];
+ main_axis -= 3;
+ data->r_axis_closest[0] = !data->sign[0];
+ }
+ else if ((tmin[1] >= tmin[0]) && (tmin[1] >= tmin[2])) {
+ rtmin = tmin[1];
+ va[1] = vb[1] = local_bvmin[1];
+ main_axis -= 1;
+ data->r_axis_closest[1] = !data->sign[1];
+ }
+ else {
+ rtmin = tmin[2];
+ va[2] = vb[2] = local_bvmin[2];
+ main_axis -= 2;
+ data->r_axis_closest[2] = !data->sign[2];
+ }
+ if (main_axis < 0) {
+ main_axis += 3;
+ }
- if (ED_view3d_project_float_global(ar, location, screen_loc, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
- new_dist = len_manhattan_v2v2(mval_fl, screen_loc);
+ /* if rtmin < rtmax, ray intersect `AABB` */
+ if (rtmin <= rtmax) {
+#ifdef IGNORE_BEHIND_RAY
+ /* `if rtmax < depth_min`, the whole `AABB` is behind us */
+ if (rtmax < min_depth) {
+ return fallback;
+ }
+#endif
+ const float proj = rtmin * data->ray_direction_local[main_axis];
+ data->r_axis_closest[main_axis] = (proj - va[main_axis]) < (vb[main_axis] - proj);
+ return true;
+ }
+#ifdef IGNORE_BEHIND_RAY
+ /* `if rtmin < depth_min`, the whole `AABB` is behing us */
+ else if (rtmin < min_depth) {
+ return fallback;
+ }
+#endif
+ if (data->sign[main_axis]) {
+ va[main_axis] = local_bvmax[main_axis];
+ vb[main_axis] = local_bvmin[main_axis];
+ }
+ else {
+ va[main_axis] = local_bvmin[main_axis];
+ vb[main_axis] = local_bvmax[main_axis];
+ }
+ float scale = fabsf(local_bvmax[main_axis] - local_bvmin[main_axis]);
+
+ float (*pmat)[4] = data->projectdefs.pmat;
+ float depth_a = mul_project_m4_v3_zfac(pmat, va);
+ float depth_b = depth_a + pmat[main_axis][3] * scale;
+
+ float va2d[2] = {
+ (dot_m4_v3_row_x(pmat, va) + pmat[3][0]),
+ (dot_m4_v3_row_y(pmat, va) + pmat[3][1]),
+ };
+ float vb2d[2] = {
+ (va2d[0] + pmat[main_axis][0] * scale) / depth_b,
+ (va2d[1] + pmat[main_axis][1] * scale) / depth_b,
+ };
+
+ va2d[0] /= depth_a;
+ va2d[1] /= depth_a;
+
+ va2d[0] += 1.0f;
+ va2d[1] += 1.0f;
+ vb2d[0] += 1.0f;
+ vb2d[1] += 1.0f;
+
+ va2d[0] *= data->projectdefs.win_half[0];
+ va2d[1] *= data->projectdefs.win_half[1];
+ vb2d[0] *= data->projectdefs.win_half[0];
+ vb2d[1] *= data->projectdefs.win_half[1];
+
+ //float dvec[2], edge[2], rdist;
+ //sub_v2_v2v2(dvec, data->mval, va2d);
+ //sub_v2_v2v2(edge, vb2d, va2d);
+ float rdist;
+ short dvec[2] = {data->mval[0] - va2d[0], data->mval[1] - va2d[1]};
+ short edge[2] = {vb2d[0] - va2d[0], vb2d[1] - va2d[1]};
+ float lambda = dvec[0] * edge[0] + dvec[1] * edge[1];
+ if (lambda != 0.0f) {
+ lambda /= edge[0] * edge[0] + edge[1] * edge[1];
+ if (lambda <= 0.0f) {
+ rdist = len_squared_v2v2(data->mval, va2d);
+ data->r_axis_closest[main_axis] = true;
+ }
+ else if (lambda >= 1.0f) {
+ rdist = len_squared_v2v2(data->mval, vb2d);
+ data->r_axis_closest[main_axis] = false;
}
else {
- new_dist = TRANSFORM_DIST_MAX_PX;
+ va2d[0] += edge[0] * lambda;
+ va2d[1] += edge[1] * lambda;
+ rdist = len_squared_v2v2(data->mval, va2d);
+ data->r_axis_closest[main_axis] = lambda < 0.5f;
}
+ }
+ else {
+ rdist = len_squared_v2v2(data->mval, va2d);
+ }
+ return rdist < data->projectdefs.dist_px_sq;
+}
+static bool cb_walk_leaf_snap_vert(const BVHTreeAxisRange *bounds, int index, void *userdata)
+{
+ struct Object_Nearest2dPrecalc *neasrest_precalc = userdata;
+ const float co[3] = {
+ (bounds[0].min + bounds[0].max) / 2,
+ (bounds[1].min + bounds[1].max) / 2,
+ (bounds[2].min + bounds[2].max) / 2,
+ };
+
+ /* Currently the `BLI_bvhtree_walk_dfs` is being used only in the perspective view mode (VIEW_PROJ_PERSP)
+ * It could be used in orthographic view mode too (VIEW_PROJ_ORTHO),
+ * but in this case the `BLI_bvhtree_find_nearest_to_ray` is more efficient.*/
+ if (test_projected_vert_dist(
+ &neasrest_precalc->projectdefs, co, VIEW_PROJ_PERSP,
+ neasrest_precalc->mval, neasrest_precalc->depth_range,
+ neasrest_precalc->co))
+ {
+ copy_vert_no(neasrest_precalc->userdata, index, neasrest_precalc->no);
+ neasrest_precalc->index = index;
+ }
+ return true;
+}
- if (new_dist <= *dist_px && new_depth < *ray_depth) {
- *ray_depth = new_depth;
- retval = true;
+static bool cb_walk_leaf_snap_edge(const BVHTreeAxisRange *UNUSED(bounds), int index, void *userdata)
+{
+ struct Object_Nearest2dPrecalc *neasrest_precalc = userdata;
+
+ const float *v_pair[2];
+ get_edge_verts(neasrest_precalc->userdata, index, v_pair);
+
+ /* Currently the `BLI_bvhtree_walk_dfs` is being used only in the perspective view mode (VIEW_PROJ_PERSP)
+ * It could be used in orthographic view mode too (VIEW_PROJ_ORTHO),
+ * but in this case the `BLI_bvhtree_find_nearest_to_ray` is more efficient.*/
+ if (test_projected_edge_dist(
+ &neasrest_precalc->projectdefs, v_pair[0], v_pair[1],
+ neasrest_precalc->ray_origin_local, neasrest_precalc->ray_direction_local,
+ VIEW_PROJ_PERSP, neasrest_precalc->mval, neasrest_precalc->depth_range,
+ neasrest_precalc->co))
+ {
+ sub_v3_v3v3(neasrest_precalc->no, v_pair[0], v_pair[1]);
+ neasrest_precalc->index = index;
+ }
+ return true;
+}
- copy_v3_v3(r_loc, location);
+static bool cb_nearest_walk_order(const BVHTreeAxisRange *UNUSED(bounds), char axis, void *userdata)
+{
+ const bool *r_axis_closest = ((struct Object_Nearest2dPrecalc *)userdata)->r_axis_closest;
+ return r_axis_closest[axis];
+}
- if (r_no) {
- copy_v3_v3(r_no, vno);
- mul_m3_v3(timat, r_no);
- normalize_v3(r_no);
- }
+/** \} */
- *dist_px = new_dist;
- }
- }
+/* -------------------------------------------------------------------- */
- return retval;
-}
+/** \name Internal Object Snapping API
+ * \{ */
static bool snapArmature(
- ARegion *ar, Object *ob, bArmature *arm, float obmat[4][4],
- const float mval[2], float *dist_px, const short snap_to,
- const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ const ARegion *ar, Object *ob, bArmature *arm, float obmat[4][4],
+ const short snap_to, const float origin[3], const float dir[3],
+ const float mval[2], const enum eViewProj view_proj, const float depth_range[2],
+ /* read/write args */
+ float *dist_px,
+ /* return args */
float r_loc[3], float *UNUSED(r_no))
{
- float imat[4][4];
- float ray_start_local[3], ray_normal_local[3];
bool retval = false;
- invert_m4_m4(imat, obmat);
+ float ray_start_local[3], ray_normal_local[3];
+ if (snap_to != SCE_SNAP_MODE_VERTEX) {
+ float imat[4][4];
+ invert_m4_m4(imat, obmat);
+
+ copy_v3_v3(ray_start_local, origin);
+ copy_v3_v3(ray_normal_local, dir);
+ mul_m4_v3(imat, ray_start_local);
+ mul_mat3_m4_v3(imat, ray_normal_local);
+ }
- mul_v3_m4v3(ray_start_local, imat, ray_start);
- mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal);
+ PreDefProject projectdefs;
+ precalc_project(&projectdefs, ar, *dist_px, obmat);
if (arm->edbo) {
- EditBone *eBone;
-
- for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
+ for (EditBone *eBone = arm->edbo->first; eBone; eBone = eBone->next) {
if (eBone->layer & arm->layer) {
/* skip hidden or moving (selected) bones */
if ((eBone->flag & (BONE_HIDDEN_A | BONE_ROOTSEL | BONE_TIPSEL)) == 0) {
switch (snap_to) {
case SCE_SNAP_MODE_VERTEX:
- retval |= snapVertex(
- ar, eBone->head, NULL, obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
- r_loc, NULL);
- retval |= snapVertex(
- ar, eBone->tail, NULL, obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
- r_loc, NULL);
+ retval |= test_projected_vert_dist(
+ &projectdefs, eBone->head, view_proj, mval, depth_range, r_loc);
+ retval |= test_projected_vert_dist(
+ &projectdefs, eBone->tail, view_proj, mval, depth_range, r_loc);
break;
case SCE_SNAP_MODE_EDGE:
- retval |= snapEdge(
- ar, eBone->head, NULL, eBone->tail, NULL,
- obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local,
- ray_depth, r_loc, NULL);
+ retval |= test_projected_edge_dist(
+ &projectdefs, eBone->head, eBone->tail, ray_start_local, ray_normal_local,
+ view_proj, mval, depth_range, r_loc);
break;
}
}
@@ -407,11 +778,8 @@ static bool snapArmature(
}
}
else if (ob->pose && ob->pose->chanbase.first) {
- bPoseChannel *pchan;
- Bone *bone;
-
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- bone = pchan->bone;
+ for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ Bone *bone = pchan->bone;
/* skip hidden bones */
if (bone && !(bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) {
const float *head_vec = pchan->pose_head;
@@ -419,58 +787,49 @@ static bool snapArmature(
switch (snap_to) {
case SCE_SNAP_MODE_VERTEX:
- retval |= snapVertex(
- ar, head_vec, NULL, obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local,
- ray_depth, r_loc, NULL);
- retval |= snapVertex(
- ar, tail_vec, NULL, obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
- r_loc, NULL);
+ retval |= test_projected_vert_dist(
+ &projectdefs, head_vec, view_proj, mval, depth_range, r_loc);
+ retval |= test_projected_vert_dist(
+ &projectdefs, tail_vec, view_proj, mval, depth_range, r_loc);
break;
case SCE_SNAP_MODE_EDGE:
- retval |= snapEdge(
- ar, head_vec, NULL, tail_vec, NULL,
- obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local,
- ray_depth, r_loc, NULL);
+ retval |= test_projected_edge_dist(
+ &projectdefs, head_vec, tail_vec, ray_start_local, ray_normal_local,
+ view_proj, mval, depth_range, r_loc);
break;
}
}
}
}
-
- return retval;
+ if (retval) {
+ *dist_px = sqrtf(projectdefs.dist_px_sq);
+ mul_m4_v3(obmat, r_loc);
+ return true;
+ }
+ return false;
}
static bool snapCurve(
- ARegion *ar, Object *ob, Curve *cu, float obmat[4][4],
- const float mval[2], float *dist_px, const short snap_to,
- const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ const ARegion *ar, Object *ob, Curve *cu, float obmat[4][4],
+ const short snap_to, const float mval[2], const enum eViewProj view_proj,
+ const float depth_range[2],
+ /* read/write args */
+ float *dist_px,
+ /* return args */
float r_loc[3], float *UNUSED(r_no))
{
- float imat[4][4];
- float ray_start_local[3], ray_normal_local[3];
bool retval = false;
- int u;
-
- Nurb *nu;
/* only vertex snapping mode (eg control points and handles) supported for now) */
if (snap_to != SCE_SNAP_MODE_VERTEX) {
return retval;
}
- invert_m4_m4(imat, obmat);
+ PreDefProject projectdefs;
+ precalc_project(&projectdefs, ar, *dist_px, obmat);
- copy_v3_v3(ray_start_local, ray_start);
- copy_v3_v3(ray_normal_local, ray_normal);
-
- mul_m4_v3(imat, ray_start_local);
- mul_mat3_m4_v3(imat, ray_normal_local);
-
- for (nu = (ob->mode == OB_MODE_EDIT ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) {
- for (u = 0; u < nu->pntsu; u++) {
+ for (Nurb *nu = (ob->mode == OB_MODE_EDIT ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) {
+ for (int u = 0; u < nu->pntsu; u++) {
switch (snap_to) {
case SCE_SNAP_MODE_VERTEX:
{
@@ -480,26 +839,20 @@ static bool snapCurve(
if (nu->bezt[u].f2 & SELECT || nu->bezt[u].hide != 0) {
break;
}
- retval |= snapVertex(
- ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
- r_loc, NULL);
+ retval |= test_projected_vert_dist(
+ &projectdefs, nu->bezt[u].vec[1], view_proj, mval, depth_range, r_loc);
/* don't snap if handle is selected (moving), or if it is aligning to a moving handle */
if (!(nu->bezt[u].f1 & SELECT) &&
!(nu->bezt[u].h1 & HD_ALIGN && nu->bezt[u].f3 & SELECT))
{
- retval |= snapVertex(
- ar, nu->bezt[u].vec[0], NULL, obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
- r_loc, NULL);
+ retval |= test_projected_vert_dist(
+ &projectdefs, nu->bezt[u].vec[0], view_proj, mval, depth_range, r_loc);
}
if (!(nu->bezt[u].f3 & SELECT) &&
!(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT))
{
- retval |= snapVertex(
- ar, nu->bezt[u].vec[2], NULL, obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
- r_loc, NULL);
+ retval |= test_projected_vert_dist(
+ &projectdefs, nu->bezt[u].vec[2], view_proj, mval, depth_range, r_loc);
}
}
else {
@@ -507,26 +860,20 @@ static bool snapCurve(
if (nu->bp[u].f1 & SELECT || nu->bp[u].hide != 0) {
break;
}
- retval |= snapVertex(
- ar, nu->bp[u].vec, NULL, obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
- r_loc, NULL);
+ retval |= test_projected_vert_dist(
+ &projectdefs, nu->bp[u].vec, view_proj, mval, depth_range, r_loc);
}
}
else {
/* curve is not visible outside editmode if nurb length less than two */
if (nu->pntsu > 1) {
if (nu->bezt) {
- retval |= snapVertex(
- ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
- r_loc, NULL);
+ retval |= test_projected_vert_dist(
+ &projectdefs, nu->bezt[u].vec[1], view_proj, mval, depth_range, r_loc);
}
else {
- retval |= snapVertex(
- ar, nu->bp[u].vec, NULL, obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
- r_loc, NULL);
+ retval |= test_projected_vert_dist(
+ &projectdefs, nu->bp[u].vec, view_proj, mval, depth_range, r_loc);
}
}
}
@@ -537,41 +884,42 @@ static bool snapCurve(
}
}
}
- return retval;
+ if (retval) {
+ *dist_px = sqrtf(projectdefs.dist_px_sq);
+ mul_m4_v3(obmat, r_loc);
+ return true;
+ }
+ return false;
}
/* may extend later (for now just snaps to empty center) */
static bool snapEmpty(
- ARegion *ar, Object *ob, float obmat[4][4],
- const float mval[2], float *dist_px, const short snap_to,
- const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ const ARegion *ar, Object *ob, float obmat[4][4],
+ const short snap_to, const float mval[2], const enum eViewProj view_proj,
+ const float depth_range[2],
+ /* read/write args */
+ float *dist_px,
+ /* return args */
float r_loc[3], float *UNUSED(r_no))
{
- float imat[4][4];
- float ray_start_local[3], ray_normal_local[3];
bool retval = false;
if (ob->transflag & OB_DUPLI) {
return retval;
}
- /* for now only vertex supported */
- if (snap_to != SCE_SNAP_MODE_VERTEX) {
- return retval;
- }
-
- invert_m4_m4(imat, obmat);
-
- mul_v3_m4v3(ray_start_local, imat, ray_start);
- mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal);
+ /* for now only vertex supported */
switch (snap_to) {
case SCE_SNAP_MODE_VERTEX:
{
- const float zero_co[3] = {0.0f};
- retval |= snapVertex(
- ar, zero_co, NULL, obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
- r_loc, NULL);
+ PreDefProject projectdefs;
+ precalc_project(&projectdefs, ar, *dist_px, NULL);
+ float tmp_co[3];
+ copy_v3_v3(tmp_co, obmat[3]);
+ if (test_projected_vert_dist(&projectdefs, tmp_co, view_proj, mval, depth_range, r_loc)) {
+ *dist_px = sqrtf(projectdefs.dist_px_sq);
+ retval = true;
+ }
break;
}
default:
@@ -582,16 +930,23 @@ static bool snapEmpty(
}
static bool snapCamera(
- ARegion *ar, Scene *scene, Object *object, float obmat[4][4],
- const float mval[2], float *dist_px, const short snap_to,
- const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ const SnapObjectContext *sctx, Object *object, float obmat[4][4],
+ const short snap_to, const float mval[2], const enum eViewProj view_proj,
+ const float depth_range[2],
+ /* read/write args */
+ float *dist_px,
+ /* return args */
float r_loc[3], float *UNUSED(r_no))
{
+ Scene *scene = sctx->scene;
+
+ PreDefProject projectdefs;
+ precalc_project(&projectdefs, sctx->v3d_data.ar, *dist_px, NULL);
+
float orig_camera_mat[4][4], orig_camera_imat[4][4], imat[4][4];
bool retval = false;
MovieClip *clip = BKE_object_movieclip_get(scene, object, false);
MovieTracking *tracking;
- float ray_start_local[3], ray_normal_local[3];
if (clip == NULL) {
return retval;
@@ -622,9 +977,6 @@ static bool snapCamera(
reconstructed_camera_imat[4][4];
float (*vertex_obmat)[4];
- copy_v3_v3(ray_start_local, ray_start);
- copy_v3_v3(ray_normal_local, ray_normal);
-
if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) {
BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object,
CFRA, reconstructed_camera_mat);
@@ -641,21 +993,16 @@ static bool snapCamera(
copy_v3_v3(bundle_pos, track->bundle_pos);
if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
- mul_m4_v3(orig_camera_imat, ray_start_local);
- mul_mat3_m4_v3(orig_camera_imat, ray_normal_local);
vertex_obmat = orig_camera_mat;
}
else {
mul_m4_v3(reconstructed_camera_imat, bundle_pos);
- mul_m4_v3(imat, ray_start_local);
- mul_mat3_m4_v3(imat, ray_normal_local);
vertex_obmat = obmat;
}
- retval |= snapVertex(
- ar, bundle_pos, NULL, vertex_obmat, NULL, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
- r_loc, NULL);
+ mul_m4_v3(vertex_obmat, bundle_pos);
+ retval |= test_projected_vert_dist(
+ &projectdefs, bundle_pos, view_proj, mval, depth_range, r_loc);
}
}
@@ -665,7 +1012,11 @@ static bool snapCamera(
break;
}
- return retval;
+ if (retval) {
+ *dist_px = sqrtf(projectdefs.dist_px_sq);
+ return true;
+ }
+ return false;
}
static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt)
@@ -674,24 +1025,83 @@ static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt)
return index_mp_to_orig ? index_mp_to_orig[lt->poly] : lt->poly;
}
+struct NearestDM_Data {
+ void *bvhdata;
+ const float *depth_range;
+ float *ray_depth;
+};
+
+static void test_vert_ray_dist_cb(
+ void *userdata, const float origin[3], const float dir[3],
+ const float scale[3], int index, BVHTreeNearest *nearest)
+{
+ struct NearestDM_Data *ndata = userdata;
+ const struct BVHTreeFromMeshType *data = ndata->bvhdata;
+
+ const float *co = get_vert_co(data, index);
+
+ if (test_vert_dist(
+ co, origin, dir, ndata->depth_range,
+ scale, ndata->ray_depth, &nearest->dist_sq,
+ nearest->co))
+ {
+ copy_vert_no(data, index, nearest->no);
+ nearest->index = index;
+ }
+}
+
+static void test_edge_ray_dist_cb(
+ void *userdata, const float origin[3], const float dir[3],
+ const float scale[3], int index, BVHTreeNearest *nearest)
+{
+ struct NearestDM_Data *ndata = userdata;
+ BVHTreeFromMeshType *data = ndata->bvhdata;
+
+ const float *v_pair[2];
+ get_edge_verts(data, index, v_pair);
+
+ if (test_edge_dist(
+ v_pair[0], v_pair[1], origin, dir, ndata->depth_range,
+ scale, ndata->ray_depth, &nearest->dist_sq,
+ nearest->co))
+ {
+ sub_v3_v3v3(nearest->no, v_pair[0], v_pair[1]);
+ nearest->index = index;
+ }
+}
+
static bool snapDerivedMesh(
SnapObjectContext *sctx,
- Object *ob, DerivedMesh *dm, float obmat[4][4],
- const float mval[2], float *dist_px, const short snap_to, bool do_bb,
- const float ray_start[3], const float ray_normal[3], const float ray_origin[3],
- float *ray_depth, unsigned int ob_index,
+ Object *ob, DerivedMesh *dm, float obmat[4][4], const unsigned int ob_index,
+ const short snap_to, const float mval[2], const enum eViewProj view_proj, bool do_bb,
+ const float ray_origin[3], const float ray_start[3], const float ray_normal[3],
+ const float depth_range[2],
+ /* read/write args */
+ float *ray_depth, float *dist_px,
+ /* return args */
float r_loc[3], float r_no[3], int *r_index,
ListBase *r_hit_list)
{
- ARegion *ar = sctx->v3d_data.ar;
bool retval = false;
- int totvert = dm->getNumVerts(dm);
- if (totvert > 0) {
- const bool do_ray_start_correction = (
- ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX) &&
- (sctx->use_v3d && !((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp));
- bool need_ray_start_correction_init = do_ray_start_correction;
+ if (snap_to == SCE_SNAP_MODE_FACE) {
+ if (dm->getNumPolys(dm) == 0) {
+ return retval;
+ }
+ }
+ else if (snap_to == SCE_SNAP_MODE_EDGE) {
+ if (dm->getNumEdges(dm) == 0) {
+ return retval;
+ }
+ }
+ else {
+ if (dm->getNumVerts(dm) == 0) {
+ return retval;
+ }
+ }
+
+ {
+ bool need_ray_start_correction_init = (snap_to == SCE_SNAP_MODE_FACE) && (view_proj == VIEW_PROJ_ORTHO);
float imat[4][4];
float timat[3][3]; /* transpose inverse matrix for normals */
@@ -720,7 +1130,7 @@ static bool snapDerivedMesh(
if (bb) {
BoundBox bb_temp;
- /* We cannot aford a bbox with some null dimension, which may happen in some cases...
+ /* We cannot afford a bounding box with some null dimension, which may happen in some cases...
* Threshold is rather high, but seems to be needed to get good behavior, see T46099. */
bb = BKE_boundbox_ensure_minimum_dimensions(bb, &bb_temp, 1e-1f);
@@ -757,6 +1167,9 @@ static bool snapDerivedMesh(
int tree_index = -1;
switch (snap_to) {
case SCE_SNAP_MODE_FACE:
+ tree_index = 2;
+ break;
+ case SCE_SNAP_MODE_EDGE:
tree_index = 1;
break;
case SCE_SNAP_MODE_VERTEX:
@@ -771,18 +1184,15 @@ static bool snapDerivedMesh(
/* the tree is owned by the DM and may have been freed since we last used! */
if (treedata && treedata->tree) {
- if (BLI_linklist_index(dm->bvhCache, treedata->tree) == -1) {
+ if (treedata->cached && !bvhcache_has_tree(dm->bvhCache, treedata->tree)) {
free_bvhtree_from_mesh(treedata);
-
}
}
}
}
else {
- if (ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX)) {
- treedata = &treedata_stack;
- memset(treedata, 0, sizeof(*treedata));
- }
+ treedata = &treedata_stack;
+ memset(treedata, 0, sizeof(*treedata));
}
if (treedata && treedata->tree == NULL) {
@@ -790,144 +1200,182 @@ static bool snapDerivedMesh(
case SCE_SNAP_MODE_FACE:
bvhtree_from_mesh_looptri(treedata, dm, 0.0f, 4, 6);
break;
+ case SCE_SNAP_MODE_EDGE:
+ bvhtree_from_mesh_edges(treedata, dm, 0.0f, 2, 6);
+ break;
case SCE_SNAP_MODE_VERTEX:
bvhtree_from_mesh_verts(treedata, dm, 0.0f, 2, 6);
break;
}
}
- if (need_ray_start_correction_init) {
- /* We *need* a reasonably valid len_diff in this case.
- * Use BHVTree to find the closest face from ray_start_local.
+ if (!treedata || !treedata->tree) {
+ return retval;
+ }
+
+ if (snap_to == SCE_SNAP_MODE_FACE) {
+ /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already
+ * been *inside* boundbox, leading to snap failures (see T38409).
+ * Note also ar might be null (see T38435), in this case we assume ray_start is ok!
*/
- if (treedata && treedata->tree != NULL) {
- BVHTreeNearest nearest;
- nearest.index = -1;
- nearest.dist_sq = FLT_MAX;
- /* Compute and store result. */
- BLI_bvhtree_find_nearest(
- treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata);
- if (nearest.index != -1) {
- len_diff = sqrtf(nearest.dist_sq);
+ if (view_proj == VIEW_PROJ_ORTHO) { /* do_ray_start_correction */
+ if (need_ray_start_correction_init) {
+ /* We *need* a reasonably valid len_diff in this case.
+ * Use BHVTree to find the closest face from ray_start_local.
+ */
+ BVHTreeNearest nearest;
+ nearest.index = -1;
+ nearest.dist_sq = FLT_MAX;
+ /* Compute and store result. */
+ BLI_bvhtree_find_nearest(
+ treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata);
+ if (nearest.index != -1) {
+ float dvec[3];
+ sub_v3_v3v3(dvec, nearest.co, ray_start_local);
+ len_diff = dot_v3v3(dvec, ray_normal_local);
+ }
}
+ float ray_org_local[3];
+
+ copy_v3_v3(ray_org_local, ray_origin);
+ mul_m4_v3(imat, ray_org_local);
+
+ /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with very far
+ * away ray_start values (as returned in case of ortho view3d), see T38358.
+ */
+ len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
+ madd_v3_v3v3fl(
+ ray_start_local, ray_org_local, ray_normal_local, len_diff + depth_range[0] * local_scale);
+ local_depth -= len_diff;
}
- }
- /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already
- * been *inside* boundbox, leading to snap failures (see T38409).
- * Note also ar might be null (see T38435), in this case we assume ray_start is ok!
- */
- if (do_ray_start_correction) {
- float ray_org_local[3];
+ else {
+ len_diff = 0.0f;
+ }
+ if (r_hit_list) {
+ struct RayCastAll_Data data;
+
+ data.bvhdata = treedata;
+ data.raycast_callback = treedata->raycast_callback;
+ data.obmat = obmat;
+ data.timat = timat;
+ data.len_diff = len_diff;
+ data.local_scale = local_scale;
+ data.ob = ob;
+ data.ob_uuid = ob_index;
+ data.hit_list = r_hit_list;
+ data.retval = retval;
+
+ BLI_bvhtree_ray_cast_all(
+ treedata->tree, ray_start_local, ray_normal_local, 0.0f,
+ *ray_depth, raycast_all_cb, &data);
+
+ retval = data.retval;
+ }
+ else {
+ BVHTreeRayHit hit = {.index = -1, .dist = local_depth};
- copy_v3_v3(ray_org_local, ray_origin);
- mul_m4_v3(imat, ray_org_local);
+ if (BLI_bvhtree_ray_cast(
+ treedata->tree, ray_start_local, ray_normal_local, 0.0f,
+ &hit, treedata->raycast_callback, treedata) != -1)
+ {
+ hit.dist += len_diff;
+ hit.dist /= local_scale;
+ if (hit.dist <= *ray_depth) {
+ *ray_depth = hit.dist;
+ copy_v3_v3(r_loc, hit.co);
- /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with very far
- * away ray_start values (as returned in case of ortho view3d), see T38358.
- */
- len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
- madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local,
- len_diff - len_v3v3(ray_start_local, ray_org_local));
- local_depth -= len_diff;
- }
- else {
- len_diff = 0.0f;
- }
+ /* back to worldspace */
+ mul_m4_v3(obmat, r_loc);
- switch (snap_to) {
- case SCE_SNAP_MODE_FACE:
- {
- if (r_hit_list) {
- struct RayCastAll_Data data;
-
- data.bvhdata = treedata;
- data.raycast_callback = treedata->raycast_callback;
- data.obmat = obmat;
- data.timat = timat;
- data.len_diff = len_diff;
- data.local_scale = local_scale;
- data.ob = ob;
- data.ob_uuid = ob_index,
- data.dm = dm;
- data.hit_list = r_hit_list;
- data.retval = retval;
-
- BLI_bvhtree_ray_cast_all(
- treedata->tree, ray_start_local, ray_normal_local, 0.0f,
- *ray_depth, raycast_all_cb, &data);
-
- retval = data.retval;
- }
- else {
- BVHTreeRayHit hit;
-
- hit.index = -1;
- hit.dist = local_depth;
-
- if (treedata->tree &&
- BLI_bvhtree_ray_cast(
- treedata->tree, ray_start_local, ray_normal_local, 0.0f,
- &hit, treedata->raycast_callback, treedata) != -1)
- {
- hit.dist += len_diff;
- hit.dist /= local_scale;
- if (hit.dist <= *ray_depth) {
- *ray_depth = hit.dist;
- copy_v3_v3(r_loc, hit.co);
+ if (r_no) {
copy_v3_v3(r_no, hit.no);
-
- /* back to worldspace */
- mul_m4_v3(obmat, r_loc);
mul_m3_v3(timat, r_no);
normalize_v3(r_no);
+ }
- retval = true;
+ retval = true;
- if (r_index) {
- *r_index = dm_looptri_to_poly_index(dm, &treedata->looptri[hit.index]);
- }
+ if (r_index) {
+ *r_index = dm_looptri_to_poly_index(dm, &treedata->looptri[hit.index]);
}
}
}
- break;
}
- case SCE_SNAP_MODE_VERTEX:
- {
+ }
+ /* SCE_SNAP_MODE_VERTEX or SCE_SNAP_MODE_EDGE */
+ else {
+ const ARegion *ar = sctx->v3d_data.ar;
+
+ float ray_org_local[3];
+ copy_v3_v3(ray_org_local, ray_origin);
+ mul_m4_v3(imat, ray_org_local);
+
+ BVHTreeFromMeshType treedata_type = {.userdata = treedata, .type = SNAP_MESH};
+
+ if (view_proj == VIEW_PROJ_PERSP) {
+ Object_Nearest2dPrecalc neasrest_precalc;
+ neasrest_precalc.userdata = &treedata_type;
+ neasrest_precalc.index = -1;
+
+ nearest2d_precalc(&neasrest_precalc, ar, *dist_px, obmat,
+ ray_org_local, ray_normal_local, mval, depth_range);
+
+ BVHTree_WalkLeafCallback cb_walk_leaf =
+ (snap_to == SCE_SNAP_MODE_VERTEX) ?
+ cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge;
+
+ BLI_bvhtree_walk_dfs(
+ treedata->tree,
+ cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest_precalc);
+
+ if (neasrest_precalc.index != -1) {
+ copy_v3_v3(r_loc, neasrest_precalc.co);
+ mul_m4_v3(obmat, r_loc);
+ if (r_no) {
+ copy_v3_v3(r_no, neasrest_precalc.no);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
+ }
+ *dist_px = sqrtf(neasrest_precalc.projectdefs.dist_px_sq);
+
+ retval = true;
+ }
+ }
+ else {
BVHTreeNearest nearest;
nearest.index = -1;
- nearest.dist_sq = local_depth * local_depth;
- if (treedata->tree &&
- BLI_bvhtree_find_nearest_to_ray(
- treedata->tree, ray_start_local, ray_normal_local,
- &nearest, NULL, NULL) != -1)
+ float dist_3d = dist_px_to_dist3d_or_tangent(ar, *dist_px);
+ nearest.dist_sq = SQUARE(dist_3d);
+
+
+ float ob_scale[3];
+ mat4_to_size(ob_scale, obmat);
+
+ struct NearestDM_Data userdata;
+ userdata.bvhdata = &treedata_type;
+ userdata.depth_range = depth_range;
+ userdata.ray_depth = ray_depth;
+
+ BVHTree_NearestToRayCallback cb_test_ray_dist =
+ (snap_to == SCE_SNAP_MODE_VERTEX) ?
+ test_vert_ray_dist_cb : test_edge_ray_dist_cb;
+
+ if (BLI_bvhtree_find_nearest_to_ray(
+ treedata->tree, ray_org_local, ray_normal_local,
+ true, ob_scale, &nearest, cb_test_ray_dist, &userdata) != -1)
{
- const MVert *v = &treedata->vert[nearest.index];
- float vno[3];
- normal_short_to_float_v3(vno, v->no);
- retval = snapVertex(
- ar, v->co, vno, obmat, timat, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
- r_loc, r_no);
- }
- break;
- }
- case SCE_SNAP_MODE_EDGE:
- {
- MVert *verts = dm->getVertArray(dm);
- MEdge *edges = dm->getEdgeArray(dm);
- int totedge = dm->getNumEdges(dm);
-
- for (int i = 0; i < totedge; i++) {
- MEdge *e = edges + i;
- retval |= snapEdge(
- ar, verts[e->v1].co, verts[e->v1].no, verts[e->v2].co, verts[e->v2].no,
- obmat, timat, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
- r_loc, r_no);
- }
+ copy_v3_v3(r_loc, nearest.co);
+ mul_m4_v3(obmat, r_loc);
+ if (r_no) {
+ copy_v3_v3(r_no, nearest.no);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
+ }
+ *dist_px *= sqrtf(nearest.dist_sq) / dist_3d;
- break;
+ retval = true;
+ }
}
}
@@ -941,46 +1389,48 @@ static bool snapDerivedMesh(
return retval;
}
-
static bool snapEditMesh(
SnapObjectContext *sctx,
- Object *ob, BMEditMesh *em, float obmat[4][4],
- const float mval[2], float *dist_px, const short snap_to,
- const float ray_start[3], const float ray_normal[3], const float ray_origin[3],
- float *ray_depth, const unsigned int ob_index,
+ Object *ob, BMEditMesh *em, float obmat[4][4], const unsigned int ob_index,
+ const short snap_to, const float mval[2], const enum eViewProj view_proj,
+ const float ray_origin[3], const float ray_start[3], const float ray_normal[3],
+ const float depth_range[2],
+ /* read/write args */
+ float *ray_depth, float *dist_px,
+ /* return args */
float r_loc[3], float r_no[3], int *r_index,
ListBase *r_hit_list)
{
- ARegion *ar = sctx->v3d_data.ar;
bool retval = false;
- int totvert = em->bm->totvert;
- if (totvert > 0) {
- const bool do_ray_start_correction = (
- ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX) &&
- (sctx->use_v3d && !((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp));
+ if (snap_to == SCE_SNAP_MODE_FACE) {
+ if (em->bm->totface == 0) {
+ return retval;
+ }
+ }
+ if (snap_to == SCE_SNAP_MODE_EDGE) {
+ if (em->bm->totedge == 0) {
+ return retval;
+ }
+ }
+ else {
+ if (em->bm->totvert == 0) {
+ return retval;
+ }
+ }
+ {
float imat[4][4];
float timat[3][3]; /* transpose inverse matrix for normals */
- float ray_start_local[3], ray_normal_local[3];
- float local_scale, local_depth, len_diff;
+ float ray_normal_local[3];
invert_m4_m4(imat, obmat);
transpose_m3_m4(timat, imat);
- copy_v3_v3(ray_start_local, ray_start);
copy_v3_v3(ray_normal_local, ray_normal);
- mul_m4_v3(imat, ray_start_local);
mul_mat3_m4_v3(imat, ray_normal_local);
- /* local scale in normal direction */
- local_scale = normalize_v3(ray_normal_local);
- local_depth = *ray_depth;
- if (local_depth != BVH_RAYCAST_DIST_MAX) {
- local_depth *= local_scale;
- }
-
SnapObjectData_EditMesh *sod = NULL;
BVHTreeFromEditMesh *treedata = NULL, treedata_stack;
@@ -998,6 +1448,9 @@ static bool snapEditMesh(
int tree_index = -1;
switch (snap_to) {
case SCE_SNAP_MODE_FACE:
+ tree_index = 2;
+ break;
+ case SCE_SNAP_MODE_EDGE:
tree_index = 1;
break;
case SCE_SNAP_MODE_VERTEX:
@@ -1012,10 +1465,8 @@ static bool snapEditMesh(
}
}
else {
- if (ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX)) {
- treedata = &treedata_stack;
- memset(treedata, 0, sizeof(*treedata));
- }
+ treedata = &treedata_stack;
+ memset(treedata, 0, sizeof(*treedata));
}
if (treedata && treedata->tree == NULL) {
@@ -1030,12 +1481,29 @@ static bool snapEditMesh(
em->bm, looptri_mask,
sctx->callbacks.edit_mesh.test_face_fn, sctx->callbacks.edit_mesh.user_data);
}
- bvhtree_from_editmesh_looptri_ex(treedata, em, looptri_mask, looptri_num_active, 0.0f, 4, 6);
+ bvhtree_from_editmesh_looptri_ex(treedata, em, looptri_mask, looptri_num_active, 0.0f, 4, 6, NULL);
if (looptri_mask) {
MEM_freeN(looptri_mask);
}
break;
}
+ case SCE_SNAP_MODE_EDGE:
+ {
+ BLI_bitmap *edges_mask = NULL;
+ int edges_num_active = -1;
+ if (sctx->callbacks.edit_mesh.test_edge_fn) {
+ edges_mask = BLI_BITMAP_NEW(em->bm->totedge, __func__);
+ edges_num_active = BM_iter_mesh_bitmap_from_filter(
+ BM_EDGES_OF_MESH, em->bm, edges_mask,
+ (bool (*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_edge_fn,
+ sctx->callbacks.edit_mesh.user_data);
+ }
+ bvhtree_from_editmesh_edges_ex(treedata, em, edges_mask, edges_num_active, 0.0f, 2, 6);
+ if (edges_mask) {
+ MEM_freeN(edges_mask);
+ }
+ break;
+ }
case SCE_SNAP_MODE_VERTEX:
{
BLI_bitmap *verts_mask = NULL;
@@ -1056,141 +1524,180 @@ static bool snapEditMesh(
}
}
- /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already
- * been *inside* boundbox, leading to snap failures (see T38409).
- * Note also ar might be null (see T38435), in this case we assume ray_start is ok!
- */
- if (do_ray_start_correction) {
- /* We *need* a reasonably valid len_diff in this case.
- * Use BHVTree to find the closest face from ray_start_local.
+ if (!treedata || !treedata->tree) {
+ return retval;
+ }
+
+ if (snap_to == SCE_SNAP_MODE_FACE) {
+ float ray_start_local[3];
+ copy_v3_v3(ray_start_local, ray_start);
+ mul_m4_v3(imat, ray_start_local);
+
+ /* local scale in normal direction */
+ float local_scale = normalize_v3(ray_normal_local);
+ float local_depth = *ray_depth;
+ if (local_depth != BVH_RAYCAST_DIST_MAX) {
+ local_depth *= local_scale;
+ }
+
+ /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already
+ * been *inside* boundbox, leading to snap failures (see T38409).
+ * Note also ar might be null (see T38435), in this case we assume ray_start is ok!
*/
- if (treedata && treedata->tree != NULL) {
+ float len_diff = 0.0f;
+ if (view_proj == VIEW_PROJ_ORTHO) { /* do_ray_start_correction */
+ /* We *need* a reasonably valid len_diff in this case.
+ * Use BHVTree to find the closest face from ray_start_local.
+ */
BVHTreeNearest nearest;
nearest.index = -1;
nearest.dist_sq = FLT_MAX;
/* Compute and store result. */
- BLI_bvhtree_find_nearest(
- treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata);
- if (nearest.index != -1) {
- len_diff = sqrtf(nearest.dist_sq);
+ if (BLI_bvhtree_find_nearest(
+ treedata->tree, ray_start_local, &nearest, NULL, NULL) != -1)
+ {
+ float dvec[3];
+ sub_v3_v3v3(dvec, nearest.co, ray_start_local);
+ len_diff = dot_v3v3(dvec, ray_normal_local);
+ float ray_org_local[3];
+
+ copy_v3_v3(ray_org_local, ray_origin);
+ mul_m4_v3(imat, ray_org_local);
+
+ /* We pass a temp ray_start, set from object's boundbox,
+ * to avoid precision issues with very far away ray_start values
+ * (as returned in case of ortho view3d), see T38358.
+ */
+ len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
+ madd_v3_v3v3fl(
+ ray_start_local, ray_org_local, ray_normal_local, len_diff + depth_range[0] * local_scale);
+ local_depth -= len_diff;
}
}
- float ray_org_local[3];
+ if (r_hit_list) {
+ struct RayCastAll_Data data;
+
+ data.bvhdata = treedata;
+ data.raycast_callback = treedata->raycast_callback;
+ data.obmat = obmat;
+ data.timat = timat;
+ data.len_diff = len_diff;
+ data.local_scale = local_scale;
+ data.ob = ob;
+ data.ob_uuid = ob_index;
+ data.hit_list = r_hit_list;
+ data.retval = retval;
+
+ BLI_bvhtree_ray_cast_all(
+ treedata->tree, ray_start_local, ray_normal_local, 0.0f,
+ *ray_depth, raycast_all_cb, &data);
+
+ retval = data.retval;
+ }
+ else {
+ BVHTreeRayHit hit = {.index = -1, .dist = local_depth};
- copy_v3_v3(ray_org_local, ray_origin);
- mul_m4_v3(imat, ray_org_local);
+ if (BLI_bvhtree_ray_cast(
+ treedata->tree, ray_start_local, ray_normal_local, 0.0f,
+ &hit, treedata->raycast_callback, treedata) != -1)
+ {
+ hit.dist += len_diff;
+ hit.dist /= local_scale;
+ if (hit.dist <= *ray_depth) {
+ *ray_depth = hit.dist;
+ copy_v3_v3(r_loc, hit.co);
- /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with very far
- * away ray_start values (as returned in case of ortho view3d), see T38358.
- */
- len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
- madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local,
- len_diff - len_v3v3(ray_start_local, ray_org_local));
- local_depth -= len_diff;
- }
- else {
- len_diff = 0.0f;
- }
+ /* back to worldspace */
+ mul_m4_v3(obmat, r_loc);
- switch (snap_to) {
- case SCE_SNAP_MODE_FACE:
- {
- if (r_hit_list) {
- struct RayCastAll_Data data;
-
- data.bvhdata = treedata;
- data.raycast_callback = treedata->raycast_callback;
- data.obmat = obmat;
- data.timat = timat;
- data.len_diff = len_diff;
- data.local_scale = local_scale;
- data.ob = ob;
- data.ob_uuid = ob_index;
- data.dm = NULL;
- data.hit_list = r_hit_list;
- data.retval = retval;
-
- BLI_bvhtree_ray_cast_all(
- treedata->tree, ray_start_local, ray_normal_local, 0.0f,
- *ray_depth, raycast_all_cb, &data);
-
- retval = data.retval;
- }
- else {
- BVHTreeRayHit hit;
-
- hit.index = -1;
- hit.dist = local_depth;
-
- if (treedata->tree &&
- BLI_bvhtree_ray_cast(
- treedata->tree, ray_start_local, ray_normal_local, 0.0f,
- &hit, treedata->raycast_callback, treedata) != -1)
- {
- hit.dist += len_diff;
- hit.dist /= local_scale;
- if (hit.dist <= *ray_depth) {
- *ray_depth = hit.dist;
- copy_v3_v3(r_loc, hit.co);
+ if (r_no) {
copy_v3_v3(r_no, hit.no);
-
- /* back to worldspace */
- mul_m4_v3(obmat, r_loc);
mul_m3_v3(timat, r_no);
normalize_v3(r_no);
+ }
- retval = true;
+ retval = true;
- if (r_index) {
- *r_index = hit.index;
- }
+ if (r_index) {
+ *r_index = hit.index;
}
}
}
- break;
}
- case SCE_SNAP_MODE_VERTEX:
- {
+ }
+ else {
+ const ARegion *ar = sctx->v3d_data.ar;
+
+ float ray_org_local[3];
+ copy_v3_v3(ray_org_local, ray_origin);
+ mul_m4_v3(imat, ray_org_local);
+
+ BVHTreeFromMeshType treedata_type = {.userdata = treedata, .type = SNAP_EDIT_MESH};
+
+ if (view_proj == VIEW_PROJ_PERSP) {
+ Object_Nearest2dPrecalc neasrest_precalc;
+ neasrest_precalc.userdata = &treedata_type;
+ neasrest_precalc.index = -1;
+
+ nearest2d_precalc(&neasrest_precalc, ar, *dist_px, obmat,
+ ray_org_local, ray_normal_local, mval, depth_range);
+
+ BVHTree_WalkLeafCallback cb_walk_leaf =
+ (snap_to == SCE_SNAP_MODE_VERTEX) ?
+ cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge;
+
+ BLI_bvhtree_walk_dfs(
+ treedata->tree,
+ cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest_precalc);
+
+ if (neasrest_precalc.index != -1) {
+ copy_v3_v3(r_loc, neasrest_precalc.co);
+ mul_m4_v3(obmat, r_loc);
+ if (r_no) {
+ copy_v3_v3(r_no, neasrest_precalc.no);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
+ }
+ *dist_px = sqrtf(neasrest_precalc.projectdefs.dist_px_sq);
+
+ retval = true;
+ }
+ }
+ else {
BVHTreeNearest nearest;
nearest.index = -1;
- nearest.dist_sq = local_depth * local_depth;
- if (treedata->tree &&
- BLI_bvhtree_find_nearest_to_ray(
- treedata->tree, ray_start_local, ray_normal_local,
- &nearest, NULL, NULL) != -1)
+ float dist_3d = dist_px_to_dist3d_or_tangent(ar, *dist_px);
+ nearest.dist_sq = SQUARE(dist_3d);
+
+
+ float ob_scale[3];
+ mat4_to_size(ob_scale, obmat);
+
+ struct NearestDM_Data userdata;
+ userdata.bvhdata = &treedata_type;
+ userdata.depth_range = depth_range;
+ userdata.ray_depth = ray_depth;
+
+ BVHTree_NearestToRayCallback cb_test_ray_dist =
+ (snap_to == SCE_SNAP_MODE_VERTEX) ?
+ test_vert_ray_dist_cb : test_edge_ray_dist_cb;
+
+ if (BLI_bvhtree_find_nearest_to_ray(
+ treedata->tree, ray_org_local, ray_normal_local,
+ false, ob_scale, &nearest, cb_test_ray_dist, &userdata) != -1)
{
- const BMVert *v = BM_vert_at_index(em->bm, nearest.index);
- retval = snapVertex(
- ar, v->co, v->no, obmat, timat, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
- r_loc, r_no);
- }
- break;
- }
- case SCE_SNAP_MODE_EDGE:
- {
- BM_mesh_elem_table_ensure(em->bm, BM_EDGE);
- int totedge = em->bm->totedge;
- for (int i = 0; i < totedge; i++) {
- BMEdge *eed = BM_edge_at_index(em->bm, i);
-
- if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) &&
- !BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) &&
- !BM_elem_flag_test(eed->v2, BM_ELEM_SELECT))
- {
- short v1no[3], v2no[3];
- normal_float_to_short_v3(v1no, eed->v1->no);
- normal_float_to_short_v3(v2no, eed->v2->no);
- retval |= snapEdge(
- ar, eed->v1->co, v1no, eed->v2->co, v2no,
- obmat, timat, mval, dist_px,
- ray_start, ray_start_local, ray_normal_local, ray_depth,
- r_loc, r_no);
+ copy_v3_v3(r_loc, nearest.co);
+ mul_m4_v3(obmat, r_loc);
+ if (r_no) {
+ copy_v3_v3(r_no, nearest.no);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
}
- }
+ *dist_px *= sqrtf(nearest.dist_sq) / dist_3d;
- break;
+ retval = true;
+ }
}
}
@@ -1204,18 +1711,30 @@ static bool snapEditMesh(
return retval;
}
+/**
+ * \param use_obedit: Uses the coordinates of BMesh (if any) to do the snapping;
+ *
+ * \note Duplicate args here are documented at #snapObjectsRay
+ */
static bool snapObject(
SnapObjectContext *sctx,
- Object *ob, float obmat[4][4], bool use_obedit, const short snap_to,
- const float mval[2], float *dist_px, const unsigned int ob_index,
- const float ray_start[3], const float ray_normal[3], const float ray_origin[3],
- float *ray_depth,
+ Object *ob, float obmat[4][4], const unsigned int ob_index,
+ bool use_obedit, const short snap_to, const float mval[2],
+ const float ray_origin[3], const float ray_start[3], const float ray_normal[3],
+ const float depth_range[2],
+ /* read/write args */
+ float *ray_depth, float *dist_px,
/* return args */
float r_loc[3], float r_no[3], int *r_index,
Object **r_ob, float r_obmat[4][4],
ListBase *r_hit_list)
{
- ARegion *ar = sctx->v3d_data.ar;
+ const enum eViewProj view_proj =
+ ((sctx->use_v3d == false) || (mval == NULL)) ? VIEW_PROJ_NONE :
+ (((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp ? VIEW_PROJ_PERSP : VIEW_PROJ_ORTHO);
+
+ const ARegion *ar = sctx->v3d_data.ar;
+
bool retval = false;
if (ob->type == OB_MESH) {
@@ -1224,9 +1743,10 @@ static bool snapObject(
if (use_obedit) {
em = BKE_editmesh_from_object(ob);
retval = snapEditMesh(
- sctx, ob, em, obmat, mval, dist_px, snap_to,
- ray_start, ray_normal, ray_origin,
- ray_depth, ob_index,
+ sctx, ob, em, obmat, ob_index,
+ snap_to, mval, view_proj,
+ ray_origin, ray_start, ray_normal, depth_range,
+ ray_depth, dist_px,
r_loc, r_no, r_index,
r_hit_list);
}
@@ -1242,37 +1762,44 @@ static bool snapObject(
dm = mesh_get_derived_final(sctx->scene, ob, CD_MASK_BAREMESH);
}
retval = snapDerivedMesh(
- sctx, ob, dm, obmat, mval, dist_px, snap_to, true,
- ray_start, ray_normal, ray_origin,
- ray_depth, ob_index,
- r_loc, r_no, r_index, r_hit_list);
+ sctx, ob, dm, obmat, ob_index,
+ snap_to, mval, view_proj, true,
+ ray_origin, ray_start, ray_normal, depth_range,
+ ray_depth, dist_px,
+ r_loc, r_no,
+ r_index, r_hit_list);
dm->release(dm);
}
}
- else if (ob->type == OB_ARMATURE) {
- retval = snapArmature(
- ar, ob, ob->data, obmat, mval, dist_px, snap_to,
- ray_start, ray_normal, ray_depth,
- r_loc, r_no);
- }
- else if (ob->type == OB_CURVE) {
- retval = snapCurve(
- ar, ob, ob->data, obmat, mval, dist_px, snap_to,
- ray_start, ray_normal, ray_depth,
- r_loc, r_no);
- }
- else if (ob->type == OB_EMPTY) {
- retval = snapEmpty(
- ar, ob, obmat, mval, dist_px, snap_to,
- ray_start, ray_normal, ray_depth,
- r_loc, r_no);
- }
- else if (ob->type == OB_CAMERA) {
- retval = snapCamera(
- ar, sctx->scene, ob, obmat, mval, dist_px, snap_to,
- ray_start, ray_normal, ray_depth,
- r_loc, r_no);
+ else if (snap_to != SCE_SNAP_MODE_FACE) {
+ if (ob->type == OB_ARMATURE) {
+ retval = snapArmature(
+ ar, ob, ob->data, obmat, snap_to, ray_origin, ray_normal,
+ mval, view_proj, depth_range, dist_px,
+ r_loc, r_no);
+ }
+ else if (ob->type == OB_CURVE) {
+ retval = snapCurve(
+ ar, ob, ob->data, obmat, snap_to, mval, view_proj,
+ depth_range,
+ dist_px,
+ r_loc, r_no);
+ }
+ else if (ob->type == OB_EMPTY) {
+ retval = snapEmpty(
+ ar, ob, obmat, snap_to, mval, view_proj,
+ depth_range,
+ dist_px,
+ r_loc, r_no);
+ }
+ else if (ob->type == OB_CAMERA) {
+ retval = snapCamera(
+ sctx, ob, obmat, snap_to, mval, view_proj,
+ depth_range,
+ dist_px,
+ r_loc, r_no);
+ }
}
if (retval) {
@@ -1285,58 +1812,98 @@ static bool snapObject(
return retval;
}
+/**
+ * Main Snapping Function
+ * ======================
+ *
+ * Walks through all objects in the scene to find the closest snap element ray.
+ *
+ * \param sctx: Snap context to store data.
+ * \param snap_to: Element to snap, Vertice, Edge or Face.
+ * Currently only works one at a time, but can eventually operate as flag.
+ *
+ * \param snap_select: from enum SnapSelect.
+ *
+ * \param use_object_edit_cage: Uses the coordinates of BMesh (if any) to do the snapping.
+ * \param mval: Mouse coords.
+ * When NULL, ray-casting is handled without any projection matrix correction.
+ * \param ray_origin: ray_start before being moved toward the ray_normal at the distance from vew3d clip_min.
+ * \param ray_start: ray_origin moved for the start clipping plane (clip_min).
+ * \param ray_normal: Unit length direction of the ray.
+ * \param depth_range: distances of clipe plane min and clip plane max;
+ *
+ * Read/Write Args
+ * ---------------
+ *
+ * \param ray_depth: maximum depth allowed for r_co, elements deeper than this value will be ignored.
+ * \param dist_px: Maximum threshold distance (in pixels).
+ *
+ * Output Args
+ * -----------
+ *
+ * \param r_loc: Hit location.
+ * \param r_no: Hit normal (optional).
+ * \param r_index: Hit index or -1 when no valid index is found.
+ * (currently only set to the polygon index when when using ``snap_to == SCE_SNAP_MODE_FACE``).
+ * \param r_ob: Hit object.
+ * \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances).
+ * \param r_hit_list: List of #SnapObjectHitDepth (caller must free).
+ *
+ */
static bool snapObjectsRay(
SnapObjectContext *sctx,
- SnapSelect snap_select, const short snap_to,
- const float mval[2], float *dist_px,
- /* special handling of active and edit objects */
- Base *base_act, Object *obedit,
- const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth,
+ const unsigned short snap_to, const SnapSelect snap_select,
+ const bool use_object_edit_cage, const float mval[2],
+ const float ray_origin[3], const float ray_start[3], const float ray_normal[3],
+ const float depth_range[2],
+ /* read/write args */
+ float *ray_depth, float *dist_px,
/* return args */
float r_loc[3], float r_no[3], int *r_index,
Object **r_ob, float r_obmat[4][4],
ListBase *r_hit_list)
{
- Base *base;
bool retval = false;
- bool snap_obedit_first = snap_select == SNAP_ALL && obedit;
- unsigned int ob_index = 0;
-
- if (snap_obedit_first) {
- Object *ob = obedit;
- retval |= snapObject(
- sctx, ob, ob->obmat, true, snap_to,
- mval, dist_px, ob_index++,
- ray_start, ray_normal, ray_origin, ray_depth,
- r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
- }
+ unsigned int ob_index = 0;
+ Object *obedit = use_object_edit_cage ? sctx->scene->obedit : NULL;
/* Need an exception for particle edit because the base is flagged with BA_HAS_RECALC_DATA
* which makes the loop skip it, even the derived mesh will never change
*
* To solve that problem, we do it first as an exception.
* */
- base = base_act;
- if (base && base->object && base->object->mode & OB_MODE_PARTICLE_EDIT) {
- Object *ob = base->object;
+ Base *base_act = sctx->scene->basact;
+ if (base_act && base_act->object && base_act->object->mode & OB_MODE_PARTICLE_EDIT) {
+ Object *ob = base_act->object;
+
retval |= snapObject(
- sctx, ob, ob->obmat, false, snap_to,
- mval, dist_px, ob_index++,
- ray_start, ray_normal, ray_origin, ray_depth,
+ sctx, ob, ob->obmat, ob_index++,
+ false, snap_to, mval,
+ ray_origin, ray_start, ray_normal, depth_range,
+ ray_depth, dist_px,
r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
}
- for (base = sctx->scene->base.first; base != NULL; base = base->next) {
+ bool ignore_object_selected = false, ignore_object_active = false;
+ switch (snap_select) {
+ case SNAP_ALL:
+ break;
+ case SNAP_NOT_SELECTED:
+ ignore_object_selected = true;
+ break;
+ case SNAP_NOT_ACTIVE:
+ ignore_object_active = true;
+ break;
+ }
+ for (Base *base = sctx->scene->base.first; base != NULL; base = base->next) {
if ((BASE_VISIBLE_BGMODE(sctx->v3d_data.v3d, sctx->scene, base)) &&
(base->flag & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 &&
- ((snap_select == SNAP_NOT_SELECTED && (base->flag & (SELECT | BA_WAS_SEL)) == 0) ||
- (ELEM(snap_select, SNAP_ALL, SNAP_NOT_OBEDIT) && base != base_act)))
+ !((ignore_object_selected && (base->flag & (SELECT | BA_WAS_SEL))) ||
+ (ignore_object_active && base == base_act)))
{
Object *ob = base->object;
- Object *ob_snap = ob;
- bool use_obedit = false;
if (ob->transflag & OB_DUPLI) {
DupliObject *dupli_ob;
@@ -1347,33 +1914,24 @@ static bool snapObjectsRay(
Object *dupli_snap = (use_obedit_dupli) ? obedit : dupli_ob->ob;
retval |= snapObject(
- sctx, dupli_snap, dupli_ob->mat, use_obedit_dupli, snap_to,
- mval, dist_px, ob_index++,
- ray_start, ray_normal, ray_origin, ray_depth,
+ sctx, dupli_snap, dupli_ob->mat, ob_index++,
+ use_obedit_dupli, snap_to, mval,
+ ray_origin, ray_start, ray_normal, depth_range,
+ ray_depth, dist_px,
r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
}
free_object_duplilist(lb);
}
- if (obedit) {
- if ((ob == obedit) &&
- (snap_obedit_first || (snap_select == SNAP_NOT_OBEDIT)))
- {
- continue;
- }
-
- if (ob->data == obedit->data) {
- /* for linked objects, use the same object but a different matrix */
- use_obedit = true;
- ob_snap = obedit;
- }
- }
+ bool use_obedit = (obedit != NULL) && (ob->data == obedit->data);
+ Object *ob_snap = use_obedit ? obedit : ob;
retval |= snapObject(
- sctx, ob_snap, ob->obmat, use_obedit, snap_to,
- mval, dist_px, ob_index++,
- ray_start, ray_normal, ray_origin, ray_depth,
+ sctx, ob_snap, ob->obmat, ob_index++,
+ use_obedit, snap_to, mval,
+ ray_origin, ray_start, ray_normal, depth_range,
+ ray_depth, dist_px,
r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
}
}
@@ -1405,7 +1963,7 @@ SnapObjectContext *ED_transform_snap_object_context_create(
SnapObjectContext *ED_transform_snap_object_context_create_view3d(
Main *bmain, Scene *scene, int flag,
/* extra args for view3d */
- ARegion *ar, View3D *v3d)
+ const ARegion *ar, const View3D *v3d)
{
SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, flag);
@@ -1473,22 +2031,20 @@ void ED_transform_snap_object_context_set_editmesh_callbacks(
bool ED_transform_snap_object_project_ray_ex(
SnapObjectContext *sctx,
+ const unsigned short snap_to,
const struct SnapObjectParams *params,
- const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ const float ray_start[3], const float ray_normal[3],
+ float *ray_depth,
float r_loc[3], float r_no[3], int *r_index,
Object **r_ob, float r_obmat[4][4])
{
- Base *base_act = params->use_object_active ? sctx->scene->basact : NULL;
- Object *obedit = params->use_object_edit ? sctx->scene->obedit : NULL;
-
+ const float depth_range[2] = {0.0f, FLT_MAX};
return snapObjectsRay(
sctx,
- params->snap_select, params->snap_to,
- NULL, NULL,
- base_act, obedit,
- ray_start, ray_normal, ray_start, ray_depth,
- r_loc, r_no, r_index,
- r_ob, r_obmat, NULL);
+ snap_to, params->snap_select, params->use_object_edit_cage, NULL,
+ ray_start, ray_start, ray_normal, depth_range,
+ ray_depth, NULL,
+ r_loc, r_no, r_index, r_ob, r_obmat, NULL);
}
/**
@@ -1500,14 +2056,13 @@ bool ED_transform_snap_object_project_ray_ex(
*/
bool ED_transform_snap_object_project_ray_all(
SnapObjectContext *sctx,
+ const unsigned short snap_to,
const struct SnapObjectParams *params,
const float ray_start[3], const float ray_normal[3],
float ray_depth, bool sort,
ListBase *r_hit_list)
{
- Base *base_act = params->use_object_active ? sctx->scene->basact : NULL;
- Object *obedit = params->use_object_edit ? sctx->scene->obedit : NULL;
-
+ const float depth_range[2] = {0.0f, FLT_MAX};
if (ray_depth == -1.0f) {
ray_depth = BVH_RAYCAST_DIST_MAX;
}
@@ -1518,10 +2073,9 @@ bool ED_transform_snap_object_project_ray_all(
bool retval = snapObjectsRay(
sctx,
- params->snap_select, params->snap_to,
- NULL, NULL,
- base_act, obedit,
- ray_start, ray_normal, ray_start, &ray_depth,
+ snap_to, params->snap_select, params->use_object_edit_cage, NULL,
+ ray_start, ray_start, ray_normal, depth_range,
+ &ray_depth, NULL,
NULL, NULL, NULL, NULL, NULL,
r_hit_list);
@@ -1546,6 +2100,7 @@ bool ED_transform_snap_object_project_ray_all(
*/
static bool transform_snap_context_project_ray_impl(
SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
const float ray_start[3], const float ray_normal[3], float *ray_depth,
float r_co[3], float r_no[3])
{
@@ -1554,11 +2109,8 @@ static bool transform_snap_context_project_ray_impl(
/* try snap edge, then face if it fails */
ret = ED_transform_snap_object_project_ray_ex(
sctx,
- &(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
- .snap_to = SCE_SNAP_MODE_FACE,
- .use_object_edit = (sctx->scene->obedit != NULL),
- },
+ SCE_SNAP_MODE_FACE,
+ params,
ray_start, ray_normal, ray_depth,
r_co, r_no, NULL,
NULL, NULL);
@@ -1568,6 +2120,7 @@ static bool transform_snap_context_project_ray_impl(
bool ED_transform_snap_object_project_ray(
SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
const float ray_origin[3], const float ray_direction[3], float *ray_depth,
float r_co[3], float r_no[3])
{
@@ -1577,19 +2130,16 @@ bool ED_transform_snap_object_project_ray(
ray_depth = &ray_depth_fallback;
}
- float no_fallback[3];
- if (r_no == NULL) {
- r_no = no_fallback;
- }
-
return transform_snap_context_project_ray_impl(
sctx,
+ params,
ray_origin, ray_direction, ray_depth,
r_co, r_no);
}
static bool transform_snap_context_project_view3d_mixed_impl(
SnapObjectContext *sctx,
+ const unsigned short snap_to_flag,
const struct SnapObjectParams *params,
const float mval[2], float *dist_px,
bool use_depth,
@@ -1598,29 +2148,20 @@ static bool transform_snap_context_project_view3d_mixed_impl(
float ray_depth = BVH_RAYCAST_DIST_MAX;
bool is_hit = false;
- float r_no_dummy[3];
- if (r_no == NULL) {
- r_no = r_no_dummy;
- }
-
const int elem_type[3] = {SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE, SCE_SNAP_MODE_FACE};
- BLI_assert(params->snap_to_flag != 0);
- BLI_assert((params->snap_to_flag & ~(1 | 2 | 4)) == 0);
-
- struct SnapObjectParams params_temp = *params;
+ BLI_assert(snap_to_flag != 0);
+ BLI_assert((snap_to_flag & ~(1 | 2 | 4)) == 0);
for (int i = 0; i < 3; i++) {
- if ((params->snap_to_flag & (1 << i)) && (is_hit == false || use_depth)) {
+ if ((snap_to_flag & (1 << i)) && (is_hit == false || use_depth)) {
if (use_depth == false) {
ray_depth = BVH_RAYCAST_DIST_MAX;
}
- params_temp.snap_to = elem_type[i];
-
if (ED_transform_snap_object_project_view3d(
sctx,
- &params_temp,
+ elem_type[i], params,
mval, dist_px, &ray_depth,
r_co, r_no))
{
@@ -1638,7 +2179,7 @@ static bool transform_snap_context_project_view3d_mixed_impl(
* Given a 2D region value, snap to vert/edge/face.
*
* \param sctx: Snap context.
- * \param mval: Screenspace coordinate.
+ * \param mval_fl: Screenspace coordinate.
* \param dist_px: Maximum distance to snap (in pixels).
* \param use_depth: Snap to the closest element, use when using more than one snap type.
* \param r_co: hit location.
@@ -1647,6 +2188,7 @@ static bool transform_snap_context_project_view3d_mixed_impl(
*/
bool ED_transform_snap_object_project_view3d_mixed(
SnapObjectContext *sctx,
+ const unsigned short snap_to_flag,
const struct SnapObjectParams *params,
const float mval_fl[2], float *dist_px,
bool use_depth,
@@ -1654,19 +2196,37 @@ bool ED_transform_snap_object_project_view3d_mixed(
{
return transform_snap_context_project_view3d_mixed_impl(
sctx,
- params,
+ snap_to_flag, params,
mval_fl, dist_px, use_depth,
r_co, r_no);
}
bool ED_transform_snap_object_project_view3d_ex(
SnapObjectContext *sctx,
+ const unsigned short snap_to,
const struct SnapObjectParams *params,
const float mval[2], float *dist_px,
float *ray_depth,
float r_loc[3], float r_no[3], int *r_index)
{
- float ray_start[3], ray_normal[3], ray_orgigin[3];
+ float ray_origin[3], ray_start[3], ray_normal[3], depth_range[2], ray_end[3];
+
+ const ARegion *ar = sctx->v3d_data.ar;
+ const RegionView3D *rv3d = ar->regiondata;
+
+ ED_view3d_win_to_origin(ar, mval, ray_origin);
+ ED_view3d_win_to_vector(ar, mval, ray_normal);
+
+ ED_view3d_clip_range_get(
+ sctx->v3d_data.v3d, sctx->v3d_data.ar->regiondata,
+ &depth_range[0], &depth_range[1], false);
+
+ madd_v3_v3v3fl(ray_start, ray_origin, ray_normal, depth_range[0]);
+ madd_v3_v3v3fl(ray_end, ray_origin, ray_normal, depth_range[1]);
+
+ if (!ED_view3d_clip_segment(rv3d, ray_start, ray_end)) {
+ return false;
+ }
float ray_depth_fallback;
if (ray_depth == NULL) {
@@ -1674,26 +2234,17 @@ bool ED_transform_snap_object_project_view3d_ex(
ray_depth = &ray_depth_fallback;
}
- if (!ED_view3d_win_to_ray_ex(
- sctx->v3d_data.ar, sctx->v3d_data.v3d,
- mval, ray_orgigin, ray_normal, ray_start, true))
- {
- return false;
- }
-
- Base *base_act = params->use_object_active ? sctx->scene->basact : NULL;
- Object *obedit = params->use_object_edit ? sctx->scene->obedit : NULL;
return snapObjectsRay(
sctx,
- params->snap_select, params->snap_to,
- mval, dist_px,
- base_act, obedit,
- ray_start, ray_normal, ray_orgigin, ray_depth,
+ snap_to, params->snap_select, params->use_object_edit_cage,
+ mval, ray_origin, ray_start, ray_normal, depth_range,
+ ray_depth, dist_px,
r_loc, r_no, r_index, NULL, NULL, NULL);
}
bool ED_transform_snap_object_project_view3d(
SnapObjectContext *sctx,
+ const unsigned short snap_to,
const struct SnapObjectParams *params,
const float mval[2], float *dist_px,
float *ray_depth,
@@ -1701,6 +2252,7 @@ bool ED_transform_snap_object_project_view3d(
{
return ED_transform_snap_object_project_view3d_ex(
sctx,
+ snap_to,
params,
mval, dist_px,
ray_depth,
@@ -1719,8 +2271,6 @@ bool ED_transform_snap_object_project_all_view3d_ex(
{
float ray_start[3], ray_normal[3];
- BLI_assert(params->snap_to == SCE_SNAP_MODE_FACE);
-
if (!ED_view3d_win_to_ray_ex(
sctx->v3d_data.ar, sctx->v3d_data.v3d,
mval, NULL, ray_normal, ray_start, true))
@@ -1730,6 +2280,7 @@ bool ED_transform_snap_object_project_all_view3d_ex(
return ED_transform_snap_object_project_ray_all(
sctx,
+ SCE_SNAP_MODE_FACE,
params,
ray_start, ray_normal, ray_depth, sort,
r_hit_list);
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index 1f4ce926f16..1f1a778cac7 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -57,6 +57,7 @@
#include "BKE_multires.h"
#include "BKE_packedFile.h"
#include "BKE_paint.h"
+#include "BKE_screen.h"
#include "ED_armature.h"
#include "ED_buttons.h"
@@ -104,7 +105,7 @@ void ED_editors_init(bContext *C)
ob->mode = OB_MODE_OBJECT;
data = ob->data;
- if (ob == obact && !ob->id.lib && !(data && data->lib))
+ if (ob == obact && !ID_IS_LINKED_DATABLOCK(ob) && !(data && ID_IS_LINKED_DATABLOCK(data)))
ED_object_toggle_modes(C, mode);
}
}
@@ -326,22 +327,14 @@ void ED_region_draw_mouse_line_cb(const bContext *C, ARegion *ar, void *arg_info
/**
* Use to free ID references within runtime data (stored outside of DNA)
*
- * \note Typically notifiers take care of this,
- * but there are times we have to free references immediately, see: T44376
+ * \param new_id may be NULL to unlink \a old_id.
*/
-void ED_spacedata_id_unref(struct SpaceLink *sl, const ID *id)
+void ED_spacedata_id_remap(struct ScrArea *sa, struct SpaceLink *sl, ID *old_id, ID *new_id)
{
+ SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
- switch (sl->spacetype) {
- case SPACE_OUTLINER:
- ED_outliner_id_unref((SpaceOops *)sl, id);
- break;
- case SPACE_BUTS:
- ED_buttons_id_unref((SpaceButs *)sl, id);
- break;
- case SPACE_NODE:
- ED_node_id_unref((SpaceNode *)sl, id);
- break;
+ if (st && st->id_remap) {
+ st->id_remap(sa, sl, old_id, new_id);
}
}
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index baa471e920b..5c5e84ee5f0 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -279,8 +279,6 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe
col[3] = 0.5f; /* hard coded alpha, not that nice */
- glShadeModel(GL_SMOOTH);
-
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
@@ -344,8 +342,6 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe
BLI_buffer_free(&av_buf);
BLI_buffer_free(&auv_buf);
- glShadeModel(GL_FLAT);
-
break;
}
}
@@ -381,7 +377,7 @@ static void draw_uvs_lineloop_mpoly(Mesh *me, MPoly *mpoly)
glEnd();
}
-static void draw_uvs_other_mesh_texface(Object *ob, const Image *curimage)
+static void draw_uvs_other_mesh_texface(Object *ob, const Image *curimage, const int other_uv_filter)
{
Mesh *me = ob->data;
MPoly *mpoly = me->mpoly;
@@ -393,14 +389,19 @@ static void draw_uvs_other_mesh_texface(Object *ob, const Image *curimage)
}
for (a = me->totpoly; a != 0; a--, mpoly++, mtpoly++) {
- if (mtpoly->tpage != curimage) {
- continue;
+ if (other_uv_filter == SI_FILTER_ALL) {
+ /* Nothing to compare, all UV faces are visible. */
+ }
+ else if (other_uv_filter == SI_FILTER_SAME_IMAGE) {
+ if (mtpoly->tpage != curimage) {
+ continue;
+ }
}
draw_uvs_lineloop_mpoly(me, mpoly);
}
}
-static void draw_uvs_other_mesh_new_shading(Object *ob, const Image *curimage)
+static void draw_uvs_other_mesh_new_shading(Object *ob, const Image *curimage, const int other_uv_filter)
{
Mesh *me = ob->data;
MPoly *mpoly = me->mpoly;
@@ -440,27 +441,34 @@ static void draw_uvs_other_mesh_new_shading(Object *ob, const Image *curimage)
}
for (a = me->totpoly; a != 0; a--, mpoly++) {
- const int mat_nr = mpoly->mat_nr;
- if ((mat_nr >= totcol) ||
- (BLI_BITMAP_TEST(mat_test_array, mat_nr)) == 0)
- {
- continue;
+ if (other_uv_filter == SI_FILTER_ALL) {
+ /* Nothing to compare, all UV faces are visible. */
+ }
+ else if (other_uv_filter == SI_FILTER_SAME_IMAGE) {
+ const int mat_nr = mpoly->mat_nr;
+ if ((mat_nr >= totcol) ||
+ (BLI_BITMAP_TEST(mat_test_array, mat_nr)) == 0)
+ {
+ continue;
+ }
}
draw_uvs_lineloop_mpoly(me, mpoly);
}
}
-static void draw_uvs_other_mesh(Object *ob, const Image *curimage, const bool new_shading_nodes)
+static void draw_uvs_other_mesh(Object *ob, const Image *curimage, const bool new_shading_nodes,
+ const int other_uv_filter)
{
if (new_shading_nodes) {
- draw_uvs_other_mesh_new_shading(ob, curimage);
+ draw_uvs_other_mesh_new_shading(ob, curimage, other_uv_filter);
}
else {
- draw_uvs_other_mesh_texface(ob, curimage);
+ draw_uvs_other_mesh_texface(ob, curimage, other_uv_filter);
}
}
-static void draw_uvs_other(Scene *scene, Object *obedit, const Image *curimage, const bool new_shading_nodes)
+static void draw_uvs_other(Scene *scene, Object *obedit, const Image *curimage, const bool new_shading_nodes,
+ const int other_uv_filter)
{
Base *base;
@@ -474,7 +482,7 @@ static void draw_uvs_other(Scene *scene, Object *obedit, const Image *curimage,
if (ob->restrictflag & OB_RESTRICT_VIEW) continue;
if ((ob->type == OB_MESH) && (ob != obedit) && ((Mesh *)ob->data)->mloopuv) {
- draw_uvs_other_mesh(ob, curimage, new_shading_nodes);
+ draw_uvs_other_mesh(ob, curimage, new_shading_nodes, other_uv_filter);
}
}
}
@@ -487,7 +495,7 @@ static void draw_uvs_texpaint(SpaceImage *sima, Scene *scene, Object *ob)
Material *ma;
if (sima->flag & SI_DRAW_OTHER) {
- draw_uvs_other(scene, ob, curimage, new_shading_nodes);
+ draw_uvs_other(scene, ob, curimage, new_shading_nodes, sima->other_uv_filter);
}
UI_ThemeColor(TH_UV_SHADOW);
@@ -590,7 +598,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
curimage = (activetf) ? activetf->tpage : ima;
}
- draw_uvs_other(scene, obedit, curimage, new_shading_nodes);
+ draw_uvs_other(scene, obedit, curimage, new_shading_nodes, sima->other_uv_filter);
}
/* 1. draw shadow mesh */
@@ -794,8 +802,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
UI_GetThemeColor4ubv(TH_EDGE_SELECT, col1);
if (interpedges) {
- glShadeModel(GL_SMOOTH);
-
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
continue;
@@ -810,8 +817,6 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
}
glEnd();
}
-
- glShadeModel(GL_FLAT);
}
else {
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c
index 59f9cd16908..bdfff123aa4 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.c
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.c
@@ -740,6 +740,16 @@ static PVert *p_vert_add(PHandle *handle, PHashKey key, const float co[3], PEdge
{
PVert *v = (PVert *)BLI_memarena_alloc(handle->arena, sizeof(*v));
copy_v3_v3(v->co, co);
+
+ /* Sanity check, a single nan/inf point causes the entire result to be invalid.
+ * Note that values within the calculation may _become_ non-finite,
+ * so the rest of the code still needs to take this possibility into account. */
+ for (int i = 0; i < 3; i++) {
+ if (UNLIKELY(!isfinite(v->co[i]))) {
+ v->co[i] = 0.0f;
+ }
+ }
+
v->u.key = key;
v->edge = e;
v->flag = 0;
@@ -2794,7 +2804,7 @@ static PBool p_chart_abf_solve(PChart *chart)
static void p_chart_pin_positions(PChart *chart, PVert **pin1, PVert **pin2)
{
- if (pin1 == pin2) {
+ if (!*pin1 || !*pin2 || *pin1 == *pin2) {
/* degenerate case */
PFace *f = chart->faces;
*pin1 = f->edge->vert;
@@ -3040,8 +3050,10 @@ static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf)
p_chart_boundaries(chart, NULL, &outer);
- if (!p_chart_symmetry_pins(chart, outer, &pin1, &pin2))
+ /* outer can be NULL with non-finite coords. */
+ if (!(outer && p_chart_symmetry_pins(chart, outer, &pin1, &pin2))) {
p_chart_extrema_verts(chart, &pin1, &pin2);
+ }
chart->u.lscm.pin1 = pin1;
chart->u.lscm.pin2 = pin2;
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index 20a8ab5c98c..59442e89787 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -46,6 +46,8 @@
#include "BLI_math_vector.h"
#include "BLI_string.h"
+#include "BLT_translation.h"
+
#include "BIF_gl.h"
#include "BKE_context.h"
@@ -54,6 +56,8 @@
#include "BKE_mesh_mapping.h"
#include "BKE_editmesh.h"
+#include "UI_interface.h"
+
#include "ED_mesh.h"
#include "ED_uvedit.h"
#include "ED_screen.h"
@@ -259,25 +263,24 @@ static void stitch_preview_delete(StitchPreviewer *stitch_preview)
}
}
-#define HEADER_LENGTH 256
-
/* This function updates the header of the UV editor when the stitch tool updates its settings */
static void stitch_update_header(StitchState *state, bContext *C)
{
- static char str[] =
+ const char *str = IFACE_(
"Mode(TAB) %s, "
"(S)nap %s, "
"(M)idpoints %s, "
"(L)imit %.2f (Alt Wheel adjust) %s, "
"Switch (I)sland, "
- "shift select vertices";
+ "shift select vertices"
+ );
- char msg[HEADER_LENGTH];
+ char msg[UI_MAX_DRAW_STR];
ScrArea *sa = CTX_wm_area(C);
if (sa) {
- BLI_snprintf(msg, HEADER_LENGTH, str,
- state->mode == STITCH_VERT ? "Vertex" : "Edge",
+ BLI_snprintf(msg, sizeof(msg), str,
+ state->mode == STITCH_VERT ? IFACE_("Vertex") : IFACE_("Edge"),
WM_bool_as_string(state->snap_islands),
WM_bool_as_string(state->midpoints),
state->limit_dist,
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 768624b1968..8e4ba4c0afa 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -49,6 +49,8 @@
#include "BLI_uvproject.h"
#include "BLI_string.h"
+#include "BLT_translation.h"
+
#include "BKE_cdderivedmesh.h"
#include "BKE_subsurf.h"
#include "BKE_context.h"
@@ -62,6 +64,8 @@
#include "PIL_time.h"
+#include "UI_interface.h"
+
#include "ED_image.h"
#include "ED_mesh.h"
#include "ED_screen.h"
@@ -554,12 +558,13 @@ static void minimize_stretch_iteration(bContext *C, wmOperator *op, bool interac
RNA_int_set(op->ptr, "iterations", ms->i);
if (interactive && (PIL_check_seconds_timer() - ms->lasttime > 0.5)) {
- char str[100];
+ char str[UI_MAX_DRAW_STR];
param_flush(ms->handle);
if (sa) {
- BLI_snprintf(str, sizeof(str), "Minimize Stretch. Blend %.2f (Press + and -, or scroll wheel to set)", ms->blend);
+ BLI_snprintf(str, sizeof(str),
+ IFACE_("Minimize Stretch. Blend %.2f (Press + and -, or scroll wheel to set)"), ms->blend);
ED_area_headerprint(sa, str);
}
diff --git a/source/blender/freestyle/FRS_freestyle.h b/source/blender/freestyle/FRS_freestyle.h
index 039a75a2f0f..a6382010ca7 100644
--- a/source/blender/freestyle/FRS_freestyle.h
+++ b/source/blender/freestyle/FRS_freestyle.h
@@ -63,8 +63,7 @@ void FRS_exit(void);
void FRS_copy_active_lineset(struct FreestyleConfig *config);
void FRS_paste_active_lineset(struct FreestyleConfig *config);
void FRS_delete_active_lineset(struct FreestyleConfig *config);
-void FRS_move_active_lineset_up(struct FreestyleConfig *config);
-void FRS_move_active_lineset_down(struct FreestyleConfig *config);
+bool FRS_move_active_lineset(struct FreestyleConfig *config, int direction);
/* Testing */
struct Material *FRS_create_stroke_material(struct Main *bmain, struct FreestyleLineStyle *linestyle);
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
index ea5a55731c3..1f5e2b63bfa 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
@@ -807,6 +807,7 @@ void BlenderFileLoader::insertShapeNode(ObjectInstanceRen *obi, int id)
// sets the id of the rep
rep->setId(Id(id, 0));
rep->setName(obi->ob->id.name + 2);
+ rep->setLibraryPath(obi->ob->id.lib ? obi->ob->id.lib->name : NULL);
const BBox<Vec3r> bbox = BBox<Vec3r>(Vec3r(ls.minBBox[0], ls.minBBox[1], ls.minBBox[2]),
Vec3r(ls.maxBBox[0], ls.maxBBox[1], ls.maxBBox[2]));
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
index 5c361de8d8d..f63cf771120 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
@@ -907,7 +907,7 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
material_index++;
} // loop over strokes
- test_object_materials(freestyle_bmain, (ID *)mesh);
+ test_object_materials(object_mesh, (ID *)mesh);
#if 0 // XXX
BLI_assert(mesh->totvert == vertex_index);
diff --git a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
index 4d8c6a66d42..2af4447e4dc 100644
--- a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
+++ b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
@@ -730,24 +730,14 @@ void FRS_delete_active_lineset(FreestyleConfig *config)
}
}
-void FRS_move_active_lineset_up(FreestyleConfig *config)
-{
- FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(config);
-
- if (lineset) {
- BLI_remlink(&config->linesets, lineset);
- BLI_insertlinkbefore(&config->linesets, lineset->prev, lineset);
- }
-}
-
-void FRS_move_active_lineset_down(FreestyleConfig *config)
+/**
+ * Reinsert the active lineset at an offset \a direction from current position.
+ * \return if position of active lineset has changed.
+ */
+bool FRS_move_active_lineset(FreestyleConfig *config, int direction)
{
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(config);
-
- if (lineset) {
- BLI_remlink(&config->linesets, lineset);
- BLI_insertlinkafter(&config->linesets, lineset->next, lineset);
- }
+ return (lineset != NULL) && BLI_listbase_link_move(&config->linesets, lineset, direction);
}
// Testing
diff --git a/source/blender/freestyle/intern/geometry/normal_cycle.h b/source/blender/freestyle/intern/geometry/normal_cycle.h
index 53bc23c6eb3..8d06865e31b 100644
--- a/source/blender/freestyle/intern/geometry/normal_cycle.h
+++ b/source/blender/freestyle/intern/geometry/normal_cycle.h
@@ -63,13 +63,13 @@ template <class T> inline void ogf_swap(T& x, T& y)
//_________________________________________________________
/**
-* NormalCycle evaluates the curvature tensor in function
-* of a set of dihedral angles and associated vectors.
-* Reference:
-* Restricted Delaunay Triangulation and Normal Cycle,
-* D. Cohen-Steiner and J.M. Morvan,
-* SOCG 2003
-*/
+ * NormalCycle evaluates the curvature tensor in function
+ * of a set of dihedral angles and associated vectors.
+ * Reference:
+ * Restricted Delaunay Triangulation and Normal Cycle,
+ * D. Cohen-Steiner and J.M. Morvan,
+ * SOCG 2003
+ */
class NormalCycle {
public:
NormalCycle();
diff --git a/source/blender/freestyle/intern/python/BPy_FrsNoise.cpp b/source/blender/freestyle/intern/python/BPy_FrsNoise.cpp
index 3f29d9899e8..9efbe6b53be 100644
--- a/source/blender/freestyle/intern/python/BPy_FrsNoise.cpp
+++ b/source/blender/freestyle/intern/python/BPy_FrsNoise.cpp
@@ -111,7 +111,7 @@ static PyObject *FrsNoise_drand(BPy_FrsNoise * /*self*/, PyObject *args, PyObjec
PyErr_SetString(PyExc_TypeError, "optional argument 1 must be of type int");
return NULL;
}
- if (seed){
+ if (seed) {
RandGen::srand48(seed);
}
return PyFloat_FromDouble(RandGen::drand48());
diff --git a/source/blender/freestyle/intern/python/BPy_ViewShape.cpp b/source/blender/freestyle/intern/python/BPy_ViewShape.cpp
index 253bf278478..f2f53159fcf 100644
--- a/source/blender/freestyle/intern/python/BPy_ViewShape.cpp
+++ b/source/blender/freestyle/intern/python/BPy_ViewShape.cpp
@@ -296,6 +296,19 @@ static PyObject *ViewShape_name_get(BPy_ViewShape *self, void *UNUSED(closure))
return PyUnicode_FromString(self->vs->getName());
}
+PyDoc_STRVAR(ViewShape_library_path_doc,
+"The library path of the ViewShape.\n"
+"\n"
+":type: str, or None if the ViewShape is not part of a library");
+
+static PyObject *ViewShape_library_path_get(BPy_ViewShape *self, void *UNUSED(closure))
+{
+ const char *name = self->vs->getLibraryPath();
+ if (!name)
+ Py_RETURN_NONE;
+ return PyUnicode_FromString(name);
+}
+
PyDoc_STRVAR(ViewShape_id_doc,
"The Id of this ViewShape.\n"
"\n"
@@ -313,6 +326,7 @@ static PyGetSetDef BPy_ViewShape_getseters[] = {
(char *)ViewShape_vertices_doc, NULL},
{(char *)"edges", (getter)ViewShape_edges_get, (setter)ViewShape_edges_set, (char *)ViewShape_edges_doc, NULL},
{(char *)"name", (getter)ViewShape_name_get, (setter)NULL, (char *)ViewShape_name_doc, NULL},
+ {(char *)"library_path", (getter)ViewShape_library_path_get, (setter)NULL, (char *)ViewShape_library_path_doc, NULL},
{(char *)"id", (getter)ViewShape_id_get, (setter)NULL, (char *)ViewShape_id_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp
index e35076ec7fe..96a8bee9394 100644
--- a/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp
@@ -121,7 +121,7 @@ static PyObject *StrokeVertexIterator_iternext(BPy_StrokeVertexIterator *self)
return NULL;
}
/* If at the start of the iterator, only return the object
- * and don't increment, to keep for-loops in sync */
+ * and don't increment, to keep for-loops in sync */
else if (self->at_start) {
self->at_start = false;
}
diff --git a/source/blender/freestyle/intern/scene_graph/FrsMaterial.h b/source/blender/freestyle/intern/scene_graph/FrsMaterial.h
index a00f983bbcf..220c966a5d0 100644
--- a/source/blender/freestyle/intern/scene_graph/FrsMaterial.h
+++ b/source/blender/freestyle/intern/scene_graph/FrsMaterial.h
@@ -298,9 +298,9 @@ public:
inline void setShininess(const float s);
/*! Sets the line color priority.
- * \param priority
- * Priority
- */
+ * \param priority
+ * Priority
+ */
inline void setPriority(const int priority);
/* operators */
diff --git a/source/blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.h b/source/blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.h
index 4b079df5632..8dc93d84201 100644
--- a/source/blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.h
+++ b/source/blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.h
@@ -52,16 +52,6 @@ public:
return _SceneRenderLayer;
}
- inline void setSceneRenderLayer(Scene& scene)
- {
- _Scene = scene;
- }
-
- inline void setSceneRenderLayer(SceneRenderLayer& srl)
- {
- _SceneRenderLayer = srl;
- }
-
/*! Accept the corresponding visitor */
virtual void accept(SceneVisitor& v);
diff --git a/source/blender/freestyle/intern/scene_graph/Rep.h b/source/blender/freestyle/intern/scene_graph/Rep.h
index c5036cdb153..773eb2d3278 100644
--- a/source/blender/freestyle/intern/scene_graph/Rep.h
+++ b/source/blender/freestyle/intern/scene_graph/Rep.h
@@ -48,6 +48,8 @@ public:
inline Rep() : BaseObject()
{
_Id = 0;
+ _Name = 0;
+ _LibraryPath = 0;
_FrsMaterial = 0;
}
@@ -55,6 +57,7 @@ public:
{
_Id = iBrother._Id;
_Name = iBrother._Name;
+ _LibraryPath = iBrother._LibraryPath;
if (0 == iBrother._FrsMaterial)
_FrsMaterial = 0;
else
@@ -68,6 +71,7 @@ public:
std::swap(_BBox, ioOther._BBox);
std::swap(_Id, ioOther._Id);
std::swap(_Name, ioOther._Name);
+ std::swap(_LibraryPath, ioOther._LibraryPath);
std::swap(_FrsMaterial, ioOther._FrsMaterial);
}
@@ -76,6 +80,7 @@ public:
if (&iBrother != this) {
_Id = iBrother._Id;
_Name = iBrother._Name;
+ _LibraryPath = iBrother._LibraryPath;
if (0 == iBrother._FrsMaterial) {
_FrsMaterial = 0;
}
@@ -132,6 +137,11 @@ public:
return _Name;
}
+ inline const char *getLibraryPath() const
+ {
+ return _LibraryPath;
+ }
+
inline const FrsMaterial *frs_material() const
{
return _FrsMaterial;
@@ -153,7 +163,12 @@ public:
_Name = name;
}
- inline void setFrsMaterial(const FrsMaterial& iMaterial)
+ inline void setLibraryPath(const char *path)
+ {
+ _LibraryPath = path;
+ }
+
+ inline void setFrsMaterial(const FrsMaterial& iMaterial)
{
_FrsMaterial = new FrsMaterial(iMaterial);
}
@@ -162,6 +177,7 @@ private:
BBox<Vec3f> _BBox;
Id _Id;
const char *_Name;
+ const char *_LibraryPath;
FrsMaterial *_FrsMaterial;
};
diff --git a/source/blender/freestyle/intern/stroke/AdvancedPredicates1D.h b/source/blender/freestyle/intern/stroke/AdvancedPredicates1D.h
index f650e32b278..c65f121e9ba 100644
--- a/source/blender/freestyle/intern/stroke/AdvancedPredicates1D.h
+++ b/source/blender/freestyle/intern/stroke/AdvancedPredicates1D.h
@@ -46,8 +46,8 @@ namespace Predicates1D {
// DensityLowerThanUP1D
/*! Returns true if the density evaluated for the
-* Interface1D is less than a user-defined density value.
-*/
+ * Interface1D is less than a user-defined density value.
+ */
class DensityLowerThanUP1D : public UnaryPredicate1D
{
public:
diff --git a/source/blender/freestyle/intern/stroke/BasicStrokeShaders.h b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.h
index e3842f45eb0..cc935a7e311 100644
--- a/source/blender/freestyle/intern/stroke/BasicStrokeShaders.h
+++ b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.h
@@ -619,9 +619,9 @@ public:
}
/*! Builds the shader.
- * \param nodetree
- * A node tree (of new shading nodes) to define textures.
- */
+ * \param nodetree
+ * A node tree (of new shading nodes) to define textures.
+ */
BlenderTextureShader(bNodeTree *nodetree) : StrokeShader()
{
_nodeTree = nodetree;
diff --git a/source/blender/freestyle/intern/stroke/Curve.cpp b/source/blender/freestyle/intern/stroke/Curve.cpp
index 69c5dcdfe28..a8dbce84971 100644
--- a/source/blender/freestyle/intern/stroke/Curve.cpp
+++ b/source/blender/freestyle/intern/stroke/Curve.cpp
@@ -133,7 +133,7 @@ iA_B_eq_iB_A:
//_t2d = t3;
_t2d = t2 * t3;
}
- else if ((iA->getPoint2D() - iA->getPoint2D()).norm() < 1.0e-6) {
+ else if ((iA->getPoint2D() - iB->getPoint2D()).norm() < 1.0e-6) {
__A = iB->A();
__B = iB->B();
//_t2d = t3;
diff --git a/source/blender/freestyle/intern/stroke/Stroke.h b/source/blender/freestyle/intern/stroke/Stroke.h
index 5f0b4eab309..db96a27e073 100644
--- a/source/blender/freestyle/intern/stroke/Stroke.h
+++ b/source/blender/freestyle/intern/stroke/Stroke.h
@@ -605,15 +605,15 @@ public:
*/
int Resample(float iSampling);
- /*! Removes all vertices from the Stroke.
- */
- void RemoveAllVertices();
+ /*! Removes all vertices from the Stroke.
+ */
+ void RemoveAllVertices();
/*! Removes the stroke vertex iVertex
- * from the stroke.
- * The length and curvilinear abscissa are updated
- * consequently.
- */
+ * from the stroke.
+ * The length and curvilinear abscissa are updated
+ * consequently.
+ */
void RemoveVertex(StrokeVertex *iVertex);
/*! Inserts the stroke vertex iVertex in the stroke before next.
diff --git a/source/blender/freestyle/intern/stroke/StrokeRep.cpp b/source/blender/freestyle/intern/stroke/StrokeRep.cpp
index ab06e207331..028127897ff 100644
--- a/source/blender/freestyle/intern/stroke/StrokeRep.cpp
+++ b/source/blender/freestyle/intern/stroke/StrokeRep.cpp
@@ -135,11 +135,11 @@ void Strip::createStrip (const vector<StrokeVertex*>& iStrokeVertices)
int orientationErrors = 0;
//special case of first vertex
- v = iStrokeVertices.begin();
+ v2 = v = iStrokeVertices.begin();
+ ++v2;
sv = *v;
vPrev = v; //in case the stroke has only 2 vertices;
- ++v;
- sv2 = *v;
+ sv2 = *v2;
Vec2r dir(sv2->getPoint() - sv->getPoint());
Vec2r orthDir(-dir[1], dir[0]);
if (orthDir.norm() > ZERO)
@@ -189,11 +189,7 @@ void Strip::createStrip (const vector<StrokeVertex*>& iStrokeVertices)
int i = 2; // 2 because we have already processed the first vertex
- for (vend = iStrokeVertices.end(); v != vend; ++v) {
- v2 = v;
- ++v2;
- if (v2 == vend)
- break;
+ for (vend = iStrokeVertices.end(), ++v, ++v2; v2 != vend; vPrev = v++, ++v2) {
sv = (*v);
sv2 = (*v2);
svPrev = (*vPrev);
@@ -289,8 +285,6 @@ void Strip::createStrip (const vector<StrokeVertex*>& iStrokeVertices)
{
_vertices[i - 1]->setPoint2d(p - thickness[0] * stripDir);
}
-
- vPrev = v;
} // end of for
//special case of last vertex
diff --git a/source/blender/freestyle/intern/system/PseudoNoise.cpp b/source/blender/freestyle/intern/system/PseudoNoise.cpp
index 4949cb8c430..638eb6ca16a 100644
--- a/source/blender/freestyle/intern/system/PseudoNoise.cpp
+++ b/source/blender/freestyle/intern/system/PseudoNoise.cpp
@@ -33,7 +33,7 @@
static int modf_to_index(Freestyle::real x, unsigned int range)
{
- if (finite(x)) {
+ if (isfinite(x)) {
Freestyle::real tmp;
int i = abs((int)(modf(x, &tmp) * range));
BLI_assert(i >= 0 && i < range);
diff --git a/source/blender/freestyle/intern/system/PythonInterpreter.h b/source/blender/freestyle/intern/system/PythonInterpreter.h
index 5403ec6b13b..0e08af1bac8 100644
--- a/source/blender/freestyle/intern/system/PythonInterpreter.h
+++ b/source/blender/freestyle/intern/system/PythonInterpreter.h
@@ -84,8 +84,7 @@ public:
Text *text = BKE_text_load(&_freestyle_bmain, fn, G.main->name);
if (text) {
ok = BPY_execute_text(_context, text, reports, false);
- BKE_text_unlink(&_freestyle_bmain, text);
- BKE_libblock_free(&_freestyle_bmain, text);
+ BKE_libblock_delete(&_freestyle_bmain, text);
}
else {
BKE_reportf(reports, RPT_ERROR, "Cannot open file: %s", fn);
diff --git a/source/blender/freestyle/intern/view_map/BoxGrid.cpp b/source/blender/freestyle/intern/view_map/BoxGrid.cpp
index ae22a26ec9b..34fa2b14379 100644
--- a/source/blender/freestyle/intern/view_map/BoxGrid.cpp
+++ b/source/blender/freestyle/intern/view_map/BoxGrid.cpp
@@ -77,11 +77,11 @@ BoxGrid::Iterator::Iterator (BoxGrid& grid, Vec3r& center, real /*epsilon*/)
// Find target cell
_cell = grid.findCell(_target);
#if BOX_GRID_LOGGING
- if (G.debug & G_DEBUG_FREESTYLE) {
- cout << "Searching for occluders of edge centered at " << _target << " in cell [" <<
- 1_cell->boundary[0] << ", " << _cell->boundary[1] << ", " << _cell->boundary[2] <<
- ", " << _cell->boundary[3] << "] (" << _cell->faces.size() << " occluders)" << endl;
- }
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Searching for occluders of edge centered at " << _target << " in cell [" <<
+ 1_cell->boundary[0] << ", " << _cell->boundary[1] << ", " << _cell->boundary[2] <<
+ ", " << _cell->boundary[3] << "] (" << _cell->faces.size() << " occluders)" << endl;
+ }
#endif
// Set iterator
diff --git a/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp b/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp
index 85c6390cb9e..a97e60d5f60 100644
--- a/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp
+++ b/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp
@@ -640,7 +640,7 @@ void FEdgeXDetector::postProcessSuggestiveContourFace(WXFace *iFace)
normal_vec = wxf->GetVertexNormal(v); // FIXME: what about e1 ^ e2 ?
radial_normal_vec = er_vec ^ normal_vec;
- // Test wether the radial plan intersects with the edge at the opposite of v.
+ // Test whether the radial plan intersects with the edge at the opposite of v.
res = GeomUtils::intersectRayPlane(opposite_vertex_a->GetVertex(), opposite_edge->GetVec(),
radial_normal_vec, -(v_vec * radial_normal_vec),
t, 1.0e-06);
diff --git a/source/blender/freestyle/intern/view_map/Functions0D.h b/source/blender/freestyle/intern/view_map/Functions0D.h
index 647a3a530c6..f0009fca6ea 100644
--- a/source/blender/freestyle/intern/view_map/Functions0D.h
+++ b/source/blender/freestyle/intern/view_map/Functions0D.h
@@ -429,12 +429,12 @@ public:
// QiF0D
/*! Returns the quantitative invisibility of this Interface0D.
-* This evaluation can be ambiguous (in the case of a TVertex for example).
-* This functor tries to remove this ambiguity using the context offered by the 1D element to which the
-* Interface0DIterator& belongs to.
-* However, there still can be problematic cases, and the user willing to deal with this cases in a specific way
-* should implement its own getQIF0D functor.
-*/
+ * This evaluation can be ambiguous (in the case of a TVertex for example).
+ * This functor tries to remove this ambiguity using the context offered by the 1D element to which the
+ * Interface0DIterator& belongs to.
+ * However, there still can be problematic cases, and the user willing to deal with this cases in a specific way
+ * should implement its own getQIF0D functor.
+ */
class QuantitativeInvisibilityF0D : public UnaryFunction0D<unsigned int>
{
public:
diff --git a/source/blender/freestyle/intern/view_map/Functions1D.cpp b/source/blender/freestyle/intern/view_map/Functions1D.cpp
index 11e0cc37d4d..8f16f78cb10 100644
--- a/source/blender/freestyle/intern/view_map/Functions1D.cpp
+++ b/source/blender/freestyle/intern/view_map/Functions1D.cpp
@@ -104,7 +104,7 @@ int QuantitativeInvisibilityF1D::operator()(Interface1D& inter)
}
FEdge *fe = dynamic_cast<FEdge*>(&inter);
if (fe) {
- result = ve->qi();
+ result = fe->qi();
return 0;
}
result = integrate(_func, inter.verticesBegin(), inter.verticesEnd(), _integration);
diff --git a/source/blender/freestyle/intern/view_map/Silhouette.h b/source/blender/freestyle/intern/view_map/Silhouette.h
index 0b20c9f6aa2..9d373107bfa 100644
--- a/source/blender/freestyle/intern/view_map/Silhouette.h
+++ b/source/blender/freestyle/intern/view_map/Silhouette.h
@@ -1204,9 +1204,9 @@ public:
}
/*! Returns the index of the material of the face lying on the
- * right of the FEdge. If this FEdge is a border,
- * it has no Face on its right and therefore, no material.
- */
+ * right of the FEdge. If this FEdge is a border,
+ * it has no Face on its right and therefore, no material.
+ */
inline unsigned aFrsMaterialIndex() const
{
return _aFrsMaterialIndex;
@@ -1416,6 +1416,7 @@ private:
vector<FEdge*> _edgesList; // list of all edges
Id _Id;
const char *_Name;
+ const char *_LibraryPath;
BBox<Vec3r> _BBox;
vector<FrsMaterial> _FrsMaterials;
@@ -1436,6 +1437,7 @@ public:
_importance = 0.0f;
_ViewShape = NULL;
_Name = NULL;
+ _LibraryPath = NULL;
}
/*! Copy constructor */
@@ -1444,6 +1446,7 @@ public:
userdata = NULL;
_Id = iBrother._Id;
_Name = iBrother._Name;
+ _LibraryPath = iBrother._LibraryPath;
_BBox = iBrother.bbox();
_FrsMaterials = iBrother._FrsMaterials;
_importance = iBrother._importance;
@@ -1893,6 +1896,12 @@ public:
return _Name;
}
+ /*! Returns the library path of the Shape. */
+ inline const char *getLibraryPath() const
+ {
+ return _LibraryPath;
+ }
+
/* Modififers */
/*! Sets the Id of the shape.*/
inline void setId(Id id)
@@ -1906,6 +1915,12 @@ public:
_Name = name;
}
+ /*! Sets the library path of the shape.*/
+ inline void setLibraryPath(const char *path)
+ {
+ _LibraryPath = path;
+ }
+
/*! Sets the list of materials for the shape */
inline void setFrsMaterials(const vector<FrsMaterial>& iMaterials)
{
diff --git a/source/blender/freestyle/intern/view_map/ViewMap.h b/source/blender/freestyle/intern/view_map/ViewMap.h
index 74297e1dbfd..8b73c8aac3a 100644
--- a/source/blender/freestyle/intern/view_map/ViewMap.h
+++ b/source/blender/freestyle/intern/view_map/ViewMap.h
@@ -1565,12 +1565,18 @@ public:
return _SShape->getId();
}
- /*! Returns the ViewShape id. */
+ /*! Returns the ViewShape name. */
inline const char *getName() const
{
return _SShape->getName();
}
+ /*! Returns the ViewShape library path. */
+ inline const char *getLibraryPath() const
+ {
+ return _SShape->getLibraryPath();
+ }
+
/* modifiers */
/*! Sets the SShape on top of which the ViewShape is built. */
inline void setSShape(SShape *iSShape)
diff --git a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp
index 9ca021475b2..380bb0dd3ca 100644
--- a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp
+++ b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp
@@ -1204,6 +1204,7 @@ void ViewMapBuilder::computeInitialViewEdges(WingedEdge& we)
psShape = new SShape;
psShape->setId((*it)->GetId());
psShape->setName((*it)->getName());
+ psShape->setLibraryPath((*it)->getLibraryPath());
psShape->setFrsMaterials((*it)->frs_materials()); // FIXME
// create the view shape
@@ -2098,7 +2099,7 @@ int ViewMapBuilder::ComputeRayCastingVisibility(FEdge *fe, Grid *iGrid, real eps
}
// Find occludee
- FindOccludee(fe, iGrid, epsilon, oaPolygon, timestamp, u, center, edge, origin, faceVertices);
+ FindOccludee(fe, iGrid, epsilon, oaPolygon, timestamp, u, center, origin, edge, faceVertices);
return qi;
}
diff --git a/source/blender/freestyle/intern/winged_edge/Curvature.cpp b/source/blender/freestyle/intern/winged_edge/Curvature.cpp
index 97dcc86cf31..989e101dd1a 100644
--- a/source/blender/freestyle/intern/winged_edge/Curvature.cpp
+++ b/source/blender/freestyle/intern/winged_edge/Curvature.cpp
@@ -372,21 +372,21 @@ void gts_vertex_principal_directions(WVertex *v, Vec3r Kh, real Kg, Vec3r &e1, V
f2 = e->GetbFace();
/* We are solving for the values of the curvature tensor
- * B = [ a b ; b c ].
- * The computations here are from section 5 of [Meyer et al 2002].
- *
- * The first step is to calculate the linear equations governing the values of (a,b,c). These can be computed
- * by setting the derivatives of the error E to zero (section 5.3).
- *
- * Since a + c = norm(Kh), we only compute the linear equations for dE/da and dE/db. (NB: [Meyer et al 2002]
- * has the equation a + b = norm(Kh), but I'm almost positive this is incorrect).
- *
- * Note that the w_ij (defined in section 5.2) are all scaled by (1/8*A_mixed). We drop this uniform scale
- * factor because the solution of the linear equations doesn't rely on it.
- *
- * The terms of the linear equations are xterm_dy with x in {a,b,c} and y in {a,b}. There are also const_dy
- * terms that are the constant factors in the equations.
- */
+ * B = [ a b ; b c ].
+ * The computations here are from section 5 of [Meyer et al 2002].
+ *
+ * The first step is to calculate the linear equations governing the values of (a,b,c). These can be computed
+ * by setting the derivatives of the error E to zero (section 5.3).
+ *
+ * Since a + c = norm(Kh), we only compute the linear equations for dE/da and dE/db. (NB: [Meyer et al 2002]
+ * has the equation a + b = norm(Kh), but I'm almost positive this is incorrect).
+ *
+ * Note that the w_ij (defined in section 5.2) are all scaled by (1/8*A_mixed). We drop this uniform scale
+ * factor because the solution of the linear equations doesn't rely on it.
+ *
+ * The terms of the linear equations are xterm_dy with x in {a,b,c} and y in {a,b}. There are also const_dy
+ * terms that are the constant factors in the equations.
+ */
/* find the vector from v along edge e */
vec_edge = Vec3r(-1 * e->GetVec());
@@ -400,7 +400,7 @@ void gts_vertex_principal_directions(WVertex *v, Vec3r Kh, real Kg, Vec3r &e1, V
/* section 5.2 */
/* I don't like performing a minimization where some of the weights can be negative (as can be the case
- * if f1 or f2 are obtuse). To ensure all-positive weights, we check for obtuseness. */
+ * if f1 or f2 are obtuse). To ensure all-positive weights, we check for obtuseness. */
weight = 0.0;
if (!triangle_obtuse(v, f1)) {
weight += ve2 * cotan(f1->GetNextOEdge(e->twin())->GetbVertex(), e->GetaVertex(), e->GetbVertex()) / 8.0;
diff --git a/source/blender/freestyle/intern/winged_edge/WEdge.cpp b/source/blender/freestyle/intern/winged_edge/WEdge.cpp
index 99aa2d22239..7bec5ba1d6e 100644
--- a/source/blender/freestyle/intern/winged_edge/WEdge.cpp
+++ b/source/blender/freestyle/intern/winged_edge/WEdge.cpp
@@ -471,6 +471,7 @@ WShape::WShape(WShape& iBrother)
{
_Id = iBrother.GetId();
_Name = iBrother._Name;
+ _LibraryPath = iBrother._LibraryPath;
_FrsMaterials = iBrother._FrsMaterials;
#if 0
_meanEdgeSize = iBrother._meanEdgeSize;
diff --git a/source/blender/freestyle/intern/winged_edge/WEdge.h b/source/blender/freestyle/intern/winged_edge/WEdge.h
index 8001342775b..14109fba843 100644
--- a/source/blender/freestyle/intern/winged_edge/WEdge.h
+++ b/source/blender/freestyle/intern/winged_edge/WEdge.h
@@ -1025,6 +1025,7 @@ protected:
vector<WFace *> _FaceList;
int _Id;
const char *_Name;
+ const char *_LibraryPath;
static unsigned _SceneCurrentId;
#if 0
Vec3f _min;
@@ -1043,6 +1044,8 @@ public:
#endif
_Id = _SceneCurrentId;
_SceneCurrentId++;
+ _Name = 0;
+ _LibraryPath = 0;
}
/*! copy constructor */
@@ -1127,6 +1130,11 @@ public:
return _Name;
}
+ inline const char *getLibraryPath() const
+ {
+ return _LibraryPath;
+ }
+
/*! modifiers */
static inline void setCurrentId(const unsigned id)
{
@@ -1176,6 +1184,11 @@ public:
_Name = name;
}
+ inline void setLibraryPath(const char *path)
+ {
+ _LibraryPath = path;
+ }
+
/*! designed to build a specialized WFace for use in MakeFace */
virtual WFace *instanciateFace() const
{
diff --git a/source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp b/source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp
index 78773a9680d..dfdeedef2e1 100644
--- a/source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp
+++ b/source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp
@@ -42,6 +42,7 @@ void WXEdgeBuilder::visitIndexedFaceSet(IndexedFaceSet& ifs)
}
shape->setId(ifs.getId().getFirst());
shape->setName(ifs.getName());
+ shape->setLibraryPath(ifs.getLibraryPath());
//ifs.setId(shape->GetId());
}
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index cfa083116f2..8885209ce01 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -78,6 +78,7 @@ set(SRC
shaders/gpu_shader_vsm_store_frag.glsl
shaders/gpu_shader_vsm_store_vert.glsl
shaders/gpu_shader_fx_depth_resolve.glsl
+ shaders/gpu_shader_fire_frag.glsl
shaders/gpu_shader_smoke_frag.glsl
shaders/gpu_shader_smoke_vert.glsl
@@ -99,6 +100,7 @@ set(SRC
)
data_to_c_simple(shaders/gpu_shader_geometry.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_fire_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_smoke_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_smoke_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_material.glsl SRC)
diff --git a/source/blender/gpu/GPU_basic_shader.h b/source/blender/gpu/GPU_basic_shader.h
index df2da971845..d9bf3d1ced3 100644
--- a/source/blender/gpu/GPU_basic_shader.h
+++ b/source/blender/gpu/GPU_basic_shader.h
@@ -46,11 +46,13 @@ typedef enum GPUBasicShaderOption {
GPU_SHADER_LIGHTING = (1 << 1), /* use lighting */
GPU_SHADER_TWO_SIDED = (1 << 2), /* flip normals towards viewer */
GPU_SHADER_TEXTURE_2D = (1 << 3), /* use 2D texture to replace diffuse color */
+ GPU_SHADER_TEXTURE_RECT = (1 << 4), /* same as GPU_SHADER_TEXTURE_2D, for GL_TEXTURE_RECTANGLE */
- GPU_SHADER_SOLID_LIGHTING = (1 << 4), /* use faster lighting (set automatically) */
- GPU_SHADER_STIPPLE = (1 << 5), /* use stipple */
- GPU_SHADER_LINE = (1 << 6), /* draw lines */
- GPU_SHADER_OPTIONS_NUM = 7,
+ GPU_SHADER_SOLID_LIGHTING = (1 << 5), /* use faster lighting (set automatically) */
+ GPU_SHADER_STIPPLE = (1 << 6), /* use stipple */
+ GPU_SHADER_LINE = (1 << 7), /* draw lines */
+ GPU_SHADER_FLAT_NORMAL = (1 << 8), /* use flat normals */
+ GPU_SHADER_OPTIONS_NUM = 9,
GPU_SHADER_OPTION_COMBINATIONS = (1 << GPU_SHADER_OPTIONS_NUM)
} GPUBasicShaderOption;
@@ -74,10 +76,30 @@ void GPU_basic_shaders_init(void);
void GPU_basic_shaders_exit(void);
void GPU_basic_shader_bind(int options);
+void GPU_basic_shader_bind_enable(int options);
+void GPU_basic_shader_bind_disable(int options);
+
int GPU_basic_shader_bound_options(void);
-void GPU_basic_shader_colors(const float diffuse[3], const float specular[3],
- int shininess, float alpha);
+/* Only use for small blocks of code that don't support glsl shader. */
+#define GPU_BASIC_SHADER_DISABLE_AND_STORE(bound_options) \
+if (GPU_basic_shader_use_glsl_get()) { \
+ if ((bound_options = GPU_basic_shader_bound_options())) { \
+ GPU_basic_shader_bind(0); \
+ } \
+} \
+else { bound_options = 0; } ((void)0)
+#define GPU_BASIC_SHADER_ENABLE_AND_RESTORE(bound_options) \
+if (GPU_basic_shader_use_glsl_get()) { \
+ if (bound_options) { \
+ GPU_basic_shader_bind(bound_options); \
+ } \
+} ((void)0)
+
+
+void GPU_basic_shader_colors(
+ const float diffuse[3], const float specular[3],
+ int shininess, float alpha);
/* Fixed Function Lighting */
@@ -110,6 +132,9 @@ void GPU_basic_shader_stipple(GPUBasicShaderStipple stipple_id);
void GPU_basic_shader_line_stipple(GLint stipple_factor, GLushort stipple_pattern);
void GPU_basic_shader_line_width(float line_width);
+bool GPU_basic_shader_use_glsl_get(void);
+void GPU_basic_shader_use_glsl_set(bool enabled);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index a8656c05224..b693d473bd8 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -49,6 +49,7 @@ struct DerivedMesh;
struct GSet;
struct GPUVertPointLink;
struct GPUDrawObject;
+struct GridCommonGPUBuffer;
struct PBVH;
struct MVert;
@@ -147,6 +148,7 @@ typedef struct GPUVertPointLink {
/* used for GLSL materials */
typedef struct GPUAttrib {
int index;
+ int info_index;
int size;
int type;
} GPUAttrib;
@@ -159,9 +161,6 @@ void GPU_buffer_free(GPUBuffer *buffer);
void GPU_drawobject_free(struct DerivedMesh *dm);
-/* free special global multires grid buffer */
-void GPU_buffer_multires_free(bool force);
-
/* flag that controls data type to fill buffer with, a modifier will prepare. */
typedef enum {
GPU_BUFFER_VERTEX = 0,
@@ -179,6 +178,10 @@ typedef enum {
GPU_BINDING_INDEX = 1,
} GPUBindingType;
+typedef enum {
+ GPU_ATTR_INFO_SRGB = (1 << 0),
+} GPUAttrInfo;
+
/* called before drawing */
void GPU_vertex_setup(struct DerivedMesh *dm);
void GPU_normal_setup(struct DerivedMesh *dm);
@@ -220,14 +223,15 @@ typedef struct GPU_PBVH_Buffers GPU_PBVH_Buffers;
/* build */
GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers(
- const int (*face_vert_indices)[4],
+ const int (*face_vert_indices)[3],
const struct MPoly *mpoly, const struct MLoop *mloop, const struct MLoopTri *looptri,
const struct MVert *verts,
const int *face_indices,
const int face_indices_len);
-GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(int *grid_indices, int totgrid,
- unsigned int **grid_hidden, int gridsize, const struct CCGKey *key);
+GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(
+ int *grid_indices, int totgrid, unsigned int **grid_hidden, int gridsize, const struct CCGKey *key,
+ struct GridCommonGPUBuffer **grid_common_gpu_buffer);
GPU_PBVH_Buffers *GPU_build_bmesh_pbvh_buffers(bool smooth_shading);
@@ -236,7 +240,7 @@ GPU_PBVH_Buffers *GPU_build_bmesh_pbvh_buffers(bool smooth_shading);
void GPU_update_mesh_pbvh_buffers(
GPU_PBVH_Buffers *buffers, const struct MVert *mvert,
const int *vert_indices, int totvert, const float *vmask,
- const int (*face_vert_indices)[4], bool show_diffuse_color);
+ const int (*face_vert_indices)[3], bool show_diffuse_color);
void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers,
struct BMesh *bm,
@@ -262,5 +266,6 @@ void GPU_init_draw_pbvh_BB(void);
bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, struct GSet *bm_faces, bool show_diffuse_color);
void GPU_free_pbvh_buffers(GPU_PBVH_Buffers *buffers);
+void GPU_free_pbvh_buffer_multires(struct GridCommonGPUBuffer **grid_common_gpu_buffer);
#endif
diff --git a/source/blender/gpu/GPU_debug.h b/source/blender/gpu/GPU_debug.h
index 2c1728bfff1..61b2bc591ce 100644
--- a/source/blender/gpu/GPU_debug.h
+++ b/source/blender/gpu/GPU_debug.h
@@ -34,8 +34,6 @@
#include "GPU_glew.h"
-#include "BLI_utildefines.h"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -62,7 +60,7 @@ void GPU_assert_no_gl_errors(const char *file, int line, const char *str);
/* inserts a debug marker message for the debug context messaging system */
-void GPU_string_marker(size_t size, const char *str);
+void GPU_string_marker(const char *str);
#ifdef __cplusplus
}
diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h
index 75d6362f13e..90b65af87c8 100644
--- a/source/blender/gpu/GPU_draw.h
+++ b/source/blender/gpu/GPU_draw.h
@@ -97,8 +97,9 @@ void GPU_clear_tpage(bool force);
* - this affects fixed functions materials and texface, not glsl */
int GPU_default_lights(void);
-int GPU_scene_object_lights(struct Scene *scene, struct Object *ob,
- int lay, float viewmat[4][4], int ortho);
+int GPU_scene_object_lights(
+ struct Scene *scene, struct Object *ob,
+ int lay, float viewmat[4][4], int ortho);
/* Text render
* - based on moving uv coordinates */
@@ -132,13 +133,15 @@ void GPU_set_gpu_mipmapping(int gpu_mipmap);
void GPU_paint_update_image(struct Image *ima, struct ImageUser *iuser, int x, int y, int w, int h);
void GPU_update_images_framechange(void);
int GPU_update_image_time(struct Image *ima, double time);
-int GPU_verify_image(struct Image *ima,
- struct ImageUser *iuser, int textarget, int tftile, bool compare, bool mipmap, bool is_data);
-void GPU_create_gl_tex(unsigned int *bind, unsigned int *rect, float *frect, int rectw, int recth,
- int textarget, bool mipmap, bool use_hight_bit_depth, struct Image *ima);
+int GPU_verify_image(
+ struct Image *ima, struct ImageUser *iuser,
+ int textarget, int tftile, bool compare, bool mipmap, bool is_data);
+void GPU_create_gl_tex(
+ unsigned int *bind, unsigned int *rect, float *frect, int rectw, int recth,
+ int textarget, bool mipmap, bool use_hight_bit_depth, struct Image *ima);
void GPU_create_gl_tex_compressed(
- unsigned int *bind, unsigned int *pix, int x, int y, int mipmap,
- int textarget, struct Image *ima, struct ImBuf *ibuf);
+ unsigned int *bind, unsigned int *pix, int x, int y, int mipmap,
+ int textarget, struct Image *ima, struct ImBuf *ibuf);
bool GPU_upload_dxt_texture(struct ImBuf *ibuf);
void GPU_free_image(struct Image *ima);
void GPU_free_images(void);
@@ -157,6 +160,12 @@ struct DerivedMesh;
void GPU_draw_update_fvar_offset(struct DerivedMesh *dm);
#endif
+/* utilities */
+void GPU_select_index_set(int index);
+void GPU_select_index_get(int index, int *r_col);
+int GPU_select_to_index(unsigned int col);
+void GPU_select_to_index_array(unsigned int *col, const unsigned int size);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h
index 4a728c881b6..31ad8243c4b 100644
--- a/source/blender/gpu/GPU_extensions.h
+++ b/source/blender/gpu/GPU_extensions.h
@@ -41,7 +41,6 @@ extern "C" {
void GPU_extensions_disable(void);
bool GPU_legacy_support(void);
-bool GPU_glsl_support(void);
bool GPU_full_non_power_of_two_support(void);
bool GPU_display_list_support(void);
bool GPU_bicubic_bump_support(void);
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index 81b08e2b128..0d92d22a173 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -241,6 +241,7 @@ void GPU_material_vertex_attributes(GPUMaterial *material,
bool GPU_material_do_color_management(GPUMaterial *mat);
bool GPU_material_use_new_shading_nodes(GPUMaterial *mat);
+bool GPU_material_use_world_space_shading(GPUMaterial *mat);
/* Exported shading */
@@ -282,6 +283,7 @@ typedef struct GPUInputUniform {
GPUDataType datatype; /* type of uniform data */
struct Object *lamp; /* when type=GPU_DYNAMIC_LAMP_... or GPU_DYNAMIC_SAMPLER_2DSHADOW */
struct Image *image; /* when type=GPU_DYNAMIC_SAMPLER_2DIMAGE */
+ struct Material *material;/* when type=GPU_DYNAMIC_MAT_... */
int texnumber; /* when type=GPU_DYNAMIC_SAMPLER, texture number: 0.. */
unsigned char *texpixels; /* for internally generated texture, pixel data in RGBA format */
int texsize; /* size in pixel of the texture in texpixels buffer:
@@ -335,6 +337,7 @@ void GPU_mist_update_enable(short enable);
void GPU_mist_update_values(int type, float start, float dist, float inten, float color[3]);
void GPU_horizon_update_color(float color[3]);
void GPU_ambient_update_color(float color[3]);
+void GPU_zenith_update_color(float color[3]);
struct GPUParticleInfo
{
diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h
index 4c674b460aa..762329ee077 100644
--- a/source/blender/gpu/GPU_shader.h
+++ b/source/blender/gpu/GPU_shader.h
@@ -104,6 +104,7 @@ typedef struct GPUVertexAttribs {
struct {
int type;
int glindex;
+ int glinfoindoex;
int gltexco;
int attribid;
char name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */
diff --git a/source/blender/gpu/intern/gpu_basic_shader.c b/source/blender/gpu/intern/gpu_basic_shader.c
index b6fe40a13ee..a2b89239344 100644
--- a/source/blender/gpu/intern/gpu_basic_shader.c
+++ b/source/blender/gpu/intern/gpu_basic_shader.c
@@ -51,8 +51,6 @@
/* State */
-static const bool USE_GLSL = false;
-
static struct {
GPUShader *cached_shaders[GPU_SHADER_OPTION_COMBINATIONS];
bool failed_shaders[GPU_SHADER_OPTION_COMBINATIONS];
@@ -269,6 +267,24 @@ const GLubyte stipple_hexagon[128] = {
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22};
/* ********************************************* */
+/* GLSL State */
+
+static bool USE_GLSL = false;
+
+/**
+ * \note this isn't part of the basic shader API,
+ * only set from the command line once on startup.
+ */
+void GPU_basic_shader_use_glsl_set(bool enabled)
+{
+ USE_GLSL = enabled;
+}
+
+bool GPU_basic_shader_use_glsl_get(void)
+{
+ return USE_GLSL;
+}
+
/* Init / exit */
void GPU_basic_shaders_init(void)
@@ -308,6 +324,9 @@ static int detect_options()
if (glIsEnabled(GL_TEXTURE_2D))
options |= GPU_SHADER_TEXTURE_2D;
+ if (glIsEnabled(GL_TEXTURE_RECTANGLE))
+ options |= GPU_SHADER_TEXTURE_RECT;
+ GPU_SHADER_TEXTURE_RECT
if (glIsEnabled(GL_COLOR_MATERIAL))
options |= GPU_SHADER_USE_COLOR;
@@ -347,14 +366,18 @@ static GPUShader *gpu_basic_shader(int options)
strcat(defines, "#define USE_COLOR\n");
if (options & GPU_SHADER_TWO_SIDED)
strcat(defines, "#define USE_TWO_SIDED\n");
- if (options & GPU_SHADER_TEXTURE_2D)
+ if (options & (GPU_SHADER_TEXTURE_2D | GPU_SHADER_TEXTURE_RECT))
strcat(defines, "#define USE_TEXTURE\n");
+ if (options & GPU_SHADER_TEXTURE_RECT)
+ strcat(defines, "#define USE_TEXTURE_RECTANGLE\n");
if (options & GPU_SHADER_STIPPLE)
strcat(defines, "#define USE_STIPPLE\n");
if (options & GPU_SHADER_LINE) {
strcat(defines, "#define DRAW_LINE\n");
geom_glsl = datatoc_gpu_shader_basic_geom_glsl;
}
+ if (options & GPU_SHADER_FLAT_NORMAL)
+ strcat(defines, "#define USE_FLAT_NORMAL\n");
if (options & GPU_SHADER_SOLID_LIGHTING)
strcat(defines, "#define USE_SOLID_LIGHTING\n");
else if (options & GPU_SHADER_LIGHTING)
@@ -369,7 +392,7 @@ static GPUShader *gpu_basic_shader(int options)
if (shader) {
/* set texture map to first texture unit */
- if (options & GPU_SHADER_TEXTURE_2D) {
+ if (options & (GPU_SHADER_TEXTURE_2D | GPU_SHADER_TEXTURE_RECT)) {
GPU_shader_bind(shader);
glUniform1i(GPU_shader_get_uniform(shader, "texture_map"), 0);
GPU_shader_unbind();
@@ -399,6 +422,23 @@ void GPU_basic_shader_bind(int options)
{
if (USE_GLSL) {
if (options) {
+ const int bound_options = GPU_MATERIAL_STATE.bound_options;
+
+ /* texture options need to be set for basic shader too */
+ if (options & GPU_SHADER_TEXTURE_2D) {
+ glEnable(GL_TEXTURE_2D);
+ }
+ else if (bound_options & GPU_SHADER_TEXTURE_2D) {
+ glDisable(GL_TEXTURE_2D);
+ }
+
+ if (options & GPU_SHADER_TEXTURE_RECT) {
+ glEnable(GL_TEXTURE_RECTANGLE);
+ }
+ else if (bound_options & GPU_SHADER_TEXTURE_RECT) {
+ glDisable(GL_TEXTURE_RECTANGLE);
+ }
+
GPUShader *shader = gpu_basic_shader(options);
if (shader) {
@@ -411,7 +451,7 @@ void GPU_basic_shader_bind(int options)
}
}
else {
- int bound_options = GPU_MATERIAL_STATE.bound_options;
+ const int bound_options = GPU_MATERIAL_STATE.bound_options;
if (options & GPU_SHADER_LIGHTING) {
glEnable(GL_LIGHTING);
@@ -438,28 +478,59 @@ void GPU_basic_shader_bind(int options)
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env_mode);
}
else if (bound_options & GPU_SHADER_TEXTURE_2D) {
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ if ((options & GPU_SHADER_TEXTURE_RECT) == 0) {
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ }
glDisable(GL_TEXTURE_2D);
}
+ if (options & GPU_SHADER_TEXTURE_RECT) {
+ GLint env_mode = (options & (GPU_SHADER_USE_COLOR | GPU_SHADER_LIGHTING)) ? GL_MODULATE : GL_REPLACE;
+ glEnable(GL_TEXTURE_RECTANGLE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env_mode);
+ }
+ else if (bound_options & GPU_SHADER_TEXTURE_RECT) {
+ if ((options & GPU_SHADER_TEXTURE_2D) == 0) {
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ }
+ glDisable(GL_TEXTURE_RECTANGLE);
+ }
+
if ((options & GPU_SHADER_LINE) && (options & GPU_SHADER_STIPPLE)) {
glEnable(GL_LINE_STIPPLE);
}
else if ((bound_options & GPU_SHADER_LINE) && (bound_options & GPU_SHADER_STIPPLE)) {
glDisable(GL_LINE_STIPPLE);
}
- else {
- if (options & GPU_SHADER_STIPPLE)
- glEnable(GL_POLYGON_STIPPLE);
- else if (bound_options & GPU_SHADER_STIPPLE)
- glDisable(GL_POLYGON_STIPPLE);
+
+ if (((options & GPU_SHADER_LINE) == 0) && (options & GPU_SHADER_STIPPLE)) {
+ glEnable(GL_POLYGON_STIPPLE);
+ }
+ else if (((bound_options & GPU_SHADER_LINE) == 0) && (bound_options & GPU_SHADER_STIPPLE)) {
+ glDisable(GL_POLYGON_STIPPLE);
}
+ if (options & GPU_SHADER_FLAT_NORMAL) {
+ glShadeModel(GL_FLAT);
+ }
+ else if (bound_options & GPU_SHADER_FLAT_NORMAL) {
+ glShadeModel(GL_SMOOTH);
+ }
}
GPU_MATERIAL_STATE.bound_options = options;
}
+void GPU_basic_shader_bind_enable(int options)
+{
+ GPU_basic_shader_bind(GPU_MATERIAL_STATE.bound_options | options);
+}
+
+void GPU_basic_shader_bind_disable(int options)
+{
+ GPU_basic_shader_bind(GPU_MATERIAL_STATE.bound_options & ~options);
+}
+
int GPU_basic_shader_bound_options(void)
{
/* ideally this should disappear, anything that uses this is making fragile
@@ -469,8 +540,9 @@ int GPU_basic_shader_bound_options(void)
/* Material Colors */
-void GPU_basic_shader_colors(const float diffuse[3], const float specular[3],
- int shininess, float alpha)
+void GPU_basic_shader_colors(
+ const float diffuse[3], const float specular[3],
+ int shininess, float alpha)
{
float gl_diffuse[4], gl_specular[4];
@@ -552,7 +624,8 @@ void GPU_basic_shader_light_set(int light_num, GPULightData *light)
GPU_MATERIAL_STATE.lights_directional |= light_bit;
}
else {
- if (USE_GLSL) {
+ /* TODO(sergey): Needs revisit. */
+ if (USE_GLSL || true) {
/* glsl shader needs these zero to skip them */
const float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f};
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index 072ff5235bf..370841327aa 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -53,8 +53,6 @@
#include "BKE_mesh.h"
#include "BKE_pbvh.h"
-#include "DNA_userdef_types.h"
-
#include "GPU_buffers.h"
#include "GPU_draw.h"
#include "GPU_basic_shader.h"
@@ -107,10 +105,12 @@ static GPUAttrib attribData[MAX_GPU_ATTRIB_DATA] = { { -1, 0, 0 } };
static ThreadMutex buffer_mutex = BLI_MUTEX_INITIALIZER;
/* multires global buffer, can be used for many grids having the same grid size */
-static GPUBuffer *mres_glob_buffer = NULL;
-static int mres_prev_gridsize = -1;
-static GLenum mres_prev_index_type = 0;
-static unsigned mres_prev_totquad = 0;
+typedef struct GridCommonGPUBuffer {
+ GPUBuffer *mres_buffer;
+ int mres_prev_gridsize;
+ GLenum mres_prev_index_type;
+ unsigned mres_prev_totquad;
+} GridCommonGPUBuffer;
void GPU_buffer_material_finalize(GPUDrawObject *gdo, GPUBufferMaterial *matinfo, int totmat)
{
@@ -407,33 +407,6 @@ void GPU_buffer_free(GPUBuffer *buffer)
BLI_mutex_unlock(&buffer_mutex);
}
-void GPU_buffer_multires_free(bool force)
-{
- if (!mres_glob_buffer) {
- /* Early output, no need to lock in this case, */
- return;
- }
-
- if (force && BLI_thread_is_main()) {
- if (mres_glob_buffer) {
- if (mres_glob_buffer->id)
- glDeleteBuffers(1, &mres_glob_buffer->id);
- MEM_freeN(mres_glob_buffer);
- }
- }
- else {
- BLI_mutex_lock(&buffer_mutex);
- gpu_buffer_free_intern(mres_glob_buffer);
- BLI_mutex_unlock(&buffer_mutex);
- }
-
- mres_glob_buffer = NULL;
- mres_prev_gridsize = -1;
- mres_prev_index_type = 0;
- mres_prev_totquad = 0;
-}
-
-
void GPU_drawobject_free(DerivedMesh *dm)
{
GPUDrawObject *gdo;
@@ -822,8 +795,14 @@ void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numda
for (i = 0; i < numdata; i++) {
glEnableVertexAttribArray(data[i].index);
+ int info = 0;
+ if (data[i].type == GL_UNSIGNED_BYTE) {
+ info |= GPU_ATTR_INFO_SRGB;
+ }
+ glUniform1i(data[i].info_index, info);
+
glVertexAttribPointer(data[i].index, data[i].size, data[i].type,
- GL_FALSE, elementsize, BUFFER_OFFSET(offset));
+ GL_TRUE, elementsize, BUFFER_OFFSET(offset));
offset += data[i].size * GPU_typesize(data[i].type);
attribData[i].index = data[i].index;
@@ -937,7 +916,7 @@ void GPU_buffer_unlock(GPUBuffer *UNUSED(buffer), GPUBindingType binding)
{
int bindtypegl = gpu_binding_type_gl[binding];
/* note: this operation can fail, could return
- * an error code from this function? */
+ * an error code from this function? */
glUnmapBuffer(bindtypegl);
glBindBuffer(bindtypegl, 0);
}
@@ -1003,6 +982,7 @@ struct GPU_PBVH_Buffers {
const int *grid_indices;
int totgrid;
bool has_hidden;
+ bool is_index_buf_global; /* Means index_buf uses global bvh's grid_common_gpu_buffer, **DO NOT** free it! */
bool use_bmesh;
@@ -1053,7 +1033,7 @@ static void gpu_color_from_mask_quad_copy(const CCGKey *key,
void GPU_update_mesh_pbvh_buffers(
GPU_PBVH_Buffers *buffers, const MVert *mvert,
const int *vert_indices, int totvert, const float *vmask,
- const int (*face_vert_indices)[4], bool show_diffuse_color)
+ const int (*face_vert_indices)[3], bool show_diffuse_color)
{
VertexBufferFormat *vert_data;
int i, j;
@@ -1181,7 +1161,7 @@ void GPU_update_mesh_pbvh_buffers(
}
GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers(
- const int (*face_vert_indices)[4],
+ const int (*face_vert_indices)[3],
const MPoly *mpoly, const MLoop *mloop, const MLoopTri *looptri,
const MVert *mvert,
const int *face_indices,
@@ -1220,8 +1200,10 @@ GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers(
/* An element index buffer is used for smooth shading, but flat
* shading requires separate vertex normals so an index buffer is
* can't be used there. */
- if (buffers->smooth)
+ if (buffers->smooth) {
buffers->index_buf = GPU_buffer_alloc(sizeof(unsigned short) * tottri * 3);
+ buffers->is_index_buf_global = false;
+ }
if (buffers->index_buf) {
/* Fill the triangle buffer */
@@ -1242,8 +1224,11 @@ GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers(
GPU_buffer_unlock(buffers->index_buf, GPU_BINDING_INDEX);
}
else {
- GPU_buffer_free(buffers->index_buf);
+ if (!buffers->is_index_buf_global) {
+ GPU_buffer_free(buffers->index_buf);
+ }
buffers->index_buf = NULL;
+ buffers->is_index_buf_global = false;
}
}
@@ -1410,22 +1395,33 @@ void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, CCGElem **grids,
} (void)0
/* end FILL_QUAD_BUFFER */
-static GPUBuffer *gpu_get_grid_buffer(int gridsize, GLenum *index_type, unsigned *totquad)
+static GPUBuffer *gpu_get_grid_buffer(
+ int gridsize, GLenum *index_type, unsigned *totquad, GridCommonGPUBuffer **grid_common_gpu_buffer)
{
/* used in the FILL_QUAD_BUFFER macro */
BLI_bitmap * const *grid_hidden = NULL;
const int *grid_indices = NULL;
int totgrid = 1;
+ GridCommonGPUBuffer *gridbuff = *grid_common_gpu_buffer;
+
+ if (gridbuff == NULL) {
+ *grid_common_gpu_buffer = gridbuff = MEM_mallocN(sizeof(GridCommonGPUBuffer), __func__);
+ gridbuff->mres_buffer = NULL;
+ gridbuff->mres_prev_gridsize = -1;
+ gridbuff->mres_prev_index_type = 0;
+ gridbuff->mres_prev_totquad = 0;
+ }
+
/* VBO is already built */
- if (mres_glob_buffer && mres_prev_gridsize == gridsize) {
- *index_type = mres_prev_index_type;
- *totquad = mres_prev_totquad;
- return mres_glob_buffer;
+ if (gridbuff->mres_buffer && gridbuff->mres_prev_gridsize == gridsize) {
+ *index_type = gridbuff->mres_prev_index_type;
+ *totquad = gridbuff->mres_prev_totquad;
+ return gridbuff->mres_buffer;
}
/* we can't reuse old, delete the existing buffer */
- else if (mres_glob_buffer) {
- GPU_buffer_free(mres_glob_buffer);
+ else if (gridbuff->mres_buffer) {
+ GPU_buffer_free(gridbuff->mres_buffer);
}
/* Build new VBO */
@@ -1433,17 +1429,17 @@ static GPUBuffer *gpu_get_grid_buffer(int gridsize, GLenum *index_type, unsigned
if (gridsize * gridsize < USHRT_MAX) {
*index_type = GL_UNSIGNED_SHORT;
- FILL_QUAD_BUFFER(unsigned short, *totquad, mres_glob_buffer);
+ FILL_QUAD_BUFFER(unsigned short, *totquad, gridbuff->mres_buffer);
}
else {
*index_type = GL_UNSIGNED_INT;
- FILL_QUAD_BUFFER(unsigned int, *totquad, mres_glob_buffer);
+ FILL_QUAD_BUFFER(unsigned int, *totquad, gridbuff->mres_buffer);
}
- mres_prev_gridsize = gridsize;
- mres_prev_index_type = *index_type;
- mres_prev_totquad = *totquad;
- return mres_glob_buffer;
+ gridbuff->mres_prev_gridsize = gridsize;
+ gridbuff->mres_prev_index_type = *index_type;
+ gridbuff->mres_prev_totquad = *totquad;
+ return gridbuff->mres_buffer;
}
#define FILL_FAST_BUFFER(type_) \
@@ -1470,8 +1466,9 @@ static GPUBuffer *gpu_get_grid_buffer(int gridsize, GLenum *index_type, unsigned
} \
} (void)0
-GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(int *grid_indices, int totgrid,
- BLI_bitmap **grid_hidden, int gridsize, const CCGKey *key)
+GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(
+ int *grid_indices, int totgrid, BLI_bitmap **grid_hidden, int gridsize, const CCGKey *key,
+ GridCommonGPUBuffer **grid_common_gpu_buffer)
{
GPU_PBVH_Buffers *buffers;
int totquad;
@@ -1500,8 +1497,10 @@ GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(int *grid_indices, int totgrid,
}
if (totquad == fully_visible_totquad) {
- buffers->index_buf = gpu_get_grid_buffer(gridsize, &buffers->index_type, &buffers->tot_quad);
+ buffers->index_buf = gpu_get_grid_buffer(
+ gridsize, &buffers->index_type, &buffers->tot_quad, grid_common_gpu_buffer);
buffers->has_hidden = false;
+ buffers->is_index_buf_global = true;
}
else {
buffers->tot_quad = totquad;
@@ -1516,6 +1515,7 @@ GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(int *grid_indices, int totgrid,
}
buffers->has_hidden = true;
+ buffers->is_index_buf_global = false;
}
/* Build coord/normal VBO */
@@ -1740,8 +1740,9 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers,
const int use_short = (maxvert < USHRT_MAX);
/* Initialize triangle index buffer */
- if (buffers->index_buf)
+ if (buffers->index_buf && !buffers->is_index_buf_global)
GPU_buffer_free(buffers->index_buf);
+ buffers->is_index_buf_global = false;
buffers->index_buf = GPU_buffer_alloc((use_short ?
sizeof(unsigned short) :
sizeof(unsigned int)) * 3 * tottri);
@@ -1786,12 +1787,19 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers,
}
else {
/* Memory map failed */
- GPU_buffer_free(buffers->index_buf);
+ if (!buffers->is_index_buf_global) {
+ GPU_buffer_free(buffers->index_buf);
+ }
buffers->index_buf = NULL;
+ buffers->is_index_buf_global = false;
}
}
else if (buffers->index_buf) {
- GPU_buffer_free(buffers->index_buf);
+ if (!buffers->is_index_buf_global) {
+ GPU_buffer_free(buffers->index_buf);
+ }
+ buffers->index_buf = NULL;
+ buffers->is_index_buf_global = false;
}
}
@@ -1835,15 +1843,15 @@ void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial,
if (buffers->vert_buf) {
char *base = NULL;
char *index_base = NULL;
- int bound_options = 0;
+ /* weak inspection of bound options, should not be necessary ideally */
+ const int bound_options_old = GPU_basic_shader_bound_options();
+ int bound_options_new = 0;
glEnableClientState(GL_VERTEX_ARRAY);
if (!wireframe) {
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
- /* weak inspection of bound options, should not be necessary ideally */
- bound_options = GPU_basic_shader_bound_options();
- GPU_basic_shader_bind(bound_options | GPU_SHADER_USE_COLOR);
+ bound_options_new |= GPU_SHADER_USE_COLOR;
}
GPU_buffer_bind(buffers->vert_buf, GPU_BINDING_ARRAY);
@@ -1855,10 +1863,18 @@ void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial,
GPU_buffer_bind(buffers->index_buf, GPU_BINDING_INDEX);
}
- if (wireframe)
+ if (wireframe) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- else
- glShadeModel((buffers->smooth || buffers->face_indices_len) ? GL_SMOOTH : GL_FLAT);
+ }
+ else {
+ if ((buffers->smooth == false) && (buffers->face_indices_len == 0)) {
+ bound_options_new |= GPU_SHADER_FLAT_NORMAL;
+ }
+ }
+
+ if (bound_options_new & ~bound_options_old) {
+ GPU_basic_shader_bind(bound_options_old | bound_options_new);
+ }
if (buffers->tot_quad) {
const char *offset = base;
@@ -1932,7 +1948,10 @@ void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial,
if (!wireframe) {
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
- GPU_basic_shader_bind(bound_options);
+ }
+
+ if (bound_options_new & ~bound_options_old) {
+ GPU_basic_shader_bind(bound_options_old);
}
}
}
@@ -1985,7 +2004,7 @@ void GPU_free_pbvh_buffers(GPU_PBVH_Buffers *buffers)
if (buffers) {
if (buffers->vert_buf)
GPU_buffer_free(buffers->vert_buf);
- if (buffers->index_buf && (buffers->tot_tri || buffers->has_hidden))
+ if (buffers->index_buf && !buffers->is_index_buf_global)
GPU_buffer_free(buffers->index_buf);
if (buffers->index_buf_fast)
GPU_buffer_free(buffers->index_buf_fast);
@@ -1998,6 +2017,20 @@ void GPU_free_pbvh_buffers(GPU_PBVH_Buffers *buffers)
}
}
+void GPU_free_pbvh_buffer_multires(GridCommonGPUBuffer **grid_common_gpu_buffer)
+{
+ GridCommonGPUBuffer *gridbuff = *grid_common_gpu_buffer;
+
+ if (gridbuff) {
+ if (gridbuff->mres_buffer) {
+ BLI_mutex_lock(&buffer_mutex);
+ gpu_buffer_free_intern(gridbuff->mres_buffer);
+ BLI_mutex_unlock(&buffer_mutex);
+ }
+ MEM_freeN(gridbuff);
+ *grid_common_gpu_buffer = NULL;
+ }
+}
/* debug function, draws the pbvh BB */
void GPU_draw_pbvh_BB(float min[3], float max[3], bool leaf)
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index 94d52c3617c..211394e7932 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -86,8 +86,10 @@ typedef struct GPUFunction {
} GPUFunction;
/* Indices match the GPUType enum */
-static const char *GPU_DATATYPE_STR[17] = {"", "float", "vec2", "vec3", "vec4",
- NULL, NULL, NULL, NULL, "mat3", NULL, NULL, NULL, NULL, NULL, NULL, "mat4"};
+static const char *GPU_DATATYPE_STR[17] = {
+ "", "float", "vec2", "vec3", "vec4",
+ NULL, NULL, NULL, NULL, "mat3", NULL, NULL, NULL, NULL, NULL, NULL, "mat4",
+};
/* GLSL code parsing for finding function definitions.
* These are stored in a hash for lookup when creating a material. */
@@ -749,6 +751,7 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type)
BLI_dynstr_appendf(ds, "%s %s att%d;\n",
GLEW_VERSION_3_0 ? "in" : "attribute",
GPU_DATATYPE_STR[input->type], input->attribid);
+ BLI_dynstr_appendf(ds, "uniform int att%d_info;\n", input->attribid);
BLI_dynstr_appendf(ds, "%s %s var%d;\n",
GLEW_VERSION_3_0 ? "out" : "varying",
GPU_DATATYPE_STR[input->type], input->attribid);
@@ -801,7 +804,8 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type)
BLI_dynstr_appendf(ds, "#ifndef USE_OPENSUBDIV\n");
}
#endif
- BLI_dynstr_appendf(ds, "\tvar%d = att%d;\n", input->attribid, input->attribid);
+ BLI_dynstr_appendf(ds, "\tset_var_from_attr(att%d, att%d_info, var%d);\n",
+ input->attribid, input->attribid, input->attribid);
#ifdef WITH_OPENSUBDIV
if (is_mtface) {
BLI_dynstr_appendf(ds, "#endif\n");
@@ -849,11 +853,14 @@ static char *code_generate_geometry(ListBase *nodes, bool use_opensubdiv)
for (input = node->inputs.first; input; input = input->next) {
if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
if (input->attribtype == CD_MTFACE) {
+ /* NOTE: For now we are using varying on purpose,
+ * otherwise we are not able to write to the varying.
+ */
BLI_dynstr_appendf(ds, "%s %s var%d%s;\n",
- GLEW_VERSION_3_0 ? "in" : "varying",
+ "varying",
GPU_DATATYPE_STR[input->type],
input->attribid,
- GLEW_VERSION_3_0 ? "[]" : "");
+ "");
BLI_dynstr_appendf(ds, "uniform int fvar%d_offset;\n",
input->attribid);
}
@@ -864,22 +871,20 @@ static char *code_generate_geometry(ListBase *nodes, bool use_opensubdiv)
BLI_dynstr_append(ds, datatoc_gpu_shader_geometry_glsl);
/* Generate varying assignments. */
- /* TODO(sergey): Disabled for now, needs revisit. */
-#if 0
for (node = nodes->first; node; node = node->next) {
for (input = node->inputs.first; input; input = input->next) {
if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
if (input->attribtype == CD_MTFACE) {
- BLI_dynstr_appendf(ds,
- "\tINTERP_FACE_VARYING_2(var%d, "
- "fvar%d_offset, st);\n",
- input->attribid,
- input->attribid);
+ BLI_dynstr_appendf(
+ ds,
+ "\tINTERP_FACE_VARYING_ATT_2(var%d, "
+ "int(texelFetch(FVarDataOffsetBuffer, fvar%d_offset).r), st);\n",
+ input->attribid,
+ input->attribid);
}
}
}
}
-#endif
BLI_dynstr_append(ds, "}\n");
code = BLI_dynstr_get_cstring(ds);
@@ -1727,3 +1732,9 @@ void GPU_pass_free(GPUPass *pass)
MEM_freeN(pass->vertexcode);
MEM_freeN(pass);
}
+
+void GPU_pass_free_nodes(ListBase *nodes)
+{
+ gpu_nodes_free(nodes);
+}
+
diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h
index 417e46a83ee..7af17f9122d 100644
--- a/source/blender/gpu/intern/gpu_codegen.h
+++ b/source/blender/gpu/intern/gpu_codegen.h
@@ -183,6 +183,7 @@ void GPU_pass_update_uniforms(GPUPass *pass);
void GPU_pass_unbind(GPUPass *pass);
void GPU_pass_free(GPUPass *pass);
+void GPU_pass_free_nodes(ListBase *nodes);
void gpu_codegen_init(void);
void gpu_codegen_exit(void);
diff --git a/source/blender/gpu/intern/gpu_compositing.c b/source/blender/gpu/intern/gpu_compositing.c
index c2a2b1804ca..964c2b5051e 100644
--- a/source/blender/gpu/intern/gpu_compositing.c
+++ b/source/blender/gpu/intern/gpu_compositing.c
@@ -34,16 +34,11 @@
#include "BLI_sys_types.h"
#include "BLI_rect.h"
#include "BLI_math.h"
-#include "BLI_listbase.h"
-#include "BLI_linklist.h"
#include "BLI_rand.h"
#include "DNA_vec_types.h"
-#include "DNA_view3d_types.h"
#include "DNA_scene_types.h"
-#include "DNA_object_types.h"
-#include "DNA_camera_types.h"
#include "DNA_gpu_types.h"
#include "GPU_compositing.h"
diff --git a/source/blender/gpu/intern/gpu_debug.c b/source/blender/gpu/intern/gpu_debug.c
index be9285727fe..d632e767ca9 100644
--- a/source/blender/gpu/intern/gpu_debug.c
+++ b/source/blender/gpu/intern/gpu_debug.c
@@ -29,7 +29,9 @@
* \ingroup gpu
*/
+#include "BLI_utildefines.h"
#include "BLI_sys_types.h"
+#include "BLI_system.h"
#include "BKE_global.h"
@@ -159,17 +161,73 @@ const char *gpuErrorString(GLenum err)
#endif
+static const char* source_name(GLenum source)
+{
+ switch (source) {
+ case GL_DEBUG_SOURCE_API: return "API";
+ case GL_DEBUG_SOURCE_WINDOW_SYSTEM: return "window system";
+ case GL_DEBUG_SOURCE_SHADER_COMPILER: return "shader compiler";
+ case GL_DEBUG_SOURCE_THIRD_PARTY: return "3rd party";
+ case GL_DEBUG_SOURCE_APPLICATION: return "application";
+ case GL_DEBUG_SOURCE_OTHER: return "other";
+ default: return "???";
+ }
+}
+
+static const char* message_type_name(GLenum message)
+{
+ switch (message) {
+ case GL_DEBUG_TYPE_ERROR: return "error";
+ case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: return "deprecated behavior";
+ case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: return "undefined behavior";
+ case GL_DEBUG_TYPE_PORTABILITY: return "portability";
+ case GL_DEBUG_TYPE_PERFORMANCE: return "performance";
+ case GL_DEBUG_TYPE_OTHER: return "other";
+ case GL_DEBUG_TYPE_MARKER: return "marker"; /* KHR has this, ARB does not */
+ default: return "???";
+ }
+}
+
+static const char* category_name_amd(GLenum category)
+{
+ switch (category) {
+ case GL_DEBUG_CATEGORY_API_ERROR_AMD: return "API error";
+ case GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD: return "window system";
+ case GL_DEBUG_CATEGORY_DEPRECATION_AMD: return "deprecated behavior";
+ case GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD: return "undefined behavior";
+ case GL_DEBUG_CATEGORY_PERFORMANCE_AMD: return "performance";
+ case GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD: return "shader compiler";
+ case GL_DEBUG_CATEGORY_APPLICATION_AMD: return "application";
+ case GL_DEBUG_CATEGORY_OTHER_AMD: return "other";
+ default: return "???";
+ }
+}
+
+
static void APIENTRY gpu_debug_proc(
GLenum source, GLenum type, GLuint UNUSED(id),
- GLenum UNUSED(severity), GLsizei UNUSED(length),
+ GLenum severity, GLsizei UNUSED(length),
const GLchar *message, const GLvoid *UNUSED(userParm))
{
- if (source == GL_DEBUG_SOURCE_API && type == GL_DEBUG_TYPE_ERROR) {
- fprintf(stderr, "GL: %s\n", message);
- fflush(stderr);
+ if (type == GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR) {
+ /* Blender 2.7x uses OpenGL 2.1, we don't care if features are deprecated */
+ return;
}
- else if (G.debug_value == 20) {
- fprintf(stderr, "GL: %s\n", message);
+
+ bool backtrace = false;
+
+ switch (severity) {
+ case GL_DEBUG_SEVERITY_HIGH:
+ backtrace = true;
+ /* fall through */
+ case GL_DEBUG_SEVERITY_MEDIUM:
+ case GL_DEBUG_SEVERITY_LOW:
+ case GL_DEBUG_SEVERITY_NOTIFICATION: /* KHR has this, ARB does not */
+ fprintf(stderr, "GL %s %s: %s\n", source_name(source), message_type_name(type), message);
+ }
+
+ if (backtrace) {
+ BLI_system_backtrace(stderr);
fflush(stderr);
}
}
@@ -177,11 +235,30 @@ static void APIENTRY gpu_debug_proc(
#ifndef GLEW_ES_ONLY
static void APIENTRY gpu_debug_proc_amd(
- GLuint UNUSED(id), GLenum UNUSED(category),
- GLenum UNUSED(severity), GLsizei UNUSED(length),
+ GLuint UNUSED(id), GLenum category,
+ GLenum severity, GLsizei UNUSED(length),
const GLchar *message, GLvoid *UNUSED(userParm))
{
- fprintf(stderr, "GL: %s\n", message);
+ if (category == GL_DEBUG_CATEGORY_DEPRECATION_AMD) {
+ /* Blender 2.7x uses OpenGL 2.1, we don't care if features are deprecated */
+ return;
+ }
+
+ bool backtrace = false;
+
+ switch (severity) {
+ case GL_DEBUG_SEVERITY_HIGH:
+ backtrace = true;
+ /* fall through */
+ case GL_DEBUG_SEVERITY_MEDIUM:
+ case GL_DEBUG_SEVERITY_LOW:
+ fprintf(stderr, "GL %s: %s\n", category_name_amd(category), message);
+ }
+
+ if (backtrace) {
+ BLI_system_backtrace(stderr);
+ fflush(stderr);
+ }
}
#endif
@@ -194,36 +271,44 @@ void gpu_debug_init(void)
#if !defined(WITH_GLEW_ES) && !defined(GLEW_ES_ONLY)
if (GLEW_VERSION_4_3) {
+ fprintf(stderr, "Using OpenGL 4.3 debug facilities\n");
glEnable(GL_DEBUG_OUTPUT);
+ glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
glDebugMessageCallback((GLDEBUGPROC)gpu_debug_proc, mxGetCurrentContext());
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
- GPU_string_marker(sizeof(success), success);
+ GPU_string_marker(success);
return;
}
#endif
if (GLEW_KHR_debug) {
#ifndef GLEW_ES_ONLY
+ fprintf(stderr, "Using KHR_debug extension\n");
+ glEnable(GL_DEBUG_OUTPUT);
+ glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
glDebugMessageCallback((GLDEBUGPROC)gpu_debug_proc, mxGetCurrentContext());
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
- GPU_string_marker(sizeof(success), success);
+ GPU_string_marker(success);
#endif
return;
}
#ifndef GLEW_ES_ONLY
if (GLEW_ARB_debug_output) {
+ fprintf(stderr, "Using ARB_debug_output extension\n");
+ glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
glDebugMessageCallbackARB((GLDEBUGPROCARB)gpu_debug_proc, mxGetCurrentContext());
glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
- GPU_string_marker(sizeof(success), success);
+ GPU_string_marker(success);
return;
}
if (GLEW_AMD_debug_output) {
+ fprintf(stderr, "Using AMD_debug_output extension\n");
glDebugMessageCallbackAMD(gpu_debug_proc_amd, mxGetCurrentContext());
glDebugMessageEnableAMD(GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
- GPU_string_marker(sizeof(success), success);
+ GPU_string_marker(success);
return;
}
@@ -271,14 +356,14 @@ void gpu_debug_exit(void)
return;
}
-void GPU_string_marker(size_t length, const char *buf)
+void GPU_string_marker(const char *buf)
{
#ifndef WITH_GLEW_ES
#ifndef GLEW_ES_ONLY
if (GLEW_VERSION_4_3) {
glDebugMessageInsert(
GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 0,
- GL_DEBUG_SEVERITY_NOTIFICATION, length, buf);
+ GL_DEBUG_SEVERITY_NOTIFICATION, -1, buf);
return;
}
@@ -289,7 +374,7 @@ void GPU_string_marker(size_t length, const char *buf)
#ifndef GLEW_ES_ONLY
glDebugMessageInsert(
GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 0,
- GL_DEBUG_SEVERITY_NOTIFICATION, length, buf);
+ GL_DEBUG_SEVERITY_NOTIFICATION, -1, buf);
#endif
return;
}
@@ -298,7 +383,7 @@ void GPU_string_marker(size_t length, const char *buf)
if (GLEW_ARB_debug_output) {
glDebugMessageInsertARB(
GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_OTHER_ARB, 0,
- GL_DEBUG_SEVERITY_LOW_ARB, length, buf);
+ GL_DEBUG_SEVERITY_LOW_ARB, -1, buf);
return;
}
@@ -306,19 +391,17 @@ void GPU_string_marker(size_t length, const char *buf)
if (GLEW_AMD_debug_output) {
glDebugMessageInsertAMD(
GL_DEBUG_CATEGORY_APPLICATION_AMD, GL_DEBUG_SEVERITY_LOW_AMD, 0,
- length, buf);
+ 0, buf);
return;
}
if (GLEW_GREMEDY_string_marker) {
- glStringMarkerGREMEDY(length, buf);
+ glStringMarkerGREMEDY(0, buf);
return;
}
#endif
-
- return;
}
void GPU_print_error_debug(const char *str)
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index e5d51772bb2..7936811ab4d 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -39,7 +39,6 @@
#include <string.h>
#include "GPU_glew.h"
-#include "GPU_debug.h"
#include "BLI_blenlib.h"
#include "BLI_linklist.h"
@@ -70,10 +69,11 @@
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_node.h"
-#include "BKE_object.h"
#include "BKE_scene.h"
-#include "BKE_subsurf.h"
#include "BKE_DerivedMesh.h"
+#ifdef WITH_GAMEENGINE
+# include "BKE_object.h"
+#endif
#include "GPU_basic_shader.h"
#include "GPU_buffers.h"
@@ -85,9 +85,12 @@
#include "PIL_time.h"
-#include "smoke_API.h"
+#ifdef WITH_SMOKE
+# include "smoke_API.h"
+#endif
#ifdef WITH_OPENSUBDIV
+# include "BKE_subsurf.h"
# include "BKE_editmesh.h"
# include "gpu_codegen.h"
@@ -561,7 +564,9 @@ static void gpu_verify_high_bit_srgb_buffer(float *srgb_frect,
}
}
-int GPU_verify_image(Image *ima, ImageUser *iuser, int textarget, int tftile, bool compare, bool mipmap, bool is_data)
+int GPU_verify_image(
+ Image *ima, ImageUser *iuser,
+ int textarget, int tftile, bool compare, bool mipmap, bool is_data)
{
unsigned int *bind = NULL;
int tpx = 0, tpy = 0;
@@ -798,7 +803,7 @@ static void **gpu_gen_cube_map(unsigned int *rect, float *frect, int rectw, int
* | | | |
* | NegZ | PosZ | PosY |
* |______|______|______|
- */
+ */
if (use_high_bit_depth) {
float (*frectb)[4] = (float(*)[4])frect;
float (**fsides)[4] = (float(**)[4])sides;
@@ -843,8 +848,9 @@ static void gpu_del_cube_map(void **cube_map)
}
/* Image *ima can be NULL */
-void GPU_create_gl_tex(unsigned int *bind, unsigned int *rect, float *frect, int rectw, int recth,
- int textarget, bool mipmap, bool use_high_bit_depth, Image *ima)
+void GPU_create_gl_tex(
+ unsigned int *bind, unsigned int *rect, float *frect, int rectw, int recth,
+ int textarget, bool mipmap, bool use_high_bit_depth, Image *ima)
{
ImBuf *ibuf = NULL;
@@ -1988,8 +1994,9 @@ int GPU_object_material_bind(int nr, void *attribs)
}
else {
/* or do fixed function opengl material */
- GPU_basic_shader_colors(GMS.matbuf[nr].diff,
- GMS.matbuf[nr].spec, GMS.matbuf[nr].hard, GMS.matbuf[nr].alpha);
+ GPU_basic_shader_colors(
+ GMS.matbuf[nr].diff,
+ GMS.matbuf[nr].spec, GMS.matbuf[nr].hard, GMS.matbuf[nr].alpha);
if (GMS.two_sided_lighting)
GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_TWO_SIDED);
@@ -2283,8 +2290,6 @@ void GPU_state_init(void)
/* scaling matrices */
glEnable(GL_NORMALIZE);
- glShadeModel(GL_FLAT);
-
glDisable(GL_ALPHA_TEST);
glDisable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
@@ -2356,3 +2361,152 @@ void GPU_draw_update_fvar_offset(DerivedMesh *dm)
}
}
#endif
+
+
+/** \name Framebuffer color depth, for selection codes
+ * \{ */
+
+#ifdef __APPLE__
+
+/* apple seems to round colors to below and up on some configs */
+
+static unsigned int index_to_framebuffer(int index)
+{
+ unsigned int i = index;
+
+ switch (GPU_color_depth()) {
+ case 12:
+ i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4);
+ /* sometimes dithering subtracts! */
+ i |= 0x070707;
+ break;
+ case 15:
+ case 16:
+ i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3);
+ i |= 0x030303;
+ break;
+ case 24:
+ break;
+ default: /* 18 bits... */
+ i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2);
+ i |= 0x010101;
+ break;
+ }
+
+ return i;
+}
+
+#else
+
+/* this is the old method as being in use for ages.... seems to work? colors are rounded to lower values */
+
+static unsigned int index_to_framebuffer(int index)
+{
+ unsigned int i = index;
+
+ switch (GPU_color_depth()) {
+ case 8:
+ i = ((i & 48) << 18) + ((i & 12) << 12) + ((i & 3) << 6);
+ i |= 0x3F3F3F;
+ break;
+ case 12:
+ i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4);
+ /* sometimes dithering subtracts! */
+ i |= 0x0F0F0F;
+ break;
+ case 15:
+ case 16:
+ i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3);
+ i |= 0x070707;
+ break;
+ case 24:
+ break;
+ default: /* 18 bits... */
+ i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2);
+ i |= 0x030303;
+ break;
+ }
+
+ return i;
+}
+
+#endif
+
+
+void GPU_select_index_set(int index)
+{
+ const int col = index_to_framebuffer(index);
+ glColor3ub(( (col) & 0xFF),
+ (((col) >> 8) & 0xFF),
+ (((col) >> 16) & 0xFF));
+}
+
+void GPU_select_index_get(int index, int *r_col)
+{
+ const int col = index_to_framebuffer(index);
+ char *c_col = (char *)r_col;
+ c_col[0] = (col & 0xFF); /* red */
+ c_col[1] = ((col >> 8) & 0xFF); /* green */
+ c_col[2] = ((col >> 16) & 0xFF); /* blue */
+ c_col[3] = 0xFF; /* alpha */
+}
+
+
+#define INDEX_FROM_BUF_8(col) ((((col) & 0xC00000) >> 18) + (((col) & 0xC000) >> 12) + (((col) & 0xC0) >> 6))
+#define INDEX_FROM_BUF_12(col) ((((col) & 0xF00000) >> 12) + (((col) & 0xF000) >> 8) + (((col) & 0xF0) >> 4))
+#define INDEX_FROM_BUF_15_16(col) ((((col) & 0xF80000) >> 9) + (((col) & 0xF800) >> 6) + (((col) & 0xF8) >> 3))
+#define INDEX_FROM_BUF_18(col) ((((col) & 0xFC0000) >> 6) + (((col) & 0xFC00) >> 4) + (((col) & 0xFC) >> 2))
+#define INDEX_FROM_BUF_24(col) ((col) & 0xFFFFFF)
+
+int GPU_select_to_index(unsigned int col)
+{
+ if (col == 0) {
+ return 0;
+ }
+
+ switch (GPU_color_depth()) {
+ case 8: return INDEX_FROM_BUF_8(col);
+ case 12: return INDEX_FROM_BUF_12(col);
+ case 15:
+ case 16: return INDEX_FROM_BUF_15_16(col);
+ case 24: return INDEX_FROM_BUF_24(col);
+ default: return INDEX_FROM_BUF_18(col);
+ }
+}
+
+void GPU_select_to_index_array(unsigned int *col, const unsigned int size)
+{
+#define INDEX_BUF_ARRAY(INDEX_FROM_BUF_BITS) \
+ for (i = size; i--; col++) { \
+ if ((c = *col)) { \
+ *col = INDEX_FROM_BUF_BITS(c); \
+ } \
+ } ((void)0)
+
+ if (size > 0) {
+ unsigned int i, c;
+
+ switch (GPU_color_depth()) {
+ case 8:
+ INDEX_BUF_ARRAY(INDEX_FROM_BUF_8);
+ break;
+ case 12:
+ INDEX_BUF_ARRAY(INDEX_FROM_BUF_12);
+ break;
+ case 15:
+ case 16:
+ INDEX_BUF_ARRAY(INDEX_FROM_BUF_15_16);
+ break;
+ case 24:
+ INDEX_BUF_ARRAY(INDEX_FROM_BUF_24);
+ break;
+ default:
+ INDEX_BUF_ARRAY(INDEX_FROM_BUF_18);
+ break;
+ }
+ }
+
+#undef INDEX_BUF_ARRAY
+}
+
+/** \} */
diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c
index 3c96b628cd6..26e86fe61b8 100644
--- a/source/blender/gpu/intern/gpu_extensions.c
+++ b/source/blender/gpu/intern/gpu_extensions.c
@@ -32,9 +32,6 @@
* with checks for drivers and GPU support.
*/
-#include "MEM_guardedalloc.h"
-
-#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_math_base.h"
#include "BLI_math_vector.h"
@@ -42,7 +39,6 @@
#include "BKE_global.h"
#include "GPU_basic_shader.h"
-#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "GPU_glew.h"
#include "GPU_texture.h"
@@ -81,9 +77,10 @@ static struct GPUGlobal {
GPUDeviceType device;
GPUOSType os;
GPUDriverType driver;
- float dfdyfactors[2]; /* workaround for different calculation of dfdy factors on GPUs. Some GPUs/drivers
- calculate dfdy in shader differently when drawing to an offscreen buffer. First
- number is factor on screen and second is off-screen */
+ /* workaround for different calculation of dfdy factors on GPUs. Some GPUs/drivers
+ * calculate dfdy in shader differently when drawing to an offscreen buffer. First
+ * number is factor on screen and second is off-screen */
+ float dfdyfactors[2];
float max_anisotropy;
} GG = {1, 0};
@@ -283,12 +280,6 @@ bool GPU_legacy_support(void)
return support;
}
-bool GPU_glsl_support(void)
-{
- /* always supported, still queried by game engine */
- return true;
-}
-
bool GPU_full_non_power_of_two_support(void)
{
/* always supported on full GL but still relevant for OpenGL ES 2.0 where
diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c
index c15e49a8ed1..f62ef677434 100644
--- a/source/blender/gpu/intern/gpu_framebuffer.c
+++ b/source/blender/gpu/intern/gpu_framebuffer.c
@@ -29,8 +29,6 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-#include "BLI_math_base.h"
-#include "BLI_math_vector.h"
#include "BKE_global.h"
@@ -403,13 +401,13 @@ void GPU_framebuffer_blur(
GPU_shader_uniform_texture(blur_shader, texture_source_uniform, tex);
glViewport(0, 0, GPU_texture_width(blurtex), GPU_texture_height(blurtex));
- /* Peparing to draw quad */
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
+ /* Preparing to draw quad */
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
glDisable(GL_DEPTH_TEST);
@@ -575,7 +573,7 @@ void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels)
glFramebufferTexture2DEXT(
GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + ofs->color->fb_attachment,
GL_TEXTURE_2D_MULTISAMPLE, ofs->color->bindcode, 0);
- status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER_EXT);
+ status = glCheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER_EXT);
if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
goto finally;
}
@@ -583,11 +581,11 @@ void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels)
/* write into new single-sample buffer */
glGenFramebuffersEXT(1, &fbo_blit);
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, fbo_blit);
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, fbo_blit);
glFramebufferTexture2DEXT(
- GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
+ GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
GL_TEXTURE_2D, tex_blit, 0);
- status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER_EXT);
+ status = glCheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER_EXT);
if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
goto finally;
}
diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c
index da4dd65d2e1..c72c83b6b07 100644
--- a/source/blender/gpu/intern/gpu_init_exit.c
+++ b/source/blender/gpu/intern/gpu_init_exit.c
@@ -29,11 +29,8 @@
* \ingroup gpu
*/
-#include "BKE_DerivedMesh.h"
-
#include "BLI_sys_types.h"
#include "GPU_init_exit.h" /* interface */
-#include "GPU_buffers.h"
#include "BKE_global.h"
@@ -73,7 +70,6 @@ void GPU_exit(void)
gpu_codegen_exit();
gpu_extensions_exit(); /* must come last */
- GPU_buffer_multires_free(true);
initialized = false;
}
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 587e6340450..b857aea29ad 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -31,7 +31,6 @@
* Manages materials, lights and textures.
*/
-
#include <math.h>
#include <string.h>
@@ -49,7 +48,6 @@
#include "BKE_anim.h"
#include "BKE_colortools.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_main.h"
@@ -68,7 +66,9 @@
#include "gpu_codegen.h"
-#include <string.h>
+#ifdef WITH_OPENSUBDIV
+# include "BKE_DerivedMesh.h"
+#endif
/* Structs */
@@ -88,6 +88,7 @@ static struct GPUWorld {
float mistcol[4];
float horicol[3];
float ambcol[4];
+ float zencol[3];
} GPUWorld;
struct GPUMaterial {
@@ -212,6 +213,9 @@ static void gpu_material_set_attrib_id(GPUMaterial *material)
BLI_snprintf(name, sizeof(name), "att%d", attribs->layer[a].attribid);
attribs->layer[a].glindex = GPU_shader_get_attribute(shader, name);
+ BLI_snprintf(name, sizeof(name), "att%d_info", attribs->layer[a].attribid);
+ attribs->layer[a].glinfoindoex = GPU_shader_get_uniform(shader, name);
+
if (attribs->layer[a].glindex >= 0) {
attribs->layer[b] = attribs->layer[a];
b++;
@@ -266,6 +270,9 @@ static int GPU_material_construct_end(GPUMaterial *material, const char *passnam
material->partangvel = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_ANG_VELOCITY));
return 1;
}
+ else {
+ GPU_pass_free_nodes(&material->nodes);
+ }
return 0;
}
@@ -514,6 +521,11 @@ bool GPU_material_use_new_shading_nodes(GPUMaterial *mat)
return BKE_scene_use_new_shading_nodes(mat->scene);
}
+bool GPU_material_use_world_space_shading(GPUMaterial *mat)
+{
+ return BKE_scene_use_world_space_shading(mat->scene);
+}
+
static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **lv, GPUNodeLink **dist)
{
GPUNodeLink *visifac;
@@ -792,7 +804,7 @@ static void shade_light_textures(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **
for (int i = 0; i < MAX_MTEX; ++i) {
MTex *mtex = lamp->la->mtex[i];
- if (mtex && mtex->tex->type & TEX_IMAGE && mtex->tex->ima) {
+ if (mtex && mtex->tex && (mtex->tex->type & TEX_IMAGE) && mtex->tex->ima) {
mat->dynproperty |= DYN_LAMP_PERSMAT;
float one = 1.0f;
@@ -1615,22 +1627,22 @@ void GPU_shadeinput_set(GPUMaterial *mat, Material *ma, GPUShadeInput *shi)
shi->gpumat = mat;
shi->mat = ma;
- GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->r, GPU_DYNAMIC_MAT_DIFFRGB, NULL), &shi->rgb);
- GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->specr, GPU_DYNAMIC_MAT_SPECRGB, NULL), &shi->specrgb);
- GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->mirr, GPU_DYNAMIC_MAT_MIR, NULL), &shi->mir);
+ GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->r, GPU_DYNAMIC_MAT_DIFFRGB, ma), &shi->rgb);
+ GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->specr, GPU_DYNAMIC_MAT_SPECRGB, ma), &shi->specrgb);
+ GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->mirr, GPU_DYNAMIC_MAT_MIR, ma), &shi->mir);
GPU_link(mat, "set_rgba_zero", &shi->refcol);
GPU_link(mat, "shade_norm", GPU_builtin(GPU_VIEW_NORMAL), &shi->vn);
if (mat->alpha)
- GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->alpha, GPU_DYNAMIC_MAT_ALPHA, NULL), &shi->alpha);
+ GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->alpha, GPU_DYNAMIC_MAT_ALPHA, ma), &shi->alpha);
else
GPU_link(mat, "set_value", GPU_uniform(&one), &shi->alpha);
- GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->ref, GPU_DYNAMIC_MAT_REF, NULL), &shi->refl);
- GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->spec, GPU_DYNAMIC_MAT_SPEC, NULL), &shi->spec);
- GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->emit, GPU_DYNAMIC_MAT_EMIT, NULL), &shi->emit);
- GPU_link(mat, "set_value", GPU_dynamic_uniform((float *)&ma->har, GPU_DYNAMIC_MAT_HARD, NULL), &shi->har);
- GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->amb, GPU_DYNAMIC_MAT_AMB, NULL), &shi->amb);
+ GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->ref, GPU_DYNAMIC_MAT_REF, ma), &shi->refl);
+ GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->spec, GPU_DYNAMIC_MAT_SPEC, ma), &shi->spec);
+ GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->emit, GPU_DYNAMIC_MAT_EMIT, ma), &shi->emit);
+ GPU_link(mat, "set_value", GPU_dynamic_uniform((float *)&ma->har, GPU_DYNAMIC_MAT_HARD, ma), &shi->har);
+ GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->amb, GPU_DYNAMIC_MAT_AMB, ma), &shi->amb);
GPU_link(mat, "set_value", GPU_uniform(&ma->spectra), &shi->spectra);
GPU_link(mat, "shade_view", GPU_builtin(GPU_VIEW_POSITION), &shi->view);
GPU_link(mat, "vcol_attribute", GPU_attribute(CD_MCOL, ""), &shi->vcol);
@@ -1665,6 +1677,11 @@ void GPU_ambient_update_color(float color[3])
GPUWorld.ambcol[3] = 1.0f;
}
+void GPU_zenith_update_color(float color[3])
+{
+ copy_v3_v3(GPUWorld.zencol, color);
+}
+
void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr)
{
GPUMaterial *mat = shi->gpumat;
@@ -1721,6 +1738,36 @@ void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr)
ulinfac, ulogfac, &shr->spec);
}
+ /* environment lighting */
+ if (!(mat->scene->gm.flag & GAME_GLSL_NO_ENV_LIGHTING) &&
+ (world->mode & WO_ENV_LIGHT) &&
+ (mat->scene->r.mode & R_SHADOW) &&
+ !BKE_scene_use_new_shading_nodes(mat->scene))
+ {
+ if ((world->ao_env_energy != 0.0f) && (GPU_link_changed(shi->amb) || ma->amb != 0.0f) &&
+ (GPU_link_changed(shi->refl) || ma->ref != 0.0f))
+ {
+ if (world->aocolor != WO_AOPLAIN) {
+ if (!(is_zero_v3(&world->horr) & is_zero_v3(&world->zenr))) {
+ GPUNodeLink *fcol, *f;
+ GPU_link(mat, "math_multiply", shi->amb, shi->refl, &f);
+ GPU_link(mat, "math_multiply", f, GPU_uniform(&world->ao_env_energy), &f);
+ GPU_link(mat, "shade_mul_value", f, shi->rgb, &fcol);
+ GPU_link(mat, "env_apply", shr->combined,
+ GPU_dynamic_uniform(GPUWorld.horicol, GPU_DYNAMIC_HORIZON_COLOR, NULL),
+ GPU_dynamic_uniform(GPUWorld.zencol, GPU_DYNAMIC_ZENITH_COLOR, NULL), fcol,
+ GPU_builtin(GPU_VIEW_MATRIX), shi->vn, &shr->combined);
+ }
+ }
+ else {
+ GPUNodeLink *f;
+ GPU_link(mat, "math_multiply", shi->amb, shi->refl, &f);
+ GPU_link(mat, "math_multiply", f, GPU_uniform(&world->ao_env_energy), &f);
+ GPU_link(mat, "shade_maddf", shr->combined, f, shi->rgb, &shr->combined);
+ }
+ }
+ }
+
/* ambient color */
if (GPU_link_changed(shi->amb) || ma->amb != 0.0f) {
GPU_link(mat, "shade_maddf", shr->combined, GPU_uniform(&ma->amb),
@@ -2544,7 +2591,7 @@ int GPU_lamp_shadow_bind_code(GPULamp *lamp)
float *GPU_lamp_dynpersmat(GPULamp *lamp)
{
- return lamp->dynpersmat ? (float *)lamp->dynpersmat : NULL;
+ return &lamp->dynpersmat[0][0];
}
int GPU_lamp_shadow_layer(GPULamp *lamp)
@@ -2710,6 +2757,9 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma)
if (GPU_DYNAMIC_GROUP_FROM_TYPE(uniform->type) == GPU_DYNAMIC_GROUP_LAMP)
uniform->lamp = input->dynamicdata;
+
+ if (GPU_DYNAMIC_GROUP_FROM_TYPE(uniform->type) == GPU_DYNAMIC_GROUP_MAT)
+ uniform->material = input->dynamicdata;
}
if (uniform->type != GPU_DYNAMIC_NONE)
@@ -2839,8 +2889,7 @@ void GPU_material_update_fvar_offset(GPUMaterial *gpu_material,
"fvar%d_offset",
input->attribid);
location = GPU_shader_get_uniform(shader, name);
- /* Multiply by 2 because we're offseting U and V variables. */
- GPU_shader_uniform_int(shader, location, layer_index * 2);
+ GPU_shader_uniform_int(shader, location, layer_index);
}
}
diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c
index 49f244083f9..5cfb323bc4b 100644
--- a/source/blender/gpu/intern/gpu_shader.c
+++ b/source/blender/gpu/intern/gpu_shader.c
@@ -27,7 +27,6 @@
#include "MEM_guardedalloc.h"
-#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_math_base.h"
#include "BLI_math_vector.h"
@@ -46,6 +45,7 @@
#define MAX_EXT_DEFINE_LENGTH 1024
/* Non-generated shaders */
+extern char datatoc_gpu_shader_fire_frag_glsl[];
extern char datatoc_gpu_shader_smoke_vert_glsl[];
extern char datatoc_gpu_shader_smoke_frag_glsl[];
extern char datatoc_gpu_shader_vsm_store_vert_glsl[];
@@ -205,6 +205,10 @@ static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH],
if (GPU_bicubic_bump_support())
strcat(defines, "#define BUMP_BICUBIC\n");
+ if (GLEW_VERSION_3_0) {
+ strcat(defines, "#define BIT_OPERATIONS\n");
+ }
+
#ifdef WITH_OPENSUBDIV
/* TODO(sergey): Check whether we actually compiling shader for
* the OpenSubdiv mesh.
@@ -434,6 +438,10 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode,
/* TODO(sergey): Find a better place for this. */
if (use_opensubdiv && GLEW_VERSION_4_1) {
glProgramUniform1i(shader->program,
+ glGetUniformLocation(shader->program, "FVarDataOffsetBuffer"),
+ 30); /* GL_TEXTURE30 */
+
+ glProgramUniform1i(shader->program,
glGetUniformLocation(shader->program, "FVarDataBuffer"),
31); /* GL_TEXTURE31 */
}
@@ -611,8 +619,8 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader)
case GPU_SHADER_SMOKE_FIRE:
if (!GG.shaders.smoke_fire)
GG.shaders.smoke_fire = GPU_shader_create(
- datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl,
- NULL, NULL, "#define USE_FIRE;\n", 0, 0, 0);
+ datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_fire_frag_glsl,
+ NULL, NULL, NULL, 0, 0, 0);
retval = GG.shaders.smoke_fire;
break;
}
diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c
index 294b08f155a..54f0003c086 100644
--- a/source/blender/gpu/intern/gpu_texture.c
+++ b/source/blender/gpu/intern/gpu_texture.c
@@ -32,7 +32,6 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_math_base.h"
-#include "BLI_math_vector.h"
#include "BKE_global.h"
@@ -56,7 +55,8 @@ struct GPUTexture {
int number; /* number for multitexture binding */
int refcount; /* reference count */
GLenum target; /* GL_TEXTURE_* */
- GLenum target_base; /* same as target, (but no multisample) */
+ GLenum target_base; /* same as target, (but no multisample)
+ * use it for unbinding */
GLuint bindcode; /* opengl identifier for texture */
int fromblender; /* we got the texture from Blender */
@@ -375,6 +375,9 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget
GLint bindcode = GPU_verify_image(ima, iuser, textarget, 0, 0, mipmap, is_data);
GPU_update_image_time(ima, time);
+ /* see GPUInput::textarget: it can take two values - GL_TEXTURE_2D and GL_TEXTURE_CUBE_MAP
+ * these values are correct for glDisable, so textarget can be safely used in
+ * GPU_texture_bind/GPU_texture_unbind through tex->target_base */
if (textarget == GL_TEXTURE_2D)
gputt = TEXTARGET_TEXTURE_2D;
else
@@ -391,7 +394,7 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget
tex->number = -1;
tex->refcount = 1;
tex->target = textarget;
- tex->target_base = GL_TEXTURE_2D;
+ tex->target_base = textarget;
tex->fromblender = 1;
ima->gputexture[gputt] = tex;
@@ -627,11 +630,11 @@ void GPU_texture_bind(GPUTexture *tex, int number)
GLenum arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + number);
if (number != 0) glActiveTexture(arbnumber);
if (tex->bindcode != 0) {
- glBindTexture(tex->target, tex->bindcode);
+ glBindTexture(tex->target_base, tex->bindcode);
}
else
- GPU_invalid_tex_bind(tex->target);
- glEnable(tex->target);
+ GPU_invalid_tex_bind(tex->target_base);
+ glEnable(tex->target_base);
if (number != 0) glActiveTexture(GL_TEXTURE0);
tex->number = number;
@@ -653,8 +656,6 @@ void GPU_texture_unbind(GPUTexture *tex)
GLenum arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + tex->number);
if (tex->number != 0) glActiveTexture(arbnumber);
- glBindTexture(tex->target, 0);
- glDisable(tex->target);
glBindTexture(tex->target_base, 0);
glDisable(tex->target_base);
if (tex->number != 0) glActiveTexture(GL_TEXTURE0);
diff --git a/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl b/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl
index c7b29ee5707..01a335af048 100644
--- a/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl
@@ -3,6 +3,7 @@
*
* USE_COLOR: use glColor for diffuse colors
* USE_TEXTURE: use texture for diffuse colors
+ * USE_TEXTURE_RECTANGLE: use GL_TEXTURE_RECTANGLE instead of GL_TEXTURE_2D
* 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
@@ -27,8 +28,11 @@
#define STIPPLE_S3D_INTERLACE_CHECKERBOARD_SWAP 11
#if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING)
+#if defined(USE_FLAT_NORMAL)
+varying vec3 eyespace_vert_pos;
+#else
varying vec3 varying_normal;
-
+#endif
#ifndef USE_SOLID_LIGHTING
varying vec3 varying_position;
#endif
@@ -39,8 +43,16 @@ varying vec4 varying_vertex_color;
#endif
#ifdef USE_TEXTURE
+#ifdef USE_TEXTURE_RECTANGLE
+#define sampler2D_default sampler2DRect
+#define texture2D_default texture2DRect
+#else
+#define sampler2D_default sampler2D
+#define texture2D_default texture2D
+#endif
+
varying vec2 varying_texture_coord;
-uniform sampler2D texture_map;
+uniform sampler2D_default texture_map;
#endif
#ifdef USE_STIPPLE
@@ -55,89 +67,93 @@ void main()
{
#if defined(USE_STIPPLE)
#if defined(DRAW_LINE)
- /* GLSL 1.3 */
- if (!bool((1 << int(mod(t, 16))) & stipple_pattern))
- discard;
+ /* GLSL 1.3 */
+ if (!bool((1 << int(mod(t, 16))) & stipple_pattern))
+ discard;
#else
- /* We have to use mod function and integer casting.
- * This can be optimized further with the bitwise operations
- * when GLSL 1.3 is supported. */
- if (stipple_id == STIPPLE_HALFTONE ||
- stipple_id == STIPPLE_S3D_INTERLACE_CHECKERBOARD ||
- stipple_id == STIPPLE_S3D_INTERLACE_CHECKERBOARD_SWAP)
- {
- int result = int(mod(gl_FragCoord.x + gl_FragCoord.y, 2));
- bool dis = result == 0;
- if (stipple_id == STIPPLE_S3D_INTERLACE_CHECKERBOARD_SWAP)
- dis = !dis;
- if (dis)
- discard;
- }
- else if (stipple_id == STIPPLE_QUARTTONE) {
- int mody = int(mod(gl_FragCoord.y, 4));
- int modx = int(mod(gl_FragCoord.x, 4));
- if (mody == 0) {
- if (modx != 2)
- discard;
- }
- else if (mody == 2){
- if (modx != 0)
- discard;
- }
- else
- discard;
- }
- else if (stipple_id == STIPPLE_CHECKER_8PX) {
- int result = int(mod(int(gl_FragCoord.x)/8 + int(gl_FragCoord.y)/8, 2));
- if (result != 0)
- discard;
- }
- else if (stipple_id == STIPPLE_DIAG_STRIPES) {
- int mody = int(mod(gl_FragCoord.y, 16));
- int modx = int(mod(gl_FragCoord.x, 16));
- if ((16 - modx > mody && mody > 8 - modx) || mody > 24 - modx)
- discard;
- }
- else if (stipple_id == STIPPLE_DIAG_STRIPES_SWAP) {
- int mody = int(mod(gl_FragCoord.y, 16));
- int modx = int(mod(gl_FragCoord.x, 16));
- if (!((16 - modx > mody && mody > 8 - modx) || mody > 24 - modx))
- discard;
- }
- else if (stipple_id == STIPPLE_S3D_INTERLACE_ROW || stipple_id == STIPPLE_S3D_INTERLACE_ROW_SWAP) {
- int result = int(mod(gl_FragCoord.y, 2));
- bool dis = result == 0;
- if (stipple_id == STIPPLE_S3D_INTERLACE_ROW_SWAP)
- dis = !dis;
- if (dis)
- discard;
- }
- else if (stipple_id == STIPPLE_S3D_INTERLACE_COLUMN || stipple_id == STIPPLE_S3D_INTERLACE_COLUMN_SWAP) {
- int result = int(mod(gl_FragCoord.x, 2));
- bool dis = result != 0;
- if (stipple_id == STIPPLE_S3D_INTERLACE_COLUMN_SWAP)
- dis = !dis;
- if (dis)
- discard;
- }
- else if (stipple_id == STIPPLE_HEXAGON) {
- int mody = int(mod(gl_FragCoord.y, 2));
- int modx = int(mod(gl_FragCoord.x, 4));
- if (mody != 0) {
- if (modx != 1)
- discard;
- }
- else {
- if (modx != 3)
- discard;
- }
- }
+ /* We have to use mod function and integer casting.
+ * This can be optimized further with the bitwise operations
+ * when GLSL 1.3 is supported. */
+ if (stipple_id == STIPPLE_HALFTONE ||
+ stipple_id == STIPPLE_S3D_INTERLACE_CHECKERBOARD ||
+ stipple_id == STIPPLE_S3D_INTERLACE_CHECKERBOARD_SWAP)
+ {
+ int result = int(mod(gl_FragCoord.x + gl_FragCoord.y, 2));
+ bool dis = result == 0;
+ if (stipple_id == STIPPLE_S3D_INTERLACE_CHECKERBOARD_SWAP)
+ dis = !dis;
+ if (dis)
+ discard;
+ }
+ else if (stipple_id == STIPPLE_QUARTTONE) {
+ int mody = int(mod(gl_FragCoord.y, 4));
+ int modx = int(mod(gl_FragCoord.x, 4));
+ if (mody == 0) {
+ if (modx != 2)
+ discard;
+ }
+ else if (mody == 2) {
+ if (modx != 0)
+ discard;
+ }
+ else
+ discard;
+ }
+ else if (stipple_id == STIPPLE_CHECKER_8PX) {
+ int result = int(mod(int(gl_FragCoord.x) / 8 + int(gl_FragCoord.y) / 8, 2));
+ if (result != 0)
+ discard;
+ }
+ else if (stipple_id == STIPPLE_DIAG_STRIPES) {
+ int mody = int(mod(gl_FragCoord.y, 16));
+ int modx = int(mod(gl_FragCoord.x, 16));
+ if ((16 - modx > mody && mody > 8 - modx) || mody > 24 - modx)
+ discard;
+ }
+ else if (stipple_id == STIPPLE_DIAG_STRIPES_SWAP) {
+ int mody = int(mod(gl_FragCoord.y, 16));
+ int modx = int(mod(gl_FragCoord.x, 16));
+ if (!((16 - modx > mody && mody > 8 - modx) || mody > 24 - modx))
+ discard;
+ }
+ else if (stipple_id == STIPPLE_S3D_INTERLACE_ROW || stipple_id == STIPPLE_S3D_INTERLACE_ROW_SWAP) {
+ int result = int(mod(gl_FragCoord.y, 2));
+ bool dis = result == 0;
+ if (stipple_id == STIPPLE_S3D_INTERLACE_ROW_SWAP)
+ dis = !dis;
+ if (dis)
+ discard;
+ }
+ else if (stipple_id == STIPPLE_S3D_INTERLACE_COLUMN || stipple_id == STIPPLE_S3D_INTERLACE_COLUMN_SWAP) {
+ int result = int(mod(gl_FragCoord.x, 2));
+ bool dis = result != 0;
+ if (stipple_id == STIPPLE_S3D_INTERLACE_COLUMN_SWAP)
+ dis = !dis;
+ if (dis)
+ discard;
+ }
+ else if (stipple_id == STIPPLE_HEXAGON) {
+ int mody = int(mod(gl_FragCoord.y, 2));
+ int modx = int(mod(gl_FragCoord.x, 4));
+ if (mody != 0) {
+ if (modx != 1)
+ discard;
+ }
+ else {
+ if (modx != 3)
+ discard;
+ }
+ }
#endif /* !DRAW_LINE */
#endif /* USE_STIPPLE */
#if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING)
/* compute normal */
+#if defined(USE_FLAT_NORMAL)
+ vec3 N = normalize(cross(dFdx(eyespace_vert_pos), dFdy(eyespace_vert_pos)));
+#else
vec3 N = normalize(varying_normal);
+#endif
#ifdef USE_TWO_SIDED
if (!gl_FrontFacing)
@@ -158,7 +174,7 @@ void main()
/* 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;
+ L_diffuse += light_diffuse * diffuse_bsdf;
#ifndef NO_SPECULAR
/* specular light */
@@ -166,7 +182,7 @@ void main()
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;
+ L_specular += light_specular * specular_bsdf;
#endif
}
#else
@@ -174,7 +190,7 @@ void main()
#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);
+ 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++) {
@@ -205,14 +221,14 @@ void main()
float distance = length(d);
intensity /= gl_LightSource[i].constantAttenuation +
- gl_LightSource[i].linearAttenuation * distance +
- gl_LightSource[i].quadraticAttenuation * distance * distance;
+ 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;
+ L_diffuse += light_diffuse * diffuse_bsdf * intensity;
#ifndef NO_SPECULAR
/* specular light */
@@ -220,7 +236,7 @@ void main()
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;
+ L_specular += light_specular * specular_bsdf * intensity;
#endif
}
#endif
@@ -229,12 +245,12 @@ void main()
float alpha;
#if defined(USE_TEXTURE) && defined(USE_COLOR)
- vec4 texture_color = texture2D(texture_map, varying_texture_coord);
+ vec4 texture_color = texture2D_default(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);
+ vec4 texture_color = texture2D_default(texture_map, varying_texture_coord);
L_diffuse *= texture_color.rgb;
alpha = texture_color.a;
@@ -250,7 +266,7 @@ void main()
vec3 L = gl_FrontLightModelProduct.sceneColor.rgb + L_diffuse;
#ifndef NO_SPECULAR
- L += L_specular*gl_FrontMaterial.specular.rgb;
+ L += L_specular * gl_FrontMaterial.specular.rgb;
#endif
/* write out fragment color */
@@ -259,9 +275,9 @@ void main()
/* no lighting */
#if defined(USE_TEXTURE) && defined(USE_COLOR)
- gl_FragColor = texture2D(texture_map, varying_texture_coord) * varying_vertex_color;
+ gl_FragColor = texture2D_default(texture_map, varying_texture_coord) * varying_vertex_color;
#elif defined(USE_TEXTURE)
- gl_FragColor = texture2D(texture_map, varying_texture_coord);
+ gl_FragColor = texture2D_default(texture_map, varying_texture_coord);
#elif defined(USE_COLOR)
gl_FragColor = varying_vertex_color;
#else
diff --git a/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl b/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl
index ffd747ab1eb..a88681a5fd3 100644
--- a/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl
@@ -1,6 +1,6 @@
/*
-* Used the implementation of wide lines of Timo Suoranta (http://neure.dy.fi/wideline.html)
-*/
+ * Used the implementation of wide lines of Timo Suoranta (http://neure.dy.fi/wideline.html)
+ */
#define PASSTHROUGH 0
@@ -24,72 +24,72 @@ uniform int stipple_factor;
void main(void)
{
- vec2 window_size = viewport.zw;
- vec4 start = gl_in[0].gl_Position;
- vec4 end = gl_in[1].gl_Position;
+ vec2 window_size = viewport.zw;
+ vec4 start = gl_in[0].gl_Position;
+ vec4 end = gl_in[1].gl_Position;
#if PASSTHROUGH
- gl_Position = start; EmitVertex();
- gl_Position = end; EmitVertex();
- EndPrimitive();
- return;
+ gl_Position = start; EmitVertex();
+ gl_Position = end; EmitVertex();
+ EndPrimitive();
+ return;
#endif
-/* t = 0 t = ~(len(end - start) + 2*line_width)
- * A-------------------------------------B
- * | | | |
- * | side | |
- * | | | |
- * |--axis--*start--------------*end-----|
- * | | | |
- * | | | |
- * | | | |
- * D-------------------------------------C
- */
-
- /* Clip the line before homogenization.
- * Compute line start and end distances to nearplane in clipspace
- * Distances are t0 = dot(start, plane) and t1 = dot(end, plane)
- */
- float t0 = start.z + start.w;
- float t1 = end.z + end.w;
- if(t0 < 0.0) {
- if(t1 < 0.0) {
- return;
- }
- start = mix(start, end, (0 - t0) / (t1 - t0));
- }
- if(t1 < 0.0) {
- end = mix(start, end, (0 - t0) / (t1 - t0));
- }
-
- /* Compute line axis and side vector in screen space */
- vec2 startInNDC = start.xy / start.w; /* clip to NDC: homogenize and drop z */
- vec2 endInNDC = end.xy / end.w;
- vec2 lineInNDC = endInNDC - startInNDC;
- vec2 lineInScreen = lineInNDC * window_size; /* ndc to screen (direction vector) */
-
- vec2 axisInScreen = normalize(lineInScreen);
- vec2 sideInScreen = vec2(-axisInScreen.y, axisInScreen.x); /* rotate */
- vec2 axisInNDC = axisInScreen / window_size; /* screen to NDC */
- vec2 sideInNDC = sideInScreen / window_size;
- vec4 axis = vec4(axisInNDC, 0.0, 0.0) * line_width; /* NDC to clip (delta vector) */
- vec4 side = vec4(sideInNDC, 0.0, 0.0) * line_width;
-
- vec4 A = (start + (side - axis) * start.w);
- vec4 B = (end + (side + axis) * end.w);
- vec4 C = (end - (side - axis) * end.w);
- vec4 D = (start - (side + axis) * start.w);
-
- /* There is no relation between lines yet */
- /* TODO Pass here t0 to make continuous pattern. */
- t0 = 0;
- t1 = (length(lineInScreen) + 2*line_width)/ (2*line_width * stipple_factor);
-
- gl_Position = A; t = t0; varying_vertex_color = varying_vertex_color_line[0]; EmitVertex();
- gl_Position = D; t = t0; varying_vertex_color = varying_vertex_color_line[0]; EmitVertex();
- gl_Position = B; t = t1; varying_vertex_color = varying_vertex_color_line[1]; EmitVertex();
- gl_Position = C; t = t1; varying_vertex_color = varying_vertex_color_line[1]; EmitVertex();
- EndPrimitive();
+ /* t = 0 t = ~(len(end - start) + 2*line_width)
+ * A-------------------------------------B
+ * | | | |
+ * | side | |
+ * | | | |
+ * |--axis--*start--------------*end-----|
+ * | | | |
+ * | | | |
+ * | | | |
+ * D-------------------------------------C
+ */
+
+ /* Clip the line before homogenization.
+ * Compute line start and end distances to nearplane in clipspace
+ * Distances are t0 = dot(start, plane) and t1 = dot(end, plane)
+ */
+ float t0 = start.z + start.w;
+ float t1 = end.z + end.w;
+ if (t0 < 0.0) {
+ if (t1 < 0.0) {
+ return;
+ }
+ start = mix(start, end, (0 - t0) / (t1 - t0));
+ }
+ if (t1 < 0.0) {
+ end = mix(start, end, (0 - t0) / (t1 - t0));
+ }
+
+ /* Compute line axis and side vector in screen space */
+ vec2 startInNDC = start.xy / start.w; /* clip to NDC: homogenize and drop z */
+ vec2 endInNDC = end.xy / end.w;
+ vec2 lineInNDC = endInNDC - startInNDC;
+ vec2 lineInScreen = lineInNDC * window_size; /* ndc to screen (direction vector) */
+
+ vec2 axisInScreen = normalize(lineInScreen);
+ vec2 sideInScreen = vec2(-axisInScreen.y, axisInScreen.x); /* rotate */
+ vec2 axisInNDC = axisInScreen / window_size; /* screen to NDC */
+ vec2 sideInNDC = sideInScreen / window_size;
+ vec4 axis = vec4(axisInNDC, 0.0, 0.0) * line_width; /* NDC to clip (delta vector) */
+ vec4 side = vec4(sideInNDC, 0.0, 0.0) * line_width;
+
+ vec4 A = (start + (side - axis) * start.w);
+ vec4 B = (end + (side + axis) * end.w);
+ vec4 C = (end - (side - axis) * end.w);
+ vec4 D = (start - (side + axis) * start.w);
+
+ /* There is no relation between lines yet */
+ /* TODO Pass here t0 to make continuous pattern. */
+ t0 = 0;
+ t1 = (length(lineInScreen) + 2 * line_width) / (2 * line_width * stipple_factor);
+
+ gl_Position = A; t = t0; varying_vertex_color = varying_vertex_color_line[0]; EmitVertex();
+ gl_Position = D; t = t0; varying_vertex_color = varying_vertex_color_line[0]; EmitVertex();
+ gl_Position = B; t = t1; varying_vertex_color = varying_vertex_color_line[1]; EmitVertex();
+ gl_Position = C; t = t1; varying_vertex_color = varying_vertex_color_line[1]; EmitVertex();
+ EndPrimitive();
}
#else
diff --git a/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl b/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl
index 04900001998..42fbdadf1d1 100644
--- a/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl
@@ -1,6 +1,10 @@
#if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING)
+#if defined(USE_FLAT_NORMAL)
+varying vec3 eyespace_vert_pos;
+#else
varying vec3 varying_normal;
+#endif
#ifndef USE_SOLID_LIGHTING
varying vec3 varying_position;
@@ -28,7 +32,13 @@ void main()
vec4 co = gl_ModelViewMatrix * gl_Vertex;
#if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING)
+#if !defined(USE_FLAT_NORMAL)
varying_normal = normalize(gl_NormalMatrix * gl_Normal);
+#endif
+#if defined(USE_FLAT_NORMAL)
+ /* transform vertex into eyespace */
+ eyespace_vert_pos = (gl_ModelViewMatrix * gl_Vertex).xyz;
+#endif
#ifndef USE_SOLID_LIGHTING
varying_position = co.xyz;
@@ -39,7 +49,7 @@ void main()
#ifdef CLIP_WORKAROUND
int i;
- for(i = 0; i < 6; i++)
+ for (i = 0; i < 6; i++)
gl_ClipDistance[i] = dot(co, gl_ClipPlane[i]);
#elif !defined(GPU_ATI)
// Setting gl_ClipVertex is necessary to get glClipPlane working on NVIDIA
diff --git a/source/blender/gpu/shaders/gpu_shader_fire_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fire_frag.glsl
new file mode 100644
index 00000000000..3819203bcd9
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_fire_frag.glsl
@@ -0,0 +1,17 @@
+
+varying vec3 coords;
+
+uniform sampler3D flame_texture;
+uniform sampler1D spectrum_texture;
+
+void main()
+{
+ float flame = texture3D(flame_texture, coords).r;
+ vec4 emission = texture1D(spectrum_texture, flame);
+
+ vec4 color;
+ color.rgb = emission.a * emission.rgb;
+ color.a = emission.a;
+
+ gl_FragColor = color;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl
index e9dab04de5d..338ef6d51a7 100644
--- a/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl
@@ -115,9 +115,9 @@ void second_pass()
color += texture2D(colorbuffer, uvcoordsvar.xy + invrendertargetdim) * 0.234375;
color += texture2D(colorbuffer, uvcoordsvar.xy + 2.5 * invrendertargetdim) * 0.09375;
color += texture2D(colorbuffer, uvcoordsvar.xy + 4.5 * invrendertargetdim) * 0.015625;
- color += texture2D(colorbuffer, uvcoordsvar.xy -invrendertargetdim) * 0.234375;
- color += texture2D(colorbuffer, uvcoordsvar.xy -2.5 * invrendertargetdim) * 0.09375;
- color += texture2D(colorbuffer, uvcoordsvar.xy -4.5 * invrendertargetdim) * 0.015625;
+ color += texture2D(colorbuffer, uvcoordsvar.xy - invrendertargetdim) * 0.234375;
+ color += texture2D(colorbuffer, uvcoordsvar.xy - 2.5 * invrendertargetdim) * 0.09375;
+ color += texture2D(colorbuffer, uvcoordsvar.xy - 4.5 * invrendertargetdim) * 0.015625;
gl_FragColor = color;
}
@@ -128,7 +128,7 @@ void third_pass()
{
vec4 color = texture2D(colorbuffer, uvcoordsvar.xy);
vec4 color_blurred = texture2D(blurredcolorbuffer, uvcoordsvar.xy);
- float coc = 2.0 * max(color_blurred.a, color.a); - color.a;
+ float coc = 2.0 * max(color_blurred.a, color.a); -color.a;
gl_FragColor = vec4(color.rgb, coc);
}
@@ -146,7 +146,7 @@ void fourth_pass()
vec4 small_sample_blur(in sampler2D colorbuffer, in vec2 uv, in vec4 color)
{
- float weight = 1.0/ 17.0;
+ float weight = 1.0 / 17.0;
vec4 result = weight * color;
weight *= 4.0;
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl
index e315d2fb97a..182113367d3 100644
--- a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl
@@ -102,7 +102,8 @@ void accumulate_pass(void) {
if (dof_params.w == 0.0)
r = 1.0;
else
- r = cos(M_PI / dof_params.w) / (cos(theta - (2.0 * M_PI / dof_params.w) * floor((dof_params.w * theta + M_PI) / (2.0 * M_PI))));
+ r = cos(M_PI / dof_params.w) /
+ (cos(theta - (2.0 * M_PI / dof_params.w) * floor((dof_params.w * theta + M_PI) / (2.0 * M_PI))));
if (dot(particlecoord, particlecoord) > r * r)
discard;
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl
index a2ef990c4e8..63b57d5775c 100644
--- a/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl
@@ -38,8 +38,12 @@ void vert_dof_first_pass()
void vert_dof_fourth_pass()
{
vec4 halfpixel = vec4(-0.5, 0.5, -0.5, 0.5);
- uvcoordsvar = gl_MultiTexCoord0.xxyy + halfpixel * vec4(invrendertargetdim.x,
- invrendertargetdim.x, invrendertargetdim.y, invrendertargetdim.y);
+ uvcoordsvar = gl_MultiTexCoord0.xxyy +
+ halfpixel *
+ vec4(invrendertargetdim.x,
+ invrendertargetdim.x,
+ invrendertargetdim.y,
+ invrendertargetdim.y);
gl_Position = gl_Vertex;
}
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
index 494a74dcdf8..054a2f795ee 100644
--- a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
@@ -44,7 +44,8 @@ float calculate_ssao_factor(float depth)
vec3 position = get_view_space_from_depth(uvcoordsvar.xy, viewvecs[0].xyz, viewvecs[1].xyz, depth);
vec3 normal = calculate_view_space_normal(position);
- // find the offset in screen space by multiplying a point in camera space at the depth of the point by the projection matrix.
+ /* find the offset in screen space by multiplying a point
+ * in camera space at the depth of the point by the projection matrix. */
vec2 offset;
float homcoord = gl_ProjectionMatrix[2][3] * position.z + gl_ProjectionMatrix[3][3];
offset.x = gl_ProjectionMatrix[0][0] * ssao_params.x / homcoord;
@@ -76,7 +77,7 @@ float calculate_ssao_factor(float depth)
/* use minor bias here to avoid self shadowing */
if (f > 0.05 * len + 0.0001)
- factor += f * 1.0/(len * (1.0 + len * len * ssao_params.z));
+ factor += f * 1.0 / (len * (1.0 + len * len * ssao_params.z));
}
}
diff --git a/source/blender/gpu/shaders/gpu_shader_geometry.glsl b/source/blender/gpu/shaders/gpu_shader_geometry.glsl
index 16fba0dd055..fe630dbeddb 100644
--- a/source/blender/gpu/shaders/gpu_shader_geometry.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_geometry.glsl
@@ -31,7 +31,20 @@ uniform int osd_fvar_count;
tessCoord.t); \
}
+#ifdef USE_NEW_SHADING
+# define INTERP_FACE_VARYING_ATT_2(result, fvarOffset, tessCoord) \
+ { \
+ vec2 tmp; \
+ INTERP_FACE_VARYING_2(tmp, fvarOffset, tessCoord); \
+ result = vec3(tmp, 0); \
+ }
+#else
+# define INTERP_FACE_VARYING_ATT_2(result, fvarOffset, tessCoord) \
+ INTERP_FACE_VARYING_2(result, fvarOffset, tessCoord)
+#endif
+
uniform samplerBuffer FVarDataBuffer;
+uniform isamplerBuffer FVarDataOffsetBuffer;
out block {
VertexData v;
@@ -49,7 +62,7 @@ void emit_flat(int index, vec3 normal)
varposition = outpt.v.position.xyz;
/* TODO(sergey): Only uniform subdivisions atm. */
- vec2 quadst[4] = vec2[](vec2(0,0), vec2(1,0), vec2(1,1), vec2(0,1));
+ vec2 quadst[4] = vec2[](vec2(0, 0), vec2(1, 0), vec2(1, 1), vec2(0, 1));
vec2 st = quadst[index];
INTERP_FACE_VARYING_2(outpt.v.uv, osd_active_uv_offset, st);
@@ -70,7 +83,7 @@ void emit_smooth(int index)
varposition = outpt.v.position.xyz;
/* TODO(sergey): Only uniform subdivisions atm. */
- vec2 quadst[4] = vec2[](vec2(0,0), vec2(1,0), vec2(1,1), vec2(0,1));
+ vec2 quadst[4] = vec2[](vec2(0, 0), vec2(1, 0), vec2(1, 1), vec2(0, 1));
vec2 st = quadst[index];
INTERP_FACE_VARYING_2(outpt.v.uv, osd_active_uv_offset, st);
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index 72a59e6843d..67da8201f66 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -3,7 +3,7 @@
float convert_rgba_to_float(vec4 color)
{
#ifdef USE_NEW_SHADING
- return color.r*0.2126 + color.g*0.7152 + color.b*0.0722;
+ return color.r * 0.2126 + color.g * 0.7152 + color.b * 0.0722;
#else
return (color.r + color.g + color.b) / 3.0;
#endif
@@ -16,17 +16,17 @@ float exp_blender(float f)
float compatible_pow(float x, float y)
{
- if(y == 0.0) /* x^0 -> 1, including 0^0 */
+ if (y == 0.0) /* x^0 -> 1, including 0^0 */
return 1.0;
/* glsl pow doesn't accept negative x */
- if(x < 0.0) {
- if(mod(-y, 2.0) == 0.0)
+ if (x < 0.0) {
+ if (mod(-y, 2.0) == 0.0)
return pow(-x, y);
else
return -pow(-x, y);
}
- else if(x == 0.0)
+ else if (x == 0.0)
return 0.0;
return pow(x, y);
@@ -39,11 +39,11 @@ void rgb_to_hsv(vec4 rgb, out vec4 outcol)
cmax = max(rgb[0], max(rgb[1], rgb[2]));
cmin = min(rgb[0], min(rgb[1], rgb[2]));
- cdelta = cmax-cmin;
+ cdelta = cmax - cmin;
v = cmax;
- if (cmax!=0.0)
- s = cdelta/cmax;
+ if (cmax != 0.0)
+ s = cdelta / cmax;
else {
s = 0.0;
h = 0.0;
@@ -53,15 +53,15 @@ void rgb_to_hsv(vec4 rgb, out vec4 outcol)
h = 0.0;
}
else {
- c = (vec3(cmax, cmax, cmax) - rgb.xyz)/cdelta;
+ c = (vec3(cmax, cmax, cmax) - rgb.xyz) / cdelta;
- if (rgb.x==cmax) h = c[2] - c[1];
- else if (rgb.y==cmax) h = 2.0 + c[0] - c[2];
+ if (rgb.x == cmax) h = c[2] - c[1];
+ else if (rgb.y == cmax) h = 2.0 + c[0] - c[2];
else h = 4.0 + c[1] - c[0];
h /= 6.0;
- if (h<0.0)
+ if (h < 0.0)
h += 1.0;
}
@@ -77,21 +77,21 @@ void hsv_to_rgb(vec4 hsv, out vec4 outcol)
s = hsv[1];
v = hsv[2];
- if(s==0.0) {
+ if (s == 0.0) {
rgb = vec3(v, v, v);
}
else {
- if(h==1.0)
+ if (h == 1.0)
h = 0.0;
-
+
h *= 6.0;
i = floor(h);
f = h - i;
rgb = vec3(f, f, f);
- p = v*(1.0-s);
- q = v*(1.0-(s*f));
- t = v*(1.0-(s*(1.0-f)));
-
+ p = v * (1.0 - s);
+ q = v * (1.0 - (s * f));
+ t = v * (1.0 - (s * (1.0 - f)));
+
if (i == 0.0) rgb = vec3(v, t, p);
else if (i == 1.0) rgb = vec3(q, v, p);
else if (i == 2.0) rgb = vec3(p, v, t);
@@ -105,18 +105,18 @@ void hsv_to_rgb(vec4 hsv, out vec4 outcol)
float srgb_to_linearrgb(float c)
{
- if(c < 0.04045)
- return (c < 0.0) ? 0.0: c * (1.0 / 12.92);
+ if (c < 0.04045)
+ return (c < 0.0) ? 0.0 : c * (1.0 / 12.92);
else
- return pow((c + 0.055)*(1.0/1.055), 2.4);
+ return pow((c + 0.055) * (1.0 / 1.055), 2.4);
}
float linearrgb_to_srgb(float c)
{
- if(c < 0.0031308)
- return (c < 0.0) ? 0.0: c * 12.92;
+ if (c < 0.0031308)
+ return (c < 0.0) ? 0.0 : c * 12.92;
else
- return 1.055 * pow(c, 1.0/2.4) - 0.055;
+ return 1.055 * pow(c, 1.0 / 2.4) - 0.055;
}
void srgb_to_linearrgb(vec4 col_from, out vec4 col_to)
@@ -142,6 +142,20 @@ void color_to_normal(vec3 color, out vec3 normal)
normal.z = 2.0 * ((color.b) - 0.5);
}
+void color_to_normal_new_shading(vec3 color, out vec3 normal)
+{
+ normal.x = 2.0 * ((color.r) - 0.5);
+ normal.y = 2.0 * ((color.g) - 0.5);
+ normal.z = 2.0 * ((color.b) - 0.5);
+}
+
+void color_to_blender_normal_new_shading(vec3 color, out vec3 normal)
+{
+ normal.x = 2.0 * ((color.r) - 0.5);
+ normal.y = -2.0 * ((color.g) - 0.5);
+ normal.z = -2.0 * ((color.b) - 0.5);
+}
+
#define M_PI 3.14159265358979323846
#define M_1_PI 0.31830988618379069
@@ -149,38 +163,44 @@ void color_to_normal(vec3 color, out vec3 normal)
void vcol_attribute(vec4 attvcol, out vec4 vcol)
{
- vcol = vec4(attvcol.x/255.0, attvcol.y/255.0, attvcol.z/255.0, 1.0);
+ vcol = vec4(attvcol.x, attvcol.y, attvcol.z, 1.0);
}
void uv_attribute(vec2 attuv, out vec3 uv)
{
- uv = vec3(attuv*2.0 - vec2(1.0, 1.0), 0.0);
+ uv = vec3(attuv * 2.0 - vec2(1.0, 1.0), 0.0);
}
-void geom(vec3 co, vec3 nor, mat4 viewinvmat, vec3 attorco, vec2 attuv, vec4 attvcol, out vec3 global, out vec3 local, out vec3 view, out vec3 orco, out vec3 uv, out vec3 normal, out vec4 vcol, out float vcol_alpha, out float frontback)
+void geom(
+ vec3 co, vec3 nor, mat4 viewinvmat, vec3 attorco, vec2 attuv, vec4 attvcol,
+ out vec3 global, out vec3 local, out vec3 view, out vec3 orco, out vec3 uv,
+ out vec3 normal, out vec4 vcol, out float vcol_alpha, out float frontback)
{
local = co;
- view = (gl_ProjectionMatrix[3][3] == 0.0)? normalize(local): vec3(0.0, 0.0, -1.0);
- global = (viewinvmat*vec4(local, 1.0)).xyz;
+ view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(local) : vec3(0.0, 0.0, -1.0);
+ global = (viewinvmat * vec4(local, 1.0)).xyz;
orco = attorco;
uv_attribute(attuv, uv);
- normal = -normalize(nor); /* blender render normal is negated */
+ normal = -normalize(nor); /* blender render normal is negated */
vcol_attribute(attvcol, vcol);
srgb_to_linearrgb(vcol, vcol);
vcol_alpha = attvcol.a;
- frontback = (gl_FrontFacing)? 1.0: 0.0;
+ frontback = (gl_FrontFacing) ? 1.0 : 0.0;
}
-void particle_info(vec4 sprops, vec3 loc, vec3 vel, vec3 avel, out float index, out float age, out float life_time, out vec3 location, out float size, out vec3 velocity, out vec3 angular_velocity)
+void particle_info(
+ vec4 sprops, vec3 loc, vec3 vel, vec3 avel,
+ out float index, out float age, out float life_time, out vec3 location,
+ out float size, out vec3 velocity, out vec3 angular_velocity)
{
- index = sprops.x;
- age = sprops.y;
- life_time = sprops.z;
- size = sprops.w;
+ index = sprops.x;
+ age = sprops.y;
+ life_time = sprops.z;
+ size = sprops.w;
- location = loc;
- velocity = vel;
- angular_velocity = avel;
+ location = loc;
+ velocity = vel;
+ angular_velocity = avel;
}
void vect_normalize(vec3 vin, out vec3 vout)
@@ -190,20 +210,56 @@ void vect_normalize(vec3 vin, out vec3 vout)
void direction_transform_m4v3(vec3 vin, mat4 mat, out vec3 vout)
{
- vout = (mat*vec4(vin, 0.0)).xyz;
+ vout = (mat * vec4(vin, 0.0)).xyz;
}
void point_transform_m4v3(vec3 vin, mat4 mat, out vec3 vout)
{
- vout = (mat*vec4(vin, 1.0)).xyz;
+ vout = (mat * vec4(vin, 1.0)).xyz;
+}
+
+void point_texco_remap_square(vec3 vin, out vec3 vout)
+{
+ vout = vec3(vin - vec3(0.5, 0.5, 0.5)) * 2.0;
+}
+
+void point_map_to_sphere(vec3 vin, out vec3 vout)
+{
+ float len = length(vin);
+ float v, u;
+ if (len > 0.0) {
+ if (vin.x == 0.0 && vin.y == 0.0)
+ u = 0.0;
+ else
+ u = (1.0 - atan(vin.x, vin.y) / M_PI) / 2.0;
+
+ v = 1.0 - acos(vin.z / len) / M_PI;
+ }
+ else
+ v = u = 0.0;
+
+ vout = vec3(u, v, 0.0);
+}
+
+void point_map_to_tube(vec3 vin, out vec3 vout)
+{
+ float u, v;
+ v = (vin.z + 1.0) * 0.5;
+ float len = sqrt(vin.x * vin.x + vin.y * vin[1]);
+ if (len > 0.0)
+ u = (1.0 - (atan(vin.x / len, vin.y / len) / M_PI)) * 0.5;
+ else
+ v = u = 0.0;
+
+ vout = vec3(u, v, 0.0);
}
void mapping(vec3 vec, mat4 mat, vec3 minvec, vec3 maxvec, float domin, float domax, out vec3 outvec)
{
outvec = (mat * vec4(vec, 1.0)).xyz;
- if(domin == 1.0)
+ if (domin == 1.0)
outvec = max(outvec, minvec);
- if(domax == 1.0)
+ if (domax == 1.0)
outvec = min(outvec, maxvec);
}
@@ -214,7 +270,9 @@ void camera(vec3 co, out vec3 outview, out float outdepth, out float outdist)
outview = normalize(co);
}
-void lamp(vec4 col, float energy, vec3 lv, float dist, vec3 shadow, float visifac, out vec4 outcol, out vec3 outlv, out float outdist, out vec4 outshadow, out float outvisifac)
+void lamp(
+ vec4 col, float energy, vec3 lv, float dist, vec3 shadow, float visifac,
+ out vec4 outcol, out vec3 outlv, out float outdist, out vec4 outshadow, out float outvisifac)
{
outcol = col * energy;
outlv = lv;
@@ -299,10 +357,10 @@ void math_pow(float val1, float val2, out float outval)
void math_log(float val1, float val2, out float outval)
{
- if(val1 > 0.0 && val2 > 0.0)
- outval= log2(val1) / log2(val2);
+ if (val1 > 0.0 && val2 > 0.0)
+ outval = log2(val1) / log2(val2);
else
- outval= 0.0;
+ outval = 0.0;
}
void math_max(float val1, float val2, out float outval)
@@ -317,12 +375,12 @@ void math_min(float val1, float val2, out float outval)
void math_round(float val, out float outval)
{
- outval= floor(val + 0.5);
+ outval = floor(val + 0.5);
}
void math_less_than(float val1, float val2, out float outval)
{
- if(val1 < val2)
+ if (val1 < val2)
outval = 1.0;
else
outval = 0.0;
@@ -330,7 +388,7 @@ void math_less_than(float val1, float val2, out float outval)
void math_greater_than(float val1, float val2, out float outval)
{
- if(val1 > val2)
+ if (val1 > val2)
outval = 1.0;
else
outval = 0.0;
@@ -350,24 +408,24 @@ void math_modulo(float val1, float val2, out float outval)
void math_abs(float val1, out float outval)
{
- outval = abs(val1);
+ outval = abs(val1);
}
void squeeze(float val, float width, float center, out float outval)
{
- outval = 1.0/(1.0 + pow(2.71828183, -((val-center)*width)));
+ outval = 1.0 / (1.0 + pow(2.71828183, -((val - center) * width)));
}
void vec_math_add(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
{
outvec = v1 + v2;
- outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2]))/3.0;
+ outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) / 3.0;
}
void vec_math_sub(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
{
outvec = v1 - v2;
- outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2]))/3.0;
+ outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) / 3.0;
}
void vec_math_average(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
@@ -378,7 +436,7 @@ void vec_math_average(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
}
void vec_math_mix(float strength, vec3 v1, vec3 v2, out vec3 outvec)
{
- outvec = strength*v1 + (1 - strength) * v2;
+ outvec = strength * v1 + (1 - strength) * v2;
}
void vec_math_dot(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
@@ -407,8 +465,8 @@ void vec_math_negate(vec3 v, out vec3 outv)
void invert_z(vec3 v, out vec3 outv)
{
- v.z = -v.z;
- outv = v;
+ v.z = -v.z;
+ outv = v;
}
void normal(vec3 dir, vec3 nor, out vec3 outnor, out float outdot)
@@ -425,12 +483,12 @@ void normal_new_shading(vec3 dir, vec3 nor, out vec3 outnor, out float outdot)
void curves_vec(float fac, vec3 vec, sampler2D curvemap, out vec3 outvec)
{
- outvec.x = texture2D(curvemap, vec2((vec.x + 1.0)*0.5, 0.0)).x;
- outvec.y = texture2D(curvemap, vec2((vec.y + 1.0)*0.5, 0.0)).y;
- outvec.z = texture2D(curvemap, vec2((vec.z + 1.0)*0.5, 0.0)).z;
+ outvec.x = texture2D(curvemap, vec2((vec.x + 1.0) * 0.5, 0.0)).x;
+ outvec.y = texture2D(curvemap, vec2((vec.y + 1.0) * 0.5, 0.0)).y;
+ outvec.z = texture2D(curvemap, vec2((vec.z + 1.0) * 0.5, 0.0)).z;
if (fac != 1.0)
- outvec = (outvec*fac) + (vec*(1.0-fac));
+ outvec = (outvec * fac) + (vec * (1.0 - fac));
}
@@ -441,7 +499,7 @@ void curves_rgb(float fac, vec4 col, sampler2D curvemap, out vec4 outcol)
outcol.b = texture2D(curvemap, vec2(texture2D(curvemap, vec2(col.b, 0.0)).a, 0.0)).b;
if (fac != 1.0)
- outcol = (outcol*fac) + (col*(1.0-fac));
+ outcol = (outcol * fac) + (col * (1.0 - fac));
outcol.a = col.a;
}
@@ -494,11 +552,11 @@ void set_rgba_one(out vec4 outval)
void brightness_contrast(vec4 col, float brightness, float contrast, out vec4 outcol)
{
float a = 1.0 + contrast;
- float b = brightness - contrast*0.5;
+ float b = brightness - contrast * 0.5;
- outcol.r = max(a*col.r + b, 0.0);
- outcol.g = max(a*col.g + b, 0.0);
- outcol.b = max(a*col.b + b, 0.0);
+ outcol.r = max(a * col.r + b, 0.0);
+ outcol.g = max(a * col.g + b, 0.0);
+ outcol.b = max(a * col.b + b, 0.0);
outcol.a = col.a;
}
@@ -528,7 +586,7 @@ void mix_screen(float fac, vec4 col1, vec4 col2, out vec4 outcol)
fac = clamp(fac, 0.0, 1.0);
float facm = 1.0 - fac;
- outcol = vec4(1.0) - (vec4(facm) + fac*(vec4(1.0) - col2))*(vec4(1.0) - col1);
+ outcol = vec4(1.0) - (vec4(facm) + fac * (vec4(1.0) - col2)) * (vec4(1.0) - col1);
outcol.a = col1.a;
}
@@ -539,20 +597,20 @@ void mix_overlay(float fac, vec4 col1, vec4 col2, out vec4 outcol)
outcol = col1;
- if(outcol.r < 0.5)
- outcol.r *= facm + 2.0*fac*col2.r;
+ if (outcol.r < 0.5)
+ outcol.r *= facm + 2.0 * fac * col2.r;
else
- outcol.r = 1.0 - (facm + 2.0*fac*(1.0 - col2.r))*(1.0 - outcol.r);
+ outcol.r = 1.0 - (facm + 2.0 * fac * (1.0 - col2.r)) * (1.0 - outcol.r);
- if(outcol.g < 0.5)
- outcol.g *= facm + 2.0*fac*col2.g;
+ if (outcol.g < 0.5)
+ outcol.g *= facm + 2.0 * fac * col2.g;
else
- outcol.g = 1.0 - (facm + 2.0*fac*(1.0 - col2.g))*(1.0 - outcol.g);
+ outcol.g = 1.0 - (facm + 2.0 * fac * (1.0 - col2.g)) * (1.0 - outcol.g);
- if(outcol.b < 0.5)
- outcol.b *= facm + 2.0*fac*col2.b;
+ if (outcol.b < 0.5)
+ outcol.b *= facm + 2.0 * fac * col2.b;
else
- outcol.b = 1.0 - (facm + 2.0*fac*(1.0 - col2.b))*(1.0 - outcol.b);
+ outcol.b = 1.0 - (facm + 2.0 * fac * (1.0 - col2.b)) * (1.0 - outcol.b);
}
void mix_sub(float fac, vec4 col1, vec4 col2, out vec4 outcol)
@@ -569,9 +627,9 @@ void mix_div(float fac, vec4 col1, vec4 col2, out vec4 outcol)
outcol = col1;
- if(col2.r != 0.0) outcol.r = facm*outcol.r + fac*outcol.r/col2.r;
- if(col2.g != 0.0) outcol.g = facm*outcol.g + fac*outcol.g/col2.g;
- if(col2.b != 0.0) outcol.b = facm*outcol.b + fac*outcol.b/col2.b;
+ if (col2.r != 0.0) outcol.r = facm * outcol.r + fac * outcol.r / col2.r;
+ if (col2.g != 0.0) outcol.g = facm * outcol.g + fac * outcol.g / col2.g;
+ if (col2.b != 0.0) outcol.b = facm * outcol.b + fac * outcol.b / col2.b;
}
void mix_diff(float fac, vec4 col1, vec4 col2, out vec4 outcol)
@@ -584,14 +642,14 @@ void mix_diff(float fac, vec4 col1, vec4 col2, out vec4 outcol)
void mix_dark(float fac, vec4 col1, vec4 col2, out vec4 outcol)
{
fac = clamp(fac, 0.0, 1.0);
- outcol.rgb = min(col1.rgb, col2.rgb*fac);
+ outcol.rgb = min(col1.rgb, col2.rgb * fac);
outcol.a = col1.a;
}
void mix_light(float fac, vec4 col1, vec4 col2, out vec4 outcol)
{
fac = clamp(fac, 0.0, 1.0);
- outcol.rgb = max(col1.rgb, col2.rgb*fac);
+ outcol.rgb = max(col1.rgb, col2.rgb * fac);
outcol.a = col1.a;
}
@@ -600,29 +658,29 @@ void mix_dodge(float fac, vec4 col1, vec4 col2, out vec4 outcol)
fac = clamp(fac, 0.0, 1.0);
outcol = col1;
- if(outcol.r != 0.0) {
- float tmp = 1.0 - fac*col2.r;
- if(tmp <= 0.0)
+ if (outcol.r != 0.0) {
+ float tmp = 1.0 - fac * col2.r;
+ if (tmp <= 0.0)
outcol.r = 1.0;
- else if((tmp = outcol.r/tmp) > 1.0)
+ else if ((tmp = outcol.r / tmp) > 1.0)
outcol.r = 1.0;
else
outcol.r = tmp;
}
- if(outcol.g != 0.0) {
- float tmp = 1.0 - fac*col2.g;
- if(tmp <= 0.0)
+ if (outcol.g != 0.0) {
+ float tmp = 1.0 - fac * col2.g;
+ if (tmp <= 0.0)
outcol.g = 1.0;
- else if((tmp = outcol.g/tmp) > 1.0)
+ else if ((tmp = outcol.g / tmp) > 1.0)
outcol.g = 1.0;
else
outcol.g = tmp;
}
- if(outcol.b != 0.0) {
- float tmp = 1.0 - fac*col2.b;
- if(tmp <= 0.0)
+ if (outcol.b != 0.0) {
+ float tmp = 1.0 - fac * col2.b;
+ if (tmp <= 0.0)
outcol.b = 1.0;
- else if((tmp = outcol.b/tmp) > 1.0)
+ else if ((tmp = outcol.b / tmp) > 1.0)
outcol.b = 1.0;
else
outcol.b = tmp;
@@ -636,32 +694,32 @@ void mix_burn(float fac, vec4 col1, vec4 col2, out vec4 outcol)
outcol = col1;
- tmp = facm + fac*col2.r;
- if(tmp <= 0.0)
+ tmp = facm + fac * col2.r;
+ if (tmp <= 0.0)
outcol.r = 0.0;
- else if((tmp = (1.0 - (1.0 - outcol.r)/tmp)) < 0.0)
+ else if ((tmp = (1.0 - (1.0 - outcol.r) / tmp)) < 0.0)
outcol.r = 0.0;
- else if(tmp > 1.0)
+ else if (tmp > 1.0)
outcol.r = 1.0;
else
outcol.r = tmp;
- tmp = facm + fac*col2.g;
- if(tmp <= 0.0)
+ tmp = facm + fac * col2.g;
+ if (tmp <= 0.0)
outcol.g = 0.0;
- else if((tmp = (1.0 - (1.0 - outcol.g)/tmp)) < 0.0)
+ else if ((tmp = (1.0 - (1.0 - outcol.g) / tmp)) < 0.0)
outcol.g = 0.0;
- else if(tmp > 1.0)
+ else if (tmp > 1.0)
outcol.g = 1.0;
else
outcol.g = tmp;
- tmp = facm + fac*col2.b;
- if(tmp <= 0.0)
+ tmp = facm + fac * col2.b;
+ if (tmp <= 0.0)
outcol.b = 0.0;
- else if((tmp = (1.0 - (1.0 - outcol.b)/tmp)) < 0.0)
+ else if ((tmp = (1.0 - (1.0 - outcol.b) / tmp)) < 0.0)
outcol.b = 0.0;
- else if(tmp > 1.0)
+ else if (tmp > 1.0)
outcol.b = 1.0;
else
outcol.b = tmp;
@@ -677,10 +735,10 @@ void mix_hue(float fac, vec4 col1, vec4 col2, out vec4 outcol)
vec4 hsv, hsv2, tmp;
rgb_to_hsv(col2, hsv2);
- if(hsv2.y != 0.0) {
+ if (hsv2.y != 0.0) {
rgb_to_hsv(outcol, hsv);
hsv.x = hsv2.x;
- hsv_to_rgb(hsv, tmp);
+ hsv_to_rgb(hsv, tmp);
outcol = mix(outcol, tmp, fac);
outcol.a = col1.a;
@@ -697,10 +755,10 @@ void mix_sat(float fac, vec4 col1, vec4 col2, out vec4 outcol)
vec4 hsv, hsv2;
rgb_to_hsv(outcol, hsv);
- if(hsv.y != 0.0) {
+ if (hsv.y != 0.0) {
rgb_to_hsv(col2, hsv2);
- hsv.y = facm*hsv.y + fac*hsv2.y;
+ hsv.y = facm * hsv.y + fac * hsv2.y;
hsv_to_rgb(hsv, outcol);
}
}
@@ -714,7 +772,7 @@ void mix_val(float fac, vec4 col1, vec4 col2, out vec4 outcol)
rgb_to_hsv(col1, hsv);
rgb_to_hsv(col2, hsv2);
- hsv.z = facm*hsv.z + fac*hsv2.z;
+ hsv.z = facm * hsv.z + fac * hsv2.z;
hsv_to_rgb(hsv, outcol);
}
@@ -728,11 +786,11 @@ void mix_color(float fac, vec4 col1, vec4 col2, out vec4 outcol)
vec4 hsv, hsv2, tmp;
rgb_to_hsv(col2, hsv2);
- if(hsv2.y != 0.0) {
+ if (hsv2.y != 0.0) {
rgb_to_hsv(outcol, hsv);
hsv.x = hsv2.x;
hsv.y = hsv2.y;
- hsv_to_rgb(hsv, tmp);
+ hsv_to_rgb(hsv, tmp);
outcol = mix(outcol, tmp, fac);
outcol.a = col1.a;
@@ -744,16 +802,16 @@ void mix_soft(float fac, vec4 col1, vec4 col2, out vec4 outcol)
fac = clamp(fac, 0.0, 1.0);
float facm = 1.0 - fac;
- vec4 one= vec4(1.0);
- vec4 scr= one - (one - col2)*(one - col1);
- outcol = facm*col1 + fac*((one - col1)*col2*col1 + col1*scr);
+ vec4 one = vec4(1.0);
+ vec4 scr = one - (one - col2) * (one - col1);
+ outcol = facm * col1 + fac * ((one - col1) * col2 * col1 + col1 * scr);
}
void mix_linear(float fac, vec4 col1, vec4 col2, out vec4 outcol)
{
fac = clamp(fac, 0.0, 1.0);
- outcol = col1 + fac*(2.0*(col2 - vec4(0.5)));
+ outcol = col1 + fac * (2.0 * (col2 - vec4(0.5)));
}
void valtorgb(float fac, sampler2D colormap, out vec4 outcol, out float outalpha)
@@ -762,12 +820,12 @@ void valtorgb(float fac, sampler2D colormap, out vec4 outcol, out float outalpha
outalpha = outcol.a;
}
-void rgbtobw(vec4 color, out float outval)
+void rgbtobw(vec4 color, out float outval)
{
#ifdef USE_NEW_SHADING
- outval = color.r*0.2126 + color.g*0.7152 + color.b*0.0722;
+ outval = color.r * 0.2126 + color.g * 0.7152 + color.b * 0.0722;
#else
- outval = color.r*0.35 + color.g*0.45 + color.b*0.2; /* keep these factors in sync with texture.h:RGBTOBW */
+ outval = color.r * 0.35 + color.g * 0.45 + color.b * 0.2; /* keep these factors in sync with texture.h:RGBTOBW */
#endif
}
@@ -794,11 +852,11 @@ void hue_sat(float hue, float sat, float value, float fac, vec4 col, out vec4 ou
rgb_to_hsv(col, hsv);
hsv[0] += (hue - 0.5);
- if(hsv[0]>1.0) hsv[0]-=1.0; else if(hsv[0]<0.0) hsv[0]+= 1.0;
+ if (hsv[0] > 1.0) hsv[0] -= 1.0; else if (hsv[0] < 0.0) hsv[0] += 1.0;
hsv[1] *= sat;
- if(hsv[1]>1.0) hsv[1]= 1.0; else if(hsv[1]<0.0) hsv[1]= 0.0;
+ if (hsv[1] > 1.0) hsv[1] = 1.0; else if (hsv[1] < 0.0) hsv[1] = 0.0;
hsv[2] *= value;
- if(hsv[2]>1.0) hsv[2]= 1.0; else if(hsv[2]<0.0) hsv[2]= 0.0;
+ if (hsv[2] > 1.0) hsv[2] = 1.0; else if (hsv[2] < 0.0) hsv[2] = 0.0;
hsv_to_rgb(hsv, outcol);
@@ -858,19 +916,19 @@ void texture_flip_blend(vec3 vec, out vec3 outvec)
void texture_blend_lin(vec3 vec, out float outval)
{
- outval = (1.0+vec.x)/2.0;
+ outval = (1.0 + vec.x) / 2.0;
}
void texture_blend_quad(vec3 vec, out float outval)
{
- outval = max((1.0+vec.x)/2.0, 0.0);
+ outval = max((1.0 + vec.x) / 2.0, 0.0);
outval *= outval;
}
void texture_wood_sin(vec3 vec, out float value, out vec4 color, out vec3 normal)
{
- float a = sqrt(vec.x*vec.x + vec.y*vec.y + vec.z*vec.z)*20.0;
- float wi = 0.5 + 0.5*sin(a);
+ float a = sqrt(vec.x * vec.x + vec.y * vec.y + vec.z * vec.z) * 20.0;
+ float wi = 0.5 + 0.5 * sin(a);
value = wi;
color = vec4(wi, wi, wi, 1.0);
@@ -879,12 +937,12 @@ void texture_wood_sin(vec3 vec, out float value, out vec4 color, out vec3 normal
void texture_image(vec3 vec, sampler2D ima, out float value, out vec4 color, out vec3 normal)
{
- color = texture2D(ima, (vec.xy + vec2(1.0, 1.0))*0.5);
+ color = texture2D(ima, (vec.xy + vec2(1.0, 1.0)) * 0.5);
value = color.a;
- normal.x = 2.0*(color.r - 0.5);
- normal.y = 2.0*(0.5 - color.g);
- normal.z = 2.0*(color.b - 0.5);
+ normal.x = 2.0 * (color.r - 0.5);
+ normal.y = 2.0 * (0.5 - color.g);
+ normal.z = 2.0 * (color.b - 0.5);
}
/************* MTEX *****************/
@@ -915,17 +973,17 @@ void texco_tangent(vec4 tangent, out vec3 outtangent)
void texco_global(mat4 viewinvmat, vec3 co, out vec3 global)
{
- global = (viewinvmat*vec4(co, 1.0)).xyz;
+ global = (viewinvmat * vec4(co, 1.0)).xyz;
}
void texco_object(mat4 viewinvmat, mat4 obinvmat, vec3 co, out vec3 object)
{
- object = (obinvmat*(viewinvmat*vec4(co, 1.0))).xyz;
+ object = (obinvmat * (viewinvmat * vec4(co, 1.0))).xyz;
}
void texco_refl(vec3 vn, vec3 view, out vec3 ref)
{
- ref = view - 2.0*dot(vn, view)*vn;
+ ref = view - 2.0 * dot(vn, view) * vn;
}
void shade_norm(vec3 normal, out vec3 outnormal)
@@ -936,7 +994,7 @@ void shade_norm(vec3 normal, out vec3 outnormal)
void mtex_mirror(vec3 tcol, vec4 refcol, float tin, float colmirfac, out vec4 outrefcol)
{
- outrefcol = mix(refcol, vec4(1.0, tcol), tin*colmirfac);
+ outrefcol = mix(refcol, vec4(1.0, tcol), tin * colmirfac);
}
void mtex_rgb_blend(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
@@ -944,9 +1002,9 @@ void mtex_rgb_blend(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 i
float facm;
fact *= facg;
- facm = 1.0-fact;
+ facm = 1.0 - fact;
- incol = fact*texcol + facm*outcol;
+ incol = fact * texcol + facm * outcol;
}
void mtex_rgb_mul(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
@@ -954,9 +1012,9 @@ void mtex_rgb_mul(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 inc
float facm;
fact *= facg;
- facm = 1.0-fact;
+ facm = 1.0 - fact;
- incol = (facm + fact*texcol)*outcol;
+ incol = (facm + fact * texcol) * outcol;
}
void mtex_rgb_screen(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
@@ -964,9 +1022,9 @@ void mtex_rgb_screen(vec3 outcol, vec3 texcol, float fact, float facg, out vec3
float facm;
fact *= facg;
- facm = 1.0-fact;
+ facm = 1.0 - fact;
- incol = vec3(1.0) - (vec3(facm) + fact*(vec3(1.0) - texcol))*(vec3(1.0) - outcol);
+ incol = vec3(1.0) - (vec3(facm) + fact * (vec3(1.0) - texcol)) * (vec3(1.0) - outcol);
}
void mtex_rgb_overlay(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
@@ -974,32 +1032,32 @@ void mtex_rgb_overlay(vec3 outcol, vec3 texcol, float fact, float facg, out vec3
float facm;
fact *= facg;
- facm = 1.0-fact;
+ facm = 1.0 - fact;
- if(outcol.r < 0.5)
- incol.r = outcol.r*(facm + 2.0*fact*texcol.r);
+ if (outcol.r < 0.5)
+ incol.r = outcol.r * (facm + 2.0 * fact * texcol.r);
else
- incol.r = 1.0 - (facm + 2.0*fact*(1.0 - texcol.r))*(1.0 - outcol.r);
+ incol.r = 1.0 - (facm + 2.0 * fact * (1.0 - texcol.r)) * (1.0 - outcol.r);
- if(outcol.g < 0.5)
- incol.g = outcol.g*(facm + 2.0*fact*texcol.g);
+ if (outcol.g < 0.5)
+ incol.g = outcol.g * (facm + 2.0 * fact * texcol.g);
else
- incol.g = 1.0 - (facm + 2.0*fact*(1.0 - texcol.g))*(1.0 - outcol.g);
+ incol.g = 1.0 - (facm + 2.0 * fact * (1.0 - texcol.g)) * (1.0 - outcol.g);
- if(outcol.b < 0.5)
- incol.b = outcol.b*(facm + 2.0*fact*texcol.b);
+ if (outcol.b < 0.5)
+ incol.b = outcol.b * (facm + 2.0 * fact * texcol.b);
else
- incol.b = 1.0 - (facm + 2.0*fact*(1.0 - texcol.b))*(1.0 - outcol.b);
+ incol.b = 1.0 - (facm + 2.0 * fact * (1.0 - texcol.b)) * (1.0 - outcol.b);
}
void mtex_rgb_sub(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
{
- incol = -fact*facg*texcol + outcol;
+ incol = -fact * facg * texcol + outcol;
}
void mtex_rgb_add(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
{
- incol = fact*facg*texcol + outcol;
+ incol = fact * facg * texcol + outcol;
}
void mtex_rgb_div(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
@@ -1007,11 +1065,11 @@ void mtex_rgb_div(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 inc
float facm;
fact *= facg;
- facm = 1.0-fact;
+ facm = 1.0 - fact;
- if(texcol.r != 0.0) incol.r = facm*outcol.r + fact*outcol.r/texcol.r;
- if(texcol.g != 0.0) incol.g = facm*outcol.g + fact*outcol.g/texcol.g;
- if(texcol.b != 0.0) incol.b = facm*outcol.b + fact*outcol.b/texcol.b;
+ if (texcol.r != 0.0) incol.r = facm * outcol.r + fact * outcol.r / texcol.r;
+ if (texcol.g != 0.0) incol.g = facm * outcol.g + fact * outcol.g / texcol.g;
+ if (texcol.b != 0.0) incol.b = facm * outcol.b + fact * outcol.b / texcol.b;
}
void mtex_rgb_diff(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
@@ -1019,9 +1077,9 @@ void mtex_rgb_diff(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 in
float facm;
fact *= facg;
- facm = 1.0-fact;
+ facm = 1.0 - fact;
- incol = facm*outcol + fact*abs(texcol - outcol);
+ incol = facm * outcol + fact * abs(texcol - outcol);
}
void mtex_rgb_dark(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
@@ -1029,7 +1087,7 @@ void mtex_rgb_dark(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 in
float facm, col;
fact *= facg;
- facm = 1.0-fact;
+ facm = 1.0 - fact;
incol.r = min(outcol.r, texcol.r) * fact + outcol.r * facm;
incol.g = min(outcol.g, texcol.g) * fact + outcol.g * facm;
@@ -1042,19 +1100,19 @@ void mtex_rgb_light(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 i
fact *= facg;
- col = fact*texcol.r;
- if(col > outcol.r) incol.r = col; else incol.r = outcol.r;
- col = fact*texcol.g;
- if(col > outcol.g) incol.g = col; else incol.g = outcol.g;
- col = fact*texcol.b;
- if(col > outcol.b) incol.b = col; else incol.b = outcol.b;
+ col = fact * texcol.r;
+ if (col > outcol.r) incol.r = col; else incol.r = outcol.r;
+ col = fact * texcol.g;
+ if (col > outcol.g) incol.g = col; else incol.g = outcol.g;
+ col = fact * texcol.b;
+ if (col > outcol.b) incol.b = col; else incol.b = outcol.b;
}
void mtex_rgb_hue(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
{
vec4 col;
- mix_hue(fact*facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
+ mix_hue(fact * facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
incol.rgb = col.rgb;
}
@@ -1062,7 +1120,7 @@ void mtex_rgb_sat(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 inc
{
vec4 col;
- mix_sat(fact*facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
+ mix_sat(fact * facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
incol.rgb = col.rgb;
}
@@ -1070,7 +1128,7 @@ void mtex_rgb_val(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 inc
{
vec4 col;
- mix_val(fact*facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
+ mix_val(fact * facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
incol.rgb = col.rgb;
}
@@ -1078,48 +1136,44 @@ void mtex_rgb_color(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 i
{
vec4 col;
- mix_color(fact*facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
+ mix_color(fact * facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
incol.rgb = col.rgb;
}
void mtex_rgb_soft(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
{
- float facm;
-
- fact *= facg;
- facm = 1.0-fact;
+ vec4 col;
- vec3 one = vec3(1.0);
- vec3 scr = one - (one - texcol)*(one - outcol);
- incol = facm*outcol + fact*((one - texcol)*outcol*texcol + outcol*scr);
+ mix_soft(fact * facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
+ incol.rgb = col.rgb;
}
void mtex_rgb_linear(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
{
fact *= facg;
- if(texcol.r > 0.5)
- incol.r = outcol.r + fact*(2.0*(texcol.r - 0.5));
+ if (texcol.r > 0.5)
+ incol.r = outcol.r + fact * (2.0 * (texcol.r - 0.5));
else
- incol.r = outcol.r + fact*(2.0*(texcol.r) - 1.0);
+ incol.r = outcol.r + fact * (2.0 * (texcol.r) - 1.0);
- if(texcol.g > 0.5)
- incol.g = outcol.g + fact*(2.0*(texcol.g - 0.5));
+ if (texcol.g > 0.5)
+ incol.g = outcol.g + fact * (2.0 * (texcol.g - 0.5));
else
- incol.g = outcol.g + fact*(2.0*(texcol.g) - 1.0);
+ incol.g = outcol.g + fact * (2.0 * (texcol.g) - 1.0);
- if(texcol.b > 0.5)
- incol.b = outcol.b + fact*(2.0*(texcol.b - 0.5));
+ if (texcol.b > 0.5)
+ incol.b = outcol.b + fact * (2.0 * (texcol.b - 0.5));
else
- incol.b = outcol.b + fact*(2.0*(texcol.b) - 1.0);
+ incol.b = outcol.b + fact * (2.0 * (texcol.b) - 1.0);
}
void mtex_value_vars(inout float fact, float facg, out float facm)
{
fact *= abs(facg);
- facm = 1.0-fact;
+ facm = 1.0 - fact;
- if(facg < 0.0) {
+ if (facg < 0.0) {
float tmp = fact;
fact = facm;
facm = tmp;
@@ -1131,7 +1185,7 @@ void mtex_value_blend(float outcol, float texcol, float fact, float facg, out fl
float facm;
mtex_value_vars(fact, facg, facm);
- incol = fact*texcol + facm*outcol;
+ incol = fact * texcol + facm * outcol;
}
void mtex_value_mul(float outcol, float texcol, float fact, float facg, out float incol)
@@ -1140,7 +1194,7 @@ void mtex_value_mul(float outcol, float texcol, float fact, float facg, out floa
mtex_value_vars(fact, facg, facm);
facm = 1.0 - facg;
- incol = (facm + fact*texcol)*outcol;
+ incol = (facm + fact * texcol) * outcol;
}
void mtex_value_screen(float outcol, float texcol, float fact, float facg, out float incol)
@@ -1149,7 +1203,7 @@ void mtex_value_screen(float outcol, float texcol, float fact, float facg, out f
mtex_value_vars(fact, facg, facm);
facm = 1.0 - facg;
- incol = 1.0 - (facm + fact*(1.0 - texcol))*(1.0 - outcol);
+ incol = 1.0 - (facm + fact * (1.0 - texcol)) * (1.0 - outcol);
}
void mtex_value_sub(float outcol, float texcol, float fact, float facg, out float incol)
@@ -1158,7 +1212,7 @@ void mtex_value_sub(float outcol, float texcol, float fact, float facg, out floa
mtex_value_vars(fact, facg, facm);
fact = -fact;
- incol = fact*texcol + outcol;
+ incol = fact * texcol + outcol;
}
void mtex_value_add(float outcol, float texcol, float fact, float facg, out float incol)
@@ -1167,7 +1221,7 @@ void mtex_value_add(float outcol, float texcol, float fact, float facg, out floa
mtex_value_vars(fact, facg, facm);
fact = fact;
- incol = fact*texcol + outcol;
+ incol = fact * texcol + outcol;
}
void mtex_value_div(float outcol, float texcol, float fact, float facg, out float incol)
@@ -1175,8 +1229,8 @@ void mtex_value_div(float outcol, float texcol, float fact, float facg, out floa
float facm;
mtex_value_vars(fact, facg, facm);
- if(texcol != 0.0)
- incol = facm*outcol + fact*outcol/texcol;
+ if (texcol != 0.0)
+ incol = facm * outcol + fact * outcol / texcol;
else
incol = 0.0;
}
@@ -1186,7 +1240,7 @@ void mtex_value_diff(float outcol, float texcol, float fact, float facg, out flo
float facm;
mtex_value_vars(fact, facg, facm);
- incol = facm*outcol + fact*abs(texcol - outcol);
+ incol = facm * outcol + fact * abs(texcol - outcol);
}
void mtex_value_dark(float outcol, float texcol, float fact, float facg, out float incol)
@@ -1194,7 +1248,7 @@ void mtex_value_dark(float outcol, float texcol, float fact, float facg, out flo
float facm;
mtex_value_vars(fact, facg, facm);
- incol = facm*outcol + fact*min(outcol, texcol);
+ incol = facm * outcol + fact * min(outcol, texcol);
}
void mtex_value_light(float outcol, float texcol, float fact, float facg, out float incol)
@@ -1202,8 +1256,8 @@ void mtex_value_light(float outcol, float texcol, float fact, float facg, out fl
float facm;
mtex_value_vars(fact, facg, facm);
- float col = fact*texcol;
- if(col > outcol) incol = col; else incol = outcol;
+ float col = fact * texcol;
+ if (col > outcol) incol = col; else incol = outcol;
}
void mtex_value_clamp_positive(float fac, out float outfac)
@@ -1218,15 +1272,15 @@ void mtex_value_clamp(float fac, out float outfac)
void mtex_har_divide(float har, out float outhar)
{
- outhar = har/128.0;
+ outhar = har / 128.0;
}
void mtex_har_multiply_clamp(float har, out float outhar)
{
har *= 128.0;
- if(har < 1.0) outhar = 1.0;
- else if(har > 511.0) outhar = 511.0;
+ if (har < 1.0) outhar = 1.0;
+ else if (har > 511.0) outhar = 511.0;
else outhar = har;
}
@@ -1242,7 +1296,7 @@ void mtex_alpha_to_col(vec4 col, float alpha, out vec4 outcol)
void mtex_alpha_multiply_value(vec4 col, float value, out vec4 outcol)
{
- outcol = vec4(col.rgb, col.a * value);
+ outcol = vec4(col.rgb, col.a * value);
}
void mtex_rgbtoint(vec4 rgb, out float intensity)
@@ -1263,15 +1317,15 @@ void mtex_rgb_invert(vec4 inrgb, out vec4 outrgb)
void mtex_value_stencil(float stencil, float intensity, out float outstencil, out float outintensity)
{
float fact = intensity;
- outintensity = intensity*stencil;
- outstencil = stencil*fact;
+ outintensity = intensity * stencil;
+ outstencil = stencil * fact;
}
void mtex_rgb_stencil(float stencil, vec4 rgb, out float outstencil, out vec4 outrgb)
{
float fact = rgb.a;
- outrgb = vec4(rgb.rgb, rgb.a*stencil);
- outstencil = stencil*fact;
+ outrgb = vec4(rgb.rgb, rgb.a * stencil);
+ outstencil = stencil * fact;
}
void mtex_mapping_ofs(vec3 texco, vec3 ofs, out vec3 outtexco)
@@ -1281,17 +1335,17 @@ void mtex_mapping_ofs(vec3 texco, vec3 ofs, out vec3 outtexco)
void mtex_mapping_size(vec3 texco, vec3 size, out vec3 outtexco)
{
- outtexco = size*texco;
+ outtexco = size * texco;
}
void mtex_2d_mapping(vec3 vec, out vec3 outvec)
{
- outvec = vec3(vec.xy*0.5 + vec2(0.5), vec.z);
+ outvec = vec3(vec.xy * 0.5 + vec2(0.5), vec.z);
}
vec3 mtex_2d_mapping(vec3 vec)
{
- return vec3(vec.xy*0.5 + vec2(0.5), vec.z);
+ return vec3(vec.xy * 0.5 + vec2(0.5), vec.z);
}
void mtex_cube_map(vec3 co, samplerCube ima, out float value, out vec4 color)
@@ -1300,7 +1354,16 @@ void mtex_cube_map(vec3 co, samplerCube ima, out float value, out vec4 color)
value = 1.0;
}
-void mtex_cube_map_refl(samplerCube ima, vec3 vp, vec3 vn, mat4 viewmatrixinverse, mat4 viewmatrix, out float value, out vec4 color)
+void mtex_cube_map_refl_from_refldir(
+ samplerCube ima, vec3 reflecteddirection, out float value, out vec4 color)
+{
+ color = textureCube(ima, reflecteddirection);
+ value = 1.0;
+}
+
+void mtex_cube_map_refl(
+ samplerCube ima, vec3 vp, vec3 vn, mat4 viewmatrixinverse, mat4 viewmatrix,
+ out float value, out vec4 color)
{
vec3 viewdirection = vec3(viewmatrixinverse * vec4(vp, 0.0));
vec3 normaldirection = normalize(vec3(vec4(vn, 0.0) * viewmatrix));
@@ -1323,10 +1386,10 @@ void mtex_normal(vec3 texco, sampler2D ima, out vec3 normal)
// the normal used points inward.
// Should this ever change this negate must be removed.
vec4 color = texture2D(ima, texco.xy);
- normal = 2.0*(vec3(-color.r, color.g, color.b) - vec3(-0.5, 0.5, 0.5));
+ normal = 2.0 * (vec3(-color.r, color.g, color.b) - vec3(-0.5, 0.5, 0.5));
}
-void mtex_bump_normals_init( vec3 vN, out vec3 vNorg, out vec3 vNacc, out float fPrevMagnitude )
+void mtex_bump_normals_init(vec3 vN, out vec3 vNorg, out vec3 vNacc, out float fPrevMagnitude)
{
vNorg = vN;
vNacc = vN;
@@ -1343,171 +1406,175 @@ mat3 to_mat3(mat4 m4)
return m3;
}
-void mtex_bump_init_objspace( vec3 surf_pos, vec3 surf_norm,
- mat4 mView, mat4 mViewInv, mat4 mObj, mat4 mObjInv,
- float fPrevMagnitude_in, vec3 vNacc_in,
- out float fPrevMagnitude_out, out vec3 vNacc_out,
- out vec3 vR1, out vec3 vR2, out float fDet )
+void mtex_bump_init_objspace(
+ vec3 surf_pos, vec3 surf_norm,
+ mat4 mView, mat4 mViewInv, mat4 mObj, mat4 mObjInv,
+ float fPrevMagnitude_in, vec3 vNacc_in,
+ out float fPrevMagnitude_out, out vec3 vNacc_out,
+ out vec3 vR1, out vec3 vR2, out float fDet)
{
mat3 obj2view = to_mat3(gl_ModelViewMatrix);
mat3 view2obj = to_mat3(gl_ModelViewMatrixInverse);
-
- vec3 vSigmaS = view2obj * dFdx( surf_pos );
- vec3 vSigmaT = view2obj * dFdy( surf_pos );
- vec3 vN = normalize( surf_norm * obj2view );
- vR1 = cross( vSigmaT, vN );
- vR2 = cross( vN, vSigmaS ) ;
- fDet = dot ( vSigmaS, vR1 );
-
+ vec3 vSigmaS = view2obj * dFdx(surf_pos);
+ vec3 vSigmaT = view2obj * dFdy(surf_pos);
+ vec3 vN = normalize(surf_norm * obj2view);
+
+ vR1 = cross(vSigmaT, vN);
+ vR2 = cross(vN, vSigmaS);
+ fDet = dot(vSigmaS, vR1);
+
/* pretransform vNacc (in mtex_bump_apply) using the inverse transposed */
vR1 = vR1 * view2obj;
vR2 = vR2 * view2obj;
vN = vN * view2obj;
-
+
float fMagnitude = abs(fDet) * length(vN);
vNacc_out = vNacc_in * (fMagnitude / fPrevMagnitude_in);
fPrevMagnitude_out = fMagnitude;
}
-void mtex_bump_init_texturespace( vec3 surf_pos, vec3 surf_norm,
- float fPrevMagnitude_in, vec3 vNacc_in,
- out float fPrevMagnitude_out, out vec3 vNacc_out,
- out vec3 vR1, out vec3 vR2, out float fDet )
+void mtex_bump_init_texturespace(
+ vec3 surf_pos, vec3 surf_norm,
+ float fPrevMagnitude_in, vec3 vNacc_in,
+ out float fPrevMagnitude_out, out vec3 vNacc_out,
+ out vec3 vR1, out vec3 vR2, out float fDet)
{
- vec3 vSigmaS = dFdx( surf_pos );
- vec3 vSigmaT = dFdy( surf_pos );
+ vec3 vSigmaS = dFdx(surf_pos);
+ vec3 vSigmaT = dFdy(surf_pos);
vec3 vN = surf_norm; /* normalized interpolated vertex normal */
-
- vR1 = normalize( cross( vSigmaT, vN ) );
- vR2 = normalize( cross( vN, vSigmaS ) );
- fDet = sign( dot(vSigmaS, vR1) );
-
+
+ vR1 = normalize(cross(vSigmaT, vN));
+ vR2 = normalize(cross(vN, vSigmaS));
+ fDet = sign(dot(vSigmaS, vR1));
+
float fMagnitude = abs(fDet);
vNacc_out = vNacc_in * (fMagnitude / fPrevMagnitude_in);
fPrevMagnitude_out = fMagnitude;
}
-void mtex_bump_init_viewspace( vec3 surf_pos, vec3 surf_norm,
- float fPrevMagnitude_in, vec3 vNacc_in,
- out float fPrevMagnitude_out, out vec3 vNacc_out,
- out vec3 vR1, out vec3 vR2, out float fDet )
+void mtex_bump_init_viewspace(
+ vec3 surf_pos, vec3 surf_norm,
+ float fPrevMagnitude_in, vec3 vNacc_in,
+ out float fPrevMagnitude_out, out vec3 vNacc_out,
+ out vec3 vR1, out vec3 vR2, out float fDet)
{
- vec3 vSigmaS = dFdx( surf_pos );
- vec3 vSigmaT = dFdy( surf_pos );
+ vec3 vSigmaS = dFdx(surf_pos);
+ vec3 vSigmaT = dFdy(surf_pos);
vec3 vN = surf_norm; /* normalized interpolated vertex normal */
-
- vR1 = cross( vSigmaT, vN );
- vR2 = cross( vN, vSigmaS ) ;
- fDet = dot ( vSigmaS, vR1 );
-
+
+ vR1 = cross(vSigmaT, vN);
+ vR2 = cross(vN, vSigmaS);
+ fDet = dot(vSigmaS, vR1);
+
float fMagnitude = abs(fDet);
vNacc_out = vNacc_in * (fMagnitude / fPrevMagnitude_in);
fPrevMagnitude_out = fMagnitude;
}
-void mtex_bump_tap3( vec3 texco, sampler2D ima, float hScale,
- out float dBs, out float dBt )
+void mtex_bump_tap3(
+ vec3 texco, sampler2D ima, float hScale,
+ out float dBs, out float dBt)
{
vec2 STll = texco.xy;
- vec2 STlr = texco.xy + dFdx(texco.xy) ;
- vec2 STul = texco.xy + dFdy(texco.xy) ;
-
- float Hll,Hlr,Hul;
- rgbtobw( texture2D(ima, STll), Hll );
- rgbtobw( texture2D(ima, STlr), Hlr );
- rgbtobw( texture2D(ima, STul), Hul );
-
+ vec2 STlr = texco.xy + dFdx(texco.xy);
+ vec2 STul = texco.xy + dFdy(texco.xy);
+
+ float Hll, Hlr, Hul;
+ rgbtobw(texture2D(ima, STll), Hll);
+ rgbtobw(texture2D(ima, STlr), Hlr);
+ rgbtobw(texture2D(ima, STul), Hul);
+
dBs = hScale * (Hlr - Hll);
dBt = hScale * (Hul - Hll);
}
#ifdef BUMP_BICUBIC
-void mtex_bump_bicubic( vec3 texco, sampler2D ima, float hScale,
- out float dBs, out float dBt )
+void mtex_bump_bicubic(
+ vec3 texco, sampler2D ima, float hScale,
+ out float dBs, out float dBt )
{
float Hl;
float Hr;
float Hd;
float Hu;
-
+
vec2 TexDx = dFdx(texco.xy);
vec2 TexDy = dFdy(texco.xy);
-
- vec2 STl = texco.xy - 0.5 * TexDx ;
- vec2 STr = texco.xy + 0.5 * TexDx ;
- vec2 STd = texco.xy - 0.5 * TexDy ;
- vec2 STu = texco.xy + 0.5 * TexDy ;
-
+
+ vec2 STl = texco.xy - 0.5 * TexDx;
+ vec2 STr = texco.xy + 0.5 * TexDx;
+ vec2 STd = texco.xy - 0.5 * TexDy;
+ vec2 STu = texco.xy + 0.5 * TexDy;
+
rgbtobw(texture2D(ima, STl), Hl);
rgbtobw(texture2D(ima, STr), Hr);
rgbtobw(texture2D(ima, STd), Hd);
rgbtobw(texture2D(ima, STu), Hu);
-
+
vec2 dHdxy = vec2(Hr - Hl, Hu - Hd);
- float fBlend = clamp(1.0-textureQueryLOD(ima, texco.xy).x, 0.0, 1.0);
- if(fBlend!=0.0)
- {
+ float fBlend = clamp(1.0 - textureQueryLOD(ima, texco.xy).x, 0.0, 1.0);
+ if (fBlend != 0.0) {
// the derivative of the bicubic sampling of level 0
ivec2 vDim;
vDim = textureSize(ima, 0);
// taking the fract part of the texture coordinate is a hardcoded wrap mode.
- // this is acceptable as textures use wrap mode exclusively in 3D view elsewhere in blender.
+ // this is acceptable as textures use wrap mode exclusively in 3D view elsewhere in blender.
// this is done so that we can still get a valid texel with uvs outside the 0,1 range
// by texelFetch below, as coordinates are clamped when using this function.
- vec2 fTexLoc = vDim*fract(texco.xy) - vec2(0.5, 0.5);
+ vec2 fTexLoc = vDim * fract(texco.xy) - vec2(0.5, 0.5);
ivec2 iTexLoc = ivec2(floor(fTexLoc));
- vec2 t = clamp(fTexLoc - iTexLoc, 0.0, 1.0); // sat just to be pedantic
+ vec2 t = clamp(fTexLoc - iTexLoc, 0.0, 1.0); // sat just to be pedantic
/*******************************************************************************************
* This block will replace the one below when one channel textures are properly supported. *
*******************************************************************************************
- vec4 vSamplesUL = textureGather(ima, (iTexLoc+ivec2(-1,-1) + vec2(0.5,0.5))/vDim );
- vec4 vSamplesUR = textureGather(ima, (iTexLoc+ivec2(1,-1) + vec2(0.5,0.5))/vDim );
- vec4 vSamplesLL = textureGather(ima, (iTexLoc+ivec2(-1,1) + vec2(0.5,0.5))/vDim );
- vec4 vSamplesLR = textureGather(ima, (iTexLoc+ivec2(1,1) + vec2(0.5,0.5))/vDim );
+ vec4 vSamplesUL = textureGather(ima, (iTexLoc+ivec2(-1,-1) + vec2(0.5,0.5))/vDim);
+ vec4 vSamplesUR = textureGather(ima, (iTexLoc+ivec2(1,-1) + vec2(0.5,0.5))/vDim);
+ vec4 vSamplesLL = textureGather(ima, (iTexLoc+ivec2(-1,1) + vec2(0.5,0.5))/vDim);
+ vec4 vSamplesLR = textureGather(ima, (iTexLoc+ivec2(1,1) + vec2(0.5,0.5))/vDim);
mat4 H = mat4(vSamplesUL.w, vSamplesUL.x, vSamplesLL.w, vSamplesLL.x,
- vSamplesUL.z, vSamplesUL.y, vSamplesLL.z, vSamplesLL.y,
- vSamplesUR.w, vSamplesUR.x, vSamplesLR.w, vSamplesLR.x,
- vSamplesUR.z, vSamplesUR.y, vSamplesLR.z, vSamplesLR.y);
-*/
+ vSamplesUL.z, vSamplesUL.y, vSamplesLL.z, vSamplesLL.y,
+ vSamplesUR.w, vSamplesUR.x, vSamplesLR.w, vSamplesLR.x,
+ vSamplesUR.z, vSamplesUR.y, vSamplesLR.z, vSamplesLR.y);
+ */
ivec2 iTexLocMod = iTexLoc + ivec2(-1, -1);
mat4 H;
-
- for(int i = 0; i < 4; i++) {
- for(int j = 0; j < 4; j++) {
- ivec2 iTexTmp = iTexLocMod + ivec2(i,j);
-
+
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ ivec2 iTexTmp = iTexLocMod + ivec2(i, j);
+
// wrap texture coordinates manually for texelFetch to work on uvs oitside the 0,1 range.
// this is guaranteed to work since we take the fractional part of the uv above.
- iTexTmp.x = (iTexTmp.x < 0)? iTexTmp.x + vDim.x : ((iTexTmp.x >= vDim.x)? iTexTmp.x - vDim.x : iTexTmp.x);
- iTexTmp.y = (iTexTmp.y < 0)? iTexTmp.y + vDim.y : ((iTexTmp.y >= vDim.y)? iTexTmp.y - vDim.y : iTexTmp.y);
+ iTexTmp.x = (iTexTmp.x < 0) ? iTexTmp.x + vDim.x : ((iTexTmp.x >= vDim.x) ? iTexTmp.x - vDim.x : iTexTmp.x);
+ iTexTmp.y = (iTexTmp.y < 0) ? iTexTmp.y + vDim.y : ((iTexTmp.y >= vDim.y) ? iTexTmp.y - vDim.y : iTexTmp.y);
rgbtobw(texelFetch(ima, iTexTmp, 0), H[i][j]);
}
}
-
+
float x = t.x, y = t.y;
float x2 = x * x, x3 = x2 * x, y2 = y * y, y3 = y2 * y;
- vec4 X = vec4(-0.5*(x3+x)+x2, 1.5*x3-2.5*x2+1, -1.5*x3+2*x2+0.5*x, 0.5*(x3-x2));
- vec4 Y = vec4(-0.5*(y3+y)+y2, 1.5*y3-2.5*y2+1, -1.5*y3+2*y2+0.5*y, 0.5*(y3-y2));
- vec4 dX = vec4(-1.5*x2+2*x-0.5, 4.5*x2-5*x, -4.5*x2+4*x+0.5, 1.5*x2-x);
- vec4 dY = vec4(-1.5*y2+2*y-0.5, 4.5*y2-5*y, -4.5*y2+4*y+0.5, 1.5*y2-y);
-
+ vec4 X = vec4(-0.5 * (x3 + x) + x2, 1.5 * x3 - 2.5 * x2 + 1, -1.5 * x3 + 2 * x2 + 0.5 * x, 0.5 * (x3 - x2));
+ vec4 Y = vec4(-0.5 * (y3 + y) + y2, 1.5 * y3 - 2.5 * y2 + 1, -1.5 * y3 + 2 * y2 + 0.5 * y, 0.5 * (y3 - y2));
+ vec4 dX = vec4(-1.5 * x2 + 2 * x - 0.5, 4.5 * x2 - 5 * x, -4.5 * x2 + 4 * x + 0.5, 1.5 * x2 - x);
+ vec4 dY = vec4(-1.5 * y2 + 2 * y - 0.5, 4.5 * y2 - 5 * y, -4.5 * y2 + 4 * y + 0.5, 1.5 * y2 - y);
+
// complete derivative in normalized coordinates (mul by vDim)
vec2 dHdST = vDim * vec2(dot(Y, H * dX), dot(dY, H * X));
// transform derivative to screen-space
- vec2 dHdxy_bicubic = vec2( dHdST.x * TexDx.x + dHdST.y * TexDx.y,
- dHdST.x * TexDy.x + dHdST.y * TexDy.y );
+ vec2 dHdxy_bicubic = vec2(dHdST.x * TexDx.x + dHdST.y * TexDx.y,
+ dHdST.x * TexDy.x + dHdST.y * TexDy.y);
// blend between the two
- dHdxy = dHdxy*(1-fBlend) + dHdxy_bicubic*fBlend;
+ dHdxy = dHdxy * (1 - fBlend) + dHdxy_bicubic * fBlend;
}
dBs = hScale * dHdxy.x;
@@ -1516,67 +1583,71 @@ void mtex_bump_bicubic( vec3 texco, sampler2D ima, float hScale,
#endif
-void mtex_bump_tap5( vec3 texco, sampler2D ima, float hScale,
- out float dBs, out float dBt )
+void mtex_bump_tap5(
+ vec3 texco, sampler2D ima, float hScale,
+ out float dBs, out float dBt)
{
vec2 TexDx = dFdx(texco.xy);
vec2 TexDy = dFdy(texco.xy);
vec2 STc = texco.xy;
- vec2 STl = texco.xy - 0.5 * TexDx ;
- vec2 STr = texco.xy + 0.5 * TexDx ;
- vec2 STd = texco.xy - 0.5 * TexDy ;
- vec2 STu = texco.xy + 0.5 * TexDy ;
-
- float Hc,Hl,Hr,Hd,Hu;
- rgbtobw( texture2D(ima, STc), Hc );
- rgbtobw( texture2D(ima, STl), Hl );
- rgbtobw( texture2D(ima, STr), Hr );
- rgbtobw( texture2D(ima, STd), Hd );
- rgbtobw( texture2D(ima, STu), Hu );
-
+ vec2 STl = texco.xy - 0.5 * TexDx;
+ vec2 STr = texco.xy + 0.5 * TexDx;
+ vec2 STd = texco.xy - 0.5 * TexDy;
+ vec2 STu = texco.xy + 0.5 * TexDy;
+
+ float Hc, Hl, Hr, Hd, Hu;
+ rgbtobw(texture2D(ima, STc), Hc);
+ rgbtobw(texture2D(ima, STl), Hl);
+ rgbtobw(texture2D(ima, STr), Hr);
+ rgbtobw(texture2D(ima, STd), Hd);
+ rgbtobw(texture2D(ima, STu), Hu);
+
dBs = hScale * (Hr - Hl);
dBt = hScale * (Hu - Hd);
}
-void mtex_bump_deriv( vec3 texco, sampler2D ima, float ima_x, float ima_y, float hScale,
- out float dBs, out float dBt )
+void mtex_bump_deriv(
+ vec3 texco, sampler2D ima, float ima_x, float ima_y, float hScale,
+ out float dBs, out float dBt)
{
- float s = 1.0; // negate this if flipped texture coordinate
+ float s = 1.0; // negate this if flipped texture coordinate
vec2 TexDx = dFdx(texco.xy);
vec2 TexDy = dFdy(texco.xy);
-
+
// this variant using a derivative map is described here
// http://mmikkelsen3d.blogspot.com/2011/07/derivative-maps.html
vec2 dim = vec2(ima_x, ima_y);
- vec2 dBduv = hScale*dim*(2.0*texture2D(ima, texco.xy).xy-1.0);
-
- dBs = dBduv.x*TexDx.x + s*dBduv.y*TexDx.y;
- dBt = dBduv.x*TexDy.x + s*dBduv.y*TexDy.y;
+ vec2 dBduv = hScale * dim * (2.0 * texture2D(ima, texco.xy).xy - 1.0);
+
+ dBs = dBduv.x * TexDx.x + s * dBduv.y * TexDx.y;
+ dBt = dBduv.x * TexDy.x + s * dBduv.y * TexDy.y;
}
-void mtex_bump_apply( float fDet, float dBs, float dBt, vec3 vR1, vec3 vR2, vec3 vNacc_in,
- out vec3 vNacc_out, out vec3 perturbed_norm )
+void mtex_bump_apply(
+ float fDet, float dBs, float dBt, vec3 vR1, vec3 vR2, vec3 vNacc_in,
+ out vec3 vNacc_out, out vec3 perturbed_norm)
{
- vec3 vSurfGrad = sign(fDet) * ( dBs * vR1 + dBt * vR2 );
-
+ vec3 vSurfGrad = sign(fDet) * (dBs * vR1 + dBt * vR2);
+
vNacc_out = vNacc_in - vSurfGrad;
- perturbed_norm = normalize( vNacc_out );
+ perturbed_norm = normalize(vNacc_out);
}
-void mtex_bump_apply_texspace( float fDet, float dBs, float dBt, vec3 vR1, vec3 vR2,
- sampler2D ima, vec3 texco, float ima_x, float ima_y, vec3 vNacc_in,
- out vec3 vNacc_out, out vec3 perturbed_norm )
+void mtex_bump_apply_texspace(
+ float fDet, float dBs, float dBt, vec3 vR1, vec3 vR2,
+ sampler2D ima, vec3 texco, float ima_x, float ima_y, vec3 vNacc_in,
+ out vec3 vNacc_out, out vec3 perturbed_norm)
{
vec2 TexDx = dFdx(texco.xy);
vec2 TexDy = dFdy(texco.xy);
- vec3 vSurfGrad = sign(fDet) * (
- dBs / length( vec2(ima_x*TexDx.x, ima_y*TexDx.y) ) * vR1 +
- dBt / length( vec2(ima_x*TexDy.x, ima_y*TexDy.y) ) * vR2 );
-
+ vec3 vSurfGrad = sign(fDet) * (
+ dBs / length(vec2(ima_x * TexDx.x, ima_y * TexDx.y)) * vR1 +
+ dBt / length(vec2(ima_x * TexDy.x, ima_y * TexDy.y)) * vR2);
+
vNacc_out = vNacc_in - vSurfGrad;
- perturbed_norm = normalize( vNacc_out );
+ perturbed_norm = normalize(vNacc_out);
}
void mtex_negate_texnormal(vec3 normal, out vec3 outnormal)
@@ -1588,13 +1659,13 @@ void mtex_nspace_tangent(vec4 tangent, vec3 normal, vec3 texnormal, out vec3 out
{
vec3 B = tangent.w * cross(normal, tangent.xyz);
- outnormal = texnormal.x*tangent.xyz + texnormal.y*B + texnormal.z*normal;
+ outnormal = texnormal.x * tangent.xyz + texnormal.y * B + texnormal.z * normal;
outnormal = normalize(outnormal);
}
void mtex_nspace_world(mat4 viewmat, vec3 texnormal, out vec3 outnormal)
{
- outnormal = normalize((viewmat*vec4(texnormal, 0.0)).xyz);
+ outnormal = normalize((viewmat * vec4(texnormal, 0.0)).xyz);
}
void mtex_nspace_object(vec3 texnormal, out vec3 outnormal)
@@ -1604,7 +1675,7 @@ void mtex_nspace_object(vec3 texnormal, out vec3 outnormal)
void mtex_blend_normal(float norfac, vec3 normal, vec3 newnormal, out vec3 outnormal)
{
- outnormal = (1.0 - norfac)*normal + norfac*newnormal;
+ outnormal = (1.0 - norfac) * normal + norfac * newnormal;
outnormal = normalize(outnormal);
}
@@ -1627,26 +1698,26 @@ void lamp_visibility_other(vec3 co, vec3 lampco, out vec3 lv, out float dist, ou
void lamp_falloff_invlinear(float lampdist, float dist, out float visifac)
{
- visifac = lampdist/(lampdist + dist);
+ visifac = lampdist / (lampdist + dist);
}
void lamp_falloff_invsquare(float lampdist, float dist, out float visifac)
{
- visifac = lampdist/(lampdist + dist*dist);
+ visifac = lampdist / (lampdist + dist * dist);
}
void lamp_falloff_sliders(float lampdist, float ld1, float ld2, float dist, out float visifac)
{
- float lampdistkw = lampdist*lampdist;
+ float lampdistkw = lampdist * lampdist;
- visifac = lampdist/(lampdist + ld1*dist);
- visifac *= lampdistkw/(lampdistkw + ld2*dist*dist);
+ visifac = lampdist / (lampdist + ld1 * dist);
+ visifac *= lampdistkw / (lampdistkw + ld2 * dist * dist);
}
void lamp_falloff_invcoefficients(float coeff_const, float coeff_lin, float coeff_quad, float dist, out float visifac)
{
vec3 coeff = vec3(coeff_const, coeff_lin, coeff_quad);
- vec3 d_coeff = vec3(1.0, dist, dist*dist);
+ vec3 d_coeff = vec3(1.0, dist, dist * dist);
float visifac_r = dot(coeff, d_coeff);
if (visifac_r > 0.0)
visifac = 1.0 / visifac_r;
@@ -1656,25 +1727,25 @@ void lamp_falloff_invcoefficients(float coeff_const, float coeff_lin, float coef
void lamp_falloff_curve(float lampdist, sampler2D curvemap, float dist, out float visifac)
{
- visifac = texture2D(curvemap, vec2(dist/lampdist, 0.0)).x;
+ visifac = texture2D(curvemap, vec2(dist / lampdist, 0.0)).x;
}
void lamp_visibility_sphere(float lampdist, float dist, float visifac, out float outvisifac)
{
- float t= lampdist - dist;
+ float t = lampdist - dist;
- outvisifac= visifac*max(t, 0.0)/lampdist;
+ outvisifac = visifac * max(t, 0.0) / lampdist;
}
void lamp_visibility_spot_square(vec3 lampvec, mat4 lampimat, vec2 scale, vec3 lv, out float inpr)
{
- if(dot(lv, lampvec) > 0.0) {
- vec3 lvrot = (lampimat*vec4(lv, 0.0)).xyz;
+ if (dot(lv, lampvec) > 0.0) {
+ vec3 lvrot = (lampimat * vec4(lv, 0.0)).xyz;
/* without clever non-uniform scale, we could do: */
// float x = max(abs(lvrot.x / lvrot.z), abs(lvrot.y / lvrot.z));
float x = max(abs((lvrot.x / scale.x) / lvrot.z), abs((lvrot.y / scale.y) / lvrot.z));
- inpr = 1.0/sqrt(1.0 + x*x);
+ inpr = 1.0 / sqrt(1.0 + x * x);
}
else
inpr = 0.0;
@@ -1701,23 +1772,23 @@ void lamp_visibility_spot(float spotsi, float spotbl, float inpr, float visifac,
{
float t = spotsi;
- if(inpr <= t) {
+ if (inpr <= t) {
outvisifac = 0.0;
}
else {
t = inpr - t;
/* soft area */
- if(spotbl != 0.0)
- inpr *= smoothstep(0.0, 1.0, t/spotbl);
+ if (spotbl != 0.0)
+ inpr *= smoothstep(0.0, 1.0, t / spotbl);
- outvisifac = visifac*inpr;
+ outvisifac = visifac * inpr;
}
}
void lamp_visibility_clamp(float visifac, out float outvisifac)
{
- outvisifac = (visifac < 0.001)? 0.0: visifac;
+ outvisifac = (visifac < 0.001) ? 0.0 : visifac;
}
void world_paper_view(vec3 vec, out vec3 outvec)
@@ -1757,7 +1828,7 @@ void world_blend(vec3 vec, out float blend)
void shade_view(vec3 co, out vec3 view)
{
/* handle perspective/orthographic */
- view = (gl_ProjectionMatrix[3][3] == 0.0)? normalize(co): vec3(0.0, 0.0, -1.0);
+ view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(co) : vec3(0.0, 0.0, -1.0);
}
void shade_tangent_v(vec3 lv, vec3 tang, out vec3 vn)
@@ -1780,14 +1851,14 @@ void shade_is_no_diffuse(out float is)
void shade_is_hemi(float inp, out float is)
{
- is = 0.5*inp + 0.5;
+ is = 0.5 * inp + 0.5;
}
float area_lamp_energy(mat4 area, vec3 co, vec3 vn)
{
vec3 vec[4], c[4];
float rad[4], fac;
-
+
vec[0] = normalize(co - area[0].xyz);
vec[1] = normalize(co - area[1].xyz);
vec[2] = normalize(co - area[2].xyz);
@@ -1803,26 +1874,28 @@ float area_lamp_energy(mat4 area, vec3 co, vec3 vn)
rad[2] = acos(dot(vec[2], vec[3]));
rad[3] = acos(dot(vec[3], vec[0]));
- fac= rad[0]*dot(vn, c[0]);
- fac+= rad[1]*dot(vn, c[1]);
- fac+= rad[2]*dot(vn, c[2]);
- fac+= rad[3]*dot(vn, c[3]);
+ fac = rad[0] * dot(vn, c[0]);
+ fac += rad[1] * dot(vn, c[1]);
+ fac += rad[2] * dot(vn, c[2]);
+ fac += rad[3] * dot(vn, c[3]);
return max(fac, 0.0);
}
-void shade_inp_area(vec3 position, vec3 lampco, vec3 lampvec, vec3 vn, mat4 area, float areasize, float k, out float inp)
+void shade_inp_area(
+ vec3 position, vec3 lampco, vec3 lampvec, vec3 vn, mat4 area, float areasize, float k,
+ out float inp)
{
vec3 co = position;
vec3 vec = co - lampco;
- if(dot(vec, lampvec) < 0.0) {
+ if (dot(vec, lampvec) < 0.0) {
inp = 0.0;
}
else {
float intens = area_lamp_energy(area, co, vn);
- inp = pow(intens*areasize, k);
+ inp = pow(intens * areasize, k);
}
}
@@ -1833,10 +1906,10 @@ void shade_diffuse_oren_nayer(float nl, vec3 n, vec3 l, vec3 v, float rough, out
float nv = max(dot(n, v), 0.0);
float realnl = dot(n, l);
- if(realnl < 0.0) {
+ if (realnl < 0.0) {
is = 0.0;
}
- else if(nl < 0.0) {
+ else if (nl < 0.0) {
is = 0.0;
}
else {
@@ -1844,14 +1917,14 @@ void shade_diffuse_oren_nayer(float nl, vec3 n, vec3 l, vec3 v, float rough, out
float Lit_A = acos(realnl);
float View_A = acos(nv);
- vec3 Lit_B = normalize(l - realnl*n);
- vec3 View_B = normalize(v - nv*n);
+ vec3 Lit_B = normalize(l - realnl * n);
+ vec3 View_B = normalize(v - nv * n);
float t = max(dot(Lit_B, View_B), 0.0);
float a, b;
- if(Lit_A > View_A) {
+ if (Lit_A > View_A) {
a = Lit_A;
b = View_A;
}
@@ -1860,11 +1933,11 @@ void shade_diffuse_oren_nayer(float nl, vec3 n, vec3 l, vec3 v, float rough, out
b = Lit_A;
}
- float A = 1.0 - (0.5*((rough*rough)/((rough*rough) + 0.33)));
- float B = 0.45*((rough*rough)/((rough*rough) + 0.09));
+ float A = 1.0 - (0.5 * ((rough * rough) / ((rough * rough) + 0.33)));
+ float B = 0.45 * ((rough * rough) / ((rough * rough) + 0.09));
b *= 0.95;
- is = nl*(A + (B * t * sin(a) * tan(b)));
+ is = nl * (A + (B * t * sin(a) * tan(b)));
}
}
@@ -1873,23 +1946,23 @@ void shade_diffuse_toon(vec3 n, vec3 l, vec3 v, float size, float tsmooth, out f
float rslt = dot(n, l);
float ang = acos(rslt);
- if(ang < size) is = 1.0;
- else if(ang > (size + tsmooth) || tsmooth == 0.0) is = 0.0;
- else is = 1.0 - ((ang - size)/tsmooth);
+ if (ang < size) is = 1.0;
+ else if (ang > (size + tsmooth) || tsmooth == 0.0) is = 0.0;
+ else is = 1.0 - ((ang - size) / tsmooth);
}
void shade_diffuse_minnaert(float nl, vec3 n, vec3 v, float darkness, out float is)
{
- if(nl <= 0.0) {
+ if (nl <= 0.0) {
is = 0.0;
}
else {
float nv = max(dot(n, v), 0.0);
- if(darkness <= 1.0)
- is = nl*pow(max(nv*nl, 0.1), darkness - 1.0);
+ if (darkness <= 1.0)
+ is = nl * pow(max(nv * nl, 0.1), darkness - 1.0);
else
- is = nl*pow(1.0001 - nv, darkness - 1.0);
+ is = nl * pow(1.0001 - nv, darkness - 1.0);
}
}
@@ -1898,18 +1971,18 @@ float fresnel_fac(vec3 view, vec3 vn, float grad, float fac)
float t1, t2;
float ffac;
- if(fac==0.0) {
+ if (fac == 0.0) {
ffac = 1.0;
}
else {
- t1= dot(view, vn);
- if(t1>0.0) t2= 1.0+t1;
- else t2= 1.0-t1;
+ t1 = dot(view, vn);
+ if (t1 > 0.0) t2 = 1.0 + t1;
+ else t2 = 1.0 - t1;
- t2= grad + (1.0-grad)*pow(t2, fac);
+ t2 = grad + (1.0 - grad) * pow(t2, fac);
- if(t2<0.0) ffac = 0.0;
- else if(t2>1.0) ffac = 1.0;
+ if (t2 < 0.0) ffac = 0.0;
+ else if (t2 > 1.0) ffac = 1.0;
else ffac = t2;
}
@@ -1923,18 +1996,18 @@ void shade_diffuse_fresnel(vec3 vn, vec3 lv, vec3 view, float fac_i, float fac,
void shade_cubic(float is, out float outis)
{
- if(is>0.0 && is<1.0)
- outis= smoothstep(0.0, 1.0, is);
+ if (is > 0.0 && is < 1.0)
+ outis = smoothstep(0.0, 1.0, is);
else
- outis= is;
+ outis = is;
}
void shade_visifac(float i, float visifac, float refl, out float outi)
{
- /*if(i > 0.0)*/
- outi = max(i*visifac*refl, 0.0);
+ /*if (i > 0.0)*/
+ outi = max(i * visifac * refl, 0.0);
/*else
- outi = i;*/
+ outi = i;*/
}
void shade_tangent_v_spec(vec3 tang, out vec3 vn)
@@ -1944,8 +2017,8 @@ void shade_tangent_v_spec(vec3 tang, out vec3 vn)
void shade_add_to_diffuse(float i, vec3 lampcol, vec3 col, out vec3 outcol)
{
- if(i > 0.0)
- outcol = i*lampcol*col;
+ if (i > 0.0)
+ outcol = i * lampcol * col;
else
outcol = vec3(0.0, 0.0, 0.0);
}
@@ -1956,9 +2029,9 @@ void shade_hemi_spec(vec3 vn, vec3 lv, vec3 view, float spec, float hard, float
lv = normalize(lv);
t = dot(vn, lv);
- t = 0.5*t + 0.5;
+ t = 0.5 * t + 0.5;
- t = visifac*spec*pow(t, hard);
+ t = visifac * spec * pow(t, hard);
}
void shade_phong_spec(vec3 n, vec3 l, vec3 v, float hard, out float specfac)
@@ -1974,61 +2047,63 @@ void shade_cooktorr_spec(vec3 n, vec3 l, vec3 v, float hard, out float specfac)
vec3 h = normalize(v + l);
float nh = dot(n, h);
- if(nh < 0.0) {
+ if (nh < 0.0) {
specfac = 0.0;
}
else {
float nv = max(dot(n, v), 0.0);
float i = pow(nh, hard);
- i = i/(0.1+nv);
+ i = i / (0.1 + nv);
specfac = i;
}
}
void shade_blinn_spec(vec3 n, vec3 l, vec3 v, float refrac, float spec_power, out float specfac)
{
- if(refrac < 1.0) {
+ if (refrac < 1.0) {
specfac = 0.0;
}
- else if(spec_power == 0.0) {
+ else if (spec_power == 0.0) {
specfac = 0.0;
}
else {
- if(spec_power<100.0)
- spec_power= sqrt(1.0/spec_power);
+ if (spec_power < 100.0)
+ spec_power = sqrt(1.0 / spec_power);
else
- spec_power= 10.0/spec_power;
+ spec_power = 10.0 / spec_power;
vec3 h = normalize(v + l);
float nh = dot(n, h);
- if(nh < 0.0) {
+ if (nh < 0.0) {
specfac = 0.0;
}
else {
float nv = max(dot(n, v), 0.01);
float nl = dot(n, l);
- if(nl <= 0.01) {
+ if (nl <= 0.01) {
specfac = 0.0;
}
else {
float vh = max(dot(v, h), 0.01);
float a = 1.0;
- float b = (2.0*nh*nv)/vh;
- float c = (2.0*nh*nl)/vh;
+ float b = (2.0 * nh * nv) / vh;
+ float c = (2.0 * nh * nl) / vh;
float g = 0.0;
- if(a < b && a < c) g = a;
- else if(b < a && b < c) g = b;
- else if(c < a && c < b) g = c;
+ if (a < b && a < c) g = a;
+ else if (b < a && b < c) g = b;
+ else if (c < a && c < b) g = c;
- float p = sqrt(((refrac * refrac)+(vh*vh)-1.0));
- float f = (((p-vh)*(p-vh))/((p+vh)*(p+vh)))*(1.0+((((vh*(p+vh))-1.0)*((vh*(p+vh))-1.0))/(((vh*(p-vh))+1.0)*((vh*(p-vh))+1.0))));
+ float p = sqrt(((refrac * refrac) + (vh * vh) - 1.0));
+ float f = ((((p - vh) * (p - vh)) / ((p + vh) * (p + vh))) *
+ (1.0 + ((((vh * (p + vh)) - 1.0) * ((vh * (p + vh)) - 1.0)) /
+ (((vh * (p - vh)) + 1.0) * ((vh * (p - vh)) + 1.0)))));
float ang = acos(nh);
- specfac = max(f*g*exp_blender((-(ang*ang)/(2.0*spec_power*spec_power))), 0.0);
+ specfac = max(f * g * exp_blender((-(ang * ang) / (2.0 * spec_power * spec_power))), 0.0);
}
}
}
@@ -2043,7 +2118,7 @@ void shade_wardiso_spec(vec3 n, vec3 l, vec3 v, float rms, out float specfac)
float angle = tan(acos(nh));
float alpha = max(rms, 0.001);
- specfac= nl * (1.0/(4.0*M_PI*alpha*alpha))*(exp_blender(-(angle*angle)/(alpha*alpha))/(sqrt(nv*nl)));
+ specfac = nl * (1.0 / (4.0 * M_PI * alpha * alpha)) * (exp_blender(-(angle * angle) / (alpha * alpha)) / (sqrt(nv * nl)));
}
void shade_toon_spec(vec3 n, vec3 l, vec3 v, float size, float tsmooth, out float specfac)
@@ -2052,31 +2127,31 @@ void shade_toon_spec(vec3 n, vec3 l, vec3 v, float size, float tsmooth, out floa
float rslt = dot(h, n);
float ang = acos(rslt);
- if(ang < size) rslt = 1.0;
- else if(ang >= (size + tsmooth) || tsmooth == 0.0) rslt = 0.0;
- else rslt = 1.0 - ((ang - size)/tsmooth);
+ if (ang < size) rslt = 1.0;
+ else if (ang >= (size + tsmooth) || tsmooth == 0.0) rslt = 0.0;
+ else rslt = 1.0 - ((ang - size) / tsmooth);
specfac = rslt;
}
void shade_spec_area_inp(float specfac, float inp, out float outspecfac)
{
- outspecfac = specfac*inp;
+ outspecfac = specfac * inp;
}
void shade_spec_t(float shadfac, float spec, float visifac, float specfac, out float t)
{
- t = shadfac*spec*visifac*specfac;
+ t = shadfac * spec * visifac * specfac;
}
void shade_add_spec(float t, vec3 lampcol, vec3 speccol, out vec3 outcol)
{
- outcol = t*lampcol*speccol;
+ outcol = t * lampcol * speccol;
}
void shade_add_mirror(vec3 mir, vec4 refcol, vec3 combined, out vec3 result)
{
- result = mir*refcol.gba + (vec3(1.0) - mir*refcol.rrr)*combined;
+ result = mir * refcol.gba + (vec3(1.0) - mir * refcol.rrr) * combined;
}
void alpha_spec_correction(vec3 spec, float spectra, float alpha, out float outalpha)
@@ -2097,7 +2172,7 @@ void shade_add(vec4 col1, vec4 col2, out vec4 outcol)
void shade_madd(vec4 col, vec4 col1, vec4 col2, out vec4 outcol)
{
- outcol = col + col1*col2;
+ outcol = col + col1 * col2;
}
void shade_add_clamped(vec4 col1, vec4 col2, out vec4 outcol)
@@ -2107,52 +2182,59 @@ void shade_add_clamped(vec4 col1, vec4 col2, out vec4 outcol)
void shade_madd_clamped(vec4 col, vec4 col1, vec4 col2, out vec4 outcol)
{
- outcol = col + max(col1*col2, vec4(0.0, 0.0, 0.0, 0.0));
+ outcol = col + max(col1 * col2, vec4(0.0, 0.0, 0.0, 0.0));
+}
+
+void env_apply(vec4 col, vec3 hor, vec3 zen, vec4 f, mat4 vm, vec3 vn, out vec4 outcol)
+{
+ vec3 vv = normalize(vm[2].xyz);
+ float skyfac = 0.5 * (1.0 + dot(vn, -vv));
+ outcol = col + f * vec4(mix(hor, zen, skyfac), 0);
}
void shade_maddf(vec4 col, float f, vec4 col1, out vec4 outcol)
{
- outcol = col + f*col1;
+ outcol = col + f * col1;
}
void shade_mul(vec4 col1, vec4 col2, out vec4 outcol)
{
- outcol = col1*col2;
+ outcol = col1 * col2;
}
void shade_mul_value(float fac, vec4 col, out vec4 outcol)
{
- outcol = col*fac;
+ outcol = col * fac;
}
void shade_mul_value_v3(float fac, vec3 col, out vec3 outcol)
{
- outcol = col*fac;
+ outcol = col * fac;
}
void shade_obcolor(vec4 col, vec4 obcol, out vec4 outcol)
{
- outcol = vec4(col.rgb*obcol.rgb, col.a);
+ outcol = vec4(col.rgb * obcol.rgb, col.a);
}
void ramp_rgbtobw(vec3 color, out float outval)
{
- outval = color.r*0.3 + color.g*0.58 + color.b*0.12;
+ outval = color.r * 0.3 + color.g * 0.58 + color.b * 0.12;
}
void shade_only_shadow(float i, float shadfac, float energy, vec3 shadcol, out vec3 outshadrgb)
{
- outshadrgb = i*energy*(1.0 - shadfac)*(vec3(1.0)-shadcol);
+ outshadrgb = i * energy * (1.0 - shadfac) * (vec3(1.0) - shadcol);
}
void shade_only_shadow_diffuse(vec3 shadrgb, vec3 rgb, vec4 diff, out vec4 outdiff)
{
- outdiff = diff - vec4(rgb*shadrgb, 0.0);
+ outdiff = diff - vec4(rgb * shadrgb, 0.0);
}
void shade_only_shadow_specular(vec3 shadrgb, vec3 specrgb, vec4 spec, out vec4 outspec)
{
- outspec = spec - vec4(specrgb*shadrgb, 0.0);
+ outspec = spec - vec4(specrgb * shadrgb, 0.0);
}
void shade_clamp_positive(vec4 col, out vec4 outcol)
@@ -2160,47 +2242,51 @@ void shade_clamp_positive(vec4 col, out vec4 outcol)
outcol = max(col, vec4(0.0));
}
-void test_shadowbuf(vec3 rco, sampler2DShadow shadowmap, mat4 shadowpersmat, float shadowbias, float inp, out float result)
+void test_shadowbuf(
+ vec3 rco, sampler2DShadow shadowmap, mat4 shadowpersmat, float shadowbias, float inp,
+ out float result)
{
- if(inp <= 0.0) {
+ if (inp <= 0.0) {
result = 0.0;
}
else {
- vec4 co = shadowpersmat*vec4(rco, 1.0);
+ vec4 co = shadowpersmat * vec4(rco, 1.0);
//float bias = (1.5 - inp*inp)*shadowbias;
- co.z -= shadowbias*co.w;
-
- if (co.w > 0.0 && co.x > 0.0 && co.x/co.w < 1.0 && co.y > 0.0 && co.y/co.w < 1.0)
+ co.z -= shadowbias * co.w;
+
+ if (co.w > 0.0 && co.x > 0.0 && co.x / co.w < 1.0 && co.y > 0.0 && co.y / co.w < 1.0)
result = shadow2DProj(shadowmap, co).x;
else
result = 1.0;
}
}
-void test_shadowbuf_vsm(vec3 rco, sampler2D shadowmap, mat4 shadowpersmat, float shadowbias, float bleedbias, float inp, out float result)
+void test_shadowbuf_vsm(
+ vec3 rco, sampler2D shadowmap, mat4 shadowpersmat, float shadowbias, float bleedbias, float inp,
+ out float result)
{
- if(inp <= 0.0) {
+ if (inp <= 0.0) {
result = 0.0;
}
else {
- vec4 co = shadowpersmat*vec4(rco, 1.0);
- if (co.w > 0.0 && co.x > 0.0 && co.x/co.w < 1.0 && co.y > 0.0 && co.y/co.w < 1.0) {
+ vec4 co = shadowpersmat * vec4(rco, 1.0);
+ if (co.w > 0.0 && co.x > 0.0 && co.x / co.w < 1.0 && co.y > 0.0 && co.y / co.w < 1.0) {
vec2 moments = texture2DProj(shadowmap, co).rg;
- float dist = co.z/co.w;
+ float dist = co.z / co.w;
float p = 0.0;
-
- if(dist <= moments.x)
+
+ if (dist <= moments.x)
p = 1.0;
- float variance = moments.y - (moments.x*moments.x);
- variance = max(variance, shadowbias/10.0);
+ float variance = moments.y - (moments.x * moments.x);
+ variance = max(variance, shadowbias / 10.0);
float d = moments.x - dist;
- float p_max = variance / (variance + d*d);
+ float p_max = variance / (variance + d * d);
// Now reduce light-bleeding by removing the [0, x] tail and linearly rescaling (x, 1]
- p_max = clamp((p_max-bleedbias)/(1.0-bleedbias), 0.0, 1.0);
+ p_max = clamp((p_max - bleedbias) / (1.0 - bleedbias), 0.0, 1.0);
result = max(p, p_max);
}
@@ -2210,11 +2296,14 @@ void test_shadowbuf_vsm(vec3 rco, sampler2D shadowmap, mat4 shadowpersmat, float
}
}
-void shadows_only(vec3 rco, sampler2DShadow shadowmap, mat4 shadowpersmat, float shadowbias, vec3 shadowcolor, float inp, out vec3 result)
+void shadows_only(
+ vec3 rco, sampler2DShadow shadowmap, mat4 shadowpersmat,
+ float shadowbias, vec3 shadowcolor, float inp,
+ out vec3 result)
{
result = vec3(1.0);
- if(inp > 0.0) {
+ if (inp > 0.0) {
float shadfac;
test_shadowbuf(rco, shadowmap, shadowpersmat, shadowbias, inp, shadfac);
@@ -2222,11 +2311,14 @@ void shadows_only(vec3 rco, sampler2DShadow shadowmap, mat4 shadowpersmat, float
}
}
-void shadows_only_vsm(vec3 rco, sampler2D shadowmap, mat4 shadowpersmat, float shadowbias, float bleedbias, vec3 shadowcolor, float inp, out vec3 result)
+void shadows_only_vsm(
+ vec3 rco, sampler2D shadowmap, mat4 shadowpersmat,
+ float shadowbias, float bleedbias, vec3 shadowcolor, float inp,
+ out vec3 result)
{
result = vec3(1.0);
- if(inp > 0.0) {
+ if (inp > 0.0) {
float shadfac;
test_shadowbuf_vsm(rco, shadowmap, shadowpersmat, shadowbias, bleedbias, inp, shadfac);
@@ -2237,26 +2329,28 @@ void shadows_only_vsm(vec3 rco, sampler2D shadowmap, mat4 shadowpersmat, float s
void shade_light_texture(vec3 rco, sampler2D cookie, mat4 shadowpersmat, out vec4 result)
{
- vec4 co = shadowpersmat*vec4(rco, 1.0);
+ vec4 co = shadowpersmat * vec4(rco, 1.0);
result = texture2DProj(cookie, co);
}
void shade_exposure_correct(vec3 col, float linfac, float logfac, out vec3 outcol)
{
- outcol = linfac*(1.0 - exp(col*logfac));
+ outcol = linfac * (1.0 - exp(col * logfac));
}
-void shade_mist_factor(vec3 co, float enable, float miststa, float mistdist, float misttype, float misi, out float outfac)
+void shade_mist_factor(
+ vec3 co, float enable, float miststa, float mistdist, float misttype, float misi,
+ out float outfac)
{
- if(enable == 1.0) {
+ if (enable == 1.0) {
float fac, zcor;
- zcor = (gl_ProjectionMatrix[3][3] == 0.0)? length(co): -co[2];
-
+ zcor = (gl_ProjectionMatrix[3][3] == 0.0) ? length(co) : -co[2];
+
fac = clamp((zcor - miststa) / mistdist, 0.0, 1.0);
- if(misttype == 0.0) fac *= fac;
- else if(misttype == 1.0);
+ if (misttype == 0.0) fac *= fac;
+ else if (misttype == 1.0) ;
else fac = sqrt(fac);
outfac = 1.0 - (1.0 - fac) * (1.0 - misi);
@@ -2279,7 +2373,7 @@ void shade_alpha_opaque(vec4 col, out vec4 outcol)
void shade_alpha_obcolor(vec4 col, vec4 obcol, out vec4 outcol)
{
- outcol = vec4(col.rgb, col.a*obcol.a);
+ outcol = vec4(col.rgb, col.a * obcol.a);
}
/*********** NEW SHADER UTILITIES **************/
@@ -2292,11 +2386,11 @@ float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta)
float g = eta * eta - 1.0 + c * c;
float result;
- if(g > 0.0) {
+ if (g > 0.0) {
g = sqrt(g);
- float A =(g - c)/(g + c);
- float B =(c *(g + c)- 1.0)/(c *(g - c)+ 1.0);
- result = 0.5 * A * A *(1.0 + B * B);
+ float A = (g - c) / (g + c);
+ float B = (c * (g + c) - 1.0) / (c * (g - c) + 1.0);
+ result = 0.5 * A * A * (1.0 + B * B);
}
else {
result = 1.0; /* TIR (no refracted component) */
@@ -2307,7 +2401,95 @@ float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta)
float hypot(float x, float y)
{
- return sqrt(x*x + y*y);
+ return sqrt(x * x + y * y);
+}
+
+void generated_from_orco(vec3 orco, out vec3 generated)
+{
+ generated = orco * 0.5 + vec3(0.5);
+}
+
+int floor_to_int(float x)
+{
+ return int(floor(x));
+}
+
+int quick_floor(float x)
+{
+ return int(x) - ((x < 0) ? 1 : 0);
+}
+
+#ifdef BIT_OPERATIONS
+float integer_noise(int n)
+{
+ int nn;
+ n = (n + 1013) & 0x7fffffff;
+ n = (n >> 13) ^ n;
+ nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
+ return 0.5 * (float(nn) / 1073741824.0);
+}
+
+uint hash(uint kx, uint ky, uint kz)
+{
+#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
+#define final(a, b, c) \
+{ \
+ c ^= b; c -= rot(b, 14); \
+ a ^= c; a -= rot(c, 11); \
+ b ^= a; b -= rot(a, 25); \
+ c ^= b; c -= rot(b, 16); \
+ a ^= c; a -= rot(c, 4); \
+ b ^= a; b -= rot(a, 14); \
+ c ^= b; c -= rot(b, 24); \
+}
+ // now hash the data!
+ uint a, b, c, len = 3u;
+ a = b = c = 0xdeadbeefu + (len << 2u) + 13u;
+
+ c += kz;
+ b += ky;
+ a += kx;
+ final (a, b, c);
+
+ return c;
+#undef rot
+#undef final
+}
+
+uint hash(int kx, int ky, int kz)
+{
+ return hash(uint(kx), uint(ky), uint(kz));
+}
+
+float bits_to_01(uint bits)
+{
+ float x = float(bits) * (1.0 / float(0xffffffffu));
+ return x;
+}
+
+float cellnoise(vec3 p)
+{
+ int ix = quick_floor(p.x);
+ int iy = quick_floor(p.y);
+ int iz = quick_floor(p.z);
+
+ return bits_to_01(hash(uint(ix), uint(iy), uint(iz)));
+}
+
+vec3 cellnoise_color(vec3 p)
+{
+ float r = cellnoise(p);
+ float g = cellnoise(vec3(p.y, p.x, p.z));
+ float b = cellnoise(vec3(p.y, p.z, p.x));
+
+ return vec3(r, g, b);
+}
+#endif // BIT_OPERATIONS
+
+float floorfrac(float x, out int i)
+{
+ i = floor_to_int(x);
+ return x - i;
}
/*********** NEW SHADER NODES ***************/
@@ -2322,15 +2504,15 @@ void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out vec4 result)
vec3 L = vec3(0.2);
/* directional lights */
- for(int i = 0; i < NUM_LIGHTS; i++) {
+ for (int i = 0; i < NUM_LIGHTS; i++) {
vec3 light_position = gl_LightSource[i].position.xyz;
vec3 light_diffuse = gl_LightSource[i].diffuse.rgb;
float bsdf = max(dot(N, light_position), 0.0);
- L += light_diffuse*bsdf;
+ L += light_diffuse * bsdf;
}
- result = vec4(L*color.rgb, 1.0);
+ result = vec4(L * color.rgb, 1.0);
}
void node_bsdf_glossy(vec4 color, float roughness, vec3 N, out vec4 result)
@@ -2339,22 +2521,24 @@ void node_bsdf_glossy(vec4 color, float roughness, vec3 N, out vec4 result)
vec3 L = vec3(0.2);
/* directional lights */
- for(int i = 0; i < NUM_LIGHTS; i++) {
+ for (int i = 0; i < NUM_LIGHTS; i++) {
vec3 light_position = gl_LightSource[i].position.xyz;
vec3 H = gl_LightSource[i].halfVector.xyz;
vec3 light_diffuse = gl_LightSource[i].diffuse.rgb;
vec3 light_specular = gl_LightSource[i].specular.rgb;
/* we mix in some diffuse so low roughness still shows up */
- float bsdf = 0.5*pow(max(dot(N, H), 0.0), 1.0/roughness);
- bsdf += 0.5*max(dot(N, light_position), 0.0);
- L += light_specular*bsdf;
+ float bsdf = 0.5 * pow(max(dot(N, H), 0.0), 1.0 / roughness);
+ bsdf += 0.5 * max(dot(N, light_position), 0.0);
+ L += light_specular * bsdf;
}
- result = vec4(L*color.rgb, 1.0);
+ result = vec4(L * color.rgb, 1.0);
}
-void node_bsdf_anisotropic(vec4 color, float roughness, float anisotropy, float rotation, vec3 N, vec3 T, out vec4 result)
+void node_bsdf_anisotropic(
+ vec4 color, float roughness, float anisotropy, float rotation, vec3 N, vec3 T,
+ out vec4 result)
{
node_bsdf_diffuse(color, 0.0, N, result);
}
@@ -2388,7 +2572,9 @@ void node_bsdf_velvet(vec4 color, float sigma, vec3 N, out vec4 result)
node_bsdf_diffuse(color, 0.0, N, result);
}
-void node_subsurface_scattering(vec4 color, float scale, vec3 radius, float sharpen, float texture_blur, vec3 N, out vec4 result)
+void node_subsurface_scattering(
+ vec4 color, float scale, vec3 radius, float sharpen, float texture_blur, vec3 N,
+ out vec4 result)
{
node_bsdf_diffuse(color, 0.0, N, result);
}
@@ -2412,7 +2598,7 @@ void node_ambient_occlusion(vec4 color, out vec4 result)
void node_emission(vec4 color, float strength, vec3 N, out vec4 result)
{
- result = color*strength;
+ result = color * strength;
}
/* background */
@@ -2428,7 +2614,7 @@ void background_transform_to_world(vec3 viewvec, out vec3 worldvec)
void node_background(vec4 color, float strength, vec3 N, out vec4 result)
{
- result = color*strength;
+ result = color * strength;
}
/* closures */
@@ -2448,10 +2634,10 @@ void node_add_shader(vec4 shader1, vec4 shader2, out vec4 shader)
void node_fresnel(float ior, vec3 N, vec3 I, out float result)
{
/* handle perspective/orthographic */
- vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0)? normalize(I): vec3(0.0, 0.0, -1.0);
+ vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
float eta = max(ior, 0.00001);
- result = fresnel_dielectric(I_view, N, (gl_FrontFacing)? eta: 1.0/eta);
+ result = fresnel_dielectric(I_view, N, (gl_FrontFacing) ? eta : 1.0 / eta);
}
/* layer_weight */
@@ -2460,15 +2646,15 @@ void node_layer_weight(float blend, vec3 N, vec3 I, out float fresnel, out float
{
/* fresnel */
float eta = max(1.0 - blend, 0.00001);
- vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0)? normalize(I): vec3(0.0, 0.0, -1.0);
+ vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
- fresnel = fresnel_dielectric(I_view, N, (gl_FrontFacing)? 1.0/eta : eta );
+ fresnel = fresnel_dielectric(I_view, N, (gl_FrontFacing) ? 1.0 / eta : eta);
/* facing */
facing = abs(dot(I_view, N));
- if(blend != 0.5) {
+ if (blend != 0.5) {
blend = clamp(blend, 0.0, 0.99999);
- blend = (blend < 0.5)? 2.0*blend: 0.5/(1.0 - blend);
+ blend = (blend < 0.5) ? 2.0 * blend : 0.5 / (1.0 - blend);
facing = pow(facing, blend);
}
facing = 1.0 - facing;
@@ -2480,21 +2666,21 @@ void node_gamma(vec4 col, float gamma, out vec4 outcol)
{
outcol = col;
- if(col.r > 0.0)
+ if (col.r > 0.0)
outcol.r = compatible_pow(col.r, gamma);
- if(col.g > 0.0)
+ if (col.g > 0.0)
outcol.g = compatible_pow(col.g, gamma);
- if(col.b > 0.0)
+ if (col.b > 0.0)
outcol.b = compatible_pow(col.b, gamma);
}
/* geometry */
-void node_attribute(vec3 attr_uv, out vec4 outcol, out vec3 outvec, out float outf)
+void node_attribute(vec3 attr, out vec4 outcol, out vec3 outvec, out float outf)
{
- outcol = vec4(attr_uv, 1.0);
- outvec = attr_uv;
- outf = (attr_uv.x + attr_uv.y + attr_uv.z)/3.0;
+ outcol = vec4(attr, 1.0);
+ outvec = attr;
+ outf = (attr.x + attr.y + attr.z) / 3.0;
}
void node_uvmap(vec3 attr_uv, out vec3 outvec)
@@ -2502,48 +2688,51 @@ void node_uvmap(vec3 attr_uv, out vec3 outvec)
outvec = attr_uv;
}
-void node_geometry(vec3 I, vec3 N, mat4 toworld,
- out vec3 position, out vec3 normal, out vec3 tangent,
- out vec3 true_normal, out vec3 incoming, out vec3 parametric,
- out float backfacing, out float pointiness)
+void node_geometry(
+ vec3 I, vec3 N, mat4 toworld,
+ out vec3 position, out vec3 normal, out vec3 tangent,
+ out vec3 true_normal, out vec3 incoming, out vec3 parametric,
+ out float backfacing, out float pointiness)
{
- position = (toworld*vec4(I, 1.0)).xyz;
- normal = (toworld*vec4(N, 0.0)).xyz;
+ position = (toworld * vec4(I, 1.0)).xyz;
+ normal = (toworld * vec4(N, 0.0)).xyz;
tangent = vec3(0.0);
true_normal = normal;
/* handle perspective/orthographic */
- vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0)? normalize(I): vec3(0.0, 0.0, -1.0);
- incoming = -(toworld*vec4(I_view, 0.0)).xyz;
+ vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
+ incoming = -(toworld * vec4(I_view, 0.0)).xyz;
parametric = vec3(0.0);
- backfacing = (gl_FrontFacing)? 0.0: 1.0;
- pointiness = 0.0;
+ backfacing = (gl_FrontFacing) ? 0.0 : 1.0;
+ pointiness = 0.5;
}
-void node_tex_coord(vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat, vec4 camerafac,
- vec3 attr_orco, vec3 attr_uv,
- out vec3 generated, out vec3 normal, out vec3 uv, out vec3 object,
- out vec3 camera, out vec3 window, out vec3 reflection)
+void node_tex_coord(
+ vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat, vec4 camerafac,
+ vec3 attr_orco, vec3 attr_uv,
+ out vec3 generated, out vec3 normal, out vec3 uv, out vec3 object,
+ out vec3 camera, out vec3 window, out vec3 reflection)
{
generated = attr_orco * 0.5 + vec3(0.5);
- normal = normalize((obinvmat*(viewinvmat*vec4(N, 0.0))).xyz);
+ normal = normalize((obinvmat * (viewinvmat * vec4(N, 0.0))).xyz);
uv = attr_uv;
- object = (obinvmat*(viewinvmat*vec4(I, 1.0))).xyz;
+ object = (obinvmat * (viewinvmat * vec4(I, 1.0))).xyz;
camera = vec3(I.xy, -I.z);
vec4 projvec = gl_ProjectionMatrix * vec4(I, 1.0);
- window = vec3(mtex_2d_mapping(projvec.xyz/projvec.w).xy * camerafac.xy + camerafac.zw, 0.0);
+ window = vec3(mtex_2d_mapping(projvec.xyz / projvec.w).xy * camerafac.xy + camerafac.zw, 0.0);
vec3 shade_I;
shade_view(I, shade_I);
vec3 view_reflection = reflect(shade_I, normalize(N));
- reflection = (viewinvmat*vec4(view_reflection, 0.0)).xyz;
+ reflection = (viewinvmat * vec4(view_reflection, 0.0)).xyz;
}
-void node_tex_coord_background(vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat, vec4 camerafac,
- vec3 attr_orco, vec3 attr_uv,
- out vec3 generated, out vec3 normal, out vec3 uv, out vec3 object,
- out vec3 camera, out vec3 window, out vec3 reflection)
+void node_tex_coord_background(
+ vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat, vec4 camerafac,
+ vec3 attr_orco, vec3 attr_uv,
+ out vec3 generated, out vec3 normal, out vec3 uv, out vec3 object,
+ out vec3 camera, out vec3 window, out vec3 reflection)
{
vec4 v = (gl_ProjectionMatrix[3][3] == 0.0) ? vec4(I, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
vec4 co_homogenous = (gl_ProjectionMatrixInverse * v);
@@ -2559,31 +2748,135 @@ void node_tex_coord_background(vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat, v
object = coords;
camera = vec3(co.xy, -co.z);
- window = (gl_ProjectionMatrix[3][3] == 0.0) ?
- vec3(mtex_2d_mapping(I).xy * camerafac.xy + camerafac.zw, 0.0) :
- vec3(vec2(0.5) * camerafac.xy + camerafac.zw, 0.0);
+ window = (gl_ProjectionMatrix[3][3] == 0.0) ?
+ vec3(mtex_2d_mapping(I).xy * camerafac.xy + camerafac.zw, 0.0) :
+ vec3(vec2(0.5) * camerafac.xy + camerafac.zw, 0.0);
reflection = -coords;
}
/* textures */
-void node_tex_gradient(vec3 co, out vec4 color, out float fac)
+float calc_gradient(vec3 p, int gradient_type)
{
- color = vec4(1.0);
- fac = 1.0;
+ float x, y, z;
+ x = p.x;
+ y = p.y;
+ z = p.z;
+ if (gradient_type == 0) { /* linear */
+ return x;
+ }
+ else if (gradient_type == 1) { /* quadratic */
+ float r = max(x, 0.0);
+ return r * r;
+ }
+ else if (gradient_type == 2) { /* easing */
+ float r = min(max(x, 0.0), 1.0);
+ float t = r * r;
+ return (3.0 * t - 2.0 * t * r);
+ }
+ else if (gradient_type == 3) { /* diagonal */
+ return (x + y) * 0.5;
+ }
+ else if (gradient_type == 4) { /* radial */
+ return atan(y, x) / (M_PI * 2) + 0.5;
+ }
+ else {
+ float r = max(1.0 - sqrt(x * x + y * y + z * z), 0.0);
+ if (gradient_type == 5) { /* quadratic sphere */
+ return r * r;
+ }
+ else if (gradient_type == 6) { /* sphere */
+ return r;
+ }
+ }
+ return 0.0;
+}
+
+void node_tex_gradient(vec3 co, float gradient_type, out vec4 color, out float fac)
+{
+ float f = calc_gradient(co, int(gradient_type));
+ f = clamp(f, 0.0, 1.0);
+
+ color = vec4(f, f, f, 1.0);
+ fac = f;
}
void node_tex_checker(vec3 co, vec4 color1, vec4 color2, float scale, out vec4 color, out float fac)
{
- color = vec4(1.0);
- fac = 1.0;
+ vec3 p = co * scale;
+
+ /* Prevent precision issues on unit coordinates. */
+ p.x = (p.x + 0.000001) * 0.999999;
+ p.y = (p.y + 0.000001) * 0.999999;
+ p.z = (p.z + 0.000001) * 0.999999;
+
+ int xi = int(abs(floor(p.x)));
+ int yi = int(abs(floor(p.y)));
+ int zi = int(abs(floor(p.z)));
+
+ bool check = ((mod(xi, 2) == mod(yi, 2)) == bool(mod(zi, 2)));
+
+ color = check ? color1 : color2;
+ fac = check ? 1.0 : 0.0;
}
-void node_tex_brick(vec3 co, vec4 color1, vec4 color2, vec4 mortar, float scale, float mortar_size, float bias, float brick_width, float row_height, out vec4 color, out float fac)
+#ifdef BIT_OPERATIONS
+vec2 calc_brick_texture(vec3 p, float mortar_size, float bias,
+ float brick_width, float row_height,
+ float offset_amount, int offset_frequency,
+ float squash_amount, int squash_frequency)
{
+ int bricknum, rownum;
+ float offset = 0.0;
+ float x, y;
+
+ rownum = floor_to_int(p.y / row_height);
+
+ if (offset_frequency != 0 && squash_frequency != 0) {
+ brick_width *= (rownum % squash_frequency != 0) ? 1.0 : squash_amount; /* squash */
+ offset = (rownum % offset_frequency != 0) ? 0.0 : (brick_width * offset_amount); /* offset */
+ }
+
+ bricknum = floor_to_int((p.x + offset) / brick_width);
+
+ x = (p.x + offset) - brick_width * bricknum;
+ y = p.y - row_height * rownum;
+
+ return vec2(clamp((integer_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias), 0.0, 1.0),
+ (x < mortar_size || y < mortar_size ||
+ x > (brick_width - mortar_size) ||
+ y > (row_height - mortar_size)) ? 1.0 : 0.0);
+}
+#endif
+
+void node_tex_brick(vec3 co,
+ vec4 color1, vec4 color2,
+ vec4 mortar, float scale,
+ float mortar_size, float bias,
+ float brick_width, float row_height,
+ float offset_amount, float offset_frequency,
+ float squash_amount, float squash_frequency,
+ out vec4 color, out float fac)
+{
+#ifdef BIT_OPERATIONS
+ vec2 f2 = calc_brick_texture(co * scale,
+ mortar_size, bias,
+ brick_width, row_height,
+ offset_amount, int(offset_frequency),
+ squash_amount, int(squash_frequency));
+ float tint = f2.x;
+ float f = f2.y;
+ if (f != 1.0) {
+ float facm = 1.0 - tint;
+ color1 = facm * color1 + tint * color2;
+ }
+ color = (f == 1.0) ? mortar : color1;
+ fac = f;
+#else
color = vec4(1.0);
fac = 1.0;
+#endif
}
void node_tex_clouds(vec3 co, float size, out vec4 color, out float fac)
@@ -2595,8 +2888,8 @@ void node_tex_clouds(vec3 co, float size, out vec4 color, out float fac)
void node_tex_environment_equirectangular(vec3 co, sampler2D ima, out vec4 color)
{
vec3 nco = normalize(co);
- float u = -atan(nco.y, nco.x)/(2.0*M_PI) + 0.5;
- float v = atan(nco.z, hypot(nco.x, nco.y))/M_PI + 0.5;
+ float u = -atan(nco.y, nco.x) / (2.0 * M_PI) + 0.5;
+ float v = atan(nco.z, hypot(nco.x, nco.y)) / M_PI + 0.5;
color = texture2D(ima, vec2(u, v));
}
@@ -2607,12 +2900,12 @@ void node_tex_environment_mirror_ball(vec3 co, sampler2D ima, out vec4 color)
nco.y -= 1.0;
- float div = 2.0*sqrt(max(-0.5*nco.y, 0.0));
- if(div > 0.0)
+ float div = 2.0 * sqrt(max(-0.5 * nco.y, 0.0));
+ if (div > 0.0)
nco /= div;
- float u = 0.5*(nco.x + 1.0);
- float v = 0.5*(nco.z + 1.0);
+ float u = 0.5 * (nco.x + 1.0);
+ float v = 0.5 * (nco.z + 1.0);
color = texture2D(ima, vec2(u, v));
}
@@ -2628,28 +2921,480 @@ void node_tex_image(vec3 co, sampler2D ima, out vec4 color, out float alpha)
alpha = color.a;
}
+void node_tex_image_box(vec3 texco,
+ vec3 nob,
+ sampler2D ima,
+ float blend,
+ out vec4 color,
+ out float alpha)
+{
+ /* project from direction vector to barycentric coordinates in triangles */
+ nob = vec3(abs(nob.x), abs(nob.y), abs(nob.z));
+ nob /= (nob.x + nob.y + nob.z);
+
+ /* basic idea is to think of this as a triangle, each corner representing
+ * one of the 3 faces of the cube. in the corners we have single textures,
+ * in between we blend between two textures, and in the middle we a blend
+ * between three textures.
+ *
+ * the Nxyz values are the barycentric coordinates in an equilateral
+ * triangle, which in case of blending, in the middle has a smaller
+ * equilateral triangle where 3 textures blend. this divides things into
+ * 7 zones, with an if () test for each zone */
+
+ vec3 weight = vec3(0.0, 0.0, 0.0);
+ float limit = 0.5 * (1.0 + blend);
+
+ /* first test for corners with single texture */
+ if (nob.x > limit * (nob.x + nob.y) && nob.x > limit * (nob.x + nob.z)) {
+ weight.x = 1.0;
+ }
+ else if (nob.y > limit * (nob.x + nob.y) && nob.y > limit * (nob.y + nob.z)) {
+ weight.y = 1.0;
+ }
+ else if (nob.z > limit * (nob.x + nob.z) && nob.z > limit * (nob.y + nob.z)) {
+ weight.z = 1.0;
+ }
+ else if (blend > 0.0) {
+ /* in case of blending, test for mixes between two textures */
+ if (nob.z < (1.0 - limit) * (nob.y + nob.x)) {
+ weight.x = nob.x / (nob.x + nob.y);
+ weight.x = clamp((weight.x - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0);
+ weight.y = 1.0 - weight.x;
+ }
+ else if (nob.x < (1.0 - limit) * (nob.y + nob.z)) {
+ weight.y = nob.y / (nob.y + nob.z);
+ weight.y = clamp((weight.y - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0);
+ weight.z = 1.0 - weight.y;
+ }
+ else if (nob.y < (1.0 - limit) * (nob.x + nob.z)) {
+ weight.x = nob.x / (nob.x + nob.z);
+ weight.x = clamp((weight.x - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0);
+ weight.z = 1.0 - weight.x;
+ }
+ else {
+ /* last case, we have a mix between three */
+ weight.x = ((2.0 - limit) * nob.x + (limit - 1.0)) / (2.0 * limit - 1.0);
+ weight.y = ((2.0 - limit) * nob.y + (limit - 1.0)) / (2.0 * limit - 1.0);
+ weight.z = ((2.0 - limit) * nob.z + (limit - 1.0)) / (2.0 * limit - 1.0);
+ }
+ }
+ else {
+ /* Desperate mode, no valid choice anyway, fallback to one side.*/
+ weight.x = 1.0;
+ }
+ color = vec4(0);
+ if (weight.x > 0.0) {
+ color += weight.x * texture2D(ima, texco.yz);
+ }
+ if (weight.y > 0.0) {
+ color += weight.y * texture2D(ima, texco.xz);
+ }
+ if (weight.z > 0.0) {
+ color += weight.z * texture2D(ima, texco.yx);
+ }
+
+ alpha = color.a;
+}
+
void node_tex_image_empty(vec3 co, out vec4 color, out float alpha)
{
color = vec4(0.0);
alpha = 0.0;
}
-void node_tex_magic(vec3 p, float scale, float distortion, out vec4 color, out float fac)
+void node_tex_magic(vec3 co, float scale, float distortion, float depth, out vec4 color, out float fac)
+{
+ vec3 p = co * scale;
+ float x = sin((p.x + p.y + p.z) * 5.0);
+ float y = cos((-p.x + p.y - p.z) * 5.0);
+ float z = -cos((-p.x - p.y + p.z) * 5.0);
+
+ if (depth > 0) {
+ x *= distortion;
+ y *= distortion;
+ z *= distortion;
+ y = -cos(x - y + z);
+ y *= distortion;
+ if (depth > 1) {
+ x = cos(x - y - z);
+ x *= distortion;
+ if (depth > 2) {
+ z = sin(-x - y - z);
+ z *= distortion;
+ if (depth > 3) {
+ x = -cos(-x + y - z);
+ x *= distortion;
+ if (depth > 4) {
+ y = -sin(-x + y + z);
+ y *= distortion;
+ if (depth > 5) {
+ y = -cos(-x + y + z);
+ y *= distortion;
+ if (depth > 6) {
+ x = cos(x + y + z);
+ x *= distortion;
+ if (depth > 7) {
+ z = sin(x + y - z);
+ z *= distortion;
+ if (depth > 8) {
+ x = -cos(-x - y + z);
+ x *= distortion;
+ if (depth > 9) {
+ y = -sin(x - y + z);
+ y *= distortion;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (distortion != 0.0) {
+ distortion *= 2.0;
+ x /= distortion;
+ y /= distortion;
+ z /= distortion;
+ }
+
+ color = vec4(0.5 - x, 0.5 - y, 0.5 - z, 1.0);
+ fac = (color.x + color.y + color.z) / 3.0;
+}
+
+#ifdef BIT_OPERATIONS
+float noise_fade(float t)
{
- color = vec4(1.0);
- fac = 1.0;
+ return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);
}
-void node_tex_musgrave(vec3 co, float scale, float detail, float dimension, float lacunarity, float offset, float gain, out vec4 color, out float fac)
+float noise_scale3(float result)
{
- color = vec4(1.0);
- fac = 1.0;
+ return 0.9820 * result;
+}
+
+float noise_nerp(float t, float a, float b)
+{
+ return (1.0 - t) * a + t * b;
}
+float noise_grad(uint hash, float x, float y, float z)
+{
+ uint h = hash & 15u;
+ float u = h < 8u ? x : y;
+ float vt = ((h == 12u) || (h == 14u)) ? x : z;
+ float v = h < 4u ? y : vt;
+ return (((h & 1u) != 0u) ? -u : u) + (((h & 2u) != 0u) ? -v : v);
+}
+
+float noise_perlin(float x, float y, float z)
+{
+ int X; float fx = floorfrac(x, X);
+ int Y; float fy = floorfrac(y, Y);
+ int Z; float fz = floorfrac(z, Z);
+
+ float u = noise_fade(fx);
+ float v = noise_fade(fy);
+ float w = noise_fade(fz);
+
+ float result;
+
+ result = noise_nerp(w, noise_nerp(v, noise_nerp(u, noise_grad(hash(X, Y, Z), fx, fy, fz),
+ noise_grad(hash(X + 1, Y, Z), fx - 1.0, fy, fz)),
+ noise_nerp(u, noise_grad(hash(X, Y + 1, Z), fx, fy - 1.0, fz),
+ noise_grad(hash(X + 1, Y + 1, Z), fx - 1.0, fy - 1.0, fz))),
+ noise_nerp(v, noise_nerp(u, noise_grad(hash(X, Y, Z + 1), fx, fy, fz - 1.0),
+ noise_grad(hash(X + 1, Y, Z + 1), fx - 1.0, fy, fz - 1.0)),
+ noise_nerp(u, noise_grad(hash(X, Y + 1, Z + 1), fx, fy - 1.0, fz - 1.0),
+ noise_grad(hash(X + 1, Y + 1, Z + 1), fx - 1.0, fy - 1.0, fz - 1.0))));
+ return noise_scale3(result);
+}
+
+float noise(vec3 p)
+{
+ return 0.5 * noise_perlin(p.x, p.y, p.z) + 0.5;
+}
+
+float snoise(vec3 p)
+{
+ return noise_perlin(p.x, p.y, p.z);
+}
+
+float noise_turbulence(vec3 p, float octaves, int hard)
+{
+ float fscale = 1.0;
+ float amp = 1.0;
+ float sum = 0.0;
+ int i, n;
+ octaves = clamp(octaves, 0.0, 16.0);
+ n = int(octaves);
+ for (i = 0; i <= n; i++) {
+ float t = noise(fscale * p);
+ if (hard != 0) {
+ t = abs(2.0 * t - 1.0);
+ }
+ sum += t * amp;
+ amp *= 0.5;
+ fscale *= 2.0;
+ }
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float t = noise(fscale * p);
+ if (hard != 0) {
+ t = abs(2.0 * t - 1.0);
+ }
+ float sum2 = sum + t * amp;
+ sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
+ sum2 *= (float(1 << (n + 1)) / float((1 << (n + 2)) - 1));
+ return (1.0 - rmd) * sum + rmd * sum2;
+ }
+ else {
+ sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
+ return sum;
+ }
+}
+#endif // BIT_OPERATIONS
+
void node_tex_noise(vec3 co, float scale, float detail, float distortion, out vec4 color, out float fac)
{
+#ifdef BIT_OPERATIONS
+ vec3 p = co * scale;
+ int hard = 0;
+ if (distortion != 0.0) {
+ vec3 r, offset = vec3(13.5, 13.5, 13.5);
+ r.x = noise(p + offset) * distortion;
+ r.y = noise(p) * distortion;
+ r.z = noise(p - offset) * distortion;
+ p += r;
+ }
+
+ fac = noise_turbulence(p, detail, hard);
+ color = vec4(fac,
+ noise_turbulence(vec3(p.y, p.x, p.z), detail, hard),
+ noise_turbulence(vec3(p.y, p.z, p.x), detail, hard),
+ 1);
+#else // BIT_OPERATIONS
color = vec4(1.0);
fac = 1.0;
+#endif // BIT_OPERATIONS
+}
+
+
+#ifdef BIT_OPERATIONS
+
+/* Musgrave fBm
+ *
+ * H: fractal increment parameter
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ *
+ * from "Texturing and Modelling: A procedural approach"
+ */
+
+float noise_musgrave_fBm(vec3 p, float H, float lacunarity, float octaves)
+{
+ float rmd;
+ float value = 0.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+ int i;
+
+ for (i = 0; i < int(octaves); i++) {
+ value += snoise(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0)
+ value += rmd * snoise(p) * pwr;
+
+ return value;
+}
+
+/* Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+float noise_musgrave_multi_fractal(vec3 p, float H, float lacunarity, float octaves)
+{
+ float rmd;
+ float value = 1.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+ int i;
+
+ for (i = 0; i < int(octaves); i++) {
+ value *= (pwr * snoise(p) + 1.0);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0)
+ value *= (rmd * pwr * snoise(p) + 1.0); /* correct? */
+
+ return value;
+}
+
+/* Musgrave Heterogeneous Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+float noise_musgrave_hetero_terrain(vec3 p, float H, float lacunarity, float octaves, float offset)
+{
+ float value, increment, rmd;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+ int i;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ value = offset + snoise(p);
+ p *= lacunarity;
+
+ for (i = 1; i < int(octaves); i++) {
+ increment = (snoise(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ increment = (snoise(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ return value;
+}
+
+/* Hybrid Additive/Multiplicative Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+float noise_musgrave_hybrid_multi_fractal(vec3 p, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float result, signal, weight, rmd;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+ int i;
+
+ result = snoise(p) + offset;
+ weight = gain * result;
+ p *= lacunarity;
+
+ for (i = 1; (weight > 0.001f) && (i < int(octaves)); i++) {
+ if (weight > 1.0)
+ weight = 1.0;
+
+ signal = (snoise(p) + offset) * pwr;
+ pwr *= pwHL;
+ result += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0)
+ result += rmd * ((snoise(p) + offset) * pwr);
+
+ return result;
+}
+
+/* Ridged Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+float noise_musgrave_ridged_multi_fractal(vec3 p, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float result, signal, weight;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+ int i;
+
+ signal = offset - abs(snoise(p));
+ signal *= signal;
+ result = signal;
+ weight = 1.0;
+
+ for (i = 1; i < int(octaves); i++) {
+ p *= lacunarity;
+ weight = clamp(signal * gain, 0.0, 1.0);
+ signal = offset - abs(snoise(p));
+ signal *= signal;
+ signal *= weight;
+ result += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ return result;
+}
+
+float svm_musgrave(int type,
+ float dimension,
+ float lacunarity,
+ float octaves,
+ float offset,
+ float intensity,
+ float gain,
+ vec3 p)
+{
+ if (type == 0 /*NODE_MUSGRAVE_MULTIFRACTAL*/)
+ return intensity * noise_musgrave_multi_fractal(p, dimension, lacunarity, octaves);
+ else if (type == 1 /*NODE_MUSGRAVE_FBM*/)
+ return intensity * noise_musgrave_fBm(p, dimension, lacunarity, octaves);
+ else if (type == 2 /*NODE_MUSGRAVE_HYBRID_MULTIFRACTAL*/)
+ return intensity * noise_musgrave_hybrid_multi_fractal(p, dimension, lacunarity, octaves, offset, gain);
+ else if (type == 3 /*NODE_MUSGRAVE_RIDGED_MULTIFRACTAL*/)
+ return intensity * noise_musgrave_ridged_multi_fractal(p, dimension, lacunarity, octaves, offset, gain);
+ else if (type == 4 /*NODE_MUSGRAVE_HETERO_TERRAIN*/)
+ return intensity * noise_musgrave_hetero_terrain(p, dimension, lacunarity, octaves, offset);
+ return 0.0;
+}
+#endif // #ifdef BIT_OPERATIONS
+
+void node_tex_musgrave(vec3 co,
+ float scale,
+ float detail,
+ float dimension,
+ float lacunarity,
+ float offset,
+ float gain,
+ float type,
+ out vec4 color,
+ out float fac)
+{
+#ifdef BIT_OPERATIONS
+ fac = svm_musgrave(int(type),
+ dimension,
+ lacunarity,
+ detail,
+ offset,
+ 1.0,
+ gain,
+ co * scale);
+#else
+ fac = 1.0;
+#endif
+
+ color = vec4(fac, fac, fac, 1.0);
}
void node_tex_sky(vec3 co, out vec4 color)
@@ -2657,16 +3402,117 @@ void node_tex_sky(vec3 co, out vec4 color)
color = vec4(1.0);
}
-void node_tex_voronoi(vec3 co, float scale, out vec4 color, out float fac)
-{
+void node_tex_voronoi(vec3 co, float scale, float coloring, out vec4 color, out float fac)
+{
+#ifdef BIT_OPERATIONS
+ vec3 p = co * scale;
+ int xx, yy, zz, xi, yi, zi;
+ float da[4];
+ vec3 pa[4];
+
+ xi = floor_to_int(p[0]);
+ yi = floor_to_int(p[1]);
+ zi = floor_to_int(p[2]);
+
+ da[0] = 1e+10;
+ da[1] = 1e+10;
+ da[2] = 1e+10;
+ da[3] = 1e+10;
+
+ for (xx = xi - 1; xx <= xi + 1; xx++) {
+ for (yy = yi - 1; yy <= yi + 1; yy++) {
+ for (zz = zi - 1; zz <= zi + 1; zz++) {
+ vec3 ip = vec3(xx, yy, zz);
+ vec3 vp = cellnoise_color(ip);
+ vec3 pd = p - (vp + ip);
+ float d = dot(pd, pd);
+ vp += vec3(xx, yy, zz);
+ if (d < da[0]) {
+ da[3] = da[2];
+ da[2] = da[1];
+ da[1] = da[0];
+ da[0] = d;
+ pa[3] = pa[2];
+ pa[2] = pa[1];
+ pa[1] = pa[0];
+ pa[0] = vp;
+ }
+ else if (d < da[1]) {
+ da[3] = da[2];
+ da[2] = da[1];
+ da[1] = d;
+
+ pa[3] = pa[2];
+ pa[2] = pa[1];
+ pa[1] = vp;
+ }
+ else if (d < da[2]) {
+ da[3] = da[2];
+ da[2] = d;
+
+ pa[3] = pa[2];
+ pa[2] = vp;
+ }
+ else if (d < da[3]) {
+ da[3] = d;
+ pa[3] = vp;
+ }
+ }
+ }
+ }
+
+ if (coloring == 0.0) {
+ fac = abs(da[0]);
+ color = vec4(fac, fac, fac, 1);
+ }
+ else {
+ color = vec4(cellnoise_color(pa[0]), 1);
+ fac = (color.x + color.y + color.z) * (1.0 / 3.0);
+ }
+#else // BIT_OPERATIONS
color = vec4(1.0);
fac = 1.0;
+#endif // BIT_OPERATIONS
+}
+
+#ifdef BIT_OPERATIONS
+float calc_wave(vec3 p, float distortion, float detail, float detail_scale, int wave_type, int wave_profile)
+{
+ float n;
+
+ if (wave_type == 0) /* type bands */
+ n = (p.x + p.y + p.z) * 10.0;
+ else /* type rings */
+ n = length(p) * 20.0;
+
+ if (distortion != 0.0)
+ n += distortion * noise_turbulence(p * detail_scale, detail, 0);
+
+ if (wave_profile == 0) { /* profile sin */
+ return 0.5 + 0.5 * sin(n);
+ }
+ else { /* profile saw */
+ n /= 2.0 * M_PI;
+ n -= int(n);
+ return (n < 0.0) ? n + 1.0 : n;
+ }
}
+#endif // BIT_OPERATIONS
-void node_tex_wave(vec3 co, float scale, float distortion, float detail, float detail_scale, out vec4 color, out float fac)
+void node_tex_wave(
+ vec3 co, float scale, float distortion, float detail, float detail_scale, float wave_type, float wave_profile,
+ out vec4 color, out float fac)
{
+#ifdef BIT_OPERATIONS
+ float f;
+ f = calc_wave(co * scale, distortion, detail, detail_scale, int(wave_type), int(wave_profile));
+
+ color = vec4(f, f, f, 1.0);
+ fac = f;
+#else // BIT_OPERATIONS
color = vec4(1.0);
- fac = 1.0;
+ fac = 1;
+#endif // BIT_OPERATIONS
}
/* light path */
@@ -2720,9 +3566,30 @@ void node_normal_map(vec4 tangent, vec3 normal, vec3 texnormal, out vec3 outnorm
outnormal = normalize(outnormal);
}
-void node_bump(float strength, float dist, float height, vec3 N, out vec3 result)
+void node_bump(float strength, float dist, float height, vec3 N, vec3 surf_pos, float invert, out vec3 result)
{
- result = N;
+ if (invert != 0.0) {
+ dist *= -1.0;
+ }
+ vec3 dPdx = dFdx(surf_pos);
+ vec3 dPdy = dFdy(surf_pos);
+
+ /* Get surface tangents from normal. */
+ vec3 Rx = cross(dPdy, N);
+ vec3 Ry = cross(N, dPdx);
+
+ /* Compute surface gradient and determinant. */
+ float det = dot(dPdx, Rx);
+ float absdet = abs(det);
+
+ float dHdx = dFdx(height);
+ float dHdy = dFdy(height);
+ vec3 surfgrad = dHdx * Rx + dHdy * Ry;
+
+ strength = max(strength, 0.0);
+
+ result = normalize(absdet * N - dist * sign(det) * surfgrad);
+ result = normalize(strength * result + (1.0 - strength) * N);
}
/* output */
@@ -2745,7 +3612,7 @@ void material_preview_matcap(vec4 color, sampler2D ima, vec4 N, vec4 mask, out v
vec2 tex;
#ifndef USE_OPENSUBDIV
- /* remap to 0.0 - 1.0 range. This is done because OpenGL 2.0 clamps colors
+ /* remap to 0.0 - 1.0 range. This is done because OpenGL 2.0 clamps colors
* between shader stages and we want the full range of the normal */
normal = vec3(2.0, 2.0, 2.0) * vec3(N.x, N.y, N.z) - vec3(1.0, 1.0, 1.0);
if (normal.z < 0.0) {
diff --git a/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl b/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl
index 5f406c959f1..b485d2cce86 100644
--- a/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl
@@ -4,13 +4,13 @@ uniform sampler2D textureSource;
void main()
{
vec4 color = vec4(0.0);
- color += texture2D( textureSource, gl_TexCoord[0].st + vec2(-3.0 * ScaleU.x, -3.0 * ScaleU.y ) ) * 0.015625;
- color += texture2D( textureSource, gl_TexCoord[0].st + vec2(-2.0 * ScaleU.x, -2.0 * ScaleU.y ) ) * 0.09375;
- color += texture2D( textureSource, gl_TexCoord[0].st + vec2(-1.0 * ScaleU.x, -1.0 * ScaleU.y ) ) * 0.234375;
- color += texture2D( textureSource, gl_TexCoord[0].st + vec2(0.0, 0.0)) * 0.3125;
- color += texture2D( textureSource, gl_TexCoord[0].st + vec2(1.0 * ScaleU.x, 1.0 * ScaleU.y ) ) * 0.234375;
- color += texture2D( textureSource, gl_TexCoord[0].st + vec2(2.0 * ScaleU.x, 2.0 * ScaleU.y ) ) * 0.09375;
- color += texture2D( textureSource, gl_TexCoord[0].st + vec2(3.0 * ScaleU.x, 3.0 * ScaleU.y ) ) * 0.015625;
+ color += texture2D(textureSource, gl_TexCoord[0].st + vec2(-3.0 * ScaleU.x, -3.0 * ScaleU.y)) * 0.015625;
+ color += texture2D(textureSource, gl_TexCoord[0].st + vec2(-2.0 * ScaleU.x, -2.0 * ScaleU.y)) * 0.09375;
+ color += texture2D(textureSource, gl_TexCoord[0].st + vec2(-1.0 * ScaleU.x, -1.0 * ScaleU.y)) * 0.234375;
+ color += texture2D(textureSource, gl_TexCoord[0].st + vec2(0.0, 0.0)) * 0.3125;
+ color += texture2D(textureSource, gl_TexCoord[0].st + vec2(1.0 * ScaleU.x, 1.0 * ScaleU.y)) * 0.234375;
+ color += texture2D(textureSource, gl_TexCoord[0].st + vec2(2.0 * ScaleU.x, 2.0 * ScaleU.y)) * 0.09375;
+ color += texture2D(textureSource, gl_TexCoord[0].st + vec2(3.0 * ScaleU.x, 3.0 * ScaleU.y)) * 0.015625;
gl_FragColor = color;
}
diff --git a/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl b/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl
index 9bb2e7ad469..5d00108b052 100644
--- a/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl
@@ -1,6 +1,6 @@
void main()
{
- gl_Position = ftransform();
- gl_TexCoord[0] = gl_MultiTexCoord0;
+ gl_Position = ftransform();
+ gl_TexCoord[0] = gl_MultiTexCoord0;
}
diff --git a/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl b/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl
index 4d1feb5c83e..fd790009e02 100644
--- a/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl
@@ -8,11 +8,6 @@ uniform float density_scale;
uniform sampler3D soot_texture;
uniform sampler3D shadow_texture;
-#ifdef USE_FIRE
-uniform sampler3D flame_texture;
-uniform sampler1D spectrum_texture;
-#endif
-
void main()
{
/* compute color and density from volume texture */
@@ -37,12 +32,5 @@ void main()
/* premultiply alpha */
vec4 color = vec4(soot_alpha * soot_color, soot_alpha);
-#ifdef USE_FIRE
- /* fire */
- float flame = texture3D(flame_texture, coords).r;
- vec4 emission = texture1D(spectrum_texture, flame);
- color.rgb += (1 - color.a) * emission.a * emission.rgb;
-#endif
-
gl_FragColor = color;
}
diff --git a/source/blender/gpu/shaders/gpu_shader_vertex.glsl b/source/blender/gpu/shaders/gpu_shader_vertex.glsl
index 7e332706695..db0068d2f3d 100644
--- a/source/blender/gpu/shaders/gpu_shader_vertex.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_vertex.glsl
@@ -14,6 +14,74 @@ varying vec3 varnormal;
varying float gl_ClipDistance[6];
#endif
+
+/* Color, keep in sync with: gpu_shader_vertex_world.glsl */
+
+float srgb_to_linearrgb(float c)
+{
+ if (c < 0.04045)
+ return (c < 0.0) ? 0.0 : c * (1.0 / 12.92);
+ else
+ return pow((c + 0.055) * (1.0 / 1.055), 2.4);
+}
+
+void srgb_to_linearrgb(vec3 col_from, out vec3 col_to)
+{
+ col_to.r = srgb_to_linearrgb(col_from.r);
+ col_to.g = srgb_to_linearrgb(col_from.g);
+ col_to.b = srgb_to_linearrgb(col_from.b);
+}
+
+void srgb_to_linearrgb(vec4 col_from, out vec4 col_to)
+{
+ col_to.r = srgb_to_linearrgb(col_from.r);
+ col_to.g = srgb_to_linearrgb(col_from.g);
+ col_to.b = srgb_to_linearrgb(col_from.b);
+ col_to.a = col_from.a;
+}
+
+bool is_srgb(int info)
+{
+#ifdef USE_NEW_SHADING
+ return (info == 1)? true: false;
+#else
+ return false;
+#endif
+}
+
+void set_var_from_attr(float attr, int info, out float var)
+{
+ var = attr;
+}
+
+void set_var_from_attr(vec2 attr, int info, out vec2 var)
+{
+ var = attr;
+}
+
+void set_var_from_attr(vec3 attr, int info, out vec3 var)
+{
+ if (is_srgb(info)) {
+ srgb_to_linearrgb(attr, var);
+ }
+ else {
+ var = attr;
+ }
+}
+
+void set_var_from_attr(vec4 attr, int info, out vec4 var)
+{
+ if (is_srgb(info)) {
+ srgb_to_linearrgb(attr, var);
+ }
+ else {
+ var = attr;
+ }
+}
+
+/* end color code */
+
+
void main()
{
#ifndef USE_OPENSUBDIV
@@ -29,7 +97,7 @@ void main()
#ifdef CLIP_WORKAROUND
int i;
- for(i = 0; i < 6; i++)
+ for (i = 0; i < 6; i++)
gl_ClipDistance[i] = dot(co, gl_ClipPlane[i]);
#elif !defined(GPU_ATI)
// Setting gl_ClipVertex is necessary to get glClipPlane working on NVIDIA
diff --git a/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl b/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl
index 9dbcaeb7a32..d45a4b316a8 100644
--- a/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl
@@ -2,6 +2,74 @@
varying vec3 varposition;
varying vec3 varnormal;
+
+/* Color, keep in sync with: gpu_shader_vertex.glsl */
+
+float srgb_to_linearrgb(float c)
+{
+ if (c < 0.04045)
+ return (c < 0.0) ? 0.0 : c * (1.0 / 12.92);
+ else
+ return pow((c + 0.055) * (1.0 / 1.055), 2.4);
+}
+
+void srgb_to_linearrgb(vec3 col_from, out vec3 col_to)
+{
+ col_to.r = srgb_to_linearrgb(col_from.r);
+ col_to.g = srgb_to_linearrgb(col_from.g);
+ col_to.b = srgb_to_linearrgb(col_from.b);
+}
+
+void srgb_to_linearrgb(vec4 col_from, out vec4 col_to)
+{
+ col_to.r = srgb_to_linearrgb(col_from.r);
+ col_to.g = srgb_to_linearrgb(col_from.g);
+ col_to.b = srgb_to_linearrgb(col_from.b);
+ col_to.a = col_from.a;
+}
+
+bool is_srgb(int info)
+{
+#ifdef USE_NEW_SHADING
+ return (info == 1)? true: false;
+#else
+ return false;
+#endif
+}
+
+void set_var_from_attr(float attr, int info, out float var)
+{
+ var = attr;
+}
+
+void set_var_from_attr(vec2 attr, int info, out vec2 var)
+{
+ var = attr;
+}
+
+void set_var_from_attr(vec3 attr, int info, out vec3 var)
+{
+ if (is_srgb(info)) {
+ srgb_to_linearrgb(attr, var);
+ }
+ else {
+ var = attr;
+ }
+}
+
+void set_var_from_attr(vec4 attr, int info, out vec4 var)
+{
+ if (is_srgb(info)) {
+ srgb_to_linearrgb(attr, var);
+ }
+ else {
+ var = attr;
+ }
+}
+
+/* end color code */
+
+
void main()
{
/* position does not need to be transformed, we already have it */
diff --git a/source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl b/source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl
index 4838289ff9e..3761bf350eb 100644
--- a/source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl
@@ -15,7 +15,7 @@ void main()
// Adjusting moments using partial derivative
float dx = dFdx(depth);
float dy = dFdy(depth);
- moment2 += 0.25*(dx*dx+dy*dy);
+ moment2 += 0.25 * (dx * dx + dy * dy);
gl_FragColor = vec4(moment1, moment2, 0.0, 0.0);
}
diff --git a/source/blender/ikplugin/intern/iksolver_plugin.c b/source/blender/ikplugin/intern/iksolver_plugin.c
index b3c83bffb3f..6ea311b2c7b 100644
--- a/source/blender/ikplugin/intern/iksolver_plugin.c
+++ b/source/blender/ikplugin/intern/iksolver_plugin.c
@@ -50,6 +50,8 @@
#include <string.h> /* memcpy */
+#define USE_NONUNIFORM_SCALE
+
/* ********************** THE IK SOLVER ******************* */
/* allocates PoseTree, and links that to root bone/channel */
@@ -525,10 +527,10 @@ void iksolver_initialize_tree(struct Scene *UNUSED(scene), struct Object *ob, fl
ob->pose->flag &= ~POSE_WAS_REBUILT;
}
-void iksolver_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime)
+void iksolver_execute_tree(struct Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime)
{
- while (pchan->iktree.first) {
- PoseTree *tree = pchan->iktree.first;
+ while (pchan_root->iktree.first) {
+ PoseTree *tree = pchan_root->iktree.first;
int a;
/* stop on the first tree that isn't a standard IK chain */
@@ -542,6 +544,19 @@ void iksolver_execute_tree(struct Scene *scene, struct Object *ob, struct bPose
/* tell blender that this channel was controlled by IK, it's cleared on each BKE_pose_where_is() */
tree->pchan[a]->flag |= POSE_CHAIN;
}
+
+#ifdef USE_NONUNIFORM_SCALE
+ float (*pchan_scale_data)[3] = MEM_mallocN(sizeof(float[3]) * tree->totchannel, __func__);
+
+ for (a = 0; a < tree->totchannel; a++) {
+ mat4_to_size(pchan_scale_data[a], tree->pchan[a]->pose_mat);
+
+ /* make uniform at y scale since this controls the length */
+ normalize_v3_length(tree->pchan[a]->pose_mat[0], pchan_scale_data[a][1]);
+ normalize_v3_length(tree->pchan[a]->pose_mat[2], pchan_scale_data[a][1]);
+ }
+#endif
+
/* 5. execute the IK solver */
execute_posetree(scene, ob, tree);
@@ -556,8 +571,16 @@ void iksolver_execute_tree(struct Scene *scene, struct Object *ob, struct bPose
where_is_ik_bone(tree->pchan[a], tree->basis_change[a]);
}
+#ifdef USE_NONUNIFORM_SCALE
+ for (a = 0; a < tree->totchannel; a++) {
+ normalize_v3_length(tree->pchan[a]->pose_mat[0], pchan_scale_data[a][0]);
+ normalize_v3_length(tree->pchan[a]->pose_mat[2], pchan_scale_data[a][2]);
+ }
+ MEM_freeN(pchan_scale_data);
+#endif
+
/* 7. and free */
- BLI_remlink(&pchan->iktree, tree);
+ BLI_remlink(&pchan_root->iktree, tree);
free_posetree(tree);
}
}
diff --git a/source/blender/ikplugin/intern/iksolver_plugin.h b/source/blender/ikplugin/intern/iksolver_plugin.h
index c2ae4f937e7..07264280a25 100644
--- a/source/blender/ikplugin/intern/iksolver_plugin.h
+++ b/source/blender/ikplugin/intern/iksolver_plugin.h
@@ -41,7 +41,7 @@ extern "C" {
#endif
void iksolver_initialize_tree(struct Scene *scene, struct Object *ob, float ctime);
-void iksolver_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime);
+void iksolver_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan_root, float ctime);
#ifdef __cplusplus
}
diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp
index d4814a4e3a2..b8ed780397f 100644
--- a/source/blender/ikplugin/intern/itasc_plugin.cpp
+++ b/source/blender/ikplugin/intern/itasc_plugin.cpp
@@ -1770,7 +1770,7 @@ void itasc_initialize_tree(struct Scene *scene, Object *ob, float ctime)
ob->pose->flag &= ~POSE_WAS_REBUILT;
}
-void itasc_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime)
+void itasc_execute_tree(struct Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime)
{
if (!ob->pose->ikdata) {
// IK tree not yet created, no it now
@@ -1784,7 +1784,7 @@ void itasc_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseCha
if (!ikparam) ikparam = &DefIKParam;
for (IK_Scene *ikscene = ikdata->first; ikscene; ikscene = ikscene->next) {
- if (ikscene->channels[0].pchan == pchan) {
+ if (ikscene->channels[0].pchan == pchan_root) {
float timestep = scene->r.frs_sec_base / scene->r.frs_sec;
if (ob->pose->flag & POSE_GAME_ENGINE) {
timestep = ob->pose->ctime;
diff --git a/source/blender/ikplugin/intern/itasc_plugin.h b/source/blender/ikplugin/intern/itasc_plugin.h
index 0500125b4c7..bcd95bc31ca 100644
--- a/source/blender/ikplugin/intern/itasc_plugin.h
+++ b/source/blender/ikplugin/intern/itasc_plugin.h
@@ -41,7 +41,7 @@ extern "C" {
#endif
void itasc_initialize_tree(struct Scene *scene, struct Object *ob, float ctime);
-void itasc_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime);
+void itasc_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan_root, float ctime);
void itasc_release_tree(struct Scene *scene, struct Object *ob, float ctime);
void itasc_clear_data(struct bPose *pose);
void itasc_clear_cache(struct bPose *pose);
diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h
index f4763883489..d89393b9903 100644
--- a/source/blender/imbuf/intern/IMB_anim.h
+++ b/source/blender/imbuf/intern/IMB_anim.h
@@ -83,18 +83,10 @@
# include <libswscale/swscale.h>
#endif
-/* actually hard coded endianness */
-#define GET_BIG_LONG(x) (((uchar *) (x))[0] << 24 | ((uchar *) (x))[1] << 16 | ((uchar *) (x))[2] << 8 | ((uchar *) (x))[3])
-#define GET_LITTLE_LONG(x) (((uchar *) (x))[3] << 24 | ((uchar *) (x))[2] << 16 | ((uchar *) (x))[1] << 8 | ((uchar *) (x))[0])
-#define SWAP_L(x) (((x << 24) & 0xff000000) | ((x << 8) & 0xff0000) | ((x >> 8) & 0xff00) | ((x >> 24) & 0xff))
-#define SWAP_S(x) (((x << 8) & 0xff00) | ((x >> 8) & 0xff))
-
/* more endianness... should move to a separate file... */
#ifdef __BIG_ENDIAN__
-# define GET_ID GET_BIG_LONG
# define LITTLE_LONG SWAP_LONG
#else
-# define GET_ID GET_LITTLE_LONG
# define LITTLE_LONG ENDIAN_NOP
#endif
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index d378ca9a78c..a40b257b75b 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -522,9 +522,9 @@ static int startffmpeg(struct anim *anim)
anim->duration = pFormatCtx->streams[videoStream]->nb_frames;
}
else {
- anim->duration = ceil(pFormatCtx->duration *
- av_q2d(frame_rate) /
- AV_TIME_BASE);
+ anim->duration = (int)(pFormatCtx->duration *
+ av_q2d(frame_rate) /
+ AV_TIME_BASE + 0.5f);
}
frs_num = frame_rate.num;
diff --git a/source/blender/imbuf/intern/cineon/logImageCore.c b/source/blender/imbuf/intern/cineon/logImageCore.c
index 5ec0a87890c..6fb1bccf491 100644
--- a/source/blender/imbuf/intern/cineon/logImageCore.c
+++ b/source/blender/imbuf/intern/cineon/logImageCore.c
@@ -296,10 +296,11 @@ static int logImageSetData10(LogImageFile *logImage, LogImageElement logElement,
row[index] = swap_uint(pixel, logImage->isMSB);
if (logimage_fwrite(row, rowLength, 1, logImage) == 0) {
- if (verbose) printf("DPX/Cineon: Error while writing file.\n"); {
- MEM_freeN(row);
- return 1;
+ if (verbose) {
+ printf("DPX/Cineon: Error while writing file.\n");
}
+ MEM_freeN(row);
+ return 1;
}
}
MEM_freeN(row);
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index 41812872f11..01348549bc4 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -3268,6 +3268,13 @@ bool IMB_colormanagement_setup_glsl_draw_from_space(const ColorManagedViewSettin
update_glsl_display_processor(applied_view_settings, display_settings,
from_colorspace ? from_colorspace->name : global_role_scene_linear);
+ if (global_glsl_state.processor == NULL) {
+ /* Happens when requesting non-existing color space or LUT in the
+ * configuration file does not exist.
+ */
+ return false;
+ }
+
return OCIO_setupGLSLDraw(&global_glsl_state.ocio_glsl_state, global_glsl_state.processor,
global_glsl_state.use_curve_mapping ? &global_glsl_state.curve_mapping_settings : NULL,
dither, predivide);
@@ -3304,5 +3311,7 @@ bool IMB_colormanagement_setup_glsl_draw_ctx(const bContext *C, float dither, bo
/* Finish GLSL-based display space conversion */
void IMB_colormanagement_finish_glsl_draw(void)
{
- OCIO_finishGLSLDraw(global_glsl_state.ocio_glsl_state);
+ if (global_glsl_state.ocio_glsl_state != NULL) {
+ OCIO_finishGLSLDraw(global_glsl_state.ocio_glsl_state);
+ }
}
diff --git a/source/blender/imbuf/intern/filter.c b/source/blender/imbuf/intern/filter.c
index 26ced49a333..1987c6d2a9a 100644
--- a/source/blender/imbuf/intern/filter.c
+++ b/source/blender/imbuf/intern/filter.c
@@ -206,7 +206,7 @@ void imb_filterx(struct ImBuf *ibuf)
static void imb_filterN(ImBuf *out, ImBuf *in)
{
BLI_assert(out->channels == in->channels);
- BLI_assert(out->x == in->x && out->y == out->y);
+ BLI_assert(out->x == in->x && out->y == in->y);
const int channels = in->channels;
const int rowlen = in->x;
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index fdadb783815..89e796fb7ee 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -77,7 +77,7 @@ extern "C"
{
// The following prevents a linking error in debug mode for MSVC using the libs in CVS
-#if defined(WITH_OPENEXR) && defined(_WIN32) && defined(DEBUG) && !defined(__MINGW32__)
+#if defined(WITH_OPENEXR) && defined(_WIN32) && defined(DEBUG) && !defined(__MINGW32__) && _MSC_VER < 1900
_CRTIMP void __cdecl _invalid_parameter_noinfo(void)
{
}
@@ -127,7 +127,7 @@ class Mem_IStream : public Imf::IStream
{
public:
- Mem_IStream (unsigned char *exrbuf, size_t exrsize) :
+ Mem_IStream(unsigned char *exrbuf, size_t exrsize) :
IStream("dummy"), _exrpos(0), _exrsize(exrsize)
{
_exrbuf = exrbuf;
diff --git a/source/blender/imbuf/intern/stereoimbuf.c b/source/blender/imbuf/intern/stereoimbuf.c
index a55cef60943..a4418443790 100644
--- a/source/blender/imbuf/intern/stereoimbuf.c
+++ b/source/blender/imbuf/intern/stereoimbuf.c
@@ -117,7 +117,7 @@ static void imb_stereo3d_write_anaglyph(Stereo3DData *s3d, enum eStereo3dAnaglyp
to[0] = from[r][0];
to[1] = from[g][1];
to[2] = from[b][2];
- to[3] = MAX2(from[0][3], from[0][3]);
+ to[3] = MAX2(from[0][3], from[1][3]);
}
}
}
@@ -154,7 +154,7 @@ static void imb_stereo3d_write_anaglyph(Stereo3DData *s3d, enum eStereo3dAnaglyp
to[0] = from[r][0];
to[1] = from[g][1];
to[2] = from[b][2];
- to[3] = MAX2(from[0][3], from[0][3]);
+ to[3] = MAX2(from[0][3], from[1][3]);
}
}
}
diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c
index 95d061bcb75..3629332a4ac 100644
--- a/source/blender/imbuf/intern/thumbs.c
+++ b/source/blender/imbuf/intern/thumbs.c
@@ -46,6 +46,8 @@
#include "BLO_readfile.h"
+#include "DNA_space_types.h" /* For FILE_MAX_LIBEXTRA */
+
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
#include "IMB_thumbs.h"
@@ -533,7 +535,7 @@ ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source
char thumb_path[FILE_MAX];
char thumb_name[40];
char uri[URI_MAX];
- char path_buff[FILE_MAX];
+ char path_buff[FILE_MAX_LIBEXTRA];
const char *file_path;
const char *path;
BLI_stat_t st;
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index 0bf3c350263..feeb2d5e4d7 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -142,7 +142,6 @@ typedef struct ID {
*/
typedef struct Library {
ID id;
- ID *idblock;
struct FileData *filedata;
char name[1024]; /* path name used for reading, can be relative and edited in the outliner */
@@ -155,6 +154,9 @@ typedef struct Library {
struct Library *parent; /* set for indirectly linked libs, used in the outliner and while reading */
struct PackedFile *packedfile;
+
+ int temp_index;
+ int _pad;
} Library;
enum eIconSizes {
@@ -170,6 +172,13 @@ enum ePreviewImage_Flag {
PRV_USER_EDITED = (1 << 1), /* if user-edited, do not auto-update this anymore! */
};
+/* for PreviewImage->tag */
+enum {
+ PRV_TAG_DEFFERED = (1 << 0), /* Actual loading of preview is deffered. */
+ PRV_TAG_DEFFERED_RENDERING = (1 << 1), /* Deffered preview is being loaded. */
+ PRV_TAG_DEFFERED_DELETE = (1 << 2), /* Deffered preview should be deleted asap. */
+};
+
typedef struct PreviewImage {
/* All values of 2 are really NUM_ICON_SIZES */
unsigned int w[2];
@@ -182,12 +191,12 @@ typedef struct PreviewImage {
struct GPUTexture *gputexture[2];
int icon_id; /* Used by previews outside of ID context. */
- char pad[3];
- char use_deferred; /* for now a mere bool, if we add more deferred loading methods we can switch to bitflag. */
+ short tag; /* Runtime data. */
+ char pad[2];
} PreviewImage;
#define PRV_DEFERRED_DATA(prv) \
- (CHECK_TYPE_INLINE(prv, PreviewImage *), BLI_assert((prv)->use_deferred), (void *)((prv) + 1))
+ (CHECK_TYPE_INLINE(prv, PreviewImage *), BLI_assert((prv)->tag & PRV_TAG_DEFFERED), (void *)((prv) + 1))
/**
* Defines for working with IDs.
@@ -211,43 +220,50 @@ typedef struct PreviewImage {
* Written to #BHead.code (for file IO)
* and the first 2 bytes of #ID.name (for runtime checks, see #GS macro).
*/
-#define ID_SCE MAKE_ID2('S', 'C') /* Scene */
-#define ID_LI MAKE_ID2('L', 'I') /* Library */
-#define ID_OB MAKE_ID2('O', 'B') /* Object */
-#define ID_ME MAKE_ID2('M', 'E') /* Mesh */
-#define ID_CU MAKE_ID2('C', 'U') /* Curve */
-#define ID_MB MAKE_ID2('M', 'B') /* MetaBall */
-#define ID_MA MAKE_ID2('M', 'A') /* Material */
-#define ID_TE MAKE_ID2('T', 'E') /* Tex (Texture) */
-#define ID_IM MAKE_ID2('I', 'M') /* Image */
-#define ID_LT MAKE_ID2('L', 'T') /* Lattice */
-#define ID_LA MAKE_ID2('L', 'A') /* Lamp */
-#define ID_CA MAKE_ID2('C', 'A') /* Camera */
-#define ID_IP MAKE_ID2('I', 'P') /* Ipo (depreciated, replaced by FCurves) */
-#define ID_KE MAKE_ID2('K', 'E') /* Key (shape key) */
-#define ID_WO MAKE_ID2('W', 'O') /* World */
-#define ID_SCR MAKE_ID2('S', 'R') /* Screen */
-#define ID_SCRN MAKE_ID2('S', 'N') /* (depreciated?) */
-#define ID_VF MAKE_ID2('V', 'F') /* VFont (Vector Font) */
-#define ID_TXT MAKE_ID2('T', 'X') /* Text */
-#define ID_SPK MAKE_ID2('S', 'K') /* Speaker */
-#define ID_SO MAKE_ID2('S', 'O') /* Sound */
-#define ID_GR MAKE_ID2('G', 'R') /* Group */
-#define ID_ID MAKE_ID2('I', 'D') /* (internal use only) */
-#define ID_AR MAKE_ID2('A', 'R') /* bArmature */
-#define ID_AC MAKE_ID2('A', 'C') /* bAction */
-#define ID_NT MAKE_ID2('N', 'T') /* bNodeTree */
-#define ID_BR MAKE_ID2('B', 'R') /* Brush */
-#define ID_PA MAKE_ID2('P', 'A') /* ParticleSettings */
-#define ID_GD MAKE_ID2('G', 'D') /* bGPdata, (Grease Pencil) */
-#define ID_WM MAKE_ID2('W', 'M') /* WindowManager */
-#define ID_MC MAKE_ID2('M', 'C') /* MovieClip */
-#define ID_MSK MAKE_ID2('M', 'S') /* Mask */
-#define ID_LS MAKE_ID2('L', 'S') /* FreestyleLineStyle */
-#define ID_PAL MAKE_ID2('P', 'L') /* Palette */
-#define ID_PC MAKE_ID2('P', 'C') /* PaintCurve */
-
- /* NOTE! Fake IDs, needed for g.sipo->blocktype or outliner */
+typedef enum ID_Type {
+ ID_SCE = MAKE_ID2('S', 'C'), /* Scene */
+ ID_LI = MAKE_ID2('L', 'I'), /* Library */
+ ID_OB = MAKE_ID2('O', 'B'), /* Object */
+ ID_ME = MAKE_ID2('M', 'E'), /* Mesh */
+ ID_CU = MAKE_ID2('C', 'U'), /* Curve */
+ ID_MB = MAKE_ID2('M', 'B'), /* MetaBall */
+ ID_MA = MAKE_ID2('M', 'A'), /* Material */
+ ID_TE = MAKE_ID2('T', 'E'), /* Tex (Texture) */
+ ID_IM = MAKE_ID2('I', 'M'), /* Image */
+ ID_LT = MAKE_ID2('L', 'T'), /* Lattice */
+ ID_LA = MAKE_ID2('L', 'A'), /* Lamp */
+ ID_CA = MAKE_ID2('C', 'A'), /* Camera */
+ ID_IP = MAKE_ID2('I', 'P'), /* Ipo (depreciated, replaced by FCurves) */
+ ID_KE = MAKE_ID2('K', 'E'), /* Key (shape key) */
+ ID_WO = MAKE_ID2('W', 'O'), /* World */
+ ID_SCR = MAKE_ID2('S', 'R'), /* Screen */
+ ID_VF = MAKE_ID2('V', 'F'), /* VFont (Vector Font) */
+ ID_TXT = MAKE_ID2('T', 'X'), /* Text */
+ ID_SPK = MAKE_ID2('S', 'K'), /* Speaker */
+ ID_SO = MAKE_ID2('S', 'O'), /* Sound */
+ ID_GR = MAKE_ID2('G', 'R'), /* Group */
+ ID_AR = MAKE_ID2('A', 'R'), /* bArmature */
+ ID_AC = MAKE_ID2('A', 'C'), /* bAction */
+ ID_NT = MAKE_ID2('N', 'T'), /* bNodeTree */
+ ID_BR = MAKE_ID2('B', 'R'), /* Brush */
+ ID_PA = MAKE_ID2('P', 'A'), /* ParticleSettings */
+ ID_GD = MAKE_ID2('G', 'D'), /* bGPdata, (Grease Pencil) */
+ ID_WM = MAKE_ID2('W', 'M'), /* WindowManager */
+ ID_MC = MAKE_ID2('M', 'C'), /* MovieClip */
+ ID_MSK = MAKE_ID2('M', 'S'), /* Mask */
+ ID_LS = MAKE_ID2('L', 'S'), /* FreestyleLineStyle */
+ ID_PAL = MAKE_ID2('P', 'L'), /* Palette */
+ ID_PC = MAKE_ID2('P', 'C'), /* PaintCurve */
+ ID_CF = MAKE_ID2('C', 'F'), /* CacheFile */
+} ID_Type;
+
+/* Only used as 'placeholder' in .blend files for directly linked datablocks. */
+#define ID_ID MAKE_ID2('I', 'D') /* (internal use only) */
+
+/* Deprecated. */
+#define ID_SCRN MAKE_ID2('S', 'N')
+
+/* NOTE! Fake IDs, needed for g.sipo->blocktype or outliner */
#define ID_SEQ MAKE_ID2('S', 'Q')
/* constraint */
#define ID_CO MAKE_ID2('C', 'O')
@@ -267,6 +283,8 @@ typedef struct PreviewImage {
#define ID_MISSING(_id) (((_id)->tag & LIB_TAG_MISSING) != 0)
+#define ID_IS_LINKED_DATABLOCK(_id) (((ID *)(_id))->lib != NULL)
+
#ifdef GS
# undef GS
#endif
@@ -367,6 +385,47 @@ enum {
FILTER_ID_VF = (1 << 25),
FILTER_ID_WO = (1 << 26),
FILTER_ID_PA = (1 << 27),
+ FILTER_ID_CF = (1 << 28),
+};
+
+/* IMPORTANT: this enum matches the order currently use in set_lisbasepointers,
+ * keep them in sync! */
+enum {
+ INDEX_ID_LI = 0,
+ INDEX_ID_IP,
+ INDEX_ID_AC,
+ INDEX_ID_KE,
+ INDEX_ID_GD,
+ INDEX_ID_NT,
+ INDEX_ID_IM,
+ INDEX_ID_TE,
+ INDEX_ID_MA,
+ INDEX_ID_VF,
+ INDEX_ID_AR,
+ INDEX_ID_CF,
+ INDEX_ID_ME,
+ INDEX_ID_CU,
+ INDEX_ID_MB,
+ INDEX_ID_LT,
+ INDEX_ID_LA,
+ INDEX_ID_CA,
+ INDEX_ID_TXT,
+ INDEX_ID_SO,
+ INDEX_ID_GR,
+ INDEX_ID_PAL,
+ INDEX_ID_PC,
+ INDEX_ID_BR,
+ INDEX_ID_PA,
+ INDEX_ID_SPK,
+ INDEX_ID_WO,
+ INDEX_ID_MC,
+ INDEX_ID_SCR,
+ INDEX_ID_OB,
+ INDEX_ID_LS,
+ INDEX_ID_SCE,
+ INDEX_ID_WM,
+ INDEX_ID_MSK,
+ INDEX_ID_NULL,
};
#ifdef __cplusplus
diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h
index 96d7ec3128c..f3df9090d41 100644
--- a/source/blender/makesdna/DNA_action_types.h
+++ b/source/blender/makesdna/DNA_action_types.h
@@ -199,7 +199,8 @@ typedef struct bPoseChannel {
char constflag; /* for quick detecting which constraints affect this channel */
char selectflag; /* copy of bone flag, so you can work with library armatures, not for runtime use */
char drawflag;
- char pad0[5];
+ char bboneflag;
+ char pad0[4];
struct Bone *bone; /* set on read file or rebuild pose */
struct bPoseChannel *parent; /* set on read file or rebuild pose */
@@ -242,7 +243,16 @@ typedef struct bPoseChannel {
float ikstretch;
float ikrotweight; /* weight of joint rotation constraint */
float iklinweight; /* weight of joint stretch constraint */
-
+
+ /* curved bones settings - these are for animating, and are applied on top of the copies in pchan->bone */
+ float roll1, roll2;
+ float curveInX, curveInY;
+ float curveOutX, curveOutY;
+ float scaleIn, scaleOut;
+
+ struct bPoseChannel *bbone_prev; /* next/prev bones to use as handle references when calculating bbones (optional) */
+ struct bPoseChannel *bbone_next;
+
void *temp; /* use for outliner */
} bPoseChannel;
@@ -253,17 +263,17 @@ typedef enum ePchan_Flag {
POSE_LOC = (1 << 0),
POSE_ROT = (1 << 1),
POSE_SIZE = (1 << 2),
- /* old IK/cache stuff... */
-#if 0
- POSE_IK_MAT = (1 << 3),
- POSE_UNUSED2 = (1 << 4),
- POSE_UNUSED3 = (1 << 5),
- POSE_UNUSED4 = (1 << 6),
- POSE_UNUSED5 = (1 << 7),
- /* has Standard IK */
- POSE_HAS_IK = (1 << 8),
-#endif
- /* IK/Pose solving*/
+
+ /* old IK/cache stuff
+ * - used to be here from (1 << 3) to (1 << 8)
+ * but has been repurposed since 2.77.2
+ * as they haven't been used in over 10 years
+ */
+
+ /* has BBone deforms */
+ POSE_BBONE_SHAPE = (1 << 3),
+
+ /* IK/Pose solving */
POSE_CHAIN = (1 << 9),
POSE_DONE = (1 << 10),
/* visualization */
@@ -318,6 +328,16 @@ typedef enum ePchan_DrawFlag {
#define PCHAN_CUSTOM_DRAW_SIZE(pchan) \
(pchan)->custom_scale * (((pchan)->drawflag & PCHAN_DRAW_NO_CUSTOM_BONE_SIZE) ? 1.0f : (pchan)->bone->length)
+/* PoseChannel->bboneflag */
+typedef enum ePchan_BBoneFlag {
+ /* Use custom reference bones (for roll and handle alignment), instead of immediate neighbors */
+ PCHAN_BBONE_CUSTOM_HANDLES = (1 << 1),
+ /* Evaluate start handle as being "relative" */
+ PCHAN_BBONE_CUSTOM_START_REL = (1 << 2),
+ /* Evaluate end handle as being "relative" */
+ PCHAN_BBONE_CUSTOM_END_REL = (1 << 3),
+} ePchan_BBoneFlag;
+
/* PoseChannel->rotmode and Object->rotmode */
typedef enum eRotationModes {
/* quaternion rotations (default, and for older Blender versions) */
@@ -607,8 +627,9 @@ typedef enum eDopeSheet_FilterFlag {
typedef enum eDopeSheet_Flag {
ADS_FLAG_SUMMARY_COLLAPSED = (1 << 0), /* when summary is shown, it is collapsed, so all other channels get hidden */
ADS_FLAG_SHOW_DBFILTERS = (1 << 1), /* show filters for datablocks */
-
+
ADS_FLAG_FUZZY_NAMES = (1 << 2), /* use fuzzy/partial string matches when ADS_FILTER_BY_FCU_NAME is enabled (WARNING: expensive operation) */
+ ADS_FLAG_NO_DB_SORT = (1 << 3), /* do not sort datablocks (mostly objects) by name (NOTE: potentially expensive operation) */
/* NOTE: datablock filter flags continued (1 << 10) onwards... */
} eDopeSheet_Flag;
@@ -673,7 +694,9 @@ typedef enum eAnimEdit_Context {
/* dopesheet (default) */
SACTCONT_DOPESHEET = 3,
/* mask */
- SACTCONT_MASK = 4
+ SACTCONT_MASK = 4,
+ /* cache file */
+ SACTCONT_CACHEFILE = 5,
} eAnimEdit_Context;
/* SpaceAction AutoSnap Settings (also used by other Animation Editors) */
diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h
index fdad6aae094..e50a2637fff 100644
--- a/source/blender/makesdna/DNA_anim_types.h
+++ b/source/blender/makesdna/DNA_anim_types.h
@@ -450,7 +450,9 @@ typedef enum eDriver_Flags {
/* the names are cached so they don't need have python unicode versions created each time */
DRIVER_FLAG_RENAMEVAR = (1<<4),
/* intermediate values of driver should be shown in the UI for debugging purposes */
- DRIVER_FLAG_SHOWDEBUG = (1<<5)
+ DRIVER_FLAG_SHOWDEBUG = (1<<5),
+ /* include 'self' in the drivers namespace. */
+ DRIVER_FLAG_USE_SELF = (1<<6),
} eDriver_Flags;
/* F-Curves -------------------------------------- */
@@ -484,7 +486,7 @@ typedef struct FCurve {
unsigned int totvert; /* total number of points which define the curve (i.e. size of arrays in FPoints) */
/* value cache + settings */
- float curval; /* value stored from last time curve was evaluated */
+ float curval; /* value stored from last time curve was evaluated (not threadsafe, debug display only!) */
short flag; /* user-editable settings for this curve */
short extend; /* value-extending mode for this curve (does not cover */
@@ -537,8 +539,9 @@ typedef enum eFCurve_Extend {
/* curve coloring modes */
typedef enum eFCurve_Coloring {
FCURVE_COLOR_AUTO_RAINBOW = 0, /* automatically determine color using rainbow (calculated at drawtime) */
- FCURVE_COLOR_AUTO_RGB, /* automatically determine color using XYZ (array index) <-> RGB */
- FCURVE_COLOR_CUSTOM /* custom color */
+ FCURVE_COLOR_AUTO_RGB = 1, /* automatically determine color using XYZ (array index) <-> RGB */
+ FCURVE_COLOR_AUTO_YRGB = 3, /* automatically determine color where XYZ <-> RGB, but index(X) != 0 */
+ FCURVE_COLOR_CUSTOM = 2, /* custom color */
} eFCurve_Coloring;
/* ************************************************ */
@@ -936,7 +939,10 @@ typedef enum eAnimData_Flag {
ADT_UI_ACTIVE = (1<<15),
/* F-Curves from this AnimData block are not visible in the Graph Editor */
- ADT_CURVES_NOT_VISIBLE = (1<<16)
+ ADT_CURVES_NOT_VISIBLE = (1<<16),
+
+ /* F-Curves from this AnimData block are always visible */
+ ADT_CURVES_ALWAYS_VISIBLE = (1<<17),
} eAnimData_Flag;
/* Animation Data recalculation settings (to be set by depsgraph) */
diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h
index b995e6917a9..cda6441f0ae 100644
--- a/source/blender/makesdna/DNA_armature_types.h
+++ b/source/blender/makesdna/DNA_armature_types.h
@@ -68,11 +68,18 @@ typedef struct Bone {
float xwidth, length, zwidth; /* width: for block bones. keep in this order, transform! */
float ease1, ease2; /* length of bezier handles */
float rad_head, rad_tail; /* radius for head/tail sphere, defining deform as well, parent->rad_tip overrides rad_head */
-
+
+ float roll1, roll2; /* curved bones settings - these define the "restpose" for a curved bone */
+ float curveInX, curveInY;
+ float curveOutX, curveOutY;
+ float scaleIn, scaleOut;
+
float size[3]; /* patch for upward compat, UNUSED! */
int layer; /* layers that bone appears on */
short segments; /* for B-bones */
- short pad[1];
+
+ short pad1;
+
} Bone;
typedef struct bArmature {
@@ -204,7 +211,8 @@ typedef enum eBone_Flag {
BONE_TRANSFORM_CHILD = (1 << 20), /* Indicates that a parent is also being transformed */
BONE_UNSELECTABLE = (1 << 21), /* bone cannot be selected */
BONE_NO_LOCAL_LOCATION = (1 << 22), /* bone location is in armature space */
- BONE_RELATIVE_PARENTING = (1 << 23) /* object child will use relative transform (like deform) */
+ BONE_RELATIVE_PARENTING = (1 << 23), /* object child will use relative transform (like deform) */
+ BONE_ADD_PARENT_END_ROLL = (1 << 24) /* it will add the parent end roll to the inroll */
} eBone_Flag;
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 3dca087c7fa..f4a1677efc4 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -4,7 +4,7 @@
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
+ * of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -70,7 +70,6 @@ typedef struct Brush {
float normal_weight;
float rake_factor; /* rake actual data (not texture), used for sculpt */
- int pad;
short blend; /* blend mode */
short ob_mode; /* & with ob->mode to see if the brush is compatible, use for display only. */
@@ -95,7 +94,6 @@ typedef struct Brush {
float plane_offset; /* offset for plane brushes (clay, flatten, fill, scrape) */
- int flag2;
int gradient_spacing;
int gradient_stroke_mode; /* source for stroke color gradient application */
int gradient_fill_mode; /* source for fill tool color gradient application */
@@ -104,7 +102,7 @@ typedef struct Brush {
char vertexpaint_tool; /* active vertex/weight paint blend mode (poorly named) */
char imagepaint_tool; /* active image paint tool */
char mask_tool; /* enum BrushMaskTool, only used if sculpt_tool is SCULPT_TOOL_MASK */
-
+
float autosmooth_factor;
float crease_pinch_factor;
@@ -333,5 +331,4 @@ typedef enum BlurKernelType {
#define MAX_BRUSH_PIXEL_RADIUS 500
-#endif
-
+#endif /* __DNA_BRUSH_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_cachefile_types.h b/source/blender/makesdna/DNA_cachefile_types.h
new file mode 100644
index 00000000000..46b1adf2725
--- /dev/null
+++ b/source/blender/makesdna/DNA_cachefile_types.h
@@ -0,0 +1,85 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Kevin Dietrich.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file DNA_cachefile_types.h
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_CACHEFILE_TYPES_H__
+#define __DNA_CACHEFILE_TYPES_H__
+
+#include "DNA_ID.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* CacheFile::flag */
+enum {
+ CACHEFILE_DS_EXPAND = (1 << 0),
+ CACHEFILE_DIRTY = (1 << 1),
+};
+
+/* CacheFile::draw_flag */
+enum {
+ CACHEFILE_KEYFRAME_DRAWN = (1 << 0),
+};
+
+typedef struct AlembicObjectPath {
+ struct AlembicObjectPath *next, *prev;
+
+ char path[1024]; /* 1024 = FILE_MAX, might use PATH_MAX in the future. */
+} AlembicObjectPath;
+
+typedef struct CacheFile {
+ ID id;
+ struct AnimData *adt;
+
+ struct AbcArchiveHandle *handle;
+ void *handle_mutex;
+
+ /* Paths of the objects inside of the Alembic archive referenced by this
+ * CacheFile. */
+ ListBase object_paths;
+
+ char filepath[1024]; /* 1024 = FILE_MAX */
+
+ char is_sequence;
+ char forward_axis;
+ char up_axis;
+ char override_frame;
+
+ float scale;
+ float frame; /* The frame/time to lookup in the cache file. */
+
+ short flag; /* Animation flag. */
+ short draw_flag;
+} CacheFile;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DNA_CACHEFILE_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_camera_types.h b/source/blender/makesdna/DNA_camera_types.h
index 7f2e1aaadf9..52e40cbc098 100644
--- a/source/blender/makesdna/DNA_camera_types.h
+++ b/source/blender/makesdna/DNA_camera_types.h
@@ -53,6 +53,10 @@ typedef struct CameraStereoSettings {
short pivot;
short flag;
short pad;
+ /* Cut-off angle at which interocular distance start to fade down. */
+ float pole_merge_angle_from;
+ /* Cut-off angle at which interocular distance stops to fade down. */
+ float pole_merge_angle_to;
} CameraStereoSettings;
typedef struct Camera {
@@ -81,8 +85,8 @@ typedef struct Camera {
char sensor_fit;
char pad[7];
- /* Stereo settings */
- struct CameraStereoSettings stereo;
+ /* Stereo settings */
+ struct CameraStereoSettings stereo;
} Camera;
/* **************** CAMERA ********************* */
@@ -152,6 +156,7 @@ enum {
/* stereo->flag */
enum {
CAM_S3D_SPHERICAL = (1 << 0),
+ CAM_S3D_POLE_MERGE = (1 << 1),
};
#ifdef __cplusplus
diff --git a/source/blender/makesdna/DNA_cloth_types.h b/source/blender/makesdna/DNA_cloth_types.h
index 07bc2478837..ee147da8dae 100644
--- a/source/blender/makesdna/DNA_cloth_types.h
+++ b/source/blender/makesdna/DNA_cloth_types.h
@@ -42,7 +42,7 @@
*
* I've tried to keep similar, if not exact names for the variables as
* are presented in the paper. Where I've changed the concept slightly,
- * as in stepsPerFrame comapred to the time step in the paper, I've used
+ * as in stepsPerFrame compared to the time step in the paper, I've used
* variables with different names to minimize confusion.
*/
@@ -63,6 +63,7 @@ typedef struct ClothSimSettings {
float max_sewing; /* max sewing force */
float avg_spring_len; /* used for normalized springs */
float timescale; /* parameter how fast cloth runs */
+ float time_scale; /* multiplies cloth speed */
float maxgoal; /* see SB */
float eff_force_scale;/* Scaling of effector forces (see softbody_calc_forces).*/
float eff_wind_scale; /* Scaling of effector wind (see softbody_calc_forces). */
@@ -98,6 +99,7 @@ typedef struct ClothSimSettings {
short presets; /* used for presets on GUI */
short reset;
+ char pad0[4];
struct EffectorWeights *effector_weights;
} ClothSimSettings;
diff --git a/source/blender/makesdna/DNA_color_types.h b/source/blender/makesdna/DNA_color_types.h
index c9a5e056e4a..f7ee1ff3915 100644
--- a/source/blender/makesdna/DNA_color_types.h
+++ b/source/blender/makesdna/DNA_color_types.h
@@ -49,7 +49,8 @@ typedef struct CurveMapPoint {
/* curvepoint->flag */
enum {
CUMA_SELECT = 1,
- CUMA_VECTOR = 2
+ CUMA_HANDLE_VECTOR = 2,
+ CUMA_HANDLE_AUTO_ANIM = 4,
};
typedef struct CurveMap {
@@ -157,10 +158,11 @@ typedef struct Scopes {
/* scopes->wavefrm_mode */
#define SCOPES_WAVEFRM_LUMA 0
-#define SCOPES_WAVEFRM_RGB 1
+#define SCOPES_WAVEFRM_RGB_PARADE 1
#define SCOPES_WAVEFRM_YCC_601 2
#define SCOPES_WAVEFRM_YCC_709 3
#define SCOPES_WAVEFRM_YCC_JPEG 4
+#define SCOPES_WAVEFRM_RGB 5
typedef struct ColorManagedViewSettings {
int flag, pad;
diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h
index 86991245068..ca774864e95 100644
--- a/source/blender/makesdna/DNA_constraint_types.h
+++ b/source/blender/makesdna/DNA_constraint_types.h
@@ -458,6 +458,13 @@ typedef struct bObjectSolverConstraint {
struct Object *camera;
} bObjectSolverConstraint;
+/* Transform matrix cache constraint */
+typedef struct bTransformCacheConstraint {
+ struct CacheFile *cache_file;
+ struct CacheReader *reader;
+ char object_path[1024]; /* FILE_MAX */
+} bTransformCacheConstraint;
+
/* ------------------------------------------ */
/* bConstraint->type
@@ -494,6 +501,7 @@ typedef enum eBConstraint_Types {
CONSTRAINT_TYPE_FOLLOWTRACK = 26, /* Follow Track Constraint */
CONSTRAINT_TYPE_CAMERASOLVER = 27, /* Camera Solver Constraint */
CONSTRAINT_TYPE_OBJECTSOLVER = 28, /* Object Solver Constraint */
+ CONSTRAINT_TYPE_TRANSFORM_CACHE = 29, /* Transform Cache Constraint */
/* NOTE: no constraints are allowed to be added after this */
NUM_CONSTRAINT_TYPES
@@ -516,7 +524,9 @@ typedef enum eBConstraint_Flags {
/* indicates that constraint was added locally (i.e. didn't come from the proxy-lib) */
CONSTRAINT_PROXY_LOCAL = (1<<8),
/* indicates that constraint is temporarily disabled (only used in GE) */
- CONSTRAINT_OFF = (1<<9)
+ CONSTRAINT_OFF = (1<<9),
+ /* use bbone curve shape when calculating headtail values */
+ CONSTRAINT_BBONE_SHAPE = (1<<10),
} eBConstraint_Flags;
/* bConstraint->ownspace/tarspace */
diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h
index 8f711c1b23b..902fa4ce987 100644
--- a/source/blender/makesdna/DNA_curve_types.h
+++ b/source/blender/makesdna/DNA_curve_types.h
@@ -230,7 +230,7 @@ typedef struct Curve {
/* font part */
short lines;
- char spacemode, pad1;
+ char spacemode, align_y;
float spacing, linedist, shear, fsize, wordspace, ulpos, ulheight;
float xof, yof;
float linewidth;
@@ -322,11 +322,19 @@ enum {
/* Curve.spacemode */
enum {
- CU_LEFT = 0,
- CU_MIDDLE = 1,
- CU_RIGHT = 2,
- CU_JUSTIFY = 3,
- CU_FLUSH = 4,
+ CU_ALIGN_X_LEFT = 0,
+ CU_ALIGN_X_MIDDLE = 1,
+ CU_ALIGN_X_RIGHT = 2,
+ CU_ALIGN_X_JUSTIFY = 3,
+ CU_ALIGN_X_FLUSH = 4,
+};
+
+/* Curve.align_y */
+enum {
+ CU_ALIGN_Y_TOP_BASELINE = 0,
+ CU_ALIGN_Y_TOP = 1,
+ CU_ALIGN_Y_CENTER = 2,
+ CU_ALIGN_Y_BOTTOM = 3,
};
/* Nurb.flag */
@@ -416,6 +424,7 @@ typedef enum eBezTriple_KeyframeType {
BEZT_KEYTYPE_EXTREME = 1, /* 'extreme' keyframe */
BEZT_KEYTYPE_BREAKDOWN = 2, /* 'breakdown' keyframe */
BEZT_KEYTYPE_JITTER = 3, /* 'jitter' keyframe (for adding 'filler' secondary motion) */
+ BEZT_KEYTYPE_MOVEHOLD = 4, /* one end of a 'moving hold' */
} eBezTriple_KeyframeType;
/* checks if the given BezTriple is selected */
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index 3807bb296fd..2d1ffaa53eb 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -75,6 +75,12 @@ typedef struct CustomData {
/* CustomData.type */
typedef enum CustomDataType {
+ /* Used by GLSL attributes in the cases when we need a delayed CD type
+ * assignment (in the cases when we don't know in advance which layer
+ * we are addressing).
+ */
+ CD_AUTO_FROM_NAME = -1,
+
CD_MVERT = 0,
#ifdef DNA_DEPRECATED
CD_MSTICKY = 1, /* DEPRECATED */
diff --git a/source/blender/makesdna/DNA_genfile.h b/source/blender/makesdna/DNA_genfile.h
index d62369803d6..9e9ab974b01 100644
--- a/source/blender/makesdna/DNA_genfile.h
+++ b/source/blender/makesdna/DNA_genfile.h
@@ -69,23 +69,39 @@ typedef enum eSDNA_Type {
* For use with #DNA_struct_reconstruct & #DNA_struct_get_compareflags
*/
enum eSDNA_StructCompare {
+ /* Struct has disappeared (values of this struct type will not be loaded by the current Blender) */
SDNA_CMP_REMOVED = 0,
+ /* Struct is the same (can be loaded with straight memory copy after any necessary endian conversion) */
SDNA_CMP_EQUAL = 1,
+ /* Struct is different in some way (needs to be copied/converted field by field) */
SDNA_CMP_NOT_EQUAL = 2,
};
-struct SDNA *DNA_sdna_from_data(const void *data, const int datalen, bool do_endian_swap);
+struct SDNA *DNA_sdna_from_data(
+ const void *data, const int datalen,
+ bool do_endian_swap, bool data_alloc,
+ const char **r_error_message);
void DNA_sdna_free(struct SDNA *sdna);
-int DNA_struct_find_nr(struct SDNA *sdna, const char *str);
-void DNA_struct_switch_endian(struct SDNA *oldsdna, int oldSDNAnr, char *data);
-char *DNA_struct_get_compareflags(struct SDNA *sdna, struct SDNA *newsdna);
-void *DNA_struct_reconstruct(struct SDNA *newsdna, struct SDNA *oldsdna, char *compflags, int oldSDNAnr, int blocks, void *data);
+/* Access for current Blender versions SDNA*/
+void DNA_sdna_current_init(void);
+/* borrowed reference */
+const struct SDNA *DNA_sdna_current_get(void);
+void DNA_sdna_current_free(void);
+
+int DNA_struct_find_nr_ex(const struct SDNA *sdna, const char *str, unsigned int *index_last);
+int DNA_struct_find_nr(const struct SDNA *sdna, const char *str);
+void DNA_struct_switch_endian(const struct SDNA *oldsdna, int oldSDNAnr, char *data);
+const char *DNA_struct_get_compareflags(const struct SDNA *sdna, const struct SDNA *newsdna);
+void *DNA_struct_reconstruct(
+ const struct SDNA *newsdna, const struct SDNA *oldsdna,
+ const char *compflags, int oldSDNAnr, int blocks, const void *data);
int DNA_elem_array_size(const char *str);
int DNA_elem_offset(struct SDNA *sdna, const char *stype, const char *vartype, const char *name);
-bool DNA_struct_elem_find(struct SDNA *sdna, const char *stype, const char *vartype, const char *name);
+bool DNA_struct_find(const struct SDNA *sdna, const char *stype);
+bool DNA_struct_elem_find(const struct SDNA *sdna, const char *stype, const char *vartype, const char *name);
int DNA_elem_type_size(const eSDNA_Type elem_nr);
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
index 41f53f9f51c..23b73424da5 100644
--- a/source/blender/makesdna/DNA_gpencil_types.h
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -18,7 +18,7 @@
* The Original Code is Copyright (C) 2008, Blender Foundation.
* This is a new part of Blender
*
- * Contributor(s): Joshua Leung
+ * Contributor(s): Joshua Leung, Antonio Vazquez
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -32,9 +32,10 @@
#include "DNA_listBase.h"
#include "DNA_ID.h"
+#include "DNA_brush_types.h"
struct AnimData;
-
+struct CurveMapping;
/* Grease-Pencil Annotations - 'Stroke Point'
* -> Coordinates may either be 2d or 3d depending on settings at the time
@@ -44,6 +45,7 @@ struct AnimData;
typedef struct bGPDspoint {
float x, y, z; /* co-ordinates of point (usually 2d, but can be 3d as well) */
float pressure; /* pressure of input device (from 0 to 1) at this point */
+ float strength; /* color strength (used for alpha factor) */
float time; /* seconds since start of stroke */
int flag; /* additional options (NOTE: can shrink this field down later if needed) */
} bGPDspoint;
@@ -65,24 +67,113 @@ typedef struct bGPDtriangle {
int v1, v2, v3; /* indices for tesselated triangle used for GP Fill */
} bGPDtriangle;
+/* GP brush (used for new strokes) */
+typedef struct bGPDbrush {
+ struct bGPDbrush *next, *prev;
+
+ char info[64]; /* Brush name. Must be unique. */
+ short thickness; /* thickness to apply to strokes */
+ short flag;
+ float draw_smoothfac; /* amount of smoothing to apply to newly created strokes */
+ short draw_smoothlvl; /* number of times to apply smooth factor to new strokes */
+ short sublevel; /* number of times to subdivide new strokes */
+
+ float draw_sensitivity; /* amount of sensivity to apply to newly created strokes */
+ float draw_strength; /* amount of alpha strength to apply to newly created strokes */
+ float draw_jitter; /* amount of jitter to apply to newly created strokes */
+ float draw_angle; /* angle when the brush has full thickness */
+ float draw_angle_factor; /* factor to apply when angle change (only 90 degrees) */
+ float draw_random_press; /* factor of randomness for sensitivity and strength */
+ float draw_random_sub; /* factor of randomness for subdivision */
+ struct CurveMapping *cur_sensitivity;
+ struct CurveMapping *cur_strength;
+ struct CurveMapping *cur_jitter;
+} bGPDbrush;
+
+/* bGPDbrush->flag */
+typedef enum eGPDbrush_Flag {
+ /* brush is active */
+ GP_BRUSH_ACTIVE = (1 << 0),
+ /* brush use pressure */
+ GP_BRUSH_USE_PRESSURE = (1 << 1),
+ /* brush use pressure for alpha factor */
+ GP_BRUSH_USE_STENGTH_PRESSURE = (1 << 2),
+ /* brush use pressure for alpha factor */
+ GP_BRUSH_USE_JITTER_PRESSURE = (1 << 3),
+ /* brush use random for pressure */
+ GP_BRUSH_USE_RANDOM_PRESSURE = (1 << 4),
+ /* brush use random for strength */
+ GP_BRUSH_USE_RANDOM_STRENGTH = (1 << 5)
+} eGPDbrush_Flag;
+
+/* color of palettes */
+typedef struct bGPDpalettecolor {
+ struct bGPDpalettecolor *next, *prev;
+ char info[64]; /* Color name. Must be unique. */
+ float color[4];
+ float fill[4]; /* color that should be used for drawing "fills" for strokes */
+ short flag; /* settings for palette color */
+ char pad[6]; /* padding for compiler alignment error */
+} bGPDpalettecolor;
+
+/* bGPDpalettecolor->flag */
+typedef enum eGPDpalettecolor_Flag {
+ /* color is active */
+ PC_COLOR_ACTIVE = (1 << 0),
+ /* don't display color */
+ PC_COLOR_HIDE = (1 << 1),
+ /* protected from further editing */
+ PC_COLOR_LOCKED = (1 << 2),
+ /* do onion skinning */
+ PC_COLOR_ONIONSKIN = (1 << 3),
+ /* "volumetric" strokes (i.e. GLU Quadric discs in 3D) */
+ PC_COLOR_VOLUMETRIC = (1 << 4),
+ /* Use High quality fill */
+ PC_COLOR_HQ_FILL = (1 << 5)
+} eGPDpalettecolor_Flag;
+
+/* palette of colors */
+typedef struct bGPDpalette {
+ struct bGPDpalette *next, *prev;
+
+ /* pointer to individual colours */
+ ListBase colors;
+ char info[64]; /* Palette name. Must be unique. */
+
+ short flag;
+ char pad[6]; /* padding for compiler alignment error */
+} bGPDpalette;
+
+/* bGPDpalette->flag */
+typedef enum eGPDpalette_Flag {
+ /* palette is active */
+ PL_PALETTE_ACTIVE = (1 << 0)
+} eGPDpalette_Flag;
+
/* Grease-Pencil Annotations - 'Stroke'
* -> A stroke represents a (simplified version) of the curve
* drawn by the user in one 'mousedown'->'mouseup' operation
*/
typedef struct bGPDstroke {
struct bGPDstroke *next, *prev;
+
bGPDspoint *points; /* array of data-points for stroke */
- void *pad; /* keep 4 pointers at the beginning, padding for 'inittime' is tricky 64/32bit */
- int totpoints; /* number of data-points in array */
-
- short thickness; /* thickness of stroke (currently not used) */
- short flag; /* various settings about this stroke */
-
bGPDtriangle *triangles;/* tesselated triangles for GP Fill */
+ int totpoints; /* number of data-points in array */
int tot_triangles; /* number of triangles in array */
- int pad1, *pad2;
+
+ short thickness; /* thickness of stroke */
+ short flag, pad[2]; /* various settings about this stroke */
double inittime; /* Init time of stroke */
+ /* The pointer to color is only used during drawing, but not saved
+ * colorname is the join with the palette, but when draw, the pointer is update if the value is NULL
+ * to speed up the drawing
+ */
+ char colorname[128]; /* color name */
+ bGPDpalettecolor *palcolor; /* current palette color */
+ /* temporary layer name only used during copy/paste to put the stroke in the original layer */
+ char tmp_layerinfo[128];
} bGPDstroke;
/* bGPDstroke->flag */
@@ -97,6 +188,10 @@ typedef enum eGPDstroke_Flag {
GP_STROKE_SELECT = (1 << 3),
/* Recalculate triangulation for high quality fill (when true, force a new recalc) */
GP_STROKE_RECALC_CACHES = (1 << 4),
+ /* Recalculate the color pointer using the name as index (true force a new recalc) */
+ GP_STROKE_RECALC_COLOR = (1 << 5),
+ /* Flag used to indicate that stroke is closed and draw edge between last and first point */
+ GP_STROKE_CYCLIC = (1 << 7),
/* only for use with stroke-buffer (while drawing eraser) */
GP_STROKE_ERASER = (1 << 15)
} eGPDstroke_Flag;
@@ -139,16 +234,18 @@ typedef struct bGPDlayer {
float gcolor_prev[3]; /* optional color for ghosts before the active frame */
float gcolor_next[3]; /* optional color for ghosts after the active frame */
- float color[4]; /* color that should be used to draw all the strokes in this layer */
- float fill[4]; /* color that should be used for drawing "fills" for strokes */
+ float color[4]; /* Color for strokes in layers (replaced by palettecolor). Only used for ruler (which uses GPencil internally) */
+ float fill[4]; /* Fill color for strokes in layers. Not used and replaced by palettecolor fill */
char info[128]; /* optional reference info about this layer (i.e. "director's comments, 12/3")
* this is used for the name of the layer too and kept unique. */
- float draw_smoothfac; /* amount of smoothing to apply to newly created strokes */
- short draw_smoothlvl; /* number of times to apply smooth factor to new strokes */
- short sublevel; /* number of times to subdivide new strokes */
- short pad[4]; /* padding for compiler error */
+ struct Object *parent; /* parent object */
+ float inverse[4][4]; /* inverse matrix (only used if parented) */
+ char parsubstr[64]; /* String describing subobject info, MAX_ID_NAME-2 */
+ short partype, pad;
+ float tintcolor[4]; /* Color used to tint layer, alpha value is used as factor */
+ float opacity; /* Opacity of the layer */
} bGPDlayer;
/* bGPDlayer->flag */
@@ -176,7 +273,9 @@ typedef enum eGPDlayer_Flag {
/* "volumetric" strokes (i.e. GLU Quadric discs in 3D) */
GP_LAYER_VOLUMETRIC = (1 << 10),
/* Use high quality fill (instead of buggy legacy OpenGL Fill) */
- GP_LAYER_HQ_FILL = (1 << 11)
+ GP_LAYER_HQ_FILL = (1 << 11),
+ /* Unlock color */
+ GP_LAYER_UNLOCK_COLOR = (1 << 12)
} eGPDlayer_Flag;
/* Grease-Pencil Annotations - 'DataBlock' */
@@ -187,7 +286,7 @@ typedef struct bGPdata {
/* saved Grease-Pencil data */
ListBase layers; /* bGPDlayers */
int flag; /* settings for this datablock */
-
+
/* not-saved stroke buffer data (only used during paint-session)
* - buffer must be initialized before use, but freed after
* whole paint operation is over
@@ -195,6 +294,12 @@ typedef struct bGPdata {
short sbuffer_size; /* number of elements currently in cache */
short sbuffer_sflag; /* flags for stroke that cache represents */
void *sbuffer; /* stroke buffer (can hold GP_STROKE_BUFFER_MAX) */
+ float scolor[4]; /* buffer color using palettes */
+ char pad[6]; /* padding for compiler alignment error */
+ short sflag; /* settings for palette color */
+
+ /* saved palettes */
+ ListBase palettes;
} bGPdata;
/* bGPdata->flag */
@@ -229,7 +334,9 @@ typedef enum eGPdata_Flag {
GP_DATA_STROKE_EDITMODE = (1 << 8),
/* Convenience/cache flag to make it easier to quickly toggle onion skinning on/off */
- GP_DATA_SHOW_ONIONSKINS = (1 << 9)
+ GP_DATA_SHOW_ONIONSKINS = (1 << 9),
+ /* Draw a green and red point to indicate start and end of the stroke */
+ GP_DATA_SHOW_DIRECTION = (1 << 10)
} eGPdata_Flag;
#endif /* __DNA_GPENCIL_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 457db70cd28..f95533a88f9 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -85,6 +85,7 @@ typedef enum ModifierType {
eModifierType_DataTransfer = 49,
eModifierType_NormalEdit = 50,
eModifierType_CorrectiveSmooth = 51,
+ eModifierType_MeshSequenceCache = 52,
NUM_MODIFIER_TYPES
} ModifierType;
@@ -382,7 +383,7 @@ typedef struct DisplaceModifierData {
int direction;
char defgrp_name[64]; /* MAX_VGROUP_NAME */
float midlevel;
- int pad;
+ int space;
} DisplaceModifierData;
/* DisplaceModifierData->direction */
@@ -403,6 +404,12 @@ enum {
MOD_DISP_MAP_UV = 3,
};
+/* DisplaceModifierData->space */
+enum {
+ MOD_DISP_SPACE_LOCAL = 0,
+ MOD_DISP_SPACE_GLOBAL = 1,
+};
+
typedef struct UVProjectModifierData {
ModifierData modifier;
@@ -620,6 +627,9 @@ typedef struct CollisionModifierData {
unsigned int mvert_num;
unsigned int tri_num;
float time_x, time_xnew; /* cfra time of modifier */
+ char is_static; /* collider doesn't move this frame, i.e. x[].co==xnew[].co */
+ char pad[7];
+
struct BVHTree *bvhtree; /* bounding volume hierarchy for this cloth object */
} CollisionModifierData;
@@ -641,8 +651,9 @@ typedef struct BooleanModifierData {
struct Object *object;
char operation;
- char bm_flag, pad[2];
- float threshold;
+ char solver;
+ char pad[2];
+ float double_threshold;
} BooleanModifierData;
typedef enum {
@@ -651,13 +662,10 @@ typedef enum {
eBooleanModifierOp_Difference = 2,
} BooleanModifierOp;
-/* temp bm_flag (debugging only) */
-enum {
- eBooleanModifierBMeshFlag_Enabled = (1 << 0),
- eBooleanModifierBMeshFlag_BMesh_Separate = (1 << 1),
- eBooleanModifierBMeshFlag_BMesh_NoDissolve = (1 << 2),
- eBooleanModifierBMeshFlag_BMesh_NoConnectRegions = (1 << 3),
-};
+typedef enum {
+ eBooleanModifierSolver_Carve = 0,
+ eBooleanModifierSolver_BMesh = 1,
+} BooleanSolver;
typedef struct MDefInfluence {
int vertex;
@@ -1518,7 +1526,9 @@ typedef struct NormalEditModifierData {
short mix_mode;
char pad[2];
float mix_factor;
+ float mix_limit;
float offset[3];
+ float pad_f1;
} NormalEditModifierData;
/* NormalEditModifierData.mode */
@@ -1541,4 +1551,26 @@ enum {
MOD_NORMALEDIT_MIX_MUL = 3,
};
+typedef struct MeshSeqCacheModifierData {
+ ModifierData modifier;
+
+ struct CacheFile *cache_file;
+ struct CacheReader *reader;
+ char object_path[1024]; /* 1024 = FILE_MAX */
+
+ char read_flag;
+ char pad[7];
+} MeshSeqCacheModifierData;
+
+/* MeshSeqCacheModifierData.read_flag */
+enum {
+ MOD_MESHSEQ_READ_VERT = (1 << 0),
+ MOD_MESHSEQ_READ_POLY = (1 << 1),
+ MOD_MESHSEQ_READ_UV = (1 << 2),
+ MOD_MESHSEQ_READ_COLOR = (1 << 3),
+};
+
+#define MOD_MESHSEQ_READ_ALL \
+ (MOD_MESHSEQ_READ_VERT | MOD_MESHSEQ_READ_POLY | MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)
+
#endif /* __DNA_MODIFIER_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_movieclip_types.h b/source/blender/makesdna/DNA_movieclip_types.h
index 499f1c50155..56b99475909 100644
--- a/source/blender/makesdna/DNA_movieclip_types.h
+++ b/source/blender/makesdna/DNA_movieclip_types.h
@@ -146,6 +146,7 @@ enum {
MCLIP_USE_PROXY = (1 << 0),
MCLIP_USE_PROXY_CUSTOM_DIR = (1 << 1),
/* MCLIP_CUSTOM_START_FRAME = (1<<2), */ /* UNUSED */
+ MCLIP_DATA_EXPAND = (1 << 3),
MCLIP_TIMECODE_FLAGS = (MCLIP_USE_PROXY | MCLIP_USE_PROXY_CUSTOM_DIR)
};
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 3a0a0995650..f9f348faa75 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -950,7 +950,8 @@ typedef struct NodeSunBeams {
#define SHD_GLOSSY_BECKMANN 0
#define SHD_GLOSSY_SHARP 1
#define SHD_GLOSSY_GGX 2
-#define SHD_GLOSSY_ASHIKHMIN_SHIRLEY 3
+#define SHD_GLOSSY_ASHIKHMIN_SHIRLEY 3
+#define SHD_GLOSSY_MULTI_GGX 4
/* vector transform */
#define SHD_VECT_TRANSFORM_TYPE_VECTOR 0
diff --git a/source/blender/makesdna/DNA_object_force.h b/source/blender/makesdna/DNA_object_force.h
index cccee82cb51..59acefeffe4 100644
--- a/source/blender/makesdna/DNA_object_force.h
+++ b/source/blender/makesdna/DNA_object_force.h
@@ -339,6 +339,8 @@ typedef struct SoftBody {
struct PointCache *pointcache;
struct ListBase ptcaches;
+ struct Group *collision_group;
+
struct EffectorWeights *effector_weights;
/* reverse esimated obmatrix .. no need to store in blend file .. how ever who cares */
float lcom[3];
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index d53c8360bb5..d24c7faa9f5 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -331,7 +331,7 @@ typedef struct DupliObject {
/* persistent identifier for a dupli object, for inter-frame matching of
* objects with motion blur, or inter-update matching for syncing */
- int persistent_id[8]; /* MAX_DUPLI_RECUR */
+ int persistent_id[16]; /* 2*MAX_DUPLI_RECUR */
/* particle this dupli was generated from */
struct ParticleSystem *particle_system;
diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h
index b284a683f8e..1deb9bf3787 100644
--- a/source/blender/makesdna/DNA_particle_types.h
+++ b/source/blender/makesdna/DNA_particle_types.h
@@ -160,6 +160,7 @@ typedef struct ParticleSettings {
struct SPHFluidSettings *fluid;
struct EffectorWeights *effector_weights;
+ struct Group *collision_group;
int flag, rt;
short type, from, distr, texact;
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 39508e17be5..9b0781ebe70 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -62,6 +62,7 @@ struct AnimData;
struct Editing;
struct SceneStats;
struct bGPdata;
+struct bGPDbrush;
struct MovieClip;
struct ColorSpace;
@@ -134,6 +135,37 @@ typedef struct QuicktimeCodecSettings {
int pad1;
} QuicktimeCodecSettings;
+typedef enum FFMpegPreset {
+ FFM_PRESET_NONE,
+ FFM_PRESET_ULTRAFAST,
+ FFM_PRESET_SUPERFAST,
+ FFM_PRESET_VERYFAST,
+ FFM_PRESET_FASTER,
+ FFM_PRESET_FAST,
+ FFM_PRESET_MEDIUM,
+ FFM_PRESET_SLOW,
+ FFM_PRESET_SLOWER,
+ FFM_PRESET_VERYSLOW,
+} FFMpegPreset;
+
+
+/* Mapping from easily-understandable descriptions to CRF values.
+ * Assumes we output 8-bit video. Needs to be remapped if 10-bit
+ * is output.
+ * We use a slightly wider than "subjectively sane range" according
+ * to https://trac.ffmpeg.org/wiki/Encode/H.264#a1.ChooseaCRFvalue
+ */
+typedef enum FFMpegCrf {
+ FFM_CRF_NONE = -1,
+ FFM_CRF_LOSSLESS = 0,
+ FFM_CRF_PERC_LOSSLESS = 17,
+ FFM_CRF_HIGH = 20,
+ FFM_CRF_MEDIUM = 23,
+ FFM_CRF_LOW = 26,
+ FFM_CRF_VERYLOW = 29,
+ FFM_CRF_LOWEST = 32,
+} FFMpegCrf;
+
typedef struct FFMpegCodecData {
int type;
int codec;
@@ -145,13 +177,18 @@ typedef struct FFMpegCodecData {
int audio_pad;
float audio_volume;
int gop_size;
+ int max_b_frames; /* only used if FFMPEG_USE_MAX_B_FRAMES flag is set. */
int flags;
+ int constant_rate_factor;
+ int ffmpeg_preset; /* see FFMpegPreset */
int rc_min_rate;
int rc_max_rate;
int rc_buffer_size;
int mux_packet_size;
int mux_rate;
+ int pad1;
+
IDProperty *properties;
} FFMpegCodecData;
@@ -902,6 +939,7 @@ typedef struct GameData {
#define GAME_GLSL_NO_COLOR_MANAGEMENT (1 << 15)
#define GAME_SHOW_OBSTACLE_SIMULATION (1 << 16)
#define GAME_NO_MATERIAL_CACHING (1 << 17)
+#define GAME_GLSL_NO_ENV_LIGHTING (1 << 18)
/* Note: GameData.flag is now an int (max 32 flags). A short could only take 16 flags */
/* GameData.playerflag */
@@ -1116,11 +1154,19 @@ typedef enum eGP_EditBrush_Types {
GP_EDITBRUSH_TYPE_SUBDIVIDE = 7,
GP_EDITBRUSH_TYPE_SIMPLIFY = 8,
GP_EDITBRUSH_TYPE_CLONE = 9,
-
+ GP_EDITBRUSH_TYPE_STRENGTH = 10,
+
/* !!! Update GP_EditBrush_Data brush[###]; below !!! */
TOT_GP_EDITBRUSH_TYPES
} eGP_EditBrush_Types;
+/* Lock axis options */
+typedef enum eGP_Lockaxis_Types {
+ GP_LOCKAXIS_NONE = 0,
+ GP_LOCKAXIS_X = 1,
+ GP_LOCKAXIS_Y = 2,
+ GP_LOCKAXIS_Z = 3
+} eGP_Lockaxis_Types;
/* Settings for a GPencil Stroke Sculpting Brush */
typedef struct GP_EditBrush_Data {
@@ -1147,17 +1193,30 @@ typedef enum eGP_EditBrush_Flag {
/* GPencil Stroke Sculpting Settings */
typedef struct GP_BrushEdit_Settings {
- GP_EditBrush_Data brush[10]; /* TOT_GP_EDITBRUSH_TYPES */
+ GP_EditBrush_Data brush[11]; /* TOT_GP_EDITBRUSH_TYPES */
void *paintcursor; /* runtime */
int brushtype; /* eGP_EditBrush_Types */
int flag; /* eGP_BrushEdit_SettingsFlag */
+ int lock_axis; /* lock drawing to one axis */
+ float alpha; /* alpha factor for selection color */
} GP_BrushEdit_Settings;
/* GP_BrushEdit_Settings.flag */
typedef enum eGP_BrushEdit_SettingsFlag {
/* only affect selected points */
- GP_BRUSHEDIT_FLAG_SELECT_MASK = (1 << 0)
+ GP_BRUSHEDIT_FLAG_SELECT_MASK = (1 << 0),
+ /* apply brush to position */
+ GP_BRUSHEDIT_FLAG_APPLY_POSITION = (1 << 1),
+ /* apply brush to strength */
+ GP_BRUSHEDIT_FLAG_APPLY_STRENGTH = (1 << 2),
+ /* apply brush to thickness */
+ GP_BRUSHEDIT_FLAG_APPLY_THICKNESS = (1 << 3),
+ /* apply interpolation to all layers */
+ GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS = (1 << 4),
+ /* apply interpolation to only selected */
+ GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED = (1 << 5)
+
} eGP_BrushEdit_SettingsFlag;
/* *************************************************************** */
@@ -1272,7 +1331,9 @@ typedef struct CurvePaintSettings {
char flag;
char depth_mode;
char surface_plane;
- int error_threshold;
+ char fit_method;
+ char pad;
+ short error_threshold;
float radius_min, radius_max;
float radius_taper_start, radius_taper_end;
float surface_offset;
@@ -1287,6 +1348,12 @@ enum {
CURVE_PAINT_FLAG_DEPTH_STROKE_OFFSET_ABS = (1 << 3),
};
+/* CurvePaintSettings.fit_method */
+enum {
+ CURVE_PAINT_FIT_METHOD_REFIT = 0,
+ CURVE_PAINT_FIT_METHOD_SPLIT = 1,
+};
+
/* CurvePaintSettings.depth_mode */
enum {
CURVE_PAINT_PROJECT_CURSOR = 0,
@@ -1369,6 +1436,9 @@ typedef struct ToolSettings {
/* Grease Pencil Sculpt */
struct GP_BrushEdit_Settings gp_sculpt;
+ /* Grease Pencil Drawing Brushes (bGPDbrush) */
+ ListBase gp_brushes;
+
/* Image Paint (8 byttse aligned please!) */
struct ImagePaintSettings imapaint;
@@ -1639,6 +1709,7 @@ typedef struct Scene {
#define R_SIMPLIFY 0x1000000
#define R_EDGE_FRS 0x2000000 /* R_EDGE reserved for Freestyle */
#define R_PERSISTENT_DATA 0x4000000 /* keep data around for re-render */
+#define R_USE_WS_SHADING 0x8000000 /* use world space interpretation of lighting data */
/* seq_flag */
#define R_SEQ_GL_PREV 1
@@ -1714,9 +1785,12 @@ typedef struct Scene {
#define R_STAMP_RENDERTIME 0x0400
#define R_STAMP_CAMERALENS 0x0800
#define R_STAMP_STRIPMETA 0x1000
+#define R_STAMP_MEMORY 0x2000
+#define R_STAMP_HIDE_LABELS 0x4000
#define R_STAMP_ALL (R_STAMP_TIME|R_STAMP_FRAME|R_STAMP_DATE|R_STAMP_CAMERA|R_STAMP_SCENE| \
R_STAMP_NOTE|R_STAMP_MARKER|R_STAMP_FILENAME|R_STAMP_SEQSTRIP| \
- R_STAMP_RENDERTIME|R_STAMP_CAMERALENS)
+ R_STAMP_RENDERTIME|R_STAMP_CAMERALENS|R_STAMP_MEMORY| \
+ R_STAMP_HIDE_LABELS)
/* alphamode */
#define R_ADDSKY 0
@@ -1952,6 +2026,7 @@ enum {
#endif
FFMPEG_AUTOSPLIT_OUTPUT = 2,
FFMPEG_LOSSLESS_OUTPUT = 4,
+ FFMPEG_USE_MAX_B_FRAMES = (1 << 3),
};
/* Paint.flags */
@@ -2064,6 +2139,8 @@ typedef enum eGPencil_Flags {
GP_TOOL_FLAG_PAINTSESSIONS_ON = (1 << 0),
/* When creating new frames, the last frame gets used as the basis for the new one */
GP_TOOL_FLAG_RETAIN_LAST = (1 << 1),
+ /* Add the strokes below all strokes in the layer */
+ GP_TOOL_FLAG_PAINT_ONBACK = (1 << 2)
} eGPencil_Flags;
/* toolsettings->gpencil_src */
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index fbeabb351ac..e208ef39719 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -218,11 +218,18 @@ typedef struct ScrArea {
char temp, pad;
struct SpaceType *type; /* callbacks for this space type */
-
- ListBase spacedata; /* SpaceLink */
- ListBase regionbase; /* ARegion */
- ListBase handlers; /* wmEventHandler */
-
+
+ /* A list of space links (editors) that were open in this area before. When
+ * changing the editor type, we try to reuse old editor data from this list.
+ * The first item is the active/visible one.
+ */
+ ListBase spacedata; /* SpaceLink */
+ /* NOTE: This region list is the one from the active/visible editor (first item in
+ * spacedata list). Use SpaceLink.regionbase if it's inactive (but only then)!
+ */
+ ListBase regionbase; /* ARegion */
+ ListBase handlers; /* wmEventHandler */
+
ListBase actionzones; /* AZone */
} ScrArea;
diff --git a/source/blender/makesdna/DNA_sdna_types.h b/source/blender/makesdna/DNA_sdna_types.h
index 28204ebeb88..bd8f23f30c1 100644
--- a/source/blender/makesdna/DNA_sdna_types.h
+++ b/source/blender/makesdna/DNA_sdna_types.h
@@ -35,16 +35,17 @@
#
#
typedef struct SDNA {
- char *data; /* full copy of 'encoded' data */
+ const char *data; /* full copy of 'encoded' data (when data_alloc is set, otherwise borrowed). */
int datalen; /* length of data */
+ bool data_alloc;
int nr_names; /* total number of struct members */
- const char **names; /* struct member names */
+ const char **names; /* struct member names */
int pointerlen; /* size of a pointer in bytes */
int nr_types; /* number of basic types + struct types */
- char **types; /* type names */
+ const char **types; /* type names */
short *typelens; /* type lengths */
int nr_structs; /* number of struct types */
@@ -56,18 +57,13 @@ typedef struct SDNA {
struct GHash *structs_map; /* ghash for faster lookups,
* requires WITH_DNA_GHASH to be used for now */
-
- /* wrong place for this really, its a simple
- * cache for findstruct_nr.
- */
- int lastfind;
} SDNA;
#
#
typedef struct BHead {
int code, len;
- void *old;
+ const void *old;
int SDNAnr, nr;
} BHead;
#
diff --git a/source/blender/makesdna/DNA_smoke_types.h b/source/blender/makesdna/DNA_smoke_types.h
index 76de8443faa..ba7f73c2f63 100644
--- a/source/blender/makesdna/DNA_smoke_types.h
+++ b/source/blender/makesdna/DNA_smoke_types.h
@@ -52,6 +52,31 @@ enum {
/* viewsettings */
#define MOD_SMOKE_VIEW_SHOWBIG (1<<0)
+/* slice method */
+enum {
+ MOD_SMOKE_SLICE_VIEW_ALIGNED = 0,
+ MOD_SMOKE_SLICE_AXIS_ALIGNED = 1,
+};
+
+/* axis aligned method */
+enum {
+ AXIS_SLICE_FULL = 0,
+ AXIS_SLICE_SINGLE = 1,
+};
+
+/* single slice direction */
+enum {
+ SLICE_AXIS_AUTO = 0,
+ SLICE_AXIS_X = 1,
+ SLICE_AXIS_Y = 2,
+ SLICE_AXIS_Z = 3,
+};
+
+enum {
+ VECTOR_DRAW_NEEDLE = 0,
+ VECTOR_DRAW_STREAMLINE = 1,
+};
+
/* cache compression */
#define SM_CACHE_LIGHT 0
#define SM_CACHE_HEAVY 1
@@ -161,6 +186,16 @@ typedef struct SmokeDomainSettings {
float burning_rate, flame_smoke, flame_vorticity;
float flame_ignition, flame_max_temp;
float flame_smoke_color[3];
+
+ /* Display settings */
+ char slice_method, axis_slice_method;
+ char slice_axis, draw_velocity;
+ float slice_per_voxel;
+ float slice_depth;
+ float display_thickness;
+ float vector_scale;
+ char vector_draw_type;
+ char pad2[3];
} SmokeDomainSettings;
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 46b7d717991..5e015544dc9 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -252,7 +252,7 @@ typedef struct SpaceOops {
struct BLI_mempool *treestore;
/* search stuff */
- char search_string[32];
+ char search_string[64];
struct TreeStoreElem search_tse;
short flag, outlinevis, storeflag, search_flags;
@@ -412,6 +412,8 @@ typedef enum eSpaceNla_Flag {
SNLA_NOSTRIPCURVES = (1 << 5),
/* don't perform realtime updates */
SNLA_NOREALTIMEUPDATES = (1 << 6),
+ /* don't show local strip marker indications */
+ SNLA_NOLOCALMARKERS = (1 << 7),
} eSpaceNla_Flag;
@@ -736,6 +738,7 @@ typedef enum eFileSel_File_Types {
FILE_TYPE_COLLADA = (1 << 13),
FILE_TYPE_OPERATOR = (1 << 14), /* from filter_glob operator property */
FILE_TYPE_APPLICATIONBUNDLE = (1 << 15),
+ FILE_TYPE_ALEMBIC = (1 << 16),
FILE_TYPE_DIR = (1 << 30), /* An FS directory (i.e. S_ISDIR on its path is true). */
FILE_TYPE_BLENDERLIB = (1 << 31),
@@ -875,8 +878,6 @@ typedef struct SpaceImage {
struct Image *image;
struct ImageUser iuser;
- struct CurveMapping *cumap DNA_DEPRECATED; /* was switched to scene's color management settings */
-
struct Scopes scopes; /* histogram waveform and vectorscope */
struct Histogram sample_line_hist; /* sample line histogram */
@@ -897,6 +898,10 @@ typedef struct SpaceImage {
char dt_uvstretch;
char around;
+ /* Filter settings when editor shows other object's UVs. */
+ int other_uv_filter;
+ int pad2;
+
MaskSpaceInfo mask_info;
} SpaceImage;
@@ -975,6 +980,12 @@ typedef enum eSpaceImage_Flag {
SI_SHOW_B = (1 << 29),
} eSpaceImage_Flag;
+/* SpaceImage->other_uv_filter */
+typedef enum eSpaceImage_OtherUVFilter {
+ SI_FILTER_SAME_IMAGE = 0,
+ SI_FILTER_ALL = 1,
+} eSpaceImage_OtherUVFilter;
+
/* Text Editor ============================================ */
/* Text Editor */
diff --git a/source/blender/makesdna/DNA_tracking_types.h b/source/blender/makesdna/DNA_tracking_types.h
index 9888b735b8b..42b72c1ff93 100644
--- a/source/blender/makesdna/DNA_tracking_types.h
+++ b/source/blender/makesdna/DNA_tracking_types.h
@@ -158,7 +158,10 @@ typedef struct MovieTrackingTrack {
* Used to prevent jumps of the camera when tracks are appearing or
* disappearing.
*/
- float weight, pad;
+ float weight;
+
+ /* track weight especially for 2D stabilization */
+ float weight_stab;
} MovieTrackingTrack;
typedef struct MovieTrackingPlaneMarker {
@@ -250,19 +253,24 @@ typedef struct MovieTrackingSettings {
typedef struct MovieTrackingStabilization {
int flag;
- int tot_track, act_track; /* total number and index of active track in list */
+ int tot_track, act_track; /* total number of translation tracks and index of active track in list */
+ int tot_rot_track, act_rot_track; /* total number of rotation tracks and index of active track in list */
/* 2d stabilization */
float maxscale; /* max auto-scale factor */
- MovieTrackingTrack *rot_track; /* track used to stabilize rotation */
+ MovieTrackingTrack *rot_track DNA_DEPRECATED; /* use TRACK_USE_2D_STAB_ROT on individual tracks instead */
+
+ int anchor_frame; /* reference point to anchor stabilization offset */
+ float target_pos[2]; /* expected target position of frame after raw stabilization, will be subtracted */
+ float target_rot; /* expected target rotation of frame after raw stabilization, will be compensated */
+ float scale; /* zoom factor known to be present on original footage. Also used for autoscale */
float locinf, scaleinf, rotinf; /* influence on location, scale and rotation */
int filter; /* filter used for pixel interpolation */
- /* some pre-computing run-time variables */
- int ok; /* are precomputed values and scaled buf relevant? */
- float scale; /* autoscale factor */
+ /* initialization and run-time data */
+ int ok DNA_DEPRECATED; /* Without effect now, we initialize on every frame. Formerly used for caching of init values */
} MovieTrackingStabilization;
typedef struct MovieTrackingReconstruction {
@@ -386,7 +394,8 @@ enum {
TRACK_USE_2D_STAB = (1 << 8),
TRACK_PREVIEW_GRAYSCALE = (1 << 9),
TRACK_DOPE_SEL = (1 << 10),
- TRACK_PREVIEW_ALPHA = (1 << 11)
+ TRACK_PREVIEW_ALPHA = (1 << 11),
+ TRACK_USE_2D_STAB_ROT = (1 << 12)
};
/* MovieTrackingTrack->motion_model */
@@ -452,7 +461,9 @@ enum {
enum {
TRACKING_2D_STABILIZATION = (1 << 0),
TRACKING_AUTOSCALE = (1 << 1),
- TRACKING_STABILIZE_ROTATION = (1 << 2)
+ TRACKING_STABILIZE_ROTATION = (1 << 2),
+ TRACKING_STABILIZE_SCALE = (1 << 3),
+ TRACKING_SHOW_STAB_TRACKS = (1 << 5)
};
/* MovieTrackingStrabilization->filter */
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index af1dfc62894..e018b66dd60 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -240,9 +240,9 @@ typedef struct ThemeSpace {
char wire[4], wire_edit[4], select[4];
char lamp[4], speaker[4], empty[4], camera[4];
char active[4], group[4], group_active[4], transform[4];
- char vertex[4], vertex_select[4], vertex_unreferenced[4];
+ char vertex[4], vertex_select[4], vertex_bevel[4], vertex_unreferenced[4];
char edge[4], edge_select[4];
- char edge_seam[4], edge_sharp[4], edge_facesel[4], edge_crease[4];
+ char edge_seam[4], edge_sharp[4], edge_facesel[4], edge_crease[4], edge_bevel[4];
char face[4], face_select[4]; /* solid faces */
char face_dot[4]; /* selected color */
char extra_edge_len[4], extra_edge_angle[4], extra_face_angle[4], extra_face_area[4];
@@ -284,7 +284,10 @@ typedef struct ThemeSpace {
char nodeclass_pattern[4], nodeclass_layout[4];
char movie[4], movieclip[4], mask[4], image[4], scene[4], audio[4]; /* for sequence editor */
- char effect[4], transition[4], meta[4], text_strip[4], pad[4];
+ char effect[4], transition[4], meta[4], text_strip[4];
+
+ float keyframe_scale_fac; /* for dopesheet - scale factor for size of keyframes (i.e. height of channels) */
+
char editmesh_active[4];
char handle_vertex[4];
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index 0ef8f2616c4..4c243507e82 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -237,6 +237,13 @@ typedef struct View3D {
float stereo3d_convergence_factor;
float stereo3d_volume_alpha;
float stereo3d_convergence_alpha;
+
+ /* Previous viewport draw type.
+ * Runtime-only, set in the rendered viewport toggle operator.
+ */
+ short prev_drawtype;
+ short pad1;
+ float pad2;
} View3D;
@@ -291,7 +298,7 @@ typedef struct View3D {
#define RV3D_VIEW_CAMERA 8
#define RV3D_VIEW_IS_AXIS(view) \
- ((view >= RV3D_VIEW_FRONT) && (view <= RV3D_VIEW_BOTTOM))
+ (((view) >= RV3D_VIEW_FRONT) && ((view) <= RV3D_VIEW_BOTTOM))
/* View3d->flag2 (short) */
#define V3D_RENDER_OVERRIDE (1 << 2)
diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt
index 52487edfd2b..8c758c33dc5 100644
--- a/source/blender/makesdna/intern/CMakeLists.txt
+++ b/source/blender/makesdna/intern/CMakeLists.txt
@@ -52,12 +52,20 @@ endif()
# SRC_DNA_INC is defined in the parent dir
+add_cc_flags_custom_test(makesdna)
+
add_executable(makesdna ${SRC} ${SRC_DNA_INC})
# Output dna.c
add_custom_command(
- OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/dna.c
- COMMAND "$<TARGET_FILE:makesdna>" ${CMAKE_CURRENT_BINARY_DIR}/dna.c ${CMAKE_SOURCE_DIR}/source/blender/makesdna/
+ OUTPUT
+ ${CMAKE_CURRENT_BINARY_DIR}/dna.c
+ ${CMAKE_CURRENT_BINARY_DIR}/dna_type_offsets.h
+ COMMAND
+ "$<TARGET_FILE:makesdna>"
+ ${CMAKE_CURRENT_BINARY_DIR}/dna.c
+ ${CMAKE_CURRENT_BINARY_DIR}/dna_type_offsets.h
+ ${CMAKE_SOURCE_DIR}/source/blender/makesdna/
DEPENDS makesdna
)
@@ -78,7 +86,11 @@ set(SRC
${SRC_DNA_INC}
)
-set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/dna.c PROPERTIES GENERATED TRUE)
+set_source_files_properties(
+ ${CMAKE_CURRENT_BINARY_DIR}/dna.c
+ ${CMAKE_CURRENT_BINARY_DIR}/dna_type_offsets.h
+ PROPERTIES GENERATED TRUE
+)
blender_add_lib(bf_dna "${SRC}" "${INC}" "${INC_SYS}")
@@ -94,10 +106,11 @@ set(INC_SYS
)
set(SRC
- ../../blenlib/intern/BLI_mempool.c
- ../../blenlib/intern/listbase.c
../../blenlib/intern/BLI_ghash.c
+ ../../blenlib/intern/BLI_mempool.c
+ ../../blenlib/intern/endian_switch.c
../../blenlib/intern/hash_mm2a.c
+ ../../blenlib/intern/listbase.c
)
blender_add_lib(bf_dna_blenlib "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c
index 4f19e819625..96085a79eff 100644
--- a/source/blender/makesdna/intern/dna_genfile.c
+++ b/source/blender/makesdna/intern/dna_genfile.c
@@ -39,10 +39,12 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <limits.h>
#include "MEM_guardedalloc.h" // for MEM_freeN MEM_mallocN MEM_callocN
#include "BLI_utildefines.h"
+#include "BLI_endian_switch.h"
#ifdef WITH_DNA_GHASH
# include "BLI_ghash.h"
@@ -132,39 +134,6 @@
*
*/
-/* ************************* ENDIAN STUFF ********************** */
-
-/**
- * converts a short between big/little endian.
- */
-static short le_short(short temp)
-{
- short new;
- char *rt = (char *)&temp, *rtn = (char *)&new;
-
- rtn[0] = rt[1];
- rtn[1] = rt[0];
-
- return new;
-}
-
-/**
- * converts an int between big/little endian.
- */
-static int le_int(int temp)
-{
- int new;
- char *rt = (char *)&temp, *rtn = (char *)&new;
-
- rtn[0] = rt[3];
- rtn[1] = rt[2];
- rtn[2] = rt[1];
- rtn[3] = rt[0];
-
- return new;
-}
-
-
/* ************************* MAKE DNA ********************** */
/* allowed duplicate code from makesdna.c */
@@ -195,7 +164,10 @@ int DNA_elem_array_size(const char *str)
void DNA_sdna_free(SDNA *sdna)
{
- MEM_freeN(sdna->data);
+ if (sdna->data_alloc) {
+ MEM_freeN((void *)sdna->data);
+ }
+
MEM_freeN((void *)sdna->names);
MEM_freeN(sdna->types);
MEM_freeN(sdna->structs);
@@ -276,37 +248,16 @@ static void printstruct(SDNA *sdna, short strnr)
#endif
/**
- * Returns a pointer to the start of the struct info for the struct with the specified name.
- */
-static short *findstruct_name(SDNA *sdna, const char *str)
-{
- int a;
- short *sp = NULL;
-
-
- for (a = 0; a < sdna->nr_structs; a++) {
-
- sp = sdna->structs[a];
-
- if (strcmp(sdna->types[sp[0]], str) == 0) {
- return sp;
- }
- }
-
- return NULL;
-}
-
-/**
* Returns the index of the struct info for the struct with the specified name.
*/
-int DNA_struct_find_nr(SDNA *sdna, const char *str)
+int DNA_struct_find_nr_ex(const SDNA *sdna, const char *str, unsigned int *index_last)
{
const short *sp = NULL;
- if (sdna->lastfind < sdna->nr_structs) {
- sp = sdna->structs[sdna->lastfind];
+ if (*index_last < sdna->nr_structs) {
+ sp = sdna->structs[*index_last];
if (strcmp(sdna->types[sp[0]], str) == 0) {
- return sdna->lastfind;
+ return *index_last;
}
}
@@ -319,7 +270,7 @@ int DNA_struct_find_nr(SDNA *sdna, const char *str)
if (index_p) {
a = GET_INT_FROM_POINTER(*index_p);
- sdna->lastfind = a;
+ *index_last = a;
}
else {
a = -1;
@@ -335,7 +286,7 @@ int DNA_struct_find_nr(SDNA *sdna, const char *str)
sp = sdna->structs[a];
if (strcmp(sdna->types[sp[0]], str) == 0) {
- sdna->lastfind = a;
+ *index_last = a;
return a;
}
}
@@ -344,26 +295,51 @@ int DNA_struct_find_nr(SDNA *sdna, const char *str)
#endif
}
+int DNA_struct_find_nr(const SDNA *sdna, const char *str)
+{
+ unsigned int index_last_dummy = UINT_MAX;
+ return DNA_struct_find_nr_ex(sdna, str, &index_last_dummy);
+}
+
/* ************************* END DIV ********************** */
/* ************************* READ DNA ********************** */
+BLI_INLINE const char *pad_up_4(const char *ptr)
+{
+ return (const char *)((((uintptr_t)ptr) + 3) & ~3);
+}
+
/**
* In sdna->data the data, now we convert that to something understandable
*/
-static void init_structDNA(SDNA *sdna, bool do_endian_swap)
+static bool init_structDNA(
+ SDNA *sdna, bool do_endian_swap,
+ const char **r_error_message)
{
int *data, *verg, gravity_fix = -1;
- intptr_t nr;
short *sp;
- char str[8], *cp;
+ char str[8];
verg = (int *)str;
data = (int *)sdna->data;
+ /* clear pointers incase of error */
+ sdna->names = NULL;
+ sdna->types = NULL;
+ sdna->structs = NULL;
+#ifdef WITH_DNA_GHASH
+ sdna->structs_map = NULL;
+#endif
+
strcpy(str, "SDNA");
- if (*data == *verg) {
-
+ if (*data != *verg) {
+ *r_error_message = "SDNA error in SDNA file";
+ return false;
+ }
+ else {
+ const char *cp;
+
data++;
/* load names array */
@@ -371,20 +347,21 @@ static void init_structDNA(SDNA *sdna, bool do_endian_swap)
if (*data == *verg) {
data++;
- if (do_endian_swap) sdna->nr_names = le_int(*data);
- else sdna->nr_names = *data;
+ sdna->nr_names = *data;
+ if (do_endian_swap) {
+ BLI_endian_switch_int32(&sdna->nr_names);
+ }
data++;
sdna->names = MEM_callocN(sizeof(void *) * sdna->nr_names, "sdnanames");
}
else {
- printf("NAME error in SDNA file\n");
- return;
+ *r_error_message = "NAME error in SDNA file";
+ return false;
}
- nr = 0;
cp = (char *)data;
- while (nr < sdna->nr_names) {
+ for (int nr = 0; nr < sdna->nr_names; nr++) {
sdna->names[nr] = cp;
/* "float gravity [3]" was parsed wrong giving both "gravity" and
@@ -399,32 +376,31 @@ static void init_structDNA(SDNA *sdna, bool do_endian_swap)
while (*cp) cp++;
cp++;
- nr++;
}
- nr = (intptr_t)cp; /* prevent BUS error */
- nr = (nr + 3) & ~3;
- cp = (char *)nr;
+
+ cp = pad_up_4(cp);
/* load type names array */
data = (int *)cp;
strcpy(str, "TYPE");
if (*data == *verg) {
data++;
-
- if (do_endian_swap) sdna->nr_types = le_int(*data);
- else sdna->nr_types = *data;
+
+ sdna->nr_types = *data;
+ if (do_endian_swap) {
+ BLI_endian_switch_int32(&sdna->nr_types);
+ }
data++;
sdna->types = MEM_callocN(sizeof(void *) * sdna->nr_types, "sdnatypes");
}
else {
- printf("TYPE error in SDNA file\n");
- return;
+ *r_error_message = "TYPE error in SDNA file";
+ return false;
}
- nr = 0;
cp = (char *)data;
- while (nr < sdna->nr_types) {
+ for (int nr = 0; nr < sdna->nr_types; nr++) {
sdna->types[nr] = cp;
/* this is a patch, to change struct names without a conflict with SDNA */
@@ -437,11 +413,9 @@ static void init_structDNA(SDNA *sdna, bool do_endian_swap)
while (*cp) cp++;
cp++;
- nr++;
}
- nr = (intptr_t)cp; /* prevent BUS error */
- nr = (nr + 3) & ~3;
- cp = (char *)nr;
+
+ cp = pad_up_4(cp);
/* load typelen array */
data = (int *)cp;
@@ -452,20 +426,14 @@ static void init_structDNA(SDNA *sdna, bool do_endian_swap)
sdna->typelens = sp;
if (do_endian_swap) {
- short a, *spo = sp;
-
- a = sdna->nr_types;
- while (a--) {
- spo[0] = le_short(spo[0]);
- spo++;
- }
+ BLI_endian_switch_int16_array(sp, sdna->nr_types);
}
sp += sdna->nr_types;
}
else {
- printf("TLEN error in SDNA file\n");
- return;
+ *r_error_message = "TLEN error in SDNA file";
+ return false;
}
if (sdna->nr_types & 1) sp++; /* prevent BUS error */
@@ -475,92 +443,152 @@ static void init_structDNA(SDNA *sdna, bool do_endian_swap)
if (*data == *verg) {
data++;
- if (do_endian_swap) sdna->nr_structs = le_int(*data);
- else sdna->nr_structs = *data;
+ sdna->nr_structs = *data;
+ if (do_endian_swap) {
+ BLI_endian_switch_int32(&sdna->nr_structs);
+ }
data++;
sdna->structs = MEM_callocN(sizeof(void *) * sdna->nr_structs, "sdnastrcs");
}
else {
- printf("STRC error in SDNA file\n");
- return;
+ *r_error_message = "STRC error in SDNA file";
+ return false;
}
- nr = 0;
sp = (short *)data;
- while (nr < sdna->nr_structs) {
+ for (int nr = 0; nr < sdna->nr_structs; nr++) {
sdna->structs[nr] = sp;
if (do_endian_swap) {
short a;
- sp[0] = le_short(sp[0]);
- sp[1] = le_short(sp[1]);
+ BLI_endian_switch_int16(&sp[0]);
+ BLI_endian_switch_int16(&sp[1]);
a = sp[1];
sp += 2;
while (a--) {
- sp[0] = le_short(sp[0]);
- sp[1] = le_short(sp[1]);
+ BLI_endian_switch_int16(&sp[0]);
+ BLI_endian_switch_int16(&sp[1]);
sp += 2;
}
}
else {
sp += 2 * sp[1] + 2;
}
-
- nr++;
}
+ }
- /* finally pointerlen: use struct ListBase to test it, never change the size of it! */
- sp = findstruct_name(sdna, "ListBase");
- /* weird; i have no memory of that... I think I used sizeof(void *) before... (ton) */
-
- sdna->pointerlen = sdna->typelens[sp[0]] / 2;
-
- if (sp[1] != 2 || (sdna->pointerlen != 4 && sdna->pointerlen != 8)) {
- printf("ListBase struct error! Needs it to calculate pointerize.\n");
- exit(1);
- /* well, at least sizeof(ListBase) is error proof! (ton) */
- }
-
+ {
/* second part of gravity problem, setting "gravity" type to void */
if (gravity_fix > -1) {
- for (nr = 0; nr < sdna->nr_structs; nr++) {
+ for (int nr = 0; nr < sdna->nr_structs; nr++) {
sp = sdna->structs[nr];
if (strcmp(sdna->types[sp[0]], "ClothSimSettings") == 0)
sp[10] = SDNA_TYPE_VOID;
}
}
+ }
#ifdef WITH_DNA_GHASH
+ {
/* create a ghash lookup to speed up */
sdna->structs_map = BLI_ghash_str_new_ex("init_structDNA gh", sdna->nr_structs);
- for (nr = 0; nr < sdna->nr_structs; nr++) {
+ for (intptr_t nr = 0; nr < sdna->nr_structs; nr++) {
sp = sdna->structs[nr];
- BLI_ghash_insert(sdna->structs_map, sdna->types[sp[0]], SET_INT_IN_POINTER(nr));
+ BLI_ghash_insert(sdna->structs_map, (void *)sdna->types[sp[0]], SET_INT_IN_POINTER(nr));
}
+ }
#endif
+
+ /* Calculate 'sdna->pointerlen' */
+ {
+ intptr_t nr = DNA_struct_find_nr(sdna, "ListBase");
+
+ /* should never happen, only with corrupt file for example */
+ if (UNLIKELY(nr == -1)) {
+ *r_error_message = "ListBase struct error! Not found.";
+ return false;
+ }
+
+ /* finally pointerlen: use struct ListBase to test it, never change the size of it! */
+ sp = sdna->structs[nr];
+ /* weird; i have no memory of that... I think I used sizeof(void *) before... (ton) */
+
+ sdna->pointerlen = sdna->typelens[sp[0]] / 2;
+
+ if (sp[1] != 2 || (sdna->pointerlen != 4 && sdna->pointerlen != 8)) {
+ *r_error_message = "ListBase struct error! Needs it to calculate pointerize.";
+ /* well, at least sizeof(ListBase) is error proof! (ton) */
+ return false;
+ }
}
+
+ return true;
}
/**
* Constructs and returns a decoded SDNA structure from the given encoded SDNA data block.
*/
-SDNA *DNA_sdna_from_data(const void *data, const int datalen, bool do_endian_swap)
+SDNA *DNA_sdna_from_data(
+ const void *data, const int datalen,
+ bool do_endian_swap, bool data_alloc,
+ const char **r_error_message)
{
SDNA *sdna = MEM_mallocN(sizeof(*sdna), "sdna");
-
- sdna->lastfind = 0;
+ const char *error_message = NULL;
sdna->datalen = datalen;
- sdna->data = MEM_mallocN(datalen, "sdna_data");
- memcpy(sdna->data, data, datalen);
-
- init_structDNA(sdna, do_endian_swap);
+ if (data_alloc) {
+ char *data_copy = MEM_mallocN(datalen, "sdna_data");
+ memcpy(data_copy, data, datalen);
+ sdna->data = data_copy;
+ }
+ else {
+ sdna->data = data;
+ }
+ sdna->data_alloc = data_alloc;
- return sdna;
+
+ if (init_structDNA(sdna, do_endian_swap, &error_message)) {
+ return sdna;
+ }
+ else {
+ if (r_error_message == NULL) {
+ fprintf(stderr, "Error decoding blend file SDNA: %s\n", error_message);
+ }
+ else {
+ *r_error_message = error_message;
+ }
+ DNA_sdna_free(sdna);
+ return NULL;
+ }
+}
+
+/**
+ * Using globals is acceptable here, the data is read-only and only changes between Blender versions.
+ *
+ * So it is safe to create once and reuse.
+ */
+static SDNA *g_sdna = NULL;
+
+void DNA_sdna_current_init(void)
+{
+ g_sdna = DNA_sdna_from_data(DNAstr, DNAlen, false, false, NULL);
+}
+
+const struct SDNA *DNA_sdna_current_get(void)
+{
+ BLI_assert(g_sdna != NULL);
+ return g_sdna;
+}
+
+void DNA_sdna_current_free(void)
+{
+ DNA_sdna_free(g_sdna);
+ g_sdna = NULL;
}
/* ******************** END READ DNA ********************** */
@@ -604,13 +632,8 @@ static void recurs_test_compflags(const SDNA *sdna, char *compflags, int structn
/**
* Constructs and returns an array of byte flags with one element for each struct in oldsdna,
* indicating how it compares to newsdna:
- *
- * flag value:
- * - 0 Struct has disappeared (values of this struct type will not be loaded by the current Blender)
- * - 1 Struct is the same (can be loaded with straight memory copy after any necessary endian conversion)
- * - 2 Struct is different in some way (needs to be copied/converted field by field)
*/
-char *DNA_struct_get_compareflags(SDNA *oldsdna, SDNA *newsdna)
+const char *DNA_struct_get_compareflags(const SDNA *oldsdna, const SDNA *newsdna)
{
int a, b;
const short *sp_old, *sp_new;
@@ -627,14 +650,19 @@ char *DNA_struct_get_compareflags(SDNA *oldsdna, SDNA *newsdna)
/* we check all structs in 'oldsdna' and compare them with
* the structs in 'newsdna'
*/
+ unsigned int newsdna_index_last = 0;
for (a = 0; a < oldsdna->nr_structs; a++) {
sp_old = oldsdna->structs[a];
/* search for type in cur */
- sp_new = findstruct_name(newsdna, oldsdna->types[sp_old[0]]);
-
- if (sp_new) {
+ int sp_new_index = DNA_struct_find_nr_ex(newsdna, oldsdna->types[sp_old[0]], &newsdna_index_last);
+
+ /* The next indices will almost always match */
+ newsdna_index_last++;
+
+ if (sp_new_index != -1) {
+ sp_new = newsdna->structs[sp_new_index];
/* initial assumption */
compflags[a] = SDNA_CMP_NOT_EQUAL;
@@ -876,12 +904,12 @@ static int elem_strcmp(const char *name, const char *oname)
* \param sppo Optional place to return pointer to field info in sdna
* \return Data address.
*/
-static char *find_elem(
+static const char *find_elem(
const SDNA *sdna,
const char *type,
const char *name,
const short *old,
- char *olddata,
+ const char *olddata,
const short **sppo)
{
int a, elemcount, len;
@@ -1024,12 +1052,12 @@ static void reconstruct_elem(
* \param cur Where to put converted struct contents
*/
static void reconstruct_struct(
- SDNA *newsdna,
- SDNA *oldsdna,
+ const SDNA *newsdna,
+ const SDNA *oldsdna,
const char *compflags,
int oldSDNAnr,
- char *data,
+ const char *data,
int curSDNAnr,
char *cur)
{
@@ -1040,9 +1068,14 @@ static void reconstruct_struct(
int a, elemcount, elen, eleno, mul, mulo, firststructtypenr;
const short *spo, *spc, *sppo;
const char *type;
- char *cpo, *cpc;
+ const char *cpo;
+ char *cpc;
const char *name, *nameo;
+ unsigned int oldsdna_index_last = UINT_MAX;
+ unsigned int cursdna_index_last = UINT_MAX;
+
+
if (oldSDNAnr == -1) return;
if (curSDNAnr == -1) return;
@@ -1074,11 +1107,11 @@ static void reconstruct_struct(
if (spc[0] >= firststructtypenr && !ispointer(name)) {
/* struct field type */
/* where does the old struct data start (and is there an old one?) */
- cpo = find_elem(oldsdna, type, name, spo, data, &sppo);
+ cpo = (char *)find_elem(oldsdna, type, name, spo, data, &sppo);
if (cpo) {
- oldSDNAnr = DNA_struct_find_nr(oldsdna, type);
- curSDNAnr = DNA_struct_find_nr(newsdna, type);
+ oldSDNAnr = DNA_struct_find_nr_ex(oldsdna, type, &oldsdna_index_last);
+ curSDNAnr = DNA_struct_find_nr_ex(newsdna, type, &cursdna_index_last);
/* array! */
mul = DNA_elem_array_size(name);
@@ -1119,15 +1152,16 @@ static void reconstruct_struct(
* \param oldSDNAnr Index of struct info within oldsdna
* \param data Struct data
*/
-void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data)
+void DNA_struct_switch_endian(const SDNA *oldsdna, int oldSDNAnr, char *data)
{
/* Recursive!
* If element is a struct, call recursive.
*/
int a, mul, elemcount, elen, elena, firststructtypenr;
const short *spo, *spc;
- char *cpo, *cur, cval;
+ char *cur;
const char *type, *name;
+ unsigned int oldsdna_index_last = UINT_MAX;
if (oldSDNAnr == -1) return;
firststructtypenr = *(oldsdna->structs[0]);
@@ -1148,11 +1182,11 @@ void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data)
/* test: is type a struct? */
if (spc[0] >= firststructtypenr && !ispointer(name)) {
- /* struct field type */
+ /* struct field type */
/* where does the old data start (is there one?) */
- cpo = find_elem(oldsdna, type, name, spo, data, NULL);
+ char *cpo = (char *)find_elem(oldsdna, type, name, spo, data, NULL);
if (cpo) {
- oldSDNAnr = DNA_struct_find_nr(oldsdna, type);
+ oldSDNAnr = DNA_struct_find_nr_ex(oldsdna, type, &oldsdna_index_last);
mul = DNA_elem_array_size(name);
elena = elen / mul;
@@ -1167,18 +1201,7 @@ void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data)
/* non-struct field type */
if (ispointer(name)) {
if (oldsdna->pointerlen == 8) {
-
- mul = DNA_elem_array_size(name);
- cpo = cur;
- while (mul--) {
- cval = cpo[0]; cpo[0] = cpo[7]; cpo[7] = cval;
- cval = cpo[1]; cpo[1] = cpo[6]; cpo[6] = cval;
- cval = cpo[2]; cpo[2] = cpo[5]; cpo[5] = cval;
- cval = cpo[3]; cpo[3] = cpo[4]; cpo[4] = cval;
-
- cpo += 8;
- }
-
+ BLI_endian_switch_int64_array((int64_t *)cur, DNA_elem_array_size(name));
}
}
else {
@@ -1191,14 +1214,7 @@ void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data)
}
if (skip == false) {
- mul = DNA_elem_array_size(name);
- cpo = cur;
- while (mul--) {
- cval = cpo[0];
- cpo[0] = cpo[1];
- cpo[1] = cval;
- cpo += 2;
- }
+ BLI_endian_switch_int16_array((int16_t *)cur, DNA_elem_array_size(name));
}
}
else if (ELEM(spc[0], SDNA_TYPE_INT, SDNA_TYPE_FLOAT)) {
@@ -1206,29 +1222,10 @@ void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data)
* but turns out we only used for runtime vars and
* only once for a struct type thats no longer used. */
- mul = DNA_elem_array_size(name);
- cpo = cur;
- while (mul--) {
- cval = cpo[0];
- cpo[0] = cpo[3];
- cpo[3] = cval;
- cval = cpo[1];
- cpo[1] = cpo[2];
- cpo[2] = cval;
- cpo += 4;
- }
+ BLI_endian_switch_int32_array((int32_t *)cur, DNA_elem_array_size(name));
}
else if (ELEM(spc[0], SDNA_TYPE_INT64, SDNA_TYPE_UINT64, SDNA_TYPE_DOUBLE)) {
- mul = DNA_elem_array_size(name);
- cpo = cur;
- while (mul--) {
- cval = cpo[0]; cpo[0] = cpo[7]; cpo[7] = cval;
- cval = cpo[1]; cpo[1] = cpo[6]; cpo[6] = cval;
- cval = cpo[2]; cpo[2] = cpo[5]; cpo[5] = cval;
- cval = cpo[3]; cpo[3] = cpo[4]; cpo[4] = cval;
-
- cpo += 8;
- }
+ BLI_endian_switch_int64_array((int64_t *)cur, DNA_elem_array_size(name));
}
}
}
@@ -1247,11 +1244,14 @@ void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data)
* \param data Array of struct data
* \return An allocated reconstructed struct
*/
-void *DNA_struct_reconstruct(SDNA *newsdna, SDNA *oldsdna, char *compflags, int oldSDNAnr, int blocks, void *data)
+void *DNA_struct_reconstruct(
+ const SDNA *newsdna, const SDNA *oldsdna,
+ const char *compflags, int oldSDNAnr, int blocks, const void *data)
{
int a, curSDNAnr, curlen = 0, oldlen;
const short *spo, *spc;
- char *cur, *cpc, *cpo;
+ char *cur, *cpc;
+ const char *cpo;
const char *type;
/* oldSDNAnr == structnr, we're looking for the corresponding 'cur' number */
@@ -1287,7 +1287,6 @@ void *DNA_struct_reconstruct(SDNA *newsdna, SDNA *oldsdna, char *compflags, int
*/
int DNA_elem_offset(SDNA *sdna, const char *stype, const char *vartype, const char *name)
{
-
const int SDNAnr = DNA_struct_find_nr(sdna, stype);
const short * const spo = sdna->structs[SDNAnr];
const char * const cp = find_elem(sdna, vartype, name, spo, NULL, NULL);
@@ -1295,9 +1294,13 @@ int DNA_elem_offset(SDNA *sdna, const char *stype, const char *vartype, const ch
return (int)((intptr_t)cp);
}
-bool DNA_struct_elem_find(SDNA *sdna, const char *stype, const char *vartype, const char *name)
+bool DNA_struct_find(const SDNA *sdna, const char *stype)
+{
+ return DNA_struct_find_nr(sdna, stype) != -1;
+}
+
+bool DNA_struct_elem_find(const SDNA *sdna, const char *stype, const char *vartype, const char *name)
{
-
const int SDNAnr = DNA_struct_find_nr(sdna, stype);
if (SDNAnr != -1) {
diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
index fc94a8d9ff4..2cea8715a65 100644
--- a/source/blender/makesdna/intern/makesdna.c
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -129,6 +129,7 @@ static const char *includefiles[] = {
"DNA_rigidbody_types.h",
"DNA_freestyle_types.h",
"DNA_linestyle_types.h",
+ "DNA_cachefile_types.h",
/* see comment above before editing! */
/* empty string to indicate end of includefiles */
@@ -968,7 +969,7 @@ void printStructLengths(void)
}
-static int make_structDNA(const char *baseDirectory, FILE *file)
+static int make_structDNA(const char *baseDirectory, FILE *file, FILE *file_offsets)
{
int len, i;
const short *sp;
@@ -1159,6 +1160,19 @@ static int make_structDNA(const char *baseDirectory, FILE *file)
/* end end padding test */
}
+ /* write a simple enum with all structs offsets,
+ * should only be accessed via SDNA_TYPE_FROM_STRUCT macro */
+ {
+ fprintf(file_offsets, "#define SDNA_TYPE_FROM_STRUCT(id) _SDNA_TYPE_##id\n");
+ fprintf(file_offsets, "enum {\n");
+ for (i = 0; i < nr_structs; i++) {
+ const short *structpoin = structs[i];
+ const int structtype = structpoin[0];
+ fprintf(file_offsets, "\t_SDNA_TYPE_%s = %d,\n", types[structtype], i);
+ }
+ fprintf(file_offsets, "\tSDNA_TYPE_MAX = %d,\n", nr_structs);
+ fprintf(file_offsets, "};\n");
+ }
MEM_freeN(namedata);
MEM_freeN(typedata);
@@ -1190,43 +1204,53 @@ static void make_bad_file(const char *file, int line)
int main(int argc, char **argv)
{
- FILE *file;
int return_status = 0;
- if (argc != 2 && argc != 3) {
- printf("Usage: %s outfile.c [base directory]\n", argv[0]);
+ if (argc != 3 && argc != 4) {
+ printf("Usage: %s dna.c dna_struct_offsets.h [base directory]\n", argv[0]);
return_status = 1;
}
else {
- file = fopen(argv[1], "w");
- if (!file) {
+ FILE *file_dna = fopen(argv[1], "w");
+ FILE *file_dna_offsets = fopen(argv[2], "w");
+ if (!file_dna) {
printf("Unable to open file: %s\n", argv[1]);
return_status = 1;
}
+ else if (!file_dna_offsets) {
+ printf("Unable to open file: %s\n", argv[2]);
+ return_status = 1;
+ }
else {
const char *baseDirectory;
- if (argc == 3) {
- baseDirectory = argv[2];
+ if (argc == 4) {
+ baseDirectory = argv[3];
}
else {
baseDirectory = BASE_HEADER;
}
- fprintf(file, "const unsigned char DNAstr[] = {\n");
- if (make_structDNA(baseDirectory, file)) {
+ fprintf(file_dna, "const unsigned char DNAstr[] = {\n");
+ if (make_structDNA(baseDirectory, file_dna, file_dna_offsets)) {
/* error */
- fclose(file);
+ fclose(file_dna);
+ file_dna = NULL;
make_bad_file(argv[1], __LINE__);
return_status = 1;
}
else {
- fprintf(file, "};\n");
- fprintf(file, "const int DNAlen = sizeof(DNAstr);\n");
-
- fclose(file);
+ fprintf(file_dna, "};\n");
+ fprintf(file_dna, "const int DNAlen = sizeof(DNAstr);\n");
}
}
+
+ if (file_dna) {
+ fclose(file_dna);
+ }
+ if (file_dna_offsets) {
+ fclose(file_dna_offsets);
+ }
}
@@ -1317,4 +1341,5 @@ int main(int argc, char **argv)
#include "DNA_rigidbody_types.h"
#include "DNA_freestyle_types.h"
#include "DNA_linestyle_types.h"
+#include "DNA_cachefile_types.h"
/* end of list */
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 3a19211ab39..44d1a6bfaaf 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -95,6 +95,8 @@ extern StructRNA RNA_Brush;
extern StructRNA RNA_BrushTextureSlot;
extern StructRNA RNA_BuildModifier;
extern StructRNA RNA_MeshCacheModifier;
+extern StructRNA RNA_MeshSequenceCacheModifier;
+extern StructRNA RNA_CacheFile;
extern StructRNA RNA_Camera;
extern StructRNA RNA_CastModifier;
extern StructRNA RNA_ChildOfConstraint;
@@ -257,6 +259,9 @@ extern StructRNA RNA_FreestyleSettings;
extern StructRNA RNA_Function;
extern StructRNA RNA_GPencilFrame;
extern StructRNA RNA_GPencilLayer;
+extern StructRNA RNA_GPencilPalette;
+extern StructRNA RNA_GPencilPaletteColor;
+extern StructRNA RNA_GPencilBrush;
extern StructRNA RNA_GPencilStroke;
extern StructRNA RNA_GPencilStrokePoint;
extern StructRNA RNA_GPencilSculptSettings;
@@ -417,6 +422,7 @@ extern StructRNA RNA_MovieClipSequence;
extern StructRNA RNA_MovieTracking;
extern StructRNA RNA_MovieTrackingObject;
extern StructRNA RNA_MovieTrackingTrack;
+extern StructRNA RNA_MovieTrackingStabilization;
extern StructRNA RNA_MulticamSequence;
extern StructRNA RNA_MultiresModifier;
extern StructRNA RNA_MusgraveTexture;
@@ -715,6 +721,11 @@ void RNA_main_pointer_create(struct Main *main, PointerRNA *r_ptr);
void RNA_id_pointer_create(struct ID *id, PointerRNA *r_ptr);
void RNA_pointer_create(struct ID *id, StructRNA *type, void *data, PointerRNA *r_ptr);
+bool RNA_path_resolved_create(
+ PointerRNA *ptr, struct PropertyRNA *prop,
+ const int prop_index,
+ PathResolvedRNA *r_anim_rna);
+
void RNA_blender_rna_pointer_create(PointerRNA *r_ptr);
void RNA_pointer_recast(PointerRNA *ptr, PointerRNA *r_ptr);
@@ -845,6 +856,7 @@ StructRNA *RNA_property_pointer_type(PointerRNA *ptr, PropertyRNA *prop);
int RNA_property_pointer_poll(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *value);
bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop);
+bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char **r_info);
bool RNA_property_editable_index(PointerRNA *ptr, PropertyRNA *prop, int index);
bool RNA_property_editable_flag(PointerRNA *ptr, PropertyRNA *prop); /* without lib check, only checks the flag */
bool RNA_property_animateable(PointerRNA *ptr, PropertyRNA *prop);
@@ -905,6 +917,7 @@ int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop);
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value);
int RNA_property_enum_get_default(PointerRNA *ptr, PropertyRNA *prop);
void *RNA_property_enum_py_data_get(PropertyRNA *prop);
+int RNA_property_enum_step(const struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, int from_value, int step);
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop);
void RNA_property_pointer_set(PointerRNA *ptr, PropertyRNA *prop, PointerRNA ptr_value);
@@ -979,6 +992,7 @@ bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, struct ListBas
char *RNA_path_from_ID_to_struct(PointerRNA *ptr);
char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop);
+char *RNA_path_from_ID_to_property_index(PointerRNA *ptr, PropertyRNA *prop, int array_dim, int index);
char *RNA_path_resolve_from_type_to_property(
struct PointerRNA *ptr, struct PropertyRNA *prop,
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index b1048f72022..1c9b3593d17 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -52,6 +52,7 @@ extern EnumPropertyItem rna_enum_proportional_editing_items[];
extern EnumPropertyItem rna_enum_snap_target_items[];
extern EnumPropertyItem rna_enum_snap_element_items[];
extern EnumPropertyItem rna_enum_snap_node_element_items[];
+extern EnumPropertyItem rna_enum_curve_fit_method_items[];
extern EnumPropertyItem rna_enum_mesh_select_mode_items[];
extern EnumPropertyItem rna_enum_mesh_delimit_mode_items[];
extern EnumPropertyItem rna_enum_space_type_items[];
@@ -197,6 +198,8 @@ extern EnumPropertyItem rna_enum_dt_mix_mode_items[];
extern EnumPropertyItem rna_enum_dt_layers_select_src_items[];
extern EnumPropertyItem rna_enum_dt_layers_select_dst_items[];
+extern EnumPropertyItem rna_enum_abc_compression_items[];
+
/* API calls */
int rna_node_tree_type_to_enum(struct bNodeTreeType *typeinfo);
diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h
index d8bea93bcbc..276531992f9 100644
--- a/source/blender/makesrna/RNA_types.h
+++ b/source/blender/makesrna/RNA_types.h
@@ -64,6 +64,16 @@ typedef struct PropertyPointerRNA {
struct PropertyRNA *prop;
} PropertyPointerRNA;
+/**
+ * Stored result of a RNA path lookup (as used by anim-system)
+ */
+typedef struct PathResolvedRNA {
+ struct PointerRNA ptr;
+ struct PropertyRNA *prop;
+ /* -1 for non-array access */
+ int prop_index;
+} PathResolvedRNA;
+
/* Property */
typedef enum PropertyType {
@@ -285,6 +295,11 @@ typedef struct CollectionPointerLink {
PointerRNA ptr;
} CollectionPointerLink;
+/* Copy of ListBase for RNA... */
+typedef struct CollectionListBase {
+ struct CollectionPointerLink *first, *last;
+} CollectionListBase;
+
typedef enum RawPropertyType {
PROP_RAW_UNSET = -1,
PROP_RAW_INT, // XXX - abused for types that are not set, eg. MFace.verts, needs fixing.
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 31bf0c9389b..0f3ea27a7f9 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -38,6 +38,7 @@ set(DEFSRC
rna_armature.c
rna_boid.c
rna_brush.c
+ rna_cachefile.c
rna_camera.c
rna_cloth.c
rna_color.c
@@ -290,6 +291,13 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+if(WITH_ALEMBIC)
+ list(APPEND INC
+ ../../alembic
+ )
+ add_definitions(-DWITH_ALEMBIC)
+endif()
+
if(WITH_BULLET)
list(APPEND INC
../../../../intern/rigidbody
@@ -319,6 +327,10 @@ if(WITH_OPENVDB)
endif()
endif()
+if(WITH_INPUT_NDOF)
+ add_definitions(-DWITH_INPUT_NDOF)
+endif()
+
# Build makesrna executable
blender_include_dirs(
.
@@ -350,7 +362,10 @@ blender_include_dirs_sys(
"${GLEW_INCLUDE_PATH}"
)
+add_cc_flags_custom_test(makesrna)
+
add_executable(makesrna ${SRC} ${SRC_RNA_INC} ${SRC_DNA_INC})
+
target_link_libraries(makesrna bf_dna)
target_link_libraries(makesrna bf_dna_blenlib)
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index 535847cfc78..569c1ee5f3f 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -50,7 +50,7 @@
#ifndef NDEBUG
void BLI_system_backtrace(FILE *fp)
{
- (void)fp;
+ (void)fp;
}
#endif
@@ -227,6 +227,10 @@ static const char *rna_safe_id(const char *id)
return "operator_value";
else if (STREQ(id, "new"))
return "create";
+ else if (STREQ(id, "co_return")) {
+ /* MSVC2015, C++ uses for coroutines */
+ return "coord_return";
+ }
return id;
}
@@ -466,7 +470,7 @@ static const char *rna_parameter_type_name(PropertyRNA *parm)
}
case PROP_COLLECTION:
{
- return "ListBase";
+ return "CollectionListBase";
}
default:
return "<error, no type specified>";
@@ -3297,6 +3301,7 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_armature.c", "rna_armature_api.c", RNA_def_armature},
{"rna_boid.c", NULL, RNA_def_boid},
{"rna_brush.c", NULL, RNA_def_brush},
+ {"rna_cachefile.c", NULL, RNA_def_cachefile},
{"rna_camera.c", "rna_camera_api.c", RNA_def_camera},
{"rna_cloth.c", NULL, RNA_def_cloth},
{"rna_color.c", NULL, RNA_def_color},
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 63ea836e3de..280ad4aa9b1 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -52,6 +52,7 @@ EnumPropertyItem rna_enum_id_type_items[] = {
{ID_AR, "ARMATURE", ICON_ARMATURE_DATA, "Armature", ""},
{ID_BR, "BRUSH", ICON_BRUSH_DATA, "Brush", ""},
{ID_CA, "CAMERA", ICON_CAMERA_DATA, "Camera", ""},
+ {ID_CF, "CACHEFILE", ICON_FILE, "Cache File", ""},
{ID_CU, "CURVE", ICON_CURVE_DATA, "Curve", ""},
{ID_VF, "FONT", ICON_FONT_DATA, "Font", ""},
{ID_GD, "GREASEPENCIL", ICON_GREASEPENCIL, "Grease Pencil", ""},
@@ -64,10 +65,10 @@ EnumPropertyItem rna_enum_id_type_items[] = {
{ID_LT, "LATTICE", ICON_LATTICE_DATA, "Lattice", ""},
{ID_MSK, "MASK", ICON_MOD_MASK, "Mask", ""},
{ID_MA, "MATERIAL", ICON_MATERIAL_DATA, "Material", ""},
- {ID_MB, "META", ICON_META_DATA, "MetaBall", ""},
+ {ID_MB, "META", ICON_META_DATA, "Metaball", ""},
{ID_ME, "MESH", ICON_MESH_DATA, "Mesh", ""},
- {ID_MC, "MOVIECLIP", ICON_CLIP, "MovieClip", ""},
- {ID_NT, "NODETREE", ICON_NODETREE, "NodeTree", ""},
+ {ID_MC, "MOVIECLIP", ICON_CLIP, "Movie Clip", ""},
+ {ID_NT, "NODETREE", ICON_NODETREE, "Node Tree", ""},
{ID_OB, "OBJECT", ICON_OBJECT_DATA, "Object", ""},
{ID_PC, "PAINTCURVE", ICON_CURVE_BEZCURVE, "Paint Curve", ""},
{ID_PAL, "PALETTE", ICON_COLOR, "Palette", ""},
@@ -87,10 +88,13 @@ EnumPropertyItem rna_enum_id_type_items[] = {
#include "DNA_anim_types.h"
+#include "BLI_listbase.h"
+
#include "BKE_font.h"
#include "BKE_idprop.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_animsys.h"
#include "BKE_material.h"
#include "BKE_depsgraph.h"
@@ -118,7 +122,7 @@ void rna_ID_name_set(PointerRNA *ptr, const char *value)
BLI_libblock_ensure_unique_name(G.main, id->name);
}
-static int rna_ID_name_editable(PointerRNA *ptr)
+static int rna_ID_name_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
ID *id = (ID *)ptr->data;
@@ -136,6 +140,7 @@ short RNA_type_to_ID_code(StructRNA *type)
if (RNA_struct_is_a(type, &RNA_Action)) return ID_AC;
if (RNA_struct_is_a(type, &RNA_Armature)) return ID_AR;
if (RNA_struct_is_a(type, &RNA_Brush)) return ID_BR;
+ if (RNA_struct_is_a(type, &RNA_CacheFile)) return ID_CF;
if (RNA_struct_is_a(type, &RNA_Camera)) return ID_CA;
if (RNA_struct_is_a(type, &RNA_Curve)) return ID_CU;
if (RNA_struct_is_a(type, &RNA_GreasePencil)) return ID_GD;
@@ -176,6 +181,7 @@ StructRNA *ID_code_to_RNA_type(short idcode)
case ID_AR: return &RNA_Armature;
case ID_BR: return &RNA_Brush;
case ID_CA: return &RNA_Camera;
+ case ID_CF: return &RNA_CacheFile;
case ID_CU: return &RNA_Curve;
case ID_GD: return &RNA_GreasePencil;
case ID_GR: return &RNA_Group;
@@ -274,11 +280,11 @@ StructRNA *rna_PropertyGroup_refine(PointerRNA *ptr)
return ptr->type;
}
-static ID *rna_ID_copy(ID *id)
+static ID *rna_ID_copy(ID *id, Main *bmain)
{
ID *newid;
- if (id_copy(id, &newid, false)) {
+ if (id_copy(bmain, id, &newid, false)) {
if (newid) id_us_min(newid);
return newid;
}
@@ -333,6 +339,14 @@ static void rna_ID_user_clear(ID *id)
id->us = 0; /* don't save */
}
+static void rna_ID_user_remap(ID *id, Main *bmain, ID *new_id)
+{
+ if (GS(id->name) == GS(new_id->name)) {
+ /* For now, do not allow remapping data in linked data from here... */
+ BKE_libblock_remap(bmain, id, new_id, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE);
+ }
+}
+
static AnimData * rna_ID_animation_data_create(ID *id, Main *bmain)
{
AnimData *adt = BKE_animdata_add_id(id);
@@ -342,7 +356,7 @@ static AnimData * rna_ID_animation_data_create(ID *id, Main *bmain)
static void rna_ID_animation_data_free(ID *id, Main *bmain)
{
- BKE_animdata_free(id);
+ BKE_animdata_free(id, true);
DAG_relations_tag_update(bmain);
}
@@ -372,15 +386,15 @@ int rna_IDMaterials_assign_int(PointerRNA *ptr, int key, const PointerRNA *assig
}
}
-static void rna_IDMaterials_append_id(ID *id, Material *ma)
+static void rna_IDMaterials_append_id(ID *id, Main *bmain, Material *ma)
{
- BKE_material_append_id(id, ma);
+ BKE_material_append_id(bmain, id, ma);
WM_main_add_notifier(NC_OBJECT | ND_DRAW, id);
WM_main_add_notifier(NC_OBJECT | ND_OB_SHADING, id);
}
-static Material *rna_IDMaterials_pop_id(ID *id, ReportList *reports, int index_i, int remove_material_slot)
+static Material *rna_IDMaterials_pop_id(ID *id, Main *bmain, ReportList *reports, int index_i, int remove_material_slot)
{
Material *ma;
short *totcol = give_totcolp_id(id);
@@ -394,7 +408,7 @@ static Material *rna_IDMaterials_pop_id(ID *id, ReportList *reports, int index_i
return NULL;
}
- ma = BKE_material_pop_id(id, index_i, remove_material_slot);
+ ma = BKE_material_pop_id(bmain, id, index_i, remove_material_slot);
if (*totcol == totcol_orig) {
BKE_report(reports, RPT_ERROR, "No material to removed");
@@ -410,7 +424,7 @@ static Material *rna_IDMaterials_pop_id(ID *id, ReportList *reports, int index_i
static void rna_IDMaterials_clear_id(ID *id, int remove_material_slot)
{
- BKE_material_clear_id(id, remove_material_slot);
+ BKE_material_clear_id(G.main, id, remove_material_slot);
DAG_id_tag_update(id, OB_RECALC_DATA);
WM_main_add_notifier(NC_OBJECT | ND_DRAW, id);
@@ -687,7 +701,7 @@ static void rna_ImagePreview_icon_pixels_float_set(PointerRNA *ptr, const float
static int rna_ImagePreview_icon_id_get(PointerRNA *ptr)
{
/* Using a callback here allows us to only generate icon matching that preview when icon_id is requested. */
- return BKE_icon_preview_ensure((PreviewImage *)(ptr->data));
+ return BKE_icon_preview_ensure(ptr->id.data, (PreviewImage *)(ptr->data));
}
static void rna_ImagePreview_icon_reload(PreviewImage *prv)
{
@@ -806,20 +820,21 @@ static void rna_def_ID_materials(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "ID Materials", "Collection of materials");
func = RNA_def_function(srna, "append", "rna_IDMaterials_append_id");
- RNA_def_function_ui_description(func, "Add a new material to the data block");
+ RNA_def_function_flag(func, FUNC_USE_MAIN);
+ RNA_def_function_ui_description(func, "Add a new material to the data-block");
parm = RNA_def_pointer(func, "material", "Material", "", "Material to add");
RNA_def_property_flag(parm, PROP_REQUIRED);
func = RNA_def_function(srna, "pop", "rna_IDMaterials_pop_id");
- RNA_def_function_flag(func, FUNC_USE_REPORTS);
- RNA_def_function_ui_description(func, "Remove a material from the data block");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_MAIN);
+ RNA_def_function_ui_description(func, "Remove a material from the data-block");
parm = RNA_def_int(func, "index", -1, -MAXMAT, MAXMAT, "", "Index of material to remove", 0, MAXMAT);
RNA_def_boolean(func, "update_data", 0, "", "Update data by re-adjusting the material slots assigned");
parm = RNA_def_pointer(func, "material", "Material", "", "Material to remove");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "clear", "rna_IDMaterials_clear_id");
- RNA_def_function_ui_description(func, "Remove all materials from the data block");
+ RNA_def_function_ui_description(func, "Remove all materials from the data-block");
RNA_def_boolean(func, "update_data", 0, "", "Update data by re-adjusting the material slots assigned");
}
@@ -945,12 +960,12 @@ static void rna_def_ID(BlenderRNA *brna)
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "tag", LIB_TAG_ID_RECALC);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Is Updated", "Datablock is tagged for recalculation");
+ RNA_def_property_ui_text(prop, "Is Updated", "Data-block is tagged for recalculation");
prop = RNA_def_property(srna, "is_updated_data", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "tag", LIB_TAG_ID_RECALC_DATA);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Is Updated Data", "Datablock data is tagged for recalculation");
+ RNA_def_property_ui_text(prop, "Is Updated Data", "Data-block data is tagged for recalculation");
prop = RNA_def_property(srna, "is_library_indirect", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "tag", LIB_TAG_INDIRECT);
@@ -970,6 +985,7 @@ static void rna_def_ID(BlenderRNA *brna)
/* functions */
func = RNA_def_function(srna, "copy", "rna_ID_copy");
RNA_def_function_ui_description(func, "Create a copy of this data-block (not supported for all data-blocks)");
+ RNA_def_function_flag(func, FUNC_USE_MAIN);
parm = RNA_def_pointer(func, "id", "ID", "", "New copy of the ID");
RNA_def_function_return(func, parm);
@@ -977,12 +993,18 @@ static void rna_def_ID(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Clear the user count of a data-block so its not saved, "
"on reload the data will be removed");
+ func = RNA_def_function(srna, "user_remap", "rna_ID_user_remap");
+ RNA_def_function_ui_description(func, "Replace all usage in the .blend file of this ID by new given one");
+ RNA_def_function_flag(func, FUNC_USE_MAIN);
+ parm = RNA_def_pointer(func, "new_id", "ID", "", "New ID to use");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+
func = RNA_def_function(srna, "user_of_id", "BKE_library_ID_use_ID");
RNA_def_function_ui_description(func, "Count the number of times that ID uses/references given one");
parm = RNA_def_pointer(func, "id", "ID", "", "ID to count usages");
- RNA_def_property_flag(parm, PROP_NEVER_NULL);
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
parm = RNA_def_int(func, "count", 0, 0, INT_MAX,
- "", "Number of usages/references of given id by current datablock", 0, INT_MAX);
+ "", "Number of usages/references of given id by current data-block", 0, INT_MAX);
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "animation_data_create", "rna_ID_animation_data_create");
@@ -1006,6 +1028,7 @@ static void rna_def_ID(BlenderRNA *brna)
static void rna_def_library(BlenderRNA *brna)
{
StructRNA *srna;
+ FunctionRNA *func;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "Library", "ID");
@@ -1024,6 +1047,10 @@ static void rna_def_library(BlenderRNA *brna)
prop = RNA_def_property(srna, "packed_file", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "packedfile");
RNA_def_property_ui_text(prop, "Packed File", "");
+
+ func = RNA_def_function(srna, "reload", "WM_lib_reload");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Reload this library and all its linked data-blocks");
}
void RNA_def_ID(BlenderRNA *brna)
{
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 97c71715349..6f054e586ec 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -1619,20 +1619,56 @@ bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop)
{
ID *id = ptr->id.data;
int flag;
+ const char *dummy_info;
prop = rna_ensure_property(prop);
- flag = prop->editable ? prop->editable(ptr) : prop->flag;
+ flag = prop->editable ? prop->editable(ptr, &dummy_info) : prop->flag;
+
return ((flag & PROP_EDITABLE) &&
(flag & PROP_REGISTER) == 0 &&
- (!id || !id->lib || (prop->flag & PROP_LIB_EXCEPTION)));
+ (!id || !ID_IS_LINKED_DATABLOCK(id) || (prop->flag & PROP_LIB_EXCEPTION)));
+}
+
+/**
+ * Version of #RNA_property_editable that tries to return additional info in \a r_info that can be exposed in UI.
+ */
+bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char **r_info)
+{
+ ID *id = ptr->id.data;
+ int flag;
+
+ prop = rna_ensure_property(prop);
+ *r_info = "";
+
+ /* get flag */
+ if (prop->editable) {
+ flag = prop->editable(ptr, r_info);
+ }
+ else {
+ flag = prop->flag;
+ if ((flag & PROP_EDITABLE) == 0 || (flag & PROP_REGISTER)) {
+ *r_info = "This property is for internal use only and can't be edited.";
+ }
+ }
+
+ /* property from linked data-block */
+ if (id && ID_IS_LINKED_DATABLOCK(id) && (prop->flag & PROP_LIB_EXCEPTION) == 0) {
+ if (!(*r_info)[0]) {
+ *r_info = "Can't edit this property from a linked data-block.";
+ }
+ return false;
+ }
+
+ return ((flag & PROP_EDITABLE) && (flag & PROP_REGISTER) == 0);
}
bool RNA_property_editable_flag(PointerRNA *ptr, PropertyRNA *prop)
{
int flag;
+ const char *dummy_info;
prop = rna_ensure_property(prop);
- flag = prop->editable ? prop->editable(ptr) : prop->flag;
+ flag = prop->editable ? prop->editable(ptr, &dummy_info) : prop->flag;
return (flag & PROP_EDITABLE) != 0;
}
@@ -1647,22 +1683,24 @@ bool RNA_property_editable_index(PointerRNA *ptr, PropertyRNA *prop, int index)
prop = rna_ensure_property(prop);
flag = prop->flag;
-
- if (prop->editable)
- flag &= prop->editable(ptr);
+
+ if (prop->editable) {
+ const char *dummy_info;
+ flag &= prop->editable(ptr, &dummy_info);
+ }
if (prop->itemeditable)
flag &= prop->itemeditable(ptr, index);
id = ptr->id.data;
- return (flag & PROP_EDITABLE) && (!id || !id->lib || (prop->flag & PROP_LIB_EXCEPTION));
+ return (flag & PROP_EDITABLE) && (!id || !ID_IS_LINKED_DATABLOCK(id) || (prop->flag & PROP_LIB_EXCEPTION));
}
bool RNA_property_animateable(PointerRNA *ptr, PropertyRNA *prop)
{
/* check that base ID-block can support animation data */
- if (!id_type_can_have_animdata(ptr->id.data))
+ if (!id_can_have_animdata(ptr->id.data))
return false;
prop = rna_ensure_property(prop);
@@ -2873,6 +2911,45 @@ void *RNA_property_enum_py_data_get(PropertyRNA *prop)
return eprop->py_data;
}
+/**
+ * Get the value of the item that is \a step items away from \a from_value.
+ *
+ * \param from_value: Item value to start stepping from.
+ * \param step: Absolute value defines step size, sign defines direction.
+ * E.g to get the next item, pass 1, for the previous -1.
+ */
+int RNA_property_enum_step(const bContext *C, PointerRNA *ptr, PropertyRNA *prop, int from_value, int step)
+{
+ EnumPropertyItem *item_array;
+ int totitem;
+ bool free;
+ int result_value = from_value;
+ int i, i_init;
+ int single_step = (step < 0) ? -1 : 1;
+ int step_tot = 0;
+
+ RNA_property_enum_items((bContext *)C, ptr, prop, &item_array, &totitem, &free);
+ i = RNA_enum_from_value(item_array, from_value);
+ i_init = i;
+
+ do {
+ i = mod_i(i + single_step, totitem);
+ if (item_array[i].identifier[0]) {
+ step_tot += single_step;
+ }
+ } while ((i != i_init) && (step_tot != step));
+
+ if (i != i_init) {
+ result_value = item_array[i].value;
+ }
+
+ if (free) {
+ MEM_freeN(item_array);
+ }
+
+ return result_value;
+}
+
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
{
PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
@@ -3127,8 +3204,11 @@ void RNA_property_collection_add(PointerRNA *ptr, PropertyRNA *prop, PointerRNA
RNA_parameter_list_free(&params);
}
}
- /*else
- printf("%s %s.%s: not implemented for this property.\n", __func__, ptr->type->identifier, prop->identifier);*/
+#if 0
+ else {
+ printf("%s %s.%s: not implemented for this property.\n", __func__, ptr->type->identifier, prop->identifier);
+ }
+#endif
#endif
if (r_ptr) {
@@ -3187,8 +3267,11 @@ bool RNA_property_collection_remove(PointerRNA *ptr, PropertyRNA *prop, int key)
return false;
}
- /*else
- printf("%s %s.%s: only supported for id properties.\n", __func__, ptr->type->identifier, prop->identifier);*/
+#if 0
+ else {
+ printf("%s %s.%s: only supported for id properties.\n", __func__, ptr->type->identifier, prop->identifier);
+ }
+#endif
#endif
return false;
}
@@ -4642,7 +4725,47 @@ char *RNA_path_from_ID_to_struct(PointerRNA *ptr)
return ptrpath;
}
-char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop)
+static void rna_path_array_multi_from_flat_index(
+ const int dimsize[RNA_MAX_ARRAY_LENGTH], const int totdims,
+ const int index_dim, int index,
+ int r_index_multi[RNA_MAX_ARRAY_LENGTH])
+{
+ int dimsize_step[RNA_MAX_ARRAY_LENGTH + 1];
+ int i = totdims - 1;
+ dimsize_step[i + 1] = 1;
+ dimsize_step[i] = dimsize[i];
+ while (--i != -1) {
+ dimsize_step[i] = dimsize[i] * dimsize_step[i + 1];
+ }
+ while (++i != index_dim) {
+ int index_round = index / dimsize_step[i + 1];
+ r_index_multi[i] = index_round;
+ index -= (index_round * dimsize_step[i + 1]);
+ }
+ BLI_assert(index == 0);
+}
+
+static void rna_path_array_multi_string_from_flat_index(
+ PointerRNA *ptr, PropertyRNA *prop, int index_dim, int index,
+ char *index_str, int index_str_len)
+{
+ int dimsize[RNA_MAX_ARRAY_LENGTH];
+ int totdims = RNA_property_array_dimension(ptr, prop, dimsize);
+ int index_multi[RNA_MAX_ARRAY_LENGTH];
+
+ rna_path_array_multi_from_flat_index(dimsize, totdims, index_dim, index, index_multi);
+
+ for (int i = 0, offset = 0; (i < index_dim) && (offset < index_str_len); i++) {
+ offset += BLI_snprintf_rlen(&index_str[offset], index_str_len - offset, "[%d]", index_multi[i]);
+ }
+}
+
+/**
+ * \param index_dim: The dimension to show, 0 disables. 1 for 1d array, 2 for 2d. etc.
+ * \param index: The *flattened* index to use when \a ``index_dim > 0``,
+ * this is expanded when used with multi-dimensional arrays.
+ */
+char *RNA_path_from_ID_to_property_index(PointerRNA *ptr, PropertyRNA *prop, int index_dim, int index)
{
const bool is_rna = (prop->magic == RNA_MAGIC);
const char *propname;
@@ -4656,25 +4779,36 @@ char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop)
propname = RNA_property_identifier(prop);
+ /* support indexing w/ multi-dimensional arrays */
+ char index_str[RNA_MAX_ARRAY_LENGTH * 12 + 1];
+ if (index_dim == 0) {
+ index_str[0] = '\0';
+ }
+ else {
+ rna_path_array_multi_string_from_flat_index(
+ ptr, prop, index_dim, index,
+ index_str, sizeof(index_str));
+ }
+
if (ptrpath) {
if (is_rna) {
- path = BLI_sprintfN("%s.%s", ptrpath, propname);
+ path = BLI_sprintfN("%s.%s%s", ptrpath, propname, index_str);
}
else {
char propname_esc[MAX_IDPROP_NAME * 2];
BLI_strescape(propname_esc, propname, sizeof(propname_esc));
- path = BLI_sprintfN("%s[\"%s\"]", ptrpath, propname_esc);
+ path = BLI_sprintfN("%s[\"%s\"]%s", ptrpath, propname_esc, index_str);
}
MEM_freeN(ptrpath);
}
else if (RNA_struct_is_ID(ptr->type)) {
if (is_rna) {
- path = BLI_strdup(propname);
+ path = BLI_sprintfN("%s%s", propname, index_str);
}
else {
char propname_esc[MAX_IDPROP_NAME * 2];
BLI_strescape(propname_esc, propname, sizeof(propname_esc));
- path = BLI_sprintfN("[\"%s\"]", propname_esc);
+ path = BLI_sprintfN("[\"%s\"]%s", propname_esc, index_str);
}
}
else {
@@ -4684,6 +4818,11 @@ char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop)
return path;
}
+char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop)
+{
+ return RNA_path_from_ID_to_property_index(ptr, prop, 0, -1);
+}
+
/**
* \return the path to given ptr/prop from the closest ancestor of given type, if any (else return NULL).
*/
@@ -6904,3 +7043,22 @@ bool RNA_struct_equals(PointerRNA *a, PointerRNA *b, eRNAEqualsMode mode)
return equals;
}
+
+bool RNA_path_resolved_create(
+ PointerRNA *ptr, struct PropertyRNA *prop,
+ const int prop_index,
+ PathResolvedRNA *r_anim_rna)
+{
+ int array_len = RNA_property_array_length(ptr, prop);
+
+ if ((array_len == 0) || (prop_index < array_len)) {
+ r_anim_rna->ptr = *ptr;
+ r_anim_rna->prop = prop;
+ r_anim_rna->prop_index = array_len ? prop_index : -1;
+
+ return true;
+ }
+ else {
+ return false;
+ }
+}
diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c
index 7c21ce95a1d..3f2c0f3d434 100644
--- a/source/blender/makesrna/intern/rna_action.c
+++ b/source/blender/makesrna/intern/rna_action.c
@@ -308,6 +308,14 @@ static void rna_def_dopesheet(BlenderRNA *brna)
RNA_def_property_ui_icon(prop, ICON_GHOST_ENABLED, 0);
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+ prop = RNA_def_property(srna, "use_datablock_sort", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", ADS_FLAG_NO_DB_SORT);
+ RNA_def_property_ui_text(prop, "Sort Data-Blocks",
+ "Alphabetically sorts data-blocks - mainly objects in the scene "
+ "(disable to increase viewport speed)");
+ RNA_def_property_ui_icon(prop, ICON_SORTALPHA, 0);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+
/* Debug Filtering Settings */
prop = RNA_def_property(srna, "show_only_errors", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "filterflag", ADS_FILTER_ONLY_ERRORS);
@@ -369,7 +377,7 @@ static void rna_def_dopesheet(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_missing_nla", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "filterflag", ADS_FILTER_NLA_NOACT);
RNA_def_property_ui_text(prop, "Include Missing NLA",
- "Include animation data blocks with no NLA data (NLA editor only)");
+ "Include animation data-blocks with no NLA data (NLA editor only)");
RNA_def_property_ui_icon(prop, ICON_ACTION, 0);
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
@@ -508,7 +516,7 @@ static void rna_def_dopesheet(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_gpencil_3d_only", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "filterflag", ADS_FILTER_GP_3DONLY);
RNA_def_property_ui_text(prop, "Active Scene Only",
- "Only show Grease Pencil datablocks used as part of the active scene");
+ "Only show Grease Pencil data-blocks used as part of the active scene");
RNA_def_property_ui_icon(prop, ICON_SCENE_DATA, 0);
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
}
@@ -706,7 +714,8 @@ static void rna_def_action(BlenderRNA *brna)
prop = RNA_def_property(srna, "pose_markers", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "markers", NULL);
RNA_def_property_struct_type(prop, "TimelineMarker");
- RNA_def_property_flag(prop, PROP_LIB_EXCEPTION); /* T45689 - so that the list isn't greyed out; adding/removing is still banned though */
+ /* Use lib exception so the list isn't grayed out; adding/removing is still banned though, see T45689 */
+ RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
RNA_def_property_ui_text(prop, "Pose Markers", "Markers specific to this action, for labeling poses");
rna_def_action_pose_markers(brna, prop);
diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c
index c3d1070b8c2..cdbf7582fa7 100644
--- a/source/blender/makesrna/intern/rna_animation.c
+++ b/source/blender/makesrna/intern/rna_animation.c
@@ -89,7 +89,7 @@ static void rna_AnimData_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Point
DAG_id_tag_update(id, OB_RECALC_OB | OB_RECALC_DATA);
}
-static int rna_AnimData_action_editable(PointerRNA *ptr)
+static int rna_AnimData_action_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
AnimData *adt = (AnimData *)ptr->data;
@@ -116,6 +116,23 @@ static void rna_AnimData_action_set(PointerRNA *ptr, PointerRNA value)
}
}
+static void rna_AnimData_tweakmode_set(PointerRNA *ptr, const int value)
+{
+ AnimData *adt = (AnimData *)ptr->data;
+
+ /* NOTE: technically we should also set/unset SCE_NLA_EDIT_ON flag on the
+ * scene which is used to make polling tests faster, but this flag is weak
+ * and can easily break e.g. by changing layer visibility. This needs to be
+ * dealt with at some point. */
+
+ if (value) {
+ BKE_nla_tweakmode_enter(adt);
+ }
+ else {
+ BKE_nla_tweakmode_exit(adt);
+ }
+}
+
/* ****************************** */
/* wrapper for poll callback */
@@ -288,7 +305,7 @@ static StructRNA *rna_ksPath_id_typef(PointerRNA *ptr)
return ID_code_to_RNA_type(ksp->idtype);
}
-static int rna_ksPath_id_editable(PointerRNA *ptr)
+static int rna_ksPath_id_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
KS_Path *ksp = (KS_Path *)ptr->data;
return (ksp->idtype) ? PROP_EDITABLE : 0;
@@ -376,7 +393,7 @@ static void rna_KeyingSet_name_set(PointerRNA *ptr, const char *value)
}
-static int rna_KeyingSet_active_ksPath_editable(PointerRNA *ptr)
+static int rna_KeyingSet_active_ksPath_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
KeyingSet *ks = (KeyingSet *)ptr->data;
@@ -789,7 +806,7 @@ static void rna_def_keyingset_paths(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "ksp", "KeyingSetPath", "New Path", "Path created and added to the Keying Set");
RNA_def_function_return(func, parm);
/* ID-block for target */
- parm = RNA_def_pointer(func, "target_id", "ID", "Target ID", "ID-Datablock for the destination");
+ parm = RNA_def_pointer(func, "target_id", "ID", "Target ID", "ID data-block for the destination");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* rna-path */
/* XXX hopefully this is long enough */
@@ -1041,6 +1058,12 @@ static void rna_def_animdata(BlenderRNA *brna)
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", ADT_NLA_EVAL_OFF);
RNA_def_property_ui_text(prop, "NLA Evaluation Enabled", "NLA stack is evaluated when evaluating this block");
RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
+
+ prop = RNA_def_property(srna, "use_tweak_mode", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", ADT_NLA_EDIT_ON);
+ RNA_def_property_boolean_funcs(prop, NULL, "rna_AnimData_tweakmode_set");
+ RNA_def_property_ui_text(prop, "Use NLA Tweak Mode", "Whether to enable or disable tweak mode in NLA");
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL);
}
/* --- */
diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c
index a8ef4664fd7..5c7f51516cb 100644
--- a/source/blender/makesrna/intern/rna_armature.c
+++ b/source/blender/makesrna/intern/rna_armature.c
@@ -482,6 +482,82 @@ static void rna_Armature_transform(struct bArmature *arm, float *mat)
#else
+/* Settings for curved bbone settings - The posemode values get applied over the top of the editmode ones */
+void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone)
+{
+#define RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone) \
+ { \
+ if (is_posebone) \
+ RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update"); \
+ else \
+ RNA_def_property_update(prop, 0, "rna_Armature_update_data"); \
+ } (void)0;
+
+ PropertyRNA *prop;
+
+ /* Roll In/Out */
+ prop = RNA_def_property(srna, "bbone_rollin", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "roll1");
+ RNA_def_property_range(prop, -M_PI * 2.0, M_PI * 2.0);
+ RNA_def_property_ui_text(prop, "Roll In", "Roll offset for the start of the B-Bone, adjusts twist");
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+
+ prop = RNA_def_property(srna, "bbone_rollout", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "roll2");
+ RNA_def_property_range(prop, -M_PI * 2.0, M_PI * 2.0);
+ RNA_def_property_ui_text(prop, "Roll Out", "Roll offset for the end of the B-Bone, adjusts twist");
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+
+ if (is_posebone == false) {
+ prop = RNA_def_property(srna, "use_endroll_as_inroll", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Inherit End Roll", "Use Roll Out of parent bone as Roll In of its children");
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_ADD_PARENT_END_ROLL);
+ RNA_def_property_update(prop, 0, "rna_Armature_update_data");
+ }
+
+ /* Curve X/Y Offsets */
+ prop = RNA_def_property(srna, "bbone_curveinx", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "curveInX");
+ RNA_def_property_range(prop, -5.0f, 5.0f);
+ RNA_def_property_ui_text(prop, "In X", "X-axis handle offset for start of the B-Bone's curve, adjusts curvature");
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+
+ prop = RNA_def_property(srna, "bbone_curveiny", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "curveInY");
+ RNA_def_property_range(prop, -5.0f, 5.0f);
+ RNA_def_property_ui_text(prop, "In Y", "Y-axis handle offset for start of the B-Bone's curve, adjusts curvature");
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+
+ prop = RNA_def_property(srna, "bbone_curveoutx", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "curveOutX");
+ RNA_def_property_range(prop, -5.0f, 5.0f);
+ RNA_def_property_ui_text(prop, "Out X", "X-axis handle offset for end of the B-Bone's curve, adjusts curvature");
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+
+ prop = RNA_def_property(srna, "bbone_curveouty", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "curveOutY");
+ RNA_def_property_range(prop, -5.0f, 5.0f);
+ RNA_def_property_ui_text(prop, "Out Y", "Y-axis handle offset for end of the B-Bone's curve, adjusts curvature");
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+
+ /* Scale In/Out */
+ prop = RNA_def_property(srna, "bbone_scalein", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "scaleIn");
+ RNA_def_property_range(prop, 0.0f, 5.0f);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Scale In", "Scale factor for start of the B-Bone, adjusts thickness (for tapering effects)");
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+
+ prop = RNA_def_property(srna, "bbone_scaleout", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "scaleOut");
+ RNA_def_property_range(prop, 0.0f, 5.0f);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Scale Out", "Scale factor for end of the B-Bone, adjusts thickness (for tapering effects)");
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+
+#undef RNA_DEF_CURVEBONE_UPDATE
+}
+
static void rna_def_bone_common(StructRNA *srna, int editbone)
{
PropertyRNA *prop;
@@ -653,6 +729,7 @@ static void rna_def_bone(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Children", "Bones which are children of this bone");
rna_def_bone_common(srna, 0);
+ rna_def_bone_curved_common(srna, 0);
/* XXX should we define this in PoseChannel wrapping code instead?
* But PoseChannels directly get some of their flags from here... */
@@ -766,6 +843,7 @@ static void rna_def_edit_bone(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Armature_editbone_transform_update");
rna_def_bone_common(srna, 1);
+ rna_def_bone_curved_common(srna, 0);
prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_HIDDEN_A);
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index e13919dd1a1..ac348c1750c 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -530,10 +530,12 @@ static EnumPropertyItem *rna_Brush_direction_itemf(bContext *C, PointerRNA *ptr,
switch ((BrushMaskTool)me->mask_tool) {
case BRUSH_MASK_DRAW:
return prop_direction_items;
- break;
+
case BRUSH_MASK_SMOOTH:
return prop_default_items;
- break;
+
+ default:
+ return prop_default_items;
}
case SCULPT_TOOL_FLATTEN:
@@ -554,7 +556,6 @@ static EnumPropertyItem *rna_Brush_direction_itemf(bContext *C, PointerRNA *ptr,
default:
return prop_default_items;
}
- break;
case ePaintTexture2D:
case ePaintTextureProjective:
@@ -565,7 +566,6 @@ static EnumPropertyItem *rna_Brush_direction_itemf(bContext *C, PointerRNA *ptr,
default:
return prop_default_items;
}
- break;
default:
return prop_default_items;
diff --git a/source/blender/makesrna/intern/rna_cachefile.c b/source/blender/makesrna/intern/rna_cachefile.c
new file mode 100644
index 00000000000..09fdeb15b10
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_cachefile.c
@@ -0,0 +1,192 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Kevin Dietrich.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "DNA_cachefile_types.h"
+#include "DNA_scene_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "rna_internal.h"
+
+#ifdef RNA_RUNTIME
+
+#include "BKE_cachefile.h"
+#include "BKE_depsgraph.h"
+
+#include "BLI_string.h"
+
+#include "DEG_depsgraph.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#ifdef WITH_ALEMBIC
+# include "../../../alembic/ABC_alembic.h"
+#endif
+
+static void rna_CacheFile_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ CacheFile *cache_file = (CacheFile *)ptr->data;
+
+ DAG_id_tag_update(&cache_file->id, 0);
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
+
+ UNUSED_VARS(bmain, scene);
+}
+
+static void rna_CacheFile_update_handle(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ CacheFile *cache_file = ptr->data;
+
+ if ((cache_file->flag & CACHEFILE_DIRTY) != 0) {
+ BKE_cachefile_clean(scene, cache_file);
+ BLI_freelistN(&cache_file->object_paths);
+ cache_file->flag &= ~CACHEFILE_DIRTY;
+ }
+
+ BKE_cachefile_reload(bmain, cache_file);
+
+ rna_CacheFile_update(bmain, scene, ptr);
+}
+
+static void rna_CacheFile_object_paths_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ CacheFile *cache_file = (CacheFile *)ptr->data;
+ rna_iterator_listbase_begin(iter, &cache_file->object_paths, NULL);
+}
+
+static void rna_CacheFile_filename_set(PointerRNA *ptr, const char *value)
+{
+ CacheFile *cache_file = ptr->data;
+
+ if (STREQ(cache_file->filepath, value)) {
+ return;
+ }
+
+ /* Different file is opened, close all readers. */
+ cache_file->flag |= CACHEFILE_DIRTY;
+
+ BLI_strncpy(cache_file->filepath, value, sizeof(cache_file->filepath));
+}
+
+#else
+
+/* cachefile.object_paths */
+static void rna_def_alembic_object_path(BlenderRNA *brna)
+{
+ StructRNA *srna = RNA_def_struct(brna, "AlembicObjectPath", NULL);
+ RNA_def_struct_sdna(srna, "AlembicObjectPath");
+ RNA_def_struct_ui_text(srna, "Object Path", "Path of an object inside of an Alembic archive");
+ RNA_def_struct_ui_icon(srna, ICON_NONE);
+
+ PropertyRNA *prop = RNA_def_property(srna, "path", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Path", "Object path");
+ RNA_def_struct_name_property(srna, prop);
+}
+
+/* cachefile.object_paths */
+static void rna_def_cachefile_object_paths(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ RNA_def_property_srna(cprop, "AlembicObjectPaths");
+ StructRNA *srna = RNA_def_struct(brna, "AlembicObjectPaths", NULL);
+ RNA_def_struct_sdna(srna, "CacheFile");
+ RNA_def_struct_ui_text(srna, "Object Paths", "Collection of object paths");
+}
+
+static void rna_def_cachefile(BlenderRNA *brna)
+{
+ StructRNA *srna = RNA_def_struct(brna, "CacheFile", "ID");
+ RNA_def_struct_sdna(srna, "CacheFile");
+ RNA_def_struct_ui_text(srna, "CacheFile", "");
+ RNA_def_struct_ui_icon(srna, ICON_FILE);
+
+ PropertyRNA *prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_CacheFile_filename_set");
+ RNA_def_property_ui_text(prop, "File Path", "Path to external displacements file");
+ RNA_def_property_update(prop, 0, "rna_CacheFile_update_handle");
+
+ prop = RNA_def_property(srna, "is_sequence", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Sequence", "Whether the cache is separated in a series of files");
+ RNA_def_property_update(prop, 0, "rna_CacheFile_update");
+
+ /* ----------------- For Scene time ------------------- */
+
+ prop = RNA_def_property(srna, "override_frame", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Override Frame",
+ "Whether to use a custom frame for looking up data in the cache file,"
+ " instead of using the current scene frame");
+ RNA_def_property_update(prop, 0, "rna_CacheFile_update");
+
+ prop = RNA_def_property(srna, "frame", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "frame");
+ RNA_def_property_range(prop, -MAXFRAME, MAXFRAME);
+ RNA_def_property_ui_text(prop, "Frame", "The time to use for looking up the data in the cache file,"
+ " or to determine which file to use in a file sequence");
+ RNA_def_property_update(prop, 0, "rna_CacheFile_update");
+
+ /* ----------------- Axis Conversion ----------------- */
+
+ prop = RNA_def_property(srna, "forward_axis", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "forward_axis");
+ RNA_def_property_enum_items(prop, rna_enum_object_axis_items);
+ RNA_def_property_ui_text(prop, "Forward", "");
+ RNA_def_property_update(prop, 0, "rna_CacheFile_update");
+
+ prop = RNA_def_property(srna, "up_axis", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "up_axis");
+ RNA_def_property_enum_items(prop, rna_enum_object_axis_items);
+ RNA_def_property_ui_text(prop, "Up", "");
+ RNA_def_property_update(prop, 0, "rna_CacheFile_update");
+
+ prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "scale");
+ RNA_def_property_range(prop, 0.0001f, 1000.0f);
+ RNA_def_property_ui_text(prop, "Scale", "Value by which to enlarge or shrink the object with respect to the world's origin"
+ " (only applicable through a Transform Cache constraint)");
+ RNA_def_property_update(prop, 0, "rna_CacheFile_update");
+
+ /* object paths */
+ prop = RNA_def_property(srna, "object_paths", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "object_paths", NULL);
+ RNA_def_property_collection_funcs(prop, "rna_CacheFile_object_paths_begin", "rna_iterator_listbase_next",
+ "rna_iterator_listbase_end", "rna_iterator_listbase_get",
+ NULL, NULL, NULL, NULL);
+ RNA_def_property_struct_type(prop, "AlembicObjectPath");
+ RNA_def_property_srna(prop, "AlembicObjectPaths");
+ RNA_def_property_ui_text(prop, "Object Paths", "Paths of the objects inside the Alembic archive");
+ rna_def_cachefile_object_paths(brna, prop);
+
+ rna_def_animdata_common(srna);
+}
+
+void RNA_def_cachefile(BlenderRNA *brna)
+{
+ rna_def_cachefile(brna);
+ rna_def_alembic_object_path(brna);
+}
+
+#endif
diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c
index fd81f3aa46c..078ba13d76d 100644
--- a/source/blender/makesrna/intern/rna_camera.c
+++ b/source/blender/makesrna/intern/rna_camera.c
@@ -131,8 +131,8 @@ static void rna_def_camera_stereo_data(BlenderRNA *brna)
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
prop = RNA_def_property(srna, "interocular_distance", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_range(prop, 0.0f, 100.0f);
- RNA_def_property_ui_range(prop, 0.0f, 1.f, 1, 3);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 1e4f, 1, 3);
RNA_def_property_ui_text(prop, "Interocular Distance",
"Set the distance between the eyes - the stereo plane distance / 30 should be fine");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
@@ -151,6 +151,24 @@ static void rna_def_camera_stereo_data(BlenderRNA *brna)
"Render every pixel rotating the camera around the "
"middle of the interocular distance");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "use_pole_merge", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CAM_S3D_POLE_MERGE);
+ RNA_def_property_ui_text(prop, "Use Pole Merge",
+ "Fade interocular distance to 0 after the given cutoff angle");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "pole_merge_angle_from", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_range(prop, 0.0f, M_PI / 2.0);
+ RNA_def_property_ui_text(prop, "Pole Merge Start Angle",
+ "Angle at which interocular distance starts to fade to 0");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "pole_merge_angle_to", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_range(prop, 0.0f, M_PI / 2.0);
+ RNA_def_property_ui_text(prop, "Pole Merge End Angle",
+ "Angle at which interocular distance is 0");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
}
void RNA_def_camera(BlenderRNA *brna)
@@ -239,13 +257,15 @@ void RNA_def_camera(BlenderRNA *brna)
prop = RNA_def_property(srna, "clip_start", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "clipsta");
- RNA_def_property_range(prop, 0.001f, FLT_MAX);
+ RNA_def_property_range(prop, 1e-6f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
RNA_def_property_ui_text(prop, "Clip Start", "Camera near clipping distance");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
prop = RNA_def_property(srna, "clip_end", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "clipend");
- RNA_def_property_range(prop, 1.0f, FLT_MAX);
+ RNA_def_property_range(prop, 1e-6f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
RNA_def_property_ui_text(prop, "Clip End", "Camera far clipping distance");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
diff --git a/source/blender/makesrna/intern/rna_cloth.c b/source/blender/makesrna/intern/rna_cloth.c
index c91b6487653..d8bcbc2cc72 100644
--- a/source/blender/makesrna/intern/rna_cloth.c
+++ b/source/blender/makesrna/intern/rna_cloth.c
@@ -56,6 +56,12 @@ static void rna_cloth_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerR
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ob);
}
+static void rna_cloth_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ DAG_relations_tag_update(bmain);
+ rna_cloth_update(bmain, scene, ptr);
+}
+
static void rna_cloth_pinning_changed(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
Object *ob = (Object *)ptr->id.data;
@@ -68,6 +74,16 @@ static void rna_cloth_pinning_changed(Main *UNUSED(bmain), Scene *UNUSED(scene),
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ob);
}
+static void rna_ClothSettings_bending_set(struct PointerRNA *ptr, float value)
+{
+ ClothSimSettings *settings = (ClothSimSettings *)ptr->data;
+
+ settings->bending = value;
+
+ /* check for max clipping */
+ if (value > settings->max_bend)
+ settings->max_bend = value;
+}
static void rna_ClothSettings_max_bend_set(struct PointerRNA *ptr, float value)
{
@@ -80,6 +96,17 @@ static void rna_ClothSettings_max_bend_set(struct PointerRNA *ptr, float value)
settings->max_bend = value;
}
+static void rna_ClothSettings_structural_set(struct PointerRNA *ptr, float value)
+{
+ ClothSimSettings *settings = (ClothSimSettings *)ptr->data;
+
+ settings->structural = value;
+
+ /* check for max clipping */
+ if (value > settings->max_struct)
+ settings->max_struct = value;
+}
+
static void rna_ClothSettings_max_struct_set(struct PointerRNA *ptr, float value)
{
ClothSimSettings *settings = (ClothSimSettings *)ptr->data;
@@ -436,11 +463,19 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "quality", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "stepsPerFrame");
- RNA_def_property_range(prop, 1, 80);
+ RNA_def_property_range(prop, 1, INT_MAX);
+ RNA_def_property_ui_range(prop, 1, 80, 1, -1);
RNA_def_property_ui_text(prop, "Quality",
"Quality of the simulation in steps per frame (higher is better quality but slower)");
RNA_def_property_update(prop, 0, "rna_cloth_update");
+ prop = RNA_def_property(srna, "time_scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "time_scale");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 10.0f, 10, 3);
+ RNA_def_property_ui_text(prop, "Speed", "Cloth speed is multiplied by this value");
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
+
prop = RNA_def_property(srna, "vertex_group_shrink", PROP_STRING, PROP_NONE);
RNA_def_property_string_funcs(prop, "rna_ClothSettings_shrink_vgroup_get", "rna_ClothSettings_shrink_vgroup_length",
"rna_ClothSettings_shrink_vgroup_set");
@@ -485,6 +520,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "structural_stiffness", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "structural");
RNA_def_property_range(prop, 0.0f, 10000.0f);
+ RNA_def_property_float_funcs(prop, NULL, "rna_ClothSettings_structural_set", NULL);
RNA_def_property_ui_text(prop, "Structural Stiffness", "Overall stiffness of structure");
RNA_def_property_update(prop, 0, "rna_cloth_update");
@@ -513,6 +549,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "bending_stiffness", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "bending");
RNA_def_property_range(prop, 0.0f, 10000.0f);
+ RNA_def_property_float_funcs(prop, NULL, "rna_ClothSettings_bending_set", NULL);
RNA_def_property_ui_text(prop, "Bending Stiffness",
"Wrinkle coefficient (higher = less smaller but more big wrinkles)");
RNA_def_property_update(prop, 0, "rna_cloth_update");
@@ -557,6 +594,12 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Rest Shape Key", "Shape key to use the rest spring lengths from");
RNA_def_property_update(prop, 0, "rna_cloth_update");
+ prop = RNA_def_property(srna, "use_dynamic_mesh", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH);
+ RNA_def_property_ui_text(prop, "Dynamic Base Mesh", "Make simulation respect deformations in the base mesh");
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+
/* unused */
/* unused still */
@@ -656,7 +699,8 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "collision_quality", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "loop_count");
- RNA_def_property_range(prop, 1, 20);
+ RNA_def_property_range(prop, 1, SHRT_MAX);
+ RNA_def_property_ui_range(prop, 1, 20, 1, -1);
RNA_def_property_ui_text(prop, "Collision Quality",
"How many collision iterations should be done. (higher is better quality but slower)");
RNA_def_property_update(prop, 0, "rna_cloth_update");
@@ -681,7 +725,8 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "self_collision_quality", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "self_loop_count");
- RNA_def_property_range(prop, 1, 10);
+ RNA_def_property_range(prop, 1, SHRT_MAX);
+ RNA_def_property_ui_range(prop, 1, 10, 1, -1);
RNA_def_property_ui_text(prop, "Self Collision Quality",
"How many self collision iterations should be done "
"(higher is better quality but slower)");
@@ -690,7 +735,7 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "group", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Collision Group", "Limit colliders to this Group");
- RNA_def_property_update(prop, 0, "rna_cloth_update");
+ RNA_def_property_update(prop, 0, "rna_cloth_dependency_update");
prop = RNA_def_property(srna, "vertex_group_self_collisions", PROP_STRING, PROP_NONE);
RNA_def_property_string_funcs(prop, "rna_CollSettings_selfcol_vgroup_get", "rna_CollSettings_selfcol_vgroup_length",
diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c
index 021bc608564..24f2d8174af 100644
--- a/source/blender/makesrna/intern/rna_color.c
+++ b/source/blender/makesrna/intern/rna_color.c
@@ -690,7 +690,8 @@ static void rna_def_curvemappoint(BlenderRNA *brna)
PropertyRNA *prop;
static EnumPropertyItem prop_handle_type_items[] = {
{0, "AUTO", 0, "Auto Handle", ""},
- {CUMA_VECTOR, "VECTOR", 0, "Vector Handle", ""},
+ {CUMA_HANDLE_AUTO_ANIM, "AUTO_CLAMPED", 0, "Auto Clamped Handle", ""},
+ {CUMA_HANDLE_VECTOR, "VECTOR", 0, "Vector Handle", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -1018,10 +1019,11 @@ static void rna_def_scopes(BlenderRNA *brna)
static EnumPropertyItem prop_wavefrm_mode_items[] = {
{SCOPES_WAVEFRM_LUMA, "LUMA", ICON_COLOR, "Luma", ""},
- {SCOPES_WAVEFRM_RGB, "RGB", ICON_COLOR, "Red Green Blue", ""},
+ {SCOPES_WAVEFRM_RGB_PARADE, "PARADE", ICON_COLOR, "Parade", ""},
{SCOPES_WAVEFRM_YCC_601, "YCBCR601", ICON_COLOR, "YCbCr (ITU 601)", ""},
{SCOPES_WAVEFRM_YCC_709, "YCBCR709", ICON_COLOR, "YCbCr (ITU 709)", ""},
{SCOPES_WAVEFRM_YCC_JPEG, "YCBCRJPG", ICON_COLOR, "YCbCr (Jpeg)", ""},
+ {SCOPES_WAVEFRM_RGB, "RGB", ICON_COLOR, "Red Green Blue", ""},
{0, NULL, 0, NULL, NULL}
};
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index 0b5d0f3d41d..de1a0f24c31 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -72,6 +72,8 @@ EnumPropertyItem rna_enum_constraint_type_items[] = {
"Compensate for scaling one axis by applying suitable scaling to the other two axes"},
{CONSTRAINT_TYPE_TRANSFORM, "TRANSFORM", ICON_CONSTRAINT_DATA, "Transformation",
"Use one transform property from target to control another (or same) property on owner"},
+ {CONSTRAINT_TYPE_TRANSFORM_CACHE, "TRANSFORM_CACHE", ICON_CONSTRAINT_DATA, "Transform Cache",
+ "Look up the transformation matrix from an external file"},
{0, "", 0, N_("Tracking"), ""},
{CONSTRAINT_TYPE_CLAMPTO, "CLAMP_TO", ICON_CONSTRAINT_DATA, "Clamp To",
"Restrict movements to lie along a curve by remapping location along curve's longest axis"},
@@ -146,12 +148,17 @@ static EnumPropertyItem space_object_items[] = {
{0, NULL, 0, NULL, NULL}
};
+#include "DNA_cachefile_types.h"
+
#include "BKE_animsys.h"
#include "BKE_action.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
+#ifdef WITH_ALEMBIC
+# include "ABC_alembic.h"
+#endif
static StructRNA *rna_ConstraintType_refine(struct PointerRNA *ptr)
{
@@ -214,6 +221,8 @@ static StructRNA *rna_ConstraintType_refine(struct PointerRNA *ptr)
return &RNA_CameraSolverConstraint;
case CONSTRAINT_TYPE_OBJECTSOLVER:
return &RNA_ObjectSolverConstraint;
+ case CONSTRAINT_TYPE_TRANSFORM_CACHE:
+ return &RNA_TransformCacheConstraint;
default:
return &RNA_UnknownType;
}
@@ -467,6 +476,22 @@ static void rna_Constraint_objectSolver_camera_set(PointerRNA *ptr, PointerRNA v
}
}
+static void rna_Constraint_transformCache_object_path_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+#ifdef WITH_ALEMBIC
+ bConstraint *con = (bConstraint *)ptr->data;
+ bTransformCacheConstraint *data = (bTransformCacheConstraint *)con->data;
+ Object *ob = (Object *)ptr->id.data;
+
+ data->reader = CacheReader_open_alembic_object(data->cache_file->handle,
+ data->reader,
+ ob,
+ data->object_path);
+#endif
+
+ rna_Constraint_update(bmain, scene, ptr);
+}
+
#else
static EnumPropertyItem constraint_distance_items[] = {
@@ -483,6 +508,21 @@ static EnumPropertyItem constraint_distance_items[] = {
};
+static void rna_def_constraint_headtail_common(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, "bConstraint", "headtail");
+ RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ prop = RNA_def_property(srna, "use_bbone_shape", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, "bConstraint", "flag", CONSTRAINT_BBONE_SHAPE);
+ RNA_def_property_ui_text(prop, "Follow B-Bone", "Follow shape of B-Bone segments when calculating Head/Tail position");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+}
+
static void rna_def_constrainttarget(BlenderRNA *brna)
{
StructRNA *srna;
@@ -787,10 +827,7 @@ static void rna_def_constraint_track_to(BlenderRNA *brna)
srna = RNA_def_struct(brna, "TrackToConstraint", "Constraint");
RNA_def_struct_ui_text(srna, "Track To Constraint", "Aim the constrained object toward the target");
- prop = RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, "bConstraint", "headtail");
- RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+ rna_def_constraint_headtail_common(srna);
RNA_def_struct_sdna_from(srna, "bTrackToConstraint", "data");
@@ -831,10 +868,7 @@ static void rna_def_constraint_locate_like(BlenderRNA *brna)
srna = RNA_def_struct(brna, "CopyLocationConstraint", "Constraint");
RNA_def_struct_ui_text(srna, "Copy Location Constraint", "Copy the location of the target");
- prop = RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, "bConstraint", "headtail");
- RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+ rna_def_constraint_headtail_common(srna);
RNA_def_struct_sdna_from(srna, "bLocateLikeConstraint", "data");
@@ -1022,10 +1056,7 @@ static void rna_def_constraint_transform_like(BlenderRNA *brna)
srna = RNA_def_struct(brna, "CopyTransformsConstraint", "Constraint");
RNA_def_struct_ui_text(srna, "Copy Transforms Constraint", "Copy all the transforms of the target");
- prop = RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, "bConstraint", "headtail");
- RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+ rna_def_constraint_headtail_common(srna);
RNA_def_struct_sdna_from(srna, "bTransLikeConstraint", "data");
@@ -1200,10 +1231,7 @@ static void rna_def_constraint_locked_track(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Locked Track Constraint",
"Point toward the target along the track axis, while locking the other axis");
- prop = RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, "bConstraint", "headtail");
- RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+ rna_def_constraint_headtail_common(srna);
RNA_def_struct_sdna_from(srna, "bLockTrackConstraint", "data");
@@ -1327,10 +1355,7 @@ static void rna_def_constraint_stretch_to(BlenderRNA *brna)
srna = RNA_def_struct(brna, "StretchToConstraint", "Constraint");
RNA_def_struct_ui_text(srna, "Stretch To Constraint", "Stretch to meet the target object");
- prop = RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, "bConstraint", "headtail");
- RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+ rna_def_constraint_headtail_common(srna);
RNA_def_struct_sdna_from(srna, "bStretchToConstraint", "data");
@@ -2122,10 +2147,7 @@ static void rna_def_constraint_distance_limit(BlenderRNA *brna)
srna = RNA_def_struct(brna, "LimitDistanceConstraint", "Constraint");
RNA_def_struct_ui_text(srna, "Limit Distance Constraint", "Limit the distance from target object");
- prop = RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, "bConstraint", "headtail");
- RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+ rna_def_constraint_headtail_common(srna);
RNA_def_struct_sdna_from(srna, "bDistLimitConstraint", "data");
@@ -2236,10 +2258,7 @@ static void rna_def_constraint_damped_track(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Damped Track Constraint",
"Point toward target by taking the shortest rotation path");
- prop = RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, "bConstraint", "headtail");
- RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+rna_def_constraint_headtail_common(srna);
RNA_def_struct_sdna_from(srna, "bDampTrackConstraint", "data");
@@ -2396,10 +2415,7 @@ static void rna_def_constraint_pivot(BlenderRNA *brna)
srna = RNA_def_struct(brna, "PivotConstraint", "Constraint");
RNA_def_struct_ui_text(srna, "Pivot Constraint", "Rotate around a different point");
- prop = RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, "bConstraint", "headtail");
- RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+ rna_def_constraint_headtail_common(srna);
RNA_def_struct_sdna_from(srna, "bPivotConstraint", "data");
@@ -2580,6 +2596,27 @@ static void rna_def_constraint_object_solver(BlenderRNA *brna)
"rna_Constraint_cameraObject_poll");
}
+static void rna_def_constraint_transform_cache(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "TransformCacheConstraint", "Constraint");
+ RNA_def_struct_ui_text(srna, "Transform Cache Constraint", "Look up transformation from an external file");
+ RNA_def_struct_sdna_from(srna, "bTransformCacheConstraint", "data");
+
+ prop = RNA_def_property(srna, "cache_file", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "cache_file");
+ RNA_def_property_struct_type(prop, "CacheFile");
+ RNA_def_property_ui_text(prop, "Cache File", "");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_update(prop, 0, "rna_Constraint_dependency_update");
+
+ prop = RNA_def_property(srna, "object_path", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Object Path", "Path to the object in the Alembic archive used to lookup the transform matrix");
+ RNA_def_property_update(prop, 0, "rna_Constraint_transformCache_object_path_update");
+}
+
/* base struct for constraints */
void RNA_def_constraint(BlenderRNA *brna)
{
@@ -2696,6 +2733,7 @@ void RNA_def_constraint(BlenderRNA *brna)
rna_def_constraint_follow_track(brna);
rna_def_constraint_camera_solver(brna);
rna_def_constraint_object_solver(brna);
+ rna_def_constraint_transform_cache(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index d28dd8f7607..22e45964742 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -221,7 +221,7 @@ static void rna_Curve_texspace_set(Main *UNUSED(bmain), Scene *UNUSED(scene), Po
BKE_curve_texspace_calc(cu);
}
-static int rna_Curve_texspace_editable(PointerRNA *ptr)
+static int rna_Curve_texspace_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
Curve *cu = (Curve *)ptr->data;
return (cu->texflag & CU_AUTOSPACE) ? 0 : PROP_EDITABLE;
@@ -952,23 +952,37 @@ static void rna_def_nurbs(BlenderRNA *UNUSED(brna), StructRNA *srna)
static void rna_def_font(BlenderRNA *UNUSED(brna), StructRNA *srna)
{
PropertyRNA *prop;
-
+
static EnumPropertyItem prop_align_items[] = {
- {CU_LEFT, "LEFT", 0, "Left", "Align text to the left"},
- {CU_MIDDLE, "CENTER", 0, "Center", "Center text"},
- {CU_RIGHT, "RIGHT", 0, "Right", "Align text to the right"},
- {CU_JUSTIFY, "JUSTIFY", 0, "Justify", "Align to the left and the right"},
- {CU_FLUSH, "FLUSH", 0, "Flush", "Align to the left and the right, with equal character spacing"},
+ {CU_ALIGN_X_LEFT, "LEFT", 0, "Left", "Align text to the left"},
+ {CU_ALIGN_X_MIDDLE, "CENTER", 0, "Center", "Center text"},
+ {CU_ALIGN_X_RIGHT, "RIGHT", 0, "Right", "Align text to the right"},
+ {CU_ALIGN_X_JUSTIFY, "JUSTIFY", 0, "Justify", "Align to the left and the right"},
+ {CU_ALIGN_X_FLUSH, "FLUSH", 0, "Flush", "Align to the left and the right, with equal character spacing"},
{0, NULL, 0, NULL, NULL}
};
-
+
+ static EnumPropertyItem prop_align_y_items[] = {
+ {CU_ALIGN_Y_TOP_BASELINE, "TOP_BASELINE", 0, "Top Base-Line", "Align to top but use the base-line of the text"},
+ {CU_ALIGN_Y_TOP, "TOP", 0, "Top", "Align text to the top"},
+ {CU_ALIGN_Y_CENTER, "CENTER", 0, "Center", "Align text to the middle"},
+ {CU_ALIGN_Y_BOTTOM, "BOTTOM", 0, "Bottom", "Align text to the bottom"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
/* Enums */
- prop = RNA_def_property(srna, "align", PROP_ENUM, PROP_NONE);
+ prop = RNA_def_property(srna, "align_x", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "spacemode");
RNA_def_property_enum_items(prop, prop_align_items);
- RNA_def_property_ui_text(prop, "Text Align", "Text align from the object center");
+ RNA_def_property_ui_text(prop, "Text Horizontal Align", "Text horizontal align from the object center");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
-
+
+ prop = RNA_def_property(srna, "align_y", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "align_y");
+ RNA_def_property_enum_items(prop, prop_align_y_items);
+ RNA_def_property_ui_text(prop, "Text Vertical Align", "Text vertical align from the object center");
+ RNA_def_property_update(prop, 0, "rna_Curve_update_data");
+
/* number values */
prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "fsize");
@@ -1009,13 +1023,15 @@ static void rna_def_font(BlenderRNA *UNUSED(brna), StructRNA *srna)
prop = RNA_def_property(srna, "offset_x", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "xof");
- RNA_def_property_range(prop, -50.0f, 50.0f);
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, -50.0f, 50.0f, 10, 3);
RNA_def_property_ui_text(prop, "X Offset", "Horizontal offset from the object origin");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
prop = RNA_def_property(srna, "offset_y", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "yof");
- RNA_def_property_range(prop, -50.0f, 50.0f);
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, -50.0f, 50.0f, 10, 3);
RNA_def_property_ui_text(prop, "Y Offset", "Vertical offset from the object origin");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
@@ -1117,25 +1133,29 @@ static void rna_def_textbox(BlenderRNA *brna)
/* number values */
prop = RNA_def_property(srna, "x", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "x");
- RNA_def_property_range(prop, -50.0f, 50.0f);
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, -50.0f, 50.0f, 10, 3);
RNA_def_property_ui_text(prop, "Textbox X Offset", "");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
prop = RNA_def_property(srna, "y", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "y");
- RNA_def_property_range(prop, -50.0f, 50.0f);
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, -50.0f, 50.0f, 10, 3);
RNA_def_property_ui_text(prop, "Textbox Y Offset", "");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
prop = RNA_def_property(srna, "width", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "w");
- RNA_def_property_range(prop, 0.0f, 50.0f);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 50.0f, 10, 3);
RNA_def_property_ui_text(prop, "Textbox Width", "");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
prop = RNA_def_property(srna, "height", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "h");
- RNA_def_property_range(prop, 0.0f, 50.0f);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 50.0f, 10, 3);
RNA_def_property_ui_text(prop, "Textbox Height", "");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
@@ -1253,7 +1273,7 @@ static void rna_def_curve_spline_bezpoints(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_srna(cprop, "SplineBezierPoints");
srna = RNA_def_struct(brna, "SplineBezierPoints", NULL);
RNA_def_struct_sdna(srna, "Nurb");
- RNA_def_struct_ui_text(srna, "Spline Bezier Points", "Collection of spline bezirt points");
+ RNA_def_struct_ui_text(srna, "Spline Bezier Points", "Collection of spline Bezier points");
func = RNA_def_function(srna, "add", "rna_Curve_spline_bezpoints_add");
RNA_def_function_ui_description(func, "Add a number of points to this spline");
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index 36e2b9b0572..7ff4eaea169 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -531,12 +531,18 @@ BlenderRNA *RNA_create(void)
BlenderRNA *brna;
brna = MEM_callocN(sizeof(BlenderRNA), "BlenderRNA");
+ const char *error_message = NULL;
- DefRNA.sdna = DNA_sdna_from_data(DNAstr, DNAlen, false);
BLI_listbase_clear(&DefRNA.structs);
DefRNA.error = 0;
DefRNA.preprocess = 1;
+ DefRNA.sdna = DNA_sdna_from_data(DNAstr, DNAlen, false, false, &error_message);
+ if (DefRNA.sdna == NULL) {
+ fprintf(stderr, "Error decoding SDNA: %s\n", error_message);
+ DefRNA.error = 1;
+ }
+
return brna;
}
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index 1487dfa074e..1d3b65bb7ba 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -72,6 +72,7 @@ EnumPropertyItem rna_enum_fmodifier_type_items[] = {
EnumPropertyItem rna_enum_beztriple_keyframe_type_items[] = {
{BEZT_KEYTYPE_KEYFRAME, "KEYFRAME", VICO_KEYTYPE_KEYFRAME_VEC, "Keyframe", "Normal keyframe - e.g. for key poses"},
{BEZT_KEYTYPE_BREAKDOWN, "BREAKDOWN", VICO_KEYTYPE_BREAKDOWN_VEC, "Breakdown", "A breakdown pose - e.g. for transitions between key poses"},
+ {BEZT_KEYTYPE_MOVEHOLD, "MOVING_HOLD", VICO_KEYTYPE_MOVING_HOLD_VEC, "Moving Hold", "A keyframe that is part of a moving hold"},
{BEZT_KEYTYPE_EXTREME, "EXTREME", VICO_KEYTYPE_EXTREME_VEC, "Extreme", "An 'extreme' pose, or some other purpose as needed"},
{BEZT_KEYTYPE_JITTER, "JITTER", VICO_KEYTYPE_JITTER_VEC, "Jitter", "A filler or baked keyframe for keying on ones, or some other purpose as needed"},
{0, NULL, 0, NULL, NULL}
@@ -198,13 +199,13 @@ static StructRNA *rna_DriverTarget_id_typef(PointerRNA *ptr)
return ID_code_to_RNA_type(dtar->idtype);
}
-static int rna_DriverTarget_id_editable(PointerRNA *ptr)
+static int rna_DriverTarget_id_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
DriverTarget *dtar = (DriverTarget *)ptr->data;
return (dtar->idtype) ? PROP_EDITABLE : 0;
}
-static int rna_DriverTarget_id_type_editable(PointerRNA *ptr)
+static int rna_DriverTarget_id_type_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
DriverTarget *dtar = (DriverTarget *)ptr->data;
@@ -1599,7 +1600,13 @@ static void rna_def_channeldriver(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", DRIVER_FLAG_SHOWDEBUG);
RNA_def_property_ui_text(prop, "Show Debug Info",
"Show intermediate values for the driver calculations to allow debugging of drivers");
-
+
+ prop = RNA_def_property(srna, "use_self", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", DRIVER_FLAG_USE_SELF);
+ RNA_def_property_ui_text(prop, "Use Self",
+ "Include a 'self' variable in the name-space, "
+ "so drivers can easily reference the data being modified (object, bone, etc...)");
+
/* State Info (for Debugging) */
prop = RNA_def_property(srna, "is_valid", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", DRIVER_FLAG_INVALID);
@@ -1844,6 +1851,8 @@ static void rna_def_fcurve(BlenderRNA *brna)
"Cycle through the rainbow, trying to give each curve a unique color"},
{FCURVE_COLOR_AUTO_RGB, "AUTO_RGB", 0, "Auto XYZ to RGB",
"Use axis colors for transform and color properties, and auto-rainbow for the rest"},
+ {FCURVE_COLOR_AUTO_YRGB, "AUTO_YRGB", 0, "Auto WXYZ to YRGB",
+ "Use axis colors for XYZ parts of transform, and yellow for the 'W' channel"},
{FCURVE_COLOR_CUSTOM, "CUSTOM", 0, "User Defined",
"Use custom hand-picked color for F-Curve"},
{0, NULL, 0, NULL, NULL}
diff --git a/source/blender/makesrna/intern/rna_fluidsim.c b/source/blender/makesrna/intern/rna_fluidsim.c
index 16e0f17eac5..091950a8e66 100644
--- a/source/blender/makesrna/intern/rna_fluidsim.c
+++ b/source/blender/makesrna/intern/rna_fluidsim.c
@@ -204,18 +204,6 @@ static char *rna_FluidSettings_path(PointerRNA *ptr)
return BLI_sprintfN("modifiers[\"%s\"].settings", name_esc);
}
-static void rna_FluidMeshVertex_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
-{
- FluidsimSettings *fss = (FluidsimSettings *)ptr->data;
- rna_iterator_array_begin(iter, fss->meshVelocities, sizeof(float) * 3, fss->totvert, 0, NULL);
-}
-
-static int rna_FluidMeshVertex_data_length(PointerRNA *ptr)
-{
- FluidsimSettings *fss = (FluidsimSettings *)ptr->data;
- return fss->totvert;
-}
-
#else
static void rna_def_fluidsim_slip(StructRNA *srna)
@@ -251,9 +239,8 @@ static void rna_def_fluid_mesh_vertices(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- srna = RNA_def_struct(brna, "FluidMeshVertex", NULL);
- RNA_def_struct_sdna(srna, "FluidVertexVelocity");
- RNA_def_struct_ui_text(srna, "Fluid Mesh Vertex", "Vertex of a simulated fluid mesh");
+ srna = RNA_def_struct(brna, "FluidVertexVelocity", NULL);
+ RNA_def_struct_ui_text(srna, "Fluid Mesh Velocity", "Velocity of a simulated fluid mesh");
RNA_def_struct_ui_icon(srna, ICON_VERTEXSEL);
prop = RNA_def_property(srna, "velocity", PROP_FLOAT, PROP_VELOCITY);
@@ -442,11 +429,10 @@ static void rna_def_fluidsim_domain(BlenderRNA *brna)
/* simulated fluid mesh data */
prop = RNA_def_property(srna, "fluid_mesh_vertices", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_struct_type(prop, "FluidMeshVertex");
+ RNA_def_property_collection_sdna(prop, NULL, "meshVelocities", "totvert");
+ RNA_def_property_struct_type(prop, "FluidVertexVelocity");
RNA_def_property_ui_text(prop, "Fluid Mesh Vertices", "Vertices of the fluid mesh generated by simulation");
- RNA_def_property_collection_funcs(prop, "rna_FluidMeshVertex_data_begin", "rna_iterator_array_next",
- "rna_iterator_array_end", "rna_iterator_array_get",
- "rna_FluidMeshVertex_data_length", NULL, NULL, NULL);
+
rna_def_fluid_mesh_vertices(brna);
}
diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c
index 2c4e47a19fc..7ba89538b18 100644
--- a/source/blender/makesrna/intern/rna_gpencil.c
+++ b/source/blender/makesrna/intern/rna_gpencil.c
@@ -15,7 +15,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * Contributor(s): Blender Foundation (2009), Joshua Leung
+ * Contributor(s): Blender Foundation (2009), Joshua Leung, Antonio Vazquez
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -41,6 +41,17 @@
#include "rna_internal.h"
#include "WM_types.h"
+#include "DNA_object_types.h"
+#include "ED_gpencil.h"
+
+/* parent type */
+static EnumPropertyItem parent_type_items[] = {
+ {PAROBJECT, "OBJECT", 0, "Object", "The layer is parented to an object"},
+ {PARSKEL, "ARMATURE", 0, "Armature", ""},
+ {PARBONE, "BONE", 0, "Bone", "The layer is parented to a bone"},
+ {0, NULL, 0, NULL, NULL}
+};
+
#ifdef RNA_RUNTIME
@@ -49,8 +60,7 @@
#include "WM_api.h"
#include "BKE_gpencil.h"
-
-#include "DNA_object_types.h"
+#include "BKE_action.h"
static void rna_GPencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
@@ -90,6 +100,16 @@ static void rna_GPencil_onion_skinning_update(Main *bmain, Scene *scene, Pointer
rna_GPencil_update(bmain, scene, ptr);
}
+static void rna_GPencil_stroke_colorname_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ bGPDstroke *gps = (bGPDstroke *)ptr->data;
+ gps->flag |= GP_STROKE_RECALC_COLOR;
+ gps->palcolor = NULL;
+
+ /* Now do standard updates... */
+ rna_GPencil_update(bmain, scene, ptr);
+}
+
static char *rna_GPencilLayer_path(PointerRNA *ptr)
{
bGPDlayer *gpl = (bGPDlayer *)ptr->data;
@@ -100,7 +120,7 @@ static char *rna_GPencilLayer_path(PointerRNA *ptr)
return BLI_sprintfN("layers[\"%s\"]", name_esc);
}
-static int rna_GPencilLayer_active_frame_editable(PointerRNA *ptr)
+static int rna_GPencilLayer_active_frame_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
bGPDlayer *gpl = (bGPDlayer *)ptr->data;
@@ -123,38 +143,140 @@ static void rna_GPencilLayer_line_width_range(PointerRNA *ptr, int *min, int *ma
* it's relatively hard to test for that. So, for now, only volumetric strokes
* get to be larger...
*/
+
+ /* From GP v2 this value is used to increase or decrease the thickness of the stroke */
if (gpl->flag & GP_LAYER_VOLUMETRIC) {
- *min = 1;
+ *min = -300;
*max = 300;
- *softmin = 1;
+ *softmin = -100;
*softmax = 100;
}
else {
- *min = 1;
+ *min = -10;
*max = 10;
- *softmin = 1;
+ *softmin = -10;
*softmax = 10;
}
}
-static int rna_GPencilLayer_is_stroke_visible_get(PointerRNA *ptr)
+/* set parent */
+static void set_parent(bGPDlayer *gpl, Object *par, const int type, const char *substr)
+{
+ if (type == PAROBJECT) {
+ invert_m4_m4(gpl->inverse, par->obmat);
+ gpl->parent = par;
+ gpl->partype |= PAROBJECT;
+ gpl->parsubstr[0] = 0;
+ }
+ else if (type == PARSKEL) {
+ invert_m4_m4(gpl->inverse, par->obmat);
+ gpl->parent = par;
+ gpl->partype |= PARSKEL;
+ gpl->parsubstr[0] = 0;
+ }
+ else if (type == PARBONE) {
+ bPoseChannel *pchan = BKE_pose_channel_find_name(par->pose, substr);
+ if (pchan) {
+ float tmp_mat[4][4];
+ mul_m4_m4m4(tmp_mat, par->obmat, pchan->pose_mat);
+
+ invert_m4_m4(gpl->inverse, tmp_mat);
+ gpl->parent = par;
+ gpl->partype |= PARBONE;
+ BLI_strncpy(gpl->parsubstr, substr, sizeof(gpl->parsubstr));
+ }
+ }
+}
+
+/* set parent object and inverse matrix */
+static void rna_GPencilLayer_parent_set(PointerRNA *ptr, PointerRNA value)
+{
+ bGPDlayer *gpl = (bGPDlayer *)ptr->data;
+ Object *par = (Object *)value.data;
+
+ if (par != NULL) {
+ set_parent(gpl, par, gpl->partype, gpl->parsubstr);
+ }
+ else {
+ /* keep strokes in the same place, so apply current transformation */
+ if (gpl->parent != NULL) {
+ bGPDspoint *pt;
+ int i;
+ float diff_mat[4][4];
+ /* calculate difference matrix */
+ ED_gpencil_parent_location(gpl, diff_mat);
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ mul_m4_v3(diff_mat, &pt->x);
+ }
+ }
+ }
+ }
+ /* clear parent */
+ gpl->parent = NULL;
+ }
+}
+
+/* set parent type */
+static void rna_GPencilLayer_parent_type_set(PointerRNA *ptr, int value)
{
- /* see drawgpencil.c -> gp_draw_data_layers() for more details
- * about this limit for showing/not showing
- */
bGPDlayer *gpl = (bGPDlayer *)ptr->data;
- return (gpl->color[3] > GPENCIL_ALPHA_OPACITY_THRESH);
+ Object *par = gpl->parent;
+ gpl->partype = value;
+
+ if (par != NULL) {
+ set_parent(gpl, par, value, gpl->parsubstr);
+ }
}
-static int rna_GPencilLayer_is_fill_visible_get(PointerRNA *ptr)
+/* set parent bone */
+static void rna_GPencilLayer_parent_bone_set(PointerRNA *ptr, const char *value)
+{
+ bGPDlayer *gpl = (bGPDlayer *)ptr->data;
+
+ Object *par = gpl->parent;
+ gpl->partype = PARBONE;
+
+ if (par != NULL) {
+ set_parent(gpl, par, gpl->partype, value);
+ }
+}
+
+
+/* parent types enum */
+static EnumPropertyItem *rna_Object_parent_type_itemf(
+ bContext *UNUSED(C), PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ bGPDlayer *gpl = (bGPDlayer *)ptr->data;
+ EnumPropertyItem *item = NULL;
+ int totitem = 0;
+
+ RNA_enum_items_add_value(&item, &totitem, parent_type_items, PAROBJECT);
+
+ if (gpl->parent) {
+ Object *par = gpl->parent;
+
+ if (par->type == OB_ARMATURE) {
+ /* special hack: prevents this being overrided */
+ RNA_enum_items_add_value(&item, &totitem, &parent_type_items[1], PARSKEL);
+ RNA_enum_items_add_value(&item, &totitem, parent_type_items, PARBONE);
+ }
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+static int rna_GPencilLayer_is_parented_get(PointerRNA *ptr)
{
- /* see drawgpencil.c -> gp_draw_data_layers() for more details
- * about this limit for showing/not showing
- */
bGPDlayer *gpl = (bGPDlayer *)ptr->data;
- return (gpl->fill[3] > GPENCIL_ALPHA_OPACITY_THRESH);
+ return (gpl->parent != NULL);
}
static PointerRNA rna_GPencil_active_layer_get(PointerRNA *ptr)
@@ -201,7 +323,7 @@ static void rna_GPencil_active_layer_set(PointerRNA *ptr, PointerRNA value)
static int rna_GPencil_active_layer_index_get(PointerRNA *ptr)
{
bGPdata *gpd = (bGPdata *)ptr->id.data;
- bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
return BLI_findindex(&gpd->layers, gpl);
}
@@ -211,7 +333,7 @@ static void rna_GPencil_active_layer_index_set(PointerRNA *ptr, int value)
bGPdata *gpd = (bGPdata *)ptr->id.data;
bGPDlayer *gpl = BLI_findlink(&gpd->layers, value);
- gpencil_layer_setactive(gpd, gpl);
+ BKE_gpencil_layer_setactive(gpd, gpl);
}
static void rna_GPencil_active_layer_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax)
@@ -244,7 +366,7 @@ static void rna_GPencil_use_onion_skinning_set(PointerRNA *ptr, const int value)
/* set new value */
if (value) {
/* enable on active layer (it's the one that's most likely to be of interest right now) */
- gpl = gpencil_layer_getactive(gpd);
+ gpl = BKE_gpencil_layer_getactive(gpd);
if (gpl) {
gpl->flag |= GP_LAYER_ONIONSKIN;
}
@@ -313,16 +435,27 @@ static void rna_GPencil_stroke_point_select_set(PointerRNA *ptr, const int value
pt->flag &= ~GP_SPOINT_SELECT;
/* Check if the stroke should be selected or not... */
- gpencil_stroke_sync_selection(gps);
+ BKE_gpencil_stroke_sync_selection(gps);
}
}
-static void rna_GPencil_stroke_point_add(bGPDstroke *stroke, int count)
+static void rna_GPencil_stroke_point_add(bGPDstroke *stroke, int count, float pressure, float strength)
{
if (count > 0) {
+ /* create space at the end of the array for extra points */
stroke->points = MEM_recallocN_id(stroke->points,
sizeof(bGPDspoint) * (stroke->totpoints + count),
"gp_stroke_points");
+
+ /* init the pressure and strength values so that old scripts won't need to
+ * be modified to give these initial values...
+ */
+ for (int i = 0; i < count; i++) {
+ bGPDspoint *pt = stroke->points + (stroke->totpoints + i);
+ pt->pressure = pressure;
+ pt->strength = strength;
+ }
+
stroke->totpoints += count;
}
}
@@ -357,10 +490,14 @@ static void rna_GPencil_stroke_point_pop(bGPDstroke *stroke, ReportList *reports
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
}
-static bGPDstroke *rna_GPencil_stroke_new(bGPDframe *frame)
+static bGPDstroke *rna_GPencil_stroke_new(bGPDframe *frame, const char *colorname)
{
bGPDstroke *stroke = MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
-
+ if (colorname) {
+ BLI_strncpy(stroke->colorname, colorname, sizeof(stroke->colorname));
+ }
+ stroke->palcolor = NULL;
+ stroke->flag |= GP_STROKE_RECALC_COLOR;
BLI_addtail(&frame->strokes, stroke);
return stroke;
@@ -410,7 +547,7 @@ static bGPDframe *rna_GPencil_frame_new(bGPDlayer *layer, ReportList *reports, i
return NULL;
}
- frame = gpencil_frame_addnew(layer, frame_number);
+ frame = BKE_gpencil_frame_addnew(layer, frame_number);
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
@@ -425,7 +562,7 @@ static void rna_GPencil_frame_remove(bGPDlayer *layer, ReportList *reports, Poin
return;
}
- gpencil_layer_delframe(layer, frame);
+ BKE_gpencil_layer_delframe(layer, frame);
RNA_POINTER_INVALIDATE(frame_ptr);
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
@@ -433,7 +570,7 @@ static void rna_GPencil_frame_remove(bGPDlayer *layer, ReportList *reports, Poin
static bGPDframe *rna_GPencil_frame_copy(bGPDlayer *layer, bGPDframe *src)
{
- bGPDframe *frame = gpencil_frame_duplicate(src);
+ bGPDframe *frame = BKE_gpencil_frame_duplicate(src);
while (BKE_gpencil_layer_find_frame(layer, frame->framenum)) {
frame->framenum++;
@@ -448,7 +585,7 @@ static bGPDframe *rna_GPencil_frame_copy(bGPDlayer *layer, bGPDframe *src)
static bGPDlayer *rna_GPencil_layer_new(bGPdata *gpd, const char *name, int setactive)
{
- bGPDlayer *gl = gpencil_layer_addnew(gpd, name, setactive != 0);
+ bGPDlayer *gl = BKE_gpencil_layer_addnew(gpd, name, setactive != 0);
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -463,7 +600,7 @@ static void rna_GPencil_layer_remove(bGPdata *gpd, ReportList *reports, PointerR
return;
}
- gpencil_layer_delete(gpd, layer);
+ BKE_gpencil_layer_delete(gpd, layer);
RNA_POINTER_INVALIDATE(layer_ptr);
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -471,23 +608,266 @@ static void rna_GPencil_layer_remove(bGPdata *gpd, ReportList *reports, PointerR
static void rna_GPencil_frame_clear(bGPDframe *frame)
{
- free_gpencil_strokes(frame);
+ BKE_gpencil_free_strokes(frame);
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
static void rna_GPencil_layer_clear(bGPDlayer *layer)
{
- free_gpencil_frames(layer);
+ BKE_gpencil_free_frames(layer);
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
static void rna_GPencil_clear(bGPdata *gpd)
{
- free_gpencil_layers(&gpd->layers);
+ BKE_gpencil_free_layers(&gpd->layers);
+
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+}
+
+/* Palettes */
+static bGPDpalette *rna_GPencil_palette_new(bGPdata *gpd, const char *name, int setactive)
+{
+ bGPDpalette *palette = BKE_gpencil_palette_addnew(gpd, name, setactive != 0);
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return palette;
+}
+
+static void rna_GPencil_palette_remove(bGPdata *gpd, ReportList *reports, PointerRNA *palette_ptr)
+{
+ bGPDpalette *palette = palette_ptr->data;
+ if (BLI_findindex(&gpd->palettes, palette) == -1) {
+ BKE_report(reports, RPT_ERROR, "Palette not found in grease pencil data");
+ return;
+ }
+
+ BKE_gpencil_palette_delete(gpd, palette);
+ RNA_POINTER_INVALIDATE(palette_ptr);
+
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+}
+
+static PointerRNA rna_GPencil_active_palette_get(PointerRNA *ptr)
+{
+ bGPdata *gpd = ptr->id.data;
+
+ if (GS(gpd->id.name) == ID_GD) { /* why would this ever be not GD */
+ bGPDpalette *palette;
+
+ for (palette = gpd->palettes.first; palette; palette = palette->next) {
+ if (palette->flag & PL_PALETTE_ACTIVE) {
+ break;
+ }
+ }
+
+ if (palette) {
+ return rna_pointer_inherit_refine(ptr, &RNA_GPencilPalette, palette);
+ }
+ }
+
+ return rna_pointer_inherit_refine(ptr, NULL, NULL);
+}
+
+static void rna_GPencil_active_palette_set(PointerRNA *ptr, PointerRNA value)
+{
+ bGPdata *gpd = ptr->id.data;
+
+ if (GS(gpd->id.name) == ID_GD) { /* why would this ever be not GD */
+ bGPDpalette *palette;
+
+ for (palette = gpd->palettes.first; palette; palette = palette->next) {
+ if (palette == value.data) {
+ palette->flag |= PL_PALETTE_ACTIVE;
+ }
+ else {
+ palette->flag &= ~PL_PALETTE_ACTIVE;
+ }
+ }
+ /* force color recalc */
+ BKE_gpencil_palette_change_strokes(gpd);
+
+ WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
+ }
+}
+
+static int rna_GPencilPalette_index_get(PointerRNA *ptr)
+{
+ bGPdata *gpd = (bGPdata *)ptr->id.data;
+ bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
+
+ return BLI_findindex(&gpd->palettes, palette);
+}
+
+static void rna_GPencilPalette_index_set(PointerRNA *ptr, int value)
+{
+ bGPdata *gpd = (bGPdata *)ptr->id.data;
+ bGPDpalette *palette = BLI_findlink(&gpd->palettes, value);
+
+ BKE_gpencil_palette_setactive(gpd, palette);
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+}
+
+static void rna_GPencilPalette_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax)
+{
+ bGPdata *gpd = (bGPdata *)ptr->id.data;
+
+ *min = 0;
+ *max = max_ii(0, BLI_listbase_count(&gpd->palettes) - 1);
+
+ *softmin = *min;
+ *softmax = *max;
+}
+
+/* Palette colors */
+static bGPDpalettecolor *rna_GPencilPalette_color_new(bGPDpalette *palette)
+{
+ bGPDpalettecolor *color = BKE_gpencil_palettecolor_addnew(palette, DATA_("Color"), true);
+
+ return color;
+}
+
+static void rna_GPencilPalette_color_remove(bGPDpalette *palette, ReportList *reports, PointerRNA *color_ptr)
+{
+ bGPDpalettecolor *color = color_ptr->data;
+
+ if (BLI_findindex(&palette->colors, color) == -1) {
+ BKE_reportf(reports, RPT_ERROR, "Palette '%s' does not contain color given", palette->info + 2);
+ return;
+ }
+
+ BKE_gpencil_palettecolor_delete(palette, color);
+ RNA_POINTER_INVALIDATE(color_ptr);
+
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+}
+
+static PointerRNA rna_GPencilPalette_active_color_get(PointerRNA *ptr)
+{
+ bGPDpalette *palette = (bGPDpalette *)ptr->data;
+ bGPDpalettecolor *color;
+
+ for (color = palette->colors.first; color; color = color->next) {
+ if (color->flag & PC_COLOR_ACTIVE) {
+ break;
+ }
+ }
+
+ if (color) {
+ return rna_pointer_inherit_refine(ptr, &RNA_GPencilPaletteColor, color);
+ }
+
+ return rna_pointer_inherit_refine(ptr, NULL, NULL);
+}
+
+static void rna_GPencilPalette_active_color_set(PointerRNA *ptr, PointerRNA value)
+{
+ bGPDpalette *palette = (bGPDpalette *)ptr->data;
+ bGPDpalettecolor *color = value.data;
+
+ BKE_gpencil_palettecolor_setactive(palette, color);
+}
+
+static void rna_GPencilPalette_info_set(PointerRNA *ptr, const char *value)
+{
+ bGPdata *gpd = ptr->id.data;
+ bGPDpalette *palette = ptr->data;
+
+ /* copy the new name into the name slot */
+ BLI_strncpy_utf8(palette->info, value, sizeof(palette->info));
+
+ BLI_uniquename(&gpd->palettes, palette, DATA_("GP_Palette"), '.', offsetof(bGPDpalette, info),
+ sizeof(palette->info));
+}
+
+static char *rna_GPencilPalette_path(PointerRNA *ptr)
+{
+ bGPDpalette *palette = ptr->data;
+ char name_esc[sizeof(palette->info) * 2];
+
+ BLI_strescape(name_esc, palette->info, sizeof(name_esc));
+
+ return BLI_sprintfN("palettes[\"%s\"]", name_esc);
+}
+
+static char *rna_GPencilPalette_color_path(PointerRNA *ptr)
+{
+ bGPdata *gpd = ptr->id.data;
+ bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
+ bGPDpalettecolor *palcolor = ptr->data;
+
+ char name_palette[sizeof(palette->info) * 2];
+ char name_color[sizeof(palcolor->info) * 2];
+
+ BLI_strescape(name_palette, palette->info, sizeof(name_palette));
+ BLI_strescape(name_color, palcolor->info, sizeof(name_color));
+
+ return BLI_sprintfN("palettes[\"%s\"].colors[\"%s\"]", name_palette, name_color);
+}
+
+static void rna_GPencilPaletteColor_info_set(PointerRNA *ptr, const char *value)
+{
+ bGPdata *gpd = ptr->id.data;
+ bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
+ bGPDpalettecolor *palcolor = ptr->data;
+
+ /* rename all strokes */
+ BKE_gpencil_palettecolor_changename(gpd, palcolor->info, value);
+
+ /* copy the new name into the name slot */
+ BLI_strncpy_utf8(palcolor->info, value, sizeof(palcolor->info));
+ BLI_uniquename(&palette->colors, palcolor, DATA_("Color"), '.', offsetof(bGPDpalettecolor, info),
+ sizeof(palcolor->info));
+}
+
+static void rna_GPencilStrokeColor_info_set(PointerRNA *ptr, const char *value)
+{
+ bGPDstroke *gps = ptr->data;
+
+ /* copy the new name into the name slot */
+ BLI_strncpy_utf8(gps->colorname, value, sizeof(gps->colorname));
+}
+
+
+static int rna_GPencilPaletteColor_is_stroke_visible_get(PointerRNA *ptr)
+{
+ bGPDpalettecolor *pcolor = (bGPDpalettecolor *)ptr->data;
+ return (pcolor->color[3] > GPENCIL_ALPHA_OPACITY_THRESH);
+}
+
+static int rna_GPencilPaletteColor_is_fill_visible_get(PointerRNA *ptr)
+{
+ bGPDpalettecolor *pcolor = (bGPDpalettecolor *)ptr->data;
+ return (pcolor->fill[3] > GPENCIL_ALPHA_OPACITY_THRESH);
+}
+
+static int rna_GPencilPaletteColor_index_get(PointerRNA *ptr)
+{
+ bGPDpalette *palette = (bGPDpalette *)ptr->data;
+ bGPDpalettecolor *pcolor = BKE_gpencil_palettecolor_getactive(palette);
+
+ return BLI_findindex(&palette->colors, pcolor);
+}
+
+static void rna_GPencilPaletteColor_index_set(PointerRNA *ptr, int value)
+{
+ bGPDpalette *palette = (bGPDpalette *)ptr->data;
+ bGPDpalettecolor *pcolor = BLI_findlink(&palette->colors, value);
+ BKE_gpencil_palettecolor_setactive(palette, pcolor);
+}
+
+static void rna_GPencilPaletteColor_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax)
+{
+ bGPDpalette *palette = (bGPDpalette *)ptr->data;
+
+ *min = 0;
+ *max = max_ii(0, BLI_listbase_count(&palette->colors) - 1);
+
+ *softmin = *min;
+ *softmax = *max;
}
#else
@@ -513,6 +893,12 @@ static void rna_def_gpencil_stroke_point(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Pressure", "Pressure of tablet at point when drawing it");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+ prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "strength");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Strength", "Color intensity (alpha factor)");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SPOINT_SELECT);
RNA_def_property_boolean_funcs(prop, NULL, "rna_GPencil_stroke_point_select_set");
@@ -523,9 +909,7 @@ static void rna_def_gpencil_stroke_point(BlenderRNA *brna)
static void rna_def_gpencil_stroke_points_api(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
-
FunctionRNA *func;
- /* PropertyRNA *parm; */
RNA_def_property_srna(cprop, "GPencilStrokePoints");
srna = RNA_def_struct(brna, "GPencilStrokePoints", NULL);
@@ -535,6 +919,8 @@ static void rna_def_gpencil_stroke_points_api(BlenderRNA *brna, PropertyRNA *cpr
func = RNA_def_function(srna, "add", "rna_GPencil_stroke_point_add");
RNA_def_function_ui_description(func, "Add a new grease pencil stroke point");
RNA_def_int(func, "count", 1, 0, INT_MAX, "Number", "Number of points to add to the stroke", 0, INT_MAX);
+ RNA_def_float(func, "pressure", 1.0f, 0.0f, 1.0f, "Pressure", "Pressure for newly created points", 0.0f, 1.0f);
+ RNA_def_float(func, "strength", 1.0f, 0.0f, 1.0f, "Strength", "Color intensity (alpha factor) for newly created points", 0.0f, 1.0f);
func = RNA_def_function(srna, "pop", "rna_GPencil_stroke_point_pop");
RNA_def_function_ui_description(func, "Remove a grease pencil stroke point");
@@ -542,6 +928,35 @@ static void rna_def_gpencil_stroke_points_api(BlenderRNA *brna, PropertyRNA *cpr
RNA_def_int(func, "index", -1, INT_MIN, INT_MAX, "Index", "point index", INT_MIN, INT_MAX);
}
+/* This information is read only and it can be used by add-ons */
+static void rna_def_gpencil_triangle(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "GPencilTriangle", NULL);
+ RNA_def_struct_sdna(srna, "bGPDtriangle");
+ RNA_def_struct_ui_text(srna, "Triangle", "Triangulation data for HQ fill");
+
+ /* point v1 */
+ prop = RNA_def_property(srna, "v1", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "v1");
+ RNA_def_property_ui_text(prop, "v1", "First triangle vertex index");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ /* point v2 */
+ prop = RNA_def_property(srna, "v2", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "v2");
+ RNA_def_property_ui_text(prop, "v2", "Second triangle vertex index");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ /* point v3 */
+ prop = RNA_def_property(srna, "v3", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "v3");
+ RNA_def_property_ui_text(prop, "v3", "Third triangle vertex index");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+}
+
static void rna_def_gpencil_stroke(BlenderRNA *brna)
{
StructRNA *srna;
@@ -566,6 +981,19 @@ static void rna_def_gpencil_stroke(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Stroke Points", "Stroke data points");
rna_def_gpencil_stroke_points_api(brna, prop);
+ /* Triangles */
+ prop = RNA_def_property(srna, "triangles", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "triangles", "tot_triangles");
+ RNA_def_property_struct_type(prop, "GPencilTriangle");
+ RNA_def_property_ui_text(prop, "Triangles", "Triangulation data for HQ fill");
+
+ /* Color */
+ prop = RNA_def_property(srna, "color", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "GPencilPaletteColor");
+ RNA_def_property_pointer_sdna(prop, NULL, "palcolor");
+ RNA_def_property_ui_text(prop, "Palette Color", "Color from palette used in Stroke");
+ RNA_def_property_update(prop, 0, "rna_GPencil_update");
+
/* Settings */
prop = RNA_def_property(srna, "draw_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
@@ -578,6 +1006,27 @@ static void rna_def_gpencil_stroke(BlenderRNA *brna)
RNA_def_property_boolean_funcs(prop, NULL, "rna_GPencil_stroke_select_set");
RNA_def_property_ui_text(prop, "Select", "Stroke is selected for viewport editing");
RNA_def_property_update(prop, 0, "rna_GPencil_update");
+
+ /* Color Name */
+ prop = RNA_def_property(srna, "colorname", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GPencilStrokeColor_info_set");
+ RNA_def_property_ui_text(prop, "Color Name", "Palette color name");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_stroke_colorname_update");
+
+ /* Cyclic: Draw a line from end to start point */
+ prop = RNA_def_property(srna, "draw_cyclic", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STROKE_CYCLIC);
+ RNA_def_property_ui_text(prop, "Cyclic", "Enable cyclic drawing, closing the stroke");
+ RNA_def_property_update(prop, 0, "rna_GPencil_update");
+
+ /* Line Thickness */
+ prop = RNA_def_property(srna, "line_width", PROP_INT, PROP_PIXEL);
+ RNA_def_property_int_sdna(prop, NULL, "thickness");
+ RNA_def_property_range(prop, 1, 300);
+ RNA_def_property_ui_range(prop, 1, 10, 1, 0);
+ RNA_def_property_ui_text(prop, "Thickness", "Thickness of stroke (in pixels)");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
}
static void rna_def_gpencil_strokes_api(BlenderRNA *brna, PropertyRNA *cprop)
@@ -594,6 +1043,7 @@ static void rna_def_gpencil_strokes_api(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_GPencil_stroke_new");
RNA_def_function_ui_description(func, "Add a new grease pencil stroke");
+ parm = RNA_def_string(func, "colorname", 0, MAX_NAME, "Color", "Name of the color");
parm = RNA_def_pointer(func, "stroke", "GPencilStroke", "", "The newly created stroke");
RNA_def_function_return(func, parm);
@@ -718,48 +1168,37 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
// TODO: replace these with a "draw type" combo (i.e. strokes only, filled strokes, strokes + fills, volumetric)?
prop = RNA_def_property(srna, "use_volumetric_strokes", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_VOLUMETRIC);
- RNA_def_property_ui_text(prop, "Volumetric Strokes", "Draw strokes as a series of circular blobs, resulting in a volumetric effect");
+ RNA_def_property_ui_text(prop, "Volumetric Strokes",
+ "Draw strokes as a series of circular blobs, resulting in a volumetric effect");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
- /* Use High Quality Fill */
- prop = RNA_def_property(srna, "use_hq_fill", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_HQ_FILL);
- RNA_def_property_ui_text(prop, "High Quality Fill", "Fill strokes using high quality method to avoid glitches (slower fps during animation playback)");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
-
- /* Stroke Drawing Color */
- prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_array(prop, 3);
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Color", "Color for all strokes in this layer");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
-
- prop = RNA_def_property(srna, "alpha", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "color[3]");
+ prop = RNA_def_property(srna, "opacity", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "opacity");
RNA_def_property_range(prop, 0.0, 1.0f);
RNA_def_property_ui_text(prop, "Opacity", "Layer Opacity");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
- /* Fill Drawing Color */
- prop = RNA_def_property(srna, "fill_color", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "fill");
+ /* Tint Color */
+ prop = RNA_def_property(srna, "tint_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "tintcolor");
RNA_def_property_array(prop, 3);
RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Fill Color", "Color for filling region bounded by each stroke");
+ RNA_def_property_ui_text(prop, "Tint Color", "Color for tinting stroke colors");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
- prop = RNA_def_property(srna, "fill_alpha", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "fill[3]");
+ /* Tint factor */
+ prop = RNA_def_property(srna, "tint_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "tintcolor[3]");
RNA_def_property_range(prop, 0.0, 1.0f);
- RNA_def_property_ui_text(prop, "Fill Opacity", "Opacity for filling region bounded by each stroke");
+ RNA_def_property_ui_text(prop, "Tint Factor", "Factor of tinting color");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
- /* Line Thickness */
- prop = RNA_def_property(srna, "line_width", PROP_INT, PROP_PIXEL);
+ /* Line Thickness change */
+ prop = RNA_def_property(srna, "line_change", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "thickness");
//RNA_def_property_range(prop, 1, 10); /* 10 px limit comes from Windows OpenGL limits for natively-drawn strokes */
RNA_def_property_int_funcs(prop, NULL, NULL, "rna_GPencilLayer_line_width_range");
- RNA_def_property_ui_text(prop, "Thickness", "Thickness of strokes (in pixels)");
+ RNA_def_property_ui_text(prop, "Thickness", "Thickness change to apply to current strokes (in pixels)");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Onion-Skinning */
@@ -773,7 +1212,7 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_range(prop, -1, 120);
RNA_def_property_ui_text(prop, "Frames Before",
"Maximum number of frames to show before current frame "
- "(0 = show only the previous sketch, -1 = Don't show any frames before current)");
+ "(0 = show only the previous sketch, -1 = don't show any frames before current)");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
prop = RNA_def_property(srna, "ghost_after_range", PROP_INT, PROP_NONE);
@@ -781,7 +1220,7 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_range(prop, -1, 120);
RNA_def_property_ui_text(prop, "Frames After",
"Maximum number of frames to show after current frame "
- "(0 = show only the next sketch, -1 = Don't show any frames after current)");
+ "(0 = show only the next sketch, -1 = don't show any frames after current)");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
prop = RNA_def_property(srna, "use_ghost_custom_colors", PROP_BOOLEAN, PROP_NONE);
@@ -803,29 +1242,6 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "After Color", "Base color for ghosts after the active frame");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
- /* Smoothing factor for new strokes */
- prop = RNA_def_property(srna, "pen_smooth_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "draw_smoothfac");
- RNA_def_property_range(prop, 0.0, 2.0f);
- RNA_def_property_ui_text(prop, "Smooth", "Amount of smoothing to apply to newly created strokes, to reduce jitter/noise");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
-
- /* Iterations of the Smoothing factor */
- prop = RNA_def_property(srna, "pen_smooth_steps", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "draw_smoothlvl");
- RNA_def_property_range(prop, 1, 3);
- RNA_def_property_ui_text(prop, "Iterations",
- "Number of times to smooth newly created strokes."
- "Smoothing strength is halved on each successive round of smoothing applied");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
-
- /* Subdivision level for new strokes */
- prop = RNA_def_property(srna, "pen_subdivision_steps", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "sublevel");
- RNA_def_property_range(prop, 0, 3);
- RNA_def_property_ui_text(prop, "Subdivision Steps", "Number of times to subdivide newly created strokes, for less jagged strokes");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
-
/* Flags */
prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_HIDE);
@@ -845,6 +1261,15 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Frame Locked", "Lock current frame displayed by layer");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+ /* Unlock colors */
+ prop = RNA_def_property(srna, "unlock_color", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_UNLOCK_COLOR);
+ RNA_def_property_ui_icon(prop, ICON_RESTRICT_COLOR_OFF, 1);
+ RNA_def_property_ui_text(prop, "Unlock Color",
+ "Unprotect selected colors from further editing and/or frame changes");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+
/* expose as layers.active */
#if 0
prop = RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
@@ -871,18 +1296,42 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "X Ray", "Make the layer draw in front of objects");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
-
- /* Read-only state props (for simpler UI code) */
- prop = RNA_def_property(srna, "is_stroke_visible", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_funcs(prop, "rna_GPencilLayer_is_stroke_visible_get", NULL);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Is Stroke Visible", "True when opacity of stroke is set high enough to be visible");
-
- prop = RNA_def_property(srna, "is_fill_visible", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_funcs(prop, "rna_GPencilLayer_is_fill_visible_get", NULL);
+ /* Parent object */
+ prop = RNA_def_property(srna, "parent", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_GPencilLayer_parent_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_ui_text(prop, "Parent", "Parent Object");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ /* parent type */
+ prop = RNA_def_property(srna, "parent_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "partype");
+ RNA_def_property_enum_items(prop, parent_type_items);
+ RNA_def_property_enum_funcs(prop, NULL, "rna_GPencilLayer_parent_type_set", "rna_Object_parent_type_itemf");
+ RNA_def_property_ui_text(prop, "Parent Type", "Type of parent relation");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ /* parent bone */
+ prop = RNA_def_property(srna, "parent_bone", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "parsubstr");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GPencilLayer_parent_bone_set");
+ RNA_def_property_ui_text(prop, "Parent Bone", "Name of parent bone in case of a bone parenting relation");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ /* matrix */
+ prop = RNA_def_property(srna, "matrix_inverse", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_property_float_sdna(prop, NULL, "inverse");
+ RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Inverse Matrix", "Parent inverse transformation matrix");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ /* read only parented flag */
+ prop = RNA_def_property(srna, "is_parented", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_GPencilLayer_is_parented_get", NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Is Fill Visible", "True when opacity of fill is set high enough to be visible");
-
+ RNA_def_property_ui_text(prop, "Is Parented", "True when the layer parent object is set");
+
/* Layers API */
func = RNA_def_function(srna, "clear", "rna_GPencil_layer_clear");
RNA_def_function_ui_description(func, "Remove all the grease pencil layer data");
@@ -931,6 +1380,209 @@ static void rna_def_gpencil_layers_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_ui_text(prop, "Active Layer Index", "Index of active grease pencil layer");
}
+static void rna_def_gpencil_palettecolor(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "GPencilPaletteColor", NULL);
+ RNA_def_struct_sdna(srna, "bGPDpalettecolor");
+ RNA_def_struct_ui_text(srna, "Grease Pencil Palette color", "Collection of related colors");
+ RNA_def_struct_path_func(srna, "rna_GPencilPalette_color_path");
+
+ /* Stroke Drawing Color */
+ prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "color");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Color", "Color for strokes");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "alpha", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "color[3]");
+ RNA_def_property_range(prop, 0.0, 1.0f);
+ RNA_def_property_ui_text(prop, "Opacity", "Color Opacity");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ /* Name */
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "info");
+ RNA_def_property_ui_text(prop, "Name", "Color name");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GPencilPaletteColor_info_set");
+ RNA_def_struct_name_property(srna, prop);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ /* Fill Drawing Color */
+ prop = RNA_def_property(srna, "fill_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "fill");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Fill Color", "Color for filling region bounded by each stroke");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ /* Fill alpha */
+ prop = RNA_def_property(srna, "fill_alpha", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "fill[3]");
+ RNA_def_property_range(prop, 0.0, 1.0f);
+ RNA_def_property_ui_text(prop, "Fill Opacity", "Opacity for filling region bounded by each stroke");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ /* Flags */
+ prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", PC_COLOR_HIDE);
+ RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, 1);
+ RNA_def_property_ui_text(prop, "Hide", "Set color Visibility");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "lock", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", PC_COLOR_LOCKED);
+ RNA_def_property_ui_icon(prop, ICON_UNLOCKED, 1);
+ RNA_def_property_ui_text(prop, "Locked", "Protect color from further editing and/or frame changes");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "ghost", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", PC_COLOR_ONIONSKIN);
+ RNA_def_property_ui_icon(prop, ICON_GHOST_ENABLED, 0);
+ RNA_def_property_ui_text(prop, "Ghost", "Display the color in onion skinning");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ /* Draw Style */
+ prop = RNA_def_property(srna, "use_volumetric_strokes", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", PC_COLOR_VOLUMETRIC);
+ RNA_def_property_ui_text(prop, "Volumetric Strokes", "Draw strokes as a series of circular blobs, resulting in "
+ "a volumetric effect");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ /* Use High quality fill */
+ prop = RNA_def_property(srna, "use_hq_fill", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", PC_COLOR_HQ_FILL);
+ RNA_def_property_ui_text(prop, "High Quality Fill", "Fill strokes using high quality to avoid glitches "
+ "(slower fps during animation play)");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ /* Read-only state props (for simpler UI code) */
+ prop = RNA_def_property(srna, "is_stroke_visible", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_GPencilPaletteColor_is_stroke_visible_get", NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Is Stroke Visible", "True when opacity of stroke is set high enough to be visible");
+
+ prop = RNA_def_property(srna, "is_fill_visible", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_GPencilPaletteColor_is_fill_visible_get", NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Is Fill Visible", "True when opacity of fill is set high enough to be visible");
+}
+
+/* palette colors api */
+static void rna_def_gpencil_palettecolors_api(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "GPencilPaletteColors");
+ srna = RNA_def_struct(brna, "GPencilPaletteColors", NULL);
+ RNA_def_struct_sdna(srna, "bGPDpalette");
+ RNA_def_struct_ui_text(srna, "Palette colors", "Collection of palette colors");
+
+ func = RNA_def_function(srna, "new", "rna_GPencilPalette_color_new");
+ RNA_def_function_ui_description(func, "Add a new color to the palette");
+ parm = RNA_def_pointer(func, "color", "GPencilPaletteColor", "", "The newly created color");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_GPencilPalette_color_remove");
+ RNA_def_function_ui_description(func, "Remove a color from the palette");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(func, "color", "GPencilPaletteColor", "", "The color to remove");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+
+ prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "GPencilPaletteColor");
+ RNA_def_property_pointer_funcs(prop, "rna_GPencilPalette_active_color_get", "rna_GPencilPalette_active_color_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Active Palette Color", "Current active color");
+
+ prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_funcs(prop,
+ "rna_GPencilPaletteColor_index_get",
+ "rna_GPencilPaletteColor_index_set",
+ "rna_GPencilPaletteColor_index_range");
+ RNA_def_property_ui_text(prop, "Active color Index", "Index of active palette color");
+}
+
+static void rna_def_gpencil_palette(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "GPencilPalette", NULL);
+ RNA_def_struct_sdna(srna, "bGPDpalette");
+ RNA_def_struct_ui_text(srna, "Grease Pencil Palette", "Collection of related palettes");
+ RNA_def_struct_path_func(srna, "rna_GPencilPalette_path");
+ RNA_def_struct_ui_icon(srna, ICON_COLOR);
+
+ /* Name */
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "info");
+ RNA_def_property_ui_text(prop, "Name", "Palette name");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GPencilPalette_info_set");
+ RNA_def_struct_name_property(srna, prop);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ /* Colors */
+ prop = RNA_def_property(srna, "colors", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "colors", NULL);
+ RNA_def_property_struct_type(prop, "GPencilPaletteColor");
+ RNA_def_property_ui_text(prop, "Colors", "Colors of the palette");
+ rna_def_gpencil_palettecolors_api(brna, prop);
+
+}
+
+static void rna_def_gpencil_palettes_api(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "GreasePencilPalettes");
+ srna = RNA_def_struct(brna, "GreasePencilPalettes", NULL);
+ RNA_def_struct_sdna(srna, "bGPdata");
+ RNA_def_struct_ui_text(srna, "Grease Pencil Palettes", "Collection of grease pencil palettes");
+
+ func = RNA_def_function(srna, "new", "rna_GPencil_palette_new");
+ RNA_def_function_ui_description(func, "Add a new grease pencil palette");
+ parm = RNA_def_string(func, "name", "GPencilPalette", MAX_NAME, "Name", "Name of the palette");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_boolean(func, "set_active", 0, "Set Active", "Activate the newly created palette");
+ parm = RNA_def_pointer(func, "palette", "GPencilPalette", "", "The newly created palette");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_GPencil_palette_remove");
+ RNA_def_function_ui_description(func, "Remove a grease pencil palette");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(func, "palette", "GPencilPalette", "", "The palette to remove");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+
+ prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "GPencilPalette");
+ RNA_def_property_pointer_funcs(prop, "rna_GPencil_active_palette_get", "rna_GPencil_active_palette_set",
+ NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Active Palette", "Current active palette");
+
+ prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_funcs(prop,
+ "rna_GPencilPalette_index_get",
+ "rna_GPencilPalette_index_set",
+ "rna_GPencilPalette_index_range");
+ RNA_def_property_ui_text(prop, "Active Palette Index", "Index of active palette");
+}
+
static void rna_def_gpencil_data(BlenderRNA *brna)
{
StructRNA *srna;
@@ -949,6 +1601,13 @@ static void rna_def_gpencil_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Layers", "");
rna_def_gpencil_layers_api(brna, prop);
+ /* Palettes */
+ prop = RNA_def_property(srna, "palettes", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "palettes", NULL);
+ RNA_def_property_struct_type(prop, "GPencilPalette");
+ RNA_def_property_ui_text(prop, "Palettes", "");
+ rna_def_gpencil_palettes_api(brna, prop);
+
/* Animation Data */
rna_def_animdata_common(srna);
@@ -965,6 +1624,12 @@ static void rna_def_gpencil_data(BlenderRNA *brna)
"Show ghosts of the frames before and after the current frame, toggle to enable on active layer or disable all");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+ prop = RNA_def_property(srna, "show_stroke_direction", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_SHOW_DIRECTION);
+ RNA_def_property_ui_text(prop, "Show Direction", "Show stroke drawing direction with a bigger green dot (start) "
+ "and smaller red dot (end) points");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
/* API Functions */
func = RNA_def_function(srna, "clear", "rna_GPencil_clear");
RNA_def_function_ui_description(func, "Remove all the grease pencil data");
@@ -978,8 +1643,12 @@ void RNA_def_gpencil(BlenderRNA *brna)
rna_def_gpencil_layer(brna);
rna_def_gpencil_frame(brna);
+ rna_def_gpencil_triangle(brna);
rna_def_gpencil_stroke(brna);
rna_def_gpencil_stroke_point(brna);
+
+ rna_def_gpencil_palette(brna);
+ rna_def_gpencil_palettecolor(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index 703b02f9d18..76455adbc78 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -133,6 +133,7 @@ void RNA_def_armature(struct BlenderRNA *brna);
void RNA_def_actuator(struct BlenderRNA *brna);
void RNA_def_boid(struct BlenderRNA *brna);
void RNA_def_brush(struct BlenderRNA *brna);
+void RNA_def_cachefile(struct BlenderRNA *brna);
void RNA_def_camera(struct BlenderRNA *brna);
void RNA_def_cloth(struct BlenderRNA *brna);
void RNA_def_color(struct BlenderRNA *brna);
@@ -197,6 +198,8 @@ void rna_def_animdata_common(struct StructRNA *srna);
void rna_def_animviz_common(struct StructRNA *srna);
void rna_def_motionpath_common(struct StructRNA *srna);
+void rna_def_bone_curved_common(struct StructRNA *srna, bool is_posebone);
+
void rna_def_texmat_common(struct StructRNA *srna, const char *texspace_editable);
void rna_def_mtex_common(struct BlenderRNA *brna, struct StructRNA *srna, const char *begin, const char *activeget,
const char *activeset, const char *activeeditable, const char *structname,
@@ -330,6 +333,8 @@ void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop);
+void RNA_def_main_cachefiles(BlenderRNA *brna, PropertyRNA *cprop);
+void RNA_def_main_paintcurves(BlenderRNA *brna, PropertyRNA *cprop);
/* ID Properties */
diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h
index ba0705b5caa..04b85b8997e 100644
--- a/source/blender/makesrna/intern/rna_internal_types.h
+++ b/source/blender/makesrna/intern/rna_internal_types.h
@@ -62,7 +62,7 @@ struct Scene;
typedef void (*UpdateFunc)(struct Main *main, struct Scene *scene, struct PointerRNA *ptr);
typedef void (*ContextPropUpdateFunc)(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop);
typedef void (*ContextUpdateFunc)(struct bContext *C, struct PointerRNA *ptr);
-typedef int (*EditableFunc)(struct PointerRNA *ptr);
+typedef int (*EditableFunc)(struct PointerRNA *ptr, const char **r_info);
typedef int (*ItemEditableFunc)(struct PointerRNA *ptr, int index);
typedef struct IDProperty *(*IDPropertiesFunc)(struct PointerRNA *ptr, bool create);
typedef struct StructRNA *(*StructRefineFunc)(struct PointerRNA *ptr);
@@ -188,7 +188,9 @@ struct PropertyRNA {
UpdateFunc update;
int noteflag;
- /* callback for testing if editable */
+ /* Callback for testing if editable. Its r_info parameter can be used to
+ * return info on editable state that might be shown to user. E.g. tooltips
+ * of disabled buttons can show reason why button is disabled using this. */
EditableFunc editable;
/* callback for testing if array-item editable (if applicable) */
ItemEditableFunc itemeditable;
diff --git a/source/blender/makesrna/intern/rna_key.c b/source/blender/makesrna/intern/rna_key.c
index 502e22e2c07..f20e8fb8ed4 100644
--- a/source/blender/makesrna/intern/rna_key.c
+++ b/source/blender/makesrna/intern/rna_key.c
@@ -797,7 +797,7 @@ static void rna_def_key(BlenderRNA *brna)
prop = RNA_def_property(srna, "user", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_pointer_sdna(prop, NULL, "from");
- RNA_def_property_ui_text(prop, "User", "Datablock using these shape keys");
+ RNA_def_property_ui_text(prop, "User", "Data-block using these shape keys");
prop = RNA_def_property(srna, "use_relative", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "type", KEY_RELATIVE);
diff --git a/source/blender/makesrna/intern/rna_lamp.c b/source/blender/makesrna/intern/rna_lamp.c
index e4e3699f301..51709d3137c 100644
--- a/source/blender/makesrna/intern/rna_lamp.c
+++ b/source/blender/makesrna/intern/rna_lamp.c
@@ -546,7 +546,7 @@ static void rna_def_lamp_shadow(StructRNA *srna, int spot, int area)
prop = RNA_def_property(srna, "shadow_method", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "mode");
RNA_def_property_enum_items(prop, (spot) ? prop_spot_shadow_items : prop_shadow_items);
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
+ RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
prop = RNA_def_property(srna, "shadow_buffer_size", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "bufsize");
diff --git a/source/blender/makesrna/intern/rna_lattice.c b/source/blender/makesrna/intern/rna_lattice.c
index 6bc9cc38a7d..9424ddf7d0e 100644
--- a/source/blender/makesrna/intern/rna_lattice.c
+++ b/source/blender/makesrna/intern/rna_lattice.c
@@ -171,7 +171,7 @@ static void rna_Lattice_use_outside_set(PointerRNA *ptr, int value)
}
}
-static int rna_Lattice_size_editable(PointerRNA *ptr)
+static int rna_Lattice_size_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
Lattice *lt = (Lattice *)ptr->data;
diff --git a/source/blender/makesrna/intern/rna_linestyle.c b/source/blender/makesrna/intern/rna_linestyle.c
index d8cc61bf906..9b28009d161 100644
--- a/source/blender/makesrna/intern/rna_linestyle.c
+++ b/source/blender/makesrna/intern/rna_linestyle.c
@@ -1499,14 +1499,15 @@ static void rna_def_freestyle_thickness_modifiers(BlenderRNA *brna, PropertyRNA
RNA_def_property_srna(cprop, "LineStyleThicknessModifiers");
srna = RNA_def_struct(brna, "LineStyleThicknessModifiers", NULL);
RNA_def_struct_sdna(srna, "FreestyleLineStyle");
- RNA_def_struct_ui_text(srna, "Thickness Modifiers", "Thickness modifiers for changing line thicknesss");
+ RNA_def_struct_ui_text(srna, "Thickness Modifiers", "Thickness modifiers for changing line thickness");
func = RNA_def_function(srna, "new", "rna_LineStyle_thickness_modifier_add");
RNA_def_function_ui_description(func, "Add a thickness modifier to line style");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "name", "ThicknessModifier", 0, "", "New name for the thickness modifier (not unique)");
RNA_def_property_flag(parm, PROP_REQUIRED);
- parm = RNA_def_enum(func, "type", rna_enum_linestyle_thickness_modifier_type_items, 0, "", "Thickness modifier type to add");
+ parm = RNA_def_enum(func, "type", rna_enum_linestyle_thickness_modifier_type_items, 0,
+ "", "Thickness modifier type to add");
RNA_def_property_flag(parm, PROP_REQUIRED);
parm = RNA_def_pointer(func, "modifier", "LineStyleThicknessModifier", "", "Newly added thickness modifier");
RNA_def_function_return(func, parm);
@@ -1528,14 +1529,15 @@ static void rna_def_freestyle_geometry_modifiers(BlenderRNA *brna, PropertyRNA *
RNA_def_property_srna(cprop, "LineStyleGeometryModifiers");
srna = RNA_def_struct(brna, "LineStyleGeometryModifiers", NULL);
RNA_def_struct_sdna(srna, "FreestyleLineStyle");
- RNA_def_struct_ui_text(srna, "Geometry Modifiers", "Geometry modifiers for changing line geometrys");
+ RNA_def_struct_ui_text(srna, "Geometry Modifiers", "Geometry modifiers for changing line geometries");
func = RNA_def_function(srna, "new", "rna_LineStyle_geometry_modifier_add");
RNA_def_function_ui_description(func, "Add a geometry modifier to line style");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "name", "GeometryModifier", 0, "", "New name for the geometry modifier (not unique)");
RNA_def_property_flag(parm, PROP_REQUIRED);
- parm = RNA_def_enum(func, "type", rna_enum_linestyle_geometry_modifier_type_items, 0, "", "Geometry modifier type to add");
+ parm = RNA_def_enum(func, "type", rna_enum_linestyle_geometry_modifier_type_items, 0,
+ "", "Geometry modifier type to add");
RNA_def_property_flag(parm, PROP_REQUIRED);
parm = RNA_def_pointer(func, "modifier", "LineStyleGeometryModifier", "", "Newly added geometry modifier");
RNA_def_function_return(func, parm);
diff --git a/source/blender/makesrna/intern/rna_main.c b/source/blender/makesrna/intern/rna_main.c
index e0538d1c05b..d432f086dba 100644
--- a/source/blender/makesrna/intern/rna_main.c
+++ b/source/blender/makesrna/intern/rna_main.c
@@ -281,6 +281,18 @@ static void rna_Main_linestyle_begin(CollectionPropertyIterator *iter, PointerRN
rna_iterator_listbase_begin(iter, &bmain->linestyle, NULL);
}
+static void rna_Main_cachefiles_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ Main *bmain = (Main *)ptr->data;
+ rna_iterator_listbase_begin(iter, &bmain->cachefiles, NULL);
+}
+
+static void rna_Main_paintcurves_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ Main *bmain = (Main *)ptr->data;
+ rna_iterator_listbase_begin(iter, &bmain->paintcurves, NULL);
+}
+
static void rna_Main_version_get(PointerRNA *ptr, int *value)
{
Main *bmain = (Main *)ptr->data;
@@ -323,37 +335,39 @@ void RNA_def_main(BlenderRNA *brna)
/* plural must match idtypes in readblenentry.c */
MainCollectionDef lists[] = {
- {"cameras", "Camera", "rna_Main_camera_begin", "Cameras", "Camera datablocks", RNA_def_main_cameras},
- {"scenes", "Scene", "rna_Main_scene_begin", "Scenes", "Scene datablocks", RNA_def_main_scenes},
- {"objects", "Object", "rna_Main_object_begin", "Objects", "Object datablocks", RNA_def_main_objects},
- {"materials", "Material", "rna_Main_mat_begin", "Materials", "Material datablocks", RNA_def_main_materials},
- {"node_groups", "NodeTree", "rna_Main_nodetree_begin", "Node Groups", "Node group datablocks", RNA_def_main_node_groups},
- {"meshes", "Mesh", "rna_Main_mesh_begin", "Meshes", "Mesh datablocks", RNA_def_main_meshes},
- {"lamps", "Lamp", "rna_Main_lamp_begin", "Lamps", "Lamp datablocks", RNA_def_main_lamps},
- {"libraries", "Library", "rna_Main_library_begin", "Libraries", "Library datablocks", RNA_def_main_libraries},
- {"screens", "Screen", "rna_Main_screen_begin", "Screens", "Screen datablocks", RNA_def_main_screens},
- {"window_managers", "WindowManager", "rna_Main_wm_begin", "Window Managers", "Window manager datablocks", RNA_def_main_window_managers},
- {"images", "Image", "rna_Main_image_begin", "Images", "Image datablocks", RNA_def_main_images},
- {"lattices", "Lattice", "rna_Main_latt_begin", "Lattices", "Lattice datablocks", RNA_def_main_lattices},
- {"curves", "Curve", "rna_Main_curve_begin", "Curves", "Curve datablocks", RNA_def_main_curves},
- {"metaballs", "MetaBall", "rna_Main_mball_begin", "Metaballs", "Metaball datablocks", RNA_def_main_metaballs},
- {"fonts", "VectorFont", "rna_Main_font_begin", "Vector Fonts", "Vector font datablocks", RNA_def_main_fonts},
- {"textures", "Texture", "rna_Main_tex_begin", "Textures", "Texture datablocks", RNA_def_main_textures},
- {"brushes", "Brush", "rna_Main_brush_begin", "Brushes", "Brush datablocks", RNA_def_main_brushes},
- {"worlds", "World", "rna_Main_world_begin", "Worlds", "World datablocks", RNA_def_main_worlds},
- {"groups", "Group", "rna_Main_group_begin", "Groups", "Group datablocks", RNA_def_main_groups},
- {"shape_keys", "Key", "rna_Main_key_begin", "Shape Keys", "Shape Key datablocks", NULL},
- {"texts", "Text", "rna_Main_text_begin", "Texts", "Text datablocks", RNA_def_main_texts},
- {"speakers", "Speaker", "rna_Main_speaker_begin", "Speakers", "Speaker datablocks", RNA_def_main_speakers},
- {"sounds", "Sound", "rna_Main_sound_begin", "Sounds", "Sound datablocks", RNA_def_main_sounds},
- {"armatures", "Armature", "rna_Main_armature_begin", "Armatures", "Armature datablocks", RNA_def_main_armatures},
- {"actions", "Action", "rna_Main_action_begin", "Actions", "Action datablocks", RNA_def_main_actions},
- {"particles", "ParticleSettings", "rna_Main_particle_begin", "Particles", "Particle datablocks", RNA_def_main_particles},
- {"palettes", "Palette", "rna_Main_palettes_begin", "Palettes", "Palette datablocks", RNA_def_main_palettes},
- {"grease_pencil", "GreasePencil", "rna_Main_gpencil_begin", "Grease Pencil", "Grease Pencil datablocks", RNA_def_main_gpencil},
- {"movieclips", "MovieClip", "rna_Main_movieclips_begin", "Movie Clips", "Movie Clip datablocks", RNA_def_main_movieclips},
- {"masks", "Mask", "rna_Main_masks_begin", "Masks", "Masks datablocks", RNA_def_main_masks},
- {"linestyles", "FreestyleLineStyle", "rna_Main_linestyle_begin", "Line Styles", "Line Style datablocks", RNA_def_main_linestyles},
+ {"cameras", "Camera", "rna_Main_camera_begin", "Cameras", "Camera data-blocks", RNA_def_main_cameras},
+ {"scenes", "Scene", "rna_Main_scene_begin", "Scenes", "Scene data-blocks", RNA_def_main_scenes},
+ {"objects", "Object", "rna_Main_object_begin", "Objects", "Object data-blocks", RNA_def_main_objects},
+ {"materials", "Material", "rna_Main_mat_begin", "Materials", "Material data-blocks", RNA_def_main_materials},
+ {"node_groups", "NodeTree", "rna_Main_nodetree_begin", "Node Groups", "Node group data-blocks", RNA_def_main_node_groups},
+ {"meshes", "Mesh", "rna_Main_mesh_begin", "Meshes", "Mesh data-blocks", RNA_def_main_meshes},
+ {"lamps", "Lamp", "rna_Main_lamp_begin", "Lamps", "Lamp data-blocks", RNA_def_main_lamps},
+ {"libraries", "Library", "rna_Main_library_begin", "Libraries", "Library data-blocks", RNA_def_main_libraries},
+ {"screens", "Screen", "rna_Main_screen_begin", "Screens", "Screen data-blocks", RNA_def_main_screens},
+ {"window_managers", "WindowManager", "rna_Main_wm_begin", "Window Managers", "Window manager data-blocks", RNA_def_main_window_managers},
+ {"images", "Image", "rna_Main_image_begin", "Images", "Image data-blocks", RNA_def_main_images},
+ {"lattices", "Lattice", "rna_Main_latt_begin", "Lattices", "Lattice data-blocks", RNA_def_main_lattices},
+ {"curves", "Curve", "rna_Main_curve_begin", "Curves", "Curve data-blocks", RNA_def_main_curves},
+ {"metaballs", "MetaBall", "rna_Main_mball_begin", "Metaballs", "Metaball data-blocks", RNA_def_main_metaballs},
+ {"fonts", "VectorFont", "rna_Main_font_begin", "Vector Fonts", "Vector font data-blocks", RNA_def_main_fonts},
+ {"textures", "Texture", "rna_Main_tex_begin", "Textures", "Texture data-blocks", RNA_def_main_textures},
+ {"brushes", "Brush", "rna_Main_brush_begin", "Brushes", "Brush data-blocks", RNA_def_main_brushes},
+ {"worlds", "World", "rna_Main_world_begin", "Worlds", "World data-blocks", RNA_def_main_worlds},
+ {"groups", "Group", "rna_Main_group_begin", "Groups", "Group data-blocks", RNA_def_main_groups},
+ {"shape_keys", "Key", "rna_Main_key_begin", "Shape Keys", "Shape Key data-blocks", NULL},
+ {"texts", "Text", "rna_Main_text_begin", "Texts", "Text data-blocks", RNA_def_main_texts},
+ {"speakers", "Speaker", "rna_Main_speaker_begin", "Speakers", "Speaker data-blocks", RNA_def_main_speakers},
+ {"sounds", "Sound", "rna_Main_sound_begin", "Sounds", "Sound data-blocks", RNA_def_main_sounds},
+ {"armatures", "Armature", "rna_Main_armature_begin", "Armatures", "Armature data-blocks", RNA_def_main_armatures},
+ {"actions", "Action", "rna_Main_action_begin", "Actions", "Action data-blocks", RNA_def_main_actions},
+ {"particles", "ParticleSettings", "rna_Main_particle_begin", "Particles", "Particle data-blocks", RNA_def_main_particles},
+ {"palettes", "Palette", "rna_Main_palettes_begin", "Palettes", "Palette data-blocks", RNA_def_main_palettes},
+ {"grease_pencil", "GreasePencil", "rna_Main_gpencil_begin", "Grease Pencil", "Grease Pencil data-blocks", RNA_def_main_gpencil},
+ {"movieclips", "MovieClip", "rna_Main_movieclips_begin", "Movie Clips", "Movie Clip data-blocks", RNA_def_main_movieclips},
+ {"masks", "Mask", "rna_Main_masks_begin", "Masks", "Masks data-blocks", RNA_def_main_masks},
+ {"linestyles", "FreestyleLineStyle", "rna_Main_linestyle_begin", "Line Styles", "Line Style data-blocks", RNA_def_main_linestyles},
+ {"cache_files", "CacheFile", "rna_Main_cachefiles_begin", "Cache Files", "Cache Files data-blocks", RNA_def_main_cachefiles},
+ {"paint_curves", "PaintCurve", "rna_Main_paintcurves_begin", "Paint Curves", "Paint Curves data-blocks", RNA_def_main_paintcurves},
{NULL, NULL, NULL, NULL, NULL, NULL}
};
@@ -361,7 +375,7 @@ void RNA_def_main(BlenderRNA *brna)
srna = RNA_def_struct(brna, "BlendData", NULL);
RNA_def_struct_ui_text(srna, "Blendfile Data",
- "Main data structure representing a .blend file and all its datablocks");
+ "Main data structure representing a .blend file and all its data-blocks");
RNA_def_struct_ui_icon(srna, ICON_BLENDER);
prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
index 4b7ce640a56..cc290eab59d 100644
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ b/source/blender/makesrna/intern/rna_main_api.c
@@ -58,9 +58,11 @@
#include "BKE_armature.h"
#include "BKE_lamp.h"
#include "BKE_library.h"
+#include "BKE_library_remap.h"
#include "BKE_object.h"
#include "BKE_material.h"
#include "BKE_icons.h"
+#include "BKE_idcode.h"
#include "BKE_image.h"
#include "BKE_texture.h"
#include "BKE_scene.h"
@@ -113,30 +115,38 @@
# include "BPY_extern.h"
#endif
+
+static void rna_Main_ID_remove(Main *bmain, ReportList *reports, PointerRNA *id_ptr, int do_unlink)
+{
+ ID *id = id_ptr->data;
+ if (do_unlink) {
+ BKE_libblock_delete(bmain, id);
+ RNA_POINTER_INVALIDATE(id_ptr);
+ }
+ else if (ID_REAL_USERS(id) <= 0) {
+ BKE_libblock_free(bmain, id);
+ RNA_POINTER_INVALIDATE(id_ptr);
+ }
+ else {
+ BKE_reportf(reports, RPT_ERROR,
+ "%s '%s' must have zero users to be removed, found %d (try with do_unlink=True parameter)",
+ BKE_idcode_to_name(GS(id->name)), id->name + 2, ID_REAL_USERS(id));
+ }
+}
+
+
static Camera *rna_Main_cameras_new(Main *bmain, const char *name)
{
ID *id = BKE_camera_add(bmain, name);
id_us_min(id);
return (Camera *)id;
}
-static void rna_Main_cameras_remove(Main *bmain, ReportList *reports, PointerRNA *camera_ptr)
-{
- Camera *camera = camera_ptr->data;
- if (ID_REAL_USERS(camera) <= 0) {
- BKE_libblock_free(bmain, camera);
- RNA_POINTER_INVALIDATE(camera_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Camera '%s' must have zero users to be removed, found %d",
- camera->id.name + 2, ID_REAL_USERS(camera));
- }
-}
static Scene *rna_Main_scenes_new(Main *bmain, const char *name)
{
return BKE_scene_add(bmain, name);
}
-static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports, PointerRNA *scene_ptr)
+static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports, PointerRNA *scene_ptr, int do_unlink)
{
/* don't call BKE_libblock_free(...) directly */
Scene *scene = scene_ptr->data;
@@ -145,23 +155,23 @@ static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports
if ((scene_new = scene->id.prev) ||
(scene_new = scene->id.next))
{
- bScreen *sc = CTX_wm_screen(C);
- if (sc->scene == scene) {
+ if (do_unlink) {
+ bScreen *sc = CTX_wm_screen(C);
+ if (sc->scene == scene) {
#ifdef WITH_PYTHON
- BPy_BEGIN_ALLOW_THREADS;
+ BPy_BEGIN_ALLOW_THREADS;
#endif
- ED_screen_set_scene(C, sc, scene_new);
+ ED_screen_set_scene(C, sc, scene_new);
#ifdef WITH_PYTHON
- BPy_END_ALLOW_THREADS;
+ BPy_END_ALLOW_THREADS;
#endif
+ }
}
-
- BKE_scene_unlink(bmain, scene, scene_new);
- RNA_POINTER_INVALIDATE(scene_ptr);
+ rna_Main_ID_remove(bmain, reports, scene_ptr, do_unlink);
}
else {
BKE_reportf(reports, RPT_ERROR, "Scene '%s' is the last, cannot be removed", scene->id.name + 2);
@@ -217,43 +227,17 @@ static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char
id_us_min(&ob->id);
ob->data = data;
- test_object_materials(bmain, ob->data);
+ test_object_materials(ob, ob->data);
return ob;
}
-static void rna_Main_objects_remove(Main *bmain, ReportList *reports, PointerRNA *object_ptr)
-{
- Object *object = object_ptr->data;
- if (ID_REAL_USERS(object) <= 0) {
- BKE_object_unlink(bmain, object); /* needed or ID pointers to this are not cleared */
- BKE_libblock_free(bmain, object);
- RNA_POINTER_INVALIDATE(object_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Object '%s' must have zero users to be removed, found %d",
- object->id.name + 2, ID_REAL_USERS(object));
- }
-}
-
static Material *rna_Main_materials_new(Main *bmain, const char *name)
{
ID *id = (ID *)BKE_material_add(bmain, name);
id_us_min(id);
return (Material *)id;
}
-static void rna_Main_materials_remove(Main *bmain, ReportList *reports, PointerRNA *material_ptr)
-{
- Material *material = material_ptr->data;
- if (ID_REAL_USERS(material) <= 0) {
- BKE_libblock_free(bmain, material);
- RNA_POINTER_INVALIDATE(material_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Material '%s' must have zero users to be removed, found %d",
- material->id.name + 2, ID_REAL_USERS(material));
- }
-}
static EnumPropertyItem *rna_Main_nodetree_type_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
{
@@ -271,18 +255,6 @@ static struct bNodeTree *rna_Main_nodetree_new(Main *bmain, const char *name, in
else
return NULL;
}
-static void rna_Main_nodetree_remove(Main *bmain, ReportList *reports, PointerRNA *ntree_ptr)
-{
- bNodeTree *ntree = ntree_ptr->data;
- if (ID_REAL_USERS(ntree) <= 0) {
- BKE_libblock_free(bmain, ntree);
- RNA_POINTER_INVALIDATE(ntree_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Node tree '%s' must have zero users to be removed, found %d",
- ntree->id.name + 2, ID_REAL_USERS(ntree));
- }
-}
static Mesh *rna_Main_meshes_new(Main *bmain, const char *name)
{
@@ -312,19 +284,6 @@ Mesh *rna_Main_meshes_new_from_object(
return BKE_mesh_new_from_object(bmain, sce, ob, apply_modifiers, settings, calc_tessface, calc_undeformed);
}
-static void rna_Main_meshes_remove(Main *bmain, ReportList *reports, PointerRNA *mesh_ptr)
-{
- Mesh *mesh = mesh_ptr->data;
- if (ID_REAL_USERS(mesh) <= 0) {
- BKE_libblock_free(bmain, mesh);
- RNA_POINTER_INVALIDATE(mesh_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Mesh '%s' must have zero users to be removed, found %d",
- mesh->id.name + 2, ID_REAL_USERS(mesh));
- }
-}
-
static Lamp *rna_Main_lamps_new(Main *bmain, const char *name, int type)
{
Lamp *lamp = BKE_lamp_add(bmain, name);
@@ -332,18 +291,6 @@ static Lamp *rna_Main_lamps_new(Main *bmain, const char *name, int type)
id_us_min(&lamp->id);
return lamp;
}
-static void rna_Main_lamps_remove(Main *bmain, ReportList *reports, PointerRNA *lamp_ptr)
-{
- Lamp *lamp = lamp_ptr->data;
- if (ID_REAL_USERS(lamp) <= 0) {
- BKE_libblock_free(bmain, lamp);
- RNA_POINTER_INVALIDATE(lamp_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Lamp '%s' must have zero users to be removed, found %d",
- lamp->id.name + 2, ID_REAL_USERS(lamp));
- }
-}
static Image *rna_Main_images_new(Main *bmain, const char *name, int width, int height, int alpha, int float_buffer, int stereo3d)
{
@@ -372,18 +319,6 @@ static Image *rna_Main_images_load(Main *bmain, ReportList *reports, const char
id_us_min((ID *)ima);
return ima;
}
-static void rna_Main_images_remove(Main *bmain, ReportList *reports, PointerRNA *image_ptr)
-{
- Image *image = image_ptr->data;
- if (ID_REAL_USERS(image) <= 0) {
- BKE_libblock_free(bmain, image);
- RNA_POINTER_INVALIDATE(image_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Image '%s' must have zero users to be removed, found %d",
- image->id.name + 2, ID_REAL_USERS(image));
- }
-}
static Lattice *rna_Main_lattices_new(Main *bmain, const char *name)
{
@@ -391,18 +326,6 @@ static Lattice *rna_Main_lattices_new(Main *bmain, const char *name)
id_us_min(&lt->id);
return lt;
}
-static void rna_Main_lattices_remove(Main *bmain, ReportList *reports, PointerRNA *lt_ptr)
-{
- Lattice *lt = lt_ptr->data;
- if (ID_REAL_USERS(lt) <= 0) {
- BKE_libblock_free(bmain, lt);
- RNA_POINTER_INVALIDATE(lt_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Lattice '%s' must have zero users to be removed, found %d",
- lt->id.name + 2, ID_REAL_USERS(lt));
- }
-}
static Curve *rna_Main_curves_new(Main *bmain, const char *name, int type)
{
@@ -410,18 +333,6 @@ static Curve *rna_Main_curves_new(Main *bmain, const char *name, int type)
id_us_min(&cu->id);
return cu;
}
-static void rna_Main_curves_remove(Main *bmain, ReportList *reports, PointerRNA *cu_ptr)
-{
- Curve *cu = cu_ptr->data;
- if (ID_REAL_USERS(cu) <= 0) {
- BKE_libblock_free(bmain, cu);
- RNA_POINTER_INVALIDATE(cu_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Curve '%s' must have zero users to be removed, found %d",
- cu->id.name + 2, ID_REAL_USERS(cu));
- }
-}
static MetaBall *rna_Main_metaballs_new(Main *bmain, const char *name)
{
@@ -429,18 +340,6 @@ static MetaBall *rna_Main_metaballs_new(Main *bmain, const char *name)
id_us_min(&mb->id);
return mb;
}
-static void rna_Main_metaballs_remove(Main *bmain, ReportList *reports, PointerRNA *mb_ptr)
-{
- MetaBall *mb = mb_ptr->data;
- if (ID_REAL_USERS(mb) <= 0) {
- BKE_libblock_free(bmain, mb);
- RNA_POINTER_INVALIDATE(mb_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Metaball '%s' must have zero users to be removed, found %d",
- mb->id.name + 2, ID_REAL_USERS(mb));
- }
-}
static VFont *rna_Main_fonts_load(Main *bmain, ReportList *reports, const char *filepath, int check_existing)
{
@@ -462,18 +361,6 @@ static VFont *rna_Main_fonts_load(Main *bmain, ReportList *reports, const char *
return font;
}
-static void rna_Main_fonts_remove(Main *bmain, ReportList *reports, PointerRNA *vfont_ptr)
-{
- VFont *vfont = vfont_ptr->data;
- if (ID_REAL_USERS(vfont) <= 0) {
- BKE_libblock_free(bmain, vfont);
- RNA_POINTER_INVALIDATE(vfont_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Font '%s' must have zero users to be removed, found %d",
- vfont->id.name + 2, ID_REAL_USERS(vfont));
- }
-}
static Tex *rna_Main_textures_new(Main *bmain, const char *name, int type)
{
@@ -482,18 +369,6 @@ static Tex *rna_Main_textures_new(Main *bmain, const char *name, int type)
id_us_min(&tex->id);
return tex;
}
-static void rna_Main_textures_remove(Main *bmain, ReportList *reports, PointerRNA *tex_ptr)
-{
- Tex *tex = tex_ptr->data;
- if (ID_REAL_USERS(tex) <= 0) {
- BKE_libblock_free(bmain, tex);
- RNA_POINTER_INVALIDATE(tex_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Texture '%s' must have zero users to be removed, found %d",
- tex->id.name + 2, ID_REAL_USERS(tex));
- }
-}
static Brush *rna_Main_brushes_new(Main *bmain, const char *name, int mode)
{
@@ -502,50 +377,17 @@ static Brush *rna_Main_brushes_new(Main *bmain, const char *name, int mode)
return brush;
}
-static void rna_Main_brushes_remove(Main *bmain, ReportList *reports, PointerRNA *brush_ptr)
-{
- Brush *brush = brush_ptr->data;
- if (ID_REAL_USERS(brush) <= 0) {
- BKE_brush_unlink(bmain, brush);
- BKE_libblock_free(bmain, brush);
- RNA_POINTER_INVALIDATE(brush_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Brush '%s' must have zero users to be removed, found %d",
- brush->id.name + 2, ID_REAL_USERS(brush));
- }
-}
-
static World *rna_Main_worlds_new(Main *bmain, const char *name)
{
World *world = add_world(bmain, name);
id_us_min(&world->id);
return world;
}
-static void rna_Main_worlds_remove(Main *bmain, ReportList *reports, PointerRNA *world_ptr)
-{
- Group *world = world_ptr->data;
- if (ID_REAL_USERS(world) <= 0) {
- BKE_libblock_free(bmain, world);
- RNA_POINTER_INVALIDATE(world_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "World '%s' must have zero users to be removed, found %d",
- world->id.name + 2, ID_REAL_USERS(world));
- }
-}
static Group *rna_Main_groups_new(Main *bmain, const char *name)
{
return BKE_group_add(bmain, name);
}
-static void rna_Main_groups_remove(Main *bmain, PointerRNA *group_ptr)
-{
- Group *group = group_ptr->data;
- BKE_group_unlink(bmain, group);
- BKE_libblock_free(bmain, group);
- RNA_POINTER_INVALIDATE(group_ptr);
-}
static Speaker *rna_Main_speakers_new(Main *bmain, const char *name)
{
@@ -553,18 +395,6 @@ static Speaker *rna_Main_speakers_new(Main *bmain, const char *name)
id_us_min(&speaker->id);
return speaker;
}
-static void rna_Main_speakers_remove(Main *bmain, ReportList *reports, PointerRNA *speaker_ptr)
-{
- Speaker *speaker = speaker_ptr->data;
- if (ID_REAL_USERS(speaker) <= 0) {
- BKE_libblock_free(bmain, speaker);
- RNA_POINTER_INVALIDATE(speaker_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Speaker '%s' must have zero users to be removed, found %d",
- speaker->id.name + 2, ID_REAL_USERS(speaker));
- }
-}
static bSound *rna_Main_sounds_load(Main *bmain, const char *name, int check_existing)
{
@@ -580,30 +410,11 @@ static bSound *rna_Main_sounds_load(Main *bmain, const char *name, int check_exi
id_us_min(&sound->id);
return sound;
}
-static void rna_Main_sounds_remove(Main *bmain, ReportList *reports, PointerRNA *sound_ptr)
-{
- Speaker *sound = sound_ptr->data;
- if (ID_REAL_USERS(sound) <= 0) {
- BKE_libblock_free(bmain, sound);
- RNA_POINTER_INVALIDATE(sound_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Sound '%s' must have zero users to be removed, found %d",
- sound->id.name + 2, ID_REAL_USERS(sound));
- }
-}
static Text *rna_Main_texts_new(Main *bmain, const char *name)
{
return BKE_text_add(bmain, name);
}
-static void rna_Main_texts_remove(Main *bmain, PointerRNA *text_ptr)
-{
- Text *text = text_ptr->data;
- BKE_text_unlink(bmain, text);
- BKE_libblock_free(bmain, text);
- RNA_POINTER_INVALIDATE(text_ptr);
-}
static Text *rna_Main_texts_load(Main *bmain, ReportList *reports, const char *filepath, int is_internal)
{
@@ -625,18 +436,6 @@ static bArmature *rna_Main_armatures_new(Main *bmain, const char *name)
id_us_min(&arm->id);
return arm;
}
-static void rna_Main_armatures_remove(Main *bmain, ReportList *reports, PointerRNA *arm_ptr)
-{
- bArmature *arm = arm_ptr->data;
- if (ID_REAL_USERS(arm) <= 0) {
- BKE_libblock_free(bmain, arm);
- RNA_POINTER_INVALIDATE(arm_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Armature '%s' must have zero users to be removed, found %d",
- arm->id.name + 2, ID_REAL_USERS(arm));
- }
-}
static bAction *rna_Main_actions_new(Main *bmain, const char *name)
{
@@ -644,18 +443,6 @@ static bAction *rna_Main_actions_new(Main *bmain, const char *name)
id_fake_user_clear(&act->id);
return act;
}
-static void rna_Main_actions_remove(Main *bmain, ReportList *reports, PointerRNA *act_ptr)
-{
- bAction *act = act_ptr->data;
- if (ID_REAL_USERS(act) <= 0) {
- BKE_libblock_free(bmain, act);
- RNA_POINTER_INVALIDATE(act_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Action '%s' must have zero users to be removed, found %d",
- act->id.name + 2, ID_REAL_USERS(act));
- }
-}
static ParticleSettings *rna_Main_particles_new(Main *bmain, const char *name)
{
@@ -663,18 +450,6 @@ static ParticleSettings *rna_Main_particles_new(Main *bmain, const char *name)
id_us_min(&part->id);
return part;
}
-static void rna_Main_particles_remove(Main *bmain, ReportList *reports, PointerRNA *part_ptr)
-{
- ParticleSettings *part = part_ptr->data;
- if (ID_REAL_USERS(part) <= 0) {
- BKE_libblock_free(bmain, part);
- RNA_POINTER_INVALIDATE(part_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Particle settings '%s' must have zero users to be removed, found %d",
- part->id.name + 2, ID_REAL_USERS(part));
- }
-}
static Palette *rna_Main_palettes_new(Main *bmain, const char *name)
{
@@ -682,18 +457,6 @@ static Palette *rna_Main_palettes_new(Main *bmain, const char *name)
id_us_min(&palette->id);
return (Palette *)palette;
}
-static void rna_Main_palettes_remove(Main *bmain, ReportList *reports, PointerRNA *palette_ptr)
-{
- Palette *palette = palette_ptr->data;
- if (ID_REAL_USERS(palette) <= 0) {
- BKE_libblock_free(bmain, palette);
- RNA_POINTER_INVALIDATE(palette_ptr);
- }
- else {
- BKE_reportf(reports, RPT_ERROR, "Palette settings '%s' must have zero users to be removed, found %d",
- palette->id.name + 2, ID_REAL_USERS(palette));
- }
-}
static MovieClip *rna_Main_movieclip_load(Main *bmain, ReportList *reports, const char *filepath, int check_existing)
{
@@ -716,14 +479,6 @@ static MovieClip *rna_Main_movieclip_load(Main *bmain, ReportList *reports, cons
return clip;
}
-static void rna_Main_movieclips_remove(Main *bmain, PointerRNA *clip_ptr)
-{
- MovieClip *clip = clip_ptr->data;
- BKE_movieclip_unlink(bmain, clip);
- BKE_libblock_free(bmain, clip);
- RNA_POINTER_INVALIDATE(clip_ptr);
-}
-
static Mask *rna_Main_mask_new(Main *bmain, const char *name)
{
Mask *mask;
@@ -733,27 +488,6 @@ static Mask *rna_Main_mask_new(Main *bmain, const char *name)
return mask;
}
-static void rna_Main_masks_remove(Main *bmain, PointerRNA *mask_ptr)
-{
- Mask *mask = mask_ptr->data;
- BKE_mask_free(bmain, mask);
- BKE_libblock_free(bmain, mask);
- RNA_POINTER_INVALIDATE(mask_ptr);
-}
-
-static void rna_Main_grease_pencil_remove(Main *bmain, ReportList *reports, PointerRNA *gpd_ptr)
-{
- bGPdata *gpd = gpd_ptr->data;
- if (ID_REAL_USERS(gpd) <= 0) {
- BKE_gpencil_free(gpd);
- BKE_libblock_free(bmain, gpd);
- RNA_POINTER_INVALIDATE(gpd_ptr);
- }
- else
- BKE_reportf(reports, RPT_ERROR, "Grease pencil '%s' must have zero users to be removed, found %d",
- gpd->id.name + 2, ID_REAL_USERS(gpd));
-}
-
static FreestyleLineStyle *rna_Main_linestyles_new(Main *bmain, const char *name)
{
FreestyleLineStyle *linestyle = BKE_linestyle_new(bmain, name);
@@ -761,17 +495,6 @@ static FreestyleLineStyle *rna_Main_linestyles_new(Main *bmain, const char *name
return linestyle;
}
-static void rna_Main_linestyles_remove(Main *bmain, ReportList *reports, FreestyleLineStyle *linestyle)
-{
- if (ID_REAL_USERS(linestyle) <= 0)
- BKE_libblock_free(bmain, linestyle);
- else
- BKE_reportf(reports, RPT_ERROR, "Line style '%s' must have zero users to be removed, found %d",
- linestyle->id.name + 2, ID_REAL_USERS(linestyle));
-
- /* XXX python now has invalid pointer? */
-}
-
/* tag and is_updated functions, all the same */
#define RNA_MAIN_ID_TAG_FUNCS_DEF(_func_name, _listbase_name, _id_type) \
static void rna_Main_##_func_name##_tag(Main *bmain, int value) { \
@@ -812,6 +535,8 @@ RNA_MAIN_ID_TAG_FUNCS_DEF(gpencil, gpencil, ID_GD)
RNA_MAIN_ID_TAG_FUNCS_DEF(movieclips, movieclip, ID_MC)
RNA_MAIN_ID_TAG_FUNCS_DEF(masks, mask, ID_MSK)
RNA_MAIN_ID_TAG_FUNCS_DEF(linestyle, linestyle, ID_LS)
+RNA_MAIN_ID_TAG_FUNCS_DEF(cachefiles, cachefiles, ID_CF)
+RNA_MAIN_ID_TAG_FUNCS_DEF(paintcurves, paintcurves, ID_PC)
#undef RNA_MAIN_ID_TAG_FUNCS_DEF
@@ -854,12 +579,15 @@ void RNA_def_main_cameras(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "camera", "Camera", "", "New camera data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_cameras_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a camera from the current blendfile");
parm = RNA_def_pointer(func, "camera", "Camera", "", "Camera to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "",
+ "Unlink all usages of this camera before deleting it "
+ "(WARNING: will also delete objects instancing that camera data)");
func = RNA_def_function(srna, "tag", "rna_Main_cameras_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -896,6 +624,7 @@ void RNA_def_main_scenes(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this scene before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_scenes_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -930,12 +659,13 @@ void RNA_def_main_objects(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "object", "Object", "", "New object data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_objects_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_ui_description(func, "Remove a object from the current blendfile");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "object", "Object", "", "Object to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this object before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_objects_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -966,12 +696,13 @@ void RNA_def_main_materials(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "material", "Material", "", "New material data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_materials_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a material from the current blendfile");
parm = RNA_def_pointer(func, "material", "Material", "", "Material to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this material before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_materials_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1009,12 +740,13 @@ void RNA_def_main_node_groups(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "tree", "NodeTree", "", "New node tree data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_nodetree_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a node tree from the current blendfile");
parm = RNA_def_pointer(func, "tree", "NodeTree", "", "Node tree to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this node tree before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_node_groups_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1067,12 +799,15 @@ void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop)
"Mesh created from object, remove it if it is only used for export");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_meshes_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a mesh from the current blendfile");
parm = RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "",
+ "Unlink all usages of this mesh before deleting it "
+ "(WARNING: will also delete objects instancing that mesh data)");
func = RNA_def_function(srna, "tag", "rna_Main_meshes_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1104,12 +839,15 @@ void RNA_def_main_lamps(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "lamp", "Lamp", "", "New lamp data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_lamps_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a lamp from the current blendfile");
parm = RNA_def_pointer(func, "lamp", "Lamp", "", "Lamp to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "",
+ "Unlink all usages of this lamp before deleting it "
+ "(WARNING: will also delete objects instancing that lamp data)");
func = RNA_def_function(srna, "tag", "rna_Main_lamps_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1219,12 +957,13 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "image", "Image", "", "New image data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_images_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove an image from the current blendfile");
parm = RNA_def_pointer(func, "image", "Image", "", "Image to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this image before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_images_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1255,12 +994,15 @@ void RNA_def_main_lattices(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "lattice", "Lattice", "", "New lattices data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_lattices_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a lattice from the current blendfile");
parm = RNA_def_pointer(func, "lattice", "Lattice", "", "Lattice to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "",
+ "Unlink all usages of this lattice before deleting it "
+ "(WARNING: will also delete objects instancing that lattice data)");
func = RNA_def_function(srna, "tag", "rna_Main_lattices_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1292,12 +1034,15 @@ void RNA_def_main_curves(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "curve", "Curve", "", "New curve data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_curves_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a curve from the current blendfile");
parm = RNA_def_pointer(func, "curve", "Curve", "", "Curve to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "",
+ "Unlink all usages of this curve before deleting it "
+ "(WARNING: will also delete objects instancing that curve data)");
func = RNA_def_function(srna, "tag", "rna_Main_curves_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1327,12 +1072,15 @@ void RNA_def_main_metaballs(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "metaball", "MetaBall", "", "New metaball data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_metaballs_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a metaball from the current blendfile");
parm = RNA_def_pointer(func, "metaball", "MetaBall", "", "Metaball to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "",
+ "Unlink all usages of this metaball before deleting it "
+ "(WARNING: will also delete objects instancing that metaball data)");
func = RNA_def_function(srna, "tag", "rna_Main_metaballs_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1364,12 +1112,13 @@ void RNA_def_main_fonts(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "vfont", "VectorFont", "", "New font data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_fonts_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a font from the current blendfile");
parm = RNA_def_pointer(func, "vfont", "VectorFont", "", "Font to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this font before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_fonts_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1401,12 +1150,13 @@ void RNA_def_main_textures(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "texture", "Texture", "", "New texture data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_textures_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a texture from the current blendfile");
parm = RNA_def_pointer(func, "texture", "Texture", "", "Texture to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this texture before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_textures_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1437,12 +1187,13 @@ void RNA_def_main_brushes(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "brush", "Brush", "", "New brush data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_brushes_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a brush from the current blendfile");
parm = RNA_def_pointer(func, "brush", "Brush", "", "Brush to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this brush before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_brushes_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1473,12 +1224,13 @@ void RNA_def_main_worlds(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "world", "World", "", "New world data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_worlds_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a world from the current blendfile");
parm = RNA_def_pointer(func, "world", "World", "", "World to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this world before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_worlds_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1509,11 +1261,13 @@ void RNA_def_main_groups(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "group", "Group", "", "New group data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_groups_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_ui_description(func, "Remove a group from the current blendfile");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "group", "Group", "", "Group to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this group before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_groups_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1544,12 +1298,15 @@ void RNA_def_main_speakers(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "speaker", "Speaker", "", "New speaker data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_speakers_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a speaker from the current blendfile");
parm = RNA_def_pointer(func, "speaker", "Speaker", "", "Speaker to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "",
+ "Unlink all usages of this speaker before deleting it "
+ "(WARNING: will also delete objects instancing that speaker data)");
func = RNA_def_function(srna, "tag", "rna_Main_speakers_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1580,11 +1337,13 @@ void RNA_def_main_texts(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "text", "Text", "", "New text data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_texts_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_ui_description(func, "Remove a text from the current blendfile");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "text", "Text", "", "Text to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this text before deleting it");
/* load func */
func = RNA_def_function(srna, "load", "rna_Main_texts_load");
@@ -1628,12 +1387,13 @@ void RNA_def_main_sounds(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "sound", "Sound", "", "New text data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_sounds_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a sound from the current blendfile");
parm = RNA_def_pointer(func, "sound", "Sound", "", "Sound to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this sound before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_sounds_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1664,12 +1424,15 @@ void RNA_def_main_armatures(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "armature", "Armature", "", "New armature data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_armatures_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a armature from the current blendfile");
parm = RNA_def_pointer(func, "armature", "Armature", "", "Armature to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "",
+ "Unlink all usages of this armature before deleting it "
+ "(WARNING: will also delete objects instancing that armature data)");
func = RNA_def_function(srna, "tag", "rna_Main_armatures_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1699,12 +1462,13 @@ void RNA_def_main_actions(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "action", "Action", "", "New action data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_actions_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a action from the current blendfile");
parm = RNA_def_pointer(func, "action", "Action", "", "Action to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this action before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_actions_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1734,12 +1498,13 @@ void RNA_def_main_particles(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "particle", "ParticleSettings", "", "New particle settings data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_particles_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a particle settings instance from the current blendfile");
parm = RNA_def_pointer(func, "particle", "ParticleSettings", "", "Particle Settings to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of those particle settings before deleting them");
func = RNA_def_function(srna, "tag", "rna_Main_particles_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1769,12 +1534,13 @@ void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "palette", "Palette", "", "New palette data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_palettes_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a palette from the current blendfile");
parm = RNA_def_pointer(func, "palette", "Palette", "", "Palette to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this palette before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_palettes_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1784,6 +1550,36 @@ void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_funcs(prop, "rna_Main_palettes_is_updated_get", NULL);
}
+void RNA_def_main_cachefiles(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ RNA_def_property_srna(cprop, "BlendDataCacheFiles");
+ StructRNA *srna = RNA_def_struct(brna, "BlendDataCacheFiles", NULL);
+ RNA_def_struct_sdna(srna, "Main");
+ RNA_def_struct_ui_text(srna, "Main Cache Files", "Collection of cache files");
+
+ FunctionRNA *func = RNA_def_function(srna, "tag", "rna_Main_cachefiles_tag");
+ PropertyRNA *parm = RNA_def_boolean(func, "value", 0, "Value", "");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+
+ PropertyRNA *prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_boolean_funcs(prop, "rna_Main_cachefiles_is_updated_get", NULL);
+}
+void RNA_def_main_paintcurves(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ RNA_def_property_srna(cprop, "BlendDataPaintCurves");
+ StructRNA *srna = RNA_def_struct(brna, "BlendDataPaintCurves", NULL);
+ RNA_def_struct_sdna(srna, "Main");
+ RNA_def_struct_ui_text(srna, "Main Paint Curves", "Collection of paint curves");
+
+ FunctionRNA *func = RNA_def_function(srna, "tag", "rna_Main_paintcurves_tag");
+ PropertyRNA *parm = RNA_def_boolean(func, "value", 0, "Value", "");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+
+ PropertyRNA *prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_boolean_funcs(prop, "rna_Main_paintcurves_is_updated_get", NULL);
+}
void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
@@ -1800,7 +1596,7 @@ void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_property_flag(parm, PROP_REQUIRED);
- func = RNA_def_function(srna, "new", "gpencil_data_addnew");
+ func = RNA_def_function(srna, "new", "BKE_gpencil_data_addnew");
RNA_def_function_flag(func, FUNC_NO_SELF);
parm = RNA_def_string(func, "name", "GreasePencil", 0, "", "New name for the data-block");
RNA_def_property_flag(parm, PROP_REQUIRED);
@@ -1808,12 +1604,13 @@ void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "grease_pencil", "GreasePencil", "", "New grease pencil data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_grease_pencil_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a grease pencil instance from the current blendfile");
parm = RNA_def_pointer(func, "grease_pencil", "GreasePencil", "", "Grease Pencil to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this grease pencil before deleting it");
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1836,11 +1633,13 @@ void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_property_flag(parm, PROP_REQUIRED);
- func = RNA_def_function(srna, "remove", "rna_Main_movieclips_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a movie clip from the current blendfile.");
parm = RNA_def_pointer(func, "clip", "MovieClip", "", "Movie clip to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this movie clip before deleting it");
/* load func */
func = RNA_def_function(srna, "load", "rna_Main_movieclip_load");
@@ -1886,11 +1685,13 @@ void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_return(func, parm);
/* remove func */
- func = RNA_def_function(srna, "remove", "rna_Main_masks_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a masks from the current blendfile.");
parm = RNA_def_pointer(func, "mask", "Mask", "", "Mask to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this mask before deleting it");
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1921,11 +1722,13 @@ void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "linestyle", "FreestyleLineStyle", "", "New line style data-block");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_Main_linestyles_remove");
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a line style instance from the current blendfile");
parm = RNA_def_pointer(func, "linestyle", "FreestyleLineStyle", "", "Line style to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this line style before deleting it");
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
diff --git a/source/blender/makesrna/intern/rna_mask.c b/source/blender/makesrna/intern/rna_mask.c
index a23d4444861..faf36d28ff9 100644
--- a/source/blender/makesrna/intern/rna_mask.c
+++ b/source/blender/makesrna/intern/rna_mask.c
@@ -632,13 +632,13 @@ static void rna_def_maskParent(BlenderRNA *brna)
/* parent */
prop = RNA_def_property(srna, "parent", PROP_STRING, PROP_NONE);
- RNA_def_property_ui_text(prop, "Parent", "Name of parent object in specified data block to which parenting happens");
+ RNA_def_property_ui_text(prop, "Parent", "Name of parent object in specified data-block to which parenting happens");
RNA_def_property_string_maxlength(prop, MAX_ID_NAME - 2);
RNA_def_property_update(prop, 0, "rna_Mask_update_parent");
/* sub_parent */
prop = RNA_def_property(srna, "sub_parent", PROP_STRING, PROP_NONE);
- RNA_def_property_ui_text(prop, "Sub Parent", "Name of parent sub-object in specified data block to which parenting happens");
+ RNA_def_property_ui_text(prop, "Sub Parent", "Name of parent sub-object in specified data-block to which parenting happens");
RNA_def_property_string_maxlength(prop, MAX_ID_NAME - 2);
RNA_def_property_update(prop, 0, "rna_Mask_update_parent");
}
diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c
index e4f9f856db7..752f406264a 100644
--- a/source/blender/makesrna/intern/rna_material.c
+++ b/source/blender/makesrna/intern/rna_material.c
@@ -233,7 +233,7 @@ static void rna_Material_active_texture_set(PointerRNA *ptr, PointerRNA value)
set_current_material_texture(ma, value.data);
}
-static int rna_Material_active_texture_editable(PointerRNA *ptr)
+static int rna_Material_active_texture_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
Material *ma = (Material *)ptr->id.data;
@@ -1889,7 +1889,7 @@ void RNA_def_material(BlenderRNA *brna)
prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "index");
- RNA_def_property_ui_text(prop, "Pass Index", "Index number for the IndexMA render pass");
+ RNA_def_property_ui_text(prop, "Pass Index", "Index number for the \"Material Index\" render pass");
RNA_def_property_update(prop, NC_OBJECT, "rna_Material_update");
/* flags */
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index 1d734864833..7c66f43fe00 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -662,7 +662,7 @@ static void rna_MeshLoopColor_color_set(PointerRNA *ptr, const float *values)
(&mcol->r)[2] = (char)(CLAMPIS(values[2] * 255.0f, 0, 255));
}
-static int rna_Mesh_texspace_editable(PointerRNA *ptr)
+static int rna_Mesh_texspace_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
Mesh *me = (Mesh *)ptr->data;
return (me->texflag & ME_AUTOSPACE) ? 0 : PROP_EDITABLE;
@@ -3200,9 +3200,9 @@ static void rna_def_skin_vertices(BlenderRNA *brna, PropertyRNA *UNUSED(cprop))
RNA_def_struct_ui_text(srna, "Skin Vertex", "Per-vertex skin data for use with the Skin modifier");
RNA_def_struct_path_func(srna, "rna_MeshSkinVertex_path");
- prop = RNA_def_property(srna, "radius", PROP_FLOAT, PROP_NONE);
+ prop = RNA_def_property(srna, "radius", PROP_FLOAT, PROP_UNSIGNED);
RNA_def_property_array(prop, 2);
- RNA_def_property_ui_range(prop, 0.001, 100, 1, 3);
+ RNA_def_property_ui_range(prop, 0.001, 100.0, 1, 3);
RNA_def_property_ui_text(prop, "Radius", "Radius of the skin");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
diff --git a/source/blender/makesrna/intern/rna_meta.c b/source/blender/makesrna/intern/rna_meta.c
index d3b66e4c3b4..9d13bc90e72 100644
--- a/source/blender/makesrna/intern/rna_meta.c
+++ b/source/blender/makesrna/intern/rna_meta.c
@@ -53,7 +53,7 @@
#include "WM_types.h"
#include "WM_api.h"
-static int rna_Meta_texspace_editable(PointerRNA *ptr)
+static int rna_Meta_texspace_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
MetaBall *mb = (MetaBall *)ptr->data;
return (mb->texflag & MB_AUTOSPACE) ? 0 : PROP_EDITABLE;
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 0c4b3ba485d..c4f0db38a16 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -30,6 +30,7 @@
#include <stdlib.h>
#include "DNA_armature_types.h"
+#include "DNA_cachefile_types.h"
#include "DNA_mesh_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
@@ -65,6 +66,7 @@ EnumPropertyItem rna_enum_object_modifier_type_items[] = {
{0, "", 0, N_("Modify"), ""},
{eModifierType_DataTransfer, "DATA_TRANSFER", ICON_MOD_DATA_TRANSFER, "Data Transfer", ""},
{eModifierType_MeshCache, "MESH_CACHE", ICON_MOD_MESHDEFORM, "Mesh Cache", ""},
+ {eModifierType_MeshSequenceCache, "MESH_SEQUENCE_CACHE", ICON_MOD_MESHDEFORM, "Mesh Sequence Cache", ""},
{eModifierType_NormalEdit, "NORMAL_EDIT", ICON_MOD_NORMALEDIT, "Normal Edit", ""},
{eModifierType_UVProject, "UV_PROJECT", ICON_MOD_UVPROJECT, "UV Project", ""},
{eModifierType_UVWarp, "UV_WARP", ICON_MOD_UVPROJECT, "UV Warp", ""},
@@ -281,6 +283,7 @@ EnumPropertyItem rna_enum_axis_flag_xyz_items[] = {
#include "DNA_curve_types.h"
#include "DNA_smoke_types.h"
+#include "BKE_cachefile.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_library.h"
@@ -288,6 +291,10 @@ EnumPropertyItem rna_enum_axis_flag_xyz_items[] = {
#include "BKE_object.h"
#include "BKE_particle.h"
+#ifdef WITH_ALEMBIC
+# include "ABC_alembic.h"
+#endif
+
static void rna_UVProject_projectors_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
UVProjectModifierData *uvp = (UVProjectModifierData *)ptr->data;
@@ -399,6 +406,8 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr)
return &RNA_NormalEditModifier;
case eModifierType_CorrectiveSmooth:
return &RNA_CorrectiveSmoothModifier;
+ case eModifierType_MeshSequenceCache:
+ return &RNA_MeshSequenceCacheModifier;
/* Default */
case eModifierType_None:
case eModifierType_ShapeKey:
@@ -923,17 +932,18 @@ static EnumPropertyItem *rna_DataTransferModifier_layers_select_src_itemf(bConte
CustomData *pdata;
int num_data, i;
- /* XXX Is this OK? */
- dm_src = mesh_get_derived_final(dtmd->modifier.scene, ob_src, CD_MASK_BAREMESH | CD_MTEXPOLY);
- pdata = dm_src->getPolyDataLayout(dm_src);
- num_data = CustomData_number_of_layers(pdata, CD_MTEXPOLY);
+ dm_src = object_get_derived_final(ob_src, false);
+ if (dm_src != NULL) {
+ pdata = dm_src->getPolyDataLayout(dm_src);
+ num_data = CustomData_number_of_layers(pdata, CD_MTEXPOLY);
- RNA_enum_item_add_separator(&item, &totitem);
+ RNA_enum_item_add_separator(&item, &totitem);
- for (i = 0; i < num_data; i++) {
- tmp_item.value = i;
- tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(pdata, CD_MTEXPOLY, i);
- RNA_enum_item_add(&item, &totitem, &tmp_item);
+ for (i = 0; i < num_data; i++) {
+ tmp_item.value = i;
+ tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(pdata, CD_MTEXPOLY, i);
+ RNA_enum_item_add(&item, &totitem, &tmp_item);
+ }
}
}
}
@@ -945,17 +955,18 @@ static EnumPropertyItem *rna_DataTransferModifier_layers_select_src_itemf(bConte
CustomData *ldata;
int num_data, i;
- /* XXX Is this OK? */
- dm_src = mesh_get_derived_final(dtmd->modifier.scene, ob_src, CD_MASK_BAREMESH | CD_MLOOPCOL);
- ldata = dm_src->getLoopDataLayout(dm_src);
- num_data = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
+ dm_src = object_get_derived_final(ob_src, false);
+ if (dm_src != NULL) {
+ ldata = dm_src->getLoopDataLayout(dm_src);
+ num_data = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
- RNA_enum_item_add_separator(&item, &totitem);
+ RNA_enum_item_add_separator(&item, &totitem);
- for (i = 0; i < num_data; i++) {
- tmp_item.value = i;
- tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(ldata, CD_MLOOPCOL, i);
- RNA_enum_item_add(&item, &totitem, &tmp_item);
+ for (i = 0; i < num_data; i++) {
+ tmp_item.value = i;
+ tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(ldata, CD_MLOOPCOL, i);
+ RNA_enum_item_add(&item, &totitem, &tmp_item);
+ }
}
}
}
@@ -1120,6 +1131,21 @@ static int rna_CorrectiveSmoothModifier_is_bind_get(PointerRNA *ptr)
return (csmd->bind_coords != NULL);
}
+static void rna_MeshSequenceCache_object_path_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+#ifdef WITH_ALEMBIC
+ MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)ptr->data;
+ Object *ob = (Object *)ptr->id.data;
+
+ mcmd->reader = CacheReader_open_alembic_object(mcmd->cache_file->handle,
+ mcmd->reader,
+ ob,
+ mcmd->object_path);
+#endif
+
+ rna_Modifier_update(bmain, scene, ptr);
+}
+
#else
static PropertyRNA *rna_def_property_subdivision_common(StructRNA *srna, const char type[])
@@ -1514,6 +1540,8 @@ static void rna_def_modifier_decimate(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ /* Note, keep in sync with operator 'MESH_OT_decimate' */
+
StructRNA *srna;
PropertyRNA *prop;
@@ -1826,6 +1854,12 @@ static void rna_def_modifier_hook(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Hook Center", "");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_property(srna, "matrix_inverse", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_property_float_sdna(prop, NULL, "parentinv");
+ RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
+ RNA_def_property_ui_text(prop, "Matrix", "Reverse the transformation between this object and its target");
+ RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Modifier_update");
+
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
RNA_def_property_ui_text(prop, "Object", "Parent Object for hook, also recalculates and clears offset");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
@@ -1887,6 +1921,12 @@ static void rna_def_modifier_boolean(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem prop_solver_items[] = {
+ {eBooleanModifierSolver_BMesh, "BMESH", 0, "BMesh", "Use the BMesh boolean solver"},
+ {eBooleanModifierSolver_Carve, "CARVE", 0, "Carve", "Use the Carve boolean solver"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
srna = RNA_def_struct(brna, "BooleanModifier", "Modifier");
RNA_def_struct_ui_text(srna, "Boolean Modifier", "Boolean operations modifier");
RNA_def_struct_sdna(srna, "BooleanModifierData");
@@ -1903,35 +1943,17 @@ static void rna_def_modifier_boolean(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Operation", "");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
-#if 0 /* WITH_MOD_BOOLEAN */
- /* BMesh intersection options */
- prop = RNA_def_property(srna, "use_bmesh", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "bm_flag", eBooleanModifierBMeshFlag_Enabled);
- RNA_def_property_ui_text(prop, "Use BMesh", "Use BMesh boolean calculation");
- RNA_def_property_update(prop, 0, "rna_Modifier_update");
-
- prop = RNA_def_property(srna, "use_bmesh_separate", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "bm_flag", eBooleanModifierBMeshFlag_BMesh_Separate);
- RNA_def_property_ui_text(prop, "Separate", "Keep edges separate");
- RNA_def_property_update(prop, 0, "rna_Modifier_update");
-
- prop = RNA_def_property(srna, "use_bmesh_dissolve", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "bm_flag", eBooleanModifierBMeshFlag_BMesh_NoDissolve);
- RNA_def_property_ui_text(prop, "Dissolve", "Dissolve verts created from tessellated intersection");
+ prop = RNA_def_property(srna, "solver", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, prop_solver_items);
+ RNA_def_property_ui_text(prop, "Solver", "");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
- prop = RNA_def_property(srna, "use_bmesh_connect_regions", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "bm_flag", eBooleanModifierBMeshFlag_BMesh_NoConnectRegions);
- RNA_def_property_ui_text(prop, "Calculate Holes", "Connect regions (needed for hole filling)");
- RNA_def_property_update(prop, 0, "rna_Modifier_update");
-
- prop = RNA_def_property(srna, "threshold", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_sdna(prop, NULL, "threshold");
+ prop = RNA_def_property(srna, "double_threshold", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "double_threshold");
RNA_def_property_range(prop, 0, 1.0f);
- RNA_def_property_ui_range(prop, 0, 1, 1, 7);
- RNA_def_property_ui_text(prop, "Threshold", "");
+ RNA_def_property_ui_range(prop, 0, 1, 0.0001, 7);
+ RNA_def_property_ui_text(prop, "Overlap Threshold", "Threshold for checking overlapping geometry");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
-#endif
}
static void rna_def_modifier_array(BlenderRNA *brna)
@@ -2093,6 +2115,12 @@ static void rna_def_modifier_displace(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem prop_space_items[] = {
+ {MOD_DISP_SPACE_LOCAL, "LOCAL", 0, "Local", "Direction is defined in local coordinates"},
+ {MOD_DISP_SPACE_GLOBAL, "GLOBAL", 0, "Global", "Direction is defined in global coordinates"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
srna = RNA_def_struct(brna, "DisplaceModifier", "Modifier");
RNA_def_struct_ui_text(srna, "Displace Modifier", "Displacement modifier");
RNA_def_struct_sdna(srna, "DisplaceModifierData");
@@ -2123,6 +2151,11 @@ static void rna_def_modifier_displace(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Direction", "");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_property(srna, "space", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, prop_space_items);
+ RNA_def_property_ui_text(prop, "Space", "");
+ RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
+
rna_def_modifier_generic_map_info(srna);
}
@@ -4220,6 +4253,42 @@ static void rna_def_modifier_meshcache(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
+static void rna_def_modifier_meshseqcache(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "MeshSequenceCacheModifier", "Modifier");
+ RNA_def_struct_ui_text(srna, "Cache Modifier", "Cache Mesh");
+ RNA_def_struct_sdna(srna, "MeshSeqCacheModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_MESHDEFORM); /* XXX, needs own icon */
+
+ prop = RNA_def_property(srna, "cache_file", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "cache_file");
+ RNA_def_property_struct_type(prop, "CacheFile");
+ RNA_def_property_ui_text(prop, "Cache File", "");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
+
+ prop = RNA_def_property(srna, "object_path", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Object Path", "Path to the object in the Alembic archive used to lookup geometric data");
+ RNA_def_property_update(prop, 0, "rna_MeshSequenceCache_object_path_update");
+
+ static EnumPropertyItem read_flag_items[] = {
+ {MOD_MESHSEQ_READ_VERT, "VERT", 0, "Vertex", ""},
+ {MOD_MESHSEQ_READ_POLY, "POLY", 0, "Faces", ""},
+ {MOD_MESHSEQ_READ_UV, "UV", 0, "UV", ""},
+ {MOD_MESHSEQ_READ_COLOR, "COLOR", 0, "Color", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ prop = RNA_def_property(srna, "read_data", PROP_ENUM, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_ENUM_FLAG);
+ RNA_def_property_enum_sdna(prop, NULL, "read_flag");
+ RNA_def_property_enum_items(prop, read_flag_items);
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+}
+
static void rna_def_modifier_laplaciandeform(BlenderRNA *brna)
{
StructRNA *srna;
@@ -4602,6 +4671,11 @@ static void rna_def_modifier_normaledit(BlenderRNA *brna)
"How much of generated normals to mix with exiting ones", 0.0f, 1.0f);
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_float(srna, "mix_limit", 1.0f, 0.0f, DEG2RADF(180.0f), "Max Angle",
+ "Maximum angle between old and new normals", 0.0f, DEG2RADF(180.0f));
+ RNA_def_property_subtype(prop, PROP_ANGLE);
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "defgrp_name");
RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for selecting/weighting the affected areas");
@@ -4744,6 +4818,7 @@ void RNA_def_modifier(BlenderRNA *brna)
rna_def_modifier_wireframe(brna);
rna_def_modifier_datatransfer(brna);
rna_def_modifier_normaledit(brna);
+ rna_def_modifier_meshseqcache(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_movieclip.c b/source/blender/makesrna/intern/rna_movieclip.c
index 19d78361019..15411f85ba3 100644
--- a/source/blender/makesrna/intern/rna_movieclip.c
+++ b/source/blender/makesrna/intern/rna_movieclip.c
@@ -347,6 +347,8 @@ static void rna_def_movieclip(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "colorspace_settings");
RNA_def_property_struct_type(prop, "ColorManagedInputColorspaceSettings");
RNA_def_property_ui_text(prop, "Color Space Settings", "Input color space settings");
+
+ rna_def_animdata_common(srna);
}
void RNA_def_movieclip(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_nla.c b/source/blender/makesrna/intern/rna_nla.c
index eb87eafe16c..55bc40f573c 100644
--- a/source/blender/makesrna/intern/rna_nla.c
+++ b/source/blender/makesrna/intern/rna_nla.c
@@ -282,7 +282,7 @@ static void rna_NlaStrip_use_auto_blend_set(PointerRNA *ptr, int value)
}
}
-static int rna_NlaStrip_action_editable(PointerRNA *ptr)
+static int rna_NlaStrip_action_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
NlaStrip *strip = (NlaStrip *)ptr->data;
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 9f32184f35c..c6379bc4381 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -803,6 +803,7 @@ static bNodeLink *rna_NodeTree_link_new(bNodeTree *ntree, ReportList *reports,
ntreeUpdateTree(G.main, ntree);
+ ED_node_tag_update_nodetree(G.main, ntree, ret->tonode);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
return ret;
@@ -2605,6 +2606,10 @@ static void rna_Node_image_layer_update(Main *bmain, Scene *scene, PointerRNA *p
BKE_image_signal(ima, iuser, IMA_SIGNAL_SRC_CHANGE);
rna_Node_update(bmain, scene, ptr);
+
+ if (scene->nodetree != NULL) {
+ ntreeCompositForceHidden(scene->nodetree);
+ }
}
static EnumPropertyItem *renderresult_layers_add_enum(RenderLayer *rl)
@@ -2738,6 +2743,14 @@ static EnumPropertyItem *rna_Node_scene_layer_itemf(bContext *UNUSED(C), Pointer
return item;
}
+static void rna_Node_scene_layer_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ rna_Node_update(bmain, scene, ptr);
+ if (scene->nodetree != NULL) {
+ ntreeCompositForceHidden(scene->nodetree);
+ }
+}
+
static EnumPropertyItem *rna_Node_channel_itemf(bContext *UNUSED(C), PointerRNA *ptr,
PropertyRNA *UNUSED(prop), bool *r_free)
{
@@ -3204,12 +3217,14 @@ static EnumPropertyItem node_glossy_items[] = {
{SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""},
{SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""},
{SHD_GLOSSY_ASHIKHMIN_SHIRLEY, "ASHIKHMIN_SHIRLEY", 0, "Ashikhmin-Shirley", ""},
+ {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""},
{0, NULL, 0, NULL, NULL}
};
static EnumPropertyItem node_anisotropic_items[] = {
{SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""},
{SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""},
+ {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""},
{SHD_GLOSSY_ASHIKHMIN_SHIRLEY, "ASHIKHMIN_SHIRLEY", 0, "Ashikhmin-Shirley", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -3218,6 +3233,14 @@ static EnumPropertyItem node_glass_items[] = {
{SHD_GLOSSY_SHARP, "SHARP", 0, "Sharp", ""},
{SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""},
{SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""},
+ {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static EnumPropertyItem node_refraction_items[] = {
+ {SHD_GLOSSY_SHARP, "SHARP", 0, "Sharp", ""},
+ {SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""},
+ {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -4170,6 +4193,17 @@ static void def_glass(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_refraction(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, node_refraction_items);
+ RNA_def_property_ui_text(prop, "Distribution", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
static void def_anisotropic(StructRNA *srna)
{
PropertyRNA *prop;
@@ -4811,7 +4845,7 @@ static void def_cmp_render_layers(StructRNA *srna)
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_Node_scene_layer_itemf");
RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
RNA_def_property_ui_text(prop, "Layer", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_scene_layer_update");
}
static void rna_def_cmp_output_file_slot_file(BlenderRNA *brna)
@@ -5406,13 +5440,13 @@ static void def_cmp_double_edge_mask(StructRNA *srna)
};
prop = RNA_def_property(srna, "inner_mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "custom2");
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, InnerEdgeMode_items);
RNA_def_property_ui_text(prop, "Inner Edge Mode", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "edge_mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_sdna(prop, NULL, "custom2");
RNA_def_property_enum_items(prop, BufEdgeMode_items);
RNA_def_property_ui_text(prop, "Buffer Edge Mode", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
@@ -6713,7 +6747,8 @@ static void def_cmp_translate(StructRNA *srna)
prop = RNA_def_property(srna, "use_relative", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "relative", 1);
- RNA_def_property_ui_text(prop, "Relative", "Use relative (percent) values to define blur radius");
+ RNA_def_property_ui_text(prop, "Relative",
+ "Use relative (fraction of input image size) values to define translation");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "wrap_axis", PROP_ENUM, PROP_NONE);
@@ -8231,9 +8266,9 @@ static void rna_def_nodetree(BlenderRNA *brna)
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
parm = RNA_def_pointer(func, "result_1", "NodeTree", "Node Tree", "Active node tree from context");
RNA_def_function_output(func, parm);
- parm = RNA_def_pointer(func, "result_2", "ID", "Owner ID", "ID data block that owns the node tree");
+ parm = RNA_def_pointer(func, "result_2", "ID", "Owner ID", "ID data-block that owns the node tree");
RNA_def_function_output(func, parm);
- parm = RNA_def_pointer(func, "result_3", "ID", "From ID", "Original ID data block selected from the context");
+ parm = RNA_def_pointer(func, "result_3", "ID", "From ID", "Original ID data-block selected from the context");
RNA_def_function_output(func, parm);
}
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 9ebef9db454..0e735350e05 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -398,7 +398,7 @@ static void rna_Object_data_set(PointerRNA *ptr, PointerRNA value)
id_us_plus(id);
ob->data = id;
- test_object_materials(G.main, id);
+ test_object_materials(ob, id);
if (GS(id->name) == ID_CU)
BKE_curve_type_test(ob);
@@ -712,16 +712,16 @@ static void rna_Object_active_material_set(PointerRNA *ptr, PointerRNA value)
assign_material(ob, value.data, ob->actcol, BKE_MAT_ASSIGN_EXISTING);
}
-static int rna_Object_active_material_editable(PointerRNA *ptr)
+static int rna_Object_active_material_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
Object *ob = (Object *)ptr->id.data;
bool is_editable;
if ((ob->matbits == NULL) || (ob->actcol == 0) || ob->matbits[ob->actcol - 1]) {
- is_editable = (ob->id.lib == NULL);
+ is_editable = !ID_IS_LINKED_DATABLOCK(ob);
}
else {
- is_editable = ob->data ? (((ID *)ob->data)->lib == NULL) : false;
+ is_editable = ob->data ? !ID_IS_LINKED_DATABLOCK(ob->data) : false;
}
return is_editable ? PROP_EDITABLE : 0;
@@ -1033,7 +1033,7 @@ static void rna_GameObjectSettings_physics_type_set(PointerRNA *ptr, int value)
ob->gameflag &= ~(OB_SENSOR | OB_OCCLUDER | OB_DYNAMIC | OB_RIGID_BODY | OB_SOFT_BODY | OB_ACTOR |
OB_ANISOTROPIC_FRICTION | OB_DO_FH | OB_ROT_FH | OB_COLLISION_RESPONSE | OB_NAVMESH);
/* When we switch to character physics and the collision bounds is set to triangle mesh
- we have to change collision bounds because triangle mesh is not supported by Characters*/
+ * we have to change collision bounds because triangle mesh is not supported by Characters */
if ((ob->gameflag & OB_BOUNDS) && ob->collision_boundtype == OB_BOUND_TRIANGLE_MESH) {
ob->boundtype = ob->collision_boundtype = OB_BOUND_BOX;
}
@@ -2387,6 +2387,8 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "dimensions", PROP_FLOAT, PROP_XYZ_LENGTH);
RNA_def_property_array(prop, 3);
+ /* only for the transform-panel and conflicts with animating scale */
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_float_funcs(prop, "rna_Object_dimensions_get", "rna_Object_dimensions_set", NULL);
RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, 3);
RNA_def_property_ui_text(prop, "Dimensions", "Absolute bounding box dimensions of the object");
@@ -2557,7 +2559,7 @@ static void rna_def_object(BlenderRNA *brna)
/* render */
prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "index");
- RNA_def_property_ui_text(prop, "Pass Index", "Index number for the IndexOB render pass");
+ RNA_def_property_ui_text(prop, "Pass Index", "Index number for the \"Object Index\" render pass");
RNA_def_property_update(prop, NC_OBJECT, "rna_Object_internal_update");
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR);
diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c
index 7cc69831dce..b66556109e6 100644
--- a/source/blender/makesrna/intern/rna_object_api.c
+++ b/source/blender/makesrna/intern/rna_object_api.c
@@ -698,7 +698,7 @@ void RNA_api_object(StructRNA *srna)
#endif /* NDEBUG */
func = RNA_def_function(srna, "update_from_editmode", "rna_Object_update_from_editmode");
- RNA_def_function_ui_description(func, "Load the objects edit-mode data intp the object data");
+ RNA_def_function_ui_description(func, "Load the objects edit-mode data into the object data");
parm = RNA_def_boolean(func, "result", 0, "", "Success");
RNA_def_function_return(func, parm);
diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c
index ed765f1b5c6..1d89f7535c4 100644
--- a/source/blender/makesrna/intern/rna_object_force.c
+++ b/source/blender/makesrna/intern/rna_object_force.c
@@ -199,6 +199,8 @@ static void rna_Cache_idname_change(Main *UNUSED(bmain), Scene *UNUSED(scene), P
}
if (use_new_name) {
+ BLI_filename_make_safe(cache->name);
+
if (pid2 && cache->flag & PTCACHE_DISK_CACHE) {
char old_name[80];
char new_name[80];
@@ -728,6 +730,11 @@ static void rna_softbody_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Point
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ob);
}
+static void rna_softbody_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ DAG_relations_tag_update(bmain);
+ rna_softbody_update(bmain, scene, ptr);
+}
static EnumPropertyItem *rna_Effector_shape_itemf(bContext *UNUSED(C), PointerRNA *ptr,
PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
@@ -1376,7 +1383,7 @@ static void rna_def_field(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_absorption", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PFIELD_VISIBILITY);
RNA_def_property_ui_text(prop, "Absorption", "Force gets absorbed by collision objects");
- RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
+ RNA_def_property_update(prop, 0, "rna_FieldSettings_dependency_update");
prop = RNA_def_property(srna, "use_multiple_springs", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PFIELD_MULTIPLE_SPRINGS);
@@ -1850,6 +1857,11 @@ static void rna_def_softbody(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Self Collision", "Enable naive vertex ball self collision");
RNA_def_property_update(prop, 0, "rna_softbody_update");
+ prop = RNA_def_property(srna, "collision_group", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Collision Group", "Limit colliders to this Group");
+ RNA_def_property_update(prop, 0, "rna_softbody_dependency_update");
+
prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "effector_weights");
RNA_def_property_struct_type(prop, "EffectorWeights");
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index 3f401a29945..5e3fa4b467d 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -341,7 +341,7 @@ static void rna_ParticleSystem_co_hair(ParticleSystem *particlesystem, Object *o
totchild = (int)((float)particlesystem->totchild * (float)(part->disp) / 100.0f);
}
- if (part == NULL || pars == NULL || !psys_check_enabled(object, particlesystem))
+ if (part == NULL || pars == NULL || !psys_check_enabled(object, particlesystem, particlesystem->renderdata != NULL))
return;
if (part->ren_as == PART_DRAW_OB || part->ren_as == PART_DRAW_GR || part->ren_as == PART_DRAW_NOT)
@@ -586,7 +586,7 @@ static void rna_ParticleSystem_set_resolution(ParticleSystem *particlesystem, Sc
psys_render_set(object, particlesystem, mat, mat, 1, 1, 0.f);
psmd->flag &= ~eParticleSystemFlag_psys_updated;
- particle_system_update(scene, object, particlesystem);
+ particle_system_update(scene, object, particlesystem, true);
}
else {
ParticleSystemModifierData *psmd = psys_get_modifier(object, particlesystem);
@@ -596,7 +596,7 @@ static void rna_ParticleSystem_set_resolution(ParticleSystem *particlesystem, Sc
}
psmd->flag &= ~eParticleSystemFlag_psys_updated;
- particle_system_update(scene, object, particlesystem);
+ particle_system_update(scene, object, particlesystem, false);
}
}
@@ -630,6 +630,12 @@ static void rna_Particle_reset(Main *bmain, Scene *scene, PointerRNA *ptr)
particle_recalc(bmain, scene, ptr, PSYS_RECALC_RESET);
}
+static void rna_Particle_reset_dependency(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ DAG_relations_tag_update(bmain);
+ rna_Particle_reset(bmain, scene, ptr);
+}
+
static void rna_Particle_change_type(Main *bmain, Scene *scene, PointerRNA *ptr)
{
particle_recalc(bmain, scene, ptr, PSYS_RECALC_RESET | PSYS_RECALC_TYPE);
@@ -2635,35 +2641,35 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "normfac"); /*optional if prop names are the same */
RNA_def_property_range(prop, -1000.0f, 1000.0f);
RNA_def_property_ui_range(prop, 0, 100, 1, 3);
- RNA_def_property_ui_text(prop, "Normal", "Let the surface normal give the particle a starting speed");
+ RNA_def_property_ui_text(prop, "Normal", "Let the surface normal give the particle a starting velocity");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
prop = RNA_def_property(srna, "object_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "obfac");
RNA_def_property_range(prop, -200.0f, 200.0f);
RNA_def_property_ui_range(prop, -1.0f, 1.0f, 0.1, 3);
- RNA_def_property_ui_text(prop, "Object", "Let the object give the particle a starting speed");
+ RNA_def_property_ui_text(prop, "Object", "Let the object give the particle a starting velocity");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
prop = RNA_def_property(srna, "factor_random", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "randfac"); /*optional if prop names are the same */
RNA_def_property_range(prop, 0.0f, 200.0f);
RNA_def_property_ui_range(prop, 0, 100, 1, 3);
- RNA_def_property_ui_text(prop, "Random", "Give the starting speed a random variation");
+ RNA_def_property_ui_text(prop, "Random", "Give the starting velocity a random variation");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
prop = RNA_def_property(srna, "particle_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "partfac");
RNA_def_property_range(prop, -200.0f, 200.0f);
RNA_def_property_ui_range(prop, -1.0f, 1.0f, 0.1, 3);
- RNA_def_property_ui_text(prop, "Particle", "Let the target particle give the particle a starting speed");
+ RNA_def_property_ui_text(prop, "Particle", "Let the target particle give the particle a starting velocity");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
prop = RNA_def_property(srna, "tangent_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "tanfac");
RNA_def_property_range(prop, -1000.0f, 1000.0f);
RNA_def_property_ui_range(prop, -100, 100, 1, 2);
- RNA_def_property_ui_text(prop, "Tangent", "Let the surface tangent give the particle a starting speed");
+ RNA_def_property_ui_text(prop, "Tangent", "Let the surface tangent give the particle a starting velocity");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
prop = RNA_def_property(srna, "tangent_phase", PROP_FLOAT, PROP_NONE);
@@ -2677,7 +2683,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_range(prop, -10.0f, 10.0f);
RNA_def_property_ui_text(prop, "Reactor",
"Let the vector away from the target particle's location give the particle "
- "a starting speed");
+ "a starting velocity");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
prop = RNA_def_property(srna, "object_align_factor", PROP_FLOAT, PROP_VELOCITY);
@@ -2686,7 +2692,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_range(prop, -200.0f, 200.0f);
RNA_def_property_ui_range(prop, -100, 100, 1, 3);
RNA_def_property_ui_text(prop, "Object Aligned",
- "Let the emitter object orientation give the particle a starting speed");
+ "Let the emitter object orientation give the particle a starting velocity");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
prop = RNA_def_property(srna, "angular_velocity_factor", PROP_FLOAT, PROP_NONE);
@@ -2741,6 +2747,10 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Random Size", "Give the particle size a random variation");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
+ prop = RNA_def_property(srna, "collision_group", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Collision Group", "Limit colliders to this Group");
+ RNA_def_property_update(prop, 0, "rna_Particle_reset_dependency");
/* global physical properties */
prop = RNA_def_property(srna, "drag_factor", PROP_FLOAT, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index 5bbc2b49a0d..0591e877634 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -43,6 +43,8 @@
#include "BLT_translation.h"
+#include "UI_resources.h"
+
#include "WM_types.h"
@@ -65,26 +67,26 @@ EnumPropertyItem rna_enum_posebone_rotmode_items[] = {
/* Bone and Group Color Sets */
EnumPropertyItem rna_enum_color_sets_items[] = {
{0, "DEFAULT", 0, "Default Colors", ""},
- {1, "THEME01", 0, "01 - Theme Color Set", ""},
- {2, "THEME02", 0, "02 - Theme Color Set", ""},
- {3, "THEME03", 0, "03 - Theme Color Set", ""},
- {4, "THEME04", 0, "04 - Theme Color Set", ""},
- {5, "THEME05", 0, "05 - Theme Color Set", ""},
- {6, "THEME06", 0, "06 - Theme Color Set", ""},
- {7, "THEME07", 0, "07 - Theme Color Set", ""},
- {8, "THEME08", 0, "08 - Theme Color Set", ""},
- {9, "THEME09", 0, "09 - Theme Color Set", ""},
- {10, "THEME10", 0, "10 - Theme Color Set", ""},
- {11, "THEME11", 0, "11 - Theme Color Set", ""},
- {12, "THEME12", 0, "12 - Theme Color Set", ""},
- {13, "THEME13", 0, "13 - Theme Color Set", ""},
- {14, "THEME14", 0, "14 - Theme Color Set", ""},
- {15, "THEME15", 0, "15 - Theme Color Set", ""},
- {16, "THEME16", 0, "16 - Theme Color Set", ""},
- {17, "THEME17", 0, "17 - Theme Color Set", ""},
- {18, "THEME18", 0, "18 - Theme Color Set", ""},
- {19, "THEME19", 0, "19 - Theme Color Set", ""},
- {20, "THEME20", 0, "20 - Theme Color Set", ""},
+ {1, "THEME01", VICO_COLORSET_01_VEC, "01 - Theme Color Set", ""},
+ {2, "THEME02", VICO_COLORSET_02_VEC, "02 - Theme Color Set", ""},
+ {3, "THEME03", VICO_COLORSET_03_VEC, "03 - Theme Color Set", ""},
+ {4, "THEME04", VICO_COLORSET_04_VEC, "04 - Theme Color Set", ""},
+ {5, "THEME05", VICO_COLORSET_05_VEC, "05 - Theme Color Set", ""},
+ {6, "THEME06", VICO_COLORSET_06_VEC, "06 - Theme Color Set", ""},
+ {7, "THEME07", VICO_COLORSET_07_VEC, "07 - Theme Color Set", ""},
+ {8, "THEME08", VICO_COLORSET_08_VEC, "08 - Theme Color Set", ""},
+ {9, "THEME09", VICO_COLORSET_09_VEC, "09 - Theme Color Set", ""},
+ {10, "THEME10", VICO_COLORSET_10_VEC, "10 - Theme Color Set", ""},
+ {11, "THEME11", VICO_COLORSET_11_VEC, "11 - Theme Color Set", ""},
+ {12, "THEME12", VICO_COLORSET_12_VEC, "12 - Theme Color Set", ""},
+ {13, "THEME13", VICO_COLORSET_13_VEC, "13 - Theme Color Set", ""},
+ {14, "THEME14", VICO_COLORSET_14_VEC, "14 - Theme Color Set", ""},
+ {15, "THEME15", VICO_COLORSET_15_VEC, "15 - Theme Color Set", ""},
+ {16, "THEME16", VICO_COLORSET_16_VEC, "16 - Theme Color Set", ""},
+ {17, "THEME17", VICO_COLORSET_17_VEC, "17 - Theme Color Set", ""},
+ {18, "THEME18", VICO_COLORSET_18_VEC, "18 - Theme Color Set", ""},
+ {19, "THEME19", VICO_COLORSET_19_VEC, "19 - Theme Color Set", ""},
+ {20, "THEME20", VICO_COLORSET_20_VEC, "20 - Theme Color Set", ""},
{-1, "CUSTOM", 0, "Custom Color Set", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -554,13 +556,18 @@ static void rna_PoseChannel_constraints_remove(ID *id, bPoseChannel *pchan, Repo
}
}
-static int rna_PoseChannel_proxy_editable(PointerRNA *ptr)
+static int rna_PoseChannel_proxy_editable(PointerRNA *ptr, const char **r_info)
{
Object *ob = (Object *)ptr->id.data;
bArmature *arm = ob->data;
bPoseChannel *pchan = (bPoseChannel *)ptr->data;
- return (ob->proxy && pchan->bone && (pchan->bone->layer & arm->layer_protected)) ? 0 : PROP_EDITABLE;
+ if (ob->proxy && pchan->bone && (pchan->bone->layer & arm->layer_protected)) {
+ *r_info = "Can't edit property of a proxy on a protected layer";
+ return 0;
+ }
+
+ return PROP_EDITABLE;
}
static int rna_PoseChannel_location_editable(PointerRNA *ptr, int index)
@@ -872,6 +879,50 @@ static void rna_def_pose_channel(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Rotation Mode", "");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
+ /* Curved bones settings - Applied on top of restpose values */
+ rna_def_bone_curved_common(srna, true);
+
+ /* Custom BBone next/prev sources */
+ prop = RNA_def_property(srna, "use_bbone_custom_handles", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "bboneflag", PCHAN_BBONE_CUSTOM_HANDLES);
+ RNA_def_property_ui_text(prop, "Use Custom Handle References",
+ "Use custom reference bones as handles for B-Bones instead of next/previous bones, "
+ "leave these blank to use only B-Bone offset properties to control the shape");
+ RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
+ RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
+
+ prop = RNA_def_property(srna, "bbone_custom_handle_start", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "bbone_prev");
+ RNA_def_property_struct_type(prop, "PoseBone");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "B-Bone Start Handle",
+ "Bone that serves as the start handle for the B-Bone curve");
+ RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
+ RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
+
+ prop = RNA_def_property(srna, "use_bbone_relative_start_handle", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "bboneflag", PCHAN_BBONE_CUSTOM_START_REL);
+ RNA_def_property_ui_text(prop, "Relative B-Bone Start Handle",
+ "Treat custom start handle position as a relative value");
+ RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
+ RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
+
+ prop = RNA_def_property(srna, "bbone_custom_handle_end", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "bbone_next");
+ RNA_def_property_struct_type(prop, "PoseBone");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "B-Bone End Handle",
+ "Bone that serves as the end handle for the B-Bone curve");
+ RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
+ RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
+
+ prop = RNA_def_property(srna, "use_bbone_relative_end_handle", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "bboneflag", PCHAN_BBONE_CUSTOM_END_REL);
+ RNA_def_property_ui_text(prop, "Relative B-Bone End Handle",
+ "Treat custom end handle position as a relative value");
+ RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
+ RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
+
/* transform matrices - should be read-only since these are set directly by AnimSys evaluation */
prop = RNA_def_property(srna, "matrix_channel", PROP_FLOAT, PROP_MATRIX);
RNA_def_property_float_sdna(prop, NULL, "chan_mat");
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index e89edaf74ad..c63d4e775f8 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -35,6 +35,7 @@
#include "DNA_linestyle_types.h"
#include "DNA_userdef_types.h"
#include "DNA_world_types.h"
+#include "DNA_gpencil_types.h"
#include "IMB_imbuf_types.h"
@@ -178,6 +179,11 @@ EnumPropertyItem snap_uv_element_items[] = {
{0, NULL, 0, NULL, NULL}
};
+EnumPropertyItem rna_enum_curve_fit_method_items[] = {
+ {CURVE_PAINT_FIT_METHOD_REFIT, "REFIT", 0, "Refit", "Incrementally re-fit the curve (high quality)"},
+ {CURVE_PAINT_FIT_METHOD_SPLIT, "SPLIT", 0, "Split", "Split the curve until the tolerance is met (fast)"},
+ {0, NULL, 0, NULL, NULL}};
+
/* workaround for duplicate enums,
* have each enum line as a define then conditionally set it or not
*/
@@ -276,16 +282,11 @@ EnumPropertyItem rna_enum_image_type_items[] = {
{R_IMF_IMTYPE_FRAMESERVER, "FRAMESERVER", ICON_FILE_SCRIPT, "Frame Server", "Output image to a frameserver"},
#endif
#ifdef WITH_FFMPEG
- {R_IMF_IMTYPE_H264, "H264", ICON_FILE_MOVIE, "H.264", "Output video in H.264 format"},
- {R_IMF_IMTYPE_FFMPEG, "FFMPEG", ICON_FILE_MOVIE, "MPEG", "Output video in MPEG format"},
- {R_IMF_IMTYPE_THEORA, "THEORA", ICON_FILE_MOVIE, "Ogg Theora", "Output video in Ogg format"},
+ {R_IMF_IMTYPE_FFMPEG, "FFMPEG", ICON_FILE_MOVIE, "FFmpeg video", "The most versatile way to output video files"},
#endif
#ifdef WITH_QUICKTIME
{R_IMF_IMTYPE_QUICKTIME, "QUICKTIME", ICON_FILE_MOVIE, "QuickTime", "Output video in Quicktime format"},
#endif
-#ifdef WITH_FFMPEG
- {R_IMF_IMTYPE_XVID, "XVID", ICON_FILE_MOVIE, "Xvid", "Output video in Xvid format"},
-#endif
{0, NULL, 0, NULL, NULL}
};
@@ -432,6 +433,7 @@ EnumPropertyItem rna_enum_bake_pass_filter_type_items[] = {
#include "BKE_sequencer.h"
#include "BKE_animsys.h"
#include "BKE_freestyle.h"
+#include "BKE_gpencil.h"
#include "ED_info.h"
#include "ED_node.h"
@@ -444,6 +446,108 @@ EnumPropertyItem rna_enum_bake_pass_filter_type_items[] = {
#include "FRS_freestyle.h"
#endif
+/* Grease pencil Drawing Brushes */
+static bGPDbrush *rna_GPencil_brush_new(ToolSettings *ts, const char *name, int setactive)
+{
+ bGPDbrush *brush = BKE_gpencil_brush_addnew(ts, name, setactive != 0);
+
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return brush;
+}
+
+static void rna_GPencil_brush_remove(ToolSettings *ts, ReportList *reports, PointerRNA *brush_ptr)
+{
+ bGPDbrush *brush = brush_ptr->data;
+ if (BLI_findindex(&ts->gp_brushes, brush) == -1) {
+ BKE_report(reports, RPT_ERROR, "Brush not found in grease pencil data");
+ return;
+ }
+
+ BKE_gpencil_brush_delete(ts, brush);
+ RNA_POINTER_INVALIDATE(brush_ptr);
+
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+}
+
+static PointerRNA rna_GPencilBrushes_active_get(PointerRNA *ptr)
+{
+ ToolSettings *ts = (ToolSettings *) ptr->data;
+
+ bGPDbrush *brush;
+
+ for (brush = ts->gp_brushes.first; brush; brush = brush->next) {
+ if (brush->flag & GP_BRUSH_ACTIVE) {
+ break;
+ }
+ }
+
+ if (brush) {
+ return rna_pointer_inherit_refine(ptr, &RNA_GPencilBrush, brush);
+ }
+
+ return rna_pointer_inherit_refine(ptr, NULL, NULL);
+}
+
+static void rna_GPencilBrushes_active_set(PointerRNA *ptr, PointerRNA value)
+{
+ ToolSettings *ts = (ToolSettings *) ptr->data;
+
+ bGPDbrush *brush;
+
+ for (brush = ts->gp_brushes.first; brush; brush = brush->next) {
+ if (brush == value.data) {
+ brush->flag |= GP_BRUSH_ACTIVE;
+ }
+ else {
+ brush->flag &= ~GP_BRUSH_ACTIVE;
+ }
+ }
+ WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
+}
+
+static int rna_GPencilBrushes_index_get(PointerRNA *ptr)
+{
+ ToolSettings *ts = (ToolSettings *) ptr->data;
+ bGPDbrush *brush = BKE_gpencil_brush_getactive(ts);
+
+ return BLI_findindex(&ts->gp_brushes, brush);
+}
+
+static void rna_GPencilBrushes_index_set(PointerRNA *ptr, int value)
+{
+ ToolSettings *ts = (ToolSettings *) ptr->data;
+
+ bGPDbrush *brush = BLI_findlink(&ts->gp_brushes, value);
+
+ BKE_gpencil_brush_setactive(ts, brush);
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+}
+
+static void rna_GPencilBrushes_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax)
+{
+ ToolSettings *ts = (ToolSettings *) ptr->data;
+
+ *min = 0;
+ *max = max_ii(0, BLI_listbase_count(&ts->gp_brushes) - 1);
+
+ *softmin = *min;
+ *softmax = *max;
+}
+
+static void rna_GPencilBrush_name_set(PointerRNA *ptr, const char *value)
+{
+ ToolSettings *ts = ((Scene *) ptr->id.data)->toolsettings;
+ bGPDbrush *brush = ptr->data;
+
+ /* copy the new name into the name slot */
+ BLI_strncpy_utf8(brush->info, value, sizeof(brush->info));
+
+ BLI_uniquename(&ts->gp_brushes, brush, DATA_("GP_Brush"), '.', offsetof(bGPDbrush, info), sizeof(brush->info));
+}
+
+/* ----------------- end of Grease pencil drawing brushes ------------*/
+
static void rna_SpaceImageEditor_uv_sculpt_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(ptr))
{
ED_space_image_uv_sculpt_update(bmain->wm.first, scene);
@@ -813,6 +917,53 @@ static char *rna_RenderSettings_path(PointerRNA *UNUSED(ptr))
return BLI_sprintfN("render");
}
+static char *rna_ImageFormatSettings_path(PointerRNA *ptr)
+{
+ ImageFormatData *imf = (ImageFormatData *)ptr->data;
+ ID *id = ptr->id.data;
+
+ switch (GS(id->name)) {
+ case ID_SCE:
+ {
+ Scene *scene = (Scene *)id;
+
+ if (&scene->r.im_format == imf) {
+ return BLI_sprintfN("render.image_settings");
+ }
+ else if (&scene->r.bake.im_format == imf) {
+ return BLI_sprintfN("render.bake.image_settings");
+ }
+ return BLI_sprintfN("..");
+ }
+ case ID_NT:
+ {
+ bNodeTree *ntree = (bNodeTree *)id;
+ bNode *node;
+
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == CMP_NODE_OUTPUT_FILE) {
+ if (&((NodeImageMultiFile *)node->storage)->format == imf) {
+ return BLI_sprintfN("nodes['%s'].format", node->name);
+ }
+ else {
+ bNodeSocket *sock;
+
+ for (sock = node->inputs.first; sock; sock = sock->next) {
+ NodeImageMultiFileSocket *sockdata = sock->storage;
+ if (&sockdata->format == imf) {
+ return BLI_sprintfN("nodes['%s'].file_slots['%s'].format", node->name, sockdata->path);
+ }
+ }
+ }
+ }
+ }
+ return BLI_sprintfN("..");
+ }
+ default:
+ return BLI_sprintfN("..");
+ }
+}
+
static int rna_RenderSettings_threads_get(PointerRNA *ptr)
{
RenderData *rd = (RenderData *)ptr->data;
@@ -841,21 +992,12 @@ static int rna_RenderSettings_save_buffers_get(PointerRNA *ptr)
RenderData *rd = (RenderData *)ptr->data;
Scene *scene = (Scene *)ptr->id.data;
- if (rd->mode & R_BORDER)
- return 0;
- else if (!BKE_scene_use_new_shading_nodes(scene))
+ if (!BKE_scene_use_new_shading_nodes(scene))
return (rd->scemode & (R_EXR_TILE_FILE | R_FULL_SAMPLE)) != 0;
else
return (rd->scemode & R_EXR_TILE_FILE) != 0;
}
-static int rna_RenderSettings_full_sample_get(PointerRNA *ptr)
-{
- RenderData *rd = (RenderData *)ptr->data;
-
- return (rd->scemode & R_FULL_SAMPLE) && !(rd->mode & R_BORDER);
-}
-
static void rna_ImageFormatSettings_file_format_set(PointerRNA *ptr, int value)
{
ImageFormatData *imf = (ImageFormatData *)ptr->data;
@@ -1995,6 +2137,205 @@ static int rna_gpu_is_hq_supported_get(PointerRNA *UNUSED(ptr))
#else
+/* Grease Pencil Drawing Brushes */
+static void rna_def_gpencil_brush(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "GPencilBrush", NULL);
+ RNA_def_struct_sdna(srna, "bGPDbrush");
+ RNA_def_struct_ui_text(srna, "Grease Pencil Brush",
+ "Collection of brushes being used to control the line style of new strokes");
+ RNA_def_struct_ui_icon(srna, ICON_BRUSH_DATA);
+
+ /* Name */
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "info");
+ RNA_def_property_ui_text(prop, "Name", "Brush name");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GPencilBrush_name_set");
+ RNA_def_struct_name_property(srna, prop);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Line Thickness */
+ prop = RNA_def_property(srna, "line_width", PROP_INT, PROP_PIXEL);
+ RNA_def_property_int_sdna(prop, NULL, "thickness");
+ RNA_def_property_range(prop, 1, 300);
+ RNA_def_property_ui_range(prop, 1, 10, 1, 0);
+ RNA_def_property_ui_text(prop, "Thickness", "Thickness of strokes (in pixels)");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Sensitivity factor for new strokes */
+ prop = RNA_def_property(srna, "pen_sensitivity_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "draw_sensitivity");
+ RNA_def_property_range(prop, 0.1f, 3.0f);
+ RNA_def_property_ui_text(prop, "Sensitivity", "Pressure sensitivity factor for new strokes");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Strength factor for new strokes */
+ prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "draw_strength");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Strength", "Color strength for new strokes (affect alpha factor of color)");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Jitter factor for new strokes */
+ prop = RNA_def_property(srna, "jitter", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "draw_jitter");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Jitter", "Jitter factor for new strokes");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Randomnes factor for sensitivity and strength */
+ prop = RNA_def_property(srna, "random_press", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "draw_random_press");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Randomness", "Randomness factor for pressure and strength in new strokes");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Randomnes factor for subdivision */
+ prop = RNA_def_property(srna, "random_subdiv", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "draw_random_sub");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Random Subdivision", "Randomness factor for new strokes after subdivision");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Angle when brush is full size */
+ prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "draw_angle");
+ RNA_def_property_range(prop, -M_PI_2, M_PI_2);
+ RNA_def_property_ui_text(prop, "Angle",
+ "Direction of the stroke at which brush gives maximal thickness "
+ "(0° for horizontal)");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Factor to change brush size depending of angle */
+ prop = RNA_def_property(srna, "angle_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "draw_angle_factor");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Angle Factor",
+ "Reduce brush thickness by this factor when stroke is perpendicular to 'Angle' direction");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Smoothing factor for new strokes */
+ prop = RNA_def_property(srna, "pen_smooth_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "draw_smoothfac");
+ RNA_def_property_range(prop, 0.0, 2.0f);
+ RNA_def_property_ui_text(prop, "Smooth",
+ "Amount of smoothing to apply to newly created strokes, to reduce jitter/noise");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Iterations of the Smoothing factor */
+ prop = RNA_def_property(srna, "pen_smooth_steps", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "draw_smoothlvl");
+ RNA_def_property_range(prop, 1, 3);
+ RNA_def_property_ui_text(prop, "Iterations",
+ "Number of times to smooth newly created strokes");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Subdivision level for new strokes */
+ prop = RNA_def_property(srna, "pen_subdivision_steps", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "sublevel");
+ RNA_def_property_range(prop, 0, 3);
+ RNA_def_property_ui_text(prop, "Subdivision Steps",
+ "Number of times to subdivide newly created strokes, for less jagged strokes");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Curves for pressure */
+ prop = RNA_def_property(srna, "curve_sensitivity", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "cur_sensitivity");
+ RNA_def_property_struct_type(prop, "CurveMapping");
+ RNA_def_property_ui_text(prop, "Curve Sensitivity", "Curve used for the sensitivity");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "curve_strength", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "cur_strength");
+ RNA_def_property_struct_type(prop, "CurveMapping");
+ RNA_def_property_ui_text(prop, "Curve Strength", "Curve used for the strength");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "curve_jitter", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "cur_jitter");
+ RNA_def_property_struct_type(prop, "CurveMapping");
+ RNA_def_property_ui_text(prop, "Curve Jitter", "Curve used for the jitter effect");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Flags */
+ prop = RNA_def_property(srna, "use_pressure", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_PRESSURE);
+ RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
+ RNA_def_property_ui_text(prop, "Use Pressure", "Use tablet pressure");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "use_strength_pressure", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_STENGTH_PRESSURE);
+ RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
+ RNA_def_property_ui_text(prop, "Use Pressure Strength", "Use tablet pressure for color strength");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "use_jitter_pressure", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_JITTER_PRESSURE);
+ RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
+ RNA_def_property_ui_text(prop, "Use Pressure Jitter", "Use tablet pressure for jitter");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "use_random_pressure", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_RANDOM_PRESSURE);
+ RNA_def_property_ui_icon(prop, ICON_PARTICLES, 0);
+ RNA_def_property_ui_text(prop, "Random Pressure", "Use random value for pressure");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "use_random_strength", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_RANDOM_STRENGTH);
+ RNA_def_property_ui_icon(prop, ICON_PARTICLES, 0);
+ RNA_def_property_ui_text(prop, "Random Strength", "Use random value for strength");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+}
+
+/* Grease Pencil Drawing Brushes API */
+static void rna_def_gpencil_brushes(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "GreasePencilBrushes");
+ srna = RNA_def_struct(brna, "GreasePencilBrushes", NULL);
+ RNA_def_struct_sdna(srna, "ToolSettings");
+ RNA_def_struct_ui_text(srna, "Grease Pencil Brushes", "Collection of grease pencil brushes");
+
+ func = RNA_def_function(srna, "new", "rna_GPencil_brush_new");
+ RNA_def_function_ui_description(func, "Add a new grease pencil brush");
+ parm = RNA_def_string(func, "name", "GPencilBrush", MAX_NAME, "Name", "Name of the brush");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_boolean(func, "set_active", 0, "Set Active", "Set the newly created brush to the active brush");
+ parm = RNA_def_pointer(func, "palette", "GPencilBrush", "", "The newly created brush");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_GPencil_brush_remove");
+ RNA_def_function_ui_description(func, "Remove a grease pencil brush");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(func, "brush", "GPencilBrush", "", "The brush to remove");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+
+ prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "GPencilBrush");
+ RNA_def_property_pointer_funcs(prop, "rna_GPencilBrushes_active_get", "rna_GPencilBrushes_active_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Active Brush", "Current active brush");
+
+ prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_funcs(prop,
+ "rna_GPencilBrushes_index_get",
+ "rna_GPencilBrushes_index_set",
+ "rna_GPencilBrushes_index_range");
+ RNA_def_property_ui_text(prop, "Active Brush Index", "Index of active brush");
+}
+
static void rna_def_transform_orientation(BlenderRNA *brna)
{
StructRNA *srna;
@@ -2315,18 +2656,31 @@ static void rna_def_tool_settings(BlenderRNA *brna)
"are included as the basis for the new one");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ prop = RNA_def_property(srna, "use_gpencil_draw_onback", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "gpencil_flags", GP_TOOL_FLAG_PAINT_ONBACK);
+ RNA_def_property_ui_text(prop, "Draw Strokes on Back",
+ "When draw new strokes, the new stroke is drawn below of all strokes in the layer");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
prop = RNA_def_property(srna, "grease_pencil_source", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "gpencil_src");
RNA_def_property_enum_items(prop, gpencil_source_3d_items);
RNA_def_property_ui_text(prop, "Grease Pencil Source",
- "Datablock where active Grease Pencil data is found from");
+ "Data-block where active Grease Pencil data is found from");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
prop = RNA_def_property(srna, "gpencil_sculpt", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "gp_sculpt");
RNA_def_property_struct_type(prop, "GPencilSculptSettings");
RNA_def_property_ui_text(prop, "Grease Pencil Sculpt", "");
-
+
+ /* Grease Pencil - Drawing brushes */
+ prop = RNA_def_property(srna, "gpencil_brushes", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "gp_brushes", NULL);
+ RNA_def_property_struct_type(prop, "GPencilBrush");
+ RNA_def_property_ui_text(prop, "Grease Pencil Brushes", "Grease Pencil drawing brushes");
+ rna_def_gpencil_brushes(brna, prop);
+
/* Grease Pencil - 3D View Stroke Placement */
prop = RNA_def_property(srna, "gpencil_stroke_placement_view3d", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "gpencil_v3d_align");
@@ -2647,6 +3001,11 @@ static void rna_def_curve_paint_settings(BlenderRNA *brna)
RNA_def_property_range(prop, 1, 100);
RNA_def_property_ui_text(prop, "Tolerance", "Allow deviation for a smoother, less precise line");
+ prop = RNA_def_property(srna, "fit_method", PROP_ENUM, PROP_PIXEL);
+ RNA_def_property_enum_sdna(prop, NULL, "fit_method");
+ RNA_def_property_enum_items(prop, rna_enum_curve_fit_method_items);
+ RNA_def_property_ui_text(prop, "Method", "Curve fitting method");
+
prop = RNA_def_property(srna, "corner_angle", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_range(prop, 0, M_PI);
RNA_def_property_ui_text(prop, "Corner Angle", "Angles above this are considered corners");
@@ -4381,6 +4740,11 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
"Use extra textures like normal or specular maps for GLSL rendering");
RNA_def_property_update(prop, NC_SCENE | NA_EDITED, "rna_Scene_glsl_update");
+ prop = RNA_def_property(srna, "use_glsl_environment_lighting", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GAME_GLSL_NO_ENV_LIGHTING);
+ RNA_def_property_ui_text(prop, "GLSL Environment Lighting", "Use environment lighting for GLSL rendering");
+ RNA_def_property_update(prop, NC_SCENE | NA_EDITED, "rna_Scene_glsl_update");
+
prop = RNA_def_property(srna, "use_material_caching", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GAME_NO_MATERIAL_CACHING);
RNA_def_property_ui_text(prop, "Use Material Caching",
@@ -4794,7 +5158,7 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna)
srna = RNA_def_struct(brna, "ImageFormatSettings", NULL);
RNA_def_struct_sdna(srna, "ImageFormatData");
RNA_def_struct_nested(brna, srna, "Scene");
- /* RNA_def_struct_path_func(srna, "rna_RenderSettings_path"); *//* no need for the path, its not animated! */
+ RNA_def_struct_path_func(srna, "rna_ImageFormatSettings_path");
RNA_def_struct_ui_text(srna, "Image Format", "Settings for image formats");
prop = RNA_def_property(srna, "file_format", PROP_ENUM, PROP_NONE);
@@ -4951,6 +5315,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
PropertyRNA *prop;
#ifdef WITH_FFMPEG
+ /* Container types */
static EnumPropertyItem ffmpeg_format_items[] = {
{FFMPEG_MPEG1, "MPEG1", 0, "MPEG-1", ""},
{FFMPEG_MPEG2, "MPEG2", 0, "MPEG-2", ""},
@@ -4958,8 +5323,8 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
{FFMPEG_AVI, "AVI", 0, "AVI", ""},
{FFMPEG_MOV, "QUICKTIME", 0, "Quicktime", ""},
{FFMPEG_DV, "DV", 0, "DV", ""},
- {FFMPEG_H264, "H264", 0, "H.264", ""},
- {FFMPEG_XVID, "XVID", 0, "Xvid", ""},
+// {FFMPEG_H264, "H264", 0, "H.264", ""}, not a container
+// {FFMPEG_XVID, "XVID", 0, "Xvid", ""}, not a container
{FFMPEG_OGG, "OGG", 0, "Ogg", ""},
{FFMPEG_MKV, "MKV", 0, "Matroska", ""},
{FFMPEG_FLV, "FLASH", 0, "Flash", ""},
@@ -4983,6 +5348,32 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem ffmpeg_preset_items[] = {
+ {FFM_PRESET_ULTRAFAST, "ULTRAFAST", 0, "Ultra fast; biggest file", ""},
+ {FFM_PRESET_SUPERFAST, "SUPERFAST", 0, "Super fast", ""},
+ {FFM_PRESET_VERYFAST, "VERYFAST", 0, "Very fast", ""},
+ {FFM_PRESET_FASTER, "FASTER", 0, "Faster", ""},
+ {FFM_PRESET_FAST, "FAST", 0, "Fast", ""},
+ {FFM_PRESET_MEDIUM, "MEDIUM", 0, "Medium speed", ""},
+ {FFM_PRESET_SLOW, "SLOW", 0, "Slow", ""},
+ {FFM_PRESET_SLOWER, "SLOWER", 0, "Slower", ""},
+ {FFM_PRESET_VERYSLOW, "VERYSLOW", 0, "Very slow; smallest file", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem ffmpeg_crf_items[] = {
+ {FFM_CRF_NONE, "NONE", 0, "None; use constant bit-rate",
+ "Use constant bit rate, rather than constant output quality"},
+ {FFM_CRF_LOSSLESS, "LOSSLESS", 0, "Lossless", ""},
+ {FFM_CRF_PERC_LOSSLESS, "PERC_LOSSLESS", 0, "Perceptually lossless", ""},
+ {FFM_CRF_HIGH, "HIGH", 0, "High quality", ""},
+ {FFM_CRF_MEDIUM, "MEDIUM", 0, "Medium quality", ""},
+ {FFM_CRF_LOW, "LOW", 0, "Low quality", ""},
+ {FFM_CRF_VERYLOW, "VERYLOW", 0, "Very low quality", ""},
+ {FFM_CRF_LOWEST, "LOWEST", 0, "Lowest quality", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
static EnumPropertyItem ffmpeg_audio_codec_items[] = {
{AV_CODEC_ID_NONE, "NONE", 0, "None", ""},
{AV_CODEC_ID_MP2, "MP2", 0, "MP2", ""},
@@ -5014,13 +5405,15 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
RNA_def_property_enum_bitflag_sdna(prop, NULL, "type");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_enum_items(prop, ffmpeg_format_items);
- RNA_def_property_ui_text(prop, "Format", "Output file format");
+ RNA_def_property_enum_default(prop, FFMPEG_MKV);
+ RNA_def_property_ui_text(prop, "Container", "Output file container");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_FFmpegSettings_codec_settings_update");
prop = RNA_def_property(srna, "codec", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "codec");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_enum_items(prop, ffmpeg_codec_items);
+ RNA_def_property_enum_default(prop, AV_CODEC_ID_H264);
RNA_def_property_ui_text(prop, "Codec", "FFmpeg codec to use");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_FFmpegSettings_codec_settings_update");
@@ -5052,8 +5445,25 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "gopsize", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "gop_size");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_range(prop, 0, 100);
- RNA_def_property_ui_text(prop, "GOP Size", "Distance between key frames");
+ RNA_def_property_range(prop, 0, 500);
+ RNA_def_property_int_default(prop, 25);
+ RNA_def_property_ui_text(prop, "Keyframe interval",
+ "Distance between key frames, also known as GOP size; "
+ "influences file size and seekability");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ prop = RNA_def_property(srna, "max_b_frames", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "max_b_frames");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_range(prop, 0, 16);
+ RNA_def_property_ui_text(prop, "Max B-frames",
+ "Maximum number of B-frames between non-B-frames; influences file size and seekability");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ prop = RNA_def_property(srna, "use_max_b_frames", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FFMPEG_USE_MAX_B_FRAMES);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Use max B-frames", "Set a maximum number of B-frames");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "buffersize", PROP_INT, PROP_NONE);
@@ -5070,6 +5480,24 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Mux Packet Size", "Mux packet size (byte)");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ prop = RNA_def_property(srna, "constant_rate_factor", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "constant_rate_factor");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_enum_items(prop, ffmpeg_crf_items);
+ RNA_def_property_enum_default(prop, FFM_CRF_MEDIUM);
+ RNA_def_property_ui_text(prop, "Output quality",
+ "Constant Rate Factor (CRF); tradeoff between video quality and file size");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ prop = RNA_def_property(srna, "ffmpeg_preset", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "ffmpeg_preset");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_enum_items(prop, ffmpeg_preset_items);
+ RNA_def_property_enum_default(prop, FFM_PRESET_MEDIUM);
+ RNA_def_property_ui_text(prop, "Encoding speed",
+ "Tradeoff between encoding speed and compression ratio");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
prop = RNA_def_property(srna, "use_autosplit", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FFMPEG_AUTOSPLIT_OUTPUT);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
@@ -5567,6 +5995,11 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "mode", R_SSS);
RNA_def_property_ui_text(prop, "Subsurface Scattering", "Calculate sub-surface scattering in materials rendering");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
+
+ prop = RNA_def_property(srna, "use_world_space_shading", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "mode", R_USE_WS_SHADING);
+ RNA_def_property_ui_text(prop, "World Space Shading", "Use world space interpretation of lighting data for node materials");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
prop = RNA_def_property(srna, "use_raytrace", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", R_RAYTRACE);
@@ -5758,7 +6191,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_full_sample", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "scemode", R_FULL_SAMPLE);
- RNA_def_property_boolean_funcs(prop, "rna_RenderSettings_full_sample_get", NULL);
RNA_def_property_ui_text(prop, "Full Sample",
"Save for every anti-aliasing sample the entire RenderLayer results "
"(this solves anti-aliasing issues with compositing)");
@@ -5963,11 +6395,21 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Stamp Output", "Render the stamp info text in the rendered image");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ prop = RNA_def_property(srna, "use_stamp_labels", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "stamp", R_STAMP_HIDE_LABELS);
+ RNA_def_property_ui_text(prop, "Stamp Labels", "Draw stamp labels (\"Camera\" in front of camera name, etc.)");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
prop = RNA_def_property(srna, "use_stamp_strip_meta", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "stamp", R_STAMP_STRIPMETA);
RNA_def_property_ui_text(prop, "Strip Metadata", "Use metadata from the strips in the sequencer");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ prop = RNA_def_property(srna, "use_stamp_memory", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "stamp", R_STAMP_MEMORY);
+ RNA_def_property_ui_text(prop, "Stamp Peak Memory", "Include the peak memory usage in image metadata");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
prop = RNA_def_property(srna, "stamp_font_size", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "stamp_font_id");
RNA_def_property_range(prop, 8, 64);
@@ -6440,8 +6882,8 @@ void RNA_def_scene(BlenderRNA *brna)
/* Struct definition */
srna = RNA_def_struct(brna, "Scene", "ID");
- RNA_def_struct_ui_text(srna, "Scene",
- "Scene data block, consisting in objects and defining time and render related settings");
+ RNA_def_struct_ui_text(srna, "Scene", "Scene data-block, consisting in objects and "
+ "defining time and render related settings");
RNA_def_struct_ui_icon(srna, ICON_SCENE_DATA);
RNA_def_struct_clear_flag(srna, STRUCT_ID_REFCOUNT);
@@ -6824,6 +7266,7 @@ void RNA_def_scene(BlenderRNA *brna)
/* *** Non-Animated *** */
RNA_define_animate_sdna(false);
rna_def_tool_settings(brna);
+ rna_def_gpencil_brush(brna);
rna_def_unified_paint_settings(brna);
rna_def_curve_paint_settings(brna);
rna_def_statvis(brna);
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index 74fb4a08eda..85c0b01334f 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -37,6 +37,7 @@
#include "BLI_path_util.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "DNA_anim_types.h"
#include "DNA_object_types.h"
@@ -44,6 +45,18 @@
#include "rna_internal.h" /* own include */
+#ifdef WITH_ALEMBIC
+# include "../../alembic/ABC_alembic.h"
+#endif
+
+EnumPropertyItem rna_enum_abc_compression_items[] = {
+#ifdef WITH_ALEMBIC
+ { ABC_ARCHIVE_OGAWA, "OGAWA", 0, "Ogawa", "" },
+ { ABC_ARCHIVE_HDF5, "HDF5", 0, "HDF5", "" },
+#endif
+ { 0, NULL, 0, NULL, NULL }
+};
+
#ifdef RNA_RUNTIME
#include "BKE_animsys.h"
@@ -151,9 +164,9 @@ static void rna_Scene_ray_cast(
bool ret = ED_transform_snap_object_project_ray_ex(
sctx,
+ SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
- .snap_to = SCE_SNAP_MODE_FACE,
},
origin, direction, &ray_dist,
r_location, r_normal, r_index,
@@ -173,6 +186,79 @@ static void rna_Scene_ray_cast(
}
}
+#ifdef WITH_ALEMBIC
+
+static void rna_Scene_alembic_export(
+ Scene *scene,
+ bContext *C,
+ const char *filepath,
+ int frame_start,
+ int frame_end,
+ int xform_samples,
+ int geom_samples,
+ float shutter_open,
+ float shutter_close,
+ int selected_only,
+ int uvs,
+ int normals,
+ int vcolors,
+ int apply_subdiv,
+ int flatten_hierarchy,
+ int visible_layers_only,
+ int renderable_only,
+ int face_sets,
+ int use_subdiv_schema,
+ int compression_type,
+ int packuv,
+ float scale,
+ int triangulate,
+ int quad_method,
+ int ngon_method)
+{
+/* We have to enable allow_threads, because we may change scene frame number
+ * during export. */
+#ifdef WITH_PYTHON
+ BPy_BEGIN_ALLOW_THREADS;
+#endif
+
+ const struct AlembicExportParams params = {
+ .frame_start = frame_start,
+ .frame_end = frame_end,
+
+ .frame_step_xform = 1.0 / (double)xform_samples,
+ .frame_step_shape = 1.0 / (double)geom_samples,
+
+ .shutter_open = shutter_open,
+ .shutter_close = shutter_close,
+
+ .selected_only = selected_only,
+ .uvs = uvs,
+ .normals = normals,
+ .vcolors = vcolors,
+ .apply_subdiv = apply_subdiv,
+ .flatten_hierarchy = flatten_hierarchy,
+ .visible_layers_only = visible_layers_only,
+ .renderable_only = renderable_only,
+ .face_sets = face_sets,
+ .use_subdiv_schema = use_subdiv_schema,
+ .compression_type = compression_type,
+ .packuv = packuv,
+ .triangulate = triangulate,
+ .quad_method = quad_method,
+ .ngon_method = ngon_method,
+
+ .global_scale = scale,
+ };
+
+ ABC_export(scene, C, filepath, &params);
+
+#ifdef WITH_PYTHON
+ BPy_END_ALLOW_THREADS;
+#endif
+}
+
+#endif
+
#ifdef WITH_COLLADA
/* don't remove this, as COLLADA exporting cannot be done through operators in render() callback. */
#include "../../collada/collada.h"
@@ -196,14 +282,15 @@ static void rna_Scene_collada_export(
int use_ngons,
int use_object_instantiation,
+ int use_blender_profile,
int sort_by_name,
- int export_transformation_type,
- int open_sim)
+ int open_sim,
+ int export_transformation_type)
{
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_ngons, use_object_instantiation, sort_by_name, export_transformation_type, open_sim);
+ use_texture_copies, use_ngons, use_object_instantiation, use_blender_profile, sort_by_name, export_transformation_type, open_sim);
}
#endif
@@ -286,6 +373,7 @@ void RNA_api_scene(StructRNA *srna)
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, "use_blender_profile", 1, "Use Blender Profile", "Export additional Blender specific information (for material, shaders, bones, etc.)");
parm = RNA_def_boolean(func, "sort_by_name", 0, "Sort by Object name", "Sort exported data by Object name");
parm = RNA_def_boolean(func, "open_sim", 0, "Export for SL/OpenSim", "Compatibility mode for SL, OpenSim and similar online worlds");
@@ -294,6 +382,40 @@ void RNA_api_scene(StructRNA *srna)
RNA_def_function_ui_description(func, "Export to collada file");
#endif
+
+#ifdef WITH_ALEMBIC
+ func = RNA_def_function(srna, "alembic_export", "rna_Scene_alembic_export");
+ RNA_def_function_ui_description(func, "Export to Alembic file");
+
+ parm = RNA_def_string(func, "filepath", NULL, FILE_MAX, "File Path", "File path to write Alembic file");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_property_subtype(parm, PROP_FILEPATH); /* allow non utf8 */
+
+ RNA_def_int(func, "frame_start", 1, INT_MIN, INT_MAX, "Start", "Start Frame", INT_MIN, INT_MAX);
+ RNA_def_int(func, "frame_end", 1, INT_MIN, INT_MAX, "End", "End Frame", INT_MIN, INT_MAX);
+ RNA_def_int(func, "xform_samples", 1, 1, 128, "Xform samples", "Transform samples per frame", 1, 128);
+ RNA_def_int(func, "geom_samples", 1, 1, 128, "Geom samples", "Geometry samples per frame", 1, 128);
+ RNA_def_float(func, "shutter_open", 0.0f, -1.0f, 1.0f, "Shutter open", "", -1.0f, 1.0f);
+ RNA_def_float(func, "shutter_close", 1.0f, -1.0f, 1.0f, "Shutter close", "", -1.0f, 1.0f);
+ RNA_def_boolean(func, "selected_only" , 0, "Selected only", "Export only selected objects");
+ RNA_def_boolean(func, "uvs" , 1, "UVs", "Export UVs");
+ RNA_def_boolean(func, "normals" , 1, "Normals", "Export cormals");
+ RNA_def_boolean(func, "vcolors" , 0, "Vertex colors", "Export vertex colors");
+ RNA_def_boolean(func, "apply_subdiv" , 1, "Subsurfs as meshes", "Export subdivision surfaces as meshes");
+ RNA_def_boolean(func, "flatten" , 0, "Flatten hierarchy", "Flatten hierarchy");
+ RNA_def_boolean(func, "visible_layers_only" , 0, "Visible layers only", "Export only objects in visible layers");
+ RNA_def_boolean(func, "renderable_only" , 0, "Renderable objects only", "Export only objects marked renderable in the outliner");
+ RNA_def_boolean(func, "face_sets" , 0, "Facesets", "Export face sets");
+ RNA_def_boolean(func, "subdiv_schema", 0, "Use Alembic subdivision Schema", "Use Alembic subdivision Schema");
+ RNA_def_enum(func, "compression_type", rna_enum_abc_compression_items, 0, "Compression", "");
+ RNA_def_boolean(func, "packuv" , 0, "Export with packed UV islands", "Export with packed UV islands");
+ RNA_def_float(func, "scale", 1.0f, 0.0001f, 1000.0f, "Scale", "Value by which to enlarge or shrink the objects with respect to the world's origin", 0.0001f, 1000.0f);
+ RNA_def_boolean(func, "triangulate", 0, "Triangulate", "Export Polygons (Quads & NGons) as Triangles");
+ RNA_def_enum(func, "quad_method", rna_enum_modifier_triangulate_quad_method_items, 0, "Quad Method", "Method for splitting the quads into triangles");
+ RNA_def_enum(func, "ngon_method", rna_enum_modifier_triangulate_quad_method_items, 0, "Polygon Method", "Method for splitting the polygons into triangles");
+
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+#endif
}
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index 90215bc883f..e169ef0d822 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -63,7 +63,8 @@ static EnumPropertyItem particle_edit_hair_brush_items[] = {
EnumPropertyItem rna_enum_gpencil_sculpt_brush_items[] = {
{GP_EDITBRUSH_TYPE_SMOOTH, "SMOOTH", 0, "Smooth", "Smooth stroke points"},
{GP_EDITBRUSH_TYPE_THICKNESS, "THICKNESS", 0, "Thickness", "Adjust thickness of strokes"},
- {GP_EDITBRUSH_TYPE_GRAB, "GRAB", 0, "Grab", "Translate the set of points initially within the brush circle"},
+ { GP_EDITBRUSH_TYPE_STRENGTH, "STRENGTH", 0, "Strength", "Adjust color strength of strokes" },
+ { GP_EDITBRUSH_TYPE_GRAB, "GRAB", 0, "Grab", "Translate the set of points initially within the brush circle" },
{GP_EDITBRUSH_TYPE_PUSH, "PUSH", 0, "Push", "Move points out of the way, as if combing them"},
{GP_EDITBRUSH_TYPE_TWIST, "TWIST", 0, "Twist", "Rotate points around the midpoint of the brush"},
{GP_EDITBRUSH_TYPE_PINCH, "PINCH", 0, "Pinch", "Pull points towards the midpoint of the brush"},
@@ -71,7 +72,15 @@ EnumPropertyItem rna_enum_gpencil_sculpt_brush_items[] = {
//{GP_EDITBRUSH_TYPE_SUBDIVIDE, "SUBDIVIDE", 0, "Subdivide", "Increase point density for higher resolution strokes when zoomed in"},
//{GP_EDITBRUSH_TYPE_SIMPLIFY, "SIMPLIFY", 0, "Simplify", "Reduce density of stroke points"},
{GP_EDITBRUSH_TYPE_CLONE, "CLONE", 0, "Clone", "Paste copies of the strokes stored on the clipboard"},
- {0, NULL, 0, NULL, NULL}
+ { 0, NULL, 0, NULL, NULL }
+};
+
+EnumPropertyItem rna_enum_gpencil_lockaxis_items[] = {
+ { GP_LOCKAXIS_NONE, "GP_LOCKAXIS_NONE", 0, "None", "" },
+ { GP_LOCKAXIS_X, "GP_LOCKAXIS_X", 0, "X", "Project strokes to plane locked to X" },
+ { GP_LOCKAXIS_Y, "GP_LOCKAXIS_Y", 0, "Y", "Project strokes to plane locked to Y" },
+ { GP_LOCKAXIS_Z, "GP_LOCKAXIS_Z", 0, "Z", "Project strokes to plane locked to Z" },
+ { 0, NULL, 0, NULL, NULL }
};
EnumPropertyItem rna_enum_symmetrize_direction_items[] = {
@@ -100,6 +109,11 @@ EnumPropertyItem rna_enum_symmetrize_direction_items[] = {
#include "ED_particle.h"
+static void rna_GPencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
+{
+ WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
+}
+
static EnumPropertyItem particle_edit_disconnected_hair_brush_items[] = {
{PE_BRUSH_NONE, "NONE", 0, "None", "Don't use any brush"},
{PE_BRUSH_COMB, "COMB", 0, "Comb", "Comb hairs"},
@@ -1016,6 +1030,44 @@ static void rna_def_gpencil_sculpt(BlenderRNA *brna)
RNA_def_property_ui_icon(prop, ICON_VERTEXSEL, 0); // FIXME: this needs a custom icon
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ prop = RNA_def_property(srna, "affect_position", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_APPLY_POSITION);
+ RNA_def_property_ui_text(prop, "Affect Position", "The brush affects the position of the point");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "affect_strength", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_APPLY_STRENGTH);
+ RNA_def_property_ui_text(prop, "Affect Strength", "The brush affects the color strength of the point");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "affect_thickness", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_APPLY_THICKNESS);
+ RNA_def_property_ui_text(prop, "Affect Thickness", "The brush affects the thickness of the point");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "interpolate_all_layers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS);
+ RNA_def_property_ui_text(prop, "Interpolate All Layers", "Interpolate all layers, not only active");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "interpolate_selected_only", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED);
+ RNA_def_property_ui_text(prop, "Interpolate Selected Strokes", "Interpolate only selected strokes in the original frame");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "selection_alpha", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "alpha");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Alpha", "Alpha value for selected vertices");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_GPencil_update");
+
+ /* lock axis */
+ prop = RNA_def_property(srna, "lockaxis", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "lock_axis");
+ RNA_def_property_enum_items(prop, rna_enum_gpencil_lockaxis_items);
+ RNA_def_property_ui_text(prop, "Lock", "");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
/* brush */
srna = RNA_def_struct(brna, "GPencilSculptBrush", NULL);
RNA_def_struct_sdna(srna, "GP_EditBrush_Data");
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index 68d4f7f7e51..bb9c2a6c2fd 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -292,7 +292,7 @@ static int rna_Sequence_frame_length_get(PointerRNA *ptr)
return BKE_sequence_tx_get_final_right(seq, false) - BKE_sequence_tx_get_final_left(seq, false);
}
-static int rna_Sequence_frame_editable(PointerRNA *ptr)
+static int rna_Sequence_frame_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
Sequence *seq = (Sequence *)ptr->data;
/* Effect sequences' start frame and length must be readonly! */
@@ -2327,6 +2327,7 @@ static void rna_def_text(StructRNA *srna)
prop = RNA_def_property(srna, "font_size", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "text_size");
RNA_def_property_ui_text(prop, "Size", "Size of the text");
+ RNA_def_property_range(prop, 0.0, 2000);
RNA_def_property_ui_range(prop, 0.0f, 1000, 1, -1);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c
index 9a31952b84b..b4ba306df3f 100644
--- a/source/blender/makesrna/intern/rna_smoke.c
+++ b/source/blender/makesrna/intern/rna_smoke.c
@@ -76,6 +76,21 @@ static void rna_Smoke_resetCache(Main *UNUSED(bmain), Scene *UNUSED(scene), Poin
DAG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
}
+static void rna_Smoke_cachetype_set(struct PointerRNA *ptr, int value)
+{
+ SmokeDomainSettings *settings = (SmokeDomainSettings *)ptr->data;
+ Object *ob = (Object *)ptr->id.data;
+
+ if (value != settings->cache_file_format) {
+ /* Clear old caches. */
+ PTCacheID id;
+ BKE_ptcache_id_from_smoke(&id, ob, settings->smd);
+ BKE_ptcache_id_clear(&id, PTCACHE_CLEAR_ALL, 0);
+
+ settings->cache_file_format = value;
+ }
+}
+
static void rna_Smoke_reset(Main *bmain, Scene *scene, PointerRNA *ptr)
{
SmokeDomainSettings *settings = (SmokeDomainSettings *)ptr->data;
@@ -428,6 +443,32 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem smoke_view_items[] = {
+ {MOD_SMOKE_SLICE_VIEW_ALIGNED, "VIEW_ALIGNED", 0, "View", "Slice volume parallel to the view plane"},
+ {MOD_SMOKE_SLICE_AXIS_ALIGNED, "AXIS_ALIGNED", 0, "Axis", "Slice volume parallel to the major axis"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem axis_slice_method_items[] = {
+ {AXIS_SLICE_FULL, "FULL", 0, "Full", "Slice the whole domain object"},
+ {AXIS_SLICE_SINGLE, "SINGLE", 0, "Single", "Perform a single slice of the domain object"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem axis_slice_position_items[] = {
+ {SLICE_AXIS_AUTO, "AUTO", 0, "Auto", "Adjust slice direction according to the view direction"},
+ {SLICE_AXIS_X, "X", 0, "X", "Slice along the X axis"},
+ {SLICE_AXIS_Y, "Y", 0, "Y", "Slice along the Y axis"},
+ {SLICE_AXIS_Z, "Z", 0, "Z", "Slice along the Z axis"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem vector_draw_items[] = {
+ {VECTOR_DRAW_NEEDLE, "NEEDLE", 0, "Needle", "Draw vectors as needles"},
+ {VECTOR_DRAW_STREAMLINE, "STREAMLINE", 0, "Streamlines", "Draw vectors as streamlines"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
srna = RNA_def_struct(brna, "SmokeDomainSettings", NULL);
RNA_def_struct_ui_text(srna, "Domain Settings", "Smoke domain settings");
RNA_def_struct_sdna(srna, "SmokeDomainSettings");
@@ -701,8 +742,69 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "cache_file_format", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "cache_file_format");
RNA_def_property_enum_items(prop, cache_file_type_items);
+ RNA_def_property_enum_funcs(prop, NULL, "rna_Smoke_cachetype_set", NULL);
RNA_def_property_ui_text(prop, "File Format", "Select the file format to be used for caching");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
+
+ /* display settings */
+
+ prop = RNA_def_property(srna, "slice_method", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "slice_method");
+ RNA_def_property_enum_items(prop, smoke_view_items);
+ RNA_def_property_ui_text(prop, "View Method", "How to slice the volume for viewport rendering");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "axis_slice_method", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "axis_slice_method");
+ RNA_def_property_enum_items(prop, axis_slice_method_items);
+ RNA_def_property_ui_text(prop, "Method", "");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "slice_axis", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "slice_axis");
+ RNA_def_property_enum_items(prop, axis_slice_position_items);
+ RNA_def_property_ui_text(prop, "Axis", "");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "slice_per_voxel", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "slice_per_voxel");
+ RNA_def_property_range(prop, 0.0, 100.0);
+ RNA_def_property_ui_range(prop, 0.0, 5.0, 0.1, 1);
+ RNA_def_property_ui_text(prop, "Slice Per Voxel",
+ "How many slices per voxel should be generated");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "slice_depth", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "slice_depth");
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 3);
+ RNA_def_property_ui_text(prop, "Position", "Position of the slice");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "display_thickness", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "display_thickness");
+ RNA_def_property_range(prop, 0.001, 1000.0);
+ RNA_def_property_ui_range(prop, 0.1, 100.0, 0.1, 3);
+ RNA_def_property_ui_text(prop, "Thickness", "Thickness of smoke drawing in the viewport");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
+ prop = RNA_def_property(srna, "draw_velocity", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "draw_velocity", 0);
+ RNA_def_property_ui_text(prop, "Draw Velocity", "Toggle visualization of the velocity field as needles");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "vector_draw_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "vector_draw_type");
+ RNA_def_property_enum_items(prop, vector_draw_items);
+ RNA_def_property_ui_text(prop, "Draw Type", "");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "vector_scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "vector_scale");
+ RNA_def_property_range(prop, 0.0, 1000.0);
+ RNA_def_property_ui_range(prop, 0.0, 100.0, 0.1, 3);
+ RNA_def_property_ui_text(prop, "Scale", "Multiplier for scaling the vectors");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
}
static void rna_def_smoke_flow_settings(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index f4db0277660..ffcf12edb2d 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -454,6 +454,15 @@ EnumPropertyItem *rna_TransformOrientation_itemf(bContext *C, PointerRNA *ptr, P
}
/* Space 3D View */
+static void rna_SpaceView3D_camera_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ View3D *v3d = (View3D *)(ptr->data);
+ if (v3d->scenelock) {
+ scene->camera = v3d->camera;
+ BKE_screen_view3d_main_sync(&bmain->screen, scene);
+ }
+}
+
static void rna_SpaceView3D_lock_camera_and_layers_set(PointerRNA *ptr, int value)
{
View3D *v3d = (View3D *)(ptr->data);
@@ -513,6 +522,13 @@ static void rna_SpaceView3D_layer_set(PointerRNA *ptr, const int *values)
v3d->lay = ED_view3d_scene_layer_set(v3d->lay, values, &v3d->layact);
}
+static int rna_SpaceView3D_active_layer_get(PointerRNA *ptr)
+{
+ View3D *v3d = (View3D *)(ptr->data);
+
+ return (int)(log(v3d->layact) / M_LN2);
+}
+
static void rna_SpaceView3D_layer_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
{
DAG_on_visible_update(bmain, false);
@@ -689,6 +705,15 @@ static int rna_SpaceView3D_viewport_shade_get(PointerRNA *ptr)
return drawtype;
}
+static void rna_SpaceView3D_viewport_shade_set(PointerRNA *ptr, int value)
+{
+ View3D *v3d = (View3D *)ptr->data;
+ if (value != v3d->drawtype && value == OB_RENDER) {
+ v3d->prev_drawtype = v3d->drawtype;
+ }
+ v3d->drawtype = value;
+}
+
static EnumPropertyItem *rna_SpaceView3D_viewport_shade_itemf(bContext *UNUSED(C), PointerRNA *ptr,
PropertyRNA *UNUSED(prop), bool *r_free)
{
@@ -1636,7 +1661,7 @@ static void rna_FileBrowser_FSMenuEntry_name_set(PointerRNA *ptr, const char *va
ED_fsmenu_entry_set_name(fsm, value);
}
-static int rna_FileBrowser_FSMenuEntry_name_get_editable(PointerRNA *ptr)
+static int rna_FileBrowser_FSMenuEntry_name_get_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
FSMenuEntry *fsm = ptr->data;
@@ -1794,7 +1819,7 @@ static void rna_FileBrowser_FSMenu_active_range(
static void rna_FileBrowser_FSMenu_active_update(struct bContext *C, PointerRNA *UNUSED(ptr))
{
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
}
static int rna_FileBrowser_FSMenuSystem_active_get(PointerRNA *ptr)
@@ -1952,6 +1977,13 @@ static void rna_def_space_image_uv(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem other_uv_filter_items[] = {
+ {SI_FILTER_ALL, "ALL", 0, "All", "No filter, show all islands from other objects"},
+ {SI_FILTER_SAME_IMAGE, "SAME_IMAGE", ICON_IMAGE_DATA, "Same Image",
+ "Only show others' UV islads who's active image matches image of the active face"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
srna = RNA_def_struct(brna, "SpaceUVEditor", NULL);
RNA_def_struct_sdna(srna, "SpaceImage");
RNA_def_struct_nested(brna, srna, "SpaceImageEditor");
@@ -2039,6 +2071,13 @@ static void rna_def_space_image_uv(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Live Unwrap",
"Continuously unwrap the selected UV island while transforming pinned vertices");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
+
+ /* Other UV filtering */
+ prop = RNA_def_property(srna, "other_uv_filter", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, other_uv_filter_items);
+ RNA_def_property_ui_text(prop, "Other UV filter",
+ "Filter applied on the other object's UV to limit displayed");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
}
static void rna_def_space_outliner(BlenderRNA *brna)
@@ -2359,7 +2398,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "camera");
RNA_def_property_ui_text(prop, "Camera",
"Active camera used in this view (when unlocked from the scene's active camera)");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_SpaceView3D_camera_update");
/* render border */
prop = RNA_def_property(srna, "use_render_border", PROP_BOOLEAN, PROP_NONE);
@@ -2412,7 +2451,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
prop = RNA_def_property(srna, "viewport_shade", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "drawtype");
RNA_def_property_enum_items(prop, rna_enum_viewport_shade_items);
- RNA_def_property_enum_funcs(prop, "rna_SpaceView3D_viewport_shade_get", NULL,
+ RNA_def_property_enum_funcs(prop, "rna_SpaceView3D_viewport_shade_get", "rna_SpaceView3D_viewport_shade_set",
"rna_SpaceView3D_viewport_shade_itemf");
RNA_def_property_ui_text(prop, "Viewport Shading", "Method to display/shade objects in the 3D View");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_SpaceView3D_viewport_shade_update");
@@ -2438,14 +2477,16 @@ static void rna_def_space_view3d(BlenderRNA *brna)
prop = RNA_def_property(srna, "clip_start", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "near");
- RNA_def_property_range(prop, 0.001f, FLT_MAX);
+ RNA_def_property_range(prop, 1e-6f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
RNA_def_property_float_default(prop, 0.1f);
RNA_def_property_ui_text(prop, "Clip Start", "3D View near clipping distance (perspective view only)");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "clip_end", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "far");
- RNA_def_property_range(prop, 1.0f, FLT_MAX);
+ RNA_def_property_range(prop, 1e-6f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
RNA_def_property_float_default(prop, 1000.0f);
RNA_def_property_ui_text(prop, "Clip End", "3D View far clipping distance");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
@@ -2627,6 +2668,11 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Visible Layers", "Layers visible in this 3D View");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_SpaceView3D_layer_update");
+ prop = RNA_def_property(srna, "active_layer", PROP_INT, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
+ RNA_def_property_int_funcs(prop, "rna_SpaceView3D_active_layer_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Active Layer", "Active 3D view layer index");
+
prop = RNA_def_property(srna, "layers_local_view", PROP_BOOLEAN, PROP_LAYER_MEMBER);
RNA_def_property_boolean_sdna(prop, NULL, "lay", 0x01000000);
RNA_def_property_array(prop, 8);
@@ -3344,6 +3390,7 @@ static void rna_def_space_dopesheet(BlenderRNA *brna)
{SACTCONT_SHAPEKEY, "SHAPEKEY", ICON_SHAPEKEY_DATA, "Shape Key Editor", "Edit keyframes in active object's Shape Keys action"},
{SACTCONT_GPENCIL, "GPENCIL", ICON_GREASEPENCIL, "Grease Pencil", "Edit timings for all Grease Pencil sketches in file"},
{SACTCONT_MASK, "MASK", ICON_MOD_MASK, "Mask", "Edit timings for Mask Editor splines"},
+ {SACTCONT_CACHEFILE, "CACHEFILE", ICON_FILE, "Cache File", "Edit timings for Cache File data-blocks"},
{0, NULL, 0, NULL, NULL}
};
@@ -3602,6 +3649,12 @@ static void rna_def_space_nla(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Show Control F-Curves", "Show influence F-Curves on strips");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NLA, NULL);
+ prop = RNA_def_property(srna, "show_local_markers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SNLA_NOLOCALMARKERS);
+ RNA_def_property_ui_text(prop, "Show Local Markers",
+ "Show action-local markers on the strips, useful when synchronizing timing across strips");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NLA, NULL);
+
/* editing */
prop = RNA_def_property(srna, "use_realtime_update", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SNLA_NOREALTIMEUPDATES);
@@ -3782,6 +3835,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
{FILTER_ID_AR, "ARMATURE", ICON_ARMATURE_DATA, "Armatures", "Show/hide Armature data-blocks"},
{FILTER_ID_BR, "BRUSH", ICON_BRUSH_DATA, "Brushes", "Show/hide Brushes data-blocks"},
{FILTER_ID_CA, "CAMERA", ICON_CAMERA_DATA, "Cameras", "Show/hide Camera data-blocks"},
+ {FILTER_ID_CF, "CACHEFILE", ICON_FILE, "Cache Files", "Show/hide Cache File data-blocks"},
{FILTER_ID_CU, "CURVE", ICON_CURVE_DATA, "Curves", "Show/hide Curve data-blocks"},
{FILTER_ID_GD, "GREASE_PENCIL", ICON_GREASEPENCIL, "Grease Pencil", "Show/hide Grease pencil data-blocks"},
{FILTER_ID_GR, "GROUP", ICON_GROUP, "Groups", "Show/hide Group data-blocks"},
@@ -3827,7 +3881,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
"IMAGE", ICON_IMAGE_DATA, "Images & Sounds", "Show/hide images, movie clips, sounds and masks"},
{FILTER_ID_CA | FILTER_ID_LA | FILTER_ID_SPK | FILTER_ID_WO,
"ENVIRONMENT", ICON_WORLD_DATA, "Environment", "Show/hide worlds, lamps, cameras and speakers"},
- {FILTER_ID_BR | FILTER_ID_GD | FILTER_ID_PA | FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_TXT | FILTER_ID_VF,
+ {FILTER_ID_BR | FILTER_ID_GD | FILTER_ID_PA | FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_CF,
"MISC", ICON_GREASEPENCIL, "Miscellaneous", "Show/hide other data types"},
{0, NULL, 0, NULL, NULL}
};
@@ -4284,17 +4338,17 @@ static void rna_def_space_node(BlenderRNA *brna)
prop = RNA_def_property(srna, "id", PROP_POINTER, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "ID", "Datablock whose nodes are being edited");
+ RNA_def_property_ui_text(prop, "ID", "Data-block whose nodes are being edited");
prop = RNA_def_property(srna, "id_from", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "from");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "ID From", "Datablock from which the edited data-block is linked");
+ RNA_def_property_ui_text(prop, "ID From", "Data-block from which the edited data-block is linked");
prop = RNA_def_property(srna, "path", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "treepath", NULL);
RNA_def_property_struct_type(prop, "NodeTreePath");
- RNA_def_property_ui_text(prop, "Node Tree Path", "Path from the data block to the currently edited node tree");
+ RNA_def_property_ui_text(prop, "Node Tree Path", "Path from the data-block to the currently edited node tree");
rna_def_space_node_path_api(brna, prop);
prop = RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c
index a9901fd3a50..2340345c1c6 100644
--- a/source/blender/makesrna/intern/rna_tracking.c
+++ b/source/blender/makesrna/intern/rna_tracking.c
@@ -394,6 +394,16 @@ static int rna_track_2d_stabilization(CollectionPropertyIterator *UNUSED(iter),
return 0;
}
+static int rna_track_2d_stabilization_rotation(CollectionPropertyIterator *UNUSED(iter), void *data)
+{
+ MovieTrackingTrack *track = (MovieTrackingTrack *)data;
+
+ if ((track->flag & TRACK_USE_2D_STAB_ROT) == 0)
+ return 1;
+
+ return 0;
+}
+
static void rna_tracking_stabTracks_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
MovieClip *clip = (MovieClip *)ptr->id.data;
@@ -421,23 +431,36 @@ static void rna_tracking_stabTracks_active_index_range(PointerRNA *ptr, int *min
*max = max_ii(0, clip->tracking.stabilization.tot_track - 1);
}
-static void rna_tracking_resetIntrinsics(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+static void rna_tracking_stabRotTracks_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
MovieClip *clip = (MovieClip *)ptr->id.data;
- MovieTracking *tracking = &clip->tracking;
+ rna_iterator_listbase_begin(iter, &clip->tracking.tracks, rna_track_2d_stabilization_rotation);
+}
- if (tracking->camera.intrinsics) {
- BKE_tracking_distortion_free(tracking->camera.intrinsics);
- tracking->camera.intrinsics = NULL;
- }
+static int rna_tracking_stabRotTracks_active_index_get(PointerRNA *ptr)
+{
+ MovieClip *clip = (MovieClip *)ptr->id.data;
+ return clip->tracking.stabilization.act_rot_track;
}
-static void rna_tracking_flushUpdate(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
+static void rna_tracking_stabRotTracks_active_index_set(PointerRNA *ptr, int value)
+{
+ MovieClip *clip = (MovieClip *)ptr->id.data;
+ clip->tracking.stabilization.act_rot_track = value;
+}
+
+static void rna_tracking_stabRotTracks_active_index_range(PointerRNA *ptr, int *min, int *max,
+ int *UNUSED(softmin), int *UNUSED(softmax))
{
MovieClip *clip = (MovieClip *)ptr->id.data;
- MovieTrackingStabilization *stab = &clip->tracking.stabilization;
- stab->ok = 0;
+ *min = 0;
+ *max = max_ii(0, clip->tracking.stabilization.tot_rot_track - 1);
+}
+
+static void rna_tracking_flushUpdate(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
+{
+ MovieClip *clip = (MovieClip *)ptr->id.data;
nodeUpdateID(scene->nodetree, &clip->id);
@@ -446,6 +469,17 @@ static void rna_tracking_flushUpdate(Main *UNUSED(bmain), Scene *scene, PointerR
DAG_id_tag_update(&clip->id, 0);
}
+static void rna_tracking_resetIntrinsics(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ MovieClip *clip = (MovieClip *)ptr->id.data;
+ MovieTracking *tracking = &clip->tracking;
+
+ if (tracking->camera.intrinsics) {
+ BKE_tracking_distortion_free(tracking->camera.intrinsics);
+ tracking->camera.intrinsics = NULL;
+ }
+}
+
static void rna_trackingObject_tracks_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
MovieTrackingObject *object = (MovieTrackingObject *)ptr->data;
@@ -1495,6 +1529,12 @@ static void rna_def_trackingTrack(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Weight", "Influence of this track on a final solution");
+ /* weight_stab */
+ prop = RNA_def_property(srna, "weight_stab", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "weight_stab");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Stab Weight", "Influence of this track on 2D stabilization");
+
/* offset */
prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_array(prop, 2);
@@ -1634,15 +1674,15 @@ static void rna_def_trackingStabilization(BlenderRNA *brna)
PropertyRNA *prop;
static EnumPropertyItem filter_items[] = {
- {TRACKING_FILTER_NEAREST, "NEAREST", 0, "Nearest", ""},
- {TRACKING_FILTER_BILINEAR, "BILINEAR", 0, "Bilinear", ""},
- {TRACKING_FILTER_BICUBIC, "BICUBIC", 0, "Bicubic", ""},
+ {TRACKING_FILTER_NEAREST, "NEAREST", 0, "Nearest", "No interpolation, use nearest neighbor pixel"},
+ {TRACKING_FILTER_BILINEAR, "BILINEAR", 0, "Bilinear", "Simple interpolation between adjacent pixels"},
+ {TRACKING_FILTER_BICUBIC, "BICUBIC", 0, "Bicubic", "High quality pixel interpolation"},
{0, NULL, 0, NULL, NULL}
};
srna = RNA_def_struct(brna, "MovieTrackingStabilization", NULL);
RNA_def_struct_path_func(srna, "rna_trackingStabilization_path");
- RNA_def_struct_ui_text(srna, "Movie tracking stabilization data", "Match-moving stabilization data for tracking");
+ RNA_def_struct_ui_text(srna, "Movie tracking stabilization data", "2D stabilization based on tracking markers");
/* 2d stabilization */
prop = RNA_def_property(srna, "use_2d_stabilization", PROP_BOOLEAN, PROP_NONE);
@@ -1651,22 +1691,30 @@ static void rna_def_trackingStabilization(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Use 2D stabilization", "Use 2D stabilization for footage");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
+ /* use_stabilize_rotation */
+ prop = RNA_def_property(srna, "use_stabilize_rotation", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", TRACKING_STABILIZE_ROTATION);
+ RNA_def_property_ui_text(prop, "Stabilize Rotation", "Stabilize detected rotation around center of frame");
+ RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
+
+ /* use_stabilize_scale */
+ prop = RNA_def_property(srna, "use_stabilize_scale", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", TRACKING_STABILIZE_SCALE);
+ RNA_def_property_ui_text(prop, "Stabilize Scale", "Compensate any scale changes relative to center of rotation");
+ RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
+
/* tracks */
prop = RNA_def_property(srna, "tracks", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_funcs(prop, "rna_tracking_stabTracks_begin", "rna_iterator_listbase_next",
"rna_iterator_listbase_end", "rna_iterator_listbase_get",
NULL, NULL, NULL, NULL);
RNA_def_property_struct_type(prop, "MovieTrackingTrack");
- RNA_def_property_ui_text(prop, "Tracks", "Collection of tracks used for stabilization");
+ RNA_def_property_ui_text(prop, "Translation Tracks",
+ "Collection of tracks used for 2D stabilization (translation)");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
- /* rotation track */
- prop = RNA_def_property(srna, "rotation_track", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "rot_track");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Rotation Track", "Track used to compensate rotation");
- RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, "rna_tracking_flushUpdate");
-
/* active track index */
prop = RNA_def_property(srna, "active_track_index", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "act_track");
@@ -1674,7 +1722,65 @@ static void rna_def_trackingStabilization(BlenderRNA *brna)
RNA_def_property_int_funcs(prop, "rna_tracking_stabTracks_active_index_get",
"rna_tracking_stabTracks_active_index_set",
"rna_tracking_stabTracks_active_index_range");
- RNA_def_property_ui_text(prop, "Active Track Index", "Index of active track in stabilization tracks list");
+ RNA_def_property_ui_text(prop, "Active Track Index",
+ "Index of active track in translation stabilization tracks list");
+
+ /* tracks used for rotation stabilization */
+ prop = RNA_def_property(srna, "rotation_tracks", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_funcs(prop, "rna_tracking_stabRotTracks_begin", "rna_iterator_listbase_next",
+ "rna_iterator_listbase_end", "rna_iterator_listbase_get",
+ NULL, NULL, NULL, NULL);
+ RNA_def_property_struct_type(prop, "MovieTrackingTrack");
+ RNA_def_property_ui_text(prop, "Rotation Tracks", "Collection of tracks used for 2D stabilization (translation)");
+ RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
+
+ /* active rotation track index */
+ prop = RNA_def_property(srna, "active_rotation_track_index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "act_rot_track");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_int_funcs(prop, "rna_tracking_stabRotTracks_active_index_get",
+ "rna_tracking_stabRotTracks_active_index_set",
+ "rna_tracking_stabRotTracks_active_index_range");
+ RNA_def_property_ui_text(prop, "Active Rotation Track Index",
+ "Index of active track in rotation stabilization tracks list");
+
+ /* anchor frame */
+ prop = RNA_def_property(srna, "anchor_frame", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "anchor_frame");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_range(prop, MINFRAME, MAXFRAME);
+ RNA_def_property_ui_text(prop, "Anchor Frame",
+ "Reference point to anchor stabilization "
+ "(other frames will be adjusted relative to this frame's position)");
+ RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
+
+ /* target position */
+ prop = RNA_def_property(srna, "target_position", PROP_FLOAT, PROP_TRANSLATION);
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, 3); /* increment in steps of 0.01 and show 3 digit after point */
+ RNA_def_property_float_sdna(prop, NULL, "target_pos");
+ RNA_def_property_ui_text(prop, "Expected Position",
+ "Known relative offset of original shot, will be subtracted "
+ "(e.g. for panning shot, can be animated)");
+ RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL);
+
+ /* target rotation */
+ prop = RNA_def_property(srna, "target_rotation", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "target_rot");
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 10.0f, 3);
+ RNA_def_property_ui_text(prop, "Expected Rotation",
+ "Rotation present on original shot, will be compensated (e.g. for deliberate tilting)");
+ RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL);
+
+ /* target scale */
+ prop = RNA_def_property(srna, "target_scale", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "scale");
+ RNA_def_property_range(prop, FLT_EPSILON, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.01f, 10.0f, 0.001f, 3); /* increment in steps of 0.001. Show 3 digit after point */
+ RNA_def_property_ui_text(prop, "Expected Scale",
+ "Explicitly scale resulting frame to compensate zoom of original shot");
+ RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
/* autoscale */
prop = RNA_def_property(srna, "use_autoscale", PROP_BOOLEAN, PROP_NONE);
@@ -1705,13 +1811,6 @@ static void rna_def_trackingStabilization(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Scale Influence", "Influence of stabilization algorithm on footage scale");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
- /* use_stabilize_rotation */
- prop = RNA_def_property(srna, "use_stabilize_rotation", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", TRACKING_STABILIZE_ROTATION);
- RNA_def_property_ui_text(prop, "Stabilize Rotation", "Stabilize horizon line on the shot");
- RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
-
/* influence_rotation */
prop = RNA_def_property(srna, "influence_rotation", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "rotinf");
@@ -1723,8 +1822,16 @@ static void rna_def_trackingStabilization(BlenderRNA *brna)
prop = RNA_def_property(srna, "filter_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "filter");
RNA_def_property_enum_items(prop, filter_items);
- RNA_def_property_ui_text(prop, "Filter", "Method to use to filter stabilization");
+ RNA_def_property_ui_text(prop, "Interpolate",
+ "Interpolation to use for sub-pixel shifts and rotations due to stabilization");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
+
+ /* UI display : show participating tracks */
+ prop = RNA_def_property(srna, "show_tracks_expanded", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", TRACKING_SHOW_STAB_TRACKS);
+ RNA_def_property_ui_text(prop, "Show Tracks", "Show UI list of tracks participating in stabilization");
+ RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1);
}
static void rna_def_reconstructedCamera(BlenderRNA *brna)
@@ -1777,8 +1884,8 @@ static void rna_def_trackingReconstructedCameras(BlenderRNA *brna)
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Return interpolated camera matrix for a given frame");
RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame", "Frame number to find camera for", MINFRAME, MAXFRAME);
- parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, FLT_MIN, FLT_MAX, "Matrix",
- "Interpolated camera matrix for a given frame", FLT_MIN, FLT_MAX);
+ parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, -FLT_MAX, FLT_MAX, "Matrix",
+ "Interpolated camera matrix for a given frame", -FLT_MAX, FLT_MAX);
RNA_def_property_flag(parm, PROP_THICK_WRAP); /* needed for string return value */
RNA_def_function_output(func, parm);
}
@@ -1987,7 +2094,7 @@ static void rna_def_trackingObjects(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_srna(cprop, "MovieTrackingObjects");
srna = RNA_def_struct(brna, "MovieTrackingObjects", NULL);
RNA_def_struct_sdna(srna, "MovieTracking");
- RNA_def_struct_ui_text(srna, "Movie Objects", "Collection of movie trackingobjects");
+ RNA_def_struct_ui_text(srna, "Movie Objects", "Collection of movie tracking objects");
func = RNA_def_function(srna, "new", "rna_trackingObject_new");
RNA_def_function_ui_description(func, "Add tracking object to this movie clip");
diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
index 80777f57811..9d55115a14c 100644
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ b/source/blender/makesrna/intern/rna_ui_api.c
@@ -618,7 +618,7 @@ void RNA_api_ui_layout(StructRNA *srna)
#endif
func = RNA_def_function(srna, "label", "rna_uiItemL");
- RNA_def_function_ui_description(func, "Item. Display text and/or icon in the layout");
+ RNA_def_function_ui_description(func, "Item. Displays text and/or icon in the layout");
api_ui_item_common(func);
parm = RNA_def_property(func, "icon_value", PROP_INT, PROP_UNSIGNED);
RNA_def_property_ui_text(parm, "Icon Value", "Override automatic icon of the item");
@@ -644,6 +644,7 @@ void RNA_api_ui_layout(StructRNA *srna)
/* templates */
func = RNA_def_function(srna, "template_header", "uiTemplateHeader");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Inserts common Space header UI (editor type selector)");
func = RNA_def_function(srna, "template_ID", "uiTemplateID");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
@@ -853,9 +854,12 @@ void RNA_api_ui_layout(StructRNA *srna)
func = RNA_def_function(srna, "template_header_3D", "uiTemplateHeader3D");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Inserts common 3DView header UI (selectors for context mode, shading, etc.)");
+
func = RNA_def_function(srna, "template_edit_mode_selection", "uiTemplateEditModeSelection");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Inserts common 3DView Edit modes header UI (selector for selection mode)");
func = RNA_def_function(srna, "template_reports_banner", "uiTemplateReportsBanner");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
@@ -912,6 +916,11 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_ui_description(func, "Node Socket Icon");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
RNA_def_float_array(func, "color", 4, node_socket_color_default, 0.0f, 1.0f, "Color", "", 0.0f, 1.0f);
+
+ func = RNA_def_function(srna, "template_cache_file", "uiTemplateCacheFile");
+ RNA_def_function_ui_description(func, "Item(s). User interface for selecting cache files and their source paths");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ api_ui_item_rna_common(func);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 0fbc1ce1854..8ad016007f4 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -83,7 +83,7 @@ static EnumPropertyItem audio_device_items[] = {
{2, "OPENAL", 0, "OpenAL", "OpenAL device - supports 3D audio, recommended for game engine usage"},
#endif
#ifdef WITH_JACK
- {3, "JACK", 0, "Jack", "JACK - Audio Connection Kit, recommended for pro audio users"},
+ {3, "JACK", 0, "JACK", "JACK Audio Connection Kit, recommended for pro audio users"},
#endif
{0, NULL, 0, NULL, NULL}
};
@@ -94,6 +94,13 @@ EnumPropertyItem rna_enum_navigation_mode_items[] = {
{0, NULL, 0, NULL, NULL}
};
+#if defined(WITH_INTERNATIONAL) || !defined(RNA_RUNTIME)
+static EnumPropertyItem rna_enum_language_default_items[] = {
+ {0, "DEFAULT", 0, "Default (Default)", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+#endif
+
#ifdef RNA_RUNTIME
#include "DNA_object_types.h"
@@ -285,11 +292,13 @@ static void rna_userdef_autokeymode_set(PointerRNA *ptr, int value)
}
}
+#ifdef WITH_INPUT_NDOF
static void rna_userdef_ndof_deadzone_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
UserDef *userdef = ptr->data;
WM_ndof_deadzone_set(userdef->ndof_deadzone);
}
+#endif
static void rna_userdef_timecode_style_set(PointerRNA *ptr, int value)
{
@@ -408,7 +417,7 @@ static void rna_userdef_addon_remove(ReportList *reports, PointerRNA *path_cmp_p
{
bAddon *bext = path_cmp_ptr->data;
if (BLI_findindex(&U.addons, bext) == -1) {
- BKE_report(reports, RPT_ERROR, "Addon is no longer valid");
+ BKE_report(reports, RPT_ERROR, "Add-on is no longer valid");
return;
}
@@ -642,7 +651,11 @@ static EnumPropertyItem *rna_userdef_audio_device_itemf(bContext *UNUSED(C), Poi
static EnumPropertyItem *rna_lang_enum_properties_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
{
- return BLT_lang_RNA_enum_properties();
+ EnumPropertyItem *items = BLT_lang_RNA_enum_properties();
+ if (items == NULL) {
+ items = rna_enum_language_default_items;
+ }
+ return items;
}
#endif
@@ -705,7 +718,7 @@ static StructRNA *rna_AddonPref_register(Main *bmain, ReportList *reports, void
BLI_strncpy(dummyapt.idname, dummyaddon.module, sizeof(dummyapt.idname));
if (strlen(identifier) >= sizeof(dummyapt.idname)) {
- BKE_reportf(reports, RPT_ERROR, "Registering addon-prefs class: '%s' is too long, maximum length is %d",
+ BKE_reportf(reports, RPT_ERROR, "Registering add-on preferences class: '%s' is too long, maximum length is %d",
identifier, (int)sizeof(dummyapt.idname));
return NULL;
}
@@ -1352,6 +1365,11 @@ static void rna_def_userdef_theme_spaces_vertex(StructRNA *srna)
RNA_def_property_ui_text(prop, "Vertex Size", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+ prop = RNA_def_property(srna, "vertex_bevel", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Vertex Bevel", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
prop = RNA_def_property(srna, "vertex_unreferenced", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Vertex Group Unreferenced", "");
@@ -1382,6 +1400,11 @@ static void rna_def_userdef_theme_spaces_edge(StructRNA *srna)
RNA_def_property_ui_text(prop, "Edge Crease", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+ prop = RNA_def_property(srna, "edge_bevel", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Edge Bevel", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
prop = RNA_def_property(srna, "edge_facesel", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Edge UV Face Select", "");
@@ -1878,37 +1901,12 @@ static void rna_def_userdef_theme_space_file(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Theme File Browser", "Theme settings for the File Browser");
rna_def_userdef_theme_spaces_main(srna);
- rna_def_userdef_theme_spaces_list_main(srna);
prop = RNA_def_property(srna, "selected_file", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "hilite");
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Selected File", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
-
- prop = RNA_def_property(srna, "scrollbar", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "shade1");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Scrollbar", "");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
-
- prop = RNA_def_property(srna, "scroll_handle", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "shade2");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Scroll Handle", "");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
-
- prop = RNA_def_property(srna, "active_file", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "active");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Active File", "");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
-
- prop = RNA_def_property(srna, "active_file_text", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "grid");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Active File Text", "");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
}
static void rna_def_userdef_theme_space_outliner(BlenderRNA *brna)
@@ -2779,6 +2777,13 @@ static void rna_def_userdef_theme_space_action(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Keyframe Border Selected", "Color of selected keyframe border");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+ prop = RNA_def_property(srna, "keyframe_scale_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "keyframe_scale_fac");
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Keyframe Scale Factor", "Scale factor for adjusting the height of keyframes");
+ RNA_def_property_range(prop, 0.8f, 5.0f); /* Note: These limits prevent buttons overlapping (min), and excessive size... (max) */
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_DOPESHEET, "rna_userdef_update");
+
prop = RNA_def_property(srna, "summary", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "anim_active");
@@ -2815,13 +2820,13 @@ static void rna_def_userdef_theme_space_nla(BlenderRNA *brna)
prop = RNA_def_property(srna, "active_action", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "anim_active");
RNA_def_property_array(prop, 4);
- RNA_def_property_ui_text(prop, "Active Action", "Animation data block has active action");
+ RNA_def_property_ui_text(prop, "Active Action", "Animation data-block has active action");
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop = RNA_def_property(srna, "active_action_unset", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "anim_non_active");
RNA_def_property_array(prop, 4);
- RNA_def_property_ui_text(prop, "No Active Action", "Animation data block doesn't have active action");
+ RNA_def_property_ui_text(prop, "No Active Action", "Animation data-block doesn't have active action");
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop = RNA_def_property(srna, "strips", PROP_FLOAT, PROP_COLOR_GAMMA);
@@ -3195,7 +3200,7 @@ static void rna_def_userdef_addon(BlenderRNA *brna)
srna = RNA_def_struct(brna, "Addon", NULL);
RNA_def_struct_sdna(srna, "bAddon");
RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
- RNA_def_struct_ui_text(srna, "Addon", "Python addons to be loaded automatically");
+ RNA_def_struct_ui_text(srna, "Add-on", "Python add-ons to be loaded automatically");
prop = RNA_def_property(srna, "module", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Module", "Module name");
@@ -3232,7 +3237,7 @@ static void rna_def_userdef_addon_pref(BlenderRNA *brna)
PropertyRNA *prop;
srna = RNA_def_struct(brna, "AddonPreferences", NULL);
- RNA_def_struct_ui_text(srna, "Addon Preferences", "");
+ RNA_def_struct_ui_text(srna, "Add-on Preferences", "");
RNA_def_struct_sdna(srna, "bAddon"); /* WARNING: only a bAddon during registration */
RNA_def_struct_refine_func(srna, "rna_AddonPref_refine");
@@ -3971,11 +3976,6 @@ static void rna_def_userdef_system(BlenderRNA *brna)
{USER_MULTISAMPLE_16, "16", 0, "MultiSample: 16", "Use 16x OpenGL MultiSample (requires restart)"},
{0, NULL, 0, NULL, NULL}
};
-
- static EnumPropertyItem language_items[] = {
- {0, "DEFAULT", 0, "Default (Default)", ""},
- {0, NULL, 0, NULL, NULL}
- };
#ifdef WITH_CYCLES
static EnumPropertyItem compute_device_items[] = {
@@ -4058,7 +4058,7 @@ static void rna_def_userdef_system(BlenderRNA *brna)
/* Language Selection */
prop = RNA_def_property(srna, "language", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, language_items);
+ RNA_def_property_enum_items(prop, rna_enum_language_default_items);
#ifdef WITH_INTERNATIONAL
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_lang_enum_properties_itemf");
#endif
@@ -4320,6 +4320,7 @@ static void rna_def_userdef_input(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+#ifdef WITH_INPUT_NDOF
static EnumPropertyItem ndof_view_navigation_items[] = {
{0, "FREE", 0, "Free", "Use full 6 degrees of freedom by default"},
{NDOF_MODE_ORBIT, "ORBIT", 0, "Orbit", "Orbit about the view center by default"},
@@ -4331,6 +4332,7 @@ static void rna_def_userdef_input(BlenderRNA *brna)
{0, "TRACKBALL", 0, "Trackball", "Use trackball style rotation in the viewport"},
{0, NULL, 0, NULL, NULL}
};
+#endif /* WITH_INPUT_NDOF */
static EnumPropertyItem view_zoom_styles[] = {
{USER_ZOOM_CONT, "CONTINUE", 0, "Continue", "Old style zoom, continues while moving mouse up or down"},
@@ -4408,6 +4410,7 @@ static void rna_def_userdef_input(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Tweak Threshold",
"Number of pixels you have to drag before tweak event is triggered");
+#ifdef WITH_INPUT_NDOF
/* 3D mouse settings */
/* global options */
prop = RNA_def_property(srna, "ndof_sensitivity", PROP_FLOAT, PROP_NONE);
@@ -4488,6 +4491,13 @@ static void rna_def_userdef_input(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "ndof_flag", NDOF_FLY_HELICOPTER);
RNA_def_property_ui_text(prop, "Helicopter Mode", "Device up/down directly controls your Z position");
+ /* let Python know whether NDOF is enabled */
+ prop = RNA_def_boolean(srna, "use_ndof", true, "", "");
+#else
+ prop = RNA_def_boolean(srna, "use_ndof", false, "", "");
+#endif /* WITH_INPUT_NDOF */
+ RNA_def_property_flag(prop, PROP_IDPROPERTY);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "mouse_double_click_time", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "dbl_click_time");
@@ -4551,7 +4561,7 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_hidden_files_datablocks", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_HIDE_DOT);
- RNA_def_property_ui_text(prop, "Hide Dot Files/Datablocks", "Hide files/data-blocks that start with a dot (.*)");
+ RNA_def_property_ui_text(prop, "Hide Dot Files/Data-Blocks", "Hide files/data-blocks that start with a dot (.*)");
prop = RNA_def_property(srna, "use_filter_files", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_FILTERFILEEXTS);
@@ -4600,7 +4610,7 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna)
RNA_def_property_string_sdna(prop, NULL, "pythondir");
RNA_def_property_ui_text(prop, "Python Scripts Directory",
"Alternate script path, matching the default layout with subdirs: "
- "startup, addons & modules (requires restart)");
+ "startup, add-ons & modules (requires restart)");
/* TODO, editing should reset sys.path! */
prop = RNA_def_property(srna, "i18n_branches_directory", PROP_STRING, PROP_DIRPATH);
@@ -4692,7 +4702,7 @@ static void rna_def_userdef_addon_collection(BlenderRNA *brna, PropertyRNA *cpro
func = RNA_def_function(srna, "remove", "rna_userdef_addon_remove");
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove add-on");
- parm = RNA_def_pointer(func, "addon", "Addon", "", "Addon to remove");
+ parm = RNA_def_pointer(func, "addon", "Addon", "", "Add-on to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
}
@@ -4768,7 +4778,7 @@ void RNA_def_userdef(BlenderRNA *brna)
prop = RNA_def_property(srna, "addons", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "addons", NULL);
RNA_def_property_struct_type(prop, "Addon");
- RNA_def_property_ui_text(prop, "Addon", "");
+ RNA_def_property_ui_text(prop, "Add-on", "");
rna_def_userdef_addon_collection(brna, prop);
prop = RNA_def_property(srna, "autoexec_paths", PROP_COLLECTION, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_vfont.c b/source/blender/makesrna/intern/rna_vfont.c
index e9ba0c78439..c743751649c 100644
--- a/source/blender/makesrna/intern/rna_vfont.c
+++ b/source/blender/makesrna/intern/rna_vfont.c
@@ -44,7 +44,7 @@
#include "WM_api.h"
/* matching fnction in rna_ID.c */
-static int rna_VectorFont_filepath_editable(PointerRNA *ptr)
+static int rna_VectorFont_filepath_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
VFont *vfont = ptr->id.data;
if (BKE_vfont_is_builtin(vfont)) {
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index 0d11414c878..90081a93188 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -167,7 +167,7 @@ static EnumPropertyItem event_ndof_type_items[] = {
{NDOF_BUTTON_C, "NDOF_BUTTON_C", 0, "Button C", ""},
{0, NULL, 0, NULL, NULL}
};
-#endif
+#endif /* RNA_RUNTIME */
/* not returned: CAPSLOCKKEY, UNKNOWNKEY */
EnumPropertyItem rna_enum_event_type_items[] = {
@@ -469,13 +469,15 @@ EnumPropertyItem rna_enum_wm_report_items[] = {
static wmOperator *rna_OperatorProperties_find_operator(PointerRNA *ptr)
{
wmWindowManager *wm = ptr->id.data;
- IDProperty *properties = (IDProperty *)ptr->data;
- wmOperator *op;
- if (wm)
- for (op = wm->operators.first; op; op = op->next)
- if (op->properties == properties)
+ if (wm) {
+ IDProperty *properties = (IDProperty *)ptr->data;
+ for (wmOperator *op = wm->operators.last; op; op = op->prev) {
+ if (op->properties == properties) {
return op;
+ }
+ }
+ }
return NULL;
}
@@ -1933,15 +1935,15 @@ static void rna_def_wm_keyconfigs(BlenderRNA *brna, PropertyRNA *cprop)
prop = RNA_def_property(srna, "addon", PROP_POINTER, PROP_NEVER_NULL);
RNA_def_property_pointer_sdna(prop, NULL, "addonconf");
RNA_def_property_struct_type(prop, "KeyConfig");
- RNA_def_property_ui_text(prop, "Addon Key Configuration",
- "Key configuration that can be extended by addons, and is added to the active "
+ RNA_def_property_ui_text(prop, "Add-on Key Configuration",
+ "Key configuration that can be extended by add-ons, and is added to the active "
"configuration when handling events");
prop = RNA_def_property(srna, "user", PROP_POINTER, PROP_NEVER_NULL);
RNA_def_property_pointer_sdna(prop, NULL, "userconf");
RNA_def_property_struct_type(prop, "KeyConfig");
RNA_def_property_ui_text(prop, "User Key Configuration",
- "Final key configuration that combines keymaps from the active and addon configurations, "
+ "Final key configuration that combines keymaps from the active and add-on configurations, "
"and can be edited by the user");
RNA_api_keyconfigs(srna);
diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c
index 7cf0cf67269..8d0b704a402 100644
--- a/source/blender/makesrna/intern/rna_wm_api.c
+++ b/source/blender/makesrna/intern/rna_wm_api.c
@@ -398,18 +398,21 @@ void RNA_api_wm(StructRNA *srna)
rna_generic_op_invoke(func, 0);
func = RNA_def_function(srna, "modal_handler_add", "rna_event_modal_handler_add");
+ RNA_def_function_ui_description(func, "Add a modal handler to the window manager, for the given modal operator "
+ "(called by invoke() with self, just before returning {'RUNNING_MODAL'})");
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "operator", "Operator", "", "Operator to call");
RNA_def_property_flag(parm, PROP_REQUIRED);
- RNA_def_function_return(func, RNA_def_boolean(func, "handle", 1, "", ""));
+ RNA_def_function_return(func, RNA_def_boolean(func, "handle", 1, "", "Whether adding the handler was successful"));
func = RNA_def_function(srna, "event_timer_add", "rna_event_timer_add");
+ RNA_def_function_ui_description(func, "Add a timer to the given window, to generate periodic 'TIMER' events");
parm = RNA_def_property(func, "time_step", PROP_FLOAT, PROP_NONE);
RNA_def_property_flag(parm, PROP_REQUIRED);
RNA_def_property_range(parm, 0.0, FLT_MAX);
RNA_def_property_ui_text(parm, "Time Step", "Interval in seconds between timer events");
- RNA_def_pointer(func, "window", "Window", "", "Window to attach the timer to or None");
+ RNA_def_pointer(func, "window", "Window", "", "Window to attach the timer to, or None");
parm = RNA_def_pointer(func, "result", "Timer", "", "");
RNA_def_function_return(func, parm);
@@ -421,44 +424,49 @@ void RNA_api_wm(StructRNA *srna)
/* Progress bar interface */
func = RNA_def_function(srna, "progress_begin", "rna_progress_begin");
RNA_def_function_ui_description(func, "Start progress report");
-
parm = RNA_def_property(func, "min", PROP_FLOAT, PROP_NONE);
RNA_def_property_ui_text(parm, "min", "any value in range [0,9999]");
RNA_def_property_flag(parm, PROP_REQUIRED);
-
parm = RNA_def_property(func, "max", PROP_FLOAT, PROP_NONE);
RNA_def_property_flag(parm, PROP_REQUIRED);
RNA_def_property_ui_text(parm, "max", "any value in range [min+1,9998]");
func = RNA_def_function(srna, "progress_update", "rna_progress_update");
+ RNA_def_function_ui_description(func, "Update the progress feedback");
parm = RNA_def_property(func, "value", PROP_FLOAT, PROP_NONE);
RNA_def_property_flag(parm, PROP_REQUIRED);
- RNA_def_property_ui_text(parm, "value", "any value between min and max as set in progress_begin()");
+ RNA_def_property_ui_text(parm, "value", "Any value between min and max as set in progress_begin()");
func = RNA_def_function(srna, "progress_end", "rna_progress_end");
RNA_def_function_ui_description(func, "Terminate progress report");
/* invoke functions, for use with python */
func = RNA_def_function(srna, "invoke_props_popup", "rna_Operator_props_popup");
- RNA_def_function_ui_description(func, "Operator popup invoke");
+ RNA_def_function_ui_description(func, "Operator popup invoke "
+ "(show operator properties and execute it automatically on changes)");
rna_generic_op_invoke(func, WM_GEN_INVOKE_EVENT | WM_GEN_INVOKE_RETURN);
/* invoked dialog opens popup with OK button, does not auto-exec operator. */
func = RNA_def_function(srna, "invoke_props_dialog", "WM_operator_props_dialog_popup");
- RNA_def_function_ui_description(func, "Operator dialog (non-autoexec popup) invoke");
+ RNA_def_function_ui_description(func, "Operator dialog (non-autoexec popup) invoke "
+ "(show operator properties and only execute it on click on OK button)");
rna_generic_op_invoke(func, WM_GEN_INVOKE_SIZE | WM_GEN_INVOKE_RETURN);
/* invoke enum */
func = RNA_def_function(srna, "invoke_search_popup", "rna_Operator_enum_search_invoke");
+ RNA_def_function_ui_description(func, "Operator search popup invoke (search in values of "
+ "operator's type 'prop' EnumProperty, and execute it on confirmation)");
rna_generic_op_invoke(func, 0);
/* invoke functions, for use with python */
func = RNA_def_function(srna, "invoke_popup", "WM_operator_ui_popup");
- RNA_def_function_ui_description(func, "Operator popup invoke");
+ RNA_def_function_ui_description(func, "Operator popup invoke "
+ "(only shows operator's properties, without executing it)");
rna_generic_op_invoke(func, WM_GEN_INVOKE_SIZE | WM_GEN_INVOKE_RETURN);
func = RNA_def_function(srna, "invoke_confirm", "rna_Operator_confirm");
- RNA_def_function_ui_description(func, "Operator confirmation");
+ RNA_def_function_ui_description(func, "Operator confirmation popup "
+ "(only to let user confirm the execution, no operator properties shown)");
rna_generic_op_invoke(func, WM_GEN_INVOKE_EVENT | WM_GEN_INVOKE_RETURN);
diff --git a/source/blender/makesrna/intern/rna_world.c b/source/blender/makesrna/intern/rna_world.c
index f950ba75c42..7c1ef6b0d87 100644
--- a/source/blender/makesrna/intern/rna_world.c
+++ b/source/blender/makesrna/intern/rna_world.c
@@ -102,8 +102,7 @@ static void rna_World_draw_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poi
}
#endif
-/* so camera mist limits redraw */
-static void rna_World_draw_mist_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+static void rna_World_draw_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
World *wo = ptr->id.data;
@@ -264,19 +263,19 @@ static void rna_def_lighting(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_environment_light", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", WO_ENV_LIGHT);
RNA_def_property_ui_text(prop, "Use Environment Lighting", "Add light coming from the environment");
- RNA_def_property_update(prop, 0, "rna_World_update");
+ RNA_def_property_update(prop, 0, "rna_World_draw_update");
prop = RNA_def_property(srna, "environment_energy", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "ao_env_energy");
RNA_def_property_ui_range(prop, 0, FLT_MAX, 1, 3);
RNA_def_property_ui_text(prop, "Environment Color", "Defines the strength of environment light");
- RNA_def_property_update(prop, 0, "rna_World_update");
+ RNA_def_property_update(prop, 0, "rna_World_draw_update");
prop = RNA_def_property(srna, "environment_color", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "aocolor");
RNA_def_property_enum_items(prop, prop_color_items);
RNA_def_property_ui_text(prop, "Environment Color", "Defines where the color of the environment light comes from");
- RNA_def_property_update(prop, 0, "rna_World_update");
+ RNA_def_property_update(prop, 0, "rna_World_draw_update");
/* indirect lighting */
prop = RNA_def_property(srna, "use_indirect_light", PROP_BOOLEAN, PROP_NONE);
@@ -405,27 +404,27 @@ static void rna_def_world_mist(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_mist", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", WO_MIST);
RNA_def_property_ui_text(prop, "Use Mist", "Occlude objects with the environment color as they are further away");
- RNA_def_property_update(prop, 0, "rna_World_draw_mist_update");
+ RNA_def_property_update(prop, 0, "rna_World_draw_update");
prop = RNA_def_property(srna, "intensity", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "misi");
RNA_def_property_range(prop, 0, 1);
RNA_def_property_ui_text(prop, "Minimum", "Overall minimum intensity of the mist effect");
- RNA_def_property_update(prop, 0, "rna_World_draw_mist_update");
+ RNA_def_property_update(prop, 0, "rna_World_draw_update");
prop = RNA_def_property(srna, "start", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "miststa");
RNA_def_property_range(prop, 0, FLT_MAX);
RNA_def_property_ui_range(prop, 0, 10000, 10, 2);
RNA_def_property_ui_text(prop, "Start", "Starting distance of the mist, measured from the camera");
- RNA_def_property_update(prop, 0, "rna_World_draw_mist_update");
+ RNA_def_property_update(prop, 0, "rna_World_draw_update");
prop = RNA_def_property(srna, "depth", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "mistdist");
RNA_def_property_range(prop, 0, FLT_MAX);
RNA_def_property_ui_range(prop, 0, 10000, 10, 2);
RNA_def_property_ui_text(prop, "Depth", "Distance over which the mist effect fades in");
- RNA_def_property_update(prop, 0, "rna_World_draw_mist_update");
+ RNA_def_property_update(prop, 0, "rna_World_draw_update");
prop = RNA_def_property(srna, "height", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "misthi");
@@ -437,7 +436,7 @@ static void rna_def_world_mist(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "mistype");
RNA_def_property_enum_items(prop, falloff_items);
RNA_def_property_ui_text(prop, "Falloff", "Type of transition used to fade mist");
- RNA_def_property_update(prop, 0, "rna_World_draw_mist_update");
+ RNA_def_property_update(prop, 0, "rna_World_draw_update");
}
void RNA_def_world(BlenderRNA *brna)
@@ -462,19 +461,19 @@ void RNA_def_world(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Horizon Color", "Color at the horizon");
/* RNA_def_property_update(prop, 0, "rna_World_update"); */
/* render-only uses this */
- RNA_def_property_update(prop, 0, "rna_World_draw_mist_update");
+ RNA_def_property_update(prop, 0, "rna_World_draw_update");
prop = RNA_def_property(srna, "zenith_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "zenr");
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Zenith Color", "Color at the zenith");
- RNA_def_property_update(prop, NC_WORLD | ND_WORLD_DRAW, "rna_World_update");
+ RNA_def_property_update(prop, 0, "rna_World_draw_update");
prop = RNA_def_property(srna, "ambient_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "ambr");
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Ambient Color", "Ambient color of the world");
- RNA_def_property_update(prop, 0, "rna_World_draw_mist_update");
+ RNA_def_property_update(prop, 0, "rna_World_draw_update");
/* exp, range */
prop = RNA_def_property(srna, "exposure", PROP_FLOAT, PROP_NONE);
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index 0de7676e8f8..b8ebb375a48 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -73,6 +73,7 @@ set(SRC
intern/MOD_meshcache_pc2.c
intern/MOD_meshcache_util.c
intern/MOD_meshdeform.c
+ intern/MOD_meshsequencecache.c
intern/MOD_mirror.c
intern/MOD_multires.c
intern/MOD_none.c
@@ -112,6 +113,13 @@ set(SRC
intern/MOD_weightvg_util.h
)
+if(WITH_ALEMBIC)
+ add_definitions(-DWITH_ALEMBIC)
+ list(APPEND INC
+ ../alembic
+ )
+endif()
+
if(WITH_MOD_BOOLEAN)
add_definitions(-DWITH_MOD_BOOLEAN)
list(APPEND SRC
diff --git a/source/blender/modifiers/MOD_modifiertypes.h b/source/blender/modifiers/MOD_modifiertypes.h
index a5d96759952..4c881445893 100644
--- a/source/blender/modifiers/MOD_modifiertypes.h
+++ b/source/blender/modifiers/MOD_modifiertypes.h
@@ -84,6 +84,7 @@ extern ModifierTypeInfo modifierType_Wireframe;
extern ModifierTypeInfo modifierType_DataTransfer;
extern ModifierTypeInfo modifierType_NormalEdit;
extern ModifierTypeInfo modifierType_CorrectiveSmooth;
+extern ModifierTypeInfo modifierType_MeshSequenceCache;
/* MOD_util.c */
void modifier_type_init(ModifierTypeInfo *types[]);
diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c
index 2241a787630..567505ea45d 100644
--- a/source/blender/modifiers/intern/MOD_armature.c
+++ b/source/blender/modifiers/intern/MOD_armature.c
@@ -207,6 +207,7 @@ ModifierTypeInfo modifierType_Armature = {
/* structSize */ sizeof(ArmatureModifierData),
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsCVs |
+ eModifierTypeFlag_AcceptsLattice |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c
index 1fcf4c5ec79..da0f5aa3923 100644
--- a/source/blender/modifiers/intern/MOD_boolean.c
+++ b/source/blender/modifiers/intern/MOD_boolean.c
@@ -33,7 +33,7 @@
*/
// #ifdef DEBUG_TIME
-// #define USE_BMESH
+#define USE_BMESH
#ifdef WITH_MOD_BOOLEAN
# define USE_CARVE WITH_MOD_BOOLEAN
#endif
@@ -71,6 +71,14 @@
#include "PIL_time_utildefines.h"
#endif
+static void initData(ModifierData *md)
+{
+ BooleanModifierData *bmd = (BooleanModifierData *)md;
+
+ bmd->solver = eBooleanModifierSolver_BMesh;
+ bmd->double_threshold = 1e-6f;
+}
+
static void copyData(ModifierData *md, ModifierData *target)
{
#if 0
@@ -222,7 +230,9 @@ static DerivedMesh *applyModifier_bmesh(
#ifdef DEBUG_TIME
TIMEIT_START(boolean_bmesh);
#endif
- bm = BM_mesh_create(&allocsize);
+ bm = BM_mesh_create(
+ &allocsize,
+ &((struct BMeshCreateParams){.use_toolflags = false,}));
DM_to_bmesh_ex(dm_other, bm, true);
DM_to_bmesh_ex(dm, bm, true);
@@ -296,16 +306,21 @@ static DerivedMesh *applyModifier_bmesh(
* currently this is ok for 'BM_mesh_intersect' */
// BM_mesh_normals_update(bm);
+ /* change for testing */
+ bool use_separate = false;
+ bool use_dissolve = true;
+ bool use_island_connect = true;
+
BM_mesh_intersect(
bm,
looptris, tottri,
bm_face_isect_pair, NULL,
false,
- (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_Separate) != 0,
- (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_NoDissolve) == 0,
- (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_NoConnectRegions) == 0,
+ use_separate,
+ use_dissolve,
+ use_island_connect,
bmd->operation,
- bmd->threshold);
+ bmd->double_threshold);
MEM_freeN(looptris);
}
@@ -409,15 +424,14 @@ static DerivedMesh *applyModifier(
ModifierApplyFlag flag)
{
BooleanModifierData *bmd = (BooleanModifierData *)md;
- const int method = (bmd->bm_flag & eBooleanModifierBMeshFlag_Enabled) ? 1 : 0;
- switch (method) {
+ switch (bmd->solver) {
#ifdef USE_CARVE
- case 0:
+ case eBooleanModifierSolver_Carve:
return applyModifier_carve(md, ob, derivedData, flag);
#endif
#ifdef USE_BMESH
- case 1:
+ case eBooleanModifierSolver_BMesh:
return applyModifier_bmesh(md, ob, derivedData, flag);
#endif
default:
@@ -441,7 +455,7 @@ ModifierTypeInfo modifierType_Boolean = {
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
/* applyModifierEM */ NULL,
- /* initData */ NULL,
+ /* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ isDisabled,
diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c
index 32c3d41c4b6..33e5b3615d9 100644
--- a/source/blender/modifiers/intern/MOD_cast.c
+++ b/source/blender/modifiers/intern/MOD_cast.c
@@ -498,6 +498,7 @@ ModifierTypeInfo modifierType_Cast = {
/* structSize */ sizeof(CastModifierData),
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsCVs |
+ eModifierTypeFlag_AcceptsLattice |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c
index 6cc2f097be8..d15a6fcb1c8 100644
--- a/source/blender/modifiers/intern/MOD_cloth.c
+++ b/source/blender/modifiers/intern/MOD_cloth.c
@@ -123,19 +123,11 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
{
ClothModifierData *clmd = (ClothModifierData *) md;
- Base *base;
-
if (clmd) {
- for (base = scene->base.first; base; base = base->next) {
- Object *ob1 = base->object;
- if (ob1 != ob) {
- CollisionModifierData *coll_clmd = (CollisionModifierData *)modifiers_findByType(ob1, eModifierType_Collision);
- if (coll_clmd) {
- DagNode *curNode = dag_get_node(forest, ob1);
- dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Cloth Collision");
- }
- }
- }
+ /* Actual code uses get_collisionobjects */
+ dag_add_collision_relations(forest, scene, ob, obNode, clmd->coll_parms->group, ob->lay|scene->lay, eModifierType_Collision, NULL, true, "Cloth Collision");
+
+ dag_add_forcefield_relations(forest, scene, ob, obNode, clmd->sim_parms->effector_weights, true, 0, "Cloth Field");
}
}
@@ -147,16 +139,10 @@ static void updateDepsgraph(ModifierData *md,
{
ClothModifierData *clmd = (ClothModifierData *)md;
if (clmd != NULL) {
- Base *base;
- for (base = scene->base.first; base; base = base->next) {
- Object *ob1 = base->object;
- if (ob1 != ob) {
- CollisionModifierData *coll_clmd = (CollisionModifierData *)modifiers_findByType(ob1, eModifierType_Collision);
- if (coll_clmd) {
- DEG_add_object_relation(node, ob1, DEG_OB_COMP_TRANSFORM, "Cloth Modifier");
- }
- }
- }
+ /* Actual code uses get_collisionobjects */
+ DEG_add_collision_relations(node, scene, ob, clmd->coll_parms->group, ob->lay|scene->lay, eModifierType_Collision, NULL, true, "Cloth Collision");
+
+ DEG_add_forcefield_relations(node, scene, ob, clmd->sim_parms->effector_weights, true, 0, "Cloth Field");
}
}
diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c
index ff0c6500479..e7ff0a90fbc 100644
--- a/source/blender/modifiers/intern/MOD_collision.c
+++ b/source/blender/modifiers/intern/MOD_collision.c
@@ -60,6 +60,7 @@ static void initData(ModifierData *md)
collmd->time_x = collmd->time_xnew = -1000;
collmd->mvert_num = 0;
collmd->tri_num = 0;
+ collmd->is_static = false;
collmd->bvhtree = NULL;
}
@@ -87,6 +88,7 @@ static void freeData(ModifierData *md)
collmd->time_x = collmd->time_xnew = -1000;
collmd->mvert_num = 0;
collmd->tri_num = 0;
+ collmd->is_static = false;
}
}
@@ -169,6 +171,7 @@ static void deformVerts(ModifierData *md, Object *ob,
ob->pd->pdef_sboft);
collmd->time_x = collmd->time_xnew = current_time;
+ collmd->is_static = true;
}
else if (mvert_num == collmd->mvert_num) {
/* put positions to old positions */
@@ -179,14 +182,19 @@ static void deformVerts(ModifierData *md, Object *ob,
memcpy(collmd->xnew, dm->getVertArray(dm), mvert_num * sizeof(MVert));
+ bool is_static = true;
+
for (i = 0; i < mvert_num; i++) {
/* we save global positions */
mul_m4_v3(ob->obmat, collmd->xnew[i].co);
+
+ /* detect motion */
+ is_static = is_static && equals_v3v3(collmd->x[i].co, collmd->xnew[i].co);
}
-
+
memcpy(collmd->current_xnew, collmd->x, mvert_num * sizeof(MVert));
memcpy(collmd->current_x, collmd->x, mvert_num * sizeof(MVert));
-
+
/* check if GUI setting has changed for bvh */
if (collmd->bvhtree) {
if (ob->pd->pdef_sboft != BLI_bvhtree_get_epsilon(collmd->bvhtree)) {
@@ -206,7 +214,7 @@ static void deformVerts(ModifierData *md, Object *ob,
collmd->tri, collmd->tri_num,
ob->pd->pdef_sboft);
}
- else {
+ else if (!collmd->is_static || !is_static) {
/* recalc static bounding boxes */
bvhtree_update_from_mvert(
collmd->bvhtree,
@@ -214,7 +222,8 @@ static void deformVerts(ModifierData *md, Object *ob,
collmd->tri, collmd->tri_num,
true);
}
-
+
+ collmd->is_static = is_static;
collmd->time_xnew = current_time;
}
else if (mvert_num != collmd->mvert_num) {
diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c
index 4046620592b..77fd84a2948 100644
--- a/source/blender/modifiers/intern/MOD_correctivesmooth.c
+++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c
@@ -1,29 +1,29 @@
/*
-* ***** BEGIN GPL LICENSE BLOCK *****
-*
-* This program is free software; you can redistribute it and/or
-* modify it under the terms of the GNU General Public License
-* as published by the Free Software Foundation; either version 2
-* of the License, or (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program; if not, write to the Free Software Foundation,
-* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*
-* The Original Code is Copyright (C) 2015 by the Blender Foundation.
-* All rights reserved.
-*
-* Contributor(s): Jack Simpson,
-* Campbell Barton
-*
-* ***** END GPL LICENSE BLOCK *****
-*
-*/
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 by the Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Jack Simpson,
+ * Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
/** \file blender/modifiers/intern/MOD_correctivesmooth.c
* \ingroup modifiers
@@ -319,7 +319,7 @@ static void smooth_iter__length_weight(
/* fast-path */
for (i = 0; i < numVerts; i++) {
struct SmoothingData_Weighted *sd = &smooth_data[i];
- /* divide by sum of all neighbour distances (weighted) and amount of neighbours, (mean average) */
+ /* divide by sum of all neighbour distances (weighted) and amount of neighbors, (mean average) */
const float div = sd->edge_length_sum * vertex_edge_count[i];
if (div > eps) {
#if 0
diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c
index 6e2d746c858..9bc96e593fd 100644
--- a/source/blender/modifiers/intern/MOD_curve.c
+++ b/source/blender/modifiers/intern/MOD_curve.c
@@ -164,6 +164,7 @@ ModifierTypeInfo modifierType_Curve = {
/* structSize */ sizeof(CurveModifierData),
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsCVs |
+ eModifierTypeFlag_AcceptsLattice |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c
index 9ba2d214d50..059e096ddb4 100644
--- a/source/blender/modifiers/intern/MOD_displace.c
+++ b/source/blender/modifiers/intern/MOD_displace.c
@@ -46,6 +46,7 @@
#include "BKE_modifier.h"
#include "BKE_texture.h"
#include "BKE_deform.h"
+#include "BKE_object.h"
#include "depsgraph_private.h"
#include "MEM_guardedalloc.h"
@@ -65,6 +66,7 @@ static void initData(ModifierData *md)
dmd->strength = 1;
dmd->direction = MOD_DISP_DIR_NOR;
dmd->midlevel = 0.5;
+ dmd->space = MOD_DISP_SPACE_LOCAL;
}
static void copyData(ModifierData *md, ModifierData *target)
@@ -171,10 +173,13 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
- if (dmd->texmapping == MOD_DISP_MAP_GLOBAL)
+ if (dmd->texmapping == MOD_DISP_MAP_GLOBAL ||
+ (ELEM(dmd->direction, MOD_DISP_DIR_X, MOD_DISP_DIR_Y, MOD_DISP_DIR_Z, MOD_DISP_DIR_RGB_XYZ) &&
+ dmd->space == MOD_DISP_SPACE_GLOBAL))
+ {
dag_add_relation(forest, obNode, obNode,
DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Displace Modifier");
-
+ }
}
static void updateDepsgraph(ModifierData *md,
@@ -187,7 +192,10 @@ static void updateDepsgraph(ModifierData *md,
if (dmd->map_object != NULL && dmd->texmapping == MOD_DISP_MAP_OBJECT) {
DEG_add_object_relation(node, dmd->map_object, DEG_OB_COMP_TRANSFORM, "Displace Modifier");
}
- if (dmd->texmapping == MOD_DISP_MAP_GLOBAL) {
+ if (dmd->texmapping == MOD_DISP_MAP_GLOBAL ||
+ (ELEM(dmd->direction, MOD_DISP_DIR_X, MOD_DISP_DIR_Y, MOD_DISP_DIR_Z, MOD_DISP_DIR_RGB_XYZ) &&
+ dmd->space == MOD_DISP_SPACE_GLOBAL))
+ {
DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "Displace Modifier");
}
}
@@ -206,6 +214,8 @@ static void displaceModifier_do(
float weight = 1.0f; /* init value unused but some compilers may complain */
const float delta_fixed = 1.0f - dmd->midlevel; /* when no texture is used, we fallback to white */
float (*vert_clnors)[3] = NULL;
+ float local_mat[4][4];
+ const bool use_global_direction = dmd->space == MOD_DISP_SPACE_GLOBAL;
if (!dmd->texture && dmd->direction == MOD_DISP_DIR_RGB_XYZ) return;
if (dmd->strength == 0.0f) return;
@@ -243,11 +253,17 @@ static void displaceModifier_do(
direction = MOD_DISP_DIR_NOR;
}
}
+ else if (ELEM(direction, MOD_DISP_DIR_X, MOD_DISP_DIR_Y, MOD_DISP_DIR_Z, MOD_DISP_DIR_RGB_XYZ) &&
+ use_global_direction)
+ {
+ copy_m4_m4(local_mat, ob->obmat);
+ }
for (i = 0; i < numVerts; i++) {
TexResult texres;
float strength = dmd->strength;
float delta;
+ float local_vec[3];
if (dvert) {
weight = defvert_find_weight(dvert + i, defgrp_index);
@@ -270,18 +286,44 @@ static void displaceModifier_do(
switch (direction) {
case MOD_DISP_DIR_X:
- vertexCos[i][0] += delta;
+ if (use_global_direction) {
+ vertexCos[i][0] += delta * local_mat[0][0];
+ vertexCos[i][1] += delta * local_mat[1][0];
+ vertexCos[i][2] += delta * local_mat[2][0];
+ }
+ else {
+ vertexCos[i][0] += delta;
+ }
break;
case MOD_DISP_DIR_Y:
- vertexCos[i][1] += delta;
+ if (use_global_direction) {
+ vertexCos[i][0] += delta * local_mat[0][1];
+ vertexCos[i][1] += delta * local_mat[1][1];
+ vertexCos[i][2] += delta * local_mat[2][1];
+ }
+ else {
+ vertexCos[i][1] += delta;
+ }
break;
case MOD_DISP_DIR_Z:
- vertexCos[i][2] += delta;
+ if (use_global_direction) {
+ vertexCos[i][0] += delta * local_mat[0][2];
+ vertexCos[i][1] += delta * local_mat[1][2];
+ vertexCos[i][2] += delta * local_mat[2][2];
+ }
+ else {
+ vertexCos[i][2] += delta;
+ }
break;
case MOD_DISP_DIR_RGB_XYZ:
- vertexCos[i][0] += (texres.tr - dmd->midlevel) * strength;
- vertexCos[i][1] += (texres.tg - dmd->midlevel) * strength;
- vertexCos[i][2] += (texres.tb - dmd->midlevel) * strength;
+ local_vec[0] = texres.tr - dmd->midlevel;
+ local_vec[1] = texres.tg - dmd->midlevel;
+ local_vec[2] = texres.tb - dmd->midlevel;
+ if (use_global_direction) {
+ mul_transposed_mat3_m4_v3(local_mat, local_vec);
+ }
+ mul_v3_fl(local_vec, strength);
+ add_v3_v3(vertexCos[i], local_vec);
break;
case MOD_DISP_DIR_NOR:
vertexCos[i][0] += delta * (mvert[i].no[0] / 32767.0f);
diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c
index edf959f42c6..bde20e56748 100644
--- a/source/blender/modifiers/intern/MOD_dynamicpaint.c
+++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c
@@ -114,6 +114,11 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
return dm;
}
+static bool is_brush_cb(Object *UNUSED(ob), ModifierData *pmd)
+{
+ return ((DynamicPaintModifierData*)pmd)->brush != NULL;
+}
+
static void updateDepgraph(ModifierData *md, DagForest *forest,
struct Main *UNUSED(bmain),
struct Scene *scene,
@@ -124,16 +129,13 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
/* add relation from canvases to all brush objects */
if (pmd && pmd->canvas) {
- Base *base = scene->base.first;
-
- for (; base; base = base->next) {
- DynamicPaintModifierData *pmd2 =
- (DynamicPaintModifierData *)modifiers_findByType(base->object, eModifierType_DynamicPaint);
-
- if (pmd2 && pmd2->brush && ob != base->object) {
- DagNode *brushNode = dag_get_node(forest, base->object);
- dag_add_relation(forest, brushNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Dynamic Paint Brush");
+ for (DynamicPaintSurface *surface = pmd->canvas->surfaces.first; surface; surface = surface->next) {
+ if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) {
+ dag_add_forcefield_relations(forest, scene, ob, obNode, surface->effector_weights, true, 0, "Dynamic Paint Field");
}
+
+ /* Actual code uses custom loop over group/scene without layer checks in dynamicPaint_doStep */
+ dag_add_collision_relations(forest, scene, ob, obNode, surface->brush_group, -1, eModifierType_DynamicPaint, is_brush_cb, false, "Dynamic Paint Brush");
}
}
}
@@ -147,13 +149,13 @@ static void updateDepsgraph(ModifierData *md,
DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
/* Add relation from canvases to all brush objects. */
if (pmd->canvas != NULL) {
- Base *base = scene->base.first;
- for (; base; base = base->next) {
- DynamicPaintModifierData *pmd2 =
- (DynamicPaintModifierData *)modifiers_findByType(base->object, eModifierType_DynamicPaint);
- if (pmd2 && pmd2->brush && ob != base->object) {
- DEG_add_object_relation(node, base->object, DEG_OB_COMP_TRANSFORM, "Dynamic Paint Brush");
+ for (DynamicPaintSurface *surface = pmd->canvas->surfaces.first; surface; surface = surface->next) {
+ if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) {
+ DEG_add_forcefield_relations(node, scene, ob, surface->effector_weights, true, 0, "Dynamic Paint Field");
}
+
+ /* Actual code uses custom loop over group/scene without layer checks in dynamicPaint_doStep */
+ DEG_add_collision_relations(node, scene, ob, surface->brush_group, -1, eModifierType_DynamicPaint, is_brush_cb, false, "Dynamic Paint Brush");
}
}
}
diff --git a/source/blender/modifiers/intern/MOD_fluidsim_util.c b/source/blender/modifiers/intern/MOD_fluidsim_util.c
index 77fbb482f8b..ffbbb1b0745 100644
--- a/source/blender/modifiers/intern/MOD_fluidsim_util.c
+++ b/source/blender/modifiers/intern/MOD_fluidsim_util.c
@@ -525,7 +525,7 @@ DerivedMesh *fluidsimModifier_do(FluidsimModifierData *fluidmd, Scene *scene,
return dm;
/* sanity check */
- if (!fluidmd || (fluidmd && !fluidmd->fss))
+ if (!fluidmd || !fluidmd->fss)
return dm;
fss = fluidmd->fss;
diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c
index bec0cc0d8a3..83c4ca7984c 100644
--- a/source/blender/modifiers/intern/MOD_hook.c
+++ b/source/blender/modifiers/intern/MOD_hook.c
@@ -417,6 +417,7 @@ ModifierTypeInfo modifierType_Hook = {
/* structSize */ sizeof(HookModifierData),
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsCVs |
+ eModifierTypeFlag_AcceptsLattice |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
/* deformVerts */ deformVerts,
diff --git a/source/blender/modifiers/intern/MOD_lattice.c b/source/blender/modifiers/intern/MOD_lattice.c
index 0f49ce6cfbf..7d4701e3ef2 100644
--- a/source/blender/modifiers/intern/MOD_lattice.c
+++ b/source/blender/modifiers/intern/MOD_lattice.c
@@ -156,6 +156,7 @@ ModifierTypeInfo modifierType_Lattice = {
/* structSize */ sizeof(LatticeModifierData),
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsCVs |
+ eModifierTypeFlag_AcceptsLattice |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
/* deformVerts */ deformVerts,
diff --git a/source/blender/modifiers/intern/MOD_meshcache.c b/source/blender/modifiers/intern/MOD_meshcache.c
index 92926ed9424..aa3e3ebcf7e 100644
--- a/source/blender/modifiers/intern/MOD_meshcache.c
+++ b/source/blender/modifiers/intern/MOD_meshcache.c
@@ -299,6 +299,7 @@ ModifierTypeInfo modifierType_MeshCache = {
/* structSize */ sizeof(MeshCacheModifierData),
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsCVs |
+ eModifierTypeFlag_AcceptsLattice |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c
index e3c94a1a4df..3f34319d25f 100644
--- a/source/blender/modifiers/intern/MOD_meshdeform.c
+++ b/source/blender/modifiers/intern/MOD_meshdeform.c
@@ -520,6 +520,7 @@ ModifierTypeInfo modifierType_MeshDeform = {
/* structSize */ sizeof(MeshDeformModifierData),
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsCVs |
+ eModifierTypeFlag_AcceptsLattice |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c
new file mode 100644
index 00000000000..d25e8e38de3
--- /dev/null
+++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c
@@ -0,0 +1,210 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/modifiers/intern/MOD_meshsequencecache.c
+ * \ingroup modifiers
+ */
+
+#include "DNA_cachefile_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_cachefile.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_scene.h"
+
+#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
+
+#include "MOD_modifiertypes.h"
+
+#ifdef WITH_ALEMBIC
+# include "ABC_alembic.h"
+#endif
+
+static void initData(ModifierData *md)
+{
+ MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
+
+ mcmd->cache_file = NULL;
+ mcmd->object_path[0] = '\0';
+ mcmd->read_flag = MOD_MESHSEQ_READ_ALL;
+}
+
+static void copyData(ModifierData *md, ModifierData *target)
+{
+#if 0
+ MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
+#endif
+ MeshSeqCacheModifierData *tmcmd = (MeshSeqCacheModifierData *)target;
+
+ modifier_copyData_generic(md, target);
+
+ if (tmcmd->cache_file) {
+ id_us_plus(&tmcmd->cache_file->id);
+ tmcmd->reader = NULL;
+ }
+}
+
+static void freeData(ModifierData *md)
+{
+ MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md;
+
+ if (mcmd->cache_file) {
+ id_us_min(&mcmd->cache_file->id);
+ }
+
+ if (mcmd->reader) {
+#ifdef WITH_ALEMBIC
+ CacheReader_free(mcmd->reader);
+#endif
+ }
+}
+
+static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
+{
+ MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md;
+
+ /* leave it up to the modifier to check the file is valid on calculation */
+ return (mcmd->cache_file == NULL) || (mcmd->object_path[0] == '\0');
+}
+
+static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
+ DerivedMesh *dm,
+ ModifierApplyFlag flag)
+{
+#ifdef WITH_ALEMBIC
+ MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md;
+
+ Scene *scene = md->scene;
+ const float frame = BKE_scene_frame_get(scene);
+ const float time = BKE_cachefile_time_offset(mcmd->cache_file, frame, FPS);
+
+ const char *err_str = NULL;
+
+ CacheFile *cache_file = mcmd->cache_file;
+
+ BKE_cachefile_ensure_handle(G.main, cache_file);
+
+ if (!mcmd->reader) {
+ mcmd->reader = CacheReader_open_alembic_object(cache_file->handle,
+ mcmd->reader,
+ ob,
+ mcmd->object_path);
+ }
+
+ DerivedMesh *result = ABC_read_mesh(mcmd->reader,
+ ob,
+ dm,
+ time,
+ &err_str,
+ mcmd->read_flag);
+
+ if (err_str) {
+ modifier_setError(md, "%s", err_str);
+ }
+
+ return result ? result : dm;
+ UNUSED_VARS(flag);
+#else
+ return dm;
+ UNUSED_VARS(md, ob, flag);
+#endif
+}
+
+static bool dependsOnTime(ModifierData *md)
+{
+ UNUSED_VARS(md);
+ return true;
+}
+
+static void foreachIDLink(ModifierData *md, Object *ob,
+ IDWalkFunc walk, void *userData)
+{
+ MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md;
+
+ walk(userData, ob, (ID **)&mcmd->cache_file, IDWALK_USER);
+}
+
+
+static void updateDepgraph(ModifierData *md, DagForest *forest,
+ struct Main *bmain,
+ struct Scene *scene,
+ Object *ob, DagNode *obNode)
+{
+ MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md;
+
+ if (mcmd->cache_file != NULL) {
+ DagNode *curNode = dag_get_node(forest, mcmd->cache_file);
+
+ dag_add_relation(forest, curNode, obNode,
+ DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Cache File Modifier");
+ }
+
+ UNUSED_VARS(bmain, scene, ob);
+}
+
+static void updateDepsgraph(ModifierData *md,
+ struct Main *bmain,
+ struct Scene *scene,
+ Object *ob,
+ struct DepsNodeHandle *node)
+{
+ MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md;
+
+ if (mcmd->cache_file != NULL) {
+ DEG_add_object_cache_relation(node, mcmd->cache_file, DEG_OB_COMP_CACHE, "Mesh Cache File");
+ }
+
+ UNUSED_VARS(bmain, scene, ob);
+}
+
+ModifierTypeInfo modifierType_MeshSequenceCache = {
+ /* name */ "Mesh Sequence Cache",
+ /* structName */ "MeshSeqCacheModifierData",
+ /* structSize */ sizeof(MeshSeqCacheModifierData),
+ /* type */ eModifierTypeType_Constructive,
+ /* flags */ eModifierTypeFlag_AcceptsMesh |
+ eModifierTypeFlag_AcceptsCVs,
+ /* copyData */ copyData,
+ /* deformVerts */ NULL,
+ /* deformMatrices */ NULL,
+ /* deformVertsEM */ NULL,
+ /* deformMatricesEM */ NULL,
+ /* applyModifier */ applyModifier,
+ /* applyModifierEM */ NULL,
+ /* initData */ initData,
+ /* requiredDataMask */ NULL,
+ /* freeData */ freeData,
+ /* isDisabled */ isDisabled,
+ /* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
+ /* dependsOnTime */ dependsOnTime,
+ /* dependsOnNormals */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ foreachIDLink,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c
index 355dd6d6677..454c97451a8 100644
--- a/source/blender/modifiers/intern/MOD_normal_edit.c
+++ b/source/blender/modifiers/intern/MOD_normal_edit.c
@@ -110,7 +110,7 @@ static void generate_vert_coordinates(
/* Note this modifies nos_new in-place. */
static void mix_normals(
const float mix_factor, MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup,
- const short mix_mode,
+ const float mix_limit, const short mix_mode,
const int num_verts, MLoop *mloop, float (*nos_old)[3], float (*nos_new)[3], const int num_loops)
{
/* Mix with org normals... */
@@ -143,7 +143,10 @@ static void mix_normals(
case MOD_NORMALEDIT_MIX_COPY:
break;
}
- interp_v3_v3v3_slerp_safe(*no_new, *no_old, *no_new, fac);
+
+ interp_v3_v3v3_slerp_safe(
+ *no_new, *no_old, *no_new,
+ (mix_limit < (float)M_PI) ? min_ff(fac, mix_limit / angle_v3v3(*no_new, *no_old)) : fac);
}
MEM_SAFE_FREE(facs);
@@ -156,6 +159,7 @@ static bool polygons_check_flip(
MPoly *mpoly, float (*polynors)[3], const int num_polys)
{
MPoly *mp;
+ MDisps *mdisp = CustomData_get_layer(ldata, CD_MDISPS);
int i;
bool flipped = false;
@@ -174,7 +178,7 @@ static bool polygons_check_flip(
/* If average of new loop normals is opposed to polygon normal, flip polygon. */
if (dot_v3v3(polynors[i], norsum) < 0.0f) {
- BKE_mesh_polygon_flip(mp, mloop, ldata);
+ BKE_mesh_polygon_flip_ex(mp, mloop, ldata, nos, mdisp, true);
negate_v3(polynors[i]);
flipped = true;
}
@@ -184,9 +188,9 @@ static bool polygons_check_flip(
}
static void normalEditModifier_do_radial(
- NormalEditModifierData *smd, Object *ob, DerivedMesh *dm,
+ NormalEditModifierData *enmd, Object *ob, DerivedMesh *dm,
short (*clnors)[2], float (*loopnors)[3], float (*polynors)[3],
- const short mix_mode, const float mix_factor,
+ const short mix_mode, const float mix_factor, const float mix_limit,
MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup,
MVert *mvert, const int num_verts, MEdge *medge, const int num_edges,
MLoop *mloop, const int num_loops, MPoly *mpoly, const int num_polys)
@@ -199,7 +203,7 @@ static void normalEditModifier_do_radial(
BLI_bitmap *done_verts = BLI_BITMAP_NEW((size_t)num_verts, __func__);
- generate_vert_coordinates(dm, ob, smd->target, smd->offset, num_verts, cos, size);
+ generate_vert_coordinates(dm, ob, enmd->target, enmd->offset, num_verts, cos, size);
/**
* size gives us our spheroid coefficients ``(A, B, C)``.
@@ -265,11 +269,13 @@ static void normalEditModifier_do_radial(
if (loopnors) {
mix_normals(mix_factor, dvert, defgrp_index, use_invert_vgroup,
- mix_mode, num_verts, mloop, loopnors, nos, num_loops);
+ mix_limit, mix_mode, num_verts, mloop, loopnors, nos, num_loops);
}
if (polygons_check_flip(mloop, nos, dm->getLoopDataLayout(dm), mpoly, polynors, num_polys)) {
dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
+ /* We need to recompute vertex normals! */
+ dm->calcNormals(dm);
}
BKE_mesh_normals_loop_custom_set(mvert, num_verts, medge, num_edges, mloop, nos, num_loops,
@@ -281,14 +287,14 @@ static void normalEditModifier_do_radial(
}
static void normalEditModifier_do_directional(
- NormalEditModifierData *smd, Object *ob, DerivedMesh *dm,
+ NormalEditModifierData *enmd, Object *ob, DerivedMesh *dm,
short (*clnors)[2], float (*loopnors)[3], float (*polynors)[3],
- const short mix_mode, const float mix_factor,
+ const short mix_mode, const float mix_factor, const float mix_limit,
MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup,
MVert *mvert, const int num_verts, MEdge *medge, const int num_edges,
MLoop *mloop, const int num_loops, MPoly *mpoly, const int num_polys)
{
- const bool use_parallel_normals = (smd->flag & MOD_NORMALEDIT_USE_DIRECTION_PARALLEL) != 0;
+ const bool use_parallel_normals = (enmd->flag & MOD_NORMALEDIT_USE_DIRECTION_PARALLEL) != 0;
float (*cos)[3] = MEM_mallocN(sizeof(*cos) * num_verts, __func__);
float (*nos)[3] = MEM_mallocN(sizeof(*nos) * num_loops, __func__);
@@ -303,14 +309,14 @@ static void normalEditModifier_do_directional(
float mat[4][4];
invert_m4_m4(mat, ob->obmat);
- mul_m4_m4m4(mat, mat, smd->target->obmat);
+ mul_m4_m4m4(mat, mat, enmd->target->obmat);
copy_v3_v3(target_co, mat[3]);
}
if (use_parallel_normals) {
float no[3];
- sub_v3_v3v3(no, target_co, smd->offset);
+ sub_v3_v3v3(no, target_co, enmd->offset);
normalize_v3(no);
for (i = num_loops; i--; ) {
@@ -342,7 +348,7 @@ static void normalEditModifier_do_directional(
if (loopnors) {
mix_normals(mix_factor, dvert, defgrp_index, use_invert_vgroup,
- mix_mode, num_verts, mloop, loopnors, nos, num_loops);
+ mix_limit, mix_mode, num_verts, mloop, loopnors, nos, num_loops);
}
if (polygons_check_flip(mloop, nos, dm->getLoopDataLayout(dm), mpoly, polynors, num_polys)) {
@@ -356,19 +362,19 @@ static void normalEditModifier_do_directional(
MEM_freeN(nos);
}
-static bool is_valid_target(NormalEditModifierData *smd)
+static bool is_valid_target(NormalEditModifierData *enmd)
{
- if (smd->mode == MOD_NORMALEDIT_MODE_RADIAL) {
+ if (enmd->mode == MOD_NORMALEDIT_MODE_RADIAL) {
return true;
}
- else if ((smd->mode == MOD_NORMALEDIT_MODE_DIRECTIONAL) && smd->target) {
+ else if ((enmd->mode == MOD_NORMALEDIT_MODE_DIRECTIONAL) && enmd->target) {
return true;
}
- modifier_setError((ModifierData *)smd, "Invalid target settings");
+ modifier_setError((ModifierData *)enmd, "Invalid target settings");
return false;
}
-static DerivedMesh *normalEditModifier_do(NormalEditModifierData *smd, Object *ob, DerivedMesh *dm)
+static DerivedMesh *normalEditModifier_do(NormalEditModifierData *enmd, Object *ob, DerivedMesh *dm)
{
Mesh *me = ob->data;
@@ -381,10 +387,11 @@ static DerivedMesh *normalEditModifier_do(NormalEditModifierData *smd, Object *o
MLoop *mloop;
MPoly *mpoly;
- const bool use_invert_vgroup = ((smd->flag & MOD_NORMALEDIT_INVERT_VGROUP) != 0);
- const bool use_current_clnors = !((smd->mix_mode == MOD_NORMALEDIT_MIX_COPY) &&
- (smd->mix_factor == 1.0f) &&
- (smd->defgrp_name[0] == '\0'));
+ const bool use_invert_vgroup = ((enmd->flag & MOD_NORMALEDIT_INVERT_VGROUP) != 0);
+ const bool use_current_clnors = !((enmd->mix_mode == MOD_NORMALEDIT_MIX_COPY) &&
+ (enmd->mix_factor == 1.0f) &&
+ (enmd->defgrp_name[0] == '\0') &&
+ (enmd->mix_limit == (float)M_PI));
int defgrp_index;
MDeformVert *dvert;
@@ -396,12 +403,12 @@ static DerivedMesh *normalEditModifier_do(NormalEditModifierData *smd, Object *o
bool free_polynors = false;
/* Do not run that modifier at all if autosmooth is disabled! */
- if (!is_valid_target(smd) || !num_loops) {
+ if (!is_valid_target(enmd) || !num_loops) {
return dm;
}
if (!(me->flag & ME_AUTOSMOOTH)) {
- modifier_setError((ModifierData *)smd, "Enable 'Auto Smooth' option in mesh settings");
+ modifier_setError((ModifierData *)enmd, "Enable 'Auto Smooth' option in mesh settings");
return dm;
}
@@ -434,18 +441,18 @@ static DerivedMesh *normalEditModifier_do(NormalEditModifierData *smd, Object *o
free_polynors = true;
}
- modifier_get_vgroup(ob, dm, smd->defgrp_name, &dvert, &defgrp_index);
+ modifier_get_vgroup(ob, dm, enmd->defgrp_name, &dvert, &defgrp_index);
- if (smd->mode == MOD_NORMALEDIT_MODE_RADIAL) {
+ if (enmd->mode == MOD_NORMALEDIT_MODE_RADIAL) {
normalEditModifier_do_radial(
- smd, ob, dm, clnors, loopnors, polynors,
- smd->mix_mode, smd->mix_factor, dvert, defgrp_index, use_invert_vgroup,
+ enmd, ob, dm, clnors, loopnors, polynors,
+ enmd->mix_mode, enmd->mix_factor, enmd->mix_limit, dvert, defgrp_index, use_invert_vgroup,
mvert, num_verts, medge, num_edges, mloop, num_loops, mpoly, num_polys);
}
- else if (smd->mode == MOD_NORMALEDIT_MODE_DIRECTIONAL) {
+ else if (enmd->mode == MOD_NORMALEDIT_MODE_DIRECTIONAL) {
normalEditModifier_do_directional(
- smd, ob, dm, clnors, loopnors, polynors,
- smd->mix_mode, smd->mix_factor, dvert, defgrp_index, use_invert_vgroup,
+ enmd, ob, dm, clnors, loopnors, polynors,
+ enmd->mix_mode, enmd->mix_factor, enmd->mix_limit, dvert, defgrp_index, use_invert_vgroup,
mvert, num_verts, medge, num_edges, mloop, num_loops, mpoly, num_polys);
}
@@ -458,12 +465,13 @@ static DerivedMesh *normalEditModifier_do(NormalEditModifierData *smd, Object *o
static void initData(ModifierData *md)
{
- NormalEditModifierData *smd = (NormalEditModifierData *)md;
+ NormalEditModifierData *enmd = (NormalEditModifierData *)md;
- smd->mode = MOD_NORMALEDIT_MODE_RADIAL;
+ enmd->mode = MOD_NORMALEDIT_MODE_RADIAL;
- smd->mix_mode = MOD_NORMALEDIT_MIX_COPY;
- smd->mix_factor = 1.0f;
+ enmd->mix_mode = MOD_NORMALEDIT_MIX_COPY;
+ enmd->mix_factor = 1.0f;
+ enmd->mix_limit = M_PI;
}
static void copyData(ModifierData *md, ModifierData *target)
@@ -473,11 +481,11 @@ static void copyData(ModifierData *md, ModifierData *target)
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
{
- NormalEditModifierData *smd = (NormalEditModifierData *)md;
+ NormalEditModifierData *enmd = (NormalEditModifierData *)md;
CustomDataMask dataMask = CD_CUSTOMLOOPNORMAL;
/* Ask for vertexgroups if we need them. */
- if (smd->defgrp_name[0]) {
+ if (enmd->defgrp_name[0]) {
dataMask |= (CD_MASK_MDEFORMVERT);
}
@@ -491,16 +499,16 @@ static bool dependsOnNormals(ModifierData *UNUSED(md))
static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
{
- NormalEditModifierData *smd = (NormalEditModifierData *) md;
+ NormalEditModifierData *enmd = (NormalEditModifierData *) md;
- walk(userData, ob, &smd->target, IDWALK_NOP);
+ walk(userData, ob, &enmd->target, IDWALK_NOP);
}
static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
{
- NormalEditModifierData *smd = (NormalEditModifierData *)md;
+ NormalEditModifierData *enmd = (NormalEditModifierData *)md;
- return !is_valid_target(smd);
+ return !is_valid_target(enmd);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
@@ -508,10 +516,10 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
struct Scene *UNUSED(scene),
Object *UNUSED(ob), DagNode *obNode)
{
- NormalEditModifierData *smd = (NormalEditModifierData *) md;
+ NormalEditModifierData *enmd = (NormalEditModifierData *) md;
- if (smd->target) {
- DagNode *Node = dag_get_node(forest, smd->target);
+ if (enmd->target) {
+ DagNode *Node = dag_get_node(forest, enmd->target);
dag_add_relation(forest, Node, obNode, DAG_RL_OB_DATA, "NormalEdit Modifier");
}
@@ -523,9 +531,9 @@ static void updateDepsgraph(ModifierData *md,
Object *UNUSED(ob),
struct DepsNodeHandle *node)
{
- NormalEditModifierData *smd = (NormalEditModifierData *) md;
- if (smd->target) {
- DEG_add_object_relation(node, smd->target, DEG_OB_COMP_GEOMETRY, "NormalEdit Modifier");
+ NormalEditModifierData *enmd = (NormalEditModifierData *) md;
+ if (enmd->target) {
+ DEG_add_object_relation(node, enmd->target, DEG_OB_COMP_TRANSFORM, "NormalEdit Modifier");
}
}
diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c
index a90a51e9ddc..e77cc655c16 100644
--- a/source/blender/modifiers/intern/MOD_ocean.c
+++ b/source/blender/modifiers/intern/MOD_ocean.c
@@ -435,7 +435,7 @@ static DerivedMesh *doOcean(ModifierData *md, Object *ob,
const float size_co_inv = 1.0f / (omd->size * omd->spatial_size);
/* can happen in when size is small, avoid bad array lookups later and quit now */
- if (!finite(size_co_inv)) {
+ if (!isfinite(size_co_inv)) {
return derivedData;
}
diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c
index 4791e41d433..d8cccca415c 100644
--- a/source/blender/modifiers/intern/MOD_particlesystem.c
+++ b/source/blender/modifiers/intern/MOD_particlesystem.c
@@ -101,7 +101,7 @@ static void deformVerts(ModifierData *md, Object *ob,
DerivedMesh *derivedData,
float (*vertexCos)[3],
int UNUSED(numVerts),
- ModifierApplyFlag UNUSED(flag))
+ ModifierApplyFlag flag)
{
DerivedMesh *dm = derivedData;
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *) md;
@@ -114,7 +114,7 @@ static void deformVerts(ModifierData *md, Object *ob,
else
return;
- if (!psys_check_enabled(ob, psys))
+ if (!psys_check_enabled(ob, psys, (flag & MOD_APPLY_RENDER) != 0))
return;
if (dm == NULL) {
@@ -186,7 +186,7 @@ static void deformVerts(ModifierData *md, Object *ob,
if (!(ob->transflag & OB_NO_PSYS_UPDATE)) {
psmd->flag &= ~eParticleSystemFlag_psys_updated;
- particle_system_update(md->scene, ob, psys);
+ particle_system_update(md->scene, ob, psys, (flag & MOD_APPLY_RENDER) != 0);
psmd->flag |= eParticleSystemFlag_psys_updated;
}
}
diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c
index 41ebd865720..df94975e274 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -73,7 +73,7 @@ typedef struct ScrewVertIter {
#define SV_UNUSED (UINT_MAX)
#define SV_INVALID ((UINT_MAX) - 1)
-#define SV_IS_VALID(v) (v < SV_INVALID)
+#define SV_IS_VALID(v) ((v) < SV_INVALID)
static void screwvert_iter_init(ScrewVertIter *iter, ScrewVertConnect *array, unsigned int v_init, unsigned int dir)
{
diff --git a/source/blender/modifiers/intern/MOD_shapekey.c b/source/blender/modifiers/intern/MOD_shapekey.c
index a543aac74b9..97aae733532 100644
--- a/source/blender/modifiers/intern/MOD_shapekey.c
+++ b/source/blender/modifiers/intern/MOD_shapekey.c
@@ -124,6 +124,7 @@ ModifierTypeInfo modifierType_ShapeKey = {
/* structSize */ sizeof(ShapeKeyModifierData),
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsCVs |
+ eModifierTypeFlag_AcceptsLattice |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_shrinkwrap.c b/source/blender/modifiers/intern/MOD_shrinkwrap.c
index a9919cadd16..633311c2b87 100644
--- a/source/blender/modifiers/intern/MOD_shrinkwrap.c
+++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c
@@ -194,6 +194,7 @@ ModifierTypeInfo modifierType_Shrinkwrap = {
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsMesh |
eModifierTypeFlag_AcceptsCVs |
+ eModifierTypeFlag_AcceptsLattice |
eModifierTypeFlag_SupportsEditmode |
eModifierTypeFlag_EnableInEditmode,
diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c
index 588b56d6aba..c68f2651191 100644
--- a/source/blender/modifiers/intern/MOD_simpledeform.c
+++ b/source/blender/modifiers/intern/MOD_simpledeform.c
@@ -366,6 +366,7 @@ ModifierTypeInfo modifierType_SimpleDeform = {
/* flags */ eModifierTypeFlag_AcceptsMesh |
eModifierTypeFlag_AcceptsCVs |
+ eModifierTypeFlag_AcceptsLattice |
eModifierTypeFlag_SupportsEditmode |
eModifierTypeFlag_EnableInEditmode,
diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c
index 9f1ec4de3d5..8ed623734be 100644
--- a/source/blender/modifiers/intern/MOD_skin.c
+++ b/source/blender/modifiers/intern/MOD_skin.c
@@ -1745,7 +1745,9 @@ static BMesh *build_skin(SkinNode *skin_nodes,
int v;
so.smd = smd;
- so.bm = BM_mesh_create(&bm_mesh_allocsize_default);
+ so.bm = BM_mesh_create(
+ &bm_mesh_allocsize_default,
+ &((struct BMeshCreateParams){.use_toolflags = true,}));
so.mat_nr = 0;
/* BMESH_TODO: bumping up the stack level (see MOD_array.c) */
diff --git a/source/blender/modifiers/intern/MOD_smoke.c b/source/blender/modifiers/intern/MOD_smoke.c
index 237d4cc6718..f04d7432a8f 100644
--- a/source/blender/modifiers/intern/MOD_smoke.c
+++ b/source/blender/modifiers/intern/MOD_smoke.c
@@ -117,219 +117,48 @@ static bool dependsOnTime(ModifierData *UNUSED(md))
return true;
}
-static void update_depsgraph_flow_coll_object(DagForest *forest,
- DagNode *obNode,
- Object *object2)
+static bool is_flow_cb(Object *UNUSED(ob), ModifierData *md)
{
- SmokeModifierData *smd;
- if ((object2->id.tag & LIB_TAG_DOIT) == 0) {
- return;
- }
- object2->id.tag &= ~LIB_TAG_DOIT;
- smd = (SmokeModifierData *)modifiers_findByType(object2, eModifierType_Smoke);
- if (smd && (((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) ||
- ((smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll)))
- {
- DagNode *curNode = dag_get_node(forest, object2);
- dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Smoke Flow/Coll");
- }
- if ((object2->transflag & OB_DUPLIGROUP) && object2->dup_group) {
- GroupObject *go;
- for (go = object2->dup_group->gobject.first;
- go != NULL;
- go = go->next)
- {
- if (go->ob == NULL) {
- continue;
- }
- update_depsgraph_flow_coll_object(forest, obNode, go->ob);
- }
- }
+ SmokeModifierData *smd = (SmokeModifierData *) md;
+ return (smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow;
}
-static void update_depsgraph_field_source_object(DagForest *forest,
- DagNode *obNode,
- Object *object,
- Object *object2)
+static bool is_coll_cb(Object *UNUSED(ob), ModifierData *md)
{
- if ((object2->id.tag & LIB_TAG_DOIT) == 0) {
- return;
- }
- object2->id.tag &= ~LIB_TAG_DOIT;
- if (object2->pd && object2->pd->forcefield == PFIELD_SMOKEFLOW && object2->pd->f_source == object) {
- DagNode *node2 = dag_get_node(forest, object2);
- dag_add_relation(forest, obNode, node2, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Field Source Object");
- }
- if ((object2->transflag & OB_DUPLIGROUP) && object2->dup_group) {
- GroupObject *go;
- for (go = object2->dup_group->gobject.first;
- go != NULL;
- go = go->next)
- {
- if (go->ob == NULL) {
- continue;
- }
- update_depsgraph_field_source_object(forest, obNode, object, go->ob);
- }
- }
+ SmokeModifierData *smd = (SmokeModifierData *) md;
+ return (smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll;
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Main *bmain,
+ struct Main *UNUSED(bmain),
struct Scene *scene, struct Object *ob,
DagNode *obNode)
{
SmokeModifierData *smd = (SmokeModifierData *) md;
- Base *base;
if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
- if (smd->domain->fluid_group || smd->domain->coll_group) {
- GroupObject *go = NULL;
-
- if (smd->domain->fluid_group)
- for (go = smd->domain->fluid_group->gobject.first; go; go = go->next) {
- if (go->ob) {
- SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(go->ob, eModifierType_Smoke);
-
- /* check for initialized smoke object */
- if (smd2 && (smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) {
- DagNode *curNode = dag_get_node(forest, go->ob);
- dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Smoke Flow");
- }
- }
- }
-
- if (smd->domain->coll_group)
- for (go = smd->domain->coll_group->gobject.first; go; go = go->next) {
- if (go->ob) {
- SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(go->ob, eModifierType_Smoke);
-
- /* check for initialized smoke object */
- if (smd2 && (smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll) {
- DagNode *curNode = dag_get_node(forest, go->ob);
- dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Smoke Coll");
- }
- }
- }
- }
- else {
- BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, true);
- base = scene->base.first;
- for (; base; base = base->next) {
- update_depsgraph_flow_coll_object(forest, obNode, base->object);
- }
- }
- /* add relation to all "smoke flow" force fields */
- base = scene->base.first;
- BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, true);
- for (; base; base = base->next) {
- update_depsgraph_field_source_object(forest, obNode, ob, base->object);
- }
- }
-}
+ /* Actual code uses get_collisionobjects */
+ dag_add_collision_relations(forest, scene, ob, obNode, smd->domain->fluid_group, ob->lay|scene->lay, eModifierType_Smoke, is_flow_cb, true, "Smoke Flow");
+ dag_add_collision_relations(forest, scene, ob, obNode, smd->domain->coll_group, ob->lay|scene->lay, eModifierType_Smoke, is_coll_cb, true, "Smoke Coll");
-static void update_depsgraph_flow_coll_object_new(struct DepsNodeHandle *node,
- Object *object2)
-{
- SmokeModifierData *smd;
- if ((object2->id.tag & LIB_TAG_DOIT) == 0) {
- return;
- }
- object2->id.tag &= ~LIB_TAG_DOIT;
- smd = (SmokeModifierData *)modifiers_findByType(object2, eModifierType_Smoke);
- if (smd && (((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) ||
- ((smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll)))
- {
- DEG_add_object_relation(node, object2, DEG_OB_COMP_TRANSFORM, "Smoke Flow/Coll");
- DEG_add_object_relation(node, object2, DEG_OB_COMP_GEOMETRY, "Smoke Flow/Coll");
- }
- if ((object2->transflag & OB_DUPLIGROUP) && object2->dup_group) {
- GroupObject *go;
- for (go = object2->dup_group->gobject.first;
- go != NULL;
- go = go->next)
- {
- if (go->ob == NULL) {
- continue;
- }
- update_depsgraph_flow_coll_object_new(node, go->ob);
- }
- }
-}
-
-static void update_depsgraph_field_source_object_new(struct DepsNodeHandle *node,
- Object *object,
- Object *object2)
-{
- if ((object2->id.tag & LIB_TAG_DOIT) == 0) {
- return;
- }
- object2->id.tag &= ~LIB_TAG_DOIT;
- if (object2->pd && object2->pd->forcefield == PFIELD_SMOKEFLOW && object2->pd->f_source == object) {
- DEG_add_object_relation(node, object2, DEG_OB_COMP_TRANSFORM, "Field Source Object");
- DEG_add_object_relation(node, object2, DEG_OB_COMP_GEOMETRY, "Field Source Object");
- }
- if ((object2->transflag & OB_DUPLIGROUP) && object2->dup_group) {
- GroupObject *go;
- for (go = object2->dup_group->gobject.first;
- go != NULL;
- go = go->next)
- {
- if (go->ob == NULL) {
- continue;
- }
- update_depsgraph_field_source_object_new(node, object, go->ob);
- }
+ dag_add_forcefield_relations(forest, scene, ob, obNode, smd->domain->effector_weights, true, PFIELD_SMOKEFLOW, "Smoke Force Field");
}
}
static void updateDepsgraph(ModifierData *md,
- struct Main *bmain,
+ struct Main *UNUSED(bmain),
struct Scene *scene,
Object *ob,
struct DepsNodeHandle *node)
{
SmokeModifierData *smd = (SmokeModifierData *)md;
- Base *base;
+
if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
- if (smd->domain->fluid_group || smd->domain->coll_group) {
- GroupObject *go = NULL;
- if (smd->domain->fluid_group != NULL) {
- for (go = smd->domain->fluid_group->gobject.first; go; go = go->next) {
- if (go->ob != NULL) {
- SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(go->ob, eModifierType_Smoke);
- /* Check for initialized smoke object. */
- if (smd2 && (smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) {
- DEG_add_object_relation(node, go->ob, DEG_OB_COMP_TRANSFORM, "Smoke Flow");
- }
- }
- }
- }
- if (smd->domain->coll_group != NULL) {
- for (go = smd->domain->coll_group->gobject.first; go; go = go->next) {
- if (go->ob != NULL) {
- SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(go->ob, eModifierType_Smoke);
- /* Check for initialized smoke object. */
- if (smd2 && (smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll) {
- DEG_add_object_relation(node, go->ob, DEG_OB_COMP_TRANSFORM, "Smoke Coll");
- }
- }
- }
- }
- }
- else {
- BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, true);
- base = scene->base.first;
- for (; base; base = base->next) {
- update_depsgraph_flow_coll_object_new(node, base->object);
- }
- }
- /* add relation to all "smoke flow" force fields */
- base = scene->base.first;
- BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, true);
- for (; base; base = base->next) {
- update_depsgraph_field_source_object_new(node, ob, base->object);
- }
+ /* Actual code uses get_collisionobjects */
+ DEG_add_collision_relations(node, scene, ob, smd->domain->fluid_group, ob->lay|scene->lay, eModifierType_Smoke, is_flow_cb, true, "Smoke Flow");
+ DEG_add_collision_relations(node, scene, ob, smd->domain->coll_group, ob->lay|scene->lay, eModifierType_Smoke, is_coll_cb, true, "Smoke Coll");
+
+ DEG_add_forcefield_relations(node, scene, ob, smd->domain->effector_weights, true, PFIELD_SMOKEFLOW, "Smoke Force Field");
}
}
diff --git a/source/blender/modifiers/intern/MOD_softbody.c b/source/blender/modifiers/intern/MOD_softbody.c
index d958badc33c..17adc7f1520 100644
--- a/source/blender/modifiers/intern/MOD_softbody.c
+++ b/source/blender/modifiers/intern/MOD_softbody.c
@@ -35,6 +35,7 @@
#include <stdio.h>
#include "DNA_scene_types.h"
+#include "DNA_object_force.h"
#include "BLI_utildefines.h"
@@ -42,6 +43,9 @@
#include "BKE_particle.h"
#include "BKE_softbody.h"
+#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
+
#include "MOD_modifiertypes.h"
static void deformVerts(ModifierData *md, Object *ob,
@@ -58,6 +62,31 @@ static bool dependsOnTime(ModifierData *UNUSED(md))
return true;
}
+static void updateDepgraph(ModifierData *UNUSED(md), DagForest *forest,
+ struct Main *UNUSED(bmain),
+ Scene *scene, Object *ob, DagNode *obNode)
+{
+ if (ob->soft) {
+ /* Actual code uses ccd_build_deflector_hash */
+ dag_add_collision_relations(forest, scene, ob, obNode, ob->soft->collision_group, ob->lay, eModifierType_Collision, NULL, false, "Softbody Collision");
+
+ dag_add_forcefield_relations(forest, scene, ob, obNode, ob->soft->effector_weights, true, 0, "Softbody Field");
+ }
+}
+
+static void updateDepsgraph(ModifierData *UNUSED(md),
+ struct Main *UNUSED(bmain),
+ struct Scene *scene,
+ Object *ob,
+ struct DepsNodeHandle *node)
+{
+ if (ob->soft) {
+ /* Actual code uses ccd_build_deflector_hash */
+ DEG_add_collision_relations(node, scene, ob, ob->soft->collision_group, ob->lay, eModifierType_Collision, NULL, false, "Softbody Collision");
+
+ DEG_add_forcefield_relations(node, scene, ob, ob->soft->effector_weights, true, 0, "Softbody Field");
+ }
+}
ModifierTypeInfo modifierType_Softbody = {
/* name */ "Softbody",
@@ -65,6 +94,7 @@ ModifierTypeInfo modifierType_Softbody = {
/* structSize */ sizeof(SoftbodyModifierData),
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsCVs |
+ eModifierTypeFlag_AcceptsLattice |
eModifierTypeFlag_RequiresOriginalData |
eModifierTypeFlag_Single,
@@ -79,8 +109,8 @@ ModifierTypeInfo modifierType_Softbody = {
/* requiredDataMask */ NULL,
/* freeData */ NULL,
/* isDisabled */ NULL,
- /* updateDepgraph */ NULL,
- /* updateDepsgraph */ NULL,
+ /* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c
index 527576843e3..911b6997058 100644
--- a/source/blender/modifiers/intern/MOD_solidify.c
+++ b/source/blender/modifiers/intern/MOD_solidify.c
@@ -141,9 +141,9 @@ static void dm_calc_normal(DerivedMesh *dm, float (*face_nors)[3], float (*r_ver
* using the angle between the 2 faces as a weighting */
#if 0
add_v3_v3v3(edge_normal, face_nors[edge_ref->f1], face_nors[edge_ref->f2]);
- normalize_v3(edge_normal);
-
- mul_v3_fl(edge_normal, angle_normalized_v3v3(face_nors[edge_ref->f1], face_nors[edge_ref->f2]));
+ normalize_v3_length(
+ edge_normal,
+ angle_normalized_v3v3(face_nors[edge_ref->f1], face_nors[edge_ref->f2]));
#else
mid_v3_v3v3_angle_weighted(edge_normal, face_nors[edge_ref->f1], face_nors[edge_ref->f2]);
#endif
diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c
index 23ab61821f4..8711384e1ee 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -130,6 +130,9 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
if (U.opensubdiv_compute_type == USER_OPENSUBDIV_COMPUTE_NONE) {
modifier_setError(md, "OpenSubdiv is disabled in User Preferences");
}
+ else if ((ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)) != 0) {
+ modifier_setError(md, "OpenSubdiv is not supported in paint modes");
+ }
else if ((DAG_get_eval_flags_for_object(md->scene, ob) & DAG_EVAL_NEED_CPU) == 0) {
subsurf_flags |= SUBSURF_USE_GPU_BACKEND;
do_cddm_convert = false;
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index f9291fb077f..93414562ccf 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -286,5 +286,6 @@ void modifier_type_init(ModifierTypeInfo *types[])
INIT_TYPE(DataTransfer);
INIT_TYPE(NormalEdit);
INIT_TYPE(CorrectiveSmooth);
+ INIT_TYPE(MeshSequenceCache);
#undef INIT_TYPE
}
diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c
index 27d3bac59ec..b38de140a91 100644
--- a/source/blender/modifiers/intern/MOD_warp.c
+++ b/source/blender/modifiers/intern/MOD_warp.c
@@ -374,6 +374,7 @@ ModifierTypeInfo modifierType_Warp = {
/* structSize */ sizeof(WarpModifierData),
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsCVs |
+ eModifierTypeFlag_AcceptsLattice |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
/* deformVerts */ deformVerts,
diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c
index f13eeb3185e..683649ed1c0 100644
--- a/source/blender/modifiers/intern/MOD_wave.c
+++ b/source/blender/modifiers/intern/MOD_wave.c
@@ -384,6 +384,7 @@ ModifierTypeInfo modifierType_Wave = {
/* structSize */ sizeof(WaveModifierData),
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsCVs |
+ eModifierTypeFlag_AcceptsLattice |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
/* deformVerts */ deformVerts,
diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c
index 01a219d1457..170fbbed7f1 100644
--- a/source/blender/modifiers/intern/MOD_weightvgmix.c
+++ b/source/blender/modifiers/intern/MOD_weightvgmix.c
@@ -221,9 +221,11 @@ static void updateDepsgraph(ModifierData *md,
WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md;
if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
DEG_add_object_relation(node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGMix Modifier");
+ DEG_add_object_relation(node, wmd->mask_tex_map_obj, DEG_OB_COMP_GEOMETRY, "WeightVGMix Modifier");
}
if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) {
DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "WeightVGMix Modifier");
+ DEG_add_object_relation(node, ob, DEG_OB_COMP_GEOMETRY, "WeightVGMix Modifier");
}
}
diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c
index 0968d2aa5e0..af59f11ba15 100644
--- a/source/blender/modifiers/intern/MOD_weightvgproximity.c
+++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c
@@ -378,12 +378,15 @@ static void updateDepsgraph(ModifierData *md,
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *)md;
if (wmd->proximity_ob_target != NULL) {
DEG_add_object_relation(node, wmd->proximity_ob_target, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier");
+ DEG_add_object_relation(node, wmd->proximity_ob_target, DEG_OB_COMP_GEOMETRY, "WeightVGProximity Modifier");
}
if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
DEG_add_object_relation(node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier");
+ DEG_add_object_relation(node, wmd->mask_tex_map_obj, DEG_OB_COMP_GEOMETRY, "WeightVGProximity Modifier");
}
if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) {
DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier");
+ DEG_add_object_relation(node, ob, DEG_OB_COMP_GEOMETRY, "WeightVGProximity Modifier");
}
}
diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c
index fe21757d5c2..adadd4834d4 100644
--- a/source/blender/modifiers/intern/MOD_wireframe.c
+++ b/source/blender/modifiers/intern/MOD_wireframe.c
@@ -1,23 +1,23 @@
/*
-* ***** BEGIN GPL LICENSE BLOCK *****
-*
-* This program is free software; you can redistribute it and/or
-* modify it under the terms of the GNU General Public License
-* as published by the Free Software Foundation; either version 2
-* of the License, or (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public 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 *****
-*
-*/
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
/** \file blender/modifiers/intern/MOD_wireframe.c
* \ingroup modifiers
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 47808fbec77..ac0fa2ea5fb 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -82,7 +82,7 @@ DefNode( ShaderNode, SH_NODE_BSDF_ANISOTROPIC, def_anisotropic, "BS
DefNode( ShaderNode, SH_NODE_BSDF_DIFFUSE, 0, "BSDF_DIFFUSE", BsdfDiffuse, "Diffuse BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_GLOSSY, def_glossy, "BSDF_GLOSSY", BsdfGlossy, "Glossy BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_GLASS, def_glass, "BSDF_GLASS", BsdfGlass, "Glass BSDF", "" )
-DefNode( ShaderNode, SH_NODE_BSDF_REFRACTION, def_glass, "BSDF_REFRACTION", BsdfRefraction, "Refraction BSDF", "" )
+DefNode( ShaderNode, SH_NODE_BSDF_REFRACTION, def_refraction, "BSDF_REFRACTION", BsdfRefraction, "Refraction BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_TRANSLUCENT, 0, "BSDF_TRANSLUCENT", BsdfTranslucent, "Translucent BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_TRANSPARENT, 0, "BSDF_TRANSPARENT", BsdfTransparent, "Transparent BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_VELVET, 0, "BSDF_VELVET", BsdfVelvet, "Velvet BSDF", "" )
diff --git a/source/blender/nodes/intern/node_common.c b/source/blender/nodes/intern/node_common.c
index 12cd93e418b..fbc036435f0 100644
--- a/source/blender/nodes/intern/node_common.c
+++ b/source/blender/nodes/intern/node_common.c
@@ -78,7 +78,7 @@ bNodeSocket *node_group_find_output_socket(bNode *groupnode, const char *identif
/* groups display their internal tree name as label */
void node_group_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
{
- BLI_strncpy(label, (node->id) ? node->id->name + 2 : IFACE_("Missing Datablock"), maxlen);
+ BLI_strncpy(label, (node->id) ? node->id->name + 2 : IFACE_("Missing Data-Block"), maxlen);
}
int node_group_poll_instance(bNode *node, bNodeTree *nodetree)
diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c
index c4ec55c8d06..40d1cfdfcb0 100644
--- a/source/blender/nodes/shader/node_shader_tree.c
+++ b/source/blender/nodes/shader/node_shader_tree.c
@@ -57,6 +57,8 @@
#include "RE_shader_ext.h"
+#include "NOD_common.h"
+
#include "node_common.h"
#include "node_exec.h"
#include "node_util.h"
@@ -199,17 +201,295 @@ void register_node_tree_type_sh(void)
/* GPU material from shader nodes */
+static void ntree_shader_link_builtin_normal(bNodeTree *ntree,
+ bNode *node_from,
+ bNodeSocket *socket_from,
+ bNode *displacement_node,
+ bNodeSocket *displacement_socket);
+
+/* Find an output node of the shader tree.
+ *
+ * NOTE: it will only return output which is NOT in the group, which isn't how
+ * render engines works but it's how the GPU shader compilation works. This we
+ * can change in the future and make it a generic function, but for now it stays
+ * private here.
+ */
+static bNode *ntree_shader_output_node(bNodeTree *ntree)
+{
+ /* Make sure we only have single node tagged as output. */
+ ntreeSetOutput(ntree);
+ for (bNode *node = ntree->nodes.first; node != NULL; node = node->next) {
+ if (node->flag & NODE_DO_OUTPUT) {
+ return node;
+ }
+ }
+ return NULL;
+}
+
+/* Find socket with a specified identifier. */
+static bNodeSocket *ntree_shader_node_find_socket(ListBase *sockets,
+ const char *identifier)
+{
+ for (bNodeSocket *sock = sockets->first; sock != NULL; sock = sock->next) {
+ if (STREQ(sock->identifier, identifier)) {
+ return sock;
+ }
+ }
+ return NULL;
+}
+
+/* Find input socket with a specified identifier. */
+static bNodeSocket *ntree_shader_node_find_input(bNode *node,
+ const char *identifier)
+{
+ return ntree_shader_node_find_socket(&node->inputs, identifier);
+}
+
+/* Find output socket with a specified identifier. */
+static bNodeSocket *ntree_shader_node_find_output(bNode *node,
+ const char *identifier)
+{
+ return ntree_shader_node_find_socket(&node->outputs, identifier);
+}
+
+/* Check whether shader has a displacement.
+ *
+ * Will also return a node and it's socket which is connected to a displacement
+ * output. Additionally, link which is attached to the displacement output is
+ * also returned.
+ */
+static bool ntree_shader_has_displacement(bNodeTree *ntree,
+ bNode **r_node,
+ bNodeSocket **r_socket,
+ bNodeLink **r_link)
+{
+ bNode *output_node = ntree_shader_output_node(ntree);
+ if (output_node == NULL) {
+ /* We can't have displacement without output node, apparently. */
+ return false;
+ }
+ /* Make sure sockets links pointers are correct. */
+ ntreeUpdateTree(G.main, ntree);
+ bNodeSocket *displacement = ntree_shader_node_find_input(output_node,
+ "Displacement");
+
+ if (displacement == NULL) {
+ /* Non-cycles node is used as an output. */
+ return false;
+ }
+ if (displacement->link != NULL) {
+ *r_node = displacement->link->fromnode;
+ *r_socket = displacement->link->fromsock;
+ *r_link = displacement->link;
+ }
+ return displacement->link != NULL;
+}
+
+static bool ntree_shader_relink_node_normal(bNodeTree *ntree,
+ bNode *node,
+ bNode *node_from,
+ bNodeSocket *socket_from)
+{
+ bNodeSocket *sock = ntree_shader_node_find_input(node, "Normal");
+ /* TODO(sergey): Can we do something smarter here than just a name-based
+ * matching?
+ */
+ if (sock == NULL) {
+ /* There's no Normal input, nothing to link. */
+ return false;
+ }
+ if (sock->link != NULL) {
+ /* Something is linked to the normal input already. can't
+ * use other input for that.
+ */
+ return false;
+ }
+ /* Create connection between specified node and the normal input. */
+ nodeAddLink(ntree, node_from, socket_from, node, sock);
+ return true;
+}
+
+static void ntree_shader_link_builtin_group_normal(
+ bNodeTree *ntree,
+ bNode *group_node,
+ bNode *node_from,
+ bNodeSocket *socket_from,
+ bNode *displacement_node,
+ bNodeSocket *displacement_socket)
+{
+ bNodeTree *group_ntree = (bNodeTree *)group_node->id;
+ /* Create input socket to plug displacement connection to. */
+ bNodeSocket *group_normal_socket =
+ ntreeAddSocketInterface(group_ntree,
+ SOCK_IN,
+ "NodeSocketVector",
+ "Normal");
+ /* Need to update tree so all node instances nodes gets proper sockets. */
+ bNode *group_input_node = ntreeFindType(group_ntree, NODE_GROUP_INPUT);
+ node_group_verify(ntree, group_node, &group_ntree->id);
+ if (group_input_node)
+ node_group_input_verify(group_ntree, group_input_node, &group_ntree->id);
+ ntreeUpdateTree(G.main, group_ntree);
+ /* Assumes sockets are always added at the end. */
+ bNodeSocket *group_node_normal_socket = group_node->inputs.last;
+ if (displacement_node == group_node) {
+ /* If displacement is coming from this node group we need to perform
+ * some internal re-linking in order to avoid cycles.
+ */
+ bNode *group_output_node = ntreeFindType(group_ntree, NODE_GROUP_OUTPUT);
+ BLI_assert(group_output_node != NULL);
+ bNodeSocket *group_output_node_displacement_socket =
+ nodeFindSocket(group_output_node,
+ SOCK_IN,
+ displacement_socket->identifier);
+ bNodeLink *group_displacement_link = group_output_node_displacement_socket->link;
+ if (group_displacement_link == NULL) {
+ /* Displacement output is not connected to anything, can just stop
+ * right away.
+ */
+ return;
+ }
+ /* This code is similar to ntree_shader_relink_displacement() */
+ bNode *group_displacement_node = group_displacement_link->fromnode;
+ bNodeSocket *group_displacement_socket = group_displacement_link->fromsock;
+ /* Create and link bump node.
+ * Can't re-use bump node from parent tree because it'll cause cycle.
+ */
+ bNode *bump_node = nodeAddStaticNode(NULL, group_ntree, SH_NODE_BUMP);
+ bNodeSocket *bump_input_socket = ntree_shader_node_find_input(bump_node, "Height");
+ bNodeSocket *bump_output_socket = ntree_shader_node_find_output(bump_node, "Normal");
+ BLI_assert(bump_input_socket != NULL);
+ BLI_assert(bump_output_socket != NULL);
+ nodeAddLink(group_ntree,
+ group_displacement_node, group_displacement_socket,
+ bump_node, bump_input_socket);
+ /* Relink normals inside of the instanced tree. */
+ ntree_shader_link_builtin_normal(group_ntree,
+ bump_node,
+ bump_output_socket,
+ group_displacement_node,
+ group_displacement_socket);
+ ntreeUpdateTree(G.main, group_ntree);
+ }
+ else if (group_input_node) {
+ /* Connect group node normal input. */
+ nodeAddLink(ntree,
+ node_from, socket_from,
+ group_node, group_node_normal_socket);
+ BLI_assert(group_input_node != NULL);
+ bNodeSocket *group_input_node_normal_socket =
+ nodeFindSocket(group_input_node,
+ SOCK_OUT,
+ group_normal_socket->identifier);
+ BLI_assert(group_input_node_normal_socket != NULL);
+ /* Relink normals inside of the instanced tree. */
+ ntree_shader_link_builtin_normal(group_ntree,
+ group_input_node,
+ group_input_node_normal_socket,
+ displacement_node,
+ displacement_socket);
+ ntreeUpdateTree(G.main, group_ntree);
+ }
+}
+
+/* Use specified node and socket as an input for unconnected normal sockets. */
+static void ntree_shader_link_builtin_normal(bNodeTree *ntree,
+ bNode *node_from,
+ bNodeSocket *socket_from,
+ bNode *displacement_node,
+ bNodeSocket *displacement_socket)
+{
+ for (bNode *node = ntree->nodes.first; node != NULL; node = node->next) {
+ if (node == node_from) {
+ /* Don't connect node itself! */
+ continue;
+ }
+ if (node->type == NODE_GROUP && node->id) {
+ /* Special re-linking for group nodes. */
+ ntree_shader_link_builtin_group_normal(ntree,
+ node,
+ node_from,
+ socket_from,
+ displacement_node,
+ displacement_socket);
+ continue;
+ }
+ if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) {
+ /* Group inputs and outputs needs nothing special. */
+ continue;
+ }
+ ntree_shader_relink_node_normal(ntree, node, node_from, socket_from);
+ }
+}
+
+/* Re-link displacement output to unconnected normal sockets via bump node.
+ * This way material with have proper displacement in the viewport.
+ */
+static void ntree_shader_relink_displacement(bNodeTree *ntree,
+ short compatibility)
+{
+ if (compatibility != NODE_NEW_SHADING) {
+ /* We can only deal with new shading system here. */
+ return;
+ }
+ bNode *displacement_node;
+ bNodeSocket *displacement_socket;
+ bNodeLink *displacement_link;
+ if (!ntree_shader_has_displacement(ntree,
+ &displacement_node,
+ &displacement_socket,
+ &displacement_link))
+ {
+ /* There is no displacement output connected, nothing to re-link. */
+ return;
+ }
+ /* We have to disconnect displacement output socket, otherwise we'll have
+ * cycles in the Cycles material :)
+ */
+ nodeRemLink(ntree, displacement_link);
+ /* We can't connect displacement to normal directly, use bump node for that
+ * and hope that it gives good enough approximation.
+ */
+ bNode *bump_node = nodeAddStaticNode(NULL, ntree, SH_NODE_BUMP);
+ bNodeSocket *bump_input_socket = ntree_shader_node_find_input(bump_node, "Height");
+ bNodeSocket *bump_output_socket = ntree_shader_node_find_output(bump_node, "Normal");
+ BLI_assert(bump_input_socket != NULL);
+ BLI_assert(bump_output_socket != NULL);
+ /* Connect bump node to where displacement output was originally
+ * connected to.
+ */
+ nodeAddLink(ntree,
+ displacement_node, displacement_socket,
+ bump_node, bump_input_socket);
+ /* Connect all free-standing Normal inputs. */
+ ntree_shader_link_builtin_normal(ntree,
+ bump_node,
+ bump_output_socket,
+ displacement_node,
+ displacement_socket);
+ /* TODO(sergey): Reconnect Geometry Info->Normal sockets to the new
+ * bump node.
+ */
+ /* We modified the tree, it needs to be updated now. */
+ ntreeUpdateTree(G.main, ntree);
+}
+
void ntreeGPUMaterialNodes(bNodeTree *ntree, GPUMaterial *mat, short compatibility)
{
/* localize tree to create links for reroute and mute */
bNodeTree *localtree = ntreeLocalize(ntree);
bNodeTreeExec *exec;
+ /* Perform all needed modifications on the tree in order to support
+ * displacement/bump mapping.
+ */
+ ntree_shader_relink_displacement(localtree, compatibility);
+
exec = ntreeShaderBeginExecTree(localtree);
ntreeExecGPUNodes(exec, mat, 1, compatibility);
ntreeShaderEndExecTree(exec);
- ntreeFreeTree_ex(localtree, false);
+ ntreeFreeTree(localtree);
MEM_freeN(localtree);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_attribute.c b/source/blender/nodes/shader/nodes/node_shader_attribute.c
index 61bdfb3dfd6..0a69593cf07 100644
--- a/source/blender/nodes/shader/nodes/node_shader_attribute.c
+++ b/source/blender/nodes/shader/nodes/node_shader_attribute.c
@@ -45,9 +45,9 @@ static void node_shader_init_attribute(bNodeTree *UNUSED(ntree), bNode *node)
static int node_shader_gpu_attribute(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
NodeShaderAttribute *attr = node->storage;
- GPUNodeLink *mtface = GPU_attribute(CD_MTFACE, attr->name);
+ GPUNodeLink *cd_attr = GPU_attribute(CD_AUTO_FROM_NAME, attr->name);
- return GPU_stack_link(mat, "node_attribute", in, out, mtface);
+ return GPU_stack_link(mat, "node_attribute", in, out, cd_attr);
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_brightness.c b/source/blender/nodes/shader/nodes/node_shader_brightness.c
index 8c873b57790..e992c0773c2 100644
--- a/source/blender/nodes/shader/nodes/node_shader_brightness.c
+++ b/source/blender/nodes/shader/nodes/node_shader_brightness.c
@@ -23,8 +23,7 @@
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
-
-*/
+ */
#include "node_shader_util.h"
diff --git a/source/blender/nodes/shader/nodes/node_shader_bump.c b/source/blender/nodes/shader/nodes/node_shader_bump.c
index 22027d58385..b39ca5d90ee 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bump.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bump.c
@@ -45,14 +45,21 @@ static bNodeSocketTemplate sh_node_bump_out[] = {
{ -1, 0, "" }
};
-static int gpu_shader_bump(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int gpu_shader_bump(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
if (!in[3].link)
in[3].link = GPU_builtin(GPU_VIEW_NORMAL);
else
GPU_link(mat, "direction_transform_m4v3", in[3].link, GPU_builtin(GPU_VIEW_MATRIX), &in[3].link);
-
- return GPU_stack_link(mat, "node_bump", in, out);
+ float invert = node->custom1;
+ GPU_stack_link(mat, "node_bump", in, out, GPU_builtin(GPU_VIEW_POSITION), GPU_uniform(&invert));
+ /* Other nodes are applying view matrix if the input Normal has a link.
+ * We don't want normal to have view matrix applied twice, so we cancel it here.
+ *
+ * TODO(sergey): This is an extra multiplication which cancels each other,
+ * better avoid this but that requires bigger refactor.
+ */
+ return GPU_link(mat, "direction_transform_m4v3", out[0].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[0].link);
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_camera.c b/source/blender/nodes/shader/nodes/node_shader_camera.c
index 49ebb15d7a4..3bdb5c36d69 100644
--- a/source/blender/nodes/shader/nodes/node_shader_camera.c
+++ b/source/blender/nodes/shader/nodes/node_shader_camera.c
@@ -54,7 +54,15 @@ static void node_shader_exec_camera(void *data, int UNUSED(thread), bNode *UNUSE
static int gpu_shader_camera(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "camera", in, out, GPU_builtin(GPU_VIEW_POSITION));
+ GPUNodeLink *viewvec;
+
+ viewvec = GPU_builtin(GPU_VIEW_POSITION);
+
+ /* Blender has negative Z, Cycles positive Z convention */
+ if (GPU_material_use_new_shading_nodes(mat))
+ GPU_link(mat, "invert_z", viewvec, &viewvec);
+
+ return GPU_stack_link(mat, "camera", in, out, viewvec);
}
void register_node_type_sh_camera(void)
diff --git a/source/blender/nodes/shader/nodes/node_shader_fresnel.c b/source/blender/nodes/shader/nodes/node_shader_fresnel.c
index b50f722c71b..ef2ce99c924 100644
--- a/source/blender/nodes/shader/nodes/node_shader_fresnel.c
+++ b/source/blender/nodes/shader/nodes/node_shader_fresnel.c
@@ -41,10 +41,12 @@ static bNodeSocketTemplate sh_node_fresnel_out[] = {
static int node_shader_gpu_fresnel(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- if (!in[1].link)
+ if (!in[1].link) {
in[1].link = GPU_builtin(GPU_VIEW_NORMAL);
- else
+ }
+ else if (GPU_material_use_world_space_shading(mat)) {
GPU_link(mat, "direction_transform_m4v3", in[1].link, GPU_builtin(GPU_VIEW_MATRIX), &in[1].link);
+ }
return GPU_stack_link(mat, "node_fresnel", in, out, GPU_builtin(GPU_VIEW_POSITION));
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_gamma.c b/source/blender/nodes/shader/nodes/node_shader_gamma.c
index 0264abe451f..37439569f77 100644
--- a/source/blender/nodes/shader/nodes/node_shader_gamma.c
+++ b/source/blender/nodes/shader/nodes/node_shader_gamma.c
@@ -23,8 +23,7 @@
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
-
-*/
+ */
#include "node_shader_util.h"
diff --git a/source/blender/nodes/shader/nodes/node_shader_geom.c b/source/blender/nodes/shader/nodes/node_shader_geom.c
index cd52c4e2547..b289d66efc3 100644
--- a/source/blender/nodes/shader/nodes/node_shader_geom.c
+++ b/source/blender/nodes/shader/nodes/node_shader_geom.c
@@ -78,6 +78,10 @@ static void node_shader_exec_geom(void *data, int UNUSED(thread), bNode *node, b
copy_v3_v3(out[GEOM_OUT_UV]->vec, suv->uv);
copy_v3_v3(out[GEOM_OUT_NORMAL]->vec, shi->vno);
+ if (shi->use_world_space_shading) {
+ negate_v3(out[GEOM_OUT_NORMAL]->vec);
+ mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), out[GEOM_OUT_NORMAL]->vec);
+ }
if (shi->totcol) {
/* find vertex color layer by name */
ShadeInputCol *scol = &shi->col[0];
@@ -132,9 +136,14 @@ static int gpu_shader_geom(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(
GPUNodeLink *mtface = GPU_attribute(CD_MTFACE, ngeo->uvname);
GPUNodeLink *mcol = GPU_attribute(CD_MCOL, ngeo->colname);
- return GPU_stack_link(mat, "geom", in, out,
+ bool ret = GPU_stack_link(mat, "geom", in, out,
GPU_builtin(GPU_VIEW_POSITION), GPU_builtin(GPU_VIEW_NORMAL),
GPU_builtin(GPU_INVERSE_VIEW_MATRIX), orco, mtface, mcol);
+ if (GPU_material_use_world_space_shading(mat)) {
+ GPU_link(mat, "vec_math_negate", out[5].link, &out[5].link);
+ ret &= GPU_link(mat, "direction_transform_m4v3", out[5].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[5].link);
+ }
+ return ret;
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_lamp.c b/source/blender/nodes/shader/nodes/node_shader_lamp.c
index d5dac3b7ff8..2c96c91958e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_lamp.c
+++ b/source/blender/nodes/shader/nodes/node_shader_lamp.c
@@ -54,6 +54,8 @@ static void node_shader_exec_lamp(void *data, int UNUSED(thread), bNode *node, b
shi->nodes = 1; /* temp hack to prevent trashadow recursion */
out[4]->vec[0] = RE_lamp_get_data(shi, ob, out[0]->vec, out[1]->vec, out[2]->vec, out[3]->vec);
shi->nodes = 0;
+ if (shi->use_world_space_shading)
+ mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), out[1]->vec);
}
}
}
@@ -66,7 +68,10 @@ static int gpu_shader_lamp(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(
visifac = GPU_lamp_get_data(mat, lamp, &col, &lv, &dist, &shadow, &energy);
- return GPU_stack_link(mat, "lamp", in, out, col, energy, lv, dist, shadow, visifac);
+ bool ret = GPU_stack_link(mat, "lamp", in, out, col, energy, lv, dist, shadow, visifac);
+ if (GPU_material_use_world_space_shading(mat))
+ ret &= GPU_link(mat, "direction_transform_m4v3", out[1].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[1].link);
+ return ret;
}
return false;
diff --git a/source/blender/nodes/shader/nodes/node_shader_material.c b/source/blender/nodes/shader/nodes/node_shader_material.c
index fa13f6191ad..6850cdbf6ea 100644
--- a/source/blender/nodes/shader/nodes/node_shader_material.c
+++ b/source/blender/nodes/shader/nodes/node_shader_material.c
@@ -114,6 +114,10 @@ static void node_shader_exec_material(void *data, int UNUSED(thread), bNode *nod
/* retrieve normal */
if (hasinput[MAT_IN_NORMAL]) {
nodestack_get_vec(shi->vn, SOCK_VECTOR, in[MAT_IN_NORMAL]);
+ if (shi->use_world_space_shading) {
+ negate_v3(shi->vn);
+ mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEW_MATRIX), shi->vn);
+ }
normalize_v3(shi->vn);
}
else
@@ -181,7 +185,11 @@ static void node_shader_exec_material(void *data, int UNUSED(thread), bNode *nod
}
copy_v3_v3(out[MAT_OUT_NORMAL]->vec, shi->vn);
-
+
+ if (shi->use_world_space_shading) {
+ negate_v3(out[MAT_OUT_NORMAL]->vec);
+ mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), out[MAT_OUT_NORMAL]->vec);
+ }
/* Extended material options */
if (node->type == SH_NODE_MATERIAL_EXT) {
/* Shadow, Reflect, Refract, Radiosity, Speed seem to cause problems inside
@@ -215,12 +223,27 @@ static void node_shader_init_material(bNodeTree *UNUSED(ntree), bNode *node)
/* XXX this is also done as a local static function in gpu_codegen.c,
* but we need this to hack around the crappy material node.
*/
-static GPUNodeLink *gpu_get_input_link(GPUNodeStack *in)
+static GPUNodeLink *gpu_get_input_link(GPUMaterial *mat, GPUNodeStack *in)
{
- if (in->link)
+ if (in->link) {
return in->link;
- else
- return GPU_uniform(in->vec);
+ }
+ else {
+ GPUNodeLink *result = NULL;
+
+ /* note GPU_uniform() is only intended to be used as a parameter to
+ * GPU_link(), returning it directly results in leaks or double frees */
+ if (in->type == GPU_FLOAT)
+ GPU_link(mat, "set_value", GPU_uniform(in->vec), &result);
+ else if (in->type == GPU_VEC3)
+ GPU_link(mat, "set_rgb", GPU_uniform(in->vec), &result);
+ else if (in->type == GPU_VEC4)
+ GPU_link(mat, "set_rgba", GPU_uniform(in->vec), &result);
+ else
+ BLI_assert(0);
+
+ return result;
+ }
}
static int gpu_shader_material(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
@@ -243,18 +266,22 @@ static int gpu_shader_material(GPUMaterial *mat, bNode *node, bNodeExecData *UNU
/* write values */
if (hasinput[MAT_IN_COLOR])
- shi.rgb = gpu_get_input_link(&in[MAT_IN_COLOR]);
+ shi.rgb = gpu_get_input_link(mat, &in[MAT_IN_COLOR]);
if (hasinput[MAT_IN_SPEC])
- shi.specrgb = gpu_get_input_link(&in[MAT_IN_SPEC]);
+ shi.specrgb = gpu_get_input_link(mat, &in[MAT_IN_SPEC]);
if (hasinput[MAT_IN_REFL])
- shi.refl = gpu_get_input_link(&in[MAT_IN_REFL]);
+ shi.refl = gpu_get_input_link(mat, &in[MAT_IN_REFL]);
/* retrieve normal */
if (hasinput[MAT_IN_NORMAL]) {
GPUNodeLink *tmp;
- shi.vn = gpu_get_input_link(&in[MAT_IN_NORMAL]);
+ shi.vn = gpu_get_input_link(mat, &in[MAT_IN_NORMAL]);
+ if (GPU_material_use_world_space_shading(mat)) {
+ GPU_link(mat, "vec_math_negate", shi.vn, &shi.vn);
+ GPU_link(mat, "direction_transform_m4v3", shi.vn, GPU_builtin(GPU_VIEW_MATRIX), &shi.vn);
+ }
GPU_link(mat, "vec_math_normalize", shi.vn, &shi.vn, &tmp);
}
@@ -264,15 +291,15 @@ static int gpu_shader_material(GPUMaterial *mat, bNode *node, bNodeExecData *UNU
if (node->type == SH_NODE_MATERIAL_EXT) {
if (hasinput[MAT_IN_MIR])
- shi.mir = gpu_get_input_link(&in[MAT_IN_MIR]);
+ shi.mir = gpu_get_input_link(mat, &in[MAT_IN_MIR]);
if (hasinput[MAT_IN_AMB])
- shi.amb = gpu_get_input_link(&in[MAT_IN_AMB]);
+ shi.amb = gpu_get_input_link(mat, &in[MAT_IN_AMB]);
if (hasinput[MAT_IN_EMIT])
- shi.emit = gpu_get_input_link(&in[MAT_IN_EMIT]);
+ shi.emit = gpu_get_input_link(mat, &in[MAT_IN_EMIT]);
if (hasinput[MAT_IN_SPECTRA])
- shi.spectra = gpu_get_input_link(&in[MAT_IN_SPECTRA]);
+ shi.spectra = gpu_get_input_link(mat, &in[MAT_IN_SPECTRA]);
if (hasinput[MAT_IN_ALPHA])
- shi.alpha = gpu_get_input_link(&in[MAT_IN_ALPHA]);
+ shi.alpha = gpu_get_input_link(mat, &in[MAT_IN_ALPHA]);
}
GPU_shaderesult_set(&shi, &shr); /* clears shr */
@@ -299,6 +326,10 @@ static int gpu_shader_material(GPUMaterial *mat, bNode *node, bNodeExecData *UNU
if (node->custom1 & SH_NODE_MAT_NEG)
GPU_link(mat, "vec_math_negate", shi.vn, &shi.vn);
out[MAT_OUT_NORMAL].link = shi.vn;
+ if (GPU_material_use_world_space_shading(mat)) {
+ GPU_link(mat, "vec_math_negate", out[MAT_OUT_NORMAL].link, &out[MAT_OUT_NORMAL].link);
+ GPU_link(mat, "direction_transform_m4v3", out[MAT_OUT_NORMAL].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[MAT_OUT_NORMAL].link);
+ }
if (node->type == SH_NODE_MATERIAL_EXT) {
out[MAT_OUT_DIFFUSE].link = shr.diff;
diff --git a/source/blender/nodes/shader/nodes/node_shader_normal_map.c b/source/blender/nodes/shader/nodes/node_shader_normal_map.c
index 642e5b296be..48d1688c386 100644
--- a/source/blender/nodes/shader/nodes/node_shader_normal_map.c
+++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.c
@@ -89,20 +89,34 @@ static void node_shader_exec_normal_map(void *data, int UNUSED(thread), bNode *n
for (int j = 0; j < 3; j++)
out[0]->vec[j] = vecIn[0] * T[j] + vecIn[1] * B[j] + vecIn[2] * N[j];
interp_v3_v3v3(out[0]->vec, N, out[0]->vec, strength);
+ if (shi->use_world_space_shading) {
+ mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), out[0]->vec);
+ }
break;
case SHD_NORMAL_MAP_OBJECT:
case SHD_NORMAL_MAP_BLENDER_OBJECT:
- mul_mat3_m4_v3((float (*)[4])RE_object_instance_get_matrix(shi->obi, RE_OBJECT_INSTANCE_MATRIX_LOCALTOVIEW), vecIn);
+ if (shi->use_world_space_shading) {
+ mul_mat3_m4_v3((float (*)[4])RE_object_instance_get_matrix(shi->obi, RE_OBJECT_INSTANCE_MATRIX_OB), vecIn);
+ mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), N);
+ }
+ else
+ mul_mat3_m4_v3((float (*)[4])RE_object_instance_get_matrix(shi->obi, RE_OBJECT_INSTANCE_MATRIX_LOCALTOVIEW), vecIn);
interp_v3_v3v3(out[0]->vec, N, vecIn, strength);
break;
case SHD_NORMAL_MAP_WORLD:
case SHD_NORMAL_MAP_BLENDER_WORLD:
- mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEW_MATRIX), vecIn);
+ if (shi->use_world_space_shading)
+ mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), N);
+ else
+ mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEW_MATRIX), vecIn);
interp_v3_v3v3(out[0]->vec, N, vecIn, strength);
break;
}
+ if (shi->use_world_space_shading) {
+ negate_v3(out[0]->vec);
+ }
normalize_v3(out[0]->vec);
}
}
@@ -121,35 +135,70 @@ static int gpu_shader_normal_map(GPUMaterial *mat, bNode *node, bNodeExecData *U
else
strength = GPU_uniform(in[0].vec);
- if (in[1].link) {
- GPU_link(mat, "color_to_normal", in[1].link, &realnorm);
- GPU_link(mat, "mtex_negate_texnormal", realnorm, &realnorm);
- }
+ if (in[1].link)
+ realnorm = in[1].link;
+ else
+ realnorm = GPU_uniform(in[1].vec);
+ negnorm = GPU_builtin(GPU_VIEW_NORMAL);
GPU_link(mat, "math_max", strength, GPU_uniform(d), &strength);
- GPU_link(mat, "vec_math_negate", GPU_builtin(GPU_VIEW_NORMAL), &negnorm);
- if (in[1].link) {
+ if (GPU_material_use_world_space_shading(mat)) {
+
+ /* ******* CYCLES or BLENDER INTERNAL with world space shading flag ******* */
+
+ const char *color_to_normal_fnc_name = "color_to_normal_new_shading";
+ if (nm->space == SHD_NORMAL_MAP_BLENDER_OBJECT || nm->space == SHD_NORMAL_MAP_BLENDER_WORLD || !GPU_material_use_new_shading_nodes(mat))
+ color_to_normal_fnc_name = "color_to_blender_normal_new_shading";
switch (nm->space) {
case SHD_NORMAL_MAP_TANGENT:
- GPU_link(mat, "node_normal_map", GPU_attribute(CD_TANGENT, nm->uv_map), negnorm, realnorm, &out[0].link);
- break;
+ GPU_link(mat, "color_to_normal_new_shading", realnorm, &realnorm);
+ GPU_link(mat, "node_normal_map", GPU_attribute(CD_TANGENT, nm->uv_map), negnorm, realnorm, &realnorm);
+ GPU_link(mat, "vec_math_mix", strength, realnorm, GPU_builtin(GPU_VIEW_NORMAL), &out[0].link);
+ /* for uniform scale this is sufficient to match Cycles */
+ GPU_link(mat, "direction_transform_m4v3", out[0].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[0].link);
+ GPU_link(mat, "vect_normalize", out[0].link, &out[0].link);
+ return true;
case SHD_NORMAL_MAP_OBJECT:
case SHD_NORMAL_MAP_BLENDER_OBJECT:
- GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_LOC_TO_VIEW_MATRIX), &out[0].link);
+ GPU_link(mat, "direction_transform_m4v3", negnorm, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &negnorm);
+ GPU_link(mat, color_to_normal_fnc_name, realnorm, &realnorm);
+ GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_OBJECT_MATRIX), &realnorm);
break;
case SHD_NORMAL_MAP_WORLD:
case SHD_NORMAL_MAP_BLENDER_WORLD:
- GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_VIEW_MATRIX), &out[0].link);
+ GPU_link(mat, "direction_transform_m4v3", negnorm, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &negnorm);
+ GPU_link(mat, color_to_normal_fnc_name, realnorm, &realnorm);
break;
}
+
}
+ else {
+
+ /* ************** BLENDER INTERNAL without world space shading flag ******* */
+
+ GPU_link(mat, "color_to_normal", realnorm, &realnorm);
+ GPU_link(mat, "mtex_negate_texnormal", realnorm, &realnorm);
+ GPU_link(mat, "vec_math_negate", negnorm, &negnorm);
- if (out[0].link) {
- GPU_link(mat, "vec_math_mix", strength, out[0].link, negnorm, &out[0].link);
- GPU_link(mat, "vect_normalize", out[0].link, &out[0].link);
+ switch (nm->space) {
+ case SHD_NORMAL_MAP_TANGENT:
+ GPU_link(mat, "node_normal_map", GPU_attribute(CD_TANGENT, nm->uv_map), negnorm, realnorm, &realnorm);
+ break;
+ case SHD_NORMAL_MAP_OBJECT:
+ case SHD_NORMAL_MAP_BLENDER_OBJECT:
+ GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_LOC_TO_VIEW_MATRIX), &realnorm);
+ break;
+ case SHD_NORMAL_MAP_WORLD:
+ case SHD_NORMAL_MAP_BLENDER_WORLD:
+ GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_VIEW_MATRIX), &realnorm);
+ break;
+ }
}
+ GPU_link(mat, "vec_math_mix", strength, realnorm, negnorm, &out[0].link);
+ GPU_link(mat, "vect_normalize", out[0].link, &out[0].link);
+
return true;
}
@@ -169,4 +218,3 @@ void register_node_type_sh_normal_map(void)
nodeRegisterType(&ntype);
}
-
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_brick.c b/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
index 569eaf5ff9b..0be47c4f751 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
@@ -36,6 +36,7 @@ static bNodeSocketTemplate sh_node_tex_brick_in[] = {
{ SOCK_RGBA, 1, N_("Mortar"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK},
{ SOCK_FLOAT, 1, N_("Scale"), 5.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK},
{ SOCK_FLOAT, 1, N_("Mortar Size"), 0.02f, 0.0f, 0.0f, 0.0f, 0.0f, 0.125f, PROP_NONE, SOCK_NO_INTERNAL_LINK},
+ { SOCK_FLOAT, 1, N_("Mortar Smooth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK},
{ SOCK_FLOAT, 1, N_("Bias"), 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK},
{ SOCK_FLOAT, 1, N_("Brick Width"), 0.5f, 0.0f, 0.0f, 0.0f, 0.01f, 100.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK},
{ SOCK_FLOAT, 1, N_("Row Height"), 0.25f, 0.0f, 0.0f, 0.0f, 0.01f, 100.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK},
@@ -60,16 +61,29 @@ static void node_shader_init_tex_brick(bNodeTree *UNUSED(ntree), bNode *node)
tex->squash_freq = 2;
node->storage = tex;
+
+ for (bNodeSocket *sock = node->inputs.first; sock; sock = sock->next) {
+ if (STREQ(sock->name, "Mortar Smooth")) {
+ ((bNodeSocketValueFloat*)sock->default_value)->value = 0.1f;
+ }
+ }
}
static int node_shader_gpu_tex_brick(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- if (!in[0].link)
+ if (!in[0].link) {
in[0].link = GPU_attribute(CD_ORCO, "");
+ GPU_link(mat, "generated_from_orco", in[0].link, &in[0].link);
+ }
node_shader_gpu_tex_mapping(mat, node, in, out);
-
- return GPU_stack_link(mat, "node_tex_brick", in, out);
+ NodeTexBrick *tex = (NodeTexBrick *)node->storage;
+ float offset_freq = tex->offset_freq;
+ float squash_freq = tex->squash_freq;
+ return GPU_stack_link(mat, "node_tex_brick",
+ in, out,
+ GPU_uniform(&tex->offset), GPU_uniform(&offset_freq),
+ GPU_uniform(&tex->squash), GPU_uniform(&squash_freq));
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_checker.c b/source/blender/nodes/shader/nodes/node_shader_tex_checker.c
index b7498df1706..77edd0e115e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_checker.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_checker.c
@@ -54,8 +54,10 @@ static void node_shader_init_tex_checker(bNodeTree *UNUSED(ntree), bNode *node)
static int node_shader_gpu_tex_checker(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- if (!in[0].link)
+ if (!in[0].link) {
in[0].link = GPU_attribute(CD_ORCO, "");
+ GPU_link(mat, "generated_from_orco", in[0].link, &in[0].link);
+ }
node_shader_gpu_tex_mapping(mat, node, in, out);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c
index 24916e8f013..18a8065fb57 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c
@@ -52,12 +52,16 @@ static void node_shader_init_tex_gradient(bNodeTree *UNUSED(ntree), bNode *node)
static int node_shader_gpu_tex_gradient(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- if (!in[0].link)
+ if (!in[0].link) {
in[0].link = GPU_attribute(CD_ORCO, "");
+ GPU_link(mat, "generated_from_orco", in[0].link, &in[0].link);
+ }
node_shader_gpu_tex_mapping(mat, node, in, out);
- return GPU_stack_link(mat, "node_tex_gradient", in, out);
+ NodeTexGradient *tex = (NodeTexGradient *)node->storage;
+ float gradient_type = tex->gradient_type;
+ return GPU_stack_link(mat, "node_tex_gradient", in, out, GPU_uniform(&gradient_type));
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.c b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
index f0a8cda045e..71200dfe9d3 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_image.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
@@ -59,17 +59,49 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, bNode *node, bNodeExecDat
Image *ima = (Image *)node->id;
ImageUser *iuser = NULL;
NodeTexImage *tex = node->storage;
+
+ GPUNodeLink *norm;
+
int isdata = tex->color_space == SHD_COLORSPACE_NONE;
+ float blend = tex->projection_blend;
if (!ima)
return GPU_stack_link(mat, "node_tex_image_empty", in, out);
-
+
if (!in[0].link)
in[0].link = GPU_attribute(CD_MTFACE, "");
node_shader_gpu_tex_mapping(mat, node, in, out);
- GPU_stack_link(mat, "node_tex_image", in, out, GPU_image(ima, iuser, isdata));
+ switch (tex->projection) {
+ case SHD_PROJ_FLAT:
+ GPU_stack_link(mat, "node_tex_image", in, out, GPU_image(ima, iuser, isdata));
+ break;
+ case SHD_PROJ_BOX:
+ GPU_link(mat, "direction_transform_m4v3", GPU_builtin(GPU_VIEW_NORMAL),
+ GPU_builtin(GPU_INVERSE_VIEW_MATRIX),
+ &norm);
+ GPU_link(mat, "direction_transform_m4v3", norm,
+ GPU_builtin(GPU_INVERSE_OBJECT_MATRIX),
+ &norm);
+ GPU_link(mat, "node_tex_image_box", in[0].link,
+ norm,
+ GPU_image(ima, iuser, isdata),
+ GPU_uniform(&blend),
+ &out[0].link,
+ &out[1].link);
+ break;
+ case SHD_PROJ_SPHERE:
+ GPU_link(mat, "point_texco_remap_square", in[0].link, &in[0].link);
+ GPU_link(mat, "point_map_to_sphere", in[0].link, &in[0].link);
+ GPU_stack_link(mat, "node_tex_image", in, out, GPU_image(ima, iuser, isdata));
+ break;
+ case SHD_PROJ_TUBE:
+ GPU_link(mat, "point_texco_remap_square", in[0].link, &in[0].link);
+ GPU_link(mat, "point_map_to_tube", in[0].link, &in[0].link);
+ GPU_stack_link(mat, "node_tex_image", in, out, GPU_image(ima, iuser, isdata));
+ break;
+ }
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
if ((tex->color_space == SHD_COLORSPACE_COLOR) &&
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_magic.c b/source/blender/nodes/shader/nodes/node_shader_tex_magic.c
index 80904e376bc..8700d7954e7 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_magic.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_magic.c
@@ -57,8 +57,10 @@ static int node_shader_gpu_tex_magic(GPUMaterial *mat, bNode *node, bNodeExecDat
NodeTexMagic *tex = (NodeTexMagic *)node->storage;
float depth = tex->depth;
- if (!in[0].link)
+ if (!in[0].link) {
in[0].link = GPU_attribute(CD_ORCO, "");
+ GPU_link(mat, "generated_from_orco", in[0].link, &in[0].link);
+ }
node_shader_gpu_tex_mapping(mat, node, in, out);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
index 825ba7eb3c1..51d6699fadd 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
@@ -58,12 +58,17 @@ static void node_shader_init_tex_musgrave(bNodeTree *UNUSED(ntree), bNode *node)
static int node_shader_gpu_tex_musgrave(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- if (!in[0].link)
+ if (!in[0].link) {
in[0].link = GPU_attribute(CD_ORCO, "");
+ GPU_link(mat, "generated_from_orco", in[0].link, &in[0].link);
+ }
node_shader_gpu_tex_mapping(mat, node, in, out);
- return GPU_stack_link(mat, "node_tex_musgrave", in, out);
+ NodeTexMusgrave *tex = (NodeTexMusgrave *)node->storage;
+ float type = tex->musgrave_type;
+
+ return GPU_stack_link(mat, "node_tex_musgrave", in, out, GPU_uniform(&type));
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_noise.c b/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
index d806140694e..91015b3db25 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
@@ -54,8 +54,10 @@ static void node_shader_init_tex_noise(bNodeTree *UNUSED(ntree), bNode *node)
static int node_shader_gpu_tex_noise(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- if (!in[0].link)
+ if (!in[0].link) {
in[0].link = GPU_attribute(CD_ORCO, "");
+ GPU_link(mat, "generated_from_orco", in[0].link, &in[0].link);
+ }
node_shader_gpu_tex_mapping(mat, node, in, out);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c
index 88596a4a72f..c994798e2da 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c
@@ -53,12 +53,17 @@ static void node_shader_init_tex_voronoi(bNodeTree *UNUSED(ntree), bNode *node)
static int node_shader_gpu_tex_voronoi(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- if (!in[0].link)
+ if (!in[0].link) {
in[0].link = GPU_attribute(CD_ORCO, "");
+ GPU_link(mat, "generated_from_orco", in[0].link, &in[0].link);
+ }
node_shader_gpu_tex_mapping(mat, node, in, out);
- return GPU_stack_link(mat, "node_tex_voronoi", in, out);
+ NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
+ float coloring = tex->coloring;
+
+ return GPU_stack_link(mat, "node_tex_voronoi", in, out, GPU_uniform(&coloring));
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_wave.c b/source/blender/nodes/shader/nodes/node_shader_tex_wave.c
index 100510641e8..1194874e06c 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_wave.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_wave.c
@@ -56,12 +56,18 @@ static void node_shader_init_tex_wave(bNodeTree *UNUSED(ntree), bNode *node)
static int node_shader_gpu_tex_wave(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- if (!in[0].link)
+ if (!in[0].link) {
in[0].link = GPU_attribute(CD_ORCO, "");
+ GPU_link(mat, "generated_from_orco", in[0].link, &in[0].link);
+ }
node_shader_gpu_tex_mapping(mat, node, in, out);
- return GPU_stack_link(mat, "node_tex_wave", in, out);
+ NodeTexWave *tex = (NodeTexWave *)node->storage;
+ float wave_type = tex->wave_type;
+ float wave_profile = tex->wave_profile;
+
+ return GPU_stack_link(mat, "node_tex_wave", in, out, GPU_uniform(&wave_type), GPU_uniform(&wave_profile));
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_texture.c b/source/blender/nodes/shader/nodes/node_shader_texture.c
index 6edf6c2a0b4..b0b25a4878b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_texture.c
+++ b/source/blender/nodes/shader/nodes/node_shader_texture.c
@@ -33,6 +33,8 @@
#include "node_shader_util.h"
+#include "GPU_material.h"
+
/* **************** TEXTURE ******************** */
static bNodeSocketTemplate sh_node_texture_in[] = {
{ SOCK_VECTOR, 1, "Vector", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, /* no limit */
@@ -121,9 +123,20 @@ static int gpu_shader_texture(GPUMaterial *mat, bNode *node, bNodeExecData *UNUS
{
Tex *tex = (Tex *)node->id;
- if (tex && tex->type == TEX_IMAGE && tex->ima) {
- GPUNodeLink *texlink = GPU_image(tex->ima, &tex->iuser, false);
- GPU_stack_link(mat, "texture_image", in, out, texlink);
+ if (tex && tex->ima && (tex->type == TEX_IMAGE || tex->type == TEX_ENVMAP)) {
+ if (tex->type == TEX_IMAGE) {
+ GPUNodeLink *texlink = GPU_image(tex->ima, &tex->iuser, false);
+ GPU_stack_link(mat, "texture_image", in, out, texlink);
+ }
+ else { /* TEX_ENVMAP */
+ if (!in[0].link)
+ in[0].link = GPU_uniform(in[0].vec);
+ if (!GPU_material_use_world_space_shading(mat))
+ GPU_link(mat, "direction_transform_m4v3", in[0].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &in[0].link);
+ GPU_link(mat, "mtex_cube_map_refl_from_refldir",
+ GPU_cube_map(tex->ima, &tex->iuser, false), in[0].link, &out[0].link, &out[1].link);
+ GPU_link(mat, "color_to_normal", out[1].link, &out[2].link);
+ }
ImBuf *ibuf = BKE_image_acquire_ibuf(tex->ima, &tex->iuser, NULL);
if (ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 &&
diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp
index 648ef132655..359395b63c4 100644
--- a/source/blender/physics/intern/BPH_mass_spring.cpp
+++ b/source/blender/physics/intern/BPH_mass_spring.cpp
@@ -376,7 +376,8 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s,
s->flags |= CLOTH_SPRING_FLAG_NEEDED;
// current_position = xold + t * (newposition - xold)
- interp_v3_v3v3(goal_x, verts[s->ij].xold, verts[s->ij].xconst, time);
+ /* divide by time_scale to prevent goal vertices' delta locations from being multiplied */
+ interp_v3_v3v3(goal_x, verts[s->ij].xold, verts[s->ij].xconst, time / parms->time_scale);
sub_v3_v3v3(goal_v, verts[s->ij].xconst, verts[s->ij].xold); // distance covered over dt==1
scaling = parms->goalspring + s->stiffness * fabsf(parms->max_struct - parms->goalspring);
@@ -1004,6 +1005,8 @@ int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, ListBase *
float v[3];
sub_v3_v3v3(v, verts[i].xconst, verts[i].xold);
// mul_v3_fl(v, clmd->sim_parms->stepsPerFrame);
+ /* divide by time_scale to prevent constrained velocities from being multiplied */
+ mul_v3_fl(v, 1.0f / clmd->sim_parms->time_scale);
BPH_mass_spring_set_velocity(id, i, v);
}
}
@@ -1070,7 +1073,8 @@ int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, ListBase *
if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) {
if (verts[i].flags & CLOTH_VERT_FLAG_PINNED) {
float x[3];
- interp_v3_v3v3(x, verts[i].xold, verts[i].xconst, step + dt);
+ /* divide by time_scale to prevent pinned vertices' delta locations from being multiplied */
+ interp_v3_v3v3(x, verts[i].xold, verts[i].xconst, (step + dt) / clmd->sim_parms->time_scale);
BPH_mass_spring_set_position(id, i, x);
}
}
diff --git a/source/blender/physics/intern/hair_volume.cpp b/source/blender/physics/intern/hair_volume.cpp
index d79cf7d8c31..5cc1231e6cb 100644
--- a/source/blender/physics/intern/hair_volume.cpp
+++ b/source/blender/physics/intern/hair_volume.cpp
@@ -710,7 +710,7 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target
* div(grad(p)) = div(v)
*
* The finite difference approximation yields the linear equation system described here:
- * http://en.wikipedia.org/wiki/Discrete_Poisson_equation
+ * https://en.wikipedia.org/wiki/Discrete_Poisson_equation
*/
lMatrix A(num_cellsA, num_cellsA);
/* Reserve space for the base equation system (without boundary conditions).
@@ -888,7 +888,7 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target
#if 0 /* XXX weighting is incorrect, disabled for now */
/* Velocity filter kernel
- * See http://en.wikipedia.org/wiki/Filter_%28large_eddy_simulation%29
+ * See https://en.wikipedia.org/wiki/Filter_%28large_eddy_simulation%29
*/
BLI_INLINE void hair_volume_filter_box_convolute(HairVertexGrid *grid, float invD, const int kernel_size[3], int i, int j, int k)
diff --git a/source/blender/physics/intern/implicit_blender.c b/source/blender/physics/intern/implicit_blender.c
index 832d516b839..2ad8ee0547f 100644
--- a/source/blender/physics/intern/implicit_blender.c
+++ b/source/blender/physics/intern/implicit_blender.c
@@ -1586,8 +1586,11 @@ bool BPH_mass_spring_force_spring_linear(Implicit_Data *data, int i, int j, floa
// calculate elonglation
spring_length(data, i, j, extent, dir, &length, vel);
-
- if (length > restlen || no_compress) {
+
+ /* This code computes not only the force, but also its derivative.
+ Zero derivative effectively disables the spring for the implicit solver.
+ Thus length > restlen makes cloth unconstrained at the start of simulation. */
+ if ((length >= restlen && length > 0) || no_compress) {
float stretch_force, f[3], dfdx[3][3], dfdv[3][3];
stretch_force = stiffness * (length - restlen);
diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h
index 4006816e788..3148dab3c50 100644
--- a/source/blender/python/BPY_extern.h
+++ b/source/blender/python/BPY_extern.h
@@ -32,6 +32,7 @@
#ifndef __BPY_EXTERN_H__
#define __BPY_EXTERN_H__
+struct PathResolvedRNA;
struct Text; /* defined in DNA_text_types.h */
struct ID; /* DNA_ID.h */
struct Object; /* DNA_object_types.h */
@@ -85,7 +86,7 @@ void BPY_modules_load_user(struct bContext *C);
void BPY_app_handlers_reset(const short do_all);
void BPY_driver_reset(void);
-float BPY_driver_exec(struct ChannelDriver *driver, const float evaltime);
+float BPY_driver_exec(struct PathResolvedRNA *anim_rna, struct ChannelDriver *driver, const float evaltime);
void BPY_DECREF(void *pyob_ptr); /* Py_DECREF() */
void BPY_DECREF_RNA_INVALIDATE(void *pyob_ptr);
diff --git a/source/blender/python/bmesh/bmesh_py_api.c b/source/blender/python/bmesh/bmesh_py_api.c
index 7c5d1961849..d5973baeadb 100644
--- a/source/blender/python/bmesh/bmesh_py_api.c
+++ b/source/blender/python/bmesh/bmesh_py_api.c
@@ -53,17 +53,31 @@
#include "bmesh_py_api.h" /* own include */
PyDoc_STRVAR(bpy_bm_new_doc,
-".. method:: new()\n"
+".. method:: new(use_operators=True)\n"
"\n"
+" :arg use_operators: Support calling operators in :mod:`bmesh.ops` (uses some extra memory per vert/edge/face).\n"
+" :type use_operators: bool\n"
" :return: Return a new, empty BMesh.\n"
" :rtype: :class:`bmesh.types.BMesh`\n"
);
-static PyObject *bpy_bm_new(PyObject *UNUSED(self))
+static PyObject *bpy_bm_new(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
+ static const char *kwlist[] = {"use_operators", NULL};
BMesh *bm;
- bm = BM_mesh_create(&bm_mesh_allocsize_default);
+ bool use_operators = true;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "|$O&:new", (char **)kwlist,
+ PyC_ParseBool, &use_operators))
+ {
+ return NULL;
+ }
+
+ bm = BM_mesh_create(
+ &bm_mesh_allocsize_default,
+ &((struct BMeshCreateParams){.use_toolflags = use_operators,}));
return BPy_BMesh_CreatePyObject(bm, BPY_BMFLAG_NOP);
}
@@ -155,7 +169,7 @@ static PyObject *bpy_bm_update_edit_mesh(PyObject *UNUSED(self), PyObject *args,
}
static struct PyMethodDef BPy_BM_methods[] = {
- {"new", (PyCFunction)bpy_bm_new, METH_NOARGS, bpy_bm_new_doc},
+ {"new", (PyCFunction)bpy_bm_new, METH_VARARGS | METH_KEYWORDS, bpy_bm_new_doc},
{"from_edit_mesh", (PyCFunction)bpy_bm_from_edit_mesh, METH_O, bpy_bm_from_edit_mesh_doc},
{"update_edit_mesh", (PyCFunction)bpy_bm_update_edit_mesh, METH_VARARGS | METH_KEYWORDS, bpy_bm_update_edit_mesh_doc},
{NULL, NULL, 0, NULL}
@@ -193,20 +207,21 @@ PyObject *BPyInit_bmesh(void)
/* bmesh.types */
PyModule_AddObject(mod, "types", (submodule = BPyInit_bmesh_types()));
- PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
+ PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
Py_INCREF(submodule);
+ /* bmesh.ops (not a real module, exposes module like access). */
PyModule_AddObject(mod, "ops", (submodule = BPyInit_bmesh_ops()));
- /* PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule); */
+ /* PyDict_SetItemString(sys_modules, PyModule_GetNameObject(submodule), submodule); */
PyDict_SetItemString(sys_modules, "bmesh.ops", submodule); /* fake module */
Py_INCREF(submodule);
PyModule_AddObject(mod, "utils", (submodule = BPyInit_bmesh_utils()));
- PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
+ PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
Py_INCREF(submodule);
PyModule_AddObject(mod, "geometry", (submodule = BPyInit_bmesh_geometry()));
- PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
+ PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
Py_INCREF(submodule);
return mod;
diff --git a/source/blender/python/bmesh/bmesh_py_ops_call.c b/source/blender/python/bmesh/bmesh_py_ops_call.c
index 1dc70c3d288..8f287918a4a 100644
--- a/source/blender/python/bmesh/bmesh_py_ops_call.c
+++ b/source/blender/python/bmesh/bmesh_py_ops_call.c
@@ -581,7 +581,7 @@ static PyObject *bpy_slot_to_py(BMesh *bm, BMOpSlot *slot)
switch (slot->slot_subtype.map) {
case BMO_OP_SLOT_SUBTYPE_MAP_ELEM:
{
- item = PyDict_New();
+ item = _PyDict_NewPresized(slot_hash ? BLI_ghash_size(slot_hash) : 0);
if (slot_hash) {
GHASH_ITER (hash_iter, slot_hash) {
BMHeader *ele_key = BLI_ghashIterator_getKey(&hash_iter);
@@ -599,7 +599,7 @@ static PyObject *bpy_slot_to_py(BMesh *bm, BMOpSlot *slot)
}
case BMO_OP_SLOT_SUBTYPE_MAP_FLT:
{
- item = PyDict_New();
+ item = _PyDict_NewPresized(slot_hash ? BLI_ghash_size(slot_hash) : 0);
if (slot_hash) {
GHASH_ITER (hash_iter, slot_hash) {
BMHeader *ele_key = BLI_ghashIterator_getKey(&hash_iter);
@@ -617,7 +617,7 @@ static PyObject *bpy_slot_to_py(BMesh *bm, BMOpSlot *slot)
}
case BMO_OP_SLOT_SUBTYPE_MAP_INT:
{
- item = PyDict_New();
+ item = _PyDict_NewPresized(slot_hash ? BLI_ghash_size(slot_hash) : 0);
if (slot_hash) {
GHASH_ITER (hash_iter, slot_hash) {
BMHeader *ele_key = BLI_ghashIterator_getKey(&hash_iter);
@@ -635,7 +635,7 @@ static PyObject *bpy_slot_to_py(BMesh *bm, BMOpSlot *slot)
}
case BMO_OP_SLOT_SUBTYPE_MAP_BOOL:
{
- item = PyDict_New();
+ item = _PyDict_NewPresized(slot_hash ? BLI_ghash_size(slot_hash) : 0);
if (slot_hash) {
GHASH_ITER (hash_iter, slot_hash) {
BMHeader *ele_key = BLI_ghashIterator_getKey(&hash_iter);
@@ -698,6 +698,12 @@ PyObject *BPy_BMO_call(BPy_BMeshOpFunc *self, PyObject *args, PyObject *kw)
BPY_BM_CHECK_OBJ(py_bm);
bm = py_bm->bm;
+ if (bm->use_toolflags == false) {
+ PyErr_SetString(PyExc_ValueError,
+ "bmesh created with 'use_operators=False'");
+ return NULL;
+ }
+
/* could complain about entering with exceptions... */
BMO_error_clear(bm);
}
diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c
index a0722af522b..1d951bae48b 100644
--- a/source/blender/python/bmesh/bmesh_py_types.c
+++ b/source/blender/python/bmesh/bmesh_py_types.c
@@ -1803,6 +1803,82 @@ static PyObject *bpy_bmface_calc_perimeter(BPy_BMFace *self)
}
+PyDoc_STRVAR(bpy_bmface_calc_tangent_edge_doc,
+".. method:: calc_tangent_edge()\n"
+"\n"
+" Return face tangent based on longest edge.\n"
+"\n"
+" :return: a normalized vector.\n"
+" :rtype: :class:`mathutils.Vector`\n"
+);
+static PyObject *bpy_bmface_calc_tangent_edge(BPy_BMFace *self)
+{
+ float tangent[3];
+
+ BPY_BM_CHECK_OBJ(self);
+ BM_face_calc_tangent_edge(self->f, tangent);
+ return Vector_CreatePyObject(tangent, 3, NULL);
+}
+
+
+PyDoc_STRVAR(bpy_bmface_calc_tangent_edge_pair_doc,
+".. method:: calc_tangent_edge_pair()\n"
+"\n"
+" Return face tangent based on the two longest disconnected edges.\n"
+"\n"
+" - Tris: Use the edge pair with the most similar lengths.\n"
+" - Quads: Use the longest edge pair.\n"
+" - NGons: Use the two longest disconnected edges.\n"
+"\n"
+" :return: a normalized vector.\n"
+" :rtype: :class:`mathutils.Vector`\n"
+);
+static PyObject *bpy_bmface_calc_tangent_edge_pair(BPy_BMFace *self)
+{
+ float tangent[3];
+
+ BPY_BM_CHECK_OBJ(self);
+ BM_face_calc_tangent_edge_pair(self->f, tangent);
+ return Vector_CreatePyObject(tangent, 3, NULL);
+}
+
+
+PyDoc_STRVAR(bpy_bmface_calc_tangent_edge_diagonal_doc,
+".. method:: calc_tangent_edge_diagonal()\n"
+"\n"
+" Return face tangent based on the edge farthest from any vertex.\n"
+"\n"
+" :return: a normalized vector.\n"
+" :rtype: :class:`mathutils.Vector`\n"
+);
+static PyObject *bpy_bmface_calc_tangent_edge_diagonal(BPy_BMFace *self)
+{
+ float tangent[3];
+
+ BPY_BM_CHECK_OBJ(self);
+ BM_face_calc_tangent_edge_diagonal(self->f, tangent);
+ return Vector_CreatePyObject(tangent, 3, NULL);
+}
+
+
+PyDoc_STRVAR(bpy_bmface_calc_tangent_vert_diagonal_doc,
+".. method:: calc_tangent_vert_diagonal()\n"
+"\n"
+" Return face tangent based on the two most distent vertices.\n"
+"\n"
+" :return: a normalized vector.\n"
+" :rtype: :class:`mathutils.Vector`\n"
+);
+static PyObject *bpy_bmface_calc_tangent_vert_diagonal(BPy_BMFace *self)
+{
+ float tangent[3];
+
+ BPY_BM_CHECK_OBJ(self);
+ BM_face_calc_tangent_vert_diagonal(self->f, tangent);
+ return Vector_CreatePyObject(tangent, 3, NULL);
+}
+
+
PyDoc_STRVAR(bpy_bmface_calc_center_mean_doc,
".. method:: calc_center_median()\n"
"\n"
@@ -2702,6 +2778,10 @@ static struct PyMethodDef bpy_bmface_methods[] = {
{"calc_area", (PyCFunction)bpy_bmface_calc_area, METH_NOARGS, bpy_bmface_calc_area_doc},
{"calc_perimeter", (PyCFunction)bpy_bmface_calc_perimeter, METH_NOARGS, bpy_bmface_calc_perimeter_doc},
+ {"calc_tangent_edge", (PyCFunction)bpy_bmface_calc_tangent_edge, METH_NOARGS, bpy_bmface_calc_tangent_edge_doc},
+ {"calc_tangent_edge_pair", (PyCFunction)bpy_bmface_calc_tangent_edge_pair, METH_NOARGS, bpy_bmface_calc_tangent_edge_pair_doc},
+ {"calc_tangent_edge_diagonal", (PyCFunction)bpy_bmface_calc_tangent_edge_diagonal, METH_NOARGS, bpy_bmface_calc_tangent_edge_diagonal_doc},
+ {"calc_tangent_vert_diagonal", (PyCFunction)bpy_bmface_calc_tangent_vert_diagonal, METH_NOARGS, bpy_bmface_calc_tangent_vert_diagonal_doc},
{"calc_center_median", (PyCFunction)bpy_bmface_calc_center_mean, METH_NOARGS, bpy_bmface_calc_center_mean_doc},
{"calc_center_median_weighted", (PyCFunction)bpy_bmface_calc_center_mean_weighted, METH_NOARGS, bpy_bmface_calc_center_mean_weighted_doc},
{"calc_center_bounds", (PyCFunction)bpy_bmface_calc_center_bounds, METH_NOARGS, bpy_bmface_calc_center_bounds_doc},
diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c
index 4bd2e9d8d62..3ea10228ad4 100644
--- a/source/blender/python/generic/bgl.c
+++ b/source/blender/python/generic/bgl.c
@@ -983,7 +983,7 @@ static PyObject *Buffer_repr(Buffer *self)
switch (self->type) {
case GL_BYTE: typestr = "GL_BYTE"; break;
case GL_SHORT: typestr = "GL_SHORT"; break;
- case GL_INT: typestr = "GL_BYTE"; break;
+ case GL_INT: typestr = "GL_INT"; break;
case GL_FLOAT: typestr = "GL_FLOAT"; break;
case GL_DOUBLE: typestr = "GL_DOUBLE"; break;
default: typestr = "UNKNOWN"; break;
diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c
index db8ed072722..2e15b7b1413 100644
--- a/source/blender/python/generic/idprop_py_api.c
+++ b/source/blender/python/generic/idprop_py_api.c
@@ -98,7 +98,7 @@ static PyObject *idprop_py_from_idp_array(ID *id, IDProperty *prop)
static PyObject *idprop_py_from_idp_idparray(ID *id, IDProperty *prop)
{
- PyObject *seq = PyList_New(prop->len), *wrap;
+ PyObject *seq = PyList_New(prop->len);
IDProperty *array = IDP_IDPArray(prop);
int i;
@@ -110,10 +110,13 @@ static PyObject *idprop_py_from_idp_idparray(ID *id, IDProperty *prop)
}
for (i = 0; i < prop->len; i++) {
- wrap = BPy_IDGroup_WrapData(id, array++, prop);
+ PyObject *wrap = BPy_IDGroup_WrapData(id, array++, prop);
- if (!wrap) /* BPy_IDGroup_MapDataToPy sets the error */
+ /* BPy_IDGroup_MapDataToPy sets the error */
+ if (UNLIKELY(wrap == NULL)) {
+ Py_DECREF(seq);
return NULL;
+ }
PyList_SET_ITEM(seq, i, wrap);
}
@@ -378,8 +381,10 @@ bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group,
}
else if (PyUnicode_Check(ob)) {
#ifdef USE_STRING_COERCE
+ Py_ssize_t value_size;
PyObject *value_coerce = NULL;
- val.string.str = PyC_UnicodeAsByte(ob, &value_coerce);
+ val.string.str = PyC_UnicodeAsByteAndSize(ob, &value_size, &value_coerce);
+ val.string.len = (int)value_size + 1;
val.string.subtype = IDP_STRING_SUB_UTF8;
prop = IDP_New(IDP_STRING, &val, name);
Py_XDECREF(value_coerce);
@@ -657,7 +662,7 @@ static PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
}
case IDP_IDPARRAY:
{
- PyObject *seq = PyList_New(prop->len), *wrap;
+ PyObject *seq = PyList_New(prop->len);
IDProperty *array = IDP_IDPArray(prop);
int i;
@@ -669,10 +674,13 @@ static PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
}
for (i = 0; i < prop->len; i++) {
- wrap = BPy_IDGroup_MapDataToPy(array++);
+ PyObject *wrap = BPy_IDGroup_MapDataToPy(array++);
- if (!wrap) /* BPy_IDGroup_MapDataToPy sets the error */
+ /* BPy_IDGroup_MapDataToPy sets the error */
+ if (UNLIKELY(wrap == NULL)) {
+ Py_DECREF(seq);
return NULL;
+ }
PyList_SET_ITEM(seq, i, wrap);
}
@@ -680,14 +688,17 @@ static PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
}
case IDP_GROUP:
{
- PyObject *dict = PyDict_New(), *wrap;
+ PyObject *dict = _PyDict_NewPresized(prop->len);
IDProperty *loop;
for (loop = prop->data.group.first; loop; loop = loop->next) {
- wrap = BPy_IDGroup_MapDataToPy(loop);
+ PyObject *wrap = BPy_IDGroup_MapDataToPy(loop);
- if (!wrap) /* BPy_IDGroup_MapDataToPy sets the error */
+ /* BPy_IDGroup_MapDataToPy sets the error */
+ if (UNLIKELY(wrap == NULL)) {
+ Py_DECREF(dict);
return NULL;
+ }
PyDict_SetItemString(dict, loop->name, wrap);
Py_DECREF(wrap);
@@ -702,7 +713,17 @@ static PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
return NULL;
}
-static PyObject *BPy_IDGroup_Pop(BPy_IDProperty *self, PyObject *value)
+PyDoc_STRVAR(BPy_IDGroup_pop_doc,
+".. method:: pop(key)\n"
+"\n"
+" Remove an item from the group, returning a Python representation.\n"
+"\n"
+" :raises KeyError: When the item doesn't exist.\n"
+"\n"
+" :arg key: Name of item to remove.\n"
+" :type key: string\n"
+);
+static PyObject *BPy_IDGroup_pop(BPy_IDProperty *self, PyObject *value)
{
IDProperty *idprop;
PyObject *pyform;
@@ -735,7 +756,12 @@ static PyObject *BPy_IDGroup_Pop(BPy_IDProperty *self, PyObject *value)
return NULL;
}
-static PyObject *BPy_IDGroup_IterItems(BPy_IDProperty *self)
+PyDoc_STRVAR(BPy_IDGroup_iter_items_doc,
+".. method:: iteritems()\n"
+"\n"
+" Iterate through the items in the dict; behaves like dictionary method iteritems.\n"
+);
+static PyObject *BPy_IDGroup_iter_items(BPy_IDProperty *self)
{
BPy_IDGroup_Iter *iter = PyObject_New(BPy_IDGroup_Iter, &BPy_IDGroup_Iter_Type);
iter->group = self;
@@ -829,18 +855,32 @@ PyObject *BPy_Wrap_GetItems(ID *id, IDProperty *prop)
return seq;
}
-
-static PyObject *BPy_IDGroup_GetKeys(BPy_IDProperty *self)
+PyDoc_STRVAR(BPy_IDGroup_keys_doc,
+".. method:: keys()\n"
+"\n"
+" Return the keys associated with this group as a list of strings.\n"
+);
+static PyObject *BPy_IDGroup_keys(BPy_IDProperty *self)
{
return BPy_Wrap_GetKeys(self->prop);
}
-static PyObject *BPy_IDGroup_GetValues(BPy_IDProperty *self)
+PyDoc_STRVAR(BPy_IDGroup_values_doc,
+".. method:: values()\n"
+"\n"
+" Return the values associated with this group.\n"
+);
+static PyObject *BPy_IDGroup_values(BPy_IDProperty *self)
{
return BPy_Wrap_GetValues(self->id, self->prop);
}
-static PyObject *BPy_IDGroup_GetItems(BPy_IDProperty *self)
+PyDoc_STRVAR(BPy_IDGroup_items_doc,
+".. method:: items()\n"
+"\n"
+" Return the items associated with this group.\n"
+);
+static PyObject *BPy_IDGroup_items(BPy_IDProperty *self)
{
return BPy_Wrap_GetItems(self->id, self->prop);
}
@@ -859,7 +899,15 @@ static int BPy_IDGroup_Contains(BPy_IDProperty *self, PyObject *value)
return IDP_GetPropertyFromGroup(self->prop, name) ? 1 : 0;
}
-static PyObject *BPy_IDGroup_Update(BPy_IDProperty *self, PyObject *value)
+PyDoc_STRVAR(BPy_IDGroup_update_doc,
+".. method:: update(other)\n"
+"\n"
+" Update key, values.\n"
+"\n"
+" :arg other: Updates the values in the group with this.\n"
+" :type other: :class:`IDPropertyGroup` or dict\n"
+);
+static PyObject *BPy_IDGroup_update(BPy_IDProperty *self, PyObject *value)
{
PyObject *pkey, *pval;
Py_ssize_t i = 0;
@@ -890,19 +938,33 @@ static PyObject *BPy_IDGroup_Update(BPy_IDProperty *self, PyObject *value)
Py_RETURN_NONE;
}
+PyDoc_STRVAR(BPy_IDGroup_to_dict_doc,
+".. method:: to_dict()\n"
+"\n"
+" Return a purely python version of the group.\n"
+);
static PyObject *BPy_IDGroup_to_dict(BPy_IDProperty *self)
{
return BPy_IDGroup_MapDataToPy(self->prop);
}
+PyDoc_STRVAR(BPy_IDGroup_clear_doc,
+".. method:: clear()\n"
+"\n"
+" Clear all members from this group.\n"
+);
static PyObject *BPy_IDGroup_clear(BPy_IDProperty *self)
{
IDP_ClearProperty(self->prop);
Py_RETURN_NONE;
}
-/* Matches python dict.get(key, [default]) */
-static PyObject *BPy_IDGroup_Get(BPy_IDProperty *self, PyObject *args)
+PyDoc_STRVAR(BPy_IDGroup_get_doc,
+".. method:: get(key, default=None)\n"
+"\n"
+" Return the value for key, if it exists, else default.\n"
+);
+static PyObject *BPy_IDGroup_get(BPy_IDProperty *self, PyObject *args)
{
IDProperty *idprop;
const char *key;
@@ -923,24 +985,15 @@ static PyObject *BPy_IDGroup_Get(BPy_IDProperty *self, PyObject *args)
}
static struct PyMethodDef BPy_IDGroup_methods[] = {
- {"pop", (PyCFunction)BPy_IDGroup_Pop, METH_O,
- "pop an item from the group; raises KeyError if the item doesn't exist"},
- {"iteritems", (PyCFunction)BPy_IDGroup_IterItems, METH_NOARGS,
- "iterate through the items in the dict; behaves like dictionary method iteritems"},
- {"keys", (PyCFunction)BPy_IDGroup_GetKeys, METH_NOARGS,
- "get the keys associated with this group as a list of strings"},
- {"values", (PyCFunction)BPy_IDGroup_GetValues, METH_NOARGS,
- "get the values associated with this group"},
- {"items", (PyCFunction)BPy_IDGroup_GetItems, METH_NOARGS,
- "get the items associated with this group"},
- {"update", (PyCFunction)BPy_IDGroup_Update, METH_O,
- "updates the values in the group with the values of another or a dict"},
- {"get", (PyCFunction)BPy_IDGroup_Get, METH_VARARGS,
- "idprop.get(k[,d]) -> idprop[k] if k in idprop, else d. d defaults to None"},
- {"to_dict", (PyCFunction)BPy_IDGroup_to_dict, METH_NOARGS,
- "return a purely python version of the group"},
- {"clear", (PyCFunction)BPy_IDGroup_clear, METH_NOARGS,
- "clear all members from this group"},
+ {"pop", (PyCFunction)BPy_IDGroup_pop, METH_O, BPy_IDGroup_pop_doc},
+ {"iteritems", (PyCFunction)BPy_IDGroup_iter_items, METH_NOARGS, BPy_IDGroup_iter_items_doc},
+ {"keys", (PyCFunction)BPy_IDGroup_keys, METH_NOARGS, BPy_IDGroup_keys_doc},
+ {"values", (PyCFunction)BPy_IDGroup_values, METH_NOARGS, BPy_IDGroup_values_doc},
+ {"items", (PyCFunction)BPy_IDGroup_items, METH_NOARGS, BPy_IDGroup_items_doc},
+ {"update", (PyCFunction)BPy_IDGroup_update, METH_O, BPy_IDGroup_update_doc},
+ {"get", (PyCFunction)BPy_IDGroup_get, METH_VARARGS, BPy_IDGroup_get_doc},
+ {"to_dict", (PyCFunction)BPy_IDGroup_to_dict, METH_NOARGS, BPy_IDGroup_to_dict_doc},
+ {"clear", (PyCFunction)BPy_IDGroup_clear, METH_NOARGS, BPy_IDGroup_clear_doc},
{NULL, NULL, 0, NULL}
};
@@ -1049,7 +1102,10 @@ static PyObject *BPy_IDArray_repr(BPy_IDArray *self)
return PyUnicode_FromFormat("<bpy id property array [%d]>", self->prop->len);
}
-static PyObject *BPy_IDArray_GetType(BPy_IDArray *self)
+PyDoc_STRVAR(BPy_IDArray_get_typecode_doc,
+"The type of the data in the array {'f': float, 'd': double, 'i': int}."
+);
+static PyObject *BPy_IDArray_get_typecode(BPy_IDArray *self)
{
switch (self->prop->subtype) {
case IDP_FLOAT: return PyUnicode_FromString("f");
@@ -1066,18 +1122,22 @@ static PyObject *BPy_IDArray_GetType(BPy_IDArray *self)
static PyGetSetDef BPy_IDArray_getseters[] = {
/* matches pythons array.typecode */
- {(char *)"typecode", (getter)BPy_IDArray_GetType, (setter)NULL, (char *)"The type of the data in the array, is an int.", NULL},
+ {(char *)"typecode", (getter)BPy_IDArray_get_typecode, (setter)NULL, BPy_IDArray_get_typecode_doc, NULL},
{NULL, NULL, NULL, NULL, NULL},
};
+PyDoc_STRVAR(BPy_IDArray_to_list_doc,
+".. method:: to_list()\n"
+"\n"
+" Return the array as a list.\n"
+);
static PyObject *BPy_IDArray_to_list(BPy_IDArray *self)
{
return BPy_IDGroup_MapDataToPy(self->prop);
}
static PyMethodDef BPy_IDArray_methods[] = {
- {"to_list", (PyCFunction)BPy_IDArray_to_list, METH_NOARGS,
- "return the array as a list"},
+ {"to_list", (PyCFunction)BPy_IDArray_to_list, METH_NOARGS, BPy_IDArray_to_list_doc},
{NULL, NULL, 0, NULL}
};
@@ -1560,7 +1620,7 @@ PyObject *BPyInit_idprop(void)
/* idprop.types */
PyModule_AddObject(mod, "types", (submodule = BPyInit_idprop_types()));
- PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
+ PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
Py_INCREF(submodule);
return mod;
diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c
index dd32c913f78..7b2d58a1268 100644
--- a/source/blender/python/generic/py_capi_utils.c
+++ b/source/blender/python/generic/py_capi_utils.c
@@ -45,7 +45,7 @@
#ifdef _WIN32
#include "BLI_path_util.h" /* BLI_setenv() */
-#include "BLI_math_base.h" /* finite() */
+#include "BLI_math_base.h" /* isfinite() */
#endif
/* array utility function */
@@ -177,7 +177,7 @@ PyObject *PyC_FromArray(const void *array, int length, const PyTypeObject *type,
/**
* Caller needs to ensure tuple is uninitialized.
- * Handy for filling a typle with None for eg.
+ * Handy for filling a tuple with None for eg.
*/
void PyC_Tuple_Fill(PyObject *tuple, PyObject *value)
{
@@ -367,11 +367,12 @@ PyObject *PyC_FrozenSetFromStrings(const char **strings)
}
-/* similar to PyErr_Format(),
+/**
+ * Similar to #PyErr_Format(),
*
- * implementation - we cant actually preprend the existing exception,
+ * Implementation - we cant actually prepend the existing exception,
* because it could have _any_ arguments given to it, so instead we get its
- * __str__ output and raise our own exception including it.
+ * ``__str__`` output and raise our own exception including it.
*/
PyObject *PyC_Err_Format_Prefix(PyObject *exception_type_prefix, const char *format, ...)
{
@@ -539,6 +540,35 @@ PyObject *PyC_ExceptionBuffer_Simple(void)
}
/* string conversion, escape non-unicode chars, coerce must be set to NULL */
+const char *PyC_UnicodeAsByteAndSize(PyObject *py_str, Py_ssize_t *size, PyObject **coerce)
+{
+ const char *result;
+
+ result = _PyUnicode_AsStringAndSize(py_str, size);
+
+ if (result) {
+ /* 99% of the time this is enough but we better support non unicode
+ * chars since blender doesnt limit this */
+ return result;
+ }
+ else {
+ PyErr_Clear();
+
+ if (PyBytes_Check(py_str)) {
+ *size = PyBytes_GET_SIZE(py_str);
+ return PyBytes_AS_STRING(py_str);
+ }
+ else if ((*coerce = PyUnicode_EncodeFSDefault(py_str))) {
+ *size = PyBytes_GET_SIZE(*coerce);
+ return PyBytes_AS_STRING(*coerce);
+ }
+ else {
+ /* leave error raised from EncodeFS */
+ return NULL;
+ }
+ }
+}
+
const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce)
{
const char *result;
@@ -748,6 +778,7 @@ void PyC_RunQuicky(const char *filepath, int n, ...)
/* set the value so we can access it */
PyDict_SetItemString(py_dict, "values", values);
+ Py_DECREF(values);
py_result = PyRun_File(fp, filepath, Py_file_input, py_dict, py_dict);
@@ -1026,7 +1057,7 @@ bool PyC_RunString_AsNumber(const char *expr, double *value, const char *filenam
if (val == -1 && PyErr_Occurred()) {
ok = false;
}
- else if (!finite(val)) {
+ else if (!isfinite(val)) {
*value = 0.0;
}
else {
diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h
index a06a717ecbc..04cfc8801eb 100644
--- a/source/blender/python/generic/py_capi_utils.h
+++ b/source/blender/python/generic/py_capi_utils.h
@@ -53,6 +53,7 @@ void PyC_List_Fill(PyObject *list, PyObject *value);
PyObject * PyC_UnicodeFromByte(const char *str);
PyObject * PyC_UnicodeFromByteAndSize(const char *str, Py_ssize_t size);
const char * PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce); /* coerce must be NULL */
+const char * PyC_UnicodeAsByteAndSize(PyObject *py_str, Py_ssize_t *size, PyObject **coerce);
/* name namespace function for bpy & bge */
PyObject * PyC_DefaultNameSpace(const char *filename);
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index 2715d2c5992..038c1e7eb10 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -49,6 +49,7 @@ set(SRC
gpu_offscreen.c
bpy.c
bpy_app.c
+ bpy_app_alembic.c
bpy_app_build_options.c
bpy_app_ffmpeg.c
bpy_app_handlers.c
@@ -82,6 +83,7 @@ set(SRC
gpu.h
bpy.h
bpy_app.h
+ bpy_app_alembic.h
bpy_app_build_options.h
bpy_app_ffmpeg.h
bpy_app_handlers.h
@@ -264,6 +266,10 @@ if(WITH_OPENCOLLADA)
add_definitions(-DWITH_COLLADA)
endif()
+if(WITH_ALEMBIC)
+ add_definitions(-DWITH_ALEMBIC)
+endif()
+
if(WITH_OPENCOLORIO)
add_definitions(-DWITH_OCIO)
endif()
@@ -275,6 +281,13 @@ if(WITH_OPENVDB)
)
endif()
+if(WITH_ALEMBIC)
+ add_definitions(-DWITH_ALEMBIC)
+ list(APPEND INC
+ ../../alembic
+ )
+endif()
+
if(WITH_OPENIMAGEIO)
add_definitions(-DWITH_OPENIMAGEIO)
list(APPEND INC
diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c
index 17617a231b2..ed7cec2f2d5 100644
--- a/source/blender/python/intern/bpy_app.c
+++ b/source/blender/python/intern/bpy_app.c
@@ -33,6 +33,7 @@
#include "bpy_app.h"
+#include "bpy_app_alembic.h"
#include "bpy_app_ffmpeg.h"
#include "bpy_app_ocio.h"
#include "bpy_app_oiio.h"
@@ -104,6 +105,7 @@ static PyStructSequence_Field app_info_fields[] = {
{(char *)"build_system", (char *)"Build system used"},
/* submodules */
+ {(char *)"alembic", (char *)"Alembic library information backend"},
{(char *)"ffmpeg", (char *)"FFmpeg library information backend"},
{(char *)"ocio", (char *)"OpenColorIO library information backend"},
{(char *)"oiio", (char *)"OpenImageIO library information backend"},
@@ -182,6 +184,7 @@ static PyObject *make_app_info(void)
SetBytesItem("Unknown");
#endif
+ SetObjItem(BPY_app_alembic_struct());
SetObjItem(BPY_app_ffmpeg_struct());
SetObjItem(BPY_app_ocio_struct());
SetObjItem(BPY_app_oiio_struct());
@@ -231,12 +234,12 @@ static int bpy_app_debug_set(PyObject *UNUSED(self), PyObject *value, void *clos
return 0;
}
-
+#define BROKEN_BINARY_PATH_PYTHON_HACK
PyDoc_STRVAR(bpy_app_binary_path_python_doc,
"String, the path to the python executable (read-only)"
);
-static PyObject *bpy_app_binary_path_python_get(PyObject *UNUSED(self), void *UNUSED(closure))
+static PyObject *bpy_app_binary_path_python_get(PyObject *self, void *UNUSED(closure))
{
/* refcount is held in BlenderAppType.tp_dict */
static PyObject *ret = NULL;
@@ -248,14 +251,18 @@ static PyObject *bpy_app_binary_path_python_get(PyObject *UNUSED(self), void *UN
fullpath, sizeof(fullpath),
PY_MAJOR_VERSION, PY_MINOR_VERSION);
ret = PyC_UnicodeFromByte(fullpath);
- PyDict_SetItemString(BlenderAppType.tp_dict, "binary_path_python", ret);
+#ifdef BROKEN_BINARY_PATH_PYTHON_HACK
+ Py_INCREF(ret);
+ UNUSED_VARS(self);
+#else
+ PyDict_SetItem(BlenderAppType.tp_dict, /* XXX BAAAADDDDDD! self is not a PyDescr at all! it's bpy.app!!! */ PyDescr_NAME(self), ret);
+#endif
}
else {
Py_INCREF(ret);
}
return ret;
-
}
PyDoc_STRVAR(bpy_app_debug_value_doc,
@@ -356,10 +363,10 @@ static PyGetSetDef bpy_app_getsets[] = {
static void py_struct_seq_getset_init(void)
{
/* tricky dynamic members, not to py-spec! */
- PyGetSetDef *getset;
-
- for (getset = bpy_app_getsets; getset->name; getset++) {
- PyDict_SetItemString(BlenderAppType.tp_dict, getset->name, PyDescr_NewGetSet(&BlenderAppType, getset));
+ for (PyGetSetDef *getset = bpy_app_getsets; getset->name; getset++) {
+ PyObject *item = PyDescr_NewGetSet(&BlenderAppType, getset);
+ PyDict_SetItem(BlenderAppType.tp_dict, PyDescr_NAME(item), item);
+ Py_DECREF(item);
}
}
/* end dynamic bpy.app */
diff --git a/source/blender/python/intern/bpy_app_alembic.c b/source/blender/python/intern/bpy_app_alembic.c
new file mode 100644
index 00000000000..90e6a02b418
--- /dev/null
+++ b/source/blender/python/intern/bpy_app_alembic.c
@@ -0,0 +1,113 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_app_alembic.c
+ * \ingroup pythonintern
+ */
+
+#include <Python.h>
+#include "BLI_utildefines.h"
+
+#include "bpy_app_alembic.h"
+
+#ifdef WITH_ALEMBIC
+# include "ABC_alembic.h"
+#endif
+
+static PyTypeObject BlenderAppABCType;
+
+static PyStructSequence_Field app_alembic_info_fields[] = {
+ {(char *)"supported", (char *)"Boolean, True when Blender is built with Alembic support"},
+ {(char *)"version", (char *)"The Alembic version as a tuple of 3 numbers"},
+ {(char *)"version_string", (char *)"The Alembic version formatted as a string"},
+ {NULL}
+};
+
+static PyStructSequence_Desc app_alembic_info_desc = {
+ (char *)"bpy.app.alembic", /* name */
+ (char *)"This module contains information about Alembic blender is linked against", /* doc */
+ app_alembic_info_fields, /* fields */
+ ARRAY_SIZE(app_alembic_info_fields) - 1
+};
+
+static PyObject *make_alembic_info(void)
+{
+ PyObject *alembic_info = PyStructSequence_New(&BlenderAppABCType);
+
+ if (alembic_info == NULL) {
+ return NULL;
+ }
+
+ int pos = 0;
+
+#ifndef WITH_ALEMBIC
+# define SetStrItem(str) \
+ PyStructSequence_SET_ITEM(alembic_info, pos++, PyUnicode_FromString(str))
+#endif
+
+#define SetObjItem(obj) \
+ PyStructSequence_SET_ITEM(alembic_info, pos++, obj)
+
+#ifdef WITH_ALEMBIC
+ const int curversion = ABC_get_version();
+ const int major = curversion / 10000;
+ const int minor = (curversion / 100) - (major * 100);
+ const int patch = curversion - ((curversion / 100 ) * 100);
+
+ SetObjItem(PyBool_FromLong(1));
+ SetObjItem(Py_BuildValue("(iii)", major, minor, patch));
+ SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d", major, minor, patch));
+#else
+ SetObjItem(PyBool_FromLong(0));
+ SetObjItem(Py_BuildValue("(iii)", 0, 0, 0));
+ SetStrItem("Unknown");
+#endif
+
+ if (PyErr_Occurred()) {
+ Py_CLEAR(alembic_info);
+ return NULL;
+ }
+
+#undef SetStrItem
+#undef SetObjItem
+
+ return alembic_info;
+}
+
+PyObject *BPY_app_alembic_struct(void)
+{
+ PyStructSequence_InitType(&BlenderAppABCType, &app_alembic_info_desc);
+
+ PyObject *ret = make_alembic_info();
+
+ /* prevent user from creating new instances */
+ BlenderAppABCType.tp_init = NULL;
+ BlenderAppABCType.tp_new = NULL;
+ BlenderAppABCType.tp_hash = (hashfunc)_Py_HashPointer; /* without this we can't do set(sys.modules) [#29635] */
+
+ return ret;
+}
diff --git a/source/blender/python/intern/bpy_app_alembic.h b/source/blender/python/intern/bpy_app_alembic.h
new file mode 100644
index 00000000000..8cc647a77df
--- /dev/null
+++ b/source/blender/python/intern/bpy_app_alembic.h
@@ -0,0 +1,38 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_app_alembic.h
+ * \ingroup pythonintern
+ */
+
+#ifndef __BPY_APP_ALEMBIC_H__
+#define __BPY_APP_ALEMBIC_H__
+
+PyObject *BPY_app_alembic_struct(void);
+
+#endif /* __BPY_APP_ALEMBIC_H__ */
+
diff --git a/source/blender/python/intern/bpy_app_build_options.c b/source/blender/python/intern/bpy_app_build_options.c
index 4c186aab100..a6b98567a9a 100644
--- a/source/blender/python/intern/bpy_app_build_options.c
+++ b/source/blender/python/intern/bpy_app_build_options.c
@@ -69,6 +69,7 @@ static PyStructSequence_Field app_builtopts_info_fields[] = {
{(char *)"player", NULL},
{(char *)"openmp", NULL},
{(char *)"openvdb", NULL},
+ {(char *)"alembic", NULL},
{NULL}
};
@@ -303,6 +304,12 @@ static PyObject *make_builtopts_info(void)
SetObjIncref(Py_False);
#endif
+#ifdef WITH_ALEMBIC
+ SetObjIncref(Py_True);
+#else
+ SetObjIncref(Py_False);
+#endif
+
#undef SetObjIncref
return builtopts_info;
diff --git a/source/blender/python/intern/bpy_app_handlers.c b/source/blender/python/intern/bpy_app_handlers.c
index 6a8b0b065c2..1cc2d6f1307 100644
--- a/source/blender/python/intern/bpy_app_handlers.c
+++ b/source/blender/python/intern/bpy_app_handlers.c
@@ -317,7 +317,13 @@ void bpy_app_generic_callback(struct Main *UNUSED(main), struct ID *id, void *ar
func = PyList_GET_ITEM(cb_list, pos);
ret = PyObject_Call(func, args, NULL);
if (ret == NULL) {
- PyErr_Print();
+ /* Don't set last system variables because they might cause some
+ * dangling pointers to external render engines (when exception
+ * happens during rendering) which will break logic of render pipeline
+ * which expects to be the only user of render engine when rendering
+ * is finished.
+ */
+ PyErr_PrintEx(0);
PyErr_Clear();
}
else {
diff --git a/source/blender/python/intern/bpy_app_translations.c b/source/blender/python/intern/bpy_app_translations.c
index b90deafb377..6ba858f0228 100644
--- a/source/blender/python/intern/bpy_app_translations.c
+++ b/source/blender/python/intern/bpy_app_translations.c
@@ -675,7 +675,7 @@ static PyObject *app_translations_new(PyTypeObject *type, PyObject *UNUSED(args)
_translations->contexts = app_translations_contexts_make();
- py_ctxts = PyDict_New();
+ py_ctxts = _PyDict_NewPresized(ARRAY_SIZE(_contexts));
for (ctxt = _contexts; ctxt->c_id; ctxt++) {
PyObject *val = PyUnicode_FromString(ctxt->py_id);
PyDict_SetItemString(py_ctxts, ctxt->c_id, val);
diff --git a/source/blender/python/intern/bpy_driver.c b/source/blender/python/intern/bpy_driver.c
index 9cd6fe3da91..c8ce7b2f770 100644
--- a/source/blender/python/intern/bpy_driver.c
+++ b/source/blender/python/intern/bpy_driver.c
@@ -44,6 +44,8 @@
#include "bpy_rna_driver.h" /* for pyrna_driver_get_variable_value */
+#include "bpy_intern_string.h"
+
#include "bpy_driver.h"
extern void BPY_update_rna_module(void);
@@ -97,24 +99,48 @@ int bpy_pydriver_create_dict(void)
}
/* note, this function should do nothing most runs, only when changing frame */
-static PyObject *bpy_pydriver_InternStr__frame = NULL;
/* not thread safe but neither is python */
-static float bpy_pydriver_evaltime_prev = FLT_MAX;
-
-static void bpy_pydriver_update_dict(const float evaltime)
+static struct {
+ float evaltime;
+
+ /* borrowed reference to the 'self' in 'bpy_pydriver_Dict'
+ * keep for as long as the same self is used. */
+ PyObject *self;
+} g_pydriver_state_prev = {
+ .evaltime = FLT_MAX,
+ .self = NULL,
+};
+
+static void bpy_pydriver_namespace_update_frame(const float evaltime)
{
- if (bpy_pydriver_evaltime_prev != evaltime) {
+ if (g_pydriver_state_prev.evaltime != evaltime) {
+ PyObject *item = PyFloat_FromDouble(evaltime);
+ PyDict_SetItem(bpy_pydriver_Dict, bpy_intern_str_frame, item);
+ Py_DECREF(item);
- /* currently only update the frame */
- if (bpy_pydriver_InternStr__frame == NULL) {
- bpy_pydriver_InternStr__frame = PyUnicode_FromString("frame");
- }
+ g_pydriver_state_prev.evaltime = evaltime;
+ }
+}
+
+static void bpy_pydriver_namespace_update_self(struct PathResolvedRNA *anim_rna)
+{
+ if ((g_pydriver_state_prev.self == NULL) ||
+ (pyrna_driver_is_equal_anim_rna(anim_rna, g_pydriver_state_prev.self) == false))
+ {
+ PyObject *item = pyrna_driver_self_from_anim_rna(anim_rna);
+ PyDict_SetItem(bpy_pydriver_Dict, bpy_intern_str_self, item);
+ Py_DECREF(item);
+
+ g_pydriver_state_prev.self = item;
+ }
+}
- PyDict_SetItem(bpy_pydriver_Dict,
- bpy_pydriver_InternStr__frame,
- PyFloat_FromDouble(evaltime));
+static void bpy_pydriver_namespace_clear_self(void)
+{
+ if (g_pydriver_state_prev.self) {
+ PyDict_DelItem(bpy_pydriver_Dict, bpy_intern_str_self);
- bpy_pydriver_evaltime_prev = evaltime;
+ g_pydriver_state_prev.self = NULL;
}
}
@@ -137,11 +163,10 @@ void BPY_driver_reset(void)
bpy_pydriver_Dict = NULL;
}
- if (bpy_pydriver_InternStr__frame) {
- Py_DECREF(bpy_pydriver_InternStr__frame);
- bpy_pydriver_InternStr__frame = NULL;
- bpy_pydriver_evaltime_prev = FLT_MAX;
- }
+ g_pydriver_state_prev.evaltime = FLT_MAX;
+
+ /* freed when clearing driver dict */
+ g_pydriver_state_prev.self = NULL;
if (use_gil)
PyGILState_Release(gilstate);
@@ -172,7 +197,7 @@ static void pydriver_error(ChannelDriver *driver)
* now release the GIL on python operator execution instead, using
* PyEval_SaveThread() / PyEval_RestoreThread() so we don't lock up blender.
*/
-float BPY_driver_exec(ChannelDriver *driver, const float evaltime)
+float BPY_driver_exec(struct PathResolvedRNA *anim_rna, ChannelDriver *driver, const float evaltime)
{
PyObject *driver_vars = NULL;
PyObject *retval = NULL;
@@ -222,8 +247,14 @@ float BPY_driver_exec(ChannelDriver *driver, const float evaltime)
}
/* update global namespace */
- bpy_pydriver_update_dict(evaltime);
+ bpy_pydriver_namespace_update_frame(evaltime);
+ if (driver->flag & DRIVER_FLAG_USE_SELF) {
+ bpy_pydriver_namespace_update_self(anim_rna);
+ }
+ else {
+ bpy_pydriver_namespace_clear_self();
+ }
if (driver->expr_comp == NULL)
driver->flag |= DRIVER_FLAG_RECOMPILE;
@@ -262,7 +293,7 @@ float BPY_driver_exec(ChannelDriver *driver, const float evaltime)
}
/* add target values to a dict that will be used as '__locals__' dict */
- driver_vars = PyDict_New();
+ driver_vars = _PyDict_NewPresized(PyTuple_GET_SIZE(expr_vars));
for (dvar = driver->variables.first, i = 0; dvar; dvar = dvar->next) {
PyObject *driver_arg = NULL;
@@ -301,7 +332,10 @@ float BPY_driver_exec(ChannelDriver *driver, const float evaltime)
/* try to add to dictionary */
/* if (PyDict_SetItemString(driver_vars, dvar->name, driver_arg)) { */
- if (PyDict_SetItem(driver_vars, PyTuple_GET_ITEM(expr_vars, i++), driver_arg) < 0) {
+ if (PyDict_SetItem(driver_vars, PyTuple_GET_ITEM(expr_vars, i++), driver_arg) != -1) {
+ Py_DECREF(driver_arg);
+ }
+ else {
/* this target failed - bad name */
if (targets_ok) {
/* first one - print some extra info for easier identification */
@@ -347,7 +381,7 @@ float BPY_driver_exec(ChannelDriver *driver, const float evaltime)
if (use_gil)
PyGILState_Release(gilstate);
- if (finite(result)) {
+ if (isfinite(result)) {
return (float)result;
}
else {
diff --git a/source/blender/python/intern/bpy_driver.h b/source/blender/python/intern/bpy_driver.h
index 1fccec7e1b2..017a6fe89c5 100644
--- a/source/blender/python/intern/bpy_driver.h
+++ b/source/blender/python/intern/bpy_driver.h
@@ -28,12 +28,13 @@
#define __BPY_DRIVER_H__
struct ChannelDriver;
+struct PathResolvedRNA;
int bpy_pydriver_create_dict(void);
extern PyObject *bpy_pydriver_Dict;
/* externals */
-float BPY_driver_exec(struct ChannelDriver *driver, const float evaltime);
+float BPY_driver_exec(struct PathResolvedRNA *anim_rna, struct ChannelDriver *driver, const float evaltime);
void BPY_driver_reset(void);
#endif /* __BPY_DRIVER_H__ */
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index b559623f619..311f621e13b 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -31,10 +31,6 @@
#include <Python.h>
-#ifdef WIN32
-# include "BLI_math_base.h" /* finite */
-#endif
-
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
@@ -905,8 +901,8 @@ static void bpy_module_free(void *UNUSED(mod))
bool BPY_string_is_keyword(const char *str)
{
/* list is from...
- * ", ".join(['"%s"' % kw for kw in __import__("keyword").kwlist])
- */
+ * ", ".join(['"%s"' % kw for kw in __import__("keyword").kwlist])
+ */
const char *kwlist[] = {
"False", "None", "True",
"and", "as", "assert", "break",
diff --git a/source/blender/python/intern/bpy_intern_string.c b/source/blender/python/intern/bpy_intern_string.c
index fd32c91a480..ac0100fa75d 100644
--- a/source/blender/python/intern/bpy_intern_string.c
+++ b/source/blender/python/intern/bpy_intern_string.c
@@ -34,7 +34,7 @@
#include "BLI_utildefines.h"
-static PyObject *bpy_intern_str_arr[11];
+static PyObject *bpy_intern_str_arr[13];
PyObject *bpy_intern_str_register;
PyObject *bpy_intern_str_unregister;
@@ -43,6 +43,8 @@ PyObject *bpy_intern_str_bl_property;
PyObject *bpy_intern_str_bpy_types;
PyObject *bpy_intern_str_order;
PyObject *bpy_intern_str_attr;
+PyObject *bpy_intern_str_self;
+PyObject *bpy_intern_str_frame;
PyObject *bpy_intern_str___slots__;
PyObject *bpy_intern_str___name__;
PyObject *bpy_intern_str___doc__;
@@ -62,6 +64,8 @@ void bpy_intern_string_init(void)
BPY_INTERN_STR(bpy_intern_str_bpy_types, "bpy.types");
BPY_INTERN_STR(bpy_intern_str_order, "order");
BPY_INTERN_STR(bpy_intern_str_attr, "attr");
+ BPY_INTERN_STR(bpy_intern_str_self, "self");
+ BPY_INTERN_STR(bpy_intern_str_frame, "frame");
BPY_INTERN_STR(bpy_intern_str___slots__, "__slots__");
BPY_INTERN_STR(bpy_intern_str___name__, "__name__");
BPY_INTERN_STR(bpy_intern_str___doc__, "__doc__");
diff --git a/source/blender/python/intern/bpy_intern_string.h b/source/blender/python/intern/bpy_intern_string.h
index f4f4560dbfd..394e84d89bd 100644
--- a/source/blender/python/intern/bpy_intern_string.h
+++ b/source/blender/python/intern/bpy_intern_string.h
@@ -37,6 +37,8 @@ extern PyObject *bpy_intern_str_bl_property;
extern PyObject *bpy_intern_str_bpy_types;
extern PyObject *bpy_intern_str_order;
extern PyObject *bpy_intern_str_attr;
+extern PyObject *bpy_intern_str_self;
+extern PyObject *bpy_intern_str_frame;
extern PyObject *bpy_intern_str___slots__;
extern PyObject *bpy_intern_str___name__;
extern PyObject *bpy_intern_str___doc__;
diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c
index a120e4886e0..ec69abbb1df 100644
--- a/source/blender/python/intern/bpy_library_load.c
+++ b/source/blender/python/intern/bpy_library_load.c
@@ -39,7 +39,6 @@
#include "BLO_readfile.h"
-#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_library.h"
#include "BKE_idcode.h"
@@ -186,6 +185,7 @@ PyDoc_STRVAR(bpy_lib_load_doc,
static PyObject *bpy_lib_load(PyObject *UNUSED(self), PyObject *args, PyObject *kwds)
{
static const char *kwlist[] = {"filepath", "link", "relative", NULL};
+ Main *bmain = CTX_data_main(BPy_GetContext());
BPy_Library *ret;
const char *filename = NULL;
bool is_rel = false, is_link = false;
@@ -204,13 +204,13 @@ static PyObject *bpy_lib_load(PyObject *UNUSED(self), PyObject *args, PyObject *
BLI_strncpy(ret->relpath, filename, sizeof(ret->relpath));
BLI_strncpy(ret->abspath, filename, sizeof(ret->abspath));
- BLI_path_abs(ret->abspath, G.main->name);
+ BLI_path_abs(ret->abspath, bmain->name);
ret->blo_handle = NULL;
ret->flag = ((is_link ? FILE_LINK : 0) |
(is_rel ? FILE_RELPATH : 0));
- ret->dict = PyDict_New();
+ ret->dict = _PyDict_NewPresized(MAX_LIBARRAY);
return (PyObject *)ret;
}
@@ -222,19 +222,16 @@ static PyObject *_bpy_names(BPy_Library *self, int blocktype)
int totnames;
names = BLO_blendhandle_get_datablock_names(self->blo_handle, blocktype, &totnames);
+ list = PyList_New(totnames);
if (names) {
int counter = 0;
- list = PyList_New(totnames);
for (l = names; l; l = l->next) {
PyList_SET_ITEM(list, counter, PyUnicode_FromString((char *)l->link));
counter++;
}
BLI_linklist_free(names, free); /* free linklist *and* each node's data */
}
- else {
- list = PyList_New(0);
- }
return list;
}
@@ -243,7 +240,7 @@ static PyObject *bpy_lib_enter(BPy_Library *self, PyObject *UNUSED(args))
{
PyObject *ret;
BPy_Library *self_from;
- PyObject *from_dict = PyDict_New();
+ PyObject *from_dict = _PyDict_NewPresized(MAX_LIBARRAY);
ReportList reports;
BKE_reports_init(&reports, RPT_STORE);
@@ -264,8 +261,13 @@ static PyObject *bpy_lib_enter(BPy_Library *self, PyObject *UNUSED(args))
if (BKE_idcode_is_linkable(code)) {
const char *name_plural = BKE_idcode_to_name_plural(code);
PyObject *str = PyUnicode_FromString(name_plural);
- PyDict_SetItem(self->dict, str, PyList_New(0));
- PyDict_SetItem(from_dict, str, _bpy_names(self, code));
+ PyObject *item;
+
+ PyDict_SetItem(self->dict, str, item = PyList_New(0));
+ Py_DECREF(item);
+ PyDict_SetItem(from_dict, str, item = _bpy_names(self, code));
+ Py_DECREF(item);
+
Py_DECREF(str);
}
}
@@ -346,48 +348,44 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
/* loop */
Py_ssize_t size = PyList_GET_SIZE(ls);
Py_ssize_t i;
- PyObject *item;
- const char *item_str;
for (i = 0; i < size; i++) {
- item = PyList_GET_ITEM(ls, i);
- item_str = _PyUnicode_AsString(item);
+ PyObject *item_src = PyList_GET_ITEM(ls, i);
+ PyObject *item_dst; /* must be set below */
+ const char *item_idname = _PyUnicode_AsString(item_src);
- // printf(" %s\n", item_str);
+ // printf(" %s\n", item_idname);
- if (item_str) {
- ID *id = BLO_library_link_named_part(mainl, &(self->blo_handle), idcode, item_str);
+ if (item_idname) {
+ ID *id = BLO_library_link_named_part(mainl, &(self->blo_handle), idcode, item_idname);
if (id) {
#ifdef USE_RNA_DATABLOCKS
/* swap name for pointer to the id */
- Py_DECREF(item);
- item = PyCapsule_New((void *)id, NULL, NULL);
+ item_dst = PyCapsule_New((void *)id, NULL, NULL);
+#else
+ /* leave as is */
+ continue;
#endif
}
else {
- bpy_lib_exit_warn_idname(self, name_plural, item_str);
+ bpy_lib_exit_warn_idname(self, name_plural, item_idname);
/* just warn for now */
/* err = -1; */
-#ifdef USE_RNA_DATABLOCKS
- item = Py_INCREF_RET(Py_None);
-#endif
+ item_dst = Py_INCREF_RET(Py_None);
}
/* ID or None */
}
else {
/* XXX, could complain about this */
- bpy_lib_exit_warn_type(self, item);
+ bpy_lib_exit_warn_type(self, item_src);
PyErr_Clear();
-
-#ifdef USE_RNA_DATABLOCKS
- item = Py_INCREF_RET(Py_None);
-#endif
+ item_dst = Py_INCREF_RET(Py_None);
}
-#ifdef USE_RNA_DATABLOCKS
- PyList_SET_ITEM(ls, i, item);
-#endif
+ /* item_dst must be new or already incref'd */
+ Py_DECREF(item_src);
+ PyList_SET_ITEM(ls, i, item_dst);
}
}
}
@@ -410,7 +408,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
/* copied from wm_operator.c */
{
/* mark all library linked objects to be updated */
- BKE_main_lib_objects_recalc_all(G.main);
+ BKE_main_lib_objects_recalc_all(bmain);
/* append, rather than linking */
if ((self->flag & FILE_LINK) == 0) {
@@ -422,6 +420,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
/* finally swap the capsules for real bpy objects
* important since BLO_library_append_end initializes NodeTree types used by srna->refine */
+#ifdef USE_RNA_DATABLOCKS
{
int idcode_step = 0, idcode;
while ((idcode = BKE_idcode_iter_step(&idcode_step))) {
@@ -451,6 +450,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
}
}
}
+#endif /* USE_RNA_DATABLOCKS */
Py_RETURN_NONE;
}
diff --git a/source/blender/python/intern/bpy_library_write.c b/source/blender/python/intern/bpy_library_write.c
index f582cebb260..bf91253141a 100644
--- a/source/blender/python/intern/bpy_library_write.c
+++ b/source/blender/python/intern/bpy_library_write.c
@@ -50,7 +50,7 @@
PyDoc_STRVAR(bpy_lib_write_doc,
-".. method:: write(filepath, datablocks, relative_remap=False, fake_user=False)\n"
+".. method:: write(filepath, datablocks, relative_remap=False, fake_user=False, compress=False)\n"
"\n"
" Write data-blocks into a blend file.\n"
"\n"
diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c
index d6c57f4c302..bd3e5736c6c 100644
--- a/source/blender/python/intern/bpy_operator.c
+++ b/source/blender/python/intern/bpy_operator.c
@@ -223,9 +223,9 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args)
WM_operator_properties_create_ptr(&ptr, ot);
WM_operator_properties_sanitize(&ptr, 0);
- if (kw && PyDict_Size(kw))
- error_val = pyrna_pydict_to_props(&ptr, kw, 0, "Converting py args to operator properties: ");
-
+ if (kw && PyDict_Size(kw)) {
+ error_val = pyrna_pydict_to_props(&ptr, kw, false, "Converting py args to operator properties: ");
+ }
if (error_val == 0) {
ReportList *reports;
@@ -264,6 +264,11 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args)
if ((reports->flag & RPT_FREE) == 0) {
MEM_freeN(reports);
}
+ else {
+ /* The WM is now responsible for running the modal operator,
+ * show reports in the info window. */
+ reports->flag &= ~RPT_OP_HOLD;
+ }
}
WM_operator_properties_free(&ptr);
@@ -348,8 +353,9 @@ static PyObject *pyop_as_string(PyObject *UNUSED(self), PyObject *args)
/* Save another lookup */
RNA_pointer_create(NULL, ot->srna, NULL, &ptr);
- if (kw && PyDict_Size(kw))
- error_val = pyrna_pydict_to_props(&ptr, kw, 0, "Converting py args to operator properties: ");
+ if (kw && PyDict_Size(kw)) {
+ error_val = pyrna_pydict_to_props(&ptr, kw, false, "Converting py args to operator properties: ");
+ }
if (error_val == 0)
buf = WM_operator_pystring_ex(C, NULL, all_args, macro_args, ot, &ptr);
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index bce1d923462..e61018865ab 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -2627,17 +2627,30 @@ PyDoc_STRVAR(BPy_EnumProperty_doc,
" Returns a new enumerator property definition.\n"
"\n"
" :arg items: sequence of enum items formatted:\n"
-" [(identifier, name, description, icon, number), ...] where the identifier is used\n"
-" for python access and other values are used for the interface.\n"
-" The three first elements of the tuples are mandatory.\n"
-" The fourth one is either the (unique!) number id of the item or, if followed by a fith element\n"
-" (which must be the numid), an icon string identifier or integer icon value (e.g. returned by icon()...).\n"
-" Note the item is optional.\n"
+" ``[(identifier, name, description, icon, number), ...]``.\n"
+"\n"
+" The first three elements of the tuples are mandatory.\n"
+"\n"
+" :identifier: The identifier is used for Python access.\n"
+" :name: Name for the interace.\n"
+" :description: Used for documentation and tooltips.\n"
+" :icon: An icon string identifier or integer icon value\n"
+" (e.g. returned by :class:`bpy.types.UILayout.icon`)\n"
+" :number: Unique value used as the identifier for this item (stored in file data).\n"
+" Use when the identifier may need to change.\n"
+"\n"
+" When an item only contains 4 items they define ``(identifier, name, description, number)``.\n"
+"\n"
" For dynamic values a callback can be passed which returns a list in\n"
" the same format as the static list.\n"
-" This function must take 2 arguments (self, context), **context may be None**.\n"
-" WARNING: There is a known bug with using a callback,\n"
-" Python must keep a reference to the strings returned or Blender will crash.\n"
+" This function must take 2 arguments ``(self, context)``, **context may be None**.\n"
+"\n"
+" .. warning::\n"
+"\n"
+" There is a known bug with using a callback,\n"
+" Python must keep a reference to the strings returned or Blender will misbehave\n"
+" or even crash."
+"\n"
" :type items: sequence of string tuples or a function\n"
BPY_PROPDEF_NAME_DOC
BPY_PROPDEF_DESC_DOC
@@ -2986,7 +2999,7 @@ static struct PyModuleDef props_module = {
"This module defines properties to extend Blender's internal data. The result of these functions"
" is used to assign properties to classes registered with Blender and can't be used directly.\n"
"\n"
- ".. warning:: All parameters to these functions must be passed as keywords.\n",
+ ".. note:: All parameters to these functions must be passed as keywords.\n",
-1, /* multiple "initialization" just copies the module dict. */
props_methods,
NULL, NULL, NULL, NULL
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 33ac58dadb1..ab523e03f4d 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -136,7 +136,9 @@ static void id_release_gc(struct ID *id)
PyGC_Head *g = gen->gc.gc_next;
while ((g = g->gc.gc_next) != gen) {
PyObject *ob = FROM_GC(g);
- if (PyType_IsSubtype(Py_TYPE(ob), &pyrna_struct_Type) || PyType_IsSubtype(Py_TYPE(ob), &pyrna_prop_Type)) {
+ if (PyType_IsSubtype(Py_TYPE(ob), &pyrna_struct_Type) ||
+ PyType_IsSubtype(Py_TYPE(ob), &pyrna_prop_Type))
+ {
BPy_DummyPointerRNA *ob_ptr = (BPy_DummyPointerRNA *)ob;
if (ob_ptr->ptr.id.data == id) {
pyrna_invalidate(ob_ptr);
@@ -358,9 +360,12 @@ static int deferred_register_prop(StructRNA *srna, PyObject *key, PyObject *item
#ifdef USE_MATHUTILS
#include "../mathutils/mathutils.h" /* so we can have mathutils callbacks */
-static PyObject *pyrna_prop_array_subscript_slice(BPy_PropertyArrayRNA *self, PointerRNA *ptr, PropertyRNA *prop,
- Py_ssize_t start, Py_ssize_t stop, Py_ssize_t length);
-static short pyrna_rotation_euler_order_get(PointerRNA *ptr, PropertyRNA **prop_eul_order, const short order_fallback);
+static PyObject *pyrna_prop_array_subscript_slice(
+ BPy_PropertyArrayRNA *self, PointerRNA *ptr, PropertyRNA *prop,
+ Py_ssize_t start, Py_ssize_t stop, Py_ssize_t length);
+static short pyrna_rotation_euler_order_get(
+ PointerRNA *ptr, const short order_fallback,
+ PropertyRNA **r_prop_eul_order);
/* bpyrna vector/euler/quat callbacks */
static unsigned char mathutils_rna_array_cb_index = -1; /* index for our callbacks */
@@ -395,7 +400,7 @@ static int mathutils_rna_vector_get(BaseMathObject *bmo, int subtype)
if (subtype == MATHUTILS_CB_SUBTYPE_EUL) {
EulerObject *eul = (EulerObject *)bmo;
PropertyRNA *prop_eul_order = NULL;
- eul->order = pyrna_rotation_euler_order_get(&self->ptr, &prop_eul_order, eul->order);
+ eul->order = pyrna_rotation_euler_order_get(&self->ptr, eul->order, &prop_eul_order);
}
return 0;
@@ -442,7 +447,7 @@ static int mathutils_rna_vector_set(BaseMathObject *bmo, int subtype)
if (subtype == MATHUTILS_CB_SUBTYPE_EUL) {
EulerObject *eul = (EulerObject *)bmo;
PropertyRNA *prop_eul_order = NULL;
- short order = pyrna_rotation_euler_order_get(&self->ptr, &prop_eul_order, eul->order);
+ short order = pyrna_rotation_euler_order_get(&self->ptr, eul->order, &prop_eul_order);
if (order != eul->order) {
RNA_property_enum_set(&self->ptr, prop_eul_order, eul->order);
if (RNA_property_update_check(prop_eul_order)) {
@@ -562,16 +567,21 @@ static Mathutils_Callback mathutils_rna_matrix_cb = {
NULL
};
-static short pyrna_rotation_euler_order_get(PointerRNA *ptr, PropertyRNA **prop_eul_order, const short order_fallback)
+static short pyrna_rotation_euler_order_get(
+ PointerRNA *ptr, const short order_fallback,
+ PropertyRNA **r_prop_eul_order)
{
/* attempt to get order */
- if (*prop_eul_order == NULL)
- *prop_eul_order = RNA_struct_find_property(ptr, "rotation_mode");
+ if (*r_prop_eul_order == NULL) {
+ *r_prop_eul_order = RNA_struct_find_property(ptr, "rotation_mode");
+ }
- if (*prop_eul_order) {
- short order = RNA_property_enum_get(ptr, *prop_eul_order);
- if (order >= EULER_ORDER_XYZ && order <= EULER_ORDER_ZYX) /* could be quat or axisangle */
+ if (*r_prop_eul_order) {
+ short order = RNA_property_enum_get(ptr, *r_prop_eul_order);
+ /* could be quat or axisangle */
+ if (order >= EULER_ORDER_XYZ && order <= EULER_ORDER_ZYX) {
return order;
+ }
}
return order_fallback;
@@ -639,7 +649,8 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop)
RNA_property_float_get_array(ptr, prop, ((VectorObject *)ret)->vec);
}
else {
- PyObject *vec_cb = Vector_CreatePyObject_cb(ret, len, mathutils_rna_array_cb_index, MATHUTILS_CB_SUBTYPE_VEC);
+ PyObject *vec_cb = Vector_CreatePyObject_cb(
+ ret, len, mathutils_rna_array_cb_index, MATHUTILS_CB_SUBTYPE_VEC);
Py_DECREF(ret); /* the vector owns now */
ret = vec_cb; /* return the vector instead */
}
@@ -652,7 +663,8 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop)
RNA_property_float_get_array(ptr, prop, ((MatrixObject *)ret)->matrix);
}
else {
- PyObject *mat_cb = Matrix_CreatePyObject_cb(ret, 4, 4, mathutils_rna_matrix_cb_index, 0);
+ PyObject *mat_cb = Matrix_CreatePyObject_cb(
+ ret, 4, 4, mathutils_rna_matrix_cb_index, 0);
Py_DECREF(ret); /* the matrix owns now */
ret = mat_cb; /* return the matrix instead */
}
@@ -663,7 +675,8 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop)
RNA_property_float_get_array(ptr, prop, ((MatrixObject *)ret)->matrix);
}
else {
- PyObject *mat_cb = Matrix_CreatePyObject_cb(ret, 3, 3, mathutils_rna_matrix_cb_index, 0);
+ PyObject *mat_cb = Matrix_CreatePyObject_cb(
+ ret, 3, 3, mathutils_rna_matrix_cb_index, 0);
Py_DECREF(ret); /* the matrix owns now */
ret = mat_cb; /* return the matrix instead */
}
@@ -675,14 +688,16 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop)
if (is_thick) {
/* attempt to get order, only needed for thick types since wrapped with update via callbacks */
PropertyRNA *prop_eul_order = NULL;
- short order = pyrna_rotation_euler_order_get(ptr, &prop_eul_order, EULER_ORDER_XYZ);
+ short order = pyrna_rotation_euler_order_get(ptr, EULER_ORDER_XYZ, &prop_eul_order);
ret = Euler_CreatePyObject(NULL, order, NULL); /* TODO, get order from RNA */
RNA_property_float_get_array(ptr, prop, ((EulerObject *)ret)->eul);
}
else {
/* order will be updated from callback on use */
- PyObject *eul_cb = Euler_CreatePyObject_cb(ret, EULER_ORDER_XYZ, mathutils_rna_array_cb_index, MATHUTILS_CB_SUBTYPE_EUL); // TODO, get order from RNA
+ // TODO, get order from RNA
+ PyObject *eul_cb = Euler_CreatePyObject_cb(
+ ret, EULER_ORDER_XYZ, mathutils_rna_array_cb_index, MATHUTILS_CB_SUBTYPE_EUL);
Py_DECREF(ret); /* the euler owns now */
ret = eul_cb; /* return the euler instead */
}
@@ -693,7 +708,8 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop)
RNA_property_float_get_array(ptr, prop, ((QuaternionObject *)ret)->quat);
}
else {
- PyObject *quat_cb = Quaternion_CreatePyObject_cb(ret, mathutils_rna_array_cb_index, MATHUTILS_CB_SUBTYPE_QUAT);
+ PyObject *quat_cb = Quaternion_CreatePyObject_cb(
+ ret, mathutils_rna_array_cb_index, MATHUTILS_CB_SUBTYPE_QUAT);
Py_DECREF(ret); /* the quat owns now */
ret = quat_cb; /* return the quat instead */
}
@@ -707,7 +723,8 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop)
RNA_property_float_get_array(ptr, prop, ((ColorObject *)ret)->col);
}
else {
- PyObject *col_cb = Color_CreatePyObject_cb(ret, mathutils_rna_array_cb_index, MATHUTILS_CB_SUBTYPE_COLOR);
+ PyObject *col_cb = Color_CreatePyObject_cb(
+ ret, mathutils_rna_array_cb_index, MATHUTILS_CB_SUBTYPE_COLOR);
Py_DECREF(ret); /* the color owns now */
ret = col_cb; /* return the color instead */
}
@@ -738,9 +755,11 @@ thick_wrap_slice:
}
/* same as RNA_enum_value_from_id but raises an exception */
-int pyrna_enum_value_from_id(EnumPropertyItem *item, const char *identifier, int *value, const char *error_prefix)
+int pyrna_enum_value_from_id(
+ EnumPropertyItem *item, const char *identifier, int *r_value,
+ const char *error_prefix)
{
- if (RNA_enum_value_from_id(item, identifier, value) == 0) {
+ if (RNA_enum_value_from_id(item, identifier, r_value) == 0) {
const char *enum_str = BPy_enum_as_string(item);
PyErr_Format(PyExc_ValueError,
"%s: '%.200s' not found in (%s)",
@@ -973,7 +992,9 @@ static PyObject *pyrna_prop_str(BPy_PropertyRNA *self)
RNA_property_identifier(self->prop));
}
-static PyObject *pyrna_prop_repr(BPy_PropertyRNA *self)
+static PyObject *pyrna_prop_repr_ex(
+ BPy_PropertyRNA *self,
+ const int index_dim, const int index)
{
ID *id = self->ptr.id.data;
PyObject *tmp_str;
@@ -987,7 +1008,8 @@ static PyObject *pyrna_prop_repr(BPy_PropertyRNA *self)
tmp_str = PyUnicode_FromString(id->name + 2);
- path = RNA_path_from_ID_to_property(&self->ptr, self->prop);
+ path = RNA_path_from_ID_to_property_index(&self->ptr, self->prop, index_dim, index);
+
if (path) {
const char *data_delim = (path[0] == '[') ? "" : ".";
if (GS(id->name) == ID_NT) { /* nodetree paths are not accurate */
@@ -1015,6 +1037,15 @@ static PyObject *pyrna_prop_repr(BPy_PropertyRNA *self)
return ret;
}
+static PyObject *pyrna_prop_repr(BPy_PropertyRNA *self)
+{
+ return pyrna_prop_repr_ex(self, 0, -1);
+}
+
+static PyObject *pyrna_prop_array_repr(BPy_PropertyArrayRNA *self)
+{
+ return pyrna_prop_repr_ex((BPy_PropertyRNA *)self, self->arraydim, self->arrayoffset);
+}
static PyObject *pyrna_func_repr(BPy_FunctionRNA *self)
{
@@ -1153,7 +1184,9 @@ static const char *pyrna_enum_as_string(PointerRNA *ptr, PropertyRNA *prop)
}
-static int pyrna_string_to_enum(PyObject *item, PointerRNA *ptr, PropertyRNA *prop, int *val, const char *error_prefix)
+static int pyrna_string_to_enum(
+ PyObject *item, PointerRNA *ptr, PropertyRNA *prop, int *r_value,
+ const char *error_prefix)
{
const char *param = _PyUnicode_AsString(item);
@@ -1164,7 +1197,7 @@ static int pyrna_string_to_enum(PyObject *item, PointerRNA *ptr, PropertyRNA *pr
return -1;
}
else {
- if (!RNA_property_enum_value(BPy_GetContext(), ptr, prop, param, val)) {
+ if (!RNA_property_enum_value(BPy_GetContext(), ptr, prop, param, r_value)) {
const char *enum_str = pyrna_enum_as_string(ptr, prop);
PyErr_Format(PyExc_TypeError,
"%.200s enum \"%.200s\" not found in (%.200s)",
@@ -1241,7 +1274,9 @@ error:
}
/* 'value' _must_ be a set type, error check before calling */
-int pyrna_set_to_enum_bitfield(EnumPropertyItem *items, PyObject *value, int *r_value, const char *error_prefix)
+int pyrna_set_to_enum_bitfield(
+ EnumPropertyItem *items, PyObject *value, int *r_value,
+ const char *error_prefix)
{
/* set of enum items, concatenate all values with OR */
int ret, flag = 0;
@@ -1274,7 +1309,9 @@ int pyrna_set_to_enum_bitfield(EnumPropertyItem *items, PyObject *value, int *r_
return 0;
}
-static int pyrna_prop_to_enum_bitfield(PointerRNA *ptr, PropertyRNA *prop, PyObject *value, int *r_value, const char *error_prefix)
+static int pyrna_prop_to_enum_bitfield(
+ PointerRNA *ptr, PropertyRNA *prop, PyObject *value, int *r_value,
+ const char *error_prefix)
{
EnumPropertyItem *item;
int ret;
@@ -1493,9 +1530,13 @@ PyObject *pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop)
return ret;
}
-/* This function is used by operators and converting dicts into collections.
- * Its takes keyword args and fills them with property values */
-int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, int all_args, const char *error_prefix)
+/**
+ * This function is used by operators and converting dicts into collections.
+ * Its takes keyword args and fills them with property values
+ */
+int pyrna_pydict_to_props(
+ PointerRNA *ptr, PyObject *kw, const bool all_args,
+ const char *error_prefix)
{
int error_val = 0;
int totkw;
@@ -1570,7 +1611,9 @@ static PyObject *pyrna_func_to_py(const PointerRNA *ptr, FunctionRNA *func)
}
-static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *value, const char *error_prefix)
+static int pyrna_py_to_prop(
+ PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *value,
+ const char *error_prefix)
{
/* XXX hard limits should be checked here */
const int type = RNA_property_type(prop);
@@ -1701,7 +1744,8 @@ static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyOb
}
else {
/* same as unicode */
- if (data) *((char **)data) = (char *)param; /*XXX, this is suspect but needed for function calls, need to see if theres a better way */
+ /* XXX, this is suspect but needed for function calls, need to see if theres a better way */
+ if (data) *((char **)data) = (char *)param;
else RNA_property_string_set(ptr, prop, param);
}
}
@@ -1741,7 +1785,8 @@ static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyOb
}
else {
/* same as bytes */
- if (data) *((char **)data) = (char *)param; /*XXX, this is suspect but needed for function calls, need to see if theres a better way */
+ /* XXX, this is suspect but needed for function calls, need to see if theres a better way */
+ if (data) *((char **)data) = (char *)param;
else RNA_property_string_set(ptr, prop, param);
}
#ifdef USE_STRING_COERCE
@@ -1789,8 +1834,8 @@ static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyOb
* if the prop is not an operator type and the pyobject is an operator,
* use its properties in place of its self.
*
- * this is so bad that its almost a good reason to do away with fake 'self.properties -> self' class mixing
- * if this causes problems in the future it should be removed.
+ * this is so bad that its almost a good reason to do away with fake 'self.properties -> self'
+ * class mixing if this causes problems in the future it should be removed.
*/
if ((ptr_type == &RNA_AnyType) &&
(BPy_StructRNA_Check(value)) &&
@@ -1805,7 +1850,7 @@ static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyOb
* forward back to pyrna_pydict_to_props */
if (RNA_struct_is_a(ptr_type, &RNA_OperatorProperties) && PyDict_Check(value)) {
PointerRNA opptr = RNA_property_pointer_get(ptr, prop);
- return pyrna_pydict_to_props(&opptr, value, 0, error_prefix);
+ return pyrna_pydict_to_props(&opptr, value, false, error_prefix);
}
/* another exception, allow to pass a collection as an RNA property */
@@ -1971,7 +2016,10 @@ static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyOb
else
RNA_property_collection_add(ptr, prop, &itemptr);
- if (pyrna_pydict_to_props(&itemptr, item, 1, "Converting a python list to an RNA collection") == -1) {
+ if (pyrna_pydict_to_props(
+ &itemptr, item, true,
+ "Converting a python list to an RNA collection") == -1)
+ {
PyObject *msg = PyC_ExceptionBuffer();
const char *msg_char = _PyUnicode_AsString(msg);
@@ -2233,19 +2281,21 @@ static PyObject *pyrna_prop_collection_subscript_str(BPy_PropertyRNA *self, cons
}
/* static PyObject *pyrna_prop_array_subscript_str(BPy_PropertyRNA *self, char *keyname) */
-/* special case: bpy.data.objects["some_id_name", "//some_lib_name.blend"]
- * also for: bpy.data.objects.get(("some_id_name", "//some_lib_name.blend"), fallback)
+/**
+ * Special case: `bpy.data.objects["some_id_name", "//some_lib_name.blend"]`
+ * also for: `bpy.data.objects.get(("some_id_name", "//some_lib_name.blend"), fallback)`
*
- * note:
+ * \note
* error codes since this is not to be called directly from python,
- * this matches pythons __contains__ values capi.
- * -1: exception set
- * 0: not found
- * 1: found */
-static int pyrna_prop_collection_subscript_str_lib_pair_ptr(BPy_PropertyRNA *self, PyObject *key,
- const char *err_prefix, const short err_not_found,
- PointerRNA *r_ptr
- )
+ * this matches pythons `__contains__` values capi.
+ * - -1: exception set
+ * - 0: not found
+ * - 1: found
+ */
+static int pyrna_prop_collection_subscript_str_lib_pair_ptr(
+ BPy_PropertyRNA *self, PyObject *key,
+ const char *err_prefix, const short err_not_found,
+ PointerRNA *r_ptr)
{
const char *keyname;
@@ -2330,8 +2380,9 @@ static int pyrna_prop_collection_subscript_str_lib_pair_ptr(BPy_PropertyRNA *sel
}
}
-static PyObject *pyrna_prop_collection_subscript_str_lib_pair(BPy_PropertyRNA *self, PyObject *key,
- const char *err_prefix, const bool err_not_found)
+static PyObject *pyrna_prop_collection_subscript_str_lib_pair(
+ BPy_PropertyRNA *self, PyObject *key,
+ const char *err_prefix, const bool err_not_found)
{
PointerRNA ptr;
const int contains = pyrna_prop_collection_subscript_str_lib_pair_ptr(self, key, err_prefix, err_not_found, &ptr);
@@ -2383,8 +2434,9 @@ static PyObject *pyrna_prop_collection_subscript_slice(BPy_PropertyRNA *self, Py
* note: could also use pyrna_prop_array_to_py_index(self, count) in a loop but its a lot slower
* since at the moment it reads (and even allocates) the entire array for each index.
*/
-static PyObject *pyrna_prop_array_subscript_slice(BPy_PropertyArrayRNA *self, PointerRNA *ptr, PropertyRNA *prop,
- Py_ssize_t start, Py_ssize_t stop, Py_ssize_t length)
+static PyObject *pyrna_prop_array_subscript_slice(
+ BPy_PropertyArrayRNA *self, PointerRNA *ptr, PropertyRNA *prop,
+ Py_ssize_t start, Py_ssize_t stop, Py_ssize_t length)
{
int count, totdim;
PyObject *tuple;
@@ -4576,9 +4628,10 @@ static PyObject *pyrna_prop_collection_find(BPy_PropertyRNA *self, PyObject *key
return PyLong_FromLong(index);
}
-static bool foreach_attr_type(BPy_PropertyRNA *self, const char *attr,
- /* values to assign */
- RawPropertyType *raw_type, int *attr_tot, bool *attr_signed)
+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;
@@ -4606,12 +4659,12 @@ static bool foreach_attr_type(BPy_PropertyRNA *self, const char *attr,
}
/* pyrna_prop_collection_foreach_get/set both use this */
-static int foreach_parse_args(BPy_PropertyRNA *self, PyObject *args,
+static int foreach_parse_args(
+ BPy_PropertyRNA *self, PyObject *args,
- /* values to assign */
- const char **attr, PyObject **seq, int *tot, int *size,
- RawPropertyType *raw_type, int *attr_tot, bool *attr_signed
- )
+ /* values to assign */
+ const char **attr, PyObject **seq, int *tot, int *size,
+ RawPropertyType *raw_type, int *attr_tot, bool *attr_signed)
{
#if 0
int array_tot;
@@ -5208,7 +5261,7 @@ static PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *dat
}
case PROP_COLLECTION:
{
- ListBase *lb = (ListBase *)data;
+ CollectionListBase *lb = (CollectionListBase *)data;
CollectionPointerLink *link;
ret = PyList_New(0);
@@ -5841,7 +5894,7 @@ PyTypeObject pyrna_prop_array_Type = {
NULL, /* getattrfunc tp_getattr; */
NULL, /* setattrfunc tp_setattr; */
NULL, /* tp_compare */ /* DEPRECATED in python 3.0! */
- NULL, /* subclassed */ /* tp_repr */
+ (reprfunc)pyrna_prop_array_repr, /* tp_repr */
/* Method suites for standard classes */
@@ -7488,7 +7541,8 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param
}
}
- if (err != -1 && (is_staticmethod || is_classmethod || py_class_instance)) { /* Initializing the class worked, now run its invoke function */
+ /* Initializing the class worked, now run its invoke function */
+ if (err != -1 && (is_staticmethod || is_classmethod || py_class_instance)) {
PyObject *item = PyObject_GetAttrString((PyObject *)py_class, RNA_function_identifier(func));
if (item) {
@@ -7901,7 +7955,9 @@ static PyObject *pyrna_register_class(PyObject *UNUSED(self), PyObject *py_class
}
-static int pyrna_srna_contains_pointer_prop_srna(StructRNA *srna_props, StructRNA *srna, const char **prop_identifier)
+static int pyrna_srna_contains_pointer_prop_srna(
+ StructRNA *srna_props, StructRNA *srna,
+ const char **r_prop_identifier)
{
PropertyRNA *prop;
LinkData *link;
@@ -7916,7 +7972,7 @@ static int pyrna_srna_contains_pointer_prop_srna(StructRNA *srna_props, StructRN
RNA_pointer_create(NULL, &RNA_Struct, srna_props, &tptr);
if (RNA_property_pointer_type(&tptr, prop) == srna) {
- *prop_identifier = RNA_property_identifier(prop);
+ *r_prop_identifier = RNA_property_identifier(prop);
return 1;
}
}
diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h
index c5d4a346f56..e38d4f095d6 100644
--- a/source/blender/python/intern/bpy_rna.h
+++ b/source/blender/python/intern/bpy_rna.h
@@ -181,7 +181,7 @@ PyObject *pyrna_id_CreatePyObject(struct ID *id);
bool pyrna_id_FromPyObject(PyObject *obj, struct ID **id);
/* operators also need this to set args */
-int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, int all_args, const char *error_prefix);
+int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, const bool all_args, const char *error_prefix);
PyObject *pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop);
unsigned int *pyrna_set_to_enum_bitmap(
diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c
index 2ec73c3c9b7..92931eb8090 100644
--- a/source/blender/python/intern/bpy_rna_anim.c
+++ b/source/blender/python/intern/bpy_rna_anim.c
@@ -27,7 +27,7 @@
*/
#include <Python.h>
-#include <float.h> /* FLT_MIN/MAX */
+#include <float.h> /* FLT_MAX */
#include "MEM_guardedalloc.h"
diff --git a/source/blender/python/intern/bpy_rna_driver.c b/source/blender/python/intern/bpy_rna_driver.c
index 482508a8d85..b4c0de51c04 100644
--- a/source/blender/python/intern/bpy_rna_driver.c
+++ b/source/blender/python/intern/bpy_rna_driver.c
@@ -77,3 +77,24 @@ PyObject *pyrna_driver_get_variable_value(
return driver_arg;
}
+
+PyObject *pyrna_driver_self_from_anim_rna(PathResolvedRNA *anim_rna)
+{
+ return pyrna_struct_CreatePyObject(&anim_rna->ptr);
+}
+
+bool pyrna_driver_is_equal_anim_rna(const PathResolvedRNA *anim_rna, const PyObject *py_anim_rna)
+{
+ if (BPy_StructRNA_Check(py_anim_rna)) {
+ const PointerRNA *ptr_a = &anim_rna->ptr;
+ const PointerRNA *ptr_b = &(((const BPy_StructRNA *)py_anim_rna)->ptr);
+
+ if ((ptr_a->id.data == ptr_b->id.data) &&
+ (ptr_a->type == ptr_b->type) &&
+ (ptr_a->data == ptr_b->data))
+ {
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/source/blender/python/intern/bpy_rna_driver.h b/source/blender/python/intern/bpy_rna_driver.h
index 8deac2e4384..3f4bf2b9df5 100644
--- a/source/blender/python/intern/bpy_rna_driver.h
+++ b/source/blender/python/intern/bpy_rna_driver.h
@@ -27,7 +27,11 @@
struct ChannelDriver;
struct DriverTarget;
+struct PathResolvedRNA;
PyObject *pyrna_driver_get_variable_value(struct ChannelDriver *driver, struct DriverTarget *dtar);
+PyObject *pyrna_driver_self_from_anim_rna(struct PathResolvedRNA *anim_rna);
+bool pyrna_driver_is_equal_anim_rna(const struct PathResolvedRNA *anim_rna, const PyObject *py_anim_rna);
+
#endif /* __BPY_RNA_DRIVER_H__ */
diff --git a/source/blender/python/intern/bpy_rna_id_collection.c b/source/blender/python/intern/bpy_rna_id_collection.c
index 104e3e47646..1037c83815c 100644
--- a/source/blender/python/intern/bpy_rna_id_collection.c
+++ b/source/blender/python/intern/bpy_rna_id_collection.c
@@ -40,6 +40,9 @@
#include "BKE_library_query.h"
#include "DNA_ID.h"
+/* Those folowing are only to support hack of not listing some internal 'backward' pointers in generated user_map... */
+#include "DNA_object_types.h"
+#include "DNA_key_types.h"
#include "bpy_util.h"
#include "bpy_rna_id_collection.h"
@@ -81,7 +84,7 @@ static bool id_check_type(const ID *id, const BLI_bitmap *types_bitmap)
}
static int foreach_libblock_id_user_map_callback(
- void *user_data, ID *UNUSED(self_id), ID **id_p, int UNUSED(cb_flag))
+ void *user_data, ID *self_id, ID **id_p, int UNUSED(cb_flag))
{
IDUserMapData *data = user_data;
@@ -93,6 +96,15 @@ static int foreach_libblock_id_user_map_callback(
}
}
+ if ((GS(self_id->name) == ID_OB) && (id_p == (ID **)&((Object *)self_id)->proxy_from)) {
+ /* We skip proxy_from here, since it some internal pointer which is not irrelevant info for py/API level. */
+ return IDWALK_RET_NOP;
+ }
+ else if ((GS(self_id->name) == ID_KE) && (id_p == (ID **)&((Key *)self_id)->from)) {
+ /* We skip from here, since it some internal pointer which is not irrelevant info for py/API level. */
+ return IDWALK_RET_NOP;
+ }
+
/* pyrna_struct_hash() uses ptr.data only,
* but pyrna_struct_richcmp() uses also ptr.type,
* so we need to create a valid PointerRNA here...
@@ -198,7 +210,7 @@ static PyObject *bpy_user_map(PyObject *UNUSED(self), PyObject *args, PyObject *
PyObject **subset_array = PySequence_Fast_ITEMS(subset_fast);
Py_ssize_t subset_len = PySequence_Fast_GET_SIZE(subset_fast);
- data_cb.user_map = PyDict_New();
+ data_cb.user_map = _PyDict_NewPresized(subset_len);
data_cb.is_subset = true;
for (; subset_len; subset_array++, subset_len--) {
PyObject *set = PySet_New(NULL);
@@ -233,8 +245,26 @@ static PyObject *bpy_user_map(PyObject *UNUSED(self), PyObject *args, PyObject *
data_cb.py_id_key_lookup_only = pyrna_id_CreatePyObject(id);
}
+ if (!data_cb.is_subset) {
+ PyObject *key = data_cb.py_id_key_lookup_only;
+ PyObject *set;
+
+ RNA_id_pointer_create(id, &((BPy_StructRNA *)key)->ptr);
+
+ /* We have to insert the key now, otherwise ID unused would be missing from final dict... */
+ if ((set = PyDict_GetItem(data_cb.user_map, key)) == NULL) {
+ /* Cannot use our placeholder key here! */
+ key = pyrna_id_CreatePyObject(id);
+ set = PySet_New(NULL);
+ PyDict_SetItem(data_cb.user_map, key, set);
+ Py_DECREF(set);
+ Py_DECREF(key);
+ }
+ }
+
data_cb.id_curr = id;
BKE_library_foreach_ID_link(id, foreach_libblock_id_user_map_callback, &data_cb, IDWALK_NOP);
+
if (data_cb.py_id_curr) {
Py_DECREF(data_cb.py_id_curr);
data_cb.py_id_curr = NULL;
diff --git a/source/blender/python/intern/bpy_util.c b/source/blender/python/intern/bpy_util.c
index ee827c06e14..2b8ad6ccb90 100644
--- a/source/blender/python/intern/bpy_util.c
+++ b/source/blender/python/intern/bpy_util.c
@@ -148,4 +148,4 @@ bool BPy_errors_to_report_ex(ReportList *reports, const bool use_full, const boo
bool BPy_errors_to_report(ReportList *reports)
{
return BPy_errors_to_report_ex(reports, true, true);
-} \ No newline at end of file
+}
diff --git a/source/blender/python/intern/gpu.c b/source/blender/python/intern/gpu.c
index 66c1ddcc352..50dd4618166 100644
--- a/source/blender/python/intern/gpu.c
+++ b/source/blender/python/intern/gpu.c
@@ -261,6 +261,9 @@ static PyObject *GPU_export_shader(PyObject *UNUSED(self), PyObject *args, PyObj
if (uniform->lamp) {
PY_DICT_ADD_ID(dict, uniform, lamp);
}
+ if (uniform->material) {
+ PY_DICT_ADD_ID(dict, uniform, material);
+ }
if (uniform->image) {
PY_DICT_ADD_ID(dict, uniform, image);
}
@@ -327,10 +330,10 @@ PyObject *GPU_initPython(void)
/* gpu.offscreen */
PyModule_AddObject(module, "offscreen", (submodule = BPyInit_gpu_offscreen()));
- PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
+ PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
Py_INCREF(submodule);
- PyDict_SetItemString(PyImport_GetModuleDict(), "gpu", module);
+ PyDict_SetItem(PyImport_GetModuleDict(), PyModule_GetNameObject(module), module);
return module;
}
diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c
index 635090869ea..5c505247a97 100644
--- a/source/blender/python/mathutils/mathutils.c
+++ b/source/blender/python/mathutils/mathutils.c
@@ -638,30 +638,30 @@ PyMODINIT_FUNC PyInit_mathutils(void)
/* XXX, python doesnt do imports with this usefully yet
* 'from mathutils.geometry import PolyFill'
* ...fails without this. */
- PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
+ PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
Py_INCREF(submodule);
PyModule_AddObject(mod, "interpolate", (submodule = PyInit_mathutils_interpolate()));
/* XXX, python doesnt do imports with this usefully yet
* 'from mathutils.geometry import PolyFill'
* ...fails without this. */
- PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
+ PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
Py_INCREF(submodule);
#ifndef MATH_STANDALONE
/* Noise submodule */
PyModule_AddObject(mod, "noise", (submodule = PyInit_mathutils_noise()));
- PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
+ PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
Py_INCREF(submodule);
/* BVHTree submodule */
PyModule_AddObject(mod, "bvhtree", (submodule = PyInit_mathutils_bvhtree()));
- PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
+ PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
Py_INCREF(submodule);
/* KDTree submodule */
PyModule_AddObject(mod, "kdtree", (submodule = PyInit_mathutils_kdtree()));
- PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
+ PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
Py_INCREF(submodule);
#endif
diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c
index 71288871104..4e980e4c0e6 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.c
+++ b/source/blender/python/mathutils/mathutils_Matrix.c
@@ -1394,7 +1394,7 @@ PyDoc_STRVAR(Matrix_invert_doc,
" (instead of raising a :exc:`ValueError` exception).\n"
" :type fallback: :class:`Matrix`\n"
"\n"
-" .. seealso:: <http://en.wikipedia.org/wiki/Inverse_matrix>\n"
+" .. seealso:: <https://en.wikipedia.org/wiki/Inverse_matrix>\n"
);
static PyObject *Matrix_invert(MatrixObject *self, PyObject *args)
{
@@ -1505,7 +1505,7 @@ PyDoc_STRVAR(Matrix_invert_safe_doc,
" If degenerated (e.g. zero scale on an axis), add some epsilon to its diagonal, to get an invertible one.\n"
" If tweaked matrix is still degenerated, set to the identity matrix instead.\n"
"\n"
-" .. seealso:: <http://en.wikipedia.org/wiki/Inverse_matrix>\n"
+" .. seealso:: <https://en.wikipedia.org/wiki/Inverse_matrix>\n"
);
static PyObject *Matrix_invert_safe(MatrixObject *self)
{
@@ -1556,7 +1556,7 @@ PyDoc_STRVAR(Matrix_adjugate_doc,
"\n"
" .. note:: When the matrix cant be adjugated a :exc:`ValueError` exception is raised.\n"
"\n"
-" .. seealso:: <http://en.wikipedia.org/wiki/Adjugate_matrix>\n"
+" .. seealso:: <https://en.wikipedia.org/wiki/Adjugate_matrix>\n"
);
static PyObject *Matrix_adjugate(MatrixObject *self)
{
@@ -1733,7 +1733,7 @@ PyDoc_STRVAR(Matrix_determinant_doc,
" :return: Return the determinant of a matrix.\n"
" :rtype: float\n"
"\n"
-" .. seealso:: <http://en.wikipedia.org/wiki/Determinant>\n"
+" .. seealso:: <https://en.wikipedia.org/wiki/Determinant>\n"
);
static PyObject *Matrix_determinant(MatrixObject *self)
{
@@ -1755,7 +1755,7 @@ PyDoc_STRVAR(Matrix_transpose_doc,
"\n"
" Set the matrix to its transpose.\n"
"\n"
-" .. seealso:: <http://en.wikipedia.org/wiki/Transpose>\n"
+" .. seealso:: <https://en.wikipedia.org/wiki/Transpose>\n"
);
static PyObject *Matrix_transpose(MatrixObject *self)
{
@@ -1890,7 +1890,7 @@ PyDoc_STRVAR(Matrix_identity_doc,
" .. note:: An object with zero location and rotation, a scale of one,\n"
" will have an identity matrix.\n"
"\n"
-" .. seealso:: <http://en.wikipedia.org/wiki/Identity_matrix>\n"
+" .. seealso:: <https://en.wikipedia.org/wiki/Identity_matrix>\n"
);
static PyObject *Matrix_identity(MatrixObject *self)
{
diff --git a/source/blender/python/mathutils/mathutils_Matrix.h b/source/blender/python/mathutils/mathutils_Matrix.h
index 9ae5a4bd61d..542a0e349c7 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.h
+++ b/source/blender/python/mathutils/mathutils_Matrix.h
@@ -41,7 +41,7 @@ extern PyTypeObject matrix_access_Type;
# define MATRIX_ITEM_ASSERT(_mat, _row, _col) (void)0
#endif
-#define MATRIX_ITEM_INDEX_NUMROW(_totrow, _row, _col) ((_totrow * (_col)) + (_row))
+#define MATRIX_ITEM_INDEX_NUMROW(_totrow, _row, _col) (((_totrow) * (_col)) + (_row))
#define MATRIX_ITEM_INDEX(_mat, _row, _col) (MATRIX_ITEM_ASSERT(_mat, _row, _col),(((_mat)->num_row * (_col)) + (_row)))
#define MATRIX_ITEM_PTR( _mat, _row, _col) ((_mat)->matrix + MATRIX_ITEM_INDEX(_mat, _row, _col))
#define MATRIX_ITEM( _mat, _row, _col) ((_mat)->matrix [MATRIX_ITEM_INDEX(_mat, _row, _col)])
diff --git a/source/blender/python/mathutils/mathutils_Quaternion.c b/source/blender/python/mathutils/mathutils_Quaternion.c
index ea5732966b2..71b3cf8ddac 100644
--- a/source/blender/python/mathutils/mathutils_Quaternion.c
+++ b/source/blender/python/mathutils/mathutils_Quaternion.c
@@ -1165,9 +1165,9 @@ static void quat__axis_angle_sanitize(float axis[3], float *angle)
{
if (axis) {
if (is_zero_v3(axis) ||
- !finite(axis[0]) ||
- !finite(axis[1]) ||
- !finite(axis[2]))
+ !isfinite(axis[0]) ||
+ !isfinite(axis[1]) ||
+ !isfinite(axis[2]))
{
axis[0] = 1.0f;
axis[1] = 0.0f;
@@ -1182,7 +1182,7 @@ static void quat__axis_angle_sanitize(float axis[3], float *angle)
}
if (angle) {
- if (!finite(*angle)) {
+ if (!isfinite(*angle)) {
*angle = 0.0f;
}
}
diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c
index 7b6fa466fce..afc8a30a6b5 100644
--- a/source/blender/python/mathutils/mathutils_Vector.c
+++ b/source/blender/python/mathutils/mathutils_Vector.c
@@ -2324,6 +2324,20 @@ static int Vector_swizzle_set(VectorObject *self, PyObject *value, void *closure
return 0;
}
+/* XYZW -> 0123 */
+#define AXIS_FROM_CHAR(a) (((a) != 'W') ? ((a) - 'X') : 3)
+
+#define _VA_SWIZZLE_1(a) ( \
+ ((AXIS_FROM_CHAR(a) | SWIZZLE_VALID_AXIS)))
+#define _VA_SWIZZLE_2(a, b) (_VA_SWIZZLE_1(a) | \
+ ((AXIS_FROM_CHAR(b) | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS)))
+#define _VA_SWIZZLE_3(a, b, c) (_VA_SWIZZLE_2(a, b) | \
+ ((AXIS_FROM_CHAR(c) | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)))
+#define _VA_SWIZZLE_4(a, b, c, d) (_VA_SWIZZLE_3(a, b, c) | \
+ ((AXIS_FROM_CHAR(d) | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3)))
+
+#define SWIZZLE(...) SET_INT_IN_POINTER(VA_NARGS_CALL_OVERLOAD(_VA_SWIZZLE_, __VA_ARGS__))
+
/*****************************************************************************/
/* Python attributes get/set structure: */
/*****************************************************************************/
@@ -2340,385 +2354,409 @@ static PyGetSetDef Vector_getseters[] = {
{(char *)"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL},
/* autogenerated swizzle attrs, see python script below */
- {(char *)"xx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 36
- {(char *)"xxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 292
- {(char *)"xxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2340
- {(char *)"xxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2852
- {(char *)"xxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3364
- {(char *)"xxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3876
- {(char *)"xxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 356
- {(char *)"xxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2404
- {(char *)"xxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2916
- {(char *)"xxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3428
- {(char *)"xxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3940
- {(char *)"xxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 420
- {(char *)"xxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2468
- {(char *)"xxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2980
- {(char *)"xxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3492
- {(char *)"xxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4004
- {(char *)"xxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 484
- {(char *)"xxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2532
- {(char *)"xxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3044
- {(char *)"xxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3556
- {(char *)"xxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4068
- {(char *)"xy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 44
- {(char *)"xyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 300
- {(char *)"xyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2348
- {(char *)"xyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2860
- {(char *)"xyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3372
- {(char *)"xyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3884
- {(char *)"xyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 364
- {(char *)"xyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2412
- {(char *)"xyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2924
- {(char *)"xyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3436
- {(char *)"xyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3948
- {(char *)"xyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 428
- {(char *)"xyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2476
- {(char *)"xyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2988
- {(char *)"xyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3500
- {(char *)"xyzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4012
- {(char *)"xyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 492
- {(char *)"xywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2540
- {(char *)"xywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3052
- {(char *)"xywz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3564
- {(char *)"xyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4076
- {(char *)"xz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 52
- {(char *)"xzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 308
- {(char *)"xzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2356
- {(char *)"xzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2868
- {(char *)"xzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3380
- {(char *)"xzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3892
- {(char *)"xzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 372
- {(char *)"xzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2420
- {(char *)"xzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2932
- {(char *)"xzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3444
- {(char *)"xzyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3956
- {(char *)"xzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 436
- {(char *)"xzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2484
- {(char *)"xzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2996
- {(char *)"xzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3508
- {(char *)"xzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4020
- {(char *)"xzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 500
- {(char *)"xzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2548
- {(char *)"xzwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3060
- {(char *)"xzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3572
- {(char *)"xzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4084
- {(char *)"xw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 60
- {(char *)"xwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 316
- {(char *)"xwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2364
- {(char *)"xwxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2876
- {(char *)"xwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3388
- {(char *)"xwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3900
- {(char *)"xwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 380
- {(char *)"xwyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2428
- {(char *)"xwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2940
- {(char *)"xwyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3452
- {(char *)"xwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3964
- {(char *)"xwz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 444
- {(char *)"xwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2492
- {(char *)"xwzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3004
- {(char *)"xwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3516
- {(char *)"xwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4028
- {(char *)"xww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 508
- {(char *)"xwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2556
- {(char *)"xwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3068
- {(char *)"xwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3580
- {(char *)"xwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((0 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4092
- {(char *)"yx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 37
- {(char *)"yxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 293
- {(char *)"yxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2341
- {(char *)"yxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2853
- {(char *)"yxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3365
- {(char *)"yxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3877
- {(char *)"yxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 357
- {(char *)"yxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2405
- {(char *)"yxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2917
- {(char *)"yxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3429
- {(char *)"yxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3941
- {(char *)"yxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 421
- {(char *)"yxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2469
- {(char *)"yxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2981
- {(char *)"yxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3493
- {(char *)"yxzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4005
- {(char *)"yxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 485
- {(char *)"yxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2533
- {(char *)"yxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3045
- {(char *)"yxwz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3557
- {(char *)"yxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4069
- {(char *)"yy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 45
- {(char *)"yyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 301
- {(char *)"yyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2349
- {(char *)"yyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2861
- {(char *)"yyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3373
- {(char *)"yyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3885
- {(char *)"yyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 365
- {(char *)"yyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2413
- {(char *)"yyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2925
- {(char *)"yyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3437
- {(char *)"yyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3949
- {(char *)"yyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 429
- {(char *)"yyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2477
- {(char *)"yyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2989
- {(char *)"yyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3501
- {(char *)"yyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4013
- {(char *)"yyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 493
- {(char *)"yywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2541
- {(char *)"yywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3053
- {(char *)"yywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3565
- {(char *)"yyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4077
- {(char *)"yz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 53
- {(char *)"yzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 309
- {(char *)"yzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2357
- {(char *)"yzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2869
- {(char *)"yzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3381
- {(char *)"yzxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3893
- {(char *)"yzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 373
- {(char *)"yzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2421
- {(char *)"yzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2933
- {(char *)"yzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3445
- {(char *)"yzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3957
- {(char *)"yzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 437
- {(char *)"yzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2485
- {(char *)"yzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2997
- {(char *)"yzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3509
- {(char *)"yzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4021
- {(char *)"yzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 501
- {(char *)"yzwx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2549
- {(char *)"yzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3061
- {(char *)"yzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3573
- {(char *)"yzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4085
- {(char *)"yw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 61
- {(char *)"ywx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 317
- {(char *)"ywxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2365
- {(char *)"ywxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2877
- {(char *)"ywxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3389
- {(char *)"ywxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3901
- {(char *)"ywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 381
- {(char *)"ywyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2429
- {(char *)"ywyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2941
- {(char *)"ywyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3453
- {(char *)"ywyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3965
- {(char *)"ywz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 445
- {(char *)"ywzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2493
- {(char *)"ywzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3005
- {(char *)"ywzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3517
- {(char *)"ywzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4029
- {(char *)"yww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 509
- {(char *)"ywwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2557
- {(char *)"ywwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3069
- {(char *)"ywwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3581
- {(char *)"ywww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((1 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4093
- {(char *)"zx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 38
- {(char *)"zxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 294
- {(char *)"zxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2342
- {(char *)"zxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2854
- {(char *)"zxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3366
- {(char *)"zxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3878
- {(char *)"zxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 358
- {(char *)"zxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2406
- {(char *)"zxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2918
- {(char *)"zxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3430
- {(char *)"zxyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3942
- {(char *)"zxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 422
- {(char *)"zxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2470
- {(char *)"zxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2982
- {(char *)"zxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3494
- {(char *)"zxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4006
- {(char *)"zxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 486
- {(char *)"zxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2534
- {(char *)"zxwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3046
- {(char *)"zxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3558
- {(char *)"zxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4070
- {(char *)"zy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 46
- {(char *)"zyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 302
- {(char *)"zyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2350
- {(char *)"zyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2862
- {(char *)"zyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3374
- {(char *)"zyxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3886
- {(char *)"zyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 366
- {(char *)"zyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2414
- {(char *)"zyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2926
- {(char *)"zyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3438
- {(char *)"zyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3950
- {(char *)"zyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 430
- {(char *)"zyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2478
- {(char *)"zyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2990
- {(char *)"zyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3502
- {(char *)"zyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4014
- {(char *)"zyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 494
- {(char *)"zywx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2542
- {(char *)"zywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3054
- {(char *)"zywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3566
- {(char *)"zyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4078
- {(char *)"zz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 54
- {(char *)"zzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 310
- {(char *)"zzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2358
- {(char *)"zzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2870
- {(char *)"zzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3382
- {(char *)"zzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3894
- {(char *)"zzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 374
- {(char *)"zzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2422
- {(char *)"zzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2934
- {(char *)"zzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3446
- {(char *)"zzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3958
- {(char *)"zzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 438
- {(char *)"zzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2486
- {(char *)"zzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2998
- {(char *)"zzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3510
- {(char *)"zzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4022
- {(char *)"zzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 502
- {(char *)"zzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2550
- {(char *)"zzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3062
- {(char *)"zzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3574
- {(char *)"zzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4086
- {(char *)"zw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 62
- {(char *)"zwx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 318
- {(char *)"zwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2366
- {(char *)"zwxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2878
- {(char *)"zwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3390
- {(char *)"zwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3902
- {(char *)"zwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 382
- {(char *)"zwyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2430
- {(char *)"zwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2942
- {(char *)"zwyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3454
- {(char *)"zwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3966
- {(char *)"zwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 446
- {(char *)"zwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2494
- {(char *)"zwzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3006
- {(char *)"zwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3518
- {(char *)"zwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4030
- {(char *)"zww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 510
- {(char *)"zwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2558
- {(char *)"zwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3070
- {(char *)"zwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3582
- {(char *)"zwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((2 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4094
- {(char *)"wx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 39
- {(char *)"wxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 295
- {(char *)"wxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2343
- {(char *)"wxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2855
- {(char *)"wxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3367
- {(char *)"wxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3879
- {(char *)"wxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 359
- {(char *)"wxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2407
- {(char *)"wxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2919
- {(char *)"wxyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3431
- {(char *)"wxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3943
- {(char *)"wxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 423
- {(char *)"wxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2471
- {(char *)"wxzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2983
- {(char *)"wxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3495
- {(char *)"wxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4007
- {(char *)"wxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 487
- {(char *)"wxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2535
- {(char *)"wxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3047
- {(char *)"wxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3559
- {(char *)"wxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4071
- {(char *)"wy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 47
- {(char *)"wyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 303
- {(char *)"wyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2351
- {(char *)"wyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2863
- {(char *)"wyxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3375
- {(char *)"wyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3887
- {(char *)"wyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 367
- {(char *)"wyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2415
- {(char *)"wyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2927
- {(char *)"wyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3439
- {(char *)"wyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3951
- {(char *)"wyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 431
- {(char *)"wyzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2479
- {(char *)"wyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2991
- {(char *)"wyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3503
- {(char *)"wyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4015
- {(char *)"wyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 495
- {(char *)"wywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2543
- {(char *)"wywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3055
- {(char *)"wywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3567
- {(char *)"wyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4079
- {(char *)"wz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 55
- {(char *)"wzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 311
- {(char *)"wzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2359
- {(char *)"wzxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2871
- {(char *)"wzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3383
- {(char *)"wzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3895
- {(char *)"wzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 375
- {(char *)"wzyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2423
- {(char *)"wzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2935
- {(char *)"wzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3447
- {(char *)"wzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3959
- {(char *)"wzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 439
- {(char *)"wzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2487
- {(char *)"wzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2999
- {(char *)"wzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3511
- {(char *)"wzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4023
- {(char *)"wzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 503
- {(char *)"wzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2551
- {(char *)"wzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3063
- {(char *)"wzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3575
- {(char *)"wzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4087
- {(char *)"ww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS)))}, // 63
- {(char *)"wwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 319
- {(char *)"wwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2367
- {(char *)"wwxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2879
- {(char *)"wwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3391
- {(char *)"wwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3903
- {(char *)"wwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 383
- {(char *)"wwyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2431
- {(char *)"wwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2943
- {(char *)"wwyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3455
- {(char *)"wwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3967
- {(char *)"wwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 447
- {(char *)"wwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2495
- {(char *)"wwzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3007
- {(char *)"wwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3519
- {(char *)"wwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4031
- {(char *)"www", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))))}, // 511
- {(char *)"wwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((0 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 2559
- {(char *)"wwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((1 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3071
- {(char *)"wwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((2 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 3583
- {(char *)"wwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SET_INT_IN_POINTER(((3 | SWIZZLE_VALID_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((3 | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) )}, // 4095
+ {(char *)"xx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X')},
+ {(char *)"xxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'X')},
+ {(char *)"xxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'X', 'X')},
+ {(char *)"xxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'X', 'Y')},
+ {(char *)"xxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'X', 'Z')},
+ {(char *)"xxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'X', 'W')},
+ {(char *)"xxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Y')},
+ {(char *)"xxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Y', 'X')},
+ {(char *)"xxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Y', 'Y')},
+ {(char *)"xxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Y', 'Z')},
+ {(char *)"xxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Y', 'W')},
+ {(char *)"xxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Z')},
+ {(char *)"xxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Z', 'X')},
+ {(char *)"xxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Z', 'Y')},
+ {(char *)"xxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Z', 'Z')},
+ {(char *)"xxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Z', 'W')},
+ {(char *)"xxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'W')},
+ {(char *)"xxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'W', 'X')},
+ {(char *)"xxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'W', 'Y')},
+ {(char *)"xxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'W', 'Z')},
+ {(char *)"xxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'W', 'W')},
+ {(char *)"xy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Y')},
+ {(char *)"xyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'X')},
+ {(char *)"xyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'X', 'X')},
+ {(char *)"xyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'X', 'Y')},
+ {(char *)"xyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'X', 'Z')},
+ {(char *)"xyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'X', 'W')},
+ {(char *)"xyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Y')},
+ {(char *)"xyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Y', 'X')},
+ {(char *)"xyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Y', 'Y')},
+ {(char *)"xyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Y', 'Z')},
+ {(char *)"xyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Y', 'W')},
+ {(char *)"xyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Y', 'Z')},
+ {(char *)"xyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Z', 'X')},
+ {(char *)"xyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Z', 'Y')},
+ {(char *)"xyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Z', 'Z')},
+ {(char *)"xyzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Y', 'Z', 'W')},
+ {(char *)"xyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Y', 'W')},
+ {(char *)"xywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'W', 'X')},
+ {(char *)"xywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'W', 'Y')},
+ {(char *)"xywz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Y', 'W', 'Z')},
+ {(char *)"xyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'W', 'W')},
+ {(char *)"xz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Z')},
+ {(char *)"xzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'X')},
+ {(char *)"xzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'X', 'X')},
+ {(char *)"xzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'X', 'Y')},
+ {(char *)"xzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'X', 'Z')},
+ {(char *)"xzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'X', 'W')},
+ {(char *)"xzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Z', 'Y')},
+ {(char *)"xzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Y', 'X')},
+ {(char *)"xzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Y', 'Y')},
+ {(char *)"xzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Y', 'Z')},
+ {(char *)"xzyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Z', 'Y', 'W')},
+ {(char *)"xzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Z')},
+ {(char *)"xzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Z', 'X')},
+ {(char *)"xzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Z', 'Y')},
+ {(char *)"xzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Z', 'Z')},
+ {(char *)"xzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Z', 'W')},
+ {(char *)"xzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Z', 'W')},
+ {(char *)"xzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'W', 'X')},
+ {(char *)"xzwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Z', 'W', 'Y')},
+ {(char *)"xzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'W', 'Z')},
+ {(char *)"xzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'W', 'W')},
+ {(char *)"xw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'W')},
+ {(char *)"xwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'X')},
+ {(char *)"xwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'X', 'X')},
+ {(char *)"xwxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'X', 'Y')},
+ {(char *)"xwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'X', 'Z')},
+ {(char *)"xwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'X', 'W')},
+ {(char *)"xwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'W', 'Y')},
+ {(char *)"xwyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Y', 'X')},
+ {(char *)"xwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Y', 'Y')},
+ {(char *)"xwyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'W', 'Y', 'Z')},
+ {(char *)"xwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Y', 'W')},
+ {(char *)"xwz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'W', 'Z')},
+ {(char *)"xwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Z', 'X')},
+ {(char *)"xwzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'W', 'Z', 'Y')},
+ {(char *)"xwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Z', 'Z')},
+ {(char *)"xwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Z', 'W')},
+ {(char *)"xww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'W')},
+ {(char *)"xwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'W', 'X')},
+ {(char *)"xwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'W', 'Y')},
+ {(char *)"xwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'W', 'Z')},
+ {(char *)"xwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'W', 'W')},
+ {(char *)"yx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'X')},
+ {(char *)"yxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'X')},
+ {(char *)"yxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'X', 'X')},
+ {(char *)"yxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'X', 'Y')},
+ {(char *)"yxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'X', 'Z')},
+ {(char *)"yxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'X', 'W')},
+ {(char *)"yxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Y')},
+ {(char *)"yxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Y', 'X')},
+ {(char *)"yxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Y', 'Y')},
+ {(char *)"yxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Y', 'Z')},
+ {(char *)"yxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Y', 'W')},
+ {(char *)"yxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'X', 'Z')},
+ {(char *)"yxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Z', 'X')},
+ {(char *)"yxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Z', 'Y')},
+ {(char *)"yxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Z', 'Z')},
+ {(char *)"yxzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'X', 'Z', 'W')},
+ {(char *)"yxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'X', 'W')},
+ {(char *)"yxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'W', 'X')},
+ {(char *)"yxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'W', 'Y')},
+ {(char *)"yxwz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'X', 'W', 'Z')},
+ {(char *)"yxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'W', 'W')},
+ {(char *)"yy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y')},
+ {(char *)"yyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'X')},
+ {(char *)"yyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'X', 'X')},
+ {(char *)"yyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'X', 'Y')},
+ {(char *)"yyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'X', 'Z')},
+ {(char *)"yyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'X', 'W')},
+ {(char *)"yyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Y')},
+ {(char *)"yyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Y', 'X')},
+ {(char *)"yyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Y', 'Y')},
+ {(char *)"yyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Y', 'Z')},
+ {(char *)"yyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Y', 'W')},
+ {(char *)"yyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Z')},
+ {(char *)"yyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Z', 'X')},
+ {(char *)"yyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Z', 'Y')},
+ {(char *)"yyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Z', 'Z')},
+ {(char *)"yyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Z', 'W')},
+ {(char *)"yyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'W')},
+ {(char *)"yywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'W', 'X')},
+ {(char *)"yywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'W', 'Y')},
+ {(char *)"yywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'W', 'Z')},
+ {(char *)"yyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'W', 'W')},
+ {(char *)"yz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'Z')},
+ {(char *)"yzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'Z', 'X')},
+ {(char *)"yzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'X', 'X')},
+ {(char *)"yzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'X', 'Y')},
+ {(char *)"yzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'X', 'Z')},
+ {(char *)"yzxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'Z', 'X', 'W')},
+ {(char *)"yzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Y')},
+ {(char *)"yzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Y', 'X')},
+ {(char *)"yzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Y', 'Y')},
+ {(char *)"yzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Y', 'Z')},
+ {(char *)"yzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Y', 'W')},
+ {(char *)"yzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Z')},
+ {(char *)"yzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Z', 'X')},
+ {(char *)"yzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Z', 'Y')},
+ {(char *)"yzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Z', 'Z')},
+ {(char *)"yzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Z', 'W')},
+ {(char *)"yzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'Z', 'W')},
+ {(char *)"yzwx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'Z', 'W', 'X')},
+ {(char *)"yzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'W', 'Y')},
+ {(char *)"yzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'W', 'Z')},
+ {(char *)"yzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'W', 'W')},
+ {(char *)"yw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'W')},
+ {(char *)"ywx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'W', 'X')},
+ {(char *)"ywxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'X', 'X')},
+ {(char *)"ywxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'X', 'Y')},
+ {(char *)"ywxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'W', 'X', 'Z')},
+ {(char *)"ywxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'X', 'W')},
+ {(char *)"ywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Y')},
+ {(char *)"ywyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Y', 'X')},
+ {(char *)"ywyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Y', 'Y')},
+ {(char *)"ywyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Y', 'Z')},
+ {(char *)"ywyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Y', 'W')},
+ {(char *)"ywz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'W', 'Z')},
+ {(char *)"ywzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'W', 'Z', 'X')},
+ {(char *)"ywzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Z', 'Y')},
+ {(char *)"ywzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Z', 'Z')},
+ {(char *)"ywzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Z', 'W')},
+ {(char *)"yww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'W')},
+ {(char *)"ywwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'W', 'X')},
+ {(char *)"ywwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'W', 'Y')},
+ {(char *)"ywwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'W', 'Z')},
+ {(char *)"ywww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'W', 'W')},
+ {(char *)"zx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'X')},
+ {(char *)"zxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'X')},
+ {(char *)"zxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'X', 'X')},
+ {(char *)"zxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'X', 'Y')},
+ {(char *)"zxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'X', 'Z')},
+ {(char *)"zxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'X', 'W')},
+ {(char *)"zxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'X', 'Y')},
+ {(char *)"zxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Y', 'X')},
+ {(char *)"zxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Y', 'Y')},
+ {(char *)"zxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Y', 'Z')},
+ {(char *)"zxyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'X', 'Y', 'W')},
+ {(char *)"zxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Z')},
+ {(char *)"zxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Z', 'X')},
+ {(char *)"zxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Z', 'Y')},
+ {(char *)"zxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Z', 'Z')},
+ {(char *)"zxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Z', 'W')},
+ {(char *)"zxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'X', 'W')},
+ {(char *)"zxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'W', 'X')},
+ {(char *)"zxwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'X', 'W', 'Y')},
+ {(char *)"zxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'W', 'Z')},
+ {(char *)"zxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'W', 'W')},
+ {(char *)"zy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'Y')},
+ {(char *)"zyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'Y', 'X')},
+ {(char *)"zyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'X', 'X')},
+ {(char *)"zyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'X', 'Y')},
+ {(char *)"zyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'X', 'Z')},
+ {(char *)"zyxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'Y', 'X', 'W')},
+ {(char *)"zyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Y')},
+ {(char *)"zyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Y', 'X')},
+ {(char *)"zyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Y', 'Y')},
+ {(char *)"zyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Y', 'Z')},
+ {(char *)"zyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Y', 'W')},
+ {(char *)"zyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Z')},
+ {(char *)"zyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Z', 'X')},
+ {(char *)"zyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Z', 'Y')},
+ {(char *)"zyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Z', 'Z')},
+ {(char *)"zyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Z', 'W')},
+ {(char *)"zyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'Y', 'W')},
+ {(char *)"zywx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'Y', 'W', 'X')},
+ {(char *)"zywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'W', 'Y')},
+ {(char *)"zywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'W', 'Z')},
+ {(char *)"zyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'W', 'W')},
+ {(char *)"zz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z')},
+ {(char *)"zzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'X')},
+ {(char *)"zzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'X', 'X')},
+ {(char *)"zzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'X', 'Y')},
+ {(char *)"zzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'X', 'Z')},
+ {(char *)"zzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'X', 'W')},
+ {(char *)"zzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Y')},
+ {(char *)"zzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Y', 'X')},
+ {(char *)"zzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Y', 'Y')},
+ {(char *)"zzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Y', 'Z')},
+ {(char *)"zzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Y', 'W')},
+ {(char *)"zzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Z')},
+ {(char *)"zzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Z', 'X')},
+ {(char *)"zzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Z', 'Y')},
+ {(char *)"zzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Z', 'Z')},
+ {(char *)"zzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Z', 'W')},
+ {(char *)"zzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'W')},
+ {(char *)"zzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'W', 'X')},
+ {(char *)"zzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'W', 'Y')},
+ {(char *)"zzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'W', 'Z')},
+ {(char *)"zzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'W', 'W')},
+ {(char *)"zw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'W')},
+ {(char *)"zwx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'W', 'X')},
+ {(char *)"zwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'X', 'X')},
+ {(char *)"zwxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'W', 'X', 'Y')},
+ {(char *)"zwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'X', 'Z')},
+ {(char *)"zwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'X', 'W')},
+ {(char *)"zwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'W', 'Y')},
+ {(char *)"zwyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'W', 'Y', 'X')},
+ {(char *)"zwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Y', 'Y')},
+ {(char *)"zwyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Y', 'Z')},
+ {(char *)"zwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Y', 'W')},
+ {(char *)"zwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Z')},
+ {(char *)"zwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Z', 'X')},
+ {(char *)"zwzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Z', 'Y')},
+ {(char *)"zwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Z', 'Z')},
+ {(char *)"zwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Z', 'W')},
+ {(char *)"zww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'W')},
+ {(char *)"zwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'W', 'X')},
+ {(char *)"zwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'W', 'Y')},
+ {(char *)"zwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'W', 'Z')},
+ {(char *)"zwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'W', 'W')},
+ {(char *)"wx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'X')},
+ {(char *)"wxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'X')},
+ {(char *)"wxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'X', 'X')},
+ {(char *)"wxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'X', 'Y')},
+ {(char *)"wxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'X', 'Z')},
+ {(char *)"wxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'X', 'W')},
+ {(char *)"wxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'X', 'Y')},
+ {(char *)"wxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Y', 'X')},
+ {(char *)"wxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Y', 'Y')},
+ {(char *)"wxyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'X', 'Y', 'Z')},
+ {(char *)"wxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Y', 'W')},
+ {(char *)"wxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'X', 'Z')},
+ {(char *)"wxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Z', 'X')},
+ {(char *)"wxzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'X', 'Z', 'Y')},
+ {(char *)"wxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Z', 'Z')},
+ {(char *)"wxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Z', 'W')},
+ {(char *)"wxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'W')},
+ {(char *)"wxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'W', 'X')},
+ {(char *)"wxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'W', 'Y')},
+ {(char *)"wxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'W', 'Z')},
+ {(char *)"wxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'W', 'W')},
+ {(char *)"wy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Y')},
+ {(char *)"wyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Y', 'X')},
+ {(char *)"wyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'X', 'X')},
+ {(char *)"wyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'X', 'Y')},
+ {(char *)"wyxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Y', 'X', 'Z')},
+ {(char *)"wyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'X', 'W')},
+ {(char *)"wyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Y')},
+ {(char *)"wyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Y', 'X')},
+ {(char *)"wyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Y', 'Y')},
+ {(char *)"wyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Y', 'Z')},
+ {(char *)"wyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Y', 'W')},
+ {(char *)"wyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Y', 'Z')},
+ {(char *)"wyzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Y', 'Z', 'X')},
+ {(char *)"wyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Z', 'Y')},
+ {(char *)"wyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Z', 'Z')},
+ {(char *)"wyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Z', 'W')},
+ {(char *)"wyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'W')},
+ {(char *)"wywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'W', 'X')},
+ {(char *)"wywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'W', 'Y')},
+ {(char *)"wywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'W', 'Z')},
+ {(char *)"wyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'W', 'W')},
+ {(char *)"wz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Z')},
+ {(char *)"wzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Z', 'X')},
+ {(char *)"wzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'X', 'X')},
+ {(char *)"wzxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Z', 'X', 'Y')},
+ {(char *)"wzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'X', 'Z')},
+ {(char *)"wzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'X', 'W')},
+ {(char *)"wzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Z', 'Y')},
+ {(char *)"wzyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Z', 'Y', 'X')},
+ {(char *)"wzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Y', 'Y')},
+ {(char *)"wzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Y', 'Z')},
+ {(char *)"wzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Y', 'W')},
+ {(char *)"wzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Z')},
+ {(char *)"wzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Z', 'X')},
+ {(char *)"wzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Z', 'Y')},
+ {(char *)"wzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Z', 'Z')},
+ {(char *)"wzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Z', 'W')},
+ {(char *)"wzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'W')},
+ {(char *)"wzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'W', 'X')},
+ {(char *)"wzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'W', 'Y')},
+ {(char *)"wzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'W', 'Z')},
+ {(char *)"wzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'W', 'W')},
+ {(char *)"ww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W')},
+ {(char *)"wwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'X')},
+ {(char *)"wwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'X', 'X')},
+ {(char *)"wwxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'X', 'Y')},
+ {(char *)"wwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'X', 'Z')},
+ {(char *)"wwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'X', 'W')},
+ {(char *)"wwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Y')},
+ {(char *)"wwyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Y', 'X')},
+ {(char *)"wwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Y', 'Y')},
+ {(char *)"wwyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Y', 'Z')},
+ {(char *)"wwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Y', 'W')},
+ {(char *)"wwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Z')},
+ {(char *)"wwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Z', 'X')},
+ {(char *)"wwzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Z', 'Y')},
+ {(char *)"wwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Z', 'Z')},
+ {(char *)"wwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Z', 'W')},
+ {(char *)"www", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'W')},
+ {(char *)"wwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'W', 'X')},
+ {(char *)"wwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'W', 'Y')},
+ {(char *)"wwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'W', 'Z')},
+ {(char *)"wwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'W', 'W')},
+
+#undef AXIS_FROM_CHAR
+#undef SWIZZLE
+#undef _VA_SWIZZLE_1
+#undef _VA_SWIZZLE_2
+#undef _VA_SWIZZLE_3
+#undef _VA_SWIZZLE_4
+
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
-/* Python script used to make swizzle array */
-/*
-SWIZZLE_BITS_PER_AXIS = 3
-SWIZZLE_VALID_AXIS = 0x4
-
-axis_dict = {}
-axis_pos = {'x':0, 'y':1, 'z':2, 'w':3}
-axises = 'xyzw'
-while len(axises) >= 2:
-
- for axis_0 in axises:
- axis_0_pos = axis_pos[axis_0]
- for axis_1 in axises:
- axis_1_pos = axis_pos[axis_1]
- axis_dict[axis_0 + axis_1] = '((%s|SWIZZLE_VALID_AXIS) | ((%s|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS))' % (axis_0_pos, axis_1_pos)
- if len(axises)>2:
- for axis_2 in axises:
- axis_2_pos = axis_pos[axis_2]
- axis_dict[axis_0 + axis_1 + axis_2] = '((%s|SWIZZLE_VALID_AXIS) | ((%s|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((%s|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS * 2)))' % (axis_0_pos, axis_1_pos, axis_2_pos)
- if len(axises)>3:
- for axis_3 in axises:
- axis_3_pos = axis_pos[axis_3]
- axis_dict[axis_0 + axis_1 + axis_2 + axis_3] = '((%s|SWIZZLE_VALID_AXIS) | ((%s|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((%s|SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ((%s|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS * 3))) ' % (axis_0_pos, axis_1_pos, axis_2_pos, axis_3_pos)
-
- axises = axises[:-1]
-
-
-items = axis_dict.items()
-items.sort(key = lambda a: a[0].replace('x', '0').replace('y', '1').replace('z', '2').replace('w', '3'))
-
-unique = set()
-for key, val in items:
- num = eval(val)
- set_str = 'Vector_setSwizzle' if (len(set(key)) == len(key)) else 'NULL'
- print '\t{"%s", %s(getter)Vector_getSwizzle, (setter)%s, NULL, SET_INT_IN_POINTER(%s)}, // %s' % (key, (' '*(4 - len(key))), set_str, axis_dict[key], num)
- unique.add(num)
-
-if len(unique) != len(items):
- print "ERROR"
-*/
+/**
+ * Python script used to make swizzle array:
+ *
+ * \code{.py}
+ * SWIZZLE_BITS_PER_AXIS = 3
+ * SWIZZLE_VALID_AXIS = 0x4
+ *
+ * axis_dict = {}
+ * axis_pos = {'x': 0, 'y': 1, 'z': 2, 'w': 3}
+ * axises = 'xyzw'
+ * while len(axises) >= 2:
+ * for axis_0 in axises:
+ * axis_0_pos = axis_pos[axis_0]
+ * for axis_1 in axises:
+ * axis_1_pos = axis_pos[axis_1]
+ * axis_dict[axis_0 + axis_1] = (
+ * '((%s | SWIZZLE_VALID_AXIS) | '
+ * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS))' %
+ * (axis_0_pos, axis_1_pos))
+ * if len(axises) > 2:
+ * for axis_2 in axises:
+ * axis_2_pos = axis_pos[axis_2]
+ * axis_dict[axis_0 + axis_1 + axis_2] = (
+ * '((%s | SWIZZLE_VALID_AXIS) | '
+ * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | '
+ * '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)))' %
+ * (axis_0_pos, axis_1_pos, axis_2_pos))
+ * if len(axises) > 3:
+ * for axis_3 in axises:
+ * axis_3_pos = axis_pos[axis_3]
+ * axis_dict[axis_0 + axis_1 + axis_2 + axis_3] = (
+ * '((%s | SWIZZLE_VALID_AXIS) | '
+ * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | '
+ * '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | '
+ * '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) ' %
+ * (axis_0_pos, axis_1_pos, axis_2_pos, axis_3_pos))
+ *
+ * axises = axises[:-1]
+ *
+ *
+ * items = list(axis_dict.items())
+ * items.sort(key=lambda a: a[0].replace('x', '0').replace('y', '1').replace('z', '2').replace('w', '3'))
+ *
+ * unique = set()
+ * for key, val in items:
+ * num = eval(val)
+ * set_str = 'Vector_swizzle_set' if (len(set(key)) == len(key)) else 'NULL'
+ * key_args = ', '.join(["'%s'" % c for c in key.upper()])
+ * print('\t{(char *)"%s", %s(getter)Vector_swizzle_get, (setter)%s, NULL, SWIZZLE(%s)},' %
+ * (key, (' ' * (4 - len(key))), set_str, key_args))
+ * unique.add(num)
+ *
+ * if len(unique) != len(items):
+ * print("ERROR, duplicate values found")
+ * \endcode
+ */
/* ROW VECTOR Multiplication - Vector X Matrix
* [x][y][z] * [1][4][7]
diff --git a/source/blender/quicktime/apple/qtkit_import.m b/source/blender/quicktime/apple/qtkit_import.m
index d42d0ee8ebb..ba7ee0a8936 100644
--- a/source/blender/quicktime/apple/qtkit_import.m
+++ b/source/blender/quicktime/apple/qtkit_import.m
@@ -200,7 +200,7 @@ static ImBuf *nsImageToiBuf(NSImage *sourceImage, int width, int height)
/* Convert the image in a RGBA 32bit format */
/* As Core Graphics does not support contextes with non premutliplied alpha,
- we need to get alpha key values in a separate batch */
+ * we need to get alpha key values in a separate batch */
/* First get RGB values w/o Alpha to avoid pre-multiplication, 32bit but last byte is unused */
blBitmapFormatImageRGB = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h
index ce0691b7632..7021477a702 100644
--- a/source/blender/render/extern/include/RE_pipeline.h
+++ b/source/blender/render/extern/include/RE_pipeline.h
@@ -48,7 +48,6 @@ struct ReportList;
struct Scene;
struct SceneRenderLayer;
struct EnvMap;
-struct RenderResult;
struct StampData;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
@@ -231,12 +230,16 @@ struct RenderStats *RE_GetStats(struct Render *re);
void RE_ResultGet32(struct Render *re, unsigned int *rect);
void RE_AcquiredResultGet32(struct Render *re, struct RenderResult *result, unsigned int *rect, const int view_id);
-void RE_render_result_rect_from_ibuf(struct RenderResult *rr, struct RenderData *rd,
- struct ImBuf *ibuf, const int view_id);
+void RE_render_result_rect_from_ibuf(
+ struct RenderResult *rr, struct RenderData *rd,
+ struct ImBuf *ibuf, const int view_id);
struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name);
float *RE_RenderLayerGetPass(volatile struct RenderLayer *rl, int passtype, const char *viewname);
+/* add passes for grease pencil */
+struct RenderPass *RE_create_gp_pass(struct RenderResult *rr, const char *layername, const char *viewname);
+
/* obligatory initialize call, disprect is optional */
void RE_InitState(struct Render *re, struct Render *source, struct RenderData *rd,
struct SceneRenderLayer *srl,
@@ -249,8 +252,8 @@ struct Object *RE_GetCamera(struct Render *re); /* return camera override if set
void RE_SetOverrideCamera(struct Render *re, struct Object *camera);
void RE_SetCamera(struct Render *re, struct Object *camera);
void RE_SetEnvmapCamera(struct Render *re, struct Object *cam_ob, float viewscale, float clipsta, float clipend);
-void RE_SetWindow(struct Render *re, rctf *viewplane, float clipsta, float clipend);
-void RE_SetOrtho(struct Render *re, rctf *viewplane, float clipsta, float clipend);
+void RE_SetWindow(struct Render *re, const rctf *viewplane, float clipsta, float clipend);
+void RE_SetOrtho(struct Render *re, const rctf *viewplane, float clipsta, float clipend);
void RE_SetPixelSize(struct Render *re, float pixsize);
/* option to set viewmatrix before making dbase */
@@ -258,10 +261,12 @@ void RE_SetView(struct Render *re, float mat[4][4]);
/* get current view and window transform */
void RE_GetView(struct Render *re, float mat[4][4]);
-void RE_GetViewPlane(struct Render *re, rctf *viewplane, rcti *disprect);
+void RE_GetViewPlane(struct Render *re, rctf *r_viewplane, rcti *r_disprect);
/* make or free the dbase */
-void RE_Database_FromScene(struct Render *re, struct Main *bmain, struct Scene *scene, unsigned int lay, int use_camera_view);
+void RE_Database_FromScene(
+ struct Render *re, struct Main *bmain, struct Scene *scene,
+ unsigned int lay, int use_camera_view);
void RE_Database_Preprocess(struct Render *re);
void RE_Database_Free(struct Render *re);
@@ -304,11 +309,16 @@ void RE_SetReports(struct Render *re, struct ReportList *reports);
void RE_PreviewRender(struct Render *re, struct Main *bmain, struct Scene *scene);
bool RE_ReadRenderResult(struct Scene *scene, struct Scene *scenode);
-bool RE_WriteRenderResult(struct ReportList *reports, RenderResult *rr, const char *filename, struct ImageFormatData *imf, const bool multiview, const char *view);
-struct RenderResult *RE_MultilayerConvert(void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty);
+bool RE_WriteRenderResult(
+ struct ReportList *reports, RenderResult *rr, const char *filename,
+ struct ImageFormatData *imf, const bool multiview, const char *view);
+struct RenderResult *RE_MultilayerConvert(
+ void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty);
extern const float default_envmap_layout[];
-bool RE_WriteEnvmapResult(struct ReportList *reports, struct Scene *scene, struct EnvMap *env, const char *relpath, const char imtype, float layout[12]);
+bool RE_WriteEnvmapResult(
+ struct ReportList *reports, struct Scene *scene, struct EnvMap *env,
+ const char *relpath, const char imtype, float layout[12]);
/* do a full sample buffer compo */
void RE_MergeFullSample(struct Render *re, struct Main *bmain, struct Scene *sce, struct bNodeTree *ntree);
@@ -326,7 +336,9 @@ void RE_current_scene_update_cb(struct Render *re, void *handle, void (*f)(void
/* should move to kernel once... still unsure on how/where */
float RE_filter_value(int type, float x);
/* vector blur zbuffer method */
-void RE_zbuf_accumulate_vecblur(struct NodeBlurData *nbd, int xsize, int ysize, float *newrect, float *imgrect, float *vecbufrect, float *zbufrect);
+void RE_zbuf_accumulate_vecblur(
+ struct NodeBlurData *nbd, int xsize, int ysize, float *newrect,
+ const float *imgrect, float *vecbufrect, const float *zbufrect);
int RE_seq_render_active(struct Scene *scene, struct RenderData *rd);
@@ -351,7 +363,9 @@ struct RenderPass *RE_pass_find_by_type(volatile struct RenderLayer *rl, int pas
#define RE_BAKE_DERIVATIVE 13
#define RE_BAKE_VERTEX_COLORS 14
-void RE_Database_Baking(struct Render *re, struct Main *bmain, struct Scene *scene, unsigned int lay, const int type, struct Object *actob);
+void RE_Database_Baking(
+ struct Render *re, struct Main *bmain, struct Scene *scene,
+ unsigned int lay, const int type, struct Object *actob);
void RE_DataBase_GetView(struct Render *re, float mat[4][4]);
void RE_GetCameraWindow(struct Render *re, struct Object *camera, int frame, float mat[4][4]);
@@ -377,6 +391,8 @@ bool RE_RenderResult_is_stereo(RenderResult *res);
struct RenderView *RE_RenderViewGetById(struct RenderResult *res, const int view_id);
struct RenderView *RE_RenderViewGetByName(struct RenderResult *res, const char *viewname);
+RenderResult *RE_DuplicateRenderResult(RenderResult *rr);
+
/******* Debug pass helper functions *********/
#ifdef WITH_CYCLES_DEBUG
diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h
index 8b6dfb88b73..73867de6b2e 100644
--- a/source/blender/render/extern/include/RE_shader_ext.h
+++ b/source/blender/render/extern/include/RE_shader_ext.h
@@ -172,6 +172,7 @@ typedef struct ShadeInput {
/* from initialize, part or renderlayer */
bool do_preview; /* for nodes, in previewrender */
bool do_manage; /* color management flag */
+ bool use_world_space_shading;
short thread, sample; /* sample: ShadeSample array index */
short nodes; /* indicate node shading, temp hack to prevent recursion */
diff --git a/source/blender/render/intern/include/pixelblending.h b/source/blender/render/intern/include/pixelblending.h
index 19759bf3e97..17a872a0676 100644
--- a/source/blender/render/intern/include/pixelblending.h
+++ b/source/blender/render/intern/include/pixelblending.h
@@ -38,7 +38,7 @@
*/
void add_filt_fmask(unsigned int mask, const float col[4], float *rowbuf, int row_w);
void add_filt_fmask_pixsize(unsigned int mask, float *in, float *rowbuf, int row_w, int pixsize);
-void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, int row_w, int col_h, int x, int y);
+void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, int row_stride, int x, int y, rcti *mask);
void mask_array(unsigned int mask, float filt[3][3]);
/**
diff --git a/source/blender/render/intern/include/rayintersection.h b/source/blender/render/intern/include/rayintersection.h
index 3607e66a237..1935e4ef59c 100644
--- a/source/blender/render/intern/include/rayintersection.h
+++ b/source/blender/render/intern/include/rayintersection.h
@@ -38,6 +38,8 @@
extern "C" {
#endif
+#include "BLI_math_geom.h"
+
struct RayObject;
/* Ray Hints */
@@ -101,6 +103,9 @@ typedef struct Isect {
#ifdef RE_RAYCOUNTER
RayCounter *raycounter;
#endif
+
+ /* Precalculated coefficients for watertight intersection check. */
+ struct IsectRayPrecalc isect_precalc;
} Isect;
/* ray types */
diff --git a/source/blender/render/intern/include/render_result.h b/source/blender/render/intern/include/render_result.h
index 2619ac76d59..0c4f4e20325 100644
--- a/source/blender/render/intern/include/render_result.h
+++ b/source/blender/render/intern/include/render_result.h
@@ -83,6 +83,9 @@ void render_result_save_empty_result_tiles(struct Render *re);
void render_result_exr_file_begin(struct Render *re);
void render_result_exr_file_end(struct Render *re);
+/* render pass wrapper for gpencil */
+struct RenderPass *gp_add_pass(struct RenderResult *rr, struct RenderLayer *rl, int channels, int passtype, const char *viewname);
+
void render_result_exr_file_merge(struct RenderResult *rr, struct RenderResult *rrpart, const char *viewname);
void render_result_exr_file_path(struct Scene *scene, const char *layname, int sample, char *filepath);
diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h
index 6de5da3795a..b3a5ccdae17 100644
--- a/source/blender/render/intern/include/render_types.h
+++ b/source/blender/render/intern/include/render_types.h
@@ -180,6 +180,7 @@ struct Render {
float jit[32][2];
float mblur_jit[32][2];
ListBase *qmcsamplers;
+ int num_qmc_samplers;
/* shadow counter, detect shadow-reuse for shaders */
int shadowsamplenr[BLENDER_MAX_THREADS];
diff --git a/source/blender/render/intern/include/rendercore.h b/source/blender/render/intern/include/rendercore.h
index 308903c6c6d..7254fd25ee6 100644
--- a/source/blender/render/intern/include/rendercore.h
+++ b/source/blender/render/intern/include/rendercore.h
@@ -90,7 +90,7 @@ extern void ray_shadow(ShadeInput *shi, LampRen *lar, float shadfac[4]);
extern void ray_trace(ShadeInput *shi, ShadeResult *);
extern void ray_ao(ShadeInput *shi, float ao[3], float env[3]);
extern void init_jitter_plane(LampRen *lar);
-extern void init_ao_sphere(struct World *wrld);
+extern void init_ao_sphere(Render *re, struct World *wrld);
extern void init_render_qmcsampler(Render *re);
extern void free_render_qmcsampler(Render *re);
diff --git a/source/blender/render/intern/raytrace/rayobject.cpp b/source/blender/render/intern/raytrace/rayobject.cpp
index de6b9139363..c16ef5500df 100644
--- a/source/blender/render/intern/raytrace/rayobject.cpp
+++ b/source/blender/render/intern/raytrace/rayobject.cpp
@@ -138,80 +138,94 @@ MALWAYS_INLINE int vlr_check_bake(Isect *is, ObjectInstanceRen *obi, VlakRen *UN
/* Ray Triangle/Quad Intersection */
-MALWAYS_INLINE int isec_tri_quad(float start[3], float dir[3], RayFace *face, float uv[2], float *lambda)
+static bool isect_ray_tri_watertight_no_sign_check_v3(
+ const float ray_origin[3], const struct IsectRayPrecalc *isect_precalc,
+ const float v0[3], const float v1[3], const float v2[3],
+ float *r_lambda, float r_uv[2])
{
- float co1[3], co2[3], co3[3], co4[3];
- float t0[3], t1[3], x[3], r[3], m[3], u, v, divdet, det1, l;
- int quad;
-
- quad = RE_rayface_isQuad(face);
-
- copy_v3_v3(co1, face->v1);
- copy_v3_v3(co2, face->v2);
- copy_v3_v3(co3, face->v3);
-
- copy_v3_v3(r, dir);
-
- /* intersect triangle */
- sub_v3_v3v3(t0, co3, co2);
- sub_v3_v3v3(t1, co3, co1);
-
- cross_v3_v3v3(x, r, t1);
- divdet = dot_v3v3(t0, x);
-
- sub_v3_v3v3(m, start, co3);
- det1 = dot_v3v3(m, x);
-
- if (divdet != 0.0f) {
- divdet = 1.0f / divdet;
- v = det1 * divdet;
-
- if (v < RE_RAYTRACE_EPSILON && v > -(1.0f + RE_RAYTRACE_EPSILON)) {
- float cros[3];
-
- cross_v3_v3v3(cros, m, t0);
- u = divdet * dot_v3v3(cros, r);
+ const int kx = isect_precalc->kx;
+ const int ky = isect_precalc->ky;
+ const int kz = isect_precalc->kz;
+ const float sx = isect_precalc->sx;
+ const float sy = isect_precalc->sy;
+ const float sz = isect_precalc->sz;
+
+ /* Calculate vertices relative to ray origin. */
+ const float a[3] = {v0[0] - ray_origin[0], v0[1] - ray_origin[1], v0[2] - ray_origin[2]};
+ const float b[3] = {v1[0] - ray_origin[0], v1[1] - ray_origin[1], v1[2] - ray_origin[2]};
+ const float c[3] = {v2[0] - ray_origin[0], v2[1] - ray_origin[1], v2[2] - ray_origin[2]};
+
+ const float a_kx = a[kx], a_ky = a[ky], a_kz = a[kz];
+ const float b_kx = b[kx], b_ky = b[ky], b_kz = b[kz];
+ const float c_kx = c[kx], c_ky = c[ky], c_kz = c[kz];
+
+ /* Perform shear and scale of vertices. */
+ const float ax = a_kx - sx * a_kz;
+ const float ay = a_ky - sy * a_kz;
+ const float bx = b_kx - sx * b_kz;
+ const float by = b_ky - sy * b_kz;
+ const float cx = c_kx - sx * c_kz;
+ const float cy = c_ky - sy * c_kz;
+
+ /* Calculate scaled barycentric coordinates. */
+ const float u = cx * by - cy * bx;
+ const float v = ax * cy - ay * cx;
+ const float w = bx * ay - by * ax;
+ float det;
+
+ if ((u < 0.0f || v < 0.0f || w < 0.0f) &&
+ (u > 0.0f || v > 0.0f || w > 0.0f))
+ {
+ return false;
+ }
- if (u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f + RE_RAYTRACE_EPSILON)) {
- l = divdet * dot_v3v3(cros, t1);
+ /* Calculate determinant. */
+ det = u + v + w;
+ if (UNLIKELY(det == 0.0f)) {
+ return false;
+ }
+ else {
+ /* Calculate scaled z-coordinates of vertices and use them to calculate
+ * the hit distance.
+ */
+ const float t = (u * a_kz + v * b_kz + w * c_kz) * sz;
+ /* Normalize u, v and t. */
+ const float inv_det = 1.0f / det;
+ if (r_uv) {
+ r_uv[0] = u * inv_det;
+ r_uv[1] = v * inv_det;
+ }
+ *r_lambda = t * inv_det;
+ return true;
+ }
+}
- /* check if intersection is within ray length */
- if (l > -RE_RAYTRACE_EPSILON && l < *lambda) {
- uv[0] = u;
- uv[1] = v;
- *lambda = l;
- return 1;
- }
- }
+MALWAYS_INLINE int isec_tri_quad(const float start[3],
+ const struct IsectRayPrecalc *isect_precalc,
+ const RayFace *face,
+ float r_uv[2], float *r_lambda)
+{
+ float uv[2], l;
+
+ if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v2, face->v3, &l, uv)) {
+ /* check if intersection is within ray length */
+ if (l > -RE_RAYTRACE_EPSILON && l < *r_lambda) {
+ r_uv[0] = -uv[0];
+ r_uv[1] = -uv[1];
+ *r_lambda = l;
+ return 1;
}
}
/* intersect second triangle in quad */
- if (quad) {
- copy_v3_v3(co4, face->v4);
- sub_v3_v3v3(t0, co3, co4);
- divdet = dot_v3v3(t0, x);
-
- if (divdet != 0.0f) {
- divdet = 1.0f / divdet;
- v = det1 * divdet;
-
- if (v < RE_RAYTRACE_EPSILON && v > -(1.0f + RE_RAYTRACE_EPSILON)) {
- float cros[3];
-
- cross_v3_v3v3(cros, m, t0);
- u = divdet * dot_v3v3(cros, r);
-
- if (u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f + RE_RAYTRACE_EPSILON)) {
- l = divdet * dot_v3v3(cros, t1);
-
- if (l > -RE_RAYTRACE_EPSILON && l < *lambda) {
- uv[0] = u;
- uv[1] = -(1.0f + v + u);
- *lambda = l;
- return 2;
- }
- }
+ if (RE_rayface_isQuad(face)) {
+ if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v3, face->v4, &l, uv)) {
+ /* check if intersection is within ray length */
+ if (l > -RE_RAYTRACE_EPSILON && l < *r_lambda) {
+ r_uv[0] = -uv[0];
+ r_uv[1] = -uv[1];
+ *r_lambda = l;
+ return 2;
}
}
}
@@ -221,64 +235,26 @@ MALWAYS_INLINE int isec_tri_quad(float start[3], float dir[3], RayFace *face, fl
/* Simpler yes/no Ray Triangle/Quad Intersection */
-MALWAYS_INLINE int isec_tri_quad_neighbour(float start[3], float dir[3], RayFace *face)
+MALWAYS_INLINE int isec_tri_quad_neighbour(const float start[3],
+ const float dir[3],
+ const RayFace *face)
{
- float co1[3], co2[3], co3[3], co4[3];
- float t0[3], t1[3], x[3], r[3], m[3], u, v, divdet, det1;
- int quad;
-
- quad = RE_rayface_isQuad(face);
-
- copy_v3_v3(co1, face->v1);
- copy_v3_v3(co2, face->v2);
- copy_v3_v3(co3, face->v3);
+ float r[3];
+ struct IsectRayPrecalc isect_precalc;
+ float uv[2], l;
negate_v3_v3(r, dir); /* note, different than above function */
- /* intersect triangle */
- sub_v3_v3v3(t0, co3, co2);
- sub_v3_v3v3(t1, co3, co1);
+ isect_ray_tri_watertight_v3_precalc(&isect_precalc, r);
- cross_v3_v3v3(x, r, t1);
- divdet = dot_v3v3(t0, x);
-
- sub_v3_v3v3(m, start, co3);
- det1 = dot_v3v3(m, x);
-
- if (divdet != 0.0f) {
- divdet = 1.0f / divdet;
- v = det1 * divdet;
-
- if (v < RE_RAYTRACE_EPSILON && v > -(1.0f + RE_RAYTRACE_EPSILON)) {
- float cros[3];
-
- cross_v3_v3v3(cros, m, t0);
- u = divdet * dot_v3v3(cros, r);
-
- if (u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f + RE_RAYTRACE_EPSILON))
- return 1;
- }
+ if (isect_ray_tri_watertight_no_sign_check_v3(start, &isect_precalc, face->v1, face->v2, face->v3, &l, uv)) {
+ return 1;
}
/* intersect second triangle in quad */
- if (quad) {
- copy_v3_v3(co4, face->v4);
- sub_v3_v3v3(t0, co3, co4);
- divdet = dot_v3v3(t0, x);
-
- if (divdet != 0.0f) {
- divdet = 1.0f / divdet;
- v = det1 * divdet;
-
- if (v < RE_RAYTRACE_EPSILON && v > -(1.0f + RE_RAYTRACE_EPSILON)) {
- float cros[3];
-
- cross_v3_v3v3(cros, m, t0);
- u = divdet * dot_v3v3(cros, r);
-
- if (u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f + RE_RAYTRACE_EPSILON))
- return 2;
- }
+ if (RE_rayface_isQuad(face)) {
+ if (isect_ray_tri_watertight_no_sign_check_v3(start, &isect_precalc, face->v1, face->v3, face->v4, &l, uv)) {
+ return 2;
}
}
@@ -317,7 +293,7 @@ MALWAYS_INLINE int intersect_rayface(RayObject *hit_obj, RayFace *face, Isect *i
RE_RC_COUNT(is->raycounter->faces.test);
dist = is->dist;
- ok = isec_tri_quad(is->start, is->dir, face, uv, &dist);
+ ok = isec_tri_quad(is->start, &is->isect_precalc, face, uv, &dist);
if (ok) {
@@ -389,6 +365,9 @@ int RE_rayobject_raycast(RayObject *r, Isect *isec)
{
int i;
+ /* Pre-calculate orientation for watertight intersection checks. */
+ isect_ray_tri_watertight_v3_precalc(&isec->isect_precalc, isec->dir);
+
RE_RC_COUNT(isec->raycounter->raycast.test);
/* setup vars used on raycast */
diff --git a/source/blender/render/intern/raytrace/rayobject_instance.cpp b/source/blender/render/intern/raytrace/rayobject_instance.cpp
index d080ddcc375..349f0fc6844 100644
--- a/source/blender/render/intern/raytrace/rayobject_instance.cpp
+++ b/source/blender/render/intern/raytrace/rayobject_instance.cpp
@@ -125,6 +125,9 @@ static int RE_rayobject_instance_intersect(RayObject *o, Isect *isec)
isec->bv_index[2 * i + 1] = i + 3 * isec->bv_index[2 * i + 1];
}
+ // Pre-calculate orientation for watertight intersection checks.
+ isect_ray_tri_watertight_v3_precalc(&isec->isect_precalc, isec->dir);
+
// raycast
res = RE_rayobject_intersect(obj->target, isec);
@@ -168,6 +171,9 @@ static int RE_rayobject_instance_intersect(RayObject *o, Isect *isec)
isec->bv_index[2 * i + 1] = i + 3 * isec->bv_index[2 * i + 1];
}
+ // Pre-calculate orientation for watertight intersection checks.
+ isect_ray_tri_watertight_v3_precalc(&isec->isect_precalc, isec->dir);
+
return res;
}
diff --git a/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp b/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp
index 00c1129fa85..81e41a20f2e 100644
--- a/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp
+++ b/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp
@@ -31,10 +31,16 @@
#include <assert.h>
-#include <math.h>
#include <stdlib.h>
#include <algorithm>
+#if __cplusplus >= 201103L
+#include <cmath>
+using std::isfinite;
+#else
+#include <math.h>
+#endif
+
#include "rayobject_rtbuild.h"
#include "MEM_guardedalloc.h"
@@ -109,9 +115,9 @@ void rtbuild_add(RTBuilder *b, RayObject *o)
if (bb[0] > bb[3] || bb[1] > bb[4] || bb[2] > bb[5])
return;
/* skip objects with inf bounding boxes */
- if (!finite(bb[0]) || !finite(bb[1]) || !finite(bb[2]))
+ if (!isfinite(bb[0]) || !isfinite(bb[1]) || !isfinite(bb[2]))
return;
- if (!finite(bb[3]) || !finite(bb[4]) || !finite(bb[5]))
+ if (!isfinite(bb[3]) || !isfinite(bb[4]) || !isfinite(bb[5]))
return;
/* skip objects with zero bounding box, they are of no use, and
* will give problems in rtbuild_heuristic_object_split later */
diff --git a/source/blender/render/intern/source/bake_api.c b/source/blender/render/intern/source/bake_api.c
index 1a0ef4e64d4..73424a4e846 100644
--- a/source/blender/render/intern/source/bake_api.c
+++ b/source/blender/render/intern/source/bake_api.c
@@ -298,20 +298,16 @@ static bool cast_ray_highpoly(
}
if (hits[i].index != -1) {
- /* cull backface */
- const float dot = dot_v3v3(dir_high, hits[i].no);
- if (dot < 0.0f) {
- float distance;
- float hit_world[3];
-
- /* distance comparison in world space */
- mul_v3_m4v3(hit_world, highpoly[i].obmat, hits[i].co);
- distance = len_squared_v3v3(hit_world, co);
-
- if (distance < hit_distance) {
- hit_mesh = i;
- hit_distance = distance;
- }
+ float distance;
+ float hit_world[3];
+
+ /* distance comparison in world space */
+ mul_v3_m4v3(hit_world, highpoly[i].obmat, hits[i].co);
+ distance = len_squared_v3v3(hit_world, co);
+
+ if (distance < hit_distance) {
+ hit_mesh = i;
+ hit_distance = distance;
}
}
}
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index b6ee88de290..86961cdd169 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -1330,7 +1330,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
part=psys->part;
pars=psys->particles;
- if (part==NULL || pars==NULL || !psys_check_enabled(ob, psys))
+ if (part==NULL || pars==NULL || !psys_check_enabled(ob, psys, G.is_rendering))
return 0;
if (part->ren_as==PART_DRAW_OB || part->ren_as==PART_DRAW_GR || part->ren_as==PART_DRAW_NOT)
@@ -2816,7 +2816,7 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset)
}
}
- if (dl->bevelSplitFlag || timeoffset==0) {
+ if (dl->bevel_split || timeoffset == 0) {
const int startvlak= obr->totvlak;
for (a=0; a<dl->parts; a++) {
@@ -2856,10 +2856,15 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset)
}
}
- if (dl->bevelSplitFlag) {
- for (a=0; a<dl->parts-1+!!(dl->flag&DL_CYCL_V); a++)
- if (dl->bevelSplitFlag[a>>5]&(1<<(a&0x1F)))
- split_v_renderfaces(obr, startvlak, startvert, dl->parts, dl->nr, a, dl->flag&DL_CYCL_V, dl->flag&DL_CYCL_U);
+ if (dl->bevel_split) {
+ for (a = 0; a < dl->parts - 1 + !!(dl->flag & DL_CYCL_V); a++) {
+ if (BLI_BITMAP_TEST(dl->bevel_split, a)) {
+ split_v_renderfaces(
+ obr, startvlak, startvert, dl->parts, dl->nr, a,
+ /* intentionally swap (v, u) --> (u, v) */
+ dl->flag & DL_CYCL_V, dl->flag & DL_CYCL_U);
+ }
+ }
}
/* vertex normals */
@@ -3167,9 +3172,8 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
/* exception for tangent space baking */
if (me->mtpoly==NULL) {
need_orco= 1;
- need_tangent= 1;
}
- need_nmap_tangent_concrete = true;
+ need_tangent= 1;
}
/* check autosmooth and displacement, we then have to skip only-verts optimize
@@ -4188,7 +4192,7 @@ static void split_quads(ObjectRen *obr, int dir)
vlr= RE_findOrAddVlak(obr, a);
/* test if rendering as a quad or triangle, skip wire */
- if (vlr->v4 && (vlr->flag & R_STRAND)==0 && (vlr->mat->material_type != MA_TYPE_WIRE)) {
+ if ((vlr->flag & R_STRAND)==0 && (vlr->mat->material_type != MA_TYPE_WIRE)) {
if (vlr->v4) {
@@ -4697,7 +4701,7 @@ static void add_render_object(Render *re, Object *ob, Object *par, DupliObject *
if (ob->particlesystem.first) {
psysindex= 1;
for (psys=ob->particlesystem.first; psys; psys=psys->next, psysindex++) {
- if (!psys_check_enabled(ob, psys))
+ if (!psys_check_enabled(ob, psys, G.is_rendering))
continue;
obr= RE_addRenderObject(re, ob, par, index, psysindex, ob->lay);
@@ -5226,7 +5230,7 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l
if (re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT))
if (re->wrld.ao_samp_method == WO_AOSAMP_CONSTANT)
- init_ao_sphere(&re->wrld);
+ init_ao_sphere(re, &re->wrld);
}
/* still bad... doing all */
@@ -5952,7 +5956,7 @@ void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay,
if (re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT))
if (re->wrld.ao_samp_method == WO_AOSAMP_CONSTANT)
- init_ao_sphere(&re->wrld);
+ init_ao_sphere(re, &re->wrld);
}
/* still bad... doing all */
diff --git a/source/blender/render/intern/source/envmap.c b/source/blender/render/intern/source/envmap.c
index b1afb86e5af..d97e18d6511 100644
--- a/source/blender/render/intern/source/envmap.c
+++ b/source/blender/render/intern/source/envmap.c
@@ -52,6 +52,7 @@
#include "BKE_main.h"
#include "BKE_image.h" /* BKE_imbuf_write */
#include "BKE_texture.h"
+#include "BKE_scene.h"
/* this module */
#include "render_types.h"
@@ -737,21 +738,28 @@ int envmaptex(Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int o
/* rotate to envmap space, if object is set */
copy_v3_v3(vec, texvec);
- if (env->object) mul_m3_v3(env->obimat, vec);
- else mul_mat3_m4_v3(R.viewinv, vec);
+ if (env->object) {
+ mul_m3_v3(env->obimat, vec);
+ if (osatex) {
+ mul_m3_v3(env->obimat, dxt);
+ mul_m3_v3(env->obimat, dyt);
+ }
+ }
+ else {
+ if (!BKE_scene_use_world_space_shading(R.scene)) {
+ // texvec is in view space
+ mul_mat3_m4_v3(R.viewinv, vec);
+ if (osatex) {
+ mul_mat3_m4_v3(R.viewinv, dxt);
+ mul_mat3_m4_v3(R.viewinv, dyt);
+ }
+ }
+ }
face = envcube_isect(env, vec, sco);
ibuf = env->cube[face];
if (osatex) {
- if (env->object) {
- mul_m3_v3(env->obimat, dxt);
- mul_m3_v3(env->obimat, dyt);
- }
- else {
- mul_mat3_m4_v3(R.viewinv, dxt);
- mul_mat3_m4_v3(R.viewinv, dyt);
- }
set_dxtdyt(dxts, dyts, dxt, dyt, face);
imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, texres, pool, skip_load_image);
diff --git a/source/blender/render/intern/source/multires_bake.c b/source/blender/render/intern/source/multires_bake.c
index 8c6d9c5f951..fba5836ac32 100644
--- a/source/blender/render/intern/source/multires_bake.c
+++ b/source/blender/render/intern/source/multires_bake.c
@@ -864,8 +864,7 @@ static void apply_tangmat_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm,
lvl, lt, uv[0], uv[1], NULL, n);
mul_v3_m3v3(vec, tangmat, n);
- normalize_v3(vec);
- mul_v3_fl(vec, 0.5);
+ normalize_v3_length(vec, 0.5);
add_v3_v3(vec, tmp);
if (ibuf->rect_float) {
diff --git a/source/blender/render/intern/source/occlusion.c b/source/blender/render/intern/source/occlusion.c
index c5c3b6bbf94..b3d31e3b93a 100644
--- a/source/blender/render/intern/source/occlusion.c
+++ b/source/blender/render/intern/source/occlusion.c
@@ -115,6 +115,8 @@ typedef struct OcclusionTree {
int doindirect;
OcclusionCache *cache;
+
+ int num_threads;
} OcclusionTree;
typedef struct OcclusionThread {
@@ -641,6 +643,7 @@ static void occ_build_sh_normalize(OccNode *node)
static OcclusionTree *occ_tree_build(Render *re)
{
+ const int num_threads = re->r.threads;
OcclusionTree *tree;
ObjectInstanceRen *obi;
ObjectRen *obr;
@@ -679,7 +682,7 @@ static OcclusionTree *occ_tree_build(Render *re)
BLI_memarena_use_calloc(tree->arena);
if (re->wrld.aomode & WO_AOCACHE)
- tree->cache = MEM_callocN(sizeof(OcclusionCache) * BLENDER_MAX_THREADS, "OcclusionCache");
+ tree->cache = MEM_callocN(sizeof(OcclusionCache) * num_threads, "OcclusionCache");
tree->face = MEM_callocN(sizeof(OccFace) * totface, "OcclusionFace");
tree->co = MEM_callocN(sizeof(float) * 3 * totface, "OcclusionCo");
@@ -730,9 +733,11 @@ static OcclusionTree *occ_tree_build(Render *re)
if (!(re->test_break(re->tbh)))
occ_build_sh_normalize(tree->root);
- for (a = 0; a < BLENDER_MAX_THREADS; a++)
+ for (a = 0; a < num_threads; a++)
tree->stack[a] = MEM_callocN(sizeof(OccNode) * TOTCHILD * (tree->maxdepth + 1), "OccStack");
+ tree->num_threads = num_threads;
+
return tree;
}
@@ -742,7 +747,7 @@ static void occ_free_tree(OcclusionTree *tree)
if (tree) {
if (tree->arena) BLI_memarena_free(tree->arena);
- for (a = 0; a < BLENDER_MAX_THREADS; a++)
+ for (a = 0; a < tree->num_threads; a++)
if (tree->stack[a])
MEM_freeN(tree->stack[a]);
if (tree->occlusion) MEM_freeN(tree->occlusion);
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index c88e3b36e27..9f1ae4a96e0 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -66,6 +66,7 @@
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_library.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_node.h"
@@ -354,7 +355,7 @@ Scene *RE_GetScene(Render *re)
* Same as #RE_AcquireResultImage but creating the necessary views to store the result
* fill provided result struct with a copy of thew views of what is done so far the
* #RenderResult.views #ListBase needs to be freed after with #RE_ReleaseResultImageViews
-*/
+ */
void RE_AcquireResultImageViews(Render *re, RenderResult *rr)
{
memset(rr, 0, sizeof(RenderResult));
@@ -633,12 +634,6 @@ static int check_mode_full_sample(RenderData *rd)
#ifdef WITH_OPENEXR
if (scemode & R_FULL_SAMPLE)
scemode |= R_EXR_TILE_FILE; /* enable automatic */
-
- /* Until use_border is made compatible with save_buffers/full_sample, render without the later instead of not rendering at all.*/
- if (rd->mode & R_BORDER) {
- scemode &= ~(R_EXR_TILE_FILE | R_FULL_SAMPLE);
- }
-
#else
/* can't do this without openexr support */
scemode &= ~(R_EXR_TILE_FILE | R_FULL_SAMPLE);
@@ -727,6 +722,13 @@ void RE_InitState(Render *re, Render *source, RenderData *rd,
re->r.size = source->r.size;
}
+ /* disable border if it's a full render anyway */
+ if (re->r.border.xmin == 0.0f && re->r.border.xmax == 1.0f &&
+ re->r.border.ymin == 0.0f && re->r.border.ymax == 1.0f)
+ {
+ re->r.mode &= ~R_BORDER;
+ }
+
re_init_resolution(re, source, winx, winy, disprect);
if (re->rectx < 1 || re->recty < 1 || (BKE_imtype_is_movie(rd->im_format.imtype) &&
@@ -929,7 +931,7 @@ void render_update_anim_renderdata(Render *re, RenderData *rd)
BLI_duplicatelist(&re->r.views, &rd->views);
}
-void RE_SetWindow(Render *re, rctf *viewplane, float clipsta, float clipend)
+void RE_SetWindow(Render *re, const rctf *viewplane, float clipsta, float clipend)
{
/* re->ok flag? */
@@ -944,7 +946,7 @@ void RE_SetWindow(Render *re, rctf *viewplane, float clipsta, float clipend)
}
-void RE_SetOrtho(Render *re, rctf *viewplane, float clipsta, float clipend)
+void RE_SetOrtho(Render *re, const rctf *viewplane, float clipsta, float clipend)
{
/* re->ok flag? */
@@ -965,15 +967,17 @@ void RE_SetView(Render *re, float mat[4][4])
invert_m4_m4(re->viewinv, re->viewmat);
}
-void RE_GetViewPlane(Render *re, rctf *viewplane, rcti *disprect)
+void RE_GetViewPlane(Render *re, rctf *r_viewplane, rcti *r_disprect)
{
- *viewplane = re->viewplane;
+ *r_viewplane = re->viewplane;
/* make disprect zero when no border render, is needed to detect changes in 3d view render */
- if (re->r.mode & R_BORDER)
- *disprect = re->disprect;
- else
- BLI_rcti_init(disprect, 0, 0, 0, 0);
+ if (re->r.mode & R_BORDER) {
+ *r_disprect = re->disprect;
+ }
+ else {
+ BLI_rcti_init(r_disprect, 0, 0, 0, 0);
+ }
}
void RE_GetView(Render *re, float mat[4][4])
@@ -1828,6 +1832,53 @@ static void render_result_disprect_to_full_resolution(Render *re)
re->recty = re->winy;
}
+static void render_result_uncrop(Render *re)
+{
+ /* when using border render with crop disabled, insert render result into
+ * full size with black pixels outside */
+ if (re->result && (re->r.mode & R_BORDER)) {
+ if ((re->r.mode & R_CROP) == 0) {
+ RenderResult *rres;
+
+ /* backup */
+ const rcti orig_disprect = re->disprect;
+ const int orig_rectx = re->rectx, orig_recty = re->recty;
+
+ BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
+
+ /* sub-rect for merge call later on */
+ re->result->tilerect = re->disprect;
+
+ /* weak is: it chances disprect from border */
+ render_result_disprect_to_full_resolution(re);
+
+ rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
+
+ render_result_merge(rres, re->result);
+ render_result_free(re->result);
+ re->result = rres;
+
+ /* weak... the display callback wants an active renderlayer pointer... */
+ re->result->renlay = render_get_active_layer(re, re->result);
+
+ BLI_rw_mutex_unlock(&re->resultmutex);
+
+ re->display_init(re->dih, re->result);
+ re->display_update(re->duh, re->result, NULL);
+
+ /* restore the disprect from border */
+ re->disprect = orig_disprect;
+ re->rectx = orig_rectx;
+ re->recty = orig_recty;
+ }
+ else {
+ /* set offset (again) for use in compositor, disprect was manipulated. */
+ re->result->xof = 0;
+ re->result->yof = 0;
+ }
+ }
+}
+
/* main render routine, no compositing */
static void do_render_fields_blur_3d(Render *re)
{
@@ -1850,49 +1901,7 @@ static void do_render_fields_blur_3d(Render *re)
do_render_3d(re);
/* when border render, check if we have to insert it in black */
- if (re->result) {
- if (re->r.mode & R_BORDER) {
- if ((re->r.mode & R_CROP) == 0) {
- RenderResult *rres;
-
- /* backup */
- const rcti orig_disprect = re->disprect;
- const int orig_rectx = re->rectx, orig_recty = re->recty;
-
- BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
-
- /* sub-rect for merge call later on */
- re->result->tilerect = re->disprect;
-
- /* weak is: it chances disprect from border */
- render_result_disprect_to_full_resolution(re);
-
- rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
-
- render_result_merge(rres, re->result);
- render_result_free(re->result);
- re->result = rres;
-
- /* weak... the display callback wants an active renderlayer pointer... */
- re->result->renlay = render_get_active_layer(re, re->result);
-
- BLI_rw_mutex_unlock(&re->resultmutex);
-
- re->display_init(re->dih, re->result);
- re->display_update(re->duh, re->result, NULL);
-
- /* restore the disprect from border */
- re->disprect = orig_disprect;
- re->rectx = orig_rectx;
- re->recty = orig_recty;
- }
- else {
- /* set offset (again) for use in compositor, disprect was manipulated. */
- re->result->xof = 0;
- re->result->yof = 0;
- }
- }
- }
+ render_result_uncrop(re);
}
@@ -2177,12 +2186,12 @@ static void init_freestyle(Render *re)
re->freestyle_bmain = BKE_main_new();
/* We use the same window manager for freestyle bmain as
- * real bmain uses. This is needed because freestyle's
- * bmain could be used to tag scenes for update, which
- * implies call of ED_render_scene_update in some cases
- * and that function requires proper window manager
- * to present (sergey)
- */
+ * real bmain uses. This is needed because freestyle's
+ * bmain could be used to tag scenes for update, which
+ * implies call of ED_render_scene_update in some cases
+ * and that function requires proper window manager
+ * to present (sergey)
+ */
re->freestyle_bmain->wm = re->main->wm;
FRS_init_stroke_renderer(re);
@@ -2267,7 +2276,8 @@ static void free_all_freestyle_renders(void)
if (freestyle_render) {
freestyle_scene = freestyle_render->scene;
RE_FreeRender(freestyle_render);
- BKE_scene_unlink(re1->freestyle_bmain, freestyle_scene, NULL);
+ BKE_libblock_unlink(re1->freestyle_bmain, freestyle_scene, false, false);
+ BKE_libblock_free(re1->freestyle_bmain, freestyle_scene);
}
}
BLI_freelistN(&re1->freestyle_renders);
@@ -2290,6 +2300,7 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree)
{
ListBase *rectfs;
RenderView *rv;
+ rcti filter_mask = re->disprect;
float *rectf, filt[3][3];
int x, y, sample;
int nr, numviews;
@@ -2315,7 +2326,7 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree)
rv = MEM_callocN(sizeof(RenderView), "fullsample renderview");
/* we accumulate in here */
- rv->rectf = MEM_mapallocN(re->rectx * re->recty * sizeof(float) * 4, "fullsample rgba");
+ rv->rectf = MEM_mapallocN(re->result->rectx * re->result->recty * sizeof(float) * 4, "fullsample rgba");
BLI_addtail(rectfs, rv);
}
@@ -2345,6 +2356,7 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree)
composite_freestyle_renders(re1, sample);
#endif
BLI_rw_mutex_unlock(&re->resultmutex);
+ render_result_uncrop(re1);
}
ntreeCompositTagRender(re1->scene); /* ensure node gets exec to put buffers on stack */
}
@@ -2371,17 +2383,17 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree)
mask = (1 << sample);
mask_array(mask, filt);
- for (y = 0; y < re->recty; y++) {
- float *rf = rectf + 4 * y * re->rectx;
- float *col = rres.rectf + 4 * y * re->rectx;
+ for (y = 0; y < re->result->recty; y++) {
+ float *rf = rectf + 4 * y * re->result->rectx;
+ float *col = rres.rectf + 4 * y * re->result->rectx;
- for (x = 0; x < re->rectx; x++, rf += 4, col += 4) {
+ for (x = 0; x < re->result->rectx; x++, rf += 4, col += 4) {
/* clamping to 1.0 is needed for correct AA */
CLAMP(col[0], 0.0f, 1.0f);
CLAMP(col[1], 0.0f, 1.0f);
CLAMP(col[2], 0.0f, 1.0f);
- add_filt_fmask_coord(filt, col, rf, re->rectx, re->recty, x, y);
+ add_filt_fmask_coord(filt, col, rf, re->result->rectx, x, y, &filter_mask);
}
}
@@ -2401,10 +2413,10 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree)
rectf = ((RenderView *)BLI_findlink(rectfs, nr))->rectf;
/* clamp alpha and RGB to 0..1 and 0..inf, can go outside due to filter */
- for (y = 0; y < re->recty; y++) {
- float *rf = rectf + 4 * y * re->rectx;
+ for (y = 0; y < re->result->recty; y++) {
+ float *rf = rectf + 4 * y * re->result->rectx;
- for (x = 0; x < re->rectx; x++, rf += 4) {
+ for (x = 0; x < re->result->rectx; x++, rf += 4) {
rf[0] = MAX2(rf[0], 0.0f);
rf[1] = MAX2(rf[1], 0.0f);
rf[2] = MAX2(rf[2], 0.0f);
@@ -2773,6 +2785,7 @@ static void do_render_all_options(Render *re)
/* ensure no images are in memory from previous animated sequences */
BKE_image_all_free_anim_ibufs(re->r.cfra);
+ BKE_sequencer_all_free_anim_ibufs(re->r.cfra);
if (RE_engine_render(re, 1)) {
/* in this case external render overrides all */
@@ -3046,6 +3059,13 @@ bool RE_is_rendering_allowed(Scene *scene, Object *camera_override, ReportList *
}
#endif
+ if (RE_seq_render_active(scene, &scene->r)) {
+ if (scene->r.mode & R_BORDER) {
+ BKE_report(reports, RPT_ERROR, "Border rendering is not supported by sequencer");
+ return false;
+ }
+ }
+
/* layer flag tests */
if (!render_scene_has_layers_to_render(scene)) {
BKE_report(reports, RPT_ERROR, "All render layers are disabled");
@@ -3845,6 +3865,8 @@ bool RE_ReadRenderResult(Scene *scene, Scene *scenode)
success = render_result_exr_file_cache_read(re);
BLI_rw_mutex_unlock(&re->resultmutex);
+ render_result_uncrop(re);
+
return success;
}
@@ -4004,3 +4026,31 @@ RenderPass *RE_pass_find_by_type(volatile RenderLayer *rl, int passtype, const c
}
return rp;
}
+
+/* create a renderlayer and renderpass for grease pencil layer */
+RenderPass *RE_create_gp_pass(RenderResult *rr, const char *layername, const char *viewname)
+{
+ RenderLayer *rl = BLI_findstring(&rr->layers, layername, offsetof(RenderLayer, name));
+ /* only create render layer if not exist */
+ if (!rl) {
+ rl = MEM_callocN(sizeof(RenderLayer), layername);
+ BLI_addtail(&rr->layers, rl);
+ BLI_strncpy(rl->name, layername, sizeof(rl->name));
+ rl->lay = 0;
+ rl->layflag = SCE_LAY_SOLID;
+ rl->passflag = SCE_PASS_COMBINED;
+ rl->rectx = rr->rectx;
+ rl->recty = rr->recty;
+ }
+
+ /* clear previous pass if exist or the new image will be over previous one*/
+ RenderPass *rp = RE_pass_find_by_type(rl, SCE_PASS_COMBINED, viewname);
+ if (rp) {
+ if (rp->rect) {
+ MEM_freeN(rp->rect);
+ }
+ BLI_freelinkN(&rl->passes, rp);
+ }
+ /* create a totally new pass */
+ return gp_add_pass(rr, rl, 4, SCE_PASS_COMBINED, viewname);
+}
diff --git a/source/blender/render/intern/source/pixelblending.c b/source/blender/render/intern/source/pixelblending.c
index 32fb196e1f3..fc79786e5c7 100644
--- a/source/blender/render/intern/source/pixelblending.c
+++ b/source/blender/render/intern/source/pixelblending.c
@@ -240,7 +240,7 @@ void mask_array(unsigned int mask, float filt[3][3])
* </pre>
*/
-void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, int row_w, int col_h, int x, int y)
+void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, int row_stride, int x, int y, rcti *mask)
{
float *fpoin[3][3];
float val, r, g, b, al, lfilt[3][3];
@@ -252,9 +252,9 @@ void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, i
memcpy(lfilt, filt, sizeof(lfilt));
- fpoin[0][1] = rowbuf - 4 * row_w;
+ fpoin[0][1] = rowbuf - 4 * row_stride;
fpoin[1][1] = rowbuf;
- fpoin[2][1] = rowbuf + 4 * row_w;
+ fpoin[2][1] = rowbuf + 4 * row_stride;
fpoin[0][0] = fpoin[0][1] - 4;
fpoin[1][0] = fpoin[1][1] - 4;
@@ -264,7 +264,9 @@ void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, i
fpoin[1][2] = fpoin[1][1] + 4;
fpoin[2][2] = fpoin[2][1] + 4;
- if (y == 0) {
+ /* limit filtering to withing a mask for border rendering, so pixels don't
+ * leak outside of the border */
+ if (y <= mask->ymin) {
fpoin[0][0] = fpoin[1][0];
fpoin[0][1] = fpoin[1][1];
fpoin[0][2] = fpoin[1][2];
@@ -273,7 +275,7 @@ void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, i
lfilt[0][1] = filt[2][1];
lfilt[0][2] = filt[2][2];
}
- else if (y == col_h - 1) {
+ else if (y >= mask->ymax - 1) {
fpoin[2][0] = fpoin[1][0];
fpoin[2][1] = fpoin[1][1];
fpoin[2][2] = fpoin[1][2];
@@ -283,7 +285,7 @@ void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, i
lfilt[2][2] = filt[0][2];
}
- if (x == 0) {
+ if (x <= mask->xmin) {
fpoin[2][0] = fpoin[2][1];
fpoin[1][0] = fpoin[1][1];
fpoin[0][0] = fpoin[0][1];
@@ -292,7 +294,7 @@ void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, i
lfilt[1][0] = filt[1][2];
lfilt[0][0] = filt[0][2];
}
- else if (x == row_w - 1) {
+ else if (x >= mask->xmax - 1) {
fpoin[2][2] = fpoin[2][1];
fpoin[1][2] = fpoin[1][1];
fpoin[0][2] = fpoin[0][1];
diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c
index 59aaad661c9..a03ea9cb896 100644
--- a/source/blender/render/intern/source/pointdensity.c
+++ b/source/blender/render/intern/source/pointdensity.c
@@ -211,7 +211,7 @@ static void pointdensity_cache_psys(Scene *scene,
CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL);
}
- if (!psys_check_enabled(ob, psys)) {
+ if (!psys_check_enabled(ob, psys, use_render_params)) {
psys_render_restore(ob, psys);
return;
}
@@ -333,7 +333,16 @@ static void pointdensity_cache_vertex_color(PointDensity *pd, Object *UNUSED(ob)
for (i = 0; i < totloop; i++) {
int v = mloop[i].v;
- rgb_uchar_to_float(&data_color[v*3], &mcol[i].r);
+
+ if (mcorners[v] == 0) {
+ rgb_uchar_to_float(&data_color[v * 3], &mcol[i].r);
+ }
+ else {
+ float col[3];
+ rgb_uchar_to_float(col, &mcol[i].r);
+ add_v3_v3(&data_color[v * 3], col);
+ }
+
++mcorners[v];
}
diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c
index 9aac5ed1f1d..26a0b0c71b4 100644
--- a/source/blender/render/intern/source/rayshade.c
+++ b/source/blender/render/intern/source/rayshade.c
@@ -174,10 +174,11 @@ void freeraytree(Render *re)
#ifdef RE_RAYCOUNTER
{
+ const int num_threads = re->r.threads;
RayCounter sum;
memset(&sum, 0, sizeof(sum));
int i;
- for (i=0; i<BLENDER_MAX_THREADS; i++)
+ for (i=0; i<num_threads; i++)
RE_RC_MERGE(&sum, re_rc_counter+i);
RE_RC_INFO(&sum);
}
@@ -1186,7 +1187,9 @@ static void QMC_sampleHemiCosine(float vec[3], QMCSampler *qsa, int thread, int
/* called from convertBlenderScene.c */
void init_render_qmcsampler(Render *re)
{
- re->qmcsamplers= MEM_callocN(sizeof(ListBase)*BLENDER_MAX_THREADS, "QMCListBase");
+ const int num_threads = re->r.threads;
+ re->qmcsamplers= MEM_callocN(sizeof(ListBase)*num_threads, "QMCListBase");
+ re->num_qmc_samplers = num_threads;
}
static QMCSampler *get_thread_qmcsampler(Render *re, int thread, int type, int tot)
@@ -1220,7 +1223,7 @@ void free_render_qmcsampler(Render *re)
if (re->qmcsamplers) {
QMCSampler *qsa, *next;
int a;
- for (a=0; a<BLENDER_MAX_THREADS; a++) {
+ for (a = 0; a < re->num_qmc_samplers; a++) {
for (qsa=re->qmcsamplers[a].first; qsa; qsa=next) {
next= qsa->next;
QMC_freeSampler(qsa);
@@ -1695,9 +1698,10 @@ static void DS_energy(float *sphere, int tot, float vec[3])
/* called from convertBlenderScene.c */
/* creates an equally distributed spherical sample pattern */
/* and allocates threadsafe memory */
-void init_ao_sphere(World *wrld)
+void init_ao_sphere(Render *re, World *wrld)
{
/* fixed random */
+ const int num_threads = re->r.threads;
RNG *rng;
float *fp;
int a, tot, iter= 16;
@@ -1721,7 +1725,7 @@ void init_ao_sphere(World *wrld)
}
/* tables */
- wrld->aotables= MEM_mallocN(BLENDER_MAX_THREADS*3*tot*sizeof(float), "AO tables");
+ wrld->aotables= MEM_mallocN(num_threads*3*tot*sizeof(float), "AO tables");
BLI_rng_free(rng);
}
diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c
index 2d26fcf4905..2be6238eeec 100644
--- a/source/blender/render/intern/source/render_result.c
+++ b/source/blender/render/intern/source/render_result.c
@@ -359,102 +359,109 @@ static const char *name_from_passtype(int passtype, int channel)
return "Unknown";
}
-static int passtype_from_name(const char *str)
+static int passtype_from_name(const char *str, int passflag)
{
+ /* We do not really support several pass of the same types, so in case we are opening an EXR file with several pass
+ * names detected as same pass type, only return that pass type the first time, and return 'uknown' for the others.
+ * See T48466. */
+#define RETURN_PASS(_passtype) return (passflag & (_passtype)) ? 0 : (_passtype)
+
if (STRPREFIX(str, "Combined"))
- return SCE_PASS_COMBINED;
+ RETURN_PASS(SCE_PASS_COMBINED);
if (STRPREFIX(str, "Depth"))
- return SCE_PASS_Z;
+ RETURN_PASS(SCE_PASS_Z);
if (STRPREFIX(str, "Vector"))
- return SCE_PASS_VECTOR;
+ RETURN_PASS(SCE_PASS_VECTOR);
if (STRPREFIX(str, "Normal"))
- return SCE_PASS_NORMAL;
+ RETURN_PASS(SCE_PASS_NORMAL);
if (STRPREFIX(str, "UV"))
- return SCE_PASS_UV;
+ RETURN_PASS(SCE_PASS_UV);
if (STRPREFIX(str, "Color"))
- return SCE_PASS_RGBA;
+ RETURN_PASS(SCE_PASS_RGBA);
if (STRPREFIX(str, "Emit"))
- return SCE_PASS_EMIT;
+ RETURN_PASS(SCE_PASS_EMIT);
if (STRPREFIX(str, "Diffuse"))
- return SCE_PASS_DIFFUSE;
+ RETURN_PASS(SCE_PASS_DIFFUSE);
if (STRPREFIX(str, "Spec"))
- return SCE_PASS_SPEC;
+ RETURN_PASS(SCE_PASS_SPEC);
if (STRPREFIX(str, "Shadow"))
- return SCE_PASS_SHADOW;
+ RETURN_PASS(SCE_PASS_SHADOW);
if (STRPREFIX(str, "AO"))
- return SCE_PASS_AO;
+ RETURN_PASS(SCE_PASS_AO);
if (STRPREFIX(str, "Env"))
- return SCE_PASS_ENVIRONMENT;
+ RETURN_PASS(SCE_PASS_ENVIRONMENT);
if (STRPREFIX(str, "Indirect"))
- return SCE_PASS_INDIRECT;
+ RETURN_PASS(SCE_PASS_INDIRECT);
if (STRPREFIX(str, "Reflect"))
- return SCE_PASS_REFLECT;
+ RETURN_PASS(SCE_PASS_REFLECT);
if (STRPREFIX(str, "Refract"))
- return SCE_PASS_REFRACT;
+ RETURN_PASS(SCE_PASS_REFRACT);
if (STRPREFIX(str, "IndexOB"))
- return SCE_PASS_INDEXOB;
+ RETURN_PASS(SCE_PASS_INDEXOB);
if (STRPREFIX(str, "IndexMA"))
- return SCE_PASS_INDEXMA;
+ RETURN_PASS(SCE_PASS_INDEXMA);
if (STRPREFIX(str, "Mist"))
- return SCE_PASS_MIST;
+ RETURN_PASS(SCE_PASS_MIST);
if (STRPREFIX(str, "RayHits"))
- return SCE_PASS_RAYHITS;
+ RETURN_PASS(SCE_PASS_RAYHITS);
if (STRPREFIX(str, "DiffDir"))
- return SCE_PASS_DIFFUSE_DIRECT;
+ RETURN_PASS(SCE_PASS_DIFFUSE_DIRECT);
if (STRPREFIX(str, "DiffInd"))
- return SCE_PASS_DIFFUSE_INDIRECT;
+ RETURN_PASS(SCE_PASS_DIFFUSE_INDIRECT);
if (STRPREFIX(str, "DiffCol"))
- return SCE_PASS_DIFFUSE_COLOR;
+ RETURN_PASS(SCE_PASS_DIFFUSE_COLOR);
if (STRPREFIX(str, "GlossDir"))
- return SCE_PASS_GLOSSY_DIRECT;
+ RETURN_PASS(SCE_PASS_GLOSSY_DIRECT);
if (STRPREFIX(str, "GlossInd"))
- return SCE_PASS_GLOSSY_INDIRECT;
+ RETURN_PASS(SCE_PASS_GLOSSY_INDIRECT);
if (STRPREFIX(str, "GlossCol"))
- return SCE_PASS_GLOSSY_COLOR;
+ RETURN_PASS(SCE_PASS_GLOSSY_COLOR);
if (STRPREFIX(str, "TransDir"))
- return SCE_PASS_TRANSM_DIRECT;
+ RETURN_PASS(SCE_PASS_TRANSM_DIRECT);
if (STRPREFIX(str, "TransInd"))
- return SCE_PASS_TRANSM_INDIRECT;
+ RETURN_PASS(SCE_PASS_TRANSM_INDIRECT);
if (STRPREFIX(str, "TransCol"))
- return SCE_PASS_TRANSM_COLOR;
+ RETURN_PASS(SCE_PASS_TRANSM_COLOR);
if (STRPREFIX(str, "SubsurfaceDir"))
- return SCE_PASS_SUBSURFACE_DIRECT;
+ RETURN_PASS(SCE_PASS_SUBSURFACE_DIRECT);
if (STRPREFIX(str, "SubsurfaceInd"))
- return SCE_PASS_SUBSURFACE_INDIRECT;
+ RETURN_PASS(SCE_PASS_SUBSURFACE_INDIRECT);
if (STRPREFIX(str, "SubsurfaceCol"))
- return SCE_PASS_SUBSURFACE_COLOR;
+ RETURN_PASS(SCE_PASS_SUBSURFACE_COLOR);
return 0;
+
+#undef RETURN_PASS
}
@@ -533,6 +540,11 @@ static RenderPass *render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int
return rpass;
}
+/* wrapper called from render_opengl */
+RenderPass *gp_add_pass(RenderResult *rr, RenderLayer *rl, int channels, int passtype, const char *viewname)
+{
+ return render_layer_add_pass(rr, rl, channels, passtype, viewname);
+}
#ifdef WITH_CYCLES_DEBUG
const char *RE_debug_pass_name_get(int debug_type)
@@ -838,8 +850,9 @@ static void ml_addpass_cb(void *base, void *lay, const char *str, float *rect, i
BLI_addtail(&rl->passes, rpass);
rpass->channels = totchan;
- rpass->passtype = passtype_from_name(str);
- if (rpass->passtype == 0) printf("unknown pass %s\n", str);
+ rpass->passtype = passtype_from_name(str, rl->passflag);
+ if (rpass->passtype == 0)
+ printf("unknown pass %s\n", str);
rl->passflag |= rpass->passtype;
/* channel id chars */
@@ -1652,3 +1665,84 @@ RenderView *RE_RenderViewGetByName(RenderResult *res, const char *viewname)
BLI_assert(res->views.first);
return rv ? rv : res->views.first;
}
+
+static RenderPass *duplicate_render_pass(RenderPass *rpass)
+{
+ RenderPass *new_rpass = MEM_mallocN(sizeof(RenderPass), "new render pass");
+ *new_rpass = *rpass;
+ new_rpass->next = new_rpass->prev = NULL;
+ if (new_rpass->rect != NULL) {
+ new_rpass->rect = MEM_dupallocN(new_rpass->rect);
+ }
+ return new_rpass;
+}
+
+static RenderLayer *duplicate_render_layer(RenderLayer *rl)
+{
+ RenderLayer *new_rl = MEM_mallocN(sizeof(RenderLayer), "new render layer");
+ *new_rl = *rl;
+ new_rl->next = new_rl->prev = NULL;
+ new_rl->passes.first = new_rl->passes.last = NULL;
+ new_rl->exrhandle = NULL;
+ if (new_rl->acolrect != NULL) {
+ new_rl->acolrect = MEM_dupallocN(new_rl->acolrect);
+ }
+ if (new_rl->scolrect != NULL) {
+ new_rl->scolrect = MEM_dupallocN(new_rl->scolrect);
+ }
+ if (new_rl->display_buffer != NULL) {
+ new_rl->display_buffer = MEM_dupallocN(new_rl->display_buffer);
+ }
+ for (RenderPass *rpass = rl->passes.first; rpass != NULL; rpass = rpass->next) {
+ RenderPass *new_rpass = duplicate_render_pass(rpass);
+ BLI_addtail(&new_rl->passes, new_rpass);
+ }
+ return new_rl;
+}
+
+static RenderView *duplicate_render_view(RenderView *rview)
+{
+ RenderView *new_rview = MEM_mallocN(sizeof(RenderView), "new render view");
+ *new_rview = *rview;
+ if (new_rview->rectf != NULL) {
+ new_rview->rectf = MEM_dupallocN(new_rview->rectf);
+ }
+ if (new_rview->rectf != NULL) {
+ new_rview->rectf = MEM_dupallocN(new_rview->rectf);
+ }
+ if (new_rview->rectz != NULL) {
+ new_rview->rectz = MEM_dupallocN(new_rview->rectz);
+ }
+ if (new_rview->rect32 != NULL) {
+ new_rview->rect32 = MEM_dupallocN(new_rview->rect32);
+ }
+ return new_rview;
+}
+
+RenderResult *RE_DuplicateRenderResult(RenderResult *rr)
+{
+ RenderResult *new_rr = MEM_mallocN(sizeof(RenderResult), "new duplicated render result");
+ *new_rr = *rr;
+ new_rr->next = new_rr->prev = NULL;
+ new_rr->layers.first = new_rr->layers.last = NULL;
+ new_rr->views.first = new_rr->views.last = NULL;
+ for (RenderLayer *rl = rr->layers.first; rl != NULL; rl = rl->next) {
+ RenderLayer *new_rl = duplicate_render_layer(rl);
+ BLI_addtail(&new_rr->layers, new_rl);
+ }
+ for (RenderView *rview = rr->views.first; rview != NULL; rview = rview->next) {
+ RenderView *new_rview = duplicate_render_view(rview);
+ BLI_addtail(&new_rr->views, new_rview);
+ }
+ if (new_rr->rect32 != NULL) {
+ new_rr->rect32 = MEM_dupallocN(new_rr->rect32);
+ }
+ if (new_rr->rectf != NULL) {
+ new_rr->rectf = MEM_dupallocN(new_rr->rectf);
+ }
+ if (new_rr->rectz != NULL) {
+ new_rr->rectz = MEM_dupallocN(new_rr->rectz);
+ }
+ new_rr->stamp_data = MEM_dupallocN(new_rr->stamp_data);
+ return new_rr;
+}
diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c
index 8f61f4159e6..b4a14f5337d 100644
--- a/source/blender/render/intern/source/render_texture.c
+++ b/source/blender/render/intern/source/render_texture.c
@@ -1720,6 +1720,21 @@ static void texco_mapping(ShadeInput *shi, Tex *tex, MTex *mtex,
}
else dxt[2]= dyt[2] = 0.f;
}
+
+ if (mtex->tex->type == TEX_ENVMAP) {
+ EnvMap *env = tex->env;
+ if (!env->object) {
+ // env->object is a view point for envmap rendering
+ // if it's not set, return the result depending on the world_space_shading flag
+ if (BKE_scene_use_world_space_shading(R.scene)) {
+ mul_mat3_m4_v3(R.viewinv, texvec);
+ if (shi->osatex) {
+ mul_mat3_m4_v3(R.viewinv, dxt);
+ mul_mat3_m4_v3(R.viewinv, dyt);
+ }
+ }
+ }
+ }
}
}
@@ -2480,8 +2495,7 @@ void do_material_tex(ShadeInput *shi, Render *re)
/* can be optimized... (ton) */
mul_mat3_m4_v3(shi->obr->ob->obmat, texres.nor);
mul_mat3_m4_v3(re->viewmat, texres.nor);
- normalize_v3(texres.nor);
- mul_v3_fl(texres.nor, len);
+ normalize_v3_length(texres.nor, len);
}
}
}
@@ -3639,7 +3653,8 @@ void render_realtime_texture(ShadeInput *shi, Image *ima)
if (firsttime) {
BLI_lock_thread(LOCK_IMAGE);
if (firsttime) {
- for (a=0; a<BLENDER_MAX_THREADS; a++) {
+ const int num_threads = BLI_system_thread_count();
+ for (a = 0; a < num_threads; a++) {
memset(&imatex[a], 0, sizeof(Tex));
BKE_texture_default(&imatex[a]);
imatex[a].type= TEX_IMAGE;
@@ -3806,6 +3821,7 @@ void RE_sample_material_free(Material *mat)
MTex *mtex= mat->mtex[tex_nr];
if (mtex->tex) {
+ /* don't update user counts as we are freeing a duplicate */
BKE_texture_free(mtex->tex);
MEM_freeN(mtex->tex);
mtex->tex = NULL;
@@ -3814,7 +3830,7 @@ void RE_sample_material_free(Material *mat)
}
/* don't update user counts as we are freeing a duplicate */
- BKE_material_free_ex(mat, false);
+ BKE_material_free(mat);
MEM_freeN(mat);
}
diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c
index d3d26011a57..76e6ca8d467 100644
--- a/source/blender/render/intern/source/renderdatabase.c
+++ b/source/blender/render/intern/source/renderdatabase.c
@@ -1006,7 +1006,7 @@ HaloRen *RE_inithalo(Render *re, ObjectRen *obr, Material *ma,
xn= har->xs - 0.5f*re->winx*(hoco1[0]/hoco1[3]);
yn= har->ys - 0.5f*re->winy*(hoco1[1]/hoco1[3]);
- if (xn==0.0f || (xn==0.0f && yn==0.0f)) zn= 0.0f;
+ if (yn == 0.0f && xn >= 0.0f) zn = 0.0f;
else zn = atan2f(yn, xn);
har->sin = sinf(zn);
@@ -1136,7 +1136,7 @@ HaloRen *RE_inithalo_particle(Render *re, ObjectRen *obr, DerivedMesh *dm, Mater
xn= har->xs - 0.5f*re->winx*(hoco1[0]/hoco1[3]);
yn= har->ys - 0.5f*re->winy*(hoco1[1]/hoco1[3]);
- if (xn==0.0f || (xn==0.0f && yn==0.0f)) zn= 0.0;
+ if (yn == 0.0f && xn >= 0.0f) zn = 0.0f;
else zn = atan2f(yn, xn);
har->sin = sinf(zn);
diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c
index 6e01921a6a7..20602314526 100644
--- a/source/blender/render/intern/source/shadeinput.c
+++ b/source/blender/render/intern/source/shadeinput.c
@@ -1339,6 +1339,7 @@ void shade_input_initialize(ShadeInput *shi, RenderPart *pa, RenderLayer *rl, in
shi->do_preview = (R.r.scemode & R_MATNODE_PREVIEW) != 0;
shi->do_manage = BKE_scene_check_color_management_enabled(R.scene);
+ shi->use_world_space_shading = BKE_scene_use_world_space_shading(R.scene);
shi->lay = rl->lay;
shi->layflag = rl->layflag;
diff --git a/source/blender/render/intern/source/sss.c b/source/blender/render/intern/source/sss.c
index 553710b4367..26ca3ad50e0 100644
--- a/source/blender/render/intern/source/sss.c
+++ b/source/blender/render/intern/source/sss.c
@@ -279,13 +279,19 @@ static void build_Rd_table(ScatterSettings *ss)
for (i= 0; i < size; i++) {
r= i*(RD_TABLE_RANGE/RD_TABLE_SIZE);
- /*if (r < ss->invsigma_t_*ss->invsigma_t_)
- r= ss->invsigma_t_*ss->invsigma_t_;*/
+#if 0
+ if (r < ss->invsigma_t_*ss->invsigma_t_) {
+ r= ss->invsigma_t_*ss->invsigma_t_;
+ }
+#endif
ss->tableRd[i]= Rd(ss, sqrtf(r));
r= i*(RD_TABLE_RANGE_2/RD_TABLE_SIZE);
- /*if (r < ss->invsigma_t_)
- r= ss->invsigma_t_;*/
+#if 0
+ if (r < ss->invsigma_t_) {
+ r= ss->invsigma_t_;
+ }
+#endif
ss->tableRd2[i]= Rd(ss, r);
}
}
diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c
index d3a1dcfd8ce..9f777631e52 100644
--- a/source/blender/render/intern/source/zbuf.c
+++ b/source/blender/render/intern/source/zbuf.c
@@ -2883,14 +2883,17 @@ static void set_quad_bezier_ipo(float fac, float *data)
data[2]= fac*fac;
}
-void RE_zbuf_accumulate_vecblur(NodeBlurData *nbd, int xsize, int ysize, float *newrect, float *imgrect, float *vecbufrect, float *zbufrect)
+void RE_zbuf_accumulate_vecblur(
+ NodeBlurData *nbd, int xsize, int ysize, float *newrect,
+ const float *imgrect, float *vecbufrect, const float *zbufrect)
{
ZSpan zspan;
DrawBufPixel *rectdraw, *dr;
static float jit[256][2];
float v1[3], v2[3], v3[3], v4[3], fx, fy;
- float *rectvz, *dvz, *dimg, *dvec1, *dvec2, *dz, *dz1, *dz2, *rectz;
- float *minvecbufrect= NULL, *rectweight, *rw, *rectmax, *rm, *ro;
+ const float *dimg, *dz, *ro;
+ float *rectvz, *dvz, *dvec1, *dvec2, *dz1, *dz2, *rectz;
+ float *minvecbufrect= NULL, *rectweight, *rw, *rectmax, *rm;
float maxspeedsq= (float)nbd->maxspeed*nbd->maxspeed;
int y, x, step, maxspeed=nbd->maxspeed, samples= nbd->samples;
int tsktsk= 0;
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index 01188cb7f65..b6245a8c0d1 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -146,6 +146,10 @@ if(WITH_OPENSUBDIV)
add_definitions(-DWITH_OPENSUBDIV)
endif()
+if(WITH_INPUT_NDOF)
+ add_definitions(-DWITH_INPUT_NDOF)
+endif()
+
if(WIN32)
if(WITH_INPUT_IME)
add_definitions(-DWITH_INPUT_IME)
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index db2547e4fbe..2b82f1becb3 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -64,7 +64,10 @@ struct wmDrag;
struct ImBuf;
struct ImageFormatData;
struct ARegion;
+
+#ifdef WITH_INPUT_NDOF
struct wmNDOFMotionData;
+#endif
typedef struct wmJob wmJob;
@@ -114,6 +117,8 @@ void WM_autosave_init(struct wmWindowManager *wm);
void WM_recover_last_session(struct bContext *C, struct ReportList *reports);
void WM_file_tag_modified(const struct bContext *C);
+void WM_lib_reload(struct Library *lib, struct bContext *C, struct ReportList *reports);
+
/* mouse cursors */
void WM_cursor_set(struct wmWindow *win, int curs);
void WM_cursor_modal_set(struct wmWindow *win, int curs);
@@ -184,14 +189,15 @@ void WM_event_add_mousemove(struct bContext *C);
bool WM_modal_tweak_exit(const struct wmEvent *event, int tweak_event);
bool WM_event_is_absolute(const struct wmEvent *event);
+#ifdef WITH_INPUT_NDOF
/* 3D mouse */
void WM_ndof_deadzone_set(float deadzone);
-
+#endif
/* notifiers */
void WM_event_add_notifier(const struct bContext *C, unsigned int type, void *reference);
void WM_main_add_notifier(unsigned int type, void *reference);
void WM_main_remove_notifier_reference(const void *reference);
-void WM_main_remove_editor_id_reference(const struct ID *id);
+void WM_main_remap_editor_id_reference(struct ID *old_id, struct ID *new_id);
/* reports */
void WM_report_banner_show(void);
@@ -220,6 +226,7 @@ void WM_event_timer_sleep(struct wmWindowManager *wm, struct wmWindow *wi
/* invoke callback, uses enum property named "type" */
void WM_operator_view3d_unit_defaults(struct bContext *C, struct wmOperator *op);
int WM_operator_smooth_viewtx_get(const struct wmOperator *op);
+int WM_menu_invoke_ex(struct bContext *C, struct wmOperator *op, int opcontext);
int WM_menu_invoke (struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
int WM_enum_search_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
/* invoke callback, confirm menu + exec */
@@ -384,9 +391,7 @@ void WM_gestures_remove(struct bContext *C);
/* fileselecting support */
void WM_event_add_fileselect(struct bContext *C, struct wmOperator *op);
void WM_event_fileselect_event(struct wmWindowManager *wm, void *ophandle, int eventval);
-#ifndef NDEBUG
void WM_event_print(const struct wmEvent *event);
-#endif
void WM_operator_region_active_win_set(struct bContext *C);
@@ -412,12 +417,6 @@ void wmOrtho2 (float x1, float x2, float y1, float y2);
void wmOrtho2_region_pixelspace(const struct ARegion *ar);
void wmOrtho2_pixelspace(const float x, const float y);
- /* utilities */
-void WM_framebuffer_index_set(int index);
-void WM_framebuffer_index_get(int index, int *r_col);
-int WM_framebuffer_to_index(unsigned int col);
-void WM_framebuffer_to_index_array(unsigned int *col, const unsigned int size);
-
/* threaded Jobs Manager */
enum {
WM_JOB_PRIORITY = (1 << 0),
@@ -446,6 +445,7 @@ enum {
WM_JOB_TYPE_SEQ_BUILD_PREVIEW,
WM_JOB_TYPE_POINTCACHE,
WM_JOB_TYPE_DPAINT_BAKE,
+ WM_JOB_TYPE_ALEMBIC,
/* add as needed, screencast, seq proxy build
* if having hard coded values is a problem */
};
@@ -502,11 +502,13 @@ bool write_crash_blend(void);
/* Lock the interface for any communication */
void WM_set_locked_interface(struct wmWindowManager *wm, bool lock);
+#ifdef WITH_INPUT_NDOF
void WM_event_ndof_pan_get(const struct wmNDOFMotionData *ndof, float r_pan[3], const bool use_zoom);
void WM_event_ndof_rotate_get(const struct wmNDOFMotionData *ndof, float r_rot[3]);
float WM_event_ndof_to_axis_angle(const struct wmNDOFMotionData *ndof, float axis[3]);
void WM_event_ndof_to_quat(const struct wmNDOFMotionData *ndof, float q[4]);
+#endif /* WITH_INPUT_NDOF */
float WM_event_tablet_data(const struct wmEvent *event, int *pen_flip, float tilt[2]);
bool WM_event_is_tablet(const struct wmEvent *event);
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 3c0e99bddd0..0fe3e8a0fcf 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -485,6 +485,7 @@ typedef enum { /* motion progress, for modal handlers */
P_FINISHED
} wmProgress;
+#ifdef WITH_INPUT_NDOF
typedef struct wmNDOFMotionData {
/* awfully similar to GHOST_TEventNDOFMotionData... */
/* Each component normally ranges from -1 to +1, but can exceed that.
@@ -496,6 +497,7 @@ typedef struct wmNDOFMotionData {
float dt; /* time since previous NDOF Motion event */
wmProgress progress; /* is this the first event, the last, or one of many in between? */
} wmNDOFMotionData;
+#endif /* WITH_INPUT_NDOF */
typedef struct wmTimer {
struct wmTimer *next, *prev;
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 8f15d94f538..3825db14e93 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -437,8 +437,6 @@ void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha)
float halfx, halfy, ratiox, ratioy;
- glEnable(triple->target);
-
/* wmOrtho for the screen has this same offset */
ratiox = sizex;
ratioy = sizey;
@@ -453,6 +451,8 @@ void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha)
halfy /= triple->y;
}
+ GPU_basic_shader_bind((triple->target == GL_TEXTURE_2D) ? GPU_SHADER_TEXTURE_2D : GPU_SHADER_TEXTURE_RECT);
+
glBindTexture(triple->target, triple->bind);
glColor4f(1.0f, 1.0f, 1.0f, alpha);
@@ -471,7 +471,8 @@ void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha)
glEnd();
glBindTexture(triple->target, 0);
- glDisable(triple->target);
+
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
static void wm_triple_copy_textures(wmWindow *win, wmDrawTriple *triple)
@@ -861,11 +862,8 @@ static int wm_automatic_draw_method(wmWindow *win)
* copy to texture is slow though and so we use overlap instead there. */
if (win->drawmethod == USER_DRAW_AUTOMATIC) {
- /* ATI opensource driver is known to be very slow at this */
- if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE))
- return USER_DRAW_OVERLAP;
/* Windows software driver darkens color on each redraw */
- else if (GPU_type_matches(GPU_DEVICE_SOFTWARE, GPU_OS_WIN, GPU_DRIVER_SOFTWARE))
+ if (GPU_type_matches(GPU_DEVICE_SOFTWARE, GPU_OS_WIN, GPU_DRIVER_SOFTWARE))
return USER_DRAW_OVERLAP_FLIP;
else if (GPU_type_matches(GPU_DEVICE_SOFTWARE, GPU_OS_UNIX, GPU_DRIVER_SOFTWARE))
return USER_DRAW_OVERLAP;
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 40b6f90f6f3..dc34e8015c9 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -81,9 +81,7 @@
#include "wm_event_system.h"
#include "wm_event_types.h"
-#ifndef NDEBUG
-# include "RNA_enum_types.h"
-#endif
+#include "RNA_enum_types.h"
static void wm_notifier_clear(wmNotifier *note);
static void update_tablet_data(wmWindow *win, wmEvent *event);
@@ -241,7 +239,7 @@ void WM_main_remove_notifier_reference(const void *reference)
}
}
-void WM_main_remove_editor_id_reference(const ID *id)
+void WM_main_remap_editor_id_reference(ID *old_id, ID *new_id)
{
Main *bmain = G.main;
bScreen *sc;
@@ -253,7 +251,7 @@ void WM_main_remove_editor_id_reference(const ID *id)
SpaceLink *sl;
for (sl = sa->spacedata.first; sl; sl = sl->next) {
- ED_spacedata_id_unref(sl, id);
+ ED_spacedata_id_remap(sa, sl, old_id, new_id);
}
}
}
@@ -550,8 +548,6 @@ void WM_operator_region_active_win_set(bContext *C)
}
/* for debugging only, getting inspecting events manually is tedious */
-#ifndef NDEBUG
-
void WM_event_print(const wmEvent *event)
{
if (event) {
@@ -571,6 +567,7 @@ void WM_event_print(const wmEvent *event)
BLI_str_utf8_size(event->utf8_buf), event->utf8_buf,
event->keymap_idname, (const void *)event);
+#ifdef WITH_INPUT_NDOF
if (ISNDOF(event->type)) {
const wmNDOFMotionData *ndof = event->customdata;
if (event->type == NDOF_MOTION) {
@@ -581,6 +578,7 @@ void WM_event_print(const wmEvent *event)
/* ndof buttons printed already */
}
}
+#endif /* WITH_INPUT_NDOF */
if (event->tablet_data) {
const wmTabletData *wmtab = event->tablet_data;
@@ -593,8 +591,6 @@ void WM_event_print(const wmEvent *event)
}
}
-#endif /* NDEBUG */
-
/**
* Show the report in the info header.
*/
@@ -619,10 +615,12 @@ bool WM_event_is_absolute(const wmEvent *event)
return (event->tablet_data != NULL);
}
+#ifdef WITH_INPUT_NDOF
void WM_ndof_deadzone_set(float deadzone)
{
GHOST_setNDOFDeadZone(deadzone);
}
+#endif
static void wm_add_reports(ReportList *reports)
{
@@ -793,7 +791,10 @@ static int wm_operator_exec(bContext *C, wmOperator *op, const bool repeat, cons
wm_operator_finished(C, op, repeat);
}
else if (repeat == 0) {
- WM_operator_free(op);
+ /* warning: modal from exec is bad practice, but avoid crashing. */
+ if (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED)) {
+ WM_operator_free(op);
+ }
}
return retval | OPERATOR_HANDLED;
@@ -1966,15 +1967,11 @@ static int wm_action_not_handled(int action)
static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers)
{
-#ifndef NDEBUG
const bool do_debug_handler = (G.debug & G_DEBUG_HANDLERS) &&
/* comment this out to flood the console! (if you really want to test) */
!ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)
;
-# define PRINT if (do_debug_handler) printf
-#else
-# define PRINT(format, ...)
-#endif
+# define PRINT if (do_debug_handler) printf
wmWindowManager *wm = CTX_wm_manager(C);
wmEventHandler *handler, *nexthandler;
@@ -2035,11 +2032,13 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
break;
}
else {
- if (action & WM_HANDLER_HANDLED)
+ if (action & WM_HANDLER_HANDLED) {
if (G.debug & (G_DEBUG_EVENTS | G_DEBUG_HANDLERS))
printf("%s: handled - and pass on! '%s'\n", __func__, kmi->idname);
-
- PRINT("%s: un-handled '%s'...", __func__, kmi->idname);
+ }
+ else {
+ PRINT("%s: un-handled '%s'\n", __func__, kmi->idname);
+ }
}
}
}
@@ -2359,7 +2358,7 @@ void wm_event_do_handlers(bContext *C)
if (is_playing_sound == 0) {
const float time = BKE_sound_sync_scene(scene);
- if (finite(time)) {
+ if (isfinite(time)) {
int ncfra = time * (float)FPS + 0.5f;
if (ncfra != scene->r.cfra) {
scene->r.cfra = ncfra;
@@ -2379,20 +2378,16 @@ void wm_event_do_handlers(bContext *C)
while ( (event = win->queue.first) ) {
int action = WM_HANDLER_CONTINUE;
-#ifndef NDEBUG
if (G.debug & (G_DEBUG_HANDLERS | G_DEBUG_EVENTS) && !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
printf("\n%s: Handling event\n", __func__);
WM_event_print(event);
}
-#endif
/* take care of pie event filter */
if (wm_event_pie_filter(win, event)) {
-#ifndef NDEBUG
if (G.debug & (G_DEBUG_HANDLERS | G_DEBUG_EVENTS) && !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
printf("\n%s: event filtered due to pie button pressed\n", __func__);
}
-#endif
BLI_remlink(&win->queue, event);
wm_event_free(event);
continue;
@@ -2434,9 +2429,11 @@ void wm_event_do_handlers(bContext *C)
/* for regions having custom cursors */
wm_paintcursor_test(C, event);
}
+#ifdef WITH_INPUT_NDOF
else if (event->type == NDOF_MOTION) {
win->addmousemove = true;
}
+#endif
for (sa = win->screen->areabase.first; sa; sa = sa->next) {
/* after restoring a screen from SCREENMAXIMIZED we have to wait
@@ -3037,6 +3034,7 @@ static void update_tablet_data(wmWindow *win, wmEvent *event)
}
}
+#ifdef WITH_INPUT_NDOF
/* adds customdata to event */
static void attach_ndof_data(wmEvent *event, const GHOST_TEventNDOFMotionData *ghost)
{
@@ -3063,6 +3061,7 @@ static void attach_ndof_data(wmEvent *event, const GHOST_TEventNDOFMotionData *g
event->customdata = data;
event->customdatafree = 1;
}
+#endif /* WITH_INPUT_NDOF */
/* imperfect but probably usable... draw/enable drags to other windows */
static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *win, wmEvent *event)
@@ -3450,6 +3449,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
break;
}
+#ifdef WITH_INPUT_NDOF
case GHOST_kEventNDOFMotion:
{
event.type = NDOF_MOTION;
@@ -3485,6 +3485,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
break;
}
+#endif /* WITH_INPUT_NDOF */
case GHOST_kEventUnknown:
case GHOST_kNumEventTypes:
@@ -3556,6 +3557,7 @@ void WM_set_locked_interface(wmWindowManager *wm, bool lock)
}
+#ifdef WITH_INPUT_NDOF
/* -------------------------------------------------------------------- */
/* NDOF */
@@ -3598,6 +3600,7 @@ void WM_event_ndof_to_quat(const struct wmNDOFMotionData *ndof, float q[4])
angle = WM_event_ndof_to_axis_angle(ndof, axis);
axis_angle_to_quat(q, axis, angle);
}
+#endif /* WITH_INPUT_NDOF */
/* if this is a tablet event, return tablet pressure and set *pen_flip
* to 1 if the eraser tool is being used, 0 otherwise */
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 36b819d3495..fe257cc4c41 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -435,8 +435,7 @@ void wm_file_read_report(bContext *C)
}
BKE_reportf(reports, RPT_ERROR,
- "Engine '%s' not available for scene '%s' "
- "(an addon may need to be installed or enabled)",
+ "Engine '%s' not available for scene '%s' (an add-on may need to be installed or enabled)",
sce->r.engine, sce->id.name + 2);
}
}
@@ -483,8 +482,6 @@ static void wm_file_read_post(bContext *C, bool is_startup_file)
BPY_python_reset(C);
addons_loaded = true;
}
-#else
- UNUSED_VARS(is_startup_file);
#endif /* WITH_PYTHON */
WM_operatortype_last_properties_clear_all();
@@ -493,8 +490,12 @@ static void wm_file_read_post(bContext *C, bool is_startup_file)
BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_VERSION_UPDATE);
BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST);
- /* would otherwise be handled by event loop */
- if (G.background) {
+ /* Would otherwise be handled by event loop.
+ *
+ * Disabled for startup file, since it causes problems when PyDrivers are used in the startup file.
+ * While its possible state of startup file may be wrong,
+ * in this case users nearly always load a file to replace the startup file. */
+ if (G.background && (is_startup_file == false)) {
Main *bmain = CTX_data_main(C);
BKE_scene_update_tagged(bmain->eval_ctx, bmain, CTX_data_scene(C));
}
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index 5041eebd126..e872ec1a524 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -61,6 +61,7 @@
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_library.h"
+#include "BKE_library_remap.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_report.h"
@@ -211,7 +212,8 @@ static WMLinkAppendDataItem *wm_link_append_data_item_add(
}
static void wm_link_do(
- WMLinkAppendData *lapp_data, ReportList *reports, Main *bmain, Scene *scene, View3D *v3d)
+ WMLinkAppendData *lapp_data, ReportList *reports, Main *bmain, Scene *scene, View3D *v3d,
+ const bool use_placeholders, const bool force_indirect)
{
Main *mainl;
BlendHandle *bh;
@@ -258,9 +260,11 @@ static void wm_link_do(
continue;
}
- new_id = BLO_library_link_named_part_ex(mainl, &bh, item->idcode, item->name, flag, scene, v3d);
+ new_id = BLO_library_link_named_part_ex(
+ mainl, &bh, item->idcode, item->name, flag, scene, v3d, use_placeholders, force_indirect);
+
if (new_id) {
- /* If the link is sucessful, clear item's libs 'todo' flags.
+ /* If the link is successful, clear item's libs 'todo' flags.
* This avoids trying to link same item with other libraries to come. */
BLI_BITMAP_SET_ALL(item->libraries, false, lapp_data->num_libraries);
item->new_id = new_id;
@@ -401,22 +405,42 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
/* XXX We'd need re-entrant locking on Main for this to work... */
/* BKE_main_lock(bmain); */
- wm_link_do(lapp_data, op->reports, bmain, scene, CTX_wm_view3d(C));
+ wm_link_do(lapp_data, op->reports, bmain, scene, CTX_wm_view3d(C), false, false);
/* BKE_main_unlock(bmain); */
- wm_link_append_data_free(lapp_data);
-
/* mark all library linked objects to be updated */
BKE_main_lib_objects_recalc_all(bmain);
IMB_colormanagement_check_file_config(bmain);
/* append, rather than linking */
if ((flag & FILE_LINK) == 0) {
- bool set_fake = RNA_boolean_get(op->ptr, "set_fake");
- BKE_library_make_local(bmain, NULL, true, set_fake);
+ const bool set_fake = RNA_boolean_get(op->ptr, "set_fake");
+ const bool use_recursive = RNA_boolean_get(op->ptr, "use_recursive");
+
+ if (use_recursive) {
+ BKE_library_make_local(bmain, NULL, true, set_fake);
+ }
+ else {
+ LinkNode *itemlink;
+ GSet *done_libraries = BLI_gset_new_ex(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp,
+ __func__, lapp_data->num_libraries);
+
+ for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
+ ID *new_id = ((WMLinkAppendDataItem *)(itemlink->link))->new_id;
+
+ if (new_id && !BLI_gset_haskey(done_libraries, new_id->lib)) {
+ BKE_library_make_local(bmain, new_id->lib, true, set_fake);
+ BLI_gset_insert(done_libraries, new_id->lib);
+ }
+ }
+
+ BLI_gset_free(done_libraries, NULL);
+ }
}
+ wm_link_append_data_free(lapp_data);
+
/* important we unset, otherwise these object wont
* link into other scenes from this blend file */
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
@@ -442,7 +466,7 @@ static void wm_link_append_properties_common(wmOperatorType *ot, bool is_link)
/* better not save _any_ settings for this operator */
/* properties */
prop = RNA_def_boolean(ot->srna, "link", is_link,
- "Link", "Link the objects or datablocks rather than appending");
+ "Link", "Link the objects or data-blocks rather than appending");
RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
prop = RNA_def_boolean(ot->srna, "autoselect", true,
"Select", "Select new objects");
@@ -493,5 +517,421 @@ void WM_OT_append(wmOperatorType *ot)
FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
wm_link_append_properties_common(ot, false);
- RNA_def_boolean(ot->srna, "set_fake", false, "Fake User", "Set Fake User for appended items (except Objects and Groups)");
+ RNA_def_boolean(ot->srna, "set_fake", false, "Fake User",
+ "Set Fake User for appended items (except Objects and Groups)");
+ RNA_def_boolean(ot->srna, "use_recursive", true, "Localize All",
+ "Localize all appended data, including those indirectly linked from other libraries");
+}
+
+/** \name Reload/relocate libraries.
+ *
+ * \{ */
+
+static int wm_lib_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ Library *lib;
+ char lib_name[MAX_NAME];
+
+ RNA_string_get(op->ptr, "library", lib_name);
+ lib = (Library *)BKE_libblock_find_name_ex(CTX_data_main(C), ID_LI, lib_name);
+
+ if (lib) {
+ if (lib->parent) {
+ BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT,
+ "Cannot relocate indirectly linked library '%s'", lib->filepath);
+ return OPERATOR_CANCELLED;
+ }
+ RNA_string_set(op->ptr, "filepath", lib->filepath);
+
+ WM_event_add_fileselect(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+static void lib_relocate_do(
+ Main *bmain, Scene *scene,
+ Library *library, WMLinkAppendData *lapp_data, ReportList *reports, const bool do_reload)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ int lba_idx;
+
+ LinkNode *itemlink;
+ int item_idx;
+
+ /* Remove all IDs to be reloaded from Main. */
+ lba_idx = set_listbasepointers(bmain, lbarray);
+ while (lba_idx--) {
+ ID *id = lbarray[lba_idx]->first;
+ const short idcode = id ? GS(id->name) : 0;
+
+ if (!id || !BKE_idcode_is_linkable(idcode)) {
+ /* No need to reload non-linkable datatypes, those will get relinked with their 'users ID'. */
+ continue;
+ }
+
+ for (; id; id = id->next) {
+ if (id->lib == library) {
+ WMLinkAppendDataItem *item;
+
+ /* We remove it from current Main, and add it to items to link... */
+ /* Note that non-linkable IDs (like e.g. shapekeys) are also explicitly linked here... */
+ BLI_remlink(lbarray[lba_idx], id);
+ item = wm_link_append_data_item_add(lapp_data, id->name + 2, idcode, id);
+ BLI_BITMAP_SET_ALL(item->libraries, true, lapp_data->num_libraries);
+
+#ifdef PRINT_DEBUG
+ printf("\tdatablock to seek for: %s\n", id->name);
+#endif
+ }
+ }
+ }
+
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
+
+ /* We do not want any instanciation here! */
+ wm_link_do(lapp_data, reports, bmain, NULL, NULL, do_reload, do_reload);
+
+ BKE_main_lock(bmain);
+
+ /* We add back old id to bmain.
+ * We need to do this in a first, separated loop, otherwise some of those may not be handled by
+ * ID remapping, which means they would still reference old data to be deleted... */
+ for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; item_idx++, itemlink = itemlink->next) {
+ WMLinkAppendDataItem *item = itemlink->link;
+ ID *old_id = item->customdata;
+
+ BLI_assert(old_id);
+ BLI_addtail(which_libbase(bmain, GS(old_id->name)), old_id);
+ }
+
+ /* Note that in reload case, we also want to replace indirect usages. */
+ const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE | (do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE);
+ for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; item_idx++, itemlink = itemlink->next) {
+ WMLinkAppendDataItem *item = itemlink->link;
+ ID *old_id = item->customdata;
+ ID *new_id = item->new_id;
+
+ BLI_assert(old_id);
+ if (do_reload) {
+ /* Since we asked for placeholders in case of missing IDs, we expect to always get a valid one. */
+ BLI_assert(new_id);
+ }
+ if (new_id) {
+#ifdef PRINT_DEBUG
+ printf("before remap, old_id users: %d, new_id users: %d\n", old_id->us, new_id->us);
+#endif
+ BKE_libblock_remap_locked(bmain, old_id, new_id, remap_flags);
+
+ if (old_id->flag & LIB_FAKEUSER) {
+ id_fake_user_clear(old_id);
+ id_fake_user_set(new_id);
+ }
+
+#ifdef PRINT_DEBUG
+ printf("after remap, old_id users: %d, new_id users: %d\n", old_id->us, new_id->us);
+#endif
+
+ /* In some cases, new_id might become direct link, remove parent of library in this case. */
+ if (new_id->lib->parent && (new_id->tag & LIB_TAG_INDIRECT) == 0) {
+ if (do_reload) {
+ BLI_assert(0); /* Should not happen in 'pure' reload case... */
+ }
+ new_id->lib->parent = NULL;
+ }
+ }
+
+ if (old_id->us > 0 && new_id && old_id->lib == new_id->lib) {
+ /* Note that this *should* not happen - but better be safe than sorry in this area, at least until we are
+ * 100% sure this cannot ever happen.
+ * Also, we can safely assume names were unique so far, so just replacing '.' by '~' should work,
+ * but this does not totally rules out the possibility of name collision. */
+ size_t len = strlen(old_id->name);
+ size_t dot_pos;
+ bool has_num = false;
+
+ for (dot_pos = len; dot_pos--;) {
+ char c = old_id->name[dot_pos];
+ if (c == '.') {
+ break;
+ }
+ else if (c < '0' || c > '9') {
+ has_num = false;
+ break;
+ }
+ has_num = true;
+ }
+
+ if (has_num) {
+ old_id->name[dot_pos] = '~';
+ }
+ else {
+ len = MIN2(len, MAX_ID_NAME - 7);
+ BLI_strncpy(&old_id->name[len], "~000", 7);
+ }
+
+ id_sort_by_name(which_libbase(bmain, GS(old_id->name)), old_id);
+
+ BKE_reportf(reports, RPT_WARNING,
+ "Lib Reload: Replacing all references to old data-block '%s' by reloaded one failed, "
+ "old one (%d remaining users) had to be kept and was renamed to '%s'",
+ new_id->name, old_id->us, old_id->name);
+ }
+ }
+
+ BKE_main_unlock(bmain);
+
+ for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; item_idx++, itemlink = itemlink->next) {
+ WMLinkAppendDataItem *item = itemlink->link;
+ ID *old_id = item->customdata;
+
+ if (old_id->us == 0) {
+ BKE_libblock_free(bmain, old_id);
+ }
+ }
+
+ /* Some datablocks can get reloaded/replaced 'silently' because they are not linkable (shape keys e.g.),
+ * so we need another loop here to clear old ones if possible. */
+ lba_idx = set_listbasepointers(bmain, lbarray);
+ while (lba_idx--) {
+ ID *id, *id_next;
+ for (id = lbarray[lba_idx]->first; id; id = id_next) {
+ id_next = id->next;
+ /* XXX That check may be a bit to generic/permissive? */
+ if (id->lib && (id->flag & LIB_TAG_PRE_EXISTING) && id->us == 0) {
+ BKE_libblock_free(bmain, id);
+ }
+ }
+ }
+
+ /* Get rid of no more used libraries... */
+ BKE_main_id_tag_idcode(bmain, ID_LI, LIB_TAG_DOIT, true);
+ lba_idx = set_listbasepointers(bmain, lbarray);
+ while (lba_idx--) {
+ ID *id;
+ for (id = lbarray[lba_idx]->first; id; id = id->next) {
+ if (id->lib) {
+ id->lib->id.tag &= ~LIB_TAG_DOIT;
+ }
+ }
+ }
+ Library *lib, *lib_next;
+ for (lib = which_libbase(bmain, ID_LI)->first; lib; lib = lib_next) {
+ lib_next = lib->id.next;
+ if (lib->id.tag & LIB_TAG_DOIT) {
+ id_us_clear_real(&lib->id);
+ if (lib->id.us == 0) {
+ BKE_libblock_free(bmain, (ID *)lib);
+ }
+ }
+ }
+
+ BKE_main_lib_objects_recalc_all(bmain);
+ IMB_colormanagement_check_file_config(bmain);
+
+ /* important we unset, otherwise these object wont
+ * link into other scenes from this blend file */
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
+
+ /* recreate dependency graph to include new objects */
+ DAG_scene_relations_rebuild(bmain, scene);
+
+ /* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */
+ GPU_materials_free();
+}
+
+void WM_lib_reload(Library *lib, bContext *C, ReportList *reports)
+{
+ if (!BLO_has_bfile_extension(lib->filepath)) {
+ BKE_reportf(reports, RPT_ERROR, "'%s' is not a valid library filepath", lib->filepath);
+ return;
+ }
+
+ if (!BLI_exists(lib->filepath)) {
+ BKE_reportf(reports, RPT_ERROR,
+ "Trying to reload library '%s' from invalid path '%s'", lib->id.name, lib->filepath);
+ return;
+ }
+
+ WMLinkAppendData *lapp_data = wm_link_append_data_new(0);
+
+ wm_link_append_data_library_add(lapp_data, lib->filepath);
+
+ lib_relocate_do(CTX_data_main(C), CTX_data_scene(C), lib, lapp_data, reports, true);
+
+ wm_link_append_data_free(lapp_data);
+
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+}
+
+static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload)
+{
+ Library *lib;
+ char lib_name[MAX_NAME];
+
+ RNA_string_get(op->ptr, "library", lib_name);
+ lib = (Library *)BKE_libblock_find_name_ex(CTX_data_main(C), ID_LI, lib_name);
+
+ if (lib) {
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ PropertyRNA *prop;
+ WMLinkAppendData *lapp_data;
+
+ char path[FILE_MAX], root[FILE_MAXDIR], libname[FILE_MAX], relname[FILE_MAX];
+ short flag = 0;
+
+ if (RNA_boolean_get(op->ptr, "relative_path")) {
+ flag |= FILE_RELPATH;
+ }
+
+ if (lib->parent && !do_reload) {
+ BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT,
+ "Cannot relocate indirectly linked library '%s'", lib->filepath);
+ return OPERATOR_CANCELLED;
+ }
+
+ RNA_string_get(op->ptr, "directory", root);
+ RNA_string_get(op->ptr, "filename", libname);
+
+ if (!BLO_has_bfile_extension(libname)) {
+ BKE_report(op->reports, RPT_ERROR, "Not a library");
+ return OPERATOR_CANCELLED;
+ }
+
+ BLI_join_dirfile(path, sizeof(path), root, libname);
+
+ if (!BLI_exists(path)) {
+ BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT,
+ "Trying to reload or relocate library '%s' to invalid path '%s'", lib->id.name, path);
+ return OPERATOR_CANCELLED;
+ }
+
+ if (BLI_path_cmp(lib->filepath, path) == 0) {
+#ifdef PRINT_DEBUG
+ printf("We are supposed to reload '%s' lib (%d)...\n", lib->filepath, lib->id.us);
+#endif
+
+ do_reload = true;
+
+ lapp_data = wm_link_append_data_new(flag);
+ wm_link_append_data_library_add(lapp_data, path);
+ }
+ else {
+ int totfiles = 0;
+
+#ifdef PRINT_DEBUG
+ printf("We are supposed to relocate '%s' lib to new '%s' one...\n", lib->filepath, libname);
+#endif
+
+ /* Check if something is indicated for relocate. */
+ prop = RNA_struct_find_property(op->ptr, "files");
+ if (prop) {
+ totfiles = RNA_property_collection_length(op->ptr, prop);
+ if (totfiles == 0) {
+ if (!libname[0]) {
+ BKE_report(op->reports, RPT_ERROR, "Nothing indicated");
+ return OPERATOR_CANCELLED;
+ }
+ }
+ }
+
+ lapp_data = wm_link_append_data_new(flag);
+
+ if (totfiles) {
+ RNA_BEGIN (op->ptr, itemptr, "files")
+ {
+ RNA_string_get(&itemptr, "name", relname);
+
+ BLI_join_dirfile(path, sizeof(path), root, relname);
+
+ if (BLI_path_cmp(path, lib->filepath) == 0 || !BLO_has_bfile_extension(relname)) {
+ continue;
+ }
+
+#ifdef PRINT_DEBUG
+ printf("\t candidate new lib to reload datablocks from: %s\n", path);
+#endif
+ wm_link_append_data_library_add(lapp_data, path);
+ }
+ RNA_END;
+ }
+ else {
+#ifdef PRINT_DEBUG
+ printf("\t candidate new lib to reload datablocks from: %s\n", path);
+#endif
+ wm_link_append_data_library_add(lapp_data, path);
+ }
+ }
+
+ lib_relocate_do(bmain, scene, lib, lapp_data, op->reports, do_reload);
+
+ wm_link_append_data_free(lapp_data);
+
+ /* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */
+ BLI_strncpy(G.lib, root, FILE_MAX);
+
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+
+ return OPERATOR_FINISHED;
+ }
+
+ return OPERATOR_CANCELLED;
}
+
+static int wm_lib_relocate_exec(bContext *C, wmOperator *op)
+{
+ return wm_lib_relocate_exec_do(C, op, false);
+}
+
+void WM_OT_lib_relocate(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ ot->name = "Relocate Library";
+ ot->idname = "WM_OT_lib_relocate";
+ ot->description = "Relocate the given library to one or several others";
+
+ ot->invoke = wm_lib_relocate_invoke;
+ ot->exec = wm_lib_relocate_exec;
+
+ ot->flag |= OPTYPE_UNDO;
+
+ prop = RNA_def_string(ot->srna, "library", NULL, MAX_NAME, "Library", "Library to relocate");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_FILES | WM_FILESEL_RELPATH,
+ FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+}
+
+static int wm_lib_reload_exec(bContext *C, wmOperator *op)
+{
+ return wm_lib_relocate_exec_do(C, op, true);
+}
+
+void WM_OT_lib_reload(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ ot->name = "Reload Library";
+ ot->idname = "WM_OT_lib_reload";
+ ot->description = "Reload the given library";
+
+ ot->exec = wm_lib_reload_exec;
+
+ ot->flag |= OPTYPE_UNDO;
+
+ prop = RNA_def_string(ot->srna, "library", NULL, MAX_NAME, "Library", "Library to reload");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_RELPATH,
+ FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c
index 26d1d4c3266..46203333eb5 100644
--- a/source/blender/windowmanager/intern/wm_gesture.c
+++ b/source/blender/windowmanager/intern/wm_gesture.c
@@ -37,6 +37,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_bitmap_draw_2d.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -233,19 +234,15 @@ static void wm_gesture_draw_circle(wmGesture *gt)
}
struct LassoFillData {
- unsigned int *px;
+ unsigned char *px;
int width;
};
static void draw_filled_lasso_px_cb(int x, int x_end, int y, void *user_data)
{
struct LassoFillData *data = user_data;
- unsigned char *col = (unsigned char *)&(data->px[(y * data->width) + x]);
- do {
- col[0] = col[1] = col[2] = 0xff;
- col[3] = 0x10;
- col += 4;
- } while (++x != x_end);
+ unsigned char *col = &(data->px[(y * data->width) + x]);
+ memset(col, 0x10, x_end - x);
}
static void draw_filled_lasso(wmWindow *win, wmGesture *gt)
@@ -273,22 +270,35 @@ static void draw_filled_lasso(wmWindow *win, wmGesture *gt)
if (BLI_rcti_is_empty(&rect) == false) {
const int w = BLI_rcti_size_x(&rect);
const int h = BLI_rcti_size_y(&rect);
- unsigned int *pixel_buf = MEM_callocN(sizeof(*pixel_buf) * w * h, __func__);
+ unsigned char *pixel_buf = MEM_callocN(sizeof(*pixel_buf) * w * h, __func__);
struct LassoFillData lasso_fill_data = {pixel_buf, w};
- fill_poly_v2i_n(
+ BLI_bitmap_draw_2d_poly_v2i_n(
rect.xmin, rect.ymin, rect.xmax, rect.ymax,
(const int (*)[2])moves, tot,
draw_filled_lasso_px_cb, &lasso_fill_data);
- glEnable(GL_BLEND);
- // glColor4f(1.0, 1.0, 1.0, 0.05);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- glRasterPos2f(rect.xmin, rect.ymin);
+ glColor4f(1, 1, 1, 1);
+ glPixelTransferf(GL_RED_BIAS, 1);
+ glPixelTransferf(GL_GREEN_BIAS, 1);
+ glPixelTransferf(GL_BLUE_BIAS, 1);
- glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixel_buf);
+ GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR);
+ glEnable(GL_BLEND);
+ glaDrawPixelsTex(rect.xmin, rect.ymin, w, h, GL_ALPHA, GL_UNSIGNED_BYTE, GL_NEAREST, pixel_buf);
glDisable(GL_BLEND);
+
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+
+ glPixelTransferf(GL_RED_BIAS, 0);
+ glPixelTransferf(GL_GREEN_BIAS, 0);
+ glPixelTransferf(GL_BLUE_BIAS, 0);
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+
MEM_freeN(pixel_buf);
}
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 6300d2ed3c7..c11c398c616 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -40,6 +40,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_genfile.h"
#include "DNA_scene_types.h"
#include "DNA_userdef_types.h"
#include "DNA_windowmanager_types.h"
@@ -61,6 +62,7 @@
#include "BKE_global.h"
#include "BKE_icons.h"
#include "BKE_library.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_mball_tessellate.h"
#include "BKE_node.h"
@@ -140,6 +142,11 @@ static void wm_free_reports(bContext *C)
BKE_reports_clear(reports);
}
+static void wm_undo_kill_callback(bContext *C)
+{
+ WM_jobs_kill_all_except(CTX_wm_manager(C), CTX_wm_screen(C));
+}
+
bool wm_start_with_console = false; /* used in creator.c */
/* only called once, for startup */
@@ -158,11 +165,13 @@ void WM_init(bContext *C, int argc, const char **argv)
WM_menutype_init();
WM_uilisttype_init();
+ BKE_undo_callback_wm_kill_jobs_set(wm_undo_kill_callback);
+
BKE_library_callback_free_window_manager_set(wm_close_and_free); /* library.c */
BKE_library_callback_free_notifier_reference_set(WM_main_remove_notifier_reference); /* library.c */
- BKE_library_callback_free_editor_id_reference_set(WM_main_remove_editor_id_reference); /* library.c */
+ BKE_library_callback_remap_editor_id_reference_set(WM_main_remap_editor_id_reference); /* library.c */
BKE_blender_callback_test_break_set(wm_window_testbreak); /* blender.c */
- BKE_spacedata_callback_id_unref_set(ED_spacedata_id_unref); /* screen.c */
+ BKE_spacedata_callback_id_remap_set(ED_spacedata_id_remap); /* screen.c */
DAG_editors_update_cb(ED_render_id_flush_update,
ED_render_scene_update,
ED_render_scene_update_pre); /* depsgraph.c */
@@ -189,8 +198,11 @@ void WM_init(bContext *C, int argc, const char **argv)
BLT_lang_set(NULL);
if (!G.background) {
+
+#ifdef WITH_INPUT_NDOF
/* sets 3D mouse deadzone */
WM_ndof_deadzone_set(U.ndof_deadzone);
+#endif
GPU_init();
@@ -515,7 +527,6 @@ void WM_exit_ext(bContext *C, const bool do_python)
ANIM_fmodifiers_copybuf_free();
ED_gpencil_anim_copybuf_free();
ED_gpencil_strokes_copybuf_free();
- ED_clipboard_posebuf_free();
BKE_node_clipboard_clear();
BLF_exit();
@@ -533,7 +544,7 @@ void WM_exit_ext(bContext *C, const bool do_python)
#ifdef WITH_PYTHON
/* option not to close python so we can use 'atexit' */
- if (do_python) {
+ if (do_python && ((C == NULL) || CTX_py_init_get(C))) {
/* XXX - old note */
/* before BKE_blender_free so py's gc happens while library still exists */
/* needed at least for a rare sigsegv that can happen in pydrivers */
@@ -576,8 +587,12 @@ void WM_exit_ext(bContext *C, const bool do_python)
GHOST_DisposeSystemPaths();
+ DNA_sdna_current_free();
+
BLI_threadapi_exit();
+ BKE_blender_atexit();
+
if (MEM_get_memory_blocks_in_use() != 0) {
size_t mem_in_use = MEM_get_memory_in_use() + MEM_get_memory_in_use();
printf("Error: Not freed memory blocks: %u, total unfreed memory %f MB\n",
diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index 72b26cc6207..e201fa433d4 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -77,6 +77,10 @@ static wmKeyMapItem *wm_keymap_item_copy(wmKeyMapItem *kmi)
kmin->properties = IDP_CopyProperty(kmin->properties);
kmin->ptr->data = kmin->properties;
}
+ else {
+ kmin->properties = NULL;
+ kmin->ptr = NULL;
+ }
return kmin;
}
@@ -87,6 +91,8 @@ static void wm_keymap_item_free(wmKeyMapItem *kmi)
if (kmi->ptr) {
WM_operator_properties_free(kmi->ptr);
MEM_freeN(kmi->ptr);
+ kmi->ptr = NULL;
+ kmi->properties = NULL;
}
}
@@ -120,7 +126,7 @@ static void wm_keymap_item_properties_update_ot(wmKeyMapItem *kmi)
}
else {
/* zombie keymap item */
- MEM_SAFE_FREE(kmi->ptr);
+ wm_keymap_item_free(kmi);
}
}
}
@@ -1787,7 +1793,17 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
}
/* UV Editor */
else if (STRPREFIX(opname, "UV_OT")) {
- km = WM_keymap_find_all(C, "UV Editor", 0, 0);
+ /* Hack to allow using UV unwrapping ops from 3DView/editmode.
+ * Mesh keymap is probably not ideal, but best place I could find to put those. */
+ if (sl->spacetype == SPACE_VIEW3D) {
+ km = WM_keymap_find_all(C, "Mesh", 0, 0);
+ if (km && km->poll && !km->poll((bContext *)C)) {
+ km = NULL;
+ }
+ }
+ if (!km) {
+ km = WM_keymap_find_all(C, "UV Editor", 0, 0);
+ }
}
/* Node Editor */
else if (STRPREFIX(opname, "NODE_OT")) {
diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c
index 7ec2aea73e1..18836f34c99 100644
--- a/source/blender/windowmanager/intern/wm_operator_props.c
+++ b/source/blender/windowmanager/intern/wm_operator_props.c
@@ -97,6 +97,8 @@ void WM_operator_properties_filesel(
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "filter_collada", (filter & FILE_TYPE_COLLADA) != 0, "Filter COLLADA files", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "filter_alembic", (filter & FILE_TYPE_ALEMBIC) != 0, "Filter Alembic files", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "filter_folder", (filter & FILE_TYPE_FOLDER) != 0, "Filter folders", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "filter_blenlib", (filter & FILE_TYPE_BLENDERLIB) != 0, "Filter Blender IDs", "");
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 37919a79e16..b9fd4d2e762 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -1068,7 +1068,7 @@ int WM_operator_smooth_viewtx_get(const wmOperator *op)
}
/* invoke callback, uses enum property named "type" */
-int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+int WM_menu_invoke_ex(bContext *C, wmOperator *op, int opcontext)
{
PropertyRNA *prop = op->type->prop;
uiPopupMenu *pup;
@@ -1090,8 +1090,8 @@ int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
pup = UI_popup_menu_begin(C, RNA_struct_ui_name(op->type->srna), ICON_NONE);
layout = UI_popup_menu_layout(pup);
/* set this so the default execution context is the same as submenus */
- uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_REGION_WIN);
- uiItemsFullEnumO(layout, op->type->idname, RNA_property_identifier(prop), op->ptr->data, WM_OP_EXEC_REGION_WIN, 0);
+ uiLayoutSetOperatorContext(layout, opcontext);
+ uiItemsFullEnumO(layout, op->type->idname, RNA_property_identifier(prop), op->ptr->data, opcontext, 0);
UI_popup_menu_end(C, pup);
return OPERATOR_INTERFACE;
}
@@ -1099,6 +1099,11 @@ int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
return OPERATOR_CANCELLED;
}
+int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ return WM_menu_invoke_ex(C, op, WM_OP_INVOKE_REGION_WIN);
+}
+
/* generic enum search invoke popup */
static uiBlock *wm_enum_search_menu(bContext *C, ARegion *ar, void *arg_op)
@@ -1364,12 +1369,13 @@ typedef struct wmOpPopUp {
/* Only invoked by OK button in popups created with wm_block_dialog_create() */
static void dialog_exec_cb(bContext *C, void *arg1, void *arg2)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- wmWindow *win = CTX_wm_window(C);
-
wmOpPopUp *data = arg1;
uiBlock *block = arg2;
+ /* Explicitly set UI_RETURN_OK flag, otherwise the menu might be cancelled
+ * in case WM_operator_call_ex exits/reloads the current file (T49199). */
+ UI_popup_menu_retval_set(block, UI_RETURN_OK, true);
+
WM_operator_call_ex(C, data->op, true);
/* let execute handle freeing it */
@@ -1379,14 +1385,24 @@ static void dialog_exec_cb(bContext *C, void *arg1, void *arg2)
/* in this case, wm_operator_ui_popup_cancel wont run */
MEM_freeN(data);
+ /* get context data *after* WM_operator_call_ex which might have closed the current file and changed context */
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
+
/* check window before 'block->handle' incase the
- * popup execution closed the window and freed the block. see T44688. */
+ * popup execution closed the window and freed the block. see T44688.
+ */
+ /* Post 2.78 TODO: Check if this fix and others related to T44688 are still
+ * needed or can be improved now that requesting context data has been corrected
+ * (see above). We're close to release so not a good time for experiments.
+ * -- Julian
+ */
if (BLI_findindex(&wm->windows, win) != -1) {
UI_popup_block_close(C, win, block);
}
}
-static void dialog_check_cb(bContext *C, void *op_ptr, void *UNUSED(arg))
+static void popup_check_cb(bContext *C, void *op_ptr, void *UNUSED(arg))
{
wmOperator *op = op_ptr;
if (op->type->check) {
@@ -1418,7 +1434,7 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *ar, void *userData)
layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style);
- UI_block_func_set(block, dialog_check_cb, op, NULL);
+ UI_block_func_set(block, popup_check_cb, op, NULL);
uiLayoutOperatorButs(C, layout, op, NULL, 'H', UI_LAYOUT_OP_SHOW_TITLE);
@@ -1458,9 +1474,13 @@ static uiBlock *wm_operator_ui_create(bContext *C, ARegion *ar, void *userData)
layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style);
+ UI_block_func_set(block, popup_check_cb, op, NULL);
+
/* since ui is defined the auto-layout args are not used */
uiLayoutOperatorButs(C, layout, op, NULL, 'V', 0);
+ UI_block_func_set(block, NULL, NULL, NULL);
+
UI_block_bounds_set_popup(block, 4, 0, 0);
return block;
@@ -2279,6 +2299,11 @@ int WM_border_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
+#ifdef WITH_INPUT_NDOF
+ else if (event->type == NDOF_MOTION) {
+ return OPERATOR_PASS_THROUGH;
+ }
+#endif
// /* Allow view navigation??? */
// else {
// return OPERATOR_PASS_THROUGH;
@@ -2393,6 +2418,11 @@ int WM_gesture_circle_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_FINISHED; /* use finish or we don't get an undo */
}
}
+#ifdef WITH_INPUT_NDOF
+ else if (event->type == NDOF_MOTION) {
+ return OPERATOR_PASS_THROUGH;
+ }
+#endif
/* Allow view navigation??? */
/* note, this gives issues: 1) other modal ops run on top (border select), 2) middlemouse is used now 3) tablet/trackpad? */
// else {
@@ -2842,10 +2872,9 @@ void WM_OT_straightline_gesture(wmOperatorType *ot)
/* *********************** radial control ****************** */
-#define WM_RADIAL_CONTROL_DISPLAY_SIZE (200 * U.pixelsize)
-#define WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE (35 * U.pixelsize)
+#define WM_RADIAL_CONTROL_DISPLAY_SIZE (200 * UI_DPI_FAC)
+#define WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE (35 * UI_DPI_FAC)
#define WM_RADIAL_CONTROL_DISPLAY_WIDTH (WM_RADIAL_CONTROL_DISPLAY_SIZE - WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE)
-#define WM_RADIAL_CONTROL_HEADER_LENGTH 180
#define WM_RADIAL_MAX_STR 10
typedef struct {
@@ -2871,7 +2900,7 @@ typedef struct {
static void radial_control_update_header(wmOperator *op, bContext *C)
{
RadialControl *rc = op->customdata;
- char msg[WM_RADIAL_CONTROL_HEADER_LENGTH];
+ char msg[UI_MAX_DRAW_STR];
ScrArea *sa = CTX_wm_area(C);
Scene *scene = CTX_data_scene(C);
@@ -2879,34 +2908,33 @@ static void radial_control_update_header(wmOperator *op, bContext *C)
if (hasNumInput(&rc->num_input)) {
char num_str[NUM_STR_REP_LEN];
outputNumInput(&rc->num_input, num_str, &scene->unit);
- BLI_snprintf(msg, WM_RADIAL_CONTROL_HEADER_LENGTH, "%s: %s", RNA_property_ui_name(rc->prop), num_str);
- ED_area_headerprint(sa, msg);
+ BLI_snprintf(msg, sizeof(msg), "%s: %s", RNA_property_ui_name(rc->prop), num_str);
}
else {
const char *ui_name = RNA_property_ui_name(rc->prop);
switch (rc->subtype) {
case PROP_NONE:
case PROP_DISTANCE:
- BLI_snprintf(msg, WM_RADIAL_CONTROL_HEADER_LENGTH, "%s: %0.4f", ui_name, rc->current_value);
+ BLI_snprintf(msg, sizeof(msg), "%s: %0.4f", ui_name, rc->current_value);
break;
case PROP_PIXEL:
- BLI_snprintf(msg, WM_RADIAL_CONTROL_HEADER_LENGTH, "%s: %d", ui_name, (int)rc->current_value); /* XXX: round to nearest? */
+ BLI_snprintf(msg, sizeof(msg), "%s: %d", ui_name, (int)rc->current_value); /* XXX: round to nearest? */
break;
case PROP_PERCENTAGE:
- BLI_snprintf(msg, WM_RADIAL_CONTROL_HEADER_LENGTH, "%s: %3.1f%%", ui_name, rc->current_value);
+ BLI_snprintf(msg, sizeof(msg), "%s: %3.1f%%", ui_name, rc->current_value);
break;
case PROP_FACTOR:
- BLI_snprintf(msg, WM_RADIAL_CONTROL_HEADER_LENGTH, "%s: %1.3f", ui_name, rc->current_value);
+ BLI_snprintf(msg, sizeof(msg), "%s: %1.3f", ui_name, rc->current_value);
break;
case PROP_ANGLE:
- BLI_snprintf(msg, WM_RADIAL_CONTROL_HEADER_LENGTH, "%s: %3.2f", ui_name, RAD2DEGF(rc->current_value));
+ BLI_snprintf(msg, sizeof(msg), "%s: %3.2f", ui_name, RAD2DEGF(rc->current_value));
break;
default:
- BLI_snprintf(msg, WM_RADIAL_CONTROL_HEADER_LENGTH, "%s", ui_name); /* XXX: No value? */
+ BLI_snprintf(msg, sizeof(msg), "%s", ui_name); /* XXX: No value? */
break;
}
- ED_area_headerprint(sa, msg);
}
+ ED_area_headerprint(sa, msg);
}
}
@@ -2922,7 +2950,7 @@ static void radial_control_set_initial_mouse(RadialControl *rc, const wmEvent *e
case PROP_NONE:
case PROP_DISTANCE:
case PROP_PIXEL:
- d[0] = rc->initial_value * U.pixelsize;
+ d[0] = rc->initial_value;
break;
case PROP_PERCENTAGE:
d[0] = (rc->initial_value) / 100.0f * WM_RADIAL_CONTROL_DISPLAY_WIDTH + WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
@@ -3048,8 +3076,8 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd
case PROP_NONE:
case PROP_DISTANCE:
case PROP_PIXEL:
- r1 = rc->current_value * U.pixelsize;
- r2 = rc->initial_value * U.pixelsize;
+ r1 = rc->current_value;
+ r2 = rc->initial_value;
tex_radius = r1;
alpha = 0.75;
break;
@@ -3122,7 +3150,7 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd
if (rmin > 0.0f)
glutil_draw_lined_arc(0.0, (float)(M_PI * 2.0), rmin, 40);
- BLF_size(fontid, 1.5 * fstyle_points, 1.0f / U.dpi);
+ BLF_size(fontid, 1.5 * fstyle_points * U.pixelsize, U.dpi);
BLF_enable(fontid, BLF_SHADOW);
BLF_shadow(fontid, 3, (const float[4]){0.0f, 0.0f, 0.0f, 0.5f});
BLF_shadow_offset(fontid, 1, -1);
@@ -3531,7 +3559,6 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even
case PROP_PIXEL:
new_value = dist;
if (snap) new_value = ((int)new_value + 5) / 10 * 10;
- new_value /= U.pixelsize;
break;
case PROP_PERCENTAGE:
new_value = ((dist - WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE) / WM_RADIAL_CONTROL_DISPLAY_WIDTH) * 100.0f;
@@ -3877,7 +3904,7 @@ static void previews_id_ensure(bContext *C, Scene *scene, ID *id)
/* Only preview non-library datablocks, lib ones do not pertain to this .blend file!
* Same goes for ID with no user. */
- if (!id->lib && (id->us != 0)) {
+ if (!ID_IS_LINKED_DATABLOCK(id) && (id->us != 0)) {
UI_id_icon_render(C, scene, id, false, false);
UI_id_icon_render(C, scene, id, true, false);
}
@@ -3936,9 +3963,9 @@ static int previews_ensure_exec(bContext *C, wmOperator *UNUSED(op))
static void WM_OT_previews_ensure(wmOperatorType *ot)
{
- ot->name = "Refresh DataBlock Previews";
+ ot->name = "Refresh Data-Block Previews";
ot->idname = "WM_OT_previews_ensure";
- ot->description = "Ensure datablock previews are available and up-to-date "
+ ot->description = "Ensure data-block previews are available and up-to-date "
"(to be saved in .blend file, only for some types like materials, textures, etc.)";
ot->exec = previews_ensure_exec;
@@ -3995,9 +4022,9 @@ static int previews_clear_exec(bContext *C, wmOperator *op)
static void WM_OT_previews_clear(wmOperatorType *ot)
{
- ot->name = "Clear DataBlock Previews";
+ ot->name = "Clear Data-Block Previews";
ot->idname = "WM_OT_previews_clear";
- ot->description = "Clear datablock previews (only for some types like objects, materials, textures, etc.)";
+ ot->description = "Clear data-block previews (only for some types like objects, materials, textures, etc.)";
ot->exec = previews_clear_exec;
ot->invoke = WM_menu_invoke;
@@ -4005,7 +4032,7 @@ static void WM_OT_previews_clear(wmOperatorType *ot)
ot->prop = RNA_def_enum_flag(ot->srna, "id_type", preview_id_type_items,
FILTER_ID_SCE | FILTER_ID_OB | FILTER_ID_GR |
FILTER_ID_MA | FILTER_ID_LA | FILTER_ID_WO | FILTER_ID_TE | FILTER_ID_IM,
- "DataBlock Type", "Which datablock previews to clear");
+ "Data-Block Type", "Which data-block previews to clear");
}
/* *************************** Doc from UI ************* */
@@ -4120,6 +4147,8 @@ void wm_operatortype_init(void)
WM_operatortype_append(WM_OT_revert_mainfile);
WM_operatortype_append(WM_OT_link);
WM_operatortype_append(WM_OT_append);
+ WM_operatortype_append(WM_OT_lib_relocate);
+ WM_operatortype_append(WM_OT_lib_reload);
WM_operatortype_append(WM_OT_recover_last_session);
WM_operatortype_append(WM_OT_recover_auto_save);
WM_operatortype_append(WM_OT_save_as_mainfile);
@@ -4199,7 +4228,8 @@ static void gesture_circle_modal_keymap(wmKeyConfig *keyconf)
WM_modalkeymap_assign(keymap, "MASK_OT_select_circle");
WM_modalkeymap_assign(keymap, "NODE_OT_select_circle");
WM_modalkeymap_assign(keymap, "GPENCIL_OT_select_circle");
- WM_modalkeymap_assign(keymap, "GRAPH_OT_select_circle");
+ WM_modalkeymap_assign(keymap, "GRAPH_OT_select_circle");
+ WM_modalkeymap_assign(keymap, "ACTION_OT_select_circle");
}
@@ -4339,7 +4369,6 @@ void wm_window_keymap(wmKeyConfig *keyconf)
{
wmKeyMap *keymap = WM_keymap_find(keyconf, "Window", 0, 0);
wmKeyMapItem *kmi;
- const char *data_path;
/* note, this doesn't replace existing keymap items */
WM_keymap_verify_item(keymap, "WM_OT_window_duplicate", WKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
@@ -4377,7 +4406,9 @@ void wm_window_keymap(wmKeyConfig *keyconf)
/* menus that can be accessed anywhere in blender */
WM_keymap_verify_item(keymap, "WM_OT_search_menu", SPACEKEY, KM_PRESS, 0, 0);
+#ifdef WITH_INPUT_NDOF
WM_keymap_add_menu(keymap, "USERPREF_MT_ndof_settings", NDOF_BUTTON_MENU, KM_PRESS, 0, 0);
+#endif
/* Space switching */
kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F2KEY, KM_PRESS, KM_SHIFT, 0); /* new in 2.5x, was DXF export */
@@ -4424,8 +4455,9 @@ void wm_window_keymap(wmKeyConfig *keyconf)
RNA_string_set(kmi->ptr, "data_path", "area.type");
RNA_string_set(kmi->ptr, "value", "DOPESHEET_EDITOR");
+#ifdef WITH_INPUT_NDOF
/* ndof speed */
- data_path = "user_preferences.inputs.ndof_sensitivity";
+ const char *data_path = "user_preferences.inputs.ndof_sensitivity";
kmi = WM_keymap_add_item(keymap, "WM_OT_context_scale_float", NDOF_BUTTON_PLUS, KM_PRESS, 0, 0);
RNA_string_set(kmi->ptr, "data_path", data_path);
RNA_float_set(kmi->ptr, "value", 1.1f);
@@ -4441,9 +4473,7 @@ void wm_window_keymap(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "WM_OT_context_scale_float", NDOF_BUTTON_MINUS, KM_PRESS, KM_SHIFT, 0);
RNA_string_set(kmi->ptr, "data_path", data_path);
RNA_float_set(kmi->ptr, "value", 1.0f / 1.5f);
- data_path = NULL;
- (void)data_path;
-
+#endif /* WITH_INPUT_NDOF */
gesture_circle_modal_keymap(keyconf);
gesture_border_modal_keymap(keyconf);
@@ -4459,7 +4489,7 @@ static EnumPropertyItem *rna_id_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(pt
int i = 0;
for (; id; id = id->next) {
- if (local == false || id->lib == NULL) {
+ if (local == false || !ID_IS_LINKED_DATABLOCK(id)) {
item_tmp.identifier = item_tmp.name = id->name + 2;
item_tmp.value = i++;
RNA_enum_item_add(&item, &totitem, &item_tmp);
diff --git a/source/blender/windowmanager/intern/wm_stereo.c b/source/blender/windowmanager/intern/wm_stereo.c
index 5576a104123..1c1c2ad35af 100644
--- a/source/blender/windowmanager/intern/wm_stereo.c
+++ b/source/blender/windowmanager/intern/wm_stereo.c
@@ -168,7 +168,6 @@ static void wm_method_draw_stereo3d_sidebyside(wmWindow *win)
wmDrawData *drawdata;
wmDrawTriple *triple;
float halfx, halfy, ratiox, ratioy;
- float alpha = 1.0f;
int view;
int soffx;
bool cross_eyed = (win->stereo3d_format->flag & S3D_SIDEBYSIDE_CROSSEYED) != 0;
@@ -187,8 +186,6 @@ static void wm_method_draw_stereo3d_sidebyside(wmWindow *win)
soffx = 0;
}
- glEnable(triple->target);
-
const int sizex = triple->x;
const int sizey = triple->y;
@@ -206,9 +203,10 @@ static void wm_method_draw_stereo3d_sidebyside(wmWindow *win)
halfy /= triple->y;
}
+ glEnable(triple->target);
glBindTexture(triple->target, triple->bind);
- glColor4f(1.0f, 1.0f, 1.0f, alpha);
+ glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glBegin(GL_QUADS);
glTexCoord2f(halfx, halfy);
glVertex2f(soffx, 0);
@@ -225,7 +223,6 @@ static void wm_method_draw_stereo3d_sidebyside(wmWindow *win)
glBindTexture(triple->target, 0);
glDisable(triple->target);
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
}
}
@@ -234,7 +231,6 @@ static void wm_method_draw_stereo3d_topbottom(wmWindow *win)
wmDrawData *drawdata;
wmDrawTriple *triple;
float halfx, halfy, ratiox, ratioy;
- float alpha = 1.0f;
int view;
int soffy;
@@ -249,8 +245,6 @@ static void wm_method_draw_stereo3d_topbottom(wmWindow *win)
soffy = 0;
}
- glEnable(triple->target);
-
const int sizex = triple->x;
const int sizey = triple->y;
@@ -268,9 +262,10 @@ static void wm_method_draw_stereo3d_topbottom(wmWindow *win)
halfy /= triple->y;
}
+ glEnable(triple->target);
glBindTexture(triple->target, triple->bind);
- glColor4f(1.0f, 1.0f, 1.0f, alpha);
+ glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glBegin(GL_QUADS);
glTexCoord2f(halfx, halfy);
glVertex2f(0, soffy);
@@ -287,7 +282,6 @@ static void wm_method_draw_stereo3d_topbottom(wmWindow *win)
glBindTexture(triple->target, 0);
glDisable(triple->target);
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
}
}
diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c
index 6526d419914..458ac4a121a 100644
--- a/source/blender/windowmanager/intern/wm_subwindow.c
+++ b/source/blender/windowmanager/intern/wm_subwindow.c
@@ -378,149 +378,5 @@ void wmOrtho2_pixelspace(const float x, const float y)
wmOrtho2_offset(x, y, -GLA_PIXEL_OFS);
}
-/* *************************** Framebuffer color depth, for selection codes ********************** */
-
-#ifdef __APPLE__
-
-/* apple seems to round colors to below and up on some configs */
-
-unsigned int index_to_framebuffer(int index)
-{
- unsigned int i = index;
-
- switch (GPU_color_depth()) {
- case 12:
- i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4);
- /* sometimes dithering subtracts! */
- i |= 0x070707;
- break;
- case 15:
- case 16:
- i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3);
- i |= 0x030303;
- break;
- case 24:
- break;
- default: /* 18 bits... */
- i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2);
- i |= 0x010101;
- break;
- }
-
- return i;
-}
-
-#else
-
-/* this is the old method as being in use for ages.... seems to work? colors are rounded to lower values */
-
-unsigned int index_to_framebuffer(int index)
-{
- unsigned int i = index;
-
- switch (GPU_color_depth()) {
- case 8:
- i = ((i & 48) << 18) + ((i & 12) << 12) + ((i & 3) << 6);
- i |= 0x3F3F3F;
- break;
- case 12:
- i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4);
- /* sometimes dithering subtracts! */
- i |= 0x0F0F0F;
- break;
- case 15:
- case 16:
- i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3);
- i |= 0x070707;
- break;
- case 24:
- break;
- default: /* 18 bits... */
- i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2);
- i |= 0x030303;
- break;
- }
-
- return i;
-}
-
-#endif
-
-void WM_framebuffer_index_set(int index)
-{
- const int col = index_to_framebuffer(index);
- cpack(col);
-}
-
-void WM_framebuffer_index_get(int index, int *r_col)
-{
- const int col = index_to_framebuffer(index);
- char *c_col = (char *)r_col;
- c_col[0] = (col & 0xFF); /* red */
- c_col[1] = ((col >> 8) & 0xFF); /* green */
- c_col[2] = ((col >> 16) & 0xFF); /* blue */
- c_col[3] = 0xFF; /* alpha */
-}
-
-
-
-#define INDEX_FROM_BUF_8(col) (((col & 0xC00000) >> 18) + ((col & 0xC000) >> 12) + ((col & 0xC0) >> 6))
-#define INDEX_FROM_BUF_12(col) (((col & 0xF00000) >> 12) + ((col & 0xF000) >> 8) + ((col & 0xF0) >> 4))
-#define INDEX_FROM_BUF_15_16(col) (((col & 0xF80000) >> 9) + ((col & 0xF800) >> 6) + ((col & 0xF8) >> 3))
-#define INDEX_FROM_BUF_18(col) (((col & 0xFC0000) >> 6) + ((col & 0xFC00) >> 4) + ((col & 0xFC) >> 2))
-#define INDEX_FROM_BUF_24(col) (col & 0xFFFFFF)
-
-int WM_framebuffer_to_index(unsigned int col)
-{
- if (col == 0) {
- return 0;
- }
-
- switch (GPU_color_depth()) {
- case 8: return INDEX_FROM_BUF_8(col);
- case 12: return INDEX_FROM_BUF_12(col);
- case 15:
- case 16: return INDEX_FROM_BUF_15_16(col);
- case 24: return INDEX_FROM_BUF_24(col);
- default: return INDEX_FROM_BUF_18(col);
- }
-}
-
-void WM_framebuffer_to_index_array(unsigned int *col, const unsigned int size)
-{
-#define INDEX_BUF_ARRAY(INDEX_FROM_BUF_BITS) \
- for (i = size; i--; col++) { \
- if ((c = *col)) { \
- *col = INDEX_FROM_BUF_BITS(c); \
- } \
- } ((void)0)
-
- if (size > 0) {
- unsigned int i, c;
-
- switch (GPU_color_depth()) {
- case 8:
- INDEX_BUF_ARRAY(INDEX_FROM_BUF_8);
- break;
- case 12:
- INDEX_BUF_ARRAY(INDEX_FROM_BUF_12);
- break;
- case 15:
- case 16:
- INDEX_BUF_ARRAY(INDEX_FROM_BUF_15_16);
- break;
- case 24:
- INDEX_BUF_ARRAY(INDEX_FROM_BUF_24);
- break;
- default:
- INDEX_BUF_ARRAY(INDEX_FROM_BUF_18);
- break;
- }
- }
-
-#undef INDEX_BUF_ARRAY
-}
-
-
/* ********** END MY WINDOW ************** */
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 42f6585f152..2d43c47679d 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -69,6 +69,8 @@
#include "ED_screen.h"
#include "ED_fileselect.h"
+#include "UI_interface.h"
+
#include "PIL_time.h"
#include "GPU_draw.h"
@@ -1194,14 +1196,30 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
break;
}
case GHOST_kEventNativeResolutionChange:
- // printf("change, pixel size %f\n", GHOST_GetNativePixelSize(win->ghostwin));
-
+ {
+ // only update if the actual pixel size changes
+ float prev_pixelsize = U.pixelsize;
U.pixelsize = wm_window_pixelsize(win);
- BKE_blender_userdef_refresh();
- WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
- WM_event_add_notifier(C, NC_WINDOW | NA_EDITED, NULL);
+
+ if (U.pixelsize != prev_pixelsize) {
+ BKE_blender_userdef_refresh();
+
+ // close all popups since they are positioned with the pixel
+ // size baked in and it's difficult to correct them
+ wmWindow *oldWindow = CTX_wm_window(C);
+ CTX_wm_window_set(C, win);
+ UI_popup_handlers_remove_all(C, &win->modalhandlers);
+ CTX_wm_window_set(C, oldWindow);
+
+ wm_window_make_drawable(wm, win);
+ wm_draw_window_clear(win);
+
+ WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_WINDOW | NA_EDITED, NULL);
+ }
break;
+ }
case GHOST_kEventTrackpad:
{
GHOST_TEventTrackpadData *pd = data;
diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h
index 449612bc5fd..3085f138846 100644
--- a/source/blender/windowmanager/wm_event_types.h
+++ b/source/blender/windowmanager/wm_event_types.h
@@ -311,14 +311,17 @@ enum {
TIMERNOTIFIER = 0x0118, /* timer event, notifier sender */
TIMERF = 0x011F, /* last timer */
- /* Tweak, gestures: 0x500x, 0x501x */
+ /* Actionzones, tweak, gestures: 0x500x, 0x501x */
EVT_ACTIONZONE_AREA = 0x5000,
EVT_ACTIONZONE_REGION = 0x5001,
EVT_ACTIONZONE_FULLSCREEN = 0x5011,
/* NOTE: these values are saved in keymap files, do not change them but just add new ones */
- /* tweak events, for L M R mousebuttons */
+ /* Tweak events:
+ * Sent as additional event with the mouse coordinates from where the initial click was placed. */
+
+ /* tweak events for L M R mousebuttons */
EVT_TWEAK_L = 0x5002,
EVT_TWEAK_M = 0x5003,
EVT_TWEAK_R = 0x5004,
@@ -343,37 +346,38 @@ enum {
/* *********** wmEvent.type helpers. ********** */
/* test whether the event is timer event */
-#define ISTIMER(event_type) (event_type >= TIMER && event_type <= TIMERF)
+#define ISTIMER(event_type) ((event_type) >= TIMER && (event_type) <= TIMERF)
/* for event checks */
/* only used for KM_TEXTINPUT, so assume that we want all user-inputtable ascii codes included */
/* UNUSED - see wm_eventmatch - BUG [#30479] */
-/* #define ISTEXTINPUT(event_type) (event_type >= ' ' && event_type <= 255) */
+/* #define ISTEXTINPUT(event_type) ((event_type) >= ' ' && (event_type) <= 255) */
/* note, an alternative could be to check 'event->utf8_buf' */
/* test whether the event is a key on the keyboard */
#define ISKEYBOARD(event_type) \
- ((event_type >= 0x0020 && event_type <= 0x00ff) || \
- (event_type >= 0x012c && event_type <= 0x013f))
+ (((event_type) >= 0x0020 && (event_type) <= 0x00ff) || \
+ ((event_type) >= 0x012c && (event_type) <= 0x013f))
/* test whether the event is a modifier key */
-#define ISKEYMODIFIER(event_type) ((event_type >= LEFTCTRLKEY && event_type <= LEFTSHIFTKEY) || event_type == OSKEY)
+#define ISKEYMODIFIER(event_type) \
+ (((event_type) >= LEFTCTRLKEY && (event_type) <= LEFTSHIFTKEY) || (event_type) == OSKEY)
/* test whether the event is a mouse button */
-#define ISMOUSE(event_type) (event_type >= LEFTMOUSE && event_type <= BUTTON7MOUSE)
+#define ISMOUSE(event_type) ((event_type) >= LEFTMOUSE && (event_type) <= BUTTON7MOUSE)
/* test whether the event is tweak event */
-#define ISTWEAK(event_type) (event_type >= EVT_TWEAK_L && event_type <= EVT_GESTURE)
+#define ISTWEAK(event_type) ((event_type) >= EVT_TWEAK_L && (event_type) <= EVT_GESTURE)
/* test whether the event is a NDOF event */
-#define ISNDOF(event_type) (event_type >= NDOF_MOTION && event_type < NDOF_LAST)
+#define ISNDOF(event_type) ((event_type) >= NDOF_MOTION && (event_type) < NDOF_LAST)
/* test whether event type is acceptable as hotkey, excluding modifiers */
#define ISHOTKEY(event_type) \
((ISKEYBOARD(event_type) || ISMOUSE(event_type) || ISNDOF(event_type)) && \
- (event_type != ESCKEY) && \
- (event_type >= LEFTCTRLKEY && event_type <= LEFTSHIFTKEY) == false && \
- (event_type >= UNKNOWNKEY && event_type <= GRLESSKEY) == false)
+ ((event_type) != ESCKEY) && \
+ ((event_type) >= LEFTCTRLKEY && (event_type) <= LEFTSHIFTKEY) == false && \
+ ((event_type) >= UNKNOWNKEY && (event_type) <= GRLESSKEY) == false)
/* internal helpers*/
#define _VA_IS_EVENT_MOD2(v, a) (CHECK_TYPE_INLINE(v, wmEvent *), \
diff --git a/source/blender/windowmanager/wm_files.h b/source/blender/windowmanager/wm_files.h
index 2eae9cdb012..396907a3f6d 100644
--- a/source/blender/windowmanager/wm_files.h
+++ b/source/blender/windowmanager/wm_files.h
@@ -59,5 +59,8 @@ void WM_OT_save_mainfile(struct wmOperatorType *ot);
void WM_OT_link(struct wmOperatorType *ot);
void WM_OT_append(struct wmOperatorType *ot);
+void WM_OT_lib_relocate(struct wmOperatorType *ot);
+void WM_OT_lib_reload(struct wmOperatorType *ot);
+
#endif /* __WM_FILES_H__ */
diff --git a/source/blender/windowmanager/wm_subwindow.h b/source/blender/windowmanager/wm_subwindow.h
index 2a8118a726b..cc9abf87514 100644
--- a/source/blender/windowmanager/wm_subwindow.h
+++ b/source/blender/windowmanager/wm_subwindow.h
@@ -48,7 +48,5 @@ void wm_subwindow_matrix_get(wmWindow *win, int swinid, float mat[4][4]);
void wm_subwindow_rect_get(wmWindow *win, int swinid, struct rcti *r_rect);
void wm_subwindow_rect_set(wmWindow *win, int swinid, const rcti *rect);
-unsigned int index_to_framebuffer(int index);
-
#endif /* __WM_SUBWINDOW_H__ */
diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt
index 4b828408e45..58bebc66a3e 100644
--- a/source/blenderplayer/CMakeLists.txt
+++ b/source/blenderplayer/CMakeLists.txt
@@ -58,11 +58,13 @@ if(WIN32 AND NOT UNIX)
blenderplayer ${EXETYPE}
bad_level_call_stubs/stubs.c
${CMAKE_SOURCE_DIR}/release/windows/icons/winblender.rc)
-
+ WINDOWS_SIGN_TARGET(blenderplayer)
install(TARGETS blenderplayer
COMPONENT Blenderplayer
DESTINATION ".")
+add_cc_flags_custom_test(blenderplayer)
+
elseif(APPLE)
add_executable(blenderplayer ${EXETYPE} bad_level_call_stubs/stubs.c)
# setup Info.plist
@@ -111,7 +113,6 @@ endif()
ge_player_common
bf_intern_string
bf_intern_ghost
- bf_intern_ghostndof3dconnexion
bf_rna
bf_blenkernel
bf_depsgraph
@@ -216,6 +217,14 @@ endif()
list(APPEND BLENDER_SORTED_LIBS bf_intern_locale)
endif()
+ if(WITH_GAMEENGINE_DECKLINK)
+ list(APPEND BLENDER_SORTED_LIBS bf_intern_decklink)
+ endif()
+
+ if(WIN32)
+ list(APPEND BLENDER_SORTED_LIBS bf_intern_gpudirect)
+ endif()
+
if(WITH_OPENSUBDIV)
list(APPEND BLENDER_SORTED_LIBS bf_intern_opensubdiv)
endif()
@@ -224,6 +233,10 @@ endif()
list(APPEND BLENDER_SORTED_LIBS bf_intern_openvdb)
endif()
+ if(WITH_ALEMBIC)
+ list(APPEND BLENDER_SORTED_LIBS bf_alembic)
+ endif()
+
foreach(SORTLIB ${BLENDER_SORTED_LIBS})
set(REMLIB ${SORTLIB})
foreach(SEARCHLIB ${BLENDER_LINK_LIBS})
diff --git a/source/blenderplayer/bad_level_call_stubs/CMakeLists.txt b/source/blenderplayer/bad_level_call_stubs/CMakeLists.txt
index 1d681d28589..0e570e19258 100644
--- a/source/blenderplayer/bad_level_call_stubs/CMakeLists.txt
+++ b/source/blenderplayer/bad_level_call_stubs/CMakeLists.txt
@@ -70,4 +70,8 @@ if(WITH_FREESTYLE)
add_definitions(-DWITH_FREESTYLE)
endif()
+if(WITH_INPUT_NDOF)
+ add_definitions(-DWITH_INPUT_NDOF)
+endif()
+
blender_add_lib_nolist(blenkernel_blc "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c
index 3ce7788fdf8..d8a4ddc8d4f 100644
--- a/source/blenderplayer/bad_level_call_stubs/stubs.c
+++ b/source/blenderplayer/bad_level_call_stubs/stubs.c
@@ -45,6 +45,7 @@ struct ARegion;
struct ARegionType;
struct BMEditMesh;
struct Base;
+struct bContext;
struct BoundBox;
struct Brush;
struct CSG_FaceIteratorDescriptor;
@@ -111,6 +112,7 @@ struct bConstraint;
struct bConstraintOb;
struct bConstraintTarget;
struct bContextDataResult;
+struct bGPDlayer;
struct bNode;
struct bNodeType;
struct bNodeSocket;
@@ -153,6 +155,7 @@ struct wmWindowManager;
#include "../blender/editors/include/ED_clip.h"
#include "../blender/editors/include/ED_curve.h"
#include "../blender/editors/include/ED_fileselect.h"
+#include "../blender/editors/include/ED_gpencil.h"
#include "../blender/editors/include/ED_image.h"
#include "../blender/editors/include/ED_info.h"
#include "../blender/editors/include/ED_keyframes_edit.h"
@@ -246,7 +249,7 @@ bool RE_HasFakeLayer(RenderResult *res) RET_ZERO
/* zbuf.c stub */
void antialias_tagbuf(int xsize, int ysize, char *rectmove) RET_NONE
-void RE_zbuf_accumulate_vecblur(struct NodeBlurData *nbd, int xsize, int ysize, float *newrect, float *imgrect, float *vecbufrect, float *zbufrect) RET_NONE
+void RE_zbuf_accumulate_vecblur(struct NodeBlurData *nbd, int xsize, int ysize, float *newrect, const float *imgrect, float *vecbufrect, const float *zbufrect) RET_NONE
/* imagetexture.c stub */
void ibuf_sample(struct ImBuf *ibuf, float fx, float fy, float dx, float dy, float *result) RET_NONE
@@ -308,6 +311,8 @@ void WM_operator_handlers_clear(wmWindowManager *wm, struct wmOperatorType *ot)
void WM_autosave_init(wmWindowManager *wm) RET_NONE
void WM_jobs_kill_all_except(struct wmWindowManager *wm, void *owner) RET_NONE
+void WM_lib_reload(struct Library *lib, struct bContext *C, struct ReportList *reports) RET_NONE
+
char *WM_clipboard_text_get(bool selection, int *r_len) RET_NULL
char *WM_clipboard_text_get_firstline(bool selection, int *r_len) RET_NULL
void WM_clipboard_text_set(const char *buf, bool selection) RET_NONE
@@ -318,7 +323,22 @@ void WM_cursor_modal_restore(struct wmWindow *win) RET_NONE
void WM_cursor_time(struct wmWindow *win, int nr) RET_NONE
void WM_cursor_warp(struct wmWindow *win, int x, int y) RET_NONE
-void WM_ndof_deadzone_set(float deadzone) RET_NONE
+struct wmJob *WM_jobs_get(struct wmWindowManager *wm, struct wmWindow *win, void *owner, const char *name, int flag, int job_type) RET_NULL
+void WM_jobs_customdata_set(struct wmJob *job, void *customdata, void (*free)(void *)) RET_NONE
+void WM_jobs_timer(struct wmJob *job, double timestep, unsigned int note, unsigned int endnote) RET_NONE
+
+void WM_jobs_callbacks(struct wmJob *job,
+ void (*startjob)(void *, short *, short *, float *),
+ void (*initjob)(void *),
+ void (*update)(void *),
+ void (*endjob)(void *)) RET_NONE
+
+void WM_jobs_start(struct wmWindowManager *wm, struct wmJob *job) RET_NONE
+void WM_report(ReportType type, const char *message) RET_NONE
+
+#ifdef WITH_INPUT_NDOF
+ void WM_ndof_deadzone_set(float deadzone) RET_NONE
+#endif
void WM_uilisttype_init(void) RET_NONE
struct uiListType *WM_uilisttype_find(const char *idname, bool quiet) RET_NULL
@@ -326,8 +346,6 @@ bool WM_uilisttype_add(struct uiListType *ult) RET_ZERO
void WM_uilisttype_freelink(struct uiListType *ult) RET_NONE
void WM_uilisttype_free(void) RET_NONE
-void WM_framebuffer_index_get(int index, int *r_col) RET_NONE
-
struct wmKeyMapItem *WM_keymap_item_find_id(struct wmKeyMap *keymap, int id) RET_NULL
int WM_enum_search_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event) RET_ZERO
void WM_event_add_notifier(const struct bContext *C, unsigned int type, void *reference) RET_NONE
@@ -350,6 +368,7 @@ void *ED_region_draw_cb_activate(struct ARegionType *art, void(*draw)(const stru
void *ED_region_draw_cb_customdata(void *handle) RET_ZERO /* XXX This one looks wrong also */
void ED_region_draw_cb_exit(struct ARegionType *art, void *handle) RET_NONE
void ED_area_headerprint(struct ScrArea *sa, const char *str) RET_NONE
+void ED_gpencil_parent_location(struct bGPDlayer *gpl, float diff_mat[4][4]) RET_NONE
void UI_view2d_region_to_view(struct View2D *v2d, float x, float y, float *viewx, float *viewy) RET_NONE
bool UI_view2d_view_to_region_clip(struct View2D *v2d, float x, float y, int *regionx, int *regiony) RET_ZERO
void UI_view2d_view_to_region(struct View2D *v2d, float x, float y, int *regionx, int *region_y) RET_NONE
@@ -380,7 +399,7 @@ void ED_area_tag_redraw_regiontype(struct ScrArea *sa, int regiontype) RET_NONE
void ED_render_engine_changed(struct Main *bmain) RET_NONE
void ED_file_read_bookmarks(void) RET_NONE
-void ED_file_change_dir(struct bContext *C, const bool checkdir) RET_NONE
+void ED_file_change_dir(struct bContext *C) RET_NONE
void ED_preview_kill_jobs(struct wmWindowManager *wm, struct Main *bmain) RET_NONE
struct FSMenu *ED_fsmenu_get(void) RET_NULL
struct FSMenuEntry *ED_fsmenu_get_category(struct FSMenu *fsmenu, FSMenuCategory category) RET_NULL
@@ -526,10 +545,11 @@ SnapObjectContext *ED_transform_snap_object_context_create(
struct Main *bmain, struct Scene *scene, int flag) RET_NULL
SnapObjectContext *ED_transform_snap_object_context_create_view3d(
struct Main *bmain, struct Scene *scene, int flag,
- struct ARegion *ar, struct View3D *v3d) RET_NULL
+ const struct ARegion *ar, const struct View3D *v3d) RET_NULL
void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx) RET_NONE
bool ED_transform_snap_object_project_ray_ex(
struct SnapObjectContext *sctx,
+ const unsigned short snap_to,
const struct SnapObjectParams *params,
const float ray_start[3], const float ray_normal[3], float *ray_depth,
/* return args */
@@ -619,6 +639,7 @@ void uiTemplateComponentMenu(struct uiLayout *layout, struct PointerRNA *ptr, co
void uiTemplateNodeSocket(struct uiLayout *layout, struct bContext *C, float *color) RET_NONE
void uiTemplatePalette(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname, int color) RET_NONE
void uiTemplateImageStereo3d(struct uiLayout *layout, struct PointerRNA *stereo3d_format_ptr) RET_NONE
+void uiTemplateCacheFile(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname) RET_NONE
/* rna render */
struct RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername, const char *viewname) RET_NULL
@@ -712,6 +733,7 @@ int collada_export(struct Scene *sce,
int triangulate,
int use_object_instantiation,
+ int use_blender_profile,
int sort_by_name,
BC_export_transformation_type export_transformation_type,
int open_sim) RET_ZERO
@@ -724,7 +746,7 @@ void BPY_text_free_code(struct Text *text) RET_NONE
void BPY_id_release(struct ID *id) RET_NONE
int BPY_context_member_get(struct bContext *C, const char *member, struct bContextDataResult *result) RET_ZERO
void BPY_pyconstraint_target(struct bPythonConstraint *con, struct bConstraintTarget *ct) RET_NONE
-float BPY_driver_exec(struct ChannelDriver *driver, const float evaltime) RET_ZERO /* might need this one! */
+float BPY_driver_exec(PathResolvedRNA *anim_rna, struct ChannelDriver *driver, const float evaltime) RET_ZERO /* might need this one! */
void BPY_DECREF(void *pyob_ptr) RET_NONE
void BPY_pyconstraint_exec(struct bPythonConstraint *con, struct bConstraintOb *cob, struct ListBase *targets) RET_NONE
void macro_wrapper(struct wmOperatorType *ot, void *userdata) RET_NONE
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index daba01e33c7..f65688e1304 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -172,18 +172,28 @@ if(WITH_BUILDINFO)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
- # XXX, "_buildinfo.h" is used twice here,
+ # XXX, ${buildinfo_h_fake} is used here,
# because we rely on that file being detected as missing
# every build so that the real header "buildinfo.h" is updated.
#
# Keep this until we find a better way to resolve!
+ set(buildinfo_h_real "${CMAKE_CURRENT_BINARY_DIR}/buildinfo.h")
+ set(buildinfo_h_fake "${CMAKE_CURRENT_BINARY_DIR}/buildinfo.h_fake")
+
+ if(EXISTS ${buildinfo_h_fake})
+ message(FATAL_ERROR "File \"${buildinfo_h_fake}\" found, this should never be created, remove!")
+ endif()
+
# a custom target that is always built
add_custom_target(buildinfo ALL
- DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/_buildinfo.h)
+ DEPENDS ${buildinfo_h_fake})
# creates buildinfo.h using cmake script
- add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/_buildinfo.h
+ add_custom_command(
+ OUTPUT
+ ${buildinfo_h_fake} # ensure we always run
+ ${buildinfo_h_real}
COMMAND ${CMAKE_COMMAND}
-DSOURCE_DIR=${CMAKE_SOURCE_DIR}
# overrides only used when non-empty strings
@@ -192,10 +202,14 @@ if(WITH_BUILDINFO)
-P ${CMAKE_SOURCE_DIR}/build_files/cmake/buildinfo.cmake)
# buildinfo.h is a generated file
- set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/buildinfo.h
+ set_source_files_properties(
+ ${buildinfo_h_real}
PROPERTIES GENERATED TRUE
HEADER_FILE_ONLY TRUE)
+ unset(buildinfo_h_real)
+ unset(buildinfo_h_fake)
+
# add deps below, after adding blender
# -------------- done with header values.
@@ -208,6 +222,8 @@ if(WITH_BUILDINFO)
add_dependencies(buildinfoobj buildinfo)
endif()
+add_cc_flags_custom_test(blender)
+
# message(STATUS "Configuring blender")
if(WITH_PYTHON_MODULE)
add_definitions(-DWITH_PYTHON_MODULE)
@@ -230,7 +246,7 @@ if(WITH_PYTHON_MODULE)
set_target_properties(
blender
PROPERTIES
- MACOSX_BUNDLE
+ MACOSX_BUNDLE TRUE
LINK_FLAGS_RELEASE "${PLATFORM_LINKFLAGS}"
LINK_FLAGS_DEBUG "${PLATFORM_LINKFLAGS_DEBUG}"
)
@@ -247,6 +263,7 @@ if(WITH_PYTHON_MODULE)
else()
add_executable(blender ${EXETYPE} ${SRC})
+ WINDOWS_SIGN_TARGET(blender)
endif()
if(WITH_BUILDINFO)
@@ -321,7 +338,8 @@ if(WITH_PYTHON)
# install(CODE "message(\"copying blender scripts...\")")
# exclude addons_contrib if release
- if("${BLENDER_VERSION_CYCLE}" STREQUAL "release")
+ if("${BLENDER_VERSION_CYCLE}" STREQUAL "release" OR
+ "${BLENDER_VERSION_CYCLE}" STREQUAL "rc")
set(ADDON_EXCLUDE_CONDITIONAL "addons_contrib/*")
else()
set(ADDON_EXCLUDE_CONDITIONAL "_addons_contrib/*") # dummy, wont do anything
@@ -338,6 +356,8 @@ if(WITH_PYTHON)
DIRECTORY ${CMAKE_SOURCE_DIR}/release/scripts
DESTINATION ${TARGETDIR_VER}
PATTERN ".git" EXCLUDE
+ PATTERN ".gitignore" EXCLUDE
+ PATTERN ".arcconfig" EXCLUDE
PATTERN "__pycache__" EXCLUDE
PATTERN "${ADDON_EXCLUDE_CONDITIONAL}" EXCLUDE
PATTERN "${FREESTYLE_EXCLUDE_CONDITIONAL}" EXCLUDE
@@ -408,7 +428,8 @@ if("${CMAKE_GENERATOR}" MATCHES ".*Makefiles.*")
# message after building.
add_custom_command(
TARGET blender POST_BUILD MAIN_DEPENDENCY blender
- COMMAND ${CMAKE_COMMAND} -E echo 'now run: \"make install\" to copy runtime files and scripts to ${TARGETDIR_VER}'
+ COMMAND ${CMAKE_COMMAND} -E
+ echo 'now run: \"make install\" to copy runtime files and scripts to ${TARGETDIR_VER}'
)
endif()
@@ -537,6 +558,7 @@ if(UNIX AND NOT APPLE)
DIRECTORY ${PYTHON_LIBPATH}/python${PYTHON_VERSION}
DESTINATION ${TARGETDIR_VER}/python/${_target_LIB}
PATTERN "__pycache__" EXCLUDE # * any cache *
+ PATTERN "config-${PYTHON_VERSION}m/*.a" EXCLUDE # static lib
PATTERN "lib2to3" EXCLUDE # ./lib2to3
PATTERN "site-packages/*" EXCLUDE # ./site-packages/*
PATTERN "tkinter" EXCLUDE # ./tkinter
@@ -556,9 +578,6 @@ if(UNIX AND NOT APPLE)
)
unset(_py_inc_suffix)
- # # doesnt work, todo
- # install(CODE "execute_process(COMMAND find ${CMAKE_INSTALL_PREFIX}/${BLENDER_VERSION}/python/lib/ -name '*.so' -exec strip -s {} '\;')")
-
if(WITH_PYTHON_INSTALL_NUMPY)
# Install to the same directory as the source, so debian-like
# distros are happy with their policy.
@@ -576,7 +595,7 @@ if(UNIX AND NOT APPLE)
PATTERN "oldnumeric" EXCLUDE # ./oldnumeric
PATTERN "doc" EXCLUDE # ./doc
PATTERN "tests" EXCLUDE # ./tests
- PATTERN "f2py" EXCLUDE # ./f2py - fortran/python interface code, not fun for blender devs.
+ PATTERN "f2py" EXCLUDE # ./f2py - fortran/python interface code, not for blender.
PATTERN "include" EXCLUDE # include dirs all over, we wont use NumPy/CAPI
PATTERN "*.h" EXCLUDE # some includes are not in include dirs
PATTERN "*.a" EXCLUDE # ./core/lib/libnpymath.a - for linking, we dont need.
@@ -617,7 +636,7 @@ if(UNIX AND NOT APPLE)
FILES ${PYTHON_REQUESTS_PATH}/six.py
DESTINATION ${TARGETDIR_VER}/python/${_target_LIB}/python${PYTHON_VERSION}/${_suffix}
)
- endif()
+ endif()
unset(_requests_dep)
unset(_requests_deps)
unset(_suffix)
@@ -694,17 +713,31 @@ elseif(WIN32)
)
if(WITH_PYTHON_INSTALL_NUMPY)
+ set(PYTHON_NUMPY_VERSION 1.9)
+ if(MSVC_VERSION EQUAL 1900)
+ set(PYTHON_NUMPY_VERSION 1.11)
+ endif()
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages
- COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages)
-
- add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages/numpy
- COMMAND ${CMAKE_COMMAND} -E tar xzvf "${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}_numpy_1.9.tar.gz"
- DEPENDS ${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}_numpy_1.9.tar.gz
+ COMMAND ${CMAKE_COMMAND} -E
+ make_directory ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages)
+
+ add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages/numpy
+ COMMAND ${CMAKE_COMMAND} -E
+ tar xzvf "${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}_numpy_${PYTHON_NUMPY_VERSION}.tar.gz"
+ DEPENDS
+ ${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}_numpy_${PYTHON_NUMPY_VERSION}.tar.gz
${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages)
- add_custom_target(python_numpy ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages/numpy)
- install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages/numpy
- DESTINATION ${BLENDER_VERSION}/python/lib/site-packages)
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages
+ )
+ add_custom_target(
+ python_numpy ALL
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages/numpy
+ )
+ install(
+ DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages/numpy
+ DESTINATION ${BLENDER_VERSION}/python/lib/site-packages
+ )
endif()
@@ -902,6 +935,7 @@ elseif(APPLE)
PATTERN "__pycache__" EXCLUDE
PATTERN "__MACOSX" EXCLUDE
PATTERN ".DS_Store" EXCLUDE
+ PATTERN "config-${PYTHON_VERSION}m/*.a" EXCLUDE # static lib
)
endmacro()
@@ -923,7 +957,8 @@ elseif(APPLE)
OUTPUT_STRIP_TRAILING_WHITESPACE)
# Give the bundle actual creation/modification date
- execute_process(COMMAND SetFile -d ${SETFILE_DATE} -m ${SETFILE_DATE} ${EXECUTABLE_OUTPUT_PATH}/blender.app)
+ execute_process(COMMAND SetFile -d ${SETFILE_DATE} -m ${SETFILE_DATE}
+ ${EXECUTABLE_OUTPUT_PATH}/blender.app)
install(
TARGETS blender
@@ -1025,7 +1060,8 @@ elseif(APPLE)
)
# Give the bundle actual creation/modification date
- execute_process(COMMAND SetFile -d ${SETFILE_DATE} -m ${SETFILE_DATE} ${EXECUTABLE_OUTPUT_PATH}/blenderplayer.app)
+ execute_process(COMMAND SetFile -d ${SETFILE_DATE} -m ${SETFILE_DATE}
+ ${EXECUTABLE_OUTPUT_PATH}/blenderplayer.app)
install(
FILES ${OSX_APP_PLAYER_SOURCEDIR}/Contents/PkgInfo
@@ -1038,10 +1074,10 @@ elseif(APPLE)
)
if(WITH_OPENMP AND CMAKE_C_COMPILER_ID MATCHES "Clang" AND NOT ${CMAKE_C_COMPILER_VERSION} VERSION_LESS '3.4')
- install(
- FILES ${LIBDIR}/openmp/lib/libiomp5.dylib
- DESTINATION blenderplayer.app/Contents/Resources/lib/
- )
+ install(
+ FILES ${LIBDIR}/openmp/lib/libiomp5.dylib
+ DESTINATION blenderplayer.app/Contents/Resources/lib/
+ )
endif()
@@ -1112,9 +1148,11 @@ setup_liblinks(blender)
# Setup launcher
if(WIN32 AND NOT WITH_PYTHON_MODULE)
- install(TARGETS blender
- COMPONENT Blender
- DESTINATION ".")
+ install(
+ TARGETS blender
+ COMPONENT Blender
+ DESTINATION "."
+ )
if(MSVC12_REDIST_DIR)
if(CMAKE_CL_64)
@@ -1123,13 +1161,16 @@ if(WIN32 AND NOT WITH_PYTHON_MODULE)
set(_WIN_PLATFORM x86)
endif()
install(
- FILES ${MSVC12_REDIST_DIR}/${_WIN_PLATFORM}/Microsoft.VC120.CRT/msvcp120.dll
- ${MSVC12_REDIST_DIR}/${_WIN_PLATFORM}/Microsoft.VC120.CRT/msvcr120.dll
- DESTINATION ".")
+ FILES
+ ${MSVC12_REDIST_DIR}/${_WIN_PLATFORM}/Microsoft.VC120.CRT/msvcp120.dll
+ ${MSVC12_REDIST_DIR}/${_WIN_PLATFORM}/Microsoft.VC120.CRT/msvcr120.dll
+ DESTINATION "."
+ )
if(WITH_OPENMP)
install(
FILES ${MSVC12_REDIST_DIR}/${_WIN_PLATFORM}/Microsoft.VC120.OpenMP/vcomp120.dll
- DESTINATION ".")
+ DESTINATION "."
+ )
endif()
endif()
endif()
diff --git a/source/creator/creator.c b/source/creator/creator.c
index c32ba9474fd..a59a45f885c 100644
--- a/source/creator/creator.c
+++ b/source/creator/creator.c
@@ -42,9 +42,7 @@
#include "MEM_guardedalloc.h"
-#ifdef WIN32
-# include "BLI_winstuff.h"
-#endif
+#include "DNA_genfile.h"
#include "BLI_args.h"
#include "BLI_threads.h"
@@ -56,6 +54,7 @@
#include "BKE_appdir.h"
#include "BKE_blender.h"
#include "BKE_brush.h"
+#include "BKE_cachefile.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h" /* for DAG_init */
#include "BKE_font.h"
@@ -152,6 +151,35 @@ static void main_callback_setup(void)
MEM_set_error_callback(callback_mem_error);
}
+/* free data on early exit (if Python calls 'sys.exit()' while parsing args for eg). */
+struct CreatorAtExitData {
+ bArgs *ba;
+#ifdef WIN32
+ const char **argv;
+ int argv_num;
+#endif
+};
+
+static void callback_main_atexit(void *user_data)
+{
+ struct CreatorAtExitData *app_init_data = user_data;
+
+ if (app_init_data->ba) {
+ BLI_argsFree(app_init_data->ba);
+ app_init_data->ba = NULL;
+ }
+
+#ifdef WIN32
+ if (app_init_data->argv) {
+ while (app_init_data->argv_num) {
+ free((void *)app_init_data->argv[--app_init_data->argv_num]);
+ }
+ free((void *)app_init_data->argv);
+ app_init_data->argv = NULL;
+ }
+#endif
+}
+
/** \} */
@@ -203,6 +231,9 @@ int main(
/* --- end declarations --- */
+ /* ensure we free data on early-exit */
+ struct CreatorAtExitData app_init_data = {NULL};
+ BKE_blender_atexit_register(callback_main_atexit, &app_init_data);
#ifdef WIN32
/* We delay loading of openmp so we can set the policy here. */
@@ -226,6 +257,10 @@ int main(
argv[argv_num] = alloc_utf_8_from_16(argv_16[argv_num], 0);
}
LocalFree(argv_16);
+
+ /* free on early-exit */
+ app_init_data.argv = argv;
+ app_init_data.argv_num = argv_num;
}
#endif /* WIN32 */
@@ -318,9 +353,12 @@ int main(
BLI_threadapi_init();
+ DNA_sdna_current_init();
+
BKE_blender_globals_init(); /* blender.c */
IMB_init();
+ BKE_cachefiles_init();
BKE_images_init();
BKE_modifier_init();
DAG_init();
@@ -340,6 +378,10 @@ int main(
/* first test for background */
#ifndef WITH_PYTHON_MODULE
ba = BLI_argsInit(argc, (const char **)argv); /* skip binary path */
+
+ /* ensure we free on early exit */
+ app_init_data.ba = ba;
+
main_args_setup(C, ba, &syshandle);
BLI_argsParse(ba, 1, NULL, NULL);
@@ -436,16 +478,22 @@ int main(
#endif
+ /* Explicitly free data allocated for argument parsing:
+ * - 'ba'
+ * - 'argv' on WIN32.
+ */
+ callback_main_atexit(&app_init_data);
+ BKE_blender_atexit_unregister(callback_main_atexit, &app_init_data);
+
+ /* paranoid, avoid accidental re-use */
#ifndef WITH_PYTHON_MODULE
- BLI_argsFree(ba);
+ ba = NULL;
+ (void)ba;
#endif
#ifdef WIN32
- while (argv_num) {
- free(argv[--argv_num]);
- }
- free(argv);
argv = NULL;
+ (void)argv;
#endif
#ifdef WITH_PYTHON_MODULE
diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c
index 69765fc2341..c3c76a0d1d3 100644
--- a/source/creator/creator_args.c
+++ b/source/creator/creator_args.c
@@ -72,6 +72,7 @@
#include "WM_api.h"
+#include "GPU_basic_shader.h"
#include "GPU_draw.h"
#include "GPU_extensions.h"
@@ -583,9 +584,17 @@ static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), vo
BLI_argsPrintArgDoc(ba, "--");
+ printf("\n");
printf("Other Options:\n");
BLI_argsPrintOtherDoc(ba);
+ /* keep last args */
+ printf("\n");
+ printf("Experimental Features:\n");
+ BLI_argsPrintArgDoc(ba, "--enable-new-depsgraph");
+ BLI_argsPrintArgDoc(ba, "--enable-new-basic-shader-glsl");
+
+ printf("\n");
printf("Argument Parsing:\n");
printf("\tArguments must be separated by white space, eg:\n");
printf("\t# blender -ba test.blend\n");
@@ -619,11 +628,6 @@ static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), vo
#endif
printf(" $PYTHONHOME Path to the python directory, eg. /usr/lib/python.\n\n");
- /* keep last */
- printf("\n");
- printf("Experimental Features:\n");
- BLI_argsPrintArgDoc(ba, "--enable-new-depsgraph");
-
exit(0);
return 0;
@@ -735,8 +739,6 @@ static const char arg_handle_debug_mode_generic_set_doc_handlers[] =
"\n\tEnable debug messages for event handling";
static const char arg_handle_debug_mode_generic_set_doc_wm[] =
"\n\tEnable debug messages for the window manager, also prints every operator call";
-static const char arg_handle_debug_mode_generic_set_doc_all[] =
-"\n\tEnable all debug messages (excludes libmv)";
static const char arg_handle_debug_mode_generic_set_doc_jobs[] =
"\n\tEnable time profiling for background jobs.";
static const char arg_handle_debug_mode_generic_set_doc_gpu[] =
@@ -754,6 +756,20 @@ static int arg_handle_debug_mode_generic_set(int UNUSED(argc), const char **UNUS
return 0;
}
+static const char arg_handle_debug_mode_all_doc[] =
+"\n\tEnable all debug messages";
+static int arg_handle_debug_mode_all(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
+{
+ G.debug |= G_DEBUG_ALL;
+#ifdef WITH_LIBMV
+ libmv_startDebugLogging();
+#endif
+#ifdef WITH_CYCLES_LOGGING
+ CCL_start_debug_logging();
+#endif
+ return 0;
+}
+
#ifdef WITH_LIBMV
static const char arg_handle_debug_mode_libmv_doc[] =
"\n\tEnable debug messages from libmv library"
@@ -862,7 +878,7 @@ static const char arg_handle_playback_mode_doc[] =
"<options> <file(s)>\n"
"\tPlayback <file(s)>, only operates this way when not running in background.\n"
"\t\t-p <sx> <sy>\tOpen with lower left corner at <sx>, <sy>\n"
-"\t\t-m\t\tRead from disk (Don't buffer)\n"
+"\t\t-m\t\tRead from disk (Do not buffer)\n"
"\t\t-f <fps> <fps-base>\t\tSpecify FPS to start with\n"
"\t\t-j <frame>\tSet frame step to <frame>\n"
"\t\t-s <frame>\tPlay from <frame>\n"
@@ -950,10 +966,10 @@ static int arg_handle_start_with_console(int UNUSED(argc), const char **UNUSED(a
}
static const char arg_handle_register_extension_doc[] =
-"\n\tRegister .blend extension, then exit (Windows only)"
+"\n\tRegister blend-file extension, then exit (Windows only)"
;
static const char arg_handle_register_extension_doc_silent[] =
-"\n\tSilently register .blend extension, then exit (Windows only)"
+"\n\tSilently register blend-file extension, then exit (Windows only)"
;
static int arg_handle_register_extension(int UNUSED(argc), const char **UNUSED(argv), void *data)
{
@@ -1170,6 +1186,16 @@ static int arg_handle_depsgraph_use_new(int UNUSED(argc), const char **UNUSED(ar
return 0;
}
+static const char arg_handle_basic_shader_glsl_use_new_doc[] =
+"\n\tUse new GLSL basic shader"
+;
+static int arg_handle_basic_shader_glsl_use_new(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
+{
+ printf("Using new GLSL basic shader.\n");
+ GPU_basic_shader_use_glsl_set(true);
+ return 0;
+}
+
static const char arg_handle_verbosity_set_doc[] =
"<verbose>\n"
"\tSet logging verbosity level."
@@ -1777,8 +1803,7 @@ void main_args_setup(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle)
CB_EX(arg_handle_debug_mode_generic_set, handlers), (void *)G_DEBUG_HANDLERS);
BLI_argsAdd(ba, 1, NULL, "--debug-wm",
CB_EX(arg_handle_debug_mode_generic_set, wm), (void *)G_DEBUG_WM);
- BLI_argsAdd(ba, 1, NULL, "--debug-all",
- CB_EX(arg_handle_debug_mode_generic_set, all), (void *)G_DEBUG_ALL);
+ BLI_argsAdd(ba, 1, NULL, "--debug-all", CB(arg_handle_debug_mode_all), NULL);
BLI_argsAdd(ba, 1, NULL, "--debug-fpe",
CB(arg_handle_debug_fpe_set), NULL);
@@ -1805,6 +1830,7 @@ void main_args_setup(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle)
CB_EX(arg_handle_debug_mode_generic_set, gpumem), (void *)G_DEBUG_GPU_MEM);
BLI_argsAdd(ba, 1, NULL, "--enable-new-depsgraph", CB(arg_handle_depsgraph_use_new), NULL);
+ BLI_argsAdd(ba, 1, NULL, "--enable-new-basic-shader-glsl", CB(arg_handle_basic_shader_glsl_use_new), NULL);
BLI_argsAdd(ba, 1, NULL, "--verbose", CB(arg_handle_verbosity_set), NULL);
diff --git a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
index c5fc55a8e68..d7fe8d8ce59 100644
--- a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
+++ b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
@@ -341,6 +341,7 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c
ketsjiengine->SetUseFixedTime(usefixed);
ketsjiengine->SetTimingDisplay(frameRate, profile, properties);
ketsjiengine->SetRestrictAnimationFPS(restrictAnimFPS);
+ ketsjiengine->SetRender(true);
KX_KetsjiEngine::SetExitKey(ConvertKeyCode(startscene->gm.exitkey));
//set the global settings (carried over if restart/load new files)
@@ -464,19 +465,9 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c
if (always_use_expand_framing)
sceneconverter->SetAlwaysUseExpandFraming(true);
- bool usemat = false, useglslmat = false;
+ sceneconverter->SetMaterials(true);
- if (GLEW_ARB_multitexture && GLEW_VERSION_1_1)
- usemat = true;
-
- if (GPU_glsl_support())
- useglslmat = true;
- else if (gs.matmode == GAME_MAT_GLSL)
- usemat = false;
-
- if (usemat)
- sceneconverter->SetMaterials(true);
- if (useglslmat && (gs.matmode == GAME_MAT_GLSL))
+ if (gs.matmode == GAME_MAT_GLSL)
sceneconverter->SetGLSLMaterials(true);
if (scene->gm.flag & GAME_NO_MATERIAL_CACHING)
sceneconverter->SetCacheMaterials(false);
diff --git a/source/gameengine/Converter/BL_ArmatureObject.cpp b/source/gameengine/Converter/BL_ArmatureObject.cpp
index a1819a8dc92..a5af525e13a 100644
--- a/source/gameengine/Converter/BL_ArmatureObject.cpp
+++ b/source/gameengine/Converter/BL_ArmatureObject.cpp
@@ -233,8 +233,8 @@ BL_ArmatureObject::BL_ArmatureObject(
m_lastapplyframe(0.0)
{
m_origObjArma = armature; // Keep a copy of the original armature so we can fix drivers later
- m_objArma = BKE_object_copy(armature);
- m_objArma->data = BKE_armature_copy((bArmature *)armature->data);
+ m_objArma = BKE_object_copy(G.main, armature);
+ m_objArma->data = BKE_armature_copy(G.main, (bArmature *)armature->data);
// During object replication ob->data is increase, we decrease it now because we get a copy.
id_us_min(&((bArmature *)m_origObjArma->data)->id);
m_pose = m_objArma->pose;
@@ -433,8 +433,8 @@ void BL_ArmatureObject::ProcessReplica()
KX_GameObject::ProcessReplica();
bArmature* tmp = (bArmature*)m_objArma->data;
- m_objArma = BKE_object_copy(m_objArma);
- m_objArma->data = BKE_armature_copy(tmp);
+ m_objArma = BKE_object_copy(G.main, m_objArma);
+ m_objArma->data = BKE_armature_copy(G.main, tmp);
m_pose = m_objArma->pose;
}
diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
index ec99de45918..4751e60996d 100644
--- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp
+++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
@@ -281,7 +281,8 @@ static std::map<int, SCA_IInputDevice::KX_EnumInputs> create_translate_table()
m[QUOTEKEY ] = SCA_IInputDevice::KX_QUOTEKEY;
m[ACCENTGRAVEKEY ] = SCA_IInputDevice::KX_ACCENTGRAVEKEY;
m[MINUSKEY ] = SCA_IInputDevice::KX_MINUSKEY;
- m[SLASHKEY ] = SCA_IInputDevice::KX_SLASHKEY;
+ m[PLUSKEY ] = SCA_IInputDevice::KX_PLUSKEY;
+ m[SLASHKEY ] = SCA_IInputDevice::KX_SLASHKEY;
m[BACKSLASHKEY ] = SCA_IInputDevice::KX_BACKSLASHKEY;
m[EQUALKEY ] = SCA_IInputDevice::KX_EQUALKEY;
m[LEFTBRACKETKEY ] = SCA_IInputDevice::KX_LEFTBRACKETKEY;
@@ -1365,7 +1366,7 @@ static void BL_CreatePhysicsObjectNew(KX_GameObject* gameobj,
/* When the parent is not OB_DYNAMIC and has no OB_COLLISION then it gets no bullet controller
* and cant be apart of the parents compound shape, same goes for OB_SOFT_BODY */
if (parent && (parent->gameflag & (OB_DYNAMIC | OB_COLLISION))) {
- if( (parent->gameflag & OB_CHILD)!=0 && (blenderobject->gameflag & OB_CHILD) && !(parent->gameflag & OB_SOFT_BODY)) {
+ if ((parent->gameflag & OB_CHILD)!=0 && (blenderobject->gameflag & OB_CHILD) && !(parent->gameflag & OB_SOFT_BODY)) {
isCompoundChild = true;
}
}
diff --git a/source/gameengine/Converter/BL_ShapeDeformer.cpp b/source/gameengine/Converter/BL_ShapeDeformer.cpp
index 5e31dabfab1..94256a64d75 100644
--- a/source/gameengine/Converter/BL_ShapeDeformer.cpp
+++ b/source/gameengine/Converter/BL_ShapeDeformer.cpp
@@ -75,7 +75,7 @@ BL_ShapeDeformer::BL_ShapeDeformer(BL_DeformableGameObject *gameobj,
m_useShapeDrivers(false),
m_lastShapeUpdate(-1)
{
- m_key = BKE_key_copy(m_bmesh->key);
+ m_key = m_bmesh->key ? BKE_key_copy(G.main, m_bmesh->key) : NULL;
};
/* this second constructor is needed for making a mesh deformable on the fly. */
@@ -91,7 +91,7 @@ BL_ShapeDeformer::BL_ShapeDeformer(BL_DeformableGameObject *gameobj,
m_useShapeDrivers(false),
m_lastShapeUpdate(-1)
{
- m_key = BKE_key_copy(m_bmesh->key);
+ m_key = m_bmesh->key ? BKE_key_copy(G.main, m_bmesh->key) : NULL;
};
BL_ShapeDeformer::~BL_ShapeDeformer()
@@ -117,7 +117,7 @@ void BL_ShapeDeformer::ProcessReplica()
BL_SkinDeformer::ProcessReplica();
m_lastShapeUpdate = -1;
- m_key = BKE_key_copy(m_key);
+ m_key = m_key ? BKE_key_copy(G.main, m_key) : NULL;
}
bool BL_ShapeDeformer::LoadShapeDrivers(KX_GameObject* parent)
diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp
index b97d0b2a85d..08b569fa4c2 100644
--- a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp
+++ b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp
@@ -1425,7 +1425,7 @@ RAS_MeshObject *KX_BlenderSceneConverter::ConvertMeshSpecial(KX_Scene *kx_scene,
#ifdef DEBUG
printf("Mesh has a user \"%s\"\n", name);
#endif
- me = (ID*)BKE_mesh_copy_ex(from_maggie, (Mesh*)me);
+ me = (ID*)BKE_mesh_copy(from_maggie, (Mesh*)me);
id_us_min(me);
}
BLI_remlink(&from_maggie->mesh, me); /* even if we made the copy it needs to be removed */
@@ -1447,12 +1447,12 @@ RAS_MeshObject *KX_BlenderSceneConverter::ConvertMeshSpecial(KX_Scene *kx_scene,
/* if its tagged its a replaced material */
if (mat_old && (mat_old->id.tag & LIB_TAG_DOIT) == 0) {
Material *mat_old = mesh->mat[i];
- Material *mat_new = BKE_material_copy(mat_old);
+ Material *mat_new = BKE_material_copy(from_maggie, mat_old);
mat_new->id.tag |= LIB_TAG_DOIT;
id_us_min(&mat_old->id);
- BLI_remlink(&G.main->mat, mat_new); // BKE_material_copy uses G.main, and there is no BKE_material_copy_ex
+ BLI_remlink(&from_maggie->mat, mat_new); // BKE_material_copy uses G.main, and there is no BKE_material_copy_ex
BLI_addtail(&maggie->mat, mat_new);
mesh->mat[i] = mat_new;
diff --git a/source/gameengine/Converter/KX_ConvertActuators.cpp b/source/gameengine/Converter/KX_ConvertActuators.cpp
index 455fef0aceb..974dcbca95b 100644
--- a/source/gameengine/Converter/KX_ConvertActuators.cpp
+++ b/source/gameengine/Converter/KX_ConvertActuators.cpp
@@ -394,8 +394,9 @@ void BL_ConvertActuators(const char* maggiename,
soundActuatorType);
// if we made it mono, we have to free it
- if(sound && snd_sound && snd_sound != sound->playback_handle)
+ if (sound && snd_sound && snd_sound != sound->playback_handle) {
AUD_Sound_free(snd_sound);
+ }
tmpsoundact->SetName(bact->name);
baseact = tmpsoundact;
diff --git a/source/gameengine/Expressions/EXP_PyObjectPlus.h b/source/gameengine/Expressions/EXP_PyObjectPlus.h
index dd612a08494..32dc79cf6eb 100644
--- a/source/gameengine/Expressions/EXP_PyObjectPlus.h
+++ b/source/gameengine/Expressions/EXP_PyObjectPlus.h
@@ -73,7 +73,7 @@ typedef struct {
wlink.warn_done = true; \
wlink.link = NULL; \
\
- if(wlink_last) { \
+ if (wlink_last) { \
wlink_last->link= (void *)&(wlink); \
PyObjectPlus::SetDeprecationWarningLinkLast(&(wlink)); \
} \
@@ -195,7 +195,7 @@ public: \
PyObject *Py##method_name(PyObject *args, PyObject *kwds); \
static PyObject * \
sPy##method_name(PyObject *self, PyObject *args, PyObject *kwds) { \
- if(BGE_PROXY_REF(self)==NULL) { \
+ if (BGE_PROXY_REF(self)==NULL) { \
PyErr_SetString(PyExc_RuntimeError, \
#class_name "." #method_name "() - " \
BGE_PROXY_ERROR_MSG); \
@@ -208,7 +208,7 @@ public: \
PyObject *Py##method_name(PyObject *args); \
static PyObject* \
sPy##method_name(PyObject *self, PyObject *args) { \
- if(BGE_PROXY_REF(self)==NULL) { \
+ if (BGE_PROXY_REF(self)==NULL) { \
PyErr_SetString(PyExc_RuntimeError, \
#class_name "." #method_name "() - " \
BGE_PROXY_ERROR_MSG); return NULL; \
@@ -220,7 +220,7 @@ public: \
PyObject *Py##method_name(); \
static PyObject* \
sPy##method_name(PyObject *self) { \
- if(BGE_PROXY_REF(self)==NULL) { \
+ if (BGE_PROXY_REF(self)==NULL) { \
PyErr_SetString(PyExc_RuntimeError, \
#class_name "." #method_name "() - " \
BGE_PROXY_ERROR_MSG); return NULL; \
@@ -232,7 +232,7 @@ public: \
PyObject *Py##method_name(PyObject *value); \
static PyObject* \
sPy##method_name(PyObject *self, PyObject *value) { \
- if(BGE_PROXY_REF(self)==NULL) { \
+ if (BGE_PROXY_REF(self)==NULL) { \
PyErr_SetString(PyExc_RuntimeError, \
#class_name "." #method_name "(value) - " \
BGE_PROXY_ERROR_MSG); return NULL; \
@@ -244,7 +244,7 @@ public: \
PyObject *Py##method_name(PyObject *args, PyObject *kwds); \
static PyObject* \
sPy##method_name(PyObject *self, PyObject *args, PyObject *kwds) { \
- if(BGE_PROXY_REF(self)==NULL) { \
+ if (BGE_PROXY_REF(self)==NULL) { \
PyErr_SetString(PyExc_RuntimeError, \
#class_name "." #method_name "(...) - " \
BGE_PROXY_ERROR_MSG); return NULL; \
@@ -257,7 +257,7 @@ public: \
PyObject *Py##method_name(PyObject *args); \
static PyObject* \
sPy##method_name(PyObject *self, PyObject *args) { \
- if(BGE_PROXY_REF(self)==NULL) { \
+ if (BGE_PROXY_REF(self)==NULL) { \
PyErr_SetString(PyExc_RuntimeError, \
#class_name "." #method_name "(...) - " \
BGE_PROXY_ERROR_MSG); \
@@ -271,7 +271,7 @@ public: \
PyObject *Py##method_name(PyObject *value); \
static PyObject * \
sPy##method_name(PyObject *self, PyObject *value) { \
- if(BGE_PROXY_REF(self)==NULL) { \
+ if (BGE_PROXY_REF(self)==NULL) { \
PyErr_SetString(PyExc_RuntimeError, \
#class_name "." #method_name "(value) - " \
BGE_PROXY_ERROR_MSG); \
@@ -285,7 +285,7 @@ public: \
PyObject *Py##method_name(); \
static PyObject * \
sPy##method_name(PyObject *self) { \
- if(BGE_PROXY_REF(self)==NULL) { \
+ if (BGE_PROXY_REF(self)==NULL) { \
PyErr_SetString(PyExc_RuntimeError, \
#class_name "." #method_name "() - " \
BGE_PROXY_ERROR_MSG); \
diff --git a/source/gameengine/Expressions/intern/IntValue.cpp b/source/gameengine/Expressions/intern/IntValue.cpp
index 25aff5b32ab..7b2e841f13f 100644
--- a/source/gameengine/Expressions/intern/IntValue.cpp
+++ b/source/gameengine/Expressions/intern/IntValue.cpp
@@ -3,17 +3,17 @@
*/
// IntValue.cpp: implementation of the CIntValue class.
/*
-* Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
-*
-* Permission to use, copy, modify, distribute and sell this software
-* and its documentation for any purpose is hereby granted without fee,
-* provided that the above copyright notice appear in all copies and
-* that both that copyright notice and this permission notice appear
-* in supporting documentation. Erwin Coumans makes no
-* representations about the suitability of this software for any
-* purpose. It is provided "as is" without express or implied warranty.
-*
-*/
+ * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Erwin Coumans makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
#include <stdio.h>
diff --git a/source/gameengine/GameLogic/SCA_PropertySensor.cpp b/source/gameengine/GameLogic/SCA_PropertySensor.cpp
index 82f3bee86b2..abb64cf1733 100644
--- a/source/gameengine/GameLogic/SCA_PropertySensor.cpp
+++ b/source/gameengine/GameLogic/SCA_PropertySensor.cpp
@@ -199,7 +199,7 @@ bool SCA_PropertySensor::CheckPropertyCondition()
const float max = m_checkpropmaxval.ToFloat();
float val;
- if (orgprop->GetValueType() == VALUE_STRING_TYPE){
+ if (orgprop->GetValueType() == VALUE_STRING_TYPE) {
val = orgprop->GetText().ToFloat();
}
else {
@@ -240,7 +240,7 @@ bool SCA_PropertySensor::CheckPropertyCondition()
const float ref = m_checkpropval.ToFloat();
float val;
- if (orgprop->GetValueType() == VALUE_STRING_TYPE){
+ if (orgprop->GetValueType() == VALUE_STRING_TYPE) {
val = orgprop->GetText().ToFloat();
}
else {
diff --git a/source/gameengine/GameLogic/SCA_PythonController.cpp b/source/gameengine/GameLogic/SCA_PythonController.cpp
index 25936b34fde..fd2e723741c 100644
--- a/source/gameengine/GameLogic/SCA_PythonController.cpp
+++ b/source/gameengine/GameLogic/SCA_PythonController.cpp
@@ -163,7 +163,9 @@ void SCA_PythonController::SetNamespace(PyObject* pythondictionary)
/* Without __file__ set the sys.argv[0] is used for the filename
* which ends up with lines from the blender binary being printed in the console */
- PyDict_SetItemString(m_pythondictionary, "__file__", PyUnicode_From_STR_String(m_scriptName));
+ PyObject *value = PyUnicode_From_STR_String(m_scriptName);
+ PyDict_SetItemString(m_pythondictionary, "__file__", value);
+ Py_DECREF(value);
}
#endif
diff --git a/source/gameengine/GameLogic/SCA_PythonKeyboard.cpp b/source/gameengine/GameLogic/SCA_PythonKeyboard.cpp
index 19aae46f2a3..9a96a7b0334 100644
--- a/source/gameengine/GameLogic/SCA_PythonKeyboard.cpp
+++ b/source/gameengine/GameLogic/SCA_PythonKeyboard.cpp
@@ -113,11 +113,15 @@ PyObject *SCA_PythonKeyboard::pyattr_get_events(void *self_v, const KX_PYATTRIBU
{
SCA_PythonKeyboard* self = static_cast<SCA_PythonKeyboard*>(self_v);
- for (int i=SCA_IInputDevice::KX_BEGINKEY; i<=SCA_IInputDevice::KX_ENDKEY; i++)
- {
+ for (int i = SCA_IInputDevice::KX_BEGINKEY; i <= SCA_IInputDevice::KX_ENDKEY; i++) {
const SCA_InputEvent & inevent = self->m_keyboard->GetEventValue((SCA_IInputDevice::KX_EnumInputs)i);
-
- PyDict_SetItem(self->m_event_dict, PyLong_FromLong(i), PyLong_FromLong(inevent.m_status));
+ PyObject *key = PyLong_FromLong(i);
+ PyObject *value = PyLong_FromLong(inevent.m_status);
+
+ PyDict_SetItem(self->m_event_dict, key, value);
+
+ Py_DECREF(key);
+ Py_DECREF(value);
}
Py_INCREF(self->m_event_dict);
return self->m_event_dict;
@@ -129,12 +133,18 @@ PyObject *SCA_PythonKeyboard::pyattr_get_active_events(void *self_v, const KX_PY
PyDict_Clear(self->m_event_dict);
- for (int i=SCA_IInputDevice::KX_BEGINKEY; i<=SCA_IInputDevice::KX_ENDKEY; i++)
- {
+ for (int i = SCA_IInputDevice::KX_BEGINKEY; i <= SCA_IInputDevice::KX_ENDKEY; i++) {
const SCA_InputEvent & inevent = self->m_keyboard->GetEventValue((SCA_IInputDevice::KX_EnumInputs)i);
- if (inevent.m_status != SCA_InputEvent::KX_NO_INPUTSTATUS)
- PyDict_SetItem(self->m_event_dict, PyLong_FromLong(i), PyLong_FromLong(inevent.m_status));
+ if (inevent.m_status != SCA_InputEvent::KX_NO_INPUTSTATUS) {
+ PyObject *key = PyLong_FromLong(i);
+ PyObject *value = PyLong_FromLong(inevent.m_status);
+
+ PyDict_SetItem(self->m_event_dict, key, value);
+
+ Py_DECREF(key);
+ Py_DECREF(value);
+ }
}
Py_INCREF(self->m_event_dict);
return self->m_event_dict;
diff --git a/source/gameengine/GameLogic/SCA_PythonMouse.cpp b/source/gameengine/GameLogic/SCA_PythonMouse.cpp
index 1617f714113..184b306a665 100644
--- a/source/gameengine/GameLogic/SCA_PythonMouse.cpp
+++ b/source/gameengine/GameLogic/SCA_PythonMouse.cpp
@@ -96,11 +96,15 @@ PyObject *SCA_PythonMouse::pyattr_get_events(void *self_v, const KX_PYATTRIBUTE_
{
SCA_PythonMouse* self = static_cast<SCA_PythonMouse*>(self_v);
- for (int i=SCA_IInputDevice::KX_BEGINMOUSE; i<=SCA_IInputDevice::KX_ENDMOUSE; i++)
- {
- const SCA_InputEvent & inevent = self->m_mouse->GetEventValue((SCA_IInputDevice::KX_EnumInputs)i);
-
- PyDict_SetItem(self->m_event_dict, PyLong_FromLong(i), PyLong_FromLong(inevent.m_status));
+ for (int i = SCA_IInputDevice::KX_BEGINMOUSE; i <= SCA_IInputDevice::KX_ENDMOUSE; i++) {
+ const SCA_InputEvent &inevent = self->m_mouse->GetEventValue((SCA_IInputDevice::KX_EnumInputs)i);
+ PyObject *key = PyLong_FromLong(i);
+ PyObject *value = PyLong_FromLong(inevent.m_status);
+
+ PyDict_SetItem(self->m_event_dict, key, value);
+
+ Py_DECREF(key);
+ Py_DECREF(value);
}
Py_INCREF(self->m_event_dict);
return self->m_event_dict;
@@ -112,12 +116,19 @@ PyObject *SCA_PythonMouse::pyattr_get_active_events(void *self_v, const KX_PYATT
PyDict_Clear(self->m_event_dict);
- for (int i=SCA_IInputDevice::KX_BEGINMOUSE; i<=SCA_IInputDevice::KX_ENDMOUSE; i++)
- {
- const SCA_InputEvent & inevent = self->m_mouse->GetEventValue((SCA_IInputDevice::KX_EnumInputs)i);
+ for (int i = SCA_IInputDevice::KX_BEGINMOUSE; i <= SCA_IInputDevice::KX_ENDMOUSE; i++) {
+ const SCA_InputEvent &inevent = self->m_mouse->GetEventValue((SCA_IInputDevice::KX_EnumInputs)i);
- if (inevent.m_status != SCA_InputEvent::KX_NO_INPUTSTATUS)
- PyDict_SetItem(self->m_event_dict, PyLong_FromLong(i), PyLong_FromLong(inevent.m_status));
+ if (inevent.m_status != SCA_InputEvent::KX_NO_INPUTSTATUS) {
+
+ PyObject *key = PyLong_FromLong(i);
+ PyObject *value = PyLong_FromLong(inevent.m_status);
+
+ PyDict_SetItem(self->m_event_dict, key, value);
+
+ Py_DECREF(key);
+ Py_DECREF(value);
+ }
}
Py_INCREF(self->m_event_dict);
return self->m_event_dict;
diff --git a/source/gameengine/GamePlayer/ghost/CMakeLists.txt b/source/gameengine/GamePlayer/ghost/CMakeLists.txt
index 6c09af33f9e..577e25d6198 100644
--- a/source/gameengine/GamePlayer/ghost/CMakeLists.txt
+++ b/source/gameengine/GamePlayer/ghost/CMakeLists.txt
@@ -81,6 +81,10 @@ if(WIN32)
blender_include_dirs(../../../../intern/utfconv)
endif()
+if(WITH_INPUT_NDOF)
+ add_definitions(-DWITH_INPUT_NDOF)
+endif(WITH_INPUT_NDOF)
+
if(WITH_CODEC_FFMPEG)
add_definitions(-DWITH_FFMPEG)
endif()
diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
index f0a7bd47ca3..408006a0dae 100644
--- a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
+++ b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
@@ -301,7 +301,7 @@ bool GPG_Application::startScreenSaverFullScreen(
const int stereoMode,
const GHOST_TUns16 samples)
{
- bool ret = startFullScreen(width, height, bpp, frequency, stereoVisual, stereoMode, samples);
+ bool ret = startFullScreen(width, height, bpp, frequency, stereoVisual, stereoMode, 0, samples);
if (ret)
{
HWND ghost_hwnd = findGhostWindowHWND(m_mainWindow);
@@ -325,6 +325,7 @@ bool GPG_Application::startWindow(
int windowHeight,
const bool stereoVisual,
const int stereoMode,
+ const int alphaBackground,
const GHOST_TUns16 samples)
{
GHOST_GLSettings glSettings = {0};
@@ -333,6 +334,8 @@ bool GPG_Application::startWindow(
//STR_String title ("Blender Player - GHOST");
if (stereoVisual)
glSettings.flags |= GHOST_glStereoVisual;
+ if (alphaBackground)
+ glSettings.flags |= GHOST_glAlphaBackground;
glSettings.numOfAASamples = samples;
m_mainWindow = fSystem->createWindow(title, windowLeft, windowTop, windowWidth, windowHeight, GHOST_kWindowStateNormal,
@@ -360,6 +363,7 @@ bool GPG_Application::startEmbeddedWindow(
const GHOST_TEmbedderWindowID parentWindow,
const bool stereoVisual,
const int stereoMode,
+ const int alphaBackground,
const GHOST_TUns16 samples)
{
GHOST_TWindowState state = GHOST_kWindowStateNormal;
@@ -367,6 +371,8 @@ bool GPG_Application::startEmbeddedWindow(
if (stereoVisual)
glSettings.flags |= GHOST_glStereoVisual;
+ if (alphaBackground)
+ glSettings.flags |= GHOST_glAlphaBackground;
glSettings.numOfAASamples = samples;
if (parentWindow != 0)
@@ -394,6 +400,7 @@ bool GPG_Application::startFullScreen(
int bpp,int frequency,
const bool stereoVisual,
const int stereoMode,
+ const int alphaBackground,
const GHOST_TUns16 samples,
bool useDesktop)
{
@@ -407,7 +414,7 @@ bool GPG_Application::startFullScreen(
setting.bpp = bpp;
setting.frequency = frequency;
- fSystem->beginFullScreen(setting, &m_mainWindow, stereoVisual, samples);
+ fSystem->beginFullScreen(setting, &m_mainWindow, stereoVisual, alphaBackground, samples);
m_mainWindow->setCursorVisibility(false);
/* note that X11 ignores this (it uses a window internally for fullscreen) */
m_mainWindow->setState(GHOST_kWindowStateFullScreen);
@@ -583,13 +590,8 @@ bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode)
bool nodepwarnings = (SYS_GetCommandLineInt(syshandle, "ignore_deprecation_warnings", 1) != 0);
bool restrictAnimFPS = (gm->flag & GAME_RESTRICT_ANIM_UPDATES) != 0;
- if (GLEW_ARB_multitexture && GLEW_VERSION_1_1)
- m_blendermat = (SYS_GetCommandLineInt(syshandle, "blender_material", 1) != 0);
-
- if (GPU_glsl_support())
- m_blenderglslmat = (SYS_GetCommandLineInt(syshandle, "blender_glsl_material", 1) != 0);
- else if (m_globalSettings->matmode == GAME_MAT_GLSL)
- m_blendermat = false;
+ m_blendermat = (SYS_GetCommandLineInt(syshandle, "blender_material", 1) != 0);
+ m_blenderglslmat = (SYS_GetCommandLineInt(syshandle, "blender_glsl_material", 1) != 0);
// create the canvas, rasterizer and rendertools
m_canvas = new GPG_Canvas(window);
@@ -626,7 +628,9 @@ bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode)
if (!m_rasterizer)
goto initFailed;
-
+
+ m_rasterizer->PrintHardwareInfo();
+
// create the inputdevices
m_keyboard = new GPG_KeyboardDevice();
if (!m_keyboard)
@@ -671,6 +675,7 @@ bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode)
//set the global settings (carried over if restart/load new files)
m_ketsjiengine->SetGlobalSettings(m_globalSettings);
+ m_ketsjiengine->SetRender(true);
m_engineInitialized = true;
}
diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.h b/source/gameengine/GamePlayer/ghost/GPG_Application.h
index b6f545c2de8..e757cc10e32 100644
--- a/source/gameengine/GamePlayer/ghost/GPG_Application.h
+++ b/source/gameengine/GamePlayer/ghost/GPG_Application.h
@@ -65,13 +65,13 @@ public:
bool startWindow(STR_String& title,
int windowLeft, int windowTop,
int windowWidth, int windowHeight,
- const bool stereoVisual, const int stereoMode, const GHOST_TUns16 samples=0);
+ const bool stereoVisual, const int stereoMode, const int alphaBackground=0, const GHOST_TUns16 samples=0);
bool startFullScreen(int width, int height,
int bpp, int frequency,
- const bool stereoVisual, const int stereoMode,
+ const bool stereoVisual, const int stereoMode, const int alphaBackground = 0,
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);
+ const bool stereoVisual, const int stereoMode, const int alphaBackground=0, const GHOST_TUns16 samples=0);
#ifdef WIN32
bool startScreenSaverFullScreen(int width, int height,
int bpp, int frequency,
diff --git a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
index ac2e4dfa563..dd93a6ff424 100644
--- a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
+++ b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
@@ -46,8 +46,8 @@
#include "KX_PyConstraintBinding.h" // for PHY_SetActiveEnvironment
/**********************************
-* Begin Blender include block
-**********************************/
+ * Begin Blender include block
+ **********************************/
#ifdef __cplusplus
extern "C"
{
@@ -61,6 +61,7 @@ extern "C"
#include "DNA_scene_types.h"
#include "DNA_userdef_types.h"
+#include "DNA_genfile.h"
#include "BLO_readfile.h"
#include "BLO_runtime.h"
@@ -74,6 +75,7 @@ extern "C"
#include "BKE_node.h"
#include "BKE_report.h"
#include "BKE_library.h"
+#include "BKE_library_remap.h"
#include "BKE_modifier.h"
#include "BKE_material.h"
#include "BKE_text.h"
@@ -102,8 +104,8 @@ extern char datatoc_bmonofont_ttf[];
#include "GPU_draw.h"
/**********************************
-* End Blender include block
-**********************************/
+ * End Blender include block
+ **********************************/
#include "BL_System.h"
#include "GPG_Application.h"
@@ -444,6 +446,7 @@ int main(
int validArguments=0;
bool samplesParFound = false;
GHOST_TUns16 aasamples = 0;
+ int alphaBackground = 0;
#ifdef WIN32
char **argv;
@@ -461,8 +464,8 @@ int main(
/* Win32 Unicode Args */
/* NOTE: cannot use guardedalloc malloc here, as it's not yet initialized
- * (it depends on the args passed in, which is what we're getting here!)
- */
+ * (it depends on the args passed in, which is what we're getting here!)
+ */
{
wchar_t **argv_16 = CommandLineToArgvW(GetCommandLineW(), &argc);
argv = (char**)malloc(argc * sizeof(char *));
@@ -490,6 +493,8 @@ int main(
// freeing up GPU_Textures works correctly.
BLI_threadapi_init();
+ DNA_sdna_current_init();
+
RNA_init();
init_nodesystem();
@@ -707,7 +712,7 @@ int main(
{
i++;
if ( (i + 1) <= validArguments )
- parentWindow = atoi(argv[i++]);
+ parentWindow = (GHOST_TEmbedderWindowID)atoll(argv[i++]);
else {
error = true;
printf("error: too few options for parent window argument.\n");
@@ -838,6 +843,12 @@ int main(
}
break;
}
+ case 'a': // allow window to blend with display background
+ {
+ i++;
+ alphaBackground = 1;
+ break;
+ }
default: //not recognized
{
printf("Unknown argument: %s\n", argv[i++]);
@@ -1041,7 +1052,7 @@ int main(
#endif
{
app.startFullScreen(fullScreenWidth, fullScreenHeight, fullScreenBpp, fullScreenFrequency,
- stereoWindow, stereomode, aasamples, (scene->gm.playerflag & GAME_PLAYER_DESKTOP_RESOLUTION));
+ stereoWindow, stereomode, alphaBackground, aasamples, (scene->gm.playerflag & GAME_PLAYER_DESKTOP_RESOLUTION));
}
}
else
@@ -1088,7 +1099,7 @@ int main(
app.startEmbeddedWindow(title, parentWindow, stereoWindow, stereomode, aasamples);
else
app.startWindow(title, windowLeft, windowTop, windowWidth, windowHeight,
- stereoWindow, stereomode, aasamples);
+ stereoWindow, stereomode, alphaBackground, aasamples);
if (SYS_GetCommandLineInt(syshandle, "nomipmap", 0)) {
GPU_set_mipmap(0);
@@ -1137,7 +1148,7 @@ int main(
MEM_freeN(python_code);
}
else {
- fprintf(stderr, "ERROR: cannot yield control to Python: no Python text data block named '%s'\n", python_main);
+ fprintf(stderr, "ERROR: cannot yield control to Python: no Python text data-block named '%s'\n", python_main);
}
}
else {
diff --git a/source/gameengine/Ketsji/BL_Action.cpp b/source/gameengine/Ketsji/BL_Action.cpp
index 45946f30827..7175eb877dd 100644
--- a/source/gameengine/Ketsji/BL_Action.cpp
+++ b/source/gameengine/Ketsji/BL_Action.cpp
@@ -161,7 +161,7 @@ bool BL_Action::Play(const char* name,
BKE_libblock_free(G.main, m_tmpaction);
m_tmpaction = NULL;
}
- m_tmpaction = BKE_action_copy(m_action);
+ m_tmpaction = BKE_action_copy(G.main, m_action);
// First get rid of any old controllers
ClearControllerList();
diff --git a/source/gameengine/Ketsji/BL_Shader.cpp b/source/gameengine/Ketsji/BL_Shader.cpp
index 6613780a0f8..72815cadc70 100644
--- a/source/gameengine/Ketsji/BL_Shader.cpp
+++ b/source/gameengine/Ketsji/BL_Shader.cpp
@@ -32,6 +32,7 @@
#include "MT_Matrix4x4.h"
#include "MT_Matrix3x3.h"
#include "KX_PyMath.h"
+#include "KX_PythonInit.h"
#include "MEM_guardedalloc.h"
#include "RAS_MeshObject.h"
@@ -67,15 +68,16 @@ BL_Uniform::~BL_Uniform()
#endif
}
-void BL_Uniform::Apply(class BL_Shader *shader)
+bool BL_Uniform::Apply(class BL_Shader *shader)
{
#ifdef SORT_UNIFORMS
+ RAS_IRasterizer *ras;
MT_assert(mType > UNI_NONE && mType < UNI_MAX && mData);
- if (!mDirty) {
- return;
- }
+ if (!mDirty)
+ return false;
+ mDirty = false;
switch (mType) {
case UNI_FLOAT:
{
@@ -83,6 +85,15 @@ void BL_Uniform::Apply(class BL_Shader *shader)
glUniform1fARB(mLoc, (GLfloat)*f);
break;
}
+ case UNI_FLOAT_EYE:
+ {
+ float *f = (float*)mData;
+ ras = KX_GetActiveEngine()->GetRasterizer();
+ *f = (ras->GetEye() == RAS_IRasterizer::RAS_STEREO_LEFTEYE) ? 0.0f : 0.5f;
+ glUniform1fARB(mLoc, (GLfloat)*f);
+ mDirty = (ras->Stereo()) ? true : false;
+ break;
+ }
case UNI_INT:
{
int *f = (int *)mData;
@@ -138,7 +149,7 @@ void BL_Uniform::Apply(class BL_Shader *shader)
break;
}
}
- mDirty = false;
+ return mDirty;
#endif
}
@@ -274,11 +285,10 @@ void BL_Shader::ApplyShader()
return;
}
- for (unsigned int i = 0; i < mUniforms.size(); i++) {
- mUniforms[i]->Apply(this);
- }
-
mDirty = false;
+ for (unsigned int i=0; i<mUniforms.size(); i++) {
+ mDirty |= mUniforms[i]->Apply(this);
+ }
#endif
}
@@ -314,64 +324,70 @@ bool BL_Shader::LinkProgram()
return false;
}
- // -- vertex shader ------------------
- tmpVert = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
- glShaderSourceARB(tmpVert, 1, (const char **)&vertProg, 0);
- glCompileShaderARB(tmpVert);
- glGetObjectParameterivARB(tmpVert, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint *)&vertlen);
-
- // print info if any
- if (vertlen > 0 && vertlen < MAX_LOG_LEN) {
- logInf = (char *)MEM_mallocN(vertlen, "vert-log");
- glGetInfoLogARB(tmpVert, vertlen, (GLsizei *)&char_len, logInf);
-
- if (char_len > 0) {
- spit("---- Vertex Shader Error ----");
- spit(logInf);
+ if (vertProg[0] != 0) {
+ // -- vertex shader ------------------
+ tmpVert = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
+ glShaderSourceARB(tmpVert, 1, (const char**)&vertProg, 0);
+ glCompileShaderARB(tmpVert);
+ glGetObjectParameterivARB(tmpVert, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint*)&vertlen);
+
+ // print info if any
+ if (vertlen > 0 && vertlen < MAX_LOG_LEN) {
+ logInf = (char*)MEM_mallocN(vertlen, "vert-log");
+ glGetInfoLogARB(tmpVert, vertlen, (GLsizei*)&char_len, logInf);
+ if (char_len > 0) {
+ spit("---- Vertex Shader Error ----");
+ spit(logInf);
+ }
+ MEM_freeN(logInf);
+ logInf = 0;
+ }
+ // check for compile errors
+ glGetObjectParameterivARB(tmpVert, GL_OBJECT_COMPILE_STATUS_ARB, (GLint*)&vertstatus);
+ if (!vertstatus) {
+ spit("---- Vertex shader failed to compile ----");
+ goto programError;
}
-
- MEM_freeN(logInf);
- logInf = 0;
- }
-
- // check for compile errors
- glGetObjectParameterivARB(tmpVert, GL_OBJECT_COMPILE_STATUS_ARB, (GLint *)&vertstatus);
- if (!vertstatus) {
- spit("---- Vertex shader failed to compile ----");
- goto programError;
}
- // -- fragment shader ----------------
- tmpFrag = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
- glShaderSourceARB(tmpFrag, 1, (const char **)&fragProg, 0);
- glCompileShaderARB(tmpFrag);
- glGetObjectParameterivARB(tmpFrag, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint *)&fraglen);
-
- if (fraglen > 0 && fraglen < MAX_LOG_LEN) {
- logInf = (char *)MEM_mallocN(fraglen, "frag-log");
- glGetInfoLogARB(tmpFrag, fraglen, (GLsizei *)&char_len, logInf);
-
- if (char_len > 0) {
- spit("---- Fragment Shader Error ----");
- spit(logInf);
+ if (fragProg[0] != 0) {
+ // -- fragment shader ----------------
+ tmpFrag = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
+ glShaderSourceARB(tmpFrag, 1, (const char**)&fragProg, 0);
+ glCompileShaderARB(tmpFrag);
+ glGetObjectParameterivARB(tmpFrag, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint*)&fraglen);
+ if (fraglen > 0 && fraglen < MAX_LOG_LEN) {
+ logInf = (char*)MEM_mallocN(fraglen, "frag-log");
+ glGetInfoLogARB(tmpFrag, fraglen, (GLsizei*)&char_len, logInf);
+ if (char_len > 0) {
+ spit("---- Fragment Shader Error ----");
+ spit(logInf);
+ }
+ MEM_freeN(logInf);
+ logInf = 0;
}
- MEM_freeN(logInf);
- logInf = 0;
+ glGetObjectParameterivARB(tmpFrag, GL_OBJECT_COMPILE_STATUS_ARB, (GLint*)&fragstatus);
+ if (!fragstatus) {
+ spit("---- Fragment shader failed to compile ----");
+ goto programError;
+ }
}
-
- glGetObjectParameterivARB(tmpFrag, GL_OBJECT_COMPILE_STATUS_ARB, (GLint *)&fragstatus);
-
- if (!fragstatus) {
- spit("---- Fragment shader failed to compile ----");
+
+ if (!tmpFrag && !tmpVert) {
+ spit("---- No shader given ----");
goto programError;
}
// -- program ------------------------
// set compiled vert/frag shader & link
tmpProg = glCreateProgramObjectARB();
- glAttachObjectARB(tmpProg, tmpVert);
- glAttachObjectARB(tmpProg, tmpFrag);
+ if (tmpVert) {
+ glAttachObjectARB(tmpProg, tmpVert);
+ }
+ if (tmpFrag) {
+ glAttachObjectARB(tmpProg, tmpFrag);
+ }
glLinkProgramARB(tmpProg);
glGetObjectParameterivARB(tmpProg, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint *)&proglen);
glGetObjectParameterivARB(tmpProg, GL_OBJECT_LINK_STATUS_ARB, (GLint *)&progstatus);
@@ -396,8 +412,12 @@ bool BL_Shader::LinkProgram()
// set
mShader = tmpProg;
- glDeleteObjectARB(tmpVert);
- glDeleteObjectARB(tmpFrag);
+ if (tmpVert) {
+ glDeleteObjectARB(tmpVert);
+ }
+ if (tmpFrag) {
+ glDeleteObjectARB(tmpFrag);
+ }
mOk = 1;
mError = 0;
return true;
@@ -748,6 +768,7 @@ PyMethodDef BL_Shader::Methods[] = {
KX_PYMETHODTABLE(BL_Shader, validate),
// access functions
KX_PYMETHODTABLE(BL_Shader, isValid),
+ KX_PYMETHODTABLE(BL_Shader, setUniformEyef),
KX_PYMETHODTABLE(BL_Shader, setUniform1f),
KX_PYMETHODTABLE(BL_Shader, setUniform2f),
KX_PYMETHODTABLE(BL_Shader, setUniform3f),
@@ -1019,6 +1040,27 @@ KX_PYMETHODDEF_DOC(BL_Shader, setUniform4f, "setUniform4f(name, fx,fy,fz, fw) ")
return NULL;
}
+KX_PYMETHODDEF_DOC(BL_Shader, setUniformEyef, "setUniformEyef(name)")
+{
+ if (mError) {
+ Py_RETURN_NONE;
+ }
+ const char *uniform;
+ float value = 0.0f;
+ if (PyArg_ParseTuple(args, "s:setUniformEyef", &uniform)) {
+ int loc = GetUniformLocation(uniform);
+ if (loc != -1) {
+#ifdef SORT_UNIFORMS
+ SetUniformfv(loc, BL_Uniform::UNI_FLOAT_EYE, &value, sizeof(float));
+#else
+ SetUniform(loc, (int)value);
+#endif
+ }
+ Py_RETURN_NONE;
+ }
+ return NULL;
+}
+
KX_PYMETHODDEF_DOC(BL_Shader, setUniform1i, "setUniform1i(name, ix)")
{
if (mError) {
diff --git a/source/gameengine/Ketsji/BL_Shader.h b/source/gameengine/Ketsji/BL_Shader.h
index aef4b42a85a..5de715d67d4 100644
--- a/source/gameengine/Ketsji/BL_Shader.h
+++ b/source/gameengine/Ketsji/BL_Shader.h
@@ -64,10 +64,11 @@ public:
UNI_FLOAT4,
UNI_MAT3,
UNI_MAT4,
+ UNI_FLOAT_EYE,
UNI_MAX
};
- void Apply(class BL_Shader *shader);
+ bool Apply(class BL_Shader *shader);
void SetData(int location, int type, bool transpose = false);
int GetLocation() { return mLoc; }
void *getData() { return mData; }
@@ -226,6 +227,7 @@ public:
KX_PYMETHOD_DOC(BL_Shader, setUniform3i);
KX_PYMETHOD_DOC(BL_Shader, setUniform2i);
KX_PYMETHOD_DOC(BL_Shader, setUniform1i);
+ KX_PYMETHOD_DOC(BL_Shader, setUniformEyef);
KX_PYMETHOD_DOC(BL_Shader, setUniformfv);
KX_PYMETHOD_DOC(BL_Shader, setUniformiv);
KX_PYMETHOD_DOC(BL_Shader, setUniformMatrix4);
diff --git a/source/gameengine/Ketsji/BL_Texture.cpp b/source/gameengine/Ketsji/BL_Texture.cpp
index 730e49c4918..cc7fea5ad25 100644
--- a/source/gameengine/Ketsji/BL_Texture.cpp
+++ b/source/gameengine/Ketsji/BL_Texture.cpp
@@ -420,14 +420,7 @@ int BL_Texture::GetMaxUnits()
{
if (g_max_units < 0) {
GLint unit = 0;
-
- if (GPU_glsl_support()) {
- glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &unit);
- }
- else if (GLEW_ARB_multitexture) {
- glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &unit);
- }
-
+ glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &unit);
g_max_units = (MAXTEX >= unit) ? unit : MAXTEX;
}
diff --git a/source/gameengine/Ketsji/KX_Dome.cpp b/source/gameengine/Ketsji/KX_Dome.cpp
index 6585b9dc831..d08372e47d4 100644
--- a/source/gameengine/Ketsji/KX_Dome.cpp
+++ b/source/gameengine/Ketsji/KX_Dome.cpp
@@ -1600,7 +1600,7 @@ void KX_Dome::RotateCamera(KX_Camera* cam, int i)
MT_Transform camtrans(cam->GetWorldToCamera());
MT_Matrix4x4 viewmat(camtrans);
- m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->GetCameraData()->m_perspective);
+ m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->NodeGetLocalScaling(), cam->GetCameraData()->m_perspective);
cam->SetModelviewMatrix(viewmat);
// restore the original orientation
@@ -2035,7 +2035,7 @@ void KX_Dome::RenderDomeFrame(KX_Scene* scene, KX_Camera* cam, int i)
MT_Transform camtrans(cam->GetWorldToCamera());
MT_Matrix4x4 viewmat(camtrans);
- m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), 1.0f);
+ m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->NodeGetLocalScaling(), 1.0f);
cam->SetModelviewMatrix(viewmat);
// restore the original orientation
diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp
index 69c1af35bd9..3244400e1bd 100644
--- a/source/gameengine/Ketsji/KX_GameObject.cpp
+++ b/source/gameengine/Ketsji/KX_GameObject.cpp
@@ -142,7 +142,7 @@ KX_GameObject::~KX_GameObject()
}
// Unregister collision callbacks
// Do this before we start freeing physics information like m_pClient_info
- if (m_collisionCallbacks){
+ if (m_collisionCallbacks) {
UnregisterCollisionCallbacks();
Py_CLEAR(m_collisionCallbacks);
}
@@ -1564,7 +1564,7 @@ void KX_GameObject::UnregisterCollisionCallbacks()
PHY_IPhysicsEnvironment* pe = scene->GetPhysicsEnvironment();
PHY_IPhysicsController* spc = GetPhysicsController();
// If we are the last to unregister on this physics controller
- if (pe->RemoveCollisionCallback(spc)){
+ if (pe->RemoveCollisionCallback(spc)) {
// If we are a sensor object
if (m_pClient_info->isSensor())
// Remove sensor body from physics world
@@ -1584,7 +1584,7 @@ void KX_GameObject::RegisterCollisionCallbacks()
PHY_IPhysicsEnvironment* pe = scene->GetPhysicsEnvironment();
PHY_IPhysicsController* spc = GetPhysicsController();
// If we are the first to register on this physics controller
- if (pe->RequestCollisionCallback(spc)){
+ if (pe->RequestCollisionCallback(spc)) {
// If we are a sensor object
if (m_pClient_info->isSensor())
// Add sensor body to physics world
diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
index 7237c473332..b0a8e376eb6 100644
--- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
+++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
@@ -108,7 +108,7 @@ double KX_KetsjiEngine::m_suspendeddelta = 0.0;
double KX_KetsjiEngine::m_average_framerate = 0.0;
bool KX_KetsjiEngine::m_restrict_anim_fps = false;
short KX_KetsjiEngine::m_exitkey = 130; // ESC Key
-
+bool KX_KetsjiEngine::m_doRender = true;
/**
* Constructor of the Ketsji Engine
@@ -173,6 +173,7 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system)
m_overrideFrameColorR(0.0f),
m_overrideFrameColorG(0.0f),
m_overrideFrameColorB(0.0f),
+ m_overrideFrameColorA(0.0f),
m_usedome(false)
{
@@ -381,7 +382,7 @@ void KX_KetsjiEngine::RenderDome()
m_overrideFrameColorR,
m_overrideFrameColorG,
m_overrideFrameColorB,
- 1.0
+ m_overrideFrameColorA
);
}
else
@@ -749,6 +750,9 @@ bool KX_KetsjiEngine::NextFrame()
scene->setSuspendedTime(m_clockTime);
m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(), true);
+
+ // invalidates the shadow buffer from previous render/ImageRender because the scene has changed
+ scene->SetShadowDone(false);
}
// update system devices
@@ -771,7 +775,7 @@ bool KX_KetsjiEngine::NextFrame()
// Start logging time spent outside main loop
m_logger->StartLog(tc_outside, m_kxsystem->GetTimeInSeconds(), true);
- return doRender;
+ return doRender && m_doRender;
}
@@ -805,7 +809,7 @@ void KX_KetsjiEngine::Render()
m_overrideFrameColorR,
m_overrideFrameColorG,
m_overrideFrameColorB,
- 1.0
+ m_overrideFrameColorA
);
}
else
@@ -1133,6 +1137,8 @@ void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene)
cam->Release();
}
}
+ /* remember that we have a valid shadow buffer for that scene */
+ scene->SetShadowDone(true);
}
// update graphics
@@ -1252,7 +1258,7 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam)
MT_Transform camtrans(cam->GetWorldToCamera());
MT_Matrix4x4 viewmat(camtrans);
- m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->GetCameraData()->m_perspective);
+ m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->NodeGetLocalScaling(), cam->GetCameraData()->m_perspective);
cam->SetModelviewMatrix(viewmat);
// The following actually reschedules all vertices to be
@@ -1925,6 +1931,16 @@ short KX_KetsjiEngine::GetExitKey()
return m_exitkey;
}
+void KX_KetsjiEngine::SetRender(bool render)
+{
+ m_doRender = render;
+}
+
+bool KX_KetsjiEngine::GetRender()
+{
+ return m_doRender;
+}
+
void KX_KetsjiEngine::SetShowFramerate(bool frameRate)
{
m_show_framerate = frameRate;
@@ -2023,19 +2039,21 @@ bool KX_KetsjiEngine::GetUseOverrideFrameColor(void) const
}
-void KX_KetsjiEngine::SetOverrideFrameColor(float r, float g, float b)
+void KX_KetsjiEngine::SetOverrideFrameColor(float r, float g, float b, float a)
{
m_overrideFrameColorR = r;
m_overrideFrameColorG = g;
m_overrideFrameColorB = b;
+ m_overrideFrameColorA = a;
}
-void KX_KetsjiEngine::GetOverrideFrameColor(float& r, float& g, float& b) const
+void KX_KetsjiEngine::GetOverrideFrameColor(float& r, float& g, float& b, float& a) const
{
r = m_overrideFrameColorR;
g = m_overrideFrameColorG;
b = m_overrideFrameColorB;
+ a = m_overrideFrameColorA;
}
diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.h b/source/gameengine/Ketsji/KX_KetsjiEngine.h
index 3b8cec2ac82..1756214b6dd 100644
--- a/source/gameengine/Ketsji/KX_KetsjiEngine.h
+++ b/source/gameengine/Ketsji/KX_KetsjiEngine.h
@@ -129,6 +129,8 @@ private:
static short m_exitkey; /* Key used to exit the BGE */
+ static bool m_doRender; /* whether or not the scene should be rendered after the logic frame */
+
int m_exitcode;
STR_String m_exitstring;
@@ -199,6 +201,8 @@ private:
float m_overrideFrameColorG;
/** Blue component of framing bar color. */
float m_overrideFrameColorB;
+ /** alpha component of framing bar color. */
+ float m_overrideFrameColorA;
/** Settings that doesn't go away with Game Actuator */
GlobalSettings m_globalsettings;
@@ -209,7 +213,6 @@ private:
void RenderFrame(KX_Scene* scene, KX_Camera* cam);
void PostRenderScene(KX_Scene* scene);
void RenderDebugProperties();
- void RenderShadowBuffers(KX_Scene *scene);
public:
KX_KetsjiEngine(class KX_ISystem* system);
@@ -249,6 +252,7 @@ public:
///returns true if an update happened to indicate -> Render
bool NextFrame();
void Render();
+ void RenderShadowBuffers(KX_Scene *scene);
void StartEngine(bool clearIpo);
void StopEngine();
@@ -401,6 +405,16 @@ public:
static short GetExitKey();
/**
+ * Activate or deactivates the render of the scene after the logic frame
+ * \param render true (render) or false (do not render)
+ */
+ static void SetRender(bool render);
+ /**
+ * Get the current render flag value
+ */
+ static bool GetRender();
+
+ /**
* \Sets the display for frame rate on or off.
*/
void SetShowFramerate(bool frameRate);
@@ -485,7 +499,7 @@ public:
* \param g Green component of the override color.
* \param b Blue component of the override color.
*/
- void SetOverrideFrameColor(float r, float g, float b);
+ void SetOverrideFrameColor(float r, float g, float b, float a);
/**
* Returns the color used for framing bar color instead of the one in the Blender file's scenes.
@@ -493,7 +507,7 @@ public:
* \param g Green component of the override color.
* \param b Blue component of the override color.
*/
- void GetOverrideFrameColor(float& r, float& g, float& b) const;
+ void GetOverrideFrameColor(float& r, float& g, float& b, float& a) const;
KX_Scene* CreateScene(const STR_String& scenename);
KX_Scene* CreateScene(Scene *scene, bool libloading=false);
diff --git a/source/gameengine/Ketsji/KX_Light.cpp b/source/gameengine/Ketsji/KX_Light.cpp
index 9ccf60b15ce..5f490747c2b 100644
--- a/source/gameengine/Ketsji/KX_Light.cpp
+++ b/source/gameengine/Ketsji/KX_Light.cpp
@@ -195,7 +195,7 @@ int KX_LightObject::pyattr_set_layer(void *self_v, const KX_PYATTRIBUTE_DEF *att
PyErr_Format(PyExc_TypeError, "expected an integer greater than 1 for attribute \"%s\"", attrdef->m_name);
return PY_SET_ATTR_FAIL;
}
- else if(layer > MAX_LIGHT_LAYERS) {
+ else if (layer > MAX_LIGHT_LAYERS) {
PyErr_Format(PyExc_TypeError, "expected an integer less than %i for attribute \"%s\"", MAX_LIGHT_LAYERS, attrdef->m_name);
return PY_SET_ATTR_FAIL;
}
diff --git a/source/gameengine/Ketsji/KX_NavMeshObject.cpp b/source/gameengine/Ketsji/KX_NavMeshObject.cpp
index b8907ca5c6b..5beda2e038a 100644
--- a/source/gameengine/Ketsji/KX_NavMeshObject.cpp
+++ b/source/gameengine/Ketsji/KX_NavMeshObject.cpp
@@ -306,7 +306,12 @@ bool KX_NavMeshObject::BuildNavMesh()
|| vertsPerPoly<3)
{
printf("Can't build navigation mesh data for object:%s\n", m_name.ReadPtr());
- if (vertices) delete[] vertices;
+ if (vertices) {
+ delete[] vertices;
+ }
+ if (dvertices) {
+ delete[] dvertices;
+ }
return false;
}
diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp
index 9f173a567ee..cdc2f9f3644 100644
--- a/source/gameengine/Ketsji/KX_PythonInit.cpp
+++ b/source/gameengine/Ketsji/KX_PythonInit.cpp
@@ -104,6 +104,7 @@ extern "C" {
#include "BL_ArmatureObject.h"
#include "RAS_IRasterizer.h"
#include "RAS_ICanvas.h"
+#include "RAS_IOffScreen.h"
#include "RAS_BucketManager.h"
#include "RAS_2DFilterManager.h"
#include "MT_Vector3.h"
@@ -469,6 +470,21 @@ static PyObject *gPyGetExitKey(PyObject *)
return PyLong_FromLong(KX_KetsjiEngine::GetExitKey());
}
+static PyObject *gPySetRender(PyObject *, PyObject *args)
+{
+ int render;
+ if (!PyArg_ParseTuple(args, "i:setRender", &render))
+ return NULL;
+ KX_KetsjiEngine::SetRender(render);
+ Py_RETURN_NONE;
+}
+
+static PyObject *gPyGetRender(PyObject *)
+{
+ return PyBool_FromLong(KX_KetsjiEngine::GetRender());
+}
+
+
static PyObject *gPySetMaxLogicFrame(PyObject *, PyObject *args)
{
int frame;
@@ -909,6 +925,8 @@ static struct PyMethodDef game_methods[] = {
{"setAnimRecordFrame", (PyCFunction) gPySetAnimRecordFrame, METH_VARARGS, (const char *)"Sets the current frame number used for animation recording"},
{"getExitKey", (PyCFunction) gPyGetExitKey, METH_NOARGS, (const char *)"Gets the key used to exit the game engine"},
{"setExitKey", (PyCFunction) gPySetExitKey, METH_VARARGS, (const char *)"Sets the key used to exit the game engine"},
+ {"setRender", (PyCFunction) gPySetRender, METH_VARARGS, (const char *)"Set the global render flag"},
+ {"getRender", (PyCFunction) gPyGetRender, METH_NOARGS, (const char *)"get the global render flag value"},
{"getUseExternalClock", (PyCFunction) gPyGetUseExternalClock, METH_NOARGS, (const char *)"Get if we use the time provided by an external clock"},
{"setUseExternalClock", (PyCFunction) gPySetUseExternalClock, METH_VARARGS, (const char *)"Set if we use the time provided by an external clock"},
{"getClockTime", (PyCFunction) gPyGetClockTime, METH_NOARGS, (const char *)"Get the last BGE render time. "
@@ -1457,6 +1475,158 @@ static PyObject *gPyGetDisplayDimensions(PyObject *)
return result;
}
+
+/* python wrapper around RAS_IOffScreen
+ * Should eventually gets its own file
+ */
+
+static void PyRASOffScreen__tp_dealloc(PyRASOffScreen *self)
+{
+ if (self->ofs)
+ delete self->ofs;
+ Py_TYPE(self)->tp_free((PyObject *)self);
+}
+
+PyDoc_STRVAR(py_RASOffScreen_doc,
+"RASOffscreen(width, height) -> new GPU Offscreen object"
+"initialized to hold a framebuffer object of ``width`` x ``height``.\n"
+""
+);
+
+PyDoc_STRVAR(RASOffScreen_width_doc, "Offscreen buffer width.\n\n:type: integer");
+static PyObject *RASOffScreen_width_get(PyRASOffScreen *self, void *UNUSED(type))
+{
+ return PyLong_FromLong(self->ofs->GetWidth());
+}
+
+PyDoc_STRVAR(RASOffScreen_height_doc, "Offscreen buffer height.\n\n:type: GLsizei");
+static PyObject *RASOffScreen_height_get(PyRASOffScreen *self, void *UNUSED(type))
+{
+ return PyLong_FromLong(self->ofs->GetHeight());
+}
+
+PyDoc_STRVAR(RASOffScreen_color_doc, "Offscreen buffer texture object (if target is RAS_OFS_RENDER_TEXTURE).\n\n:type: GLuint");
+static PyObject *RASOffScreen_color_get(PyRASOffScreen *self, void *UNUSED(type))
+{
+ return PyLong_FromLong(self->ofs->GetColor());
+}
+
+static PyGetSetDef RASOffScreen_getseters[] = {
+ {(char *)"width", (getter)RASOffScreen_width_get, (setter)NULL, RASOffScreen_width_doc, NULL},
+ {(char *)"height", (getter)RASOffScreen_height_get, (setter)NULL, RASOffScreen_height_doc, NULL},
+ {(char *)"color", (getter)RASOffScreen_color_get, (setter)NULL, RASOffScreen_color_doc, NULL},
+ {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
+};
+
+static int PyRASOffScreen__tp_init(PyRASOffScreen *self, PyObject *args, PyObject *kwargs)
+{
+ int width, height, samples, target;
+ const char *keywords[] = {"width", "height", "samples", "target", NULL};
+
+ samples = 0;
+ target = RAS_IOffScreen::RAS_OFS_RENDER_BUFFER;
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii|ii:RASOffscreen", (char **)keywords, &width, &height, &samples, &target)) {
+ return -1;
+ }
+
+ if (width <= 0) {
+ PyErr_SetString(PyExc_ValueError, "negative 'width' given");
+ return -1;
+ }
+
+ if (height <= 0) {
+ PyErr_SetString(PyExc_ValueError, "negative 'height' given");
+ return -1;
+ }
+
+ if (samples < 0) {
+ PyErr_SetString(PyExc_ValueError, "negative 'samples' given");
+ return -1;
+ }
+
+ if (target != RAS_IOffScreen::RAS_OFS_RENDER_BUFFER && target != RAS_IOffScreen::RAS_OFS_RENDER_TEXTURE)
+ {
+ PyErr_SetString(PyExc_ValueError, "invalid 'target' given, can only be RAS_OFS_RENDER_BUFFER or RAS_OFS_RENDER_TEXTURE");
+ return -1;
+ }
+ if (!gp_Rasterizer)
+ {
+ PyErr_SetString(PyExc_SystemError, "no rasterizer");
+ return -1;
+ }
+ self->ofs = gp_Rasterizer->CreateOffScreen(width, height, samples, target);
+ if (!self->ofs) {
+ PyErr_SetString(PyExc_SystemError, "creation failed");
+ return -1;
+ }
+ return 0;
+}
+
+PyTypeObject PyRASOffScreen_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "RASOffScreen", /* tp_name */
+ sizeof(PyRASOffScreen), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ (destructor)PyRASOffScreen__tp_dealloc, /* tp_dealloc */
+ NULL, /* tp_print */
+ NULL, /* tp_getattr */
+ NULL, /* tp_setattr */
+ NULL, /* tp_compare */
+ NULL, /* tp_repr */
+ NULL, /* tp_as_number */
+ NULL, /* tp_as_sequence */
+ NULL, /* tp_as_mapping */
+ NULL, /* tp_hash */
+ NULL, /* tp_call */
+ NULL, /* tp_str */
+ NULL, /* tp_getattro */
+ NULL, /* tp_setattro */
+ NULL, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ py_RASOffScreen_doc, /* Documentation string */
+ NULL, /* tp_traverse */
+ NULL, /* tp_clear */
+ NULL, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ NULL, /* tp_iter */
+ NULL, /* tp_iternext */
+ NULL, /* tp_methods */
+ NULL, /* tp_members */
+ RASOffScreen_getseters, /* tp_getset */
+ NULL, /* tp_base */
+ NULL, /* tp_dict */
+ NULL, /* tp_descr_get */
+ NULL, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)PyRASOffScreen__tp_init, /* tp_init */
+ (allocfunc)PyType_GenericAlloc, /* tp_alloc */
+ (newfunc)PyType_GenericNew, /* tp_new */
+ (freefunc)0, /* tp_free */
+ NULL, /* tp_is_gc */
+ NULL, /* tp_bases */
+ NULL, /* tp_mro */
+ NULL, /* tp_cache */
+ NULL, /* tp_subclasses */
+ NULL, /* tp_weaklist */
+ (destructor) NULL /* tp_del */
+};
+
+
+static PyObject *gPyOffScreenCreate(PyObject *UNUSED(self), PyObject *args)
+{
+ int width;
+ int height;
+ int samples;
+ int target;
+
+ samples = 0;
+ if (!PyArg_ParseTuple(args, "ii|ii:offScreenCreate", &width, &height, &samples, &target))
+ return NULL;
+
+ return PyObject_CallObject((PyObject *) &PyRASOffScreen_Type, args);
+}
+
PyDoc_STRVAR(Rasterizer_module_documentation,
"This is the Python API for the game engine of Rasterizer"
);
@@ -1511,6 +1681,7 @@ static struct PyMethodDef rasterizer_methods[] = {
{"showProperties",(PyCFunction) gPyShowProperties, METH_VARARGS, "show or hide the debug properties"},
{"autoDebugList",(PyCFunction) gPyAutoDebugList, METH_VARARGS, "enable or disable auto adding debug properties to the debug list"},
{"clearDebugList",(PyCFunction) gPyClearDebugList, METH_NOARGS, "clears the debug property list"},
+ {"offScreenCreate", (PyCFunction) gPyOffScreenCreate, METH_VARARGS, "create an offscreen buffer object, arguments are width and height in pixels"},
{ NULL, (PyCFunction) NULL, 0, NULL }
};
@@ -2330,6 +2501,8 @@ PyMODINIT_FUNC initRasterizerPythonBinding()
PyObject *m;
PyObject *d;
+ PyType_Ready(&PyRASOffScreen_Type);
+
m = PyModule_Create(&Rasterizer_module_def);
PyDict_SetItemString(PySys_GetObject("modules"), Rasterizer_module_def.m_name, m);
@@ -2357,6 +2530,11 @@ PyMODINIT_FUNC initRasterizerPythonBinding()
KX_MACRO_addTypesToDict(d, LEFT_EYE, RAS_IRasterizer::RAS_STEREO_LEFTEYE);
KX_MACRO_addTypesToDict(d, RIGHT_EYE, RAS_IRasterizer::RAS_STEREO_RIGHTEYE);
+ /* offscreen render */
+ KX_MACRO_addTypesToDict(d, RAS_OFS_RENDER_BUFFER, RAS_IOffScreen::RAS_OFS_RENDER_BUFFER);
+ KX_MACRO_addTypesToDict(d, RAS_OFS_RENDER_TEXTURE, RAS_IOffScreen::RAS_OFS_RENDER_TEXTURE);
+
+
// XXXX Add constants here
// Check for errors
diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp
index a5a418b5e78..b3061087344 100644
--- a/source/gameengine/Ketsji/KX_Scene.cpp
+++ b/source/gameengine/Ketsji/KX_Scene.cpp
@@ -172,6 +172,7 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice,
m_activity_culling = false;
m_suspend = false;
m_isclearingZbuffer = true;
+ m_isShadowDone = false;
m_tempObjectList = new CListValue();
m_objectlist = new CListValue();
m_parentlist = new CListValue();
@@ -1664,7 +1665,7 @@ static void update_anim_thread_func(TaskPool *pool, void *taskdata, int UNUSED(t
// Only do deformers here if they are not parented to an armature, otherwise the armature will
// handle updating its children
- if (gameobj->GetDeformer() && (!parent || (parent && parent->GetGameObjectType() != SCA_IObject::OBJ_ARMATURE)))
+ if (gameobj->GetDeformer() && (!parent || parent->GetGameObjectType() != SCA_IObject::OBJ_ARMATURE))
gameobj->GetDeformer()->Update();
for (int j=0; j<children->GetCount(); ++j) {
@@ -1784,7 +1785,7 @@ void KX_Scene::UpdateObjectLods(void)
for (int i = 0; i < this->GetObjectList()->GetCount(); i++) {
gameobj = (KX_GameObject*) GetObjectList()->GetValue(i);
- if (!gameobj->GetCulled()){
+ if (!gameobj->GetCulled()) {
gameobj->UpdateLod(cam_pos);
}
}
diff --git a/source/gameengine/Ketsji/KX_Scene.h b/source/gameengine/Ketsji/KX_Scene.h
index c43b7be45dc..6d8ae8a321b 100644
--- a/source/gameengine/Ketsji/KX_Scene.h
+++ b/source/gameengine/Ketsji/KX_Scene.h
@@ -172,6 +172,11 @@ protected:
bool m_isclearingZbuffer;
/**
+ * Does the shadow buffer needs calculing
+ */
+ bool m_isShadowDone;
+
+ /**
* The name of the scene
*/
STR_String m_sceneName;
@@ -572,6 +577,8 @@ public:
bool IsSuspended();
bool IsClearingZBuffer();
void EnableZBufferClearing(bool isclearingZbuffer);
+ bool IsShadowDone() { return m_isShadowDone; }
+ void SetShadowDone(bool b) { m_isShadowDone = b; }
// use of DBVT tree for camera culling
void SetDbvtCulling(bool b) { m_dbvt_culling = b; }
bool GetDbvtCulling() { return m_dbvt_culling; }
diff --git a/source/gameengine/Ketsji/KX_SoundActuator.cpp b/source/gameengine/Ketsji/KX_SoundActuator.cpp
index 1c42d65ae75..a27f37c0441 100644
--- a/source/gameengine/Ketsji/KX_SoundActuator.cpp
+++ b/source/gameengine/Ketsji/KX_SoundActuator.cpp
@@ -79,21 +79,18 @@ KX_SoundActuator::KX_SoundActuator(SCA_IObject* gameobj,
KX_SoundActuator::~KX_SoundActuator()
{
- if(m_handle)
- {
+ if (m_handle) {
AUD_Handle_stop(m_handle);
}
- if(m_sound)
- {
+ if (m_sound) {
AUD_Sound_free(m_sound);
}
}
void KX_SoundActuator::play()
{
- if(m_handle)
- {
+ if (m_handle) {
AUD_Handle_stop(m_handle);
m_handle = NULL;
}
@@ -130,10 +127,8 @@ void KX_SoundActuator::play()
if(sound != m_sound)
AUD_Sound_free(sound);
- if (m_handle != NULL)
- {
- if (m_is3d)
- {
+ if (m_handle != NULL) {
+ if (m_is3d) {
AUD_Handle_setRelative(m_handle, true);
AUD_Handle_setVolumeMaximum(m_handle, m_3d.max_gain);
AUD_Handle_setVolumeMinimum(m_handle, m_3d.min_gain);
diff --git a/source/gameengine/Ketsji/KX_TrackToActuator.cpp b/source/gameengine/Ketsji/KX_TrackToActuator.cpp
index beccdfaad93..a8fa9b0815d 100644
--- a/source/gameengine/Ketsji/KX_TrackToActuator.cpp
+++ b/source/gameengine/Ketsji/KX_TrackToActuator.cpp
@@ -207,7 +207,7 @@ static MT_Matrix3x3 vectomat(MT_Vector3 vec, short axis, short upflag, short thr
vec = vec.safe_normalized_vec(z);
/* if 2D doesn't move the up vector */
- if (!threedimup){
+ if (!threedimup) {
vec.setValue(MT_Scalar(vec[0]), MT_Scalar(vec[1]), MT_Scalar(0.0f));
vec = (vec - z.dot(vec)*z).safe_normalized_vec(z);
}
diff --git a/source/gameengine/Ketsji/KX_VehicleWrapper.cpp b/source/gameengine/Ketsji/KX_VehicleWrapper.cpp
index c1af6de127e..ddae645802c 100644
--- a/source/gameengine/Ketsji/KX_VehicleWrapper.cpp
+++ b/source/gameengine/Ketsji/KX_VehicleWrapper.cpp
@@ -89,17 +89,17 @@ PyObject *KX_VehicleWrapper::PyAddWheel(PyObject *args)
if (gameOb->GetSGNode())
{
MT_Vector3 attachPos,attachDir,attachAxle;
- if(!PyVecTo(pylistPos,attachPos)) {
+ if (!PyVecTo(pylistPos,attachPos)) {
PyErr_SetString(PyExc_AttributeError,
"addWheel(...) Unable to add wheel. attachPos must be a vector with 3 elements.");
return NULL;
}
- if(!PyVecTo(pylistDir,attachDir)) {
+ if (!PyVecTo(pylistDir,attachDir)) {
PyErr_SetString(PyExc_AttributeError,
"addWheel(...) Unable to add wheel. downDir must be a vector with 3 elements.");
return NULL;
}
- if(!PyVecTo(pylistAxleDir,attachAxle)) {
+ if (!PyVecTo(pylistAxleDir,attachAxle)) {
PyErr_SetString(PyExc_AttributeError,
"addWheel(...) Unable to add wheel. axleDir must be a vector with 3 elements.");
return NULL;
@@ -108,7 +108,7 @@ PyObject *KX_VehicleWrapper::PyAddWheel(PyObject *args)
//someone reverse some conventions inside Bullet (axle winding)
attachAxle = -attachAxle;
- if(wheelRadius<=0) {
+ if (wheelRadius <= 0) {
PyErr_SetString(PyExc_AttributeError,
"addWheel(...) Unable to add wheel. wheelRadius must be positive.");
return NULL;
diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.h b/source/gameengine/Physics/Bullet/CcdPhysicsController.h
index 58ea5e2e390..831e7346df7 100644
--- a/source/gameengine/Physics/Bullet/CcdPhysicsController.h
+++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.h
@@ -430,7 +430,7 @@ public:
// PHY_ICharacter interface
virtual void Jump() { jump(); }
- virtual bool OnGround(){ return onGround(); }
+ virtual bool OnGround() { return onGround(); }
virtual float GetGravity() { return getGravity(); }
virtual void SetGravity(float gravity) { setGravity(gravity); }
virtual unsigned char GetMaxJumps() { return getMaxJumps(); }
@@ -542,14 +542,14 @@ protected:
CcdPhysicsController (const CcdConstructionInfo& ci);
/**
- * Delete the current Bullet shape used in the rigid body.
- */
+ * Delete the current Bullet shape used in the rigid body.
+ */
bool DeleteControllerShape();
/**
- * Delete the old Bullet shape and set the new Bullet shape : newShape
- * \param newShape The new Bullet shape to set, if is NULL we create a new Bullet shape
- */
+ * Delete the old Bullet shape and set the new Bullet shape : newShape
+ * \param newShape The new Bullet shape to set, if is NULL we create a new Bullet shape
+ */
bool ReplaceControllerShape(btCollisionShape *newShape);
virtual ~CcdPhysicsController();
diff --git a/source/gameengine/Physics/common/PHY_ICharacter.h b/source/gameengine/Physics/common/PHY_ICharacter.h
index 81c567ef08a..1a924904b7d 100644
--- a/source/gameengine/Physics/common/PHY_ICharacter.h
+++ b/source/gameengine/Physics/common/PHY_ICharacter.h
@@ -15,7 +15,7 @@
class PHY_ICharacter
{
public:
- virtual ~PHY_ICharacter(){};
+ virtual ~PHY_ICharacter() {};
virtual void Jump()= 0;
virtual bool OnGround()= 0;
diff --git a/source/gameengine/Physics/common/PHY_IController.h b/source/gameengine/Physics/common/PHY_IController.h
index 284d77ca221..741fae8d2ad 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_IMotionState.h b/source/gameengine/Physics/common/PHY_IMotionState.h
index d40b8da9451..e803d658713 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.h b/source/gameengine/Physics/common/PHY_IPhysicsController.h
index 62b163536dd..4c6e8c71ef7 100644
--- a/source/gameengine/Physics/common/PHY_IPhysicsController.h
+++ b/source/gameengine/Physics/common/PHY_IPhysicsController.h
@@ -53,7 +53,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.h b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h
index 2997048805f..72ec7b1edd0 100644
--- a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h
+++ b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h
@@ -116,7 +116,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.h b/source/gameengine/Physics/common/PHY_IVehicle.h
index 1dcec69a335..7e4a49e923e 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/Rasterizer/CMakeLists.txt b/source/gameengine/Rasterizer/CMakeLists.txt
index 496a864244b..c65fcac5161 100644
--- a/source/gameengine/Rasterizer/CMakeLists.txt
+++ b/source/gameengine/Rasterizer/CMakeLists.txt
@@ -65,6 +65,8 @@ set(SRC
RAS_IPolygonMaterial.h
RAS_IRasterizer.h
RAS_ILightObject.h
+ RAS_IOffScreen.h
+ RAS_ISync.h
RAS_MaterialBucket.h
RAS_MeshObject.h
RAS_ObjectColor.h
diff --git a/source/gameengine/Rasterizer/RAS_IOffScreen.h b/source/gameengine/Rasterizer/RAS_IOffScreen.h
new file mode 100644
index 00000000000..d61a31504b8
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_IOffScreen.h
@@ -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.
+ *
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file RAS_IOffScreen.h
+ * \ingroup bgerast
+ */
+
+#ifndef __RAS_OFFSCREEN_H__
+#define __RAS_OFFSCREEN_H__
+
+#include "EXP_Python.h"
+
+class RAS_ICanvas;
+
+class MT_Transform;
+
+struct Image;
+
+class RAS_IOffScreen
+{
+public:
+ enum RAS_OFS_BIND_MODE {
+ RAS_OFS_BIND_RENDER = 0,
+ RAS_OFS_BIND_READ,
+ };
+ enum RAS_OFS_RENDER_TARGET {
+ RAS_OFS_RENDER_BUFFER = 0, // use render buffer as render target
+ RAS_OFS_RENDER_TEXTURE, // use texture as render target
+ };
+
+ int m_width;
+ int m_height;
+ int m_samples;
+ int m_color; // if used, holds the texture object, 0 if not used
+
+ virtual ~RAS_IOffScreen() {}
+
+ virtual bool Create(int width, int height, int samples, RAS_OFS_RENDER_TARGET target) = 0;
+ virtual void Destroy() = 0;
+ virtual void Bind(RAS_OFS_BIND_MODE mode) = 0;
+ virtual void Blit() = 0;
+ virtual void Unbind() = 0;
+ virtual void MipMap() = 0;
+
+ virtual int GetWidth() { return m_width; }
+ virtual int GetHeight() { return m_height; }
+ virtual int GetSamples() { return m_samples; }
+ virtual int GetColor() { return m_color; }
+};
+
+#ifdef WITH_PYTHON
+typedef struct {
+ PyObject_HEAD
+ RAS_IOffScreen *ofs;
+} PyRASOffScreen;
+
+extern PyTypeObject PyRASOffScreen_Type;
+#endif
+
+#endif /* __RAS_OFFSCREEN_H__ */
diff --git a/source/gameengine/Rasterizer/RAS_IRasterizer.h b/source/gameengine/Rasterizer/RAS_IRasterizer.h
index a92b87773c7..dc92408915b 100644
--- a/source/gameengine/Rasterizer/RAS_IRasterizer.h
+++ b/source/gameengine/Rasterizer/RAS_IRasterizer.h
@@ -55,6 +55,8 @@ class RAS_IPolyMaterial;
class RAS_MeshSlot;
class RAS_ILightObject;
class SCA_IScene;
+class RAS_IOffScreen;
+class RAS_ISync;
typedef vector<unsigned short> KX_IndexArray;
typedef vector<RAS_TexVert> KX_VertexArray;
@@ -258,6 +260,18 @@ public:
virtual float GetFocalLength() = 0;
/**
+ * Create an offscreen render buffer that can be used as target for render.
+ * For the time being, it is only used in VideoTexture for custom render.
+ */
+ virtual RAS_IOffScreen *CreateOffScreen(int width, int height, int samples, int target) = 0;
+
+ /**
+ * Create a sync object
+ * For use with offscreen render
+ */
+ virtual RAS_ISync *CreateSync(int type) = 0;
+
+ /**
* SwapBuffers swaps the back buffer with the front buffer.
*/
virtual void SwapBuffers() = 0;
@@ -287,7 +301,7 @@ public:
* Sets the modelview matrix.
*/
virtual void SetViewMatrix(const MT_Matrix4x4 &mat, const MT_Matrix3x3 &ori,
- const MT_Point3 &pos, bool perspective) = 0;
+ const MT_Point3 &pos, const MT_Vector3 &scale, bool perspective) = 0;
/**
*/
diff --git a/source/gameengine/Rasterizer/RAS_ISync.h b/source/gameengine/Rasterizer/RAS_ISync.h
new file mode 100644
index 00000000000..7e34172c2a3
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_ISync.h
@@ -0,0 +1,48 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file RAS_ISync.h
+ * \ingroup bgerast
+ */
+
+#ifndef __RAS_ISYNC_H__
+#define __RAS_ISYNC_H__
+
+class RAS_ISync
+{
+public:
+ enum RAS_SYNC_TYPE {
+ RAS_SYNC_TYPE_FENCE = 0,
+ };
+ virtual ~RAS_ISync() {}
+
+ virtual bool Create(RAS_SYNC_TYPE type) = 0;
+ virtual void Destroy() = 0;
+ virtual void Wait() = 0;
+};
+
+#endif /* __RAS_ISYNC_H__ */
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt
index 9f95e2c82af..89e31b62b41 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt
@@ -51,6 +51,8 @@ set(INC_SYS
set(SRC
RAS_ListRasterizer.cpp
RAS_OpenGLLight.cpp
+ RAS_OpenGLOffScreen.cpp
+ RAS_OpenGLSync.cpp
RAS_OpenGLRasterizer.cpp
RAS_StorageVA.cpp
RAS_StorageVBO.cpp
@@ -58,6 +60,8 @@ set(SRC
RAS_IStorage.h
RAS_ListRasterizer.h
RAS_OpenGLLight.h
+ RAS_OpenGLOffScreen.h
+ RAS_OpenGLSync.h
RAS_OpenGLRasterizer.h
RAS_StorageVA.h
RAS_StorageVBO.h
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp
index e15ae4bd0d7..fff988a07c5 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp
@@ -242,7 +242,7 @@ void RAS_OpenGLLight::BindShadowBuffer(RAS_ICanvas *canvas, KX_Camera *cam, MT_T
RAS_IRasterizer::StereoMode stereomode = m_rasterizer->GetStereoMode();
m_rasterizer->SetStereoMode(RAS_IRasterizer::RAS_STEREO_NOSTEREO);
m_rasterizer->SetProjectionMatrix(projectionmat);
- m_rasterizer->SetViewMatrix(modelviewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->GetCameraData()->m_perspective);
+ m_rasterizer->SetViewMatrix(modelviewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->NodeGetLocalScaling(), cam->GetCameraData()->m_perspective);
m_rasterizer->SetStereoMode(stereomode);
}
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp
new file mode 100644
index 00000000000..e589bffcaf1
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp
@@ -0,0 +1,347 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "glew-mx.h"
+
+#include <stdio.h>
+
+#include "RAS_OpenGLOffScreen.h"
+#include "RAS_ICanvas.h"
+
+RAS_OpenGLOffScreen::RAS_OpenGLOffScreen(RAS_ICanvas *canvas)
+ :m_canvas(canvas), m_depthrb(0), m_colorrb(0), m_depthtx(0), m_colortx(0),
+ m_fbo(0), m_blitfbo(0), m_blitrbo(0), m_blittex(0), m_target(RAS_OFS_RENDER_BUFFER), m_bound(false)
+{
+ m_width = 0;
+ m_height = 0;
+ m_samples = 0;
+ m_color = 0;
+}
+
+RAS_OpenGLOffScreen::~RAS_OpenGLOffScreen()
+{
+ Destroy();
+}
+
+bool RAS_OpenGLOffScreen::Create(int width, int height, int samples, RAS_OFS_RENDER_TARGET target)
+{
+ GLenum status;
+ GLuint glo[2], fbo;
+ GLint max_samples;
+ GLenum textarget;
+
+ if (m_fbo) {
+ printf("RAS_OpenGLOffScreen::Create(): buffer exists already, destroy first\n");
+ return false;
+ }
+ if (target != RAS_IOffScreen::RAS_OFS_RENDER_BUFFER &&
+ target != RAS_IOffScreen::RAS_OFS_RENDER_TEXTURE)
+ {
+ printf("RAS_OpenGLOffScreen::Create(): invalid offscren target\n");
+ return false;
+ }
+ if (!GLEW_EXT_framebuffer_object) {
+ printf("RAS_OpenGLOffScreen::Create(): frame buffer not supported\n");
+ return false;
+ }
+ if (samples) {
+ if (!GLEW_EXT_framebuffer_multisample ||
+ !GLEW_EXT_framebuffer_blit)
+ {
+ samples = 0;
+ }
+ }
+ if (samples && target == RAS_OFS_RENDER_TEXTURE) {
+ // we need this in addition if we use multisample textures
+ if (!GLEW_ARB_texture_multisample ||
+ !GLEW_EXT_framebuffer_multisample_blit_scaled)
+ {
+ samples = 0;
+ }
+ }
+ if (samples) {
+ max_samples = 0;
+ glGetIntegerv(GL_MAX_SAMPLES_EXT , &max_samples);
+ if (samples > max_samples)
+ samples = max_samples;
+ }
+ m_target = target;
+ fbo = 0;
+ glGenFramebuffersEXT(1, &fbo);
+ if (fbo == 0) {
+ printf("RAS_OpenGLOffScreen::Create(): frame buffer creation failed: %d\n", (int)glGetError());
+ return false;
+ }
+ m_fbo = fbo;
+ glo[0] = glo[1] = 0;
+ if (target == RAS_OFS_RENDER_TEXTURE) {
+ glGenTextures(2, glo);
+ if (glo[0] == 0 || glo[1] == 0) {
+ printf("RAS_OpenGLOffScreen::Create(): texture creation failed: %d\n", (int)glGetError());
+ goto L_ERROR;
+ }
+ m_depthtx = glo[0];
+ m_color = m_colortx = glo[1];
+ if (samples) {
+ textarget = GL_TEXTURE_2D_MULTISAMPLE;
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_depthtx);
+ glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_DEPTH_COMPONENT, width, height, true);
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_colortx);
+ glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGBA8, width, height, true);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
+ }
+ else {
+ textarget = GL_TEXTURE_2D;
+ glBindTexture(GL_TEXTURE_2D, m_depthtx);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
+ glBindTexture(GL_TEXTURE_2D, m_colortx);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, textarget, m_depthtx, 0);
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, textarget, m_colortx, 0);
+ }
+ else {
+ glGenRenderbuffersEXT(2, glo);
+ if (glo[0] == 0 || glo[1] == 0) {
+ printf("RAS_OpenGLOffScreen::Create(): render buffer creation failed: %d\n", (int)glGetError());
+ goto L_ERROR;
+ }
+ m_depthrb = glo[0];
+ m_colorrb = glo[1];
+ glBindRenderbufferEXT(GL_RENDERBUFFER, m_depthrb);
+ glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples, GL_DEPTH_COMPONENT, width, height);
+ glBindRenderbufferEXT(GL_RENDERBUFFER, m_colorrb);
+ glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples, GL_RGBA8, width, height);
+ glBindRenderbufferEXT(GL_RENDERBUFFER, 0);
+
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER, m_depthrb);
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER, m_colorrb);
+ }
+ status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+
+ if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+ printf("RAS_OpenGLOffScreen::Create(): frame buffer incomplete: %d\n", (int)status);
+ goto L_ERROR;
+ }
+ m_width = width;
+ m_height = height;
+
+ if (samples > 0) {
+ GLuint blit_tex;
+ GLuint blit_fbo;
+ // create a secondary FBO to blit to before the pixel can be read
+
+ /* write into new single-sample buffer */
+ glGenFramebuffersEXT(1, &blit_fbo);
+ if (!blit_fbo) {
+ printf("RAS_OpenGLOffScreen::Create(): failed creating a FBO for multi-sample offscreen buffer\n");
+ goto L_ERROR;
+ }
+ m_blitfbo = blit_fbo;
+ blit_tex = 0;
+ if (target == RAS_OFS_RENDER_TEXTURE) {
+ glGenTextures(1, &blit_tex);
+ if (!blit_tex) {
+ printf("RAS_OpenGLOffScreen::Create(): failed creating a texture for multi-sample offscreen buffer\n");
+ goto L_ERROR;
+ }
+ // m_color is the texture where the final render goes, the blit texture in this case
+ m_color = m_blittex = blit_tex;
+ glBindTexture(GL_TEXTURE_2D, m_blittex);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_blitfbo);
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_blittex, 0);
+ }
+ else {
+ /* create render buffer for new 'fbo_blit' */
+ glGenRenderbuffersEXT(1, &blit_tex);
+ if (!blit_tex) {
+ printf("RAS_OpenGLOffScreen::Create(): failed creating a render buffer for multi-sample offscreen buffer\n");
+ goto L_ERROR;
+ }
+ m_blitrbo = blit_tex;
+ glBindRenderbufferEXT(GL_RENDERBUFFER, m_blitrbo);
+ glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, 0, GL_RGBA8, width, height);
+ glBindRenderbufferEXT(GL_RENDERBUFFER, 0);
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_blitfbo);
+ glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER, m_blitrbo);
+ }
+ status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER_EXT);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, 0);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ printf("RAS_OpenGLOffScreen::Create(): frame buffer for multi-sample offscreen buffer incomplete: %d\n", (int)status);
+ goto L_ERROR;
+ }
+ // remember that multisample is enabled
+ m_samples = 1;
+ }
+ return true;
+
+L_ERROR:
+ Destroy();
+ return false;
+}
+
+void RAS_OpenGLOffScreen::Destroy()
+{
+ GLuint globj;
+ Unbind();
+ if (m_fbo) {
+ globj = m_fbo;
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
+ if (m_target == RAS_OFS_RENDER_TEXTURE) {
+ GLenum textarget = (m_samples) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, textarget, 0, 0);
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, textarget, 0, 0);
+ }
+ else {
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, 0);
+ }
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ glDeleteFramebuffersEXT(1, &globj);
+ m_fbo = 0;
+ }
+ if (m_depthrb) {
+ globj = m_depthrb;
+ glDeleteRenderbuffers(1, &globj);
+ m_depthrb = 0;
+ }
+ if (m_colorrb) {
+ globj = m_colorrb;
+ glDeleteRenderbuffers(1, &globj);
+ m_colorrb = 0;
+ }
+ if (m_depthtx) {
+ globj = m_depthtx;
+ glDeleteTextures(1, &globj);
+ m_depthtx = 0;
+ }
+ if (m_colortx) {
+ globj = m_colortx;
+ glDeleteTextures(1, &globj);
+ m_colortx = 0;
+ }
+ if (m_blitfbo) {
+ globj = m_blitfbo;
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_blitfbo);
+ if (m_target == RAS_OFS_RENDER_TEXTURE) {
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 0, 0);
+ }
+ else {
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, 0);
+ }
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ glDeleteFramebuffersEXT(1, &globj);
+ m_blitfbo = 0;
+ }
+ if (m_blitrbo) {
+ globj = m_blitrbo;
+ glDeleteRenderbuffers(1, &globj);
+ m_blitrbo = 0;
+ }
+ if (m_blittex) {
+ globj = m_blittex;
+ glDeleteTextures(1, &globj);
+ m_blittex = 0;
+ }
+ m_width = 0;
+ m_height = 0;
+ m_samples = 0;
+ m_color = 0;
+ m_target = RAS_OFS_RENDER_BUFFER;
+}
+
+void RAS_OpenGLOffScreen::Bind(RAS_OFS_BIND_MODE mode)
+{
+ if (m_fbo) {
+ if (mode == RAS_OFS_BIND_RENDER) {
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
+ glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
+ glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
+ glViewport(0, 0, m_width, m_height);
+ glDisable(GL_SCISSOR_TEST);
+ }
+ else if (!m_blitfbo) {
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
+ glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
+ }
+ else {
+ glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_blitfbo);
+ glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
+ }
+ m_bound = true;
+ }
+}
+
+void RAS_OpenGLOffScreen::Unbind()
+{
+ if (!m_bound)
+ return;
+
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ glEnable(GL_SCISSOR_TEST);
+ glReadBuffer(GL_BACK);
+ glDrawBuffer(GL_BACK);
+ m_bound = false;
+}
+
+void RAS_OpenGLOffScreen::MipMap()
+{
+ if (m_color) {
+ glBindTexture(GL_TEXTURE_2D, m_color);
+ glGenerateMipmap(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+}
+
+void RAS_OpenGLOffScreen::Blit()
+{
+ if (m_bound && m_blitfbo) {
+ // set the draw target to the secondary FBO, the read target is still the multisample FBO
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, m_blitfbo);
+
+ // sample the primary
+ glBlitFramebufferEXT(0, 0, m_width, m_height, 0, 0, m_width, m_height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+
+ // make sure the next glReadPixels will read from the secondary buffer
+ glBindFramebufferEXT(GL_READ_FRAMEBUFFER, m_blitfbo);
+ }
+}
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.h
new file mode 100644
index 00000000000..3f6845f1e21
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.h
@@ -0,0 +1,65 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __RAS_OPENGLOFFSCREEN__
+#define __RAS_OPENGLOFFSCREEN__
+
+#include "RAS_IOffScreen.h"
+#include "GPU_extensions.h"
+
+class RAS_ICanvas;
+
+class RAS_OpenGLOffScreen : public RAS_IOffScreen
+{
+ RAS_ICanvas *m_canvas;
+ // these are GL objects
+ unsigned int m_depthrb;
+ unsigned int m_colorrb;
+ unsigned int m_depthtx;
+ unsigned int m_colortx;
+ unsigned int m_fbo;
+ unsigned int m_blitfbo;
+ unsigned int m_blitrbo;
+ unsigned int m_blittex;
+ RAS_OFS_RENDER_TARGET m_target;
+ bool m_bound;
+
+
+public:
+ RAS_OpenGLOffScreen(RAS_ICanvas *canvas);
+ ~RAS_OpenGLOffScreen();
+
+ bool Create(int width, int height, int samples, RAS_OFS_RENDER_TARGET target);
+ void Destroy();
+ void Bind(RAS_OFS_BIND_MODE mode);
+ void Blit();
+ void Unbind();
+ void MipMap();
+};
+
+#endif /* __RAS_OPENGLOFFSCREEN__ */
+
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
index 34f0ef04a58..3f82c513f7d 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
@@ -46,6 +46,8 @@
#include "MT_CmMatrix4x4.h"
#include "RAS_OpenGLLight.h"
+#include "RAS_OpenGLOffScreen.h"
+#include "RAS_OpenGLSync.h"
#include "RAS_StorageVA.h"
#include "RAS_StorageVBO.h"
@@ -92,6 +94,7 @@ RAS_OpenGLRasterizer::RAS_OpenGLRasterizer(RAS_ICanvas* canvas, RAS_STORAGE_TYPE
m_time(0.0f),
m_campos(0.0f, 0.0f, 0.0f),
m_camortho(false),
+ m_camnegscale(false),
m_stereomode(RAS_STEREO_NOSTEREO),
m_curreye(RAS_STEREO_LEFTEYE),
m_eyeseparation(0.0f),
@@ -138,8 +141,6 @@ RAS_OpenGLRasterizer::RAS_OpenGLRasterizer(RAS_ICanvas* canvas, RAS_STORAGE_TYPE
glGetIntegerv(GL_MAX_LIGHTS, (GLint *) &m_numgllights);
if (m_numgllights < 8)
m_numgllights = 8;
-
- PrintHardwareInfo();
}
@@ -207,7 +208,7 @@ void RAS_OpenGLRasterizer::SetBackColor(float color[3])
m_redback = color[0];
m_greenback = color[1];
m_blueback = color[2];
- m_alphaback = 1.0f;
+ m_alphaback = 0.0f;
}
void RAS_OpenGLRasterizer::SetFog(short type, float start, float dist, float intensity, float color[3])
@@ -600,6 +601,31 @@ float RAS_OpenGLRasterizer::GetFocalLength()
return m_focallength;
}
+RAS_IOffScreen *RAS_OpenGLRasterizer::CreateOffScreen(int width, int height, int samples, int target)
+{
+ RAS_IOffScreen *ofs;
+
+ ofs = new RAS_OpenGLOffScreen(m_2DCanvas);
+
+ if (!ofs->Create(width, height, samples, (RAS_IOffScreen::RAS_OFS_RENDER_TARGET)target)) {
+ delete ofs;
+ return NULL;
+ }
+ return ofs;
+}
+
+RAS_ISync *RAS_OpenGLRasterizer::CreateSync(int type)
+{
+ RAS_ISync *sync;
+
+ sync = new RAS_OpenGLSync();
+
+ if (!sync->Create((RAS_ISync::RAS_SYNC_TYPE)type)) {
+ delete sync;
+ return NULL;
+ }
+ return sync;
+}
void RAS_OpenGLRasterizer::SwapBuffers()
{
@@ -924,6 +950,7 @@ MT_Matrix4x4 RAS_OpenGLRasterizer::GetOrthoMatrix(
void RAS_OpenGLRasterizer::SetViewMatrix(const MT_Matrix4x4 &mat,
const MT_Matrix3x3 & camOrientMat3x3,
const MT_Point3 & pos,
+ const MT_Vector3 &scale,
bool perspective)
{
m_viewmatrix = mat;
@@ -966,6 +993,12 @@ void RAS_OpenGLRasterizer::SetViewMatrix(const MT_Matrix4x4 &mat,
}
}
+ bool negX = (scale[0] < 0.0f);
+ bool negY = (scale[0] < 0.0f);
+ bool negZ = (scale[0] < 0.0f);
+ if (negX || negY || negZ) {
+ m_viewmatrix.tscale((negX)?-1.0f:1.0f, (negY)?-1.0f:1.0f, (negZ)?-1.0f:1.0f, 1.0);
+ }
m_viewinvmatrix = m_viewmatrix;
m_viewinvmatrix.invert();
@@ -976,6 +1009,7 @@ void RAS_OpenGLRasterizer::SetViewMatrix(const MT_Matrix4x4 &mat,
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(glviewmat);
m_campos = pos;
+ m_camnegscale = negX ^ negY ^ negZ;
}
@@ -1108,6 +1142,9 @@ void RAS_OpenGLRasterizer::SetAlphaBlend(int alphablend)
void RAS_OpenGLRasterizer::SetFrontFace(bool ccw)
{
+ if (m_camnegscale)
+ ccw = !ccw;
+
if (m_last_frontface == ccw)
return;
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h
index 4c22d1de611..9561e207dba 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h
@@ -96,6 +96,7 @@ class RAS_OpenGLRasterizer : public RAS_IRasterizer
MT_Matrix4x4 m_viewinvmatrix;
MT_Point3 m_campos;
bool m_camortho;
+ bool m_camnegscale;
StereoMode m_stereomode;
StereoEye m_curreye;
@@ -180,7 +181,8 @@ public:
virtual float GetEyeSeparation();
virtual void SetFocalLength(const float focallength);
virtual float GetFocalLength();
-
+ virtual RAS_IOffScreen *CreateOffScreen(int width, int height, int samples, int target);
+ virtual RAS_ISync *CreateSync(int type);
virtual void SwapBuffers();
virtual void IndexPrimitives(class RAS_MeshSlot &ms);
@@ -189,7 +191,12 @@ public:
virtual void SetProjectionMatrix(MT_CmMatrix4x4 &mat);
virtual void SetProjectionMatrix(const MT_Matrix4x4 &mat);
- virtual void SetViewMatrix(const MT_Matrix4x4 &mat, const MT_Matrix3x3 &ori, const MT_Point3 &pos, bool perspective);
+ virtual void SetViewMatrix(
+ const MT_Matrix4x4 &mat,
+ const MT_Matrix3x3 &ori,
+ const MT_Point3 &pos,
+ const MT_Vector3 &scale,
+ bool perspective);
virtual const MT_Point3& GetCameraPosition();
virtual bool GetCameraOrtho();
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp
new file mode 100644
index 00000000000..d54b3232067
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp
@@ -0,0 +1,82 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "glew-mx.h"
+
+#include <stdio.h>
+
+#include "RAS_OpenGLSync.h"
+
+RAS_OpenGLSync::RAS_OpenGLSync()
+ :m_sync(NULL)
+{
+}
+
+RAS_OpenGLSync::~RAS_OpenGLSync()
+{
+ Destroy();
+}
+
+bool RAS_OpenGLSync::Create(RAS_SYNC_TYPE type)
+{
+ if (m_sync) {
+ printf("RAS_OpenGLSync::Create(): sync already exists, destroy first\n");
+ return false;
+ }
+ if (type != RAS_SYNC_TYPE_FENCE) {
+ printf("RAS_OpenGLSync::Create(): only RAS_SYNC_TYPE_FENCE are currently supported\n");
+ return false;
+ }
+ if (!GLEW_ARB_sync) {
+ printf("RAS_OpenGLSync::Create(): ARB_sync extension is needed to create sync object\n");
+ return false;
+ }
+ m_sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+ if (!m_sync) {
+ printf("RAS_OpenGLSync::Create(): glFenceSync() failed");
+ return false;
+ }
+ return true;
+}
+
+void RAS_OpenGLSync::Destroy()
+{
+ if (m_sync) {
+ glDeleteSync(m_sync);
+ m_sync = NULL;
+ }
+}
+
+void RAS_OpenGLSync::Wait()
+{
+ if (m_sync) {
+ // this is needed to ensure that the sync is in the GPU
+ glFlush();
+ // block until the operation have completed
+ glWaitSync(m_sync, 0, GL_TIMEOUT_IGNORED);
+ }
+}
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.h
new file mode 100644
index 00000000000..4ba96903856
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.h
@@ -0,0 +1,50 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __RAS_OPENGLSYNC__
+#define __RAS_OPENGLSYNC__
+
+
+#include "RAS_ISync.h"
+
+struct __GLsync;
+
+class RAS_OpenGLSync : public RAS_ISync
+{
+private:
+ struct __GLsync *m_sync;
+
+public:
+ RAS_OpenGLSync();
+ ~RAS_OpenGLSync();
+
+ virtual bool Create(RAS_SYNC_TYPE type);
+ virtual void Destroy();
+ virtual void Wait();
+};
+
+#endif /* __RAS_OPENGLSYNC__ */
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp
index cf77ebfbeb9..316871e6025 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp
@@ -171,7 +171,7 @@ void RAS_StorageVA::TexCoordPtr(const RAS_TexVert *tv)
glVertexAttribPointerARB(unit, 4, GL_FLOAT, GL_FALSE, sizeof(RAS_TexVert), tv->getTangent());
break;
case RAS_IRasterizer::RAS_TEXCO_VCOL:
- glVertexAttribPointerARB(unit, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(RAS_TexVert), tv->getRGBA());
+ glVertexAttribPointerARB(unit, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(RAS_TexVert), tv->getRGBA());
break;
default:
break;
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h
index 34fdca23ee6..a5a3170ed77 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h
@@ -45,7 +45,7 @@ public:
virtual void IndexPrimitives(RAS_MeshSlot& ms);
- virtual void SetDrawingMode(int drawingmode){m_drawingmode=drawingmode;};
+ virtual void SetDrawingMode(int drawingmode) {m_drawingmode = drawingmode;};
protected:
int m_drawingmode;
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp
index cad5b5a508e..114defb60a5 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp
@@ -149,6 +149,9 @@ void VBO::Draw(int texco_num, RAS_IRasterizer::TexCoGen* texco, int attrib_num,
glVertexAttribPointerARB(unit, 4, GL_FLOAT, GL_FALSE, this->stride, this->tangent_offset);
glEnableVertexAttribArrayARB(unit);
break;
+ case RAS_IRasterizer::RAS_TEXCO_VCOL:
+ glVertexAttribPointerARB(unit, 4, GL_UNSIGNED_BYTE, GL_TRUE, this->stride, this->color_offset);
+ glEnableVertexAttribArrayARB(unit);
default:
break;
}
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h
index 9cb3449bed5..4c8e4a8931c 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h
@@ -76,7 +76,7 @@ public:
virtual void IndexPrimitives(RAS_MeshSlot& ms);
- virtual void SetDrawingMode(int drawingmode){m_drawingmode=drawingmode;};
+ virtual void SetDrawingMode(int drawingmode) {m_drawingmode = drawingmode;};
protected:
int m_drawingmode;
diff --git a/source/gameengine/VideoTexture/CMakeLists.txt b/source/gameengine/VideoTexture/CMakeLists.txt
index 4be9a9abe5c..1eb09b02e05 100644
--- a/source/gameengine/VideoTexture/CMakeLists.txt
+++ b/source/gameengine/VideoTexture/CMakeLists.txt
@@ -45,6 +45,9 @@ set(INC
../../../intern/glew-mx
../../../intern/guardedalloc
../../../intern/string
+ ../../../intern/decklink
+ ../../../intern/gpudirect
+ ../../../intern/atomic
)
set(INC_SYS
@@ -68,8 +71,10 @@ set(SRC
ImageViewport.cpp
PyTypeList.cpp
Texture.cpp
+ DeckLink.cpp
VideoBase.cpp
VideoFFmpeg.cpp
+ VideoDeckLink.cpp
blendVideoTex.cpp
BlendType.h
@@ -87,8 +92,10 @@ set(SRC
ImageViewport.h
PyTypeList.h
Texture.h
+ DeckLink.h
VideoBase.h
VideoFFmpeg.h
+ VideoDeckLink.h
)
if(WITH_CODEC_FFMPEG)
@@ -100,7 +107,13 @@ if(WITH_CODEC_FFMPEG)
remove_strict_flags_file(
VideoFFmpeg.cpp
+ VideoDeckLink
+ DeckLink
)
endif()
+if(WITH_GAMEENGINE_DECKLINK)
+ add_definitions(-DWITH_GAMEENGINE_DECKLINK)
+endif()
+
blender_add_lib(ge_videotex "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/gameengine/VideoTexture/Common.h b/source/gameengine/VideoTexture/Common.h
index 90f7e66452a..22ea177addc 100644
--- a/source/gameengine/VideoTexture/Common.h
+++ b/source/gameengine/VideoTexture/Common.h
@@ -36,7 +36,8 @@
#define NULL 0
#endif
-#ifndef HRESULT
+#ifndef _HRESULT_DEFINED
+#define _HRESULT_DEFINED
#define HRESULT long
#endif
diff --git a/source/gameengine/VideoTexture/DeckLink.cpp b/source/gameengine/VideoTexture/DeckLink.cpp
new file mode 100644
index 00000000000..fa8ab8c641c
--- /dev/null
+++ b/source/gameengine/VideoTexture/DeckLink.cpp
@@ -0,0 +1,813 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file gameengine/VideoTexture/Texture.cpp
+ * \ingroup bgevideotex
+ */
+
+#ifdef WITH_GAMEENGINE_DECKLINK
+
+// implementation
+
+// FFmpeg defines its own version of stdint.h on Windows.
+// Decklink needs FFmpeg, so it uses its version of stdint.h
+// this is necessary for INT64_C macro
+#ifndef __STDC_CONSTANT_MACROS
+#define __STDC_CONSTANT_MACROS
+#endif
+// this is necessary for UINTPTR_MAX (used by atomic-ops)
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS
+#endif
+
+#include "atomic_ops.h"
+
+#include "EXP_PyObjectPlus.h"
+#include "KX_KetsjiEngine.h"
+#include "KX_PythonInit.h"
+#include "DeckLink.h"
+
+#include <memory.h>
+
+// macro for exception handling and logging
+#define CATCH_EXCP catch (Exception & exp) \
+{ exp.report(); return NULL; }
+
+static struct
+{
+ const char *name;
+ BMDDisplayMode mode;
+} sModeStringTab[] = {
+ { "NTSC", bmdModeNTSC },
+ { "NTSC2398", bmdModeNTSC2398 },
+ { "PAL", bmdModePAL },
+ { "NTSCp", bmdModeNTSCp },
+ { "PALp", bmdModePALp },
+
+ /* HD 1080 Modes */
+
+ { "HD1080p2398", bmdModeHD1080p2398 },
+ { "HD1080p24", bmdModeHD1080p24 },
+ { "HD1080p25", bmdModeHD1080p25 },
+ { "HD1080p2997", bmdModeHD1080p2997 },
+ { "HD1080p30", bmdModeHD1080p30 },
+ { "HD1080i50", bmdModeHD1080i50 },
+ { "HD1080i5994", bmdModeHD1080i5994 },
+ { "HD1080i6000", bmdModeHD1080i6000 },
+ { "HD1080p50", bmdModeHD1080p50 },
+ { "HD1080p5994", bmdModeHD1080p5994 },
+ { "HD1080p6000", bmdModeHD1080p6000 },
+
+ /* HD 720 Modes */
+
+ { "HD720p50", bmdModeHD720p50 },
+ { "HD720p5994", bmdModeHD720p5994 },
+ { "HD720p60", bmdModeHD720p60 },
+
+ /* 2k Modes */
+
+ { "2k2398", bmdMode2k2398 },
+ { "2k24", bmdMode2k24 },
+ { "2k25", bmdMode2k25 },
+
+ /* DCI Modes (output only) */
+
+ { "2kDCI2398", bmdMode2kDCI2398 },
+ { "2kDCI24", bmdMode2kDCI24 },
+ { "2kDCI25", bmdMode2kDCI25 },
+
+ /* 4k Modes */
+
+ { "4K2160p2398", bmdMode4K2160p2398 },
+ { "4K2160p24", bmdMode4K2160p24 },
+ { "4K2160p25", bmdMode4K2160p25 },
+ { "4K2160p2997", bmdMode4K2160p2997 },
+ { "4K2160p30", bmdMode4K2160p30 },
+ { "4K2160p50", bmdMode4K2160p50 },
+ { "4K2160p5994", bmdMode4K2160p5994 },
+ { "4K2160p60", bmdMode4K2160p60 },
+ // sentinel
+ { NULL }
+};
+
+static struct
+{
+ const char *name;
+ BMDPixelFormat format;
+} sFormatStringTab[] = {
+ { "8BitYUV", bmdFormat8BitYUV },
+ { "10BitYUV", bmdFormat10BitYUV },
+ { "8BitARGB", bmdFormat8BitARGB },
+ { "8BitBGRA", bmdFormat8BitBGRA },
+ { "10BitRGB", bmdFormat10BitRGB },
+ { "12BitRGB", bmdFormat12BitRGB },
+ { "12BitRGBLE", bmdFormat12BitRGBLE },
+ { "10BitRGBXLE", bmdFormat10BitRGBXLE },
+ { "10BitRGBX", bmdFormat10BitRGBX },
+ // sentinel
+ { NULL }
+};
+
+ExceptionID DeckLinkBadDisplayMode, DeckLinkBadPixelFormat;
+ExpDesc DeckLinkBadDisplayModeDesc(DeckLinkBadDisplayMode, "Invalid or unsupported display mode");
+ExpDesc DeckLinkBadPixelFormatDesc(DeckLinkBadPixelFormat, "Invalid or unsupported pixel format");
+
+HRESULT decklink_ReadDisplayMode(const char *format, size_t len, BMDDisplayMode *displayMode)
+{
+ int i;
+
+ if (len == 0)
+ len = strlen(format);
+ for (i = 0; sModeStringTab[i].name != NULL; i++) {
+ if (strlen(sModeStringTab[i].name) == len &&
+ !strncmp(sModeStringTab[i].name, format, len))
+ {
+ *displayMode = sModeStringTab[i].mode;
+ return S_OK;
+ }
+ }
+ if (len != 4)
+ THRWEXCP(DeckLinkBadDisplayMode, S_OK);
+ // assume the user entered directly the mode value as a 4 char string
+ *displayMode = (BMDDisplayMode)((((uint32_t)format[0]) << 24) + (((uint32_t)format[1]) << 16) + (((uint32_t)format[2]) << 8) + ((uint32_t)format[3]));
+ return S_OK;
+}
+
+HRESULT decklink_ReadPixelFormat(const char *format, size_t len, BMDPixelFormat *pixelFormat)
+{
+ int i;
+
+ if (!len)
+ len = strlen(format);
+ for (i = 0; sFormatStringTab[i].name != NULL; i++) {
+ if (strlen(sFormatStringTab[i].name) == len &&
+ !strncmp(sFormatStringTab[i].name, format, len))
+ {
+ *pixelFormat = sFormatStringTab[i].format;
+ return S_OK;
+ }
+ }
+ if (len != 4)
+ THRWEXCP(DeckLinkBadPixelFormat, S_OK);
+ // assume the user entered directly the mode value as a 4 char string
+ *pixelFormat = (BMDPixelFormat)((((uint32_t)format[0]) << 24) + (((uint32_t)format[1]) << 16) + (((uint32_t)format[2]) << 8) + ((uint32_t)format[3]));
+ return S_OK;
+}
+
+class DeckLink3DFrameWrapper : public IDeckLinkVideoFrame, IDeckLinkVideoFrame3DExtensions
+{
+public:
+ // IUnknown
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv)
+ {
+ if (!memcmp(&iid, &IID_IDeckLinkVideoFrame3DExtensions, sizeof(iid))) {
+ if (mpRightEye) {
+ *ppv = (IDeckLinkVideoFrame3DExtensions*)this;
+ return S_OK;
+ }
+ }
+ return E_NOTIMPL;
+ }
+ virtual ULONG STDMETHODCALLTYPE AddRef(void) { return 1U; }
+ virtual ULONG STDMETHODCALLTYPE Release(void) { return 1U; }
+ // IDeckLinkVideoFrame
+ virtual long STDMETHODCALLTYPE GetWidth(void) { return mpLeftEye->GetWidth(); }
+ virtual long STDMETHODCALLTYPE GetHeight(void) { return mpLeftEye->GetHeight(); }
+ virtual long STDMETHODCALLTYPE GetRowBytes(void) { return mpLeftEye->GetRowBytes(); }
+ virtual BMDPixelFormat STDMETHODCALLTYPE GetPixelFormat(void) { return mpLeftEye->GetPixelFormat(); }
+ virtual BMDFrameFlags STDMETHODCALLTYPE GetFlags(void) { return mpLeftEye->GetFlags(); }
+ virtual HRESULT STDMETHODCALLTYPE GetBytes(void **buffer) { return mpLeftEye->GetBytes(buffer); }
+ virtual HRESULT STDMETHODCALLTYPE GetTimecode(BMDTimecodeFormat format,IDeckLinkTimecode **timecode)
+ { return mpLeftEye->GetTimecode(format, timecode); }
+ virtual HRESULT STDMETHODCALLTYPE GetAncillaryData(IDeckLinkVideoFrameAncillary **ancillary)
+ { return mpLeftEye->GetAncillaryData(ancillary); }
+ // IDeckLinkVideoFrame3DExtensions
+ virtual BMDVideo3DPackingFormat STDMETHODCALLTYPE Get3DPackingFormat(void)
+ {
+ return bmdVideo3DPackingLeftOnly;
+ }
+ virtual HRESULT STDMETHODCALLTYPE GetFrameForRightEye(
+ /* [out] */ IDeckLinkVideoFrame **rightEyeFrame)
+ {
+ mpRightEye->AddRef();
+ *rightEyeFrame = mpRightEye;
+ return S_OK;
+ }
+ // Constructor
+ DeckLink3DFrameWrapper(IDeckLinkVideoFrame *leftEye, IDeckLinkVideoFrame *rightEye)
+ {
+ mpLeftEye = leftEye;
+ mpRightEye = rightEye;
+ }
+ // no need for a destructor, it's just a wrapper
+private:
+ IDeckLinkVideoFrame *mpLeftEye;
+ IDeckLinkVideoFrame *mpRightEye;
+};
+
+static void decklink_Reset(DeckLink *self)
+{
+ self->m_lastClock = 0.0;
+ self->mDLOutput = NULL;
+ self->mUse3D = false;
+ self->mDisplayMode = bmdModeUnknown;
+ self->mKeyingSupported = false;
+ self->mHDKeyingSupported = false;
+ self->mSize[0] = 0;
+ self->mSize[1] = 0;
+ self->mFrameSize = 0;
+ self->mLeftFrame = NULL;
+ self->mRightFrame = NULL;
+ self->mKeyer = NULL;
+ self->mUseKeying = false;
+ self->mKeyingLevel = 255;
+ self->mUseExtend = false;
+}
+
+#ifdef __BIG_ENDIAN__
+#define CONV_PIXEL(i) ((((i)>>16)&0xFF00)+(((i)&0xFF00)<<16)+((i)&0xFF00FF))
+#else
+#define CONV_PIXEL(i) ((((i)&0xFF)<<16)+(((i)>>16)&0xFF)+((i)&0xFF00FF00))
+#endif
+
+// adapt the pixel format and picture size from VideoTexture (RGBA) to DeckLink (BGRA)
+static void decklink_ConvImage(uint32_t *dest, const short *destSize, const uint32_t *source, const short *srcSize, bool extend)
+{
+ short w, h, x, y;
+ const uint32_t *s;
+ uint32_t *d, p;
+ bool sameSize = (destSize[0] == srcSize[0] && destSize[1] == srcSize[1]);
+
+ if (sameSize || !extend) {
+ // here we convert pixel by pixel
+ w = (destSize[0] < srcSize[0]) ? destSize[0] : srcSize[0];
+ h = (destSize[1] < srcSize[1]) ? destSize[1] : srcSize[1];
+ for (y = 0; y < h; ++y) {
+ s = source + y*srcSize[0];
+ d = dest + y*destSize[0];
+ for (x = 0; x < w; ++x, ++s, ++d) {
+ *d = CONV_PIXEL(*s);
+ }
+ }
+ }
+ else {
+ // here we scale
+ // interpolation accumulator
+ int accHeight = srcSize[1] >> 1;
+ d = dest;
+ s = source;
+ // process image rows
+ for (y = 0; y < srcSize[1]; ++y) {
+ // increase height accum
+ accHeight += destSize[1];
+ // if pixel row has to be drawn
+ if (accHeight >= srcSize[1]) {
+ // decrease accum
+ accHeight -= srcSize[1];
+ // width accum
+ int accWidth = srcSize[0] >> 1;
+ // process row
+ for (x = 0; x < srcSize[0]; ++x, ++s) {
+ // increase width accum
+ accWidth += destSize[0];
+ // convert pixel
+ p = CONV_PIXEL(*s);
+ // if pixel has to be drown one or more times
+ while (accWidth >= srcSize[0]) {
+ // decrease accum
+ accWidth -= srcSize[0];
+ *d++ = p;
+ }
+ }
+ // if there should be more identical lines
+ while (accHeight >= srcSize[1]) {
+ accHeight -= srcSize[1];
+ // copy previous line
+ memcpy(d, d - destSize[0], 4 * destSize[0]);
+ d += destSize[0];
+ }
+ }
+ else {
+ // if we skip a source line
+ s += srcSize[0];
+ }
+ }
+ }
+}
+
+// DeckLink object allocation
+static PyObject *DeckLink_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ // allocate object
+ DeckLink * self = reinterpret_cast<DeckLink*>(type->tp_alloc(type, 0));
+ // initialize object structure
+ decklink_Reset(self);
+ // m_leftEye is a python object, it's handled by python
+ self->m_leftEye = NULL;
+ self->m_rightEye = NULL;
+ // return allocated object
+ return reinterpret_cast<PyObject*>(self);
+}
+
+
+// forward declaration
+PyObject *DeckLink_close(DeckLink *self);
+int DeckLink_setSource(DeckLink *self, PyObject *value, void *closure);
+
+
+// DeckLink object deallocation
+static void DeckLink_dealloc(DeckLink *self)
+{
+ // release renderer
+ Py_XDECREF(self->m_leftEye);
+ // close decklink
+ PyObject *ret = DeckLink_close(self);
+ Py_DECREF(ret);
+ // release object
+ Py_TYPE((PyObject *)self)->tp_free((PyObject *)self);
+}
+
+
+ExceptionID AutoDetectionNotAvail, DeckLinkOpenCard, DeckLinkBadFormat, DeckLinkInternalError;
+ExpDesc AutoDetectionNotAvailDesc(AutoDetectionNotAvail, "Auto detection not yet available");
+ExpDesc DeckLinkOpenCardDesc(DeckLinkOpenCard, "Cannot open card for output");
+ExpDesc DeckLinkBadFormatDesc(DeckLinkBadFormat, "Invalid or unsupported output format, use <mode>[/3D]");
+ExpDesc DeckLinkInternalErrorDesc(DeckLinkInternalError, "DeckLink API internal error, please report");
+
+// DeckLink object initialization
+static int DeckLink_init(DeckLink *self, PyObject *args, PyObject *kwds)
+{
+ IDeckLinkIterator* pIterator;
+ IDeckLinkAttributes* pAttributes;
+ IDeckLinkDisplayModeIterator* pDisplayModeIterator;
+ IDeckLinkDisplayMode* pDisplayMode;
+ IDeckLink* pDL;
+ char* p3D;
+ BOOL flag;
+ size_t len;
+ int i;
+ uint32_t displayFlags;
+ BMDVideoOutputFlags outputFlags;
+ BMDDisplayModeSupport support;
+ uint32_t* bytes;
+
+
+ // material ID
+ short cardIdx = 0;
+ // texture ID
+ char *format = NULL;
+
+ static const char *kwlist[] = {"cardIdx", "format", NULL};
+ // get parameters
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|hs",
+ const_cast<char**>(kwlist), &cardIdx, &format))
+ return -1;
+
+ try {
+ if (format == NULL) {
+ THRWEXCP(AutoDetectionNotAvail, S_OK);
+ }
+
+ if ((p3D = strchr(format, '/')) != NULL && strcmp(p3D, "/3D"))
+ THRWEXCP(DeckLinkBadFormat, S_OK);
+ self->mUse3D = (p3D) ? true : false;
+ // read the mode
+ len = (p3D) ? (size_t)(p3D - format) : strlen(format);
+ // throws if bad mode
+ decklink_ReadDisplayMode(format, len, &self->mDisplayMode);
+
+ pIterator = BMD_CreateDeckLinkIterator();
+ pDL = NULL;
+ if (pIterator) {
+ i = 0;
+ while (pIterator->Next(&pDL) == S_OK) {
+ if (i == cardIdx) {
+ break;
+ }
+ i++;
+ pDL->Release();
+ pDL = NULL;
+ }
+ pIterator->Release();
+ }
+
+ if (!pDL) {
+ THRWEXCP(DeckLinkOpenCard, S_OK);
+ }
+ // detect the capabilities
+ if (pDL->QueryInterface(IID_IDeckLinkAttributes, (void**)&pAttributes) == S_OK) {
+ if (pAttributes->GetFlag(BMDDeckLinkSupportsInternalKeying, &flag) == S_OK && flag) {
+ self->mKeyingSupported = true;
+ if (pAttributes->GetFlag(BMDDeckLinkSupportsHDKeying, &flag) == S_OK && flag) {
+ self->mHDKeyingSupported = true;
+ }
+ }
+ pAttributes->Release();
+ }
+
+ if (pDL->QueryInterface(IID_IDeckLinkOutput, (void**)&self->mDLOutput) != S_OK) {
+ self->mDLOutput = NULL;
+ }
+ if (self->mKeyingSupported) {
+ pDL->QueryInterface(IID_IDeckLinkKeyer, (void **)&self->mKeyer);
+ }
+ // we don't need the device anymore, release to avoid leaking
+ pDL->Release();
+
+ if (!self->mDLOutput)
+ THRWEXCP(DeckLinkOpenCard, S_OK);
+
+ if (self->mDLOutput->GetDisplayModeIterator(&pDisplayModeIterator) != S_OK)
+ THRWEXCP(DeckLinkInternalError, S_OK);
+
+ displayFlags = (self->mUse3D) ? bmdDisplayModeSupports3D : 0;
+ outputFlags = (self->mUse3D) ? bmdVideoOutputDualStream3D : bmdVideoOutputFlagDefault;
+ pDisplayMode = NULL;
+ i = 0;
+ while (pDisplayModeIterator->Next(&pDisplayMode) == S_OK) {
+ if (pDisplayMode->GetDisplayMode() == self->mDisplayMode
+ && (pDisplayMode->GetFlags() & displayFlags) == displayFlags) {
+ if (self->mDLOutput->DoesSupportVideoMode(self->mDisplayMode, bmdFormat8BitBGRA, outputFlags, &support, NULL) != S_OK ||
+ support == bmdDisplayModeNotSupported)
+ {
+ printf("Warning: DeckLink card %d reports no BGRA support, proceed anyway\n", cardIdx);
+ }
+ break;
+ }
+ pDisplayMode->Release();
+ pDisplayMode = NULL;
+ i++;
+ }
+ pDisplayModeIterator->Release();
+
+ if (!pDisplayMode)
+ THRWEXCP(DeckLinkBadFormat, S_OK);
+ self->mSize[0] = pDisplayMode->GetWidth();
+ self->mSize[1] = pDisplayMode->GetHeight();
+ self->mFrameSize = 4*self->mSize[0]*self->mSize[1];
+ pDisplayMode->Release();
+ if (self->mDLOutput->EnableVideoOutput(self->mDisplayMode, outputFlags) != S_OK)
+ // this shouldn't fail
+ THRWEXCP(DeckLinkOpenCard, S_OK);
+
+ if (self->mDLOutput->CreateVideoFrame(self->mSize[0], self->mSize[1], self->mSize[0] * 4, bmdFormat8BitBGRA, bmdFrameFlagFlipVertical, &self->mLeftFrame) != S_OK)
+ THRWEXCP(DeckLinkInternalError, S_OK);
+ // clear alpha channel in the frame buffer
+ self->mLeftFrame->GetBytes((void **)&bytes);
+ memset(bytes, 0, self->mFrameSize);
+ if (self->mUse3D) {
+ if (self->mDLOutput->CreateVideoFrame(self->mSize[0], self->mSize[1], self->mSize[0] * 4, bmdFormat8BitBGRA, bmdFrameFlagFlipVertical, &self->mRightFrame) != S_OK)
+ THRWEXCP(DeckLinkInternalError, S_OK);
+ // clear alpha channel in the frame buffer
+ self->mRightFrame->GetBytes((void **)&bytes);
+ memset(bytes, 0, self->mFrameSize);
+ }
+ }
+ catch (Exception & exp)
+ {
+ printf("DeckLink: exception when opening card %d: %s\n", cardIdx, exp.what());
+ exp.report();
+ // normally, the object should be deallocated
+ return -1;
+ }
+ // initialization succeeded
+ return 0;
+}
+
+
+// close added decklink
+PyObject *DeckLink_close(DeckLink * self)
+{
+ if (self->mLeftFrame)
+ self->mLeftFrame->Release();
+ if (self->mRightFrame)
+ self->mRightFrame->Release();
+ if (self->mKeyer)
+ self->mKeyer->Release();
+ if (self->mDLOutput)
+ self->mDLOutput->Release();
+ decklink_Reset(self);
+ Py_RETURN_NONE;
+}
+
+
+// refresh decklink key frame
+static PyObject *DeckLink_refresh(DeckLink *self, PyObject *args)
+{
+ // get parameter - refresh source
+ PyObject *param;
+ double ts = -1.0;
+
+ if (!PyArg_ParseTuple(args, "O|d:refresh", &param, &ts) || !PyBool_Check(param)) {
+ // report error
+ PyErr_SetString(PyExc_TypeError, "The value must be a bool");
+ return NULL;
+ }
+ // some trick here: we are in the business of loading a key frame in decklink,
+ // no use to do it if we are still in the same rendering frame.
+ // We find this out by looking at the engine current clock time
+ KX_KetsjiEngine* engine = KX_GetActiveEngine();
+ if (engine->GetClockTime() != self->m_lastClock)
+ {
+ self->m_lastClock = engine->GetClockTime();
+ // set source refresh
+ bool refreshSource = (param == Py_True);
+ uint32_t *leftEye = NULL;
+ uint32_t *rightEye = NULL;
+ // try to process key frame from source
+ try {
+ // check if optimization is possible
+ if (self->m_leftEye != NULL) {
+ ImageBase *leftImage = self->m_leftEye->m_image;
+ short * srcSize = leftImage->getSize();
+ self->mLeftFrame->GetBytes((void **)&leftEye);
+ if (srcSize[0] == self->mSize[0] && srcSize[1] == self->mSize[1])
+ {
+ // buffer has same size, can load directly
+ if (!leftImage->loadImage(leftEye, self->mFrameSize, GL_BGRA, ts))
+ leftEye = NULL;
+ }
+ else {
+ // scaling is required, go the hard way
+ unsigned int *src = leftImage->getImage(0, ts);
+ if (src != NULL)
+ decklink_ConvImage(leftEye, self->mSize, src, srcSize, self->mUseExtend);
+ else
+ leftEye = NULL;
+ }
+ }
+ if (leftEye) {
+ if (self->mUse3D && self->m_rightEye != NULL) {
+ ImageBase *rightImage = self->m_rightEye->m_image;
+ short * srcSize = rightImage->getSize();
+ self->mRightFrame->GetBytes((void **)&rightEye);
+ if (srcSize[0] == self->mSize[0] && srcSize[1] == self->mSize[1])
+ {
+ // buffer has same size, can load directly
+ rightImage->loadImage(rightEye, self->mFrameSize, GL_BGRA, ts);
+ }
+ else {
+ // scaling is required, go the hard way
+ unsigned int *src = rightImage->getImage(0, ts);
+ if (src != NULL)
+ decklink_ConvImage(rightEye, self->mSize, src, srcSize, self->mUseExtend);
+ }
+ }
+ if (self->mUse3D) {
+ DeckLink3DFrameWrapper frame3D(
+ (IDeckLinkVideoFrame*)self->mLeftFrame,
+ (IDeckLinkVideoFrame*)self->mRightFrame);
+ self->mDLOutput->DisplayVideoFrameSync(&frame3D);
+ }
+ else {
+ self->mDLOutput->DisplayVideoFrameSync((IDeckLinkVideoFrame*)self->mLeftFrame);
+ }
+ }
+ // refresh texture source, if required
+ if (refreshSource) {
+ if (self->m_leftEye)
+ self->m_leftEye->m_image->refresh();
+ if (self->m_rightEye)
+ self->m_rightEye->m_image->refresh();
+ }
+ }
+ CATCH_EXCP;
+ }
+ Py_RETURN_NONE;
+}
+
+// get source object
+static PyObject *DeckLink_getSource(DeckLink *self, PyObject *value, void *closure)
+{
+ // if source exists
+ if (self->m_leftEye != NULL) {
+ Py_INCREF(self->m_leftEye);
+ return reinterpret_cast<PyObject*>(self->m_leftEye);
+ }
+ // otherwise return None
+ Py_RETURN_NONE;
+}
+
+
+// set source object
+int DeckLink_setSource(DeckLink *self, PyObject *value, void *closure)
+{
+ // check new value
+ if (value == NULL || !pyImageTypes.in(Py_TYPE(value))) {
+ // report value error
+ PyErr_SetString(PyExc_TypeError, "Invalid type of value");
+ return -1;
+ }
+ // increase ref count for new value
+ Py_INCREF(value);
+ // release previous
+ Py_XDECREF(self->m_leftEye);
+ // set new value
+ self->m_leftEye = reinterpret_cast<PyImage*>(value);
+ // return success
+ return 0;
+}
+
+// get source object
+static PyObject *DeckLink_getRight(DeckLink *self, PyObject *value, void *closure)
+{
+ // if source exists
+ if (self->m_rightEye != NULL)
+ {
+ Py_INCREF(self->m_rightEye);
+ return reinterpret_cast<PyObject*>(self->m_rightEye);
+ }
+ // otherwise return None
+ Py_RETURN_NONE;
+}
+
+
+// set source object
+static int DeckLink_setRight(DeckLink *self, PyObject *value, void *closure)
+{
+ // check new value
+ if (value == NULL || !pyImageTypes.in(Py_TYPE(value)))
+ {
+ // report value error
+ PyErr_SetString(PyExc_TypeError, "Invalid type of value");
+ return -1;
+ }
+ // increase ref count for new value
+ Py_INCREF(value);
+ // release previous
+ Py_XDECREF(self->m_rightEye);
+ // set new value
+ self->m_rightEye = reinterpret_cast<PyImage*>(value);
+ // return success
+ return 0;
+}
+
+
+static PyObject *DeckLink_getKeying(DeckLink *self, PyObject *value, void *closure)
+{
+ if (self->mUseKeying) Py_RETURN_TRUE;
+ else Py_RETURN_FALSE;
+}
+
+static int DeckLink_setKeying(DeckLink *self, PyObject *value, void *closure)
+{
+ if (value == NULL || !PyBool_Check(value))
+ {
+ PyErr_SetString(PyExc_TypeError, "The value must be a bool");
+ return -1;
+ }
+ if (self->mKeyer != NULL)
+ {
+ if (value == Py_True)
+ {
+ if (self->mKeyer->Enable(false) != S_OK)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "Error enabling keyer");
+ return -1;
+ }
+ self->mUseKeying = true;
+ self->mKeyer->SetLevel(self->mKeyingLevel);
+ }
+ else
+ {
+ self->mKeyer->Disable();
+ self->mUseKeying = false;
+ }
+ }
+ // success
+ return 0;
+}
+
+static PyObject *DeckLink_getLevel(DeckLink *self, PyObject *value, void *closure)
+{
+ return Py_BuildValue("h", self->mKeyingLevel);
+}
+
+static int DeckLink_setLevel(DeckLink *self, PyObject *value, void *closure)
+{
+ long level;
+ if (value == NULL || !PyLong_Check(value)) {
+ PyErr_SetString(PyExc_TypeError, "The value must be an integer from 0 to 255");
+ return -1;
+ }
+ level = PyLong_AsLong(value);
+ if (level > 255)
+ level = 255;
+ else if (level < 0)
+ level = 0;
+ self->mKeyingLevel = (uint8_t)level;
+ if (self->mUseKeying) {
+ if (self->mKeyer->SetLevel(self->mKeyingLevel) != S_OK) {
+ PyErr_SetString(PyExc_RuntimeError, "Error changin level of keyer");
+ return -1;
+ }
+ }
+ // success
+ return 0;
+}
+
+static PyObject *DeckLink_getExtend(DeckLink *self, PyObject *value, void *closure)
+{
+ if (self->mUseExtend) Py_RETURN_TRUE;
+ else Py_RETURN_FALSE;
+}
+
+static int DeckLink_setExtend(DeckLink *self, PyObject *value, void *closure)
+{
+ if (value == NULL || !PyBool_Check(value))
+ {
+ PyErr_SetString(PyExc_TypeError, "The value must be a bool");
+ return -1;
+ }
+ self->mUseExtend = (value == Py_True);
+ return 0;
+}
+
+// class DeckLink methods
+static PyMethodDef decklinkMethods[] =
+{
+ { "close", (PyCFunction)DeckLink_close, METH_NOARGS, "Close dynamic decklink and restore original"},
+ { "refresh", (PyCFunction)DeckLink_refresh, METH_VARARGS, "Refresh decklink from source"},
+ {NULL} /* Sentinel */
+};
+
+// class DeckLink attributes
+static PyGetSetDef decklinkGetSets[] =
+{
+ { (char*)"source", (getter)DeckLink_getSource, (setter)DeckLink_setSource, (char*)"source of decklink (left eye)", NULL},
+ { (char*)"right", (getter)DeckLink_getRight, (setter)DeckLink_setRight, (char*)"source of decklink (right eye)", NULL },
+ { (char*)"keying", (getter)DeckLink_getKeying, (setter)DeckLink_setKeying, (char*)"whether keying is enabled (frame is alpha-composited with passthrough output)", NULL },
+ { (char*)"level", (getter)DeckLink_getLevel, (setter)DeckLink_setLevel, (char*)"change the level of keying (overall alpha level of key frame, 0 to 255)", NULL },
+ { (char*)"extend", (getter)DeckLink_getExtend, (setter)DeckLink_setExtend, (char*)"whether image should stretched to fit frame", NULL },
+ { NULL }
+};
+
+
+// class DeckLink declaration
+PyTypeObject DeckLinkType =
+{
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "VideoTexture.DeckLink", /*tp_name*/
+ sizeof(DeckLink), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)DeckLink_dealloc,/*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ &imageBufferProcs, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ "DeckLink objects", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ decklinkMethods, /* tp_methods */
+ 0, /* tp_members */
+ decklinkGetSets, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)DeckLink_init, /* tp_init */
+ 0, /* tp_alloc */
+ DeckLink_new, /* tp_new */
+};
+
+#endif /* WITH_GAMEENGINE_DECKLINK */
diff --git a/source/gameengine/VideoTexture/DeckLink.h b/source/gameengine/VideoTexture/DeckLink.h
new file mode 100644
index 00000000000..4528fe7cec0
--- /dev/null
+++ b/source/gameengine/VideoTexture/DeckLink.h
@@ -0,0 +1,86 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file VideoTexture/DeckLink.h
+ * \ingroup bgevideotex
+ */
+
+#ifndef __DECKLINK_H__
+#define __DECKLINK_H__
+
+#ifdef WITH_GAMEENGINE_DECKLINK
+
+#include "EXP_PyObjectPlus.h"
+#include <structmember.h>
+
+#include "DNA_image_types.h"
+
+#include "DeckLinkAPI.h"
+
+#include "ImageBase.h"
+#include "BlendType.h"
+#include "Exception.h"
+
+
+// type DeckLink declaration
+struct DeckLink
+{
+ PyObject_HEAD
+
+ // last refresh
+ double m_lastClock;
+ // decklink card to which we output
+ IDeckLinkOutput * mDLOutput;
+ IDeckLinkKeyer * mKeyer;
+ IDeckLinkMutableVideoFrame *mLeftFrame;
+ IDeckLinkMutableVideoFrame *mRightFrame;
+ bool mUse3D;
+ bool mUseKeying;
+ bool mUseExtend;
+ bool mKeyingSupported;
+ bool mHDKeyingSupported;
+ uint8_t mKeyingLevel;
+ BMDDisplayMode mDisplayMode;
+ short mSize[2];
+ uint32_t mFrameSize;
+
+ // image source
+ PyImage * m_leftEye;
+ PyImage * m_rightEye;
+};
+
+
+// DeckLink type description
+extern PyTypeObject DeckLinkType;
+
+// helper function
+HRESULT decklink_ReadDisplayMode(const char *format, size_t len, BMDDisplayMode *displayMode);
+HRESULT decklink_ReadPixelFormat(const char *format, size_t len, BMDPixelFormat *displayMode);
+
+#endif /* WITH_GAMEENGINE_DECKLINK */
+
+#endif /* __DECKLINK_H__ */
diff --git a/source/gameengine/VideoTexture/Exception.cpp b/source/gameengine/VideoTexture/Exception.cpp
index 08616e0c41c..9f82987ea62 100644
--- a/source/gameengine/VideoTexture/Exception.cpp
+++ b/source/gameengine/VideoTexture/Exception.cpp
@@ -213,6 +213,7 @@ void registerAllExceptions(void)
ImageSizesNotMatchDesc.registerDesc();
ImageHasExportsDesc.registerDesc();
InvalidColorChannelDesc.registerDesc();
+ InvalidImageModeDesc.registerDesc();
SceneInvalidDesc.registerDesc();
CameraInvalidDesc.registerDesc();
ObserverInvalidDesc.registerDesc();
@@ -223,4 +224,18 @@ void registerAllExceptions(void)
MirrorTooSmallDesc.registerDesc();
SourceVideoEmptyDesc.registerDesc();
SourceVideoCreationDesc.registerDesc();
+ OffScreenInvalidDesc.registerDesc();
+#ifdef WITH_GAMEENGINE_DECKLINK
+ AutoDetectionNotAvailDesc.registerDesc();
+ DeckLinkBadDisplayModeDesc.registerDesc();
+ DeckLinkBadPixelFormatDesc.registerDesc();
+ DeckLinkOpenCardDesc.registerDesc();
+ DeckLinkBadFormatDesc.registerDesc();
+ DeckLinkInternalErrorDesc.registerDesc();
+ SourceVideoOnlyCaptureDesc.registerDesc();
+ VideoDeckLinkBadFormatDesc.registerDesc();
+ VideoDeckLinkOpenCardDesc.registerDesc();
+ VideoDeckLinkDvpInternalErrorDesc.registerDesc();
+ VideoDeckLinkPinMemoryErrorDesc.registerDesc();
+#endif
}
diff --git a/source/gameengine/VideoTexture/Exception.h b/source/gameengine/VideoTexture/Exception.h
index c3c27abe019..c4de85ff34d 100644
--- a/source/gameengine/VideoTexture/Exception.h
+++ b/source/gameengine/VideoTexture/Exception.h
@@ -46,7 +46,7 @@
throw Exception (err, macroHRslt, __FILE__, __LINE__); \
}
-#define THRWEXCP(err,hRslt) throw Exception (err, hRslt, __FILE__, __LINE__);
+#define THRWEXCP(err,hRslt) throw Exception (err, hRslt, __FILE__, __LINE__)
#if defined WIN32
@@ -209,9 +209,11 @@ extern ExpDesc MaterialNotAvailDesc;
extern ExpDesc ImageSizesNotMatchDesc;
extern ExpDesc ImageHasExportsDesc;
extern ExpDesc InvalidColorChannelDesc;
+extern ExpDesc InvalidImageModeDesc;
extern ExpDesc SceneInvalidDesc;
extern ExpDesc CameraInvalidDesc;
extern ExpDesc ObserverInvalidDesc;
+extern ExpDesc OffScreenInvalidDesc;
extern ExpDesc MirrorInvalidDesc;
extern ExpDesc MirrorSizeInvalidDesc;
extern ExpDesc MirrorNormalInvalidDesc;
@@ -219,7 +221,19 @@ extern ExpDesc MirrorHorizontalDesc;
extern ExpDesc MirrorTooSmallDesc;
extern ExpDesc SourceVideoEmptyDesc;
extern ExpDesc SourceVideoCreationDesc;
-
+extern ExpDesc DeckLinkBadDisplayModeDesc;
+extern ExpDesc DeckLinkBadPixelFormatDesc;
+extern ExpDesc AutoDetectionNotAvailDesc;
+extern ExpDesc DeckLinkOpenCardDesc;
+extern ExpDesc DeckLinkBadFormatDesc;
+extern ExpDesc DeckLinkInternalErrorDesc;
+extern ExpDesc SourceVideoOnlyCaptureDesc;
+extern ExpDesc VideoDeckLinkBadFormatDesc;
+extern ExpDesc VideoDeckLinkOpenCardDesc;
+extern ExpDesc VideoDeckLinkDvpInternalErrorDesc;
+extern ExpDesc VideoDeckLinkPinMemoryErrorDesc;
+
+extern ExceptionID InvalidImageMode;
void registerAllExceptions(void);
#endif
diff --git a/source/gameengine/VideoTexture/FilterBase.h b/source/gameengine/VideoTexture/FilterBase.h
index 498917e2375..db688d551d0 100644
--- a/source/gameengine/VideoTexture/FilterBase.h
+++ b/source/gameengine/VideoTexture/FilterBase.h
@@ -44,6 +44,13 @@
#define VT_A(v) ((unsigned char*)&v)[3]
#define VT_RGBA(v,r,g,b,a) VT_R(v)=(unsigned char)r, VT_G(v)=(unsigned char)g, VT_B(v)=(unsigned char)b, VT_A(v)=(unsigned char)a
+#ifdef __BIG_ENDIAN__
+# define VT_SWAPBR(i) ((((i) >> 16) & 0xFF00) + (((i) & 0xFF00) << 16) + ((i) & 0xFF00FF))
+#else
+# define VT_SWAPBR(i) ((((i) & 0xFF) << 16) + (((i) >> 16) & 0xFF) + ((i) & 0xFF00FF00))
+#endif
+
+
// forward declaration
class FilterBase;
diff --git a/source/gameengine/VideoTexture/FilterSource.h b/source/gameengine/VideoTexture/FilterSource.h
index bc80b2b36cc..820576dfff9 100644
--- a/source/gameengine/VideoTexture/FilterSource.h
+++ b/source/gameengine/VideoTexture/FilterSource.h
@@ -81,6 +81,30 @@ protected:
}
};
+/// class for BGRA32 conversion
+class FilterBGRA32 : public FilterBase
+{
+public:
+ /// constructor
+ FilterBGRA32 (void) {}
+ /// destructor
+ virtual ~FilterBGRA32 (void) {}
+
+ /// get source pixel size
+ virtual unsigned int getPixelSize (void) { return 4; }
+
+protected:
+ /// filter pixel, source byte buffer
+ virtual unsigned int filter(
+ unsigned char *src, short x, short y,
+ short * size, unsigned int pixSize, unsigned int val)
+ {
+ VT_RGBA(val,src[2],src[1],src[0],src[3]);
+ return val;
+ }
+};
+
+
/// class for BGR24 conversion
class FilterBGR24 : public FilterBase
{
diff --git a/source/gameengine/VideoTexture/ImageBase.cpp b/source/gameengine/VideoTexture/ImageBase.cpp
index 8be152c7b8e..0db1fa293da 100644
--- a/source/gameengine/VideoTexture/ImageBase.cpp
+++ b/source/gameengine/VideoTexture/ImageBase.cpp
@@ -32,7 +32,6 @@
extern "C" {
#include "bgl.h"
}
-#include "glew-mx.h"
#include <vector>
#include <string.h>
@@ -50,6 +49,14 @@ extern "C" {
// ImageBase class implementation
+ExceptionID ImageHasExports;
+ExceptionID InvalidColorChannel;
+ExceptionID InvalidImageMode;
+
+ExpDesc ImageHasExportsDesc(ImageHasExports, "Image has exported buffers, cannot resize");
+ExpDesc InvalidColorChannelDesc(InvalidColorChannel, "Invalid or too many color channels specified. At most 4 values within R, G, B, A, 0, 1");
+ExpDesc InvalidImageModeDesc(InvalidImageMode, "Invalid image mode, only RGBA and BGRA are supported");
+
// constructor
ImageBase::ImageBase (bool staticSrc) : m_image(NULL), m_imgSize(0),
m_avail(false), m_scale(false), m_scaleChange(false), m_flip(false),
@@ -111,6 +118,28 @@ unsigned int * ImageBase::getImage (unsigned int texId, double ts)
return m_avail ? m_image : NULL;
}
+bool ImageBase::loadImage(unsigned int *buffer, unsigned int size, unsigned int format, double ts)
+{
+ unsigned int *d, *s, v, len;
+ if (getImage(0, ts) != NULL && size >= getBuffSize()) {
+ switch (format) {
+ case GL_RGBA:
+ memcpy(buffer, m_image, getBuffSize());
+ break;
+ case GL_BGRA:
+ len = (unsigned int)m_size[0] * m_size[1];
+ for (s=m_image, d=buffer; len; len--) {
+ v = *s++;
+ *d++ = VT_SWAPBR(v);
+ }
+ break;
+ default:
+ THRWEXCP(InvalidImageMode,S_OK);
+ }
+ return true;
+ }
+ return false;
+}
// refresh image source
void ImageBase::refresh (void)
@@ -179,11 +208,18 @@ void ImageBase::setFilter (PyFilter * filt)
m_pyfilter = filt;
}
-ExceptionID ImageHasExports;
-ExceptionID InvalidColorChannel;
+void ImageBase::swapImageBR()
+{
+ unsigned int size, v, *s;
-ExpDesc ImageHasExportsDesc(ImageHasExports, "Image has exported buffers, cannot resize");
-ExpDesc InvalidColorChannelDesc(InvalidColorChannel, "Invalid or too many color channels specified. At most 4 values within R, G, B, A, 0, 1");
+ if (m_avail) {
+ size = 1 * m_size[0] * m_size[1];
+ for (s=m_image; size; size--) {
+ v = *s;
+ *s++ = VT_SWAPBR(v);
+ }
+ }
+}
// initialize image data
void ImageBase::init (short width, short height)
@@ -500,10 +536,57 @@ PyObject *Image_getSize (PyImage *self, void *closure)
}
// refresh image
-PyObject *Image_refresh (PyImage *self)
-{
+PyObject *Image_refresh (PyImage *self, PyObject *args)
+{
+ Py_buffer buffer;
+ bool done = true;
+ char *mode = NULL;
+ double ts = -1.0;
+ unsigned int format;
+
+ memset(&buffer, 0, sizeof(buffer));
+ if (PyArg_ParseTuple(args, "|s*sd:refresh", &buffer, &mode, &ts)) {
+ if (buffer.buf) {
+ // a target buffer is provided, verify its format
+ if (buffer.readonly) {
+ PyErr_SetString(PyExc_TypeError, "Buffers passed in argument must be writable");
+ }
+ else if (!PyBuffer_IsContiguous(&buffer, 'C')) {
+ PyErr_SetString(PyExc_TypeError, "Buffers passed in argument must be contiguous in memory");
+ }
+ else if (((intptr_t)buffer.buf & 3) != 0) {
+ PyErr_SetString(PyExc_TypeError, "Buffers passed in argument must be aligned to 4 bytes boundary");
+ }
+ else {
+ // ready to get the image into our buffer
+ try {
+ if (mode == NULL || !strcmp(mode, "RGBA"))
+ format = GL_RGBA;
+ else if (!strcmp(mode, "BGRA"))
+ format = GL_BGRA;
+ else
+ THRWEXCP(InvalidImageMode,S_OK);
+
+ done = self->m_image->loadImage((unsigned int *)buffer.buf, buffer.len, format, ts);
+ }
+ catch (Exception & exp) {
+ exp.report();
+ }
+ }
+ PyBuffer_Release(&buffer);
+ if (PyErr_Occurred()) {
+ return NULL;
+ }
+ }
+ }
+ else {
+ return NULL;
+ }
+
self->m_image->refresh();
- Py_RETURN_NONE;
+ if (done)
+ Py_RETURN_TRUE;
+ Py_RETURN_FALSE;
}
// get scale
diff --git a/source/gameengine/VideoTexture/ImageBase.h b/source/gameengine/VideoTexture/ImageBase.h
index f646d145365..4c9fc5a58fb 100644
--- a/source/gameengine/VideoTexture/ImageBase.h
+++ b/source/gameengine/VideoTexture/ImageBase.h
@@ -40,6 +40,7 @@
#include "FilterBase.h"
+#include "glew-mx.h"
// forward declarations
struct PyImage;
@@ -104,6 +105,13 @@ public:
/// calculate size(nearest power of 2)
static short calcSize(short size);
+ /// calculate image from sources and send it to a target buffer instead of a texture
+ /// format is GL_RGBA or GL_BGRA
+ virtual bool loadImage(unsigned int *buffer, unsigned int size, unsigned int format, double ts);
+
+ /// swap the B and R channel in-place in the image buffer
+ void swapImageBR();
+
/// number of buffer pointing to m_image, public because not handled by this class
int m_exports;
@@ -348,7 +356,7 @@ PyObject *Image_getImage(PyImage *self, char *mode);
// get image size
PyObject *Image_getSize(PyImage *self, void *closure);
// refresh image - invalidate current content
-PyObject *Image_refresh(PyImage *self);
+PyObject *Image_refresh(PyImage *self, PyObject *args);
// get scale
PyObject *Image_getScale(PyImage *self, void *closure);
diff --git a/source/gameengine/VideoTexture/ImageMix.cpp b/source/gameengine/VideoTexture/ImageMix.cpp
index 973be52e0fc..2de00f5ba05 100644
--- a/source/gameengine/VideoTexture/ImageMix.cpp
+++ b/source/gameengine/VideoTexture/ImageMix.cpp
@@ -156,7 +156,7 @@ static PyMethodDef imageMixMethods[] = {
{"getWeight", (PyCFunction)getWeight, METH_VARARGS, "get image source weight"},
{"setWeight", (PyCFunction)setWeight, METH_VARARGS, "set image source weight"},
// methods from ImageBase class
- {"refresh", (PyCFunction)Image_refresh, METH_NOARGS, "Refresh image - invalidate its current content"},
+ {"refresh", (PyCFunction)Image_refresh, METH_VARARGS, "Refresh image - invalidate its current content"},
{NULL}
};
// attributes structure
diff --git a/source/gameengine/VideoTexture/ImageRender.cpp b/source/gameengine/VideoTexture/ImageRender.cpp
index a374fbba2df..9991bf42a9f 100644
--- a/source/gameengine/VideoTexture/ImageRender.cpp
+++ b/source/gameengine/VideoTexture/ImageRender.cpp
@@ -43,6 +43,8 @@
#include "RAS_CameraData.h"
#include "RAS_MeshObject.h"
#include "RAS_Polygon.h"
+#include "RAS_IOffScreen.h"
+#include "RAS_ISync.h"
#include "BLI_math.h"
#include "ImageRender.h"
@@ -51,11 +53,12 @@
#include "Exception.h"
#include "Texture.h"
-ExceptionID SceneInvalid, CameraInvalid, ObserverInvalid;
+ExceptionID SceneInvalid, CameraInvalid, ObserverInvalid, OffScreenInvalid;
ExceptionID MirrorInvalid, MirrorSizeInvalid, MirrorNormalInvalid, MirrorHorizontal, MirrorTooSmall;
ExpDesc SceneInvalidDesc(SceneInvalid, "Scene object is invalid");
ExpDesc CameraInvalidDesc(CameraInvalid, "Camera object is invalid");
ExpDesc ObserverInvalidDesc(ObserverInvalid, "Observer object is invalid");
+ExpDesc OffScreenInvalidDesc(OffScreenInvalid, "Offscreen object is invalid");
ExpDesc MirrorInvalidDesc(MirrorInvalid, "Mirror object is invalid");
ExpDesc MirrorSizeInvalidDesc(MirrorSizeInvalid, "Mirror has no vertex or no size");
ExpDesc MirrorNormalInvalidDesc(MirrorNormalInvalid, "Cannot determine mirror plane");
@@ -63,12 +66,15 @@ ExpDesc MirrorHorizontalDesc(MirrorHorizontal, "Mirror is horizontal in local sp
ExpDesc MirrorTooSmallDesc(MirrorTooSmall, "Mirror is too small");
// constructor
-ImageRender::ImageRender (KX_Scene *scene, KX_Camera * camera) :
- ImageViewport(),
+ImageRender::ImageRender (KX_Scene *scene, KX_Camera * camera, PyRASOffScreen * offscreen) :
+ ImageViewport(offscreen),
m_render(true),
+ m_done(false),
m_scene(scene),
m_camera(camera),
m_owncamera(false),
+ m_offscreen(offscreen),
+ m_sync(NULL),
m_observer(NULL),
m_mirror(NULL),
m_clip(100.f),
@@ -81,6 +87,10 @@ ImageRender::ImageRender (KX_Scene *scene, KX_Camera * camera) :
m_engine = KX_GetActiveEngine();
m_rasterizer = m_engine->GetRasterizer();
m_canvas = m_engine->GetCanvas();
+ // keep a reference to the offscreen buffer
+ if (m_offscreen) {
+ Py_INCREF(m_offscreen);
+ }
}
// destructor
@@ -88,6 +98,9 @@ ImageRender::~ImageRender (void)
{
if (m_owncamera)
m_camera->Release();
+ if (m_sync)
+ delete m_sync;
+ Py_XDECREF(m_offscreen);
}
// get background color
@@ -121,30 +134,41 @@ void ImageRender::setBackgroundFromScene (KX_Scene *scene)
// capture image from viewport
-void ImageRender::calcImage (unsigned int texId, double ts)
+void ImageRender::calcViewport (unsigned int texId, double ts, unsigned int format)
{
- if (m_rasterizer->GetDrawingMode() != RAS_IRasterizer::KX_TEXTURED || // no need for texture
- m_camera->GetViewport() || // camera must be inactive
- m_camera == m_scene->GetActiveCamera())
- {
- // no need to compute texture in non texture rendering
- m_avail = false;
- return;
- }
// render the scene from the camera
- Render();
- // get image from viewport
- ImageViewport::calcImage(texId, ts);
- // restore OpenGL state
- m_canvas->EndFrame();
+ if (!m_done) {
+ if (!Render()) {
+ return;
+ }
+ }
+ else if (m_offscreen) {
+ m_offscreen->ofs->Bind(RAS_IOffScreen::RAS_OFS_BIND_READ);
+ }
+ // wait until all render operations are completed
+ WaitSync();
+ // get image from viewport (or FBO)
+ ImageViewport::calcViewport(texId, ts, format);
+ if (m_offscreen) {
+ m_offscreen->ofs->Unbind();
+ }
}
-void ImageRender::Render()
+bool ImageRender::Render()
{
RAS_FrameFrustum frustum;
- if (!m_render)
- return;
+ if (!m_render ||
+ m_rasterizer->GetDrawingMode() != RAS_IRasterizer::KX_TEXTURED || // no need for texture
+ m_camera->GetViewport() || // camera must be inactive
+ m_camera == m_scene->GetActiveCamera())
+ {
+ // no need to compute texture in non texture rendering
+ return false;
+ }
+
+ if (!m_scene->IsShadowDone())
+ m_engine->RenderShadowBuffers(m_scene);
if (m_mirror)
{
@@ -164,7 +188,7 @@ void ImageRender::Render()
MT_Scalar observerDistance = mirrorPlaneDTerm - observerWorldPos.dot(mirrorWorldZ);
// if distance < 0.01 => observer is on wrong side of mirror, don't render
if (observerDistance < 0.01)
- return;
+ return false;
// set camera world position = observerPos + normal * 2 * distance
MT_Point3 cameraWorldPos = observerWorldPos + (MT_Scalar(2.0)*observerDistance)*mirrorWorldZ;
m_camera->GetSGNode()->SetLocalPosition(cameraWorldPos);
@@ -215,7 +239,15 @@ void ImageRender::Render()
RAS_Rect area = m_canvas->GetWindowArea();
// The screen area that ImageViewport will copy is also the rendering zone
- m_canvas->SetViewPort(m_position[0], m_position[1], m_position[0]+m_capSize[0]-1, m_position[1]+m_capSize[1]-1);
+ if (m_offscreen) {
+ // bind the fbo and set the viewport to full size
+ m_offscreen->ofs->Bind(RAS_IOffScreen::RAS_OFS_BIND_RENDER);
+ // this is needed to stop crashing in canvas check
+ m_canvas->UpdateViewPort(0, 0, m_offscreen->ofs->GetWidth(), m_offscreen->ofs->GetHeight());
+ }
+ else {
+ m_canvas->SetViewPort(m_position[0], m_position[1], m_position[0]+m_capSize[0]-1, m_position[1]+m_capSize[1]-1);
+ }
m_canvas->ClearColor(m_background[0], m_background[1], m_background[2], m_background[3]);
m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER|RAS_ICanvas::DEPTH_BUFFER);
m_rasterizer->BeginFrame(m_engine->GetClockTime());
@@ -292,17 +324,18 @@ void ImageRender::Render()
MT_Transform camtrans(m_camera->GetWorldToCamera());
MT_Matrix4x4 viewmat(camtrans);
- m_rasterizer->SetViewMatrix(viewmat, m_camera->NodeGetWorldOrientation(), m_camera->NodeGetWorldPosition(), m_camera->GetCameraData()->m_perspective);
+ m_rasterizer->SetViewMatrix(viewmat, m_camera->NodeGetWorldOrientation(), m_camera->NodeGetWorldPosition(), m_camera->NodeGetLocalScaling(), m_camera->GetCameraData()->m_perspective);
m_camera->SetModelviewMatrix(viewmat);
// restore the stereo mode now that the matrix is computed
m_rasterizer->SetStereoMode(stereomode);
- if (stereomode == RAS_IRasterizer::RAS_STEREO_QUADBUFFERED) {
- // In QUAD buffer stereo mode, the GE render pass ends with the right eye on the right buffer
- // but we need to draw on the left buffer to capture the render
- // TODO: implement an explicit function in rasterizer to restore the left buffer.
- m_rasterizer->SetEye(RAS_IRasterizer::RAS_STEREO_LEFTEYE);
- }
+ if (m_rasterizer->Stereo()) {
+ // stereo mode change render settings that disturb this render, cancel them all
+ // we don't need to restore them as they are set before each frame render.
+ glDrawBuffer(GL_BACK_LEFT);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glDisable(GL_POLYGON_STIPPLE);
+ }
m_scene->CalculateVisibleMeshes(m_rasterizer,m_camera);
@@ -314,8 +347,48 @@ void ImageRender::Render()
// restore the canvas area now that the render is completed
m_canvas->GetWindowArea() = area;
+ m_canvas->EndFrame();
+
+ // In case multisample is active, blit the FBO
+ if (m_offscreen)
+ m_offscreen->ofs->Blit();
+ // end of all render operations, let's create a sync object just in case
+ if (m_sync) {
+ // a sync from a previous render, should not happen
+ delete m_sync;
+ m_sync = NULL;
+ }
+ m_sync = m_rasterizer->CreateSync(RAS_ISync::RAS_SYNC_TYPE_FENCE);
+ // remember that we have done render
+ m_done = true;
+ // the image is not available at this stage
+ m_avail = false;
+ return true;
+}
+
+void ImageRender::Unbind()
+{
+ if (m_offscreen)
+ {
+ m_offscreen->ofs->Unbind();
+ }
}
+void ImageRender::WaitSync()
+{
+ if (m_sync) {
+ m_sync->Wait();
+ // done with it, deleted it
+ delete m_sync;
+ m_sync = NULL;
+ }
+ if (m_offscreen) {
+ // this is needed to finalize the image if the target is a texture
+ m_offscreen->ofs->MipMap();
+ }
+ // all rendered operation done and complete, invalidate render for next time
+ m_done = false;
+}
// cast Image pointer to ImageRender
inline ImageRender * getImageRender (PyImage *self)
@@ -337,11 +410,13 @@ static int ImageRender_init(PyObject *pySelf, PyObject *args, PyObject *kwds)
PyObject *scene;
// camera object
PyObject *camera;
+ // offscreen buffer object
+ PyRASOffScreen *offscreen = NULL;
// parameter keywords
- static const char *kwlist[] = {"sceneObj", "cameraObj", NULL};
+ static const char *kwlist[] = {"sceneObj", "cameraObj", "ofsObj", NULL};
// get parameters
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO",
- const_cast<char**>(kwlist), &scene, &camera))
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|O",
+ const_cast<char**>(kwlist), &scene, &camera, &offscreen))
return -1;
try
{
@@ -357,11 +432,16 @@ static int ImageRender_init(PyObject *pySelf, PyObject *args, PyObject *kwds)
// throw exception if camera is not available
if (cameraPtr == NULL) THRWEXCP(CameraInvalid, S_OK);
+ if (offscreen) {
+ if (Py_TYPE(offscreen) != &PyRASOffScreen_Type) {
+ THRWEXCP(OffScreenInvalid, S_OK);
+ }
+ }
// get pointer to image structure
PyImage *self = reinterpret_cast<PyImage*>(pySelf);
// create source object
if (self->m_image != NULL) delete self->m_image;
- self->m_image = new ImageRender(scenePtr, cameraPtr);
+ self->m_image = new ImageRender(scenePtr, cameraPtr, offscreen);
}
catch (Exception & exp)
{
@@ -372,6 +452,55 @@ static int ImageRender_init(PyObject *pySelf, PyObject *args, PyObject *kwds)
return 0;
}
+static PyObject *ImageRender_refresh(PyImage *self, PyObject *args)
+{
+ ImageRender *imageRender = getImageRender(self);
+
+ if (!imageRender) {
+ PyErr_SetString(PyExc_TypeError, "Incomplete ImageRender() object");
+ return NULL;
+ }
+ if (PyArg_ParseTuple(args, "")) {
+ // refresh called with no argument.
+ // For other image objects it simply invalidates the image buffer
+ // For ImageRender it triggers a render+sync
+ // Note that this only makes sense when doing offscreen render on texture
+ if (!imageRender->isDone()) {
+ if (!imageRender->Render()) {
+ Py_RETURN_FALSE;
+ }
+ // as we are not trying to read the pixels, just unbind
+ imageRender->Unbind();
+ }
+ // wait until all render operations are completed
+ // this will also finalize the texture
+ imageRender->WaitSync();
+ Py_RETURN_TRUE;
+ }
+ else {
+ // fallback on standard processing
+ PyErr_Clear();
+ return Image_refresh(self, args);
+ }
+}
+
+// refresh image
+static PyObject *ImageRender_render(PyImage *self)
+{
+ ImageRender *imageRender = getImageRender(self);
+
+ if (!imageRender) {
+ PyErr_SetString(PyExc_TypeError, "Incomplete ImageRender() object");
+ return NULL;
+ }
+ if (!imageRender->Render()) {
+ Py_RETURN_FALSE;
+ }
+ // we are not reading the pixels now, unbind
+ imageRender->Unbind();
+ Py_RETURN_TRUE;
+}
+
// get background color
static PyObject *getBackground (PyImage *self, void *closure)
@@ -410,7 +539,8 @@ static int setBackground(PyImage *self, PyObject *value, void *closure)
// methods structure
static PyMethodDef imageRenderMethods[] =
{ // methods from ImageBase class
- {"refresh", (PyCFunction)Image_refresh, METH_NOARGS, "Refresh image - invalidate its current content"},
+ {"refresh", (PyCFunction)ImageRender_refresh, METH_VARARGS, "Refresh image - invalidate its current content after optionally transferring its content to a target buffer"},
+ {"render", (PyCFunction)ImageRender_render, METH_NOARGS, "Render scene - run before refresh() to performs asynchronous render"},
{NULL}
};
// attributes structure
@@ -601,7 +731,9 @@ static PyGetSetDef imageMirrorGetSets[] =
ImageRender::ImageRender (KX_Scene *scene, KX_GameObject *observer, KX_GameObject *mirror, RAS_IPolyMaterial *mat) :
ImageViewport(),
m_render(false),
+ m_done(false),
m_scene(scene),
+ m_offscreen(NULL),
m_observer(observer),
m_mirror(mirror),
m_clip(100.f)
diff --git a/source/gameengine/VideoTexture/ImageRender.h b/source/gameengine/VideoTexture/ImageRender.h
index ef55e4dea84..d062db44348 100644
--- a/source/gameengine/VideoTexture/ImageRender.h
+++ b/source/gameengine/VideoTexture/ImageRender.h
@@ -39,6 +39,8 @@
#include "DNA_screen_types.h"
#include "RAS_ICanvas.h"
#include "RAS_IRasterizer.h"
+#include "RAS_IOffScreen.h"
+#include "RAS_ISync.h"
#include "ImageViewport.h"
@@ -48,7 +50,7 @@ class ImageRender : public ImageViewport
{
public:
/// constructor
- ImageRender(KX_Scene *scene, KX_Camera *camera);
+ ImageRender(KX_Scene *scene, KX_Camera *camera, PyRASOffScreen *offscreen);
ImageRender(KX_Scene *scene, KX_GameObject *observer, KX_GameObject *mirror, RAS_IPolyMaterial * mat);
/// destructor
@@ -63,16 +65,30 @@ public:
float getClip (void) { return m_clip; }
/// set whole buffer use
void setClip (float clip) { m_clip = clip; }
+ /// render status
+ bool isDone() { return m_done; }
+ /// render frame (public so that it is accessible from python)
+ bool Render();
+ /// in case fbo is used, method to unbind
+ void Unbind();
+ /// wait for render to complete
+ void WaitSync();
protected:
/// true if ready to render
bool m_render;
+ /// is render done already?
+ bool m_done;
/// rendered scene
KX_Scene * m_scene;
/// camera for render
KX_Camera * m_camera;
/// do we own the camera?
bool m_owncamera;
+ /// if offscreen render
+ PyRASOffScreen *m_offscreen;
+ /// object to synchronize render even if no buffer transfer
+ RAS_ISync *m_sync;
/// for mirror operation
KX_GameObject * m_observer;
KX_GameObject * m_mirror;
@@ -91,15 +107,15 @@ protected:
KX_KetsjiEngine* m_engine;
/// background color
- float m_background[4];
+ float m_background[4];
/// render 3d scene to image
- virtual void calcImage (unsigned int texId, double ts);
+ virtual void calcImage (unsigned int texId, double ts) { calcViewport(texId, ts, GL_RGBA); }
+
+ /// render 3d scene to image
+ virtual void calcViewport (unsigned int texId, double ts, unsigned int format);
- void Render();
- void SetupRenderFrame(KX_Scene *scene, KX_Camera* cam);
- void RenderFrame(KX_Scene* scene, KX_Camera* cam);
void setBackgroundFromScene(KX_Scene *scene);
void SetWorldSettings(KX_WorldInfo* wi);
};
diff --git a/source/gameengine/VideoTexture/ImageViewport.cpp b/source/gameengine/VideoTexture/ImageViewport.cpp
index 820a019832e..8852c190053 100644
--- a/source/gameengine/VideoTexture/ImageViewport.cpp
+++ b/source/gameengine/VideoTexture/ImageViewport.cpp
@@ -45,14 +45,22 @@
// constructor
-ImageViewport::ImageViewport (void) : m_alpha(false), m_texInit(false)
+ImageViewport::ImageViewport (PyRASOffScreen *offscreen) : m_alpha(false), m_texInit(false)
{
// get viewport rectangle
- RAS_Rect rect = KX_GetActiveEngine()->GetCanvas()->GetWindowArea();
- m_viewport[0] = rect.GetLeft();
- m_viewport[1] = rect.GetBottom();
- m_viewport[2] = rect.GetWidth();
- m_viewport[3] = rect.GetHeight();
+ if (offscreen) {
+ m_viewport[0] = 0;
+ m_viewport[1] = 0;
+ m_viewport[2] = offscreen->ofs->GetWidth();
+ m_viewport[3] = offscreen->ofs->GetHeight();
+ }
+ else {
+ RAS_Rect rect = KX_GetActiveEngine()->GetCanvas()->GetWindowArea();
+ m_viewport[0] = rect.GetLeft();
+ m_viewport[1] = rect.GetBottom();
+ m_viewport[2] = rect.GetWidth();
+ m_viewport[3] = rect.GetHeight();
+ }
//glGetIntegerv(GL_VIEWPORT, m_viewport);
// create buffer for viewport image
@@ -60,7 +68,7 @@ ImageViewport::ImageViewport (void) : m_alpha(false), m_texInit(false)
// float (1 float = 4 bytes per pixel)
m_viewportImage = new BYTE [4 * getViewportSize()[0] * getViewportSize()[1]];
// set attributes
- setWhole(false);
+ setWhole((offscreen) ? true : false);
}
// destructor
@@ -126,25 +134,26 @@ void ImageViewport::setPosition (GLint pos[2])
// capture image from viewport
-void ImageViewport::calcImage (unsigned int texId, double ts)
+void ImageViewport::calcViewport (unsigned int texId, double ts, unsigned int format)
{
// if scale was changed
if (m_scaleChange)
// reset image
init(m_capSize[0], m_capSize[1]);
// if texture wasn't initialized
- if (!m_texInit) {
+ if (!m_texInit && texId != 0) {
// initialize it
loadTexture(texId, m_image, m_size);
m_texInit = true;
}
// if texture can be directly created
- if (texId != 0 && m_pyfilter == NULL && m_capSize[0] == calcSize(m_capSize[0])
- && m_capSize[1] == calcSize(m_capSize[1]) && !m_flip && !m_zbuff && !m_depth)
+ if (texId != 0 && m_pyfilter == NULL && m_size[0] == m_capSize[0] &&
+ m_size[1] == m_capSize[1] && !m_flip && !m_zbuff && !m_depth)
{
// just copy current viewport to texture
glBindTexture(GL_TEXTURE_2D, texId);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1]);
+ glBindTexture(GL_TEXTURE_2D, 0);
// image is not available
m_avail = false;
}
@@ -176,11 +185,33 @@ void ImageViewport::calcImage (unsigned int texId, double ts)
// get frame buffer data
if (m_alpha) {
- glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], GL_RGBA,
- GL_UNSIGNED_BYTE, m_viewportImage);
- // filter loaded data
- FilterRGBA32 filt;
- filterImage(filt, m_viewportImage, m_capSize);
+ // as we are reading the pixel in the native format, we can read directly in the image buffer
+ // if we are sure that no processing is needed on the image
+ if (m_size[0] == m_capSize[0] &&
+ m_size[1] == m_capSize[1] &&
+ !m_flip &&
+ !m_pyfilter)
+ {
+ glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], format,
+ GL_UNSIGNED_BYTE, m_image);
+ m_avail = true;
+ }
+ else if (!m_pyfilter) {
+ glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], format,
+ GL_UNSIGNED_BYTE, m_viewportImage);
+ FilterRGBA32 filt;
+ filterImage(filt, m_viewportImage, m_capSize);
+ }
+ else {
+ glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], GL_RGBA,
+ GL_UNSIGNED_BYTE, m_viewportImage);
+ FilterRGBA32 filt;
+ filterImage(filt, m_viewportImage, m_capSize);
+ if (format == GL_BGRA) {
+ // in place byte swapping
+ swapImageBR();
+ }
+ }
}
else {
glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], GL_RGB,
@@ -188,12 +219,46 @@ void ImageViewport::calcImage (unsigned int texId, double ts)
// filter loaded data
FilterRGB24 filt;
filterImage(filt, m_viewportImage, m_capSize);
+ if (format == GL_BGRA) {
+ // in place byte swapping
+ swapImageBR();
+ }
}
}
}
}
}
+bool ImageViewport::loadImage(unsigned int *buffer, unsigned int size, unsigned int format, double ts)
+{
+ unsigned int *tmp_image;
+ bool ret;
+
+ // if scale was changed
+ if (m_scaleChange) {
+ // reset image
+ init(m_capSize[0], m_capSize[1]);
+ }
+
+ // size must be identical
+ if (size < getBuffSize())
+ return false;
+
+ if (m_avail) {
+ // just copy
+ return ImageBase::loadImage(buffer, size, format, ts);
+ }
+ else {
+ tmp_image = m_image;
+ m_image = buffer;
+ calcViewport(0, ts, format);
+ ret = m_avail;
+ m_image = tmp_image;
+ // since the image was not loaded to our buffer, it's not valid
+ m_avail = false;
+ }
+ return ret;
+}
// cast Image pointer to ImageViewport
@@ -336,7 +401,7 @@ int ImageViewport_setCaptureSize(PyImage *self, PyObject *value, void *closure)
// methods structure
static PyMethodDef imageViewportMethods[] =
{ // methods from ImageBase class
- {"refresh", (PyCFunction)Image_refresh, METH_NOARGS, "Refresh image - invalidate its current content"},
+ {"refresh", (PyCFunction)Image_refresh, METH_VARARGS, "Refresh image - invalidate its current content"},
{NULL}
};
// attributes structure
diff --git a/source/gameengine/VideoTexture/ImageViewport.h b/source/gameengine/VideoTexture/ImageViewport.h
index 10d894a9fb8..8a7e9cfd2ba 100644
--- a/source/gameengine/VideoTexture/ImageViewport.h
+++ b/source/gameengine/VideoTexture/ImageViewport.h
@@ -35,6 +35,7 @@
#include "Common.h"
#include "ImageBase.h"
+#include "RAS_IOffScreen.h"
/// class for viewport access
@@ -42,7 +43,7 @@ class ImageViewport : public ImageBase
{
public:
/// constructor
- ImageViewport (void);
+ ImageViewport (PyRASOffScreen *offscreen=NULL);
/// destructor
virtual ~ImageViewport (void);
@@ -67,6 +68,9 @@ public:
/// set position in viewport
void setPosition (GLint pos[2] = NULL);
+ /// capture image from viewport to user buffer
+ virtual bool loadImage(unsigned int *buffer, unsigned int size, unsigned int format, double ts);
+
protected:
/// frame buffer rectangle
GLint m_viewport[4];
@@ -89,7 +93,10 @@ protected:
bool m_texInit;
/// capture image from viewport
- virtual void calcImage (unsigned int texId, double ts);
+ virtual void calcImage (unsigned int texId, double ts) { calcViewport(texId, ts, GL_RGBA); }
+
+ /// capture image from viewport
+ virtual void calcViewport (unsigned int texId, double ts, unsigned int format);
/// get viewport size
GLint * getViewportSize (void) { return m_viewport + 2; }
diff --git a/source/gameengine/VideoTexture/Texture.cpp b/source/gameengine/VideoTexture/Texture.cpp
index f1c7bc303ee..bb995747360 100644
--- a/source/gameengine/VideoTexture/Texture.cpp
+++ b/source/gameengine/VideoTexture/Texture.cpp
@@ -393,9 +393,10 @@ static PyObject *Texture_refresh(Texture *self, PyObject *args)
}
// load texture for rendering
loadTexture(self->m_actTex, texture, size, self->m_mipmap);
-
- // refresh texture source, if required
- if (refreshSource) self->m_source->m_image->refresh();
+ }
+ // refresh texture source, if required
+ if (refreshSource) {
+ self->m_source->m_image->refresh();
}
}
}
diff --git a/source/gameengine/VideoTexture/VideoBase.cpp b/source/gameengine/VideoTexture/VideoBase.cpp
index 9c8df0ca8c4..d373055b5df 100644
--- a/source/gameengine/VideoTexture/VideoBase.cpp
+++ b/source/gameengine/VideoTexture/VideoBase.cpp
@@ -137,8 +137,53 @@ PyObject *Video_getStatus(PyImage *self, void *closure)
}
// refresh video
-PyObject *Video_refresh(PyImage *self)
+PyObject *Video_refresh(PyImage *self, PyObject *args)
{
+ Py_buffer buffer;
+ char *mode = NULL;
+ unsigned int format;
+ double ts = -1.0;
+
+ memset(&buffer, 0, sizeof(buffer));
+ if (PyArg_ParseTuple(args, "|s*sd:refresh", &buffer, &mode, &ts)) {
+ if (buffer.buf) {
+ // a target buffer is provided, verify its format
+ if (buffer.readonly) {
+ PyErr_SetString(PyExc_TypeError, "Buffers passed in argument must be writable");
+ }
+ else if (!PyBuffer_IsContiguous(&buffer, 'C')) {
+ PyErr_SetString(PyExc_TypeError, "Buffers passed in argument must be contiguous in memory");
+ }
+ else if (((intptr_t)buffer.buf & 3) != 0) {
+ PyErr_SetString(PyExc_TypeError, "Buffers passed in argument must be aligned to 4 bytes boundary");
+ }
+ else {
+ // ready to get the image into our buffer
+ try {
+ if (mode == NULL || !strcmp(mode, "RGBA"))
+ format = GL_RGBA;
+ else if (!strcmp(mode, "BGRA"))
+ format = GL_BGRA;
+ else
+ THRWEXCP(InvalidImageMode,S_OK);
+
+ if (!self->m_image->loadImage((unsigned int *)buffer.buf, buffer.len, format, ts)) {
+ PyErr_SetString(PyExc_TypeError, "Could not load the buffer, perhaps size is not compatible");
+ }
+ }
+ catch (Exception & exp) {
+ exp.report();
+ }
+ }
+ PyBuffer_Release(&buffer);
+ if (PyErr_Occurred())
+ return NULL;
+ }
+ }
+ else
+ {
+ return NULL;
+ }
getVideo(self)->refresh();
return Video_getStatus(self, NULL);
}
diff --git a/source/gameengine/VideoTexture/VideoBase.h b/source/gameengine/VideoTexture/VideoBase.h
index 6f35c474300..77f46fdccd8 100644
--- a/source/gameengine/VideoTexture/VideoBase.h
+++ b/source/gameengine/VideoTexture/VideoBase.h
@@ -190,7 +190,7 @@ void Video_open(VideoBase *self, char *file, short captureID);
PyObject *Video_play(PyImage *self);
PyObject *Video_pause(PyImage *self);
PyObject *Video_stop(PyImage *self);
-PyObject *Video_refresh(PyImage *self);
+PyObject *Video_refresh(PyImage *self, PyObject *args);
PyObject *Video_getStatus(PyImage *self, void *closure);
PyObject *Video_getRange(PyImage *self, void *closure);
int Video_setRange(PyImage *self, PyObject *value, void *closure);
diff --git a/source/gameengine/VideoTexture/VideoDeckLink.cpp b/source/gameengine/VideoTexture/VideoDeckLink.cpp
new file mode 100644
index 00000000000..4f5e34896fc
--- /dev/null
+++ b/source/gameengine/VideoTexture/VideoDeckLink.cpp
@@ -0,0 +1,1228 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file gameengine/VideoTexture/VideoDeckLink.cpp
+ * \ingroup bgevideotex
+ */
+
+#ifdef WITH_GAMEENGINE_DECKLINK
+
+// FFmpeg defines its own version of stdint.h on Windows.
+// Decklink needs FFmpeg, so it uses its version of stdint.h
+// this is necessary for INT64_C macro
+#ifndef __STDC_CONSTANT_MACROS
+#define __STDC_CONSTANT_MACROS
+#endif
+// this is necessary for UINTPTR_MAX (used by atomic-ops)
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS
+#ifdef __STDC_LIMIT_MACROS /* else it may be unused */
+#endif
+#endif
+#include <stdint.h>
+#include <string.h>
+#ifndef WIN32
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/mman.h>
+#endif
+
+#include "atomic_ops.h"
+
+#include "MEM_guardedalloc.h"
+#include "PIL_time.h"
+#include "VideoDeckLink.h"
+#include "DeckLink.h"
+#include "Exception.h"
+#include "KX_KetsjiEngine.h"
+#include "KX_PythonInit.h"
+
+extern ExceptionID DeckLinkInternalError;
+ExceptionID SourceVideoOnlyCapture, VideoDeckLinkBadFormat, VideoDeckLinkOpenCard, VideoDeckLinkDvpInternalError, VideoDeckLinkPinMemoryError;
+ExpDesc SourceVideoOnlyCaptureDesc(SourceVideoOnlyCapture, "This video source only allows live capture");
+ExpDesc VideoDeckLinkBadFormatDesc(VideoDeckLinkBadFormat, "Invalid or unsupported capture format, should be <mode>/<pixel>[/3D]");
+ExpDesc VideoDeckLinkOpenCardDesc(VideoDeckLinkOpenCard, "Cannot open capture card, check if driver installed");
+ExpDesc VideoDeckLinkDvpInternalErrorDesc(VideoDeckLinkDvpInternalError, "DVP API internal error, please report");
+ExpDesc VideoDeckLinkPinMemoryErrorDesc(VideoDeckLinkPinMemoryError, "Error pinning memory");
+
+
+#ifdef WIN32
+////////////////////////////////////////////
+// SynInfo
+//
+// Sets up a semaphore which is shared between the GPU and CPU and used to
+// synchronise access to DVP buffers.
+#define DVP_CHECK(cmd) if ((cmd) != DVP_STATUS_OK) THRWEXCP(VideoDeckLinkDvpInternalError, S_OK)
+
+struct SyncInfo
+{
+ SyncInfo(uint32_t semaphoreAllocSize, uint32_t semaphoreAddrAlignment)
+ {
+ mSemUnaligned = (uint32_t*)malloc(semaphoreAllocSize + semaphoreAddrAlignment - 1);
+
+ // Apply alignment constraints
+ uint64_t val = (uint64_t)mSemUnaligned;
+ val += semaphoreAddrAlignment - 1;
+ val &= ~((uint64_t)semaphoreAddrAlignment - 1);
+ mSem = (uint32_t*)val;
+
+ // Initialise
+ mSem[0] = 0;
+ mReleaseValue = 0;
+ mAcquireValue = 0;
+
+ // Setup DVP sync object and import it
+ DVPSyncObjectDesc syncObjectDesc;
+ syncObjectDesc.externalClientWaitFunc = NULL;
+ syncObjectDesc.sem = (uint32_t*)mSem;
+
+ DVP_CHECK(dvpImportSyncObject(&syncObjectDesc, &mDvpSync));
+
+ }
+ ~SyncInfo()
+ {
+ dvpFreeSyncObject(mDvpSync);
+ free((void*)mSemUnaligned);
+ }
+
+ volatile uint32_t* mSem;
+ volatile uint32_t* mSemUnaligned;
+ volatile uint32_t mReleaseValue;
+ volatile uint32_t mAcquireValue;
+ DVPSyncObjectHandle mDvpSync;
+};
+
+////////////////////////////////////////////
+// TextureTransferDvp: transfer with GPUDirect
+////////////////////////////////////////////
+
+class TextureTransferDvp : public TextureTransfer
+{
+public:
+ TextureTransferDvp(DVPBufferHandle dvpTextureHandle, TextureDesc *pDesc, void *address, uint32_t allocatedSize)
+ {
+ DVPSysmemBufferDesc sysMemBuffersDesc;
+
+ mExtSync = NULL;
+ mGpuSync = NULL;
+ mDvpSysMemHandle = 0;
+ mDvpTextureHandle = 0;
+ mTextureHeight = 0;
+ mAllocatedSize = 0;
+ mBuffer = NULL;
+
+ if (!_PinBuffer(address, allocatedSize))
+ THRWEXCP(VideoDeckLinkPinMemoryError, S_OK);
+ mAllocatedSize = allocatedSize;
+ mBuffer = address;
+
+ try {
+ if (!mBufferAddrAlignment) {
+ DVP_CHECK(dvpGetRequiredConstantsGLCtx(&mBufferAddrAlignment, &mBufferGpuStrideAlignment,
+ &mSemaphoreAddrAlignment, &mSemaphoreAllocSize,
+ &mSemaphorePayloadOffset, &mSemaphorePayloadSize));
+ }
+ mExtSync = new SyncInfo(mSemaphoreAllocSize, mSemaphoreAddrAlignment);
+ mGpuSync = new SyncInfo(mSemaphoreAllocSize, mSemaphoreAddrAlignment);
+ sysMemBuffersDesc.width = pDesc->width;
+ sysMemBuffersDesc.height = pDesc->height;
+ sysMemBuffersDesc.stride = pDesc->stride;
+ switch (pDesc->format) {
+ case GL_RED_INTEGER:
+ sysMemBuffersDesc.format = DVP_RED_INTEGER;
+ break;
+ default:
+ sysMemBuffersDesc.format = DVP_BGRA;
+ break;
+ }
+ switch (pDesc->type) {
+ case GL_UNSIGNED_BYTE:
+ sysMemBuffersDesc.type = DVP_UNSIGNED_BYTE;
+ break;
+ case GL_UNSIGNED_INT_2_10_10_10_REV:
+ sysMemBuffersDesc.type = DVP_UNSIGNED_INT_2_10_10_10_REV;
+ break;
+ case GL_UNSIGNED_INT_8_8_8_8:
+ sysMemBuffersDesc.type = DVP_UNSIGNED_INT_8_8_8_8;
+ break;
+ case GL_UNSIGNED_INT_10_10_10_2:
+ sysMemBuffersDesc.type = DVP_UNSIGNED_INT_10_10_10_2;
+ break;
+ default:
+ sysMemBuffersDesc.type = DVP_UNSIGNED_INT;
+ break;
+ }
+ sysMemBuffersDesc.size = pDesc->width * pDesc->height * 4;
+ sysMemBuffersDesc.bufAddr = mBuffer;
+ DVP_CHECK(dvpCreateBuffer(&sysMemBuffersDesc, &mDvpSysMemHandle));
+ DVP_CHECK(dvpBindToGLCtx(mDvpSysMemHandle));
+ mDvpTextureHandle = dvpTextureHandle;
+ mTextureHeight = pDesc->height;
+ }
+ catch (Exception &) {
+ clean();
+ throw;
+ }
+ }
+ ~TextureTransferDvp()
+ {
+ clean();
+ }
+
+ virtual void PerformTransfer()
+ {
+ // perform the transfer
+ // tell DVP that the old texture buffer will no longer be used
+ dvpMapBufferEndAPI(mDvpTextureHandle);
+ // do we need this?
+ mGpuSync->mReleaseValue++;
+ dvpBegin();
+ // Copy from system memory to GPU texture
+ dvpMapBufferWaitDVP(mDvpTextureHandle);
+ dvpMemcpyLined(mDvpSysMemHandle, mExtSync->mDvpSync, mExtSync->mAcquireValue, DVP_TIMEOUT_IGNORED,
+ mDvpTextureHandle, mGpuSync->mDvpSync, mGpuSync->mReleaseValue, 0, mTextureHeight);
+ dvpMapBufferEndDVP(mDvpTextureHandle);
+ dvpEnd();
+ dvpMapBufferWaitAPI(mDvpTextureHandle);
+ // the transfer is now complete and the texture is ready for use
+ }
+
+private:
+ static uint32_t mBufferAddrAlignment;
+ static uint32_t mBufferGpuStrideAlignment;
+ static uint32_t mSemaphoreAddrAlignment;
+ static uint32_t mSemaphoreAllocSize;
+ static uint32_t mSemaphorePayloadOffset;
+ static uint32_t mSemaphorePayloadSize;
+
+ void clean()
+ {
+ if (mDvpSysMemHandle) {
+ dvpUnbindFromGLCtx(mDvpSysMemHandle);
+ dvpDestroyBuffer(mDvpSysMemHandle);
+ }
+ if (mExtSync)
+ delete mExtSync;
+ if (mGpuSync)
+ delete mGpuSync;
+ if (mBuffer)
+ _UnpinBuffer(mBuffer, mAllocatedSize);
+ }
+ SyncInfo* mExtSync;
+ SyncInfo* mGpuSync;
+ DVPBufferHandle mDvpSysMemHandle;
+ DVPBufferHandle mDvpTextureHandle;
+ uint32_t mTextureHeight;
+ uint32_t mAllocatedSize;
+ void* mBuffer;
+};
+
+uint32_t TextureTransferDvp::mBufferAddrAlignment;
+uint32_t TextureTransferDvp::mBufferGpuStrideAlignment;
+uint32_t TextureTransferDvp::mSemaphoreAddrAlignment;
+uint32_t TextureTransferDvp::mSemaphoreAllocSize;
+uint32_t TextureTransferDvp::mSemaphorePayloadOffset;
+uint32_t TextureTransferDvp::mSemaphorePayloadSize;
+
+#endif
+
+////////////////////////////////////////////
+// TextureTransferOGL: transfer using standard OGL buffers
+////////////////////////////////////////////
+
+class TextureTransferOGL : public TextureTransfer
+{
+public:
+ TextureTransferOGL(GLuint texId, TextureDesc *pDesc, void *address)
+ {
+ memcpy(&mDesc, pDesc, sizeof(mDesc));
+ mTexId = texId;
+ mBuffer = address;
+
+ // as we cache transfer object, we will create one texture to hold the buffer
+ glGenBuffers(1, &mUnpinnedTextureBuffer);
+ // create a storage for it
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mUnpinnedTextureBuffer);
+ glBufferData(GL_PIXEL_UNPACK_BUFFER, pDesc->size, NULL, GL_DYNAMIC_DRAW);
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+ }
+ ~TextureTransferOGL()
+ {
+ glDeleteBuffers(1, &mUnpinnedTextureBuffer);
+ }
+
+ virtual void PerformTransfer()
+ {
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mUnpinnedTextureBuffer);
+ glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, mDesc.size, mBuffer);
+ glBindTexture(GL_TEXTURE_2D, mTexId);
+ // NULL for last arg indicates use current GL_PIXEL_UNPACK_BUFFER target as texture data
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, mDesc.width, mDesc.height, mDesc.format, mDesc.type, NULL);
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+ }
+private:
+ // intermediate texture to receive the buffer
+ GLuint mUnpinnedTextureBuffer;
+ // target texture to receive the image
+ GLuint mTexId;
+ // buffer
+ void *mBuffer;
+ // characteristic of the image
+ TextureDesc mDesc;
+};
+
+////////////////////////////////////////////
+// TextureTransferPMB: transfer using pinned memory buffer
+////////////////////////////////////////////
+
+class TextureTransferPMD : public TextureTransfer
+{
+public:
+ TextureTransferPMD(GLuint texId, TextureDesc *pDesc, void *address, uint32_t allocatedSize)
+ {
+ memcpy(&mDesc, pDesc, sizeof(mDesc));
+ mTexId = texId;
+ mBuffer = address;
+ mAllocatedSize = allocatedSize;
+
+ _PinBuffer(address, allocatedSize);
+
+ // as we cache transfer object, we will create one texture to hold the buffer
+ glGenBuffers(1, &mPinnedTextureBuffer);
+ // create a storage for it
+ glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, mPinnedTextureBuffer);
+ glBufferData(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, pDesc->size, address, GL_STREAM_DRAW);
+ glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, 0);
+ }
+ ~TextureTransferPMD()
+ {
+ glDeleteBuffers(1, &mPinnedTextureBuffer);
+ if (mBuffer)
+ _UnpinBuffer(mBuffer, mAllocatedSize);
+ }
+
+ virtual void PerformTransfer()
+ {
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mPinnedTextureBuffer);
+ glBindTexture(GL_TEXTURE_2D, mTexId);
+ // NULL for last arg indicates use current GL_PIXEL_UNPACK_BUFFER target as texture data
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, mDesc.width, mDesc.height, mDesc.format, mDesc.type, NULL);
+ // wait for the trasnfer to complete
+ GLsync fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+ glClientWaitSync(fence, GL_SYNC_FLUSH_COMMANDS_BIT, 40 * 1000 * 1000); // timeout in nanosec
+ glDeleteSync(fence);
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+ }
+private:
+ // intermediate texture to receive the buffer
+ GLuint mPinnedTextureBuffer;
+ // target texture to receive the image
+ GLuint mTexId;
+ // buffer
+ void *mBuffer;
+ // the allocated size
+ uint32_t mAllocatedSize;
+ // characteristic of the image
+ TextureDesc mDesc;
+};
+
+bool TextureTransfer::_PinBuffer(void *address, uint32_t size)
+{
+#ifdef WIN32
+ return VirtualLock(address, size);
+#elif defined(_POSIX_MEMLOCK_RANGE)
+ return !mlock(address, size);
+#endif
+}
+
+void TextureTransfer::_UnpinBuffer(void* address, uint32_t size)
+{
+#ifdef WIN32
+ VirtualUnlock(address, size);
+#elif defined(_POSIX_MEMLOCK_RANGE)
+ munlock(address, size);
+#endif
+}
+
+
+
+////////////////////////////////////////////
+// PinnedMemoryAllocator
+////////////////////////////////////////////
+
+
+// static members
+bool PinnedMemoryAllocator::mGPUDirectInitialized = false;
+bool PinnedMemoryAllocator::mHasDvp = false;
+bool PinnedMemoryAllocator::mHasAMDPinnedMemory = false;
+size_t PinnedMemoryAllocator::mReservedProcessMemory = 0;
+
+bool PinnedMemoryAllocator::ReserveMemory(size_t size)
+{
+#ifdef WIN32
+ // Increase the process working set size to allow pinning of memory.
+ if (size <= mReservedProcessMemory)
+ return true;
+ SIZE_T dwMin = 0, dwMax = 0;
+ HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_SET_QUOTA, FALSE, GetCurrentProcessId());
+ if (!hProcess)
+ return false;
+
+ // Retrieve the working set size of the process.
+ if (!dwMin && !GetProcessWorkingSetSize(hProcess, &dwMin, &dwMax))
+ return false;
+
+ BOOL res = SetProcessWorkingSetSize(hProcess, (size - mReservedProcessMemory) + dwMin, (size - mReservedProcessMemory) + dwMax);
+ if (!res)
+ return false;
+ mReservedProcessMemory = size;
+ CloseHandle(hProcess);
+ return true;
+#else
+ struct rlimit rlim;
+ if (getrlimit(RLIMIT_MEMLOCK, &rlim) == 0) {
+ if (rlim.rlim_cur < size) {
+ if (rlim.rlim_max < size)
+ rlim.rlim_max = size;
+ rlim.rlim_cur = size;
+ return !setrlimit(RLIMIT_MEMLOCK, &rlim);
+ }
+ }
+ return false;
+#endif
+}
+
+PinnedMemoryAllocator::PinnedMemoryAllocator(unsigned cacheSize, size_t memSize) :
+mRefCount(1U),
+#ifdef WIN32
+mDvpCaptureTextureHandle(0),
+#endif
+mTexId(0),
+mBufferCacheSize(cacheSize)
+{
+ pthread_mutex_init(&mMutex, NULL);
+ // do it once
+ if (!mGPUDirectInitialized) {
+#ifdef WIN32
+ // In windows, AMD_pinned_memory option is not available,
+ // we must use special DVP API only available for Quadro cards
+ const char* renderer = (const char *)glGetString(GL_RENDERER);
+ mHasDvp = (strstr(renderer, "Quadro") != NULL);
+
+ if (mHasDvp) {
+ // In case the DLL is not in place, don't fail, just fallback on OpenGL
+ if (dvpInitGLContext(DVP_DEVICE_FLAGS_SHARE_APP_CONTEXT) != DVP_STATUS_OK) {
+ printf("Warning: Could not initialize DVP context, fallback on OpenGL transfer.\nInstall dvp.dll to take advantage of nVidia GPUDirect.\n");
+ mHasDvp = false;
+ }
+ }
+#endif
+ if (GLEW_AMD_pinned_memory)
+ mHasAMDPinnedMemory = true;
+
+ mGPUDirectInitialized = true;
+ }
+ if (mHasDvp || mHasAMDPinnedMemory) {
+ ReserveMemory(memSize);
+ }
+}
+
+PinnedMemoryAllocator::~PinnedMemoryAllocator()
+{
+ void *address;
+ // first clean the cache if not already done
+ while (!mBufferCache.empty()) {
+ address = mBufferCache.back();
+ mBufferCache.pop_back();
+ _ReleaseBuffer(address);
+ }
+ // clean preallocated buffers
+ while (!mAllocatedSize.empty()) {
+ address = mAllocatedSize.begin()->first;
+ _ReleaseBuffer(address);
+ }
+
+#ifdef WIN32
+ if (mDvpCaptureTextureHandle)
+ dvpDestroyBuffer(mDvpCaptureTextureHandle);
+#endif
+}
+
+void PinnedMemoryAllocator::TransferBuffer(void* address, TextureDesc* texDesc, GLuint texId)
+{
+ uint32_t allocatedSize = 0;
+ TextureTransfer *pTransfer = NULL;
+
+ Lock();
+ if (mAllocatedSize.count(address) > 0)
+ allocatedSize = mAllocatedSize[address];
+ Unlock();
+ if (!allocatedSize)
+ // internal error!!
+ return;
+ if (mTexId != texId)
+ {
+ // first time we try to send data to the GPU, allocate a buffer for the texture
+ glBindTexture(GL_TEXTURE_2D, texId);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+ glTexImage2D(GL_TEXTURE_2D, 0, texDesc->internalFormat, texDesc->width, texDesc->height, 0, texDesc->format, texDesc->type, NULL);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ mTexId = texId;
+ }
+#ifdef WIN32
+ if (mHasDvp)
+ {
+ if (!mDvpCaptureTextureHandle)
+ {
+ // bind DVP to the OGL texture
+ DVP_CHECK(dvpCreateGPUTextureGL(texId, &mDvpCaptureTextureHandle));
+ }
+ }
+#endif
+ Lock();
+ if (mPinnedBuffer.count(address) > 0)
+ {
+ pTransfer = mPinnedBuffer[address];
+ }
+ Unlock();
+ if (!pTransfer)
+ {
+#ifdef WIN32
+ if (mHasDvp)
+ pTransfer = new TextureTransferDvp(mDvpCaptureTextureHandle, texDesc, address, allocatedSize);
+ else
+#endif
+ if (mHasAMDPinnedMemory) {
+ pTransfer = new TextureTransferPMD(texId, texDesc, address, allocatedSize);
+ }
+ else {
+ pTransfer = new TextureTransferOGL(texId, texDesc, address);
+ }
+ if (pTransfer)
+ {
+ Lock();
+ mPinnedBuffer[address] = pTransfer;
+ Unlock();
+ }
+ }
+ if (pTransfer)
+ pTransfer->PerformTransfer();
+}
+
+// IUnknown methods
+HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::QueryInterface(REFIID /*iid*/, LPVOID* /*ppv*/)
+{
+ return E_NOTIMPL;
+}
+
+ULONG STDMETHODCALLTYPE PinnedMemoryAllocator::AddRef(void)
+{
+ return atomic_add_uint32(&mRefCount, 1U);
+}
+
+ULONG STDMETHODCALLTYPE PinnedMemoryAllocator::Release(void)
+{
+ uint32_t newCount = atomic_sub_uint32(&mRefCount, 1U);
+ if (newCount == 0)
+ delete this;
+ return (ULONG)newCount;
+}
+
+// IDeckLinkMemoryAllocator methods
+HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::AllocateBuffer(dl_size_t bufferSize, void* *allocatedBuffer)
+{
+ Lock();
+ if (mBufferCache.empty())
+ {
+ // Allocate memory on a page boundary
+ // Note: aligned alloc exist in Blender but only for small alignment, use direct allocation then.
+ // Note: the DeckLink API tries to allocate up to 65 buffer in advance, we will limit this to 3
+ // because we don't need any caching
+ if (mAllocatedSize.size() >= mBufferCacheSize)
+ *allocatedBuffer = NULL;
+ else {
+#ifdef WIN32
+ *allocatedBuffer = VirtualAlloc(NULL, bufferSize, MEM_COMMIT | MEM_RESERVE | MEM_WRITE_WATCH, PAGE_READWRITE);
+#else
+ if (posix_memalign(allocatedBuffer, 4096, bufferSize) != 0)
+ *allocatedBuffer = NULL;
+#endif
+ mAllocatedSize[*allocatedBuffer] = bufferSize;
+ }
+ }
+ else {
+ // Re-use most recently ReleaseBuffer'd address
+ *allocatedBuffer = mBufferCache.back();
+ mBufferCache.pop_back();
+ }
+ Unlock();
+ return (*allocatedBuffer) ? S_OK : E_OUTOFMEMORY;
+}
+
+HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::ReleaseBuffer(void* buffer)
+{
+ HRESULT result = S_OK;
+ Lock();
+ if (mBufferCache.size() < mBufferCacheSize) {
+ mBufferCache.push_back(buffer);
+ }
+ else {
+ result = _ReleaseBuffer(buffer);
+ }
+ Unlock();
+ return result;
+}
+
+
+HRESULT PinnedMemoryAllocator::_ReleaseBuffer(void* buffer)
+{
+ TextureTransfer *pTransfer;
+ if (mAllocatedSize.count(buffer) == 0) {
+ // Internal error!!
+ return S_OK;
+ }
+ else {
+ // No room left in cache, so un-pin (if it was pinned) and free this buffer
+ if (mPinnedBuffer.count(buffer) > 0) {
+ pTransfer = mPinnedBuffer[buffer];
+ mPinnedBuffer.erase(buffer);
+ delete pTransfer;
+ }
+#ifdef WIN32
+ VirtualFree(buffer, 0, MEM_RELEASE);
+#else
+ free(buffer);
+#endif
+ mAllocatedSize.erase(buffer);
+ }
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::Commit()
+{
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::Decommit()
+{
+ void *buffer;
+ Lock();
+ while (!mBufferCache.empty()) {
+ // Cleanup any frames allocated and pinned in AllocateBuffer() but not freed in ReleaseBuffer()
+ buffer = mBufferCache.back();
+ mBufferCache.pop_back();
+ _ReleaseBuffer(buffer);
+ }
+ Unlock();
+ return S_OK;
+}
+
+
+////////////////////////////////////////////
+// Capture Delegate Class
+////////////////////////////////////////////
+
+CaptureDelegate::CaptureDelegate(VideoDeckLink* pOwner) : mpOwner(pOwner)
+{
+}
+
+HRESULT CaptureDelegate::VideoInputFrameArrived(IDeckLinkVideoInputFrame* inputFrame, IDeckLinkAudioInputPacket* /*audioPacket*/)
+{
+ if (!inputFrame) {
+ // It's possible to receive a NULL inputFrame, but a valid audioPacket. Ignore audio-only frame.
+ return S_OK;
+ }
+ if ((inputFrame->GetFlags() & bmdFrameHasNoInputSource) == bmdFrameHasNoInputSource) {
+ // let's not bother transferring frames if there is no source
+ return S_OK;
+ }
+ mpOwner->VideoFrameArrived(inputFrame);
+ return S_OK;
+}
+
+HRESULT CaptureDelegate::VideoInputFormatChanged(BMDVideoInputFormatChangedEvents notificationEvents, IDeckLinkDisplayMode *newDisplayMode, BMDDetectedVideoInputFormatFlags detectedSignalFlags)
+{
+ return S_OK;
+}
+
+
+
+
+// macro for exception handling and logging
+#define CATCH_EXCP catch (Exception & exp) \
+{ exp.report(); m_status = SourceError; }
+
+// class VideoDeckLink
+
+
+// constructor
+VideoDeckLink::VideoDeckLink (HRESULT * hRslt) : VideoBase(),
+mDLInput(NULL),
+mUse3D(false),
+mFrameWidth(0),
+mFrameHeight(0),
+mpAllocator(NULL),
+mpCaptureDelegate(NULL),
+mpCacheFrame(NULL),
+mClosing(false)
+{
+ mDisplayMode = (BMDDisplayMode)0;
+ mPixelFormat = (BMDPixelFormat)0;
+ pthread_mutex_init(&mCacheMutex, NULL);
+}
+
+// destructor
+VideoDeckLink::~VideoDeckLink ()
+{
+ LockCache();
+ mClosing = true;
+ if (mpCacheFrame)
+ {
+ mpCacheFrame->Release();
+ mpCacheFrame = NULL;
+ }
+ UnlockCache();
+ if (mDLInput != NULL)
+ {
+ // Cleanup for Capture
+ mDLInput->StopStreams();
+ mDLInput->SetCallback(NULL);
+ mDLInput->DisableVideoInput();
+ mDLInput->DisableAudioInput();
+ mDLInput->FlushStreams();
+ if (mDLInput->Release() != 0) {
+ printf("Reference count not NULL on DeckLink device when closing it, please report!\n");
+ }
+ mDLInput = NULL;
+ }
+
+ if (mpAllocator)
+ {
+ // if the device was properly cleared, this should be 0
+ if (mpAllocator->Release() != 0) {
+ printf("Reference count not NULL on Allocator when closing it, please report!\n");
+ }
+ mpAllocator = NULL;
+ }
+ if (mpCaptureDelegate)
+ {
+ delete mpCaptureDelegate;
+ mpCaptureDelegate = NULL;
+ }
+}
+
+void VideoDeckLink::refresh(void)
+{
+ m_avail = false;
+}
+
+// release components
+bool VideoDeckLink::release()
+{
+ // release
+ return true;
+}
+
+// open video file
+void VideoDeckLink::openFile (char *filename)
+{
+ // only live capture on this device
+ THRWEXCP(SourceVideoOnlyCapture, S_OK);
+}
+
+
+// open video capture device
+void VideoDeckLink::openCam (char *format, short camIdx)
+{
+ IDeckLinkDisplayModeIterator* pDLDisplayModeIterator;
+ BMDDisplayModeSupport modeSupport;
+ IDeckLinkDisplayMode* pDLDisplayMode;
+ IDeckLinkIterator* pIterator;
+ BMDTimeValue frameDuration;
+ BMDTimeScale frameTimescale;
+ IDeckLink* pDL;
+ uint32_t displayFlags, inputFlags;
+ char *pPixel, *p3D, *pEnd, *pSize;
+ size_t len;
+ int i, modeIdx, cacheSize;
+
+ // format is constructed as <displayMode>/<pixelFormat>[/3D][:<cacheSize>]
+ // <displayMode> takes the form of BMDDisplayMode identifier minus the 'bmdMode' prefix.
+ // This implementation understands all the modes defined in SDK 10.3.1 but you can alternatively
+ // use the 4 characters internal representation of the mode (e.g. 'HD1080p24' == '24ps')
+ // <pixelFormat> takes the form of BMDPixelFormat identifier minus the 'bmdFormat' prefix.
+ // This implementation understand all the formats defined in SDK 10.32.1 but you can alternatively
+ // use the 4 characters internal representation of the format (e.g. '10BitRGB' == 'r210')
+ // Not all combinations of mode and pixel format are possible and it also depends on the card!
+ // Use /3D postfix if you are capturing a 3D stream with frame packing
+ // Example: To capture FullHD 1920x1080@24Hz with 3D packing and 4:4:4 10 bits RGB pixel format, use
+ // "HD1080p24/10BitRGB/3D" (same as "24ps/r210/3D")
+ // (this will be the normal capture format for FullHD on the DeckLink 4k extreme)
+
+ if ((pSize = strchr(format, ':')) != NULL) {
+ cacheSize = strtol(pSize+1, &pEnd, 10);
+ }
+ else {
+ cacheSize = 8;
+ pSize = format + strlen(format);
+ }
+ if ((pPixel = strchr(format, '/')) == NULL ||
+ ((p3D = strchr(pPixel + 1, '/')) != NULL && strncmp(p3D, "/3D", pSize-p3D)))
+ THRWEXCP(VideoDeckLinkBadFormat, S_OK);
+ mUse3D = (p3D) ? true : false;
+ // to simplify pixel format parsing
+ if (!p3D)
+ p3D = pSize;
+
+ // read the mode
+ len = (size_t)(pPixel - format);
+ // accept integer display mode
+
+ try {
+ // throws if bad mode
+ decklink_ReadDisplayMode(format, len, &mDisplayMode);
+ // found a valid mode, remember that we do not look for an index
+ modeIdx = -1;
+ }
+ catch (Exception &) {
+ // accept also purely numerical mode as a mode index
+ modeIdx = strtol(format, &pEnd, 10);
+ if (pEnd != pPixel || modeIdx < 0)
+ // not a pure number, give up
+ throw;
+ }
+
+ // skip /
+ pPixel++;
+ len = (size_t)(p3D - pPixel);
+ // throws if bad format
+ decklink_ReadPixelFormat(pPixel, len, &mPixelFormat);
+
+ // Caution: DeckLink API used from this point, make sure entity are released before throwing
+ // open the card
+ pIterator = BMD_CreateDeckLinkIterator();
+ if (pIterator) {
+ i = 0;
+ while (pIterator->Next(&pDL) == S_OK) {
+ if (i == camIdx) {
+ if (pDL->QueryInterface(IID_IDeckLinkInput, (void**)&mDLInput) != S_OK)
+ mDLInput = NULL;
+ pDL->Release();
+ break;
+ }
+ i++;
+ pDL->Release();
+ }
+ pIterator->Release();
+ }
+ if (!mDLInput)
+ THRWEXCP(VideoDeckLinkOpenCard, S_OK);
+
+
+ // check if display mode and pixel format are supported
+ if (mDLInput->GetDisplayModeIterator(&pDLDisplayModeIterator) != S_OK)
+ THRWEXCP(DeckLinkInternalError, S_OK);
+
+ pDLDisplayMode = NULL;
+ displayFlags = (mUse3D) ? bmdDisplayModeSupports3D : 0;
+ inputFlags = (mUse3D) ? bmdVideoInputDualStream3D : bmdVideoInputFlagDefault;
+ while (pDLDisplayModeIterator->Next(&pDLDisplayMode) == S_OK)
+ {
+ if (modeIdx == 0 || pDLDisplayMode->GetDisplayMode() == mDisplayMode) {
+ // in case we get here because of modeIdx, make sure we have mDisplayMode set
+ mDisplayMode = pDLDisplayMode->GetDisplayMode();
+ if ((pDLDisplayMode->GetFlags() & displayFlags) == displayFlags &&
+ mDLInput->DoesSupportVideoMode(mDisplayMode, mPixelFormat, inputFlags, &modeSupport, NULL) == S_OK &&
+ modeSupport == bmdDisplayModeSupported)
+ {
+ break;
+ }
+ }
+ pDLDisplayMode->Release();
+ pDLDisplayMode = NULL;
+ if (modeIdx-- == 0) {
+ // reached the correct mode index but it does not meet the pixel format, give up
+ break;
+ }
+ }
+ pDLDisplayModeIterator->Release();
+
+ if (pDLDisplayMode == NULL)
+ THRWEXCP(VideoDeckLinkBadFormat, S_OK);
+
+ mFrameWidth = pDLDisplayMode->GetWidth();
+ mFrameHeight = pDLDisplayMode->GetHeight();
+ mTextureDesc.height = (mUse3D) ? 2 * mFrameHeight : mFrameHeight;
+ pDLDisplayMode->GetFrameRate(&frameDuration, &frameTimescale);
+ pDLDisplayMode->Release();
+ // for information, in case the application wants to know
+ m_size[0] = mFrameWidth;
+ m_size[1] = mTextureDesc.height;
+ m_frameRate = (float)frameTimescale / (float)frameDuration;
+
+ switch (mPixelFormat)
+ {
+ case bmdFormat8BitYUV:
+ // 2 pixels per word
+ mTextureDesc.stride = mFrameWidth * 2;
+ mTextureDesc.width = mFrameWidth / 2;
+ mTextureDesc.internalFormat = GL_RGBA;
+ mTextureDesc.format = GL_BGRA;
+ mTextureDesc.type = GL_UNSIGNED_BYTE;
+ break;
+ case bmdFormat10BitYUV:
+ // 6 pixels in 4 words, rounded to 48 pixels
+ mTextureDesc.stride = ((mFrameWidth + 47) / 48) * 128;
+ mTextureDesc.width = mTextureDesc.stride/4;
+ mTextureDesc.internalFormat = GL_RGB10_A2;
+ mTextureDesc.format = GL_BGRA;
+ mTextureDesc.type = GL_UNSIGNED_INT_2_10_10_10_REV;
+ break;
+ case bmdFormat8BitARGB:
+ mTextureDesc.stride = mFrameWidth * 4;
+ mTextureDesc.width = mFrameWidth;
+ mTextureDesc.internalFormat = GL_RGBA;
+ mTextureDesc.format = GL_BGRA;
+ mTextureDesc.type = GL_UNSIGNED_INT_8_8_8_8;
+ break;
+ case bmdFormat8BitBGRA:
+ mTextureDesc.stride = mFrameWidth * 4;
+ mTextureDesc.width = mFrameWidth;
+ mTextureDesc.internalFormat = GL_RGBA;
+ mTextureDesc.format = GL_BGRA;
+ mTextureDesc.type = GL_UNSIGNED_BYTE;
+ break;
+ case bmdFormat10BitRGBXLE:
+ // 1 pixel per word, rounded to 64 pixels
+ mTextureDesc.stride = ((mFrameWidth + 63) / 64) * 256;
+ mTextureDesc.width = mTextureDesc.stride/4;
+ mTextureDesc.internalFormat = GL_RGB10_A2;
+ mTextureDesc.format = GL_RGBA;
+ mTextureDesc.type = GL_UNSIGNED_INT_10_10_10_2;
+ break;
+ case bmdFormat10BitRGBX:
+ case bmdFormat10BitRGB:
+ // 1 pixel per word, rounded to 64 pixels
+ mTextureDesc.stride = ((mFrameWidth + 63) / 64) * 256;
+ mTextureDesc.width = mTextureDesc.stride/4;
+ mTextureDesc.internalFormat = GL_R32UI;
+ mTextureDesc.format = GL_RED_INTEGER;
+ mTextureDesc.type = GL_UNSIGNED_INT;
+ break;
+ case bmdFormat12BitRGB:
+ case bmdFormat12BitRGBLE:
+ // 8 pixels in 9 word
+ mTextureDesc.stride = (mFrameWidth * 36) / 8;
+ mTextureDesc.width = mTextureDesc.stride/4;
+ mTextureDesc.internalFormat = GL_R32UI;
+ mTextureDesc.format = GL_RED_INTEGER;
+ mTextureDesc.type = GL_UNSIGNED_INT;
+ break;
+ default:
+ // for unknown pixel format, this will be resolved when a frame arrives
+ mTextureDesc.format = GL_RED_INTEGER;
+ mTextureDesc.type = GL_UNSIGNED_INT;
+ break;
+ }
+ // reserve memory for cache frame + 1 to accomodate for pixel format that we don't know yet
+ // note: we can't use stride as it is not yet known if the pixel format is unknown
+ // use instead the frame width as in worst case it's not much different (e.g. HD720/10BITYUV: 1296 pixels versus 1280)
+ // note: some pixel format take more than 4 bytes take that into account (9/8 versus 1)
+ mpAllocator = new PinnedMemoryAllocator(cacheSize, mFrameWidth*mTextureDesc.height * 4 * (1+cacheSize*9/8));
+
+ if (mDLInput->SetVideoInputFrameMemoryAllocator(mpAllocator) != S_OK)
+ THRWEXCP(DeckLinkInternalError, S_OK);
+
+ mpCaptureDelegate = new CaptureDelegate(this);
+ if (mDLInput->SetCallback(mpCaptureDelegate) != S_OK)
+ THRWEXCP(DeckLinkInternalError, S_OK);
+
+ if (mDLInput->EnableVideoInput(mDisplayMode, mPixelFormat, ((mUse3D) ? bmdVideoInputDualStream3D : bmdVideoInputFlagDefault)) != S_OK)
+ // this shouldn't failed, we tested above
+ THRWEXCP(DeckLinkInternalError, S_OK);
+
+ // just in case it is needed to capture from certain cards, we don't check error because we don't need audio
+ mDLInput->EnableAudioInput(bmdAudioSampleRate48kHz, bmdAudioSampleType16bitInteger, 2);
+
+ // open base class
+ VideoBase::openCam(format, camIdx);
+
+ // ready to capture, will start when application calls play()
+}
+
+// play video
+bool VideoDeckLink::play (void)
+{
+ try
+ {
+ // if object is able to play
+ if (VideoBase::play())
+ {
+ mDLInput->FlushStreams();
+ return (mDLInput->StartStreams() == S_OK);
+ }
+ }
+ CATCH_EXCP;
+ return false;
+}
+
+
+// pause video
+bool VideoDeckLink::pause (void)
+{
+ try
+ {
+ if (VideoBase::pause())
+ {
+ mDLInput->PauseStreams();
+ return true;
+ }
+ }
+ CATCH_EXCP;
+ return false;
+}
+
+// stop video
+bool VideoDeckLink::stop (void)
+{
+ try
+ {
+ VideoBase::stop();
+ mDLInput->StopStreams();
+ return true;
+ }
+ CATCH_EXCP;
+ return false;
+}
+
+
+// set video range
+void VideoDeckLink::setRange (double start, double stop)
+{
+}
+
+// set framerate
+void VideoDeckLink::setFrameRate (float rate)
+{
+}
+
+
+// image calculation
+// send cache frame directly to GPU
+void VideoDeckLink::calcImage (unsigned int texId, double ts)
+{
+ IDeckLinkVideoInputFrame* pFrame;
+ LockCache();
+ pFrame = mpCacheFrame;
+ mpCacheFrame = NULL;
+ UnlockCache();
+ if (pFrame) {
+ // BUG: the dvpBindToGLCtx function fails the first time it is used, don't know why.
+ // This causes an exception to be thrown.
+ // This should be fixed but in the meantime we will catch the exception because
+ // it is crucial that we release the frame to keep the reference count right on the DeckLink device
+ try {
+ uint32_t rowSize = pFrame->GetRowBytes();
+ uint32_t textureSize = rowSize * pFrame->GetHeight();
+ void* videoPixels = NULL;
+ void* rightEyePixels = NULL;
+ if (!mTextureDesc.stride) {
+ // we could not compute the texture size earlier (unknown pixel size)
+ // let's do it now
+ mTextureDesc.stride = rowSize;
+ mTextureDesc.width = mTextureDesc.stride / 4;
+ }
+ if (mTextureDesc.stride != rowSize) {
+ // unexpected frame size, ignore
+ // TBD: print a warning
+ }
+ else {
+ pFrame->GetBytes(&videoPixels);
+ if (mUse3D) {
+ IDeckLinkVideoFrame3DExtensions *if3DExtensions = NULL;
+ IDeckLinkVideoFrame *rightEyeFrame = NULL;
+ if (pFrame->QueryInterface(IID_IDeckLinkVideoFrame3DExtensions, (void **)&if3DExtensions) == S_OK &&
+ if3DExtensions->GetFrameForRightEye(&rightEyeFrame) == S_OK) {
+ rightEyeFrame->GetBytes(&rightEyePixels);
+ textureSize += ((uint64_t)rightEyePixels - (uint64_t)videoPixels);
+ }
+ if (rightEyeFrame)
+ rightEyeFrame->Release();
+ if (if3DExtensions)
+ if3DExtensions->Release();
+ }
+ mTextureDesc.size = mTextureDesc.width * mTextureDesc.height * 4;
+ if (mTextureDesc.size == textureSize) {
+ // this means that both left and right frame are contiguous and that there is no padding
+ // do the transfer
+ mpAllocator->TransferBuffer(videoPixels, &mTextureDesc, texId);
+ }
+ }
+ }
+ catch (Exception &) {
+ pFrame->Release();
+ throw;
+ }
+ // this will trigger PinnedMemoryAllocator::RealaseBuffer
+ pFrame->Release();
+ }
+ // currently we don't pass the image to the application
+ m_avail = false;
+}
+
+// A frame is available from the board
+// Called from an internal thread, just pass the frame to the main thread
+void VideoDeckLink::VideoFrameArrived(IDeckLinkVideoInputFrame* inputFrame)
+{
+ IDeckLinkVideoInputFrame* pOldFrame = NULL;
+ LockCache();
+ if (!mClosing)
+ {
+ pOldFrame = mpCacheFrame;
+ mpCacheFrame = inputFrame;
+ inputFrame->AddRef();
+ }
+ UnlockCache();
+ // old frame no longer needed, just release it
+ if (pOldFrame)
+ pOldFrame->Release();
+}
+
+// python methods
+
+// object initialization
+static int VideoDeckLink_init(PyObject *pySelf, PyObject *args, PyObject *kwds)
+{
+ static const char *kwlist[] = { "format", "capture", NULL };
+ PyImage *self = reinterpret_cast<PyImage*>(pySelf);
+ // see openCam for a description of format
+ char * format = NULL;
+ // capture device number, i.e. DeckLink card number, default first one
+ short capt = 0;
+
+ if (!GLEW_VERSION_1_5) {
+ PyErr_SetString(PyExc_RuntimeError, "VideoDeckLink requires at least OpenGL 1.5");
+ return -1;
+ }
+ // get parameters
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|h",
+ const_cast<char**>(kwlist), &format, &capt))
+ return -1;
+
+ try {
+ // create video object
+ Video_init<VideoDeckLink>(self);
+
+ // open video source, control comes back to VideoDeckLink::openCam
+ Video_open(getVideo(self), format, capt);
+ }
+ catch (Exception & exp) {
+ exp.report();
+ return -1;
+ }
+ // initialization succeded
+ return 0;
+}
+
+// methods structure
+static PyMethodDef videoMethods[] =
+{ // methods from VideoBase class
+ {"play", (PyCFunction)Video_play, METH_NOARGS, "Play (restart) video"},
+ {"pause", (PyCFunction)Video_pause, METH_NOARGS, "pause video"},
+ {"stop", (PyCFunction)Video_stop, METH_NOARGS, "stop video (play will replay it from start)"},
+ {"refresh", (PyCFunction)Video_refresh, METH_VARARGS, "Refresh video - get its status"},
+ {NULL}
+};
+// attributes structure
+static PyGetSetDef videoGetSets[] =
+{ // methods from VideoBase class
+ {(char*)"status", (getter)Video_getStatus, NULL, (char*)"video status", NULL},
+ {(char*)"framerate", (getter)Video_getFrameRate, NULL, (char*)"frame rate", NULL},
+ // attributes from ImageBase class
+ {(char*)"valid", (getter)Image_valid, NULL, (char*)"bool to tell if an image is available", NULL},
+ {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL},
+ {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL},
+ {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbor)", NULL},
+ {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL},
+ {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL},
+ {NULL}
+};
+
+// python type declaration
+PyTypeObject VideoDeckLinkType =
+{
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "VideoTexture.VideoDeckLink", /*tp_name*/
+ sizeof(PyImage), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)Image_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ &imageBufferProcs, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ "DeckLink video source", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ videoMethods, /* tp_methods */
+ 0, /* tp_members */
+ videoGetSets, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)VideoDeckLink_init, /* tp_init */
+ 0, /* tp_alloc */
+ Image_allocNew, /* tp_new */
+};
+
+
+
+////////////////////////////////////////////
+// DeckLink Capture Delegate Class
+////////////////////////////////////////////
+
+#endif // WITH_GAMEENGINE_DECKLINK
+
diff --git a/source/gameengine/VideoTexture/VideoDeckLink.h b/source/gameengine/VideoTexture/VideoDeckLink.h
new file mode 100644
index 00000000000..50099d2ead4
--- /dev/null
+++ b/source/gameengine/VideoTexture/VideoDeckLink.h
@@ -0,0 +1,256 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file VideoDeckLink.h
+ * \ingroup bgevideotex
+ */
+
+#ifndef __VIDEODECKLINK_H__
+#define __VIDEODECKLINK_H__
+
+#ifdef WITH_GAMEENGINE_DECKLINK
+
+/* this needs to be parsed with __cplusplus defined before included through DeckLink_compat.h */
+#if defined(__FreeBSD__)
+# include <inttypes.h>
+#endif
+#include <map>
+#include <set>
+
+extern "C" {
+#include <pthread.h>
+#include "DNA_listBase.h"
+#include "BLI_threads.h"
+#include "BLI_blenlib.h"
+}
+#include "GL/glew.h"
+#ifdef WIN32
+#include "dvpapi.h"
+#endif
+#include "DeckLinkAPI.h"
+#include "VideoBase.h"
+
+class PinnedMemoryAllocator;
+
+struct TextureDesc
+{
+ uint32_t width;
+ uint32_t height;
+ uint32_t stride;
+ uint32_t size;
+ GLenum internalFormat;
+ GLenum format;
+ GLenum type;
+ TextureDesc()
+ {
+ width = 0;
+ height = 0;
+ stride = 0;
+ size = 0;
+ internalFormat = 0;
+ format = 0;
+ type = 0;
+ }
+};
+
+class CaptureDelegate;
+
+// type VideoDeckLink declaration
+class VideoDeckLink : public VideoBase
+{
+ friend class CaptureDelegate;
+public:
+ /// constructor
+ VideoDeckLink (HRESULT * hRslt);
+ /// destructor
+ virtual ~VideoDeckLink ();
+
+ /// open video/image file
+ virtual void openFile(char *file);
+ /// open video capture device
+ virtual void openCam(char *driver, short camIdx);
+
+ /// release video source
+ virtual bool release (void);
+ /// overwrite base refresh to handle fixed image
+ virtual void refresh(void);
+ /// play video
+ virtual bool play (void);
+ /// pause video
+ virtual bool pause (void);
+ /// stop video
+ virtual bool stop (void);
+ /// set play range
+ virtual void setRange (double start, double stop);
+ /// set frame rate
+ virtual void setFrameRate (float rate);
+
+protected:
+ // format and codec information
+ /// image calculation
+ virtual void calcImage (unsigned int texId, double ts);
+
+private:
+ void VideoFrameArrived(IDeckLinkVideoInputFrame* inputFrame);
+ void LockCache()
+ {
+ pthread_mutex_lock(&mCacheMutex);
+ }
+ void UnlockCache()
+ {
+ pthread_mutex_unlock(&mCacheMutex);
+ }
+
+ IDeckLinkInput* mDLInput;
+ BMDDisplayMode mDisplayMode;
+ BMDPixelFormat mPixelFormat;
+ bool mUse3D;
+ uint32_t mFrameWidth;
+ uint32_t mFrameHeight;
+ TextureDesc mTextureDesc;
+ PinnedMemoryAllocator* mpAllocator;
+ CaptureDelegate* mpCaptureDelegate;
+
+ // cache frame in transit between the callback thread and the main BGE thread
+ // keep only one frame in cache because we just want to keep up with real time
+ pthread_mutex_t mCacheMutex;
+ IDeckLinkVideoInputFrame* mpCacheFrame;
+ bool mClosing;
+
+};
+
+inline VideoDeckLink *getDeckLink(PyImage *self)
+{
+ return static_cast<VideoDeckLink*>(self->m_image);
+}
+
+////////////////////////////////////////////
+// TextureTransfer : Abstract class to perform a transfer to GPU memory using fast transfer if available
+////////////////////////////////////////////
+class TextureTransfer
+{
+public:
+ TextureTransfer() {}
+ virtual ~TextureTransfer() { }
+
+ virtual void PerformTransfer() = 0;
+protected:
+ static bool _PinBuffer(void *address, uint32_t size);
+ static void _UnpinBuffer(void* address, uint32_t size);
+};
+
+////////////////////////////////////////////
+// PinnedMemoryAllocator
+////////////////////////////////////////////
+
+// PinnedMemoryAllocator implements the IDeckLinkMemoryAllocator interface and can be used instead of the
+// built-in frame allocator, by setting with SetVideoInputFrameMemoryAllocator() or SetVideoOutputFrameMemoryAllocator().
+//
+// For this sample application a custom frame memory allocator is used to ensure each address
+// of frame memory is aligned on a 4kB boundary required by the OpenGL pinned memory extension.
+// If the pinned memory extension is not available, this allocator will still be used and
+// demonstrates how to cache frame allocations for efficiency.
+//
+// The frame cache delays the releasing of buffers until the cache fills up, thereby avoiding an
+// allocate plus pin operation for every frame, followed by an unpin and deallocate on every frame.
+
+
+class PinnedMemoryAllocator : public IDeckLinkMemoryAllocator
+{
+public:
+ PinnedMemoryAllocator(unsigned cacheSize, size_t memSize);
+ virtual ~PinnedMemoryAllocator();
+
+ void TransferBuffer(void* address, TextureDesc* texDesc, GLuint texId);
+
+ // IUnknown methods
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv);
+ virtual ULONG STDMETHODCALLTYPE AddRef(void);
+ virtual ULONG STDMETHODCALLTYPE Release(void);
+
+ // IDeckLinkMemoryAllocator methods
+ virtual HRESULT STDMETHODCALLTYPE AllocateBuffer(dl_size_t bufferSize, void* *allocatedBuffer);
+ virtual HRESULT STDMETHODCALLTYPE ReleaseBuffer(void* buffer);
+ virtual HRESULT STDMETHODCALLTYPE Commit();
+ virtual HRESULT STDMETHODCALLTYPE Decommit();
+
+private:
+ static bool mGPUDirectInitialized;
+ static bool mHasDvp;
+ static bool mHasAMDPinnedMemory;
+ static size_t mReservedProcessMemory;
+ static bool ReserveMemory(size_t size);
+
+ void Lock()
+ {
+ pthread_mutex_lock(&mMutex);
+ }
+ void Unlock()
+ {
+ pthread_mutex_unlock(&mMutex);
+ }
+ HRESULT _ReleaseBuffer(void* buffer);
+
+ uint32_t mRefCount;
+ // protect the cache and the allocated map,
+ // not the pinnedBuffer map as it is only used from main thread
+ pthread_mutex_t mMutex;
+ std::map<void*, uint32_t> mAllocatedSize;
+ std::vector<void*> mBufferCache;
+ std::map<void *, TextureTransfer*> mPinnedBuffer;
+#ifdef WIN32
+ DVPBufferHandle mDvpCaptureTextureHandle;
+#endif
+ // target texture in GPU
+ GLuint mTexId;
+ uint32_t mBufferCacheSize;
+};
+
+////////////////////////////////////////////
+// Capture Delegate Class
+////////////////////////////////////////////
+
+class CaptureDelegate : public IDeckLinkInputCallback
+{
+ VideoDeckLink* mpOwner;
+
+public:
+ CaptureDelegate(VideoDeckLink* pOwner);
+
+ // IUnknown needs only a dummy implementation
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) { return E_NOINTERFACE; }
+ virtual ULONG STDMETHODCALLTYPE AddRef() { return 1; }
+ virtual ULONG STDMETHODCALLTYPE Release() { return 1; }
+
+ virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(IDeckLinkVideoInputFrame *videoFrame, IDeckLinkAudioInputPacket *audioPacket);
+ virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(BMDVideoInputFormatChangedEvents notificationEvents, IDeckLinkDisplayMode *newDisplayMode, BMDDetectedVideoInputFormatFlags detectedSignalFlags);
+};
+
+
+#endif /* WITH_GAMEENGINE_DECKLINK */
+
+#endif /* __VIDEODECKLINK_H__ */
diff --git a/source/gameengine/VideoTexture/VideoFFmpeg.cpp b/source/gameengine/VideoTexture/VideoFFmpeg.cpp
index 5fed1211d6c..083e9e28502 100644
--- a/source/gameengine/VideoTexture/VideoFFmpeg.cpp
+++ b/source/gameengine/VideoTexture/VideoFFmpeg.cpp
@@ -1203,7 +1203,7 @@ static PyMethodDef videoMethods[] =
{"play", (PyCFunction)Video_play, METH_NOARGS, "Play (restart) video"},
{"pause", (PyCFunction)Video_pause, METH_NOARGS, "pause video"},
{"stop", (PyCFunction)Video_stop, METH_NOARGS, "stop video (play will replay it from start)"},
- {"refresh", (PyCFunction)Video_refresh, METH_NOARGS, "Refresh video - get its status"},
+ {"refresh", (PyCFunction)Video_refresh, METH_VARARGS, "Refresh video - get its status"},
{NULL}
};
// attributes structure
@@ -1326,7 +1326,7 @@ static PyObject *Image_reload(PyImage *self, PyObject *args)
// methods structure
static PyMethodDef imageMethods[] =
{ // methods from VideoBase class
- {"refresh", (PyCFunction)Video_refresh, METH_NOARGS, "Refresh image, i.e. load it"},
+ {"refresh", (PyCFunction)Video_refresh, METH_VARARGS, "Refresh image, i.e. load it"},
{"reload", (PyCFunction)Image_reload, METH_VARARGS, "Reload image, i.e. reopen it"},
{NULL}
};
diff --git a/source/gameengine/VideoTexture/blendVideoTex.cpp b/source/gameengine/VideoTexture/blendVideoTex.cpp
index a62ffee3137..9b046d46412 100644
--- a/source/gameengine/VideoTexture/blendVideoTex.cpp
+++ b/source/gameengine/VideoTexture/blendVideoTex.cpp
@@ -128,6 +128,10 @@ static PyMethodDef moduleMethods[] =
extern PyTypeObject VideoFFmpegType;
extern PyTypeObject ImageFFmpegType;
#endif
+#ifdef WITH_GAMEENGINE_DECKLINK
+extern PyTypeObject VideoDeckLinkType;
+extern PyTypeObject DeckLinkType;
+#endif
extern PyTypeObject FilterBlueScreenType;
extern PyTypeObject FilterGrayType;
extern PyTypeObject FilterColorType;
@@ -145,6 +149,9 @@ static void registerAllTypes(void)
pyImageTypes.add(&VideoFFmpegType, "VideoFFmpeg");
pyImageTypes.add(&ImageFFmpegType, "ImageFFmpeg");
#endif
+#ifdef WITH_GAMEENGINE_DECKLINK
+ pyImageTypes.add(&VideoDeckLinkType, "VideoDeckLink");
+#endif
pyImageTypes.add(&ImageBuffType, "ImageBuff");
pyImageTypes.add(&ImageMixType, "ImageMix");
pyImageTypes.add(&ImageRenderType, "ImageRender");
@@ -194,6 +201,10 @@ PyMODINIT_FUNC initVideoTexturePythonBinding(void)
return NULL;
if (PyType_Ready(&TextureType) < 0)
return NULL;
+#ifdef WITH_GAMEENGINE_DECKLINK
+ if (PyType_Ready(&DeckLinkType) < 0)
+ return NULL;
+#endif
m = PyModule_Create(&VideoTexture_module_def);
PyDict_SetItemString(PySys_GetObject("modules"), VideoTexture_module_def.m_name, m);
@@ -207,6 +218,10 @@ PyMODINIT_FUNC initVideoTexturePythonBinding(void)
Py_INCREF(&TextureType);
PyModule_AddObject(m, "Texture", (PyObject *)&TextureType);
+#ifdef WITH_GAMEENGINE_DECKLINK
+ Py_INCREF(&DeckLinkType);
+ PyModule_AddObject(m, "DeckLink", (PyObject *)&DeckLinkType);
+#endif
PyModule_AddIntConstant(m, "SOURCE_ERROR", SourceError);
PyModule_AddIntConstant(m, "SOURCE_EMPTY", SourceEmpty);
PyModule_AddIntConstant(m, "SOURCE_READY", SourceReady);
diff --git a/source/tools b/source/tools
new file mode 160000
+Subproject 896c5f78952adb2d091d28c65086d46992dabda
diff --git a/tests/gtests/blenlib/BLI_array_store_test.cc b/tests/gtests/blenlib/BLI_array_store_test.cc
new file mode 100644
index 00000000000..b71dc4575f1
--- /dev/null
+++ b/tests/gtests/blenlib/BLI_array_store_test.cc
@@ -0,0 +1,806 @@
+/* Apache License, Version 2.0 */
+
+#include "testing/testing.h"
+
+extern "C" {
+#include "BLI_array_store.h"
+
+#include "MEM_guardedalloc.h"
+#include "BLI_sys_types.h"
+#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+#include "BLI_array_utils.h"
+#include "BLI_string.h"
+#include "BLI_rand.h"
+#include "BLI_ressource_strings.h"
+}
+
+/* print memory savings */
+// #define DEBUG_PRINT
+
+
+/* -------------------------------------------------------------------- */
+/* Helper functions */
+
+#ifdef DEBUG_PRINT
+static void print_mem_saved(const char *id, const BArrayStore *bs)
+{
+ const double size_real = BLI_array_store_calc_size_compacted_get(bs);
+ const double size_expand = BLI_array_store_calc_size_expanded_get(bs);
+ const double percent = size_expand ? ((size_real / size_expand) * 100.0) : -1.0;
+ printf("%s: %.8f%%\n", id, percent);
+}
+#endif
+
+
+/* -------------------------------------------------------------------- */
+/* Test Chunks (building data from list of chunks) */
+
+typedef struct TestChunnk {
+ struct TestChunnk *next, *prev;
+ const void *data;
+ size_t data_len;
+} TestChunnk;
+
+static TestChunnk *testchunk_list_add(ListBase *lb, const void *data, size_t data_len)
+{
+ TestChunnk *tc = (TestChunnk *)MEM_mallocN(sizeof(*tc), __func__);
+ tc->data = data;
+ tc->data_len = data_len;
+ BLI_addtail(lb, tc);
+
+ return tc;
+}
+
+#if 0
+static TestChunnk *testchunk_list_add_copydata(ListBase *lb, const void *data, size_t data_len)
+{
+ void *data_copy = MEM_mallocN(data_len, __func__);
+ memcpy(data_copy, data, data_len);
+ return testchunk_list_add(lb, data_copy, data_len);
+}
+#endif
+
+static void testchunk_list_free(ListBase *lb)
+{
+ for (TestChunnk *tc = (TestChunnk *)lb->first, *tb_next; tc; tc = tb_next) {
+ tb_next = tc->next;
+ MEM_freeN((void *)tc->data);
+ MEM_freeN(tc);
+ }
+ BLI_listbase_clear(lb);
+}
+
+#if 0
+static char *testchunk_as_data(
+ ListBase *lb,
+ size_t *r_data_len)
+{
+ size_t data_len = 0;
+ for (TestChunnk *tc = (TestChunnk *)lb->first; tc; tc = tc->next) {
+ data_len += tc->data_len;
+ }
+ char *data = (char *)MEM_mallocN(data_len, __func__);
+ size_t i = 0;
+ for (TestChunnk *tc = (TestChunnk *)lb->first; tc; tc = tc->next) {
+ memcpy(&data[i], tc->data, tc->data_len);
+ data_len += tc->data_len;
+ i += tc->data_len;
+ }
+ if (r_data_len) {
+ *r_data_len = i;
+ }
+ return data;
+}
+#endif
+
+static char *testchunk_as_data_array(
+ TestChunnk **tc_array, int tc_array_len,
+ size_t *r_data_len)
+{
+ size_t data_len = 0;
+ for (int tc_index = 0; tc_index < tc_array_len; tc_index++) {
+ data_len += tc_array[tc_index]->data_len;
+ }
+ char *data = (char *)MEM_mallocN(data_len, __func__);
+ size_t i = 0;
+ for (int tc_index = 0; tc_index < tc_array_len; tc_index++) {
+ TestChunnk *tc = tc_array[tc_index];
+ memcpy(&data[i], tc->data, tc->data_len);
+ i += tc->data_len;
+ }
+ if (r_data_len) {
+ *r_data_len = i;
+ }
+ return data;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* Test Buffer */
+
+/* API to handle local allocation of data so we can compare it with the data in the array_store */
+typedef struct TestBuffer {
+ struct TestBuffer *next, *prev;
+ const void *data;
+ size_t data_len;
+
+ /* for reference */
+ BArrayState *state;
+} TestBuffer;
+
+static TestBuffer *testbuffer_list_add(ListBase *lb, const void *data, size_t data_len)
+{
+ TestBuffer *tb = (TestBuffer *)MEM_mallocN(sizeof(*tb), __func__);
+ tb->data = data;
+ tb->data_len = data_len;
+ tb->state = NULL;
+ BLI_addtail(lb, tb);
+ return tb;
+}
+
+static TestBuffer *testbuffer_list_add_copydata(ListBase *lb, const void *data, size_t data_len)
+{
+ void *data_copy = MEM_mallocN(data_len, __func__);
+ memcpy(data_copy, data, data_len);
+ return testbuffer_list_add(lb, data_copy, data_len);
+}
+
+static void testbuffer_list_state_from_data(
+ ListBase *lb,
+ const char *data, const size_t data_len)
+{
+ testbuffer_list_add_copydata(lb, (const void *)data, data_len);
+}
+
+/**
+ * A version of testbuffer_list_state_from_data that expand data by stride,
+ * handy so we can test data at different strides.
+ */
+static void testbuffer_list_state_from_data__stride_expand(
+ ListBase *lb,
+ const char *data, const size_t data_len,
+ const size_t stride)
+{
+ if (stride == 1) {
+ testbuffer_list_state_from_data(lb, data, data_len);
+ }
+ else {
+ const size_t data_stride_len = data_len * stride;
+ char *data_stride = (char *)MEM_mallocN(data_stride_len, __func__);
+
+ for (size_t i = 0, i_stride = 0; i < data_len; i += 1, i_stride += stride) {
+ memset(&data_stride[i_stride], data[i], stride);
+ }
+
+ testbuffer_list_add(lb, (const void *)data_stride, data_stride_len);
+ }
+}
+
+#define testbuffer_list_state_from_string_array(lb, data_array) \
+{ \
+ unsigned int i_ = 0; \
+ const char *data; \
+ while ((data = data_array[i_++])) { \
+ testbuffer_list_state_from_data(lb, data, strlen(data)); \
+ } \
+} ((void)0)
+
+//
+
+#define TESTBUFFER_STRINGS_CREATE(lb, ...) \
+{ \
+ BLI_listbase_clear(lb); \
+ const char *data_array[] = {__VA_ARGS__ NULL}; \
+ testbuffer_list_state_from_string_array((lb), data_array); \
+} ((void)0)
+
+/* test in both directions */
+#define TESTBUFFER_STRINGS_EX(bs, ...) \
+{ \
+ ListBase lb; \
+ TESTBUFFER_STRINGS_CREATE(&lb, __VA_ARGS__); \
+ \
+ testbuffer_run_tests(bs, &lb); \
+ \
+ testbuffer_list_free(&lb); \
+} ((void)0)
+
+#define TESTBUFFER_STRINGS(stride, chunk_count, ...) \
+{ \
+ ListBase lb; \
+ TESTBUFFER_STRINGS_CREATE(&lb, __VA_ARGS__); \
+ \
+ testbuffer_run_tests_simple(&lb, stride, chunk_count); \
+ \
+ testbuffer_list_free(&lb); \
+} ((void)0)
+
+static bool testbuffer_item_validate(TestBuffer *tb)
+{
+ size_t data_state_len;
+ bool ok = true;
+ void *data_state = BLI_array_store_state_data_get_alloc(tb->state, &data_state_len);
+ if (tb->data_len != data_state_len) {
+ ok = false;
+ }
+ else if (memcmp(data_state, tb->data, data_state_len) != 0) {
+ ok = false;
+ }
+ MEM_freeN(data_state);
+ return ok;
+}
+
+static bool testbuffer_list_validate(const ListBase *lb)
+{
+ for (TestBuffer *tb = (TestBuffer *)lb->first; tb; tb = tb->next) {
+ if (!testbuffer_item_validate(tb)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void testbuffer_list_data_randomize(ListBase *lb, unsigned int random_seed)
+{
+ for (TestBuffer *tb = (TestBuffer *)lb->first; tb; tb = tb->next) {
+ BLI_array_randomize((void *)tb->data, 1, tb->data_len, random_seed++);
+ }
+}
+
+static void testbuffer_list_store_populate(
+ BArrayStore *bs, ListBase *lb)
+{
+ for (TestBuffer *tb = (TestBuffer *)lb->first, *tb_prev = NULL; tb; tb_prev = tb, tb = tb->next) {
+ tb->state = BLI_array_store_state_add(bs, tb->data, tb->data_len, (tb_prev ? tb_prev->state : NULL));
+ }
+}
+
+static void testbuffer_list_store_clear(
+ BArrayStore *bs, ListBase *lb)
+{
+ for (TestBuffer *tb = (TestBuffer *)lb->first; tb; tb = tb->next) {
+ BLI_array_store_state_remove(bs, tb->state);
+ tb->state = NULL;
+ }
+}
+
+static void testbuffer_list_free(ListBase *lb)
+{
+ for (TestBuffer *tb = (TestBuffer *)lb->first, *tb_next; tb; tb = tb_next) {
+ tb_next = tb->next;
+ MEM_freeN((void *)tb->data);
+ MEM_freeN(tb);
+ }
+ BLI_listbase_clear(lb);
+}
+
+static void testbuffer_run_tests_single(
+ BArrayStore *bs, ListBase *lb)
+{
+ testbuffer_list_store_populate(bs, lb);
+ EXPECT_EQ(true, testbuffer_list_validate(lb));
+ EXPECT_EQ(true, BLI_array_store_is_valid(bs));
+#ifdef DEBUG_PRINT
+ print_mem_saved("data", bs);
+#endif
+}
+
+/* avoid copy-paste code to run tests */
+static void testbuffer_run_tests(
+ BArrayStore *bs, ListBase *lb)
+{
+ /* forwards */
+ testbuffer_run_tests_single(bs, lb);
+ testbuffer_list_store_clear(bs, lb);
+
+ BLI_listbase_reverse(lb);
+
+ /* backwards */
+ testbuffer_run_tests_single(bs, lb);
+ testbuffer_list_store_clear(bs, lb);
+}
+
+static void testbuffer_run_tests_simple(
+ ListBase *lb,
+ const int stride, const int chunk_count)
+{
+ BArrayStore *bs = BLI_array_store_create(stride, chunk_count);
+ testbuffer_run_tests(bs, lb);
+ BLI_array_store_destroy(bs);
+}
+
+
+/* -------------------------------------------------------------------- */
+/* Basic Tests */
+
+TEST(array_store, Nop)
+{
+ BArrayStore *bs = BLI_array_store_create(1, 32);
+ BLI_array_store_destroy(bs);
+}
+
+TEST(array_store, NopState)
+{
+ BArrayStore *bs = BLI_array_store_create(1, 32);
+ const unsigned char data[] = "test";
+ BArrayState *state = BLI_array_store_state_add(bs, data, sizeof(data) - 1, NULL);
+ EXPECT_EQ(sizeof(data) - 1, BLI_array_store_state_size_get(state));
+ BLI_array_store_state_remove(bs, state);
+ BLI_array_store_destroy(bs);
+}
+
+TEST(array_store, Single)
+{
+ BArrayStore *bs = BLI_array_store_create(1, 32);
+ const char data_src[] = "test";
+ const char *data_dst;
+ BArrayState *state = BLI_array_store_state_add(bs, data_src, sizeof(data_src), NULL);
+ size_t data_dst_len;
+ data_dst = (char *)BLI_array_store_state_data_get_alloc(state, &data_dst_len);
+ EXPECT_STREQ(data_src, data_dst);
+ EXPECT_EQ(sizeof(data_src), data_dst_len);
+ BLI_array_store_destroy(bs);
+ MEM_freeN((void *)data_dst);
+}
+
+TEST(array_store, DoubleNop)
+{
+ BArrayStore *bs = BLI_array_store_create(1, 32);
+ const char data_src[] = "test";
+ const char *data_dst;
+
+ BArrayState *state_a = BLI_array_store_state_add(bs, data_src, sizeof(data_src), NULL);
+ BArrayState *state_b = BLI_array_store_state_add(bs, data_src, sizeof(data_src), state_a);
+
+ EXPECT_EQ(sizeof(data_src), BLI_array_store_calc_size_compacted_get(bs));
+ EXPECT_EQ(sizeof(data_src) * 2, BLI_array_store_calc_size_expanded_get(bs));
+
+ size_t data_dst_len;
+
+ data_dst = (char *)BLI_array_store_state_data_get_alloc(state_a, &data_dst_len);
+ EXPECT_STREQ(data_src, data_dst);
+ MEM_freeN((void *)data_dst);
+
+ data_dst = (char *)BLI_array_store_state_data_get_alloc(state_b, &data_dst_len);
+ EXPECT_STREQ(data_src, data_dst);
+ MEM_freeN((void *)data_dst);
+
+ EXPECT_EQ(sizeof(data_src), data_dst_len);
+ BLI_array_store_destroy(bs);
+}
+
+TEST(array_store, DoubleDiff)
+{
+ BArrayStore *bs = BLI_array_store_create(1, 32);
+ const char data_src_a[] = "test";
+ const char data_src_b[] = "####";
+ const char *data_dst;
+
+ BArrayState *state_a = BLI_array_store_state_add(bs, data_src_a, sizeof(data_src_a), NULL);
+ BArrayState *state_b = BLI_array_store_state_add(bs, data_src_b, sizeof(data_src_b), state_a);
+ size_t data_dst_len;
+
+ EXPECT_EQ(sizeof(data_src_a) * 2, BLI_array_store_calc_size_compacted_get(bs));
+ EXPECT_EQ(sizeof(data_src_a) * 2, BLI_array_store_calc_size_expanded_get(bs));
+
+ data_dst = (char *)BLI_array_store_state_data_get_alloc(state_a, &data_dst_len);
+ EXPECT_STREQ(data_src_a, data_dst);
+ MEM_freeN((void *)data_dst);
+
+ data_dst = (char *)BLI_array_store_state_data_get_alloc(state_b, &data_dst_len);
+ EXPECT_STREQ(data_src_b, data_dst);
+ MEM_freeN((void *)data_dst);
+
+ BLI_array_store_destroy(bs);
+}
+
+TEST(array_store, TextMixed)
+{
+ TESTBUFFER_STRINGS(1, 4, "",);
+ TESTBUFFER_STRINGS(1, 4, "test",);
+ TESTBUFFER_STRINGS(1, 4, "", "test",);
+ TESTBUFFER_STRINGS(1, 4, "test", "",);
+ TESTBUFFER_STRINGS(1, 4, "test", "", "test",);
+ TESTBUFFER_STRINGS(1, 4, "", "test", "",);
+}
+
+TEST(array_store, TextDupeIncreaseDecrease)
+{
+ ListBase lb;
+
+#define D "#1#2#3#4"
+ TESTBUFFER_STRINGS_CREATE(
+ &lb,
+ D,
+ D D,
+ D D D,
+ D D D D,
+ );
+
+ BArrayStore *bs = BLI_array_store_create(1, 8);
+
+ /* forward */
+ testbuffer_list_store_populate(bs, &lb);
+ EXPECT_EQ(true, testbuffer_list_validate(&lb));
+ EXPECT_EQ(true, BLI_array_store_is_valid(bs));
+ EXPECT_EQ(strlen(D), BLI_array_store_calc_size_compacted_get(bs));
+
+ testbuffer_list_store_clear(bs, &lb);
+ BLI_listbase_reverse(&lb);
+
+ /* backwards */
+ testbuffer_list_store_populate(bs, &lb);
+ EXPECT_EQ(true, testbuffer_list_validate(&lb));
+ EXPECT_EQ(true, BLI_array_store_is_valid(bs));
+ /* larger since first block doesn't de-duplicate */
+ EXPECT_EQ(strlen(D) * 4, BLI_array_store_calc_size_compacted_get(bs));
+
+#undef D
+ testbuffer_list_free(&lb); \
+
+ BLI_array_store_destroy(bs);
+}
+
+
+/* -------------------------------------------------------------------- */
+/* Plain Text Tests */
+
+/**
+ * Test that uses text input with different params for the array-store
+ * to ensure no corner cases fail.
+ */
+static void plain_text_helper(
+ const char *words, int words_len, const char word_delim,
+ const int stride, const int chunk_count, const int random_seed)
+{
+
+ ListBase lb;
+ BLI_listbase_clear(&lb);
+
+ for (int i = 0, i_prev = 0; i < words_len; i++) {
+ if (ELEM(words[i], word_delim, '\0')) {
+ if (i != i_prev) {
+ testbuffer_list_state_from_data__stride_expand(&lb, &words[i_prev], i - i_prev, stride);
+ }
+ i_prev = i;
+ }
+ }
+
+ if (random_seed) {
+ testbuffer_list_data_randomize(&lb, random_seed);
+ }
+
+ testbuffer_run_tests_simple(&lb, stride, chunk_count);
+
+ testbuffer_list_free(&lb);
+}
+
+/* split by '.' (multiple words) */
+#define WORDS words10k, sizeof(words10k)
+TEST(array_store, TextSentences_Chunk1) { plain_text_helper(WORDS, '.', 1, 1, 0); }
+TEST(array_store, TextSentences_Chunk2) { plain_text_helper(WORDS, '.', 1, 2, 0); }
+TEST(array_store, TextSentences_Chunk8) { plain_text_helper(WORDS, '.', 1, 8, 0); }
+TEST(array_store, TextSentences_Chunk32) { plain_text_helper(WORDS, '.', 1, 32, 0); }
+TEST(array_store, TextSentences_Chunk128) { plain_text_helper(WORDS, '.', 1, 128, 0); }
+TEST(array_store, TextSentences_Chunk1024) { plain_text_helper(WORDS, '.', 1, 1024, 0); }
+/* odd numbers */
+TEST(array_store, TextSentences_Chunk3) { plain_text_helper(WORDS, '.', 1, 3, 0); }
+TEST(array_store, TextSentences_Chunk13) { plain_text_helper(WORDS, '.', 1, 13, 0); }
+TEST(array_store, TextSentences_Chunk131) { plain_text_helper(WORDS, '.', 1, 131, 0); }
+
+/* split by ' ', individual words */
+TEST(array_store, TextWords_Chunk1) { plain_text_helper(WORDS, ' ', 1, 1, 0); }
+TEST(array_store, TextWords_Chunk2) { plain_text_helper(WORDS, ' ', 1, 2, 0); }
+TEST(array_store, TextWords_Chunk8) { plain_text_helper(WORDS, ' ', 1, 8, 0); }
+TEST(array_store, TextWords_Chunk32) { plain_text_helper(WORDS, ' ', 1, 32, 0); }
+TEST(array_store, TextWords_Chunk128) { plain_text_helper(WORDS, ' ', 1, 128, 0); }
+TEST(array_store, TextWords_Chunk1024) { plain_text_helper(WORDS, ' ', 1, 1024, 0); }
+/* odd numbers */
+TEST(array_store, TextWords_Chunk3) { plain_text_helper(WORDS, ' ', 1, 3, 0); }
+TEST(array_store, TextWords_Chunk13) { plain_text_helper(WORDS, ' ', 1, 13, 0); }
+TEST(array_store, TextWords_Chunk131) { plain_text_helper(WORDS, ' ', 1, 131, 0); }
+
+/* various tests with different strides & randomizing */
+TEST(array_store, TextSentencesRandom_Stride3_Chunk3) { plain_text_helper(WORDS, 'q', 3, 3, 7337); }
+TEST(array_store, TextSentencesRandom_Stride8_Chunk8) { plain_text_helper(WORDS, 'n', 8, 8, 5667); }
+TEST(array_store, TextSentencesRandom_Stride32_Chunk1) { plain_text_helper(WORDS, 'a', 1, 32, 1212); }
+TEST(array_store, TextSentencesRandom_Stride12_Chunk512) { plain_text_helper(WORDS, 'g', 12, 512, 9999); }
+TEST(array_store, TextSentencesRandom_Stride128_Chunk6) { plain_text_helper(WORDS, 'b', 20, 6, 1000); }
+
+#undef WORDS
+
+
+/* -------------------------------------------------------------------- */
+/* Random Data Tests */
+
+static unsigned int rand_range_i(RNG *rng, unsigned int min_i, unsigned int max_i, unsigned int step)
+{
+ if (min_i == max_i) {
+ return min_i;
+ }
+ BLI_assert(min_i <= max_i);
+ BLI_assert(((min_i % step) == 0) && ((max_i % step) == 0));
+ unsigned int range = (max_i - min_i);
+ unsigned int value = BLI_rng_get_uint(rng) % range;
+ value = (value / step) * step;
+ return min_i + value;
+}
+
+static void testbuffer_list_state_random_data(
+ ListBase *lb,
+ const size_t stride,
+ const size_t data_min_len, const size_t data_max_len,
+
+ const unsigned int mutate, RNG *rng)
+{
+ size_t data_len = rand_range_i(rng, data_min_len, data_max_len + stride, stride);
+ char *data = (char *)MEM_mallocN(data_len, __func__);
+
+ if (lb->last == NULL) {
+ BLI_rng_get_char_n(rng, data, data_len);
+ }
+ else {
+ TestBuffer *tb_last = (TestBuffer *)lb->last;
+ if (tb_last->data_len >= data_len) {
+ memcpy(data, tb_last->data, data_len);
+ }
+ else {
+ memcpy(data, tb_last->data, tb_last->data_len);
+ BLI_rng_get_char_n(rng, &data[tb_last->data_len], data_len - tb_last->data_len);
+ }
+
+ /* perform multiple small mutations to the array. */
+ for (int i = 0; i < mutate; i++) {
+ enum {
+ MUTATE_NOP = 0,
+ MUTATE_ADD,
+ MUTATE_REMOVE,
+ MUTATE_ROTATE,
+ MUTATE_RANDOMIZE,
+ MUTATE_TOTAL,
+ };
+
+ switch ((BLI_rng_get_uint(rng) % MUTATE_TOTAL)) {
+ case MUTATE_NOP:
+ {
+ break;
+ }
+ case MUTATE_ADD:
+ {
+ const unsigned int offset = rand_range_i(rng, 0, data_len, stride);
+ if (data_len < data_max_len) {
+ data_len += stride;
+ data = (char *)MEM_reallocN((void *)data, data_len);
+ memmove(&data[offset + stride], &data[offset], data_len - (offset + stride));
+ BLI_rng_get_char_n(rng, &data[offset], stride);
+ }
+ break;
+ }
+ case MUTATE_REMOVE:
+ {
+ const unsigned int offset = rand_range_i(rng, 0, data_len, stride);
+ if (data_len > data_min_len) {
+ memmove(&data[offset], &data[offset + stride], data_len - (offset + stride));
+ data_len -= stride;
+ }
+ break;
+ }
+ case MUTATE_ROTATE:
+ {
+ int items = data_len / stride;
+ if (items > 1) {
+ _bli_array_wrap(data, items, stride, (BLI_rng_get_uint(rng) % 2) ? -1 : 1);
+ }
+ break;
+ }
+ case MUTATE_RANDOMIZE:
+ {
+ if (data_len > 0) {
+ const unsigned int offset = rand_range_i(rng, 0, data_len - stride, stride);
+ BLI_rng_get_char_n(rng, &data[offset], stride);
+ }
+ break;
+ }
+ default:
+ BLI_assert(0);
+ }
+ }
+ }
+
+ testbuffer_list_add(lb, (const void *)data, data_len);
+}
+
+static void random_data_mutate_helper(
+ const int items_size_min, const int items_size_max, const int items_total,
+ const int stride, const int chunk_count,
+ const int random_seed, const int mutate)
+{
+
+
+ ListBase lb;
+ BLI_listbase_clear(&lb);
+
+ const size_t data_min_len = items_size_min * stride;
+ const size_t data_max_len = items_size_max * stride;
+
+ {
+ RNG *rng = BLI_rng_new(random_seed);
+ for (int i = 0; i < items_total; i++) {
+ testbuffer_list_state_random_data(&lb, stride, data_min_len, data_max_len, mutate, rng);
+ }
+ BLI_rng_free(rng);
+ }
+
+ testbuffer_run_tests_simple(&lb, stride, chunk_count);
+
+ testbuffer_list_free(&lb);
+}
+
+TEST(array_store, TestData_Stride1_Chunk32_Mutate2) { random_data_mutate_helper(0, 100, 400, 1, 32, 9779, 2); }
+TEST(array_store, TestData_Stride8_Chunk512_Mutate2) { random_data_mutate_helper(0, 128, 400, 8, 512, 1001, 2); }
+TEST(array_store, TestData_Stride12_Chunk48_Mutate2) { random_data_mutate_helper(200, 256, 400, 12, 48, 1331, 2); }
+TEST(array_store, TestData_Stride32_Chunk64_Mutate1) { random_data_mutate_helper(0, 256, 200, 32, 64, 3112, 1); }
+TEST(array_store, TestData_Stride32_Chunk64_Mutate8) { random_data_mutate_helper(0, 256, 200, 32, 64, 7117, 8); }
+
+
+/* -------------------------------------------------------------------- */
+/* Randomized Chunks Test */
+
+static void random_chunk_generate(
+ ListBase *lb,
+ const int chunks_per_buffer,
+ const int stride, const int chunk_count,
+ const int random_seed)
+{
+ RNG *rng = BLI_rng_new(random_seed);
+ const size_t chunk_size_bytes = stride * chunk_count;
+ for (int i = 0; i < chunks_per_buffer; i++) {
+ char *data_chunk = (char *)MEM_mallocN(chunk_size_bytes, __func__);
+ BLI_rng_get_char_n(rng, data_chunk, chunk_size_bytes);
+ testchunk_list_add(lb, data_chunk, chunk_size_bytes);
+ }
+ BLI_rng_free(rng);
+}
+
+/**
+ * Add random chunks, then re-order them to ensure chunk de-duplication is working.
+ */
+static void random_chunk_mutate_helper(
+ const int chunks_per_buffer, const int items_total,
+ const int stride, const int chunk_count,
+ const int random_seed)
+{
+ /* generate random chunks */
+
+ ListBase random_chunks;
+ BLI_listbase_clear(&random_chunks);
+ random_chunk_generate(&random_chunks, chunks_per_buffer, stride, chunk_count, random_seed);
+ TestChunnk **chunks_array = (TestChunnk **)MEM_mallocN(chunks_per_buffer * sizeof(TestChunnk *), __func__);
+ {
+ TestChunnk *tc = (TestChunnk *)random_chunks.first;
+ for (int i = 0; i < chunks_per_buffer; i++, tc = tc->next) {
+ chunks_array[i] = tc;
+ }
+ }
+
+ /* add and re-order each time */
+ ListBase lb;
+ BLI_listbase_clear(&lb);
+
+ {
+ RNG *rng = BLI_rng_new(random_seed);
+ for (int i = 0; i < items_total; i++) {
+ BLI_rng_shuffle_array(rng, chunks_array, sizeof(TestChunnk *), chunks_per_buffer);
+ size_t data_len;
+ char *data = testchunk_as_data_array(chunks_array, chunks_per_buffer, &data_len);
+ BLI_assert(data_len == chunks_per_buffer * chunk_count * stride);
+ testbuffer_list_add(&lb, (const void *)data, data_len);
+ }
+ BLI_rng_free(rng);
+ }
+
+ testchunk_list_free(&random_chunks);
+ MEM_freeN(chunks_array);
+
+ BArrayStore *bs = BLI_array_store_create(stride, chunk_count);
+ testbuffer_run_tests_single(bs, &lb);
+
+ size_t expected_size = chunks_per_buffer * chunk_count * stride;
+ EXPECT_EQ(expected_size, BLI_array_store_calc_size_compacted_get(bs));
+
+ BLI_array_store_destroy(bs);
+
+ testbuffer_list_free(&lb);
+
+}
+
+TEST(array_store, TestChunk_Rand8_Stride1_Chunk64) { random_chunk_mutate_helper(8, 100, 1, 64, 9779); }
+TEST(array_store, TestChunk_Rand32_Stride1_Chunk64) { random_chunk_mutate_helper(32, 100, 1, 64, 1331); }
+TEST(array_store, TestChunk_Rand64_Stride8_Chunk32) { random_chunk_mutate_helper(64, 100, 8, 32, 2772); }
+TEST(array_store, TestChunk_Rand31_Stride11_Chunk21) { random_chunk_mutate_helper(31, 100, 11, 21, 7117); }
+
+
+#if 0
+/* -------------------------------------------------------------------- */
+
+/* Test From Files (disabled, keep for local tests.) */
+
+void *file_read_binary_as_mem(const char *filepath, size_t pad_bytes, size_t *r_size)
+{
+ FILE *fp = fopen(filepath, "rb");
+ void *mem = NULL;
+
+ if (fp) {
+ long int filelen_read;
+ fseek(fp, 0L, SEEK_END);
+ const long int filelen = ftell(fp);
+ if (filelen == -1) {
+ goto finally;
+ }
+ fseek(fp, 0L, SEEK_SET);
+
+ mem = MEM_mallocN(filelen + pad_bytes, __func__);
+ if (mem == NULL) {
+ goto finally;
+ }
+
+ filelen_read = fread(mem, 1, filelen, fp);
+ if ((filelen_read != filelen) || ferror(fp)) {
+ MEM_freeN(mem);
+ mem = NULL;
+ goto finally;
+ }
+
+ *r_size = filelen_read;
+
+finally:
+ fclose(fp);
+ }
+
+ return mem;
+}
+
+
+TEST(array_store, PlainTextFiles)
+{ ListBase lb;
+ BLI_listbase_clear(&lb);
+ BArrayStore *bs = BLI_array_store_create(1, 128);
+
+ for (int i = 0; i < 629; i++) {
+ char str[512];
+ BLI_snprintf(str, sizeof(str), "/src/py_array_cow/test_data/xz_data/%04d.c.xz", i);
+ // BLI_snprintf(str, sizeof(str), "/src/py_array_cow/test_data/c_code/%04d.c", i);
+ // printf("%s\n", str);
+ size_t data_len;
+ void *data;
+ data = file_read_binary_as_mem(str, 0, &data_len);
+
+ testbuffer_list_add(&lb, (const void *)data, data_len);
+ }
+
+ /* forwards */
+ testbuffer_list_store_populate(bs, &lb);
+ EXPECT_EQ(true, testbuffer_list_validate(&lb));
+ EXPECT_EQ(true, BLI_array_store_is_valid(bs));
+#ifdef DEBUG_PRINT
+ print_mem_saved("source code forward", bs);
+#endif
+
+ testbuffer_list_store_clear(bs, &lb);
+ BLI_listbase_reverse(&lb);
+
+ /* backwards */
+ testbuffer_list_store_populate(bs, &lb);
+ EXPECT_EQ(true, testbuffer_list_validate(&lb));
+ EXPECT_EQ(true, BLI_array_store_is_valid(bs));
+#ifdef DEBUG_PRINT
+ print_mem_saved("source code backwards", bs);
+#endif
+
+
+ testbuffer_list_free(&lb);
+ BLI_array_store_destroy(bs);
+}
+#endif
diff --git a/tests/gtests/blenlib/BLI_array_utils_test.cc b/tests/gtests/blenlib/BLI_array_utils_test.cc
index e532419691a..eabf5bc72cf 100644
--- a/tests/gtests/blenlib/BLI_array_utils_test.cc
+++ b/tests/gtests/blenlib/BLI_array_utils_test.cc
@@ -5,6 +5,7 @@
extern "C" {
#include "BLI_utildefines.h"
#include "BLI_array_utils.h"
+#include "BLI_stackdefines.h"
}
/* -------------------------------------------------------------------- */
@@ -44,33 +45,102 @@ TEST(array_utils, ReverseInt4)
TEST(array_utils, FindIndexStringEmpty)
{
char data[] = "", find = '0';
- EXPECT_EQ(-1, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find));
+ EXPECT_EQ(-1, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find));
+ EXPECT_EQ(-1, BLI_array_rfindindex(data, ARRAY_SIZE(data) - 1, &find));
}
TEST(array_utils, FindIndexStringSingle)
{
char data[] = "0", find = '0';
- EXPECT_EQ(0, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find));
+ EXPECT_EQ(0, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find));
+ EXPECT_EQ(0, BLI_array_rfindindex(data, ARRAY_SIZE(data) - 1, &find));
}
TEST(array_utils, FindIndexStringSingleMissing)
{
char data[] = "1", find = '0';
- EXPECT_EQ(-1, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find));
+ EXPECT_EQ(-1, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find));
+ EXPECT_EQ(-1, BLI_array_rfindindex(data, ARRAY_SIZE(data) - 1, &find));
}
TEST(array_utils, FindIndexString4)
{
char data[] = "0123", find = '3';
- EXPECT_EQ(3, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find));
+ EXPECT_EQ(3, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find));
+ EXPECT_EQ(3, BLI_array_rfindindex(data, ARRAY_SIZE(data) - 1, &find));
}
TEST(array_utils, FindIndexInt4)
{
- int data[] = {0, 1, 2, 3}, find = 2;
- EXPECT_EQ(2, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find));
+ int data[] = {0, 1, 2, 3}, find = 3;
+ EXPECT_EQ(3, BLI_array_findindex(data, ARRAY_SIZE(data), &find));
+ EXPECT_EQ(3, BLI_array_rfindindex(data, ARRAY_SIZE(data), &find));
}
+TEST(array_utils, FindIndexInt4_DupeEnd)
+{
+ int data[] = {0, 1, 2, 0}, find = 0;
+ EXPECT_EQ(0, BLI_array_findindex(data, ARRAY_SIZE(data), &find));
+ EXPECT_EQ(3, BLI_array_rfindindex(data, ARRAY_SIZE(data), &find));
+}
+
+TEST(array_utils, FindIndexInt4_DupeMid)
+{
+ int data[] = {1, 0, 0, 3}, find = 0;
+ EXPECT_EQ(1, BLI_array_findindex(data, ARRAY_SIZE(data), &find));
+ EXPECT_EQ(2, BLI_array_rfindindex(data, ARRAY_SIZE(data), &find));
+}
+
+TEST(array_utils, FindIndexPointer)
+{
+ const char *data[4] = {NULL};
+ STACK_DECLARE(data);
+
+ STACK_INIT(data, ARRAY_SIZE(data));
+
+ const char *a = "a", *b = "b", *c = "c", *d = "d";
+
+#define STACK_PUSH_AND_CHECK_FORWARD(v, i) { \
+ STACK_PUSH(data, v); \
+ EXPECT_EQ(i, BLI_array_findindex(data, STACK_SIZE(data), &(v))); \
+} ((void)0)
+
+#define STACK_PUSH_AND_CHECK_BACKWARD(v, i) { \
+ STACK_PUSH(data, v); \
+ EXPECT_EQ(i, BLI_array_rfindindex(data, STACK_SIZE(data), &(v))); \
+} ((void)0)
+
+#define STACK_PUSH_AND_CHECK_BOTH(v, i) { \
+ STACK_PUSH(data, v); \
+ EXPECT_EQ(i, BLI_array_findindex(data, STACK_SIZE(data), &(v))); \
+ EXPECT_EQ(i, BLI_array_rfindindex(data, STACK_SIZE(data), &(v))); \
+} ((void)0)
+
+ STACK_PUSH_AND_CHECK_BOTH(a, 0);
+ STACK_PUSH_AND_CHECK_BOTH(b, 1);
+ STACK_PUSH_AND_CHECK_BOTH(c, 2);
+ STACK_PUSH_AND_CHECK_BOTH(d, 3);
+
+ STACK_POP(data);
+ STACK_PUSH_AND_CHECK_BACKWARD(a, 3);
+
+ STACK_POP(data);
+ STACK_PUSH_AND_CHECK_FORWARD(a, 0);
+
+ STACK_POP(data);
+ STACK_POP(data);
+
+ STACK_PUSH_AND_CHECK_BACKWARD(b, 2);
+ STACK_PUSH_AND_CHECK_BACKWARD(a, 3);
+
+#undef STACK_PUSH_AND_CHECK_FORWARD
+#undef STACK_PUSH_AND_CHECK_BACKWARD
+#undef STACK_PUSH_AND_CHECK_BOTH
+
+}
+
+
+
/* BLI_array_binary_and */
#define BINARY_AND_TEST(data_cmp, data_a, data_b, data_combine, length) \
{ \
diff --git a/tests/gtests/blenlib/BLI_ghash_performance_test.cc b/tests/gtests/blenlib/BLI_ghash_performance_test.cc
index 709302db021..fb32cb3f0a5 100644
--- a/tests/gtests/blenlib/BLI_ghash_performance_test.cc
+++ b/tests/gtests/blenlib/BLI_ghash_performance_test.cc
@@ -21,6 +21,12 @@ extern "C" {
/* Resizing the hash has a huge cost over global filling operation! */
//#define GHASH_RESERVE
+/* Run the longest tests! */
+//#define GHASH_RUN_BIG
+
+/* Size of 'small case' ghash (number of entries). */
+#define TESTCASE_SIZE_SMALL 17
+
#define PRINTF_GHASH_STATS(_gh) \
{ \
double q, lf, var, pempty, poverloaded; \
@@ -32,7 +38,6 @@ extern "C" {
BLI_ghash_size(_gh), q, var, lf, pempty * 100.0, poverloaded * 100.0, bigb); \
} void (0)
-
/* Str: whole text, lines and words from a 'corpus' text. */
static void str_ghash_tests(GHash *ghash, const char *id)
@@ -223,12 +228,14 @@ TEST(ghash, IntGHash12000)
int_ghash_tests(ghash, "IntGHash - GHash - 12000", 12000);
}
+#ifdef GHASH_RUN_BIG
TEST(ghash, IntGHash100000000)
{
GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__);
int_ghash_tests(ghash, "IntGHash - GHash - 100000000", 100000000);
}
+#endif
TEST(ghash, IntMurmur2a12000)
{
@@ -237,13 +244,14 @@ TEST(ghash, IntMurmur2a12000)
int_ghash_tests(ghash, "IntGHash - Murmur - 12000", 12000);
}
+#ifdef GHASH_RUN_BIG
TEST(ghash, IntMurmur2a100000000)
{
GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p_murmur, BLI_ghashutil_intcmp, __func__);
int_ghash_tests(ghash, "IntGHash - Murmur - 100000000", 100000000);
}
-
+#endif
/* Int: random 50M integers. */
@@ -302,12 +310,14 @@ TEST(ghash, IntRandGHash12000)
randint_ghash_tests(ghash, "RandIntGHash - GHash - 12000", 12000);
}
+#ifdef GHASH_RUN_BIG
TEST(ghash, IntRandGHash50000000)
{
GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__);
randint_ghash_tests(ghash, "RandIntGHash - GHash - 50000000", 50000000);
}
+#endif
TEST(ghash, IntRandMurmur2a12000)
{
@@ -316,12 +326,14 @@ TEST(ghash, IntRandMurmur2a12000)
randint_ghash_tests(ghash, "RandIntGHash - Murmur - 12000", 12000);
}
+#ifdef GHASH_RUN_BIG
TEST(ghash, IntRandMurmur2a50000000)
{
GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p_murmur, BLI_ghashutil_intcmp, __func__);
randint_ghash_tests(ghash, "RandIntGHash - Murmur - 50000000", 50000000);
}
+#endif
static unsigned int ghashutil_tests_nohash_p(const void *p)
{
@@ -340,13 +352,14 @@ TEST(ghash, Int4NoHash12000)
randint_ghash_tests(ghash, "RandIntGHash - No Hash - 12000", 12000);
}
+#ifdef GHASH_RUN_BIG
TEST(ghash, Int4NoHash50000000)
{
GHash *ghash = BLI_ghash_new(ghashutil_tests_nohash_p, ghashutil_tests_cmp_p, __func__);
randint_ghash_tests(ghash, "RandIntGHash - No Hash - 50000000", 50000000);
}
-
+#endif
/* Int_v4: 20M of randomly-generated integer vectors. */
@@ -409,12 +422,14 @@ TEST(ghash, Int4GHash2000)
int4_ghash_tests(ghash, "Int4GHash - GHash - 2000", 2000);
}
+#ifdef GHASH_RUN_BIG
TEST(ghash, Int4GHash20000000)
{
GHash *ghash = BLI_ghash_new(BLI_ghashutil_uinthash_v4_p, BLI_ghashutil_uinthash_v4_cmp, __func__);
int4_ghash_tests(ghash, "Int4GHash - GHash - 20000000", 20000000);
}
+#endif
TEST(ghash, Int4Murmur2a2000)
{
@@ -423,9 +438,99 @@ TEST(ghash, Int4Murmur2a2000)
int4_ghash_tests(ghash, "Int4GHash - Murmur - 2000", 2000);
}
+#ifdef GHASH_RUN_BIG
TEST(ghash, Int4Murmur2a20000000)
{
GHash *ghash = BLI_ghash_new(BLI_ghashutil_uinthash_v4_p_murmur, BLI_ghashutil_uinthash_v4_cmp, __func__);
int4_ghash_tests(ghash, "Int4GHash - Murmur - 20000000", 20000000);
}
+#endif
+
+/* MultiSmall: create and manipulate a lot of very small ghashes (90% < 10 items, 9% < 100 items, 1% < 1000 items). */
+
+static void multi_small_ghash_tests_one(GHash *ghash, RNG *rng, const unsigned int nbr)
+{
+ unsigned int *data = (unsigned int *)MEM_mallocN(sizeof(*data) * (size_t)nbr, __func__);
+ unsigned int *dt;
+ unsigned int i;
+
+ for (i = nbr, dt = data; i--; dt++) {
+ *dt = BLI_rng_get_uint(rng);
+ }
+
+#ifdef GHASH_RESERVE
+ BLI_ghash_reserve(ghash, nbr);
+#endif
+
+ for (i = nbr, dt = data; i--; dt++) {
+ BLI_ghash_insert(ghash, SET_UINT_IN_POINTER(*dt), SET_UINT_IN_POINTER(*dt));
+ }
+
+ for (i = nbr, dt = data; i--; dt++) {
+ void *v = BLI_ghash_lookup(ghash, SET_UINT_IN_POINTER(*dt));
+ EXPECT_EQ(*dt, GET_UINT_FROM_POINTER(v));
+ }
+
+ BLI_ghash_clear(ghash, NULL, NULL);
+}
+
+static void multi_small_ghash_tests(GHash *ghash, const char *id, const unsigned int nbr)
+{
+ printf("\n========== STARTING %s ==========\n", id);
+
+ RNG *rng = BLI_rng_new(0);
+
+ TIMEIT_START(multi_small_ghash);
+
+ unsigned int i = nbr;
+ while (i--) {
+ const int nbr = 1 + (BLI_rng_get_int(rng) % TESTCASE_SIZE_SMALL) * (!(i % 100) ? 100 : (!(i % 10) ? 10 : 1));
+ multi_small_ghash_tests_one(ghash, rng, nbr);
+ }
+
+ TIMEIT_END(multi_small_ghash);
+
+ TIMEIT_START(multi_small2_ghash);
+
+ unsigned int i = nbr;
+ while (i--) {
+ const int nbr = 1 + (BLI_rng_get_int(rng) % TESTCASE_SIZE_SMALL) / 2 * (!(i % 100) ? 100 : (!(i % 10) ? 10 : 1));
+ multi_small_ghash_tests_one(ghash, rng, nbr);
+ }
+
+ TIMEIT_END(multi_small2_ghash);
+
+ BLI_ghash_free(ghash, NULL, NULL);
+ BLI_rng_free(rng);
+
+ printf("========== ENDED %s ==========\n\n", id);
+}
+
+TEST(ghash, MultiRandIntGHash2000)
+{
+ GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__);
+
+ multi_small_ghash_tests(ghash, "MultiSmall RandIntGHash - GHash - 2000", 2000);
+}
+
+TEST(ghash, MultiRandIntGHash200000)
+{
+ GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__);
+
+ multi_small_ghash_tests(ghash, "MultiSmall RandIntGHash - GHash - 200000", 200000);
+}
+
+TEST(ghash, MultiRandIntMurmur2a2000)
+{
+ GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p_murmur, BLI_ghashutil_intcmp, __func__);
+
+ multi_small_ghash_tests(ghash, "MultiSmall RandIntGHash - Murmur2a - 2000", 2000);
+}
+
+TEST(ghash, MultiRandIntMurmur2a200000)
+{
+ GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p_murmur, BLI_ghashutil_intcmp, __func__);
+
+ multi_small_ghash_tests(ghash, "MultiSmall RandIntGHash - Murmur2a - 200000", 200000);
+}
diff --git a/tests/gtests/blenlib/CMakeLists.txt b/tests/gtests/blenlib/CMakeLists.txt
index 5e6bddcdeab..12112e7a481 100644
--- a/tests/gtests/blenlib/CMakeLists.txt
+++ b/tests/gtests/blenlib/CMakeLists.txt
@@ -35,6 +35,7 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PLATFORM_LINKFLAGS}")
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${PLATFORM_LINKFLAGS_DEBUG}")
+BLENDER_TEST(BLI_array_store "bf_blenlib")
BLENDER_TEST(BLI_array_utils "bf_blenlib")
BLENDER_TEST(BLI_stack "bf_blenlib")
BLENDER_TEST(BLI_math_color "bf_blenlib")
diff --git a/tests/gtests/bmesh/bmesh_core_test.cc b/tests/gtests/bmesh/bmesh_core_test.cc
index 0cbb6ca343e..f386abc0b2b 100644
--- a/tests/gtests/bmesh/bmesh_core_test.cc
+++ b/tests/gtests/bmesh/bmesh_core_test.cc
@@ -9,7 +9,9 @@ TEST(bmesh_core, BMVertCreate) {
BMVert *bv1, *bv2, *bv3;
const float co1[3] = {1.0f, 2.0f, 0.0f};
- bm = BM_mesh_create(&bm_mesh_allocsize_default);
+ BMeshCreateParams bm_params;
+ bm_params.use_toolflags = true;
+ bm = BM_mesh_create(&bm_mesh_allocsize_default, &bm_params);
EXPECT_EQ(0, bm->totvert);
/* make a custom layer so we can see if it is copied properly */
BM_data_layer_add(bm, &bm->vdata, CD_PROP_FLT);
diff --git a/tests/gtests/testing/mock_log.h b/tests/gtests/testing/mock_log.h
new file mode 100644
index 00000000000..2ec558fac87
--- /dev/null
+++ b/tests/gtests/testing/mock_log.h
@@ -0,0 +1,162 @@
+// Copyright (c) 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Zhanyong Wan
+//
+// Defines the ScopedMockLog class (using Google C++ Mocking
+// Framework), which is convenient for testing code that uses LOG().
+//
+// NOTE(keir): This is a fork until Google Log exports the scoped mock log
+// class; see: http://code.google.com/p/google-glog/issues/detail?id=88
+
+#ifndef GOOGLE_CERES_INTERNAL_MOCK_LOG_H_
+#define GOOGLE_CERES_INTERNAL_MOCK_LOG_H_
+
+#include <string>
+
+#include "gmock/gmock.h"
+#include "glog/logging.h"
+
+// Needed to make the scoped mock log tests work without modification.
+namespace ceres {
+namespace internal {
+using google::WARNING;
+} // namespace internal
+} // namespace ceres
+
+namespace testing {
+
+// A ScopedMockLog object intercepts LOG() messages issued during its
+// lifespan. Using this together with Google C++ Mocking Framework,
+// it's very easy to test how a piece of code calls LOG(). The
+// typical usage:
+//
+// TEST(FooTest, LogsCorrectly) {
+// ScopedMockLog log;
+//
+// // We expect the WARNING "Something bad!" exactly twice.
+// EXPECT_CALL(log, Log(WARNING, _, "Something bad!"))
+// .Times(2);
+//
+// // We allow foo.cc to call LOG(INFO) any number of times.
+// EXPECT_CALL(log, Log(INFO, HasSubstr("/foo.cc"), _))
+// .Times(AnyNumber());
+//
+// Foo(); // Exercises the code under test.
+// }
+class ScopedMockLog : public google::LogSink {
+ public:
+ // When a ScopedMockLog object is constructed, it starts to
+ // intercept logs.
+ ScopedMockLog() { AddLogSink(this); }
+
+ // When the object is destructed, it stops intercepting logs.
+ virtual ~ScopedMockLog() { RemoveLogSink(this); }
+
+ // Implements the mock method:
+ //
+ // void Log(LogSeverity severity, const string& file_path,
+ // const string& message);
+ //
+ // The second argument to Send() is the full path of the source file
+ // in which the LOG() was issued.
+ //
+ // Note, that in a multi-threaded environment, all LOG() messages from a
+ // single thread will be handled in sequence, but that cannot be guaranteed
+ // for messages from different threads. In fact, if the same or multiple
+ // expectations are matched on two threads concurrently, their actions will
+ // be executed concurrently as well and may interleave.
+ MOCK_METHOD3(Log, void(google::LogSeverity severity,
+ const std::string& file_path,
+ const std::string& message));
+
+ private:
+ // Implements the send() virtual function in class LogSink.
+ // Whenever a LOG() statement is executed, this function will be
+ // invoked with information presented in the LOG().
+ //
+ // The method argument list is long and carries much information a
+ // test usually doesn't care about, so we trim the list before
+ // forwarding the call to Log(), which is much easier to use in
+ // tests.
+ //
+ // We still cannot call Log() directly, as it may invoke other LOG()
+ // messages, either due to Invoke, or due to an error logged in
+ // Google C++ Mocking Framework code, which would trigger a deadlock
+ // since a lock is held during send().
+ //
+ // Hence, we save the message for WaitTillSent() which will be called after
+ // the lock on send() is released, and we'll call Log() inside
+ // WaitTillSent(). Since while a single send() call may be running at a
+ // time, multiple WaitTillSent() calls (along with the one send() call) may
+ // be running simultaneously, we ensure thread-safety of the exchange between
+ // send() and WaitTillSent(), and that for each message, LOG(), send(),
+ // WaitTillSent() and Log() are executed in the same thread.
+ virtual void send(google::LogSeverity severity,
+ const char* full_filename,
+ const char* /*base_filename*/,
+ int /*line*/,
+ const tm* /*tm_time*/,
+ const char* message,
+ size_t message_len) {
+ // We are only interested in the log severity, full file name, and
+ // log message.
+ message_info_.severity = severity;
+ message_info_.file_path = full_filename;
+ message_info_.message = std::string(message, message_len);
+ }
+
+ // Implements the WaitTillSent() virtual function in class LogSink.
+ // It will be executed after send() and after the global logging lock is
+ // released, so calls within it (or rather within the Log() method called
+ // within) may also issue LOG() statements.
+ //
+ // LOG(), send(), WaitTillSent() and Log() will occur in the same thread for
+ // a given log message.
+ virtual void WaitTillSent() {
+ // First, and very importantly, we save a copy of the message being
+ // processed before calling Log(), since Log() may indirectly call send()
+ // and WaitTillSent() in the same thread again.
+ MessageInfo message_info = message_info_;
+ Log(message_info.severity, message_info.file_path, message_info.message);
+ }
+
+ // All relevant information about a logged message that needs to be passed
+ // from send() to WaitTillSent().
+ struct MessageInfo {
+ google::LogSeverity severity;
+ std::string file_path;
+ std::string message;
+ };
+ MessageInfo message_info_;
+};
+
+} // namespace testing
+
+#endif // GOOGLE_CERES_INTERNAL_MOCK_LOG_H_
diff --git a/tests/python/cycles_render_tests.py b/tests/python/cycles_render_tests.py
index 36fad175cfa..78b4b346f24 100755
--- a/tests/python/cycles_render_tests.py
+++ b/tests/python/cycles_render_tests.py
@@ -3,6 +3,7 @@
import argparse
import os
+import shutil
import subprocess
import sys
import tempfile
@@ -16,6 +17,8 @@ def render_file(filepath):
"--factory-startup",
filepath,
"-E", "CYCLES",
+ # Run with OSL enabled
+ # "--python-expr", "import bpy; bpy.context.scene.cycles.shading_system = True",
"-o", TEMP_FILE_MASK,
"-F", "PNG",
"-f", "1",
@@ -35,11 +38,11 @@ def render_file(filepath):
elif b"blender probably wont start" in e.output:
return "NO_START"
return "CRASH"
- except:
+ except BaseException as e:
if os.path.exists(TEMP_FILE):
os.remove(TEMP_FILE)
if VERBOSE:
- print(e.output.decode("utf-8"))
+ print(e)
return "CRASH"
@@ -53,22 +56,28 @@ def verify_output(filepath):
dirpath = os.path.dirname(filepath)
reference_dirpath = os.path.join(dirpath, "reference_renders")
reference_image = os.path.join(reference_dirpath, testname + ".png")
+ failed_image = os.path.join(reference_dirpath, testname + ".fail.png")
if not os.path.exists(reference_image):
return False
command = (
IDIFF,
- "-fail", "0.01",
+ "-fail", "0.015",
"-failpercent", "1",
reference_image,
TEMP_FILE,
)
try:
subprocess.check_output(command)
- return True
+ failed = False
except subprocess.CalledProcessError as e:
if VERBOSE:
print(e.output.decode("utf-8"))
- return e.returncode == 1
+ failed = e.returncode != 1
+ if failed:
+ shutil.copy(TEMP_FILE, failed_image)
+ elif os.path.exists(failed_image):
+ os.remove(failed_image)
+ return not failed
def run_test(filepath):
diff --git a/tests/python/pep8.py b/tests/python/pep8.py
index 61093fd7c27..0e6250f534b 100644
--- a/tests/python/pep8.py
+++ b/tests/python/pep8.py
@@ -113,7 +113,7 @@ def main():
print("%s:%d:0: empty class (), remove" % (f, i + 1))
del re, class_check
- print("\n\n\n# running pep8...")
+ print("\n\n\n# running flake8...")
# these are very picky and often hard to follow
# while keeping common script formatting.
@@ -128,6 +128,10 @@ def main():
# "imports not at top of file."
# prefer to load as needed (lazy load addons etc).
"E402",
+ # "do not compare types, use 'isinstance()'"
+ # times types are compared,
+ # I rather keep them specific
+ "E721",
)
for f, pep8_type in files:
@@ -138,7 +142,10 @@ def main():
else:
ignore_tmp = ignore
- os.system("pep8 --repeat --ignore=%s '%s'" % (",".join(ignore_tmp), f))
+ os.system("flake8 "
+ "--isolated "
+ "--ignore=%s '%s'" %
+ (",".join(ignore_tmp), f))
# frosted
print("\n\n\n# running frosted...")
@@ -152,6 +159,7 @@ def main():
"--disable="
"C0111," # missing doc string
"C0103," # invalid name
+ "C0413," # import should be placed at the top
"W0613," # unused argument, may add this back
# but happens a lot for 'context' for eg.
"W0232," # class has no __init__, Operator/Panel/Menu etc
@@ -165,7 +173,6 @@ def main():
"R0914," # Too many local variables
"R0915," # Too many statements
" "
- "--include-ids=y "
"--output-format=parseable "
"--reports=n "
"--max-line-length=1000"